From ccbc219b29f1f91054807479a4400987694fd651 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 17 Aug 2013 14:20:15 +0200 Subject: [PATCH 001/627] import sources --- .gitignore | 2 + AUTHORS | 2 + LICENSE | 20 ++ Makefile | 13 + README | 6 + aux.c | 45 +++ aux.h | 38 +++ ecdsa.c | 515 +++++++++++++++++++++++++++++++++ ecdsa.h | 32 ++ rand.c | 36 +++ rand.h | 30 ++ secp256k1.c | 820 ++++++++++++++++++++++++++++++++++++++++++++++++++++ secp256k1.h | 63 ++++ sha256.c | 127 ++++++++ sha256.h | 31 ++ test.c | 100 +++++++ 16 files changed, 1880 insertions(+) create mode 100644 .gitignore create mode 100644 AUTHORS create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 README create mode 100644 aux.c create mode 100644 aux.h create mode 100644 ecdsa.c create mode 100644 ecdsa.h create mode 100644 rand.c create mode 100644 rand.h create mode 100644 secp256k1.c create mode 100644 secp256k1.h create mode 100644 sha256.c create mode 100644 sha256.h create mode 100644 test.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..76758b086 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.o +test diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 000000000..51c9bdab0 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,2 @@ +Tomas Dzetkulic +Pavol Rusnak diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..f43bfa74c --- /dev/null +++ b/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2013 Tomas Dzetkulic +Copyright (c) 2013 Pavol Rusnak + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES +OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 000000000..dae2048f0 --- /dev/null +++ b/Makefile @@ -0,0 +1,13 @@ +CC = gcc +CFLAGS = -Wall +OBJS = aux.o ecdsa.o secp256k1.o sha256.o rand.o test.o +NAME = test + +%.o: %.c + $(CC) $(CFLAGS) -o $@ -c $< + +$(NAME): $(OBJS) + gcc $(OBJS) -o $(NAME) -lcrypto + +clean: + rm -f $(OBJS) $(NAME) diff --git a/README b/README new file mode 100644 index 000000000..8709b7f08 --- /dev/null +++ b/README @@ -0,0 +1,6 @@ +MicroECDSA +========== + +Heavily optimized ECDSA (secp256k1) signer for embedded devices. + +Distibuted under MIT License. diff --git a/aux.c b/aux.c new file mode 100644 index 000000000..61f6285c7 --- /dev/null +++ b/aux.c @@ -0,0 +1,45 @@ +/** + * Copyright (c) 2013 Tomas Dzetkulic + * Copyright (c) 2013 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "aux.h" + +inline uint32_t ror(const uint32_t x, const int n) +{ + return (x >> n) | (x << (32 - n)); +} + +inline uint32_t read_be(const uint8_t *data) +{ + return (((uint32_t)data[0]) << 24) | + (((uint32_t)data[1]) << 16) | + (((uint32_t)data[2]) << 8) | + (((uint32_t)data[3])); +} + +inline void write_be(uint8_t *data, uint32_t x) +{ + data[0] = x >> 24; + data[1] = x >> 16; + data[2] = x >>8; + data[3] = x; +} diff --git a/aux.h b/aux.h new file mode 100644 index 000000000..059579eb4 --- /dev/null +++ b/aux.h @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2013 Tomas Dzetkulic + * Copyright (c) 2013 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __AUX_H__ +#define __AUX_H__ + +#include + +// rotate uint32 right +inline uint32_t ror(const uint32_t x, const int n); + +// read 4 big endian bytes into uint32 +inline uint32_t read_be(const uint8_t *data); + +// write 4 big endian bytes +inline void write_be(uint8_t *data, uint32_t x); + +#endif diff --git a/ecdsa.c b/ecdsa.c new file mode 100644 index 000000000..7f86ccb17 --- /dev/null +++ b/ecdsa.c @@ -0,0 +1,515 @@ +/** + * Copyright (c) 2013 Tomas Dzetkulic + * Copyright (c) 2013 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include + +#include "rand.h" +#include "sha256.h" +#include "ecdsa.h" +#include "secp256k1.h" +#include "aux.h" + +// assumes x < 2*prime +void mod(bignum256 *x, bignum256 const *prime) +{ + int i = 8; + uint32_t temp; + // compare numbers + while (i >= 0 && prime->val[i] == x->val[i]) --i; + // if equal + if (i==-1) { + // set x to zero + for (i = 0; i < 9; i++) { + x->val[i] = 0; + } + } else { + // if x is greater + if (x->val[i] > prime->val[i]) { + // substract p from x + temp = 0x40000000u; + for (i = 0;i < 9; i++) { + temp += x->val[i] - prime->val[i]; + x->val[i] = temp & 0x3FFFFFFF; + temp >>= 30; + temp += 0x3FFFFFFFu; + } + } + } +} + +// x = k * x +// both inputs and result may be bigger than prime but not bigger than 2 * prime +void multiply(const bignum256 *k, bignum256 *x, bignum256 const *prime) +{ + int i, j; + uint64_t temp = 0; + uint32_t res[18], coef; + + // compute lower half of long multiplication + for (i = 0;i < 9; i++) + { + for (j = 0;j <= i; j++) { + temp += k->val[j] * (uint64_t)x->val[i-j]; + } + res[i] = temp & 0x3FFFFFFFu; + temp >>= 30; + } + // compute upper half + for (;i < 17; i++) + { + for (j = i - 8; j < 9 ;j++) { + temp += k->val[j] * (uint64_t)x->val[i-j]; + } + res[i] = temp & 0x3FFFFFFFu; + temp >>= 30; + } + res[17] = temp; + // compute modulo p division is only estimated so this may give result greater than prime but not bigger than 2 * prime + for (i = 16;i >= 8; i--) { + // estimate (res / prime) + coef = (res[i] >> 16) + (res[i+1] << 14); + // substract (coef * prime) from res + temp = 0x1000000000000000llu + res[i-8] - prime->val[0] * (uint64_t)coef; + res[i-8] = temp & 0x3FFFFFFF; + for (j = 1; j < 9; j++) { + temp >>= 30; + temp += 0xFFFFFFFC0000000llu + res[i-8+j] - prime->val[j] * (uint64_t)coef; + res[i - 8 + j] = temp & 0x3FFFFFFF; + } + } + // store the result + for (i = 0;i < 9; i++) { + x->val[i] = res[i]; + } +} + +void fast_mod(bignum256 *x, bignum256 const *prime) +{ + int j; + uint32_t coef; + uint64_t temp; + + coef = x->val[8] >> 16; + if (!coef) return; + // substract (coef * prime) from x + temp = 0x1000000000000000llu + x->val[0] - prime->val[0] * (uint64_t)coef; + x->val[0] = temp & 0x3FFFFFFF; + for (j = 1; j < 9; j++) { + temp >>= 30; + temp += 0xFFFFFFFC0000000llu + x->val[j] - prime->val[j] * (uint64_t)coef; + x->val[j] = temp & 0x3FFFFFFF; + } +} + +// in field G_prime +void inverse(bignum256 *x, bignum256 const *prime) +{ + int i, j, k, len1, len2, mask; + uint32_t u[9], v[9], s[10], r[10], temp, temp2; + fast_mod(x, prime); + mod(x, prime); + for (i = 0; i < 9; i++) { + u[i] = prime->val[i]; + v[i] = x->val[i]; + } + len1 = 9; + s[0] = 1; + r[0] = 0; + len2 = 1; + k = 0; + for (;;) { + for (i = 0;i < len1; i++) { + if (v[i]) break; + } + if (i == len1) break; + for (;;) { + for (i = 0;i < 30; i++) { + if (u[0] & (1 << i)) break; + } + if (i == 0) break; + mask=(1 << i) - 1; + for (j = 0; j + 1 < len1; j++) { + u[j] = (u[j] >> i) | ((u[j + 1] & mask) << (30 - i)); + } + u[j] = (u[j] >> i); + mask=(1 << (30 - i)) - 1; + s[len2] = s[len2 - 1] >> (30 - i); + for (j = len2 - 1; j > 0; j--) { + s[j] = (s[j - 1] >> (30 - i)) | ((s[j] & mask) << i); + } + s[0] = (s[0] & mask) << i; + if (s[len2]) { + r[len2]=0; + len2++; + } + k += i; + } + for (;;) { + for (i = 0;i < 30; i++) { + if (v[0] & (1 << i)) break; + } + if (i == 0) break; + mask = (1 << i) - 1; + for (j = 0; j + 1 < len1; j++) { + v[j] = (v[j] >> i) | ((v[j + 1] & mask) << (30 - i)); + } + v[j] = (v[j] >> i); + mask=(1 << (30 - i)) - 1; + r[len2] = r[len2 - 1] >> (30 - i); + for (j = len2 - 1; j > 0; j--) { + r[j] = (r[j - 1] >> (30 - i)) | ((r[j] & mask) << i); + } + r[0] = (r[0] & mask) << i; + if (r[len2]) { + s[len2]=0; + len2++; + } + k += i; + } + + i = len1 - 1; + while (i>0 && u[i] == v[i]) i--; + if (u[i] > v[i]) { + temp = 0x40000000u + u[0] - v[0]; + u[0] = (temp >> 1) & 0x1FFFFFFF; + temp >>= 30; + for (i = 1; i < len1; i++) { + temp += 0x3FFFFFFFu + u[i] - v[i]; + u[i-1] += (temp & 1) << 29; + u[i] = (temp >> 1) & 0x1FFFFFFF; + temp >>= 30; + } + temp = temp2 = 0; + for (i = 0; i < len2; i++) { + temp += s[i] + r[i]; + temp2 += s[i] << 1; + r[i] = temp & 0x3FFFFFFF; + s[i] = temp2 & 0x3FFFFFFF; + temp >>= 30; + temp2 >>= 30; + } + if (temp != 0 || temp2 != 0) { + r[len2] = temp; + s[len2] = temp2; + len2++; + } + } else { + temp = 0x40000000u + v[0] - u[0]; + v[0] = (temp >> 1) & 0x1FFFFFFF; + temp >>= 30; + for (i = 1; i < len1; i++) { + temp += 0x3FFFFFFFu + v[i] - u[i]; + v[i-1] += (temp & 1) << 29; + v[i] = (temp >> 1) & 0x1FFFFFFF; + temp >>= 30; + } + temp = temp2 = 0; + for (i = 0; i < len2; i++) { + temp += s[i] + r[i]; + temp2 += r[i] << 1; + s[i] = temp & 0x3FFFFFFF; + r[i] = temp2 & 0x3FFFFFFF; + temp >>= 30; + temp2 >>= 30; + } + if (temp != 0 || temp2 != 0) { + s[len2] = temp; + r[len2] = temp2; + len2++; + } + } + if (u[len1 - 1]==0 && v[len1 - 1]==0) len1--; + k++; + } + i = 8; + while (i>0 && r[i] == prime->val[i]) i--; + if (r[i] >= prime->val[i]) { + temp = 1; + for (i = 0; i < 9; i++) { + temp += 0x3FFFFFFF + r[i] - prime->val[i]; + r[i] = temp & 0x3FFFFFFF; + temp >>= 30; + } + } + temp = 1; + for (i = 0;i < 9; i++) { + temp += 0x3FFFFFFF + prime->val[i] - r[i]; + r[i] = temp & 0x3FFFFFFF; + temp >>= 30; + } + int done = 0; +#ifdef USE_PRECOMPUTED_IV + if (prime == &prime256k1) { + for (j = 0; j < 9; j++) { + x->val[j] = r[j]; + } + multiply(secp256k1_iv + k - 256, x, prime); + fast_mod(x, prime); + done = 1; + } +#endif + if (!done) { + for (j = 0; j < k; j++) { + if (r[0] & 1) { + temp = r[0] + prime->val[0]; + r[0] = (temp >> 1) & 0x1FFFFFFF; + temp >>= 30; + for (i = 1;i < 9; i++) { + temp += r[i] + prime->val[i]; + r[i-1] += (temp & 1) << 29; + r[i] = (temp >> 1) & 0x1FFFFFFF; + temp >>= 30; + } + } else { + for (i = 0; i < 8; i++) { + r[i] = (r[i] >> 1) | ((r[i+1] & 1) << 29); + } + r[8] = r[8] >> 1; + } + } + for (j = 0; j < 9; j++) { + x->val[j] = r[j]; + } + } +} + +// res = a - b +// b < 2*prime; result not normalized +void fast_substract(const bignum256 *a, const bignum256 *b, bignum256 *res) +{ + int i; + uint32_t temp = 0; + for (i = 0; i < 9; i++) { + temp += a->val[i] + 2u *prime256k1.val[i] - b->val[i]; + res->val[i] = temp & 0x3FFFFFFF; + temp >>= 30; + } +} + +// x2 = x1 + x2; +void point_add(const curve_point *x1, curve_point *x2) +{ + int i; + uint32_t temp; + bignum256 lambda, inv, xr, yr; + fast_substract(&(x2->x), &(x1->x), &inv); + inverse(&inv, &prime256k1); + fast_substract(&(x2->y), &(x1->y), &lambda); + multiply(&inv, &lambda, &prime256k1); + memcpy(&xr, &lambda, sizeof(bignum256)); + multiply(&xr, &xr, &prime256k1); + temp = 0; + for (i = 0;i < 9; i++) { + temp += xr.val[i] + 3u * prime256k1.val[i] - x1->x.val[i] - x2->x.val[i]; + xr.val[i] = temp & 0x3FFFFFFF; + temp >>= 30; + } + fast_mod(&xr, &prime256k1); + fast_substract(&(x1->x), &xr, &yr); + // no need to fast_mod here + // fast_mod(&yr); + multiply(&lambda, &yr, &prime256k1); + fast_substract(&yr, &(x1->y), &yr); + fast_mod(&yr, &prime256k1); + memcpy(&(x2->x), &xr, sizeof(bignum256)); + memcpy(&(x2->y), &yr, sizeof(bignum256)); +} + +#ifndef USE_PRECOMPUTED_CP +// x = x + x; +void point_double(curve_point *x) +{ + int i; + uint32_t temp; + bignum256 lambda, inverse_y, xr, yr; + memcpy(&inverse_y, &(x->y), sizeof(bignum256)); + inverse(&inverse_y, &prime256k1); + memcpy(&lambda, &three_over_two256k1, sizeof(bignum256)); + multiply(&inverse_y, &lambda, &prime256k1); + multiply(&(x->x), &lambda, &prime256k1); + multiply(&(x->x), &lambda, &prime256k1); + memcpy(&xr, &lambda, sizeof(bignum256)); + multiply(&xr, &xr, &prime256k1); + temp = 0; + for (i = 0;i < 9; i++) { + temp += xr.val[i] + 3u * prime256k1.val[i] - 2u * x->x.val[i]; + xr.val[i] = temp & 0x3FFFFFFF; + temp >>= 30; + } + fast_mod(&xr, &prime256k1); + fast_substract(&(x->x), &xr, &yr); + // no need to fast_mod here + // fast_mod(&yr); + multiply(&lambda, &yr, &prime256k1); + fast_substract(&yr, &(x->y), &yr); + fast_mod(&yr, &prime256k1); + memcpy(&(x->x), &xr, sizeof(bignum256)); + memcpy(&(x->y), &yr, sizeof(bignum256)); +} +#endif + +// res = k * G +void scalar_multiply(bignum256 *k, curve_point *res) +{ + int i, j; + // result is zero + int is_zero = 1; +#ifdef USE_PRECOMPUTED_CP + int exp = 0; +#else + curve_point curr; + // initial res + memcpy(&curr, &G256k1, sizeof(curve_point)); +#endif + for (i = 0; i < 9; i++) { + for (j = 0; j < 30; j++) { + if (i == 8 && (k->val[i] >> j) == 0) break; + if (k->val[i] & (1u<x), &prime256k1); + mod(&(res->y), &prime256k1); +} + +// write DER encoding of number to buffer +void write_der(const bignum256 *x, uint8_t *buf) +{ + int i, j = 8, k = 8, len = 0; + uint8_t r = 0, temp; + buf[0] = 2; + for (i = 0; i < 32; i++) { + temp = (x->val[j] >> k) + r; + k -= 8; + if (k < 0) { + r = (x->val[j]) << (-k); + k += 30; + j--; + } else { + r = 0; + } + if (len || temp) { + buf[2 + len] = temp; + len++; + } + } + buf[1] = len; +} + +// uses secp256k1 curve +// private key is a 32 byte big endian stored number +// message is a data to be signed +// len is the message length +// sig is at least 70 bytes long array for the signature +// sig_len is the pointer to a uint that will contain resulting signature length. note that ((*sig_len) == sig[1]+2) +void ecdsa_sign(uint8_t *private_key, uint8_t *message, uint32_t len, uint8_t *sig, uint32_t *sig_len) +{ + uint32_t i; + uint64_t temp; + uint8_t hash[32]; + curve_point R; + bignum256 k, z; + bignum256 *da = &R.y; + // compute hash function of message + sha256(message, len, hash); + // if double hash is required uncomment the following line: + // sha256(hash, 32, hash); + + temp = 0; + for (i = 0; i < 8; i++) { + temp += (((uint64_t)read_be(hash + (7 - i) * 4)) << (2 * i)); + z.val[i]= temp & 0x3FFFFFFF; + temp >>= 30; + } + z.val[8] = temp; + for (;;) { + // generate random number k + for (i = 0;i < 8; i++) { + k.val[i] = random32() & 0x3FFFFFFF; + } + k.val[8] =random32() & 0xFFFF; + // if k is too big or too small, we don't like it + if (k.val[5] == 0x3FFFFFFF && k.val[6]==0x3FFFFFFF && k.val[7]==0x3FFFFFFF && k.val[8]==0xFFFF) continue; + if (k.val[5] == 0x0 && k.val[6]==0x0 && k.val[7]==0x0 && k.val[8]==0x0) continue; + // compute k*G + scalar_multiply(&k, &R); + // r = (rx mod n) + mod(&R.x, &order256k1); + // if r is zero, we try different k + for (i = 0;i < 9; i++) { + if (R.x.val[i] != 0) break; + } + if (i == 9) continue; + inverse(&k, &order256k1); + temp = 0; + for (i=0; i<8; i++) { + temp += (((uint64_t)read_be(private_key + (7 - i) * 4)) << (2 * i)); + da->val[i] = temp & 0x3FFFFFFF; + temp >>= 30; + } + da->val[8] = temp; + multiply(&R.x, da, &order256k1); + for (i = 0; i < 8; i++) { + da->val[i] += z.val[i]; + da->val[i+1] += (da->val[i] >> 30); + da->val[i] &= 0x3FFFFFFF; + } + da->val[8] += z.val[8]; + multiply(da, &k, &order256k1); + mod(&k, &order256k1); + for (i = 0; i < 9; i++) { + if (k.val[i] != 0) break; + } + if (i == 9) continue; + // we are done, R.x and k is the result signature + break; + } + write_der(&R.x, sig + 2); + i = sig[3] + 2; + write_der(&k, sig + 2 + i); + i += sig[3+i] + 2; + sig[0] = 0x30; + sig[1] = i; + *sig_len = i + 2; +} diff --git a/ecdsa.h b/ecdsa.h new file mode 100644 index 000000000..6968bfa07 --- /dev/null +++ b/ecdsa.h @@ -0,0 +1,32 @@ +/** + * Copyright (c) 2013 Tomas Dzetkulic + * Copyright (c) 2013 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __ECDSA_H__ +#define __ECDSA_H__ + +#include + +// uses secp256k1 curve +void ecdsa_sign(uint8_t *private_key, uint8_t *message, uint32_t len, uint8_t *sig, uint32_t *sig_len); + +#endif diff --git a/rand.c b/rand.c new file mode 100644 index 000000000..24b990a27 --- /dev/null +++ b/rand.c @@ -0,0 +1,36 @@ +/** + * Copyright (c) 2013 Tomas Dzetkulic + * Copyright (c) 2013 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include + +#include "rand.h" + +void init_rand(void) { + srand(time(NULL)); +} + +uint32_t random32(void) { + return (rand() & 0xFF) + ((rand() & 0xFF) << 8) + ((rand() & 0xFF) << 16) + ((rand() & 0xFF) << 24); +} diff --git a/rand.h b/rand.h new file mode 100644 index 000000000..2ee45ed63 --- /dev/null +++ b/rand.h @@ -0,0 +1,30 @@ +/** + * Copyright (c) 2013 Tomas Dzetkulic + * Copyright (c) 2013 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __RAND_H__ +#define __RAND_H__ + +void init_rand(void); +uint32_t random32(void); + +#endif diff --git a/secp256k1.c b/secp256k1.c new file mode 100644 index 000000000..6149afec8 --- /dev/null +++ b/secp256k1.c @@ -0,0 +1,820 @@ +/** + * Copyright (c) 2013 Tomas Dzetkulic + * Copyright (c) 2013 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "secp256k1.h" + +const bignum256 prime256k1 = { +.val = {0x3ffffc2f, 0x3ffffffb, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0xffff} +}; + +const curve_point G256k1 = { +.x = { .val = {0x16f81798, 0x27ca056c, 0x1ce28d95, 0x26ff36cb, 0x70b0702, 0x18a573a, 0xbbac55a, 0x199fbe77, 0x79be}}, +.y = { .val = {0x3b10d4b8, 0x311f423f, 0x28554199, 0x5ed1229, 0x1108a8fd, 0x13eff038, 0x3c4655da, 0x369dc9a8, 0x483a}}}; + +const bignum256 order256k1 = { +.val = {0x10364141, 0x3f497a33, 0x348a03bb, 0x2bb739ab, 0x3ffffeba, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0xffff}}; + +const bignum256 three_over_two256k1 = { +.val = {0x3ffffe19, 0x3ffffffd, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x7fff}}; + +#ifdef USE_PRECOMPUTED_IV + +const bignum256 secp256k1_iv[256] = { +{ .val = {0x868192a, 0x20e02474, 0x24a059d, 0x2c88ffb7, 0x32b761bc, 0x1b0b0a57, 0x383999c4, 0x6414554, 0xc9bd}}, +{ .val = {0x4340c95, 0x3070123a, 0x212502ce, 0x16447fdb, 0x395bb0de, 0xd85852b, 0x1c1ccce2, 0x2320a2aa, 0x64de}}, +{ .val = {0x21a0462, 0x1838091b, 0x30928167, 0xb223fed, 0x3cadd86f, 0x6c2c295, 0xe0e6671, 0x11905155, 0xb26f}}, +{ .val = {0x210d0231, 0x2c1c048d, 0x384940b3, 0x25911ff6, 0x3e56ec37, 0x2361614a, 0x27073338, 0x28c828aa, 0x5937}}, +{ .val = {0x30867f30, 0x360e0244, 0x1c24a059, 0x32c88ffb, 0x1f2b761b, 0x11b0b0a5, 0x1383999c, 0x34641455, 0xac9b}}, +{ .val = {0x18433f98, 0x3b070122, 0x2e12502c, 0x396447fd, 0x2f95bb0d, 0x8d85852, 0x29c1ccce, 0x3a320a2a, 0x564d}}, +{ .val = {0xc219fcc, 0x1d838091, 0x37092816, 0x3cb223fe, 0x17cadd86, 0x46c2c29, 0x14e0e667, 0x3d190515, 0x2b26}}, +{ .val = {0x2610cfe6, 0xec1c048, 0x1b84940b, 0x1e5911ff, 0x2be56ec3, 0x22361614, 0x2a707333, 0x1e8c828a, 0x1593}}, +{ .val = {0x130867f3, 0x2760e024, 0x2dc24a05, 0x2f2c88ff, 0x15f2b761, 0x311b0b0a, 0x15383999, 0x2f464145, 0xac9}}, +{ .val = {0x9843211, 0x33b07010, 0x36e12502, 0x3796447f, 0xaf95bb0, 0x388d8585, 0x2a9c1ccc, 0x37a320a2, 0x8564}}, +{ .val = {0x4c21720, 0x19d83806, 0x3b709281, 0x1bcb223f, 0x257cadd8, 0x1c46c2c2, 0x154e0e66, 0x1bd19051, 0xc2b2}}, +{ .val = {0x2610b90, 0x2cec1c03, 0x3db84940, 0xde5911f, 0x12be56ec, 0xe236161, 0x2aa70733, 0xde8c828, 0x6159}}, +{ .val = {0x213085c8, 0x16760e01, 0x3edc24a0, 0x6f2c88f, 0x295f2b76, 0x2711b0b0, 0x15538399, 0x26f46414, 0x30ac}}, +{ .val = {0x309842e4, 0xb3b0700, 0x3f6e1250, 0x3796447, 0x14af95bb, 0x3388d858, 0xaa9c1cc, 0x137a320a, 0x1856}}, +{ .val = {0x184c2172, 0x59d8380, 0x3fb70928, 0x21bcb223, 0xa57cadd, 0x19c46c2c, 0x554e0e6, 0x9bd1905, 0xc2b}}, +{ .val = {0xc2610b9, 0x2cec1c0, 0x3fdb8494, 0x30de5911, 0x52be56e, 0xce23616, 0x22aa7073, 0x24de8c82, 0x615}}, +{ .val = {0x6130674, 0x16760de, 0x3fedc24a, 0x186f2c88, 0x295f2b7, 0x26711b0b, 0x11553839, 0x326f4641, 0x830a}}, +{ .val = {0x309833a, 0xb3b06f, 0x1ff6e125, 0x2c379644, 0x214af95b, 0x33388d85, 0x28aa9c1c, 0x1937a320, 0x4185}}, +{ .val = {0x2184c19d, 0x2059d837, 0xffb7092, 0x361bcb22, 0x30a57cad, 0x199c46c2, 0x14554e0e, 0x2c9bd190, 0x20c2}}, +{ .val = {0x30c25ee6, 0x102cec19, 0x7fdb849, 0x3b0de591, 0x1852be56, 0xcce2361, 0xa2aa707, 0x164de8c8, 0x9061}}, +{ .val = {0x38612f73, 0x2816760c, 0x23fedc24, 0x1d86f2c8, 0x2c295f2b, 0x266711b0, 0x5155383, 0x2b26f464, 0x4830}}, +{ .val = {0x1c3095d1, 0x140b3b04, 0x11ff6e12, 0x2ec37964, 0x1614af95, 0x333388d8, 0x28aa9c1, 0x15937a32, 0xa418}}, +{ .val = {0xe184900, 0xa059d80, 0x8ffb709, 0x3761bcb2, 0xb0a57ca, 0x3999c46c, 0x14554e0, 0xac9bd19, 0xd20c}}, +{ .val = {0x70c2480, 0x2502cec0, 0x47fdb84, 0x1bb0de59, 0x5852be5, 0x1ccce236, 0x20a2aa70, 0x564de8c, 0x6906}}, +{ .val = {0x3861240, 0x12816760, 0x223fedc2, 0x2dd86f2c, 0x2c295f2, 0xe66711b, 0x10515538, 0x2b26f46, 0x3483}}, +{ .val = {0x1c30920, 0x940b3b0, 0x111ff6e1, 0x16ec3796, 0x21614af9, 0x733388d, 0x828aa9c, 0x215937a3, 0x1a41}}, +{ .val = {0xe18490, 0x24a059d8, 0x88ffb70, 0x2b761bcb, 0x30b0a57c, 0x3999c46, 0x2414554e, 0x30ac9bd1, 0xd20}}, +{ .val = {0x70c248, 0x12502cec, 0x2447fdb8, 0x15bb0de5, 0x185852be, 0x1ccce23, 0x320a2aa7, 0x18564de8, 0x690}}, +{ .val = {0x386124, 0x9281676, 0x3223fedc, 0xadd86f2, 0x2c2c295f, 0x20e66711, 0x19051553, 0xc2b26f4, 0x348}}, +{ .val = {0x1c3092, 0x4940b3b, 0x1911ff6e, 0x256ec379, 0x361614af, 0x30733388, 0xc828aa9, 0x615937a, 0x1a4}}, +{ .val = {0x200e1849, 0x24a059d, 0x2c88ffb7, 0x32b761bc, 0x1b0b0a57, 0x383999c4, 0x6414554, 0x30ac9bd, 0xd2}}, +{ .val = {0x30070a3c, 0x212502cc, 0x16447fdb, 0x395bb0de, 0xd85852b, 0x1c1ccce2, 0x2320a2aa, 0x18564de, 0x8069}}, +{ .val = {0x1803851e, 0x30928166, 0xb223fed, 0x3cadd86f, 0x6c2c295, 0xe0e6671, 0x11905155, 0x20c2b26f, 0x4034}}, +{ .val = {0xc01c28f, 0x384940b3, 0x25911ff6, 0x3e56ec37, 0x2361614a, 0x27073338, 0x28c828aa, 0x10615937, 0x201a}}, +{ .val = {0x2600df5f, 0x1c24a057, 0x32c88ffb, 0x1f2b761b, 0x11b0b0a5, 0x1383999c, 0x34641455, 0x830ac9b, 0x900d}}, +{ .val = {0x33006dc7, 0x2e125029, 0x396447fd, 0x2f95bb0d, 0x8d85852, 0x29c1ccce, 0x3a320a2a, 0x2418564d, 0xc806}}, +{ .val = {0x398034fb, 0x37092812, 0x3cb223fe, 0x17cadd86, 0x46c2c29, 0x14e0e667, 0x3d190515, 0x120c2b26, 0xe403}}, +{ .val = {0x1cc01895, 0x1b849407, 0x1e5911ff, 0x2be56ec3, 0x22361614, 0x2a707333, 0x1e8c828a, 0x29061593, 0xf201}}, +{ .val = {0x2e600a62, 0x2dc24a01, 0x2f2c88ff, 0x15f2b761, 0x311b0b0a, 0x15383999, 0x2f464145, 0x34830ac9, 0xf900}}, +{ .val = {0x37300531, 0x36e12500, 0x3796447f, 0xaf95bb0, 0x388d8585, 0x2a9c1ccc, 0x37a320a2, 0x1a418564, 0x7c80}}, +{ .val = {0x1b9800b0, 0x3b70927e, 0x1bcb223f, 0x257cadd8, 0x1c46c2c2, 0x154e0e66, 0x1bd19051, 0xd20c2b2, 0xbe40}}, +{ .val = {0xdcc0058, 0x3db8493f, 0xde5911f, 0x12be56ec, 0xe236161, 0x2aa70733, 0xde8c828, 0x6906159, 0x5f20}}, +{ .val = {0x26e6002c, 0x3edc249f, 0x6f2c88f, 0x295f2b76, 0x2711b0b0, 0x15538399, 0x26f46414, 0x34830ac, 0x2f90}}, +{ .val = {0x33730016, 0x3f6e124f, 0x3796447, 0x14af95bb, 0x3388d858, 0xaa9c1cc, 0x137a320a, 0x1a41856, 0x17c8}}, +{ .val = {0x39b9800b, 0x3fb70927, 0x21bcb223, 0xa57cadd, 0x19c46c2c, 0x554e0e6, 0x9bd1905, 0xd20c2b, 0xbe4}}, +{ .val = {0x3cdcbe1d, 0x3fdb8491, 0x30de5911, 0x52be56e, 0xce23616, 0x22aa7073, 0x24de8c82, 0x690615, 0x85f2}}, +{ .val = {0x3e6e5d26, 0x3fedc246, 0x186f2c88, 0x295f2b7, 0x26711b0b, 0x11553839, 0x326f4641, 0x34830a, 0xc2f9}}, +{ .val = {0x1f372e93, 0x1ff6e123, 0x2c379644, 0x214af95b, 0x33388d85, 0x28aa9c1c, 0x1937a320, 0x201a4185, 0x617c}}, +{ .val = {0x2f9b9561, 0xffb708f, 0x361bcb22, 0x30a57cad, 0x199c46c2, 0x14554e0e, 0x2c9bd190, 0x100d20c2, 0xb0be}}, +{ .val = {0x37cdc8c8, 0x7fdb845, 0x3b0de591, 0x1852be56, 0xcce2361, 0xa2aa707, 0x164de8c8, 0x8069061, 0xd85f}}, +{ .val = {0x3be6e464, 0x23fedc22, 0x1d86f2c8, 0x2c295f2b, 0x266711b0, 0x5155383, 0x2b26f464, 0x24034830, 0x6c2f}}, +{ .val = {0x1df37232, 0x11ff6e11, 0x2ec37964, 0x1614af95, 0x333388d8, 0x28aa9c1, 0x15937a32, 0x3201a418, 0x3617}}, +{ .val = {0x2ef9b919, 0x8ffb708, 0x3761bcb2, 0xb0a57ca, 0x3999c46c, 0x14554e0, 0xac9bd19, 0x3900d20c, 0x1b0b}}, +{ .val = {0x177cdaa4, 0x47fdb82, 0x1bb0de59, 0x5852be5, 0x1ccce236, 0x20a2aa70, 0x564de8c, 0x3c806906, 0x8d85}}, +{ .val = {0xbbe6d52, 0x223fedc1, 0x2dd86f2c, 0x2c295f2, 0xe66711b, 0x10515538, 0x2b26f46, 0x3e403483, 0x46c2}}, +{ .val = {0x25df36a9, 0x111ff6e0, 0x16ec3796, 0x21614af9, 0x733388d, 0x828aa9c, 0x215937a3, 0x1f201a41, 0x2361}}, +{ .val = {0x12ef996c, 0x88ffb6e, 0x2b761bcb, 0x30b0a57c, 0x3999c46, 0x2414554e, 0x30ac9bd1, 0x2f900d20, 0x91b0}}, +{ .val = {0x977ccb6, 0x2447fdb7, 0x15bb0de5, 0x185852be, 0x1ccce23, 0x320a2aa7, 0x18564de8, 0x17c80690, 0x48d8}}, +{ .val = {0x24bbe65b, 0x3223fedb, 0xadd86f2, 0x2c2c295f, 0x20e66711, 0x19051553, 0xc2b26f4, 0xbe40348, 0x246c}}, +{ .val = {0x325df145, 0x1911ff6b, 0x256ec379, 0x361614af, 0x30733388, 0xc828aa9, 0x615937a, 0x5f201a4, 0x9236}}, +{ .val = {0x392ef6ba, 0x2c88ffb3, 0x32b761bc, 0x1b0b0a57, 0x383999c4, 0x6414554, 0x30ac9bd, 0x2f900d2, 0xc91b}}, +{ .val = {0x3c977b5d, 0x16447fd9, 0x395bb0de, 0xd85852b, 0x1c1ccce2, 0x2320a2aa, 0x18564de, 0x217c8069, 0x648d}}, +{ .val = {0x3e4bbbc6, 0xb223fea, 0x3cadd86f, 0x6c2c295, 0xe0e6671, 0x11905155, 0x20c2b26f, 0x30be4034, 0xb246}}, +{ .val = {0x1f25dde3, 0x25911ff5, 0x3e56ec37, 0x2361614a, 0x27073338, 0x28c828aa, 0x10615937, 0x185f201a, 0x5923}}, +{ .val = {0x2f92ed09, 0x32c88ff8, 0x1f2b761b, 0x11b0b0a5, 0x1383999c, 0x34641455, 0x830ac9b, 0x2c2f900d, 0xac91}}, +{ .val = {0x17c9749c, 0x396447fa, 0x2f95bb0d, 0x8d85852, 0x29c1ccce, 0x3a320a2a, 0x2418564d, 0x3617c806, 0xd648}}, +{ .val = {0xbe4ba4e, 0x3cb223fd, 0x17cadd86, 0x46c2c29, 0x14e0e667, 0x3d190515, 0x120c2b26, 0x1b0be403, 0x6b24}}, +{ .val = {0x25f25d27, 0x1e5911fe, 0x2be56ec3, 0x22361614, 0x2a707333, 0x1e8c828a, 0x29061593, 0xd85f201, 0x3592}}, +{ .val = {0x12f92cab, 0x2f2c88fd, 0x15f2b761, 0x311b0b0a, 0x15383999, 0x2f464145, 0x34830ac9, 0x6c2f900, 0x9ac9}}, +{ .val = {0x297c946d, 0x3796447c, 0xaf95bb0, 0x388d8585, 0x2a9c1ccc, 0x37a320a2, 0x1a418564, 0x23617c80, 0xcd64}}, +{ .val = {0x14be484e, 0x1bcb223c, 0x257cadd8, 0x1c46c2c2, 0x154e0e66, 0x1bd19051, 0xd20c2b2, 0x11b0be40, 0xe6b2}}, +{ .val = {0xa5f2427, 0xde5911e, 0x12be56ec, 0xe236161, 0x2aa70733, 0xde8c828, 0x6906159, 0x8d85f20, 0x7359}}, +{ .val = {0x52f902b, 0x6f2c88d, 0x295f2b76, 0x2711b0b0, 0x15538399, 0x26f46414, 0x34830ac, 0x246c2f90, 0xb9ac}}, +{ .val = {0x2297c62d, 0x3796444, 0x14af95bb, 0x3388d858, 0xaa9c1cc, 0x137a320a, 0x1a41856, 0x123617c8, 0xdcd6}}, +{ .val = {0x114be12e, 0x21bcb220, 0xa57cadd, 0x19c46c2c, 0x554e0e6, 0x9bd1905, 0xd20c2b, 0x91b0be4, 0xee6b}}, +{ .val = {0x8a5f097, 0x30de5910, 0x52be56e, 0xce23616, 0x22aa7073, 0x24de8c82, 0x690615, 0x248d85f2, 0x7735}}, +{ .val = {0x452f663, 0x186f2c86, 0x295f2b7, 0x26711b0b, 0x11553839, 0x326f4641, 0x34830a, 0x3246c2f9, 0xbb9a}}, +{ .val = {0x2297949, 0x2c379641, 0x214af95b, 0x33388d85, 0x28aa9c1c, 0x1937a320, 0x201a4185, 0x1923617c, 0xddcd}}, +{ .val = {0x2114babc, 0x361bcb1e, 0x30a57cad, 0x199c46c2, 0x14554e0e, 0x2c9bd190, 0x100d20c2, 0x2c91b0be, 0xeee6}}, +{ .val = {0x108a5d5e, 0x3b0de58f, 0x1852be56, 0xcce2361, 0xa2aa707, 0x164de8c8, 0x8069061, 0x1648d85f, 0x7773}}, +{ .val = {0x28452eaf, 0x1d86f2c7, 0x2c295f2b, 0x266711b0, 0x5155383, 0x2b26f464, 0x24034830, 0x2b246c2f, 0x3bb9}}, +{ .val = {0x3422956f, 0x2ec37961, 0x1614af95, 0x333388d8, 0x28aa9c1, 0x15937a32, 0x3201a418, 0x35923617, 0x9ddc}}, +{ .val = {0x3a1148cf, 0x3761bcae, 0xb0a57ca, 0x3999c46c, 0x14554e0, 0xac9bd19, 0x3900d20c, 0x1ac91b0b, 0xceee}}, +{ .val = {0x1d08a27f, 0x1bb0de55, 0x5852be5, 0x1ccce236, 0x20a2aa70, 0x564de8c, 0x3c806906, 0xd648d85, 0xe777}}, +{ .val = {0x2e844f57, 0x2dd86f28, 0x2c295f2, 0xe66711b, 0x10515538, 0x2b26f46, 0x3e403483, 0x26b246c2, 0xf3bb}}, +{ .val = {0x174225c3, 0x16ec3792, 0x21614af9, 0x733388d, 0x828aa9c, 0x215937a3, 0x1f201a41, 0x33592361, 0xf9dd}}, +{ .val = {0xba110f9, 0x2b761bc7, 0x30b0a57c, 0x3999c46, 0x2414554e, 0x30ac9bd1, 0x2f900d20, 0x39ac91b0, 0xfcee}}, +{ .val = {0x25d08694, 0x15bb0de1, 0x185852be, 0x1ccce23, 0x320a2aa7, 0x18564de8, 0x17c80690, 0x1cd648d8, 0xfe77}}, +{ .val = {0x32e8434a, 0xadd86f0, 0x2c2c295f, 0x20e66711, 0x19051553, 0xc2b26f4, 0xbe40348, 0x2e6b246c, 0x7f3b}}, +{ .val = {0x197421a5, 0x256ec378, 0x361614af, 0x30733388, 0xc828aa9, 0x615937a, 0x5f201a4, 0x37359236, 0x3f9d}}, +{ .val = {0xcba0eea, 0x32b761ba, 0x1b0b0a57, 0x383999c4, 0x6414554, 0x30ac9bd, 0x2f900d2, 0x3b9ac91b, 0x9fce}}, +{ .val = {0x65d0775, 0x395bb0dd, 0xd85852b, 0x1c1ccce2, 0x2320a2aa, 0x18564de, 0x217c8069, 0x1dcd648d, 0x4fe7}}, +{ .val = {0x232e81d2, 0x3cadd86c, 0x6c2c295, 0xe0e6671, 0x11905155, 0x20c2b26f, 0x30be4034, 0x2ee6b246, 0xa7f3}}, +{ .val = {0x119740e9, 0x3e56ec36, 0x2361614a, 0x27073338, 0x28c828aa, 0x10615937, 0x185f201a, 0x37735923, 0x53f9}}, +{ .val = {0x8cb9e8c, 0x1f2b7619, 0x11b0b0a5, 0x1383999c, 0x34641455, 0x830ac9b, 0x2c2f900d, 0x3bb9ac91, 0xa9fc}}, +{ .val = {0x2465cf46, 0x2f95bb0c, 0x8d85852, 0x29c1ccce, 0x3a320a2a, 0x2418564d, 0x3617c806, 0x1ddcd648, 0x54fe}}, +{ .val = {0x1232e7a3, 0x17cadd86, 0x46c2c29, 0x14e0e667, 0x3d190515, 0x120c2b26, 0x1b0be403, 0xeee6b24, 0x2a7f}}, +{ .val = {0x91971e9, 0x2be56ec1, 0x22361614, 0x2a707333, 0x1e8c828a, 0x29061593, 0xd85f201, 0x27773592, 0x953f}}, +{ .val = {0x248cb70c, 0x15f2b75e, 0x311b0b0a, 0x15383999, 0x2f464145, 0x34830ac9, 0x6c2f900, 0x33bb9ac9, 0xca9f}}, +{ .val = {0x12465b86, 0xaf95baf, 0x388d8585, 0x2a9c1ccc, 0x37a320a2, 0x1a418564, 0x23617c80, 0x39ddcd64, 0x654f}}, +{ .val = {0x29232dc3, 0x257cadd7, 0x1c46c2c2, 0x154e0e66, 0x1bd19051, 0xd20c2b2, 0x11b0be40, 0x3ceee6b2, 0x32a7}}, +{ .val = {0x349194f9, 0x12be56e9, 0xe236161, 0x2aa70733, 0xde8c828, 0x6906159, 0x8d85f20, 0x3e777359, 0x9953}}, +{ .val = {0x3a48c894, 0x295f2b72, 0x2711b0b0, 0x15538399, 0x26f46414, 0x34830ac, 0x246c2f90, 0x3f3bb9ac, 0xcca9}}, +{ .val = {0x1d24644a, 0x14af95b9, 0x3388d858, 0xaa9c1cc, 0x137a320a, 0x1a41856, 0x123617c8, 0x3f9ddcd6, 0x6654}}, +{ .val = {0x2e923225, 0xa57cadc, 0x19c46c2c, 0x554e0e6, 0x9bd1905, 0xd20c2b, 0x91b0be4, 0x1fceee6b, 0x332a}}, +{ .val = {0x1749172a, 0x52be56c, 0xce23616, 0x22aa7073, 0x24de8c82, 0x690615, 0x248d85f2, 0xfe77735, 0x9995}}, +{ .val = {0xba48b95, 0x295f2b6, 0x26711b0b, 0x11553839, 0x326f4641, 0x34830a, 0x3246c2f9, 0x27f3bb9a, 0x4cca}}, +{ .val = {0x5d243e2, 0x214af959, 0x33388d85, 0x28aa9c1c, 0x1937a320, 0x201a4185, 0x1923617c, 0x13f9ddcd, 0xa665}}, +{ .val = {0x22e921f1, 0x30a57cac, 0x199c46c2, 0x14554e0e, 0x2c9bd190, 0x100d20c2, 0x2c91b0be, 0x29fceee6, 0x5332}}, +{ .val = {0x11748f10, 0x1852be54, 0xcce2361, 0xa2aa707, 0x164de8c8, 0x8069061, 0x1648d85f, 0x14fe7773, 0xa999}}, +{ .val = {0x8ba4788, 0x2c295f2a, 0x266711b0, 0x5155383, 0x2b26f464, 0x24034830, 0x2b246c2f, 0x2a7f3bb9, 0x54cc}}, +{ .val = {0x45d23c4, 0x1614af95, 0x333388d8, 0x28aa9c1, 0x15937a32, 0x3201a418, 0x35923617, 0x153f9ddc, 0x2a66}}, +{ .val = {0x222e91e2, 0xb0a57ca, 0x3999c46c, 0x14554e0, 0xac9bd19, 0x3900d20c, 0x1ac91b0b, 0xa9fceee, 0x1533}}, +{ .val = {0x111748f1, 0x5852be5, 0x1ccce236, 0x20a2aa70, 0x564de8c, 0x3c806906, 0xd648d85, 0x254fe777, 0xa99}}, +{ .val = {0x288ba290, 0x2c295f0, 0xe66711b, 0x10515538, 0x2b26f46, 0x3e403483, 0x26b246c2, 0x32a7f3bb, 0x854c}}, +{ .val = {0x1445d148, 0x21614af8, 0x733388d, 0x828aa9c, 0x215937a3, 0x1f201a41, 0x33592361, 0x1953f9dd, 0x42a6}}, +{ .val = {0xa22e8a4, 0x30b0a57c, 0x3999c46, 0x2414554e, 0x30ac9bd1, 0x2f900d20, 0x39ac91b0, 0xca9fcee, 0x2153}}, +{ .val = {0x5117452, 0x185852be, 0x1ccce23, 0x320a2aa7, 0x18564de8, 0x17c80690, 0x1cd648d8, 0x2654fe77, 0x10a9}}, +{ .val = {0x288ba29, 0x2c2c295f, 0x20e66711, 0x19051553, 0xc2b26f4, 0xbe40348, 0x2e6b246c, 0x332a7f3b, 0x854}}, +{ .val = {0x21445b2c, 0x361614ad, 0x30733388, 0xc828aa9, 0x615937a, 0x5f201a4, 0x37359236, 0x19953f9d, 0x842a}}, +{ .val = {0x30a22d96, 0x1b0b0a56, 0x383999c4, 0x6414554, 0x30ac9bd, 0x2f900d2, 0x3b9ac91b, 0xcca9fce, 0x4215}}, +{ .val = {0x185116cb, 0xd85852b, 0x1c1ccce2, 0x2320a2aa, 0x18564de, 0x217c8069, 0x1dcd648d, 0x26654fe7, 0x210a}}, +{ .val = {0x2c28897d, 0x6c2c293, 0xe0e6671, 0x11905155, 0x20c2b26f, 0x30be4034, 0x2ee6b246, 0x1332a7f3, 0x9085}}, +{ .val = {0x361442d6, 0x23616147, 0x27073338, 0x28c828aa, 0x10615937, 0x185f201a, 0x37735923, 0x299953f9, 0xc842}}, +{ .val = {0x3b0a216b, 0x11b0b0a3, 0x1383999c, 0x34641455, 0x830ac9b, 0x2c2f900d, 0x3bb9ac91, 0x14cca9fc, 0x6421}}, +{ .val = {0x3d850ecd, 0x8d8584f, 0x29c1ccce, 0x3a320a2a, 0x2418564d, 0x3617c806, 0x1ddcd648, 0x2a6654fe, 0xb210}}, +{ .val = {0x3ec2857e, 0x46c2c25, 0x14e0e667, 0x3d190515, 0x120c2b26, 0x1b0be403, 0xeee6b24, 0x15332a7f, 0xd908}}, +{ .val = {0x3f6142bf, 0x22361612, 0x2a707333, 0x1e8c828a, 0x29061593, 0xd85f201, 0x27773592, 0xa99953f, 0x6c84}}, +{ .val = {0x1fb09f77, 0x311b0b07, 0x15383999, 0x2f464145, 0x34830ac9, 0x6c2f900, 0x33bb9ac9, 0x54cca9f, 0xb642}}, +{ .val = {0x2fd84dd3, 0x388d8581, 0x2a9c1ccc, 0x37a320a2, 0x1a418564, 0x23617c80, 0x39ddcd64, 0x2a6654f, 0xdb21}}, +{ .val = {0x37ec2501, 0x1c46c2be, 0x154e0e66, 0x1bd19051, 0xd20c2b2, 0x11b0be40, 0x3ceee6b2, 0x215332a7, 0xed90}}, +{ .val = {0x1bf61098, 0xe23615d, 0x2aa70733, 0xde8c828, 0x6906159, 0x8d85f20, 0x3e777359, 0x10a99953, 0xf6c8}}, +{ .val = {0x2dfb084c, 0x2711b0ae, 0x15538399, 0x26f46414, 0x34830ac, 0x246c2f90, 0x3f3bb9ac, 0x854cca9, 0x7b64}}, +{ .val = {0x16fd8426, 0x3388d857, 0xaa9c1cc, 0x137a320a, 0x1a41856, 0x123617c8, 0x3f9ddcd6, 0x42a6654, 0x3db2}}, +{ .val = {0x2b7ec213, 0x19c46c2b, 0x554e0e6, 0x9bd1905, 0xd20c2b, 0x91b0be4, 0x1fceee6b, 0x215332a, 0x1ed9}}, +{ .val = {0x35bf5f21, 0xce23613, 0x22aa7073, 0x24de8c82, 0x690615, 0x248d85f2, 0xfe77735, 0x210a9995, 0x8f6c}}, +{ .val = {0x3adfada8, 0x26711b07, 0x11553839, 0x326f4641, 0x34830a, 0x3246c2f9, 0x27f3bb9a, 0x10854cca, 0xc7b6}}, +{ .val = {0x3d6fd6d4, 0x33388d83, 0x28aa9c1c, 0x1937a320, 0x201a4185, 0x1923617c, 0x13f9ddcd, 0x842a665, 0x63db}}, +{ .val = {0x3eb7eb6a, 0x199c46c1, 0x14554e0e, 0x2c9bd190, 0x100d20c2, 0x2c91b0be, 0x29fceee6, 0x24215332, 0x31ed}}, +{ .val = {0x3f5bf5b5, 0xcce2360, 0xa2aa707, 0x164de8c8, 0x8069061, 0x1648d85f, 0x14fe7773, 0x3210a999, 0x18f6}}, +{ .val = {0x1fadf8f2, 0x266711ae, 0x5155383, 0x2b26f464, 0x24034830, 0x2b246c2f, 0x2a7f3bb9, 0x190854cc, 0x8c7b}}, +{ .val = {0xfd6fc79, 0x333388d7, 0x28aa9c1, 0x15937a32, 0x3201a418, 0x35923617, 0x153f9ddc, 0x2c842a66, 0x463d}}, +{ .val = {0x27eb7c54, 0x3999c469, 0x14554e0, 0xac9bd19, 0x3900d20c, 0x1ac91b0b, 0xa9fceee, 0x36421533, 0xa31e}}, +{ .val = {0x33f5be2a, 0x1ccce234, 0x20a2aa70, 0x564de8c, 0x3c806906, 0xd648d85, 0x254fe777, 0x1b210a99, 0x518f}}, +{ .val = {0x19fadf15, 0xe66711a, 0x10515538, 0x2b26f46, 0x3e403483, 0x26b246c2, 0x32a7f3bb, 0x2d90854c, 0x28c7}}, +{ .val = {0xcfd6da2, 0x733388b, 0x828aa9c, 0x215937a3, 0x1f201a41, 0x33592361, 0x1953f9dd, 0x36c842a6, 0x9463}}, +{ .val = {0x267eb6d1, 0x3999c45, 0x2414554e, 0x30ac9bd1, 0x2f900d20, 0x39ac91b0, 0xca9fcee, 0x3b642153, 0x4a31}}, +{ .val = {0x333f5980, 0x1ccce20, 0x320a2aa7, 0x18564de8, 0x17c80690, 0x1cd648d8, 0x2654fe77, 0x3db210a9, 0xa518}}, +{ .val = {0x199facc0, 0x20e66710, 0x19051553, 0xc2b26f4, 0xbe40348, 0x2e6b246c, 0x332a7f3b, 0x1ed90854, 0x528c}}, +{ .val = {0xccfd660, 0x30733388, 0xc828aa9, 0x615937a, 0x5f201a4, 0x37359236, 0x19953f9d, 0xf6c842a, 0x2946}}, +{ .val = {0x667eb30, 0x383999c4, 0x6414554, 0x30ac9bd, 0x2f900d2, 0x3b9ac91b, 0xcca9fce, 0x7b64215, 0x14a3}}, +{ .val = {0x333f598, 0x1c1ccce2, 0x2320a2aa, 0x18564de, 0x217c8069, 0x1dcd648d, 0x26654fe7, 0x23db210a, 0xa51}}, +{ .val = {0x199facc, 0xe0e6671, 0x11905155, 0x20c2b26f, 0x30be4034, 0x2ee6b246, 0x1332a7f3, 0x31ed9085, 0x528}}, +{ .val = {0x20ccfd66, 0x27073338, 0x28c828aa, 0x10615937, 0x185f201a, 0x37735923, 0x299953f9, 0x18f6c842, 0x294}}, +{ .val = {0x10667eb3, 0x1383999c, 0x34641455, 0x830ac9b, 0x2c2f900d, 0x3bb9ac91, 0x14cca9fc, 0xc7b6421, 0x14a}}, +{ .val = {0x8333d71, 0x29c1cccc, 0x3a320a2a, 0x2418564d, 0x3617c806, 0x1ddcd648, 0x2a6654fe, 0x63db210, 0x80a5}}, +{ .val = {0x4199cd0, 0x14e0e664, 0x3d190515, 0x120c2b26, 0x1b0be403, 0xeee6b24, 0x15332a7f, 0x231ed908, 0xc052}}, +{ .val = {0x20cce68, 0x2a707332, 0x1e8c828a, 0x29061593, 0xd85f201, 0x27773592, 0xa99953f, 0x118f6c84, 0x6029}}, +{ .val = {0x1066734, 0x15383999, 0x2f464145, 0x34830ac9, 0x6c2f900, 0x33bb9ac9, 0x54cca9f, 0x28c7b642, 0x3014}}, +{ .val = {0x2083339a, 0x2a9c1ccc, 0x37a320a2, 0x1a418564, 0x23617c80, 0x39ddcd64, 0x2a6654f, 0x1463db21, 0x180a}}, +{ .val = {0x104199cd, 0x154e0e66, 0x1bd19051, 0xd20c2b2, 0x11b0be40, 0x3ceee6b2, 0x215332a7, 0xa31ed90, 0xc05}}, +{ .val = {0x820cafe, 0x2aa70731, 0xde8c828, 0x6906159, 0x8d85f20, 0x3e777359, 0x10a99953, 0x2518f6c8, 0x8602}}, +{ .val = {0x2410657f, 0x15538398, 0x26f46414, 0x34830ac, 0x246c2f90, 0x3f3bb9ac, 0x854cca9, 0x128c7b64, 0x4301}}, +{ .val = {0x120830d7, 0xaa9c1ca, 0x137a320a, 0x1a41856, 0x123617c8, 0x3f9ddcd6, 0x42a6654, 0x29463db2, 0xa180}}, +{ .val = {0x9041683, 0x554e0e3, 0x9bd1905, 0xd20c2b, 0x91b0be4, 0x1fceee6b, 0x215332a, 0x14a31ed9, 0xd0c0}}, +{ .val = {0x24820959, 0x22aa706f, 0x24de8c82, 0x690615, 0x248d85f2, 0xfe77735, 0x210a9995, 0xa518f6c, 0xe860}}, +{ .val = {0x324102c4, 0x11553835, 0x326f4641, 0x34830a, 0x3246c2f9, 0x27f3bb9a, 0x10854cca, 0x528c7b6, 0xf430}}, +{ .val = {0x39208162, 0x28aa9c1a, 0x1937a320, 0x201a4185, 0x1923617c, 0x13f9ddcd, 0x842a665, 0x29463db, 0x7a18}}, +{ .val = {0x1c9040b1, 0x14554e0d, 0x2c9bd190, 0x100d20c2, 0x2c91b0be, 0x29fceee6, 0x24215332, 0x14a31ed, 0x3d0c}}, +{ .val = {0x2e481e70, 0xa2aa704, 0x164de8c8, 0x8069061, 0x1648d85f, 0x14fe7773, 0x3210a999, 0xa518f6, 0x9e86}}, +{ .val = {0x17240f38, 0x5155382, 0x2b26f464, 0x24034830, 0x2b246c2f, 0x2a7f3bb9, 0x190854cc, 0x528c7b, 0x4f43}}, +{ .val = {0xb92079c, 0x28aa9c1, 0x15937a32, 0x3201a418, 0x35923617, 0x153f9ddc, 0x2c842a66, 0x2029463d, 0x27a1}}, +{ .val = {0x25c903ce, 0x14554e0, 0xac9bd19, 0x3900d20c, 0x1ac91b0b, 0xa9fceee, 0x36421533, 0x3014a31e, 0x13d0}}, +{ .val = {0x12e481e7, 0x20a2aa70, 0x564de8c, 0x3c806906, 0xd648d85, 0x254fe777, 0x1b210a99, 0x180a518f, 0x9e8}}, +{ .val = {0x9723f0b, 0x10515536, 0x2b26f46, 0x3e403483, 0x26b246c2, 0x32a7f3bb, 0x2d90854c, 0xc0528c7, 0x84f4}}, +{ .val = {0x4b91d9d, 0x828aa99, 0x215937a3, 0x1f201a41, 0x33592361, 0x1953f9dd, 0x36c842a6, 0x6029463, 0xc27a}}, +{ .val = {0x225c8ce6, 0x2414554a, 0x30ac9bd1, 0x2f900d20, 0x39ac91b0, 0xca9fcee, 0x3b642153, 0x3014a31, 0xe13d}}, +{ .val = {0x112e4673, 0x320a2aa5, 0x18564de8, 0x17c80690, 0x1cd648d8, 0x2654fe77, 0x3db210a9, 0x2180a518, 0x709e}}, +{ .val = {0x28972151, 0x19051550, 0xc2b26f4, 0xbe40348, 0x2e6b246c, 0x332a7f3b, 0x1ed90854, 0x10c0528c, 0xb84f}}, +{ .val = {0x144b8ec0, 0xc828aa6, 0x615937a, 0x5f201a4, 0x37359236, 0x19953f9d, 0xf6c842a, 0x28602946, 0xdc27}}, +{ .val = {0xa25c760, 0x6414553, 0x30ac9bd, 0x2f900d2, 0x3b9ac91b, 0xcca9fce, 0x7b64215, 0x343014a3, 0x6e13}}, +{ .val = {0x2512e3b0, 0x2320a2a9, 0x18564de, 0x217c8069, 0x1dcd648d, 0x26654fe7, 0x23db210a, 0x3a180a51, 0x3709}}, +{ .val = {0x328971d8, 0x11905154, 0x20c2b26f, 0x30be4034, 0x2ee6b246, 0x1332a7f3, 0x31ed9085, 0x3d0c0528, 0x1b84}}, +{ .val = {0x1944b8ec, 0x28c828aa, 0x10615937, 0x185f201a, 0x37735923, 0x299953f9, 0x18f6c842, 0x1e860294, 0xdc2}}, +{ .val = {0xca25c76, 0x34641455, 0x830ac9b, 0x2c2f900d, 0x3bb9ac91, 0x14cca9fc, 0xc7b6421, 0xf43014a, 0x6e1}}, +{ .val = {0x26512e3b, 0x3a320a2a, 0x2418564d, 0x3617c806, 0x1ddcd648, 0x2a6654fe, 0x63db210, 0x27a180a5, 0x370}}, +{ .val = {0x13289535, 0x3d190513, 0x120c2b26, 0x1b0be403, 0xeee6b24, 0x15332a7f, 0x231ed908, 0x13d0c052, 0x81b8}}, +{ .val = {0x299448b2, 0x1e8c8287, 0x29061593, 0xd85f201, 0x27773592, 0xa99953f, 0x118f6c84, 0x9e86029, 0xc0dc}}, +{ .val = {0x34ca2459, 0x2f464143, 0x34830ac9, 0x6c2f900, 0x33bb9ac9, 0x54cca9f, 0x28c7b642, 0x4f43014, 0x606e}}, +{ .val = {0x3a651044, 0x37a3209f, 0x1a418564, 0x23617c80, 0x39ddcd64, 0x2a6654f, 0x1463db21, 0x27a180a, 0xb037}}, +{ .val = {0x3d328822, 0x1bd1904f, 0xd20c2b2, 0x11b0be40, 0x3ceee6b2, 0x215332a7, 0xa31ed90, 0x213d0c05, 0x581b}}, +{ .val = {0x3e994411, 0xde8c827, 0x6906159, 0x8d85f20, 0x3e777359, 0x10a99953, 0x2518f6c8, 0x309e8602, 0x2c0d}}, +{ .val = {0x3f4ca020, 0x26f46411, 0x34830ac, 0x246c2f90, 0x3f3bb9ac, 0x854cca9, 0x128c7b64, 0x384f4301, 0x9606}}, +{ .val = {0x3fa65010, 0x137a3208, 0x1a41856, 0x123617c8, 0x3f9ddcd6, 0x42a6654, 0x29463db2, 0x1c27a180, 0x4b03}}, +{ .val = {0x1fd32808, 0x9bd1904, 0xd20c2b, 0x91b0be4, 0x1fceee6b, 0x215332a, 0x14a31ed9, 0x2e13d0c0, 0x2581}}, +{ .val = {0xfe99404, 0x24de8c82, 0x690615, 0x248d85f2, 0xfe77735, 0x210a9995, 0xa518f6c, 0x3709e860, 0x12c0}}, +{ .val = {0x7f4ca02, 0x326f4641, 0x34830a, 0x3246c2f9, 0x27f3bb9a, 0x10854cca, 0x528c7b6, 0x1b84f430, 0x960}}, +{ .val = {0x23fa6501, 0x1937a320, 0x201a4185, 0x1923617c, 0x13f9ddcd, 0x842a665, 0x29463db, 0xdc27a18, 0x4b0}}, +{ .val = {0x11fd3098, 0x2c9bd18e, 0x100d20c2, 0x2c91b0be, 0x29fceee6, 0x24215332, 0x14a31ed, 0x6e13d0c, 0x8258}}, +{ .val = {0x8fe984c, 0x164de8c7, 0x8069061, 0x1648d85f, 0x14fe7773, 0x3210a999, 0xa518f6, 0x3709e86, 0x412c}}, +{ .val = {0x247f4c26, 0x2b26f463, 0x24034830, 0x2b246c2f, 0x2a7f3bb9, 0x190854cc, 0x528c7b, 0x1b84f43, 0x2096}}, +{ .val = {0x323fa613, 0x15937a31, 0x3201a418, 0x35923617, 0x153f9ddc, 0x2c842a66, 0x2029463d, 0xdc27a1, 0x104b}}, +{ .val = {0x391fd121, 0xac9bd16, 0x3900d20c, 0x1ac91b0b, 0xa9fceee, 0x36421533, 0x3014a31e, 0x206e13d0, 0x8825}}, +{ .val = {0x1c8fe6a8, 0x564de89, 0x3c806906, 0xd648d85, 0x254fe777, 0x1b210a99, 0x180a518f, 0x303709e8, 0xc412}}, +{ .val = {0x2e47f354, 0x2b26f44, 0x3e403483, 0x26b246c2, 0x32a7f3bb, 0x2d90854c, 0xc0528c7, 0x181b84f4, 0x6209}}, +{ .val = {0x1723f9aa, 0x215937a2, 0x1f201a41, 0x33592361, 0x1953f9dd, 0x36c842a6, 0x6029463, 0x2c0dc27a, 0x3104}}, +{ .val = {0xb91fcd5, 0x30ac9bd1, 0x2f900d20, 0x39ac91b0, 0xca9fcee, 0x3b642153, 0x3014a31, 0x1606e13d, 0x1882}}, +{ .val = {0x25c8fc82, 0x18564de6, 0x17c80690, 0x1cd648d8, 0x2654fe77, 0x3db210a9, 0x2180a518, 0xb03709e, 0x8c41}}, +{ .val = {0x12e47e41, 0xc2b26f3, 0xbe40348, 0x2e6b246c, 0x332a7f3b, 0x1ed90854, 0x10c0528c, 0x2581b84f, 0x4620}}, +{ .val = {0x29723d38, 0x6159377, 0x5f201a4, 0x37359236, 0x19953f9d, 0xf6c842a, 0x28602946, 0x12c0dc27, 0xa310}}, +{ .val = {0x34b91e9c, 0x30ac9bb, 0x2f900d2, 0x3b9ac91b, 0xcca9fce, 0x7b64215, 0x343014a3, 0x9606e13, 0x5188}}, +{ .val = {0x3a5c8f4e, 0x18564dd, 0x217c8069, 0x1dcd648d, 0x26654fe7, 0x23db210a, 0x3a180a51, 0x4b03709, 0x28c4}}, +{ .val = {0x3d2e47a7, 0x20c2b26e, 0x30be4034, 0x2ee6b246, 0x1332a7f3, 0x31ed9085, 0x3d0c0528, 0x2581b84, 0x1462}}, +{ .val = {0x1e9721eb, 0x10615935, 0x185f201a, 0x37735923, 0x299953f9, 0x18f6c842, 0x1e860294, 0x12c0dc2, 0x8a31}}, +{ .val = {0x2f4b8f0d, 0x830ac98, 0x2c2f900d, 0x3bb9ac91, 0x14cca9fc, 0xc7b6421, 0xf43014a, 0x209606e1, 0xc518}}, +{ .val = {0x17a5c59e, 0x2418564a, 0x3617c806, 0x1ddcd648, 0x2a6654fe, 0x63db210, 0x27a180a5, 0x104b0370, 0xe28c}}, +{ .val = {0xbd2e2cf, 0x120c2b25, 0x1b0be403, 0xeee6b24, 0x15332a7f, 0x231ed908, 0x13d0c052, 0x82581b8, 0x7146}}, +{ .val = {0x25e96f7f, 0x29061590, 0xd85f201, 0x27773592, 0xa99953f, 0x118f6c84, 0x9e86029, 0x412c0dc, 0xb8a3}}, +{ .val = {0x12f4b5d7, 0x34830ac6, 0x6c2f900, 0x33bb9ac9, 0x54cca9f, 0x28c7b642, 0x4f43014, 0x2209606e, 0xdc51}}, +{ .val = {0x97a5903, 0x1a418561, 0x23617c80, 0x39ddcd64, 0x2a6654f, 0x1463db21, 0x27a180a, 0x3104b037, 0xee28}}, +{ .val = {0x24bd2a99, 0xd20c2ae, 0x11b0be40, 0x3ceee6b2, 0x215332a7, 0xa31ed90, 0x213d0c05, 0x1882581b, 0xf714}}, +{ .val = {0x125e9364, 0x6906155, 0x8d85f20, 0x3e777359, 0x10a99953, 0x2518f6c8, 0x309e8602, 0xc412c0d, 0xfb8a}}, +{ .val = {0x292f49b2, 0x34830aa, 0x246c2f90, 0x3f3bb9ac, 0x854cca9, 0x128c7b64, 0x384f4301, 0x6209606, 0x7dc5}}, +{ .val = {0x1497a4d9, 0x1a41855, 0x123617c8, 0x3f9ddcd6, 0x42a6654, 0x29463db2, 0x1c27a180, 0x23104b03, 0x3ee2}}, +{ .val = {0x2a4bd084, 0xd20c28, 0x91b0be4, 0x1fceee6b, 0x215332a, 0x14a31ed9, 0x2e13d0c0, 0x11882581, 0x9f71}}, +{ .val = {0x1525e842, 0x690614, 0x248d85f2, 0xfe77735, 0x210a9995, 0xa518f6c, 0x3709e860, 0x28c412c0, 0x4fb8}}, +{ .val = {0xa92f421, 0x34830a, 0x3246c2f9, 0x27f3bb9a, 0x10854cca, 0x528c7b6, 0x1b84f430, 0x14620960, 0x27dc}}, +{ .val = {0x5497828, 0x201a4183, 0x1923617c, 0x13f9ddcd, 0x842a665, 0x29463db, 0xdc27a18, 0xa3104b0, 0x93ee}}, +{ .val = {0x22a4bc14, 0x100d20c1, 0x2c91b0be, 0x29fceee6, 0x24215332, 0x14a31ed, 0x6e13d0c, 0x5188258, 0x49f7}}, +{ .val = {0x31525e0a, 0x8069060, 0x1648d85f, 0x14fe7773, 0x3210a999, 0xa518f6, 0x3709e86, 0x228c412c, 0x24fb}}, +{ .val = {0x18a92f05, 0x24034830, 0x2b246c2f, 0x2a7f3bb9, 0x190854cc, 0x528c7b, 0x1b84f43, 0x31462096, 0x127d}}, +{ .val = {0xc54959a, 0x3201a416, 0x35923617, 0x153f9ddc, 0x2c842a66, 0x2029463d, 0xdc27a1, 0x38a3104b, 0x893e}}, +{ .val = {0x62a4acd, 0x3900d20b, 0x1ac91b0b, 0xa9fceee, 0x36421533, 0x3014a31e, 0x206e13d0, 0x1c518825, 0x449f}}, +{ .val = {0x2315237e, 0x3c806903, 0xd648d85, 0x254fe777, 0x1b210a99, 0x180a518f, 0x303709e8, 0x2e28c412, 0xa24f}}, +{ .val = {0x318a91bf, 0x3e403481, 0x26b246c2, 0x32a7f3bb, 0x2d90854c, 0xc0528c7, 0x181b84f4, 0x37146209, 0x5127}}, +{ .val = {0x38c546f7, 0x1f201a3e, 0x33592361, 0x1953f9dd, 0x36c842a6, 0x6029463, 0x2c0dc27a, 0x3b8a3104, 0xa893}}, +{ .val = {0x1c62a193, 0x2f900d1d, 0x39ac91b0, 0xca9fcee, 0x3b642153, 0x3014a31, 0x1606e13d, 0x3dc51882, 0xd449}}, +{ .val = {0x2e314ee1, 0x17c8068c, 0x1cd648d8, 0x2654fe77, 0x3db210a9, 0x2180a518, 0xb03709e, 0x3ee28c41, 0xea24}}, +{ .val = {0x1718a588, 0xbe40344, 0x2e6b246c, 0x332a7f3b, 0x1ed90854, 0x10c0528c, 0x2581b84f, 0x1f714620, 0xf512}}, +{ .val = {0xb8c52c4, 0x5f201a2, 0x37359236, 0x19953f9d, 0xf6c842a, 0x28602946, 0x12c0dc27, 0xfb8a310, 0x7a89}}, +{ .val = {0x5c62962, 0x2f900d1, 0x3b9ac91b, 0xcca9fce, 0x7b64215, 0x343014a3, 0x9606e13, 0x27dc5188, 0x3d44}}, +{ .val = {0x22e314b1, 0x217c8068, 0x1dcd648d, 0x26654fe7, 0x23db210a, 0x3a180a51, 0x4b03709, 0x13ee28c4, 0x1ea2}}, +{ .val = {0x11718870, 0x30be4032, 0x2ee6b246, 0x1332a7f3, 0x31ed9085, 0x3d0c0528, 0x2581b84, 0x9f71462, 0x8f51}}, +{ .val = {0x8b8c438, 0x185f2019, 0x37735923, 0x299953f9, 0x18f6c842, 0x1e860294, 0x12c0dc2, 0x24fb8a31, 0x47a8}}, +{ .val = {0x245c621c, 0x2c2f900c, 0x3bb9ac91, 0x14cca9fc, 0xc7b6421, 0xf43014a, 0x209606e1, 0x127dc518, 0x23d4}}, +{ .val = {0x122e310e, 0x3617c806, 0x1ddcd648, 0x2a6654fe, 0x63db210, 0x27a180a5, 0x104b0370, 0x93ee28c, 0x11ea}}, +{ .val = {0x9171887, 0x1b0be403, 0xeee6b24, 0x15332a7f, 0x231ed908, 0x13d0c052, 0x82581b8, 0x49f7146, 0x8f5}}, +{ .val = {0x248b8a5b, 0xd85f1ff, 0x27773592, 0xa99953f, 0x118f6c84, 0x9e86029, 0x412c0dc, 0x224fb8a3, 0x847a}}, +{ .val = {0x3245c345, 0x6c2f8fd, 0x33bb9ac9, 0x54cca9f, 0x28c7b642, 0x4f43014, 0x2209606e, 0x1127dc51, 0xc23d}}, +{ .val = {0x3922dfba, 0x23617c7c, 0x39ddcd64, 0x2a6654f, 0x1463db21, 0x27a180a, 0x3104b037, 0x2893ee28, 0xe11e}}, +{ .val = {0x1c916fdd, 0x11b0be3e, 0x3ceee6b2, 0x215332a7, 0xa31ed90, 0x213d0c05, 0x1882581b, 0x1449f714, 0x708f}}, +{ .val = {0xe48b606, 0x8d85f1d, 0x3e777359, 0x10a99953, 0x2518f6c8, 0x309e8602, 0xc412c0d, 0x2a24fb8a, 0xb847}}, +{ .val = {0x27245b03, 0x246c2f8e, 0x3f3bb9ac, 0x854cca9, 0x128c7b64, 0x384f4301, 0x6209606, 0x35127dc5, 0x5c23}}, +{ .val = {0x13922b99, 0x123617c5, 0x3f9ddcd6, 0x42a6654, 0x29463db2, 0x1c27a180, 0x23104b03, 0x3a893ee2, 0xae11}}, +{ .val = {0x29c913e4, 0x91b0be0, 0x1fceee6b, 0x215332a, 0x14a31ed9, 0x2e13d0c0, 0x11882581, 0x3d449f71, 0xd708}}, +{ .val = {0x14e489f2, 0x248d85f0, 0xfe77735, 0x210a9995, 0xa518f6c, 0x3709e860, 0x28c412c0, 0x1ea24fb8, 0x6b84}}, +}; + +#endif + +#ifdef USE_PRECOMPUTED_CP + +const curve_point secp256k1_cp[256] = { +{.x = { .val = {0x16f81798, 0x27ca056c, 0x1ce28d95, 0x26ff36cb, 0x70b0702, 0x18a573a, 0xbbac55a, 0x199fbe77, 0x79be}}, + .y = { .val = {0x3b10d4b8, 0x311f423f, 0x28554199, 0x5ed1229, 0x1108a8fd, 0x13eff038, 0x3c4655da, 0x369dc9a8, 0x483a}}}, +{.x = { .val = {0x1c709ee5, 0x2eb026e5, 0xef3ca7a, 0x1de392e3, 0x7cd85c, 0x1501ba57, 0x17d6d304, 0x1fe5107b, 0xc604}}, + .y = { .val = {0x10cfe52a, 0xd90c6a5, 0x266d0e12, 0x3d8c994c, 0x2ceaeef7, 0x16106519, 0x1c339a3c, 0x1a3fa98f, 0x1ae1}}}, +{.x = { .val = {0x28c4cd13, 0x13ea52af, 0x2e075847, 0x1b04e403, 0xb1404cc, 0x3924124c, 0x180f3581, 0x36fc7043, 0xe493}}, + .y = { .val = {0x7739922, 0x3fa5ef71, 0x3bdfe40c, 0x19eb8cef, 0x251448d9, 0xb88263a, 0x55b7564, 0x264fa835, 0x51ed}}}, +{.x = { .val = {0x210a2a01, 0x1de13bcf, 0x1af888a6, 0x6f74179, 0xf3c2f0a, 0xe10fedc, 0x2351daff, 0x39785732, 0x2f01}}, + .y = { .val = {0x2cbde904, 0x1768b2dd, 0x25b7617b, 0x3884f5ae, 0x2d13b4c2, 0x3420a84c, 0x39949293, 0x2a29d054, 0x5c4d}}}, +{.x = { .val = {0x2a6dec0a, 0x113ba278, 0x7a5ae9c, 0x28c4da6e, 0x23e97b2, 0x6aaf087, 0x29ec5301, 0x33a4ed67, 0xe60f}}, + .y = { .val = {0x29616821, 0x7ccb339, 0xd23f0be, 0x25a24791, 0x39371012, 0x267cd3d5, 0x195929db, 0x141ce679, 0xf7e3}}}, +{.x = { .val = {0x7143e65, 0x17436f50, 0x104a61d7, 0x33ff2e26, 0x3378ceda, 0x1b81538b, 0x1a22d47b, 0x2675d3ed, 0xd301}}, + .y = { .val = {0x24106ab9, 0x16cffc7c, 0xed81960, 0x1d8330d9, 0x380651f, 0x1b7b27a6, 0x3d5c3b3d, 0x236742b8, 0x9503}}}, +{.x = { .val = {0x3874ef8b, 0xde4639b, 0x1bafd81e, 0x131bc773, 0x32823cfc, 0x147abe0, 0x2eab70b1, 0x30550b45, 0xbf23}}, + .y = { .val = {0x26831d9f, 0x370dfbf9, 0x11e2f784, 0x8bf1520, 0x1392e4c5, 0x24a282e9, 0x3737ad, 0x219bf0cc, 0x5cb3}}}, +{.x = { .val = {0x2769a24e, 0x11c1dd15, 0x5356556, 0x3d5735c0, 0x11671cbc, 0x30f427df, 0x37a06696, 0xef900cf, 0x34ff}}, + .y = { .val = {0x33cc2f1a, 0x124419e9, 0xf8b6818, 0x37c5b0fa, 0x32098c55, 0x18676260, 0x36c553f6, 0x4588e88, 0x5d9d}}}, +{.x = { .val = {0x15f51508, 0x191b88ff, 0x1ac1ca10, 0x30e72af5, 0x2de238d8, 0x29b8f85c, 0x209d9ea2, 0x98c84b1, 0x8282}}, + .y = { .val = {0x36e26caf, 0xc6dbabf, 0x37b17bed, 0x3584eb0b, 0x360ace62, 0x95ba0c2, 0x3dfe45e8, 0x2a026155, 0x11f8}}}, +{.x = { .val = {0x2f34a24d, 0x9b8b003, 0x1e159d09, 0x36f25a36, 0x3918d50a, 0x2a15ea73, 0x39ff3905, 0x1c2ca1e9, 0x4653}}, + .y = { .val = {0x333887f4, 0xbe3ec82, 0x1d37a10a, 0x23826c85, 0x2ec2c158, 0x3e2f6bf7, 0xc082a4a, 0xc6ce0da, 0x35e5}}}, +{.x = { .val = {0x2285131f, 0x16e406cb, 0x13b088d, 0x3b1bb372, 0x2d6240aa, 0x12863d9a, 0xbd77d66, 0x3aee388f, 0x241f}}, + .y = { .val = {0x2750026d, 0x2ecf99bc, 0x10cb5afa, 0x143f43ef, 0x181df8cd, 0x1082f44e, 0xf8d3d6c, 0x1e367fe5, 0x5133}}}, +{.x = { .val = {0x1b920471, 0x372d8c1a, 0x23de0de, 0xc62e17d, 0x18f8d9fc, 0x1330a60f, 0x2fa79fce, 0x36d3a85c, 0x5d1b}}, + .y = { .val = {0x37b83103, 0xcc199b, 0x2c56e7b7, 0x3ac7a665, 0x22265679, 0x2ee650e2, 0x39e2e794, 0x2099de4d, 0x2843}}}, +{.x = { .val = {0x11e5b739, 0xff396d5, 0x12222ed7, 0x2e4e0cff, 0x3c846de0, 0x26731b1b, 0x3865a72f, 0x567dca2, 0x175e}}, + .y = { .val = {0x29fed695, 0x3be9bffb, 0x124345c6, 0x2d6556b7, 0x371f5eac, 0x3e5e947f, 0x79eba4e, 0x1b83678f, 0xd350}}}, +{.x = { .val = {0x6bc47d6, 0x39e01279, 0x2da121bc, 0x3f7fad71, 0x39c62130, 0x3ef32384, 0x332d7a5f, 0x4fc0ff, 0x423a}}, + .y = { .val = {0xb548a34, 0x48db9b6, 0x24f009ed, 0x363b0d4, 0x36b3c772, 0x1e7deeeb, 0x1d970a11, 0x3803f878, 0xb91a}}}, +{.x = { .val = {0x416824a, 0xb7dbde, 0x33e27413, 0x37d98bce, 0x16877649, 0x1e9eaf3, 0x3b905089, 0x1a916b07, 0x111d}}, + .y = { .val = {0x2108e9d0, 0x26844750, 0x2daca4ca, 0x1c002265, 0x65952f0, 0x35236ffc, 0x2affbb90, 0x244711e3, 0x696}}}, +{.x = { .val = {0x1bced775, 0x2d7b7780, 0x2f74e56a, 0x242da297, 0x39dcff72, 0x2576faf2, 0x3c8b8ad7, 0x1b725eb1, 0x4a4a}}, + .y = { .val = {0x278dd66d, 0xafe3da2, 0x24742acb, 0x3a4336d0, 0xf4571d, 0x3be7dce7, 0x31e72943, 0x46c0598, 0x5299}}}, +{.x = { .val = {0x3ff4640, 0x9aeb63e, 0x1552ffe5, 0x11071f95, 0x262ee053, 0x3ab016d8, 0xc9c99c, 0x243511ec, 0x363d}}, + .y = { .val = {0x3bee9de9, 0x800f1fc, 0x199ecb6, 0x2e6a2402, 0x33363145, 0x2d114e5f, 0x32221953, 0x1ceb7f1c, 0x4e2}}}, +{.x = { .val = {0x2f92c541, 0x9c4a972, 0x2dfb59dd, 0x18bec04b, 0x3b02bf0b, 0x25cf1b24, 0x27e9b553, 0x2619bb66, 0x4c1b}}, + .y = { .val = {0x68fe020, 0xb13cff7, 0x3eb1ad7, 0x14bab5f9, 0x16e69cc6, 0x32dd4f39, 0x28a0f7fb, 0x24b4c82f, 0xc1f7}}}, +{.x = { .val = {0x3eaaf3d1, 0x323ca32, 0x228f135e, 0xcfb6f06, 0xb54e32, 0x28bcf01e, 0x3b12b529, 0xe1deea0, 0xa408}}, + .y = { .val = {0x30b254b9, 0x4ad4d37, 0x2d1ef90b, 0x79d5db, 0x21b3e220, 0x3e0f5a4d, 0x3bc79b8b, 0x3d84bfbb, 0x40e9}}}, +{.x = { .val = {0x3940d33a, 0x334f6d69, 0x14203b98, 0x3620291, 0x16c86f6e, 0x38f868bd, 0xc0b53a4, 0x319074a3, 0xa804}}, + .y = { .val = {0x2d46967a, 0xf3a57e9, 0xf736a94, 0x3c632a27, 0x2047e81a, 0x30a10b05, 0x3a6d03de, 0x20c94acb, 0x95be}}}, +{.x = { .val = {0x1ffdf80c, 0x27de6957, 0x15bcd1b6, 0x3929e068, 0x5638843, 0x912d6dd, 0x3c2be8c6, 0x17c5977c, 0x8b4b}}, + .y = { .val = {0x1fd4fd36, 0xfbfc319, 0x162ee56b, 0x38cd9518, 0x30da04f9, 0x2f5e04ea, 0x308b4b3f, 0x29bda34, 0x4aad}}}, +{.x = { .val = {0x755e4be, 0x2cfc99c5, 0x17c997ab, 0x2bd93b90, 0x3c611071, 0x5f1fb20, 0x291718ce, 0x1739384c, 0xed0c}}, + .y = { .val = {0x207bf42f, 0xfe7e9ba, 0x23ddab16, 0x364e495d, 0x3ea68049, 0x36b5fd69, 0x345bdbf3, 0x27f1ef08, 0x221a}}}, +{.x = { .val = {0x7cec8ab, 0x12db9b20, 0x20552ced, 0xc95159b, 0x31fae8e5, 0x570fe0f, 0xe694b3b, 0x2c04f113, 0xfaec}}, + .y = { .val = {0x2b155070, 0x26077f66, 0x5e2e2e8, 0xcaca1ae, 0x2fb13d9c, 0x380b1bb0, 0x2cb57fc2, 0x2d7a43a7, 0xcc09}}}, +{.x = { .val = {0x1ad1b1f7, 0x1fd93aba, 0x323cd3e0, 0x2cb76093, 0xbcafdb3, 0xc682cdf, 0x2d2f2c87, 0x2284cb72, 0x9bb}}, + .y = { .val = {0x3811c80, 0x104c189f, 0x752d536, 0x152a103d, 0x63e850f, 0x2774a13e, 0x2e3b9b6f, 0x2cacabfb, 0x945b}}}, +{.x = { .val = {0x1232fcda, 0x2d845649, 0x2c0e77bc, 0x36ffe9, 0x1548c7b7, 0x1dc7002f, 0x3996d6bf, 0x2ea9b976, 0x723c}}, + .y = { .val = {0x1eb39f5f, 0x7701a76, 0x37949480, 0x1828194d, 0x24d6e26, 0x44dd222, 0xc498a92, 0x19ed5657, 0x96e8}}}, +{.x = { .val = {0xca030d5, 0x3f4e0f58, 0x39849071, 0x90290c1, 0x33a3c62d, 0x35f7115d, 0x3744d343, 0x29e190de, 0x57ef}}, + .y = { .val = {0x34b02f9e, 0x1ead109, 0x1e9974ab, 0x26db4ab9, 0x1e03ec68, 0x189f24a3, 0x8518893, 0x36c2f46d, 0xd712}}}, +{.x = { .val = {0xc584dd5, 0x3ebf1ddc, 0x27b012a7, 0x2015df8c, 0x226cb910, 0x3dfa7354, 0xbc42a2d, 0x2f50da8a, 0x264b}}, + .y = { .val = {0x3704ab11, 0x18489e4d, 0x17b8d8de, 0x46090dc, 0x33be226a, 0x1d738930, 0x93b4d4f, 0x1bea53b8, 0xd87c}}}, +{.x = { .val = {0xb2438e8, 0x2fc9af61, 0x1bdec9d2, 0x22f187f5, 0x36a79da7, 0x21701588, 0xd2bbdac, 0x19492f50, 0xa94c}}, + .y = { .val = {0x318661f4, 0xb8b236f, 0xe39b2bc, 0x174f1828, 0x19e3a7e, 0x24865414, 0x16280fd7, 0x7f664be, 0xb520}}}, +{.x = { .val = {0xe7dd7fa, 0x294cfb28, 0x3a919839, 0x11e5848d, 0x2d3b509, 0x3fbb204b, 0x2bf98ba5, 0x293524ef, 0xeebf}}, + .y = { .val = {0x21de8999, 0x37f53f6b, 0x311f712d, 0x393370e9, 0x38089d9a, 0x39fb6bc5, 0x2f0f269e, 0x2328e5c3, 0x5d9a}}}, +{.x = { .val = {0x7d297fd, 0x1afba421, 0x36766d67, 0x3a92f023, 0x18495fc4, 0x3180c704, 0x17bfda61, 0x12b5e9ea, 0x381c}}, + .y = { .val = {0x3d493fc5, 0xeb38c61, 0x3939c009, 0x11440cb6, 0x115eccf0, 0x397e9c26, 0x2eee48f3, 0x3d4ec8e3, 0x936a}}}, +{.x = { .val = {0x2ede454c, 0x1235c108, 0x3dd08b24, 0x3c7417fb, 0x138c479c, 0x420c765, 0x1c63bcce, 0x2e73416b, 0xe1ef}}, + .y = { .val = {0x28913797, 0x367f48ce, 0x3a2d4c6a, 0x138c9129, 0x7712346, 0x15307ff9, 0x39be7b01, 0x114c362b, 0xecb}}}, +{.x = { .val = {0x29eb99a4, 0xcffbacc, 0x3d47b18d, 0x395067cc, 0x3475a8c7, 0x308d7a6b, 0x17010c5a, 0x3e6c689a, 0x5318}}, + .y = { .val = {0x3e91f92d, 0x31c9bbbb, 0x1e3ec652, 0x7cad034, 0x3405e8a4, 0xb64ebae, 0x1a419577, 0x33fad2fb, 0xf44c}}}, +{.x = { .val = {0x39a48db0, 0x3f5e0d6c, 0x33c03bfe, 0x48568a6, 0x3bde459f, 0x742826d, 0x27167279, 0x11369a5b, 0x100f}}, + .y = { .val = {0x2bc65a09, 0x3ef57358, 0x35195ac0, 0x3fd2863f, 0x90666b7, 0x23ccc030, 0xb772ec, 0x384c64a8, 0xcdd9}}}, +{.x = { .val = {0x1e4df706, 0x2c14a13c, 0x37d08084, 0x36723e48, 0xc4199d8, 0x577fcad, 0x1c771a84, 0x227cb3ad, 0x8c09}}, + .y = { .val = {0x1d72fa98, 0xdab168d, 0x16511aa7, 0x379afd45, 0x1c966c60, 0x85cb2e7, 0x32034ffd, 0x2f4113d0, 0xfb4d}}}, +{.x = { .val = {0x1c47bffd, 0x798f0cf, 0x95bc1bb, 0x14a14e6f, 0x22c0259c, 0x1205d0c9, 0x26704c4a, 0x54f1789, 0xfb8f}}, + .y = { .val = {0x1949b095, 0x24291777, 0x5426130, 0x3784e26b, 0x3ccd531d, 0x284766d2, 0x621816f, 0x1ea77178, 0x6ca2}}}, +{.x = { .val = {0xbb2629a, 0x23e86e2d, 0x337a7b8b, 0x280b161d, 0x28708465, 0x3327c29c, 0x151755a0, 0xccff5d7, 0xe747}}, + .y = { .val = {0x2946f6d6, 0x3e365869, 0x21a969a9, 0x20ddaa9b, 0xc2581c8, 0x10d80e01, 0x30c114cc, 0x3f805141, 0xf2af}}}, +{.x = { .val = {0x2534fd2d, 0x322b379b, 0xf3b3852, 0x1fe35119, 0x4c017a7, 0x2489e928, 0x3ed1b1dc, 0x6f898b1, 0xe103}}, + .y = { .val = {0x1456a00d, 0x113c63ca, 0x21ced79a, 0x24b75067, 0x17535af2, 0x1a905d96, 0x405e6bb, 0x1864a250, 0x9d70}}}, +{.x = { .val = {0x295c8356, 0x1389f8da, 0x294d8578, 0x229ab177, 0x29b2c902, 0x2577343c, 0x89eab9f, 0xfc89320, 0xf4b9}}, + .y = { .val = {0x3e001fd3, 0x356186e6, 0x115609ab, 0x1fbc4d12, 0xeee90c3, 0x17da9e90, 0x162dfb0e, 0x24bb018a, 0xa67a}}}, +{.x = { .val = {0x3b160e8a, 0x358bf85, 0x17e696c2, 0x7a144be, 0x1b08b0d5, 0x188ba809, 0x15236b19, 0x2b287f39, 0x9d1}}, + .y = { .val = {0x3ca04c44, 0x13814315, 0x212b5e53, 0x3a783ba4, 0x18c27e6f, 0x19a4b383, 0x1f0c63e5, 0x623d440, 0x1153}}}, +{.x = { .val = {0x35ba7fc2, 0x25f5f411, 0x3c39562e, 0x22cea4ef, 0x21cde751, 0xab5e4e0, 0x2b9e18a, 0x16731153, 0xc66c}}, + .y = { .val = {0x375f5956, 0x3b0f1a73, 0x15955977, 0x298376c, 0x10cb2f0, 0x13cf3aab, 0x30fcfbea, 0xbf8afec, 0xd959}}}, +{.x = { .val = {0x1094696d, 0x3579a236, 0x1d6af52, 0x3e2c99a9, 0x3bd7ec5c, 0xa0e7c50, 0x15b530ac, 0x1b2b91b5, 0xfeea}}, + .y = { .val = {0x18090088, 0x5577afc, 0x41442d3, 0x72255f3, 0x3ecd5c98, 0x39384afc, 0xe1bab06, 0x1adb25f7, 0xe57c}}}, +{.x = { .val = {0x2e752b08, 0x2a90102b, 0x331a1870, 0x7b2b82c, 0x32e17914, 0x986be76, 0x387e1c53, 0x2d886b6, 0x4d00}}, + .y = { .val = {0x8302cea, 0x39ca147d, 0x1c7293a3, 0x1f7d7c46, 0x1972cccb, 0x3609560b, 0xd255cb6, 0x16e3c638, 0x6a0d}}}, +{.x = { .val = {0x75c58ef, 0x22658bf5, 0x21f1b77f, 0x15e8100f, 0x317128d6, 0x28988451, 0x1a05dd6a, 0x1c32880f, 0x71f5}}, + .y = { .val = {0x135d420e, 0x219269cb, 0x3363e7df, 0x11174030, 0x95b8df2, 0x155cd16f, 0x880dd25, 0x1056e577, 0xeb42}}}, +{.x = { .val = {0x3ff8359, 0x122c181, 0x25e76516, 0x2d208771, 0x1da01446, 0xa0ad708, 0x3d253b7d, 0x2cd8a7de, 0xa2b7}}, + .y = { .val = {0x3e86fec2, 0x8e5ffb3, 0x6f3835a, 0x34420d41, 0x1e29c910, 0x24de8fdc, 0x1122d57a, 0xe2505a5, 0x6930}}}, +{.x = { .val = {0x1ec6cb1, 0xfea5e2f, 0x8583de3, 0x3b595f60, 0x3fca3cfe, 0x1ef92f9b, 0x9cdcb36, 0x2a476441, 0xda67}}, + .y = { .val = {0x3a68be1d, 0x3a7aa389, 0xf740a17, 0x31eb7142, 0x1780e5de, 0x118fdfb2, 0x242bc41f, 0x2a8d5205, 0x9bac}}}, +{.x = { .val = {0x1fe741c9, 0x3b8f3208, 0xea5a835, 0x2f67cd73, 0xd8718b, 0x3033eabc, 0x1ef587c0, 0x334d97e8, 0x4dba}}, + .y = { .val = {0x338eb623, 0x2f843e0, 0x3c0535f6, 0x30e12827, 0x38299d0c, 0x33f567a0, 0x1892e7fd, 0x1503a294, 0x16c3}}}, +{.x = { .val = {0x34e218da, 0x1fb6a2ea, 0x26860508, 0x13217c54, 0x1c2590f, 0x3c5f63fd, 0x9beee68, 0x3ff12054, 0x13d1}}, + .y = { .val = {0x1b191c19, 0x36d0677, 0x15bd127e, 0x2b40481b, 0x3758bda4, 0x2e4cdec6, 0x1961dcec, 0xe47ea64, 0x6008}}}, +{.x = { .val = {0x22e96db8, 0xced032a, 0x229dbff1, 0x327645b3, 0x30533b3c, 0x271e7116, 0x6000765, 0x13e73bdb, 0x219b}}, + .y = { .val = {0xd3b6bc7, 0x1f7c069e, 0x29057652, 0x13e2b14f, 0x372a6e39, 0x11060300, 0x1efeaf5a, 0x31817656, 0x24d9}}}, +{.x = { .val = {0x1a37b7c0, 0x1d517330, 0x311069f5, 0x2343dee, 0x322151ec, 0x24d7b, 0x34cdda6e, 0x13ea82cc, 0x5390}}, + .y = { .val = {0x22771c8, 0x372c25ac, 0x14434699, 0x26666078, 0xd3c1c13, 0x27b32b08, 0x106d88c, 0x21f42f20, 0x5bc0}}}, +{.x = { .val = {0x38a47ca9, 0x1f343c7c, 0x10f85ad5, 0x1bb9eaab, 0x16995d2a, 0x2644658c, 0x146753cf, 0x1d6be750, 0x1a5}}, + .y = { .val = {0x37ebcdb7, 0x1f177cb9, 0x34d7ea66, 0x2e4f1767, 0x3b8698bd, 0x17f14b86, 0x20dc3cc5, 0x3c72e2ac, 0x3038}}}, +{.x = { .val = {0x2315565b, 0xc275d57, 0x3c20c6ee, 0x2986a0f4, 0x2155d6d3, 0x7d706dd, 0x1d439ca7, 0x3810dd88, 0xf5f0}}, + .y = { .val = {0x1d2ecc82, 0x1e10c2bf, 0x2d7e40a6, 0x2fd86fcf, 0x37101aa5, 0x6245837, 0x2052bf62, 0x1398af96, 0x6b9f}}}, +{.x = { .val = {0x35362d33, 0x2f9e0767, 0x2227642c, 0x32f24851, 0xca4e347, 0x1fcdb65c, 0x36e9a57a, 0x1bc2db02, 0x8f50}}, + .y = { .val = {0x7fa243f, 0x121f432, 0x3bb8eaf3, 0x33e49750, 0x1c336848, 0x315093c, 0x26171953, 0x25574abe, 0x469f}}}, +{.x = { .val = {0x3ad86047, 0x3fe567d0, 0x29b8bcae, 0x2d4e810e, 0xa906779, 0x3329dd93, 0x183a7719, 0x3342f4d6, 0x8e7b}}, + .y = { .val = {0x460372a, 0x284011fa, 0x3fd68b3e, 0x3a238b91, 0x29514579, 0xc410832, 0x1a4b3940, 0x1dc2ca8f, 0x10b7}}}, +{.x = { .val = {0x313f0351, 0x1f4a022f, 0x10389e77, 0x3056e34f, 0x2950df3b, 0x3cc6665, 0x2729dc35, 0x16ea8657, 0x33b3}}, + .y = { .val = {0xb8d7418, 0x2f140f33, 0x889b702, 0x19583bef, 0xd52bcaa, 0x1900d892, 0x2bf87f94, 0x615902, 0xa58a}}}, +{.x = { .val = {0x414bb36, 0x1c771ec9, 0x2d7bca6d, 0x3db84272, 0x1f7e2256, 0x20eb481c, 0x13f955cb, 0x3bab88b2, 0x374d}}, + .y = { .val = {0xdaf734a, 0x21d6faa6, 0xe543217, 0xa3598c0, 0x6f72938, 0xcb01be0, 0x14f99160, 0x196d93f3, 0x1711}}}, +{.x = { .val = {0x2ae7d616, 0x3a2992b5, 0x22a9f0c5, 0x136ebcad, 0x2eb0dc94, 0x1b81ce56, 0x2eae57c4, 0x30271fce, 0x2380}}, + .y = { .val = {0x161bbc1a, 0x266f920, 0x38467560, 0x2be48523, 0x9b09a93, 0x262bbf54, 0x956af15, 0x21864d19, 0x6f8e}}}, +{.x = { .val = {0x19c43862, 0x2a107856, 0x397e6690, 0x29fd3c60, 0x381bde71, 0x2061a26, 0x1ff21e6d, 0x3b4d3073, 0x385e}}, + .y = { .val = {0x142e5453, 0x1163f95, 0x86dc8cc, 0xc13bb08, 0x2bf4576b, 0x77867a7, 0x223f5670, 0x3af0fa3a, 0x283b}}}, +{.x = { .val = {0x38f2827c, 0x320e89c1, 0x2fc1ce2d, 0x320990af, 0x1f67d147, 0x1af84d35, 0x35480045, 0x8820f6b, 0xf6f6}}, + .y = { .val = {0x20aaa102, 0x56c82d4, 0x321bf6d, 0x15f29d12, 0x27cee7e6, 0x315c56cd, 0x33a0faf2, 0x13a05f79, 0x1bcd}}}, +{.x = { .val = {0x315adcb6, 0x3624c825, 0x18c6f369, 0x2470f39f, 0x1fc255cd, 0x32cf0f4, 0x13de2bd7, 0x394623e5, 0xfb26}}, + .y = { .val = {0x18ba68f3, 0x276f28ed, 0xb7ab544, 0x34b2cc6e, 0x10176916, 0x211a9c67, 0x2a34d58e, 0xa204404, 0xf3e1}}}, +{.x = { .val = {0x20788c1e, 0x35136dd5, 0x28bd1d7e, 0x230dc183, 0x3ceab7d1, 0x171af1d8, 0x1132d28f, 0x896446e, 0x8991}}, + .y = { .val = {0xe8f0ef1, 0xd71088a, 0x1ef9e116, 0x25a7213f, 0x3136fa36, 0x21d8d566, 0x1ac9b27b, 0x13661f32, 0xda8b}}}, +{.x = { .val = {0x3fac3a7, 0x181bb61b, 0x147fbc9c, 0x377e1296, 0x3dfa180f, 0x31ce9104, 0xf191637, 0x366e00fb, 0x6f9}}, + .y = { .val = {0x3a842160, 0x21a24180, 0x281002d, 0x29374bd7, 0x5c4d47e, 0x238a8c39, 0x59ba69b, 0x31a3980c, 0x7c80}}}, +{.x = { .val = {0xb7fd72d, 0x327489d1, 0x3e4da175, 0x5d17969, 0x82939da, 0x30db0a11, 0x3411c1cd, 0x3bba894a, 0xae86}}, + .y = { .val = {0xeee38bc, 0xcd32de9, 0x72f7282, 0x24845545, 0x1ff0e98d, 0x2c2b3962, 0x302f962a, 0x24f25c1c, 0x19e9}}}, +{.x = { .val = {0x3c169290, 0x2851d099, 0x336f2ee7, 0x62f9d73, 0x1c2c4887, 0x34be315b, 0x3ff55e61, 0x327e42ef, 0x2248}}, + .y = { .val = {0x83ea257, 0x1a76284a, 0x1da2be23, 0x18dd408d, 0x35ba18e1, 0x1aed56d0, 0x1eed7a50, 0x251a4b48, 0xfa05}}}, +{.x = { .val = {0x350964e3, 0x3436b12e, 0x11c6f76f, 0x27c21df7, 0x85d0a9, 0x46d2365, 0x44074ac, 0x1b85b817, 0xe11a}}, + .y = { .val = {0x682bfc8, 0x19fefe2c, 0x318c6f7, 0x2b71b84e, 0x30af2417, 0x3578965b, 0x2d430e1a, 0x196e1e8, 0x87d6}}}, +{.x = { .val = {0x2d0e6bd, 0xedf839d, 0x30f5e531, 0x1d3458f6, 0xd6ecbf7, 0x851f041, 0x4e2582a, 0x3500490f, 0x3322}}, + .y = { .val = {0x2c28b2a0, 0x13ce8ba5, 0x2873af62, 0x17d8fa8, 0x1af9b728, 0x66f137, 0x24ef5bfb, 0x1e5fa59, 0x56e7}}}, +{.x = { .val = {0xade462, 0x31a5b4cb, 0x2dbcf29f, 0x1337723a, 0x80cd50d, 0x3bcc6c13, 0x2bdae120, 0x8009433, 0x8d26}}, + .y = { .val = {0xf26470c, 0x2382a2e4, 0x2678b3ad, 0x12bed39c, 0x2e36ba1d, 0x3dbcb70f, 0x3f437d31, 0xeed1c56, 0xebed}}}, +{.x = { .val = {0x1516e633, 0x59190f8, 0x32d9c8b9, 0x3524c341, 0x14d03b8e, 0x1a287d6, 0x2bea9ce4, 0x301d9bab, 0x1238}}, + .y = { .val = {0x77b7805, 0x1736dca3, 0x7402280, 0x11894b73, 0x3dc1709, 0x25e78b47, 0x31359d6c, 0x2c0b6ec9, 0x8a9d}}}, +{.x = { .val = {0x388e7a66, 0x26c05549, 0x30ec2161, 0x3735ca0a, 0x2a11b9cd, 0xba9d629, 0x39c15e7b, 0x16c1dc32, 0x271d}}, + .y = { .val = {0x203c9727, 0x2a35c963, 0x8a824e7, 0x281978d4, 0x2c877fe2, 0x1f426526, 0x3f491e45, 0x29160d39, 0x5d3a}}}, +{.x = { .val = {0x134ab83, 0x875d34a, 0x36433977, 0x6cfe6bd, 0x26586874, 0x5dc3625, 0xb7da2bd, 0xb1f4b78, 0x8567}}, + .y = { .val = {0x390313a6, 0x238c253d, 0x1298f44c, 0x1fc5ff31, 0x22c2e5e7, 0x10126fe9, 0x3b2eb637, 0x6e6d6d0, 0x7c48}}}, +{.x = { .val = {0x1f17fc25, 0x262e42f0, 0x32e6d969, 0x227a91b7, 0x8a61f3b, 0x6184857, 0x39ec036c, 0x33dadd03, 0x534c}}, + .y = { .val = {0xfe86e76, 0x1c71fdbb, 0x3dd28ddd, 0x38f49def, 0x1543550a, 0x2b8f74cb, 0x32ddb462, 0x172c2722, 0xd571}}}, +{.x = { .val = {0x28bee8b6, 0x1c5c248f, 0xfbc8d2c, 0x8351fb, 0x38aaed79, 0x38508063, 0x3b7f3081, 0x7d73ba1, 0xa91d}}, + .y = { .val = {0x10644c1, 0xf45aa9, 0x28cb2250, 0x15a7d8, 0x1ad3b2f8, 0x6272377, 0x38ee15a7, 0xc93b8b7, 0x748a}}}, +{.x = { .val = {0x1984cf74, 0x28687095, 0x2f61f10a, 0xd6b916f, 0x14383c07, 0x853778b, 0x8e35c1a, 0x2308f643, 0xc15c}}, + .y = { .val = {0x39ccb000, 0x12923360, 0xb015a2c, 0x2fddcb54, 0x1fd7ba47, 0x31bd1789, 0x22235c8d, 0x15360a14, 0x2ba9}}}, +{.x = { .val = {0x20c82a0a, 0x3f6566bd, 0x3668832f, 0x2489b183, 0x1413b10f, 0x1b27c646, 0x188a46b0, 0x2fe026c6, 0x948}}, + .y = { .val = {0x18c8e589, 0x132dfe23, 0x17cd2bed, 0x137fc232, 0x3418c6d, 0x2dd31747, 0x36646dc6, 0x18a15b72, 0x53a5}}}, +{.x = { .val = {0x3e8b000a, 0x25bac115, 0x2825e513, 0x5b04cc7, 0x11f0b6ef, 0x3393198a, 0x259360d5, 0xb1fcdcb, 0x2695}}, + .y = { .val = {0x5ef705a, 0x30f5007c, 0x13d67318, 0x2f8e63d9, 0x288422de, 0x3224f4b5, 0xa68862b, 0x3a931600, 0xf513}}}, +{.x = { .val = {0x36134f96, 0x4096225, 0x2d6b0e9f, 0x846595c, 0x1ff243f5, 0xafa2c4c, 0x3c5bdbef, 0x1639bf08, 0xc62e}}, + .y = { .val = {0x114cf97e, 0x89dfb53, 0x3731c3e8, 0x3ee14d58, 0x141fc5bc, 0x359d9d4c, 0x1a1678c3, 0x209f516c, 0x4397}}}, +{.x = { .val = {0xb188cbb, 0x1a1be200, 0x7de973, 0x700c802, 0x2622b0b8, 0xcca69c5, 0x5c74168, 0x181483bb, 0x1074}}, + .y = { .val = {0x1f272124, 0x75ed8d8, 0x1ce3da60, 0xb835d23, 0x354a1124, 0x9ae6e73, 0x1598c353, 0x35302688, 0xabe5}}}, +{.x = { .val = {0x338fd8e8, 0x33b36067, 0x69752ac, 0x2c39137f, 0x2873a8f1, 0x19f383c0, 0x1c34f0, 0x339fd186, 0x6260}}, + .y = { .val = {0x32b4ae17, 0x6a13a56, 0x51c198c, 0x34a488e0, 0x2a1ef7ec, 0x24125dd, 0x1b571a7f, 0x2a0adbe9, 0xbc2d}}}, +{.x = { .val = {0x3d477c2d, 0x1d99d1bc, 0x2aad27e0, 0x39971465, 0xf1a1316, 0x21026fa1, 0x11a73dec, 0x3691d22b, 0x85d8}}, + .y = { .val = {0x7d1dd70, 0x1e605bf, 0x3c4d5a62, 0x2c28080c, 0x2fc7bc94, 0x2d4d94c7, 0x6690586, 0x22d4d997, 0x5894}}}, +{.x = { .val = {0x2c0b80d9, 0x2140c4b5, 0x3dc47f04, 0x79f8403, 0x3ee3ee4d, 0x224ba730, 0x4b968c0, 0x1c59b9fb, 0x8e2a}}, + .y = { .val = {0x16b29f50, 0x27187cab, 0x306349a4, 0x25eda235, 0x2a9d4852, 0x374a6dc5, 0xbe592ce, 0x2ea6b8b, 0xeadb}}}, +{.x = { .val = {0x2c4561be, 0x2487e8f4, 0x359d90f9, 0x12acba04, 0xf8950ee, 0xd9bb35e, 0x3f58edc8, 0x31d610af, 0x769b}}, + .y = { .val = {0x30d9685f, 0x16482ffe, 0x37873add, 0x285ddd9e, 0x3f5d4741, 0x33933bdc, 0x383bac8d, 0x5cd8bf9, 0x4bf8}}}, +{.x = { .val = {0x2037fa2d, 0x254f3234, 0x1bfdc432, 0xfb23d5d, 0x3f410304, 0xd21052e, 0x1d8d43d8, 0x1f782bf0, 0xe503}}, + .y = { .val = {0x1d755bda, 0x3977210, 0x481f10e, 0x17d6c0fb, 0x190bddbd, 0x263427ee, 0xd3b5f9f, 0x14d2eaa5, 0x4571}}}, +{.x = { .val = {0x1e3d34ef, 0x318f231e, 0x12a2ddb8, 0x2ac85f1e, 0x161b3ec3, 0x2db3df4b, 0x15494f40, 0x36919ff, 0xa5e0}}, + .y = { .val = {0x2f7adb4c, 0x21571738, 0x10900acb, 0x18373f9e, 0x3f43d25b, 0x1c9bfa66, 0x8555421, 0x397d7958, 0x98f}}}, +{.x = { .val = {0x17b91252, 0x19cdc583, 0x77572ae, 0x12bf4b91, 0x1bfbc46d, 0x27d2ec72, 0x22b40351, 0x57d7bce, 0xa994}}, + .y = { .val = {0xbedc264, 0xe8ddeb1, 0x10f4ddd7, 0x2685ab56, 0x36f6b689, 0xbc43c93, 0x1f84bb9e, 0x39932ba0, 0x82d0}}}, +{.x = { .val = {0x2a540f17, 0x231196d9, 0x30c132bd, 0x1d435c17, 0x3935f84c, 0x3b778263, 0x3d1fc7d8, 0x13a7e793, 0xb56f}}, + .y = { .val = {0x200102d, 0x1a8bf2b8, 0x3cca8544, 0x350a58f2, 0x182d1d21, 0x3046b7c1, 0xa856d3d, 0x394d0a73, 0x32e8}}}, +{.x = { .val = {0x24fce725, 0x1619a82b, 0x2a6c5b72, 0x3a36f471, 0x1771b4e7, 0x2a417a3c, 0x207adf5e, 0x1cac3d28, 0xe063}}, + .y = { .val = {0xeee31dd, 0x9c0d3e5, 0x3104870b, 0x12129de1, 0x1a488cd7, 0x9eecab5, 0x18cfe12a, 0x225d2f38, 0x7a90}}}, +{.x = { .val = {0x3ed2ff3e, 0x3826bb90, 0x2c6ed3cf, 0x17aff6d3, 0x2d3f3c04, 0x36f4c13e, 0x6b8f9c8, 0x4d32881, 0xeac}}, + .y = { .val = {0x3d210988, 0x5c81881, 0x3f21376e, 0x67da5ad, 0x311799ac, 0x3c40efca, 0x19b4245b, 0x36f9e4d, 0x4963}}}, +{.x = { .val = {0x1fbfa4dc, 0x1d9c1b93, 0xc85b174, 0x25229e01, 0x1bb41ff5, 0x84675eb, 0x3ea19839, 0x21641cc7, 0xd678}}, + .y = { .val = {0x3d3b5406, 0x29ef35ae, 0x1c9a07cc, 0x1bc7137, 0x1c13aa62, 0x3bd71b48, 0x63c4940, 0x2a322754, 0x28ea}}}, +{.x = { .val = {0x248ff9b3, 0x9d7ed03, 0x199b01a7, 0x2c698815, 0x371d4bc7, 0x3c843c4a, 0x40974ab, 0x3f32f668, 0x6930}}, + .y = { .val = {0xee96a4e, 0x3f76ad7e, 0xacc51ac, 0x3e6c4f9, 0x1f6d7809, 0x3f36e1d, 0x301eada3, 0x2ba52e51, 0x7f02}}}, +{.x = { .val = {0x10559754, 0x2b5a423, 0x2a3f5854, 0x2c42f778, 0xce02204, 0x2efe770, 0x1d45358d, 0x1e9c5735, 0x213c}}, + .y = { .val = {0x34b458f2, 0x3fcb09d4, 0x36a7eedd, 0x12143d7c, 0x1ba190bb, 0xeb41891, 0x6250701, 0x2b42d6b9, 0x4b6d}}}, +{.x = { .val = {0xec87fac, 0x264e2578, 0x22e7cf08, 0x6ae5d18, 0x23480e0d, 0x3a7fb60c, 0x9a7f66a, 0x15204cad, 0x1c5e}}, + .y = { .val = {0x1fc2d4ef, 0x1575ecf5, 0x2fe324c5, 0x37ab3ac9, 0xc2ad3a3, 0x2567e875, 0x3468f2bb, 0x3d83e0df, 0x4ffc}}}, +{.x = { .val = {0x14531dbc, 0x83f2e87, 0x2d5c970e, 0x2407067f, 0x3bc7ce1f, 0x1ba50842, 0x1668ddef, 0x1b4180b1, 0x4627}}, + .y = { .val = {0x1686b8e2, 0x3e1cc026, 0x3e1bc99a, 0x22eb7eff, 0xded9949, 0x248a1d5c, 0x75b84a2, 0x1fc93513, 0xe0f}}}, +{.x = { .val = {0x122f001d, 0x453bc4d, 0x78d8996, 0x14382b37, 0x31916368, 0x17ac8470, 0x2c24f4e6, 0x1a3b29e9, 0xefea}}, + .y = { .val = {0x33bc4415, 0x4a1067d, 0x3848771c, 0x4e567ec, 0x319a17e4, 0x140c1e8d, 0x3c14da1, 0x11e1a756, 0xaab8}}}, +{.x = { .val = {0x8fbd53c, 0x330e8ec, 0x1c62cddf, 0x20e31c2b, 0x19a87e2, 0x2e4d4a95, 0xb34e8db, 0x9ca9ebd, 0x4e7c}}, + .y = { .val = {0x17dcaae6, 0x2ce5060, 0x3f7dd33e, 0x2e5852f, 0x2f681b53, 0x3f427db7, 0x10b18e16, 0x271d9b27, 0x1774}}}, +{.x = { .val = {0x3c6e1b4d, 0xa0879b9, 0x3ef8790e, 0x47c9686, 0x385d9c9b, 0x289a7d38, 0x2888f268, 0x5ec09a5, 0x8990}}, + .y = { .val = {0x1814ab2b, 0x26baf6b, 0x132b2120, 0x3946f03e, 0x358bfae4, 0x15e60cd8, 0x334f0bb4, 0xb36ad6c, 0x43ae}}}, +{.x = { .val = {0x3e5f712f, 0x3c98d685, 0x1b583a8a, 0xc7d6fe4, 0x227f0e28, 0x11ca398c, 0x5fd4a8f, 0x113ddba4, 0x67f6}}, + .y = { .val = {0x307160e5, 0x1a2b2d79, 0x3d36198d, 0x385223d, 0x6cf785e, 0x2b7aded6, 0x5d04f05, 0x35a3d991, 0xb833}}}, +{.x = { .val = {0x3b89a762, 0x4098fb4, 0x2ee6b8dc, 0x3724c04, 0xb471293, 0x281525a, 0x12555fa8, 0x21db24d9, 0x327f}}, + .y = { .val = {0x39203301, 0x327f6566, 0x2bd7dfe9, 0x14d41c3f, 0x1997b975, 0x25a49578, 0x24026b09, 0x13aacd4, 0xb2d4}}}, +{.x = { .val = {0xfb27b6, 0x909f8a1, 0x24305763, 0x1b8f6caf, 0x286aa5c7, 0x8e2b585, 0x38b1b10f, 0x138f6f9d, 0xfea7}}, + .y = { .val = {0x323cb96f, 0x74f6df, 0x33f7b777, 0x1ad65ae5, 0x36af9312, 0x19d37b32, 0x313297cf, 0x1a36e6c2, 0x6e05}}}, +{.x = { .val = {0x1f9756e4, 0x3f65f258, 0x23730488, 0x15c3b977, 0x28cd0ebb, 0x380f6143, 0x280ff180, 0x10720c10, 0xed94}}, + .y = { .val = {0x3f3abfae, 0x3c3827e4, 0x24de98bf, 0x3c8ddd3f, 0x13911e09, 0x5d84a2c, 0x3fa19afa, 0x27a7bfa2, 0x3dbe}}}, +{.x = { .val = {0x151cf119, 0x16eb40cf, 0x3ab4d301, 0x42f7613, 0x3487515b, 0x3b4fd892, 0x27c3fc9f, 0x1a63b99e, 0x29d9}}, + .y = { .val = {0x35056339, 0x3221d015, 0x3a7c2963, 0x272503a4, 0x31c96fb8, 0x28495013, 0x2b45277, 0xb145f72, 0x7fd0}}}, +{.x = { .val = {0x3f422491, 0x19f1114d, 0x2060cff4, 0x114f92a1, 0x180a31fd, 0x3edef4cd, 0x3936d6f3, 0x15f41404, 0x126b}}, + .y = { .val = {0x1da3ef84, 0x3e8c7c66, 0x3f39347a, 0x122eb0c2, 0x3f3fb0e1, 0x128fae8a, 0x262c2e3c, 0x3704c185, 0xc1a7}}}, +{.x = { .val = {0x17bdde39, 0xb00a910, 0x36043295, 0x11385e6d, 0x1968d315, 0x95c3566, 0x3cf0e10a, 0x1044fd9d, 0x76e6}}, + .y = { .val = {0x1901ac01, 0x12c5d4b4, 0x16d2032b, 0xa8cf4ad, 0x1f0d35e, 0x19b5c1a, 0x295cf577, 0x37e37b93, 0xc90d}}}, +{.x = { .val = {0x3a1187a5, 0x33e666a0, 0x29ae691, 0x1755d88b, 0x21c81000, 0x1f276205, 0x2c73bee8, 0x14c3a794, 0x708a}}, + .y = { .val = {0x73db9c0, 0x2293c66d, 0x1353e8a5, 0x3369cf1b, 0x2d38283e, 0x195b72ed, 0x1a897fa9, 0x1204787e, 0x9b88}}}, +{.x = { .val = {0xde4f5be, 0x386c5b1b, 0x2b2b59e2, 0xdd2db61, 0x2462cf9f, 0x35920e57, 0x33be219b, 0xd3f122, 0x19cf}}, + .y = { .val = {0x2f321af2, 0x2a454cad, 0x30f1c0c0, 0x2474724f, 0x181947ef, 0x12f9a2ac, 0x2b466c3b, 0xac1a856, 0x28e3}}}, +{.x = { .val = {0x117cf3e8, 0xeaf0827, 0x3ea2219e, 0x24ef40d2, 0x17f576ee, 0x670be0e, 0x35f0d7c7, 0x11281e32, 0xaf6c}}, + .y = { .val = {0x1751baea, 0x22b74180, 0xa0d435b, 0xd8aba9f, 0x3246dfec, 0x39cc54f2, 0x14b30af9, 0x25bfa17, 0x784}}}, +{.x = { .val = {0x2bcbb891, 0x2ac54090, 0x326cbee3, 0x1f3190f7, 0x3f8f9a8f, 0x206ea9d0, 0x2abe1e82, 0x315ac0ec, 0xc738}}, + .y = { .val = {0x299a84c3, 0x1f9cd765, 0x80cfe91, 0xc53bbde, 0x3fbbbb82, 0x63cbab2, 0x2d2537f7, 0x2d5e2546, 0x893f}}}, +{.x = { .val = {0x662ab1b, 0x36aac1e1, 0x1b8c9e4d, 0x1c65fa92, 0x27aa9464, 0xca9a64b, 0x37435b, 0x2117b35f, 0x5578}}, + .y = { .val = {0x56f3511, 0x5b463cc, 0x25d64de3, 0x14e9dd1a, 0x2a4053f6, 0x1b429474, 0x1e2c3cea, 0x1e5e2db, 0xe61d}}}, +{.x = { .val = {0x148b6c29, 0x13e1a6e2, 0xe399609, 0x3c48d53f, 0xceccd22, 0x3e8ef074, 0x364cc4ab, 0xe0e2228, 0x47f3}}, + .y = { .val = {0xe537ef9, 0x3b7b8448, 0xf994a81, 0x2ed26562, 0x16c7118, 0x39219d6d, 0x32937190, 0x26a343c0, 0x48ca}}}, +{.x = { .val = {0x5ff4adb, 0x2069b23c, 0xbef768a, 0x3d5c35bf, 0x25d5f614, 0x1ad3271a, 0x1b8cfe46, 0x7cd2b90, 0xc0c0}}, + .y = { .val = {0x2c351065, 0x313bfdce, 0xd15b85f, 0x2f10f45c, 0x35b8cecd, 0xde82d01, 0x17f5c7c9, 0x3d6fb90d, 0xb84}}}, +{.x = { .val = {0x8f6c14b, 0x1cba7d96, 0x29250143, 0x35cb97ce, 0x172877d1, 0x131d8df2, 0x25b81e26, 0x1899522d, 0xd895}}, + .y = { .val = {0x1d7d991f, 0x24d8fb5d, 0x3b067e17, 0x10a358ca, 0x340eb03, 0x3b182063, 0x7eae728, 0x2a8e3caf, 0xfebf}}}, +{.x = { .val = {0x37078424, 0x296d652d, 0x2c40c3fb, 0x3b2bde83, 0x3a26703, 0x290d8880, 0x1044e8a3, 0x1bbbe25c, 0xfd13}}, + .y = { .val = {0x671ddf1, 0x3587bbbf, 0x22adfa8c, 0x3cac7de2, 0x5efa57c, 0x74646d7, 0x252cc67a, 0x2a0d3cf1, 0x218d}}}, +{.x = { .val = {0xdb1cb3c, 0x3c7613b2, 0x3f024a5, 0x1c00e835, 0x119f861b, 0x33294d9d, 0x38d140e9, 0x23a77658, 0xd99e}}, + .y = { .val = {0x2b8637a7, 0x2228a78d, 0x3c8765cd, 0x21bfbe3f, 0xeba6e62, 0x16ecc86f, 0xa3a7a94, 0x66b4730, 0x36dc}}}, +{.x = { .val = {0x3c385172, 0x351bda34, 0x40e636f, 0xcd4781, 0x309191d2, 0x36295396, 0x18317a1b, 0x3c586686, 0x3fd}}, + .y = { .val = {0x3ccb9794, 0x26b19fc3, 0xe7232b7, 0x26e4a7a4, 0x573755b, 0x1c31f4f2, 0x12c3fe4, 0xb01b97, 0x408d}}}, +{.x = { .val = {0xf676e03, 0x24542959, 0x3e84edd4, 0x3ff1cda4, 0x1e8761ce, 0x3d90cd5c, 0x17518eb0, 0x2500caa5, 0xb8da}}, + .y = { .val = {0xefdf6e7, 0x1223939d, 0x1ff3b511, 0x33161365, 0x2808b092, 0x267325d8, 0x1a1e4d7c, 0x37e91201, 0x2804}}}, +{.x = { .val = {0x5af726a, 0x104fd053, 0x25bf6e6d, 0x268f972c, 0x3620f946, 0xb2da62a, 0xc5ce53f, 0x34417b63, 0x6d36}}, + .y = { .val = {0x13f9fc7d, 0x15c12468, 0x108a35c, 0x31664dad, 0x50029dc, 0x2319b257, 0x3669e72d, 0x170d38dd, 0xe4ba}}}, +{.x = { .val = {0x2540db99, 0x1b8a8c32, 0x34b81228, 0x4c27014, 0x30b0e3eb, 0x220fe99b, 0x3ac0cd06, 0x2f784334, 0x3ab6}}, + .y = { .val = {0x1bda78a3, 0x1a1cff8c, 0x369c043e, 0x344dec38, 0x13e99c38, 0x45ea5a8, 0x71d7fc3, 0x1881e6fa, 0xbaca}}}, +{.x = { .val = {0x1f1048da, 0x1ddefc9e, 0x3ddd3ba7, 0xbf53cdc, 0x7bce2ba, 0x281a7674, 0x156f0fdb, 0xd38fc6b, 0x7966}}, + .y = { .val = {0x2106cf01, 0x23e6f892, 0x3d74862e, 0x95db633, 0x3927f253, 0x39d1cd69, 0x20b8956d, 0x38adb3ec, 0x4d8e}}}, +{.x = { .val = {0x23c0df5d, 0x6845de3, 0x156a792f, 0x67bfed4, 0x1d7fab20, 0x2b6ae51d, 0x3b33a7d8, 0x3a851107, 0xe80f}}, + .y = { .val = {0x2ac9ec78, 0x32d0a46d, 0x3322ea9f, 0x557a02b, 0xa94472d, 0x25da328f, 0x200771e8, 0x379fd8e3, 0xeed1}}}, +{.x = { .val = {0xf83cd58, 0x36c39e2c, 0x3d2f9162, 0xb730e1d, 0x3e7a3712, 0x2b13b47b, 0x1265981, 0x287c23a9, 0x440c}}, + .y = { .val = {0x388a3f4b, 0x1ef01a6, 0x1c0a260b, 0x793509a, 0xe2f02a2, 0x25537275, 0x2e122af8, 0x2c34b357, 0xa6c8}}}, +{.x = { .val = {0x12998b10, 0x206f689c, 0x1b229d9e, 0x31c3af30, 0x2907819b, 0x1fe0a74e, 0x26c1cc5f, 0x32ebcae5, 0xf694}}, + .y = { .val = {0xf05e51, 0x19e22c5c, 0x3c2a47f, 0x1b1930c6, 0x6d82aeb, 0x317feb31, 0x2f03d633, 0xfae986f, 0x40a6}}}, +{.x = { .val = {0xdd553fd, 0x25684cd6, 0x8b6414f, 0x2afda570, 0x22595047, 0x1b53d0e6, 0x2684850b, 0x218a8d55, 0x8b6e}}, + .y = { .val = {0x3e9be5ed, 0x200f6b4c, 0x3383d0d, 0x2b0f1686, 0x2b9fa124, 0x2f0b7d3, 0x11cb40d1, 0x22443b4, 0xea5e}}}, +{.x = { .val = {0x4e16070, 0x3701eef3, 0x2fd6915d, 0x286080c7, 0x167543f2, 0x29239475, 0x1704313b, 0x1a5ef7f3, 0xa301}}, + .y = { .val = {0x1e177ea1, 0x30346810, 0xa11a130, 0xd76fdf0, 0x140f9b17, 0x2027e897, 0x3e4f5081, 0x3e473ed9, 0x7370}}}, +{.x = { .val = {0x324ba5ae, 0x5080c5b, 0x34b5d81, 0xe594013, 0xbff74b4, 0x23490678, 0x1f049f3e, 0x39673fde, 0x27e1}}, + .y = { .val = {0x83a45b3, 0x1296ffba, 0x2fa63f78, 0x122869a6, 0x39df05df, 0x2d78f3f1, 0xe209ee1, 0x9a9b201, 0x310b}}}, +{.x = { .val = {0x1caed7ae, 0x25a45d72, 0xfbfb4f9, 0xe6b77a1, 0x2d7e4f5a, 0x223b0e24, 0x24aee165, 0x39e97da1, 0xc712}}, + .y = { .val = {0x6156294, 0x134522a9, 0x30ce6378, 0x3639512, 0x1dd9e538, 0x352e08c4, 0x363b365e, 0x1041d458, 0x4964}}}, +{.x = { .val = {0x4a6db03, 0x2d0f87f9, 0x275d791, 0x32175bd6, 0x675fcb2, 0x303509ae, 0x3235d065, 0x141292c, 0xbfc}}, + .y = { .val = {0x64b8542, 0x22b23469, 0x5d4f055, 0x109c65cd, 0x26c99237, 0x23b1fe52, 0xf3453fb, 0x119e9b0d, 0x1955}}}, +{.x = { .val = {0x3fb04ed4, 0x2deb18f8, 0x1307fffa, 0x330cc2c4, 0x278de208, 0x3e741449, 0x2b936463, 0x216ce275, 0x90ad}}, + .y = { .val = {0xb6ef150, 0x24753523, 0x182894d9, 0x2bbeaf85, 0x3222b839, 0x372f6509, 0x38261aff, 0x1e8d8828, 0xe50}}}, +{.x = { .val = {0x27dc0151, 0x2062c3b6, 0x2707bad2, 0x496f991, 0x25e3d7e, 0x2c745521, 0x14077f44, 0x3503be32, 0x7e2c}}, + .y = { .val = {0x20721ec7, 0x28ef14e4, 0x2ee082c9, 0x26fb902b, 0x1ef95d88, 0x186a2cc8, 0xfab382a, 0x1d420ab7, 0x905b}}}, +{.x = { .val = {0x1345e597, 0x3840eb90, 0x3853cf90, 0x18dafe76, 0x2f52a79c, 0x25d6ef47, 0x2dace21c, 0x3d48656f, 0xa146}}, + .y = { .val = {0x345a770a, 0x19d59dab, 0x1f094b07, 0x19e96c88, 0x331b40ea, 0x25774b6e, 0x3feb09ae, 0x26c2ac14, 0xa5a9}}}, +{.x = { .val = {0xce45444, 0x32ed4ff1, 0x2ccc4e20, 0x379087bf, 0x1a8114db, 0x2fe76ac9, 0x193b9bcf, 0x1d6873c6, 0xd24c}}, + .y = { .val = {0x7dd4a57, 0x2e4c91a6, 0x1f1e524c, 0x1d64fd26, 0x25a78abf, 0x2df46043, 0x1c1d1cfc, 0x74b7a13, 0x58fe}}}, +{.x = { .val = {0x1ec4c0da, 0x2ded1132, 0x23ea3351, 0x23159e1c, 0x1f162ee8, 0x2706b660, 0x35f33923, 0x2e74bd8e, 0x8f68}}, + .y = { .val = {0x101fff82, 0x8f2fde5, 0x1510bfdf, 0x3a8b3fa5, 0x3e215dbb, 0x36430ada, 0x23986de1, 0x27cb6e81, 0x662a}}}, +{.x = { .val = {0xcf27076, 0x1a11f7e1, 0x3627eaee, 0x26162b79, 0x19af59d8, 0x3faf9dff, 0x28158fca, 0x2bbf5e13, 0x4d49}}, + .y = { .val = {0x3aa781e, 0x2e42d988, 0x1f4d8466, 0x3cb469f, 0x1ca6f06e, 0xfc840d6, 0x1d135e72, 0x3f166843, 0xcd32}}}, +{.x = { .val = {0x29b62026, 0x236f2d5c, 0x9d1d4ee, 0xa8f7822, 0x1c5aa78d, 0x1986787d, 0x16f8537d, 0x14e7a175, 0x7564}}, + .y = { .val = {0x1ace0cf3, 0x5cb23eb, 0xb79f334, 0x12ab3655, 0x32292568, 0x77d4929, 0x1b3c6523, 0x21504dd2, 0xc1d6}}}, +{.x = { .val = {0x17b4a278, 0xd936b35, 0x3f4082b5, 0x3d8697c7, 0x19ccc878, 0x1bfcc06b, 0x32779674, 0x245eb677, 0x210a}}, + .y = { .val = {0xc7b2231, 0x3c9c4ff4, 0x3f20bfc7, 0x227986ab, 0x16737d37, 0x26fa07e3, 0x1e57b7a3, 0x6d5142d, 0x670e}}}, +{.x = { .val = {0x13231e11, 0x1a1bf541, 0x3681e3e6, 0x123a1940, 0xc36091f, 0x267fe466, 0x385d65ff, 0x3ec05dab, 0xe4f3}}, + .y = { .val = {0x2feb73bc, 0x8b0e15d, 0x151d1c98, 0x31f9d3b2, 0x2b7286c, 0x69b43a8, 0x34f1c166, 0x18ceb43b, 0x1e63}}}, +{.x = { .val = {0x3bcdaf2f, 0x2ffb888c, 0x3a172953, 0x14c6a096, 0x1b362f88, 0x190442af, 0x373e01ec, 0x32edda19, 0x4b30}}, + .y = { .val = {0x3d26b5b7, 0x200cf518, 0x3485756, 0x37cf2079, 0x3c4a91f, 0x38b15ddf, 0x3629b6f9, 0xd40996e, 0x74c6}}}, +{.x = { .val = {0x2673059f, 0x3ffa70a6, 0xe0fa192, 0x45c5414, 0x64817ec, 0x16c82c5d, 0x1700dcd1, 0xd2a9eb8, 0xcbb4}}, + .y = { .val = {0x227c070c, 0x1f6a5908, 0x2d5f845b, 0x351793c2, 0x35dfad41, 0x35248ce2, 0x2bd17562, 0x802ad36, 0x4a1a}}}, +{.x = { .val = {0x6de12c0, 0x351e1b84, 0x34610e94, 0x2736b161, 0x17244c6d, 0x35ec79d5, 0x2c1cd06, 0x15b6704, 0xf478}}, + .y = { .val = {0xa5361fe, 0x269db39b, 0x1ab92d76, 0x305fbd82, 0x28694c26, 0x2578041, 0x23946e68, 0x39843ccf, 0x7f09}}}, +{.x = { .val = {0x20eae29e, 0x1bedbab8, 0x14e1d071, 0xd3cbc3, 0x1a4266c7, 0x1854de91, 0x3f331eb9, 0x3ea6c63a, 0x8c00}}, + .y = { .val = {0x2702414b, 0x1f4a9319, 0x1e36c54e, 0x3eb6bea0, 0x36c974c2, 0x30d0e8dc, 0x121a1a9d, 0x1c99ffa9, 0xefa4}}}, +{.x = { .val = {0x18ada5f, 0x21326ac3, 0x1122fb3e, 0x1f8a5fca, 0x2be1effd, 0x2d6fe58d, 0x2b46fa8b, 0x3005db68, 0x24cf}}, + .y = { .val = {0x178a586b, 0x23e984e6, 0xf814f26, 0x25672869, 0x2da927ed, 0x21c53577, 0x61a6986, 0x23eec1e7, 0xebff}}}, +{.x = { .val = {0x14679da2, 0x40c6256, 0x3f057edf, 0x37759ff1, 0x292ec616, 0x37b5ca84, 0x1bc82ea2, 0x1f56352e, 0x4a}}, + .y = { .val = {0x379ffe26, 0x21dfd211, 0x23fa28a4, 0x30ed2525, 0x71b3b71, 0x76051fb, 0x2cb75e6b, 0x316dd9c0, 0xb98a}}}, +{.x = { .val = {0x87c4b65, 0x33cd3ab7, 0x207b2a9c, 0x3e202287, 0x26ce4996, 0x1b178b01, 0x1c7fc7, 0x1a7132f4, 0xee7d}}, + .y = { .val = {0x1136a95a, 0xfa3d13b, 0x2e942e52, 0xfa2666e, 0xf2ee2c3, 0x24aafc0c, 0x13821a1, 0x189bb069, 0xecc8}}}, +{.x = { .val = {0x20cb3e41, 0x25ff77f1, 0x8b92c09, 0xf4213cc, 0x298ed314, 0x33b02a7, 0x829f3e1, 0x1b39a775, 0xe7a2}}, + .y = { .val = {0xf2cfd51, 0x3a2a5087, 0x20e83e20, 0x29acb010, 0x2fbb18d0, 0x2c01a86a, 0x3984b471, 0x238c03e9, 0x2a75}}}, +{.x = { .val = {0x3b4ae861, 0x25f96e45, 0x2e32fa9d, 0xf0d7935, 0x2089f520, 0x22fed9dc, 0x3f8d00d3, 0x3eae80da, 0xf5ca}}, + .y = { .val = {0xd82239c, 0x32708e70, 0x12f05f3c, 0xecaa715, 0x839159b, 0x3e641190, 0x26d817bf, 0xee2808a, 0x19e8}}}, +{.x = { .val = {0x3d2a9651, 0x13f5335e, 0x14c98208, 0x27942712, 0x2805428f, 0x3d455b5f, 0x23f1f12d, 0x240933ad, 0xe938}}, + .y = { .val = {0x1e786824, 0x3bf78add, 0x2770bfef, 0x1c4433b1, 0x31aaf18d, 0x21eaebd9, 0x26595f92, 0x1a21c8dc, 0x8648}}}, +{.x = { .val = {0x3cddab8b, 0x3cb506b9, 0x3c68e6fc, 0x3934494, 0x2d0c379f, 0x5a40360, 0x1256bed1, 0x16761e0a, 0x2645}}, + .y = { .val = {0x1de473, 0x27d92d14, 0x1caf1e6c, 0x218c6bce, 0x72d77a, 0x2f18dc0d, 0x3512cef7, 0x2f4649b4, 0x79e5}}}, +{.x = { .val = {0x1e6b80ef, 0x33ca7acf, 0x179424f3, 0x32f2e59f, 0x3cbdc571, 0x1503088e, 0x22ec8d23, 0x2783b8d9, 0xb645}}, + .y = { .val = {0x1a71ba45, 0xc2fc2d8, 0xe35b2ff, 0x2ceb9b52, 0x261db3c4, 0x2b7c5b95, 0x3e06de1d, 0x21db41bc, 0x67c}}}, +{.x = { .val = {0x33eb51f, 0x14fbcdd4, 0x279c2112, 0x22415daf, 0x341593b6, 0xdbdcc07, 0x23c88e4d, 0x3a3c3660, 0xe5d8}}, + .y = { .val = {0x1a62a2d9, 0x2756f659, 0x1f0f5497, 0x27711b6, 0x3eeef0e5, 0x5a95f63, 0x23e04abb, 0x3a6de187, 0x4dc1}}}, +{.x = { .val = {0xf155e64, 0x1e99d920, 0xa301173, 0x19af93ea, 0x3ae0ddab, 0x2c3dcc86, 0x8c3dc56, 0x9fddf6f, 0xa9ca}}, + .y = { .val = {0x161b3297, 0x3cfcccf1, 0x3caf0ae1, 0x17506086, 0x2d00487, 0x1f4891b0, 0x314d4d19, 0xcd59e3e, 0xf4bb}}}, +{.x = { .val = {0x16ee247c, 0x352f18a7, 0x351cee06, 0x11e3a11f, 0xfe7591f, 0x28415847, 0x2d7f25eb, 0x1c6001a1, 0x68fb}}, + .y = { .val = {0x1a01865d, 0x387e08b4, 0xc73c9da, 0x235602c1, 0x1b0c079a, 0xd509d40, 0x19636737, 0x348d18b7, 0xcd12}}}, +{.x = { .val = {0x96943e8, 0x3b683d6d, 0x273c5a5d, 0x1bc7f19f, 0xf06231d, 0x8d2a846, 0x3b840793, 0x20320a02, 0xd68a}}, + .y = { .val = {0x2b133120, 0x25321099, 0x45295a2, 0x39ee3de, 0x30e28b5b, 0x2c7e45de, 0x186d00c4, 0x2a7ffd2d, 0xdb8b}}}, +{.x = { .val = {0x2412b6fd, 0x2f6888b2, 0x3702b828, 0x3b414f1b, 0x12373cac, 0x3e3becdd, 0x240be402, 0x102719de, 0xf16a}}, + .y = { .val = {0x2ca052da, 0x1a36b9df, 0x9ebca42, 0x15019649, 0x230e4e16, 0x1a9d69d3, 0x32799d7a, 0xc45c514, 0x2a41}}}, +{.x = { .val = {0x326dd4e4, 0x30682db8, 0x3ed98325, 0x27d3cbda, 0x36f84db8, 0xdfda665, 0x26f42fbe, 0x2d41aadd, 0x4154}}, + .y = { .val = {0x75ded1c, 0x32164a54, 0x1e22dd46, 0x13aa7674, 0x25ff641, 0x1b913584, 0x1988894c, 0x1d410f1, 0x23ad}}}, +{.x = { .val = {0x3f7f0246, 0x31469e98, 0x727ddf4, 0x3a1b927f, 0x1956ea93, 0x2a35342d, 0x95c1080, 0x1949da73, 0xb73c}}, + .y = { .val = {0x2a2a407b, 0x25f94593, 0x2e554e55, 0x35cb931, 0x36c1ea1a, 0xd624f16, 0xca9d4b5, 0x36c41c5d, 0x9a67}}}, +{.x = { .val = {0x28d3d5d, 0x256603f, 0x3449cea4, 0x4abae5c, 0x3a30b096, 0x3009c241, 0x804252d, 0x3b5f7d97, 0x324a}}, + .y = { .val = {0x16ab7c84, 0x19c892be, 0x23328439, 0x84ec31f, 0x2c1f4f19, 0x3030d6b, 0x21f2ff13, 0xd95dd2d, 0x648a}}}, +{.x = { .val = {0x32919749, 0x23ce0e06, 0x1e0db1fa, 0xacf92a3, 0xd7203f7, 0xc9a0620, 0x3490228d, 0xcc7a89b, 0x32c9}}, + .y = { .val = {0x3290b5e3, 0xc7a5ec3, 0x239ab096, 0x2292af6b, 0x33dbb826, 0x28bc0adb, 0x9cb5695, 0x9cacd08, 0xd7cd}}}, +{.x = { .val = {0x3b9795e4, 0x38708949, 0x1846b8e1, 0x30586db8, 0x2c6b1c69, 0xbda9c3f, 0x37854a0, 0xbcecee6, 0xeb29}}, + .y = { .val = {0x2e53a0fe, 0x2dfa74be, 0x1111c6f5, 0x4c75d42, 0x5835b57, 0x198d2bc5, 0x2be80169, 0x3096a5bb, 0x8c43}}}, +{.x = { .val = {0x9303fdd, 0x3a8e755e, 0x1d1ed35a, 0x1c515fc6, 0x9fbe14d, 0x350c401, 0x35ef2e62, 0xe8077ce, 0xa65a}}, + .y = { .val = {0x2e68703, 0x2b512a34, 0x3aed3cad, 0x21874093, 0x2d2c7686, 0x10f63643, 0x35c6fb8f, 0x2825033f, 0x798e}}}, +{.x = { .val = {0x3d054c96, 0x3a2f4dcf, 0xd1ca888, 0x31050eea, 0x3ee5dcee, 0x77f6f97, 0x1e61f6d5, 0x30524673, 0x4df9}}, + .y = { .val = {0xad10d5d, 0xbaeb01b, 0x28849019, 0x3541b370, 0x1d85d4b5, 0x25d308e8, 0x18728050, 0x3b14424b, 0x35}}}, +{.x = { .val = {0x1da49e04, 0x31ac3f0, 0x17a8d70c, 0x37915539, 0x387088e9, 0xc5f5392, 0x998cd25, 0x32b634b3, 0xed32}}, + .y = { .val = {0x3c1db9e0, 0x18c48345, 0x9fab7db, 0x36a7eb2d, 0x19d20b52, 0x728dd61, 0x30204a54, 0x3bd7c740, 0x129f}}}, +{.x = { .val = {0x2883f855, 0x2dd06353, 0x3c34016c, 0x30db72d8, 0x30366e28, 0x27904471, 0x360f1804, 0x2adc9358, 0xe821}}, + .y = { .val = {0x19852ddf, 0x353831a9, 0xec23efe, 0xec67185, 0x16cf598b, 0x3504550, 0x13ce367d, 0x32fe18fd, 0xadef}}}, +{.x = { .val = {0x3441742e, 0x2ffd67ba, 0x33806e9f, 0x52951eb, 0x1693a72f, 0x1514bef2, 0x2d212f45, 0x22653946, 0x3f0d}}, + .y = { .val = {0xfecadbe, 0x3194d8ef, 0x2d13d958, 0x8178b0e, 0x3a6e0b1e, 0x172c3a11, 0x3dc445e, 0x1b08fca3, 0xfbd7}}}, +{.x = { .val = {0x2c1f98cd, 0x2ff26722, 0x17f0308c, 0xd224153, 0x6602152, 0x362a7073, 0x34870fae, 0x66a1291, 0x9c39}}, + .y = { .val = {0x14fc599d, 0x39f9780f, 0x64c8e6b, 0x14c9bddb, 0x20e64190, 0x3c112fc9, 0x1dd57584, 0x13c3d293, 0xddb8}}}, +{.x = { .val = {0x294a09ec, 0xd7beded, 0x28535f04, 0x34c9a94f, 0x92aa40c, 0xbf1a757, 0x1d80f0a4, 0x14c9895, 0x2e3c}}, + .y = { .val = {0x8c7327e, 0x14d21a06, 0x7b66512, 0x12294f1c, 0x2fc1abe0, 0x2b8902e0, 0x6fb5bdd, 0x3e24595b, 0x1f}}}, +{.x = { .val = {0x2b9c7ce6, 0x17c668a, 0x19089342, 0x1c40c5a8, 0x24dda433, 0x17edf8f8, 0x1587ae1, 0x289333e9, 0xe8e2}}, + .y = { .val = {0x836267c, 0xb007ada, 0x1c27a73b, 0x27980ed, 0x2e20596e, 0x3cacacef, 0x35d1b4ca, 0x20f3831b, 0x46c9}}}, +{.x = { .val = {0xac7b3c2, 0x2c34e59a, 0x3d5b5f5, 0x2b2be48e, 0x32a212, 0x28e2c5c, 0x173c2b2f, 0x26ab1761, 0xa754}}, + .y = { .val = {0x1287eaef, 0x283245c6, 0x37116dff, 0x1ad44554, 0x147d2b5d, 0x2875c306, 0x2415335, 0x346e4347, 0xbd17}}}, +{.x = { .val = {0x20a959e5, 0x2884e084, 0x391d4cc5, 0x38524ea2, 0xe06bb91, 0x17ca076, 0x12fdf8de, 0x5c2c774, 0x6057}}, + .y = { .val = {0x2385a2a8, 0x2266fa4c, 0x2e24c65e, 0x1454af0f, 0x1df26246, 0x268b6bdc, 0x24807add, 0x3c2c9a9a, 0x9a1a}}}, +{.x = { .val = {0x2fd545c, 0x22672976, 0xa28e661, 0x4cfe375, 0x1c85df7c, 0x1044291b, 0x2e064039, 0x3f59df14, 0x6773}}, + .y = { .val = {0x147eb1ae, 0x231fc0d2, 0x1c6cf98e, 0x35e03d68, 0x2b246bea, 0x3c972774, 0x3652f0f0, 0x2db63365, 0x444e}}}, +{.x = { .val = {0xb86f021, 0x1cf185ac, 0x4680503, 0x1d390e04, 0xc87c203, 0x31e6ab38, 0xe565237, 0x1b65345f, 0xe0f8}}, + .y = { .val = {0x35bf325a, 0x2dade732, 0x15fc45b3, 0x202f3004, 0x89a2c9a, 0x7a0cbc7, 0x2bcf47a9, 0x71cdcc2, 0xc57}}}, +{.x = { .val = {0x2da6e03, 0x2b41dcb0, 0xcad6038, 0x9df7e42, 0x296f4f4c, 0x247864f5, 0x5041ce9, 0x56ae7c9, 0x42ca}}, + .y = { .val = {0xc347793, 0xda227ea, 0x106bea78, 0x1ba169a0, 0x3800eed6, 0x339347f2, 0x57c9647, 0x3bc9b207, 0x68d2}}}, +{.x = { .val = {0x2cb94266, 0x69a5cfb, 0x3d4df12b, 0x33bc3ee9, 0xda31880, 0x10e69146, 0x8411421, 0x37e388e8, 0xa576}}, + .y = { .val = {0x21b28ec8, 0x3a2f846b, 0x114d9f3e, 0xb8429fd, 0xcd82c43, 0x2e5ebf96, 0x240b2c92, 0x2fc839d9, 0x40a6}}}, +{.x = { .val = {0x1a704896, 0x3b15c96f, 0x1acfb8dc, 0xee818f2, 0x271bae6f, 0x148219ef, 0x35a3b546, 0x3318bbce, 0x9e5d}}, + .y = { .val = {0xa82c835, 0x23c9da77, 0x30f5124, 0x18174618, 0x7612279, 0x34e88553, 0x25f3ea5f, 0x344b76e4, 0x6fed}}}, +{.x = { .val = {0x4bf7ea0, 0x14fb561d, 0xef58339, 0xd896817, 0x303b20e3, 0x1ba7e5db, 0x345adf8d, 0x20dd6e1, 0xa7de}}, + .y = { .val = {0x1bbcabaa, 0x130154e, 0x2bc5aa2e, 0x1691f03f, 0x88e9a64, 0x1282ccd2, 0x1a5e5210, 0x25ac15eb, 0xa63d}}}, +{.x = { .val = {0xad916fb, 0x27e3e841, 0x149e4a3a, 0x20197f7a, 0xff4cbe6, 0x30d6b007, 0x80c9c13, 0x19639a24, 0xc266}}, + .y = { .val = {0x20887814, 0x1abbd4ae, 0x36113885, 0x23fb37fa, 0x627ab6b, 0x2605c2c9, 0x3daab0f7, 0x164e1539, 0xe7e8}}}, +{.x = { .val = {0x3e58ad71, 0x3dd8e226, 0x39a3a208, 0xc347d73, 0x1e8c38bb, 0x17fa58a7, 0x2c3e30a0, 0x29e30a37, 0x7778}}, + .y = { .val = {0x3d9f43ac, 0x2d44ff07, 0x324ac563, 0x2ce1047f, 0x3f580087, 0x26384bcb, 0x1b22ff70, 0x1b66ad69, 0x3462}}}, +{.x = { .val = {0x1073e879, 0x1fa87094, 0x104eea7a, 0x3c5a96b8, 0xfe3932c, 0x3d20b5fc, 0x6d1632, 0x1e5ad728, 0xe7b9}}, + .y = { .val = {0x3aa89d98, 0x239c4226, 0x1a98af33, 0x2d6fc97b, 0x3cc1ca9c, 0x840a9cd, 0x29e2fdf4, 0x26230645, 0x12b8}}}, +{.x = { .val = {0x32628f0f, 0x1975c8af, 0x2aee9198, 0x108f6abc, 0x209a7365, 0x2456892f, 0x36203c2c, 0x3c061421, 0x71b}}, + .y = { .val = {0x5a1c334, 0x15f172f5, 0x31c80bbb, 0x23e71a88, 0x84ce209, 0x1802f070, 0x1cf4ae33, 0x28575413, 0x527a}}}, +{.x = { .val = {0x239620e1, 0x3d8ddb7e, 0x1213786, 0x6447214, 0x3c39e5b, 0xcb96530, 0x3e56833a, 0xd0eb2e6, 0x218}}, + .y = { .val = {0x106998b5, 0x380667d9, 0x343c9ec5, 0xca6690b, 0x2fbfc044, 0x3c93f580, 0x250beaf3, 0x75225c2, 0xbea8}}}, +{.x = { .val = {0x6d903ac, 0x27b6a70, 0x1ad7e5cb, 0x3e589d39, 0x3afd2ed5, 0xa7f4c39, 0x3a844637, 0x2557b98d, 0x928}}, + .y = { .val = {0x1bcd091f, 0x14603a4d, 0xa8d83fc, 0xf49bbea, 0x3a95eeac, 0x1e284c24, 0x342a827b, 0x8400f4f, 0xc256}}}, +{.x = { .val = {0xf59dd9e, 0xc411e98, 0x358f0e72, 0x397a7156, 0x318ad67c, 0x58ec132, 0x1d350dad, 0x2f7b8ddc, 0x4f89}}, + .y = { .val = {0x156b049, 0x5ab8c8, 0x238df5c1, 0x12209419, 0x3bb2471e, 0x2ebd3010, 0x21f695c4, 0x14b5489e, 0xca79}}}, +{.x = { .val = {0x3ff01197, 0xa70c533, 0x1a245bf5, 0x2d9a3c1e, 0x3c4c994, 0x25aeb28b, 0x3c5a80c3, 0x20c132b8, 0xcb9e}}, + .y = { .val = {0x3b989c1d, 0xcd381d8, 0x15e0a24c, 0x2cb46300, 0x8891741, 0x96337fc, 0xe6a127, 0x34a007ae, 0x62c7}}}, +{.x = { .val = {0x108d2cc2, 0x17e7ff09, 0x48c58c1, 0x2fbb51c, 0x330dc58e, 0x33ca9041, 0x69bd3c8, 0x126c3e27, 0xe2f3}}, + .y = { .val = {0x20d4c04f, 0x38d1ef63, 0x9cbdb37, 0xd12fa38, 0x215ba42, 0x182bb1d8, 0x27237818, 0xbca03e0, 0x1feb}}}, +{.x = { .val = {0x23d82751, 0x1eab9d45, 0x3ad35452, 0x116d2a41, 0x23b28556, 0x193ce83, 0x1b109399, 0x3fbcfb1b, 0x85d0}}, + .y = { .val = {0xeb1f962, 0xb08de89, 0x7733158, 0x21d47a5a, 0x2cf5663e, 0x3525b960, 0x38c0be29, 0x192104e8, 0x1f03}}}, +{.x = { .val = {0x1d5fcade, 0x18d5b450, 0x1711ff75, 0x2d20b802, 0x11df0468, 0x1e9b3f34, 0xc4f4f60, 0x3d2c669, 0x6b79}}, + .y = { .val = {0x338d3ff, 0x1bffe1bf, 0x3e26b0ab, 0xfe96d1e, 0x2e09cba8, 0x19987e72, 0x1eb3ef29, 0x2606cbfe, 0xd03a}}}, +{.x = { .val = {0x23a3e0cb, 0x2c3336af, 0x1978be0b, 0x91e77a1, 0x4f8fe3d, 0xb0d9eb3, 0x2bed3c16, 0x26cb0b5f, 0x4114}}, + .y = { .val = {0x339033a8, 0x3a4ba60, 0x3490f247, 0x3b1e017b, 0x2cf28b3, 0x5726e64, 0x30542b4, 0x16e4b6df, 0xc90d}}}, +{.x = { .val = {0x23f3d3fc, 0x237774a3, 0x1c29cebf, 0x12a6e081, 0x32a7ba66, 0x30f7f8a1, 0x849dfae, 0x353e939f, 0xd1fa}}, + .y = { .val = {0x10f3704d, 0x3488d0f1, 0x3f37326e, 0x34dc4c7b, 0xb7818ba, 0xfdc3a16, 0xfdfe547, 0x25c528d2, 0x8fe1}}}, +{.x = { .val = {0x526087e, 0x3d501209, 0x2da20308, 0x3edb6220, 0x18b85dfd, 0x26d8105e, 0x2ce97c1c, 0x373a5fb, 0xff2b}}, + .y = { .val = {0x30c29907, 0x32547807, 0x10e2ceb2, 0x2dfb5bee, 0x107936c7, 0x13137153, 0xba188af, 0x4ffbd49, 0x493d}}}, +{.x = { .val = {0x3149f8ef, 0x2f4ea6bc, 0x238b4583, 0x3ad713b9, 0x31bb223d, 0xa7aefb2, 0x26c9f78e, 0x36ef17cd, 0x2982}}, + .y = { .val = {0x16c7a248, 0x1b9c9ac0, 0x2e3ed845, 0x176e6504, 0x35bc9d09, 0x294ce71e, 0x2220ab9f, 0x16fa6bd9, 0xa61b}}}, +{.x = { .val = {0x2380441b, 0x14a27d84, 0xe176588, 0x47d160, 0x17db5860, 0x1bad6412, 0xc0f6b43, 0x39410abc, 0x1a28}}, + .y = { .val = {0x452af25, 0x17d81aa, 0x2ee67aeb, 0x2cf9d6d1, 0x36f0ed04, 0x20ca6a25, 0x19dab7c7, 0x269e65b1, 0x5577}}}, +{.x = { .val = {0x221e30a7, 0x3bbc38e5, 0x5d83242, 0x3757ade6, 0x3f20142e, 0x143302f4, 0x330601d2, 0x20fa54d7, 0xc8b}}, + .y = { .val = {0x1ff688de, 0x3afdefae, 0x187134db, 0x32b48dee, 0x3dc854aa, 0x38fc5fb, 0x3dac7b85, 0x1c1dc197, 0xdcc}}}, +{.x = { .val = {0x3856e241, 0x203978b3, 0xd6dd287, 0x3c7b8523, 0x1b212b57, 0xacb98c0, 0x80ea9ed, 0x2ef92c7a, 0x827f}}, + .y = { .val = {0x2ec293ec, 0x1816da2e, 0x2903166d, 0x3de98c61, 0x1d12687f, 0x3bcb19f4, 0x27b0b71b, 0x27248f1c, 0xc60f}}}, +{.x = { .val = {0xcb1815d, 0x3db912dc, 0xb87461e, 0x11c2a486, 0x2e6b3660, 0x35f2355d, 0x16b973e2, 0x4a9f739, 0xb77f}}, + .y = { .val = {0xe57dbc5, 0x2e8f4af2, 0x244816d6, 0x10bc3e46, 0xc2e654c, 0x33becdcf, 0x2acc43f0, 0x216c53e1, 0x4b6f}}}, +{.x = { .val = {0x45565ec, 0x3f976b4b, 0x177c5970, 0x163637d2, 0x39f956d8, 0xc22cb2d, 0xbf1247b, 0xee50c06, 0x4897}}, + .y = { .val = {0x3aed07e9, 0x2e1e41d7, 0x477b83, 0x6cd6596, 0x45af151, 0x1eece805, 0xdc1b643, 0x1d5a13cf, 0x761f}}}, +{.x = { .val = {0x3bfd71fa, 0x13535d0a, 0x34527d4a, 0x1dd68996, 0x304c170b, 0x25c9ca29, 0x1559c6d6, 0x963a3ad, 0xe931}}, + .y = { .val = {0x174d3307, 0x366f434c, 0x35e35f33, 0x251b386e, 0x154b40b3, 0x3ad05a72, 0x3dee0e85, 0xccd930f, 0xfb1e}}}, +{.x = { .val = {0x2120e2b3, 0x3ced63e8, 0x347f9aa7, 0x163f739f, 0x26e5217a, 0x392b8d33, 0x1bdbae7b, 0x127c87d4, 0xeaa6}}, + .y = { .val = {0x3a5ad93d, 0x11e94c16, 0x13f7e59d, 0x29ae597c, 0x39aa5a01, 0x2a03e261, 0x3b03ac69, 0x1e7b56ee, 0xbe32}}}, +{.x = { .val = {0x1fc9b0a8, 0xf6f0730, 0x5f3db45, 0xcded71c, 0x2279ea9e, 0x8fa9400, 0x197eec26, 0x276cefae, 0x3adb}}, + .y = { .val = {0x305bbdda, 0x6b9e5d7, 0x30266cc6, 0x36723e61, 0x95ff6aa, 0x1d3781f0, 0x34e713c7, 0xb5b6bb9, 0x374e}}}, +{.x = { .val = {0x10ae86f9, 0x153a7832, 0x23e7caf0, 0x3f7fd5a5, 0x5fc69fe, 0x255795b, 0x29cbb7e1, 0x14eb10a3, 0x129e}}, + .y = { .val = {0x1e89c85d, 0x8bbf734, 0x2b3e01b8, 0x288cbf45, 0x12183fb2, 0x288456dc, 0x29a29b2d, 0x32e562bb, 0x415e}}}, +{.x = { .val = {0x2855b8da, 0x8890f57, 0x28947119, 0x15899f44, 0x210956c7, 0x17b2dabb, 0x294485b8, 0x1125323d, 0x6014}}, + .y = { .val = {0x334e4bbd, 0x35401643, 0x23f2a4ba, 0xe55709f, 0x32e65b54, 0x2f87f644, 0x1e6469e8, 0x359a7da0, 0x8bb5}}}, +{.x = { .val = {0x1a34d24f, 0x388d8cb7, 0x1a137401, 0x2db63c32, 0x342ee541, 0x77db7b3, 0x3169d939, 0xb50f173, 0xe4a4}}, + .y = { .val = {0x1eba9414, 0x29fdc4c7, 0xd8e4f13, 0x21bbb7ea, 0xad34ce8, 0x326733ee, 0x1c73526f, 0x24b9c5b4, 0x4d9f}}}, +{.x = { .val = {0x3e8f62bb, 0xfcba8c, 0x3ae4d2a3, 0x14f158bd, 0x4ef4d05, 0x2b3e15b, 0x3b18d3ef, 0x147ee133, 0xfd64}}, + .y = { .val = {0x132c0911, 0x2b64218, 0x200e83fd, 0xaad24b4, 0x344ccfa, 0x39e9706f, 0x31578b6f, 0x33acac61, 0xe745}}}, +{.x = { .val = {0x15fe696b, 0x28747ee7, 0xf3c7a1f, 0x10b8b577, 0x1edbbb00, 0x3a0681be, 0x86bc716, 0x81f2c90, 0x1eee}}, + .y = { .val = {0x3429337b, 0x2d159c39, 0x2fd694eb, 0x818b82, 0x21c95f7a, 0x65b4491, 0x2269cd2b, 0x2f466bbd, 0x652c}}}, +{.x = { .val = {0x2f94c0d5, 0x23503c67, 0x5725790, 0x303f005f, 0x2e2111e1, 0x16acb0d1, 0x1eb14d46, 0x28cfaa2a, 0xcc0e}}, + .y = { .val = {0x2f452fe6, 0x3aaf965e, 0x113f543d, 0x1d3c998, 0x3be663f6, 0x37480ed7, 0x8a2fb23, 0x1e8edc47, 0xf990}}}, +{.x = { .val = {0x300bf19, 0x1c5cee75, 0x8fea494, 0x2d4d5daa, 0x352b6b92, 0x183eb6ac, 0xbdd9541, 0x3fbcd83, 0x1ec8}}, + .y = { .val = {0x107cefd, 0x1c737073, 0x295a07b6, 0x11b9dfd8, 0x2bbf5e01, 0x2925629e, 0x1340d2f3, 0x3a4dd5ad, 0xaeef}}}, +{.x = { .val = {0x14ff9e4, 0x36ba0175, 0x3d890560, 0x2118bdba, 0x3c90bb8e, 0x3aa80d13, 0x4bc6cbe, 0x3a8d467c, 0x5be7}}, + .y = { .val = {0x7e0bdbb, 0xc2c1e1, 0x119a3094, 0x26718c08, 0x1ab7fe0e, 0x3e243d95, 0xe605477, 0xbb0fd8e, 0x32f3}}}, +{.x = { .val = {0xddb7bb8, 0xfed517d, 0x3853991e, 0xa1927, 0x1f7f5cd5, 0xff21a63, 0x24e65081, 0x26445bab, 0x58f0}}, + .y = { .val = {0x2e5b2d6e, 0x37b1cd60, 0x1174302b, 0x1fb9018b, 0x23806650, 0xbfdd851, 0x2111a0d6, 0xaabff, 0x7e07}}}, +{.x = { .val = {0xc9a8e2c, 0x4f0581b, 0xc1a1c14, 0xf634693, 0x20cb0f82, 0x33013f61, 0x390b633b, 0x392e6ca5, 0xb0f9}}, + .y = { .val = {0x1f3d0db4, 0x30819b13, 0x171cee76, 0x143300b0, 0x3de3f033, 0x2ec2e41b, 0x2de6d41c, 0xafc610e, 0x49e8}}}, +{.x = { .val = {0x366642be, 0x376d64a0, 0x158ba889, 0xd241c5f, 0xdfa8bce, 0x2bd1a0, 0x30c2f91b, 0x1de30119, 0x146a}}, + .y = { .val = {0x3d83efd0, 0x2ca5d20, 0x37e5ed1d, 0x2aa5c74b, 0x14b2870a, 0x1a609fe7, 0x28add6, 0x383b0cd5, 0xb318}}}, +{.x = { .val = {0x39de5cac, 0x6c8d955, 0x2cb26191, 0x3f260f1f, 0xd14cfee, 0x1c2d702f, 0x17e24e56, 0x3c33a296, 0x574e}}, + .y = { .val = {0x75a4805, 0x3966ba9b, 0x310008ca, 0x9829efb, 0x1b78451a, 0x1ab6815a, 0x319c73bd, 0x264c0a07, 0x9b9}}}, +{.x = { .val = {0x260966d3, 0x230b5d0, 0x2ff86458, 0x29dc306b, 0xc835d10, 0x24e5ee6, 0x3f9f85d9, 0x1f9e6762, 0xd3d9}}, + .y = { .val = {0x33c2e52, 0x377ae142, 0x28dc4eeb, 0x3921c46f, 0x3ad3b5, 0x2a249d75, 0x2c95e6aa, 0x2d18ddae, 0x8ddb}}}, +{.x = { .val = {0x168c6d4b, 0x103ee4e, 0x3494c120, 0x2f9e33e3, 0x3bee0ab2, 0x1d39e0b2, 0x318987b9, 0x194ca22c, 0xb1aa}}, + .y = { .val = {0x2891ac51, 0xf6798ab, 0x1623cc38, 0x2876427, 0x23a83b10, 0x12aa38b5, 0x10d71268, 0x1c71820, 0x7ed6}}}, +{.x = { .val = {0x3180eef9, 0x35daa1e4, 0x228b9776, 0x48826, 0x207b128d, 0x2b3aec6a, 0x2e5f07e3, 0x303d8748, 0xfa50}}, + .y = { .val = {0x3f4f2811, 0x233635f4, 0x17a213b3, 0x1a0ca4e9, 0x1a68a5e, 0x334a1c8a, 0x3eba9b72, 0x31a488e5, 0x6b84}}}, +{.x = { .val = {0x187f5048, 0x2716f88c, 0x8386d45, 0x8ca3491, 0x290836e7, 0x503f80b, 0x74e0780, 0x13bb9864, 0x6396}}, + .y = { .val = {0x9309df8, 0x20e8a136, 0x1de6c843, 0x1602e4d3, 0xbfbc93d, 0x3fe6c70d, 0x1cf41a39, 0x3ece9ae2, 0x3b6c}}}, +{.x = { .val = {0x3adb2a65, 0x2052e87a, 0x3cbda31f, 0x35fc4ab4, 0x3c9f75af, 0x11a777c3, 0x1b7e22d1, 0x3896d345, 0x5a3c}}, + .y = { .val = {0x1d327f1d, 0x22c5c33c, 0x25fe8ed, 0x38a2f0f6, 0x3f99af3e, 0x29b6fefc, 0x5f63873, 0x496e4b8, 0x8b34}}}, +{.x = { .val = {0xa9f44d0, 0x1a9ccdd5, 0x1a8fa001, 0x36f2db9a, 0x1e41ff85, 0x2f8d3c3, 0x13eda691, 0x16be63e, 0x5ce6}}, + .y = { .val = {0x9d30105, 0x3417cd2, 0x32eccc6c, 0xf2c6fe8, 0x76c58ab, 0x15af40c7, 0x26bfe7ba, 0x33e6fb08, 0x4cdd}}}, +{.x = { .val = {0x1f067ec2, 0x394f4cad, 0x1bba5220, 0xa22ad75, 0x8e8421a, 0x16fdadf6, 0x21a11b1a, 0x1874329c, 0xda1d}}, + .y = { .val = {0x1ad836f1, 0x157ee83c, 0x279b48a6, 0x29ce2674, 0x91e2966, 0x1d98587, 0x1306c79c, 0x3d569f26, 0x8157}}}, +{.x = { .val = {0x2cd3c369, 0xf084348, 0x1f8e934b, 0x181520f8, 0x1283a23, 0x1757d877, 0xc444df8, 0x3802d3bd, 0x9c7b}}, + .y = { .val = {0x22329515, 0x27b8ffae, 0x2769cbd2, 0xc454e85, 0x2401483e, 0x9b51573, 0x20d2052a, 0x30379d2c, 0x9220}}}, +{.x = { .val = {0x3bb8c9e3, 0x1af364b5, 0x141178e7, 0x3741a9c1, 0xcc49174, 0x1992c8e3, 0x1263bb55, 0x20fd0a09, 0xfcd}}, + .y = { .val = {0x1f4aa9ad, 0x21b557ef, 0x1627bf4e, 0x2fabb37c, 0x3db683ad, 0x208cb797, 0x1fbced1d, 0x3073fab1, 0x6c0b}}}, +{.x = { .val = {0x326b64f1, 0x33ce6512, 0x1476d995, 0x3b73ca3d, 0x11e59db7, 0x36931894, 0xf010d4c, 0x101fc6d6, 0x7175}}, + .y = { .val = {0x324234d5, 0x9b9fbea, 0x471d2a4, 0x7fa2ddd, 0xcc86eb0, 0x34d0044d, 0x3d550f36, 0x1550d138, 0x43b4}}}, +{.x = { .val = {0xd064e13, 0x29cec184, 0x6f1e062, 0xc477811, 0x3d416615, 0x17fe63a3, 0x30690721, 0x20bfc325, 0xa8e2}}, + .y = { .val = {0x11f4cc0c, 0x3bdf1cc4, 0xdd6bd6c, 0x19e68f94, 0x2515888b, 0x2dfcf16c, 0x1c09abf, 0xd56e36e, 0x7f97}}}, +{.x = { .val = {0x3f7653a1, 0x57ae7a9, 0x13d67c1c, 0x2fa7aa9d, 0x266e63ef, 0x1dbe017a, 0x3aecbcb8, 0x3cb9f89f, 0xcac6}}, + .y = { .val = {0x3ec5e556, 0x23042b43, 0x8103a06, 0x3a0eb95a, 0x2a345081, 0x2d976690, 0x26f194cd, 0x5b978aa, 0xf7d4}}}, +{.x = { .val = {0x624003d, 0x327d2ac2, 0x238cb11c, 0x2dd9ca50, 0xe43254a, 0x3164cb96, 0x3d206efb, 0x3791bb8d, 0xe6df}}, + .y = { .val = {0x2216b93b, 0x15219438, 0x27fd7dd7, 0x7397a94, 0xf92203b, 0x3d23dee2, 0x139498f2, 0x2cedefa4, 0x8727}}}, +{.x = { .val = {0x8dce109, 0x38440d5, 0xf211d3b, 0x1438c527, 0x96082e2, 0x1033f1eb, 0x2823d66a, 0x2273669, 0x3c4e}}, + .y = { .val = {0x3a19aeea, 0xafd9648, 0x17fe697e, 0x1e7850b6, 0x364d3795, 0x15ef2855, 0x191b4807, 0x2f99a7f8, 0x43fb}}}, +{.x = { .val = {0x319497c, 0xbce0b7a, 0x12508c02, 0x166c7e94, 0x13cab15d, 0x2795b9a4, 0x285872d3, 0x14ee7268, 0x174a}}, + .y = { .val = {0x79afa73, 0xf684eb0, 0xb985438, 0x1ace8763, 0x7f9e664, 0x10557cb1, 0x9c1657b, 0x370deaff, 0xccc9}}}, +{.x = { .val = {0x40dd273, 0x3d768dbe, 0x24501115, 0xf4a0383, 0x392ea3d5, 0x1c1c7bc6, 0x6bb630c, 0x38b9e5a5, 0x20e6}}, + .y = { .val = {0x3b46b593, 0x1f3f456, 0x1a8693cc, 0x7b25e4f, 0x7465581, 0x2e86b65e, 0x159e44a0, 0x1ebf93c5, 0xd3ad}}}, +{.x = { .val = {0x1a077674, 0x1ed53cc0, 0xc24ca3e, 0x2b9a04db, 0x31db7035, 0xa0281f9, 0x351dba80, 0x2a0935e8, 0x8e0c}}, + .y = { .val = {0x12b7ed98, 0x2e132fb0, 0x2f910290, 0x3d810674, 0x22cf57cf, 0x1a749369, 0x12d41dc5, 0x1581d646, 0x4ec}}}, +{.x = { .val = {0x28192441, 0x25abf17a, 0x321b4afe, 0x36d60868, 0x3d66c1af, 0x298d54f8, 0x182d1c5f, 0x14369472, 0xf7bb}}, + .y = { .val = {0x145165ae, 0x31903a87, 0x3c4c74bb, 0x33f707ee, 0x26485db1, 0x2f18ef77, 0xa526311, 0xef8c0cd, 0x93cc}}}, +{.x = { .val = {0x1475b7ba, 0x213f7fc2, 0x918b3d8, 0xe79cc39, 0x18cdbe0, 0x395fb7d4, 0x3785c3d3, 0x25a60650, 0x9593}}, + .y = { .val = {0x3524f2fd, 0x26e2afe1, 0x709385e, 0x194fd932, 0x1cd6849c, 0xe1a92e, 0x331dd8ba, 0x154a2230, 0x2e7e}}}, +{.x = { .val = {0xbc8f53b, 0x1c9d6a50, 0x11747c70, 0x889ace, 0x33d95ed7, 0xcb29f75, 0x1a7deafe, 0x5017fc3, 0xcbee}}, + .y = { .val = {0x38c87f45, 0x248b9ac9, 0x126f7282, 0x27fd3da0, 0x294cf0d, 0x3cf9a26e, 0x1f902b51, 0x7d3d39d, 0xf621}}}, +{.x = { .val = {0x14b311dd, 0xddf222c, 0x3d71b9cf, 0x38efabbe, 0x2252e03d, 0x202fe82e, 0x2f5acdd5, 0x2eb4a3ea, 0xadd5}}, + .y = { .val = {0x9d6c38d, 0xbe60bcd, 0x29b9b890, 0x353879d9, 0x19814f52, 0x390d3e0d, 0x1c3a5974, 0xf3d368f, 0xe9c4}}}, +{.x = { .val = {0xd7c0979, 0x17d90028, 0x5a8c96f, 0xa6cc52f, 0x1ced24a, 0x277cf7fd, 0x317143fa, 0x10caea05, 0x53f2}}, + .y = { .val = {0x137b36a2, 0x27dfa431, 0x1e8b845f, 0x35693d72, 0x1b07de4b, 0x138f8244, 0x79b7ccd, 0x3bfef07c, 0xbd52}}}, +{.x = { .val = {0x1d82b151, 0x2d44d032, 0x21fba2db, 0x28290f55, 0x109a8fcc, 0x168454ec, 0x1e56d64, 0xe942b90, 0xd2a6}}, + .y = { .val = {0x1cf89405, 0x105085d3, 0x84ca52d, 0x3dd42bd, 0x148220a7, 0x2bb962ca, 0x3fcb7565, 0x21bed910, 0xe82d}}}, +{.x = { .val = {0xa72da5f, 0x31b12eb3, 0x2c413497, 0x2e735acd, 0x3725f922, 0x31c8080c, 0x525e23b, 0x20e9d840, 0xbaf1}}, + .y = { .val = {0x28f2a0cf, 0x1df398a2, 0x27393613, 0x8cdb172, 0x29b1d18e, 0x22f56375, 0x34d33568, 0x27efa732, 0xdeac}}}, +{.x = { .val = {0x56c3943, 0x296b2963, 0x2b76a5ff, 0x36f40b55, 0x8f6fd5a, 0xcca41b9, 0x40238f9, 0x3e29f8e1, 0xf7ae}}, + .y = { .val = {0x2cf442f1, 0xc7d89fe, 0xdcd0034, 0x30c0612a, 0x2b3fcfee, 0x10aef70e, 0x3da797c4, 0x2d1357f, 0x4e3b}}}, +{.x = { .val = {0x11924459, 0x3eb2515c, 0x3c7a78c1, 0x3cbe8968, 0x1dbb1f7a, 0xb8a7c37, 0x19036c5a, 0x11f2c400, 0xdfb5}}, + .y = { .val = {0xc65fd9e, 0x28817837, 0x1c031dcf, 0x2bc24c39, 0x864cc22, 0xe273a77, 0x347088b8, 0x34aa6e83, 0x9acc}}}, +{.x = { .val = {0x1617e073, 0x10dbe6d1, 0x39317b3, 0x2b2f6f4e, 0xfdc866b, 0x39e25b5f, 0x31eb890e, 0x1f88cd51, 0x6458}}, + .y = { .val = {0x1faf6589, 0x20a6797a, 0x33aeab35, 0x2e428e44, 0x299a185, 0x1b75911f, 0x102e2ae9, 0x33756fda, 0xd99f}}}, +{.x = { .val = {0x384480d, 0x12f36231, 0x291f2ef4, 0x382da88a, 0x2f0c1294, 0xa2d5324, 0x3940f2cf, 0x35ac50b7, 0xb866}}, + .y = { .val = {0xc4cafa8, 0x39966d1c, 0x31d86d60, 0x3948a012, 0x1ad7ac24, 0x9e35faa, 0x2eb7089a, 0x2c2cd09a, 0x1914}}}, +{.x = { .val = {0x1db20d6c, 0x8a736a0, 0x14fe455d, 0x354ab93b, 0x2ba87e2, 0x27459184, 0x2819ec4d, 0x2e242177, 0xec2b}}, + .y = { .val = {0x229cf4a0, 0x3a67135, 0x7efa98a, 0x288d92fa, 0x940c633, 0x3d9bc194, 0x13a1332, 0x305d9878, 0xccec}}}, +{.x = { .val = {0x23b09d0f, 0x22983b2c, 0x350becf3, 0x141903, 0x145905e5, 0x35d7bd79, 0x296ced39, 0x29f8e278, 0x71c4}}, + .y = { .val = {0x320ddb62, 0xdec7c05, 0x262ffc76, 0x1bcac212, 0x3810aa78, 0xf828a4b, 0x2f3ba0af, 0x3eb6dcde, 0x1313}}}, +{.x = { .val = {0x1d45e458, 0x1635b21b, 0x250e7fd3, 0x2a9b3a8, 0x9de042f, 0x151b4f95, 0xd885b3a, 0x2f783939, 0x8481}}, + .y = { .val = {0x1779057e, 0x3592c6d6, 0x3262e556, 0x29e710a, 0x2cb2ca90, 0x96fce73, 0x4dd84a, 0x1ee32e95, 0x38ee}}}, +{.x = { .val = {0x2ce9f114, 0x1510cd49, 0x19561dde, 0xbb5814a, 0x1492bf39, 0x10f1b347, 0x3a8b9fd, 0x29142f4e, 0x9629}}, + .y = { .val = {0x224aa391, 0x28e5cb12, 0x56af8dc, 0x9564f97, 0xef64db9, 0x2fbf4883, 0x3b6d7576, 0x26ca0317, 0xbf43}}}, +{.x = { .val = {0x26ca6cc3, 0xf4e3658, 0x187e1838, 0x1df5d1f8, 0x893df14, 0x1cc369f3, 0x24688eb1, 0x711fbc7, 0xb73b}}, + .y = { .val = {0x254fdba3, 0x2b0d75da, 0x1757f5af, 0x8a89482, 0x8050973, 0x1f592ef3, 0x122a90a5, 0x572ca52, 0x5843}}}, +{.x = { .val = {0x138f93e0, 0x31b8864b, 0x276899f9, 0x16ca8eed, 0x22fef7d0, 0x2624801e, 0x180311f, 0x5acb6d0, 0xedfe}}, + .y = { .val = {0x229405ad, 0x3405e4f7, 0x6e227e3, 0xf544031, 0x5d0d25b, 0x1d3ea92c, 0x1db3694d, 0xbc7f29, 0xee69}}}, +{.x = { .val = {0x2caf666b, 0x3358c0fd, 0xb1ce30b, 0x3f3fb4f1, 0x17f4637f, 0x1a5e6ba0, 0x102aa62b, 0x1295e9e0, 0x1346}}, + .y = { .val = {0x3f6ecc27, 0x3d256a41, 0x10942e13, 0x3cc02a07, 0xcb0ca48, 0x390cd14f, 0x14580ef7, 0x5640118, 0x69be}}}, +{.x = { .val = {0x65084ae, 0x1d612718, 0x2abe577c, 0x20af9f73, 0x3e12d191, 0x17223217, 0x5362ec0, 0x3e3d4c89, 0xeb3c}}, + .y = { .val = {0x396b9480, 0x3d9f07ff, 0x3dbd2a66, 0xad17179, 0x1ca4a1f5, 0x398f73bf, 0x1d70043f, 0x31e088b6, 0xc833}}}, +{.x = { .val = {0x2e9a5d0, 0x2396f2f3, 0xa201d9f, 0x1dbf3e61, 0x519b2a5, 0x2983c861, 0x199974f7, 0x299f424b, 0xbdf1}}, + .y = { .val = {0x562ff7b, 0x36d3dc06, 0x1626461c, 0xa02d879, 0x3f7baaa6, 0x2f952a1a, 0x1a1aaa80, 0x240aead9, 0x4095}}}, +{.x = { .val = {0x3b27e771, 0x3797f05c, 0x37da62ab, 0xed06591, 0x483b48c, 0x2f899ed9, 0xec29cd5, 0x1a9bb771, 0x6885}}, + .y = { .val = {0x7bbdab6, 0x46358a8, 0x3b0733a6, 0x748bca4, 0x1f7b4a33, 0x1bf52706, 0x1a1fb13b, 0xf7c53de, 0x77a3}}}, +{.x = { .val = {0x2d83f366, 0x2b68e834, 0x2f28588c, 0x36733b78, 0x1dc97a0c, 0x3d0c2f30, 0x3fe2e9ae, 0x277d6dc4, 0xbc4a}}, + .y = { .val = {0x181f33c1, 0x1d635999, 0x2547b16d, 0x3a2a7efe, 0x3798caa6, 0x24deb7d2, 0x5c06383, 0x20729b9e, 0xd3a}}}, +{.x = { .val = {0x33fceb19, 0x20b79517, 0x385c4092, 0x226c887d, 0x27bab42e, 0x171d89b3, 0x2ccc0abc, 0xf578473, 0xda43}}, + .y = { .val = {0x26f5cc64, 0x2139c482, 0x227b2776, 0x1dff0b64, 0x15e5218e, 0x2ef712be, 0x10301de, 0x36f4c86a, 0xe498}}}, +{.x = { .val = {0x1acf692a, 0x13789d71, 0x2207e065, 0x3120e29c, 0x16efdbc, 0x3045a607, 0xc7ec1c1, 0x2387ba7a, 0x31e}}, + .y = { .val = {0x316f667a, 0x330aa13a, 0x1bf73b09, 0x192609f1, 0x16743b70, 0x25c0a43, 0x3353dd9d, 0x1fd6d196, 0xad7e}}}, +{.x = { .val = {0x1f488b6, 0xaef5ffe, 0x3c7a9159, 0x326fcd8f, 0x257f73e9, 0x38036189, 0x161155d3, 0x2181ea23, 0xa987}}, + .y = { .val = {0x31dab1d, 0x2569eeec, 0xad5c6d4, 0x343c0659, 0x157c2239, 0x18f9f208, 0x95d61c0, 0x286af562, 0xd181}}}, +{.x = { .val = {0x25324caa, 0x152acc3f, 0x29472a39, 0x12d978c2, 0x12a32e69, 0x3631d251, 0x18bc0d23, 0x2a5efe0a, 0x8c28}}, + .y = { .val = {0xbef9482, 0x39c771cf, 0x11cb9459, 0x39e13c11, 0x3cc0eb7a, 0x3fb7cc7d, 0x5193378, 0x118e8cc, 0x40a3}}}, +{.x = { .val = {0x3611d8e2, 0x37ec807d, 0x249fc4d5, 0x4c3fa37, 0x3f0da2c8, 0x3b569811, 0xa2f196b, 0x3061ca8e, 0xab1a}}, + .y = { .val = {0x429d15b, 0x69607cf, 0x21e545f0, 0x3be4f4cf, 0x2a42b6f7, 0x297ce76d, 0x117a1e9a, 0x28de8c93, 0x13f4}}}, +{.x = { .val = {0x2651b3fa, 0x9abb990, 0x32df4342, 0x286cd95d, 0x3f31ef8e, 0xe981c94, 0x2f82d370, 0x3fa6d6fb, 0x2564}}, + .y = { .val = {0x1e5122d, 0x2e0b9a8c, 0x379816ed, 0x3cdf6ada, 0x3925f14, 0x2852b848, 0x389095f, 0x3de9819e, 0x8ad9}}}, +{.x = { .val = {0x2e180068, 0x5e38f4e, 0xbd3103b, 0x28f55b08, 0xdc01a7e, 0x1b17030c, 0x5b0cbfc, 0x184dbfeb, 0xff3d}}, + .y = { .val = {0x188c6077, 0x29aedb8, 0x1f5e67, 0x1d9dbc90, 0x16adc154, 0xdcb376, 0xe40d, 0xe6fa139, 0x1332}}}, +{.x = { .val = {0x1faccae0, 0x2312e844, 0x24bb3374, 0x22cd4316, 0x71fd23c, 0x3653393c, 0x127a8c1d, 0x259984e5, 0x8ea}}, + .y = { .val = {0xe62b945, 0x16bcd28c, 0xf0f8e95, 0x2de0efa7, 0x15c5d735, 0x39f033ee, 0x22782e24, 0x3eaef23b, 0x620e}}}, +{.x = { .val = {0x2190b632, 0xa4c4c76, 0xab5ab9a, 0x33ca88e9, 0x159d8263, 0x19b7cc55, 0x20cd9f3a, 0x18dc5d88, 0xc25f}}, + .y = { .val = {0x3c9590cf, 0x3bafcf5b, 0x2027a1d6, 0x27c13fe7, 0x9d7980a, 0x12640e0, 0x12873989, 0x13fb7a53, 0x5315}}}, +{.x = { .val = {0x1466d561, 0xb32cedf, 0x1978b4de, 0x1ed5770c, 0x8544c0c, 0xb60a95a, 0x26bab3e8, 0x237f8f33, 0x2a9e}}, + .y = { .val = {0x12e76373, 0x25b33d49, 0x3a02182f, 0x7abb05, 0xb96cf5e, 0x1ed6b582, 0x2651fbac, 0x3b69705b, 0x1df}}}, +{.x = { .val = {0x3f8be384, 0x22f4c810, 0x31db6c3e, 0x3b02ab68, 0x1ef07271, 0x2b5b253f, 0x23e1b251, 0x24290af9, 0xb237}}, + .y = { .val = {0x2b19880e, 0x4291cf7, 0x9ecb58d, 0x3c013d05, 0x1f94517, 0x143e22aa, 0x15edbe8d, 0x1a524675, 0xfc6b}}}, +}; + +#endif diff --git a/secp256k1.h b/secp256k1.h new file mode 100644 index 000000000..0e22f6c70 --- /dev/null +++ b/secp256k1.h @@ -0,0 +1,63 @@ +/** + * Copyright (c) 2013 Tomas Dzetkulic + * Copyright (c) 2013 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __SECP256K1_H__ +#define __SECP256K1_H__ + +#include + +#define USE_PRECOMPUTED_IV 1 +#define USE_PRECOMPUTED_CP 1 + +// bignum256 are 256 bits stored as 8*30 bit + 1*16 bit +// val[0] are lowest 30 bits, val[8] highest 16 bits +typedef struct { + uint32_t val[9]; +} bignum256; + +// curve point x and y +typedef struct { + bignum256 x, y; +} curve_point; + +// secp256k1 prime +extern const bignum256 prime256k1; + +// secp256k1 initial curve point +extern const curve_point G256k1; + +// secp256k1 order of G +extern const bignum256 order256k1; + +// 3/2 in G_p +extern const bignum256 three_over_two256k1; + +#ifdef USE_PRECOMPUTED_IV +extern const bignum256 secp256k1_iv[256]; +#endif + +#ifdef USE_PRECOMPUTED_CP +extern const curve_point secp256k1_cp[256]; +#endif + +#endif diff --git a/sha256.c b/sha256.c new file mode 100644 index 000000000..d4d6e43f9 --- /dev/null +++ b/sha256.c @@ -0,0 +1,127 @@ +/** + * Copyright (c) 2013 Tomas Dzetkulic + * Copyright (c) 2013 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include "aux.h" + +// process sha256 chunk (of length 64 bytes) +void process_chunk(const uint8_t *chunk, uint32_t *hash) +{ + static const uint32_t k0[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 + }; + uint32_t i, s0, s1, a, b, c, d, e, f, g, h, ch, temp, maj, w[64]; + + for (i = 0;i < 16;i++) { + w[i] = read_be(chunk + 4 * i); + } + for (;i < 64;i++) { + s0 = ror(w[i-15], 7) ^ ror(w[i-15], 18) ^ (w[i-15]>>3); + s1 = ror(w[i-2], 17) ^ ror(w[i-2], 19) ^ (w[i-2]>>10); + w[i] = w[i-16] + s0 + w[i-7] + s1; + } + a = hash[0]; + b = hash[1]; + c = hash[2]; + d = hash[3]; + e = hash[4]; + f = hash[5]; + g = hash[6]; + h = hash[7]; + for (i = 0;i < 64;i++) { + s1 = ror(e, 6) ^ ror(e, 11) ^ ror(e, 25); + ch = (e & f) ^ ((~ e) & g); + temp = h + s1 + ch + k0[i] + w[i]; + d = d + temp; + s0 = ror(a, 2) ^ ror(a, 13) ^ ror(a, 22); + maj = (a & (b ^ c)) ^ (b & c); + temp = temp + s0 + maj; + h = g; + g = f; + f = e; + e = d; + d = c; + c = b; + b = a; + a = temp; + } + hash[0] += a; + hash[1] += b; + hash[2] += c; + hash[3] += d; + hash[4] += e; + hash[5] += f; + hash[6] += g; + hash[7] += h; +} + +// compute sha256 of a message with len length in bytes +// hash is a pointer to at least 32byte array +void sha256(const uint8_t *msg, const uint32_t len, uint8_t *hash) +{ + // initial hash vales + static const uint32_t h0[8] = { + 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 + }; + uint32_t l = len, i, h[8]; + uint8_t last_chunks[128]; //for storing last 1 or 2 chunks + for (i = 0;i < 8; i++) { + h[i] = h0[i]; + } + // process complete message chunks + while (l >= 64) { + process_chunk(msg, h); + l -= 64; + msg += 64; + } + // process rest of the message + for (i = 0;i < l; i++) { + last_chunks[i] = msg[i]; + } + // add '1' bit + last_chunks[i++] = 0x80; + // pad message with zeroes + for (;(i & 63) != 56; i++) { + last_chunks[i]=0; + } + // add message length in bits + l = 8 * len; + write_be(last_chunks + i, 0); + write_be(last_chunks + i + 4, l); + // process remaining 1 or 2 chunks + process_chunk(last_chunks, h); + if (i > 64) { + process_chunk(last_chunks + 64, h); + } + // write the result + for (i = 0;i < 8; i++) { + write_be(hash + 4 * i, h[i]); + } +} diff --git a/sha256.h b/sha256.h new file mode 100644 index 000000000..5405a6008 --- /dev/null +++ b/sha256.h @@ -0,0 +1,31 @@ +/** + * Copyright (c) 2013 Tomas Dzetkulic + * Copyright (c) 2013 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __SHA256_H_ +#define __SHA256_H_ + +// compute sha256 of a message with len length (in bytes) +// hash is a pointer to at least 32 byte array +void sha256(const uint8_t *msg, const uint32_t len, uint8_t *hash); + +#endif diff --git a/test.c b/test.c new file mode 100644 index 000000000..10d2a5e1b --- /dev/null +++ b/test.c @@ -0,0 +1,100 @@ +/** + * Copyright (c) 2013 Tomas Dzetkulic + * Copyright (c) 2013 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include + +#include "ecdsa.h" +#include "rand.h" + +int main() +{ + uint8_t sig[70], priv_key[32], msg[256], buffer[1000], hash[32], *p; + uint32_t sig_len, i, j, msg_len; + SHA256_CTX sha256; + EC_GROUP *ecgroup; + int cnt = 0; + + init_rand(); + ecgroup = EC_GROUP_new_by_curve_name(NID_secp256k1); + + for (;;) { + // random message len between 1 and 256 + msg_len = (random32() & 0xFF) + 1; + // create random message + for (i = 0; i 32) { + for (j = 0;j < 32; j++) { + priv_key[j] = buffer[j + i - 23]; + } + } else { + for (j = 0; j < 32 - i; j++) { + priv_key[j] = 0; + } + for (j = 0; j < i; j++) { + priv_key[j + 32 - i] = buffer[j + 9]; + } + } + + // use our ECDSA signer to sign the message with the key + ecdsa_sign(priv_key, msg, msg_len, sig, &sig_len); + + // copy signature to the OpenSSL struct + p = sig; + ECDSA_SIG *signature = d2i_ECDSA_SIG(NULL, (const uint8_t **)&p, sig_len); + + // compute the digest of the message + SHA256_Init(&sha256); + SHA256_Update(&sha256, msg, msg_len); + SHA256_Final(hash, &sha256); + + // verify all went well, i.e. we can decrypt our signature with OpenSSL + if (ECDSA_do_verify(hash, 32, signature, eckey) != 1) { + printf("Verification failed\n"); + break; + } + ECDSA_SIG_free(signature); + EC_KEY_free(eckey); + cnt++; + if ((cnt % 100) == 0) printf("Passed ... %d\n", cnt); + } + EC_GROUP_free(ecgroup); + return 0; +} From 3645df58e1c99cee80d1fcf54bc259fbef30dcba Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 17 Aug 2013 14:28:45 +0200 Subject: [PATCH 002/627] add note about RNG --- README | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README b/README index 8709b7f08..a241d4ac2 100644 --- a/README +++ b/README @@ -4,3 +4,10 @@ MicroECDSA Heavily optimized ECDSA (secp256k1) signer for embedded devices. Distibuted under MIT License. + +Notes +----- + +a) random generator in rand.c is using stdlib's rand() function. + you should replace this code with one that uses a hardware random + generator of your microcontroller. From 1bd0592c26bc6fc100e025f19bc05e8eae2c9495 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 17 Aug 2013 14:32:25 +0200 Subject: [PATCH 003/627] fix for formatting --- ecdsa.c | 32 ++++++++++++++++---------------- sha256.c | 14 +++++++------- test.c | 2 +- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/ecdsa.c b/ecdsa.c index 7f86ccb17..1681fd82b 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -49,7 +49,7 @@ void mod(bignum256 *x, bignum256 const *prime) if (x->val[i] > prime->val[i]) { // substract p from x temp = 0x40000000u; - for (i = 0;i < 9; i++) { + for (i = 0; i < 9; i++) { temp += x->val[i] - prime->val[i]; x->val[i] = temp & 0x3FFFFFFF; temp >>= 30; @@ -68,18 +68,18 @@ void multiply(const bignum256 *k, bignum256 *x, bignum256 const *prime) uint32_t res[18], coef; // compute lower half of long multiplication - for (i = 0;i < 9; i++) + for (i = 0; i < 9; i++) { - for (j = 0;j <= i; j++) { + for (j = 0; j <= i; j++) { temp += k->val[j] * (uint64_t)x->val[i-j]; } res[i] = temp & 0x3FFFFFFFu; temp >>= 30; } // compute upper half - for (;i < 17; i++) + for (; i < 17; i++) { - for (j = i - 8; j < 9 ;j++) { + for (j = i - 8; j < 9 ; j++) { temp += k->val[j] * (uint64_t)x->val[i-j]; } res[i] = temp & 0x3FFFFFFFu; @@ -87,7 +87,7 @@ void multiply(const bignum256 *k, bignum256 *x, bignum256 const *prime) } res[17] = temp; // compute modulo p division is only estimated so this may give result greater than prime but not bigger than 2 * prime - for (i = 16;i >= 8; i--) { + for (i = 16; i >= 8; i--) { // estimate (res / prime) coef = (res[i] >> 16) + (res[i+1] << 14); // substract (coef * prime) from res @@ -100,7 +100,7 @@ void multiply(const bignum256 *k, bignum256 *x, bignum256 const *prime) } } // store the result - for (i = 0;i < 9; i++) { + for (i = 0; i < 9; i++) { x->val[i] = res[i]; } } @@ -140,12 +140,12 @@ void inverse(bignum256 *x, bignum256 const *prime) len2 = 1; k = 0; for (;;) { - for (i = 0;i < len1; i++) { + for (i = 0; i < len1; i++) { if (v[i]) break; } if (i == len1) break; for (;;) { - for (i = 0;i < 30; i++) { + for (i = 0; i < 30; i++) { if (u[0] & (1 << i)) break; } if (i == 0) break; @@ -167,7 +167,7 @@ void inverse(bignum256 *x, bignum256 const *prime) k += i; } for (;;) { - for (i = 0;i < 30; i++) { + for (i = 0; i < 30; i++) { if (v[0] & (1 << i)) break; } if (i == 0) break; @@ -254,7 +254,7 @@ void inverse(bignum256 *x, bignum256 const *prime) } } temp = 1; - for (i = 0;i < 9; i++) { + for (i = 0; i < 9; i++) { temp += 0x3FFFFFFF + prime->val[i] - r[i]; r[i] = temp & 0x3FFFFFFF; temp >>= 30; @@ -276,7 +276,7 @@ void inverse(bignum256 *x, bignum256 const *prime) temp = r[0] + prime->val[0]; r[0] = (temp >> 1) & 0x1FFFFFFF; temp >>= 30; - for (i = 1;i < 9; i++) { + for (i = 1; i < 9; i++) { temp += r[i] + prime->val[i]; r[i-1] += (temp & 1) << 29; r[i] = (temp >> 1) & 0x1FFFFFFF; @@ -321,7 +321,7 @@ void point_add(const curve_point *x1, curve_point *x2) memcpy(&xr, &lambda, sizeof(bignum256)); multiply(&xr, &xr, &prime256k1); temp = 0; - for (i = 0;i < 9; i++) { + for (i = 0; i < 9; i++) { temp += xr.val[i] + 3u * prime256k1.val[i] - x1->x.val[i] - x2->x.val[i]; xr.val[i] = temp & 0x3FFFFFFF; temp >>= 30; @@ -353,7 +353,7 @@ void point_double(curve_point *x) memcpy(&xr, &lambda, sizeof(bignum256)); multiply(&xr, &xr, &prime256k1); temp = 0; - for (i = 0;i < 9; i++) { + for (i = 0; i < 9; i++) { temp += xr.val[i] + 3u * prime256k1.val[i] - 2u * x->x.val[i]; xr.val[i] = temp & 0x3FFFFFFF; temp >>= 30; @@ -465,7 +465,7 @@ void ecdsa_sign(uint8_t *private_key, uint8_t *message, uint32_t len, uint8_t *s z.val[8] = temp; for (;;) { // generate random number k - for (i = 0;i < 8; i++) { + for (i = 0; i < 8; i++) { k.val[i] = random32() & 0x3FFFFFFF; } k.val[8] =random32() & 0xFFFF; @@ -477,7 +477,7 @@ void ecdsa_sign(uint8_t *private_key, uint8_t *message, uint32_t len, uint8_t *s // r = (rx mod n) mod(&R.x, &order256k1); // if r is zero, we try different k - for (i = 0;i < 9; i++) { + for (i = 0; i < 9; i++) { if (R.x.val[i] != 0) break; } if (i == 9) continue; diff --git a/sha256.c b/sha256.c index d4d6e43f9..b083d51ac 100644 --- a/sha256.c +++ b/sha256.c @@ -39,10 +39,10 @@ void process_chunk(const uint8_t *chunk, uint32_t *hash) }; uint32_t i, s0, s1, a, b, c, d, e, f, g, h, ch, temp, maj, w[64]; - for (i = 0;i < 16;i++) { + for (i = 0; i < 16; i++) { w[i] = read_be(chunk + 4 * i); } - for (;i < 64;i++) { + for (; i < 64; i++) { s0 = ror(w[i-15], 7) ^ ror(w[i-15], 18) ^ (w[i-15]>>3); s1 = ror(w[i-2], 17) ^ ror(w[i-2], 19) ^ (w[i-2]>>10); w[i] = w[i-16] + s0 + w[i-7] + s1; @@ -55,7 +55,7 @@ void process_chunk(const uint8_t *chunk, uint32_t *hash) f = hash[5]; g = hash[6]; h = hash[7]; - for (i = 0;i < 64;i++) { + for (i = 0; i < 64; i++) { s1 = ror(e, 6) ^ ror(e, 11) ^ ror(e, 25); ch = (e & f) ^ ((~ e) & g); temp = h + s1 + ch + k0[i] + w[i]; @@ -92,7 +92,7 @@ void sha256(const uint8_t *msg, const uint32_t len, uint8_t *hash) }; uint32_t l = len, i, h[8]; uint8_t last_chunks[128]; //for storing last 1 or 2 chunks - for (i = 0;i < 8; i++) { + for (i = 0; i < 8; i++) { h[i] = h0[i]; } // process complete message chunks @@ -102,13 +102,13 @@ void sha256(const uint8_t *msg, const uint32_t len, uint8_t *hash) msg += 64; } // process rest of the message - for (i = 0;i < l; i++) { + for (i = 0; i < l; i++) { last_chunks[i] = msg[i]; } // add '1' bit last_chunks[i++] = 0x80; // pad message with zeroes - for (;(i & 63) != 56; i++) { + for (; (i & 63) != 56; i++) { last_chunks[i]=0; } // add message length in bits @@ -121,7 +121,7 @@ void sha256(const uint8_t *msg, const uint32_t len, uint8_t *hash) process_chunk(last_chunks + 64, h); } // write the result - for (i = 0;i < 8; i++) { + for (i = 0; i < 8; i++) { write_be(hash + 4 * i, h[i]); } } diff --git a/test.c b/test.c index 10d2a5e1b..5419494c6 100644 --- a/test.c +++ b/test.c @@ -61,7 +61,7 @@ int main() i = buffer[8]; // extract key data if (i > 32) { - for (j = 0;j < 32; j++) { + for (j = 0; j < 32; j++) { priv_key[j] = buffer[j + i - 23]; } } else { From 8e7bee704316d354d8bcf1aa4371f0df6a7efc4e Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 18 Aug 2013 17:30:23 +0200 Subject: [PATCH 004/627] add speed test --- .gitignore | 3 ++- Makefile | 14 ++++++---- test-speed.c | 58 +++++++++++++++++++++++++++++++++++++++++ test.c => test-verify.c | 3 ++- 4 files changed, 71 insertions(+), 7 deletions(-) create mode 100644 test-speed.c rename test.c => test-verify.c (98%) diff --git a/.gitignore b/.gitignore index 76758b086..e9c650a56 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ *.o -test +test-speed +test-verify diff --git a/Makefile b/Makefile index dae2048f0..96a2291fa 100644 --- a/Makefile +++ b/Makefile @@ -1,13 +1,17 @@ CC = gcc CFLAGS = -Wall -OBJS = aux.o ecdsa.o secp256k1.o sha256.o rand.o test.o -NAME = test +OBJS = aux.o ecdsa.o secp256k1.o sha256.o rand.o + +all: test-speed test-verify %.o: %.c $(CC) $(CFLAGS) -o $@ -c $< -$(NAME): $(OBJS) - gcc $(OBJS) -o $(NAME) -lcrypto +test-speed: test-speed.o $(OBJS) + gcc test-speed.o $(OBJS) -o test-speed -lcrypto + +test-verify: test-verify.o $(OBJS) + gcc test-verify.o $(OBJS) -o test-verify -lcrypto clean: - rm -f $(OBJS) $(NAME) + rm -f $(OBJS) test-speed test-verify diff --git a/test-speed.c b/test-speed.c new file mode 100644 index 000000000..51b06fa6f --- /dev/null +++ b/test-speed.c @@ -0,0 +1,58 @@ +/** + * Copyright (c) 2013 Tomas Dzetkulic + * Copyright (c) 2013 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include + +#include "ecdsa.h" +#include "rand.h" + +int main() +{ + uint8_t sig[70], priv_key[32], msg[256]; + uint32_t sig_len, i, msg_len; + int cnt = 0; + + init_rand(); + + clock_t t = clock(); + for (;;) { + // random message len between 1 and 256 + msg_len = (random32() & 0xFF) + 1; + // create random message + for (i = 0; i < msg_len; i++) { + msg[i] = random32() & 0xFF; + } + // create random privkey + for (i = 0; i < 32; i++) { + priv_key[i] = random32() & 0xFF; + } + + // use our ECDSA signer to sign the message with the key + ecdsa_sign(priv_key, msg, msg_len, sig, &sig_len); + + cnt++; + if ((cnt % 100) == 0) printf("Speed: %f sig/s \n", 1.0f * cnt / ((float)(clock() - t) / CLOCKS_PER_SEC)); + } + return 0; +} diff --git a/test.c b/test-verify.c similarity index 98% rename from test.c rename to test-verify.c index 5419494c6..a5f92c88f 100644 --- a/test.c +++ b/test-verify.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include "ecdsa.h" @@ -44,7 +45,7 @@ int main() // random message len between 1 and 256 msg_len = (random32() & 0xFF) + 1; // create random message - for (i = 0; i Date: Sun, 18 Aug 2013 20:54:18 +0200 Subject: [PATCH 005/627] add speed testing code for stm32 --- speed-stm32/Makefile | 8 ++ speed-stm32/Makefile.include | 54 +++++++ speed-stm32/aux.c | 1 + speed-stm32/aux.h | 1 + speed-stm32/ecdsa.c | 1 + speed-stm32/ecdsa.h | 1 + speed-stm32/rand.c | 16 +++ speed-stm32/rand.h | 1 + speed-stm32/secp256k1.c | 1 + speed-stm32/secp256k1.h | 1 + speed-stm32/sha256.c | 1 + speed-stm32/sha256.h | 1 + speed-stm32/speed.c | 270 +++++++++++++++++++++++++++++++++++ speed-stm32/speed.ld | 9 ++ test-speed.c | 2 +- 15 files changed, 367 insertions(+), 1 deletion(-) create mode 100644 speed-stm32/Makefile create mode 100644 speed-stm32/Makefile.include create mode 120000 speed-stm32/aux.c create mode 120000 speed-stm32/aux.h create mode 120000 speed-stm32/ecdsa.c create mode 120000 speed-stm32/ecdsa.h create mode 100644 speed-stm32/rand.c create mode 120000 speed-stm32/rand.h create mode 120000 speed-stm32/secp256k1.c create mode 120000 speed-stm32/secp256k1.h create mode 120000 speed-stm32/sha256.c create mode 120000 speed-stm32/sha256.h create mode 100644 speed-stm32/speed.c create mode 100644 speed-stm32/speed.ld diff --git a/speed-stm32/Makefile b/speed-stm32/Makefile new file mode 100644 index 000000000..a26e62282 --- /dev/null +++ b/speed-stm32/Makefile @@ -0,0 +1,8 @@ +NAME = speed +OBJS += aux.o +OBJS += ecdsa.o +OBJS += rand.o +OBJS += secp256k1.o +OBJS += sha256.o + +include Makefile.include diff --git a/speed-stm32/Makefile.include b/speed-stm32/Makefile.include new file mode 100644 index 000000000..26f52eb6a --- /dev/null +++ b/speed-stm32/Makefile.include @@ -0,0 +1,54 @@ +PREFIX ?= arm-none-eabi +CC = $(PREFIX)-gcc +LD = $(PREFIX)-gcc +OBJCOPY = $(PREFIX)-objcopy +OBJDUMP = $(PREFIX)-objdump +FLASH = $(shell which st-flash) + +TOOLCHAIN_DIR ?= ../../../STM/libopencm3 + +CFLAGS += -Os -g \ + -Wall -Wextra -Wimplicit-function-declaration -Wredundant-decls -Wstrict-prototypes -Wundef -Wshadow \ + -fno-common -mcpu=cortex-m3 -mthumb -msoft-float -MD -DSTM32F2 \ + -I$(TOOLCHAIN_DIR)/include +LDSCRIPT ?= $(NAME).ld +LDFLAGS += --static -Wl,--start-group -lc -lgcc -lnosys -Wl,--end-group \ + -L$(TOOLCHAIN_DIR)/lib -L$(TOOLCHAIN_DIR)/lib/stm32/f2 \ + -T$(LDSCRIPT) -nostartfiles -Wl,--gc-sections \ + -mthumb -march=armv7 -mfix-cortex-m3-ldrd -msoft-float +OBJS += $(NAME).o + +all: images + +images: $(NAME).bin + +flash: $(NAME).bin + $(FLASH) write $(NAME).bin 0x8000000 + +$(NAME).bin: $(NAME).elf + $(OBJCOPY) -Obinary $(NAME).elf $(NAME).bin + +$(NAME).hex: $(NAME).elf + $(OBJCOPY) -Oihex $(NAME).elf $(NAME).hex + +$(NAME).srec: $(NAME).elf + $(OBJCOPY) -Osrec $(NAME).elf $(NAME).srec + +$(NAME).list: $(NAME).elf + $(OBJDUMP) -S $(NAME).elf > $(NAME).list + +$(NAME).elf: $(OBJS) $(LDSCRIPT) $(TOOLCHAIN_DIR)/lib/libopencm3_stm32f2.a + $(LD) -o $(NAME).elf $(OBJS) -lopencm3_stm32f2 $(LDFLAGS) + +%.o: %.c Makefile + $(CC) $(CFLAGS) -o $@ -c $< + +clean: + rm -f *.o + rm -f *.d + rm -f *.elf + rm -f *.bin + rm -f *.hex + rm -f *.srec + rm -f *.list + rm -f usb.pb* diff --git a/speed-stm32/aux.c b/speed-stm32/aux.c new file mode 120000 index 000000000..aced8d8ff --- /dev/null +++ b/speed-stm32/aux.c @@ -0,0 +1 @@ +../aux.c \ No newline at end of file diff --git a/speed-stm32/aux.h b/speed-stm32/aux.h new file mode 120000 index 000000000..cb12794d5 --- /dev/null +++ b/speed-stm32/aux.h @@ -0,0 +1 @@ +../aux.h \ No newline at end of file diff --git a/speed-stm32/ecdsa.c b/speed-stm32/ecdsa.c new file mode 120000 index 000000000..72f7870c9 --- /dev/null +++ b/speed-stm32/ecdsa.c @@ -0,0 +1 @@ +../ecdsa.c \ No newline at end of file diff --git a/speed-stm32/ecdsa.h b/speed-stm32/ecdsa.h new file mode 120000 index 000000000..23affb2f2 --- /dev/null +++ b/speed-stm32/ecdsa.h @@ -0,0 +1 @@ +../ecdsa.h \ No newline at end of file diff --git a/speed-stm32/rand.c b/speed-stm32/rand.c new file mode 100644 index 000000000..73ebecfa4 --- /dev/null +++ b/speed-stm32/rand.c @@ -0,0 +1,16 @@ +#include +#include "rand.h" + +void init_rand(void) { +} + +uint32_t random32(void) { + static uint32_t last = 0, new = 0; + while (new == last) { + if (((RNG_SR & (RNG_SR_SEIS | RNG_SR_CEIS)) == 0) && ((RNG_SR & RNG_SR_DRDY) > 0)) { + new = RNG_DR; + } + } + last = new; + return new; +} diff --git a/speed-stm32/rand.h b/speed-stm32/rand.h new file mode 120000 index 000000000..f3be0086c --- /dev/null +++ b/speed-stm32/rand.h @@ -0,0 +1 @@ +../rand.h \ No newline at end of file diff --git a/speed-stm32/secp256k1.c b/speed-stm32/secp256k1.c new file mode 120000 index 000000000..5a9d1084e --- /dev/null +++ b/speed-stm32/secp256k1.c @@ -0,0 +1 @@ +../secp256k1.c \ No newline at end of file diff --git a/speed-stm32/secp256k1.h b/speed-stm32/secp256k1.h new file mode 120000 index 000000000..c5f18c823 --- /dev/null +++ b/speed-stm32/secp256k1.h @@ -0,0 +1 @@ +../secp256k1.h \ No newline at end of file diff --git a/speed-stm32/sha256.c b/speed-stm32/sha256.c new file mode 120000 index 000000000..1068d4ffe --- /dev/null +++ b/speed-stm32/sha256.c @@ -0,0 +1 @@ +../sha256.c \ No newline at end of file diff --git a/speed-stm32/sha256.h b/speed-stm32/sha256.h new file mode 120000 index 000000000..d625aee2f --- /dev/null +++ b/speed-stm32/sha256.h @@ -0,0 +1 @@ +../sha256.h \ No newline at end of file diff --git a/speed-stm32/speed.c b/speed-stm32/speed.c new file mode 100644 index 000000000..bf429a0ce --- /dev/null +++ b/speed-stm32/speed.c @@ -0,0 +1,270 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2010 Gareth McMullin + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rand.h" +#include "ecdsa.h" + +static const struct usb_device_descriptor dev = { + .bLength = USB_DT_DEVICE_SIZE, + .bDescriptorType = USB_DT_DEVICE, + .bcdUSB = 0x0200, + .bDeviceClass = USB_CLASS_CDC, + .bDeviceSubClass = 0, + .bDeviceProtocol = 0, + .bMaxPacketSize0 = 64, + .idVendor = 0x0483, + .idProduct = 0x5740, + .bcdDevice = 0x0200, + .iManufacturer = 1, + .iProduct = 2, + .iSerialNumber = 3, + .bNumConfigurations = 1, +}; + +/* + * This notification endpoint isn't implemented. According to CDC spec it's + * optional, but its absence causes a NULL pointer dereference in the + * Linux cdc_acm driver. + */ +static const struct usb_endpoint_descriptor comm_endp[] = {{ + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0x83, + .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, + .wMaxPacketSize = 16, + .bInterval = 255, +}}; + +static const struct usb_endpoint_descriptor data_endp[] = {{ + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0x01, + .bmAttributes = USB_ENDPOINT_ATTR_BULK, + .wMaxPacketSize = 64, + .bInterval = 1, +}, { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0x82, + .bmAttributes = USB_ENDPOINT_ATTR_BULK, + .wMaxPacketSize = 64, + .bInterval = 1, +}}; + +static const struct { + struct usb_cdc_header_descriptor header; + struct usb_cdc_call_management_descriptor call_mgmt; + struct usb_cdc_acm_descriptor acm; + struct usb_cdc_union_descriptor cdc_union; +} __attribute__((packed)) cdcacm_functional_descriptors = { + .header = { + .bFunctionLength = sizeof(struct usb_cdc_header_descriptor), + .bDescriptorType = CS_INTERFACE, + .bDescriptorSubtype = USB_CDC_TYPE_HEADER, + .bcdCDC = 0x0110, + }, + .call_mgmt = { + .bFunctionLength = + sizeof(struct usb_cdc_call_management_descriptor), + .bDescriptorType = CS_INTERFACE, + .bDescriptorSubtype = USB_CDC_TYPE_CALL_MANAGEMENT, + .bmCapabilities = 0, + .bDataInterface = 1, + }, + .acm = { + .bFunctionLength = sizeof(struct usb_cdc_acm_descriptor), + .bDescriptorType = CS_INTERFACE, + .bDescriptorSubtype = USB_CDC_TYPE_ACM, + .bmCapabilities = 0, + }, + .cdc_union = { + .bFunctionLength = sizeof(struct usb_cdc_union_descriptor), + .bDescriptorType = CS_INTERFACE, + .bDescriptorSubtype = USB_CDC_TYPE_UNION, + .bControlInterface = 0, + .bSubordinateInterface0 = 1, + } +}; + +static const struct usb_interface_descriptor comm_iface[] = {{ + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 0, + .bAlternateSetting = 0, + .bNumEndpoints = 1, + .bInterfaceClass = USB_CLASS_CDC, + .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM, + .bInterfaceProtocol = USB_CDC_PROTOCOL_AT, + .iInterface = 0, + + .endpoint = comm_endp, + + .extra = &cdcacm_functional_descriptors, + .extralen = sizeof(cdcacm_functional_descriptors) +}}; + +static const struct usb_interface_descriptor data_iface[] = {{ + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 1, + .bAlternateSetting = 0, + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_DATA, + .bInterfaceSubClass = 0, + .bInterfaceProtocol = 0, + .iInterface = 0, + + .endpoint = data_endp, +}}; + +static const struct usb_interface ifaces[] = {{ + .num_altsetting = 1, + .altsetting = comm_iface, +}, { + .num_altsetting = 1, + .altsetting = data_iface, +}}; + +static const struct usb_config_descriptor config = { + .bLength = USB_DT_CONFIGURATION_SIZE, + .bDescriptorType = USB_DT_CONFIGURATION, + .wTotalLength = 0, + .bNumInterfaces = 2, + .bConfigurationValue = 1, + .iConfiguration = 0, + .bmAttributes = 0x80, + .bMaxPower = 0x32, + + .interface = ifaces, +}; + +static const char *usb_strings[] = { + "Black Sphere Technologies", + "CDC-ACM Demo", + "DEMO", +}; + +/* Buffer to be used for control requests. */ +uint8_t usbd_control_buffer[128]; + +static int cdcacm_control_request(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf, + uint16_t *len, void (**complete)(usbd_device *usbd_dev, struct usb_setup_data *req)) +{ + (void)complete; + (void)buf; + (void)usbd_dev; + + switch (req->bRequest) { + case USB_CDC_REQ_SET_CONTROL_LINE_STATE: { + /* + * This Linux cdc_acm driver requires this to be implemented + * even though it's optional in the CDC spec, and we don't + * advertise it in the ACM functional descriptor. + */ + return 1; + } + case USB_CDC_REQ_SET_LINE_CODING: + if (*len < sizeof(struct usb_cdc_line_coding)) + return 0; + + return 1; + } + return 0; +} + +void test_sign(void) +{ + uint8_t sig[70], priv_key[32], msg[256]; + uint32_t sig_len, i, msg_len; + + // random message len between 1 and 256 + msg_len = (random32() & 0xFF) + 1; + // create random message + for (i = 0; i < msg_len; i++) { + msg[i] = random32() & 0xFF; + } + // create random privkey + for (i = 0; i < 32; i++) { + priv_key[i] = random32() & 0xFF; + } + + // use our ECDSA signer to sign the message with the key + for (i = 0; i < 100; i++) { + ecdsa_sign(priv_key, msg, msg_len, sig, &sig_len); + } +} + +static void cdcacm_data_rx_cb(usbd_device *usbd_dev, uint8_t ep) +{ + (void)ep; + + char buf[64]; + int len = usbd_ep_read_packet(usbd_dev, 0x01, buf, 64); + + if (len) { + len = sprintf(buf, "Start\r\n"); + usbd_ep_write_packet(usbd_dev, 0x82, buf, len); + test_sign(); + len = sprintf(buf, "Done!\r\n"); + usbd_ep_write_packet(usbd_dev, 0x82, buf, len); + } +} + +static void cdcacm_set_config(usbd_device *usbd_dev, uint16_t wValue) +{ + (void)wValue; + + usbd_ep_setup(usbd_dev, 0x01, USB_ENDPOINT_ATTR_BULK, 64, cdcacm_data_rx_cb); + usbd_ep_setup(usbd_dev, 0x82, USB_ENDPOINT_ATTR_BULK, 64, NULL); + usbd_ep_setup(usbd_dev, 0x83, USB_ENDPOINT_ATTR_INTERRUPT, 16, NULL); + + usbd_register_control_callback( + usbd_dev, + USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE, + USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, + cdcacm_control_request); +} + +int main(void) +{ + usbd_device *usbd_dev; + + rcc_clock_setup_hse_3v3(&hse_8mhz_3v3[CLOCK_3V3_120MHZ]); + + rcc_peripheral_enable_clock(&RCC_AHB1ENR, RCC_AHB1ENR_IOPAEN); + rcc_peripheral_enable_clock(&RCC_AHB2ENR, RCC_AHB2ENR_OTGFSEN); + + gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO9 | GPIO11 | GPIO12); + gpio_set_af(GPIOA, GPIO_AF10, GPIO9 | GPIO11 | GPIO12); + + usbd_dev = usbd_init(&otgfs_usb_driver, &dev, &config, usb_strings, 3, usbd_control_buffer, sizeof(usbd_control_buffer)); + usbd_register_set_config_callback(usbd_dev, cdcacm_set_config); + + while (1) + usbd_poll(usbd_dev); +} diff --git a/speed-stm32/speed.ld b/speed-stm32/speed.ld new file mode 100644 index 000000000..539837839 --- /dev/null +++ b/speed-stm32/speed.ld @@ -0,0 +1,9 @@ +/* STM32F205RE - 512K Flash, 128K RAM */ + +MEMORY +{ + rom (rx) : ORIGIN = 0x08000000, LENGTH = 512K + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 128K +} + +INCLUDE libopencm3_stm32f2.ld diff --git a/test-speed.c b/test-speed.c index 51b06fa6f..9766fd42b 100644 --- a/test-speed.c +++ b/test-speed.c @@ -52,7 +52,7 @@ int main() ecdsa_sign(priv_key, msg, msg_len, sig, &sig_len); cnt++; - if ((cnt % 100) == 0) printf("Speed: %f sig/s \n", 1.0f * cnt / ((float)(clock() - t) / CLOCKS_PER_SEC)); + if ((cnt % 100) == 0) printf("Speed: %f sig/s\n", 1.0f * cnt / ((float)(clock() - t) / CLOCKS_PER_SEC)); } return 0; } From ee09a6a7b2856ab11cde9d7c942348e01df632ee Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 19 Aug 2013 12:40:58 +0200 Subject: [PATCH 006/627] param names cleanup --- ecdsa.c | 72 ++++++++++++++++++++++++++++---------------------------- ecdsa.h | 2 +- sha256.c | 2 +- 3 files changed, 38 insertions(+), 38 deletions(-) diff --git a/ecdsa.c b/ecdsa.c index 1681fd82b..50a6ce48b 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -39,7 +39,7 @@ void mod(bignum256 *x, bignum256 const *prime) // compare numbers while (i >= 0 && prime->val[i] == x->val[i]) --i; // if equal - if (i==-1) { + if (i == -1) { // set x to zero for (i = 0; i < 9; i++) { x->val[i] = 0; @@ -149,19 +149,19 @@ void inverse(bignum256 *x, bignum256 const *prime) if (u[0] & (1 << i)) break; } if (i == 0) break; - mask=(1 << i) - 1; + mask = (1 << i) - 1; for (j = 0; j + 1 < len1; j++) { u[j] = (u[j] >> i) | ((u[j + 1] & mask) << (30 - i)); } u[j] = (u[j] >> i); - mask=(1 << (30 - i)) - 1; + mask = (1 << (30 - i)) - 1; s[len2] = s[len2 - 1] >> (30 - i); for (j = len2 - 1; j > 0; j--) { s[j] = (s[j - 1] >> (30 - i)) | ((s[j] & mask) << i); } s[0] = (s[0] & mask) << i; if (s[len2]) { - r[len2]=0; + r[len2] = 0; len2++; } k += i; @@ -176,14 +176,14 @@ void inverse(bignum256 *x, bignum256 const *prime) v[j] = (v[j] >> i) | ((v[j + 1] & mask) << (30 - i)); } v[j] = (v[j] >> i); - mask=(1 << (30 - i)) - 1; + mask = (1 << (30 - i)) - 1; r[len2] = r[len2 - 1] >> (30 - i); for (j = len2 - 1; j > 0; j--) { r[j] = (r[j - 1] >> (30 - i)) | ((r[j] & mask) << i); } r[0] = (r[0] & mask) << i; if (r[len2]) { - s[len2]=0; + s[len2] = 0; len2++; } k += i; @@ -240,7 +240,7 @@ void inverse(bignum256 *x, bignum256 const *prime) len2++; } } - if (u[len1 - 1]==0 && v[len1 - 1]==0) len1--; + if (u[len1 - 1] == 0 && v[len1 - 1] == 0) len1--; k++; } i = 8; @@ -308,65 +308,65 @@ void fast_substract(const bignum256 *a, const bignum256 *b, bignum256 *res) } } -// x2 = x1 + x2; -void point_add(const curve_point *x1, curve_point *x2) +// cp2 = cp1 + cp2 +void point_add(const curve_point *cp1, curve_point *cp2) { int i; uint32_t temp; bignum256 lambda, inv, xr, yr; - fast_substract(&(x2->x), &(x1->x), &inv); + fast_substract(&(cp2->x), &(cp1->x), &inv); inverse(&inv, &prime256k1); - fast_substract(&(x2->y), &(x1->y), &lambda); + fast_substract(&(cp2->y), &(cp1->y), &lambda); multiply(&inv, &lambda, &prime256k1); memcpy(&xr, &lambda, sizeof(bignum256)); multiply(&xr, &xr, &prime256k1); temp = 0; for (i = 0; i < 9; i++) { - temp += xr.val[i] + 3u * prime256k1.val[i] - x1->x.val[i] - x2->x.val[i]; + temp += xr.val[i] + 3u * prime256k1.val[i] - cp1->x.val[i] - cp2->x.val[i]; xr.val[i] = temp & 0x3FFFFFFF; temp >>= 30; } fast_mod(&xr, &prime256k1); - fast_substract(&(x1->x), &xr, &yr); + fast_substract(&(cp1->x), &xr, &yr); // no need to fast_mod here // fast_mod(&yr); multiply(&lambda, &yr, &prime256k1); - fast_substract(&yr, &(x1->y), &yr); + fast_substract(&yr, &(cp1->y), &yr); fast_mod(&yr, &prime256k1); - memcpy(&(x2->x), &xr, sizeof(bignum256)); - memcpy(&(x2->y), &yr, sizeof(bignum256)); + memcpy(&(cp2->x), &xr, sizeof(bignum256)); + memcpy(&(cp2->y), &yr, sizeof(bignum256)); } #ifndef USE_PRECOMPUTED_CP -// x = x + x; -void point_double(curve_point *x) +// cp = cp + cp +void point_double(curve_point *cp) { int i; uint32_t temp; bignum256 lambda, inverse_y, xr, yr; - memcpy(&inverse_y, &(x->y), sizeof(bignum256)); + memcpy(&inverse_y, &(cp->y), sizeof(bignum256)); inverse(&inverse_y, &prime256k1); memcpy(&lambda, &three_over_two256k1, sizeof(bignum256)); multiply(&inverse_y, &lambda, &prime256k1); - multiply(&(x->x), &lambda, &prime256k1); - multiply(&(x->x), &lambda, &prime256k1); + multiply(&(cp->x), &lambda, &prime256k1); + multiply(&(cp->x), &lambda, &prime256k1); memcpy(&xr, &lambda, sizeof(bignum256)); multiply(&xr, &xr, &prime256k1); temp = 0; for (i = 0; i < 9; i++) { - temp += xr.val[i] + 3u * prime256k1.val[i] - 2u * x->x.val[i]; + temp += xr.val[i] + 3u * prime256k1.val[i] - 2u * cp->x.val[i]; xr.val[i] = temp & 0x3FFFFFFF; temp >>= 30; } fast_mod(&xr, &prime256k1); - fast_substract(&(x->x), &xr, &yr); + fast_substract(&(cp->x), &xr, &yr); // no need to fast_mod here // fast_mod(&yr); multiply(&lambda, &yr, &prime256k1); - fast_substract(&yr, &(x->y), &yr); + fast_substract(&yr, &(cp->y), &yr); fast_mod(&yr, &prime256k1); - memcpy(&(x->x), &xr, sizeof(bignum256)); - memcpy(&(x->y), &yr, sizeof(bignum256)); + memcpy(&(cp->x), &xr, sizeof(bignum256)); + memcpy(&(cp->y), &yr, sizeof(bignum256)); } #endif @@ -438,12 +438,12 @@ void write_der(const bignum256 *x, uint8_t *buf) } // uses secp256k1 curve -// private key is a 32 byte big endian stored number -// message is a data to be signed -// len is the message length +// priv_key is a 32 byte big endian stored number +// msg is a data to be signed +// msg_len is the message length // sig is at least 70 bytes long array for the signature // sig_len is the pointer to a uint that will contain resulting signature length. note that ((*sig_len) == sig[1]+2) -void ecdsa_sign(uint8_t *private_key, uint8_t *message, uint32_t len, uint8_t *sig, uint32_t *sig_len) +void ecdsa_sign(uint8_t *priv_key, uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint32_t *sig_len) { uint32_t i; uint64_t temp; @@ -452,7 +452,7 @@ void ecdsa_sign(uint8_t *private_key, uint8_t *message, uint32_t len, uint8_t *s bignum256 k, z; bignum256 *da = &R.y; // compute hash function of message - sha256(message, len, hash); + sha256(msg, msg_len, hash); // if double hash is required uncomment the following line: // sha256(hash, 32, hash); @@ -468,10 +468,10 @@ void ecdsa_sign(uint8_t *private_key, uint8_t *message, uint32_t len, uint8_t *s for (i = 0; i < 8; i++) { k.val[i] = random32() & 0x3FFFFFFF; } - k.val[8] =random32() & 0xFFFF; + k.val[8] = random32() & 0xFFFF; // if k is too big or too small, we don't like it - if (k.val[5] == 0x3FFFFFFF && k.val[6]==0x3FFFFFFF && k.val[7]==0x3FFFFFFF && k.val[8]==0xFFFF) continue; - if (k.val[5] == 0x0 && k.val[6]==0x0 && k.val[7]==0x0 && k.val[8]==0x0) continue; + if (k.val[5] == 0x3FFFFFFF && k.val[6] == 0x3FFFFFFF && k.val[7] == 0x3FFFFFFF && k.val[8] == 0xFFFF) continue; + if (k.val[5] == 0x0 && k.val[6] == 0x0 && k.val[7] == 0x0 && k.val[8] == 0x0) continue; // compute k*G scalar_multiply(&k, &R); // r = (rx mod n) @@ -483,8 +483,8 @@ void ecdsa_sign(uint8_t *private_key, uint8_t *message, uint32_t len, uint8_t *s if (i == 9) continue; inverse(&k, &order256k1); temp = 0; - for (i=0; i<8; i++) { - temp += (((uint64_t)read_be(private_key + (7 - i) * 4)) << (2 * i)); + for (i = 0; i < 8; i++) { + temp += (((uint64_t)read_be(priv_key + (7 - i) * 4)) << (2 * i)); da->val[i] = temp & 0x3FFFFFFF; temp >>= 30; } diff --git a/ecdsa.h b/ecdsa.h index 6968bfa07..d7d1f6173 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -27,6 +27,6 @@ #include // uses secp256k1 curve -void ecdsa_sign(uint8_t *private_key, uint8_t *message, uint32_t len, uint8_t *sig, uint32_t *sig_len); +void ecdsa_sign(uint8_t *priv_key, uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint32_t *sig_len); #endif diff --git a/sha256.c b/sha256.c index b083d51ac..ccb9ed4da 100644 --- a/sha256.c +++ b/sha256.c @@ -109,7 +109,7 @@ void sha256(const uint8_t *msg, const uint32_t len, uint8_t *hash) last_chunks[i++] = 0x80; // pad message with zeroes for (; (i & 63) != 56; i++) { - last_chunks[i]=0; + last_chunks[i] = 0; } // add message length in bits l = 8 * len; From 0ed5bea0d04fac1d4902cb52ee40c5d2ab80aaf6 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 21 Aug 2013 01:31:24 +0200 Subject: [PATCH 007/627] properly initialize rng --- speed-stm32/.gitignore | 7 +++++++ speed-stm32/rand.c | 1 + speed-stm32/speed.c | 6 ++++-- 3 files changed, 12 insertions(+), 2 deletions(-) create mode 100644 speed-stm32/.gitignore diff --git a/speed-stm32/.gitignore b/speed-stm32/.gitignore new file mode 100644 index 000000000..73f188b62 --- /dev/null +++ b/speed-stm32/.gitignore @@ -0,0 +1,7 @@ +*.o +*.d +*.bin +*.hex +*.srec +*.list +*.elf diff --git a/speed-stm32/rand.c b/speed-stm32/rand.c index 73ebecfa4..3aaa7be72 100644 --- a/speed-stm32/rand.c +++ b/speed-stm32/rand.c @@ -2,6 +2,7 @@ #include "rand.h" void init_rand(void) { + RNG_CR |= RNG_CR_IE | RNG_CR_RNGEN; } uint32_t random32(void) { diff --git a/speed-stm32/speed.c b/speed-stm32/speed.c index bf429a0ce..cddda1b6d 100644 --- a/speed-stm32/speed.c +++ b/speed-stm32/speed.c @@ -213,8 +213,8 @@ void test_sign(void) priv_key[i] = random32() & 0xFF; } - // use our ECDSA signer to sign the message with the key - for (i = 0; i < 100; i++) { + // use our ECDSA signer 10 times to sign the message with the key + for (i = 0; i < 10; i++) { ecdsa_sign(priv_key, msg, msg_len, sig, &sig_len); } } @@ -258,6 +258,8 @@ int main(void) rcc_peripheral_enable_clock(&RCC_AHB1ENR, RCC_AHB1ENR_IOPAEN); rcc_peripheral_enable_clock(&RCC_AHB2ENR, RCC_AHB2ENR_OTGFSEN); + rcc_peripheral_enable_clock(&RCC_AHB2ENR, RCC_AHB2ENR_RNGEN); + init_rand(); gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO9 | GPIO11 | GPIO12); gpio_set_af(GPIOA, GPIO_AF10, GPIO9 | GPIO11 | GPIO12); From 32c9ff72a5fc0b9d9ea27782398fc9f734bd3a8a Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 21 Aug 2013 14:49:36 +0200 Subject: [PATCH 008/627] reorganize code in speed tests --- speed-stm32/speed.c | 48 +++++++++++++++++++++++---------------------- test-speed.c | 27 +++++++++++++------------ 2 files changed, 40 insertions(+), 35 deletions(-) diff --git a/speed-stm32/speed.c b/speed-stm32/speed.c index cddda1b6d..1532f0f4a 100644 --- a/speed-stm32/speed.c +++ b/speed-stm32/speed.c @@ -197,39 +197,41 @@ static int cdcacm_control_request(usbd_device *usbd_dev, struct usb_setup_data * return 0; } -void test_sign(void) -{ - uint8_t sig[70], priv_key[32], msg[256]; - uint32_t sig_len, i, msg_len; - - // random message len between 1 and 256 - msg_len = (random32() & 0xFF) + 1; - // create random message - for (i = 0; i < msg_len; i++) { - msg[i] = random32() & 0xFF; - } - // create random privkey - for (i = 0; i < 32; i++) { - priv_key[i] = random32() & 0xFF; - } - - // use our ECDSA signer 10 times to sign the message with the key - for (i = 0; i < 10; i++) { - ecdsa_sign(priv_key, msg, msg_len, sig, &sig_len); - } -} - static void cdcacm_data_rx_cb(usbd_device *usbd_dev, uint8_t ep) { (void)ep; char buf[64]; + int len = usbd_ep_read_packet(usbd_dev, 0x01, buf, 64); if (len) { + uint8_t sig[70], priv_key[32], msg[256]; + uint32_t sig_len, i, msg_len; + + // random message len between 1 and 256 + msg_len = (random32() & 0xFF) + 1; + // create random message + for (i = 0; i < msg_len; i++) { + msg[i] = random32() & 0xFF; + } + // create random privkey + for (i = 0; i < 8; i++) { + uint32_t r = random32(); + priv_key[4 * i ] = r & 0xFF; + priv_key[4 * i + 1] = (r >> 8) & 0xFF; + priv_key[4 * i + 2] = (r >> 16) & 0xFF; + priv_key[4 * i + 3] = (r >> 24) & 0xFF; + } + len = sprintf(buf, "Start\r\n"); usbd_ep_write_packet(usbd_dev, 0x82, buf, len); - test_sign(); + + // use our ECDSA signer 10 times to sign the message with the key + for (i = 0; i < 10; i++) { + ecdsa_sign(priv_key, msg, msg_len, sig, &sig_len); + } + len = sprintf(buf, "Done!\r\n"); usbd_ep_write_packet(usbd_dev, 0x82, buf, len); } diff --git a/test-speed.c b/test-speed.c index 9766fd42b..0c336382b 100644 --- a/test-speed.c +++ b/test-speed.c @@ -35,22 +35,25 @@ int main() init_rand(); + // random message len between 1 and 256 + msg_len = (random32() & 0xFF) + 1; + // create random message + for (i = 0; i < msg_len; i++) { + msg[i] = random32() & 0xFF; + } + // create random privkey + for (i = 0; i < 8; i++) { + uint32_t r = random32(); + priv_key[4 * i ] = r & 0xFF; + priv_key[4 * i + 1] = (r >> 8) & 0xFF; + priv_key[4 * i + 2] = (r >> 16) & 0xFF; + priv_key[4 * i + 3] = (r >> 24) & 0xFF; + } + clock_t t = clock(); for (;;) { - // random message len between 1 and 256 - msg_len = (random32() & 0xFF) + 1; - // create random message - for (i = 0; i < msg_len; i++) { - msg[i] = random32() & 0xFF; - } - // create random privkey - for (i = 0; i < 32; i++) { - priv_key[i] = random32() & 0xFF; - } - // use our ECDSA signer to sign the message with the key ecdsa_sign(priv_key, msg, msg_len, sig, &sig_len); - cnt++; if ((cnt % 100) == 0) printf("Speed: %f sig/s\n", 1.0f * cnt / ((float)(clock() - t) / CLOCKS_PER_SEC)); } From 1830c2066d60a5a583f388e1c1a17041fcaa70bb Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 21 Aug 2013 18:07:02 +0200 Subject: [PATCH 009/627] add more comments to readme --- README | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README b/README index a241d4ac2..bfcd6b5f0 100644 --- a/README +++ b/README @@ -8,6 +8,9 @@ Distibuted under MIT License. Notes ----- -a) random generator in rand.c is using stdlib's rand() function. +a) the signer only understands secp256k1 elliptic curve + +b) random generator in rand.c is using stdlib's rand() function. you should replace this code with one that uses a hardware random - generator of your microcontroller. + generator of your microcontroller in production. + (see speed-stm32/rand.c for such example) From 7c13e810fc6a5fb4022a12a16789161ffd028364 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 21 Aug 2013 18:20:52 +0200 Subject: [PATCH 010/627] add -Os flag to makefile --- Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 96a2291fa..1e400c8fb 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ -CC = gcc -CFLAGS = -Wall -OBJS = aux.o ecdsa.o secp256k1.o sha256.o rand.o +CC = gcc +CFLAGS = -Wall -Os +OBJS = aux.o ecdsa.o secp256k1.o sha256.o rand.o all: test-speed test-verify From 0f7c3be5dd6b60151e1174c60049a4cd0fdec004 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 21 Aug 2013 20:05:25 +0200 Subject: [PATCH 011/627] expand readme --- Makefile | 2 +- README | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 1e400c8fb..a232f6126 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ all: test-speed test-verify $(CC) $(CFLAGS) -o $@ -c $< test-speed: test-speed.o $(OBJS) - gcc test-speed.o $(OBJS) -o test-speed -lcrypto + gcc test-speed.o $(OBJS) -o test-speed test-verify: test-verify.o $(OBJS) gcc test-verify.o $(OBJS) -o test-verify -lcrypto diff --git a/README b/README index bfcd6b5f0..6aa6031b5 100644 --- a/README +++ b/README @@ -14,3 +14,13 @@ b) random generator in rand.c is using stdlib's rand() function. you should replace this code with one that uses a hardware random generator of your microcontroller in production. (see speed-stm32/rand.c for such example) + +c) there are executables: + * test-speed + - check signing speed (sign 100x and compute speed from duration) + * test-verify + - generate random messages and private keys + - check signature validity against OpenSSL (call verify method) + +d) directory speed-stm32 contains project for deploying the code + on STM32 microcontroller and checking signing speed there From 4593b3f63655878cbdc91bd43f9e49b814fdfdcf Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 21 Aug 2013 20:23:43 +0200 Subject: [PATCH 012/627] use /dev/urandom in example --- README | 9 ++------- rand.c | 12 +++++++----- rand.h | 2 ++ 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/README b/README index 6aa6031b5..2b17df76a 100644 --- a/README +++ b/README @@ -10,17 +10,12 @@ Notes a) the signer only understands secp256k1 elliptic curve -b) random generator in rand.c is using stdlib's rand() function. - you should replace this code with one that uses a hardware random - generator of your microcontroller in production. - (see speed-stm32/rand.c for such example) - -c) there are executables: +b) there are executables: * test-speed - check signing speed (sign 100x and compute speed from duration) * test-verify - generate random messages and private keys - check signature validity against OpenSSL (call verify method) -d) directory speed-stm32 contains project for deploying the code +c) directory speed-stm32 contains project for deploying the code on STM32 microcontroller and checking signing speed there diff --git a/rand.c b/rand.c index 24b990a27..fe6d724ad 100644 --- a/rand.c +++ b/rand.c @@ -21,16 +21,18 @@ * OTHER DEALINGS IN THE SOFTWARE. */ -#include -#include -#include +#include #include "rand.h" +static FILE *f; + void init_rand(void) { - srand(time(NULL)); + f = fopen("/dev/urandom", "r"); } uint32_t random32(void) { - return (rand() & 0xFF) + ((rand() & 0xFF) << 8) + ((rand() & 0xFF) << 16) + ((rand() & 0xFF) << 24); + uint32_t r; + fread(&r, 1, sizeof(r), f); + return r; } diff --git a/rand.h b/rand.h index 2ee45ed63..2b72bde5e 100644 --- a/rand.h +++ b/rand.h @@ -24,6 +24,8 @@ #ifndef __RAND_H__ #define __RAND_H__ +#include + void init_rand(void); uint32_t random32(void); From c87691205bc5bfb336f42641552b4deaa9f1732a Mon Sep 17 00:00:00 2001 From: mog Date: Thu, 5 Sep 2013 03:57:26 -0500 Subject: [PATCH 013/627] added support for getting public key from a private key. --- ecdsa.c | 20 ++++++++++++++++++++ ecdsa.h | 1 + 2 files changed, 21 insertions(+) diff --git a/ecdsa.c b/ecdsa.c index 50a6ce48b..f07c6bede 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -513,3 +513,23 @@ void ecdsa_sign(uint8_t *priv_key, uint8_t *msg, uint32_t msg_len, uint8_t *sig, sig[1] = i; *sig_len = i + 2; } + +void ecdsa_pubkey(uint8_t *priv_key, uint8_t *public_key_x, uint8_t *public_key_y) +{ + uint32_t i; + uint64_t temp; + curve_point G; + bignum256 da; + temp = 0; + + for (i = 0; i < 8; i++) { + temp += (((uint64_t)read_be(priv_key + (7 - i) * 4)) << (2 * i)); + da.val[i] = temp & 0x3FFFFFFF; + temp >>= 30; + } + da.val[8] = temp; + scalar_multiply(&da, &G); + write_der(&G.x, public_key_x); + write_der(&G.y, public_key_y); +} + diff --git a/ecdsa.h b/ecdsa.h index d7d1f6173..ea585e1a4 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -28,5 +28,6 @@ // uses secp256k1 curve void ecdsa_sign(uint8_t *priv_key, uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint32_t *sig_len); +void ecdsa_pubkey(uint8_t *priv_key, uint8_t *public_key_x, uint8_t *public_key_y); #endif From 3f737896a45ea33c3061b3cf895383af9ed600bc Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 9 Sep 2013 17:52:25 +0200 Subject: [PATCH 014/627] ecdsa_get_public_key and ecdsa_verify methods --- ecdsa.c | 204 ++++++++++++++++++++++++++++++++++++++++++-------- ecdsa.h | 3 +- secp256k1.h | 3 + test-verify.c | 15 +++- 4 files changed, 190 insertions(+), 35 deletions(-) diff --git a/ecdsa.c b/ecdsa.c index f07c6bede..89d0a9a7f 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -31,6 +31,8 @@ #include "secp256k1.h" #include "aux.h" +#define INVERSE_FAST 1 + // assumes x < 2*prime void mod(bignum256 *x, bignum256 const *prime) { @@ -123,7 +125,40 @@ void fast_mod(bignum256 *x, bignum256 const *prime) } } -// in field G_prime +#ifndef INVERSE_FAST + +#ifdef USE_PRECOMPUTED_IV +#warning USE_PRECOMPUTED_IV will not be used, please undef +#endif +// in field G_prime, small but slow +void inverse(bignum256 *x, bignum256 const *prime) +{ + uint32_t i, j, limb; + bignum256 res; + res.val[0] = 1; + for (i = 1; i < 9;i++) { + res.val[i] = 0; + } + for (i = 0; i < 9;i++) { + limb = prime->val[i]; + // this is not enough in general but fine for secp256k1 because prime->val[0] > 1 + if (i == 0) limb -= 2; + for (j = 0;j < 30; j++) { + if (i == 8 && limb == 0) break; + if (limb & 1) { + multiply(x, &res, prime); + } + limb >>= 1; + multiply(x, x, prime); + } + } + mod(&res, prime); + memcpy(x, &res, sizeof(bignum256)); +} + +#else + +// in field G_prime, big but fast void inverse(bignum256 *x, bignum256 const *prime) { int i, j, k, len1, len2, mask; @@ -294,6 +329,7 @@ void inverse(bignum256 *x, bignum256 const *prime) } } } +#endif // res = a - b // b < 2*prime; result not normalized @@ -337,7 +373,6 @@ void point_add(const curve_point *cp1, curve_point *cp2) memcpy(&(cp2->y), &yr, sizeof(bignum256)); } -#ifndef USE_PRECOMPUTED_CP // cp = cp + cp void point_double(curve_point *cp) { @@ -368,7 +403,6 @@ void point_double(curve_point *cp) memcpy(&(cp->x), &xr, sizeof(bignum256)); memcpy(&(cp->y), &yr, sizeof(bignum256)); } -#endif // res = k * G void scalar_multiply(bignum256 *k, curve_point *res) @@ -437,6 +471,19 @@ void write_der(const bignum256 *x, uint8_t *buf) buf[1] = len; } +void read_32byte_big_endian(uint8_t *in_number, bignum256 *out_number) +{ + uint32_t i; + uint64_t temp; + temp = 0; + for (i = 0; i < 8; i++) { + temp += (((uint64_t)read_be(in_number + (7 - i) * 4)) << (2 * i)); + out_number->val[i]= temp & 0x3FFFFFFF; + temp >>= 30; + } + out_number->val[8] = temp; +} + // uses secp256k1 curve // priv_key is a 32 byte big endian stored number // msg is a data to be signed @@ -446,7 +493,6 @@ void write_der(const bignum256 *x, uint8_t *buf) void ecdsa_sign(uint8_t *priv_key, uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint32_t *sig_len) { uint32_t i; - uint64_t temp; uint8_t hash[32]; curve_point R; bignum256 k, z; @@ -456,13 +502,7 @@ void ecdsa_sign(uint8_t *priv_key, uint8_t *msg, uint32_t msg_len, uint8_t *sig, // if double hash is required uncomment the following line: // sha256(hash, 32, hash); - temp = 0; - for (i = 0; i < 8; i++) { - temp += (((uint64_t)read_be(hash + (7 - i) * 4)) << (2 * i)); - z.val[i]= temp & 0x3FFFFFFF; - temp >>= 30; - } - z.val[8] = temp; + read_32byte_big_endian(hash, &z); for (;;) { // generate random number k for (i = 0; i < 8; i++) { @@ -482,13 +522,7 @@ void ecdsa_sign(uint8_t *priv_key, uint8_t *msg, uint32_t msg_len, uint8_t *sig, } if (i == 9) continue; inverse(&k, &order256k1); - temp = 0; - for (i = 0; i < 8; i++) { - temp += (((uint64_t)read_be(priv_key + (7 - i) * 4)) << (2 * i)); - da->val[i] = temp & 0x3FFFFFFF; - temp >>= 30; - } - da->val[8] = temp; + read_32byte_big_endian(priv_key, da); multiply(&R.x, da, &order256k1); for (i = 0; i < 8; i++) { da->val[i] += z.val[i]; @@ -514,22 +548,130 @@ void ecdsa_sign(uint8_t *priv_key, uint8_t *msg, uint32_t msg_len, uint8_t *sig, *sig_len = i + 2; } -void ecdsa_pubkey(uint8_t *priv_key, uint8_t *public_key_x, uint8_t *public_key_y) +// uses secp256k1 curve +// priv_key is a 32 byte big endian stored number +// pub_key is at least 70 bytes long array for the public key +void ecdsa_get_public_key(uint8_t *priv_key, uint8_t *pub_key, uint32_t *pub_key_len) { uint32_t i; - uint64_t temp; - curve_point G; - bignum256 da; - temp = 0; + curve_point R; + bignum256 k; - for (i = 0; i < 8; i++) { - temp += (((uint64_t)read_be(priv_key + (7 - i) * 4)) << (2 * i)); - da.val[i] = temp & 0x3FFFFFFF; - temp >>= 30; + read_32byte_big_endian(priv_key, &k); + // compute k*G + scalar_multiply(&k, &R); + write_der(&R.x, pub_key + 2); + i = pub_key[3] + 2; + write_der(&R.y, pub_key + 2 + i); + i += pub_key[3+i] + 2; + pub_key[0] = 0x30; + pub_key[1] = i; + *pub_key_len = i + 2; +} + +// does not validate that this is valid der encoding +// assumes it is der encoding containing 1 number +void read_der_single(uint8_t *der, bignum256 *elem) +{ + int i, j; + uint8_t val[32]; + i = 1 + der[1]; + j = 31; + // we ignore all bytes after 32nd. if there are any, those are either zero or invalid for secp256k1 + while (i > 1 && j >= 0) { + val[j] = der[i]; + i--; j--; } - da.val[8] = temp; - scalar_multiply(&da, &G); - write_der(&G.x, public_key_x); - write_der(&G.y, public_key_y); + for (i = 0;i <= j; i++) { + val[i] = 0; + } + read_32byte_big_endian(val, elem); } +// does not validate that this is valid der encoding +// assumes it is der encoding containing 2 numbers (either public key or ecdsa signature) +void read_der_pair(uint8_t *der, bignum256 *elem1, bignum256 *elem2) +{ + read_der_single(der + 2, elem1); + read_der_single(der + 4 + der[3], elem2); +} + +int is_zero(const bignum256 *a) +{ + int i; + for (i = 0;i < 9; i++) { + if (a->val[i] != 0) return 0; + } + return 1; +} + +int bignum256_less(const bignum256 *a, const bignum256 *b) +{ + int i; + for (i = 8;i >= 0; i--) { + if (a->val[i] < b->val[i]) return 1; + if (a->val[i] > b->val[i]) return 0; + } + return 0; +} + +// uses secp256k1 curve +// pub_key and signature are DER encoded +// msg is a data that was signed +// msg_len is the message length +// returns 0 if verification succeeded +// it is assumed that public key is valid otherwise calling this does not make much sense +int ecdsa_verify(uint8_t *pub_key, uint8_t *signature, uint8_t *msg, uint32_t msg_len) +{ + int i, j; + uint8_t hash[32]; + curve_point pub,res; + bignum256 r, s, z; + int res_is_zero = 0; + // compute hash function of message + sha256(msg, msg_len, hash); + // if double hash is required uncomment the following line: + // sha256(hash, 32, hash); + + read_32byte_big_endian(hash, &z); + read_der_pair(pub_key, &pub.x, &pub.y); + read_der_pair(signature, &r, &s); + + if (is_zero(&r) || + is_zero(&s) || + (!bignum256_less(&r,&order256k1)) || + (!bignum256_less(&s,&order256k1))) return 1; + + inverse(&s, &order256k1); // s^-1 + multiply(&s, &z, &order256k1); // z*s^-1 + mod(&z, &order256k1); + multiply(&r, &s, &order256k1); // r*s^-1 + mod(&s, &order256k1); + if (is_zero(&z)) { + // our message hashes to zero + // I don't expect this to happen any time soon + res_is_zero = 1; + } else { + scalar_multiply(&z, &res); + } + + // TODO both pub and res can be infinity, can have y = 0 OR can be equal + for (i = 0; i < 9; i++) { + for (j = 0; j < 30; j++) { + if (i == 8 && (s.val[i] >> j) == 0) break; + if (s.val[i] & (1u << j)) { + point_add(&pub, &res); + } + point_double(&pub); + } + } + + mod(&(res.x), &prime256k1); + mod(&(res.x), &order256k1); + for (i = 0;i < 9; i++) { + if (res.x.val[i] != r.val[i]) { + return 1; + } + } + return 0; +} diff --git a/ecdsa.h b/ecdsa.h index ea585e1a4..78edd4435 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -28,6 +28,7 @@ // uses secp256k1 curve void ecdsa_sign(uint8_t *priv_key, uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint32_t *sig_len); -void ecdsa_pubkey(uint8_t *priv_key, uint8_t *public_key_x, uint8_t *public_key_y); +void ecdsa_get_public_key(uint8_t *priv_key, uint8_t *pub_key, uint32_t *pub_key_len); +int ecdsa_verify(uint8_t *pub_key, uint8_t *signature, uint8_t *msg, uint32_t msg_len); #endif diff --git a/secp256k1.h b/secp256k1.h index 0e22f6c70..805e4e658 100644 --- a/secp256k1.h +++ b/secp256k1.h @@ -26,7 +26,10 @@ #include +// use precomputed Inverse Values of powers of two #define USE_PRECOMPUTED_IV 1 + +// use precomputed Curve Points (some scalar multiples of curve base point G) #define USE_PRECOMPUTED_CP 1 // bignum256 are 256 bits stored as 8*30 bit + 1*16 bit diff --git a/test-verify.c b/test-verify.c index a5f92c88f..4bb4e52e3 100644 --- a/test-verify.c +++ b/test-verify.c @@ -32,8 +32,8 @@ int main() { - uint8_t sig[70], priv_key[32], msg[256], buffer[1000], hash[32], *p; - uint32_t sig_len, i, j, msg_len; + uint8_t sig[70], pub_key[70], priv_key[32], msg[256], buffer[1000], hash[32], *p; + uint32_t sig_len, pub_key_len, i, j, msg_len; SHA256_CTX sha256; EC_GROUP *ecgroup; int cnt = 0; @@ -77,6 +77,15 @@ int main() // use our ECDSA signer to sign the message with the key ecdsa_sign(priv_key, msg, msg_len, sig, &sig_len); + // generate public key from private key + ecdsa_get_public_key(priv_key, pub_key, &pub_key_len); + + // use our ECDSA verifier to verify the message signature + if (ecdsa_verify(pub_key, sig, msg, msg_len) != 0) { + printf("MicroECDSA verification failed\n"); + break; + } + // copy signature to the OpenSSL struct p = sig; ECDSA_SIG *signature = d2i_ECDSA_SIG(NULL, (const uint8_t **)&p, sig_len); @@ -88,7 +97,7 @@ int main() // verify all went well, i.e. we can decrypt our signature with OpenSSL if (ECDSA_do_verify(hash, 32, signature, eckey) != 1) { - printf("Verification failed\n"); + printf("OpenSSL verification failed\n"); break; } ECDSA_SIG_free(signature); From df79a330e6bf4175af9d18ec2d9595518e8f49e9 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 10 Sep 2013 01:03:24 +0200 Subject: [PATCH 015/627] pave the way for RFC6979 --- ecdsa.c | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/ecdsa.c b/ecdsa.c index 89d0a9a7f..9e8bfae14 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -484,6 +484,27 @@ void read_32byte_big_endian(uint8_t *in_number, bignum256 *out_number) out_number->val[8] = temp; } +// generate random K for signing +void generate_k_random(bignum256 *k) { + int i; + for (;;) { + for (i = 0; i < 8; i++) { + k->val[i] = random32() & 0x3FFFFFFF; + } + k->val[8] = random32() & 0xFFFF; + // if k is too big or too small, we don't like it + if (k->val[5] == 0x3FFFFFFF && k->val[6] == 0x3FFFFFFF && k->val[7] == 0x3FFFFFFF && k->val[8] == 0xFFFF) continue; + if (k->val[5] == 0x0 && k->val[6] == 0x0 && k->val[7] == 0x0 && k->val[8] == 0x0) continue; + return; + } +} + +// generate K in a deterministic way, according to RFC6979 +// http://tools.ietf.org/html/rfc6979 +void generate_k_rfc6979(bignum256 *k, uint8_t *priv_key, uint8_t *hash) { + // TODO +} + // uses secp256k1 curve // priv_key is a 32 byte big endian stored number // msg is a data to be signed @@ -492,7 +513,7 @@ void read_32byte_big_endian(uint8_t *in_number, bignum256 *out_number) // sig_len is the pointer to a uint that will contain resulting signature length. note that ((*sig_len) == sig[1]+2) void ecdsa_sign(uint8_t *priv_key, uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint32_t *sig_len) { - uint32_t i; + int i; uint8_t hash[32]; curve_point R; bignum256 k, z; @@ -505,13 +526,7 @@ void ecdsa_sign(uint8_t *priv_key, uint8_t *msg, uint32_t msg_len, uint8_t *sig, read_32byte_big_endian(hash, &z); for (;;) { // generate random number k - for (i = 0; i < 8; i++) { - k.val[i] = random32() & 0x3FFFFFFF; - } - k.val[8] = random32() & 0xFFFF; - // if k is too big or too small, we don't like it - if (k.val[5] == 0x3FFFFFFF && k.val[6] == 0x3FFFFFFF && k.val[7] == 0x3FFFFFFF && k.val[8] == 0xFFFF) continue; - if (k.val[5] == 0x0 && k.val[6] == 0x0 && k.val[7] == 0x0 && k.val[8] == 0x0) continue; + generate_k_random(&k); // compute k*G scalar_multiply(&k, &R); // r = (rx mod n) From d958d8a90ee98b54c0ab808b3ad6594c3587dc72 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 10 Sep 2013 01:41:10 +0200 Subject: [PATCH 016/627] cleanup --- aux.c | 2 +- ecdsa.c | 56 ++++++++++++++++++++++++++++---------------------------- sha256.c | 6 +++--- 3 files changed, 32 insertions(+), 32 deletions(-) diff --git a/aux.c b/aux.c index 61f6285c7..71d28b809 100644 --- a/aux.c +++ b/aux.c @@ -40,6 +40,6 @@ inline void write_be(uint8_t *data, uint32_t x) { data[0] = x >> 24; data[1] = x >> 16; - data[2] = x >>8; + data[2] = x >> 8; data[3] = x; } diff --git a/ecdsa.c b/ecdsa.c index 9e8bfae14..5e876b1ae 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -39,7 +39,7 @@ void mod(bignum256 *x, bignum256 const *prime) int i = 8; uint32_t temp; // compare numbers - while (i >= 0 && prime->val[i] == x->val[i]) --i; + while (i >= 0 && prime->val[i] == x->val[i]) i--; // if equal if (i == -1) { // set x to zero @@ -73,7 +73,7 @@ void multiply(const bignum256 *k, bignum256 *x, bignum256 const *prime) for (i = 0; i < 9; i++) { for (j = 0; j <= i; j++) { - temp += k->val[j] * (uint64_t)x->val[i-j]; + temp += k->val[j] * (uint64_t)x->val[i - j]; } res[i] = temp & 0x3FFFFFFFu; temp >>= 30; @@ -82,7 +82,7 @@ void multiply(const bignum256 *k, bignum256 *x, bignum256 const *prime) for (; i < 17; i++) { for (j = i - 8; j < 9 ; j++) { - temp += k->val[j] * (uint64_t)x->val[i-j]; + temp += k->val[j] * (uint64_t)x->val[i - j]; } res[i] = temp & 0x3FFFFFFFu; temp >>= 30; @@ -91,13 +91,13 @@ void multiply(const bignum256 *k, bignum256 *x, bignum256 const *prime) // compute modulo p division is only estimated so this may give result greater than prime but not bigger than 2 * prime for (i = 16; i >= 8; i--) { // estimate (res / prime) - coef = (res[i] >> 16) + (res[i+1] << 14); + coef = (res[i] >> 16) + (res[i + 1] << 14); // substract (coef * prime) from res - temp = 0x1000000000000000llu + res[i-8] - prime->val[0] * (uint64_t)coef; - res[i-8] = temp & 0x3FFFFFFF; + temp = 0x1000000000000000llu + res[i - 8] - prime->val[0] * (uint64_t)coef; + res[i - 8] = temp & 0x3FFFFFFF; for (j = 1; j < 9; j++) { temp >>= 30; - temp += 0xFFFFFFFC0000000llu + res[i-8+j] - prime->val[j] * (uint64_t)coef; + temp += 0xFFFFFFFC0000000llu + res[i - 8 + j] - prime->val[j] * (uint64_t)coef; res[i - 8 + j] = temp & 0x3FFFFFFF; } } @@ -136,14 +136,14 @@ void inverse(bignum256 *x, bignum256 const *prime) uint32_t i, j, limb; bignum256 res; res.val[0] = 1; - for (i = 1; i < 9;i++) { + for (i = 1; i < 9; i++) { res.val[i] = 0; } - for (i = 0; i < 9;i++) { + for (i = 0; i < 9; i++) { limb = prime->val[i]; // this is not enough in general but fine for secp256k1 because prime->val[0] > 1 if (i == 0) limb -= 2; - for (j = 0;j < 30; j++) { + for (j = 0; j < 30; j++) { if (i == 8 && limb == 0) break; if (limb & 1) { multiply(x, &res, prime); @@ -225,14 +225,14 @@ void inverse(bignum256 *x, bignum256 const *prime) } i = len1 - 1; - while (i>0 && u[i] == v[i]) i--; + while (i > 0 && u[i] == v[i]) i--; if (u[i] > v[i]) { temp = 0x40000000u + u[0] - v[0]; u[0] = (temp >> 1) & 0x1FFFFFFF; temp >>= 30; for (i = 1; i < len1; i++) { temp += 0x3FFFFFFFu + u[i] - v[i]; - u[i-1] += (temp & 1) << 29; + u[i - 1] += (temp & 1) << 29; u[i] = (temp >> 1) & 0x1FFFFFFF; temp >>= 30; } @@ -256,7 +256,7 @@ void inverse(bignum256 *x, bignum256 const *prime) temp >>= 30; for (i = 1; i < len1; i++) { temp += 0x3FFFFFFFu + v[i] - u[i]; - v[i-1] += (temp & 1) << 29; + v[i - 1] += (temp & 1) << 29; v[i] = (temp >> 1) & 0x1FFFFFFF; temp >>= 30; } @@ -279,7 +279,7 @@ void inverse(bignum256 *x, bignum256 const *prime) k++; } i = 8; - while (i>0 && r[i] == prime->val[i]) i--; + while (i > 0 && r[i] == prime->val[i]) i--; if (r[i] >= prime->val[i]) { temp = 1; for (i = 0; i < 9; i++) { @@ -313,13 +313,13 @@ void inverse(bignum256 *x, bignum256 const *prime) temp >>= 30; for (i = 1; i < 9; i++) { temp += r[i] + prime->val[i]; - r[i-1] += (temp & 1) << 29; + r[i - 1] += (temp & 1) << 29; r[i] = (temp >> 1) & 0x1FFFFFFF; temp >>= 30; } } else { for (i = 0; i < 8; i++) { - r[i] = (r[i] >> 1) | ((r[i+1] & 1) << 29); + r[i] = (r[i] >> 1) | ((r[i + 1] & 1) << 29); } r[8] = r[8] >> 1; } @@ -420,7 +420,7 @@ void scalar_multiply(bignum256 *k, curve_point *res) for (i = 0; i < 9; i++) { for (j = 0; j < 30; j++) { if (i == 8 && (k->val[i] >> j) == 0) break; - if (k->val[i] & (1u<val[i] & (1u << j)) { if (is_zero) { #ifdef USE_PRECOMPUTED_CP memcpy(res, secp256k1_cp + exp, sizeof(curve_point)); @@ -541,7 +541,7 @@ void ecdsa_sign(uint8_t *priv_key, uint8_t *msg, uint32_t msg_len, uint8_t *sig, multiply(&R.x, da, &order256k1); for (i = 0; i < 8; i++) { da->val[i] += z.val[i]; - da->val[i+1] += (da->val[i] >> 30); + da->val[i + 1] += (da->val[i] >> 30); da->val[i] &= 0x3FFFFFFF; } da->val[8] += z.val[8]; @@ -557,7 +557,7 @@ void ecdsa_sign(uint8_t *priv_key, uint8_t *msg, uint32_t msg_len, uint8_t *sig, write_der(&R.x, sig + 2); i = sig[3] + 2; write_der(&k, sig + 2 + i); - i += sig[3+i] + 2; + i += sig[3 + i] + 2; sig[0] = 0x30; sig[1] = i; *sig_len = i + 2; @@ -578,7 +578,7 @@ void ecdsa_get_public_key(uint8_t *priv_key, uint8_t *pub_key, uint32_t *pub_key write_der(&R.x, pub_key + 2); i = pub_key[3] + 2; write_der(&R.y, pub_key + 2 + i); - i += pub_key[3+i] + 2; + i += pub_key[3 + i] + 2; pub_key[0] = 0x30; pub_key[1] = i; *pub_key_len = i + 2; @@ -597,7 +597,7 @@ void read_der_single(uint8_t *der, bignum256 *elem) val[j] = der[i]; i--; j--; } - for (i = 0;i <= j; i++) { + for (i = 0; i <= j; i++) { val[i] = 0; } read_32byte_big_endian(val, elem); @@ -614,16 +614,16 @@ void read_der_pair(uint8_t *der, bignum256 *elem1, bignum256 *elem2) int is_zero(const bignum256 *a) { int i; - for (i = 0;i < 9; i++) { + for (i = 0; i < 9; i++) { if (a->val[i] != 0) return 0; } return 1; } -int bignum256_less(const bignum256 *a, const bignum256 *b) +int is_less(const bignum256 *a, const bignum256 *b) { int i; - for (i = 8;i >= 0; i--) { + for (i = 8; i >= 0; i--) { if (a->val[i] < b->val[i]) return 1; if (a->val[i] > b->val[i]) return 0; } @@ -640,7 +640,7 @@ int ecdsa_verify(uint8_t *pub_key, uint8_t *signature, uint8_t *msg, uint32_t ms { int i, j; uint8_t hash[32]; - curve_point pub,res; + curve_point pub, res; bignum256 r, s, z; int res_is_zero = 0; // compute hash function of message @@ -654,8 +654,8 @@ int ecdsa_verify(uint8_t *pub_key, uint8_t *signature, uint8_t *msg, uint32_t ms if (is_zero(&r) || is_zero(&s) || - (!bignum256_less(&r,&order256k1)) || - (!bignum256_less(&s,&order256k1))) return 1; + (!is_less(&r, &order256k1)) || + (!is_less(&s, &order256k1))) return 1; inverse(&s, &order256k1); // s^-1 multiply(&s, &z, &order256k1); // z*s^-1 @@ -683,7 +683,7 @@ int ecdsa_verify(uint8_t *pub_key, uint8_t *signature, uint8_t *msg, uint32_t ms mod(&(res.x), &prime256k1); mod(&(res.x), &order256k1); - for (i = 0;i < 9; i++) { + for (i = 0; i < 9; i++) { if (res.x.val[i] != r.val[i]) { return 1; } diff --git a/sha256.c b/sha256.c index ccb9ed4da..29844c8ba 100644 --- a/sha256.c +++ b/sha256.c @@ -43,9 +43,9 @@ void process_chunk(const uint8_t *chunk, uint32_t *hash) w[i] = read_be(chunk + 4 * i); } for (; i < 64; i++) { - s0 = ror(w[i-15], 7) ^ ror(w[i-15], 18) ^ (w[i-15]>>3); - s1 = ror(w[i-2], 17) ^ ror(w[i-2], 19) ^ (w[i-2]>>10); - w[i] = w[i-16] + s0 + w[i-7] + s1; + s0 = ror(w[i - 15], 7) ^ ror(w[i - 15], 18) ^ (w[i - 15] >> 3); + s1 = ror(w[i - 2], 17) ^ ror(w[i - 2], 19) ^ (w[i - 2] >> 10); + w[i] = w[i - 16] + s0 + w[i - 7] + s1; } a = hash[0]; b = hash[1]; From 40fa3f52e41115647baa1f359bc00e93e05213b2 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 10 Sep 2013 20:50:13 +0200 Subject: [PATCH 017/627] use sha2 implementation by Aaron D. Gifford --- Makefile | 2 +- ecdsa.c | 10 +- sha2.c | 935 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ sha2.h | 68 ++++ sha256.c | 127 -------- sha256.h | 31 -- 6 files changed, 1009 insertions(+), 164 deletions(-) create mode 100644 sha2.c create mode 100644 sha2.h delete mode 100644 sha256.c delete mode 100644 sha256.h diff --git a/Makefile b/Makefile index a232f6126..fde282959 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ CC = gcc CFLAGS = -Wall -Os -OBJS = aux.o ecdsa.o secp256k1.o sha256.o rand.o +OBJS = aux.o ecdsa.o secp256k1.o sha2.o rand.o all: test-speed test-verify diff --git a/ecdsa.c b/ecdsa.c index 5e876b1ae..5fd51c14b 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -26,7 +26,7 @@ #include #include "rand.h" -#include "sha256.h" +#include "sha2.h" #include "ecdsa.h" #include "secp256k1.h" #include "aux.h" @@ -519,9 +519,9 @@ void ecdsa_sign(uint8_t *priv_key, uint8_t *msg, uint32_t msg_len, uint8_t *sig, bignum256 k, z; bignum256 *da = &R.y; // compute hash function of message - sha256(msg, msg_len, hash); + SHA256_Raw(msg, msg_len, hash); // if double hash is required uncomment the following line: - // sha256(hash, 32, hash); + // SHA256_Raw(hash, 32, hash); read_32byte_big_endian(hash, &z); for (;;) { @@ -644,9 +644,9 @@ int ecdsa_verify(uint8_t *pub_key, uint8_t *signature, uint8_t *msg, uint32_t ms bignum256 r, s, z; int res_is_zero = 0; // compute hash function of message - sha256(msg, msg_len, hash); + SHA256_Raw(msg, msg_len, hash); // if double hash is required uncomment the following line: - // sha256(hash, 32, hash); + // SHA256_Raw(hash, 32, hash); read_32byte_big_endian(hash, &z); read_der_pair(pub_key, &pub.x, &pub.y); diff --git a/sha2.c b/sha2.c new file mode 100644 index 000000000..4487bf8fa --- /dev/null +++ b/sha2.c @@ -0,0 +1,935 @@ +/** + * Copyright (c) 2000-2001 Aaron D. Gifford + * Copyright (c) 2013 Pavol Rusnak + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTOR(S) BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include "sha2.h" + +/* + * ASSERT NOTE: + * Some sanity checking code is included using assert(). On my FreeBSD + * system, this additional code can be removed by compiling with NDEBUG + * defined. Check your own systems manpage on assert() to see how to + * compile WITHOUT the sanity checking code on your system. + * + * UNROLLED TRANSFORM LOOP NOTE: + * You can define SHA2_UNROLL_TRANSFORM to use the unrolled transform + * loop version for the hash transform rounds (defined using macros + * later in this file). Either define on the command line, for example: + * + * cc -DSHA2_UNROLL_TRANSFORM -o sha2 sha2.c sha2prog.c + * + * or define below: + * + * #define SHA2_UNROLL_TRANSFORM + * + */ + + +/*** SHA-256/384/512 Machine Architecture Definitions *****************/ +/* + * BYTE_ORDER NOTE: + * + * Please make sure that your system defines BYTE_ORDER. If your + * architecture is little-endian, make sure it also defines + * LITTLE_ENDIAN and that the two (BYTE_ORDER and LITTLE_ENDIAN) are + * equivilent. + * + * If your system does not define the above, then you can do so by + * hand like this: + * + * #define LITTLE_ENDIAN 1234 + * #define BIG_ENDIAN 4321 + * + * And for little-endian machines, add: + * + * #define BYTE_ORDER LITTLE_ENDIAN + * + * Or for big-endian machines: + * + * #define BYTE_ORDER BIG_ENDIAN + * + * The FreeBSD machine this was written on defines BYTE_ORDER + * appropriately by including (which in turn includes + * where the appropriate definitions are actually + * made). + */ + +#ifndef BYTE_ORDER +#define BYTE_ORDER LITTLE_ENDIAN +#endif + +#if !defined(BYTE_ORDER) || (BYTE_ORDER != LITTLE_ENDIAN && BYTE_ORDER != BIG_ENDIAN) +#error Define BYTE_ORDER to be equal to either LITTLE_ENDIAN or BIG_ENDIAN +#endif + +typedef uint8_t sha2_byte; /* Exactly 1 byte */ +typedef uint32_t sha2_word32; /* Exactly 4 bytes */ +typedef uint64_t sha2_word64; /* Exactly 8 bytes */ + +/*** SHA-256/384/512 Various Length Definitions ***********************/ +/* NOTE: Most of these are in sha2.h */ +#define SHA256_SHORT_BLOCK_LENGTH (SHA256_BLOCK_LENGTH - 8) +#define SHA512_SHORT_BLOCK_LENGTH (SHA512_BLOCK_LENGTH - 16) + + +/*** ENDIAN REVERSAL MACROS *******************************************/ +#if BYTE_ORDER == LITTLE_ENDIAN +#define REVERSE32(w,x) { \ + sha2_word32 tmp = (w); \ + tmp = (tmp >> 16) | (tmp << 16); \ + (x) = ((tmp & 0xff00ff00UL) >> 8) | ((tmp & 0x00ff00ffUL) << 8); \ +} +#define REVERSE64(w,x) { \ + sha2_word64 tmp = (w); \ + tmp = (tmp >> 32) | (tmp << 32); \ + tmp = ((tmp & 0xff00ff00ff00ff00ULL) >> 8) | \ + ((tmp & 0x00ff00ff00ff00ffULL) << 8); \ + (x) = ((tmp & 0xffff0000ffff0000ULL) >> 16) | \ + ((tmp & 0x0000ffff0000ffffULL) << 16); \ +} +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ + +/* + * Macro for incrementally adding the unsigned 64-bit integer n to the + * unsigned 128-bit integer (represented using a two-element array of + * 64-bit words): + */ +#define ADDINC128(w,n) { \ + (w)[0] += (sha2_word64)(n); \ + if ((w)[0] < (n)) { \ + (w)[1]++; \ + } \ +} + +#define MEMSET_BZERO(p,l) memset((p), 0, (l)) +#define MEMCPY_BCOPY(d,s,l) memcpy((d), (s), (l)) + +/*** THE SIX LOGICAL FUNCTIONS ****************************************/ +/* + * Bit shifting and rotation (used by the six SHA-XYZ logical functions: + * + * NOTE: The naming of R and S appears backwards here (R is a SHIFT and + * S is a ROTATION) because the SHA-256/384/512 description document + * (see http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf) uses this + * same "backwards" definition. + */ +/* Shift-right (used in SHA-256, SHA-384, and SHA-512): */ +#define R(b,x) ((x) >> (b)) +/* 32-bit Rotate-right (used in SHA-256): */ +#define S32(b,x) (((x) >> (b)) | ((x) << (32 - (b)))) +/* 64-bit Rotate-right (used in SHA-384 and SHA-512): */ +#define S64(b,x) (((x) >> (b)) | ((x) << (64 - (b)))) + +/* Two of six logical functions used in SHA-256, SHA-384, and SHA-512: */ +#define Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z))) +#define Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) + +/* Four of six logical functions used in SHA-256: */ +#define Sigma0_256(x) (S32(2, (x)) ^ S32(13, (x)) ^ S32(22, (x))) +#define Sigma1_256(x) (S32(6, (x)) ^ S32(11, (x)) ^ S32(25, (x))) +#define sigma0_256(x) (S32(7, (x)) ^ S32(18, (x)) ^ R(3 , (x))) +#define sigma1_256(x) (S32(17, (x)) ^ S32(19, (x)) ^ R(10, (x))) + +/* Four of six logical functions used in SHA-384 and SHA-512: */ +#define Sigma0_512(x) (S64(28, (x)) ^ S64(34, (x)) ^ S64(39, (x))) +#define Sigma1_512(x) (S64(14, (x)) ^ S64(18, (x)) ^ S64(41, (x))) +#define sigma0_512(x) (S64( 1, (x)) ^ S64( 8, (x)) ^ R( 7, (x))) +#define sigma1_512(x) (S64(19, (x)) ^ S64(61, (x)) ^ R( 6, (x))) + +/*** INTERNAL FUNCTION PROTOTYPES *************************************/ +/* NOTE: These should not be accessed directly from outside this + * library -- they are intended for private internal visibility/use + * only. + */ +void SHA512_Last(SHA512_CTX*); +void SHA256_Transform(SHA256_CTX*, const sha2_word32*); +void SHA512_Transform(SHA512_CTX*, const sha2_word64*); + + +/*** SHA-XYZ INITIAL HASH VALUES AND CONSTANTS ************************/ +/* Hash constant words K for SHA-256: */ +const static sha2_word32 K256[64] = { + 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, + 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, + 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL, + 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL, + 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, + 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, + 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, + 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL, + 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL, + 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, + 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, + 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, + 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL, + 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL, + 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, + 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL +}; + +/* Initial hash value H for SHA-256: */ +const static sha2_word32 sha256_initial_hash_value[8] = { + 0x6a09e667UL, + 0xbb67ae85UL, + 0x3c6ef372UL, + 0xa54ff53aUL, + 0x510e527fUL, + 0x9b05688cUL, + 0x1f83d9abUL, + 0x5be0cd19UL +}; + +/* Hash constant words K for SHA-384 and SHA-512: */ +const static sha2_word64 K512[80] = { + 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, + 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL, + 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, + 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, + 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, + 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, + 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, + 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL, + 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, + 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, + 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, + 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, + 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, + 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL, + 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, + 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, + 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, + 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL, + 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, + 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL, + 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, + 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, + 0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, + 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, + 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, + 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL, + 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, + 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, + 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, + 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, + 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, + 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL, + 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, + 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, + 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, + 0x113f9804bef90daeULL, 0x1b710b35131c471bULL, + 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, + 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL, + 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, + 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL +}; + +/* Initial hash value H for SHA-384 */ +const static sha2_word64 sha384_initial_hash_value[8] = { + 0xcbbb9d5dc1059ed8ULL, + 0x629a292a367cd507ULL, + 0x9159015a3070dd17ULL, + 0x152fecd8f70e5939ULL, + 0x67332667ffc00b31ULL, + 0x8eb44a8768581511ULL, + 0xdb0c2e0d64f98fa7ULL, + 0x47b5481dbefa4fa4ULL +}; + +/* Initial hash value H for SHA-512 */ +const static sha2_word64 sha512_initial_hash_value[8] = { + 0x6a09e667f3bcc908ULL, + 0xbb67ae8584caa73bULL, + 0x3c6ef372fe94f82bULL, + 0xa54ff53a5f1d36f1ULL, + 0x510e527fade682d1ULL, + 0x9b05688c2b3e6c1fULL, + 0x1f83d9abfb41bd6bULL, + 0x5be0cd19137e2179ULL +}; + +/* + * Constant used by SHA256/384/512_End() functions for converting the + * digest to a readable hexadecimal character string: + */ +static const char *sha2_hex_digits = "0123456789abcdef"; + + +/*** SHA-256: *********************************************************/ +void SHA256_Init(SHA256_CTX* context) { + if (context == (SHA256_CTX*)0) { + return; + } + MEMCPY_BCOPY(context->state, sha256_initial_hash_value, SHA256_DIGEST_LENGTH); + MEMSET_BZERO(context->buffer, SHA256_BLOCK_LENGTH); + context->bitcount = 0; +} + +#ifdef SHA2_UNROLL_TRANSFORM + +/* Unrolled SHA-256 round macros: */ + +#if BYTE_ORDER == LITTLE_ENDIAN + +#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \ + REVERSE32(*data++, W256[j]); \ + T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \ + K256[j] + W256[j]; \ + (d) += T1; \ + (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ + j++ + + +#else /* BYTE_ORDER == LITTLE_ENDIAN */ + +#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \ + T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \ + K256[j] + (W256[j] = *data++); \ + (d) += T1; \ + (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ + j++ + +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ + +#define ROUND256(a,b,c,d,e,f,g,h) \ + s0 = W256[(j+1)&0x0f]; \ + s0 = sigma0_256(s0); \ + s1 = W256[(j+14)&0x0f]; \ + s1 = sigma1_256(s1); \ + T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + K256[j] + \ + (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); \ + (d) += T1; \ + (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ + j++ + +void SHA256_Transform(SHA256_CTX* context, const sha2_word32* data) { + sha2_word32 a, b, c, d, e, f, g, h, s0, s1; + sha2_word32 T1, *W256; + int j; + + W256 = (sha2_word32*)context->buffer; + + /* Initialize registers with the prev. intermediate value */ + a = context->state[0]; + b = context->state[1]; + c = context->state[2]; + d = context->state[3]; + e = context->state[4]; + f = context->state[5]; + g = context->state[6]; + h = context->state[7]; + + j = 0; + do { + /* Rounds 0 to 15 (unrolled): */ + ROUND256_0_TO_15(a,b,c,d,e,f,g,h); + ROUND256_0_TO_15(h,a,b,c,d,e,f,g); + ROUND256_0_TO_15(g,h,a,b,c,d,e,f); + ROUND256_0_TO_15(f,g,h,a,b,c,d,e); + ROUND256_0_TO_15(e,f,g,h,a,b,c,d); + ROUND256_0_TO_15(d,e,f,g,h,a,b,c); + ROUND256_0_TO_15(c,d,e,f,g,h,a,b); + ROUND256_0_TO_15(b,c,d,e,f,g,h,a); + } while (j < 16); + + /* Now for the remaining rounds to 64: */ + do { + ROUND256(a,b,c,d,e,f,g,h); + ROUND256(h,a,b,c,d,e,f,g); + ROUND256(g,h,a,b,c,d,e,f); + ROUND256(f,g,h,a,b,c,d,e); + ROUND256(e,f,g,h,a,b,c,d); + ROUND256(d,e,f,g,h,a,b,c); + ROUND256(c,d,e,f,g,h,a,b); + ROUND256(b,c,d,e,f,g,h,a); + } while (j < 64); + + /* Compute the current intermediate hash value */ + context->state[0] += a; + context->state[1] += b; + context->state[2] += c; + context->state[3] += d; + context->state[4] += e; + context->state[5] += f; + context->state[6] += g; + context->state[7] += h; + + /* Clean up */ + a = b = c = d = e = f = g = h = T1 = 0; +} + +#else /* SHA2_UNROLL_TRANSFORM */ + +void SHA256_Transform(SHA256_CTX* context, const sha2_word32* data) { + sha2_word32 a, b, c, d, e, f, g, h, s0, s1; + sha2_word32 T1, T2, *W256; + int j; + + W256 = (sha2_word32*)context->buffer; + + /* Initialize registers with the prev. intermediate value */ + a = context->state[0]; + b = context->state[1]; + c = context->state[2]; + d = context->state[3]; + e = context->state[4]; + f = context->state[5]; + g = context->state[6]; + h = context->state[7]; + + j = 0; + do { +#if BYTE_ORDER == LITTLE_ENDIAN + /* Copy data while converting to host byte order */ + REVERSE32(*data++,W256[j]); + /* Apply the SHA-256 compression function to update a..h */ + T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + W256[j]; +#else /* BYTE_ORDER == LITTLE_ENDIAN */ + /* Apply the SHA-256 compression function to update a..h with copy */ + T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + (W256[j] = *data++); +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ + T2 = Sigma0_256(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + + j++; + } while (j < 16); + + do { + /* Part of the message block expansion: */ + s0 = W256[(j+1)&0x0f]; + s0 = sigma0_256(s0); + s1 = W256[(j+14)&0x0f]; + s1 = sigma1_256(s1); + + /* Apply the SHA-256 compression function to update a..h */ + T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + + (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); + T2 = Sigma0_256(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + + j++; + } while (j < 64); + + /* Compute the current intermediate hash value */ + context->state[0] += a; + context->state[1] += b; + context->state[2] += c; + context->state[3] += d; + context->state[4] += e; + context->state[5] += f; + context->state[6] += g; + context->state[7] += h; + + /* Clean up */ + a = b = c = d = e = f = g = h = T1 = T2 = 0; +} + +#endif /* SHA2_UNROLL_TRANSFORM */ + +void SHA256_Update(SHA256_CTX* context, const sha2_byte *data, size_t len) { + unsigned int freespace, usedspace; + + if (len == 0) { + /* Calling with no data is valid - we do nothing */ + return; + } + + usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH; + if (usedspace > 0) { + /* Calculate how much free space is available in the buffer */ + freespace = SHA256_BLOCK_LENGTH - usedspace; + + if (len >= freespace) { + /* Fill the buffer completely and process it */ + MEMCPY_BCOPY(&context->buffer[usedspace], data, freespace); + context->bitcount += freespace << 3; + len -= freespace; + data += freespace; + SHA256_Transform(context, (sha2_word32*)context->buffer); + } else { + /* The buffer is not yet full */ + MEMCPY_BCOPY(&context->buffer[usedspace], data, len); + context->bitcount += len << 3; + /* Clean up: */ + usedspace = freespace = 0; + return; + } + } + while (len >= SHA256_BLOCK_LENGTH) { + /* Process as many complete blocks as we can */ + SHA256_Transform(context, (sha2_word32*)data); + context->bitcount += SHA256_BLOCK_LENGTH << 3; + len -= SHA256_BLOCK_LENGTH; + data += SHA256_BLOCK_LENGTH; + } + if (len > 0) { + /* There's left-overs, so save 'em */ + MEMCPY_BCOPY(context->buffer, data, len); + context->bitcount += len << 3; + } + /* Clean up: */ + usedspace = freespace = 0; +} + +void SHA256_Final(sha2_byte digest[], SHA256_CTX* context) { + sha2_word32 *d = (sha2_word32*)digest; + unsigned int usedspace; + + /* If no digest buffer is passed, we don't bother doing this: */ + if (digest != (sha2_byte*)0) { + usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH; +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert FROM host byte order */ + REVERSE64(context->bitcount,context->bitcount); +#endif + if (usedspace > 0) { + /* Begin padding with a 1 bit: */ + context->buffer[usedspace++] = 0x80; + + if (usedspace <= SHA256_SHORT_BLOCK_LENGTH) { + /* Set-up for the last transform: */ + MEMSET_BZERO(&context->buffer[usedspace], SHA256_SHORT_BLOCK_LENGTH - usedspace); + } else { + if (usedspace < SHA256_BLOCK_LENGTH) { + MEMSET_BZERO(&context->buffer[usedspace], SHA256_BLOCK_LENGTH - usedspace); + } + /* Do second-to-last transform: */ + SHA256_Transform(context, (sha2_word32*)context->buffer); + + /* And set-up for the last transform: */ + MEMSET_BZERO(context->buffer, SHA256_SHORT_BLOCK_LENGTH); + } + } else { + /* Set-up for the last transform: */ + MEMSET_BZERO(context->buffer, SHA256_SHORT_BLOCK_LENGTH); + + /* Begin padding with a 1 bit: */ + *context->buffer = 0x80; + } + /* Set the bit count: */ + *(sha2_word64*)&context->buffer[SHA256_SHORT_BLOCK_LENGTH] = context->bitcount; + + /* Final transform: */ + SHA256_Transform(context, (sha2_word32*)context->buffer); + +#if BYTE_ORDER == LITTLE_ENDIAN + { + /* Convert TO host byte order */ + int j; + for (j = 0; j < 8; j++) { + REVERSE32(context->state[j],context->state[j]); + *d++ = context->state[j]; + } + } +#else + MEMCPY_BCOPY(d, context->state, SHA256_DIGEST_LENGTH); +#endif + } + + /* Clean up state data: */ + MEMSET_BZERO(context, sizeof(SHA256_CTX)); + usedspace = 0; +} + +char *SHA256_End(SHA256_CTX* context, char buffer[]) { + sha2_byte digest[SHA256_DIGEST_LENGTH], *d = digest; + int i; + + if (buffer != (char*)0) { + SHA256_Final(digest, context); + + for (i = 0; i < SHA256_DIGEST_LENGTH; i++) { + *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; + *buffer++ = sha2_hex_digits[*d & 0x0f]; + d++; + } + *buffer = (char)0; + } else { + MEMSET_BZERO(context, sizeof(SHA256_CTX)); + } + MEMSET_BZERO(digest, SHA256_DIGEST_LENGTH); + return buffer; +} + +void SHA256_Raw(const sha2_byte* data, size_t len, uint8_t digest[SHA256_DIGEST_LENGTH]) { + SHA256_CTX context; + SHA256_Init(&context); + SHA256_Update(&context, data, len); + SHA256_Final(digest, &context); +} + +char* SHA256_Data(const sha2_byte* data, size_t len, char digest[SHA256_DIGEST_STRING_LENGTH]) { + SHA256_CTX context; + + SHA256_Init(&context); + SHA256_Update(&context, data, len); + return SHA256_End(&context, digest); +} + + +/*** SHA-512: *********************************************************/ +void SHA512_Init(SHA512_CTX* context) { + if (context == (SHA512_CTX*)0) { + return; + } + MEMCPY_BCOPY(context->state, sha512_initial_hash_value, SHA512_DIGEST_LENGTH); + MEMSET_BZERO(context->buffer, SHA512_BLOCK_LENGTH); + context->bitcount[0] = context->bitcount[1] = 0; +} + +#ifdef SHA2_UNROLL_TRANSFORM + +/* Unrolled SHA-512 round macros: */ +#if BYTE_ORDER == LITTLE_ENDIAN + +#define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) \ + REVERSE64(*data++, W512[j]); \ + T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \ + K512[j] + W512[j]; \ + (d) += T1, \ + (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)), \ + j++ + + +#else /* BYTE_ORDER == LITTLE_ENDIAN */ + +#define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) \ + T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \ + K512[j] + (W512[j] = *data++); \ + (d) += T1; \ + (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \ + j++ + +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ + +#define ROUND512(a,b,c,d,e,f,g,h) \ + s0 = W512[(j+1)&0x0f]; \ + s0 = sigma0_512(s0); \ + s1 = W512[(j+14)&0x0f]; \ + s1 = sigma1_512(s1); \ + T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + K512[j] + \ + (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); \ + (d) += T1; \ + (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \ + j++ + +void SHA512_Transform(SHA512_CTX* context, const sha2_word64* data) { + sha2_word64 a, b, c, d, e, f, g, h, s0, s1; + sha2_word64 T1, *W512 = (sha2_word64*)context->buffer; + int j; + + /* Initialize registers with the prev. intermediate value */ + a = context->state[0]; + b = context->state[1]; + c = context->state[2]; + d = context->state[3]; + e = context->state[4]; + f = context->state[5]; + g = context->state[6]; + h = context->state[7]; + + j = 0; + do { + ROUND512_0_TO_15(a,b,c,d,e,f,g,h); + ROUND512_0_TO_15(h,a,b,c,d,e,f,g); + ROUND512_0_TO_15(g,h,a,b,c,d,e,f); + ROUND512_0_TO_15(f,g,h,a,b,c,d,e); + ROUND512_0_TO_15(e,f,g,h,a,b,c,d); + ROUND512_0_TO_15(d,e,f,g,h,a,b,c); + ROUND512_0_TO_15(c,d,e,f,g,h,a,b); + ROUND512_0_TO_15(b,c,d,e,f,g,h,a); + } while (j < 16); + + /* Now for the remaining rounds up to 79: */ + do { + ROUND512(a,b,c,d,e,f,g,h); + ROUND512(h,a,b,c,d,e,f,g); + ROUND512(g,h,a,b,c,d,e,f); + ROUND512(f,g,h,a,b,c,d,e); + ROUND512(e,f,g,h,a,b,c,d); + ROUND512(d,e,f,g,h,a,b,c); + ROUND512(c,d,e,f,g,h,a,b); + ROUND512(b,c,d,e,f,g,h,a); + } while (j < 80); + + /* Compute the current intermediate hash value */ + context->state[0] += a; + context->state[1] += b; + context->state[2] += c; + context->state[3] += d; + context->state[4] += e; + context->state[5] += f; + context->state[6] += g; + context->state[7] += h; + + /* Clean up */ + a = b = c = d = e = f = g = h = T1 = 0; +} + +#else /* SHA2_UNROLL_TRANSFORM */ + +void SHA512_Transform(SHA512_CTX* context, const sha2_word64* data) { + sha2_word64 a, b, c, d, e, f, g, h, s0, s1; + sha2_word64 T1, T2, *W512 = (sha2_word64*)context->buffer; + int j; + + /* Initialize registers with the prev. intermediate value */ + a = context->state[0]; + b = context->state[1]; + c = context->state[2]; + d = context->state[3]; + e = context->state[4]; + f = context->state[5]; + g = context->state[6]; + h = context->state[7]; + + j = 0; + do { +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert TO host byte order */ + REVERSE64(*data++, W512[j]); + /* Apply the SHA-512 compression function to update a..h */ + T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + W512[j]; +#else /* BYTE_ORDER == LITTLE_ENDIAN */ + /* Apply the SHA-512 compression function to update a..h with copy */ + T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + (W512[j] = *data++); +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ + T2 = Sigma0_512(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + + j++; + } while (j < 16); + + do { + /* Part of the message block expansion: */ + s0 = W512[(j+1)&0x0f]; + s0 = sigma0_512(s0); + s1 = W512[(j+14)&0x0f]; + s1 = sigma1_512(s1); + + /* Apply the SHA-512 compression function to update a..h */ + T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + + (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); + T2 = Sigma0_512(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + + j++; + } while (j < 80); + + /* Compute the current intermediate hash value */ + context->state[0] += a; + context->state[1] += b; + context->state[2] += c; + context->state[3] += d; + context->state[4] += e; + context->state[5] += f; + context->state[6] += g; + context->state[7] += h; + + /* Clean up */ + a = b = c = d = e = f = g = h = T1 = T2 = 0; +} + +#endif /* SHA2_UNROLL_TRANSFORM */ + +void SHA512_Update(SHA512_CTX* context, const sha2_byte *data, size_t len) { + unsigned int freespace, usedspace; + + if (len == 0) { + /* Calling with no data is valid - we do nothing */ + return; + } + + usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH; + if (usedspace > 0) { + /* Calculate how much free space is available in the buffer */ + freespace = SHA512_BLOCK_LENGTH - usedspace; + + if (len >= freespace) { + /* Fill the buffer completely and process it */ + MEMCPY_BCOPY(&context->buffer[usedspace], data, freespace); + ADDINC128(context->bitcount, freespace << 3); + len -= freespace; + data += freespace; + SHA512_Transform(context, (sha2_word64*)context->buffer); + } else { + /* The buffer is not yet full */ + MEMCPY_BCOPY(&context->buffer[usedspace], data, len); + ADDINC128(context->bitcount, len << 3); + /* Clean up: */ + usedspace = freespace = 0; + return; + } + } + while (len >= SHA512_BLOCK_LENGTH) { + /* Process as many complete blocks as we can */ + SHA512_Transform(context, (sha2_word64*)data); + ADDINC128(context->bitcount, SHA512_BLOCK_LENGTH << 3); + len -= SHA512_BLOCK_LENGTH; + data += SHA512_BLOCK_LENGTH; + } + if (len > 0) { + /* There's left-overs, so save 'em */ + MEMCPY_BCOPY(context->buffer, data, len); + ADDINC128(context->bitcount, len << 3); + } + /* Clean up: */ + usedspace = freespace = 0; +} + +void SHA512_Last(SHA512_CTX* context) { + unsigned int usedspace; + + usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH; +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert FROM host byte order */ + REVERSE64(context->bitcount[0],context->bitcount[0]); + REVERSE64(context->bitcount[1],context->bitcount[1]); +#endif + if (usedspace > 0) { + /* Begin padding with a 1 bit: */ + context->buffer[usedspace++] = 0x80; + + if (usedspace <= SHA512_SHORT_BLOCK_LENGTH) { + /* Set-up for the last transform: */ + MEMSET_BZERO(&context->buffer[usedspace], SHA512_SHORT_BLOCK_LENGTH - usedspace); + } else { + if (usedspace < SHA512_BLOCK_LENGTH) { + MEMSET_BZERO(&context->buffer[usedspace], SHA512_BLOCK_LENGTH - usedspace); + } + /* Do second-to-last transform: */ + SHA512_Transform(context, (sha2_word64*)context->buffer); + + /* And set-up for the last transform: */ + MEMSET_BZERO(context->buffer, SHA512_BLOCK_LENGTH - 2); + } + } else { + /* Prepare for final transform: */ + MEMSET_BZERO(context->buffer, SHA512_SHORT_BLOCK_LENGTH); + + /* Begin padding with a 1 bit: */ + *context->buffer = 0x80; + } + /* Store the length of input data (in bits): */ + *(sha2_word64*)&context->buffer[SHA512_SHORT_BLOCK_LENGTH] = context->bitcount[1]; + *(sha2_word64*)&context->buffer[SHA512_SHORT_BLOCK_LENGTH+8] = context->bitcount[0]; + + /* Final transform: */ + SHA512_Transform(context, (sha2_word64*)context->buffer); +} + +void SHA512_Final(sha2_byte digest[], SHA512_CTX* context) { + sha2_word64 *d = (sha2_word64*)digest; + + /* If no digest buffer is passed, we don't bother doing this: */ + if (digest != (sha2_byte*)0) { + SHA512_Last(context); + + /* Save the hash data for output: */ +#if BYTE_ORDER == LITTLE_ENDIAN + { + /* Convert TO host byte order */ + int j; + for (j = 0; j < 8; j++) { + REVERSE64(context->state[j],context->state[j]); + *d++ = context->state[j]; + } + } +#else + MEMCPY_BCOPY(d, context->state, SHA512_DIGEST_LENGTH); +#endif + } + + /* Zero out state data */ + MEMSET_BZERO(context, sizeof(SHA512_CTX)); +} + +char *SHA512_End(SHA512_CTX* context, char buffer[]) { + sha2_byte digest[SHA512_DIGEST_LENGTH], *d = digest; + int i; + + if (buffer != (char*)0) { + SHA512_Final(digest, context); + + for (i = 0; i < SHA512_DIGEST_LENGTH; i++) { + *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; + *buffer++ = sha2_hex_digits[*d & 0x0f]; + d++; + } + *buffer = (char)0; + } else { + MEMSET_BZERO(context, sizeof(SHA512_CTX)); + } + MEMSET_BZERO(digest, SHA512_DIGEST_LENGTH); + return buffer; +} + +void SHA512_Raw(const sha2_byte* data, size_t len, uint8_t digest[SHA512_DIGEST_LENGTH]) { + SHA512_CTX context; + SHA512_Init(&context); + SHA512_Update(&context, data, len); + SHA512_Final(digest, &context); +} + +char* SHA512_Data(const sha2_byte* data, size_t len, char digest[SHA512_DIGEST_STRING_LENGTH]) { + SHA512_CTX context; + + SHA512_Init(&context); + SHA512_Update(&context, data, len); + return SHA512_End(&context, digest); +} diff --git a/sha2.h b/sha2.h new file mode 100644 index 000000000..962e28a0e --- /dev/null +++ b/sha2.h @@ -0,0 +1,68 @@ +/** + * Copyright (c) 2000-2001 Aaron D. Gifford + * Copyright (c) 2013 Pavol Rusnak + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTOR(S) BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef __SHA2_H__ +#define __SHA2_H__ + +#include + +#define SHA256_BLOCK_LENGTH 64 +#define SHA256_DIGEST_LENGTH 32 +#define SHA256_DIGEST_STRING_LENGTH (SHA256_DIGEST_LENGTH * 2 + 1) +#define SHA512_BLOCK_LENGTH 128 +#define SHA512_DIGEST_LENGTH 64 +#define SHA512_DIGEST_STRING_LENGTH (SHA512_DIGEST_LENGTH * 2 + 1) + +typedef struct _SHA256_CTX { + uint32_t state[8]; + uint64_t bitcount; + uint8_t buffer[SHA256_BLOCK_LENGTH]; +} SHA256_CTX; +typedef struct _SHA512_CTX { + uint64_t state[8]; + uint64_t bitcount[2]; + uint8_t buffer[SHA512_BLOCK_LENGTH]; +} SHA512_CTX; + +void SHA256_Init(SHA256_CTX *); +void SHA256_Update(SHA256_CTX*, const uint8_t*, size_t); +void SHA256_Final(uint8_t[SHA256_DIGEST_LENGTH], SHA256_CTX*); +char* SHA256_End(SHA256_CTX*, char[SHA256_DIGEST_STRING_LENGTH]); +void SHA256_Raw(const uint8_t*, size_t, uint8_t[SHA256_DIGEST_LENGTH]); +char* SHA256_Data(const uint8_t*, size_t, char[SHA256_DIGEST_STRING_LENGTH]); + +void SHA512_Init(SHA512_CTX*); +void SHA512_Update(SHA512_CTX*, const uint8_t*, size_t); +void SHA512_Final(uint8_t[SHA512_DIGEST_LENGTH], SHA512_CTX*); +char* SHA512_End(SHA512_CTX*, char[SHA512_DIGEST_STRING_LENGTH]); +void SHA512_Raw(const uint8_t*, size_t, uint8_t[SHA512_DIGEST_LENGTH]); +char* SHA512_Data(const uint8_t*, size_t, char[SHA512_DIGEST_STRING_LENGTH]); + +#endif diff --git a/sha256.c b/sha256.c deleted file mode 100644 index 29844c8ba..000000000 --- a/sha256.c +++ /dev/null @@ -1,127 +0,0 @@ -/** - * Copyright (c) 2013 Tomas Dzetkulic - * Copyright (c) 2013 Pavol Rusnak - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#include -#include "aux.h" - -// process sha256 chunk (of length 64 bytes) -void process_chunk(const uint8_t *chunk, uint32_t *hash) -{ - static const uint32_t k0[64] = { - 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, - 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, - 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, - 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, - 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, - 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, - 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, - 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 - }; - uint32_t i, s0, s1, a, b, c, d, e, f, g, h, ch, temp, maj, w[64]; - - for (i = 0; i < 16; i++) { - w[i] = read_be(chunk + 4 * i); - } - for (; i < 64; i++) { - s0 = ror(w[i - 15], 7) ^ ror(w[i - 15], 18) ^ (w[i - 15] >> 3); - s1 = ror(w[i - 2], 17) ^ ror(w[i - 2], 19) ^ (w[i - 2] >> 10); - w[i] = w[i - 16] + s0 + w[i - 7] + s1; - } - a = hash[0]; - b = hash[1]; - c = hash[2]; - d = hash[3]; - e = hash[4]; - f = hash[5]; - g = hash[6]; - h = hash[7]; - for (i = 0; i < 64; i++) { - s1 = ror(e, 6) ^ ror(e, 11) ^ ror(e, 25); - ch = (e & f) ^ ((~ e) & g); - temp = h + s1 + ch + k0[i] + w[i]; - d = d + temp; - s0 = ror(a, 2) ^ ror(a, 13) ^ ror(a, 22); - maj = (a & (b ^ c)) ^ (b & c); - temp = temp + s0 + maj; - h = g; - g = f; - f = e; - e = d; - d = c; - c = b; - b = a; - a = temp; - } - hash[0] += a; - hash[1] += b; - hash[2] += c; - hash[3] += d; - hash[4] += e; - hash[5] += f; - hash[6] += g; - hash[7] += h; -} - -// compute sha256 of a message with len length in bytes -// hash is a pointer to at least 32byte array -void sha256(const uint8_t *msg, const uint32_t len, uint8_t *hash) -{ - // initial hash vales - static const uint32_t h0[8] = { - 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 - }; - uint32_t l = len, i, h[8]; - uint8_t last_chunks[128]; //for storing last 1 or 2 chunks - for (i = 0; i < 8; i++) { - h[i] = h0[i]; - } - // process complete message chunks - while (l >= 64) { - process_chunk(msg, h); - l -= 64; - msg += 64; - } - // process rest of the message - for (i = 0; i < l; i++) { - last_chunks[i] = msg[i]; - } - // add '1' bit - last_chunks[i++] = 0x80; - // pad message with zeroes - for (; (i & 63) != 56; i++) { - last_chunks[i] = 0; - } - // add message length in bits - l = 8 * len; - write_be(last_chunks + i, 0); - write_be(last_chunks + i + 4, l); - // process remaining 1 or 2 chunks - process_chunk(last_chunks, h); - if (i > 64) { - process_chunk(last_chunks + 64, h); - } - // write the result - for (i = 0; i < 8; i++) { - write_be(hash + 4 * i, h[i]); - } -} diff --git a/sha256.h b/sha256.h deleted file mode 100644 index 5405a6008..000000000 --- a/sha256.h +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Copyright (c) 2013 Tomas Dzetkulic - * Copyright (c) 2013 Pavol Rusnak - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef __SHA256_H_ -#define __SHA256_H_ - -// compute sha256 of a message with len length (in bytes) -// hash is a pointer to at least 32 byte array -void sha256(const uint8_t *msg, const uint32_t len, uint8_t *hash); - -#endif From 047b30cf2f7de0e93a61fc268ea0a4440a16b125 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 10 Sep 2013 21:47:06 +0200 Subject: [PATCH 018/627] add hmac-sha256/512 --- Makefile | 2 +- hmac.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ hmac.h | 9 ++++++++ 3 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 hmac.c create mode 100644 hmac.h diff --git a/Makefile b/Makefile index fde282959..dc8f469b3 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ CC = gcc CFLAGS = -Wall -Os -OBJS = aux.o ecdsa.o secp256k1.o sha2.o rand.o +OBJS = aux.o ecdsa.o secp256k1.o sha2.o rand.o hmac.o all: test-speed test-verify diff --git a/hmac.c b/hmac.c new file mode 100644 index 000000000..3ea37d6e7 --- /dev/null +++ b/hmac.c @@ -0,0 +1,62 @@ +#include + +#include "hmac.h" +#include "sha2.h" + +void hmac_sha256(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, const uint32_t msglen, uint8_t *hmac) +{ + int i; + uint8_t buf[SHA256_BLOCK_LENGTH], o_key_pad[SHA256_BLOCK_LENGTH], i_key_pad[SHA256_BLOCK_LENGTH]; + SHA256_CTX ctx; + + memset(buf, 0, SHA256_BLOCK_LENGTH); + if (keylen > SHA256_BLOCK_LENGTH) { + SHA256_Raw(key, keylen, buf); + } else { + memcpy(buf, key, keylen); + } + + for (i = 0; i < SHA256_BLOCK_LENGTH; i++) { + o_key_pad[i] = buf[i] ^ 0x5c; + i_key_pad[i] = buf[i] ^ 0x36; + } + + SHA256_Init(&ctx); + SHA256_Update(&ctx, i_key_pad, SHA256_BLOCK_LENGTH); + SHA256_Update(&ctx, msg, msglen); + SHA256_Final(buf, &ctx); + + SHA256_Init(&ctx); + SHA256_Update(&ctx, o_key_pad, SHA256_BLOCK_LENGTH); + SHA256_Update(&ctx, buf, SHA256_DIGEST_LENGTH); + SHA256_Final(hmac, &ctx); +} + +void hmac_sha512(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, const uint32_t msglen, uint8_t *hmac) +{ + int i; + uint8_t buf[SHA512_BLOCK_LENGTH], o_key_pad[SHA512_BLOCK_LENGTH], i_key_pad[SHA512_BLOCK_LENGTH]; + SHA512_CTX ctx; + + memset(buf, 0, SHA512_BLOCK_LENGTH); + if (keylen > SHA512_BLOCK_LENGTH) { + SHA512_Raw(key, keylen, buf); + } else { + memcpy(buf, key, keylen); + } + + for (i = 0; i < SHA512_BLOCK_LENGTH; i++) { + o_key_pad[i] = buf[i] ^ 0x5c; + i_key_pad[i] = buf[i] ^ 0x36; + } + + SHA512_Init(&ctx); + SHA512_Update(&ctx, i_key_pad, SHA512_BLOCK_LENGTH); + SHA512_Update(&ctx, msg, msglen); + SHA512_Final(buf, &ctx); + + SHA512_Init(&ctx); + SHA512_Update(&ctx, o_key_pad, SHA512_BLOCK_LENGTH); + SHA512_Update(&ctx, buf, SHA512_DIGEST_LENGTH); + SHA512_Final(hmac, &ctx); +} diff --git a/hmac.h b/hmac.h new file mode 100644 index 000000000..7481a67a6 --- /dev/null +++ b/hmac.h @@ -0,0 +1,9 @@ +#ifndef __HMAC_H__ +#define __HMAC_H__ + +#include + +void hmac_sha256(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, const uint32_t msglen, uint8_t *hmac); +void hmac_sha512(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, const uint32_t msglen, uint8_t *hmac); + +#endif From 603acbd1be2c0cd1247661b5e7abe2303740e503 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 11 Sep 2013 19:02:22 +0200 Subject: [PATCH 019/627] implement RFC 6979 --- .gitignore | 1 + Makefile | 5 ++- README | 2 + aux.h | 6 +-- ecdsa.c | 114 +++++++++++++++++++++++++++++++++++-------------- ecdsa.h | 8 ++-- test-rfc6979.c | 51 ++++++++++++++++++++++ 7 files changed, 148 insertions(+), 39 deletions(-) create mode 100644 test-rfc6979.c diff --git a/.gitignore b/.gitignore index e9c650a56..96e561504 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ *.o +test-rfc6979 test-speed test-verify diff --git a/Makefile b/Makefile index dc8f469b3..a9b90415c 100644 --- a/Makefile +++ b/Makefile @@ -2,11 +2,14 @@ CC = gcc CFLAGS = -Wall -Os OBJS = aux.o ecdsa.o secp256k1.o sha2.o rand.o hmac.o -all: test-speed test-verify +all: test-rfc6979 test-speed test-verify %.o: %.c $(CC) $(CFLAGS) -o $@ -c $< +test-rfc6979: test-rfc6979.o $(OBJS) + gcc test-rfc6979.o $(OBJS) -o test-rfc6979 + test-speed: test-speed.o $(OBJS) gcc test-speed.o $(OBJS) -o test-speed diff --git a/README b/README index 2b17df76a..887c93aa5 100644 --- a/README +++ b/README @@ -11,6 +11,8 @@ Notes a) the signer only understands secp256k1 elliptic curve b) there are executables: + * test-rfc6979 + - check RFC 6979 algorithm for generating deterministic K * test-speed - check signing speed (sign 100x and compute speed from duration) * test-verify diff --git a/aux.h b/aux.h index 059579eb4..c73b7b355 100644 --- a/aux.h +++ b/aux.h @@ -27,12 +27,12 @@ #include // rotate uint32 right -inline uint32_t ror(const uint32_t x, const int n); +uint32_t ror(const uint32_t x, const int n); // read 4 big endian bytes into uint32 -inline uint32_t read_be(const uint8_t *data); +uint32_t read_be(const uint8_t *data); // write 4 big endian bytes -inline void write_be(uint8_t *data, uint32_t x); +void write_be(uint8_t *data, uint32_t x); #endif diff --git a/ecdsa.c b/ecdsa.c index 5fd51c14b..c0371af61 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -27,8 +27,8 @@ #include "rand.h" #include "sha2.h" +#include "hmac.h" #include "ecdsa.h" -#include "secp256k1.h" #include "aux.h" #define INVERSE_FAST 1 @@ -471,11 +471,10 @@ void write_der(const bignum256 *x, uint8_t *buf) buf[1] = len; } -void read_32byte_big_endian(uint8_t *in_number, bignum256 *out_number) +void read_32byte_big_endian(const uint8_t *in_number, bignum256 *out_number) { - uint32_t i; - uint64_t temp; - temp = 0; + int i; + uint64_t temp = 0; for (i = 0; i < 8; i++) { temp += (((uint64_t)read_be(in_number + (7 - i) * 4)) << (2 * i)); out_number->val[i]= temp & 0x3FFFFFFF; @@ -484,6 +483,37 @@ void read_32byte_big_endian(uint8_t *in_number, bignum256 *out_number) out_number->val[8] = temp; } +void write_32byte_big_endian(const bignum256 *in_number, uint8_t *out_number) +{ + int i, shift = 30 + 16 - 32; + uint64_t temp = in_number->val[8]; + for (i = 0; i < 8; i++) { + temp <<= 30; + temp |= in_number->val[7 - i]; + write_be(out_number + i * 4, temp >> shift); + shift -= 2; + } +} + +int is_zero(const bignum256 *a) +{ + int i; + for (i = 0; i < 9; i++) { + if (a->val[i] != 0) return 0; + } + return 1; +} + +int is_less(const bignum256 *a, const bignum256 *b) +{ + int i; + for (i = 8; i >= 0; i--) { + if (a->val[i] < b->val[i]) return 1; + if (a->val[i] > b->val[i]) return 0; + } + return 0; +} + // generate random K for signing void generate_k_random(bignum256 *k) { int i; @@ -501,8 +531,42 @@ void generate_k_random(bignum256 *k) { // generate K in a deterministic way, according to RFC6979 // http://tools.ietf.org/html/rfc6979 -void generate_k_rfc6979(bignum256 *k, uint8_t *priv_key, uint8_t *hash) { - // TODO +void generate_k_rfc6979(bignum256 *secret, const uint8_t *priv_key, const uint8_t *hash) +{ + uint8_t v[32], k[32], bx[2*32], buf[32 + 1 + sizeof(bx)], t[32]; + bignum256 z1; + + memcpy(bx, priv_key, 32); + read_32byte_big_endian(hash, &z1); + mod(&z1, &order256k1); + write_32byte_big_endian(&z1, bx + 32); + + memset(v, 1, sizeof(v)); + memset(k, 0, sizeof(k)); + + memcpy(buf, v, sizeof(v)); + buf[sizeof(v)] = 0x00; + memcpy(buf + sizeof(v) + 1, bx, 64); + hmac_sha256(k, sizeof(k), buf, sizeof(buf), k); + hmac_sha256(k, sizeof(k), v, sizeof(v), v); + + memcpy(buf, v, sizeof(v)); + buf[sizeof(v)] = 0x01; + memcpy(buf + sizeof(v) + 1, bx, 64); + hmac_sha256(k, sizeof(k), buf, sizeof(buf), k); + hmac_sha256(k, sizeof(k), v, sizeof(k), v); + + for (;;) { + hmac_sha256(k, sizeof(k), v, sizeof(v), t); + read_32byte_big_endian(t, secret); + if ( !is_zero(secret) && is_less(secret, &order256k1) ) { + return; + } + memcpy(buf, v, sizeof(v)); + buf[sizeof(v)] = 0x00; + hmac_sha256(k, sizeof(k), buf, sizeof(v) + 1, k); + hmac_sha256(k, sizeof(k), v, sizeof(v), v); + } } // uses secp256k1 curve @@ -511,7 +575,7 @@ void generate_k_rfc6979(bignum256 *k, uint8_t *priv_key, uint8_t *hash) { // msg_len is the message length // sig is at least 70 bytes long array for the signature // sig_len is the pointer to a uint that will contain resulting signature length. note that ((*sig_len) == sig[1]+2) -void ecdsa_sign(uint8_t *priv_key, uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint32_t *sig_len) +void ecdsa_sign(const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint32_t *sig_len) { int i; uint8_t hash[32]; @@ -525,8 +589,13 @@ void ecdsa_sign(uint8_t *priv_key, uint8_t *msg, uint32_t msg_len, uint8_t *sig, read_32byte_big_endian(hash, &z); for (;;) { + // generate random number k - generate_k_random(&k); + //generate_k_random(&k); + + // generate K deterministically + generate_k_rfc6979(&k, priv_key, hash); + // compute k*G scalar_multiply(&k, &R); // r = (rx mod n) @@ -566,7 +635,7 @@ void ecdsa_sign(uint8_t *priv_key, uint8_t *msg, uint32_t msg_len, uint8_t *sig, // uses secp256k1 curve // priv_key is a 32 byte big endian stored number // pub_key is at least 70 bytes long array for the public key -void ecdsa_get_public_key(uint8_t *priv_key, uint8_t *pub_key, uint32_t *pub_key_len) +void ecdsa_get_public_key(const uint8_t *priv_key, uint8_t *pub_key, uint32_t *pub_key_len) { uint32_t i; curve_point R; @@ -586,7 +655,7 @@ void ecdsa_get_public_key(uint8_t *priv_key, uint8_t *pub_key, uint32_t *pub_key // does not validate that this is valid der encoding // assumes it is der encoding containing 1 number -void read_der_single(uint8_t *der, bignum256 *elem) +void read_der_single(const uint8_t *der, bignum256 *elem) { int i, j; uint8_t val[32]; @@ -605,38 +674,19 @@ void read_der_single(uint8_t *der, bignum256 *elem) // does not validate that this is valid der encoding // assumes it is der encoding containing 2 numbers (either public key or ecdsa signature) -void read_der_pair(uint8_t *der, bignum256 *elem1, bignum256 *elem2) +void read_der_pair(const uint8_t *der, bignum256 *elem1, bignum256 *elem2) { read_der_single(der + 2, elem1); read_der_single(der + 4 + der[3], elem2); } -int is_zero(const bignum256 *a) -{ - int i; - for (i = 0; i < 9; i++) { - if (a->val[i] != 0) return 0; - } - return 1; -} - -int is_less(const bignum256 *a, const bignum256 *b) -{ - int i; - for (i = 8; i >= 0; i--) { - if (a->val[i] < b->val[i]) return 1; - if (a->val[i] > b->val[i]) return 0; - } - return 0; -} - // uses secp256k1 curve // pub_key and signature are DER encoded // msg is a data that was signed // msg_len is the message length // returns 0 if verification succeeded // it is assumed that public key is valid otherwise calling this does not make much sense -int ecdsa_verify(uint8_t *pub_key, uint8_t *signature, uint8_t *msg, uint32_t msg_len) +int ecdsa_verify(const uint8_t *pub_key, const uint8_t *signature, const uint8_t *msg, uint32_t msg_len) { int i, j; uint8_t hash[32]; diff --git a/ecdsa.h b/ecdsa.h index 78edd4435..57ad8a780 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -26,9 +26,11 @@ #include +#include "secp256k1.h" + // uses secp256k1 curve -void ecdsa_sign(uint8_t *priv_key, uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint32_t *sig_len); -void ecdsa_get_public_key(uint8_t *priv_key, uint8_t *pub_key, uint32_t *pub_key_len); -int ecdsa_verify(uint8_t *pub_key, uint8_t *signature, uint8_t *msg, uint32_t msg_len); +void ecdsa_sign(const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint32_t *sig_len); +void ecdsa_get_public_key(const uint8_t *priv_key, uint8_t *pub_key, uint32_t *pub_key_len); +int ecdsa_verify(const uint8_t *pub_key, const uint8_t *signature, const uint8_t *msg, uint32_t msg_len); #endif diff --git a/test-rfc6979.c b/test-rfc6979.c new file mode 100644 index 000000000..48c7d576c --- /dev/null +++ b/test-rfc6979.c @@ -0,0 +1,51 @@ +/** + * Copyright (c) 2013 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include "ecdsa.h" +#include "sha2.h" + +bignum256 k; +uint8_t kb[32]; +uint8_t priv[32] = {0xcc, 0xa9, 0xfb, 0xcc, 0x1b, 0x41, 0xe5, 0xa9, 0x5d, 0x36, 0x9e, 0xaa, 0x6d, 0xdc, 0xff, 0x73, 0xb6, 0x1a, 0x4e, 0xfa, 0xa2, 0x79, 0xcf, 0xc6, 0x56, 0x7e, 0x8d, 0xaa, 0x39, 0xcb, 0xaf, 0x50}; +uint8_t hash[32]; + +void write_32byte_big_endian(const bignum256 *in_number, uint8_t *out_number); +void generate_k_rfc6979(bignum256 *k, const uint8_t *priv_key, const uint8_t *hash); + +int main() +{ + int i; + + SHA256_Raw((uint8_t *)"sample", 6, hash); + printf("hash : "); + for (i = 0; i < 32; i++) printf("%02x", hash[i]); printf("\n"); + generate_k_rfc6979(&k, priv, hash); + write_32byte_big_endian(&k, kb); + + printf("expected : 2df40ca70e639d89528a6b670d9d48d9165fdc0febc0974056bdce192b8e16a3\n"); + printf("got : "); + for (i = 0; i < 32; i++) printf("%02x", kb[i]); + printf("\n"); + + return 0; +} From 07d1c227308e11402339b840425b3b1afae7bc38 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 12 Sep 2013 03:15:22 +0200 Subject: [PATCH 020/627] refactor code -> bignum.c/h --- Makefile | 4 +- aux.c | 45 ---- bignum.c | 396 ++++++++++++++++++++++++++++++++ aux.h => bignum.h | 37 ++- ecdsa.c | 530 +++++++------------------------------------ ecdsa.h | 2 +- secp256k1.h | 12 +- sha2.c | 25 +- speed-stm32/Makefile | 5 +- speed-stm32/aux.c | 1 - speed-stm32/aux.h | 1 - speed-stm32/bignum.c | 1 + speed-stm32/bignum.h | 1 + speed-stm32/hmac.c | 1 + speed-stm32/hmac.h | 1 + speed-stm32/sha2.c | 1 + speed-stm32/sha2.h | 1 + speed-stm32/sha256.c | 1 - speed-stm32/sha256.h | 1 - test-rfc6979.c | 4 +- 20 files changed, 548 insertions(+), 522 deletions(-) delete mode 100644 aux.c create mode 100644 bignum.c rename aux.h => bignum.h (58%) delete mode 120000 speed-stm32/aux.c delete mode 120000 speed-stm32/aux.h create mode 120000 speed-stm32/bignum.c create mode 120000 speed-stm32/bignum.h create mode 120000 speed-stm32/hmac.c create mode 120000 speed-stm32/hmac.h create mode 120000 speed-stm32/sha2.c create mode 120000 speed-stm32/sha2.h delete mode 120000 speed-stm32/sha256.c delete mode 120000 speed-stm32/sha256.h diff --git a/Makefile b/Makefile index a9b90415c..b790094a3 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ CC = gcc CFLAGS = -Wall -Os -OBJS = aux.o ecdsa.o secp256k1.o sha2.o rand.o hmac.o +OBJS = bignum.o ecdsa.o secp256k1.o sha2.o rand.o hmac.o all: test-rfc6979 test-speed test-verify @@ -17,4 +17,4 @@ test-verify: test-verify.o $(OBJS) gcc test-verify.o $(OBJS) -o test-verify -lcrypto clean: - rm -f $(OBJS) test-speed test-verify + rm -f $(OBJS) test-rfc6979 test-speed test-verify diff --git a/aux.c b/aux.c deleted file mode 100644 index 71d28b809..000000000 --- a/aux.c +++ /dev/null @@ -1,45 +0,0 @@ -/** - * Copyright (c) 2013 Tomas Dzetkulic - * Copyright (c) 2013 Pavol Rusnak - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#include "aux.h" - -inline uint32_t ror(const uint32_t x, const int n) -{ - return (x >> n) | (x << (32 - n)); -} - -inline uint32_t read_be(const uint8_t *data) -{ - return (((uint32_t)data[0]) << 24) | - (((uint32_t)data[1]) << 16) | - (((uint32_t)data[2]) << 8) | - (((uint32_t)data[3])); -} - -inline void write_be(uint8_t *data, uint32_t x) -{ - data[0] = x >> 24; - data[1] = x >> 16; - data[2] = x >> 8; - data[3] = x; -} diff --git a/bignum.c b/bignum.c new file mode 100644 index 000000000..d4b341fb2 --- /dev/null +++ b/bignum.c @@ -0,0 +1,396 @@ +/** + * Copyright (c) 2013 Tomas Dzetkulic + * Copyright (c) 2013 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "bignum.h" +#include "secp256k1.h" + +inline uint32_t read_be(const uint8_t *data) +{ + return (((uint32_t)data[0]) << 24) | + (((uint32_t)data[1]) << 16) | + (((uint32_t)data[2]) << 8) | + (((uint32_t)data[3])); +} + +inline void write_be(uint8_t *data, uint32_t x) +{ + data[0] = x >> 24; + data[1] = x >> 16; + data[2] = x >> 8; + data[3] = x; +} + +void bn_read_be(const uint8_t *in_number, bignum256 *out_number) +{ + int i; + uint64_t temp = 0; + for (i = 0; i < 8; i++) { + temp += (((uint64_t)read_be(in_number + (7 - i) * 4)) << (2 * i)); + out_number->val[i]= temp & 0x3FFFFFFF; + temp >>= 30; + } + out_number->val[8] = temp; +} + +void bn_write_be(const bignum256 *in_number, uint8_t *out_number) +{ + int i, shift = 30 + 16 - 32; + uint64_t temp = in_number->val[8]; + for (i = 0; i < 8; i++) { + temp <<= 30; + temp |= in_number->val[7 - i]; + write_be(out_number + i * 4, temp >> shift); + shift -= 2; + } +} + +int bn_is_zero(const bignum256 *a) +{ + int i; + for (i = 0; i < 9; i++) { + if (a->val[i] != 0) return 0; + } + return 1; +} + +int bn_is_less(const bignum256 *a, const bignum256 *b) +{ + int i; + for (i = 8; i >= 0; i--) { + if (a->val[i] < b->val[i]) return 1; + if (a->val[i] > b->val[i]) return 0; + } + return 0; +} + +// assumes x < 2*prime +void bn_mod(bignum256 *x, bignum256 const *prime) +{ + int i = 8; + uint32_t temp; + // compare numbers + while (i >= 0 && prime->val[i] == x->val[i]) i--; + // if equal + if (i == -1) { + // set x to zero + for (i = 0; i < 9; i++) { + x->val[i] = 0; + } + } else { + // if x is greater + if (x->val[i] > prime->val[i]) { + // substract p from x + temp = 0x40000000u; + for (i = 0; i < 9; i++) { + temp += x->val[i] - prime->val[i]; + x->val[i] = temp & 0x3FFFFFFF; + temp >>= 30; + temp += 0x3FFFFFFFu; + } + } + } +} + +// x = k * x +// both inputs and result may be bigger than prime but not bigger than 2 * prime +void bn_multiply(const bignum256 *k, bignum256 *x, bignum256 const *prime) +{ + int i, j; + uint64_t temp = 0; + uint32_t res[18], coef; + + // compute lower half of long multiplication + for (i = 0; i < 9; i++) + { + for (j = 0; j <= i; j++) { + temp += k->val[j] * (uint64_t)x->val[i - j]; + } + res[i] = temp & 0x3FFFFFFFu; + temp >>= 30; + } + // compute upper half + for (; i < 17; i++) + { + for (j = i - 8; j < 9 ; j++) { + temp += k->val[j] * (uint64_t)x->val[i - j]; + } + res[i] = temp & 0x3FFFFFFFu; + temp >>= 30; + } + res[17] = temp; + // compute modulo p division is only estimated so this may give result greater than prime but not bigger than 2 * prime + for (i = 16; i >= 8; i--) { + // estimate (res / prime) + coef = (res[i] >> 16) + (res[i + 1] << 14); + // substract (coef * prime) from res + temp = 0x1000000000000000llu + res[i - 8] - prime->val[0] * (uint64_t)coef; + res[i - 8] = temp & 0x3FFFFFFF; + for (j = 1; j < 9; j++) { + temp >>= 30; + temp += 0xFFFFFFFC0000000llu + res[i - 8 + j] - prime->val[j] * (uint64_t)coef; + res[i - 8 + j] = temp & 0x3FFFFFFF; + } + } + // store the result + for (i = 0; i < 9; i++) { + x->val[i] = res[i]; + } +} + +void bn_fast_mod(bignum256 *x, bignum256 const *prime) +{ + int j; + uint32_t coef; + uint64_t temp; + + coef = x->val[8] >> 16; + if (!coef) return; + // substract (coef * prime) from x + temp = 0x1000000000000000llu + x->val[0] - prime->val[0] * (uint64_t)coef; + x->val[0] = temp & 0x3FFFFFFF; + for (j = 1; j < 9; j++) { + temp >>= 30; + temp += 0xFFFFFFFC0000000llu + x->val[j] - prime->val[j] * (uint64_t)coef; + x->val[j] = temp & 0x3FFFFFFF; + } +} + +#ifndef INVERSE_FAST + +#ifdef USE_PRECOMPUTED_IV +#warning USE_PRECOMPUTED_IV will not be used, please undef +#endif + +// in field G_prime, small but slow +void bn_inverse(bignum256 *x, bignum256 const *prime) +{ + uint32_t i, j, limb; + bignum256 res; + res.val[0] = 1; + for (i = 1; i < 9; i++) { + res.val[i] = 0; + } + for (i = 0; i < 9; i++) { + limb = prime->val[i]; + // this is not enough in general but fine for secp256k1 because prime->val[0] > 1 + if (i == 0) limb -= 2; + for (j = 0; j < 30; j++) { + if (i == 8 && limb == 0) break; + if (limb & 1) { + multiply(x, &res, prime); + } + limb >>= 1; + multiply(x, x, prime); + } + } + bn_mod(&res, prime); + memcpy(x, &res, sizeof(bignum256)); +} + +#else + +// in field G_prime, big but fast +void bn_inverse(bignum256 *x, bignum256 const *prime) +{ + int i, j, k, len1, len2, mask; + uint32_t u[9], v[9], s[10], r[10], temp, temp2; + bn_fast_mod(x, prime); + bn_mod(x, prime); + for (i = 0; i < 9; i++) { + u[i] = prime->val[i]; + v[i] = x->val[i]; + } + len1 = 9; + s[0] = 1; + r[0] = 0; + len2 = 1; + k = 0; + for (;;) { + for (i = 0; i < len1; i++) { + if (v[i]) break; + } + if (i == len1) break; + for (;;) { + for (i = 0; i < 30; i++) { + if (u[0] & (1 << i)) break; + } + if (i == 0) break; + mask = (1 << i) - 1; + for (j = 0; j + 1 < len1; j++) { + u[j] = (u[j] >> i) | ((u[j + 1] & mask) << (30 - i)); + } + u[j] = (u[j] >> i); + mask = (1 << (30 - i)) - 1; + s[len2] = s[len2 - 1] >> (30 - i); + for (j = len2 - 1; j > 0; j--) { + s[j] = (s[j - 1] >> (30 - i)) | ((s[j] & mask) << i); + } + s[0] = (s[0] & mask) << i; + if (s[len2]) { + r[len2] = 0; + len2++; + } + k += i; + } + for (;;) { + for (i = 0; i < 30; i++) { + if (v[0] & (1 << i)) break; + } + if (i == 0) break; + mask = (1 << i) - 1; + for (j = 0; j + 1 < len1; j++) { + v[j] = (v[j] >> i) | ((v[j + 1] & mask) << (30 - i)); + } + v[j] = (v[j] >> i); + mask = (1 << (30 - i)) - 1; + r[len2] = r[len2 - 1] >> (30 - i); + for (j = len2 - 1; j > 0; j--) { + r[j] = (r[j - 1] >> (30 - i)) | ((r[j] & mask) << i); + } + r[0] = (r[0] & mask) << i; + if (r[len2]) { + s[len2] = 0; + len2++; + } + k += i; + } + + i = len1 - 1; + while (i > 0 && u[i] == v[i]) i--; + if (u[i] > v[i]) { + temp = 0x40000000u + u[0] - v[0]; + u[0] = (temp >> 1) & 0x1FFFFFFF; + temp >>= 30; + for (i = 1; i < len1; i++) { + temp += 0x3FFFFFFFu + u[i] - v[i]; + u[i - 1] += (temp & 1) << 29; + u[i] = (temp >> 1) & 0x1FFFFFFF; + temp >>= 30; + } + temp = temp2 = 0; + for (i = 0; i < len2; i++) { + temp += s[i] + r[i]; + temp2 += s[i] << 1; + r[i] = temp & 0x3FFFFFFF; + s[i] = temp2 & 0x3FFFFFFF; + temp >>= 30; + temp2 >>= 30; + } + if (temp != 0 || temp2 != 0) { + r[len2] = temp; + s[len2] = temp2; + len2++; + } + } else { + temp = 0x40000000u + v[0] - u[0]; + v[0] = (temp >> 1) & 0x1FFFFFFF; + temp >>= 30; + for (i = 1; i < len1; i++) { + temp += 0x3FFFFFFFu + v[i] - u[i]; + v[i - 1] += (temp & 1) << 29; + v[i] = (temp >> 1) & 0x1FFFFFFF; + temp >>= 30; + } + temp = temp2 = 0; + for (i = 0; i < len2; i++) { + temp += s[i] + r[i]; + temp2 += r[i] << 1; + s[i] = temp & 0x3FFFFFFF; + r[i] = temp2 & 0x3FFFFFFF; + temp >>= 30; + temp2 >>= 30; + } + if (temp != 0 || temp2 != 0) { + s[len2] = temp; + r[len2] = temp2; + len2++; + } + } + if (u[len1 - 1] == 0 && v[len1 - 1] == 0) len1--; + k++; + } + i = 8; + while (i > 0 && r[i] == prime->val[i]) i--; + if (r[i] >= prime->val[i]) { + temp = 1; + for (i = 0; i < 9; i++) { + temp += 0x3FFFFFFF + r[i] - prime->val[i]; + r[i] = temp & 0x3FFFFFFF; + temp >>= 30; + } + } + temp = 1; + for (i = 0; i < 9; i++) { + temp += 0x3FFFFFFF + prime->val[i] - r[i]; + r[i] = temp & 0x3FFFFFFF; + temp >>= 30; + } + int done = 0; +#ifdef USE_PRECOMPUTED_IV + if (prime == &prime256k1) { + for (j = 0; j < 9; j++) { + x->val[j] = r[j]; + } + bn_multiply(secp256k1_iv + k - 256, x, prime); + bn_fast_mod(x, prime); + done = 1; + } +#endif + if (!done) { + for (j = 0; j < k; j++) { + if (r[0] & 1) { + temp = r[0] + prime->val[0]; + r[0] = (temp >> 1) & 0x1FFFFFFF; + temp >>= 30; + for (i = 1; i < 9; i++) { + temp += r[i] + prime->val[i]; + r[i - 1] += (temp & 1) << 29; + r[i] = (temp >> 1) & 0x1FFFFFFF; + temp >>= 30; + } + } else { + for (i = 0; i < 8; i++) { + r[i] = (r[i] >> 1) | ((r[i + 1] & 1) << 29); + } + r[8] = r[8] >> 1; + } + } + for (j = 0; j < 9; j++) { + x->val[j] = r[j]; + } + } +} +#endif + +// res = a - b +// b < 2*prime; result not normalized +void bn_substract(const bignum256 *a, const bignum256 *b, bignum256 *res) +{ + int i; + uint32_t temp = 0; + for (i = 0; i < 9; i++) { + temp += a->val[i] + 2u *prime256k1.val[i] - b->val[i]; + res->val[i] = temp & 0x3FFFFFFF; + temp >>= 30; + } +} diff --git a/aux.h b/bignum.h similarity index 58% rename from aux.h rename to bignum.h index c73b7b355..62a5f6e78 100644 --- a/aux.h +++ b/bignum.h @@ -21,13 +21,24 @@ * OTHER DEALINGS IN THE SOFTWARE. */ -#ifndef __AUX_H__ -#define __AUX_H__ +#ifndef __BIGNUM_H__ +#define __BIGNUM_H__ #include -// rotate uint32 right -uint32_t ror(const uint32_t x, const int n); +// use precomputed Inverse Values of powers of two +#define USE_PRECOMPUTED_IV 1 + +// use precomputed Curve Points (some scalar multiples of curve base point G) +#define USE_PRECOMPUTED_CP 1 + +#define INVERSE_FAST 1 + +// bignum256 are 256 bits stored as 8*30 bit + 1*16 bit +// val[0] are lowest 30 bits, val[8] highest 16 bits +typedef struct { + uint32_t val[9]; +} bignum256; // read 4 big endian bytes into uint32 uint32_t read_be(const uint8_t *data); @@ -35,4 +46,22 @@ uint32_t read_be(const uint8_t *data); // write 4 big endian bytes void write_be(uint8_t *data, uint32_t x); +void bn_read_be(const uint8_t *in_number, bignum256 *out_number); + +void bn_write_be(const bignum256 *in_number, uint8_t *out_number); + +int bn_is_zero(const bignum256 *a); + +int bn_is_less(const bignum256 *a, const bignum256 *b); + +void bn_mod(bignum256 *x, bignum256 const *prime); + +void bn_multiply(const bignum256 *k, bignum256 *x, bignum256 const *prime); + +void bn_fast_mod(bignum256 *x, bignum256 const *prime); + +void bn_inverse(bignum256 *x, bignum256 const *prime); + +void bn_substract(const bignum256 *a, const bignum256 *b, bignum256 *res); + #endif diff --git a/ecdsa.c b/ecdsa.c index c0371af61..4757f733e 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -25,324 +25,11 @@ #include #include +#include "bignum.h" #include "rand.h" #include "sha2.h" #include "hmac.h" #include "ecdsa.h" -#include "aux.h" - -#define INVERSE_FAST 1 - -// assumes x < 2*prime -void mod(bignum256 *x, bignum256 const *prime) -{ - int i = 8; - uint32_t temp; - // compare numbers - while (i >= 0 && prime->val[i] == x->val[i]) i--; - // if equal - if (i == -1) { - // set x to zero - for (i = 0; i < 9; i++) { - x->val[i] = 0; - } - } else { - // if x is greater - if (x->val[i] > prime->val[i]) { - // substract p from x - temp = 0x40000000u; - for (i = 0; i < 9; i++) { - temp += x->val[i] - prime->val[i]; - x->val[i] = temp & 0x3FFFFFFF; - temp >>= 30; - temp += 0x3FFFFFFFu; - } - } - } -} - -// x = k * x -// both inputs and result may be bigger than prime but not bigger than 2 * prime -void multiply(const bignum256 *k, bignum256 *x, bignum256 const *prime) -{ - int i, j; - uint64_t temp = 0; - uint32_t res[18], coef; - - // compute lower half of long multiplication - for (i = 0; i < 9; i++) - { - for (j = 0; j <= i; j++) { - temp += k->val[j] * (uint64_t)x->val[i - j]; - } - res[i] = temp & 0x3FFFFFFFu; - temp >>= 30; - } - // compute upper half - for (; i < 17; i++) - { - for (j = i - 8; j < 9 ; j++) { - temp += k->val[j] * (uint64_t)x->val[i - j]; - } - res[i] = temp & 0x3FFFFFFFu; - temp >>= 30; - } - res[17] = temp; - // compute modulo p division is only estimated so this may give result greater than prime but not bigger than 2 * prime - for (i = 16; i >= 8; i--) { - // estimate (res / prime) - coef = (res[i] >> 16) + (res[i + 1] << 14); - // substract (coef * prime) from res - temp = 0x1000000000000000llu + res[i - 8] - prime->val[0] * (uint64_t)coef; - res[i - 8] = temp & 0x3FFFFFFF; - for (j = 1; j < 9; j++) { - temp >>= 30; - temp += 0xFFFFFFFC0000000llu + res[i - 8 + j] - prime->val[j] * (uint64_t)coef; - res[i - 8 + j] = temp & 0x3FFFFFFF; - } - } - // store the result - for (i = 0; i < 9; i++) { - x->val[i] = res[i]; - } -} - -void fast_mod(bignum256 *x, bignum256 const *prime) -{ - int j; - uint32_t coef; - uint64_t temp; - - coef = x->val[8] >> 16; - if (!coef) return; - // substract (coef * prime) from x - temp = 0x1000000000000000llu + x->val[0] - prime->val[0] * (uint64_t)coef; - x->val[0] = temp & 0x3FFFFFFF; - for (j = 1; j < 9; j++) { - temp >>= 30; - temp += 0xFFFFFFFC0000000llu + x->val[j] - prime->val[j] * (uint64_t)coef; - x->val[j] = temp & 0x3FFFFFFF; - } -} - -#ifndef INVERSE_FAST - -#ifdef USE_PRECOMPUTED_IV -#warning USE_PRECOMPUTED_IV will not be used, please undef -#endif -// in field G_prime, small but slow -void inverse(bignum256 *x, bignum256 const *prime) -{ - uint32_t i, j, limb; - bignum256 res; - res.val[0] = 1; - for (i = 1; i < 9; i++) { - res.val[i] = 0; - } - for (i = 0; i < 9; i++) { - limb = prime->val[i]; - // this is not enough in general but fine for secp256k1 because prime->val[0] > 1 - if (i == 0) limb -= 2; - for (j = 0; j < 30; j++) { - if (i == 8 && limb == 0) break; - if (limb & 1) { - multiply(x, &res, prime); - } - limb >>= 1; - multiply(x, x, prime); - } - } - mod(&res, prime); - memcpy(x, &res, sizeof(bignum256)); -} - -#else - -// in field G_prime, big but fast -void inverse(bignum256 *x, bignum256 const *prime) -{ - int i, j, k, len1, len2, mask; - uint32_t u[9], v[9], s[10], r[10], temp, temp2; - fast_mod(x, prime); - mod(x, prime); - for (i = 0; i < 9; i++) { - u[i] = prime->val[i]; - v[i] = x->val[i]; - } - len1 = 9; - s[0] = 1; - r[0] = 0; - len2 = 1; - k = 0; - for (;;) { - for (i = 0; i < len1; i++) { - if (v[i]) break; - } - if (i == len1) break; - for (;;) { - for (i = 0; i < 30; i++) { - if (u[0] & (1 << i)) break; - } - if (i == 0) break; - mask = (1 << i) - 1; - for (j = 0; j + 1 < len1; j++) { - u[j] = (u[j] >> i) | ((u[j + 1] & mask) << (30 - i)); - } - u[j] = (u[j] >> i); - mask = (1 << (30 - i)) - 1; - s[len2] = s[len2 - 1] >> (30 - i); - for (j = len2 - 1; j > 0; j--) { - s[j] = (s[j - 1] >> (30 - i)) | ((s[j] & mask) << i); - } - s[0] = (s[0] & mask) << i; - if (s[len2]) { - r[len2] = 0; - len2++; - } - k += i; - } - for (;;) { - for (i = 0; i < 30; i++) { - if (v[0] & (1 << i)) break; - } - if (i == 0) break; - mask = (1 << i) - 1; - for (j = 0; j + 1 < len1; j++) { - v[j] = (v[j] >> i) | ((v[j + 1] & mask) << (30 - i)); - } - v[j] = (v[j] >> i); - mask = (1 << (30 - i)) - 1; - r[len2] = r[len2 - 1] >> (30 - i); - for (j = len2 - 1; j > 0; j--) { - r[j] = (r[j - 1] >> (30 - i)) | ((r[j] & mask) << i); - } - r[0] = (r[0] & mask) << i; - if (r[len2]) { - s[len2] = 0; - len2++; - } - k += i; - } - - i = len1 - 1; - while (i > 0 && u[i] == v[i]) i--; - if (u[i] > v[i]) { - temp = 0x40000000u + u[0] - v[0]; - u[0] = (temp >> 1) & 0x1FFFFFFF; - temp >>= 30; - for (i = 1; i < len1; i++) { - temp += 0x3FFFFFFFu + u[i] - v[i]; - u[i - 1] += (temp & 1) << 29; - u[i] = (temp >> 1) & 0x1FFFFFFF; - temp >>= 30; - } - temp = temp2 = 0; - for (i = 0; i < len2; i++) { - temp += s[i] + r[i]; - temp2 += s[i] << 1; - r[i] = temp & 0x3FFFFFFF; - s[i] = temp2 & 0x3FFFFFFF; - temp >>= 30; - temp2 >>= 30; - } - if (temp != 0 || temp2 != 0) { - r[len2] = temp; - s[len2] = temp2; - len2++; - } - } else { - temp = 0x40000000u + v[0] - u[0]; - v[0] = (temp >> 1) & 0x1FFFFFFF; - temp >>= 30; - for (i = 1; i < len1; i++) { - temp += 0x3FFFFFFFu + v[i] - u[i]; - v[i - 1] += (temp & 1) << 29; - v[i] = (temp >> 1) & 0x1FFFFFFF; - temp >>= 30; - } - temp = temp2 = 0; - for (i = 0; i < len2; i++) { - temp += s[i] + r[i]; - temp2 += r[i] << 1; - s[i] = temp & 0x3FFFFFFF; - r[i] = temp2 & 0x3FFFFFFF; - temp >>= 30; - temp2 >>= 30; - } - if (temp != 0 || temp2 != 0) { - s[len2] = temp; - r[len2] = temp2; - len2++; - } - } - if (u[len1 - 1] == 0 && v[len1 - 1] == 0) len1--; - k++; - } - i = 8; - while (i > 0 && r[i] == prime->val[i]) i--; - if (r[i] >= prime->val[i]) { - temp = 1; - for (i = 0; i < 9; i++) { - temp += 0x3FFFFFFF + r[i] - prime->val[i]; - r[i] = temp & 0x3FFFFFFF; - temp >>= 30; - } - } - temp = 1; - for (i = 0; i < 9; i++) { - temp += 0x3FFFFFFF + prime->val[i] - r[i]; - r[i] = temp & 0x3FFFFFFF; - temp >>= 30; - } - int done = 0; -#ifdef USE_PRECOMPUTED_IV - if (prime == &prime256k1) { - for (j = 0; j < 9; j++) { - x->val[j] = r[j]; - } - multiply(secp256k1_iv + k - 256, x, prime); - fast_mod(x, prime); - done = 1; - } -#endif - if (!done) { - for (j = 0; j < k; j++) { - if (r[0] & 1) { - temp = r[0] + prime->val[0]; - r[0] = (temp >> 1) & 0x1FFFFFFF; - temp >>= 30; - for (i = 1; i < 9; i++) { - temp += r[i] + prime->val[i]; - r[i - 1] += (temp & 1) << 29; - r[i] = (temp >> 1) & 0x1FFFFFFF; - temp >>= 30; - } - } else { - for (i = 0; i < 8; i++) { - r[i] = (r[i] >> 1) | ((r[i + 1] & 1) << 29); - } - r[8] = r[8] >> 1; - } - } - for (j = 0; j < 9; j++) { - x->val[j] = r[j]; - } - } -} -#endif - -// res = a - b -// b < 2*prime; result not normalized -void fast_substract(const bignum256 *a, const bignum256 *b, bignum256 *res) -{ - int i; - uint32_t temp = 0; - for (i = 0; i < 9; i++) { - temp += a->val[i] + 2u *prime256k1.val[i] - b->val[i]; - res->val[i] = temp & 0x3FFFFFFF; - temp >>= 30; - } -} // cp2 = cp1 + cp2 void point_add(const curve_point *cp1, curve_point *cp2) @@ -350,25 +37,25 @@ void point_add(const curve_point *cp1, curve_point *cp2) int i; uint32_t temp; bignum256 lambda, inv, xr, yr; - fast_substract(&(cp2->x), &(cp1->x), &inv); - inverse(&inv, &prime256k1); - fast_substract(&(cp2->y), &(cp1->y), &lambda); - multiply(&inv, &lambda, &prime256k1); + bn_substract(&(cp2->x), &(cp1->x), &inv); + bn_inverse(&inv, &prime256k1); + bn_substract(&(cp2->y), &(cp1->y), &lambda); + bn_multiply(&inv, &lambda, &prime256k1); memcpy(&xr, &lambda, sizeof(bignum256)); - multiply(&xr, &xr, &prime256k1); + bn_multiply(&xr, &xr, &prime256k1); temp = 0; for (i = 0; i < 9; i++) { temp += xr.val[i] + 3u * prime256k1.val[i] - cp1->x.val[i] - cp2->x.val[i]; xr.val[i] = temp & 0x3FFFFFFF; temp >>= 30; } - fast_mod(&xr, &prime256k1); - fast_substract(&(cp1->x), &xr, &yr); + bn_fast_mod(&xr, &prime256k1); + bn_substract(&(cp1->x), &xr, &yr); // no need to fast_mod here - // fast_mod(&yr); - multiply(&lambda, &yr, &prime256k1); - fast_substract(&yr, &(cp1->y), &yr); - fast_mod(&yr, &prime256k1); + // bn_fast_mod(&yr); + bn_multiply(&lambda, &yr, &prime256k1); + bn_substract(&yr, &(cp1->y), &yr); + bn_fast_mod(&yr, &prime256k1); memcpy(&(cp2->x), &xr, sizeof(bignum256)); memcpy(&(cp2->y), &yr, sizeof(bignum256)); } @@ -380,26 +67,26 @@ void point_double(curve_point *cp) uint32_t temp; bignum256 lambda, inverse_y, xr, yr; memcpy(&inverse_y, &(cp->y), sizeof(bignum256)); - inverse(&inverse_y, &prime256k1); + bn_inverse(&inverse_y, &prime256k1); memcpy(&lambda, &three_over_two256k1, sizeof(bignum256)); - multiply(&inverse_y, &lambda, &prime256k1); - multiply(&(cp->x), &lambda, &prime256k1); - multiply(&(cp->x), &lambda, &prime256k1); + bn_multiply(&inverse_y, &lambda, &prime256k1); + bn_multiply(&(cp->x), &lambda, &prime256k1); + bn_multiply(&(cp->x), &lambda, &prime256k1); memcpy(&xr, &lambda, sizeof(bignum256)); - multiply(&xr, &xr, &prime256k1); + bn_multiply(&xr, &xr, &prime256k1); temp = 0; for (i = 0; i < 9; i++) { temp += xr.val[i] + 3u * prime256k1.val[i] - 2u * cp->x.val[i]; xr.val[i] = temp & 0x3FFFFFFF; temp >>= 30; } - fast_mod(&xr, &prime256k1); - fast_substract(&(cp->x), &xr, &yr); + bn_fast_mod(&xr, &prime256k1); + bn_substract(&(cp->x), &xr, &yr); // no need to fast_mod here - // fast_mod(&yr); - multiply(&lambda, &yr, &prime256k1); - fast_substract(&yr, &(cp->y), &yr); - fast_mod(&yr, &prime256k1); + // bn_fast_mod(&yr); + bn_multiply(&lambda, &yr, &prime256k1); + bn_substract(&yr, &(cp->y), &yr); + bn_fast_mod(&yr, &prime256k1); memcpy(&(cp->x), &xr, sizeof(bignum256)); memcpy(&(cp->y), &yr, sizeof(bignum256)); } @@ -443,12 +130,39 @@ void scalar_multiply(bignum256 *k, curve_point *res) #endif } } - mod(&(res->x), &prime256k1); - mod(&(res->y), &prime256k1); + bn_mod(&(res->x), &prime256k1); + bn_mod(&(res->y), &prime256k1); +} + +// does not validate that this is valid der encoding +// assumes it is der encoding containing 1 number +void der_read_single(const uint8_t *der, bignum256 *elem) +{ + int i, j; + uint8_t val[32]; + i = 1 + der[1]; + j = 31; + // we ignore all bytes after 32nd. if there are any, those are either zero or invalid for secp256k1 + while (i > 1 && j >= 0) { + val[j] = der[i]; + i--; j--; + } + for (i = 0; i <= j; i++) { + val[i] = 0; + } + bn_read_be(val, elem); +} + +// does not validate that this is valid der encoding +// assumes it is der encoding containing 2 numbers (either public key or ecdsa signature) +void der_read_pair(const uint8_t *der, bignum256 *elem1, bignum256 *elem2) +{ + der_read_single(der + 2, elem1); + der_read_single(der + 4 + der[3], elem2); } // write DER encoding of number to buffer -void write_der(const bignum256 *x, uint8_t *buf) +void der_write(const bignum256 *x, uint8_t *buf) { int i, j = 8, k = 8, len = 0; uint8_t r = 0, temp; @@ -471,49 +185,6 @@ void write_der(const bignum256 *x, uint8_t *buf) buf[1] = len; } -void read_32byte_big_endian(const uint8_t *in_number, bignum256 *out_number) -{ - int i; - uint64_t temp = 0; - for (i = 0; i < 8; i++) { - temp += (((uint64_t)read_be(in_number + (7 - i) * 4)) << (2 * i)); - out_number->val[i]= temp & 0x3FFFFFFF; - temp >>= 30; - } - out_number->val[8] = temp; -} - -void write_32byte_big_endian(const bignum256 *in_number, uint8_t *out_number) -{ - int i, shift = 30 + 16 - 32; - uint64_t temp = in_number->val[8]; - for (i = 0; i < 8; i++) { - temp <<= 30; - temp |= in_number->val[7 - i]; - write_be(out_number + i * 4, temp >> shift); - shift -= 2; - } -} - -int is_zero(const bignum256 *a) -{ - int i; - for (i = 0; i < 9; i++) { - if (a->val[i] != 0) return 0; - } - return 1; -} - -int is_less(const bignum256 *a, const bignum256 *b) -{ - int i; - for (i = 8; i >= 0; i--) { - if (a->val[i] < b->val[i]) return 1; - if (a->val[i] > b->val[i]) return 0; - } - return 0; -} - // generate random K for signing void generate_k_random(bignum256 *k) { int i; @@ -537,9 +208,9 @@ void generate_k_rfc6979(bignum256 *secret, const uint8_t *priv_key, const uint8_ bignum256 z1; memcpy(bx, priv_key, 32); - read_32byte_big_endian(hash, &z1); - mod(&z1, &order256k1); - write_32byte_big_endian(&z1, bx + 32); + bn_read_be(hash, &z1); + bn_mod(&z1, &order256k1); + bn_write_be(&z1, bx + 32); memset(v, 1, sizeof(v)); memset(k, 0, sizeof(k)); @@ -558,8 +229,8 @@ void generate_k_rfc6979(bignum256 *secret, const uint8_t *priv_key, const uint8_ for (;;) { hmac_sha256(k, sizeof(k), v, sizeof(v), t); - read_32byte_big_endian(t, secret); - if ( !is_zero(secret) && is_less(secret, &order256k1) ) { + bn_read_be(t, secret); + if ( !bn_is_zero(secret) && bn_is_less(secret, &order256k1) ) { return; } memcpy(buf, v, sizeof(v)); @@ -587,7 +258,7 @@ void ecdsa_sign(const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, u // if double hash is required uncomment the following line: // SHA256_Raw(hash, 32, hash); - read_32byte_big_endian(hash, &z); + bn_read_be(hash, &z); for (;;) { // generate random number k @@ -599,23 +270,23 @@ void ecdsa_sign(const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, u // compute k*G scalar_multiply(&k, &R); // r = (rx mod n) - mod(&R.x, &order256k1); + bn_mod(&R.x, &order256k1); // if r is zero, we try different k for (i = 0; i < 9; i++) { if (R.x.val[i] != 0) break; } if (i == 9) continue; - inverse(&k, &order256k1); - read_32byte_big_endian(priv_key, da); - multiply(&R.x, da, &order256k1); + bn_inverse(&k, &order256k1); + bn_read_be(priv_key, da); + bn_multiply(&R.x, da, &order256k1); for (i = 0; i < 8; i++) { da->val[i] += z.val[i]; da->val[i + 1] += (da->val[i] >> 30); da->val[i] &= 0x3FFFFFFF; } da->val[8] += z.val[8]; - multiply(da, &k, &order256k1); - mod(&k, &order256k1); + bn_multiply(da, &k, &order256k1); + bn_mod(&k, &order256k1); for (i = 0; i < 9; i++) { if (k.val[i] != 0) break; } @@ -623,9 +294,9 @@ void ecdsa_sign(const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, u // we are done, R.x and k is the result signature break; } - write_der(&R.x, sig + 2); + der_write(&R.x, sig + 2); i = sig[3] + 2; - write_der(&k, sig + 2 + i); + der_write(&k, sig + 2 + i); i += sig[3 + i] + 2; sig[0] = 0x30; sig[1] = i; @@ -641,45 +312,18 @@ void ecdsa_get_public_key(const uint8_t *priv_key, uint8_t *pub_key, uint32_t *p curve_point R; bignum256 k; - read_32byte_big_endian(priv_key, &k); + bn_read_be(priv_key, &k); // compute k*G scalar_multiply(&k, &R); - write_der(&R.x, pub_key + 2); + der_write(&R.x, pub_key + 2); i = pub_key[3] + 2; - write_der(&R.y, pub_key + 2 + i); + der_write(&R.y, pub_key + 2 + i); i += pub_key[3 + i] + 2; pub_key[0] = 0x30; pub_key[1] = i; *pub_key_len = i + 2; } -// does not validate that this is valid der encoding -// assumes it is der encoding containing 1 number -void read_der_single(const uint8_t *der, bignum256 *elem) -{ - int i, j; - uint8_t val[32]; - i = 1 + der[1]; - j = 31; - // we ignore all bytes after 32nd. if there are any, those are either zero or invalid for secp256k1 - while (i > 1 && j >= 0) { - val[j] = der[i]; - i--; j--; - } - for (i = 0; i <= j; i++) { - val[i] = 0; - } - read_32byte_big_endian(val, elem); -} - -// does not validate that this is valid der encoding -// assumes it is der encoding containing 2 numbers (either public key or ecdsa signature) -void read_der_pair(const uint8_t *der, bignum256 *elem1, bignum256 *elem2) -{ - read_der_single(der + 2, elem1); - read_der_single(der + 4 + der[3], elem2); -} - // uses secp256k1 curve // pub_key and signature are DER encoded // msg is a data that was signed @@ -698,21 +342,21 @@ int ecdsa_verify(const uint8_t *pub_key, const uint8_t *signature, const uint8_t // if double hash is required uncomment the following line: // SHA256_Raw(hash, 32, hash); - read_32byte_big_endian(hash, &z); - read_der_pair(pub_key, &pub.x, &pub.y); - read_der_pair(signature, &r, &s); - - if (is_zero(&r) || - is_zero(&s) || - (!is_less(&r, &order256k1)) || - (!is_less(&s, &order256k1))) return 1; - - inverse(&s, &order256k1); // s^-1 - multiply(&s, &z, &order256k1); // z*s^-1 - mod(&z, &order256k1); - multiply(&r, &s, &order256k1); // r*s^-1 - mod(&s, &order256k1); - if (is_zero(&z)) { + bn_read_be(hash, &z); + der_read_pair(pub_key, &pub.x, &pub.y); + der_read_pair(signature, &r, &s); + + if (bn_is_zero(&r) || + bn_is_zero(&s) || + (!bn_is_less(&r, &order256k1)) || + (!bn_is_less(&s, &order256k1))) return 1; + + bn_inverse(&s, &order256k1); // s^-1 + bn_multiply(&s, &z, &order256k1); // z*s^-1 + bn_mod(&z, &order256k1); + bn_multiply(&r, &s, &order256k1); // r*s^-1 + bn_mod(&s, &order256k1); + if (bn_is_zero(&z)) { // our message hashes to zero // I don't expect this to happen any time soon res_is_zero = 1; @@ -731,8 +375,8 @@ int ecdsa_verify(const uint8_t *pub_key, const uint8_t *signature, const uint8_t } } - mod(&(res.x), &prime256k1); - mod(&(res.x), &order256k1); + bn_mod(&(res.x), &prime256k1); + bn_mod(&(res.x), &order256k1); for (i = 0; i < 9; i++) { if (res.x.val[i] != r.val[i]) { return 1; diff --git a/ecdsa.h b/ecdsa.h index 57ad8a780..f993fde08 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -28,7 +28,7 @@ #include "secp256k1.h" -// uses secp256k1 curve +// all functions use secp256k1 curve void ecdsa_sign(const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint32_t *sig_len); void ecdsa_get_public_key(const uint8_t *priv_key, uint8_t *pub_key, uint32_t *pub_key_len); int ecdsa_verify(const uint8_t *pub_key, const uint8_t *signature, const uint8_t *msg, uint32_t msg_len); diff --git a/secp256k1.h b/secp256k1.h index 805e4e658..cf5a53df8 100644 --- a/secp256k1.h +++ b/secp256k1.h @@ -26,17 +26,7 @@ #include -// use precomputed Inverse Values of powers of two -#define USE_PRECOMPUTED_IV 1 - -// use precomputed Curve Points (some scalar multiples of curve base point G) -#define USE_PRECOMPUTED_CP 1 - -// bignum256 are 256 bits stored as 8*30 bit + 1*16 bit -// val[0] are lowest 30 bits, val[8] highest 16 bits -typedef struct { - uint32_t val[9]; -} bignum256; +#include "bignum.h" // curve point x and y typedef struct { diff --git a/sha2.c b/sha2.c index 4487bf8fa..13868f8af 100644 --- a/sha2.c +++ b/sha2.c @@ -82,6 +82,11 @@ * made). */ +#ifndef LITTLE_ENDIAN +#define LITTLE_ENDIAN 1234 +#define BIG_ENDIAN 4321 +#endif + #ifndef BYTE_ORDER #define BYTE_ORDER LITTLE_ENDIAN #endif @@ -176,7 +181,7 @@ void SHA512_Transform(SHA512_CTX*, const sha2_word64*); /*** SHA-XYZ INITIAL HASH VALUES AND CONSTANTS ************************/ /* Hash constant words K for SHA-256: */ -const static sha2_word32 K256[64] = { +static const sha2_word32 K256[64] = { 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL, @@ -196,7 +201,7 @@ const static sha2_word32 K256[64] = { }; /* Initial hash value H for SHA-256: */ -const static sha2_word32 sha256_initial_hash_value[8] = { +static const sha2_word32 sha256_initial_hash_value[8] = { 0x6a09e667UL, 0xbb67ae85UL, 0x3c6ef372UL, @@ -208,7 +213,7 @@ const static sha2_word32 sha256_initial_hash_value[8] = { }; /* Hash constant words K for SHA-384 and SHA-512: */ -const static sha2_word64 K512[80] = { +static const sha2_word64 K512[80] = { 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL, 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, @@ -252,7 +257,7 @@ const static sha2_word64 K512[80] = { }; /* Initial hash value H for SHA-384 */ -const static sha2_word64 sha384_initial_hash_value[8] = { +static const sha2_word64 sha384_initial_hash_value[8] = { 0xcbbb9d5dc1059ed8ULL, 0x629a292a367cd507ULL, 0x9159015a3070dd17ULL, @@ -264,7 +269,7 @@ const static sha2_word64 sha384_initial_hash_value[8] = { }; /* Initial hash value H for SHA-512 */ -const static sha2_word64 sha512_initial_hash_value[8] = { +static const sha2_word64 sha512_initial_hash_value[8] = { 0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, 0x3c6ef372fe94f82bULL, @@ -548,7 +553,8 @@ void SHA256_Final(sha2_byte digest[], SHA256_CTX* context) { *context->buffer = 0x80; } /* Set the bit count: */ - *(sha2_word64*)&context->buffer[SHA256_SHORT_BLOCK_LENGTH] = context->bitcount; + sha2_word64 *t = (sha2_word64 *)&context->buffer[SHA256_SHORT_BLOCK_LENGTH]; + *t = context->bitcount; /* Final transform: */ SHA256_Transform(context, (sha2_word32*)context->buffer); @@ -866,8 +872,11 @@ void SHA512_Last(SHA512_CTX* context) { *context->buffer = 0x80; } /* Store the length of input data (in bits): */ - *(sha2_word64*)&context->buffer[SHA512_SHORT_BLOCK_LENGTH] = context->bitcount[1]; - *(sha2_word64*)&context->buffer[SHA512_SHORT_BLOCK_LENGTH+8] = context->bitcount[0]; + sha2_word64 *t; + t = (sha2_word64 *)&context->buffer[SHA512_SHORT_BLOCK_LENGTH]; + *t = context->bitcount[1]; + t = (sha2_word64 *)&context->buffer[SHA512_SHORT_BLOCK_LENGTH+8]; + *t = context->bitcount[0]; /* Final transform: */ SHA512_Transform(context, (sha2_word64*)context->buffer); diff --git a/speed-stm32/Makefile b/speed-stm32/Makefile index a26e62282..946e85564 100644 --- a/speed-stm32/Makefile +++ b/speed-stm32/Makefile @@ -1,8 +1,9 @@ NAME = speed -OBJS += aux.o +OBJS += bignum.o OBJS += ecdsa.o OBJS += rand.o OBJS += secp256k1.o -OBJS += sha256.o +OBJS += hmac.o +OBJS += sha2.o include Makefile.include diff --git a/speed-stm32/aux.c b/speed-stm32/aux.c deleted file mode 120000 index aced8d8ff..000000000 --- a/speed-stm32/aux.c +++ /dev/null @@ -1 +0,0 @@ -../aux.c \ No newline at end of file diff --git a/speed-stm32/aux.h b/speed-stm32/aux.h deleted file mode 120000 index cb12794d5..000000000 --- a/speed-stm32/aux.h +++ /dev/null @@ -1 +0,0 @@ -../aux.h \ No newline at end of file diff --git a/speed-stm32/bignum.c b/speed-stm32/bignum.c new file mode 120000 index 000000000..ae4e38c68 --- /dev/null +++ b/speed-stm32/bignum.c @@ -0,0 +1 @@ +../bignum.c \ No newline at end of file diff --git a/speed-stm32/bignum.h b/speed-stm32/bignum.h new file mode 120000 index 000000000..5efc7ca42 --- /dev/null +++ b/speed-stm32/bignum.h @@ -0,0 +1 @@ +../bignum.h \ No newline at end of file diff --git a/speed-stm32/hmac.c b/speed-stm32/hmac.c new file mode 120000 index 000000000..68437fdea --- /dev/null +++ b/speed-stm32/hmac.c @@ -0,0 +1 @@ +../hmac.c \ No newline at end of file diff --git a/speed-stm32/hmac.h b/speed-stm32/hmac.h new file mode 120000 index 000000000..10ae0cd97 --- /dev/null +++ b/speed-stm32/hmac.h @@ -0,0 +1 @@ +../hmac.h \ No newline at end of file diff --git a/speed-stm32/sha2.c b/speed-stm32/sha2.c new file mode 120000 index 000000000..8e8fb5a97 --- /dev/null +++ b/speed-stm32/sha2.c @@ -0,0 +1 @@ +../sha2.c \ No newline at end of file diff --git a/speed-stm32/sha2.h b/speed-stm32/sha2.h new file mode 120000 index 000000000..3eba17921 --- /dev/null +++ b/speed-stm32/sha2.h @@ -0,0 +1 @@ +../sha2.h \ No newline at end of file diff --git a/speed-stm32/sha256.c b/speed-stm32/sha256.c deleted file mode 120000 index 1068d4ffe..000000000 --- a/speed-stm32/sha256.c +++ /dev/null @@ -1 +0,0 @@ -../sha256.c \ No newline at end of file diff --git a/speed-stm32/sha256.h b/speed-stm32/sha256.h deleted file mode 120000 index d625aee2f..000000000 --- a/speed-stm32/sha256.h +++ /dev/null @@ -1 +0,0 @@ -../sha256.h \ No newline at end of file diff --git a/test-rfc6979.c b/test-rfc6979.c index 48c7d576c..b21519d65 100644 --- a/test-rfc6979.c +++ b/test-rfc6979.c @@ -21,6 +21,7 @@ */ #include +#include "bignum.h" #include "ecdsa.h" #include "sha2.h" @@ -29,7 +30,6 @@ uint8_t kb[32]; uint8_t priv[32] = {0xcc, 0xa9, 0xfb, 0xcc, 0x1b, 0x41, 0xe5, 0xa9, 0x5d, 0x36, 0x9e, 0xaa, 0x6d, 0xdc, 0xff, 0x73, 0xb6, 0x1a, 0x4e, 0xfa, 0xa2, 0x79, 0xcf, 0xc6, 0x56, 0x7e, 0x8d, 0xaa, 0x39, 0xcb, 0xaf, 0x50}; uint8_t hash[32]; -void write_32byte_big_endian(const bignum256 *in_number, uint8_t *out_number); void generate_k_rfc6979(bignum256 *k, const uint8_t *priv_key, const uint8_t *hash); int main() @@ -40,7 +40,7 @@ int main() printf("hash : "); for (i = 0; i < 32; i++) printf("%02x", hash[i]); printf("\n"); generate_k_rfc6979(&k, priv, hash); - write_32byte_big_endian(&k, kb); + bn_write_be(&k, kb); printf("expected : 2df40ca70e639d89528a6b670d9d48d9165fdc0febc0974056bdce192b8e16a3\n"); printf("got : "); From afc9bcfe30fb26ca3611486eaf2c08e75a7b3571 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 12 Sep 2013 19:21:24 +0200 Subject: [PATCH 021/627] implement bip32 - https://en.bitcoin.it/wiki/BIP_0032 --- .gitignore | 2 ++ Makefile | 12 ++++++--- bignum.c | 30 ++++++++++++++++----- bignum.h | 10 ++++--- bip32.c | 47 ++++++++++++++++++++++++++++++++ bip32.h | 22 +++++++++++++++ ecdsa.c | 16 ++++++++++- ecdsa.h | 3 ++- test-bip32.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++ test-pubkey.c | 58 ++++++++++++++++++++++++++++++++++++++++ test-verify.c | 2 +- 11 files changed, 260 insertions(+), 16 deletions(-) create mode 100644 bip32.c create mode 100644 bip32.h create mode 100644 test-bip32.c create mode 100644 test-pubkey.c diff --git a/.gitignore b/.gitignore index 96e561504..25ad0464d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ *.o +test-bip32 +test-pubkey test-rfc6979 test-speed test-verify diff --git a/Makefile b/Makefile index b790094a3..652a858e0 100644 --- a/Makefile +++ b/Makefile @@ -1,12 +1,18 @@ CC = gcc CFLAGS = -Wall -Os -OBJS = bignum.o ecdsa.o secp256k1.o sha2.o rand.o hmac.o +OBJS = bignum.o ecdsa.o secp256k1.o sha2.o rand.o hmac.o bip32.o -all: test-rfc6979 test-speed test-verify +all: test-bip32 test-pubkey test-rfc6979 test-speed test-verify %.o: %.c $(CC) $(CFLAGS) -o $@ -c $< +test-bip32: test-bip32.o $(OBJS) + gcc test-bip32.o $(OBJS) -o test-bip32 + +test-pubkey: test-pubkey.o $(OBJS) + gcc test-pubkey.o $(OBJS) -o test-pubkey + test-rfc6979: test-rfc6979.o $(OBJS) gcc test-rfc6979.o $(OBJS) -o test-rfc6979 @@ -17,4 +23,4 @@ test-verify: test-verify.o $(OBJS) gcc test-verify.o $(OBJS) -o test-verify -lcrypto clean: - rm -f $(OBJS) test-rfc6979 test-speed test-verify + rm -f *.o test-bip32 test-pubkey test-rfc6979 test-speed test-verify diff --git a/bignum.c b/bignum.c index d4b341fb2..6910153d4 100644 --- a/bignum.c +++ b/bignum.c @@ -83,8 +83,8 @@ int bn_is_less(const bignum256 *a, const bignum256 *b) return 0; } -// assumes x < 2*prime -void bn_mod(bignum256 *x, bignum256 const *prime) +// assumes x < 2*prime, result < prime +void bn_mod(bignum256 *x, const bignum256 *prime) { int i = 8; uint32_t temp; @@ -113,7 +113,7 @@ void bn_mod(bignum256 *x, bignum256 const *prime) // x = k * x // both inputs and result may be bigger than prime but not bigger than 2 * prime -void bn_multiply(const bignum256 *k, bignum256 *x, bignum256 const *prime) +void bn_multiply(const bignum256 *k, bignum256 *x, const bignum256 *prime) { int i, j; uint64_t temp = 0; @@ -157,7 +157,8 @@ void bn_multiply(const bignum256 *k, bignum256 *x, bignum256 const *prime) } } -void bn_fast_mod(bignum256 *x, bignum256 const *prime) +// result is smaller than 2*prime +void bn_fast_mod(bignum256 *x, const bignum256 *prime) { int j; uint32_t coef; @@ -182,7 +183,7 @@ void bn_fast_mod(bignum256 *x, bignum256 const *prime) #endif // in field G_prime, small but slow -void bn_inverse(bignum256 *x, bignum256 const *prime) +void bn_inverse(bignum256 *x, const bignum256 *prime) { uint32_t i, j, limb; bignum256 res; @@ -210,7 +211,7 @@ void bn_inverse(bignum256 *x, bignum256 const *prime) #else // in field G_prime, big but fast -void bn_inverse(bignum256 *x, bignum256 const *prime) +void bn_inverse(bignum256 *x, const bignum256 *prime) { int i, j, k, len1, len2, mask; uint32_t u[9], v[9], s[10], r[10], temp, temp2; @@ -382,6 +383,23 @@ void bn_inverse(bignum256 *x, bignum256 const *prime) } #endif + +void bn_addmod(bignum256 *a, const bignum256 *b, const bignum256 *prime) +{ + int i; + uint32_t carry = 0; + for (i = 0; i < 9; i++) { + a->val[i] += b->val[i] + carry; + if (a->val[i] > 0x3FFFFFFF) { + carry = a->val[i] >> 30; + a->val[i] &= 0x3FFFFFFF; + } else { + carry = 0; + } + } + bn_mod(a, prime); +} + // res = a - b // b < 2*prime; result not normalized void bn_substract(const bignum256 *a, const bignum256 *b, bignum256 *res) diff --git a/bignum.h b/bignum.h index 62a5f6e78..5a292f7ed 100644 --- a/bignum.h +++ b/bignum.h @@ -54,13 +54,15 @@ int bn_is_zero(const bignum256 *a); int bn_is_less(const bignum256 *a, const bignum256 *b); -void bn_mod(bignum256 *x, bignum256 const *prime); +void bn_mod(bignum256 *x, const bignum256 *prime); -void bn_multiply(const bignum256 *k, bignum256 *x, bignum256 const *prime); +void bn_multiply(const bignum256 *k, bignum256 *x, const bignum256 *prime); -void bn_fast_mod(bignum256 *x, bignum256 const *prime); +void bn_fast_mod(bignum256 *x, const bignum256 *prime); -void bn_inverse(bignum256 *x, bignum256 const *prime); +void bn_inverse(bignum256 *x, const bignum256 *prime); + +void bn_addmod(bignum256 *a, const bignum256 *b, const bignum256 *prime); void bn_substract(const bignum256 *a, const bignum256 *b, bignum256 *res); diff --git a/bip32.c b/bip32.c new file mode 100644 index 000000000..566a2d186 --- /dev/null +++ b/bip32.c @@ -0,0 +1,47 @@ +#include + +#include "bignum.h" +#include "hmac.h" +#include "ecdsa.h" +#include "bip32.h" + +void xprv_from_seed(uint8_t *seed, int seed_len, xprv *out) +{ + out->version = 0x0488ADE4; // main-net + out->depth = 0; + out->fingerprint = 0x00000000; + out->child_num = 0; + // this can be done because private_key[32] and chain_code[32] + // form a continuous 64 byte block in the memory + hmac_sha512((uint8_t *)"Bitcoin seed", 12, seed, seed_len, out->private_key); + ecdsa_get_public_key_compressed(out->private_key, out->public_key); +} + +void xprv_descent(xprv *inout, uint32_t i) +{ + uint8_t data[1 + 32 + 4]; + bignum256 a, b; + + if (i & 0x80000000) { + data[0] = 0; + memcpy(data + 1, inout->private_key, 32); + } else { + ecdsa_get_public_key_compressed(inout->private_key, data); + } + write_be(data + 33, i); + + bn_read_be(inout->private_key, &a); + + // this can be done because private_key[32] and chain_code[32] + // form a continuous 64 byte block in the memory + hmac_sha512(inout->chain_code, 32, data, sizeof(data), inout->private_key); + + bn_read_be(inout->private_key, &b); + bn_addmod(&a, &b, &order256k1); + + inout->depth++; + inout->child_num = i; + bn_write_be(&a, inout->private_key); + + ecdsa_get_public_key_compressed(inout->private_key, inout->public_key); +} diff --git a/bip32.h b/bip32.h new file mode 100644 index 000000000..497f244a6 --- /dev/null +++ b/bip32.h @@ -0,0 +1,22 @@ +#ifndef __BIP32_H__ +#define __BIP32_H__ + +#include + +typedef struct { + uint32_t version; + uint32_t depth; + uint32_t fingerprint; + uint32_t child_num; + uint8_t private_key[32]; // private_key + chain_code have to + uint8_t chain_code[32]; // form a continuous 64 byte block + uint8_t public_key[33]; +} xprv; + +void xprv_from_seed(uint8_t *seed, int seed_len, xprv *out); + +#define xprv_descent_prime(X, I) xprv_descent((X), ((I) | 0x80000000)) + +void xprv_descent(xprv *inout, uint32_t i); + +#endif diff --git a/ecdsa.c b/ecdsa.c index 4757f733e..7b33d9222 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -306,7 +306,7 @@ void ecdsa_sign(const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, u // uses secp256k1 curve // priv_key is a 32 byte big endian stored number // pub_key is at least 70 bytes long array for the public key -void ecdsa_get_public_key(const uint8_t *priv_key, uint8_t *pub_key, uint32_t *pub_key_len) +void ecdsa_get_public_key_der(const uint8_t *priv_key, uint8_t *pub_key, uint32_t *pub_key_len) { uint32_t i; curve_point R; @@ -324,6 +324,20 @@ void ecdsa_get_public_key(const uint8_t *priv_key, uint8_t *pub_key, uint32_t *p *pub_key_len = i + 2; } + +// pub_key is always 33 bytes long +void ecdsa_get_public_key_compressed(const uint8_t *priv_key, uint8_t *pub_key) +{ + curve_point R; + bignum256 k; + + bn_read_be(priv_key, &k); + // compute k*G + scalar_multiply(&k, &R); + pub_key[0] = 0x02 | (R.y.val[0] & 0x01); + bn_write_be(&R.x, pub_key + 1); +} + // uses secp256k1 curve // pub_key and signature are DER encoded // msg is a data that was signed diff --git a/ecdsa.h b/ecdsa.h index f993fde08..77def1712 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -30,7 +30,8 @@ // all functions use secp256k1 curve void ecdsa_sign(const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint32_t *sig_len); -void ecdsa_get_public_key(const uint8_t *priv_key, uint8_t *pub_key, uint32_t *pub_key_len); +void ecdsa_get_public_key_der(const uint8_t *priv_key, uint8_t *pub_key, uint32_t *pub_key_len); +void ecdsa_get_public_key_compressed(const uint8_t *priv_key, uint8_t *pub_key); int ecdsa_verify(const uint8_t *pub_key, const uint8_t *signature, const uint8_t *msg, uint32_t msg_len); #endif diff --git a/test-bip32.c b/test-bip32.c new file mode 100644 index 000000000..3d01e06d0 --- /dev/null +++ b/test-bip32.c @@ -0,0 +1,74 @@ +/** + * Copyright (c) 2013 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include + +#include "bip32.h" + +// test vectors from https://en.bitcoin.it/wiki/BIP_0032_TestVectors + +void xprv_print(xprv *in) +{ + int i; + + printf("chain : "); for (i = 0; i < 32; i++) printf("%02x", in->chain_code[i]); printf("\n"); + printf("priv : "); for (i = 0; i < 32; i++) printf("%02x", in->private_key[i]); printf("\n"); + printf("pub : "); for (i = 0; i < 33; i++) printf("%02x", in->public_key[i]); printf("\n"); + printf("\n"); +} + +int main() +{ + xprv node; + + xprv_from_seed((uint8_t *)"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", 16, &node); + + printf("[Chain m] got\n"); + xprv_print(&node); + printf("[Chain m] expected\n"); + printf("chain : 873dff81c02f525623fd1fe5167eac3a55a049de3d314bb42ee227ffed37d508\n"); + printf("priv : e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35\n"); + printf("pub : 0339a36013301597daef41fbe593a02cc513d0b55527ec2df1050e2e8ff49c85c2\n"); + printf("\n"); + + xprv_descent_prime(&node, 0); + + printf("[Chain m/0'] got\n"); + xprv_print(&node); + printf("[Chain m/0'] expected\n"); + printf("chain : 47fdacbd0f1097043b78c63c20c34ef4ed9a111d980047ad16282c7ae6236141\n"); + printf("priv : edb2e14f9ee77d26dd93b4ecede8d16ed408ce149b6cd80b0715a2d911a0afea\n"); + printf("pub : 035a784662a4a20a65bf6aab9ae98a6c068a81c52e4b032c0fb5400c706cfccc56\n"); + printf("\n"); + + xprv_descent(&node, 1); + + printf("[Chain m/0'/1] got\n"); + xprv_print(&node); + printf("[Chain m/0'/1] expected\n"); + printf("chain : 2a7857631386ba23dacac34180dd1983734e444fdbf774041578e9b6adb37c19\n"); + printf("priv : 3c6cb8d0f6a264c91ea8b5030fadaa8e538b020f0a387421a12de9319dc93368\n"); + printf("pub : 03501e454bf00751f24b1b489aa925215d66af2234e3891c3b21a52bedb3cd711c\n"); + printf("\n"); + + return 0; +} diff --git a/test-pubkey.c b/test-pubkey.c new file mode 100644 index 000000000..28797e475 --- /dev/null +++ b/test-pubkey.c @@ -0,0 +1,58 @@ +/** + * Copyright (c) 2013 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include "ecdsa.h" + +// vectors from https://en.bitcoin.it/wiki/BIP_0032_TestVectors + +const char *privs[] = { +"\xe8\xf3\x2e\x72\x3d\xec\xf4\x05\x1a\xef\xac\x8e\x2c\x93\xc9\xc5\xb2\x14\x31\x38\x17\xcd\xb0\x1a\x14\x94\xb9\x17\xc8\x43\x6b\x35", +"\xed\xb2\xe1\x4f\x9e\xe7\x7d\x26\xdd\x93\xb4\xec\xed\xe8\xd1\x6e\xd4\x08\xce\x14\x9b\x6c\xd8\x0b\x07\x15\xa2\xd9\x11\xa0\xaf\xea", +"\x3c\x6c\xb8\xd0\xf6\xa2\x64\xc9\x1e\xa8\xb5\x03\x0f\xad\xaa\x8e\x53\x8b\x02\x0f\x0a\x38\x74\x21\xa1\x2d\xe9\x31\x9d\xc9\x33\x68", +"\xcb\xce\x0d\x71\x9e\xcf\x74\x31\xd8\x8e\x6a\x89\xfa\x14\x83\xe0\x2e\x35\x09\x2a\xf6\x0c\x04\x2b\x1d\xf2\xff\x59\xfa\x42\x4d\xca", +"\x0f\x47\x92\x45\xfb\x19\xa3\x8a\x19\x54\xc5\xc7\xc0\xeb\xab\x2f\x9b\xdf\xd9\x6a\x17\x56\x3e\xf2\x8a\x6a\x4b\x1a\x2a\x76\x4e\xf4", +"\x47\x1b\x76\xe3\x89\xe5\x28\xd6\xde\x6d\x81\x68\x57\xe0\x12\xc5\x45\x50\x51\xca\xd6\x66\x08\x50\xe5\x83\x72\xa6\xc3\xe6\xe7\xc8", +}; + +const char *pubs[] = { +"0339a36013301597daef41fbe593a02cc513d0b55527ec2df1050e2e8ff49c85c2", +"035a784662a4a20a65bf6aab9ae98a6c068a81c52e4b032c0fb5400c706cfccc56", +"03501e454bf00751f24b1b489aa925215d66af2234e3891c3b21a52bedb3cd711c", +"0357bfe1e341d01c69fe5654309956cbea516822fba8a601743a012a7896ee8dc2", +"02e8445082a72f29b75ca48748a914df60622a609cacfce8ed0e35804560741d29", +"022a471424da5e657499d1ff51cb43c47481a03b1e77f951fe64cec9f5a48f7011", +}; + +int main() +{ + int i, k; + uint8_t pub[33]; + + for (k = 0; k < 6; k++) { + ecdsa_get_public_key_compressed((uint8_t *)privs[k], pub); + printf("got : "); for (i = 0; i < 33; i++) printf("%02x", pub[i]); printf("\n"); + printf("expected : %s\n", pubs[k]); + } + + return 0; +} diff --git a/test-verify.c b/test-verify.c index 4bb4e52e3..cd894c305 100644 --- a/test-verify.c +++ b/test-verify.c @@ -78,7 +78,7 @@ int main() ecdsa_sign(priv_key, msg, msg_len, sig, &sig_len); // generate public key from private key - ecdsa_get_public_key(priv_key, pub_key, &pub_key_len); + ecdsa_get_public_key_der(priv_key, pub_key, &pub_key_len); // use our ECDSA verifier to verify the message signature if (ecdsa_verify(pub_key, sig, msg, msg_len) != 0) { From 65250325c41bdd3487ccab596183603e03decf86 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 16 Sep 2013 01:32:56 +0200 Subject: [PATCH 022/627] add ripemd160 --- Makefile | 2 +- ripemd160.c | 307 ++++++++++++++++++++++++++++++++++++++++++++++++++++ ripemd160.h | 8 ++ 3 files changed, 316 insertions(+), 1 deletion(-) create mode 100644 ripemd160.c create mode 100644 ripemd160.h diff --git a/Makefile b/Makefile index 652a858e0..3d96dcb29 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ CC = gcc CFLAGS = -Wall -Os -OBJS = bignum.o ecdsa.o secp256k1.o sha2.o rand.o hmac.o bip32.o +OBJS = bignum.o ecdsa.o secp256k1.o sha2.o rand.o hmac.o bip32.o ripemd160.o all: test-bip32 test-pubkey test-rfc6979 test-speed test-verify diff --git a/ripemd160.c b/ripemd160.c new file mode 100644 index 000000000..f6b849b8b --- /dev/null +++ b/ripemd160.c @@ -0,0 +1,307 @@ +#include + +#include "ripemd160.h" + +#define ROL(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + +#define F(x, y, z) ((x) ^ (y) ^ (z)) +#define G(x, y, z) (((x) & (y)) | (~(x) & (z))) +#define H(x, y, z) (((x) | ~(y)) ^ (z)) +#define IQ(x, y, z) (((x) & (z)) | ((y) & ~(z))) +#define J(x, y, z) ((x) ^ ((y) | ~(z))) + +#define FF(a, b, c, d, e, x, s) {\ + (a) += F((b), (c), (d)) + (x);\ + (a) = ROL((a), (s)) + (e);\ + (c) = ROL((c), 10);\ + } +#define GG(a, b, c, d, e, x, s) {\ + (a) += G((b), (c), (d)) + (x) + 0x5a827999UL;\ + (a) = ROL((a), (s)) + (e);\ + (c) = ROL((c), 10);\ + } +#define HH(a, b, c, d, e, x, s) {\ + (a) += H((b), (c), (d)) + (x) + 0x6ed9eba1UL;\ + (a) = ROL((a), (s)) + (e);\ + (c) = ROL((c), 10);\ + } +#define II(a, b, c, d, e, x, s) {\ + (a) += IQ((b), (c), (d)) + (x) + 0x8f1bbcdcUL;\ + (a) = ROL((a), (s)) + (e);\ + (c) = ROL((c), 10);\ + } +#define JJ(a, b, c, d, e, x, s) {\ + (a) += J((b), (c), (d)) + (x) + 0xa953fd4eUL;\ + (a) = ROL((a), (s)) + (e);\ + (c) = ROL((c), 10);\ + } +#define FFF(a, b, c, d, e, x, s) {\ + (a) += F((b), (c), (d)) + (x);\ + (a) = ROL((a), (s)) + (e);\ + (c) = ROL((c), 10);\ + } +#define GGG(a, b, c, d, e, x, s) {\ + (a) += G((b), (c), (d)) + (x) + 0x7a6d76e9UL;\ + (a) = ROL((a), (s)) + (e);\ + (c) = ROL((c), 10);\ + } +#define HHH(a, b, c, d, e, x, s) {\ + (a) += H((b), (c), (d)) + (x) + 0x6d703ef3UL;\ + (a) = ROL((a), (s)) + (e);\ + (c) = ROL((c), 10);\ + } +#define III(a, b, c, d, e, x, s) {\ + (a) += IQ((b), (c), (d)) + (x) + 0x5c4dd124UL;\ + (a) = ROL((a), (s)) + (e);\ + (c) = ROL((c), 10);\ + } +#define JJJ(a, b, c, d, e, x, s) {\ + (a) += J((b), (c), (d)) + (x) + 0x50a28be6UL;\ + (a) = ROL((a), (s)) + (e);\ + (c) = ROL((c), 10);\ + } + + +static void compress(uint32_t *MDbuf, uint32_t *X); + + +static void compress(uint32_t *MDbuf, uint32_t *X) +{ + uint32_t aa = MDbuf[0], bb = MDbuf[1], cc = MDbuf[2], dd = MDbuf[3], ee = MDbuf[4]; + uint32_t aaa = MDbuf[0], bbb = MDbuf[1], ccc = MDbuf[2], ddd = MDbuf[3], eee = MDbuf[4]; + + /* round 1 */ + FF(aa, bb, cc, dd, ee, X[ 0], 11); + FF(ee, aa, bb, cc, dd, X[ 1], 14); + FF(dd, ee, aa, bb, cc, X[ 2], 15); + FF(cc, dd, ee, aa, bb, X[ 3], 12); + FF(bb, cc, dd, ee, aa, X[ 4], 5); + FF(aa, bb, cc, dd, ee, X[ 5], 8); + FF(ee, aa, bb, cc, dd, X[ 6], 7); + FF(dd, ee, aa, bb, cc, X[ 7], 9); + FF(cc, dd, ee, aa, bb, X[ 8], 11); + FF(bb, cc, dd, ee, aa, X[ 9], 13); + FF(aa, bb, cc, dd, ee, X[10], 14); + FF(ee, aa, bb, cc, dd, X[11], 15); + FF(dd, ee, aa, bb, cc, X[12], 6); + FF(cc, dd, ee, aa, bb, X[13], 7); + FF(bb, cc, dd, ee, aa, X[14], 9); + FF(aa, bb, cc, dd, ee, X[15], 8); + + /* round 2 */ + GG(ee, aa, bb, cc, dd, X[ 7], 7); + GG(dd, ee, aa, bb, cc, X[ 4], 6); + GG(cc, dd, ee, aa, bb, X[13], 8); + GG(bb, cc, dd, ee, aa, X[ 1], 13); + GG(aa, bb, cc, dd, ee, X[10], 11); + GG(ee, aa, bb, cc, dd, X[ 6], 9); + GG(dd, ee, aa, bb, cc, X[15], 7); + GG(cc, dd, ee, aa, bb, X[ 3], 15); + GG(bb, cc, dd, ee, aa, X[12], 7); + GG(aa, bb, cc, dd, ee, X[ 0], 12); + GG(ee, aa, bb, cc, dd, X[ 9], 15); + GG(dd, ee, aa, bb, cc, X[ 5], 9); + GG(cc, dd, ee, aa, bb, X[ 2], 11); + GG(bb, cc, dd, ee, aa, X[14], 7); + GG(aa, bb, cc, dd, ee, X[11], 13); + GG(ee, aa, bb, cc, dd, X[ 8], 12); + + /* round 3 */ + HH(dd, ee, aa, bb, cc, X[ 3], 11); + HH(cc, dd, ee, aa, bb, X[10], 13); + HH(bb, cc, dd, ee, aa, X[14], 6); + HH(aa, bb, cc, dd, ee, X[ 4], 7); + HH(ee, aa, bb, cc, dd, X[ 9], 14); + HH(dd, ee, aa, bb, cc, X[15], 9); + HH(cc, dd, ee, aa, bb, X[ 8], 13); + HH(bb, cc, dd, ee, aa, X[ 1], 15); + HH(aa, bb, cc, dd, ee, X[ 2], 14); + HH(ee, aa, bb, cc, dd, X[ 7], 8); + HH(dd, ee, aa, bb, cc, X[ 0], 13); + HH(cc, dd, ee, aa, bb, X[ 6], 6); + HH(bb, cc, dd, ee, aa, X[13], 5); + HH(aa, bb, cc, dd, ee, X[11], 12); + HH(ee, aa, bb, cc, dd, X[ 5], 7); + HH(dd, ee, aa, bb, cc, X[12], 5); + + /* round 4 */ + II(cc, dd, ee, aa, bb, X[ 1], 11); + II(bb, cc, dd, ee, aa, X[ 9], 12); + II(aa, bb, cc, dd, ee, X[11], 14); + II(ee, aa, bb, cc, dd, X[10], 15); + II(dd, ee, aa, bb, cc, X[ 0], 14); + II(cc, dd, ee, aa, bb, X[ 8], 15); + II(bb, cc, dd, ee, aa, X[12], 9); + II(aa, bb, cc, dd, ee, X[ 4], 8); + II(ee, aa, bb, cc, dd, X[13], 9); + II(dd, ee, aa, bb, cc, X[ 3], 14); + II(cc, dd, ee, aa, bb, X[ 7], 5); + II(bb, cc, dd, ee, aa, X[15], 6); + II(aa, bb, cc, dd, ee, X[14], 8); + II(ee, aa, bb, cc, dd, X[ 5], 6); + II(dd, ee, aa, bb, cc, X[ 6], 5); + II(cc, dd, ee, aa, bb, X[ 2], 12); + + /* round 5 */ + JJ(bb, cc, dd, ee, aa, X[ 4], 9); + JJ(aa, bb, cc, dd, ee, X[ 0], 15); + JJ(ee, aa, bb, cc, dd, X[ 5], 5); + JJ(dd, ee, aa, bb, cc, X[ 9], 11); + JJ(cc, dd, ee, aa, bb, X[ 7], 6); + JJ(bb, cc, dd, ee, aa, X[12], 8); + JJ(aa, bb, cc, dd, ee, X[ 2], 13); + JJ(ee, aa, bb, cc, dd, X[10], 12); + JJ(dd, ee, aa, bb, cc, X[14], 5); + JJ(cc, dd, ee, aa, bb, X[ 1], 12); + JJ(bb, cc, dd, ee, aa, X[ 3], 13); + JJ(aa, bb, cc, dd, ee, X[ 8], 14); + JJ(ee, aa, bb, cc, dd, X[11], 11); + JJ(dd, ee, aa, bb, cc, X[ 6], 8); + JJ(cc, dd, ee, aa, bb, X[15], 5); + JJ(bb, cc, dd, ee, aa, X[13], 6); + + /* parallel round 1 */ + JJJ(aaa, bbb, ccc, ddd, eee, X[ 5], 8); + JJJ(eee, aaa, bbb, ccc, ddd, X[14], 9); + JJJ(ddd, eee, aaa, bbb, ccc, X[ 7], 9); + JJJ(ccc, ddd, eee, aaa, bbb, X[ 0], 11); + JJJ(bbb, ccc, ddd, eee, aaa, X[ 9], 13); + JJJ(aaa, bbb, ccc, ddd, eee, X[ 2], 15); + JJJ(eee, aaa, bbb, ccc, ddd, X[11], 15); + JJJ(ddd, eee, aaa, bbb, ccc, X[ 4], 5); + JJJ(ccc, ddd, eee, aaa, bbb, X[13], 7); + JJJ(bbb, ccc, ddd, eee, aaa, X[ 6], 7); + JJJ(aaa, bbb, ccc, ddd, eee, X[15], 8); + JJJ(eee, aaa, bbb, ccc, ddd, X[ 8], 11); + JJJ(ddd, eee, aaa, bbb, ccc, X[ 1], 14); + JJJ(ccc, ddd, eee, aaa, bbb, X[10], 14); + JJJ(bbb, ccc, ddd, eee, aaa, X[ 3], 12); + JJJ(aaa, bbb, ccc, ddd, eee, X[12], 6); + + /* parallel round 2 */ + III(eee, aaa, bbb, ccc, ddd, X[ 6], 9); + III(ddd, eee, aaa, bbb, ccc, X[11], 13); + III(ccc, ddd, eee, aaa, bbb, X[ 3], 15); + III(bbb, ccc, ddd, eee, aaa, X[ 7], 7); + III(aaa, bbb, ccc, ddd, eee, X[ 0], 12); + III(eee, aaa, bbb, ccc, ddd, X[13], 8); + III(ddd, eee, aaa, bbb, ccc, X[ 5], 9); + III(ccc, ddd, eee, aaa, bbb, X[10], 11); + III(bbb, ccc, ddd, eee, aaa, X[14], 7); + III(aaa, bbb, ccc, ddd, eee, X[15], 7); + III(eee, aaa, bbb, ccc, ddd, X[ 8], 12); + III(ddd, eee, aaa, bbb, ccc, X[12], 7); + III(ccc, ddd, eee, aaa, bbb, X[ 4], 6); + III(bbb, ccc, ddd, eee, aaa, X[ 9], 15); + III(aaa, bbb, ccc, ddd, eee, X[ 1], 13); + III(eee, aaa, bbb, ccc, ddd, X[ 2], 11); + + /* parallel round 3 */ + HHH(ddd, eee, aaa, bbb, ccc, X[15], 9); + HHH(ccc, ddd, eee, aaa, bbb, X[ 5], 7); + HHH(bbb, ccc, ddd, eee, aaa, X[ 1], 15); + HHH(aaa, bbb, ccc, ddd, eee, X[ 3], 11); + HHH(eee, aaa, bbb, ccc, ddd, X[ 7], 8); + HHH(ddd, eee, aaa, bbb, ccc, X[14], 6); + HHH(ccc, ddd, eee, aaa, bbb, X[ 6], 6); + HHH(bbb, ccc, ddd, eee, aaa, X[ 9], 14); + HHH(aaa, bbb, ccc, ddd, eee, X[11], 12); + HHH(eee, aaa, bbb, ccc, ddd, X[ 8], 13); + HHH(ddd, eee, aaa, bbb, ccc, X[12], 5); + HHH(ccc, ddd, eee, aaa, bbb, X[ 2], 14); + HHH(bbb, ccc, ddd, eee, aaa, X[10], 13); + HHH(aaa, bbb, ccc, ddd, eee, X[ 0], 13); + HHH(eee, aaa, bbb, ccc, ddd, X[ 4], 7); + HHH(ddd, eee, aaa, bbb, ccc, X[13], 5); + + /* parallel round 4 */ + GGG(ccc, ddd, eee, aaa, bbb, X[ 8], 15); + GGG(bbb, ccc, ddd, eee, aaa, X[ 6], 5); + GGG(aaa, bbb, ccc, ddd, eee, X[ 4], 8); + GGG(eee, aaa, bbb, ccc, ddd, X[ 1], 11); + GGG(ddd, eee, aaa, bbb, ccc, X[ 3], 14); + GGG(ccc, ddd, eee, aaa, bbb, X[11], 14); + GGG(bbb, ccc, ddd, eee, aaa, X[15], 6); + GGG(aaa, bbb, ccc, ddd, eee, X[ 0], 14); + GGG(eee, aaa, bbb, ccc, ddd, X[ 5], 6); + GGG(ddd, eee, aaa, bbb, ccc, X[12], 9); + GGG(ccc, ddd, eee, aaa, bbb, X[ 2], 12); + GGG(bbb, ccc, ddd, eee, aaa, X[13], 9); + GGG(aaa, bbb, ccc, ddd, eee, X[ 9], 12); + GGG(eee, aaa, bbb, ccc, ddd, X[ 7], 5); + GGG(ddd, eee, aaa, bbb, ccc, X[10], 15); + GGG(ccc, ddd, eee, aaa, bbb, X[14], 8); + + /* parallel round 5 */ + FFF(bbb, ccc, ddd, eee, aaa, X[12] , 8); + FFF(aaa, bbb, ccc, ddd, eee, X[15] , 5); + FFF(eee, aaa, bbb, ccc, ddd, X[10] , 12); + FFF(ddd, eee, aaa, bbb, ccc, X[ 4] , 9); + FFF(ccc, ddd, eee, aaa, bbb, X[ 1] , 12); + FFF(bbb, ccc, ddd, eee, aaa, X[ 5] , 5); + FFF(aaa, bbb, ccc, ddd, eee, X[ 8] , 14); + FFF(eee, aaa, bbb, ccc, ddd, X[ 7] , 6); + FFF(ddd, eee, aaa, bbb, ccc, X[ 6] , 8); + FFF(ccc, ddd, eee, aaa, bbb, X[ 2] , 13); + FFF(bbb, ccc, ddd, eee, aaa, X[13] , 6); + FFF(aaa, bbb, ccc, ddd, eee, X[14] , 5); + FFF(eee, aaa, bbb, ccc, ddd, X[ 0] , 15); + FFF(ddd, eee, aaa, bbb, ccc, X[ 3] , 13); + FFF(ccc, ddd, eee, aaa, bbb, X[ 9] , 11); + FFF(bbb, ccc, ddd, eee, aaa, X[11] , 11); + + /* combine results */ + ddd += cc + MDbuf[1]; + MDbuf[1] = MDbuf[2] + dd + eee; + MDbuf[2] = MDbuf[3] + ee + aaa; + MDbuf[3] = MDbuf[4] + aa + bbb; + MDbuf[4] = MDbuf[0] + bb + ccc; + MDbuf[0] = ddd; +} + +void ripemd160(const uint8_t *msg, uint32_t msg_len, uint8_t *hash) +{ + uint32_t i; + int j; + uint32_t digest[5] = {0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0UL}; + + for (i = 0; i < (msg_len >> 6); ++i) { + uint32_t chunk[16]; + + for (j = 0; j < 16; ++j) { + chunk[j] = (uint32_t)(*(msg++)); + chunk[j] |= (uint32_t)(*(msg++)) << 8; + chunk[j] |= (uint32_t)(*(msg++)) << 16; + chunk[j] |= (uint32_t)(*(msg++)) << 24; + } + + compress (digest, chunk); + } + + // Last chunk + { + uint32_t chunk[16] = {0}; + + for (i = 0; i < (msg_len & 63); ++i) { + chunk[i >> 2] ^= (uint32_t) *msg++ << ((i&3) << 3); + } + + chunk[(msg_len >> 2)&15] ^= (uint32_t)1 << (8*(msg_len&3) + 7); + + if ((msg_len & 63) > 55) { + compress (digest, chunk); + memset (chunk, 0, 64); + } + + chunk[14] = msg_len << 3; + chunk[15] = (msg_len >> 29); + compress (digest, chunk); + } + + for (i = 0; i < 5; ++i) { + *(hash++) = digest[i]; + *(hash++) = digest[i] >> 8; + *(hash++) = digest[i] >> 16; + *(hash++) = digest[i] >> 24; + } +} diff --git a/ripemd160.h b/ripemd160.h new file mode 100644 index 000000000..2c634f16c --- /dev/null +++ b/ripemd160.h @@ -0,0 +1,8 @@ +#ifndef __RIPEMD160_H__ +#define __RIPEMD160_H__ + +#include + +void ripemd160(const uint8_t *msg, uint32_t msg_len, uint8_t *hash); + +#endif From 1fda6fe339b3683798216df8c39c20527f7a785b Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 19 Sep 2013 02:54:10 +0200 Subject: [PATCH 023/627] add bn_zero, bn_bits, bn_lshift, bn_rshift, bn_normalize to bignum --- bignum.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++---------- bignum.h | 10 ++++++++++ 2 files changed, 60 insertions(+), 11 deletions(-) diff --git a/bignum.c b/bignum.c index 6910153d4..5abb47f1d 100644 --- a/bignum.c +++ b/bignum.c @@ -64,6 +64,14 @@ void bn_write_be(const bignum256 *in_number, uint8_t *out_number) } } +void bn_zero(bignum256 *a) +{ + int i; + for (i = 0; i < 9; i++) { + a->val[i] = 0; + } +} + int bn_is_zero(const bignum256 *a) { int i; @@ -83,6 +91,34 @@ int bn_is_less(const bignum256 *a, const bignum256 *b) return 0; } +int bn_bits(const bignum256 *a) { + int i, r = 0; + for (i = 0; i < 256; i++) { + if (a->val[i / 30] & (1 << (i % 30))) { + r = i; + } + } + return r; +} + +void bn_lshift(bignum256 *a) +{ + int i; + for (i = 8; i > 0; i--) { + a->val[i] = ((a->val[i] << 1) & 0x3FFFFFFF) | ((a->val[i - 1] & 0x20000000) >> 29); + } + a->val[0] = (a->val[0] << 1) & 0x3FFFFFFF; +} + +void bn_rshift(bignum256 *a) +{ + int i; + for (i = 0; i < 8; i++) { + a->val[i] = (a->val[i] >> 1) | ((a->val[i + 1] & 1) << 29); + } + a->val[8] >>= 1; +} + // assumes x < 2*prime, result < prime void bn_mod(bignum256 *x, const bignum256 *prime) { @@ -93,9 +129,7 @@ void bn_mod(bignum256 *x, const bignum256 *prime) // if equal if (i == -1) { // set x to zero - for (i = 0; i < 9; i++) { - x->val[i] = 0; - } + bn_zero(x); } else { // if x is greater if (x->val[i] > prime->val[i]) { @@ -188,9 +222,7 @@ void bn_inverse(bignum256 *x, const bignum256 *prime) uint32_t i, j, limb; bignum256 res; res.val[0] = 1; - for (i = 1; i < 9; i++) { - res.val[i] = 0; - } + bn_zero(&res); for (i = 0; i < 9; i++) { limb = prime->val[i]; // this is not enough in general but fine for secp256k1 because prime->val[0] > 1 @@ -383,13 +415,11 @@ void bn_inverse(bignum256 *x, const bignum256 *prime) } #endif - -void bn_addmod(bignum256 *a, const bignum256 *b, const bignum256 *prime) -{ +void bn_normalize(bignum256 *a) { int i; uint32_t carry = 0; for (i = 0; i < 9; i++) { - a->val[i] += b->val[i] + carry; + a->val[i] += carry; if (a->val[i] > 0x3FFFFFFF) { carry = a->val[i] >> 30; a->val[i] &= 0x3FFFFFFF; @@ -397,6 +427,15 @@ void bn_addmod(bignum256 *a, const bignum256 *b, const bignum256 *prime) carry = 0; } } +} + +void bn_addmod(bignum256 *a, const bignum256 *b, const bignum256 *prime) +{ + int i; + for (i = 0; i < 9; i++) { + a->val[i] += b->val[i]; + } + bn_normalize(a); bn_mod(a, prime); } @@ -407,7 +446,7 @@ void bn_substract(const bignum256 *a, const bignum256 *b, bignum256 *res) int i; uint32_t temp = 0; for (i = 0; i < 9; i++) { - temp += a->val[i] + 2u *prime256k1.val[i] - b->val[i]; + temp += a->val[i] + 2u * prime256k1.val[i] - b->val[i]; res->val[i] = temp & 0x3FFFFFFF; temp >>= 30; } diff --git a/bignum.h b/bignum.h index 5a292f7ed..0e5106f77 100644 --- a/bignum.h +++ b/bignum.h @@ -50,10 +50,18 @@ void bn_read_be(const uint8_t *in_number, bignum256 *out_number); void bn_write_be(const bignum256 *in_number, uint8_t *out_number); +void bn_zero(bignum256 *a); + int bn_is_zero(const bignum256 *a); int bn_is_less(const bignum256 *a, const bignum256 *b); +int bn_bits(const bignum256 *a); + +void bn_lshift(bignum256 *a); + +void bn_rshift(bignum256 *a); + void bn_mod(bignum256 *x, const bignum256 *prime); void bn_multiply(const bignum256 *k, bignum256 *x, const bignum256 *prime); @@ -62,6 +70,8 @@ void bn_fast_mod(bignum256 *x, const bignum256 *prime); void bn_inverse(bignum256 *x, const bignum256 *prime); +void bn_normalize(bignum256 *a); + void bn_addmod(bignum256 *a, const bignum256 *b, const bignum256 *prime); void bn_substract(const bignum256 *a, const bignum256 *b, bignum256 *res); From 92f070498fdd4f9bb303a8b400d509e1833727be Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 19 Sep 2013 14:52:52 +0200 Subject: [PATCH 024/627] add function for computing addresses --- Makefile | 2 +- bignum.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++- bignum.h | 8 ++++++- bip32.c | 2 ++ bip32.h | 1 + ecdsa.c | 48 +++++++++++++++++++++++++++++++++++++ ecdsa.h | 1 + test-bip32.c | 4 ++++ 8 files changed, 131 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 3d96dcb29..4e94b2f69 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ OBJS = bignum.o ecdsa.o secp256k1.o sha2.o rand.o hmac.o bip32.o ripemd160.o all: test-bip32 test-pubkey test-rfc6979 test-speed test-verify -%.o: %.c +%.o: %.c %.h $(CC) $(CFLAGS) -o $@ -c $< test-bip32: test-bip32.o $(OBJS) diff --git a/bignum.c b/bignum.c index 5abb47f1d..37b60e8f4 100644 --- a/bignum.c +++ b/bignum.c @@ -21,6 +21,7 @@ * OTHER DEALINGS IN THE SOFTWARE. */ +#include #include "bignum.h" #include "secp256k1.h" @@ -91,7 +92,7 @@ int bn_is_less(const bignum256 *a, const bignum256 *b) return 0; } -int bn_bits(const bignum256 *a) { +int bn_bitlen(const bignum256 *a) { int i, r = 0; for (i = 0; i < 256; i++) { if (a->val[i / 30] & (1 << (i % 30))) { @@ -451,3 +452,68 @@ void bn_substract(const bignum256 *a, const bignum256 *b, bignum256 *res) temp >>= 30; } } + +// res = a - b ; a > b +void bn_substract_noprime(const bignum256 *a, const bignum256 *b, bignum256 *res) +{ + int i; + char carry = 0; + for (i = 0; i < 8; i++) { + if (a->val[i] >= b->val[i] + carry) { + res->val[i] = a->val[i] - b->val[i] - carry; + carry = 0; + } else { + res->val[i] = a->val[i] + 0x40000000 - b->val[i]; + carry = 1; + } + } + res->val[8] = a->val[8] - b->val[8] - carry; +} + +// a / 58 = q (+r) +void bn_divmod58(const bignum256 *a, bignum256 *q, uint32_t *r) +{ + bignum256 i58, rem; + int na, i; + + bn_zero(q); + bn_zero(&i58); i58.val[0] = 58; + + if (bn_is_less(a, &i58)) { + *r = a->val[0]; + } + + na = bn_bitlen(a); + + for (i = 0; i < 9; i++) { + rem.val[i] = a->val[i]; + } + + for (i = 0; i <= na - 6; i++) { + bn_lshift(&i58); + } + + for (i = na - 5; i >= 0; --i) { + bn_lshift(q); + if (!bn_is_less(&rem, &i58)) { + bn_substract_noprime(&rem, &i58, &rem); + q->val[0] |= 1; + } + bn_rshift(&i58); + } + + *r = rem.val[0]; +} + +void bn_print(const bignum256 *a) +{ + printf("%04x", a->val[8] & 0x0000FFFF); + printf("%08x", (a->val[7] << 2) | ((a->val[6] & 0x30000000) >> 28)); + printf("%07x", a->val[6] & 0x0FFFFFFF); + printf("%08x", (a->val[5] << 2) | ((a->val[4] & 0x30000000) >> 28)); + printf("%07x", a->val[4] & 0x0FFFFFFF); + printf("%08x", (a->val[3] << 2) | ((a->val[2] & 0x30000000) >> 28)); + printf("%07x", a->val[2] & 0x0FFFFFFF); + printf("%08x", (a->val[1] << 2) | ((a->val[0] & 0x30000000) >> 28)); + printf("%07x", a->val[0] & 0x0FFFFFFF); +} diff --git a/bignum.h b/bignum.h index 0e5106f77..6a59c4122 100644 --- a/bignum.h +++ b/bignum.h @@ -56,7 +56,7 @@ int bn_is_zero(const bignum256 *a); int bn_is_less(const bignum256 *a, const bignum256 *b); -int bn_bits(const bignum256 *a); +int bn_bitlen(const bignum256 *a); void bn_lshift(bignum256 *a); @@ -76,4 +76,10 @@ void bn_addmod(bignum256 *a, const bignum256 *b, const bignum256 *prime); void bn_substract(const bignum256 *a, const bignum256 *b, bignum256 *res); +void bn_substract_noprime(const bignum256 *a, const bignum256 *b, bignum256 *res); + +void bn_divmod58(const bignum256 *a, bignum256 *q, uint32_t *r); + +void bn_print(const bignum256 *a); + #endif diff --git a/bip32.c b/bip32.c index 566a2d186..a0ba5361c 100644 --- a/bip32.c +++ b/bip32.c @@ -15,6 +15,7 @@ void xprv_from_seed(uint8_t *seed, int seed_len, xprv *out) // form a continuous 64 byte block in the memory hmac_sha512((uint8_t *)"Bitcoin seed", 12, seed, seed_len, out->private_key); ecdsa_get_public_key_compressed(out->private_key, out->public_key); + ecdsa_get_address(out->public_key, 0, out->address); } void xprv_descent(xprv *inout, uint32_t i) @@ -44,4 +45,5 @@ void xprv_descent(xprv *inout, uint32_t i) bn_write_be(&a, inout->private_key); ecdsa_get_public_key_compressed(inout->private_key, inout->public_key); + ecdsa_get_address(inout->public_key, 0, inout->address); } diff --git a/bip32.h b/bip32.h index 497f244a6..a413575f3 100644 --- a/bip32.h +++ b/bip32.h @@ -11,6 +11,7 @@ typedef struct { uint8_t private_key[32]; // private_key + chain_code have to uint8_t chain_code[32]; // form a continuous 64 byte block uint8_t public_key[33]; + char address[35]; } xprv; void xprv_from_seed(uint8_t *seed, int seed_len, xprv *out); diff --git a/ecdsa.c b/ecdsa.c index 7b33d9222..acf7a518c 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -28,6 +28,7 @@ #include "bignum.h" #include "rand.h" #include "sha2.h" +#include "ripemd160.h" #include "hmac.h" #include "ecdsa.h" @@ -338,6 +339,53 @@ void ecdsa_get_public_key_compressed(const uint8_t *priv_key, uint8_t *pub_key) bn_write_be(&R.x, pub_key + 1); } +void ecdsa_get_address(const uint8_t *pub_key, char version, char *addr) +{ + const char code[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; + char *p = addr, s; + uint8_t a[32], b[21]; + uint32_t r; + bignum256 c, q; + int i, l; + + SHA256_Raw(pub_key, 33, a); + b[0] = version; + ripemd160(a, 32, b + 1); + + SHA256_Raw(b, 21, a); + SHA256_Raw(a, 32, a); + + memcpy(a + 28, a, 4); // checksum + memset(a, 0, 7); // zeroes + memcpy(a + 7, b, 21); // ripemd160(sha256(version + pubkey) + + bn_read_be(a, &c); + + while (!bn_is_zero(&c)) { + bn_divmod58(&c, &q, &r); + *p = code[r]; + p++; + for (i = 0; i < 9; i++) { + c.val[i] = q.val[i]; + } + } + + if (a[0] == 0) { + *p = '1'; + p++; + } + + *p = 0; + + l = strlen(addr); + + for (i = 0; i < l / 2; i++) { + s = addr[i]; + addr[i] = addr[l - 1 - i]; + addr[l - 1 - i] = s;; + } +} + // uses secp256k1 curve // pub_key and signature are DER encoded // msg is a data that was signed diff --git a/ecdsa.h b/ecdsa.h index 77def1712..f58a60dd7 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -32,6 +32,7 @@ void ecdsa_sign(const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint32_t *sig_len); void ecdsa_get_public_key_der(const uint8_t *priv_key, uint8_t *pub_key, uint32_t *pub_key_len); void ecdsa_get_public_key_compressed(const uint8_t *priv_key, uint8_t *pub_key); +void ecdsa_get_address(const uint8_t *pub_key, char version, char *addr); int ecdsa_verify(const uint8_t *pub_key, const uint8_t *signature, const uint8_t *msg, uint32_t msg_len); #endif diff --git a/test-bip32.c b/test-bip32.c index 3d01e06d0..261690b0f 100644 --- a/test-bip32.c +++ b/test-bip32.c @@ -33,6 +33,7 @@ void xprv_print(xprv *in) printf("chain : "); for (i = 0; i < 32; i++) printf("%02x", in->chain_code[i]); printf("\n"); printf("priv : "); for (i = 0; i < 32; i++) printf("%02x", in->private_key[i]); printf("\n"); printf("pub : "); for (i = 0; i < 33; i++) printf("%02x", in->public_key[i]); printf("\n"); + printf("addr : "); printf("%s\n", in->address); printf("\n"); } @@ -48,6 +49,7 @@ int main() printf("chain : 873dff81c02f525623fd1fe5167eac3a55a049de3d314bb42ee227ffed37d508\n"); printf("priv : e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35\n"); printf("pub : 0339a36013301597daef41fbe593a02cc513d0b55527ec2df1050e2e8ff49c85c2\n"); + printf("addr : 15mKKb2eos1hWa6tisdPwwDC1a5J1y9nma\n"); printf("\n"); xprv_descent_prime(&node, 0); @@ -58,6 +60,7 @@ int main() printf("chain : 47fdacbd0f1097043b78c63c20c34ef4ed9a111d980047ad16282c7ae6236141\n"); printf("priv : edb2e14f9ee77d26dd93b4ecede8d16ed408ce149b6cd80b0715a2d911a0afea\n"); printf("pub : 035a784662a4a20a65bf6aab9ae98a6c068a81c52e4b032c0fb5400c706cfccc56\n"); + printf("addr : 19Q2WoS5hSS6T8GjhK8KZLMgmWaq4neXrh\n"); printf("\n"); xprv_descent(&node, 1); @@ -68,6 +71,7 @@ int main() printf("chain : 2a7857631386ba23dacac34180dd1983734e444fdbf774041578e9b6adb37c19\n"); printf("priv : 3c6cb8d0f6a264c91ea8b5030fadaa8e538b020f0a387421a12de9319dc93368\n"); printf("pub : 03501e454bf00751f24b1b489aa925215d66af2234e3891c3b21a52bedb3cd711c\n"); + printf("addr : 1JQheacLPdM5ySCkrZkV66G2ApAXe1mqLj\n"); printf("\n"); return 0; From 638cf2310b63e8affe32c856d29e6c891f8b2415 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 20 Sep 2013 21:49:17 +0200 Subject: [PATCH 025/627] cleanup --- bignum.c | 14 ------ bignum.h | 2 - speed-stm32/Makefile | 19 ++++++--- speed-stm32/Makefile.include | 83 ++++++++++++++++++++++++++---------- speed-stm32/bignum.c | 1 - speed-stm32/bignum.h | 1 - speed-stm32/ecdsa.c | 1 - speed-stm32/ecdsa.h | 1 - speed-stm32/hmac.c | 1 - speed-stm32/hmac.h | 1 - speed-stm32/rand.h | 1 - speed-stm32/secp256k1.c | 1 - speed-stm32/secp256k1.h | 1 - speed-stm32/sha2.c | 1 - speed-stm32/sha2.h | 1 - 15 files changed, 73 insertions(+), 56 deletions(-) delete mode 120000 speed-stm32/bignum.c delete mode 120000 speed-stm32/bignum.h delete mode 120000 speed-stm32/ecdsa.c delete mode 120000 speed-stm32/ecdsa.h delete mode 120000 speed-stm32/hmac.c delete mode 120000 speed-stm32/hmac.h delete mode 120000 speed-stm32/rand.h delete mode 120000 speed-stm32/secp256k1.c delete mode 120000 speed-stm32/secp256k1.h delete mode 120000 speed-stm32/sha2.c delete mode 120000 speed-stm32/sha2.h diff --git a/bignum.c b/bignum.c index 37b60e8f4..0e438bdab 100644 --- a/bignum.c +++ b/bignum.c @@ -21,7 +21,6 @@ * OTHER DEALINGS IN THE SOFTWARE. */ -#include #include "bignum.h" #include "secp256k1.h" @@ -504,16 +503,3 @@ void bn_divmod58(const bignum256 *a, bignum256 *q, uint32_t *r) *r = rem.val[0]; } - -void bn_print(const bignum256 *a) -{ - printf("%04x", a->val[8] & 0x0000FFFF); - printf("%08x", (a->val[7] << 2) | ((a->val[6] & 0x30000000) >> 28)); - printf("%07x", a->val[6] & 0x0FFFFFFF); - printf("%08x", (a->val[5] << 2) | ((a->val[4] & 0x30000000) >> 28)); - printf("%07x", a->val[4] & 0x0FFFFFFF); - printf("%08x", (a->val[3] << 2) | ((a->val[2] & 0x30000000) >> 28)); - printf("%07x", a->val[2] & 0x0FFFFFFF); - printf("%08x", (a->val[1] << 2) | ((a->val[0] & 0x30000000) >> 28)); - printf("%07x", a->val[0] & 0x0FFFFFFF); -} diff --git a/bignum.h b/bignum.h index 6a59c4122..320451711 100644 --- a/bignum.h +++ b/bignum.h @@ -80,6 +80,4 @@ void bn_substract_noprime(const bignum256 *a, const bignum256 *b, bignum256 *res void bn_divmod58(const bignum256 *a, bignum256 *q, uint32_t *r); -void bn_print(const bignum256 *a); - #endif diff --git a/speed-stm32/Makefile b/speed-stm32/Makefile index 946e85564..94560dfe0 100644 --- a/speed-stm32/Makefile +++ b/speed-stm32/Makefile @@ -1,9 +1,16 @@ -NAME = speed -OBJS += bignum.o -OBJS += ecdsa.o +NAME = speed + OBJS += rand.o -OBJS += secp256k1.o -OBJS += hmac.o -OBJS += sha2.o +OBJS += speed.o + +OBJS += ../bignum.o +OBJS += ../bip32.o +OBJS += ../ecdsa.o +OBJS += ../hmac.o +OBJS += ../ripemd160.o +OBJS += ../secp256k1.o +OBJS += ../sha2.o include Makefile.include + +CFLAGS += -I.. diff --git a/speed-stm32/Makefile.include b/speed-stm32/Makefile.include index 26f52eb6a..cdf2b406d 100644 --- a/speed-stm32/Makefile.include +++ b/speed-stm32/Makefile.include @@ -1,30 +1,66 @@ -PREFIX ?= arm-none-eabi -CC = $(PREFIX)-gcc -LD = $(PREFIX)-gcc -OBJCOPY = $(PREFIX)-objcopy -OBJDUMP = $(PREFIX)-objdump -FLASH = $(shell which st-flash) - -TOOLCHAIN_DIR ?= ../../../STM/libopencm3 - -CFLAGS += -Os -g \ - -Wall -Wextra -Wimplicit-function-declaration -Wredundant-decls -Wstrict-prototypes -Wundef -Wshadow \ - -fno-common -mcpu=cortex-m3 -mthumb -msoft-float -MD -DSTM32F2 \ - -I$(TOOLCHAIN_DIR)/include -LDSCRIPT ?= $(NAME).ld -LDFLAGS += --static -Wl,--start-group -lc -lgcc -lnosys -Wl,--end-group \ - -L$(TOOLCHAIN_DIR)/lib -L$(TOOLCHAIN_DIR)/lib/stm32/f2 \ - -T$(LDSCRIPT) -nostartfiles -Wl,--gc-sections \ - -mthumb -march=armv7 -mfix-cortex-m3-ldrd -msoft-float -OBJS += $(NAME).o - -all: images - -images: $(NAME).bin +APPIFY ?= 0 +PREFIX ?= arm-none-eabi- +CC = $(PREFIX)gcc +LD = $(PREFIX)gcc +OBJCOPY = $(PREFIX)objcopy +OBJDUMP = $(PREFIX)objdump +FLASH = st-flash +OPENOCD = openocd +TOP_DIR = /home/stick/work/trezor/trezor-mcu +TOOLCHAIN_DIR = /home/stick/work/STM/libopencm3 + +OPTFLAGS = -Os -g + +CFLAGS += $(OPTFLAGS) \ + -Wall \ + -Wextra \ + -Wimplicit-function-declaration \ + -Wredundant-decls \ + -Wstrict-prototypes \ + -Wundef \ + -Wshadow \ + -fno-common \ + -mcpu=cortex-m3 \ + -mthumb \ + -msoft-float \ + -DSTM32F2 \ + -I$(TOOLCHAIN_DIR)/include \ + -I$(TOP_DIR) \ + -DAPPIFY=$(APPIFY) + +LDSCRIPT = $(TOP_DIR)/layout$(APPIFY).ld + +LDFLAGS += --static \ + -Wl,--start-group \ + -lc \ + -lgcc \ + -lnosys \ + -Wl,--end-group \ + -L$(TOP_DIR) \ + -L$(TOOLCHAIN_DIR)/lib \ + -L$(TOOLCHAIN_DIR)/lib/stm32/f2 \ + -T$(LDSCRIPT) \ + -nostartfiles \ + -Wl,--gc-sections \ + -mthumb \ + -march=armv7 \ + -mfix-cortex-m3-ldrd \ + -msoft-float + +all: $(NAME).bin flash: $(NAME).bin $(FLASH) write $(NAME).bin 0x8000000 +flash2: $(NAME).hex + $(OPENOCD) -f board/stm32f4discovery.cfg \ + -c "init" \ + -c "reset init" \ + -c "stm32f2x mass_erase 0" \ + -c "flash write_image $(NAME).hex" \ + -c "reset" \ + -c "shutdown" + $(NAME).bin: $(NAME).elf $(OBJCOPY) -Obinary $(NAME).elf $(NAME).bin @@ -44,6 +80,7 @@ $(NAME).elf: $(OBJS) $(LDSCRIPT) $(TOOLCHAIN_DIR)/lib/libopencm3_stm32f2.a $(CC) $(CFLAGS) -o $@ -c $< clean: + rm -f *.a rm -f *.o rm -f *.d rm -f *.elf diff --git a/speed-stm32/bignum.c b/speed-stm32/bignum.c deleted file mode 120000 index ae4e38c68..000000000 --- a/speed-stm32/bignum.c +++ /dev/null @@ -1 +0,0 @@ -../bignum.c \ No newline at end of file diff --git a/speed-stm32/bignum.h b/speed-stm32/bignum.h deleted file mode 120000 index 5efc7ca42..000000000 --- a/speed-stm32/bignum.h +++ /dev/null @@ -1 +0,0 @@ -../bignum.h \ No newline at end of file diff --git a/speed-stm32/ecdsa.c b/speed-stm32/ecdsa.c deleted file mode 120000 index 72f7870c9..000000000 --- a/speed-stm32/ecdsa.c +++ /dev/null @@ -1 +0,0 @@ -../ecdsa.c \ No newline at end of file diff --git a/speed-stm32/ecdsa.h b/speed-stm32/ecdsa.h deleted file mode 120000 index 23affb2f2..000000000 --- a/speed-stm32/ecdsa.h +++ /dev/null @@ -1 +0,0 @@ -../ecdsa.h \ No newline at end of file diff --git a/speed-stm32/hmac.c b/speed-stm32/hmac.c deleted file mode 120000 index 68437fdea..000000000 --- a/speed-stm32/hmac.c +++ /dev/null @@ -1 +0,0 @@ -../hmac.c \ No newline at end of file diff --git a/speed-stm32/hmac.h b/speed-stm32/hmac.h deleted file mode 120000 index 10ae0cd97..000000000 --- a/speed-stm32/hmac.h +++ /dev/null @@ -1 +0,0 @@ -../hmac.h \ No newline at end of file diff --git a/speed-stm32/rand.h b/speed-stm32/rand.h deleted file mode 120000 index f3be0086c..000000000 --- a/speed-stm32/rand.h +++ /dev/null @@ -1 +0,0 @@ -../rand.h \ No newline at end of file diff --git a/speed-stm32/secp256k1.c b/speed-stm32/secp256k1.c deleted file mode 120000 index 5a9d1084e..000000000 --- a/speed-stm32/secp256k1.c +++ /dev/null @@ -1 +0,0 @@ -../secp256k1.c \ No newline at end of file diff --git a/speed-stm32/secp256k1.h b/speed-stm32/secp256k1.h deleted file mode 120000 index c5f18c823..000000000 --- a/speed-stm32/secp256k1.h +++ /dev/null @@ -1 +0,0 @@ -../secp256k1.h \ No newline at end of file diff --git a/speed-stm32/sha2.c b/speed-stm32/sha2.c deleted file mode 120000 index 8e8fb5a97..000000000 --- a/speed-stm32/sha2.c +++ /dev/null @@ -1 +0,0 @@ -../sha2.c \ No newline at end of file diff --git a/speed-stm32/sha2.h b/speed-stm32/sha2.h deleted file mode 120000 index 3eba17921..000000000 --- a/speed-stm32/sha2.h +++ /dev/null @@ -1 +0,0 @@ -../sha2.h \ No newline at end of file From 2df62d4877132d848924a7775983ac05bc66ecf3 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 21 Sep 2013 17:41:02 +0200 Subject: [PATCH 026/627] use unit tests via Check instead of small test programs --- .gitignore | 3 +- Makefile | 14 +--- ecdsa.h | 2 + test-bip32.c | 78 ------------------ test-pubkey.c | 58 -------------- test-rfc6979.c | 51 ------------ tests.c | 212 +++++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 219 insertions(+), 199 deletions(-) delete mode 100644 test-bip32.c delete mode 100644 test-pubkey.c delete mode 100644 test-rfc6979.c create mode 100644 tests.c diff --git a/.gitignore b/.gitignore index 25ad0464d..ca4c1dd1f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,5 @@ *.o -test-bip32 -test-pubkey test-rfc6979 test-speed test-verify +tests diff --git a/Makefile b/Makefile index 4e94b2f69..702bc724f 100644 --- a/Makefile +++ b/Makefile @@ -2,19 +2,13 @@ CC = gcc CFLAGS = -Wall -Os OBJS = bignum.o ecdsa.o secp256k1.o sha2.o rand.o hmac.o bip32.o ripemd160.o -all: test-bip32 test-pubkey test-rfc6979 test-speed test-verify +all: tests test-speed test-verify %.o: %.c %.h $(CC) $(CFLAGS) -o $@ -c $< -test-bip32: test-bip32.o $(OBJS) - gcc test-bip32.o $(OBJS) -o test-bip32 - -test-pubkey: test-pubkey.o $(OBJS) - gcc test-pubkey.o $(OBJS) -o test-pubkey - -test-rfc6979: test-rfc6979.o $(OBJS) - gcc test-rfc6979.o $(OBJS) -o test-rfc6979 +tests: tests.o $(OBJS) + gcc tests.o $(OBJS) -lcheck -o tests test-speed: test-speed.o $(OBJS) gcc test-speed.o $(OBJS) -o test-speed @@ -23,4 +17,4 @@ test-verify: test-verify.o $(OBJS) gcc test-verify.o $(OBJS) -o test-verify -lcrypto clean: - rm -f *.o test-bip32 test-pubkey test-rfc6979 test-speed test-verify + rm -f *.o tests test-speed test-verify diff --git a/ecdsa.h b/ecdsa.h index f58a60dd7..2f5028ebb 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -35,4 +35,6 @@ void ecdsa_get_public_key_compressed(const uint8_t *priv_key, uint8_t *pub_key); void ecdsa_get_address(const uint8_t *pub_key, char version, char *addr); int ecdsa_verify(const uint8_t *pub_key, const uint8_t *signature, const uint8_t *msg, uint32_t msg_len); +void generate_k_rfc6979(bignum256 *secret, const uint8_t *priv_key, const uint8_t *hash); + #endif diff --git a/test-bip32.c b/test-bip32.c deleted file mode 100644 index 261690b0f..000000000 --- a/test-bip32.c +++ /dev/null @@ -1,78 +0,0 @@ -/** - * Copyright (c) 2013 Pavol Rusnak - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#include - -#include "bip32.h" - -// test vectors from https://en.bitcoin.it/wiki/BIP_0032_TestVectors - -void xprv_print(xprv *in) -{ - int i; - - printf("chain : "); for (i = 0; i < 32; i++) printf("%02x", in->chain_code[i]); printf("\n"); - printf("priv : "); for (i = 0; i < 32; i++) printf("%02x", in->private_key[i]); printf("\n"); - printf("pub : "); for (i = 0; i < 33; i++) printf("%02x", in->public_key[i]); printf("\n"); - printf("addr : "); printf("%s\n", in->address); - printf("\n"); -} - -int main() -{ - xprv node; - - xprv_from_seed((uint8_t *)"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", 16, &node); - - printf("[Chain m] got\n"); - xprv_print(&node); - printf("[Chain m] expected\n"); - printf("chain : 873dff81c02f525623fd1fe5167eac3a55a049de3d314bb42ee227ffed37d508\n"); - printf("priv : e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35\n"); - printf("pub : 0339a36013301597daef41fbe593a02cc513d0b55527ec2df1050e2e8ff49c85c2\n"); - printf("addr : 15mKKb2eos1hWa6tisdPwwDC1a5J1y9nma\n"); - printf("\n"); - - xprv_descent_prime(&node, 0); - - printf("[Chain m/0'] got\n"); - xprv_print(&node); - printf("[Chain m/0'] expected\n"); - printf("chain : 47fdacbd0f1097043b78c63c20c34ef4ed9a111d980047ad16282c7ae6236141\n"); - printf("priv : edb2e14f9ee77d26dd93b4ecede8d16ed408ce149b6cd80b0715a2d911a0afea\n"); - printf("pub : 035a784662a4a20a65bf6aab9ae98a6c068a81c52e4b032c0fb5400c706cfccc56\n"); - printf("addr : 19Q2WoS5hSS6T8GjhK8KZLMgmWaq4neXrh\n"); - printf("\n"); - - xprv_descent(&node, 1); - - printf("[Chain m/0'/1] got\n"); - xprv_print(&node); - printf("[Chain m/0'/1] expected\n"); - printf("chain : 2a7857631386ba23dacac34180dd1983734e444fdbf774041578e9b6adb37c19\n"); - printf("priv : 3c6cb8d0f6a264c91ea8b5030fadaa8e538b020f0a387421a12de9319dc93368\n"); - printf("pub : 03501e454bf00751f24b1b489aa925215d66af2234e3891c3b21a52bedb3cd711c\n"); - printf("addr : 1JQheacLPdM5ySCkrZkV66G2ApAXe1mqLj\n"); - printf("\n"); - - return 0; -} diff --git a/test-pubkey.c b/test-pubkey.c deleted file mode 100644 index 28797e475..000000000 --- a/test-pubkey.c +++ /dev/null @@ -1,58 +0,0 @@ -/** - * Copyright (c) 2013 Pavol Rusnak - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#include -#include "ecdsa.h" - -// vectors from https://en.bitcoin.it/wiki/BIP_0032_TestVectors - -const char *privs[] = { -"\xe8\xf3\x2e\x72\x3d\xec\xf4\x05\x1a\xef\xac\x8e\x2c\x93\xc9\xc5\xb2\x14\x31\x38\x17\xcd\xb0\x1a\x14\x94\xb9\x17\xc8\x43\x6b\x35", -"\xed\xb2\xe1\x4f\x9e\xe7\x7d\x26\xdd\x93\xb4\xec\xed\xe8\xd1\x6e\xd4\x08\xce\x14\x9b\x6c\xd8\x0b\x07\x15\xa2\xd9\x11\xa0\xaf\xea", -"\x3c\x6c\xb8\xd0\xf6\xa2\x64\xc9\x1e\xa8\xb5\x03\x0f\xad\xaa\x8e\x53\x8b\x02\x0f\x0a\x38\x74\x21\xa1\x2d\xe9\x31\x9d\xc9\x33\x68", -"\xcb\xce\x0d\x71\x9e\xcf\x74\x31\xd8\x8e\x6a\x89\xfa\x14\x83\xe0\x2e\x35\x09\x2a\xf6\x0c\x04\x2b\x1d\xf2\xff\x59\xfa\x42\x4d\xca", -"\x0f\x47\x92\x45\xfb\x19\xa3\x8a\x19\x54\xc5\xc7\xc0\xeb\xab\x2f\x9b\xdf\xd9\x6a\x17\x56\x3e\xf2\x8a\x6a\x4b\x1a\x2a\x76\x4e\xf4", -"\x47\x1b\x76\xe3\x89\xe5\x28\xd6\xde\x6d\x81\x68\x57\xe0\x12\xc5\x45\x50\x51\xca\xd6\x66\x08\x50\xe5\x83\x72\xa6\xc3\xe6\xe7\xc8", -}; - -const char *pubs[] = { -"0339a36013301597daef41fbe593a02cc513d0b55527ec2df1050e2e8ff49c85c2", -"035a784662a4a20a65bf6aab9ae98a6c068a81c52e4b032c0fb5400c706cfccc56", -"03501e454bf00751f24b1b489aa925215d66af2234e3891c3b21a52bedb3cd711c", -"0357bfe1e341d01c69fe5654309956cbea516822fba8a601743a012a7896ee8dc2", -"02e8445082a72f29b75ca48748a914df60622a609cacfce8ed0e35804560741d29", -"022a471424da5e657499d1ff51cb43c47481a03b1e77f951fe64cec9f5a48f7011", -}; - -int main() -{ - int i, k; - uint8_t pub[33]; - - for (k = 0; k < 6; k++) { - ecdsa_get_public_key_compressed((uint8_t *)privs[k], pub); - printf("got : "); for (i = 0; i < 33; i++) printf("%02x", pub[i]); printf("\n"); - printf("expected : %s\n", pubs[k]); - } - - return 0; -} diff --git a/test-rfc6979.c b/test-rfc6979.c deleted file mode 100644 index b21519d65..000000000 --- a/test-rfc6979.c +++ /dev/null @@ -1,51 +0,0 @@ -/** - * Copyright (c) 2013 Pavol Rusnak - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#include -#include "bignum.h" -#include "ecdsa.h" -#include "sha2.h" - -bignum256 k; -uint8_t kb[32]; -uint8_t priv[32] = {0xcc, 0xa9, 0xfb, 0xcc, 0x1b, 0x41, 0xe5, 0xa9, 0x5d, 0x36, 0x9e, 0xaa, 0x6d, 0xdc, 0xff, 0x73, 0xb6, 0x1a, 0x4e, 0xfa, 0xa2, 0x79, 0xcf, 0xc6, 0x56, 0x7e, 0x8d, 0xaa, 0x39, 0xcb, 0xaf, 0x50}; -uint8_t hash[32]; - -void generate_k_rfc6979(bignum256 *k, const uint8_t *priv_key, const uint8_t *hash); - -int main() -{ - int i; - - SHA256_Raw((uint8_t *)"sample", 6, hash); - printf("hash : "); - for (i = 0; i < 32; i++) printf("%02x", hash[i]); printf("\n"); - generate_k_rfc6979(&k, priv, hash); - bn_write_be(&k, kb); - - printf("expected : 2df40ca70e639d89528a6b670d9d48d9165fdc0febc0974056bdce192b8e16a3\n"); - printf("got : "); - for (i = 0; i < 32; i++) printf("%02x", kb[i]); - printf("\n"); - - return 0; -} diff --git a/tests.c b/tests.c new file mode 100644 index 000000000..943439c77 --- /dev/null +++ b/tests.c @@ -0,0 +1,212 @@ +/** + * Copyright (c) 2013 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include + +#include "bignum.h" +#include "bip32.h" +#include "ecdsa.h" +#include "sha2.h" + +uint8_t *fromhex(const char *str) +{ + static uint8_t buf[128]; + uint8_t c; + size_t i; + for (i = 0; i < strlen(str) / 2; i++) { + c = 0; + if (str[i*2] >= '0' && str[i*2] <= '9') c += (str[i*2] - '0') << 4; + if (str[i*2] >= 'a' && str[i*2] <= 'f') c += (10 + str[i*2] - 'a') << 4; + if (str[i*2+1] >= '0' && str[i*2+1] <= '9') c += (str[i*2+1] - '0'); + if (str[i*2+1] >= 'a' && str[i*2+1] <= 'f') c += (10 + str[i*2+1] - 'a'); + buf[i] = c; + } + return buf; +} + +char *tohex(const uint8_t *bin, size_t l) +{ + static char buf[257], digits[] = "0123456789abcdef"; + size_t i; + for (i = 0; i < l; i++) { + buf[i*2 ] = digits[(bin[i] >> 4) & 0xF]; + buf[i*2+1] = digits[bin[i] & 0xF]; + } + return buf; +} + +#define _ck_assert_mem(X, Y, L, OP) do { \ + const void* _ck_x = (X); \ + const void* _ck_y = (Y); \ + size_t _ck_l = (L); \ + ck_assert_msg(0 OP memcmp(_ck_y, _ck_x, _ck_l), \ + "Assertion '"#X#OP#Y"' failed: "#X"==\"%s\"", tohex(_ck_x, _ck_l)); \ +} while (0) +#define ck_assert_mem_eq(X, Y, L) _ck_assert_mem(X, Y, L, ==) +#define ck_assert_mem_ne(X, Y, L) _ck_assert_mem(X, Y, L, !=) + +// test vector 1 from https://en.bitcoin.it/wiki/BIP_0032_TestVectors +START_TEST(test_bip32_vector_1) +{ + xprv node; + + // init m + xprv_from_seed(fromhex("000102030405060708090a0b0c0d0e0f"), 16, &node); + + // [Chain m] + ck_assert_mem_eq(node.chain_code, fromhex("873dff81c02f525623fd1fe5167eac3a55a049de3d314bb42ee227ffed37d508"), 32); + ck_assert_mem_eq(node.private_key, fromhex("e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35"), 32); + ck_assert_mem_eq(node.public_key, fromhex("0339a36013301597daef41fbe593a02cc513d0b55527ec2df1050e2e8ff49c85c2"), 33); + ck_assert_str_eq(node.address, "15mKKb2eos1hWa6tisdPwwDC1a5J1y9nma"); + + // [Chain m/0'] + xprv_descent_prime(&node, 0); + ck_assert_mem_eq(node.chain_code, fromhex("47fdacbd0f1097043b78c63c20c34ef4ed9a111d980047ad16282c7ae6236141"), 32); + ck_assert_mem_eq(node.private_key, fromhex("edb2e14f9ee77d26dd93b4ecede8d16ed408ce149b6cd80b0715a2d911a0afea"), 32); + ck_assert_mem_eq(node.public_key, fromhex("035a784662a4a20a65bf6aab9ae98a6c068a81c52e4b032c0fb5400c706cfccc56"), 33); + ck_assert_str_eq(node.address, "19Q2WoS5hSS6T8GjhK8KZLMgmWaq4neXrh"); + + // [Chain m/0'/1] + xprv_descent(&node, 1); + ck_assert_mem_eq(node.chain_code, fromhex("2a7857631386ba23dacac34180dd1983734e444fdbf774041578e9b6adb37c19"), 32); + ck_assert_mem_eq(node.private_key, fromhex("3c6cb8d0f6a264c91ea8b5030fadaa8e538b020f0a387421a12de9319dc93368"), 32); + ck_assert_mem_eq(node.public_key, fromhex("03501e454bf00751f24b1b489aa925215d66af2234e3891c3b21a52bedb3cd711c"), 33); + ck_assert_str_eq(node.address, "1JQheacLPdM5ySCkrZkV66G2ApAXe1mqLj"); + + // [Chain m/0'/1/2'] + xprv_descent_prime(&node, 2); + ck_assert_mem_eq(node.chain_code, fromhex("04466b9cc8e161e966409ca52986c584f07e9dc81f735db683c3ff6ec7b1503f"), 32); + ck_assert_mem_eq(node.private_key, fromhex("cbce0d719ecf7431d88e6a89fa1483e02e35092af60c042b1df2ff59fa424dca"), 32); + ck_assert_mem_eq(node.public_key, fromhex("0357bfe1e341d01c69fe5654309956cbea516822fba8a601743a012a7896ee8dc2"), 33); + ck_assert_str_eq(node.address, "1NjxqbA9aZWnh17q1UW3rB4EPu79wDXj7x"); + + // [Chain m/0'/1/2'/2] + xprv_descent(&node, 2); + ck_assert_mem_eq(node.chain_code, fromhex("cfb71883f01676f587d023cc53a35bc7f88f724b1f8c2892ac1275ac822a3edd"), 32); + ck_assert_mem_eq(node.private_key, fromhex("0f479245fb19a38a1954c5c7c0ebab2f9bdfd96a17563ef28a6a4b1a2a764ef4"), 32); + ck_assert_mem_eq(node.public_key, fromhex("02e8445082a72f29b75ca48748a914df60622a609cacfce8ed0e35804560741d29"), 33); + ck_assert_str_eq(node.address, "1LjmJcdPnDHhNTUgrWyhLGnRDKxQjoxAgt"); + + + // [Chain m/0'/1/2'/2/1000000000] + xprv_descent(&node, 1000000000); + ck_assert_mem_eq(node.chain_code, fromhex("c783e67b921d2beb8f6b389cc646d7263b4145701dadd2161548a8b078e65e9e"), 32); + ck_assert_mem_eq(node.private_key, fromhex("471b76e389e528d6de6d816857e012c5455051cad6660850e58372a6c3e6e7c8"), 32); + ck_assert_mem_eq(node.public_key, fromhex("022a471424da5e657499d1ff51cb43c47481a03b1e77f951fe64cec9f5a48f7011"), 33); + ck_assert_str_eq(node.address, "1LZiqrop2HGR4qrH1ULZPyBpU6AUP49Uam"); +} +END_TEST + +// test vector 2 from https://en.bitcoin.it/wiki/BIP_0032_TestVectors +START_TEST(test_bip32_vector_2) +{ + xprv node; + + // init m + xprv_from_seed(fromhex("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), 64, &node); + + // [Chain m] + ck_assert_mem_eq(node.chain_code, fromhex("60499f801b896d83179a4374aeb7822aaeaceaa0db1f85ee3e904c4defbd9689"), 32); + ck_assert_mem_eq(node.private_key, fromhex("4b03d6fc340455b363f51020ad3ecca4f0850280cf436c70c727923f6db46c3e"), 32); + ck_assert_mem_eq(node.public_key, fromhex("03cbcaa9c98c877a26977d00825c956a238e8dddfbd322cce4f74b0b5bd6ace4a7"), 33); + ck_assert_str_eq(node.address, "1JEoxevbLLG8cVqeoGKQiAwoWbNYSUyYjg"); + + // [Chain m/0] + xprv_descent(&node, 0); + ck_assert_mem_eq(node.chain_code, fromhex("f0909affaa7ee7abe5dd4e100598d4dc53cd709d5a5c2cac40e7412f232f7c9c"), 32); + ck_assert_mem_eq(node.private_key, fromhex("abe74a98f6c7eabee0428f53798f0ab8aa1bd37873999041703c742f15ac7e1e"), 32); + ck_assert_mem_eq(node.public_key, fromhex("02fc9e5af0ac8d9b3cecfe2a888e2117ba3d089d8585886c9c826b6b22a98d12ea"), 33); + ck_assert_str_eq(node.address, "19EuDJdgfRkwCmRzbzVBHZWQG9QNWhftbZ"); + + // [Chain m/0/2147483647'] + xprv_descent_prime(&node, 2147483647); + ck_assert_mem_eq(node.chain_code, fromhex("be17a268474a6bb9c61e1d720cf6215e2a88c5406c4aee7b38547f585c9a37d9"), 32); + ck_assert_mem_eq(node.private_key, fromhex("877c779ad9687164e9c2f4f0f4ff0340814392330693ce95a58fe18fd52e6e93"), 32); + ck_assert_mem_eq(node.public_key, fromhex("03c01e7425647bdefa82b12d9bad5e3e6865bee0502694b94ca58b666abc0a5c3b"), 33); + ck_assert_str_eq(node.address, "1Lke9bXGhn5VPrBuXgN12uGUphrttUErmk"); + + // [Chain m/0/2147483647'/1] + xprv_descent(&node, 1); + ck_assert_mem_eq(node.chain_code, fromhex("f366f48f1ea9f2d1d3fe958c95ca84ea18e4c4ddb9366c336c927eb246fb38cb"), 32); + ck_assert_mem_eq(node.private_key, fromhex("704addf544a06e5ee4bea37098463c23613da32020d604506da8c0518e1da4b7"), 32); + ck_assert_mem_eq(node.public_key, fromhex("03a7d1d856deb74c508e05031f9895dab54626251b3806e16b4bd12e781a7df5b9"), 33); + ck_assert_str_eq(node.address, "1BxrAr2pHpeBheusmd6fHDP2tSLAUa3qsW"); + + // [Chain m/0/2147483647'/1/2147483646'] + xprv_descent_prime(&node, 2147483646); + ck_assert_mem_eq(node.chain_code, fromhex("637807030d55d01f9a0cb3a7839515d796bd07706386a6eddf06cc29a65a0e29"), 32); + ck_assert_mem_eq(node.private_key, fromhex("f1c7c871a54a804afe328b4c83a1c33b8e5ff48f5087273f04efa83b247d6a2d"), 32); + ck_assert_mem_eq(node.public_key, fromhex("02d2b36900396c9282fa14628566582f206a5dd0bcc8d5e892611806cafb0301f0"), 33); + ck_assert_str_eq(node.address, "15XVotxCAV7sRx1PSCkQNsGw3W9jT9A94R"); + + // [Chain m/0/2147483647'/1/2147483646'/2] + xprv_descent(&node, 2); + ck_assert_mem_eq(node.chain_code, fromhex("9452b549be8cea3ecb7a84bec10dcfd94afe4d129ebfd3b3cb58eedf394ed271"), 32); + ck_assert_mem_eq(node.private_key, fromhex("bb7d39bdb83ecf58f2fd82b6d918341cbef428661ef01ab97c28a4842125ac23"), 32); + ck_assert_mem_eq(node.public_key, fromhex("024d902e1a2fc7a8755ab5b694c575fce742c48d9ff192e63df5193e4c7afe1f9c"), 33); + ck_assert_str_eq(node.address, "14UKfRV9ZPUp6ZC9PLhqbRtxdihW9em3xt"); +} +END_TEST + +START_TEST(test_rfc6979) +{ + bignum256 k; + uint8_t buf[32]; + + SHA256_Raw((uint8_t *)"sample", 6, buf); + generate_k_rfc6979(&k, fromhex("cca9fbcc1b41e5a95d369eaa6ddcff73b61a4efaa279cfc6567e8daa39cbaf50"), buf); + bn_write_be(&k, buf); + + ck_assert_mem_eq(buf, fromhex("2df40ca70e639d89528a6b670d9d48d9165fdc0febc0974056bdce192b8e16a3"), 32); +} +END_TEST + +// define test suite and cases +Suite *test_suite(void) +{ + Suite *s = suite_create("MicroECDSA"); + TCase *tc; + + tc = tcase_create("bip32"); + tcase_add_test(tc, test_bip32_vector_1); + tcase_add_test(tc, test_bip32_vector_2); + suite_add_tcase(s, tc); + + tc = tcase_create("rfc6979"); + tcase_add_test(tc, test_rfc6979); + suite_add_tcase(s, tc); + + return s; +} + +// run suite +int main() +{ + int number_failed; + Suite *s = test_suite(); + SRunner *sr = srunner_create(s); + srunner_run_all(sr, CK_NORMAL); + number_failed = srunner_ntests_failed(sr); + srunner_free(sr); + return number_failed; +} From 58a65d9cd79d6bdb850113a995110962457710c2 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 22 Sep 2013 12:42:35 +0200 Subject: [PATCH 027/627] move speed tests to unit testing suite --- .gitignore | 4 +-- Makefile | 11 +++--- ecdsa.c | 2 +- test-verify.c => test-openssl.c | 0 test-speed.c | 61 --------------------------------- tests.c | 52 +++++++++++++++++++++++++++- 6 files changed, 57 insertions(+), 73 deletions(-) rename test-verify.c => test-openssl.c (100%) delete mode 100644 test-speed.c diff --git a/.gitignore b/.gitignore index ca4c1dd1f..eca727cdd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,3 @@ *.o -test-rfc6979 -test-speed -test-verify +test-openssl tests diff --git a/Makefile b/Makefile index 702bc724f..ed1fed844 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ CC = gcc CFLAGS = -Wall -Os OBJS = bignum.o ecdsa.o secp256k1.o sha2.o rand.o hmac.o bip32.o ripemd160.o -all: tests test-speed test-verify +all: tests test-openssl %.o: %.c %.h $(CC) $(CFLAGS) -o $@ -c $< @@ -10,11 +10,8 @@ all: tests test-speed test-verify tests: tests.o $(OBJS) gcc tests.o $(OBJS) -lcheck -o tests -test-speed: test-speed.o $(OBJS) - gcc test-speed.o $(OBJS) -o test-speed - -test-verify: test-verify.o $(OBJS) - gcc test-verify.o $(OBJS) -o test-verify -lcrypto +test-openssl: test-openssl.o $(OBJS) + gcc test-openssl.o $(OBJS) -o test-openssl -lcrypto clean: - rm -f *.o tests test-speed test-verify + rm -f *.o tests test-openssl diff --git a/ecdsa.c b/ecdsa.c index acf7a518c..a0f07831b 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -249,7 +249,7 @@ void generate_k_rfc6979(bignum256 *secret, const uint8_t *priv_key, const uint8_ // sig_len is the pointer to a uint that will contain resulting signature length. note that ((*sig_len) == sig[1]+2) void ecdsa_sign(const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint32_t *sig_len) { - int i; + uint32_t i; uint8_t hash[32]; curve_point R; bignum256 k, z; diff --git a/test-verify.c b/test-openssl.c similarity index 100% rename from test-verify.c rename to test-openssl.c diff --git a/test-speed.c b/test-speed.c deleted file mode 100644 index 0c336382b..000000000 --- a/test-speed.c +++ /dev/null @@ -1,61 +0,0 @@ -/** - * Copyright (c) 2013 Tomas Dzetkulic - * Copyright (c) 2013 Pavol Rusnak - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#include -#include - -#include "ecdsa.h" -#include "rand.h" - -int main() -{ - uint8_t sig[70], priv_key[32], msg[256]; - uint32_t sig_len, i, msg_len; - int cnt = 0; - - init_rand(); - - // random message len between 1 and 256 - msg_len = (random32() & 0xFF) + 1; - // create random message - for (i = 0; i < msg_len; i++) { - msg[i] = random32() & 0xFF; - } - // create random privkey - for (i = 0; i < 8; i++) { - uint32_t r = random32(); - priv_key[4 * i ] = r & 0xFF; - priv_key[4 * i + 1] = (r >> 8) & 0xFF; - priv_key[4 * i + 2] = (r >> 16) & 0xFF; - priv_key[4 * i + 3] = (r >> 24) & 0xFF; - } - - clock_t t = clock(); - for (;;) { - // use our ECDSA signer to sign the message with the key - ecdsa_sign(priv_key, msg, msg_len, sig, &sig_len); - cnt++; - if ((cnt % 100) == 0) printf("Speed: %f sig/s\n", 1.0f * cnt / ((float)(clock() - t) / CLOCKS_PER_SEC)); - } - return 0; -} diff --git a/tests.c b/tests.c index 943439c77..bc88830a6 100644 --- a/tests.c +++ b/tests.c @@ -1,4 +1,5 @@ /** + * Copyright (c) 2013 Tomas Dzetkulic * Copyright (c) 2013 Pavol Rusnak * * Permission is hereby granted, free of charge, to any person obtaining @@ -22,6 +23,8 @@ #include #include +#include +#include #include "bignum.h" #include "bip32.h" @@ -181,6 +184,48 @@ START_TEST(test_rfc6979) } END_TEST +START_TEST(test_sign_speed) +{ + uint8_t sig[70], priv_key[32], msg[256]; + uint32_t sig_len; + int i; + + memcpy(priv_key, fromhex("c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd5"), 32); + + for (i = 0; i < sizeof(msg); i++) { + msg[i] = i * 1103515245; + } + + clock_t t = clock(); + for (i = 0 ; i < 500; i++) { + // use our ECDSA signer to sign the message with the key + ecdsa_sign(priv_key, msg, sizeof(msg), sig, &sig_len); + } + printf("Signing speed: %0.2f sig/s\n", 1.0f * i / ((float)(clock() - t) / CLOCKS_PER_SEC)); +} +END_TEST + +START_TEST(test_verify_speed) +{ + uint8_t sig[70], pub_key[33], msg[256]; + int i; + + memcpy(sig, fromhex("3044022088dc0db6bc5efa762e75fbcc802af69b9f1fcdbdffce748d403f687f855556e6022010ee8035414099ac7d89cff88a3fa246d332dfa3c78d82c801394112dda039c2"), 70); + memcpy(pub_key, fromhex("024054fd18aeb277aeedea01d3f3986ff4e5be18092a04339dcf4e524e2c0a0974"), 33); + + for (i = 0; i < sizeof(msg); i++) { + msg[i] = i * 1103515245; + } + + clock_t t = clock(); + for (i = 0 ; i < 150; i++) { + // use our ECDSA verifier to verify the message with the key + ecdsa_verify(pub_key, sig, msg, sizeof(msg)); + } + printf("Verifying speed: %0.2f sig/s\n", 1.0f * i / ((float)(clock() - t) / CLOCKS_PER_SEC)); +} +END_TEST + // define test suite and cases Suite *test_suite(void) { @@ -196,6 +241,11 @@ Suite *test_suite(void) tcase_add_test(tc, test_rfc6979); suite_add_tcase(s, tc); + tc = tcase_create("speed"); + tcase_add_test(tc, test_sign_speed); + tcase_add_test(tc, test_verify_speed); + suite_add_tcase(s, tc); + return s; } @@ -205,7 +255,7 @@ int main() int number_failed; Suite *s = test_suite(); SRunner *sr = srunner_create(s); - srunner_run_all(sr, CK_NORMAL); + srunner_run_all(sr, CK_VERBOSE); number_failed = srunner_ntests_failed(sr); srunner_free(sr); return number_failed; From 896905c5c82f1eabda08e8a1e42956d02f559c09 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 23 Sep 2013 21:09:42 +0200 Subject: [PATCH 028/627] remove der encoding, introduce 33/65 bytes pubkeys, 64 bytes signature --- bip32.c | 6 +-- ecdsa.c | 106 ++++++++++---------------------------------- ecdsa.h | 8 ++-- speed-stm32/speed.c | 6 +-- test-openssl.c | 17 +++---- tests.c | 19 ++++---- 6 files changed, 51 insertions(+), 111 deletions(-) diff --git a/bip32.c b/bip32.c index a0ba5361c..a636d1e7e 100644 --- a/bip32.c +++ b/bip32.c @@ -14,7 +14,7 @@ void xprv_from_seed(uint8_t *seed, int seed_len, xprv *out) // this can be done because private_key[32] and chain_code[32] // form a continuous 64 byte block in the memory hmac_sha512((uint8_t *)"Bitcoin seed", 12, seed, seed_len, out->private_key); - ecdsa_get_public_key_compressed(out->private_key, out->public_key); + ecdsa_get_public_key33(out->private_key, out->public_key); ecdsa_get_address(out->public_key, 0, out->address); } @@ -27,7 +27,7 @@ void xprv_descent(xprv *inout, uint32_t i) data[0] = 0; memcpy(data + 1, inout->private_key, 32); } else { - ecdsa_get_public_key_compressed(inout->private_key, data); + ecdsa_get_public_key33(inout->private_key, data); } write_be(data + 33, i); @@ -44,6 +44,6 @@ void xprv_descent(xprv *inout, uint32_t i) inout->child_num = i; bn_write_be(&a, inout->private_key); - ecdsa_get_public_key_compressed(inout->private_key, inout->public_key); + ecdsa_get_public_key33(inout->private_key, inout->public_key); ecdsa_get_address(inout->public_key, 0, inout->address); } diff --git a/ecdsa.c b/ecdsa.c index a0f07831b..ed0c79ff5 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -135,57 +135,6 @@ void scalar_multiply(bignum256 *k, curve_point *res) bn_mod(&(res->y), &prime256k1); } -// does not validate that this is valid der encoding -// assumes it is der encoding containing 1 number -void der_read_single(const uint8_t *der, bignum256 *elem) -{ - int i, j; - uint8_t val[32]; - i = 1 + der[1]; - j = 31; - // we ignore all bytes after 32nd. if there are any, those are either zero or invalid for secp256k1 - while (i > 1 && j >= 0) { - val[j] = der[i]; - i--; j--; - } - for (i = 0; i <= j; i++) { - val[i] = 0; - } - bn_read_be(val, elem); -} - -// does not validate that this is valid der encoding -// assumes it is der encoding containing 2 numbers (either public key or ecdsa signature) -void der_read_pair(const uint8_t *der, bignum256 *elem1, bignum256 *elem2) -{ - der_read_single(der + 2, elem1); - der_read_single(der + 4 + der[3], elem2); -} - -// write DER encoding of number to buffer -void der_write(const bignum256 *x, uint8_t *buf) -{ - int i, j = 8, k = 8, len = 0; - uint8_t r = 0, temp; - buf[0] = 2; - for (i = 0; i < 32; i++) { - temp = (x->val[j] >> k) + r; - k -= 8; - if (k < 0) { - r = (x->val[j]) << (-k); - k += 30; - j--; - } else { - r = 0; - } - if (len || temp) { - buf[2 + len] = temp; - len++; - } - } - buf[1] = len; -} - // generate random K for signing void generate_k_random(bignum256 *k) { int i; @@ -245,9 +194,8 @@ void generate_k_rfc6979(bignum256 *secret, const uint8_t *priv_key, const uint8_ // priv_key is a 32 byte big endian stored number // msg is a data to be signed // msg_len is the message length -// sig is at least 70 bytes long array for the signature -// sig_len is the pointer to a uint that will contain resulting signature length. note that ((*sig_len) == sig[1]+2) -void ecdsa_sign(const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint32_t *sig_len) +// sig is 64 bytes long array for the signature +void ecdsa_sign(const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig) { uint32_t i; uint8_t hash[32]; @@ -295,39 +243,24 @@ void ecdsa_sign(const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, u // we are done, R.x and k is the result signature break; } - der_write(&R.x, sig + 2); - i = sig[3] + 2; - der_write(&k, sig + 2 + i); - i += sig[3 + i] + 2; - sig[0] = 0x30; - sig[1] = i; - *sig_len = i + 2; + + bn_write_be(&R.x, sig); + bn_write_be(&k, sig + 32); } -// uses secp256k1 curve -// priv_key is a 32 byte big endian stored number -// pub_key is at least 70 bytes long array for the public key -void ecdsa_get_public_key_der(const uint8_t *priv_key, uint8_t *pub_key, uint32_t *pub_key_len) +void ecdsa_get_public_key33(const uint8_t *priv_key, uint8_t *pub_key) { - uint32_t i; curve_point R; bignum256 k; bn_read_be(priv_key, &k); // compute k*G scalar_multiply(&k, &R); - der_write(&R.x, pub_key + 2); - i = pub_key[3] + 2; - der_write(&R.y, pub_key + 2 + i); - i += pub_key[3 + i] + 2; - pub_key[0] = 0x30; - pub_key[1] = i; - *pub_key_len = i + 2; + pub_key[0] = 0x02 | (R.y.val[0] & 0x01); + bn_write_be(&R.x, pub_key + 1); } - -// pub_key is always 33 bytes long -void ecdsa_get_public_key_compressed(const uint8_t *priv_key, uint8_t *pub_key) +void ecdsa_get_public_key65(const uint8_t *priv_key, uint8_t *pub_key) { curve_point R; bignum256 k; @@ -335,8 +268,9 @@ void ecdsa_get_public_key_compressed(const uint8_t *priv_key, uint8_t *pub_key) bn_read_be(priv_key, &k); // compute k*G scalar_multiply(&k, &R); - pub_key[0] = 0x02 | (R.y.val[0] & 0x01); + pub_key[0] = 0x04; bn_write_be(&R.x, pub_key + 1); + bn_write_be(&R.y, pub_key + 33); } void ecdsa_get_address(const uint8_t *pub_key, char version, char *addr) @@ -387,12 +321,13 @@ void ecdsa_get_address(const uint8_t *pub_key, char version, char *addr) } // uses secp256k1 curve -// pub_key and signature are DER encoded +// pub_key - 65 bytes uncompressed key +// signature - 64 bytes signature // msg is a data that was signed // msg_len is the message length // returns 0 if verification succeeded // it is assumed that public key is valid otherwise calling this does not make much sense -int ecdsa_verify(const uint8_t *pub_key, const uint8_t *signature, const uint8_t *msg, uint32_t msg_len) +int ecdsa_verify(const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, uint32_t msg_len) { int i, j; uint8_t hash[32]; @@ -404,14 +339,19 @@ int ecdsa_verify(const uint8_t *pub_key, const uint8_t *signature, const uint8_t // if double hash is required uncomment the following line: // SHA256_Raw(hash, 32, hash); + if (pub_key[0] != 0x04) return 1; + bn_read_be(pub_key + 1, &pub.x); + bn_read_be(pub_key + 33, &pub.y); + + bn_read_be(sig, &r); + bn_read_be(sig + 32, &s); + bn_read_be(hash, &z); - der_read_pair(pub_key, &pub.x, &pub.y); - der_read_pair(signature, &r, &s); if (bn_is_zero(&r) || bn_is_zero(&s) || (!bn_is_less(&r, &order256k1)) || - (!bn_is_less(&s, &order256k1))) return 1; + (!bn_is_less(&s, &order256k1))) return 2; bn_inverse(&s, &order256k1); // s^-1 bn_multiply(&s, &z, &order256k1); // z*s^-1 @@ -441,7 +381,7 @@ int ecdsa_verify(const uint8_t *pub_key, const uint8_t *signature, const uint8_t bn_mod(&(res.x), &order256k1); for (i = 0; i < 9; i++) { if (res.x.val[i] != r.val[i]) { - return 1; + return 3; } } return 0; diff --git a/ecdsa.h b/ecdsa.h index 2f5028ebb..7e18c411a 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -29,11 +29,11 @@ #include "secp256k1.h" // all functions use secp256k1 curve -void ecdsa_sign(const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint32_t *sig_len); -void ecdsa_get_public_key_der(const uint8_t *priv_key, uint8_t *pub_key, uint32_t *pub_key_len); -void ecdsa_get_public_key_compressed(const uint8_t *priv_key, uint8_t *pub_key); +void ecdsa_sign(const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig); +void ecdsa_get_public_key33(const uint8_t *priv_key, uint8_t *pub_key); +void ecdsa_get_public_key65(const uint8_t *priv_key, uint8_t *pub_key); void ecdsa_get_address(const uint8_t *pub_key, char version, char *addr); -int ecdsa_verify(const uint8_t *pub_key, const uint8_t *signature, const uint8_t *msg, uint32_t msg_len); +int ecdsa_verify(const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, uint32_t msg_len); void generate_k_rfc6979(bignum256 *secret, const uint8_t *priv_key, const uint8_t *hash); diff --git a/speed-stm32/speed.c b/speed-stm32/speed.c index 1532f0f4a..44835de68 100644 --- a/speed-stm32/speed.c +++ b/speed-stm32/speed.c @@ -206,8 +206,8 @@ static void cdcacm_data_rx_cb(usbd_device *usbd_dev, uint8_t ep) int len = usbd_ep_read_packet(usbd_dev, 0x01, buf, 64); if (len) { - uint8_t sig[70], priv_key[32], msg[256]; - uint32_t sig_len, i, msg_len; + uint8_t sig[64], priv_key[32], msg[256]; + uint32_t i, msg_len; // random message len between 1 and 256 msg_len = (random32() & 0xFF) + 1; @@ -229,7 +229,7 @@ static void cdcacm_data_rx_cb(usbd_device *usbd_dev, uint8_t ep) // use our ECDSA signer 10 times to sign the message with the key for (i = 0; i < 10; i++) { - ecdsa_sign(priv_key, msg, msg_len, sig, &sig_len); + ecdsa_sign(priv_key, msg, msg_len, sig); } len = sprintf(buf, "Done!\r\n"); diff --git a/test-openssl.c b/test-openssl.c index cd894c305..c19839468 100644 --- a/test-openssl.c +++ b/test-openssl.c @@ -32,8 +32,8 @@ int main() { - uint8_t sig[70], pub_key[70], priv_key[32], msg[256], buffer[1000], hash[32], *p; - uint32_t sig_len, pub_key_len, i, j, msg_len; + uint8_t sig[64], pub_key[65], priv_key[32], msg[256], buffer[1000], hash[32], *p; + uint32_t i, j, msg_len; SHA256_CTX sha256; EC_GROUP *ecgroup; int cnt = 0; @@ -51,11 +51,11 @@ int main() // new ECDSA key EC_KEY *eckey = EC_KEY_new(); EC_KEY_set_group(eckey, ecgroup); - + // generate the key EC_KEY_generate_key(eckey); - p = buffer; // copy key to buffer + p = buffer; i2d_ECPrivateKey(eckey, &p); // size of the key is in buffer[8] and the key begins right after that @@ -75,10 +75,10 @@ int main() } // use our ECDSA signer to sign the message with the key - ecdsa_sign(priv_key, msg, msg_len, sig, &sig_len); + ecdsa_sign(priv_key, msg, msg_len, sig); // generate public key from private key - ecdsa_get_public_key_der(priv_key, pub_key, &pub_key_len); + ecdsa_get_public_key65(priv_key, pub_key); // use our ECDSA verifier to verify the message signature if (ecdsa_verify(pub_key, sig, msg, msg_len) != 0) { @@ -87,8 +87,9 @@ int main() } // copy signature to the OpenSSL struct - p = sig; - ECDSA_SIG *signature = d2i_ECDSA_SIG(NULL, (const uint8_t **)&p, sig_len); + ECDSA_SIG *signature = ECDSA_SIG_new(); + BN_bin2bn(sig, 32, signature->r); + BN_bin2bn(sig + 32, 32, signature->s); // compute the digest of the message SHA256_Init(&sha256); diff --git a/tests.c b/tests.c index bc88830a6..5088b64c8 100644 --- a/tests.c +++ b/tests.c @@ -49,7 +49,7 @@ uint8_t *fromhex(const char *str) char *tohex(const uint8_t *bin, size_t l) { - static char buf[257], digits[] = "0123456789abcdef"; + static char buf[256], digits[] = "0123456789abcdef"; size_t i; for (i = 0; i < l; i++) { buf[i*2 ] = digits[(bin[i] >> 4) & 0xF]; @@ -186,8 +186,7 @@ END_TEST START_TEST(test_sign_speed) { - uint8_t sig[70], priv_key[32], msg[256]; - uint32_t sig_len; + uint8_t sig[64], priv_key[32], msg[256]; int i; memcpy(priv_key, fromhex("c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd5"), 32); @@ -199,7 +198,7 @@ START_TEST(test_sign_speed) clock_t t = clock(); for (i = 0 ; i < 500; i++) { // use our ECDSA signer to sign the message with the key - ecdsa_sign(priv_key, msg, sizeof(msg), sig, &sig_len); + ecdsa_sign(priv_key, msg, sizeof(msg), sig); } printf("Signing speed: %0.2f sig/s\n", 1.0f * i / ((float)(clock() - t) / CLOCKS_PER_SEC)); } @@ -207,11 +206,10 @@ END_TEST START_TEST(test_verify_speed) { - uint8_t sig[70], pub_key[33], msg[256]; - int i; - - memcpy(sig, fromhex("3044022088dc0db6bc5efa762e75fbcc802af69b9f1fcdbdffce748d403f687f855556e6022010ee8035414099ac7d89cff88a3fa246d332dfa3c78d82c801394112dda039c2"), 70); - memcpy(pub_key, fromhex("024054fd18aeb277aeedea01d3f3986ff4e5be18092a04339dcf4e524e2c0a0974"), 33); + uint8_t sig[64], pub_key[65], msg[256]; + int i, res; + memcpy(sig, fromhex("88dc0db6bc5efa762e75fbcc802af69b9f1fcdbdffce748d403f687f855556e610ee8035414099ac7d89cff88a3fa246d332dfa3c78d82c801394112dda039c2"), 70); + memcpy(pub_key, fromhex("044054fd18aeb277aeedea01d3f3986ff4e5be18092a04339dcf4e524e2c0a09746c7083ed2097011b1223a17a644e81f59aa3de22dac119fd980b36a8ff29a244"), 65); for (i = 0; i < sizeof(msg); i++) { msg[i] = i * 1103515245; @@ -220,7 +218,8 @@ START_TEST(test_verify_speed) clock_t t = clock(); for (i = 0 ; i < 150; i++) { // use our ECDSA verifier to verify the message with the key - ecdsa_verify(pub_key, sig, msg, sizeof(msg)); + res = ecdsa_verify(pub_key, sig, msg, sizeof(msg)); + ck_assert_int_eq(res, 0); } printf("Verifying speed: %0.2f sig/s\n", 1.0f * i / ((float)(clock() - t) / CLOCKS_PER_SEC)); } From dfdcdfa044af014414405ad432777aa1ad1b7e2e Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 23 Sep 2013 21:15:25 +0200 Subject: [PATCH 029/627] alter readme --- README | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/README b/README index 887c93aa5..db54e3eb1 100644 --- a/README +++ b/README @@ -10,14 +10,9 @@ Notes a) the signer only understands secp256k1 elliptic curve -b) there are executables: - * test-rfc6979 - - check RFC 6979 algorithm for generating deterministic K - * test-speed - - check signing speed (sign 100x and compute speed from duration) - * test-verify - - generate random messages and private keys - - check signature validity against OpenSSL (call verify method) +b) unit tests using Check (check.sf.net) are in tests.c -c) directory speed-stm32 contains project for deploying the code +c) tests against OpenSSL are in test-openssl.c + +d) directory speed-stm32 contains project for deploying the code on STM32 microcontroller and checking signing speed there From 74a5b04b81ab9cb4c086a55bb47b1c8ccdf705cb Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 24 Sep 2013 15:54:36 +0200 Subject: [PATCH 030/627] verify now supports compressed keys --- bignum.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++---- bignum.h | 8 ++++++++ ecdsa.c | 21 ++++++++++++++++--- test-openssl.c | 13 ++++++++---- tests.c | 48 +++++++++++++++++++++++++++++++------------ 5 files changed, 122 insertions(+), 24 deletions(-) diff --git a/bignum.c b/bignum.c index 0e438bdab..cfce5d7cb 100644 --- a/bignum.c +++ b/bignum.c @@ -21,6 +21,8 @@ * OTHER DEALINGS IN THE SOFTWARE. */ +#include +#include #include "bignum.h" #include "secp256k1.h" @@ -210,6 +212,32 @@ void bn_fast_mod(bignum256 *x, const bignum256 *prime) } } +// square root of x = x^((p+1)/4) +// http://en.wikipedia.org/wiki/Quadratic_residue#Prime_or_prime_power_modulus +void bn_sqrt(bignum256 *x, const bignum256 *prime) +{ + uint32_t i, j, limb; + bignum256 res, p; + bn_zero(&res); res.val[0] = 1; + memcpy(&p, prime, sizeof(bignum256)); + p.val[0] += 1; + bn_rshift(&p); + bn_rshift(&p); + for (i = 0; i < 9; i++) { + limb = p.val[i]; + for (j = 0; j < 30; j++) { + if (i == 8 && limb == 0) break; + if (limb & 1) { + bn_multiply(x, &res, prime); + } + limb >>= 1; + bn_multiply(x, x, prime); + } + } + bn_mod(&res, prime); + memcpy(x, &res, sizeof(bignum256)); +} + #ifndef INVERSE_FAST #ifdef USE_PRECOMPUTED_IV @@ -221,8 +249,7 @@ void bn_inverse(bignum256 *x, const bignum256 *prime) { uint32_t i, j, limb; bignum256 res; - res.val[0] = 1; - bn_zero(&res); + bn_zero(&res); res.val[0] = 1; for (i = 0; i < 9; i++) { limb = prime->val[i]; // this is not enough in general but fine for secp256k1 because prime->val[0] > 1 @@ -230,10 +257,10 @@ void bn_inverse(bignum256 *x, const bignum256 *prime) for (j = 0; j < 30; j++) { if (i == 8 && limb == 0) break; if (limb & 1) { - multiply(x, &res, prime); + bn_multiply(x, &res, prime); } limb >>= 1; - multiply(x, x, prime); + bn_multiply(x, x, prime); } } bn_mod(&res, prime); @@ -439,6 +466,12 @@ void bn_addmod(bignum256 *a, const bignum256 *b, const bignum256 *prime) bn_mod(a, prime); } +void bn_addmodi(bignum256 *a, uint32_t b, const bignum256 *prime) { + a->val[0] += b; + bn_normalize(a); + bn_mod(a, prime); +} + // res = a - b // b < 2*prime; result not normalized void bn_substract(const bignum256 *a, const bignum256 *b, bignum256 *res) @@ -503,3 +536,18 @@ void bn_divmod58(const bignum256 *a, bignum256 *q, uint32_t *r) *r = rem.val[0]; } + +#if 0 +void bn_print(const bignum256 *a) +{ + printf("%04x", a->val[8] & 0x0000FFFF); + printf("%08x", (a->val[7] << 2) | ((a->val[6] & 0x30000000) >> 28)); + printf("%07x", a->val[6] & 0x0FFFFFFF); + printf("%08x", (a->val[5] << 2) | ((a->val[4] & 0x30000000) >> 28)); + printf("%07x", a->val[4] & 0x0FFFFFFF); + printf("%08x", (a->val[3] << 2) | ((a->val[2] & 0x30000000) >> 28)); + printf("%07x", a->val[2] & 0x0FFFFFFF); + printf("%08x", (a->val[1] << 2) | ((a->val[0] & 0x30000000) >> 28)); + printf("%07x", a->val[0] & 0x0FFFFFFF); +} +#endif diff --git a/bignum.h b/bignum.h index 320451711..7da67e709 100644 --- a/bignum.h +++ b/bignum.h @@ -68,16 +68,24 @@ void bn_multiply(const bignum256 *k, bignum256 *x, const bignum256 *prime); void bn_fast_mod(bignum256 *x, const bignum256 *prime); +void bn_sqrt(bignum256 *x, const bignum256 *prime); + void bn_inverse(bignum256 *x, const bignum256 *prime); void bn_normalize(bignum256 *a); void bn_addmod(bignum256 *a, const bignum256 *b, const bignum256 *prime); +void bn_addmodi(bignum256 *a, uint32_t b, const bignum256 *prime); + void bn_substract(const bignum256 *a, const bignum256 *b, bignum256 *res); void bn_substract_noprime(const bignum256 *a, const bignum256 *b, bignum256 *res); void bn_divmod58(const bignum256 *a, bignum256 *q, uint32_t *r); +#if 0 +void bn_print(const bignum256 *a); +#endif + #endif diff --git a/ecdsa.c b/ecdsa.c index ed0c79ff5..7c08474fa 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -339,9 +339,24 @@ int ecdsa_verify(const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, // if double hash is required uncomment the following line: // SHA256_Raw(hash, 32, hash); - if (pub_key[0] != 0x04) return 1; - bn_read_be(pub_key + 1, &pub.x); - bn_read_be(pub_key + 33, &pub.y); + if (pub_key[0] == 0x04) { + bn_read_be(pub_key + 1, &pub.x); + bn_read_be(pub_key + 33, &pub.y); + } else + if (pub_key[0] == 0x02 || pub_key[0] == 0x03) { // compute missing y coords + // y^2 = x^3 + 0*x + 7 + bn_read_be(pub_key + 1, &pub.x); + bn_read_be(pub_key + 1, &pub.y); // y is x + bn_multiply(&pub.x, &pub.y, &prime256k1); // y is x^2 + bn_multiply(&pub.x, &pub.y, &prime256k1); // y is x^3 + bn_addmodi(&pub.y, 7, &prime256k1); // y is x^3 + 7 + bn_sqrt(&pub.y, &prime256k1); // y = sqrt(y) + if ((pub_key[0] & 0x01) != (pub.y.val[0] & 1)) { + bn_substract(&prime256k1, &pub.y, &pub.y); // y = -y + bn_mod(&pub.y, &prime256k1); + } + } else + return 1; bn_read_be(sig, &r); bn_read_be(sig + 32, &s); diff --git a/test-openssl.c b/test-openssl.c index c19839468..f575ec153 100644 --- a/test-openssl.c +++ b/test-openssl.c @@ -32,7 +32,7 @@ int main() { - uint8_t sig[64], pub_key[65], priv_key[32], msg[256], buffer[1000], hash[32], *p; + uint8_t sig[64], pub_key33[33], pub_key65[65], priv_key[32], msg[256], buffer[1000], hash[32], *p; uint32_t i, j, msg_len; SHA256_CTX sha256; EC_GROUP *ecgroup; @@ -78,11 +78,16 @@ int main() ecdsa_sign(priv_key, msg, msg_len, sig); // generate public key from private key - ecdsa_get_public_key65(priv_key, pub_key); + ecdsa_get_public_key33(priv_key, pub_key33); + ecdsa_get_public_key65(priv_key, pub_key65); // use our ECDSA verifier to verify the message signature - if (ecdsa_verify(pub_key, sig, msg, msg_len) != 0) { - printf("MicroECDSA verification failed\n"); + if (ecdsa_verify(pub_key65, sig, msg, msg_len) != 0) { + printf("MicroECDSA verification failed (pub_key_len = 65)\n"); + break; + } + if (ecdsa_verify(pub_key33, sig, msg, msg_len) != 0) { + printf("MicroECDSA verification failed (pub_key_len = 33)\n"); break; } diff --git a/tests.c b/tests.c index 5088b64c8..a0ce7f9f2 100644 --- a/tests.c +++ b/tests.c @@ -49,12 +49,13 @@ uint8_t *fromhex(const char *str) char *tohex(const uint8_t *bin, size_t l) { - static char buf[256], digits[] = "0123456789abcdef"; + static char buf[257], digits[] = "0123456789abcdef"; size_t i; for (i = 0; i < l; i++) { buf[i*2 ] = digits[(bin[i] >> 4) & 0xF]; buf[i*2+1] = digits[bin[i] & 0xF]; } + buf[l * 2] = 0; return buf; } @@ -189,39 +190,60 @@ START_TEST(test_sign_speed) uint8_t sig[64], priv_key[32], msg[256]; int i; - memcpy(priv_key, fromhex("c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd5"), 32); - for (i = 0; i < sizeof(msg); i++) { msg[i] = i * 1103515245; } clock_t t = clock(); - for (i = 0 ; i < 500; i++) { - // use our ECDSA signer to sign the message with the key + + memcpy(priv_key, fromhex("c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd5"), 32); + for (i = 0 ; i < 250; i++) { ecdsa_sign(priv_key, msg, sizeof(msg), sig); } - printf("Signing speed: %0.2f sig/s\n", 1.0f * i / ((float)(clock() - t) / CLOCKS_PER_SEC)); + + memcpy(priv_key, fromhex("509a0382ff5da48e402967a671bdcde70046d07f0df52cff12e8e3883b426a0a"), 32); + for (i = 0 ; i < 250; i++) { + ecdsa_sign(priv_key, msg, sizeof(msg), sig); + } + + printf("Signing speed: %0.2f sig/s\n", 500.0f / ((float)(clock() - t) / CLOCKS_PER_SEC)); } END_TEST START_TEST(test_verify_speed) { - uint8_t sig[64], pub_key[65], msg[256]; + uint8_t sig[64], pub_key33[33], pub_key65[65], msg[256]; int i, res; - memcpy(sig, fromhex("88dc0db6bc5efa762e75fbcc802af69b9f1fcdbdffce748d403f687f855556e610ee8035414099ac7d89cff88a3fa246d332dfa3c78d82c801394112dda039c2"), 70); - memcpy(pub_key, fromhex("044054fd18aeb277aeedea01d3f3986ff4e5be18092a04339dcf4e524e2c0a09746c7083ed2097011b1223a17a644e81f59aa3de22dac119fd980b36a8ff29a244"), 65); for (i = 0; i < sizeof(msg); i++) { msg[i] = i * 1103515245; } clock_t t = clock(); - for (i = 0 ; i < 150; i++) { - // use our ECDSA verifier to verify the message with the key - res = ecdsa_verify(pub_key, sig, msg, sizeof(msg)); + + memcpy(sig, fromhex("88dc0db6bc5efa762e75fbcc802af69b9f1fcdbdffce748d403f687f855556e610ee8035414099ac7d89cff88a3fa246d332dfa3c78d82c801394112dda039c2"), 64); + memcpy(pub_key33, fromhex("024054fd18aeb277aeedea01d3f3986ff4e5be18092a04339dcf4e524e2c0a0974"), 33); + memcpy(pub_key65, fromhex("044054fd18aeb277aeedea01d3f3986ff4e5be18092a04339dcf4e524e2c0a09746c7083ed2097011b1223a17a644e81f59aa3de22dac119fd980b36a8ff29a244"), 65); + + for (i = 0 ; i < 50; i++) { + res = ecdsa_verify(pub_key65, sig, msg, sizeof(msg)); + ck_assert_int_eq(res, 0); + res = ecdsa_verify(pub_key33, sig, msg, sizeof(msg)); + ck_assert_int_eq(res, 0); + } + + memcpy(sig, fromhex("067040a2adb3d9deefeef95dae86f69671968a0b90ee72c2eab54369612fd524eb6756c5a1bb662f1175a5fa888763cddc3a07b8a045ef6ab358d8d5d1a9a745"), 64); + memcpy(pub_key33, fromhex("03ff45a5561a76be930358457d113f25fac790794ec70317eff3b97d7080d45719"), 33); + memcpy(pub_key65, fromhex("04ff45a5561a76be930358457d113f25fac790794ec70317eff3b97d7080d457196235193a15778062ddaa44aef7e6901b781763e52147f2504e268b2d572bf197"), 65); + + for (i = 0 ; i < 50; i++) { + res = ecdsa_verify(pub_key65, sig, msg, sizeof(msg)); + ck_assert_int_eq(res, 0); + res = ecdsa_verify(pub_key33, sig, msg, sizeof(msg)); ck_assert_int_eq(res, 0); } - printf("Verifying speed: %0.2f sig/s\n", 1.0f * i / ((float)(clock() - t) / CLOCKS_PER_SEC)); + + printf("Verifying speed: %0.2f sig/s\n", 200.0f / ((float)(clock() - t) / CLOCKS_PER_SEC)); } END_TEST From 7ed18947bae60b4bacdd9192a27683db3f39b1a4 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 25 Sep 2013 12:39:23 +0200 Subject: [PATCH 031/627] simplify divmod58 --- bignum.c | 44 +++++++++++++------------------------------- bignum.h | 2 +- ecdsa.c | 7 ++----- 3 files changed, 16 insertions(+), 37 deletions(-) diff --git a/bignum.c b/bignum.c index cfce5d7cb..b23bcaf5c 100644 --- a/bignum.c +++ b/bignum.c @@ -502,41 +502,23 @@ void bn_substract_noprime(const bignum256 *a, const bignum256 *b, bignum256 *res res->val[8] = a->val[8] - b->val[8] - carry; } -// a / 58 = q (+r) -void bn_divmod58(const bignum256 *a, bignum256 *q, uint32_t *r) +// a / 58 = a (+r) +void bn_divmod58(bignum256 *a, uint32_t *r) { - bignum256 i58, rem; - int na, i; - - bn_zero(q); - bn_zero(&i58); i58.val[0] = 58; - - if (bn_is_less(a, &i58)) { - *r = a->val[0]; - } - - na = bn_bitlen(a); - - for (i = 0; i < 9; i++) { - rem.val[i] = a->val[i]; - } - - for (i = 0; i <= na - 6; i++) { - bn_lshift(&i58); - } - - for (i = na - 5; i >= 0; --i) { - bn_lshift(q); - if (!bn_is_less(&rem, &i58)) { - bn_substract_noprime(&rem, &i58, &rem); - q->val[0] |= 1; - } - bn_rshift(&i58); + int i; + uint32_t rem, tmp; + rem = a->val[8] % 58; + a->val[8] /= 58; + for (i = 7; i >= 0; i--) { + // 2^30 == 18512790*58 + 4 + tmp = rem * 4 + a->val[i]; + a->val[i] = rem * 18512790 + (tmp / 58); + rem = tmp % 58; } - - *r = rem.val[0]; + *r = rem; } + #if 0 void bn_print(const bignum256 *a) { diff --git a/bignum.h b/bignum.h index 7da67e709..9cbc7890a 100644 --- a/bignum.h +++ b/bignum.h @@ -82,7 +82,7 @@ void bn_substract(const bignum256 *a, const bignum256 *b, bignum256 *res); void bn_substract_noprime(const bignum256 *a, const bignum256 *b, bignum256 *res); -void bn_divmod58(const bignum256 *a, bignum256 *q, uint32_t *r); +void bn_divmod58(bignum256 *a, uint32_t *r); #if 0 void bn_print(const bignum256 *a); diff --git a/ecdsa.c b/ecdsa.c index 7c08474fa..2e2c5aefd 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -279,7 +279,7 @@ void ecdsa_get_address(const uint8_t *pub_key, char version, char *addr) char *p = addr, s; uint8_t a[32], b[21]; uint32_t r; - bignum256 c, q; + bignum256 c; int i, l; SHA256_Raw(pub_key, 33, a); @@ -296,12 +296,9 @@ void ecdsa_get_address(const uint8_t *pub_key, char version, char *addr) bn_read_be(a, &c); while (!bn_is_zero(&c)) { - bn_divmod58(&c, &q, &r); + bn_divmod58(&c, &r); *p = code[r]; p++; - for (i = 0; i < 9; i++) { - c.val[i] = q.val[i]; - } } if (a[0] == 0) { From f4f246f3d7b8a8995c1d6556496ebdb6aec0d680 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 27 Sep 2013 15:42:52 +0200 Subject: [PATCH 032/627] optimize computations --- bignum.c | 42 +++++++++++++++++------------------------- ecdsa.c | 12 +++++++++--- ecdsa.h | 2 +- test-openssl.c | 5 ++++- tests.c | 8 +++++--- 5 files changed, 36 insertions(+), 33 deletions(-) diff --git a/bignum.c b/bignum.c index b23bcaf5c..5856a388f 100644 --- a/bignum.c +++ b/bignum.c @@ -94,13 +94,12 @@ int bn_is_less(const bignum256 *a, const bignum256 *b) } int bn_bitlen(const bignum256 *a) { - int i, r = 0; - for (i = 0; i < 256; i++) { - if (a->val[i / 30] & (1 << (i % 30))) { - r = i; - } - } - return r; + int i = 8, j; + while (i >= 0 && a->val[i] == 0) i--; + if (i == -1) return 0; + j = 29; + while ((a->val[i] & (1 << j)) == 0) j--; + return i * 30 + j + 1; } void bn_lshift(bignum256 *a) @@ -444,15 +443,11 @@ void bn_inverse(bignum256 *x, const bignum256 *prime) void bn_normalize(bignum256 *a) { int i; - uint32_t carry = 0; + uint32_t tmp = 0; for (i = 0; i < 9; i++) { - a->val[i] += carry; - if (a->val[i] > 0x3FFFFFFF) { - carry = a->val[i] >> 30; - a->val[i] &= 0x3FFFFFFF; - } else { - carry = 0; - } + tmp += a->val[i]; + a->val[i] = tmp & 0x3FFFFFFF; + tmp >>= 30; } } @@ -463,12 +458,14 @@ void bn_addmod(bignum256 *a, const bignum256 *b, const bignum256 *prime) a->val[i] += b->val[i]; } bn_normalize(a); + bn_fast_mod(a, prime); bn_mod(a, prime); } void bn_addmodi(bignum256 *a, uint32_t b, const bignum256 *prime) { a->val[0] += b; bn_normalize(a); + bn_fast_mod(a, prime); bn_mod(a, prime); } @@ -489,17 +486,12 @@ void bn_substract(const bignum256 *a, const bignum256 *b, bignum256 *res) void bn_substract_noprime(const bignum256 *a, const bignum256 *b, bignum256 *res) { int i; - char carry = 0; - for (i = 0; i < 8; i++) { - if (a->val[i] >= b->val[i] + carry) { - res->val[i] = a->val[i] - b->val[i] - carry; - carry = 0; - } else { - res->val[i] = a->val[i] + 0x40000000 - b->val[i]; - carry = 1; - } + uint32_t tmp = 1; + for (i = 0; i < 9; i++) { + tmp += 0x3FFFFFFF + a->val[i] - b->val[i]; + res->val[i] = tmp & 0x3FFFFFFF; + tmp >>= 30; } - res->val[8] = a->val[8] - b->val[8] - carry; } // a / 58 = a (+r) diff --git a/ecdsa.c b/ecdsa.c index 2e2c5aefd..d63c5825e 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -195,7 +195,7 @@ void generate_k_rfc6979(bignum256 *secret, const uint8_t *priv_key, const uint8_ // msg is a data to be signed // msg_len is the message length // sig is 64 bytes long array for the signature -void ecdsa_sign(const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig) +int ecdsa_sign(const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig) { uint32_t i; uint8_t hash[32]; @@ -224,7 +224,9 @@ void ecdsa_sign(const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, u for (i = 0; i < 9; i++) { if (R.x.val[i] != 0) break; } - if (i == 9) continue; + if (i == 9) { + return 1; + } bn_inverse(&k, &order256k1); bn_read_be(priv_key, da); bn_multiply(&R.x, da, &order256k1); @@ -239,13 +241,17 @@ void ecdsa_sign(const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, u for (i = 0; i < 9; i++) { if (k.val[i] != 0) break; } - if (i == 9) continue; + if (i == 9) { + return 2; + } // we are done, R.x and k is the result signature break; } bn_write_be(&R.x, sig); bn_write_be(&k, sig + 32); + + return 0; } void ecdsa_get_public_key33(const uint8_t *priv_key, uint8_t *pub_key) diff --git a/ecdsa.h b/ecdsa.h index 7e18c411a..10f1841e3 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -29,7 +29,7 @@ #include "secp256k1.h" // all functions use secp256k1 curve -void ecdsa_sign(const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig); +int ecdsa_sign(const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig); void ecdsa_get_public_key33(const uint8_t *priv_key, uint8_t *pub_key); void ecdsa_get_public_key65(const uint8_t *priv_key, uint8_t *pub_key); void ecdsa_get_address(const uint8_t *pub_key, char version, char *addr); diff --git a/test-openssl.c b/test-openssl.c index f575ec153..ccaefef07 100644 --- a/test-openssl.c +++ b/test-openssl.c @@ -75,7 +75,10 @@ int main() } // use our ECDSA signer to sign the message with the key - ecdsa_sign(priv_key, msg, msg_len, sig); + if (ecdsa_sign(priv_key, msg, msg_len, sig) != 0) { + printf("MicroECDSA signing failed\n"); + break; + } // generate public key from private key ecdsa_get_public_key33(priv_key, pub_key33); diff --git a/tests.c b/tests.c index a0ce7f9f2..493c7023e 100644 --- a/tests.c +++ b/tests.c @@ -188,7 +188,7 @@ END_TEST START_TEST(test_sign_speed) { uint8_t sig[64], priv_key[32], msg[256]; - int i; + int i, res; for (i = 0; i < sizeof(msg); i++) { msg[i] = i * 1103515245; @@ -198,12 +198,14 @@ START_TEST(test_sign_speed) memcpy(priv_key, fromhex("c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd5"), 32); for (i = 0 ; i < 250; i++) { - ecdsa_sign(priv_key, msg, sizeof(msg), sig); + res = ecdsa_sign(priv_key, msg, sizeof(msg), sig); + ck_assert_int_eq(res, 0); } memcpy(priv_key, fromhex("509a0382ff5da48e402967a671bdcde70046d07f0df52cff12e8e3883b426a0a"), 32); for (i = 0 ; i < 250; i++) { - ecdsa_sign(priv_key, msg, sizeof(msg), sig); + res = ecdsa_sign(priv_key, msg, sizeof(msg), sig); + ck_assert_int_eq(res, 0); } printf("Signing speed: %0.2f sig/s\n", 500.0f / ((float)(clock() - t) / CLOCKS_PER_SEC)); From 71ff1c5124f13300bdc6e5c3c5d113f0df260ff5 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 27 Sep 2013 15:55:55 +0200 Subject: [PATCH 033/627] replace infinite loops with loops with counters --- ecdsa.c | 91 +++++++++++++++++++++++++++++++-------------------------- ecdsa.h | 2 +- tests.c | 6 ++-- 3 files changed, 54 insertions(+), 45 deletions(-) diff --git a/ecdsa.c b/ecdsa.c index d63c5825e..fd0e31a4a 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -136,9 +136,9 @@ void scalar_multiply(bignum256 *k, curve_point *res) } // generate random K for signing -void generate_k_random(bignum256 *k) { - int i; - for (;;) { +int generate_k_random(bignum256 *k) { + int i, j; + for (j = 0; j < 10000; j++) { for (i = 0; i < 8; i++) { k->val[i] = random32() & 0x3FFFFFFF; } @@ -146,14 +146,17 @@ void generate_k_random(bignum256 *k) { // if k is too big or too small, we don't like it if (k->val[5] == 0x3FFFFFFF && k->val[6] == 0x3FFFFFFF && k->val[7] == 0x3FFFFFFF && k->val[8] == 0xFFFF) continue; if (k->val[5] == 0x0 && k->val[6] == 0x0 && k->val[7] == 0x0 && k->val[8] == 0x0) continue; - return; + return 0; // good number - no error } + // we generated 10000 numbers, none of them is good -> fail + return 1; } // generate K in a deterministic way, according to RFC6979 // http://tools.ietf.org/html/rfc6979 -void generate_k_rfc6979(bignum256 *secret, const uint8_t *priv_key, const uint8_t *hash) +int generate_k_rfc6979(bignum256 *secret, const uint8_t *priv_key, const uint8_t *hash) { + int i; uint8_t v[32], k[32], bx[2*32], buf[32 + 1 + sizeof(bx)], t[32]; bignum256 z1; @@ -177,17 +180,19 @@ void generate_k_rfc6979(bignum256 *secret, const uint8_t *priv_key, const uint8_ hmac_sha256(k, sizeof(k), buf, sizeof(buf), k); hmac_sha256(k, sizeof(k), v, sizeof(k), v); - for (;;) { + for (i = 0; i < 10000; i++) { hmac_sha256(k, sizeof(k), v, sizeof(v), t); bn_read_be(t, secret); if ( !bn_is_zero(secret) && bn_is_less(secret, &order256k1) ) { - return; + return 0; // good number -> no error } memcpy(buf, v, sizeof(v)); buf[sizeof(v)] = 0x00; hmac_sha256(k, sizeof(k), buf, sizeof(v) + 1, k); hmac_sha256(k, sizeof(k), v, sizeof(v), v); } + // we generated 10000 numbers, none of them is good -> fail + return 1; } // uses secp256k1 curve @@ -208,46 +213,48 @@ int ecdsa_sign(const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, ui // SHA256_Raw(hash, 32, hash); bn_read_be(hash, &z); - for (;;) { - // generate random number k - //generate_k_random(&k); + // generate random number k + //if (generate_k_random(&k) != 0) { + // return 1; + //} - // generate K deterministically - generate_k_rfc6979(&k, priv_key, hash); + // generate K deterministically + if (generate_k_rfc6979(&k, priv_key, hash) != 0) { + return 1; + } - // compute k*G - scalar_multiply(&k, &R); - // r = (rx mod n) - bn_mod(&R.x, &order256k1); - // if r is zero, we try different k - for (i = 0; i < 9; i++) { - if (R.x.val[i] != 0) break; - } - if (i == 9) { - return 1; - } - bn_inverse(&k, &order256k1); - bn_read_be(priv_key, da); - bn_multiply(&R.x, da, &order256k1); - for (i = 0; i < 8; i++) { - da->val[i] += z.val[i]; - da->val[i + 1] += (da->val[i] >> 30); - da->val[i] &= 0x3FFFFFFF; - } - da->val[8] += z.val[8]; - bn_multiply(da, &k, &order256k1); - bn_mod(&k, &order256k1); - for (i = 0; i < 9; i++) { - if (k.val[i] != 0) break; - } - if (i == 9) { - return 2; - } - // we are done, R.x and k is the result signature - break; + // compute k*G + scalar_multiply(&k, &R); + // r = (rx mod n) + bn_mod(&R.x, &order256k1); + // if r is zero, we fail + for (i = 0; i < 9; i++) { + if (R.x.val[i] != 0) break; + } + if (i == 9) { + return 2; + } + bn_inverse(&k, &order256k1); + bn_read_be(priv_key, da); + bn_multiply(&R.x, da, &order256k1); + for (i = 0; i < 8; i++) { + da->val[i] += z.val[i]; + da->val[i + 1] += (da->val[i] >> 30); + da->val[i] &= 0x3FFFFFFF; + } + da->val[8] += z.val[8]; + bn_multiply(da, &k, &order256k1); + bn_mod(&k, &order256k1); + for (i = 0; i < 9; i++) { + if (k.val[i] != 0) break; + } + // if k is zero, we fail + if (i == 9) { + return 3; } + // we are done, R.x and k is the result signature bn_write_be(&R.x, sig); bn_write_be(&k, sig + 32); diff --git a/ecdsa.h b/ecdsa.h index 10f1841e3..9df72d1a9 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -35,6 +35,6 @@ void ecdsa_get_public_key65(const uint8_t *priv_key, uint8_t *pub_key); void ecdsa_get_address(const uint8_t *pub_key, char version, char *addr); int ecdsa_verify(const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, uint32_t msg_len); -void generate_k_rfc6979(bignum256 *secret, const uint8_t *priv_key, const uint8_t *hash); +int generate_k_rfc6979(bignum256 *secret, const uint8_t *priv_key, const uint8_t *hash); #endif diff --git a/tests.c b/tests.c index 493c7023e..ff8b747dc 100644 --- a/tests.c +++ b/tests.c @@ -174,13 +174,15 @@ END_TEST START_TEST(test_rfc6979) { + int res; bignum256 k; uint8_t buf[32]; SHA256_Raw((uint8_t *)"sample", 6, buf); - generate_k_rfc6979(&k, fromhex("cca9fbcc1b41e5a95d369eaa6ddcff73b61a4efaa279cfc6567e8daa39cbaf50"), buf); - bn_write_be(&k, buf); + res = generate_k_rfc6979(&k, fromhex("cca9fbcc1b41e5a95d369eaa6ddcff73b61a4efaa279cfc6567e8daa39cbaf50"), buf); + ck_assert_int_eq(res, 0); + bn_write_be(&k, buf); ck_assert_mem_eq(buf, fromhex("2df40ca70e639d89528a6b670d9d48d9165fdc0febc0974056bdce192b8e16a3"), 32); } END_TEST From e19f7cd2e5be16c9044e991048592ea27fdee681 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 1 Oct 2013 16:45:26 +0200 Subject: [PATCH 034/627] add more rfc6979 test vectors by fpgaminer --- tests.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/tests.c b/tests.c index ff8b747dc..2f0916edb 100644 --- a/tests.c +++ b/tests.c @@ -181,9 +181,32 @@ START_TEST(test_rfc6979) SHA256_Raw((uint8_t *)"sample", 6, buf); res = generate_k_rfc6979(&k, fromhex("cca9fbcc1b41e5a95d369eaa6ddcff73b61a4efaa279cfc6567e8daa39cbaf50"), buf); ck_assert_int_eq(res, 0); - bn_write_be(&k, buf); ck_assert_mem_eq(buf, fromhex("2df40ca70e639d89528a6b670d9d48d9165fdc0febc0974056bdce192b8e16a3"), 32); + + SHA256_Raw((uint8_t *)"Satoshi Nakamoto", 16, buf); + res = generate_k_rfc6979(&k, fromhex("0000000000000000000000000000000000000000000000000000000000000001"), buf); + ck_assert_int_eq(res, 0); + bn_write_be(&k, buf); + ck_assert_mem_eq(buf, fromhex("8f8a276c19f4149656b280621e358cce24f5f52542772691ee69063b74f15d15"), 32); + + SHA256_Raw((uint8_t *)"Satoshi Nakamoto", 16, buf); + res = generate_k_rfc6979(&k, fromhex("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140"), buf); + ck_assert_int_eq(res, 0); + bn_write_be(&k, buf); + ck_assert_mem_eq(buf, fromhex("33a19b60e25fb6f4435af53a3d42d493644827367e6453928554f43e49aa6f90"), 32); + + SHA256_Raw((uint8_t *)"Alan Turing", 11, buf); + res = generate_k_rfc6979(&k, fromhex("f8b8af8ce3c7cca5e300d33939540c10d45ce001b8f252bfbc57ba0342904181"), buf); + ck_assert_int_eq(res, 0); + bn_write_be(&k, buf); + ck_assert_mem_eq(buf, fromhex("525a82b70e67874398067543fd84c83d30c175fdc45fdeee082fe13b1d7cfdf1"), 32); + + SHA256_Raw((uint8_t *)"All those moments will be lost in time, like tears in rain. Time to die...", 74, buf); + res = generate_k_rfc6979(&k, fromhex("0000000000000000000000000000000000000000000000000000000000000001"), buf); + ck_assert_int_eq(res, 0); + bn_write_be(&k, buf); + ck_assert_mem_eq(buf, fromhex("38aa22d72376b4dbc472e06c3ba403ee0a394da63fc58d88686c611aba98d6b3"), 32); } END_TEST From 1691d5cc8c8bbb7e074a7876fb678dbec5717241 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 1 Oct 2013 18:08:33 +0200 Subject: [PATCH 035/627] small cleanup --- ecdsa.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ecdsa.c b/ecdsa.c index fd0e31a4a..24b07e5ce 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -326,7 +326,7 @@ void ecdsa_get_address(const uint8_t *pub_key, char version, char *addr) for (i = 0; i < l / 2; i++) { s = addr[i]; addr[i] = addr[l - 1 - i]; - addr[l - 1 - i] = s;; + addr[l - 1 - i] = s; } } @@ -343,7 +343,6 @@ int ecdsa_verify(const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, uint8_t hash[32]; curve_point pub, res; bignum256 r, s, z; - int res_is_zero = 0; // compute hash function of message SHA256_Raw(msg, msg_len, hash); // if double hash is required uncomment the following line: @@ -386,7 +385,7 @@ int ecdsa_verify(const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, if (bn_is_zero(&z)) { // our message hashes to zero // I don't expect this to happen any time soon - res_is_zero = 1; + return 3; } else { scalar_multiply(&z, &res); } From 3d163fc29be7784014af42ea40522dbd2b78014c Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 1 Oct 2013 18:13:25 +0200 Subject: [PATCH 036/627] move speed-stm32 to trezor repo --- README | 3 - speed-stm32/.gitignore | 7 - speed-stm32/Makefile | 16 -- speed-stm32/Makefile.include | 91 ------------ speed-stm32/rand.c | 17 --- speed-stm32/speed.c | 274 ----------------------------------- speed-stm32/speed.ld | 9 -- 7 files changed, 417 deletions(-) delete mode 100644 speed-stm32/.gitignore delete mode 100644 speed-stm32/Makefile delete mode 100644 speed-stm32/Makefile.include delete mode 100644 speed-stm32/rand.c delete mode 100644 speed-stm32/speed.c delete mode 100644 speed-stm32/speed.ld diff --git a/README b/README index db54e3eb1..dc7e963eb 100644 --- a/README +++ b/README @@ -13,6 +13,3 @@ a) the signer only understands secp256k1 elliptic curve b) unit tests using Check (check.sf.net) are in tests.c c) tests against OpenSSL are in test-openssl.c - -d) directory speed-stm32 contains project for deploying the code - on STM32 microcontroller and checking signing speed there diff --git a/speed-stm32/.gitignore b/speed-stm32/.gitignore deleted file mode 100644 index 73f188b62..000000000 --- a/speed-stm32/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -*.o -*.d -*.bin -*.hex -*.srec -*.list -*.elf diff --git a/speed-stm32/Makefile b/speed-stm32/Makefile deleted file mode 100644 index 94560dfe0..000000000 --- a/speed-stm32/Makefile +++ /dev/null @@ -1,16 +0,0 @@ -NAME = speed - -OBJS += rand.o -OBJS += speed.o - -OBJS += ../bignum.o -OBJS += ../bip32.o -OBJS += ../ecdsa.o -OBJS += ../hmac.o -OBJS += ../ripemd160.o -OBJS += ../secp256k1.o -OBJS += ../sha2.o - -include Makefile.include - -CFLAGS += -I.. diff --git a/speed-stm32/Makefile.include b/speed-stm32/Makefile.include deleted file mode 100644 index cdf2b406d..000000000 --- a/speed-stm32/Makefile.include +++ /dev/null @@ -1,91 +0,0 @@ -APPIFY ?= 0 -PREFIX ?= arm-none-eabi- -CC = $(PREFIX)gcc -LD = $(PREFIX)gcc -OBJCOPY = $(PREFIX)objcopy -OBJDUMP = $(PREFIX)objdump -FLASH = st-flash -OPENOCD = openocd -TOP_DIR = /home/stick/work/trezor/trezor-mcu -TOOLCHAIN_DIR = /home/stick/work/STM/libopencm3 - -OPTFLAGS = -Os -g - -CFLAGS += $(OPTFLAGS) \ - -Wall \ - -Wextra \ - -Wimplicit-function-declaration \ - -Wredundant-decls \ - -Wstrict-prototypes \ - -Wundef \ - -Wshadow \ - -fno-common \ - -mcpu=cortex-m3 \ - -mthumb \ - -msoft-float \ - -DSTM32F2 \ - -I$(TOOLCHAIN_DIR)/include \ - -I$(TOP_DIR) \ - -DAPPIFY=$(APPIFY) - -LDSCRIPT = $(TOP_DIR)/layout$(APPIFY).ld - -LDFLAGS += --static \ - -Wl,--start-group \ - -lc \ - -lgcc \ - -lnosys \ - -Wl,--end-group \ - -L$(TOP_DIR) \ - -L$(TOOLCHAIN_DIR)/lib \ - -L$(TOOLCHAIN_DIR)/lib/stm32/f2 \ - -T$(LDSCRIPT) \ - -nostartfiles \ - -Wl,--gc-sections \ - -mthumb \ - -march=armv7 \ - -mfix-cortex-m3-ldrd \ - -msoft-float - -all: $(NAME).bin - -flash: $(NAME).bin - $(FLASH) write $(NAME).bin 0x8000000 - -flash2: $(NAME).hex - $(OPENOCD) -f board/stm32f4discovery.cfg \ - -c "init" \ - -c "reset init" \ - -c "stm32f2x mass_erase 0" \ - -c "flash write_image $(NAME).hex" \ - -c "reset" \ - -c "shutdown" - -$(NAME).bin: $(NAME).elf - $(OBJCOPY) -Obinary $(NAME).elf $(NAME).bin - -$(NAME).hex: $(NAME).elf - $(OBJCOPY) -Oihex $(NAME).elf $(NAME).hex - -$(NAME).srec: $(NAME).elf - $(OBJCOPY) -Osrec $(NAME).elf $(NAME).srec - -$(NAME).list: $(NAME).elf - $(OBJDUMP) -S $(NAME).elf > $(NAME).list - -$(NAME).elf: $(OBJS) $(LDSCRIPT) $(TOOLCHAIN_DIR)/lib/libopencm3_stm32f2.a - $(LD) -o $(NAME).elf $(OBJS) -lopencm3_stm32f2 $(LDFLAGS) - -%.o: %.c Makefile - $(CC) $(CFLAGS) -o $@ -c $< - -clean: - rm -f *.a - rm -f *.o - rm -f *.d - rm -f *.elf - rm -f *.bin - rm -f *.hex - rm -f *.srec - rm -f *.list - rm -f usb.pb* diff --git a/speed-stm32/rand.c b/speed-stm32/rand.c deleted file mode 100644 index 3aaa7be72..000000000 --- a/speed-stm32/rand.c +++ /dev/null @@ -1,17 +0,0 @@ -#include -#include "rand.h" - -void init_rand(void) { - RNG_CR |= RNG_CR_IE | RNG_CR_RNGEN; -} - -uint32_t random32(void) { - static uint32_t last = 0, new = 0; - while (new == last) { - if (((RNG_SR & (RNG_SR_SEIS | RNG_SR_CEIS)) == 0) && ((RNG_SR & RNG_SR_DRDY) > 0)) { - new = RNG_DR; - } - } - last = new; - return new; -} diff --git a/speed-stm32/speed.c b/speed-stm32/speed.c deleted file mode 100644 index 44835de68..000000000 --- a/speed-stm32/speed.c +++ /dev/null @@ -1,274 +0,0 @@ -/* - * This file is part of the libopencm3 project. - * - * Copyright (C) 2010 Gareth McMullin - * - * This library is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "rand.h" -#include "ecdsa.h" - -static const struct usb_device_descriptor dev = { - .bLength = USB_DT_DEVICE_SIZE, - .bDescriptorType = USB_DT_DEVICE, - .bcdUSB = 0x0200, - .bDeviceClass = USB_CLASS_CDC, - .bDeviceSubClass = 0, - .bDeviceProtocol = 0, - .bMaxPacketSize0 = 64, - .idVendor = 0x0483, - .idProduct = 0x5740, - .bcdDevice = 0x0200, - .iManufacturer = 1, - .iProduct = 2, - .iSerialNumber = 3, - .bNumConfigurations = 1, -}; - -/* - * This notification endpoint isn't implemented. According to CDC spec it's - * optional, but its absence causes a NULL pointer dereference in the - * Linux cdc_acm driver. - */ -static const struct usb_endpoint_descriptor comm_endp[] = {{ - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = 0x83, - .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, - .wMaxPacketSize = 16, - .bInterval = 255, -}}; - -static const struct usb_endpoint_descriptor data_endp[] = {{ - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = 0x01, - .bmAttributes = USB_ENDPOINT_ATTR_BULK, - .wMaxPacketSize = 64, - .bInterval = 1, -}, { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = 0x82, - .bmAttributes = USB_ENDPOINT_ATTR_BULK, - .wMaxPacketSize = 64, - .bInterval = 1, -}}; - -static const struct { - struct usb_cdc_header_descriptor header; - struct usb_cdc_call_management_descriptor call_mgmt; - struct usb_cdc_acm_descriptor acm; - struct usb_cdc_union_descriptor cdc_union; -} __attribute__((packed)) cdcacm_functional_descriptors = { - .header = { - .bFunctionLength = sizeof(struct usb_cdc_header_descriptor), - .bDescriptorType = CS_INTERFACE, - .bDescriptorSubtype = USB_CDC_TYPE_HEADER, - .bcdCDC = 0x0110, - }, - .call_mgmt = { - .bFunctionLength = - sizeof(struct usb_cdc_call_management_descriptor), - .bDescriptorType = CS_INTERFACE, - .bDescriptorSubtype = USB_CDC_TYPE_CALL_MANAGEMENT, - .bmCapabilities = 0, - .bDataInterface = 1, - }, - .acm = { - .bFunctionLength = sizeof(struct usb_cdc_acm_descriptor), - .bDescriptorType = CS_INTERFACE, - .bDescriptorSubtype = USB_CDC_TYPE_ACM, - .bmCapabilities = 0, - }, - .cdc_union = { - .bFunctionLength = sizeof(struct usb_cdc_union_descriptor), - .bDescriptorType = CS_INTERFACE, - .bDescriptorSubtype = USB_CDC_TYPE_UNION, - .bControlInterface = 0, - .bSubordinateInterface0 = 1, - } -}; - -static const struct usb_interface_descriptor comm_iface[] = {{ - .bLength = USB_DT_INTERFACE_SIZE, - .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = 0, - .bAlternateSetting = 0, - .bNumEndpoints = 1, - .bInterfaceClass = USB_CLASS_CDC, - .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM, - .bInterfaceProtocol = USB_CDC_PROTOCOL_AT, - .iInterface = 0, - - .endpoint = comm_endp, - - .extra = &cdcacm_functional_descriptors, - .extralen = sizeof(cdcacm_functional_descriptors) -}}; - -static const struct usb_interface_descriptor data_iface[] = {{ - .bLength = USB_DT_INTERFACE_SIZE, - .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = 1, - .bAlternateSetting = 0, - .bNumEndpoints = 2, - .bInterfaceClass = USB_CLASS_DATA, - .bInterfaceSubClass = 0, - .bInterfaceProtocol = 0, - .iInterface = 0, - - .endpoint = data_endp, -}}; - -static const struct usb_interface ifaces[] = {{ - .num_altsetting = 1, - .altsetting = comm_iface, -}, { - .num_altsetting = 1, - .altsetting = data_iface, -}}; - -static const struct usb_config_descriptor config = { - .bLength = USB_DT_CONFIGURATION_SIZE, - .bDescriptorType = USB_DT_CONFIGURATION, - .wTotalLength = 0, - .bNumInterfaces = 2, - .bConfigurationValue = 1, - .iConfiguration = 0, - .bmAttributes = 0x80, - .bMaxPower = 0x32, - - .interface = ifaces, -}; - -static const char *usb_strings[] = { - "Black Sphere Technologies", - "CDC-ACM Demo", - "DEMO", -}; - -/* Buffer to be used for control requests. */ -uint8_t usbd_control_buffer[128]; - -static int cdcacm_control_request(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf, - uint16_t *len, void (**complete)(usbd_device *usbd_dev, struct usb_setup_data *req)) -{ - (void)complete; - (void)buf; - (void)usbd_dev; - - switch (req->bRequest) { - case USB_CDC_REQ_SET_CONTROL_LINE_STATE: { - /* - * This Linux cdc_acm driver requires this to be implemented - * even though it's optional in the CDC spec, and we don't - * advertise it in the ACM functional descriptor. - */ - return 1; - } - case USB_CDC_REQ_SET_LINE_CODING: - if (*len < sizeof(struct usb_cdc_line_coding)) - return 0; - - return 1; - } - return 0; -} - -static void cdcacm_data_rx_cb(usbd_device *usbd_dev, uint8_t ep) -{ - (void)ep; - - char buf[64]; - - int len = usbd_ep_read_packet(usbd_dev, 0x01, buf, 64); - - if (len) { - uint8_t sig[64], priv_key[32], msg[256]; - uint32_t i, msg_len; - - // random message len between 1 and 256 - msg_len = (random32() & 0xFF) + 1; - // create random message - for (i = 0; i < msg_len; i++) { - msg[i] = random32() & 0xFF; - } - // create random privkey - for (i = 0; i < 8; i++) { - uint32_t r = random32(); - priv_key[4 * i ] = r & 0xFF; - priv_key[4 * i + 1] = (r >> 8) & 0xFF; - priv_key[4 * i + 2] = (r >> 16) & 0xFF; - priv_key[4 * i + 3] = (r >> 24) & 0xFF; - } - - len = sprintf(buf, "Start\r\n"); - usbd_ep_write_packet(usbd_dev, 0x82, buf, len); - - // use our ECDSA signer 10 times to sign the message with the key - for (i = 0; i < 10; i++) { - ecdsa_sign(priv_key, msg, msg_len, sig); - } - - len = sprintf(buf, "Done!\r\n"); - usbd_ep_write_packet(usbd_dev, 0x82, buf, len); - } -} - -static void cdcacm_set_config(usbd_device *usbd_dev, uint16_t wValue) -{ - (void)wValue; - - usbd_ep_setup(usbd_dev, 0x01, USB_ENDPOINT_ATTR_BULK, 64, cdcacm_data_rx_cb); - usbd_ep_setup(usbd_dev, 0x82, USB_ENDPOINT_ATTR_BULK, 64, NULL); - usbd_ep_setup(usbd_dev, 0x83, USB_ENDPOINT_ATTR_INTERRUPT, 16, NULL); - - usbd_register_control_callback( - usbd_dev, - USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE, - USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, - cdcacm_control_request); -} - -int main(void) -{ - usbd_device *usbd_dev; - - rcc_clock_setup_hse_3v3(&hse_8mhz_3v3[CLOCK_3V3_120MHZ]); - - rcc_peripheral_enable_clock(&RCC_AHB1ENR, RCC_AHB1ENR_IOPAEN); - rcc_peripheral_enable_clock(&RCC_AHB2ENR, RCC_AHB2ENR_OTGFSEN); - rcc_peripheral_enable_clock(&RCC_AHB2ENR, RCC_AHB2ENR_RNGEN); - init_rand(); - - gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO9 | GPIO11 | GPIO12); - gpio_set_af(GPIOA, GPIO_AF10, GPIO9 | GPIO11 | GPIO12); - - usbd_dev = usbd_init(&otgfs_usb_driver, &dev, &config, usb_strings, 3, usbd_control_buffer, sizeof(usbd_control_buffer)); - usbd_register_set_config_callback(usbd_dev, cdcacm_set_config); - - while (1) - usbd_poll(usbd_dev); -} diff --git a/speed-stm32/speed.ld b/speed-stm32/speed.ld deleted file mode 100644 index 539837839..000000000 --- a/speed-stm32/speed.ld +++ /dev/null @@ -1,9 +0,0 @@ -/* STM32F205RE - 512K Flash, 128K RAM */ - -MEMORY -{ - rom (rx) : ORIGIN = 0x08000000, LENGTH = 512K - ram (rwx) : ORIGIN = 0x20000000, LENGTH = 128K -} - -INCLUDE libopencm3_stm32f2.ld From 678e5b1af2ba26051ed7618c6e8d2a029fb024cc Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 3 Oct 2013 17:32:27 +0200 Subject: [PATCH 037/627] use #if instead of #ifdef for conditional macros --- bignum.c | 9 ++++----- bignum.h | 9 ++++++++- ecdsa.c | 8 ++++---- ripemd160.c | 4 ---- secp256k1.c | 8 ++------ secp256k1.h | 4 ++-- 6 files changed, 20 insertions(+), 22 deletions(-) diff --git a/bignum.c b/bignum.c index 5856a388f..bcfbe88e7 100644 --- a/bignum.c +++ b/bignum.c @@ -237,10 +237,10 @@ void bn_sqrt(bignum256 *x, const bignum256 *prime) memcpy(x, &res, sizeof(bignum256)); } -#ifndef INVERSE_FAST +#if ! USE_INVERSE_FAST -#ifdef USE_PRECOMPUTED_IV -#warning USE_PRECOMPUTED_IV will not be used, please undef +#if USE_PRECOMPUTED_IV +#warning USE_PRECOMPUTED_IV will not be used #endif // in field G_prime, small but slow @@ -405,7 +405,7 @@ void bn_inverse(bignum256 *x, const bignum256 *prime) temp >>= 30; } int done = 0; -#ifdef USE_PRECOMPUTED_IV +#if USE_PRECOMPUTED_IV if (prime == &prime256k1) { for (j = 0; j < 9; j++) { x->val[j] = r[j]; @@ -510,7 +510,6 @@ void bn_divmod58(bignum256 *a, uint32_t *r) *r = rem; } - #if 0 void bn_print(const bignum256 *a) { diff --git a/bignum.h b/bignum.h index 9cbc7890a..c9eeb1d64 100644 --- a/bignum.h +++ b/bignum.h @@ -27,12 +27,19 @@ #include // use precomputed Inverse Values of powers of two +#ifndef USE_PRECOMPUTED_IV #define USE_PRECOMPUTED_IV 1 +#endif // use precomputed Curve Points (some scalar multiples of curve base point G) +#ifndef USE_PRECOMPUTED_CP #define USE_PRECOMPUTED_CP 1 +#endif -#define INVERSE_FAST 1 +// use fast inverse method +#ifndef USE_INVERSE_FAST +#define USE_INVERSE_FAST 1 +#endif // bignum256 are 256 bits stored as 8*30 bit + 1*16 bit // val[0] are lowest 30 bits, val[8] highest 16 bits diff --git a/ecdsa.c b/ecdsa.c index 24b07e5ce..5b3a213d5 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -98,7 +98,7 @@ void scalar_multiply(bignum256 *k, curve_point *res) int i, j; // result is zero int is_zero = 1; -#ifdef USE_PRECOMPUTED_CP +#if USE_PRECOMPUTED_CP int exp = 0; #else curve_point curr; @@ -110,21 +110,21 @@ void scalar_multiply(bignum256 *k, curve_point *res) if (i == 8 && (k->val[i] >> j) == 0) break; if (k->val[i] & (1u << j)) { if (is_zero) { -#ifdef USE_PRECOMPUTED_CP +#if USE_PRECOMPUTED_CP memcpy(res, secp256k1_cp + exp, sizeof(curve_point)); #else memcpy(res, &curr, sizeof(curve_point)); #endif is_zero = 0; } else { -#ifdef USE_PRECOMPUTED_CP +#if USE_PRECOMPUTED_CP point_add(secp256k1_cp + exp, res); #else point_add(&curr, res); #endif } } -#ifdef USE_PRECOMPUTED_CP +#if USE_PRECOMPUTED_CP exp++; #else point_double(&curr); diff --git a/ripemd160.c b/ripemd160.c index f6b849b8b..1d767b7e1 100644 --- a/ripemd160.c +++ b/ripemd160.c @@ -61,10 +61,6 @@ (c) = ROL((c), 10);\ } - -static void compress(uint32_t *MDbuf, uint32_t *X); - - static void compress(uint32_t *MDbuf, uint32_t *X) { uint32_t aa = MDbuf[0], bb = MDbuf[1], cc = MDbuf[2], dd = MDbuf[3], ee = MDbuf[4]; diff --git a/secp256k1.c b/secp256k1.c index 6149afec8..5917456fc 100644 --- a/secp256k1.c +++ b/secp256k1.c @@ -37,8 +37,7 @@ const bignum256 order256k1 = { const bignum256 three_over_two256k1 = { .val = {0x3ffffe19, 0x3ffffffd, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x7fff}}; -#ifdef USE_PRECOMPUTED_IV - +#if USE_PRECOMPUTED_IV const bignum256 secp256k1_iv[256] = { { .val = {0x868192a, 0x20e02474, 0x24a059d, 0x2c88ffb7, 0x32b761bc, 0x1b0b0a57, 0x383999c4, 0x6414554, 0xc9bd}}, { .val = {0x4340c95, 0x3070123a, 0x212502ce, 0x16447fdb, 0x395bb0de, 0xd85852b, 0x1c1ccce2, 0x2320a2aa, 0x64de}}, @@ -297,11 +296,9 @@ const bignum256 secp256k1_iv[256] = { { .val = {0x29c913e4, 0x91b0be0, 0x1fceee6b, 0x215332a, 0x14a31ed9, 0x2e13d0c0, 0x11882581, 0x3d449f71, 0xd708}}, { .val = {0x14e489f2, 0x248d85f0, 0xfe77735, 0x210a9995, 0xa518f6c, 0x3709e860, 0x28c412c0, 0x1ea24fb8, 0x6b84}}, }; - #endif -#ifdef USE_PRECOMPUTED_CP - +#if USE_PRECOMPUTED_CP const curve_point secp256k1_cp[256] = { {.x = { .val = {0x16f81798, 0x27ca056c, 0x1ce28d95, 0x26ff36cb, 0x70b0702, 0x18a573a, 0xbbac55a, 0x199fbe77, 0x79be}}, .y = { .val = {0x3b10d4b8, 0x311f423f, 0x28554199, 0x5ed1229, 0x1108a8fd, 0x13eff038, 0x3c4655da, 0x369dc9a8, 0x483a}}}, @@ -816,5 +813,4 @@ const curve_point secp256k1_cp[256] = { {.x = { .val = {0x3f8be384, 0x22f4c810, 0x31db6c3e, 0x3b02ab68, 0x1ef07271, 0x2b5b253f, 0x23e1b251, 0x24290af9, 0xb237}}, .y = { .val = {0x2b19880e, 0x4291cf7, 0x9ecb58d, 0x3c013d05, 0x1f94517, 0x143e22aa, 0x15edbe8d, 0x1a524675, 0xfc6b}}}, }; - #endif diff --git a/secp256k1.h b/secp256k1.h index cf5a53df8..fea7e85ae 100644 --- a/secp256k1.h +++ b/secp256k1.h @@ -45,11 +45,11 @@ extern const bignum256 order256k1; // 3/2 in G_p extern const bignum256 three_over_two256k1; -#ifdef USE_PRECOMPUTED_IV +#if USE_PRECOMPUTED_IV extern const bignum256 secp256k1_iv[256]; #endif -#ifdef USE_PRECOMPUTED_CP +#if USE_PRECOMPUTED_CP extern const curve_point secp256k1_cp[256]; #endif From f87e7064071b0f730922f533f565038c7973ebf6 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 3 Oct 2013 18:19:30 +0200 Subject: [PATCH 038/627] add define for RFC6979 --- ecdsa.c | 18 ++++++++++-------- ecdsa.h | 4 ++++ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/ecdsa.c b/ecdsa.c index 5b3a213d5..0ac4ef28b 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -144,9 +144,9 @@ int generate_k_random(bignum256 *k) { } k->val[8] = random32() & 0xFFFF; // if k is too big or too small, we don't like it - if (k->val[5] == 0x3FFFFFFF && k->val[6] == 0x3FFFFFFF && k->val[7] == 0x3FFFFFFF && k->val[8] == 0xFFFF) continue; - if (k->val[5] == 0x0 && k->val[6] == 0x0 && k->val[7] == 0x0 && k->val[8] == 0x0) continue; - return 0; // good number - no error + if ( !bn_is_zero(k) && bn_is_less(k, &order256k1) ) { + return 0; // good number - no error + } } // we generated 10000 numbers, none of them is good -> fail return 1; @@ -214,15 +214,17 @@ int ecdsa_sign(const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, ui bn_read_be(hash, &z); - // generate random number k - //if (generate_k_random(&k) != 0) { - // return 1; - //} - +#if USE_RFC6979 // generate K deterministically if (generate_k_rfc6979(&k, priv_key, hash) != 0) { return 1; } +#else + // generate random number k + if (generate_k_random(&k) != 0) { + return 1; + } +#endif // compute k*G scalar_multiply(&k, &R); diff --git a/ecdsa.h b/ecdsa.h index 9df72d1a9..fc0acbba6 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -28,6 +28,10 @@ #include "secp256k1.h" +#ifndef USE_RFC6979 +#define USE_RFC6979 1 +#endif + // all functions use secp256k1 curve int ecdsa_sign(const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig); void ecdsa_get_public_key33(const uint8_t *priv_key, uint8_t *pub_key); From 7e41c2a5684b7038b401d6283c734b9221caae02 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 7 Oct 2013 21:10:39 +0200 Subject: [PATCH 039/627] add blowfish algo with tests --- Makefile | 2 +- blowfish.c | 375 +++++++++++++++++++++++++++++++++++++++++++++++++++++ blowfish.h | 10 ++ tests.c | 19 +++ 4 files changed, 405 insertions(+), 1 deletion(-) create mode 100644 blowfish.c create mode 100644 blowfish.h diff --git a/Makefile b/Makefile index ed1fed844..ace51a0d0 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ CC = gcc CFLAGS = -Wall -Os -OBJS = bignum.o ecdsa.o secp256k1.o sha2.o rand.o hmac.o bip32.o ripemd160.o +OBJS = bignum.o ecdsa.o secp256k1.o sha2.o rand.o hmac.o bip32.o ripemd160.o blowfish.o all: tests test-openssl diff --git a/blowfish.c b/blowfish.c new file mode 100644 index 000000000..a80ef5f61 --- /dev/null +++ b/blowfish.c @@ -0,0 +1,375 @@ +#include +#include "blowfish.h" + +static const uint32_t P_orig[16 + 2] = { + 0x243F6A88, 0x85A308D3, 0x13198A2E, 0x03707344, + 0xA4093822, 0x299F31D0, 0x082EFA98, 0xEC4E6C89, + 0x452821E6, 0x38D01377, 0xBE5466CF, 0x34E90C6C, + 0xC0AC29B7, 0xC97C50DD, 0x3F84D5B5, 0xB5470917, + 0x9216D5D9, 0x8979FB1B, +}; + +static const uint32_t S_orig[4][256] = {{ + 0xD1310BA6, 0x98DFB5AC, 0x2FFD72DB, 0xD01ADFB7, + 0xB8E1AFED, 0x6A267E96, 0xBA7C9045, 0xF12C7F99, + 0x24A19947, 0xB3916CF7, 0x0801F2E2, 0x858EFC16, + 0x636920D8, 0x71574E69, 0xA458FEA3, 0xF4933D7E, + 0x0D95748F, 0x728EB658, 0x718BCD58, 0x82154AEE, + 0x7B54A41D, 0xC25A59B5, 0x9C30D539, 0x2AF26013, + 0xC5D1B023, 0x286085F0, 0xCA417918, 0xB8DB38EF, + 0x8E79DCB0, 0x603A180E, 0x6C9E0E8B, 0xB01E8A3E, + 0xD71577C1, 0xBD314B27, 0x78AF2FDA, 0x55605C60, + 0xE65525F3, 0xAA55AB94, 0x57489862, 0x63E81440, + 0x55CA396A, 0x2AAB10B6, 0xB4CC5C34, 0x1141E8CE, + 0xA15486AF, 0x7C72E993, 0xB3EE1411, 0x636FBC2A, + 0x2BA9C55D, 0x741831F6, 0xCE5C3E16, 0x9B87931E, + 0xAFD6BA33, 0x6C24CF5C, 0x7A325381, 0x28958677, + 0x3B8F4898, 0x6B4BB9AF, 0xC4BFE81B, 0x66282193, + 0x61D809CC, 0xFB21A991, 0x487CAC60, 0x5DEC8032, + 0xEF845D5D, 0xE98575B1, 0xDC262302, 0xEB651B88, + 0x23893E81, 0xD396ACC5, 0x0F6D6FF3, 0x83F44239, + 0x2E0B4482, 0xA4842004, 0x69C8F04A, 0x9E1F9B5E, + 0x21C66842, 0xF6E96C9A, 0x670C9C61, 0xABD388F0, + 0x6A51A0D2, 0xD8542F68, 0x960FA728, 0xAB5133A3, + 0x6EEF0B6C, 0x137A3BE4, 0xBA3BF050, 0x7EFB2A98, + 0xA1F1651D, 0x39AF0176, 0x66CA593E, 0x82430E88, + 0x8CEE8619, 0x456F9FB4, 0x7D84A5C3, 0x3B8B5EBE, + 0xE06F75D8, 0x85C12073, 0x401A449F, 0x56C16AA6, + 0x4ED3AA62, 0x363F7706, 0x1BFEDF72, 0x429B023D, + 0x37D0D724, 0xD00A1248, 0xDB0FEAD3, 0x49F1C09B, + 0x075372C9, 0x80991B7B, 0x25D479D8, 0xF6E8DEF7, + 0xE3FE501A, 0xB6794C3B, 0x976CE0BD, 0x04C006BA, + 0xC1A94FB6, 0x409F60C4, 0x5E5C9EC2, 0x196A2463, + 0x68FB6FAF, 0x3E6C53B5, 0x1339B2EB, 0x3B52EC6F, + 0x6DFC511F, 0x9B30952C, 0xCC814544, 0xAF5EBD09, + 0xBEE3D004, 0xDE334AFD, 0x660F2807, 0x192E4BB3, + 0xC0CBA857, 0x45C8740F, 0xD20B5F39, 0xB9D3FBDB, + 0x5579C0BD, 0x1A60320A, 0xD6A100C6, 0x402C7279, + 0x679F25FE, 0xFB1FA3CC, 0x8EA5E9F8, 0xDB3222F8, + 0x3C7516DF, 0xFD616B15, 0x2F501EC8, 0xAD0552AB, + 0x323DB5FA, 0xFD238760, 0x53317B48, 0x3E00DF82, + 0x9E5C57BB, 0xCA6F8CA0, 0x1A87562E, 0xDF1769DB, + 0xD542A8F6, 0x287EFFC3, 0xAC6732C6, 0x8C4F5573, + 0x695B27B0, 0xBBCA58C8, 0xE1FFA35D, 0xB8F011A0, + 0x10FA3D98, 0xFD2183B8, 0x4AFCB56C, 0x2DD1D35B, + 0x9A53E479, 0xB6F84565, 0xD28E49BC, 0x4BFB9790, + 0xE1DDF2DA, 0xA4CB7E33, 0x62FB1341, 0xCEE4C6E8, + 0xEF20CADA, 0x36774C01, 0xD07E9EFE, 0x2BF11FB4, + 0x95DBDA4D, 0xAE909198, 0xEAAD8E71, 0x6B93D5A0, + 0xD08ED1D0, 0xAFC725E0, 0x8E3C5B2F, 0x8E7594B7, + 0x8FF6E2FB, 0xF2122B64, 0x8888B812, 0x900DF01C, + 0x4FAD5EA0, 0x688FC31C, 0xD1CFF191, 0xB3A8C1AD, + 0x2F2F2218, 0xBE0E1777, 0xEA752DFE, 0x8B021FA1, + 0xE5A0CC0F, 0xB56F74E8, 0x18ACF3D6, 0xCE89E299, + 0xB4A84FE0, 0xFD13E0B7, 0x7CC43B81, 0xD2ADA8D9, + 0x165FA266, 0x80957705, 0x93CC7314, 0x211A1477, + 0xE6AD2065, 0x77B5FA86, 0xC75442F5, 0xFB9D35CF, + 0xEBCDAF0C, 0x7B3E89A0, 0xD6411BD3, 0xAE1E7E49, + 0x00250E2D, 0x2071B35E, 0x226800BB, 0x57B8E0AF, + 0x2464369B, 0xF009B91E, 0x5563911D, 0x59DFA6AA, + 0x78C14389, 0xD95A537F, 0x207D5BA2, 0x02E5B9C5, + 0x83260376, 0x6295CFA9, 0x11C81968, 0x4E734A41, + 0xB3472DCA, 0x7B14A94A, 0x1B510052, 0x9A532915, + 0xD60F573F, 0xBC9BC6E4, 0x2B60A476, 0x81E67400, + 0x08BA6FB5, 0x571BE91F, 0xF296EC6B, 0x2A0DD915, + 0xB6636521, 0xE7B9F9B6, 0xFF34052E, 0xC5855664, + 0x53B02D5D, 0xA99F8FA1, 0x08BA4799, 0x6E85076A, + },{ + 0x4B7A70E9, 0xB5B32944, 0xDB75092E, 0xC4192623, + 0xAD6EA6B0, 0x49A7DF7D, 0x9CEE60B8, 0x8FEDB266, + 0xECAA8C71, 0x699A17FF, 0x5664526C, 0xC2B19EE1, + 0x193602A5, 0x75094C29, 0xA0591340, 0xE4183A3E, + 0x3F54989A, 0x5B429D65, 0x6B8FE4D6, 0x99F73FD6, + 0xA1D29C07, 0xEFE830F5, 0x4D2D38E6, 0xF0255DC1, + 0x4CDD2086, 0x8470EB26, 0x6382E9C6, 0x021ECC5E, + 0x09686B3F, 0x3EBAEFC9, 0x3C971814, 0x6B6A70A1, + 0x687F3584, 0x52A0E286, 0xB79C5305, 0xAA500737, + 0x3E07841C, 0x7FDEAE5C, 0x8E7D44EC, 0x5716F2B8, + 0xB03ADA37, 0xF0500C0D, 0xF01C1F04, 0x0200B3FF, + 0xAE0CF51A, 0x3CB574B2, 0x25837A58, 0xDC0921BD, + 0xD19113F9, 0x7CA92FF6, 0x94324773, 0x22F54701, + 0x3AE5E581, 0x37C2DADC, 0xC8B57634, 0x9AF3DDA7, + 0xA9446146, 0x0FD0030E, 0xECC8C73E, 0xA4751E41, + 0xE238CD99, 0x3BEA0E2F, 0x3280BBA1, 0x183EB331, + 0x4E548B38, 0x4F6DB908, 0x6F420D03, 0xF60A04BF, + 0x2CB81290, 0x24977C79, 0x5679B072, 0xBCAF89AF, + 0xDE9A771F, 0xD9930810, 0xB38BAE12, 0xDCCF3F2E, + 0x5512721F, 0x2E6B7124, 0x501ADDE6, 0x9F84CD87, + 0x7A584718, 0x7408DA17, 0xBC9F9ABC, 0xE94B7D8C, + 0xEC7AEC3A, 0xDB851DFA, 0x63094366, 0xC464C3D2, + 0xEF1C1847, 0x3215D908, 0xDD433B37, 0x24C2BA16, + 0x12A14D43, 0x2A65C451, 0x50940002, 0x133AE4DD, + 0x71DFF89E, 0x10314E55, 0x81AC77D6, 0x5F11199B, + 0x043556F1, 0xD7A3C76B, 0x3C11183B, 0x5924A509, + 0xF28FE6ED, 0x97F1FBFA, 0x9EBABF2C, 0x1E153C6E, + 0x86E34570, 0xEAE96FB1, 0x860E5E0A, 0x5A3E2AB3, + 0x771FE71C, 0x4E3D06FA, 0x2965DCB9, 0x99E71D0F, + 0x803E89D6, 0x5266C825, 0x2E4CC978, 0x9C10B36A, + 0xC6150EBA, 0x94E2EA78, 0xA5FC3C53, 0x1E0A2DF4, + 0xF2F74EA7, 0x361D2B3D, 0x1939260F, 0x19C27960, + 0x5223A708, 0xF71312B6, 0xEBADFE6E, 0xEAC31F66, + 0xE3BC4595, 0xA67BC883, 0xB17F37D1, 0x018CFF28, + 0xC332DDEF, 0xBE6C5AA5, 0x65582185, 0x68AB9802, + 0xEECEA50F, 0xDB2F953B, 0x2AEF7DAD, 0x5B6E2F84, + 0x1521B628, 0x29076170, 0xECDD4775, 0x619F1510, + 0x13CCA830, 0xEB61BD96, 0x0334FE1E, 0xAA0363CF, + 0xB5735C90, 0x4C70A239, 0xD59E9E0B, 0xCBAADE14, + 0xEECC86BC, 0x60622CA7, 0x9CAB5CAB, 0xB2F3846E, + 0x648B1EAF, 0x19BDF0CA, 0xA02369B9, 0x655ABB50, + 0x40685A32, 0x3C2AB4B3, 0x319EE9D5, 0xC021B8F7, + 0x9B540B19, 0x875FA099, 0x95F7997E, 0x623D7DA8, + 0xF837889A, 0x97E32D77, 0x11ED935F, 0x16681281, + 0x0E358829, 0xC7E61FD6, 0x96DEDFA1, 0x7858BA99, + 0x57F584A5, 0x1B227263, 0x9B83C3FF, 0x1AC24696, + 0xCDB30AEB, 0x532E3054, 0x8FD948E4, 0x6DBC3128, + 0x58EBF2EF, 0x34C6FFEA, 0xFE28ED61, 0xEE7C3C73, + 0x5D4A14D9, 0xE864B7E3, 0x42105D14, 0x203E13E0, + 0x45EEE2B6, 0xA3AAABEA, 0xDB6C4F15, 0xFACB4FD0, + 0xC742F442, 0xEF6ABBB5, 0x654F3B1D, 0x41CD2105, + 0xD81E799E, 0x86854DC7, 0xE44B476A, 0x3D816250, + 0xCF62A1F2, 0x5B8D2646, 0xFC8883A0, 0xC1C7B6A3, + 0x7F1524C3, 0x69CB7492, 0x47848A0B, 0x5692B285, + 0x095BBF00, 0xAD19489D, 0x1462B174, 0x23820E00, + 0x58428D2A, 0x0C55F5EA, 0x1DADF43E, 0x233F7061, + 0x3372F092, 0x8D937E41, 0xD65FECF1, 0x6C223BDB, + 0x7CDE3759, 0xCBEE7460, 0x4085F2A7, 0xCE77326E, + 0xA6078084, 0x19F8509E, 0xE8EFD855, 0x61D99735, + 0xA969A7AA, 0xC50C06C2, 0x5A04ABFC, 0x800BCADC, + 0x9E447A2E, 0xC3453484, 0xFDD56705, 0x0E1E9EC9, + 0xDB73DBD3, 0x105588CD, 0x675FDA79, 0xE3674340, + 0xC5C43465, 0x713E38D8, 0x3D28F89E, 0xF16DFF20, + 0x153E21E7, 0x8FB03D4A, 0xE6E39F2B, 0xDB83ADF7, + },{ + 0xE93D5A68, 0x948140F7, 0xF64C261C, 0x94692934, + 0x411520F7, 0x7602D4F7, 0xBCF46B2E, 0xD4A20068, + 0xD4082471, 0x3320F46A, 0x43B7D4B7, 0x500061AF, + 0x1E39F62E, 0x97244546, 0x14214F74, 0xBF8B8840, + 0x4D95FC1D, 0x96B591AF, 0x70F4DDD3, 0x66A02F45, + 0xBFBC09EC, 0x03BD9785, 0x7FAC6DD0, 0x31CB8504, + 0x96EB27B3, 0x55FD3941, 0xDA2547E6, 0xABCA0A9A, + 0x28507825, 0x530429F4, 0x0A2C86DA, 0xE9B66DFB, + 0x68DC1462, 0xD7486900, 0x680EC0A4, 0x27A18DEE, + 0x4F3FFEA2, 0xE887AD8C, 0xB58CE006, 0x7AF4D6B6, + 0xAACE1E7C, 0xD3375FEC, 0xCE78A399, 0x406B2A42, + 0x20FE9E35, 0xD9F385B9, 0xEE39D7AB, 0x3B124E8B, + 0x1DC9FAF7, 0x4B6D1856, 0x26A36631, 0xEAE397B2, + 0x3A6EFA74, 0xDD5B4332, 0x6841E7F7, 0xCA7820FB, + 0xFB0AF54E, 0xD8FEB397, 0x454056AC, 0xBA489527, + 0x55533A3A, 0x20838D87, 0xFE6BA9B7, 0xD096954B, + 0x55A867BC, 0xA1159A58, 0xCCA92963, 0x99E1DB33, + 0xA62A4A56, 0x3F3125F9, 0x5EF47E1C, 0x9029317C, + 0xFDF8E802, 0x04272F70, 0x80BB155C, 0x05282CE3, + 0x95C11548, 0xE4C66D22, 0x48C1133F, 0xC70F86DC, + 0x07F9C9EE, 0x41041F0F, 0x404779A4, 0x5D886E17, + 0x325F51EB, 0xD59BC0D1, 0xF2BCC18F, 0x41113564, + 0x257B7834, 0x602A9C60, 0xDFF8E8A3, 0x1F636C1B, + 0x0E12B4C2, 0x02E1329E, 0xAF664FD1, 0xCAD18115, + 0x6B2395E0, 0x333E92E1, 0x3B240B62, 0xEEBEB922, + 0x85B2A20E, 0xE6BA0D99, 0xDE720C8C, 0x2DA2F728, + 0xD0127845, 0x95B794FD, 0x647D0862, 0xE7CCF5F0, + 0x5449A36F, 0x877D48FA, 0xC39DFD27, 0xF33E8D1E, + 0x0A476341, 0x992EFF74, 0x3A6F6EAB, 0xF4F8FD37, + 0xA812DC60, 0xA1EBDDF8, 0x991BE14C, 0xDB6E6B0D, + 0xC67B5510, 0x6D672C37, 0x2765D43B, 0xDCD0E804, + 0xF1290DC7, 0xCC00FFA3, 0xB5390F92, 0x690FED0B, + 0x667B9FFB, 0xCEDB7D9C, 0xA091CF0B, 0xD9155EA3, + 0xBB132F88, 0x515BAD24, 0x7B9479BF, 0x763BD6EB, + 0x37392EB3, 0xCC115979, 0x8026E297, 0xF42E312D, + 0x6842ADA7, 0xC66A2B3B, 0x12754CCC, 0x782EF11C, + 0x6A124237, 0xB79251E7, 0x06A1BBE6, 0x4BFB6350, + 0x1A6B1018, 0x11CAEDFA, 0x3D25BDD8, 0xE2E1C3C9, + 0x44421659, 0x0A121386, 0xD90CEC6E, 0xD5ABEA2A, + 0x64AF674E, 0xDA86A85F, 0xBEBFE988, 0x64E4C3FE, + 0x9DBC8057, 0xF0F7C086, 0x60787BF8, 0x6003604D, + 0xD1FD8346, 0xF6381FB0, 0x7745AE04, 0xD736FCCC, + 0x83426B33, 0xF01EAB71, 0xB0804187, 0x3C005E5F, + 0x77A057BE, 0xBDE8AE24, 0x55464299, 0xBF582E61, + 0x4E58F48F, 0xF2DDFDA2, 0xF474EF38, 0x8789BDC2, + 0x5366F9C3, 0xC8B38E74, 0xB475F255, 0x46FCD9B9, + 0x7AEB2661, 0x8B1DDF84, 0x846A0E79, 0x915F95E2, + 0x466E598E, 0x20B45770, 0x8CD55591, 0xC902DE4C, + 0xB90BACE1, 0xBB8205D0, 0x11A86248, 0x7574A99E, + 0xB77F19B6, 0xE0A9DC09, 0x662D09A1, 0xC4324633, + 0xE85A1F02, 0x09F0BE8C, 0x4A99A025, 0x1D6EFE10, + 0x1AB93D1D, 0x0BA5A4DF, 0xA186F20F, 0x2868F169, + 0xDCB7DA83, 0x573906FE, 0xA1E2CE9B, 0x4FCD7F52, + 0x50115E01, 0xA70683FA, 0xA002B5C4, 0x0DE6D027, + 0x9AF88C27, 0x773F8641, 0xC3604C06, 0x61A806B5, + 0xF0177A28, 0xC0F586E0, 0x006058AA, 0x30DC7D62, + 0x11E69ED7, 0x2338EA63, 0x53C2DD94, 0xC2C21634, + 0xBBCBEE56, 0x90BCB6DE, 0xEBFC7DA1, 0xCE591D76, + 0x6F05E409, 0x4B7C0188, 0x39720A3D, 0x7C927C24, + 0x86E3725F, 0x724D9DB9, 0x1AC15BB4, 0xD39EB8FC, + 0xED545578, 0x08FCA5B5, 0xD83D7CD3, 0x4DAD0FC4, + 0x1E50EF5E, 0xB161E6F8, 0xA28514D9, 0x6C51133C, + 0x6FD5C7E7, 0x56E14EC4, 0x362ABFCE, 0xDDC6C837, + 0xD79A3234, 0x92638212, 0x670EFA8E, 0x406000E0, + },{ + 0x3A39CE37, 0xD3FAF5CF, 0xABC27737, 0x5AC52D1B, + 0x5CB0679E, 0x4FA33742, 0xD3822740, 0x99BC9BBE, + 0xD5118E9D, 0xBF0F7315, 0xD62D1C7E, 0xC700C47B, + 0xB78C1B6B, 0x21A19045, 0xB26EB1BE, 0x6A366EB4, + 0x5748AB2F, 0xBC946E79, 0xC6A376D2, 0x6549C2C8, + 0x530FF8EE, 0x468DDE7D, 0xD5730A1D, 0x4CD04DC6, + 0x2939BBDB, 0xA9BA4650, 0xAC9526E8, 0xBE5EE304, + 0xA1FAD5F0, 0x6A2D519A, 0x63EF8CE2, 0x9A86EE22, + 0xC089C2B8, 0x43242EF6, 0xA51E03AA, 0x9CF2D0A4, + 0x83C061BA, 0x9BE96A4D, 0x8FE51550, 0xBA645BD6, + 0x2826A2F9, 0xA73A3AE1, 0x4BA99586, 0xEF5562E9, + 0xC72FEFD3, 0xF752F7DA, 0x3F046F69, 0x77FA0A59, + 0x80E4A915, 0x87B08601, 0x9B09E6AD, 0x3B3EE593, + 0xE990FD5A, 0x9E34D797, 0x2CF0B7D9, 0x022B8B51, + 0x96D5AC3A, 0x017DA67D, 0xD1CF3ED6, 0x7C7D2D28, + 0x1F9F25CF, 0xADF2B89B, 0x5AD6B472, 0x5A88F54C, + 0xE029AC71, 0xE019A5E6, 0x47B0ACFD, 0xED93FA9B, + 0xE8D3C48D, 0x283B57CC, 0xF8D56629, 0x79132E28, + 0x785F0191, 0xED756055, 0xF7960E44, 0xE3D35E8C, + 0x15056DD4, 0x88F46DBA, 0x03A16125, 0x0564F0BD, + 0xC3EB9E15, 0x3C9057A2, 0x97271AEC, 0xA93A072A, + 0x1B3F6D9B, 0x1E6321F5, 0xF59C66FB, 0x26DCF319, + 0x7533D928, 0xB155FDF5, 0x03563482, 0x8ABA3CBB, + 0x28517711, 0xC20AD9F8, 0xABCC5167, 0xCCAD925F, + 0x4DE81751, 0x3830DC8E, 0x379D5862, 0x9320F991, + 0xEA7A90C2, 0xFB3E7BCE, 0x5121CE64, 0x774FBE32, + 0xA8B6E37E, 0xC3293D46, 0x48DE5369, 0x6413E680, + 0xA2AE0810, 0xDD6DB224, 0x69852DFD, 0x09072166, + 0xB39A460A, 0x6445C0DD, 0x586CDECF, 0x1C20C8AE, + 0x5BBEF7DD, 0x1B588D40, 0xCCD2017F, 0x6BB4E3BB, + 0xDDA26A7E, 0x3A59FF45, 0x3E350A44, 0xBCB4CDD5, + 0x72EACEA8, 0xFA6484BB, 0x8D6612AE, 0xBF3C6F47, + 0xD29BE463, 0x542F5D9E, 0xAEC2771B, 0xF64E6370, + 0x740E0D8D, 0xE75B1357, 0xF8721671, 0xAF537D5D, + 0x4040CB08, 0x4EB4E2CC, 0x34D2466A, 0x0115AF84, + 0xE1B00428, 0x95983A1D, 0x06B89FB4, 0xCE6EA048, + 0x6F3F3B82, 0x3520AB82, 0x011A1D4B, 0x277227F8, + 0x611560B1, 0xE7933FDC, 0xBB3A792B, 0x344525BD, + 0xA08839E1, 0x51CE794B, 0x2F32C9B7, 0xA01FBAC9, + 0xE01CC87E, 0xBCC7D1F6, 0xCF0111C3, 0xA1E8AAC7, + 0x1A908749, 0xD44FBD9A, 0xD0DADECB, 0xD50ADA38, + 0x0339C32A, 0xC6913667, 0x8DF9317C, 0xE0B12B4F, + 0xF79E59B7, 0x43F5BB3A, 0xF2D519FF, 0x27D9459C, + 0xBF97222C, 0x15E6FC2A, 0x0F91FC71, 0x9B941525, + 0xFAE59361, 0xCEB69CEB, 0xC2A86459, 0x12BAA8D1, + 0xB6C1075E, 0xE3056A0C, 0x10D25065, 0xCB03A442, + 0xE0EC6E0E, 0x1698DB3B, 0x4C98A0BE, 0x3278E964, + 0x9F1F9532, 0xE0D392DF, 0xD3A0342B, 0x8971F21E, + 0x1B0A7441, 0x4BA3348C, 0xC5BE7120, 0xC37632D8, + 0xDF359F8D, 0x9B992F2E, 0xE60B6F47, 0x0FE3F11D, + 0xE54CDA54, 0x1EDAD891, 0xCE6279CF, 0xCD3E7E6F, + 0x1618B166, 0xFD2C1D05, 0x848FD2C5, 0xF6FB2299, + 0xF523F357, 0xA6327623, 0x93A83531, 0x56CCCD02, + 0xACF08162, 0x5A75EBB5, 0x6E163697, 0x88D273CC, + 0xDE966292, 0x81B949D0, 0x4C50901B, 0x71C65614, + 0xE6C6C7BD, 0x327A140A, 0x45E1D006, 0xC3F27B9A, + 0xC9AA53FD, 0x62A80F00, 0xBB25BFE2, 0x35BDD2F6, + 0x71126905, 0xB2040222, 0xB6CBCF7C, 0xCD769C2B, + 0x53113EC0, 0x1640E3D3, 0x38ABBD60, 0x2547ADF0, + 0xBA38209C, 0xF746CE76, 0x77AFA1C5, 0x20756060, + 0x85CBFE4E, 0x8AE88DD8, 0x7AAAF9B0, 0x4CF9AA7E, + 0x1948C25C, 0x02FB8A8C, 0x01C36AE4, 0xD6EBE1F9, + 0x90D4F869, 0xA65CDEA0, 0x3F09252D, 0xC208E69F, + 0xB74E6132, 0xCE77E25B, 0x578FDFE3, 0x3AC372E6, +}}; + +static uint32_t P[16 + 2]; +static uint32_t S[4][256]; + +static inline void swap(uint32_t *L, uint32_t *R) +{ + uint32_t t; + t = *L; + *L = *R; + *R = t; +} + +static inline void swapendian(uint32_t *n) +{ + uint8_t a, b, c, d; + a = (*n >> 24) & 0xff; + b = (*n >> 16) & 0xff; + c = (*n >> 8) & 0xff; + d = *n & 0xff; + *n = (d << 24) | (c << 16) | (b << 8) | a; +} + +static uint32_t f(uint32_t x) +{ + uint32_t h = S[0][x >> 24] + S[1][x >> 16 & 0xff]; + return (h ^ S[2][x >> 8 & 0xff]) + S[3][x & 0xff]; +} + +static void encrypt(uint32_t *L, uint32_t *R) +{ + int i; + for (i = 0; i < 16; i += 2) { + *L ^= P[i]; + *R ^= f(*L); + *R ^= P[i + 1]; + *L ^= f(*R); + } + *L ^= P[16]; + *R ^= P[17]; + swap(L, R); +} + +static void decrypt(uint32_t *L, uint32_t *R) +{ + int i; + for (i = 16; i > 0; i -= 2) { + *L ^= P[i + 1]; + *R ^= f(*L); + *R ^= P[i]; + *L ^= f(*R); + } + *L ^= P[1]; + *R ^= P[0]; + swap(L, R); +} + +static void key_schedule(uint32_t *key, int keylen) +{ + int i, j; + uint32_t L = 0, R = 0; + memcpy(P, P_orig, sizeof(P)); + memcpy(S, S_orig, sizeof(S)); + for (i = 0; i < 18; i++) { + P[i] ^= key[i % keylen]; + } + for (i = 0; i < 18; i+=2) { + encrypt(&L, &R); + P[i] = L; + P[i + 1] = R; + } + for (i = 0; i < 4; i++) { + for (j = 0; j < 256; j += 2) { + encrypt(&L, &R); + S[i][j] = L; + S[i][j + 1] = R; + } + } +} + +void blowfish_setkey(uint8_t *key, int keylen) +{ + int i; + for (i = 0; i < keylen / 4; i++) { + swapendian((uint32_t *)(key + i * 4)); + } + key_schedule((uint32_t *)key, keylen / 4); +} + +void blowfish_encrypt(uint8_t *data, int datalen) +{ + int i; + for (i = 0; i < datalen / 8; i++) { + encrypt((uint32_t *)(data + i * 8), (uint32_t *)(data + i * 8 + 4)); + } +} + +void blowfish_decrypt(uint8_t *data, int datalen) +{ + int i; + for (i = 0; i < datalen / 8; i++) { + decrypt((uint32_t *)(data + i * 8), (uint32_t *)(data + i * 8 + 4)); + } +} diff --git a/blowfish.h b/blowfish.h new file mode 100644 index 000000000..1408d3e9b --- /dev/null +++ b/blowfish.h @@ -0,0 +1,10 @@ +#ifndef __BLOWFISH_H__ +#define __BLOWFISH_H__ + +#include + +void blowfish_setkey(uint8_t *key, int keylen); +void blowfish_encrypt(uint8_t *data, int datalen); +void blowfish_decrypt(uint8_t *data, int datalen); + +#endif diff --git a/tests.c b/tests.c index 2f0916edb..442ab18e6 100644 --- a/tests.c +++ b/tests.c @@ -26,6 +26,7 @@ #include #include +#include "blowfish.h" #include "bignum.h" #include "bip32.h" #include "ecdsa.h" @@ -274,6 +275,20 @@ START_TEST(test_verify_speed) } END_TEST +// test vectors from https://www.schneier.com/code/vectors.txt +START_TEST(test_blowfish) +{ + uint8_t key[8]; + uint8_t data[8]; + + memcpy(key, fromhex("0000000000000000"), 8); + memcpy(data, fromhex("0000000000000000"), 8); + blowfish_setkey(key, 8); + blowfish_encrypt(data, 8); + ck_assert_mem_eq(data, fromhex("4ef997456198dd78"), 8); +} +END_TEST + // define test suite and cases Suite *test_suite(void) { @@ -294,6 +309,10 @@ Suite *test_suite(void) tcase_add_test(tc, test_verify_speed); suite_add_tcase(s, tc); + tc = tcase_create("blowfish"); + tcase_add_test(tc, test_blowfish); + suite_add_tcase(s, tc); + return s; } From 9205c0d952101013ec99ab398c16580568c406c5 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 8 Oct 2013 14:01:20 +0200 Subject: [PATCH 040/627] use canonical signatures (if S > Order/2: S = Order - S) --- bignum.c | 10 +++++++++- bignum.h | 3 ++- ecdsa.c | 5 +++++ secp256k1.c | 6 ++++-- secp256k1.h | 3 +++ tests.c | 6 ++++++ 6 files changed, 29 insertions(+), 4 deletions(-) diff --git a/bignum.c b/bignum.c index bcfbe88e7..b6bf0046a 100644 --- a/bignum.c +++ b/bignum.c @@ -510,7 +510,7 @@ void bn_divmod58(bignum256 *a, uint32_t *r) *r = rem; } -#if 0 +#if BN_PRINT void bn_print(const bignum256 *a) { printf("%04x", a->val[8] & 0x0000FFFF); @@ -523,4 +523,12 @@ void bn_print(const bignum256 *a) printf("%08x", (a->val[1] << 2) | ((a->val[0] & 0x30000000) >> 28)); printf("%07x", a->val[0] & 0x0FFFFFFF); } + +void bn_print_raw(const bignum256 *a) +{ + int i; + for (i = 0; i <= 8; i++) { + printf("0x%08x, ", a->val[i]); + } +} #endif diff --git a/bignum.h b/bignum.h index c9eeb1d64..a0d2aeb06 100644 --- a/bignum.h +++ b/bignum.h @@ -91,8 +91,9 @@ void bn_substract_noprime(const bignum256 *a, const bignum256 *b, bignum256 *res void bn_divmod58(bignum256 *a, uint32_t *r); -#if 0 +#if BN_PRINT void bn_print(const bignum256 *a); +void bn_print_raw(const bignum256 *a); #endif #endif diff --git a/ecdsa.c b/ecdsa.c index 0ac4ef28b..324223d5d 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -256,6 +256,11 @@ int ecdsa_sign(const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, ui return 3; } + // if S > order/2 => S = -S + if (bn_is_less(&order256k1_half, &k)) { + bn_substract_noprime(&order256k1, &k, &k); + } + // we are done, R.x and k is the result signature bn_write_be(&R.x, sig); bn_write_be(&k, sig + 32); diff --git a/secp256k1.c b/secp256k1.c index 5917456fc..cbed98888 100644 --- a/secp256k1.c +++ b/secp256k1.c @@ -24,8 +24,7 @@ #include "secp256k1.h" const bignum256 prime256k1 = { -.val = {0x3ffffc2f, 0x3ffffffb, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0xffff} -}; +.val = {0x3ffffc2f, 0x3ffffffb, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0xffff}}; const curve_point G256k1 = { .x = { .val = {0x16f81798, 0x27ca056c, 0x1ce28d95, 0x26ff36cb, 0x70b0702, 0x18a573a, 0xbbac55a, 0x199fbe77, 0x79be}}, @@ -34,6 +33,9 @@ const curve_point G256k1 = { const bignum256 order256k1 = { .val = {0x10364141, 0x3f497a33, 0x348a03bb, 0x2bb739ab, 0x3ffffeba, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0xffff}}; +const bignum256 order256k1_half = { +.val = {0x281b20a0, 0x3fa4bd19, 0x3a4501dd, 0x15db9cd5, 0x3fffff5d, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x00007fff}}; + const bignum256 three_over_two256k1 = { .val = {0x3ffffe19, 0x3ffffffd, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x7fff}}; diff --git a/secp256k1.h b/secp256k1.h index fea7e85ae..331107ef1 100644 --- a/secp256k1.h +++ b/secp256k1.h @@ -42,6 +42,9 @@ extern const curve_point G256k1; // secp256k1 order of G extern const bignum256 order256k1; +// secp256k1 order of G / 2 +extern const bignum256 order256k1_half; + // 3/2 in G_p extern const bignum256 three_over_two256k1; diff --git a/tests.c b/tests.c index 442ab18e6..40b7fe25e 100644 --- a/tests.c +++ b/tests.c @@ -208,6 +208,12 @@ START_TEST(test_rfc6979) ck_assert_int_eq(res, 0); bn_write_be(&k, buf); ck_assert_mem_eq(buf, fromhex("38aa22d72376b4dbc472e06c3ba403ee0a394da63fc58d88686c611aba98d6b3"), 32); + + SHA256_Raw((uint8_t *)"There is a computer disease that anybody who works with computers knows about. It's a very serious disease and it interferes completely with the work. The trouble with computers is that you 'play' with them!", 207, buf); + res = generate_k_rfc6979(&k, fromhex("e91671c46231f833a6406ccbea0e3e392c76c167bac1cb013f6f1013980455c2"), buf); + ck_assert_int_eq(res, 0); + bn_write_be(&k, buf); + ck_assert_mem_eq(buf, fromhex("1f4b84c23a86a221d233f2521be018d9318639d5b8bbd6374a8a59232d16ad3d"), 32); } END_TEST From 47cb0fefce7d67e6ee4887742ab35f21ca4732fb Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 8 Oct 2013 14:18:35 +0200 Subject: [PATCH 041/627] renamed to trezor-crypto, modified readme --- README | 27 +++++++++++++++------------ test-openssl.c | 6 +++--- tests.c | 2 +- 3 files changed, 19 insertions(+), 16 deletions(-) diff --git a/README b/README index dc7e963eb..3698fe64b 100644 --- a/README +++ b/README @@ -1,15 +1,18 @@ -MicroECDSA -========== +trezor-crypto +============= -Heavily optimized ECDSA (secp256k1) signer for embedded devices. +Heavily optimized cryptography algorithms for embedded devices. -Distibuted under MIT License. - -Notes ------ - -a) the signer only understands secp256k1 elliptic curve +These include: +- Big Number (256 bit) Arithmetics +- BIP32 Hierarchical Deterministic Wallets +- Blowfish encrypt/decrypt +- ECDSA signer/verifier (only secp256k1 curve) +- ECDSA public key derivation and Base58 address representation +- HMAC-SHA256 and HMAC-SHA512 +- RIPEMD-160 +- SHA256/SHA512 +- unit tests (using Check - check.sf.net; in tests.c) +- tests against OpenSSL (in test-openssl.c) -b) unit tests using Check (check.sf.net) are in tests.c - -c) tests against OpenSSL are in test-openssl.c +Distibuted under MIT License. diff --git a/test-openssl.c b/test-openssl.c index ccaefef07..65d685fc5 100644 --- a/test-openssl.c +++ b/test-openssl.c @@ -76,7 +76,7 @@ int main() // use our ECDSA signer to sign the message with the key if (ecdsa_sign(priv_key, msg, msg_len, sig) != 0) { - printf("MicroECDSA signing failed\n"); + printf("trezor-crypto signing failed\n"); break; } @@ -86,11 +86,11 @@ int main() // use our ECDSA verifier to verify the message signature if (ecdsa_verify(pub_key65, sig, msg, msg_len) != 0) { - printf("MicroECDSA verification failed (pub_key_len = 65)\n"); + printf("trezor-crypto verification failed (pub_key_len = 65)\n"); break; } if (ecdsa_verify(pub_key33, sig, msg, msg_len) != 0) { - printf("MicroECDSA verification failed (pub_key_len = 33)\n"); + printf("trezor-crypto verification failed (pub_key_len = 33)\n"); break; } diff --git a/tests.c b/tests.c index 40b7fe25e..d5f64c9ac 100644 --- a/tests.c +++ b/tests.c @@ -298,7 +298,7 @@ END_TEST // define test suite and cases Suite *test_suite(void) { - Suite *s = suite_create("MicroECDSA"); + Suite *s = suite_create("trezor-crypto"); TCase *tc; tc = tcase_create("bip32"); From 99565b3130c6934704159e0adc0dea66f1cbcb1e Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 8 Oct 2013 16:59:14 +0200 Subject: [PATCH 042/627] fix blowfish. add unit tests for blowfish --- blowfish.c | 34 ++++++++++++++++++++++++++ blowfish.h | 22 +++++++++++++++++ tests.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 121 insertions(+), 7 deletions(-) diff --git a/blowfish.c b/blowfish.c index a80ef5f61..1e32a3eed 100644 --- a/blowfish.c +++ b/blowfish.c @@ -1,3 +1,25 @@ +/** + * Copyright (c) 2013 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + #include #include "blowfish.h" @@ -361,15 +383,27 @@ void blowfish_setkey(uint8_t *key, int keylen) void blowfish_encrypt(uint8_t *data, int datalen) { int i; + for (i = 0; i < datalen / 4; i++) { + swapendian((uint32_t *)(data + i * 4)); + } for (i = 0; i < datalen / 8; i++) { encrypt((uint32_t *)(data + i * 8), (uint32_t *)(data + i * 8 + 4)); } + for (i = 0; i < datalen / 4; i++) { + swapendian((uint32_t *)(data + i * 4)); + } } void blowfish_decrypt(uint8_t *data, int datalen) { int i; + for (i = 0; i < datalen / 4; i++) { + swapendian((uint32_t *)(data + i * 4)); + } for (i = 0; i < datalen / 8; i++) { decrypt((uint32_t *)(data + i * 8), (uint32_t *)(data + i * 8 + 4)); } + for (i = 0; i < datalen / 4; i++) { + swapendian((uint32_t *)(data + i * 4)); + } } diff --git a/blowfish.h b/blowfish.h index 1408d3e9b..6cd6bc530 100644 --- a/blowfish.h +++ b/blowfish.h @@ -1,3 +1,25 @@ +/** + * Copyright (c) 2013 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + #ifndef __BLOWFISH_H__ #define __BLOWFISH_H__ diff --git a/tests.c b/tests.c index d5f64c9ac..8a46b74fb 100644 --- a/tests.c +++ b/tests.c @@ -281,17 +281,74 @@ START_TEST(test_verify_speed) } END_TEST +#define test_bfsh(KEY, CLEAR, CIPHER) do { \ + memcpy(key, fromhex(KEY), strlen(KEY)/2); \ + memcpy(data, fromhex(CLEAR), strlen(CLEAR)/2); \ + blowfish_setkey(key, strlen(KEY)/2); \ + blowfish_encrypt(data, strlen(CLEAR)/2); \ + ck_assert_mem_eq(data, fromhex(CIPHER), strlen(CIPHER)/2); \ +} while (0) + // test vectors from https://www.schneier.com/code/vectors.txt -START_TEST(test_blowfish) +START_TEST(test_blowfish_1) { uint8_t key[8]; uint8_t data[8]; + test_bfsh("0000000000000000", "0000000000000000", "4ef997456198dd78"); + test_bfsh("ffffffffffffffff", "ffffffffffffffff", "51866fd5b85ecb8a"); + test_bfsh("3000000000000000", "1000000000000001", "7d856f9a613063f2"); + test_bfsh("1111111111111111", "1111111111111111", "2466dd878b963c9d"); + test_bfsh("0123456789abcdef", "1111111111111111", "61f9c3802281b096"); + test_bfsh("1111111111111111", "0123456789abcdef", "7d0cc630afda1ec7"); + test_bfsh("0000000000000000", "0000000000000000", "4ef997456198dd78"); + test_bfsh("fedcba9876543210", "0123456789abcdef", "0aceab0fc6a0a28d"); + test_bfsh("7ca110454a1a6e57", "01a1d6d039776742", "59c68245eb05282b"); + test_bfsh("0131d9619dc1376e", "5cd54ca83def57da", "b1b8cc0b250f09a0"); + test_bfsh("07a1133e4a0b2686", "0248d43806f67172", "1730e5778bea1da4"); + test_bfsh("3849674c2602319e", "51454b582ddf440a", "a25e7856cf2651eb"); + test_bfsh("04b915ba43feb5b6", "42fd443059577fa2", "353882b109ce8f1a"); + test_bfsh("0113b970fd34f2ce", "059b5e0851cf143a", "48f4d0884c379918"); + test_bfsh("0170f175468fb5e6", "0756d8e0774761d2", "432193b78951fc98"); + test_bfsh("43297fad38e373fe", "762514b829bf486a", "13f04154d69d1ae5"); + test_bfsh("07a7137045da2a16", "3bdd119049372802", "2eedda93ffd39c79"); + test_bfsh("04689104c2fd3b2f", "26955f6835af609a", "d887e0393c2da6e3"); + test_bfsh("37d06bb516cb7546", "164d5e404f275232", "5f99d04f5b163969"); + test_bfsh("1f08260d1ac2465e", "6b056e18759f5cca", "4a057a3b24d3977b"); + test_bfsh("584023641aba6176", "004bd6ef09176062", "452031c1e4fada8e"); + test_bfsh("025816164629b007", "480d39006ee762f2", "7555ae39f59b87bd"); + test_bfsh("49793ebc79b3258f", "437540c8698f3cfa", "53c55f9cb49fc019"); + test_bfsh("4fb05e1515ab73a7", "072d43a077075292", "7a8e7bfa937e89a3"); + test_bfsh("49e95d6d4ca229bf", "02fe55778117f12a", "cf9c5d7a4986adb5"); + test_bfsh("018310dc409b26d6", "1d9d5c5018f728c2", "d1abb290658bc778"); + test_bfsh("1c587f1c13924fef", "305532286d6f295a", "55cb3774d13ef201"); + test_bfsh("0101010101010101", "0123456789abcdef", "fa34ec4847b268b2"); + test_bfsh("1f1f1f1f0e0e0e0e", "0123456789abcdef", "a790795108ea3cae"); + test_bfsh("e0fee0fef1fef1fe", "0123456789abcdef", "c39e072d9fac631d"); + test_bfsh("0000000000000000", "ffffffffffffffff", "014933e0cdaff6e4"); + test_bfsh("ffffffffffffffff", "0000000000000000", "f21e9a77b71c49bc"); + test_bfsh("0123456789abcdef", "0000000000000000", "245946885754369a"); + test_bfsh("fedcba9876543210", "ffffffffffffffff", "6b5c5a9c5d9e0a5a"); +} +END_TEST - memcpy(key, fromhex("0000000000000000"), 8); - memcpy(data, fromhex("0000000000000000"), 8); - blowfish_setkey(key, 8); - blowfish_encrypt(data, 8); - ck_assert_mem_eq(data, fromhex("4ef997456198dd78"), 8); +// mnemonic test vectors +START_TEST(test_blowfish_2) +{ + uint8_t key[24]; + uint8_t data[24]; + // 6d6e656d6f6e6963 = "mnemonic" + test_bfsh("6d6e656d6f6e6963", "0000000000000000", "e6b5de53efaec3a5"); + test_bfsh("6d6e656d6f6e6963", "00000000000000000000000000000000", "e6b5de53efaec3a5e6b5de53efaec3a5"); + test_bfsh("6d6e656d6f6e6963", "000000000000000000000000000000000000000000000000", "e6b5de53efaec3a5e6b5de53efaec3a5e6b5de53efaec3a5"); + test_bfsh("6d6e656d6f6e6963", "7f7f7f7f7f7f7f7f", "cb21e7cd6313594b"); + test_bfsh("6d6e656d6f6e6963", "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", "cb21e7cd6313594bcb21e7cd6313594b"); + test_bfsh("6d6e656d6f6e6963", "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", "cb21e7cd6313594bcb21e7cd6313594bcb21e7cd6313594b"); + test_bfsh("6d6e656d6f6e6963", "8080808080808080", "8800e1df66298ae6"); + test_bfsh("6d6e656d6f6e6963", "80808080808080808080808080808080", "8800e1df66298ae68800e1df66298ae6"); + test_bfsh("6d6e656d6f6e6963", "808080808080808080808080808080808080808080808080", "8800e1df66298ae68800e1df66298ae68800e1df66298ae6"); + test_bfsh("6d6e656d6f6e6963", "ffffffffffffffff", "4c8be56fcf3de4cf"); + test_bfsh("6d6e656d6f6e6963", "ffffffffffffffffffffffffffffffff", "4c8be56fcf3de4cf4c8be56fcf3de4cf"); + test_bfsh("6d6e656d6f6e6963", "ffffffffffffffffffffffffffffffffffffffffffffffff", "4c8be56fcf3de4cf4c8be56fcf3de4cf4c8be56fcf3de4cf"); } END_TEST @@ -316,7 +373,8 @@ Suite *test_suite(void) suite_add_tcase(s, tc); tc = tcase_create("blowfish"); - tcase_add_test(tc, test_blowfish); + tcase_add_test(tc, test_blowfish_1); + tcase_add_test(tc, test_blowfish_2); suite_add_tcase(s, tc); return s; From 946c23e2cf09135758cb47e530af0d50d7c88d18 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 8 Oct 2013 17:25:28 +0200 Subject: [PATCH 043/627] small readme update --- README | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README b/README index 3698fe64b..b669327d7 100644 --- a/README +++ b/README @@ -6,9 +6,10 @@ Heavily optimized cryptography algorithms for embedded devices. These include: - Big Number (256 bit) Arithmetics - BIP32 Hierarchical Deterministic Wallets -- Blowfish encrypt/decrypt -- ECDSA signer/verifier (only secp256k1 curve) -- ECDSA public key derivation and Base58 address representation +- Blowfish encryption/decryption (ECB) +- ECDSA signing/verifying (only hardcoded secp256k1 curve, + uses RFC6979 for deterministic signatures) +- ECDSA public key derivation + Base58 address representation - HMAC-SHA256 and HMAC-SHA512 - RIPEMD-160 - SHA256/SHA512 From 52485b9008cf2f70e4f9dcb0da48bbce46ca8631 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 8 Oct 2013 18:54:21 +0200 Subject: [PATCH 044/627] define BN_PRINT if not defined --- bignum.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bignum.h b/bignum.h index a0d2aeb06..32babf0dd 100644 --- a/bignum.h +++ b/bignum.h @@ -91,6 +91,10 @@ void bn_substract_noprime(const bignum256 *a, const bignum256 *b, bignum256 *res void bn_divmod58(bignum256 *a, uint32_t *r); +#ifndef BN_PRINT +#define BN_PRINT 0 +#endif + #if BN_PRINT void bn_print(const bignum256 *a); void bn_print_raw(const bignum256 *a); From 0fc4ad097662ec28c6511958508a9f0ed9c56bd9 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 8 Oct 2013 21:07:53 +0200 Subject: [PATCH 045/627] move declaration --- ecdsa.h | 3 --- sha2.h | 1 + tests.c | 2 ++ 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ecdsa.h b/ecdsa.h index fc0acbba6..0aa221bff 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -32,13 +32,10 @@ #define USE_RFC6979 1 #endif -// all functions use secp256k1 curve int ecdsa_sign(const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig); void ecdsa_get_public_key33(const uint8_t *priv_key, uint8_t *pub_key); void ecdsa_get_public_key65(const uint8_t *priv_key, uint8_t *pub_key); void ecdsa_get_address(const uint8_t *pub_key, char version, char *addr); int ecdsa_verify(const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, uint32_t msg_len); -int generate_k_rfc6979(bignum256 *secret, const uint8_t *priv_key, const uint8_t *hash); - #endif diff --git a/sha2.h b/sha2.h index 962e28a0e..c105d7078 100644 --- a/sha2.h +++ b/sha2.h @@ -32,6 +32,7 @@ #define __SHA2_H__ #include +#include #define SHA256_BLOCK_LENGTH 64 #define SHA256_DIGEST_LENGTH 32 diff --git a/tests.c b/tests.c index 8a46b74fb..0e65b5919 100644 --- a/tests.c +++ b/tests.c @@ -173,6 +173,8 @@ START_TEST(test_bip32_vector_2) } END_TEST +int generate_k_rfc6979(bignum256 *secret, const uint8_t *priv_key, const uint8_t *hash); + START_TEST(test_rfc6979) { int res; From 69a88a28a8f3cb069270f87cf2ce2d646e1c7067 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 8 Oct 2013 22:59:36 +0200 Subject: [PATCH 046/627] simplify rfc6979 tests --- tests.c | 49 ++++++++++++++----------------------------------- 1 file changed, 14 insertions(+), 35 deletions(-) diff --git a/tests.c b/tests.c index 0e65b5919..b9b9e4f43 100644 --- a/tests.c +++ b/tests.c @@ -175,47 +175,26 @@ END_TEST int generate_k_rfc6979(bignum256 *secret, const uint8_t *priv_key, const uint8_t *hash); +#define test_deterministic(KEY, MSG, K) do { \ + SHA256_Raw((uint8_t *)MSG, strlen(MSG), buf); \ + res = generate_k_rfc6979(&k, fromhex(KEY), buf); \ + ck_assert_int_eq(res, 0); \ + bn_write_be(&k, buf); \ + ck_assert_mem_eq(buf, fromhex(K), 32); \ +} while (0) + START_TEST(test_rfc6979) { int res; bignum256 k; uint8_t buf[32]; - SHA256_Raw((uint8_t *)"sample", 6, buf); - res = generate_k_rfc6979(&k, fromhex("cca9fbcc1b41e5a95d369eaa6ddcff73b61a4efaa279cfc6567e8daa39cbaf50"), buf); - ck_assert_int_eq(res, 0); - bn_write_be(&k, buf); - ck_assert_mem_eq(buf, fromhex("2df40ca70e639d89528a6b670d9d48d9165fdc0febc0974056bdce192b8e16a3"), 32); - - SHA256_Raw((uint8_t *)"Satoshi Nakamoto", 16, buf); - res = generate_k_rfc6979(&k, fromhex("0000000000000000000000000000000000000000000000000000000000000001"), buf); - ck_assert_int_eq(res, 0); - bn_write_be(&k, buf); - ck_assert_mem_eq(buf, fromhex("8f8a276c19f4149656b280621e358cce24f5f52542772691ee69063b74f15d15"), 32); - - SHA256_Raw((uint8_t *)"Satoshi Nakamoto", 16, buf); - res = generate_k_rfc6979(&k, fromhex("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140"), buf); - ck_assert_int_eq(res, 0); - bn_write_be(&k, buf); - ck_assert_mem_eq(buf, fromhex("33a19b60e25fb6f4435af53a3d42d493644827367e6453928554f43e49aa6f90"), 32); - - SHA256_Raw((uint8_t *)"Alan Turing", 11, buf); - res = generate_k_rfc6979(&k, fromhex("f8b8af8ce3c7cca5e300d33939540c10d45ce001b8f252bfbc57ba0342904181"), buf); - ck_assert_int_eq(res, 0); - bn_write_be(&k, buf); - ck_assert_mem_eq(buf, fromhex("525a82b70e67874398067543fd84c83d30c175fdc45fdeee082fe13b1d7cfdf1"), 32); - - SHA256_Raw((uint8_t *)"All those moments will be lost in time, like tears in rain. Time to die...", 74, buf); - res = generate_k_rfc6979(&k, fromhex("0000000000000000000000000000000000000000000000000000000000000001"), buf); - ck_assert_int_eq(res, 0); - bn_write_be(&k, buf); - ck_assert_mem_eq(buf, fromhex("38aa22d72376b4dbc472e06c3ba403ee0a394da63fc58d88686c611aba98d6b3"), 32); - - SHA256_Raw((uint8_t *)"There is a computer disease that anybody who works with computers knows about. It's a very serious disease and it interferes completely with the work. The trouble with computers is that you 'play' with them!", 207, buf); - res = generate_k_rfc6979(&k, fromhex("e91671c46231f833a6406ccbea0e3e392c76c167bac1cb013f6f1013980455c2"), buf); - ck_assert_int_eq(res, 0); - bn_write_be(&k, buf); - ck_assert_mem_eq(buf, fromhex("1f4b84c23a86a221d233f2521be018d9318639d5b8bbd6374a8a59232d16ad3d"), 32); + test_deterministic("cca9fbcc1b41e5a95d369eaa6ddcff73b61a4efaa279cfc6567e8daa39cbaf50", "sample", "2df40ca70e639d89528a6b670d9d48d9165fdc0febc0974056bdce192b8e16a3"); + test_deterministic("0000000000000000000000000000000000000000000000000000000000000001", "Satoshi Nakamoto", "8f8a276c19f4149656b280621e358cce24f5f52542772691ee69063b74f15d15"); + test_deterministic("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", "Satoshi Nakamoto", "33a19b60e25fb6f4435af53a3d42d493644827367e6453928554f43e49aa6f90"); + test_deterministic("f8b8af8ce3c7cca5e300d33939540c10d45ce001b8f252bfbc57ba0342904181", "Alan Turing", "525a82b70e67874398067543fd84c83d30c175fdc45fdeee082fe13b1d7cfdf1"); + test_deterministic("0000000000000000000000000000000000000000000000000000000000000001", "All those moments will be lost in time, like tears in rain. Time to die...", "38aa22d72376b4dbc472e06c3ba403ee0a394da63fc58d88686c611aba98d6b3"); + test_deterministic("e91671c46231f833a6406ccbea0e3e392c76c167bac1cb013f6f1013980455c2", "There is a computer disease that anybody who works with computers knows about. It's a very serious disease and it interferes completely with the work. The trouble with computers is that you 'play' with them!", "1f4b84c23a86a221d233f2521be018d9318639d5b8bbd6374a8a59232d16ad3d"); } END_TEST From 9308fddb7f3ff6c872191416e94874ec0f982843 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 10 Oct 2013 14:58:59 +0200 Subject: [PATCH 047/627] replace blowfish with rijndael --- Makefile | 3 +- README | 2 +- aes.h | 103 +++++++ aescrypt.c | 421 +++++++++++++++++++++++++++ aeskey.c | 369 +++++++++++++++++++++++ aesopt.h | 836 +++++++++++++++++++++++++++++++++++++++++++++++++++++ aestab.c | 494 +++++++++++++++++++++++++++++++ blowfish.c | 409 -------------------------- blowfish.h | 32 -- tests.c | 92 ++---- 10 files changed, 2250 insertions(+), 511 deletions(-) create mode 100644 aes.h create mode 100644 aescrypt.c create mode 100644 aeskey.c create mode 100644 aesopt.h create mode 100644 aestab.c delete mode 100644 blowfish.c delete mode 100644 blowfish.h diff --git a/Makefile b/Makefile index ace51a0d0..24810b13d 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,7 @@ CC = gcc CFLAGS = -Wall -Os -OBJS = bignum.o ecdsa.o secp256k1.o sha2.o rand.o hmac.o bip32.o ripemd160.o blowfish.o +OBJS = bignum.o ecdsa.o secp256k1.o sha2.o rand.o hmac.o bip32.o ripemd160.o +OBJS += aescrypt.o aeskey.o aestab.o all: tests test-openssl diff --git a/README b/README index b669327d7..c3f8ee40d 100644 --- a/README +++ b/README @@ -4,9 +4,9 @@ trezor-crypto Heavily optimized cryptography algorithms for embedded devices. These include: +- AES/Rijndael encryption/decryption - Big Number (256 bit) Arithmetics - BIP32 Hierarchical Deterministic Wallets -- Blowfish encryption/decryption (ECB) - ECDSA signing/verifying (only hardcoded secp256k1 curve, uses RFC6979 for deterministic signatures) - ECDSA public key derivation + Base58 address representation diff --git a/aes.h b/aes.h new file mode 100644 index 000000000..724111956 --- /dev/null +++ b/aes.h @@ -0,0 +1,103 @@ +/* + ------------------------------------------------------------------------- + Copyright (c) 2001, Dr Brian Gladman < >, Worcester, UK. + All rights reserved. + + LICENSE TERMS + + The free distribution and use of this software in both source and binary + form is allowed (with or without changes) provided that: + + 1. distributions of this source code include the above copyright + notice, this list of conditions and the following disclaimer; + + 2. distributions in binary form include the above copyright + notice, this list of conditions and the following disclaimer + in the documentation and/or other associated materials; + + 3. the copyright holder's name is not used to endorse products + built using this software without specific written permission. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and fitness for purpose. + ------------------------------------------------------------------------- + Issue Date: 29/07/2002 + + This file contains the definitions required to use AES (Rijndael) in C. +*/ + +#ifndef _AES_H +#define _AES_H + +/* This include is used only to find 8 and 32 bit unsigned integer types */ + +#include "limits.h" + +#if UCHAR_MAX == 0xff /* an unsigned 8 bit type for internal AES use */ + typedef unsigned char aes_08t; +#else +#error Please define an unsigned 8 bit type in aes.h +#endif + +#if UINT_MAX == 0xffffffff /* an unsigned 32 bit type for internal AES use */ + typedef unsigned int aes_32t; +#elif ULONG_MAX == 0xffffffff + typedef unsigned long aes_32t; +#else +#error Please define an unsigned 32 bit type in aes.h +#endif + +/* BLOCK_SIZE is in BYTES: 16, 24, 32 or undefined for aes.c and 16, 20, + 24, 28, 32 or undefined for aespp.c. When left undefined a slower + version that provides variable block length is compiled. +*/ + +// #define BLOCK_SIZE 16 + +/* key schedule length (in 32-bit words) */ + +#if !defined(BLOCK_SIZE) +#define KS_LENGTH 128 +#else +#define KS_LENGTH 4 * BLOCK_SIZE +#endif + +#if defined(__cplusplus) +extern "C" +{ +#endif + +typedef unsigned int aes_fret; /* type for function return value */ +#define aes_bad 0 /* bad function return value */ +#define aes_good 1 /* good function return value */ +#ifndef AES_DLL /* implement normal or DLL functions */ +#define aes_rval aes_fret +#else +#define aes_rval aes_fret __declspec(dllexport) _stdcall +#endif + + +typedef struct /* the AES context for encryption */ +{ aes_32t k_sch[KS_LENGTH]; /* the encryption key schedule */ + aes_32t n_rnd; /* the number of cipher rounds */ + aes_32t n_blk; /* the number of bytes in the state */ +} aes_ctx; + +#if !defined(BLOCK_SIZE) +aes_rval aes_blk_len(unsigned int blen, aes_ctx cx[1]); +#endif + +aes_rval aes_enc_key(const unsigned char in_key[], unsigned int klen, aes_ctx cx[1]); +aes_rval aes_enc_blk(const unsigned char in_blk[], unsigned char out_blk[], const aes_ctx cx[1]); + +aes_rval aes_dec_key(const unsigned char in_key[], unsigned int klen, aes_ctx cx[1]); +aes_rval aes_dec_blk(const unsigned char in_blk[], unsigned char out_blk[], const aes_ctx cx[1]); + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/aescrypt.c b/aescrypt.c new file mode 100644 index 000000000..a832c6368 --- /dev/null +++ b/aescrypt.c @@ -0,0 +1,421 @@ +/* + ------------------------------------------------------------------------- + Copyright (c) 2001, Dr Brian Gladman < >, Worcester, UK. + All rights reserved. + + LICENSE TERMS + + The free distribution and use of this software in both source and binary + form is allowed (with or without changes) provided that: + + 1. distributions of this source code include the above copyright + notice, this list of conditions and the following disclaimer; + + 2. distributions in binary form include the above copyright + notice, this list of conditions and the following disclaimer + in the documentation and/or other associated materials; + + 3. the copyright holder's name is not used to endorse products + built using this software without specific written permission. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and fitness for purpose. + ------------------------------------------------------------------------- + Issue Date: 29/07/2002 + + This file contains the code for implementing encryption and decryption + for AES (Rijndael) for block and key sizes of 16, 24 and 32 bytes. It + can optionally be replaced by code written in assembler using NASM. +*/ + +#include "aesopt.h" + +#if defined(BLOCK_SIZE) && (BLOCK_SIZE & 7) +#error An illegal block size has been specified. +#endif + +#define unused 77 /* Sunset Strip */ + +#define si(y,x,k,c) s(y,c) = word_in(x + 4 * c) ^ k[c] +#define so(y,x,c) word_out(y + 4 * c, s(x,c)) + +#if BLOCK_SIZE == 16 + +#if defined(ARRAYS) +#define locals(y,x) x[4],y[4] +#else +#define locals(y,x) x##0,x##1,x##2,x##3,y##0,y##1,y##2,y##3 + /* + the following defines prevent the compiler requiring the declaration + of generated but unused variables in the fwd_var and inv_var macros + */ +#define b04 unused +#define b05 unused +#define b06 unused +#define b07 unused +#define b14 unused +#define b15 unused +#define b16 unused +#define b17 unused +#endif +#define l_copy(y, x) s(y,0) = s(x,0); s(y,1) = s(x,1); \ + s(y,2) = s(x,2); s(y,3) = s(x,3); +#define state_in(y,x,k) si(y,x,k,0); si(y,x,k,1); si(y,x,k,2); si(y,x,k,3) +#define state_out(y,x) so(y,x,0); so(y,x,1); so(y,x,2); so(y,x,3) +#define round(rm,y,x,k) rm(y,x,k,0); rm(y,x,k,1); rm(y,x,k,2); rm(y,x,k,3) + +#elif BLOCK_SIZE == 24 + +#if defined(ARRAYS) +#define locals(y,x) x[6],y[6] +#else +#define locals(y,x) x##0,x##1,x##2,x##3,x##4,x##5, \ + y##0,y##1,y##2,y##3,y##4,y##5 +#define b06 unused +#define b07 unused +#define b16 unused +#define b17 unused +#endif +#define l_copy(y, x) s(y,0) = s(x,0); s(y,1) = s(x,1); \ + s(y,2) = s(x,2); s(y,3) = s(x,3); \ + s(y,4) = s(x,4); s(y,5) = s(x,5); +#define state_in(y,x,k) si(y,x,k,0); si(y,x,k,1); si(y,x,k,2); \ + si(y,x,k,3); si(y,x,k,4); si(y,x,k,5) +#define state_out(y,x) so(y,x,0); so(y,x,1); so(y,x,2); \ + so(y,x,3); so(y,x,4); so(y,x,5) +#define round(rm,y,x,k) rm(y,x,k,0); rm(y,x,k,1); rm(y,x,k,2); \ + rm(y,x,k,3); rm(y,x,k,4); rm(y,x,k,5) +#else + +#if defined(ARRAYS) +#define locals(y,x) x[8],y[8] +#else +#define locals(y,x) x##0,x##1,x##2,x##3,x##4,x##5,x##6,x##7, \ + y##0,y##1,y##2,y##3,y##4,y##5,y##6,y##7 +#endif +#define l_copy(y, x) s(y,0) = s(x,0); s(y,1) = s(x,1); \ + s(y,2) = s(x,2); s(y,3) = s(x,3); \ + s(y,4) = s(x,4); s(y,5) = s(x,5); \ + s(y,6) = s(x,6); s(y,7) = s(x,7); + +#if BLOCK_SIZE == 32 + +#define state_in(y,x,k) si(y,x,k,0); si(y,x,k,1); si(y,x,k,2); si(y,x,k,3); \ + si(y,x,k,4); si(y,x,k,5); si(y,x,k,6); si(y,x,k,7) +#define state_out(y,x) so(y,x,0); so(y,x,1); so(y,x,2); so(y,x,3); \ + so(y,x,4); so(y,x,5); so(y,x,6); so(y,x,7) +#define round(rm,y,x,k) rm(y,x,k,0); rm(y,x,k,1); rm(y,x,k,2); rm(y,x,k,3); \ + rm(y,x,k,4); rm(y,x,k,5); rm(y,x,k,6); rm(y,x,k,7) +#else + +#define state_in(y,x,k) \ +switch(nc) \ +{ case 8: si(y,x,k,7); si(y,x,k,6); \ + case 6: si(y,x,k,5); si(y,x,k,4); \ + case 4: si(y,x,k,3); si(y,x,k,2); \ + si(y,x,k,1); si(y,x,k,0); \ +} + +#define state_out(y,x) \ +switch(nc) \ +{ case 8: so(y,x,7); so(y,x,6); \ + case 6: so(y,x,5); so(y,x,4); \ + case 4: so(y,x,3); so(y,x,2); \ + so(y,x,1); so(y,x,0); \ +} + +#if defined(FAST_VARIABLE) + +#define round(rm,y,x,k) \ +switch(nc) \ +{ case 8: rm(y,x,k,7); rm(y,x,k,6); \ + rm(y,x,k,5); rm(y,x,k,4); \ + rm(y,x,k,3); rm(y,x,k,2); \ + rm(y,x,k,1); rm(y,x,k,0); \ + break; \ + case 6: rm(y,x,k,5); rm(y,x,k,4); \ + rm(y,x,k,3); rm(y,x,k,2); \ + rm(y,x,k,1); rm(y,x,k,0); \ + break; \ + case 4: rm(y,x,k,3); rm(y,x,k,2); \ + rm(y,x,k,1); rm(y,x,k,0); \ + break; \ +} +#else + +#define round(rm,y,x,k) \ +switch(nc) \ +{ case 8: rm(y,x,k,7); rm(y,x,k,6); \ + case 6: rm(y,x,k,5); rm(y,x,k,4); \ + case 4: rm(y,x,k,3); rm(y,x,k,2); \ + rm(y,x,k,1); rm(y,x,k,0); \ +} + +#endif + +#endif +#endif + +#if defined(ENCRYPTION) + +/* I am grateful to Frank Yellin for the following construction + (and that for decryption) which, given the column (c) of the + output state variable, gives the input state variables which + are needed in its computation for each row (r) of the state. + + For the fixed block size options, compilers should be able to + reduce this complex expression (and the equivalent one for + decryption) to a static variable reference at compile time. + But for variable block size code, there will be some limbs on + which conditional clauses will be returned. +*/ + +/* y = output word, x = input word, r = row, c = column for r = 0, + 1, 2 and 3 = column accessed for row r. +*/ + +#define fwd_var(x,r,c)\ + ( r == 0 ? \ + ( c == 0 ? s(x,0) \ + : c == 1 ? s(x,1) \ + : c == 2 ? s(x,2) \ + : c == 3 ? s(x,3) \ + : c == 4 ? s(x,4) \ + : c == 5 ? s(x,5) \ + : c == 6 ? s(x,6) \ + : s(x,7))\ + : r == 1 ? \ + ( c == 0 ? s(x,1) \ + : c == 1 ? s(x,2) \ + : c == 2 ? s(x,3) \ + : c == 3 ? nc == 4 ? s(x,0) : s(x,4) \ + : c == 4 ? s(x,5) \ + : c == 5 ? nc == 8 ? s(x,6) : s(x,0) \ + : c == 6 ? s(x,7) \ + : s(x,0))\ + : r == 2 ? \ + ( c == 0 ? nc == 8 ? s(x,3) : s(x,2) \ + : c == 1 ? nc == 8 ? s(x,4) : s(x,3) \ + : c == 2 ? nc == 4 ? s(x,0) : nc == 8 ? s(x,5) : s(x,4) \ + : c == 3 ? nc == 4 ? s(x,1) : nc == 8 ? s(x,6) : s(x,5) \ + : c == 4 ? nc == 8 ? s(x,7) : s(x,0) \ + : c == 5 ? nc == 8 ? s(x,0) : s(x,1) \ + : c == 6 ? s(x,1) \ + : s(x,2))\ + : \ + ( c == 0 ? nc == 8 ? s(x,4) : s(x,3) \ + : c == 1 ? nc == 4 ? s(x,0) : nc == 8 ? s(x,5) : s(x,4) \ + : c == 2 ? nc == 4 ? s(x,1) : nc == 8 ? s(x,6) : s(x,5) \ + : c == 3 ? nc == 4 ? s(x,2) : nc == 8 ? s(x,7) : s(x,0) \ + : c == 4 ? nc == 8 ? s(x,0) : s(x,1) \ + : c == 5 ? nc == 8 ? s(x,1) : s(x,2) \ + : c == 6 ? s(x,2) \ + : s(x,3))) + +#if defined(FT4_SET) +#undef dec_fmvars +#define dec_fmvars +#define fwd_rnd(y,x,k,c) s(y,c)= (k)[c] ^ four_tables(x,ft_tab,fwd_var,rf1,c) +#elif defined(FT1_SET) +#undef dec_fmvars +#define dec_fmvars +#define fwd_rnd(y,x,k,c) s(y,c)= (k)[c] ^ one_table(x,upr,ft_tab,fwd_var,rf1,c) +#else +#define fwd_rnd(y,x,k,c) s(y,c) = fwd_mcol(no_table(x,s_box,fwd_var,rf1,c)) ^ (k)[c] +#endif + +#if defined(FL4_SET) +#define fwd_lrnd(y,x,k,c) s(y,c)= (k)[c] ^ four_tables(x,fl_tab,fwd_var,rf1,c) +#elif defined(FL1_SET) +#define fwd_lrnd(y,x,k,c) s(y,c)= (k)[c] ^ one_table(x,ups,fl_tab,fwd_var,rf1,c) +#else +#define fwd_lrnd(y,x,k,c) s(y,c) = no_table(x,s_box,fwd_var,rf1,c) ^ (k)[c] +#endif + +aes_rval aes_enc_blk(const unsigned char in_blk[], unsigned char out_blk[], const aes_ctx cx[1]) +{ aes_32t locals(b0, b1); + const aes_32t *kp = cx->k_sch; + dec_fmvars /* declare variables for fwd_mcol() if needed */ + + if(!(cx->n_blk & 1)) return aes_bad; + + state_in(b0, in_blk, kp); + +#if (ENC_UNROLL == FULL) + + kp += (cx->n_rnd - 9) * nc; + + switch(cx->n_rnd) + { + case 14: round(fwd_rnd, b1, b0, kp - 4 * nc); + round(fwd_rnd, b0, b1, kp - 3 * nc); + case 12: round(fwd_rnd, b1, b0, kp - 2 * nc); + round(fwd_rnd, b0, b1, kp - nc); + case 10: round(fwd_rnd, b1, b0, kp ); + round(fwd_rnd, b0, b1, kp + nc); + round(fwd_rnd, b1, b0, kp + 2 * nc); + round(fwd_rnd, b0, b1, kp + 3 * nc); + round(fwd_rnd, b1, b0, kp + 4 * nc); + round(fwd_rnd, b0, b1, kp + 5 * nc); + round(fwd_rnd, b1, b0, kp + 6 * nc); + round(fwd_rnd, b0, b1, kp + 7 * nc); + round(fwd_rnd, b1, b0, kp + 8 * nc); + round(fwd_lrnd, b0, b1, kp + 9 * nc); + } +#else + +#if (ENC_UNROLL == PARTIAL) + { aes_32t rnd; + for(rnd = 0; rnd < (cx->n_rnd >> 1) - 1; ++rnd) + { + kp += nc; + round(fwd_rnd, b1, b0, kp); + kp += nc; + round(fwd_rnd, b0, b1, kp); + } + kp += nc; + round(fwd_rnd, b1, b0, kp); +#else + { aes_32t rnd, *p0 = b0, *p1 = b1, *pt; + for(rnd = 0; rnd < cx->n_rnd - 1; ++rnd) + { + kp += nc; + round(fwd_rnd, p1, p0, kp); + pt = p0, p0 = p1, p1 = pt; + } +#endif + kp += nc; + round(fwd_lrnd, b0, b1, kp); + } +#endif + + state_out(out_blk, b0); + return aes_good; +} + +#endif + +#if defined(DECRYPTION) + +#define inv_var(x,r,c) \ + ( r == 0 ? \ + ( c == 0 ? s(x,0) \ + : c == 1 ? s(x,1) \ + : c == 2 ? s(x,2) \ + : c == 3 ? s(x,3) \ + : c == 4 ? s(x,4) \ + : c == 5 ? s(x,5) \ + : c == 6 ? s(x,6) \ + : s(x,7))\ + : r == 1 ? \ + ( c == 0 ? nc == 4 ? s(x,3) : nc == 8 ? s(x,7) : s(x,5) \ + : c == 1 ? s(x,0) \ + : c == 2 ? s(x,1) \ + : c == 3 ? s(x,2) \ + : c == 4 ? s(x,3) \ + : c == 5 ? s(x,4) \ + : c == 6 ? s(x,5) \ + : s(x,6))\ + : r == 2 ? \ + ( c == 0 ? nc == 4 ? s(x,2) : nc == 8 ? s(x,5) : s(x,4) \ + : c == 1 ? nc == 4 ? s(x,3) : nc == 8 ? s(x,6) : s(x,5) \ + : c == 2 ? nc == 8 ? s(x,7) : s(x,0) \ + : c == 3 ? nc == 8 ? s(x,0) : s(x,1) \ + : c == 4 ? nc == 8 ? s(x,1) : s(x,2) \ + : c == 5 ? nc == 8 ? s(x,2) : s(x,3) \ + : c == 6 ? s(x,3) \ + : s(x,4))\ + : \ + ( c == 0 ? nc == 4 ? s(x,1) : nc == 8 ? s(x,4) : s(x,3) \ + : c == 1 ? nc == 4 ? s(x,2) : nc == 8 ? s(x,5) : s(x,4) \ + : c == 2 ? nc == 4 ? s(x,3) : nc == 8 ? s(x,6) : s(x,5) \ + : c == 3 ? nc == 8 ? s(x,7) : s(x,0) \ + : c == 4 ? nc == 8 ? s(x,0) : s(x,1) \ + : c == 5 ? nc == 8 ? s(x,1) : s(x,2) \ + : c == 6 ? s(x,2) \ + : s(x,3))) + +#if defined(IT4_SET) +#undef dec_imvars +#define dec_imvars +#define inv_rnd(y,x,k,c) s(y,c)= (k)[c] ^ four_tables(x,it_tab,inv_var,rf1,c) +#elif defined(IT1_SET) +#undef dec_imvars +#define dec_imvars +#define inv_rnd(y,x,k,c) s(y,c)= (k)[c] ^ one_table(x,upr,it_tab,inv_var,rf1,c) +#else +#define inv_rnd(y,x,k,c) s(y,c) = inv_mcol(no_table(x,inv_s_box,inv_var,rf1,c) ^ (k)[c]) +#endif + +#if defined(IL4_SET) +#define inv_lrnd(y,x,k,c) s(y,c)= (k)[c] ^ four_tables(x,il_tab,inv_var,rf1,c) +#elif defined(IL1_SET) +#define inv_lrnd(y,x,k,c) s(y,c)= (k)[c] ^ one_table(x,ups,il_tab,inv_var,rf1,c) +#else +#define inv_lrnd(y,x,k,c) s(y,c) = no_table(x,inv_s_box,inv_var,rf1,c) ^ (k)[c] +#endif + +aes_rval aes_dec_blk(const unsigned char in_blk[], unsigned char out_blk[], const aes_ctx cx[1]) +{ aes_32t locals(b0, b1); + const aes_32t *kp = cx->k_sch + nc * cx->n_rnd; + dec_imvars /* declare variables for inv_mcol() if needed */ + + if(!(cx->n_blk & 2)) return aes_bad; + + state_in(b0, in_blk, kp); + +#if (DEC_UNROLL == FULL) + + kp = cx->k_sch + 9 * nc; + switch(cx->n_rnd) + { + case 14: round(inv_rnd, b1, b0, kp + 4 * nc); + round(inv_rnd, b0, b1, kp + 3 * nc); + case 12: round(inv_rnd, b1, b0, kp + 2 * nc); + round(inv_rnd, b0, b1, kp + nc ); + case 10: round(inv_rnd, b1, b0, kp ); + round(inv_rnd, b0, b1, kp - nc); + round(inv_rnd, b1, b0, kp - 2 * nc); + round(inv_rnd, b0, b1, kp - 3 * nc); + round(inv_rnd, b1, b0, kp - 4 * nc); + round(inv_rnd, b0, b1, kp - 5 * nc); + round(inv_rnd, b1, b0, kp - 6 * nc); + round(inv_rnd, b0, b1, kp - 7 * nc); + round(inv_rnd, b1, b0, kp - 8 * nc); + round(inv_lrnd, b0, b1, kp - 9 * nc); + } +#else + +#if (DEC_UNROLL == PARTIAL) + { aes_32t rnd; + for(rnd = 0; rnd < (cx->n_rnd >> 1) - 1; ++rnd) + { + kp -= nc; + round(inv_rnd, b1, b0, kp); + kp -= nc; + round(inv_rnd, b0, b1, kp); + } + kp -= nc; + round(inv_rnd, b1, b0, kp); +#else + { aes_32t rnd, *p0 = b0, *p1 = b1, *pt; + for(rnd = 0; rnd < cx->n_rnd - 1; ++rnd) + { + kp -= nc; + round(inv_rnd, p1, p0, kp); + pt = p0, p0 = p1, p1 = pt; + } +#endif + kp -= nc; + round(inv_lrnd, b0, b1, kp); + } +#endif + + state_out(out_blk, b0); + return aes_good; +} + +#endif diff --git a/aeskey.c b/aeskey.c new file mode 100644 index 000000000..b6dee48d3 --- /dev/null +++ b/aeskey.c @@ -0,0 +1,369 @@ +/* + ------------------------------------------------------------------------- + Copyright (c) 2001, Dr Brian Gladman < >, Worcester, UK. + All rights reserved. + + LICENSE TERMS + + The free distribution and use of this software in both source and binary + form is allowed (with or without changes) provided that: + + 1. distributions of this source code include the above copyright + notice, this list of conditions and the following disclaimer; + + 2. distributions in binary form include the above copyright + notice, this list of conditions and the following disclaimer + in the documentation and/or other associated materials; + + 3. the copyright holder's name is not used to endorse products + built using this software without specific written permission. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and fitness for purpose. + ------------------------------------------------------------------------- + Issue Date: 29/07/2002 + + This file contains the code for implementing the key schedule for AES + (Rijndael) for block and key sizes of 16, 24, and 32 bytes. +*/ + +#include "aesopt.h" + +#if defined(BLOCK_SIZE) && (BLOCK_SIZE & 7) +#error An illegal block size has been specified. +#endif + +/* Subroutine to set the block size (if variable) in bytes, legal + values being 16, 24 and 32. +*/ + +#if !defined(BLOCK_SIZE) + +aes_rval aes_blk_len(unsigned int blen, aes_ctx cx[1]) +{ +#if !defined(FIXED_TABLES) + if(!tab_init) gen_tabs(); +#endif + + if((blen & 7) || blen < 16 || blen > 32) + { + cx->n_blk = 0; return aes_bad; + } + + cx->n_blk = blen; + return aes_good; +} + +#endif + +/* Initialise the key schedule from the user supplied key. The key + length is now specified in bytes - 16, 24 or 32 as appropriate. + This corresponds to bit lengths of 128, 192 and 256 bits, and + to Nk values of 4, 6 and 8 respectively. + + The following macros implement a single cycle in the key + schedule generation process. The number of cycles needed + for each cx->n_col and nk value is: + + nk = 4 5 6 7 8 + ------------------------------ + cx->n_col = 4 10 9 8 7 7 + cx->n_col = 5 14 11 10 9 9 + cx->n_col = 6 19 15 12 11 11 + cx->n_col = 7 21 19 16 13 14 + cx->n_col = 8 29 23 19 17 14 +*/ + +#define ke4(k,i) \ +{ k[4*(i)+4] = ss[0] ^= ls_box(ss[3],3) ^ rcon_tab[i]; k[4*(i)+5] = ss[1] ^= ss[0]; \ + k[4*(i)+6] = ss[2] ^= ss[1]; k[4*(i)+7] = ss[3] ^= ss[2]; \ +} +#define kel4(k,i) \ +{ k[4*(i)+4] = ss[0] ^= ls_box(ss[3],3) ^ rcon_tab[i]; k[4*(i)+5] = ss[1] ^= ss[0]; \ + k[4*(i)+6] = ss[2] ^= ss[1]; k[4*(i)+7] = ss[3] ^= ss[2]; \ +} + +#define ke6(k,i) \ +{ k[6*(i)+ 6] = ss[0] ^= ls_box(ss[5],3) ^ rcon_tab[i]; k[6*(i)+ 7] = ss[1] ^= ss[0]; \ + k[6*(i)+ 8] = ss[2] ^= ss[1]; k[6*(i)+ 9] = ss[3] ^= ss[2]; \ + k[6*(i)+10] = ss[4] ^= ss[3]; k[6*(i)+11] = ss[5] ^= ss[4]; \ +} +#define kel6(k,i) \ +{ k[6*(i)+ 6] = ss[0] ^= ls_box(ss[5],3) ^ rcon_tab[i]; k[6*(i)+ 7] = ss[1] ^= ss[0]; \ + k[6*(i)+ 8] = ss[2] ^= ss[1]; k[6*(i)+ 9] = ss[3] ^= ss[2]; \ +} + +#define ke8(k,i) \ +{ k[8*(i)+ 8] = ss[0] ^= ls_box(ss[7],3) ^ rcon_tab[i]; k[8*(i)+ 9] = ss[1] ^= ss[0]; \ + k[8*(i)+10] = ss[2] ^= ss[1]; k[8*(i)+11] = ss[3] ^= ss[2]; \ + k[8*(i)+12] = ss[4] ^= ls_box(ss[3],0); k[8*(i)+13] = ss[5] ^= ss[4]; \ + k[8*(i)+14] = ss[6] ^= ss[5]; k[8*(i)+15] = ss[7] ^= ss[6]; \ +} +#define kel8(k,i) \ +{ k[8*(i)+ 8] = ss[0] ^= ls_box(ss[7],3) ^ rcon_tab[i]; k[8*(i)+ 9] = ss[1] ^= ss[0]; \ + k[8*(i)+10] = ss[2] ^= ss[1]; k[8*(i)+11] = ss[3] ^= ss[2]; \ +} + +#if defined(ENCRYPTION_KEY_SCHEDULE) + +aes_rval aes_enc_key(const unsigned char in_key[], unsigned int klen, aes_ctx cx[1]) +{ aes_32t ss[8]; + +#if !defined(FIXED_TABLES) + if(!tab_init) gen_tabs(); +#endif + +#if !defined(BLOCK_SIZE) + if(!cx->n_blk) cx->n_blk = 16; +#else + cx->n_blk = BLOCK_SIZE; +#endif + + cx->n_blk = (cx->n_blk & ~3) | 1; + + cx->k_sch[0] = ss[0] = word_in(in_key ); + cx->k_sch[1] = ss[1] = word_in(in_key + 4); + cx->k_sch[2] = ss[2] = word_in(in_key + 8); + cx->k_sch[3] = ss[3] = word_in(in_key + 12); + +#if (BLOCK_SIZE == 16) && (ENC_UNROLL != NONE) + + switch(klen) + { + case 16: ke4(cx->k_sch, 0); ke4(cx->k_sch, 1); + ke4(cx->k_sch, 2); ke4(cx->k_sch, 3); + ke4(cx->k_sch, 4); ke4(cx->k_sch, 5); + ke4(cx->k_sch, 6); ke4(cx->k_sch, 7); + ke4(cx->k_sch, 8); kel4(cx->k_sch, 9); + cx->n_rnd = 10; break; + case 24: cx->k_sch[4] = ss[4] = word_in(in_key + 16); + cx->k_sch[5] = ss[5] = word_in(in_key + 20); + ke6(cx->k_sch, 0); ke6(cx->k_sch, 1); + ke6(cx->k_sch, 2); ke6(cx->k_sch, 3); + ke6(cx->k_sch, 4); ke6(cx->k_sch, 5); + ke6(cx->k_sch, 6); kel6(cx->k_sch, 7); + cx->n_rnd = 12; break; + case 32: cx->k_sch[4] = ss[4] = word_in(in_key + 16); + cx->k_sch[5] = ss[5] = word_in(in_key + 20); + cx->k_sch[6] = ss[6] = word_in(in_key + 24); + cx->k_sch[7] = ss[7] = word_in(in_key + 28); + ke8(cx->k_sch, 0); ke8(cx->k_sch, 1); + ke8(cx->k_sch, 2); ke8(cx->k_sch, 3); + ke8(cx->k_sch, 4); ke8(cx->k_sch, 5); + kel8(cx->k_sch, 6); + cx->n_rnd = 14; break; + default: cx->n_rnd = 0; return aes_bad; + } +#else + { aes_32t i, l; + cx->n_rnd = ((klen >> 2) > nc ? (klen >> 2) : nc) + 6; + l = (nc * cx->n_rnd + nc - 1) / (klen >> 2); + + switch(klen) + { + case 16: for(i = 0; i < l; ++i) + ke4(cx->k_sch, i); + break; + case 24: cx->k_sch[4] = ss[4] = word_in(in_key + 16); + cx->k_sch[5] = ss[5] = word_in(in_key + 20); + for(i = 0; i < l; ++i) + ke6(cx->k_sch, i); + break; + case 32: cx->k_sch[4] = ss[4] = word_in(in_key + 16); + cx->k_sch[5] = ss[5] = word_in(in_key + 20); + cx->k_sch[6] = ss[6] = word_in(in_key + 24); + cx->k_sch[7] = ss[7] = word_in(in_key + 28); + for(i = 0; i < l; ++i) + ke8(cx->k_sch, i); + break; + default: cx->n_rnd = 0; return aes_bad; + } + } +#endif + + return aes_good; +} + +#endif + +#if defined(DECRYPTION_KEY_SCHEDULE) + +#if (DEC_ROUND != NO_TABLES) +#define d_vars dec_imvars +#define ff(x) inv_mcol(x) +#else +#define ff(x) (x) +#define d_vars +#endif + +#if 1 +#define kdf4(k,i) \ +{ ss[0] = ss[0] ^ ss[2] ^ ss[1] ^ ss[3]; ss[1] = ss[1] ^ ss[3]; ss[2] = ss[2] ^ ss[3]; ss[3] = ss[3]; \ + ss[4] = ls_box(ss[(i+3) % 4], 3) ^ rcon_tab[i]; ss[i % 4] ^= ss[4]; \ + ss[4] ^= k[4*(i)]; k[4*(i)+4] = ff(ss[4]); ss[4] ^= k[4*(i)+1]; k[4*(i)+5] = ff(ss[4]); \ + ss[4] ^= k[4*(i)+2]; k[4*(i)+6] = ff(ss[4]); ss[4] ^= k[4*(i)+3]; k[4*(i)+7] = ff(ss[4]); \ +} +#define kd4(k,i) \ +{ ss[4] = ls_box(ss[(i+3) % 4], 3) ^ rcon_tab[i]; ss[i % 4] ^= ss[4]; ss[4] = ff(ss[4]); \ + k[4*(i)+4] = ss[4] ^= k[4*(i)]; k[4*(i)+5] = ss[4] ^= k[4*(i)+1]; \ + k[4*(i)+6] = ss[4] ^= k[4*(i)+2]; k[4*(i)+7] = ss[4] ^= k[4*(i)+3]; \ +} +#define kdl4(k,i) \ +{ ss[4] = ls_box(ss[(i+3) % 4], 3) ^ rcon_tab[i]; ss[i % 4] ^= ss[4]; \ + k[4*(i)+4] = (ss[0] ^= ss[1]) ^ ss[2] ^ ss[3]; k[4*(i)+5] = ss[1] ^ ss[3]; \ + k[4*(i)+6] = ss[0]; k[4*(i)+7] = ss[1]; \ +} +#else +#define kdf4(k,i) \ +{ ss[0] ^= ls_box(ss[3],3) ^ rcon_tab[i]; k[4*(i)+ 4] = ff(ss[0]); ss[1] ^= ss[0]; k[4*(i)+ 5] = ff(ss[1]); \ + ss[2] ^= ss[1]; k[4*(i)+ 6] = ff(ss[2]); ss[3] ^= ss[2]; k[4*(i)+ 7] = ff(ss[3]); \ +} +#define kd4(k,i) \ +{ ss[4] = ls_box(ss[3],3) ^ rcon_tab[i]; \ + ss[0] ^= ss[4]; ss[4] = ff(ss[4]); k[4*(i)+ 4] = ss[4] ^= k[4*(i)]; \ + ss[1] ^= ss[0]; k[4*(i)+ 5] = ss[4] ^= k[4*(i)+ 1]; \ + ss[2] ^= ss[1]; k[4*(i)+ 6] = ss[4] ^= k[4*(i)+ 2]; \ + ss[3] ^= ss[2]; k[4*(i)+ 7] = ss[4] ^= k[4*(i)+ 3]; \ +} +#define kdl4(k,i) \ +{ ss[0] ^= ls_box(ss[3],3) ^ rcon_tab[i]; k[4*(i)+ 4] = ss[0]; ss[1] ^= ss[0]; k[4*(i)+ 5] = ss[1]; \ + ss[2] ^= ss[1]; k[4*(i)+ 6] = ss[2]; ss[3] ^= ss[2]; k[4*(i)+ 7] = ss[3]; \ +} +#endif + +#define kdf6(k,i) \ +{ ss[0] ^= ls_box(ss[5],3) ^ rcon_tab[i]; k[6*(i)+ 6] = ff(ss[0]); ss[1] ^= ss[0]; k[6*(i)+ 7] = ff(ss[1]); \ + ss[2] ^= ss[1]; k[6*(i)+ 8] = ff(ss[2]); ss[3] ^= ss[2]; k[6*(i)+ 9] = ff(ss[3]); \ + ss[4] ^= ss[3]; k[6*(i)+10] = ff(ss[4]); ss[5] ^= ss[4]; k[6*(i)+11] = ff(ss[5]); \ +} +#define kd6(k,i) \ +{ ss[6] = ls_box(ss[5],3) ^ rcon_tab[i]; \ + ss[0] ^= ss[6]; ss[6] = ff(ss[6]); k[6*(i)+ 6] = ss[6] ^= k[6*(i)]; \ + ss[1] ^= ss[0]; k[6*(i)+ 7] = ss[6] ^= k[6*(i)+ 1]; \ + ss[2] ^= ss[1]; k[6*(i)+ 8] = ss[6] ^= k[6*(i)+ 2]; \ + ss[3] ^= ss[2]; k[6*(i)+ 9] = ss[6] ^= k[6*(i)+ 3]; \ + ss[4] ^= ss[3]; k[6*(i)+10] = ss[6] ^= k[6*(i)+ 4]; \ + ss[5] ^= ss[4]; k[6*(i)+11] = ss[6] ^= k[6*(i)+ 5]; \ +} +#define kdl6(k,i) \ +{ ss[0] ^= ls_box(ss[5],3) ^ rcon_tab[i]; k[6*(i)+ 6] = ss[0]; ss[1] ^= ss[0]; k[6*(i)+ 7] = ss[1]; \ + ss[2] ^= ss[1]; k[6*(i)+ 8] = ss[2]; ss[3] ^= ss[2]; k[6*(i)+ 9] = ss[3]; \ +} + +#define kdf8(k,i) \ +{ ss[0] ^= ls_box(ss[7],3) ^ rcon_tab[i]; k[8*(i)+ 8] = ff(ss[0]); ss[1] ^= ss[0]; k[8*(i)+ 9] = ff(ss[1]); \ + ss[2] ^= ss[1]; k[8*(i)+10] = ff(ss[2]); ss[3] ^= ss[2]; k[8*(i)+11] = ff(ss[3]); \ + ss[4] ^= ls_box(ss[3],0); k[8*(i)+12] = ff(ss[4]); ss[5] ^= ss[4]; k[8*(i)+13] = ff(ss[5]); \ + ss[6] ^= ss[5]; k[8*(i)+14] = ff(ss[6]); ss[7] ^= ss[6]; k[8*(i)+15] = ff(ss[7]); \ +} +#define kd8(k,i) \ +{ aes_32t g = ls_box(ss[7],3) ^ rcon_tab[i]; \ + ss[0] ^= g; g = ff(g); k[8*(i)+ 8] = g ^= k[8*(i)]; \ + ss[1] ^= ss[0]; k[8*(i)+ 9] = g ^= k[8*(i)+ 1]; \ + ss[2] ^= ss[1]; k[8*(i)+10] = g ^= k[8*(i)+ 2]; \ + ss[3] ^= ss[2]; k[8*(i)+11] = g ^= k[8*(i)+ 3]; \ + g = ls_box(ss[3],0); \ + ss[4] ^= g; g = ff(g); k[8*(i)+12] = g ^= k[8*(i)+ 4]; \ + ss[5] ^= ss[4]; k[8*(i)+13] = g ^= k[8*(i)+ 5]; \ + ss[6] ^= ss[5]; k[8*(i)+14] = g ^= k[8*(i)+ 6]; \ + ss[7] ^= ss[6]; k[8*(i)+15] = g ^= k[8*(i)+ 7]; \ +} +#define kdl8(k,i) \ +{ ss[0] ^= ls_box(ss[7],3) ^ rcon_tab[i]; k[8*(i)+ 8] = ss[0]; ss[1] ^= ss[0]; k[8*(i)+ 9] = ss[1]; \ + ss[2] ^= ss[1]; k[8*(i)+10] = ss[2]; ss[3] ^= ss[2]; k[8*(i)+11] = ss[3]; \ +} + +aes_rval aes_dec_key(const unsigned char in_key[], unsigned int klen, aes_ctx cx[1]) +{ aes_32t ss[8]; + d_vars + +#if !defined(FIXED_TABLES) + if(!tab_init) gen_tabs(); +#endif + +#if !defined(BLOCK_SIZE) + if(!cx->n_blk) cx->n_blk = 16; +#else + cx->n_blk = BLOCK_SIZE; +#endif + + cx->n_blk = (cx->n_blk & ~3) | 2; + + cx->k_sch[0] = ss[0] = word_in(in_key ); + cx->k_sch[1] = ss[1] = word_in(in_key + 4); + cx->k_sch[2] = ss[2] = word_in(in_key + 8); + cx->k_sch[3] = ss[3] = word_in(in_key + 12); + +#if (BLOCK_SIZE == 16) && (DEC_UNROLL != NONE) + + switch(klen) + { + case 16: kdf4(cx->k_sch, 0); kd4(cx->k_sch, 1); + kd4(cx->k_sch, 2); kd4(cx->k_sch, 3); + kd4(cx->k_sch, 4); kd4(cx->k_sch, 5); + kd4(cx->k_sch, 6); kd4(cx->k_sch, 7); + kd4(cx->k_sch, 8); kdl4(cx->k_sch, 9); + cx->n_rnd = 10; break; + case 24: ss[4] = word_in(in_key + 16); + cx->k_sch[4] = ff(ss[4]); + ss[5] = word_in(in_key + 20); + cx->k_sch[5] = ff(ss[5]); + kdf6(cx->k_sch, 0); kd6(cx->k_sch, 1); + kd6(cx->k_sch, 2); kd6(cx->k_sch, 3); + kd6(cx->k_sch, 4); kd6(cx->k_sch, 5); + kd6(cx->k_sch, 6); kdl6(cx->k_sch, 7); + cx->n_rnd = 12; break; + case 32: ss[4] = word_in(in_key + 16); + cx->k_sch[4] = ff(ss[4]); + ss[5] = word_in(in_key + 20); + cx->k_sch[5] = ff(ss[5]); + ss[6] = word_in(in_key + 24); + cx->k_sch[6] = ff(ss[6]); + ss[7] = word_in(in_key + 28); + cx->k_sch[7] = ff(ss[7]); + kdf8(cx->k_sch, 0); kd8(cx->k_sch, 1); + kd8(cx->k_sch, 2); kd8(cx->k_sch, 3); + kd8(cx->k_sch, 4); kd8(cx->k_sch, 5); + kdl8(cx->k_sch, 6); + cx->n_rnd = 14; break; + default: cx->n_rnd = 0; return aes_bad; + } +#else + { aes_32t i, l; + cx->n_rnd = ((klen >> 2) > nc ? (klen >> 2) : nc) + 6; + l = (nc * cx->n_rnd + nc - 1) / (klen >> 2); + + switch(klen) + { + case 16: + for(i = 0; i < l; ++i) + ke4(cx->k_sch, i); + break; + case 24: cx->k_sch[4] = ss[4] = word_in(in_key + 16); + cx->k_sch[5] = ss[5] = word_in(in_key + 20); + for(i = 0; i < l; ++i) + ke6(cx->k_sch, i); + break; + case 32: cx->k_sch[4] = ss[4] = word_in(in_key + 16); + cx->k_sch[5] = ss[5] = word_in(in_key + 20); + cx->k_sch[6] = ss[6] = word_in(in_key + 24); + cx->k_sch[7] = ss[7] = word_in(in_key + 28); + for(i = 0; i < l; ++i) + ke8(cx->k_sch, i); + break; + default: cx->n_rnd = 0; return aes_bad; + } +#if (DEC_ROUND != NO_TABLES) + for(i = nc; i < nc * cx->n_rnd; ++i) + cx->k_sch[i] = inv_mcol(cx->k_sch[i]); +#endif + } +#endif + + return aes_good; +} + +#endif diff --git a/aesopt.h b/aesopt.h new file mode 100644 index 000000000..485d5ec3e --- /dev/null +++ b/aesopt.h @@ -0,0 +1,836 @@ +/* + ------------------------------------------------------------------------- + Copyright (c) 2001, Dr Brian Gladman < >, Worcester, UK. + All rights reserved. + + LICENSE TERMS + + The free distribution and use of this software in both source and binary + form is allowed (with or without changes) provided that: + + 1. distributions of this source code include the above copyright + notice, this list of conditions and the following disclaimer; + + 2. distributions in binary form include the above copyright + notice, this list of conditions and the following disclaimer + in the documentation and/or other associated materials; + + 3. the copyright holder's name is not used to endorse products + built using this software without specific written permission. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and fitness for purpose. + ------------------------------------------------------------------------- + Issue Date: 29/07/2002 + + This file contains the compilation options for AES (Rijndael) and code + that is common across encryption, key scheduling and table generation. + + OPERATION + + These source code files implement the AES algorithm Rijndael designed by + Joan Daemen and Vincent Rijmen. The version in aes.c is designed for + block and key sizes of 128, 192 and 256 bits (16, 24 and 32 bytes) while + that in aespp.c provides for block and keys sizes of 128, 160, 192, 224 + and 256 bits (16, 20, 24, 28 and 32 bytes). This file is a common header + file for these two implementations and for aesref.c, which is a reference + implementation. + + This version is designed for flexibility and speed using operations on + 32-bit words rather than operations on bytes. It provides aes_both fixed + and dynamic block and key lengths and can also run with either big or + little endian internal byte order (see aes.h). It inputs block and key + lengths in bytes with the legal values being 16, 24 and 32 for aes.c and + 16, 20, 24, 28 and 32 for aespp.c + + THE CIPHER INTERFACE + + aes_08t (an unsigned 8-bit type) + aes_32t (an unsigned 32-bit type) + aes_fret (a signed 16 bit type for function return values) + aes_good (value != 0, a good return) + aes_bad (value == 0, an error return) + struct aes_ctx (structure for the cipher encryption context) + struct aes_ctx (structure for the cipher decryption context) + aes_rval the function return type (aes_fret if not DLL) + + C subroutine calls: + + aes_rval aes_blk_len(unsigned int blen, aes_ctx cx[1]); + aes_rval aes_enc_key(const unsigned char in_key[], unsigned int klen, aes_ctx cx[1]); + aes_rval aes_enc_blk(const unsigned char in_blk[], unsigned char out_blk[], const aes_ctx cx[1]); + + aes_rval aes_dec_len(unsigned int blen, aes_ctx cx[1]); + aes_rval aes_dec_key(const unsigned char in_key[], unsigned int klen, aes_ctx cx[1]); + aes_rval aes_dec_blk(const unsigned char in_blk[], unsigned char out_blk[], const aes_ctx cx[1]); + + IMPORTANT NOTE: If you are using this C interface and your compiler does + not set the memory used for objects to zero before use, you will need to + ensure that cx.s_flg is set to zero before using these subroutine calls. + + C++ aes class subroutines: + + class AESclass for encryption + class AESclass for decryption + + aes_rval len(unsigned int blen = 16); + aes_rval key(const unsigned char in_key[], unsigned int klen); + aes_rval blk(const unsigned char in_blk[], unsigned char out_blk[]); + + aes_rval len(unsigned int blen = 16); + aes_rval key(const unsigned char in_key[], unsigned int klen); + aes_rval blk(const unsigned char in_blk[], unsigned char out_blk[]); + + The block length inputs to set_block and set_key are in numbers of + BYTES, not bits. The calls to subroutines must be made in the above + order but multiple calls can be made without repeating earlier calls + if their parameters have not changed. If the cipher block length is + variable but set_blk has not been called before cipher operations a + value of 16 is assumed (that is, the AES block size). In contrast to + earlier versions the block and key length parameters are now checked + for correctness and the encryption and decryption routines check to + ensure that an appropriate key has been set before they are called. + + COMPILATION + + The files used to provide AES (Rijndael) are + + a. aes.h for the definitions needed for use in C. + b. aescpp.h for the definitions needed for use in C++. + c. aesopt.h for setting compilation options (also includes common + code). + d. aescrypt.c for encryption and decrytpion, or + e. aescrypt.asm for encryption and decryption using assembler code. + f. aeskey.c for key scheduling. + g. aestab.c for table loading or generation. + + The assembler code uses the NASM assembler. The above files provice + block and key lengths of 16, 24 and 32 bytes (128, 192 and 256 bits). + If aescrypp.c and aeskeypp.c are used instead of aescrypt.c and + aeskey.c respectively, the block and key lengths can then be 16, 20, + 24, 28 or 32 bytes. However this code has not been optimised to the + same extent and is hence slower (esepcially for the AES block size + of 16 bytes). + + To compile AES (Rijndael) for use in C code use aes.h and exclude + the AES_DLL define in aes.h + + To compile AES (Rijndael) for use in in C++ code use aescpp.h and + exclude the AES_DLL define in aes.h + + To compile AES (Rijndael) in C as a Dynamic Link Library DLL) use + aes.h, include the AES_DLL define and compile the DLL. If using + the test files to test the DLL, exclude aes.c from the test build + project and compile it with the same defines as used for the DLL + (ensure that the DLL path is correct) + + CONFIGURATION OPTIONS (here and in aes.h) + + a. define BLOCK_SIZE in aes.h to set the cipher block size (16, 24 + or 32 for the standard code, or 16, 20, 24, 28 or 32 for the + extended code) or leave this undefined for dynamically variable + block size (this will result in much slower code). + b. set AES_DLL in aes.h if AES (Rijndael) is to be compiled as a DLL + c. You may need to set PLATFORM_BYTE_ORDER to define the byte order. + d. If you want the code to run in a specific internal byte order, then + INTERNAL_BYTE_ORDER must be set accordingly. + e. set other configuration options decribed below. +*/ + +#ifndef _AESOPT_H +#define _AESOPT_H + +/* START OF CONFIGURATION OPTIONS + + USE OF DEFINES + + Later in this section there are a number of defines that control the + operation of the code. In each section, the purpose of each define is + explained so that the relevant form can be included or excluded by + setting either 1's or 0's respectively on the branches of the related + #if clauses. +*/ + +/* 1. PLATFORM SPECIFIC INCLUDES */ + +#include "aes.h" +#define PLATFORM_BYTE_ORDER AES_LITTLE_ENDIAN + +/* +#if defined( __CRYPTLIB__ ) && !defined( INC_ALL ) && !defined( INC_CHILD ) +#include "crypt/aes.h" +#else + #include "aes.h" +#endif + +#if defined(__GNUC__) || defined(__GNU_LIBRARY__) +//# include +//# include +#elif defined(__CRYPTLIB__) +# if defined( INC_ALL ) +# include "crypt.h" +# elif defined( INC_CHILD ) +# include "../crypt.h" +# else +# include "crypt.h" +# endif +# if defined(DATA_LITTLEENDIAN) +# define PLATFORM_BYTE_ORDER AES_LITTLE_ENDIAN +# else +# define PLATFORM_BYTE_ORDER AES_BIG_ENDIAN +# endif +#elif defined(_MSC_VER) +# include +#elif !defined(WIN32) +# include +# if !defined (_ENDIAN_H) +# include +# else +# include _ENDIAN_H +# endif +#endif +*/ + +/* 2. BYTE ORDER IN 32-BIT WORDS + + To obtain the highest speed on processors with 32-bit words, this code + needs to determine the order in which bytes are packed into such words. + The following block of code is an attempt to capture the most obvious + ways in which various environemnts define byte order. It may well fail, + in which case the definitions will need to be set by editing at the + points marked **** EDIT HERE IF NECESSARY **** below. +*/ +#define AES_LITTLE_ENDIAN 1234 /* byte 0 is least significant (i386) */ +#define AES_BIG_ENDIAN 4321 /* byte 0 is most significant (mc68k) */ + +#if !defined(PLATFORM_BYTE_ORDER) +#if defined(LITTLE_ENDIAN) || defined(BIG_ENDIAN) +# if defined(LITTLE_ENDIAN) && defined(BIG_ENDIAN) +# if defined(BYTE_ORDER) +# if (BYTE_ORDER == LITTLE_ENDIAN) +# define PLATFORM_BYTE_ORDER AES_LITTLE_ENDIAN +# elif (BYTE_ORDER == BIG_ENDIAN) +# define PLATFORM_BYTE_ORDER AES_BIG_ENDIAN +# endif +# endif +# elif defined(LITTLE_ENDIAN) && !defined(BIG_ENDIAN) +# define PLATFORM_BYTE_ORDER AES_LITTLE_ENDIAN +# elif !defined(LITTLE_ENDIAN) && defined(BIG_ENDIAN) +# define PLATFORM_BYTE_ORDER AES_BIG_ENDIAN +# endif +#elif defined(_LITTLE_ENDIAN) || defined(_BIG_ENDIAN) +# if defined(_LITTLE_ENDIAN) && defined(_BIG_ENDIAN) +# if defined(_BYTE_ORDER) +# if (_BYTE_ORDER == _LITTLE_ENDIAN) +# define PLATFORM_BYTE_ORDER AES_LITTLE_ENDIAN +# elif (_BYTE_ORDER == _BIG_ENDIAN) +# define PLATFORM_BYTE_ORDER AES_BIG_ENDIAN +# endif +# endif +# elif defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN) +# define PLATFORM_BYTE_ORDER AES_LITTLE_ENDIAN +# elif !defined(_LITTLE_ENDIAN) && defined(_BIG_ENDIAN) +# define PLATFORM_BYTE_ORDER AES_BIG_ENDIAN +# endif +#elif 0 /* **** EDIT HERE IF NECESSARY **** */ +#define PLATFORM_BYTE_ORDER AES_LITTLE_ENDIAN +#elif 0 /* **** EDIT HERE IF NECESSARY **** */ +#define PLATFORM_BYTE_ORDER AES_BIG_ENDIAN +/* +#elif (('1234' >> 24) == '1') +# define PLATFORM_BYTE_ORDER AES_LITTLE_ENDIAN +#elif (('4321' >> 24) == '1') +# define PLATFORM_BYTE_ORDER AES_BIG_ENDIAN +*/ +#endif +#endif + +#if !defined(PLATFORM_BYTE_ORDER) +# error Please set undetermined byte order (lines 233 or 235 of aesopt.h). +#endif + +/* 3. ASSEMBLER SUPPORT + + If the assembler code is used for encryption and decryption this file only + provides key scheduling so the following defines are used +*/ +#ifdef AES_ASM +#define ENCRYPTION_KEY_SCHEDULE +#define DECRYPTION_KEY_SCHEDULE +#else + +/* 4. FUNCTIONS REQUIRED + + This implementation provides five main subroutines which provide for + setting block length, setting encryption and decryption keys and for + encryption and decryption. When the assembler code is not being used + the following definition blocks allow the selection of the routines + that are to be included in the compilation. +*/ +#if 1 +#define ENCRYPTION_KEY_SCHEDULE +#endif + +#if 1 +#define DECRYPTION_KEY_SCHEDULE +#endif + +#if 1 +#define ENCRYPTION +#endif + +#if 1 +#define DECRYPTION +#endif + +#endif + +/* 5. BYTE ORDER WITHIN 32 BIT WORDS + + The fundamental data processing units in Rijndael are 8-bit bytes. The + input, output and key input are all enumerated arrays of bytes in which + bytes are numbered starting at zero and increasing to one less than the + number of bytes in the array in question. This enumeration is only used + for naming bytes and does not imply any adjacency or order relationship + from one byte to another. When these inputs and outputs are considered + as bit sequences, bits 8*n to 8*n+7 of the bit sequence are mapped to + byte[n] with bit 8n+i in the sequence mapped to bit 7-i within the byte. + In this implementation bits are numbered from 0 to 7 starting at the + numerically least significant end of each byte (bit n represents 2^n). + + However, Rijndael can be implemented more efficiently using 32-bit + words by packing bytes into words so that bytes 4*n to 4*n+3 are placed + into word[n]. While in principle these bytes can be assembled into words + in any positions, this implementation only supports the two formats in + which bytes in adjacent positions within words also have adjacent byte + numbers. This order is called big-endian if the lowest numbered bytes + in words have the highest numeric significance and little-endian if the + opposite applies. + + This code can work in either order irrespective of the order used by the + machine on which it runs. Normally the internal byte order will be set + to the order of the processor on which the code is to be run but this + define can be used to reverse this in special situations +*/ +#if 1 +#define INTERNAL_BYTE_ORDER PLATFORM_BYTE_ORDER +#elif defined(AES_LITTLE_ENDIAN) +#define INTERNAL_BYTE_ORDER AES_LITTLE_ENDIAN +#elif defined(AES_BIG_ENDIAN) +#define INTERNAL_BYTE_ORDER AES_BIG_ENDIAN +#endif + +/* 6. FAST INPUT/OUTPUT OPERATIONS. + + On some machines it is possible to improve speed by transferring the + bytes in the input and output arrays to and from the internal 32-bit + variables by addressing these arrays as if they are arrays of 32-bit + words. On some machines this will always be possible but there may + be a large performance penalty if the byte arrays are not aligned on + the normal word boundaries. On other machines this technique will + lead to memory access errors when such 32-bit word accesses are not + properly aligned. The option SAFE_IO avoids such problems but will + often be slower on those machines that support misaligned access + (especially so if care is taken to align the input and output byte + arrays on 32-bit word boundaries). If SAFE_IO is not defined it is + assumed that access to byte arrays as if they are arrays of 32-bit + words will not cause problems when such accesses are misaligned. +*/ +#if 1 +#define SAFE_IO +#endif + +/* 7. LOOP UNROLLING + + The code for encryption and decrytpion cycles through a number of rounds + that can be implemented either in a loop or by expanding the code into a + long sequence of instructions, the latter producing a larger program but + one that will often be much faster. The latter is called loop unrolling. + There are also potential speed advantages in expanding two iterations in + a loop with half the number of iterations, which is called partial loop + unrolling. The following options allow partial or full loop unrolling + to be set independently for encryption and decryption +*/ +#if 1 +#define ENC_UNROLL FULL +#elif 0 +#define ENC_UNROLL PARTIAL +#else +#define ENC_UNROLL NONE +#endif + +#if 1 +#define DEC_UNROLL FULL +#elif 0 +#define DEC_UNROLL PARTIAL +#else +#define DEC_UNROLL NONE +#endif + +/* 8. FIXED OR DYNAMIC TABLES + + When this section is included the tables used by the code are comipled + statically into the binary file. Otherwise they are computed once when + the code is first used. +*/ +#if 1 +#define FIXED_TABLES +#endif + +/* 9. FAST FINITE FIELD OPERATIONS + + If this section is included, tables are used to provide faster finite + field arithmetic (this has no effect if FIXED_TABLES is defined). +*/ +#if 1 +#define FF_TABLES +#endif + +/* 10. INTERNAL STATE VARIABLE FORMAT + + The internal state of Rijndael is stored in a number of local 32-bit + word varaibles which can be defined either as an array or as individual + names variables. Include this section if you want to store these local + varaibles in arrays. Otherwise individual local variables will be used. +*/ +#if 1 +#define ARRAYS +#endif + +/* In this implementation the columns of the state array are each held in + 32-bit words. The state array can be held in various ways: in an array + of words, in a number of individual word variables or in a number of + processor registers. The following define maps a variable name x and + a column number c to the way the state array variable is to be held. + The first define below maps the state into an array x[c] whereas the + second form maps the state into a number of individual variables x0, + x1, etc. Another form could map individual state colums to machine + register names. +*/ + +#if defined(ARRAYS) +#define s(x,c) x[c] +#else +#define s(x,c) x##c +#endif + +/* 11. VARIABLE BLOCK SIZE SPEED + + This section is only relevant if you wish to use the variable block + length feature of the code. Include this section if you place more + emphasis on speed rather than code size. +*/ +#if 1 +#define FAST_VARIABLE +#endif + +/* 12. INTERNAL TABLE CONFIGURATION + + This cipher proceeds by repeating in a number of cycles known as 'rounds' + which are implemented by a round function which can optionally be speeded + up using tables. The basic tables are each 256 32-bit words, with either + one or four tables being required for each round function depending on + how much speed is required. The encryption and decryption round functions + are different and the last encryption and decrytpion round functions are + different again making four different round functions in all. + + This means that: + 1. Normal encryption and decryption rounds can each use either 0, 1 + or 4 tables and table spaces of 0, 1024 or 4096 bytes each. + 2. The last encryption and decryption rounds can also use either 0, 1 + or 4 tables and table spaces of 0, 1024 or 4096 bytes each. + + Include or exclude the appropriate definitions below to set the number + of tables used by this implementation. +*/ + +#if 1 /* set tables for the normal encryption round */ +#define ENC_ROUND FOUR_TABLES +#elif 0 +#define ENC_ROUND ONE_TABLE +#else +#define ENC_ROUND NO_TABLES +#endif + +#if 1 /* set tables for the last encryption round */ +#define LAST_ENC_ROUND FOUR_TABLES +#elif 0 +#define LAST_ENC_ROUND ONE_TABLE +#else +#define LAST_ENC_ROUND NO_TABLES +#endif + +#if 1 /* set tables for the normal decryption round */ +#define DEC_ROUND FOUR_TABLES +#elif 0 +#define DEC_ROUND ONE_TABLE +#else +#define DEC_ROUND NO_TABLES +#endif + +#if 1 /* set tables for the last decryption round */ +#define LAST_DEC_ROUND FOUR_TABLES +#elif 0 +#define LAST_DEC_ROUND ONE_TABLE +#else +#define LAST_DEC_ROUND NO_TABLES +#endif + +/* The decryption key schedule can be speeded up with tables in the same + way that the round functions can. Include or exclude the following + defines to set this requirement. +*/ +#if 1 +#define KEY_SCHED FOUR_TABLES +#elif 0 +#define KEY_SCHED ONE_TABLE +#else +#define KEY_SCHED NO_TABLES +#endif + +/* END OF CONFIGURATION OPTIONS */ + +#define NO_TABLES 0 /* DO NOT CHANGE */ +#define ONE_TABLE 1 /* DO NOT CHANGE */ +#define FOUR_TABLES 4 /* DO NOT CHANGE */ +#define NONE 0 /* DO NOT CHANGE */ +#define PARTIAL 1 /* DO NOT CHANGE */ +#define FULL 2 /* DO NOT CHANGE */ + +#if defined(BLOCK_SIZE) && ((BLOCK_SIZE & 3) || BLOCK_SIZE < 16 || BLOCK_SIZE > 32) +#error An illegal block size has been specified. +#endif + +#if !defined(BLOCK_SIZE) +#define RC_LENGTH 29 +#else +#define RC_LENGTH 5 * BLOCK_SIZE / 4 - (BLOCK_SIZE == 16 ? 10 : 11) +#endif + +/* Disable at least some poor combinations of options */ + +#if ENC_ROUND == NO_TABLES && LAST_ENC_ROUND != NO_TABLES +#undef LAST_ENC_ROUND +#define LAST_ENC_ROUND NO_TABLES +#elif ENC_ROUND == ONE_TABLE && LAST_ENC_ROUND == FOUR_TABLES +#undef LAST_ENC_ROUND +#define LAST_ENC_ROUND ONE_TABLE +#endif + +#if ENC_ROUND == NO_TABLES && ENC_UNROLL != NONE +#undef ENC_UNROLL +#define ENC_UNROLL NONE +#endif + +#if DEC_ROUND == NO_TABLES && LAST_DEC_ROUND != NO_TABLES +#undef LAST_DEC_ROUND +#define LAST_DEC_ROUND NO_TABLES +#elif DEC_ROUND == ONE_TABLE && LAST_DEC_ROUND == FOUR_TABLES +#undef LAST_DEC_ROUND +#define LAST_DEC_ROUND ONE_TABLE +#endif + +#if DEC_ROUND == NO_TABLES && DEC_UNROLL != NONE +#undef DEC_UNROLL +#define DEC_UNROLL NONE +#endif + +/* upr(x,n): rotates bytes within words by n positions, moving bytes to + higher index positions with wrap around into low positions + ups(x,n): moves bytes by n positions to higher index positions in + words but without wrap around + bval(x,n): extracts a byte from a word + + NOTE: The definitions given here are intended only for use with + unsigned variables and with shift counts that are compile + time constants +*/ + +#if (INTERNAL_BYTE_ORDER == AES_LITTLE_ENDIAN) +#if defined(_MSC_VER) +#define upr(x,n) _lrotl((aes_32t)(x), 8 * (n)) +#else +#define upr(x,n) ((aes_32t)(x) << 8 * (n) | (aes_32t)(x) >> 32 - 8 * (n)) +#endif +#define ups(x,n) ((aes_32t)(x) << 8 * (n)) +#define bval(x,n) ((aes_08t)((x) >> 8 * (n))) +#define bytes2word(b0, b1, b2, b3) \ + (((aes_32t)(b3) << 24) | ((aes_32t)(b2) << 16) | ((aes_32t)(b1) << 8) | (b0)) +#endif + +#if (INTERNAL_BYTE_ORDER == AES_BIG_ENDIAN) +#define upr(x,n) ((aes_32t)(x) >> 8 * (n) | (aes_32t)(x) << 32 - 8 * (n)) +#define ups(x,n) ((aes_32t)(x) >> 8 * (n))) +#define bval(x,n) ((aes_08t)((x) >> 24 - 8 * (n))) +#define bytes2word(b0, b1, b2, b3) \ + (((aes_32t)(b0) << 24) | ((aes_32t)(b1) << 16) | ((aes_32t)(b2) << 8) | (b3)) +#endif + +#if defined(SAFE_IO) + +#define word_in(x) bytes2word((x)[0], (x)[1], (x)[2], (x)[3]) +#define word_out(x,v) { (x)[0] = bval(v,0); (x)[1] = bval(v,1); \ + (x)[2] = bval(v,2); (x)[3] = bval(v,3); } + +#elif (INTERNAL_BYTE_ORDER == PLATFORM_BYTE_ORDER) + +#define word_in(x) *(aes_32t*)(x) +#define word_out(x,v) *(aes_32t*)(x) = (v) + +#else + +#if !defined(bswap_32) +#if !defined(_MSC_VER) +#define _lrotl(x,n) ((aes_32t)(x) << n | (aes_32t)(x) >> 32 - n) +#endif +#define bswap_32(x) ((_lrotl((x),8) & 0x00ff00ff) | (_lrotl((x),24) & 0xff00ff00)) +#endif + +#define word_in(x) bswap_32(*(aes_32t*)(x)) +#define word_out(x,v) *(aes_32t*)(x) = bswap_32(v) + +#endif + +/* the finite field modular polynomial and elements */ + +#define WPOLY 0x011b +#define BPOLY 0x1b + +/* multiply four bytes in GF(2^8) by 'x' {02} in parallel */ + +#define m1 0x80808080 +#define m2 0x7f7f7f7f +#define FFmulX(x) ((((x) & m2) << 1) ^ ((((x) & m1) >> 7) * BPOLY)) + +/* The following defines provide alternative definitions of FFmulX that might + give improved performance if a fast 32-bit multiply is not available. Note + that a temporary variable u needs to be defined where FFmulX is used. + +#define FFmulX(x) (u = (x) & m1, u |= (u >> 1), ((x) & m2) << 1) ^ ((u >> 3) | (u >> 6)) +#define m4 (0x01010101 * BPOLY) +#define FFmulX(x) (u = (x) & m1, ((x) & m2) << 1) ^ ((u - (u >> 7)) & m4) +*/ + +/* Work out which tables are needed for the different options */ + +#ifdef AES_ASM +#ifdef ENC_ROUND +#undef ENC_ROUND +#endif +#define ENC_ROUND FOUR_TABLES +#ifdef LAST_ENC_ROUND +#undef LAST_ENC_ROUND +#endif +#define LAST_ENC_ROUND FOUR_TABLES +#ifdef DEC_ROUND +#undef DEC_ROUND +#endif +#define DEC_ROUND FOUR_TABLES +#ifdef LAST_DEC_ROUND +#undef LAST_DEC_ROUND +#endif +#define LAST_DEC_ROUND FOUR_TABLES +#ifdef KEY_SCHED +#undef KEY_SCHED +#define KEY_SCHED FOUR_TABLES +#endif +#endif + +#if defined(ENCRYPTION) || defined(AES_ASM) +#if ENC_ROUND == ONE_TABLE +#define FT1_SET +#elif ENC_ROUND == FOUR_TABLES +#define FT4_SET +#else +#define SBX_SET +#endif +#if LAST_ENC_ROUND == ONE_TABLE +#define FL1_SET +#elif LAST_ENC_ROUND == FOUR_TABLES +#define FL4_SET +#elif !defined(SBX_SET) +#define SBX_SET +#endif +#endif + +#if defined(DECRYPTION) || defined(AES_ASM) +#if DEC_ROUND == ONE_TABLE +#define IT1_SET +#elif DEC_ROUND == FOUR_TABLES +#define IT4_SET +#else +#define ISB_SET +#endif +#if LAST_DEC_ROUND == ONE_TABLE +#define IL1_SET +#elif LAST_DEC_ROUND == FOUR_TABLES +#define IL4_SET +#elif !defined(ISB_SET) +#define ISB_SET +#endif +#endif + +#if defined(ENCRYPTION_KEY_SCHEDULE) || defined(DECRYPTION_KEY_SCHEDULE) +#if KEY_SCHED == ONE_TABLE +#define LS1_SET +#define IM1_SET +#elif KEY_SCHED == FOUR_TABLES +#define LS4_SET +#define IM4_SET +#elif !defined(SBX_SET) +#define SBX_SET +#endif +#endif + +#ifdef FIXED_TABLES +#define prefx extern const +#else +#define prefx extern +extern aes_08t tab_init; +void gen_tabs(void); +#endif + +prefx aes_32t rcon_tab[29]; + +#ifdef SBX_SET +prefx aes_08t s_box[256]; +#endif + +#ifdef ISB_SET +prefx aes_08t inv_s_box[256]; +#endif + +#ifdef FT1_SET +prefx aes_32t ft_tab[256]; +#endif + +#ifdef FT4_SET +prefx aes_32t ft_tab[4][256]; +#endif + +#ifdef FL1_SET +prefx aes_32t fl_tab[256]; +#endif + +#ifdef FL4_SET +prefx aes_32t fl_tab[4][256]; +#endif + +#ifdef IT1_SET +prefx aes_32t it_tab[256]; +#endif + +#ifdef IT4_SET +prefx aes_32t it_tab[4][256]; +#endif + +#ifdef IL1_SET +prefx aes_32t il_tab[256]; +#endif + +#ifdef IL4_SET +prefx aes_32t il_tab[4][256]; +#endif + +#ifdef LS1_SET +#ifdef FL1_SET +#undef LS1_SET +#else +prefx aes_32t ls_tab[256]; +#endif +#endif + +#ifdef LS4_SET +#ifdef FL4_SET +#undef LS4_SET +#else +prefx aes_32t ls_tab[4][256]; +#endif +#endif + +#ifdef IM1_SET +prefx aes_32t im_tab[256]; +#endif + +#ifdef IM4_SET +prefx aes_32t im_tab[4][256]; +#endif + +/* Set the number of columns in nc. Note that it is important + that nc is a constant which is known at compile time if the + highest speed version of the code is needed. +*/ + +#if defined(BLOCK_SIZE) +#define nc (BLOCK_SIZE >> 2) +#else +#define nc (cx->n_blk >> 2) +#endif + +/* generic definitions of Rijndael macros that use tables */ + +#define no_table(x,box,vf,rf,c) bytes2word( \ + box[bval(vf(x,0,c),rf(0,c))], \ + box[bval(vf(x,1,c),rf(1,c))], \ + box[bval(vf(x,2,c),rf(2,c))], \ + box[bval(vf(x,3,c),rf(3,c))]) + +#define one_table(x,op,tab,vf,rf,c) \ + ( tab[bval(vf(x,0,c),rf(0,c))] \ + ^ op(tab[bval(vf(x,1,c),rf(1,c))],1) \ + ^ op(tab[bval(vf(x,2,c),rf(2,c))],2) \ + ^ op(tab[bval(vf(x,3,c),rf(3,c))],3)) + +#define four_tables(x,tab,vf,rf,c) \ + ( tab[0][bval(vf(x,0,c),rf(0,c))] \ + ^ tab[1][bval(vf(x,1,c),rf(1,c))] \ + ^ tab[2][bval(vf(x,2,c),rf(2,c))] \ + ^ tab[3][bval(vf(x,3,c),rf(3,c))]) + +#define vf1(x,r,c) (x) +#define rf1(r,c) (r) +#define rf2(r,c) ((r-c)&3) + +/* perform forward and inverse column mix operation on four bytes in long word x in */ +/* parallel. NOTE: x must be a simple variable, NOT an expression in these macros. */ + +#define dec_fmvars +#if defined(FM4_SET) /* not currently used */ +#define fwd_mcol(x) four_tables(x,fm_tab,vf1,rf1,0) +#elif defined(FM1_SET) /* not currently used */ +#define fwd_mcol(x) one_table(x,upr,fm_tab,vf1,rf1,0) +#else +#undef dec_fmvars +#define dec_fmvars aes_32t f1, f2; +#define fwd_mcol(x) (f1 = (x), f2 = FFmulX(f1), f2 ^ upr(f1 ^ f2, 3) ^ upr(f1, 2) ^ upr(f1, 1)) +#endif + +#define dec_imvars +#if defined(IM4_SET) +#define inv_mcol(x) four_tables(x,im_tab,vf1,rf1,0) +#elif defined(IM1_SET) +#define inv_mcol(x) one_table(x,upr,im_tab,vf1,rf1,0) +#else +#undef dec_imvars +#define dec_imvars aes_32t f2, f4, f8, f9; +#define inv_mcol(x) \ + (f9 = (x), f2 = FFmulX(f9), f4 = FFmulX(f2), f8 = FFmulX(f4), f9 ^= f8, \ + f2 ^= f4 ^ f8 ^ upr(f2 ^ f9,3) ^ upr(f4 ^ f9,2) ^ upr(f9,1)) +#endif + +#if defined(FL4_SET) +#define ls_box(x,c) four_tables(x,fl_tab,vf1,rf2,c) +#elif defined(LS4_SET) +#define ls_box(x,c) four_tables(x,ls_tab,vf1,rf2,c) +#elif defined(FL1_SET) +#define ls_box(x,c) one_table(x,upr,fl_tab,vf1,rf2,c) +#elif defined(LS1_SET) +#define ls_box(x,c) one_table(x,upr,ls_tab,vf1,rf2,c) +#else +#define ls_box(x,c) no_table(x,s_box,vf1,rf2,c) +#endif + +#endif diff --git a/aestab.c b/aestab.c new file mode 100644 index 000000000..cbfa70d20 --- /dev/null +++ b/aestab.c @@ -0,0 +1,494 @@ +/* +------------------------------------------------------------------------- +Copyright (c) 2001, Dr Brian Gladman < >, Worcester, UK. +All rights reserved. + +LICENSE TERMS + +The free distribution and use of this software in both source and binary +form is allowed (with or without changes) provided that: + +1. distributions of this source code include the above copyright +notice, this list of conditions and the following disclaimer; + +2. distributions in binary form include the above copyright +notice, this list of conditions and the following disclaimer +in the documentation and/or other associated materials; + +3. the copyright holder's name is not used to endorse products +built using this software without specific written permission. + +DISCLAIMER + +This software is provided 'as is' with no explicit or implied warranties +in respect of its properties, including, but not limited to, correctness +and fitness for purpose. +------------------------------------------------------------------------- +Issue Date: 29/07/2002 +*/ + +#include "aesopt.h" + +#if defined(FIXED_TABLES) || !defined(FF_TABLES) + +/* finite field arithmetic operations */ + +#define f2(x) ((x<<1) ^ (((x>>7) & 1) * WPOLY)) +#define f4(x) ((x<<2) ^ (((x>>6) & 1) * WPOLY) ^ (((x>>6) & 2) * WPOLY)) +#define f8(x) ((x<<3) ^ (((x>>5) & 1) * WPOLY) ^ (((x>>5) & 2) * WPOLY) \ +^ (((x>>5) & 4) * WPOLY)) +#define f3(x) (f2(x) ^ x) +#define f9(x) (f8(x) ^ x) +#define fb(x) (f8(x) ^ f2(x) ^ x) +#define fd(x) (f8(x) ^ f4(x) ^ x) +#define fe(x) (f8(x) ^ f4(x) ^ f2(x)) + +#endif + +#if defined(FIXED_TABLES) + +#define sb_data(w) \ +w(0x63), w(0x7c), w(0x77), w(0x7b), w(0xf2), w(0x6b), w(0x6f), w(0xc5),\ +w(0x30), w(0x01), w(0x67), w(0x2b), w(0xfe), w(0xd7), w(0xab), w(0x76),\ +w(0xca), w(0x82), w(0xc9), w(0x7d), w(0xfa), w(0x59), w(0x47), w(0xf0),\ +w(0xad), w(0xd4), w(0xa2), w(0xaf), w(0x9c), w(0xa4), w(0x72), w(0xc0),\ +w(0xb7), w(0xfd), w(0x93), w(0x26), w(0x36), w(0x3f), w(0xf7), w(0xcc),\ +w(0x34), w(0xa5), w(0xe5), w(0xf1), w(0x71), w(0xd8), w(0x31), w(0x15),\ +w(0x04), w(0xc7), w(0x23), w(0xc3), w(0x18), w(0x96), w(0x05), w(0x9a),\ +w(0x07), w(0x12), w(0x80), w(0xe2), w(0xeb), w(0x27), w(0xb2), w(0x75),\ +w(0x09), w(0x83), w(0x2c), w(0x1a), w(0x1b), w(0x6e), w(0x5a), w(0xa0),\ +w(0x52), w(0x3b), w(0xd6), w(0xb3), w(0x29), w(0xe3), w(0x2f), w(0x84),\ +w(0x53), w(0xd1), w(0x00), w(0xed), w(0x20), w(0xfc), w(0xb1), w(0x5b),\ +w(0x6a), w(0xcb), w(0xbe), w(0x39), w(0x4a), w(0x4c), w(0x58), w(0xcf),\ +w(0xd0), w(0xef), w(0xaa), w(0xfb), w(0x43), w(0x4d), w(0x33), w(0x85),\ +w(0x45), w(0xf9), w(0x02), w(0x7f), w(0x50), w(0x3c), w(0x9f), w(0xa8),\ +w(0x51), w(0xa3), w(0x40), w(0x8f), w(0x92), w(0x9d), w(0x38), w(0xf5),\ +w(0xbc), w(0xb6), w(0xda), w(0x21), w(0x10), w(0xff), w(0xf3), w(0xd2),\ +w(0xcd), w(0x0c), w(0x13), w(0xec), w(0x5f), w(0x97), w(0x44), w(0x17),\ +w(0xc4), w(0xa7), w(0x7e), w(0x3d), w(0x64), w(0x5d), w(0x19), w(0x73),\ +w(0x60), w(0x81), w(0x4f), w(0xdc), w(0x22), w(0x2a), w(0x90), w(0x88),\ +w(0x46), w(0xee), w(0xb8), w(0x14), w(0xde), w(0x5e), w(0x0b), w(0xdb),\ +w(0xe0), w(0x32), w(0x3a), w(0x0a), w(0x49), w(0x06), w(0x24), w(0x5c),\ +w(0xc2), w(0xd3), w(0xac), w(0x62), w(0x91), w(0x95), w(0xe4), w(0x79),\ +w(0xe7), w(0xc8), w(0x37), w(0x6d), w(0x8d), w(0xd5), w(0x4e), w(0xa9),\ +w(0x6c), w(0x56), w(0xf4), w(0xea), w(0x65), w(0x7a), w(0xae), w(0x08),\ +w(0xba), w(0x78), w(0x25), w(0x2e), w(0x1c), w(0xa6), w(0xb4), w(0xc6),\ +w(0xe8), w(0xdd), w(0x74), w(0x1f), w(0x4b), w(0xbd), w(0x8b), w(0x8a),\ +w(0x70), w(0x3e), w(0xb5), w(0x66), w(0x48), w(0x03), w(0xf6), w(0x0e),\ +w(0x61), w(0x35), w(0x57), w(0xb9), w(0x86), w(0xc1), w(0x1d), w(0x9e),\ +w(0xe1), w(0xf8), w(0x98), w(0x11), w(0x69), w(0xd9), w(0x8e), w(0x94),\ +w(0x9b), w(0x1e), w(0x87), w(0xe9), w(0xce), w(0x55), w(0x28), w(0xdf),\ +w(0x8c), w(0xa1), w(0x89), w(0x0d), w(0xbf), w(0xe6), w(0x42), w(0x68),\ +w(0x41), w(0x99), w(0x2d), w(0x0f), w(0xb0), w(0x54), w(0xbb), w(0x16) + +#define isb_data(w) \ +w(0x52), w(0x09), w(0x6a), w(0xd5), w(0x30), w(0x36), w(0xa5), w(0x38),\ +w(0xbf), w(0x40), w(0xa3), w(0x9e), w(0x81), w(0xf3), w(0xd7), w(0xfb),\ +w(0x7c), w(0xe3), w(0x39), w(0x82), w(0x9b), w(0x2f), w(0xff), w(0x87),\ +w(0x34), w(0x8e), w(0x43), w(0x44), w(0xc4), w(0xde), w(0xe9), w(0xcb),\ +w(0x54), w(0x7b), w(0x94), w(0x32), w(0xa6), w(0xc2), w(0x23), w(0x3d),\ +w(0xee), w(0x4c), w(0x95), w(0x0b), w(0x42), w(0xfa), w(0xc3), w(0x4e),\ +w(0x08), w(0x2e), w(0xa1), w(0x66), w(0x28), w(0xd9), w(0x24), w(0xb2),\ +w(0x76), w(0x5b), w(0xa2), w(0x49), w(0x6d), w(0x8b), w(0xd1), w(0x25),\ +w(0x72), w(0xf8), w(0xf6), w(0x64), w(0x86), w(0x68), w(0x98), w(0x16),\ +w(0xd4), w(0xa4), w(0x5c), w(0xcc), w(0x5d), w(0x65), w(0xb6), w(0x92),\ +w(0x6c), w(0x70), w(0x48), w(0x50), w(0xfd), w(0xed), w(0xb9), w(0xda),\ +w(0x5e), w(0x15), w(0x46), w(0x57), w(0xa7), w(0x8d), w(0x9d), w(0x84),\ +w(0x90), w(0xd8), w(0xab), w(0x00), w(0x8c), w(0xbc), w(0xd3), w(0x0a),\ +w(0xf7), w(0xe4), w(0x58), w(0x05), w(0xb8), w(0xb3), w(0x45), w(0x06),\ +w(0xd0), w(0x2c), w(0x1e), w(0x8f), w(0xca), w(0x3f), w(0x0f), w(0x02),\ +w(0xc1), w(0xaf), w(0xbd), w(0x03), w(0x01), w(0x13), w(0x8a), w(0x6b),\ +w(0x3a), w(0x91), w(0x11), w(0x41), w(0x4f), w(0x67), w(0xdc), w(0xea),\ +w(0x97), w(0xf2), w(0xcf), w(0xce), w(0xf0), w(0xb4), w(0xe6), w(0x73),\ +w(0x96), w(0xac), w(0x74), w(0x22), w(0xe7), w(0xad), w(0x35), w(0x85),\ +w(0xe2), w(0xf9), w(0x37), w(0xe8), w(0x1c), w(0x75), w(0xdf), w(0x6e),\ +w(0x47), w(0xf1), w(0x1a), w(0x71), w(0x1d), w(0x29), w(0xc5), w(0x89),\ +w(0x6f), w(0xb7), w(0x62), w(0x0e), w(0xaa), w(0x18), w(0xbe), w(0x1b),\ +w(0xfc), w(0x56), w(0x3e), w(0x4b), w(0xc6), w(0xd2), w(0x79), w(0x20),\ +w(0x9a), w(0xdb), w(0xc0), w(0xfe), w(0x78), w(0xcd), w(0x5a), w(0xf4),\ +w(0x1f), w(0xdd), w(0xa8), w(0x33), w(0x88), w(0x07), w(0xc7), w(0x31),\ +w(0xb1), w(0x12), w(0x10), w(0x59), w(0x27), w(0x80), w(0xec), w(0x5f),\ +w(0x60), w(0x51), w(0x7f), w(0xa9), w(0x19), w(0xb5), w(0x4a), w(0x0d),\ +w(0x2d), w(0xe5), w(0x7a), w(0x9f), w(0x93), w(0xc9), w(0x9c), w(0xef),\ +w(0xa0), w(0xe0), w(0x3b), w(0x4d), w(0xae), w(0x2a), w(0xf5), w(0xb0),\ +w(0xc8), w(0xeb), w(0xbb), w(0x3c), w(0x83), w(0x53), w(0x99), w(0x61),\ +w(0x17), w(0x2b), w(0x04), w(0x7e), w(0xba), w(0x77), w(0xd6), w(0x26),\ +w(0xe1), w(0x69), w(0x14), w(0x63), w(0x55), w(0x21), w(0x0c), w(0x7d), + +#define mm_data(w) \ +w(0x00), w(0x01), w(0x02), w(0x03), w(0x04), w(0x05), w(0x06), w(0x07),\ +w(0x08), w(0x09), w(0x0a), w(0x0b), w(0x0c), w(0x0d), w(0x0e), w(0x0f),\ +w(0x10), w(0x11), w(0x12), w(0x13), w(0x14), w(0x15), w(0x16), w(0x17),\ +w(0x18), w(0x19), w(0x1a), w(0x1b), w(0x1c), w(0x1d), w(0x1e), w(0x1f),\ +w(0x20), w(0x21), w(0x22), w(0x23), w(0x24), w(0x25), w(0x26), w(0x27),\ +w(0x28), w(0x29), w(0x2a), w(0x2b), w(0x2c), w(0x2d), w(0x2e), w(0x2f),\ +w(0x30), w(0x31), w(0x32), w(0x33), w(0x34), w(0x35), w(0x36), w(0x37),\ +w(0x38), w(0x39), w(0x3a), w(0x3b), w(0x3c), w(0x3d), w(0x3e), w(0x3f),\ +w(0x40), w(0x41), w(0x42), w(0x43), w(0x44), w(0x45), w(0x46), w(0x47),\ +w(0x48), w(0x49), w(0x4a), w(0x4b), w(0x4c), w(0x4d), w(0x4e), w(0x4f),\ +w(0x50), w(0x51), w(0x52), w(0x53), w(0x54), w(0x55), w(0x56), w(0x57),\ +w(0x58), w(0x59), w(0x5a), w(0x5b), w(0x5c), w(0x5d), w(0x5e), w(0x5f),\ +w(0x60), w(0x61), w(0x62), w(0x63), w(0x64), w(0x65), w(0x66), w(0x67),\ +w(0x68), w(0x69), w(0x6a), w(0x6b), w(0x6c), w(0x6d), w(0x6e), w(0x6f),\ +w(0x70), w(0x71), w(0x72), w(0x73), w(0x74), w(0x75), w(0x76), w(0x77),\ +w(0x78), w(0x79), w(0x7a), w(0x7b), w(0x7c), w(0x7d), w(0x7e), w(0x7f),\ +w(0x80), w(0x81), w(0x82), w(0x83), w(0x84), w(0x85), w(0x86), w(0x87),\ +w(0x88), w(0x89), w(0x8a), w(0x8b), w(0x8c), w(0x8d), w(0x8e), w(0x8f),\ +w(0x90), w(0x91), w(0x92), w(0x93), w(0x94), w(0x95), w(0x96), w(0x97),\ +w(0x98), w(0x99), w(0x9a), w(0x9b), w(0x9c), w(0x9d), w(0x9e), w(0x9f),\ +w(0xa0), w(0xa1), w(0xa2), w(0xa3), w(0xa4), w(0xa5), w(0xa6), w(0xa7),\ +w(0xa8), w(0xa9), w(0xaa), w(0xab), w(0xac), w(0xad), w(0xae), w(0xaf),\ +w(0xb0), w(0xb1), w(0xb2), w(0xb3), w(0xb4), w(0xb5), w(0xb6), w(0xb7),\ +w(0xb8), w(0xb9), w(0xba), w(0xbb), w(0xbc), w(0xbd), w(0xbe), w(0xbf),\ +w(0xc0), w(0xc1), w(0xc2), w(0xc3), w(0xc4), w(0xc5), w(0xc6), w(0xc7),\ +w(0xc8), w(0xc9), w(0xca), w(0xcb), w(0xcc), w(0xcd), w(0xce), w(0xcf),\ +w(0xd0), w(0xd1), w(0xd2), w(0xd3), w(0xd4), w(0xd5), w(0xd6), w(0xd7),\ +w(0xd8), w(0xd9), w(0xda), w(0xdb), w(0xdc), w(0xdd), w(0xde), w(0xdf),\ +w(0xe0), w(0xe1), w(0xe2), w(0xe3), w(0xe4), w(0xe5), w(0xe6), w(0xe7),\ +w(0xe8), w(0xe9), w(0xea), w(0xeb), w(0xec), w(0xed), w(0xee), w(0xef),\ +w(0xf0), w(0xf1), w(0xf2), w(0xf3), w(0xf4), w(0xf5), w(0xf6), w(0xf7),\ +w(0xf8), w(0xf9), w(0xfa), w(0xfb), w(0xfc), w(0xfd), w(0xfe), w(0xff) + +#define h0(x) (x) + +/* These defines are used to ensure tables are generated in the +right format depending on the internal byte order required +*/ + +#define w0(p) bytes2word(p, 0, 0, 0) +#define w1(p) bytes2word(0, p, 0, 0) +#define w2(p) bytes2word(0, 0, p, 0) +#define w3(p) bytes2word(0, 0, 0, p) + +/* Number of elements required in this table for different +block and key lengths is: + +Rcon Table key length (bytes) +Length 16 20 24 28 32 +--------------------- +block 16 | 10 9 8 7 7 +length 20 | 14 11 10 9 9 +(bytes) 24 | 19 15 12 11 11 +28 | 24 19 16 13 13 +32 | 29 23 19 17 14 + +this table can be a table of bytes if the key schedule +code is adjusted accordingly +*/ + +#define u0(p) bytes2word(f2(p), p, p, f3(p)) +#define u1(p) bytes2word(f3(p), f2(p), p, p) +#define u2(p) bytes2word(p, f3(p), f2(p), p) +#define u3(p) bytes2word(p, p, f3(p), f2(p)) + +#define v0(p) bytes2word(fe(p), f9(p), fd(p), fb(p)) +#define v1(p) bytes2word(fb(p), fe(p), f9(p), fd(p)) +#define v2(p) bytes2word(fd(p), fb(p), fe(p), f9(p)) +#define v3(p) bytes2word(f9(p), fd(p), fb(p), fe(p)) + +const aes_32t rcon_tab[29] = +{ +w0(0x01), w0(0x02), w0(0x04), w0(0x08), +w0(0x10), w0(0x20), w0(0x40), w0(0x80), +w0(0x1b), w0(0x36), w0(0x6c), w0(0xd8), +w0(0xab), w0(0x4d), w0(0x9a), w0(0x2f), +w0(0x5e), w0(0xbc), w0(0x63), w0(0xc6), +w0(0x97), w0(0x35), w0(0x6a), w0(0xd4), +w0(0xb3), w0(0x7d), w0(0xfa), w0(0xef), +w0(0xc5) +}; + +#ifdef SBX_SET +const aes_08t s_box[256] = { sb_data(h0) }; +#endif +#ifdef ISB_SET +const aes_08t inv_s_box[256] = { isb_data(h0) }; +#endif + +#ifdef FT1_SET +const aes_32t ft_tab[256] = { sb_data(u0) }; +#endif +#ifdef FT4_SET +const aes_32t ft_tab[4][256] = +{ { sb_data(u0) }, { sb_data(u1) }, { sb_data(u2) }, { sb_data(u3) } }; +#endif + +#ifdef FL1_SET +const aes_32t fl_tab[256] = { sb_data(w0) }; +#endif +#ifdef FL4_SET +const aes_32t fl_tab[4][256] = +{ { sb_data(w0) }, { sb_data(w1) }, { sb_data(w2) }, { sb_data(w3) } }; +#endif + +#ifdef IT1_SET +const aes_32t it_tab[256] = { isb_data(v0) }; +#endif +#ifdef IT4_SET +const aes_32t it_tab[4][256] = +{ { isb_data(v0) }, { isb_data(v1) }, { isb_data(v2) }, { isb_data(v3) } }; +#endif + +#ifdef IL1_SET +const aes_32t il_tab[256] = { isb_data(w0) }; +#endif +#ifdef IL4_SET +const aes_32t il_tab[4][256] = +{ { isb_data(w0) }, { isb_data(w1) }, { isb_data(w2) }, { isb_data(w3) } }; +#endif + +#ifdef LS1_SET +const aes_32t ls_tab[256] = { sb_data(w0) }; +#endif +#ifdef LS4_SET +const aes_32t ls_tab[4][256] = +{ { sb_data(w0) }, { sb_data(w1) }, { sb_data(w2) }, { sb_data(w3) } }; +#endif + +#ifdef IM1_SET +const aes_32t im_tab[256] = { mm_data(v0) }; +#endif +#ifdef IM4_SET +const aes_32t im_tab[4][256] = +{ { mm_data(v0) }, { mm_data(v1) }, { mm_data(v2) }, { mm_data(v3) } }; +#endif + +#else /* dynamic table generation */ + +aes_08t tab_init = 0; + +#define const + +aes_32t rcon_tab[RC_LENGTH]; + +#ifdef SBX_SET +aes_08t s_box[256]; +#endif +#ifdef ISB_SET +aes_08t inv_s_box[256]; +#endif + +#ifdef FT1_SET +aes_32t ft_tab[256]; +#endif +#ifdef FT4_SET +aes_32t ft_tab[4][256]; +#endif + +#ifdef FL1_SET +aes_32t fl_tab[256]; +#endif +#ifdef FL4_SET +aes_32t fl_tab[4][256]; +#endif + +#ifdef IT1_SET +aes_32t it_tab[256]; +#endif +#ifdef IT4_SET +aes_32t it_tab[4][256]; +#endif + +#ifdef IL1_SET +aes_32t il_tab[256]; +#endif +#ifdef IL4_SET +aes_32t il_tab[4][256]; +#endif + +#ifdef LS1_SET +aes_32t ls_tab[256]; +#endif +#ifdef LS4_SET +aes_32t ls_tab[4][256]; +#endif + +#ifdef IM1_SET +aes_32t im_tab[256]; +#endif +#ifdef IM4_SET +aes_32t im_tab[4][256]; +#endif + +#if !defined(FF_TABLES) + +/* Generate the tables for the dynamic table option + +It will generally be sensible to use tables to compute finite +field multiplies and inverses but where memory is scarse this +code might sometimes be better. But it only has effect during +initialisation so its pretty unimportant in overall terms. +*/ + +/* return 2 ^ (n - 1) where n is the bit number of the highest bit +set in x with x in the range 1 < x < 0x00000200. This form is +used so that locals within fi can be bytes rather than words +*/ + +static aes_08t hibit(const aes_32t x) +{ aes_08t r = (aes_08t)((x >> 1) | (x >> 2)); + +r |= (r >> 2); +r |= (r >> 4); +return (r + 1) >> 1; +} + +/* return the inverse of the finite field element x */ + +static aes_08t fi(const aes_08t x) +{ aes_08t p1 = x, p2 = BPOLY, n1 = hibit(x), n2 = 0x80, v1 = 1, v2 = 0; + +if(x < 2) return x; + +for(;;) +{ +if(!n1) return v1; + +while(n2 >= n1) +{ +n2 /= n1; p2 ^= p1 * n2; v2 ^= v1 * n2; n2 = hibit(p2); +} + +if(!n2) return v2; + +while(n1 >= n2) +{ +n1 /= n2; p1 ^= p2 * n1; v1 ^= v2 * n1; n1 = hibit(p1); +} +} +} + +#else + +/* define the finite field multiplies required for Rijndael */ + +#define f2(x) ((x) ? pow[log[x] + 0x19] : 0) +#define f3(x) ((x) ? pow[log[x] + 0x01] : 0) +#define f9(x) ((x) ? pow[log[x] + 0xc7] : 0) +#define fb(x) ((x) ? pow[log[x] + 0x68] : 0) +#define fd(x) ((x) ? pow[log[x] + 0xee] : 0) +#define fe(x) ((x) ? pow[log[x] + 0xdf] : 0) +#define fi(x) ((x) ? pow[255 - log[x]]: 0) + +#endif + +/* The forward and inverse affine transformations used in the S-box */ + +#define fwd_affine(x) \ +(w = (aes_32t)x, w ^= (w<<1)^(w<<2)^(w<<3)^(w<<4), 0x63^(aes_08t)(w^(w>>8))) + +#define inv_affine(x) \ +(w = (aes_32t)x, w = (w<<1)^(w<<3)^(w<<6), 0x05^(aes_08t)(w^(w>>8))) + +void gen_tabs(void) +{ aes_32t i, w; + +#if defined(FF_TABLES) + +aes_08t pow[512], log[256]; + +/* log and power tables for GF(2^8) finite field with +WPOLY as modular polynomial - the simplest primitive +root is 0x03, used here to generate the tables +*/ + +i = 0; w = 1; +do +{ +pow[i] = (aes_08t)w; +pow[i + 255] = (aes_08t)w; +log[w] = (aes_08t)i++; +w ^= (w << 1) ^ (w & 0x80 ? WPOLY : 0); +} +while (w != 1); + +#endif + +for(i = 0, w = 1; i < RC_LENGTH; ++i) +{ +rcon_tab[i] = bytes2word(w, 0, 0, 0); +w = f2(w); +} + +for(i = 0; i < 256; ++i) +{ aes_08t b; + +b = fwd_affine(fi((aes_08t)i)); +w = bytes2word(f2(b), b, b, f3(b)); + +#ifdef SBX_SET +s_box[i] = b; +#endif + +#ifdef FT1_SET /* tables for a normal encryption round */ +ft_tab[i] = w; +#endif +#ifdef FT4_SET +ft_tab[0][i] = w; +ft_tab[1][i] = upr(w,1); +ft_tab[2][i] = upr(w,2); +ft_tab[3][i] = upr(w,3); +#endif +w = bytes2word(b, 0, 0, 0); + +#ifdef FL1_SET /* tables for last encryption round (may also */ +fl_tab[i] = w; /* be used in the key schedule) */ +#endif +#ifdef FL4_SET +fl_tab[0][i] = w; +fl_tab[1][i] = upr(w,1); +fl_tab[2][i] = upr(w,2); +fl_tab[3][i] = upr(w,3); +#endif + +#ifdef LS1_SET /* table for key schedule if fl_tab above is */ +ls_tab[i] = w; /* not of the required form */ +#endif +#ifdef LS4_SET +ls_tab[0][i] = w; +ls_tab[1][i] = upr(w,1); +ls_tab[2][i] = upr(w,2); +ls_tab[3][i] = upr(w,3); +#endif + +b = fi(inv_affine((aes_08t)i)); +w = bytes2word(fe(b), f9(b), fd(b), fb(b)); + +#ifdef IM1_SET /* tables for the inverse mix column operation */ +im_tab[b] = w; +#endif +#ifdef IM4_SET +im_tab[0][b] = w; +im_tab[1][b] = upr(w,1); +im_tab[2][b] = upr(w,2); +im_tab[3][b] = upr(w,3); +#endif + +#ifdef ISB_SET +inv_s_box[i] = b; +#endif +#ifdef IT1_SET /* tables for a normal decryption round */ +it_tab[i] = w; +#endif +#ifdef IT4_SET +it_tab[0][i] = w; +it_tab[1][i] = upr(w,1); +it_tab[2][i] = upr(w,2); +it_tab[3][i] = upr(w,3); +#endif +w = bytes2word(b, 0, 0, 0); +#ifdef IL1_SET /* tables for last decryption round */ +il_tab[i] = w; +#endif +#ifdef IL4_SET +il_tab[0][i] = w; +il_tab[1][i] = upr(w,1); +il_tab[2][i] = upr(w,2); +il_tab[3][i] = upr(w,3); +#endif +} + +tab_init = 1; +} + +#endif diff --git a/blowfish.c b/blowfish.c deleted file mode 100644 index 1e32a3eed..000000000 --- a/blowfish.c +++ /dev/null @@ -1,409 +0,0 @@ -/** - * Copyright (c) 2013 Pavol Rusnak - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#include -#include "blowfish.h" - -static const uint32_t P_orig[16 + 2] = { - 0x243F6A88, 0x85A308D3, 0x13198A2E, 0x03707344, - 0xA4093822, 0x299F31D0, 0x082EFA98, 0xEC4E6C89, - 0x452821E6, 0x38D01377, 0xBE5466CF, 0x34E90C6C, - 0xC0AC29B7, 0xC97C50DD, 0x3F84D5B5, 0xB5470917, - 0x9216D5D9, 0x8979FB1B, -}; - -static const uint32_t S_orig[4][256] = {{ - 0xD1310BA6, 0x98DFB5AC, 0x2FFD72DB, 0xD01ADFB7, - 0xB8E1AFED, 0x6A267E96, 0xBA7C9045, 0xF12C7F99, - 0x24A19947, 0xB3916CF7, 0x0801F2E2, 0x858EFC16, - 0x636920D8, 0x71574E69, 0xA458FEA3, 0xF4933D7E, - 0x0D95748F, 0x728EB658, 0x718BCD58, 0x82154AEE, - 0x7B54A41D, 0xC25A59B5, 0x9C30D539, 0x2AF26013, - 0xC5D1B023, 0x286085F0, 0xCA417918, 0xB8DB38EF, - 0x8E79DCB0, 0x603A180E, 0x6C9E0E8B, 0xB01E8A3E, - 0xD71577C1, 0xBD314B27, 0x78AF2FDA, 0x55605C60, - 0xE65525F3, 0xAA55AB94, 0x57489862, 0x63E81440, - 0x55CA396A, 0x2AAB10B6, 0xB4CC5C34, 0x1141E8CE, - 0xA15486AF, 0x7C72E993, 0xB3EE1411, 0x636FBC2A, - 0x2BA9C55D, 0x741831F6, 0xCE5C3E16, 0x9B87931E, - 0xAFD6BA33, 0x6C24CF5C, 0x7A325381, 0x28958677, - 0x3B8F4898, 0x6B4BB9AF, 0xC4BFE81B, 0x66282193, - 0x61D809CC, 0xFB21A991, 0x487CAC60, 0x5DEC8032, - 0xEF845D5D, 0xE98575B1, 0xDC262302, 0xEB651B88, - 0x23893E81, 0xD396ACC5, 0x0F6D6FF3, 0x83F44239, - 0x2E0B4482, 0xA4842004, 0x69C8F04A, 0x9E1F9B5E, - 0x21C66842, 0xF6E96C9A, 0x670C9C61, 0xABD388F0, - 0x6A51A0D2, 0xD8542F68, 0x960FA728, 0xAB5133A3, - 0x6EEF0B6C, 0x137A3BE4, 0xBA3BF050, 0x7EFB2A98, - 0xA1F1651D, 0x39AF0176, 0x66CA593E, 0x82430E88, - 0x8CEE8619, 0x456F9FB4, 0x7D84A5C3, 0x3B8B5EBE, - 0xE06F75D8, 0x85C12073, 0x401A449F, 0x56C16AA6, - 0x4ED3AA62, 0x363F7706, 0x1BFEDF72, 0x429B023D, - 0x37D0D724, 0xD00A1248, 0xDB0FEAD3, 0x49F1C09B, - 0x075372C9, 0x80991B7B, 0x25D479D8, 0xF6E8DEF7, - 0xE3FE501A, 0xB6794C3B, 0x976CE0BD, 0x04C006BA, - 0xC1A94FB6, 0x409F60C4, 0x5E5C9EC2, 0x196A2463, - 0x68FB6FAF, 0x3E6C53B5, 0x1339B2EB, 0x3B52EC6F, - 0x6DFC511F, 0x9B30952C, 0xCC814544, 0xAF5EBD09, - 0xBEE3D004, 0xDE334AFD, 0x660F2807, 0x192E4BB3, - 0xC0CBA857, 0x45C8740F, 0xD20B5F39, 0xB9D3FBDB, - 0x5579C0BD, 0x1A60320A, 0xD6A100C6, 0x402C7279, - 0x679F25FE, 0xFB1FA3CC, 0x8EA5E9F8, 0xDB3222F8, - 0x3C7516DF, 0xFD616B15, 0x2F501EC8, 0xAD0552AB, - 0x323DB5FA, 0xFD238760, 0x53317B48, 0x3E00DF82, - 0x9E5C57BB, 0xCA6F8CA0, 0x1A87562E, 0xDF1769DB, - 0xD542A8F6, 0x287EFFC3, 0xAC6732C6, 0x8C4F5573, - 0x695B27B0, 0xBBCA58C8, 0xE1FFA35D, 0xB8F011A0, - 0x10FA3D98, 0xFD2183B8, 0x4AFCB56C, 0x2DD1D35B, - 0x9A53E479, 0xB6F84565, 0xD28E49BC, 0x4BFB9790, - 0xE1DDF2DA, 0xA4CB7E33, 0x62FB1341, 0xCEE4C6E8, - 0xEF20CADA, 0x36774C01, 0xD07E9EFE, 0x2BF11FB4, - 0x95DBDA4D, 0xAE909198, 0xEAAD8E71, 0x6B93D5A0, - 0xD08ED1D0, 0xAFC725E0, 0x8E3C5B2F, 0x8E7594B7, - 0x8FF6E2FB, 0xF2122B64, 0x8888B812, 0x900DF01C, - 0x4FAD5EA0, 0x688FC31C, 0xD1CFF191, 0xB3A8C1AD, - 0x2F2F2218, 0xBE0E1777, 0xEA752DFE, 0x8B021FA1, - 0xE5A0CC0F, 0xB56F74E8, 0x18ACF3D6, 0xCE89E299, - 0xB4A84FE0, 0xFD13E0B7, 0x7CC43B81, 0xD2ADA8D9, - 0x165FA266, 0x80957705, 0x93CC7314, 0x211A1477, - 0xE6AD2065, 0x77B5FA86, 0xC75442F5, 0xFB9D35CF, - 0xEBCDAF0C, 0x7B3E89A0, 0xD6411BD3, 0xAE1E7E49, - 0x00250E2D, 0x2071B35E, 0x226800BB, 0x57B8E0AF, - 0x2464369B, 0xF009B91E, 0x5563911D, 0x59DFA6AA, - 0x78C14389, 0xD95A537F, 0x207D5BA2, 0x02E5B9C5, - 0x83260376, 0x6295CFA9, 0x11C81968, 0x4E734A41, - 0xB3472DCA, 0x7B14A94A, 0x1B510052, 0x9A532915, - 0xD60F573F, 0xBC9BC6E4, 0x2B60A476, 0x81E67400, - 0x08BA6FB5, 0x571BE91F, 0xF296EC6B, 0x2A0DD915, - 0xB6636521, 0xE7B9F9B6, 0xFF34052E, 0xC5855664, - 0x53B02D5D, 0xA99F8FA1, 0x08BA4799, 0x6E85076A, - },{ - 0x4B7A70E9, 0xB5B32944, 0xDB75092E, 0xC4192623, - 0xAD6EA6B0, 0x49A7DF7D, 0x9CEE60B8, 0x8FEDB266, - 0xECAA8C71, 0x699A17FF, 0x5664526C, 0xC2B19EE1, - 0x193602A5, 0x75094C29, 0xA0591340, 0xE4183A3E, - 0x3F54989A, 0x5B429D65, 0x6B8FE4D6, 0x99F73FD6, - 0xA1D29C07, 0xEFE830F5, 0x4D2D38E6, 0xF0255DC1, - 0x4CDD2086, 0x8470EB26, 0x6382E9C6, 0x021ECC5E, - 0x09686B3F, 0x3EBAEFC9, 0x3C971814, 0x6B6A70A1, - 0x687F3584, 0x52A0E286, 0xB79C5305, 0xAA500737, - 0x3E07841C, 0x7FDEAE5C, 0x8E7D44EC, 0x5716F2B8, - 0xB03ADA37, 0xF0500C0D, 0xF01C1F04, 0x0200B3FF, - 0xAE0CF51A, 0x3CB574B2, 0x25837A58, 0xDC0921BD, - 0xD19113F9, 0x7CA92FF6, 0x94324773, 0x22F54701, - 0x3AE5E581, 0x37C2DADC, 0xC8B57634, 0x9AF3DDA7, - 0xA9446146, 0x0FD0030E, 0xECC8C73E, 0xA4751E41, - 0xE238CD99, 0x3BEA0E2F, 0x3280BBA1, 0x183EB331, - 0x4E548B38, 0x4F6DB908, 0x6F420D03, 0xF60A04BF, - 0x2CB81290, 0x24977C79, 0x5679B072, 0xBCAF89AF, - 0xDE9A771F, 0xD9930810, 0xB38BAE12, 0xDCCF3F2E, - 0x5512721F, 0x2E6B7124, 0x501ADDE6, 0x9F84CD87, - 0x7A584718, 0x7408DA17, 0xBC9F9ABC, 0xE94B7D8C, - 0xEC7AEC3A, 0xDB851DFA, 0x63094366, 0xC464C3D2, - 0xEF1C1847, 0x3215D908, 0xDD433B37, 0x24C2BA16, - 0x12A14D43, 0x2A65C451, 0x50940002, 0x133AE4DD, - 0x71DFF89E, 0x10314E55, 0x81AC77D6, 0x5F11199B, - 0x043556F1, 0xD7A3C76B, 0x3C11183B, 0x5924A509, - 0xF28FE6ED, 0x97F1FBFA, 0x9EBABF2C, 0x1E153C6E, - 0x86E34570, 0xEAE96FB1, 0x860E5E0A, 0x5A3E2AB3, - 0x771FE71C, 0x4E3D06FA, 0x2965DCB9, 0x99E71D0F, - 0x803E89D6, 0x5266C825, 0x2E4CC978, 0x9C10B36A, - 0xC6150EBA, 0x94E2EA78, 0xA5FC3C53, 0x1E0A2DF4, - 0xF2F74EA7, 0x361D2B3D, 0x1939260F, 0x19C27960, - 0x5223A708, 0xF71312B6, 0xEBADFE6E, 0xEAC31F66, - 0xE3BC4595, 0xA67BC883, 0xB17F37D1, 0x018CFF28, - 0xC332DDEF, 0xBE6C5AA5, 0x65582185, 0x68AB9802, - 0xEECEA50F, 0xDB2F953B, 0x2AEF7DAD, 0x5B6E2F84, - 0x1521B628, 0x29076170, 0xECDD4775, 0x619F1510, - 0x13CCA830, 0xEB61BD96, 0x0334FE1E, 0xAA0363CF, - 0xB5735C90, 0x4C70A239, 0xD59E9E0B, 0xCBAADE14, - 0xEECC86BC, 0x60622CA7, 0x9CAB5CAB, 0xB2F3846E, - 0x648B1EAF, 0x19BDF0CA, 0xA02369B9, 0x655ABB50, - 0x40685A32, 0x3C2AB4B3, 0x319EE9D5, 0xC021B8F7, - 0x9B540B19, 0x875FA099, 0x95F7997E, 0x623D7DA8, - 0xF837889A, 0x97E32D77, 0x11ED935F, 0x16681281, - 0x0E358829, 0xC7E61FD6, 0x96DEDFA1, 0x7858BA99, - 0x57F584A5, 0x1B227263, 0x9B83C3FF, 0x1AC24696, - 0xCDB30AEB, 0x532E3054, 0x8FD948E4, 0x6DBC3128, - 0x58EBF2EF, 0x34C6FFEA, 0xFE28ED61, 0xEE7C3C73, - 0x5D4A14D9, 0xE864B7E3, 0x42105D14, 0x203E13E0, - 0x45EEE2B6, 0xA3AAABEA, 0xDB6C4F15, 0xFACB4FD0, - 0xC742F442, 0xEF6ABBB5, 0x654F3B1D, 0x41CD2105, - 0xD81E799E, 0x86854DC7, 0xE44B476A, 0x3D816250, - 0xCF62A1F2, 0x5B8D2646, 0xFC8883A0, 0xC1C7B6A3, - 0x7F1524C3, 0x69CB7492, 0x47848A0B, 0x5692B285, - 0x095BBF00, 0xAD19489D, 0x1462B174, 0x23820E00, - 0x58428D2A, 0x0C55F5EA, 0x1DADF43E, 0x233F7061, - 0x3372F092, 0x8D937E41, 0xD65FECF1, 0x6C223BDB, - 0x7CDE3759, 0xCBEE7460, 0x4085F2A7, 0xCE77326E, - 0xA6078084, 0x19F8509E, 0xE8EFD855, 0x61D99735, - 0xA969A7AA, 0xC50C06C2, 0x5A04ABFC, 0x800BCADC, - 0x9E447A2E, 0xC3453484, 0xFDD56705, 0x0E1E9EC9, - 0xDB73DBD3, 0x105588CD, 0x675FDA79, 0xE3674340, - 0xC5C43465, 0x713E38D8, 0x3D28F89E, 0xF16DFF20, - 0x153E21E7, 0x8FB03D4A, 0xE6E39F2B, 0xDB83ADF7, - },{ - 0xE93D5A68, 0x948140F7, 0xF64C261C, 0x94692934, - 0x411520F7, 0x7602D4F7, 0xBCF46B2E, 0xD4A20068, - 0xD4082471, 0x3320F46A, 0x43B7D4B7, 0x500061AF, - 0x1E39F62E, 0x97244546, 0x14214F74, 0xBF8B8840, - 0x4D95FC1D, 0x96B591AF, 0x70F4DDD3, 0x66A02F45, - 0xBFBC09EC, 0x03BD9785, 0x7FAC6DD0, 0x31CB8504, - 0x96EB27B3, 0x55FD3941, 0xDA2547E6, 0xABCA0A9A, - 0x28507825, 0x530429F4, 0x0A2C86DA, 0xE9B66DFB, - 0x68DC1462, 0xD7486900, 0x680EC0A4, 0x27A18DEE, - 0x4F3FFEA2, 0xE887AD8C, 0xB58CE006, 0x7AF4D6B6, - 0xAACE1E7C, 0xD3375FEC, 0xCE78A399, 0x406B2A42, - 0x20FE9E35, 0xD9F385B9, 0xEE39D7AB, 0x3B124E8B, - 0x1DC9FAF7, 0x4B6D1856, 0x26A36631, 0xEAE397B2, - 0x3A6EFA74, 0xDD5B4332, 0x6841E7F7, 0xCA7820FB, - 0xFB0AF54E, 0xD8FEB397, 0x454056AC, 0xBA489527, - 0x55533A3A, 0x20838D87, 0xFE6BA9B7, 0xD096954B, - 0x55A867BC, 0xA1159A58, 0xCCA92963, 0x99E1DB33, - 0xA62A4A56, 0x3F3125F9, 0x5EF47E1C, 0x9029317C, - 0xFDF8E802, 0x04272F70, 0x80BB155C, 0x05282CE3, - 0x95C11548, 0xE4C66D22, 0x48C1133F, 0xC70F86DC, - 0x07F9C9EE, 0x41041F0F, 0x404779A4, 0x5D886E17, - 0x325F51EB, 0xD59BC0D1, 0xF2BCC18F, 0x41113564, - 0x257B7834, 0x602A9C60, 0xDFF8E8A3, 0x1F636C1B, - 0x0E12B4C2, 0x02E1329E, 0xAF664FD1, 0xCAD18115, - 0x6B2395E0, 0x333E92E1, 0x3B240B62, 0xEEBEB922, - 0x85B2A20E, 0xE6BA0D99, 0xDE720C8C, 0x2DA2F728, - 0xD0127845, 0x95B794FD, 0x647D0862, 0xE7CCF5F0, - 0x5449A36F, 0x877D48FA, 0xC39DFD27, 0xF33E8D1E, - 0x0A476341, 0x992EFF74, 0x3A6F6EAB, 0xF4F8FD37, - 0xA812DC60, 0xA1EBDDF8, 0x991BE14C, 0xDB6E6B0D, - 0xC67B5510, 0x6D672C37, 0x2765D43B, 0xDCD0E804, - 0xF1290DC7, 0xCC00FFA3, 0xB5390F92, 0x690FED0B, - 0x667B9FFB, 0xCEDB7D9C, 0xA091CF0B, 0xD9155EA3, - 0xBB132F88, 0x515BAD24, 0x7B9479BF, 0x763BD6EB, - 0x37392EB3, 0xCC115979, 0x8026E297, 0xF42E312D, - 0x6842ADA7, 0xC66A2B3B, 0x12754CCC, 0x782EF11C, - 0x6A124237, 0xB79251E7, 0x06A1BBE6, 0x4BFB6350, - 0x1A6B1018, 0x11CAEDFA, 0x3D25BDD8, 0xE2E1C3C9, - 0x44421659, 0x0A121386, 0xD90CEC6E, 0xD5ABEA2A, - 0x64AF674E, 0xDA86A85F, 0xBEBFE988, 0x64E4C3FE, - 0x9DBC8057, 0xF0F7C086, 0x60787BF8, 0x6003604D, - 0xD1FD8346, 0xF6381FB0, 0x7745AE04, 0xD736FCCC, - 0x83426B33, 0xF01EAB71, 0xB0804187, 0x3C005E5F, - 0x77A057BE, 0xBDE8AE24, 0x55464299, 0xBF582E61, - 0x4E58F48F, 0xF2DDFDA2, 0xF474EF38, 0x8789BDC2, - 0x5366F9C3, 0xC8B38E74, 0xB475F255, 0x46FCD9B9, - 0x7AEB2661, 0x8B1DDF84, 0x846A0E79, 0x915F95E2, - 0x466E598E, 0x20B45770, 0x8CD55591, 0xC902DE4C, - 0xB90BACE1, 0xBB8205D0, 0x11A86248, 0x7574A99E, - 0xB77F19B6, 0xE0A9DC09, 0x662D09A1, 0xC4324633, - 0xE85A1F02, 0x09F0BE8C, 0x4A99A025, 0x1D6EFE10, - 0x1AB93D1D, 0x0BA5A4DF, 0xA186F20F, 0x2868F169, - 0xDCB7DA83, 0x573906FE, 0xA1E2CE9B, 0x4FCD7F52, - 0x50115E01, 0xA70683FA, 0xA002B5C4, 0x0DE6D027, - 0x9AF88C27, 0x773F8641, 0xC3604C06, 0x61A806B5, - 0xF0177A28, 0xC0F586E0, 0x006058AA, 0x30DC7D62, - 0x11E69ED7, 0x2338EA63, 0x53C2DD94, 0xC2C21634, - 0xBBCBEE56, 0x90BCB6DE, 0xEBFC7DA1, 0xCE591D76, - 0x6F05E409, 0x4B7C0188, 0x39720A3D, 0x7C927C24, - 0x86E3725F, 0x724D9DB9, 0x1AC15BB4, 0xD39EB8FC, - 0xED545578, 0x08FCA5B5, 0xD83D7CD3, 0x4DAD0FC4, - 0x1E50EF5E, 0xB161E6F8, 0xA28514D9, 0x6C51133C, - 0x6FD5C7E7, 0x56E14EC4, 0x362ABFCE, 0xDDC6C837, - 0xD79A3234, 0x92638212, 0x670EFA8E, 0x406000E0, - },{ - 0x3A39CE37, 0xD3FAF5CF, 0xABC27737, 0x5AC52D1B, - 0x5CB0679E, 0x4FA33742, 0xD3822740, 0x99BC9BBE, - 0xD5118E9D, 0xBF0F7315, 0xD62D1C7E, 0xC700C47B, - 0xB78C1B6B, 0x21A19045, 0xB26EB1BE, 0x6A366EB4, - 0x5748AB2F, 0xBC946E79, 0xC6A376D2, 0x6549C2C8, - 0x530FF8EE, 0x468DDE7D, 0xD5730A1D, 0x4CD04DC6, - 0x2939BBDB, 0xA9BA4650, 0xAC9526E8, 0xBE5EE304, - 0xA1FAD5F0, 0x6A2D519A, 0x63EF8CE2, 0x9A86EE22, - 0xC089C2B8, 0x43242EF6, 0xA51E03AA, 0x9CF2D0A4, - 0x83C061BA, 0x9BE96A4D, 0x8FE51550, 0xBA645BD6, - 0x2826A2F9, 0xA73A3AE1, 0x4BA99586, 0xEF5562E9, - 0xC72FEFD3, 0xF752F7DA, 0x3F046F69, 0x77FA0A59, - 0x80E4A915, 0x87B08601, 0x9B09E6AD, 0x3B3EE593, - 0xE990FD5A, 0x9E34D797, 0x2CF0B7D9, 0x022B8B51, - 0x96D5AC3A, 0x017DA67D, 0xD1CF3ED6, 0x7C7D2D28, - 0x1F9F25CF, 0xADF2B89B, 0x5AD6B472, 0x5A88F54C, - 0xE029AC71, 0xE019A5E6, 0x47B0ACFD, 0xED93FA9B, - 0xE8D3C48D, 0x283B57CC, 0xF8D56629, 0x79132E28, - 0x785F0191, 0xED756055, 0xF7960E44, 0xE3D35E8C, - 0x15056DD4, 0x88F46DBA, 0x03A16125, 0x0564F0BD, - 0xC3EB9E15, 0x3C9057A2, 0x97271AEC, 0xA93A072A, - 0x1B3F6D9B, 0x1E6321F5, 0xF59C66FB, 0x26DCF319, - 0x7533D928, 0xB155FDF5, 0x03563482, 0x8ABA3CBB, - 0x28517711, 0xC20AD9F8, 0xABCC5167, 0xCCAD925F, - 0x4DE81751, 0x3830DC8E, 0x379D5862, 0x9320F991, - 0xEA7A90C2, 0xFB3E7BCE, 0x5121CE64, 0x774FBE32, - 0xA8B6E37E, 0xC3293D46, 0x48DE5369, 0x6413E680, - 0xA2AE0810, 0xDD6DB224, 0x69852DFD, 0x09072166, - 0xB39A460A, 0x6445C0DD, 0x586CDECF, 0x1C20C8AE, - 0x5BBEF7DD, 0x1B588D40, 0xCCD2017F, 0x6BB4E3BB, - 0xDDA26A7E, 0x3A59FF45, 0x3E350A44, 0xBCB4CDD5, - 0x72EACEA8, 0xFA6484BB, 0x8D6612AE, 0xBF3C6F47, - 0xD29BE463, 0x542F5D9E, 0xAEC2771B, 0xF64E6370, - 0x740E0D8D, 0xE75B1357, 0xF8721671, 0xAF537D5D, - 0x4040CB08, 0x4EB4E2CC, 0x34D2466A, 0x0115AF84, - 0xE1B00428, 0x95983A1D, 0x06B89FB4, 0xCE6EA048, - 0x6F3F3B82, 0x3520AB82, 0x011A1D4B, 0x277227F8, - 0x611560B1, 0xE7933FDC, 0xBB3A792B, 0x344525BD, - 0xA08839E1, 0x51CE794B, 0x2F32C9B7, 0xA01FBAC9, - 0xE01CC87E, 0xBCC7D1F6, 0xCF0111C3, 0xA1E8AAC7, - 0x1A908749, 0xD44FBD9A, 0xD0DADECB, 0xD50ADA38, - 0x0339C32A, 0xC6913667, 0x8DF9317C, 0xE0B12B4F, - 0xF79E59B7, 0x43F5BB3A, 0xF2D519FF, 0x27D9459C, - 0xBF97222C, 0x15E6FC2A, 0x0F91FC71, 0x9B941525, - 0xFAE59361, 0xCEB69CEB, 0xC2A86459, 0x12BAA8D1, - 0xB6C1075E, 0xE3056A0C, 0x10D25065, 0xCB03A442, - 0xE0EC6E0E, 0x1698DB3B, 0x4C98A0BE, 0x3278E964, - 0x9F1F9532, 0xE0D392DF, 0xD3A0342B, 0x8971F21E, - 0x1B0A7441, 0x4BA3348C, 0xC5BE7120, 0xC37632D8, - 0xDF359F8D, 0x9B992F2E, 0xE60B6F47, 0x0FE3F11D, - 0xE54CDA54, 0x1EDAD891, 0xCE6279CF, 0xCD3E7E6F, - 0x1618B166, 0xFD2C1D05, 0x848FD2C5, 0xF6FB2299, - 0xF523F357, 0xA6327623, 0x93A83531, 0x56CCCD02, - 0xACF08162, 0x5A75EBB5, 0x6E163697, 0x88D273CC, - 0xDE966292, 0x81B949D0, 0x4C50901B, 0x71C65614, - 0xE6C6C7BD, 0x327A140A, 0x45E1D006, 0xC3F27B9A, - 0xC9AA53FD, 0x62A80F00, 0xBB25BFE2, 0x35BDD2F6, - 0x71126905, 0xB2040222, 0xB6CBCF7C, 0xCD769C2B, - 0x53113EC0, 0x1640E3D3, 0x38ABBD60, 0x2547ADF0, - 0xBA38209C, 0xF746CE76, 0x77AFA1C5, 0x20756060, - 0x85CBFE4E, 0x8AE88DD8, 0x7AAAF9B0, 0x4CF9AA7E, - 0x1948C25C, 0x02FB8A8C, 0x01C36AE4, 0xD6EBE1F9, - 0x90D4F869, 0xA65CDEA0, 0x3F09252D, 0xC208E69F, - 0xB74E6132, 0xCE77E25B, 0x578FDFE3, 0x3AC372E6, -}}; - -static uint32_t P[16 + 2]; -static uint32_t S[4][256]; - -static inline void swap(uint32_t *L, uint32_t *R) -{ - uint32_t t; - t = *L; - *L = *R; - *R = t; -} - -static inline void swapendian(uint32_t *n) -{ - uint8_t a, b, c, d; - a = (*n >> 24) & 0xff; - b = (*n >> 16) & 0xff; - c = (*n >> 8) & 0xff; - d = *n & 0xff; - *n = (d << 24) | (c << 16) | (b << 8) | a; -} - -static uint32_t f(uint32_t x) -{ - uint32_t h = S[0][x >> 24] + S[1][x >> 16 & 0xff]; - return (h ^ S[2][x >> 8 & 0xff]) + S[3][x & 0xff]; -} - -static void encrypt(uint32_t *L, uint32_t *R) -{ - int i; - for (i = 0; i < 16; i += 2) { - *L ^= P[i]; - *R ^= f(*L); - *R ^= P[i + 1]; - *L ^= f(*R); - } - *L ^= P[16]; - *R ^= P[17]; - swap(L, R); -} - -static void decrypt(uint32_t *L, uint32_t *R) -{ - int i; - for (i = 16; i > 0; i -= 2) { - *L ^= P[i + 1]; - *R ^= f(*L); - *R ^= P[i]; - *L ^= f(*R); - } - *L ^= P[1]; - *R ^= P[0]; - swap(L, R); -} - -static void key_schedule(uint32_t *key, int keylen) -{ - int i, j; - uint32_t L = 0, R = 0; - memcpy(P, P_orig, sizeof(P)); - memcpy(S, S_orig, sizeof(S)); - for (i = 0; i < 18; i++) { - P[i] ^= key[i % keylen]; - } - for (i = 0; i < 18; i+=2) { - encrypt(&L, &R); - P[i] = L; - P[i + 1] = R; - } - for (i = 0; i < 4; i++) { - for (j = 0; j < 256; j += 2) { - encrypt(&L, &R); - S[i][j] = L; - S[i][j + 1] = R; - } - } -} - -void blowfish_setkey(uint8_t *key, int keylen) -{ - int i; - for (i = 0; i < keylen / 4; i++) { - swapendian((uint32_t *)(key + i * 4)); - } - key_schedule((uint32_t *)key, keylen / 4); -} - -void blowfish_encrypt(uint8_t *data, int datalen) -{ - int i; - for (i = 0; i < datalen / 4; i++) { - swapendian((uint32_t *)(data + i * 4)); - } - for (i = 0; i < datalen / 8; i++) { - encrypt((uint32_t *)(data + i * 8), (uint32_t *)(data + i * 8 + 4)); - } - for (i = 0; i < datalen / 4; i++) { - swapendian((uint32_t *)(data + i * 4)); - } -} - -void blowfish_decrypt(uint8_t *data, int datalen) -{ - int i; - for (i = 0; i < datalen / 4; i++) { - swapendian((uint32_t *)(data + i * 4)); - } - for (i = 0; i < datalen / 8; i++) { - decrypt((uint32_t *)(data + i * 8), (uint32_t *)(data + i * 8 + 4)); - } - for (i = 0; i < datalen / 4; i++) { - swapendian((uint32_t *)(data + i * 4)); - } -} diff --git a/blowfish.h b/blowfish.h deleted file mode 100644 index 6cd6bc530..000000000 --- a/blowfish.h +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Copyright (c) 2013 Pavol Rusnak - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef __BLOWFISH_H__ -#define __BLOWFISH_H__ - -#include - -void blowfish_setkey(uint8_t *key, int keylen); -void blowfish_encrypt(uint8_t *data, int datalen); -void blowfish_decrypt(uint8_t *data, int datalen); - -#endif diff --git a/tests.c b/tests.c index b9b9e4f43..dd80ca823 100644 --- a/tests.c +++ b/tests.c @@ -26,7 +26,7 @@ #include #include -#include "blowfish.h" +#include "aes.h" #include "bignum.h" #include "bip32.h" #include "ecdsa.h" @@ -262,74 +262,31 @@ START_TEST(test_verify_speed) } END_TEST -#define test_bfsh(KEY, CLEAR, CIPHER) do { \ - memcpy(key, fromhex(KEY), strlen(KEY)/2); \ - memcpy(data, fromhex(CLEAR), strlen(CLEAR)/2); \ - blowfish_setkey(key, strlen(KEY)/2); \ - blowfish_encrypt(data, strlen(CLEAR)/2); \ - ck_assert_mem_eq(data, fromhex(CIPHER), strlen(CIPHER)/2); \ +#define test_aes(KEY, BLKLEN, IN, OUT) do { \ + SHA256_Raw((uint8_t *)KEY, strlen(KEY), key); \ + aes_blk_len(BLKLEN, &ctx); \ + aes_enc_key(key, 32, &ctx); \ + memcpy(in, fromhex(IN), BLKLEN); \ + aes_enc_blk(in, out, &ctx); \ + ck_assert_mem_eq(out, fromhex(OUT), BLKLEN); \ } while (0) -// test vectors from https://www.schneier.com/code/vectors.txt -START_TEST(test_blowfish_1) +START_TEST(test_rijndael) { - uint8_t key[8]; - uint8_t data[8]; - test_bfsh("0000000000000000", "0000000000000000", "4ef997456198dd78"); - test_bfsh("ffffffffffffffff", "ffffffffffffffff", "51866fd5b85ecb8a"); - test_bfsh("3000000000000000", "1000000000000001", "7d856f9a613063f2"); - test_bfsh("1111111111111111", "1111111111111111", "2466dd878b963c9d"); - test_bfsh("0123456789abcdef", "1111111111111111", "61f9c3802281b096"); - test_bfsh("1111111111111111", "0123456789abcdef", "7d0cc630afda1ec7"); - test_bfsh("0000000000000000", "0000000000000000", "4ef997456198dd78"); - test_bfsh("fedcba9876543210", "0123456789abcdef", "0aceab0fc6a0a28d"); - test_bfsh("7ca110454a1a6e57", "01a1d6d039776742", "59c68245eb05282b"); - test_bfsh("0131d9619dc1376e", "5cd54ca83def57da", "b1b8cc0b250f09a0"); - test_bfsh("07a1133e4a0b2686", "0248d43806f67172", "1730e5778bea1da4"); - test_bfsh("3849674c2602319e", "51454b582ddf440a", "a25e7856cf2651eb"); - test_bfsh("04b915ba43feb5b6", "42fd443059577fa2", "353882b109ce8f1a"); - test_bfsh("0113b970fd34f2ce", "059b5e0851cf143a", "48f4d0884c379918"); - test_bfsh("0170f175468fb5e6", "0756d8e0774761d2", "432193b78951fc98"); - test_bfsh("43297fad38e373fe", "762514b829bf486a", "13f04154d69d1ae5"); - test_bfsh("07a7137045da2a16", "3bdd119049372802", "2eedda93ffd39c79"); - test_bfsh("04689104c2fd3b2f", "26955f6835af609a", "d887e0393c2da6e3"); - test_bfsh("37d06bb516cb7546", "164d5e404f275232", "5f99d04f5b163969"); - test_bfsh("1f08260d1ac2465e", "6b056e18759f5cca", "4a057a3b24d3977b"); - test_bfsh("584023641aba6176", "004bd6ef09176062", "452031c1e4fada8e"); - test_bfsh("025816164629b007", "480d39006ee762f2", "7555ae39f59b87bd"); - test_bfsh("49793ebc79b3258f", "437540c8698f3cfa", "53c55f9cb49fc019"); - test_bfsh("4fb05e1515ab73a7", "072d43a077075292", "7a8e7bfa937e89a3"); - test_bfsh("49e95d6d4ca229bf", "02fe55778117f12a", "cf9c5d7a4986adb5"); - test_bfsh("018310dc409b26d6", "1d9d5c5018f728c2", "d1abb290658bc778"); - test_bfsh("1c587f1c13924fef", "305532286d6f295a", "55cb3774d13ef201"); - test_bfsh("0101010101010101", "0123456789abcdef", "fa34ec4847b268b2"); - test_bfsh("1f1f1f1f0e0e0e0e", "0123456789abcdef", "a790795108ea3cae"); - test_bfsh("e0fee0fef1fef1fe", "0123456789abcdef", "c39e072d9fac631d"); - test_bfsh("0000000000000000", "ffffffffffffffff", "014933e0cdaff6e4"); - test_bfsh("ffffffffffffffff", "0000000000000000", "f21e9a77b71c49bc"); - test_bfsh("0123456789abcdef", "0000000000000000", "245946885754369a"); - test_bfsh("fedcba9876543210", "ffffffffffffffff", "6b5c5a9c5d9e0a5a"); -} -END_TEST + aes_ctx ctx; + uint8_t key[32], in[32], out[32]; -// mnemonic test vectors -START_TEST(test_blowfish_2) -{ - uint8_t key[24]; - uint8_t data[24]; - // 6d6e656d6f6e6963 = "mnemonic" - test_bfsh("6d6e656d6f6e6963", "0000000000000000", "e6b5de53efaec3a5"); - test_bfsh("6d6e656d6f6e6963", "00000000000000000000000000000000", "e6b5de53efaec3a5e6b5de53efaec3a5"); - test_bfsh("6d6e656d6f6e6963", "000000000000000000000000000000000000000000000000", "e6b5de53efaec3a5e6b5de53efaec3a5e6b5de53efaec3a5"); - test_bfsh("6d6e656d6f6e6963", "7f7f7f7f7f7f7f7f", "cb21e7cd6313594b"); - test_bfsh("6d6e656d6f6e6963", "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", "cb21e7cd6313594bcb21e7cd6313594b"); - test_bfsh("6d6e656d6f6e6963", "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", "cb21e7cd6313594bcb21e7cd6313594bcb21e7cd6313594b"); - test_bfsh("6d6e656d6f6e6963", "8080808080808080", "8800e1df66298ae6"); - test_bfsh("6d6e656d6f6e6963", "80808080808080808080808080808080", "8800e1df66298ae68800e1df66298ae6"); - test_bfsh("6d6e656d6f6e6963", "808080808080808080808080808080808080808080808080", "8800e1df66298ae68800e1df66298ae68800e1df66298ae6"); - test_bfsh("6d6e656d6f6e6963", "ffffffffffffffff", "4c8be56fcf3de4cf"); - test_bfsh("6d6e656d6f6e6963", "ffffffffffffffffffffffffffffffff", "4c8be56fcf3de4cf4c8be56fcf3de4cf"); - test_bfsh("6d6e656d6f6e6963", "ffffffffffffffffffffffffffffffffffffffffffffffff", "4c8be56fcf3de4cf4c8be56fcf3de4cf4c8be56fcf3de4cf"); + test_aes("mnemonic", 16, "00000000000000000000000000000000", "a3af8b7d326a2d47bd7576012e07d103"); + test_aes("mnemonic", 24, "000000000000000000000000000000000000000000000000", "7b8704678f263c316ddd1746d8377a4046a99dd9e5687d59"); + test_aes("mnemonic", 32, "0000000000000000000000000000000000000000000000000000000000000000", "7c0575db9badc9960441c6b8dcbd5ebdfec522ede5309904b7088d0e77c2bcef"); + + test_aes("mnemonic", 16, "686f6a6461686f6a6461686f6a6461686f6a6461", "9c3bb85af2122cc2df449033338beb56"); + test_aes("mnemonic", 24, "686f6a6461686f6a6461686f6a6461686f6a6461686f6a64", "0d7009c589869eaa1d7398bffc7660cce32207a520d6cafe"); + test_aes("mnemonic", 32, "686f6a6461686f6a6461686f6a6461686f6a6461686f6a6461686f6a6461686f", "b1a4d05e3827611c5986ea4c207679a6934f20767434218029c4b3b7a53806a3"); + + test_aes("mnemonic", 16, "ffffffffffffffffffffffffffffffff", "e720f4474b7dabe382eec0529e2b1128"); + test_aes("mnemonic", 24, "ffffffffffffffffffffffffffffffffffffffffffffffff", "14dfe4c7a93e14616dce6c793110baee0b8bb404f3bec6c5"); + test_aes("mnemonic", 32, "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "ccf498fd9a57f872a4d274549fab474cbacdbd9d935ca31b06e3025526a704fb"); } END_TEST @@ -353,9 +310,8 @@ Suite *test_suite(void) tcase_add_test(tc, test_verify_speed); suite_add_tcase(s, tc); - tc = tcase_create("blowfish"); - tcase_add_test(tc, test_blowfish_1); - tcase_add_test(tc, test_blowfish_2); + tc = tcase_create("rijndael"); + tcase_add_test(tc, test_rijndael); suite_add_tcase(s, tc); return s; From a439d8674d025da2a99cc1eab5b76d3871897e68 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 24 Oct 2013 19:44:54 +0200 Subject: [PATCH 048/627] small cosmetic changes --- ecdsa.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/ecdsa.c b/ecdsa.c index 324223d5d..92765e58f 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -379,8 +379,7 @@ int ecdsa_verify(const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, bn_read_be(hash, &z); - if (bn_is_zero(&r) || - bn_is_zero(&s) || + if (bn_is_zero(&r) || bn_is_zero(&s) || (!bn_is_less(&r, &order256k1)) || (!bn_is_less(&s, &order256k1))) return 2; @@ -410,10 +409,14 @@ int ecdsa_verify(const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, bn_mod(&(res.x), &prime256k1); bn_mod(&(res.x), &order256k1); + + // signature does not match for (i = 0; i < 9; i++) { if (res.x.val[i] != r.val[i]) { - return 3; + return 4; } } + + // all OK return 0; } From 42da580ce86c92053500df2d78e94a1b9858d4d6 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 8 Nov 2013 01:24:47 +0100 Subject: [PATCH 049/627] bip39 implementation with unit tests --- Makefile | 2 +- README | 1 + bip39.c | 155 ++++ bip39.h | 11 + bip39_english.h | 2051 +++++++++++++++++++++++++++++++++++++++++++++++ tests.c | 86 ++ 6 files changed, 2305 insertions(+), 1 deletion(-) create mode 100644 bip39.c create mode 100644 bip39.h create mode 100644 bip39_english.h diff --git a/Makefile b/Makefile index 24810b13d..43049aafe 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ CC = gcc CFLAGS = -Wall -Os -OBJS = bignum.o ecdsa.o secp256k1.o sha2.o rand.o hmac.o bip32.o ripemd160.o +OBJS = bignum.o ecdsa.o secp256k1.o sha2.o rand.o hmac.o bip32.o ripemd160.o bip39.o OBJS += aescrypt.o aeskey.o aestab.o all: tests test-openssl diff --git a/README b/README index c3f8ee40d..feb8d0adb 100644 --- a/README +++ b/README @@ -7,6 +7,7 @@ These include: - AES/Rijndael encryption/decryption - Big Number (256 bit) Arithmetics - BIP32 Hierarchical Deterministic Wallets +- BIP39 Mnemonic code - ECDSA signing/verifying (only hardcoded secp256k1 curve, uses RFC6979 for deterministic signatures) - ECDSA public key derivation + Base58 address representation diff --git a/bip39.c b/bip39.c new file mode 100644 index 000000000..f8eb4d403 --- /dev/null +++ b/bip39.c @@ -0,0 +1,155 @@ +#include + +#include "bip39.h" +#include "sha2.h" +#include "aes.h" +#include "bip39_english.h" + +#define RIJNDAEL_ITERATIONS 10000 + +void mnemonic_rijndael(uint8_t *data, int len, char *passphrase, bool encrypt) +{ + if (len != 16 && len != 24 && len != 32) return; + + SHA256_CTX sha_ctx; + aes_ctx ctx; + uint8_t key[32]; + int i; + + SHA256_Init(&sha_ctx); + SHA256_Update(&sha_ctx, (uint8_t *)"mnemonic", 8); + if (passphrase) { + SHA256_Update(&sha_ctx, (uint8_t *)passphrase, strlen(passphrase)); + } + SHA256_Final(key, &sha_ctx); + + aes_blk_len(len, &ctx); + + if (encrypt) { + aes_enc_key(key, 32, &ctx); + for (i = 0; i < RIJNDAEL_ITERATIONS; i++) { + aes_enc_blk(data, data, &ctx); + } + } else { + aes_dec_key(key, 32, &ctx); + for (i = 0; i < RIJNDAEL_ITERATIONS; i++) { + aes_dec_blk(data, data, &ctx); + } + } +} + +#define mnemonic_stretch(D, L, P) mnemonic_rijndael((D), (L), (P), true) +#define mnemonic_unstretch(D, L, P) mnemonic_rijndael((D), (L), (P), false) + +static char mnemo[24 * 10]; +static char bits[256 + 8]; + +char mnemonic_checksum(uint8_t *data, int len) +{ + char r = 0; + int i; + switch (len) { + case 16: // checksum = 4 bits + for (i = 0; i < 16; i++) { + r ^= (data[i] & 0xF0) >> 4; + r ^= (data[i] & 0x0F); + } + break; + case 24: // checksum = 6 bits + for (i = 0; i < 8; i++) { + r ^= (data[3 * i] & 0xFC) >> 2; // xxxxxx__ ________ ________ + r ^= ((data[3 * i] & 0x03) << 4) | ((data[3 * i + 1] & 0xF0) >> 4); // ______xx xxxx____ ________ + r ^= ((data[3 * i + 1] & 0x0F) << 2) | ((data[3 * i + 2] & 0xC0) >> 6); // ________ ____xxxx xx______ + r ^= data[3 * i + 2] & 0x3F; // ________ ________ __xxxxxx + } + break; + case 32: // checksum = 8 bits + for (i = 0; i < 32; i++) { + r ^= data[i]; + } + break; + } + return r; +} + +const char *mnemonic_encode(uint8_t *data, int len, char *passphrase) +{ + if (len != 16 && len != 24 && len != 32) return 0; + + mnemonic_stretch(data, len, passphrase); + + int i, j; + for (i = 0; i < len; i++) { + for (j = 0; j < 8; j++) { + bits[8 * i + j] = (data[i] & (1 << (7 - j))) > 0; + } + } + + char checksum = mnemonic_checksum(data, len); + for (j = 0; j < (len/4); j++) { + bits[8 * len + j] = (checksum & (1 << ((len / 4 - 1) - j))) > 0; + } + + len = len * 3 / 4; + char *p = mnemo; + for (i = 0; i < len; i++) { + int idx = 0; + for (j = 0; j < 11; j++) { + idx += bits[i * 11 + j] << (10 - j); + } + strcpy(p, wordlist[idx]); + p += strlen(wordlist[idx]); + *p = (i < len - 1) ? ' ' : 0; + p++; + } + + return mnemo; +} + +int wordlist_index(const char *word) +{ + int i = 0; + while (wordlist[i]) { + if (strcmp(word, wordlist[i]) == 0) return i; + i++; + } + return -1; +} + +int mnemonic_decode(const char *mnemonic, uint8_t *data, char *passphrase) +{ + strcpy(mnemo, mnemonic); + + int i, j, b = 0, len; + char *p = strtok(mnemo, " "); + while (p) { + int idx = wordlist_index(p); + if (idx < 0 || idx > 2047) return 0; + for (j = 0; j < 11; j++) { + bits[b] = (idx & (1 << (10 - j))) > 0; + b++; + } + p = strtok(NULL, " "); + } + if (b != 128 + 4 && b != 192 + 6 && b != 256 + 8) return 0; + + len = b / 33 * 4; + + for (i = 0; i < len; i++) { + data[i] = 0; + for (j = 0; j < 8; j++) { + data[i] |= bits[8 * i + j] << (7 - j); + } + } + char checksum = 0; + for (j = 0; j < (len/4); j++) { + checksum |= bits[8 * len + j] << ((len / 4 - 1) - j); + } + if (checksum != mnemonic_checksum(data, len)) { + return 0; + } + + mnemonic_unstretch(data, len, passphrase); + + return len; +} diff --git a/bip39.h b/bip39.h new file mode 100644 index 000000000..34fbf62fc --- /dev/null +++ b/bip39.h @@ -0,0 +1,11 @@ +#ifndef __BIP39_H__ +#define __BIP39_H__ + +#include +#include + +const char *mnemonic_encode(uint8_t *data, int len, char *passphrase); + +int mnemonic_decode(const char *mnemonic, uint8_t *data, char *passphrase); + +#endif diff --git a/bip39_english.h b/bip39_english.h new file mode 100644 index 000000000..d9c173472 --- /dev/null +++ b/bip39_english.h @@ -0,0 +1,2051 @@ +const char *wordlist[] = { +"abandon", +"ability", +"able", +"about", +"above", +"absent", +"absorb", +"abstract", +"absurd", +"abuse", +"access", +"accident", +"account", +"accuse", +"achieve", +"acid", +"acoustic", +"acquire", +"across", +"act", +"action", +"actor", +"actress", +"actual", +"adapt", +"add", +"addict", +"address", +"adjust", +"admit", +"adult", +"advance", +"advice", +"aerobic", +"affair", +"afford", +"afraid", +"again", +"age", +"agent", +"agree", +"ahead", +"aim", +"air", +"airport", +"aisle", +"alarm", +"album", +"alcohol", +"alert", +"alien", +"all", +"alley", +"allow", +"almost", +"alone", +"alpha", +"already", +"also", +"alter", +"always", +"amateur", +"amazing", +"among", +"amount", +"amused", +"analyst", +"anchor", +"ancient", +"anger", +"angle", +"angry", +"animal", +"ankle", +"announce", +"annual", +"another", +"answer", +"antenna", +"antique", +"anxiety", +"any", +"apart", +"apology", +"appear", +"apple", +"approve", +"april", +"arch", +"arctic", +"area", +"arena", +"argue", +"arm", +"armed", +"armor", +"army", +"around", +"arrange", +"arrest", +"arrive", +"arrow", +"art", +"artefact", +"artist", +"artwork", +"ask", +"aspect", +"assault", +"asset", +"assist", +"assume", +"asthma", +"athlete", +"atom", +"attack", +"attend", +"attitude", +"attract", +"auction", +"audit", +"august", +"aunt", +"author", +"auto", +"autumn", +"average", +"avocado", +"avoid", +"awake", +"aware", +"away", +"awesome", +"awful", +"awkward", +"axis", +"baby", +"bachelor", +"bacon", +"badge", +"bag", +"balance", +"balcony", +"ball", +"bamboo", +"banana", +"banner", +"bar", +"barely", +"bargain", +"barrel", +"base", +"basic", +"basket", +"battle", +"beach", +"bean", +"beauty", +"because", +"become", +"beef", +"before", +"begin", +"behave", +"behind", +"believe", +"below", +"belt", +"bench", +"benefit", +"best", +"betray", +"better", +"between", +"beyond", +"bicycle", +"bid", +"bike", +"bind", +"biology", +"bird", +"birth", +"bitter", +"black", +"blade", +"blame", +"blanket", +"blast", +"bleak", +"bless", +"blind", +"blood", +"blossom", +"blouse", +"blue", +"blur", +"blush", +"board", +"boat", +"body", +"boil", +"bomb", +"bone", +"bonus", +"book", +"boost", +"border", +"boring", +"borrow", +"boss", +"bottom", +"bounce", +"box", +"boy", +"bracket", +"brain", +"brand", +"brass", +"brave", +"bread", +"breeze", +"brick", +"bridge", +"brief", +"bright", +"bring", +"brisk", +"broccoli", +"broken", +"bronze", +"broom", +"brother", +"brown", +"brush", +"bubble", +"buddy", +"budget", +"buffalo", +"build", +"bulb", +"bulk", +"bullet", +"bundle", +"bunker", +"burden", +"burger", +"burst", +"bus", +"business", +"busy", +"butter", +"buyer", +"buzz", +"cabbage", +"cabin", +"cable", +"cactus", +"cage", +"cake", +"call", +"calm", +"camera", +"camp", +"can", +"canal", +"cancel", +"candy", +"cannon", +"canoe", +"canvas", +"canyon", +"capable", +"capital", +"captain", +"car", +"carbon", +"card", +"cargo", +"carpet", +"carry", +"cart", +"case", +"cash", +"casino", +"castle", +"casual", +"cat", +"catalog", +"catch", +"category", +"cattle", +"caught", +"cause", +"caution", +"cave", +"ceiling", +"celery", +"cement", +"census", +"century", +"cereal", +"certain", +"chair", +"chalk", +"champion", +"change", +"chaos", +"chapter", +"charge", +"chase", +"chat", +"cheap", +"check", +"cheese", +"chef", +"cherry", +"chest", +"chicken", +"chief", +"child", +"chimney", +"choice", +"choose", +"chronic", +"chuckle", +"chunk", +"churn", +"cigar", +"cinnamon", +"circle", +"citizen", +"city", +"civil", +"claim", +"clap", +"clarify", +"claw", +"clay", +"clean", +"clerk", +"clever", +"click", +"client", +"cliff", +"climb", +"clinic", +"clip", +"clock", +"clog", +"close", +"cloth", +"cloud", +"clown", +"club", +"clump", +"cluster", +"clutch", +"coach", +"coast", +"coconut", +"code", +"coffee", +"coil", +"coin", +"collect", +"color", +"column", +"combine", +"come", +"comfort", +"comic", +"common", +"company", +"concert", +"conduct", +"confirm", +"congress", +"connect", +"consider", +"control", +"convince", +"cook", +"cool", +"copper", +"copy", +"coral", +"core", +"corn", +"correct", +"cost", +"cotton", +"couch", +"country", +"couple", +"course", +"cousin", +"cover", +"coyote", +"crack", +"cradle", +"craft", +"cram", +"crane", +"crash", +"crater", +"crawl", +"crazy", +"cream", +"credit", +"creek", +"crew", +"cricket", +"crime", +"crisp", +"critic", +"crop", +"cross", +"crouch", +"crowd", +"crucial", +"cruel", +"cruise", +"crumble", +"crunch", +"crush", +"cry", +"crystal", +"cube", +"culture", +"cup", +"cupboard", +"curious", +"current", +"curtain", +"curve", +"cushion", +"custom", +"cute", +"cycle", +"dad", +"damage", +"damp", +"dance", +"danger", +"daring", +"dash", +"daughter", +"dawn", +"day", +"deal", +"debate", +"debris", +"decade", +"december", +"decide", +"decline", +"decorate", +"decrease", +"deer", +"defense", +"define", +"defy", +"degree", +"delay", +"deliver", +"demand", +"demise", +"denial", +"dentist", +"deny", +"depart", +"depend", +"deposit", +"depth", +"deputy", +"derive", +"describe", +"desert", +"design", +"desk", +"despair", +"destroy", +"detail", +"detect", +"develop", +"device", +"devote", +"diagram", +"dial", +"diamond", +"diary", +"dice", +"diesel", +"diet", +"differ", +"digital", +"dignity", +"dilemma", +"dinner", +"dinosaur", +"direct", +"dirt", +"disagree", +"discover", +"disease", +"dish", +"dismiss", +"disorder", +"display", +"distance", +"divert", +"divide", +"divorce", +"dizzy", +"doctor", +"document", +"dog", +"doll", +"dolphin", +"domain", +"donate", +"donkey", +"donor", +"door", +"dose", +"double", +"dove", +"draft", +"dragon", +"drama", +"drastic", +"draw", +"dream", +"dress", +"drift", +"drill", +"drink", +"drip", +"drive", +"drop", +"drum", +"dry", +"duck", +"dumb", +"dune", +"during", +"dust", +"dutch", +"duty", +"dwarf", +"dynamic", +"eager", +"eagle", +"early", +"earn", +"earth", +"easily", +"east", +"easy", +"echo", +"ecology", +"economy", +"edge", +"edit", +"educate", +"effort", +"egg", +"eight", +"either", +"elbow", +"elder", +"electric", +"elegant", +"element", +"elephant", +"elevator", +"elite", +"else", +"embark", +"embody", +"embrace", +"emerge", +"emotion", +"employ", +"empower", +"empty", +"enable", +"enact", +"end", +"endless", +"endorse", +"enemy", +"energy", +"enforce", +"engage", +"engine", +"enhance", +"enjoy", +"enlist", +"enough", +"enrich", +"enroll", +"ensure", +"enter", +"entire", +"entry", +"envelope", +"episode", +"equal", +"equip", +"era", +"erase", +"erode", +"erosion", +"error", +"erupt", +"escape", +"essay", +"essence", +"estate", +"eternal", +"ethics", +"evidence", +"evil", +"evoke", +"evolve", +"exact", +"example", +"excess", +"exchange", +"excite", +"exclude", +"excuse", +"execute", +"exercise", +"exhaust", +"exhibit", +"exile", +"exist", +"exit", +"exotic", +"expand", +"expect", +"expire", +"explain", +"expose", +"express", +"extend", +"extra", +"eye", +"eyebrow", +"fabric", +"face", +"faculty", +"fade", +"faint", +"faith", +"fall", +"false", +"fame", +"family", +"famous", +"fan", +"fancy", +"fantasy", +"farm", +"fashion", +"fat", +"fatal", +"father", +"fatigue", +"fault", +"favorite", +"feature", +"february", +"federal", +"fee", +"feed", +"feel", +"female", +"fence", +"festival", +"fetch", +"fever", +"few", +"fiber", +"fiction", +"field", +"figure", +"file", +"film", +"filter", +"final", +"find", +"fine", +"finger", +"finish", +"fire", +"firm", +"first", +"fiscal", +"fish", +"fit", +"fitness", +"fix", +"flag", +"flame", +"flash", +"flat", +"flavor", +"flee", +"flight", +"flip", +"float", +"flock", +"floor", +"flower", +"fluid", +"flush", +"fly", +"foam", +"focus", +"fog", +"foil", +"fold", +"follow", +"food", +"foot", +"force", +"forest", +"forget", +"fork", +"fortune", +"forum", +"forward", +"fossil", +"foster", +"found", +"fox", +"fragile", +"frame", +"frequent", +"fresh", +"friend", +"fringe", +"frog", +"front", +"frost", +"frown", +"frozen", +"fruit", +"fuel", +"fun", +"funny", +"furnace", +"fury", +"future", +"gadget", +"gain", +"galaxy", +"gallery", +"game", +"gap", +"garage", +"garbage", +"garden", +"garlic", +"garment", +"gas", +"gasp", +"gate", +"gather", +"gauge", +"gaze", +"general", +"genius", +"genre", +"gentle", +"genuine", +"gesture", +"ghost", +"giant", +"gift", +"giggle", +"ginger", +"giraffe", +"girl", +"give", +"glad", +"glance", +"glare", +"glass", +"glide", +"glimpse", +"globe", +"gloom", +"glory", +"glove", +"glow", +"glue", +"goat", +"goddess", +"gold", +"good", +"goose", +"gorilla", +"gospel", +"gossip", +"govern", +"gown", +"grab", +"grace", +"grain", +"grant", +"grape", +"grass", +"gravity", +"great", +"green", +"grid", +"grief", +"grit", +"grocery", +"group", +"grow", +"grunt", +"guard", +"guess", +"guide", +"guilt", +"guitar", +"gun", +"gym", +"habit", +"hair", +"half", +"hammer", +"hamster", +"hand", +"happy", +"harbor", +"hard", +"harsh", +"harvest", +"hat", +"have", +"hawk", +"hazard", +"head", +"health", +"heart", +"heavy", +"hedgehog", +"height", +"hello", +"helmet", +"help", +"hen", +"hero", +"hidden", +"high", +"hill", +"hint", +"hip", +"hire", +"history", +"hobby", +"hockey", +"hold", +"hole", +"holiday", +"hollow", +"home", +"honey", +"hood", +"hope", +"horn", +"horror", +"horse", +"hospital", +"host", +"hotel", +"hour", +"hover", +"hub", +"huge", +"human", +"humble", +"humor", +"hundred", +"hungry", +"hunt", +"hurdle", +"hurry", +"hurt", +"husband", +"hybrid", +"ice", +"icon", +"idea", +"identify", +"idle", +"ignore", +"ill", +"illegal", +"illness", +"image", +"imitate", +"immense", +"immune", +"impact", +"impose", +"improve", +"impulse", +"inch", +"include", +"income", +"increase", +"index", +"indicate", +"indoor", +"industry", +"infant", +"inflict", +"inform", +"inhale", +"inherit", +"initial", +"inject", +"injury", +"inmate", +"inner", +"innocent", +"input", +"inquiry", +"insane", +"insect", +"inside", +"inspire", +"install", +"intact", +"interest", +"into", +"invest", +"invite", +"involve", +"iron", +"island", +"isolate", +"issue", +"item", +"ivory", +"jacket", +"jaguar", +"jar", +"jazz", +"jealous", +"jeans", +"jelly", +"jewel", +"job", +"join", +"joke", +"journey", +"joy", +"judge", +"juice", +"jump", +"jungle", +"junior", +"junk", +"just", +"kangaroo", +"keen", +"keep", +"ketchup", +"key", +"kick", +"kid", +"kidney", +"kind", +"kingdom", +"kiss", +"kit", +"kitchen", +"kite", +"kitten", +"kiwi", +"knee", +"knife", +"knock", +"know", +"lab", +"label", +"labor", +"ladder", +"lady", +"lake", +"lamp", +"language", +"laptop", +"large", +"later", +"latin", +"laugh", +"laundry", +"lava", +"law", +"lawn", +"lawsuit", +"layer", +"lazy", +"leader", +"leaf", +"learn", +"leave", +"lecture", +"left", +"leg", +"legal", +"legend", +"leisure", +"lemon", +"lend", +"length", +"lens", +"leopard", +"lesson", +"letter", +"level", +"liar", +"liberty", +"library", +"license", +"life", +"lift", +"light", +"like", +"limb", +"limit", +"link", +"lion", +"liquid", +"list", +"little", +"live", +"lizard", +"load", +"loan", +"lobster", +"local", +"lock", +"logic", +"lonely", +"long", +"loop", +"lottery", +"loud", +"lounge", +"love", +"loyal", +"lucky", +"luggage", +"lumber", +"lunar", +"lunch", +"luxury", +"lyrics", +"machine", +"mad", +"magic", +"magnet", +"maid", +"mail", +"main", +"major", +"make", +"mammal", +"man", +"manage", +"mandate", +"mango", +"mansion", +"manual", +"maple", +"marble", +"march", +"margin", +"marine", +"market", +"marriage", +"mask", +"mass", +"master", +"match", +"material", +"math", +"matrix", +"matter", +"maximum", +"maze", +"meadow", +"mean", +"measure", +"meat", +"mechanic", +"medal", +"media", +"melody", +"melt", +"member", +"memory", +"mention", +"menu", +"mercy", +"merge", +"merit", +"merry", +"mesh", +"message", +"metal", +"method", +"middle", +"midnight", +"milk", +"million", +"mimic", +"mind", +"minimum", +"minor", +"minute", +"miracle", +"mirror", +"misery", +"miss", +"mistake", +"mix", +"mixed", +"mixture", +"mobile", +"model", +"modify", +"mom", +"moment", +"monitor", +"monkey", +"monster", +"month", +"moon", +"moral", +"more", +"morning", +"mosquito", +"mother", +"motion", +"motor", +"mountain", +"mouse", +"move", +"movie", +"much", +"muffin", +"mule", +"multiply", +"muscle", +"museum", +"mushroom", +"music", +"must", +"mutual", +"myself", +"mystery", +"myth", +"naive", +"name", +"napkin", +"narrow", +"nasty", +"nation", +"nature", +"near", +"neck", +"need", +"negative", +"neglect", +"neither", +"nephew", +"nerve", +"nest", +"net", +"network", +"neutral", +"never", +"news", +"next", +"nice", +"night", +"noble", +"noise", +"nominee", +"noodle", +"normal", +"north", +"nose", +"notable", +"note", +"nothing", +"notice", +"novel", +"now", +"nuclear", +"number", +"nurse", +"nut", +"oak", +"obey", +"object", +"oblige", +"obscure", +"observe", +"obtain", +"obvious", +"occur", +"ocean", +"october", +"odor", +"off", +"offer", +"office", +"often", +"oil", +"okay", +"old", +"olive", +"olympic", +"omit", +"once", +"one", +"onion", +"online", +"only", +"open", +"opera", +"opinion", +"oppose", +"option", +"orange", +"orbit", +"orchard", +"order", +"ordinary", +"organ", +"orient", +"original", +"orphan", +"ostrich", +"other", +"outdoor", +"outer", +"output", +"outside", +"oval", +"oven", +"over", +"own", +"owner", +"oxygen", +"oyster", +"ozone", +"pact", +"paddle", +"page", +"pair", +"palace", +"palm", +"panda", +"panel", +"panic", +"panther", +"paper", +"parade", +"parent", +"park", +"parrot", +"party", +"pass", +"patch", +"path", +"patient", +"patrol", +"pattern", +"pause", +"pave", +"payment", +"peace", +"peanut", +"pear", +"peasant", +"pelican", +"pen", +"penalty", +"pencil", +"people", +"pepper", +"perfect", +"permit", +"person", +"pet", +"phone", +"photo", +"phrase", +"physical", +"piano", +"picnic", +"picture", +"piece", +"pig", +"pigeon", +"pill", +"pilot", +"pink", +"pioneer", +"pipe", +"pistol", +"pitch", +"pizza", +"place", +"planet", +"plastic", +"plate", +"play", +"please", +"pledge", +"pluck", +"plug", +"plunge", +"poem", +"poet", +"point", +"polar", +"pole", +"police", +"pond", +"pony", +"pool", +"popular", +"portion", +"position", +"possible", +"post", +"potato", +"pottery", +"poverty", +"powder", +"power", +"practice", +"praise", +"predict", +"prefer", +"prepare", +"present", +"pretty", +"prevent", +"price", +"pride", +"primary", +"print", +"priority", +"prison", +"private", +"prize", +"problem", +"process", +"produce", +"profit", +"program", +"project", +"promote", +"proof", +"property", +"prosper", +"protect", +"proud", +"provide", +"public", +"pudding", +"pull", +"pulp", +"pulse", +"pumpkin", +"punch", +"pupil", +"puppy", +"purchase", +"purity", +"purpose", +"purse", +"push", +"put", +"puzzle", +"pyramid", +"quality", +"quantum", +"quarter", +"question", +"quick", +"quit", +"quiz", +"quote", +"rabbit", +"raccoon", +"race", +"rack", +"radar", +"radio", +"rail", +"rain", +"raise", +"rally", +"ramp", +"ranch", +"random", +"range", +"rapid", +"rare", +"rate", +"rather", +"raven", +"raw", +"razor", +"ready", +"real", +"reason", +"rebel", +"rebuild", +"recall", +"receive", +"recipe", +"record", +"recycle", +"reduce", +"reflect", +"reform", +"refuse", +"region", +"regret", +"regular", +"reject", +"relax", +"release", +"relief", +"rely", +"remain", +"remember", +"remind", +"remove", +"render", +"renew", +"rent", +"reopen", +"repair", +"repeat", +"replace", +"report", +"require", +"rescue", +"resemble", +"resist", +"resource", +"response", +"result", +"retire", +"retreat", +"return", +"reunion", +"reveal", +"review", +"reward", +"rhythm", +"rib", +"ribbon", +"rice", +"rich", +"ride", +"ridge", +"rifle", +"right", +"rigid", +"ring", +"riot", +"ripple", +"risk", +"ritual", +"rival", +"river", +"road", +"roast", +"robot", +"robust", +"rocket", +"romance", +"roof", +"rookie", +"room", +"rose", +"rotate", +"rough", +"round", +"route", +"royal", +"rubber", +"rude", +"rug", +"rule", +"run", +"runway", +"rural", +"sad", +"saddle", +"sadness", +"safe", +"sail", +"salad", +"salmon", +"salon", +"salt", +"salute", +"same", +"sample", +"sand", +"satisfy", +"satoshi", +"sauce", +"sausage", +"save", +"say", +"scale", +"scan", +"scare", +"scatter", +"scene", +"scheme", +"school", +"science", +"scissors", +"scorpion", +"scout", +"scrap", +"screen", +"script", +"scrub", +"sea", +"search", +"season", +"seat", +"second", +"secret", +"section", +"security", +"seed", +"seek", +"segment", +"select", +"sell", +"seminar", +"senior", +"sense", +"sentence", +"series", +"service", +"session", +"settle", +"setup", +"seven", +"shadow", +"shaft", +"shallow", +"share", +"shed", +"shell", +"sheriff", +"shield", +"shift", +"shine", +"ship", +"shiver", +"shock", +"shoe", +"shoot", +"shop", +"short", +"shoulder", +"shove", +"shrimp", +"shrug", +"shuffle", +"shy", +"sibling", +"sick", +"side", +"siege", +"sight", +"sign", +"silent", +"silk", +"silly", +"silver", +"similar", +"simple", +"since", +"sing", +"siren", +"sister", +"situate", +"six", +"size", +"skate", +"sketch", +"ski", +"skill", +"skin", +"skirt", +"skull", +"slab", +"slam", +"sleep", +"slender", +"slice", +"slide", +"slight", +"slim", +"slogan", +"slot", +"slow", +"slush", +"small", +"smart", +"smile", +"smoke", +"smooth", +"snack", +"snake", +"snap", +"sniff", +"snow", +"soap", +"soccer", +"social", +"sock", +"soda", +"soft", +"solar", +"soldier", +"solid", +"solution", +"solve", +"someone", +"song", +"soon", +"sorry", +"sort", +"soul", +"sound", +"soup", +"source", +"south", +"space", +"spare", +"spatial", +"spawn", +"speak", +"special", +"speed", +"spell", +"spend", +"sphere", +"spice", +"spider", +"spike", +"spin", +"spirit", +"split", +"spoil", +"sponsor", +"spoon", +"sport", +"spot", +"spray", +"spread", +"spring", +"spy", +"square", +"squeeze", +"squirrel", +"stable", +"stadium", +"staff", +"stage", +"stairs", +"stamp", +"stand", +"start", +"state", +"stay", +"steak", +"steel", +"stem", +"step", +"stereo", +"stick", +"still", +"sting", +"stock", +"stomach", +"stone", +"stool", +"story", +"stove", +"strategy", +"street", +"strike", +"strong", +"struggle", +"student", +"stuff", +"stumble", +"style", +"subject", +"submit", +"subway", +"success", +"such", +"sudden", +"suffer", +"sugar", +"suggest", +"suit", +"summer", +"sun", +"sunny", +"sunset", +"super", +"supply", +"supreme", +"sure", +"surface", +"surge", +"surprise", +"surround", +"survey", +"suspect", +"sustain", +"swallow", +"swamp", +"swap", +"swarm", +"swear", +"sweet", +"swift", +"swim", +"swing", +"switch", +"sword", +"symbol", +"symptom", +"syrup", +"system", +"table", +"tackle", +"tag", +"tail", +"talent", +"talk", +"tank", +"tape", +"target", +"task", +"taste", +"tattoo", +"taxi", +"teach", +"team", +"tell", +"ten", +"tenant", +"tennis", +"tent", +"term", +"test", +"text", +"thank", +"that", +"theme", +"then", +"theory", +"there", +"they", +"thing", +"this", +"thought", +"three", +"thrive", +"throw", +"thumb", +"thunder", +"ticket", +"tide", +"tiger", +"tilt", +"timber", +"time", +"tiny", +"tip", +"tired", +"tissue", +"title", +"toast", +"tobacco", +"today", +"toddler", +"toe", +"together", +"toilet", +"token", +"tomato", +"tomorrow", +"tone", +"tongue", +"tonight", +"tool", +"tooth", +"top", +"topic", +"topple", +"torch", +"tornado", +"tortoise", +"toss", +"total", +"tourist", +"toward", +"tower", +"town", +"toy", +"track", +"trade", +"traffic", +"tragic", +"train", +"transfer", +"trap", +"trash", +"travel", +"tray", +"treat", +"tree", +"trend", +"trial", +"tribe", +"trick", +"trigger", +"trim", +"trip", +"trophy", +"trouble", +"truck", +"true", +"truly", +"trumpet", +"trust", +"truth", +"try", +"tube", +"tuition", +"tumble", +"tuna", +"tunnel", +"turkey", +"turn", +"turtle", +"twelve", +"twenty", +"twice", +"twin", +"twist", +"two", +"type", +"typical", +"ugly", +"umbrella", +"unable", +"unaware", +"uncle", +"uncover", +"under", +"undo", +"unfair", +"unfold", +"unhappy", +"uniform", +"unique", +"unit", +"universe", +"unknown", +"unlock", +"until", +"unusual", +"unveil", +"update", +"upgrade", +"uphold", +"upon", +"upper", +"upset", +"urban", +"urge", +"usage", +"use", +"used", +"useful", +"useless", +"usual", +"utility", +"vacant", +"vacuum", +"vague", +"valid", +"valley", +"valve", +"van", +"vanish", +"vapor", +"various", +"vast", +"vault", +"vehicle", +"velvet", +"vendor", +"venture", +"venue", +"verb", +"verify", +"version", +"very", +"vessel", +"veteran", +"viable", +"vibrant", +"vicious", +"victory", +"video", +"view", +"village", +"vintage", +"violin", +"virtual", +"virus", +"visa", +"visit", +"visual", +"vital", +"vivid", +"vocal", +"voice", +"void", +"volcano", +"volume", +"vote", +"voyage", +"wage", +"wagon", +"wait", +"walk", +"wall", +"walnut", +"want", +"warfare", +"warm", +"warrior", +"wash", +"wasp", +"waste", +"water", +"wave", +"way", +"wealth", +"weapon", +"wear", +"weasel", +"weather", +"web", +"wedding", +"weekend", +"weird", +"welcome", +"west", +"wet", +"whale", +"what", +"wheat", +"wheel", +"when", +"where", +"whip", +"whisper", +"wide", +"width", +"wife", +"wild", +"will", +"win", +"window", +"wine", +"wing", +"wink", +"winner", +"winter", +"wire", +"wisdom", +"wise", +"wish", +"witness", +"wolf", +"woman", +"wonder", +"wood", +"wool", +"word", +"work", +"world", +"worry", +"worth", +"wrap", +"wreck", +"wrestle", +"wrist", +"write", +"wrong", +"yard", +"year", +"yellow", +"you", +"young", +"youth", +"zebra", +"zero", +"zone", +"zoo", +0, +}; diff --git a/tests.c b/tests.c index dd80ca823..7df7603b9 100644 --- a/tests.c +++ b/tests.c @@ -29,6 +29,7 @@ #include "aes.h" #include "bignum.h" #include "bip32.h" +#include "bip39.h" #include "ecdsa.h" #include "sha2.h" @@ -290,6 +291,87 @@ START_TEST(test_rijndael) } END_TEST +START_TEST(test_mnemonic) +{ + static const char *vectors[] = { + "00000000000000000000000000000000", + "risk tiger venture dinner age assume float denial penalty hello game wing", + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", + "truth chase learn pretty right casual acoustic frozen betray main slogan method", + "80808080808080808080808080808080", + "olive garment twenty drill people finish hat own usual level milk usage", + "ffffffffffffffffffffffffffffffff", + "laundry faint system client frog vanish plug shell slot cable large embrace", + "000000000000000000000000000000000000000000000000", + "giant twelve seat embark ostrich jazz leader lunch budget hover much weapon vendor build truth garden year list", + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", + "awful faint gun mean fuel side slogan marine glad donkey velvet oyster movie real type digital dress federal", + "808080808080808080808080808080808080808080808080", + "bless carpet daughter animal hospital pave faculty escape fortune song sign twin unknown bread mobile normal agent use", + "ffffffffffffffffffffffffffffffffffffffffffffffff", + "saddle curve flight drama client resemble venture arch will ordinary enrich clutch razor shallow trophy tumble dice outer", + "0000000000000000000000000000000000000000000000000000000000000000", + "supreme army trim onion neglect coach squirrel spider device glass cabbage giant web digital floor able social magnet only fork fuel embrace salt fence", + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", + "cloth video uncle switch year captain artist country adjust edit inherit ocean tennis soda baby express hospital forest panel actual profit boy spice elite", + "8080808080808080808080808080808080808080808080808080808080808080", + "fence twin prize extra choose mask twist deny cereal quarter can power term ostrich leg staff nature nut swift sausage amateur aim script wisdom", + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "moon fiscal evidence exile rifle series neglect giant exclude banana glance frown kangaroo globe turtle hat fitness casual sudden select idle arctic best unlock", + "449ea2d7249c6e0d8d295424fb8894cf", + "choice barrel artefact cram increase sell veteran matrix mirror hollow walk pave", + "75fc3f44a7ff8e2b8af05aa18bded3827a3796df406763dd", + "crack outside teach chat praise client manual scorpion predict chalk decrease casino lunch garbage enable ball when bamboo", + "1cce2f8c2c6a7f2d8473ebf1c32ce13b36737835d7a8768f44dcf96d64782c0e", + "muffin evoke all fiber night guard black quote neck expire dial tenant leisure have dragon neck notable peace captain insane nice uphold shine angry", + "3daa82dd08bd144ec9fb9f77c6ece3d2", + "foil dawn net enroll turtle bird vault trumpet service fun immune unveil", + "9720239c0039f8446d44334daec325f3c24b3a490315d6d9", + "damp all desert dash insane pear debate easily soup enough goddess make friend plug violin pact wealth insect", + "fe58c6644bc3fad95832d4400cea0cce208c8b19bb4734a26995440b7fae7600", + "wet sniff asthma once gap enrich pumpkin define trust rude gesture keen grass fine emerge census immense smooth ritual spirit rescue problem beef choice", + "99fe82c94edadffe75e1cc64cbd7ada7", + "thing real emerge verify domain cloud lens teach travel radio effort glad", + "4fd6e8d06d55b4700130f8f462f7f9bfc6188da83e3faadb", + "diary opinion lobster code orange odor insane permit spirit evolve upset final antique grant friend dutch say enroll", + "7a547fb59606e89ba88188013712946f6cb31c3e0ca606a7ee1ff23f57272c63", + "layer owner legal stadium glance oyster element spell episode eager wagon stand pride old defense black print junior fade easy topic ready galaxy debris", + "e5fc62d20e0e5d9b2756e8d4d91cbb80", + "flat make unit discover rifle armed unit acquire group panel nerve want", + "d29be791a9e4b6a48ff79003dbf31d6afabdc4290a273765", + "absurd valve party disorder basket injury make blanket vintage ancient please random theory cart retire odor borrow belt", + "c87c135433c16f1ecbf9919dc53dd9f30f85824dc7264d4e1bd644826c902be2", + "upper will wisdom term once bean blur inquiry used bamboo frequent hamster amazing cake attack any author mimic leopard day token joy install company", + 0, + 0, + }; + + const char **d, **s, *m; + + // check encode + d = vectors; + s = vectors + 1; + while (*d && *s) { + m = mnemonic_encode(fromhex(*d), strlen(*d) / 2, 0); + ck_assert_ptr_ne(m, 0); + ck_assert_str_eq(m, *s); + d += 2; s += 2; + } + + // check decode + d = vectors; + s = vectors + 1; + uint8_t data[32]; + int len; + while (*d && *s) { + len = mnemonic_decode(*s, data, 0); + ck_assert_int_eq(len, strlen(*d) / 2); + ck_assert_mem_eq(fromhex(*d), data, len); + d += 2; s += 2; + } +} +END_TEST + // define test suite and cases Suite *test_suite(void) { @@ -314,6 +396,10 @@ Suite *test_suite(void) tcase_add_test(tc, test_rijndael); suite_add_tcase(s, tc); + tc = tcase_create("bip39"); + tcase_add_test(tc, test_mnemonic); + suite_add_tcase(s, tc); + return s; } From b14ce58df7ef6b2d925e9a02a2fc4ec75127c123 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 8 Nov 2013 12:44:11 +0100 Subject: [PATCH 050/627] rename xprv struct to XprvNode --- bip32.c | 4 ++-- bip32.h | 6 +++--- tests.c | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/bip32.c b/bip32.c index a636d1e7e..554b101d7 100644 --- a/bip32.c +++ b/bip32.c @@ -5,7 +5,7 @@ #include "ecdsa.h" #include "bip32.h" -void xprv_from_seed(uint8_t *seed, int seed_len, xprv *out) +void xprv_from_seed(uint8_t *seed, int seed_len, XprvNode *out) { out->version = 0x0488ADE4; // main-net out->depth = 0; @@ -18,7 +18,7 @@ void xprv_from_seed(uint8_t *seed, int seed_len, xprv *out) ecdsa_get_address(out->public_key, 0, out->address); } -void xprv_descent(xprv *inout, uint32_t i) +void xprv_descent(XprvNode *inout, uint32_t i) { uint8_t data[1 + 32 + 4]; bignum256 a, b; diff --git a/bip32.h b/bip32.h index a413575f3..417ac8ef6 100644 --- a/bip32.h +++ b/bip32.h @@ -12,12 +12,12 @@ typedef struct { uint8_t chain_code[32]; // form a continuous 64 byte block uint8_t public_key[33]; char address[35]; -} xprv; +} XprvNode; -void xprv_from_seed(uint8_t *seed, int seed_len, xprv *out); +void xprv_from_seed(uint8_t *seed, int seed_len, XprvNode *out); #define xprv_descent_prime(X, I) xprv_descent((X), ((I) | 0x80000000)) -void xprv_descent(xprv *inout, uint32_t i); +void xprv_descent(XprvNode *inout, uint32_t i); #endif diff --git a/tests.c b/tests.c index 7df7603b9..034387911 100644 --- a/tests.c +++ b/tests.c @@ -74,7 +74,7 @@ char *tohex(const uint8_t *bin, size_t l) // test vector 1 from https://en.bitcoin.it/wiki/BIP_0032_TestVectors START_TEST(test_bip32_vector_1) { - xprv node; + XprvNode node; // init m xprv_from_seed(fromhex("000102030405060708090a0b0c0d0e0f"), 16, &node); @@ -126,7 +126,7 @@ END_TEST // test vector 2 from https://en.bitcoin.it/wiki/BIP_0032_TestVectors START_TEST(test_bip32_vector_2) { - xprv node; + XprvNode node; // init m xprv_from_seed(fromhex("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), 64, &node); From 9da3b35962c4cb4ac5fc90ce7d3c92f02f3e6bda Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 8 Nov 2013 16:02:48 +0100 Subject: [PATCH 051/627] extract xprv_fill_public method --- bip32.c | 13 +++++++++---- bip32.h | 2 ++ ecdsa.c | 2 +- ecdsa.h | 2 +- 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/bip32.c b/bip32.c index 554b101d7..331dc2977 100644 --- a/bip32.c +++ b/bip32.c @@ -14,8 +14,7 @@ void xprv_from_seed(uint8_t *seed, int seed_len, XprvNode *out) // this can be done because private_key[32] and chain_code[32] // form a continuous 64 byte block in the memory hmac_sha512((uint8_t *)"Bitcoin seed", 12, seed, seed_len, out->private_key); - ecdsa_get_public_key33(out->private_key, out->public_key); - ecdsa_get_address(out->public_key, 0, out->address); + xprv_fill_public(out); } void xprv_descent(XprvNode *inout, uint32_t i) @@ -44,6 +43,12 @@ void xprv_descent(XprvNode *inout, uint32_t i) inout->child_num = i; bn_write_be(&a, inout->private_key); - ecdsa_get_public_key33(inout->private_key, inout->public_key); - ecdsa_get_address(inout->public_key, 0, inout->address); + xprv_fill_public(inout); +} + +void xprv_fill_public(XprvNode *xprv) +{ + const uint8_t version = 0x00; + ecdsa_get_public_key33(xprv->private_key, xprv->public_key); + ecdsa_get_address(xprv->public_key, version, xprv->address); } diff --git a/bip32.h b/bip32.h index 417ac8ef6..fe2a28b94 100644 --- a/bip32.h +++ b/bip32.h @@ -20,4 +20,6 @@ void xprv_from_seed(uint8_t *seed, int seed_len, XprvNode *out); void xprv_descent(XprvNode *inout, uint32_t i); +void xprv_fill_public(XprvNode *xprv); + #endif diff --git a/ecdsa.c b/ecdsa.c index 92765e58f..ce2b39021 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -293,7 +293,7 @@ void ecdsa_get_public_key65(const uint8_t *priv_key, uint8_t *pub_key) bn_write_be(&R.y, pub_key + 33); } -void ecdsa_get_address(const uint8_t *pub_key, char version, char *addr) +void ecdsa_get_address(const uint8_t *pub_key, uint8_t version, char *addr) { const char code[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; char *p = addr, s; diff --git a/ecdsa.h b/ecdsa.h index 0aa221bff..cea9749ef 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -35,7 +35,7 @@ int ecdsa_sign(const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig); void ecdsa_get_public_key33(const uint8_t *priv_key, uint8_t *pub_key); void ecdsa_get_public_key65(const uint8_t *priv_key, uint8_t *pub_key); -void ecdsa_get_address(const uint8_t *pub_key, char version, char *addr); +void ecdsa_get_address(const uint8_t *pub_key, uint8_t version, char *addr); int ecdsa_verify(const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, uint32_t msg_len); #endif From 150c770e4eea21729c3c9cbf0f433070314bf966 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 25 Nov 2013 15:37:49 +0100 Subject: [PATCH 052/627] xprvnode -> hdnode, add hdnode_from_pub function --- bip32.c | 35 ++++++++++++++++++++++++++--------- bip32.h | 14 +++++++++----- tests.c | 29 ++++++++++++++--------------- 3 files changed, 49 insertions(+), 29 deletions(-) diff --git a/bip32.c b/bip32.c index 331dc2977..491543215 100644 --- a/bip32.c +++ b/bip32.c @@ -5,7 +5,19 @@ #include "ecdsa.h" #include "bip32.h" -void xprv_from_seed(uint8_t *seed, int seed_len, XprvNode *out) +void hdnode_from_pub(uint32_t version, uint32_t depth, uint32_t fingerprint, uint32_t child_num, uint8_t *chain_code, uint8_t *public_key, HDNode *out) +{ + out->version = version; + out->depth = depth; + out->fingerprint = fingerprint; + out->child_num = child_num; + memcpy(out->chain_code, chain_code, 32); + memcpy(out->public_key, public_key, 33); + memset(out->private_key, 0, 32); + hdnode_fill_address(out, 0x00); +} + +void hdnode_from_seed(uint8_t *seed, int seed_len, HDNode *out) { out->version = 0x0488ADE4; // main-net out->depth = 0; @@ -14,19 +26,20 @@ void xprv_from_seed(uint8_t *seed, int seed_len, XprvNode *out) // this can be done because private_key[32] and chain_code[32] // form a continuous 64 byte block in the memory hmac_sha512((uint8_t *)"Bitcoin seed", 12, seed, seed_len, out->private_key); - xprv_fill_public(out); + hdnode_fill_public_key(out); + hdnode_fill_address(out, 0x00); } -void xprv_descent(XprvNode *inout, uint32_t i) +void hdnode_descent(HDNode *inout, uint32_t i) { uint8_t data[1 + 32 + 4]; bignum256 a, b; - if (i & 0x80000000) { + if (i & 0x80000000) { // private derivation data[0] = 0; memcpy(data + 1, inout->private_key, 32); - } else { - ecdsa_get_public_key33(inout->private_key, data); + } else { // public derivation + memcpy(data, inout->public_key, 33); } write_be(data + 33, i); @@ -43,12 +56,16 @@ void xprv_descent(XprvNode *inout, uint32_t i) inout->child_num = i; bn_write_be(&a, inout->private_key); - xprv_fill_public(inout); + hdnode_fill_public_key(inout); + hdnode_fill_address(inout, 0x00); } -void xprv_fill_public(XprvNode *xprv) +void hdnode_fill_public_key(HDNode *xprv) { - const uint8_t version = 0x00; ecdsa_get_public_key33(xprv->private_key, xprv->public_key); +} + +void hdnode_fill_address(HDNode *xprv, uint8_t version) +{ ecdsa_get_address(xprv->public_key, version, xprv->address); } diff --git a/bip32.h b/bip32.h index fe2a28b94..ef49b950e 100644 --- a/bip32.h +++ b/bip32.h @@ -12,14 +12,18 @@ typedef struct { uint8_t chain_code[32]; // form a continuous 64 byte block uint8_t public_key[33]; char address[35]; -} XprvNode; +} HDNode; -void xprv_from_seed(uint8_t *seed, int seed_len, XprvNode *out); +void hdnode_from_pub(uint32_t version, uint32_t depth, uint32_t fingerprint, uint32_t child_num, uint8_t *chain_code, uint8_t *public_key, HDNode *out); -#define xprv_descent_prime(X, I) xprv_descent((X), ((I) | 0x80000000)) +void hdnode_from_seed(uint8_t *seed, int seed_len, HDNode *out); -void xprv_descent(XprvNode *inout, uint32_t i); +#define hdnode_descent_prime(X, I) hdnode_descent((X), ((I) | 0x80000000)) -void xprv_fill_public(XprvNode *xprv); +void hdnode_descent(HDNode *inout, uint32_t i); + +void hdnode_fill_public_key(HDNode *xprv); + +void hdnode_fill_address(HDNode *xprv, uint8_t version); #endif diff --git a/tests.c b/tests.c index 034387911..d3cc280a8 100644 --- a/tests.c +++ b/tests.c @@ -74,10 +74,10 @@ char *tohex(const uint8_t *bin, size_t l) // test vector 1 from https://en.bitcoin.it/wiki/BIP_0032_TestVectors START_TEST(test_bip32_vector_1) { - XprvNode node; + HDNode node; // init m - xprv_from_seed(fromhex("000102030405060708090a0b0c0d0e0f"), 16, &node); + hdnode_from_seed(fromhex("000102030405060708090a0b0c0d0e0f"), 16, &node); // [Chain m] ck_assert_mem_eq(node.chain_code, fromhex("873dff81c02f525623fd1fe5167eac3a55a049de3d314bb42ee227ffed37d508"), 32); @@ -86,36 +86,35 @@ START_TEST(test_bip32_vector_1) ck_assert_str_eq(node.address, "15mKKb2eos1hWa6tisdPwwDC1a5J1y9nma"); // [Chain m/0'] - xprv_descent_prime(&node, 0); + hdnode_descent_prime(&node, 0); ck_assert_mem_eq(node.chain_code, fromhex("47fdacbd0f1097043b78c63c20c34ef4ed9a111d980047ad16282c7ae6236141"), 32); ck_assert_mem_eq(node.private_key, fromhex("edb2e14f9ee77d26dd93b4ecede8d16ed408ce149b6cd80b0715a2d911a0afea"), 32); ck_assert_mem_eq(node.public_key, fromhex("035a784662a4a20a65bf6aab9ae98a6c068a81c52e4b032c0fb5400c706cfccc56"), 33); ck_assert_str_eq(node.address, "19Q2WoS5hSS6T8GjhK8KZLMgmWaq4neXrh"); // [Chain m/0'/1] - xprv_descent(&node, 1); + hdnode_descent(&node, 1); ck_assert_mem_eq(node.chain_code, fromhex("2a7857631386ba23dacac34180dd1983734e444fdbf774041578e9b6adb37c19"), 32); ck_assert_mem_eq(node.private_key, fromhex("3c6cb8d0f6a264c91ea8b5030fadaa8e538b020f0a387421a12de9319dc93368"), 32); ck_assert_mem_eq(node.public_key, fromhex("03501e454bf00751f24b1b489aa925215d66af2234e3891c3b21a52bedb3cd711c"), 33); ck_assert_str_eq(node.address, "1JQheacLPdM5ySCkrZkV66G2ApAXe1mqLj"); // [Chain m/0'/1/2'] - xprv_descent_prime(&node, 2); + hdnode_descent_prime(&node, 2); ck_assert_mem_eq(node.chain_code, fromhex("04466b9cc8e161e966409ca52986c584f07e9dc81f735db683c3ff6ec7b1503f"), 32); ck_assert_mem_eq(node.private_key, fromhex("cbce0d719ecf7431d88e6a89fa1483e02e35092af60c042b1df2ff59fa424dca"), 32); ck_assert_mem_eq(node.public_key, fromhex("0357bfe1e341d01c69fe5654309956cbea516822fba8a601743a012a7896ee8dc2"), 33); ck_assert_str_eq(node.address, "1NjxqbA9aZWnh17q1UW3rB4EPu79wDXj7x"); // [Chain m/0'/1/2'/2] - xprv_descent(&node, 2); + hdnode_descent(&node, 2); ck_assert_mem_eq(node.chain_code, fromhex("cfb71883f01676f587d023cc53a35bc7f88f724b1f8c2892ac1275ac822a3edd"), 32); ck_assert_mem_eq(node.private_key, fromhex("0f479245fb19a38a1954c5c7c0ebab2f9bdfd96a17563ef28a6a4b1a2a764ef4"), 32); ck_assert_mem_eq(node.public_key, fromhex("02e8445082a72f29b75ca48748a914df60622a609cacfce8ed0e35804560741d29"), 33); ck_assert_str_eq(node.address, "1LjmJcdPnDHhNTUgrWyhLGnRDKxQjoxAgt"); - // [Chain m/0'/1/2'/2/1000000000] - xprv_descent(&node, 1000000000); + hdnode_descent(&node, 1000000000); ck_assert_mem_eq(node.chain_code, fromhex("c783e67b921d2beb8f6b389cc646d7263b4145701dadd2161548a8b078e65e9e"), 32); ck_assert_mem_eq(node.private_key, fromhex("471b76e389e528d6de6d816857e012c5455051cad6660850e58372a6c3e6e7c8"), 32); ck_assert_mem_eq(node.public_key, fromhex("022a471424da5e657499d1ff51cb43c47481a03b1e77f951fe64cec9f5a48f7011"), 33); @@ -126,10 +125,10 @@ END_TEST // test vector 2 from https://en.bitcoin.it/wiki/BIP_0032_TestVectors START_TEST(test_bip32_vector_2) { - XprvNode node; + HDNode node; // init m - xprv_from_seed(fromhex("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), 64, &node); + hdnode_from_seed(fromhex("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), 64, &node); // [Chain m] ck_assert_mem_eq(node.chain_code, fromhex("60499f801b896d83179a4374aeb7822aaeaceaa0db1f85ee3e904c4defbd9689"), 32); @@ -138,35 +137,35 @@ START_TEST(test_bip32_vector_2) ck_assert_str_eq(node.address, "1JEoxevbLLG8cVqeoGKQiAwoWbNYSUyYjg"); // [Chain m/0] - xprv_descent(&node, 0); + hdnode_descent(&node, 0); ck_assert_mem_eq(node.chain_code, fromhex("f0909affaa7ee7abe5dd4e100598d4dc53cd709d5a5c2cac40e7412f232f7c9c"), 32); ck_assert_mem_eq(node.private_key, fromhex("abe74a98f6c7eabee0428f53798f0ab8aa1bd37873999041703c742f15ac7e1e"), 32); ck_assert_mem_eq(node.public_key, fromhex("02fc9e5af0ac8d9b3cecfe2a888e2117ba3d089d8585886c9c826b6b22a98d12ea"), 33); ck_assert_str_eq(node.address, "19EuDJdgfRkwCmRzbzVBHZWQG9QNWhftbZ"); // [Chain m/0/2147483647'] - xprv_descent_prime(&node, 2147483647); + hdnode_descent_prime(&node, 2147483647); ck_assert_mem_eq(node.chain_code, fromhex("be17a268474a6bb9c61e1d720cf6215e2a88c5406c4aee7b38547f585c9a37d9"), 32); ck_assert_mem_eq(node.private_key, fromhex("877c779ad9687164e9c2f4f0f4ff0340814392330693ce95a58fe18fd52e6e93"), 32); ck_assert_mem_eq(node.public_key, fromhex("03c01e7425647bdefa82b12d9bad5e3e6865bee0502694b94ca58b666abc0a5c3b"), 33); ck_assert_str_eq(node.address, "1Lke9bXGhn5VPrBuXgN12uGUphrttUErmk"); // [Chain m/0/2147483647'/1] - xprv_descent(&node, 1); + hdnode_descent(&node, 1); ck_assert_mem_eq(node.chain_code, fromhex("f366f48f1ea9f2d1d3fe958c95ca84ea18e4c4ddb9366c336c927eb246fb38cb"), 32); ck_assert_mem_eq(node.private_key, fromhex("704addf544a06e5ee4bea37098463c23613da32020d604506da8c0518e1da4b7"), 32); ck_assert_mem_eq(node.public_key, fromhex("03a7d1d856deb74c508e05031f9895dab54626251b3806e16b4bd12e781a7df5b9"), 33); ck_assert_str_eq(node.address, "1BxrAr2pHpeBheusmd6fHDP2tSLAUa3qsW"); // [Chain m/0/2147483647'/1/2147483646'] - xprv_descent_prime(&node, 2147483646); + hdnode_descent_prime(&node, 2147483646); ck_assert_mem_eq(node.chain_code, fromhex("637807030d55d01f9a0cb3a7839515d796bd07706386a6eddf06cc29a65a0e29"), 32); ck_assert_mem_eq(node.private_key, fromhex("f1c7c871a54a804afe328b4c83a1c33b8e5ff48f5087273f04efa83b247d6a2d"), 32); ck_assert_mem_eq(node.public_key, fromhex("02d2b36900396c9282fa14628566582f206a5dd0bcc8d5e892611806cafb0301f0"), 33); ck_assert_str_eq(node.address, "15XVotxCAV7sRx1PSCkQNsGw3W9jT9A94R"); // [Chain m/0/2147483647'/1/2147483646'/2] - xprv_descent(&node, 2); + hdnode_descent(&node, 2); ck_assert_mem_eq(node.chain_code, fromhex("9452b549be8cea3ecb7a84bec10dcfd94afe4d129ebfd3b3cb58eedf394ed271"), 32); ck_assert_mem_eq(node.private_key, fromhex("bb7d39bdb83ecf58f2fd82b6d918341cbef428661ef01ab97c28a4842125ac23"), 32); ck_assert_mem_eq(node.public_key, fromhex("024d902e1a2fc7a8755ab5b694c575fce742c48d9ff192e63df5193e4c7afe1f9c"), 33); From 1c9046b66da6faedda6d42d41175a58fec093842 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 25 Nov 2013 22:46:54 +0100 Subject: [PATCH 053/627] reworked bip39 including tests --- bip39.c | 152 ++++++++++++++------------------------------------------ bip39.h | 8 +-- tests.c | 135 +++++++++++++++++++++++++++---------------------- 3 files changed, 117 insertions(+), 178 deletions(-) diff --git a/bip39.c b/bip39.c index f8eb4d403..df12bcec0 100644 --- a/bip39.c +++ b/bip39.c @@ -1,155 +1,77 @@ #include #include "bip39.h" +#include "hmac.h" +#include "rand.h" #include "sha2.h" -#include "aes.h" #include "bip39_english.h" -#define RIJNDAEL_ITERATIONS 10000 +#define HMAC_ROUNDS 10000 -void mnemonic_rijndael(uint8_t *data, int len, char *passphrase, bool encrypt) +const char *mnemonic_generate(int strength) { - if (len != 16 && len != 24 && len != 32) return; - - SHA256_CTX sha_ctx; - aes_ctx ctx; - uint8_t key[32]; int i; - - SHA256_Init(&sha_ctx); - SHA256_Update(&sha_ctx, (uint8_t *)"mnemonic", 8); - if (passphrase) { - SHA256_Update(&sha_ctx, (uint8_t *)passphrase, strlen(passphrase)); - } - SHA256_Final(key, &sha_ctx); - - aes_blk_len(len, &ctx); - - if (encrypt) { - aes_enc_key(key, 32, &ctx); - for (i = 0; i < RIJNDAEL_ITERATIONS; i++) { - aes_enc_blk(data, data, &ctx); - } - } else { - aes_dec_key(key, 32, &ctx); - for (i = 0; i < RIJNDAEL_ITERATIONS; i++) { - aes_dec_blk(data, data, &ctx); - } + static uint32_t data[16]; + if (strength % 32 || strength < 128 || strength > 256) { + return 0; } -} - -#define mnemonic_stretch(D, L, P) mnemonic_rijndael((D), (L), (P), true) -#define mnemonic_unstretch(D, L, P) mnemonic_rijndael((D), (L), (P), false) - -static char mnemo[24 * 10]; -static char bits[256 + 8]; - -char mnemonic_checksum(uint8_t *data, int len) -{ - char r = 0; - int i; - switch (len) { - case 16: // checksum = 4 bits - for (i = 0; i < 16; i++) { - r ^= (data[i] & 0xF0) >> 4; - r ^= (data[i] & 0x0F); - } - break; - case 24: // checksum = 6 bits - for (i = 0; i < 8; i++) { - r ^= (data[3 * i] & 0xFC) >> 2; // xxxxxx__ ________ ________ - r ^= ((data[3 * i] & 0x03) << 4) | ((data[3 * i + 1] & 0xF0) >> 4); // ______xx xxxx____ ________ - r ^= ((data[3 * i + 1] & 0x0F) << 2) | ((data[3 * i + 2] & 0xC0) >> 6); // ________ ____xxxx xx______ - r ^= data[3 * i + 2] & 0x3F; // ________ ________ __xxxxxx - } - break; - case 32: // checksum = 8 bits - for (i = 0; i < 32; i++) { - r ^= data[i]; - } - break; + for (i = 0; i < 16; i++) { + data[i] = random32(); } - return r; + return mnemonic_from_data((const uint8_t *)data, strength / 8); } -const char *mnemonic_encode(uint8_t *data, int len, char *passphrase) +const char *mnemonic_from_data(const uint8_t *data, int len) { - if (len != 16 && len != 24 && len != 32) return 0; + int i, j; + static uint8_t hash[32]; + static char bits[256 + 8]; + static char mnemo[24 * 10]; - mnemonic_stretch(data, len, passphrase); + SHA256_Raw((const uint8_t *)data, len, hash); - int i, j; for (i = 0; i < len; i++) { for (j = 0; j < 8; j++) { bits[8 * i + j] = (data[i] & (1 << (7 - j))) > 0; } } - char checksum = mnemonic_checksum(data, len); - for (j = 0; j < (len/4); j++) { - bits[8 * len + j] = (checksum & (1 << ((len / 4 - 1) - j))) > 0; + char hlen = len / 4; + for (i = 0; i < hlen; i++) { + char c = (hash[0] & (1 << (7 - i))) > 0; + bits[8 * len + i] = c; } - len = len * 3 / 4; + int mlen = len * 3 / 4; + char *p = mnemo; - for (i = 0; i < len; i++) { + for (i = 0; i < mlen; i++) { int idx = 0; for (j = 0; j < 11; j++) { idx += bits[i * 11 + j] << (10 - j); } strcpy(p, wordlist[idx]); p += strlen(wordlist[idx]); - *p = (i < len - 1) ? ' ' : 0; + *p = (i < mlen - 1) ? ' ' : 0; p++; } return mnemo; } -int wordlist_index(const char *word) +void mnemonic_to_seed(const char *mnemonic, const char *passphrase, uint8_t *seed) { - int i = 0; - while (wordlist[i]) { - if (strcmp(word, wordlist[i]) == 0) return i; - i++; + static uint8_t k[8 + 256]; + uint8_t *m = seed; + int i, kl; + + kl = strlen(passphrase); + memcpy(k, "mnemonic", 8); + memcpy(k + 8, passphrase, kl); + kl += 8; + + hmac_sha512(k, kl, (const uint8_t *)mnemonic, strlen(mnemonic), m); + for (i = 1; i < HMAC_ROUNDS; i++) { + hmac_sha512(k, kl, m, 512 / 8, m); } - return -1; -} - -int mnemonic_decode(const char *mnemonic, uint8_t *data, char *passphrase) -{ - strcpy(mnemo, mnemonic); - - int i, j, b = 0, len; - char *p = strtok(mnemo, " "); - while (p) { - int idx = wordlist_index(p); - if (idx < 0 || idx > 2047) return 0; - for (j = 0; j < 11; j++) { - bits[b] = (idx & (1 << (10 - j))) > 0; - b++; - } - p = strtok(NULL, " "); - } - if (b != 128 + 4 && b != 192 + 6 && b != 256 + 8) return 0; - - len = b / 33 * 4; - - for (i = 0; i < len; i++) { - data[i] = 0; - for (j = 0; j < 8; j++) { - data[i] |= bits[8 * i + j] << (7 - j); - } - } - char checksum = 0; - for (j = 0; j < (len/4); j++) { - checksum |= bits[8 * len + j] << ((len / 4 - 1) - j); - } - if (checksum != mnemonic_checksum(data, len)) { - return 0; - } - - mnemonic_unstretch(data, len, passphrase); - - return len; } diff --git a/bip39.h b/bip39.h index 34fbf62fc..5e862cd29 100644 --- a/bip39.h +++ b/bip39.h @@ -1,11 +1,13 @@ #ifndef __BIP39_H__ #define __BIP39_H__ -#include #include -const char *mnemonic_encode(uint8_t *data, int len, char *passphrase); -int mnemonic_decode(const char *mnemonic, uint8_t *data, char *passphrase); +const char *mnemonic_generate(int strength); // strength in bits + +const char *mnemonic_from_data(const uint8_t *data, int len); + +void mnemonic_to_seed(const char *mnemonic, const char *passphrase, uint8_t *seed); #endif diff --git a/tests.c b/tests.c index d3cc280a8..4b0730212 100644 --- a/tests.c +++ b/tests.c @@ -68,8 +68,8 @@ char *tohex(const uint8_t *bin, size_t l) ck_assert_msg(0 OP memcmp(_ck_y, _ck_x, _ck_l), \ "Assertion '"#X#OP#Y"' failed: "#X"==\"%s\"", tohex(_ck_x, _ck_l)); \ } while (0) -#define ck_assert_mem_eq(X, Y, L) _ck_assert_mem(X, Y, L, ==) -#define ck_assert_mem_ne(X, Y, L) _ck_assert_mem(X, Y, L, !=) +#define ck_assert_mem_eq(X, Y, L) _ck_assert_mem((X), (Y), (L), ==) +#define ck_assert_mem_ne(X, Y, L) _ck_assert_mem((X), (Y), (L), !=) // test vector 1 from https://en.bitcoin.it/wiki/BIP_0032_TestVectors START_TEST(test_bip32_vector_1) @@ -294,79 +294,94 @@ START_TEST(test_mnemonic) { static const char *vectors[] = { "00000000000000000000000000000000", - "risk tiger venture dinner age assume float denial penalty hello game wing", + "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about", + "6ca6a10baeaeff4b9b2e0dbc9f880dd8428c61168caa8cdf57234e87b7ace148ee4531ef37d518439c42392ee3878f74efec1d677b0327bca7378bfd009722a1", "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", - "truth chase learn pretty right casual acoustic frozen betray main slogan method", + "legal winner thank year wave sausage worth useful legal winner thank yellow", + "f0eee1f28591edfad85f47ccd64f1ba18c9b3d31d5c28bf05f296f323ffd22c94edfdbe9494a094d96e8099adb80cdcc4e6b564e04ee38515d35b3d6fb9b91be", "80808080808080808080808080808080", - "olive garment twenty drill people finish hat own usual level milk usage", + "letter advice cage absurd amount doctor acoustic avoid letter advice cage above", + "14949034b83876cc10b4624c2f7489499c68df72aeea503195ef2cb1686c1767fe41b854fbb0ac2596e4ba8235c27395297039578d5e7b4921e5bf7eafe28a27", "ffffffffffffffffffffffffffffffff", - "laundry faint system client frog vanish plug shell slot cable large embrace", + "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong", + "d430f6f2fd8573c2aac937cb5eb88486cce4fd06a4c632bc58b8b24f60697e2a158e3e51290360175b38c71ca90971cbcfa26049c1cb14f3d44e031d8d18e634", "000000000000000000000000000000000000000000000000", - "giant twelve seat embark ostrich jazz leader lunch budget hover much weapon vendor build truth garden year list", + "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon agent", + "6836b4fb07e82f99f157d5abec7a6bc3fae25e6aaed44b547b6e64d9bfae955cde245db6b06decb2429b5c5f849563108d7f799734b6cfb86f797c1c74d20cca", "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", - "awful faint gun mean fuel side slogan marine glad donkey velvet oyster movie real type digital dress federal", + "legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal will", + "6b5d7995263e58421531e0c9c4084c0d5738bc2eef5306cc267e496f263256aa93f0adb51ab92b26bfaf00d448e896f8564fca91e66b7cfb2ac2c7cb1e59cb0f", "808080808080808080808080808080808080808080808080", - "bless carpet daughter animal hospital pave faculty escape fortune song sign twin unknown bread mobile normal agent use", + "letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter always", + "f3e672575342c0c0544593f76706214ab6e78098e9632b979807b1d3e0632fee8661146f740289036a831311b4e28c11601d29aec0e52ca4ee19476a0e03231e", "ffffffffffffffffffffffffffffffffffffffffffffffff", - "saddle curve flight drama client resemble venture arch will ordinary enrich clutch razor shallow trophy tumble dice outer", + "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo when", + "1a4e1e5532e8d34da0c4e225745840af7f80b6e22adf9443b424965deeab3e287a45f4ccfbc6b0a4ae9945bfd0eccef65ddb05115ff6829f051cb58e2ce02227", "0000000000000000000000000000000000000000000000000000000000000000", - "supreme army trim onion neglect coach squirrel spider device glass cabbage giant web digital floor able social magnet only fork fuel embrace salt fence", + "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon art", + "aae9cdd3667c7ab3169bc755c868f65980ae5cc02ab57fcea08e43b3d1652c4da748dfcaacc707f146e785e0c75fdd2935c99db986703a24ffc5961158f67c23", "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", - "cloth video uncle switch year captain artist country adjust edit inherit ocean tennis soda baby express hospital forest panel actual profit boy spice elite", + "legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth title", + "217b6d8b54552deb05701e1f7478431f528e82e590bf68cd8c6236fb9c2fa16bbb9d759fa68cb8e3f17a0525596de2c645aee8a2b0b071d78411d2147fdef443", "8080808080808080808080808080808080808080808080808080808080808080", - "fence twin prize extra choose mask twist deny cereal quarter can power term ostrich leg staff nature nut swift sausage amateur aim script wisdom", + "letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic bless", + "d5432ff9f0a0dc85373635a658056b04b8ad96069c79c953151de03496c81f772301acbd1b4bc87f0ef07fdcf070ea7384c1c86ec324fab11ac8851d7bc7122f", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "moon fiscal evidence exile rifle series neglect giant exclude banana glance frown kangaroo globe turtle hat fitness casual sudden select idle arctic best unlock", - "449ea2d7249c6e0d8d295424fb8894cf", - "choice barrel artefact cram increase sell veteran matrix mirror hollow walk pave", - "75fc3f44a7ff8e2b8af05aa18bded3827a3796df406763dd", - "crack outside teach chat praise client manual scorpion predict chalk decrease casino lunch garbage enable ball when bamboo", - "1cce2f8c2c6a7f2d8473ebf1c32ce13b36737835d7a8768f44dcf96d64782c0e", - "muffin evoke all fiber night guard black quote neck expire dial tenant leisure have dragon neck notable peace captain insane nice uphold shine angry", - "3daa82dd08bd144ec9fb9f77c6ece3d2", - "foil dawn net enroll turtle bird vault trumpet service fun immune unveil", - "9720239c0039f8446d44334daec325f3c24b3a490315d6d9", - "damp all desert dash insane pear debate easily soup enough goddess make friend plug violin pact wealth insect", - "fe58c6644bc3fad95832d4400cea0cce208c8b19bb4734a26995440b7fae7600", - "wet sniff asthma once gap enrich pumpkin define trust rude gesture keen grass fine emerge census immense smooth ritual spirit rescue problem beef choice", - "99fe82c94edadffe75e1cc64cbd7ada7", - "thing real emerge verify domain cloud lens teach travel radio effort glad", - "4fd6e8d06d55b4700130f8f462f7f9bfc6188da83e3faadb", - "diary opinion lobster code orange odor insane permit spirit evolve upset final antique grant friend dutch say enroll", - "7a547fb59606e89ba88188013712946f6cb31c3e0ca606a7ee1ff23f57272c63", - "layer owner legal stadium glance oyster element spell episode eager wagon stand pride old defense black print junior fade easy topic ready galaxy debris", - "e5fc62d20e0e5d9b2756e8d4d91cbb80", - "flat make unit discover rifle armed unit acquire group panel nerve want", - "d29be791a9e4b6a48ff79003dbf31d6afabdc4290a273765", - "absurd valve party disorder basket injury make blanket vintage ancient please random theory cart retire odor borrow belt", - "c87c135433c16f1ecbf9919dc53dd9f30f85824dc7264d4e1bd644826c902be2", - "upper will wisdom term once bean blur inquiry used bamboo frequent hamster amazing cake attack any author mimic leopard day token joy install company", + "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo vote", + "faed83f0823ee9958d35e9514b497729776f675ce5ce7a14d1ab47efc70d71bc7bad208c3df16ab0cce19ec2ad115fe78c93d4245028f82215c0d278616c07e7", + "b4950b98f22cdff09bd809960771012b", + "region portion tower tone social weapon hunt abuse noodle describe doctor fit", + "8917cbe312d2122616df35a4f92cc81c67063200acd2ac530502e28d01e9247b6e6c87495ead957733001096b6679ff9a63f762f07a07f9834cac326f7249926", + "e4dcab3716ef913118a8d51675c7ce8b460b5d33587c4bad", + "tooth torch soccer column weekend obtain glance boy biology purchase victory bird gaze purse sniff auto entry hundred", + "dc645f9c8d11ee5b372993b710540c59bdc4693b253dd207998811df4fbcbce711247361582a9042482a445a2123be514a2602913b5984336271879d1c36bc55", + "7874365a015417bf86b2e6e68c4fb332afcaf344ac1c5b514869bdc4503f07f5", + "journey payment notable actor door thank bracket fresh track give under grab witness keen bargain logic forget medal bounce knee eagle buzz cabin salute", + "fe49079843bb0461496faeafd6c6e18e058c6b54403d085616863bca32a8a3ec59bca20c4f68e5f300098faf7cf592e52493ee358add5161befeef601a0984b9", + "dd36b9581bef791e27dea2349d99f111", + "tag remind figure daughter wasp monitor panda stairs cruel under labor carry", + "db8870c20d22f8fd43baf8675a30567745b908c56404b65da6b940b89dee1623a207385073da5931e202006971eb0460f0c86da7be233917fde24137a5d0b4c7", + "f268b3d9a0504f7a93602f58aca5e3b296a386d1b867a271", + "venue easily wait doll agent run eternal album flavor gown jump gown health sell eight artefact pen melody", + "f4afc4679667969b2a051e530c10bda028fc66fecdf6db416f6e5b834bfd26314591f3303a6f0a607fbeb0b7072a42fde064d76d362c796284107656981ad1d2", + "575fab7f9a24cb9edd664541d491349ba1ee64ca3982ffaf0d951ffb3c03b104", + "firm wool that crowd erosion sorry intact silly dove pig essay dance bus crash cigar core zero journey grab divide record achieve series outdoor", + "000607026976a77b840eb314461bb8799ece12ce4844c452c39b6d94aa8c9f8f55f668786099add17a32e63338576316c93161e350ec9726d2384aa2d5ea884e", + "7499a884c8dc8d854996a42046764af7", + "innocent snap cancel museum silver section chaos stand cake crisp naive until", + "0a256d3cd41423b084717335a43b58ff522a41f254448304e6b80f572b09e5709dfd88ba190c43aef3b4366016212e67d85e7f48d91c2b37306ba6792f779652", + "4b87f573b3710d6551115c148698974849caeaef46baf41a", + "entire distance friend group awkward razor dust clog behind crumble chair mountain original install rug struggle village spice", + "cbe978501edc014868011032069d730947a1a37f305ad401847796c157f9039d322a0b8ba5c4e34b6ea6ea90b408249e960df501685ae720ed1d78dc8495b682", + "1eb272608649d7ca5118174f6c71bb5a9684af1dd9159a9707803c5df8c6a229", + "burger near oblige arrive output topple dutch actual exhaust glory human release hair fiscal jazz cargo once return theme judge test globe master clerk", + "7dcdf57089ca467e023bcb6d97872317b9c3b120b6363d7986a95d42555e1036f914f4f19c2f381e346d24cfa5204f8cbe6b96146f39012b0740ce5ae21e625b", + "b45c6ab5b78e98d0ec2b8cb77cf2eecb", + "reform today pulp humor trumpet half radar immense resist travel roof nurse", + "5118a62d70721d83e5525e7fdef5f049843900a60bc6bdc408feb0104f9fd5237000f166b811de432c27011a739578d8f9266d2882b290345ee04dae908d77d4", + "3b80180f9abebbbf9a45c5620dc711426c1a3b0ede191608", + "describe absorb advance cube two thank harbor reward ginger hotel session luggage script budget derive segment bid early", + "80c58137ee8a3f0fae6d4bc2ea366f95929efe2fba063a676ea7559a383c38d1cdd5a04dd09bc29c21bf7334b3f492d6b7ce0f3ba5e78ef06337f2056aacc11b", + "1fdc34f4457c1adddb0ff2de01b92817f4ffe7c82bef6719e4742a54d0463efc", + "cabin ticket dial memory script humble history wrestle task assist energy copper exit view camera law grow song brown feed escape cart winner maple", + "eae75edd758d1b65e317d15682ce76d6625251ab618dbbce179caa3aaf29e4f88e0ab97cd070c80b480bad3d50cfc458005a06949ab31d8702f95f6863eae176", + 0, 0, 0, }; - const char **d, **s, *m; - - // check encode - d = vectors; - s = vectors + 1; - while (*d && *s) { - m = mnemonic_encode(fromhex(*d), strlen(*d) / 2, 0); - ck_assert_ptr_ne(m, 0); - ck_assert_str_eq(m, *s); - d += 2; s += 2; - } - - // check decode - d = vectors; - s = vectors + 1; - uint8_t data[32]; - int len; - while (*d && *s) { - len = mnemonic_decode(*s, data, 0); - ck_assert_int_eq(len, strlen(*d) / 2); - ck_assert_mem_eq(fromhex(*d), data, len); - d += 2; s += 2; + const char **a, **b, **c, *m; + uint8_t seed[64]; + + a = vectors; + b = vectors + 1; + c = vectors + 2; + while (*a && *b && *c) { + m = mnemonic_from_data(fromhex(*a), strlen(*a) / 2); + ck_assert_str_eq(m, *b); + mnemonic_to_seed(m, "", seed); + ck_assert_mem_eq(seed, fromhex(*c), strlen(*c) / 2); + a += 3; b += 3; c += 3; } } END_TEST From 69392753629f38df0a42414e7fe1be1a164e1143 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 25 Nov 2013 23:06:02 +0100 Subject: [PATCH 054/627] use TREZOR as passphrase to check protection --- tests.c | 98 ++++++++++++++++++++++++++++----------------------------- 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/tests.c b/tests.c index 4b0730212..74d2c123b 100644 --- a/tests.c +++ b/tests.c @@ -295,76 +295,76 @@ START_TEST(test_mnemonic) static const char *vectors[] = { "00000000000000000000000000000000", "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about", - "6ca6a10baeaeff4b9b2e0dbc9f880dd8428c61168caa8cdf57234e87b7ace148ee4531ef37d518439c42392ee3878f74efec1d677b0327bca7378bfd009722a1", + "cb5e7230ce8229de990674f6aa4288325fd4d8181f761734bd8b5cc944fedc2a4300e64422864b565352de7ffbc5ad0fafdf5344489f3a83e4a4bb5271cafaae", "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", "legal winner thank year wave sausage worth useful legal winner thank yellow", - "f0eee1f28591edfad85f47ccd64f1ba18c9b3d31d5c28bf05f296f323ffd22c94edfdbe9494a094d96e8099adb80cdcc4e6b564e04ee38515d35b3d6fb9b91be", + "de1277934939d6969519f44b7b3757a905d7f635be41e1e88022c346bc52ad26c0a3e9578e73e9b89066873266f285a5891d27d28cb27fccfe26d92bbd7ee364", "80808080808080808080808080808080", "letter advice cage absurd amount doctor acoustic avoid letter advice cage above", - "14949034b83876cc10b4624c2f7489499c68df72aeea503195ef2cb1686c1767fe41b854fbb0ac2596e4ba8235c27395297039578d5e7b4921e5bf7eafe28a27", + "8863bccef9cfffeacef1e4c6fc97bba8227ab0fc7e8e162be7467282689a13521ea364d7c4bc8cd241b59f53c5147a89c18a47248a96592ab9a2c1f1870b026c", "ffffffffffffffffffffffffffffffff", "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong", - "d430f6f2fd8573c2aac937cb5eb88486cce4fd06a4c632bc58b8b24f60697e2a158e3e51290360175b38c71ca90971cbcfa26049c1cb14f3d44e031d8d18e634", + "7a29e57c7a1532af1bddb7e02b892cfccc6a57b74fe9784324ea89fab8a66dc64fde79c31166b159685116f4e93c1795496f20ffdc2d3a69d3439931dabde86e", "000000000000000000000000000000000000000000000000", "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon agent", - "6836b4fb07e82f99f157d5abec7a6bc3fae25e6aaed44b547b6e64d9bfae955cde245db6b06decb2429b5c5f849563108d7f799734b6cfb86f797c1c74d20cca", + "c3e382025b6a22a901505cf393faea450eb6c4a5f2a8c8f0596285b2bd84688877a6cc7231420e2bbdd2428e62ed549a78fa215b3adafd8dea075dabfc704d5e", "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", "legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal will", - "6b5d7995263e58421531e0c9c4084c0d5738bc2eef5306cc267e496f263256aa93f0adb51ab92b26bfaf00d448e896f8564fca91e66b7cfb2ac2c7cb1e59cb0f", + "c82666e40eb097bf6eb05fecd7dc2ddfb6bbdc6071900f4b3fd3c3e635db69aa2094f1f450c98e8dc6103aa72df635abdfcc3b6d6ec5261a9208a07a35a3f1c8", "808080808080808080808080808080808080808080808080", "letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter always", - "f3e672575342c0c0544593f76706214ab6e78098e9632b979807b1d3e0632fee8661146f740289036a831311b4e28c11601d29aec0e52ca4ee19476a0e03231e", + "e90681c67c55504afadca009ce4042819341fa0e90300b6d32b4f2e8e8a6678ff7e7fc1da663ae194dc7a2ef7ec7b50112d1a5efce47bfd00c66eec82f2265b5", "ffffffffffffffffffffffffffffffffffffffffffffffff", "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo when", - "1a4e1e5532e8d34da0c4e225745840af7f80b6e22adf9443b424965deeab3e287a45f4ccfbc6b0a4ae9945bfd0eccef65ddb05115ff6829f051cb58e2ce02227", + "2a372547df962742942674170a7cef495ea0b97f4864de16d0f3ee82eb577ca1eca345e601cc2df7c626c5bc51c52c28a3b4294224b685c958c7450bee6769e6", "0000000000000000000000000000000000000000000000000000000000000000", "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon art", - "aae9cdd3667c7ab3169bc755c868f65980ae5cc02ab57fcea08e43b3d1652c4da748dfcaacc707f146e785e0c75fdd2935c99db986703a24ffc5961158f67c23", + "58cb9c5555d67ecc7b32305a78d1a2fcf0c9b22f1af761cfafc65eb1d3909f63ee2cab84996a7478cfd3e864cda5efb0caf580d56cf49739c6b3638d94e758c1", "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", "legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth title", - "217b6d8b54552deb05701e1f7478431f528e82e590bf68cd8c6236fb9c2fa16bbb9d759fa68cb8e3f17a0525596de2c645aee8a2b0b071d78411d2147fdef443", + "0093cb3ed6d1302d3cf498017f8cb1c7dc2fdbd62ec57fc49e4b2a4dd47a23e44e0b309517d5a3e7b0f4f0ef0ed132818cf120a098a92e572ad086f1a90ccb7f", "8080808080808080808080808080808080808080808080808080808080808080", "letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic bless", - "d5432ff9f0a0dc85373635a658056b04b8ad96069c79c953151de03496c81f772301acbd1b4bc87f0ef07fdcf070ea7384c1c86ec324fab11ac8851d7bc7122f", + "8a21e46b9d264328c63e707e3d38ed4eb21508deda309fa2ef57cc8eca8b351ca3018758844ba9fb5851bab15d026a61cabace53a9a39bc91dc2c51407542cf5", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo vote", - "faed83f0823ee9958d35e9514b497729776f675ce5ce7a14d1ab47efc70d71bc7bad208c3df16ab0cce19ec2ad115fe78c93d4245028f82215c0d278616c07e7", - "b4950b98f22cdff09bd809960771012b", - "region portion tower tone social weapon hunt abuse noodle describe doctor fit", - "8917cbe312d2122616df35a4f92cc81c67063200acd2ac530502e28d01e9247b6e6c87495ead957733001096b6679ff9a63f762f07a07f9834cac326f7249926", - "e4dcab3716ef913118a8d51675c7ce8b460b5d33587c4bad", - "tooth torch soccer column weekend obtain glance boy biology purchase victory bird gaze purse sniff auto entry hundred", - "dc645f9c8d11ee5b372993b710540c59bdc4693b253dd207998811df4fbcbce711247361582a9042482a445a2123be514a2602913b5984336271879d1c36bc55", - "7874365a015417bf86b2e6e68c4fb332afcaf344ac1c5b514869bdc4503f07f5", - "journey payment notable actor door thank bracket fresh track give under grab witness keen bargain logic forget medal bounce knee eagle buzz cabin salute", - "fe49079843bb0461496faeafd6c6e18e058c6b54403d085616863bca32a8a3ec59bca20c4f68e5f300098faf7cf592e52493ee358add5161befeef601a0984b9", - "dd36b9581bef791e27dea2349d99f111", - "tag remind figure daughter wasp monitor panda stairs cruel under labor carry", - "db8870c20d22f8fd43baf8675a30567745b908c56404b65da6b940b89dee1623a207385073da5931e202006971eb0460f0c86da7be233917fde24137a5d0b4c7", - "f268b3d9a0504f7a93602f58aca5e3b296a386d1b867a271", - "venue easily wait doll agent run eternal album flavor gown jump gown health sell eight artefact pen melody", - "f4afc4679667969b2a051e530c10bda028fc66fecdf6db416f6e5b834bfd26314591f3303a6f0a607fbeb0b7072a42fde064d76d362c796284107656981ad1d2", - "575fab7f9a24cb9edd664541d491349ba1ee64ca3982ffaf0d951ffb3c03b104", - "firm wool that crowd erosion sorry intact silly dove pig essay dance bus crash cigar core zero journey grab divide record achieve series outdoor", - "000607026976a77b840eb314461bb8799ece12ce4844c452c39b6d94aa8c9f8f55f668786099add17a32e63338576316c93161e350ec9726d2384aa2d5ea884e", - "7499a884c8dc8d854996a42046764af7", - "innocent snap cancel museum silver section chaos stand cake crisp naive until", - "0a256d3cd41423b084717335a43b58ff522a41f254448304e6b80f572b09e5709dfd88ba190c43aef3b4366016212e67d85e7f48d91c2b37306ba6792f779652", - "4b87f573b3710d6551115c148698974849caeaef46baf41a", - "entire distance friend group awkward razor dust clog behind crumble chair mountain original install rug struggle village spice", - "cbe978501edc014868011032069d730947a1a37f305ad401847796c157f9039d322a0b8ba5c4e34b6ea6ea90b408249e960df501685ae720ed1d78dc8495b682", - "1eb272608649d7ca5118174f6c71bb5a9684af1dd9159a9707803c5df8c6a229", - "burger near oblige arrive output topple dutch actual exhaust glory human release hair fiscal jazz cargo once return theme judge test globe master clerk", - "7dcdf57089ca467e023bcb6d97872317b9c3b120b6363d7986a95d42555e1036f914f4f19c2f381e346d24cfa5204f8cbe6b96146f39012b0740ce5ae21e625b", - "b45c6ab5b78e98d0ec2b8cb77cf2eecb", - "reform today pulp humor trumpet half radar immense resist travel roof nurse", - "5118a62d70721d83e5525e7fdef5f049843900a60bc6bdc408feb0104f9fd5237000f166b811de432c27011a739578d8f9266d2882b290345ee04dae908d77d4", - "3b80180f9abebbbf9a45c5620dc711426c1a3b0ede191608", - "describe absorb advance cube two thank harbor reward ginger hotel session luggage script budget derive segment bid early", - "80c58137ee8a3f0fae6d4bc2ea366f95929efe2fba063a676ea7559a383c38d1cdd5a04dd09bc29c21bf7334b3f492d6b7ce0f3ba5e78ef06337f2056aacc11b", - "1fdc34f4457c1adddb0ff2de01b92817f4ffe7c82bef6719e4742a54d0463efc", - "cabin ticket dial memory script humble history wrestle task assist energy copper exit view camera law grow song brown feed escape cart winner maple", - "eae75edd758d1b65e317d15682ce76d6625251ab618dbbce179caa3aaf29e4f88e0ab97cd070c80b480bad3d50cfc458005a06949ab31d8702f95f6863eae176", + "5c8a1a284ab2844daf02cab322df3996574c9d53cbd36159c493441990f0d2a6bc9bc1502e3a067943d8ec67324663cbfb9667b57fed220e3f28335e26a90f93", + "1083fa24dbb0afa4e7b327d23f666567", + "awesome cabin matrix resist april sponsor paddle gossip split will off soon", + "467406b36a0176e40e013393e5ecef1f5b4019980b502eda9db1db06f7786e088b206f045f2bfcf93bd3b17a598335b078fcc5890115857ff741bd154b54f049", + "d8cbcd1ac2153ecd74048480c2732f637d642b21f0dd40df", + "sugar fury effort loud fault grit source mountain liar bean slim shoulder stone better march brick dolphin zero", + "f60180ea5047659cbb17ed6ef79c974de86c0170c7a1962b205329eb8fe9dcdd148615d35c515c4ec8da25f4cf54d5b7cd8cd5bf8dc4059df3a7900ca25f8306", + "2952f95cefe041616f6f379ab649cf8b702ecf8e4acceaebdda4cc50e2bf1d7b", + "citizen oak fire thank advice radar sad tragic one rather initial black actual guitar decrease flower turtle galaxy hard obvious athlete garbage invest have", + "eff4b6a15bb55fcf4bbfa2b3b9e24e7dc4bed8319ef7703f1786d472c73666922925778eaa5a06f8a26d2c7e7240be746fd69edfaf197e0dae12d7e0b550cfc8", + "f5e82717078a6ddc538a03e825f91bed", + "vote donkey shift audit plug until evolve document trial cool eight swarm", + "83dad22293225780a914083fc1a69bfe1d910f5b5962b0364820132a42ae1bd567a1fb4d5a19ad3d64539e38a7ee3d6429fac2b74e72b020913131c5eadb7db4", + "16b59b6a426f2f302f73049a32ab8572394278982212357a", + "birth proud surround luggage very object saddle gauge olive next throw tongue neither detail gauge drastic cube strategy", + "38ceb07e0dad221f612631843be6ae44a650aaf789c8ebea9313e07498d7864385227d25c7a8268a5b850367eef31639632e9218acadead20980b864b1cd477e", + "95b6cb48c7bc9c2a54496ae3eea790824b57e52b9637058f084555bc1b809b2f", + "noble rent split month six benefit eye coil token inside tomorrow afraid rely verb purity shoulder airport joke bacon problem script scare hole trumpet", + "e33e3d32e467877596a18ac60050488a0ec1557fda6bf95bad3d33d964c5e99dcd97d378403cc2723ed1c85c12b42bc59f15458d970d7a9d015f556109c146b0", + "7f93397f750f70a26513de2732ed95ee", + "legend oil garlic tube warfare eye nephew knock cheese number grace tackle", + "7f92ad63e4cdf4f15c23740556ad81e7f8cbd67cc672c93894c9c0d4fb171539eed5ab29f366570ed9940b816f45a539c3816f7ac19511794b752c5c1ec0e732", + "14c29fe840dd1c9f05d392ba13e4e1466b32ed0726a15f89", + "below belt wheel like spike exhibit blanket inch ring palace debate mimic rebel isolate broken stage garbage enhance", + "7bae6e54f8bad645f18f574b310bd3e6fde126dabcaf63a889940380e4798810e48c8151fc56bb2389c07498deacef025f03cbf8fc57ea3ec68f6421b0fcb649", + "cb30610d175ffeab8357d5190d31923997752a7f9815087bfcad5eb0b43f6468", + "sleep loan drive concert zoo fiction ask wide boil hat goose industry jar news wrist actor anchor that clip runway area cabbage museum abuse", + "b922030609e7626696b9cf5ca4c06cd99290be30b1052770f6a60c5f26532d178f287a4285d7a2add2845dc89a816b26fdba1c830067d130740f64c0ab5cfbe1", + "a30b50a5439dcd1774f412ea5ec33403", + "perfect fold citizen mango system merry stable liquid tumble voyage snack alter", + "aae175f26848370c4d5d3d0640597e2bf1b28e95908dd877259b3eac5d71ffe3140739a3ed80180f88159571df84441985620e6b2fb0696e5cba1aa7b8d10b98", + "70044da2175ad681d0ebbf2da83cf407eb9c8fd91fc0a8c9", + "hybrid carbon hammer concert pulp domain dry jewel color draft dial average right elevator good way potato energy", + "a3dffe3a31a2e949d1b04af7495a5b59db17e41d93b985feeaaae89260a9c86c6dcdf7cb32eaba61c2f4f0340f0f17d1ebb67af11657286b2ffd66ec4e05a8b7", + "0e0bab4df9669b97ba3f75a50b2e92423bbe6e91a1b01dbbf3ba200a917c9106", + "asthma front square version have slim trophy upgrade pink floor pig love room dance educate current buffalo test update divorce poverty salad dune scheme", + "2eb4d85fbd8deaf9b06bf9cdb3e5f36e8da040d110312075eb32e776fc8e505b94be3e63c1525ad41f5e5968a263853001dc7c40ea3af8e8b0cfb7effd5f408c", 0, 0, 0, @@ -379,7 +379,7 @@ START_TEST(test_mnemonic) while (*a && *b && *c) { m = mnemonic_from_data(fromhex(*a), strlen(*a) / 2); ck_assert_str_eq(m, *b); - mnemonic_to_seed(m, "", seed); + mnemonic_to_seed(m, "TREZOR", seed); ck_assert_mem_eq(seed, fromhex(*c), strlen(*c) / 2); a += 3; b += 3; c += 3; } From e04ec2a831cdbea0a95d8076e175f1044bc94a98 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 26 Nov 2013 01:29:06 +0100 Subject: [PATCH 055/627] add check to mnemonic_from_data as well --- bip39.c | 4 ++++ secp256k1.c | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/bip39.c b/bip39.c index df12bcec0..7392d9f2e 100644 --- a/bip39.c +++ b/bip39.c @@ -28,6 +28,10 @@ const char *mnemonic_from_data(const uint8_t *data, int len) static char bits[256 + 8]; static char mnemo[24 * 10]; + if (len % 4 || len < 16 || len > 32) { + return 0; + } + SHA256_Raw((const uint8_t *)data, len, hash); for (i = 0; i < len; i++) { diff --git a/secp256k1.c b/secp256k1.c index cbed98888..57a5a8677 100644 --- a/secp256k1.c +++ b/secp256k1.c @@ -34,7 +34,7 @@ const bignum256 order256k1 = { .val = {0x10364141, 0x3f497a33, 0x348a03bb, 0x2bb739ab, 0x3ffffeba, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0xffff}}; const bignum256 order256k1_half = { -.val = {0x281b20a0, 0x3fa4bd19, 0x3a4501dd, 0x15db9cd5, 0x3fffff5d, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x00007fff}}; +.val = {0x281b20a0, 0x3fa4bd19, 0x3a4501dd, 0x15db9cd5, 0x3fffff5d, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x7fff}}; const bignum256 three_over_two256k1 = { .val = {0x3ffffe19, 0x3ffffffd, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x7fff}}; From 6b66f29c3bbb028825c40686db81efd898c55c22 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 28 Nov 2013 00:52:39 +0100 Subject: [PATCH 056/627] use fixed block size (128-bit) for AES again --- aes.h | 2 +- tests.c | 13 ++++++------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/aes.h b/aes.h index 724111956..687d7ad3a 100644 --- a/aes.h +++ b/aes.h @@ -55,7 +55,7 @@ version that provides variable block length is compiled. */ -// #define BLOCK_SIZE 16 +#define BLOCK_SIZE 16 /* key schedule length (in 32-bit words) */ diff --git a/tests.c b/tests.c index 74d2c123b..1b35dba7e 100644 --- a/tests.c +++ b/tests.c @@ -264,7 +264,6 @@ END_TEST #define test_aes(KEY, BLKLEN, IN, OUT) do { \ SHA256_Raw((uint8_t *)KEY, strlen(KEY), key); \ - aes_blk_len(BLKLEN, &ctx); \ aes_enc_key(key, 32, &ctx); \ memcpy(in, fromhex(IN), BLKLEN); \ aes_enc_blk(in, out, &ctx); \ @@ -277,16 +276,16 @@ START_TEST(test_rijndael) uint8_t key[32], in[32], out[32]; test_aes("mnemonic", 16, "00000000000000000000000000000000", "a3af8b7d326a2d47bd7576012e07d103"); - test_aes("mnemonic", 24, "000000000000000000000000000000000000000000000000", "7b8704678f263c316ddd1746d8377a4046a99dd9e5687d59"); - test_aes("mnemonic", 32, "0000000000000000000000000000000000000000000000000000000000000000", "7c0575db9badc9960441c6b8dcbd5ebdfec522ede5309904b7088d0e77c2bcef"); +// test_aes("mnemonic", 24, "000000000000000000000000000000000000000000000000", "7b8704678f263c316ddd1746d8377a4046a99dd9e5687d59"); +// test_aes("mnemonic", 32, "0000000000000000000000000000000000000000000000000000000000000000", "7c0575db9badc9960441c6b8dcbd5ebdfec522ede5309904b7088d0e77c2bcef"); test_aes("mnemonic", 16, "686f6a6461686f6a6461686f6a6461686f6a6461", "9c3bb85af2122cc2df449033338beb56"); - test_aes("mnemonic", 24, "686f6a6461686f6a6461686f6a6461686f6a6461686f6a64", "0d7009c589869eaa1d7398bffc7660cce32207a520d6cafe"); - test_aes("mnemonic", 32, "686f6a6461686f6a6461686f6a6461686f6a6461686f6a6461686f6a6461686f", "b1a4d05e3827611c5986ea4c207679a6934f20767434218029c4b3b7a53806a3"); +// test_aes("mnemonic", 24, "686f6a6461686f6a6461686f6a6461686f6a6461686f6a64", "0d7009c589869eaa1d7398bffc7660cce32207a520d6cafe"); +// test_aes("mnemonic", 32, "686f6a6461686f6a6461686f6a6461686f6a6461686f6a6461686f6a6461686f", "b1a4d05e3827611c5986ea4c207679a6934f20767434218029c4b3b7a53806a3"); test_aes("mnemonic", 16, "ffffffffffffffffffffffffffffffff", "e720f4474b7dabe382eec0529e2b1128"); - test_aes("mnemonic", 24, "ffffffffffffffffffffffffffffffffffffffffffffffff", "14dfe4c7a93e14616dce6c793110baee0b8bb404f3bec6c5"); - test_aes("mnemonic", 32, "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "ccf498fd9a57f872a4d274549fab474cbacdbd9d935ca31b06e3025526a704fb"); +// test_aes("mnemonic", 24, "ffffffffffffffffffffffffffffffffffffffffffffffff", "14dfe4c7a93e14616dce6c793110baee0b8bb404f3bec6c5"); +// test_aes("mnemonic", 32, "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "ccf498fd9a57f872a4d274549fab474cbacdbd9d935ca31b06e3025526a704fb"); } END_TEST From 02adc15ec9032b165f44eab72edd6418834928ad Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 28 Nov 2013 00:53:09 +0100 Subject: [PATCH 057/627] use fixed param size for mnemonic function --- bip39.c | 7 +++---- bip39.h | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/bip39.c b/bip39.c index 7392d9f2e..732bf767c 100644 --- a/bip39.c +++ b/bip39.c @@ -63,10 +63,9 @@ const char *mnemonic_from_data(const uint8_t *data, int len) return mnemo; } -void mnemonic_to_seed(const char *mnemonic, const char *passphrase, uint8_t *seed) +void mnemonic_to_seed(const char *mnemonic, const char *passphrase, uint8_t seed[512 / 8]) { static uint8_t k[8 + 256]; - uint8_t *m = seed; int i, kl; kl = strlen(passphrase); @@ -74,8 +73,8 @@ void mnemonic_to_seed(const char *mnemonic, const char *passphrase, uint8_t *see memcpy(k + 8, passphrase, kl); kl += 8; - hmac_sha512(k, kl, (const uint8_t *)mnemonic, strlen(mnemonic), m); + hmac_sha512(k, kl, (const uint8_t *)mnemonic, strlen(mnemonic), seed); for (i = 1; i < HMAC_ROUNDS; i++) { - hmac_sha512(k, kl, m, 512 / 8, m); + hmac_sha512(k, kl, seed, 512 / 8, seed); } } diff --git a/bip39.h b/bip39.h index 5e862cd29..378dacb58 100644 --- a/bip39.h +++ b/bip39.h @@ -8,6 +8,6 @@ const char *mnemonic_generate(int strength); // strength in bits const char *mnemonic_from_data(const uint8_t *data, int len); -void mnemonic_to_seed(const char *mnemonic, const char *passphrase, uint8_t *seed); +void mnemonic_to_seed(const char *mnemonic, const char *passphrase, uint8_t seed[512 / 8]); #endif From 353606e2df80992a2e554c632bb469caf5381e32 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 28 Nov 2013 02:47:00 +0100 Subject: [PATCH 058/627] add hdnode_coin_version to be able to set coin version from outside --- bip32.c | 12 +++++++----- bip32.h | 4 +++- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/bip32.c b/bip32.c index 491543215..2f00a7564 100644 --- a/bip32.c +++ b/bip32.c @@ -5,6 +5,8 @@ #include "ecdsa.h" #include "bip32.h" +uint8_t hdnode_coin_version = 0x00; + void hdnode_from_pub(uint32_t version, uint32_t depth, uint32_t fingerprint, uint32_t child_num, uint8_t *chain_code, uint8_t *public_key, HDNode *out) { out->version = version; @@ -14,7 +16,7 @@ void hdnode_from_pub(uint32_t version, uint32_t depth, uint32_t fingerprint, uin memcpy(out->chain_code, chain_code, 32); memcpy(out->public_key, public_key, 33); memset(out->private_key, 0, 32); - hdnode_fill_address(out, 0x00); + hdnode_fill_address(out); } void hdnode_from_seed(uint8_t *seed, int seed_len, HDNode *out) @@ -27,7 +29,7 @@ void hdnode_from_seed(uint8_t *seed, int seed_len, HDNode *out) // form a continuous 64 byte block in the memory hmac_sha512((uint8_t *)"Bitcoin seed", 12, seed, seed_len, out->private_key); hdnode_fill_public_key(out); - hdnode_fill_address(out, 0x00); + hdnode_fill_address(out); } void hdnode_descent(HDNode *inout, uint32_t i) @@ -57,7 +59,7 @@ void hdnode_descent(HDNode *inout, uint32_t i) bn_write_be(&a, inout->private_key); hdnode_fill_public_key(inout); - hdnode_fill_address(inout, 0x00); + hdnode_fill_address(inout); } void hdnode_fill_public_key(HDNode *xprv) @@ -65,7 +67,7 @@ void hdnode_fill_public_key(HDNode *xprv) ecdsa_get_public_key33(xprv->private_key, xprv->public_key); } -void hdnode_fill_address(HDNode *xprv, uint8_t version) +void hdnode_fill_address(HDNode *xprv) { - ecdsa_get_address(xprv->public_key, version, xprv->address); + ecdsa_get_address(xprv->public_key, hdnode_coin_version, xprv->address); } diff --git a/bip32.h b/bip32.h index ef49b950e..3bb414d97 100644 --- a/bip32.h +++ b/bip32.h @@ -14,6 +14,8 @@ typedef struct { char address[35]; } HDNode; +extern uint8_t hdnode_coin_version; + void hdnode_from_pub(uint32_t version, uint32_t depth, uint32_t fingerprint, uint32_t child_num, uint8_t *chain_code, uint8_t *public_key, HDNode *out); void hdnode_from_seed(uint8_t *seed, int seed_len, HDNode *out); @@ -24,6 +26,6 @@ void hdnode_descent(HDNode *inout, uint32_t i); void hdnode_fill_public_key(HDNode *xprv); -void hdnode_fill_address(HDNode *xprv, uint8_t version); +void hdnode_fill_address(HDNode *xprv); #endif From 352bc42be25269f404bcd70f2ddf829cc2688d56 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 9 Dec 2013 16:21:42 +0100 Subject: [PATCH 059/627] use PBKDF2 for BIP39, add unit tests --- Makefile | 2 +- README | 1 + bip39.c | 21 ++++----- bip39.h | 1 - pbkdf2.c | 36 +++++++++++++++ pbkdf2.h | 9 ++++ tests.c | 136 +++++++++++++++++++++++++++++++++---------------------- 7 files changed, 138 insertions(+), 68 deletions(-) create mode 100644 pbkdf2.c create mode 100644 pbkdf2.h diff --git a/Makefile b/Makefile index 43049aafe..ad65fb8d0 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ CC = gcc CFLAGS = -Wall -Os -OBJS = bignum.o ecdsa.o secp256k1.o sha2.o rand.o hmac.o bip32.o ripemd160.o bip39.o +OBJS = bignum.o ecdsa.o secp256k1.o sha2.o rand.o hmac.o bip32.o ripemd160.o bip39.o pbkdf2.o OBJS += aescrypt.o aeskey.o aestab.o all: tests test-openssl diff --git a/README b/README index feb8d0adb..f694357fa 100644 --- a/README +++ b/README @@ -12,6 +12,7 @@ These include: uses RFC6979 for deterministic signatures) - ECDSA public key derivation + Base58 address representation - HMAC-SHA256 and HMAC-SHA512 +- PBKDF2 - RIPEMD-160 - SHA256/SHA512 - unit tests (using Check - check.sf.net; in tests.c) diff --git a/bip39.c b/bip39.c index 732bf767c..0574a41e3 100644 --- a/bip39.c +++ b/bip39.c @@ -4,9 +4,10 @@ #include "hmac.h" #include "rand.h" #include "sha2.h" +#include "pbkdf2.h" #include "bip39_english.h" -#define HMAC_ROUNDS 10000 +#define ROUNDS 10000 const char *mnemonic_generate(int strength) { @@ -65,16 +66,10 @@ const char *mnemonic_from_data(const uint8_t *data, int len) void mnemonic_to_seed(const char *mnemonic, const char *passphrase, uint8_t seed[512 / 8]) { - static uint8_t k[8 + 256]; - int i, kl; - - kl = strlen(passphrase); - memcpy(k, "mnemonic", 8); - memcpy(k + 8, passphrase, kl); - kl += 8; - - hmac_sha512(k, kl, (const uint8_t *)mnemonic, strlen(mnemonic), seed); - for (i = 1; i < HMAC_ROUNDS; i++) { - hmac_sha512(k, kl, seed, 512 / 8, seed); - } + static uint8_t salt[8 + 256 + 4]; + int saltlen = strlen(passphrase); + memcpy(salt, "mnemonic", 8); + memcpy(salt + 8, passphrase, saltlen); + saltlen += 8; + pbkdf2((const uint8_t *)mnemonic, strlen(mnemonic), salt, saltlen, ROUNDS, seed, 512 / 8); } diff --git a/bip39.h b/bip39.h index 378dacb58..e9c2faa1f 100644 --- a/bip39.h +++ b/bip39.h @@ -3,7 +3,6 @@ #include - const char *mnemonic_generate(int strength); // strength in bits const char *mnemonic_from_data(const uint8_t *data, int len); diff --git a/pbkdf2.c b/pbkdf2.c new file mode 100644 index 000000000..5e0919334 --- /dev/null +++ b/pbkdf2.c @@ -0,0 +1,36 @@ +#include +#include "pbkdf2.h" +#include "hmac.h" + +void pbkdf2(const uint8_t *pass, int passlen, uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key, int keylen) +{ + uint32_t i, j, k; + uint8_t f[64], g[64]; + uint32_t blocks = keylen / 64; // SHA-512 + if (keylen & 63) { + blocks++; + } + for (i = 1; i <= blocks; i++) { + salt[saltlen ] = (i >> 24) & 0xFF; + salt[saltlen + 1] = (i >> 16) & 0xFF; + salt[saltlen + 2] = (i >> 8) & 0xFF; + salt[saltlen + 3] = i & 0xFF; + hmac_sha512(pass, passlen, salt, saltlen + 4, g); + memcpy(f, g, 64); + for (j = 1; j < iterations; j++) { + hmac_sha512(pass, passlen, g, 64, g); + for (k = 0; k < 64; k++) { + f[k] ^= g[k]; + } + } + if (i == blocks - 1 && (keylen & 63)) { + for (j = 0; j < (keylen & 63); j++) { + key[64 * (i - 1) + j] = f[j]; + } + } else { + for (j = 0; j < 64; j++) { + key[64 * (i - 1) + j] = f[j]; + } + } + } +} diff --git a/pbkdf2.h b/pbkdf2.h new file mode 100644 index 000000000..05121467f --- /dev/null +++ b/pbkdf2.h @@ -0,0 +1,9 @@ +#ifndef __PBKDF2_H__ +#define __PBKDF2_H__ + +#include + +// salt needs to have 4 extra bytes available beyond saltlen +void pbkdf2(const uint8_t *pass, int passlen, uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key, int keylen); + +#endif diff --git a/tests.c b/tests.c index 1b35dba7e..490c8a190 100644 --- a/tests.c +++ b/tests.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include "aes.h" @@ -31,6 +32,7 @@ #include "bip32.h" #include "bip39.h" #include "ecdsa.h" +#include "pbkdf2.h" #include "sha2.h" uint8_t *fromhex(const char *str) @@ -49,9 +51,10 @@ uint8_t *fromhex(const char *str) return buf; } -char *tohex(const uint8_t *bin, size_t l) +inline char *tohex(const uint8_t *bin, size_t l) { - static char buf[257], digits[] = "0123456789abcdef"; + char *buf = (char *)malloc(l * 2 + 1); + static char digits[] = "0123456789abcdef"; size_t i; for (i = 0; i < l; i++) { buf[i*2 ] = digits[(bin[i] >> 4) & 0xF]; @@ -66,10 +69,10 @@ char *tohex(const uint8_t *bin, size_t l) const void* _ck_y = (Y); \ size_t _ck_l = (L); \ ck_assert_msg(0 OP memcmp(_ck_y, _ck_x, _ck_l), \ - "Assertion '"#X#OP#Y"' failed: "#X"==\"%s\"", tohex(_ck_x, _ck_l)); \ + "Assertion '"#X#OP#Y"' failed: "#X"==\"%s\", "#Y"==\"%s\"", tohex(_ck_x, _ck_l), tohex(_ck_y, _ck_l)); \ } while (0) -#define ck_assert_mem_eq(X, Y, L) _ck_assert_mem((X), (Y), (L), ==) -#define ck_assert_mem_ne(X, Y, L) _ck_assert_mem((X), (Y), (L), !=) +#define ck_assert_mem_eq(X, Y, L) _ck_assert_mem(X, Y, L, ==) +#define ck_assert_mem_ne(X, Y, L) _ck_assert_mem(X, Y, L, !=) // test vector 1 from https://en.bitcoin.it/wiki/BIP_0032_TestVectors START_TEST(test_bip32_vector_1) @@ -289,81 +292,104 @@ START_TEST(test_rijndael) } END_TEST +// test vectors from http://stackoverflow.com/questions/15593184/pbkdf2-hmac-sha-512-test-vectors +START_TEST(test_pbkdf2) +{ + uint8_t k[64], s[64]; + + strcpy((char *)s, "salt"); + pbkdf2((uint8_t *)"password", 8, s, 4, 1, k, 64); + ck_assert_mem_eq(k, fromhex("867f70cf1ade02cff3752599a3a53dc4af34c7a669815ae5d513554e1c8cf252c02d470a285a0501bad999bfe943c08f050235d7d68b1da55e63f73b60a57fce"), 64); + + strcpy((char *)s, "salt"); + pbkdf2((uint8_t *)"password", 8, s, 4, 2, k, 64); + ck_assert_mem_eq(k, fromhex("e1d9c16aa681708a45f5c7c4e215ceb66e011a2e9f0040713f18aefdb866d53cf76cab2868a39b9f7840edce4fef5a82be67335c77a6068e04112754f27ccf4e"), 64); + + strcpy((char *)s, "salt"); + pbkdf2((uint8_t *)"password", 8, s, 4, 4096, k, 64); + ck_assert_mem_eq(k, fromhex("d197b1b33db0143e018b12f3d1d1479e6cdebdcc97c5c0f87f6902e072f457b5143f30602641b3d55cd335988cb36b84376060ecd532e039b742a239434af2d5"), 64); + + strcpy((char *)s, "saltSALTsaltSALTsaltSALTsaltSALTsalt"); + pbkdf2((uint8_t *)"passwordPASSWORDpassword", 3*8, s, 9*4, 4096, k, 64); + ck_assert_mem_eq(k, fromhex("8c0511f4c6e597c6ac6315d8f0362e225f3c501495ba23b868c005174dc4ee71115b59f9e60cd9532fa33e0f75aefe30225c583a186cd82bd4daea9724a3d3b8"), 64); +} +END_TEST + START_TEST(test_mnemonic) { static const char *vectors[] = { "00000000000000000000000000000000", "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about", - "cb5e7230ce8229de990674f6aa4288325fd4d8181f761734bd8b5cc944fedc2a4300e64422864b565352de7ffbc5ad0fafdf5344489f3a83e4a4bb5271cafaae", + "a3c9324fab99733ef7b5f9313e49cd45a134ee77da9aa176a84458d4b73e46f00a59361709d71d6b68338c957366937942b8f2ce2bd306b4ab0ae63c6b4ff7f5", "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", "legal winner thank year wave sausage worth useful legal winner thank yellow", - "de1277934939d6969519f44b7b3757a905d7f635be41e1e88022c346bc52ad26c0a3e9578e73e9b89066873266f285a5891d27d28cb27fccfe26d92bbd7ee364", + "f48f158e9689580f91ae0c813f4353ba2f90cd242e811ec27b2d79f97eb21fcfaf54a0b546c27c3b0a60285df2b064b3eef84fa7269d93ab013af10a20adc758", "80808080808080808080808080808080", "letter advice cage absurd amount doctor acoustic avoid letter advice cage above", - "8863bccef9cfffeacef1e4c6fc97bba8227ab0fc7e8e162be7467282689a13521ea364d7c4bc8cd241b59f53c5147a89c18a47248a96592ab9a2c1f1870b026c", + "7804de4eb059484ebd7c384e3bd99654763ff1f736abf4e8a5053b12594ea7389beefd967031f03416fa03994cf6be7d3f2fbe37709a27cd091f9e3d310f16d0", "ffffffffffffffffffffffffffffffff", "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong", - "7a29e57c7a1532af1bddb7e02b892cfccc6a57b74fe9784324ea89fab8a66dc64fde79c31166b159685116f4e93c1795496f20ffdc2d3a69d3439931dabde86e", + "ce2467164ca78cbce7c368bf35a390474d0e3af6afc4cc47214d215dcfc52ee567fd9921e66c32fc34e8f37abc468e7ba6cc744a96e815c95c583ad849d1c372", "000000000000000000000000000000000000000000000000", "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon agent", - "c3e382025b6a22a901505cf393faea450eb6c4a5f2a8c8f0596285b2bd84688877a6cc7231420e2bbdd2428e62ed549a78fa215b3adafd8dea075dabfc704d5e", + "e6fa0d745f5b841a4c90f1487dea80d5e5cc64c46c7aebe115b10ac333066f37b6d34ae514b8a1acb21b38c3836c248aec81c10874c2323bee98e70443cb2e2c", "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", "legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal will", - "c82666e40eb097bf6eb05fecd7dc2ddfb6bbdc6071900f4b3fd3c3e635db69aa2094f1f450c98e8dc6103aa72df635abdfcc3b6d6ec5261a9208a07a35a3f1c8", + "b829d8809875e7cae49114971e6ab87f13bd133c8d676972fb7a7ce8a9604b57759137091f21018ecd757906331c7e5466c8d9bc31b705e96e959beba111acc5", "808080808080808080808080808080808080808080808080", "letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter always", - "e90681c67c55504afadca009ce4042819341fa0e90300b6d32b4f2e8e8a6678ff7e7fc1da663ae194dc7a2ef7ec7b50112d1a5efce47bfd00c66eec82f2265b5", + "e8716279b6e74e876477061b83c4b29eeab288ea85ea196d95281dc0504c3edb1c70c86042e66f56ad27fb93d24c0a64294eac9668f0bba6d13a13882de542dd", "ffffffffffffffffffffffffffffffffffffffffffffffff", "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo when", - "2a372547df962742942674170a7cef495ea0b97f4864de16d0f3ee82eb577ca1eca345e601cc2df7c626c5bc51c52c28a3b4294224b685c958c7450bee6769e6", + "417b80e3489de48dc644d9bf8e32ed907f918efdaf78541c219e6e1b6e7e17ed38448e7d2ef311ad4446f8be779507d288285eb5eff32ce723d4b3692a26d6a4", "0000000000000000000000000000000000000000000000000000000000000000", "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon art", - "58cb9c5555d67ecc7b32305a78d1a2fcf0c9b22f1af761cfafc65eb1d3909f63ee2cab84996a7478cfd3e864cda5efb0caf580d56cf49739c6b3638d94e758c1", + "c716b0c6e051b60f819ba04bc5c402ac15e3aa4071c99735dfecce05d41b550155ae3511789a0ccf2cb245050f53e48292e8d88864e7c46eaa2fe626373e6fc8", "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", "legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth title", - "0093cb3ed6d1302d3cf498017f8cb1c7dc2fdbd62ec57fc49e4b2a4dd47a23e44e0b309517d5a3e7b0f4f0ef0ed132818cf120a098a92e572ad086f1a90ccb7f", + "8d80646b3677f02a56efc2977dc5972dadddd96dc34309119fbd44f5f939344df0e6c0aa924fabfe858c123283f904e1fcb24a5e20b70d69ec82a40e3e010c12", "8080808080808080808080808080808080808080808080808080808080808080", "letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic bless", - "8a21e46b9d264328c63e707e3d38ed4eb21508deda309fa2ef57cc8eca8b351ca3018758844ba9fb5851bab15d026a61cabace53a9a39bc91dc2c51407542cf5", + "fd544f531a25958d2980925b10e7146290dd8615fd9241a66b0681cf3afb44e607a279cc88fa4afe65779b07b3ba441dcfb13be42266642c474fb4787683556c", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo vote", - "5c8a1a284ab2844daf02cab322df3996574c9d53cbd36159c493441990f0d2a6bc9bc1502e3a067943d8ec67324663cbfb9667b57fed220e3f28335e26a90f93", - "1083fa24dbb0afa4e7b327d23f666567", - "awesome cabin matrix resist april sponsor paddle gossip split will off soon", - "467406b36a0176e40e013393e5ecef1f5b4019980b502eda9db1db06f7786e088b206f045f2bfcf93bd3b17a598335b078fcc5890115857ff741bd154b54f049", - "d8cbcd1ac2153ecd74048480c2732f637d642b21f0dd40df", - "sugar fury effort loud fault grit source mountain liar bean slim shoulder stone better march brick dolphin zero", - "f60180ea5047659cbb17ed6ef79c974de86c0170c7a1962b205329eb8fe9dcdd148615d35c515c4ec8da25f4cf54d5b7cd8cd5bf8dc4059df3a7900ca25f8306", - "2952f95cefe041616f6f379ab649cf8b702ecf8e4acceaebdda4cc50e2bf1d7b", - "citizen oak fire thank advice radar sad tragic one rather initial black actual guitar decrease flower turtle galaxy hard obvious athlete garbage invest have", - "eff4b6a15bb55fcf4bbfa2b3b9e24e7dc4bed8319ef7703f1786d472c73666922925778eaa5a06f8a26d2c7e7240be746fd69edfaf197e0dae12d7e0b550cfc8", - "f5e82717078a6ddc538a03e825f91bed", - "vote donkey shift audit plug until evolve document trial cool eight swarm", - "83dad22293225780a914083fc1a69bfe1d910f5b5962b0364820132a42ae1bd567a1fb4d5a19ad3d64539e38a7ee3d6429fac2b74e72b020913131c5eadb7db4", - "16b59b6a426f2f302f73049a32ab8572394278982212357a", - "birth proud surround luggage very object saddle gauge olive next throw tongue neither detail gauge drastic cube strategy", - "38ceb07e0dad221f612631843be6ae44a650aaf789c8ebea9313e07498d7864385227d25c7a8268a5b850367eef31639632e9218acadead20980b864b1cd477e", - "95b6cb48c7bc9c2a54496ae3eea790824b57e52b9637058f084555bc1b809b2f", - "noble rent split month six benefit eye coil token inside tomorrow afraid rely verb purity shoulder airport joke bacon problem script scare hole trumpet", - "e33e3d32e467877596a18ac60050488a0ec1557fda6bf95bad3d33d964c5e99dcd97d378403cc2723ed1c85c12b42bc59f15458d970d7a9d015f556109c146b0", - "7f93397f750f70a26513de2732ed95ee", - "legend oil garlic tube warfare eye nephew knock cheese number grace tackle", - "7f92ad63e4cdf4f15c23740556ad81e7f8cbd67cc672c93894c9c0d4fb171539eed5ab29f366570ed9940b816f45a539c3816f7ac19511794b752c5c1ec0e732", - "14c29fe840dd1c9f05d392ba13e4e1466b32ed0726a15f89", - "below belt wheel like spike exhibit blanket inch ring palace debate mimic rebel isolate broken stage garbage enhance", - "7bae6e54f8bad645f18f574b310bd3e6fde126dabcaf63a889940380e4798810e48c8151fc56bb2389c07498deacef025f03cbf8fc57ea3ec68f6421b0fcb649", - "cb30610d175ffeab8357d5190d31923997752a7f9815087bfcad5eb0b43f6468", - "sleep loan drive concert zoo fiction ask wide boil hat goose industry jar news wrist actor anchor that clip runway area cabbage museum abuse", - "b922030609e7626696b9cf5ca4c06cd99290be30b1052770f6a60c5f26532d178f287a4285d7a2add2845dc89a816b26fdba1c830067d130740f64c0ab5cfbe1", - "a30b50a5439dcd1774f412ea5ec33403", - "perfect fold citizen mango system merry stable liquid tumble voyage snack alter", - "aae175f26848370c4d5d3d0640597e2bf1b28e95908dd877259b3eac5d71ffe3140739a3ed80180f88159571df84441985620e6b2fb0696e5cba1aa7b8d10b98", - "70044da2175ad681d0ebbf2da83cf407eb9c8fd91fc0a8c9", - "hybrid carbon hammer concert pulp domain dry jewel color draft dial average right elevator good way potato energy", - "a3dffe3a31a2e949d1b04af7495a5b59db17e41d93b985feeaaae89260a9c86c6dcdf7cb32eaba61c2f4f0340f0f17d1ebb67af11657286b2ffd66ec4e05a8b7", - "0e0bab4df9669b97ba3f75a50b2e92423bbe6e91a1b01dbbf3ba200a917c9106", - "asthma front square version have slim trophy upgrade pink floor pig love room dance educate current buffalo test update divorce poverty salad dune scheme", - "2eb4d85fbd8deaf9b06bf9cdb3e5f36e8da040d110312075eb32e776fc8e505b94be3e63c1525ad41f5e5968a263853001dc7c40ea3af8e8b0cfb7effd5f408c", + "024a5866efbd866885915e8eb2fc743af294c1b69285d2d62efff4228d6b3eb53bfc2ecd97048fc9691b200ee4f11af4e51fab23aa0ac674dd187235b4e3283f", + "7dce4ed2284c9134d026608ab684c05c", + "lava include region explain simple omit dog slot melt reflect copy reward", + "bf010975d766bec901a632c0eadc9461de1ff89c20e37e49a67ae03730681a08122004304ed92bff0592db5271254967de4bc7f3a20de9b3becc5ab951c28d7c", + "0ce452419635c1a5faf44d60f2029f73fdc43419b4de1f03", + "artefact card motor cluster foster spray type meadow genius mosquito pond tree sword borrow grocery orange business burger", + "fd81692c4b0341a73bdb479ad5f572444658c68e11e693c06cafbda8d27f31eed03f32fa6e02744fcf902b8383253c64f98ffd659ba12fcb7dff47991d811fb0", + "00ac97c48106f0aeb8ba061e0250a559b3251dc35854e694780ba51d53a50120", + "absent gorilla van acoustic humor firm title dolphin bulk barely citizen recall crane moment aspect appear track phrase actual enforce steel spoon afraid benefit", + "97a796e70d1ba31176e0ace6feffa6bdcda6233648deb83b7a92e0dd01ad133d0b545a4d1283e5d5bef984b6b055fe9ebb99f4063607a7f17cdcee20a5fde35f", + "5baf069620eff15c71dd97c9a6ee328f", + "forum join pitch dove yellow purchase shuffle real situate danger million bunker", + "8e6416b101bc429d59becfdeef9b4ca40b4dd938efca1d3dabb54dfcbd48a78a65a2a28fdf4732f94806f2e8aa2e40fadff71fa7060883ce50eea7a90fbe4bd3", + "977f8287f9ed670b8489838ab0476a63b65d4df12f406e68", + "number winter peanut video stool magic banana corn melt lion surround shuffle grape plunge seven trend hover dwarf", + "bb63f0b3e0f9a1ed6afa0a694e6e3673f669ec8ac16b36bb6c3d273db387357b83e0c09e05c9dfc58b09a226a84e93a6bba558050b7b73c3a9b8f1bd8f3b7c33", + "3edc83b60740d77af3afa2fcb82c2f1bc541ee4e2518ddef4996d32453f54a3c", + "disagree tomato unique attend aspect runway solid violin witness scrap armed daring favorite warm decade perfect target kid grant play early wide cigar night", + "fdd3a53afaaf299cb3c5c1f9a2bb69627a03da65106deca4301859cda102d34eece0ad49558f145fb8986cf39b4ce88aad96c21ae9be2894da97a6379659ad25", + "63deb1e7f0c3de56f4ab43c9d2ae6c86", + "glow void ketchup thunder digital clock sport half six nice open artefact", + "68ce9777c0adc97c85ff636fd0c677b00c5f1dab44c4090a5f60c516ccb50a8b8a3f59afeaf85a935d986ad37dcea8e921e9ecde3bb6649c4cbc843b19e2b8a5", + "e77c6500b49072aefdf0a8aa787cf557d1920e94103e0597", + "trash tobacco dizzy hard already first water bench price sentence diary quick bomb also expect amazing airport royal", + "4c9e646357ea442fb2734018662e7473b5870ef7dc9f5048f9460ec22f08aeea561def3664e8f8a96759eaf1aeedb2b113fb820b96e8dc5853fd7de6293568de", + "89bb4bc5555992cdaf3444c5e7ca5a6e9f27efab894f1990bae41be8b2a26ea4", + "meadow surge vanish primary odor grocery rubber mass shine dinner notable tag venue water purchase clarify book magic ribbon daughter menu eye ritual orchard", + "71ce132d69f9bd4ebd7a3f8b4c45d057341670f9093fb22ce4855ee1672119d6a430f203ebcde5767e53f7c3ff64a5ad29ccd41f31d5d4f9db59e21f65b02cd0", + "00641669f095b433a304ed0f953f28eb", + "about camera omit thrive forget border metal oval auto prepare sketch stomach", + "016837c6355b0e8998a2fe8e10294a8b5dc0d9bc87e545e38f1ae77b4ade3247998a101ac1146f52414c9c8e0442f610fd7f0af25b60823fd044dc6902c865c8", + "b8b0ff94389d3ec591c7d2fb72d8d3666e4e52b8cdf5471d", + "reward margin topic illness stadium glare either where window nothing crumble smoke top citizen tobacco salt either truth", + "366e1ba1ab99d840505b94a20d9c63f1e17ec330ff77a7e2db399b57be5d34971ca33d7dea361f5bc9f3e6c939f0624f7231d62f53b9963d9632c8926a031abe", + "911fec0fbd88029f6fa99164896c18d898c9232af18bdcca3e42d53b86493104", + "much youth advance kitchen lens exile salt cram goose enter alert raise milk muscle profit cousin system faint mouse price reveal cause series long", + "ed60c0f8ee61d91be8c96dbe8fd999c21d77c162e682fff73e904bf138d6f4b48e69becf69d4c72fd0e630179238acc9dd037eaec55eca077e0ad379249dc456", 0, 0, 0, @@ -409,6 +435,10 @@ Suite *test_suite(void) tcase_add_test(tc, test_rijndael); suite_add_tcase(s, tc); + tc = tcase_create("pbkdf2"); + tcase_add_test(tc, test_pbkdf2); + suite_add_tcase(s, tc); + tc = tcase_create("bip39"); tcase_add_test(tc, test_mnemonic); suite_add_tcase(s, tc); From 97067c918ed3d3a52d526eef188cbae97ec39659 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 9 Dec 2013 18:16:33 +0100 Subject: [PATCH 060/627] extract some pbkdf2 constants into macros --- pbkdf2.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/pbkdf2.c b/pbkdf2.c index 5e0919334..6001b1f1b 100644 --- a/pbkdf2.c +++ b/pbkdf2.c @@ -2,12 +2,15 @@ #include "pbkdf2.h" #include "hmac.h" +#define HMACFUNC hmac_sha512 +#define HMACLEN (512/8) + void pbkdf2(const uint8_t *pass, int passlen, uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key, int keylen) { uint32_t i, j, k; - uint8_t f[64], g[64]; - uint32_t blocks = keylen / 64; // SHA-512 - if (keylen & 63) { + uint8_t f[HMACLEN], g[HMACLEN]; + uint32_t blocks = keylen / HMACLEN; + if (keylen & (HMACLEN - 1)) { blocks++; } for (i = 1; i <= blocks; i++) { @@ -15,22 +18,18 @@ void pbkdf2(const uint8_t *pass, int passlen, uint8_t *salt, int saltlen, uint32 salt[saltlen + 1] = (i >> 16) & 0xFF; salt[saltlen + 2] = (i >> 8) & 0xFF; salt[saltlen + 3] = i & 0xFF; - hmac_sha512(pass, passlen, salt, saltlen + 4, g); - memcpy(f, g, 64); + HMACFUNC(pass, passlen, salt, saltlen + 4, g); + memcpy(f, g, HMACLEN); for (j = 1; j < iterations; j++) { - hmac_sha512(pass, passlen, g, 64, g); - for (k = 0; k < 64; k++) { + HMACFUNC(pass, passlen, g, HMACLEN, g); + for (k = 0; k < HMACLEN; k++) { f[k] ^= g[k]; } } - if (i == blocks - 1 && (keylen & 63)) { - for (j = 0; j < (keylen & 63); j++) { - key[64 * (i - 1) + j] = f[j]; - } + if (i == blocks - 1 && (keylen & (HMACLEN - 1))) { + memcpy(key + HMACLEN * (i - 1), f, keylen & (HMACLEN - 1)); } else { - for (j = 0; j < 64; j++) { - key[64 * (i - 1) + j] = f[j]; - } + memcpy(key + HMACLEN * (i - 1), f, HMACLEN); } } } From 3589cf5cbfb639e4f7b8d1f7c34e505dc3f4e862 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 10 Dec 2013 16:21:25 +0100 Subject: [PATCH 061/627] use 4096 pbkdf2 rounds for bip39 --- bip39.c | 4 +-- tests.c | 96 ++++++++++++++++++++++++++++----------------------------- 2 files changed, 50 insertions(+), 50 deletions(-) diff --git a/bip39.c b/bip39.c index 0574a41e3..c9f5b6b3f 100644 --- a/bip39.c +++ b/bip39.c @@ -7,7 +7,7 @@ #include "pbkdf2.h" #include "bip39_english.h" -#define ROUNDS 10000 +#define PBKDF2_ROUNDS 4096 const char *mnemonic_generate(int strength) { @@ -71,5 +71,5 @@ void mnemonic_to_seed(const char *mnemonic, const char *passphrase, uint8_t seed memcpy(salt, "mnemonic", 8); memcpy(salt + 8, passphrase, saltlen); saltlen += 8; - pbkdf2((const uint8_t *)mnemonic, strlen(mnemonic), salt, saltlen, ROUNDS, seed, 512 / 8); + pbkdf2((const uint8_t *)mnemonic, strlen(mnemonic), salt, saltlen, PBKDF2_ROUNDS, seed, 512 / 8); } diff --git a/tests.c b/tests.c index 490c8a190..8f66cb9a3 100644 --- a/tests.c +++ b/tests.c @@ -320,76 +320,76 @@ START_TEST(test_mnemonic) static const char *vectors[] = { "00000000000000000000000000000000", "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about", - "a3c9324fab99733ef7b5f9313e49cd45a134ee77da9aa176a84458d4b73e46f00a59361709d71d6b68338c957366937942b8f2ce2bd306b4ab0ae63c6b4ff7f5", + "3d39670caaa237f5fb2999474413733b59d9dfe12b2cccfe878069a2f605ae467a669619a0a45c7b3378c4c812b80be677c1b8f8f60db9383f1ed265c45eb41c", "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", "legal winner thank year wave sausage worth useful legal winner thank yellow", - "f48f158e9689580f91ae0c813f4353ba2f90cd242e811ec27b2d79f97eb21fcfaf54a0b546c27c3b0a60285df2b064b3eef84fa7269d93ab013af10a20adc758", + "34eb04e0d4d60d00217f1c0150d8b0d6ffc6086e365a8a94fcceae8614e38274e719ebe7a693356426d1c62fdf90c84eaaac3d920743f3e79e0970a295886a08", "80808080808080808080808080808080", "letter advice cage absurd amount doctor acoustic avoid letter advice cage above", - "7804de4eb059484ebd7c384e3bd99654763ff1f736abf4e8a5053b12594ea7389beefd967031f03416fa03994cf6be7d3f2fbe37709a27cd091f9e3d310f16d0", + "acd45eb0b06e53d2e0fa6d1b3e8b3c33f200d2be6013fc5f8796c8c1d238552a615a01f325d78a10e633991d92f1236e21c24afe7c679fa1ecbc67fe71a5337d", "ffffffffffffffffffffffffffffffff", "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong", - "ce2467164ca78cbce7c368bf35a390474d0e3af6afc4cc47214d215dcfc52ee567fd9921e66c32fc34e8f37abc468e7ba6cc744a96e815c95c583ad849d1c372", + "d20f4e7902c3fd2f7716a533b131042036e6df2e44b14c8d65eb57403d002e4a12fa9be5325b257637ad1209e850188ffb061b3033a315b236ffc70c4ab4ea96", "000000000000000000000000000000000000000000000000", "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon agent", - "e6fa0d745f5b841a4c90f1487dea80d5e5cc64c46c7aebe115b10ac333066f37b6d34ae514b8a1acb21b38c3836c248aec81c10874c2323bee98e70443cb2e2c", + "55fb6d9683e16f71025b73efa1a297d522010e37a4fc5b54770b09173e4f7fed85f83b075142965015d17c8f7a365e589ac943ed83cfbf76dcaf301c6c53b9d6", "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", "legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal will", - "b829d8809875e7cae49114971e6ab87f13bd133c8d676972fb7a7ce8a9604b57759137091f21018ecd757906331c7e5466c8d9bc31b705e96e959beba111acc5", + "a2455beee8e73686d56f92979ed8a69011772f68e8329a437f47e55d79eaeec25afc2ac5ff636ac8578161a09a2ea690747575653f9d91016b09b71227a53791", "808080808080808080808080808080808080808080808080", "letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter always", - "e8716279b6e74e876477061b83c4b29eeab288ea85ea196d95281dc0504c3edb1c70c86042e66f56ad27fb93d24c0a64294eac9668f0bba6d13a13882de542dd", + "dd53ab268c524bad304e3decf4298ba1413a785bc866c2118988d1634bddf5a1301718191b247761060bc6dce3c62f833b22c062e51e7508fc04201cd7f8515b", "ffffffffffffffffffffffffffffffffffffffffffffffff", "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo when", - "417b80e3489de48dc644d9bf8e32ed907f918efdaf78541c219e6e1b6e7e17ed38448e7d2ef311ad4446f8be779507d288285eb5eff32ce723d4b3692a26d6a4", + "f0747118b52dcd33d383e5f3d6dddc94f66accd38b6d48f8a07fed9752fa8457dcb40bba5f40399814dcbd1a3f5cfaead1cf26c72268d1aa71561611421d4aaf", "0000000000000000000000000000000000000000000000000000000000000000", "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon art", - "c716b0c6e051b60f819ba04bc5c402ac15e3aa4071c99735dfecce05d41b550155ae3511789a0ccf2cb245050f53e48292e8d88864e7c46eaa2fe626373e6fc8", + "681088fbeaf5e4c29de23f55967a942bcb3400dc5b6e507477dfdcb493d921902352e015cd1235279c61ddf26b9536e6cf87fccb3cf2e142db44689f78ccad12", "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", "legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth title", - "8d80646b3677f02a56efc2977dc5972dadddd96dc34309119fbd44f5f939344df0e6c0aa924fabfe858c123283f904e1fcb24a5e20b70d69ec82a40e3e010c12", + "0881d39ee42046f433bff48ae0520128b79c0b9ff376c805b384340bd73767cdd8d1583606bafe2879be99ff44847e83057dbe521415a6067e8e4d7334e35a6c", "8080808080808080808080808080808080808080808080808080808080808080", "letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic bless", - "fd544f531a25958d2980925b10e7146290dd8615fd9241a66b0681cf3afb44e607a279cc88fa4afe65779b07b3ba441dcfb13be42266642c474fb4787683556c", + "63362d97a394e67674c5e337b8b8221f242cdf84eac057e08e8d522ac458e0c8b577c487bf82255d41e2ecfaf9326be2b3b31534a990608950b05a5d849e0603", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo vote", - "024a5866efbd866885915e8eb2fc743af294c1b69285d2d62efff4228d6b3eb53bfc2ecd97048fc9691b200ee4f11af4e51fab23aa0ac674dd187235b4e3283f", - "7dce4ed2284c9134d026608ab684c05c", - "lava include region explain simple omit dog slot melt reflect copy reward", - "bf010975d766bec901a632c0eadc9461de1ff89c20e37e49a67ae03730681a08122004304ed92bff0592db5271254967de4bc7f3a20de9b3becc5ab951c28d7c", - "0ce452419635c1a5faf44d60f2029f73fdc43419b4de1f03", - "artefact card motor cluster foster spray type meadow genius mosquito pond tree sword borrow grocery orange business burger", - "fd81692c4b0341a73bdb479ad5f572444658c68e11e693c06cafbda8d27f31eed03f32fa6e02744fcf902b8383253c64f98ffd659ba12fcb7dff47991d811fb0", - "00ac97c48106f0aeb8ba061e0250a559b3251dc35854e694780ba51d53a50120", - "absent gorilla van acoustic humor firm title dolphin bulk barely citizen recall crane moment aspect appear track phrase actual enforce steel spoon afraid benefit", - "97a796e70d1ba31176e0ace6feffa6bdcda6233648deb83b7a92e0dd01ad133d0b545a4d1283e5d5bef984b6b055fe9ebb99f4063607a7f17cdcee20a5fde35f", - "5baf069620eff15c71dd97c9a6ee328f", - "forum join pitch dove yellow purchase shuffle real situate danger million bunker", - "8e6416b101bc429d59becfdeef9b4ca40b4dd938efca1d3dabb54dfcbd48a78a65a2a28fdf4732f94806f2e8aa2e40fadff71fa7060883ce50eea7a90fbe4bd3", - "977f8287f9ed670b8489838ab0476a63b65d4df12f406e68", - "number winter peanut video stool magic banana corn melt lion surround shuffle grape plunge seven trend hover dwarf", - "bb63f0b3e0f9a1ed6afa0a694e6e3673f669ec8ac16b36bb6c3d273db387357b83e0c09e05c9dfc58b09a226a84e93a6bba558050b7b73c3a9b8f1bd8f3b7c33", - "3edc83b60740d77af3afa2fcb82c2f1bc541ee4e2518ddef4996d32453f54a3c", - "disagree tomato unique attend aspect runway solid violin witness scrap armed daring favorite warm decade perfect target kid grant play early wide cigar night", - "fdd3a53afaaf299cb3c5c1f9a2bb69627a03da65106deca4301859cda102d34eece0ad49558f145fb8986cf39b4ce88aad96c21ae9be2894da97a6379659ad25", - "63deb1e7f0c3de56f4ab43c9d2ae6c86", - "glow void ketchup thunder digital clock sport half six nice open artefact", - "68ce9777c0adc97c85ff636fd0c677b00c5f1dab44c4090a5f60c516ccb50a8b8a3f59afeaf85a935d986ad37dcea8e921e9ecde3bb6649c4cbc843b19e2b8a5", - "e77c6500b49072aefdf0a8aa787cf557d1920e94103e0597", - "trash tobacco dizzy hard already first water bench price sentence diary quick bomb also expect amazing airport royal", - "4c9e646357ea442fb2734018662e7473b5870ef7dc9f5048f9460ec22f08aeea561def3664e8f8a96759eaf1aeedb2b113fb820b96e8dc5853fd7de6293568de", - "89bb4bc5555992cdaf3444c5e7ca5a6e9f27efab894f1990bae41be8b2a26ea4", - "meadow surge vanish primary odor grocery rubber mass shine dinner notable tag venue water purchase clarify book magic ribbon daughter menu eye ritual orchard", - "71ce132d69f9bd4ebd7a3f8b4c45d057341670f9093fb22ce4855ee1672119d6a430f203ebcde5767e53f7c3ff64a5ad29ccd41f31d5d4f9db59e21f65b02cd0", - "00641669f095b433a304ed0f953f28eb", - "about camera omit thrive forget border metal oval auto prepare sketch stomach", - "016837c6355b0e8998a2fe8e10294a8b5dc0d9bc87e545e38f1ae77b4ade3247998a101ac1146f52414c9c8e0442f610fd7f0af25b60823fd044dc6902c865c8", - "b8b0ff94389d3ec591c7d2fb72d8d3666e4e52b8cdf5471d", - "reward margin topic illness stadium glare either where window nothing crumble smoke top citizen tobacco salt either truth", - "366e1ba1ab99d840505b94a20d9c63f1e17ec330ff77a7e2db399b57be5d34971ca33d7dea361f5bc9f3e6c939f0624f7231d62f53b9963d9632c8926a031abe", - "911fec0fbd88029f6fa99164896c18d898c9232af18bdcca3e42d53b86493104", - "much youth advance kitchen lens exile salt cram goose enter alert raise milk muscle profit cousin system faint mouse price reveal cause series long", - "ed60c0f8ee61d91be8c96dbe8fd999c21d77c162e682fff73e904bf138d6f4b48e69becf69d4c72fd0e630179238acc9dd037eaec55eca077e0ad379249dc456", + "3c22432ca0b5c9572a631b1068749bb6b663a78390322ab4b763c3ee21d81a7774f8ecdbc6ec73932b961c7374c7d14156cd61f81e433de3953fad23ea407e58", + "b71edfa823c78c5f8d6cade654e298b4", + "require want tube elegant juice cool cup noble town poem plate harsh", + "b424ec5ee4eb4127c3ce0722572c456a47084cda617a26fb647f9a02f43fcc3d11a84dadb6e892ec2641d8592149018a39c8bd9c1cadc969188da4b820bf3371", + "8ffd2ff2b2fa4dd7c61f019698893918dfd72c0ea37d0027", + "morning truly witness grass pill typical blur then notable session exact coyote word noodle dentist hurry ability dignity", + "d20f3879eebf9858443a6ca0f04f568aac06e74fb542475824101855133ed5f54d0805d0fc9bc0e6f03c1f820ee01a462b291caeba7cbf659b670afd00e0db42", + "9b655bc7d4e380bad6148df1cf8d8a6b023b781b05c2e823c5b5dd05139d30f6", + "opinion client vehicle prefer day frost flame museum vault ladder glad stock casual rose hire reunion trial bullet hope ring eye soldier sense stereo", + "3c6d3843502c73e29d7e9ddc3e81354d3467121244e0b713cdb8e0e76c357d6db2f738c43bc2550bb85c9d5c900fbd7fbba10c76e7a8b920e0d450ef5a6750eb", + "bdc823540d4ff8d372d29f4265fe5cf8", + "saddle donate steak box zebra have slender fault draw copper now various", + "0c960d7d54415e5d3ae41ea805bc961f14d7031ea0b92058c19cecab7b7e51f82a4d987dbe63dfaed30805bd746d93e645fd5dffea8354b90688711d6fa570bd", + "53de16bcad3ea92c691f5d069de6f1870a9adfe764b1aa33", + "fatigue vague quality foil tunnel normal piece two alley upset round asthma predict husband outside normal pretty oppose", + "fa384e2775768bc4905a5f7a014cdb62bbf77f751a039d5a124191099970dafc02e679232aeab769cb1582038907829baa3995255be01fe042b462539b26f1af", + "29932ac2fbba5682ef711bd7429068ac7f90fe6132c9f1a722e8441240cb9a96", + "civil off radar wash pistol door saddle casino struggle behind boss flight weekend left luggage float vast decorate ring market catch grape heart sport", + "777122f7b4e1dd21d385e71b9811d7d8d2adffcb8d0cebb667c93346156d4baec6b23adc519515742a4f6a712cbbef3e03e528f912498a3104206f33259d8823", + "498e5f6f8039399a5e307406f448f846", + "end indicate swim about near snake juice attend alone pelican dignity mimic", + "551e36122e37276b2840ab5c71b2a33888a6efa501a47b8323b313bf03f6dec1fb3d2ef11bfb35ec41580c5c0be3f881907fe2a3154b6e0ba8e05177b8e928a6", + "7d205696a272051f60c14f146808a2c83bb0f7ef95037b4e", + "large actor pizza eager cake moral loan clarify behave doctor chunk motor roast know salad parrot kitten item", + "d8bb3b18a5b9844ae1117b680986d93074efc691d9084dc5ef9d3570d9f9bcaffc9c319fb53d6c728564ee0e4494953245607688adb2efbbe77b912835f40e8c", + "d10c1c341f19c89a5c8c505cabfa027422ea6cb4cb6c28003898676ef7611cd2", + "speed genius artist dilemma orient essay impulse meat frequent garlic letter tribe concert curve spring horn chimney achieve champion solution urge rack infant furnace", + "a2f0b91b238ca1df0c4ac89eaa628701800f70732a1952982f3021e94bf7c3aafa0bb51bbdcc210f1e433d3e740660d1e4053c12edfdc1eb77ceafbe6a32723e", + "719ddb2a59b10066c74d26954da2dc2e", + "immense uphold skin recall avoid cricket brush pill next home require friend", + "9be5826432f915ace1f77827028a0ab7098dd3776304aa17e03698b09e5e93914e3e3f0d3d38c9b265ec2cc4bba1da8c9d9a97c8a3b1ec05add8e34a1c676490", + "5746a7704cd3b9dc0a022f2a9025618d813c8ca873b8008c", + "firm cry swing often describe unlock chimney echo clever license flash brand because edge peace jacket above gentle", + "06f5b2d7af46c2e7b7b99c87aa52d17c27925ba685ba5e572b4e978da2adee44fe7d5726966cd2ee1ae47b65790baa4b3f7952505b0b45d9c8673a29e6a57ffc", + "8fdda21cc1b39a6fb264ab3c007995cf9ed9efcfebc07652951e769b6bcbfad4", + "more unfair mango lock defy daughter sister nice despair adult grace palace unique wave distance job iron net elegant unfold repeat tourist twice number", + "c37ae2956e1396b03a722d647dbcf2672cb8db1493c2c136ab9370a62c19c8f45023a635b7c2646a9748ff28c7ef64d93d089c315d390c50cee19cb46a01927f", 0, 0, 0, From 8423c7abfde37ba26e1e293a826faf67f25f8cb9 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 4 Jan 2014 17:39:37 +0100 Subject: [PATCH 062/627] add check that pub.y != res.y --- bignum.c | 8 ++++++++ bignum.h | 2 ++ ecdsa.c | 11 +++++++++-- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/bignum.c b/bignum.c index b6bf0046a..5ad5d89f3 100644 --- a/bignum.c +++ b/bignum.c @@ -93,6 +93,14 @@ int bn_is_less(const bignum256 *a, const bignum256 *b) return 0; } +int bn_is_equal(const bignum256 *a, const bignum256 *b) { + int i; + for (i = 0; i < 9; i++) { + if (a->val[i] != b->val[i]) return 0; + } + return 1; +} + int bn_bitlen(const bignum256 *a) { int i = 8, j; while (i >= 0 && a->val[i] == 0) i--; diff --git a/bignum.h b/bignum.h index 32babf0dd..928f56fc6 100644 --- a/bignum.h +++ b/bignum.h @@ -63,6 +63,8 @@ int bn_is_zero(const bignum256 *a); int bn_is_less(const bignum256 *a, const bignum256 *b); +int bn_is_equal(const bignum256 *a, const bignum256 *b); + int bn_bitlen(const bignum256 *a); void bn_lshift(bignum256 *a); diff --git a/ecdsa.c b/ecdsa.c index ce2b39021..5465b3eeb 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -396,11 +396,18 @@ int ecdsa_verify(const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, scalar_multiply(&z, &res); } - // TODO both pub and res can be infinity, can have y = 0 OR can be equal + // both pub and res can be infinity, can have y = 0 OR can be equal -> false negative for (i = 0; i < 9; i++) { for (j = 0; j < 30; j++) { if (i == 8 && (s.val[i] >> j) == 0) break; if (s.val[i] & (1u << j)) { + bn_mod(&(pub.y), &prime256k1); + bn_mod(&(res.y), &prime256k1); + if (bn_is_equal(&(pub.y), &(res.y))) { + // this is not a failure, but a very inprobable case + // that we don't handle because of its inprobability + return 4; + } point_add(&pub, &res); } point_double(&pub); @@ -413,7 +420,7 @@ int ecdsa_verify(const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, // signature does not match for (i = 0; i < 9; i++) { if (res.x.val[i] != r.val[i]) { - return 4; + return 5; } } From e681e2b7aee9eec64e43a7d71598f903d683f746 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 10 Jan 2014 20:22:33 +0100 Subject: [PATCH 063/627] bip39: pbkdf2 rounds 4096 -> 2048 --- bip39.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bip39.c b/bip39.c index c9f5b6b3f..a98d43279 100644 --- a/bip39.c +++ b/bip39.c @@ -7,7 +7,7 @@ #include "pbkdf2.h" #include "bip39_english.h" -#define PBKDF2_ROUNDS 4096 +#define PBKDF2_ROUNDS 2048 const char *mnemonic_generate(int strength) { From ed7e2e5058e1878c40c94375bf62677ab08a9567 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 14 Jan 2014 14:35:13 +0100 Subject: [PATCH 064/627] implement public child key derivation --- bip32.c | 46 ++++++++++++++++--- bip32.h | 10 +++-- ecdsa.c | 48 ++++++++++++-------- ecdsa.h | 5 +++ tests.c | 134 ++++++++++++++++++++++++++++++++------------------------ 5 files changed, 158 insertions(+), 85 deletions(-) diff --git a/bip32.c b/bip32.c index 2f00a7564..d6af5cf98 100644 --- a/bip32.c +++ b/bip32.c @@ -13,9 +13,9 @@ void hdnode_from_pub(uint32_t version, uint32_t depth, uint32_t fingerprint, uin out->depth = depth; out->fingerprint = fingerprint; out->child_num = child_num; + memset(out->private_key, 0, 32); memcpy(out->chain_code, chain_code, 32); memcpy(out->public_key, public_key, 33); - memset(out->private_key, 0, 32); hdnode_fill_address(out); } @@ -32,9 +32,10 @@ void hdnode_from_seed(uint8_t *seed, int seed_len, HDNode *out) hdnode_fill_address(out); } -void hdnode_descent(HDNode *inout, uint32_t i) +int hdnode_private_ckd(HDNode *inout, uint32_t i) { uint8_t data[1 + 32 + 4]; + uint8_t I[32 + 32]; bignum256 a, b; if (i & 0x80000000) { // private derivation @@ -47,9 +48,9 @@ void hdnode_descent(HDNode *inout, uint32_t i) bn_read_be(inout->private_key, &a); - // this can be done because private_key[32] and chain_code[32] - // form a continuous 64 byte block in the memory - hmac_sha512(inout->chain_code, 32, data, sizeof(data), inout->private_key); + hmac_sha512(inout->chain_code, 32, data, sizeof(data), I); + memcpy(inout->private_key, I, 32); + memcpy(inout->chain_code, I + 32, 32); bn_read_be(inout->private_key, &b); bn_addmod(&a, &b, &order256k1); @@ -60,6 +61,41 @@ void hdnode_descent(HDNode *inout, uint32_t i) hdnode_fill_public_key(inout); hdnode_fill_address(inout); + return 1; +} + +int hdnode_public_ckd(HDNode *inout, uint32_t i) +{ + uint8_t data[1 + 32 + 4]; + uint8_t I[32 + 32]; + curve_point a, b; + bignum256 c; + + if (i & 0x80000000) { // private derivation + return 0; + } else { // public derivation + memcpy(data, inout->public_key, 33); + } + write_be(data + 33, i); + + memset(inout->private_key, 0, 32); + if (!ecdsa_read_pubkey(inout->public_key, &a)) { + return 0; + } + + hmac_sha512(inout->chain_code, 32, data, sizeof(data), I); + memcpy(inout->chain_code, I + 32, 32); + bn_read_be(I, &c); + scalar_multiply(&c, &b); // b = c * G + point_add(&a, &b); // b = a + b + inout->public_key[0] = 0x02 | (b.y.val[0] & 0x01); + bn_write_be(&b.x, inout->public_key + 1); + + inout->depth++; + inout->child_num = i; + + hdnode_fill_address(inout); + return 1; } void hdnode_fill_public_key(HDNode *xprv) diff --git a/bip32.h b/bip32.h index 3bb414d97..605b182f6 100644 --- a/bip32.h +++ b/bip32.h @@ -8,8 +8,8 @@ typedef struct { uint32_t depth; uint32_t fingerprint; uint32_t child_num; - uint8_t private_key[32]; // private_key + chain_code have to - uint8_t chain_code[32]; // form a continuous 64 byte block + uint8_t private_key[32]; + uint8_t chain_code[32]; uint8_t public_key[33]; char address[35]; } HDNode; @@ -20,9 +20,11 @@ void hdnode_from_pub(uint32_t version, uint32_t depth, uint32_t fingerprint, uin void hdnode_from_seed(uint8_t *seed, int seed_len, HDNode *out); -#define hdnode_descent_prime(X, I) hdnode_descent((X), ((I) | 0x80000000)) +#define hdnode_private_ckd_prime(X, I) hdnode_private_ckd((X), ((I) | 0x80000000)) -void hdnode_descent(HDNode *inout, uint32_t i); +int hdnode_private_ckd(HDNode *inout, uint32_t i); + +int hdnode_public_ckd(HDNode *inout, uint32_t i); void hdnode_fill_public_key(HDNode *xprv); diff --git a/ecdsa.c b/ecdsa.c index 5465b3eeb..cbe88ea8b 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -337,6 +337,33 @@ void ecdsa_get_address(const uint8_t *pub_key, uint8_t version, char *addr) } } +int ecdsa_read_pubkey(const uint8_t *pub_key, curve_point *pub) +{ + if (pub_key[0] == 0x04) { + bn_read_be(pub_key + 1, &(pub->x)); + bn_read_be(pub_key + 33, &(pub->y)); + return 1; + } + + if (pub_key[0] == 0x02 || pub_key[0] == 0x03) { // compute missing y coords + // y^2 = x^3 + 0*x + 7 + bn_read_be(pub_key + 1, &(pub->x)); + bn_read_be(pub_key + 1, &(pub->y)); // y is x + bn_multiply(&(pub->x), &(pub->y), &prime256k1); // y is x^2 + bn_multiply(&(pub->x), &(pub->y), &prime256k1); // y is x^3 + bn_addmodi(&(pub->y), 7, &prime256k1); // y is x^3 + 7 + bn_sqrt(&(pub->y), &prime256k1); // y = sqrt(y) + if ((pub_key[0] & 0x01) != (pub->y.val[0] & 1)) { + bn_substract(&prime256k1, &(pub->y), &(pub->y)); // y = -y + bn_mod(&(pub->y), &prime256k1); + } + return 1; + } + + // error + return 0; +} + // uses secp256k1 curve // pub_key - 65 bytes uncompressed key // signature - 64 bytes signature @@ -355,24 +382,9 @@ int ecdsa_verify(const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, // if double hash is required uncomment the following line: // SHA256_Raw(hash, 32, hash); - if (pub_key[0] == 0x04) { - bn_read_be(pub_key + 1, &pub.x); - bn_read_be(pub_key + 33, &pub.y); - } else - if (pub_key[0] == 0x02 || pub_key[0] == 0x03) { // compute missing y coords - // y^2 = x^3 + 0*x + 7 - bn_read_be(pub_key + 1, &pub.x); - bn_read_be(pub_key + 1, &pub.y); // y is x - bn_multiply(&pub.x, &pub.y, &prime256k1); // y is x^2 - bn_multiply(&pub.x, &pub.y, &prime256k1); // y is x^3 - bn_addmodi(&pub.y, 7, &prime256k1); // y is x^3 + 7 - bn_sqrt(&pub.y, &prime256k1); // y = sqrt(y) - if ((pub_key[0] & 0x01) != (pub.y.val[0] & 1)) { - bn_substract(&prime256k1, &pub.y, &pub.y); // y = -y - bn_mod(&pub.y, &prime256k1); - } - } else - return 1; + if (!ecdsa_read_pubkey(pub_key, &pub)) { + return 1; + } bn_read_be(sig, &r); bn_read_be(sig + 32, &s); diff --git a/ecdsa.h b/ecdsa.h index cea9749ef..62b34cb43 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -32,10 +32,15 @@ #define USE_RFC6979 1 #endif +void point_add(const curve_point *cp1, curve_point *cp2); +void point_double(curve_point *cp); +void scalar_multiply(bignum256 *k, curve_point *res); + int ecdsa_sign(const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig); void ecdsa_get_public_key33(const uint8_t *priv_key, uint8_t *pub_key); void ecdsa_get_public_key65(const uint8_t *priv_key, uint8_t *pub_key); void ecdsa_get_address(const uint8_t *pub_key, uint8_t version, char *addr); +int ecdsa_read_pubkey(const uint8_t *pub_key, curve_point *pub); int ecdsa_verify(const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, uint32_t msg_len); #endif diff --git a/tests.c b/tests.c index 8f66cb9a3..832830116 100644 --- a/tests.c +++ b/tests.c @@ -89,35 +89,35 @@ START_TEST(test_bip32_vector_1) ck_assert_str_eq(node.address, "15mKKb2eos1hWa6tisdPwwDC1a5J1y9nma"); // [Chain m/0'] - hdnode_descent_prime(&node, 0); + hdnode_private_ckd_prime(&node, 0); ck_assert_mem_eq(node.chain_code, fromhex("47fdacbd0f1097043b78c63c20c34ef4ed9a111d980047ad16282c7ae6236141"), 32); ck_assert_mem_eq(node.private_key, fromhex("edb2e14f9ee77d26dd93b4ecede8d16ed408ce149b6cd80b0715a2d911a0afea"), 32); ck_assert_mem_eq(node.public_key, fromhex("035a784662a4a20a65bf6aab9ae98a6c068a81c52e4b032c0fb5400c706cfccc56"), 33); ck_assert_str_eq(node.address, "19Q2WoS5hSS6T8GjhK8KZLMgmWaq4neXrh"); // [Chain m/0'/1] - hdnode_descent(&node, 1); + hdnode_private_ckd(&node, 1); ck_assert_mem_eq(node.chain_code, fromhex("2a7857631386ba23dacac34180dd1983734e444fdbf774041578e9b6adb37c19"), 32); ck_assert_mem_eq(node.private_key, fromhex("3c6cb8d0f6a264c91ea8b5030fadaa8e538b020f0a387421a12de9319dc93368"), 32); ck_assert_mem_eq(node.public_key, fromhex("03501e454bf00751f24b1b489aa925215d66af2234e3891c3b21a52bedb3cd711c"), 33); ck_assert_str_eq(node.address, "1JQheacLPdM5ySCkrZkV66G2ApAXe1mqLj"); // [Chain m/0'/1/2'] - hdnode_descent_prime(&node, 2); + hdnode_private_ckd_prime(&node, 2); ck_assert_mem_eq(node.chain_code, fromhex("04466b9cc8e161e966409ca52986c584f07e9dc81f735db683c3ff6ec7b1503f"), 32); ck_assert_mem_eq(node.private_key, fromhex("cbce0d719ecf7431d88e6a89fa1483e02e35092af60c042b1df2ff59fa424dca"), 32); ck_assert_mem_eq(node.public_key, fromhex("0357bfe1e341d01c69fe5654309956cbea516822fba8a601743a012a7896ee8dc2"), 33); ck_assert_str_eq(node.address, "1NjxqbA9aZWnh17q1UW3rB4EPu79wDXj7x"); // [Chain m/0'/1/2'/2] - hdnode_descent(&node, 2); + hdnode_private_ckd(&node, 2); ck_assert_mem_eq(node.chain_code, fromhex("cfb71883f01676f587d023cc53a35bc7f88f724b1f8c2892ac1275ac822a3edd"), 32); ck_assert_mem_eq(node.private_key, fromhex("0f479245fb19a38a1954c5c7c0ebab2f9bdfd96a17563ef28a6a4b1a2a764ef4"), 32); ck_assert_mem_eq(node.public_key, fromhex("02e8445082a72f29b75ca48748a914df60622a609cacfce8ed0e35804560741d29"), 33); ck_assert_str_eq(node.address, "1LjmJcdPnDHhNTUgrWyhLGnRDKxQjoxAgt"); // [Chain m/0'/1/2'/2/1000000000] - hdnode_descent(&node, 1000000000); + hdnode_private_ckd(&node, 1000000000); ck_assert_mem_eq(node.chain_code, fromhex("c783e67b921d2beb8f6b389cc646d7263b4145701dadd2161548a8b078e65e9e"), 32); ck_assert_mem_eq(node.private_key, fromhex("471b76e389e528d6de6d816857e012c5455051cad6660850e58372a6c3e6e7c8"), 32); ck_assert_mem_eq(node.public_key, fromhex("022a471424da5e657499d1ff51cb43c47481a03b1e77f951fe64cec9f5a48f7011"), 33); @@ -129,6 +129,7 @@ END_TEST START_TEST(test_bip32_vector_2) { HDNode node; + int r; // init m hdnode_from_seed(fromhex("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), 64, &node); @@ -140,39 +141,56 @@ START_TEST(test_bip32_vector_2) ck_assert_str_eq(node.address, "1JEoxevbLLG8cVqeoGKQiAwoWbNYSUyYjg"); // [Chain m/0] - hdnode_descent(&node, 0); + r = hdnode_private_ckd(&node, 0); + ck_assert_int_eq(r, 1); ck_assert_mem_eq(node.chain_code, fromhex("f0909affaa7ee7abe5dd4e100598d4dc53cd709d5a5c2cac40e7412f232f7c9c"), 32); ck_assert_mem_eq(node.private_key, fromhex("abe74a98f6c7eabee0428f53798f0ab8aa1bd37873999041703c742f15ac7e1e"), 32); ck_assert_mem_eq(node.public_key, fromhex("02fc9e5af0ac8d9b3cecfe2a888e2117ba3d089d8585886c9c826b6b22a98d12ea"), 33); ck_assert_str_eq(node.address, "19EuDJdgfRkwCmRzbzVBHZWQG9QNWhftbZ"); // [Chain m/0/2147483647'] - hdnode_descent_prime(&node, 2147483647); + r = hdnode_private_ckd_prime(&node, 2147483647); + ck_assert_int_eq(r, 1); ck_assert_mem_eq(node.chain_code, fromhex("be17a268474a6bb9c61e1d720cf6215e2a88c5406c4aee7b38547f585c9a37d9"), 32); ck_assert_mem_eq(node.private_key, fromhex("877c779ad9687164e9c2f4f0f4ff0340814392330693ce95a58fe18fd52e6e93"), 32); ck_assert_mem_eq(node.public_key, fromhex("03c01e7425647bdefa82b12d9bad5e3e6865bee0502694b94ca58b666abc0a5c3b"), 33); ck_assert_str_eq(node.address, "1Lke9bXGhn5VPrBuXgN12uGUphrttUErmk"); // [Chain m/0/2147483647'/1] - hdnode_descent(&node, 1); + r = hdnode_private_ckd(&node, 1); + ck_assert_int_eq(r, 1); ck_assert_mem_eq(node.chain_code, fromhex("f366f48f1ea9f2d1d3fe958c95ca84ea18e4c4ddb9366c336c927eb246fb38cb"), 32); ck_assert_mem_eq(node.private_key, fromhex("704addf544a06e5ee4bea37098463c23613da32020d604506da8c0518e1da4b7"), 32); ck_assert_mem_eq(node.public_key, fromhex("03a7d1d856deb74c508e05031f9895dab54626251b3806e16b4bd12e781a7df5b9"), 33); ck_assert_str_eq(node.address, "1BxrAr2pHpeBheusmd6fHDP2tSLAUa3qsW"); // [Chain m/0/2147483647'/1/2147483646'] - hdnode_descent_prime(&node, 2147483646); + r = hdnode_private_ckd_prime(&node, 2147483646); + ck_assert_int_eq(r, 1); ck_assert_mem_eq(node.chain_code, fromhex("637807030d55d01f9a0cb3a7839515d796bd07706386a6eddf06cc29a65a0e29"), 32); ck_assert_mem_eq(node.private_key, fromhex("f1c7c871a54a804afe328b4c83a1c33b8e5ff48f5087273f04efa83b247d6a2d"), 32); ck_assert_mem_eq(node.public_key, fromhex("02d2b36900396c9282fa14628566582f206a5dd0bcc8d5e892611806cafb0301f0"), 33); ck_assert_str_eq(node.address, "15XVotxCAV7sRx1PSCkQNsGw3W9jT9A94R"); // [Chain m/0/2147483647'/1/2147483646'/2] - hdnode_descent(&node, 2); + r = hdnode_private_ckd(&node, 2); + ck_assert_int_eq(r, 1); ck_assert_mem_eq(node.chain_code, fromhex("9452b549be8cea3ecb7a84bec10dcfd94afe4d129ebfd3b3cb58eedf394ed271"), 32); ck_assert_mem_eq(node.private_key, fromhex("bb7d39bdb83ecf58f2fd82b6d918341cbef428661ef01ab97c28a4842125ac23"), 32); ck_assert_mem_eq(node.public_key, fromhex("024d902e1a2fc7a8755ab5b694c575fce742c48d9ff192e63df5193e4c7afe1f9c"), 33); ck_assert_str_eq(node.address, "14UKfRV9ZPUp6ZC9PLhqbRtxdihW9em3xt"); + + // init m + hdnode_from_seed(fromhex("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), 64, &node); + + // test public derivation + // [Chain m/0] + r = hdnode_public_ckd(&node, 0); + ck_assert_int_eq(r, 1); + ck_assert_mem_eq(node.chain_code, fromhex("f0909affaa7ee7abe5dd4e100598d4dc53cd709d5a5c2cac40e7412f232f7c9c"), 32); + ck_assert_mem_eq(node.private_key, fromhex("0000000000000000000000000000000000000000000000000000000000000000"), 32); + ck_assert_mem_eq(node.public_key, fromhex("02fc9e5af0ac8d9b3cecfe2a888e2117ba3d089d8585886c9c826b6b22a98d12ea"), 33); + ck_assert_str_eq(node.address, "19EuDJdgfRkwCmRzbzVBHZWQG9QNWhftbZ"); } END_TEST @@ -320,76 +338,76 @@ START_TEST(test_mnemonic) static const char *vectors[] = { "00000000000000000000000000000000", "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about", - "3d39670caaa237f5fb2999474413733b59d9dfe12b2cccfe878069a2f605ae467a669619a0a45c7b3378c4c812b80be677c1b8f8f60db9383f1ed265c45eb41c", + "c55257c360c07c72029aebc1b53c05ed0362ada38ead3e3e9efa3708e53495531f09a6987599d18264c1e1c92f2cf141630c7a3c4ab7c81b2f001698e7463b04", "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", "legal winner thank year wave sausage worth useful legal winner thank yellow", - "34eb04e0d4d60d00217f1c0150d8b0d6ffc6086e365a8a94fcceae8614e38274e719ebe7a693356426d1c62fdf90c84eaaac3d920743f3e79e0970a295886a08", + "2e8905819b8723fe2c1d161860e5ee1830318dbf49a83bd451cfb8440c28bd6fa457fe1296106559a3c80937a1c1069be3a3a5bd381ee6260e8d9739fce1f607", "80808080808080808080808080808080", "letter advice cage absurd amount doctor acoustic avoid letter advice cage above", - "acd45eb0b06e53d2e0fa6d1b3e8b3c33f200d2be6013fc5f8796c8c1d238552a615a01f325d78a10e633991d92f1236e21c24afe7c679fa1ecbc67fe71a5337d", + "d71de856f81a8acc65e6fc851a38d4d7ec216fd0796d0a6827a3ad6ed5511a30fa280f12eb2e47ed2ac03b5c462a0358d18d69fe4f985ec81778c1b370b652a8", "ffffffffffffffffffffffffffffffff", "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong", - "d20f4e7902c3fd2f7716a533b131042036e6df2e44b14c8d65eb57403d002e4a12fa9be5325b257637ad1209e850188ffb061b3033a315b236ffc70c4ab4ea96", + "ac27495480225222079d7be181583751e86f571027b0497b5b5d11218e0a8a13332572917f0f8e5a589620c6f15b11c61dee327651a14c34e18231052e48c069", "000000000000000000000000000000000000000000000000", "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon agent", - "55fb6d9683e16f71025b73efa1a297d522010e37a4fc5b54770b09173e4f7fed85f83b075142965015d17c8f7a365e589ac943ed83cfbf76dcaf301c6c53b9d6", + "035895f2f481b1b0f01fcf8c289c794660b289981a78f8106447707fdd9666ca06da5a9a565181599b79f53b844d8a71dd9f439c52a3d7b3e8a79c906ac845fa", "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", "legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal will", - "a2455beee8e73686d56f92979ed8a69011772f68e8329a437f47e55d79eaeec25afc2ac5ff636ac8578161a09a2ea690747575653f9d91016b09b71227a53791", + "f2b94508732bcbacbcc020faefecfc89feafa6649a5491b8c952cede496c214a0c7b3c392d168748f2d4a612bada0753b52a1c7ac53c1e93abd5c6320b9e95dd", "808080808080808080808080808080808080808080808080", "letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter always", - "dd53ab268c524bad304e3decf4298ba1413a785bc866c2118988d1634bddf5a1301718191b247761060bc6dce3c62f833b22c062e51e7508fc04201cd7f8515b", + "107d7c02a5aa6f38c58083ff74f04c607c2d2c0ecc55501dadd72d025b751bc27fe913ffb796f841c49b1d33b610cf0e91d3aa239027f5e99fe4ce9e5088cd65", "ffffffffffffffffffffffffffffffffffffffffffffffff", "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo when", - "f0747118b52dcd33d383e5f3d6dddc94f66accd38b6d48f8a07fed9752fa8457dcb40bba5f40399814dcbd1a3f5cfaead1cf26c72268d1aa71561611421d4aaf", + "0cd6e5d827bb62eb8fc1e262254223817fd068a74b5b449cc2f667c3f1f985a76379b43348d952e2265b4cd129090758b3e3c2c49103b5051aac2eaeb890a528", "0000000000000000000000000000000000000000000000000000000000000000", "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon art", - "681088fbeaf5e4c29de23f55967a942bcb3400dc5b6e507477dfdcb493d921902352e015cd1235279c61ddf26b9536e6cf87fccb3cf2e142db44689f78ccad12", + "bda85446c68413707090a52022edd26a1c9462295029f2e60cd7c4f2bbd3097170af7a4d73245cafa9c3cca8d561a7c3de6f5d4a10be8ed2a5e608d68f92fcc8", "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", "legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth title", - "0881d39ee42046f433bff48ae0520128b79c0b9ff376c805b384340bd73767cdd8d1583606bafe2879be99ff44847e83057dbe521415a6067e8e4d7334e35a6c", + "bc09fca1804f7e69da93c2f2028eb238c227f2e9dda30cd63699232578480a4021b146ad717fbb7e451ce9eb835f43620bf5c514db0f8add49f5d121449d3e87", "8080808080808080808080808080808080808080808080808080808080808080", "letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic bless", - "63362d97a394e67674c5e337b8b8221f242cdf84eac057e08e8d522ac458e0c8b577c487bf82255d41e2ecfaf9326be2b3b31534a990608950b05a5d849e0603", + "c0c519bd0e91a2ed54357d9d1ebef6f5af218a153624cf4f2da911a0ed8f7a09e2ef61af0aca007096df430022f7a2b6fb91661a9589097069720d015e4e982f", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo vote", - "3c22432ca0b5c9572a631b1068749bb6b663a78390322ab4b763c3ee21d81a7774f8ecdbc6ec73932b961c7374c7d14156cd61f81e433de3953fad23ea407e58", - "b71edfa823c78c5f8d6cade654e298b4", - "require want tube elegant juice cool cup noble town poem plate harsh", - "b424ec5ee4eb4127c3ce0722572c456a47084cda617a26fb647f9a02f43fcc3d11a84dadb6e892ec2641d8592149018a39c8bd9c1cadc969188da4b820bf3371", - "8ffd2ff2b2fa4dd7c61f019698893918dfd72c0ea37d0027", - "morning truly witness grass pill typical blur then notable session exact coyote word noodle dentist hurry ability dignity", - "d20f3879eebf9858443a6ca0f04f568aac06e74fb542475824101855133ed5f54d0805d0fc9bc0e6f03c1f820ee01a462b291caeba7cbf659b670afd00e0db42", - "9b655bc7d4e380bad6148df1cf8d8a6b023b781b05c2e823c5b5dd05139d30f6", - "opinion client vehicle prefer day frost flame museum vault ladder glad stock casual rose hire reunion trial bullet hope ring eye soldier sense stereo", - "3c6d3843502c73e29d7e9ddc3e81354d3467121244e0b713cdb8e0e76c357d6db2f738c43bc2550bb85c9d5c900fbd7fbba10c76e7a8b920e0d450ef5a6750eb", - "bdc823540d4ff8d372d29f4265fe5cf8", - "saddle donate steak box zebra have slender fault draw copper now various", - "0c960d7d54415e5d3ae41ea805bc961f14d7031ea0b92058c19cecab7b7e51f82a4d987dbe63dfaed30805bd746d93e645fd5dffea8354b90688711d6fa570bd", - "53de16bcad3ea92c691f5d069de6f1870a9adfe764b1aa33", - "fatigue vague quality foil tunnel normal piece two alley upset round asthma predict husband outside normal pretty oppose", - "fa384e2775768bc4905a5f7a014cdb62bbf77f751a039d5a124191099970dafc02e679232aeab769cb1582038907829baa3995255be01fe042b462539b26f1af", - "29932ac2fbba5682ef711bd7429068ac7f90fe6132c9f1a722e8441240cb9a96", - "civil off radar wash pistol door saddle casino struggle behind boss flight weekend left luggage float vast decorate ring market catch grape heart sport", - "777122f7b4e1dd21d385e71b9811d7d8d2adffcb8d0cebb667c93346156d4baec6b23adc519515742a4f6a712cbbef3e03e528f912498a3104206f33259d8823", - "498e5f6f8039399a5e307406f448f846", - "end indicate swim about near snake juice attend alone pelican dignity mimic", - "551e36122e37276b2840ab5c71b2a33888a6efa501a47b8323b313bf03f6dec1fb3d2ef11bfb35ec41580c5c0be3f881907fe2a3154b6e0ba8e05177b8e928a6", - "7d205696a272051f60c14f146808a2c83bb0f7ef95037b4e", - "large actor pizza eager cake moral loan clarify behave doctor chunk motor roast know salad parrot kitten item", - "d8bb3b18a5b9844ae1117b680986d93074efc691d9084dc5ef9d3570d9f9bcaffc9c319fb53d6c728564ee0e4494953245607688adb2efbbe77b912835f40e8c", - "d10c1c341f19c89a5c8c505cabfa027422ea6cb4cb6c28003898676ef7611cd2", - "speed genius artist dilemma orient essay impulse meat frequent garlic letter tribe concert curve spring horn chimney achieve champion solution urge rack infant furnace", - "a2f0b91b238ca1df0c4ac89eaa628701800f70732a1952982f3021e94bf7c3aafa0bb51bbdcc210f1e433d3e740660d1e4053c12edfdc1eb77ceafbe6a32723e", - "719ddb2a59b10066c74d26954da2dc2e", - "immense uphold skin recall avoid cricket brush pill next home require friend", - "9be5826432f915ace1f77827028a0ab7098dd3776304aa17e03698b09e5e93914e3e3f0d3d38c9b265ec2cc4bba1da8c9d9a97c8a3b1ec05add8e34a1c676490", - "5746a7704cd3b9dc0a022f2a9025618d813c8ca873b8008c", - "firm cry swing often describe unlock chimney echo clever license flash brand because edge peace jacket above gentle", - "06f5b2d7af46c2e7b7b99c87aa52d17c27925ba685ba5e572b4e978da2adee44fe7d5726966cd2ee1ae47b65790baa4b3f7952505b0b45d9c8673a29e6a57ffc", - "8fdda21cc1b39a6fb264ab3c007995cf9ed9efcfebc07652951e769b6bcbfad4", - "more unfair mango lock defy daughter sister nice despair adult grace palace unique wave distance job iron net elegant unfold repeat tourist twice number", - "c37ae2956e1396b03a722d647dbcf2672cb8db1493c2c136ab9370a62c19c8f45023a635b7c2646a9748ff28c7ef64d93d089c315d390c50cee19cb46a01927f", + "dd48c104698c30cfe2b6142103248622fb7bb0ff692eebb00089b32d22484e1613912f0a5b694407be899ffd31ed3992c456cdf60f5d4564b8ba3f05a69890ad", + "77c2b00716cec7213839159e404db50d", + "jelly better achieve collect unaware mountain thought cargo oxygen act hood bridge", + "b5b6d0127db1a9d2226af0c3346031d77af31e918dba64287a1b44b8ebf63cdd52676f672a290aae502472cf2d602c051f3e6f18055e84e4c43897fc4e51a6ff", + "b63a9c59a6e641f288ebc103017f1da9f8290b3da6bdef7b", + "renew stay biology evidence goat welcome casual join adapt armor shuffle fault little machine walk stumble urge swap", + "9248d83e06f4cd98debf5b6f010542760df925ce46cf38a1bdb4e4de7d21f5c39366941c69e1bdbf2966e0f6e6dbece898a0e2f0a4c2b3e640953dfe8b7bbdc5", + "3e141609b97933b66a060dcddc71fad1d91677db872031e85f4c015c5e7e8982", + "dignity pass list indicate nasty swamp pool script soccer toe leaf photo multiply desk host tomato cradle drill spread actor shine dismiss champion exotic", + "ff7f3184df8696d8bef94b6c03114dbee0ef89ff938712301d27ed8336ca89ef9635da20af07d4175f2bf5f3de130f39c9d9e8dd0472489c19b1a020a940da67", + "0460ef47585604c5660618db2e6a7e7f", + "afford alter spike radar gate glance object seek swamp infant panel yellow", + "65f93a9f36b6c85cbe634ffc1f99f2b82cbb10b31edc7f087b4f6cb9e976e9faf76ff41f8f27c99afdf38f7a303ba1136ee48a4c1e7fcd3dba7aa876113a36e4", + "72f60ebac5dd8add8d2a25a797102c3ce21bc029c200076f", + "indicate race push merry suffer human cruise dwarf pole review arch keep canvas theme poem divorce alter left", + "3bbf9daa0dfad8229786ace5ddb4e00fa98a044ae4c4975ffd5e094dba9e0bb289349dbe2091761f30f382d4e35c4a670ee8ab50758d2c55881be69e327117ba", + "2c85efc7f24ee4573d2b81a6ec66cee209b2dcbd09d8eddc51e0215b0b68e416", + "clutch control vehicle tonight unusual clog visa ice plunge glimpse recipe series open hour vintage deposit universe tip job dress radar refuse motion taste", + "fe908f96f46668b2d5b37d82f558c77ed0d69dd0e7e043a5b0511c48c2f1064694a956f86360c93dd04052a8899497ce9e985ebe0c8c52b955e6ae86d4ff4449", + "eaebabb2383351fd31d703840b32e9e2", + "turtle front uncle idea crush write shrug there lottery flower risk shell", + "bdfb76a0759f301b0b899a1e3985227e53b3f51e67e3f2a65363caedf3e32fde42a66c404f18d7b05818c95ef3ca1e5146646856c461c073169467511680876c", + "7ac45cfe7722ee6c7ba84fbc2d5bd61b45cb2fe5eb65aa78", + "kiss carry display unusual confirm curtain upgrade antique rotate hello void custom frequent obey nut hole price segment", + "ed56ff6c833c07982eb7119a8f48fd363c4a9b1601cd2de736b01045c5eb8ab4f57b079403485d1c4924f0790dc10a971763337cb9f9c62226f64fff26397c79", + "4fa1a8bc3e6d80ee1316050e862c1812031493212b7ec3f3bb1b08f168cabeef", + "exile ask congress lamp submit jacket era scheme attend cousin alcohol catch course end lucky hurt sentence oven short ball bird grab wing top", + "095ee6f817b4c2cb30a5a797360a81a40ab0f9a4e25ecd672a3f58a0b5ba0687c096a6b14d2c0deb3bdefce4f61d01ae07417d502429352e27695163f7447a8c", + "18ab19a9f54a9274f03e5209a2ac8a91", + "board flee heavy tunnel powder denial science ski answer betray cargo cat", + "6eff1bb21562918509c73cb990260db07c0ce34ff0e3cc4a8cb3276129fbcb300bddfe005831350efd633909f476c45c88253276d9fd0df6ef48609e8bb7dca8", + "18a2e1d81b8ecfb2a333adcb0c17a5b9eb76cc5d05db91a4", + "board blade invite damage undo sun mimic interest slam gaze truly inherit resist great inject rocket museum chief", + "f84521c777a13b61564234bf8f8b62b3afce27fc4062b51bb5e62bdfecb23864ee6ecf07c1d5a97c0834307c5c852d8ceb88e7c97923c0a3b496bedd4e5f88a9", + "15da872c95a13dd738fbf50e427583ad61f18fd99f628c417a61cf8343c90419", + "beyond stage sleep clip because twist token leaf atom beauty genius food business side grid unable middle armed observe pair crouch tonight away coconut", + "b15509eaa2d09d3efd3e006ef42151b30367dc6e3aa5e44caba3fe4d3e352e65101fbdb86a96776b91946ff06f8eac594dc6ee1d3e82a42dfe1b40fef6bcc3fd", 0, 0, 0, From 8764a03453e8df8148b1fd28b463e8e7a65a0541 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 14 Jan 2014 15:29:46 +0100 Subject: [PATCH 065/627] compute fingerprints --- bip32.c | 12 ++++++++++++ tests.c | 13 +++++++++++++ 2 files changed, 25 insertions(+) diff --git a/bip32.c b/bip32.c index d6af5cf98..a37041e48 100644 --- a/bip32.c +++ b/bip32.c @@ -4,6 +4,8 @@ #include "hmac.h" #include "ecdsa.h" #include "bip32.h" +#include "sha2.h" +#include "ripemd160.h" uint8_t hdnode_coin_version = 0x00; @@ -36,6 +38,7 @@ int hdnode_private_ckd(HDNode *inout, uint32_t i) { uint8_t data[1 + 32 + 4]; uint8_t I[32 + 32]; + uint8_t fingerprint[32]; bignum256 a, b; if (i & 0x80000000) { // private derivation @@ -46,6 +49,10 @@ int hdnode_private_ckd(HDNode *inout, uint32_t i) } write_be(data + 33, i); + SHA256_Raw(inout->public_key, 33, fingerprint); + ripemd160(fingerprint, 32, fingerprint); + inout->fingerprint = (fingerprint[0] << 24) + (fingerprint[1] << 16) + (fingerprint[2] << 8) + fingerprint[3]; + bn_read_be(inout->private_key, &a); hmac_sha512(inout->chain_code, 32, data, sizeof(data), I); @@ -68,6 +75,7 @@ int hdnode_public_ckd(HDNode *inout, uint32_t i) { uint8_t data[1 + 32 + 4]; uint8_t I[32 + 32]; + uint8_t fingerprint[32]; curve_point a, b; bignum256 c; @@ -78,6 +86,10 @@ int hdnode_public_ckd(HDNode *inout, uint32_t i) } write_be(data + 33, i); + SHA256_Raw(inout->public_key, 33, fingerprint); + ripemd160(fingerprint, 32, fingerprint); + inout->fingerprint = (fingerprint[0] << 24) + (fingerprint[1] << 16) + (fingerprint[2] << 8) + fingerprint[3]; + memset(inout->private_key, 0, 32); if (!ecdsa_read_pubkey(inout->public_key, &a)) { return 0; diff --git a/tests.c b/tests.c index 832830116..8ec319d0e 100644 --- a/tests.c +++ b/tests.c @@ -83,6 +83,7 @@ START_TEST(test_bip32_vector_1) hdnode_from_seed(fromhex("000102030405060708090a0b0c0d0e0f"), 16, &node); // [Chain m] + ck_assert_int_eq(node.fingerprint, 0x00000000); ck_assert_mem_eq(node.chain_code, fromhex("873dff81c02f525623fd1fe5167eac3a55a049de3d314bb42ee227ffed37d508"), 32); ck_assert_mem_eq(node.private_key, fromhex("e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35"), 32); ck_assert_mem_eq(node.public_key, fromhex("0339a36013301597daef41fbe593a02cc513d0b55527ec2df1050e2e8ff49c85c2"), 33); @@ -90,6 +91,7 @@ START_TEST(test_bip32_vector_1) // [Chain m/0'] hdnode_private_ckd_prime(&node, 0); + ck_assert_int_eq(node.fingerprint, 0x3442193e); ck_assert_mem_eq(node.chain_code, fromhex("47fdacbd0f1097043b78c63c20c34ef4ed9a111d980047ad16282c7ae6236141"), 32); ck_assert_mem_eq(node.private_key, fromhex("edb2e14f9ee77d26dd93b4ecede8d16ed408ce149b6cd80b0715a2d911a0afea"), 32); ck_assert_mem_eq(node.public_key, fromhex("035a784662a4a20a65bf6aab9ae98a6c068a81c52e4b032c0fb5400c706cfccc56"), 33); @@ -97,6 +99,7 @@ START_TEST(test_bip32_vector_1) // [Chain m/0'/1] hdnode_private_ckd(&node, 1); + ck_assert_int_eq(node.fingerprint, 0x5c1bd648); ck_assert_mem_eq(node.chain_code, fromhex("2a7857631386ba23dacac34180dd1983734e444fdbf774041578e9b6adb37c19"), 32); ck_assert_mem_eq(node.private_key, fromhex("3c6cb8d0f6a264c91ea8b5030fadaa8e538b020f0a387421a12de9319dc93368"), 32); ck_assert_mem_eq(node.public_key, fromhex("03501e454bf00751f24b1b489aa925215d66af2234e3891c3b21a52bedb3cd711c"), 33); @@ -104,6 +107,7 @@ START_TEST(test_bip32_vector_1) // [Chain m/0'/1/2'] hdnode_private_ckd_prime(&node, 2); + ck_assert_int_eq(node.fingerprint, 0xbef5a2f9); ck_assert_mem_eq(node.chain_code, fromhex("04466b9cc8e161e966409ca52986c584f07e9dc81f735db683c3ff6ec7b1503f"), 32); ck_assert_mem_eq(node.private_key, fromhex("cbce0d719ecf7431d88e6a89fa1483e02e35092af60c042b1df2ff59fa424dca"), 32); ck_assert_mem_eq(node.public_key, fromhex("0357bfe1e341d01c69fe5654309956cbea516822fba8a601743a012a7896ee8dc2"), 33); @@ -111,6 +115,7 @@ START_TEST(test_bip32_vector_1) // [Chain m/0'/1/2'/2] hdnode_private_ckd(&node, 2); + ck_assert_int_eq(node.fingerprint, 0xee7ab90c); ck_assert_mem_eq(node.chain_code, fromhex("cfb71883f01676f587d023cc53a35bc7f88f724b1f8c2892ac1275ac822a3edd"), 32); ck_assert_mem_eq(node.private_key, fromhex("0f479245fb19a38a1954c5c7c0ebab2f9bdfd96a17563ef28a6a4b1a2a764ef4"), 32); ck_assert_mem_eq(node.public_key, fromhex("02e8445082a72f29b75ca48748a914df60622a609cacfce8ed0e35804560741d29"), 33); @@ -118,6 +123,7 @@ START_TEST(test_bip32_vector_1) // [Chain m/0'/1/2'/2/1000000000] hdnode_private_ckd(&node, 1000000000); + ck_assert_int_eq(node.fingerprint, 0xd880d7d8); ck_assert_mem_eq(node.chain_code, fromhex("c783e67b921d2beb8f6b389cc646d7263b4145701dadd2161548a8b078e65e9e"), 32); ck_assert_mem_eq(node.private_key, fromhex("471b76e389e528d6de6d816857e012c5455051cad6660850e58372a6c3e6e7c8"), 32); ck_assert_mem_eq(node.public_key, fromhex("022a471424da5e657499d1ff51cb43c47481a03b1e77f951fe64cec9f5a48f7011"), 33); @@ -135,6 +141,7 @@ START_TEST(test_bip32_vector_2) hdnode_from_seed(fromhex("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), 64, &node); // [Chain m] + ck_assert_int_eq(node.fingerprint, 0x00000000); ck_assert_mem_eq(node.chain_code, fromhex("60499f801b896d83179a4374aeb7822aaeaceaa0db1f85ee3e904c4defbd9689"), 32); ck_assert_mem_eq(node.private_key, fromhex("4b03d6fc340455b363f51020ad3ecca4f0850280cf436c70c727923f6db46c3e"), 32); ck_assert_mem_eq(node.public_key, fromhex("03cbcaa9c98c877a26977d00825c956a238e8dddfbd322cce4f74b0b5bd6ace4a7"), 33); @@ -143,6 +150,7 @@ START_TEST(test_bip32_vector_2) // [Chain m/0] r = hdnode_private_ckd(&node, 0); ck_assert_int_eq(r, 1); + ck_assert_int_eq(node.fingerprint, 0xbd16bee5); ck_assert_mem_eq(node.chain_code, fromhex("f0909affaa7ee7abe5dd4e100598d4dc53cd709d5a5c2cac40e7412f232f7c9c"), 32); ck_assert_mem_eq(node.private_key, fromhex("abe74a98f6c7eabee0428f53798f0ab8aa1bd37873999041703c742f15ac7e1e"), 32); ck_assert_mem_eq(node.public_key, fromhex("02fc9e5af0ac8d9b3cecfe2a888e2117ba3d089d8585886c9c826b6b22a98d12ea"), 33); @@ -151,6 +159,7 @@ START_TEST(test_bip32_vector_2) // [Chain m/0/2147483647'] r = hdnode_private_ckd_prime(&node, 2147483647); ck_assert_int_eq(r, 1); + ck_assert_int_eq(node.fingerprint, 0x5a61ff8e); ck_assert_mem_eq(node.chain_code, fromhex("be17a268474a6bb9c61e1d720cf6215e2a88c5406c4aee7b38547f585c9a37d9"), 32); ck_assert_mem_eq(node.private_key, fromhex("877c779ad9687164e9c2f4f0f4ff0340814392330693ce95a58fe18fd52e6e93"), 32); ck_assert_mem_eq(node.public_key, fromhex("03c01e7425647bdefa82b12d9bad5e3e6865bee0502694b94ca58b666abc0a5c3b"), 33); @@ -159,6 +168,7 @@ START_TEST(test_bip32_vector_2) // [Chain m/0/2147483647'/1] r = hdnode_private_ckd(&node, 1); ck_assert_int_eq(r, 1); + ck_assert_int_eq(node.fingerprint, 0xd8ab4937); ck_assert_mem_eq(node.chain_code, fromhex("f366f48f1ea9f2d1d3fe958c95ca84ea18e4c4ddb9366c336c927eb246fb38cb"), 32); ck_assert_mem_eq(node.private_key, fromhex("704addf544a06e5ee4bea37098463c23613da32020d604506da8c0518e1da4b7"), 32); ck_assert_mem_eq(node.public_key, fromhex("03a7d1d856deb74c508e05031f9895dab54626251b3806e16b4bd12e781a7df5b9"), 33); @@ -167,6 +177,7 @@ START_TEST(test_bip32_vector_2) // [Chain m/0/2147483647'/1/2147483646'] r = hdnode_private_ckd_prime(&node, 2147483646); ck_assert_int_eq(r, 1); + ck_assert_int_eq(node.fingerprint, 0x78412e3a); ck_assert_mem_eq(node.chain_code, fromhex("637807030d55d01f9a0cb3a7839515d796bd07706386a6eddf06cc29a65a0e29"), 32); ck_assert_mem_eq(node.private_key, fromhex("f1c7c871a54a804afe328b4c83a1c33b8e5ff48f5087273f04efa83b247d6a2d"), 32); ck_assert_mem_eq(node.public_key, fromhex("02d2b36900396c9282fa14628566582f206a5dd0bcc8d5e892611806cafb0301f0"), 33); @@ -175,6 +186,7 @@ START_TEST(test_bip32_vector_2) // [Chain m/0/2147483647'/1/2147483646'/2] r = hdnode_private_ckd(&node, 2); ck_assert_int_eq(r, 1); + ck_assert_int_eq(node.fingerprint, 0x31a507b8); ck_assert_mem_eq(node.chain_code, fromhex("9452b549be8cea3ecb7a84bec10dcfd94afe4d129ebfd3b3cb58eedf394ed271"), 32); ck_assert_mem_eq(node.private_key, fromhex("bb7d39bdb83ecf58f2fd82b6d918341cbef428661ef01ab97c28a4842125ac23"), 32); ck_assert_mem_eq(node.public_key, fromhex("024d902e1a2fc7a8755ab5b694c575fce742c48d9ff192e63df5193e4c7afe1f9c"), 33); @@ -187,6 +199,7 @@ START_TEST(test_bip32_vector_2) // [Chain m/0] r = hdnode_public_ckd(&node, 0); ck_assert_int_eq(r, 1); + ck_assert_int_eq(node.fingerprint, 0xbd16bee5); ck_assert_mem_eq(node.chain_code, fromhex("f0909affaa7ee7abe5dd4e100598d4dc53cd709d5a5c2cac40e7412f232f7c9c"), 32); ck_assert_mem_eq(node.private_key, fromhex("0000000000000000000000000000000000000000000000000000000000000000"), 32); ck_assert_mem_eq(node.public_key, fromhex("02fc9e5af0ac8d9b3cecfe2a888e2117ba3d089d8585886c9c826b6b22a98d12ea"), 33); From c0ee25c85173f1f184ebb8effb3952789aad9ffa Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 21 Jan 2014 18:38:44 +0100 Subject: [PATCH 066/627] don't use implicit versions in bip32 --- bip32.c | 42 ++++++++++++++++++++++++++++-------------- bip32.h | 13 +++++++------ tests.c | 6 +++--- 3 files changed, 38 insertions(+), 23 deletions(-) diff --git a/bip32.c b/bip32.c index a37041e48..5acfd6d59 100644 --- a/bip32.c +++ b/bip32.c @@ -7,30 +7,44 @@ #include "sha2.h" #include "ripemd160.h" -uint8_t hdnode_coin_version = 0x00; - -void hdnode_from_pub(uint32_t version, uint32_t depth, uint32_t fingerprint, uint32_t child_num, uint8_t *chain_code, uint8_t *public_key, HDNode *out) +void hdnode_from_xpub(uint8_t version_byte, uint32_t version, uint32_t depth, uint32_t fingerprint, uint32_t child_num, uint8_t *chain_code, uint8_t *public_key, HDNode *out) { out->version = version; out->depth = depth; out->fingerprint = fingerprint; out->child_num = child_num; - memset(out->private_key, 0, 32); memcpy(out->chain_code, chain_code, 32); + memset(out->private_key, 0, 32); memcpy(out->public_key, public_key, 33); + out->version_byte = version_byte; hdnode_fill_address(out); } -void hdnode_from_seed(uint8_t *seed, int seed_len, HDNode *out) +void hdnode_from_xprv(uint8_t version_byte, uint32_t version, uint32_t depth, uint32_t fingerprint, uint32_t child_num, uint8_t *chain_code, uint8_t *private_key, HDNode *out) { - out->version = 0x0488ADE4; // main-net + out->version = version; + out->depth = depth; + out->fingerprint = fingerprint; + out->child_num = child_num; + memcpy(out->chain_code, chain_code, 32); + memcpy(out->private_key, private_key, 32); + hdnode_fill_public_key(out); + out->version_byte = version_byte; + hdnode_fill_address(out); +} + +void hdnode_from_seed(uint8_t version_byte, uint32_t version, uint8_t *seed, int seed_len, HDNode *out) +{ + uint8_t I[32 + 32]; + out->version = version; out->depth = 0; out->fingerprint = 0x00000000; out->child_num = 0; - // this can be done because private_key[32] and chain_code[32] - // form a continuous 64 byte block in the memory - hmac_sha512((uint8_t *)"Bitcoin seed", 12, seed, seed_len, out->private_key); + hmac_sha512((uint8_t *)"Bitcoin seed", 12, seed, seed_len, I); + memcpy(out->chain_code, I + 32, 32); + memcpy(out->private_key, I, 32); hdnode_fill_public_key(out); + out->version_byte = version_byte; hdnode_fill_address(out); } @@ -56,8 +70,8 @@ int hdnode_private_ckd(HDNode *inout, uint32_t i) bn_read_be(inout->private_key, &a); hmac_sha512(inout->chain_code, 32, data, sizeof(data), I); - memcpy(inout->private_key, I, 32); memcpy(inout->chain_code, I + 32, 32); + memcpy(inout->private_key, I, 32); bn_read_be(inout->private_key, &b); bn_addmod(&a, &b, &order256k1); @@ -110,12 +124,12 @@ int hdnode_public_ckd(HDNode *inout, uint32_t i) return 1; } -void hdnode_fill_public_key(HDNode *xprv) +void hdnode_fill_public_key(HDNode *node) { - ecdsa_get_public_key33(xprv->private_key, xprv->public_key); + ecdsa_get_public_key33(node->private_key, node->public_key); } -void hdnode_fill_address(HDNode *xprv) +void hdnode_fill_address(HDNode *node) { - ecdsa_get_address(xprv->public_key, hdnode_coin_version, xprv->address); + ecdsa_get_address(node->public_key, node->version_byte, node->address); } diff --git a/bip32.h b/bip32.h index 605b182f6..a49ba8519 100644 --- a/bip32.h +++ b/bip32.h @@ -8,17 +8,18 @@ typedef struct { uint32_t depth; uint32_t fingerprint; uint32_t child_num; - uint8_t private_key[32]; uint8_t chain_code[32]; + uint8_t private_key[32]; uint8_t public_key[33]; + uint8_t version_byte; char address[35]; } HDNode; -extern uint8_t hdnode_coin_version; +void hdnode_from_xpub(uint8_t version_byte, uint32_t version, uint32_t depth, uint32_t fingerprint, uint32_t child_num, uint8_t *chain_code, uint8_t *public_key, HDNode *out); -void hdnode_from_pub(uint32_t version, uint32_t depth, uint32_t fingerprint, uint32_t child_num, uint8_t *chain_code, uint8_t *public_key, HDNode *out); +void hdnode_from_xprv(uint8_t version_byte, uint32_t version, uint32_t depth, uint32_t fingerprint, uint32_t child_num, uint8_t *chain_code, uint8_t *private_key, HDNode *out); -void hdnode_from_seed(uint8_t *seed, int seed_len, HDNode *out); +void hdnode_from_seed(uint8_t version_byte, uint32_t version, uint8_t *seed, int seed_len, HDNode *out); #define hdnode_private_ckd_prime(X, I) hdnode_private_ckd((X), ((I) | 0x80000000)) @@ -26,8 +27,8 @@ int hdnode_private_ckd(HDNode *inout, uint32_t i); int hdnode_public_ckd(HDNode *inout, uint32_t i); -void hdnode_fill_public_key(HDNode *xprv); +void hdnode_fill_public_key(HDNode *node); -void hdnode_fill_address(HDNode *xprv); +void hdnode_fill_address(HDNode *node); #endif diff --git a/tests.c b/tests.c index 8ec319d0e..779657e89 100644 --- a/tests.c +++ b/tests.c @@ -80,7 +80,7 @@ START_TEST(test_bip32_vector_1) HDNode node; // init m - hdnode_from_seed(fromhex("000102030405060708090a0b0c0d0e0f"), 16, &node); + hdnode_from_seed(0x00, 0x0488B21E, fromhex("000102030405060708090a0b0c0d0e0f"), 16, &node); // [Chain m] ck_assert_int_eq(node.fingerprint, 0x00000000); @@ -138,7 +138,7 @@ START_TEST(test_bip32_vector_2) int r; // init m - hdnode_from_seed(fromhex("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), 64, &node); + hdnode_from_seed(0x00, 0x0488B21E, fromhex("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), 64, &node); // [Chain m] ck_assert_int_eq(node.fingerprint, 0x00000000); @@ -193,7 +193,7 @@ START_TEST(test_bip32_vector_2) ck_assert_str_eq(node.address, "14UKfRV9ZPUp6ZC9PLhqbRtxdihW9em3xt"); // init m - hdnode_from_seed(fromhex("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), 64, &node); + hdnode_from_seed(0x00, 0x0488B21E, fromhex("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), 64, &node); // test public derivation // [Chain m/0] From 7dc057c903a8b78f43961201e7f269c08d0e3a0a Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 27 Jan 2014 19:57:44 +0100 Subject: [PATCH 067/627] add testcases for address generation fix bug for version != 0 process uncompressed pubkeys as well --- ecdsa.c | 13 +++++++++---- tests.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 4 deletions(-) diff --git a/ecdsa.c b/ecdsa.c index cbe88ea8b..ff9d534b4 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -302,7 +302,11 @@ void ecdsa_get_address(const uint8_t *pub_key, uint8_t version, char *addr) bignum256 c; int i, l; - SHA256_Raw(pub_key, 33, a); + if (pub_key[0] == 0x04) { + SHA256_Raw(pub_key, 65, a); + } else { + SHA256_Raw(pub_key, 33, a); + } b[0] = version; ripemd160(a, 32, b + 1); @@ -321,9 +325,10 @@ void ecdsa_get_address(const uint8_t *pub_key, uint8_t version, char *addr) p++; } - if (a[0] == 0) { - *p = '1'; - p++; + i = 7; + while (a[i] == 0) { + *p = code[0]; + p++; i++; } *p = 0; diff --git a/tests.c b/tests.c index 779657e89..d89929370 100644 --- a/tests.c +++ b/tests.c @@ -442,6 +442,55 @@ START_TEST(test_mnemonic) } END_TEST +START_TEST(test_address) +{ + char address[35]; + uint8_t pub_key[65]; + + memcpy(pub_key, fromhex("0226659c1cf7321c178c07437150639ff0c5b7679c7ea195253ed9abda2e081a37"), 33); + ecdsa_get_address(pub_key, 0, address); ck_assert_str_eq(address, "139MaMHp3Vjo8o4x8N1ZLWEtovLGvBsg6s"); + ecdsa_get_address(pub_key, 111, address); ck_assert_str_eq(address, "mhfJsQNnrXB3uuYZqvywARTDfuvyjg4RBh"); + ecdsa_get_address(pub_key, 52, address); ck_assert_str_eq(address, "MxiimznnxsqMfLKTQBL8Z2PoY9jKpjgkCu"); + ecdsa_get_address(pub_key, 48, address); ck_assert_str_eq(address, "LMNJqZbe89yrPbm7JVzrcXJf28hZ1rKPaH"); + + memcpy(pub_key, fromhex("025b1654a0e78d28810094f6c5a96b8efb8a65668b578f170ac2b1f83bc63ba856"), 33); + ecdsa_get_address(pub_key, 0, address); ck_assert_str_eq(address, "19Ywfm3witp6C1yBMy4NRYHY2347WCRBfQ"); + ecdsa_get_address(pub_key, 111, address); ck_assert_str_eq(address, "mp4txp8vXvFLy8So5Y2kFTVrt2epN6YzdP"); + ecdsa_get_address(pub_key, 52, address); ck_assert_str_eq(address, "N58JsQYveGueiZDgdnNwe4SSkGTAToutAY"); + ecdsa_get_address(pub_key, 48, address); ck_assert_str_eq(address, "LTmtvyMmoZ49SpfLY73fhZMJEFRPdyohKh"); + + memcpy(pub_key, fromhex("03433f246a12e6486a51ff08802228c61cf895175a9b49ed4766ea9a9294a3c7fe"), 33); + ecdsa_get_address(pub_key, 0, address); ck_assert_str_eq(address, "1FWE2bn3MWhc4QidcF6AvEWpK77sSi2cAP"); + ecdsa_get_address(pub_key, 111, address); ck_assert_str_eq(address, "mv2BKes2AY8rqXCFKp4Yk9j9B6iaMfWRLN"); + ecdsa_get_address(pub_key, 52, address); ck_assert_str_eq(address, "NB5bEFH2GtoAawy8t4Qk8kfj3LWvQs3MhB"); + ecdsa_get_address(pub_key, 48, address); ck_assert_str_eq(address, "LZjBHp5sSAwfKDQnnP5UCFaaXKV9YheGxQ"); + + memcpy(pub_key, fromhex("03aeb03abeee0f0f8b4f7a5d65ce31f9570cef9f72c2dd8a19b4085a30ab033d48"), 33); + ecdsa_get_address(pub_key, 0, address); ck_assert_str_eq(address, "1yrZb8dhdevoqpUEGi2tUccUEeiMKeLcs"); + ecdsa_get_address(pub_key, 111, address); ck_assert_str_eq(address, "mgVoreDcWf6BaxJ5wqgQiPpwLEFRLSr8U8"); + ecdsa_get_address(pub_key, 52, address); ck_assert_str_eq(address, "MwZDmEdcd1kVLP4yW62c6zmXCU3mNbveDo"); + ecdsa_get_address(pub_key, 48, address); ck_assert_str_eq(address, "LLCopoSTnHtz4eWdQQhLAVgNgT1zTi4QBK"); + + memcpy(pub_key, fromhex("0496e8f2093f018aff6c2e2da5201ee528e2c8accbf9cac51563d33a7bb74a016054201c025e2a5d96b1629b95194e806c63eb96facaedc733b1a4b70ab3b33e3a"), 65); + ecdsa_get_address(pub_key, 0, address); ck_assert_str_eq(address, "194SZbL75xCCGBbKtMsyWLE5r9s2V6mhVM"); + ecdsa_get_address(pub_key, 111, address); ck_assert_str_eq(address, "moaPreR5tydT3J4wbvrMLFSQi9TjPCiZc6"); + ecdsa_get_address(pub_key, 52, address); ck_assert_str_eq(address, "N4domEq61LHkniqqABCYirNzaPG5NRU8GH"); + ecdsa_get_address(pub_key, 48, address); ck_assert_str_eq(address, "LTHPpodwAcSFWzHV4VsGnMHr4NEJajMnKX"); + + memcpy(pub_key, fromhex("0498010f8a687439ff497d3074beb4519754e72c4b6220fb669224749591dde416f3961f8ece18f8689bb32235e436874d2174048b86118a00afbd5a4f33a24f0f"), 65); + ecdsa_get_address(pub_key, 0, address); ck_assert_str_eq(address, "1A2WfBD4BJFwYHFPc5KgktqtbdJLBuVKc4"); + ecdsa_get_address(pub_key, 111, address); ck_assert_str_eq(address, "mpYTxEJ2zKhCKPj1KeJ4ap4DTcu39T3uzD"); + ecdsa_get_address(pub_key, 52, address); ck_assert_str_eq(address, "N5bsrpi36gMW4pVtsteFyQzoKrhPE7nkxK"); + ecdsa_get_address(pub_key, 48, address); ck_assert_str_eq(address, "LUFTvPWtFxVzo5wYnDJz2uueoqfcMYiuxH"); + + memcpy(pub_key, fromhex("04f80490839af36d13701ec3f9eebdac901b51c362119d74553a3c537faff31b17e2a59ebddbdac9e87b816307a7ed5b826b8f40b92719086238e1bebf19b77a4d"), 65); + ecdsa_get_address(pub_key, 0, address); ck_assert_str_eq(address, "19J81hrPnQxg9UGx45ibTieCkb2ttm8CLL"); + ecdsa_get_address(pub_key, 111, address); ck_assert_str_eq(address, "mop5JkwNbSPvvakZmegyHdrXcadbjLazww"); + ecdsa_get_address(pub_key, 52, address); ck_assert_str_eq(address, "N4sVDMMNho4Eg1XTKu3AgEo7UpRwq3aNbn"); + ecdsa_get_address(pub_key, 48, address); ck_assert_str_eq(address, "LTX5GvADs5CjQGy7EDhtjjhxxoQB2Uhicd"); +} +END_TEST + // define test suite and cases Suite *test_suite(void) { @@ -462,6 +511,10 @@ Suite *test_suite(void) tcase_add_test(tc, test_verify_speed); suite_add_tcase(s, tc); + tc = tcase_create("addresses"); + tcase_add_test(tc, test_address); + suite_add_tcase(s, tc); + tc = tcase_create("rijndael"); tcase_add_test(tc, test_rijndael); suite_add_tcase(s, tc); From 2e4ec7fe0a4b71bff34fa12b47bb0751fc6e995a Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 30 Jan 2014 20:34:05 +0100 Subject: [PATCH 068/627] introduce ecdsa_address_to_hash160 --- bignum.c | 23 +++++++++++++++++++++++ bignum.h | 4 ++++ ecdsa.c | 26 ++++++++++++++++++++++++++ ecdsa.h | 1 + tests.c | 23 ++++++++++++++++++++++- 5 files changed, 76 insertions(+), 1 deletion(-) diff --git a/bignum.c b/bignum.c index 5ad5d89f3..5117d0bed 100644 --- a/bignum.c +++ b/bignum.c @@ -154,6 +154,29 @@ void bn_mod(bignum256 *x, const bignum256 *prime) } } +// a = a + b +void bn_addi(bignum256 *a, uint32_t b) +{ + uint64_t t = a->val[0]; + t += b; + a->val[0] = t & 0x3FFFFFFFu; + t >>= 30; + a->val[1] += t; +} + +// a = a * b +void bn_muli(bignum256 *a, uint32_t b) +{ + uint64_t t = 0; + int i; + for (i = 0; i < 8; i++) { + t = (uint64_t)(a->val[i]) * b + t; + a->val[i] = t & 0x3FFFFFFFu; + t >>= 30; + } + a->val[8] += t; +} + // x = k * x // both inputs and result may be bigger than prime but not bigger than 2 * prime void bn_multiply(const bignum256 *k, bignum256 *x, const bignum256 *prime) diff --git a/bignum.h b/bignum.h index 928f56fc6..293d8120f 100644 --- a/bignum.h +++ b/bignum.h @@ -73,6 +73,10 @@ void bn_rshift(bignum256 *a); void bn_mod(bignum256 *x, const bignum256 *prime); +void bn_addi(bignum256 *a, uint32_t b); + +void bn_muli(bignum256 *a, uint32_t b); + void bn_multiply(const bignum256 *k, bignum256 *x, const bignum256 *prime); void bn_fast_mod(bignum256 *x, const bignum256 *prime); diff --git a/ecdsa.c b/ecdsa.c index ff9d534b4..ae93334be 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -342,6 +342,32 @@ void ecdsa_get_address(const uint8_t *pub_key, uint8_t version, char *addr) } } +int ecdsa_address_to_hash160(const char *addr, uint8_t *hash) +{ + if (!addr) return 0; + const char code[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; + bignum256 num; + uint8_t buf[32]; + bn_zero(&num); + uint32_t k; + int i; + for (i = 0; i < strlen(addr); i++) { + bn_muli(&num, 58); + for (k = 0; k <= strlen(code); k++) { + if (code[k] == 0) { // char not found -> invalid address + return 0; + } + if (addr[i] == code[k]) { + bn_addi(&num, k); + break; + } + } + } + bn_write_be(&num, buf); + memcpy(hash, buf + 8, 20); + return 1; +} + int ecdsa_read_pubkey(const uint8_t *pub_key, curve_point *pub) { if (pub_key[0] == 0x04) { diff --git a/ecdsa.h b/ecdsa.h index 62b34cb43..1b504ee9f 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -40,6 +40,7 @@ int ecdsa_sign(const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, ui void ecdsa_get_public_key33(const uint8_t *priv_key, uint8_t *pub_key); void ecdsa_get_public_key65(const uint8_t *priv_key, uint8_t *pub_key); void ecdsa_get_address(const uint8_t *pub_key, uint8_t version, char *addr); +int ecdsa_address_to_hash160(const char *addr, uint8_t *hash); int ecdsa_read_pubkey(const uint8_t *pub_key, curve_point *pub); int ecdsa_verify(const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, uint32_t msg_len); diff --git a/tests.c b/tests.c index d89929370..58e6103c4 100644 --- a/tests.c +++ b/tests.c @@ -491,6 +491,23 @@ START_TEST(test_address) } END_TEST +START_TEST(test_address_to_hash) +{ + uint8_t hash[20]; + + ecdsa_address_to_hash160("1JwSSubhmg6iPtRjtyqhUYYH7bZg3Lfy1T", hash); ck_assert_mem_eq(hash, fromhex("c4c5d791fcb4654a1ef5e03fe0ad3d9c598f9827"), 20); + ecdsa_address_to_hash160("myTPjxggahXyAzuMcYp5JTkbybANyLsYBW", hash); ck_assert_mem_eq(hash, fromhex("c4c5d791fcb4654a1ef5e03fe0ad3d9c598f9827"), 20); + ecdsa_address_to_hash160("NEWoeZ6gh4CGvRgFAoAGh4hBqpxizGT6gZ", hash); ck_assert_mem_eq(hash, fromhex("c4c5d791fcb4654a1ef5e03fe0ad3d9c598f9827"), 20); + ecdsa_address_to_hash160("LdAPi7uXrLLmeh7u57pzkZc3KovxEDYRJq", hash); ck_assert_mem_eq(hash, fromhex("c4c5d791fcb4654a1ef5e03fe0ad3d9c598f9827"), 20); + + ecdsa_address_to_hash160("1C7zdTfnkzmr13HfA2vNm5SJYRK6nEKyq8", hash); ck_assert_mem_eq(hash, fromhex("79fbfc3f34e7745860d76137da68f362380c606c"), 20); + ecdsa_address_to_hash160("mrdwvWkma2D6n9mGsbtkazedQQuoksnqJV", hash); ck_assert_mem_eq(hash, fromhex("79fbfc3f34e7745860d76137da68f362380c606c"), 20); + ecdsa_address_to_hash160("N7hMq7AmgNsQXaYARrEwybbDGei9mcPNqr", hash); ck_assert_mem_eq(hash, fromhex("79fbfc3f34e7745860d76137da68f362380c606c"), 20); + ecdsa_address_to_hash160("LWLwtfycqf1uFqypLAug36W4kdgNwrZdNs", hash); ck_assert_mem_eq(hash, fromhex("79fbfc3f34e7745860d76137da68f362380c606c"), 20); +} +END_TEST + + // define test suite and cases Suite *test_suite(void) { @@ -511,10 +528,14 @@ Suite *test_suite(void) tcase_add_test(tc, test_verify_speed); suite_add_tcase(s, tc); - tc = tcase_create("addresses"); + tc = tcase_create("address"); tcase_add_test(tc, test_address); suite_add_tcase(s, tc); + tc = tcase_create("address_to_hash"); + tcase_add_test(tc, test_address_to_hash); + suite_add_tcase(s, tc); + tc = tcase_create("rijndael"); tcase_add_test(tc, test_rijndael); suite_add_tcase(s, tc); From a40a077613d6b0b990dfe16853ba5b5b28e6d1c8 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 31 Jan 2014 15:26:51 +0100 Subject: [PATCH 069/627] rework ecdsa_address_to_hash160 into ecdsa_address_decode --- ecdsa.c | 13 +++++++++--- ecdsa.h | 2 +- tests.c | 61 +++++++++++++++++++++++++++++++++++++++++++-------------- 3 files changed, 57 insertions(+), 19 deletions(-) diff --git a/ecdsa.c b/ecdsa.c index ae93334be..6954ac59d 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -342,12 +342,12 @@ void ecdsa_get_address(const uint8_t *pub_key, uint8_t version, char *addr) } } -int ecdsa_address_to_hash160(const char *addr, uint8_t *hash) +int ecdsa_address_decode(const char *addr, uint8_t *out) { if (!addr) return 0; const char code[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; bignum256 num; - uint8_t buf[32]; + uint8_t buf[32], check[32]; bn_zero(&num); uint32_t k; int i; @@ -364,7 +364,14 @@ int ecdsa_address_to_hash160(const char *addr, uint8_t *hash) } } bn_write_be(&num, buf); - memcpy(hash, buf + 8, 20); + // compute address hash + SHA256_Raw(buf + 7, 21, check); + SHA256_Raw(check, 32, check); + // check if valid + if (memcmp(buf + 7 + 21, check, 4) != 0) { + return 0; + } + memcpy(out, buf + 7, 21); return 1; } diff --git a/ecdsa.h b/ecdsa.h index 1b504ee9f..e1e9d3ffb 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -40,7 +40,7 @@ int ecdsa_sign(const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, ui void ecdsa_get_public_key33(const uint8_t *priv_key, uint8_t *pub_key); void ecdsa_get_public_key65(const uint8_t *priv_key, uint8_t *pub_key); void ecdsa_get_address(const uint8_t *pub_key, uint8_t version, char *addr); -int ecdsa_address_to_hash160(const char *addr, uint8_t *hash); +int ecdsa_address_decode(const char *addr, uint8_t *out); int ecdsa_read_pubkey(const uint8_t *pub_key, curve_point *pub); int ecdsa_verify(const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, uint32_t msg_len); diff --git a/tests.c b/tests.c index 58e6103c4..a188171e4 100644 --- a/tests.c +++ b/tests.c @@ -491,23 +491,54 @@ START_TEST(test_address) } END_TEST -START_TEST(test_address_to_hash) +START_TEST(test_address_decode) { - uint8_t hash[20]; - - ecdsa_address_to_hash160("1JwSSubhmg6iPtRjtyqhUYYH7bZg3Lfy1T", hash); ck_assert_mem_eq(hash, fromhex("c4c5d791fcb4654a1ef5e03fe0ad3d9c598f9827"), 20); - ecdsa_address_to_hash160("myTPjxggahXyAzuMcYp5JTkbybANyLsYBW", hash); ck_assert_mem_eq(hash, fromhex("c4c5d791fcb4654a1ef5e03fe0ad3d9c598f9827"), 20); - ecdsa_address_to_hash160("NEWoeZ6gh4CGvRgFAoAGh4hBqpxizGT6gZ", hash); ck_assert_mem_eq(hash, fromhex("c4c5d791fcb4654a1ef5e03fe0ad3d9c598f9827"), 20); - ecdsa_address_to_hash160("LdAPi7uXrLLmeh7u57pzkZc3KovxEDYRJq", hash); ck_assert_mem_eq(hash, fromhex("c4c5d791fcb4654a1ef5e03fe0ad3d9c598f9827"), 20); - - ecdsa_address_to_hash160("1C7zdTfnkzmr13HfA2vNm5SJYRK6nEKyq8", hash); ck_assert_mem_eq(hash, fromhex("79fbfc3f34e7745860d76137da68f362380c606c"), 20); - ecdsa_address_to_hash160("mrdwvWkma2D6n9mGsbtkazedQQuoksnqJV", hash); ck_assert_mem_eq(hash, fromhex("79fbfc3f34e7745860d76137da68f362380c606c"), 20); - ecdsa_address_to_hash160("N7hMq7AmgNsQXaYARrEwybbDGei9mcPNqr", hash); ck_assert_mem_eq(hash, fromhex("79fbfc3f34e7745860d76137da68f362380c606c"), 20); - ecdsa_address_to_hash160("LWLwtfycqf1uFqypLAug36W4kdgNwrZdNs", hash); ck_assert_mem_eq(hash, fromhex("79fbfc3f34e7745860d76137da68f362380c606c"), 20); + int res; + uint8_t decode[21]; + // byte 0 : address type + // bytes 1-20 : pubkey hash 160 + res = ecdsa_address_decode("1JwSSubhmg6iPtRjtyqhUYYH7bZg3Lfy1T", decode); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(decode, fromhex("00c4c5d791fcb4654a1ef5e03fe0ad3d9c598f9827"), 21); + + res = ecdsa_address_decode("myTPjxggahXyAzuMcYp5JTkbybANyLsYBW", decode); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(decode, fromhex("6fc4c5d791fcb4654a1ef5e03fe0ad3d9c598f9827"), 21); + + res = ecdsa_address_decode("NEWoeZ6gh4CGvRgFAoAGh4hBqpxizGT6gZ", decode); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(decode, fromhex("34c4c5d791fcb4654a1ef5e03fe0ad3d9c598f9827"), 21); + + res = ecdsa_address_decode("LdAPi7uXrLLmeh7u57pzkZc3KovxEDYRJq", decode); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(decode, fromhex("30c4c5d791fcb4654a1ef5e03fe0ad3d9c598f9827"), 21); + + res = ecdsa_address_decode("1C7zdTfnkzmr13HfA2vNm5SJYRK6nEKyq8", decode); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(decode, fromhex("0079fbfc3f34e7745860d76137da68f362380c606c"), 21); + + res = ecdsa_address_decode("mrdwvWkma2D6n9mGsbtkazedQQuoksnqJV", decode); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(decode, fromhex("6f79fbfc3f34e7745860d76137da68f362380c606c"), 21); + + res = ecdsa_address_decode("N7hMq7AmgNsQXaYARrEwybbDGei9mcPNqr", decode); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(decode, fromhex("3479fbfc3f34e7745860d76137da68f362380c606c"), 21); + + res = ecdsa_address_decode("LWLwtfycqf1uFqypLAug36W4kdgNwrZdNs", decode); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(decode, fromhex("3079fbfc3f34e7745860d76137da68f362380c606c"), 21); + + // invalid char + res = ecdsa_address_decode("1JwSSubhmg6i000jtyqhUYYH7bZg3Lfy1T", decode); + ck_assert_int_eq(res, 0); + + // invalid address + res = ecdsa_address_decode("1111Subhmg6iPtRjtyqhUYYH7bZg3Lfy1T", decode); + ck_assert_int_eq(res, 0); } END_TEST - // define test suite and cases Suite *test_suite(void) { @@ -532,8 +563,8 @@ Suite *test_suite(void) tcase_add_test(tc, test_address); suite_add_tcase(s, tc); - tc = tcase_create("address_to_hash"); - tcase_add_test(tc, test_address_to_hash); + tc = tcase_create("address_decode"); + tcase_add_test(tc, test_address_decode); suite_add_tcase(s, tc); tc = tcase_create("rijndael"); From 73489fbd339f7b62a93b3fafd41843ac8bdaef91 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 2 Feb 2014 20:36:03 +0100 Subject: [PATCH 070/627] split signing into ecdsa_sign_digest and ecdsa_sign/ecdsa_sign_double --- ecdsa.c | 33 +++++++++++++++++++++++---------- ecdsa.h | 2 ++ 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/ecdsa.c b/ecdsa.c index 6954ac59d..3fbfe27ab 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -195,28 +195,41 @@ int generate_k_rfc6979(bignum256 *secret, const uint8_t *priv_key, const uint8_t return 1; } -// uses secp256k1 curve -// priv_key is a 32 byte big endian stored number // msg is a data to be signed // msg_len is the message length -// sig is 64 bytes long array for the signature int ecdsa_sign(const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig) { - uint32_t i; uint8_t hash[32]; + SHA256_Raw(msg, msg_len, hash); + return ecdsa_sign_digest(priv_key, hash, sig); +} + +// msg is a data to be signed +// msg_len is the message length +int ecdsa_sign_double(const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig) +{ + uint8_t hash[32]; + SHA256_Raw(msg, msg_len, hash); + SHA256_Raw(hash, 32, hash); + return ecdsa_sign_digest(priv_key, hash, sig); +} + +// uses secp256k1 curve +// priv_key is a 32 byte big endian stored number +// sig is 64 bytes long array for the signature +// digest is 32 bytes of digest +int ecdsa_sign_digest(const uint8_t *priv_key, const uint8_t *digest, uint8_t *sig) +{ + uint32_t i; curve_point R; bignum256 k, z; bignum256 *da = &R.y; - // compute hash function of message - SHA256_Raw(msg, msg_len, hash); - // if double hash is required uncomment the following line: - // SHA256_Raw(hash, 32, hash); - bn_read_be(hash, &z); + bn_read_be(digest, &z); #if USE_RFC6979 // generate K deterministically - if (generate_k_rfc6979(&k, priv_key, hash) != 0) { + if (generate_k_rfc6979(&k, priv_key, digest) != 0) { return 1; } #else diff --git a/ecdsa.h b/ecdsa.h index e1e9d3ffb..4c0bdd9ce 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -37,6 +37,8 @@ void point_double(curve_point *cp); void scalar_multiply(bignum256 *k, curve_point *res); int ecdsa_sign(const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig); +int ecdsa_sign_double(const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig); +int ecdsa_sign_digest(const uint8_t *priv_key, const uint8_t *digest, uint8_t *sig); void ecdsa_get_public_key33(const uint8_t *priv_key, uint8_t *pub_key); void ecdsa_get_public_key65(const uint8_t *priv_key, uint8_t *pub_key); void ecdsa_get_address(const uint8_t *pub_key, uint8_t version, char *addr); From 81f462a5c591e209d3165df3b26d2ff42906c874 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 2 Feb 2014 22:01:43 +0100 Subject: [PATCH 071/627] add ecdsa_sig_to_der --- ecdsa.c | 28 ++++++++++++++++++++++++++++ ecdsa.h | 1 + tests.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+) diff --git a/ecdsa.c b/ecdsa.c index 3fbfe27ab..9a489a1f7 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -490,3 +490,31 @@ int ecdsa_verify(const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, // all OK return 0; } + +int ecdsa_sig_to_der(const uint8_t *sig, uint8_t *der) +{ + int p1, p2; + p1 = sig[0] >= 0x80; + p2 = sig[32] >= 0x80; + der[0] = 0x30; // sequence + der[1] = (1 + 1 + p1 + 32) + (1 + 1 + p2 + 32); // total len + der[2] = 0x02; // int + if (p1) { + der[3] = 33; + der[4] = 0x00; + memcpy(der + 5, sig, 32); + } else { + der[3] = 32; + memcpy(der + 4, sig, 32); + } + der[36 + p1] = 0x02; // int + if (p2) { + der[37 + p1] = 33; + der[38 + p1] = 0x00; + memcpy(der + 39 + p1, sig + 32, 32); + } else { + der[37 + p1] = 32; + memcpy(der + 38 + p1, sig + 32, 32); + } + return der[1] + 2; +} diff --git a/ecdsa.h b/ecdsa.h index 4c0bdd9ce..8b73db703 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -45,5 +45,6 @@ void ecdsa_get_address(const uint8_t *pub_key, uint8_t version, char *addr); int ecdsa_address_decode(const char *addr, uint8_t *out); int ecdsa_read_pubkey(const uint8_t *pub_key, curve_point *pub); int ecdsa_verify(const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, uint32_t msg_len); +int ecdsa_sig_to_der(const uint8_t *sig, uint8_t *der); #endif diff --git a/tests.c b/tests.c index a188171e4..2140978b7 100644 --- a/tests.c +++ b/tests.c @@ -539,6 +539,44 @@ START_TEST(test_address_decode) } END_TEST +START_TEST(test_ecdsa_der) +{ + uint8_t sig[64], der[70]; + int res; + + memcpy(sig, fromhex("9a0b7be0d4ed3146ee262b42202841834698bb3ee39c24e7437df208b8b70771"), 32); + memcpy(sig + 32, fromhex("2b79ab1e7736219387dffe8d615bbdba87e11477104b867ef47afed1a5ede781"), 32); + res = ecdsa_sig_to_der(sig, der); + ck_assert_int_eq(res, 71); + ck_assert_mem_eq(der, fromhex("30450221009a0b7be0d4ed3146ee262b42202841834698bb3ee39c24e7437df208b8b7077102202b79ab1e7736219387dffe8d615bbdba87e11477104b867ef47afed1a5ede781"), 71); + + memcpy(sig, fromhex("6666666666666666666666666666666666666666666666666666666666666666"), 32); + memcpy(sig + 32, fromhex("7777777777777777777777777777777777777777777777777777777777777777"), 32); + res = ecdsa_sig_to_der(sig, der); + ck_assert_int_eq(res, 70); + ck_assert_mem_eq(der, fromhex("30440220666666666666666666666666666666666666666666666666666666666666666602207777777777777777777777777777777777777777777777777777777777777777"), 70); + + memcpy(sig, fromhex("6666666666666666666666666666666666666666666666666666666666666666"), 32); + memcpy(sig + 32, fromhex("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"), 32); + res = ecdsa_sig_to_der(sig, der); + ck_assert_int_eq(res, 71); + ck_assert_mem_eq(der, fromhex("304502206666666666666666666666666666666666666666666666666666666666666666022100eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"), 71); + + memcpy(sig, fromhex("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"), 32); + memcpy(sig + 32, fromhex("7777777777777777777777777777777777777777777777777777777777777777"), 32); + res = ecdsa_sig_to_der(sig, der); + ck_assert_int_eq(res, 71); + ck_assert_mem_eq(der, fromhex("3045022100eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee02207777777777777777777777777777777777777777777777777777777777777777"), 71); + + memcpy(sig, fromhex("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"), 32); + memcpy(sig + 32, fromhex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), 32); + res = ecdsa_sig_to_der(sig, der); + ck_assert_int_eq(res, 72); + ck_assert_mem_eq(der, fromhex("3046022100eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee022100ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), 72); +} +END_TEST + + // define test suite and cases Suite *test_suite(void) { @@ -567,6 +605,10 @@ Suite *test_suite(void) tcase_add_test(tc, test_address_decode); suite_add_tcase(s, tc); + tc = tcase_create("ecdsa_der"); + tcase_add_test(tc, test_ecdsa_der); + suite_add_tcase(s, tc); + tc = tcase_create("rijndael"); tcase_add_test(tc, test_rijndael); suite_add_tcase(s, tc); From 8aaebe761b74329f2073d30f67e5025f04f9552f Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 4 Feb 2014 18:55:17 +0100 Subject: [PATCH 072/627] introduce uncompress_coords --- ecdsa.c | 27 +++++++++++++++------------ ecdsa.h | 1 + 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/ecdsa.c b/ecdsa.c index 9a489a1f7..958ba2a52 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -388,6 +388,20 @@ int ecdsa_address_decode(const char *addr, uint8_t *out) return 1; } +void uncompress_coords(uint8_t odd, const bignum256 *x, bignum256 *y) +{ + // y^2 = x^3 + 0*x + 7 + memcpy(y, x, sizeof(bignum256)); // y is x + bn_multiply(x, y, &prime256k1); // y is x^2 + bn_multiply(x, y, &prime256k1); // y is x^3 + bn_addmodi(y, 7, &prime256k1); // y is x^3 + 7 + bn_sqrt(y, &prime256k1); // y = sqrt(y) + if ((odd & 0x01) != (y->val[0] & 1)) { + bn_substract(&prime256k1, y, y); // y = -y + bn_mod(y, &prime256k1); + } +} + int ecdsa_read_pubkey(const uint8_t *pub_key, curve_point *pub) { if (pub_key[0] == 0x04) { @@ -395,22 +409,11 @@ int ecdsa_read_pubkey(const uint8_t *pub_key, curve_point *pub) bn_read_be(pub_key + 33, &(pub->y)); return 1; } - if (pub_key[0] == 0x02 || pub_key[0] == 0x03) { // compute missing y coords - // y^2 = x^3 + 0*x + 7 bn_read_be(pub_key + 1, &(pub->x)); - bn_read_be(pub_key + 1, &(pub->y)); // y is x - bn_multiply(&(pub->x), &(pub->y), &prime256k1); // y is x^2 - bn_multiply(&(pub->x), &(pub->y), &prime256k1); // y is x^3 - bn_addmodi(&(pub->y), 7, &prime256k1); // y is x^3 + 7 - bn_sqrt(&(pub->y), &prime256k1); // y = sqrt(y) - if ((pub_key[0] & 0x01) != (pub->y.val[0] & 1)) { - bn_substract(&prime256k1, &(pub->y), &(pub->y)); // y = -y - bn_mod(&(pub->y), &prime256k1); - } + uncompress_coords(pub_key[0], &(pub->x), &(pub->y)); return 1; } - // error return 0; } diff --git a/ecdsa.h b/ecdsa.h index 8b73db703..8ff95cd19 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -35,6 +35,7 @@ void point_add(const curve_point *cp1, curve_point *cp2); void point_double(curve_point *cp); void scalar_multiply(bignum256 *k, curve_point *res); +void uncompress_coords(uint8_t odd, const bignum256 *x, bignum256 *y); int ecdsa_sign(const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig); int ecdsa_sign_double(const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig); From fc144587e6bcdbeb23dd6b15bf036c1f818294b6 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 4 Feb 2014 19:12:43 +0100 Subject: [PATCH 073/627] introduce ecdsa_verify_digest --- ecdsa.c | 25 ++++++++++++++++++------- ecdsa.h | 2 ++ 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/ecdsa.c b/ecdsa.c index 958ba2a52..7bb830ada 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -423,18 +423,29 @@ int ecdsa_read_pubkey(const uint8_t *pub_key, curve_point *pub) // signature - 64 bytes signature // msg is a data that was signed // msg_len is the message length + +int ecdsa_verify(const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, uint32_t msg_len) +{ + uint8_t hash[32]; + SHA256_Raw(msg, msg_len, hash); + return ecdsa_verify_digest(pub_key, sig, hash); +} + +int ecdsa_verify_double(const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, uint32_t msg_len) +{ + uint8_t hash[32]; + SHA256_Raw(msg, msg_len, hash); + SHA256_Raw(hash, 32, hash); + return ecdsa_verify_digest(pub_key, sig, hash); +} + // returns 0 if verification succeeded // it is assumed that public key is valid otherwise calling this does not make much sense -int ecdsa_verify(const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, uint32_t msg_len) +int ecdsa_verify_digest(const uint8_t *pub_key, const uint8_t *sig, const uint8_t *digest) { int i, j; - uint8_t hash[32]; curve_point pub, res; bignum256 r, s, z; - // compute hash function of message - SHA256_Raw(msg, msg_len, hash); - // if double hash is required uncomment the following line: - // SHA256_Raw(hash, 32, hash); if (!ecdsa_read_pubkey(pub_key, &pub)) { return 1; @@ -443,7 +454,7 @@ int ecdsa_verify(const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, bn_read_be(sig, &r); bn_read_be(sig + 32, &s); - bn_read_be(hash, &z); + bn_read_be(digest, &z); if (bn_is_zero(&r) || bn_is_zero(&s) || (!bn_is_less(&r, &order256k1)) || diff --git a/ecdsa.h b/ecdsa.h index 8ff95cd19..97661c4aa 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -46,6 +46,8 @@ void ecdsa_get_address(const uint8_t *pub_key, uint8_t version, char *addr); int ecdsa_address_decode(const char *addr, uint8_t *out); int ecdsa_read_pubkey(const uint8_t *pub_key, curve_point *pub); int ecdsa_verify(const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, uint32_t msg_len); +int ecdsa_verify_double(const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, uint32_t msg_len); +int ecdsa_verify_digest(const uint8_t *pub_key, const uint8_t *sig, const uint8_t *digest); int ecdsa_sig_to_der(const uint8_t *sig, uint8_t *der); #endif From 6a856479a846d83a22d71571329c2c9a5e68c9fe Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 5 Feb 2014 23:38:37 +0100 Subject: [PATCH 074/627] introduce point_multiply --- ecdsa.c | 32 +++++++++++++++++++++++++++++--- ecdsa.h | 3 ++- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/ecdsa.c b/ecdsa.c index 7bb830ada..92b9a95d0 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -92,8 +92,35 @@ void point_double(curve_point *cp) memcpy(&(cp->y), &yr, sizeof(bignum256)); } +// res = k * p +void point_multiply(const bignum256 *k, const curve_point *p, curve_point *res) +{ + int i, j; + // result is zero + int is_zero = 1; + curve_point curr; + // initial res + memcpy(&curr, p, sizeof(curve_point)); + for (i = 0; i < 9; i++) { + for (j = 0; j < 30; j++) { + if (i == 8 && (k->val[i] >> j) == 0) break; + if (k->val[i] & (1u << j)) { + if (is_zero) { + memcpy(res, &curr, sizeof(curve_point)); + is_zero = 0; + } else { + point_add(&curr, res); + } + } + point_double(&curr); + } + } + bn_mod(&(res->x), &prime256k1); + bn_mod(&(res->y), &prime256k1); +} + // res = k * G -void scalar_multiply(bignum256 *k, curve_point *res) +void scalar_multiply(const bignum256 *k, curve_point *res) { int i, j; // result is zero @@ -397,8 +424,7 @@ void uncompress_coords(uint8_t odd, const bignum256 *x, bignum256 *y) bn_addmodi(y, 7, &prime256k1); // y is x^3 + 7 bn_sqrt(y, &prime256k1); // y = sqrt(y) if ((odd & 0x01) != (y->val[0] & 1)) { - bn_substract(&prime256k1, y, y); // y = -y - bn_mod(y, &prime256k1); + bn_substract_noprime(&prime256k1, y, y); // y = -y } } diff --git a/ecdsa.h b/ecdsa.h index 97661c4aa..956a310ab 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -34,7 +34,8 @@ void point_add(const curve_point *cp1, curve_point *cp2); void point_double(curve_point *cp); -void scalar_multiply(bignum256 *k, curve_point *res); +void point_multiply(const bignum256 *k, const curve_point *p, curve_point *res); +void scalar_multiply(const bignum256 *k, curve_point *res); void uncompress_coords(uint8_t odd, const bignum256 *x, bignum256 *y); int ecdsa_sign(const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig); From d433bcfa103bbeae736dcdda5bdaf13c6544450b Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 8 Feb 2014 15:55:03 +0100 Subject: [PATCH 075/627] fix ecdsa_sig_to_der --- ecdsa.c | 53 +++++++++++++++++++++++++++++++---------------------- tests.c | 24 ++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 22 deletions(-) diff --git a/ecdsa.c b/ecdsa.c index 92b9a95d0..65aef7d5c 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -533,28 +533,37 @@ int ecdsa_verify_digest(const uint8_t *pub_key, const uint8_t *sig, const uint8_ int ecdsa_sig_to_der(const uint8_t *sig, uint8_t *der) { - int p1, p2; - p1 = sig[0] >= 0x80; - p2 = sig[32] >= 0x80; - der[0] = 0x30; // sequence - der[1] = (1 + 1 + p1 + 32) + (1 + 1 + p2 + 32); // total len - der[2] = 0x02; // int - if (p1) { - der[3] = 33; - der[4] = 0x00; - memcpy(der + 5, sig, 32); - } else { - der[3] = 32; - memcpy(der + 4, sig, 32); + int i; + uint8_t *p = der, *len, *len1, *len2; + *p = 0x30; p++; // sequence + *p = 0x00; len = p; p++; // len(sequence) + + *p = 0x02; p++; // integer + *p = 0x00; len1 = p; p++; // len(integer) + + // process R + i = 0; + while (sig[i] == 0 && i < 32) { i++; } // skip leading zeroes + if (sig[i] >= 0x80) { // put zero in output if MSB set + *p = 0x00; p++; *len1 = *len1 + 1; } - der[36 + p1] = 0x02; // int - if (p2) { - der[37 + p1] = 33; - der[38 + p1] = 0x00; - memcpy(der + 39 + p1, sig + 32, 32); - } else { - der[37 + p1] = 32; - memcpy(der + 38 + p1, sig + 32, 32); + while (i < 32) { // copy bytes to output + *p = sig[i]; p++; *len1 = *len1 + 1; i++; + } + + *p = 0x02; p++; // integer + *p = 0x00; len2 = p; p++; // len(integer) + + // process S + i = 32; + while (sig[i] == 0 && i < 64) { i++; } // skip leading zeroes + if (sig[i] >= 0x80) { // put zero in output if MSB set + *p = 0x00; p++; *len2 = *len2 + 1; } - return der[1] + 2; + while (i < 64) { // copy bytes to output + *p = sig[i]; p++; *len2 = *len2 + 1; i++; + } + + *len = *len1 + *len2 + 4; + return *len + 2; } diff --git a/tests.c b/tests.c index 2140978b7..c1f972ba8 100644 --- a/tests.c +++ b/tests.c @@ -573,6 +573,30 @@ START_TEST(test_ecdsa_der) res = ecdsa_sig_to_der(sig, der); ck_assert_int_eq(res, 72); ck_assert_mem_eq(der, fromhex("3046022100eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee022100ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), 72); + + memcpy(sig, fromhex("0000000000000000000000000000000000000000000000000000000000000066"), 32); + memcpy(sig + 32, fromhex("0000000000000000000000000000000000000000000000000000000000000077"), 32); + res = ecdsa_sig_to_der(sig, der); + ck_assert_int_eq(res, 8); + ck_assert_mem_eq(der, fromhex("3006020166020177"), 8); + + memcpy(sig, fromhex("0000000000000000000000000000000000000000000000000000000000000066"), 32); + memcpy(sig + 32, fromhex("00000000000000000000000000000000000000000000000000000000000000ee"), 32); + res = ecdsa_sig_to_der(sig, der); + ck_assert_int_eq(res, 9); + ck_assert_mem_eq(der, fromhex("3007020166020200ee"), 9); + + memcpy(sig, fromhex("00000000000000000000000000000000000000000000000000000000000000ee"), 32); + memcpy(sig + 32, fromhex("0000000000000000000000000000000000000000000000000000000000000077"), 32); + res = ecdsa_sig_to_der(sig, der); + ck_assert_int_eq(res, 9); + ck_assert_mem_eq(der, fromhex("3007020200ee020177"), 9); + + memcpy(sig, fromhex("00000000000000000000000000000000000000000000000000000000000000ee"), 32); + memcpy(sig + 32, fromhex("00000000000000000000000000000000000000000000000000000000000000ff"), 32); + res = ecdsa_sig_to_der(sig, der); + ck_assert_int_eq(res, 10); + ck_assert_mem_eq(der, fromhex("3008020200ee020200ff"), 10); } END_TEST From 50fb43127f5915b8b84ac5dc6c8589946f229fcc Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 8 Feb 2014 19:12:07 +0100 Subject: [PATCH 076/627] use -Wextra --- Makefile | 2 +- ecdsa.c | 2 +- tests.c | 6 ++++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index ad65fb8d0..e96dee000 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ CC = gcc -CFLAGS = -Wall -Os +CFLAGS = -Wall -Wextra -Os OBJS = bignum.o ecdsa.o secp256k1.o sha2.o rand.o hmac.o bip32.o ripemd160.o bip39.o pbkdf2.o OBJS += aescrypt.o aeskey.o aestab.o diff --git a/ecdsa.c b/ecdsa.c index 65aef7d5c..92a18c305 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -390,7 +390,7 @@ int ecdsa_address_decode(const char *addr, uint8_t *out) uint8_t buf[32], check[32]; bn_zero(&num); uint32_t k; - int i; + size_t i; for (i = 0; i < strlen(addr); i++) { bn_muli(&num, 58); for (k = 0; k <= strlen(code); k++) { diff --git a/tests.c b/tests.c index c1f972ba8..a61c2aa40 100644 --- a/tests.c +++ b/tests.c @@ -235,7 +235,8 @@ END_TEST START_TEST(test_sign_speed) { uint8_t sig[64], priv_key[32], msg[256]; - int i, res; + size_t i; + int res; for (i = 0; i < sizeof(msg); i++) { msg[i] = i * 1103515245; @@ -262,7 +263,8 @@ END_TEST START_TEST(test_verify_speed) { uint8_t sig[64], pub_key33[33], pub_key65[65], msg[256]; - int i, res; + size_t i; + int res; for (i = 0; i < sizeof(msg); i++) { msg[i] = i * 1103515245; From 67eb76fd1b6eca4895f90814360a231d90ad381a Mon Sep 17 00:00:00 2001 From: Jan Pochyla Date: Sat, 15 Feb 2014 15:39:17 +0100 Subject: [PATCH 077/627] llu -> ull for MSVC compatibility --- bignum.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bignum.c b/bignum.c index 5117d0bed..aca045483 100644 --- a/bignum.c +++ b/bignum.c @@ -209,11 +209,11 @@ void bn_multiply(const bignum256 *k, bignum256 *x, const bignum256 *prime) // estimate (res / prime) coef = (res[i] >> 16) + (res[i + 1] << 14); // substract (coef * prime) from res - temp = 0x1000000000000000llu + res[i - 8] - prime->val[0] * (uint64_t)coef; + temp = 0x1000000000000000ull + res[i - 8] - prime->val[0] * (uint64_t)coef; res[i - 8] = temp & 0x3FFFFFFF; for (j = 1; j < 9; j++) { temp >>= 30; - temp += 0xFFFFFFFC0000000llu + res[i - 8 + j] - prime->val[j] * (uint64_t)coef; + temp += 0xFFFFFFFC0000000ull + res[i - 8 + j] - prime->val[j] * (uint64_t)coef; res[i - 8 + j] = temp & 0x3FFFFFFF; } } @@ -233,11 +233,11 @@ void bn_fast_mod(bignum256 *x, const bignum256 *prime) coef = x->val[8] >> 16; if (!coef) return; // substract (coef * prime) from x - temp = 0x1000000000000000llu + x->val[0] - prime->val[0] * (uint64_t)coef; + temp = 0x1000000000000000ull + x->val[0] - prime->val[0] * (uint64_t)coef; x->val[0] = temp & 0x3FFFFFFF; for (j = 1; j < 9; j++) { temp >>= 30; - temp += 0xFFFFFFFC0000000llu + x->val[j] - prime->val[j] * (uint64_t)coef; + temp += 0xFFFFFFFC0000000ull + x->val[j] - prime->val[j] * (uint64_t)coef; x->val[j] = temp & 0x3FFFFFFF; } } From 2e22e731d635b83373782b173d4fbe1fc652df5f Mon Sep 17 00:00:00 2001 From: Jan Pochyla Date: Sat, 15 Feb 2014 15:40:20 +0100 Subject: [PATCH 078/627] remove field name struct init for MSVC compatibility --- secp256k1.c | 1548 +++++++++++++++++++++++++-------------------------- 1 file changed, 774 insertions(+), 774 deletions(-) diff --git a/secp256k1.c b/secp256k1.c index 57a5a8677..3781b5b85 100644 --- a/secp256k1.c +++ b/secp256k1.c @@ -24,795 +24,795 @@ #include "secp256k1.h" const bignum256 prime256k1 = { -.val = {0x3ffffc2f, 0x3ffffffb, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0xffff}}; +/*.val =*/{0x3ffffc2f, 0x3ffffffb, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0xffff}}; const curve_point G256k1 = { -.x = { .val = {0x16f81798, 0x27ca056c, 0x1ce28d95, 0x26ff36cb, 0x70b0702, 0x18a573a, 0xbbac55a, 0x199fbe77, 0x79be}}, -.y = { .val = {0x3b10d4b8, 0x311f423f, 0x28554199, 0x5ed1229, 0x1108a8fd, 0x13eff038, 0x3c4655da, 0x369dc9a8, 0x483a}}}; +/*.x =*/{/*.val =*/{0x16f81798, 0x27ca056c, 0x1ce28d95, 0x26ff36cb, 0x70b0702, 0x18a573a, 0xbbac55a, 0x199fbe77, 0x79be}}, +/*.y =*/{/*.val =*/{0x3b10d4b8, 0x311f423f, 0x28554199, 0x5ed1229, 0x1108a8fd, 0x13eff038, 0x3c4655da, 0x369dc9a8, 0x483a}}}; const bignum256 order256k1 = { -.val = {0x10364141, 0x3f497a33, 0x348a03bb, 0x2bb739ab, 0x3ffffeba, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0xffff}}; +/*.val =*/{0x10364141, 0x3f497a33, 0x348a03bb, 0x2bb739ab, 0x3ffffeba, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0xffff}}; const bignum256 order256k1_half = { -.val = {0x281b20a0, 0x3fa4bd19, 0x3a4501dd, 0x15db9cd5, 0x3fffff5d, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x7fff}}; +/*.val =*/{0x281b20a0, 0x3fa4bd19, 0x3a4501dd, 0x15db9cd5, 0x3fffff5d, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x7fff}}; const bignum256 three_over_two256k1 = { -.val = {0x3ffffe19, 0x3ffffffd, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x7fff}}; +/*.val =*/{0x3ffffe19, 0x3ffffffd, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x7fff}}; #if USE_PRECOMPUTED_IV const bignum256 secp256k1_iv[256] = { -{ .val = {0x868192a, 0x20e02474, 0x24a059d, 0x2c88ffb7, 0x32b761bc, 0x1b0b0a57, 0x383999c4, 0x6414554, 0xc9bd}}, -{ .val = {0x4340c95, 0x3070123a, 0x212502ce, 0x16447fdb, 0x395bb0de, 0xd85852b, 0x1c1ccce2, 0x2320a2aa, 0x64de}}, -{ .val = {0x21a0462, 0x1838091b, 0x30928167, 0xb223fed, 0x3cadd86f, 0x6c2c295, 0xe0e6671, 0x11905155, 0xb26f}}, -{ .val = {0x210d0231, 0x2c1c048d, 0x384940b3, 0x25911ff6, 0x3e56ec37, 0x2361614a, 0x27073338, 0x28c828aa, 0x5937}}, -{ .val = {0x30867f30, 0x360e0244, 0x1c24a059, 0x32c88ffb, 0x1f2b761b, 0x11b0b0a5, 0x1383999c, 0x34641455, 0xac9b}}, -{ .val = {0x18433f98, 0x3b070122, 0x2e12502c, 0x396447fd, 0x2f95bb0d, 0x8d85852, 0x29c1ccce, 0x3a320a2a, 0x564d}}, -{ .val = {0xc219fcc, 0x1d838091, 0x37092816, 0x3cb223fe, 0x17cadd86, 0x46c2c29, 0x14e0e667, 0x3d190515, 0x2b26}}, -{ .val = {0x2610cfe6, 0xec1c048, 0x1b84940b, 0x1e5911ff, 0x2be56ec3, 0x22361614, 0x2a707333, 0x1e8c828a, 0x1593}}, -{ .val = {0x130867f3, 0x2760e024, 0x2dc24a05, 0x2f2c88ff, 0x15f2b761, 0x311b0b0a, 0x15383999, 0x2f464145, 0xac9}}, -{ .val = {0x9843211, 0x33b07010, 0x36e12502, 0x3796447f, 0xaf95bb0, 0x388d8585, 0x2a9c1ccc, 0x37a320a2, 0x8564}}, -{ .val = {0x4c21720, 0x19d83806, 0x3b709281, 0x1bcb223f, 0x257cadd8, 0x1c46c2c2, 0x154e0e66, 0x1bd19051, 0xc2b2}}, -{ .val = {0x2610b90, 0x2cec1c03, 0x3db84940, 0xde5911f, 0x12be56ec, 0xe236161, 0x2aa70733, 0xde8c828, 0x6159}}, -{ .val = {0x213085c8, 0x16760e01, 0x3edc24a0, 0x6f2c88f, 0x295f2b76, 0x2711b0b0, 0x15538399, 0x26f46414, 0x30ac}}, -{ .val = {0x309842e4, 0xb3b0700, 0x3f6e1250, 0x3796447, 0x14af95bb, 0x3388d858, 0xaa9c1cc, 0x137a320a, 0x1856}}, -{ .val = {0x184c2172, 0x59d8380, 0x3fb70928, 0x21bcb223, 0xa57cadd, 0x19c46c2c, 0x554e0e6, 0x9bd1905, 0xc2b}}, -{ .val = {0xc2610b9, 0x2cec1c0, 0x3fdb8494, 0x30de5911, 0x52be56e, 0xce23616, 0x22aa7073, 0x24de8c82, 0x615}}, -{ .val = {0x6130674, 0x16760de, 0x3fedc24a, 0x186f2c88, 0x295f2b7, 0x26711b0b, 0x11553839, 0x326f4641, 0x830a}}, -{ .val = {0x309833a, 0xb3b06f, 0x1ff6e125, 0x2c379644, 0x214af95b, 0x33388d85, 0x28aa9c1c, 0x1937a320, 0x4185}}, -{ .val = {0x2184c19d, 0x2059d837, 0xffb7092, 0x361bcb22, 0x30a57cad, 0x199c46c2, 0x14554e0e, 0x2c9bd190, 0x20c2}}, -{ .val = {0x30c25ee6, 0x102cec19, 0x7fdb849, 0x3b0de591, 0x1852be56, 0xcce2361, 0xa2aa707, 0x164de8c8, 0x9061}}, -{ .val = {0x38612f73, 0x2816760c, 0x23fedc24, 0x1d86f2c8, 0x2c295f2b, 0x266711b0, 0x5155383, 0x2b26f464, 0x4830}}, -{ .val = {0x1c3095d1, 0x140b3b04, 0x11ff6e12, 0x2ec37964, 0x1614af95, 0x333388d8, 0x28aa9c1, 0x15937a32, 0xa418}}, -{ .val = {0xe184900, 0xa059d80, 0x8ffb709, 0x3761bcb2, 0xb0a57ca, 0x3999c46c, 0x14554e0, 0xac9bd19, 0xd20c}}, -{ .val = {0x70c2480, 0x2502cec0, 0x47fdb84, 0x1bb0de59, 0x5852be5, 0x1ccce236, 0x20a2aa70, 0x564de8c, 0x6906}}, -{ .val = {0x3861240, 0x12816760, 0x223fedc2, 0x2dd86f2c, 0x2c295f2, 0xe66711b, 0x10515538, 0x2b26f46, 0x3483}}, -{ .val = {0x1c30920, 0x940b3b0, 0x111ff6e1, 0x16ec3796, 0x21614af9, 0x733388d, 0x828aa9c, 0x215937a3, 0x1a41}}, -{ .val = {0xe18490, 0x24a059d8, 0x88ffb70, 0x2b761bcb, 0x30b0a57c, 0x3999c46, 0x2414554e, 0x30ac9bd1, 0xd20}}, -{ .val = {0x70c248, 0x12502cec, 0x2447fdb8, 0x15bb0de5, 0x185852be, 0x1ccce23, 0x320a2aa7, 0x18564de8, 0x690}}, -{ .val = {0x386124, 0x9281676, 0x3223fedc, 0xadd86f2, 0x2c2c295f, 0x20e66711, 0x19051553, 0xc2b26f4, 0x348}}, -{ .val = {0x1c3092, 0x4940b3b, 0x1911ff6e, 0x256ec379, 0x361614af, 0x30733388, 0xc828aa9, 0x615937a, 0x1a4}}, -{ .val = {0x200e1849, 0x24a059d, 0x2c88ffb7, 0x32b761bc, 0x1b0b0a57, 0x383999c4, 0x6414554, 0x30ac9bd, 0xd2}}, -{ .val = {0x30070a3c, 0x212502cc, 0x16447fdb, 0x395bb0de, 0xd85852b, 0x1c1ccce2, 0x2320a2aa, 0x18564de, 0x8069}}, -{ .val = {0x1803851e, 0x30928166, 0xb223fed, 0x3cadd86f, 0x6c2c295, 0xe0e6671, 0x11905155, 0x20c2b26f, 0x4034}}, -{ .val = {0xc01c28f, 0x384940b3, 0x25911ff6, 0x3e56ec37, 0x2361614a, 0x27073338, 0x28c828aa, 0x10615937, 0x201a}}, -{ .val = {0x2600df5f, 0x1c24a057, 0x32c88ffb, 0x1f2b761b, 0x11b0b0a5, 0x1383999c, 0x34641455, 0x830ac9b, 0x900d}}, -{ .val = {0x33006dc7, 0x2e125029, 0x396447fd, 0x2f95bb0d, 0x8d85852, 0x29c1ccce, 0x3a320a2a, 0x2418564d, 0xc806}}, -{ .val = {0x398034fb, 0x37092812, 0x3cb223fe, 0x17cadd86, 0x46c2c29, 0x14e0e667, 0x3d190515, 0x120c2b26, 0xe403}}, -{ .val = {0x1cc01895, 0x1b849407, 0x1e5911ff, 0x2be56ec3, 0x22361614, 0x2a707333, 0x1e8c828a, 0x29061593, 0xf201}}, -{ .val = {0x2e600a62, 0x2dc24a01, 0x2f2c88ff, 0x15f2b761, 0x311b0b0a, 0x15383999, 0x2f464145, 0x34830ac9, 0xf900}}, -{ .val = {0x37300531, 0x36e12500, 0x3796447f, 0xaf95bb0, 0x388d8585, 0x2a9c1ccc, 0x37a320a2, 0x1a418564, 0x7c80}}, -{ .val = {0x1b9800b0, 0x3b70927e, 0x1bcb223f, 0x257cadd8, 0x1c46c2c2, 0x154e0e66, 0x1bd19051, 0xd20c2b2, 0xbe40}}, -{ .val = {0xdcc0058, 0x3db8493f, 0xde5911f, 0x12be56ec, 0xe236161, 0x2aa70733, 0xde8c828, 0x6906159, 0x5f20}}, -{ .val = {0x26e6002c, 0x3edc249f, 0x6f2c88f, 0x295f2b76, 0x2711b0b0, 0x15538399, 0x26f46414, 0x34830ac, 0x2f90}}, -{ .val = {0x33730016, 0x3f6e124f, 0x3796447, 0x14af95bb, 0x3388d858, 0xaa9c1cc, 0x137a320a, 0x1a41856, 0x17c8}}, -{ .val = {0x39b9800b, 0x3fb70927, 0x21bcb223, 0xa57cadd, 0x19c46c2c, 0x554e0e6, 0x9bd1905, 0xd20c2b, 0xbe4}}, -{ .val = {0x3cdcbe1d, 0x3fdb8491, 0x30de5911, 0x52be56e, 0xce23616, 0x22aa7073, 0x24de8c82, 0x690615, 0x85f2}}, -{ .val = {0x3e6e5d26, 0x3fedc246, 0x186f2c88, 0x295f2b7, 0x26711b0b, 0x11553839, 0x326f4641, 0x34830a, 0xc2f9}}, -{ .val = {0x1f372e93, 0x1ff6e123, 0x2c379644, 0x214af95b, 0x33388d85, 0x28aa9c1c, 0x1937a320, 0x201a4185, 0x617c}}, -{ .val = {0x2f9b9561, 0xffb708f, 0x361bcb22, 0x30a57cad, 0x199c46c2, 0x14554e0e, 0x2c9bd190, 0x100d20c2, 0xb0be}}, -{ .val = {0x37cdc8c8, 0x7fdb845, 0x3b0de591, 0x1852be56, 0xcce2361, 0xa2aa707, 0x164de8c8, 0x8069061, 0xd85f}}, -{ .val = {0x3be6e464, 0x23fedc22, 0x1d86f2c8, 0x2c295f2b, 0x266711b0, 0x5155383, 0x2b26f464, 0x24034830, 0x6c2f}}, -{ .val = {0x1df37232, 0x11ff6e11, 0x2ec37964, 0x1614af95, 0x333388d8, 0x28aa9c1, 0x15937a32, 0x3201a418, 0x3617}}, -{ .val = {0x2ef9b919, 0x8ffb708, 0x3761bcb2, 0xb0a57ca, 0x3999c46c, 0x14554e0, 0xac9bd19, 0x3900d20c, 0x1b0b}}, -{ .val = {0x177cdaa4, 0x47fdb82, 0x1bb0de59, 0x5852be5, 0x1ccce236, 0x20a2aa70, 0x564de8c, 0x3c806906, 0x8d85}}, -{ .val = {0xbbe6d52, 0x223fedc1, 0x2dd86f2c, 0x2c295f2, 0xe66711b, 0x10515538, 0x2b26f46, 0x3e403483, 0x46c2}}, -{ .val = {0x25df36a9, 0x111ff6e0, 0x16ec3796, 0x21614af9, 0x733388d, 0x828aa9c, 0x215937a3, 0x1f201a41, 0x2361}}, -{ .val = {0x12ef996c, 0x88ffb6e, 0x2b761bcb, 0x30b0a57c, 0x3999c46, 0x2414554e, 0x30ac9bd1, 0x2f900d20, 0x91b0}}, -{ .val = {0x977ccb6, 0x2447fdb7, 0x15bb0de5, 0x185852be, 0x1ccce23, 0x320a2aa7, 0x18564de8, 0x17c80690, 0x48d8}}, -{ .val = {0x24bbe65b, 0x3223fedb, 0xadd86f2, 0x2c2c295f, 0x20e66711, 0x19051553, 0xc2b26f4, 0xbe40348, 0x246c}}, -{ .val = {0x325df145, 0x1911ff6b, 0x256ec379, 0x361614af, 0x30733388, 0xc828aa9, 0x615937a, 0x5f201a4, 0x9236}}, -{ .val = {0x392ef6ba, 0x2c88ffb3, 0x32b761bc, 0x1b0b0a57, 0x383999c4, 0x6414554, 0x30ac9bd, 0x2f900d2, 0xc91b}}, -{ .val = {0x3c977b5d, 0x16447fd9, 0x395bb0de, 0xd85852b, 0x1c1ccce2, 0x2320a2aa, 0x18564de, 0x217c8069, 0x648d}}, -{ .val = {0x3e4bbbc6, 0xb223fea, 0x3cadd86f, 0x6c2c295, 0xe0e6671, 0x11905155, 0x20c2b26f, 0x30be4034, 0xb246}}, -{ .val = {0x1f25dde3, 0x25911ff5, 0x3e56ec37, 0x2361614a, 0x27073338, 0x28c828aa, 0x10615937, 0x185f201a, 0x5923}}, -{ .val = {0x2f92ed09, 0x32c88ff8, 0x1f2b761b, 0x11b0b0a5, 0x1383999c, 0x34641455, 0x830ac9b, 0x2c2f900d, 0xac91}}, -{ .val = {0x17c9749c, 0x396447fa, 0x2f95bb0d, 0x8d85852, 0x29c1ccce, 0x3a320a2a, 0x2418564d, 0x3617c806, 0xd648}}, -{ .val = {0xbe4ba4e, 0x3cb223fd, 0x17cadd86, 0x46c2c29, 0x14e0e667, 0x3d190515, 0x120c2b26, 0x1b0be403, 0x6b24}}, -{ .val = {0x25f25d27, 0x1e5911fe, 0x2be56ec3, 0x22361614, 0x2a707333, 0x1e8c828a, 0x29061593, 0xd85f201, 0x3592}}, -{ .val = {0x12f92cab, 0x2f2c88fd, 0x15f2b761, 0x311b0b0a, 0x15383999, 0x2f464145, 0x34830ac9, 0x6c2f900, 0x9ac9}}, -{ .val = {0x297c946d, 0x3796447c, 0xaf95bb0, 0x388d8585, 0x2a9c1ccc, 0x37a320a2, 0x1a418564, 0x23617c80, 0xcd64}}, -{ .val = {0x14be484e, 0x1bcb223c, 0x257cadd8, 0x1c46c2c2, 0x154e0e66, 0x1bd19051, 0xd20c2b2, 0x11b0be40, 0xe6b2}}, -{ .val = {0xa5f2427, 0xde5911e, 0x12be56ec, 0xe236161, 0x2aa70733, 0xde8c828, 0x6906159, 0x8d85f20, 0x7359}}, -{ .val = {0x52f902b, 0x6f2c88d, 0x295f2b76, 0x2711b0b0, 0x15538399, 0x26f46414, 0x34830ac, 0x246c2f90, 0xb9ac}}, -{ .val = {0x2297c62d, 0x3796444, 0x14af95bb, 0x3388d858, 0xaa9c1cc, 0x137a320a, 0x1a41856, 0x123617c8, 0xdcd6}}, -{ .val = {0x114be12e, 0x21bcb220, 0xa57cadd, 0x19c46c2c, 0x554e0e6, 0x9bd1905, 0xd20c2b, 0x91b0be4, 0xee6b}}, -{ .val = {0x8a5f097, 0x30de5910, 0x52be56e, 0xce23616, 0x22aa7073, 0x24de8c82, 0x690615, 0x248d85f2, 0x7735}}, -{ .val = {0x452f663, 0x186f2c86, 0x295f2b7, 0x26711b0b, 0x11553839, 0x326f4641, 0x34830a, 0x3246c2f9, 0xbb9a}}, -{ .val = {0x2297949, 0x2c379641, 0x214af95b, 0x33388d85, 0x28aa9c1c, 0x1937a320, 0x201a4185, 0x1923617c, 0xddcd}}, -{ .val = {0x2114babc, 0x361bcb1e, 0x30a57cad, 0x199c46c2, 0x14554e0e, 0x2c9bd190, 0x100d20c2, 0x2c91b0be, 0xeee6}}, -{ .val = {0x108a5d5e, 0x3b0de58f, 0x1852be56, 0xcce2361, 0xa2aa707, 0x164de8c8, 0x8069061, 0x1648d85f, 0x7773}}, -{ .val = {0x28452eaf, 0x1d86f2c7, 0x2c295f2b, 0x266711b0, 0x5155383, 0x2b26f464, 0x24034830, 0x2b246c2f, 0x3bb9}}, -{ .val = {0x3422956f, 0x2ec37961, 0x1614af95, 0x333388d8, 0x28aa9c1, 0x15937a32, 0x3201a418, 0x35923617, 0x9ddc}}, -{ .val = {0x3a1148cf, 0x3761bcae, 0xb0a57ca, 0x3999c46c, 0x14554e0, 0xac9bd19, 0x3900d20c, 0x1ac91b0b, 0xceee}}, -{ .val = {0x1d08a27f, 0x1bb0de55, 0x5852be5, 0x1ccce236, 0x20a2aa70, 0x564de8c, 0x3c806906, 0xd648d85, 0xe777}}, -{ .val = {0x2e844f57, 0x2dd86f28, 0x2c295f2, 0xe66711b, 0x10515538, 0x2b26f46, 0x3e403483, 0x26b246c2, 0xf3bb}}, -{ .val = {0x174225c3, 0x16ec3792, 0x21614af9, 0x733388d, 0x828aa9c, 0x215937a3, 0x1f201a41, 0x33592361, 0xf9dd}}, -{ .val = {0xba110f9, 0x2b761bc7, 0x30b0a57c, 0x3999c46, 0x2414554e, 0x30ac9bd1, 0x2f900d20, 0x39ac91b0, 0xfcee}}, -{ .val = {0x25d08694, 0x15bb0de1, 0x185852be, 0x1ccce23, 0x320a2aa7, 0x18564de8, 0x17c80690, 0x1cd648d8, 0xfe77}}, -{ .val = {0x32e8434a, 0xadd86f0, 0x2c2c295f, 0x20e66711, 0x19051553, 0xc2b26f4, 0xbe40348, 0x2e6b246c, 0x7f3b}}, -{ .val = {0x197421a5, 0x256ec378, 0x361614af, 0x30733388, 0xc828aa9, 0x615937a, 0x5f201a4, 0x37359236, 0x3f9d}}, -{ .val = {0xcba0eea, 0x32b761ba, 0x1b0b0a57, 0x383999c4, 0x6414554, 0x30ac9bd, 0x2f900d2, 0x3b9ac91b, 0x9fce}}, -{ .val = {0x65d0775, 0x395bb0dd, 0xd85852b, 0x1c1ccce2, 0x2320a2aa, 0x18564de, 0x217c8069, 0x1dcd648d, 0x4fe7}}, -{ .val = {0x232e81d2, 0x3cadd86c, 0x6c2c295, 0xe0e6671, 0x11905155, 0x20c2b26f, 0x30be4034, 0x2ee6b246, 0xa7f3}}, -{ .val = {0x119740e9, 0x3e56ec36, 0x2361614a, 0x27073338, 0x28c828aa, 0x10615937, 0x185f201a, 0x37735923, 0x53f9}}, -{ .val = {0x8cb9e8c, 0x1f2b7619, 0x11b0b0a5, 0x1383999c, 0x34641455, 0x830ac9b, 0x2c2f900d, 0x3bb9ac91, 0xa9fc}}, -{ .val = {0x2465cf46, 0x2f95bb0c, 0x8d85852, 0x29c1ccce, 0x3a320a2a, 0x2418564d, 0x3617c806, 0x1ddcd648, 0x54fe}}, -{ .val = {0x1232e7a3, 0x17cadd86, 0x46c2c29, 0x14e0e667, 0x3d190515, 0x120c2b26, 0x1b0be403, 0xeee6b24, 0x2a7f}}, -{ .val = {0x91971e9, 0x2be56ec1, 0x22361614, 0x2a707333, 0x1e8c828a, 0x29061593, 0xd85f201, 0x27773592, 0x953f}}, -{ .val = {0x248cb70c, 0x15f2b75e, 0x311b0b0a, 0x15383999, 0x2f464145, 0x34830ac9, 0x6c2f900, 0x33bb9ac9, 0xca9f}}, -{ .val = {0x12465b86, 0xaf95baf, 0x388d8585, 0x2a9c1ccc, 0x37a320a2, 0x1a418564, 0x23617c80, 0x39ddcd64, 0x654f}}, -{ .val = {0x29232dc3, 0x257cadd7, 0x1c46c2c2, 0x154e0e66, 0x1bd19051, 0xd20c2b2, 0x11b0be40, 0x3ceee6b2, 0x32a7}}, -{ .val = {0x349194f9, 0x12be56e9, 0xe236161, 0x2aa70733, 0xde8c828, 0x6906159, 0x8d85f20, 0x3e777359, 0x9953}}, -{ .val = {0x3a48c894, 0x295f2b72, 0x2711b0b0, 0x15538399, 0x26f46414, 0x34830ac, 0x246c2f90, 0x3f3bb9ac, 0xcca9}}, -{ .val = {0x1d24644a, 0x14af95b9, 0x3388d858, 0xaa9c1cc, 0x137a320a, 0x1a41856, 0x123617c8, 0x3f9ddcd6, 0x6654}}, -{ .val = {0x2e923225, 0xa57cadc, 0x19c46c2c, 0x554e0e6, 0x9bd1905, 0xd20c2b, 0x91b0be4, 0x1fceee6b, 0x332a}}, -{ .val = {0x1749172a, 0x52be56c, 0xce23616, 0x22aa7073, 0x24de8c82, 0x690615, 0x248d85f2, 0xfe77735, 0x9995}}, -{ .val = {0xba48b95, 0x295f2b6, 0x26711b0b, 0x11553839, 0x326f4641, 0x34830a, 0x3246c2f9, 0x27f3bb9a, 0x4cca}}, -{ .val = {0x5d243e2, 0x214af959, 0x33388d85, 0x28aa9c1c, 0x1937a320, 0x201a4185, 0x1923617c, 0x13f9ddcd, 0xa665}}, -{ .val = {0x22e921f1, 0x30a57cac, 0x199c46c2, 0x14554e0e, 0x2c9bd190, 0x100d20c2, 0x2c91b0be, 0x29fceee6, 0x5332}}, -{ .val = {0x11748f10, 0x1852be54, 0xcce2361, 0xa2aa707, 0x164de8c8, 0x8069061, 0x1648d85f, 0x14fe7773, 0xa999}}, -{ .val = {0x8ba4788, 0x2c295f2a, 0x266711b0, 0x5155383, 0x2b26f464, 0x24034830, 0x2b246c2f, 0x2a7f3bb9, 0x54cc}}, -{ .val = {0x45d23c4, 0x1614af95, 0x333388d8, 0x28aa9c1, 0x15937a32, 0x3201a418, 0x35923617, 0x153f9ddc, 0x2a66}}, -{ .val = {0x222e91e2, 0xb0a57ca, 0x3999c46c, 0x14554e0, 0xac9bd19, 0x3900d20c, 0x1ac91b0b, 0xa9fceee, 0x1533}}, -{ .val = {0x111748f1, 0x5852be5, 0x1ccce236, 0x20a2aa70, 0x564de8c, 0x3c806906, 0xd648d85, 0x254fe777, 0xa99}}, -{ .val = {0x288ba290, 0x2c295f0, 0xe66711b, 0x10515538, 0x2b26f46, 0x3e403483, 0x26b246c2, 0x32a7f3bb, 0x854c}}, -{ .val = {0x1445d148, 0x21614af8, 0x733388d, 0x828aa9c, 0x215937a3, 0x1f201a41, 0x33592361, 0x1953f9dd, 0x42a6}}, -{ .val = {0xa22e8a4, 0x30b0a57c, 0x3999c46, 0x2414554e, 0x30ac9bd1, 0x2f900d20, 0x39ac91b0, 0xca9fcee, 0x2153}}, -{ .val = {0x5117452, 0x185852be, 0x1ccce23, 0x320a2aa7, 0x18564de8, 0x17c80690, 0x1cd648d8, 0x2654fe77, 0x10a9}}, -{ .val = {0x288ba29, 0x2c2c295f, 0x20e66711, 0x19051553, 0xc2b26f4, 0xbe40348, 0x2e6b246c, 0x332a7f3b, 0x854}}, -{ .val = {0x21445b2c, 0x361614ad, 0x30733388, 0xc828aa9, 0x615937a, 0x5f201a4, 0x37359236, 0x19953f9d, 0x842a}}, -{ .val = {0x30a22d96, 0x1b0b0a56, 0x383999c4, 0x6414554, 0x30ac9bd, 0x2f900d2, 0x3b9ac91b, 0xcca9fce, 0x4215}}, -{ .val = {0x185116cb, 0xd85852b, 0x1c1ccce2, 0x2320a2aa, 0x18564de, 0x217c8069, 0x1dcd648d, 0x26654fe7, 0x210a}}, -{ .val = {0x2c28897d, 0x6c2c293, 0xe0e6671, 0x11905155, 0x20c2b26f, 0x30be4034, 0x2ee6b246, 0x1332a7f3, 0x9085}}, -{ .val = {0x361442d6, 0x23616147, 0x27073338, 0x28c828aa, 0x10615937, 0x185f201a, 0x37735923, 0x299953f9, 0xc842}}, -{ .val = {0x3b0a216b, 0x11b0b0a3, 0x1383999c, 0x34641455, 0x830ac9b, 0x2c2f900d, 0x3bb9ac91, 0x14cca9fc, 0x6421}}, -{ .val = {0x3d850ecd, 0x8d8584f, 0x29c1ccce, 0x3a320a2a, 0x2418564d, 0x3617c806, 0x1ddcd648, 0x2a6654fe, 0xb210}}, -{ .val = {0x3ec2857e, 0x46c2c25, 0x14e0e667, 0x3d190515, 0x120c2b26, 0x1b0be403, 0xeee6b24, 0x15332a7f, 0xd908}}, -{ .val = {0x3f6142bf, 0x22361612, 0x2a707333, 0x1e8c828a, 0x29061593, 0xd85f201, 0x27773592, 0xa99953f, 0x6c84}}, -{ .val = {0x1fb09f77, 0x311b0b07, 0x15383999, 0x2f464145, 0x34830ac9, 0x6c2f900, 0x33bb9ac9, 0x54cca9f, 0xb642}}, -{ .val = {0x2fd84dd3, 0x388d8581, 0x2a9c1ccc, 0x37a320a2, 0x1a418564, 0x23617c80, 0x39ddcd64, 0x2a6654f, 0xdb21}}, -{ .val = {0x37ec2501, 0x1c46c2be, 0x154e0e66, 0x1bd19051, 0xd20c2b2, 0x11b0be40, 0x3ceee6b2, 0x215332a7, 0xed90}}, -{ .val = {0x1bf61098, 0xe23615d, 0x2aa70733, 0xde8c828, 0x6906159, 0x8d85f20, 0x3e777359, 0x10a99953, 0xf6c8}}, -{ .val = {0x2dfb084c, 0x2711b0ae, 0x15538399, 0x26f46414, 0x34830ac, 0x246c2f90, 0x3f3bb9ac, 0x854cca9, 0x7b64}}, -{ .val = {0x16fd8426, 0x3388d857, 0xaa9c1cc, 0x137a320a, 0x1a41856, 0x123617c8, 0x3f9ddcd6, 0x42a6654, 0x3db2}}, -{ .val = {0x2b7ec213, 0x19c46c2b, 0x554e0e6, 0x9bd1905, 0xd20c2b, 0x91b0be4, 0x1fceee6b, 0x215332a, 0x1ed9}}, -{ .val = {0x35bf5f21, 0xce23613, 0x22aa7073, 0x24de8c82, 0x690615, 0x248d85f2, 0xfe77735, 0x210a9995, 0x8f6c}}, -{ .val = {0x3adfada8, 0x26711b07, 0x11553839, 0x326f4641, 0x34830a, 0x3246c2f9, 0x27f3bb9a, 0x10854cca, 0xc7b6}}, -{ .val = {0x3d6fd6d4, 0x33388d83, 0x28aa9c1c, 0x1937a320, 0x201a4185, 0x1923617c, 0x13f9ddcd, 0x842a665, 0x63db}}, -{ .val = {0x3eb7eb6a, 0x199c46c1, 0x14554e0e, 0x2c9bd190, 0x100d20c2, 0x2c91b0be, 0x29fceee6, 0x24215332, 0x31ed}}, -{ .val = {0x3f5bf5b5, 0xcce2360, 0xa2aa707, 0x164de8c8, 0x8069061, 0x1648d85f, 0x14fe7773, 0x3210a999, 0x18f6}}, -{ .val = {0x1fadf8f2, 0x266711ae, 0x5155383, 0x2b26f464, 0x24034830, 0x2b246c2f, 0x2a7f3bb9, 0x190854cc, 0x8c7b}}, -{ .val = {0xfd6fc79, 0x333388d7, 0x28aa9c1, 0x15937a32, 0x3201a418, 0x35923617, 0x153f9ddc, 0x2c842a66, 0x463d}}, -{ .val = {0x27eb7c54, 0x3999c469, 0x14554e0, 0xac9bd19, 0x3900d20c, 0x1ac91b0b, 0xa9fceee, 0x36421533, 0xa31e}}, -{ .val = {0x33f5be2a, 0x1ccce234, 0x20a2aa70, 0x564de8c, 0x3c806906, 0xd648d85, 0x254fe777, 0x1b210a99, 0x518f}}, -{ .val = {0x19fadf15, 0xe66711a, 0x10515538, 0x2b26f46, 0x3e403483, 0x26b246c2, 0x32a7f3bb, 0x2d90854c, 0x28c7}}, -{ .val = {0xcfd6da2, 0x733388b, 0x828aa9c, 0x215937a3, 0x1f201a41, 0x33592361, 0x1953f9dd, 0x36c842a6, 0x9463}}, -{ .val = {0x267eb6d1, 0x3999c45, 0x2414554e, 0x30ac9bd1, 0x2f900d20, 0x39ac91b0, 0xca9fcee, 0x3b642153, 0x4a31}}, -{ .val = {0x333f5980, 0x1ccce20, 0x320a2aa7, 0x18564de8, 0x17c80690, 0x1cd648d8, 0x2654fe77, 0x3db210a9, 0xa518}}, -{ .val = {0x199facc0, 0x20e66710, 0x19051553, 0xc2b26f4, 0xbe40348, 0x2e6b246c, 0x332a7f3b, 0x1ed90854, 0x528c}}, -{ .val = {0xccfd660, 0x30733388, 0xc828aa9, 0x615937a, 0x5f201a4, 0x37359236, 0x19953f9d, 0xf6c842a, 0x2946}}, -{ .val = {0x667eb30, 0x383999c4, 0x6414554, 0x30ac9bd, 0x2f900d2, 0x3b9ac91b, 0xcca9fce, 0x7b64215, 0x14a3}}, -{ .val = {0x333f598, 0x1c1ccce2, 0x2320a2aa, 0x18564de, 0x217c8069, 0x1dcd648d, 0x26654fe7, 0x23db210a, 0xa51}}, -{ .val = {0x199facc, 0xe0e6671, 0x11905155, 0x20c2b26f, 0x30be4034, 0x2ee6b246, 0x1332a7f3, 0x31ed9085, 0x528}}, -{ .val = {0x20ccfd66, 0x27073338, 0x28c828aa, 0x10615937, 0x185f201a, 0x37735923, 0x299953f9, 0x18f6c842, 0x294}}, -{ .val = {0x10667eb3, 0x1383999c, 0x34641455, 0x830ac9b, 0x2c2f900d, 0x3bb9ac91, 0x14cca9fc, 0xc7b6421, 0x14a}}, -{ .val = {0x8333d71, 0x29c1cccc, 0x3a320a2a, 0x2418564d, 0x3617c806, 0x1ddcd648, 0x2a6654fe, 0x63db210, 0x80a5}}, -{ .val = {0x4199cd0, 0x14e0e664, 0x3d190515, 0x120c2b26, 0x1b0be403, 0xeee6b24, 0x15332a7f, 0x231ed908, 0xc052}}, -{ .val = {0x20cce68, 0x2a707332, 0x1e8c828a, 0x29061593, 0xd85f201, 0x27773592, 0xa99953f, 0x118f6c84, 0x6029}}, -{ .val = {0x1066734, 0x15383999, 0x2f464145, 0x34830ac9, 0x6c2f900, 0x33bb9ac9, 0x54cca9f, 0x28c7b642, 0x3014}}, -{ .val = {0x2083339a, 0x2a9c1ccc, 0x37a320a2, 0x1a418564, 0x23617c80, 0x39ddcd64, 0x2a6654f, 0x1463db21, 0x180a}}, -{ .val = {0x104199cd, 0x154e0e66, 0x1bd19051, 0xd20c2b2, 0x11b0be40, 0x3ceee6b2, 0x215332a7, 0xa31ed90, 0xc05}}, -{ .val = {0x820cafe, 0x2aa70731, 0xde8c828, 0x6906159, 0x8d85f20, 0x3e777359, 0x10a99953, 0x2518f6c8, 0x8602}}, -{ .val = {0x2410657f, 0x15538398, 0x26f46414, 0x34830ac, 0x246c2f90, 0x3f3bb9ac, 0x854cca9, 0x128c7b64, 0x4301}}, -{ .val = {0x120830d7, 0xaa9c1ca, 0x137a320a, 0x1a41856, 0x123617c8, 0x3f9ddcd6, 0x42a6654, 0x29463db2, 0xa180}}, -{ .val = {0x9041683, 0x554e0e3, 0x9bd1905, 0xd20c2b, 0x91b0be4, 0x1fceee6b, 0x215332a, 0x14a31ed9, 0xd0c0}}, -{ .val = {0x24820959, 0x22aa706f, 0x24de8c82, 0x690615, 0x248d85f2, 0xfe77735, 0x210a9995, 0xa518f6c, 0xe860}}, -{ .val = {0x324102c4, 0x11553835, 0x326f4641, 0x34830a, 0x3246c2f9, 0x27f3bb9a, 0x10854cca, 0x528c7b6, 0xf430}}, -{ .val = {0x39208162, 0x28aa9c1a, 0x1937a320, 0x201a4185, 0x1923617c, 0x13f9ddcd, 0x842a665, 0x29463db, 0x7a18}}, -{ .val = {0x1c9040b1, 0x14554e0d, 0x2c9bd190, 0x100d20c2, 0x2c91b0be, 0x29fceee6, 0x24215332, 0x14a31ed, 0x3d0c}}, -{ .val = {0x2e481e70, 0xa2aa704, 0x164de8c8, 0x8069061, 0x1648d85f, 0x14fe7773, 0x3210a999, 0xa518f6, 0x9e86}}, -{ .val = {0x17240f38, 0x5155382, 0x2b26f464, 0x24034830, 0x2b246c2f, 0x2a7f3bb9, 0x190854cc, 0x528c7b, 0x4f43}}, -{ .val = {0xb92079c, 0x28aa9c1, 0x15937a32, 0x3201a418, 0x35923617, 0x153f9ddc, 0x2c842a66, 0x2029463d, 0x27a1}}, -{ .val = {0x25c903ce, 0x14554e0, 0xac9bd19, 0x3900d20c, 0x1ac91b0b, 0xa9fceee, 0x36421533, 0x3014a31e, 0x13d0}}, -{ .val = {0x12e481e7, 0x20a2aa70, 0x564de8c, 0x3c806906, 0xd648d85, 0x254fe777, 0x1b210a99, 0x180a518f, 0x9e8}}, -{ .val = {0x9723f0b, 0x10515536, 0x2b26f46, 0x3e403483, 0x26b246c2, 0x32a7f3bb, 0x2d90854c, 0xc0528c7, 0x84f4}}, -{ .val = {0x4b91d9d, 0x828aa99, 0x215937a3, 0x1f201a41, 0x33592361, 0x1953f9dd, 0x36c842a6, 0x6029463, 0xc27a}}, -{ .val = {0x225c8ce6, 0x2414554a, 0x30ac9bd1, 0x2f900d20, 0x39ac91b0, 0xca9fcee, 0x3b642153, 0x3014a31, 0xe13d}}, -{ .val = {0x112e4673, 0x320a2aa5, 0x18564de8, 0x17c80690, 0x1cd648d8, 0x2654fe77, 0x3db210a9, 0x2180a518, 0x709e}}, -{ .val = {0x28972151, 0x19051550, 0xc2b26f4, 0xbe40348, 0x2e6b246c, 0x332a7f3b, 0x1ed90854, 0x10c0528c, 0xb84f}}, -{ .val = {0x144b8ec0, 0xc828aa6, 0x615937a, 0x5f201a4, 0x37359236, 0x19953f9d, 0xf6c842a, 0x28602946, 0xdc27}}, -{ .val = {0xa25c760, 0x6414553, 0x30ac9bd, 0x2f900d2, 0x3b9ac91b, 0xcca9fce, 0x7b64215, 0x343014a3, 0x6e13}}, -{ .val = {0x2512e3b0, 0x2320a2a9, 0x18564de, 0x217c8069, 0x1dcd648d, 0x26654fe7, 0x23db210a, 0x3a180a51, 0x3709}}, -{ .val = {0x328971d8, 0x11905154, 0x20c2b26f, 0x30be4034, 0x2ee6b246, 0x1332a7f3, 0x31ed9085, 0x3d0c0528, 0x1b84}}, -{ .val = {0x1944b8ec, 0x28c828aa, 0x10615937, 0x185f201a, 0x37735923, 0x299953f9, 0x18f6c842, 0x1e860294, 0xdc2}}, -{ .val = {0xca25c76, 0x34641455, 0x830ac9b, 0x2c2f900d, 0x3bb9ac91, 0x14cca9fc, 0xc7b6421, 0xf43014a, 0x6e1}}, -{ .val = {0x26512e3b, 0x3a320a2a, 0x2418564d, 0x3617c806, 0x1ddcd648, 0x2a6654fe, 0x63db210, 0x27a180a5, 0x370}}, -{ .val = {0x13289535, 0x3d190513, 0x120c2b26, 0x1b0be403, 0xeee6b24, 0x15332a7f, 0x231ed908, 0x13d0c052, 0x81b8}}, -{ .val = {0x299448b2, 0x1e8c8287, 0x29061593, 0xd85f201, 0x27773592, 0xa99953f, 0x118f6c84, 0x9e86029, 0xc0dc}}, -{ .val = {0x34ca2459, 0x2f464143, 0x34830ac9, 0x6c2f900, 0x33bb9ac9, 0x54cca9f, 0x28c7b642, 0x4f43014, 0x606e}}, -{ .val = {0x3a651044, 0x37a3209f, 0x1a418564, 0x23617c80, 0x39ddcd64, 0x2a6654f, 0x1463db21, 0x27a180a, 0xb037}}, -{ .val = {0x3d328822, 0x1bd1904f, 0xd20c2b2, 0x11b0be40, 0x3ceee6b2, 0x215332a7, 0xa31ed90, 0x213d0c05, 0x581b}}, -{ .val = {0x3e994411, 0xde8c827, 0x6906159, 0x8d85f20, 0x3e777359, 0x10a99953, 0x2518f6c8, 0x309e8602, 0x2c0d}}, -{ .val = {0x3f4ca020, 0x26f46411, 0x34830ac, 0x246c2f90, 0x3f3bb9ac, 0x854cca9, 0x128c7b64, 0x384f4301, 0x9606}}, -{ .val = {0x3fa65010, 0x137a3208, 0x1a41856, 0x123617c8, 0x3f9ddcd6, 0x42a6654, 0x29463db2, 0x1c27a180, 0x4b03}}, -{ .val = {0x1fd32808, 0x9bd1904, 0xd20c2b, 0x91b0be4, 0x1fceee6b, 0x215332a, 0x14a31ed9, 0x2e13d0c0, 0x2581}}, -{ .val = {0xfe99404, 0x24de8c82, 0x690615, 0x248d85f2, 0xfe77735, 0x210a9995, 0xa518f6c, 0x3709e860, 0x12c0}}, -{ .val = {0x7f4ca02, 0x326f4641, 0x34830a, 0x3246c2f9, 0x27f3bb9a, 0x10854cca, 0x528c7b6, 0x1b84f430, 0x960}}, -{ .val = {0x23fa6501, 0x1937a320, 0x201a4185, 0x1923617c, 0x13f9ddcd, 0x842a665, 0x29463db, 0xdc27a18, 0x4b0}}, -{ .val = {0x11fd3098, 0x2c9bd18e, 0x100d20c2, 0x2c91b0be, 0x29fceee6, 0x24215332, 0x14a31ed, 0x6e13d0c, 0x8258}}, -{ .val = {0x8fe984c, 0x164de8c7, 0x8069061, 0x1648d85f, 0x14fe7773, 0x3210a999, 0xa518f6, 0x3709e86, 0x412c}}, -{ .val = {0x247f4c26, 0x2b26f463, 0x24034830, 0x2b246c2f, 0x2a7f3bb9, 0x190854cc, 0x528c7b, 0x1b84f43, 0x2096}}, -{ .val = {0x323fa613, 0x15937a31, 0x3201a418, 0x35923617, 0x153f9ddc, 0x2c842a66, 0x2029463d, 0xdc27a1, 0x104b}}, -{ .val = {0x391fd121, 0xac9bd16, 0x3900d20c, 0x1ac91b0b, 0xa9fceee, 0x36421533, 0x3014a31e, 0x206e13d0, 0x8825}}, -{ .val = {0x1c8fe6a8, 0x564de89, 0x3c806906, 0xd648d85, 0x254fe777, 0x1b210a99, 0x180a518f, 0x303709e8, 0xc412}}, -{ .val = {0x2e47f354, 0x2b26f44, 0x3e403483, 0x26b246c2, 0x32a7f3bb, 0x2d90854c, 0xc0528c7, 0x181b84f4, 0x6209}}, -{ .val = {0x1723f9aa, 0x215937a2, 0x1f201a41, 0x33592361, 0x1953f9dd, 0x36c842a6, 0x6029463, 0x2c0dc27a, 0x3104}}, -{ .val = {0xb91fcd5, 0x30ac9bd1, 0x2f900d20, 0x39ac91b0, 0xca9fcee, 0x3b642153, 0x3014a31, 0x1606e13d, 0x1882}}, -{ .val = {0x25c8fc82, 0x18564de6, 0x17c80690, 0x1cd648d8, 0x2654fe77, 0x3db210a9, 0x2180a518, 0xb03709e, 0x8c41}}, -{ .val = {0x12e47e41, 0xc2b26f3, 0xbe40348, 0x2e6b246c, 0x332a7f3b, 0x1ed90854, 0x10c0528c, 0x2581b84f, 0x4620}}, -{ .val = {0x29723d38, 0x6159377, 0x5f201a4, 0x37359236, 0x19953f9d, 0xf6c842a, 0x28602946, 0x12c0dc27, 0xa310}}, -{ .val = {0x34b91e9c, 0x30ac9bb, 0x2f900d2, 0x3b9ac91b, 0xcca9fce, 0x7b64215, 0x343014a3, 0x9606e13, 0x5188}}, -{ .val = {0x3a5c8f4e, 0x18564dd, 0x217c8069, 0x1dcd648d, 0x26654fe7, 0x23db210a, 0x3a180a51, 0x4b03709, 0x28c4}}, -{ .val = {0x3d2e47a7, 0x20c2b26e, 0x30be4034, 0x2ee6b246, 0x1332a7f3, 0x31ed9085, 0x3d0c0528, 0x2581b84, 0x1462}}, -{ .val = {0x1e9721eb, 0x10615935, 0x185f201a, 0x37735923, 0x299953f9, 0x18f6c842, 0x1e860294, 0x12c0dc2, 0x8a31}}, -{ .val = {0x2f4b8f0d, 0x830ac98, 0x2c2f900d, 0x3bb9ac91, 0x14cca9fc, 0xc7b6421, 0xf43014a, 0x209606e1, 0xc518}}, -{ .val = {0x17a5c59e, 0x2418564a, 0x3617c806, 0x1ddcd648, 0x2a6654fe, 0x63db210, 0x27a180a5, 0x104b0370, 0xe28c}}, -{ .val = {0xbd2e2cf, 0x120c2b25, 0x1b0be403, 0xeee6b24, 0x15332a7f, 0x231ed908, 0x13d0c052, 0x82581b8, 0x7146}}, -{ .val = {0x25e96f7f, 0x29061590, 0xd85f201, 0x27773592, 0xa99953f, 0x118f6c84, 0x9e86029, 0x412c0dc, 0xb8a3}}, -{ .val = {0x12f4b5d7, 0x34830ac6, 0x6c2f900, 0x33bb9ac9, 0x54cca9f, 0x28c7b642, 0x4f43014, 0x2209606e, 0xdc51}}, -{ .val = {0x97a5903, 0x1a418561, 0x23617c80, 0x39ddcd64, 0x2a6654f, 0x1463db21, 0x27a180a, 0x3104b037, 0xee28}}, -{ .val = {0x24bd2a99, 0xd20c2ae, 0x11b0be40, 0x3ceee6b2, 0x215332a7, 0xa31ed90, 0x213d0c05, 0x1882581b, 0xf714}}, -{ .val = {0x125e9364, 0x6906155, 0x8d85f20, 0x3e777359, 0x10a99953, 0x2518f6c8, 0x309e8602, 0xc412c0d, 0xfb8a}}, -{ .val = {0x292f49b2, 0x34830aa, 0x246c2f90, 0x3f3bb9ac, 0x854cca9, 0x128c7b64, 0x384f4301, 0x6209606, 0x7dc5}}, -{ .val = {0x1497a4d9, 0x1a41855, 0x123617c8, 0x3f9ddcd6, 0x42a6654, 0x29463db2, 0x1c27a180, 0x23104b03, 0x3ee2}}, -{ .val = {0x2a4bd084, 0xd20c28, 0x91b0be4, 0x1fceee6b, 0x215332a, 0x14a31ed9, 0x2e13d0c0, 0x11882581, 0x9f71}}, -{ .val = {0x1525e842, 0x690614, 0x248d85f2, 0xfe77735, 0x210a9995, 0xa518f6c, 0x3709e860, 0x28c412c0, 0x4fb8}}, -{ .val = {0xa92f421, 0x34830a, 0x3246c2f9, 0x27f3bb9a, 0x10854cca, 0x528c7b6, 0x1b84f430, 0x14620960, 0x27dc}}, -{ .val = {0x5497828, 0x201a4183, 0x1923617c, 0x13f9ddcd, 0x842a665, 0x29463db, 0xdc27a18, 0xa3104b0, 0x93ee}}, -{ .val = {0x22a4bc14, 0x100d20c1, 0x2c91b0be, 0x29fceee6, 0x24215332, 0x14a31ed, 0x6e13d0c, 0x5188258, 0x49f7}}, -{ .val = {0x31525e0a, 0x8069060, 0x1648d85f, 0x14fe7773, 0x3210a999, 0xa518f6, 0x3709e86, 0x228c412c, 0x24fb}}, -{ .val = {0x18a92f05, 0x24034830, 0x2b246c2f, 0x2a7f3bb9, 0x190854cc, 0x528c7b, 0x1b84f43, 0x31462096, 0x127d}}, -{ .val = {0xc54959a, 0x3201a416, 0x35923617, 0x153f9ddc, 0x2c842a66, 0x2029463d, 0xdc27a1, 0x38a3104b, 0x893e}}, -{ .val = {0x62a4acd, 0x3900d20b, 0x1ac91b0b, 0xa9fceee, 0x36421533, 0x3014a31e, 0x206e13d0, 0x1c518825, 0x449f}}, -{ .val = {0x2315237e, 0x3c806903, 0xd648d85, 0x254fe777, 0x1b210a99, 0x180a518f, 0x303709e8, 0x2e28c412, 0xa24f}}, -{ .val = {0x318a91bf, 0x3e403481, 0x26b246c2, 0x32a7f3bb, 0x2d90854c, 0xc0528c7, 0x181b84f4, 0x37146209, 0x5127}}, -{ .val = {0x38c546f7, 0x1f201a3e, 0x33592361, 0x1953f9dd, 0x36c842a6, 0x6029463, 0x2c0dc27a, 0x3b8a3104, 0xa893}}, -{ .val = {0x1c62a193, 0x2f900d1d, 0x39ac91b0, 0xca9fcee, 0x3b642153, 0x3014a31, 0x1606e13d, 0x3dc51882, 0xd449}}, -{ .val = {0x2e314ee1, 0x17c8068c, 0x1cd648d8, 0x2654fe77, 0x3db210a9, 0x2180a518, 0xb03709e, 0x3ee28c41, 0xea24}}, -{ .val = {0x1718a588, 0xbe40344, 0x2e6b246c, 0x332a7f3b, 0x1ed90854, 0x10c0528c, 0x2581b84f, 0x1f714620, 0xf512}}, -{ .val = {0xb8c52c4, 0x5f201a2, 0x37359236, 0x19953f9d, 0xf6c842a, 0x28602946, 0x12c0dc27, 0xfb8a310, 0x7a89}}, -{ .val = {0x5c62962, 0x2f900d1, 0x3b9ac91b, 0xcca9fce, 0x7b64215, 0x343014a3, 0x9606e13, 0x27dc5188, 0x3d44}}, -{ .val = {0x22e314b1, 0x217c8068, 0x1dcd648d, 0x26654fe7, 0x23db210a, 0x3a180a51, 0x4b03709, 0x13ee28c4, 0x1ea2}}, -{ .val = {0x11718870, 0x30be4032, 0x2ee6b246, 0x1332a7f3, 0x31ed9085, 0x3d0c0528, 0x2581b84, 0x9f71462, 0x8f51}}, -{ .val = {0x8b8c438, 0x185f2019, 0x37735923, 0x299953f9, 0x18f6c842, 0x1e860294, 0x12c0dc2, 0x24fb8a31, 0x47a8}}, -{ .val = {0x245c621c, 0x2c2f900c, 0x3bb9ac91, 0x14cca9fc, 0xc7b6421, 0xf43014a, 0x209606e1, 0x127dc518, 0x23d4}}, -{ .val = {0x122e310e, 0x3617c806, 0x1ddcd648, 0x2a6654fe, 0x63db210, 0x27a180a5, 0x104b0370, 0x93ee28c, 0x11ea}}, -{ .val = {0x9171887, 0x1b0be403, 0xeee6b24, 0x15332a7f, 0x231ed908, 0x13d0c052, 0x82581b8, 0x49f7146, 0x8f5}}, -{ .val = {0x248b8a5b, 0xd85f1ff, 0x27773592, 0xa99953f, 0x118f6c84, 0x9e86029, 0x412c0dc, 0x224fb8a3, 0x847a}}, -{ .val = {0x3245c345, 0x6c2f8fd, 0x33bb9ac9, 0x54cca9f, 0x28c7b642, 0x4f43014, 0x2209606e, 0x1127dc51, 0xc23d}}, -{ .val = {0x3922dfba, 0x23617c7c, 0x39ddcd64, 0x2a6654f, 0x1463db21, 0x27a180a, 0x3104b037, 0x2893ee28, 0xe11e}}, -{ .val = {0x1c916fdd, 0x11b0be3e, 0x3ceee6b2, 0x215332a7, 0xa31ed90, 0x213d0c05, 0x1882581b, 0x1449f714, 0x708f}}, -{ .val = {0xe48b606, 0x8d85f1d, 0x3e777359, 0x10a99953, 0x2518f6c8, 0x309e8602, 0xc412c0d, 0x2a24fb8a, 0xb847}}, -{ .val = {0x27245b03, 0x246c2f8e, 0x3f3bb9ac, 0x854cca9, 0x128c7b64, 0x384f4301, 0x6209606, 0x35127dc5, 0x5c23}}, -{ .val = {0x13922b99, 0x123617c5, 0x3f9ddcd6, 0x42a6654, 0x29463db2, 0x1c27a180, 0x23104b03, 0x3a893ee2, 0xae11}}, -{ .val = {0x29c913e4, 0x91b0be0, 0x1fceee6b, 0x215332a, 0x14a31ed9, 0x2e13d0c0, 0x11882581, 0x3d449f71, 0xd708}}, -{ .val = {0x14e489f2, 0x248d85f0, 0xfe77735, 0x210a9995, 0xa518f6c, 0x3709e860, 0x28c412c0, 0x1ea24fb8, 0x6b84}}, +{/*.val =*/{0x868192a, 0x20e02474, 0x24a059d, 0x2c88ffb7, 0x32b761bc, 0x1b0b0a57, 0x383999c4, 0x6414554, 0xc9bd}}, +{/*.val =*/{0x4340c95, 0x3070123a, 0x212502ce, 0x16447fdb, 0x395bb0de, 0xd85852b, 0x1c1ccce2, 0x2320a2aa, 0x64de}}, +{/*.val =*/{0x21a0462, 0x1838091b, 0x30928167, 0xb223fed, 0x3cadd86f, 0x6c2c295, 0xe0e6671, 0x11905155, 0xb26f}}, +{/*.val =*/{0x210d0231, 0x2c1c048d, 0x384940b3, 0x25911ff6, 0x3e56ec37, 0x2361614a, 0x27073338, 0x28c828aa, 0x5937}}, +{/*.val =*/{0x30867f30, 0x360e0244, 0x1c24a059, 0x32c88ffb, 0x1f2b761b, 0x11b0b0a5, 0x1383999c, 0x34641455, 0xac9b}}, +{/*.val =*/{0x18433f98, 0x3b070122, 0x2e12502c, 0x396447fd, 0x2f95bb0d, 0x8d85852, 0x29c1ccce, 0x3a320a2a, 0x564d}}, +{/*.val =*/{0xc219fcc, 0x1d838091, 0x37092816, 0x3cb223fe, 0x17cadd86, 0x46c2c29, 0x14e0e667, 0x3d190515, 0x2b26}}, +{/*.val =*/{0x2610cfe6, 0xec1c048, 0x1b84940b, 0x1e5911ff, 0x2be56ec3, 0x22361614, 0x2a707333, 0x1e8c828a, 0x1593}}, +{/*.val =*/{0x130867f3, 0x2760e024, 0x2dc24a05, 0x2f2c88ff, 0x15f2b761, 0x311b0b0a, 0x15383999, 0x2f464145, 0xac9}}, +{/*.val =*/{0x9843211, 0x33b07010, 0x36e12502, 0x3796447f, 0xaf95bb0, 0x388d8585, 0x2a9c1ccc, 0x37a320a2, 0x8564}}, +{/*.val =*/{0x4c21720, 0x19d83806, 0x3b709281, 0x1bcb223f, 0x257cadd8, 0x1c46c2c2, 0x154e0e66, 0x1bd19051, 0xc2b2}}, +{/*.val =*/{0x2610b90, 0x2cec1c03, 0x3db84940, 0xde5911f, 0x12be56ec, 0xe236161, 0x2aa70733, 0xde8c828, 0x6159}}, +{/*.val =*/{0x213085c8, 0x16760e01, 0x3edc24a0, 0x6f2c88f, 0x295f2b76, 0x2711b0b0, 0x15538399, 0x26f46414, 0x30ac}}, +{/*.val =*/{0x309842e4, 0xb3b0700, 0x3f6e1250, 0x3796447, 0x14af95bb, 0x3388d858, 0xaa9c1cc, 0x137a320a, 0x1856}}, +{/*.val =*/{0x184c2172, 0x59d8380, 0x3fb70928, 0x21bcb223, 0xa57cadd, 0x19c46c2c, 0x554e0e6, 0x9bd1905, 0xc2b}}, +{/*.val =*/{0xc2610b9, 0x2cec1c0, 0x3fdb8494, 0x30de5911, 0x52be56e, 0xce23616, 0x22aa7073, 0x24de8c82, 0x615}}, +{/*.val =*/{0x6130674, 0x16760de, 0x3fedc24a, 0x186f2c88, 0x295f2b7, 0x26711b0b, 0x11553839, 0x326f4641, 0x830a}}, +{/*.val =*/{0x309833a, 0xb3b06f, 0x1ff6e125, 0x2c379644, 0x214af95b, 0x33388d85, 0x28aa9c1c, 0x1937a320, 0x4185}}, +{/*.val =*/{0x2184c19d, 0x2059d837, 0xffb7092, 0x361bcb22, 0x30a57cad, 0x199c46c2, 0x14554e0e, 0x2c9bd190, 0x20c2}}, +{/*.val =*/{0x30c25ee6, 0x102cec19, 0x7fdb849, 0x3b0de591, 0x1852be56, 0xcce2361, 0xa2aa707, 0x164de8c8, 0x9061}}, +{/*.val =*/{0x38612f73, 0x2816760c, 0x23fedc24, 0x1d86f2c8, 0x2c295f2b, 0x266711b0, 0x5155383, 0x2b26f464, 0x4830}}, +{/*.val =*/{0x1c3095d1, 0x140b3b04, 0x11ff6e12, 0x2ec37964, 0x1614af95, 0x333388d8, 0x28aa9c1, 0x15937a32, 0xa418}}, +{/*.val =*/{0xe184900, 0xa059d80, 0x8ffb709, 0x3761bcb2, 0xb0a57ca, 0x3999c46c, 0x14554e0, 0xac9bd19, 0xd20c}}, +{/*.val =*/{0x70c2480, 0x2502cec0, 0x47fdb84, 0x1bb0de59, 0x5852be5, 0x1ccce236, 0x20a2aa70, 0x564de8c, 0x6906}}, +{/*.val =*/{0x3861240, 0x12816760, 0x223fedc2, 0x2dd86f2c, 0x2c295f2, 0xe66711b, 0x10515538, 0x2b26f46, 0x3483}}, +{/*.val =*/{0x1c30920, 0x940b3b0, 0x111ff6e1, 0x16ec3796, 0x21614af9, 0x733388d, 0x828aa9c, 0x215937a3, 0x1a41}}, +{/*.val =*/{0xe18490, 0x24a059d8, 0x88ffb70, 0x2b761bcb, 0x30b0a57c, 0x3999c46, 0x2414554e, 0x30ac9bd1, 0xd20}}, +{/*.val =*/{0x70c248, 0x12502cec, 0x2447fdb8, 0x15bb0de5, 0x185852be, 0x1ccce23, 0x320a2aa7, 0x18564de8, 0x690}}, +{/*.val =*/{0x386124, 0x9281676, 0x3223fedc, 0xadd86f2, 0x2c2c295f, 0x20e66711, 0x19051553, 0xc2b26f4, 0x348}}, +{/*.val =*/{0x1c3092, 0x4940b3b, 0x1911ff6e, 0x256ec379, 0x361614af, 0x30733388, 0xc828aa9, 0x615937a, 0x1a4}}, +{/*.val =*/{0x200e1849, 0x24a059d, 0x2c88ffb7, 0x32b761bc, 0x1b0b0a57, 0x383999c4, 0x6414554, 0x30ac9bd, 0xd2}}, +{/*.val =*/{0x30070a3c, 0x212502cc, 0x16447fdb, 0x395bb0de, 0xd85852b, 0x1c1ccce2, 0x2320a2aa, 0x18564de, 0x8069}}, +{/*.val =*/{0x1803851e, 0x30928166, 0xb223fed, 0x3cadd86f, 0x6c2c295, 0xe0e6671, 0x11905155, 0x20c2b26f, 0x4034}}, +{/*.val =*/{0xc01c28f, 0x384940b3, 0x25911ff6, 0x3e56ec37, 0x2361614a, 0x27073338, 0x28c828aa, 0x10615937, 0x201a}}, +{/*.val =*/{0x2600df5f, 0x1c24a057, 0x32c88ffb, 0x1f2b761b, 0x11b0b0a5, 0x1383999c, 0x34641455, 0x830ac9b, 0x900d}}, +{/*.val =*/{0x33006dc7, 0x2e125029, 0x396447fd, 0x2f95bb0d, 0x8d85852, 0x29c1ccce, 0x3a320a2a, 0x2418564d, 0xc806}}, +{/*.val =*/{0x398034fb, 0x37092812, 0x3cb223fe, 0x17cadd86, 0x46c2c29, 0x14e0e667, 0x3d190515, 0x120c2b26, 0xe403}}, +{/*.val =*/{0x1cc01895, 0x1b849407, 0x1e5911ff, 0x2be56ec3, 0x22361614, 0x2a707333, 0x1e8c828a, 0x29061593, 0xf201}}, +{/*.val =*/{0x2e600a62, 0x2dc24a01, 0x2f2c88ff, 0x15f2b761, 0x311b0b0a, 0x15383999, 0x2f464145, 0x34830ac9, 0xf900}}, +{/*.val =*/{0x37300531, 0x36e12500, 0x3796447f, 0xaf95bb0, 0x388d8585, 0x2a9c1ccc, 0x37a320a2, 0x1a418564, 0x7c80}}, +{/*.val =*/{0x1b9800b0, 0x3b70927e, 0x1bcb223f, 0x257cadd8, 0x1c46c2c2, 0x154e0e66, 0x1bd19051, 0xd20c2b2, 0xbe40}}, +{/*.val =*/{0xdcc0058, 0x3db8493f, 0xde5911f, 0x12be56ec, 0xe236161, 0x2aa70733, 0xde8c828, 0x6906159, 0x5f20}}, +{/*.val =*/{0x26e6002c, 0x3edc249f, 0x6f2c88f, 0x295f2b76, 0x2711b0b0, 0x15538399, 0x26f46414, 0x34830ac, 0x2f90}}, +{/*.val =*/{0x33730016, 0x3f6e124f, 0x3796447, 0x14af95bb, 0x3388d858, 0xaa9c1cc, 0x137a320a, 0x1a41856, 0x17c8}}, +{/*.val =*/{0x39b9800b, 0x3fb70927, 0x21bcb223, 0xa57cadd, 0x19c46c2c, 0x554e0e6, 0x9bd1905, 0xd20c2b, 0xbe4}}, +{/*.val =*/{0x3cdcbe1d, 0x3fdb8491, 0x30de5911, 0x52be56e, 0xce23616, 0x22aa7073, 0x24de8c82, 0x690615, 0x85f2}}, +{/*.val =*/{0x3e6e5d26, 0x3fedc246, 0x186f2c88, 0x295f2b7, 0x26711b0b, 0x11553839, 0x326f4641, 0x34830a, 0xc2f9}}, +{/*.val =*/{0x1f372e93, 0x1ff6e123, 0x2c379644, 0x214af95b, 0x33388d85, 0x28aa9c1c, 0x1937a320, 0x201a4185, 0x617c}}, +{/*.val =*/{0x2f9b9561, 0xffb708f, 0x361bcb22, 0x30a57cad, 0x199c46c2, 0x14554e0e, 0x2c9bd190, 0x100d20c2, 0xb0be}}, +{/*.val =*/{0x37cdc8c8, 0x7fdb845, 0x3b0de591, 0x1852be56, 0xcce2361, 0xa2aa707, 0x164de8c8, 0x8069061, 0xd85f}}, +{/*.val =*/{0x3be6e464, 0x23fedc22, 0x1d86f2c8, 0x2c295f2b, 0x266711b0, 0x5155383, 0x2b26f464, 0x24034830, 0x6c2f}}, +{/*.val =*/{0x1df37232, 0x11ff6e11, 0x2ec37964, 0x1614af95, 0x333388d8, 0x28aa9c1, 0x15937a32, 0x3201a418, 0x3617}}, +{/*.val =*/{0x2ef9b919, 0x8ffb708, 0x3761bcb2, 0xb0a57ca, 0x3999c46c, 0x14554e0, 0xac9bd19, 0x3900d20c, 0x1b0b}}, +{/*.val =*/{0x177cdaa4, 0x47fdb82, 0x1bb0de59, 0x5852be5, 0x1ccce236, 0x20a2aa70, 0x564de8c, 0x3c806906, 0x8d85}}, +{/*.val =*/{0xbbe6d52, 0x223fedc1, 0x2dd86f2c, 0x2c295f2, 0xe66711b, 0x10515538, 0x2b26f46, 0x3e403483, 0x46c2}}, +{/*.val =*/{0x25df36a9, 0x111ff6e0, 0x16ec3796, 0x21614af9, 0x733388d, 0x828aa9c, 0x215937a3, 0x1f201a41, 0x2361}}, +{/*.val =*/{0x12ef996c, 0x88ffb6e, 0x2b761bcb, 0x30b0a57c, 0x3999c46, 0x2414554e, 0x30ac9bd1, 0x2f900d20, 0x91b0}}, +{/*.val =*/{0x977ccb6, 0x2447fdb7, 0x15bb0de5, 0x185852be, 0x1ccce23, 0x320a2aa7, 0x18564de8, 0x17c80690, 0x48d8}}, +{/*.val =*/{0x24bbe65b, 0x3223fedb, 0xadd86f2, 0x2c2c295f, 0x20e66711, 0x19051553, 0xc2b26f4, 0xbe40348, 0x246c}}, +{/*.val =*/{0x325df145, 0x1911ff6b, 0x256ec379, 0x361614af, 0x30733388, 0xc828aa9, 0x615937a, 0x5f201a4, 0x9236}}, +{/*.val =*/{0x392ef6ba, 0x2c88ffb3, 0x32b761bc, 0x1b0b0a57, 0x383999c4, 0x6414554, 0x30ac9bd, 0x2f900d2, 0xc91b}}, +{/*.val =*/{0x3c977b5d, 0x16447fd9, 0x395bb0de, 0xd85852b, 0x1c1ccce2, 0x2320a2aa, 0x18564de, 0x217c8069, 0x648d}}, +{/*.val =*/{0x3e4bbbc6, 0xb223fea, 0x3cadd86f, 0x6c2c295, 0xe0e6671, 0x11905155, 0x20c2b26f, 0x30be4034, 0xb246}}, +{/*.val =*/{0x1f25dde3, 0x25911ff5, 0x3e56ec37, 0x2361614a, 0x27073338, 0x28c828aa, 0x10615937, 0x185f201a, 0x5923}}, +{/*.val =*/{0x2f92ed09, 0x32c88ff8, 0x1f2b761b, 0x11b0b0a5, 0x1383999c, 0x34641455, 0x830ac9b, 0x2c2f900d, 0xac91}}, +{/*.val =*/{0x17c9749c, 0x396447fa, 0x2f95bb0d, 0x8d85852, 0x29c1ccce, 0x3a320a2a, 0x2418564d, 0x3617c806, 0xd648}}, +{/*.val =*/{0xbe4ba4e, 0x3cb223fd, 0x17cadd86, 0x46c2c29, 0x14e0e667, 0x3d190515, 0x120c2b26, 0x1b0be403, 0x6b24}}, +{/*.val =*/{0x25f25d27, 0x1e5911fe, 0x2be56ec3, 0x22361614, 0x2a707333, 0x1e8c828a, 0x29061593, 0xd85f201, 0x3592}}, +{/*.val =*/{0x12f92cab, 0x2f2c88fd, 0x15f2b761, 0x311b0b0a, 0x15383999, 0x2f464145, 0x34830ac9, 0x6c2f900, 0x9ac9}}, +{/*.val =*/{0x297c946d, 0x3796447c, 0xaf95bb0, 0x388d8585, 0x2a9c1ccc, 0x37a320a2, 0x1a418564, 0x23617c80, 0xcd64}}, +{/*.val =*/{0x14be484e, 0x1bcb223c, 0x257cadd8, 0x1c46c2c2, 0x154e0e66, 0x1bd19051, 0xd20c2b2, 0x11b0be40, 0xe6b2}}, +{/*.val =*/{0xa5f2427, 0xde5911e, 0x12be56ec, 0xe236161, 0x2aa70733, 0xde8c828, 0x6906159, 0x8d85f20, 0x7359}}, +{/*.val =*/{0x52f902b, 0x6f2c88d, 0x295f2b76, 0x2711b0b0, 0x15538399, 0x26f46414, 0x34830ac, 0x246c2f90, 0xb9ac}}, +{/*.val =*/{0x2297c62d, 0x3796444, 0x14af95bb, 0x3388d858, 0xaa9c1cc, 0x137a320a, 0x1a41856, 0x123617c8, 0xdcd6}}, +{/*.val =*/{0x114be12e, 0x21bcb220, 0xa57cadd, 0x19c46c2c, 0x554e0e6, 0x9bd1905, 0xd20c2b, 0x91b0be4, 0xee6b}}, +{/*.val =*/{0x8a5f097, 0x30de5910, 0x52be56e, 0xce23616, 0x22aa7073, 0x24de8c82, 0x690615, 0x248d85f2, 0x7735}}, +{/*.val =*/{0x452f663, 0x186f2c86, 0x295f2b7, 0x26711b0b, 0x11553839, 0x326f4641, 0x34830a, 0x3246c2f9, 0xbb9a}}, +{/*.val =*/{0x2297949, 0x2c379641, 0x214af95b, 0x33388d85, 0x28aa9c1c, 0x1937a320, 0x201a4185, 0x1923617c, 0xddcd}}, +{/*.val =*/{0x2114babc, 0x361bcb1e, 0x30a57cad, 0x199c46c2, 0x14554e0e, 0x2c9bd190, 0x100d20c2, 0x2c91b0be, 0xeee6}}, +{/*.val =*/{0x108a5d5e, 0x3b0de58f, 0x1852be56, 0xcce2361, 0xa2aa707, 0x164de8c8, 0x8069061, 0x1648d85f, 0x7773}}, +{/*.val =*/{0x28452eaf, 0x1d86f2c7, 0x2c295f2b, 0x266711b0, 0x5155383, 0x2b26f464, 0x24034830, 0x2b246c2f, 0x3bb9}}, +{/*.val =*/{0x3422956f, 0x2ec37961, 0x1614af95, 0x333388d8, 0x28aa9c1, 0x15937a32, 0x3201a418, 0x35923617, 0x9ddc}}, +{/*.val =*/{0x3a1148cf, 0x3761bcae, 0xb0a57ca, 0x3999c46c, 0x14554e0, 0xac9bd19, 0x3900d20c, 0x1ac91b0b, 0xceee}}, +{/*.val =*/{0x1d08a27f, 0x1bb0de55, 0x5852be5, 0x1ccce236, 0x20a2aa70, 0x564de8c, 0x3c806906, 0xd648d85, 0xe777}}, +{/*.val =*/{0x2e844f57, 0x2dd86f28, 0x2c295f2, 0xe66711b, 0x10515538, 0x2b26f46, 0x3e403483, 0x26b246c2, 0xf3bb}}, +{/*.val =*/{0x174225c3, 0x16ec3792, 0x21614af9, 0x733388d, 0x828aa9c, 0x215937a3, 0x1f201a41, 0x33592361, 0xf9dd}}, +{/*.val =*/{0xba110f9, 0x2b761bc7, 0x30b0a57c, 0x3999c46, 0x2414554e, 0x30ac9bd1, 0x2f900d20, 0x39ac91b0, 0xfcee}}, +{/*.val =*/{0x25d08694, 0x15bb0de1, 0x185852be, 0x1ccce23, 0x320a2aa7, 0x18564de8, 0x17c80690, 0x1cd648d8, 0xfe77}}, +{/*.val =*/{0x32e8434a, 0xadd86f0, 0x2c2c295f, 0x20e66711, 0x19051553, 0xc2b26f4, 0xbe40348, 0x2e6b246c, 0x7f3b}}, +{/*.val =*/{0x197421a5, 0x256ec378, 0x361614af, 0x30733388, 0xc828aa9, 0x615937a, 0x5f201a4, 0x37359236, 0x3f9d}}, +{/*.val =*/{0xcba0eea, 0x32b761ba, 0x1b0b0a57, 0x383999c4, 0x6414554, 0x30ac9bd, 0x2f900d2, 0x3b9ac91b, 0x9fce}}, +{/*.val =*/{0x65d0775, 0x395bb0dd, 0xd85852b, 0x1c1ccce2, 0x2320a2aa, 0x18564de, 0x217c8069, 0x1dcd648d, 0x4fe7}}, +{/*.val =*/{0x232e81d2, 0x3cadd86c, 0x6c2c295, 0xe0e6671, 0x11905155, 0x20c2b26f, 0x30be4034, 0x2ee6b246, 0xa7f3}}, +{/*.val =*/{0x119740e9, 0x3e56ec36, 0x2361614a, 0x27073338, 0x28c828aa, 0x10615937, 0x185f201a, 0x37735923, 0x53f9}}, +{/*.val =*/{0x8cb9e8c, 0x1f2b7619, 0x11b0b0a5, 0x1383999c, 0x34641455, 0x830ac9b, 0x2c2f900d, 0x3bb9ac91, 0xa9fc}}, +{/*.val =*/{0x2465cf46, 0x2f95bb0c, 0x8d85852, 0x29c1ccce, 0x3a320a2a, 0x2418564d, 0x3617c806, 0x1ddcd648, 0x54fe}}, +{/*.val =*/{0x1232e7a3, 0x17cadd86, 0x46c2c29, 0x14e0e667, 0x3d190515, 0x120c2b26, 0x1b0be403, 0xeee6b24, 0x2a7f}}, +{/*.val =*/{0x91971e9, 0x2be56ec1, 0x22361614, 0x2a707333, 0x1e8c828a, 0x29061593, 0xd85f201, 0x27773592, 0x953f}}, +{/*.val =*/{0x248cb70c, 0x15f2b75e, 0x311b0b0a, 0x15383999, 0x2f464145, 0x34830ac9, 0x6c2f900, 0x33bb9ac9, 0xca9f}}, +{/*.val =*/{0x12465b86, 0xaf95baf, 0x388d8585, 0x2a9c1ccc, 0x37a320a2, 0x1a418564, 0x23617c80, 0x39ddcd64, 0x654f}}, +{/*.val =*/{0x29232dc3, 0x257cadd7, 0x1c46c2c2, 0x154e0e66, 0x1bd19051, 0xd20c2b2, 0x11b0be40, 0x3ceee6b2, 0x32a7}}, +{/*.val =*/{0x349194f9, 0x12be56e9, 0xe236161, 0x2aa70733, 0xde8c828, 0x6906159, 0x8d85f20, 0x3e777359, 0x9953}}, +{/*.val =*/{0x3a48c894, 0x295f2b72, 0x2711b0b0, 0x15538399, 0x26f46414, 0x34830ac, 0x246c2f90, 0x3f3bb9ac, 0xcca9}}, +{/*.val =*/{0x1d24644a, 0x14af95b9, 0x3388d858, 0xaa9c1cc, 0x137a320a, 0x1a41856, 0x123617c8, 0x3f9ddcd6, 0x6654}}, +{/*.val =*/{0x2e923225, 0xa57cadc, 0x19c46c2c, 0x554e0e6, 0x9bd1905, 0xd20c2b, 0x91b0be4, 0x1fceee6b, 0x332a}}, +{/*.val =*/{0x1749172a, 0x52be56c, 0xce23616, 0x22aa7073, 0x24de8c82, 0x690615, 0x248d85f2, 0xfe77735, 0x9995}}, +{/*.val =*/{0xba48b95, 0x295f2b6, 0x26711b0b, 0x11553839, 0x326f4641, 0x34830a, 0x3246c2f9, 0x27f3bb9a, 0x4cca}}, +{/*.val =*/{0x5d243e2, 0x214af959, 0x33388d85, 0x28aa9c1c, 0x1937a320, 0x201a4185, 0x1923617c, 0x13f9ddcd, 0xa665}}, +{/*.val =*/{0x22e921f1, 0x30a57cac, 0x199c46c2, 0x14554e0e, 0x2c9bd190, 0x100d20c2, 0x2c91b0be, 0x29fceee6, 0x5332}}, +{/*.val =*/{0x11748f10, 0x1852be54, 0xcce2361, 0xa2aa707, 0x164de8c8, 0x8069061, 0x1648d85f, 0x14fe7773, 0xa999}}, +{/*.val =*/{0x8ba4788, 0x2c295f2a, 0x266711b0, 0x5155383, 0x2b26f464, 0x24034830, 0x2b246c2f, 0x2a7f3bb9, 0x54cc}}, +{/*.val =*/{0x45d23c4, 0x1614af95, 0x333388d8, 0x28aa9c1, 0x15937a32, 0x3201a418, 0x35923617, 0x153f9ddc, 0x2a66}}, +{/*.val =*/{0x222e91e2, 0xb0a57ca, 0x3999c46c, 0x14554e0, 0xac9bd19, 0x3900d20c, 0x1ac91b0b, 0xa9fceee, 0x1533}}, +{/*.val =*/{0x111748f1, 0x5852be5, 0x1ccce236, 0x20a2aa70, 0x564de8c, 0x3c806906, 0xd648d85, 0x254fe777, 0xa99}}, +{/*.val =*/{0x288ba290, 0x2c295f0, 0xe66711b, 0x10515538, 0x2b26f46, 0x3e403483, 0x26b246c2, 0x32a7f3bb, 0x854c}}, +{/*.val =*/{0x1445d148, 0x21614af8, 0x733388d, 0x828aa9c, 0x215937a3, 0x1f201a41, 0x33592361, 0x1953f9dd, 0x42a6}}, +{/*.val =*/{0xa22e8a4, 0x30b0a57c, 0x3999c46, 0x2414554e, 0x30ac9bd1, 0x2f900d20, 0x39ac91b0, 0xca9fcee, 0x2153}}, +{/*.val =*/{0x5117452, 0x185852be, 0x1ccce23, 0x320a2aa7, 0x18564de8, 0x17c80690, 0x1cd648d8, 0x2654fe77, 0x10a9}}, +{/*.val =*/{0x288ba29, 0x2c2c295f, 0x20e66711, 0x19051553, 0xc2b26f4, 0xbe40348, 0x2e6b246c, 0x332a7f3b, 0x854}}, +{/*.val =*/{0x21445b2c, 0x361614ad, 0x30733388, 0xc828aa9, 0x615937a, 0x5f201a4, 0x37359236, 0x19953f9d, 0x842a}}, +{/*.val =*/{0x30a22d96, 0x1b0b0a56, 0x383999c4, 0x6414554, 0x30ac9bd, 0x2f900d2, 0x3b9ac91b, 0xcca9fce, 0x4215}}, +{/*.val =*/{0x185116cb, 0xd85852b, 0x1c1ccce2, 0x2320a2aa, 0x18564de, 0x217c8069, 0x1dcd648d, 0x26654fe7, 0x210a}}, +{/*.val =*/{0x2c28897d, 0x6c2c293, 0xe0e6671, 0x11905155, 0x20c2b26f, 0x30be4034, 0x2ee6b246, 0x1332a7f3, 0x9085}}, +{/*.val =*/{0x361442d6, 0x23616147, 0x27073338, 0x28c828aa, 0x10615937, 0x185f201a, 0x37735923, 0x299953f9, 0xc842}}, +{/*.val =*/{0x3b0a216b, 0x11b0b0a3, 0x1383999c, 0x34641455, 0x830ac9b, 0x2c2f900d, 0x3bb9ac91, 0x14cca9fc, 0x6421}}, +{/*.val =*/{0x3d850ecd, 0x8d8584f, 0x29c1ccce, 0x3a320a2a, 0x2418564d, 0x3617c806, 0x1ddcd648, 0x2a6654fe, 0xb210}}, +{/*.val =*/{0x3ec2857e, 0x46c2c25, 0x14e0e667, 0x3d190515, 0x120c2b26, 0x1b0be403, 0xeee6b24, 0x15332a7f, 0xd908}}, +{/*.val =*/{0x3f6142bf, 0x22361612, 0x2a707333, 0x1e8c828a, 0x29061593, 0xd85f201, 0x27773592, 0xa99953f, 0x6c84}}, +{/*.val =*/{0x1fb09f77, 0x311b0b07, 0x15383999, 0x2f464145, 0x34830ac9, 0x6c2f900, 0x33bb9ac9, 0x54cca9f, 0xb642}}, +{/*.val =*/{0x2fd84dd3, 0x388d8581, 0x2a9c1ccc, 0x37a320a2, 0x1a418564, 0x23617c80, 0x39ddcd64, 0x2a6654f, 0xdb21}}, +{/*.val =*/{0x37ec2501, 0x1c46c2be, 0x154e0e66, 0x1bd19051, 0xd20c2b2, 0x11b0be40, 0x3ceee6b2, 0x215332a7, 0xed90}}, +{/*.val =*/{0x1bf61098, 0xe23615d, 0x2aa70733, 0xde8c828, 0x6906159, 0x8d85f20, 0x3e777359, 0x10a99953, 0xf6c8}}, +{/*.val =*/{0x2dfb084c, 0x2711b0ae, 0x15538399, 0x26f46414, 0x34830ac, 0x246c2f90, 0x3f3bb9ac, 0x854cca9, 0x7b64}}, +{/*.val =*/{0x16fd8426, 0x3388d857, 0xaa9c1cc, 0x137a320a, 0x1a41856, 0x123617c8, 0x3f9ddcd6, 0x42a6654, 0x3db2}}, +{/*.val =*/{0x2b7ec213, 0x19c46c2b, 0x554e0e6, 0x9bd1905, 0xd20c2b, 0x91b0be4, 0x1fceee6b, 0x215332a, 0x1ed9}}, +{/*.val =*/{0x35bf5f21, 0xce23613, 0x22aa7073, 0x24de8c82, 0x690615, 0x248d85f2, 0xfe77735, 0x210a9995, 0x8f6c}}, +{/*.val =*/{0x3adfada8, 0x26711b07, 0x11553839, 0x326f4641, 0x34830a, 0x3246c2f9, 0x27f3bb9a, 0x10854cca, 0xc7b6}}, +{/*.val =*/{0x3d6fd6d4, 0x33388d83, 0x28aa9c1c, 0x1937a320, 0x201a4185, 0x1923617c, 0x13f9ddcd, 0x842a665, 0x63db}}, +{/*.val =*/{0x3eb7eb6a, 0x199c46c1, 0x14554e0e, 0x2c9bd190, 0x100d20c2, 0x2c91b0be, 0x29fceee6, 0x24215332, 0x31ed}}, +{/*.val =*/{0x3f5bf5b5, 0xcce2360, 0xa2aa707, 0x164de8c8, 0x8069061, 0x1648d85f, 0x14fe7773, 0x3210a999, 0x18f6}}, +{/*.val =*/{0x1fadf8f2, 0x266711ae, 0x5155383, 0x2b26f464, 0x24034830, 0x2b246c2f, 0x2a7f3bb9, 0x190854cc, 0x8c7b}}, +{/*.val =*/{0xfd6fc79, 0x333388d7, 0x28aa9c1, 0x15937a32, 0x3201a418, 0x35923617, 0x153f9ddc, 0x2c842a66, 0x463d}}, +{/*.val =*/{0x27eb7c54, 0x3999c469, 0x14554e0, 0xac9bd19, 0x3900d20c, 0x1ac91b0b, 0xa9fceee, 0x36421533, 0xa31e}}, +{/*.val =*/{0x33f5be2a, 0x1ccce234, 0x20a2aa70, 0x564de8c, 0x3c806906, 0xd648d85, 0x254fe777, 0x1b210a99, 0x518f}}, +{/*.val =*/{0x19fadf15, 0xe66711a, 0x10515538, 0x2b26f46, 0x3e403483, 0x26b246c2, 0x32a7f3bb, 0x2d90854c, 0x28c7}}, +{/*.val =*/{0xcfd6da2, 0x733388b, 0x828aa9c, 0x215937a3, 0x1f201a41, 0x33592361, 0x1953f9dd, 0x36c842a6, 0x9463}}, +{/*.val =*/{0x267eb6d1, 0x3999c45, 0x2414554e, 0x30ac9bd1, 0x2f900d20, 0x39ac91b0, 0xca9fcee, 0x3b642153, 0x4a31}}, +{/*.val =*/{0x333f5980, 0x1ccce20, 0x320a2aa7, 0x18564de8, 0x17c80690, 0x1cd648d8, 0x2654fe77, 0x3db210a9, 0xa518}}, +{/*.val =*/{0x199facc0, 0x20e66710, 0x19051553, 0xc2b26f4, 0xbe40348, 0x2e6b246c, 0x332a7f3b, 0x1ed90854, 0x528c}}, +{/*.val =*/{0xccfd660, 0x30733388, 0xc828aa9, 0x615937a, 0x5f201a4, 0x37359236, 0x19953f9d, 0xf6c842a, 0x2946}}, +{/*.val =*/{0x667eb30, 0x383999c4, 0x6414554, 0x30ac9bd, 0x2f900d2, 0x3b9ac91b, 0xcca9fce, 0x7b64215, 0x14a3}}, +{/*.val =*/{0x333f598, 0x1c1ccce2, 0x2320a2aa, 0x18564de, 0x217c8069, 0x1dcd648d, 0x26654fe7, 0x23db210a, 0xa51}}, +{/*.val =*/{0x199facc, 0xe0e6671, 0x11905155, 0x20c2b26f, 0x30be4034, 0x2ee6b246, 0x1332a7f3, 0x31ed9085, 0x528}}, +{/*.val =*/{0x20ccfd66, 0x27073338, 0x28c828aa, 0x10615937, 0x185f201a, 0x37735923, 0x299953f9, 0x18f6c842, 0x294}}, +{/*.val =*/{0x10667eb3, 0x1383999c, 0x34641455, 0x830ac9b, 0x2c2f900d, 0x3bb9ac91, 0x14cca9fc, 0xc7b6421, 0x14a}}, +{/*.val =*/{0x8333d71, 0x29c1cccc, 0x3a320a2a, 0x2418564d, 0x3617c806, 0x1ddcd648, 0x2a6654fe, 0x63db210, 0x80a5}}, +{/*.val =*/{0x4199cd0, 0x14e0e664, 0x3d190515, 0x120c2b26, 0x1b0be403, 0xeee6b24, 0x15332a7f, 0x231ed908, 0xc052}}, +{/*.val =*/{0x20cce68, 0x2a707332, 0x1e8c828a, 0x29061593, 0xd85f201, 0x27773592, 0xa99953f, 0x118f6c84, 0x6029}}, +{/*.val =*/{0x1066734, 0x15383999, 0x2f464145, 0x34830ac9, 0x6c2f900, 0x33bb9ac9, 0x54cca9f, 0x28c7b642, 0x3014}}, +{/*.val =*/{0x2083339a, 0x2a9c1ccc, 0x37a320a2, 0x1a418564, 0x23617c80, 0x39ddcd64, 0x2a6654f, 0x1463db21, 0x180a}}, +{/*.val =*/{0x104199cd, 0x154e0e66, 0x1bd19051, 0xd20c2b2, 0x11b0be40, 0x3ceee6b2, 0x215332a7, 0xa31ed90, 0xc05}}, +{/*.val =*/{0x820cafe, 0x2aa70731, 0xde8c828, 0x6906159, 0x8d85f20, 0x3e777359, 0x10a99953, 0x2518f6c8, 0x8602}}, +{/*.val =*/{0x2410657f, 0x15538398, 0x26f46414, 0x34830ac, 0x246c2f90, 0x3f3bb9ac, 0x854cca9, 0x128c7b64, 0x4301}}, +{/*.val =*/{0x120830d7, 0xaa9c1ca, 0x137a320a, 0x1a41856, 0x123617c8, 0x3f9ddcd6, 0x42a6654, 0x29463db2, 0xa180}}, +{/*.val =*/{0x9041683, 0x554e0e3, 0x9bd1905, 0xd20c2b, 0x91b0be4, 0x1fceee6b, 0x215332a, 0x14a31ed9, 0xd0c0}}, +{/*.val =*/{0x24820959, 0x22aa706f, 0x24de8c82, 0x690615, 0x248d85f2, 0xfe77735, 0x210a9995, 0xa518f6c, 0xe860}}, +{/*.val =*/{0x324102c4, 0x11553835, 0x326f4641, 0x34830a, 0x3246c2f9, 0x27f3bb9a, 0x10854cca, 0x528c7b6, 0xf430}}, +{/*.val =*/{0x39208162, 0x28aa9c1a, 0x1937a320, 0x201a4185, 0x1923617c, 0x13f9ddcd, 0x842a665, 0x29463db, 0x7a18}}, +{/*.val =*/{0x1c9040b1, 0x14554e0d, 0x2c9bd190, 0x100d20c2, 0x2c91b0be, 0x29fceee6, 0x24215332, 0x14a31ed, 0x3d0c}}, +{/*.val =*/{0x2e481e70, 0xa2aa704, 0x164de8c8, 0x8069061, 0x1648d85f, 0x14fe7773, 0x3210a999, 0xa518f6, 0x9e86}}, +{/*.val =*/{0x17240f38, 0x5155382, 0x2b26f464, 0x24034830, 0x2b246c2f, 0x2a7f3bb9, 0x190854cc, 0x528c7b, 0x4f43}}, +{/*.val =*/{0xb92079c, 0x28aa9c1, 0x15937a32, 0x3201a418, 0x35923617, 0x153f9ddc, 0x2c842a66, 0x2029463d, 0x27a1}}, +{/*.val =*/{0x25c903ce, 0x14554e0, 0xac9bd19, 0x3900d20c, 0x1ac91b0b, 0xa9fceee, 0x36421533, 0x3014a31e, 0x13d0}}, +{/*.val =*/{0x12e481e7, 0x20a2aa70, 0x564de8c, 0x3c806906, 0xd648d85, 0x254fe777, 0x1b210a99, 0x180a518f, 0x9e8}}, +{/*.val =*/{0x9723f0b, 0x10515536, 0x2b26f46, 0x3e403483, 0x26b246c2, 0x32a7f3bb, 0x2d90854c, 0xc0528c7, 0x84f4}}, +{/*.val =*/{0x4b91d9d, 0x828aa99, 0x215937a3, 0x1f201a41, 0x33592361, 0x1953f9dd, 0x36c842a6, 0x6029463, 0xc27a}}, +{/*.val =*/{0x225c8ce6, 0x2414554a, 0x30ac9bd1, 0x2f900d20, 0x39ac91b0, 0xca9fcee, 0x3b642153, 0x3014a31, 0xe13d}}, +{/*.val =*/{0x112e4673, 0x320a2aa5, 0x18564de8, 0x17c80690, 0x1cd648d8, 0x2654fe77, 0x3db210a9, 0x2180a518, 0x709e}}, +{/*.val =*/{0x28972151, 0x19051550, 0xc2b26f4, 0xbe40348, 0x2e6b246c, 0x332a7f3b, 0x1ed90854, 0x10c0528c, 0xb84f}}, +{/*.val =*/{0x144b8ec0, 0xc828aa6, 0x615937a, 0x5f201a4, 0x37359236, 0x19953f9d, 0xf6c842a, 0x28602946, 0xdc27}}, +{/*.val =*/{0xa25c760, 0x6414553, 0x30ac9bd, 0x2f900d2, 0x3b9ac91b, 0xcca9fce, 0x7b64215, 0x343014a3, 0x6e13}}, +{/*.val =*/{0x2512e3b0, 0x2320a2a9, 0x18564de, 0x217c8069, 0x1dcd648d, 0x26654fe7, 0x23db210a, 0x3a180a51, 0x3709}}, +{/*.val =*/{0x328971d8, 0x11905154, 0x20c2b26f, 0x30be4034, 0x2ee6b246, 0x1332a7f3, 0x31ed9085, 0x3d0c0528, 0x1b84}}, +{/*.val =*/{0x1944b8ec, 0x28c828aa, 0x10615937, 0x185f201a, 0x37735923, 0x299953f9, 0x18f6c842, 0x1e860294, 0xdc2}}, +{/*.val =*/{0xca25c76, 0x34641455, 0x830ac9b, 0x2c2f900d, 0x3bb9ac91, 0x14cca9fc, 0xc7b6421, 0xf43014a, 0x6e1}}, +{/*.val =*/{0x26512e3b, 0x3a320a2a, 0x2418564d, 0x3617c806, 0x1ddcd648, 0x2a6654fe, 0x63db210, 0x27a180a5, 0x370}}, +{/*.val =*/{0x13289535, 0x3d190513, 0x120c2b26, 0x1b0be403, 0xeee6b24, 0x15332a7f, 0x231ed908, 0x13d0c052, 0x81b8}}, +{/*.val =*/{0x299448b2, 0x1e8c8287, 0x29061593, 0xd85f201, 0x27773592, 0xa99953f, 0x118f6c84, 0x9e86029, 0xc0dc}}, +{/*.val =*/{0x34ca2459, 0x2f464143, 0x34830ac9, 0x6c2f900, 0x33bb9ac9, 0x54cca9f, 0x28c7b642, 0x4f43014, 0x606e}}, +{/*.val =*/{0x3a651044, 0x37a3209f, 0x1a418564, 0x23617c80, 0x39ddcd64, 0x2a6654f, 0x1463db21, 0x27a180a, 0xb037}}, +{/*.val =*/{0x3d328822, 0x1bd1904f, 0xd20c2b2, 0x11b0be40, 0x3ceee6b2, 0x215332a7, 0xa31ed90, 0x213d0c05, 0x581b}}, +{/*.val =*/{0x3e994411, 0xde8c827, 0x6906159, 0x8d85f20, 0x3e777359, 0x10a99953, 0x2518f6c8, 0x309e8602, 0x2c0d}}, +{/*.val =*/{0x3f4ca020, 0x26f46411, 0x34830ac, 0x246c2f90, 0x3f3bb9ac, 0x854cca9, 0x128c7b64, 0x384f4301, 0x9606}}, +{/*.val =*/{0x3fa65010, 0x137a3208, 0x1a41856, 0x123617c8, 0x3f9ddcd6, 0x42a6654, 0x29463db2, 0x1c27a180, 0x4b03}}, +{/*.val =*/{0x1fd32808, 0x9bd1904, 0xd20c2b, 0x91b0be4, 0x1fceee6b, 0x215332a, 0x14a31ed9, 0x2e13d0c0, 0x2581}}, +{/*.val =*/{0xfe99404, 0x24de8c82, 0x690615, 0x248d85f2, 0xfe77735, 0x210a9995, 0xa518f6c, 0x3709e860, 0x12c0}}, +{/*.val =*/{0x7f4ca02, 0x326f4641, 0x34830a, 0x3246c2f9, 0x27f3bb9a, 0x10854cca, 0x528c7b6, 0x1b84f430, 0x960}}, +{/*.val =*/{0x23fa6501, 0x1937a320, 0x201a4185, 0x1923617c, 0x13f9ddcd, 0x842a665, 0x29463db, 0xdc27a18, 0x4b0}}, +{/*.val =*/{0x11fd3098, 0x2c9bd18e, 0x100d20c2, 0x2c91b0be, 0x29fceee6, 0x24215332, 0x14a31ed, 0x6e13d0c, 0x8258}}, +{/*.val =*/{0x8fe984c, 0x164de8c7, 0x8069061, 0x1648d85f, 0x14fe7773, 0x3210a999, 0xa518f6, 0x3709e86, 0x412c}}, +{/*.val =*/{0x247f4c26, 0x2b26f463, 0x24034830, 0x2b246c2f, 0x2a7f3bb9, 0x190854cc, 0x528c7b, 0x1b84f43, 0x2096}}, +{/*.val =*/{0x323fa613, 0x15937a31, 0x3201a418, 0x35923617, 0x153f9ddc, 0x2c842a66, 0x2029463d, 0xdc27a1, 0x104b}}, +{/*.val =*/{0x391fd121, 0xac9bd16, 0x3900d20c, 0x1ac91b0b, 0xa9fceee, 0x36421533, 0x3014a31e, 0x206e13d0, 0x8825}}, +{/*.val =*/{0x1c8fe6a8, 0x564de89, 0x3c806906, 0xd648d85, 0x254fe777, 0x1b210a99, 0x180a518f, 0x303709e8, 0xc412}}, +{/*.val =*/{0x2e47f354, 0x2b26f44, 0x3e403483, 0x26b246c2, 0x32a7f3bb, 0x2d90854c, 0xc0528c7, 0x181b84f4, 0x6209}}, +{/*.val =*/{0x1723f9aa, 0x215937a2, 0x1f201a41, 0x33592361, 0x1953f9dd, 0x36c842a6, 0x6029463, 0x2c0dc27a, 0x3104}}, +{/*.val =*/{0xb91fcd5, 0x30ac9bd1, 0x2f900d20, 0x39ac91b0, 0xca9fcee, 0x3b642153, 0x3014a31, 0x1606e13d, 0x1882}}, +{/*.val =*/{0x25c8fc82, 0x18564de6, 0x17c80690, 0x1cd648d8, 0x2654fe77, 0x3db210a9, 0x2180a518, 0xb03709e, 0x8c41}}, +{/*.val =*/{0x12e47e41, 0xc2b26f3, 0xbe40348, 0x2e6b246c, 0x332a7f3b, 0x1ed90854, 0x10c0528c, 0x2581b84f, 0x4620}}, +{/*.val =*/{0x29723d38, 0x6159377, 0x5f201a4, 0x37359236, 0x19953f9d, 0xf6c842a, 0x28602946, 0x12c0dc27, 0xa310}}, +{/*.val =*/{0x34b91e9c, 0x30ac9bb, 0x2f900d2, 0x3b9ac91b, 0xcca9fce, 0x7b64215, 0x343014a3, 0x9606e13, 0x5188}}, +{/*.val =*/{0x3a5c8f4e, 0x18564dd, 0x217c8069, 0x1dcd648d, 0x26654fe7, 0x23db210a, 0x3a180a51, 0x4b03709, 0x28c4}}, +{/*.val =*/{0x3d2e47a7, 0x20c2b26e, 0x30be4034, 0x2ee6b246, 0x1332a7f3, 0x31ed9085, 0x3d0c0528, 0x2581b84, 0x1462}}, +{/*.val =*/{0x1e9721eb, 0x10615935, 0x185f201a, 0x37735923, 0x299953f9, 0x18f6c842, 0x1e860294, 0x12c0dc2, 0x8a31}}, +{/*.val =*/{0x2f4b8f0d, 0x830ac98, 0x2c2f900d, 0x3bb9ac91, 0x14cca9fc, 0xc7b6421, 0xf43014a, 0x209606e1, 0xc518}}, +{/*.val =*/{0x17a5c59e, 0x2418564a, 0x3617c806, 0x1ddcd648, 0x2a6654fe, 0x63db210, 0x27a180a5, 0x104b0370, 0xe28c}}, +{/*.val =*/{0xbd2e2cf, 0x120c2b25, 0x1b0be403, 0xeee6b24, 0x15332a7f, 0x231ed908, 0x13d0c052, 0x82581b8, 0x7146}}, +{/*.val =*/{0x25e96f7f, 0x29061590, 0xd85f201, 0x27773592, 0xa99953f, 0x118f6c84, 0x9e86029, 0x412c0dc, 0xb8a3}}, +{/*.val =*/{0x12f4b5d7, 0x34830ac6, 0x6c2f900, 0x33bb9ac9, 0x54cca9f, 0x28c7b642, 0x4f43014, 0x2209606e, 0xdc51}}, +{/*.val =*/{0x97a5903, 0x1a418561, 0x23617c80, 0x39ddcd64, 0x2a6654f, 0x1463db21, 0x27a180a, 0x3104b037, 0xee28}}, +{/*.val =*/{0x24bd2a99, 0xd20c2ae, 0x11b0be40, 0x3ceee6b2, 0x215332a7, 0xa31ed90, 0x213d0c05, 0x1882581b, 0xf714}}, +{/*.val =*/{0x125e9364, 0x6906155, 0x8d85f20, 0x3e777359, 0x10a99953, 0x2518f6c8, 0x309e8602, 0xc412c0d, 0xfb8a}}, +{/*.val =*/{0x292f49b2, 0x34830aa, 0x246c2f90, 0x3f3bb9ac, 0x854cca9, 0x128c7b64, 0x384f4301, 0x6209606, 0x7dc5}}, +{/*.val =*/{0x1497a4d9, 0x1a41855, 0x123617c8, 0x3f9ddcd6, 0x42a6654, 0x29463db2, 0x1c27a180, 0x23104b03, 0x3ee2}}, +{/*.val =*/{0x2a4bd084, 0xd20c28, 0x91b0be4, 0x1fceee6b, 0x215332a, 0x14a31ed9, 0x2e13d0c0, 0x11882581, 0x9f71}}, +{/*.val =*/{0x1525e842, 0x690614, 0x248d85f2, 0xfe77735, 0x210a9995, 0xa518f6c, 0x3709e860, 0x28c412c0, 0x4fb8}}, +{/*.val =*/{0xa92f421, 0x34830a, 0x3246c2f9, 0x27f3bb9a, 0x10854cca, 0x528c7b6, 0x1b84f430, 0x14620960, 0x27dc}}, +{/*.val =*/{0x5497828, 0x201a4183, 0x1923617c, 0x13f9ddcd, 0x842a665, 0x29463db, 0xdc27a18, 0xa3104b0, 0x93ee}}, +{/*.val =*/{0x22a4bc14, 0x100d20c1, 0x2c91b0be, 0x29fceee6, 0x24215332, 0x14a31ed, 0x6e13d0c, 0x5188258, 0x49f7}}, +{/*.val =*/{0x31525e0a, 0x8069060, 0x1648d85f, 0x14fe7773, 0x3210a999, 0xa518f6, 0x3709e86, 0x228c412c, 0x24fb}}, +{/*.val =*/{0x18a92f05, 0x24034830, 0x2b246c2f, 0x2a7f3bb9, 0x190854cc, 0x528c7b, 0x1b84f43, 0x31462096, 0x127d}}, +{/*.val =*/{0xc54959a, 0x3201a416, 0x35923617, 0x153f9ddc, 0x2c842a66, 0x2029463d, 0xdc27a1, 0x38a3104b, 0x893e}}, +{/*.val =*/{0x62a4acd, 0x3900d20b, 0x1ac91b0b, 0xa9fceee, 0x36421533, 0x3014a31e, 0x206e13d0, 0x1c518825, 0x449f}}, +{/*.val =*/{0x2315237e, 0x3c806903, 0xd648d85, 0x254fe777, 0x1b210a99, 0x180a518f, 0x303709e8, 0x2e28c412, 0xa24f}}, +{/*.val =*/{0x318a91bf, 0x3e403481, 0x26b246c2, 0x32a7f3bb, 0x2d90854c, 0xc0528c7, 0x181b84f4, 0x37146209, 0x5127}}, +{/*.val =*/{0x38c546f7, 0x1f201a3e, 0x33592361, 0x1953f9dd, 0x36c842a6, 0x6029463, 0x2c0dc27a, 0x3b8a3104, 0xa893}}, +{/*.val =*/{0x1c62a193, 0x2f900d1d, 0x39ac91b0, 0xca9fcee, 0x3b642153, 0x3014a31, 0x1606e13d, 0x3dc51882, 0xd449}}, +{/*.val =*/{0x2e314ee1, 0x17c8068c, 0x1cd648d8, 0x2654fe77, 0x3db210a9, 0x2180a518, 0xb03709e, 0x3ee28c41, 0xea24}}, +{/*.val =*/{0x1718a588, 0xbe40344, 0x2e6b246c, 0x332a7f3b, 0x1ed90854, 0x10c0528c, 0x2581b84f, 0x1f714620, 0xf512}}, +{/*.val =*/{0xb8c52c4, 0x5f201a2, 0x37359236, 0x19953f9d, 0xf6c842a, 0x28602946, 0x12c0dc27, 0xfb8a310, 0x7a89}}, +{/*.val =*/{0x5c62962, 0x2f900d1, 0x3b9ac91b, 0xcca9fce, 0x7b64215, 0x343014a3, 0x9606e13, 0x27dc5188, 0x3d44}}, +{/*.val =*/{0x22e314b1, 0x217c8068, 0x1dcd648d, 0x26654fe7, 0x23db210a, 0x3a180a51, 0x4b03709, 0x13ee28c4, 0x1ea2}}, +{/*.val =*/{0x11718870, 0x30be4032, 0x2ee6b246, 0x1332a7f3, 0x31ed9085, 0x3d0c0528, 0x2581b84, 0x9f71462, 0x8f51}}, +{/*.val =*/{0x8b8c438, 0x185f2019, 0x37735923, 0x299953f9, 0x18f6c842, 0x1e860294, 0x12c0dc2, 0x24fb8a31, 0x47a8}}, +{/*.val =*/{0x245c621c, 0x2c2f900c, 0x3bb9ac91, 0x14cca9fc, 0xc7b6421, 0xf43014a, 0x209606e1, 0x127dc518, 0x23d4}}, +{/*.val =*/{0x122e310e, 0x3617c806, 0x1ddcd648, 0x2a6654fe, 0x63db210, 0x27a180a5, 0x104b0370, 0x93ee28c, 0x11ea}}, +{/*.val =*/{0x9171887, 0x1b0be403, 0xeee6b24, 0x15332a7f, 0x231ed908, 0x13d0c052, 0x82581b8, 0x49f7146, 0x8f5}}, +{/*.val =*/{0x248b8a5b, 0xd85f1ff, 0x27773592, 0xa99953f, 0x118f6c84, 0x9e86029, 0x412c0dc, 0x224fb8a3, 0x847a}}, +{/*.val =*/{0x3245c345, 0x6c2f8fd, 0x33bb9ac9, 0x54cca9f, 0x28c7b642, 0x4f43014, 0x2209606e, 0x1127dc51, 0xc23d}}, +{/*.val =*/{0x3922dfba, 0x23617c7c, 0x39ddcd64, 0x2a6654f, 0x1463db21, 0x27a180a, 0x3104b037, 0x2893ee28, 0xe11e}}, +{/*.val =*/{0x1c916fdd, 0x11b0be3e, 0x3ceee6b2, 0x215332a7, 0xa31ed90, 0x213d0c05, 0x1882581b, 0x1449f714, 0x708f}}, +{/*.val =*/{0xe48b606, 0x8d85f1d, 0x3e777359, 0x10a99953, 0x2518f6c8, 0x309e8602, 0xc412c0d, 0x2a24fb8a, 0xb847}}, +{/*.val =*/{0x27245b03, 0x246c2f8e, 0x3f3bb9ac, 0x854cca9, 0x128c7b64, 0x384f4301, 0x6209606, 0x35127dc5, 0x5c23}}, +{/*.val =*/{0x13922b99, 0x123617c5, 0x3f9ddcd6, 0x42a6654, 0x29463db2, 0x1c27a180, 0x23104b03, 0x3a893ee2, 0xae11}}, +{/*.val =*/{0x29c913e4, 0x91b0be0, 0x1fceee6b, 0x215332a, 0x14a31ed9, 0x2e13d0c0, 0x11882581, 0x3d449f71, 0xd708}}, +{/*.val =*/{0x14e489f2, 0x248d85f0, 0xfe77735, 0x210a9995, 0xa518f6c, 0x3709e860, 0x28c412c0, 0x1ea24fb8, 0x6b84}}, }; #endif #if USE_PRECOMPUTED_CP const curve_point secp256k1_cp[256] = { -{.x = { .val = {0x16f81798, 0x27ca056c, 0x1ce28d95, 0x26ff36cb, 0x70b0702, 0x18a573a, 0xbbac55a, 0x199fbe77, 0x79be}}, - .y = { .val = {0x3b10d4b8, 0x311f423f, 0x28554199, 0x5ed1229, 0x1108a8fd, 0x13eff038, 0x3c4655da, 0x369dc9a8, 0x483a}}}, -{.x = { .val = {0x1c709ee5, 0x2eb026e5, 0xef3ca7a, 0x1de392e3, 0x7cd85c, 0x1501ba57, 0x17d6d304, 0x1fe5107b, 0xc604}}, - .y = { .val = {0x10cfe52a, 0xd90c6a5, 0x266d0e12, 0x3d8c994c, 0x2ceaeef7, 0x16106519, 0x1c339a3c, 0x1a3fa98f, 0x1ae1}}}, -{.x = { .val = {0x28c4cd13, 0x13ea52af, 0x2e075847, 0x1b04e403, 0xb1404cc, 0x3924124c, 0x180f3581, 0x36fc7043, 0xe493}}, - .y = { .val = {0x7739922, 0x3fa5ef71, 0x3bdfe40c, 0x19eb8cef, 0x251448d9, 0xb88263a, 0x55b7564, 0x264fa835, 0x51ed}}}, -{.x = { .val = {0x210a2a01, 0x1de13bcf, 0x1af888a6, 0x6f74179, 0xf3c2f0a, 0xe10fedc, 0x2351daff, 0x39785732, 0x2f01}}, - .y = { .val = {0x2cbde904, 0x1768b2dd, 0x25b7617b, 0x3884f5ae, 0x2d13b4c2, 0x3420a84c, 0x39949293, 0x2a29d054, 0x5c4d}}}, -{.x = { .val = {0x2a6dec0a, 0x113ba278, 0x7a5ae9c, 0x28c4da6e, 0x23e97b2, 0x6aaf087, 0x29ec5301, 0x33a4ed67, 0xe60f}}, - .y = { .val = {0x29616821, 0x7ccb339, 0xd23f0be, 0x25a24791, 0x39371012, 0x267cd3d5, 0x195929db, 0x141ce679, 0xf7e3}}}, -{.x = { .val = {0x7143e65, 0x17436f50, 0x104a61d7, 0x33ff2e26, 0x3378ceda, 0x1b81538b, 0x1a22d47b, 0x2675d3ed, 0xd301}}, - .y = { .val = {0x24106ab9, 0x16cffc7c, 0xed81960, 0x1d8330d9, 0x380651f, 0x1b7b27a6, 0x3d5c3b3d, 0x236742b8, 0x9503}}}, -{.x = { .val = {0x3874ef8b, 0xde4639b, 0x1bafd81e, 0x131bc773, 0x32823cfc, 0x147abe0, 0x2eab70b1, 0x30550b45, 0xbf23}}, - .y = { .val = {0x26831d9f, 0x370dfbf9, 0x11e2f784, 0x8bf1520, 0x1392e4c5, 0x24a282e9, 0x3737ad, 0x219bf0cc, 0x5cb3}}}, -{.x = { .val = {0x2769a24e, 0x11c1dd15, 0x5356556, 0x3d5735c0, 0x11671cbc, 0x30f427df, 0x37a06696, 0xef900cf, 0x34ff}}, - .y = { .val = {0x33cc2f1a, 0x124419e9, 0xf8b6818, 0x37c5b0fa, 0x32098c55, 0x18676260, 0x36c553f6, 0x4588e88, 0x5d9d}}}, -{.x = { .val = {0x15f51508, 0x191b88ff, 0x1ac1ca10, 0x30e72af5, 0x2de238d8, 0x29b8f85c, 0x209d9ea2, 0x98c84b1, 0x8282}}, - .y = { .val = {0x36e26caf, 0xc6dbabf, 0x37b17bed, 0x3584eb0b, 0x360ace62, 0x95ba0c2, 0x3dfe45e8, 0x2a026155, 0x11f8}}}, -{.x = { .val = {0x2f34a24d, 0x9b8b003, 0x1e159d09, 0x36f25a36, 0x3918d50a, 0x2a15ea73, 0x39ff3905, 0x1c2ca1e9, 0x4653}}, - .y = { .val = {0x333887f4, 0xbe3ec82, 0x1d37a10a, 0x23826c85, 0x2ec2c158, 0x3e2f6bf7, 0xc082a4a, 0xc6ce0da, 0x35e5}}}, -{.x = { .val = {0x2285131f, 0x16e406cb, 0x13b088d, 0x3b1bb372, 0x2d6240aa, 0x12863d9a, 0xbd77d66, 0x3aee388f, 0x241f}}, - .y = { .val = {0x2750026d, 0x2ecf99bc, 0x10cb5afa, 0x143f43ef, 0x181df8cd, 0x1082f44e, 0xf8d3d6c, 0x1e367fe5, 0x5133}}}, -{.x = { .val = {0x1b920471, 0x372d8c1a, 0x23de0de, 0xc62e17d, 0x18f8d9fc, 0x1330a60f, 0x2fa79fce, 0x36d3a85c, 0x5d1b}}, - .y = { .val = {0x37b83103, 0xcc199b, 0x2c56e7b7, 0x3ac7a665, 0x22265679, 0x2ee650e2, 0x39e2e794, 0x2099de4d, 0x2843}}}, -{.x = { .val = {0x11e5b739, 0xff396d5, 0x12222ed7, 0x2e4e0cff, 0x3c846de0, 0x26731b1b, 0x3865a72f, 0x567dca2, 0x175e}}, - .y = { .val = {0x29fed695, 0x3be9bffb, 0x124345c6, 0x2d6556b7, 0x371f5eac, 0x3e5e947f, 0x79eba4e, 0x1b83678f, 0xd350}}}, -{.x = { .val = {0x6bc47d6, 0x39e01279, 0x2da121bc, 0x3f7fad71, 0x39c62130, 0x3ef32384, 0x332d7a5f, 0x4fc0ff, 0x423a}}, - .y = { .val = {0xb548a34, 0x48db9b6, 0x24f009ed, 0x363b0d4, 0x36b3c772, 0x1e7deeeb, 0x1d970a11, 0x3803f878, 0xb91a}}}, -{.x = { .val = {0x416824a, 0xb7dbde, 0x33e27413, 0x37d98bce, 0x16877649, 0x1e9eaf3, 0x3b905089, 0x1a916b07, 0x111d}}, - .y = { .val = {0x2108e9d0, 0x26844750, 0x2daca4ca, 0x1c002265, 0x65952f0, 0x35236ffc, 0x2affbb90, 0x244711e3, 0x696}}}, -{.x = { .val = {0x1bced775, 0x2d7b7780, 0x2f74e56a, 0x242da297, 0x39dcff72, 0x2576faf2, 0x3c8b8ad7, 0x1b725eb1, 0x4a4a}}, - .y = { .val = {0x278dd66d, 0xafe3da2, 0x24742acb, 0x3a4336d0, 0xf4571d, 0x3be7dce7, 0x31e72943, 0x46c0598, 0x5299}}}, -{.x = { .val = {0x3ff4640, 0x9aeb63e, 0x1552ffe5, 0x11071f95, 0x262ee053, 0x3ab016d8, 0xc9c99c, 0x243511ec, 0x363d}}, - .y = { .val = {0x3bee9de9, 0x800f1fc, 0x199ecb6, 0x2e6a2402, 0x33363145, 0x2d114e5f, 0x32221953, 0x1ceb7f1c, 0x4e2}}}, -{.x = { .val = {0x2f92c541, 0x9c4a972, 0x2dfb59dd, 0x18bec04b, 0x3b02bf0b, 0x25cf1b24, 0x27e9b553, 0x2619bb66, 0x4c1b}}, - .y = { .val = {0x68fe020, 0xb13cff7, 0x3eb1ad7, 0x14bab5f9, 0x16e69cc6, 0x32dd4f39, 0x28a0f7fb, 0x24b4c82f, 0xc1f7}}}, -{.x = { .val = {0x3eaaf3d1, 0x323ca32, 0x228f135e, 0xcfb6f06, 0xb54e32, 0x28bcf01e, 0x3b12b529, 0xe1deea0, 0xa408}}, - .y = { .val = {0x30b254b9, 0x4ad4d37, 0x2d1ef90b, 0x79d5db, 0x21b3e220, 0x3e0f5a4d, 0x3bc79b8b, 0x3d84bfbb, 0x40e9}}}, -{.x = { .val = {0x3940d33a, 0x334f6d69, 0x14203b98, 0x3620291, 0x16c86f6e, 0x38f868bd, 0xc0b53a4, 0x319074a3, 0xa804}}, - .y = { .val = {0x2d46967a, 0xf3a57e9, 0xf736a94, 0x3c632a27, 0x2047e81a, 0x30a10b05, 0x3a6d03de, 0x20c94acb, 0x95be}}}, -{.x = { .val = {0x1ffdf80c, 0x27de6957, 0x15bcd1b6, 0x3929e068, 0x5638843, 0x912d6dd, 0x3c2be8c6, 0x17c5977c, 0x8b4b}}, - .y = { .val = {0x1fd4fd36, 0xfbfc319, 0x162ee56b, 0x38cd9518, 0x30da04f9, 0x2f5e04ea, 0x308b4b3f, 0x29bda34, 0x4aad}}}, -{.x = { .val = {0x755e4be, 0x2cfc99c5, 0x17c997ab, 0x2bd93b90, 0x3c611071, 0x5f1fb20, 0x291718ce, 0x1739384c, 0xed0c}}, - .y = { .val = {0x207bf42f, 0xfe7e9ba, 0x23ddab16, 0x364e495d, 0x3ea68049, 0x36b5fd69, 0x345bdbf3, 0x27f1ef08, 0x221a}}}, -{.x = { .val = {0x7cec8ab, 0x12db9b20, 0x20552ced, 0xc95159b, 0x31fae8e5, 0x570fe0f, 0xe694b3b, 0x2c04f113, 0xfaec}}, - .y = { .val = {0x2b155070, 0x26077f66, 0x5e2e2e8, 0xcaca1ae, 0x2fb13d9c, 0x380b1bb0, 0x2cb57fc2, 0x2d7a43a7, 0xcc09}}}, -{.x = { .val = {0x1ad1b1f7, 0x1fd93aba, 0x323cd3e0, 0x2cb76093, 0xbcafdb3, 0xc682cdf, 0x2d2f2c87, 0x2284cb72, 0x9bb}}, - .y = { .val = {0x3811c80, 0x104c189f, 0x752d536, 0x152a103d, 0x63e850f, 0x2774a13e, 0x2e3b9b6f, 0x2cacabfb, 0x945b}}}, -{.x = { .val = {0x1232fcda, 0x2d845649, 0x2c0e77bc, 0x36ffe9, 0x1548c7b7, 0x1dc7002f, 0x3996d6bf, 0x2ea9b976, 0x723c}}, - .y = { .val = {0x1eb39f5f, 0x7701a76, 0x37949480, 0x1828194d, 0x24d6e26, 0x44dd222, 0xc498a92, 0x19ed5657, 0x96e8}}}, -{.x = { .val = {0xca030d5, 0x3f4e0f58, 0x39849071, 0x90290c1, 0x33a3c62d, 0x35f7115d, 0x3744d343, 0x29e190de, 0x57ef}}, - .y = { .val = {0x34b02f9e, 0x1ead109, 0x1e9974ab, 0x26db4ab9, 0x1e03ec68, 0x189f24a3, 0x8518893, 0x36c2f46d, 0xd712}}}, -{.x = { .val = {0xc584dd5, 0x3ebf1ddc, 0x27b012a7, 0x2015df8c, 0x226cb910, 0x3dfa7354, 0xbc42a2d, 0x2f50da8a, 0x264b}}, - .y = { .val = {0x3704ab11, 0x18489e4d, 0x17b8d8de, 0x46090dc, 0x33be226a, 0x1d738930, 0x93b4d4f, 0x1bea53b8, 0xd87c}}}, -{.x = { .val = {0xb2438e8, 0x2fc9af61, 0x1bdec9d2, 0x22f187f5, 0x36a79da7, 0x21701588, 0xd2bbdac, 0x19492f50, 0xa94c}}, - .y = { .val = {0x318661f4, 0xb8b236f, 0xe39b2bc, 0x174f1828, 0x19e3a7e, 0x24865414, 0x16280fd7, 0x7f664be, 0xb520}}}, -{.x = { .val = {0xe7dd7fa, 0x294cfb28, 0x3a919839, 0x11e5848d, 0x2d3b509, 0x3fbb204b, 0x2bf98ba5, 0x293524ef, 0xeebf}}, - .y = { .val = {0x21de8999, 0x37f53f6b, 0x311f712d, 0x393370e9, 0x38089d9a, 0x39fb6bc5, 0x2f0f269e, 0x2328e5c3, 0x5d9a}}}, -{.x = { .val = {0x7d297fd, 0x1afba421, 0x36766d67, 0x3a92f023, 0x18495fc4, 0x3180c704, 0x17bfda61, 0x12b5e9ea, 0x381c}}, - .y = { .val = {0x3d493fc5, 0xeb38c61, 0x3939c009, 0x11440cb6, 0x115eccf0, 0x397e9c26, 0x2eee48f3, 0x3d4ec8e3, 0x936a}}}, -{.x = { .val = {0x2ede454c, 0x1235c108, 0x3dd08b24, 0x3c7417fb, 0x138c479c, 0x420c765, 0x1c63bcce, 0x2e73416b, 0xe1ef}}, - .y = { .val = {0x28913797, 0x367f48ce, 0x3a2d4c6a, 0x138c9129, 0x7712346, 0x15307ff9, 0x39be7b01, 0x114c362b, 0xecb}}}, -{.x = { .val = {0x29eb99a4, 0xcffbacc, 0x3d47b18d, 0x395067cc, 0x3475a8c7, 0x308d7a6b, 0x17010c5a, 0x3e6c689a, 0x5318}}, - .y = { .val = {0x3e91f92d, 0x31c9bbbb, 0x1e3ec652, 0x7cad034, 0x3405e8a4, 0xb64ebae, 0x1a419577, 0x33fad2fb, 0xf44c}}}, -{.x = { .val = {0x39a48db0, 0x3f5e0d6c, 0x33c03bfe, 0x48568a6, 0x3bde459f, 0x742826d, 0x27167279, 0x11369a5b, 0x100f}}, - .y = { .val = {0x2bc65a09, 0x3ef57358, 0x35195ac0, 0x3fd2863f, 0x90666b7, 0x23ccc030, 0xb772ec, 0x384c64a8, 0xcdd9}}}, -{.x = { .val = {0x1e4df706, 0x2c14a13c, 0x37d08084, 0x36723e48, 0xc4199d8, 0x577fcad, 0x1c771a84, 0x227cb3ad, 0x8c09}}, - .y = { .val = {0x1d72fa98, 0xdab168d, 0x16511aa7, 0x379afd45, 0x1c966c60, 0x85cb2e7, 0x32034ffd, 0x2f4113d0, 0xfb4d}}}, -{.x = { .val = {0x1c47bffd, 0x798f0cf, 0x95bc1bb, 0x14a14e6f, 0x22c0259c, 0x1205d0c9, 0x26704c4a, 0x54f1789, 0xfb8f}}, - .y = { .val = {0x1949b095, 0x24291777, 0x5426130, 0x3784e26b, 0x3ccd531d, 0x284766d2, 0x621816f, 0x1ea77178, 0x6ca2}}}, -{.x = { .val = {0xbb2629a, 0x23e86e2d, 0x337a7b8b, 0x280b161d, 0x28708465, 0x3327c29c, 0x151755a0, 0xccff5d7, 0xe747}}, - .y = { .val = {0x2946f6d6, 0x3e365869, 0x21a969a9, 0x20ddaa9b, 0xc2581c8, 0x10d80e01, 0x30c114cc, 0x3f805141, 0xf2af}}}, -{.x = { .val = {0x2534fd2d, 0x322b379b, 0xf3b3852, 0x1fe35119, 0x4c017a7, 0x2489e928, 0x3ed1b1dc, 0x6f898b1, 0xe103}}, - .y = { .val = {0x1456a00d, 0x113c63ca, 0x21ced79a, 0x24b75067, 0x17535af2, 0x1a905d96, 0x405e6bb, 0x1864a250, 0x9d70}}}, -{.x = { .val = {0x295c8356, 0x1389f8da, 0x294d8578, 0x229ab177, 0x29b2c902, 0x2577343c, 0x89eab9f, 0xfc89320, 0xf4b9}}, - .y = { .val = {0x3e001fd3, 0x356186e6, 0x115609ab, 0x1fbc4d12, 0xeee90c3, 0x17da9e90, 0x162dfb0e, 0x24bb018a, 0xa67a}}}, -{.x = { .val = {0x3b160e8a, 0x358bf85, 0x17e696c2, 0x7a144be, 0x1b08b0d5, 0x188ba809, 0x15236b19, 0x2b287f39, 0x9d1}}, - .y = { .val = {0x3ca04c44, 0x13814315, 0x212b5e53, 0x3a783ba4, 0x18c27e6f, 0x19a4b383, 0x1f0c63e5, 0x623d440, 0x1153}}}, -{.x = { .val = {0x35ba7fc2, 0x25f5f411, 0x3c39562e, 0x22cea4ef, 0x21cde751, 0xab5e4e0, 0x2b9e18a, 0x16731153, 0xc66c}}, - .y = { .val = {0x375f5956, 0x3b0f1a73, 0x15955977, 0x298376c, 0x10cb2f0, 0x13cf3aab, 0x30fcfbea, 0xbf8afec, 0xd959}}}, -{.x = { .val = {0x1094696d, 0x3579a236, 0x1d6af52, 0x3e2c99a9, 0x3bd7ec5c, 0xa0e7c50, 0x15b530ac, 0x1b2b91b5, 0xfeea}}, - .y = { .val = {0x18090088, 0x5577afc, 0x41442d3, 0x72255f3, 0x3ecd5c98, 0x39384afc, 0xe1bab06, 0x1adb25f7, 0xe57c}}}, -{.x = { .val = {0x2e752b08, 0x2a90102b, 0x331a1870, 0x7b2b82c, 0x32e17914, 0x986be76, 0x387e1c53, 0x2d886b6, 0x4d00}}, - .y = { .val = {0x8302cea, 0x39ca147d, 0x1c7293a3, 0x1f7d7c46, 0x1972cccb, 0x3609560b, 0xd255cb6, 0x16e3c638, 0x6a0d}}}, -{.x = { .val = {0x75c58ef, 0x22658bf5, 0x21f1b77f, 0x15e8100f, 0x317128d6, 0x28988451, 0x1a05dd6a, 0x1c32880f, 0x71f5}}, - .y = { .val = {0x135d420e, 0x219269cb, 0x3363e7df, 0x11174030, 0x95b8df2, 0x155cd16f, 0x880dd25, 0x1056e577, 0xeb42}}}, -{.x = { .val = {0x3ff8359, 0x122c181, 0x25e76516, 0x2d208771, 0x1da01446, 0xa0ad708, 0x3d253b7d, 0x2cd8a7de, 0xa2b7}}, - .y = { .val = {0x3e86fec2, 0x8e5ffb3, 0x6f3835a, 0x34420d41, 0x1e29c910, 0x24de8fdc, 0x1122d57a, 0xe2505a5, 0x6930}}}, -{.x = { .val = {0x1ec6cb1, 0xfea5e2f, 0x8583de3, 0x3b595f60, 0x3fca3cfe, 0x1ef92f9b, 0x9cdcb36, 0x2a476441, 0xda67}}, - .y = { .val = {0x3a68be1d, 0x3a7aa389, 0xf740a17, 0x31eb7142, 0x1780e5de, 0x118fdfb2, 0x242bc41f, 0x2a8d5205, 0x9bac}}}, -{.x = { .val = {0x1fe741c9, 0x3b8f3208, 0xea5a835, 0x2f67cd73, 0xd8718b, 0x3033eabc, 0x1ef587c0, 0x334d97e8, 0x4dba}}, - .y = { .val = {0x338eb623, 0x2f843e0, 0x3c0535f6, 0x30e12827, 0x38299d0c, 0x33f567a0, 0x1892e7fd, 0x1503a294, 0x16c3}}}, -{.x = { .val = {0x34e218da, 0x1fb6a2ea, 0x26860508, 0x13217c54, 0x1c2590f, 0x3c5f63fd, 0x9beee68, 0x3ff12054, 0x13d1}}, - .y = { .val = {0x1b191c19, 0x36d0677, 0x15bd127e, 0x2b40481b, 0x3758bda4, 0x2e4cdec6, 0x1961dcec, 0xe47ea64, 0x6008}}}, -{.x = { .val = {0x22e96db8, 0xced032a, 0x229dbff1, 0x327645b3, 0x30533b3c, 0x271e7116, 0x6000765, 0x13e73bdb, 0x219b}}, - .y = { .val = {0xd3b6bc7, 0x1f7c069e, 0x29057652, 0x13e2b14f, 0x372a6e39, 0x11060300, 0x1efeaf5a, 0x31817656, 0x24d9}}}, -{.x = { .val = {0x1a37b7c0, 0x1d517330, 0x311069f5, 0x2343dee, 0x322151ec, 0x24d7b, 0x34cdda6e, 0x13ea82cc, 0x5390}}, - .y = { .val = {0x22771c8, 0x372c25ac, 0x14434699, 0x26666078, 0xd3c1c13, 0x27b32b08, 0x106d88c, 0x21f42f20, 0x5bc0}}}, -{.x = { .val = {0x38a47ca9, 0x1f343c7c, 0x10f85ad5, 0x1bb9eaab, 0x16995d2a, 0x2644658c, 0x146753cf, 0x1d6be750, 0x1a5}}, - .y = { .val = {0x37ebcdb7, 0x1f177cb9, 0x34d7ea66, 0x2e4f1767, 0x3b8698bd, 0x17f14b86, 0x20dc3cc5, 0x3c72e2ac, 0x3038}}}, -{.x = { .val = {0x2315565b, 0xc275d57, 0x3c20c6ee, 0x2986a0f4, 0x2155d6d3, 0x7d706dd, 0x1d439ca7, 0x3810dd88, 0xf5f0}}, - .y = { .val = {0x1d2ecc82, 0x1e10c2bf, 0x2d7e40a6, 0x2fd86fcf, 0x37101aa5, 0x6245837, 0x2052bf62, 0x1398af96, 0x6b9f}}}, -{.x = { .val = {0x35362d33, 0x2f9e0767, 0x2227642c, 0x32f24851, 0xca4e347, 0x1fcdb65c, 0x36e9a57a, 0x1bc2db02, 0x8f50}}, - .y = { .val = {0x7fa243f, 0x121f432, 0x3bb8eaf3, 0x33e49750, 0x1c336848, 0x315093c, 0x26171953, 0x25574abe, 0x469f}}}, -{.x = { .val = {0x3ad86047, 0x3fe567d0, 0x29b8bcae, 0x2d4e810e, 0xa906779, 0x3329dd93, 0x183a7719, 0x3342f4d6, 0x8e7b}}, - .y = { .val = {0x460372a, 0x284011fa, 0x3fd68b3e, 0x3a238b91, 0x29514579, 0xc410832, 0x1a4b3940, 0x1dc2ca8f, 0x10b7}}}, -{.x = { .val = {0x313f0351, 0x1f4a022f, 0x10389e77, 0x3056e34f, 0x2950df3b, 0x3cc6665, 0x2729dc35, 0x16ea8657, 0x33b3}}, - .y = { .val = {0xb8d7418, 0x2f140f33, 0x889b702, 0x19583bef, 0xd52bcaa, 0x1900d892, 0x2bf87f94, 0x615902, 0xa58a}}}, -{.x = { .val = {0x414bb36, 0x1c771ec9, 0x2d7bca6d, 0x3db84272, 0x1f7e2256, 0x20eb481c, 0x13f955cb, 0x3bab88b2, 0x374d}}, - .y = { .val = {0xdaf734a, 0x21d6faa6, 0xe543217, 0xa3598c0, 0x6f72938, 0xcb01be0, 0x14f99160, 0x196d93f3, 0x1711}}}, -{.x = { .val = {0x2ae7d616, 0x3a2992b5, 0x22a9f0c5, 0x136ebcad, 0x2eb0dc94, 0x1b81ce56, 0x2eae57c4, 0x30271fce, 0x2380}}, - .y = { .val = {0x161bbc1a, 0x266f920, 0x38467560, 0x2be48523, 0x9b09a93, 0x262bbf54, 0x956af15, 0x21864d19, 0x6f8e}}}, -{.x = { .val = {0x19c43862, 0x2a107856, 0x397e6690, 0x29fd3c60, 0x381bde71, 0x2061a26, 0x1ff21e6d, 0x3b4d3073, 0x385e}}, - .y = { .val = {0x142e5453, 0x1163f95, 0x86dc8cc, 0xc13bb08, 0x2bf4576b, 0x77867a7, 0x223f5670, 0x3af0fa3a, 0x283b}}}, -{.x = { .val = {0x38f2827c, 0x320e89c1, 0x2fc1ce2d, 0x320990af, 0x1f67d147, 0x1af84d35, 0x35480045, 0x8820f6b, 0xf6f6}}, - .y = { .val = {0x20aaa102, 0x56c82d4, 0x321bf6d, 0x15f29d12, 0x27cee7e6, 0x315c56cd, 0x33a0faf2, 0x13a05f79, 0x1bcd}}}, -{.x = { .val = {0x315adcb6, 0x3624c825, 0x18c6f369, 0x2470f39f, 0x1fc255cd, 0x32cf0f4, 0x13de2bd7, 0x394623e5, 0xfb26}}, - .y = { .val = {0x18ba68f3, 0x276f28ed, 0xb7ab544, 0x34b2cc6e, 0x10176916, 0x211a9c67, 0x2a34d58e, 0xa204404, 0xf3e1}}}, -{.x = { .val = {0x20788c1e, 0x35136dd5, 0x28bd1d7e, 0x230dc183, 0x3ceab7d1, 0x171af1d8, 0x1132d28f, 0x896446e, 0x8991}}, - .y = { .val = {0xe8f0ef1, 0xd71088a, 0x1ef9e116, 0x25a7213f, 0x3136fa36, 0x21d8d566, 0x1ac9b27b, 0x13661f32, 0xda8b}}}, -{.x = { .val = {0x3fac3a7, 0x181bb61b, 0x147fbc9c, 0x377e1296, 0x3dfa180f, 0x31ce9104, 0xf191637, 0x366e00fb, 0x6f9}}, - .y = { .val = {0x3a842160, 0x21a24180, 0x281002d, 0x29374bd7, 0x5c4d47e, 0x238a8c39, 0x59ba69b, 0x31a3980c, 0x7c80}}}, -{.x = { .val = {0xb7fd72d, 0x327489d1, 0x3e4da175, 0x5d17969, 0x82939da, 0x30db0a11, 0x3411c1cd, 0x3bba894a, 0xae86}}, - .y = { .val = {0xeee38bc, 0xcd32de9, 0x72f7282, 0x24845545, 0x1ff0e98d, 0x2c2b3962, 0x302f962a, 0x24f25c1c, 0x19e9}}}, -{.x = { .val = {0x3c169290, 0x2851d099, 0x336f2ee7, 0x62f9d73, 0x1c2c4887, 0x34be315b, 0x3ff55e61, 0x327e42ef, 0x2248}}, - .y = { .val = {0x83ea257, 0x1a76284a, 0x1da2be23, 0x18dd408d, 0x35ba18e1, 0x1aed56d0, 0x1eed7a50, 0x251a4b48, 0xfa05}}}, -{.x = { .val = {0x350964e3, 0x3436b12e, 0x11c6f76f, 0x27c21df7, 0x85d0a9, 0x46d2365, 0x44074ac, 0x1b85b817, 0xe11a}}, - .y = { .val = {0x682bfc8, 0x19fefe2c, 0x318c6f7, 0x2b71b84e, 0x30af2417, 0x3578965b, 0x2d430e1a, 0x196e1e8, 0x87d6}}}, -{.x = { .val = {0x2d0e6bd, 0xedf839d, 0x30f5e531, 0x1d3458f6, 0xd6ecbf7, 0x851f041, 0x4e2582a, 0x3500490f, 0x3322}}, - .y = { .val = {0x2c28b2a0, 0x13ce8ba5, 0x2873af62, 0x17d8fa8, 0x1af9b728, 0x66f137, 0x24ef5bfb, 0x1e5fa59, 0x56e7}}}, -{.x = { .val = {0xade462, 0x31a5b4cb, 0x2dbcf29f, 0x1337723a, 0x80cd50d, 0x3bcc6c13, 0x2bdae120, 0x8009433, 0x8d26}}, - .y = { .val = {0xf26470c, 0x2382a2e4, 0x2678b3ad, 0x12bed39c, 0x2e36ba1d, 0x3dbcb70f, 0x3f437d31, 0xeed1c56, 0xebed}}}, -{.x = { .val = {0x1516e633, 0x59190f8, 0x32d9c8b9, 0x3524c341, 0x14d03b8e, 0x1a287d6, 0x2bea9ce4, 0x301d9bab, 0x1238}}, - .y = { .val = {0x77b7805, 0x1736dca3, 0x7402280, 0x11894b73, 0x3dc1709, 0x25e78b47, 0x31359d6c, 0x2c0b6ec9, 0x8a9d}}}, -{.x = { .val = {0x388e7a66, 0x26c05549, 0x30ec2161, 0x3735ca0a, 0x2a11b9cd, 0xba9d629, 0x39c15e7b, 0x16c1dc32, 0x271d}}, - .y = { .val = {0x203c9727, 0x2a35c963, 0x8a824e7, 0x281978d4, 0x2c877fe2, 0x1f426526, 0x3f491e45, 0x29160d39, 0x5d3a}}}, -{.x = { .val = {0x134ab83, 0x875d34a, 0x36433977, 0x6cfe6bd, 0x26586874, 0x5dc3625, 0xb7da2bd, 0xb1f4b78, 0x8567}}, - .y = { .val = {0x390313a6, 0x238c253d, 0x1298f44c, 0x1fc5ff31, 0x22c2e5e7, 0x10126fe9, 0x3b2eb637, 0x6e6d6d0, 0x7c48}}}, -{.x = { .val = {0x1f17fc25, 0x262e42f0, 0x32e6d969, 0x227a91b7, 0x8a61f3b, 0x6184857, 0x39ec036c, 0x33dadd03, 0x534c}}, - .y = { .val = {0xfe86e76, 0x1c71fdbb, 0x3dd28ddd, 0x38f49def, 0x1543550a, 0x2b8f74cb, 0x32ddb462, 0x172c2722, 0xd571}}}, -{.x = { .val = {0x28bee8b6, 0x1c5c248f, 0xfbc8d2c, 0x8351fb, 0x38aaed79, 0x38508063, 0x3b7f3081, 0x7d73ba1, 0xa91d}}, - .y = { .val = {0x10644c1, 0xf45aa9, 0x28cb2250, 0x15a7d8, 0x1ad3b2f8, 0x6272377, 0x38ee15a7, 0xc93b8b7, 0x748a}}}, -{.x = { .val = {0x1984cf74, 0x28687095, 0x2f61f10a, 0xd6b916f, 0x14383c07, 0x853778b, 0x8e35c1a, 0x2308f643, 0xc15c}}, - .y = { .val = {0x39ccb000, 0x12923360, 0xb015a2c, 0x2fddcb54, 0x1fd7ba47, 0x31bd1789, 0x22235c8d, 0x15360a14, 0x2ba9}}}, -{.x = { .val = {0x20c82a0a, 0x3f6566bd, 0x3668832f, 0x2489b183, 0x1413b10f, 0x1b27c646, 0x188a46b0, 0x2fe026c6, 0x948}}, - .y = { .val = {0x18c8e589, 0x132dfe23, 0x17cd2bed, 0x137fc232, 0x3418c6d, 0x2dd31747, 0x36646dc6, 0x18a15b72, 0x53a5}}}, -{.x = { .val = {0x3e8b000a, 0x25bac115, 0x2825e513, 0x5b04cc7, 0x11f0b6ef, 0x3393198a, 0x259360d5, 0xb1fcdcb, 0x2695}}, - .y = { .val = {0x5ef705a, 0x30f5007c, 0x13d67318, 0x2f8e63d9, 0x288422de, 0x3224f4b5, 0xa68862b, 0x3a931600, 0xf513}}}, -{.x = { .val = {0x36134f96, 0x4096225, 0x2d6b0e9f, 0x846595c, 0x1ff243f5, 0xafa2c4c, 0x3c5bdbef, 0x1639bf08, 0xc62e}}, - .y = { .val = {0x114cf97e, 0x89dfb53, 0x3731c3e8, 0x3ee14d58, 0x141fc5bc, 0x359d9d4c, 0x1a1678c3, 0x209f516c, 0x4397}}}, -{.x = { .val = {0xb188cbb, 0x1a1be200, 0x7de973, 0x700c802, 0x2622b0b8, 0xcca69c5, 0x5c74168, 0x181483bb, 0x1074}}, - .y = { .val = {0x1f272124, 0x75ed8d8, 0x1ce3da60, 0xb835d23, 0x354a1124, 0x9ae6e73, 0x1598c353, 0x35302688, 0xabe5}}}, -{.x = { .val = {0x338fd8e8, 0x33b36067, 0x69752ac, 0x2c39137f, 0x2873a8f1, 0x19f383c0, 0x1c34f0, 0x339fd186, 0x6260}}, - .y = { .val = {0x32b4ae17, 0x6a13a56, 0x51c198c, 0x34a488e0, 0x2a1ef7ec, 0x24125dd, 0x1b571a7f, 0x2a0adbe9, 0xbc2d}}}, -{.x = { .val = {0x3d477c2d, 0x1d99d1bc, 0x2aad27e0, 0x39971465, 0xf1a1316, 0x21026fa1, 0x11a73dec, 0x3691d22b, 0x85d8}}, - .y = { .val = {0x7d1dd70, 0x1e605bf, 0x3c4d5a62, 0x2c28080c, 0x2fc7bc94, 0x2d4d94c7, 0x6690586, 0x22d4d997, 0x5894}}}, -{.x = { .val = {0x2c0b80d9, 0x2140c4b5, 0x3dc47f04, 0x79f8403, 0x3ee3ee4d, 0x224ba730, 0x4b968c0, 0x1c59b9fb, 0x8e2a}}, - .y = { .val = {0x16b29f50, 0x27187cab, 0x306349a4, 0x25eda235, 0x2a9d4852, 0x374a6dc5, 0xbe592ce, 0x2ea6b8b, 0xeadb}}}, -{.x = { .val = {0x2c4561be, 0x2487e8f4, 0x359d90f9, 0x12acba04, 0xf8950ee, 0xd9bb35e, 0x3f58edc8, 0x31d610af, 0x769b}}, - .y = { .val = {0x30d9685f, 0x16482ffe, 0x37873add, 0x285ddd9e, 0x3f5d4741, 0x33933bdc, 0x383bac8d, 0x5cd8bf9, 0x4bf8}}}, -{.x = { .val = {0x2037fa2d, 0x254f3234, 0x1bfdc432, 0xfb23d5d, 0x3f410304, 0xd21052e, 0x1d8d43d8, 0x1f782bf0, 0xe503}}, - .y = { .val = {0x1d755bda, 0x3977210, 0x481f10e, 0x17d6c0fb, 0x190bddbd, 0x263427ee, 0xd3b5f9f, 0x14d2eaa5, 0x4571}}}, -{.x = { .val = {0x1e3d34ef, 0x318f231e, 0x12a2ddb8, 0x2ac85f1e, 0x161b3ec3, 0x2db3df4b, 0x15494f40, 0x36919ff, 0xa5e0}}, - .y = { .val = {0x2f7adb4c, 0x21571738, 0x10900acb, 0x18373f9e, 0x3f43d25b, 0x1c9bfa66, 0x8555421, 0x397d7958, 0x98f}}}, -{.x = { .val = {0x17b91252, 0x19cdc583, 0x77572ae, 0x12bf4b91, 0x1bfbc46d, 0x27d2ec72, 0x22b40351, 0x57d7bce, 0xa994}}, - .y = { .val = {0xbedc264, 0xe8ddeb1, 0x10f4ddd7, 0x2685ab56, 0x36f6b689, 0xbc43c93, 0x1f84bb9e, 0x39932ba0, 0x82d0}}}, -{.x = { .val = {0x2a540f17, 0x231196d9, 0x30c132bd, 0x1d435c17, 0x3935f84c, 0x3b778263, 0x3d1fc7d8, 0x13a7e793, 0xb56f}}, - .y = { .val = {0x200102d, 0x1a8bf2b8, 0x3cca8544, 0x350a58f2, 0x182d1d21, 0x3046b7c1, 0xa856d3d, 0x394d0a73, 0x32e8}}}, -{.x = { .val = {0x24fce725, 0x1619a82b, 0x2a6c5b72, 0x3a36f471, 0x1771b4e7, 0x2a417a3c, 0x207adf5e, 0x1cac3d28, 0xe063}}, - .y = { .val = {0xeee31dd, 0x9c0d3e5, 0x3104870b, 0x12129de1, 0x1a488cd7, 0x9eecab5, 0x18cfe12a, 0x225d2f38, 0x7a90}}}, -{.x = { .val = {0x3ed2ff3e, 0x3826bb90, 0x2c6ed3cf, 0x17aff6d3, 0x2d3f3c04, 0x36f4c13e, 0x6b8f9c8, 0x4d32881, 0xeac}}, - .y = { .val = {0x3d210988, 0x5c81881, 0x3f21376e, 0x67da5ad, 0x311799ac, 0x3c40efca, 0x19b4245b, 0x36f9e4d, 0x4963}}}, -{.x = { .val = {0x1fbfa4dc, 0x1d9c1b93, 0xc85b174, 0x25229e01, 0x1bb41ff5, 0x84675eb, 0x3ea19839, 0x21641cc7, 0xd678}}, - .y = { .val = {0x3d3b5406, 0x29ef35ae, 0x1c9a07cc, 0x1bc7137, 0x1c13aa62, 0x3bd71b48, 0x63c4940, 0x2a322754, 0x28ea}}}, -{.x = { .val = {0x248ff9b3, 0x9d7ed03, 0x199b01a7, 0x2c698815, 0x371d4bc7, 0x3c843c4a, 0x40974ab, 0x3f32f668, 0x6930}}, - .y = { .val = {0xee96a4e, 0x3f76ad7e, 0xacc51ac, 0x3e6c4f9, 0x1f6d7809, 0x3f36e1d, 0x301eada3, 0x2ba52e51, 0x7f02}}}, -{.x = { .val = {0x10559754, 0x2b5a423, 0x2a3f5854, 0x2c42f778, 0xce02204, 0x2efe770, 0x1d45358d, 0x1e9c5735, 0x213c}}, - .y = { .val = {0x34b458f2, 0x3fcb09d4, 0x36a7eedd, 0x12143d7c, 0x1ba190bb, 0xeb41891, 0x6250701, 0x2b42d6b9, 0x4b6d}}}, -{.x = { .val = {0xec87fac, 0x264e2578, 0x22e7cf08, 0x6ae5d18, 0x23480e0d, 0x3a7fb60c, 0x9a7f66a, 0x15204cad, 0x1c5e}}, - .y = { .val = {0x1fc2d4ef, 0x1575ecf5, 0x2fe324c5, 0x37ab3ac9, 0xc2ad3a3, 0x2567e875, 0x3468f2bb, 0x3d83e0df, 0x4ffc}}}, -{.x = { .val = {0x14531dbc, 0x83f2e87, 0x2d5c970e, 0x2407067f, 0x3bc7ce1f, 0x1ba50842, 0x1668ddef, 0x1b4180b1, 0x4627}}, - .y = { .val = {0x1686b8e2, 0x3e1cc026, 0x3e1bc99a, 0x22eb7eff, 0xded9949, 0x248a1d5c, 0x75b84a2, 0x1fc93513, 0xe0f}}}, -{.x = { .val = {0x122f001d, 0x453bc4d, 0x78d8996, 0x14382b37, 0x31916368, 0x17ac8470, 0x2c24f4e6, 0x1a3b29e9, 0xefea}}, - .y = { .val = {0x33bc4415, 0x4a1067d, 0x3848771c, 0x4e567ec, 0x319a17e4, 0x140c1e8d, 0x3c14da1, 0x11e1a756, 0xaab8}}}, -{.x = { .val = {0x8fbd53c, 0x330e8ec, 0x1c62cddf, 0x20e31c2b, 0x19a87e2, 0x2e4d4a95, 0xb34e8db, 0x9ca9ebd, 0x4e7c}}, - .y = { .val = {0x17dcaae6, 0x2ce5060, 0x3f7dd33e, 0x2e5852f, 0x2f681b53, 0x3f427db7, 0x10b18e16, 0x271d9b27, 0x1774}}}, -{.x = { .val = {0x3c6e1b4d, 0xa0879b9, 0x3ef8790e, 0x47c9686, 0x385d9c9b, 0x289a7d38, 0x2888f268, 0x5ec09a5, 0x8990}}, - .y = { .val = {0x1814ab2b, 0x26baf6b, 0x132b2120, 0x3946f03e, 0x358bfae4, 0x15e60cd8, 0x334f0bb4, 0xb36ad6c, 0x43ae}}}, -{.x = { .val = {0x3e5f712f, 0x3c98d685, 0x1b583a8a, 0xc7d6fe4, 0x227f0e28, 0x11ca398c, 0x5fd4a8f, 0x113ddba4, 0x67f6}}, - .y = { .val = {0x307160e5, 0x1a2b2d79, 0x3d36198d, 0x385223d, 0x6cf785e, 0x2b7aded6, 0x5d04f05, 0x35a3d991, 0xb833}}}, -{.x = { .val = {0x3b89a762, 0x4098fb4, 0x2ee6b8dc, 0x3724c04, 0xb471293, 0x281525a, 0x12555fa8, 0x21db24d9, 0x327f}}, - .y = { .val = {0x39203301, 0x327f6566, 0x2bd7dfe9, 0x14d41c3f, 0x1997b975, 0x25a49578, 0x24026b09, 0x13aacd4, 0xb2d4}}}, -{.x = { .val = {0xfb27b6, 0x909f8a1, 0x24305763, 0x1b8f6caf, 0x286aa5c7, 0x8e2b585, 0x38b1b10f, 0x138f6f9d, 0xfea7}}, - .y = { .val = {0x323cb96f, 0x74f6df, 0x33f7b777, 0x1ad65ae5, 0x36af9312, 0x19d37b32, 0x313297cf, 0x1a36e6c2, 0x6e05}}}, -{.x = { .val = {0x1f9756e4, 0x3f65f258, 0x23730488, 0x15c3b977, 0x28cd0ebb, 0x380f6143, 0x280ff180, 0x10720c10, 0xed94}}, - .y = { .val = {0x3f3abfae, 0x3c3827e4, 0x24de98bf, 0x3c8ddd3f, 0x13911e09, 0x5d84a2c, 0x3fa19afa, 0x27a7bfa2, 0x3dbe}}}, -{.x = { .val = {0x151cf119, 0x16eb40cf, 0x3ab4d301, 0x42f7613, 0x3487515b, 0x3b4fd892, 0x27c3fc9f, 0x1a63b99e, 0x29d9}}, - .y = { .val = {0x35056339, 0x3221d015, 0x3a7c2963, 0x272503a4, 0x31c96fb8, 0x28495013, 0x2b45277, 0xb145f72, 0x7fd0}}}, -{.x = { .val = {0x3f422491, 0x19f1114d, 0x2060cff4, 0x114f92a1, 0x180a31fd, 0x3edef4cd, 0x3936d6f3, 0x15f41404, 0x126b}}, - .y = { .val = {0x1da3ef84, 0x3e8c7c66, 0x3f39347a, 0x122eb0c2, 0x3f3fb0e1, 0x128fae8a, 0x262c2e3c, 0x3704c185, 0xc1a7}}}, -{.x = { .val = {0x17bdde39, 0xb00a910, 0x36043295, 0x11385e6d, 0x1968d315, 0x95c3566, 0x3cf0e10a, 0x1044fd9d, 0x76e6}}, - .y = { .val = {0x1901ac01, 0x12c5d4b4, 0x16d2032b, 0xa8cf4ad, 0x1f0d35e, 0x19b5c1a, 0x295cf577, 0x37e37b93, 0xc90d}}}, -{.x = { .val = {0x3a1187a5, 0x33e666a0, 0x29ae691, 0x1755d88b, 0x21c81000, 0x1f276205, 0x2c73bee8, 0x14c3a794, 0x708a}}, - .y = { .val = {0x73db9c0, 0x2293c66d, 0x1353e8a5, 0x3369cf1b, 0x2d38283e, 0x195b72ed, 0x1a897fa9, 0x1204787e, 0x9b88}}}, -{.x = { .val = {0xde4f5be, 0x386c5b1b, 0x2b2b59e2, 0xdd2db61, 0x2462cf9f, 0x35920e57, 0x33be219b, 0xd3f122, 0x19cf}}, - .y = { .val = {0x2f321af2, 0x2a454cad, 0x30f1c0c0, 0x2474724f, 0x181947ef, 0x12f9a2ac, 0x2b466c3b, 0xac1a856, 0x28e3}}}, -{.x = { .val = {0x117cf3e8, 0xeaf0827, 0x3ea2219e, 0x24ef40d2, 0x17f576ee, 0x670be0e, 0x35f0d7c7, 0x11281e32, 0xaf6c}}, - .y = { .val = {0x1751baea, 0x22b74180, 0xa0d435b, 0xd8aba9f, 0x3246dfec, 0x39cc54f2, 0x14b30af9, 0x25bfa17, 0x784}}}, -{.x = { .val = {0x2bcbb891, 0x2ac54090, 0x326cbee3, 0x1f3190f7, 0x3f8f9a8f, 0x206ea9d0, 0x2abe1e82, 0x315ac0ec, 0xc738}}, - .y = { .val = {0x299a84c3, 0x1f9cd765, 0x80cfe91, 0xc53bbde, 0x3fbbbb82, 0x63cbab2, 0x2d2537f7, 0x2d5e2546, 0x893f}}}, -{.x = { .val = {0x662ab1b, 0x36aac1e1, 0x1b8c9e4d, 0x1c65fa92, 0x27aa9464, 0xca9a64b, 0x37435b, 0x2117b35f, 0x5578}}, - .y = { .val = {0x56f3511, 0x5b463cc, 0x25d64de3, 0x14e9dd1a, 0x2a4053f6, 0x1b429474, 0x1e2c3cea, 0x1e5e2db, 0xe61d}}}, -{.x = { .val = {0x148b6c29, 0x13e1a6e2, 0xe399609, 0x3c48d53f, 0xceccd22, 0x3e8ef074, 0x364cc4ab, 0xe0e2228, 0x47f3}}, - .y = { .val = {0xe537ef9, 0x3b7b8448, 0xf994a81, 0x2ed26562, 0x16c7118, 0x39219d6d, 0x32937190, 0x26a343c0, 0x48ca}}}, -{.x = { .val = {0x5ff4adb, 0x2069b23c, 0xbef768a, 0x3d5c35bf, 0x25d5f614, 0x1ad3271a, 0x1b8cfe46, 0x7cd2b90, 0xc0c0}}, - .y = { .val = {0x2c351065, 0x313bfdce, 0xd15b85f, 0x2f10f45c, 0x35b8cecd, 0xde82d01, 0x17f5c7c9, 0x3d6fb90d, 0xb84}}}, -{.x = { .val = {0x8f6c14b, 0x1cba7d96, 0x29250143, 0x35cb97ce, 0x172877d1, 0x131d8df2, 0x25b81e26, 0x1899522d, 0xd895}}, - .y = { .val = {0x1d7d991f, 0x24d8fb5d, 0x3b067e17, 0x10a358ca, 0x340eb03, 0x3b182063, 0x7eae728, 0x2a8e3caf, 0xfebf}}}, -{.x = { .val = {0x37078424, 0x296d652d, 0x2c40c3fb, 0x3b2bde83, 0x3a26703, 0x290d8880, 0x1044e8a3, 0x1bbbe25c, 0xfd13}}, - .y = { .val = {0x671ddf1, 0x3587bbbf, 0x22adfa8c, 0x3cac7de2, 0x5efa57c, 0x74646d7, 0x252cc67a, 0x2a0d3cf1, 0x218d}}}, -{.x = { .val = {0xdb1cb3c, 0x3c7613b2, 0x3f024a5, 0x1c00e835, 0x119f861b, 0x33294d9d, 0x38d140e9, 0x23a77658, 0xd99e}}, - .y = { .val = {0x2b8637a7, 0x2228a78d, 0x3c8765cd, 0x21bfbe3f, 0xeba6e62, 0x16ecc86f, 0xa3a7a94, 0x66b4730, 0x36dc}}}, -{.x = { .val = {0x3c385172, 0x351bda34, 0x40e636f, 0xcd4781, 0x309191d2, 0x36295396, 0x18317a1b, 0x3c586686, 0x3fd}}, - .y = { .val = {0x3ccb9794, 0x26b19fc3, 0xe7232b7, 0x26e4a7a4, 0x573755b, 0x1c31f4f2, 0x12c3fe4, 0xb01b97, 0x408d}}}, -{.x = { .val = {0xf676e03, 0x24542959, 0x3e84edd4, 0x3ff1cda4, 0x1e8761ce, 0x3d90cd5c, 0x17518eb0, 0x2500caa5, 0xb8da}}, - .y = { .val = {0xefdf6e7, 0x1223939d, 0x1ff3b511, 0x33161365, 0x2808b092, 0x267325d8, 0x1a1e4d7c, 0x37e91201, 0x2804}}}, -{.x = { .val = {0x5af726a, 0x104fd053, 0x25bf6e6d, 0x268f972c, 0x3620f946, 0xb2da62a, 0xc5ce53f, 0x34417b63, 0x6d36}}, - .y = { .val = {0x13f9fc7d, 0x15c12468, 0x108a35c, 0x31664dad, 0x50029dc, 0x2319b257, 0x3669e72d, 0x170d38dd, 0xe4ba}}}, -{.x = { .val = {0x2540db99, 0x1b8a8c32, 0x34b81228, 0x4c27014, 0x30b0e3eb, 0x220fe99b, 0x3ac0cd06, 0x2f784334, 0x3ab6}}, - .y = { .val = {0x1bda78a3, 0x1a1cff8c, 0x369c043e, 0x344dec38, 0x13e99c38, 0x45ea5a8, 0x71d7fc3, 0x1881e6fa, 0xbaca}}}, -{.x = { .val = {0x1f1048da, 0x1ddefc9e, 0x3ddd3ba7, 0xbf53cdc, 0x7bce2ba, 0x281a7674, 0x156f0fdb, 0xd38fc6b, 0x7966}}, - .y = { .val = {0x2106cf01, 0x23e6f892, 0x3d74862e, 0x95db633, 0x3927f253, 0x39d1cd69, 0x20b8956d, 0x38adb3ec, 0x4d8e}}}, -{.x = { .val = {0x23c0df5d, 0x6845de3, 0x156a792f, 0x67bfed4, 0x1d7fab20, 0x2b6ae51d, 0x3b33a7d8, 0x3a851107, 0xe80f}}, - .y = { .val = {0x2ac9ec78, 0x32d0a46d, 0x3322ea9f, 0x557a02b, 0xa94472d, 0x25da328f, 0x200771e8, 0x379fd8e3, 0xeed1}}}, -{.x = { .val = {0xf83cd58, 0x36c39e2c, 0x3d2f9162, 0xb730e1d, 0x3e7a3712, 0x2b13b47b, 0x1265981, 0x287c23a9, 0x440c}}, - .y = { .val = {0x388a3f4b, 0x1ef01a6, 0x1c0a260b, 0x793509a, 0xe2f02a2, 0x25537275, 0x2e122af8, 0x2c34b357, 0xa6c8}}}, -{.x = { .val = {0x12998b10, 0x206f689c, 0x1b229d9e, 0x31c3af30, 0x2907819b, 0x1fe0a74e, 0x26c1cc5f, 0x32ebcae5, 0xf694}}, - .y = { .val = {0xf05e51, 0x19e22c5c, 0x3c2a47f, 0x1b1930c6, 0x6d82aeb, 0x317feb31, 0x2f03d633, 0xfae986f, 0x40a6}}}, -{.x = { .val = {0xdd553fd, 0x25684cd6, 0x8b6414f, 0x2afda570, 0x22595047, 0x1b53d0e6, 0x2684850b, 0x218a8d55, 0x8b6e}}, - .y = { .val = {0x3e9be5ed, 0x200f6b4c, 0x3383d0d, 0x2b0f1686, 0x2b9fa124, 0x2f0b7d3, 0x11cb40d1, 0x22443b4, 0xea5e}}}, -{.x = { .val = {0x4e16070, 0x3701eef3, 0x2fd6915d, 0x286080c7, 0x167543f2, 0x29239475, 0x1704313b, 0x1a5ef7f3, 0xa301}}, - .y = { .val = {0x1e177ea1, 0x30346810, 0xa11a130, 0xd76fdf0, 0x140f9b17, 0x2027e897, 0x3e4f5081, 0x3e473ed9, 0x7370}}}, -{.x = { .val = {0x324ba5ae, 0x5080c5b, 0x34b5d81, 0xe594013, 0xbff74b4, 0x23490678, 0x1f049f3e, 0x39673fde, 0x27e1}}, - .y = { .val = {0x83a45b3, 0x1296ffba, 0x2fa63f78, 0x122869a6, 0x39df05df, 0x2d78f3f1, 0xe209ee1, 0x9a9b201, 0x310b}}}, -{.x = { .val = {0x1caed7ae, 0x25a45d72, 0xfbfb4f9, 0xe6b77a1, 0x2d7e4f5a, 0x223b0e24, 0x24aee165, 0x39e97da1, 0xc712}}, - .y = { .val = {0x6156294, 0x134522a9, 0x30ce6378, 0x3639512, 0x1dd9e538, 0x352e08c4, 0x363b365e, 0x1041d458, 0x4964}}}, -{.x = { .val = {0x4a6db03, 0x2d0f87f9, 0x275d791, 0x32175bd6, 0x675fcb2, 0x303509ae, 0x3235d065, 0x141292c, 0xbfc}}, - .y = { .val = {0x64b8542, 0x22b23469, 0x5d4f055, 0x109c65cd, 0x26c99237, 0x23b1fe52, 0xf3453fb, 0x119e9b0d, 0x1955}}}, -{.x = { .val = {0x3fb04ed4, 0x2deb18f8, 0x1307fffa, 0x330cc2c4, 0x278de208, 0x3e741449, 0x2b936463, 0x216ce275, 0x90ad}}, - .y = { .val = {0xb6ef150, 0x24753523, 0x182894d9, 0x2bbeaf85, 0x3222b839, 0x372f6509, 0x38261aff, 0x1e8d8828, 0xe50}}}, -{.x = { .val = {0x27dc0151, 0x2062c3b6, 0x2707bad2, 0x496f991, 0x25e3d7e, 0x2c745521, 0x14077f44, 0x3503be32, 0x7e2c}}, - .y = { .val = {0x20721ec7, 0x28ef14e4, 0x2ee082c9, 0x26fb902b, 0x1ef95d88, 0x186a2cc8, 0xfab382a, 0x1d420ab7, 0x905b}}}, -{.x = { .val = {0x1345e597, 0x3840eb90, 0x3853cf90, 0x18dafe76, 0x2f52a79c, 0x25d6ef47, 0x2dace21c, 0x3d48656f, 0xa146}}, - .y = { .val = {0x345a770a, 0x19d59dab, 0x1f094b07, 0x19e96c88, 0x331b40ea, 0x25774b6e, 0x3feb09ae, 0x26c2ac14, 0xa5a9}}}, -{.x = { .val = {0xce45444, 0x32ed4ff1, 0x2ccc4e20, 0x379087bf, 0x1a8114db, 0x2fe76ac9, 0x193b9bcf, 0x1d6873c6, 0xd24c}}, - .y = { .val = {0x7dd4a57, 0x2e4c91a6, 0x1f1e524c, 0x1d64fd26, 0x25a78abf, 0x2df46043, 0x1c1d1cfc, 0x74b7a13, 0x58fe}}}, -{.x = { .val = {0x1ec4c0da, 0x2ded1132, 0x23ea3351, 0x23159e1c, 0x1f162ee8, 0x2706b660, 0x35f33923, 0x2e74bd8e, 0x8f68}}, - .y = { .val = {0x101fff82, 0x8f2fde5, 0x1510bfdf, 0x3a8b3fa5, 0x3e215dbb, 0x36430ada, 0x23986de1, 0x27cb6e81, 0x662a}}}, -{.x = { .val = {0xcf27076, 0x1a11f7e1, 0x3627eaee, 0x26162b79, 0x19af59d8, 0x3faf9dff, 0x28158fca, 0x2bbf5e13, 0x4d49}}, - .y = { .val = {0x3aa781e, 0x2e42d988, 0x1f4d8466, 0x3cb469f, 0x1ca6f06e, 0xfc840d6, 0x1d135e72, 0x3f166843, 0xcd32}}}, -{.x = { .val = {0x29b62026, 0x236f2d5c, 0x9d1d4ee, 0xa8f7822, 0x1c5aa78d, 0x1986787d, 0x16f8537d, 0x14e7a175, 0x7564}}, - .y = { .val = {0x1ace0cf3, 0x5cb23eb, 0xb79f334, 0x12ab3655, 0x32292568, 0x77d4929, 0x1b3c6523, 0x21504dd2, 0xc1d6}}}, -{.x = { .val = {0x17b4a278, 0xd936b35, 0x3f4082b5, 0x3d8697c7, 0x19ccc878, 0x1bfcc06b, 0x32779674, 0x245eb677, 0x210a}}, - .y = { .val = {0xc7b2231, 0x3c9c4ff4, 0x3f20bfc7, 0x227986ab, 0x16737d37, 0x26fa07e3, 0x1e57b7a3, 0x6d5142d, 0x670e}}}, -{.x = { .val = {0x13231e11, 0x1a1bf541, 0x3681e3e6, 0x123a1940, 0xc36091f, 0x267fe466, 0x385d65ff, 0x3ec05dab, 0xe4f3}}, - .y = { .val = {0x2feb73bc, 0x8b0e15d, 0x151d1c98, 0x31f9d3b2, 0x2b7286c, 0x69b43a8, 0x34f1c166, 0x18ceb43b, 0x1e63}}}, -{.x = { .val = {0x3bcdaf2f, 0x2ffb888c, 0x3a172953, 0x14c6a096, 0x1b362f88, 0x190442af, 0x373e01ec, 0x32edda19, 0x4b30}}, - .y = { .val = {0x3d26b5b7, 0x200cf518, 0x3485756, 0x37cf2079, 0x3c4a91f, 0x38b15ddf, 0x3629b6f9, 0xd40996e, 0x74c6}}}, -{.x = { .val = {0x2673059f, 0x3ffa70a6, 0xe0fa192, 0x45c5414, 0x64817ec, 0x16c82c5d, 0x1700dcd1, 0xd2a9eb8, 0xcbb4}}, - .y = { .val = {0x227c070c, 0x1f6a5908, 0x2d5f845b, 0x351793c2, 0x35dfad41, 0x35248ce2, 0x2bd17562, 0x802ad36, 0x4a1a}}}, -{.x = { .val = {0x6de12c0, 0x351e1b84, 0x34610e94, 0x2736b161, 0x17244c6d, 0x35ec79d5, 0x2c1cd06, 0x15b6704, 0xf478}}, - .y = { .val = {0xa5361fe, 0x269db39b, 0x1ab92d76, 0x305fbd82, 0x28694c26, 0x2578041, 0x23946e68, 0x39843ccf, 0x7f09}}}, -{.x = { .val = {0x20eae29e, 0x1bedbab8, 0x14e1d071, 0xd3cbc3, 0x1a4266c7, 0x1854de91, 0x3f331eb9, 0x3ea6c63a, 0x8c00}}, - .y = { .val = {0x2702414b, 0x1f4a9319, 0x1e36c54e, 0x3eb6bea0, 0x36c974c2, 0x30d0e8dc, 0x121a1a9d, 0x1c99ffa9, 0xefa4}}}, -{.x = { .val = {0x18ada5f, 0x21326ac3, 0x1122fb3e, 0x1f8a5fca, 0x2be1effd, 0x2d6fe58d, 0x2b46fa8b, 0x3005db68, 0x24cf}}, - .y = { .val = {0x178a586b, 0x23e984e6, 0xf814f26, 0x25672869, 0x2da927ed, 0x21c53577, 0x61a6986, 0x23eec1e7, 0xebff}}}, -{.x = { .val = {0x14679da2, 0x40c6256, 0x3f057edf, 0x37759ff1, 0x292ec616, 0x37b5ca84, 0x1bc82ea2, 0x1f56352e, 0x4a}}, - .y = { .val = {0x379ffe26, 0x21dfd211, 0x23fa28a4, 0x30ed2525, 0x71b3b71, 0x76051fb, 0x2cb75e6b, 0x316dd9c0, 0xb98a}}}, -{.x = { .val = {0x87c4b65, 0x33cd3ab7, 0x207b2a9c, 0x3e202287, 0x26ce4996, 0x1b178b01, 0x1c7fc7, 0x1a7132f4, 0xee7d}}, - .y = { .val = {0x1136a95a, 0xfa3d13b, 0x2e942e52, 0xfa2666e, 0xf2ee2c3, 0x24aafc0c, 0x13821a1, 0x189bb069, 0xecc8}}}, -{.x = { .val = {0x20cb3e41, 0x25ff77f1, 0x8b92c09, 0xf4213cc, 0x298ed314, 0x33b02a7, 0x829f3e1, 0x1b39a775, 0xe7a2}}, - .y = { .val = {0xf2cfd51, 0x3a2a5087, 0x20e83e20, 0x29acb010, 0x2fbb18d0, 0x2c01a86a, 0x3984b471, 0x238c03e9, 0x2a75}}}, -{.x = { .val = {0x3b4ae861, 0x25f96e45, 0x2e32fa9d, 0xf0d7935, 0x2089f520, 0x22fed9dc, 0x3f8d00d3, 0x3eae80da, 0xf5ca}}, - .y = { .val = {0xd82239c, 0x32708e70, 0x12f05f3c, 0xecaa715, 0x839159b, 0x3e641190, 0x26d817bf, 0xee2808a, 0x19e8}}}, -{.x = { .val = {0x3d2a9651, 0x13f5335e, 0x14c98208, 0x27942712, 0x2805428f, 0x3d455b5f, 0x23f1f12d, 0x240933ad, 0xe938}}, - .y = { .val = {0x1e786824, 0x3bf78add, 0x2770bfef, 0x1c4433b1, 0x31aaf18d, 0x21eaebd9, 0x26595f92, 0x1a21c8dc, 0x8648}}}, -{.x = { .val = {0x3cddab8b, 0x3cb506b9, 0x3c68e6fc, 0x3934494, 0x2d0c379f, 0x5a40360, 0x1256bed1, 0x16761e0a, 0x2645}}, - .y = { .val = {0x1de473, 0x27d92d14, 0x1caf1e6c, 0x218c6bce, 0x72d77a, 0x2f18dc0d, 0x3512cef7, 0x2f4649b4, 0x79e5}}}, -{.x = { .val = {0x1e6b80ef, 0x33ca7acf, 0x179424f3, 0x32f2e59f, 0x3cbdc571, 0x1503088e, 0x22ec8d23, 0x2783b8d9, 0xb645}}, - .y = { .val = {0x1a71ba45, 0xc2fc2d8, 0xe35b2ff, 0x2ceb9b52, 0x261db3c4, 0x2b7c5b95, 0x3e06de1d, 0x21db41bc, 0x67c}}}, -{.x = { .val = {0x33eb51f, 0x14fbcdd4, 0x279c2112, 0x22415daf, 0x341593b6, 0xdbdcc07, 0x23c88e4d, 0x3a3c3660, 0xe5d8}}, - .y = { .val = {0x1a62a2d9, 0x2756f659, 0x1f0f5497, 0x27711b6, 0x3eeef0e5, 0x5a95f63, 0x23e04abb, 0x3a6de187, 0x4dc1}}}, -{.x = { .val = {0xf155e64, 0x1e99d920, 0xa301173, 0x19af93ea, 0x3ae0ddab, 0x2c3dcc86, 0x8c3dc56, 0x9fddf6f, 0xa9ca}}, - .y = { .val = {0x161b3297, 0x3cfcccf1, 0x3caf0ae1, 0x17506086, 0x2d00487, 0x1f4891b0, 0x314d4d19, 0xcd59e3e, 0xf4bb}}}, -{.x = { .val = {0x16ee247c, 0x352f18a7, 0x351cee06, 0x11e3a11f, 0xfe7591f, 0x28415847, 0x2d7f25eb, 0x1c6001a1, 0x68fb}}, - .y = { .val = {0x1a01865d, 0x387e08b4, 0xc73c9da, 0x235602c1, 0x1b0c079a, 0xd509d40, 0x19636737, 0x348d18b7, 0xcd12}}}, -{.x = { .val = {0x96943e8, 0x3b683d6d, 0x273c5a5d, 0x1bc7f19f, 0xf06231d, 0x8d2a846, 0x3b840793, 0x20320a02, 0xd68a}}, - .y = { .val = {0x2b133120, 0x25321099, 0x45295a2, 0x39ee3de, 0x30e28b5b, 0x2c7e45de, 0x186d00c4, 0x2a7ffd2d, 0xdb8b}}}, -{.x = { .val = {0x2412b6fd, 0x2f6888b2, 0x3702b828, 0x3b414f1b, 0x12373cac, 0x3e3becdd, 0x240be402, 0x102719de, 0xf16a}}, - .y = { .val = {0x2ca052da, 0x1a36b9df, 0x9ebca42, 0x15019649, 0x230e4e16, 0x1a9d69d3, 0x32799d7a, 0xc45c514, 0x2a41}}}, -{.x = { .val = {0x326dd4e4, 0x30682db8, 0x3ed98325, 0x27d3cbda, 0x36f84db8, 0xdfda665, 0x26f42fbe, 0x2d41aadd, 0x4154}}, - .y = { .val = {0x75ded1c, 0x32164a54, 0x1e22dd46, 0x13aa7674, 0x25ff641, 0x1b913584, 0x1988894c, 0x1d410f1, 0x23ad}}}, -{.x = { .val = {0x3f7f0246, 0x31469e98, 0x727ddf4, 0x3a1b927f, 0x1956ea93, 0x2a35342d, 0x95c1080, 0x1949da73, 0xb73c}}, - .y = { .val = {0x2a2a407b, 0x25f94593, 0x2e554e55, 0x35cb931, 0x36c1ea1a, 0xd624f16, 0xca9d4b5, 0x36c41c5d, 0x9a67}}}, -{.x = { .val = {0x28d3d5d, 0x256603f, 0x3449cea4, 0x4abae5c, 0x3a30b096, 0x3009c241, 0x804252d, 0x3b5f7d97, 0x324a}}, - .y = { .val = {0x16ab7c84, 0x19c892be, 0x23328439, 0x84ec31f, 0x2c1f4f19, 0x3030d6b, 0x21f2ff13, 0xd95dd2d, 0x648a}}}, -{.x = { .val = {0x32919749, 0x23ce0e06, 0x1e0db1fa, 0xacf92a3, 0xd7203f7, 0xc9a0620, 0x3490228d, 0xcc7a89b, 0x32c9}}, - .y = { .val = {0x3290b5e3, 0xc7a5ec3, 0x239ab096, 0x2292af6b, 0x33dbb826, 0x28bc0adb, 0x9cb5695, 0x9cacd08, 0xd7cd}}}, -{.x = { .val = {0x3b9795e4, 0x38708949, 0x1846b8e1, 0x30586db8, 0x2c6b1c69, 0xbda9c3f, 0x37854a0, 0xbcecee6, 0xeb29}}, - .y = { .val = {0x2e53a0fe, 0x2dfa74be, 0x1111c6f5, 0x4c75d42, 0x5835b57, 0x198d2bc5, 0x2be80169, 0x3096a5bb, 0x8c43}}}, -{.x = { .val = {0x9303fdd, 0x3a8e755e, 0x1d1ed35a, 0x1c515fc6, 0x9fbe14d, 0x350c401, 0x35ef2e62, 0xe8077ce, 0xa65a}}, - .y = { .val = {0x2e68703, 0x2b512a34, 0x3aed3cad, 0x21874093, 0x2d2c7686, 0x10f63643, 0x35c6fb8f, 0x2825033f, 0x798e}}}, -{.x = { .val = {0x3d054c96, 0x3a2f4dcf, 0xd1ca888, 0x31050eea, 0x3ee5dcee, 0x77f6f97, 0x1e61f6d5, 0x30524673, 0x4df9}}, - .y = { .val = {0xad10d5d, 0xbaeb01b, 0x28849019, 0x3541b370, 0x1d85d4b5, 0x25d308e8, 0x18728050, 0x3b14424b, 0x35}}}, -{.x = { .val = {0x1da49e04, 0x31ac3f0, 0x17a8d70c, 0x37915539, 0x387088e9, 0xc5f5392, 0x998cd25, 0x32b634b3, 0xed32}}, - .y = { .val = {0x3c1db9e0, 0x18c48345, 0x9fab7db, 0x36a7eb2d, 0x19d20b52, 0x728dd61, 0x30204a54, 0x3bd7c740, 0x129f}}}, -{.x = { .val = {0x2883f855, 0x2dd06353, 0x3c34016c, 0x30db72d8, 0x30366e28, 0x27904471, 0x360f1804, 0x2adc9358, 0xe821}}, - .y = { .val = {0x19852ddf, 0x353831a9, 0xec23efe, 0xec67185, 0x16cf598b, 0x3504550, 0x13ce367d, 0x32fe18fd, 0xadef}}}, -{.x = { .val = {0x3441742e, 0x2ffd67ba, 0x33806e9f, 0x52951eb, 0x1693a72f, 0x1514bef2, 0x2d212f45, 0x22653946, 0x3f0d}}, - .y = { .val = {0xfecadbe, 0x3194d8ef, 0x2d13d958, 0x8178b0e, 0x3a6e0b1e, 0x172c3a11, 0x3dc445e, 0x1b08fca3, 0xfbd7}}}, -{.x = { .val = {0x2c1f98cd, 0x2ff26722, 0x17f0308c, 0xd224153, 0x6602152, 0x362a7073, 0x34870fae, 0x66a1291, 0x9c39}}, - .y = { .val = {0x14fc599d, 0x39f9780f, 0x64c8e6b, 0x14c9bddb, 0x20e64190, 0x3c112fc9, 0x1dd57584, 0x13c3d293, 0xddb8}}}, -{.x = { .val = {0x294a09ec, 0xd7beded, 0x28535f04, 0x34c9a94f, 0x92aa40c, 0xbf1a757, 0x1d80f0a4, 0x14c9895, 0x2e3c}}, - .y = { .val = {0x8c7327e, 0x14d21a06, 0x7b66512, 0x12294f1c, 0x2fc1abe0, 0x2b8902e0, 0x6fb5bdd, 0x3e24595b, 0x1f}}}, -{.x = { .val = {0x2b9c7ce6, 0x17c668a, 0x19089342, 0x1c40c5a8, 0x24dda433, 0x17edf8f8, 0x1587ae1, 0x289333e9, 0xe8e2}}, - .y = { .val = {0x836267c, 0xb007ada, 0x1c27a73b, 0x27980ed, 0x2e20596e, 0x3cacacef, 0x35d1b4ca, 0x20f3831b, 0x46c9}}}, -{.x = { .val = {0xac7b3c2, 0x2c34e59a, 0x3d5b5f5, 0x2b2be48e, 0x32a212, 0x28e2c5c, 0x173c2b2f, 0x26ab1761, 0xa754}}, - .y = { .val = {0x1287eaef, 0x283245c6, 0x37116dff, 0x1ad44554, 0x147d2b5d, 0x2875c306, 0x2415335, 0x346e4347, 0xbd17}}}, -{.x = { .val = {0x20a959e5, 0x2884e084, 0x391d4cc5, 0x38524ea2, 0xe06bb91, 0x17ca076, 0x12fdf8de, 0x5c2c774, 0x6057}}, - .y = { .val = {0x2385a2a8, 0x2266fa4c, 0x2e24c65e, 0x1454af0f, 0x1df26246, 0x268b6bdc, 0x24807add, 0x3c2c9a9a, 0x9a1a}}}, -{.x = { .val = {0x2fd545c, 0x22672976, 0xa28e661, 0x4cfe375, 0x1c85df7c, 0x1044291b, 0x2e064039, 0x3f59df14, 0x6773}}, - .y = { .val = {0x147eb1ae, 0x231fc0d2, 0x1c6cf98e, 0x35e03d68, 0x2b246bea, 0x3c972774, 0x3652f0f0, 0x2db63365, 0x444e}}}, -{.x = { .val = {0xb86f021, 0x1cf185ac, 0x4680503, 0x1d390e04, 0xc87c203, 0x31e6ab38, 0xe565237, 0x1b65345f, 0xe0f8}}, - .y = { .val = {0x35bf325a, 0x2dade732, 0x15fc45b3, 0x202f3004, 0x89a2c9a, 0x7a0cbc7, 0x2bcf47a9, 0x71cdcc2, 0xc57}}}, -{.x = { .val = {0x2da6e03, 0x2b41dcb0, 0xcad6038, 0x9df7e42, 0x296f4f4c, 0x247864f5, 0x5041ce9, 0x56ae7c9, 0x42ca}}, - .y = { .val = {0xc347793, 0xda227ea, 0x106bea78, 0x1ba169a0, 0x3800eed6, 0x339347f2, 0x57c9647, 0x3bc9b207, 0x68d2}}}, -{.x = { .val = {0x2cb94266, 0x69a5cfb, 0x3d4df12b, 0x33bc3ee9, 0xda31880, 0x10e69146, 0x8411421, 0x37e388e8, 0xa576}}, - .y = { .val = {0x21b28ec8, 0x3a2f846b, 0x114d9f3e, 0xb8429fd, 0xcd82c43, 0x2e5ebf96, 0x240b2c92, 0x2fc839d9, 0x40a6}}}, -{.x = { .val = {0x1a704896, 0x3b15c96f, 0x1acfb8dc, 0xee818f2, 0x271bae6f, 0x148219ef, 0x35a3b546, 0x3318bbce, 0x9e5d}}, - .y = { .val = {0xa82c835, 0x23c9da77, 0x30f5124, 0x18174618, 0x7612279, 0x34e88553, 0x25f3ea5f, 0x344b76e4, 0x6fed}}}, -{.x = { .val = {0x4bf7ea0, 0x14fb561d, 0xef58339, 0xd896817, 0x303b20e3, 0x1ba7e5db, 0x345adf8d, 0x20dd6e1, 0xa7de}}, - .y = { .val = {0x1bbcabaa, 0x130154e, 0x2bc5aa2e, 0x1691f03f, 0x88e9a64, 0x1282ccd2, 0x1a5e5210, 0x25ac15eb, 0xa63d}}}, -{.x = { .val = {0xad916fb, 0x27e3e841, 0x149e4a3a, 0x20197f7a, 0xff4cbe6, 0x30d6b007, 0x80c9c13, 0x19639a24, 0xc266}}, - .y = { .val = {0x20887814, 0x1abbd4ae, 0x36113885, 0x23fb37fa, 0x627ab6b, 0x2605c2c9, 0x3daab0f7, 0x164e1539, 0xe7e8}}}, -{.x = { .val = {0x3e58ad71, 0x3dd8e226, 0x39a3a208, 0xc347d73, 0x1e8c38bb, 0x17fa58a7, 0x2c3e30a0, 0x29e30a37, 0x7778}}, - .y = { .val = {0x3d9f43ac, 0x2d44ff07, 0x324ac563, 0x2ce1047f, 0x3f580087, 0x26384bcb, 0x1b22ff70, 0x1b66ad69, 0x3462}}}, -{.x = { .val = {0x1073e879, 0x1fa87094, 0x104eea7a, 0x3c5a96b8, 0xfe3932c, 0x3d20b5fc, 0x6d1632, 0x1e5ad728, 0xe7b9}}, - .y = { .val = {0x3aa89d98, 0x239c4226, 0x1a98af33, 0x2d6fc97b, 0x3cc1ca9c, 0x840a9cd, 0x29e2fdf4, 0x26230645, 0x12b8}}}, -{.x = { .val = {0x32628f0f, 0x1975c8af, 0x2aee9198, 0x108f6abc, 0x209a7365, 0x2456892f, 0x36203c2c, 0x3c061421, 0x71b}}, - .y = { .val = {0x5a1c334, 0x15f172f5, 0x31c80bbb, 0x23e71a88, 0x84ce209, 0x1802f070, 0x1cf4ae33, 0x28575413, 0x527a}}}, -{.x = { .val = {0x239620e1, 0x3d8ddb7e, 0x1213786, 0x6447214, 0x3c39e5b, 0xcb96530, 0x3e56833a, 0xd0eb2e6, 0x218}}, - .y = { .val = {0x106998b5, 0x380667d9, 0x343c9ec5, 0xca6690b, 0x2fbfc044, 0x3c93f580, 0x250beaf3, 0x75225c2, 0xbea8}}}, -{.x = { .val = {0x6d903ac, 0x27b6a70, 0x1ad7e5cb, 0x3e589d39, 0x3afd2ed5, 0xa7f4c39, 0x3a844637, 0x2557b98d, 0x928}}, - .y = { .val = {0x1bcd091f, 0x14603a4d, 0xa8d83fc, 0xf49bbea, 0x3a95eeac, 0x1e284c24, 0x342a827b, 0x8400f4f, 0xc256}}}, -{.x = { .val = {0xf59dd9e, 0xc411e98, 0x358f0e72, 0x397a7156, 0x318ad67c, 0x58ec132, 0x1d350dad, 0x2f7b8ddc, 0x4f89}}, - .y = { .val = {0x156b049, 0x5ab8c8, 0x238df5c1, 0x12209419, 0x3bb2471e, 0x2ebd3010, 0x21f695c4, 0x14b5489e, 0xca79}}}, -{.x = { .val = {0x3ff01197, 0xa70c533, 0x1a245bf5, 0x2d9a3c1e, 0x3c4c994, 0x25aeb28b, 0x3c5a80c3, 0x20c132b8, 0xcb9e}}, - .y = { .val = {0x3b989c1d, 0xcd381d8, 0x15e0a24c, 0x2cb46300, 0x8891741, 0x96337fc, 0xe6a127, 0x34a007ae, 0x62c7}}}, -{.x = { .val = {0x108d2cc2, 0x17e7ff09, 0x48c58c1, 0x2fbb51c, 0x330dc58e, 0x33ca9041, 0x69bd3c8, 0x126c3e27, 0xe2f3}}, - .y = { .val = {0x20d4c04f, 0x38d1ef63, 0x9cbdb37, 0xd12fa38, 0x215ba42, 0x182bb1d8, 0x27237818, 0xbca03e0, 0x1feb}}}, -{.x = { .val = {0x23d82751, 0x1eab9d45, 0x3ad35452, 0x116d2a41, 0x23b28556, 0x193ce83, 0x1b109399, 0x3fbcfb1b, 0x85d0}}, - .y = { .val = {0xeb1f962, 0xb08de89, 0x7733158, 0x21d47a5a, 0x2cf5663e, 0x3525b960, 0x38c0be29, 0x192104e8, 0x1f03}}}, -{.x = { .val = {0x1d5fcade, 0x18d5b450, 0x1711ff75, 0x2d20b802, 0x11df0468, 0x1e9b3f34, 0xc4f4f60, 0x3d2c669, 0x6b79}}, - .y = { .val = {0x338d3ff, 0x1bffe1bf, 0x3e26b0ab, 0xfe96d1e, 0x2e09cba8, 0x19987e72, 0x1eb3ef29, 0x2606cbfe, 0xd03a}}}, -{.x = { .val = {0x23a3e0cb, 0x2c3336af, 0x1978be0b, 0x91e77a1, 0x4f8fe3d, 0xb0d9eb3, 0x2bed3c16, 0x26cb0b5f, 0x4114}}, - .y = { .val = {0x339033a8, 0x3a4ba60, 0x3490f247, 0x3b1e017b, 0x2cf28b3, 0x5726e64, 0x30542b4, 0x16e4b6df, 0xc90d}}}, -{.x = { .val = {0x23f3d3fc, 0x237774a3, 0x1c29cebf, 0x12a6e081, 0x32a7ba66, 0x30f7f8a1, 0x849dfae, 0x353e939f, 0xd1fa}}, - .y = { .val = {0x10f3704d, 0x3488d0f1, 0x3f37326e, 0x34dc4c7b, 0xb7818ba, 0xfdc3a16, 0xfdfe547, 0x25c528d2, 0x8fe1}}}, -{.x = { .val = {0x526087e, 0x3d501209, 0x2da20308, 0x3edb6220, 0x18b85dfd, 0x26d8105e, 0x2ce97c1c, 0x373a5fb, 0xff2b}}, - .y = { .val = {0x30c29907, 0x32547807, 0x10e2ceb2, 0x2dfb5bee, 0x107936c7, 0x13137153, 0xba188af, 0x4ffbd49, 0x493d}}}, -{.x = { .val = {0x3149f8ef, 0x2f4ea6bc, 0x238b4583, 0x3ad713b9, 0x31bb223d, 0xa7aefb2, 0x26c9f78e, 0x36ef17cd, 0x2982}}, - .y = { .val = {0x16c7a248, 0x1b9c9ac0, 0x2e3ed845, 0x176e6504, 0x35bc9d09, 0x294ce71e, 0x2220ab9f, 0x16fa6bd9, 0xa61b}}}, -{.x = { .val = {0x2380441b, 0x14a27d84, 0xe176588, 0x47d160, 0x17db5860, 0x1bad6412, 0xc0f6b43, 0x39410abc, 0x1a28}}, - .y = { .val = {0x452af25, 0x17d81aa, 0x2ee67aeb, 0x2cf9d6d1, 0x36f0ed04, 0x20ca6a25, 0x19dab7c7, 0x269e65b1, 0x5577}}}, -{.x = { .val = {0x221e30a7, 0x3bbc38e5, 0x5d83242, 0x3757ade6, 0x3f20142e, 0x143302f4, 0x330601d2, 0x20fa54d7, 0xc8b}}, - .y = { .val = {0x1ff688de, 0x3afdefae, 0x187134db, 0x32b48dee, 0x3dc854aa, 0x38fc5fb, 0x3dac7b85, 0x1c1dc197, 0xdcc}}}, -{.x = { .val = {0x3856e241, 0x203978b3, 0xd6dd287, 0x3c7b8523, 0x1b212b57, 0xacb98c0, 0x80ea9ed, 0x2ef92c7a, 0x827f}}, - .y = { .val = {0x2ec293ec, 0x1816da2e, 0x2903166d, 0x3de98c61, 0x1d12687f, 0x3bcb19f4, 0x27b0b71b, 0x27248f1c, 0xc60f}}}, -{.x = { .val = {0xcb1815d, 0x3db912dc, 0xb87461e, 0x11c2a486, 0x2e6b3660, 0x35f2355d, 0x16b973e2, 0x4a9f739, 0xb77f}}, - .y = { .val = {0xe57dbc5, 0x2e8f4af2, 0x244816d6, 0x10bc3e46, 0xc2e654c, 0x33becdcf, 0x2acc43f0, 0x216c53e1, 0x4b6f}}}, -{.x = { .val = {0x45565ec, 0x3f976b4b, 0x177c5970, 0x163637d2, 0x39f956d8, 0xc22cb2d, 0xbf1247b, 0xee50c06, 0x4897}}, - .y = { .val = {0x3aed07e9, 0x2e1e41d7, 0x477b83, 0x6cd6596, 0x45af151, 0x1eece805, 0xdc1b643, 0x1d5a13cf, 0x761f}}}, -{.x = { .val = {0x3bfd71fa, 0x13535d0a, 0x34527d4a, 0x1dd68996, 0x304c170b, 0x25c9ca29, 0x1559c6d6, 0x963a3ad, 0xe931}}, - .y = { .val = {0x174d3307, 0x366f434c, 0x35e35f33, 0x251b386e, 0x154b40b3, 0x3ad05a72, 0x3dee0e85, 0xccd930f, 0xfb1e}}}, -{.x = { .val = {0x2120e2b3, 0x3ced63e8, 0x347f9aa7, 0x163f739f, 0x26e5217a, 0x392b8d33, 0x1bdbae7b, 0x127c87d4, 0xeaa6}}, - .y = { .val = {0x3a5ad93d, 0x11e94c16, 0x13f7e59d, 0x29ae597c, 0x39aa5a01, 0x2a03e261, 0x3b03ac69, 0x1e7b56ee, 0xbe32}}}, -{.x = { .val = {0x1fc9b0a8, 0xf6f0730, 0x5f3db45, 0xcded71c, 0x2279ea9e, 0x8fa9400, 0x197eec26, 0x276cefae, 0x3adb}}, - .y = { .val = {0x305bbdda, 0x6b9e5d7, 0x30266cc6, 0x36723e61, 0x95ff6aa, 0x1d3781f0, 0x34e713c7, 0xb5b6bb9, 0x374e}}}, -{.x = { .val = {0x10ae86f9, 0x153a7832, 0x23e7caf0, 0x3f7fd5a5, 0x5fc69fe, 0x255795b, 0x29cbb7e1, 0x14eb10a3, 0x129e}}, - .y = { .val = {0x1e89c85d, 0x8bbf734, 0x2b3e01b8, 0x288cbf45, 0x12183fb2, 0x288456dc, 0x29a29b2d, 0x32e562bb, 0x415e}}}, -{.x = { .val = {0x2855b8da, 0x8890f57, 0x28947119, 0x15899f44, 0x210956c7, 0x17b2dabb, 0x294485b8, 0x1125323d, 0x6014}}, - .y = { .val = {0x334e4bbd, 0x35401643, 0x23f2a4ba, 0xe55709f, 0x32e65b54, 0x2f87f644, 0x1e6469e8, 0x359a7da0, 0x8bb5}}}, -{.x = { .val = {0x1a34d24f, 0x388d8cb7, 0x1a137401, 0x2db63c32, 0x342ee541, 0x77db7b3, 0x3169d939, 0xb50f173, 0xe4a4}}, - .y = { .val = {0x1eba9414, 0x29fdc4c7, 0xd8e4f13, 0x21bbb7ea, 0xad34ce8, 0x326733ee, 0x1c73526f, 0x24b9c5b4, 0x4d9f}}}, -{.x = { .val = {0x3e8f62bb, 0xfcba8c, 0x3ae4d2a3, 0x14f158bd, 0x4ef4d05, 0x2b3e15b, 0x3b18d3ef, 0x147ee133, 0xfd64}}, - .y = { .val = {0x132c0911, 0x2b64218, 0x200e83fd, 0xaad24b4, 0x344ccfa, 0x39e9706f, 0x31578b6f, 0x33acac61, 0xe745}}}, -{.x = { .val = {0x15fe696b, 0x28747ee7, 0xf3c7a1f, 0x10b8b577, 0x1edbbb00, 0x3a0681be, 0x86bc716, 0x81f2c90, 0x1eee}}, - .y = { .val = {0x3429337b, 0x2d159c39, 0x2fd694eb, 0x818b82, 0x21c95f7a, 0x65b4491, 0x2269cd2b, 0x2f466bbd, 0x652c}}}, -{.x = { .val = {0x2f94c0d5, 0x23503c67, 0x5725790, 0x303f005f, 0x2e2111e1, 0x16acb0d1, 0x1eb14d46, 0x28cfaa2a, 0xcc0e}}, - .y = { .val = {0x2f452fe6, 0x3aaf965e, 0x113f543d, 0x1d3c998, 0x3be663f6, 0x37480ed7, 0x8a2fb23, 0x1e8edc47, 0xf990}}}, -{.x = { .val = {0x300bf19, 0x1c5cee75, 0x8fea494, 0x2d4d5daa, 0x352b6b92, 0x183eb6ac, 0xbdd9541, 0x3fbcd83, 0x1ec8}}, - .y = { .val = {0x107cefd, 0x1c737073, 0x295a07b6, 0x11b9dfd8, 0x2bbf5e01, 0x2925629e, 0x1340d2f3, 0x3a4dd5ad, 0xaeef}}}, -{.x = { .val = {0x14ff9e4, 0x36ba0175, 0x3d890560, 0x2118bdba, 0x3c90bb8e, 0x3aa80d13, 0x4bc6cbe, 0x3a8d467c, 0x5be7}}, - .y = { .val = {0x7e0bdbb, 0xc2c1e1, 0x119a3094, 0x26718c08, 0x1ab7fe0e, 0x3e243d95, 0xe605477, 0xbb0fd8e, 0x32f3}}}, -{.x = { .val = {0xddb7bb8, 0xfed517d, 0x3853991e, 0xa1927, 0x1f7f5cd5, 0xff21a63, 0x24e65081, 0x26445bab, 0x58f0}}, - .y = { .val = {0x2e5b2d6e, 0x37b1cd60, 0x1174302b, 0x1fb9018b, 0x23806650, 0xbfdd851, 0x2111a0d6, 0xaabff, 0x7e07}}}, -{.x = { .val = {0xc9a8e2c, 0x4f0581b, 0xc1a1c14, 0xf634693, 0x20cb0f82, 0x33013f61, 0x390b633b, 0x392e6ca5, 0xb0f9}}, - .y = { .val = {0x1f3d0db4, 0x30819b13, 0x171cee76, 0x143300b0, 0x3de3f033, 0x2ec2e41b, 0x2de6d41c, 0xafc610e, 0x49e8}}}, -{.x = { .val = {0x366642be, 0x376d64a0, 0x158ba889, 0xd241c5f, 0xdfa8bce, 0x2bd1a0, 0x30c2f91b, 0x1de30119, 0x146a}}, - .y = { .val = {0x3d83efd0, 0x2ca5d20, 0x37e5ed1d, 0x2aa5c74b, 0x14b2870a, 0x1a609fe7, 0x28add6, 0x383b0cd5, 0xb318}}}, -{.x = { .val = {0x39de5cac, 0x6c8d955, 0x2cb26191, 0x3f260f1f, 0xd14cfee, 0x1c2d702f, 0x17e24e56, 0x3c33a296, 0x574e}}, - .y = { .val = {0x75a4805, 0x3966ba9b, 0x310008ca, 0x9829efb, 0x1b78451a, 0x1ab6815a, 0x319c73bd, 0x264c0a07, 0x9b9}}}, -{.x = { .val = {0x260966d3, 0x230b5d0, 0x2ff86458, 0x29dc306b, 0xc835d10, 0x24e5ee6, 0x3f9f85d9, 0x1f9e6762, 0xd3d9}}, - .y = { .val = {0x33c2e52, 0x377ae142, 0x28dc4eeb, 0x3921c46f, 0x3ad3b5, 0x2a249d75, 0x2c95e6aa, 0x2d18ddae, 0x8ddb}}}, -{.x = { .val = {0x168c6d4b, 0x103ee4e, 0x3494c120, 0x2f9e33e3, 0x3bee0ab2, 0x1d39e0b2, 0x318987b9, 0x194ca22c, 0xb1aa}}, - .y = { .val = {0x2891ac51, 0xf6798ab, 0x1623cc38, 0x2876427, 0x23a83b10, 0x12aa38b5, 0x10d71268, 0x1c71820, 0x7ed6}}}, -{.x = { .val = {0x3180eef9, 0x35daa1e4, 0x228b9776, 0x48826, 0x207b128d, 0x2b3aec6a, 0x2e5f07e3, 0x303d8748, 0xfa50}}, - .y = { .val = {0x3f4f2811, 0x233635f4, 0x17a213b3, 0x1a0ca4e9, 0x1a68a5e, 0x334a1c8a, 0x3eba9b72, 0x31a488e5, 0x6b84}}}, -{.x = { .val = {0x187f5048, 0x2716f88c, 0x8386d45, 0x8ca3491, 0x290836e7, 0x503f80b, 0x74e0780, 0x13bb9864, 0x6396}}, - .y = { .val = {0x9309df8, 0x20e8a136, 0x1de6c843, 0x1602e4d3, 0xbfbc93d, 0x3fe6c70d, 0x1cf41a39, 0x3ece9ae2, 0x3b6c}}}, -{.x = { .val = {0x3adb2a65, 0x2052e87a, 0x3cbda31f, 0x35fc4ab4, 0x3c9f75af, 0x11a777c3, 0x1b7e22d1, 0x3896d345, 0x5a3c}}, - .y = { .val = {0x1d327f1d, 0x22c5c33c, 0x25fe8ed, 0x38a2f0f6, 0x3f99af3e, 0x29b6fefc, 0x5f63873, 0x496e4b8, 0x8b34}}}, -{.x = { .val = {0xa9f44d0, 0x1a9ccdd5, 0x1a8fa001, 0x36f2db9a, 0x1e41ff85, 0x2f8d3c3, 0x13eda691, 0x16be63e, 0x5ce6}}, - .y = { .val = {0x9d30105, 0x3417cd2, 0x32eccc6c, 0xf2c6fe8, 0x76c58ab, 0x15af40c7, 0x26bfe7ba, 0x33e6fb08, 0x4cdd}}}, -{.x = { .val = {0x1f067ec2, 0x394f4cad, 0x1bba5220, 0xa22ad75, 0x8e8421a, 0x16fdadf6, 0x21a11b1a, 0x1874329c, 0xda1d}}, - .y = { .val = {0x1ad836f1, 0x157ee83c, 0x279b48a6, 0x29ce2674, 0x91e2966, 0x1d98587, 0x1306c79c, 0x3d569f26, 0x8157}}}, -{.x = { .val = {0x2cd3c369, 0xf084348, 0x1f8e934b, 0x181520f8, 0x1283a23, 0x1757d877, 0xc444df8, 0x3802d3bd, 0x9c7b}}, - .y = { .val = {0x22329515, 0x27b8ffae, 0x2769cbd2, 0xc454e85, 0x2401483e, 0x9b51573, 0x20d2052a, 0x30379d2c, 0x9220}}}, -{.x = { .val = {0x3bb8c9e3, 0x1af364b5, 0x141178e7, 0x3741a9c1, 0xcc49174, 0x1992c8e3, 0x1263bb55, 0x20fd0a09, 0xfcd}}, - .y = { .val = {0x1f4aa9ad, 0x21b557ef, 0x1627bf4e, 0x2fabb37c, 0x3db683ad, 0x208cb797, 0x1fbced1d, 0x3073fab1, 0x6c0b}}}, -{.x = { .val = {0x326b64f1, 0x33ce6512, 0x1476d995, 0x3b73ca3d, 0x11e59db7, 0x36931894, 0xf010d4c, 0x101fc6d6, 0x7175}}, - .y = { .val = {0x324234d5, 0x9b9fbea, 0x471d2a4, 0x7fa2ddd, 0xcc86eb0, 0x34d0044d, 0x3d550f36, 0x1550d138, 0x43b4}}}, -{.x = { .val = {0xd064e13, 0x29cec184, 0x6f1e062, 0xc477811, 0x3d416615, 0x17fe63a3, 0x30690721, 0x20bfc325, 0xa8e2}}, - .y = { .val = {0x11f4cc0c, 0x3bdf1cc4, 0xdd6bd6c, 0x19e68f94, 0x2515888b, 0x2dfcf16c, 0x1c09abf, 0xd56e36e, 0x7f97}}}, -{.x = { .val = {0x3f7653a1, 0x57ae7a9, 0x13d67c1c, 0x2fa7aa9d, 0x266e63ef, 0x1dbe017a, 0x3aecbcb8, 0x3cb9f89f, 0xcac6}}, - .y = { .val = {0x3ec5e556, 0x23042b43, 0x8103a06, 0x3a0eb95a, 0x2a345081, 0x2d976690, 0x26f194cd, 0x5b978aa, 0xf7d4}}}, -{.x = { .val = {0x624003d, 0x327d2ac2, 0x238cb11c, 0x2dd9ca50, 0xe43254a, 0x3164cb96, 0x3d206efb, 0x3791bb8d, 0xe6df}}, - .y = { .val = {0x2216b93b, 0x15219438, 0x27fd7dd7, 0x7397a94, 0xf92203b, 0x3d23dee2, 0x139498f2, 0x2cedefa4, 0x8727}}}, -{.x = { .val = {0x8dce109, 0x38440d5, 0xf211d3b, 0x1438c527, 0x96082e2, 0x1033f1eb, 0x2823d66a, 0x2273669, 0x3c4e}}, - .y = { .val = {0x3a19aeea, 0xafd9648, 0x17fe697e, 0x1e7850b6, 0x364d3795, 0x15ef2855, 0x191b4807, 0x2f99a7f8, 0x43fb}}}, -{.x = { .val = {0x319497c, 0xbce0b7a, 0x12508c02, 0x166c7e94, 0x13cab15d, 0x2795b9a4, 0x285872d3, 0x14ee7268, 0x174a}}, - .y = { .val = {0x79afa73, 0xf684eb0, 0xb985438, 0x1ace8763, 0x7f9e664, 0x10557cb1, 0x9c1657b, 0x370deaff, 0xccc9}}}, -{.x = { .val = {0x40dd273, 0x3d768dbe, 0x24501115, 0xf4a0383, 0x392ea3d5, 0x1c1c7bc6, 0x6bb630c, 0x38b9e5a5, 0x20e6}}, - .y = { .val = {0x3b46b593, 0x1f3f456, 0x1a8693cc, 0x7b25e4f, 0x7465581, 0x2e86b65e, 0x159e44a0, 0x1ebf93c5, 0xd3ad}}}, -{.x = { .val = {0x1a077674, 0x1ed53cc0, 0xc24ca3e, 0x2b9a04db, 0x31db7035, 0xa0281f9, 0x351dba80, 0x2a0935e8, 0x8e0c}}, - .y = { .val = {0x12b7ed98, 0x2e132fb0, 0x2f910290, 0x3d810674, 0x22cf57cf, 0x1a749369, 0x12d41dc5, 0x1581d646, 0x4ec}}}, -{.x = { .val = {0x28192441, 0x25abf17a, 0x321b4afe, 0x36d60868, 0x3d66c1af, 0x298d54f8, 0x182d1c5f, 0x14369472, 0xf7bb}}, - .y = { .val = {0x145165ae, 0x31903a87, 0x3c4c74bb, 0x33f707ee, 0x26485db1, 0x2f18ef77, 0xa526311, 0xef8c0cd, 0x93cc}}}, -{.x = { .val = {0x1475b7ba, 0x213f7fc2, 0x918b3d8, 0xe79cc39, 0x18cdbe0, 0x395fb7d4, 0x3785c3d3, 0x25a60650, 0x9593}}, - .y = { .val = {0x3524f2fd, 0x26e2afe1, 0x709385e, 0x194fd932, 0x1cd6849c, 0xe1a92e, 0x331dd8ba, 0x154a2230, 0x2e7e}}}, -{.x = { .val = {0xbc8f53b, 0x1c9d6a50, 0x11747c70, 0x889ace, 0x33d95ed7, 0xcb29f75, 0x1a7deafe, 0x5017fc3, 0xcbee}}, - .y = { .val = {0x38c87f45, 0x248b9ac9, 0x126f7282, 0x27fd3da0, 0x294cf0d, 0x3cf9a26e, 0x1f902b51, 0x7d3d39d, 0xf621}}}, -{.x = { .val = {0x14b311dd, 0xddf222c, 0x3d71b9cf, 0x38efabbe, 0x2252e03d, 0x202fe82e, 0x2f5acdd5, 0x2eb4a3ea, 0xadd5}}, - .y = { .val = {0x9d6c38d, 0xbe60bcd, 0x29b9b890, 0x353879d9, 0x19814f52, 0x390d3e0d, 0x1c3a5974, 0xf3d368f, 0xe9c4}}}, -{.x = { .val = {0xd7c0979, 0x17d90028, 0x5a8c96f, 0xa6cc52f, 0x1ced24a, 0x277cf7fd, 0x317143fa, 0x10caea05, 0x53f2}}, - .y = { .val = {0x137b36a2, 0x27dfa431, 0x1e8b845f, 0x35693d72, 0x1b07de4b, 0x138f8244, 0x79b7ccd, 0x3bfef07c, 0xbd52}}}, -{.x = { .val = {0x1d82b151, 0x2d44d032, 0x21fba2db, 0x28290f55, 0x109a8fcc, 0x168454ec, 0x1e56d64, 0xe942b90, 0xd2a6}}, - .y = { .val = {0x1cf89405, 0x105085d3, 0x84ca52d, 0x3dd42bd, 0x148220a7, 0x2bb962ca, 0x3fcb7565, 0x21bed910, 0xe82d}}}, -{.x = { .val = {0xa72da5f, 0x31b12eb3, 0x2c413497, 0x2e735acd, 0x3725f922, 0x31c8080c, 0x525e23b, 0x20e9d840, 0xbaf1}}, - .y = { .val = {0x28f2a0cf, 0x1df398a2, 0x27393613, 0x8cdb172, 0x29b1d18e, 0x22f56375, 0x34d33568, 0x27efa732, 0xdeac}}}, -{.x = { .val = {0x56c3943, 0x296b2963, 0x2b76a5ff, 0x36f40b55, 0x8f6fd5a, 0xcca41b9, 0x40238f9, 0x3e29f8e1, 0xf7ae}}, - .y = { .val = {0x2cf442f1, 0xc7d89fe, 0xdcd0034, 0x30c0612a, 0x2b3fcfee, 0x10aef70e, 0x3da797c4, 0x2d1357f, 0x4e3b}}}, -{.x = { .val = {0x11924459, 0x3eb2515c, 0x3c7a78c1, 0x3cbe8968, 0x1dbb1f7a, 0xb8a7c37, 0x19036c5a, 0x11f2c400, 0xdfb5}}, - .y = { .val = {0xc65fd9e, 0x28817837, 0x1c031dcf, 0x2bc24c39, 0x864cc22, 0xe273a77, 0x347088b8, 0x34aa6e83, 0x9acc}}}, -{.x = { .val = {0x1617e073, 0x10dbe6d1, 0x39317b3, 0x2b2f6f4e, 0xfdc866b, 0x39e25b5f, 0x31eb890e, 0x1f88cd51, 0x6458}}, - .y = { .val = {0x1faf6589, 0x20a6797a, 0x33aeab35, 0x2e428e44, 0x299a185, 0x1b75911f, 0x102e2ae9, 0x33756fda, 0xd99f}}}, -{.x = { .val = {0x384480d, 0x12f36231, 0x291f2ef4, 0x382da88a, 0x2f0c1294, 0xa2d5324, 0x3940f2cf, 0x35ac50b7, 0xb866}}, - .y = { .val = {0xc4cafa8, 0x39966d1c, 0x31d86d60, 0x3948a012, 0x1ad7ac24, 0x9e35faa, 0x2eb7089a, 0x2c2cd09a, 0x1914}}}, -{.x = { .val = {0x1db20d6c, 0x8a736a0, 0x14fe455d, 0x354ab93b, 0x2ba87e2, 0x27459184, 0x2819ec4d, 0x2e242177, 0xec2b}}, - .y = { .val = {0x229cf4a0, 0x3a67135, 0x7efa98a, 0x288d92fa, 0x940c633, 0x3d9bc194, 0x13a1332, 0x305d9878, 0xccec}}}, -{.x = { .val = {0x23b09d0f, 0x22983b2c, 0x350becf3, 0x141903, 0x145905e5, 0x35d7bd79, 0x296ced39, 0x29f8e278, 0x71c4}}, - .y = { .val = {0x320ddb62, 0xdec7c05, 0x262ffc76, 0x1bcac212, 0x3810aa78, 0xf828a4b, 0x2f3ba0af, 0x3eb6dcde, 0x1313}}}, -{.x = { .val = {0x1d45e458, 0x1635b21b, 0x250e7fd3, 0x2a9b3a8, 0x9de042f, 0x151b4f95, 0xd885b3a, 0x2f783939, 0x8481}}, - .y = { .val = {0x1779057e, 0x3592c6d6, 0x3262e556, 0x29e710a, 0x2cb2ca90, 0x96fce73, 0x4dd84a, 0x1ee32e95, 0x38ee}}}, -{.x = { .val = {0x2ce9f114, 0x1510cd49, 0x19561dde, 0xbb5814a, 0x1492bf39, 0x10f1b347, 0x3a8b9fd, 0x29142f4e, 0x9629}}, - .y = { .val = {0x224aa391, 0x28e5cb12, 0x56af8dc, 0x9564f97, 0xef64db9, 0x2fbf4883, 0x3b6d7576, 0x26ca0317, 0xbf43}}}, -{.x = { .val = {0x26ca6cc3, 0xf4e3658, 0x187e1838, 0x1df5d1f8, 0x893df14, 0x1cc369f3, 0x24688eb1, 0x711fbc7, 0xb73b}}, - .y = { .val = {0x254fdba3, 0x2b0d75da, 0x1757f5af, 0x8a89482, 0x8050973, 0x1f592ef3, 0x122a90a5, 0x572ca52, 0x5843}}}, -{.x = { .val = {0x138f93e0, 0x31b8864b, 0x276899f9, 0x16ca8eed, 0x22fef7d0, 0x2624801e, 0x180311f, 0x5acb6d0, 0xedfe}}, - .y = { .val = {0x229405ad, 0x3405e4f7, 0x6e227e3, 0xf544031, 0x5d0d25b, 0x1d3ea92c, 0x1db3694d, 0xbc7f29, 0xee69}}}, -{.x = { .val = {0x2caf666b, 0x3358c0fd, 0xb1ce30b, 0x3f3fb4f1, 0x17f4637f, 0x1a5e6ba0, 0x102aa62b, 0x1295e9e0, 0x1346}}, - .y = { .val = {0x3f6ecc27, 0x3d256a41, 0x10942e13, 0x3cc02a07, 0xcb0ca48, 0x390cd14f, 0x14580ef7, 0x5640118, 0x69be}}}, -{.x = { .val = {0x65084ae, 0x1d612718, 0x2abe577c, 0x20af9f73, 0x3e12d191, 0x17223217, 0x5362ec0, 0x3e3d4c89, 0xeb3c}}, - .y = { .val = {0x396b9480, 0x3d9f07ff, 0x3dbd2a66, 0xad17179, 0x1ca4a1f5, 0x398f73bf, 0x1d70043f, 0x31e088b6, 0xc833}}}, -{.x = { .val = {0x2e9a5d0, 0x2396f2f3, 0xa201d9f, 0x1dbf3e61, 0x519b2a5, 0x2983c861, 0x199974f7, 0x299f424b, 0xbdf1}}, - .y = { .val = {0x562ff7b, 0x36d3dc06, 0x1626461c, 0xa02d879, 0x3f7baaa6, 0x2f952a1a, 0x1a1aaa80, 0x240aead9, 0x4095}}}, -{.x = { .val = {0x3b27e771, 0x3797f05c, 0x37da62ab, 0xed06591, 0x483b48c, 0x2f899ed9, 0xec29cd5, 0x1a9bb771, 0x6885}}, - .y = { .val = {0x7bbdab6, 0x46358a8, 0x3b0733a6, 0x748bca4, 0x1f7b4a33, 0x1bf52706, 0x1a1fb13b, 0xf7c53de, 0x77a3}}}, -{.x = { .val = {0x2d83f366, 0x2b68e834, 0x2f28588c, 0x36733b78, 0x1dc97a0c, 0x3d0c2f30, 0x3fe2e9ae, 0x277d6dc4, 0xbc4a}}, - .y = { .val = {0x181f33c1, 0x1d635999, 0x2547b16d, 0x3a2a7efe, 0x3798caa6, 0x24deb7d2, 0x5c06383, 0x20729b9e, 0xd3a}}}, -{.x = { .val = {0x33fceb19, 0x20b79517, 0x385c4092, 0x226c887d, 0x27bab42e, 0x171d89b3, 0x2ccc0abc, 0xf578473, 0xda43}}, - .y = { .val = {0x26f5cc64, 0x2139c482, 0x227b2776, 0x1dff0b64, 0x15e5218e, 0x2ef712be, 0x10301de, 0x36f4c86a, 0xe498}}}, -{.x = { .val = {0x1acf692a, 0x13789d71, 0x2207e065, 0x3120e29c, 0x16efdbc, 0x3045a607, 0xc7ec1c1, 0x2387ba7a, 0x31e}}, - .y = { .val = {0x316f667a, 0x330aa13a, 0x1bf73b09, 0x192609f1, 0x16743b70, 0x25c0a43, 0x3353dd9d, 0x1fd6d196, 0xad7e}}}, -{.x = { .val = {0x1f488b6, 0xaef5ffe, 0x3c7a9159, 0x326fcd8f, 0x257f73e9, 0x38036189, 0x161155d3, 0x2181ea23, 0xa987}}, - .y = { .val = {0x31dab1d, 0x2569eeec, 0xad5c6d4, 0x343c0659, 0x157c2239, 0x18f9f208, 0x95d61c0, 0x286af562, 0xd181}}}, -{.x = { .val = {0x25324caa, 0x152acc3f, 0x29472a39, 0x12d978c2, 0x12a32e69, 0x3631d251, 0x18bc0d23, 0x2a5efe0a, 0x8c28}}, - .y = { .val = {0xbef9482, 0x39c771cf, 0x11cb9459, 0x39e13c11, 0x3cc0eb7a, 0x3fb7cc7d, 0x5193378, 0x118e8cc, 0x40a3}}}, -{.x = { .val = {0x3611d8e2, 0x37ec807d, 0x249fc4d5, 0x4c3fa37, 0x3f0da2c8, 0x3b569811, 0xa2f196b, 0x3061ca8e, 0xab1a}}, - .y = { .val = {0x429d15b, 0x69607cf, 0x21e545f0, 0x3be4f4cf, 0x2a42b6f7, 0x297ce76d, 0x117a1e9a, 0x28de8c93, 0x13f4}}}, -{.x = { .val = {0x2651b3fa, 0x9abb990, 0x32df4342, 0x286cd95d, 0x3f31ef8e, 0xe981c94, 0x2f82d370, 0x3fa6d6fb, 0x2564}}, - .y = { .val = {0x1e5122d, 0x2e0b9a8c, 0x379816ed, 0x3cdf6ada, 0x3925f14, 0x2852b848, 0x389095f, 0x3de9819e, 0x8ad9}}}, -{.x = { .val = {0x2e180068, 0x5e38f4e, 0xbd3103b, 0x28f55b08, 0xdc01a7e, 0x1b17030c, 0x5b0cbfc, 0x184dbfeb, 0xff3d}}, - .y = { .val = {0x188c6077, 0x29aedb8, 0x1f5e67, 0x1d9dbc90, 0x16adc154, 0xdcb376, 0xe40d, 0xe6fa139, 0x1332}}}, -{.x = { .val = {0x1faccae0, 0x2312e844, 0x24bb3374, 0x22cd4316, 0x71fd23c, 0x3653393c, 0x127a8c1d, 0x259984e5, 0x8ea}}, - .y = { .val = {0xe62b945, 0x16bcd28c, 0xf0f8e95, 0x2de0efa7, 0x15c5d735, 0x39f033ee, 0x22782e24, 0x3eaef23b, 0x620e}}}, -{.x = { .val = {0x2190b632, 0xa4c4c76, 0xab5ab9a, 0x33ca88e9, 0x159d8263, 0x19b7cc55, 0x20cd9f3a, 0x18dc5d88, 0xc25f}}, - .y = { .val = {0x3c9590cf, 0x3bafcf5b, 0x2027a1d6, 0x27c13fe7, 0x9d7980a, 0x12640e0, 0x12873989, 0x13fb7a53, 0x5315}}}, -{.x = { .val = {0x1466d561, 0xb32cedf, 0x1978b4de, 0x1ed5770c, 0x8544c0c, 0xb60a95a, 0x26bab3e8, 0x237f8f33, 0x2a9e}}, - .y = { .val = {0x12e76373, 0x25b33d49, 0x3a02182f, 0x7abb05, 0xb96cf5e, 0x1ed6b582, 0x2651fbac, 0x3b69705b, 0x1df}}}, -{.x = { .val = {0x3f8be384, 0x22f4c810, 0x31db6c3e, 0x3b02ab68, 0x1ef07271, 0x2b5b253f, 0x23e1b251, 0x24290af9, 0xb237}}, - .y = { .val = {0x2b19880e, 0x4291cf7, 0x9ecb58d, 0x3c013d05, 0x1f94517, 0x143e22aa, 0x15edbe8d, 0x1a524675, 0xfc6b}}}, +{/*.x =*/{/*.val =*/{0x16f81798, 0x27ca056c, 0x1ce28d95, 0x26ff36cb, 0x70b0702, 0x18a573a, 0xbbac55a, 0x199fbe77, 0x79be}}, + /*.y =*/{/*.val =*/{0x3b10d4b8, 0x311f423f, 0x28554199, 0x5ed1229, 0x1108a8fd, 0x13eff038, 0x3c4655da, 0x369dc9a8, 0x483a}}}, +{/*.x =*/{/*.val =*/{0x1c709ee5, 0x2eb026e5, 0xef3ca7a, 0x1de392e3, 0x7cd85c, 0x1501ba57, 0x17d6d304, 0x1fe5107b, 0xc604}}, + /*.y =*/{/*.val =*/{0x10cfe52a, 0xd90c6a5, 0x266d0e12, 0x3d8c994c, 0x2ceaeef7, 0x16106519, 0x1c339a3c, 0x1a3fa98f, 0x1ae1}}}, +{/*.x =*/{/*.val =*/{0x28c4cd13, 0x13ea52af, 0x2e075847, 0x1b04e403, 0xb1404cc, 0x3924124c, 0x180f3581, 0x36fc7043, 0xe493}}, + /*.y =*/{/*.val =*/{0x7739922, 0x3fa5ef71, 0x3bdfe40c, 0x19eb8cef, 0x251448d9, 0xb88263a, 0x55b7564, 0x264fa835, 0x51ed}}}, +{/*.x =*/{/*.val =*/{0x210a2a01, 0x1de13bcf, 0x1af888a6, 0x6f74179, 0xf3c2f0a, 0xe10fedc, 0x2351daff, 0x39785732, 0x2f01}}, + /*.y =*/{/*.val =*/{0x2cbde904, 0x1768b2dd, 0x25b7617b, 0x3884f5ae, 0x2d13b4c2, 0x3420a84c, 0x39949293, 0x2a29d054, 0x5c4d}}}, +{/*.x =*/{/*.val =*/{0x2a6dec0a, 0x113ba278, 0x7a5ae9c, 0x28c4da6e, 0x23e97b2, 0x6aaf087, 0x29ec5301, 0x33a4ed67, 0xe60f}}, + /*.y =*/{/*.val =*/{0x29616821, 0x7ccb339, 0xd23f0be, 0x25a24791, 0x39371012, 0x267cd3d5, 0x195929db, 0x141ce679, 0xf7e3}}}, +{/*.x =*/{/*.val =*/{0x7143e65, 0x17436f50, 0x104a61d7, 0x33ff2e26, 0x3378ceda, 0x1b81538b, 0x1a22d47b, 0x2675d3ed, 0xd301}}, + /*.y =*/{/*.val =*/{0x24106ab9, 0x16cffc7c, 0xed81960, 0x1d8330d9, 0x380651f, 0x1b7b27a6, 0x3d5c3b3d, 0x236742b8, 0x9503}}}, +{/*.x =*/{/*.val =*/{0x3874ef8b, 0xde4639b, 0x1bafd81e, 0x131bc773, 0x32823cfc, 0x147abe0, 0x2eab70b1, 0x30550b45, 0xbf23}}, + /*.y =*/{/*.val =*/{0x26831d9f, 0x370dfbf9, 0x11e2f784, 0x8bf1520, 0x1392e4c5, 0x24a282e9, 0x3737ad, 0x219bf0cc, 0x5cb3}}}, +{/*.x =*/{/*.val =*/{0x2769a24e, 0x11c1dd15, 0x5356556, 0x3d5735c0, 0x11671cbc, 0x30f427df, 0x37a06696, 0xef900cf, 0x34ff}}, + /*.y =*/{/*.val =*/{0x33cc2f1a, 0x124419e9, 0xf8b6818, 0x37c5b0fa, 0x32098c55, 0x18676260, 0x36c553f6, 0x4588e88, 0x5d9d}}}, +{/*.x =*/{/*.val =*/{0x15f51508, 0x191b88ff, 0x1ac1ca10, 0x30e72af5, 0x2de238d8, 0x29b8f85c, 0x209d9ea2, 0x98c84b1, 0x8282}}, + /*.y =*/{/*.val =*/{0x36e26caf, 0xc6dbabf, 0x37b17bed, 0x3584eb0b, 0x360ace62, 0x95ba0c2, 0x3dfe45e8, 0x2a026155, 0x11f8}}}, +{/*.x =*/{/*.val =*/{0x2f34a24d, 0x9b8b003, 0x1e159d09, 0x36f25a36, 0x3918d50a, 0x2a15ea73, 0x39ff3905, 0x1c2ca1e9, 0x4653}}, + /*.y =*/{/*.val =*/{0x333887f4, 0xbe3ec82, 0x1d37a10a, 0x23826c85, 0x2ec2c158, 0x3e2f6bf7, 0xc082a4a, 0xc6ce0da, 0x35e5}}}, +{/*.x =*/{/*.val =*/{0x2285131f, 0x16e406cb, 0x13b088d, 0x3b1bb372, 0x2d6240aa, 0x12863d9a, 0xbd77d66, 0x3aee388f, 0x241f}}, + /*.y =*/{/*.val =*/{0x2750026d, 0x2ecf99bc, 0x10cb5afa, 0x143f43ef, 0x181df8cd, 0x1082f44e, 0xf8d3d6c, 0x1e367fe5, 0x5133}}}, +{/*.x =*/{/*.val =*/{0x1b920471, 0x372d8c1a, 0x23de0de, 0xc62e17d, 0x18f8d9fc, 0x1330a60f, 0x2fa79fce, 0x36d3a85c, 0x5d1b}}, + /*.y =*/{/*.val =*/{0x37b83103, 0xcc199b, 0x2c56e7b7, 0x3ac7a665, 0x22265679, 0x2ee650e2, 0x39e2e794, 0x2099de4d, 0x2843}}}, +{/*.x =*/{/*.val =*/{0x11e5b739, 0xff396d5, 0x12222ed7, 0x2e4e0cff, 0x3c846de0, 0x26731b1b, 0x3865a72f, 0x567dca2, 0x175e}}, + /*.y =*/{/*.val =*/{0x29fed695, 0x3be9bffb, 0x124345c6, 0x2d6556b7, 0x371f5eac, 0x3e5e947f, 0x79eba4e, 0x1b83678f, 0xd350}}}, +{/*.x =*/{/*.val =*/{0x6bc47d6, 0x39e01279, 0x2da121bc, 0x3f7fad71, 0x39c62130, 0x3ef32384, 0x332d7a5f, 0x4fc0ff, 0x423a}}, + /*.y =*/{/*.val =*/{0xb548a34, 0x48db9b6, 0x24f009ed, 0x363b0d4, 0x36b3c772, 0x1e7deeeb, 0x1d970a11, 0x3803f878, 0xb91a}}}, +{/*.x =*/{/*.val =*/{0x416824a, 0xb7dbde, 0x33e27413, 0x37d98bce, 0x16877649, 0x1e9eaf3, 0x3b905089, 0x1a916b07, 0x111d}}, + /*.y =*/{/*.val =*/{0x2108e9d0, 0x26844750, 0x2daca4ca, 0x1c002265, 0x65952f0, 0x35236ffc, 0x2affbb90, 0x244711e3, 0x696}}}, +{/*.x =*/{/*.val =*/{0x1bced775, 0x2d7b7780, 0x2f74e56a, 0x242da297, 0x39dcff72, 0x2576faf2, 0x3c8b8ad7, 0x1b725eb1, 0x4a4a}}, + /*.y =*/{/*.val =*/{0x278dd66d, 0xafe3da2, 0x24742acb, 0x3a4336d0, 0xf4571d, 0x3be7dce7, 0x31e72943, 0x46c0598, 0x5299}}}, +{/*.x =*/{/*.val =*/{0x3ff4640, 0x9aeb63e, 0x1552ffe5, 0x11071f95, 0x262ee053, 0x3ab016d8, 0xc9c99c, 0x243511ec, 0x363d}}, + /*.y =*/{/*.val =*/{0x3bee9de9, 0x800f1fc, 0x199ecb6, 0x2e6a2402, 0x33363145, 0x2d114e5f, 0x32221953, 0x1ceb7f1c, 0x4e2}}}, +{/*.x =*/{/*.val =*/{0x2f92c541, 0x9c4a972, 0x2dfb59dd, 0x18bec04b, 0x3b02bf0b, 0x25cf1b24, 0x27e9b553, 0x2619bb66, 0x4c1b}}, + /*.y =*/{/*.val =*/{0x68fe020, 0xb13cff7, 0x3eb1ad7, 0x14bab5f9, 0x16e69cc6, 0x32dd4f39, 0x28a0f7fb, 0x24b4c82f, 0xc1f7}}}, +{/*.x =*/{/*.val =*/{0x3eaaf3d1, 0x323ca32, 0x228f135e, 0xcfb6f06, 0xb54e32, 0x28bcf01e, 0x3b12b529, 0xe1deea0, 0xa408}}, + /*.y =*/{/*.val =*/{0x30b254b9, 0x4ad4d37, 0x2d1ef90b, 0x79d5db, 0x21b3e220, 0x3e0f5a4d, 0x3bc79b8b, 0x3d84bfbb, 0x40e9}}}, +{/*.x =*/{/*.val =*/{0x3940d33a, 0x334f6d69, 0x14203b98, 0x3620291, 0x16c86f6e, 0x38f868bd, 0xc0b53a4, 0x319074a3, 0xa804}}, + /*.y =*/{/*.val =*/{0x2d46967a, 0xf3a57e9, 0xf736a94, 0x3c632a27, 0x2047e81a, 0x30a10b05, 0x3a6d03de, 0x20c94acb, 0x95be}}}, +{/*.x =*/{/*.val =*/{0x1ffdf80c, 0x27de6957, 0x15bcd1b6, 0x3929e068, 0x5638843, 0x912d6dd, 0x3c2be8c6, 0x17c5977c, 0x8b4b}}, + /*.y =*/{/*.val =*/{0x1fd4fd36, 0xfbfc319, 0x162ee56b, 0x38cd9518, 0x30da04f9, 0x2f5e04ea, 0x308b4b3f, 0x29bda34, 0x4aad}}}, +{/*.x =*/{/*.val =*/{0x755e4be, 0x2cfc99c5, 0x17c997ab, 0x2bd93b90, 0x3c611071, 0x5f1fb20, 0x291718ce, 0x1739384c, 0xed0c}}, + /*.y =*/{/*.val =*/{0x207bf42f, 0xfe7e9ba, 0x23ddab16, 0x364e495d, 0x3ea68049, 0x36b5fd69, 0x345bdbf3, 0x27f1ef08, 0x221a}}}, +{/*.x =*/{/*.val =*/{0x7cec8ab, 0x12db9b20, 0x20552ced, 0xc95159b, 0x31fae8e5, 0x570fe0f, 0xe694b3b, 0x2c04f113, 0xfaec}}, + /*.y =*/{/*.val =*/{0x2b155070, 0x26077f66, 0x5e2e2e8, 0xcaca1ae, 0x2fb13d9c, 0x380b1bb0, 0x2cb57fc2, 0x2d7a43a7, 0xcc09}}}, +{/*.x =*/{/*.val =*/{0x1ad1b1f7, 0x1fd93aba, 0x323cd3e0, 0x2cb76093, 0xbcafdb3, 0xc682cdf, 0x2d2f2c87, 0x2284cb72, 0x9bb}}, + /*.y =*/{/*.val =*/{0x3811c80, 0x104c189f, 0x752d536, 0x152a103d, 0x63e850f, 0x2774a13e, 0x2e3b9b6f, 0x2cacabfb, 0x945b}}}, +{/*.x =*/{/*.val =*/{0x1232fcda, 0x2d845649, 0x2c0e77bc, 0x36ffe9, 0x1548c7b7, 0x1dc7002f, 0x3996d6bf, 0x2ea9b976, 0x723c}}, + /*.y =*/{/*.val =*/{0x1eb39f5f, 0x7701a76, 0x37949480, 0x1828194d, 0x24d6e26, 0x44dd222, 0xc498a92, 0x19ed5657, 0x96e8}}}, +{/*.x =*/{/*.val =*/{0xca030d5, 0x3f4e0f58, 0x39849071, 0x90290c1, 0x33a3c62d, 0x35f7115d, 0x3744d343, 0x29e190de, 0x57ef}}, + /*.y =*/{/*.val =*/{0x34b02f9e, 0x1ead109, 0x1e9974ab, 0x26db4ab9, 0x1e03ec68, 0x189f24a3, 0x8518893, 0x36c2f46d, 0xd712}}}, +{/*.x =*/{/*.val =*/{0xc584dd5, 0x3ebf1ddc, 0x27b012a7, 0x2015df8c, 0x226cb910, 0x3dfa7354, 0xbc42a2d, 0x2f50da8a, 0x264b}}, + /*.y =*/{/*.val =*/{0x3704ab11, 0x18489e4d, 0x17b8d8de, 0x46090dc, 0x33be226a, 0x1d738930, 0x93b4d4f, 0x1bea53b8, 0xd87c}}}, +{/*.x =*/{/*.val =*/{0xb2438e8, 0x2fc9af61, 0x1bdec9d2, 0x22f187f5, 0x36a79da7, 0x21701588, 0xd2bbdac, 0x19492f50, 0xa94c}}, + /*.y =*/{/*.val =*/{0x318661f4, 0xb8b236f, 0xe39b2bc, 0x174f1828, 0x19e3a7e, 0x24865414, 0x16280fd7, 0x7f664be, 0xb520}}}, +{/*.x =*/{/*.val =*/{0xe7dd7fa, 0x294cfb28, 0x3a919839, 0x11e5848d, 0x2d3b509, 0x3fbb204b, 0x2bf98ba5, 0x293524ef, 0xeebf}}, + /*.y =*/{/*.val =*/{0x21de8999, 0x37f53f6b, 0x311f712d, 0x393370e9, 0x38089d9a, 0x39fb6bc5, 0x2f0f269e, 0x2328e5c3, 0x5d9a}}}, +{/*.x =*/{/*.val =*/{0x7d297fd, 0x1afba421, 0x36766d67, 0x3a92f023, 0x18495fc4, 0x3180c704, 0x17bfda61, 0x12b5e9ea, 0x381c}}, + /*.y =*/{/*.val =*/{0x3d493fc5, 0xeb38c61, 0x3939c009, 0x11440cb6, 0x115eccf0, 0x397e9c26, 0x2eee48f3, 0x3d4ec8e3, 0x936a}}}, +{/*.x =*/{/*.val =*/{0x2ede454c, 0x1235c108, 0x3dd08b24, 0x3c7417fb, 0x138c479c, 0x420c765, 0x1c63bcce, 0x2e73416b, 0xe1ef}}, + /*.y =*/{/*.val =*/{0x28913797, 0x367f48ce, 0x3a2d4c6a, 0x138c9129, 0x7712346, 0x15307ff9, 0x39be7b01, 0x114c362b, 0xecb}}}, +{/*.x =*/{/*.val =*/{0x29eb99a4, 0xcffbacc, 0x3d47b18d, 0x395067cc, 0x3475a8c7, 0x308d7a6b, 0x17010c5a, 0x3e6c689a, 0x5318}}, + /*.y =*/{/*.val =*/{0x3e91f92d, 0x31c9bbbb, 0x1e3ec652, 0x7cad034, 0x3405e8a4, 0xb64ebae, 0x1a419577, 0x33fad2fb, 0xf44c}}}, +{/*.x =*/{/*.val =*/{0x39a48db0, 0x3f5e0d6c, 0x33c03bfe, 0x48568a6, 0x3bde459f, 0x742826d, 0x27167279, 0x11369a5b, 0x100f}}, + /*.y =*/{/*.val =*/{0x2bc65a09, 0x3ef57358, 0x35195ac0, 0x3fd2863f, 0x90666b7, 0x23ccc030, 0xb772ec, 0x384c64a8, 0xcdd9}}}, +{/*.x =*/{/*.val =*/{0x1e4df706, 0x2c14a13c, 0x37d08084, 0x36723e48, 0xc4199d8, 0x577fcad, 0x1c771a84, 0x227cb3ad, 0x8c09}}, + /*.y =*/{/*.val =*/{0x1d72fa98, 0xdab168d, 0x16511aa7, 0x379afd45, 0x1c966c60, 0x85cb2e7, 0x32034ffd, 0x2f4113d0, 0xfb4d}}}, +{/*.x =*/{/*.val =*/{0x1c47bffd, 0x798f0cf, 0x95bc1bb, 0x14a14e6f, 0x22c0259c, 0x1205d0c9, 0x26704c4a, 0x54f1789, 0xfb8f}}, + /*.y =*/{/*.val =*/{0x1949b095, 0x24291777, 0x5426130, 0x3784e26b, 0x3ccd531d, 0x284766d2, 0x621816f, 0x1ea77178, 0x6ca2}}}, +{/*.x =*/{/*.val =*/{0xbb2629a, 0x23e86e2d, 0x337a7b8b, 0x280b161d, 0x28708465, 0x3327c29c, 0x151755a0, 0xccff5d7, 0xe747}}, + /*.y =*/{/*.val =*/{0x2946f6d6, 0x3e365869, 0x21a969a9, 0x20ddaa9b, 0xc2581c8, 0x10d80e01, 0x30c114cc, 0x3f805141, 0xf2af}}}, +{/*.x =*/{/*.val =*/{0x2534fd2d, 0x322b379b, 0xf3b3852, 0x1fe35119, 0x4c017a7, 0x2489e928, 0x3ed1b1dc, 0x6f898b1, 0xe103}}, + /*.y =*/{/*.val =*/{0x1456a00d, 0x113c63ca, 0x21ced79a, 0x24b75067, 0x17535af2, 0x1a905d96, 0x405e6bb, 0x1864a250, 0x9d70}}}, +{/*.x =*/{/*.val =*/{0x295c8356, 0x1389f8da, 0x294d8578, 0x229ab177, 0x29b2c902, 0x2577343c, 0x89eab9f, 0xfc89320, 0xf4b9}}, + /*.y =*/{/*.val =*/{0x3e001fd3, 0x356186e6, 0x115609ab, 0x1fbc4d12, 0xeee90c3, 0x17da9e90, 0x162dfb0e, 0x24bb018a, 0xa67a}}}, +{/*.x =*/{/*.val =*/{0x3b160e8a, 0x358bf85, 0x17e696c2, 0x7a144be, 0x1b08b0d5, 0x188ba809, 0x15236b19, 0x2b287f39, 0x9d1}}, + /*.y =*/{/*.val =*/{0x3ca04c44, 0x13814315, 0x212b5e53, 0x3a783ba4, 0x18c27e6f, 0x19a4b383, 0x1f0c63e5, 0x623d440, 0x1153}}}, +{/*.x =*/{/*.val =*/{0x35ba7fc2, 0x25f5f411, 0x3c39562e, 0x22cea4ef, 0x21cde751, 0xab5e4e0, 0x2b9e18a, 0x16731153, 0xc66c}}, + /*.y =*/{/*.val =*/{0x375f5956, 0x3b0f1a73, 0x15955977, 0x298376c, 0x10cb2f0, 0x13cf3aab, 0x30fcfbea, 0xbf8afec, 0xd959}}}, +{/*.x =*/{/*.val =*/{0x1094696d, 0x3579a236, 0x1d6af52, 0x3e2c99a9, 0x3bd7ec5c, 0xa0e7c50, 0x15b530ac, 0x1b2b91b5, 0xfeea}}, + /*.y =*/{/*.val =*/{0x18090088, 0x5577afc, 0x41442d3, 0x72255f3, 0x3ecd5c98, 0x39384afc, 0xe1bab06, 0x1adb25f7, 0xe57c}}}, +{/*.x =*/{/*.val =*/{0x2e752b08, 0x2a90102b, 0x331a1870, 0x7b2b82c, 0x32e17914, 0x986be76, 0x387e1c53, 0x2d886b6, 0x4d00}}, + /*.y =*/{/*.val =*/{0x8302cea, 0x39ca147d, 0x1c7293a3, 0x1f7d7c46, 0x1972cccb, 0x3609560b, 0xd255cb6, 0x16e3c638, 0x6a0d}}}, +{/*.x =*/{/*.val =*/{0x75c58ef, 0x22658bf5, 0x21f1b77f, 0x15e8100f, 0x317128d6, 0x28988451, 0x1a05dd6a, 0x1c32880f, 0x71f5}}, + /*.y =*/{/*.val =*/{0x135d420e, 0x219269cb, 0x3363e7df, 0x11174030, 0x95b8df2, 0x155cd16f, 0x880dd25, 0x1056e577, 0xeb42}}}, +{/*.x =*/{/*.val =*/{0x3ff8359, 0x122c181, 0x25e76516, 0x2d208771, 0x1da01446, 0xa0ad708, 0x3d253b7d, 0x2cd8a7de, 0xa2b7}}, + /*.y =*/{/*.val =*/{0x3e86fec2, 0x8e5ffb3, 0x6f3835a, 0x34420d41, 0x1e29c910, 0x24de8fdc, 0x1122d57a, 0xe2505a5, 0x6930}}}, +{/*.x =*/{/*.val =*/{0x1ec6cb1, 0xfea5e2f, 0x8583de3, 0x3b595f60, 0x3fca3cfe, 0x1ef92f9b, 0x9cdcb36, 0x2a476441, 0xda67}}, + /*.y =*/{/*.val =*/{0x3a68be1d, 0x3a7aa389, 0xf740a17, 0x31eb7142, 0x1780e5de, 0x118fdfb2, 0x242bc41f, 0x2a8d5205, 0x9bac}}}, +{/*.x =*/{/*.val =*/{0x1fe741c9, 0x3b8f3208, 0xea5a835, 0x2f67cd73, 0xd8718b, 0x3033eabc, 0x1ef587c0, 0x334d97e8, 0x4dba}}, + /*.y =*/{/*.val =*/{0x338eb623, 0x2f843e0, 0x3c0535f6, 0x30e12827, 0x38299d0c, 0x33f567a0, 0x1892e7fd, 0x1503a294, 0x16c3}}}, +{/*.x =*/{/*.val =*/{0x34e218da, 0x1fb6a2ea, 0x26860508, 0x13217c54, 0x1c2590f, 0x3c5f63fd, 0x9beee68, 0x3ff12054, 0x13d1}}, + /*.y =*/{/*.val =*/{0x1b191c19, 0x36d0677, 0x15bd127e, 0x2b40481b, 0x3758bda4, 0x2e4cdec6, 0x1961dcec, 0xe47ea64, 0x6008}}}, +{/*.x =*/{/*.val =*/{0x22e96db8, 0xced032a, 0x229dbff1, 0x327645b3, 0x30533b3c, 0x271e7116, 0x6000765, 0x13e73bdb, 0x219b}}, + /*.y =*/{/*.val =*/{0xd3b6bc7, 0x1f7c069e, 0x29057652, 0x13e2b14f, 0x372a6e39, 0x11060300, 0x1efeaf5a, 0x31817656, 0x24d9}}}, +{/*.x =*/{/*.val =*/{0x1a37b7c0, 0x1d517330, 0x311069f5, 0x2343dee, 0x322151ec, 0x24d7b, 0x34cdda6e, 0x13ea82cc, 0x5390}}, + /*.y =*/{/*.val =*/{0x22771c8, 0x372c25ac, 0x14434699, 0x26666078, 0xd3c1c13, 0x27b32b08, 0x106d88c, 0x21f42f20, 0x5bc0}}}, +{/*.x =*/{/*.val =*/{0x38a47ca9, 0x1f343c7c, 0x10f85ad5, 0x1bb9eaab, 0x16995d2a, 0x2644658c, 0x146753cf, 0x1d6be750, 0x1a5}}, + /*.y =*/{/*.val =*/{0x37ebcdb7, 0x1f177cb9, 0x34d7ea66, 0x2e4f1767, 0x3b8698bd, 0x17f14b86, 0x20dc3cc5, 0x3c72e2ac, 0x3038}}}, +{/*.x =*/{/*.val =*/{0x2315565b, 0xc275d57, 0x3c20c6ee, 0x2986a0f4, 0x2155d6d3, 0x7d706dd, 0x1d439ca7, 0x3810dd88, 0xf5f0}}, + /*.y =*/{/*.val =*/{0x1d2ecc82, 0x1e10c2bf, 0x2d7e40a6, 0x2fd86fcf, 0x37101aa5, 0x6245837, 0x2052bf62, 0x1398af96, 0x6b9f}}}, +{/*.x =*/{/*.val =*/{0x35362d33, 0x2f9e0767, 0x2227642c, 0x32f24851, 0xca4e347, 0x1fcdb65c, 0x36e9a57a, 0x1bc2db02, 0x8f50}}, + /*.y =*/{/*.val =*/{0x7fa243f, 0x121f432, 0x3bb8eaf3, 0x33e49750, 0x1c336848, 0x315093c, 0x26171953, 0x25574abe, 0x469f}}}, +{/*.x =*/{/*.val =*/{0x3ad86047, 0x3fe567d0, 0x29b8bcae, 0x2d4e810e, 0xa906779, 0x3329dd93, 0x183a7719, 0x3342f4d6, 0x8e7b}}, + /*.y =*/{/*.val =*/{0x460372a, 0x284011fa, 0x3fd68b3e, 0x3a238b91, 0x29514579, 0xc410832, 0x1a4b3940, 0x1dc2ca8f, 0x10b7}}}, +{/*.x =*/{/*.val =*/{0x313f0351, 0x1f4a022f, 0x10389e77, 0x3056e34f, 0x2950df3b, 0x3cc6665, 0x2729dc35, 0x16ea8657, 0x33b3}}, + /*.y =*/{/*.val =*/{0xb8d7418, 0x2f140f33, 0x889b702, 0x19583bef, 0xd52bcaa, 0x1900d892, 0x2bf87f94, 0x615902, 0xa58a}}}, +{/*.x =*/{/*.val =*/{0x414bb36, 0x1c771ec9, 0x2d7bca6d, 0x3db84272, 0x1f7e2256, 0x20eb481c, 0x13f955cb, 0x3bab88b2, 0x374d}}, + /*.y =*/{/*.val =*/{0xdaf734a, 0x21d6faa6, 0xe543217, 0xa3598c0, 0x6f72938, 0xcb01be0, 0x14f99160, 0x196d93f3, 0x1711}}}, +{/*.x =*/{/*.val =*/{0x2ae7d616, 0x3a2992b5, 0x22a9f0c5, 0x136ebcad, 0x2eb0dc94, 0x1b81ce56, 0x2eae57c4, 0x30271fce, 0x2380}}, + /*.y =*/{/*.val =*/{0x161bbc1a, 0x266f920, 0x38467560, 0x2be48523, 0x9b09a93, 0x262bbf54, 0x956af15, 0x21864d19, 0x6f8e}}}, +{/*.x =*/{/*.val =*/{0x19c43862, 0x2a107856, 0x397e6690, 0x29fd3c60, 0x381bde71, 0x2061a26, 0x1ff21e6d, 0x3b4d3073, 0x385e}}, + /*.y =*/{/*.val =*/{0x142e5453, 0x1163f95, 0x86dc8cc, 0xc13bb08, 0x2bf4576b, 0x77867a7, 0x223f5670, 0x3af0fa3a, 0x283b}}}, +{/*.x =*/{/*.val =*/{0x38f2827c, 0x320e89c1, 0x2fc1ce2d, 0x320990af, 0x1f67d147, 0x1af84d35, 0x35480045, 0x8820f6b, 0xf6f6}}, + /*.y =*/{/*.val =*/{0x20aaa102, 0x56c82d4, 0x321bf6d, 0x15f29d12, 0x27cee7e6, 0x315c56cd, 0x33a0faf2, 0x13a05f79, 0x1bcd}}}, +{/*.x =*/{/*.val =*/{0x315adcb6, 0x3624c825, 0x18c6f369, 0x2470f39f, 0x1fc255cd, 0x32cf0f4, 0x13de2bd7, 0x394623e5, 0xfb26}}, + /*.y =*/{/*.val =*/{0x18ba68f3, 0x276f28ed, 0xb7ab544, 0x34b2cc6e, 0x10176916, 0x211a9c67, 0x2a34d58e, 0xa204404, 0xf3e1}}}, +{/*.x =*/{/*.val =*/{0x20788c1e, 0x35136dd5, 0x28bd1d7e, 0x230dc183, 0x3ceab7d1, 0x171af1d8, 0x1132d28f, 0x896446e, 0x8991}}, + /*.y =*/{/*.val =*/{0xe8f0ef1, 0xd71088a, 0x1ef9e116, 0x25a7213f, 0x3136fa36, 0x21d8d566, 0x1ac9b27b, 0x13661f32, 0xda8b}}}, +{/*.x =*/{/*.val =*/{0x3fac3a7, 0x181bb61b, 0x147fbc9c, 0x377e1296, 0x3dfa180f, 0x31ce9104, 0xf191637, 0x366e00fb, 0x6f9}}, + /*.y =*/{/*.val =*/{0x3a842160, 0x21a24180, 0x281002d, 0x29374bd7, 0x5c4d47e, 0x238a8c39, 0x59ba69b, 0x31a3980c, 0x7c80}}}, +{/*.x =*/{/*.val =*/{0xb7fd72d, 0x327489d1, 0x3e4da175, 0x5d17969, 0x82939da, 0x30db0a11, 0x3411c1cd, 0x3bba894a, 0xae86}}, + /*.y =*/{/*.val =*/{0xeee38bc, 0xcd32de9, 0x72f7282, 0x24845545, 0x1ff0e98d, 0x2c2b3962, 0x302f962a, 0x24f25c1c, 0x19e9}}}, +{/*.x =*/{/*.val =*/{0x3c169290, 0x2851d099, 0x336f2ee7, 0x62f9d73, 0x1c2c4887, 0x34be315b, 0x3ff55e61, 0x327e42ef, 0x2248}}, + /*.y =*/{/*.val =*/{0x83ea257, 0x1a76284a, 0x1da2be23, 0x18dd408d, 0x35ba18e1, 0x1aed56d0, 0x1eed7a50, 0x251a4b48, 0xfa05}}}, +{/*.x =*/{/*.val =*/{0x350964e3, 0x3436b12e, 0x11c6f76f, 0x27c21df7, 0x85d0a9, 0x46d2365, 0x44074ac, 0x1b85b817, 0xe11a}}, + /*.y =*/{/*.val =*/{0x682bfc8, 0x19fefe2c, 0x318c6f7, 0x2b71b84e, 0x30af2417, 0x3578965b, 0x2d430e1a, 0x196e1e8, 0x87d6}}}, +{/*.x =*/{/*.val =*/{0x2d0e6bd, 0xedf839d, 0x30f5e531, 0x1d3458f6, 0xd6ecbf7, 0x851f041, 0x4e2582a, 0x3500490f, 0x3322}}, + /*.y =*/{/*.val =*/{0x2c28b2a0, 0x13ce8ba5, 0x2873af62, 0x17d8fa8, 0x1af9b728, 0x66f137, 0x24ef5bfb, 0x1e5fa59, 0x56e7}}}, +{/*.x =*/{/*.val =*/{0xade462, 0x31a5b4cb, 0x2dbcf29f, 0x1337723a, 0x80cd50d, 0x3bcc6c13, 0x2bdae120, 0x8009433, 0x8d26}}, + /*.y =*/{/*.val =*/{0xf26470c, 0x2382a2e4, 0x2678b3ad, 0x12bed39c, 0x2e36ba1d, 0x3dbcb70f, 0x3f437d31, 0xeed1c56, 0xebed}}}, +{/*.x =*/{/*.val =*/{0x1516e633, 0x59190f8, 0x32d9c8b9, 0x3524c341, 0x14d03b8e, 0x1a287d6, 0x2bea9ce4, 0x301d9bab, 0x1238}}, + /*.y =*/{/*.val =*/{0x77b7805, 0x1736dca3, 0x7402280, 0x11894b73, 0x3dc1709, 0x25e78b47, 0x31359d6c, 0x2c0b6ec9, 0x8a9d}}}, +{/*.x =*/{/*.val =*/{0x388e7a66, 0x26c05549, 0x30ec2161, 0x3735ca0a, 0x2a11b9cd, 0xba9d629, 0x39c15e7b, 0x16c1dc32, 0x271d}}, + /*.y =*/{/*.val =*/{0x203c9727, 0x2a35c963, 0x8a824e7, 0x281978d4, 0x2c877fe2, 0x1f426526, 0x3f491e45, 0x29160d39, 0x5d3a}}}, +{/*.x =*/{/*.val =*/{0x134ab83, 0x875d34a, 0x36433977, 0x6cfe6bd, 0x26586874, 0x5dc3625, 0xb7da2bd, 0xb1f4b78, 0x8567}}, + /*.y =*/{/*.val =*/{0x390313a6, 0x238c253d, 0x1298f44c, 0x1fc5ff31, 0x22c2e5e7, 0x10126fe9, 0x3b2eb637, 0x6e6d6d0, 0x7c48}}}, +{/*.x =*/{/*.val =*/{0x1f17fc25, 0x262e42f0, 0x32e6d969, 0x227a91b7, 0x8a61f3b, 0x6184857, 0x39ec036c, 0x33dadd03, 0x534c}}, + /*.y =*/{/*.val =*/{0xfe86e76, 0x1c71fdbb, 0x3dd28ddd, 0x38f49def, 0x1543550a, 0x2b8f74cb, 0x32ddb462, 0x172c2722, 0xd571}}}, +{/*.x =*/{/*.val =*/{0x28bee8b6, 0x1c5c248f, 0xfbc8d2c, 0x8351fb, 0x38aaed79, 0x38508063, 0x3b7f3081, 0x7d73ba1, 0xa91d}}, + /*.y =*/{/*.val =*/{0x10644c1, 0xf45aa9, 0x28cb2250, 0x15a7d8, 0x1ad3b2f8, 0x6272377, 0x38ee15a7, 0xc93b8b7, 0x748a}}}, +{/*.x =*/{/*.val =*/{0x1984cf74, 0x28687095, 0x2f61f10a, 0xd6b916f, 0x14383c07, 0x853778b, 0x8e35c1a, 0x2308f643, 0xc15c}}, + /*.y =*/{/*.val =*/{0x39ccb000, 0x12923360, 0xb015a2c, 0x2fddcb54, 0x1fd7ba47, 0x31bd1789, 0x22235c8d, 0x15360a14, 0x2ba9}}}, +{/*.x =*/{/*.val =*/{0x20c82a0a, 0x3f6566bd, 0x3668832f, 0x2489b183, 0x1413b10f, 0x1b27c646, 0x188a46b0, 0x2fe026c6, 0x948}}, + /*.y =*/{/*.val =*/{0x18c8e589, 0x132dfe23, 0x17cd2bed, 0x137fc232, 0x3418c6d, 0x2dd31747, 0x36646dc6, 0x18a15b72, 0x53a5}}}, +{/*.x =*/{/*.val =*/{0x3e8b000a, 0x25bac115, 0x2825e513, 0x5b04cc7, 0x11f0b6ef, 0x3393198a, 0x259360d5, 0xb1fcdcb, 0x2695}}, + /*.y =*/{/*.val =*/{0x5ef705a, 0x30f5007c, 0x13d67318, 0x2f8e63d9, 0x288422de, 0x3224f4b5, 0xa68862b, 0x3a931600, 0xf513}}}, +{/*.x =*/{/*.val =*/{0x36134f96, 0x4096225, 0x2d6b0e9f, 0x846595c, 0x1ff243f5, 0xafa2c4c, 0x3c5bdbef, 0x1639bf08, 0xc62e}}, + /*.y =*/{/*.val =*/{0x114cf97e, 0x89dfb53, 0x3731c3e8, 0x3ee14d58, 0x141fc5bc, 0x359d9d4c, 0x1a1678c3, 0x209f516c, 0x4397}}}, +{/*.x =*/{/*.val =*/{0xb188cbb, 0x1a1be200, 0x7de973, 0x700c802, 0x2622b0b8, 0xcca69c5, 0x5c74168, 0x181483bb, 0x1074}}, + /*.y =*/{/*.val =*/{0x1f272124, 0x75ed8d8, 0x1ce3da60, 0xb835d23, 0x354a1124, 0x9ae6e73, 0x1598c353, 0x35302688, 0xabe5}}}, +{/*.x =*/{/*.val =*/{0x338fd8e8, 0x33b36067, 0x69752ac, 0x2c39137f, 0x2873a8f1, 0x19f383c0, 0x1c34f0, 0x339fd186, 0x6260}}, + /*.y =*/{/*.val =*/{0x32b4ae17, 0x6a13a56, 0x51c198c, 0x34a488e0, 0x2a1ef7ec, 0x24125dd, 0x1b571a7f, 0x2a0adbe9, 0xbc2d}}}, +{/*.x =*/{/*.val =*/{0x3d477c2d, 0x1d99d1bc, 0x2aad27e0, 0x39971465, 0xf1a1316, 0x21026fa1, 0x11a73dec, 0x3691d22b, 0x85d8}}, + /*.y =*/{/*.val =*/{0x7d1dd70, 0x1e605bf, 0x3c4d5a62, 0x2c28080c, 0x2fc7bc94, 0x2d4d94c7, 0x6690586, 0x22d4d997, 0x5894}}}, +{/*.x =*/{/*.val =*/{0x2c0b80d9, 0x2140c4b5, 0x3dc47f04, 0x79f8403, 0x3ee3ee4d, 0x224ba730, 0x4b968c0, 0x1c59b9fb, 0x8e2a}}, + /*.y =*/{/*.val =*/{0x16b29f50, 0x27187cab, 0x306349a4, 0x25eda235, 0x2a9d4852, 0x374a6dc5, 0xbe592ce, 0x2ea6b8b, 0xeadb}}}, +{/*.x =*/{/*.val =*/{0x2c4561be, 0x2487e8f4, 0x359d90f9, 0x12acba04, 0xf8950ee, 0xd9bb35e, 0x3f58edc8, 0x31d610af, 0x769b}}, + /*.y =*/{/*.val =*/{0x30d9685f, 0x16482ffe, 0x37873add, 0x285ddd9e, 0x3f5d4741, 0x33933bdc, 0x383bac8d, 0x5cd8bf9, 0x4bf8}}}, +{/*.x =*/{/*.val =*/{0x2037fa2d, 0x254f3234, 0x1bfdc432, 0xfb23d5d, 0x3f410304, 0xd21052e, 0x1d8d43d8, 0x1f782bf0, 0xe503}}, + /*.y =*/{/*.val =*/{0x1d755bda, 0x3977210, 0x481f10e, 0x17d6c0fb, 0x190bddbd, 0x263427ee, 0xd3b5f9f, 0x14d2eaa5, 0x4571}}}, +{/*.x =*/{/*.val =*/{0x1e3d34ef, 0x318f231e, 0x12a2ddb8, 0x2ac85f1e, 0x161b3ec3, 0x2db3df4b, 0x15494f40, 0x36919ff, 0xa5e0}}, + /*.y =*/{/*.val =*/{0x2f7adb4c, 0x21571738, 0x10900acb, 0x18373f9e, 0x3f43d25b, 0x1c9bfa66, 0x8555421, 0x397d7958, 0x98f}}}, +{/*.x =*/{/*.val =*/{0x17b91252, 0x19cdc583, 0x77572ae, 0x12bf4b91, 0x1bfbc46d, 0x27d2ec72, 0x22b40351, 0x57d7bce, 0xa994}}, + /*.y =*/{/*.val =*/{0xbedc264, 0xe8ddeb1, 0x10f4ddd7, 0x2685ab56, 0x36f6b689, 0xbc43c93, 0x1f84bb9e, 0x39932ba0, 0x82d0}}}, +{/*.x =*/{/*.val =*/{0x2a540f17, 0x231196d9, 0x30c132bd, 0x1d435c17, 0x3935f84c, 0x3b778263, 0x3d1fc7d8, 0x13a7e793, 0xb56f}}, + /*.y =*/{/*.val =*/{0x200102d, 0x1a8bf2b8, 0x3cca8544, 0x350a58f2, 0x182d1d21, 0x3046b7c1, 0xa856d3d, 0x394d0a73, 0x32e8}}}, +{/*.x =*/{/*.val =*/{0x24fce725, 0x1619a82b, 0x2a6c5b72, 0x3a36f471, 0x1771b4e7, 0x2a417a3c, 0x207adf5e, 0x1cac3d28, 0xe063}}, + /*.y =*/{/*.val =*/{0xeee31dd, 0x9c0d3e5, 0x3104870b, 0x12129de1, 0x1a488cd7, 0x9eecab5, 0x18cfe12a, 0x225d2f38, 0x7a90}}}, +{/*.x =*/{/*.val =*/{0x3ed2ff3e, 0x3826bb90, 0x2c6ed3cf, 0x17aff6d3, 0x2d3f3c04, 0x36f4c13e, 0x6b8f9c8, 0x4d32881, 0xeac}}, + /*.y =*/{/*.val =*/{0x3d210988, 0x5c81881, 0x3f21376e, 0x67da5ad, 0x311799ac, 0x3c40efca, 0x19b4245b, 0x36f9e4d, 0x4963}}}, +{/*.x =*/{/*.val =*/{0x1fbfa4dc, 0x1d9c1b93, 0xc85b174, 0x25229e01, 0x1bb41ff5, 0x84675eb, 0x3ea19839, 0x21641cc7, 0xd678}}, + /*.y =*/{/*.val =*/{0x3d3b5406, 0x29ef35ae, 0x1c9a07cc, 0x1bc7137, 0x1c13aa62, 0x3bd71b48, 0x63c4940, 0x2a322754, 0x28ea}}}, +{/*.x =*/{/*.val =*/{0x248ff9b3, 0x9d7ed03, 0x199b01a7, 0x2c698815, 0x371d4bc7, 0x3c843c4a, 0x40974ab, 0x3f32f668, 0x6930}}, + /*.y =*/{/*.val =*/{0xee96a4e, 0x3f76ad7e, 0xacc51ac, 0x3e6c4f9, 0x1f6d7809, 0x3f36e1d, 0x301eada3, 0x2ba52e51, 0x7f02}}}, +{/*.x =*/{/*.val =*/{0x10559754, 0x2b5a423, 0x2a3f5854, 0x2c42f778, 0xce02204, 0x2efe770, 0x1d45358d, 0x1e9c5735, 0x213c}}, + /*.y =*/{/*.val =*/{0x34b458f2, 0x3fcb09d4, 0x36a7eedd, 0x12143d7c, 0x1ba190bb, 0xeb41891, 0x6250701, 0x2b42d6b9, 0x4b6d}}}, +{/*.x =*/{/*.val =*/{0xec87fac, 0x264e2578, 0x22e7cf08, 0x6ae5d18, 0x23480e0d, 0x3a7fb60c, 0x9a7f66a, 0x15204cad, 0x1c5e}}, + /*.y =*/{/*.val =*/{0x1fc2d4ef, 0x1575ecf5, 0x2fe324c5, 0x37ab3ac9, 0xc2ad3a3, 0x2567e875, 0x3468f2bb, 0x3d83e0df, 0x4ffc}}}, +{/*.x =*/{/*.val =*/{0x14531dbc, 0x83f2e87, 0x2d5c970e, 0x2407067f, 0x3bc7ce1f, 0x1ba50842, 0x1668ddef, 0x1b4180b1, 0x4627}}, + /*.y =*/{/*.val =*/{0x1686b8e2, 0x3e1cc026, 0x3e1bc99a, 0x22eb7eff, 0xded9949, 0x248a1d5c, 0x75b84a2, 0x1fc93513, 0xe0f}}}, +{/*.x =*/{/*.val =*/{0x122f001d, 0x453bc4d, 0x78d8996, 0x14382b37, 0x31916368, 0x17ac8470, 0x2c24f4e6, 0x1a3b29e9, 0xefea}}, + /*.y =*/{/*.val =*/{0x33bc4415, 0x4a1067d, 0x3848771c, 0x4e567ec, 0x319a17e4, 0x140c1e8d, 0x3c14da1, 0x11e1a756, 0xaab8}}}, +{/*.x =*/{/*.val =*/{0x8fbd53c, 0x330e8ec, 0x1c62cddf, 0x20e31c2b, 0x19a87e2, 0x2e4d4a95, 0xb34e8db, 0x9ca9ebd, 0x4e7c}}, + /*.y =*/{/*.val =*/{0x17dcaae6, 0x2ce5060, 0x3f7dd33e, 0x2e5852f, 0x2f681b53, 0x3f427db7, 0x10b18e16, 0x271d9b27, 0x1774}}}, +{/*.x =*/{/*.val =*/{0x3c6e1b4d, 0xa0879b9, 0x3ef8790e, 0x47c9686, 0x385d9c9b, 0x289a7d38, 0x2888f268, 0x5ec09a5, 0x8990}}, + /*.y =*/{/*.val =*/{0x1814ab2b, 0x26baf6b, 0x132b2120, 0x3946f03e, 0x358bfae4, 0x15e60cd8, 0x334f0bb4, 0xb36ad6c, 0x43ae}}}, +{/*.x =*/{/*.val =*/{0x3e5f712f, 0x3c98d685, 0x1b583a8a, 0xc7d6fe4, 0x227f0e28, 0x11ca398c, 0x5fd4a8f, 0x113ddba4, 0x67f6}}, + /*.y =*/{/*.val =*/{0x307160e5, 0x1a2b2d79, 0x3d36198d, 0x385223d, 0x6cf785e, 0x2b7aded6, 0x5d04f05, 0x35a3d991, 0xb833}}}, +{/*.x =*/{/*.val =*/{0x3b89a762, 0x4098fb4, 0x2ee6b8dc, 0x3724c04, 0xb471293, 0x281525a, 0x12555fa8, 0x21db24d9, 0x327f}}, + /*.y =*/{/*.val =*/{0x39203301, 0x327f6566, 0x2bd7dfe9, 0x14d41c3f, 0x1997b975, 0x25a49578, 0x24026b09, 0x13aacd4, 0xb2d4}}}, +{/*.x =*/{/*.val =*/{0xfb27b6, 0x909f8a1, 0x24305763, 0x1b8f6caf, 0x286aa5c7, 0x8e2b585, 0x38b1b10f, 0x138f6f9d, 0xfea7}}, + /*.y =*/{/*.val =*/{0x323cb96f, 0x74f6df, 0x33f7b777, 0x1ad65ae5, 0x36af9312, 0x19d37b32, 0x313297cf, 0x1a36e6c2, 0x6e05}}}, +{/*.x =*/{/*.val =*/{0x1f9756e4, 0x3f65f258, 0x23730488, 0x15c3b977, 0x28cd0ebb, 0x380f6143, 0x280ff180, 0x10720c10, 0xed94}}, + /*.y =*/{/*.val =*/{0x3f3abfae, 0x3c3827e4, 0x24de98bf, 0x3c8ddd3f, 0x13911e09, 0x5d84a2c, 0x3fa19afa, 0x27a7bfa2, 0x3dbe}}}, +{/*.x =*/{/*.val =*/{0x151cf119, 0x16eb40cf, 0x3ab4d301, 0x42f7613, 0x3487515b, 0x3b4fd892, 0x27c3fc9f, 0x1a63b99e, 0x29d9}}, + /*.y =*/{/*.val =*/{0x35056339, 0x3221d015, 0x3a7c2963, 0x272503a4, 0x31c96fb8, 0x28495013, 0x2b45277, 0xb145f72, 0x7fd0}}}, +{/*.x =*/{/*.val =*/{0x3f422491, 0x19f1114d, 0x2060cff4, 0x114f92a1, 0x180a31fd, 0x3edef4cd, 0x3936d6f3, 0x15f41404, 0x126b}}, + /*.y =*/{/*.val =*/{0x1da3ef84, 0x3e8c7c66, 0x3f39347a, 0x122eb0c2, 0x3f3fb0e1, 0x128fae8a, 0x262c2e3c, 0x3704c185, 0xc1a7}}}, +{/*.x =*/{/*.val =*/{0x17bdde39, 0xb00a910, 0x36043295, 0x11385e6d, 0x1968d315, 0x95c3566, 0x3cf0e10a, 0x1044fd9d, 0x76e6}}, + /*.y =*/{/*.val =*/{0x1901ac01, 0x12c5d4b4, 0x16d2032b, 0xa8cf4ad, 0x1f0d35e, 0x19b5c1a, 0x295cf577, 0x37e37b93, 0xc90d}}}, +{/*.x =*/{/*.val =*/{0x3a1187a5, 0x33e666a0, 0x29ae691, 0x1755d88b, 0x21c81000, 0x1f276205, 0x2c73bee8, 0x14c3a794, 0x708a}}, + /*.y =*/{/*.val =*/{0x73db9c0, 0x2293c66d, 0x1353e8a5, 0x3369cf1b, 0x2d38283e, 0x195b72ed, 0x1a897fa9, 0x1204787e, 0x9b88}}}, +{/*.x =*/{/*.val =*/{0xde4f5be, 0x386c5b1b, 0x2b2b59e2, 0xdd2db61, 0x2462cf9f, 0x35920e57, 0x33be219b, 0xd3f122, 0x19cf}}, + /*.y =*/{/*.val =*/{0x2f321af2, 0x2a454cad, 0x30f1c0c0, 0x2474724f, 0x181947ef, 0x12f9a2ac, 0x2b466c3b, 0xac1a856, 0x28e3}}}, +{/*.x =*/{/*.val =*/{0x117cf3e8, 0xeaf0827, 0x3ea2219e, 0x24ef40d2, 0x17f576ee, 0x670be0e, 0x35f0d7c7, 0x11281e32, 0xaf6c}}, + /*.y =*/{/*.val =*/{0x1751baea, 0x22b74180, 0xa0d435b, 0xd8aba9f, 0x3246dfec, 0x39cc54f2, 0x14b30af9, 0x25bfa17, 0x784}}}, +{/*.x =*/{/*.val =*/{0x2bcbb891, 0x2ac54090, 0x326cbee3, 0x1f3190f7, 0x3f8f9a8f, 0x206ea9d0, 0x2abe1e82, 0x315ac0ec, 0xc738}}, + /*.y =*/{/*.val =*/{0x299a84c3, 0x1f9cd765, 0x80cfe91, 0xc53bbde, 0x3fbbbb82, 0x63cbab2, 0x2d2537f7, 0x2d5e2546, 0x893f}}}, +{/*.x =*/{/*.val =*/{0x662ab1b, 0x36aac1e1, 0x1b8c9e4d, 0x1c65fa92, 0x27aa9464, 0xca9a64b, 0x37435b, 0x2117b35f, 0x5578}}, + /*.y =*/{/*.val =*/{0x56f3511, 0x5b463cc, 0x25d64de3, 0x14e9dd1a, 0x2a4053f6, 0x1b429474, 0x1e2c3cea, 0x1e5e2db, 0xe61d}}}, +{/*.x =*/{/*.val =*/{0x148b6c29, 0x13e1a6e2, 0xe399609, 0x3c48d53f, 0xceccd22, 0x3e8ef074, 0x364cc4ab, 0xe0e2228, 0x47f3}}, + /*.y =*/{/*.val =*/{0xe537ef9, 0x3b7b8448, 0xf994a81, 0x2ed26562, 0x16c7118, 0x39219d6d, 0x32937190, 0x26a343c0, 0x48ca}}}, +{/*.x =*/{/*.val =*/{0x5ff4adb, 0x2069b23c, 0xbef768a, 0x3d5c35bf, 0x25d5f614, 0x1ad3271a, 0x1b8cfe46, 0x7cd2b90, 0xc0c0}}, + /*.y =*/{/*.val =*/{0x2c351065, 0x313bfdce, 0xd15b85f, 0x2f10f45c, 0x35b8cecd, 0xde82d01, 0x17f5c7c9, 0x3d6fb90d, 0xb84}}}, +{/*.x =*/{/*.val =*/{0x8f6c14b, 0x1cba7d96, 0x29250143, 0x35cb97ce, 0x172877d1, 0x131d8df2, 0x25b81e26, 0x1899522d, 0xd895}}, + /*.y =*/{/*.val =*/{0x1d7d991f, 0x24d8fb5d, 0x3b067e17, 0x10a358ca, 0x340eb03, 0x3b182063, 0x7eae728, 0x2a8e3caf, 0xfebf}}}, +{/*.x =*/{/*.val =*/{0x37078424, 0x296d652d, 0x2c40c3fb, 0x3b2bde83, 0x3a26703, 0x290d8880, 0x1044e8a3, 0x1bbbe25c, 0xfd13}}, + /*.y =*/{/*.val =*/{0x671ddf1, 0x3587bbbf, 0x22adfa8c, 0x3cac7de2, 0x5efa57c, 0x74646d7, 0x252cc67a, 0x2a0d3cf1, 0x218d}}}, +{/*.x =*/{/*.val =*/{0xdb1cb3c, 0x3c7613b2, 0x3f024a5, 0x1c00e835, 0x119f861b, 0x33294d9d, 0x38d140e9, 0x23a77658, 0xd99e}}, + /*.y =*/{/*.val =*/{0x2b8637a7, 0x2228a78d, 0x3c8765cd, 0x21bfbe3f, 0xeba6e62, 0x16ecc86f, 0xa3a7a94, 0x66b4730, 0x36dc}}}, +{/*.x =*/{/*.val =*/{0x3c385172, 0x351bda34, 0x40e636f, 0xcd4781, 0x309191d2, 0x36295396, 0x18317a1b, 0x3c586686, 0x3fd}}, + /*.y =*/{/*.val =*/{0x3ccb9794, 0x26b19fc3, 0xe7232b7, 0x26e4a7a4, 0x573755b, 0x1c31f4f2, 0x12c3fe4, 0xb01b97, 0x408d}}}, +{/*.x =*/{/*.val =*/{0xf676e03, 0x24542959, 0x3e84edd4, 0x3ff1cda4, 0x1e8761ce, 0x3d90cd5c, 0x17518eb0, 0x2500caa5, 0xb8da}}, + /*.y =*/{/*.val =*/{0xefdf6e7, 0x1223939d, 0x1ff3b511, 0x33161365, 0x2808b092, 0x267325d8, 0x1a1e4d7c, 0x37e91201, 0x2804}}}, +{/*.x =*/{/*.val =*/{0x5af726a, 0x104fd053, 0x25bf6e6d, 0x268f972c, 0x3620f946, 0xb2da62a, 0xc5ce53f, 0x34417b63, 0x6d36}}, + /*.y =*/{/*.val =*/{0x13f9fc7d, 0x15c12468, 0x108a35c, 0x31664dad, 0x50029dc, 0x2319b257, 0x3669e72d, 0x170d38dd, 0xe4ba}}}, +{/*.x =*/{/*.val =*/{0x2540db99, 0x1b8a8c32, 0x34b81228, 0x4c27014, 0x30b0e3eb, 0x220fe99b, 0x3ac0cd06, 0x2f784334, 0x3ab6}}, + /*.y =*/{/*.val =*/{0x1bda78a3, 0x1a1cff8c, 0x369c043e, 0x344dec38, 0x13e99c38, 0x45ea5a8, 0x71d7fc3, 0x1881e6fa, 0xbaca}}}, +{/*.x =*/{/*.val =*/{0x1f1048da, 0x1ddefc9e, 0x3ddd3ba7, 0xbf53cdc, 0x7bce2ba, 0x281a7674, 0x156f0fdb, 0xd38fc6b, 0x7966}}, + /*.y =*/{/*.val =*/{0x2106cf01, 0x23e6f892, 0x3d74862e, 0x95db633, 0x3927f253, 0x39d1cd69, 0x20b8956d, 0x38adb3ec, 0x4d8e}}}, +{/*.x =*/{/*.val =*/{0x23c0df5d, 0x6845de3, 0x156a792f, 0x67bfed4, 0x1d7fab20, 0x2b6ae51d, 0x3b33a7d8, 0x3a851107, 0xe80f}}, + /*.y =*/{/*.val =*/{0x2ac9ec78, 0x32d0a46d, 0x3322ea9f, 0x557a02b, 0xa94472d, 0x25da328f, 0x200771e8, 0x379fd8e3, 0xeed1}}}, +{/*.x =*/{/*.val =*/{0xf83cd58, 0x36c39e2c, 0x3d2f9162, 0xb730e1d, 0x3e7a3712, 0x2b13b47b, 0x1265981, 0x287c23a9, 0x440c}}, + /*.y =*/{/*.val =*/{0x388a3f4b, 0x1ef01a6, 0x1c0a260b, 0x793509a, 0xe2f02a2, 0x25537275, 0x2e122af8, 0x2c34b357, 0xa6c8}}}, +{/*.x =*/{/*.val =*/{0x12998b10, 0x206f689c, 0x1b229d9e, 0x31c3af30, 0x2907819b, 0x1fe0a74e, 0x26c1cc5f, 0x32ebcae5, 0xf694}}, + /*.y =*/{/*.val =*/{0xf05e51, 0x19e22c5c, 0x3c2a47f, 0x1b1930c6, 0x6d82aeb, 0x317feb31, 0x2f03d633, 0xfae986f, 0x40a6}}}, +{/*.x =*/{/*.val =*/{0xdd553fd, 0x25684cd6, 0x8b6414f, 0x2afda570, 0x22595047, 0x1b53d0e6, 0x2684850b, 0x218a8d55, 0x8b6e}}, + /*.y =*/{/*.val =*/{0x3e9be5ed, 0x200f6b4c, 0x3383d0d, 0x2b0f1686, 0x2b9fa124, 0x2f0b7d3, 0x11cb40d1, 0x22443b4, 0xea5e}}}, +{/*.x =*/{/*.val =*/{0x4e16070, 0x3701eef3, 0x2fd6915d, 0x286080c7, 0x167543f2, 0x29239475, 0x1704313b, 0x1a5ef7f3, 0xa301}}, + /*.y =*/{/*.val =*/{0x1e177ea1, 0x30346810, 0xa11a130, 0xd76fdf0, 0x140f9b17, 0x2027e897, 0x3e4f5081, 0x3e473ed9, 0x7370}}}, +{/*.x =*/{/*.val =*/{0x324ba5ae, 0x5080c5b, 0x34b5d81, 0xe594013, 0xbff74b4, 0x23490678, 0x1f049f3e, 0x39673fde, 0x27e1}}, + /*.y =*/{/*.val =*/{0x83a45b3, 0x1296ffba, 0x2fa63f78, 0x122869a6, 0x39df05df, 0x2d78f3f1, 0xe209ee1, 0x9a9b201, 0x310b}}}, +{/*.x =*/{/*.val =*/{0x1caed7ae, 0x25a45d72, 0xfbfb4f9, 0xe6b77a1, 0x2d7e4f5a, 0x223b0e24, 0x24aee165, 0x39e97da1, 0xc712}}, + /*.y =*/{/*.val =*/{0x6156294, 0x134522a9, 0x30ce6378, 0x3639512, 0x1dd9e538, 0x352e08c4, 0x363b365e, 0x1041d458, 0x4964}}}, +{/*.x =*/{/*.val =*/{0x4a6db03, 0x2d0f87f9, 0x275d791, 0x32175bd6, 0x675fcb2, 0x303509ae, 0x3235d065, 0x141292c, 0xbfc}}, + /*.y =*/{/*.val =*/{0x64b8542, 0x22b23469, 0x5d4f055, 0x109c65cd, 0x26c99237, 0x23b1fe52, 0xf3453fb, 0x119e9b0d, 0x1955}}}, +{/*.x =*/{/*.val =*/{0x3fb04ed4, 0x2deb18f8, 0x1307fffa, 0x330cc2c4, 0x278de208, 0x3e741449, 0x2b936463, 0x216ce275, 0x90ad}}, + /*.y =*/{/*.val =*/{0xb6ef150, 0x24753523, 0x182894d9, 0x2bbeaf85, 0x3222b839, 0x372f6509, 0x38261aff, 0x1e8d8828, 0xe50}}}, +{/*.x =*/{/*.val =*/{0x27dc0151, 0x2062c3b6, 0x2707bad2, 0x496f991, 0x25e3d7e, 0x2c745521, 0x14077f44, 0x3503be32, 0x7e2c}}, + /*.y =*/{/*.val =*/{0x20721ec7, 0x28ef14e4, 0x2ee082c9, 0x26fb902b, 0x1ef95d88, 0x186a2cc8, 0xfab382a, 0x1d420ab7, 0x905b}}}, +{/*.x =*/{/*.val =*/{0x1345e597, 0x3840eb90, 0x3853cf90, 0x18dafe76, 0x2f52a79c, 0x25d6ef47, 0x2dace21c, 0x3d48656f, 0xa146}}, + /*.y =*/{/*.val =*/{0x345a770a, 0x19d59dab, 0x1f094b07, 0x19e96c88, 0x331b40ea, 0x25774b6e, 0x3feb09ae, 0x26c2ac14, 0xa5a9}}}, +{/*.x =*/{/*.val =*/{0xce45444, 0x32ed4ff1, 0x2ccc4e20, 0x379087bf, 0x1a8114db, 0x2fe76ac9, 0x193b9bcf, 0x1d6873c6, 0xd24c}}, + /*.y =*/{/*.val =*/{0x7dd4a57, 0x2e4c91a6, 0x1f1e524c, 0x1d64fd26, 0x25a78abf, 0x2df46043, 0x1c1d1cfc, 0x74b7a13, 0x58fe}}}, +{/*.x =*/{/*.val =*/{0x1ec4c0da, 0x2ded1132, 0x23ea3351, 0x23159e1c, 0x1f162ee8, 0x2706b660, 0x35f33923, 0x2e74bd8e, 0x8f68}}, + /*.y =*/{/*.val =*/{0x101fff82, 0x8f2fde5, 0x1510bfdf, 0x3a8b3fa5, 0x3e215dbb, 0x36430ada, 0x23986de1, 0x27cb6e81, 0x662a}}}, +{/*.x =*/{/*.val =*/{0xcf27076, 0x1a11f7e1, 0x3627eaee, 0x26162b79, 0x19af59d8, 0x3faf9dff, 0x28158fca, 0x2bbf5e13, 0x4d49}}, + /*.y =*/{/*.val =*/{0x3aa781e, 0x2e42d988, 0x1f4d8466, 0x3cb469f, 0x1ca6f06e, 0xfc840d6, 0x1d135e72, 0x3f166843, 0xcd32}}}, +{/*.x =*/{/*.val =*/{0x29b62026, 0x236f2d5c, 0x9d1d4ee, 0xa8f7822, 0x1c5aa78d, 0x1986787d, 0x16f8537d, 0x14e7a175, 0x7564}}, + /*.y =*/{/*.val =*/{0x1ace0cf3, 0x5cb23eb, 0xb79f334, 0x12ab3655, 0x32292568, 0x77d4929, 0x1b3c6523, 0x21504dd2, 0xc1d6}}}, +{/*.x =*/{/*.val =*/{0x17b4a278, 0xd936b35, 0x3f4082b5, 0x3d8697c7, 0x19ccc878, 0x1bfcc06b, 0x32779674, 0x245eb677, 0x210a}}, + /*.y =*/{/*.val =*/{0xc7b2231, 0x3c9c4ff4, 0x3f20bfc7, 0x227986ab, 0x16737d37, 0x26fa07e3, 0x1e57b7a3, 0x6d5142d, 0x670e}}}, +{/*.x =*/{/*.val =*/{0x13231e11, 0x1a1bf541, 0x3681e3e6, 0x123a1940, 0xc36091f, 0x267fe466, 0x385d65ff, 0x3ec05dab, 0xe4f3}}, + /*.y =*/{/*.val =*/{0x2feb73bc, 0x8b0e15d, 0x151d1c98, 0x31f9d3b2, 0x2b7286c, 0x69b43a8, 0x34f1c166, 0x18ceb43b, 0x1e63}}}, +{/*.x =*/{/*.val =*/{0x3bcdaf2f, 0x2ffb888c, 0x3a172953, 0x14c6a096, 0x1b362f88, 0x190442af, 0x373e01ec, 0x32edda19, 0x4b30}}, + /*.y =*/{/*.val =*/{0x3d26b5b7, 0x200cf518, 0x3485756, 0x37cf2079, 0x3c4a91f, 0x38b15ddf, 0x3629b6f9, 0xd40996e, 0x74c6}}}, +{/*.x =*/{/*.val =*/{0x2673059f, 0x3ffa70a6, 0xe0fa192, 0x45c5414, 0x64817ec, 0x16c82c5d, 0x1700dcd1, 0xd2a9eb8, 0xcbb4}}, + /*.y =*/{/*.val =*/{0x227c070c, 0x1f6a5908, 0x2d5f845b, 0x351793c2, 0x35dfad41, 0x35248ce2, 0x2bd17562, 0x802ad36, 0x4a1a}}}, +{/*.x =*/{/*.val =*/{0x6de12c0, 0x351e1b84, 0x34610e94, 0x2736b161, 0x17244c6d, 0x35ec79d5, 0x2c1cd06, 0x15b6704, 0xf478}}, + /*.y =*/{/*.val =*/{0xa5361fe, 0x269db39b, 0x1ab92d76, 0x305fbd82, 0x28694c26, 0x2578041, 0x23946e68, 0x39843ccf, 0x7f09}}}, +{/*.x =*/{/*.val =*/{0x20eae29e, 0x1bedbab8, 0x14e1d071, 0xd3cbc3, 0x1a4266c7, 0x1854de91, 0x3f331eb9, 0x3ea6c63a, 0x8c00}}, + /*.y =*/{/*.val =*/{0x2702414b, 0x1f4a9319, 0x1e36c54e, 0x3eb6bea0, 0x36c974c2, 0x30d0e8dc, 0x121a1a9d, 0x1c99ffa9, 0xefa4}}}, +{/*.x =*/{/*.val =*/{0x18ada5f, 0x21326ac3, 0x1122fb3e, 0x1f8a5fca, 0x2be1effd, 0x2d6fe58d, 0x2b46fa8b, 0x3005db68, 0x24cf}}, + /*.y =*/{/*.val =*/{0x178a586b, 0x23e984e6, 0xf814f26, 0x25672869, 0x2da927ed, 0x21c53577, 0x61a6986, 0x23eec1e7, 0xebff}}}, +{/*.x =*/{/*.val =*/{0x14679da2, 0x40c6256, 0x3f057edf, 0x37759ff1, 0x292ec616, 0x37b5ca84, 0x1bc82ea2, 0x1f56352e, 0x4a}}, + /*.y =*/{/*.val =*/{0x379ffe26, 0x21dfd211, 0x23fa28a4, 0x30ed2525, 0x71b3b71, 0x76051fb, 0x2cb75e6b, 0x316dd9c0, 0xb98a}}}, +{/*.x =*/{/*.val =*/{0x87c4b65, 0x33cd3ab7, 0x207b2a9c, 0x3e202287, 0x26ce4996, 0x1b178b01, 0x1c7fc7, 0x1a7132f4, 0xee7d}}, + /*.y =*/{/*.val =*/{0x1136a95a, 0xfa3d13b, 0x2e942e52, 0xfa2666e, 0xf2ee2c3, 0x24aafc0c, 0x13821a1, 0x189bb069, 0xecc8}}}, +{/*.x =*/{/*.val =*/{0x20cb3e41, 0x25ff77f1, 0x8b92c09, 0xf4213cc, 0x298ed314, 0x33b02a7, 0x829f3e1, 0x1b39a775, 0xe7a2}}, + /*.y =*/{/*.val =*/{0xf2cfd51, 0x3a2a5087, 0x20e83e20, 0x29acb010, 0x2fbb18d0, 0x2c01a86a, 0x3984b471, 0x238c03e9, 0x2a75}}}, +{/*.x =*/{/*.val =*/{0x3b4ae861, 0x25f96e45, 0x2e32fa9d, 0xf0d7935, 0x2089f520, 0x22fed9dc, 0x3f8d00d3, 0x3eae80da, 0xf5ca}}, + /*.y =*/{/*.val =*/{0xd82239c, 0x32708e70, 0x12f05f3c, 0xecaa715, 0x839159b, 0x3e641190, 0x26d817bf, 0xee2808a, 0x19e8}}}, +{/*.x =*/{/*.val =*/{0x3d2a9651, 0x13f5335e, 0x14c98208, 0x27942712, 0x2805428f, 0x3d455b5f, 0x23f1f12d, 0x240933ad, 0xe938}}, + /*.y =*/{/*.val =*/{0x1e786824, 0x3bf78add, 0x2770bfef, 0x1c4433b1, 0x31aaf18d, 0x21eaebd9, 0x26595f92, 0x1a21c8dc, 0x8648}}}, +{/*.x =*/{/*.val =*/{0x3cddab8b, 0x3cb506b9, 0x3c68e6fc, 0x3934494, 0x2d0c379f, 0x5a40360, 0x1256bed1, 0x16761e0a, 0x2645}}, + /*.y =*/{/*.val =*/{0x1de473, 0x27d92d14, 0x1caf1e6c, 0x218c6bce, 0x72d77a, 0x2f18dc0d, 0x3512cef7, 0x2f4649b4, 0x79e5}}}, +{/*.x =*/{/*.val =*/{0x1e6b80ef, 0x33ca7acf, 0x179424f3, 0x32f2e59f, 0x3cbdc571, 0x1503088e, 0x22ec8d23, 0x2783b8d9, 0xb645}}, + /*.y =*/{/*.val =*/{0x1a71ba45, 0xc2fc2d8, 0xe35b2ff, 0x2ceb9b52, 0x261db3c4, 0x2b7c5b95, 0x3e06de1d, 0x21db41bc, 0x67c}}}, +{/*.x =*/{/*.val =*/{0x33eb51f, 0x14fbcdd4, 0x279c2112, 0x22415daf, 0x341593b6, 0xdbdcc07, 0x23c88e4d, 0x3a3c3660, 0xe5d8}}, + /*.y =*/{/*.val =*/{0x1a62a2d9, 0x2756f659, 0x1f0f5497, 0x27711b6, 0x3eeef0e5, 0x5a95f63, 0x23e04abb, 0x3a6de187, 0x4dc1}}}, +{/*.x =*/{/*.val =*/{0xf155e64, 0x1e99d920, 0xa301173, 0x19af93ea, 0x3ae0ddab, 0x2c3dcc86, 0x8c3dc56, 0x9fddf6f, 0xa9ca}}, + /*.y =*/{/*.val =*/{0x161b3297, 0x3cfcccf1, 0x3caf0ae1, 0x17506086, 0x2d00487, 0x1f4891b0, 0x314d4d19, 0xcd59e3e, 0xf4bb}}}, +{/*.x =*/{/*.val =*/{0x16ee247c, 0x352f18a7, 0x351cee06, 0x11e3a11f, 0xfe7591f, 0x28415847, 0x2d7f25eb, 0x1c6001a1, 0x68fb}}, + /*.y =*/{/*.val =*/{0x1a01865d, 0x387e08b4, 0xc73c9da, 0x235602c1, 0x1b0c079a, 0xd509d40, 0x19636737, 0x348d18b7, 0xcd12}}}, +{/*.x =*/{/*.val =*/{0x96943e8, 0x3b683d6d, 0x273c5a5d, 0x1bc7f19f, 0xf06231d, 0x8d2a846, 0x3b840793, 0x20320a02, 0xd68a}}, + /*.y =*/{/*.val =*/{0x2b133120, 0x25321099, 0x45295a2, 0x39ee3de, 0x30e28b5b, 0x2c7e45de, 0x186d00c4, 0x2a7ffd2d, 0xdb8b}}}, +{/*.x =*/{/*.val =*/{0x2412b6fd, 0x2f6888b2, 0x3702b828, 0x3b414f1b, 0x12373cac, 0x3e3becdd, 0x240be402, 0x102719de, 0xf16a}}, + /*.y =*/{/*.val =*/{0x2ca052da, 0x1a36b9df, 0x9ebca42, 0x15019649, 0x230e4e16, 0x1a9d69d3, 0x32799d7a, 0xc45c514, 0x2a41}}}, +{/*.x =*/{/*.val =*/{0x326dd4e4, 0x30682db8, 0x3ed98325, 0x27d3cbda, 0x36f84db8, 0xdfda665, 0x26f42fbe, 0x2d41aadd, 0x4154}}, + /*.y =*/{/*.val =*/{0x75ded1c, 0x32164a54, 0x1e22dd46, 0x13aa7674, 0x25ff641, 0x1b913584, 0x1988894c, 0x1d410f1, 0x23ad}}}, +{/*.x =*/{/*.val =*/{0x3f7f0246, 0x31469e98, 0x727ddf4, 0x3a1b927f, 0x1956ea93, 0x2a35342d, 0x95c1080, 0x1949da73, 0xb73c}}, + /*.y =*/{/*.val =*/{0x2a2a407b, 0x25f94593, 0x2e554e55, 0x35cb931, 0x36c1ea1a, 0xd624f16, 0xca9d4b5, 0x36c41c5d, 0x9a67}}}, +{/*.x =*/{/*.val =*/{0x28d3d5d, 0x256603f, 0x3449cea4, 0x4abae5c, 0x3a30b096, 0x3009c241, 0x804252d, 0x3b5f7d97, 0x324a}}, + /*.y =*/{/*.val =*/{0x16ab7c84, 0x19c892be, 0x23328439, 0x84ec31f, 0x2c1f4f19, 0x3030d6b, 0x21f2ff13, 0xd95dd2d, 0x648a}}}, +{/*.x =*/{/*.val =*/{0x32919749, 0x23ce0e06, 0x1e0db1fa, 0xacf92a3, 0xd7203f7, 0xc9a0620, 0x3490228d, 0xcc7a89b, 0x32c9}}, + /*.y =*/{/*.val =*/{0x3290b5e3, 0xc7a5ec3, 0x239ab096, 0x2292af6b, 0x33dbb826, 0x28bc0adb, 0x9cb5695, 0x9cacd08, 0xd7cd}}}, +{/*.x =*/{/*.val =*/{0x3b9795e4, 0x38708949, 0x1846b8e1, 0x30586db8, 0x2c6b1c69, 0xbda9c3f, 0x37854a0, 0xbcecee6, 0xeb29}}, + /*.y =*/{/*.val =*/{0x2e53a0fe, 0x2dfa74be, 0x1111c6f5, 0x4c75d42, 0x5835b57, 0x198d2bc5, 0x2be80169, 0x3096a5bb, 0x8c43}}}, +{/*.x =*/{/*.val =*/{0x9303fdd, 0x3a8e755e, 0x1d1ed35a, 0x1c515fc6, 0x9fbe14d, 0x350c401, 0x35ef2e62, 0xe8077ce, 0xa65a}}, + /*.y =*/{/*.val =*/{0x2e68703, 0x2b512a34, 0x3aed3cad, 0x21874093, 0x2d2c7686, 0x10f63643, 0x35c6fb8f, 0x2825033f, 0x798e}}}, +{/*.x =*/{/*.val =*/{0x3d054c96, 0x3a2f4dcf, 0xd1ca888, 0x31050eea, 0x3ee5dcee, 0x77f6f97, 0x1e61f6d5, 0x30524673, 0x4df9}}, + /*.y =*/{/*.val =*/{0xad10d5d, 0xbaeb01b, 0x28849019, 0x3541b370, 0x1d85d4b5, 0x25d308e8, 0x18728050, 0x3b14424b, 0x35}}}, +{/*.x =*/{/*.val =*/{0x1da49e04, 0x31ac3f0, 0x17a8d70c, 0x37915539, 0x387088e9, 0xc5f5392, 0x998cd25, 0x32b634b3, 0xed32}}, + /*.y =*/{/*.val =*/{0x3c1db9e0, 0x18c48345, 0x9fab7db, 0x36a7eb2d, 0x19d20b52, 0x728dd61, 0x30204a54, 0x3bd7c740, 0x129f}}}, +{/*.x =*/{/*.val =*/{0x2883f855, 0x2dd06353, 0x3c34016c, 0x30db72d8, 0x30366e28, 0x27904471, 0x360f1804, 0x2adc9358, 0xe821}}, + /*.y =*/{/*.val =*/{0x19852ddf, 0x353831a9, 0xec23efe, 0xec67185, 0x16cf598b, 0x3504550, 0x13ce367d, 0x32fe18fd, 0xadef}}}, +{/*.x =*/{/*.val =*/{0x3441742e, 0x2ffd67ba, 0x33806e9f, 0x52951eb, 0x1693a72f, 0x1514bef2, 0x2d212f45, 0x22653946, 0x3f0d}}, + /*.y =*/{/*.val =*/{0xfecadbe, 0x3194d8ef, 0x2d13d958, 0x8178b0e, 0x3a6e0b1e, 0x172c3a11, 0x3dc445e, 0x1b08fca3, 0xfbd7}}}, +{/*.x =*/{/*.val =*/{0x2c1f98cd, 0x2ff26722, 0x17f0308c, 0xd224153, 0x6602152, 0x362a7073, 0x34870fae, 0x66a1291, 0x9c39}}, + /*.y =*/{/*.val =*/{0x14fc599d, 0x39f9780f, 0x64c8e6b, 0x14c9bddb, 0x20e64190, 0x3c112fc9, 0x1dd57584, 0x13c3d293, 0xddb8}}}, +{/*.x =*/{/*.val =*/{0x294a09ec, 0xd7beded, 0x28535f04, 0x34c9a94f, 0x92aa40c, 0xbf1a757, 0x1d80f0a4, 0x14c9895, 0x2e3c}}, + /*.y =*/{/*.val =*/{0x8c7327e, 0x14d21a06, 0x7b66512, 0x12294f1c, 0x2fc1abe0, 0x2b8902e0, 0x6fb5bdd, 0x3e24595b, 0x1f}}}, +{/*.x =*/{/*.val =*/{0x2b9c7ce6, 0x17c668a, 0x19089342, 0x1c40c5a8, 0x24dda433, 0x17edf8f8, 0x1587ae1, 0x289333e9, 0xe8e2}}, + /*.y =*/{/*.val =*/{0x836267c, 0xb007ada, 0x1c27a73b, 0x27980ed, 0x2e20596e, 0x3cacacef, 0x35d1b4ca, 0x20f3831b, 0x46c9}}}, +{/*.x =*/{/*.val =*/{0xac7b3c2, 0x2c34e59a, 0x3d5b5f5, 0x2b2be48e, 0x32a212, 0x28e2c5c, 0x173c2b2f, 0x26ab1761, 0xa754}}, + /*.y =*/{/*.val =*/{0x1287eaef, 0x283245c6, 0x37116dff, 0x1ad44554, 0x147d2b5d, 0x2875c306, 0x2415335, 0x346e4347, 0xbd17}}}, +{/*.x =*/{/*.val =*/{0x20a959e5, 0x2884e084, 0x391d4cc5, 0x38524ea2, 0xe06bb91, 0x17ca076, 0x12fdf8de, 0x5c2c774, 0x6057}}, + /*.y =*/{/*.val =*/{0x2385a2a8, 0x2266fa4c, 0x2e24c65e, 0x1454af0f, 0x1df26246, 0x268b6bdc, 0x24807add, 0x3c2c9a9a, 0x9a1a}}}, +{/*.x =*/{/*.val =*/{0x2fd545c, 0x22672976, 0xa28e661, 0x4cfe375, 0x1c85df7c, 0x1044291b, 0x2e064039, 0x3f59df14, 0x6773}}, + /*.y =*/{/*.val =*/{0x147eb1ae, 0x231fc0d2, 0x1c6cf98e, 0x35e03d68, 0x2b246bea, 0x3c972774, 0x3652f0f0, 0x2db63365, 0x444e}}}, +{/*.x =*/{/*.val =*/{0xb86f021, 0x1cf185ac, 0x4680503, 0x1d390e04, 0xc87c203, 0x31e6ab38, 0xe565237, 0x1b65345f, 0xe0f8}}, + /*.y =*/{/*.val =*/{0x35bf325a, 0x2dade732, 0x15fc45b3, 0x202f3004, 0x89a2c9a, 0x7a0cbc7, 0x2bcf47a9, 0x71cdcc2, 0xc57}}}, +{/*.x =*/{/*.val =*/{0x2da6e03, 0x2b41dcb0, 0xcad6038, 0x9df7e42, 0x296f4f4c, 0x247864f5, 0x5041ce9, 0x56ae7c9, 0x42ca}}, + /*.y =*/{/*.val =*/{0xc347793, 0xda227ea, 0x106bea78, 0x1ba169a0, 0x3800eed6, 0x339347f2, 0x57c9647, 0x3bc9b207, 0x68d2}}}, +{/*.x =*/{/*.val =*/{0x2cb94266, 0x69a5cfb, 0x3d4df12b, 0x33bc3ee9, 0xda31880, 0x10e69146, 0x8411421, 0x37e388e8, 0xa576}}, + /*.y =*/{/*.val =*/{0x21b28ec8, 0x3a2f846b, 0x114d9f3e, 0xb8429fd, 0xcd82c43, 0x2e5ebf96, 0x240b2c92, 0x2fc839d9, 0x40a6}}}, +{/*.x =*/{/*.val =*/{0x1a704896, 0x3b15c96f, 0x1acfb8dc, 0xee818f2, 0x271bae6f, 0x148219ef, 0x35a3b546, 0x3318bbce, 0x9e5d}}, + /*.y =*/{/*.val =*/{0xa82c835, 0x23c9da77, 0x30f5124, 0x18174618, 0x7612279, 0x34e88553, 0x25f3ea5f, 0x344b76e4, 0x6fed}}}, +{/*.x =*/{/*.val =*/{0x4bf7ea0, 0x14fb561d, 0xef58339, 0xd896817, 0x303b20e3, 0x1ba7e5db, 0x345adf8d, 0x20dd6e1, 0xa7de}}, + /*.y =*/{/*.val =*/{0x1bbcabaa, 0x130154e, 0x2bc5aa2e, 0x1691f03f, 0x88e9a64, 0x1282ccd2, 0x1a5e5210, 0x25ac15eb, 0xa63d}}}, +{/*.x =*/{/*.val =*/{0xad916fb, 0x27e3e841, 0x149e4a3a, 0x20197f7a, 0xff4cbe6, 0x30d6b007, 0x80c9c13, 0x19639a24, 0xc266}}, + /*.y =*/{/*.val =*/{0x20887814, 0x1abbd4ae, 0x36113885, 0x23fb37fa, 0x627ab6b, 0x2605c2c9, 0x3daab0f7, 0x164e1539, 0xe7e8}}}, +{/*.x =*/{/*.val =*/{0x3e58ad71, 0x3dd8e226, 0x39a3a208, 0xc347d73, 0x1e8c38bb, 0x17fa58a7, 0x2c3e30a0, 0x29e30a37, 0x7778}}, + /*.y =*/{/*.val =*/{0x3d9f43ac, 0x2d44ff07, 0x324ac563, 0x2ce1047f, 0x3f580087, 0x26384bcb, 0x1b22ff70, 0x1b66ad69, 0x3462}}}, +{/*.x =*/{/*.val =*/{0x1073e879, 0x1fa87094, 0x104eea7a, 0x3c5a96b8, 0xfe3932c, 0x3d20b5fc, 0x6d1632, 0x1e5ad728, 0xe7b9}}, + /*.y =*/{/*.val =*/{0x3aa89d98, 0x239c4226, 0x1a98af33, 0x2d6fc97b, 0x3cc1ca9c, 0x840a9cd, 0x29e2fdf4, 0x26230645, 0x12b8}}}, +{/*.x =*/{/*.val =*/{0x32628f0f, 0x1975c8af, 0x2aee9198, 0x108f6abc, 0x209a7365, 0x2456892f, 0x36203c2c, 0x3c061421, 0x71b}}, + /*.y =*/{/*.val =*/{0x5a1c334, 0x15f172f5, 0x31c80bbb, 0x23e71a88, 0x84ce209, 0x1802f070, 0x1cf4ae33, 0x28575413, 0x527a}}}, +{/*.x =*/{/*.val =*/{0x239620e1, 0x3d8ddb7e, 0x1213786, 0x6447214, 0x3c39e5b, 0xcb96530, 0x3e56833a, 0xd0eb2e6, 0x218}}, + /*.y =*/{/*.val =*/{0x106998b5, 0x380667d9, 0x343c9ec5, 0xca6690b, 0x2fbfc044, 0x3c93f580, 0x250beaf3, 0x75225c2, 0xbea8}}}, +{/*.x =*/{/*.val =*/{0x6d903ac, 0x27b6a70, 0x1ad7e5cb, 0x3e589d39, 0x3afd2ed5, 0xa7f4c39, 0x3a844637, 0x2557b98d, 0x928}}, + /*.y =*/{/*.val =*/{0x1bcd091f, 0x14603a4d, 0xa8d83fc, 0xf49bbea, 0x3a95eeac, 0x1e284c24, 0x342a827b, 0x8400f4f, 0xc256}}}, +{/*.x =*/{/*.val =*/{0xf59dd9e, 0xc411e98, 0x358f0e72, 0x397a7156, 0x318ad67c, 0x58ec132, 0x1d350dad, 0x2f7b8ddc, 0x4f89}}, + /*.y =*/{/*.val =*/{0x156b049, 0x5ab8c8, 0x238df5c1, 0x12209419, 0x3bb2471e, 0x2ebd3010, 0x21f695c4, 0x14b5489e, 0xca79}}}, +{/*.x =*/{/*.val =*/{0x3ff01197, 0xa70c533, 0x1a245bf5, 0x2d9a3c1e, 0x3c4c994, 0x25aeb28b, 0x3c5a80c3, 0x20c132b8, 0xcb9e}}, + /*.y =*/{/*.val =*/{0x3b989c1d, 0xcd381d8, 0x15e0a24c, 0x2cb46300, 0x8891741, 0x96337fc, 0xe6a127, 0x34a007ae, 0x62c7}}}, +{/*.x =*/{/*.val =*/{0x108d2cc2, 0x17e7ff09, 0x48c58c1, 0x2fbb51c, 0x330dc58e, 0x33ca9041, 0x69bd3c8, 0x126c3e27, 0xe2f3}}, + /*.y =*/{/*.val =*/{0x20d4c04f, 0x38d1ef63, 0x9cbdb37, 0xd12fa38, 0x215ba42, 0x182bb1d8, 0x27237818, 0xbca03e0, 0x1feb}}}, +{/*.x =*/{/*.val =*/{0x23d82751, 0x1eab9d45, 0x3ad35452, 0x116d2a41, 0x23b28556, 0x193ce83, 0x1b109399, 0x3fbcfb1b, 0x85d0}}, + /*.y =*/{/*.val =*/{0xeb1f962, 0xb08de89, 0x7733158, 0x21d47a5a, 0x2cf5663e, 0x3525b960, 0x38c0be29, 0x192104e8, 0x1f03}}}, +{/*.x =*/{/*.val =*/{0x1d5fcade, 0x18d5b450, 0x1711ff75, 0x2d20b802, 0x11df0468, 0x1e9b3f34, 0xc4f4f60, 0x3d2c669, 0x6b79}}, + /*.y =*/{/*.val =*/{0x338d3ff, 0x1bffe1bf, 0x3e26b0ab, 0xfe96d1e, 0x2e09cba8, 0x19987e72, 0x1eb3ef29, 0x2606cbfe, 0xd03a}}}, +{/*.x =*/{/*.val =*/{0x23a3e0cb, 0x2c3336af, 0x1978be0b, 0x91e77a1, 0x4f8fe3d, 0xb0d9eb3, 0x2bed3c16, 0x26cb0b5f, 0x4114}}, + /*.y =*/{/*.val =*/{0x339033a8, 0x3a4ba60, 0x3490f247, 0x3b1e017b, 0x2cf28b3, 0x5726e64, 0x30542b4, 0x16e4b6df, 0xc90d}}}, +{/*.x =*/{/*.val =*/{0x23f3d3fc, 0x237774a3, 0x1c29cebf, 0x12a6e081, 0x32a7ba66, 0x30f7f8a1, 0x849dfae, 0x353e939f, 0xd1fa}}, + /*.y =*/{/*.val =*/{0x10f3704d, 0x3488d0f1, 0x3f37326e, 0x34dc4c7b, 0xb7818ba, 0xfdc3a16, 0xfdfe547, 0x25c528d2, 0x8fe1}}}, +{/*.x =*/{/*.val =*/{0x526087e, 0x3d501209, 0x2da20308, 0x3edb6220, 0x18b85dfd, 0x26d8105e, 0x2ce97c1c, 0x373a5fb, 0xff2b}}, + /*.y =*/{/*.val =*/{0x30c29907, 0x32547807, 0x10e2ceb2, 0x2dfb5bee, 0x107936c7, 0x13137153, 0xba188af, 0x4ffbd49, 0x493d}}}, +{/*.x =*/{/*.val =*/{0x3149f8ef, 0x2f4ea6bc, 0x238b4583, 0x3ad713b9, 0x31bb223d, 0xa7aefb2, 0x26c9f78e, 0x36ef17cd, 0x2982}}, + /*.y =*/{/*.val =*/{0x16c7a248, 0x1b9c9ac0, 0x2e3ed845, 0x176e6504, 0x35bc9d09, 0x294ce71e, 0x2220ab9f, 0x16fa6bd9, 0xa61b}}}, +{/*.x =*/{/*.val =*/{0x2380441b, 0x14a27d84, 0xe176588, 0x47d160, 0x17db5860, 0x1bad6412, 0xc0f6b43, 0x39410abc, 0x1a28}}, + /*.y =*/{/*.val =*/{0x452af25, 0x17d81aa, 0x2ee67aeb, 0x2cf9d6d1, 0x36f0ed04, 0x20ca6a25, 0x19dab7c7, 0x269e65b1, 0x5577}}}, +{/*.x =*/{/*.val =*/{0x221e30a7, 0x3bbc38e5, 0x5d83242, 0x3757ade6, 0x3f20142e, 0x143302f4, 0x330601d2, 0x20fa54d7, 0xc8b}}, + /*.y =*/{/*.val =*/{0x1ff688de, 0x3afdefae, 0x187134db, 0x32b48dee, 0x3dc854aa, 0x38fc5fb, 0x3dac7b85, 0x1c1dc197, 0xdcc}}}, +{/*.x =*/{/*.val =*/{0x3856e241, 0x203978b3, 0xd6dd287, 0x3c7b8523, 0x1b212b57, 0xacb98c0, 0x80ea9ed, 0x2ef92c7a, 0x827f}}, + /*.y =*/{/*.val =*/{0x2ec293ec, 0x1816da2e, 0x2903166d, 0x3de98c61, 0x1d12687f, 0x3bcb19f4, 0x27b0b71b, 0x27248f1c, 0xc60f}}}, +{/*.x =*/{/*.val =*/{0xcb1815d, 0x3db912dc, 0xb87461e, 0x11c2a486, 0x2e6b3660, 0x35f2355d, 0x16b973e2, 0x4a9f739, 0xb77f}}, + /*.y =*/{/*.val =*/{0xe57dbc5, 0x2e8f4af2, 0x244816d6, 0x10bc3e46, 0xc2e654c, 0x33becdcf, 0x2acc43f0, 0x216c53e1, 0x4b6f}}}, +{/*.x =*/{/*.val =*/{0x45565ec, 0x3f976b4b, 0x177c5970, 0x163637d2, 0x39f956d8, 0xc22cb2d, 0xbf1247b, 0xee50c06, 0x4897}}, + /*.y =*/{/*.val =*/{0x3aed07e9, 0x2e1e41d7, 0x477b83, 0x6cd6596, 0x45af151, 0x1eece805, 0xdc1b643, 0x1d5a13cf, 0x761f}}}, +{/*.x =*/{/*.val =*/{0x3bfd71fa, 0x13535d0a, 0x34527d4a, 0x1dd68996, 0x304c170b, 0x25c9ca29, 0x1559c6d6, 0x963a3ad, 0xe931}}, + /*.y =*/{/*.val =*/{0x174d3307, 0x366f434c, 0x35e35f33, 0x251b386e, 0x154b40b3, 0x3ad05a72, 0x3dee0e85, 0xccd930f, 0xfb1e}}}, +{/*.x =*/{/*.val =*/{0x2120e2b3, 0x3ced63e8, 0x347f9aa7, 0x163f739f, 0x26e5217a, 0x392b8d33, 0x1bdbae7b, 0x127c87d4, 0xeaa6}}, + /*.y =*/{/*.val =*/{0x3a5ad93d, 0x11e94c16, 0x13f7e59d, 0x29ae597c, 0x39aa5a01, 0x2a03e261, 0x3b03ac69, 0x1e7b56ee, 0xbe32}}}, +{/*.x =*/{/*.val =*/{0x1fc9b0a8, 0xf6f0730, 0x5f3db45, 0xcded71c, 0x2279ea9e, 0x8fa9400, 0x197eec26, 0x276cefae, 0x3adb}}, + /*.y =*/{/*.val =*/{0x305bbdda, 0x6b9e5d7, 0x30266cc6, 0x36723e61, 0x95ff6aa, 0x1d3781f0, 0x34e713c7, 0xb5b6bb9, 0x374e}}}, +{/*.x =*/{/*.val =*/{0x10ae86f9, 0x153a7832, 0x23e7caf0, 0x3f7fd5a5, 0x5fc69fe, 0x255795b, 0x29cbb7e1, 0x14eb10a3, 0x129e}}, + /*.y =*/{/*.val =*/{0x1e89c85d, 0x8bbf734, 0x2b3e01b8, 0x288cbf45, 0x12183fb2, 0x288456dc, 0x29a29b2d, 0x32e562bb, 0x415e}}}, +{/*.x =*/{/*.val =*/{0x2855b8da, 0x8890f57, 0x28947119, 0x15899f44, 0x210956c7, 0x17b2dabb, 0x294485b8, 0x1125323d, 0x6014}}, + /*.y =*/{/*.val =*/{0x334e4bbd, 0x35401643, 0x23f2a4ba, 0xe55709f, 0x32e65b54, 0x2f87f644, 0x1e6469e8, 0x359a7da0, 0x8bb5}}}, +{/*.x =*/{/*.val =*/{0x1a34d24f, 0x388d8cb7, 0x1a137401, 0x2db63c32, 0x342ee541, 0x77db7b3, 0x3169d939, 0xb50f173, 0xe4a4}}, + /*.y =*/{/*.val =*/{0x1eba9414, 0x29fdc4c7, 0xd8e4f13, 0x21bbb7ea, 0xad34ce8, 0x326733ee, 0x1c73526f, 0x24b9c5b4, 0x4d9f}}}, +{/*.x =*/{/*.val =*/{0x3e8f62bb, 0xfcba8c, 0x3ae4d2a3, 0x14f158bd, 0x4ef4d05, 0x2b3e15b, 0x3b18d3ef, 0x147ee133, 0xfd64}}, + /*.y =*/{/*.val =*/{0x132c0911, 0x2b64218, 0x200e83fd, 0xaad24b4, 0x344ccfa, 0x39e9706f, 0x31578b6f, 0x33acac61, 0xe745}}}, +{/*.x =*/{/*.val =*/{0x15fe696b, 0x28747ee7, 0xf3c7a1f, 0x10b8b577, 0x1edbbb00, 0x3a0681be, 0x86bc716, 0x81f2c90, 0x1eee}}, + /*.y =*/{/*.val =*/{0x3429337b, 0x2d159c39, 0x2fd694eb, 0x818b82, 0x21c95f7a, 0x65b4491, 0x2269cd2b, 0x2f466bbd, 0x652c}}}, +{/*.x =*/{/*.val =*/{0x2f94c0d5, 0x23503c67, 0x5725790, 0x303f005f, 0x2e2111e1, 0x16acb0d1, 0x1eb14d46, 0x28cfaa2a, 0xcc0e}}, + /*.y =*/{/*.val =*/{0x2f452fe6, 0x3aaf965e, 0x113f543d, 0x1d3c998, 0x3be663f6, 0x37480ed7, 0x8a2fb23, 0x1e8edc47, 0xf990}}}, +{/*.x =*/{/*.val =*/{0x300bf19, 0x1c5cee75, 0x8fea494, 0x2d4d5daa, 0x352b6b92, 0x183eb6ac, 0xbdd9541, 0x3fbcd83, 0x1ec8}}, + /*.y =*/{/*.val =*/{0x107cefd, 0x1c737073, 0x295a07b6, 0x11b9dfd8, 0x2bbf5e01, 0x2925629e, 0x1340d2f3, 0x3a4dd5ad, 0xaeef}}}, +{/*.x =*/{/*.val =*/{0x14ff9e4, 0x36ba0175, 0x3d890560, 0x2118bdba, 0x3c90bb8e, 0x3aa80d13, 0x4bc6cbe, 0x3a8d467c, 0x5be7}}, + /*.y =*/{/*.val =*/{0x7e0bdbb, 0xc2c1e1, 0x119a3094, 0x26718c08, 0x1ab7fe0e, 0x3e243d95, 0xe605477, 0xbb0fd8e, 0x32f3}}}, +{/*.x =*/{/*.val =*/{0xddb7bb8, 0xfed517d, 0x3853991e, 0xa1927, 0x1f7f5cd5, 0xff21a63, 0x24e65081, 0x26445bab, 0x58f0}}, + /*.y =*/{/*.val =*/{0x2e5b2d6e, 0x37b1cd60, 0x1174302b, 0x1fb9018b, 0x23806650, 0xbfdd851, 0x2111a0d6, 0xaabff, 0x7e07}}}, +{/*.x =*/{/*.val =*/{0xc9a8e2c, 0x4f0581b, 0xc1a1c14, 0xf634693, 0x20cb0f82, 0x33013f61, 0x390b633b, 0x392e6ca5, 0xb0f9}}, + /*.y =*/{/*.val =*/{0x1f3d0db4, 0x30819b13, 0x171cee76, 0x143300b0, 0x3de3f033, 0x2ec2e41b, 0x2de6d41c, 0xafc610e, 0x49e8}}}, +{/*.x =*/{/*.val =*/{0x366642be, 0x376d64a0, 0x158ba889, 0xd241c5f, 0xdfa8bce, 0x2bd1a0, 0x30c2f91b, 0x1de30119, 0x146a}}, + /*.y =*/{/*.val =*/{0x3d83efd0, 0x2ca5d20, 0x37e5ed1d, 0x2aa5c74b, 0x14b2870a, 0x1a609fe7, 0x28add6, 0x383b0cd5, 0xb318}}}, +{/*.x =*/{/*.val =*/{0x39de5cac, 0x6c8d955, 0x2cb26191, 0x3f260f1f, 0xd14cfee, 0x1c2d702f, 0x17e24e56, 0x3c33a296, 0x574e}}, + /*.y =*/{/*.val =*/{0x75a4805, 0x3966ba9b, 0x310008ca, 0x9829efb, 0x1b78451a, 0x1ab6815a, 0x319c73bd, 0x264c0a07, 0x9b9}}}, +{/*.x =*/{/*.val =*/{0x260966d3, 0x230b5d0, 0x2ff86458, 0x29dc306b, 0xc835d10, 0x24e5ee6, 0x3f9f85d9, 0x1f9e6762, 0xd3d9}}, + /*.y =*/{/*.val =*/{0x33c2e52, 0x377ae142, 0x28dc4eeb, 0x3921c46f, 0x3ad3b5, 0x2a249d75, 0x2c95e6aa, 0x2d18ddae, 0x8ddb}}}, +{/*.x =*/{/*.val =*/{0x168c6d4b, 0x103ee4e, 0x3494c120, 0x2f9e33e3, 0x3bee0ab2, 0x1d39e0b2, 0x318987b9, 0x194ca22c, 0xb1aa}}, + /*.y =*/{/*.val =*/{0x2891ac51, 0xf6798ab, 0x1623cc38, 0x2876427, 0x23a83b10, 0x12aa38b5, 0x10d71268, 0x1c71820, 0x7ed6}}}, +{/*.x =*/{/*.val =*/{0x3180eef9, 0x35daa1e4, 0x228b9776, 0x48826, 0x207b128d, 0x2b3aec6a, 0x2e5f07e3, 0x303d8748, 0xfa50}}, + /*.y =*/{/*.val =*/{0x3f4f2811, 0x233635f4, 0x17a213b3, 0x1a0ca4e9, 0x1a68a5e, 0x334a1c8a, 0x3eba9b72, 0x31a488e5, 0x6b84}}}, +{/*.x =*/{/*.val =*/{0x187f5048, 0x2716f88c, 0x8386d45, 0x8ca3491, 0x290836e7, 0x503f80b, 0x74e0780, 0x13bb9864, 0x6396}}, + /*.y =*/{/*.val =*/{0x9309df8, 0x20e8a136, 0x1de6c843, 0x1602e4d3, 0xbfbc93d, 0x3fe6c70d, 0x1cf41a39, 0x3ece9ae2, 0x3b6c}}}, +{/*.x =*/{/*.val =*/{0x3adb2a65, 0x2052e87a, 0x3cbda31f, 0x35fc4ab4, 0x3c9f75af, 0x11a777c3, 0x1b7e22d1, 0x3896d345, 0x5a3c}}, + /*.y =*/{/*.val =*/{0x1d327f1d, 0x22c5c33c, 0x25fe8ed, 0x38a2f0f6, 0x3f99af3e, 0x29b6fefc, 0x5f63873, 0x496e4b8, 0x8b34}}}, +{/*.x =*/{/*.val =*/{0xa9f44d0, 0x1a9ccdd5, 0x1a8fa001, 0x36f2db9a, 0x1e41ff85, 0x2f8d3c3, 0x13eda691, 0x16be63e, 0x5ce6}}, + /*.y =*/{/*.val =*/{0x9d30105, 0x3417cd2, 0x32eccc6c, 0xf2c6fe8, 0x76c58ab, 0x15af40c7, 0x26bfe7ba, 0x33e6fb08, 0x4cdd}}}, +{/*.x =*/{/*.val =*/{0x1f067ec2, 0x394f4cad, 0x1bba5220, 0xa22ad75, 0x8e8421a, 0x16fdadf6, 0x21a11b1a, 0x1874329c, 0xda1d}}, + /*.y =*/{/*.val =*/{0x1ad836f1, 0x157ee83c, 0x279b48a6, 0x29ce2674, 0x91e2966, 0x1d98587, 0x1306c79c, 0x3d569f26, 0x8157}}}, +{/*.x =*/{/*.val =*/{0x2cd3c369, 0xf084348, 0x1f8e934b, 0x181520f8, 0x1283a23, 0x1757d877, 0xc444df8, 0x3802d3bd, 0x9c7b}}, + /*.y =*/{/*.val =*/{0x22329515, 0x27b8ffae, 0x2769cbd2, 0xc454e85, 0x2401483e, 0x9b51573, 0x20d2052a, 0x30379d2c, 0x9220}}}, +{/*.x =*/{/*.val =*/{0x3bb8c9e3, 0x1af364b5, 0x141178e7, 0x3741a9c1, 0xcc49174, 0x1992c8e3, 0x1263bb55, 0x20fd0a09, 0xfcd}}, + /*.y =*/{/*.val =*/{0x1f4aa9ad, 0x21b557ef, 0x1627bf4e, 0x2fabb37c, 0x3db683ad, 0x208cb797, 0x1fbced1d, 0x3073fab1, 0x6c0b}}}, +{/*.x =*/{/*.val =*/{0x326b64f1, 0x33ce6512, 0x1476d995, 0x3b73ca3d, 0x11e59db7, 0x36931894, 0xf010d4c, 0x101fc6d6, 0x7175}}, + /*.y =*/{/*.val =*/{0x324234d5, 0x9b9fbea, 0x471d2a4, 0x7fa2ddd, 0xcc86eb0, 0x34d0044d, 0x3d550f36, 0x1550d138, 0x43b4}}}, +{/*.x =*/{/*.val =*/{0xd064e13, 0x29cec184, 0x6f1e062, 0xc477811, 0x3d416615, 0x17fe63a3, 0x30690721, 0x20bfc325, 0xa8e2}}, + /*.y =*/{/*.val =*/{0x11f4cc0c, 0x3bdf1cc4, 0xdd6bd6c, 0x19e68f94, 0x2515888b, 0x2dfcf16c, 0x1c09abf, 0xd56e36e, 0x7f97}}}, +{/*.x =*/{/*.val =*/{0x3f7653a1, 0x57ae7a9, 0x13d67c1c, 0x2fa7aa9d, 0x266e63ef, 0x1dbe017a, 0x3aecbcb8, 0x3cb9f89f, 0xcac6}}, + /*.y =*/{/*.val =*/{0x3ec5e556, 0x23042b43, 0x8103a06, 0x3a0eb95a, 0x2a345081, 0x2d976690, 0x26f194cd, 0x5b978aa, 0xf7d4}}}, +{/*.x =*/{/*.val =*/{0x624003d, 0x327d2ac2, 0x238cb11c, 0x2dd9ca50, 0xe43254a, 0x3164cb96, 0x3d206efb, 0x3791bb8d, 0xe6df}}, + /*.y =*/{/*.val =*/{0x2216b93b, 0x15219438, 0x27fd7dd7, 0x7397a94, 0xf92203b, 0x3d23dee2, 0x139498f2, 0x2cedefa4, 0x8727}}}, +{/*.x =*/{/*.val =*/{0x8dce109, 0x38440d5, 0xf211d3b, 0x1438c527, 0x96082e2, 0x1033f1eb, 0x2823d66a, 0x2273669, 0x3c4e}}, + /*.y =*/{/*.val =*/{0x3a19aeea, 0xafd9648, 0x17fe697e, 0x1e7850b6, 0x364d3795, 0x15ef2855, 0x191b4807, 0x2f99a7f8, 0x43fb}}}, +{/*.x =*/{/*.val =*/{0x319497c, 0xbce0b7a, 0x12508c02, 0x166c7e94, 0x13cab15d, 0x2795b9a4, 0x285872d3, 0x14ee7268, 0x174a}}, + /*.y =*/{/*.val =*/{0x79afa73, 0xf684eb0, 0xb985438, 0x1ace8763, 0x7f9e664, 0x10557cb1, 0x9c1657b, 0x370deaff, 0xccc9}}}, +{/*.x =*/{/*.val =*/{0x40dd273, 0x3d768dbe, 0x24501115, 0xf4a0383, 0x392ea3d5, 0x1c1c7bc6, 0x6bb630c, 0x38b9e5a5, 0x20e6}}, + /*.y =*/{/*.val =*/{0x3b46b593, 0x1f3f456, 0x1a8693cc, 0x7b25e4f, 0x7465581, 0x2e86b65e, 0x159e44a0, 0x1ebf93c5, 0xd3ad}}}, +{/*.x =*/{/*.val =*/{0x1a077674, 0x1ed53cc0, 0xc24ca3e, 0x2b9a04db, 0x31db7035, 0xa0281f9, 0x351dba80, 0x2a0935e8, 0x8e0c}}, + /*.y =*/{/*.val =*/{0x12b7ed98, 0x2e132fb0, 0x2f910290, 0x3d810674, 0x22cf57cf, 0x1a749369, 0x12d41dc5, 0x1581d646, 0x4ec}}}, +{/*.x =*/{/*.val =*/{0x28192441, 0x25abf17a, 0x321b4afe, 0x36d60868, 0x3d66c1af, 0x298d54f8, 0x182d1c5f, 0x14369472, 0xf7bb}}, + /*.y =*/{/*.val =*/{0x145165ae, 0x31903a87, 0x3c4c74bb, 0x33f707ee, 0x26485db1, 0x2f18ef77, 0xa526311, 0xef8c0cd, 0x93cc}}}, +{/*.x =*/{/*.val =*/{0x1475b7ba, 0x213f7fc2, 0x918b3d8, 0xe79cc39, 0x18cdbe0, 0x395fb7d4, 0x3785c3d3, 0x25a60650, 0x9593}}, + /*.y =*/{/*.val =*/{0x3524f2fd, 0x26e2afe1, 0x709385e, 0x194fd932, 0x1cd6849c, 0xe1a92e, 0x331dd8ba, 0x154a2230, 0x2e7e}}}, +{/*.x =*/{/*.val =*/{0xbc8f53b, 0x1c9d6a50, 0x11747c70, 0x889ace, 0x33d95ed7, 0xcb29f75, 0x1a7deafe, 0x5017fc3, 0xcbee}}, + /*.y =*/{/*.val =*/{0x38c87f45, 0x248b9ac9, 0x126f7282, 0x27fd3da0, 0x294cf0d, 0x3cf9a26e, 0x1f902b51, 0x7d3d39d, 0xf621}}}, +{/*.x =*/{/*.val =*/{0x14b311dd, 0xddf222c, 0x3d71b9cf, 0x38efabbe, 0x2252e03d, 0x202fe82e, 0x2f5acdd5, 0x2eb4a3ea, 0xadd5}}, + /*.y =*/{/*.val =*/{0x9d6c38d, 0xbe60bcd, 0x29b9b890, 0x353879d9, 0x19814f52, 0x390d3e0d, 0x1c3a5974, 0xf3d368f, 0xe9c4}}}, +{/*.x =*/{/*.val =*/{0xd7c0979, 0x17d90028, 0x5a8c96f, 0xa6cc52f, 0x1ced24a, 0x277cf7fd, 0x317143fa, 0x10caea05, 0x53f2}}, + /*.y =*/{/*.val =*/{0x137b36a2, 0x27dfa431, 0x1e8b845f, 0x35693d72, 0x1b07de4b, 0x138f8244, 0x79b7ccd, 0x3bfef07c, 0xbd52}}}, +{/*.x =*/{/*.val =*/{0x1d82b151, 0x2d44d032, 0x21fba2db, 0x28290f55, 0x109a8fcc, 0x168454ec, 0x1e56d64, 0xe942b90, 0xd2a6}}, + /*.y =*/{/*.val =*/{0x1cf89405, 0x105085d3, 0x84ca52d, 0x3dd42bd, 0x148220a7, 0x2bb962ca, 0x3fcb7565, 0x21bed910, 0xe82d}}}, +{/*.x =*/{/*.val =*/{0xa72da5f, 0x31b12eb3, 0x2c413497, 0x2e735acd, 0x3725f922, 0x31c8080c, 0x525e23b, 0x20e9d840, 0xbaf1}}, + /*.y =*/{/*.val =*/{0x28f2a0cf, 0x1df398a2, 0x27393613, 0x8cdb172, 0x29b1d18e, 0x22f56375, 0x34d33568, 0x27efa732, 0xdeac}}}, +{/*.x =*/{/*.val =*/{0x56c3943, 0x296b2963, 0x2b76a5ff, 0x36f40b55, 0x8f6fd5a, 0xcca41b9, 0x40238f9, 0x3e29f8e1, 0xf7ae}}, + /*.y =*/{/*.val =*/{0x2cf442f1, 0xc7d89fe, 0xdcd0034, 0x30c0612a, 0x2b3fcfee, 0x10aef70e, 0x3da797c4, 0x2d1357f, 0x4e3b}}}, +{/*.x =*/{/*.val =*/{0x11924459, 0x3eb2515c, 0x3c7a78c1, 0x3cbe8968, 0x1dbb1f7a, 0xb8a7c37, 0x19036c5a, 0x11f2c400, 0xdfb5}}, + /*.y =*/{/*.val =*/{0xc65fd9e, 0x28817837, 0x1c031dcf, 0x2bc24c39, 0x864cc22, 0xe273a77, 0x347088b8, 0x34aa6e83, 0x9acc}}}, +{/*.x =*/{/*.val =*/{0x1617e073, 0x10dbe6d1, 0x39317b3, 0x2b2f6f4e, 0xfdc866b, 0x39e25b5f, 0x31eb890e, 0x1f88cd51, 0x6458}}, + /*.y =*/{/*.val =*/{0x1faf6589, 0x20a6797a, 0x33aeab35, 0x2e428e44, 0x299a185, 0x1b75911f, 0x102e2ae9, 0x33756fda, 0xd99f}}}, +{/*.x =*/{/*.val =*/{0x384480d, 0x12f36231, 0x291f2ef4, 0x382da88a, 0x2f0c1294, 0xa2d5324, 0x3940f2cf, 0x35ac50b7, 0xb866}}, + /*.y =*/{/*.val =*/{0xc4cafa8, 0x39966d1c, 0x31d86d60, 0x3948a012, 0x1ad7ac24, 0x9e35faa, 0x2eb7089a, 0x2c2cd09a, 0x1914}}}, +{/*.x =*/{/*.val =*/{0x1db20d6c, 0x8a736a0, 0x14fe455d, 0x354ab93b, 0x2ba87e2, 0x27459184, 0x2819ec4d, 0x2e242177, 0xec2b}}, + /*.y =*/{/*.val =*/{0x229cf4a0, 0x3a67135, 0x7efa98a, 0x288d92fa, 0x940c633, 0x3d9bc194, 0x13a1332, 0x305d9878, 0xccec}}}, +{/*.x =*/{/*.val =*/{0x23b09d0f, 0x22983b2c, 0x350becf3, 0x141903, 0x145905e5, 0x35d7bd79, 0x296ced39, 0x29f8e278, 0x71c4}}, + /*.y =*/{/*.val =*/{0x320ddb62, 0xdec7c05, 0x262ffc76, 0x1bcac212, 0x3810aa78, 0xf828a4b, 0x2f3ba0af, 0x3eb6dcde, 0x1313}}}, +{/*.x =*/{/*.val =*/{0x1d45e458, 0x1635b21b, 0x250e7fd3, 0x2a9b3a8, 0x9de042f, 0x151b4f95, 0xd885b3a, 0x2f783939, 0x8481}}, + /*.y =*/{/*.val =*/{0x1779057e, 0x3592c6d6, 0x3262e556, 0x29e710a, 0x2cb2ca90, 0x96fce73, 0x4dd84a, 0x1ee32e95, 0x38ee}}}, +{/*.x =*/{/*.val =*/{0x2ce9f114, 0x1510cd49, 0x19561dde, 0xbb5814a, 0x1492bf39, 0x10f1b347, 0x3a8b9fd, 0x29142f4e, 0x9629}}, + /*.y =*/{/*.val =*/{0x224aa391, 0x28e5cb12, 0x56af8dc, 0x9564f97, 0xef64db9, 0x2fbf4883, 0x3b6d7576, 0x26ca0317, 0xbf43}}}, +{/*.x =*/{/*.val =*/{0x26ca6cc3, 0xf4e3658, 0x187e1838, 0x1df5d1f8, 0x893df14, 0x1cc369f3, 0x24688eb1, 0x711fbc7, 0xb73b}}, + /*.y =*/{/*.val =*/{0x254fdba3, 0x2b0d75da, 0x1757f5af, 0x8a89482, 0x8050973, 0x1f592ef3, 0x122a90a5, 0x572ca52, 0x5843}}}, +{/*.x =*/{/*.val =*/{0x138f93e0, 0x31b8864b, 0x276899f9, 0x16ca8eed, 0x22fef7d0, 0x2624801e, 0x180311f, 0x5acb6d0, 0xedfe}}, + /*.y =*/{/*.val =*/{0x229405ad, 0x3405e4f7, 0x6e227e3, 0xf544031, 0x5d0d25b, 0x1d3ea92c, 0x1db3694d, 0xbc7f29, 0xee69}}}, +{/*.x =*/{/*.val =*/{0x2caf666b, 0x3358c0fd, 0xb1ce30b, 0x3f3fb4f1, 0x17f4637f, 0x1a5e6ba0, 0x102aa62b, 0x1295e9e0, 0x1346}}, + /*.y =*/{/*.val =*/{0x3f6ecc27, 0x3d256a41, 0x10942e13, 0x3cc02a07, 0xcb0ca48, 0x390cd14f, 0x14580ef7, 0x5640118, 0x69be}}}, +{/*.x =*/{/*.val =*/{0x65084ae, 0x1d612718, 0x2abe577c, 0x20af9f73, 0x3e12d191, 0x17223217, 0x5362ec0, 0x3e3d4c89, 0xeb3c}}, + /*.y =*/{/*.val =*/{0x396b9480, 0x3d9f07ff, 0x3dbd2a66, 0xad17179, 0x1ca4a1f5, 0x398f73bf, 0x1d70043f, 0x31e088b6, 0xc833}}}, +{/*.x =*/{/*.val =*/{0x2e9a5d0, 0x2396f2f3, 0xa201d9f, 0x1dbf3e61, 0x519b2a5, 0x2983c861, 0x199974f7, 0x299f424b, 0xbdf1}}, + /*.y =*/{/*.val =*/{0x562ff7b, 0x36d3dc06, 0x1626461c, 0xa02d879, 0x3f7baaa6, 0x2f952a1a, 0x1a1aaa80, 0x240aead9, 0x4095}}}, +{/*.x =*/{/*.val =*/{0x3b27e771, 0x3797f05c, 0x37da62ab, 0xed06591, 0x483b48c, 0x2f899ed9, 0xec29cd5, 0x1a9bb771, 0x6885}}, + /*.y =*/{/*.val =*/{0x7bbdab6, 0x46358a8, 0x3b0733a6, 0x748bca4, 0x1f7b4a33, 0x1bf52706, 0x1a1fb13b, 0xf7c53de, 0x77a3}}}, +{/*.x =*/{/*.val =*/{0x2d83f366, 0x2b68e834, 0x2f28588c, 0x36733b78, 0x1dc97a0c, 0x3d0c2f30, 0x3fe2e9ae, 0x277d6dc4, 0xbc4a}}, + /*.y =*/{/*.val =*/{0x181f33c1, 0x1d635999, 0x2547b16d, 0x3a2a7efe, 0x3798caa6, 0x24deb7d2, 0x5c06383, 0x20729b9e, 0xd3a}}}, +{/*.x =*/{/*.val =*/{0x33fceb19, 0x20b79517, 0x385c4092, 0x226c887d, 0x27bab42e, 0x171d89b3, 0x2ccc0abc, 0xf578473, 0xda43}}, + /*.y =*/{/*.val =*/{0x26f5cc64, 0x2139c482, 0x227b2776, 0x1dff0b64, 0x15e5218e, 0x2ef712be, 0x10301de, 0x36f4c86a, 0xe498}}}, +{/*.x =*/{/*.val =*/{0x1acf692a, 0x13789d71, 0x2207e065, 0x3120e29c, 0x16efdbc, 0x3045a607, 0xc7ec1c1, 0x2387ba7a, 0x31e}}, + /*.y =*/{/*.val =*/{0x316f667a, 0x330aa13a, 0x1bf73b09, 0x192609f1, 0x16743b70, 0x25c0a43, 0x3353dd9d, 0x1fd6d196, 0xad7e}}}, +{/*.x =*/{/*.val =*/{0x1f488b6, 0xaef5ffe, 0x3c7a9159, 0x326fcd8f, 0x257f73e9, 0x38036189, 0x161155d3, 0x2181ea23, 0xa987}}, + /*.y =*/{/*.val =*/{0x31dab1d, 0x2569eeec, 0xad5c6d4, 0x343c0659, 0x157c2239, 0x18f9f208, 0x95d61c0, 0x286af562, 0xd181}}}, +{/*.x =*/{/*.val =*/{0x25324caa, 0x152acc3f, 0x29472a39, 0x12d978c2, 0x12a32e69, 0x3631d251, 0x18bc0d23, 0x2a5efe0a, 0x8c28}}, + /*.y =*/{/*.val =*/{0xbef9482, 0x39c771cf, 0x11cb9459, 0x39e13c11, 0x3cc0eb7a, 0x3fb7cc7d, 0x5193378, 0x118e8cc, 0x40a3}}}, +{/*.x =*/{/*.val =*/{0x3611d8e2, 0x37ec807d, 0x249fc4d5, 0x4c3fa37, 0x3f0da2c8, 0x3b569811, 0xa2f196b, 0x3061ca8e, 0xab1a}}, + /*.y =*/{/*.val =*/{0x429d15b, 0x69607cf, 0x21e545f0, 0x3be4f4cf, 0x2a42b6f7, 0x297ce76d, 0x117a1e9a, 0x28de8c93, 0x13f4}}}, +{/*.x =*/{/*.val =*/{0x2651b3fa, 0x9abb990, 0x32df4342, 0x286cd95d, 0x3f31ef8e, 0xe981c94, 0x2f82d370, 0x3fa6d6fb, 0x2564}}, + /*.y =*/{/*.val =*/{0x1e5122d, 0x2e0b9a8c, 0x379816ed, 0x3cdf6ada, 0x3925f14, 0x2852b848, 0x389095f, 0x3de9819e, 0x8ad9}}}, +{/*.x =*/{/*.val =*/{0x2e180068, 0x5e38f4e, 0xbd3103b, 0x28f55b08, 0xdc01a7e, 0x1b17030c, 0x5b0cbfc, 0x184dbfeb, 0xff3d}}, + /*.y =*/{/*.val =*/{0x188c6077, 0x29aedb8, 0x1f5e67, 0x1d9dbc90, 0x16adc154, 0xdcb376, 0xe40d, 0xe6fa139, 0x1332}}}, +{/*.x =*/{/*.val =*/{0x1faccae0, 0x2312e844, 0x24bb3374, 0x22cd4316, 0x71fd23c, 0x3653393c, 0x127a8c1d, 0x259984e5, 0x8ea}}, + /*.y =*/{/*.val =*/{0xe62b945, 0x16bcd28c, 0xf0f8e95, 0x2de0efa7, 0x15c5d735, 0x39f033ee, 0x22782e24, 0x3eaef23b, 0x620e}}}, +{/*.x =*/{/*.val =*/{0x2190b632, 0xa4c4c76, 0xab5ab9a, 0x33ca88e9, 0x159d8263, 0x19b7cc55, 0x20cd9f3a, 0x18dc5d88, 0xc25f}}, + /*.y =*/{/*.val =*/{0x3c9590cf, 0x3bafcf5b, 0x2027a1d6, 0x27c13fe7, 0x9d7980a, 0x12640e0, 0x12873989, 0x13fb7a53, 0x5315}}}, +{/*.x =*/{/*.val =*/{0x1466d561, 0xb32cedf, 0x1978b4de, 0x1ed5770c, 0x8544c0c, 0xb60a95a, 0x26bab3e8, 0x237f8f33, 0x2a9e}}, + /*.y =*/{/*.val =*/{0x12e76373, 0x25b33d49, 0x3a02182f, 0x7abb05, 0xb96cf5e, 0x1ed6b582, 0x2651fbac, 0x3b69705b, 0x1df}}}, +{/*.x =*/{/*.val =*/{0x3f8be384, 0x22f4c810, 0x31db6c3e, 0x3b02ab68, 0x1ef07271, 0x2b5b253f, 0x23e1b251, 0x24290af9, 0xb237}}, + /*.y =*/{/*.val =*/{0x2b19880e, 0x4291cf7, 0x9ecb58d, 0x3c013d05, 0x1f94517, 0x143e22aa, 0x15edbe8d, 0x1a524675, 0xfc6b}}}, }; #endif From 166e19ba7c985b5643137d90ddaf2536749b4852 Mon Sep 17 00:00:00 2001 From: Jan Pochyla Date: Mon, 17 Feb 2014 18:48:57 +0100 Subject: [PATCH 079/627] add cmake file with c++ compilation on MSVC --- CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 000000000..da714d93b --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,5 @@ +set(SOURCES bignum.c ecdsa.c secp256k1.c sha2.c rand.c hmac.c bip32.c ripemd160.c bip39.c pbkdf2.c) +if(MSVC) + set_source_files_properties(${SOURCES} PROPERTIES LANGUAGE CXX) +endif(MSVC) +add_library(TrezorCrypto STATIC ${SOURCES}) From 1034b28f903f2faa1dc4e2ee46752a2e8abef13a Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 19 Feb 2014 16:58:48 +0100 Subject: [PATCH 080/627] use both private and public bip32 versions --- bip32.c | 23 +++++++++++++++++------ bip32.h | 10 ++++++---- tests.c | 6 +++--- 3 files changed, 26 insertions(+), 13 deletions(-) diff --git a/bip32.c b/bip32.c index 5acfd6d59..56a20f7b4 100644 --- a/bip32.c +++ b/bip32.c @@ -7,9 +7,11 @@ #include "sha2.h" #include "ripemd160.h" -void hdnode_from_xpub(uint8_t version_byte, uint32_t version, uint32_t depth, uint32_t fingerprint, uint32_t child_num, uint8_t *chain_code, uint8_t *public_key, HDNode *out) +void hdnode_from_xpub(uint8_t version_byte, uint32_t version_private, uint32_t version_public, uint32_t depth, uint32_t fingerprint, uint32_t child_num, uint8_t *chain_code, uint8_t *public_key, HDNode *out) { - out->version = version; + out->version = version_public; + out->version_private = version_private; + out->version_public = version_public; out->depth = depth; out->fingerprint = fingerprint; out->child_num = child_num; @@ -20,9 +22,11 @@ void hdnode_from_xpub(uint8_t version_byte, uint32_t version, uint32_t depth, ui hdnode_fill_address(out); } -void hdnode_from_xprv(uint8_t version_byte, uint32_t version, uint32_t depth, uint32_t fingerprint, uint32_t child_num, uint8_t *chain_code, uint8_t *private_key, HDNode *out) +void hdnode_from_xprv(uint8_t version_byte, uint32_t version_private, uint32_t version_public, uint32_t depth, uint32_t fingerprint, uint32_t child_num, uint8_t *chain_code, uint8_t *private_key, HDNode *out) { - out->version = version; + out->version = version_private; + out->version_private = version_private; + out->version_public = version_public; out->depth = depth; out->fingerprint = fingerprint; out->child_num = child_num; @@ -33,10 +37,12 @@ void hdnode_from_xprv(uint8_t version_byte, uint32_t version, uint32_t depth, ui hdnode_fill_address(out); } -void hdnode_from_seed(uint8_t version_byte, uint32_t version, uint8_t *seed, int seed_len, HDNode *out) +void hdnode_from_seed(uint8_t version_byte, uint32_t version_private, uint32_t version_public, uint8_t *seed, int seed_len, HDNode *out) { uint8_t I[32 + 32]; - out->version = version; + out->version = version_private; + out->version_private = version_private; + out->version_public = version_public; out->depth = 0; out->fingerprint = 0x00000000; out->child_num = 0; @@ -55,6 +61,8 @@ int hdnode_private_ckd(HDNode *inout, uint32_t i) uint8_t fingerprint[32]; bignum256 a, b; + inout->version = inout->version_private; + if (i & 0x80000000) { // private derivation data[0] = 0; memcpy(data + 1, inout->private_key, 32); @@ -82,6 +90,7 @@ int hdnode_private_ckd(HDNode *inout, uint32_t i) hdnode_fill_public_key(inout); hdnode_fill_address(inout); + return 1; } @@ -93,6 +102,8 @@ int hdnode_public_ckd(HDNode *inout, uint32_t i) curve_point a, b; bignum256 c; + inout->version = inout->version_public; + if (i & 0x80000000) { // private derivation return 0; } else { // public derivation diff --git a/bip32.h b/bip32.h index a49ba8519..4ef0c96c2 100644 --- a/bip32.h +++ b/bip32.h @@ -11,15 +11,17 @@ typedef struct { uint8_t chain_code[32]; uint8_t private_key[32]; uint8_t public_key[33]; - uint8_t version_byte; char address[35]; + uint8_t version_byte; + uint32_t version_private; + uint32_t version_public; } HDNode; -void hdnode_from_xpub(uint8_t version_byte, uint32_t version, uint32_t depth, uint32_t fingerprint, uint32_t child_num, uint8_t *chain_code, uint8_t *public_key, HDNode *out); +void hdnode_from_xpub(uint8_t version_byte, uint32_t version_private, uint32_t version_public, uint32_t depth, uint32_t fingerprint, uint32_t child_num, uint8_t *chain_code, uint8_t *public_key, HDNode *out); -void hdnode_from_xprv(uint8_t version_byte, uint32_t version, uint32_t depth, uint32_t fingerprint, uint32_t child_num, uint8_t *chain_code, uint8_t *private_key, HDNode *out); +void hdnode_from_xprv(uint8_t version_byte, uint32_t version_private, uint32_t version_public, uint32_t depth, uint32_t fingerprint, uint32_t child_num, uint8_t *chain_code, uint8_t *private_key, HDNode *out); -void hdnode_from_seed(uint8_t version_byte, uint32_t version, uint8_t *seed, int seed_len, HDNode *out); +void hdnode_from_seed(uint8_t version_byte, uint32_t version_private, uint32_t version_public, uint8_t *seed, int seed_len, HDNode *out); #define hdnode_private_ckd_prime(X, I) hdnode_private_ckd((X), ((I) | 0x80000000)) diff --git a/tests.c b/tests.c index a61c2aa40..0e876675f 100644 --- a/tests.c +++ b/tests.c @@ -80,7 +80,7 @@ START_TEST(test_bip32_vector_1) HDNode node; // init m - hdnode_from_seed(0x00, 0x0488B21E, fromhex("000102030405060708090a0b0c0d0e0f"), 16, &node); + hdnode_from_seed(0x00, 0x0488ADE4, 0x0488B21E, fromhex("000102030405060708090a0b0c0d0e0f"), 16, &node); // [Chain m] ck_assert_int_eq(node.fingerprint, 0x00000000); @@ -138,7 +138,7 @@ START_TEST(test_bip32_vector_2) int r; // init m - hdnode_from_seed(0x00, 0x0488B21E, fromhex("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), 64, &node); + hdnode_from_seed(0x00, 0x0488ADE4, 0x0488B21E, fromhex("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), 64, &node); // [Chain m] ck_assert_int_eq(node.fingerprint, 0x00000000); @@ -193,7 +193,7 @@ START_TEST(test_bip32_vector_2) ck_assert_str_eq(node.address, "14UKfRV9ZPUp6ZC9PLhqbRtxdihW9em3xt"); // init m - hdnode_from_seed(0x00, 0x0488B21E, fromhex("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), 64, &node); + hdnode_from_seed(0x00, 0x0488ADE4, 0x0488B21E, fromhex("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), 64, &node); // test public derivation // [Chain m/0] From d0e152a0889572983f832d7a4081f702d508138c Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 19 Feb 2014 21:26:42 +0100 Subject: [PATCH 081/627] replace SHA256/SHA512 prefix with sha256/sha512 (OpenSSL clash) --- bip32.c | 4 ++-- bip39.c | 2 +- ecdsa.c | 24 ++++++++++++------------ hmac.c | 36 ++++++++++++++++++------------------ sha2.c | 52 ++++++++++++++++++++++++++-------------------------- sha2.h | 24 ++++++++++++------------ tests.c | 4 ++-- 7 files changed, 73 insertions(+), 73 deletions(-) diff --git a/bip32.c b/bip32.c index 56a20f7b4..18bbc4e2a 100644 --- a/bip32.c +++ b/bip32.c @@ -71,7 +71,7 @@ int hdnode_private_ckd(HDNode *inout, uint32_t i) } write_be(data + 33, i); - SHA256_Raw(inout->public_key, 33, fingerprint); + sha256_Raw(inout->public_key, 33, fingerprint); ripemd160(fingerprint, 32, fingerprint); inout->fingerprint = (fingerprint[0] << 24) + (fingerprint[1] << 16) + (fingerprint[2] << 8) + fingerprint[3]; @@ -111,7 +111,7 @@ int hdnode_public_ckd(HDNode *inout, uint32_t i) } write_be(data + 33, i); - SHA256_Raw(inout->public_key, 33, fingerprint); + sha256_Raw(inout->public_key, 33, fingerprint); ripemd160(fingerprint, 32, fingerprint); inout->fingerprint = (fingerprint[0] << 24) + (fingerprint[1] << 16) + (fingerprint[2] << 8) + fingerprint[3]; diff --git a/bip39.c b/bip39.c index a98d43279..82962658b 100644 --- a/bip39.c +++ b/bip39.c @@ -33,7 +33,7 @@ const char *mnemonic_from_data(const uint8_t *data, int len) return 0; } - SHA256_Raw((const uint8_t *)data, len, hash); + sha256_Raw((const uint8_t *)data, len, hash); for (i = 0; i < len; i++) { for (j = 0; j < 8; j++) { diff --git a/ecdsa.c b/ecdsa.c index 92a18c305..b373f3841 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -227,7 +227,7 @@ int generate_k_rfc6979(bignum256 *secret, const uint8_t *priv_key, const uint8_t int ecdsa_sign(const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig) { uint8_t hash[32]; - SHA256_Raw(msg, msg_len, hash); + sha256_Raw(msg, msg_len, hash); return ecdsa_sign_digest(priv_key, hash, sig); } @@ -236,8 +236,8 @@ int ecdsa_sign(const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, ui int ecdsa_sign_double(const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig) { uint8_t hash[32]; - SHA256_Raw(msg, msg_len, hash); - SHA256_Raw(hash, 32, hash); + sha256_Raw(msg, msg_len, hash); + sha256_Raw(hash, 32, hash); return ecdsa_sign_digest(priv_key, hash, sig); } @@ -343,15 +343,15 @@ void ecdsa_get_address(const uint8_t *pub_key, uint8_t version, char *addr) int i, l; if (pub_key[0] == 0x04) { - SHA256_Raw(pub_key, 65, a); + sha256_Raw(pub_key, 65, a); } else { - SHA256_Raw(pub_key, 33, a); + sha256_Raw(pub_key, 33, a); } b[0] = version; ripemd160(a, 32, b + 1); - SHA256_Raw(b, 21, a); - SHA256_Raw(a, 32, a); + sha256_Raw(b, 21, a); + sha256_Raw(a, 32, a); memcpy(a + 28, a, 4); // checksum memset(a, 0, 7); // zeroes @@ -405,8 +405,8 @@ int ecdsa_address_decode(const char *addr, uint8_t *out) } bn_write_be(&num, buf); // compute address hash - SHA256_Raw(buf + 7, 21, check); - SHA256_Raw(check, 32, check); + sha256_Raw(buf + 7, 21, check); + sha256_Raw(check, 32, check); // check if valid if (memcmp(buf + 7 + 21, check, 4) != 0) { return 0; @@ -453,15 +453,15 @@ int ecdsa_read_pubkey(const uint8_t *pub_key, curve_point *pub) int ecdsa_verify(const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, uint32_t msg_len) { uint8_t hash[32]; - SHA256_Raw(msg, msg_len, hash); + sha256_Raw(msg, msg_len, hash); return ecdsa_verify_digest(pub_key, sig, hash); } int ecdsa_verify_double(const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, uint32_t msg_len) { uint8_t hash[32]; - SHA256_Raw(msg, msg_len, hash); - SHA256_Raw(hash, 32, hash); + sha256_Raw(msg, msg_len, hash); + sha256_Raw(hash, 32, hash); return ecdsa_verify_digest(pub_key, sig, hash); } diff --git a/hmac.c b/hmac.c index 3ea37d6e7..be78b0b75 100644 --- a/hmac.c +++ b/hmac.c @@ -11,7 +11,7 @@ void hmac_sha256(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, memset(buf, 0, SHA256_BLOCK_LENGTH); if (keylen > SHA256_BLOCK_LENGTH) { - SHA256_Raw(key, keylen, buf); + sha256_Raw(key, keylen, buf); } else { memcpy(buf, key, keylen); } @@ -21,15 +21,15 @@ void hmac_sha256(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, i_key_pad[i] = buf[i] ^ 0x36; } - SHA256_Init(&ctx); - SHA256_Update(&ctx, i_key_pad, SHA256_BLOCK_LENGTH); - SHA256_Update(&ctx, msg, msglen); - SHA256_Final(buf, &ctx); + sha256_Init(&ctx); + sha256_Update(&ctx, i_key_pad, SHA256_BLOCK_LENGTH); + sha256_Update(&ctx, msg, msglen); + sha256_Final(buf, &ctx); - SHA256_Init(&ctx); - SHA256_Update(&ctx, o_key_pad, SHA256_BLOCK_LENGTH); - SHA256_Update(&ctx, buf, SHA256_DIGEST_LENGTH); - SHA256_Final(hmac, &ctx); + sha256_Init(&ctx); + sha256_Update(&ctx, o_key_pad, SHA256_BLOCK_LENGTH); + sha256_Update(&ctx, buf, SHA256_DIGEST_LENGTH); + sha256_Final(hmac, &ctx); } void hmac_sha512(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, const uint32_t msglen, uint8_t *hmac) @@ -40,7 +40,7 @@ void hmac_sha512(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, memset(buf, 0, SHA512_BLOCK_LENGTH); if (keylen > SHA512_BLOCK_LENGTH) { - SHA512_Raw(key, keylen, buf); + sha512_Raw(key, keylen, buf); } else { memcpy(buf, key, keylen); } @@ -50,13 +50,13 @@ void hmac_sha512(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, i_key_pad[i] = buf[i] ^ 0x36; } - SHA512_Init(&ctx); - SHA512_Update(&ctx, i_key_pad, SHA512_BLOCK_LENGTH); - SHA512_Update(&ctx, msg, msglen); - SHA512_Final(buf, &ctx); + sha512_Init(&ctx); + sha512_Update(&ctx, i_key_pad, SHA512_BLOCK_LENGTH); + sha512_Update(&ctx, msg, msglen); + sha512_Final(buf, &ctx); - SHA512_Init(&ctx); - SHA512_Update(&ctx, o_key_pad, SHA512_BLOCK_LENGTH); - SHA512_Update(&ctx, buf, SHA512_DIGEST_LENGTH); - SHA512_Final(hmac, &ctx); + sha512_Init(&ctx); + sha512_Update(&ctx, o_key_pad, SHA512_BLOCK_LENGTH); + sha512_Update(&ctx, buf, SHA512_DIGEST_LENGTH); + sha512_Final(hmac, &ctx); } diff --git a/sha2.c b/sha2.c index 13868f8af..f6f5a79c7 100644 --- a/sha2.c +++ b/sha2.c @@ -288,7 +288,7 @@ static const char *sha2_hex_digits = "0123456789abcdef"; /*** SHA-256: *********************************************************/ -void SHA256_Init(SHA256_CTX* context) { +void sha256_Init(SHA256_CTX* context) { if (context == (SHA256_CTX*)0) { return; } @@ -472,7 +472,7 @@ void SHA256_Transform(SHA256_CTX* context, const sha2_word32* data) { #endif /* SHA2_UNROLL_TRANSFORM */ -void SHA256_Update(SHA256_CTX* context, const sha2_byte *data, size_t len) { +void sha256_Update(SHA256_CTX* context, const sha2_byte *data, size_t len) { unsigned int freespace, usedspace; if (len == 0) { @@ -517,7 +517,7 @@ void SHA256_Update(SHA256_CTX* context, const sha2_byte *data, size_t len) { usedspace = freespace = 0; } -void SHA256_Final(sha2_byte digest[], SHA256_CTX* context) { +void sha256_Final(sha2_byte digest[], SHA256_CTX* context) { sha2_word32 *d = (sha2_word32*)digest; unsigned int usedspace; @@ -578,12 +578,12 @@ void SHA256_Final(sha2_byte digest[], SHA256_CTX* context) { usedspace = 0; } -char *SHA256_End(SHA256_CTX* context, char buffer[]) { +char *sha256_End(SHA256_CTX* context, char buffer[]) { sha2_byte digest[SHA256_DIGEST_LENGTH], *d = digest; int i; if (buffer != (char*)0) { - SHA256_Final(digest, context); + sha256_Final(digest, context); for (i = 0; i < SHA256_DIGEST_LENGTH; i++) { *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; @@ -598,24 +598,24 @@ char *SHA256_End(SHA256_CTX* context, char buffer[]) { return buffer; } -void SHA256_Raw(const sha2_byte* data, size_t len, uint8_t digest[SHA256_DIGEST_LENGTH]) { +void sha256_Raw(const sha2_byte* data, size_t len, uint8_t digest[SHA256_DIGEST_LENGTH]) { SHA256_CTX context; - SHA256_Init(&context); - SHA256_Update(&context, data, len); - SHA256_Final(digest, &context); + sha256_Init(&context); + sha256_Update(&context, data, len); + sha256_Final(digest, &context); } -char* SHA256_Data(const sha2_byte* data, size_t len, char digest[SHA256_DIGEST_STRING_LENGTH]) { +char* sha256_Data(const sha2_byte* data, size_t len, char digest[SHA256_DIGEST_STRING_LENGTH]) { SHA256_CTX context; - SHA256_Init(&context); - SHA256_Update(&context, data, len); - return SHA256_End(&context, digest); + sha256_Init(&context); + sha256_Update(&context, data, len); + return sha256_End(&context, digest); } /*** SHA-512: *********************************************************/ -void SHA512_Init(SHA512_CTX* context) { +void sha512_Init(SHA512_CTX* context) { if (context == (SHA512_CTX*)0) { return; } @@ -793,7 +793,7 @@ void SHA512_Transform(SHA512_CTX* context, const sha2_word64* data) { #endif /* SHA2_UNROLL_TRANSFORM */ -void SHA512_Update(SHA512_CTX* context, const sha2_byte *data, size_t len) { +void sha512_Update(SHA512_CTX* context, const sha2_byte *data, size_t len) { unsigned int freespace, usedspace; if (len == 0) { @@ -882,7 +882,7 @@ void SHA512_Last(SHA512_CTX* context) { SHA512_Transform(context, (sha2_word64*)context->buffer); } -void SHA512_Final(sha2_byte digest[], SHA512_CTX* context) { +void sha512_Final(sha2_byte digest[], SHA512_CTX* context) { sha2_word64 *d = (sha2_word64*)digest; /* If no digest buffer is passed, we don't bother doing this: */ @@ -908,12 +908,12 @@ void SHA512_Final(sha2_byte digest[], SHA512_CTX* context) { MEMSET_BZERO(context, sizeof(SHA512_CTX)); } -char *SHA512_End(SHA512_CTX* context, char buffer[]) { +char *sha512_End(SHA512_CTX* context, char buffer[]) { sha2_byte digest[SHA512_DIGEST_LENGTH], *d = digest; int i; if (buffer != (char*)0) { - SHA512_Final(digest, context); + sha512_Final(digest, context); for (i = 0; i < SHA512_DIGEST_LENGTH; i++) { *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; @@ -928,17 +928,17 @@ char *SHA512_End(SHA512_CTX* context, char buffer[]) { return buffer; } -void SHA512_Raw(const sha2_byte* data, size_t len, uint8_t digest[SHA512_DIGEST_LENGTH]) { +void sha512_Raw(const sha2_byte* data, size_t len, uint8_t digest[SHA512_DIGEST_LENGTH]) { SHA512_CTX context; - SHA512_Init(&context); - SHA512_Update(&context, data, len); - SHA512_Final(digest, &context); + sha512_Init(&context); + sha512_Update(&context, data, len); + sha512_Final(digest, &context); } -char* SHA512_Data(const sha2_byte* data, size_t len, char digest[SHA512_DIGEST_STRING_LENGTH]) { +char* sha512_Data(const sha2_byte* data, size_t len, char digest[SHA512_DIGEST_STRING_LENGTH]) { SHA512_CTX context; - SHA512_Init(&context); - SHA512_Update(&context, data, len); - return SHA512_End(&context, digest); + sha512_Init(&context); + sha512_Update(&context, data, len); + return sha512_End(&context, digest); } diff --git a/sha2.h b/sha2.h index c105d7078..318e5fe41 100644 --- a/sha2.h +++ b/sha2.h @@ -52,18 +52,18 @@ typedef struct _SHA512_CTX { uint8_t buffer[SHA512_BLOCK_LENGTH]; } SHA512_CTX; -void SHA256_Init(SHA256_CTX *); -void SHA256_Update(SHA256_CTX*, const uint8_t*, size_t); -void SHA256_Final(uint8_t[SHA256_DIGEST_LENGTH], SHA256_CTX*); -char* SHA256_End(SHA256_CTX*, char[SHA256_DIGEST_STRING_LENGTH]); -void SHA256_Raw(const uint8_t*, size_t, uint8_t[SHA256_DIGEST_LENGTH]); -char* SHA256_Data(const uint8_t*, size_t, char[SHA256_DIGEST_STRING_LENGTH]); +void sha256_Init(SHA256_CTX *); +void sha256_Update(SHA256_CTX*, const uint8_t*, size_t); +void sha256_Final(uint8_t[SHA256_DIGEST_LENGTH], SHA256_CTX*); +char* sha256_End(SHA256_CTX*, char[SHA256_DIGEST_STRING_LENGTH]); +void sha256_Raw(const uint8_t*, size_t, uint8_t[SHA256_DIGEST_LENGTH]); +char* sha256_Data(const uint8_t*, size_t, char[SHA256_DIGEST_STRING_LENGTH]); -void SHA512_Init(SHA512_CTX*); -void SHA512_Update(SHA512_CTX*, const uint8_t*, size_t); -void SHA512_Final(uint8_t[SHA512_DIGEST_LENGTH], SHA512_CTX*); -char* SHA512_End(SHA512_CTX*, char[SHA512_DIGEST_STRING_LENGTH]); -void SHA512_Raw(const uint8_t*, size_t, uint8_t[SHA512_DIGEST_LENGTH]); -char* SHA512_Data(const uint8_t*, size_t, char[SHA512_DIGEST_STRING_LENGTH]); +void sha512_Init(SHA512_CTX*); +void sha512_Update(SHA512_CTX*, const uint8_t*, size_t); +void sha512_Final(uint8_t[SHA512_DIGEST_LENGTH], SHA512_CTX*); +char* sha512_End(SHA512_CTX*, char[SHA512_DIGEST_STRING_LENGTH]); +void sha512_Raw(const uint8_t*, size_t, uint8_t[SHA512_DIGEST_LENGTH]); +char* sha512_Data(const uint8_t*, size_t, char[SHA512_DIGEST_STRING_LENGTH]); #endif diff --git a/tests.c b/tests.c index 0e876675f..76c70a9aa 100644 --- a/tests.c +++ b/tests.c @@ -210,7 +210,7 @@ END_TEST int generate_k_rfc6979(bignum256 *secret, const uint8_t *priv_key, const uint8_t *hash); #define test_deterministic(KEY, MSG, K) do { \ - SHA256_Raw((uint8_t *)MSG, strlen(MSG), buf); \ + sha256_Raw((uint8_t *)MSG, strlen(MSG), buf); \ res = generate_k_rfc6979(&k, fromhex(KEY), buf); \ ck_assert_int_eq(res, 0); \ bn_write_be(&k, buf); \ @@ -299,7 +299,7 @@ START_TEST(test_verify_speed) END_TEST #define test_aes(KEY, BLKLEN, IN, OUT) do { \ - SHA256_Raw((uint8_t *)KEY, strlen(KEY), key); \ + sha256_Raw((uint8_t *)KEY, strlen(KEY), key); \ aes_enc_key(key, 32, &ctx); \ memcpy(in, fromhex(IN), BLKLEN); \ aes_enc_blk(in, out, &ctx); \ From b08d44d39eb996e1557def0595f618393f1ebeca Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 19 Feb 2014 21:42:14 +0100 Subject: [PATCH 082/627] fix prefixes in internal functions as well --- sha2.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/sha2.c b/sha2.c index f6f5a79c7..670a4a79c 100644 --- a/sha2.c +++ b/sha2.c @@ -174,9 +174,9 @@ typedef uint64_t sha2_word64; /* Exactly 8 bytes */ * library -- they are intended for private internal visibility/use * only. */ -void SHA512_Last(SHA512_CTX*); -void SHA256_Transform(SHA256_CTX*, const sha2_word32*); -void SHA512_Transform(SHA512_CTX*, const sha2_word64*); +void sha512_Last(SHA512_CTX*); +void sha256_Transform(SHA256_CTX*, const sha2_word32*); +void sha512_Transform(SHA512_CTX*, const sha2_word64*); /*** SHA-XYZ INITIAL HASH VALUES AND CONSTANTS ************************/ @@ -334,7 +334,7 @@ void sha256_Init(SHA256_CTX* context) { (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ j++ -void SHA256_Transform(SHA256_CTX* context, const sha2_word32* data) { +void sha256_Transform(SHA256_CTX* context, const sha2_word32* data) { sha2_word32 a, b, c, d, e, f, g, h, s0, s1; sha2_word32 T1, *W256; int j; @@ -392,7 +392,7 @@ void SHA256_Transform(SHA256_CTX* context, const sha2_word32* data) { #else /* SHA2_UNROLL_TRANSFORM */ -void SHA256_Transform(SHA256_CTX* context, const sha2_word32* data) { +void sha256_Transform(SHA256_CTX* context, const sha2_word32* data) { sha2_word32 a, b, c, d, e, f, g, h, s0, s1; sha2_word32 T1, T2, *W256; int j; @@ -491,7 +491,7 @@ void sha256_Update(SHA256_CTX* context, const sha2_byte *data, size_t len) { context->bitcount += freespace << 3; len -= freespace; data += freespace; - SHA256_Transform(context, (sha2_word32*)context->buffer); + sha256_Transform(context, (sha2_word32*)context->buffer); } else { /* The buffer is not yet full */ MEMCPY_BCOPY(&context->buffer[usedspace], data, len); @@ -503,7 +503,7 @@ void sha256_Update(SHA256_CTX* context, const sha2_byte *data, size_t len) { } while (len >= SHA256_BLOCK_LENGTH) { /* Process as many complete blocks as we can */ - SHA256_Transform(context, (sha2_word32*)data); + sha256_Transform(context, (sha2_word32*)data); context->bitcount += SHA256_BLOCK_LENGTH << 3; len -= SHA256_BLOCK_LENGTH; data += SHA256_BLOCK_LENGTH; @@ -540,7 +540,7 @@ void sha256_Final(sha2_byte digest[], SHA256_CTX* context) { MEMSET_BZERO(&context->buffer[usedspace], SHA256_BLOCK_LENGTH - usedspace); } /* Do second-to-last transform: */ - SHA256_Transform(context, (sha2_word32*)context->buffer); + sha256_Transform(context, (sha2_word32*)context->buffer); /* And set-up for the last transform: */ MEMSET_BZERO(context->buffer, SHA256_SHORT_BLOCK_LENGTH); @@ -557,7 +557,7 @@ void sha256_Final(sha2_byte digest[], SHA256_CTX* context) { *t = context->bitcount; /* Final transform: */ - SHA256_Transform(context, (sha2_word32*)context->buffer); + sha256_Transform(context, (sha2_word32*)context->buffer); #if BYTE_ORDER == LITTLE_ENDIAN { @@ -660,7 +660,7 @@ void sha512_Init(SHA512_CTX* context) { (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \ j++ -void SHA512_Transform(SHA512_CTX* context, const sha2_word64* data) { +void sha512_Transform(SHA512_CTX* context, const sha2_word64* data) { sha2_word64 a, b, c, d, e, f, g, h, s0, s1; sha2_word64 T1, *W512 = (sha2_word64*)context->buffer; int j; @@ -715,7 +715,7 @@ void SHA512_Transform(SHA512_CTX* context, const sha2_word64* data) { #else /* SHA2_UNROLL_TRANSFORM */ -void SHA512_Transform(SHA512_CTX* context, const sha2_word64* data) { +void sha512_Transform(SHA512_CTX* context, const sha2_word64* data) { sha2_word64 a, b, c, d, e, f, g, h, s0, s1; sha2_word64 T1, T2, *W512 = (sha2_word64*)context->buffer; int j; @@ -812,7 +812,7 @@ void sha512_Update(SHA512_CTX* context, const sha2_byte *data, size_t len) { ADDINC128(context->bitcount, freespace << 3); len -= freespace; data += freespace; - SHA512_Transform(context, (sha2_word64*)context->buffer); + sha512_Transform(context, (sha2_word64*)context->buffer); } else { /* The buffer is not yet full */ MEMCPY_BCOPY(&context->buffer[usedspace], data, len); @@ -824,7 +824,7 @@ void sha512_Update(SHA512_CTX* context, const sha2_byte *data, size_t len) { } while (len >= SHA512_BLOCK_LENGTH) { /* Process as many complete blocks as we can */ - SHA512_Transform(context, (sha2_word64*)data); + sha512_Transform(context, (sha2_word64*)data); ADDINC128(context->bitcount, SHA512_BLOCK_LENGTH << 3); len -= SHA512_BLOCK_LENGTH; data += SHA512_BLOCK_LENGTH; @@ -838,7 +838,7 @@ void sha512_Update(SHA512_CTX* context, const sha2_byte *data, size_t len) { usedspace = freespace = 0; } -void SHA512_Last(SHA512_CTX* context) { +void sha512_Last(SHA512_CTX* context) { unsigned int usedspace; usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH; @@ -859,7 +859,7 @@ void SHA512_Last(SHA512_CTX* context) { MEMSET_BZERO(&context->buffer[usedspace], SHA512_BLOCK_LENGTH - usedspace); } /* Do second-to-last transform: */ - SHA512_Transform(context, (sha2_word64*)context->buffer); + sha512_Transform(context, (sha2_word64*)context->buffer); /* And set-up for the last transform: */ MEMSET_BZERO(context->buffer, SHA512_BLOCK_LENGTH - 2); @@ -879,7 +879,7 @@ void SHA512_Last(SHA512_CTX* context) { *t = context->bitcount[0]; /* Final transform: */ - SHA512_Transform(context, (sha2_word64*)context->buffer); + sha512_Transform(context, (sha2_word64*)context->buffer); } void sha512_Final(sha2_byte digest[], SHA512_CTX* context) { @@ -887,7 +887,7 @@ void sha512_Final(sha2_byte digest[], SHA512_CTX* context) { /* If no digest buffer is passed, we don't bother doing this: */ if (digest != (sha2_byte*)0) { - SHA512_Last(context); + sha512_Last(context); /* Save the hash data for output: */ #if BYTE_ORDER == LITTLE_ENDIAN From 18dea222139cc3567e30388df3541dd77058c8bb Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 21 Feb 2014 19:41:33 +0100 Subject: [PATCH 083/627] get rid of bip32 versions, it's a mess :( --- bip32.c | 19 +++---------------- bip32.h | 10 ++++------ tests.c | 6 +++--- 3 files changed, 10 insertions(+), 25 deletions(-) diff --git a/bip32.c b/bip32.c index 18bbc4e2a..cd78422b1 100644 --- a/bip32.c +++ b/bip32.c @@ -7,11 +7,8 @@ #include "sha2.h" #include "ripemd160.h" -void hdnode_from_xpub(uint8_t version_byte, uint32_t version_private, uint32_t version_public, uint32_t depth, uint32_t fingerprint, uint32_t child_num, uint8_t *chain_code, uint8_t *public_key, HDNode *out) +void hdnode_from_xpub(uint8_t version_byte, uint32_t depth, uint32_t fingerprint, uint32_t child_num, uint8_t *chain_code, uint8_t *public_key, HDNode *out) { - out->version = version_public; - out->version_private = version_private; - out->version_public = version_public; out->depth = depth; out->fingerprint = fingerprint; out->child_num = child_num; @@ -22,11 +19,8 @@ void hdnode_from_xpub(uint8_t version_byte, uint32_t version_private, uint32_t v hdnode_fill_address(out); } -void hdnode_from_xprv(uint8_t version_byte, uint32_t version_private, uint32_t version_public, uint32_t depth, uint32_t fingerprint, uint32_t child_num, uint8_t *chain_code, uint8_t *private_key, HDNode *out) +void hdnode_from_xprv(uint8_t version_byte, uint32_t depth, uint32_t fingerprint, uint32_t child_num, uint8_t *chain_code, uint8_t *private_key, HDNode *out) { - out->version = version_private; - out->version_private = version_private; - out->version_public = version_public; out->depth = depth; out->fingerprint = fingerprint; out->child_num = child_num; @@ -37,12 +31,9 @@ void hdnode_from_xprv(uint8_t version_byte, uint32_t version_private, uint32_t v hdnode_fill_address(out); } -void hdnode_from_seed(uint8_t version_byte, uint32_t version_private, uint32_t version_public, uint8_t *seed, int seed_len, HDNode *out) +void hdnode_from_seed(uint8_t version_byte, uint8_t *seed, int seed_len, HDNode *out) { uint8_t I[32 + 32]; - out->version = version_private; - out->version_private = version_private; - out->version_public = version_public; out->depth = 0; out->fingerprint = 0x00000000; out->child_num = 0; @@ -61,8 +52,6 @@ int hdnode_private_ckd(HDNode *inout, uint32_t i) uint8_t fingerprint[32]; bignum256 a, b; - inout->version = inout->version_private; - if (i & 0x80000000) { // private derivation data[0] = 0; memcpy(data + 1, inout->private_key, 32); @@ -102,8 +91,6 @@ int hdnode_public_ckd(HDNode *inout, uint32_t i) curve_point a, b; bignum256 c; - inout->version = inout->version_public; - if (i & 0x80000000) { // private derivation return 0; } else { // public derivation diff --git a/bip32.h b/bip32.h index 4ef0c96c2..60f2fea05 100644 --- a/bip32.h +++ b/bip32.h @@ -4,7 +4,7 @@ #include typedef struct { - uint32_t version; +// uint32_t version; uint32_t depth; uint32_t fingerprint; uint32_t child_num; @@ -13,15 +13,13 @@ typedef struct { uint8_t public_key[33]; char address[35]; uint8_t version_byte; - uint32_t version_private; - uint32_t version_public; } HDNode; -void hdnode_from_xpub(uint8_t version_byte, uint32_t version_private, uint32_t version_public, uint32_t depth, uint32_t fingerprint, uint32_t child_num, uint8_t *chain_code, uint8_t *public_key, HDNode *out); +void hdnode_from_xpub(uint8_t version_byte, uint32_t depth, uint32_t fingerprint, uint32_t child_num, uint8_t *chain_code, uint8_t *public_key, HDNode *out); -void hdnode_from_xprv(uint8_t version_byte, uint32_t version_private, uint32_t version_public, uint32_t depth, uint32_t fingerprint, uint32_t child_num, uint8_t *chain_code, uint8_t *private_key, HDNode *out); +void hdnode_from_xprv(uint8_t version_byte, uint32_t depth, uint32_t fingerprint, uint32_t child_num, uint8_t *chain_code, uint8_t *private_key, HDNode *out); -void hdnode_from_seed(uint8_t version_byte, uint32_t version_private, uint32_t version_public, uint8_t *seed, int seed_len, HDNode *out); +void hdnode_from_seed(uint8_t version_byte, uint8_t *seed, int seed_len, HDNode *out); #define hdnode_private_ckd_prime(X, I) hdnode_private_ckd((X), ((I) | 0x80000000)) diff --git a/tests.c b/tests.c index 76c70a9aa..cab788f7a 100644 --- a/tests.c +++ b/tests.c @@ -80,7 +80,7 @@ START_TEST(test_bip32_vector_1) HDNode node; // init m - hdnode_from_seed(0x00, 0x0488ADE4, 0x0488B21E, fromhex("000102030405060708090a0b0c0d0e0f"), 16, &node); + hdnode_from_seed(0x00, fromhex("000102030405060708090a0b0c0d0e0f"), 16, &node); // [Chain m] ck_assert_int_eq(node.fingerprint, 0x00000000); @@ -138,7 +138,7 @@ START_TEST(test_bip32_vector_2) int r; // init m - hdnode_from_seed(0x00, 0x0488ADE4, 0x0488B21E, fromhex("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), 64, &node); + hdnode_from_seed(0x00, fromhex("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), 64, &node); // [Chain m] ck_assert_int_eq(node.fingerprint, 0x00000000); @@ -193,7 +193,7 @@ START_TEST(test_bip32_vector_2) ck_assert_str_eq(node.address, "14UKfRV9ZPUp6ZC9PLhqbRtxdihW9em3xt"); // init m - hdnode_from_seed(0x00, 0x0488ADE4, 0x0488B21E, fromhex("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), 64, &node); + hdnode_from_seed(0x00, fromhex("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), 64, &node); // test public derivation // [Chain m/0] From 8c47b572dff4441d83d17d152e90c604713aac2f Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 21 Feb 2014 20:30:22 +0100 Subject: [PATCH 084/627] new test to compare private and public branch of bip32 --- tests.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/tests.c b/tests.c index cab788f7a..878a98ff1 100644 --- a/tests.c +++ b/tests.c @@ -207,6 +207,35 @@ START_TEST(test_bip32_vector_2) } END_TEST +START_TEST(test_bip32_compare) +{ + HDNode node1, node2, node3; + int i, r; + hdnode_from_seed(0x00, fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, &node1); + hdnode_from_seed(0x00, fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, &node2); + for (i = 0; i < 300; i++) { + memcpy(&node3, &node1, sizeof(HDNode)); + r = hdnode_private_ckd(&node1, i); ck_assert_int_eq(r, 1); + r = hdnode_public_ckd(&node2, i); ck_assert_int_eq(r, 1); + r = hdnode_public_ckd(&node3, i); ck_assert_int_eq(r, 1); + ck_assert_int_eq(node1.depth, node2.depth); + ck_assert_int_eq(node1.depth, node3.depth); + ck_assert_int_eq(node1.fingerprint, node2.fingerprint); + ck_assert_int_eq(node1.fingerprint, node3.fingerprint); + ck_assert_int_eq(node1.child_num, node2.child_num); + ck_assert_int_eq(node1.child_num, node3.child_num); + ck_assert_mem_eq(node1.chain_code, node2.chain_code, 32); + ck_assert_mem_eq(node1.chain_code, node3.chain_code, 32); + ck_assert_mem_eq(node2.private_key, fromhex("0000000000000000000000000000000000000000000000000000000000000000"), 32); + ck_assert_mem_eq(node3.private_key, fromhex("0000000000000000000000000000000000000000000000000000000000000000"), 32); + ck_assert_mem_eq(node1.public_key, node2.public_key, 33); + ck_assert_mem_eq(node1.public_key, node3.public_key, 33); + ck_assert_str_eq(node1.address, node2.address); + ck_assert_str_eq(node1.address, node3.address); + } +} +END_TEST + int generate_k_rfc6979(bignum256 *secret, const uint8_t *priv_key, const uint8_t *hash); #define test_deterministic(KEY, MSG, K) do { \ @@ -612,6 +641,7 @@ Suite *test_suite(void) tc = tcase_create("bip32"); tcase_add_test(tc, test_bip32_vector_1); tcase_add_test(tc, test_bip32_vector_2); + tcase_add_test(tc, test_bip32_compare); suite_add_tcase(s, tc); tc = tcase_create("rfc6979"); From d5e1ff8be80b54f7d07ecd8a3a57820b022af3d9 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 21 Feb 2014 22:51:49 +0100 Subject: [PATCH 085/627] remove version_byte and address from bip32 --- bip32.c | 19 +++---------------- bip32.h | 9 +++------ tests.c | 25 +++++-------------------- 3 files changed, 11 insertions(+), 42 deletions(-) diff --git a/bip32.c b/bip32.c index cd78422b1..f0de3d18c 100644 --- a/bip32.c +++ b/bip32.c @@ -7,7 +7,7 @@ #include "sha2.h" #include "ripemd160.h" -void hdnode_from_xpub(uint8_t version_byte, uint32_t depth, uint32_t fingerprint, uint32_t child_num, uint8_t *chain_code, uint8_t *public_key, HDNode *out) +void hdnode_from_xpub(uint32_t depth, uint32_t fingerprint, uint32_t child_num, uint8_t *chain_code, uint8_t *public_key, HDNode *out) { out->depth = depth; out->fingerprint = fingerprint; @@ -15,11 +15,9 @@ void hdnode_from_xpub(uint8_t version_byte, uint32_t depth, uint32_t fingerprint memcpy(out->chain_code, chain_code, 32); memset(out->private_key, 0, 32); memcpy(out->public_key, public_key, 33); - out->version_byte = version_byte; - hdnode_fill_address(out); } -void hdnode_from_xprv(uint8_t version_byte, uint32_t depth, uint32_t fingerprint, uint32_t child_num, uint8_t *chain_code, uint8_t *private_key, HDNode *out) +void hdnode_from_xprv(uint32_t depth, uint32_t fingerprint, uint32_t child_num, uint8_t *chain_code, uint8_t *private_key, HDNode *out) { out->depth = depth; out->fingerprint = fingerprint; @@ -27,11 +25,9 @@ void hdnode_from_xprv(uint8_t version_byte, uint32_t depth, uint32_t fingerprint memcpy(out->chain_code, chain_code, 32); memcpy(out->private_key, private_key, 32); hdnode_fill_public_key(out); - out->version_byte = version_byte; - hdnode_fill_address(out); } -void hdnode_from_seed(uint8_t version_byte, uint8_t *seed, int seed_len, HDNode *out) +void hdnode_from_seed(uint8_t *seed, int seed_len, HDNode *out) { uint8_t I[32 + 32]; out->depth = 0; @@ -41,8 +37,6 @@ void hdnode_from_seed(uint8_t version_byte, uint8_t *seed, int seed_len, HDNode memcpy(out->chain_code, I + 32, 32); memcpy(out->private_key, I, 32); hdnode_fill_public_key(out); - out->version_byte = version_byte; - hdnode_fill_address(out); } int hdnode_private_ckd(HDNode *inout, uint32_t i) @@ -78,7 +72,6 @@ int hdnode_private_ckd(HDNode *inout, uint32_t i) bn_write_be(&a, inout->private_key); hdnode_fill_public_key(inout); - hdnode_fill_address(inout); return 1; } @@ -118,7 +111,6 @@ int hdnode_public_ckd(HDNode *inout, uint32_t i) inout->depth++; inout->child_num = i; - hdnode_fill_address(inout); return 1; } @@ -126,8 +118,3 @@ void hdnode_fill_public_key(HDNode *node) { ecdsa_get_public_key33(node->private_key, node->public_key); } - -void hdnode_fill_address(HDNode *node) -{ - ecdsa_get_address(node->public_key, node->version_byte, node->address); -} diff --git a/bip32.h b/bip32.h index 60f2fea05..051596d05 100644 --- a/bip32.h +++ b/bip32.h @@ -4,22 +4,19 @@ #include typedef struct { -// uint32_t version; uint32_t depth; uint32_t fingerprint; uint32_t child_num; uint8_t chain_code[32]; uint8_t private_key[32]; uint8_t public_key[33]; - char address[35]; - uint8_t version_byte; } HDNode; -void hdnode_from_xpub(uint8_t version_byte, uint32_t depth, uint32_t fingerprint, uint32_t child_num, uint8_t *chain_code, uint8_t *public_key, HDNode *out); +void hdnode_from_xpub(uint32_t depth, uint32_t fingerprint, uint32_t child_num, uint8_t *chain_code, uint8_t *public_key, HDNode *out); -void hdnode_from_xprv(uint8_t version_byte, uint32_t depth, uint32_t fingerprint, uint32_t child_num, uint8_t *chain_code, uint8_t *private_key, HDNode *out); +void hdnode_from_xprv(uint32_t depth, uint32_t fingerprint, uint32_t child_num, uint8_t *chain_code, uint8_t *private_key, HDNode *out); -void hdnode_from_seed(uint8_t version_byte, uint8_t *seed, int seed_len, HDNode *out); +void hdnode_from_seed(uint8_t *seed, int seed_len, HDNode *out); #define hdnode_private_ckd_prime(X, I) hdnode_private_ckd((X), ((I) | 0x80000000)) diff --git a/tests.c b/tests.c index 878a98ff1..9d92fead4 100644 --- a/tests.c +++ b/tests.c @@ -80,14 +80,13 @@ START_TEST(test_bip32_vector_1) HDNode node; // init m - hdnode_from_seed(0x00, fromhex("000102030405060708090a0b0c0d0e0f"), 16, &node); + hdnode_from_seed(fromhex("000102030405060708090a0b0c0d0e0f"), 16, &node); // [Chain m] ck_assert_int_eq(node.fingerprint, 0x00000000); ck_assert_mem_eq(node.chain_code, fromhex("873dff81c02f525623fd1fe5167eac3a55a049de3d314bb42ee227ffed37d508"), 32); ck_assert_mem_eq(node.private_key, fromhex("e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35"), 32); ck_assert_mem_eq(node.public_key, fromhex("0339a36013301597daef41fbe593a02cc513d0b55527ec2df1050e2e8ff49c85c2"), 33); - ck_assert_str_eq(node.address, "15mKKb2eos1hWa6tisdPwwDC1a5J1y9nma"); // [Chain m/0'] hdnode_private_ckd_prime(&node, 0); @@ -95,7 +94,6 @@ START_TEST(test_bip32_vector_1) ck_assert_mem_eq(node.chain_code, fromhex("47fdacbd0f1097043b78c63c20c34ef4ed9a111d980047ad16282c7ae6236141"), 32); ck_assert_mem_eq(node.private_key, fromhex("edb2e14f9ee77d26dd93b4ecede8d16ed408ce149b6cd80b0715a2d911a0afea"), 32); ck_assert_mem_eq(node.public_key, fromhex("035a784662a4a20a65bf6aab9ae98a6c068a81c52e4b032c0fb5400c706cfccc56"), 33); - ck_assert_str_eq(node.address, "19Q2WoS5hSS6T8GjhK8KZLMgmWaq4neXrh"); // [Chain m/0'/1] hdnode_private_ckd(&node, 1); @@ -103,7 +101,6 @@ START_TEST(test_bip32_vector_1) ck_assert_mem_eq(node.chain_code, fromhex("2a7857631386ba23dacac34180dd1983734e444fdbf774041578e9b6adb37c19"), 32); ck_assert_mem_eq(node.private_key, fromhex("3c6cb8d0f6a264c91ea8b5030fadaa8e538b020f0a387421a12de9319dc93368"), 32); ck_assert_mem_eq(node.public_key, fromhex("03501e454bf00751f24b1b489aa925215d66af2234e3891c3b21a52bedb3cd711c"), 33); - ck_assert_str_eq(node.address, "1JQheacLPdM5ySCkrZkV66G2ApAXe1mqLj"); // [Chain m/0'/1/2'] hdnode_private_ckd_prime(&node, 2); @@ -111,7 +108,6 @@ START_TEST(test_bip32_vector_1) ck_assert_mem_eq(node.chain_code, fromhex("04466b9cc8e161e966409ca52986c584f07e9dc81f735db683c3ff6ec7b1503f"), 32); ck_assert_mem_eq(node.private_key, fromhex("cbce0d719ecf7431d88e6a89fa1483e02e35092af60c042b1df2ff59fa424dca"), 32); ck_assert_mem_eq(node.public_key, fromhex("0357bfe1e341d01c69fe5654309956cbea516822fba8a601743a012a7896ee8dc2"), 33); - ck_assert_str_eq(node.address, "1NjxqbA9aZWnh17q1UW3rB4EPu79wDXj7x"); // [Chain m/0'/1/2'/2] hdnode_private_ckd(&node, 2); @@ -119,7 +115,6 @@ START_TEST(test_bip32_vector_1) ck_assert_mem_eq(node.chain_code, fromhex("cfb71883f01676f587d023cc53a35bc7f88f724b1f8c2892ac1275ac822a3edd"), 32); ck_assert_mem_eq(node.private_key, fromhex("0f479245fb19a38a1954c5c7c0ebab2f9bdfd96a17563ef28a6a4b1a2a764ef4"), 32); ck_assert_mem_eq(node.public_key, fromhex("02e8445082a72f29b75ca48748a914df60622a609cacfce8ed0e35804560741d29"), 33); - ck_assert_str_eq(node.address, "1LjmJcdPnDHhNTUgrWyhLGnRDKxQjoxAgt"); // [Chain m/0'/1/2'/2/1000000000] hdnode_private_ckd(&node, 1000000000); @@ -127,7 +122,6 @@ START_TEST(test_bip32_vector_1) ck_assert_mem_eq(node.chain_code, fromhex("c783e67b921d2beb8f6b389cc646d7263b4145701dadd2161548a8b078e65e9e"), 32); ck_assert_mem_eq(node.private_key, fromhex("471b76e389e528d6de6d816857e012c5455051cad6660850e58372a6c3e6e7c8"), 32); ck_assert_mem_eq(node.public_key, fromhex("022a471424da5e657499d1ff51cb43c47481a03b1e77f951fe64cec9f5a48f7011"), 33); - ck_assert_str_eq(node.address, "1LZiqrop2HGR4qrH1ULZPyBpU6AUP49Uam"); } END_TEST @@ -138,14 +132,13 @@ START_TEST(test_bip32_vector_2) int r; // init m - hdnode_from_seed(0x00, fromhex("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), 64, &node); + hdnode_from_seed(fromhex("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), 64, &node); // [Chain m] ck_assert_int_eq(node.fingerprint, 0x00000000); ck_assert_mem_eq(node.chain_code, fromhex("60499f801b896d83179a4374aeb7822aaeaceaa0db1f85ee3e904c4defbd9689"), 32); ck_assert_mem_eq(node.private_key, fromhex("4b03d6fc340455b363f51020ad3ecca4f0850280cf436c70c727923f6db46c3e"), 32); ck_assert_mem_eq(node.public_key, fromhex("03cbcaa9c98c877a26977d00825c956a238e8dddfbd322cce4f74b0b5bd6ace4a7"), 33); - ck_assert_str_eq(node.address, "1JEoxevbLLG8cVqeoGKQiAwoWbNYSUyYjg"); // [Chain m/0] r = hdnode_private_ckd(&node, 0); @@ -154,7 +147,6 @@ START_TEST(test_bip32_vector_2) ck_assert_mem_eq(node.chain_code, fromhex("f0909affaa7ee7abe5dd4e100598d4dc53cd709d5a5c2cac40e7412f232f7c9c"), 32); ck_assert_mem_eq(node.private_key, fromhex("abe74a98f6c7eabee0428f53798f0ab8aa1bd37873999041703c742f15ac7e1e"), 32); ck_assert_mem_eq(node.public_key, fromhex("02fc9e5af0ac8d9b3cecfe2a888e2117ba3d089d8585886c9c826b6b22a98d12ea"), 33); - ck_assert_str_eq(node.address, "19EuDJdgfRkwCmRzbzVBHZWQG9QNWhftbZ"); // [Chain m/0/2147483647'] r = hdnode_private_ckd_prime(&node, 2147483647); @@ -163,7 +155,6 @@ START_TEST(test_bip32_vector_2) ck_assert_mem_eq(node.chain_code, fromhex("be17a268474a6bb9c61e1d720cf6215e2a88c5406c4aee7b38547f585c9a37d9"), 32); ck_assert_mem_eq(node.private_key, fromhex("877c779ad9687164e9c2f4f0f4ff0340814392330693ce95a58fe18fd52e6e93"), 32); ck_assert_mem_eq(node.public_key, fromhex("03c01e7425647bdefa82b12d9bad5e3e6865bee0502694b94ca58b666abc0a5c3b"), 33); - ck_assert_str_eq(node.address, "1Lke9bXGhn5VPrBuXgN12uGUphrttUErmk"); // [Chain m/0/2147483647'/1] r = hdnode_private_ckd(&node, 1); @@ -172,7 +163,6 @@ START_TEST(test_bip32_vector_2) ck_assert_mem_eq(node.chain_code, fromhex("f366f48f1ea9f2d1d3fe958c95ca84ea18e4c4ddb9366c336c927eb246fb38cb"), 32); ck_assert_mem_eq(node.private_key, fromhex("704addf544a06e5ee4bea37098463c23613da32020d604506da8c0518e1da4b7"), 32); ck_assert_mem_eq(node.public_key, fromhex("03a7d1d856deb74c508e05031f9895dab54626251b3806e16b4bd12e781a7df5b9"), 33); - ck_assert_str_eq(node.address, "1BxrAr2pHpeBheusmd6fHDP2tSLAUa3qsW"); // [Chain m/0/2147483647'/1/2147483646'] r = hdnode_private_ckd_prime(&node, 2147483646); @@ -181,7 +171,6 @@ START_TEST(test_bip32_vector_2) ck_assert_mem_eq(node.chain_code, fromhex("637807030d55d01f9a0cb3a7839515d796bd07706386a6eddf06cc29a65a0e29"), 32); ck_assert_mem_eq(node.private_key, fromhex("f1c7c871a54a804afe328b4c83a1c33b8e5ff48f5087273f04efa83b247d6a2d"), 32); ck_assert_mem_eq(node.public_key, fromhex("02d2b36900396c9282fa14628566582f206a5dd0bcc8d5e892611806cafb0301f0"), 33); - ck_assert_str_eq(node.address, "15XVotxCAV7sRx1PSCkQNsGw3W9jT9A94R"); // [Chain m/0/2147483647'/1/2147483646'/2] r = hdnode_private_ckd(&node, 2); @@ -190,10 +179,9 @@ START_TEST(test_bip32_vector_2) ck_assert_mem_eq(node.chain_code, fromhex("9452b549be8cea3ecb7a84bec10dcfd94afe4d129ebfd3b3cb58eedf394ed271"), 32); ck_assert_mem_eq(node.private_key, fromhex("bb7d39bdb83ecf58f2fd82b6d918341cbef428661ef01ab97c28a4842125ac23"), 32); ck_assert_mem_eq(node.public_key, fromhex("024d902e1a2fc7a8755ab5b694c575fce742c48d9ff192e63df5193e4c7afe1f9c"), 33); - ck_assert_str_eq(node.address, "14UKfRV9ZPUp6ZC9PLhqbRtxdihW9em3xt"); // init m - hdnode_from_seed(0x00, fromhex("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), 64, &node); + hdnode_from_seed(fromhex("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), 64, &node); // test public derivation // [Chain m/0] @@ -203,7 +191,6 @@ START_TEST(test_bip32_vector_2) ck_assert_mem_eq(node.chain_code, fromhex("f0909affaa7ee7abe5dd4e100598d4dc53cd709d5a5c2cac40e7412f232f7c9c"), 32); ck_assert_mem_eq(node.private_key, fromhex("0000000000000000000000000000000000000000000000000000000000000000"), 32); ck_assert_mem_eq(node.public_key, fromhex("02fc9e5af0ac8d9b3cecfe2a888e2117ba3d089d8585886c9c826b6b22a98d12ea"), 33); - ck_assert_str_eq(node.address, "19EuDJdgfRkwCmRzbzVBHZWQG9QNWhftbZ"); } END_TEST @@ -211,8 +198,8 @@ START_TEST(test_bip32_compare) { HDNode node1, node2, node3; int i, r; - hdnode_from_seed(0x00, fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, &node1); - hdnode_from_seed(0x00, fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, &node2); + hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, &node1); + hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, &node2); for (i = 0; i < 300; i++) { memcpy(&node3, &node1, sizeof(HDNode)); r = hdnode_private_ckd(&node1, i); ck_assert_int_eq(r, 1); @@ -230,8 +217,6 @@ START_TEST(test_bip32_compare) ck_assert_mem_eq(node3.private_key, fromhex("0000000000000000000000000000000000000000000000000000000000000000"), 32); ck_assert_mem_eq(node1.public_key, node2.public_key, 33); ck_assert_mem_eq(node1.public_key, node3.public_key, 33); - ck_assert_str_eq(node1.address, node2.address); - ck_assert_str_eq(node1.address, node3.address); } } END_TEST From b5ceb14f8df9895ba721a9c2c22d1e4348e872b6 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 21 Feb 2014 23:33:14 +0100 Subject: [PATCH 086/627] extract ecdsa_get_pubkeyhash --- ecdsa.c | 18 ++++++++++++------ ecdsa.h | 1 + 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/ecdsa.c b/ecdsa.c index b373f3841..748a578ce 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -333,6 +333,17 @@ void ecdsa_get_public_key65(const uint8_t *priv_key, uint8_t *pub_key) bn_write_be(&R.y, pub_key + 33); } +void ecdsa_get_pubkeyhash(const uint8_t *pub_key, uint8_t *pubkeyhash) +{ + uint8_t h[32]; + if (pub_key[0] == 0x04) { + sha256_Raw(pub_key, 65, h); + } else { + sha256_Raw(pub_key, 33, h); + } + ripemd160(h, 32, pubkeyhash); +} + void ecdsa_get_address(const uint8_t *pub_key, uint8_t version, char *addr) { const char code[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; @@ -342,13 +353,8 @@ void ecdsa_get_address(const uint8_t *pub_key, uint8_t version, char *addr) bignum256 c; int i, l; - if (pub_key[0] == 0x04) { - sha256_Raw(pub_key, 65, a); - } else { - sha256_Raw(pub_key, 33, a); - } b[0] = version; - ripemd160(a, 32, b + 1); + ecdsa_get_pubkeyhash(pub_key, b + 1); sha256_Raw(b, 21, a); sha256_Raw(a, 32, a); diff --git a/ecdsa.h b/ecdsa.h index 956a310ab..8097c5288 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -43,6 +43,7 @@ int ecdsa_sign_double(const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_ int ecdsa_sign_digest(const uint8_t *priv_key, const uint8_t *digest, uint8_t *sig); void ecdsa_get_public_key33(const uint8_t *priv_key, uint8_t *pub_key); void ecdsa_get_public_key65(const uint8_t *priv_key, uint8_t *pub_key); +void ecdsa_get_pubkeyhash(const uint8_t *pub_key, uint8_t *pubkeyhash); void ecdsa_get_address(const uint8_t *pub_key, uint8_t version, char *addr); int ecdsa_address_decode(const char *addr, uint8_t *out); int ecdsa_read_pubkey(const uint8_t *pub_key, curve_point *pub); From 10c42633fc2b6b04b6f32c95e44da5175af99f63 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 7 Mar 2014 20:11:50 +0100 Subject: [PATCH 087/627] add function to retrieve mnemonic wordlist --- bip39.c | 5 +++++ bip39.h | 2 ++ 2 files changed, 7 insertions(+) diff --git a/bip39.c b/bip39.c index 82962658b..1fc8c61d5 100644 --- a/bip39.c +++ b/bip39.c @@ -73,3 +73,8 @@ void mnemonic_to_seed(const char *mnemonic, const char *passphrase, uint8_t seed saltlen += 8; pbkdf2((const uint8_t *)mnemonic, strlen(mnemonic), salt, saltlen, PBKDF2_ROUNDS, seed, 512 / 8); } + +const char **mnemonic_wordlist(void) +{ + return wordlist; +} diff --git a/bip39.h b/bip39.h index e9c2faa1f..b9cbcf4f1 100644 --- a/bip39.h +++ b/bip39.h @@ -9,4 +9,6 @@ const char *mnemonic_from_data(const uint8_t *data, int len); void mnemonic_to_seed(const char *mnemonic, const char *passphrase, uint8_t seed[512 / 8]); +const char **mnemonic_wordlist(void); + #endif From 393c298c35498fd73cab56ae0f0d26ce8ddb86d3 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 11 Mar 2014 20:09:15 +0100 Subject: [PATCH 088/627] add progress_callback to mnemonic/pbkdf2 functions --- bip39.c | 28 +++++++++++++++++----------- bip39.h | 4 +++- pbkdf2.c | 5 ++++- pbkdf2.h | 2 +- tests.c | 10 +++++----- 5 files changed, 30 insertions(+), 19 deletions(-) diff --git a/bip39.c b/bip39.c index 1fc8c61d5..42ef82798 100644 --- a/bip39.c +++ b/bip39.c @@ -11,11 +11,11 @@ const char *mnemonic_generate(int strength) { - int i; - static uint32_t data[16]; if (strength % 32 || strength < 128 || strength > 256) { return 0; } + int i; + static uint32_t data[16]; for (i = 0; i < 16; i++) { data[i] = random32(); } @@ -24,23 +24,21 @@ const char *mnemonic_generate(int strength) const char *mnemonic_from_data(const uint8_t *data, int len) { - int i, j; - static uint8_t hash[32]; - static char bits[256 + 8]; - static char mnemo[24 * 10]; - if (len % 4 || len < 16 || len > 32) { return 0; } - sha256_Raw((const uint8_t *)data, len, hash); - + int i, j; + char bits[256 + 8]; for (i = 0; i < len; i++) { for (j = 0; j < 8; j++) { bits[8 * i + j] = (data[i] & (1 << (7 - j))) > 0; } } + uint8_t hash[32]; + sha256_Raw((const uint8_t *)data, len, hash); + char hlen = len / 4; for (i = 0; i < hlen; i++) { char c = (hash[0] & (1 << (7 - i))) > 0; @@ -48,6 +46,7 @@ const char *mnemonic_from_data(const uint8_t *data, int len) } int mlen = len * 3 / 4; + static char mnemo[24 * 10]; char *p = mnemo; for (i = 0; i < mlen; i++) { @@ -64,14 +63,21 @@ const char *mnemonic_from_data(const uint8_t *data, int len) return mnemo; } -void mnemonic_to_seed(const char *mnemonic, const char *passphrase, uint8_t seed[512 / 8]) +int mnemonic_check(const char *mnemonic) +{ + // TODO: add proper check + (void)mnemonic; + return 1; +} + +void mnemonic_to_seed(const char *mnemonic, const char *passphrase, uint8_t seed[512 / 8], void (*progress_callback)(uint32_t current, uint32_t total)) { static uint8_t salt[8 + 256 + 4]; int saltlen = strlen(passphrase); memcpy(salt, "mnemonic", 8); memcpy(salt + 8, passphrase, saltlen); saltlen += 8; - pbkdf2((const uint8_t *)mnemonic, strlen(mnemonic), salt, saltlen, PBKDF2_ROUNDS, seed, 512 / 8); + pbkdf2((const uint8_t *)mnemonic, strlen(mnemonic), salt, saltlen, PBKDF2_ROUNDS, seed, 512 / 8, progress_callback); } const char **mnemonic_wordlist(void) diff --git a/bip39.h b/bip39.h index b9cbcf4f1..1f77c8496 100644 --- a/bip39.h +++ b/bip39.h @@ -7,7 +7,9 @@ const char *mnemonic_generate(int strength); // strength in bits const char *mnemonic_from_data(const uint8_t *data, int len); -void mnemonic_to_seed(const char *mnemonic, const char *passphrase, uint8_t seed[512 / 8]); +int mnemonic_check(const char *mnemonic); + +void mnemonic_to_seed(const char *mnemonic, const char *passphrase, uint8_t seed[512 / 8], void (*progress_callback)(uint32_t current, uint32_t total)); const char **mnemonic_wordlist(void); diff --git a/pbkdf2.c b/pbkdf2.c index 6001b1f1b..3e7a4f79c 100644 --- a/pbkdf2.c +++ b/pbkdf2.c @@ -5,7 +5,7 @@ #define HMACFUNC hmac_sha512 #define HMACLEN (512/8) -void pbkdf2(const uint8_t *pass, int passlen, uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key, int keylen) +void pbkdf2(const uint8_t *pass, int passlen, uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key, int keylen, void (*progress_callback)(uint32_t current, uint32_t total)) { uint32_t i, j, k; uint8_t f[HMACLEN], g[HMACLEN]; @@ -25,6 +25,9 @@ void pbkdf2(const uint8_t *pass, int passlen, uint8_t *salt, int saltlen, uint32 for (k = 0; k < HMACLEN; k++) { f[k] ^= g[k]; } + if (progress_callback && j % 256 == 255) { + progress_callback(j + 1, iterations); + } } if (i == blocks - 1 && (keylen & (HMACLEN - 1))) { memcpy(key + HMACLEN * (i - 1), f, keylen & (HMACLEN - 1)); diff --git a/pbkdf2.h b/pbkdf2.h index 05121467f..48526d472 100644 --- a/pbkdf2.h +++ b/pbkdf2.h @@ -4,6 +4,6 @@ #include // salt needs to have 4 extra bytes available beyond saltlen -void pbkdf2(const uint8_t *pass, int passlen, uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key, int keylen); +void pbkdf2(const uint8_t *pass, int passlen, uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key, int keylen, void (*progress_callback)(uint32_t current, uint32_t total)); #endif diff --git a/tests.c b/tests.c index 9d92fead4..ba2b4271d 100644 --- a/tests.c +++ b/tests.c @@ -345,19 +345,19 @@ START_TEST(test_pbkdf2) uint8_t k[64], s[64]; strcpy((char *)s, "salt"); - pbkdf2((uint8_t *)"password", 8, s, 4, 1, k, 64); + pbkdf2((uint8_t *)"password", 8, s, 4, 1, k, 64, 0); ck_assert_mem_eq(k, fromhex("867f70cf1ade02cff3752599a3a53dc4af34c7a669815ae5d513554e1c8cf252c02d470a285a0501bad999bfe943c08f050235d7d68b1da55e63f73b60a57fce"), 64); strcpy((char *)s, "salt"); - pbkdf2((uint8_t *)"password", 8, s, 4, 2, k, 64); + pbkdf2((uint8_t *)"password", 8, s, 4, 2, k, 64, 0); ck_assert_mem_eq(k, fromhex("e1d9c16aa681708a45f5c7c4e215ceb66e011a2e9f0040713f18aefdb866d53cf76cab2868a39b9f7840edce4fef5a82be67335c77a6068e04112754f27ccf4e"), 64); strcpy((char *)s, "salt"); - pbkdf2((uint8_t *)"password", 8, s, 4, 4096, k, 64); + pbkdf2((uint8_t *)"password", 8, s, 4, 4096, k, 64, 0); ck_assert_mem_eq(k, fromhex("d197b1b33db0143e018b12f3d1d1479e6cdebdcc97c5c0f87f6902e072f457b5143f30602641b3d55cd335988cb36b84376060ecd532e039b742a239434af2d5"), 64); strcpy((char *)s, "saltSALTsaltSALTsaltSALTsaltSALTsalt"); - pbkdf2((uint8_t *)"passwordPASSWORDpassword", 3*8, s, 9*4, 4096, k, 64); + pbkdf2((uint8_t *)"passwordPASSWORDpassword", 3*8, s, 9*4, 4096, k, 64, 0); ck_assert_mem_eq(k, fromhex("8c0511f4c6e597c6ac6315d8f0362e225f3c501495ba23b868c005174dc4ee71115b59f9e60cd9532fa33e0f75aefe30225c583a186cd82bd4daea9724a3d3b8"), 64); } END_TEST @@ -451,7 +451,7 @@ START_TEST(test_mnemonic) while (*a && *b && *c) { m = mnemonic_from_data(fromhex(*a), strlen(*a) / 2); ck_assert_str_eq(m, *b); - mnemonic_to_seed(m, "TREZOR", seed); + mnemonic_to_seed(m, "TREZOR", seed, 0); ck_assert_mem_eq(seed, fromhex(*c), strlen(*c) / 2); a += 3; b += 3; c += 3; } From e827517591a65b7301ecb629ce5caf816a6f03cc Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 12 Mar 2014 20:45:51 +0100 Subject: [PATCH 089/627] add mnemonic_check function --- bip39.c | 105 ++++++++++++++++++++++++++++++++++++++++++-------------- rand.c | 11 ++++-- rand.h | 1 + tests.c | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 188 insertions(+), 28 deletions(-) diff --git a/bip39.c b/bip39.c index 42ef82798..8d0fa1ee1 100644 --- a/bip39.c +++ b/bip39.c @@ -14,12 +14,9 @@ const char *mnemonic_generate(int strength) if (strength % 32 || strength < 128 || strength > 256) { return 0; } - int i; - static uint32_t data[16]; - for (i = 0; i < 16; i++) { - data[i] = random32(); - } - return mnemonic_from_data((const uint8_t *)data, strength / 8); + static uint8_t data[32]; + random_buffer(data, 32); + return mnemonic_from_data(data, strength / 8); } const char *mnemonic_from_data(const uint8_t *data, int len) @@ -28,31 +25,23 @@ const char *mnemonic_from_data(const uint8_t *data, int len) return 0; } - int i, j; - char bits[256 + 8]; - for (i = 0; i < len; i++) { - for (j = 0; j < 8; j++) { - bits[8 * i + j] = (data[i] & (1 << (7 - j))) > 0; - } - } + uint8_t bits[32 + 1]; + memcpy(bits, data, len); - uint8_t hash[32]; - sha256_Raw((const uint8_t *)data, len, hash); - - char hlen = len / 4; - for (i = 0; i < hlen; i++) { - char c = (hash[0] & (1 << (7 - i))) > 0; - bits[8 * len + i] = c; - } + sha256_Raw(data, len, bits); + bits[len] = bits[0]; + memcpy(bits, data, len); int mlen = len * 3 / 4; static char mnemo[24 * 10]; + int i, j, idx; char *p = mnemo; for (i = 0; i < mlen; i++) { - int idx = 0; + idx = 0; for (j = 0; j < 11; j++) { - idx += bits[i * 11 + j] << (10 - j); + idx <<= 1; + idx += (bits[(i * 11 + j) / 8] & (1 << (7 - ((i * 11 + j) % 8)))) > 0; } strcpy(p, wordlist[idx]); p += strlen(wordlist[idx]); @@ -65,9 +54,73 @@ const char *mnemonic_from_data(const uint8_t *data, int len) int mnemonic_check(const char *mnemonic) { - // TODO: add proper check - (void)mnemonic; - return 1; + if (!mnemonic) { + return 0; + } + + uint32_t i, n; + + i = 0; n = 0; + while (mnemonic[i]) { + if (mnemonic[i] == ' ') { + n++; + } + i++; + } + n++; + // check number of words + if (n != 12 && n != 18 && n != 24) { + return 0; + } + + char current_word[10]; + uint32_t j, k, ki, bi; + uint8_t bits[32 + 1]; + memset(bits, 0, sizeof(bits)); + i = 0; bi = 0; + while (mnemonic[i]) { + j = 0; + while (mnemonic[i] != ' ' && mnemonic[i] != 0) { + if (j >= sizeof(current_word)) { + return 0; + } + current_word[j] = mnemonic[i]; + i++; j++; + } + current_word[j] = 0; + if (mnemonic[i] != 0) i++; + k = 0; + for (;;) { + if (!wordlist[k]) { // word not found + return 0; + } + if (strcmp(current_word, wordlist[k]) == 0) { // word found on index k + for (ki = 0; ki < 11; ki++) { + if (k & (1 << (10 - ki))) { + bits[bi / 8] |= 1 << (7 - (bi % 8)); + } + bi++; + } + break; + } + k++; + } + } + if (bi != n * 11) { + return 0; + } + bits[32] = bits[n * 4 / 3]; + sha256_Raw(bits, n * 4 / 3, bits); + if (n == 12) { + return (bits[0] & 0xF0) == (bits[32] & 0xF0); // compare first 4 bits + } else + if (n == 18) { + return (bits[0] & 0xFC) == (bits[32] & 0xFC); // compare first 6 bits + } else + if (n == 24) { + return bits[0] == bits[32]; // compare 8 bits + } + return 0; } void mnemonic_to_seed(const char *mnemonic, const char *passphrase, uint8_t seed[512 / 8], void (*progress_callback)(uint32_t current, uint32_t total)) diff --git a/rand.c b/rand.c index fe6d724ad..20176d71e 100644 --- a/rand.c +++ b/rand.c @@ -27,12 +27,19 @@ static FILE *f; -void init_rand(void) { +void init_rand(void) +{ f = fopen("/dev/urandom", "r"); } -uint32_t random32(void) { +uint32_t random32(void) +{ uint32_t r; fread(&r, 1, sizeof(r), f); return r; } + +void random_buffer(uint8_t *buf, uint32_t len) +{ + fread(buf, 1, len, f); +} diff --git a/rand.h b/rand.h index 2b72bde5e..fff02e260 100644 --- a/rand.h +++ b/rand.h @@ -28,5 +28,6 @@ void init_rand(void); uint32_t random32(void); +void random_buffer(uint8_t *buf, uint32_t len); #endif diff --git a/tests.c b/tests.c index ba2b4271d..7742466e4 100644 --- a/tests.c +++ b/tests.c @@ -458,6 +458,104 @@ START_TEST(test_mnemonic) } END_TEST +START_TEST(test_mnemonic_check) +{ + static const char *vectors_ok[] = { + "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about", + "legal winner thank year wave sausage worth useful legal winner thank yellow", + "letter advice cage absurd amount doctor acoustic avoid letter advice cage above", + "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong", + "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon agent", + "legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal will", + "letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter always", + "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo when", + "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon art", + "legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth title", + "letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic bless", + "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo vote", + "jelly better achieve collect unaware mountain thought cargo oxygen act hood bridge", + "renew stay biology evidence goat welcome casual join adapt armor shuffle fault little machine walk stumble urge swap", + "dignity pass list indicate nasty swamp pool script soccer toe leaf photo multiply desk host tomato cradle drill spread actor shine dismiss champion exotic", + "afford alter spike radar gate glance object seek swamp infant panel yellow", + "indicate race push merry suffer human cruise dwarf pole review arch keep canvas theme poem divorce alter left", + "clutch control vehicle tonight unusual clog visa ice plunge glimpse recipe series open hour vintage deposit universe tip job dress radar refuse motion taste", + "turtle front uncle idea crush write shrug there lottery flower risk shell", + "kiss carry display unusual confirm curtain upgrade antique rotate hello void custom frequent obey nut hole price segment", + "exile ask congress lamp submit jacket era scheme attend cousin alcohol catch course end lucky hurt sentence oven short ball bird grab wing top", + "board flee heavy tunnel powder denial science ski answer betray cargo cat", + "board blade invite damage undo sun mimic interest slam gaze truly inherit resist great inject rocket museum chief", + "beyond stage sleep clip because twist token leaf atom beauty genius food business side grid unable middle armed observe pair crouch tonight away coconut", + 0, + }; + static const char *vectors_fail[] = { + "above abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about", + "above winner thank year wave sausage worth useful legal winner thank yellow", + "above advice cage absurd amount doctor acoustic avoid letter advice cage above", + "above zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong", + "above abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon agent", + "above winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal will", + "above advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter always", + "above zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo when", + "above abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon art", + "above winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth title", + "above advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic bless", + "above zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo vote", + "above better achieve collect unaware mountain thought cargo oxygen act hood bridge", + "above stay biology evidence goat welcome casual join adapt armor shuffle fault little machine walk stumble urge swap", + "above pass list indicate nasty swamp pool script soccer toe leaf photo multiply desk host tomato cradle drill spread actor shine dismiss champion exotic", + "above alter spike radar gate glance object seek swamp infant panel yellow", + "above race push merry suffer human cruise dwarf pole review arch keep canvas theme poem divorce alter left", + "above control vehicle tonight unusual clog visa ice plunge glimpse recipe series open hour vintage deposit universe tip job dress radar refuse motion taste", + "above front uncle idea crush write shrug there lottery flower risk shell", + "above carry display unusual confirm curtain upgrade antique rotate hello void custom frequent obey nut hole price segment", + "above ask congress lamp submit jacket era scheme attend cousin alcohol catch course end lucky hurt sentence oven short ball bird grab wing top", + "above flee heavy tunnel powder denial science ski answer betray cargo cat", + "above blade invite damage undo sun mimic interest slam gaze truly inherit resist great inject rocket museum chief", + "above stage sleep clip because twist token leaf atom beauty genius food business side grid unable middle armed observe pair crouch tonight away coconut", + "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about", + "winner thank year wave sausage worth useful legal winner thank yellow", + "advice cage absurd amount doctor acoustic avoid letter advice cage above", + "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong", + "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon agent", + "winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal will", + "advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter always", + "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo when", + "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon art", + "winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth title", + "advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic bless", + "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo vote", + "better achieve collect unaware mountain thought cargo oxygen act hood bridge", + "stay biology evidence goat welcome casual join adapt armor shuffle fault little machine walk stumble urge swap", + "pass list indicate nasty swamp pool script soccer toe leaf photo multiply desk host tomato cradle drill spread actor shine dismiss champion exotic", + "alter spike radar gate glance object seek swamp infant panel yellow", + "race push merry suffer human cruise dwarf pole review arch keep canvas theme poem divorce alter left", + "control vehicle tonight unusual clog visa ice plunge glimpse recipe series open hour vintage deposit universe tip job dress radar refuse motion taste", + "front uncle idea crush write shrug there lottery flower risk shell", + "carry display unusual confirm curtain upgrade antique rotate hello void custom frequent obey nut hole price segment", + "ask congress lamp submit jacket era scheme attend cousin alcohol catch course end lucky hurt sentence oven short ball bird grab wing top", + "flee heavy tunnel powder denial science ski answer betray cargo cat", + "blade invite damage undo sun mimic interest slam gaze truly inherit resist great inject rocket museum chief", + "stage sleep clip because twist token leaf atom beauty genius food business side grid unable middle armed observe pair crouch tonight away coconut", + 0, + }; + + const char **m; + int r; + m = vectors_ok; + while (*m) { + r = mnemonic_check(*m); + ck_assert_int_eq(r, 1); + m++; + } + m = vectors_fail; + while (*m) { + r = mnemonic_check(*m); + ck_assert_int_eq(r, 0); + m++; + } +} +END_TEST + START_TEST(test_address) { char address[35]; @@ -660,6 +758,7 @@ Suite *test_suite(void) tc = tcase_create("bip39"); tcase_add_test(tc, test_mnemonic); + tcase_add_test(tc, test_mnemonic_check); suite_add_tcase(s, tc); return s; From 94d4a3733ed10c6db9225a23edcdfee6c7fcb2b2 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 1 Apr 2014 19:44:53 +0200 Subject: [PATCH 090/627] fix typos --- ecdsa.c | 2 +- tests.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ecdsa.c b/ecdsa.c index 748a578ce..208808afd 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -361,7 +361,7 @@ void ecdsa_get_address(const uint8_t *pub_key, uint8_t version, char *addr) memcpy(a + 28, a, 4); // checksum memset(a, 0, 7); // zeroes - memcpy(a + 7, b, 21); // ripemd160(sha256(version + pubkey) + memcpy(a + 7, b, 21); // version || ripemd160(sha256(pubkey)) bn_read_be(a, &c); diff --git a/tests.c b/tests.c index 7742466e4..574a99f13 100644 --- a/tests.c +++ b/tests.c @@ -655,7 +655,7 @@ END_TEST START_TEST(test_ecdsa_der) { - uint8_t sig[64], der[70]; + uint8_t sig[64], der[72]; int res; memcpy(sig, fromhex("9a0b7be0d4ed3146ee262b42202841834698bb3ee39c24e7437df208b8b70771"), 32); From 06dd166a82d465f6db297616b42446c8b4498efe Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 15 May 2014 17:11:26 +0200 Subject: [PATCH 091/627] add more precomputation to ecdsa signing --- bignum.c | 130 +++++++------ ecdsa.c | 41 +++-- secp256k1.c | 513 ++++++++++++++++++++++++++++++++++++++++++++++++++++ secp256k1.h | 1 + 4 files changed, 611 insertions(+), 74 deletions(-) diff --git a/bignum.c b/bignum.c index aca045483..7d3db379d 100644 --- a/bignum.c +++ b/bignum.c @@ -303,14 +303,20 @@ void bn_inverse(bignum256 *x, const bignum256 *prime) void bn_inverse(bignum256 *x, const bignum256 *prime) { int i, j, k, len1, len2, mask; - uint32_t u[9], v[9], s[10], r[10], temp, temp2; + uint8_t buf[32]; + uint32_t u[8], v[8], s[9], r[10], temp32; + uint64_t temp, temp2; bn_fast_mod(x, prime); bn_mod(x, prime); - for (i = 0; i < 9; i++) { - u[i] = prime->val[i]; - v[i] = x->val[i]; + bn_write_be(prime, buf); + for (i = 0; i < 8; i++) { + u[i] = read_be(buf + 28 - i * 4); + } + bn_write_be(x, buf); + for (i = 0; i < 8; i++) { + v[i] = read_be(buf + 28 - i * 4); } - len1 = 9; + len1 = 8; s[0] = 1; r[0] = 0; len2 = 1; @@ -327,13 +333,13 @@ void bn_inverse(bignum256 *x, const bignum256 *prime) if (i == 0) break; mask = (1 << i) - 1; for (j = 0; j + 1 < len1; j++) { - u[j] = (u[j] >> i) | ((u[j + 1] & mask) << (30 - i)); + u[j] = (u[j] >> i) | ((u[j + 1] & mask) << (32 - i)); } u[j] = (u[j] >> i); - mask = (1 << (30 - i)) - 1; - s[len2] = s[len2 - 1] >> (30 - i); + mask = (1 << (32 - i)) - 1; + s[len2] = s[len2 - 1] >> (32 - i); for (j = len2 - 1; j > 0; j--) { - s[j] = (s[j - 1] >> (30 - i)) | ((s[j] & mask) << i); + s[j] = (s[j - 1] >> (32 - i)) | ((s[j] & mask) << i); } s[0] = (s[0] & mask) << i; if (s[len2]) { @@ -349,13 +355,13 @@ void bn_inverse(bignum256 *x, const bignum256 *prime) if (i == 0) break; mask = (1 << i) - 1; for (j = 0; j + 1 < len1; j++) { - v[j] = (v[j] >> i) | ((v[j + 1] & mask) << (30 - i)); + v[j] = (v[j] >> i) | ((v[j + 1] & mask) << (32 - i)); } v[j] = (v[j] >> i); - mask = (1 << (30 - i)) - 1; - r[len2] = r[len2 - 1] >> (30 - i); + mask = (1 << (32 - i)) - 1; + r[len2] = r[len2 - 1] >> (32 - i); for (j = len2 - 1; j > 0; j--) { - r[j] = (r[j - 1] >> (30 - i)) | ((r[j] & mask) << i); + r[j] = (r[j - 1] >> (32 - i)) | ((r[j] & mask) << i); } r[0] = (r[0] & mask) << i; if (r[len2]) { @@ -368,23 +374,25 @@ void bn_inverse(bignum256 *x, const bignum256 *prime) i = len1 - 1; while (i > 0 && u[i] == v[i]) i--; if (u[i] > v[i]) { - temp = 0x40000000u + u[0] - v[0]; - u[0] = (temp >> 1) & 0x1FFFFFFF; - temp >>= 30; + temp = 0x100000000ull + u[0] - v[0]; + u[0] = (temp >> 1) & 0x7FFFFFFF; + temp >>= 32; for (i = 1; i < len1; i++) { - temp += 0x3FFFFFFFu + u[i] - v[i]; - u[i - 1] += (temp & 1) << 29; - u[i] = (temp >> 1) & 0x1FFFFFFF; - temp >>= 30; + temp += 0xFFFFFFFFull + u[i] - v[i]; + u[i - 1] += (temp & 1) << 31; + u[i] = (temp >> 1) & 0x7FFFFFFF; + temp >>= 32; } temp = temp2 = 0; for (i = 0; i < len2; i++) { - temp += s[i] + r[i]; - temp2 += s[i] << 1; - r[i] = temp & 0x3FFFFFFF; - s[i] = temp2 & 0x3FFFFFFF; - temp >>= 30; - temp2 >>= 30; + temp += s[i]; + temp += r[i]; + temp2 += s[i]; + temp2 += s[i]; + r[i] = temp; + s[i] = temp2; + temp >>= 32; + temp2 >>= 32; } if (temp != 0 || temp2 != 0) { r[len2] = temp; @@ -392,23 +400,25 @@ void bn_inverse(bignum256 *x, const bignum256 *prime) len2++; } } else { - temp = 0x40000000u + v[0] - u[0]; - v[0] = (temp >> 1) & 0x1FFFFFFF; - temp >>= 30; + temp = 0x100000000ull + v[0] - u[0]; + v[0] = (temp >> 1) & 0x7FFFFFFF; + temp >>= 32; for (i = 1; i < len1; i++) { - temp += 0x3FFFFFFFu + v[i] - u[i]; - v[i - 1] += (temp & 1) << 29; - v[i] = (temp >> 1) & 0x1FFFFFFF; - temp >>= 30; + temp += 0xFFFFFFFFull + v[i] - u[i]; + v[i - 1] += (temp & 1) << 31; + v[i] = (temp >> 1) & 0x7FFFFFFF; + temp >>= 32; } temp = temp2 = 0; for (i = 0; i < len2; i++) { - temp += s[i] + r[i]; - temp2 += r[i] << 1; - s[i] = temp & 0x3FFFFFFF; - r[i] = temp2 & 0x3FFFFFFF; - temp >>= 30; - temp2 >>= 30; + temp += s[i]; + temp += r[i]; + temp2 += r[i]; + temp2 += r[i]; + s[i] = temp; + r[i] = temp2; + temp >>= 32; + temp2 >>= 32; } if (temp != 0 || temp2 != 0) { s[len2] = temp; @@ -419,21 +429,33 @@ void bn_inverse(bignum256 *x, const bignum256 *prime) if (u[len1 - 1] == 0 && v[len1 - 1] == 0) len1--; k++; } + + j = r[0] >> 30; + r[0] = r[0] & 0x3FFFFFFFu; + for (i = 1; i < len2; i++) { + uint32_t q = r[i] >> (30 - 2 * i); + r[i] = ((r[i] << (2 * i)) & 0x3FFFFFFFu) + j; + j=q; + } + r[i] = j; + i++; + for (; i < 9; i++) r[i] = 0; + i = 8; while (i > 0 && r[i] == prime->val[i]) i--; if (r[i] >= prime->val[i]) { - temp = 1; + temp32 = 1; for (i = 0; i < 9; i++) { - temp += 0x3FFFFFFF + r[i] - prime->val[i]; - r[i] = temp & 0x3FFFFFFF; - temp >>= 30; + temp32 += 0x3FFFFFFF + r[i] - prime->val[i]; + r[i] = temp32 & 0x3FFFFFFF; + temp32 >>= 30; } } - temp = 1; + temp32 = 1; for (i = 0; i < 9; i++) { - temp += 0x3FFFFFFF + prime->val[i] - r[i]; - r[i] = temp & 0x3FFFFFFF; - temp >>= 30; + temp32 += 0x3FFFFFFF + prime->val[i] - r[i]; + r[i] = temp32 & 0x3FFFFFFF; + temp32 >>= 30; } int done = 0; #if USE_PRECOMPUTED_IV @@ -449,14 +471,14 @@ void bn_inverse(bignum256 *x, const bignum256 *prime) if (!done) { for (j = 0; j < k; j++) { if (r[0] & 1) { - temp = r[0] + prime->val[0]; - r[0] = (temp >> 1) & 0x1FFFFFFF; - temp >>= 30; + temp32 = r[0] + prime->val[0]; + r[0] = (temp32 >> 1) & 0x1FFFFFFF; + temp32 >>= 30; for (i = 1; i < 9; i++) { - temp += r[i] + prime->val[i]; - r[i - 1] += (temp & 1) << 29; - r[i] = (temp >> 1) & 0x1FFFFFFF; - temp >>= 30; + temp32 += r[i] + prime->val[i]; + r[i - 1] += (temp32 & 1) << 29; + r[i] = (temp32 >> 1) & 0x1FFFFFFF; + temp32 >>= 30; } } else { for (i = 0; i < 8; i++) { diff --git a/ecdsa.c b/ecdsa.c index 208808afd..533cc7788 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -122,38 +122,39 @@ void point_multiply(const bignum256 *k, const curve_point *p, curve_point *res) // res = k * G void scalar_multiply(const bignum256 *k, curve_point *res) { - int i, j; + int i; // result is zero int is_zero = 1; -#if USE_PRECOMPUTED_CP - int exp = 0; -#else curve_point curr; // initial res memcpy(&curr, &G256k1, sizeof(curve_point)); -#endif - for (i = 0; i < 9; i++) { - for (j = 0; j < 30; j++) { - if (i == 8 && (k->val[i] >> j) == 0) break; - if (k->val[i] & (1u << j)) { - if (is_zero) { + for (i = 0; i < 256; i++) { + if (k->val[i / 30] & (1u << (i % 30))) { + if (is_zero) { #if USE_PRECOMPUTED_CP - memcpy(res, secp256k1_cp + exp, sizeof(curve_point)); + if (i < 255 && (k->val[(i + 1) / 30] & (1u << ((i + 1) % 30)))) { + memcpy(res, secp256k1_cp2 + i, sizeof(curve_point)); + i++; + } else { + memcpy(res, secp256k1_cp + i, sizeof(curve_point)); + } #else - memcpy(res, &curr, sizeof(curve_point)); + memcpy(res, &curr, sizeof(curve_point)); #endif - is_zero = 0; - } else { + is_zero = 0; + } else { #if USE_PRECOMPUTED_CP - point_add(secp256k1_cp + exp, res); + if (i < 255 && (k->val[(i + 1) / 30] & (1u << ((i + 1) % 30)))) { + point_add(secp256k1_cp2 + i, res); + i++; + } else { + point_add(secp256k1_cp + i, res); + } #else - point_add(&curr, res); + point_add(&curr, res); #endif - } } -#if USE_PRECOMPUTED_CP - exp++; -#else +#if ! USE_PRECOMPUTED_CP point_double(&curr); #endif } diff --git a/secp256k1.c b/secp256k1.c index 3781b5b85..ced28a3bc 100644 --- a/secp256k1.c +++ b/secp256k1.c @@ -815,4 +815,517 @@ const curve_point secp256k1_cp[256] = { {/*.x =*/{/*.val =*/{0x3f8be384, 0x22f4c810, 0x31db6c3e, 0x3b02ab68, 0x1ef07271, 0x2b5b253f, 0x23e1b251, 0x24290af9, 0xb237}}, /*.y =*/{/*.val =*/{0x2b19880e, 0x4291cf7, 0x9ecb58d, 0x3c013d05, 0x1f94517, 0x143e22aa, 0x15edbe8d, 0x1a524675, 0xfc6b}}}, }; + +const curve_point secp256k1_cp2[255] = { +{/*.x =*/{/*.val =*/{0x3ce036f9, 0x1807c44e, 0x36f99b08, 0xc721160, 0x1d5229b5, 0x113e17e2, 0xc310493, 0x22806496, 0xf930}}, + /*.y =*/{/*.val =*/{0x4b8e672, 0x32e7f5d6, 0xc2231b6, 0x2a664d, 0x37f35665, 0xcdf98a8, 0x1e8140fe, 0x1ec3d8cb, 0x388f}}}, +{/*.x =*/{/*.val =*/{0x20297556, 0x3c15e851, 0x168a18b2, 0x3d91cbe1, 0x1235d382, 0x14e850d5, 0x2eea4204, 0x1ef55d57, 0xfff9}}, + /*.y =*/{/*.val =*/{0x3075f297, 0x321c30da, 0x18fe4a03, 0x203c3d94, 0x5c560de, 0x3a5805fd, 0x3b620f3b, 0x1ddeab3e, 0xae12}}}, +{/*.x =*/{/*.val =*/{0x30afe85a, 0x16c3d1c1, 0x220095bc, 0x1f3d1065, 0x33463368, 0xe3c0135, 0x3561b15c, 0x5755239, 0xd011}}, + /*.y =*/{/*.val =*/{0x34062327, 0x2c146c4f, 0x1a86d526, 0x8e31776, 0x3bd81579, 0x1914df85, 0x1e0d7a8b, 0x13ff7205, 0xa9f3}}}, +{/*.x =*/{/*.val =*/{0x3202e6ce, 0x140af6a2, 0x162b7940, 0xc8550e7, 0x3a8b0968, 0x2724586, 0x133d48ac, 0x310d504f, 0xfe72}}, + /*.y =*/{/*.val =*/{0xf58c5bf, 0x1e3b4bef, 0x34a9d229, 0x372238da, 0x32998101, 0x2d1f8275, 0x24a68d3a, 0x37819ffc, 0x6851}}}, +{/*.x =*/{/*.val =*/{0x1118e5c3, 0x2f61c2a8, 0x12bebc19, 0x15e6c9d1, 0x265b4bfc, 0x595bbd3, 0x1307db44, 0xcd76591, 0x6eca}}, + /*.y =*/{/*.val =*/{0x5a08668, 0x2628bde0, 0x3f8ec344, 0x125a8e8e, 0x3875a03a, 0x3d5e41d2, 0x20710592, 0x8ed5e9e, 0xd501}}}, +{/*.x =*/{/*.val =*/{0x3f8cb0e3, 0xe4ceb29, 0x1efe3a44, 0xbad4ff8, 0x2eb72ea2, 0x1938112c, 0x16d8f8fa, 0x20395d11, 0x3f0e}}, + /*.y =*/{/*.val =*/{0x2a5f404f, 0x2c0a278b, 0x25b53a4c, 0x494ea9, 0x1d01b395, 0x2e702121, 0xbc91e90, 0x35f5ca5b, 0xcb66}}}, +{/*.x =*/{/*.val =*/{0x33ce1752, 0x1edd43dc, 0x3cd204ec, 0x20f1e5f5, 0x1c9aeae7, 0x377d9366, 0x1c635812, 0x36963407, 0xd7a0}}, + /*.y =*/{/*.val =*/{0x762cef4, 0x2f009ce0, 0x62b742b, 0x38102a30, 0x2284650b, 0xa4a0d03, 0x8032f6f, 0x1c381a00, 0x9127}}}, +{/*.x =*/{/*.val =*/{0x35476085, 0x2422dc06, 0x2eb9f84a, 0x1c539de5, 0xed1afb5, 0xeab5a9e, 0xcd3e10d, 0x29c19e82, 0x3443}}, + /*.y =*/{/*.val =*/{0xb8f52d8, 0x34d212f6, 0xc2b67f6, 0x2292c9f4, 0x3e1da901, 0x3a312e31, 0x36f854f6, 0x1e97e0a6, 0x661a}}}, +{/*.x =*/{/*.val =*/{0x257e8dfa, 0x33f032e7, 0x3c7e184f, 0x20246468, 0x298ca009, 0x28c3e2b2, 0x19c4c0d9, 0x33cbfc1e, 0x8262}}, + /*.y =*/{/*.val =*/{0x3bac376a, 0x173fe363, 0x314c4783, 0x2dbb4cca, 0x334f3457, 0x3b88bb16, 0x9e4e66f, 0x25788244, 0x83fd}}}, +{/*.x =*/{/*.val =*/{0x3c70620c, 0x5f307c9, 0x3c288d9d, 0x26312faa, 0x27178049, 0x374c68ad, 0x236dc60, 0x2a29234b, 0x1653}}, + /*.y =*/{/*.val =*/{0x315b32cd, 0x328ba074, 0x3d3dc526, 0xabdd237, 0x3a701c01, 0x2a651d3b, 0x37f7aeaf, 0xa424d6b, 0x338}}}, +{/*.x =*/{/*.val =*/{0x271dabcd, 0x1f50ae9b, 0x1e5cb4f4, 0x34ff9262, 0x35373f54, 0x22b8c982, 0x3f43c609, 0x393edad8, 0xd49e}}, + /*.y =*/{/*.val =*/{0x16603c2, 0x19aa433c, 0x2ff7031e, 0x271424c4, 0x1bf35612, 0x21fa9e98, 0x1490dd7c, 0x38e48269, 0x531}}}, +{/*.x =*/{/*.val =*/{0xc8c828a, 0xfcc2ae4, 0x16ae41f5, 0xbac90b2, 0x281c7513, 0x1283605f, 0x9e750e4, 0x21472905, 0x5f94}}, + /*.y =*/{/*.val =*/{0x37344d80, 0x3fac28fc, 0x3c68b04b, 0x19b7dd53, 0x2f35e8c, 0x1e5f622, 0x1fee8e5f, 0x30ee2be8, 0x26b8}}}, +{/*.x =*/{/*.val =*/{0x5041216, 0x16dfe3c7, 0x2b836a6, 0x1ccd7da1, 0x2fed523f, 0x2d67bf70, 0x3acf4128, 0xc5ec87d, 0xda75}}, + /*.y =*/{/*.val =*/{0x2e708572, 0x2bb4ca61, 0x37acedad, 0x2ab01eb9, 0x2d7fc6e9, 0x27886cd0, 0x2d5f0df1, 0x2811afdc, 0x73f8}}}, +{/*.x =*/{/*.val =*/{0x3c62bac0, 0x1414c93c, 0x1f0ab069, 0x54377d4, 0x28b70e19, 0x12df4b0f, 0x3469c136, 0x3c3e408f, 0x9530}}, + /*.y =*/{/*.val =*/{0x3618e309, 0x1e2af6a5, 0x31fdc684, 0x16cca14b, 0x3333e0e2, 0x34bdfd66, 0x321e234d, 0xc16a3e7, 0x8f3c}}}, +{/*.x =*/{/*.val =*/{0x1c3c9c8f, 0x19c10e17, 0x24367b20, 0x205bfb8f, 0x2332b0f2, 0x27fd0eaa, 0x298fd6f0, 0xb72f90, 0x67be}}, + /*.y =*/{/*.val =*/{0x193652d9, 0x14e12661, 0x388c2be5, 0x264efd82, 0x291693cd, 0x2516d820, 0x1ef84a2c, 0x1569cf93, 0x7a9b}}}, +{/*.x =*/{/*.val =*/{0x10aaa33a, 0x7e6f2f8, 0x17b9ca51, 0x24b74a70, 0x1718368c, 0x1a404ef1, 0x3876adf5, 0x924bd3b, 0x893b}}, + /*.y =*/{/*.val =*/{0x11af3445, 0x1ee02e2b, 0x3ceeb426, 0xe7a2884, 0x107f32a4, 0xe801d99, 0x1c89ef41, 0x14ad9cb4, 0xcdb1}}}, +{/*.x =*/{/*.val =*/{0x36e55dc8, 0x2e24485b, 0x2ca04394, 0x3e56adba, 0x1094426f, 0x12910301, 0x1ffb2ba8, 0x1011e431, 0x4431}}, + /*.y =*/{/*.val =*/{0x1be323b3, 0x76512bb, 0x2aa2e503, 0x1a8a6de7, 0x2fed7a6, 0x260dfd59, 0x366f8fe9, 0x3050b994, 0x96b0}}}, +{/*.x =*/{/*.val =*/{0x33f0e9aa, 0x3ad78658, 0x11bd34b3, 0x449ddac, 0x138d268, 0x92b8356, 0x326adb79, 0x3fa15d7, 0xe538}}, + /*.y =*/{/*.val =*/{0x82720f, 0x12e904d9, 0x68318ec, 0x2e53977d, 0xc8e016f, 0x244d8e49, 0x3b41d5b6, 0x361ce421, 0xb97f}}}, +{/*.x =*/{/*.val =*/{0x2ebc61d6, 0x2bb4d86f, 0x1ff42de1, 0x23f4e9f6, 0x2b1f518a, 0x17c34575, 0x19af0c39, 0x3cf928fb, 0x939f}}, + /*.y =*/{/*.val =*/{0x23f5cb70, 0x1d7a919a, 0x38c7f82e, 0x2fc9bad, 0x16c0498, 0x1bf13bbc, 0x3a90e9d4, 0xef3c22d, 0xdeab}}}, +{/*.x =*/{/*.val =*/{0x497e0df, 0x5b84d37, 0xf76f530, 0xeed0dbb, 0x2029a04c, 0x161e17f9, 0x3293078, 0xf94ab8e, 0xfdc6}}, + /*.y =*/{/*.val =*/{0x1b9eb19f, 0x1811127, 0x335d9d5f, 0x2fac8bef, 0x22e8b87b, 0x3dc50a2b, 0x3bb52e3d, 0x2b59eb3a, 0x292d}}}, +{/*.x =*/{/*.val =*/{0x355812dd, 0x28a960b, 0x12d30e2a, 0x1119c8d5, 0x18f78e3d, 0x2afb5b01, 0x3352f0b6, 0x2f5ea4bf, 0x7029}}, + /*.y =*/{/*.val =*/{0x1a2d2927, 0x87319ac, 0x3b2c73c7, 0x36ba1090, 0x683ac47, 0x19512b8c, 0xb3d27dd, 0x3eb6bf7a, 0xb0ee}}}, +{/*.x =*/{/*.val =*/{0x3181fdc2, 0x336affe6, 0xc62364d, 0xbd8aed7, 0x234e7edd, 0x992e062, 0x26e474aa, 0x40abd1f, 0xf42c}}, + /*.y =*/{/*.val =*/{0x2485d7fd, 0x7c0024e, 0x22acf268, 0x5540b66, 0x2fe22a4c, 0x2b4172e1, 0x2806c78f, 0xead1b3f, 0x5750}}}, +{/*.x =*/{/*.val =*/{0x2edd7dd6, 0x219b51f7, 0x1e1968c3, 0xddbf899, 0x3cfdec49, 0x29e103b9, 0x3524bca5, 0x33da8931, 0x32cf}}, + /*.y =*/{/*.val =*/{0x3e08e330, 0x17f512bb, 0x349a08b2, 0x3633480, 0x1f561e7a, 0x2025a902, 0x27748620, 0x1a8d25da, 0x2184}}}, +{/*.x =*/{/*.val =*/{0x21231d11, 0x399d20c4, 0x2aaad7c, 0x2acdb18f, 0x37c39822, 0x455731d, 0x388e433d, 0x3507a2e4, 0x3514}}, + /*.y =*/{/*.val =*/{0x23855df5, 0xf5bed03, 0x2f79ebe5, 0x213cc742, 0x39eff93, 0x1344795a, 0x17eb8ef4, 0xc940580, 0x89a8}}}, +{/*.x =*/{/*.val =*/{0x633cb1, 0x159f827a, 0x1d021132, 0x168892da, 0x181fcb57, 0x189cc848, 0x2cad400c, 0x273cc5ea, 0x6dde}}, + /*.y =*/{/*.val =*/{0x27ce6b34, 0x1f7526a9, 0x3859ef35, 0x2c9ff6b3, 0x3a66a880, 0x27be1a86, 0x3e41d5c9, 0x3ef9e9c1, 0x9188}}}, +{/*.x =*/{/*.val =*/{0x4e5467d, 0x342f5da9, 0x1bbface4, 0x2422ae06, 0x970e940, 0x7d8b83b, 0x1a1222c2, 0x193c3f1a, 0x97d0}}, + /*.y =*/{/*.val =*/{0x1e9cb3fa, 0x25cc03f4, 0xf17ccd7, 0x17ecee15, 0x10861fda, 0x1f19bea1, 0x2cc03f, 0x13cbb4cd, 0x8997}}}, +{/*.x =*/{/*.val =*/{0x13613bec, 0x32a072e4, 0x1cfe67c, 0x2d7f2744, 0xf972a8b, 0x6ccf71d, 0x137bdedf, 0x32ae324e, 0x2dcf}}, + /*.y =*/{/*.val =*/{0x1a039215, 0x39cc2492, 0x33f5f383, 0xcb3eeb4, 0x36c6f437, 0x222df5b, 0xa41265f, 0x3137651d, 0x46db}}}, +{/*.x =*/{/*.val =*/{0x7fb9e1a, 0x1f345c21, 0x22a32961, 0x39d2dd37, 0x2b0e767f, 0xaf26ee, 0x2c5a8f1a, 0x1052a923, 0x1bec}}, + /*.y =*/{/*.val =*/{0x349c0443, 0x1fdb845d, 0xc9796e5, 0x4e176ba, 0x54b0f68, 0x26f15cc3, 0x266678a7, 0x19c11c04, 0xe358}}}, +{/*.x =*/{/*.val =*/{0x3b7ceceb, 0xfd9e3fe, 0x97faf0f, 0x2967e4e2, 0x2e681473, 0x3ee049bd, 0x2d45036f, 0x2188109d, 0x437a}}, + /*.y =*/{/*.val =*/{0x16c181e1, 0xd8ef30d, 0x8f97827, 0x883f3f7, 0x1297ff87, 0x23fada67, 0x2c32f69b, 0x1ae84fba, 0xb91}}}, +{/*.x =*/{/*.val =*/{0x1cbf00eb, 0x3276761f, 0x18d02274, 0x2d3a62f0, 0x230bc241, 0x385bda86, 0x2d4dc49b, 0x1c2ba5ba, 0xb890}}, + /*.y =*/{/*.val =*/{0x1b0e664e, 0x2dfc6f34, 0x2b96a671, 0x362c1ad, 0x4a766cb, 0xa539307, 0x2d88f472, 0x3230b228, 0x6f24}}}, +{/*.x =*/{/*.val =*/{0x36fbe7b2, 0x275bfe6a, 0x18d65a3b, 0x2b7b7051, 0x2884605e, 0x1aeec6ca, 0x41f8f33, 0x21d9a72d, 0x2648}}, + /*.y =*/{/*.val =*/{0x21bc2a34, 0xca9e2f0, 0x20eb6039, 0xe36605a, 0x2ddf1856, 0x3cb72b40, 0x144988f2, 0x36ad2c80, 0x9e15}}}, +{/*.x =*/{/*.val =*/{0x2b038315, 0x1a434c18, 0x1310e6f9, 0x2b310cda, 0x14b8629c, 0x1a038e5e, 0x312221e4, 0x15a1d59d, 0xaba5}}, + /*.y =*/{/*.val =*/{0x2e25fc0a, 0x26800fe6, 0xb63338f, 0x2fed4cb6, 0x130d6f3f, 0x15c3d894, 0x25edb63d, 0x1761ea8d, 0xa0e7}}}, +{/*.x =*/{/*.val =*/{0x15bc15b4, 0x32e684d2, 0x25a2ee69, 0x1d40a391, 0x17ca8d92, 0x163ba73b, 0x2adc9ed8, 0x38b947b, 0x10e9}}, + /*.y =*/{/*.val =*/{0x18aa258d, 0x13af9825, 0x2bb6a883, 0x296258c0, 0x2d1f754c, 0x1ea3185a, 0x1e0424d5, 0xdc0e035, 0xc68a}}}, +{/*.x =*/{/*.val =*/{0x3a1c0a80, 0x3d8aaf21, 0x25a9c740, 0x18945631, 0x2ff9c34d, 0x326f9c00, 0xcca5b17, 0x169a2985, 0xb6b1}}, + /*.y =*/{/*.val =*/{0x1ce0a03, 0x1b340441, 0x2e16eeb, 0x2684acc2, 0x2536d49c, 0x3888fbbd, 0x1b61ea54, 0xb8535b3, 0xfae6}}}, +{/*.x =*/{/*.val =*/{0x12b062d4, 0x1f2a942a, 0x3b6a141a, 0x1739f966, 0x2a227a7a, 0x2c5c4a0f, 0x2eaca06f, 0xfa90c95, 0x3596}}, + /*.y =*/{/*.val =*/{0x3bb25302, 0x42a9346, 0xde59b1a, 0x1020ae59, 0x8a96d0, 0x33865be7, 0x1e5c9bfc, 0x38515254, 0xf65b}}}, +{/*.x =*/{/*.val =*/{0x1d33fd27, 0x282fd714, 0x246cc62f, 0x17d5cf6d, 0x2361b44, 0x8e23b6a, 0x3e84cd02, 0xfc24898, 0x9ed7}}, + /*.y =*/{/*.val =*/{0x2716c458, 0x25cacb78, 0x2e449345, 0x2a08f96c, 0x6725494, 0x16d3cd09, 0x1eeeaee7, 0x2259faec, 0xb631}}}, +{/*.x =*/{/*.val =*/{0x2f028d83, 0x1e588ebb, 0x27439615, 0x25649b6e, 0x1e69db61, 0x2af96857, 0x385ec6a5, 0x3df138f1, 0xa7eb}}, + /*.y =*/{/*.val =*/{0x19d0bed1, 0x1900e4ae, 0x30539199, 0x28e249d2, 0x4804b47, 0x271cddc1, 0x362d5cfd, 0x54beff8, 0x6205}}}, +{/*.x =*/{/*.val =*/{0x3bb61ee5, 0xa21104d, 0x31f0c13f, 0x13c138be, 0x34ae6eda, 0x18e33625, 0x321b8662, 0xc8c3321, 0xd493}}, + /*.y =*/{/*.val =*/{0x25d694a8, 0x18b69343, 0x2438ddc6, 0x344b2316, 0xafb5e1a, 0x317a747b, 0x29d23edc, 0x26afd46, 0x21c}}}, +{/*.x =*/{/*.val =*/{0x2c04554a, 0xc3772f3, 0x288cffe5, 0x373feed1, 0x10a2ecaa, 0x194b09e8, 0x3d1a0474, 0xdf2261c, 0x896f}}, + /*.y =*/{/*.val =*/{0x129138df, 0x1a3e7f86, 0xc417dcd, 0x216d86b, 0x11bf1e6, 0x8aec13a, 0x2c4acda6, 0x8f9c892, 0x3804}}}, +{/*.x =*/{/*.val =*/{0x343fca26, 0x101df46a, 0x3bc23678, 0x3ee10768, 0x3578a27d, 0x308276fc, 0x36d6cca6, 0x2e5fddd2, 0x11b3}}, + /*.y =*/{/*.val =*/{0x1b679d58, 0xec9fabd, 0x39f9d42d, 0x2b88c712, 0x36d3bb3b, 0x159430bc, 0xc508cd, 0x7e7eb98, 0x6533}}}, +{/*.x =*/{/*.val =*/{0x8dfd587, 0x1e4d86ed, 0x1b026560, 0x312e8e32, 0x35a12d5e, 0x19eaa8b3, 0x508b348, 0x2d06eb3d, 0x5084}}, + /*.y =*/{/*.val =*/{0x11470e89, 0x39e7a5fe, 0x91f5606, 0x2dbd581a, 0x2927475d, 0x2a9b2154, 0xd31619, 0x18c68766, 0x34a9}}}, +{/*.x =*/{/*.val =*/{0x2c953fa9, 0x341655b5, 0xb8c3db4, 0x2ac98a7c, 0x118c0628, 0x3d21752f, 0x393233a5, 0x3443aaaa, 0xa49e}}, + /*.y =*/{/*.val =*/{0x6fb4c72, 0x1ecaf489, 0x28e181b6, 0x3a1d4d25, 0x1fddfb5a, 0x11db0283, 0x35398e03, 0x2e251983, 0xcc72}}}, +{/*.x =*/{/*.val =*/{0x27a1d916, 0x3025b4ff, 0x11f1f3a3, 0x16c28e57, 0x1bb07031, 0x18562997, 0x19d0cbac, 0x3e6b2db5, 0x650e}}, + /*.y =*/{/*.val =*/{0x3068387b, 0x16127299, 0x36c26ba8, 0x2ed18229, 0x1b82c558, 0x2702e49e, 0x2b11870e, 0x47c8458, 0x85d}}}, +{/*.x =*/{/*.val =*/{0x36fb2940, 0x37f07501, 0x2534042f, 0x7f01a6c, 0x2b8fbd71, 0x1d04e10a, 0x1c82fecb, 0x283bf680, 0x5083}}, + /*.y =*/{/*.val =*/{0x36ceee44, 0x378c0ed9, 0x2cdddf3b, 0x1a849b87, 0xdf19b08, 0x3ef7e189, 0x782bba8, 0x2bbe3ff9, 0xf064}}}, +{/*.x =*/{/*.val =*/{0x15bc8a44, 0x3bf74194, 0x3e151a19, 0x10405df2, 0x1a5fc768, 0x159692e9, 0xeda3d38, 0x20160f3f, 0x4d01}}, + /*.y =*/{/*.val =*/{0x1adbc09e, 0x3c7e5324, 0x182da362, 0x250811a1, 0x16381396, 0x26ea001f, 0xf5d367e, 0x31b0632d, 0x3a33}}}, +{/*.x =*/{/*.val =*/{0x135b4eb8, 0x14884f92, 0x38b5a3cf, 0x3d55fc6a, 0x2f2dce07, 0x3d528f32, 0x32256f0f, 0x1a390eb7, 0xc119}}, + /*.y =*/{/*.val =*/{0x2f911add, 0x11265b5, 0x2a7149b7, 0x3e2d2504, 0x366f8242, 0x27607f99, 0x2458f837, 0x39a4dde1, 0xbff5}}}, +{/*.x =*/{/*.val =*/{0x19dffc96, 0x256e8425, 0x3ac58572, 0xa33696b, 0x17eb0192, 0x26ce5720, 0x3deaf6f, 0x1b2fb852, 0x161c}}, + /*.y =*/{/*.val =*/{0x1b492de4, 0x24ef3d84, 0x2af8621c, 0x258d324b, 0x3183059b, 0x964e472, 0x1ff985bd, 0x32a4a9ae, 0x8a26}}}, +{/*.x =*/{/*.val =*/{0x369671d5, 0x35f9c967, 0x14eb83e3, 0xbbabd6d, 0x2bc96056, 0x7906af5, 0x39596d76, 0x3b1580f3, 0xa8c1}}, + /*.y =*/{/*.val =*/{0x333db746, 0xf22a034, 0x18f8b182, 0x2997eccc, 0x141c5924, 0x31cc9a4, 0x345ac755, 0x181447a7, 0x5fc3}}}, +{/*.x =*/{/*.val =*/{0x8a2050e, 0x6b10bf9, 0x15f8a677, 0xbbd55d8, 0x79b8974, 0x1da731b9, 0x731896b, 0x93f492f, 0x6737}}, + /*.y =*/{/*.val =*/{0x61d3d70, 0x24326924, 0x3349cc2b, 0x1aeb3f50, 0x86b6dbe, 0x120b026a, 0x24a20203, 0x2095e25a, 0xe4cf}}}, +{/*.x =*/{/*.val =*/{0x29a78179, 0x133d807e, 0x20d6afe3, 0x143a4149, 0x9ed9f6b, 0x291ccd88, 0x1b8dc905, 0x29fcdc20, 0x995c}}, + /*.y =*/{/*.val =*/{0x2fec1f47, 0xc7eed32, 0x2b64e529, 0x332155a6, 0x12863abb, 0xd362012, 0x3573ab5e, 0x167a5554, 0xd9a0}}}, +{/*.x =*/{/*.val =*/{0x49135d3, 0xf636176, 0x2e431fc1, 0x80f3404, 0x30b16a74, 0x4d0a504, 0x2a85a65c, 0x2f1fbe0, 0x594}}, + /*.y =*/{/*.val =*/{0x162255d2, 0xb5d146, 0x1902391d, 0xa18ca32, 0x36687af1, 0x16c31eaa, 0x3ab612f7, 0x1e617ad3, 0x9053}}}, +{/*.x =*/{/*.val =*/{0x39e68f51, 0x3de3a89e, 0x16b6e1d0, 0x1b87f2ae, 0xd870cf5, 0x301895ca, 0x26fcb74d, 0x116b276e, 0xc755}}, + /*.y =*/{/*.val =*/{0x38cfbbc1, 0x7120e25, 0x22ddf68d, 0x7246272, 0x168bf725, 0x163b6ca8, 0x855c2a7, 0xf11a8ef, 0x7c80}}}, +{/*.x =*/{/*.val =*/{0x41ead4b, 0x3fa21e68, 0x11b03c1f, 0x1d7b7eda, 0x3e76be3a, 0x11cd3beb, 0x3337ec71, 0x3032323, 0xbfc9}}, + /*.y =*/{/*.val =*/{0x6fedaed, 0x114b1bc2, 0x2e0ae3e7, 0x11a3bfcc, 0x42d36fb, 0x29c63754, 0xded24db, 0x206c7827, 0x7a94}}}, +{/*.x =*/{/*.val =*/{0x25b7ad0d, 0x253215bb, 0x1d0d1d36, 0x3b9d9f2a, 0x116c4476, 0x362925b, 0x1e00dc2d, 0x1a436aed, 0x3a55}}, + /*.y =*/{/*.val =*/{0x32e8c407, 0x1b261e42, 0x2c31218d, 0x32b2e2b2, 0x2f99f301, 0x7eeb25f, 0x657bfb2, 0x23865d68, 0xc3e2}}}, +{/*.x =*/{/*.val =*/{0x19b2df82, 0x9e91ec2, 0x3104fb19, 0x179e8591, 0x232c04ec, 0xb463b33, 0x3b92ccc9, 0x191718af, 0x405a}}, + /*.y =*/{/*.val =*/{0x9307dbf, 0x368a0d28, 0x2dc462b5, 0x3ea76cb3, 0x37e7122f, 0x2b298788, 0x196e0f5c, 0x2d053d13, 0xbc3c}}}, +{/*.x =*/{/*.val =*/{0x18f4033f, 0x9f0f311, 0x20ab6d3a, 0x12b3c96c, 0x28f817cc, 0x2c835e83, 0x3cfb3d2a, 0x51ad0e6, 0x10ba}}, + /*.y =*/{/*.val =*/{0x76d1fbf, 0x173dae53, 0x1c78b4ea, 0x6dacdfa, 0x129f3677, 0x283c19a8, 0xaef4b2a, 0x19b9747, 0xade1}}}, +{/*.x =*/{/*.val =*/{0x36e2d9b3, 0x12f4c1aa, 0x338d6351, 0x36e4a0c6, 0xf845641, 0xba984e7, 0x305e75e1, 0x53ce5f1, 0x19a3}}, + /*.y =*/{/*.val =*/{0xbaaaf33, 0x154bb897, 0x4be56d, 0x874749, 0x3528b3a5, 0x2597e21f, 0x328dd234, 0x363d76b1, 0x6cac}}}, +{/*.x =*/{/*.val =*/{0x23a52264, 0xb9cdf65, 0x1400b375, 0x2b7f00c5, 0x251cffd0, 0x1b8aa6ab, 0x7fe9a80, 0x37037a06, 0x85ff}}, + /*.y =*/{/*.val =*/{0x2da2082, 0x231f4a6a, 0x3179d049, 0x2060b24a, 0x14706c67, 0x15a3d415, 0x2948d0be, 0xc061eb8, 0x3fee}}}, +{/*.x =*/{/*.val =*/{0x36a88c9c, 0x307fd692, 0x149df069, 0x1eda198c, 0x2caa2aa3, 0x766b25c, 0x391398b2, 0x24207951, 0x7865}}, + /*.y =*/{/*.val =*/{0x35a7d19b, 0x38164d15, 0x3ab6a155, 0x33e466c0, 0x28196112, 0x23e9c897, 0x30d2b69e, 0xc1de4a8, 0x59a2}}}, +{/*.x =*/{/*.val =*/{0x1e8f7605, 0x374b71e3, 0x3ed2d35b, 0x13bde7d7, 0xff48bd4, 0x2ce44ba2, 0x159def16, 0x1100533a, 0x21ce}}, + /*.y =*/{/*.val =*/{0x955155f, 0xd791446, 0x46602c1, 0x38cd259a, 0x1da46ef4, 0x1bf5987c, 0xfaf75d9, 0x19c08e8b, 0x323a}}}, +{/*.x =*/{/*.val =*/{0x121ce204, 0x13b5d7a3, 0x26763d52, 0x29c96390, 0x26f72fb2, 0x1d361672, 0x3c64fb83, 0x107458ac, 0x43ca}}, + /*.y =*/{/*.val =*/{0x134a8f6b, 0x1494113a, 0x2a4a468e, 0x2db1eccf, 0x1ba31f9a, 0x143e4863, 0x23fa1c6, 0x16a0b8dc, 0xdcea}}}, +{/*.x =*/{/*.val =*/{0x14978583, 0x2ce90c80, 0x61613f5, 0x35ba6bbc, 0x392214cd, 0x21066643, 0x23137497, 0x3e26e73c, 0x30ab}}, + /*.y =*/{/*.val =*/{0x1dc75777, 0x118600d4, 0x3b584ac4, 0x483a88e, 0x21ab8063, 0x1ed3cb43, 0x37498cdf, 0x144551df, 0x4b03}}}, +{/*.x =*/{/*.val =*/{0x2c288015, 0x268df98f, 0x2dc99cc3, 0x1cfe14fb, 0x1b6aa646, 0x3eb18681, 0x2de6f681, 0x13aab64d, 0xaa01}}, + /*.y =*/{/*.val =*/{0x6c1006f, 0x3e053999, 0x3cecad9d, 0x12e6c1d0, 0x3b0f63ef, 0xa9f90fd, 0x2be9ac3f, 0x4f0118d, 0x3de9}}}, +{/*.x =*/{/*.val =*/{0x185bfe2, 0x34231245, 0xe5e42d3, 0x37e8ab9e, 0x2679cb5e, 0x2a82a0b3, 0xa0b0b56, 0x576fcdf, 0xe526}}, + /*.y =*/{/*.val =*/{0x2a0e5888, 0x33c042f, 0x245a9c44, 0x1dbfcb72, 0x32c1a284, 0x7e54a27, 0x488520f, 0xcd459b4, 0x5403}}}, +{/*.x =*/{/*.val =*/{0x59ab499, 0x2f674fc8, 0x273c330a, 0x4ca671b, 0x3f01bc0b, 0x65acf19, 0x5ba5d2, 0x2bfcc057, 0x78ba}}, + /*.y =*/{/*.val =*/{0x3ee097fd, 0x20748c63, 0x11251996, 0x18cbbba3, 0x2082e91, 0x2a1383b6, 0x2c0afafc, 0x3736f6c1, 0xad4b}}}, +{/*.x =*/{/*.val =*/{0x25cd5379, 0xc18ccc2, 0x70bcadc, 0x2de50e16, 0x24d2232d, 0x9206e2a, 0x11382a78, 0x1cb55af7, 0x17c0}}, + /*.y =*/{/*.val =*/{0x3108cd25, 0x1f2b8146, 0x25bad0df, 0x166b1d89, 0x1d034f89, 0x30491ebc, 0x1a064e77, 0x2f7d0a0f, 0xd901}}}, +{/*.x =*/{/*.val =*/{0xa2d8dae, 0x1e4f0063, 0x3d25ea95, 0xca97e47, 0x32256eac, 0x2c97be72, 0x192f9ba6, 0x7009884, 0x8827}}, + /*.y =*/{/*.val =*/{0x3e1e77d9, 0x2d09b03c, 0x317d099f, 0x21db71, 0x2bf5acc3, 0x322ceb96, 0x176aa401, 0x3754d41c, 0xd719}}}, +{/*.x =*/{/*.val =*/{0x1ee503a6, 0x2543ebf4, 0x124e1fba, 0x7a1493c, 0x2ec5ab43, 0x2a0c4661, 0x24a29aa6, 0x1fa04b8f, 0xceb6}}, + /*.y =*/{/*.val =*/{0xe98c4d1, 0x3ff50365, 0x269e2f31, 0x225b657b, 0x1cd86b4b, 0xf7de042, 0x10613b82, 0x21516b0e, 0x5e6a}}}, +{/*.x =*/{/*.val =*/{0x3ba9000, 0x37c1c8ea, 0x25e8b6f, 0x21cbe71a, 0x143dc4, 0x21d81d61, 0x1d8c1684, 0x1d3e7ffc, 0xac38}}, + /*.y =*/{/*.val =*/{0x2f10cf0a, 0x368f1f65, 0x366e9fa4, 0x178d435f, 0x117f9308, 0xb77a250, 0x1c069b86, 0x3a48c228, 0xaa65}}}, +{/*.x =*/{/*.val =*/{0x17ba402e, 0x39758c2c, 0x1042989a, 0x2e06970b, 0x8e3c3c3, 0x3ab43121, 0x3a02a58b, 0x6d73463, 0x8e89}}, + /*.y =*/{/*.val =*/{0x4fad9e0, 0x386d89e7, 0x157a7ee8, 0x19430908, 0x32a306af, 0x23439013, 0x2c6680b3, 0x3839aa7, 0xe5d3}}}, +{/*.x =*/{/*.val =*/{0x136bcfe8, 0x187b5879, 0x29b7bb3e, 0x305e7b5, 0x2b319a0e, 0x32a3c8c1, 0x2999b472, 0x3e2f0731, 0x1332}}, + /*.y =*/{/*.val =*/{0x1ae78402, 0x6c374b3, 0x1a8c2145, 0x24ed0935, 0x1c0681ba, 0x19f114d7, 0x2ed713f, 0x31fb8a58, 0xc39d}}}, +{/*.x =*/{/*.val =*/{0x2fddec6, 0x3fffb0cd, 0x111222c7, 0xb00f7df, 0x3f461492, 0x3678cde4, 0x220b4e9c, 0x7fead4f, 0x9f13}}, + /*.y =*/{/*.val =*/{0x9df8052, 0x3855dbc6, 0x3918eac6, 0x28c8d510, 0xec8d7d3, 0x34d25302, 0x326f4fef, 0x5302c, 0x3b21}}}, +{/*.x =*/{/*.val =*/{0x38c8ac7f, 0xa0bf97e, 0x1e2aa527, 0x490bb99, 0x16f84964, 0xce5b481, 0x22bbcb5c, 0x2cbef8e0, 0x9945}}, + /*.y =*/{/*.val =*/{0x29aea3b0, 0x1b650e85, 0x2dacdfa9, 0xbde88fb, 0x28eff528, 0x36d13fec, 0x3282d607, 0x3b6092c3, 0x3eef}}}, +{/*.x =*/{/*.val =*/{0x12fccf64, 0x2ea92662, 0x181318e3, 0x349e3789, 0x95dbf3b, 0x21dcb1df, 0x637db06, 0x45703ad, 0xc7d}}, + /*.y =*/{/*.val =*/{0x2878fee0, 0xfdb4ecc, 0x19ae68d5, 0x1e1760e5, 0xaf14548, 0x1092e11e, 0x1b0447aa, 0x1d1ec649, 0x4aa8}}}, +{/*.x =*/{/*.val =*/{0x148d5622, 0x2d6baeb1, 0x251bd2e8, 0x36c1fbde, 0x33381be1, 0x161aa06f, 0x9535a39, 0x3047985a, 0x5fc6}}, + /*.y =*/{/*.val =*/{0x1ac1683, 0x34361004, 0x2c7bf300, 0x16b4239, 0x367acb0e, 0x26e8b6c0, 0x1d9db9c1, 0x39526a8, 0x10e8}}}, +{/*.x =*/{/*.val =*/{0x33c85ecf, 0x1a5916ce, 0x15dacd7, 0x6e08398, 0xff0807d, 0xbd69fa, 0x23e20844, 0x22f56a48, 0x23dd}}, + /*.y =*/{/*.val =*/{0x274504ad, 0x1c2702ae, 0xec98f6f, 0x274c6013, 0x10d4b7fc, 0x7b4bf9c, 0x3d26f710, 0x26ef0094, 0x52d}}}, +{/*.x =*/{/*.val =*/{0x1136602, 0x2c2e9195, 0x19e3a5bb, 0x311bd203, 0x333b3d38, 0x1624dfc8, 0x2dfc33d0, 0x9ca0120, 0x87d1}}, + /*.y =*/{/*.val =*/{0x18af6aac, 0x3da0f107, 0x3d3bf7c4, 0x2a211d1b, 0x27745387, 0x289db3fd, 0x203de926, 0x921c296, 0x71ce}}}, +{/*.x =*/{/*.val =*/{0x30e74459, 0x1d28d722, 0x3ddb6dd6, 0x3c8dd8e1, 0x3c8a91fe, 0x3d1961c4, 0x5680590, 0x1e0753b0, 0x28df}}, + /*.y =*/{/*.val =*/{0x2f5e656f, 0x3781f303, 0x1ae6f0a8, 0x1e56e940, 0x322794a3, 0x36c5e243, 0x30f17cb0, 0x27a99a84, 0xf149}}}, +{/*.x =*/{/*.val =*/{0x29c71143, 0x11b67714, 0xf057ea3, 0x1fab6b11, 0x23fa352e, 0x1f33e400, 0x3ea103ca, 0x17e588ae, 0xeb4}}, + /*.y =*/{/*.val =*/{0xb70b136, 0x22a33688, 0x22b1bf4c, 0x165a7a9a, 0x1e2857d6, 0x1807d640, 0xbd0f573, 0xbd6160e, 0x52c4}}}, +{/*.x =*/{/*.val =*/{0x1507a7e6, 0x37cdaf22, 0x305f129b, 0x25896ebd, 0x310c41c0, 0xa1458cd, 0x1ad0d5f4, 0x142c15d1, 0x232d}}, + /*.y =*/{/*.val =*/{0x152b5892, 0x1c202084, 0x6459ccb, 0x18303bed, 0x2257f712, 0xe22b7c1, 0x33f6b086, 0xeb14d79, 0x780f}}}, +{/*.x =*/{/*.val =*/{0x177e7775, 0x222a29b8, 0xed95f63, 0x385564e2, 0x1291aeb5, 0x150eeb3d, 0x233cee58, 0x1a8ebfe5, 0x9d89}}, + /*.y =*/{/*.val =*/{0x3a056691, 0x3f3db4ea, 0x299253be, 0x26735fb8, 0x10927de8, 0x2593b5c9, 0x1bf0b94e, 0x2a790fd2, 0xdd91}}}, +{/*.x =*/{/*.val =*/{0xc904ed3, 0x1655fc7a, 0x5857841, 0xa9d1624, 0x272384df, 0x3e3990c4, 0x18dff97, 0x230b4b6e, 0xcf}}, + /*.y =*/{/*.val =*/{0x396f77c1, 0x2658ed, 0x32f6827b, 0x26475e74, 0x1bd81122, 0x35706f54, 0x1d44119d, 0x3a9e0, 0xaaad}}}, +{/*.x =*/{/*.val =*/{0xcf8cffd, 0x2cad6622, 0x3a45ae61, 0xb9ac56d, 0x1bdd8943, 0x2bee23de, 0x38c1bd45, 0x26dfc7f9, 0x80}}, + /*.y =*/{/*.val =*/{0xdb5f32f, 0x24751686, 0x12b9f93d, 0x28d03eb6, 0x12fdc912, 0x2320db79, 0x1a863028, 0x3808afd0, 0xf817}}}, +{/*.x =*/{/*.val =*/{0x2dc7a626, 0x11f741e6, 0x33cdcc02, 0x1772ade, 0x46b0734, 0x32bc48c9, 0x806bce4, 0x1b28b13e, 0x2f45}}, + /*.y =*/{/*.val =*/{0x25279532, 0x2b3ac002, 0x16eaea9e, 0x13236f70, 0x9f5302, 0x47ed991, 0x50544d2, 0x1c69e919, 0xf8cf}}}, +{/*.x =*/{/*.val =*/{0x1a328d6a, 0x2eaa0623, 0x1adc18bd, 0x135dcea5, 0x308fa7b2, 0x1a264616, 0x34e00a34, 0x3016e988, 0xc663}}, + /*.y =*/{/*.val =*/{0x3ec9b8c0, 0xec2edaa, 0x12bf9cc2, 0x21547a94, 0x171317dd, 0x2bf73c9d, 0x21c38d39, 0x3a6357dc, 0x3331}}}, +{/*.x =*/{/*.val =*/{0x22143fb0, 0x370d6995, 0x3c205dd6, 0x3ee4a0c2, 0x399597a9, 0x2bfcce51, 0x383790cf, 0x37070ceb, 0x292a}}, + /*.y =*/{/*.val =*/{0x236ad01c, 0x2a76d8f3, 0x35e9d4d8, 0xf998b5c, 0x4ecf6d8, 0x65a2833, 0xb647f3f, 0x1986f3b8, 0xa072}}}, +{/*.x =*/{/*.val =*/{0x30b90e0b, 0x27b079b0, 0x3094a458, 0x3fc74e7e, 0x675b3d6, 0x32012967, 0x67d3fed, 0x1fe6b55, 0xa435}}, + /*.y =*/{/*.val =*/{0x3a1fdc20, 0x3c002e64, 0x3599b5a3, 0xa880d94, 0xbe8c0dc, 0x341f32d0, 0x3d71a142, 0xb72530f, 0x7c8f}}}, +{/*.x =*/{/*.val =*/{0x188f4d82, 0x2e7474ad, 0x159204ac, 0x9937676, 0x21d6fcaf, 0x170c09b0, 0x1c515b0e, 0x1665c1b9, 0x6dd5}}, + /*.y =*/{/*.val =*/{0x14132ad3, 0x287aadab, 0x15927be5, 0x3db9c11b, 0x2d0f9478, 0x3346376d, 0x1233dd46, 0x109ff54d, 0xbc92}}}, +{/*.x =*/{/*.val =*/{0x1e05dccc, 0xcb60046, 0x19a93e5, 0xfe8fb53, 0x13d172ae, 0x1b825ae5, 0x1a030954, 0x3db85d4f, 0xb8ce}}, + /*.y =*/{/*.val =*/{0xc6d5750, 0x52833f, 0x26b68133, 0x1d5ff0da, 0x12bd99df, 0x3529d393, 0x9bbf6a4, 0x229829b3, 0x302b}}}, +{/*.x =*/{/*.val =*/{0x286df50d, 0x313bb405, 0x6f92bd0, 0x179e4a87, 0x82060cd, 0x361d10b0, 0x1f02d6f, 0x58c24d7, 0x3a57}}, + /*.y =*/{/*.val =*/{0x2859679b, 0x8562ca3, 0x3781a11d, 0x2abe07ae, 0x30a0dde0, 0x3cffcb95, 0x1f32f516, 0xe1ced66, 0x85e1}}}, +{/*.x =*/{/*.val =*/{0x388f7e09, 0xaa8ad9f, 0x27d92cde, 0x280dde6e, 0x1dc0beb3, 0x384b9691, 0x5fcbbd8, 0x218f53c8, 0x5e6a}}, + /*.y =*/{/*.val =*/{0x8dfca97, 0x2f58a19d, 0x3b4cfe3b, 0x23940dc8, 0x140234a6, 0x12a347da, 0x8edfc44, 0x681e28e, 0xc257}}}, +{/*.x =*/{/*.val =*/{0x1df66583, 0x3b2a229b, 0x25580609, 0x6433e68, 0x1ea87603, 0x38bdfbf, 0x2fd019c1, 0x1c6d48f0, 0x5281}}, + /*.y =*/{/*.val =*/{0x3f480c26, 0x3407b39, 0x3de01414, 0x8104f71, 0x1e8fb495, 0x2f3a351a, 0x27a6598, 0xe575ec3, 0x7b2c}}}, +{/*.x =*/{/*.val =*/{0x2521b3ff, 0x38a61193, 0x1aa750ce, 0xf01c5fa, 0x2e24a523, 0x1134afa6, 0x1455c75e, 0x138c0432, 0x248}}, + /*.y =*/{/*.val =*/{0x269da7e, 0x306b92e4, 0x23ac8bbc, 0x1c01b7a4, 0x2d0eebad, 0x30acf0ac, 0x3e30d07e, 0x34282a88, 0x9619}}}, +{/*.x =*/{/*.val =*/{0x692fd1, 0x2c982585, 0x3d90dfe2, 0x3d0f1b32, 0x1f190edc, 0x2ab7bd2c, 0x1ff800e0, 0x322d2640, 0x4e53}}, + /*.y =*/{/*.val =*/{0x328625e0, 0xd24c39c, 0x3fc97539, 0x1e943695, 0x219da1a8, 0x335c269c, 0x1a01e186, 0xf93d350, 0xdd6e}}}, +{/*.x =*/{/*.val =*/{0x3549827b, 0x2338d5f6, 0x121bd614, 0x313dfcf8, 0x2ce311fc, 0x4b81b78, 0x375f3a82, 0x343d7834, 0xce47}}, + /*.y =*/{/*.val =*/{0x2faed097, 0xf32697f, 0x5769df4, 0x39964bfc, 0x39ad0f29, 0x244e7f96, 0x30d49d58, 0x263ee658, 0x15c6}}}, +{/*.x =*/{/*.val =*/{0xc43da59, 0x3747b53a, 0x3a48ca2f, 0x6911b8a, 0x6cf9bc9, 0x1c4ebfe0, 0x21a3319b, 0x1f592302, 0x7115}}, + /*.y =*/{/*.val =*/{0x248d28ac, 0x1f7884ad, 0xcb6ad56, 0x33c28fe9, 0x11ab13fc, 0x28440e45, 0x303053f2, 0x35451759, 0x3d53}}}, +{/*.x =*/{/*.val =*/{0x3e889756, 0x37606ba6, 0x3004bb25, 0x1ed9265e, 0x1899f3f2, 0x3365ec9c, 0x1fea8226, 0x22f0cc84, 0x762e}}, + /*.y =*/{/*.val =*/{0x3ca6b774, 0x17896781, 0x84fa5e2, 0x1cb6cc52, 0x2e34719, 0x3313c526, 0x3e97c3c7, 0x250982bc, 0xc028}}}, +{/*.x =*/{/*.val =*/{0x26714560, 0x1d560296, 0x256c6c28, 0x1fc8409f, 0x25a85c24, 0x1fbd93c6, 0x2d36b9d4, 0xa9d55e6, 0x38b8}}, + /*.y =*/{/*.val =*/{0x2774299e, 0x36a1ccd2, 0x3716284a, 0x253c8efb, 0x2434597d, 0x3d58d185, 0x21ef428b, 0x29a5dbc9, 0xf9d8}}}, +{/*.x =*/{/*.val =*/{0x1b720b26, 0x188bac12, 0xccfcd07, 0x3ca0d7e6, 0x39062026, 0x1aefb504, 0x168ee1f4, 0x316ba6b2, 0x3e10}}, + /*.y =*/{/*.val =*/{0x2dd92db5, 0x11ba631e, 0x3e09e433, 0x3fde6936, 0x215e28e2, 0x1996ca1c, 0x288915a8, 0x31b3ff90, 0xc735}}}, +{/*.x =*/{/*.val =*/{0xc15cf94, 0x3710a097, 0x12082845, 0xff5aa0, 0x3569f8bd, 0x1bdc4615, 0xd97eb79, 0x2979dbec, 0x1dc5}}, + /*.y =*/{/*.val =*/{0x140ef8a2, 0x3e95399e, 0x25d97f94, 0xb6f12d6, 0x72d0c65, 0x1ccc46a4, 0x367d6019, 0x22b89d5f, 0x855b}}}, +{/*.x =*/{/*.val =*/{0x78ee8d, 0x3c142473, 0x6919442, 0x2fc83394, 0x1b4ff64e, 0x3dc98eaa, 0x1a9be25f, 0x15eb6167, 0xd08e}}, + /*.y =*/{/*.val =*/{0x2da63e86, 0x265fd370, 0x22ed9de, 0xfbdf3e5, 0x3e6df412, 0x5cbb9d5, 0x88d72d6, 0x25e612ad, 0x852e}}}, +{/*.x =*/{/*.val =*/{0xe9c22bc, 0x10eb950c, 0x1bcc42fd, 0x3699f5a4, 0x3c7be601, 0x2cd11366, 0x2eb23765, 0x33a97a67, 0x5335}}, + /*.y =*/{/*.val =*/{0xbdacb60, 0x30b099cb, 0xa1f19b3, 0x30c308db, 0xeb86ac8, 0x1fc203c3, 0x5224a06, 0x34081da7, 0x3bf8}}}, +{/*.x =*/{/*.val =*/{0xff4de54, 0x2f079885, 0x1d3c2be5, 0x32af647a, 0xa2858a5, 0x100c73c5, 0x202a2c3b, 0x370d577c, 0x5716}}, + /*.y =*/{/*.val =*/{0x10100fa5, 0xfa93f55, 0x47e417d, 0x3cffb334, 0x1324c5eb, 0x2a9986a6, 0x383f391e, 0x1b100296, 0x985f}}}, +{/*.x =*/{/*.val =*/{0x2336a875, 0x108cff13, 0x19d064c1, 0x3b71c748, 0x2f1b5099, 0x15be606, 0x2d4dd947, 0x16786af8, 0x24a6}}, + /*.y =*/{/*.val =*/{0x1112057c, 0x3cffa170, 0x1e0b96ab, 0x2911927a, 0x1cf34f69, 0xcc6f51f, 0x27240468, 0x2beb142f, 0xd3e1}}}, +{/*.x =*/{/*.val =*/{0x761d58d, 0x12eabcce, 0xd60e2f3, 0x1326f902, 0x20df7aca, 0x9028d5c, 0x3614610a, 0x1849e08f, 0xb8c4}}, + /*.y =*/{/*.val =*/{0x1d1051a4, 0xe3a82ea, 0x2107c5b6, 0x1d411e17, 0x33c5053f, 0x1163da5f, 0xe37d14a, 0x365b145c, 0x8f9e}}}, +{/*.x =*/{/*.val =*/{0x1166ff40, 0x537a868, 0x1fff36da, 0x3bafd290, 0x80a2eca, 0x20497639, 0x18d2b7c7, 0x100cc620, 0x6b00}}, + /*.y =*/{/*.val =*/{0x1d71b847, 0x2dd04c3a, 0x3f3ede9e, 0x1a20fdb9, 0xbf2f007, 0x250e8164, 0x2fac9968, 0x6ceba2a, 0x41cd}}}, +{/*.x =*/{/*.val =*/{0xd6bf1f, 0x114841ae, 0x24fcbb0, 0x2f40cfa6, 0x3346b946, 0x87a49da, 0xb83ca35, 0x1cd0d147, 0xc333}}, + /*.y =*/{/*.val =*/{0x3cb01f48, 0x25796108, 0x2266162f, 0x2e8d9083, 0x2c315598, 0x3fcc6bdc, 0x12cda13d, 0x3a4e46e0, 0x2eef}}}, +{/*.x =*/{/*.val =*/{0x34d9279c, 0x12d43f2a, 0x99a0075, 0x1e171e64, 0x3a845c28, 0x15c0bb20, 0x22c5776b, 0x38539f8a, 0x7121}}, + /*.y =*/{/*.val =*/{0x2f97b82e, 0x1c80a5f8, 0x1100d1ec, 0x3e8a0cd2, 0x35046e47, 0x2e865b4c, 0x105ca520, 0x30028c67, 0xf194}}}, +{/*.x =*/{/*.val =*/{0x2127b756, 0x2ea1ffd, 0x3a097048, 0x10a2f92a, 0x20b41603, 0xd8b6941, 0x1f12672d, 0x1e0bdc5b, 0x6d8c}}, + /*.y =*/{/*.val =*/{0x3f172571, 0x1547dd2a, 0x17cdcca6, 0xea9b68b, 0x134daf4e, 0x26a0b4db, 0x1b911145, 0x37c225bf, 0x99ae}}}, +{/*.x =*/{/*.val =*/{0x11a3c43c, 0x1312cb15, 0x2cee258e, 0x3dc072a3, 0x2e67140d, 0x307cad2a, 0x2cd5b48c, 0x36a519f2, 0x56c9}}, + /*.y =*/{/*.val =*/{0x20d7c9ed, 0x9362df4, 0x2edcaa18, 0x3503fe4c, 0xb685241, 0x31e59377, 0x39ec2f33, 0x1ab2d0b1, 0x38d4}}}, +{/*.x =*/{/*.val =*/{0x2df771c8, 0x27892740, 0x2094c87b, 0x1694847b, 0x1f875033, 0xb0acf00, 0x1c9029d3, 0x151b648b, 0xb71e}}, + /*.y =*/{/*.val =*/{0x13f48c51, 0x114e89be, 0x1bba2862, 0x2f548ad5, 0x2288f426, 0x4a93333, 0x1f900789, 0x3bea33b2, 0xe7cc}}}, +{/*.x =*/{/*.val =*/{0x2ee40896, 0x27f5e5b0, 0x1177f5bf, 0x2b8dea49, 0x261e6aa1, 0x1b819399, 0x36de46bb, 0x3c06c124, 0x7a0d}}, + /*.y =*/{/*.val =*/{0x44a7569, 0xb6393bc, 0x117da7f2, 0x8a28a35, 0x290e9aaa, 0x35abfd7a, 0x2fcd1b2a, 0x1d6038d5, 0xb446}}}, +{/*.x =*/{/*.val =*/{0x6e1346b, 0x28661277, 0x5af1c5e, 0x2f9ec40e, 0x1152c05a, 0x31d87c53, 0x2d10be54, 0x1a3fc260, 0x690}}, + /*.y =*/{/*.val =*/{0x17226c13, 0x2ed62953, 0xc6026e7, 0x3da24e65, 0x6442aa4, 0x176caf42, 0x3de26da8, 0x38f8242f, 0xb863}}}, +{/*.x =*/{/*.val =*/{0x3235c795, 0x2138aef1, 0x3d541d75, 0x362563a, 0x1c89d70b, 0x2c16cdf4, 0x3974b393, 0x11890d7b, 0x63c}}, + /*.y =*/{/*.val =*/{0x1b110258, 0x3ccb7025, 0x249a9bd3, 0x12b2eb3e, 0x1c85b69e, 0x3d98364c, 0x38404431, 0x26ee44c0, 0xe27f}}}, +{/*.x =*/{/*.val =*/{0x2c1cbaab, 0x34de9fc5, 0x33d564cf, 0x32ae1e40, 0x30635c1a, 0x2adb0629, 0x16071598, 0x2ba63ecd, 0xd031}}, + /*.y =*/{/*.val =*/{0x5116b26, 0x30e411fe, 0x3d65fdc4, 0x3ed293f6, 0xb4dcf6d, 0x39301ab7, 0x584e8e6, 0x25ad3a55, 0x4151}}}, +{/*.x =*/{/*.val =*/{0x1affca70, 0x3f44d85f, 0x14ce5fd1, 0x1addc21d, 0x12d1f999, 0x3565346a, 0x3861d3ff, 0x47bce91, 0xd4c0}}, + /*.y =*/{/*.val =*/{0x3d9c4777, 0x31fcb8a5, 0x256ebb09, 0xbd1ec15, 0x2b2906b2, 0x1d086400, 0x21566287, 0x12e620e9, 0x90b2}}}, +{/*.x =*/{/*.val =*/{0x17592d55, 0x300d67b3, 0xe350192, 0x356e51d0, 0x3ce3b106, 0x3fbda58c, 0x1052608a, 0x31b6f128, 0x5d2e}}, + /*.y =*/{/*.val =*/{0x2f5183a7, 0x19b9743a, 0x11151742, 0xa9ef36b, 0xcd6950e, 0x1c43e89a, 0x245eb58f, 0x337e271b, 0xa92}}}, +{/*.x =*/{/*.val =*/{0x255bf84c, 0x1d12e3e3, 0x30d9027a, 0x1931bb55, 0x3cae4fd9, 0x34f09488, 0x16cc8e5d, 0xa2673ae, 0x6278}}, + /*.y =*/{/*.val =*/{0x1f15fa2a, 0x3d473ead, 0x1d176ed6, 0x8379f7, 0x3267839a, 0x1525c8a5, 0x1a28901c, 0x2b290244, 0xd670}}}, +{/*.x =*/{/*.val =*/{0x339715c2, 0x2651c743, 0x18a529a3, 0x19487e, 0x33fedd69, 0x7de33a8, 0x23d85b41, 0x27a23c66, 0x2f18}}, + /*.y =*/{/*.val =*/{0x171dfea, 0x1a98d611, 0x36854f06, 0xcccf8b0, 0x10f9f7eb, 0x211d7b4, 0x1d7cfdf7, 0xe7e3cf1, 0xc91a}}}, +{/*.x =*/{/*.val =*/{0xa222636, 0xd7de0d8, 0x299b9d3, 0x1e81212d, 0x2f88e93a, 0x3ac63cd9, 0x8f0e572, 0x2fb8c76f, 0xe583}}, + /*.y =*/{/*.val =*/{0x36b01c43, 0x3ac98e19, 0x18800b01, 0xfa7944d, 0x1dc3ac25, 0x9d40507, 0x1ddd7416, 0x1479107b, 0x75b0}}}, +{/*.x =*/{/*.val =*/{0x138011fc, 0x1c049c00, 0x17285626, 0x165a99eb, 0x200a4d83, 0x2c4cc208, 0x1eb11156, 0x4e8c205, 0x6e83}}, + /*.y =*/{/*.val =*/{0x3f15ab7d, 0x2b2da7e8, 0x1c51f9a6, 0x2be456ba, 0x1ac30426, 0x4b6c807, 0xf204c1a, 0x2062f709, 0xc147}}}, +{/*.x =*/{/*.val =*/{0x195b6f7e, 0x25527d71, 0x38b2021f, 0x2ccad4f4, 0x1876cdbe, 0x14eab42, 0x1a30c83a, 0x1f474133, 0xa5ac}}, + /*.y =*/{/*.val =*/{0xab19c84, 0x236edcc2, 0x1818a484, 0x38e4583d, 0x19ee1b99, 0x30f2491f, 0xf55b36c, 0x2282ad50, 0xdf0b}}}, +{/*.x =*/{/*.val =*/{0xe81c1bc, 0x24e92b93, 0x2bb5b33b, 0x14d97962, 0xce767d2, 0x2056e35a, 0x4635ad, 0x3c15197, 0x336}}, + /*.y =*/{/*.val =*/{0x166cbedd, 0x1b74a259, 0x8115017, 0x5ca3ad7, 0x30675323, 0x1a710944, 0x350014ff, 0x2d7e4315, 0x7e48}}}, +{/*.x =*/{/*.val =*/{0x14bc0324, 0x2a208b00, 0x24d2cfc5, 0x21fc0a35, 0x2f119155, 0x198968d9, 0xe7c338e, 0x299908fa, 0xb96b}}, + /*.y =*/{/*.val =*/{0x36c2ee15, 0x2d3afff6, 0x25ba8374, 0x33948a51, 0x1876b383, 0x3119268a, 0x285dfbea, 0xb336cee, 0xe83c}}}, +{/*.x =*/{/*.val =*/{0x30b7b678, 0x9d76cce, 0xf638166, 0xf10c46f, 0x2b6c76f1, 0x21af2909, 0x231ba19, 0x125ccd39, 0x186e}}, + /*.y =*/{/*.val =*/{0x38d91fc1, 0x1e81dbcb, 0x9535dca, 0x1dc8951, 0x37e67e11, 0x3f209702, 0x3bd84aa7, 0x18392601, 0xc0d4}}}, +{/*.x =*/{/*.val =*/{0xbb9dc8f, 0x23226e1, 0x1edd333d, 0x2a7a4fbd, 0x2787d1ab, 0x3dc0d4d4, 0x26864248, 0x1073b870, 0xfd99}}, + /*.y =*/{/*.val =*/{0x259780d5, 0x10fab94f, 0x2fe938d7, 0x1cacbf7b, 0x859e678, 0x25f815e2, 0xe6f46de, 0x3b1d6f50, 0x7a41}}}, +{/*.x =*/{/*.val =*/{0x3b963645, 0xfa50cb0, 0x271f1f8e, 0x336ca01f, 0x3132fb2d, 0x11e068b8, 0xa63e6e7, 0x2553ec6e, 0xc5f0}}, + /*.y =*/{/*.val =*/{0x8be2dd, 0x2fe21d3c, 0x47be4ed, 0xc140ac0, 0x20d7e6a3, 0xf2d1009, 0xb6fb18a, 0x34c4086c, 0xd552}}}, +{/*.x =*/{/*.val =*/{0x3b6aa206, 0x370ed72e, 0x31c19bce, 0xd5807fd, 0x1ac744bd, 0x4e3fc55, 0x1f7d2ec7, 0x215da31f, 0x9dac}}, + /*.y =*/{/*.val =*/{0x13b30b86, 0x235f518a, 0x23ff64cc, 0x1aaae446, 0x3bde77fa, 0x90ceda, 0x37bba791, 0x32b82b93, 0xb23c}}}, +{/*.x =*/{/*.val =*/{0x123809fa, 0x238ae3b7, 0x1d954be1, 0x21172cd4, 0x51f08fd, 0x24cd8fc9, 0x9f228ba, 0x76f8b94, 0x3838}}, + /*.y =*/{/*.val =*/{0x331fed52, 0x35c1d460, 0x2d8f24db, 0x207f32cc, 0xeb1cc36, 0x10169548, 0x117dcb09, 0xb4283ee, 0xe4a3}}}, +{/*.x =*/{/*.val =*/{0x3663da4, 0x2059b064, 0x35d0b81f, 0x28d8a467, 0x4aa2ba5, 0x229bb5f1, 0x1705e680, 0x128d5aa9, 0x6a66}}, + /*.y =*/{/*.val =*/{0x33fc22c4, 0xa0c4fec, 0x26c04c9c, 0x2645849f, 0x3f0cd508, 0x21bb065a, 0x1e98b29f, 0x496553f, 0x449a}}}, +{/*.x =*/{/*.val =*/{0x5ed815e, 0x3dc0b54, 0x1c017b47, 0x3d102af0, 0x147ad166, 0x17eb4865, 0x34a32ebb, 0x36b19e7d, 0x5568}}, + /*.y =*/{/*.val =*/{0x602df0, 0x26efd930, 0x2582151d, 0x17dfbb8, 0x73f2beb, 0x35bf8074, 0xba64580, 0x3e1d09e2, 0x7a85}}}, +{/*.x =*/{/*.val =*/{0x1ee840f8, 0x105d4ebc, 0x13c98f26, 0x4070980, 0x325cbe11, 0x2752e0a5, 0x3be4ecfc, 0x16a03720, 0x8719}}, + /*.y =*/{/*.val =*/{0x27eed395, 0x8a09a41, 0xa8dfa80, 0x22709c24, 0x1a2138dd, 0x3db76d2a, 0xe3aeb15, 0x773265b, 0x603}}}, +{/*.x =*/{/*.val =*/{0x2bf05bd6, 0xe67c139, 0x12a99465, 0x3d5b80c8, 0x70deca2, 0xbd47fad, 0x4fe9083, 0xc906fb9, 0x900c}}, + /*.y =*/{/*.val =*/{0x300d358b, 0x394ab4ef, 0x4efb15d, 0x2614d60f, 0xb2439d6, 0x31c8115c, 0x1f0f5f95, 0x3e7a3a2c, 0x6c31}}}, +{/*.x =*/{/*.val =*/{0x272e294d, 0x39becbde, 0xd0dd5b, 0x163ae8fc, 0x37edc6f1, 0xa27abb7, 0x134b91a6, 0x39201735, 0x29df}}, + /*.y =*/{/*.val =*/{0x2c469b52, 0x104dc983, 0x129ee694, 0x3c65870e, 0x205e4dd1, 0xd39d622, 0x272e19b4, 0x3609b401, 0xbf66}}}, +{/*.x =*/{/*.val =*/{0x33773f7, 0x31fc011b, 0x1b599953, 0x3513f4d1, 0x2372a150, 0x10430027, 0x1236d3e1, 0xc89bd77, 0x355b}}, + /*.y =*/{/*.val =*/{0x1887c182, 0x14f0ffc, 0xe251090, 0x977de33, 0x21fcb81e, 0x43bb774, 0x303ad49f, 0x29201c11, 0x8ec}}}, +{/*.x =*/{/*.val =*/{0x141fcc76, 0x10109c92, 0x227146b3, 0x34d666d9, 0x278a558d, 0x2ca70c2, 0x2d4ad848, 0x30c91061, 0x2a1e}}, + /*.y =*/{/*.val =*/{0x2451553f, 0x2837c990, 0x382a3120, 0x1549d580, 0x3e3b61b2, 0x2fb05054, 0x1cacf4c1, 0x20b9a3d9, 0xe01e}}}, +{/*.x =*/{/*.val =*/{0x2bfd913d, 0xfe5580f, 0x254c9eac, 0x29a039bb, 0x2a8d2050, 0x1e82130, 0x3ddf874d, 0xaa9fa41, 0x3636}}, + /*.y =*/{/*.val =*/{0x52e243d, 0x113e6bab, 0x2b2faafc, 0xc2ec435, 0x1a2a82d8, 0x18910dc3, 0xafd5341, 0x1e19db2e, 0x48f2}}}, +{/*.x =*/{/*.val =*/{0x375732c0, 0x1661934d, 0x33777aa8, 0xbf979c8, 0x31096e20, 0x29746df2, 0x34b9b624, 0x33cc7e2d, 0x8f3c}}, + /*.y =*/{/*.val =*/{0x25b9415b, 0x1cef7979, 0x858825e, 0x39a1dd5, 0xe53d8a9, 0x3d1b665f, 0x1e53189e, 0x334f8b4e, 0x67f1}}}, +{/*.x =*/{/*.val =*/{0x34889f3f, 0xa87e0e4, 0x1095da7f, 0x3faca2d1, 0x29b0ebc4, 0x28d1a6c5, 0x2119621e, 0x409bc6c, 0x8799}}, + /*.y =*/{/*.val =*/{0x3bb792b, 0x278b7e6f, 0x286037b4, 0xcbd86fc, 0x3f279de9, 0xbcb2dc5, 0x11d96213, 0x2e53296a, 0xddea}}}, +{/*.x =*/{/*.val =*/{0x2fa4e07e, 0x37614061, 0x3423bec4, 0xb29d215, 0x337d9a49, 0x7040ffe, 0x35718422, 0x2be545f7, 0x37d7}}, + /*.y =*/{/*.val =*/{0x2e020165, 0x24db61da, 0x18a65a4c, 0x8faa25e, 0x19c556c4, 0xecd4b18, 0x133c8f47, 0x1ea4a06a, 0x35bc}}}, +{/*.x =*/{/*.val =*/{0x3aee42db, 0x3e7f4af, 0x330714a7, 0x2eef16d1, 0x2cbfc1d9, 0x2dbb6e47, 0x19150fc7, 0x9f9f66d, 0xcc34}}, + /*.y =*/{/*.val =*/{0x15d87bdb, 0x188a7004, 0x272422dc, 0x3972eb63, 0x21520010, 0x38ff4fec, 0x1c6a1885, 0x26106948, 0xea24}}}, +{/*.x =*/{/*.val =*/{0x2e96e4f1, 0x2c29c594, 0x2e80030c, 0x17c05802, 0x1efccaff, 0x1ddc20cd, 0x197e201, 0x523c066, 0x56bb}}, + /*.y =*/{/*.val =*/{0x2eb0582e, 0x2227c067, 0x4af0eb5, 0x4f47480, 0x30ea9f73, 0xfb62f8, 0xa33beb, 0x2129584c, 0xa095}}}, +{/*.x =*/{/*.val =*/{0x1f23d1f, 0x1315fd66, 0xc036d8a, 0x2c97f5c8, 0x18a0a6b6, 0x3522787f, 0x30bbbbd3, 0x3a054f59, 0xb398}}, + /*.y =*/{/*.val =*/{0x32ff3fc, 0x160faffe, 0x26156cd1, 0x1e4762b4, 0xba52ea, 0x1ffacbec, 0x1f47f07f, 0x270895cb, 0x69f5}}}, +{/*.x =*/{/*.val =*/{0x34fb6a39, 0x9f576c6, 0x2ac90ecd, 0x235ab493, 0x1e119b8b, 0x3f4a59c, 0x1ea6e43e, 0x25abd5e5, 0x459}}, + /*.y =*/{/*.val =*/{0x725bb62, 0x30ab6de8, 0x20010535, 0x388a2d03, 0x2eef0373, 0x218a0837, 0x26c33672, 0x2b8338e0, 0xd3f9}}}, +{/*.x =*/{/*.val =*/{0x319888e9, 0xe73c9e4, 0x2448a8b4, 0x4ae9afc, 0x2681673d, 0x1834c0a5, 0x3a6e2dde, 0x3a9dceb0, 0x1f90}}, + /*.y =*/{/*.val =*/{0x2f113b79, 0x1bf7f25f, 0x19522e65, 0xdd47fb9, 0x2b96a821, 0x54f49c7, 0x2a10e958, 0xd9f0576, 0x89be}}}, +{/*.x =*/{/*.val =*/{0x1bf6c42, 0xfaacf77, 0x19887539, 0x1e4f66c4, 0xee74ef7, 0x1195205b, 0x105c7ee7, 0x6cf35b0, 0xd02e}}, + /*.y =*/{/*.val =*/{0x7bc54cc, 0xcd8ca3e, 0x31b6aac1, 0x2961e6e4, 0x124526bc, 0xc89c343, 0x22258127, 0x1d3cf2a3, 0x9a0b}}}, +{/*.x =*/{/*.val =*/{0xf6c15c2, 0x7bd1fc6, 0xf38f1ca, 0x39d90532, 0x1143483d, 0x1ce604e7, 0x1757fea1, 0x2a14af28, 0x8456}}, + /*.y =*/{/*.val =*/{0xb174134, 0x3c7bf0ca, 0x16fb671f, 0x3243c261, 0x79e7f4c, 0x127b0dc4, 0x2cdefd3, 0x3691b521, 0xe1b9}}}, +{/*.x =*/{/*.val =*/{0x27df614a, 0x1d47ebb3, 0x24705eb2, 0x27f39a4c, 0x3e1804d7, 0x91aa7fa, 0x33049180, 0x3966340b, 0xa7d2}}, + /*.y =*/{/*.val =*/{0x159b4c8d, 0x3c32f0e5, 0x19bc8656, 0x3c01de54, 0x3fa2de53, 0x207bb042, 0x10172c79, 0x33512f0, 0x62a2}}}, +{/*.x =*/{/*.val =*/{0xca1c4f9, 0x16d0aa86, 0x2b7e2823, 0x13bf8d32, 0x1f16f44f, 0x2e0f698, 0x1728c4c4, 0x3de3c8af, 0x7815}}, + /*.y =*/{/*.val =*/{0x3778bc15, 0x2ac7a8da, 0x177d1e19, 0x2d0b7985, 0x18c35d5c, 0x24f3cc51, 0x1af6a7dd, 0x7a334e, 0xc1c6}}}, +{/*.x =*/{/*.val =*/{0x3ed5996, 0x37933a2d, 0x360af53b, 0xc7f9664, 0x1b92468, 0x3ef240ca, 0x1a4ea492, 0x2dfa7fa6, 0x1a46}}, + /*.y =*/{/*.val =*/{0x28c85cae, 0x3b93b447, 0x352745c2, 0x21e52a7b, 0x23ebf550, 0x3b821281, 0x1dc570e3, 0x3a07a8fc, 0x683c}}}, +{/*.x =*/{/*.val =*/{0x2e2e607b, 0x3d34d673, 0xf36aa1, 0x2a87bb1b, 0x3fdd2b88, 0x447d595, 0x1772c20d, 0xfd9ff4c, 0x773}}, + /*.y =*/{/*.val =*/{0xc614763, 0x28bcc477, 0x3e017d26, 0x38ef7816, 0x3156f489, 0x18ea316e, 0x38285eae, 0x3a3eeb05, 0xfd9f}}}, +{/*.x =*/{/*.val =*/{0x354d61d1, 0x3ecb8807, 0x30b99baf, 0x549d76f, 0x1bf21517, 0x23e67901, 0x3ed8b9c5, 0x4f91d89, 0x875e}}, + /*.y =*/{/*.val =*/{0x945747, 0x12a27470, 0x273c5309, 0x277543a5, 0x399e3601, 0x1b784f4d, 0x56e8f64, 0x37712a59, 0x2d8f}}}, +{/*.x =*/{/*.val =*/{0x2fd53ed3, 0x17245d60, 0x1a56ccef, 0xfdd3ee7, 0x1f7c4916, 0x3d82e4c7, 0x372ad5b8, 0x2f56659, 0x2084}}, + /*.y =*/{/*.val =*/{0x1a7a7132, 0x1c50ff94, 0xe708998, 0x21f11ce5, 0x3afac254, 0x2f51da9a, 0x18243487, 0xd25f3b0, 0xf299}}}, +{/*.x =*/{/*.val =*/{0x2032f9a2, 0x122e38a4, 0x21fc6ccc, 0x159bd43e, 0x3f8f63ce, 0xdd32cc7, 0x32640ed2, 0x31af669a, 0x25aa}}, + /*.y =*/{/*.val =*/{0x2b51d4f0, 0x1d88c284, 0x19f3d9e, 0x2620eef1, 0x3190f655, 0xcbd53d3, 0x546c16f, 0x318ee991, 0xf5a6}}}, +{/*.x =*/{/*.val =*/{0x14445a7a, 0x4c72ea, 0x1cf1ec59, 0x254d7c20, 0x1c8d5df, 0x3c46db18, 0x2c6bfb12, 0x3bef27c1, 0xf82f}}, + /*.y =*/{/*.val =*/{0x242a7a98, 0x18eb3861, 0x240d1e59, 0x720ed91, 0xb4a4b5, 0xe50b065, 0x36b67550, 0xdef71be, 0x94bb}}}, +{/*.x =*/{/*.val =*/{0x362b8df9, 0xcb7ede8, 0x1da21c57, 0x7f6d47d, 0x11c8bd49, 0xcb74b72, 0x1c0cd9a8, 0x37634fb7, 0x11c4}}, + /*.y =*/{/*.val =*/{0x296edd30, 0x60c9e79, 0x2ec5448f, 0x2df9f498, 0x10fb6417, 0xd810e22, 0xac2aae4, 0x361da2fd, 0x45b3}}}, +{/*.x =*/{/*.val =*/{0x1def001d, 0x13c89769, 0x9ba27ef, 0x3e6ef5a6, 0x23b64b21, 0x2f47027, 0x22caf20e, 0x28cb6c9f, 0xa549}}, + /*.y =*/{/*.val =*/{0x30624783, 0x3576c69f, 0x2c9705ad, 0x5078a98, 0x259456eb, 0x330c3b62, 0x166cbdf4, 0x1e9e41b6, 0x799b}}}, +{/*.x =*/{/*.val =*/{0x206e37a, 0x91de2b1, 0x504731a, 0x23062523, 0x1a274f4d, 0x3a0fd1ad, 0x28002cf4, 0x2ae1fca1, 0xb526}}, + /*.y =*/{/*.val =*/{0x30c5ccab, 0x3cd9e3ff, 0xfa392ab, 0x3394e6c0, 0x26f18d28, 0x2ab3b582, 0xd8ed5c, 0xd75de04, 0x641f}}}, +{/*.x =*/{/*.val =*/{0x39d9123f, 0x3a4e0c7a, 0x388ba7d7, 0x3f1e46c7, 0x3d1e9129, 0x17e3b2be, 0x26a6f2f9, 0x14e3dcaa, 0x341b}}, + /*.y =*/{/*.val =*/{0x18bb9a40, 0x27a82abc, 0x12a26ed1, 0x37b9a9c1, 0x24d9ac72, 0x3cbc1044, 0x1c59eba6, 0x491c670, 0x5858}}}, +{/*.x =*/{/*.val =*/{0x760cb4d, 0x25763239, 0x33a69b68, 0x21f81500, 0x30673803, 0x154bafb0, 0x9df521a, 0x1fb94e37, 0xbca3}}, + /*.y =*/{/*.val =*/{0x24e10d88, 0x29dc18da, 0x8df9cf3, 0x5d5563c, 0x2ffbad9f, 0x22e020ee, 0x2d4b2263, 0xec707ef, 0x3ce0}}}, +{/*.x =*/{/*.val =*/{0xfb64db3, 0x1ee6354e, 0x1dd53841, 0x3b79328e, 0x13b8d6a7, 0x2ee0fef9, 0x1ccb740b, 0x8e48a6f, 0xc114}}, + /*.y =*/{/*.val =*/{0x3c0259be, 0x8c33a7f, 0x14567d1e, 0x1d602413, 0x178bd1a8, 0x3b3793fa, 0x6fc2a5c, 0x3db716d2, 0x1237}}}, +{/*.x =*/{/*.val =*/{0x311349e2, 0x20cab77, 0x3524c058, 0x38fb3d05, 0x1ad78d60, 0x51fa690, 0x1c2e7e62, 0x20c931ae, 0xf805}}, + /*.y =*/{/*.val =*/{0x1b2025fc, 0x3eb11a79, 0x26de88d5, 0x25262d58, 0x21122350, 0x206a983a, 0x56cdcde, 0x39682a2, 0x95c6}}}, +{/*.x =*/{/*.val =*/{0x2e548418, 0x1cdc7446, 0x9839231, 0x39221f62, 0x3a341adc, 0x1cac14d, 0x17e292fb, 0x2c327920, 0x2e6d}}, + /*.y =*/{/*.val =*/{0x10a2b918, 0x1a5e4b00, 0x1c3f5f1e, 0x23875cf8, 0x2911644b, 0xc5225e2, 0x36fbfa21, 0x1a90475d, 0x74eb}}}, +{/*.x =*/{/*.val =*/{0x3ccbdf95, 0x2b8fa3b1, 0xa5853b4, 0x8ac7291, 0x22f5494, 0x360c0ab2, 0x313050f, 0xbb60387, 0xcea0}}, + /*.y =*/{/*.val =*/{0x324a006c, 0x39954baa, 0x2ecc53d9, 0x2e8a1483, 0x10b433b2, 0x3301f5b, 0x34a6f04e, 0x1b1b61df, 0xfc00}}}, +{/*.x =*/{/*.val =*/{0x171c032b, 0x3536858a, 0x3afdc980, 0x1ad9a285, 0x766c5ff, 0x46d7f7f, 0x2603dd, 0x2a3f35b8, 0x71eb}}, + /*.y =*/{/*.val =*/{0x1668359f, 0x1ead6a38, 0x34b4755e, 0x24c6b45d, 0xcbb7f71, 0x18145bd5, 0x1d39def6, 0x49892d8, 0xd2ff}}}, +{/*.x =*/{/*.val =*/{0x3aaa138b, 0x37c367dc, 0x3786cd66, 0x3bee82fb, 0x671ff63, 0xfaf0631, 0x3ae28794, 0x389274f0, 0x417f}}, + /*.y =*/{/*.val =*/{0xa1ae869, 0x7246ccd, 0x5566afd, 0x276bf7b0, 0x3a9e57c1, 0x2974a7c3, 0x23e38c20, 0x2275ef34, 0x235}}}, +{/*.x =*/{/*.val =*/{0x307e636, 0x38562d04, 0x21611d97, 0x29df79cc, 0x2112c8b4, 0x2f0a6f68, 0x76443dd, 0x3c58058e, 0x2219}}, + /*.y =*/{/*.val =*/{0x31f15109, 0x1e86cb5, 0x373af55e, 0x35c8c34f, 0x230bd6d, 0x1b53c6e, 0x2a2f61b8, 0x212b172d, 0x4a9}}}, +{/*.x =*/{/*.val =*/{0x377220dc, 0x14ca7db7, 0x16023891, 0x27c96229, 0xe83bbd4, 0x27b40409, 0x2a8ad6a5, 0x3e507c9e, 0xffb2}}, + /*.y =*/{/*.val =*/{0x1b32b3bc, 0x26083b0c, 0x35e5f9f3, 0x3948efcf, 0x59d2f2c, 0x3e5e242, 0x3be7a03c, 0x34ffe08a, 0xf97e}}}, +{/*.x =*/{/*.val =*/{0xd9ed6c1, 0x1a2bad63, 0x3d593d6b, 0x139d16f0, 0x1edd0ec2, 0x3f061dc1, 0xf53e80b, 0xcdb72dd, 0x328}}, + /*.y =*/{/*.val =*/{0x38fafeee, 0x3b1baf9b, 0x1cb494ad, 0x16fd37c9, 0xd7c8c26, 0x35650e88, 0x19f28c46, 0x260e04bf, 0x71a8}}}, +{/*.x =*/{/*.val =*/{0x26da57e4, 0x2dd59229, 0x1cdd9f86, 0x31265bbf, 0x31bc1e98, 0x3a8a9d18, 0x118b9dbd, 0x36b8e60e, 0x690c}}, + /*.y =*/{/*.val =*/{0x133f33bb, 0x2d8656d2, 0x295a3d42, 0x18f63ef3, 0x15894df8, 0x3f646fd6, 0x379a47a9, 0x371e59de, 0x840a}}}, +{/*.x =*/{/*.val =*/{0x1cfb8036, 0x3e6262a9, 0xda35085, 0x3426a4b0, 0x167e833a, 0x45f747f, 0x247b48ae, 0x9d47ec5, 0xcff6}}, + /*.y =*/{/*.val =*/{0x24f59de0, 0x10fced68, 0x20328258, 0x2962763d, 0x2143c678, 0x38d2d621, 0x2d1ac5f, 0x3b49af55, 0xcdf4}}}, +{/*.x =*/{/*.val =*/{0x20ebec47, 0x1da4a12b, 0x142ca23d, 0x381398c4, 0x3b4ea72e, 0x10de9936, 0x27df9761, 0xe5dc744, 0xe8b6}}, + /*.y =*/{/*.val =*/{0x2eb3d8a7, 0x32a7875c, 0x15fe035, 0x398b696, 0x3ff204be, 0x6555e5f, 0x32e11ae7, 0xb7e8107, 0x5f38}}}, +{/*.x =*/{/*.val =*/{0x3319c869, 0x3df1bab8, 0x21eb2702, 0x2a7e575d, 0xcacdc18, 0x20e408bf, 0x33fc8d01, 0x1176605, 0x3018}}, + /*.y =*/{/*.val =*/{0x12b856f0, 0x3031db27, 0x23d9a7bf, 0xaa13292, 0x222e3bca, 0x1890c835, 0x3b7b6f86, 0x315e0940, 0xac5f}}}, +{/*.x =*/{/*.val =*/{0x18953133, 0x11df726c, 0x8721ae6, 0x2ced0a9d, 0xcdfa97f, 0xa01b03f, 0x1dd23881, 0xad3fb43, 0xa0b}}, + /*.y =*/{/*.val =*/{0x34af0fc9, 0x2f0928dc, 0xed4ba94, 0x28e13a2c, 0x58c8d6f, 0x71b2a19, 0x2bf2f03c, 0x60b3ed6, 0xcda1}}}, +{/*.x =*/{/*.val =*/{0x1f0a2a53, 0x3abc3b03, 0x16611e7, 0x772acfe, 0x29b892d5, 0xe515d0e, 0x3997c3a8, 0x146341f0, 0x6f86}}, + /*.y =*/{/*.val =*/{0x333bfeb2, 0x4e695d1, 0x2a05f351, 0x153ddcba, 0x309968bf, 0x1dbaa569, 0x182f29b7, 0x3d85bf51, 0xd50a}}}, +{/*.x =*/{/*.val =*/{0x278b4a0d, 0x1e78672f, 0x8c9be06, 0x3ed83c9f, 0x1c73ace4, 0xf5d6ed2, 0x3db4e1cb, 0x10bae9a8, 0x2f98}}, + /*.y =*/{/*.val =*/{0x33f39758, 0xd4cafba, 0x3d54f320, 0x23bab9da, 0xbb8f48b, 0x32489c59, 0x355552a1, 0x35a4c2f7, 0x4774}}}, +{/*.x =*/{/*.val =*/{0x3874b839, 0x444a1d5, 0x13d2b418, 0x10456ce5, 0x30b6aebe, 0x37c37ec8, 0x1e5a8053, 0x2e07f038, 0x3e03}}, + /*.y =*/{/*.val =*/{0x3c0594ba, 0x3073959, 0x1ab5b8da, 0x39717c3f, 0x198f667d, 0x3d981d5c, 0x7f42c44, 0x3858f7fc, 0xd13a}}}, +{/*.x =*/{/*.val =*/{0x39a7d197, 0x2eba434e, 0xea59459, 0x20ea3062, 0x2c234b5e, 0x23ff8288, 0x1f639477, 0x22950a03, 0xc2c5}}, + /*.y =*/{/*.val =*/{0x9eeb5e9, 0x390732fe, 0x1ad82484, 0x11fb1151, 0x2d39a60a, 0x106ad8b, 0x20927573, 0xca20d9b, 0x72ea}}}, +{/*.x =*/{/*.val =*/{0x23369217, 0x1d379b65, 0x6611ead, 0x70e5a40, 0x4eacdca, 0x289e3d50, 0xd624a21, 0x143ff2e9, 0x42dc}}, + /*.y =*/{/*.val =*/{0x3e2dbc57, 0x30c25f88, 0xe01e841, 0x284e7b2a, 0xba853a7, 0x1e3d7c58, 0x5b1d7ed, 0x2687d98e, 0xa5ba}}}, +{/*.x =*/{/*.val =*/{0x19251fa2, 0x1e7e8b49, 0x3c26cc92, 0x337ea0ae, 0x13d5e1bb, 0x1d1678dc, 0x1a1202b0, 0x31d972a4, 0x417}}, + /*.y =*/{/*.val =*/{0x3ebc52fa, 0x24c1240a, 0x161ee899, 0x292c61dd, 0x6283ad9, 0x1a19d99f, 0x357f5349, 0x397544b1, 0x72d7}}}, +{/*.x =*/{/*.val =*/{0x2cde4cf3, 0x26554187, 0x38a066ab, 0x10394d51, 0x1d9ae793, 0x30b49b45, 0x22c3be7, 0x2ad2b045, 0x384d}}, + /*.y =*/{/*.val =*/{0x252d0566, 0x1f1e5ac8, 0x351ba73b, 0x10c28ce5, 0x34c6f01f, 0x13b5b68a, 0x1ca43bfb, 0x316f346e, 0xd6e3}}}, +{/*.x =*/{/*.val =*/{0xa972627, 0x290d9a82, 0x2521e1f8, 0x24858100, 0x441a0e1, 0x2307bf2f, 0x3e15c819, 0x21c2526f, 0x8a31}}, + /*.y =*/{/*.val =*/{0x6bb8af9, 0x1ed1ed59, 0x3efcbcce, 0x110d96b0, 0x7baa417, 0x1dfb4a16, 0x3a64d095, 0x1f21da3d, 0x64bb}}}, +{/*.x =*/{/*.val =*/{0xa3a1550, 0x2951319f, 0x2ffdf279, 0x76a67e3, 0x38b75180, 0xc25db87, 0x157412dd, 0x1a6acd01, 0xebfc}}, + /*.y =*/{/*.val =*/{0x1362f6e, 0x7d0afd9, 0x28c0b195, 0x20f20639, 0x34fd0779, 0x3c6676df, 0xb540a3d, 0x3a336e67, 0xe2ff}}}, +{/*.x =*/{/*.val =*/{0x14f24bf1, 0x3e2ba88c, 0x2c500d25, 0x15500782, 0xe78708e, 0x1cdd2f0d, 0x2d024ec7, 0xeaf6dad, 0x6299}}, + /*.y =*/{/*.val =*/{0x108d1b1d, 0x34eb50c5, 0x148c6775, 0x24d4c0b2, 0x3c429b1d, 0x34b2bf8c, 0x29b93a00, 0x1cac2bab, 0x86fb}}}, +{/*.x =*/{/*.val =*/{0x39d681f9, 0x164153f9, 0x8feb9fc, 0x3383bbeb, 0x2c94b066, 0x1ffc9780, 0x3230888b, 0x3f7c9dd7, 0xc745}}, + /*.y =*/{/*.val =*/{0x3bbb1247, 0xc5cd0d, 0x27d45c76, 0x36f4cd71, 0x2818678c, 0x4e531c3, 0x1e5e78a7, 0x8bcbdae, 0x5902}}}, +{/*.x =*/{/*.val =*/{0x249a2115, 0x1dff54d1, 0x3a565ebe, 0x1e580245, 0x981aec, 0x1ab2a759, 0xc6c6dd4, 0x3014ac65, 0xfd73}}, + /*.y =*/{/*.val =*/{0x26ba6cda, 0x1272adee, 0x29d421f0, 0x3d80558b, 0x37d6d904, 0x2aeac09b, 0x38844020, 0x1a307205, 0x6207}}}, +{/*.x =*/{/*.val =*/{0x1b816b2f, 0x36e1b0d4, 0x228ee11f, 0x32de104, 0x2c5d5dee, 0x597f849, 0x11a676e8, 0x11b75965, 0x5a4d}}, + /*.y =*/{/*.val =*/{0x33e86c60, 0x3e5ebae1, 0x33ecceba, 0x39b317e, 0x3dfcd6b5, 0xf89fe3c, 0x260ab028, 0x8e5b283, 0x77c9}}}, +{/*.x =*/{/*.val =*/{0x31ce59e7, 0x110131b, 0x2d9919f3, 0x1db4e753, 0x324e6906, 0x359f05b6, 0x1f964c25, 0xbde79a8, 0x1bbc}}, + /*.y =*/{/*.val =*/{0x379aa297, 0x14c8648, 0x3839618d, 0x2265bd03, 0x1bc5a36c, 0x36c5beb4, 0x1f1a8781, 0x32d32375, 0x281f}}}, +{/*.x =*/{/*.val =*/{0x3bb80fa7, 0xd12172c, 0x30413886, 0x29f69aed, 0x20819f3a, 0x681af4c, 0xc2fbc0d, 0x38c7d8c2, 0x857}}, + /*.y =*/{/*.val =*/{0x9366b2d, 0x3660847c, 0xd7016ab, 0xb8dc10f, 0xb714717, 0x1f327477, 0x172092d, 0x24d08eb8, 0xf643}}}, +{/*.x =*/{/*.val =*/{0x3b6d6cd3, 0xe802af9, 0x38937883, 0x5984740, 0x25239734, 0x1a6e1c15, 0x3818481a, 0x19859fca, 0xea12}}, + /*.y =*/{/*.val =*/{0x34f450be, 0x2b98a497, 0x3be1a88a, 0x325d4b7a, 0x145e25b1, 0x3844afc4, 0x2e3fdaac, 0x38b941e3, 0x21a4}}}, +{/*.x =*/{/*.val =*/{0x1cff55c5, 0x1c48f509, 0x2275ec97, 0x13bf4a06, 0x2b4b635f, 0x4b079e0, 0x1442ca6c, 0x2b7f7ec9, 0xcf36}}, + /*.y =*/{/*.val =*/{0x21a0228e, 0x3289e214, 0xd2706a, 0x151fb097, 0x19f207a7, 0xbd62cef, 0x768649c, 0x4859ab8, 0xd16a}}}, +{/*.x =*/{/*.val =*/{0x125cb53b, 0x17a9e02b, 0x365eb3d0, 0x23f15763, 0x6272dab, 0x994c755, 0x25414494, 0x728acf7, 0xf474}}, + /*.y =*/{/*.val =*/{0x295a4b7e, 0x39769e65, 0x1f86e5c1, 0x5aa3ad, 0x2c8f9c0d, 0x3ec3609e, 0x1f2f01c8, 0x1bd03c89, 0xc48d}}}, +{/*.x =*/{/*.val =*/{0x3f2e070d, 0x160ff4e8, 0x12a6a98f, 0x2aadc731, 0x1047e229, 0x1cc70ee1, 0x34abff48, 0x297a410b, 0x4b72}}, + /*.y =*/{/*.val =*/{0x296dd780, 0x112ea0bb, 0x2948c3de, 0x2d197774, 0xf3c10b0, 0x1deecdb4, 0x2e1cf602, 0x753875a, 0x599e}}}, +{/*.x =*/{/*.val =*/{0x385912ec, 0xa1c0283, 0x6091134, 0x3e728139, 0x2f054327, 0x1265a52a, 0x35b786ab, 0x87538fe, 0xaa71}}, + /*.y =*/{/*.val =*/{0xae35978, 0x4532c99, 0x2056cbdb, 0x384d2a33, 0x22edebfe, 0x1499ae5a, 0x9509c50, 0x3c1df6b4, 0xc690}}}, +{/*.x =*/{/*.val =*/{0x3fd292dc, 0x2e01a893, 0x17714ce1, 0x1789a02c, 0x3d79d977, 0x201c34de, 0xf934ba4, 0x554cdc8, 0x4b99}}, + /*.y =*/{/*.val =*/{0x17095ca6, 0xce97ff9, 0x3376afd4, 0x20c8f116, 0x301f5793, 0x3029d2d7, 0x3a226df, 0x1d525844, 0xe327}}}, +{/*.x =*/{/*.val =*/{0x384da233, 0x2a560e3a, 0x1f362cd4, 0x13c36a04, 0x336ed9cf, 0x26f4ce3f, 0x25316a20, 0x32d365c7, 0x1eb7}}, + /*.y =*/{/*.val =*/{0x17c43f18, 0x2e3a954c, 0x1cf0ae9c, 0xdb26660, 0x1ed0aba3, 0x3cef342f, 0x84ff826, 0xca2b91f, 0xd984}}}, +{/*.x =*/{/*.val =*/{0x3bea0c68, 0x321042bc, 0x37b392b5, 0x10c048d9, 0x396faf09, 0x26f23a34, 0x2a3a2494, 0x258d3855, 0x3e41}}, + /*.y =*/{/*.val =*/{0x1a45edb6, 0x32edbfdc, 0x3cda1ab, 0x2846518c, 0x693062f, 0xf2ff8dc, 0x321f7f37, 0x31676492, 0x123}}}, +{/*.x =*/{/*.val =*/{0x17d4b84a, 0x2a605310, 0x1f433e69, 0x777d23c, 0x5070462, 0xa924b4a, 0x32fcb0c6, 0x26796371, 0xf13a}}, + /*.y =*/{/*.val =*/{0x13fd1c81, 0x16643f15, 0xf2d9628, 0x38df51c4, 0x3fe06eb6, 0x2e473478, 0x3e995aa6, 0x323343c2, 0x33c2}}}, +{/*.x =*/{/*.val =*/{0xe735a1e, 0x3c30ec51, 0x3e61fa05, 0xf8259a, 0x1202fc40, 0x23376b58, 0x356cb46b, 0x31f01e66, 0x678a}}, + /*.y =*/{/*.val =*/{0x12f7c055, 0xd8e97dc, 0x1371457a, 0x1fffeccf, 0x105e8e59, 0x3fcf55c, 0x1285b7a7, 0x138cf669, 0x851}}}, +{/*.x =*/{/*.val =*/{0x14c426d5, 0x30e07974, 0x22adf265, 0x29543e1e, 0x1fa93ab7, 0x1210c7e3, 0x2b66bd4c, 0x1d467823, 0x364c}}, + /*.y =*/{/*.val =*/{0x1a5876c0, 0x21b51ca9, 0x7db7191, 0x231357c5, 0x2d95be16, 0x2c62c634, 0x1fa52f1e, 0x2d65d0b2, 0xfaa8}}}, +{/*.x =*/{/*.val =*/{0x12fea1f9, 0x2c5f2ef1, 0x452b94, 0x3fc2d423, 0x106531c4, 0x3f76ad9c, 0x1f2e83bc, 0x22029574, 0xa6dc}}, + /*.y =*/{/*.val =*/{0x3bc345e9, 0x2c705391, 0x268f7e63, 0x1ee276df, 0x2cbc5005, 0x1a0e845a, 0x367c3038, 0x2a151f70, 0x7ef1}}}, +{/*.x =*/{/*.val =*/{0x1c7985c4, 0x2d84f9dc, 0x39e2b108, 0x12ff1256, 0x374c3413, 0xa10a00b, 0x19b7ce54, 0x2d72bded, 0x2320}}, + /*.y =*/{/*.val =*/{0xc2c6d44, 0x3fd3c77d, 0xd9eb8d4, 0x1bc40847, 0x1bca93d9, 0x1c86e07e, 0x3e94318c, 0x250f7222, 0xc79f}}}, +{/*.x =*/{/*.val =*/{0xa3a809c, 0x27f82c2f, 0x398346d7, 0x2d98bd75, 0x14a89eda, 0x33e5f909, 0x3df56bfb, 0x1fb20e4c, 0x125e}}, + /*.y =*/{/*.val =*/{0x149e70d9, 0x2a32402a, 0x7fca3dd, 0x138ecbbc, 0x321a371e, 0x1d1f2bd5, 0xcb38887, 0x3dbb7895, 0xe0d3}}}, +{/*.x =*/{/*.val =*/{0x208a7b1f, 0x3215fe35, 0x2a1ee514, 0x162bea6d, 0x3bc587f7, 0x141eb357, 0x37eb0079, 0x20efd263, 0x5ac}}, + /*.y =*/{/*.val =*/{0x165ccb98, 0x2198dd7e, 0x75d0f82, 0x3bc0ecc4, 0x2ac6f5b3, 0x33d08917, 0x2e6fb0fa, 0x271b3dd5, 0xe379}}}, +{/*.x =*/{/*.val =*/{0x27315443, 0x364e1ce0, 0x2e867299, 0x1e6ef552, 0x2142a13d, 0x32266082, 0x935ff42, 0x1b010198, 0xfc69}}, + /*.y =*/{/*.val =*/{0x17d28960, 0x1243582d, 0x9bd1b17, 0x1ffd2184, 0x1677b548, 0x387375a, 0x35892bbf, 0x9fafe0e, 0xe0ce}}}, +{/*.x =*/{/*.val =*/{0x3c6b5b56, 0x3cd857f5, 0x1888b607, 0x21722abb, 0x3200e541, 0x161fb4ef, 0x34338cdf, 0x2195c03b, 0xa0e8}}, + /*.y =*/{/*.val =*/{0x3a1d7518, 0x5af7944, 0x858a51a, 0x1ae1c75c, 0x13dead52, 0x29ae26e1, 0x1ad50b99, 0x11a0e7ea, 0xf5ba}}}, +{/*.x =*/{/*.val =*/{0x10cedd26, 0x35d977dd, 0x25715541, 0x322e677a, 0x239e2a3c, 0x360403e5, 0x1ebb2611, 0x120dca58, 0xaf88}}, + /*.y =*/{/*.val =*/{0x30e43f7f, 0x2db9eb4e, 0x3aa41708, 0x15279219, 0x2d2f9654, 0x32ee23af, 0x27030d28, 0x3efe5ec5, 0xdc57}}}, +{/*.x =*/{/*.val =*/{0x10b36a01, 0x1d9fddfc, 0x320812b5, 0x11e9ec5f, 0x2ec63cfc, 0x39ea5901, 0x3177a68a, 0x25375386, 0x853c}}, + /*.y =*/{/*.val =*/{0x27fe4ebe, 0x1f971fa3, 0x72f4fcc, 0x2fe60a00, 0x25123a28, 0x274080f7, 0x1b19530e, 0x33a53b26, 0xa328}}}, +{/*.x =*/{/*.val =*/{0x11da5e12, 0x7b838ce, 0x1cacb297, 0x31829005, 0x1ca2b6a9, 0xca7e4e8, 0x1e31bcda, 0xb8f10de, 0xf750}}, + /*.y =*/{/*.val =*/{0x385f4eb, 0x292e717a, 0x325cebc7, 0x21b4cbbd, 0x1672047b, 0x1c25170f, 0xfafd599, 0x3d7b759f, 0x3c57}}}, +{/*.x =*/{/*.val =*/{0x3e32478e, 0xdcc481c, 0x29ba7ed2, 0x2acc63ca, 0x332b2024, 0x31adfcfc, 0x213880fe, 0x4758041, 0xd420}}, + /*.y =*/{/*.val =*/{0x104e88d4, 0x33815a07, 0x1508cc31, 0x2c92cbcd, 0x3f847b6f, 0x357d7d12, 0x14e0c1b2, 0x353a68df, 0xbae5}}}, +{/*.x =*/{/*.val =*/{0x216ddcd3, 0x1a9c8dee, 0x1ea00355, 0x12c44008, 0x761af04, 0x16fadb2e, 0x299edf7b, 0x2b4dbd93, 0x1ae1}}, + /*.y =*/{/*.val =*/{0x2e7eb2b7, 0x33118674, 0xbb613c7, 0x185ab77f, 0x10448959, 0x1d3ddd48, 0x922059c, 0x15261e8, 0x7016}}}, +{/*.x =*/{/*.val =*/{0x19158bab, 0x264fc10e, 0x12d06caa, 0x4c9b0c6, 0x5a0674c, 0x1f3cf7cb, 0x39b3c419, 0x3d2ec203, 0xe2c6}}, + /*.y =*/{/*.val =*/{0x2d7a27f2, 0x214f3c9e, 0x49fd3f5, 0x6d622e4, 0x3ef5c641, 0xaecd847, 0xb1eabd1, 0x1e18b4f0, 0xfa92}}}, +{/*.x =*/{/*.val =*/{0x3a95a8db, 0x1761dccb, 0x39d36f61, 0xfb03111, 0x1b1723b8, 0x25991a64, 0x3dd0419e, 0x36918c0, 0xe3e9}}, + /*.y =*/{/*.val =*/{0x1b0d1cf9, 0x5b3dfc, 0x984d3d1, 0x2c7be5f3, 0x2e76afb, 0x3eaa431c, 0x178bb00, 0xef0015b, 0xfbe5}}}, +{/*.x =*/{/*.val =*/{0x141d0ce6, 0x13f0f72d, 0x3598d41f, 0x2264a8b3, 0x205fb274, 0x53338ce, 0x1a9412ee, 0x168a4dfc, 0x1429}}, + /*.y =*/{/*.val =*/{0x1738bb86, 0xaa06a2b, 0x35d241a5, 0x2255806, 0x83b131, 0xc711211, 0x150711b0, 0x14d8f7c4, 0xfea7}}}, +{/*.x =*/{/*.val =*/{0xb344f7f, 0x1c633e71, 0xce60c4c, 0x22e27f52, 0x26d410ee, 0x1f8cb2f4, 0x2e0ae0e9, 0x3212f65c, 0x354c}}, + /*.y =*/{/*.val =*/{0x25db82d6, 0x392c46ba, 0x202e0ec7, 0xdb18061, 0x3a88558e, 0x2d24fe6, 0x6b5d675, 0x2fca4a47, 0x9c04}}}, +{/*.x =*/{/*.val =*/{0x1983ce4e, 0x2ecf54dc, 0x1578253f, 0x40f6279, 0x23024a60, 0xeee0d6a, 0x35975f0e, 0x3da7674c, 0x8704}}, + /*.y =*/{/*.val =*/{0x16572c0a, 0x1c256368, 0x302df498, 0x16e840b8, 0x296bac34, 0x231d35d6, 0x2ec26a3, 0x14817389, 0x6b0b}}}, +{/*.x =*/{/*.val =*/{0x3a3979b5, 0xa8666c2, 0x27e829e2, 0xa23e379, 0x240e50ba, 0xdfc2c7b, 0x1e26327f, 0x1f1736b, 0xae22}}, + /*.y =*/{/*.val =*/{0x450fa6f, 0x23cf359a, 0x3d4f8896, 0x2a1edf4d, 0x2d7060fc, 0x3249148e, 0x39f71ad4, 0x3f944301, 0xea91}}}, +{/*.x =*/{/*.val =*/{0x2ce4dd6a, 0x16784787, 0x3221cef5, 0x392728, 0x164c460a, 0x3b28dfa3, 0x12b64bc9, 0x393dec9e, 0x49db}}, + /*.y =*/{/*.val =*/{0x2a9e3eae, 0x4edca90, 0x205bb69b, 0xe154bf2, 0x12255a1c, 0x3f8cf6da, 0x81c72c5, 0x1ca611c1, 0xb8b5}}}, +{/*.x =*/{/*.val =*/{0x34e5f03a, 0x3fa2d6f7, 0x21606d54, 0x1597fac7, 0x3dfe3596, 0x373eccf5, 0x1be33737, 0x13f740a2, 0x80c3}}, + /*.y =*/{/*.val =*/{0x3e3ca504, 0x5fd151b, 0x33245cb1, 0x2cabbc7, 0x1c9a03d3, 0x36d5c01f, 0x1ecd55e, 0x215a9e3, 0x247e}}}, +{/*.x =*/{/*.val =*/{0x29565331, 0x20617fbe, 0x1a915abf, 0x17a2498b, 0xcf1ce93, 0xe7bed50, 0x30c22611, 0x1493240d, 0x9d32}}, + /*.y =*/{/*.val =*/{0x26f06930, 0x758c2a, 0x236934f9, 0x32544bb0, 0x6d2ae5c, 0x3b130b2f, 0x22ebfd7f, 0x15cf49df, 0x3766}}}, +{/*.x =*/{/*.val =*/{0x354b8367, 0x25201cf5, 0x3d506bfe, 0x1d6ddf59, 0x36a5db7, 0x2a975161, 0x2526e40c, 0x252b911, 0x5e5a}}, + /*.y =*/{/*.val =*/{0x11ce85ca, 0x14ca6a76, 0x1e5ffa44, 0x1aaa7bcf, 0x2a4b7a79, 0x2407c55c, 0x15e05c2c, 0x3e32691e, 0xae8a}}}, +{/*.x =*/{/*.val =*/{0xcbcad59, 0x2c17a0d8, 0xe0aaa07, 0x21168169, 0x3902f17c, 0x5f21697, 0x36007aa, 0x1b0454ab, 0x2ed7}}, + /*.y =*/{/*.val =*/{0x4ea66fe, 0x12b1ea27, 0xa7f9411, 0x1cb1804c, 0x1767ed5f, 0x29babb20, 0x5f222cd, 0x135010ee, 0x639f}}}, +{/*.x =*/{/*.val =*/{0x24b84b48, 0xc3d15c7, 0x1e817ea8, 0x2b7d31e6, 0x17f7091, 0x43d5df5, 0x1a4f5419, 0x37c39f51, 0x5fb1}}, + /*.y =*/{/*.val =*/{0x37be8eb8, 0x1fb7a9a8, 0x33f21ad7, 0xa70e421, 0x2d258206, 0x3d191bf9, 0x4d49fbc, 0x3eef2f0f, 0x2152}}}, +{/*.x =*/{/*.val =*/{0x2aa2a748, 0x15d87054, 0x378c403d, 0x2c99f85, 0x2835d8c9, 0x337e7d1a, 0x141486c5, 0x27edac70, 0x135a}}, + /*.y =*/{/*.val =*/{0x38a6cf84, 0xc41675b, 0x3f91ab2d, 0x19b84fa2, 0x9453a65, 0x18b97f9c, 0x15938e7, 0x778b2a8, 0xa869}}}, +{/*.x =*/{/*.val =*/{0xfd69985, 0x2717764, 0x1df72aea, 0xc2732db, 0xccf149f, 0x3da437ef, 0x32f7e788, 0x1d9d73ad, 0xae9}}, + /*.y =*/{/*.val =*/{0x1409a003, 0x2723ad04, 0x2ee1aff8, 0x2e67505e, 0x1a54c5d0, 0x237fb814, 0x8d14e9b, 0x265cfdb9, 0x9121}}}, +{/*.x =*/{/*.val =*/{0x2078afb0, 0x39d6b9e5, 0x1261974, 0x3fc4b1b1, 0x2d170714, 0x3511a319, 0x163b5248, 0x1af35d98, 0x209d}}, + /*.y =*/{/*.val =*/{0x2740b310, 0x1746ddd6, 0x1f4e3e38, 0x3b6de4ce, 0x98a5b01, 0x196eaea6, 0x33280a09, 0x4d0a79e, 0x1a2f}}}, +{/*.x =*/{/*.val =*/{0x1f55a9bf, 0x2f2c0a63, 0x1ea5bf8e, 0x2c057bca, 0x17c578f6, 0xc1fd807, 0x23181810, 0x263ae71b, 0x7262}}, + /*.y =*/{/*.val =*/{0x3c3accae, 0x45be2c2, 0x673b4e, 0x1e5ef2f0, 0x1099e0be, 0xd68bbcf, 0x29bfda98, 0x22006a77, 0x38d4}}}, +{/*.x =*/{/*.val =*/{0x3dbb04fa, 0x5c195a8, 0x118911f9, 0x29c145ac, 0x26b5e114, 0x2e090979, 0x26ed4d7c, 0xb7eecd1, 0x7fe4}}, + /*.y =*/{/*.val =*/{0x21908c89, 0x359d2447, 0x2c1b9c55, 0x3a28a234, 0x334cf0aa, 0x1b22c1e5, 0x5f4330f, 0x1e82d3d7, 0x2eec}}}, +{/*.x =*/{/*.val =*/{0x2e4b3ba0, 0x2167d8d7, 0x18bf1f17, 0xaafbd7c, 0x3f245f5c, 0x385c3cc6, 0x3fb73bef, 0x4414887, 0x4108}}, + /*.y =*/{/*.val =*/{0x17525595, 0x21a58770, 0x1a064554, 0xd926159, 0x2b849813, 0x2996b875, 0x35668f2c, 0x3cda5dbf, 0xdc37}}}, +{/*.x =*/{/*.val =*/{0xe5485, 0x22799a8, 0x1da5df02, 0x4c1a2fd, 0x320f1245, 0x31c2189c, 0x2bdff8e2, 0x1db5e4e8, 0x1cd2}}, + /*.y =*/{/*.val =*/{0x85fbd7f, 0x2973c146, 0x209a4ecc, 0x34389c2c, 0x2e977f99, 0x2cd35154, 0x2af738d4, 0x2f7462cb, 0x6615}}}, +{/*.x =*/{/*.val =*/{0x290bc03e, 0x31d4f566, 0x1e015e33, 0x2c3ce4d4, 0x50f8084, 0x2a497dd1, 0x2072e9e5, 0x363b4b20, 0x2cee}}, + /*.y =*/{/*.val =*/{0x3ab82adc, 0x32dcae2d, 0xd53cd01, 0x77e73c8, 0x7daeb4a, 0x143adebf, 0x1de3ecd8, 0x1ae03a6e, 0xa427}}}, +{/*.x =*/{/*.val =*/{0x3009ee3e, 0x2e71352e, 0x729ead5, 0x9a8799e, 0x272de237, 0x273af1, 0x22ac92b7, 0x216c0cba, 0xb17a}}, + /*.y =*/{/*.val =*/{0x296b911d, 0x18f947b, 0x446fa38, 0x85b29f2, 0x26eda65, 0x63f703, 0x29a65f5c, 0x9a749ac, 0x966e}}}, +{/*.x =*/{/*.val =*/{0xe103dd6, 0x37dc51c8, 0x4859a, 0x1181301f, 0x12a17ac3, 0x84f3f16, 0x203f836a, 0x1ef55690, 0xbc47}}, + /*.y =*/{/*.val =*/{0x16f7c343, 0xe420b63, 0x23b44ac6, 0xa4d5cb1, 0x1ea6395d, 0x2b154b1b, 0xdd526cb, 0x7890a6a, 0xe31e}}}, +{/*.x =*/{/*.val =*/{0x36695f94, 0xb602c60, 0x1627fa59, 0x285a71a4, 0x39a9cf62, 0x32e1a0eb, 0x18f5fd0c, 0x17546d15, 0xb1d2}}, + /*.y =*/{/*.val =*/{0x1ee32736, 0x16dfae69, 0x3863edca, 0x3dbc636a, 0x2ba81760, 0x3a82b066, 0x290b1f7b, 0x369c80c3, 0x706d}}}, +{/*.x =*/{/*.val =*/{0x36f83231, 0x265c4062, 0x20425e34, 0x30c3639d, 0x33fdd0b7, 0x5609d96, 0x2ba26a8d, 0x23314d40, 0x850f}}, + /*.y =*/{/*.val =*/{0x1f2e8373, 0x280c6a75, 0x322d77f4, 0x216fe85d, 0x2cc7890a, 0x3dc21ae0, 0x39053d0b, 0x276f80a9, 0xbc4a}}}, +{/*.x =*/{/*.val =*/{0x39343959, 0xb882f6f, 0x2c9ce78a, 0x28673cbe, 0x1bc1f617, 0x2bfa4c24, 0x651465d, 0x6e01743, 0x2d38}}, + /*.y =*/{/*.val =*/{0x1442fb00, 0x1c432ba8, 0x31e45a43, 0x14b57589, 0x31025f43, 0x2bcbce90, 0x361bf59a, 0x3782534a, 0x5451}}}, +{/*.x =*/{/*.val =*/{0x152da17d, 0x18283e90, 0xd0646b1, 0x3704f6c2, 0x200bc811, 0x139ac17f, 0x18c5f089, 0x3b4783d4, 0x3bea}}, + /*.y =*/{/*.val =*/{0x2cc768d2, 0x39c12617, 0x1fec416c, 0x3379dee3, 0xe1b554, 0x12a2fafa, 0x37acdfef, 0x35fd56bf, 0xc3b0}}}, +{/*.x =*/{/*.val =*/{0x1063e1be, 0x6e6b413, 0x3e39a75c, 0x90a68bd, 0x3cf027a9, 0x185494f6, 0x2b14722, 0x10744758, 0x1316}}, + /*.y =*/{/*.val =*/{0x21fec890, 0x3747fcf8, 0x1745b77f, 0x3ebb03e, 0x3d2bebbd, 0xb8c3f36, 0x39f06a4, 0x36985e58, 0x4c3b}}}, +{/*.x =*/{/*.val =*/{0x3c46e079, 0x4a80d49, 0x1e9c78dd, 0x19a4c2e1, 0x2ba374ab, 0x3dd6b6c0, 0x3ac530fe, 0x30ab4ab3, 0xab86}}, + /*.y =*/{/*.val =*/{0x3636ffe1, 0x310a2f05, 0x50d7c0e, 0x1dca3a12, 0x3200c9ce, 0x311b535c, 0x329abcf5, 0x30a18067, 0x1209}}}, +{/*.x =*/{/*.val =*/{0x17d37248, 0x227c6075, 0x117ceae4, 0x20d6d947, 0x2b2787bc, 0x1bac891a, 0x36d5aa4d, 0x946f0fb, 0xadc4}}, + /*.y =*/{/*.val =*/{0x2adcbc1b, 0x1811f2b3, 0x50bebc8, 0x37156ec5, 0x16f70b9, 0x18f8d8a4, 0x1e7eb5d0, 0x2dd8b8f1, 0xb0f3}}}, +{/*.x =*/{/*.val =*/{0xeca5f51, 0x85ac826, 0xfc9aebf, 0x3a85c6e5, 0x5b5cfdd, 0x3b5acafc, 0x2e6962c6, 0x35453767, 0xdde9}}, + /*.y =*/{/*.val =*/{0x10c638f7, 0x2b5a69cf, 0x289571f9, 0x3fbafa37, 0x3f8f0950, 0x7cd2c29, 0x28111d89, 0x1a44cf38, 0xb84e}}}, +{/*.x =*/{/*.val =*/{0x209b0cca, 0x3331a956, 0xa4d6f01, 0x115d6249, 0x28da59a3, 0x1153da28, 0xf4c8d5c, 0x232c76ec, 0xd53}}, + /*.y =*/{/*.val =*/{0xc929e05, 0xc6c51f8, 0x9134c97, 0xd336676, 0x2ed7cf85, 0x2a357103, 0x2c110cb0, 0x1aeb1e8f, 0xc819}}}, +{/*.x =*/{/*.val =*/{0x2dd7e577, 0x2b8c0f3b, 0x136c4d56, 0x283c95a1, 0x2a2107d3, 0x1811c9c3, 0xf7b25ac, 0x3543e20a, 0xc352}}, + /*.y =*/{/*.val =*/{0x38d9b570, 0x3293fe23, 0x21217063, 0x2a2aecad, 0xe79fb00, 0x354c516f, 0x2b9b96ab, 0xa0e2e9d, 0xbe77}}}, +{/*.x =*/{/*.val =*/{0x23868246, 0x22fcdeb0, 0x6dd2ded, 0x27db62bd, 0x2248ba8, 0x17641f4b, 0x11d600b5, 0x1f82acce, 0xfb9d}}, + /*.y =*/{/*.val =*/{0x2969605a, 0x2760f82b, 0x2a2606d2, 0x34ab4c16, 0x1475f4a6, 0x2a2e05a8, 0x3680cff2, 0x26f807d2, 0xb038}}}, +{/*.x =*/{/*.val =*/{0x3712be3c, 0x1a8b8cb, 0x2146a66b, 0x257c63b6, 0x153472, 0x1c976eac, 0x1b378d3c, 0xd2764cc, 0x39d7}}, + /*.y =*/{/*.val =*/{0x1c6ff65c, 0x30c067d0, 0xa41644c, 0x17bde97b, 0x2812e8ef, 0x9d55319, 0x33bf7fb1, 0x26d3d5bb, 0x8f92}}}, +{/*.x =*/{/*.val =*/{0x37829372, 0x3b02a929, 0xba4553d, 0x26cc0322, 0x5796bc4, 0x189ab94e, 0x20d3b313, 0x273243cf, 0xb431}}, + /*.y =*/{/*.val =*/{0xadd5427, 0x1ca73300, 0x23e11bb7, 0x1ec48572, 0x21c5a270, 0x1ebf8270, 0x3502bffb, 0x3512669b, 0x4707}}}, +{/*.x =*/{/*.val =*/{0xdcbcb9e, 0x12fc449b, 0xd83c3df, 0x3e95a277, 0x143761d6, 0x30c911ff, 0x1337a9ec, 0x4b5c467, 0xcdcb}}, + /*.y =*/{/*.val =*/{0x961cfd1, 0x229616b, 0x18df340a, 0x266bc90d, 0x1e9949a1, 0x3efa825b, 0x1f11fbfe, 0x38b85eee, 0xe699}}}, +{/*.x =*/{/*.val =*/{0xe90bc26, 0x1e074991, 0x364d3aa0, 0x22880f84, 0xacd88a9, 0xf195b1d, 0x27275f3d, 0x385bd96d, 0x5e4d}}, + /*.y =*/{/*.val =*/{0x252f79e, 0x5f546a, 0x1127f9c7, 0x194f732b, 0x3ad55207, 0xebea5e0, 0x1432904e, 0x3cb90d4f, 0x5ac5}}}, +{/*.x =*/{/*.val =*/{0x754dd40, 0x18fa1c55, 0x3466cf8, 0x10898c7f, 0x32f6e9a2, 0x12107f35, 0xdfcf45b, 0x91c0cb0, 0x9729}}, + /*.y =*/{/*.val =*/{0x2aa36143, 0x212d24bc, 0x1acaf493, 0x36ba1495, 0x14df3690, 0x171d772f, 0x3ea1dcd1, 0x28910997, 0x91d1}}}, +{/*.x =*/{/*.val =*/{0xc7a89ee, 0x15f0d4cc, 0x2b6d4f80, 0x36f1671e, 0x18658a4b, 0x182e23f2, 0x179e1128, 0x29389a90, 0x71ef}}, + /*.y =*/{/*.val =*/{0x1366a2e, 0x3d224ca7, 0x25e9a0b4, 0x2abeae23, 0x3294a22a, 0x2cb0cac5, 0x224ae9ef, 0x2a07e2ed, 0x145f}}}, +{/*.x =*/{/*.val =*/{0xde0545f, 0x32c08d26, 0x106c74f5, 0x39897688, 0x3508ac80, 0x17a8012c, 0x7124a37, 0x16f31638, 0x5204}}, + /*.y =*/{/*.val =*/{0x106c3d91, 0x1ba8d301, 0x28fdaf23, 0xee743ca, 0xe312b79, 0x3b67083, 0x3123ad43, 0xc7f3af8, 0x1b3f}}}, +{/*.x =*/{/*.val =*/{0x3ddaa5d5, 0x1873f311, 0x14d4b7ab, 0x27a034e9, 0x16607331, 0x3bf9159a, 0x28c4e4e8, 0x2646e4be, 0x4e9}}, + /*.y =*/{/*.val =*/{0x2cba1c91, 0x35f800ff, 0x255f570d, 0x3827db86, 0x957303c, 0x1ab47630, 0x327f1d9e, 0x577778a, 0x62fc}}}, +{/*.x =*/{/*.val =*/{0x26a06f5e, 0x6902d65, 0x2a083702, 0x1064945b, 0x23b716a3, 0x2c350849, 0x253ac37, 0x93efa85, 0x383b}}, + /*.y =*/{/*.val =*/{0x13c6e772, 0x227d1e1b, 0x38c2b040, 0x3dab9d2e, 0x2a5a19e8, 0x3d59b553, 0x1ba2044c, 0x1c1ab13b, 0x54cf}}}, +{/*.x =*/{/*.val =*/{0x1bcf2dce, 0x4e6d023, 0x1dc6c02, 0x4528417, 0x3f998068, 0x2793264b, 0x6218bd4, 0xb50a4b9, 0x95e6}}, + /*.y =*/{/*.val =*/{0x18c86594, 0xaf77f7d, 0x304d20e6, 0x1ecc180d, 0x28d52e5e, 0x289b8ad0, 0x2875183, 0x20610a5b, 0x6b6}}}, +{/*.x =*/{/*.val =*/{0x17a6257f, 0x20149916, 0x27a6c40b, 0x1cf0ec68, 0x7e78918, 0x909d2ac, 0x14f25a64, 0xd72387d, 0x71e9}}, + /*.y =*/{/*.val =*/{0x11b1e582, 0x2c85d187, 0xf70f7a5, 0x948d503, 0x2e2a52ef, 0x361ae91e, 0x22513de, 0xf967d1f, 0x78d9}}}, +}; #endif diff --git a/secp256k1.h b/secp256k1.h index 331107ef1..3ab713d57 100644 --- a/secp256k1.h +++ b/secp256k1.h @@ -54,6 +54,7 @@ extern const bignum256 secp256k1_iv[256]; #if USE_PRECOMPUTED_CP extern const curve_point secp256k1_cp[256]; +extern const curve_point secp256k1_cp2[255]; #endif #endif From c1dc507189d0ae0e5e80ba53610e143a6268dffe Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 15 May 2014 17:36:23 +0200 Subject: [PATCH 092/627] add hdnode serialization function --- bip32.c | 32 ++++++++++++++++++++++++++++++++ bip32.h | 2 ++ tests.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+) diff --git a/bip32.c b/bip32.c index f0de3d18c..993e404e8 100644 --- a/bip32.c +++ b/bip32.c @@ -118,3 +118,35 @@ void hdnode_fill_public_key(HDNode *node) { ecdsa_get_public_key33(node->private_key, node->public_key); } + +void hdnode_serialize(const HDNode *node, uint32_t version, char use_public, uint8_t *buffer) +{ + uint8_t node_data[82], a[32]; + int i,j; + uint32_t rem, tmp; + const char code[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; + write_be(node_data, version); + node_data[4] = node->depth; + write_be(node_data + 5, node->fingerprint); + write_be(node_data + 9, node->child_num); + memcpy(node_data + 13, node->chain_code, 32); + if (use_public) { + memcpy(node_data + 45, node->public_key, 33); + } else { + node_data[45] = 0; + memcpy(node_data + 46, node->private_key, 32); + } + sha256_Raw(node_data, 78, a); + sha256_Raw(a, 32, a); + memcpy(node_data + 78, a, 4); // checksum + for (j = 110; j >= 0; j--) { + rem = node_data[0] % 58; + node_data[0] /= 58; + for (i = 1; i < 82; i++) { + tmp = rem * 24 + node_data[i]; // 2^8 == 4*58 + 24 + node_data[i] = rem * 4 + (tmp / 58); + rem = tmp % 58; + } + buffer[j] = code[rem]; + } +} diff --git a/bip32.h b/bip32.h index 051596d05..7acfb2408 100644 --- a/bip32.h +++ b/bip32.h @@ -28,4 +28,6 @@ void hdnode_fill_public_key(HDNode *node); void hdnode_fill_address(HDNode *node); +void hdnode_serialize(const HDNode *node, uint32_t version, char use_public, uint8_t *buffer); + #endif diff --git a/tests.c b/tests.c index 574a99f13..deef70704 100644 --- a/tests.c +++ b/tests.c @@ -78,6 +78,7 @@ inline char *tohex(const uint8_t *bin, size_t l) START_TEST(test_bip32_vector_1) { HDNode node; + uint8_t buffer[113]; // init m hdnode_from_seed(fromhex("000102030405060708090a0b0c0d0e0f"), 16, &node); @@ -87,6 +88,10 @@ START_TEST(test_bip32_vector_1) ck_assert_mem_eq(node.chain_code, fromhex("873dff81c02f525623fd1fe5167eac3a55a049de3d314bb42ee227ffed37d508"), 32); ck_assert_mem_eq(node.private_key, fromhex("e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35"), 32); ck_assert_mem_eq(node.public_key, fromhex("0339a36013301597daef41fbe593a02cc513d0b55527ec2df1050e2e8ff49c85c2"), 33); + hdnode_serialize(&node, 0x0488ADE4, 0, buffer); + ck_assert_str_eq(buffer, "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi"); + hdnode_serialize(&node, 0x0488B21E, 1, buffer); + ck_assert_str_eq(buffer, "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8"); // [Chain m/0'] hdnode_private_ckd_prime(&node, 0); @@ -94,6 +99,10 @@ START_TEST(test_bip32_vector_1) ck_assert_mem_eq(node.chain_code, fromhex("47fdacbd0f1097043b78c63c20c34ef4ed9a111d980047ad16282c7ae6236141"), 32); ck_assert_mem_eq(node.private_key, fromhex("edb2e14f9ee77d26dd93b4ecede8d16ed408ce149b6cd80b0715a2d911a0afea"), 32); ck_assert_mem_eq(node.public_key, fromhex("035a784662a4a20a65bf6aab9ae98a6c068a81c52e4b032c0fb5400c706cfccc56"), 33); + hdnode_serialize(&node, 0x0488ADE4, 0, buffer); + ck_assert_str_eq(buffer, "xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7"); + hdnode_serialize(&node, 0x0488B21E, 1, buffer); + ck_assert_str_eq(buffer, "xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw"); // [Chain m/0'/1] hdnode_private_ckd(&node, 1); @@ -101,6 +110,10 @@ START_TEST(test_bip32_vector_1) ck_assert_mem_eq(node.chain_code, fromhex("2a7857631386ba23dacac34180dd1983734e444fdbf774041578e9b6adb37c19"), 32); ck_assert_mem_eq(node.private_key, fromhex("3c6cb8d0f6a264c91ea8b5030fadaa8e538b020f0a387421a12de9319dc93368"), 32); ck_assert_mem_eq(node.public_key, fromhex("03501e454bf00751f24b1b489aa925215d66af2234e3891c3b21a52bedb3cd711c"), 33); + hdnode_serialize(&node, 0x0488ADE4, 0, buffer); + ck_assert_str_eq(buffer, "xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs"); + hdnode_serialize(&node, 0x0488B21E, 1, buffer); + ck_assert_str_eq(buffer, "xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFHKkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ"); // [Chain m/0'/1/2'] hdnode_private_ckd_prime(&node, 2); @@ -108,6 +121,10 @@ START_TEST(test_bip32_vector_1) ck_assert_mem_eq(node.chain_code, fromhex("04466b9cc8e161e966409ca52986c584f07e9dc81f735db683c3ff6ec7b1503f"), 32); ck_assert_mem_eq(node.private_key, fromhex("cbce0d719ecf7431d88e6a89fa1483e02e35092af60c042b1df2ff59fa424dca"), 32); ck_assert_mem_eq(node.public_key, fromhex("0357bfe1e341d01c69fe5654309956cbea516822fba8a601743a012a7896ee8dc2"), 33); + hdnode_serialize(&node, 0x0488ADE4, 0, buffer); + ck_assert_str_eq(buffer, "xprv9z4pot5VBttmtdRTWfWQmoH1taj2axGVzFqSb8C9xaxKymcFzXBDptWmT7FwuEzG3ryjH4ktypQSAewRiNMjANTtpgP4mLTj34bhnZX7UiM"); + hdnode_serialize(&node, 0x0488B21E, 1, buffer); + ck_assert_str_eq(buffer, "xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5"); // [Chain m/0'/1/2'/2] hdnode_private_ckd(&node, 2); @@ -115,6 +132,10 @@ START_TEST(test_bip32_vector_1) ck_assert_mem_eq(node.chain_code, fromhex("cfb71883f01676f587d023cc53a35bc7f88f724b1f8c2892ac1275ac822a3edd"), 32); ck_assert_mem_eq(node.private_key, fromhex("0f479245fb19a38a1954c5c7c0ebab2f9bdfd96a17563ef28a6a4b1a2a764ef4"), 32); ck_assert_mem_eq(node.public_key, fromhex("02e8445082a72f29b75ca48748a914df60622a609cacfce8ed0e35804560741d29"), 33); + hdnode_serialize(&node, 0x0488ADE4, 0, buffer); + ck_assert_str_eq(buffer, "xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334"); + hdnode_serialize(&node, 0x0488B21E, 1, buffer); + ck_assert_str_eq(buffer, "xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV"); // [Chain m/0'/1/2'/2/1000000000] hdnode_private_ckd(&node, 1000000000); @@ -122,6 +143,10 @@ START_TEST(test_bip32_vector_1) ck_assert_mem_eq(node.chain_code, fromhex("c783e67b921d2beb8f6b389cc646d7263b4145701dadd2161548a8b078e65e9e"), 32); ck_assert_mem_eq(node.private_key, fromhex("471b76e389e528d6de6d816857e012c5455051cad6660850e58372a6c3e6e7c8"), 32); ck_assert_mem_eq(node.public_key, fromhex("022a471424da5e657499d1ff51cb43c47481a03b1e77f951fe64cec9f5a48f7011"), 33); + hdnode_serialize(&node, 0x0488ADE4, 0, buffer); + ck_assert_str_eq(buffer, "xprvA41z7zogVVwxVSgdKUHDy1SKmdb533PjDz7J6N6mV6uS3ze1ai8FHa8kmHScGpWmj4WggLyQjgPie1rFSruoUihUZREPSL39UNdE3BBDu76"); + hdnode_serialize(&node, 0x0488B21E, 1, buffer); + ck_assert_str_eq(buffer, "xpub6H1LXWLaKsWFhvm6RVpEL9P4KfRZSW7abD2ttkWP3SSQvnyA8FSVqNTEcYFgJS2UaFcxupHiYkro49S8yGasTvXEYBVPamhGW6cFJodrTHy"); } END_TEST @@ -129,6 +154,7 @@ END_TEST START_TEST(test_bip32_vector_2) { HDNode node; + uint8_t buffer[113]; int r; // init m @@ -139,6 +165,10 @@ START_TEST(test_bip32_vector_2) ck_assert_mem_eq(node.chain_code, fromhex("60499f801b896d83179a4374aeb7822aaeaceaa0db1f85ee3e904c4defbd9689"), 32); ck_assert_mem_eq(node.private_key, fromhex("4b03d6fc340455b363f51020ad3ecca4f0850280cf436c70c727923f6db46c3e"), 32); ck_assert_mem_eq(node.public_key, fromhex("03cbcaa9c98c877a26977d00825c956a238e8dddfbd322cce4f74b0b5bd6ace4a7"), 33); + hdnode_serialize(&node, 0x0488ADE4, 0, buffer); + ck_assert_str_eq(buffer, "xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U"); + hdnode_serialize(&node, 0x0488B21E, 1, buffer); + ck_assert_str_eq(buffer, "xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB"); // [Chain m/0] r = hdnode_private_ckd(&node, 0); @@ -147,6 +177,10 @@ START_TEST(test_bip32_vector_2) ck_assert_mem_eq(node.chain_code, fromhex("f0909affaa7ee7abe5dd4e100598d4dc53cd709d5a5c2cac40e7412f232f7c9c"), 32); ck_assert_mem_eq(node.private_key, fromhex("abe74a98f6c7eabee0428f53798f0ab8aa1bd37873999041703c742f15ac7e1e"), 32); ck_assert_mem_eq(node.public_key, fromhex("02fc9e5af0ac8d9b3cecfe2a888e2117ba3d089d8585886c9c826b6b22a98d12ea"), 33); + hdnode_serialize(&node, 0x0488ADE4, 0, buffer); + ck_assert_str_eq(buffer, "xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt"); + hdnode_serialize(&node, 0x0488B21E, 1, buffer); + ck_assert_str_eq(buffer, "xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH"); // [Chain m/0/2147483647'] r = hdnode_private_ckd_prime(&node, 2147483647); @@ -155,6 +189,10 @@ START_TEST(test_bip32_vector_2) ck_assert_mem_eq(node.chain_code, fromhex("be17a268474a6bb9c61e1d720cf6215e2a88c5406c4aee7b38547f585c9a37d9"), 32); ck_assert_mem_eq(node.private_key, fromhex("877c779ad9687164e9c2f4f0f4ff0340814392330693ce95a58fe18fd52e6e93"), 32); ck_assert_mem_eq(node.public_key, fromhex("03c01e7425647bdefa82b12d9bad5e3e6865bee0502694b94ca58b666abc0a5c3b"), 33); + hdnode_serialize(&node, 0x0488ADE4, 0, buffer); + ck_assert_str_eq(buffer, "xprv9wSp6B7kry3Vj9m1zSnLvN3xH8RdsPP1Mh7fAaR7aRLcQMKTR2vidYEeEg2mUCTAwCd6vnxVrcjfy2kRgVsFawNzmjuHc2YmYRmagcEPdU9"); + hdnode_serialize(&node, 0x0488B21E, 1, buffer); + ck_assert_str_eq(buffer, "xpub6ASAVgeehLbnwdqV6UKMHVzgqAG8Gr6riv3Fxxpj8ksbH9ebxaEyBLZ85ySDhKiLDBrQSARLq1uNRts8RuJiHjaDMBU4Zn9h8LZNnBC5y4a"); // [Chain m/0/2147483647'/1] r = hdnode_private_ckd(&node, 1); @@ -163,6 +201,10 @@ START_TEST(test_bip32_vector_2) ck_assert_mem_eq(node.chain_code, fromhex("f366f48f1ea9f2d1d3fe958c95ca84ea18e4c4ddb9366c336c927eb246fb38cb"), 32); ck_assert_mem_eq(node.private_key, fromhex("704addf544a06e5ee4bea37098463c23613da32020d604506da8c0518e1da4b7"), 32); ck_assert_mem_eq(node.public_key, fromhex("03a7d1d856deb74c508e05031f9895dab54626251b3806e16b4bd12e781a7df5b9"), 33); + hdnode_serialize(&node, 0x0488ADE4, 0, buffer); + ck_assert_str_eq(buffer, "xprv9zFnWC6h2cLgpmSA46vutJzBcfJ8yaJGg8cX1e5StJh45BBciYTRXSd25UEPVuesF9yog62tGAQtHjXajPPdbRCHuWS6T8XA2ECKADdw4Ef"); + hdnode_serialize(&node, 0x0488B21E, 1, buffer); + ck_assert_str_eq(buffer, "xpub6DF8uhdarytz3FWdA8TvFSvvAh8dP3283MY7p2V4SeE2wyWmG5mg5EwVvmdMVCQcoNJxGoWaU9DCWh89LojfZ537wTfunKau47EL2dhHKon"); // [Chain m/0/2147483647'/1/2147483646'] r = hdnode_private_ckd_prime(&node, 2147483646); @@ -171,6 +213,10 @@ START_TEST(test_bip32_vector_2) ck_assert_mem_eq(node.chain_code, fromhex("637807030d55d01f9a0cb3a7839515d796bd07706386a6eddf06cc29a65a0e29"), 32); ck_assert_mem_eq(node.private_key, fromhex("f1c7c871a54a804afe328b4c83a1c33b8e5ff48f5087273f04efa83b247d6a2d"), 32); ck_assert_mem_eq(node.public_key, fromhex("02d2b36900396c9282fa14628566582f206a5dd0bcc8d5e892611806cafb0301f0"), 33); + hdnode_serialize(&node, 0x0488ADE4, 0, buffer); + ck_assert_str_eq(buffer, "xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc"); + hdnode_serialize(&node, 0x0488B21E, 1, buffer); + ck_assert_str_eq(buffer, "xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL"); // [Chain m/0/2147483647'/1/2147483646'/2] r = hdnode_private_ckd(&node, 2); @@ -179,6 +225,10 @@ START_TEST(test_bip32_vector_2) ck_assert_mem_eq(node.chain_code, fromhex("9452b549be8cea3ecb7a84bec10dcfd94afe4d129ebfd3b3cb58eedf394ed271"), 32); ck_assert_mem_eq(node.private_key, fromhex("bb7d39bdb83ecf58f2fd82b6d918341cbef428661ef01ab97c28a4842125ac23"), 32); ck_assert_mem_eq(node.public_key, fromhex("024d902e1a2fc7a8755ab5b694c575fce742c48d9ff192e63df5193e4c7afe1f9c"), 33); + hdnode_serialize(&node, 0x0488ADE4, 0, buffer); + ck_assert_str_eq(buffer, "xprvA2nrNbFZABcdryreWet9Ea4LvTJcGsqrMzxHx98MMrotbir7yrKCEXw7nadnHM8Dq38EGfSh6dqA9QWTyefMLEcBYJUuekgW4BYPJcr9E7j"); + hdnode_serialize(&node, 0x0488B21E, 1, buffer); + ck_assert_str_eq(buffer, "xpub6FnCn6nSzZAw5Tw7cgR9bi15UV96gLZhjDstkXXxvCLsUXBGXPdSnLFbdpq8p9HmGsApME5hQTZ3emM2rnY5agb9rXpVGyy3bdW6EEgAtqt"); // init m hdnode_from_seed(fromhex("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), 64, &node); From c08bbfa58e540b430d87631f048ad50a7d68c824 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 15 May 2014 18:50:28 +0200 Subject: [PATCH 093/627] fix last commit --- bip32.c | 3 ++- bip32.h | 2 +- tests.c | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/bip32.c b/bip32.c index 993e404e8..b622dae08 100644 --- a/bip32.c +++ b/bip32.c @@ -119,7 +119,7 @@ void hdnode_fill_public_key(HDNode *node) ecdsa_get_public_key33(node->private_key, node->public_key); } -void hdnode_serialize(const HDNode *node, uint32_t version, char use_public, uint8_t *buffer) +void hdnode_serialize(const HDNode *node, uint32_t version, char use_public, char *buffer) { uint8_t node_data[82], a[32]; int i,j; @@ -149,4 +149,5 @@ void hdnode_serialize(const HDNode *node, uint32_t version, char use_public, uin } buffer[j] = code[rem]; } + buffer[111] = 0; } diff --git a/bip32.h b/bip32.h index 7acfb2408..586574866 100644 --- a/bip32.h +++ b/bip32.h @@ -28,6 +28,6 @@ void hdnode_fill_public_key(HDNode *node); void hdnode_fill_address(HDNode *node); -void hdnode_serialize(const HDNode *node, uint32_t version, char use_public, uint8_t *buffer); +void hdnode_serialize(const HDNode *node, uint32_t version, char use_public, char *buffer); #endif diff --git a/tests.c b/tests.c index deef70704..517623179 100644 --- a/tests.c +++ b/tests.c @@ -78,7 +78,7 @@ inline char *tohex(const uint8_t *bin, size_t l) START_TEST(test_bip32_vector_1) { HDNode node; - uint8_t buffer[113]; + char buffer[112]; // init m hdnode_from_seed(fromhex("000102030405060708090a0b0c0d0e0f"), 16, &node); @@ -154,7 +154,7 @@ END_TEST START_TEST(test_bip32_vector_2) { HDNode node; - uint8_t buffer[113]; + char buffer[112]; int r; // init m From 44116b8a7405299be5de8353e9e624538b4dac92 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 15 May 2014 19:35:28 +0200 Subject: [PATCH 094/627] make serialize api more friendly --- bip32.c | 10 ++++++++++ bip32.h | 4 +++- tests.c | 48 ++++++++++++++++++++++++------------------------ 3 files changed, 37 insertions(+), 25 deletions(-) diff --git a/bip32.c b/bip32.c index b622dae08..026f45a14 100644 --- a/bip32.c +++ b/bip32.c @@ -151,3 +151,13 @@ void hdnode_serialize(const HDNode *node, uint32_t version, char use_public, cha } buffer[111] = 0; } + +void hdnode_serialize_public(const HDNode *node, char *buffer) +{ + hdnode_serialize(node, 0x0488B21E, 1, buffer); +} + +void hdnode_serialize_private(const HDNode *node, char *buffer) +{ + hdnode_serialize(node, 0x0488ADE4, 0, buffer); +} diff --git a/bip32.h b/bip32.h index 586574866..b87b71ee1 100644 --- a/bip32.h +++ b/bip32.h @@ -28,6 +28,8 @@ void hdnode_fill_public_key(HDNode *node); void hdnode_fill_address(HDNode *node); -void hdnode_serialize(const HDNode *node, uint32_t version, char use_public, char *buffer); +void hdnode_serialize_public(const HDNode *node, char *buffer); + +void hdnode_serialize_private(const HDNode *node, char *buffer); #endif diff --git a/tests.c b/tests.c index 517623179..275521603 100644 --- a/tests.c +++ b/tests.c @@ -88,9 +88,9 @@ START_TEST(test_bip32_vector_1) ck_assert_mem_eq(node.chain_code, fromhex("873dff81c02f525623fd1fe5167eac3a55a049de3d314bb42ee227ffed37d508"), 32); ck_assert_mem_eq(node.private_key, fromhex("e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35"), 32); ck_assert_mem_eq(node.public_key, fromhex("0339a36013301597daef41fbe593a02cc513d0b55527ec2df1050e2e8ff49c85c2"), 33); - hdnode_serialize(&node, 0x0488ADE4, 0, buffer); + hdnode_serialize_private(&node, buffer); ck_assert_str_eq(buffer, "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi"); - hdnode_serialize(&node, 0x0488B21E, 1, buffer); + hdnode_serialize_public(&node, buffer); ck_assert_str_eq(buffer, "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8"); // [Chain m/0'] @@ -99,9 +99,9 @@ START_TEST(test_bip32_vector_1) ck_assert_mem_eq(node.chain_code, fromhex("47fdacbd0f1097043b78c63c20c34ef4ed9a111d980047ad16282c7ae6236141"), 32); ck_assert_mem_eq(node.private_key, fromhex("edb2e14f9ee77d26dd93b4ecede8d16ed408ce149b6cd80b0715a2d911a0afea"), 32); ck_assert_mem_eq(node.public_key, fromhex("035a784662a4a20a65bf6aab9ae98a6c068a81c52e4b032c0fb5400c706cfccc56"), 33); - hdnode_serialize(&node, 0x0488ADE4, 0, buffer); + hdnode_serialize_private(&node, buffer); ck_assert_str_eq(buffer, "xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7"); - hdnode_serialize(&node, 0x0488B21E, 1, buffer); + hdnode_serialize_public(&node, buffer); ck_assert_str_eq(buffer, "xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw"); // [Chain m/0'/1] @@ -110,9 +110,9 @@ START_TEST(test_bip32_vector_1) ck_assert_mem_eq(node.chain_code, fromhex("2a7857631386ba23dacac34180dd1983734e444fdbf774041578e9b6adb37c19"), 32); ck_assert_mem_eq(node.private_key, fromhex("3c6cb8d0f6a264c91ea8b5030fadaa8e538b020f0a387421a12de9319dc93368"), 32); ck_assert_mem_eq(node.public_key, fromhex("03501e454bf00751f24b1b489aa925215d66af2234e3891c3b21a52bedb3cd711c"), 33); - hdnode_serialize(&node, 0x0488ADE4, 0, buffer); + hdnode_serialize_private(&node, buffer); ck_assert_str_eq(buffer, "xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs"); - hdnode_serialize(&node, 0x0488B21E, 1, buffer); + hdnode_serialize_public(&node, buffer); ck_assert_str_eq(buffer, "xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFHKkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ"); // [Chain m/0'/1/2'] @@ -121,9 +121,9 @@ START_TEST(test_bip32_vector_1) ck_assert_mem_eq(node.chain_code, fromhex("04466b9cc8e161e966409ca52986c584f07e9dc81f735db683c3ff6ec7b1503f"), 32); ck_assert_mem_eq(node.private_key, fromhex("cbce0d719ecf7431d88e6a89fa1483e02e35092af60c042b1df2ff59fa424dca"), 32); ck_assert_mem_eq(node.public_key, fromhex("0357bfe1e341d01c69fe5654309956cbea516822fba8a601743a012a7896ee8dc2"), 33); - hdnode_serialize(&node, 0x0488ADE4, 0, buffer); + hdnode_serialize_private(&node, buffer); ck_assert_str_eq(buffer, "xprv9z4pot5VBttmtdRTWfWQmoH1taj2axGVzFqSb8C9xaxKymcFzXBDptWmT7FwuEzG3ryjH4ktypQSAewRiNMjANTtpgP4mLTj34bhnZX7UiM"); - hdnode_serialize(&node, 0x0488B21E, 1, buffer); + hdnode_serialize_public(&node, buffer); ck_assert_str_eq(buffer, "xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5"); // [Chain m/0'/1/2'/2] @@ -132,9 +132,9 @@ START_TEST(test_bip32_vector_1) ck_assert_mem_eq(node.chain_code, fromhex("cfb71883f01676f587d023cc53a35bc7f88f724b1f8c2892ac1275ac822a3edd"), 32); ck_assert_mem_eq(node.private_key, fromhex("0f479245fb19a38a1954c5c7c0ebab2f9bdfd96a17563ef28a6a4b1a2a764ef4"), 32); ck_assert_mem_eq(node.public_key, fromhex("02e8445082a72f29b75ca48748a914df60622a609cacfce8ed0e35804560741d29"), 33); - hdnode_serialize(&node, 0x0488ADE4, 0, buffer); + hdnode_serialize_private(&node, buffer); ck_assert_str_eq(buffer, "xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334"); - hdnode_serialize(&node, 0x0488B21E, 1, buffer); + hdnode_serialize_public(&node, buffer); ck_assert_str_eq(buffer, "xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV"); // [Chain m/0'/1/2'/2/1000000000] @@ -143,9 +143,9 @@ START_TEST(test_bip32_vector_1) ck_assert_mem_eq(node.chain_code, fromhex("c783e67b921d2beb8f6b389cc646d7263b4145701dadd2161548a8b078e65e9e"), 32); ck_assert_mem_eq(node.private_key, fromhex("471b76e389e528d6de6d816857e012c5455051cad6660850e58372a6c3e6e7c8"), 32); ck_assert_mem_eq(node.public_key, fromhex("022a471424da5e657499d1ff51cb43c47481a03b1e77f951fe64cec9f5a48f7011"), 33); - hdnode_serialize(&node, 0x0488ADE4, 0, buffer); + hdnode_serialize_private(&node, buffer); ck_assert_str_eq(buffer, "xprvA41z7zogVVwxVSgdKUHDy1SKmdb533PjDz7J6N6mV6uS3ze1ai8FHa8kmHScGpWmj4WggLyQjgPie1rFSruoUihUZREPSL39UNdE3BBDu76"); - hdnode_serialize(&node, 0x0488B21E, 1, buffer); + hdnode_serialize_public(&node, buffer); ck_assert_str_eq(buffer, "xpub6H1LXWLaKsWFhvm6RVpEL9P4KfRZSW7abD2ttkWP3SSQvnyA8FSVqNTEcYFgJS2UaFcxupHiYkro49S8yGasTvXEYBVPamhGW6cFJodrTHy"); } END_TEST @@ -165,9 +165,9 @@ START_TEST(test_bip32_vector_2) ck_assert_mem_eq(node.chain_code, fromhex("60499f801b896d83179a4374aeb7822aaeaceaa0db1f85ee3e904c4defbd9689"), 32); ck_assert_mem_eq(node.private_key, fromhex("4b03d6fc340455b363f51020ad3ecca4f0850280cf436c70c727923f6db46c3e"), 32); ck_assert_mem_eq(node.public_key, fromhex("03cbcaa9c98c877a26977d00825c956a238e8dddfbd322cce4f74b0b5bd6ace4a7"), 33); - hdnode_serialize(&node, 0x0488ADE4, 0, buffer); + hdnode_serialize_private(&node, buffer); ck_assert_str_eq(buffer, "xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U"); - hdnode_serialize(&node, 0x0488B21E, 1, buffer); + hdnode_serialize_public(&node, buffer); ck_assert_str_eq(buffer, "xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB"); // [Chain m/0] @@ -177,9 +177,9 @@ START_TEST(test_bip32_vector_2) ck_assert_mem_eq(node.chain_code, fromhex("f0909affaa7ee7abe5dd4e100598d4dc53cd709d5a5c2cac40e7412f232f7c9c"), 32); ck_assert_mem_eq(node.private_key, fromhex("abe74a98f6c7eabee0428f53798f0ab8aa1bd37873999041703c742f15ac7e1e"), 32); ck_assert_mem_eq(node.public_key, fromhex("02fc9e5af0ac8d9b3cecfe2a888e2117ba3d089d8585886c9c826b6b22a98d12ea"), 33); - hdnode_serialize(&node, 0x0488ADE4, 0, buffer); + hdnode_serialize_private(&node, buffer); ck_assert_str_eq(buffer, "xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt"); - hdnode_serialize(&node, 0x0488B21E, 1, buffer); + hdnode_serialize_public(&node, buffer); ck_assert_str_eq(buffer, "xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH"); // [Chain m/0/2147483647'] @@ -189,9 +189,9 @@ START_TEST(test_bip32_vector_2) ck_assert_mem_eq(node.chain_code, fromhex("be17a268474a6bb9c61e1d720cf6215e2a88c5406c4aee7b38547f585c9a37d9"), 32); ck_assert_mem_eq(node.private_key, fromhex("877c779ad9687164e9c2f4f0f4ff0340814392330693ce95a58fe18fd52e6e93"), 32); ck_assert_mem_eq(node.public_key, fromhex("03c01e7425647bdefa82b12d9bad5e3e6865bee0502694b94ca58b666abc0a5c3b"), 33); - hdnode_serialize(&node, 0x0488ADE4, 0, buffer); + hdnode_serialize_private(&node, buffer); ck_assert_str_eq(buffer, "xprv9wSp6B7kry3Vj9m1zSnLvN3xH8RdsPP1Mh7fAaR7aRLcQMKTR2vidYEeEg2mUCTAwCd6vnxVrcjfy2kRgVsFawNzmjuHc2YmYRmagcEPdU9"); - hdnode_serialize(&node, 0x0488B21E, 1, buffer); + hdnode_serialize_public(&node, buffer); ck_assert_str_eq(buffer, "xpub6ASAVgeehLbnwdqV6UKMHVzgqAG8Gr6riv3Fxxpj8ksbH9ebxaEyBLZ85ySDhKiLDBrQSARLq1uNRts8RuJiHjaDMBU4Zn9h8LZNnBC5y4a"); // [Chain m/0/2147483647'/1] @@ -201,9 +201,9 @@ START_TEST(test_bip32_vector_2) ck_assert_mem_eq(node.chain_code, fromhex("f366f48f1ea9f2d1d3fe958c95ca84ea18e4c4ddb9366c336c927eb246fb38cb"), 32); ck_assert_mem_eq(node.private_key, fromhex("704addf544a06e5ee4bea37098463c23613da32020d604506da8c0518e1da4b7"), 32); ck_assert_mem_eq(node.public_key, fromhex("03a7d1d856deb74c508e05031f9895dab54626251b3806e16b4bd12e781a7df5b9"), 33); - hdnode_serialize(&node, 0x0488ADE4, 0, buffer); + hdnode_serialize_private(&node, buffer); ck_assert_str_eq(buffer, "xprv9zFnWC6h2cLgpmSA46vutJzBcfJ8yaJGg8cX1e5StJh45BBciYTRXSd25UEPVuesF9yog62tGAQtHjXajPPdbRCHuWS6T8XA2ECKADdw4Ef"); - hdnode_serialize(&node, 0x0488B21E, 1, buffer); + hdnode_serialize_public(&node, buffer); ck_assert_str_eq(buffer, "xpub6DF8uhdarytz3FWdA8TvFSvvAh8dP3283MY7p2V4SeE2wyWmG5mg5EwVvmdMVCQcoNJxGoWaU9DCWh89LojfZ537wTfunKau47EL2dhHKon"); // [Chain m/0/2147483647'/1/2147483646'] @@ -213,9 +213,9 @@ START_TEST(test_bip32_vector_2) ck_assert_mem_eq(node.chain_code, fromhex("637807030d55d01f9a0cb3a7839515d796bd07706386a6eddf06cc29a65a0e29"), 32); ck_assert_mem_eq(node.private_key, fromhex("f1c7c871a54a804afe328b4c83a1c33b8e5ff48f5087273f04efa83b247d6a2d"), 32); ck_assert_mem_eq(node.public_key, fromhex("02d2b36900396c9282fa14628566582f206a5dd0bcc8d5e892611806cafb0301f0"), 33); - hdnode_serialize(&node, 0x0488ADE4, 0, buffer); + hdnode_serialize_private(&node, buffer); ck_assert_str_eq(buffer, "xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc"); - hdnode_serialize(&node, 0x0488B21E, 1, buffer); + hdnode_serialize_public(&node, buffer); ck_assert_str_eq(buffer, "xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL"); // [Chain m/0/2147483647'/1/2147483646'/2] @@ -225,9 +225,9 @@ START_TEST(test_bip32_vector_2) ck_assert_mem_eq(node.chain_code, fromhex("9452b549be8cea3ecb7a84bec10dcfd94afe4d129ebfd3b3cb58eedf394ed271"), 32); ck_assert_mem_eq(node.private_key, fromhex("bb7d39bdb83ecf58f2fd82b6d918341cbef428661ef01ab97c28a4842125ac23"), 32); ck_assert_mem_eq(node.public_key, fromhex("024d902e1a2fc7a8755ab5b694c575fce742c48d9ff192e63df5193e4c7afe1f9c"), 33); - hdnode_serialize(&node, 0x0488ADE4, 0, buffer); + hdnode_serialize_private(&node, buffer); ck_assert_str_eq(buffer, "xprvA2nrNbFZABcdryreWet9Ea4LvTJcGsqrMzxHx98MMrotbir7yrKCEXw7nadnHM8Dq38EGfSh6dqA9QWTyefMLEcBYJUuekgW4BYPJcr9E7j"); - hdnode_serialize(&node, 0x0488B21E, 1, buffer); + hdnode_serialize_public(&node, buffer); ck_assert_str_eq(buffer, "xpub6FnCn6nSzZAw5Tw7cgR9bi15UV96gLZhjDstkXXxvCLsUXBGXPdSnLFbdpq8p9HmGsApME5hQTZ3emM2rnY5agb9rXpVGyy3bdW6EEgAtqt"); // init m From c1140e071eba23301c7d091d1e9f5fe9f7f13b2d Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 21 May 2014 00:15:55 +0200 Subject: [PATCH 095/627] added deserialization --- bip32.c | 75 +++++++++++++++++++++--- bip32.h | 6 +- tests.c | 177 +++++++++++++++++++++++++++++++++++++++----------------- 3 files changed, 197 insertions(+), 61 deletions(-) diff --git a/bip32.c b/bip32.c index 026f45a14..7a9d4722d 100644 --- a/bip32.c +++ b/bip32.c @@ -30,6 +30,7 @@ void hdnode_from_xprv(uint32_t depth, uint32_t fingerprint, uint32_t child_num, void hdnode_from_seed(uint8_t *seed, int seed_len, HDNode *out) { uint8_t I[32 + 32]; + memset(out, 0, sizeof(HDNode)); out->depth = 0; out->fingerprint = 0x00000000; out->child_num = 0; @@ -119,7 +120,7 @@ void hdnode_fill_public_key(HDNode *node) ecdsa_get_public_key33(node->private_key, node->public_key); } -void hdnode_serialize(const HDNode *node, uint32_t version, char use_public, char *buffer) +void hdnode_serialize(const HDNode *node, uint32_t version, char use_public, char *str) { uint8_t node_data[82], a[32]; int i,j; @@ -147,17 +148,77 @@ void hdnode_serialize(const HDNode *node, uint32_t version, char use_public, cha node_data[i] = rem * 4 + (tmp / 58); rem = tmp % 58; } - buffer[j] = code[rem]; + str[j] = code[rem]; } - buffer[111] = 0; + str[111] = 0; } -void hdnode_serialize_public(const HDNode *node, char *buffer) +void hdnode_serialize_public(const HDNode *node, char *str) { - hdnode_serialize(node, 0x0488B21E, 1, buffer); + hdnode_serialize(node, 0x0488B21E, 1, str); } -void hdnode_serialize_private(const HDNode *node, char *buffer) +void hdnode_serialize_private(const HDNode *node, char *str) { - hdnode_serialize(node, 0x0488ADE4, 0, buffer); + hdnode_serialize(node, 0x0488ADE4, 0, str); +} + +// check for validity of curve point in case of public data not performed +int hdnode_deserialize(const char *str, HDNode *node) +{ + uint8_t node_data[82], a[32]; + const char decode[] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, + 4, 5, 6, 7, 8, -1, -1, -1, -1, -1, -1, -1, 9, 10, 11, + 12, 13, 14, 15, 16, -1, 17, 18, 19, 20, 21, -1, 22, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, -1, -1, -1, + -1, -1, -1, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, + 43, -1, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57 + }; + memset(node, 0, sizeof(HDNode)); + memset(node_data, 0, sizeof(node_data)); + if (strlen(str) != 111) { // invalid data length + return -1; + } + int i, j, k; + for (i = 0; i < 111; i++) { + if (str[i] < 0 || str[i] >= (int)sizeof(decode)) { // invalid character + return -2; + } + k = decode[(int)str[i]]; + if (k == -1) { // invalid character + return -2; + } + for (j = 81; j >= 0; j--) { + k += node_data[j] * 58; + node_data[j] = k & 0xFF; + k >>= 8; + } + } + sha256_Raw(node_data, 78, a); + sha256_Raw(a, 32, a); + if (memcmp(node_data + 78, a, 4)) { // wrong checksum + return -3; + } + uint32_t version = read_be(node_data); + if (version == 0x0488B21E) { // public node + memcpy(node->public_key, node_data + 45, 33); + } else if (version == 0x0488ADE4) { // private node + if (node_data[45]) { // invalid data + return -4; + } + memcpy(node->private_key, node_data + 46, 32); + hdnode_fill_public_key(node); + } else { + return -5; // invalid version + } + node->depth = node_data[4]; + node->fingerprint = read_be(node_data + 5); + node->child_num = read_be(node_data + 9); + memcpy(node->chain_code, node_data + 13, 32); + return 0; } diff --git a/bip32.h b/bip32.h index b87b71ee1..42cc26512 100644 --- a/bip32.h +++ b/bip32.h @@ -28,8 +28,10 @@ void hdnode_fill_public_key(HDNode *node); void hdnode_fill_address(HDNode *node); -void hdnode_serialize_public(const HDNode *node, char *buffer); +void hdnode_serialize_public(const HDNode *node, char *str); -void hdnode_serialize_private(const HDNode *node, char *buffer); +void hdnode_serialize_private(const HDNode *node, char *str); + +int hdnode_deserialize(const char *str, HDNode *node); #endif diff --git a/tests.c b/tests.c index 275521603..1fb5ab562 100644 --- a/tests.c +++ b/tests.c @@ -77,8 +77,9 @@ inline char *tohex(const uint8_t *bin, size_t l) // test vector 1 from https://en.bitcoin.it/wiki/BIP_0032_TestVectors START_TEST(test_bip32_vector_1) { - HDNode node; - char buffer[112]; + HDNode node, node2, node3; + char str[112]; + int r; // init m hdnode_from_seed(fromhex("000102030405060708090a0b0c0d0e0f"), 16, &node); @@ -88,10 +89,16 @@ START_TEST(test_bip32_vector_1) ck_assert_mem_eq(node.chain_code, fromhex("873dff81c02f525623fd1fe5167eac3a55a049de3d314bb42ee227ffed37d508"), 32); ck_assert_mem_eq(node.private_key, fromhex("e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35"), 32); ck_assert_mem_eq(node.public_key, fromhex("0339a36013301597daef41fbe593a02cc513d0b55527ec2df1050e2e8ff49c85c2"), 33); - hdnode_serialize_private(&node, buffer); - ck_assert_str_eq(buffer, "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi"); - hdnode_serialize_public(&node, buffer); - ck_assert_str_eq(buffer, "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8"); + hdnode_serialize_private(&node, str); + ck_assert_str_eq(str, "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi"); + r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); ck_assert_int_eq(r, 0); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, str); + ck_assert_str_eq(str, "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8"); + r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memset(&node3.private_key, 0, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); // [Chain m/0'] hdnode_private_ckd_prime(&node, 0); @@ -99,10 +106,16 @@ START_TEST(test_bip32_vector_1) ck_assert_mem_eq(node.chain_code, fromhex("47fdacbd0f1097043b78c63c20c34ef4ed9a111d980047ad16282c7ae6236141"), 32); ck_assert_mem_eq(node.private_key, fromhex("edb2e14f9ee77d26dd93b4ecede8d16ed408ce149b6cd80b0715a2d911a0afea"), 32); ck_assert_mem_eq(node.public_key, fromhex("035a784662a4a20a65bf6aab9ae98a6c068a81c52e4b032c0fb5400c706cfccc56"), 33); - hdnode_serialize_private(&node, buffer); - ck_assert_str_eq(buffer, "xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7"); - hdnode_serialize_public(&node, buffer); - ck_assert_str_eq(buffer, "xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw"); + hdnode_serialize_private(&node, str); + ck_assert_str_eq(str, "xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7"); + r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, str); + ck_assert_str_eq(str, "xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw"); + r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memset(&node3.private_key, 0, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); // [Chain m/0'/1] hdnode_private_ckd(&node, 1); @@ -110,10 +123,16 @@ START_TEST(test_bip32_vector_1) ck_assert_mem_eq(node.chain_code, fromhex("2a7857631386ba23dacac34180dd1983734e444fdbf774041578e9b6adb37c19"), 32); ck_assert_mem_eq(node.private_key, fromhex("3c6cb8d0f6a264c91ea8b5030fadaa8e538b020f0a387421a12de9319dc93368"), 32); ck_assert_mem_eq(node.public_key, fromhex("03501e454bf00751f24b1b489aa925215d66af2234e3891c3b21a52bedb3cd711c"), 33); - hdnode_serialize_private(&node, buffer); - ck_assert_str_eq(buffer, "xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs"); - hdnode_serialize_public(&node, buffer); - ck_assert_str_eq(buffer, "xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFHKkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ"); + hdnode_serialize_private(&node, str); + ck_assert_str_eq(str, "xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs"); + r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, str); + ck_assert_str_eq(str, "xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFHKkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ"); + r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memset(&node3.private_key, 0, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); // [Chain m/0'/1/2'] hdnode_private_ckd_prime(&node, 2); @@ -121,10 +140,16 @@ START_TEST(test_bip32_vector_1) ck_assert_mem_eq(node.chain_code, fromhex("04466b9cc8e161e966409ca52986c584f07e9dc81f735db683c3ff6ec7b1503f"), 32); ck_assert_mem_eq(node.private_key, fromhex("cbce0d719ecf7431d88e6a89fa1483e02e35092af60c042b1df2ff59fa424dca"), 32); ck_assert_mem_eq(node.public_key, fromhex("0357bfe1e341d01c69fe5654309956cbea516822fba8a601743a012a7896ee8dc2"), 33); - hdnode_serialize_private(&node, buffer); - ck_assert_str_eq(buffer, "xprv9z4pot5VBttmtdRTWfWQmoH1taj2axGVzFqSb8C9xaxKymcFzXBDptWmT7FwuEzG3ryjH4ktypQSAewRiNMjANTtpgP4mLTj34bhnZX7UiM"); - hdnode_serialize_public(&node, buffer); - ck_assert_str_eq(buffer, "xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5"); + hdnode_serialize_private(&node, str); + ck_assert_str_eq(str, "xprv9z4pot5VBttmtdRTWfWQmoH1taj2axGVzFqSb8C9xaxKymcFzXBDptWmT7FwuEzG3ryjH4ktypQSAewRiNMjANTtpgP4mLTj34bhnZX7UiM"); + r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, str); + ck_assert_str_eq(str, "xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5"); + r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memset(&node3.private_key, 0, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); // [Chain m/0'/1/2'/2] hdnode_private_ckd(&node, 2); @@ -132,10 +157,16 @@ START_TEST(test_bip32_vector_1) ck_assert_mem_eq(node.chain_code, fromhex("cfb71883f01676f587d023cc53a35bc7f88f724b1f8c2892ac1275ac822a3edd"), 32); ck_assert_mem_eq(node.private_key, fromhex("0f479245fb19a38a1954c5c7c0ebab2f9bdfd96a17563ef28a6a4b1a2a764ef4"), 32); ck_assert_mem_eq(node.public_key, fromhex("02e8445082a72f29b75ca48748a914df60622a609cacfce8ed0e35804560741d29"), 33); - hdnode_serialize_private(&node, buffer); - ck_assert_str_eq(buffer, "xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334"); - hdnode_serialize_public(&node, buffer); - ck_assert_str_eq(buffer, "xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV"); + hdnode_serialize_private(&node, str); + ck_assert_str_eq(str, "xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334"); + r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, str); + ck_assert_str_eq(str, "xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV"); + r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memset(&node3.private_key, 0, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); // [Chain m/0'/1/2'/2/1000000000] hdnode_private_ckd(&node, 1000000000); @@ -143,18 +174,24 @@ START_TEST(test_bip32_vector_1) ck_assert_mem_eq(node.chain_code, fromhex("c783e67b921d2beb8f6b389cc646d7263b4145701dadd2161548a8b078e65e9e"), 32); ck_assert_mem_eq(node.private_key, fromhex("471b76e389e528d6de6d816857e012c5455051cad6660850e58372a6c3e6e7c8"), 32); ck_assert_mem_eq(node.public_key, fromhex("022a471424da5e657499d1ff51cb43c47481a03b1e77f951fe64cec9f5a48f7011"), 33); - hdnode_serialize_private(&node, buffer); - ck_assert_str_eq(buffer, "xprvA41z7zogVVwxVSgdKUHDy1SKmdb533PjDz7J6N6mV6uS3ze1ai8FHa8kmHScGpWmj4WggLyQjgPie1rFSruoUihUZREPSL39UNdE3BBDu76"); - hdnode_serialize_public(&node, buffer); - ck_assert_str_eq(buffer, "xpub6H1LXWLaKsWFhvm6RVpEL9P4KfRZSW7abD2ttkWP3SSQvnyA8FSVqNTEcYFgJS2UaFcxupHiYkro49S8yGasTvXEYBVPamhGW6cFJodrTHy"); + hdnode_serialize_private(&node, str); + ck_assert_str_eq(str, "xprvA41z7zogVVwxVSgdKUHDy1SKmdb533PjDz7J6N6mV6uS3ze1ai8FHa8kmHScGpWmj4WggLyQjgPie1rFSruoUihUZREPSL39UNdE3BBDu76"); + r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, str); + ck_assert_str_eq(str, "xpub6H1LXWLaKsWFhvm6RVpEL9P4KfRZSW7abD2ttkWP3SSQvnyA8FSVqNTEcYFgJS2UaFcxupHiYkro49S8yGasTvXEYBVPamhGW6cFJodrTHy"); + r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memset(&node3.private_key, 0, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); } END_TEST // test vector 2 from https://en.bitcoin.it/wiki/BIP_0032_TestVectors START_TEST(test_bip32_vector_2) { - HDNode node; - char buffer[112]; + HDNode node, node2, node3; + char str[112]; int r; // init m @@ -165,10 +202,16 @@ START_TEST(test_bip32_vector_2) ck_assert_mem_eq(node.chain_code, fromhex("60499f801b896d83179a4374aeb7822aaeaceaa0db1f85ee3e904c4defbd9689"), 32); ck_assert_mem_eq(node.private_key, fromhex("4b03d6fc340455b363f51020ad3ecca4f0850280cf436c70c727923f6db46c3e"), 32); ck_assert_mem_eq(node.public_key, fromhex("03cbcaa9c98c877a26977d00825c956a238e8dddfbd322cce4f74b0b5bd6ace4a7"), 33); - hdnode_serialize_private(&node, buffer); - ck_assert_str_eq(buffer, "xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U"); - hdnode_serialize_public(&node, buffer); - ck_assert_str_eq(buffer, "xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB"); + hdnode_serialize_private(&node, str); + ck_assert_str_eq(str, "xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U"); + r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, str); + ck_assert_str_eq(str, "xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB"); + r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memset(&node3.private_key, 0, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); // [Chain m/0] r = hdnode_private_ckd(&node, 0); @@ -177,10 +220,16 @@ START_TEST(test_bip32_vector_2) ck_assert_mem_eq(node.chain_code, fromhex("f0909affaa7ee7abe5dd4e100598d4dc53cd709d5a5c2cac40e7412f232f7c9c"), 32); ck_assert_mem_eq(node.private_key, fromhex("abe74a98f6c7eabee0428f53798f0ab8aa1bd37873999041703c742f15ac7e1e"), 32); ck_assert_mem_eq(node.public_key, fromhex("02fc9e5af0ac8d9b3cecfe2a888e2117ba3d089d8585886c9c826b6b22a98d12ea"), 33); - hdnode_serialize_private(&node, buffer); - ck_assert_str_eq(buffer, "xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt"); - hdnode_serialize_public(&node, buffer); - ck_assert_str_eq(buffer, "xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH"); + hdnode_serialize_private(&node, str); + ck_assert_str_eq(str, "xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt"); + r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, str); + ck_assert_str_eq(str, "xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH"); + r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memset(&node3.private_key, 0, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); // [Chain m/0/2147483647'] r = hdnode_private_ckd_prime(&node, 2147483647); @@ -189,10 +238,16 @@ START_TEST(test_bip32_vector_2) ck_assert_mem_eq(node.chain_code, fromhex("be17a268474a6bb9c61e1d720cf6215e2a88c5406c4aee7b38547f585c9a37d9"), 32); ck_assert_mem_eq(node.private_key, fromhex("877c779ad9687164e9c2f4f0f4ff0340814392330693ce95a58fe18fd52e6e93"), 32); ck_assert_mem_eq(node.public_key, fromhex("03c01e7425647bdefa82b12d9bad5e3e6865bee0502694b94ca58b666abc0a5c3b"), 33); - hdnode_serialize_private(&node, buffer); - ck_assert_str_eq(buffer, "xprv9wSp6B7kry3Vj9m1zSnLvN3xH8RdsPP1Mh7fAaR7aRLcQMKTR2vidYEeEg2mUCTAwCd6vnxVrcjfy2kRgVsFawNzmjuHc2YmYRmagcEPdU9"); - hdnode_serialize_public(&node, buffer); - ck_assert_str_eq(buffer, "xpub6ASAVgeehLbnwdqV6UKMHVzgqAG8Gr6riv3Fxxpj8ksbH9ebxaEyBLZ85ySDhKiLDBrQSARLq1uNRts8RuJiHjaDMBU4Zn9h8LZNnBC5y4a"); + hdnode_serialize_private(&node, str); + ck_assert_str_eq(str, "xprv9wSp6B7kry3Vj9m1zSnLvN3xH8RdsPP1Mh7fAaR7aRLcQMKTR2vidYEeEg2mUCTAwCd6vnxVrcjfy2kRgVsFawNzmjuHc2YmYRmagcEPdU9"); + r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, str); + ck_assert_str_eq(str, "xpub6ASAVgeehLbnwdqV6UKMHVzgqAG8Gr6riv3Fxxpj8ksbH9ebxaEyBLZ85ySDhKiLDBrQSARLq1uNRts8RuJiHjaDMBU4Zn9h8LZNnBC5y4a"); + r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memset(&node3.private_key, 0, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); // [Chain m/0/2147483647'/1] r = hdnode_private_ckd(&node, 1); @@ -201,10 +256,16 @@ START_TEST(test_bip32_vector_2) ck_assert_mem_eq(node.chain_code, fromhex("f366f48f1ea9f2d1d3fe958c95ca84ea18e4c4ddb9366c336c927eb246fb38cb"), 32); ck_assert_mem_eq(node.private_key, fromhex("704addf544a06e5ee4bea37098463c23613da32020d604506da8c0518e1da4b7"), 32); ck_assert_mem_eq(node.public_key, fromhex("03a7d1d856deb74c508e05031f9895dab54626251b3806e16b4bd12e781a7df5b9"), 33); - hdnode_serialize_private(&node, buffer); - ck_assert_str_eq(buffer, "xprv9zFnWC6h2cLgpmSA46vutJzBcfJ8yaJGg8cX1e5StJh45BBciYTRXSd25UEPVuesF9yog62tGAQtHjXajPPdbRCHuWS6T8XA2ECKADdw4Ef"); - hdnode_serialize_public(&node, buffer); - ck_assert_str_eq(buffer, "xpub6DF8uhdarytz3FWdA8TvFSvvAh8dP3283MY7p2V4SeE2wyWmG5mg5EwVvmdMVCQcoNJxGoWaU9DCWh89LojfZ537wTfunKau47EL2dhHKon"); + hdnode_serialize_private(&node, str); + ck_assert_str_eq(str, "xprv9zFnWC6h2cLgpmSA46vutJzBcfJ8yaJGg8cX1e5StJh45BBciYTRXSd25UEPVuesF9yog62tGAQtHjXajPPdbRCHuWS6T8XA2ECKADdw4Ef"); + r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, str); + ck_assert_str_eq(str, "xpub6DF8uhdarytz3FWdA8TvFSvvAh8dP3283MY7p2V4SeE2wyWmG5mg5EwVvmdMVCQcoNJxGoWaU9DCWh89LojfZ537wTfunKau47EL2dhHKon"); + r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memset(&node3.private_key, 0, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); // [Chain m/0/2147483647'/1/2147483646'] r = hdnode_private_ckd_prime(&node, 2147483646); @@ -213,10 +274,16 @@ START_TEST(test_bip32_vector_2) ck_assert_mem_eq(node.chain_code, fromhex("637807030d55d01f9a0cb3a7839515d796bd07706386a6eddf06cc29a65a0e29"), 32); ck_assert_mem_eq(node.private_key, fromhex("f1c7c871a54a804afe328b4c83a1c33b8e5ff48f5087273f04efa83b247d6a2d"), 32); ck_assert_mem_eq(node.public_key, fromhex("02d2b36900396c9282fa14628566582f206a5dd0bcc8d5e892611806cafb0301f0"), 33); - hdnode_serialize_private(&node, buffer); - ck_assert_str_eq(buffer, "xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc"); - hdnode_serialize_public(&node, buffer); - ck_assert_str_eq(buffer, "xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL"); + hdnode_serialize_private(&node, str); + ck_assert_str_eq(str, "xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc"); + r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, str); + ck_assert_str_eq(str, "xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL"); + r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memset(&node3.private_key, 0, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); // [Chain m/0/2147483647'/1/2147483646'/2] r = hdnode_private_ckd(&node, 2); @@ -225,10 +292,16 @@ START_TEST(test_bip32_vector_2) ck_assert_mem_eq(node.chain_code, fromhex("9452b549be8cea3ecb7a84bec10dcfd94afe4d129ebfd3b3cb58eedf394ed271"), 32); ck_assert_mem_eq(node.private_key, fromhex("bb7d39bdb83ecf58f2fd82b6d918341cbef428661ef01ab97c28a4842125ac23"), 32); ck_assert_mem_eq(node.public_key, fromhex("024d902e1a2fc7a8755ab5b694c575fce742c48d9ff192e63df5193e4c7afe1f9c"), 33); - hdnode_serialize_private(&node, buffer); - ck_assert_str_eq(buffer, "xprvA2nrNbFZABcdryreWet9Ea4LvTJcGsqrMzxHx98MMrotbir7yrKCEXw7nadnHM8Dq38EGfSh6dqA9QWTyefMLEcBYJUuekgW4BYPJcr9E7j"); - hdnode_serialize_public(&node, buffer); - ck_assert_str_eq(buffer, "xpub6FnCn6nSzZAw5Tw7cgR9bi15UV96gLZhjDstkXXxvCLsUXBGXPdSnLFbdpq8p9HmGsApME5hQTZ3emM2rnY5agb9rXpVGyy3bdW6EEgAtqt"); + hdnode_serialize_private(&node, str); + ck_assert_str_eq(str, "xprvA2nrNbFZABcdryreWet9Ea4LvTJcGsqrMzxHx98MMrotbir7yrKCEXw7nadnHM8Dq38EGfSh6dqA9QWTyefMLEcBYJUuekgW4BYPJcr9E7j"); + r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, str); + ck_assert_str_eq(str, "xpub6FnCn6nSzZAw5Tw7cgR9bi15UV96gLZhjDstkXXxvCLsUXBGXPdSnLFbdpq8p9HmGsApME5hQTZ3emM2rnY5agb9rXpVGyy3bdW6EEgAtqt"); + r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memset(&node3.private_key, 0, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); // init m hdnode_from_seed(fromhex("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), 64, &node); From 612f5ab050cdd0b62f56ab3b0a60f0442f37f78e Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 22 May 2014 20:54:58 +0200 Subject: [PATCH 096/627] fix copyright headers --- bignum.c | 4 ++-- bignum.h | 4 ++-- bip32.c | 23 +++++++++++++++++++++++ bip32.h | 23 +++++++++++++++++++++++ bip39.c | 23 +++++++++++++++++++++++ bip39.h | 23 +++++++++++++++++++++++ bip39_english.h | 23 +++++++++++++++++++++++ ecdsa.c | 4 ++-- ecdsa.h | 4 ++-- hmac.c | 23 +++++++++++++++++++++++ hmac.h | 23 +++++++++++++++++++++++ pbkdf2.c | 23 +++++++++++++++++++++++ pbkdf2.h | 23 +++++++++++++++++++++++ rand.c | 4 ++-- rand.h | 4 ++-- secp256k1.c | 4 ++-- secp256k1.h | 4 ++-- sha2.c | 2 +- sha2.h | 2 +- test-openssl.c | 4 ++-- tests.c | 4 ++-- 21 files changed, 229 insertions(+), 22 deletions(-) diff --git a/bignum.c b/bignum.c index 7d3db379d..06e7308bc 100644 --- a/bignum.c +++ b/bignum.c @@ -1,6 +1,6 @@ /** - * Copyright (c) 2013 Tomas Dzetkulic - * Copyright (c) 2013 Pavol Rusnak + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the "Software"), diff --git a/bignum.h b/bignum.h index 293d8120f..2e3a3917a 100644 --- a/bignum.h +++ b/bignum.h @@ -1,6 +1,6 @@ /** - * Copyright (c) 2013 Tomas Dzetkulic - * Copyright (c) 2013 Pavol Rusnak + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the "Software"), diff --git a/bip32.c b/bip32.c index 7a9d4722d..1d3ce8d19 100644 --- a/bip32.c +++ b/bip32.c @@ -1,3 +1,26 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + #include #include "bignum.h" diff --git a/bip32.h b/bip32.h index 42cc26512..49c9676e6 100644 --- a/bip32.h +++ b/bip32.h @@ -1,3 +1,26 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + #ifndef __BIP32_H__ #define __BIP32_H__ diff --git a/bip39.c b/bip39.c index 8d0fa1ee1..aa0e89afb 100644 --- a/bip39.c +++ b/bip39.c @@ -1,3 +1,26 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + #include #include "bip39.h" diff --git a/bip39.h b/bip39.h index 1f77c8496..3bf73b532 100644 --- a/bip39.h +++ b/bip39.h @@ -1,3 +1,26 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + #ifndef __BIP39_H__ #define __BIP39_H__ diff --git a/bip39_english.h b/bip39_english.h index d9c173472..4ecddba4b 100644 --- a/bip39_english.h +++ b/bip39_english.h @@ -1,3 +1,26 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + const char *wordlist[] = { "abandon", "ability", diff --git a/ecdsa.c b/ecdsa.c index 533cc7788..e1dbbe86c 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -1,6 +1,6 @@ /** - * Copyright (c) 2013 Tomas Dzetkulic - * Copyright (c) 2013 Pavol Rusnak + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the "Software"), diff --git a/ecdsa.h b/ecdsa.h index 8097c5288..b7f59b350 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -1,6 +1,6 @@ /** - * Copyright (c) 2013 Tomas Dzetkulic - * Copyright (c) 2013 Pavol Rusnak + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the "Software"), diff --git a/hmac.c b/hmac.c index be78b0b75..a8d95ff8d 100644 --- a/hmac.c +++ b/hmac.c @@ -1,3 +1,26 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + #include #include "hmac.h" diff --git a/hmac.h b/hmac.h index 7481a67a6..6981b63a7 100644 --- a/hmac.h +++ b/hmac.h @@ -1,3 +1,26 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + #ifndef __HMAC_H__ #define __HMAC_H__ diff --git a/pbkdf2.c b/pbkdf2.c index 3e7a4f79c..02699a0e9 100644 --- a/pbkdf2.c +++ b/pbkdf2.c @@ -1,3 +1,26 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + #include #include "pbkdf2.h" #include "hmac.h" diff --git a/pbkdf2.h b/pbkdf2.h index 48526d472..8e88955a8 100644 --- a/pbkdf2.h +++ b/pbkdf2.h @@ -1,3 +1,26 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + #ifndef __PBKDF2_H__ #define __PBKDF2_H__ diff --git a/rand.c b/rand.c index 20176d71e..bc9c72043 100644 --- a/rand.c +++ b/rand.c @@ -1,6 +1,6 @@ /** - * Copyright (c) 2013 Tomas Dzetkulic - * Copyright (c) 2013 Pavol Rusnak + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the "Software"), diff --git a/rand.h b/rand.h index fff02e260..3d49e68db 100644 --- a/rand.h +++ b/rand.h @@ -1,6 +1,6 @@ /** - * Copyright (c) 2013 Tomas Dzetkulic - * Copyright (c) 2013 Pavol Rusnak + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the "Software"), diff --git a/secp256k1.c b/secp256k1.c index ced28a3bc..40aa97281 100644 --- a/secp256k1.c +++ b/secp256k1.c @@ -1,6 +1,6 @@ /** - * Copyright (c) 2013 Tomas Dzetkulic - * Copyright (c) 2013 Pavol Rusnak + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the "Software"), diff --git a/secp256k1.h b/secp256k1.h index 3ab713d57..e3a5f5378 100644 --- a/secp256k1.h +++ b/secp256k1.h @@ -1,6 +1,6 @@ /** - * Copyright (c) 2013 Tomas Dzetkulic - * Copyright (c) 2013 Pavol Rusnak + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the "Software"), diff --git a/sha2.c b/sha2.c index 670a4a79c..3e21cdaa9 100644 --- a/sha2.c +++ b/sha2.c @@ -1,6 +1,6 @@ /** * Copyright (c) 2000-2001 Aaron D. Gifford - * Copyright (c) 2013 Pavol Rusnak + * Copyright (c) 2013-2014 Pavol Rusnak * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/sha2.h b/sha2.h index 318e5fe41..e8fae89ba 100644 --- a/sha2.h +++ b/sha2.h @@ -1,6 +1,6 @@ /** * Copyright (c) 2000-2001 Aaron D. Gifford - * Copyright (c) 2013 Pavol Rusnak + * Copyright (c) 2013-2014 Pavol Rusnak * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/test-openssl.c b/test-openssl.c index 65d685fc5..696563833 100644 --- a/test-openssl.c +++ b/test-openssl.c @@ -1,6 +1,6 @@ /** - * Copyright (c) 2013 Tomas Dzetkulic - * Copyright (c) 2013 Pavol Rusnak + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the "Software"), diff --git a/tests.c b/tests.c index 1fb5ab562..90c1df2d5 100644 --- a/tests.c +++ b/tests.c @@ -1,6 +1,6 @@ /** - * Copyright (c) 2013 Tomas Dzetkulic - * Copyright (c) 2013 Pavol Rusnak + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the "Software"), From 4b1211e0ae5e414c928ff0c19c778137752625f6 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 22 May 2014 21:52:04 +0200 Subject: [PATCH 097/627] extract base58 functions to separate source file --- CMakeLists.txt | 2 +- Makefile | 2 +- base58.c | 125 +++++++++++++++++++++++++++++++++++++++++++++++++ base58.h | 32 +++++++++++++ bip32.c | 62 +++--------------------- 5 files changed, 166 insertions(+), 57 deletions(-) create mode 100644 base58.c create mode 100644 base58.h diff --git a/CMakeLists.txt b/CMakeLists.txt index da714d93b..007f1a6c7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -set(SOURCES bignum.c ecdsa.c secp256k1.c sha2.c rand.c hmac.c bip32.c ripemd160.c bip39.c pbkdf2.c) +set(SOURCES bignum.c ecdsa.c secp256k1.c sha2.c rand.c hmac.c bip32.c ripemd160.c bip39.c pbkdf2.c base58.c) if(MSVC) set_source_files_properties(${SOURCES} PROPERTIES LANGUAGE CXX) endif(MSVC) diff --git a/Makefile b/Makefile index e96dee000..d2f9e61dd 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ CC = gcc CFLAGS = -Wall -Wextra -Os -OBJS = bignum.o ecdsa.o secp256k1.o sha2.o rand.o hmac.o bip32.o ripemd160.o bip39.o pbkdf2.o +OBJS = bignum.o ecdsa.o secp256k1.o sha2.o rand.o hmac.o bip32.o ripemd160.o bip39.o pbkdf2.o base58.o OBJS += aescrypt.o aeskey.o aestab.o all: tests test-openssl diff --git a/base58.c b/base58.c new file mode 100644 index 000000000..aaefa3548 --- /dev/null +++ b/base58.c @@ -0,0 +1,125 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include "base58.h" +#include "sha2.h" + +int base58_encode_check(const uint8_t *data, int len, char *str) +{ + int outlen; + switch (len) { + case 78: // xpub/xprv 78 + outlen = 111; + break; + case 34: // WIF privkey 1+32 + outlen = 51; + break; + case 21: // address 1+20 + outlen = 34; + break; + default: + return 0; + } + uint8_t mydata[82], hash[32]; + sha256_Raw(data, len, hash); + sha256_Raw(hash, 32, hash); + memcpy(mydata, data, len); + memcpy(mydata + len, hash, 4); // checksum + uint32_t rem, tmp; + const char code[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; + int i, j; + for (j = 0; j < outlen; j++) { + rem = mydata[0] % 58; + mydata[0] /= 58; + for (i = 1; i < len + 4; i++) { + tmp = rem * 24 + mydata[i]; // 2^8 == 4*58 + 24 + mydata[i] = rem * 4 + (tmp / 58); + rem = tmp % 58; + } + str[outlen - 1 - j] = code[rem]; + } + str[outlen] = 0; + return outlen; +} + +int base58_decode_check(const char *str, uint8_t *data) +{ + const char decode[] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, + 4, 5, 6, 7, 8, -1, -1, -1, -1, -1, -1, -1, 9, 10, 11, + 12, 13, 14, 15, 16, -1, 17, 18, 19, 20, 21, -1, 22, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, -1, -1, -1, + -1, -1, -1, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, + 43, -1, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57 + }; + uint8_t mydata[82], hash[32]; + int j, k, outlen; + switch (strlen(str)) { + case 111: // xpub/xprv + outlen = 78; + break; + case 51: // WIF privkey + outlen = 34; + break; + case 27: // address + case 28: + case 29: + case 30: + case 31: + case 32: + case 33: + case 34: + outlen = 21; + break; + default: + return 0; + } + memset(mydata, 0, sizeof(mydata)); + while (*str) { + if (*str < 0 || *str >= (int)sizeof(decode)) { // invalid character + return 0; + } + k = decode[(int)*str]; + if (k == -1) { // invalid character + return 0; + } + for (j = outlen + 4 - 1; j >= 0; j--) { + k += mydata[j] * 58; + mydata[j] = k & 0xFF; + k >>= 8; + } + str++; + } + sha256_Raw(mydata, outlen, hash); + sha256_Raw(hash, 32, hash); + if (memcmp(mydata + outlen, hash, 4)) { // wrong checksum + return 0; + } + memcpy(data, mydata, outlen); + return outlen; +} diff --git a/base58.h b/base58.h new file mode 100644 index 000000000..491f248bf --- /dev/null +++ b/base58.h @@ -0,0 +1,32 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __BASE58_H__ +#define __BASE58_H__ + +#include + +int base58_encode_check(const uint8_t *data, int len, char *str); +int base58_decode_check(const char *str, uint8_t *data); + +#endif diff --git a/bip32.c b/bip32.c index 1d3ce8d19..d9b25eee3 100644 --- a/bip32.c +++ b/bip32.c @@ -29,6 +29,7 @@ #include "bip32.h" #include "sha2.h" #include "ripemd160.h" +#include "base58.h" void hdnode_from_xpub(uint32_t depth, uint32_t fingerprint, uint32_t child_num, uint8_t *chain_code, uint8_t *public_key, HDNode *out) { @@ -145,10 +146,7 @@ void hdnode_fill_public_key(HDNode *node) void hdnode_serialize(const HDNode *node, uint32_t version, char use_public, char *str) { - uint8_t node_data[82], a[32]; - int i,j; - uint32_t rem, tmp; - const char code[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; + uint8_t node_data[78]; write_be(node_data, version); node_data[4] = node->depth; write_be(node_data + 5, node->fingerprint); @@ -160,20 +158,7 @@ void hdnode_serialize(const HDNode *node, uint32_t version, char use_public, cha node_data[45] = 0; memcpy(node_data + 46, node->private_key, 32); } - sha256_Raw(node_data, 78, a); - sha256_Raw(a, 32, a); - memcpy(node_data + 78, a, 4); // checksum - for (j = 110; j >= 0; j--) { - rem = node_data[0] % 58; - node_data[0] /= 58; - for (i = 1; i < 82; i++) { - tmp = rem * 24 + node_data[i]; // 2^8 == 4*58 + 24 - node_data[i] = rem * 4 + (tmp / 58); - rem = tmp % 58; - } - str[j] = code[rem]; - } - str[111] = 0; + base58_encode_check(node_data, 78, str); } void hdnode_serialize_public(const HDNode *node, char *str) @@ -189,55 +174,22 @@ void hdnode_serialize_private(const HDNode *node, char *str) // check for validity of curve point in case of public data not performed int hdnode_deserialize(const char *str, HDNode *node) { - uint8_t node_data[82], a[32]; - const char decode[] = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, - 4, 5, 6, 7, 8, -1, -1, -1, -1, -1, -1, -1, 9, 10, 11, - 12, 13, 14, 15, 16, -1, 17, 18, 19, 20, 21, -1, 22, - 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, -1, -1, -1, - -1, -1, -1, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, - 43, -1, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, - 55, 56, 57 - }; + uint8_t node_data[78]; memset(node, 0, sizeof(HDNode)); - memset(node_data, 0, sizeof(node_data)); - if (strlen(str) != 111) { // invalid data length + if (!base58_decode_check(str, node_data)) { return -1; } - int i, j, k; - for (i = 0; i < 111; i++) { - if (str[i] < 0 || str[i] >= (int)sizeof(decode)) { // invalid character - return -2; - } - k = decode[(int)str[i]]; - if (k == -1) { // invalid character - return -2; - } - for (j = 81; j >= 0; j--) { - k += node_data[j] * 58; - node_data[j] = k & 0xFF; - k >>= 8; - } - } - sha256_Raw(node_data, 78, a); - sha256_Raw(a, 32, a); - if (memcmp(node_data + 78, a, 4)) { // wrong checksum - return -3; - } uint32_t version = read_be(node_data); if (version == 0x0488B21E) { // public node memcpy(node->public_key, node_data + 45, 33); } else if (version == 0x0488ADE4) { // private node if (node_data[45]) { // invalid data - return -4; + return -2; } memcpy(node->private_key, node_data + 46, 32); hdnode_fill_public_key(node); } else { - return -5; // invalid version + return -3; // invalid version } node->depth = node_data[4]; node->fingerprint = read_be(node_data + 5); From 5e9cd15527913160ac5d9bfa8b3501f506dec4d6 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 22 May 2014 22:25:08 +0200 Subject: [PATCH 098/627] use new base58 code for address functions, add function for obtaining wif --- base58.c | 21 +++++++++++---- ecdsa.c | 81 ++++++++++---------------------------------------------- ecdsa.h | 1 + tests.c | 23 ++++++++++++++++ 4 files changed, 54 insertions(+), 72 deletions(-) diff --git a/base58.c b/base58.c index aaefa3548..4ed2a3b31 100644 --- a/base58.c +++ b/base58.c @@ -32,8 +32,8 @@ int base58_encode_check(const uint8_t *data, int len, char *str) case 78: // xpub/xprv 78 outlen = 111; break; - case 34: // WIF privkey 1+32 - outlen = 51; + case 34: // WIF privkey 1+32+1 + outlen = 52; break; case 21: // address 1+20 outlen = 34; @@ -57,9 +57,20 @@ int base58_encode_check(const uint8_t *data, int len, char *str) mydata[i] = rem * 4 + (tmp / 58); rem = tmp % 58; } - str[outlen - 1 - j] = code[rem]; + str[j] = code[rem]; + } + // remove duplicite 1s at the end + while (outlen > 1 && str[outlen - 1] == code[0] && str[outlen - 2] == code[0]) { + outlen--; } str[outlen] = 0; + char s; + // reverse string + for (i = 0; i < outlen / 2; i++) { + s = str[i]; + str[i] = str[outlen - 1 - i]; + str[outlen - 1 - i] = s; + } return outlen; } @@ -83,8 +94,8 @@ int base58_decode_check(const char *str, uint8_t *data) case 111: // xpub/xprv outlen = 78; break; - case 51: // WIF privkey - outlen = 34; + case 52: // WIF privkey + outlen = 35; break; case 27: // address case 28: diff --git a/ecdsa.c b/ecdsa.c index e1dbbe86c..31128d122 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -31,6 +31,7 @@ #include "ripemd160.h" #include "hmac.h" #include "ecdsa.h" +#include "base58.h" // cp2 = cp1 + cp2 void point_add(const curve_point *cp1, curve_point *cp2) @@ -347,79 +348,25 @@ void ecdsa_get_pubkeyhash(const uint8_t *pub_key, uint8_t *pubkeyhash) void ecdsa_get_address(const uint8_t *pub_key, uint8_t version, char *addr) { - const char code[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; - char *p = addr, s; - uint8_t a[32], b[21]; - uint32_t r; - bignum256 c; - int i, l; - - b[0] = version; - ecdsa_get_pubkeyhash(pub_key, b + 1); - - sha256_Raw(b, 21, a); - sha256_Raw(a, 32, a); - - memcpy(a + 28, a, 4); // checksum - memset(a, 0, 7); // zeroes - memcpy(a + 7, b, 21); // version || ripemd160(sha256(pubkey)) - - bn_read_be(a, &c); - - while (!bn_is_zero(&c)) { - bn_divmod58(&c, &r); - *p = code[r]; - p++; - } - - i = 7; - while (a[i] == 0) { - *p = code[0]; - p++; i++; - } - - *p = 0; - - l = strlen(addr); + uint8_t data[21]; + data[0] = version; + ecdsa_get_pubkeyhash(pub_key, data + 1); + base58_encode_check(data, 21, addr); +} - for (i = 0; i < l / 2; i++) { - s = addr[i]; - addr[i] = addr[l - 1 - i]; - addr[l - 1 - i] = s; - } +void ecdsa_get_wif(const uint8_t *priv_key, uint8_t version, char *wif) +{ + uint8_t data[34]; + data[0] = version; + memcpy(data + 1, priv_key, 32); + data[33 ] = 0x01; + base58_encode_check(data, 34, wif); } int ecdsa_address_decode(const char *addr, uint8_t *out) { if (!addr) return 0; - const char code[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; - bignum256 num; - uint8_t buf[32], check[32]; - bn_zero(&num); - uint32_t k; - size_t i; - for (i = 0; i < strlen(addr); i++) { - bn_muli(&num, 58); - for (k = 0; k <= strlen(code); k++) { - if (code[k] == 0) { // char not found -> invalid address - return 0; - } - if (addr[i] == code[k]) { - bn_addi(&num, k); - break; - } - } - } - bn_write_be(&num, buf); - // compute address hash - sha256_Raw(buf + 7, 21, check); - sha256_Raw(check, 32, check); - // check if valid - if (memcmp(buf + 7 + 21, check, 4) != 0) { - return 0; - } - memcpy(out, buf + 7, 21); - return 1; + return base58_decode_check(addr, out) == 21; } void uncompress_coords(uint8_t odd, const bignum256 *x, bignum256 *y) diff --git a/ecdsa.h b/ecdsa.h index b7f59b350..3e2dede55 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -45,6 +45,7 @@ void ecdsa_get_public_key33(const uint8_t *priv_key, uint8_t *pub_key); void ecdsa_get_public_key65(const uint8_t *priv_key, uint8_t *pub_key); void ecdsa_get_pubkeyhash(const uint8_t *pub_key, uint8_t *pubkeyhash); void ecdsa_get_address(const uint8_t *pub_key, uint8_t version, char *addr); +void ecdsa_get_wif(const uint8_t *priv_key, uint8_t version, char *wif); int ecdsa_address_decode(const char *addr, uint8_t *out); int ecdsa_read_pubkey(const uint8_t *pub_key, curve_point *pub); int ecdsa_verify(const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, uint32_t msg_len); diff --git a/tests.c b/tests.c index 90c1df2d5..0ba3fac39 100644 --- a/tests.c +++ b/tests.c @@ -728,6 +728,25 @@ START_TEST(test_address) } END_TEST +START_TEST(test_wif) +{ + uint8_t priv_key[32]; + char wif[53]; + + memcpy(priv_key, fromhex("1111111111111111111111111111111111111111111111111111111111111111"), 32); + ecdsa_get_wif(priv_key, 0x80, wif); ck_assert_str_eq(wif, "KwntMbt59tTsj8xqpqYqRRWufyjGunvhSyeMo3NTYpFYzZbXJ5Hp"); + ecdsa_get_wif(priv_key, 0xEF, wif); ck_assert_str_eq(wif, "cN9spWsvaxA8taS7DFMxnk1yJD2gaF2PX1npuTpy3vuZFJdwavaw"); + + memcpy(priv_key, fromhex("dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"), 32); + ecdsa_get_wif(priv_key, 0x80, wif); ck_assert_str_eq(wif, "L4ezQvyC6QoBhxB4GVs9fAPhUKtbaXYUn8YTqoeXwbevQq4U92vN"); + ecdsa_get_wif(priv_key, 0xEF, wif); ck_assert_str_eq(wif, "cV1ysqy3XUVSsPeKeugH2Utm6ZC1EyeArAgvxE73SiJvfa6AJng7"); + + memcpy(priv_key, fromhex("47f7616ea6f9b923076625b4488115de1ef1187f760e65f89eb6f4f7ff04b012"), 32); + ecdsa_get_wif(priv_key, 0x80, wif); ck_assert_str_eq(wif, "KydbzBtk6uc7M6dXwEgTEH2sphZxSPbmDSz6kUUHi4eUpSQuhEbq"); + ecdsa_get_wif(priv_key, 0xEF, wif); ck_assert_str_eq(wif, "cPzbT6tbXyJNWY6oKeVabbXwSvsN6qhTHV8ZrtvoDBJV5BRY1G5Q"); +} +END_TEST + START_TEST(test_address_decode) { int res; @@ -867,6 +886,10 @@ Suite *test_suite(void) tcase_add_test(tc, test_address_decode); suite_add_tcase(s, tc); + tc = tcase_create("wif"); + tcase_add_test(tc, test_wif); + suite_add_tcase(s, tc); + tc = tcase_create("ecdsa_der"); tcase_add_test(tc, test_ecdsa_der); suite_add_tcase(s, tc); From 322c06bf7bc99d76b09295f03da191324e70bbbd Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 23 May 2014 01:44:24 +0200 Subject: [PATCH 099/627] add simple gui qt utility --- gui/.gitignore | 1 + gui/gui.pro | 11 +++++ gui/main.cpp | 10 ++++ gui/mainwindow.cpp | 66 +++++++++++++++++++++++++ gui/mainwindow.h | 27 ++++++++++ gui/mainwindow.ui | 121 +++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 236 insertions(+) create mode 100644 gui/.gitignore create mode 100644 gui/gui.pro create mode 100644 gui/main.cpp create mode 100644 gui/mainwindow.cpp create mode 100644 gui/mainwindow.h create mode 100644 gui/mainwindow.ui diff --git a/gui/.gitignore b/gui/.gitignore new file mode 100644 index 000000000..f995622d5 --- /dev/null +++ b/gui/.gitignore @@ -0,0 +1 @@ +gui.pro.user diff --git a/gui/gui.pro b/gui/gui.pro new file mode 100644 index 000000000..9b9c73af9 --- /dev/null +++ b/gui/gui.pro @@ -0,0 +1,11 @@ +QT += core gui +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +TARGET = gui +TEMPLATE = app + +SOURCES += ../bip32.c ../bip39.c ../sha2.c ../pbkdf2.c ../hmac.c ../rand.c ../bignum.c ../ecdsa.c ../ripemd160.c ../base58.c ../secp256k1.c mainwindow.cpp main.cpp + +HEADERS += mainwindow.h ../bip32.h ../bip39.h + +FORMS += mainwindow.ui diff --git a/gui/main.cpp b/gui/main.cpp new file mode 100644 index 000000000..115a22bf7 --- /dev/null +++ b/gui/main.cpp @@ -0,0 +1,10 @@ +#include "mainwindow.h" +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + MainWindow w; + w.show(); + return a.exec(); +} diff --git a/gui/mainwindow.cpp b/gui/mainwindow.cpp new file mode 100644 index 000000000..1e88b2f35 --- /dev/null +++ b/gui/mainwindow.cpp @@ -0,0 +1,66 @@ +#include +#include "mainwindow.h" +#include "ui_mainwindow.h" +extern "C" { +#include "../bip32.h" +#include "../bip39.h" +#include "../ecdsa.h" +} + +HDNode root; + +MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) +{ + ui->setupUi(this); + for (int i = 0; i < 100; i++) { + ui->listAddress->insertRow(i); + ui->listChange->insertRow(i); + + } +} + +MainWindow::~MainWindow() +{ + delete ui; +} + +// abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about + +void MainWindow::on_buttonLoad_clicked() +{ + ui->listAccount->clear(); + if (!mnemonic_check(ui->editMnemonic->text().toLocal8Bit().data())) { + QMessageBox::critical(this, "Error", "Text is not a valid BIP39 mnemonic.", QMessageBox::Ok); + return; + } + uint8_t seed[64]; + mnemonic_to_seed(ui->editMnemonic->text().toLocal8Bit().data(), ui->editPassphrase->text().toLocal8Bit().data(), seed, 0); + hdnode_from_seed(seed, 64, &root); + for (int i = 1; i <= 10; i++) { + ui->listAccount->addItem(QString("Account #") + QString::number(i)); + } +} + +void MainWindow::on_listAccount_clicked(const QModelIndex &index) +{ + const char addr_version = 0x00, wif_version = 0x80; + char buf[64]; + HDNode node; + // external chain + for (int chain = 0; chain < 2; chain++) { + QTableWidget *list = chain == 0 ? ui->listAddress : ui->listChange; + node = root; + hdnode_private_ckd(&node, 44 | 0x80000000); + hdnode_private_ckd(&node, index.row() | 0x80000000); + hdnode_private_ckd(&node, chain); // external / internal + for (int i = 0; i < 100; i++) { + HDNode node2 = node; + hdnode_private_ckd(&node2, i); + ecdsa_get_address(node2.public_key, addr_version, buf); QString address = QString(buf); + ecdsa_get_wif(node2.private_key, wif_version, buf); QString wif = QString(buf); + list->setItem(i, 0, new QTableWidgetItem(address)); + list->setItem(i, 1, new QTableWidgetItem(wif)); + list->setItem(i, 2, new QTableWidgetItem("0.0")); + } + } +} diff --git a/gui/mainwindow.h b/gui/mainwindow.h new file mode 100644 index 000000000..ef7dc1b4d --- /dev/null +++ b/gui/mainwindow.h @@ -0,0 +1,27 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include +#include + +namespace Ui { +class MainWindow; +} + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit MainWindow(QWidget *parent = 0); + ~MainWindow(); + +private slots: + void on_buttonLoad_clicked(); + void on_listAccount_clicked(const QModelIndex &index); + +private: + Ui::MainWindow *ui; +}; + +#endif // MAINWINDOW_H diff --git a/gui/mainwindow.ui b/gui/mainwindow.ui new file mode 100644 index 000000000..1b1782b6f --- /dev/null +++ b/gui/mainwindow.ui @@ -0,0 +1,121 @@ + + + MainWindow + + + + 0 + 0 + 800 + 600 + + + + + DejaVu Sans Mono + + + + TREZOR + + + + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + + 120 + 16777215 + + + + Load + + + + + + + + 0 + 0 + + + + + 140 + 16777215 + + + + + + + + + address + + + + + private key + + + + + balance + + + + + + + + + address + + + + + private key + + + + + balance + + + + + + + + + + editMnemonic + buttonLoad + listAccount + listAddress + + + + From 99900eb3232fc75546d749cfad863741dc2fdb7f Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 7 Jun 2014 13:38:56 +0200 Subject: [PATCH 100/627] update AES code to support different modes of operation, add unittests --- Makefile | 8 +- aes.h | 230 ++++++++--- aes_modes.c | 947 +++++++++++++++++++++++++++++++++++++++++++ aescrypt.c | 504 +++++++++-------------- aeskey.c | 733 +++++++++++++++++++++------------- aesopt.h | 1087 +++++++++++++++++++++++--------------------------- aestab.c | 685 ++++++++++++++----------------- aestab.h | 173 ++++++++ bip39.c | 4 +- bip39.h | 2 + brg_endian.h | 126 ++++++ brg_types.h | 191 +++++++++ tests.c | 176 +++++++- 13 files changed, 3217 insertions(+), 1649 deletions(-) create mode 100644 aes_modes.c create mode 100644 aestab.h create mode 100644 brg_endian.h create mode 100644 brg_types.h diff --git a/Makefile b/Makefile index d2f9e61dd..60e9f4a8d 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,9 @@ CC = gcc -CFLAGS = -Wall -Wextra -Os -OBJS = bignum.o ecdsa.o secp256k1.o sha2.o rand.o hmac.o bip32.o ripemd160.o bip39.o pbkdf2.o base58.o -OBJS += aescrypt.o aeskey.o aestab.o +CFLAGS = -Wall -Wextra -Os -Wno-sequence-point +OBJS = bignum.o ecdsa.o secp256k1.o rand.o hmac.o bip32.o bip39.o pbkdf2.o base58.o +OBJS += ripemd160.o +OBJS += sha2.o +OBJS += aescrypt.o aeskey.o aestab.o aes_modes.o all: tests test-openssl diff --git a/aes.h b/aes.h index 687d7ad3a..f56c1b88a 100644 --- a/aes.h +++ b/aes.h @@ -1,100 +1,200 @@ /* - ------------------------------------------------------------------------- - Copyright (c) 2001, Dr Brian Gladman < >, Worcester, UK. - All rights reserved. +--------------------------------------------------------------------------- +Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved. - LICENSE TERMS +The redistribution and use of this software (with or without changes) +is allowed without the payment of fees or royalties provided that: - The free distribution and use of this software in both source and binary - form is allowed (with or without changes) provided that: + source code distributions include the above copyright notice, this + list of conditions and the following disclaimer; - 1. distributions of this source code include the above copyright - notice, this list of conditions and the following disclaimer; + binary distributions include the above copyright notice, this list + of conditions and the following disclaimer in their documentation. - 2. distributions in binary form include the above copyright - notice, this list of conditions and the following disclaimer - in the documentation and/or other associated materials; +This software is provided 'as is' with no explicit or implied warranties +in respect of its operation, including, but not limited to, correctness +and fitness for purpose. +--------------------------------------------------------------------------- +Issue Date: 20/12/2007 - 3. the copyright holder's name is not used to endorse products - built using this software without specific written permission. - - DISCLAIMER - - This software is provided 'as is' with no explicit or implied warranties - in respect of its properties, including, but not limited to, correctness - and fitness for purpose. - ------------------------------------------------------------------------- - Issue Date: 29/07/2002 - - This file contains the definitions required to use AES (Rijndael) in C. + This file contains the definitions required to use AES in C. See aesopt.h + for optimisation details. */ #ifndef _AES_H #define _AES_H -/* This include is used only to find 8 and 32 bit unsigned integer types */ +#include -#include "limits.h" +/* This include is used to find 8 & 32 bit unsigned integer types */ +#include "brg_types.h" -#if UCHAR_MAX == 0xff /* an unsigned 8 bit type for internal AES use */ - typedef unsigned char aes_08t; -#else -#error Please define an unsigned 8 bit type in aes.h +#if defined(__cplusplus) +extern "C" +{ #endif -#if UINT_MAX == 0xffffffff /* an unsigned 32 bit type for internal AES use */ - typedef unsigned int aes_32t; -#elif ULONG_MAX == 0xffffffff - typedef unsigned long aes_32t; +// #define AES_128 /* if a fast 128 bit key scheduler is needed */ +// #define AES_192 /* if a fast 192 bit key scheduler is needed */ +#define AES_256 /* if a fast 256 bit key scheduler is needed */ +// #define AES_VAR /* if variable key size scheduler is needed */ +#define AES_MODES /* if support is needed for modes */ + +/* The following must also be set in assembler files if being used */ + +#define AES_ENCRYPT /* if support for encryption is needed */ +#define AES_DECRYPT /* if support for decryption is needed */ + +#define AES_BLOCK_SIZE 16 /* the AES block size in bytes */ +#define N_COLS 4 /* the number of columns in the state */ + +/* The key schedule length is 11, 13 or 15 16-byte blocks for 128, */ +/* 192 or 256-bit keys respectively. That is 176, 208 or 240 bytes */ +/* or 44, 52 or 60 32-bit words. */ + +#if defined( AES_VAR ) || defined( AES_256 ) +#define KS_LENGTH 60 +#elif defined( AES_192 ) +#define KS_LENGTH 52 #else -#error Please define an unsigned 32 bit type in aes.h +#define KS_LENGTH 44 #endif -/* BLOCK_SIZE is in BYTES: 16, 24, 32 or undefined for aes.c and 16, 20, - 24, 28, 32 or undefined for aespp.c. When left undefined a slower - version that provides variable block length is compiled. -*/ +#define AES_RETURN INT_RETURN -#define BLOCK_SIZE 16 +/* the character array 'inf' in the following structures is used */ +/* to hold AES context information. This AES code uses cx->inf.b[0] */ +/* to hold the number of rounds multiplied by 16. The other three */ +/* elements can be used by code that implements additional modes */ -/* key schedule length (in 32-bit words) */ +typedef union +{ uint32_t l; + uint8_t b[4]; +} aes_inf; -#if !defined(BLOCK_SIZE) -#define KS_LENGTH 128 -#else -#define KS_LENGTH 4 * BLOCK_SIZE +#ifdef _WIN64 +__declspec(align(16)) +#endif +typedef struct +{ uint32_t ks[KS_LENGTH]; + aes_inf inf; +} aes_encrypt_ctx; + +#ifdef _WIN64 +__declspec(align(16)) +#endif +typedef struct +{ uint32_t ks[KS_LENGTH]; + aes_inf inf; +} aes_decrypt_ctx; + +/* This routine must be called before first use if non-static */ +/* tables are being used */ + +AES_RETURN aes_init(void); + +/* Key lengths in the range 16 <= key_len <= 32 are given in bytes, */ +/* those in the range 128 <= key_len <= 256 are given in bits */ + +#if defined( AES_ENCRYPT ) + +#if defined( AES_128 ) || defined( AES_VAR) +AES_RETURN aes_encrypt_key128(const unsigned char *key, aes_encrypt_ctx cx[1]); #endif -#if defined(__cplusplus) -extern "C" -{ +#if defined( AES_192 ) || defined( AES_VAR) +AES_RETURN aes_encrypt_key192(const unsigned char *key, aes_encrypt_ctx cx[1]); #endif -typedef unsigned int aes_fret; /* type for function return value */ -#define aes_bad 0 /* bad function return value */ -#define aes_good 1 /* good function return value */ -#ifndef AES_DLL /* implement normal or DLL functions */ -#define aes_rval aes_fret -#else -#define aes_rval aes_fret __declspec(dllexport) _stdcall +#if defined( AES_256 ) || defined( AES_VAR) +AES_RETURN aes_encrypt_key256(const unsigned char *key, aes_encrypt_ctx cx[1]); +#endif + +#if defined( AES_VAR ) +AES_RETURN aes_encrypt_key(const unsigned char *key, int key_len, aes_encrypt_ctx cx[1]); #endif +AES_RETURN aes_encrypt(const unsigned char *in, unsigned char *out, const aes_encrypt_ctx cx[1]); -typedef struct /* the AES context for encryption */ -{ aes_32t k_sch[KS_LENGTH]; /* the encryption key schedule */ - aes_32t n_rnd; /* the number of cipher rounds */ - aes_32t n_blk; /* the number of bytes in the state */ -} aes_ctx; +#endif + +#if defined( AES_DECRYPT ) + +#if defined( AES_128 ) || defined( AES_VAR) +AES_RETURN aes_decrypt_key128(const unsigned char *key, aes_decrypt_ctx cx[1]); +#endif -#if !defined(BLOCK_SIZE) -aes_rval aes_blk_len(unsigned int blen, aes_ctx cx[1]); +#if defined( AES_192 ) || defined( AES_VAR) +AES_RETURN aes_decrypt_key192(const unsigned char *key, aes_decrypt_ctx cx[1]); #endif -aes_rval aes_enc_key(const unsigned char in_key[], unsigned int klen, aes_ctx cx[1]); -aes_rval aes_enc_blk(const unsigned char in_blk[], unsigned char out_blk[], const aes_ctx cx[1]); +#if defined( AES_256 ) || defined( AES_VAR) +AES_RETURN aes_decrypt_key256(const unsigned char *key, aes_decrypt_ctx cx[1]); +#endif + +#if defined( AES_VAR ) +AES_RETURN aes_decrypt_key(const unsigned char *key, int key_len, aes_decrypt_ctx cx[1]); +#endif + +AES_RETURN aes_decrypt(const unsigned char *in, unsigned char *out, const aes_decrypt_ctx cx[1]); + +#endif + +#if defined( AES_MODES ) + +/* Multiple calls to the following subroutines for multiple block */ +/* ECB, CBC, CFB, OFB and CTR mode encryption can be used to handle */ +/* long messages incrementally provided that the context AND the iv */ +/* are preserved between all such calls. For the ECB and CBC modes */ +/* each individual call within a series of incremental calls must */ +/* process only full blocks (i.e. len must be a multiple of 16) but */ +/* the CFB, OFB and CTR mode calls can handle multiple incremental */ +/* calls of any length. Each mode is reset when a new AES key is */ +/* set but ECB and CBC operations can be reset without setting a */ +/* new key by setting a new IV value. To reset CFB, OFB and CTR */ +/* without setting the key, aes_mode_reset() must be called and the */ +/* IV must be set. NOTE: All these calls update the IV on exit so */ +/* this has to be reset if a new operation with the same IV as the */ +/* previous one is required (or decryption follows encryption with */ +/* the same IV array). */ + +AES_RETURN aes_test_alignment_detection(unsigned int n); -aes_rval aes_dec_key(const unsigned char in_key[], unsigned int klen, aes_ctx cx[1]); -aes_rval aes_dec_blk(const unsigned char in_blk[], unsigned char out_blk[], const aes_ctx cx[1]); +AES_RETURN aes_ecb_encrypt(const unsigned char *ibuf, unsigned char *obuf, + int len, const aes_encrypt_ctx cx[1]); + +AES_RETURN aes_ecb_decrypt(const unsigned char *ibuf, unsigned char *obuf, + int len, const aes_decrypt_ctx cx[1]); + +AES_RETURN aes_cbc_encrypt(const unsigned char *ibuf, unsigned char *obuf, + int len, unsigned char *iv, const aes_encrypt_ctx cx[1]); + +AES_RETURN aes_cbc_decrypt(const unsigned char *ibuf, unsigned char *obuf, + int len, unsigned char *iv, const aes_decrypt_ctx cx[1]); + +AES_RETURN aes_mode_reset(aes_encrypt_ctx cx[1]); + +AES_RETURN aes_cfb_encrypt(const unsigned char *ibuf, unsigned char *obuf, + int len, unsigned char *iv, aes_encrypt_ctx cx[1]); + +AES_RETURN aes_cfb_decrypt(const unsigned char *ibuf, unsigned char *obuf, + int len, unsigned char *iv, aes_encrypt_ctx cx[1]); + +#define aes_ofb_encrypt aes_ofb_crypt +#define aes_ofb_decrypt aes_ofb_crypt + +AES_RETURN aes_ofb_crypt(const unsigned char *ibuf, unsigned char *obuf, + int len, unsigned char *iv, aes_encrypt_ctx cx[1]); + +typedef void cbuf_inc(unsigned char *cbuf); + +#define aes_ctr_encrypt aes_ctr_crypt +#define aes_ctr_decrypt aes_ctr_crypt + +AES_RETURN aes_ctr_crypt(const unsigned char *ibuf, unsigned char *obuf, + int len, unsigned char *cbuf, cbuf_inc ctr_inc, aes_encrypt_ctx cx[1]); + +#endif #if defined(__cplusplus) } diff --git a/aes_modes.c b/aes_modes.c new file mode 100644 index 000000000..a6e37ed80 --- /dev/null +++ b/aes_modes.c @@ -0,0 +1,947 @@ +/* +--------------------------------------------------------------------------- +Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved. + +The redistribution and use of this software (with or without changes) +is allowed without the payment of fees or royalties provided that: + + source code distributions include the above copyright notice, this + list of conditions and the following disclaimer; + + binary distributions include the above copyright notice, this list + of conditions and the following disclaimer in their documentation. + +This software is provided 'as is' with no explicit or implied warranties +in respect of its operation, including, but not limited to, correctness +and fitness for purpose. +--------------------------------------------------------------------------- +Issue Date: 20/12/2007 + + These subroutines implement multiple block AES modes for ECB, CBC, CFB, + OFB and CTR encryption, The code provides support for the VIA Advanced + Cryptography Engine (ACE). + + NOTE: In the following subroutines, the AES contexts (ctx) must be + 16 byte aligned if VIA ACE is being used +*/ + +#include +#include +#include + +#include "aesopt.h" + +#if defined( AES_MODES ) +#if defined(__cplusplus) +extern "C" +{ +#endif + +#if defined( _MSC_VER ) && ( _MSC_VER > 800 ) +#pragma intrinsic(memcpy) +#endif + +#define BFR_BLOCKS 8 + +/* These values are used to detect long word alignment in order to */ +/* speed up some buffer operations. This facility may not work on */ +/* some machines so this define can be commented out if necessary */ + +#define FAST_BUFFER_OPERATIONS + +#define lp32(x) ((uint32_t*)(x)) + +#if defined( USE_VIA_ACE_IF_PRESENT ) + +#include "aes_via_ace.h" + +#pragma pack(16) + +aligned_array(unsigned long, enc_gen_table, 12, 16) = NEH_ENC_GEN_DATA; +aligned_array(unsigned long, enc_load_table, 12, 16) = NEH_ENC_LOAD_DATA; +aligned_array(unsigned long, enc_hybrid_table, 12, 16) = NEH_ENC_HYBRID_DATA; +aligned_array(unsigned long, dec_gen_table, 12, 16) = NEH_DEC_GEN_DATA; +aligned_array(unsigned long, dec_load_table, 12, 16) = NEH_DEC_LOAD_DATA; +aligned_array(unsigned long, dec_hybrid_table, 12, 16) = NEH_DEC_HYBRID_DATA; + +/* NOTE: These control word macros must only be used after */ +/* a key has been set up because they depend on key size */ +/* See the VIA ACE documentation for key type information */ +/* and aes_via_ace.h for non-default NEH_KEY_TYPE values */ + +#ifndef NEH_KEY_TYPE +# define NEH_KEY_TYPE NEH_HYBRID +#endif + +#if NEH_KEY_TYPE == NEH_LOAD +#define kd_adr(c) ((uint8_t*)(c)->ks) +#elif NEH_KEY_TYPE == NEH_GENERATE +#define kd_adr(c) ((uint8_t*)(c)->ks + (c)->inf.b[0]) +#elif NEH_KEY_TYPE == NEH_HYBRID +#define kd_adr(c) ((uint8_t*)(c)->ks + ((c)->inf.b[0] == 160 ? 160 : 0)) +#else +#error no key type defined for VIA ACE +#endif + +#else + +#define aligned_array(type, name, no, stride) type name[no] +#define aligned_auto(type, name, no, stride) type name[no] + +#endif + +#if defined( _MSC_VER ) && _MSC_VER > 1200 + +#define via_cwd(cwd, ty, dir, len) \ + unsigned long* cwd = (dir##_##ty##_table + ((len - 128) >> 4)) + +#else + +#define via_cwd(cwd, ty, dir, len) \ + aligned_auto(unsigned long, cwd, 4, 16); \ + cwd[1] = cwd[2] = cwd[3] = 0; \ + cwd[0] = neh_##dir##_##ty##_key(len) + +#endif + +/* test the code for detecting and setting pointer alignment */ + +AES_RETURN aes_test_alignment_detection(unsigned int n) /* 4 <= n <= 16 */ +{ uint8_t p[16]; + uint32_t i, count_eq = 0, count_neq = 0; + + if(n < 4 || n > 16) + return EXIT_FAILURE; + + for(i = 0; i < n; ++i) + { + uint8_t *qf = ALIGN_FLOOR(p + i, n), + *qh = ALIGN_CEIL(p + i, n); + + if(qh == qf) + ++count_eq; + else if(qh == qf + n) + ++count_neq; + else + return EXIT_FAILURE; + } + return (count_eq != 1 || count_neq != n - 1 ? EXIT_FAILURE : EXIT_SUCCESS); +} + +AES_RETURN aes_mode_reset(aes_encrypt_ctx ctx[1]) +{ + ctx->inf.b[2] = 0; + return EXIT_SUCCESS; +} + +AES_RETURN aes_ecb_encrypt(const unsigned char *ibuf, unsigned char *obuf, + int len, const aes_encrypt_ctx ctx[1]) +{ int nb = len >> 4; + + if(len & (AES_BLOCK_SIZE - 1)) + return EXIT_FAILURE; + +#if defined( USE_VIA_ACE_IF_PRESENT ) + + if(ctx->inf.b[1] == 0xff) + { uint8_t *ksp = (uint8_t*)(ctx->ks); + via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192); + + if(ALIGN_OFFSET( ctx, 16 )) + return EXIT_FAILURE; + + if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 )) + { + via_ecb_op5(ksp, cwd, ibuf, obuf, nb); + } + else + { aligned_auto(uint8_t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16); + uint8_t *ip, *op; + + while(nb) + { + int m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb); + + ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf); + op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf); + + if(ip != ibuf) + memcpy(buf, ibuf, m * AES_BLOCK_SIZE); + + via_ecb_op5(ksp, cwd, ip, op, m); + + if(op != obuf) + memcpy(obuf, buf, m * AES_BLOCK_SIZE); + + ibuf += m * AES_BLOCK_SIZE; + obuf += m * AES_BLOCK_SIZE; + nb -= m; + } + } + + return EXIT_SUCCESS; + } + +#endif + +#if !defined( ASSUME_VIA_ACE_PRESENT ) + while(nb--) + { + if(aes_encrypt(ibuf, obuf, ctx) != EXIT_SUCCESS) + return EXIT_FAILURE; + ibuf += AES_BLOCK_SIZE; + obuf += AES_BLOCK_SIZE; + } +#endif + return EXIT_SUCCESS; +} + +AES_RETURN aes_ecb_decrypt(const unsigned char *ibuf, unsigned char *obuf, + int len, const aes_decrypt_ctx ctx[1]) +{ int nb = len >> 4; + + if(len & (AES_BLOCK_SIZE - 1)) + return EXIT_FAILURE; + +#if defined( USE_VIA_ACE_IF_PRESENT ) + + if(ctx->inf.b[1] == 0xff) + { uint8_t *ksp = kd_adr(ctx); + via_cwd(cwd, hybrid, dec, 2 * ctx->inf.b[0] - 192); + + if(ALIGN_OFFSET( ctx, 16 )) + return EXIT_FAILURE; + + if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 )) + { + via_ecb_op5(ksp, cwd, ibuf, obuf, nb); + } + else + { aligned_auto(uint8_t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16); + uint8_t *ip, *op; + + while(nb) + { + int m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb); + + ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf); + op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf); + + if(ip != ibuf) + memcpy(buf, ibuf, m * AES_BLOCK_SIZE); + + via_ecb_op5(ksp, cwd, ip, op, m); + + if(op != obuf) + memcpy(obuf, buf, m * AES_BLOCK_SIZE); + + ibuf += m * AES_BLOCK_SIZE; + obuf += m * AES_BLOCK_SIZE; + nb -= m; + } + } + + return EXIT_SUCCESS; + } + +#endif + +#if !defined( ASSUME_VIA_ACE_PRESENT ) + while(nb--) + { + if(aes_decrypt(ibuf, obuf, ctx) != EXIT_SUCCESS) + return EXIT_FAILURE; + ibuf += AES_BLOCK_SIZE; + obuf += AES_BLOCK_SIZE; + } +#endif + return EXIT_SUCCESS; +} + +AES_RETURN aes_cbc_encrypt(const unsigned char *ibuf, unsigned char *obuf, + int len, unsigned char *iv, const aes_encrypt_ctx ctx[1]) +{ int nb = len >> 4; + + if(len & (AES_BLOCK_SIZE - 1)) + return EXIT_FAILURE; + +#if defined( USE_VIA_ACE_IF_PRESENT ) + + if(ctx->inf.b[1] == 0xff) + { uint8_t *ksp = (uint8_t*)(ctx->ks), *ivp = iv; + aligned_auto(uint8_t, liv, AES_BLOCK_SIZE, 16); + via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192); + + if(ALIGN_OFFSET( ctx, 16 )) + return EXIT_FAILURE; + + if(ALIGN_OFFSET( iv, 16 )) /* ensure an aligned iv */ + { + ivp = liv; + memcpy(liv, iv, AES_BLOCK_SIZE); + } + + if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 ) && !ALIGN_OFFSET( iv, 16 )) + { + via_cbc_op7(ksp, cwd, ibuf, obuf, nb, ivp, ivp); + } + else + { aligned_auto(uint8_t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16); + uint8_t *ip, *op; + + while(nb) + { + int m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb); + + ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf); + op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf); + + if(ip != ibuf) + memcpy(buf, ibuf, m * AES_BLOCK_SIZE); + + via_cbc_op7(ksp, cwd, ip, op, m, ivp, ivp); + + if(op != obuf) + memcpy(obuf, buf, m * AES_BLOCK_SIZE); + + ibuf += m * AES_BLOCK_SIZE; + obuf += m * AES_BLOCK_SIZE; + nb -= m; + } + } + + if(iv != ivp) + memcpy(iv, ivp, AES_BLOCK_SIZE); + + return EXIT_SUCCESS; + } + +#endif + +#if !defined( ASSUME_VIA_ACE_PRESENT ) +# ifdef FAST_BUFFER_OPERATIONS + if(!ALIGN_OFFSET( ibuf, 4 ) && !ALIGN_OFFSET( iv, 4 )) + while(nb--) + { + lp32(iv)[0] ^= lp32(ibuf)[0]; + lp32(iv)[1] ^= lp32(ibuf)[1]; + lp32(iv)[2] ^= lp32(ibuf)[2]; + lp32(iv)[3] ^= lp32(ibuf)[3]; + if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) + return EXIT_FAILURE; + memcpy(obuf, iv, AES_BLOCK_SIZE); + ibuf += AES_BLOCK_SIZE; + obuf += AES_BLOCK_SIZE; + } + else +# endif + while(nb--) + { + iv[ 0] ^= ibuf[ 0]; iv[ 1] ^= ibuf[ 1]; + iv[ 2] ^= ibuf[ 2]; iv[ 3] ^= ibuf[ 3]; + iv[ 4] ^= ibuf[ 4]; iv[ 5] ^= ibuf[ 5]; + iv[ 6] ^= ibuf[ 6]; iv[ 7] ^= ibuf[ 7]; + iv[ 8] ^= ibuf[ 8]; iv[ 9] ^= ibuf[ 9]; + iv[10] ^= ibuf[10]; iv[11] ^= ibuf[11]; + iv[12] ^= ibuf[12]; iv[13] ^= ibuf[13]; + iv[14] ^= ibuf[14]; iv[15] ^= ibuf[15]; + if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) + return EXIT_FAILURE; + memcpy(obuf, iv, AES_BLOCK_SIZE); + ibuf += AES_BLOCK_SIZE; + obuf += AES_BLOCK_SIZE; + } +#endif + return EXIT_SUCCESS; +} + +AES_RETURN aes_cbc_decrypt(const unsigned char *ibuf, unsigned char *obuf, + int len, unsigned char *iv, const aes_decrypt_ctx ctx[1]) +{ unsigned char tmp[AES_BLOCK_SIZE]; + int nb = len >> 4; + + if(len & (AES_BLOCK_SIZE - 1)) + return EXIT_FAILURE; + +#if defined( USE_VIA_ACE_IF_PRESENT ) + + if(ctx->inf.b[1] == 0xff) + { uint8_t *ksp = kd_adr(ctx), *ivp = iv; + aligned_auto(uint8_t, liv, AES_BLOCK_SIZE, 16); + via_cwd(cwd, hybrid, dec, 2 * ctx->inf.b[0] - 192); + + if(ALIGN_OFFSET( ctx, 16 )) + return EXIT_FAILURE; + + if(ALIGN_OFFSET( iv, 16 )) /* ensure an aligned iv */ + { + ivp = liv; + memcpy(liv, iv, AES_BLOCK_SIZE); + } + + if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 ) && !ALIGN_OFFSET( iv, 16 )) + { + via_cbc_op6(ksp, cwd, ibuf, obuf, nb, ivp); + } + else + { aligned_auto(uint8_t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16); + uint8_t *ip, *op; + + while(nb) + { + int m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb); + + ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf); + op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf); + + if(ip != ibuf) + memcpy(buf, ibuf, m * AES_BLOCK_SIZE); + + via_cbc_op6(ksp, cwd, ip, op, m, ivp); + + if(op != obuf) + memcpy(obuf, buf, m * AES_BLOCK_SIZE); + + ibuf += m * AES_BLOCK_SIZE; + obuf += m * AES_BLOCK_SIZE; + nb -= m; + } + } + + if(iv != ivp) + memcpy(iv, ivp, AES_BLOCK_SIZE); + + return EXIT_SUCCESS; + } +#endif + +#if !defined( ASSUME_VIA_ACE_PRESENT ) +# ifdef FAST_BUFFER_OPERATIONS + if(!ALIGN_OFFSET( obuf, 4 ) && !ALIGN_OFFSET( iv, 4 )) + while(nb--) + { + memcpy(tmp, ibuf, AES_BLOCK_SIZE); + if(aes_decrypt(ibuf, obuf, ctx) != EXIT_SUCCESS) + return EXIT_FAILURE; + lp32(obuf)[0] ^= lp32(iv)[0]; + lp32(obuf)[1] ^= lp32(iv)[1]; + lp32(obuf)[2] ^= lp32(iv)[2]; + lp32(obuf)[3] ^= lp32(iv)[3]; + memcpy(iv, tmp, AES_BLOCK_SIZE); + ibuf += AES_BLOCK_SIZE; + obuf += AES_BLOCK_SIZE; + } + else +# endif + while(nb--) + { + memcpy(tmp, ibuf, AES_BLOCK_SIZE); + if(aes_decrypt(ibuf, obuf, ctx) != EXIT_SUCCESS) + return EXIT_FAILURE; + obuf[ 0] ^= iv[ 0]; obuf[ 1] ^= iv[ 1]; + obuf[ 2] ^= iv[ 2]; obuf[ 3] ^= iv[ 3]; + obuf[ 4] ^= iv[ 4]; obuf[ 5] ^= iv[ 5]; + obuf[ 6] ^= iv[ 6]; obuf[ 7] ^= iv[ 7]; + obuf[ 8] ^= iv[ 8]; obuf[ 9] ^= iv[ 9]; + obuf[10] ^= iv[10]; obuf[11] ^= iv[11]; + obuf[12] ^= iv[12]; obuf[13] ^= iv[13]; + obuf[14] ^= iv[14]; obuf[15] ^= iv[15]; + memcpy(iv, tmp, AES_BLOCK_SIZE); + ibuf += AES_BLOCK_SIZE; + obuf += AES_BLOCK_SIZE; + } +#endif + return EXIT_SUCCESS; +} + +AES_RETURN aes_cfb_encrypt(const unsigned char *ibuf, unsigned char *obuf, + int len, unsigned char *iv, aes_encrypt_ctx ctx[1]) +{ int cnt = 0, b_pos = (int)ctx->inf.b[2], nb; + + if(b_pos) /* complete any partial block */ + { + while(b_pos < AES_BLOCK_SIZE && cnt < len) + { + *obuf++ = (iv[b_pos++] ^= *ibuf++); + cnt++; + } + + b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos); + } + + if((nb = (len - cnt) >> 4) != 0) /* process whole blocks */ + { +#if defined( USE_VIA_ACE_IF_PRESENT ) + + if(ctx->inf.b[1] == 0xff) + { int m; + uint8_t *ksp = (uint8_t*)(ctx->ks), *ivp = iv; + aligned_auto(uint8_t, liv, AES_BLOCK_SIZE, 16); + via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192); + + if(ALIGN_OFFSET( ctx, 16 )) + return EXIT_FAILURE; + + if(ALIGN_OFFSET( iv, 16 )) /* ensure an aligned iv */ + { + ivp = liv; + memcpy(liv, iv, AES_BLOCK_SIZE); + } + + if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 )) + { + via_cfb_op7(ksp, cwd, ibuf, obuf, nb, ivp, ivp); + ibuf += nb * AES_BLOCK_SIZE; + obuf += nb * AES_BLOCK_SIZE; + cnt += nb * AES_BLOCK_SIZE; + } + else /* input, output or both are unaligned */ + { aligned_auto(uint8_t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16); + uint8_t *ip, *op; + + while(nb) + { + m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb), nb -= m; + + ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf); + op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf); + + if(ip != ibuf) + memcpy(buf, ibuf, m * AES_BLOCK_SIZE); + + via_cfb_op7(ksp, cwd, ip, op, m, ivp, ivp); + + if(op != obuf) + memcpy(obuf, buf, m * AES_BLOCK_SIZE); + + ibuf += m * AES_BLOCK_SIZE; + obuf += m * AES_BLOCK_SIZE; + cnt += m * AES_BLOCK_SIZE; + } + } + + if(ivp != iv) + memcpy(iv, ivp, AES_BLOCK_SIZE); + } +#else +# ifdef FAST_BUFFER_OPERATIONS + if(!ALIGN_OFFSET( ibuf, 4 ) && !ALIGN_OFFSET( obuf, 4 ) && !ALIGN_OFFSET( iv, 4 )) + while(cnt + AES_BLOCK_SIZE <= len) + { + assert(b_pos == 0); + if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) + return EXIT_FAILURE; + lp32(obuf)[0] = lp32(iv)[0] ^= lp32(ibuf)[0]; + lp32(obuf)[1] = lp32(iv)[1] ^= lp32(ibuf)[1]; + lp32(obuf)[2] = lp32(iv)[2] ^= lp32(ibuf)[2]; + lp32(obuf)[3] = lp32(iv)[3] ^= lp32(ibuf)[3]; + ibuf += AES_BLOCK_SIZE; + obuf += AES_BLOCK_SIZE; + cnt += AES_BLOCK_SIZE; + } + else +# endif + while(cnt + AES_BLOCK_SIZE <= len) + { + assert(b_pos == 0); + if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) + return EXIT_FAILURE; + obuf[ 0] = iv[ 0] ^= ibuf[ 0]; obuf[ 1] = iv[ 1] ^= ibuf[ 1]; + obuf[ 2] = iv[ 2] ^= ibuf[ 2]; obuf[ 3] = iv[ 3] ^= ibuf[ 3]; + obuf[ 4] = iv[ 4] ^= ibuf[ 4]; obuf[ 5] = iv[ 5] ^= ibuf[ 5]; + obuf[ 6] = iv[ 6] ^= ibuf[ 6]; obuf[ 7] = iv[ 7] ^= ibuf[ 7]; + obuf[ 8] = iv[ 8] ^= ibuf[ 8]; obuf[ 9] = iv[ 9] ^= ibuf[ 9]; + obuf[10] = iv[10] ^= ibuf[10]; obuf[11] = iv[11] ^= ibuf[11]; + obuf[12] = iv[12] ^= ibuf[12]; obuf[13] = iv[13] ^= ibuf[13]; + obuf[14] = iv[14] ^= ibuf[14]; obuf[15] = iv[15] ^= ibuf[15]; + ibuf += AES_BLOCK_SIZE; + obuf += AES_BLOCK_SIZE; + cnt += AES_BLOCK_SIZE; + } +#endif + } + + while(cnt < len) + { + if(!b_pos && aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) + return EXIT_FAILURE; + + while(cnt < len && b_pos < AES_BLOCK_SIZE) + { + *obuf++ = (iv[b_pos++] ^= *ibuf++); + cnt++; + } + + b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos); + } + + ctx->inf.b[2] = (uint8_t)b_pos; + return EXIT_SUCCESS; +} + +AES_RETURN aes_cfb_decrypt(const unsigned char *ibuf, unsigned char *obuf, + int len, unsigned char *iv, aes_encrypt_ctx ctx[1]) +{ int cnt = 0, b_pos = (int)ctx->inf.b[2], nb; + + if(b_pos) /* complete any partial block */ + { uint8_t t; + + while(b_pos < AES_BLOCK_SIZE && cnt < len) + { + t = *ibuf++; + *obuf++ = t ^ iv[b_pos]; + iv[b_pos++] = t; + cnt++; + } + + b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos); + } + + if((nb = (len - cnt) >> 4) != 0) /* process whole blocks */ + { +#if defined( USE_VIA_ACE_IF_PRESENT ) + + if(ctx->inf.b[1] == 0xff) + { int m; + uint8_t *ksp = (uint8_t*)(ctx->ks), *ivp = iv; + aligned_auto(uint8_t, liv, AES_BLOCK_SIZE, 16); + via_cwd(cwd, hybrid, dec, 2 * ctx->inf.b[0] - 192); + + if(ALIGN_OFFSET( ctx, 16 )) + return EXIT_FAILURE; + + if(ALIGN_OFFSET( iv, 16 )) /* ensure an aligned iv */ + { + ivp = liv; + memcpy(liv, iv, AES_BLOCK_SIZE); + } + + if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 )) + { + via_cfb_op6(ksp, cwd, ibuf, obuf, nb, ivp); + ibuf += nb * AES_BLOCK_SIZE; + obuf += nb * AES_BLOCK_SIZE; + cnt += nb * AES_BLOCK_SIZE; + } + else /* input, output or both are unaligned */ + { aligned_auto(uint8_t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16); + uint8_t *ip, *op; + + while(nb) + { + m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb), nb -= m; + + ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf); + op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf); + + if(ip != ibuf) /* input buffer is not aligned */ + memcpy(buf, ibuf, m * AES_BLOCK_SIZE); + + via_cfb_op6(ksp, cwd, ip, op, m, ivp); + + if(op != obuf) /* output buffer is not aligned */ + memcpy(obuf, buf, m * AES_BLOCK_SIZE); + + ibuf += m * AES_BLOCK_SIZE; + obuf += m * AES_BLOCK_SIZE; + cnt += m * AES_BLOCK_SIZE; + } + } + + if(ivp != iv) + memcpy(iv, ivp, AES_BLOCK_SIZE); + } +#else +# ifdef FAST_BUFFER_OPERATIONS + if(!ALIGN_OFFSET( ibuf, 4 ) && !ALIGN_OFFSET( obuf, 4 ) &&!ALIGN_OFFSET( iv, 4 )) + while(cnt + AES_BLOCK_SIZE <= len) + { uint32_t t; + + assert(b_pos == 0); + if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) + return EXIT_FAILURE; + t = lp32(ibuf)[0], lp32(obuf)[0] = t ^ lp32(iv)[0], lp32(iv)[0] = t; + t = lp32(ibuf)[1], lp32(obuf)[1] = t ^ lp32(iv)[1], lp32(iv)[1] = t; + t = lp32(ibuf)[2], lp32(obuf)[2] = t ^ lp32(iv)[2], lp32(iv)[2] = t; + t = lp32(ibuf)[3], lp32(obuf)[3] = t ^ lp32(iv)[3], lp32(iv)[3] = t; + ibuf += AES_BLOCK_SIZE; + obuf += AES_BLOCK_SIZE; + cnt += AES_BLOCK_SIZE; + } + else +# endif + while(cnt + AES_BLOCK_SIZE <= len) + { uint8_t t; + + assert(b_pos == 0); + if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) + return EXIT_FAILURE; + t = ibuf[ 0], obuf[ 0] = t ^ iv[ 0], iv[ 0] = t; + t = ibuf[ 1], obuf[ 1] = t ^ iv[ 1], iv[ 1] = t; + t = ibuf[ 2], obuf[ 2] = t ^ iv[ 2], iv[ 2] = t; + t = ibuf[ 3], obuf[ 3] = t ^ iv[ 3], iv[ 3] = t; + t = ibuf[ 4], obuf[ 4] = t ^ iv[ 4], iv[ 4] = t; + t = ibuf[ 5], obuf[ 5] = t ^ iv[ 5], iv[ 5] = t; + t = ibuf[ 6], obuf[ 6] = t ^ iv[ 6], iv[ 6] = t; + t = ibuf[ 7], obuf[ 7] = t ^ iv[ 7], iv[ 7] = t; + t = ibuf[ 8], obuf[ 8] = t ^ iv[ 8], iv[ 8] = t; + t = ibuf[ 9], obuf[ 9] = t ^ iv[ 9], iv[ 9] = t; + t = ibuf[10], obuf[10] = t ^ iv[10], iv[10] = t; + t = ibuf[11], obuf[11] = t ^ iv[11], iv[11] = t; + t = ibuf[12], obuf[12] = t ^ iv[12], iv[12] = t; + t = ibuf[13], obuf[13] = t ^ iv[13], iv[13] = t; + t = ibuf[14], obuf[14] = t ^ iv[14], iv[14] = t; + t = ibuf[15], obuf[15] = t ^ iv[15], iv[15] = t; + ibuf += AES_BLOCK_SIZE; + obuf += AES_BLOCK_SIZE; + cnt += AES_BLOCK_SIZE; + } +#endif + } + + while(cnt < len) + { uint8_t t; + + if(!b_pos && aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) + return EXIT_FAILURE; + + while(cnt < len && b_pos < AES_BLOCK_SIZE) + { + t = *ibuf++; + *obuf++ = t ^ iv[b_pos]; + iv[b_pos++] = t; + cnt++; + } + + b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos); + } + + ctx->inf.b[2] = (uint8_t)b_pos; + return EXIT_SUCCESS; +} + +AES_RETURN aes_ofb_crypt(const unsigned char *ibuf, unsigned char *obuf, + int len, unsigned char *iv, aes_encrypt_ctx ctx[1]) +{ int cnt = 0, b_pos = (int)ctx->inf.b[2], nb; + + if(b_pos) /* complete any partial block */ + { + while(b_pos < AES_BLOCK_SIZE && cnt < len) + { + *obuf++ = iv[b_pos++] ^ *ibuf++; + cnt++; + } + + b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos); + } + + if((nb = (len - cnt) >> 4) != 0) /* process whole blocks */ + { +#if defined( USE_VIA_ACE_IF_PRESENT ) + + if(ctx->inf.b[1] == 0xff) + { int m; + uint8_t *ksp = (uint8_t*)(ctx->ks), *ivp = iv; + aligned_auto(uint8_t, liv, AES_BLOCK_SIZE, 16); + via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192); + + if(ALIGN_OFFSET( ctx, 16 )) + return EXIT_FAILURE; + + if(ALIGN_OFFSET( iv, 16 )) /* ensure an aligned iv */ + { + ivp = liv; + memcpy(liv, iv, AES_BLOCK_SIZE); + } + + if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 )) + { + via_ofb_op6(ksp, cwd, ibuf, obuf, nb, ivp); + ibuf += nb * AES_BLOCK_SIZE; + obuf += nb * AES_BLOCK_SIZE; + cnt += nb * AES_BLOCK_SIZE; + } + else /* input, output or both are unaligned */ + { aligned_auto(uint8_t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16); + uint8_t *ip, *op; + + while(nb) + { + m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb), nb -= m; + + ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf); + op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf); + + if(ip != ibuf) + memcpy(buf, ibuf, m * AES_BLOCK_SIZE); + + via_ofb_op6(ksp, cwd, ip, op, m, ivp); + + if(op != obuf) + memcpy(obuf, buf, m * AES_BLOCK_SIZE); + + ibuf += m * AES_BLOCK_SIZE; + obuf += m * AES_BLOCK_SIZE; + cnt += m * AES_BLOCK_SIZE; + } + } + + if(ivp != iv) + memcpy(iv, ivp, AES_BLOCK_SIZE); + } +#else +# ifdef FAST_BUFFER_OPERATIONS + if(!ALIGN_OFFSET( ibuf, 4 ) && !ALIGN_OFFSET( obuf, 4 ) && !ALIGN_OFFSET( iv, 4 )) + while(cnt + AES_BLOCK_SIZE <= len) + { + assert(b_pos == 0); + if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) + return EXIT_FAILURE; + lp32(obuf)[0] = lp32(iv)[0] ^ lp32(ibuf)[0]; + lp32(obuf)[1] = lp32(iv)[1] ^ lp32(ibuf)[1]; + lp32(obuf)[2] = lp32(iv)[2] ^ lp32(ibuf)[2]; + lp32(obuf)[3] = lp32(iv)[3] ^ lp32(ibuf)[3]; + ibuf += AES_BLOCK_SIZE; + obuf += AES_BLOCK_SIZE; + cnt += AES_BLOCK_SIZE; + } + else +# endif + while(cnt + AES_BLOCK_SIZE <= len) + { + assert(b_pos == 0); + if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) + return EXIT_FAILURE; + obuf[ 0] = iv[ 0] ^ ibuf[ 0]; obuf[ 1] = iv[ 1] ^ ibuf[ 1]; + obuf[ 2] = iv[ 2] ^ ibuf[ 2]; obuf[ 3] = iv[ 3] ^ ibuf[ 3]; + obuf[ 4] = iv[ 4] ^ ibuf[ 4]; obuf[ 5] = iv[ 5] ^ ibuf[ 5]; + obuf[ 6] = iv[ 6] ^ ibuf[ 6]; obuf[ 7] = iv[ 7] ^ ibuf[ 7]; + obuf[ 8] = iv[ 8] ^ ibuf[ 8]; obuf[ 9] = iv[ 9] ^ ibuf[ 9]; + obuf[10] = iv[10] ^ ibuf[10]; obuf[11] = iv[11] ^ ibuf[11]; + obuf[12] = iv[12] ^ ibuf[12]; obuf[13] = iv[13] ^ ibuf[13]; + obuf[14] = iv[14] ^ ibuf[14]; obuf[15] = iv[15] ^ ibuf[15]; + ibuf += AES_BLOCK_SIZE; + obuf += AES_BLOCK_SIZE; + cnt += AES_BLOCK_SIZE; + } +#endif + } + + while(cnt < len) + { + if(!b_pos && aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) + return EXIT_FAILURE; + + while(cnt < len && b_pos < AES_BLOCK_SIZE) + { + *obuf++ = iv[b_pos++] ^ *ibuf++; + cnt++; + } + + b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos); + } + + ctx->inf.b[2] = (uint8_t)b_pos; + return EXIT_SUCCESS; +} + +#define BFR_LENGTH (BFR_BLOCKS * AES_BLOCK_SIZE) + +AES_RETURN aes_ctr_crypt(const unsigned char *ibuf, unsigned char *obuf, + int len, unsigned char *cbuf, cbuf_inc ctr_inc, aes_encrypt_ctx ctx[1]) +{ unsigned char *ip; + int i, blen, b_pos = (int)(ctx->inf.b[2]); + +#if defined( USE_VIA_ACE_IF_PRESENT ) + aligned_auto(uint8_t, buf, BFR_LENGTH, 16); + if(ctx->inf.b[1] == 0xff && ALIGN_OFFSET( ctx, 16 )) + return EXIT_FAILURE; +#else + uint8_t buf[BFR_LENGTH]; +#endif + + if(b_pos) + { + memcpy(buf, cbuf, AES_BLOCK_SIZE); + if(aes_ecb_encrypt(buf, buf, AES_BLOCK_SIZE, ctx) != EXIT_SUCCESS) + return EXIT_FAILURE; + + while(b_pos < AES_BLOCK_SIZE && len) + { + *obuf++ = *ibuf++ ^ buf[b_pos++]; + --len; + } + + if(len) + ctr_inc(cbuf), b_pos = 0; + } + + while(len) + { + blen = (len > BFR_LENGTH ? BFR_LENGTH : len), len -= blen; + + for(i = 0, ip = buf; i < (blen >> 4); ++i) + { + memcpy(ip, cbuf, AES_BLOCK_SIZE); + ctr_inc(cbuf); + ip += AES_BLOCK_SIZE; + } + + if(blen & (AES_BLOCK_SIZE - 1)) + memcpy(ip, cbuf, AES_BLOCK_SIZE), i++; + +#if defined( USE_VIA_ACE_IF_PRESENT ) + if(ctx->inf.b[1] == 0xff) + { + via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192); + via_ecb_op5((ctx->ks), cwd, buf, buf, i); + } + else +#endif + if(aes_ecb_encrypt(buf, buf, i * AES_BLOCK_SIZE, ctx) != EXIT_SUCCESS) + return EXIT_FAILURE; + + i = 0; ip = buf; +# ifdef FAST_BUFFER_OPERATIONS + if(!ALIGN_OFFSET( ibuf, 4 ) && !ALIGN_OFFSET( obuf, 4 ) && !ALIGN_OFFSET( ip, 4 )) + while(i + AES_BLOCK_SIZE <= blen) + { + lp32(obuf)[0] = lp32(ibuf)[0] ^ lp32(ip)[0]; + lp32(obuf)[1] = lp32(ibuf)[1] ^ lp32(ip)[1]; + lp32(obuf)[2] = lp32(ibuf)[2] ^ lp32(ip)[2]; + lp32(obuf)[3] = lp32(ibuf)[3] ^ lp32(ip)[3]; + i += AES_BLOCK_SIZE; + ip += AES_BLOCK_SIZE; + ibuf += AES_BLOCK_SIZE; + obuf += AES_BLOCK_SIZE; + } + else +#endif + while(i + AES_BLOCK_SIZE <= blen) + { + obuf[ 0] = ibuf[ 0] ^ ip[ 0]; obuf[ 1] = ibuf[ 1] ^ ip[ 1]; + obuf[ 2] = ibuf[ 2] ^ ip[ 2]; obuf[ 3] = ibuf[ 3] ^ ip[ 3]; + obuf[ 4] = ibuf[ 4] ^ ip[ 4]; obuf[ 5] = ibuf[ 5] ^ ip[ 5]; + obuf[ 6] = ibuf[ 6] ^ ip[ 6]; obuf[ 7] = ibuf[ 7] ^ ip[ 7]; + obuf[ 8] = ibuf[ 8] ^ ip[ 8]; obuf[ 9] = ibuf[ 9] ^ ip[ 9]; + obuf[10] = ibuf[10] ^ ip[10]; obuf[11] = ibuf[11] ^ ip[11]; + obuf[12] = ibuf[12] ^ ip[12]; obuf[13] = ibuf[13] ^ ip[13]; + obuf[14] = ibuf[14] ^ ip[14]; obuf[15] = ibuf[15] ^ ip[15]; + i += AES_BLOCK_SIZE; + ip += AES_BLOCK_SIZE; + ibuf += AES_BLOCK_SIZE; + obuf += AES_BLOCK_SIZE; + } + + while(i++ < blen) + *obuf++ = *ibuf++ ^ ip[b_pos++]; + } + + ctx->inf.b[2] = (uint8_t)b_pos; + return EXIT_SUCCESS; +} + +#if defined(__cplusplus) +} +#endif +#endif diff --git a/aescrypt.c b/aescrypt.c index a832c6368..83c77f0b6 100644 --- a/aescrypt.c +++ b/aescrypt.c @@ -1,421 +1,301 @@ /* - ------------------------------------------------------------------------- - Copyright (c) 2001, Dr Brian Gladman < >, Worcester, UK. - All rights reserved. +--------------------------------------------------------------------------- +Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved. - LICENSE TERMS +The redistribution and use of this software (with or without changes) +is allowed without the payment of fees or royalties provided that: - The free distribution and use of this software in both source and binary - form is allowed (with or without changes) provided that: + source code distributions include the above copyright notice, this + list of conditions and the following disclaimer; - 1. distributions of this source code include the above copyright - notice, this list of conditions and the following disclaimer; + binary distributions include the above copyright notice, this list + of conditions and the following disclaimer in their documentation. - 2. distributions in binary form include the above copyright - notice, this list of conditions and the following disclaimer - in the documentation and/or other associated materials; - - 3. the copyright holder's name is not used to endorse products - built using this software without specific written permission. - - DISCLAIMER - - This software is provided 'as is' with no explicit or implied warranties - in respect of its properties, including, but not limited to, correctness - and fitness for purpose. - ------------------------------------------------------------------------- - Issue Date: 29/07/2002 - - This file contains the code for implementing encryption and decryption - for AES (Rijndael) for block and key sizes of 16, 24 and 32 bytes. It - can optionally be replaced by code written in assembler using NASM. +This software is provided 'as is' with no explicit or implied warranties +in respect of its operation, including, but not limited to, correctness +and fitness for purpose. +--------------------------------------------------------------------------- +Issue Date: 20/12/2007 */ #include "aesopt.h" +#include "aestab.h" -#if defined(BLOCK_SIZE) && (BLOCK_SIZE & 7) -#error An illegal block size has been specified. +#if defined( USE_INTEL_AES_IF_PRESENT ) +# include "aes_ni.h" +#else +/* map names here to provide the external API ('name' -> 'aes_name') */ +# define aes_xi(x) aes_ ## x #endif -#define unused 77 /* Sunset Strip */ - -#define si(y,x,k,c) s(y,c) = word_in(x + 4 * c) ^ k[c] -#define so(y,x,c) word_out(y + 4 * c, s(x,c)) +#if defined(__cplusplus) +extern "C" +{ +#endif -#if BLOCK_SIZE == 16 +#define si(y,x,k,c) (s(y,c) = word_in(x, c) ^ (k)[c]) +#define so(y,x,c) word_out(y, c, s(x,c)) #if defined(ARRAYS) #define locals(y,x) x[4],y[4] #else #define locals(y,x) x##0,x##1,x##2,x##3,y##0,y##1,y##2,y##3 - /* - the following defines prevent the compiler requiring the declaration - of generated but unused variables in the fwd_var and inv_var macros - */ -#define b04 unused -#define b05 unused -#define b06 unused -#define b07 unused -#define b14 unused -#define b15 unused -#define b16 unused -#define b17 unused #endif + #define l_copy(y, x) s(y,0) = s(x,0); s(y,1) = s(x,1); \ s(y,2) = s(x,2); s(y,3) = s(x,3); #define state_in(y,x,k) si(y,x,k,0); si(y,x,k,1); si(y,x,k,2); si(y,x,k,3) #define state_out(y,x) so(y,x,0); so(y,x,1); so(y,x,2); so(y,x,3) #define round(rm,y,x,k) rm(y,x,k,0); rm(y,x,k,1); rm(y,x,k,2); rm(y,x,k,3) -#elif BLOCK_SIZE == 24 - -#if defined(ARRAYS) -#define locals(y,x) x[6],y[6] -#else -#define locals(y,x) x##0,x##1,x##2,x##3,x##4,x##5, \ - y##0,y##1,y##2,y##3,y##4,y##5 -#define b06 unused -#define b07 unused -#define b16 unused -#define b17 unused -#endif -#define l_copy(y, x) s(y,0) = s(x,0); s(y,1) = s(x,1); \ - s(y,2) = s(x,2); s(y,3) = s(x,3); \ - s(y,4) = s(x,4); s(y,5) = s(x,5); -#define state_in(y,x,k) si(y,x,k,0); si(y,x,k,1); si(y,x,k,2); \ - si(y,x,k,3); si(y,x,k,4); si(y,x,k,5) -#define state_out(y,x) so(y,x,0); so(y,x,1); so(y,x,2); \ - so(y,x,3); so(y,x,4); so(y,x,5) -#define round(rm,y,x,k) rm(y,x,k,0); rm(y,x,k,1); rm(y,x,k,2); \ - rm(y,x,k,3); rm(y,x,k,4); rm(y,x,k,5) -#else - -#if defined(ARRAYS) -#define locals(y,x) x[8],y[8] -#else -#define locals(y,x) x##0,x##1,x##2,x##3,x##4,x##5,x##6,x##7, \ - y##0,y##1,y##2,y##3,y##4,y##5,y##6,y##7 -#endif -#define l_copy(y, x) s(y,0) = s(x,0); s(y,1) = s(x,1); \ - s(y,2) = s(x,2); s(y,3) = s(x,3); \ - s(y,4) = s(x,4); s(y,5) = s(x,5); \ - s(y,6) = s(x,6); s(y,7) = s(x,7); - -#if BLOCK_SIZE == 32 - -#define state_in(y,x,k) si(y,x,k,0); si(y,x,k,1); si(y,x,k,2); si(y,x,k,3); \ - si(y,x,k,4); si(y,x,k,5); si(y,x,k,6); si(y,x,k,7) -#define state_out(y,x) so(y,x,0); so(y,x,1); so(y,x,2); so(y,x,3); \ - so(y,x,4); so(y,x,5); so(y,x,6); so(y,x,7) -#define round(rm,y,x,k) rm(y,x,k,0); rm(y,x,k,1); rm(y,x,k,2); rm(y,x,k,3); \ - rm(y,x,k,4); rm(y,x,k,5); rm(y,x,k,6); rm(y,x,k,7) -#else - -#define state_in(y,x,k) \ -switch(nc) \ -{ case 8: si(y,x,k,7); si(y,x,k,6); \ - case 6: si(y,x,k,5); si(y,x,k,4); \ - case 4: si(y,x,k,3); si(y,x,k,2); \ - si(y,x,k,1); si(y,x,k,0); \ -} +#if ( FUNCS_IN_C & ENCRYPTION_IN_C ) -#define state_out(y,x) \ -switch(nc) \ -{ case 8: so(y,x,7); so(y,x,6); \ - case 6: so(y,x,5); so(y,x,4); \ - case 4: so(y,x,3); so(y,x,2); \ - so(y,x,1); so(y,x,0); \ -} - -#if defined(FAST_VARIABLE) - -#define round(rm,y,x,k) \ -switch(nc) \ -{ case 8: rm(y,x,k,7); rm(y,x,k,6); \ - rm(y,x,k,5); rm(y,x,k,4); \ - rm(y,x,k,3); rm(y,x,k,2); \ - rm(y,x,k,1); rm(y,x,k,0); \ - break; \ - case 6: rm(y,x,k,5); rm(y,x,k,4); \ - rm(y,x,k,3); rm(y,x,k,2); \ - rm(y,x,k,1); rm(y,x,k,0); \ - break; \ - case 4: rm(y,x,k,3); rm(y,x,k,2); \ - rm(y,x,k,1); rm(y,x,k,0); \ - break; \ -} -#else - -#define round(rm,y,x,k) \ -switch(nc) \ -{ case 8: rm(y,x,k,7); rm(y,x,k,6); \ - case 6: rm(y,x,k,5); rm(y,x,k,4); \ - case 4: rm(y,x,k,3); rm(y,x,k,2); \ - rm(y,x,k,1); rm(y,x,k,0); \ -} - -#endif +/* Visual C++ .Net v7.1 provides the fastest encryption code when using + Pentium optimiation with small code but this is poor for decryption + so we need to control this with the following VC++ pragmas +*/ +#if defined( _MSC_VER ) && !defined( _WIN64 ) +#pragma optimize( "s", on ) #endif -#endif - -#if defined(ENCRYPTION) - -/* I am grateful to Frank Yellin for the following construction - (and that for decryption) which, given the column (c) of the - output state variable, gives the input state variables which - are needed in its computation for each row (r) of the state. - For the fixed block size options, compilers should be able to - reduce this complex expression (and the equivalent one for - decryption) to a static variable reference at compile time. - But for variable block size code, there will be some limbs on - which conditional clauses will be returned. -*/ - -/* y = output word, x = input word, r = row, c = column for r = 0, - 1, 2 and 3 = column accessed for row r. +/* Given the column (c) of the output state variable, the following + macros give the input state variables which are needed in its + computation for each row (r) of the state. All the alternative + macros give the same end values but expand into different ways + of calculating these values. In particular the complex macro + used for dynamically variable block sizes is designed to expand + to a compile time constant whenever possible but will expand to + conditional clauses on some branches (I am grateful to Frank + Yellin for this construction) */ #define fwd_var(x,r,c)\ - ( r == 0 ? \ - ( c == 0 ? s(x,0) \ - : c == 1 ? s(x,1) \ - : c == 2 ? s(x,2) \ - : c == 3 ? s(x,3) \ - : c == 4 ? s(x,4) \ - : c == 5 ? s(x,5) \ - : c == 6 ? s(x,6) \ - : s(x,7))\ - : r == 1 ? \ - ( c == 0 ? s(x,1) \ - : c == 1 ? s(x,2) \ - : c == 2 ? s(x,3) \ - : c == 3 ? nc == 4 ? s(x,0) : s(x,4) \ - : c == 4 ? s(x,5) \ - : c == 5 ? nc == 8 ? s(x,6) : s(x,0) \ - : c == 6 ? s(x,7) \ - : s(x,0))\ - : r == 2 ? \ - ( c == 0 ? nc == 8 ? s(x,3) : s(x,2) \ - : c == 1 ? nc == 8 ? s(x,4) : s(x,3) \ - : c == 2 ? nc == 4 ? s(x,0) : nc == 8 ? s(x,5) : s(x,4) \ - : c == 3 ? nc == 4 ? s(x,1) : nc == 8 ? s(x,6) : s(x,5) \ - : c == 4 ? nc == 8 ? s(x,7) : s(x,0) \ - : c == 5 ? nc == 8 ? s(x,0) : s(x,1) \ - : c == 6 ? s(x,1) \ - : s(x,2))\ - : \ - ( c == 0 ? nc == 8 ? s(x,4) : s(x,3) \ - : c == 1 ? nc == 4 ? s(x,0) : nc == 8 ? s(x,5) : s(x,4) \ - : c == 2 ? nc == 4 ? s(x,1) : nc == 8 ? s(x,6) : s(x,5) \ - : c == 3 ? nc == 4 ? s(x,2) : nc == 8 ? s(x,7) : s(x,0) \ - : c == 4 ? nc == 8 ? s(x,0) : s(x,1) \ - : c == 5 ? nc == 8 ? s(x,1) : s(x,2) \ - : c == 6 ? s(x,2) \ - : s(x,3))) + ( r == 0 ? ( c == 0 ? s(x,0) : c == 1 ? s(x,1) : c == 2 ? s(x,2) : s(x,3))\ + : r == 1 ? ( c == 0 ? s(x,1) : c == 1 ? s(x,2) : c == 2 ? s(x,3) : s(x,0))\ + : r == 2 ? ( c == 0 ? s(x,2) : c == 1 ? s(x,3) : c == 2 ? s(x,0) : s(x,1))\ + : ( c == 0 ? s(x,3) : c == 1 ? s(x,0) : c == 2 ? s(x,1) : s(x,2))) #if defined(FT4_SET) #undef dec_fmvars -#define dec_fmvars -#define fwd_rnd(y,x,k,c) s(y,c)= (k)[c] ^ four_tables(x,ft_tab,fwd_var,rf1,c) +#define fwd_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ four_tables(x,t_use(f,n),fwd_var,rf1,c)) #elif defined(FT1_SET) #undef dec_fmvars -#define dec_fmvars -#define fwd_rnd(y,x,k,c) s(y,c)= (k)[c] ^ one_table(x,upr,ft_tab,fwd_var,rf1,c) +#define fwd_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ one_table(x,upr,t_use(f,n),fwd_var,rf1,c)) #else -#define fwd_rnd(y,x,k,c) s(y,c) = fwd_mcol(no_table(x,s_box,fwd_var,rf1,c)) ^ (k)[c] +#define fwd_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ fwd_mcol(no_table(x,t_use(s,box),fwd_var,rf1,c))) #endif #if defined(FL4_SET) -#define fwd_lrnd(y,x,k,c) s(y,c)= (k)[c] ^ four_tables(x,fl_tab,fwd_var,rf1,c) +#define fwd_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ four_tables(x,t_use(f,l),fwd_var,rf1,c)) #elif defined(FL1_SET) -#define fwd_lrnd(y,x,k,c) s(y,c)= (k)[c] ^ one_table(x,ups,fl_tab,fwd_var,rf1,c) +#define fwd_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ one_table(x,ups,t_use(f,l),fwd_var,rf1,c)) #else -#define fwd_lrnd(y,x,k,c) s(y,c) = no_table(x,s_box,fwd_var,rf1,c) ^ (k)[c] +#define fwd_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ no_table(x,t_use(s,box),fwd_var,rf1,c)) #endif -aes_rval aes_enc_blk(const unsigned char in_blk[], unsigned char out_blk[], const aes_ctx cx[1]) -{ aes_32t locals(b0, b1); - const aes_32t *kp = cx->k_sch; - dec_fmvars /* declare variables for fwd_mcol() if needed */ +AES_RETURN aes_xi(encrypt)(const unsigned char *in, unsigned char *out, const aes_encrypt_ctx cx[1]) +{ uint32_t locals(b0, b1); + const uint32_t *kp; +#if defined( dec_fmvars ) + dec_fmvars; /* declare variables for fwd_mcol() if needed */ +#endif - if(!(cx->n_blk & 1)) return aes_bad; + if(cx->inf.b[0] != 10 * 16 && cx->inf.b[0] != 12 * 16 && cx->inf.b[0] != 14 * 16) + return EXIT_FAILURE; - state_in(b0, in_blk, kp); + kp = cx->ks; + state_in(b0, in, kp); #if (ENC_UNROLL == FULL) - kp += (cx->n_rnd - 9) * nc; - - switch(cx->n_rnd) + switch(cx->inf.b[0]) { - case 14: round(fwd_rnd, b1, b0, kp - 4 * nc); - round(fwd_rnd, b0, b1, kp - 3 * nc); - case 12: round(fwd_rnd, b1, b0, kp - 2 * nc); - round(fwd_rnd, b0, b1, kp - nc); - case 10: round(fwd_rnd, b1, b0, kp ); - round(fwd_rnd, b0, b1, kp + nc); - round(fwd_rnd, b1, b0, kp + 2 * nc); - round(fwd_rnd, b0, b1, kp + 3 * nc); - round(fwd_rnd, b1, b0, kp + 4 * nc); - round(fwd_rnd, b0, b1, kp + 5 * nc); - round(fwd_rnd, b1, b0, kp + 6 * nc); - round(fwd_rnd, b0, b1, kp + 7 * nc); - round(fwd_rnd, b1, b0, kp + 8 * nc); - round(fwd_lrnd, b0, b1, kp + 9 * nc); + case 14 * 16: + round(fwd_rnd, b1, b0, kp + 1 * N_COLS); + round(fwd_rnd, b0, b1, kp + 2 * N_COLS); + kp += 2 * N_COLS; + case 12 * 16: + round(fwd_rnd, b1, b0, kp + 1 * N_COLS); + round(fwd_rnd, b0, b1, kp + 2 * N_COLS); + kp += 2 * N_COLS; + case 10 * 16: + round(fwd_rnd, b1, b0, kp + 1 * N_COLS); + round(fwd_rnd, b0, b1, kp + 2 * N_COLS); + round(fwd_rnd, b1, b0, kp + 3 * N_COLS); + round(fwd_rnd, b0, b1, kp + 4 * N_COLS); + round(fwd_rnd, b1, b0, kp + 5 * N_COLS); + round(fwd_rnd, b0, b1, kp + 6 * N_COLS); + round(fwd_rnd, b1, b0, kp + 7 * N_COLS); + round(fwd_rnd, b0, b1, kp + 8 * N_COLS); + round(fwd_rnd, b1, b0, kp + 9 * N_COLS); + round(fwd_lrnd, b0, b1, kp +10 * N_COLS); } + #else #if (ENC_UNROLL == PARTIAL) - { aes_32t rnd; - for(rnd = 0; rnd < (cx->n_rnd >> 1) - 1; ++rnd) + { uint32_t rnd; + for(rnd = 0; rnd < (cx->inf.b[0] >> 5) - 1; ++rnd) { - kp += nc; + kp += N_COLS; round(fwd_rnd, b1, b0, kp); - kp += nc; + kp += N_COLS; round(fwd_rnd, b0, b1, kp); } - kp += nc; + kp += N_COLS; round(fwd_rnd, b1, b0, kp); #else - { aes_32t rnd, *p0 = b0, *p1 = b1, *pt; - for(rnd = 0; rnd < cx->n_rnd - 1; ++rnd) + { uint32_t rnd; + for(rnd = 0; rnd < (cx->inf.b[0] >> 4) - 1; ++rnd) { - kp += nc; - round(fwd_rnd, p1, p0, kp); - pt = p0, p0 = p1, p1 = pt; + kp += N_COLS; + round(fwd_rnd, b1, b0, kp); + l_copy(b0, b1); } #endif - kp += nc; + kp += N_COLS; round(fwd_lrnd, b0, b1, kp); } #endif - state_out(out_blk, b0); - return aes_good; + state_out(out, b0); + return EXIT_SUCCESS; } #endif -#if defined(DECRYPTION) - -#define inv_var(x,r,c) \ - ( r == 0 ? \ - ( c == 0 ? s(x,0) \ - : c == 1 ? s(x,1) \ - : c == 2 ? s(x,2) \ - : c == 3 ? s(x,3) \ - : c == 4 ? s(x,4) \ - : c == 5 ? s(x,5) \ - : c == 6 ? s(x,6) \ - : s(x,7))\ - : r == 1 ? \ - ( c == 0 ? nc == 4 ? s(x,3) : nc == 8 ? s(x,7) : s(x,5) \ - : c == 1 ? s(x,0) \ - : c == 2 ? s(x,1) \ - : c == 3 ? s(x,2) \ - : c == 4 ? s(x,3) \ - : c == 5 ? s(x,4) \ - : c == 6 ? s(x,5) \ - : s(x,6))\ - : r == 2 ? \ - ( c == 0 ? nc == 4 ? s(x,2) : nc == 8 ? s(x,5) : s(x,4) \ - : c == 1 ? nc == 4 ? s(x,3) : nc == 8 ? s(x,6) : s(x,5) \ - : c == 2 ? nc == 8 ? s(x,7) : s(x,0) \ - : c == 3 ? nc == 8 ? s(x,0) : s(x,1) \ - : c == 4 ? nc == 8 ? s(x,1) : s(x,2) \ - : c == 5 ? nc == 8 ? s(x,2) : s(x,3) \ - : c == 6 ? s(x,3) \ - : s(x,4))\ - : \ - ( c == 0 ? nc == 4 ? s(x,1) : nc == 8 ? s(x,4) : s(x,3) \ - : c == 1 ? nc == 4 ? s(x,2) : nc == 8 ? s(x,5) : s(x,4) \ - : c == 2 ? nc == 4 ? s(x,3) : nc == 8 ? s(x,6) : s(x,5) \ - : c == 3 ? nc == 8 ? s(x,7) : s(x,0) \ - : c == 4 ? nc == 8 ? s(x,0) : s(x,1) \ - : c == 5 ? nc == 8 ? s(x,1) : s(x,2) \ - : c == 6 ? s(x,2) \ - : s(x,3))) +#if ( FUNCS_IN_C & DECRYPTION_IN_C) + +/* Visual C++ .Net v7.1 provides the fastest encryption code when using + Pentium optimiation with small code but this is poor for decryption + so we need to control this with the following VC++ pragmas +*/ + +#if defined( _MSC_VER ) && !defined( _WIN64 ) +#pragma optimize( "t", on ) +#endif + +/* Given the column (c) of the output state variable, the following + macros give the input state variables which are needed in its + computation for each row (r) of the state. All the alternative + macros give the same end values but expand into different ways + of calculating these values. In particular the complex macro + used for dynamically variable block sizes is designed to expand + to a compile time constant whenever possible but will expand to + conditional clauses on some branches (I am grateful to Frank + Yellin for this construction) +*/ + +#define inv_var(x,r,c)\ + ( r == 0 ? ( c == 0 ? s(x,0) : c == 1 ? s(x,1) : c == 2 ? s(x,2) : s(x,3))\ + : r == 1 ? ( c == 0 ? s(x,3) : c == 1 ? s(x,0) : c == 2 ? s(x,1) : s(x,2))\ + : r == 2 ? ( c == 0 ? s(x,2) : c == 1 ? s(x,3) : c == 2 ? s(x,0) : s(x,1))\ + : ( c == 0 ? s(x,1) : c == 1 ? s(x,2) : c == 2 ? s(x,3) : s(x,0))) #if defined(IT4_SET) #undef dec_imvars -#define dec_imvars -#define inv_rnd(y,x,k,c) s(y,c)= (k)[c] ^ four_tables(x,it_tab,inv_var,rf1,c) +#define inv_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ four_tables(x,t_use(i,n),inv_var,rf1,c)) #elif defined(IT1_SET) #undef dec_imvars -#define dec_imvars -#define inv_rnd(y,x,k,c) s(y,c)= (k)[c] ^ one_table(x,upr,it_tab,inv_var,rf1,c) +#define inv_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ one_table(x,upr,t_use(i,n),inv_var,rf1,c)) #else -#define inv_rnd(y,x,k,c) s(y,c) = inv_mcol(no_table(x,inv_s_box,inv_var,rf1,c) ^ (k)[c]) +#define inv_rnd(y,x,k,c) (s(y,c) = inv_mcol((k)[c] ^ no_table(x,t_use(i,box),inv_var,rf1,c))) #endif #if defined(IL4_SET) -#define inv_lrnd(y,x,k,c) s(y,c)= (k)[c] ^ four_tables(x,il_tab,inv_var,rf1,c) +#define inv_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ four_tables(x,t_use(i,l),inv_var,rf1,c)) #elif defined(IL1_SET) -#define inv_lrnd(y,x,k,c) s(y,c)= (k)[c] ^ one_table(x,ups,il_tab,inv_var,rf1,c) +#define inv_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ one_table(x,ups,t_use(i,l),inv_var,rf1,c)) #else -#define inv_lrnd(y,x,k,c) s(y,c) = no_table(x,inv_s_box,inv_var,rf1,c) ^ (k)[c] +#define inv_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ no_table(x,t_use(i,box),inv_var,rf1,c)) #endif -aes_rval aes_dec_blk(const unsigned char in_blk[], unsigned char out_blk[], const aes_ctx cx[1]) -{ aes_32t locals(b0, b1); - const aes_32t *kp = cx->k_sch + nc * cx->n_rnd; - dec_imvars /* declare variables for inv_mcol() if needed */ +/* This code can work with the decryption key schedule in the */ +/* order that is used for encrytpion (where the 1st decryption */ +/* round key is at the high end ot the schedule) or with a key */ +/* schedule that has been reversed to put the 1st decryption */ +/* round key at the low end of the schedule in memory (when */ +/* AES_REV_DKS is defined) */ + +#ifdef AES_REV_DKS +#define key_ofs 0 +#define rnd_key(n) (kp + n * N_COLS) +#else +#define key_ofs 1 +#define rnd_key(n) (kp - n * N_COLS) +#endif + +AES_RETURN aes_xi(decrypt)(const unsigned char *in, unsigned char *out, const aes_decrypt_ctx cx[1]) +{ uint32_t locals(b0, b1); +#if defined( dec_imvars ) + dec_imvars; /* declare variables for inv_mcol() if needed */ +#endif + const uint32_t *kp; - if(!(cx->n_blk & 2)) return aes_bad; + if(cx->inf.b[0] != 10 * 16 && cx->inf.b[0] != 12 * 16 && cx->inf.b[0] != 14 * 16) + return EXIT_FAILURE; - state_in(b0, in_blk, kp); + kp = cx->ks + (key_ofs ? (cx->inf.b[0] >> 2) : 0); + state_in(b0, in, kp); #if (DEC_UNROLL == FULL) - kp = cx->k_sch + 9 * nc; - switch(cx->n_rnd) + kp = cx->ks + (key_ofs ? 0 : (cx->inf.b[0] >> 2)); + switch(cx->inf.b[0]) { - case 14: round(inv_rnd, b1, b0, kp + 4 * nc); - round(inv_rnd, b0, b1, kp + 3 * nc); - case 12: round(inv_rnd, b1, b0, kp + 2 * nc); - round(inv_rnd, b0, b1, kp + nc ); - case 10: round(inv_rnd, b1, b0, kp ); - round(inv_rnd, b0, b1, kp - nc); - round(inv_rnd, b1, b0, kp - 2 * nc); - round(inv_rnd, b0, b1, kp - 3 * nc); - round(inv_rnd, b1, b0, kp - 4 * nc); - round(inv_rnd, b0, b1, kp - 5 * nc); - round(inv_rnd, b1, b0, kp - 6 * nc); - round(inv_rnd, b0, b1, kp - 7 * nc); - round(inv_rnd, b1, b0, kp - 8 * nc); - round(inv_lrnd, b0, b1, kp - 9 * nc); + case 14 * 16: + round(inv_rnd, b1, b0, rnd_key(-13)); + round(inv_rnd, b0, b1, rnd_key(-12)); + case 12 * 16: + round(inv_rnd, b1, b0, rnd_key(-11)); + round(inv_rnd, b0, b1, rnd_key(-10)); + case 10 * 16: + round(inv_rnd, b1, b0, rnd_key(-9)); + round(inv_rnd, b0, b1, rnd_key(-8)); + round(inv_rnd, b1, b0, rnd_key(-7)); + round(inv_rnd, b0, b1, rnd_key(-6)); + round(inv_rnd, b1, b0, rnd_key(-5)); + round(inv_rnd, b0, b1, rnd_key(-4)); + round(inv_rnd, b1, b0, rnd_key(-3)); + round(inv_rnd, b0, b1, rnd_key(-2)); + round(inv_rnd, b1, b0, rnd_key(-1)); + round(inv_lrnd, b0, b1, rnd_key( 0)); } + #else #if (DEC_UNROLL == PARTIAL) - { aes_32t rnd; - for(rnd = 0; rnd < (cx->n_rnd >> 1) - 1; ++rnd) + { uint32_t rnd; + for(rnd = 0; rnd < (cx->inf.b[0] >> 5) - 1; ++rnd) { - kp -= nc; + kp = rnd_key(1); round(inv_rnd, b1, b0, kp); - kp -= nc; + kp = rnd_key(1); round(inv_rnd, b0, b1, kp); } - kp -= nc; + kp = rnd_key(1); round(inv_rnd, b1, b0, kp); #else - { aes_32t rnd, *p0 = b0, *p1 = b1, *pt; - for(rnd = 0; rnd < cx->n_rnd - 1; ++rnd) + { uint32_t rnd; + for(rnd = 0; rnd < (cx->inf.b[0] >> 4) - 1; ++rnd) { - kp -= nc; - round(inv_rnd, p1, p0, kp); - pt = p0, p0 = p1, p1 = pt; + kp = rnd_key(1); + round(inv_rnd, b1, b0, kp); + l_copy(b0, b1); } #endif - kp -= nc; + kp = rnd_key(1); round(inv_lrnd, b0, b1, kp); - } + } #endif - state_out(out_blk, b0); - return aes_good; + state_out(out, b0); + return EXIT_SUCCESS; } #endif + +#if defined(__cplusplus) +} +#endif diff --git a/aeskey.c b/aeskey.c index b6dee48d3..16e9607ff 100644 --- a/aeskey.c +++ b/aeskey.c @@ -1,68 +1,46 @@ /* - ------------------------------------------------------------------------- - Copyright (c) 2001, Dr Brian Gladman < >, Worcester, UK. - All rights reserved. +--------------------------------------------------------------------------- +Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved. - LICENSE TERMS +The redistribution and use of this software (with or without changes) +is allowed without the payment of fees or royalties provided that: - The free distribution and use of this software in both source and binary - form is allowed (with or without changes) provided that: + source code distributions include the above copyright notice, this + list of conditions and the following disclaimer; - 1. distributions of this source code include the above copyright - notice, this list of conditions and the following disclaimer; + binary distributions include the above copyright notice, this list + of conditions and the following disclaimer in their documentation. - 2. distributions in binary form include the above copyright - notice, this list of conditions and the following disclaimer - in the documentation and/or other associated materials; - - 3. the copyright holder's name is not used to endorse products - built using this software without specific written permission. - - DISCLAIMER - - This software is provided 'as is' with no explicit or implied warranties - in respect of its properties, including, but not limited to, correctness - and fitness for purpose. - ------------------------------------------------------------------------- - Issue Date: 29/07/2002 - - This file contains the code for implementing the key schedule for AES - (Rijndael) for block and key sizes of 16, 24, and 32 bytes. +This software is provided 'as is' with no explicit or implied warranties +in respect of its operation, including, but not limited to, correctness +and fitness for purpose. +--------------------------------------------------------------------------- +Issue Date: 20/12/2007 */ #include "aesopt.h" +#include "aestab.h" -#if defined(BLOCK_SIZE) && (BLOCK_SIZE & 7) -#error An illegal block size has been specified. +#if defined( USE_INTEL_AES_IF_PRESENT ) +# include "aes_ni.h" +#else +/* map names here to provide the external API ('name' -> 'aes_name') */ +# define aes_xi(x) aes_ ## x #endif -/* Subroutine to set the block size (if variable) in bytes, legal - values being 16, 24 and 32. -*/ - -#if !defined(BLOCK_SIZE) - -aes_rval aes_blk_len(unsigned int blen, aes_ctx cx[1]) -{ -#if !defined(FIXED_TABLES) - if(!tab_init) gen_tabs(); +#ifdef USE_VIA_ACE_IF_PRESENT +# include "aes_via_ace.h" #endif - if((blen & 7) || blen < 16 || blen > 32) - { - cx->n_blk = 0; return aes_bad; - } - - cx->n_blk = blen; - return aes_good; -} - +#if defined(__cplusplus) +extern "C" +{ #endif /* Initialise the key schedule from the user supplied key. The key - length is now specified in bytes - 16, 24 or 32 as appropriate. - This corresponds to bit lengths of 128, 192 and 256 bits, and - to Nk values of 4, 6 and 8 respectively. + length can be specified in bytes, with legal values of 16, 24 + and 32, or in bits, with legal values of 128, 192 and 256. These + values correspond with Nk values of 4, 6 and 8 respectively. The following macros implement a single cycle in the key schedule generation process. The number of cycles needed @@ -77,293 +55,500 @@ aes_rval aes_blk_len(unsigned int blen, aes_ctx cx[1]) cx->n_col = 8 29 23 19 17 14 */ +#if defined( REDUCE_CODE_SIZE ) +# define ls_box ls_sub + uint32_t ls_sub(const uint32_t t, const uint32_t n); +# define inv_mcol im_sub + uint32_t im_sub(const uint32_t x); +# ifdef ENC_KS_UNROLL +# undef ENC_KS_UNROLL +# endif +# ifdef DEC_KS_UNROLL +# undef DEC_KS_UNROLL +# endif +#endif + +#if (FUNCS_IN_C & ENC_KEYING_IN_C) + +#if defined(AES_128) || defined( AES_VAR ) + #define ke4(k,i) \ -{ k[4*(i)+4] = ss[0] ^= ls_box(ss[3],3) ^ rcon_tab[i]; k[4*(i)+5] = ss[1] ^= ss[0]; \ - k[4*(i)+6] = ss[2] ^= ss[1]; k[4*(i)+7] = ss[3] ^= ss[2]; \ -} -#define kel4(k,i) \ -{ k[4*(i)+4] = ss[0] ^= ls_box(ss[3],3) ^ rcon_tab[i]; k[4*(i)+5] = ss[1] ^= ss[0]; \ - k[4*(i)+6] = ss[2] ^= ss[1]; k[4*(i)+7] = ss[3] ^= ss[2]; \ +{ k[4*(i)+4] = ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; \ + k[4*(i)+5] = ss[1] ^= ss[0]; \ + k[4*(i)+6] = ss[2] ^= ss[1]; \ + k[4*(i)+7] = ss[3] ^= ss[2]; \ } -#define ke6(k,i) \ -{ k[6*(i)+ 6] = ss[0] ^= ls_box(ss[5],3) ^ rcon_tab[i]; k[6*(i)+ 7] = ss[1] ^= ss[0]; \ - k[6*(i)+ 8] = ss[2] ^= ss[1]; k[6*(i)+ 9] = ss[3] ^= ss[2]; \ - k[6*(i)+10] = ss[4] ^= ss[3]; k[6*(i)+11] = ss[5] ^= ss[4]; \ -} -#define kel6(k,i) \ -{ k[6*(i)+ 6] = ss[0] ^= ls_box(ss[5],3) ^ rcon_tab[i]; k[6*(i)+ 7] = ss[1] ^= ss[0]; \ - k[6*(i)+ 8] = ss[2] ^= ss[1]; k[6*(i)+ 9] = ss[3] ^= ss[2]; \ +AES_RETURN aes_xi(encrypt_key128)(const unsigned char *key, aes_encrypt_ctx cx[1]) +{ uint32_t ss[4]; + + cx->ks[0] = ss[0] = word_in(key, 0); + cx->ks[1] = ss[1] = word_in(key, 1); + cx->ks[2] = ss[2] = word_in(key, 2); + cx->ks[3] = ss[3] = word_in(key, 3); + +#ifdef ENC_KS_UNROLL + ke4(cx->ks, 0); ke4(cx->ks, 1); + ke4(cx->ks, 2); ke4(cx->ks, 3); + ke4(cx->ks, 4); ke4(cx->ks, 5); + ke4(cx->ks, 6); ke4(cx->ks, 7); + ke4(cx->ks, 8); +#else + { uint32_t i; + for(i = 0; i < 9; ++i) + ke4(cx->ks, i); + } +#endif + ke4(cx->ks, 9); + cx->inf.l = 0; + cx->inf.b[0] = 10 * 16; + +#ifdef USE_VIA_ACE_IF_PRESENT + if(VIA_ACE_AVAILABLE) + cx->inf.b[1] = 0xff; +#endif + return EXIT_SUCCESS; } -#define ke8(k,i) \ -{ k[8*(i)+ 8] = ss[0] ^= ls_box(ss[7],3) ^ rcon_tab[i]; k[8*(i)+ 9] = ss[1] ^= ss[0]; \ - k[8*(i)+10] = ss[2] ^= ss[1]; k[8*(i)+11] = ss[3] ^= ss[2]; \ - k[8*(i)+12] = ss[4] ^= ls_box(ss[3],0); k[8*(i)+13] = ss[5] ^= ss[4]; \ - k[8*(i)+14] = ss[6] ^= ss[5]; k[8*(i)+15] = ss[7] ^= ss[6]; \ +#endif + +#if defined(AES_192) || defined( AES_VAR ) + +#define kef6(k,i) \ +{ k[6*(i)+ 6] = ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; \ + k[6*(i)+ 7] = ss[1] ^= ss[0]; \ + k[6*(i)+ 8] = ss[2] ^= ss[1]; \ + k[6*(i)+ 9] = ss[3] ^= ss[2]; \ } -#define kel8(k,i) \ -{ k[8*(i)+ 8] = ss[0] ^= ls_box(ss[7],3) ^ rcon_tab[i]; k[8*(i)+ 9] = ss[1] ^= ss[0]; \ - k[8*(i)+10] = ss[2] ^= ss[1]; k[8*(i)+11] = ss[3] ^= ss[2]; \ + +#define ke6(k,i) \ +{ kef6(k,i); \ + k[6*(i)+10] = ss[4] ^= ss[3]; \ + k[6*(i)+11] = ss[5] ^= ss[4]; \ } -#if defined(ENCRYPTION_KEY_SCHEDULE) +AES_RETURN aes_xi(encrypt_key192)(const unsigned char *key, aes_encrypt_ctx cx[1]) +{ uint32_t ss[6]; + + cx->ks[0] = ss[0] = word_in(key, 0); + cx->ks[1] = ss[1] = word_in(key, 1); + cx->ks[2] = ss[2] = word_in(key, 2); + cx->ks[3] = ss[3] = word_in(key, 3); + cx->ks[4] = ss[4] = word_in(key, 4); + cx->ks[5] = ss[5] = word_in(key, 5); + +#ifdef ENC_KS_UNROLL + ke6(cx->ks, 0); ke6(cx->ks, 1); + ke6(cx->ks, 2); ke6(cx->ks, 3); + ke6(cx->ks, 4); ke6(cx->ks, 5); + ke6(cx->ks, 6); +#else + { uint32_t i; + for(i = 0; i < 7; ++i) + ke6(cx->ks, i); + } +#endif + kef6(cx->ks, 7); + cx->inf.l = 0; + cx->inf.b[0] = 12 * 16; -aes_rval aes_enc_key(const unsigned char in_key[], unsigned int klen, aes_ctx cx[1]) -{ aes_32t ss[8]; +#ifdef USE_VIA_ACE_IF_PRESENT + if(VIA_ACE_AVAILABLE) + cx->inf.b[1] = 0xff; +#endif + return EXIT_SUCCESS; +} -#if !defined(FIXED_TABLES) - if(!tab_init) gen_tabs(); #endif -#if !defined(BLOCK_SIZE) - if(!cx->n_blk) cx->n_blk = 16; -#else - cx->n_blk = BLOCK_SIZE; -#endif - - cx->n_blk = (cx->n_blk & ~3) | 1; - - cx->k_sch[0] = ss[0] = word_in(in_key ); - cx->k_sch[1] = ss[1] = word_in(in_key + 4); - cx->k_sch[2] = ss[2] = word_in(in_key + 8); - cx->k_sch[3] = ss[3] = word_in(in_key + 12); - -#if (BLOCK_SIZE == 16) && (ENC_UNROLL != NONE) - - switch(klen) - { - case 16: ke4(cx->k_sch, 0); ke4(cx->k_sch, 1); - ke4(cx->k_sch, 2); ke4(cx->k_sch, 3); - ke4(cx->k_sch, 4); ke4(cx->k_sch, 5); - ke4(cx->k_sch, 6); ke4(cx->k_sch, 7); - ke4(cx->k_sch, 8); kel4(cx->k_sch, 9); - cx->n_rnd = 10; break; - case 24: cx->k_sch[4] = ss[4] = word_in(in_key + 16); - cx->k_sch[5] = ss[5] = word_in(in_key + 20); - ke6(cx->k_sch, 0); ke6(cx->k_sch, 1); - ke6(cx->k_sch, 2); ke6(cx->k_sch, 3); - ke6(cx->k_sch, 4); ke6(cx->k_sch, 5); - ke6(cx->k_sch, 6); kel6(cx->k_sch, 7); - cx->n_rnd = 12; break; - case 32: cx->k_sch[4] = ss[4] = word_in(in_key + 16); - cx->k_sch[5] = ss[5] = word_in(in_key + 20); - cx->k_sch[6] = ss[6] = word_in(in_key + 24); - cx->k_sch[7] = ss[7] = word_in(in_key + 28); - ke8(cx->k_sch, 0); ke8(cx->k_sch, 1); - ke8(cx->k_sch, 2); ke8(cx->k_sch, 3); - ke8(cx->k_sch, 4); ke8(cx->k_sch, 5); - kel8(cx->k_sch, 6); - cx->n_rnd = 14; break; - default: cx->n_rnd = 0; return aes_bad; - } +#if defined(AES_256) || defined( AES_VAR ) + +#define kef8(k,i) \ +{ k[8*(i)+ 8] = ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; \ + k[8*(i)+ 9] = ss[1] ^= ss[0]; \ + k[8*(i)+10] = ss[2] ^= ss[1]; \ + k[8*(i)+11] = ss[3] ^= ss[2]; \ +} + +#define ke8(k,i) \ +{ kef8(k,i); \ + k[8*(i)+12] = ss[4] ^= ls_box(ss[3],0); \ + k[8*(i)+13] = ss[5] ^= ss[4]; \ + k[8*(i)+14] = ss[6] ^= ss[5]; \ + k[8*(i)+15] = ss[7] ^= ss[6]; \ +} + +AES_RETURN aes_xi(encrypt_key256)(const unsigned char *key, aes_encrypt_ctx cx[1]) +{ uint32_t ss[8]; + + cx->ks[0] = ss[0] = word_in(key, 0); + cx->ks[1] = ss[1] = word_in(key, 1); + cx->ks[2] = ss[2] = word_in(key, 2); + cx->ks[3] = ss[3] = word_in(key, 3); + cx->ks[4] = ss[4] = word_in(key, 4); + cx->ks[5] = ss[5] = word_in(key, 5); + cx->ks[6] = ss[6] = word_in(key, 6); + cx->ks[7] = ss[7] = word_in(key, 7); + +#ifdef ENC_KS_UNROLL + ke8(cx->ks, 0); ke8(cx->ks, 1); + ke8(cx->ks, 2); ke8(cx->ks, 3); + ke8(cx->ks, 4); ke8(cx->ks, 5); #else - { aes_32t i, l; - cx->n_rnd = ((klen >> 2) > nc ? (klen >> 2) : nc) + 6; - l = (nc * cx->n_rnd + nc - 1) / (klen >> 2); - - switch(klen) - { - case 16: for(i = 0; i < l; ++i) - ke4(cx->k_sch, i); - break; - case 24: cx->k_sch[4] = ss[4] = word_in(in_key + 16); - cx->k_sch[5] = ss[5] = word_in(in_key + 20); - for(i = 0; i < l; ++i) - ke6(cx->k_sch, i); - break; - case 32: cx->k_sch[4] = ss[4] = word_in(in_key + 16); - cx->k_sch[5] = ss[5] = word_in(in_key + 20); - cx->k_sch[6] = ss[6] = word_in(in_key + 24); - cx->k_sch[7] = ss[7] = word_in(in_key + 28); - for(i = 0; i < l; ++i) - ke8(cx->k_sch, i); - break; - default: cx->n_rnd = 0; return aes_bad; - } + { uint32_t i; + for(i = 0; i < 6; ++i) + ke8(cx->ks, i); } #endif + kef8(cx->ks, 6); + cx->inf.l = 0; + cx->inf.b[0] = 14 * 16; - return aes_good; +#ifdef USE_VIA_ACE_IF_PRESENT + if(VIA_ACE_AVAILABLE) + cx->inf.b[1] = 0xff; +#endif + return EXIT_SUCCESS; } #endif -#if defined(DECRYPTION_KEY_SCHEDULE) +#endif -#if (DEC_ROUND != NO_TABLES) -#define d_vars dec_imvars -#define ff(x) inv_mcol(x) +#if (FUNCS_IN_C & DEC_KEYING_IN_C) + +/* this is used to store the decryption round keys */ +/* in forward or reverse order */ + +#ifdef AES_REV_DKS +#define v(n,i) ((n) - (i) + 2 * ((i) & 3)) #else +#define v(n,i) (i) +#endif + +#if DEC_ROUND == NO_TABLES #define ff(x) (x) -#define d_vars +#else +#define ff(x) inv_mcol(x) +#if defined( dec_imvars ) +#define d_vars dec_imvars #endif +#endif + +#if defined(AES_128) || defined( AES_VAR ) + +#define k4e(k,i) \ +{ k[v(40,(4*(i))+4)] = ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; \ + k[v(40,(4*(i))+5)] = ss[1] ^= ss[0]; \ + k[v(40,(4*(i))+6)] = ss[2] ^= ss[1]; \ + k[v(40,(4*(i))+7)] = ss[3] ^= ss[2]; \ +} #if 1 + #define kdf4(k,i) \ -{ ss[0] = ss[0] ^ ss[2] ^ ss[1] ^ ss[3]; ss[1] = ss[1] ^ ss[3]; ss[2] = ss[2] ^ ss[3]; ss[3] = ss[3]; \ - ss[4] = ls_box(ss[(i+3) % 4], 3) ^ rcon_tab[i]; ss[i % 4] ^= ss[4]; \ - ss[4] ^= k[4*(i)]; k[4*(i)+4] = ff(ss[4]); ss[4] ^= k[4*(i)+1]; k[4*(i)+5] = ff(ss[4]); \ - ss[4] ^= k[4*(i)+2]; k[4*(i)+6] = ff(ss[4]); ss[4] ^= k[4*(i)+3]; k[4*(i)+7] = ff(ss[4]); \ +{ ss[0] = ss[0] ^ ss[2] ^ ss[1] ^ ss[3]; \ + ss[1] = ss[1] ^ ss[3]; \ + ss[2] = ss[2] ^ ss[3]; \ + ss[4] = ls_box(ss[(i+3) % 4], 3) ^ t_use(r,c)[i]; \ + ss[i % 4] ^= ss[4]; \ + ss[4] ^= k[v(40,(4*(i)))]; k[v(40,(4*(i))+4)] = ff(ss[4]); \ + ss[4] ^= k[v(40,(4*(i))+1)]; k[v(40,(4*(i))+5)] = ff(ss[4]); \ + ss[4] ^= k[v(40,(4*(i))+2)]; k[v(40,(4*(i))+6)] = ff(ss[4]); \ + ss[4] ^= k[v(40,(4*(i))+3)]; k[v(40,(4*(i))+7)] = ff(ss[4]); \ } + #define kd4(k,i) \ -{ ss[4] = ls_box(ss[(i+3) % 4], 3) ^ rcon_tab[i]; ss[i % 4] ^= ss[4]; ss[4] = ff(ss[4]); \ - k[4*(i)+4] = ss[4] ^= k[4*(i)]; k[4*(i)+5] = ss[4] ^= k[4*(i)+1]; \ - k[4*(i)+6] = ss[4] ^= k[4*(i)+2]; k[4*(i)+7] = ss[4] ^= k[4*(i)+3]; \ +{ ss[4] = ls_box(ss[(i+3) % 4], 3) ^ t_use(r,c)[i]; \ + ss[i % 4] ^= ss[4]; ss[4] = ff(ss[4]); \ + k[v(40,(4*(i))+4)] = ss[4] ^= k[v(40,(4*(i)))]; \ + k[v(40,(4*(i))+5)] = ss[4] ^= k[v(40,(4*(i))+1)]; \ + k[v(40,(4*(i))+6)] = ss[4] ^= k[v(40,(4*(i))+2)]; \ + k[v(40,(4*(i))+7)] = ss[4] ^= k[v(40,(4*(i))+3)]; \ } + #define kdl4(k,i) \ -{ ss[4] = ls_box(ss[(i+3) % 4], 3) ^ rcon_tab[i]; ss[i % 4] ^= ss[4]; \ - k[4*(i)+4] = (ss[0] ^= ss[1]) ^ ss[2] ^ ss[3]; k[4*(i)+5] = ss[1] ^ ss[3]; \ - k[4*(i)+6] = ss[0]; k[4*(i)+7] = ss[1]; \ +{ ss[4] = ls_box(ss[(i+3) % 4], 3) ^ t_use(r,c)[i]; ss[i % 4] ^= ss[4]; \ + k[v(40,(4*(i))+4)] = (ss[0] ^= ss[1]) ^ ss[2] ^ ss[3]; \ + k[v(40,(4*(i))+5)] = ss[1] ^ ss[3]; \ + k[v(40,(4*(i))+6)] = ss[0]; \ + k[v(40,(4*(i))+7)] = ss[1]; \ } + #else + #define kdf4(k,i) \ -{ ss[0] ^= ls_box(ss[3],3) ^ rcon_tab[i]; k[4*(i)+ 4] = ff(ss[0]); ss[1] ^= ss[0]; k[4*(i)+ 5] = ff(ss[1]); \ - ss[2] ^= ss[1]; k[4*(i)+ 6] = ff(ss[2]); ss[3] ^= ss[2]; k[4*(i)+ 7] = ff(ss[3]); \ +{ ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; k[v(40,(4*(i))+ 4)] = ff(ss[0]); \ + ss[1] ^= ss[0]; k[v(40,(4*(i))+ 5)] = ff(ss[1]); \ + ss[2] ^= ss[1]; k[v(40,(4*(i))+ 6)] = ff(ss[2]); \ + ss[3] ^= ss[2]; k[v(40,(4*(i))+ 7)] = ff(ss[3]); \ } + #define kd4(k,i) \ -{ ss[4] = ls_box(ss[3],3) ^ rcon_tab[i]; \ - ss[0] ^= ss[4]; ss[4] = ff(ss[4]); k[4*(i)+ 4] = ss[4] ^= k[4*(i)]; \ - ss[1] ^= ss[0]; k[4*(i)+ 5] = ss[4] ^= k[4*(i)+ 1]; \ - ss[2] ^= ss[1]; k[4*(i)+ 6] = ss[4] ^= k[4*(i)+ 2]; \ - ss[3] ^= ss[2]; k[4*(i)+ 7] = ss[4] ^= k[4*(i)+ 3]; \ +{ ss[4] = ls_box(ss[3],3) ^ t_use(r,c)[i]; \ + ss[0] ^= ss[4]; ss[4] = ff(ss[4]); k[v(40,(4*(i))+ 4)] = ss[4] ^= k[v(40,(4*(i)))]; \ + ss[1] ^= ss[0]; k[v(40,(4*(i))+ 5)] = ss[4] ^= k[v(40,(4*(i))+ 1)]; \ + ss[2] ^= ss[1]; k[v(40,(4*(i))+ 6)] = ss[4] ^= k[v(40,(4*(i))+ 2)]; \ + ss[3] ^= ss[2]; k[v(40,(4*(i))+ 7)] = ss[4] ^= k[v(40,(4*(i))+ 3)]; \ } + #define kdl4(k,i) \ -{ ss[0] ^= ls_box(ss[3],3) ^ rcon_tab[i]; k[4*(i)+ 4] = ss[0]; ss[1] ^= ss[0]; k[4*(i)+ 5] = ss[1]; \ - ss[2] ^= ss[1]; k[4*(i)+ 6] = ss[2]; ss[3] ^= ss[2]; k[4*(i)+ 7] = ss[3]; \ +{ ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; k[v(40,(4*(i))+ 4)] = ss[0]; \ + ss[1] ^= ss[0]; k[v(40,(4*(i))+ 5)] = ss[1]; \ + ss[2] ^= ss[1]; k[v(40,(4*(i))+ 6)] = ss[2]; \ + ss[3] ^= ss[2]; k[v(40,(4*(i))+ 7)] = ss[3]; \ +} + +#endif + +AES_RETURN aes_xi(decrypt_key128)(const unsigned char *key, aes_decrypt_ctx cx[1]) +{ uint32_t ss[5]; +#if defined( d_vars ) + d_vars; +#endif + + cx->ks[v(40,(0))] = ss[0] = word_in(key, 0); + cx->ks[v(40,(1))] = ss[1] = word_in(key, 1); + cx->ks[v(40,(2))] = ss[2] = word_in(key, 2); + cx->ks[v(40,(3))] = ss[3] = word_in(key, 3); + +#ifdef DEC_KS_UNROLL + kdf4(cx->ks, 0); kd4(cx->ks, 1); + kd4(cx->ks, 2); kd4(cx->ks, 3); + kd4(cx->ks, 4); kd4(cx->ks, 5); + kd4(cx->ks, 6); kd4(cx->ks, 7); + kd4(cx->ks, 8); kdl4(cx->ks, 9); +#else + { uint32_t i; + for(i = 0; i < 10; ++i) + k4e(cx->ks, i); +#if !(DEC_ROUND == NO_TABLES) + for(i = N_COLS; i < 10 * N_COLS; ++i) + cx->ks[i] = inv_mcol(cx->ks[i]); +#endif + } +#endif + cx->inf.l = 0; + cx->inf.b[0] = 10 * 16; + +#ifdef USE_VIA_ACE_IF_PRESENT + if(VIA_ACE_AVAILABLE) + cx->inf.b[1] = 0xff; +#endif + return EXIT_SUCCESS; } + #endif +#if defined(AES_192) || defined( AES_VAR ) + +#define k6ef(k,i) \ +{ k[v(48,(6*(i))+ 6)] = ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; \ + k[v(48,(6*(i))+ 7)] = ss[1] ^= ss[0]; \ + k[v(48,(6*(i))+ 8)] = ss[2] ^= ss[1]; \ + k[v(48,(6*(i))+ 9)] = ss[3] ^= ss[2]; \ +} + +#define k6e(k,i) \ +{ k6ef(k,i); \ + k[v(48,(6*(i))+10)] = ss[4] ^= ss[3]; \ + k[v(48,(6*(i))+11)] = ss[5] ^= ss[4]; \ +} + #define kdf6(k,i) \ -{ ss[0] ^= ls_box(ss[5],3) ^ rcon_tab[i]; k[6*(i)+ 6] = ff(ss[0]); ss[1] ^= ss[0]; k[6*(i)+ 7] = ff(ss[1]); \ - ss[2] ^= ss[1]; k[6*(i)+ 8] = ff(ss[2]); ss[3] ^= ss[2]; k[6*(i)+ 9] = ff(ss[3]); \ - ss[4] ^= ss[3]; k[6*(i)+10] = ff(ss[4]); ss[5] ^= ss[4]; k[6*(i)+11] = ff(ss[5]); \ +{ ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; k[v(48,(6*(i))+ 6)] = ff(ss[0]); \ + ss[1] ^= ss[0]; k[v(48,(6*(i))+ 7)] = ff(ss[1]); \ + ss[2] ^= ss[1]; k[v(48,(6*(i))+ 8)] = ff(ss[2]); \ + ss[3] ^= ss[2]; k[v(48,(6*(i))+ 9)] = ff(ss[3]); \ + ss[4] ^= ss[3]; k[v(48,(6*(i))+10)] = ff(ss[4]); \ + ss[5] ^= ss[4]; k[v(48,(6*(i))+11)] = ff(ss[5]); \ } + #define kd6(k,i) \ -{ ss[6] = ls_box(ss[5],3) ^ rcon_tab[i]; \ - ss[0] ^= ss[6]; ss[6] = ff(ss[6]); k[6*(i)+ 6] = ss[6] ^= k[6*(i)]; \ - ss[1] ^= ss[0]; k[6*(i)+ 7] = ss[6] ^= k[6*(i)+ 1]; \ - ss[2] ^= ss[1]; k[6*(i)+ 8] = ss[6] ^= k[6*(i)+ 2]; \ - ss[3] ^= ss[2]; k[6*(i)+ 9] = ss[6] ^= k[6*(i)+ 3]; \ - ss[4] ^= ss[3]; k[6*(i)+10] = ss[6] ^= k[6*(i)+ 4]; \ - ss[5] ^= ss[4]; k[6*(i)+11] = ss[6] ^= k[6*(i)+ 5]; \ +{ ss[6] = ls_box(ss[5],3) ^ t_use(r,c)[i]; \ + ss[0] ^= ss[6]; ss[6] = ff(ss[6]); k[v(48,(6*(i))+ 6)] = ss[6] ^= k[v(48,(6*(i)))]; \ + ss[1] ^= ss[0]; k[v(48,(6*(i))+ 7)] = ss[6] ^= k[v(48,(6*(i))+ 1)]; \ + ss[2] ^= ss[1]; k[v(48,(6*(i))+ 8)] = ss[6] ^= k[v(48,(6*(i))+ 2)]; \ + ss[3] ^= ss[2]; k[v(48,(6*(i))+ 9)] = ss[6] ^= k[v(48,(6*(i))+ 3)]; \ + ss[4] ^= ss[3]; k[v(48,(6*(i))+10)] = ss[6] ^= k[v(48,(6*(i))+ 4)]; \ + ss[5] ^= ss[4]; k[v(48,(6*(i))+11)] = ss[6] ^= k[v(48,(6*(i))+ 5)]; \ } + #define kdl6(k,i) \ -{ ss[0] ^= ls_box(ss[5],3) ^ rcon_tab[i]; k[6*(i)+ 6] = ss[0]; ss[1] ^= ss[0]; k[6*(i)+ 7] = ss[1]; \ - ss[2] ^= ss[1]; k[6*(i)+ 8] = ss[2]; ss[3] ^= ss[2]; k[6*(i)+ 9] = ss[3]; \ +{ ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; k[v(48,(6*(i))+ 6)] = ss[0]; \ + ss[1] ^= ss[0]; k[v(48,(6*(i))+ 7)] = ss[1]; \ + ss[2] ^= ss[1]; k[v(48,(6*(i))+ 8)] = ss[2]; \ + ss[3] ^= ss[2]; k[v(48,(6*(i))+ 9)] = ss[3]; \ +} + +AES_RETURN aes_xi(decrypt_key192)(const unsigned char *key, aes_decrypt_ctx cx[1]) +{ uint32_t ss[7]; +#if defined( d_vars ) + d_vars; +#endif + + cx->ks[v(48,(0))] = ss[0] = word_in(key, 0); + cx->ks[v(48,(1))] = ss[1] = word_in(key, 1); + cx->ks[v(48,(2))] = ss[2] = word_in(key, 2); + cx->ks[v(48,(3))] = ss[3] = word_in(key, 3); + +#ifdef DEC_KS_UNROLL + cx->ks[v(48,(4))] = ff(ss[4] = word_in(key, 4)); + cx->ks[v(48,(5))] = ff(ss[5] = word_in(key, 5)); + kdf6(cx->ks, 0); kd6(cx->ks, 1); + kd6(cx->ks, 2); kd6(cx->ks, 3); + kd6(cx->ks, 4); kd6(cx->ks, 5); + kd6(cx->ks, 6); kdl6(cx->ks, 7); +#else + cx->ks[v(48,(4))] = ss[4] = word_in(key, 4); + cx->ks[v(48,(5))] = ss[5] = word_in(key, 5); + { uint32_t i; + + for(i = 0; i < 7; ++i) + k6e(cx->ks, i); + k6ef(cx->ks, 7); +#if !(DEC_ROUND == NO_TABLES) + for(i = N_COLS; i < 12 * N_COLS; ++i) + cx->ks[i] = inv_mcol(cx->ks[i]); +#endif + } +#endif + cx->inf.l = 0; + cx->inf.b[0] = 12 * 16; + +#ifdef USE_VIA_ACE_IF_PRESENT + if(VIA_ACE_AVAILABLE) + cx->inf.b[1] = 0xff; +#endif + return EXIT_SUCCESS; +} + +#endif + +#if defined(AES_256) || defined( AES_VAR ) + +#define k8ef(k,i) \ +{ k[v(56,(8*(i))+ 8)] = ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; \ + k[v(56,(8*(i))+ 9)] = ss[1] ^= ss[0]; \ + k[v(56,(8*(i))+10)] = ss[2] ^= ss[1]; \ + k[v(56,(8*(i))+11)] = ss[3] ^= ss[2]; \ +} + +#define k8e(k,i) \ +{ k8ef(k,i); \ + k[v(56,(8*(i))+12)] = ss[4] ^= ls_box(ss[3],0); \ + k[v(56,(8*(i))+13)] = ss[5] ^= ss[4]; \ + k[v(56,(8*(i))+14)] = ss[6] ^= ss[5]; \ + k[v(56,(8*(i))+15)] = ss[7] ^= ss[6]; \ } #define kdf8(k,i) \ -{ ss[0] ^= ls_box(ss[7],3) ^ rcon_tab[i]; k[8*(i)+ 8] = ff(ss[0]); ss[1] ^= ss[0]; k[8*(i)+ 9] = ff(ss[1]); \ - ss[2] ^= ss[1]; k[8*(i)+10] = ff(ss[2]); ss[3] ^= ss[2]; k[8*(i)+11] = ff(ss[3]); \ - ss[4] ^= ls_box(ss[3],0); k[8*(i)+12] = ff(ss[4]); ss[5] ^= ss[4]; k[8*(i)+13] = ff(ss[5]); \ - ss[6] ^= ss[5]; k[8*(i)+14] = ff(ss[6]); ss[7] ^= ss[6]; k[8*(i)+15] = ff(ss[7]); \ +{ ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; k[v(56,(8*(i))+ 8)] = ff(ss[0]); \ + ss[1] ^= ss[0]; k[v(56,(8*(i))+ 9)] = ff(ss[1]); \ + ss[2] ^= ss[1]; k[v(56,(8*(i))+10)] = ff(ss[2]); \ + ss[3] ^= ss[2]; k[v(56,(8*(i))+11)] = ff(ss[3]); \ + ss[4] ^= ls_box(ss[3],0); k[v(56,(8*(i))+12)] = ff(ss[4]); \ + ss[5] ^= ss[4]; k[v(56,(8*(i))+13)] = ff(ss[5]); \ + ss[6] ^= ss[5]; k[v(56,(8*(i))+14)] = ff(ss[6]); \ + ss[7] ^= ss[6]; k[v(56,(8*(i))+15)] = ff(ss[7]); \ } + #define kd8(k,i) \ -{ aes_32t g = ls_box(ss[7],3) ^ rcon_tab[i]; \ - ss[0] ^= g; g = ff(g); k[8*(i)+ 8] = g ^= k[8*(i)]; \ - ss[1] ^= ss[0]; k[8*(i)+ 9] = g ^= k[8*(i)+ 1]; \ - ss[2] ^= ss[1]; k[8*(i)+10] = g ^= k[8*(i)+ 2]; \ - ss[3] ^= ss[2]; k[8*(i)+11] = g ^= k[8*(i)+ 3]; \ - g = ls_box(ss[3],0); \ - ss[4] ^= g; g = ff(g); k[8*(i)+12] = g ^= k[8*(i)+ 4]; \ - ss[5] ^= ss[4]; k[8*(i)+13] = g ^= k[8*(i)+ 5]; \ - ss[6] ^= ss[5]; k[8*(i)+14] = g ^= k[8*(i)+ 6]; \ - ss[7] ^= ss[6]; k[8*(i)+15] = g ^= k[8*(i)+ 7]; \ +{ ss[8] = ls_box(ss[7],3) ^ t_use(r,c)[i]; \ + ss[0] ^= ss[8]; ss[8] = ff(ss[8]); k[v(56,(8*(i))+ 8)] = ss[8] ^= k[v(56,(8*(i)))]; \ + ss[1] ^= ss[0]; k[v(56,(8*(i))+ 9)] = ss[8] ^= k[v(56,(8*(i))+ 1)]; \ + ss[2] ^= ss[1]; k[v(56,(8*(i))+10)] = ss[8] ^= k[v(56,(8*(i))+ 2)]; \ + ss[3] ^= ss[2]; k[v(56,(8*(i))+11)] = ss[8] ^= k[v(56,(8*(i))+ 3)]; \ + ss[8] = ls_box(ss[3],0); \ + ss[4] ^= ss[8]; ss[8] = ff(ss[8]); k[v(56,(8*(i))+12)] = ss[8] ^= k[v(56,(8*(i))+ 4)]; \ + ss[5] ^= ss[4]; k[v(56,(8*(i))+13)] = ss[8] ^= k[v(56,(8*(i))+ 5)]; \ + ss[6] ^= ss[5]; k[v(56,(8*(i))+14)] = ss[8] ^= k[v(56,(8*(i))+ 6)]; \ + ss[7] ^= ss[6]; k[v(56,(8*(i))+15)] = ss[8] ^= k[v(56,(8*(i))+ 7)]; \ } + #define kdl8(k,i) \ -{ ss[0] ^= ls_box(ss[7],3) ^ rcon_tab[i]; k[8*(i)+ 8] = ss[0]; ss[1] ^= ss[0]; k[8*(i)+ 9] = ss[1]; \ - ss[2] ^= ss[1]; k[8*(i)+10] = ss[2]; ss[3] ^= ss[2]; k[8*(i)+11] = ss[3]; \ +{ ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; k[v(56,(8*(i))+ 8)] = ss[0]; \ + ss[1] ^= ss[0]; k[v(56,(8*(i))+ 9)] = ss[1]; \ + ss[2] ^= ss[1]; k[v(56,(8*(i))+10)] = ss[2]; \ + ss[3] ^= ss[2]; k[v(56,(8*(i))+11)] = ss[3]; \ } -aes_rval aes_dec_key(const unsigned char in_key[], unsigned int klen, aes_ctx cx[1]) -{ aes_32t ss[8]; - d_vars - -#if !defined(FIXED_TABLES) - if(!tab_init) gen_tabs(); +AES_RETURN aes_xi(decrypt_key256)(const unsigned char *key, aes_decrypt_ctx cx[1]) +{ uint32_t ss[9]; +#if defined( d_vars ) + d_vars; #endif -#if !defined(BLOCK_SIZE) - if(!cx->n_blk) cx->n_blk = 16; -#else - cx->n_blk = BLOCK_SIZE; -#endif - - cx->n_blk = (cx->n_blk & ~3) | 2; - - cx->k_sch[0] = ss[0] = word_in(in_key ); - cx->k_sch[1] = ss[1] = word_in(in_key + 4); - cx->k_sch[2] = ss[2] = word_in(in_key + 8); - cx->k_sch[3] = ss[3] = word_in(in_key + 12); - -#if (BLOCK_SIZE == 16) && (DEC_UNROLL != NONE) - - switch(klen) - { - case 16: kdf4(cx->k_sch, 0); kd4(cx->k_sch, 1); - kd4(cx->k_sch, 2); kd4(cx->k_sch, 3); - kd4(cx->k_sch, 4); kd4(cx->k_sch, 5); - kd4(cx->k_sch, 6); kd4(cx->k_sch, 7); - kd4(cx->k_sch, 8); kdl4(cx->k_sch, 9); - cx->n_rnd = 10; break; - case 24: ss[4] = word_in(in_key + 16); - cx->k_sch[4] = ff(ss[4]); - ss[5] = word_in(in_key + 20); - cx->k_sch[5] = ff(ss[5]); - kdf6(cx->k_sch, 0); kd6(cx->k_sch, 1); - kd6(cx->k_sch, 2); kd6(cx->k_sch, 3); - kd6(cx->k_sch, 4); kd6(cx->k_sch, 5); - kd6(cx->k_sch, 6); kdl6(cx->k_sch, 7); - cx->n_rnd = 12; break; - case 32: ss[4] = word_in(in_key + 16); - cx->k_sch[4] = ff(ss[4]); - ss[5] = word_in(in_key + 20); - cx->k_sch[5] = ff(ss[5]); - ss[6] = word_in(in_key + 24); - cx->k_sch[6] = ff(ss[6]); - ss[7] = word_in(in_key + 28); - cx->k_sch[7] = ff(ss[7]); - kdf8(cx->k_sch, 0); kd8(cx->k_sch, 1); - kd8(cx->k_sch, 2); kd8(cx->k_sch, 3); - kd8(cx->k_sch, 4); kd8(cx->k_sch, 5); - kdl8(cx->k_sch, 6); - cx->n_rnd = 14; break; - default: cx->n_rnd = 0; return aes_bad; - } + cx->ks[v(56,(0))] = ss[0] = word_in(key, 0); + cx->ks[v(56,(1))] = ss[1] = word_in(key, 1); + cx->ks[v(56,(2))] = ss[2] = word_in(key, 2); + cx->ks[v(56,(3))] = ss[3] = word_in(key, 3); + +#ifdef DEC_KS_UNROLL + cx->ks[v(56,(4))] = ff(ss[4] = word_in(key, 4)); + cx->ks[v(56,(5))] = ff(ss[5] = word_in(key, 5)); + cx->ks[v(56,(6))] = ff(ss[6] = word_in(key, 6)); + cx->ks[v(56,(7))] = ff(ss[7] = word_in(key, 7)); + kdf8(cx->ks, 0); kd8(cx->ks, 1); + kd8(cx->ks, 2); kd8(cx->ks, 3); + kd8(cx->ks, 4); kd8(cx->ks, 5); + kdl8(cx->ks, 6); #else - { aes_32t i, l; - cx->n_rnd = ((klen >> 2) > nc ? (klen >> 2) : nc) + 6; - l = (nc * cx->n_rnd + nc - 1) / (klen >> 2); - - switch(klen) - { - case 16: - for(i = 0; i < l; ++i) - ke4(cx->k_sch, i); - break; - case 24: cx->k_sch[4] = ss[4] = word_in(in_key + 16); - cx->k_sch[5] = ss[5] = word_in(in_key + 20); - for(i = 0; i < l; ++i) - ke6(cx->k_sch, i); - break; - case 32: cx->k_sch[4] = ss[4] = word_in(in_key + 16); - cx->k_sch[5] = ss[5] = word_in(in_key + 20); - cx->k_sch[6] = ss[6] = word_in(in_key + 24); - cx->k_sch[7] = ss[7] = word_in(in_key + 28); - for(i = 0; i < l; ++i) - ke8(cx->k_sch, i); - break; - default: cx->n_rnd = 0; return aes_bad; - } -#if (DEC_ROUND != NO_TABLES) - for(i = nc; i < nc * cx->n_rnd; ++i) - cx->k_sch[i] = inv_mcol(cx->k_sch[i]); + cx->ks[v(56,(4))] = ss[4] = word_in(key, 4); + cx->ks[v(56,(5))] = ss[5] = word_in(key, 5); + cx->ks[v(56,(6))] = ss[6] = word_in(key, 6); + cx->ks[v(56,(7))] = ss[7] = word_in(key, 7); + { uint32_t i; + + for(i = 0; i < 6; ++i) + k8e(cx->ks, i); + k8ef(cx->ks, 6); +#if !(DEC_ROUND == NO_TABLES) + for(i = N_COLS; i < 14 * N_COLS; ++i) + cx->ks[i] = inv_mcol(cx->ks[i]); #endif } #endif + cx->inf.l = 0; + cx->inf.b[0] = 14 * 16; - return aes_good; +#ifdef USE_VIA_ACE_IF_PRESENT + if(VIA_ACE_AVAILABLE) + cx->inf.b[1] = 0xff; +#endif + return EXIT_SUCCESS; } #endif + +#endif + +#if defined( AES_VAR ) + +AES_RETURN aes_encrypt_key(const unsigned char *key, int key_len, aes_encrypt_ctx cx[1]) +{ + switch(key_len) + { + case 16: case 128: return aes_encrypt_key128(key, cx); + case 24: case 192: return aes_encrypt_key192(key, cx); + case 32: case 256: return aes_encrypt_key256(key, cx); + default: return EXIT_FAILURE; + } +} + +AES_RETURN aes_decrypt_key(const unsigned char *key, int key_len, aes_decrypt_ctx cx[1]) +{ + switch(key_len) + { + case 16: case 128: return aes_decrypt_key128(key, cx); + case 24: case 192: return aes_decrypt_key192(key, cx); + case 32: case 256: return aes_decrypt_key256(key, cx); + default: return EXIT_FAILURE; + } +} + +#endif + +#if defined(__cplusplus) +} +#endif diff --git a/aesopt.h b/aesopt.h index 485d5ec3e..d3ac0f9be 100644 --- a/aesopt.h +++ b/aesopt.h @@ -1,294 +1,126 @@ /* - ------------------------------------------------------------------------- - Copyright (c) 2001, Dr Brian Gladman < >, Worcester, UK. - All rights reserved. +--------------------------------------------------------------------------- +Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved. - LICENSE TERMS +The redistribution and use of this software (with or without changes) +is allowed without the payment of fees or royalties provided that: - The free distribution and use of this software in both source and binary - form is allowed (with or without changes) provided that: + source code distributions include the above copyright notice, this + list of conditions and the following disclaimer; - 1. distributions of this source code include the above copyright - notice, this list of conditions and the following disclaimer; + binary distributions include the above copyright notice, this list + of conditions and the following disclaimer in their documentation. - 2. distributions in binary form include the above copyright - notice, this list of conditions and the following disclaimer - in the documentation and/or other associated materials; - - 3. the copyright holder's name is not used to endorse products - built using this software without specific written permission. - - DISCLAIMER - - This software is provided 'as is' with no explicit or implied warranties - in respect of its properties, including, but not limited to, correctness - and fitness for purpose. - ------------------------------------------------------------------------- - Issue Date: 29/07/2002 +This software is provided 'as is' with no explicit or implied warranties +in respect of its operation, including, but not limited to, correctness +and fitness for purpose. +--------------------------------------------------------------------------- +Issue Date: 20/12/2007 This file contains the compilation options for AES (Rijndael) and code that is common across encryption, key scheduling and table generation. - OPERATION - - These source code files implement the AES algorithm Rijndael designed by - Joan Daemen and Vincent Rijmen. The version in aes.c is designed for - block and key sizes of 128, 192 and 256 bits (16, 24 and 32 bytes) while - that in aespp.c provides for block and keys sizes of 128, 160, 192, 224 - and 256 bits (16, 20, 24, 28 and 32 bytes). This file is a common header - file for these two implementations and for aesref.c, which is a reference - implementation. - - This version is designed for flexibility and speed using operations on - 32-bit words rather than operations on bytes. It provides aes_both fixed - and dynamic block and key lengths and can also run with either big or - little endian internal byte order (see aes.h). It inputs block and key - lengths in bytes with the legal values being 16, 24 and 32 for aes.c and - 16, 20, 24, 28 and 32 for aespp.c - - THE CIPHER INTERFACE - - aes_08t (an unsigned 8-bit type) - aes_32t (an unsigned 32-bit type) - aes_fret (a signed 16 bit type for function return values) - aes_good (value != 0, a good return) - aes_bad (value == 0, an error return) - struct aes_ctx (structure for the cipher encryption context) - struct aes_ctx (structure for the cipher decryption context) - aes_rval the function return type (aes_fret if not DLL) - - C subroutine calls: - - aes_rval aes_blk_len(unsigned int blen, aes_ctx cx[1]); - aes_rval aes_enc_key(const unsigned char in_key[], unsigned int klen, aes_ctx cx[1]); - aes_rval aes_enc_blk(const unsigned char in_blk[], unsigned char out_blk[], const aes_ctx cx[1]); - - aes_rval aes_dec_len(unsigned int blen, aes_ctx cx[1]); - aes_rval aes_dec_key(const unsigned char in_key[], unsigned int klen, aes_ctx cx[1]); - aes_rval aes_dec_blk(const unsigned char in_blk[], unsigned char out_blk[], const aes_ctx cx[1]); - - IMPORTANT NOTE: If you are using this C interface and your compiler does - not set the memory used for objects to zero before use, you will need to - ensure that cx.s_flg is set to zero before using these subroutine calls. - - C++ aes class subroutines: - - class AESclass for encryption - class AESclass for decryption - - aes_rval len(unsigned int blen = 16); - aes_rval key(const unsigned char in_key[], unsigned int klen); - aes_rval blk(const unsigned char in_blk[], unsigned char out_blk[]); - - aes_rval len(unsigned int blen = 16); - aes_rval key(const unsigned char in_key[], unsigned int klen); - aes_rval blk(const unsigned char in_blk[], unsigned char out_blk[]); - - The block length inputs to set_block and set_key are in numbers of - BYTES, not bits. The calls to subroutines must be made in the above - order but multiple calls can be made without repeating earlier calls - if their parameters have not changed. If the cipher block length is - variable but set_blk has not been called before cipher operations a - value of 16 is assumed (that is, the AES block size). In contrast to - earlier versions the block and key length parameters are now checked - for correctness and the encryption and decryption routines check to - ensure that an appropriate key has been set before they are called. - - COMPILATION - - The files used to provide AES (Rijndael) are - - a. aes.h for the definitions needed for use in C. - b. aescpp.h for the definitions needed for use in C++. - c. aesopt.h for setting compilation options (also includes common - code). - d. aescrypt.c for encryption and decrytpion, or - e. aescrypt.asm for encryption and decryption using assembler code. - f. aeskey.c for key scheduling. - g. aestab.c for table loading or generation. - - The assembler code uses the NASM assembler. The above files provice - block and key lengths of 16, 24 and 32 bytes (128, 192 and 256 bits). - If aescrypp.c and aeskeypp.c are used instead of aescrypt.c and - aeskey.c respectively, the block and key lengths can then be 16, 20, - 24, 28 or 32 bytes. However this code has not been optimised to the - same extent and is hence slower (esepcially for the AES block size - of 16 bytes). - - To compile AES (Rijndael) for use in C code use aes.h and exclude - the AES_DLL define in aes.h - - To compile AES (Rijndael) for use in in C++ code use aescpp.h and - exclude the AES_DLL define in aes.h - - To compile AES (Rijndael) in C as a Dynamic Link Library DLL) use - aes.h, include the AES_DLL define and compile the DLL. If using - the test files to test the DLL, exclude aes.c from the test build - project and compile it with the same defines as used for the DLL - (ensure that the DLL path is correct) - - CONFIGURATION OPTIONS (here and in aes.h) - - a. define BLOCK_SIZE in aes.h to set the cipher block size (16, 24 - or 32 for the standard code, or 16, 20, 24, 28 or 32 for the - extended code) or leave this undefined for dynamically variable - block size (this will result in much slower code). - b. set AES_DLL in aes.h if AES (Rijndael) is to be compiled as a DLL - c. You may need to set PLATFORM_BYTE_ORDER to define the byte order. - d. If you want the code to run in a specific internal byte order, then - INTERNAL_BYTE_ORDER must be set accordingly. - e. set other configuration options decribed below. + OPERATION + + These source code files implement the AES algorithm Rijndael designed by + Joan Daemen and Vincent Rijmen. This version is designed for the standard + block size of 16 bytes and for key sizes of 128, 192 and 256 bits (16, 24 + and 32 bytes). + + This version is designed for flexibility and speed using operations on + 32-bit words rather than operations on bytes. It can be compiled with + either big or little endian internal byte order but is faster when the + native byte order for the processor is used. + + THE CIPHER INTERFACE + + The cipher interface is implemented as an array of bytes in which lower + AES bit sequence indexes map to higher numeric significance within bytes. + + uint8_t (an unsigned 8-bit type) + uint32_t (an unsigned 32-bit type) + struct aes_encrypt_ctx (structure for the cipher encryption context) + struct aes_decrypt_ctx (structure for the cipher decryption context) + AES_RETURN the function return type + + C subroutine calls: + + AES_RETURN aes_encrypt_key128(const unsigned char *key, aes_encrypt_ctx cx[1]); + AES_RETURN aes_encrypt_key192(const unsigned char *key, aes_encrypt_ctx cx[1]); + AES_RETURN aes_encrypt_key256(const unsigned char *key, aes_encrypt_ctx cx[1]); + AES_RETURN aes_encrypt(const unsigned char *in, unsigned char *out, + const aes_encrypt_ctx cx[1]); + + AES_RETURN aes_decrypt_key128(const unsigned char *key, aes_decrypt_ctx cx[1]); + AES_RETURN aes_decrypt_key192(const unsigned char *key, aes_decrypt_ctx cx[1]); + AES_RETURN aes_decrypt_key256(const unsigned char *key, aes_decrypt_ctx cx[1]); + AES_RETURN aes_decrypt(const unsigned char *in, unsigned char *out, + const aes_decrypt_ctx cx[1]); + + IMPORTANT NOTE: If you are using this C interface with dynamic tables make sure that + you call aes_init() before AES is used so that the tables are initialised. + + C++ aes class subroutines: + + Class AESencrypt for encryption + + Construtors: + AESencrypt(void) + AESencrypt(const unsigned char *key) - 128 bit key + Members: + AES_RETURN key128(const unsigned char *key) + AES_RETURN key192(const unsigned char *key) + AES_RETURN key256(const unsigned char *key) + AES_RETURN encrypt(const unsigned char *in, unsigned char *out) const + + Class AESdecrypt for encryption + Construtors: + AESdecrypt(void) + AESdecrypt(const unsigned char *key) - 128 bit key + Members: + AES_RETURN key128(const unsigned char *key) + AES_RETURN key192(const unsigned char *key) + AES_RETURN key256(const unsigned char *key) + AES_RETURN decrypt(const unsigned char *in, unsigned char *out) const */ -#ifndef _AESOPT_H +#if !defined( _AESOPT_H ) #define _AESOPT_H -/* START OF CONFIGURATION OPTIONS - - USE OF DEFINES - - Later in this section there are a number of defines that control the - operation of the code. In each section, the purpose of each define is - explained so that the relevant form can be included or excluded by - setting either 1's or 0's respectively on the branches of the related - #if clauses. -*/ - -/* 1. PLATFORM SPECIFIC INCLUDES */ - -#include "aes.h" -#define PLATFORM_BYTE_ORDER AES_LITTLE_ENDIAN - -/* -#if defined( __CRYPTLIB__ ) && !defined( INC_ALL ) && !defined( INC_CHILD ) -#include "crypt/aes.h" +#if defined( __cplusplus ) +#include "aescpp.h" #else - #include "aes.h" -#endif - -#if defined(__GNUC__) || defined(__GNU_LIBRARY__) -//# include -//# include -#elif defined(__CRYPTLIB__) -# if defined( INC_ALL ) -# include "crypt.h" -# elif defined( INC_CHILD ) -# include "../crypt.h" -# else -# include "crypt.h" -# endif -# if defined(DATA_LITTLEENDIAN) -# define PLATFORM_BYTE_ORDER AES_LITTLE_ENDIAN -# else -# define PLATFORM_BYTE_ORDER AES_BIG_ENDIAN -# endif -#elif defined(_MSC_VER) -# include -#elif !defined(WIN32) -# include -# if !defined (_ENDIAN_H) -# include -# else -# include _ENDIAN_H -# endif -#endif -*/ - -/* 2. BYTE ORDER IN 32-BIT WORDS - - To obtain the highest speed on processors with 32-bit words, this code - needs to determine the order in which bytes are packed into such words. - The following block of code is an attempt to capture the most obvious - ways in which various environemnts define byte order. It may well fail, - in which case the definitions will need to be set by editing at the - points marked **** EDIT HERE IF NECESSARY **** below. -*/ -#define AES_LITTLE_ENDIAN 1234 /* byte 0 is least significant (i386) */ -#define AES_BIG_ENDIAN 4321 /* byte 0 is most significant (mc68k) */ - -#if !defined(PLATFORM_BYTE_ORDER) -#if defined(LITTLE_ENDIAN) || defined(BIG_ENDIAN) -# if defined(LITTLE_ENDIAN) && defined(BIG_ENDIAN) -# if defined(BYTE_ORDER) -# if (BYTE_ORDER == LITTLE_ENDIAN) -# define PLATFORM_BYTE_ORDER AES_LITTLE_ENDIAN -# elif (BYTE_ORDER == BIG_ENDIAN) -# define PLATFORM_BYTE_ORDER AES_BIG_ENDIAN -# endif -# endif -# elif defined(LITTLE_ENDIAN) && !defined(BIG_ENDIAN) -# define PLATFORM_BYTE_ORDER AES_LITTLE_ENDIAN -# elif !defined(LITTLE_ENDIAN) && defined(BIG_ENDIAN) -# define PLATFORM_BYTE_ORDER AES_BIG_ENDIAN -# endif -#elif defined(_LITTLE_ENDIAN) || defined(_BIG_ENDIAN) -# if defined(_LITTLE_ENDIAN) && defined(_BIG_ENDIAN) -# if defined(_BYTE_ORDER) -# if (_BYTE_ORDER == _LITTLE_ENDIAN) -# define PLATFORM_BYTE_ORDER AES_LITTLE_ENDIAN -# elif (_BYTE_ORDER == _BIG_ENDIAN) -# define PLATFORM_BYTE_ORDER AES_BIG_ENDIAN -# endif -# endif -# elif defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN) -# define PLATFORM_BYTE_ORDER AES_LITTLE_ENDIAN -# elif !defined(_LITTLE_ENDIAN) && defined(_BIG_ENDIAN) -# define PLATFORM_BYTE_ORDER AES_BIG_ENDIAN -# endif -#elif 0 /* **** EDIT HERE IF NECESSARY **** */ -#define PLATFORM_BYTE_ORDER AES_LITTLE_ENDIAN -#elif 0 /* **** EDIT HERE IF NECESSARY **** */ -#define PLATFORM_BYTE_ORDER AES_BIG_ENDIAN -/* -#elif (('1234' >> 24) == '1') -# define PLATFORM_BYTE_ORDER AES_LITTLE_ENDIAN -#elif (('4321' >> 24) == '1') -# define PLATFORM_BYTE_ORDER AES_BIG_ENDIAN -*/ -#endif -#endif - -#if !defined(PLATFORM_BYTE_ORDER) -# error Please set undetermined byte order (lines 233 or 235 of aesopt.h). +#include "aes.h" #endif -/* 3. ASSEMBLER SUPPORT +/* PLATFORM SPECIFIC INCLUDES */ - If the assembler code is used for encryption and decryption this file only - provides key scheduling so the following defines are used -*/ -#ifdef AES_ASM -#define ENCRYPTION_KEY_SCHEDULE -#define DECRYPTION_KEY_SCHEDULE -#else +#include "brg_endian.h" -/* 4. FUNCTIONS REQUIRED +/* CONFIGURATION - THE USE OF DEFINES - This implementation provides five main subroutines which provide for - setting block length, setting encryption and decryption keys and for - encryption and decryption. When the assembler code is not being used - the following definition blocks allow the selection of the routines - that are to be included in the compilation. + Later in this section there are a number of defines that control the + operation of the code. In each section, the purpose of each define is + explained so that the relevant form can be included or excluded by + setting either 1's or 0's respectively on the branches of the related + #if clauses. The following local defines should not be changed. */ -#if 1 -#define ENCRYPTION_KEY_SCHEDULE -#endif -#if 1 -#define DECRYPTION_KEY_SCHEDULE -#endif +#define ENCRYPTION_IN_C 1 +#define DECRYPTION_IN_C 2 +#define ENC_KEYING_IN_C 4 +#define DEC_KEYING_IN_C 8 -#if 1 -#define ENCRYPTION -#endif +#define NO_TABLES 0 +#define ONE_TABLE 1 +#define FOUR_TABLES 4 +#define NONE 0 +#define PARTIAL 1 +#define FULL 2 -#if 1 -#define DECRYPTION -#endif - -#endif +/* --- START OF USER CONFIGURED OPTIONS --- */ -/* 5. BYTE ORDER WITHIN 32 BIT WORDS +/* 1. BYTE ORDER WITHIN 32 BIT WORDS The fundamental data processing units in Rijndael are 8-bit bytes. The input, output and key input are all enumerated arrays of bytes in which @@ -314,16 +146,111 @@ machine on which it runs. Normally the internal byte order will be set to the order of the processor on which the code is to be run but this define can be used to reverse this in special situations + + WARNING: Assembler code versions rely on PLATFORM_BYTE_ORDER being set. + This define will hence be redefined later (in section 4) if necessary */ + #if 1 -#define INTERNAL_BYTE_ORDER PLATFORM_BYTE_ORDER -#elif defined(AES_LITTLE_ENDIAN) -#define INTERNAL_BYTE_ORDER AES_LITTLE_ENDIAN -#elif defined(AES_BIG_ENDIAN) -#define INTERNAL_BYTE_ORDER AES_BIG_ENDIAN +# define ALGORITHM_BYTE_ORDER PLATFORM_BYTE_ORDER +#elif 0 +# define ALGORITHM_BYTE_ORDER IS_LITTLE_ENDIAN +#elif 0 +# define ALGORITHM_BYTE_ORDER IS_BIG_ENDIAN +#else +# error The algorithm byte order is not defined +#endif + +/* 2. Intel AES AND VIA ACE SUPPORT */ + +#if defined( __GNUC__ ) && defined( __i386__ ) \ + || defined(_WIN32) && defined(_M_IX86) \ + && !(defined(_WIN64) || defined(_WIN32_WCE) || defined(_MSC_VER) && (_MSC_VER <= 800)) +# define VIA_ACE_POSSIBLE +#endif + +/* Define this option if support for the Intel AESNI is required (not + currently available with GCC). If AESNI is known to be present, then + defining ASSUME_INTEL_AES_VIA_PRESENT will replace the ordinary + encryption/decryption. If USE_INTEL_AES_IF_PRESENT is defined then + AESNI will be used if it is detected (both present and enabled). + + AESNI uses a decryption key schedule with the first decryption + round key at the high end of the key scedule with the following + round keys at lower positions in memory. So AES_REV_DKS must NOT + be defined when AESNI will be used. ALthough it is unlikely that + assembler code will be used with an AESNI build, if it is then + AES_REV_DKS must NOT be defined when such assembler files are + built +*/ +#if 1 && defined( _WIN64 ) && defined( _MSC_VER ) +# define INTEL_AES_POSSIBLE +#endif + +#if defined( INTEL_AES_POSSIBLE ) && !defined( USE_INTEL_AES_IF_PRESENT ) +# define USE_INTEL_AES_IF_PRESENT +#endif + +/* Define this option if support for the VIA ACE is required. This uses + inline assembler instructions and is only implemented for the Microsoft, + Intel and GCC compilers. If VIA ACE is known to be present, then defining + ASSUME_VIA_ACE_PRESENT will remove the ordinary encryption/decryption + code. If USE_VIA_ACE_IF_PRESENT is defined then VIA ACE will be used if + it is detected (both present and enabled) but the normal AES code will + also be present. + + When VIA ACE is to be used, all AES encryption contexts MUST be 16 byte + aligned; other input/output buffers do not need to be 16 byte aligned + but there are very large performance gains if this can be arranged. + VIA ACE also requires the decryption key schedule to be in reverse + order (which later checks below ensure). + + AES_REV_DKS must be set for assembler code used with a VIA ACE build +*/ + +#if 1 && defined( VIA_ACE_POSSIBLE ) && !defined( USE_VIA_ACE_IF_PRESENT ) +# define USE_VIA_ACE_IF_PRESENT #endif -/* 6. FAST INPUT/OUTPUT OPERATIONS. +#if 0 && defined( VIA_ACE_POSSIBLE ) && !defined( ASSUME_VIA_ACE_PRESENT ) +# define ASSUME_VIA_ACE_PRESENT +# endif + +/* 3. ASSEMBLER SUPPORT + + This define (which can be on the command line) enables the use of the + assembler code routines for encryption, decryption and key scheduling + as follows: + + ASM_X86_V1C uses the assembler (aes_x86_v1.asm) with large tables for + encryption and decryption and but with key scheduling in C + ASM_X86_V2 uses assembler (aes_x86_v2.asm) with compressed tables for + encryption, decryption and key scheduling + ASM_X86_V2C uses assembler (aes_x86_v2.asm) with compressed tables for + encryption and decryption and but with key scheduling in C + ASM_AMD64_C uses assembler (aes_amd64.asm) with compressed tables for + encryption and decryption and but with key scheduling in C + + Change one 'if 0' below to 'if 1' to select the version or define + as a compilation option. +*/ + +#if 0 && !defined( ASM_X86_V1C ) +# define ASM_X86_V1C +#elif 0 && !defined( ASM_X86_V2 ) +# define ASM_X86_V2 +#elif 0 && !defined( ASM_X86_V2C ) +# define ASM_X86_V2C +#elif 0 && !defined( ASM_AMD64_C ) +# define ASM_AMD64_C +#endif + +#if (defined ( ASM_X86_V1C ) || defined( ASM_X86_V2 ) || defined( ASM_X86_V2C )) \ + && !defined( _M_IX86 ) || defined( ASM_AMD64_C ) && !defined( _M_X64 ) +# error Assembler code is only available for x86 and AMD64 systems +#endif + +/* 4. FAST INPUT/OUTPUT OPERATIONS. On some machines it is possible to improve speed by transferring the bytes in the input and output arrays to and from the internal 32-bit @@ -339,11 +266,11 @@ assumed that access to byte arrays as if they are arrays of 32-bit words will not cause problems when such accesses are misaligned. */ -#if 1 -#define SAFE_IO +#if 1 && !defined( _MSC_VER ) +# define SAFE_IO #endif -/* 7. LOOP UNROLLING +/* 5. LOOP UNROLLING The code for encryption and decrytpion cycles through a number of rounds that can be implemented either in a loop or by expanding the code into a @@ -355,41 +282,39 @@ to be set independently for encryption and decryption */ #if 1 -#define ENC_UNROLL FULL +# define ENC_UNROLL FULL #elif 0 -#define ENC_UNROLL PARTIAL +# define ENC_UNROLL PARTIAL #else -#define ENC_UNROLL NONE +# define ENC_UNROLL NONE #endif #if 1 -#define DEC_UNROLL FULL +# define DEC_UNROLL FULL #elif 0 -#define DEC_UNROLL PARTIAL +# define DEC_UNROLL PARTIAL #else -#define DEC_UNROLL NONE +# define DEC_UNROLL NONE #endif -/* 8. FIXED OR DYNAMIC TABLES +#if 1 +# define ENC_KS_UNROLL +#endif - When this section is included the tables used by the code are comipled - statically into the binary file. Otherwise they are computed once when - the code is first used. -*/ #if 1 -#define FIXED_TABLES +# define DEC_KS_UNROLL #endif -/* 9. FAST FINITE FIELD OPERATIONS +/* 6. FAST FINITE FIELD OPERATIONS If this section is included, tables are used to provide faster finite field arithmetic (this has no effect if FIXED_TABLES is defined). */ #if 1 -#define FF_TABLES +# define FF_TABLES #endif -/* 10. INTERNAL STATE VARIABLE FORMAT +/* 7. INTERNAL STATE VARIABLE FORMAT The internal state of Rijndael is stored in a number of local 32-bit word varaibles which can be defined either as an array or as individual @@ -397,37 +322,54 @@ varaibles in arrays. Otherwise individual local variables will be used. */ #if 1 -#define ARRAYS +# define ARRAYS #endif -/* In this implementation the columns of the state array are each held in - 32-bit words. The state array can be held in various ways: in an array - of words, in a number of individual word variables or in a number of - processor registers. The following define maps a variable name x and - a column number c to the way the state array variable is to be held. - The first define below maps the state into an array x[c] whereas the - second form maps the state into a number of individual variables x0, - x1, etc. Another form could map individual state colums to machine - register names. +/* 8. FIXED OR DYNAMIC TABLES + + When this section is included the tables used by the code are compiled + statically into the binary file. Otherwise the subroutine aes_init() + must be called to compute them before the code is first used. */ +#if 1 && !(defined( _MSC_VER ) && ( _MSC_VER <= 800 )) +# define FIXED_TABLES +#endif + +/* 9. MASKING OR CASTING FROM LONGER VALUES TO BYTES -#if defined(ARRAYS) -#define s(x,c) x[c] + In some systems it is better to mask longer values to extract bytes + rather than using a cast. This option allows this choice. +*/ +#if 0 +# define to_byte(x) ((uint8_t)(x)) #else -#define s(x,c) x##c +# define to_byte(x) ((x) & 0xff) #endif -/* 11. VARIABLE BLOCK SIZE SPEED +/* 10. TABLE ALIGNMENT - This section is only relevant if you wish to use the variable block - length feature of the code. Include this section if you place more - emphasis on speed rather than code size. + On some sytsems speed will be improved by aligning the AES large lookup + tables on particular boundaries. This define should be set to a power of + two giving the desired alignment. It can be left undefined if alignment + is not needed. This option is specific to the Microsft VC++ compiler - + it seems to sometimes cause trouble for the VC++ version 6 compiler. */ -#if 1 -#define FAST_VARIABLE + +#if 1 && defined( _MSC_VER ) && ( _MSC_VER >= 1300 ) +# define TABLE_ALIGN 32 +#endif + +/* 11. REDUCE CODE AND TABLE SIZE + + This replaces some expanded macros with function calls if AES_ASM_V2 or + AES_ASM_V2C are defined +*/ + +#if 1 && (defined( ASM_X86_V2 ) || defined( ASM_X86_V2C )) +# define REDUCE_CODE_SIZE #endif -/* 12. INTERNAL TABLE CONFIGURATION +/* 12. TABLE OPTIONS This cipher proceeds by repeating in a number of cycles known as 'rounds' which are implemented by a round function which can optionally be speeded @@ -448,35 +390,35 @@ */ #if 1 /* set tables for the normal encryption round */ -#define ENC_ROUND FOUR_TABLES +# define ENC_ROUND FOUR_TABLES #elif 0 -#define ENC_ROUND ONE_TABLE +# define ENC_ROUND ONE_TABLE #else -#define ENC_ROUND NO_TABLES +# define ENC_ROUND NO_TABLES #endif #if 1 /* set tables for the last encryption round */ -#define LAST_ENC_ROUND FOUR_TABLES +# define LAST_ENC_ROUND FOUR_TABLES #elif 0 -#define LAST_ENC_ROUND ONE_TABLE +# define LAST_ENC_ROUND ONE_TABLE #else -#define LAST_ENC_ROUND NO_TABLES +# define LAST_ENC_ROUND NO_TABLES #endif #if 1 /* set tables for the normal decryption round */ -#define DEC_ROUND FOUR_TABLES +# define DEC_ROUND FOUR_TABLES #elif 0 -#define DEC_ROUND ONE_TABLE +# define DEC_ROUND ONE_TABLE #else -#define DEC_ROUND NO_TABLES +# define DEC_ROUND NO_TABLES #endif #if 1 /* set tables for the last decryption round */ -#define LAST_DEC_ROUND FOUR_TABLES +# define LAST_DEC_ROUND FOUR_TABLES #elif 0 -#define LAST_DEC_ROUND ONE_TABLE +# define LAST_DEC_ROUND ONE_TABLE #else -#define LAST_DEC_ROUND NO_TABLES +# define LAST_DEC_ROUND NO_TABLES #endif /* The decryption key schedule can be speeded up with tables in the same @@ -484,290 +426,278 @@ defines to set this requirement. */ #if 1 -#define KEY_SCHED FOUR_TABLES +# define KEY_SCHED FOUR_TABLES #elif 0 -#define KEY_SCHED ONE_TABLE +# define KEY_SCHED ONE_TABLE #else -#define KEY_SCHED NO_TABLES +# define KEY_SCHED NO_TABLES #endif -/* END OF CONFIGURATION OPTIONS */ +/* ---- END OF USER CONFIGURED OPTIONS ---- */ -#define NO_TABLES 0 /* DO NOT CHANGE */ -#define ONE_TABLE 1 /* DO NOT CHANGE */ -#define FOUR_TABLES 4 /* DO NOT CHANGE */ -#define NONE 0 /* DO NOT CHANGE */ -#define PARTIAL 1 /* DO NOT CHANGE */ -#define FULL 2 /* DO NOT CHANGE */ +/* VIA ACE support is only available for VC++ and GCC */ -#if defined(BLOCK_SIZE) && ((BLOCK_SIZE & 3) || BLOCK_SIZE < 16 || BLOCK_SIZE > 32) -#error An illegal block size has been specified. +#if !defined( _MSC_VER ) && !defined( __GNUC__ ) +# if defined( ASSUME_VIA_ACE_PRESENT ) +# undef ASSUME_VIA_ACE_PRESENT +# endif +# if defined( USE_VIA_ACE_IF_PRESENT ) +# undef USE_VIA_ACE_IF_PRESENT +# endif #endif -#if !defined(BLOCK_SIZE) -#define RC_LENGTH 29 -#else -#define RC_LENGTH 5 * BLOCK_SIZE / 4 - (BLOCK_SIZE == 16 ? 10 : 11) +#if defined( ASSUME_VIA_ACE_PRESENT ) && !defined( USE_VIA_ACE_IF_PRESENT ) +# define USE_VIA_ACE_IF_PRESENT #endif -/* Disable at least some poor combinations of options */ - -#if ENC_ROUND == NO_TABLES && LAST_ENC_ROUND != NO_TABLES -#undef LAST_ENC_ROUND -#define LAST_ENC_ROUND NO_TABLES -#elif ENC_ROUND == ONE_TABLE && LAST_ENC_ROUND == FOUR_TABLES -#undef LAST_ENC_ROUND -#define LAST_ENC_ROUND ONE_TABLE +/* define to reverse decryption key schedule */ +#if 1 || defined( USE_VIA_ACE_IF_PRESENT ) && !defined ( AES_REV_DKS ) +# define AES_REV_DKS #endif -#if ENC_ROUND == NO_TABLES && ENC_UNROLL != NONE -#undef ENC_UNROLL -#define ENC_UNROLL NONE +/* Intel AESNI uses a decryption key schedule in the encryption order */ +#if defined( USE_INTEL_AES_IF_PRESENT ) && defined ( AES_REV_DKS ) +# undef AES_REV_DKS #endif -#if DEC_ROUND == NO_TABLES && LAST_DEC_ROUND != NO_TABLES -#undef LAST_DEC_ROUND -#define LAST_DEC_ROUND NO_TABLES -#elif DEC_ROUND == ONE_TABLE && LAST_DEC_ROUND == FOUR_TABLES -#undef LAST_DEC_ROUND -#define LAST_DEC_ROUND ONE_TABLE -#endif +/* Assembler support requires the use of platform byte order */ -#if DEC_ROUND == NO_TABLES && DEC_UNROLL != NONE -#undef DEC_UNROLL -#define DEC_UNROLL NONE +#if ( defined( ASM_X86_V1C ) || defined( ASM_X86_V2C ) || defined( ASM_AMD64_C ) ) \ + && (ALGORITHM_BYTE_ORDER != PLATFORM_BYTE_ORDER) +# undef ALGORITHM_BYTE_ORDER +# define ALGORITHM_BYTE_ORDER PLATFORM_BYTE_ORDER #endif -/* upr(x,n): rotates bytes within words by n positions, moving bytes to - higher index positions with wrap around into low positions - ups(x,n): moves bytes by n positions to higher index positions in - words but without wrap around - bval(x,n): extracts a byte from a word - - NOTE: The definitions given here are intended only for use with - unsigned variables and with shift counts that are compile - time constants +/* In this implementation the columns of the state array are each held in + 32-bit words. The state array can be held in various ways: in an array + of words, in a number of individual word variables or in a number of + processor registers. The following define maps a variable name x and + a column number c to the way the state array variable is to be held. + The first define below maps the state into an array x[c] whereas the + second form maps the state into a number of individual variables x0, + x1, etc. Another form could map individual state colums to machine + register names. */ -#if (INTERNAL_BYTE_ORDER == AES_LITTLE_ENDIAN) -#if defined(_MSC_VER) -#define upr(x,n) _lrotl((aes_32t)(x), 8 * (n)) +#if defined( ARRAYS ) +# define s(x,c) x[c] #else -#define upr(x,n) ((aes_32t)(x) << 8 * (n) | (aes_32t)(x) >> 32 - 8 * (n)) -#endif -#define ups(x,n) ((aes_32t)(x) << 8 * (n)) -#define bval(x,n) ((aes_08t)((x) >> 8 * (n))) -#define bytes2word(b0, b1, b2, b3) \ - (((aes_32t)(b3) << 24) | ((aes_32t)(b2) << 16) | ((aes_32t)(b1) << 8) | (b0)) +# define s(x,c) x##c #endif -#if (INTERNAL_BYTE_ORDER == AES_BIG_ENDIAN) -#define upr(x,n) ((aes_32t)(x) >> 8 * (n) | (aes_32t)(x) << 32 - 8 * (n)) -#define ups(x,n) ((aes_32t)(x) >> 8 * (n))) -#define bval(x,n) ((aes_08t)((x) >> 24 - 8 * (n))) -#define bytes2word(b0, b1, b2, b3) \ - (((aes_32t)(b0) << 24) | ((aes_32t)(b1) << 16) | ((aes_32t)(b2) << 8) | (b3)) -#endif - -#if defined(SAFE_IO) - -#define word_in(x) bytes2word((x)[0], (x)[1], (x)[2], (x)[3]) -#define word_out(x,v) { (x)[0] = bval(v,0); (x)[1] = bval(v,1); \ - (x)[2] = bval(v,2); (x)[3] = bval(v,3); } - -#elif (INTERNAL_BYTE_ORDER == PLATFORM_BYTE_ORDER) - -#define word_in(x) *(aes_32t*)(x) -#define word_out(x,v) *(aes_32t*)(x) = (v) +/* This implementation provides subroutines for encryption, decryption + and for setting the three key lengths (separately) for encryption + and decryption. Since not all functions are needed, masks are set + up here to determine which will be implemented in C +*/ +#if !defined( AES_ENCRYPT ) +# define EFUNCS_IN_C 0 +#elif defined( ASSUME_VIA_ACE_PRESENT ) || defined( ASM_X86_V1C ) \ + || defined( ASM_X86_V2C ) || defined( ASM_AMD64_C ) +# define EFUNCS_IN_C ENC_KEYING_IN_C +#elif !defined( ASM_X86_V2 ) +# define EFUNCS_IN_C ( ENCRYPTION_IN_C | ENC_KEYING_IN_C ) #else - -#if !defined(bswap_32) -#if !defined(_MSC_VER) -#define _lrotl(x,n) ((aes_32t)(x) << n | (aes_32t)(x) >> 32 - n) +# define EFUNCS_IN_C 0 #endif -#define bswap_32(x) ((_lrotl((x),8) & 0x00ff00ff) | (_lrotl((x),24) & 0xff00ff00)) -#endif - -#define word_in(x) bswap_32(*(aes_32t*)(x)) -#define word_out(x,v) *(aes_32t*)(x) = bswap_32(v) +#if !defined( AES_DECRYPT ) +# define DFUNCS_IN_C 0 +#elif defined( ASSUME_VIA_ACE_PRESENT ) || defined( ASM_X86_V1C ) \ + || defined( ASM_X86_V2C ) || defined( ASM_AMD64_C ) +# define DFUNCS_IN_C DEC_KEYING_IN_C +#elif !defined( ASM_X86_V2 ) +# define DFUNCS_IN_C ( DECRYPTION_IN_C | DEC_KEYING_IN_C ) +#else +# define DFUNCS_IN_C 0 #endif -/* the finite field modular polynomial and elements */ - -#define WPOLY 0x011b -#define BPOLY 0x1b +#define FUNCS_IN_C ( EFUNCS_IN_C | DFUNCS_IN_C ) -/* multiply four bytes in GF(2^8) by 'x' {02} in parallel */ - -#define m1 0x80808080 -#define m2 0x7f7f7f7f -#define FFmulX(x) ((((x) & m2) << 1) ^ ((((x) & m1) >> 7) * BPOLY)) +/* END OF CONFIGURATION OPTIONS */ -/* The following defines provide alternative definitions of FFmulX that might - give improved performance if a fast 32-bit multiply is not available. Note - that a temporary variable u needs to be defined where FFmulX is used. +#define RC_LENGTH (5 * (AES_BLOCK_SIZE / 4 - 2)) -#define FFmulX(x) (u = (x) & m1, u |= (u >> 1), ((x) & m2) << 1) ^ ((u >> 3) | (u >> 6)) -#define m4 (0x01010101 * BPOLY) -#define FFmulX(x) (u = (x) & m1, ((x) & m2) << 1) ^ ((u - (u >> 7)) & m4) -*/ +/* Disable or report errors on some combinations of options */ -/* Work out which tables are needed for the different options */ - -#ifdef AES_ASM -#ifdef ENC_ROUND -#undef ENC_ROUND -#endif -#define ENC_ROUND FOUR_TABLES -#ifdef LAST_ENC_ROUND -#undef LAST_ENC_ROUND -#endif -#define LAST_ENC_ROUND FOUR_TABLES -#ifdef DEC_ROUND -#undef DEC_ROUND -#endif -#define DEC_ROUND FOUR_TABLES -#ifdef LAST_DEC_ROUND -#undef LAST_DEC_ROUND -#endif -#define LAST_DEC_ROUND FOUR_TABLES -#ifdef KEY_SCHED -#undef KEY_SCHED -#define KEY_SCHED FOUR_TABLES -#endif +#if ENC_ROUND == NO_TABLES && LAST_ENC_ROUND != NO_TABLES +# undef LAST_ENC_ROUND +# define LAST_ENC_ROUND NO_TABLES +#elif ENC_ROUND == ONE_TABLE && LAST_ENC_ROUND == FOUR_TABLES +# undef LAST_ENC_ROUND +# define LAST_ENC_ROUND ONE_TABLE #endif -#if defined(ENCRYPTION) || defined(AES_ASM) -#if ENC_ROUND == ONE_TABLE -#define FT1_SET -#elif ENC_ROUND == FOUR_TABLES -#define FT4_SET -#else -#define SBX_SET -#endif -#if LAST_ENC_ROUND == ONE_TABLE -#define FL1_SET -#elif LAST_ENC_ROUND == FOUR_TABLES -#define FL4_SET -#elif !defined(SBX_SET) -#define SBX_SET -#endif +#if ENC_ROUND == NO_TABLES && ENC_UNROLL != NONE +# undef ENC_UNROLL +# define ENC_UNROLL NONE #endif -#if defined(DECRYPTION) || defined(AES_ASM) -#if DEC_ROUND == ONE_TABLE -#define IT1_SET -#elif DEC_ROUND == FOUR_TABLES -#define IT4_SET -#else -#define ISB_SET -#endif -#if LAST_DEC_ROUND == ONE_TABLE -#define IL1_SET -#elif LAST_DEC_ROUND == FOUR_TABLES -#define IL4_SET -#elif !defined(ISB_SET) -#define ISB_SET -#endif +#if DEC_ROUND == NO_TABLES && LAST_DEC_ROUND != NO_TABLES +# undef LAST_DEC_ROUND +# define LAST_DEC_ROUND NO_TABLES +#elif DEC_ROUND == ONE_TABLE && LAST_DEC_ROUND == FOUR_TABLES +# undef LAST_DEC_ROUND +# define LAST_DEC_ROUND ONE_TABLE #endif -#if defined(ENCRYPTION_KEY_SCHEDULE) || defined(DECRYPTION_KEY_SCHEDULE) -#if KEY_SCHED == ONE_TABLE -#define LS1_SET -#define IM1_SET -#elif KEY_SCHED == FOUR_TABLES -#define LS4_SET -#define IM4_SET -#elif !defined(SBX_SET) -#define SBX_SET -#endif +#if DEC_ROUND == NO_TABLES && DEC_UNROLL != NONE +# undef DEC_UNROLL +# define DEC_UNROLL NONE #endif -#ifdef FIXED_TABLES -#define prefx extern const +#if defined( bswap32 ) +# define aes_sw32 bswap32 +#elif defined( bswap_32 ) +# define aes_sw32 bswap_32 #else -#define prefx extern -extern aes_08t tab_init; -void gen_tabs(void); -#endif - -prefx aes_32t rcon_tab[29]; - -#ifdef SBX_SET -prefx aes_08t s_box[256]; +# define brot(x,n) (((uint32_t)(x) << n) | ((uint32_t)(x) >> (32 - n))) +# define aes_sw32(x) ((brot((x),8) & 0x00ff00ff) | (brot((x),24) & 0xff00ff00)) #endif -#ifdef ISB_SET -prefx aes_08t inv_s_box[256]; -#endif +/* upr(x,n): rotates bytes within words by n positions, moving bytes to + higher index positions with wrap around into low positions + ups(x,n): moves bytes by n positions to higher index positions in + words but without wrap around + bval(x,n): extracts a byte from a word -#ifdef FT1_SET -prefx aes_32t ft_tab[256]; -#endif + WARNING: The definitions given here are intended only for use with + unsigned variables and with shift counts that are compile + time constants +*/ -#ifdef FT4_SET -prefx aes_32t ft_tab[4][256]; +#if ( ALGORITHM_BYTE_ORDER == IS_LITTLE_ENDIAN ) +# define upr(x,n) (((uint32_t)(x) << (8 * (n))) | ((uint32_t)(x) >> (32 - 8 * (n)))) +# define ups(x,n) ((uint32_t) (x) << (8 * (n))) +# define bval(x,n) to_byte((x) >> (8 * (n))) +# define bytes2word(b0, b1, b2, b3) \ + (((uint32_t)(b3) << 24) | ((uint32_t)(b2) << 16) | ((uint32_t)(b1) << 8) | (b0)) +#endif + +#if ( ALGORITHM_BYTE_ORDER == IS_BIG_ENDIAN ) +# define upr(x,n) (((uint32_t)(x) >> (8 * (n))) | ((uint32_t)(x) << (32 - 8 * (n)))) +# define ups(x,n) ((uint32_t) (x) >> (8 * (n))) +# define bval(x,n) to_byte((x) >> (24 - 8 * (n))) +# define bytes2word(b0, b1, b2, b3) \ + (((uint32_t)(b0) << 24) | ((uint32_t)(b1) << 16) | ((uint32_t)(b2) << 8) | (b3)) +#endif + +#if defined( SAFE_IO ) +# define word_in(x,c) bytes2word(((const uint8_t*)(x)+4*c)[0], ((const uint8_t*)(x)+4*c)[1], \ + ((const uint8_t*)(x)+4*c)[2], ((const uint8_t*)(x)+4*c)[3]) +# define word_out(x,c,v) { ((uint8_t*)(x)+4*c)[0] = bval(v,0); ((uint8_t*)(x)+4*c)[1] = bval(v,1); \ + ((uint8_t*)(x)+4*c)[2] = bval(v,2); ((uint8_t*)(x)+4*c)[3] = bval(v,3); } +#elif ( ALGORITHM_BYTE_ORDER == PLATFORM_BYTE_ORDER ) +# define word_in(x,c) (*((uint32_t*)(x)+(c))) +# define word_out(x,c,v) (*((uint32_t*)(x)+(c)) = (v)) +#else +# define word_in(x,c) aes_sw32(*((uint32_t*)(x)+(c))) +# define word_out(x,c,v) (*((uint32_t*)(x)+(c)) = aes_sw32(v)) #endif -#ifdef FL1_SET -prefx aes_32t fl_tab[256]; -#endif +/* the finite field modular polynomial and elements */ -#ifdef FL4_SET -prefx aes_32t fl_tab[4][256]; -#endif +#define WPOLY 0x011b +#define BPOLY 0x1b -#ifdef IT1_SET -prefx aes_32t it_tab[256]; -#endif +/* multiply four bytes in GF(2^8) by 'x' {02} in parallel */ -#ifdef IT4_SET -prefx aes_32t it_tab[4][256]; -#endif +#define gf_c1 0x80808080 +#define gf_c2 0x7f7f7f7f +#define gf_mulx(x) ((((x) & gf_c2) << 1) ^ ((((x) & gf_c1) >> 7) * BPOLY)) -#ifdef IL1_SET -prefx aes_32t il_tab[256]; -#endif +/* The following defines provide alternative definitions of gf_mulx that might + give improved performance if a fast 32-bit multiply is not available. Note + that a temporary variable u needs to be defined where gf_mulx is used. -#ifdef IL4_SET -prefx aes_32t il_tab[4][256]; -#endif +#define gf_mulx(x) (u = (x) & gf_c1, u |= (u >> 1), ((x) & gf_c2) << 1) ^ ((u >> 3) | (u >> 6)) +#define gf_c4 (0x01010101 * BPOLY) +#define gf_mulx(x) (u = (x) & gf_c1, ((x) & gf_c2) << 1) ^ ((u - (u >> 7)) & gf_c4) +*/ -#ifdef LS1_SET -#ifdef FL1_SET -#undef LS1_SET -#else -prefx aes_32t ls_tab[256]; -#endif -#endif +/* Work out which tables are needed for the different options */ -#ifdef LS4_SET -#ifdef FL4_SET -#undef LS4_SET -#else -prefx aes_32t ls_tab[4][256]; -#endif +#if defined( ASM_X86_V1C ) +# if defined( ENC_ROUND ) +# undef ENC_ROUND +# endif +# define ENC_ROUND FOUR_TABLES +# if defined( LAST_ENC_ROUND ) +# undef LAST_ENC_ROUND +# endif +# define LAST_ENC_ROUND FOUR_TABLES +# if defined( DEC_ROUND ) +# undef DEC_ROUND +# endif +# define DEC_ROUND FOUR_TABLES +# if defined( LAST_DEC_ROUND ) +# undef LAST_DEC_ROUND +# endif +# define LAST_DEC_ROUND FOUR_TABLES +# if defined( KEY_SCHED ) +# undef KEY_SCHED +# define KEY_SCHED FOUR_TABLES +# endif #endif -#ifdef IM1_SET -prefx aes_32t im_tab[256]; +#if ( FUNCS_IN_C & ENCRYPTION_IN_C ) || defined( ASM_X86_V1C ) +# if ENC_ROUND == ONE_TABLE +# define FT1_SET +# elif ENC_ROUND == FOUR_TABLES +# define FT4_SET +# else +# define SBX_SET +# endif +# if LAST_ENC_ROUND == ONE_TABLE +# define FL1_SET +# elif LAST_ENC_ROUND == FOUR_TABLES +# define FL4_SET +# elif !defined( SBX_SET ) +# define SBX_SET +# endif #endif -#ifdef IM4_SET -prefx aes_32t im_tab[4][256]; +#if ( FUNCS_IN_C & DECRYPTION_IN_C ) || defined( ASM_X86_V1C ) +# if DEC_ROUND == ONE_TABLE +# define IT1_SET +# elif DEC_ROUND == FOUR_TABLES +# define IT4_SET +# else +# define ISB_SET +# endif +# if LAST_DEC_ROUND == ONE_TABLE +# define IL1_SET +# elif LAST_DEC_ROUND == FOUR_TABLES +# define IL4_SET +# elif !defined(ISB_SET) +# define ISB_SET +# endif #endif -/* Set the number of columns in nc. Note that it is important - that nc is a constant which is known at compile time if the - highest speed version of the code is needed. -*/ - -#if defined(BLOCK_SIZE) -#define nc (BLOCK_SIZE >> 2) -#else -#define nc (cx->n_blk >> 2) +#if !(defined( REDUCE_CODE_SIZE ) && (defined( ASM_X86_V2 ) || defined( ASM_X86_V2C ))) +# if ((FUNCS_IN_C & ENC_KEYING_IN_C) || (FUNCS_IN_C & DEC_KEYING_IN_C)) +# if KEY_SCHED == ONE_TABLE +# if !defined( FL1_SET ) && !defined( FL4_SET ) +# define LS1_SET +# endif +# elif KEY_SCHED == FOUR_TABLES +# if !defined( FL4_SET ) +# define LS4_SET +# endif +# elif !defined( SBX_SET ) +# define SBX_SET +# endif +# endif +# if (FUNCS_IN_C & DEC_KEYING_IN_C) +# if KEY_SCHED == ONE_TABLE +# define IM1_SET +# elif KEY_SCHED == FOUR_TABLES +# define IM4_SET +# elif !defined( SBX_SET ) +# define SBX_SET +# endif +# endif #endif /* generic definitions of Rijndael macros that use tables */ @@ -792,45 +722,48 @@ prefx aes_32t im_tab[4][256]; #define vf1(x,r,c) (x) #define rf1(r,c) (r) -#define rf2(r,c) ((r-c)&3) +#define rf2(r,c) ((8+r-c)&3) /* perform forward and inverse column mix operation on four bytes in long word x in */ /* parallel. NOTE: x must be a simple variable, NOT an expression in these macros. */ -#define dec_fmvars -#if defined(FM4_SET) /* not currently used */ -#define fwd_mcol(x) four_tables(x,fm_tab,vf1,rf1,0) -#elif defined(FM1_SET) /* not currently used */ -#define fwd_mcol(x) one_table(x,upr,fm_tab,vf1,rf1,0) +#if !(defined( REDUCE_CODE_SIZE ) && (defined( ASM_X86_V2 ) || defined( ASM_X86_V2C ))) + +#if defined( FM4_SET ) /* not currently used */ +# define fwd_mcol(x) four_tables(x,t_use(f,m),vf1,rf1,0) +#elif defined( FM1_SET ) /* not currently used */ +# define fwd_mcol(x) one_table(x,upr,t_use(f,m),vf1,rf1,0) #else -#undef dec_fmvars -#define dec_fmvars aes_32t f1, f2; -#define fwd_mcol(x) (f1 = (x), f2 = FFmulX(f1), f2 ^ upr(f1 ^ f2, 3) ^ upr(f1, 2) ^ upr(f1, 1)) +# define dec_fmvars uint32_t g2 +# define fwd_mcol(x) (g2 = gf_mulx(x), g2 ^ upr((x) ^ g2, 3) ^ upr((x), 2) ^ upr((x), 1)) #endif -#define dec_imvars -#if defined(IM4_SET) -#define inv_mcol(x) four_tables(x,im_tab,vf1,rf1,0) -#elif defined(IM1_SET) -#define inv_mcol(x) one_table(x,upr,im_tab,vf1,rf1,0) +#if defined( IM4_SET ) +# define inv_mcol(x) four_tables(x,t_use(i,m),vf1,rf1,0) +#elif defined( IM1_SET ) +# define inv_mcol(x) one_table(x,upr,t_use(i,m),vf1,rf1,0) #else -#undef dec_imvars -#define dec_imvars aes_32t f2, f4, f8, f9; -#define inv_mcol(x) \ - (f9 = (x), f2 = FFmulX(f9), f4 = FFmulX(f2), f8 = FFmulX(f4), f9 ^= f8, \ - f2 ^= f4 ^ f8 ^ upr(f2 ^ f9,3) ^ upr(f4 ^ f9,2) ^ upr(f9,1)) -#endif - -#if defined(FL4_SET) -#define ls_box(x,c) four_tables(x,fl_tab,vf1,rf2,c) -#elif defined(LS4_SET) -#define ls_box(x,c) four_tables(x,ls_tab,vf1,rf2,c) -#elif defined(FL1_SET) -#define ls_box(x,c) one_table(x,upr,fl_tab,vf1,rf2,c) -#elif defined(LS1_SET) -#define ls_box(x,c) one_table(x,upr,ls_tab,vf1,rf2,c) +# define dec_imvars uint32_t g2, g4, g9 +# define inv_mcol(x) (g2 = gf_mulx(x), g4 = gf_mulx(g2), g9 = (x) ^ gf_mulx(g4), g4 ^= g9, \ + (x) ^ g2 ^ g4 ^ upr(g2 ^ g9, 3) ^ upr(g4, 2) ^ upr(g9, 1)) +#endif + +#if defined( FL4_SET ) +# define ls_box(x,c) four_tables(x,t_use(f,l),vf1,rf2,c) +#elif defined( LS4_SET ) +# define ls_box(x,c) four_tables(x,t_use(l,s),vf1,rf2,c) +#elif defined( FL1_SET ) +# define ls_box(x,c) one_table(x,upr,t_use(f,l),vf1,rf2,c) +#elif defined( LS1_SET ) +# define ls_box(x,c) one_table(x,upr,t_use(l,s),vf1,rf2,c) #else -#define ls_box(x,c) no_table(x,s_box,vf1,rf2,c) +# define ls_box(x,c) no_table(x,t_use(s,box),vf1,rf2,c) +#endif + +#endif + +#if defined( ASM_X86_V1C ) && defined( AES_DECRYPT ) && !defined( ISB_SET ) +# define ISB_SET #endif #endif diff --git a/aestab.c b/aestab.c index cbfa70d20..8fd11f94a 100644 --- a/aestab.c +++ b/aestab.c @@ -1,181 +1,143 @@ /* -------------------------------------------------------------------------- -Copyright (c) 2001, Dr Brian Gladman < >, Worcester, UK. -All rights reserved. +--------------------------------------------------------------------------- +Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved. -LICENSE TERMS +The redistribution and use of this software (with or without changes) +is allowed without the payment of fees or royalties provided that: -The free distribution and use of this software in both source and binary -form is allowed (with or without changes) provided that: + source code distributions include the above copyright notice, this + list of conditions and the following disclaimer; -1. distributions of this source code include the above copyright -notice, this list of conditions and the following disclaimer; - -2. distributions in binary form include the above copyright -notice, this list of conditions and the following disclaimer -in the documentation and/or other associated materials; - -3. the copyright holder's name is not used to endorse products -built using this software without specific written permission. - -DISCLAIMER + binary distributions include the above copyright notice, this list + of conditions and the following disclaimer in their documentation. This software is provided 'as is' with no explicit or implied warranties -in respect of its properties, including, but not limited to, correctness +in respect of its operation, including, but not limited to, correctness and fitness for purpose. -------------------------------------------------------------------------- -Issue Date: 29/07/2002 +--------------------------------------------------------------------------- +Issue Date: 20/12/2007 */ -#include "aesopt.h" - -#if defined(FIXED_TABLES) || !defined(FF_TABLES) - -/* finite field arithmetic operations */ - -#define f2(x) ((x<<1) ^ (((x>>7) & 1) * WPOLY)) -#define f4(x) ((x<<2) ^ (((x>>6) & 1) * WPOLY) ^ (((x>>6) & 2) * WPOLY)) -#define f8(x) ((x<<3) ^ (((x>>5) & 1) * WPOLY) ^ (((x>>5) & 2) * WPOLY) \ -^ (((x>>5) & 4) * WPOLY)) -#define f3(x) (f2(x) ^ x) -#define f9(x) (f8(x) ^ x) -#define fb(x) (f8(x) ^ f2(x) ^ x) -#define fd(x) (f8(x) ^ f4(x) ^ x) -#define fe(x) (f8(x) ^ f4(x) ^ f2(x)) +#define DO_TABLES -#endif +#include "aes.h" +#include "aesopt.h" #if defined(FIXED_TABLES) -#define sb_data(w) \ -w(0x63), w(0x7c), w(0x77), w(0x7b), w(0xf2), w(0x6b), w(0x6f), w(0xc5),\ -w(0x30), w(0x01), w(0x67), w(0x2b), w(0xfe), w(0xd7), w(0xab), w(0x76),\ -w(0xca), w(0x82), w(0xc9), w(0x7d), w(0xfa), w(0x59), w(0x47), w(0xf0),\ -w(0xad), w(0xd4), w(0xa2), w(0xaf), w(0x9c), w(0xa4), w(0x72), w(0xc0),\ -w(0xb7), w(0xfd), w(0x93), w(0x26), w(0x36), w(0x3f), w(0xf7), w(0xcc),\ -w(0x34), w(0xa5), w(0xe5), w(0xf1), w(0x71), w(0xd8), w(0x31), w(0x15),\ -w(0x04), w(0xc7), w(0x23), w(0xc3), w(0x18), w(0x96), w(0x05), w(0x9a),\ -w(0x07), w(0x12), w(0x80), w(0xe2), w(0xeb), w(0x27), w(0xb2), w(0x75),\ -w(0x09), w(0x83), w(0x2c), w(0x1a), w(0x1b), w(0x6e), w(0x5a), w(0xa0),\ -w(0x52), w(0x3b), w(0xd6), w(0xb3), w(0x29), w(0xe3), w(0x2f), w(0x84),\ -w(0x53), w(0xd1), w(0x00), w(0xed), w(0x20), w(0xfc), w(0xb1), w(0x5b),\ -w(0x6a), w(0xcb), w(0xbe), w(0x39), w(0x4a), w(0x4c), w(0x58), w(0xcf),\ -w(0xd0), w(0xef), w(0xaa), w(0xfb), w(0x43), w(0x4d), w(0x33), w(0x85),\ -w(0x45), w(0xf9), w(0x02), w(0x7f), w(0x50), w(0x3c), w(0x9f), w(0xa8),\ -w(0x51), w(0xa3), w(0x40), w(0x8f), w(0x92), w(0x9d), w(0x38), w(0xf5),\ -w(0xbc), w(0xb6), w(0xda), w(0x21), w(0x10), w(0xff), w(0xf3), w(0xd2),\ -w(0xcd), w(0x0c), w(0x13), w(0xec), w(0x5f), w(0x97), w(0x44), w(0x17),\ -w(0xc4), w(0xa7), w(0x7e), w(0x3d), w(0x64), w(0x5d), w(0x19), w(0x73),\ -w(0x60), w(0x81), w(0x4f), w(0xdc), w(0x22), w(0x2a), w(0x90), w(0x88),\ -w(0x46), w(0xee), w(0xb8), w(0x14), w(0xde), w(0x5e), w(0x0b), w(0xdb),\ -w(0xe0), w(0x32), w(0x3a), w(0x0a), w(0x49), w(0x06), w(0x24), w(0x5c),\ -w(0xc2), w(0xd3), w(0xac), w(0x62), w(0x91), w(0x95), w(0xe4), w(0x79),\ -w(0xe7), w(0xc8), w(0x37), w(0x6d), w(0x8d), w(0xd5), w(0x4e), w(0xa9),\ -w(0x6c), w(0x56), w(0xf4), w(0xea), w(0x65), w(0x7a), w(0xae), w(0x08),\ -w(0xba), w(0x78), w(0x25), w(0x2e), w(0x1c), w(0xa6), w(0xb4), w(0xc6),\ -w(0xe8), w(0xdd), w(0x74), w(0x1f), w(0x4b), w(0xbd), w(0x8b), w(0x8a),\ -w(0x70), w(0x3e), w(0xb5), w(0x66), w(0x48), w(0x03), w(0xf6), w(0x0e),\ -w(0x61), w(0x35), w(0x57), w(0xb9), w(0x86), w(0xc1), w(0x1d), w(0x9e),\ -w(0xe1), w(0xf8), w(0x98), w(0x11), w(0x69), w(0xd9), w(0x8e), w(0x94),\ -w(0x9b), w(0x1e), w(0x87), w(0xe9), w(0xce), w(0x55), w(0x28), w(0xdf),\ -w(0x8c), w(0xa1), w(0x89), w(0x0d), w(0xbf), w(0xe6), w(0x42), w(0x68),\ -w(0x41), w(0x99), w(0x2d), w(0x0f), w(0xb0), w(0x54), w(0xbb), w(0x16) - -#define isb_data(w) \ -w(0x52), w(0x09), w(0x6a), w(0xd5), w(0x30), w(0x36), w(0xa5), w(0x38),\ -w(0xbf), w(0x40), w(0xa3), w(0x9e), w(0x81), w(0xf3), w(0xd7), w(0xfb),\ -w(0x7c), w(0xe3), w(0x39), w(0x82), w(0x9b), w(0x2f), w(0xff), w(0x87),\ -w(0x34), w(0x8e), w(0x43), w(0x44), w(0xc4), w(0xde), w(0xe9), w(0xcb),\ -w(0x54), w(0x7b), w(0x94), w(0x32), w(0xa6), w(0xc2), w(0x23), w(0x3d),\ -w(0xee), w(0x4c), w(0x95), w(0x0b), w(0x42), w(0xfa), w(0xc3), w(0x4e),\ -w(0x08), w(0x2e), w(0xa1), w(0x66), w(0x28), w(0xd9), w(0x24), w(0xb2),\ -w(0x76), w(0x5b), w(0xa2), w(0x49), w(0x6d), w(0x8b), w(0xd1), w(0x25),\ -w(0x72), w(0xf8), w(0xf6), w(0x64), w(0x86), w(0x68), w(0x98), w(0x16),\ -w(0xd4), w(0xa4), w(0x5c), w(0xcc), w(0x5d), w(0x65), w(0xb6), w(0x92),\ -w(0x6c), w(0x70), w(0x48), w(0x50), w(0xfd), w(0xed), w(0xb9), w(0xda),\ -w(0x5e), w(0x15), w(0x46), w(0x57), w(0xa7), w(0x8d), w(0x9d), w(0x84),\ -w(0x90), w(0xd8), w(0xab), w(0x00), w(0x8c), w(0xbc), w(0xd3), w(0x0a),\ -w(0xf7), w(0xe4), w(0x58), w(0x05), w(0xb8), w(0xb3), w(0x45), w(0x06),\ -w(0xd0), w(0x2c), w(0x1e), w(0x8f), w(0xca), w(0x3f), w(0x0f), w(0x02),\ -w(0xc1), w(0xaf), w(0xbd), w(0x03), w(0x01), w(0x13), w(0x8a), w(0x6b),\ -w(0x3a), w(0x91), w(0x11), w(0x41), w(0x4f), w(0x67), w(0xdc), w(0xea),\ -w(0x97), w(0xf2), w(0xcf), w(0xce), w(0xf0), w(0xb4), w(0xe6), w(0x73),\ -w(0x96), w(0xac), w(0x74), w(0x22), w(0xe7), w(0xad), w(0x35), w(0x85),\ -w(0xe2), w(0xf9), w(0x37), w(0xe8), w(0x1c), w(0x75), w(0xdf), w(0x6e),\ -w(0x47), w(0xf1), w(0x1a), w(0x71), w(0x1d), w(0x29), w(0xc5), w(0x89),\ -w(0x6f), w(0xb7), w(0x62), w(0x0e), w(0xaa), w(0x18), w(0xbe), w(0x1b),\ -w(0xfc), w(0x56), w(0x3e), w(0x4b), w(0xc6), w(0xd2), w(0x79), w(0x20),\ -w(0x9a), w(0xdb), w(0xc0), w(0xfe), w(0x78), w(0xcd), w(0x5a), w(0xf4),\ -w(0x1f), w(0xdd), w(0xa8), w(0x33), w(0x88), w(0x07), w(0xc7), w(0x31),\ -w(0xb1), w(0x12), w(0x10), w(0x59), w(0x27), w(0x80), w(0xec), w(0x5f),\ -w(0x60), w(0x51), w(0x7f), w(0xa9), w(0x19), w(0xb5), w(0x4a), w(0x0d),\ -w(0x2d), w(0xe5), w(0x7a), w(0x9f), w(0x93), w(0xc9), w(0x9c), w(0xef),\ -w(0xa0), w(0xe0), w(0x3b), w(0x4d), w(0xae), w(0x2a), w(0xf5), w(0xb0),\ -w(0xc8), w(0xeb), w(0xbb), w(0x3c), w(0x83), w(0x53), w(0x99), w(0x61),\ -w(0x17), w(0x2b), w(0x04), w(0x7e), w(0xba), w(0x77), w(0xd6), w(0x26),\ -w(0xe1), w(0x69), w(0x14), w(0x63), w(0x55), w(0x21), w(0x0c), w(0x7d), - -#define mm_data(w) \ -w(0x00), w(0x01), w(0x02), w(0x03), w(0x04), w(0x05), w(0x06), w(0x07),\ -w(0x08), w(0x09), w(0x0a), w(0x0b), w(0x0c), w(0x0d), w(0x0e), w(0x0f),\ -w(0x10), w(0x11), w(0x12), w(0x13), w(0x14), w(0x15), w(0x16), w(0x17),\ -w(0x18), w(0x19), w(0x1a), w(0x1b), w(0x1c), w(0x1d), w(0x1e), w(0x1f),\ -w(0x20), w(0x21), w(0x22), w(0x23), w(0x24), w(0x25), w(0x26), w(0x27),\ -w(0x28), w(0x29), w(0x2a), w(0x2b), w(0x2c), w(0x2d), w(0x2e), w(0x2f),\ -w(0x30), w(0x31), w(0x32), w(0x33), w(0x34), w(0x35), w(0x36), w(0x37),\ -w(0x38), w(0x39), w(0x3a), w(0x3b), w(0x3c), w(0x3d), w(0x3e), w(0x3f),\ -w(0x40), w(0x41), w(0x42), w(0x43), w(0x44), w(0x45), w(0x46), w(0x47),\ -w(0x48), w(0x49), w(0x4a), w(0x4b), w(0x4c), w(0x4d), w(0x4e), w(0x4f),\ -w(0x50), w(0x51), w(0x52), w(0x53), w(0x54), w(0x55), w(0x56), w(0x57),\ -w(0x58), w(0x59), w(0x5a), w(0x5b), w(0x5c), w(0x5d), w(0x5e), w(0x5f),\ -w(0x60), w(0x61), w(0x62), w(0x63), w(0x64), w(0x65), w(0x66), w(0x67),\ -w(0x68), w(0x69), w(0x6a), w(0x6b), w(0x6c), w(0x6d), w(0x6e), w(0x6f),\ -w(0x70), w(0x71), w(0x72), w(0x73), w(0x74), w(0x75), w(0x76), w(0x77),\ -w(0x78), w(0x79), w(0x7a), w(0x7b), w(0x7c), w(0x7d), w(0x7e), w(0x7f),\ -w(0x80), w(0x81), w(0x82), w(0x83), w(0x84), w(0x85), w(0x86), w(0x87),\ -w(0x88), w(0x89), w(0x8a), w(0x8b), w(0x8c), w(0x8d), w(0x8e), w(0x8f),\ -w(0x90), w(0x91), w(0x92), w(0x93), w(0x94), w(0x95), w(0x96), w(0x97),\ -w(0x98), w(0x99), w(0x9a), w(0x9b), w(0x9c), w(0x9d), w(0x9e), w(0x9f),\ -w(0xa0), w(0xa1), w(0xa2), w(0xa3), w(0xa4), w(0xa5), w(0xa6), w(0xa7),\ -w(0xa8), w(0xa9), w(0xaa), w(0xab), w(0xac), w(0xad), w(0xae), w(0xaf),\ -w(0xb0), w(0xb1), w(0xb2), w(0xb3), w(0xb4), w(0xb5), w(0xb6), w(0xb7),\ -w(0xb8), w(0xb9), w(0xba), w(0xbb), w(0xbc), w(0xbd), w(0xbe), w(0xbf),\ -w(0xc0), w(0xc1), w(0xc2), w(0xc3), w(0xc4), w(0xc5), w(0xc6), w(0xc7),\ -w(0xc8), w(0xc9), w(0xca), w(0xcb), w(0xcc), w(0xcd), w(0xce), w(0xcf),\ -w(0xd0), w(0xd1), w(0xd2), w(0xd3), w(0xd4), w(0xd5), w(0xd6), w(0xd7),\ -w(0xd8), w(0xd9), w(0xda), w(0xdb), w(0xdc), w(0xdd), w(0xde), w(0xdf),\ -w(0xe0), w(0xe1), w(0xe2), w(0xe3), w(0xe4), w(0xe5), w(0xe6), w(0xe7),\ -w(0xe8), w(0xe9), w(0xea), w(0xeb), w(0xec), w(0xed), w(0xee), w(0xef),\ -w(0xf0), w(0xf1), w(0xf2), w(0xf3), w(0xf4), w(0xf5), w(0xf6), w(0xf7),\ -w(0xf8), w(0xf9), w(0xfa), w(0xfb), w(0xfc), w(0xfd), w(0xfe), w(0xff) +#define sb_data(w) {\ + w(0x63), w(0x7c), w(0x77), w(0x7b), w(0xf2), w(0x6b), w(0x6f), w(0xc5),\ + w(0x30), w(0x01), w(0x67), w(0x2b), w(0xfe), w(0xd7), w(0xab), w(0x76),\ + w(0xca), w(0x82), w(0xc9), w(0x7d), w(0xfa), w(0x59), w(0x47), w(0xf0),\ + w(0xad), w(0xd4), w(0xa2), w(0xaf), w(0x9c), w(0xa4), w(0x72), w(0xc0),\ + w(0xb7), w(0xfd), w(0x93), w(0x26), w(0x36), w(0x3f), w(0xf7), w(0xcc),\ + w(0x34), w(0xa5), w(0xe5), w(0xf1), w(0x71), w(0xd8), w(0x31), w(0x15),\ + w(0x04), w(0xc7), w(0x23), w(0xc3), w(0x18), w(0x96), w(0x05), w(0x9a),\ + w(0x07), w(0x12), w(0x80), w(0xe2), w(0xeb), w(0x27), w(0xb2), w(0x75),\ + w(0x09), w(0x83), w(0x2c), w(0x1a), w(0x1b), w(0x6e), w(0x5a), w(0xa0),\ + w(0x52), w(0x3b), w(0xd6), w(0xb3), w(0x29), w(0xe3), w(0x2f), w(0x84),\ + w(0x53), w(0xd1), w(0x00), w(0xed), w(0x20), w(0xfc), w(0xb1), w(0x5b),\ + w(0x6a), w(0xcb), w(0xbe), w(0x39), w(0x4a), w(0x4c), w(0x58), w(0xcf),\ + w(0xd0), w(0xef), w(0xaa), w(0xfb), w(0x43), w(0x4d), w(0x33), w(0x85),\ + w(0x45), w(0xf9), w(0x02), w(0x7f), w(0x50), w(0x3c), w(0x9f), w(0xa8),\ + w(0x51), w(0xa3), w(0x40), w(0x8f), w(0x92), w(0x9d), w(0x38), w(0xf5),\ + w(0xbc), w(0xb6), w(0xda), w(0x21), w(0x10), w(0xff), w(0xf3), w(0xd2),\ + w(0xcd), w(0x0c), w(0x13), w(0xec), w(0x5f), w(0x97), w(0x44), w(0x17),\ + w(0xc4), w(0xa7), w(0x7e), w(0x3d), w(0x64), w(0x5d), w(0x19), w(0x73),\ + w(0x60), w(0x81), w(0x4f), w(0xdc), w(0x22), w(0x2a), w(0x90), w(0x88),\ + w(0x46), w(0xee), w(0xb8), w(0x14), w(0xde), w(0x5e), w(0x0b), w(0xdb),\ + w(0xe0), w(0x32), w(0x3a), w(0x0a), w(0x49), w(0x06), w(0x24), w(0x5c),\ + w(0xc2), w(0xd3), w(0xac), w(0x62), w(0x91), w(0x95), w(0xe4), w(0x79),\ + w(0xe7), w(0xc8), w(0x37), w(0x6d), w(0x8d), w(0xd5), w(0x4e), w(0xa9),\ + w(0x6c), w(0x56), w(0xf4), w(0xea), w(0x65), w(0x7a), w(0xae), w(0x08),\ + w(0xba), w(0x78), w(0x25), w(0x2e), w(0x1c), w(0xa6), w(0xb4), w(0xc6),\ + w(0xe8), w(0xdd), w(0x74), w(0x1f), w(0x4b), w(0xbd), w(0x8b), w(0x8a),\ + w(0x70), w(0x3e), w(0xb5), w(0x66), w(0x48), w(0x03), w(0xf6), w(0x0e),\ + w(0x61), w(0x35), w(0x57), w(0xb9), w(0x86), w(0xc1), w(0x1d), w(0x9e),\ + w(0xe1), w(0xf8), w(0x98), w(0x11), w(0x69), w(0xd9), w(0x8e), w(0x94),\ + w(0x9b), w(0x1e), w(0x87), w(0xe9), w(0xce), w(0x55), w(0x28), w(0xdf),\ + w(0x8c), w(0xa1), w(0x89), w(0x0d), w(0xbf), w(0xe6), w(0x42), w(0x68),\ + w(0x41), w(0x99), w(0x2d), w(0x0f), w(0xb0), w(0x54), w(0xbb), w(0x16) } + +#define isb_data(w) {\ + w(0x52), w(0x09), w(0x6a), w(0xd5), w(0x30), w(0x36), w(0xa5), w(0x38),\ + w(0xbf), w(0x40), w(0xa3), w(0x9e), w(0x81), w(0xf3), w(0xd7), w(0xfb),\ + w(0x7c), w(0xe3), w(0x39), w(0x82), w(0x9b), w(0x2f), w(0xff), w(0x87),\ + w(0x34), w(0x8e), w(0x43), w(0x44), w(0xc4), w(0xde), w(0xe9), w(0xcb),\ + w(0x54), w(0x7b), w(0x94), w(0x32), w(0xa6), w(0xc2), w(0x23), w(0x3d),\ + w(0xee), w(0x4c), w(0x95), w(0x0b), w(0x42), w(0xfa), w(0xc3), w(0x4e),\ + w(0x08), w(0x2e), w(0xa1), w(0x66), w(0x28), w(0xd9), w(0x24), w(0xb2),\ + w(0x76), w(0x5b), w(0xa2), w(0x49), w(0x6d), w(0x8b), w(0xd1), w(0x25),\ + w(0x72), w(0xf8), w(0xf6), w(0x64), w(0x86), w(0x68), w(0x98), w(0x16),\ + w(0xd4), w(0xa4), w(0x5c), w(0xcc), w(0x5d), w(0x65), w(0xb6), w(0x92),\ + w(0x6c), w(0x70), w(0x48), w(0x50), w(0xfd), w(0xed), w(0xb9), w(0xda),\ + w(0x5e), w(0x15), w(0x46), w(0x57), w(0xa7), w(0x8d), w(0x9d), w(0x84),\ + w(0x90), w(0xd8), w(0xab), w(0x00), w(0x8c), w(0xbc), w(0xd3), w(0x0a),\ + w(0xf7), w(0xe4), w(0x58), w(0x05), w(0xb8), w(0xb3), w(0x45), w(0x06),\ + w(0xd0), w(0x2c), w(0x1e), w(0x8f), w(0xca), w(0x3f), w(0x0f), w(0x02),\ + w(0xc1), w(0xaf), w(0xbd), w(0x03), w(0x01), w(0x13), w(0x8a), w(0x6b),\ + w(0x3a), w(0x91), w(0x11), w(0x41), w(0x4f), w(0x67), w(0xdc), w(0xea),\ + w(0x97), w(0xf2), w(0xcf), w(0xce), w(0xf0), w(0xb4), w(0xe6), w(0x73),\ + w(0x96), w(0xac), w(0x74), w(0x22), w(0xe7), w(0xad), w(0x35), w(0x85),\ + w(0xe2), w(0xf9), w(0x37), w(0xe8), w(0x1c), w(0x75), w(0xdf), w(0x6e),\ + w(0x47), w(0xf1), w(0x1a), w(0x71), w(0x1d), w(0x29), w(0xc5), w(0x89),\ + w(0x6f), w(0xb7), w(0x62), w(0x0e), w(0xaa), w(0x18), w(0xbe), w(0x1b),\ + w(0xfc), w(0x56), w(0x3e), w(0x4b), w(0xc6), w(0xd2), w(0x79), w(0x20),\ + w(0x9a), w(0xdb), w(0xc0), w(0xfe), w(0x78), w(0xcd), w(0x5a), w(0xf4),\ + w(0x1f), w(0xdd), w(0xa8), w(0x33), w(0x88), w(0x07), w(0xc7), w(0x31),\ + w(0xb1), w(0x12), w(0x10), w(0x59), w(0x27), w(0x80), w(0xec), w(0x5f),\ + w(0x60), w(0x51), w(0x7f), w(0xa9), w(0x19), w(0xb5), w(0x4a), w(0x0d),\ + w(0x2d), w(0xe5), w(0x7a), w(0x9f), w(0x93), w(0xc9), w(0x9c), w(0xef),\ + w(0xa0), w(0xe0), w(0x3b), w(0x4d), w(0xae), w(0x2a), w(0xf5), w(0xb0),\ + w(0xc8), w(0xeb), w(0xbb), w(0x3c), w(0x83), w(0x53), w(0x99), w(0x61),\ + w(0x17), w(0x2b), w(0x04), w(0x7e), w(0xba), w(0x77), w(0xd6), w(0x26),\ + w(0xe1), w(0x69), w(0x14), w(0x63), w(0x55), w(0x21), w(0x0c), w(0x7d) } + +#define mm_data(w) {\ + w(0x00), w(0x01), w(0x02), w(0x03), w(0x04), w(0x05), w(0x06), w(0x07),\ + w(0x08), w(0x09), w(0x0a), w(0x0b), w(0x0c), w(0x0d), w(0x0e), w(0x0f),\ + w(0x10), w(0x11), w(0x12), w(0x13), w(0x14), w(0x15), w(0x16), w(0x17),\ + w(0x18), w(0x19), w(0x1a), w(0x1b), w(0x1c), w(0x1d), w(0x1e), w(0x1f),\ + w(0x20), w(0x21), w(0x22), w(0x23), w(0x24), w(0x25), w(0x26), w(0x27),\ + w(0x28), w(0x29), w(0x2a), w(0x2b), w(0x2c), w(0x2d), w(0x2e), w(0x2f),\ + w(0x30), w(0x31), w(0x32), w(0x33), w(0x34), w(0x35), w(0x36), w(0x37),\ + w(0x38), w(0x39), w(0x3a), w(0x3b), w(0x3c), w(0x3d), w(0x3e), w(0x3f),\ + w(0x40), w(0x41), w(0x42), w(0x43), w(0x44), w(0x45), w(0x46), w(0x47),\ + w(0x48), w(0x49), w(0x4a), w(0x4b), w(0x4c), w(0x4d), w(0x4e), w(0x4f),\ + w(0x50), w(0x51), w(0x52), w(0x53), w(0x54), w(0x55), w(0x56), w(0x57),\ + w(0x58), w(0x59), w(0x5a), w(0x5b), w(0x5c), w(0x5d), w(0x5e), w(0x5f),\ + w(0x60), w(0x61), w(0x62), w(0x63), w(0x64), w(0x65), w(0x66), w(0x67),\ + w(0x68), w(0x69), w(0x6a), w(0x6b), w(0x6c), w(0x6d), w(0x6e), w(0x6f),\ + w(0x70), w(0x71), w(0x72), w(0x73), w(0x74), w(0x75), w(0x76), w(0x77),\ + w(0x78), w(0x79), w(0x7a), w(0x7b), w(0x7c), w(0x7d), w(0x7e), w(0x7f),\ + w(0x80), w(0x81), w(0x82), w(0x83), w(0x84), w(0x85), w(0x86), w(0x87),\ + w(0x88), w(0x89), w(0x8a), w(0x8b), w(0x8c), w(0x8d), w(0x8e), w(0x8f),\ + w(0x90), w(0x91), w(0x92), w(0x93), w(0x94), w(0x95), w(0x96), w(0x97),\ + w(0x98), w(0x99), w(0x9a), w(0x9b), w(0x9c), w(0x9d), w(0x9e), w(0x9f),\ + w(0xa0), w(0xa1), w(0xa2), w(0xa3), w(0xa4), w(0xa5), w(0xa6), w(0xa7),\ + w(0xa8), w(0xa9), w(0xaa), w(0xab), w(0xac), w(0xad), w(0xae), w(0xaf),\ + w(0xb0), w(0xb1), w(0xb2), w(0xb3), w(0xb4), w(0xb5), w(0xb6), w(0xb7),\ + w(0xb8), w(0xb9), w(0xba), w(0xbb), w(0xbc), w(0xbd), w(0xbe), w(0xbf),\ + w(0xc0), w(0xc1), w(0xc2), w(0xc3), w(0xc4), w(0xc5), w(0xc6), w(0xc7),\ + w(0xc8), w(0xc9), w(0xca), w(0xcb), w(0xcc), w(0xcd), w(0xce), w(0xcf),\ + w(0xd0), w(0xd1), w(0xd2), w(0xd3), w(0xd4), w(0xd5), w(0xd6), w(0xd7),\ + w(0xd8), w(0xd9), w(0xda), w(0xdb), w(0xdc), w(0xdd), w(0xde), w(0xdf),\ + w(0xe0), w(0xe1), w(0xe2), w(0xe3), w(0xe4), w(0xe5), w(0xe6), w(0xe7),\ + w(0xe8), w(0xe9), w(0xea), w(0xeb), w(0xec), w(0xed), w(0xee), w(0xef),\ + w(0xf0), w(0xf1), w(0xf2), w(0xf3), w(0xf4), w(0xf5), w(0xf6), w(0xf7),\ + w(0xf8), w(0xf9), w(0xfa), w(0xfb), w(0xfc), w(0xfd), w(0xfe), w(0xff) } + +#define rc_data(w) {\ + w(0x01), w(0x02), w(0x04), w(0x08), w(0x10),w(0x20), w(0x40), w(0x80),\ + w(0x1b), w(0x36) } #define h0(x) (x) -/* These defines are used to ensure tables are generated in the -right format depending on the internal byte order required -*/ - #define w0(p) bytes2word(p, 0, 0, 0) #define w1(p) bytes2word(0, p, 0, 0) #define w2(p) bytes2word(0, 0, p, 0) #define w3(p) bytes2word(0, 0, 0, p) -/* Number of elements required in this table for different -block and key lengths is: - -Rcon Table key length (bytes) -Length 16 20 24 28 32 ---------------------- -block 16 | 10 9 8 7 7 -length 20 | 14 11 10 9 9 -(bytes) 24 | 19 15 12 11 11 -28 | 24 19 16 13 13 -32 | 29 23 19 17 14 - -this table can be a table of bytes if the key schedule -code is adjusted accordingly -*/ - #define u0(p) bytes2word(f2(p), p, p, f3(p)) #define u1(p) bytes2word(f3(p), f2(p), p, p) #define u2(p) bytes2word(p, f3(p), f2(p), p) @@ -186,309 +148,244 @@ code is adjusted accordingly #define v2(p) bytes2word(fd(p), fb(p), fe(p), f9(p)) #define v3(p) bytes2word(f9(p), fd(p), fb(p), fe(p)) -const aes_32t rcon_tab[29] = -{ -w0(0x01), w0(0x02), w0(0x04), w0(0x08), -w0(0x10), w0(0x20), w0(0x40), w0(0x80), -w0(0x1b), w0(0x36), w0(0x6c), w0(0xd8), -w0(0xab), w0(0x4d), w0(0x9a), w0(0x2f), -w0(0x5e), w0(0xbc), w0(0x63), w0(0xc6), -w0(0x97), w0(0x35), w0(0x6a), w0(0xd4), -w0(0xb3), w0(0x7d), w0(0xfa), w0(0xef), -w0(0xc5) -}; - -#ifdef SBX_SET -const aes_08t s_box[256] = { sb_data(h0) }; -#endif -#ifdef ISB_SET -const aes_08t inv_s_box[256] = { isb_data(h0) }; -#endif - -#ifdef FT1_SET -const aes_32t ft_tab[256] = { sb_data(u0) }; -#endif -#ifdef FT4_SET -const aes_32t ft_tab[4][256] = -{ { sb_data(u0) }, { sb_data(u1) }, { sb_data(u2) }, { sb_data(u3) } }; #endif -#ifdef FL1_SET -const aes_32t fl_tab[256] = { sb_data(w0) }; -#endif -#ifdef FL4_SET -const aes_32t fl_tab[4][256] = -{ { sb_data(w0) }, { sb_data(w1) }, { sb_data(w2) }, { sb_data(w3) } }; -#endif +#if defined(FIXED_TABLES) || !defined(FF_TABLES) -#ifdef IT1_SET -const aes_32t it_tab[256] = { isb_data(v0) }; -#endif -#ifdef IT4_SET -const aes_32t it_tab[4][256] = -{ { isb_data(v0) }, { isb_data(v1) }, { isb_data(v2) }, { isb_data(v3) } }; -#endif +#define f2(x) ((x<<1) ^ (((x>>7) & 1) * WPOLY)) +#define f4(x) ((x<<2) ^ (((x>>6) & 1) * WPOLY) ^ (((x>>6) & 2) * WPOLY)) +#define f8(x) ((x<<3) ^ (((x>>5) & 1) * WPOLY) ^ (((x>>5) & 2) * WPOLY) \ + ^ (((x>>5) & 4) * WPOLY)) +#define f3(x) (f2(x) ^ x) +#define f9(x) (f8(x) ^ x) +#define fb(x) (f8(x) ^ f2(x) ^ x) +#define fd(x) (f8(x) ^ f4(x) ^ x) +#define fe(x) (f8(x) ^ f4(x) ^ f2(x)) -#ifdef IL1_SET -const aes_32t il_tab[256] = { isb_data(w0) }; -#endif -#ifdef IL4_SET -const aes_32t il_tab[4][256] = -{ { isb_data(w0) }, { isb_data(w1) }, { isb_data(w2) }, { isb_data(w3) } }; -#endif +#else -#ifdef LS1_SET -const aes_32t ls_tab[256] = { sb_data(w0) }; -#endif -#ifdef LS4_SET -const aes_32t ls_tab[4][256] = -{ { sb_data(w0) }, { sb_data(w1) }, { sb_data(w2) }, { sb_data(w3) } }; -#endif +#define f2(x) ((x) ? pow[log[x] + 0x19] : 0) +#define f3(x) ((x) ? pow[log[x] + 0x01] : 0) +#define f9(x) ((x) ? pow[log[x] + 0xc7] : 0) +#define fb(x) ((x) ? pow[log[x] + 0x68] : 0) +#define fd(x) ((x) ? pow[log[x] + 0xee] : 0) +#define fe(x) ((x) ? pow[log[x] + 0xdf] : 0) -#ifdef IM1_SET -const aes_32t im_tab[256] = { mm_data(v0) }; #endif -#ifdef IM4_SET -const aes_32t im_tab[4][256] = -{ { mm_data(v0) }, { mm_data(v1) }, { mm_data(v2) }, { mm_data(v3) } }; -#endif - -#else /* dynamic table generation */ - -aes_08t tab_init = 0; -#define const +#include "aestab.h" -aes_32t rcon_tab[RC_LENGTH]; - -#ifdef SBX_SET -aes_08t s_box[256]; -#endif -#ifdef ISB_SET -aes_08t inv_s_box[256]; -#endif - -#ifdef FT1_SET -aes_32t ft_tab[256]; -#endif -#ifdef FT4_SET -aes_32t ft_tab[4][256]; +#if defined(__cplusplus) +extern "C" +{ #endif -#ifdef FL1_SET -aes_32t fl_tab[256]; -#endif -#ifdef FL4_SET -aes_32t fl_tab[4][256]; -#endif +#if defined(FIXED_TABLES) -#ifdef IT1_SET -aes_32t it_tab[256]; -#endif -#ifdef IT4_SET -aes_32t it_tab[4][256]; -#endif +/* implemented in case of wrong call for fixed tables */ -#ifdef IL1_SET -aes_32t il_tab[256]; -#endif -#ifdef IL4_SET -aes_32t il_tab[4][256]; -#endif +AES_RETURN aes_init(void) +{ + return EXIT_SUCCESS; +} -#ifdef LS1_SET -aes_32t ls_tab[256]; -#endif -#ifdef LS4_SET -aes_32t ls_tab[4][256]; -#endif +#else /* Generate the tables for the dynamic table option */ -#ifdef IM1_SET -aes_32t im_tab[256]; -#endif -#ifdef IM4_SET -aes_32t im_tab[4][256]; -#endif +#if defined(FF_TABLES) -#if !defined(FF_TABLES) +#define gf_inv(x) ((x) ? pow[ 255 - log[x]] : 0) -/* Generate the tables for the dynamic table option +#else -It will generally be sensible to use tables to compute finite -field multiplies and inverses but where memory is scarse this -code might sometimes be better. But it only has effect during -initialisation so its pretty unimportant in overall terms. +/* It will generally be sensible to use tables to compute finite + field multiplies and inverses but where memory is scarse this + code might sometimes be better. But it only has effect during + initialisation so its pretty unimportant in overall terms. */ /* return 2 ^ (n - 1) where n is the bit number of the highest bit -set in x with x in the range 1 < x < 0x00000200. This form is -used so that locals within fi can be bytes rather than words + set in x with x in the range 1 < x < 0x00000200. This form is + used so that locals within fi can be bytes rather than words */ -static aes_08t hibit(const aes_32t x) -{ aes_08t r = (aes_08t)((x >> 1) | (x >> 2)); +static uint8_t hibit(const uint32_t x) +{ uint8_t r = (uint8_t)((x >> 1) | (x >> 2)); -r |= (r >> 2); -r |= (r >> 4); -return (r + 1) >> 1; + r |= (r >> 2); + r |= (r >> 4); + return (r + 1) >> 1; } /* return the inverse of the finite field element x */ -static aes_08t fi(const aes_08t x) -{ aes_08t p1 = x, p2 = BPOLY, n1 = hibit(x), n2 = 0x80, v1 = 1, v2 = 0; - -if(x < 2) return x; - -for(;;) -{ -if(!n1) return v1; - -while(n2 >= n1) -{ -n2 /= n1; p2 ^= p1 * n2; v2 ^= v1 * n2; n2 = hibit(p2); +static uint8_t gf_inv(const uint8_t x) +{ uint8_t p1 = x, p2 = BPOLY, n1 = hibit(x), n2 = 0x80, v1 = 1, v2 = 0; + + if(x < 2) + return x; + + for( ; ; ) + { + if(n1) + while(n2 >= n1) /* divide polynomial p2 by p1 */ + { + n2 /= n1; /* shift smaller polynomial left */ + p2 ^= (p1 * n2) & 0xff; /* and remove from larger one */ + v2 ^= v1 * n2; /* shift accumulated value and */ + n2 = hibit(p2); /* add into result */ + } + else + return v1; + + if(n2) /* repeat with values swapped */ + while(n1 >= n2) + { + n1 /= n2; + p1 ^= p2 * n1; + v1 ^= v2 * n1; + n1 = hibit(p1); + } + else + return v2; + } } -if(!n2) return v2; - -while(n1 >= n2) -{ -n1 /= n2; p1 ^= p2 * n1; v1 ^= v2 * n1; n1 = hibit(p1); -} -} -} - -#else - -/* define the finite field multiplies required for Rijndael */ - -#define f2(x) ((x) ? pow[log[x] + 0x19] : 0) -#define f3(x) ((x) ? pow[log[x] + 0x01] : 0) -#define f9(x) ((x) ? pow[log[x] + 0xc7] : 0) -#define fb(x) ((x) ? pow[log[x] + 0x68] : 0) -#define fd(x) ((x) ? pow[log[x] + 0xee] : 0) -#define fe(x) ((x) ? pow[log[x] + 0xdf] : 0) -#define fi(x) ((x) ? pow[255 - log[x]]: 0) - #endif /* The forward and inverse affine transformations used in the S-box */ +uint8_t fwd_affine(const uint8_t x) +{ uint32_t w = x; + w ^= (w << 1) ^ (w << 2) ^ (w << 3) ^ (w << 4); + return 0x63 ^ ((w ^ (w >> 8)) & 0xff); +} -#define fwd_affine(x) \ -(w = (aes_32t)x, w ^= (w<<1)^(w<<2)^(w<<3)^(w<<4), 0x63^(aes_08t)(w^(w>>8))) +uint8_t inv_affine(const uint8_t x) +{ uint32_t w = x; + w = (w << 1) ^ (w << 3) ^ (w << 6); + return 0x05 ^ ((w ^ (w >> 8)) & 0xff); +} -#define inv_affine(x) \ -(w = (aes_32t)x, w = (w<<1)^(w<<3)^(w<<6), 0x05^(aes_08t)(w^(w>>8))) +static int init = 0; -void gen_tabs(void) -{ aes_32t i, w; +AES_RETURN aes_init(void) +{ uint32_t i, w; #if defined(FF_TABLES) -aes_08t pow[512], log[256]; - -/* log and power tables for GF(2^8) finite field with -WPOLY as modular polynomial - the simplest primitive -root is 0x03, used here to generate the tables -*/ - -i = 0; w = 1; -do -{ -pow[i] = (aes_08t)w; -pow[i + 255] = (aes_08t)w; -log[w] = (aes_08t)i++; -w ^= (w << 1) ^ (w & 0x80 ? WPOLY : 0); -} -while (w != 1); + uint8_t pow[512], log[256]; + + if(init) + return EXIT_SUCCESS; + /* log and power tables for GF(2^8) finite field with + WPOLY as modular polynomial - the simplest primitive + root is 0x03, used here to generate the tables + */ + + i = 0; w = 1; + do + { + pow[i] = (uint8_t)w; + pow[i + 255] = (uint8_t)w; + log[w] = (uint8_t)i++; + w ^= (w << 1) ^ (w & 0x80 ? WPOLY : 0); + } + while (w != 1); +#else + if(init) + return EXIT_SUCCESS; #endif -for(i = 0, w = 1; i < RC_LENGTH; ++i) -{ -rcon_tab[i] = bytes2word(w, 0, 0, 0); -w = f2(w); -} + for(i = 0, w = 1; i < RC_LENGTH; ++i) + { + t_set(r,c)[i] = bytes2word(w, 0, 0, 0); + w = f2(w); + } -for(i = 0; i < 256; ++i) -{ aes_08t b; + for(i = 0; i < 256; ++i) + { uint8_t b; -b = fwd_affine(fi((aes_08t)i)); -w = bytes2word(f2(b), b, b, f3(b)); + b = fwd_affine(gf_inv((uint8_t)i)); + w = bytes2word(f2(b), b, b, f3(b)); -#ifdef SBX_SET -s_box[i] = b; +#if defined( SBX_SET ) + t_set(s,box)[i] = b; #endif -#ifdef FT1_SET /* tables for a normal encryption round */ -ft_tab[i] = w; +#if defined( FT1_SET ) /* tables for a normal encryption round */ + t_set(f,n)[i] = w; #endif -#ifdef FT4_SET -ft_tab[0][i] = w; -ft_tab[1][i] = upr(w,1); -ft_tab[2][i] = upr(w,2); -ft_tab[3][i] = upr(w,3); +#if defined( FT4_SET ) + t_set(f,n)[0][i] = w; + t_set(f,n)[1][i] = upr(w,1); + t_set(f,n)[2][i] = upr(w,2); + t_set(f,n)[3][i] = upr(w,3); #endif -w = bytes2word(b, 0, 0, 0); + w = bytes2word(b, 0, 0, 0); -#ifdef FL1_SET /* tables for last encryption round (may also */ -fl_tab[i] = w; /* be used in the key schedule) */ +#if defined( FL1_SET ) /* tables for last encryption round (may also */ + t_set(f,l)[i] = w; /* be used in the key schedule) */ #endif -#ifdef FL4_SET -fl_tab[0][i] = w; -fl_tab[1][i] = upr(w,1); -fl_tab[2][i] = upr(w,2); -fl_tab[3][i] = upr(w,3); +#if defined( FL4_SET ) + t_set(f,l)[0][i] = w; + t_set(f,l)[1][i] = upr(w,1); + t_set(f,l)[2][i] = upr(w,2); + t_set(f,l)[3][i] = upr(w,3); #endif -#ifdef LS1_SET /* table for key schedule if fl_tab above is */ -ls_tab[i] = w; /* not of the required form */ +#if defined( LS1_SET ) /* table for key schedule if t_set(f,l) above is*/ + t_set(l,s)[i] = w; /* not of the required form */ #endif -#ifdef LS4_SET -ls_tab[0][i] = w; -ls_tab[1][i] = upr(w,1); -ls_tab[2][i] = upr(w,2); -ls_tab[3][i] = upr(w,3); +#if defined( LS4_SET ) + t_set(l,s)[0][i] = w; + t_set(l,s)[1][i] = upr(w,1); + t_set(l,s)[2][i] = upr(w,2); + t_set(l,s)[3][i] = upr(w,3); #endif -b = fi(inv_affine((aes_08t)i)); -w = bytes2word(fe(b), f9(b), fd(b), fb(b)); + b = gf_inv(inv_affine((uint8_t)i)); + w = bytes2word(fe(b), f9(b), fd(b), fb(b)); -#ifdef IM1_SET /* tables for the inverse mix column operation */ -im_tab[b] = w; +#if defined( IM1_SET ) /* tables for the inverse mix column operation */ + t_set(i,m)[b] = w; #endif -#ifdef IM4_SET -im_tab[0][b] = w; -im_tab[1][b] = upr(w,1); -im_tab[2][b] = upr(w,2); -im_tab[3][b] = upr(w,3); +#if defined( IM4_SET ) + t_set(i,m)[0][b] = w; + t_set(i,m)[1][b] = upr(w,1); + t_set(i,m)[2][b] = upr(w,2); + t_set(i,m)[3][b] = upr(w,3); #endif -#ifdef ISB_SET -inv_s_box[i] = b; +#if defined( ISB_SET ) + t_set(i,box)[i] = b; #endif -#ifdef IT1_SET /* tables for a normal decryption round */ -it_tab[i] = w; +#if defined( IT1_SET ) /* tables for a normal decryption round */ + t_set(i,n)[i] = w; #endif -#ifdef IT4_SET -it_tab[0][i] = w; -it_tab[1][i] = upr(w,1); -it_tab[2][i] = upr(w,2); -it_tab[3][i] = upr(w,3); +#if defined( IT4_SET ) + t_set(i,n)[0][i] = w; + t_set(i,n)[1][i] = upr(w,1); + t_set(i,n)[2][i] = upr(w,2); + t_set(i,n)[3][i] = upr(w,3); #endif -w = bytes2word(b, 0, 0, 0); -#ifdef IL1_SET /* tables for last decryption round */ -il_tab[i] = w; + w = bytes2word(b, 0, 0, 0); +#if defined( IL1_SET ) /* tables for last decryption round */ + t_set(i,l)[i] = w; #endif -#ifdef IL4_SET -il_tab[0][i] = w; -il_tab[1][i] = upr(w,1); -il_tab[2][i] = upr(w,2); -il_tab[3][i] = upr(w,3); +#if defined( IL4_SET ) + t_set(i,l)[0][i] = w; + t_set(i,l)[1][i] = upr(w,1); + t_set(i,l)[2][i] = upr(w,2); + t_set(i,l)[3][i] = upr(w,3); #endif + } + init = 1; + return EXIT_SUCCESS; } -tab_init = 1; -} +#endif +#if defined(__cplusplus) +} #endif + diff --git a/aestab.h b/aestab.h new file mode 100644 index 000000000..46719d330 --- /dev/null +++ b/aestab.h @@ -0,0 +1,173 @@ +/* +--------------------------------------------------------------------------- +Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved. + +The redistribution and use of this software (with or without changes) +is allowed without the payment of fees or royalties provided that: + + source code distributions include the above copyright notice, this + list of conditions and the following disclaimer; + + binary distributions include the above copyright notice, this list + of conditions and the following disclaimer in their documentation. + +This software is provided 'as is' with no explicit or implied warranties +in respect of its operation, including, but not limited to, correctness +and fitness for purpose. +--------------------------------------------------------------------------- +Issue Date: 20/12/2007 + + This file contains the code for declaring the tables needed to implement + AES. The file aesopt.h is assumed to be included before this header file. + If there are no global variables, the definitions here can be used to put + the AES tables in a structure so that a pointer can then be added to the + AES context to pass them to the AES routines that need them. If this + facility is used, the calling program has to ensure that this pointer is + managed appropriately. In particular, the value of the t_dec(in,it) item + in the table structure must be set to zero in order to ensure that the + tables are initialised. In practice the three code sequences in aeskey.c + that control the calls to aes_init() and the aes_init() routine itself will + have to be changed for a specific implementation. If global variables are + available it will generally be preferable to use them with the precomputed + FIXED_TABLES option that uses static global tables. + + The following defines can be used to control the way the tables + are defined, initialised and used in embedded environments that + require special features for these purposes + + the 't_dec' construction is used to declare fixed table arrays + the 't_set' construction is used to set fixed table values + the 't_use' construction is used to access fixed table values + + 256 byte tables: + + t_xxx(s,box) => forward S box + t_xxx(i,box) => inverse S box + + 256 32-bit word OR 4 x 256 32-bit word tables: + + t_xxx(f,n) => forward normal round + t_xxx(f,l) => forward last round + t_xxx(i,n) => inverse normal round + t_xxx(i,l) => inverse last round + t_xxx(l,s) => key schedule table + t_xxx(i,m) => key schedule table + + Other variables and tables: + + t_xxx(r,c) => the rcon table +*/ + +#if !defined( _AESTAB_H ) +#define _AESTAB_H + +#if defined(__cplusplus) +extern "C" { +#endif + +#define t_dec(m,n) t_##m##n +#define t_set(m,n) t_##m##n +#define t_use(m,n) t_##m##n + +#if defined(FIXED_TABLES) +# if !defined( __GNUC__ ) && (defined( __MSDOS__ ) || defined( __WIN16__ )) +/* make tables far data to avoid using too much DGROUP space (PG) */ +# define CONST const far +# else +# define CONST const +# endif +#else +# define CONST +#endif + +#if defined(DO_TABLES) +# define EXTERN +#else +# define EXTERN extern +#endif + +#if defined(_MSC_VER) && defined(TABLE_ALIGN) +#define ALIGN __declspec(align(TABLE_ALIGN)) +#else +#define ALIGN +#endif + +#if defined( __WATCOMC__ ) && ( __WATCOMC__ >= 1100 ) +# define XP_DIR __cdecl +#else +# define XP_DIR +#endif + +#if defined(DO_TABLES) && defined(FIXED_TABLES) +#define d_1(t,n,b,e) EXTERN ALIGN CONST XP_DIR t n[256] = b(e) +#define d_4(t,n,b,e,f,g,h) EXTERN ALIGN CONST XP_DIR t n[4][256] = { b(e), b(f), b(g), b(h) } +EXTERN ALIGN CONST uint32_t t_dec(r,c)[RC_LENGTH] = rc_data(w0); +#else +#define d_1(t,n,b,e) EXTERN ALIGN CONST XP_DIR t n[256] +#define d_4(t,n,b,e,f,g,h) EXTERN ALIGN CONST XP_DIR t n[4][256] +EXTERN ALIGN CONST uint32_t t_dec(r,c)[RC_LENGTH]; +#endif + +#if defined( SBX_SET ) + d_1(uint8_t, t_dec(s,box), sb_data, h0); +#endif +#if defined( ISB_SET ) + d_1(uint8_t, t_dec(i,box), isb_data, h0); +#endif + +#if defined( FT1_SET ) + d_1(uint32_t, t_dec(f,n), sb_data, u0); +#endif +#if defined( FT4_SET ) + d_4(uint32_t, t_dec(f,n), sb_data, u0, u1, u2, u3); +#endif + +#if defined( FL1_SET ) + d_1(uint32_t, t_dec(f,l), sb_data, w0); +#endif +#if defined( FL4_SET ) + d_4(uint32_t, t_dec(f,l), sb_data, w0, w1, w2, w3); +#endif + +#if defined( IT1_SET ) + d_1(uint32_t, t_dec(i,n), isb_data, v0); +#endif +#if defined( IT4_SET ) + d_4(uint32_t, t_dec(i,n), isb_data, v0, v1, v2, v3); +#endif + +#if defined( IL1_SET ) + d_1(uint32_t, t_dec(i,l), isb_data, w0); +#endif +#if defined( IL4_SET ) + d_4(uint32_t, t_dec(i,l), isb_data, w0, w1, w2, w3); +#endif + +#if defined( LS1_SET ) +#if defined( FL1_SET ) +#undef LS1_SET +#else + d_1(uint32_t, t_dec(l,s), sb_data, w0); +#endif +#endif + +#if defined( LS4_SET ) +#if defined( FL4_SET ) +#undef LS4_SET +#else + d_4(uint32_t, t_dec(l,s), sb_data, w0, w1, w2, w3); +#endif +#endif + +#if defined( IM1_SET ) + d_1(uint32_t, t_dec(i,m), mm_data, v0); +#endif +#if defined( IM4_SET ) + d_4(uint32_t, t_dec(i,m), mm_data, v0, v1, v2, v3); +#endif + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/bip39.c b/bip39.c index aa0e89afb..d12105935 100644 --- a/bip39.c +++ b/bip39.c @@ -30,8 +30,6 @@ #include "pbkdf2.h" #include "bip39_english.h" -#define PBKDF2_ROUNDS 2048 - const char *mnemonic_generate(int strength) { if (strength % 32 || strength < 128 || strength > 256) { @@ -153,7 +151,7 @@ void mnemonic_to_seed(const char *mnemonic, const char *passphrase, uint8_t seed memcpy(salt, "mnemonic", 8); memcpy(salt + 8, passphrase, saltlen); saltlen += 8; - pbkdf2((const uint8_t *)mnemonic, strlen(mnemonic), salt, saltlen, PBKDF2_ROUNDS, seed, 512 / 8, progress_callback); + pbkdf2((const uint8_t *)mnemonic, strlen(mnemonic), salt, saltlen, BIP39_PBKDF2_ROUNDS, seed, 512 / 8, progress_callback); } const char **mnemonic_wordlist(void) diff --git a/bip39.h b/bip39.h index 3bf73b532..cad7a66d3 100644 --- a/bip39.h +++ b/bip39.h @@ -26,6 +26,8 @@ #include +#define BIP39_PBKDF2_ROUNDS 2048 + const char *mnemonic_generate(int strength); // strength in bits const char *mnemonic_from_data(const uint8_t *data, int len); diff --git a/brg_endian.h b/brg_endian.h new file mode 100644 index 000000000..b44c5cbd6 --- /dev/null +++ b/brg_endian.h @@ -0,0 +1,126 @@ +/* +--------------------------------------------------------------------------- +Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved. + +The redistribution and use of this software (with or without changes) +is allowed without the payment of fees or royalties provided that: + + source code distributions include the above copyright notice, this + list of conditions and the following disclaimer; + + binary distributions include the above copyright notice, this list + of conditions and the following disclaimer in their documentation. + +This software is provided 'as is' with no explicit or implied warranties +in respect of its operation, including, but not limited to, correctness +and fitness for purpose. +--------------------------------------------------------------------------- +Issue Date: 20/12/2007 +*/ + +#ifndef _BRG_ENDIAN_H +#define _BRG_ENDIAN_H + +#define IS_BIG_ENDIAN 4321 /* byte 0 is most significant (mc68k) */ +#define IS_LITTLE_ENDIAN 1234 /* byte 0 is least significant (i386) */ + +/* Include files where endian defines and byteswap functions may reside */ +#if defined( __sun ) +# include +#elif defined( __FreeBSD__ ) || defined( __OpenBSD__ ) || defined( __NetBSD__ ) +# include +#elif defined( BSD ) && ( BSD >= 199103 ) || defined( __APPLE__ ) || \ + defined( __CYGWIN32__ ) || defined( __DJGPP__ ) || defined( __osf__ ) +# include +#elif defined( __linux__ ) || defined( __GNUC__ ) || defined( __GNU_LIBRARY__ ) +# if !defined( __MINGW32__ ) && !defined( _AIX ) +# include +# if !defined( __BEOS__ ) +# include +# endif +# endif +#endif + +/* Now attempt to set the define for platform byte order using any */ +/* of the four forms SYMBOL, _SYMBOL, __SYMBOL & __SYMBOL__, which */ +/* seem to encompass most endian symbol definitions */ + +#if defined( BIG_ENDIAN ) && defined( LITTLE_ENDIAN ) +# if defined( BYTE_ORDER ) && BYTE_ORDER == BIG_ENDIAN +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +# elif defined( BYTE_ORDER ) && BYTE_ORDER == LITTLE_ENDIAN +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +# endif +#elif defined( BIG_ENDIAN ) +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +#elif defined( LITTLE_ENDIAN ) +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +#endif + +#if defined( _BIG_ENDIAN ) && defined( _LITTLE_ENDIAN ) +# if defined( _BYTE_ORDER ) && _BYTE_ORDER == _BIG_ENDIAN +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +# elif defined( _BYTE_ORDER ) && _BYTE_ORDER == _LITTLE_ENDIAN +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +# endif +#elif defined( _BIG_ENDIAN ) +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +#elif defined( _LITTLE_ENDIAN ) +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +#endif + +#if defined( __BIG_ENDIAN ) && defined( __LITTLE_ENDIAN ) +# if defined( __BYTE_ORDER ) && __BYTE_ORDER == __BIG_ENDIAN +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +# elif defined( __BYTE_ORDER ) && __BYTE_ORDER == __LITTLE_ENDIAN +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +# endif +#elif defined( __BIG_ENDIAN ) +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +#elif defined( __LITTLE_ENDIAN ) +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +#endif + +#if defined( __BIG_ENDIAN__ ) && defined( __LITTLE_ENDIAN__ ) +# if defined( __BYTE_ORDER__ ) && __BYTE_ORDER__ == __BIG_ENDIAN__ +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +# elif defined( __BYTE_ORDER__ ) && __BYTE_ORDER__ == __LITTLE_ENDIAN__ +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +# endif +#elif defined( __BIG_ENDIAN__ ) +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +#elif defined( __LITTLE_ENDIAN__ ) +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +#endif + +/* if the platform byte order could not be determined, then try to */ +/* set this define using common machine defines */ +#if !defined(PLATFORM_BYTE_ORDER) + +#if defined( __alpha__ ) || defined( __alpha ) || defined( i386 ) || \ + defined( __i386__ ) || defined( _M_I86 ) || defined( _M_IX86 ) || \ + defined( __OS2__ ) || defined( sun386 ) || defined( __TURBOC__ ) || \ + defined( vax ) || defined( vms ) || defined( VMS ) || \ + defined( __VMS ) || defined( _M_X64 ) +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN + +#elif defined( AMIGA ) || defined( applec ) || defined( __AS400__ ) || \ + defined( _CRAY ) || defined( __hppa ) || defined( __hp9000 ) || \ + defined( ibm370 ) || defined( mc68000 ) || defined( m68k ) || \ + defined( __MRC__ ) || defined( __MVS__ ) || defined( __MWERKS__ ) || \ + defined( sparc ) || defined( __sparc) || defined( SYMANTEC_C ) || \ + defined( __VOS__ ) || defined( __TIGCC__ ) || defined( __TANDEM ) || \ + defined( THINK_C ) || defined( __VMCMS__ ) || defined( _AIX ) +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN + +#elif 0 /* **** EDIT HERE IF NECESSARY **** */ +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +#elif 0 /* **** EDIT HERE IF NECESSARY **** */ +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +#else +# error Please edit lines 126 or 128 in brg_endian.h to set the platform byte order +#endif + +#endif + +#endif diff --git a/brg_types.h b/brg_types.h new file mode 100644 index 000000000..307319bf6 --- /dev/null +++ b/brg_types.h @@ -0,0 +1,191 @@ +/* +--------------------------------------------------------------------------- +Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved. + +The redistribution and use of this software (with or without changes) +is allowed without the payment of fees or royalties provided that: + + source code distributions include the above copyright notice, this + list of conditions and the following disclaimer; + + binary distributions include the above copyright notice, this list + of conditions and the following disclaimer in their documentation. + +This software is provided 'as is' with no explicit or implied warranties +in respect of its operation, including, but not limited to, correctness +and fitness for purpose. +--------------------------------------------------------------------------- +Issue Date: 20/12/2007 + + The unsigned integer types defined here are of the form uint_t where + is the length of the type; for example, the unsigned 32-bit type is + 'uint32_t'. These are NOT the same as the 'C99 integer types' that are + defined in the inttypes.h and stdint.h headers since attempts to use these + types have shown that support for them is still highly variable. However, + since the latter are of the form uint_t, a regular expression search + and replace (in VC++ search on 'uint_{:z}t' and replace with 'uint\1_t') + can be used to convert the types used here to the C99 standard types. +*/ + +#ifndef _BRG_TYPES_H +#define _BRG_TYPES_H + +#if defined(__cplusplus) +extern "C" { +#endif + +#include +#include + +#if defined( _MSC_VER ) && ( _MSC_VER >= 1300 ) +# include +# define ptrint_t intptr_t +#elif defined( __ECOS__ ) +# define intptr_t unsigned int +# define ptrint_t intptr_t +#elif defined( __GNUC__ ) && ( __GNUC__ >= 3 ) +# define ptrint_t intptr_t +#else +# define ptrint_t int +#endif + +#ifndef BRG_UI32 +# define BRG_UI32 +# if UINT_MAX == 4294967295u +# define li_32(h) 0x##h##u +# elif ULONG_MAX == 4294967295u +# define li_32(h) 0x##h##ul +# elif defined( _CRAY ) +# error This code needs 32-bit data types, which Cray machines do not provide +# else +# error Please define uint32_t as a 32-bit unsigned integer type in brg_types.h +# endif +#endif + +#ifndef BRG_UI64 +# if defined( __BORLANDC__ ) && !defined( __MSDOS__ ) +# define BRG_UI64 +# define li_64(h) 0x##h##ui64 +# elif defined( _MSC_VER ) && ( _MSC_VER < 1300 ) /* 1300 == VC++ 7.0 */ +# define BRG_UI64 +# define li_64(h) 0x##h##ui64 +# elif defined( __sun ) && defined( ULONG_MAX ) && ULONG_MAX == 0xfffffffful +# define BRG_UI64 +# define li_64(h) 0x##h##ull +# elif defined( __MVS__ ) +# define BRG_UI64 +# define li_64(h) 0x##h##ull +# elif defined( UINT_MAX ) && UINT_MAX > 4294967295u +# if UINT_MAX == 18446744073709551615u +# define BRG_UI64 +# define li_64(h) 0x##h##u +# endif +# elif defined( ULONG_MAX ) && ULONG_MAX > 4294967295u +# if ULONG_MAX == 18446744073709551615ul +# define BRG_UI64 +# define li_64(h) 0x##h##ul +# endif +# elif defined( ULLONG_MAX ) && ULLONG_MAX > 4294967295u +# if ULLONG_MAX == 18446744073709551615ull +# define BRG_UI64 +# define li_64(h) 0x##h##ull +# endif +# elif defined( ULONG_LONG_MAX ) && ULONG_LONG_MAX > 4294967295u +# if ULONG_LONG_MAX == 18446744073709551615ull +# define BRG_UI64 +# define li_64(h) 0x##h##ull +# endif +# endif +#endif + +#if !defined( BRG_UI64 ) +# if defined( NEED_UINT_64T ) +# error Please define uint64_t as an unsigned 64 bit type in brg_types.h +# endif +#endif + +#ifndef RETURN_VALUES +# define RETURN_VALUES +# if defined( DLL_EXPORT ) +# if defined( _MSC_VER ) || defined ( __INTEL_COMPILER ) +# define VOID_RETURN __declspec( dllexport ) void __stdcall +# define INT_RETURN __declspec( dllexport ) int __stdcall +# elif defined( __GNUC__ ) +# define VOID_RETURN __declspec( __dllexport__ ) void +# define INT_RETURN __declspec( __dllexport__ ) int +# else +# error Use of the DLL is only available on the Microsoft, Intel and GCC compilers +# endif +# elif defined( DLL_IMPORT ) +# if defined( _MSC_VER ) || defined ( __INTEL_COMPILER ) +# define VOID_RETURN __declspec( dllimport ) void __stdcall +# define INT_RETURN __declspec( dllimport ) int __stdcall +# elif defined( __GNUC__ ) +# define VOID_RETURN __declspec( __dllimport__ ) void +# define INT_RETURN __declspec( __dllimport__ ) int +# else +# error Use of the DLL is only available on the Microsoft, Intel and GCC compilers +# endif +# elif defined( __WATCOMC__ ) +# define VOID_RETURN void __cdecl +# define INT_RETURN int __cdecl +# else +# define VOID_RETURN void +# define INT_RETURN int +# endif +#endif + +/* These defines are used to detect and set the memory alignment of pointers. + Note that offsets are in bytes. + + ALIGN_OFFSET(x,n) return the positive or zero offset of + the memory addressed by the pointer 'x' + from an address that is aligned on an + 'n' byte boundary ('n' is a power of 2) + + ALIGN_FLOOR(x,n) return a pointer that points to memory + that is aligned on an 'n' byte boundary + and is not higher than the memory address + pointed to by 'x' ('n' is a power of 2) + + ALIGN_CEIL(x,n) return a pointer that points to memory + that is aligned on an 'n' byte boundary + and is not lower than the memory address + pointed to by 'x' ('n' is a power of 2) +*/ + +#define ALIGN_OFFSET(x,n) (((ptrint_t)(x)) & ((n) - 1)) +#define ALIGN_FLOOR(x,n) ((uint8_t*)(x) - ( ((ptrint_t)(x)) & ((n) - 1))) +#define ALIGN_CEIL(x,n) ((uint8_t*)(x) + (-((ptrint_t)(x)) & ((n) - 1))) + +/* These defines are used to declare buffers in a way that allows + faster operations on longer variables to be used. In all these + defines 'size' must be a power of 2 and >= 8. NOTE that the + buffer size is in bytes but the type length is in bits + + UNIT_TYPEDEF(x,size) declares a variable 'x' of length + 'size' bits + + BUFR_TYPEDEF(x,size,bsize) declares a buffer 'x' of length 'bsize' + bytes defined as an array of variables + each of 'size' bits (bsize must be a + multiple of size / 8) + + UNIT_CAST(x,size) casts a variable to a type of + length 'size' bits + + UPTR_CAST(x,size) casts a pointer to a pointer to a + varaiable of length 'size' bits +*/ + +#define UI_TYPE(size) uint##size##_t +#define UNIT_TYPEDEF(x,size) typedef UI_TYPE(size) x +#define BUFR_TYPEDEF(x,size,bsize) typedef UI_TYPE(size) x[bsize / (size >> 3)] +#define UNIT_CAST(x,size) ((UI_TYPE(size) )(x)) +#define UPTR_CAST(x,size) ((UI_TYPE(size)*)(x)) + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/tests.c b/tests.c index 0ba3fac39..69195cd8e 100644 --- a/tests.c +++ b/tests.c @@ -44,8 +44,10 @@ uint8_t *fromhex(const char *str) c = 0; if (str[i*2] >= '0' && str[i*2] <= '9') c += (str[i*2] - '0') << 4; if (str[i*2] >= 'a' && str[i*2] <= 'f') c += (10 + str[i*2] - 'a') << 4; + if (str[i*2] >= 'A' && str[i*2] <= 'F') c += (10 + str[i*2] - 'A') << 4; if (str[i*2+1] >= '0' && str[i*2+1] <= '9') c += (str[i*2+1] - '0'); if (str[i*2+1] >= 'a' && str[i*2+1] <= 'f') c += (10 + str[i*2+1] - 'a'); + if (str[i*2+1] >= 'A' && str[i*2+1] <= 'F') c += (10 + str[i*2+1] - 'A'); buf[i] = c; } return buf; @@ -435,30 +437,162 @@ START_TEST(test_verify_speed) } END_TEST -#define test_aes(KEY, BLKLEN, IN, OUT) do { \ - sha256_Raw((uint8_t *)KEY, strlen(KEY), key); \ - aes_enc_key(key, 32, &ctx); \ - memcpy(in, fromhex(IN), BLKLEN); \ - aes_enc_blk(in, out, &ctx); \ - ck_assert_mem_eq(out, fromhex(OUT), BLKLEN); \ -} while (0) +void aes_ctr_counter_inc(uint8_t *ctr) +{ + int i = 15; + while (i >= 0) { + ctr[i]++; + if (ctr[i]) return; // if there was no overflow + i--; + } +} -START_TEST(test_rijndael) +// test vectors from http://www.inconteam.com/software-development/41-encryption/55-aes-test-vectors +START_TEST(test_aes) { - aes_ctx ctx; - uint8_t key[32], in[32], out[32]; + aes_encrypt_ctx ctxe; + aes_decrypt_ctx ctxd; + uint8_t ibuf[16], obuf[16], iv[16], cntr[16]; + const char **ivp, **plainp, **cipherp; + + // ECB + static const char *ecb_vector[] = { + // plain cipher + "6bc1bee22e409f96e93d7e117393172a", "f3eed1bdb5d2a03c064b5a7e3db181f8", + "ae2d8a571e03ac9c9eb76fac45af8e51", "591ccb10d410ed26dc5ba74a31362870", + "30c81c46a35ce411e5fbc1191a0a52ef", "b6ed21b99ca6f4f9f153e7b1beafed1d", + "f69f2445df4f9b17ad2b417be66c3710", "23304b7a39f9f3ff067d8d8f9e24ecc7", + 0, 0, + }; + plainp = ecb_vector; + cipherp = ecb_vector + 1; + while (*plainp && *cipherp) { + // encrypt + aes_encrypt_key256(fromhex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), &ctxe); + memcpy(ibuf, fromhex(*plainp), 16); + aes_ecb_encrypt(ibuf, obuf, 16, &ctxe); + ck_assert_mem_eq(obuf, fromhex(*cipherp), 16); + // decrypt + aes_decrypt_key256(fromhex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), &ctxd); + memcpy(ibuf, fromhex(*cipherp), 16); + aes_ecb_decrypt(ibuf, obuf, 16, &ctxd); + ck_assert_mem_eq(obuf, fromhex(*plainp), 16); + plainp += 2; cipherp += 2; + } + + // CBC + static const char *cbc_vector[] = { + // iv plain cipher + "000102030405060708090A0B0C0D0E0F", "6bc1bee22e409f96e93d7e117393172a", "f58c4c04d6e5f1ba779eabfb5f7bfbd6", + "F58C4C04D6E5F1BA779EABFB5F7BFBD6", "ae2d8a571e03ac9c9eb76fac45af8e51", "9cfc4e967edb808d679f777bc6702c7d", + "9CFC4E967EDB808D679F777BC6702C7D", "30c81c46a35ce411e5fbc1191a0a52ef", "39f23369a9d9bacfa530e26304231461", + "39F23369A9D9BACFA530E26304231461", "f69f2445df4f9b17ad2b417be66c3710", "b2eb05e2c39be9fcda6c19078c6a9d1b", + 0, 0, 0, + }; + ivp = cbc_vector; + plainp = cbc_vector + 1; + cipherp = cbc_vector + 2; + while (*plainp && *cipherp) { + // encrypt + aes_encrypt_key256(fromhex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), &ctxe); + memcpy(iv, fromhex(*ivp), 16); + memcpy(ibuf, fromhex(*plainp), 16); + aes_cbc_encrypt(ibuf, obuf, 16, iv, &ctxe); + ck_assert_mem_eq(obuf, fromhex(*cipherp), 16); + // decrypt + aes_decrypt_key256(fromhex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), &ctxd); + memcpy(iv, fromhex(*ivp), 16); + memcpy(ibuf, fromhex(*cipherp), 16); + aes_cbc_decrypt(ibuf, obuf, 16, iv, &ctxd); + ck_assert_mem_eq(obuf, fromhex(*plainp), 16); + ivp += 3; plainp += 3; cipherp += 3; + } - test_aes("mnemonic", 16, "00000000000000000000000000000000", "a3af8b7d326a2d47bd7576012e07d103"); -// test_aes("mnemonic", 24, "000000000000000000000000000000000000000000000000", "7b8704678f263c316ddd1746d8377a4046a99dd9e5687d59"); -// test_aes("mnemonic", 32, "0000000000000000000000000000000000000000000000000000000000000000", "7c0575db9badc9960441c6b8dcbd5ebdfec522ede5309904b7088d0e77c2bcef"); + // CFB + static const char *cfb_vector[] = { + "000102030405060708090A0B0C0D0E0F", "6bc1bee22e409f96e93d7e117393172a", "DC7E84BFDA79164B7ECD8486985D3860", + "DC7E84BFDA79164B7ECD8486985D3860", "ae2d8a571e03ac9c9eb76fac45af8e51", "39ffed143b28b1c832113c6331e5407b", + "39FFED143B28B1C832113C6331E5407B", "30c81c46a35ce411e5fbc1191a0a52ef", "df10132415e54b92a13ed0a8267ae2f9", + "DF10132415E54B92A13ED0A8267AE2F9", "f69f2445df4f9b17ad2b417be66c3710", "75a385741ab9cef82031623d55b1e471", + 0, 0, 0, + }; + ivp = cfb_vector; + plainp = cfb_vector + 1; + cipherp = cfb_vector + 2; + while (*plainp && *cipherp) { + // encrypt + aes_encrypt_key256(fromhex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), &ctxe); + memcpy(iv, fromhex(*ivp), 16); + memcpy(ibuf, fromhex(*plainp), 16); + aes_cfb_encrypt(ibuf, obuf, 16, iv, &ctxe); + ck_assert_mem_eq(obuf, fromhex(*cipherp), 16); + // decrypt (uses encryption) + aes_encrypt_key256(fromhex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), &ctxe); + memcpy(iv, fromhex(*ivp), 16); + memcpy(ibuf, fromhex(*cipherp), 16); + aes_cfb_decrypt(ibuf, obuf, 16, iv, &ctxe); + ck_assert_mem_eq(obuf, fromhex(*plainp), 16); + ivp += 3; plainp += 3; cipherp += 3; + } - test_aes("mnemonic", 16, "686f6a6461686f6a6461686f6a6461686f6a6461", "9c3bb85af2122cc2df449033338beb56"); -// test_aes("mnemonic", 24, "686f6a6461686f6a6461686f6a6461686f6a6461686f6a64", "0d7009c589869eaa1d7398bffc7660cce32207a520d6cafe"); -// test_aes("mnemonic", 32, "686f6a6461686f6a6461686f6a6461686f6a6461686f6a6461686f6a6461686f", "b1a4d05e3827611c5986ea4c207679a6934f20767434218029c4b3b7a53806a3"); + // OFB + static const char *ofb_vector[] = { + "000102030405060708090A0B0C0D0E0F", "6bc1bee22e409f96e93d7e117393172a", "dc7e84bfda79164b7ecd8486985d3860", + "B7BF3A5DF43989DD97F0FA97EBCE2F4A", "ae2d8a571e03ac9c9eb76fac45af8e51", "4febdc6740d20b3ac88f6ad82a4fb08d", + "E1C656305ED1A7A6563805746FE03EDC", "30c81c46a35ce411e5fbc1191a0a52ef", "71ab47a086e86eedf39d1c5bba97c408", + "41635BE625B48AFC1666DD42A09D96E7", "f69f2445df4f9b17ad2b417be66c3710", "0126141d67f37be8538f5a8be740e484", + 0, 0, 0, + }; + ivp = ofb_vector; + plainp = ofb_vector + 1; + cipherp = ofb_vector + 2; + while (*plainp && *cipherp) { + // encrypt + aes_encrypt_key256(fromhex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), &ctxe); + memcpy(iv, fromhex(*ivp), 16); + memcpy(ibuf, fromhex(*plainp), 16); + aes_ofb_encrypt(ibuf, obuf, 16, iv, &ctxe); + ck_assert_mem_eq(obuf, fromhex(*cipherp), 16); + // decrypt (uses encryption) + aes_encrypt_key256(fromhex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), &ctxe); + memcpy(iv, fromhex(*ivp), 16); + memcpy(ibuf, fromhex(*cipherp), 16); + aes_ofb_decrypt(ibuf, obuf, 16, iv, &ctxe); + ck_assert_mem_eq(obuf, fromhex(*plainp), 16); + ivp += 3; plainp += 3; cipherp += 3; + } - test_aes("mnemonic", 16, "ffffffffffffffffffffffffffffffff", "e720f4474b7dabe382eec0529e2b1128"); -// test_aes("mnemonic", 24, "ffffffffffffffffffffffffffffffffffffffffffffffff", "14dfe4c7a93e14616dce6c793110baee0b8bb404f3bec6c5"); -// test_aes("mnemonic", 32, "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "ccf498fd9a57f872a4d274549fab474cbacdbd9d935ca31b06e3025526a704fb"); + // CTR + static const char *ctr_vector[] = { + // plain cipher + "6bc1bee22e409f96e93d7e117393172a", "601ec313775789a5b7a7f504bbf3d228", + "ae2d8a571e03ac9c9eb76fac45af8e51", "f443e3ca4d62b59aca84e990cacaf5c5", + "30c81c46a35ce411e5fbc1191a0a52ef", "2b0930daa23de94ce87017ba2d84988d", + "f69f2445df4f9b17ad2b417be66c3710", "dfc9c58db67aada613c2dd08457941a6", + 0, 0, + }; + // encrypt + plainp = ctr_vector; + cipherp = ctr_vector + 1; + memcpy(cntr, fromhex("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"), 16); + aes_encrypt_key256(fromhex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), &ctxe); + while (*plainp && *cipherp) { + memcpy(ibuf, fromhex(*plainp), 16); + aes_ctr_encrypt(ibuf, obuf, 16, cntr, aes_ctr_counter_inc, &ctxe); + ck_assert_mem_eq(obuf, fromhex(*cipherp), 16); + plainp += 2; cipherp += 2; + } + // decrypt (uses encryption) + plainp = ctr_vector; + cipherp = ctr_vector + 1; + memcpy(cntr, fromhex("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"), 16); + aes_encrypt_key256(fromhex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), &ctxe); + while (*plainp && *cipherp) { + memcpy(ibuf, fromhex(*cipherp), 16); + aes_ctr_decrypt(ibuf, obuf, 16, cntr, aes_ctr_counter_inc, &ctxe); + ck_assert_mem_eq(obuf, fromhex(*plainp), 16); + plainp += 2; cipherp += 2; + } } END_TEST @@ -894,8 +1028,8 @@ Suite *test_suite(void) tcase_add_test(tc, test_ecdsa_der); suite_add_tcase(s, tc); - tc = tcase_create("rijndael"); - tcase_add_test(tc, test_rijndael); + tc = tcase_create("aes"); + tcase_add_test(tc, test_aes); suite_add_tcase(s, tc); tc = tcase_create("pbkdf2"); From b91bb29ae9954d993704fe36a688e87571d16a34 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 7 Jun 2014 13:56:13 +0200 Subject: [PATCH 101/627] remove brg_endian.h brg_types.h --- aes.h | 10 +-- aesopt.h | 4 +- brg_endian.h | 126 --------------------------------- brg_types.h | 191 --------------------------------------------------- 4 files changed, 9 insertions(+), 322 deletions(-) delete mode 100644 brg_endian.h delete mode 100644 brg_types.h diff --git a/aes.h b/aes.h index f56c1b88a..8d12648e0 100644 --- a/aes.h +++ b/aes.h @@ -25,15 +25,17 @@ Issue Date: 20/12/2007 #define _AES_H #include - -/* This include is used to find 8 & 32 bit unsigned integer types */ -#include "brg_types.h" +#include #if defined(__cplusplus) extern "C" { #endif +#define ALIGN_OFFSET(x,n) (((intptr_t)(x)) & ((n) - 1)) +#define ALIGN_FLOOR(x,n) ((uint8_t*)(x) - ( ((intptr_t)(x)) & ((n) - 1))) +#define ALIGN_CEIL(x,n) ((uint8_t*)(x) + (-((intptr_t)(x)) & ((n) - 1))) + // #define AES_128 /* if a fast 128 bit key scheduler is needed */ // #define AES_192 /* if a fast 192 bit key scheduler is needed */ #define AES_256 /* if a fast 256 bit key scheduler is needed */ @@ -60,7 +62,7 @@ extern "C" #define KS_LENGTH 44 #endif -#define AES_RETURN INT_RETURN +#define AES_RETURN int /* the character array 'inf' in the following structures is used */ /* to hold AES context information. This AES code uses cx->inf.b[0] */ diff --git a/aesopt.h b/aesopt.h index d3ac0f9be..89bb01eb1 100644 --- a/aesopt.h +++ b/aesopt.h @@ -95,7 +95,9 @@ Issue Date: 20/12/2007 /* PLATFORM SPECIFIC INCLUDES */ -#include "brg_endian.h" +#define IS_BIG_ENDIAN 4321 +#define IS_LITTLE_ENDIAN 1234 +#define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN /* CONFIGURATION - THE USE OF DEFINES diff --git a/brg_endian.h b/brg_endian.h deleted file mode 100644 index b44c5cbd6..000000000 --- a/brg_endian.h +++ /dev/null @@ -1,126 +0,0 @@ -/* ---------------------------------------------------------------------------- -Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved. - -The redistribution and use of this software (with or without changes) -is allowed without the payment of fees or royalties provided that: - - source code distributions include the above copyright notice, this - list of conditions and the following disclaimer; - - binary distributions include the above copyright notice, this list - of conditions and the following disclaimer in their documentation. - -This software is provided 'as is' with no explicit or implied warranties -in respect of its operation, including, but not limited to, correctness -and fitness for purpose. ---------------------------------------------------------------------------- -Issue Date: 20/12/2007 -*/ - -#ifndef _BRG_ENDIAN_H -#define _BRG_ENDIAN_H - -#define IS_BIG_ENDIAN 4321 /* byte 0 is most significant (mc68k) */ -#define IS_LITTLE_ENDIAN 1234 /* byte 0 is least significant (i386) */ - -/* Include files where endian defines and byteswap functions may reside */ -#if defined( __sun ) -# include -#elif defined( __FreeBSD__ ) || defined( __OpenBSD__ ) || defined( __NetBSD__ ) -# include -#elif defined( BSD ) && ( BSD >= 199103 ) || defined( __APPLE__ ) || \ - defined( __CYGWIN32__ ) || defined( __DJGPP__ ) || defined( __osf__ ) -# include -#elif defined( __linux__ ) || defined( __GNUC__ ) || defined( __GNU_LIBRARY__ ) -# if !defined( __MINGW32__ ) && !defined( _AIX ) -# include -# if !defined( __BEOS__ ) -# include -# endif -# endif -#endif - -/* Now attempt to set the define for platform byte order using any */ -/* of the four forms SYMBOL, _SYMBOL, __SYMBOL & __SYMBOL__, which */ -/* seem to encompass most endian symbol definitions */ - -#if defined( BIG_ENDIAN ) && defined( LITTLE_ENDIAN ) -# if defined( BYTE_ORDER ) && BYTE_ORDER == BIG_ENDIAN -# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN -# elif defined( BYTE_ORDER ) && BYTE_ORDER == LITTLE_ENDIAN -# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN -# endif -#elif defined( BIG_ENDIAN ) -# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN -#elif defined( LITTLE_ENDIAN ) -# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN -#endif - -#if defined( _BIG_ENDIAN ) && defined( _LITTLE_ENDIAN ) -# if defined( _BYTE_ORDER ) && _BYTE_ORDER == _BIG_ENDIAN -# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN -# elif defined( _BYTE_ORDER ) && _BYTE_ORDER == _LITTLE_ENDIAN -# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN -# endif -#elif defined( _BIG_ENDIAN ) -# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN -#elif defined( _LITTLE_ENDIAN ) -# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN -#endif - -#if defined( __BIG_ENDIAN ) && defined( __LITTLE_ENDIAN ) -# if defined( __BYTE_ORDER ) && __BYTE_ORDER == __BIG_ENDIAN -# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN -# elif defined( __BYTE_ORDER ) && __BYTE_ORDER == __LITTLE_ENDIAN -# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN -# endif -#elif defined( __BIG_ENDIAN ) -# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN -#elif defined( __LITTLE_ENDIAN ) -# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN -#endif - -#if defined( __BIG_ENDIAN__ ) && defined( __LITTLE_ENDIAN__ ) -# if defined( __BYTE_ORDER__ ) && __BYTE_ORDER__ == __BIG_ENDIAN__ -# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN -# elif defined( __BYTE_ORDER__ ) && __BYTE_ORDER__ == __LITTLE_ENDIAN__ -# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN -# endif -#elif defined( __BIG_ENDIAN__ ) -# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN -#elif defined( __LITTLE_ENDIAN__ ) -# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN -#endif - -/* if the platform byte order could not be determined, then try to */ -/* set this define using common machine defines */ -#if !defined(PLATFORM_BYTE_ORDER) - -#if defined( __alpha__ ) || defined( __alpha ) || defined( i386 ) || \ - defined( __i386__ ) || defined( _M_I86 ) || defined( _M_IX86 ) || \ - defined( __OS2__ ) || defined( sun386 ) || defined( __TURBOC__ ) || \ - defined( vax ) || defined( vms ) || defined( VMS ) || \ - defined( __VMS ) || defined( _M_X64 ) -# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN - -#elif defined( AMIGA ) || defined( applec ) || defined( __AS400__ ) || \ - defined( _CRAY ) || defined( __hppa ) || defined( __hp9000 ) || \ - defined( ibm370 ) || defined( mc68000 ) || defined( m68k ) || \ - defined( __MRC__ ) || defined( __MVS__ ) || defined( __MWERKS__ ) || \ - defined( sparc ) || defined( __sparc) || defined( SYMANTEC_C ) || \ - defined( __VOS__ ) || defined( __TIGCC__ ) || defined( __TANDEM ) || \ - defined( THINK_C ) || defined( __VMCMS__ ) || defined( _AIX ) -# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN - -#elif 0 /* **** EDIT HERE IF NECESSARY **** */ -# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN -#elif 0 /* **** EDIT HERE IF NECESSARY **** */ -# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN -#else -# error Please edit lines 126 or 128 in brg_endian.h to set the platform byte order -#endif - -#endif - -#endif diff --git a/brg_types.h b/brg_types.h deleted file mode 100644 index 307319bf6..000000000 --- a/brg_types.h +++ /dev/null @@ -1,191 +0,0 @@ -/* ---------------------------------------------------------------------------- -Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved. - -The redistribution and use of this software (with or without changes) -is allowed without the payment of fees or royalties provided that: - - source code distributions include the above copyright notice, this - list of conditions and the following disclaimer; - - binary distributions include the above copyright notice, this list - of conditions and the following disclaimer in their documentation. - -This software is provided 'as is' with no explicit or implied warranties -in respect of its operation, including, but not limited to, correctness -and fitness for purpose. ---------------------------------------------------------------------------- -Issue Date: 20/12/2007 - - The unsigned integer types defined here are of the form uint_t where - is the length of the type; for example, the unsigned 32-bit type is - 'uint32_t'. These are NOT the same as the 'C99 integer types' that are - defined in the inttypes.h and stdint.h headers since attempts to use these - types have shown that support for them is still highly variable. However, - since the latter are of the form uint_t, a regular expression search - and replace (in VC++ search on 'uint_{:z}t' and replace with 'uint\1_t') - can be used to convert the types used here to the C99 standard types. -*/ - -#ifndef _BRG_TYPES_H -#define _BRG_TYPES_H - -#if defined(__cplusplus) -extern "C" { -#endif - -#include -#include - -#if defined( _MSC_VER ) && ( _MSC_VER >= 1300 ) -# include -# define ptrint_t intptr_t -#elif defined( __ECOS__ ) -# define intptr_t unsigned int -# define ptrint_t intptr_t -#elif defined( __GNUC__ ) && ( __GNUC__ >= 3 ) -# define ptrint_t intptr_t -#else -# define ptrint_t int -#endif - -#ifndef BRG_UI32 -# define BRG_UI32 -# if UINT_MAX == 4294967295u -# define li_32(h) 0x##h##u -# elif ULONG_MAX == 4294967295u -# define li_32(h) 0x##h##ul -# elif defined( _CRAY ) -# error This code needs 32-bit data types, which Cray machines do not provide -# else -# error Please define uint32_t as a 32-bit unsigned integer type in brg_types.h -# endif -#endif - -#ifndef BRG_UI64 -# if defined( __BORLANDC__ ) && !defined( __MSDOS__ ) -# define BRG_UI64 -# define li_64(h) 0x##h##ui64 -# elif defined( _MSC_VER ) && ( _MSC_VER < 1300 ) /* 1300 == VC++ 7.0 */ -# define BRG_UI64 -# define li_64(h) 0x##h##ui64 -# elif defined( __sun ) && defined( ULONG_MAX ) && ULONG_MAX == 0xfffffffful -# define BRG_UI64 -# define li_64(h) 0x##h##ull -# elif defined( __MVS__ ) -# define BRG_UI64 -# define li_64(h) 0x##h##ull -# elif defined( UINT_MAX ) && UINT_MAX > 4294967295u -# if UINT_MAX == 18446744073709551615u -# define BRG_UI64 -# define li_64(h) 0x##h##u -# endif -# elif defined( ULONG_MAX ) && ULONG_MAX > 4294967295u -# if ULONG_MAX == 18446744073709551615ul -# define BRG_UI64 -# define li_64(h) 0x##h##ul -# endif -# elif defined( ULLONG_MAX ) && ULLONG_MAX > 4294967295u -# if ULLONG_MAX == 18446744073709551615ull -# define BRG_UI64 -# define li_64(h) 0x##h##ull -# endif -# elif defined( ULONG_LONG_MAX ) && ULONG_LONG_MAX > 4294967295u -# if ULONG_LONG_MAX == 18446744073709551615ull -# define BRG_UI64 -# define li_64(h) 0x##h##ull -# endif -# endif -#endif - -#if !defined( BRG_UI64 ) -# if defined( NEED_UINT_64T ) -# error Please define uint64_t as an unsigned 64 bit type in brg_types.h -# endif -#endif - -#ifndef RETURN_VALUES -# define RETURN_VALUES -# if defined( DLL_EXPORT ) -# if defined( _MSC_VER ) || defined ( __INTEL_COMPILER ) -# define VOID_RETURN __declspec( dllexport ) void __stdcall -# define INT_RETURN __declspec( dllexport ) int __stdcall -# elif defined( __GNUC__ ) -# define VOID_RETURN __declspec( __dllexport__ ) void -# define INT_RETURN __declspec( __dllexport__ ) int -# else -# error Use of the DLL is only available on the Microsoft, Intel and GCC compilers -# endif -# elif defined( DLL_IMPORT ) -# if defined( _MSC_VER ) || defined ( __INTEL_COMPILER ) -# define VOID_RETURN __declspec( dllimport ) void __stdcall -# define INT_RETURN __declspec( dllimport ) int __stdcall -# elif defined( __GNUC__ ) -# define VOID_RETURN __declspec( __dllimport__ ) void -# define INT_RETURN __declspec( __dllimport__ ) int -# else -# error Use of the DLL is only available on the Microsoft, Intel and GCC compilers -# endif -# elif defined( __WATCOMC__ ) -# define VOID_RETURN void __cdecl -# define INT_RETURN int __cdecl -# else -# define VOID_RETURN void -# define INT_RETURN int -# endif -#endif - -/* These defines are used to detect and set the memory alignment of pointers. - Note that offsets are in bytes. - - ALIGN_OFFSET(x,n) return the positive or zero offset of - the memory addressed by the pointer 'x' - from an address that is aligned on an - 'n' byte boundary ('n' is a power of 2) - - ALIGN_FLOOR(x,n) return a pointer that points to memory - that is aligned on an 'n' byte boundary - and is not higher than the memory address - pointed to by 'x' ('n' is a power of 2) - - ALIGN_CEIL(x,n) return a pointer that points to memory - that is aligned on an 'n' byte boundary - and is not lower than the memory address - pointed to by 'x' ('n' is a power of 2) -*/ - -#define ALIGN_OFFSET(x,n) (((ptrint_t)(x)) & ((n) - 1)) -#define ALIGN_FLOOR(x,n) ((uint8_t*)(x) - ( ((ptrint_t)(x)) & ((n) - 1))) -#define ALIGN_CEIL(x,n) ((uint8_t*)(x) + (-((ptrint_t)(x)) & ((n) - 1))) - -/* These defines are used to declare buffers in a way that allows - faster operations on longer variables to be used. In all these - defines 'size' must be a power of 2 and >= 8. NOTE that the - buffer size is in bytes but the type length is in bits - - UNIT_TYPEDEF(x,size) declares a variable 'x' of length - 'size' bits - - BUFR_TYPEDEF(x,size,bsize) declares a buffer 'x' of length 'bsize' - bytes defined as an array of variables - each of 'size' bits (bsize must be a - multiple of size / 8) - - UNIT_CAST(x,size) casts a variable to a type of - length 'size' bits - - UPTR_CAST(x,size) casts a pointer to a pointer to a - varaiable of length 'size' bits -*/ - -#define UI_TYPE(size) uint##size##_t -#define UNIT_TYPEDEF(x,size) typedef UI_TYPE(size) x -#define BUFR_TYPEDEF(x,size,bsize) typedef UI_TYPE(size) x[bsize / (size >> 3)] -#define UNIT_CAST(x,size) ((UI_TYPE(size) )(x)) -#define UPTR_CAST(x,size) ((UI_TYPE(size)*)(x)) - -#if defined(__cplusplus) -} -#endif - -#endif From 22b0dd2e6244e7e9e4b7ae6a47b405a753a02a34 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 7 Jun 2014 14:05:59 +0200 Subject: [PATCH 102/627] fix warning in base58 --- base58.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/base58.c b/base58.c index 4ed2a3b31..c4bdd2544 100644 --- a/base58.c +++ b/base58.c @@ -88,8 +88,7 @@ int base58_decode_check(const char *str, uint8_t *data) 43, -1, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57 }; - uint8_t mydata[82], hash[32]; - int j, k, outlen; + int outlen; switch (strlen(str)) { case 111: // xpub/xprv outlen = 78; @@ -110,12 +109,15 @@ int base58_decode_check(const char *str, uint8_t *data) default: return 0; } + uint8_t mydata[82], hash[32]; memset(mydata, 0, sizeof(mydata)); + int i, j, k; while (*str) { - if (*str < 0 || *str >= (int)sizeof(decode)) { // invalid character + i = *str; + if (i < 0 || i >= (int)sizeof(decode)) { // invalid character return 0; } - k = decode[(int)*str]; + k = decode[i]; if (k == -1) { // invalid character return 0; } From b16e36f10e1fdf3a00c263c06468506f982030a8 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 7 Jun 2014 14:13:05 +0200 Subject: [PATCH 103/627] rename aes_ctr_counter_inc to aes_ctr_cbuf_inc and move it to aes_modes.c --- aes.h | 2 ++ aes_modes.c | 10 ++++++++++ tests.c | 20 +++++--------------- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/aes.h b/aes.h index 8d12648e0..524f4c0f5 100644 --- a/aes.h +++ b/aes.h @@ -196,6 +196,8 @@ typedef void cbuf_inc(unsigned char *cbuf); AES_RETURN aes_ctr_crypt(const unsigned char *ibuf, unsigned char *obuf, int len, unsigned char *cbuf, cbuf_inc ctr_inc, aes_encrypt_ctx cx[1]); +void aes_ctr_cbuf_inc(unsigned char *cbuf); + #endif #if defined(__cplusplus) diff --git a/aes_modes.c b/aes_modes.c index a6e37ed80..2a432c804 100644 --- a/aes_modes.c +++ b/aes_modes.c @@ -941,6 +941,16 @@ AES_RETURN aes_ctr_crypt(const unsigned char *ibuf, unsigned char *obuf, return EXIT_SUCCESS; } +void aes_ctr_cbuf_inc(unsigned char *cbuf) +{ + int i = 15; + while (i >= 0) { + cbuf[i]++; + if (cbuf[i]) return; // if there was no overflow + i--; + } +} + #if defined(__cplusplus) } #endif diff --git a/tests.c b/tests.c index 69195cd8e..a6e33305c 100644 --- a/tests.c +++ b/tests.c @@ -437,22 +437,12 @@ START_TEST(test_verify_speed) } END_TEST -void aes_ctr_counter_inc(uint8_t *ctr) -{ - int i = 15; - while (i >= 0) { - ctr[i]++; - if (ctr[i]) return; // if there was no overflow - i--; - } -} - // test vectors from http://www.inconteam.com/software-development/41-encryption/55-aes-test-vectors START_TEST(test_aes) { aes_encrypt_ctx ctxe; aes_decrypt_ctx ctxd; - uint8_t ibuf[16], obuf[16], iv[16], cntr[16]; + uint8_t ibuf[16], obuf[16], iv[16], cbuf[16]; const char **ivp, **plainp, **cipherp; // ECB @@ -574,22 +564,22 @@ START_TEST(test_aes) // encrypt plainp = ctr_vector; cipherp = ctr_vector + 1; - memcpy(cntr, fromhex("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"), 16); + memcpy(cbuf, fromhex("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"), 16); aes_encrypt_key256(fromhex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), &ctxe); while (*plainp && *cipherp) { memcpy(ibuf, fromhex(*plainp), 16); - aes_ctr_encrypt(ibuf, obuf, 16, cntr, aes_ctr_counter_inc, &ctxe); + aes_ctr_encrypt(ibuf, obuf, 16, cbuf, aes_ctr_cbuf_inc, &ctxe); ck_assert_mem_eq(obuf, fromhex(*cipherp), 16); plainp += 2; cipherp += 2; } // decrypt (uses encryption) plainp = ctr_vector; cipherp = ctr_vector + 1; - memcpy(cntr, fromhex("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"), 16); + memcpy(cbuf, fromhex("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"), 16); aes_encrypt_key256(fromhex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), &ctxe); while (*plainp && *cipherp) { memcpy(ibuf, fromhex(*cipherp), 16); - aes_ctr_decrypt(ibuf, obuf, 16, cntr, aes_ctr_counter_inc, &ctxe); + aes_ctr_decrypt(ibuf, obuf, 16, cbuf, aes_ctr_cbuf_inc, &ctxe); ck_assert_mem_eq(obuf, fromhex(*plainp), 16); plainp += 2; cipherp += 2; } From e588906f811e826c596e631d4dd2500fc38fea60 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 9 Jun 2014 13:51:31 +0200 Subject: [PATCH 104/627] fix static usage --- bip39.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/bip39.c b/bip39.c index d12105935..fe0d4f121 100644 --- a/bip39.c +++ b/bip39.c @@ -35,7 +35,7 @@ const char *mnemonic_generate(int strength) if (strength % 32 || strength < 128 || strength > 256) { return 0; } - static uint8_t data[32]; + uint8_t data[32]; random_buffer(data, 32); return mnemonic_from_data(data, strength / 8); } @@ -47,10 +47,11 @@ const char *mnemonic_from_data(const uint8_t *data, int len) } uint8_t bits[32 + 1]; - memcpy(bits, data, len); sha256_Raw(data, len, bits); + // checksum bits[len] = bits[0]; + // data memcpy(bits, data, len); int mlen = len * 3 / 4; @@ -146,7 +147,7 @@ int mnemonic_check(const char *mnemonic) void mnemonic_to_seed(const char *mnemonic, const char *passphrase, uint8_t seed[512 / 8], void (*progress_callback)(uint32_t current, uint32_t total)) { - static uint8_t salt[8 + 256 + 4]; + uint8_t salt[8 + 256 + 4]; int saltlen = strlen(passphrase); memcpy(salt, "mnemonic", 8); memcpy(salt + 8, passphrase, saltlen); From 0ad302ea4e83b9a622b13d49d628536fea7ef688 Mon Sep 17 00:00:00 2001 From: Ondrej Mikle Date: Tue, 1 Jul 2014 16:16:06 +0200 Subject: [PATCH 105/627] Hashing of secp256k1 pubkey recognizes point at infinity. --- ecdsa.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ecdsa.c b/ecdsa.c index 31128d122..e8d5cdad2 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -338,10 +338,12 @@ void ecdsa_get_public_key65(const uint8_t *priv_key, uint8_t *pub_key) void ecdsa_get_pubkeyhash(const uint8_t *pub_key, uint8_t *pubkeyhash) { uint8_t h[32]; - if (pub_key[0] == 0x04) { + if (pub_key[0] == 0x04) { // uncompressed format sha256_Raw(pub_key, 65, h); + } else if (pub_key[0] == 0x00) { // point at infinity + sha256_Raw(pub_key, 1, h); } else { - sha256_Raw(pub_key, 33, h); + sha256_Raw(pub_key, 33, h); // expecting compressed format } ripemd160(h, 32, pubkeyhash); } From 3747ba432336bf10191a63e84fbfead62e944ddb Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 3 Jul 2014 01:18:00 +0200 Subject: [PATCH 106/627] Revert "add more precomputation to ecdsa signing" This reverts commit 06dd166a82d465f6db297616b42446c8b4498efe. --- bignum.c | 130 ++++++------- ecdsa.c | 41 ++--- secp256k1.c | 513 ---------------------------------------------------- secp256k1.h | 1 - 4 files changed, 74 insertions(+), 611 deletions(-) diff --git a/bignum.c b/bignum.c index 06e7308bc..2fdb52bd8 100644 --- a/bignum.c +++ b/bignum.c @@ -303,20 +303,14 @@ void bn_inverse(bignum256 *x, const bignum256 *prime) void bn_inverse(bignum256 *x, const bignum256 *prime) { int i, j, k, len1, len2, mask; - uint8_t buf[32]; - uint32_t u[8], v[8], s[9], r[10], temp32; - uint64_t temp, temp2; + uint32_t u[9], v[9], s[10], r[10], temp, temp2; bn_fast_mod(x, prime); bn_mod(x, prime); - bn_write_be(prime, buf); - for (i = 0; i < 8; i++) { - u[i] = read_be(buf + 28 - i * 4); - } - bn_write_be(x, buf); - for (i = 0; i < 8; i++) { - v[i] = read_be(buf + 28 - i * 4); + for (i = 0; i < 9; i++) { + u[i] = prime->val[i]; + v[i] = x->val[i]; } - len1 = 8; + len1 = 9; s[0] = 1; r[0] = 0; len2 = 1; @@ -333,13 +327,13 @@ void bn_inverse(bignum256 *x, const bignum256 *prime) if (i == 0) break; mask = (1 << i) - 1; for (j = 0; j + 1 < len1; j++) { - u[j] = (u[j] >> i) | ((u[j + 1] & mask) << (32 - i)); + u[j] = (u[j] >> i) | ((u[j + 1] & mask) << (30 - i)); } u[j] = (u[j] >> i); - mask = (1 << (32 - i)) - 1; - s[len2] = s[len2 - 1] >> (32 - i); + mask = (1 << (30 - i)) - 1; + s[len2] = s[len2 - 1] >> (30 - i); for (j = len2 - 1; j > 0; j--) { - s[j] = (s[j - 1] >> (32 - i)) | ((s[j] & mask) << i); + s[j] = (s[j - 1] >> (30 - i)) | ((s[j] & mask) << i); } s[0] = (s[0] & mask) << i; if (s[len2]) { @@ -355,13 +349,13 @@ void bn_inverse(bignum256 *x, const bignum256 *prime) if (i == 0) break; mask = (1 << i) - 1; for (j = 0; j + 1 < len1; j++) { - v[j] = (v[j] >> i) | ((v[j + 1] & mask) << (32 - i)); + v[j] = (v[j] >> i) | ((v[j + 1] & mask) << (30 - i)); } v[j] = (v[j] >> i); - mask = (1 << (32 - i)) - 1; - r[len2] = r[len2 - 1] >> (32 - i); + mask = (1 << (30 - i)) - 1; + r[len2] = r[len2 - 1] >> (30 - i); for (j = len2 - 1; j > 0; j--) { - r[j] = (r[j - 1] >> (32 - i)) | ((r[j] & mask) << i); + r[j] = (r[j - 1] >> (30 - i)) | ((r[j] & mask) << i); } r[0] = (r[0] & mask) << i; if (r[len2]) { @@ -374,25 +368,23 @@ void bn_inverse(bignum256 *x, const bignum256 *prime) i = len1 - 1; while (i > 0 && u[i] == v[i]) i--; if (u[i] > v[i]) { - temp = 0x100000000ull + u[0] - v[0]; - u[0] = (temp >> 1) & 0x7FFFFFFF; - temp >>= 32; + temp = 0x40000000u + u[0] - v[0]; + u[0] = (temp >> 1) & 0x1FFFFFFF; + temp >>= 30; for (i = 1; i < len1; i++) { - temp += 0xFFFFFFFFull + u[i] - v[i]; - u[i - 1] += (temp & 1) << 31; - u[i] = (temp >> 1) & 0x7FFFFFFF; - temp >>= 32; + temp += 0x3FFFFFFFu + u[i] - v[i]; + u[i - 1] += (temp & 1) << 29; + u[i] = (temp >> 1) & 0x1FFFFFFF; + temp >>= 30; } temp = temp2 = 0; for (i = 0; i < len2; i++) { - temp += s[i]; - temp += r[i]; - temp2 += s[i]; - temp2 += s[i]; - r[i] = temp; - s[i] = temp2; - temp >>= 32; - temp2 >>= 32; + temp += s[i] + r[i]; + temp2 += s[i] << 1; + r[i] = temp & 0x3FFFFFFF; + s[i] = temp2 & 0x3FFFFFFF; + temp >>= 30; + temp2 >>= 30; } if (temp != 0 || temp2 != 0) { r[len2] = temp; @@ -400,25 +392,23 @@ void bn_inverse(bignum256 *x, const bignum256 *prime) len2++; } } else { - temp = 0x100000000ull + v[0] - u[0]; - v[0] = (temp >> 1) & 0x7FFFFFFF; - temp >>= 32; + temp = 0x40000000u + v[0] - u[0]; + v[0] = (temp >> 1) & 0x1FFFFFFF; + temp >>= 30; for (i = 1; i < len1; i++) { - temp += 0xFFFFFFFFull + v[i] - u[i]; - v[i - 1] += (temp & 1) << 31; - v[i] = (temp >> 1) & 0x7FFFFFFF; - temp >>= 32; + temp += 0x3FFFFFFFu + v[i] - u[i]; + v[i - 1] += (temp & 1) << 29; + v[i] = (temp >> 1) & 0x1FFFFFFF; + temp >>= 30; } temp = temp2 = 0; for (i = 0; i < len2; i++) { - temp += s[i]; - temp += r[i]; - temp2 += r[i]; - temp2 += r[i]; - s[i] = temp; - r[i] = temp2; - temp >>= 32; - temp2 >>= 32; + temp += s[i] + r[i]; + temp2 += r[i] << 1; + s[i] = temp & 0x3FFFFFFF; + r[i] = temp2 & 0x3FFFFFFF; + temp >>= 30; + temp2 >>= 30; } if (temp != 0 || temp2 != 0) { s[len2] = temp; @@ -429,33 +419,21 @@ void bn_inverse(bignum256 *x, const bignum256 *prime) if (u[len1 - 1] == 0 && v[len1 - 1] == 0) len1--; k++; } - - j = r[0] >> 30; - r[0] = r[0] & 0x3FFFFFFFu; - for (i = 1; i < len2; i++) { - uint32_t q = r[i] >> (30 - 2 * i); - r[i] = ((r[i] << (2 * i)) & 0x3FFFFFFFu) + j; - j=q; - } - r[i] = j; - i++; - for (; i < 9; i++) r[i] = 0; - i = 8; while (i > 0 && r[i] == prime->val[i]) i--; if (r[i] >= prime->val[i]) { - temp32 = 1; + temp = 1; for (i = 0; i < 9; i++) { - temp32 += 0x3FFFFFFF + r[i] - prime->val[i]; - r[i] = temp32 & 0x3FFFFFFF; - temp32 >>= 30; + temp += 0x3FFFFFFF + r[i] - prime->val[i]; + r[i] = temp & 0x3FFFFFFF; + temp >>= 30; } } - temp32 = 1; + temp = 1; for (i = 0; i < 9; i++) { - temp32 += 0x3FFFFFFF + prime->val[i] - r[i]; - r[i] = temp32 & 0x3FFFFFFF; - temp32 >>= 30; + temp += 0x3FFFFFFF + prime->val[i] - r[i]; + r[i] = temp & 0x3FFFFFFF; + temp >>= 30; } int done = 0; #if USE_PRECOMPUTED_IV @@ -471,14 +449,14 @@ void bn_inverse(bignum256 *x, const bignum256 *prime) if (!done) { for (j = 0; j < k; j++) { if (r[0] & 1) { - temp32 = r[0] + prime->val[0]; - r[0] = (temp32 >> 1) & 0x1FFFFFFF; - temp32 >>= 30; + temp = r[0] + prime->val[0]; + r[0] = (temp >> 1) & 0x1FFFFFFF; + temp >>= 30; for (i = 1; i < 9; i++) { - temp32 += r[i] + prime->val[i]; - r[i - 1] += (temp32 & 1) << 29; - r[i] = (temp32 >> 1) & 0x1FFFFFFF; - temp32 >>= 30; + temp += r[i] + prime->val[i]; + r[i - 1] += (temp & 1) << 29; + r[i] = (temp >> 1) & 0x1FFFFFFF; + temp >>= 30; } } else { for (i = 0; i < 8; i++) { diff --git a/ecdsa.c b/ecdsa.c index e8d5cdad2..499356c1e 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -123,39 +123,38 @@ void point_multiply(const bignum256 *k, const curve_point *p, curve_point *res) // res = k * G void scalar_multiply(const bignum256 *k, curve_point *res) { - int i; + int i, j; // result is zero int is_zero = 1; +#if USE_PRECOMPUTED_CP + int exp = 0; +#else curve_point curr; // initial res memcpy(&curr, &G256k1, sizeof(curve_point)); - for (i = 0; i < 256; i++) { - if (k->val[i / 30] & (1u << (i % 30))) { - if (is_zero) { +#endif + for (i = 0; i < 9; i++) { + for (j = 0; j < 30; j++) { + if (i == 8 && (k->val[i] >> j) == 0) break; + if (k->val[i] & (1u << j)) { + if (is_zero) { #if USE_PRECOMPUTED_CP - if (i < 255 && (k->val[(i + 1) / 30] & (1u << ((i + 1) % 30)))) { - memcpy(res, secp256k1_cp2 + i, sizeof(curve_point)); - i++; - } else { - memcpy(res, secp256k1_cp + i, sizeof(curve_point)); - } + memcpy(res, secp256k1_cp + exp, sizeof(curve_point)); #else - memcpy(res, &curr, sizeof(curve_point)); + memcpy(res, &curr, sizeof(curve_point)); #endif - is_zero = 0; - } else { -#if USE_PRECOMPUTED_CP - if (i < 255 && (k->val[(i + 1) / 30] & (1u << ((i + 1) % 30)))) { - point_add(secp256k1_cp2 + i, res); - i++; + is_zero = 0; } else { - point_add(secp256k1_cp + i, res); - } +#if USE_PRECOMPUTED_CP + point_add(secp256k1_cp + exp, res); #else - point_add(&curr, res); + point_add(&curr, res); #endif + } } -#if ! USE_PRECOMPUTED_CP +#if USE_PRECOMPUTED_CP + exp++; +#else point_double(&curr); #endif } diff --git a/secp256k1.c b/secp256k1.c index 40aa97281..b941937d2 100644 --- a/secp256k1.c +++ b/secp256k1.c @@ -815,517 +815,4 @@ const curve_point secp256k1_cp[256] = { {/*.x =*/{/*.val =*/{0x3f8be384, 0x22f4c810, 0x31db6c3e, 0x3b02ab68, 0x1ef07271, 0x2b5b253f, 0x23e1b251, 0x24290af9, 0xb237}}, /*.y =*/{/*.val =*/{0x2b19880e, 0x4291cf7, 0x9ecb58d, 0x3c013d05, 0x1f94517, 0x143e22aa, 0x15edbe8d, 0x1a524675, 0xfc6b}}}, }; - -const curve_point secp256k1_cp2[255] = { -{/*.x =*/{/*.val =*/{0x3ce036f9, 0x1807c44e, 0x36f99b08, 0xc721160, 0x1d5229b5, 0x113e17e2, 0xc310493, 0x22806496, 0xf930}}, - /*.y =*/{/*.val =*/{0x4b8e672, 0x32e7f5d6, 0xc2231b6, 0x2a664d, 0x37f35665, 0xcdf98a8, 0x1e8140fe, 0x1ec3d8cb, 0x388f}}}, -{/*.x =*/{/*.val =*/{0x20297556, 0x3c15e851, 0x168a18b2, 0x3d91cbe1, 0x1235d382, 0x14e850d5, 0x2eea4204, 0x1ef55d57, 0xfff9}}, - /*.y =*/{/*.val =*/{0x3075f297, 0x321c30da, 0x18fe4a03, 0x203c3d94, 0x5c560de, 0x3a5805fd, 0x3b620f3b, 0x1ddeab3e, 0xae12}}}, -{/*.x =*/{/*.val =*/{0x30afe85a, 0x16c3d1c1, 0x220095bc, 0x1f3d1065, 0x33463368, 0xe3c0135, 0x3561b15c, 0x5755239, 0xd011}}, - /*.y =*/{/*.val =*/{0x34062327, 0x2c146c4f, 0x1a86d526, 0x8e31776, 0x3bd81579, 0x1914df85, 0x1e0d7a8b, 0x13ff7205, 0xa9f3}}}, -{/*.x =*/{/*.val =*/{0x3202e6ce, 0x140af6a2, 0x162b7940, 0xc8550e7, 0x3a8b0968, 0x2724586, 0x133d48ac, 0x310d504f, 0xfe72}}, - /*.y =*/{/*.val =*/{0xf58c5bf, 0x1e3b4bef, 0x34a9d229, 0x372238da, 0x32998101, 0x2d1f8275, 0x24a68d3a, 0x37819ffc, 0x6851}}}, -{/*.x =*/{/*.val =*/{0x1118e5c3, 0x2f61c2a8, 0x12bebc19, 0x15e6c9d1, 0x265b4bfc, 0x595bbd3, 0x1307db44, 0xcd76591, 0x6eca}}, - /*.y =*/{/*.val =*/{0x5a08668, 0x2628bde0, 0x3f8ec344, 0x125a8e8e, 0x3875a03a, 0x3d5e41d2, 0x20710592, 0x8ed5e9e, 0xd501}}}, -{/*.x =*/{/*.val =*/{0x3f8cb0e3, 0xe4ceb29, 0x1efe3a44, 0xbad4ff8, 0x2eb72ea2, 0x1938112c, 0x16d8f8fa, 0x20395d11, 0x3f0e}}, - /*.y =*/{/*.val =*/{0x2a5f404f, 0x2c0a278b, 0x25b53a4c, 0x494ea9, 0x1d01b395, 0x2e702121, 0xbc91e90, 0x35f5ca5b, 0xcb66}}}, -{/*.x =*/{/*.val =*/{0x33ce1752, 0x1edd43dc, 0x3cd204ec, 0x20f1e5f5, 0x1c9aeae7, 0x377d9366, 0x1c635812, 0x36963407, 0xd7a0}}, - /*.y =*/{/*.val =*/{0x762cef4, 0x2f009ce0, 0x62b742b, 0x38102a30, 0x2284650b, 0xa4a0d03, 0x8032f6f, 0x1c381a00, 0x9127}}}, -{/*.x =*/{/*.val =*/{0x35476085, 0x2422dc06, 0x2eb9f84a, 0x1c539de5, 0xed1afb5, 0xeab5a9e, 0xcd3e10d, 0x29c19e82, 0x3443}}, - /*.y =*/{/*.val =*/{0xb8f52d8, 0x34d212f6, 0xc2b67f6, 0x2292c9f4, 0x3e1da901, 0x3a312e31, 0x36f854f6, 0x1e97e0a6, 0x661a}}}, -{/*.x =*/{/*.val =*/{0x257e8dfa, 0x33f032e7, 0x3c7e184f, 0x20246468, 0x298ca009, 0x28c3e2b2, 0x19c4c0d9, 0x33cbfc1e, 0x8262}}, - /*.y =*/{/*.val =*/{0x3bac376a, 0x173fe363, 0x314c4783, 0x2dbb4cca, 0x334f3457, 0x3b88bb16, 0x9e4e66f, 0x25788244, 0x83fd}}}, -{/*.x =*/{/*.val =*/{0x3c70620c, 0x5f307c9, 0x3c288d9d, 0x26312faa, 0x27178049, 0x374c68ad, 0x236dc60, 0x2a29234b, 0x1653}}, - /*.y =*/{/*.val =*/{0x315b32cd, 0x328ba074, 0x3d3dc526, 0xabdd237, 0x3a701c01, 0x2a651d3b, 0x37f7aeaf, 0xa424d6b, 0x338}}}, -{/*.x =*/{/*.val =*/{0x271dabcd, 0x1f50ae9b, 0x1e5cb4f4, 0x34ff9262, 0x35373f54, 0x22b8c982, 0x3f43c609, 0x393edad8, 0xd49e}}, - /*.y =*/{/*.val =*/{0x16603c2, 0x19aa433c, 0x2ff7031e, 0x271424c4, 0x1bf35612, 0x21fa9e98, 0x1490dd7c, 0x38e48269, 0x531}}}, -{/*.x =*/{/*.val =*/{0xc8c828a, 0xfcc2ae4, 0x16ae41f5, 0xbac90b2, 0x281c7513, 0x1283605f, 0x9e750e4, 0x21472905, 0x5f94}}, - /*.y =*/{/*.val =*/{0x37344d80, 0x3fac28fc, 0x3c68b04b, 0x19b7dd53, 0x2f35e8c, 0x1e5f622, 0x1fee8e5f, 0x30ee2be8, 0x26b8}}}, -{/*.x =*/{/*.val =*/{0x5041216, 0x16dfe3c7, 0x2b836a6, 0x1ccd7da1, 0x2fed523f, 0x2d67bf70, 0x3acf4128, 0xc5ec87d, 0xda75}}, - /*.y =*/{/*.val =*/{0x2e708572, 0x2bb4ca61, 0x37acedad, 0x2ab01eb9, 0x2d7fc6e9, 0x27886cd0, 0x2d5f0df1, 0x2811afdc, 0x73f8}}}, -{/*.x =*/{/*.val =*/{0x3c62bac0, 0x1414c93c, 0x1f0ab069, 0x54377d4, 0x28b70e19, 0x12df4b0f, 0x3469c136, 0x3c3e408f, 0x9530}}, - /*.y =*/{/*.val =*/{0x3618e309, 0x1e2af6a5, 0x31fdc684, 0x16cca14b, 0x3333e0e2, 0x34bdfd66, 0x321e234d, 0xc16a3e7, 0x8f3c}}}, -{/*.x =*/{/*.val =*/{0x1c3c9c8f, 0x19c10e17, 0x24367b20, 0x205bfb8f, 0x2332b0f2, 0x27fd0eaa, 0x298fd6f0, 0xb72f90, 0x67be}}, - /*.y =*/{/*.val =*/{0x193652d9, 0x14e12661, 0x388c2be5, 0x264efd82, 0x291693cd, 0x2516d820, 0x1ef84a2c, 0x1569cf93, 0x7a9b}}}, -{/*.x =*/{/*.val =*/{0x10aaa33a, 0x7e6f2f8, 0x17b9ca51, 0x24b74a70, 0x1718368c, 0x1a404ef1, 0x3876adf5, 0x924bd3b, 0x893b}}, - /*.y =*/{/*.val =*/{0x11af3445, 0x1ee02e2b, 0x3ceeb426, 0xe7a2884, 0x107f32a4, 0xe801d99, 0x1c89ef41, 0x14ad9cb4, 0xcdb1}}}, -{/*.x =*/{/*.val =*/{0x36e55dc8, 0x2e24485b, 0x2ca04394, 0x3e56adba, 0x1094426f, 0x12910301, 0x1ffb2ba8, 0x1011e431, 0x4431}}, - /*.y =*/{/*.val =*/{0x1be323b3, 0x76512bb, 0x2aa2e503, 0x1a8a6de7, 0x2fed7a6, 0x260dfd59, 0x366f8fe9, 0x3050b994, 0x96b0}}}, -{/*.x =*/{/*.val =*/{0x33f0e9aa, 0x3ad78658, 0x11bd34b3, 0x449ddac, 0x138d268, 0x92b8356, 0x326adb79, 0x3fa15d7, 0xe538}}, - /*.y =*/{/*.val =*/{0x82720f, 0x12e904d9, 0x68318ec, 0x2e53977d, 0xc8e016f, 0x244d8e49, 0x3b41d5b6, 0x361ce421, 0xb97f}}}, -{/*.x =*/{/*.val =*/{0x2ebc61d6, 0x2bb4d86f, 0x1ff42de1, 0x23f4e9f6, 0x2b1f518a, 0x17c34575, 0x19af0c39, 0x3cf928fb, 0x939f}}, - /*.y =*/{/*.val =*/{0x23f5cb70, 0x1d7a919a, 0x38c7f82e, 0x2fc9bad, 0x16c0498, 0x1bf13bbc, 0x3a90e9d4, 0xef3c22d, 0xdeab}}}, -{/*.x =*/{/*.val =*/{0x497e0df, 0x5b84d37, 0xf76f530, 0xeed0dbb, 0x2029a04c, 0x161e17f9, 0x3293078, 0xf94ab8e, 0xfdc6}}, - /*.y =*/{/*.val =*/{0x1b9eb19f, 0x1811127, 0x335d9d5f, 0x2fac8bef, 0x22e8b87b, 0x3dc50a2b, 0x3bb52e3d, 0x2b59eb3a, 0x292d}}}, -{/*.x =*/{/*.val =*/{0x355812dd, 0x28a960b, 0x12d30e2a, 0x1119c8d5, 0x18f78e3d, 0x2afb5b01, 0x3352f0b6, 0x2f5ea4bf, 0x7029}}, - /*.y =*/{/*.val =*/{0x1a2d2927, 0x87319ac, 0x3b2c73c7, 0x36ba1090, 0x683ac47, 0x19512b8c, 0xb3d27dd, 0x3eb6bf7a, 0xb0ee}}}, -{/*.x =*/{/*.val =*/{0x3181fdc2, 0x336affe6, 0xc62364d, 0xbd8aed7, 0x234e7edd, 0x992e062, 0x26e474aa, 0x40abd1f, 0xf42c}}, - /*.y =*/{/*.val =*/{0x2485d7fd, 0x7c0024e, 0x22acf268, 0x5540b66, 0x2fe22a4c, 0x2b4172e1, 0x2806c78f, 0xead1b3f, 0x5750}}}, -{/*.x =*/{/*.val =*/{0x2edd7dd6, 0x219b51f7, 0x1e1968c3, 0xddbf899, 0x3cfdec49, 0x29e103b9, 0x3524bca5, 0x33da8931, 0x32cf}}, - /*.y =*/{/*.val =*/{0x3e08e330, 0x17f512bb, 0x349a08b2, 0x3633480, 0x1f561e7a, 0x2025a902, 0x27748620, 0x1a8d25da, 0x2184}}}, -{/*.x =*/{/*.val =*/{0x21231d11, 0x399d20c4, 0x2aaad7c, 0x2acdb18f, 0x37c39822, 0x455731d, 0x388e433d, 0x3507a2e4, 0x3514}}, - /*.y =*/{/*.val =*/{0x23855df5, 0xf5bed03, 0x2f79ebe5, 0x213cc742, 0x39eff93, 0x1344795a, 0x17eb8ef4, 0xc940580, 0x89a8}}}, -{/*.x =*/{/*.val =*/{0x633cb1, 0x159f827a, 0x1d021132, 0x168892da, 0x181fcb57, 0x189cc848, 0x2cad400c, 0x273cc5ea, 0x6dde}}, - /*.y =*/{/*.val =*/{0x27ce6b34, 0x1f7526a9, 0x3859ef35, 0x2c9ff6b3, 0x3a66a880, 0x27be1a86, 0x3e41d5c9, 0x3ef9e9c1, 0x9188}}}, -{/*.x =*/{/*.val =*/{0x4e5467d, 0x342f5da9, 0x1bbface4, 0x2422ae06, 0x970e940, 0x7d8b83b, 0x1a1222c2, 0x193c3f1a, 0x97d0}}, - /*.y =*/{/*.val =*/{0x1e9cb3fa, 0x25cc03f4, 0xf17ccd7, 0x17ecee15, 0x10861fda, 0x1f19bea1, 0x2cc03f, 0x13cbb4cd, 0x8997}}}, -{/*.x =*/{/*.val =*/{0x13613bec, 0x32a072e4, 0x1cfe67c, 0x2d7f2744, 0xf972a8b, 0x6ccf71d, 0x137bdedf, 0x32ae324e, 0x2dcf}}, - /*.y =*/{/*.val =*/{0x1a039215, 0x39cc2492, 0x33f5f383, 0xcb3eeb4, 0x36c6f437, 0x222df5b, 0xa41265f, 0x3137651d, 0x46db}}}, -{/*.x =*/{/*.val =*/{0x7fb9e1a, 0x1f345c21, 0x22a32961, 0x39d2dd37, 0x2b0e767f, 0xaf26ee, 0x2c5a8f1a, 0x1052a923, 0x1bec}}, - /*.y =*/{/*.val =*/{0x349c0443, 0x1fdb845d, 0xc9796e5, 0x4e176ba, 0x54b0f68, 0x26f15cc3, 0x266678a7, 0x19c11c04, 0xe358}}}, -{/*.x =*/{/*.val =*/{0x3b7ceceb, 0xfd9e3fe, 0x97faf0f, 0x2967e4e2, 0x2e681473, 0x3ee049bd, 0x2d45036f, 0x2188109d, 0x437a}}, - /*.y =*/{/*.val =*/{0x16c181e1, 0xd8ef30d, 0x8f97827, 0x883f3f7, 0x1297ff87, 0x23fada67, 0x2c32f69b, 0x1ae84fba, 0xb91}}}, -{/*.x =*/{/*.val =*/{0x1cbf00eb, 0x3276761f, 0x18d02274, 0x2d3a62f0, 0x230bc241, 0x385bda86, 0x2d4dc49b, 0x1c2ba5ba, 0xb890}}, - /*.y =*/{/*.val =*/{0x1b0e664e, 0x2dfc6f34, 0x2b96a671, 0x362c1ad, 0x4a766cb, 0xa539307, 0x2d88f472, 0x3230b228, 0x6f24}}}, -{/*.x =*/{/*.val =*/{0x36fbe7b2, 0x275bfe6a, 0x18d65a3b, 0x2b7b7051, 0x2884605e, 0x1aeec6ca, 0x41f8f33, 0x21d9a72d, 0x2648}}, - /*.y =*/{/*.val =*/{0x21bc2a34, 0xca9e2f0, 0x20eb6039, 0xe36605a, 0x2ddf1856, 0x3cb72b40, 0x144988f2, 0x36ad2c80, 0x9e15}}}, -{/*.x =*/{/*.val =*/{0x2b038315, 0x1a434c18, 0x1310e6f9, 0x2b310cda, 0x14b8629c, 0x1a038e5e, 0x312221e4, 0x15a1d59d, 0xaba5}}, - /*.y =*/{/*.val =*/{0x2e25fc0a, 0x26800fe6, 0xb63338f, 0x2fed4cb6, 0x130d6f3f, 0x15c3d894, 0x25edb63d, 0x1761ea8d, 0xa0e7}}}, -{/*.x =*/{/*.val =*/{0x15bc15b4, 0x32e684d2, 0x25a2ee69, 0x1d40a391, 0x17ca8d92, 0x163ba73b, 0x2adc9ed8, 0x38b947b, 0x10e9}}, - /*.y =*/{/*.val =*/{0x18aa258d, 0x13af9825, 0x2bb6a883, 0x296258c0, 0x2d1f754c, 0x1ea3185a, 0x1e0424d5, 0xdc0e035, 0xc68a}}}, -{/*.x =*/{/*.val =*/{0x3a1c0a80, 0x3d8aaf21, 0x25a9c740, 0x18945631, 0x2ff9c34d, 0x326f9c00, 0xcca5b17, 0x169a2985, 0xb6b1}}, - /*.y =*/{/*.val =*/{0x1ce0a03, 0x1b340441, 0x2e16eeb, 0x2684acc2, 0x2536d49c, 0x3888fbbd, 0x1b61ea54, 0xb8535b3, 0xfae6}}}, -{/*.x =*/{/*.val =*/{0x12b062d4, 0x1f2a942a, 0x3b6a141a, 0x1739f966, 0x2a227a7a, 0x2c5c4a0f, 0x2eaca06f, 0xfa90c95, 0x3596}}, - /*.y =*/{/*.val =*/{0x3bb25302, 0x42a9346, 0xde59b1a, 0x1020ae59, 0x8a96d0, 0x33865be7, 0x1e5c9bfc, 0x38515254, 0xf65b}}}, -{/*.x =*/{/*.val =*/{0x1d33fd27, 0x282fd714, 0x246cc62f, 0x17d5cf6d, 0x2361b44, 0x8e23b6a, 0x3e84cd02, 0xfc24898, 0x9ed7}}, - /*.y =*/{/*.val =*/{0x2716c458, 0x25cacb78, 0x2e449345, 0x2a08f96c, 0x6725494, 0x16d3cd09, 0x1eeeaee7, 0x2259faec, 0xb631}}}, -{/*.x =*/{/*.val =*/{0x2f028d83, 0x1e588ebb, 0x27439615, 0x25649b6e, 0x1e69db61, 0x2af96857, 0x385ec6a5, 0x3df138f1, 0xa7eb}}, - /*.y =*/{/*.val =*/{0x19d0bed1, 0x1900e4ae, 0x30539199, 0x28e249d2, 0x4804b47, 0x271cddc1, 0x362d5cfd, 0x54beff8, 0x6205}}}, -{/*.x =*/{/*.val =*/{0x3bb61ee5, 0xa21104d, 0x31f0c13f, 0x13c138be, 0x34ae6eda, 0x18e33625, 0x321b8662, 0xc8c3321, 0xd493}}, - /*.y =*/{/*.val =*/{0x25d694a8, 0x18b69343, 0x2438ddc6, 0x344b2316, 0xafb5e1a, 0x317a747b, 0x29d23edc, 0x26afd46, 0x21c}}}, -{/*.x =*/{/*.val =*/{0x2c04554a, 0xc3772f3, 0x288cffe5, 0x373feed1, 0x10a2ecaa, 0x194b09e8, 0x3d1a0474, 0xdf2261c, 0x896f}}, - /*.y =*/{/*.val =*/{0x129138df, 0x1a3e7f86, 0xc417dcd, 0x216d86b, 0x11bf1e6, 0x8aec13a, 0x2c4acda6, 0x8f9c892, 0x3804}}}, -{/*.x =*/{/*.val =*/{0x343fca26, 0x101df46a, 0x3bc23678, 0x3ee10768, 0x3578a27d, 0x308276fc, 0x36d6cca6, 0x2e5fddd2, 0x11b3}}, - /*.y =*/{/*.val =*/{0x1b679d58, 0xec9fabd, 0x39f9d42d, 0x2b88c712, 0x36d3bb3b, 0x159430bc, 0xc508cd, 0x7e7eb98, 0x6533}}}, -{/*.x =*/{/*.val =*/{0x8dfd587, 0x1e4d86ed, 0x1b026560, 0x312e8e32, 0x35a12d5e, 0x19eaa8b3, 0x508b348, 0x2d06eb3d, 0x5084}}, - /*.y =*/{/*.val =*/{0x11470e89, 0x39e7a5fe, 0x91f5606, 0x2dbd581a, 0x2927475d, 0x2a9b2154, 0xd31619, 0x18c68766, 0x34a9}}}, -{/*.x =*/{/*.val =*/{0x2c953fa9, 0x341655b5, 0xb8c3db4, 0x2ac98a7c, 0x118c0628, 0x3d21752f, 0x393233a5, 0x3443aaaa, 0xa49e}}, - /*.y =*/{/*.val =*/{0x6fb4c72, 0x1ecaf489, 0x28e181b6, 0x3a1d4d25, 0x1fddfb5a, 0x11db0283, 0x35398e03, 0x2e251983, 0xcc72}}}, -{/*.x =*/{/*.val =*/{0x27a1d916, 0x3025b4ff, 0x11f1f3a3, 0x16c28e57, 0x1bb07031, 0x18562997, 0x19d0cbac, 0x3e6b2db5, 0x650e}}, - /*.y =*/{/*.val =*/{0x3068387b, 0x16127299, 0x36c26ba8, 0x2ed18229, 0x1b82c558, 0x2702e49e, 0x2b11870e, 0x47c8458, 0x85d}}}, -{/*.x =*/{/*.val =*/{0x36fb2940, 0x37f07501, 0x2534042f, 0x7f01a6c, 0x2b8fbd71, 0x1d04e10a, 0x1c82fecb, 0x283bf680, 0x5083}}, - /*.y =*/{/*.val =*/{0x36ceee44, 0x378c0ed9, 0x2cdddf3b, 0x1a849b87, 0xdf19b08, 0x3ef7e189, 0x782bba8, 0x2bbe3ff9, 0xf064}}}, -{/*.x =*/{/*.val =*/{0x15bc8a44, 0x3bf74194, 0x3e151a19, 0x10405df2, 0x1a5fc768, 0x159692e9, 0xeda3d38, 0x20160f3f, 0x4d01}}, - /*.y =*/{/*.val =*/{0x1adbc09e, 0x3c7e5324, 0x182da362, 0x250811a1, 0x16381396, 0x26ea001f, 0xf5d367e, 0x31b0632d, 0x3a33}}}, -{/*.x =*/{/*.val =*/{0x135b4eb8, 0x14884f92, 0x38b5a3cf, 0x3d55fc6a, 0x2f2dce07, 0x3d528f32, 0x32256f0f, 0x1a390eb7, 0xc119}}, - /*.y =*/{/*.val =*/{0x2f911add, 0x11265b5, 0x2a7149b7, 0x3e2d2504, 0x366f8242, 0x27607f99, 0x2458f837, 0x39a4dde1, 0xbff5}}}, -{/*.x =*/{/*.val =*/{0x19dffc96, 0x256e8425, 0x3ac58572, 0xa33696b, 0x17eb0192, 0x26ce5720, 0x3deaf6f, 0x1b2fb852, 0x161c}}, - /*.y =*/{/*.val =*/{0x1b492de4, 0x24ef3d84, 0x2af8621c, 0x258d324b, 0x3183059b, 0x964e472, 0x1ff985bd, 0x32a4a9ae, 0x8a26}}}, -{/*.x =*/{/*.val =*/{0x369671d5, 0x35f9c967, 0x14eb83e3, 0xbbabd6d, 0x2bc96056, 0x7906af5, 0x39596d76, 0x3b1580f3, 0xa8c1}}, - /*.y =*/{/*.val =*/{0x333db746, 0xf22a034, 0x18f8b182, 0x2997eccc, 0x141c5924, 0x31cc9a4, 0x345ac755, 0x181447a7, 0x5fc3}}}, -{/*.x =*/{/*.val =*/{0x8a2050e, 0x6b10bf9, 0x15f8a677, 0xbbd55d8, 0x79b8974, 0x1da731b9, 0x731896b, 0x93f492f, 0x6737}}, - /*.y =*/{/*.val =*/{0x61d3d70, 0x24326924, 0x3349cc2b, 0x1aeb3f50, 0x86b6dbe, 0x120b026a, 0x24a20203, 0x2095e25a, 0xe4cf}}}, -{/*.x =*/{/*.val =*/{0x29a78179, 0x133d807e, 0x20d6afe3, 0x143a4149, 0x9ed9f6b, 0x291ccd88, 0x1b8dc905, 0x29fcdc20, 0x995c}}, - /*.y =*/{/*.val =*/{0x2fec1f47, 0xc7eed32, 0x2b64e529, 0x332155a6, 0x12863abb, 0xd362012, 0x3573ab5e, 0x167a5554, 0xd9a0}}}, -{/*.x =*/{/*.val =*/{0x49135d3, 0xf636176, 0x2e431fc1, 0x80f3404, 0x30b16a74, 0x4d0a504, 0x2a85a65c, 0x2f1fbe0, 0x594}}, - /*.y =*/{/*.val =*/{0x162255d2, 0xb5d146, 0x1902391d, 0xa18ca32, 0x36687af1, 0x16c31eaa, 0x3ab612f7, 0x1e617ad3, 0x9053}}}, -{/*.x =*/{/*.val =*/{0x39e68f51, 0x3de3a89e, 0x16b6e1d0, 0x1b87f2ae, 0xd870cf5, 0x301895ca, 0x26fcb74d, 0x116b276e, 0xc755}}, - /*.y =*/{/*.val =*/{0x38cfbbc1, 0x7120e25, 0x22ddf68d, 0x7246272, 0x168bf725, 0x163b6ca8, 0x855c2a7, 0xf11a8ef, 0x7c80}}}, -{/*.x =*/{/*.val =*/{0x41ead4b, 0x3fa21e68, 0x11b03c1f, 0x1d7b7eda, 0x3e76be3a, 0x11cd3beb, 0x3337ec71, 0x3032323, 0xbfc9}}, - /*.y =*/{/*.val =*/{0x6fedaed, 0x114b1bc2, 0x2e0ae3e7, 0x11a3bfcc, 0x42d36fb, 0x29c63754, 0xded24db, 0x206c7827, 0x7a94}}}, -{/*.x =*/{/*.val =*/{0x25b7ad0d, 0x253215bb, 0x1d0d1d36, 0x3b9d9f2a, 0x116c4476, 0x362925b, 0x1e00dc2d, 0x1a436aed, 0x3a55}}, - /*.y =*/{/*.val =*/{0x32e8c407, 0x1b261e42, 0x2c31218d, 0x32b2e2b2, 0x2f99f301, 0x7eeb25f, 0x657bfb2, 0x23865d68, 0xc3e2}}}, -{/*.x =*/{/*.val =*/{0x19b2df82, 0x9e91ec2, 0x3104fb19, 0x179e8591, 0x232c04ec, 0xb463b33, 0x3b92ccc9, 0x191718af, 0x405a}}, - /*.y =*/{/*.val =*/{0x9307dbf, 0x368a0d28, 0x2dc462b5, 0x3ea76cb3, 0x37e7122f, 0x2b298788, 0x196e0f5c, 0x2d053d13, 0xbc3c}}}, -{/*.x =*/{/*.val =*/{0x18f4033f, 0x9f0f311, 0x20ab6d3a, 0x12b3c96c, 0x28f817cc, 0x2c835e83, 0x3cfb3d2a, 0x51ad0e6, 0x10ba}}, - /*.y =*/{/*.val =*/{0x76d1fbf, 0x173dae53, 0x1c78b4ea, 0x6dacdfa, 0x129f3677, 0x283c19a8, 0xaef4b2a, 0x19b9747, 0xade1}}}, -{/*.x =*/{/*.val =*/{0x36e2d9b3, 0x12f4c1aa, 0x338d6351, 0x36e4a0c6, 0xf845641, 0xba984e7, 0x305e75e1, 0x53ce5f1, 0x19a3}}, - /*.y =*/{/*.val =*/{0xbaaaf33, 0x154bb897, 0x4be56d, 0x874749, 0x3528b3a5, 0x2597e21f, 0x328dd234, 0x363d76b1, 0x6cac}}}, -{/*.x =*/{/*.val =*/{0x23a52264, 0xb9cdf65, 0x1400b375, 0x2b7f00c5, 0x251cffd0, 0x1b8aa6ab, 0x7fe9a80, 0x37037a06, 0x85ff}}, - /*.y =*/{/*.val =*/{0x2da2082, 0x231f4a6a, 0x3179d049, 0x2060b24a, 0x14706c67, 0x15a3d415, 0x2948d0be, 0xc061eb8, 0x3fee}}}, -{/*.x =*/{/*.val =*/{0x36a88c9c, 0x307fd692, 0x149df069, 0x1eda198c, 0x2caa2aa3, 0x766b25c, 0x391398b2, 0x24207951, 0x7865}}, - /*.y =*/{/*.val =*/{0x35a7d19b, 0x38164d15, 0x3ab6a155, 0x33e466c0, 0x28196112, 0x23e9c897, 0x30d2b69e, 0xc1de4a8, 0x59a2}}}, -{/*.x =*/{/*.val =*/{0x1e8f7605, 0x374b71e3, 0x3ed2d35b, 0x13bde7d7, 0xff48bd4, 0x2ce44ba2, 0x159def16, 0x1100533a, 0x21ce}}, - /*.y =*/{/*.val =*/{0x955155f, 0xd791446, 0x46602c1, 0x38cd259a, 0x1da46ef4, 0x1bf5987c, 0xfaf75d9, 0x19c08e8b, 0x323a}}}, -{/*.x =*/{/*.val =*/{0x121ce204, 0x13b5d7a3, 0x26763d52, 0x29c96390, 0x26f72fb2, 0x1d361672, 0x3c64fb83, 0x107458ac, 0x43ca}}, - /*.y =*/{/*.val =*/{0x134a8f6b, 0x1494113a, 0x2a4a468e, 0x2db1eccf, 0x1ba31f9a, 0x143e4863, 0x23fa1c6, 0x16a0b8dc, 0xdcea}}}, -{/*.x =*/{/*.val =*/{0x14978583, 0x2ce90c80, 0x61613f5, 0x35ba6bbc, 0x392214cd, 0x21066643, 0x23137497, 0x3e26e73c, 0x30ab}}, - /*.y =*/{/*.val =*/{0x1dc75777, 0x118600d4, 0x3b584ac4, 0x483a88e, 0x21ab8063, 0x1ed3cb43, 0x37498cdf, 0x144551df, 0x4b03}}}, -{/*.x =*/{/*.val =*/{0x2c288015, 0x268df98f, 0x2dc99cc3, 0x1cfe14fb, 0x1b6aa646, 0x3eb18681, 0x2de6f681, 0x13aab64d, 0xaa01}}, - /*.y =*/{/*.val =*/{0x6c1006f, 0x3e053999, 0x3cecad9d, 0x12e6c1d0, 0x3b0f63ef, 0xa9f90fd, 0x2be9ac3f, 0x4f0118d, 0x3de9}}}, -{/*.x =*/{/*.val =*/{0x185bfe2, 0x34231245, 0xe5e42d3, 0x37e8ab9e, 0x2679cb5e, 0x2a82a0b3, 0xa0b0b56, 0x576fcdf, 0xe526}}, - /*.y =*/{/*.val =*/{0x2a0e5888, 0x33c042f, 0x245a9c44, 0x1dbfcb72, 0x32c1a284, 0x7e54a27, 0x488520f, 0xcd459b4, 0x5403}}}, -{/*.x =*/{/*.val =*/{0x59ab499, 0x2f674fc8, 0x273c330a, 0x4ca671b, 0x3f01bc0b, 0x65acf19, 0x5ba5d2, 0x2bfcc057, 0x78ba}}, - /*.y =*/{/*.val =*/{0x3ee097fd, 0x20748c63, 0x11251996, 0x18cbbba3, 0x2082e91, 0x2a1383b6, 0x2c0afafc, 0x3736f6c1, 0xad4b}}}, -{/*.x =*/{/*.val =*/{0x25cd5379, 0xc18ccc2, 0x70bcadc, 0x2de50e16, 0x24d2232d, 0x9206e2a, 0x11382a78, 0x1cb55af7, 0x17c0}}, - /*.y =*/{/*.val =*/{0x3108cd25, 0x1f2b8146, 0x25bad0df, 0x166b1d89, 0x1d034f89, 0x30491ebc, 0x1a064e77, 0x2f7d0a0f, 0xd901}}}, -{/*.x =*/{/*.val =*/{0xa2d8dae, 0x1e4f0063, 0x3d25ea95, 0xca97e47, 0x32256eac, 0x2c97be72, 0x192f9ba6, 0x7009884, 0x8827}}, - /*.y =*/{/*.val =*/{0x3e1e77d9, 0x2d09b03c, 0x317d099f, 0x21db71, 0x2bf5acc3, 0x322ceb96, 0x176aa401, 0x3754d41c, 0xd719}}}, -{/*.x =*/{/*.val =*/{0x1ee503a6, 0x2543ebf4, 0x124e1fba, 0x7a1493c, 0x2ec5ab43, 0x2a0c4661, 0x24a29aa6, 0x1fa04b8f, 0xceb6}}, - /*.y =*/{/*.val =*/{0xe98c4d1, 0x3ff50365, 0x269e2f31, 0x225b657b, 0x1cd86b4b, 0xf7de042, 0x10613b82, 0x21516b0e, 0x5e6a}}}, -{/*.x =*/{/*.val =*/{0x3ba9000, 0x37c1c8ea, 0x25e8b6f, 0x21cbe71a, 0x143dc4, 0x21d81d61, 0x1d8c1684, 0x1d3e7ffc, 0xac38}}, - /*.y =*/{/*.val =*/{0x2f10cf0a, 0x368f1f65, 0x366e9fa4, 0x178d435f, 0x117f9308, 0xb77a250, 0x1c069b86, 0x3a48c228, 0xaa65}}}, -{/*.x =*/{/*.val =*/{0x17ba402e, 0x39758c2c, 0x1042989a, 0x2e06970b, 0x8e3c3c3, 0x3ab43121, 0x3a02a58b, 0x6d73463, 0x8e89}}, - /*.y =*/{/*.val =*/{0x4fad9e0, 0x386d89e7, 0x157a7ee8, 0x19430908, 0x32a306af, 0x23439013, 0x2c6680b3, 0x3839aa7, 0xe5d3}}}, -{/*.x =*/{/*.val =*/{0x136bcfe8, 0x187b5879, 0x29b7bb3e, 0x305e7b5, 0x2b319a0e, 0x32a3c8c1, 0x2999b472, 0x3e2f0731, 0x1332}}, - /*.y =*/{/*.val =*/{0x1ae78402, 0x6c374b3, 0x1a8c2145, 0x24ed0935, 0x1c0681ba, 0x19f114d7, 0x2ed713f, 0x31fb8a58, 0xc39d}}}, -{/*.x =*/{/*.val =*/{0x2fddec6, 0x3fffb0cd, 0x111222c7, 0xb00f7df, 0x3f461492, 0x3678cde4, 0x220b4e9c, 0x7fead4f, 0x9f13}}, - /*.y =*/{/*.val =*/{0x9df8052, 0x3855dbc6, 0x3918eac6, 0x28c8d510, 0xec8d7d3, 0x34d25302, 0x326f4fef, 0x5302c, 0x3b21}}}, -{/*.x =*/{/*.val =*/{0x38c8ac7f, 0xa0bf97e, 0x1e2aa527, 0x490bb99, 0x16f84964, 0xce5b481, 0x22bbcb5c, 0x2cbef8e0, 0x9945}}, - /*.y =*/{/*.val =*/{0x29aea3b0, 0x1b650e85, 0x2dacdfa9, 0xbde88fb, 0x28eff528, 0x36d13fec, 0x3282d607, 0x3b6092c3, 0x3eef}}}, -{/*.x =*/{/*.val =*/{0x12fccf64, 0x2ea92662, 0x181318e3, 0x349e3789, 0x95dbf3b, 0x21dcb1df, 0x637db06, 0x45703ad, 0xc7d}}, - /*.y =*/{/*.val =*/{0x2878fee0, 0xfdb4ecc, 0x19ae68d5, 0x1e1760e5, 0xaf14548, 0x1092e11e, 0x1b0447aa, 0x1d1ec649, 0x4aa8}}}, -{/*.x =*/{/*.val =*/{0x148d5622, 0x2d6baeb1, 0x251bd2e8, 0x36c1fbde, 0x33381be1, 0x161aa06f, 0x9535a39, 0x3047985a, 0x5fc6}}, - /*.y =*/{/*.val =*/{0x1ac1683, 0x34361004, 0x2c7bf300, 0x16b4239, 0x367acb0e, 0x26e8b6c0, 0x1d9db9c1, 0x39526a8, 0x10e8}}}, -{/*.x =*/{/*.val =*/{0x33c85ecf, 0x1a5916ce, 0x15dacd7, 0x6e08398, 0xff0807d, 0xbd69fa, 0x23e20844, 0x22f56a48, 0x23dd}}, - /*.y =*/{/*.val =*/{0x274504ad, 0x1c2702ae, 0xec98f6f, 0x274c6013, 0x10d4b7fc, 0x7b4bf9c, 0x3d26f710, 0x26ef0094, 0x52d}}}, -{/*.x =*/{/*.val =*/{0x1136602, 0x2c2e9195, 0x19e3a5bb, 0x311bd203, 0x333b3d38, 0x1624dfc8, 0x2dfc33d0, 0x9ca0120, 0x87d1}}, - /*.y =*/{/*.val =*/{0x18af6aac, 0x3da0f107, 0x3d3bf7c4, 0x2a211d1b, 0x27745387, 0x289db3fd, 0x203de926, 0x921c296, 0x71ce}}}, -{/*.x =*/{/*.val =*/{0x30e74459, 0x1d28d722, 0x3ddb6dd6, 0x3c8dd8e1, 0x3c8a91fe, 0x3d1961c4, 0x5680590, 0x1e0753b0, 0x28df}}, - /*.y =*/{/*.val =*/{0x2f5e656f, 0x3781f303, 0x1ae6f0a8, 0x1e56e940, 0x322794a3, 0x36c5e243, 0x30f17cb0, 0x27a99a84, 0xf149}}}, -{/*.x =*/{/*.val =*/{0x29c71143, 0x11b67714, 0xf057ea3, 0x1fab6b11, 0x23fa352e, 0x1f33e400, 0x3ea103ca, 0x17e588ae, 0xeb4}}, - /*.y =*/{/*.val =*/{0xb70b136, 0x22a33688, 0x22b1bf4c, 0x165a7a9a, 0x1e2857d6, 0x1807d640, 0xbd0f573, 0xbd6160e, 0x52c4}}}, -{/*.x =*/{/*.val =*/{0x1507a7e6, 0x37cdaf22, 0x305f129b, 0x25896ebd, 0x310c41c0, 0xa1458cd, 0x1ad0d5f4, 0x142c15d1, 0x232d}}, - /*.y =*/{/*.val =*/{0x152b5892, 0x1c202084, 0x6459ccb, 0x18303bed, 0x2257f712, 0xe22b7c1, 0x33f6b086, 0xeb14d79, 0x780f}}}, -{/*.x =*/{/*.val =*/{0x177e7775, 0x222a29b8, 0xed95f63, 0x385564e2, 0x1291aeb5, 0x150eeb3d, 0x233cee58, 0x1a8ebfe5, 0x9d89}}, - /*.y =*/{/*.val =*/{0x3a056691, 0x3f3db4ea, 0x299253be, 0x26735fb8, 0x10927de8, 0x2593b5c9, 0x1bf0b94e, 0x2a790fd2, 0xdd91}}}, -{/*.x =*/{/*.val =*/{0xc904ed3, 0x1655fc7a, 0x5857841, 0xa9d1624, 0x272384df, 0x3e3990c4, 0x18dff97, 0x230b4b6e, 0xcf}}, - /*.y =*/{/*.val =*/{0x396f77c1, 0x2658ed, 0x32f6827b, 0x26475e74, 0x1bd81122, 0x35706f54, 0x1d44119d, 0x3a9e0, 0xaaad}}}, -{/*.x =*/{/*.val =*/{0xcf8cffd, 0x2cad6622, 0x3a45ae61, 0xb9ac56d, 0x1bdd8943, 0x2bee23de, 0x38c1bd45, 0x26dfc7f9, 0x80}}, - /*.y =*/{/*.val =*/{0xdb5f32f, 0x24751686, 0x12b9f93d, 0x28d03eb6, 0x12fdc912, 0x2320db79, 0x1a863028, 0x3808afd0, 0xf817}}}, -{/*.x =*/{/*.val =*/{0x2dc7a626, 0x11f741e6, 0x33cdcc02, 0x1772ade, 0x46b0734, 0x32bc48c9, 0x806bce4, 0x1b28b13e, 0x2f45}}, - /*.y =*/{/*.val =*/{0x25279532, 0x2b3ac002, 0x16eaea9e, 0x13236f70, 0x9f5302, 0x47ed991, 0x50544d2, 0x1c69e919, 0xf8cf}}}, -{/*.x =*/{/*.val =*/{0x1a328d6a, 0x2eaa0623, 0x1adc18bd, 0x135dcea5, 0x308fa7b2, 0x1a264616, 0x34e00a34, 0x3016e988, 0xc663}}, - /*.y =*/{/*.val =*/{0x3ec9b8c0, 0xec2edaa, 0x12bf9cc2, 0x21547a94, 0x171317dd, 0x2bf73c9d, 0x21c38d39, 0x3a6357dc, 0x3331}}}, -{/*.x =*/{/*.val =*/{0x22143fb0, 0x370d6995, 0x3c205dd6, 0x3ee4a0c2, 0x399597a9, 0x2bfcce51, 0x383790cf, 0x37070ceb, 0x292a}}, - /*.y =*/{/*.val =*/{0x236ad01c, 0x2a76d8f3, 0x35e9d4d8, 0xf998b5c, 0x4ecf6d8, 0x65a2833, 0xb647f3f, 0x1986f3b8, 0xa072}}}, -{/*.x =*/{/*.val =*/{0x30b90e0b, 0x27b079b0, 0x3094a458, 0x3fc74e7e, 0x675b3d6, 0x32012967, 0x67d3fed, 0x1fe6b55, 0xa435}}, - /*.y =*/{/*.val =*/{0x3a1fdc20, 0x3c002e64, 0x3599b5a3, 0xa880d94, 0xbe8c0dc, 0x341f32d0, 0x3d71a142, 0xb72530f, 0x7c8f}}}, -{/*.x =*/{/*.val =*/{0x188f4d82, 0x2e7474ad, 0x159204ac, 0x9937676, 0x21d6fcaf, 0x170c09b0, 0x1c515b0e, 0x1665c1b9, 0x6dd5}}, - /*.y =*/{/*.val =*/{0x14132ad3, 0x287aadab, 0x15927be5, 0x3db9c11b, 0x2d0f9478, 0x3346376d, 0x1233dd46, 0x109ff54d, 0xbc92}}}, -{/*.x =*/{/*.val =*/{0x1e05dccc, 0xcb60046, 0x19a93e5, 0xfe8fb53, 0x13d172ae, 0x1b825ae5, 0x1a030954, 0x3db85d4f, 0xb8ce}}, - /*.y =*/{/*.val =*/{0xc6d5750, 0x52833f, 0x26b68133, 0x1d5ff0da, 0x12bd99df, 0x3529d393, 0x9bbf6a4, 0x229829b3, 0x302b}}}, -{/*.x =*/{/*.val =*/{0x286df50d, 0x313bb405, 0x6f92bd0, 0x179e4a87, 0x82060cd, 0x361d10b0, 0x1f02d6f, 0x58c24d7, 0x3a57}}, - /*.y =*/{/*.val =*/{0x2859679b, 0x8562ca3, 0x3781a11d, 0x2abe07ae, 0x30a0dde0, 0x3cffcb95, 0x1f32f516, 0xe1ced66, 0x85e1}}}, -{/*.x =*/{/*.val =*/{0x388f7e09, 0xaa8ad9f, 0x27d92cde, 0x280dde6e, 0x1dc0beb3, 0x384b9691, 0x5fcbbd8, 0x218f53c8, 0x5e6a}}, - /*.y =*/{/*.val =*/{0x8dfca97, 0x2f58a19d, 0x3b4cfe3b, 0x23940dc8, 0x140234a6, 0x12a347da, 0x8edfc44, 0x681e28e, 0xc257}}}, -{/*.x =*/{/*.val =*/{0x1df66583, 0x3b2a229b, 0x25580609, 0x6433e68, 0x1ea87603, 0x38bdfbf, 0x2fd019c1, 0x1c6d48f0, 0x5281}}, - /*.y =*/{/*.val =*/{0x3f480c26, 0x3407b39, 0x3de01414, 0x8104f71, 0x1e8fb495, 0x2f3a351a, 0x27a6598, 0xe575ec3, 0x7b2c}}}, -{/*.x =*/{/*.val =*/{0x2521b3ff, 0x38a61193, 0x1aa750ce, 0xf01c5fa, 0x2e24a523, 0x1134afa6, 0x1455c75e, 0x138c0432, 0x248}}, - /*.y =*/{/*.val =*/{0x269da7e, 0x306b92e4, 0x23ac8bbc, 0x1c01b7a4, 0x2d0eebad, 0x30acf0ac, 0x3e30d07e, 0x34282a88, 0x9619}}}, -{/*.x =*/{/*.val =*/{0x692fd1, 0x2c982585, 0x3d90dfe2, 0x3d0f1b32, 0x1f190edc, 0x2ab7bd2c, 0x1ff800e0, 0x322d2640, 0x4e53}}, - /*.y =*/{/*.val =*/{0x328625e0, 0xd24c39c, 0x3fc97539, 0x1e943695, 0x219da1a8, 0x335c269c, 0x1a01e186, 0xf93d350, 0xdd6e}}}, -{/*.x =*/{/*.val =*/{0x3549827b, 0x2338d5f6, 0x121bd614, 0x313dfcf8, 0x2ce311fc, 0x4b81b78, 0x375f3a82, 0x343d7834, 0xce47}}, - /*.y =*/{/*.val =*/{0x2faed097, 0xf32697f, 0x5769df4, 0x39964bfc, 0x39ad0f29, 0x244e7f96, 0x30d49d58, 0x263ee658, 0x15c6}}}, -{/*.x =*/{/*.val =*/{0xc43da59, 0x3747b53a, 0x3a48ca2f, 0x6911b8a, 0x6cf9bc9, 0x1c4ebfe0, 0x21a3319b, 0x1f592302, 0x7115}}, - /*.y =*/{/*.val =*/{0x248d28ac, 0x1f7884ad, 0xcb6ad56, 0x33c28fe9, 0x11ab13fc, 0x28440e45, 0x303053f2, 0x35451759, 0x3d53}}}, -{/*.x =*/{/*.val =*/{0x3e889756, 0x37606ba6, 0x3004bb25, 0x1ed9265e, 0x1899f3f2, 0x3365ec9c, 0x1fea8226, 0x22f0cc84, 0x762e}}, - /*.y =*/{/*.val =*/{0x3ca6b774, 0x17896781, 0x84fa5e2, 0x1cb6cc52, 0x2e34719, 0x3313c526, 0x3e97c3c7, 0x250982bc, 0xc028}}}, -{/*.x =*/{/*.val =*/{0x26714560, 0x1d560296, 0x256c6c28, 0x1fc8409f, 0x25a85c24, 0x1fbd93c6, 0x2d36b9d4, 0xa9d55e6, 0x38b8}}, - /*.y =*/{/*.val =*/{0x2774299e, 0x36a1ccd2, 0x3716284a, 0x253c8efb, 0x2434597d, 0x3d58d185, 0x21ef428b, 0x29a5dbc9, 0xf9d8}}}, -{/*.x =*/{/*.val =*/{0x1b720b26, 0x188bac12, 0xccfcd07, 0x3ca0d7e6, 0x39062026, 0x1aefb504, 0x168ee1f4, 0x316ba6b2, 0x3e10}}, - /*.y =*/{/*.val =*/{0x2dd92db5, 0x11ba631e, 0x3e09e433, 0x3fde6936, 0x215e28e2, 0x1996ca1c, 0x288915a8, 0x31b3ff90, 0xc735}}}, -{/*.x =*/{/*.val =*/{0xc15cf94, 0x3710a097, 0x12082845, 0xff5aa0, 0x3569f8bd, 0x1bdc4615, 0xd97eb79, 0x2979dbec, 0x1dc5}}, - /*.y =*/{/*.val =*/{0x140ef8a2, 0x3e95399e, 0x25d97f94, 0xb6f12d6, 0x72d0c65, 0x1ccc46a4, 0x367d6019, 0x22b89d5f, 0x855b}}}, -{/*.x =*/{/*.val =*/{0x78ee8d, 0x3c142473, 0x6919442, 0x2fc83394, 0x1b4ff64e, 0x3dc98eaa, 0x1a9be25f, 0x15eb6167, 0xd08e}}, - /*.y =*/{/*.val =*/{0x2da63e86, 0x265fd370, 0x22ed9de, 0xfbdf3e5, 0x3e6df412, 0x5cbb9d5, 0x88d72d6, 0x25e612ad, 0x852e}}}, -{/*.x =*/{/*.val =*/{0xe9c22bc, 0x10eb950c, 0x1bcc42fd, 0x3699f5a4, 0x3c7be601, 0x2cd11366, 0x2eb23765, 0x33a97a67, 0x5335}}, - /*.y =*/{/*.val =*/{0xbdacb60, 0x30b099cb, 0xa1f19b3, 0x30c308db, 0xeb86ac8, 0x1fc203c3, 0x5224a06, 0x34081da7, 0x3bf8}}}, -{/*.x =*/{/*.val =*/{0xff4de54, 0x2f079885, 0x1d3c2be5, 0x32af647a, 0xa2858a5, 0x100c73c5, 0x202a2c3b, 0x370d577c, 0x5716}}, - /*.y =*/{/*.val =*/{0x10100fa5, 0xfa93f55, 0x47e417d, 0x3cffb334, 0x1324c5eb, 0x2a9986a6, 0x383f391e, 0x1b100296, 0x985f}}}, -{/*.x =*/{/*.val =*/{0x2336a875, 0x108cff13, 0x19d064c1, 0x3b71c748, 0x2f1b5099, 0x15be606, 0x2d4dd947, 0x16786af8, 0x24a6}}, - /*.y =*/{/*.val =*/{0x1112057c, 0x3cffa170, 0x1e0b96ab, 0x2911927a, 0x1cf34f69, 0xcc6f51f, 0x27240468, 0x2beb142f, 0xd3e1}}}, -{/*.x =*/{/*.val =*/{0x761d58d, 0x12eabcce, 0xd60e2f3, 0x1326f902, 0x20df7aca, 0x9028d5c, 0x3614610a, 0x1849e08f, 0xb8c4}}, - /*.y =*/{/*.val =*/{0x1d1051a4, 0xe3a82ea, 0x2107c5b6, 0x1d411e17, 0x33c5053f, 0x1163da5f, 0xe37d14a, 0x365b145c, 0x8f9e}}}, -{/*.x =*/{/*.val =*/{0x1166ff40, 0x537a868, 0x1fff36da, 0x3bafd290, 0x80a2eca, 0x20497639, 0x18d2b7c7, 0x100cc620, 0x6b00}}, - /*.y =*/{/*.val =*/{0x1d71b847, 0x2dd04c3a, 0x3f3ede9e, 0x1a20fdb9, 0xbf2f007, 0x250e8164, 0x2fac9968, 0x6ceba2a, 0x41cd}}}, -{/*.x =*/{/*.val =*/{0xd6bf1f, 0x114841ae, 0x24fcbb0, 0x2f40cfa6, 0x3346b946, 0x87a49da, 0xb83ca35, 0x1cd0d147, 0xc333}}, - /*.y =*/{/*.val =*/{0x3cb01f48, 0x25796108, 0x2266162f, 0x2e8d9083, 0x2c315598, 0x3fcc6bdc, 0x12cda13d, 0x3a4e46e0, 0x2eef}}}, -{/*.x =*/{/*.val =*/{0x34d9279c, 0x12d43f2a, 0x99a0075, 0x1e171e64, 0x3a845c28, 0x15c0bb20, 0x22c5776b, 0x38539f8a, 0x7121}}, - /*.y =*/{/*.val =*/{0x2f97b82e, 0x1c80a5f8, 0x1100d1ec, 0x3e8a0cd2, 0x35046e47, 0x2e865b4c, 0x105ca520, 0x30028c67, 0xf194}}}, -{/*.x =*/{/*.val =*/{0x2127b756, 0x2ea1ffd, 0x3a097048, 0x10a2f92a, 0x20b41603, 0xd8b6941, 0x1f12672d, 0x1e0bdc5b, 0x6d8c}}, - /*.y =*/{/*.val =*/{0x3f172571, 0x1547dd2a, 0x17cdcca6, 0xea9b68b, 0x134daf4e, 0x26a0b4db, 0x1b911145, 0x37c225bf, 0x99ae}}}, -{/*.x =*/{/*.val =*/{0x11a3c43c, 0x1312cb15, 0x2cee258e, 0x3dc072a3, 0x2e67140d, 0x307cad2a, 0x2cd5b48c, 0x36a519f2, 0x56c9}}, - /*.y =*/{/*.val =*/{0x20d7c9ed, 0x9362df4, 0x2edcaa18, 0x3503fe4c, 0xb685241, 0x31e59377, 0x39ec2f33, 0x1ab2d0b1, 0x38d4}}}, -{/*.x =*/{/*.val =*/{0x2df771c8, 0x27892740, 0x2094c87b, 0x1694847b, 0x1f875033, 0xb0acf00, 0x1c9029d3, 0x151b648b, 0xb71e}}, - /*.y =*/{/*.val =*/{0x13f48c51, 0x114e89be, 0x1bba2862, 0x2f548ad5, 0x2288f426, 0x4a93333, 0x1f900789, 0x3bea33b2, 0xe7cc}}}, -{/*.x =*/{/*.val =*/{0x2ee40896, 0x27f5e5b0, 0x1177f5bf, 0x2b8dea49, 0x261e6aa1, 0x1b819399, 0x36de46bb, 0x3c06c124, 0x7a0d}}, - /*.y =*/{/*.val =*/{0x44a7569, 0xb6393bc, 0x117da7f2, 0x8a28a35, 0x290e9aaa, 0x35abfd7a, 0x2fcd1b2a, 0x1d6038d5, 0xb446}}}, -{/*.x =*/{/*.val =*/{0x6e1346b, 0x28661277, 0x5af1c5e, 0x2f9ec40e, 0x1152c05a, 0x31d87c53, 0x2d10be54, 0x1a3fc260, 0x690}}, - /*.y =*/{/*.val =*/{0x17226c13, 0x2ed62953, 0xc6026e7, 0x3da24e65, 0x6442aa4, 0x176caf42, 0x3de26da8, 0x38f8242f, 0xb863}}}, -{/*.x =*/{/*.val =*/{0x3235c795, 0x2138aef1, 0x3d541d75, 0x362563a, 0x1c89d70b, 0x2c16cdf4, 0x3974b393, 0x11890d7b, 0x63c}}, - /*.y =*/{/*.val =*/{0x1b110258, 0x3ccb7025, 0x249a9bd3, 0x12b2eb3e, 0x1c85b69e, 0x3d98364c, 0x38404431, 0x26ee44c0, 0xe27f}}}, -{/*.x =*/{/*.val =*/{0x2c1cbaab, 0x34de9fc5, 0x33d564cf, 0x32ae1e40, 0x30635c1a, 0x2adb0629, 0x16071598, 0x2ba63ecd, 0xd031}}, - /*.y =*/{/*.val =*/{0x5116b26, 0x30e411fe, 0x3d65fdc4, 0x3ed293f6, 0xb4dcf6d, 0x39301ab7, 0x584e8e6, 0x25ad3a55, 0x4151}}}, -{/*.x =*/{/*.val =*/{0x1affca70, 0x3f44d85f, 0x14ce5fd1, 0x1addc21d, 0x12d1f999, 0x3565346a, 0x3861d3ff, 0x47bce91, 0xd4c0}}, - /*.y =*/{/*.val =*/{0x3d9c4777, 0x31fcb8a5, 0x256ebb09, 0xbd1ec15, 0x2b2906b2, 0x1d086400, 0x21566287, 0x12e620e9, 0x90b2}}}, -{/*.x =*/{/*.val =*/{0x17592d55, 0x300d67b3, 0xe350192, 0x356e51d0, 0x3ce3b106, 0x3fbda58c, 0x1052608a, 0x31b6f128, 0x5d2e}}, - /*.y =*/{/*.val =*/{0x2f5183a7, 0x19b9743a, 0x11151742, 0xa9ef36b, 0xcd6950e, 0x1c43e89a, 0x245eb58f, 0x337e271b, 0xa92}}}, -{/*.x =*/{/*.val =*/{0x255bf84c, 0x1d12e3e3, 0x30d9027a, 0x1931bb55, 0x3cae4fd9, 0x34f09488, 0x16cc8e5d, 0xa2673ae, 0x6278}}, - /*.y =*/{/*.val =*/{0x1f15fa2a, 0x3d473ead, 0x1d176ed6, 0x8379f7, 0x3267839a, 0x1525c8a5, 0x1a28901c, 0x2b290244, 0xd670}}}, -{/*.x =*/{/*.val =*/{0x339715c2, 0x2651c743, 0x18a529a3, 0x19487e, 0x33fedd69, 0x7de33a8, 0x23d85b41, 0x27a23c66, 0x2f18}}, - /*.y =*/{/*.val =*/{0x171dfea, 0x1a98d611, 0x36854f06, 0xcccf8b0, 0x10f9f7eb, 0x211d7b4, 0x1d7cfdf7, 0xe7e3cf1, 0xc91a}}}, -{/*.x =*/{/*.val =*/{0xa222636, 0xd7de0d8, 0x299b9d3, 0x1e81212d, 0x2f88e93a, 0x3ac63cd9, 0x8f0e572, 0x2fb8c76f, 0xe583}}, - /*.y =*/{/*.val =*/{0x36b01c43, 0x3ac98e19, 0x18800b01, 0xfa7944d, 0x1dc3ac25, 0x9d40507, 0x1ddd7416, 0x1479107b, 0x75b0}}}, -{/*.x =*/{/*.val =*/{0x138011fc, 0x1c049c00, 0x17285626, 0x165a99eb, 0x200a4d83, 0x2c4cc208, 0x1eb11156, 0x4e8c205, 0x6e83}}, - /*.y =*/{/*.val =*/{0x3f15ab7d, 0x2b2da7e8, 0x1c51f9a6, 0x2be456ba, 0x1ac30426, 0x4b6c807, 0xf204c1a, 0x2062f709, 0xc147}}}, -{/*.x =*/{/*.val =*/{0x195b6f7e, 0x25527d71, 0x38b2021f, 0x2ccad4f4, 0x1876cdbe, 0x14eab42, 0x1a30c83a, 0x1f474133, 0xa5ac}}, - /*.y =*/{/*.val =*/{0xab19c84, 0x236edcc2, 0x1818a484, 0x38e4583d, 0x19ee1b99, 0x30f2491f, 0xf55b36c, 0x2282ad50, 0xdf0b}}}, -{/*.x =*/{/*.val =*/{0xe81c1bc, 0x24e92b93, 0x2bb5b33b, 0x14d97962, 0xce767d2, 0x2056e35a, 0x4635ad, 0x3c15197, 0x336}}, - /*.y =*/{/*.val =*/{0x166cbedd, 0x1b74a259, 0x8115017, 0x5ca3ad7, 0x30675323, 0x1a710944, 0x350014ff, 0x2d7e4315, 0x7e48}}}, -{/*.x =*/{/*.val =*/{0x14bc0324, 0x2a208b00, 0x24d2cfc5, 0x21fc0a35, 0x2f119155, 0x198968d9, 0xe7c338e, 0x299908fa, 0xb96b}}, - /*.y =*/{/*.val =*/{0x36c2ee15, 0x2d3afff6, 0x25ba8374, 0x33948a51, 0x1876b383, 0x3119268a, 0x285dfbea, 0xb336cee, 0xe83c}}}, -{/*.x =*/{/*.val =*/{0x30b7b678, 0x9d76cce, 0xf638166, 0xf10c46f, 0x2b6c76f1, 0x21af2909, 0x231ba19, 0x125ccd39, 0x186e}}, - /*.y =*/{/*.val =*/{0x38d91fc1, 0x1e81dbcb, 0x9535dca, 0x1dc8951, 0x37e67e11, 0x3f209702, 0x3bd84aa7, 0x18392601, 0xc0d4}}}, -{/*.x =*/{/*.val =*/{0xbb9dc8f, 0x23226e1, 0x1edd333d, 0x2a7a4fbd, 0x2787d1ab, 0x3dc0d4d4, 0x26864248, 0x1073b870, 0xfd99}}, - /*.y =*/{/*.val =*/{0x259780d5, 0x10fab94f, 0x2fe938d7, 0x1cacbf7b, 0x859e678, 0x25f815e2, 0xe6f46de, 0x3b1d6f50, 0x7a41}}}, -{/*.x =*/{/*.val =*/{0x3b963645, 0xfa50cb0, 0x271f1f8e, 0x336ca01f, 0x3132fb2d, 0x11e068b8, 0xa63e6e7, 0x2553ec6e, 0xc5f0}}, - /*.y =*/{/*.val =*/{0x8be2dd, 0x2fe21d3c, 0x47be4ed, 0xc140ac0, 0x20d7e6a3, 0xf2d1009, 0xb6fb18a, 0x34c4086c, 0xd552}}}, -{/*.x =*/{/*.val =*/{0x3b6aa206, 0x370ed72e, 0x31c19bce, 0xd5807fd, 0x1ac744bd, 0x4e3fc55, 0x1f7d2ec7, 0x215da31f, 0x9dac}}, - /*.y =*/{/*.val =*/{0x13b30b86, 0x235f518a, 0x23ff64cc, 0x1aaae446, 0x3bde77fa, 0x90ceda, 0x37bba791, 0x32b82b93, 0xb23c}}}, -{/*.x =*/{/*.val =*/{0x123809fa, 0x238ae3b7, 0x1d954be1, 0x21172cd4, 0x51f08fd, 0x24cd8fc9, 0x9f228ba, 0x76f8b94, 0x3838}}, - /*.y =*/{/*.val =*/{0x331fed52, 0x35c1d460, 0x2d8f24db, 0x207f32cc, 0xeb1cc36, 0x10169548, 0x117dcb09, 0xb4283ee, 0xe4a3}}}, -{/*.x =*/{/*.val =*/{0x3663da4, 0x2059b064, 0x35d0b81f, 0x28d8a467, 0x4aa2ba5, 0x229bb5f1, 0x1705e680, 0x128d5aa9, 0x6a66}}, - /*.y =*/{/*.val =*/{0x33fc22c4, 0xa0c4fec, 0x26c04c9c, 0x2645849f, 0x3f0cd508, 0x21bb065a, 0x1e98b29f, 0x496553f, 0x449a}}}, -{/*.x =*/{/*.val =*/{0x5ed815e, 0x3dc0b54, 0x1c017b47, 0x3d102af0, 0x147ad166, 0x17eb4865, 0x34a32ebb, 0x36b19e7d, 0x5568}}, - /*.y =*/{/*.val =*/{0x602df0, 0x26efd930, 0x2582151d, 0x17dfbb8, 0x73f2beb, 0x35bf8074, 0xba64580, 0x3e1d09e2, 0x7a85}}}, -{/*.x =*/{/*.val =*/{0x1ee840f8, 0x105d4ebc, 0x13c98f26, 0x4070980, 0x325cbe11, 0x2752e0a5, 0x3be4ecfc, 0x16a03720, 0x8719}}, - /*.y =*/{/*.val =*/{0x27eed395, 0x8a09a41, 0xa8dfa80, 0x22709c24, 0x1a2138dd, 0x3db76d2a, 0xe3aeb15, 0x773265b, 0x603}}}, -{/*.x =*/{/*.val =*/{0x2bf05bd6, 0xe67c139, 0x12a99465, 0x3d5b80c8, 0x70deca2, 0xbd47fad, 0x4fe9083, 0xc906fb9, 0x900c}}, - /*.y =*/{/*.val =*/{0x300d358b, 0x394ab4ef, 0x4efb15d, 0x2614d60f, 0xb2439d6, 0x31c8115c, 0x1f0f5f95, 0x3e7a3a2c, 0x6c31}}}, -{/*.x =*/{/*.val =*/{0x272e294d, 0x39becbde, 0xd0dd5b, 0x163ae8fc, 0x37edc6f1, 0xa27abb7, 0x134b91a6, 0x39201735, 0x29df}}, - /*.y =*/{/*.val =*/{0x2c469b52, 0x104dc983, 0x129ee694, 0x3c65870e, 0x205e4dd1, 0xd39d622, 0x272e19b4, 0x3609b401, 0xbf66}}}, -{/*.x =*/{/*.val =*/{0x33773f7, 0x31fc011b, 0x1b599953, 0x3513f4d1, 0x2372a150, 0x10430027, 0x1236d3e1, 0xc89bd77, 0x355b}}, - /*.y =*/{/*.val =*/{0x1887c182, 0x14f0ffc, 0xe251090, 0x977de33, 0x21fcb81e, 0x43bb774, 0x303ad49f, 0x29201c11, 0x8ec}}}, -{/*.x =*/{/*.val =*/{0x141fcc76, 0x10109c92, 0x227146b3, 0x34d666d9, 0x278a558d, 0x2ca70c2, 0x2d4ad848, 0x30c91061, 0x2a1e}}, - /*.y =*/{/*.val =*/{0x2451553f, 0x2837c990, 0x382a3120, 0x1549d580, 0x3e3b61b2, 0x2fb05054, 0x1cacf4c1, 0x20b9a3d9, 0xe01e}}}, -{/*.x =*/{/*.val =*/{0x2bfd913d, 0xfe5580f, 0x254c9eac, 0x29a039bb, 0x2a8d2050, 0x1e82130, 0x3ddf874d, 0xaa9fa41, 0x3636}}, - /*.y =*/{/*.val =*/{0x52e243d, 0x113e6bab, 0x2b2faafc, 0xc2ec435, 0x1a2a82d8, 0x18910dc3, 0xafd5341, 0x1e19db2e, 0x48f2}}}, -{/*.x =*/{/*.val =*/{0x375732c0, 0x1661934d, 0x33777aa8, 0xbf979c8, 0x31096e20, 0x29746df2, 0x34b9b624, 0x33cc7e2d, 0x8f3c}}, - /*.y =*/{/*.val =*/{0x25b9415b, 0x1cef7979, 0x858825e, 0x39a1dd5, 0xe53d8a9, 0x3d1b665f, 0x1e53189e, 0x334f8b4e, 0x67f1}}}, -{/*.x =*/{/*.val =*/{0x34889f3f, 0xa87e0e4, 0x1095da7f, 0x3faca2d1, 0x29b0ebc4, 0x28d1a6c5, 0x2119621e, 0x409bc6c, 0x8799}}, - /*.y =*/{/*.val =*/{0x3bb792b, 0x278b7e6f, 0x286037b4, 0xcbd86fc, 0x3f279de9, 0xbcb2dc5, 0x11d96213, 0x2e53296a, 0xddea}}}, -{/*.x =*/{/*.val =*/{0x2fa4e07e, 0x37614061, 0x3423bec4, 0xb29d215, 0x337d9a49, 0x7040ffe, 0x35718422, 0x2be545f7, 0x37d7}}, - /*.y =*/{/*.val =*/{0x2e020165, 0x24db61da, 0x18a65a4c, 0x8faa25e, 0x19c556c4, 0xecd4b18, 0x133c8f47, 0x1ea4a06a, 0x35bc}}}, -{/*.x =*/{/*.val =*/{0x3aee42db, 0x3e7f4af, 0x330714a7, 0x2eef16d1, 0x2cbfc1d9, 0x2dbb6e47, 0x19150fc7, 0x9f9f66d, 0xcc34}}, - /*.y =*/{/*.val =*/{0x15d87bdb, 0x188a7004, 0x272422dc, 0x3972eb63, 0x21520010, 0x38ff4fec, 0x1c6a1885, 0x26106948, 0xea24}}}, -{/*.x =*/{/*.val =*/{0x2e96e4f1, 0x2c29c594, 0x2e80030c, 0x17c05802, 0x1efccaff, 0x1ddc20cd, 0x197e201, 0x523c066, 0x56bb}}, - /*.y =*/{/*.val =*/{0x2eb0582e, 0x2227c067, 0x4af0eb5, 0x4f47480, 0x30ea9f73, 0xfb62f8, 0xa33beb, 0x2129584c, 0xa095}}}, -{/*.x =*/{/*.val =*/{0x1f23d1f, 0x1315fd66, 0xc036d8a, 0x2c97f5c8, 0x18a0a6b6, 0x3522787f, 0x30bbbbd3, 0x3a054f59, 0xb398}}, - /*.y =*/{/*.val =*/{0x32ff3fc, 0x160faffe, 0x26156cd1, 0x1e4762b4, 0xba52ea, 0x1ffacbec, 0x1f47f07f, 0x270895cb, 0x69f5}}}, -{/*.x =*/{/*.val =*/{0x34fb6a39, 0x9f576c6, 0x2ac90ecd, 0x235ab493, 0x1e119b8b, 0x3f4a59c, 0x1ea6e43e, 0x25abd5e5, 0x459}}, - /*.y =*/{/*.val =*/{0x725bb62, 0x30ab6de8, 0x20010535, 0x388a2d03, 0x2eef0373, 0x218a0837, 0x26c33672, 0x2b8338e0, 0xd3f9}}}, -{/*.x =*/{/*.val =*/{0x319888e9, 0xe73c9e4, 0x2448a8b4, 0x4ae9afc, 0x2681673d, 0x1834c0a5, 0x3a6e2dde, 0x3a9dceb0, 0x1f90}}, - /*.y =*/{/*.val =*/{0x2f113b79, 0x1bf7f25f, 0x19522e65, 0xdd47fb9, 0x2b96a821, 0x54f49c7, 0x2a10e958, 0xd9f0576, 0x89be}}}, -{/*.x =*/{/*.val =*/{0x1bf6c42, 0xfaacf77, 0x19887539, 0x1e4f66c4, 0xee74ef7, 0x1195205b, 0x105c7ee7, 0x6cf35b0, 0xd02e}}, - /*.y =*/{/*.val =*/{0x7bc54cc, 0xcd8ca3e, 0x31b6aac1, 0x2961e6e4, 0x124526bc, 0xc89c343, 0x22258127, 0x1d3cf2a3, 0x9a0b}}}, -{/*.x =*/{/*.val =*/{0xf6c15c2, 0x7bd1fc6, 0xf38f1ca, 0x39d90532, 0x1143483d, 0x1ce604e7, 0x1757fea1, 0x2a14af28, 0x8456}}, - /*.y =*/{/*.val =*/{0xb174134, 0x3c7bf0ca, 0x16fb671f, 0x3243c261, 0x79e7f4c, 0x127b0dc4, 0x2cdefd3, 0x3691b521, 0xe1b9}}}, -{/*.x =*/{/*.val =*/{0x27df614a, 0x1d47ebb3, 0x24705eb2, 0x27f39a4c, 0x3e1804d7, 0x91aa7fa, 0x33049180, 0x3966340b, 0xa7d2}}, - /*.y =*/{/*.val =*/{0x159b4c8d, 0x3c32f0e5, 0x19bc8656, 0x3c01de54, 0x3fa2de53, 0x207bb042, 0x10172c79, 0x33512f0, 0x62a2}}}, -{/*.x =*/{/*.val =*/{0xca1c4f9, 0x16d0aa86, 0x2b7e2823, 0x13bf8d32, 0x1f16f44f, 0x2e0f698, 0x1728c4c4, 0x3de3c8af, 0x7815}}, - /*.y =*/{/*.val =*/{0x3778bc15, 0x2ac7a8da, 0x177d1e19, 0x2d0b7985, 0x18c35d5c, 0x24f3cc51, 0x1af6a7dd, 0x7a334e, 0xc1c6}}}, -{/*.x =*/{/*.val =*/{0x3ed5996, 0x37933a2d, 0x360af53b, 0xc7f9664, 0x1b92468, 0x3ef240ca, 0x1a4ea492, 0x2dfa7fa6, 0x1a46}}, - /*.y =*/{/*.val =*/{0x28c85cae, 0x3b93b447, 0x352745c2, 0x21e52a7b, 0x23ebf550, 0x3b821281, 0x1dc570e3, 0x3a07a8fc, 0x683c}}}, -{/*.x =*/{/*.val =*/{0x2e2e607b, 0x3d34d673, 0xf36aa1, 0x2a87bb1b, 0x3fdd2b88, 0x447d595, 0x1772c20d, 0xfd9ff4c, 0x773}}, - /*.y =*/{/*.val =*/{0xc614763, 0x28bcc477, 0x3e017d26, 0x38ef7816, 0x3156f489, 0x18ea316e, 0x38285eae, 0x3a3eeb05, 0xfd9f}}}, -{/*.x =*/{/*.val =*/{0x354d61d1, 0x3ecb8807, 0x30b99baf, 0x549d76f, 0x1bf21517, 0x23e67901, 0x3ed8b9c5, 0x4f91d89, 0x875e}}, - /*.y =*/{/*.val =*/{0x945747, 0x12a27470, 0x273c5309, 0x277543a5, 0x399e3601, 0x1b784f4d, 0x56e8f64, 0x37712a59, 0x2d8f}}}, -{/*.x =*/{/*.val =*/{0x2fd53ed3, 0x17245d60, 0x1a56ccef, 0xfdd3ee7, 0x1f7c4916, 0x3d82e4c7, 0x372ad5b8, 0x2f56659, 0x2084}}, - /*.y =*/{/*.val =*/{0x1a7a7132, 0x1c50ff94, 0xe708998, 0x21f11ce5, 0x3afac254, 0x2f51da9a, 0x18243487, 0xd25f3b0, 0xf299}}}, -{/*.x =*/{/*.val =*/{0x2032f9a2, 0x122e38a4, 0x21fc6ccc, 0x159bd43e, 0x3f8f63ce, 0xdd32cc7, 0x32640ed2, 0x31af669a, 0x25aa}}, - /*.y =*/{/*.val =*/{0x2b51d4f0, 0x1d88c284, 0x19f3d9e, 0x2620eef1, 0x3190f655, 0xcbd53d3, 0x546c16f, 0x318ee991, 0xf5a6}}}, -{/*.x =*/{/*.val =*/{0x14445a7a, 0x4c72ea, 0x1cf1ec59, 0x254d7c20, 0x1c8d5df, 0x3c46db18, 0x2c6bfb12, 0x3bef27c1, 0xf82f}}, - /*.y =*/{/*.val =*/{0x242a7a98, 0x18eb3861, 0x240d1e59, 0x720ed91, 0xb4a4b5, 0xe50b065, 0x36b67550, 0xdef71be, 0x94bb}}}, -{/*.x =*/{/*.val =*/{0x362b8df9, 0xcb7ede8, 0x1da21c57, 0x7f6d47d, 0x11c8bd49, 0xcb74b72, 0x1c0cd9a8, 0x37634fb7, 0x11c4}}, - /*.y =*/{/*.val =*/{0x296edd30, 0x60c9e79, 0x2ec5448f, 0x2df9f498, 0x10fb6417, 0xd810e22, 0xac2aae4, 0x361da2fd, 0x45b3}}}, -{/*.x =*/{/*.val =*/{0x1def001d, 0x13c89769, 0x9ba27ef, 0x3e6ef5a6, 0x23b64b21, 0x2f47027, 0x22caf20e, 0x28cb6c9f, 0xa549}}, - /*.y =*/{/*.val =*/{0x30624783, 0x3576c69f, 0x2c9705ad, 0x5078a98, 0x259456eb, 0x330c3b62, 0x166cbdf4, 0x1e9e41b6, 0x799b}}}, -{/*.x =*/{/*.val =*/{0x206e37a, 0x91de2b1, 0x504731a, 0x23062523, 0x1a274f4d, 0x3a0fd1ad, 0x28002cf4, 0x2ae1fca1, 0xb526}}, - /*.y =*/{/*.val =*/{0x30c5ccab, 0x3cd9e3ff, 0xfa392ab, 0x3394e6c0, 0x26f18d28, 0x2ab3b582, 0xd8ed5c, 0xd75de04, 0x641f}}}, -{/*.x =*/{/*.val =*/{0x39d9123f, 0x3a4e0c7a, 0x388ba7d7, 0x3f1e46c7, 0x3d1e9129, 0x17e3b2be, 0x26a6f2f9, 0x14e3dcaa, 0x341b}}, - /*.y =*/{/*.val =*/{0x18bb9a40, 0x27a82abc, 0x12a26ed1, 0x37b9a9c1, 0x24d9ac72, 0x3cbc1044, 0x1c59eba6, 0x491c670, 0x5858}}}, -{/*.x =*/{/*.val =*/{0x760cb4d, 0x25763239, 0x33a69b68, 0x21f81500, 0x30673803, 0x154bafb0, 0x9df521a, 0x1fb94e37, 0xbca3}}, - /*.y =*/{/*.val =*/{0x24e10d88, 0x29dc18da, 0x8df9cf3, 0x5d5563c, 0x2ffbad9f, 0x22e020ee, 0x2d4b2263, 0xec707ef, 0x3ce0}}}, -{/*.x =*/{/*.val =*/{0xfb64db3, 0x1ee6354e, 0x1dd53841, 0x3b79328e, 0x13b8d6a7, 0x2ee0fef9, 0x1ccb740b, 0x8e48a6f, 0xc114}}, - /*.y =*/{/*.val =*/{0x3c0259be, 0x8c33a7f, 0x14567d1e, 0x1d602413, 0x178bd1a8, 0x3b3793fa, 0x6fc2a5c, 0x3db716d2, 0x1237}}}, -{/*.x =*/{/*.val =*/{0x311349e2, 0x20cab77, 0x3524c058, 0x38fb3d05, 0x1ad78d60, 0x51fa690, 0x1c2e7e62, 0x20c931ae, 0xf805}}, - /*.y =*/{/*.val =*/{0x1b2025fc, 0x3eb11a79, 0x26de88d5, 0x25262d58, 0x21122350, 0x206a983a, 0x56cdcde, 0x39682a2, 0x95c6}}}, -{/*.x =*/{/*.val =*/{0x2e548418, 0x1cdc7446, 0x9839231, 0x39221f62, 0x3a341adc, 0x1cac14d, 0x17e292fb, 0x2c327920, 0x2e6d}}, - /*.y =*/{/*.val =*/{0x10a2b918, 0x1a5e4b00, 0x1c3f5f1e, 0x23875cf8, 0x2911644b, 0xc5225e2, 0x36fbfa21, 0x1a90475d, 0x74eb}}}, -{/*.x =*/{/*.val =*/{0x3ccbdf95, 0x2b8fa3b1, 0xa5853b4, 0x8ac7291, 0x22f5494, 0x360c0ab2, 0x313050f, 0xbb60387, 0xcea0}}, - /*.y =*/{/*.val =*/{0x324a006c, 0x39954baa, 0x2ecc53d9, 0x2e8a1483, 0x10b433b2, 0x3301f5b, 0x34a6f04e, 0x1b1b61df, 0xfc00}}}, -{/*.x =*/{/*.val =*/{0x171c032b, 0x3536858a, 0x3afdc980, 0x1ad9a285, 0x766c5ff, 0x46d7f7f, 0x2603dd, 0x2a3f35b8, 0x71eb}}, - /*.y =*/{/*.val =*/{0x1668359f, 0x1ead6a38, 0x34b4755e, 0x24c6b45d, 0xcbb7f71, 0x18145bd5, 0x1d39def6, 0x49892d8, 0xd2ff}}}, -{/*.x =*/{/*.val =*/{0x3aaa138b, 0x37c367dc, 0x3786cd66, 0x3bee82fb, 0x671ff63, 0xfaf0631, 0x3ae28794, 0x389274f0, 0x417f}}, - /*.y =*/{/*.val =*/{0xa1ae869, 0x7246ccd, 0x5566afd, 0x276bf7b0, 0x3a9e57c1, 0x2974a7c3, 0x23e38c20, 0x2275ef34, 0x235}}}, -{/*.x =*/{/*.val =*/{0x307e636, 0x38562d04, 0x21611d97, 0x29df79cc, 0x2112c8b4, 0x2f0a6f68, 0x76443dd, 0x3c58058e, 0x2219}}, - /*.y =*/{/*.val =*/{0x31f15109, 0x1e86cb5, 0x373af55e, 0x35c8c34f, 0x230bd6d, 0x1b53c6e, 0x2a2f61b8, 0x212b172d, 0x4a9}}}, -{/*.x =*/{/*.val =*/{0x377220dc, 0x14ca7db7, 0x16023891, 0x27c96229, 0xe83bbd4, 0x27b40409, 0x2a8ad6a5, 0x3e507c9e, 0xffb2}}, - /*.y =*/{/*.val =*/{0x1b32b3bc, 0x26083b0c, 0x35e5f9f3, 0x3948efcf, 0x59d2f2c, 0x3e5e242, 0x3be7a03c, 0x34ffe08a, 0xf97e}}}, -{/*.x =*/{/*.val =*/{0xd9ed6c1, 0x1a2bad63, 0x3d593d6b, 0x139d16f0, 0x1edd0ec2, 0x3f061dc1, 0xf53e80b, 0xcdb72dd, 0x328}}, - /*.y =*/{/*.val =*/{0x38fafeee, 0x3b1baf9b, 0x1cb494ad, 0x16fd37c9, 0xd7c8c26, 0x35650e88, 0x19f28c46, 0x260e04bf, 0x71a8}}}, -{/*.x =*/{/*.val =*/{0x26da57e4, 0x2dd59229, 0x1cdd9f86, 0x31265bbf, 0x31bc1e98, 0x3a8a9d18, 0x118b9dbd, 0x36b8e60e, 0x690c}}, - /*.y =*/{/*.val =*/{0x133f33bb, 0x2d8656d2, 0x295a3d42, 0x18f63ef3, 0x15894df8, 0x3f646fd6, 0x379a47a9, 0x371e59de, 0x840a}}}, -{/*.x =*/{/*.val =*/{0x1cfb8036, 0x3e6262a9, 0xda35085, 0x3426a4b0, 0x167e833a, 0x45f747f, 0x247b48ae, 0x9d47ec5, 0xcff6}}, - /*.y =*/{/*.val =*/{0x24f59de0, 0x10fced68, 0x20328258, 0x2962763d, 0x2143c678, 0x38d2d621, 0x2d1ac5f, 0x3b49af55, 0xcdf4}}}, -{/*.x =*/{/*.val =*/{0x20ebec47, 0x1da4a12b, 0x142ca23d, 0x381398c4, 0x3b4ea72e, 0x10de9936, 0x27df9761, 0xe5dc744, 0xe8b6}}, - /*.y =*/{/*.val =*/{0x2eb3d8a7, 0x32a7875c, 0x15fe035, 0x398b696, 0x3ff204be, 0x6555e5f, 0x32e11ae7, 0xb7e8107, 0x5f38}}}, -{/*.x =*/{/*.val =*/{0x3319c869, 0x3df1bab8, 0x21eb2702, 0x2a7e575d, 0xcacdc18, 0x20e408bf, 0x33fc8d01, 0x1176605, 0x3018}}, - /*.y =*/{/*.val =*/{0x12b856f0, 0x3031db27, 0x23d9a7bf, 0xaa13292, 0x222e3bca, 0x1890c835, 0x3b7b6f86, 0x315e0940, 0xac5f}}}, -{/*.x =*/{/*.val =*/{0x18953133, 0x11df726c, 0x8721ae6, 0x2ced0a9d, 0xcdfa97f, 0xa01b03f, 0x1dd23881, 0xad3fb43, 0xa0b}}, - /*.y =*/{/*.val =*/{0x34af0fc9, 0x2f0928dc, 0xed4ba94, 0x28e13a2c, 0x58c8d6f, 0x71b2a19, 0x2bf2f03c, 0x60b3ed6, 0xcda1}}}, -{/*.x =*/{/*.val =*/{0x1f0a2a53, 0x3abc3b03, 0x16611e7, 0x772acfe, 0x29b892d5, 0xe515d0e, 0x3997c3a8, 0x146341f0, 0x6f86}}, - /*.y =*/{/*.val =*/{0x333bfeb2, 0x4e695d1, 0x2a05f351, 0x153ddcba, 0x309968bf, 0x1dbaa569, 0x182f29b7, 0x3d85bf51, 0xd50a}}}, -{/*.x =*/{/*.val =*/{0x278b4a0d, 0x1e78672f, 0x8c9be06, 0x3ed83c9f, 0x1c73ace4, 0xf5d6ed2, 0x3db4e1cb, 0x10bae9a8, 0x2f98}}, - /*.y =*/{/*.val =*/{0x33f39758, 0xd4cafba, 0x3d54f320, 0x23bab9da, 0xbb8f48b, 0x32489c59, 0x355552a1, 0x35a4c2f7, 0x4774}}}, -{/*.x =*/{/*.val =*/{0x3874b839, 0x444a1d5, 0x13d2b418, 0x10456ce5, 0x30b6aebe, 0x37c37ec8, 0x1e5a8053, 0x2e07f038, 0x3e03}}, - /*.y =*/{/*.val =*/{0x3c0594ba, 0x3073959, 0x1ab5b8da, 0x39717c3f, 0x198f667d, 0x3d981d5c, 0x7f42c44, 0x3858f7fc, 0xd13a}}}, -{/*.x =*/{/*.val =*/{0x39a7d197, 0x2eba434e, 0xea59459, 0x20ea3062, 0x2c234b5e, 0x23ff8288, 0x1f639477, 0x22950a03, 0xc2c5}}, - /*.y =*/{/*.val =*/{0x9eeb5e9, 0x390732fe, 0x1ad82484, 0x11fb1151, 0x2d39a60a, 0x106ad8b, 0x20927573, 0xca20d9b, 0x72ea}}}, -{/*.x =*/{/*.val =*/{0x23369217, 0x1d379b65, 0x6611ead, 0x70e5a40, 0x4eacdca, 0x289e3d50, 0xd624a21, 0x143ff2e9, 0x42dc}}, - /*.y =*/{/*.val =*/{0x3e2dbc57, 0x30c25f88, 0xe01e841, 0x284e7b2a, 0xba853a7, 0x1e3d7c58, 0x5b1d7ed, 0x2687d98e, 0xa5ba}}}, -{/*.x =*/{/*.val =*/{0x19251fa2, 0x1e7e8b49, 0x3c26cc92, 0x337ea0ae, 0x13d5e1bb, 0x1d1678dc, 0x1a1202b0, 0x31d972a4, 0x417}}, - /*.y =*/{/*.val =*/{0x3ebc52fa, 0x24c1240a, 0x161ee899, 0x292c61dd, 0x6283ad9, 0x1a19d99f, 0x357f5349, 0x397544b1, 0x72d7}}}, -{/*.x =*/{/*.val =*/{0x2cde4cf3, 0x26554187, 0x38a066ab, 0x10394d51, 0x1d9ae793, 0x30b49b45, 0x22c3be7, 0x2ad2b045, 0x384d}}, - /*.y =*/{/*.val =*/{0x252d0566, 0x1f1e5ac8, 0x351ba73b, 0x10c28ce5, 0x34c6f01f, 0x13b5b68a, 0x1ca43bfb, 0x316f346e, 0xd6e3}}}, -{/*.x =*/{/*.val =*/{0xa972627, 0x290d9a82, 0x2521e1f8, 0x24858100, 0x441a0e1, 0x2307bf2f, 0x3e15c819, 0x21c2526f, 0x8a31}}, - /*.y =*/{/*.val =*/{0x6bb8af9, 0x1ed1ed59, 0x3efcbcce, 0x110d96b0, 0x7baa417, 0x1dfb4a16, 0x3a64d095, 0x1f21da3d, 0x64bb}}}, -{/*.x =*/{/*.val =*/{0xa3a1550, 0x2951319f, 0x2ffdf279, 0x76a67e3, 0x38b75180, 0xc25db87, 0x157412dd, 0x1a6acd01, 0xebfc}}, - /*.y =*/{/*.val =*/{0x1362f6e, 0x7d0afd9, 0x28c0b195, 0x20f20639, 0x34fd0779, 0x3c6676df, 0xb540a3d, 0x3a336e67, 0xe2ff}}}, -{/*.x =*/{/*.val =*/{0x14f24bf1, 0x3e2ba88c, 0x2c500d25, 0x15500782, 0xe78708e, 0x1cdd2f0d, 0x2d024ec7, 0xeaf6dad, 0x6299}}, - /*.y =*/{/*.val =*/{0x108d1b1d, 0x34eb50c5, 0x148c6775, 0x24d4c0b2, 0x3c429b1d, 0x34b2bf8c, 0x29b93a00, 0x1cac2bab, 0x86fb}}}, -{/*.x =*/{/*.val =*/{0x39d681f9, 0x164153f9, 0x8feb9fc, 0x3383bbeb, 0x2c94b066, 0x1ffc9780, 0x3230888b, 0x3f7c9dd7, 0xc745}}, - /*.y =*/{/*.val =*/{0x3bbb1247, 0xc5cd0d, 0x27d45c76, 0x36f4cd71, 0x2818678c, 0x4e531c3, 0x1e5e78a7, 0x8bcbdae, 0x5902}}}, -{/*.x =*/{/*.val =*/{0x249a2115, 0x1dff54d1, 0x3a565ebe, 0x1e580245, 0x981aec, 0x1ab2a759, 0xc6c6dd4, 0x3014ac65, 0xfd73}}, - /*.y =*/{/*.val =*/{0x26ba6cda, 0x1272adee, 0x29d421f0, 0x3d80558b, 0x37d6d904, 0x2aeac09b, 0x38844020, 0x1a307205, 0x6207}}}, -{/*.x =*/{/*.val =*/{0x1b816b2f, 0x36e1b0d4, 0x228ee11f, 0x32de104, 0x2c5d5dee, 0x597f849, 0x11a676e8, 0x11b75965, 0x5a4d}}, - /*.y =*/{/*.val =*/{0x33e86c60, 0x3e5ebae1, 0x33ecceba, 0x39b317e, 0x3dfcd6b5, 0xf89fe3c, 0x260ab028, 0x8e5b283, 0x77c9}}}, -{/*.x =*/{/*.val =*/{0x31ce59e7, 0x110131b, 0x2d9919f3, 0x1db4e753, 0x324e6906, 0x359f05b6, 0x1f964c25, 0xbde79a8, 0x1bbc}}, - /*.y =*/{/*.val =*/{0x379aa297, 0x14c8648, 0x3839618d, 0x2265bd03, 0x1bc5a36c, 0x36c5beb4, 0x1f1a8781, 0x32d32375, 0x281f}}}, -{/*.x =*/{/*.val =*/{0x3bb80fa7, 0xd12172c, 0x30413886, 0x29f69aed, 0x20819f3a, 0x681af4c, 0xc2fbc0d, 0x38c7d8c2, 0x857}}, - /*.y =*/{/*.val =*/{0x9366b2d, 0x3660847c, 0xd7016ab, 0xb8dc10f, 0xb714717, 0x1f327477, 0x172092d, 0x24d08eb8, 0xf643}}}, -{/*.x =*/{/*.val =*/{0x3b6d6cd3, 0xe802af9, 0x38937883, 0x5984740, 0x25239734, 0x1a6e1c15, 0x3818481a, 0x19859fca, 0xea12}}, - /*.y =*/{/*.val =*/{0x34f450be, 0x2b98a497, 0x3be1a88a, 0x325d4b7a, 0x145e25b1, 0x3844afc4, 0x2e3fdaac, 0x38b941e3, 0x21a4}}}, -{/*.x =*/{/*.val =*/{0x1cff55c5, 0x1c48f509, 0x2275ec97, 0x13bf4a06, 0x2b4b635f, 0x4b079e0, 0x1442ca6c, 0x2b7f7ec9, 0xcf36}}, - /*.y =*/{/*.val =*/{0x21a0228e, 0x3289e214, 0xd2706a, 0x151fb097, 0x19f207a7, 0xbd62cef, 0x768649c, 0x4859ab8, 0xd16a}}}, -{/*.x =*/{/*.val =*/{0x125cb53b, 0x17a9e02b, 0x365eb3d0, 0x23f15763, 0x6272dab, 0x994c755, 0x25414494, 0x728acf7, 0xf474}}, - /*.y =*/{/*.val =*/{0x295a4b7e, 0x39769e65, 0x1f86e5c1, 0x5aa3ad, 0x2c8f9c0d, 0x3ec3609e, 0x1f2f01c8, 0x1bd03c89, 0xc48d}}}, -{/*.x =*/{/*.val =*/{0x3f2e070d, 0x160ff4e8, 0x12a6a98f, 0x2aadc731, 0x1047e229, 0x1cc70ee1, 0x34abff48, 0x297a410b, 0x4b72}}, - /*.y =*/{/*.val =*/{0x296dd780, 0x112ea0bb, 0x2948c3de, 0x2d197774, 0xf3c10b0, 0x1deecdb4, 0x2e1cf602, 0x753875a, 0x599e}}}, -{/*.x =*/{/*.val =*/{0x385912ec, 0xa1c0283, 0x6091134, 0x3e728139, 0x2f054327, 0x1265a52a, 0x35b786ab, 0x87538fe, 0xaa71}}, - /*.y =*/{/*.val =*/{0xae35978, 0x4532c99, 0x2056cbdb, 0x384d2a33, 0x22edebfe, 0x1499ae5a, 0x9509c50, 0x3c1df6b4, 0xc690}}}, -{/*.x =*/{/*.val =*/{0x3fd292dc, 0x2e01a893, 0x17714ce1, 0x1789a02c, 0x3d79d977, 0x201c34de, 0xf934ba4, 0x554cdc8, 0x4b99}}, - /*.y =*/{/*.val =*/{0x17095ca6, 0xce97ff9, 0x3376afd4, 0x20c8f116, 0x301f5793, 0x3029d2d7, 0x3a226df, 0x1d525844, 0xe327}}}, -{/*.x =*/{/*.val =*/{0x384da233, 0x2a560e3a, 0x1f362cd4, 0x13c36a04, 0x336ed9cf, 0x26f4ce3f, 0x25316a20, 0x32d365c7, 0x1eb7}}, - /*.y =*/{/*.val =*/{0x17c43f18, 0x2e3a954c, 0x1cf0ae9c, 0xdb26660, 0x1ed0aba3, 0x3cef342f, 0x84ff826, 0xca2b91f, 0xd984}}}, -{/*.x =*/{/*.val =*/{0x3bea0c68, 0x321042bc, 0x37b392b5, 0x10c048d9, 0x396faf09, 0x26f23a34, 0x2a3a2494, 0x258d3855, 0x3e41}}, - /*.y =*/{/*.val =*/{0x1a45edb6, 0x32edbfdc, 0x3cda1ab, 0x2846518c, 0x693062f, 0xf2ff8dc, 0x321f7f37, 0x31676492, 0x123}}}, -{/*.x =*/{/*.val =*/{0x17d4b84a, 0x2a605310, 0x1f433e69, 0x777d23c, 0x5070462, 0xa924b4a, 0x32fcb0c6, 0x26796371, 0xf13a}}, - /*.y =*/{/*.val =*/{0x13fd1c81, 0x16643f15, 0xf2d9628, 0x38df51c4, 0x3fe06eb6, 0x2e473478, 0x3e995aa6, 0x323343c2, 0x33c2}}}, -{/*.x =*/{/*.val =*/{0xe735a1e, 0x3c30ec51, 0x3e61fa05, 0xf8259a, 0x1202fc40, 0x23376b58, 0x356cb46b, 0x31f01e66, 0x678a}}, - /*.y =*/{/*.val =*/{0x12f7c055, 0xd8e97dc, 0x1371457a, 0x1fffeccf, 0x105e8e59, 0x3fcf55c, 0x1285b7a7, 0x138cf669, 0x851}}}, -{/*.x =*/{/*.val =*/{0x14c426d5, 0x30e07974, 0x22adf265, 0x29543e1e, 0x1fa93ab7, 0x1210c7e3, 0x2b66bd4c, 0x1d467823, 0x364c}}, - /*.y =*/{/*.val =*/{0x1a5876c0, 0x21b51ca9, 0x7db7191, 0x231357c5, 0x2d95be16, 0x2c62c634, 0x1fa52f1e, 0x2d65d0b2, 0xfaa8}}}, -{/*.x =*/{/*.val =*/{0x12fea1f9, 0x2c5f2ef1, 0x452b94, 0x3fc2d423, 0x106531c4, 0x3f76ad9c, 0x1f2e83bc, 0x22029574, 0xa6dc}}, - /*.y =*/{/*.val =*/{0x3bc345e9, 0x2c705391, 0x268f7e63, 0x1ee276df, 0x2cbc5005, 0x1a0e845a, 0x367c3038, 0x2a151f70, 0x7ef1}}}, -{/*.x =*/{/*.val =*/{0x1c7985c4, 0x2d84f9dc, 0x39e2b108, 0x12ff1256, 0x374c3413, 0xa10a00b, 0x19b7ce54, 0x2d72bded, 0x2320}}, - /*.y =*/{/*.val =*/{0xc2c6d44, 0x3fd3c77d, 0xd9eb8d4, 0x1bc40847, 0x1bca93d9, 0x1c86e07e, 0x3e94318c, 0x250f7222, 0xc79f}}}, -{/*.x =*/{/*.val =*/{0xa3a809c, 0x27f82c2f, 0x398346d7, 0x2d98bd75, 0x14a89eda, 0x33e5f909, 0x3df56bfb, 0x1fb20e4c, 0x125e}}, - /*.y =*/{/*.val =*/{0x149e70d9, 0x2a32402a, 0x7fca3dd, 0x138ecbbc, 0x321a371e, 0x1d1f2bd5, 0xcb38887, 0x3dbb7895, 0xe0d3}}}, -{/*.x =*/{/*.val =*/{0x208a7b1f, 0x3215fe35, 0x2a1ee514, 0x162bea6d, 0x3bc587f7, 0x141eb357, 0x37eb0079, 0x20efd263, 0x5ac}}, - /*.y =*/{/*.val =*/{0x165ccb98, 0x2198dd7e, 0x75d0f82, 0x3bc0ecc4, 0x2ac6f5b3, 0x33d08917, 0x2e6fb0fa, 0x271b3dd5, 0xe379}}}, -{/*.x =*/{/*.val =*/{0x27315443, 0x364e1ce0, 0x2e867299, 0x1e6ef552, 0x2142a13d, 0x32266082, 0x935ff42, 0x1b010198, 0xfc69}}, - /*.y =*/{/*.val =*/{0x17d28960, 0x1243582d, 0x9bd1b17, 0x1ffd2184, 0x1677b548, 0x387375a, 0x35892bbf, 0x9fafe0e, 0xe0ce}}}, -{/*.x =*/{/*.val =*/{0x3c6b5b56, 0x3cd857f5, 0x1888b607, 0x21722abb, 0x3200e541, 0x161fb4ef, 0x34338cdf, 0x2195c03b, 0xa0e8}}, - /*.y =*/{/*.val =*/{0x3a1d7518, 0x5af7944, 0x858a51a, 0x1ae1c75c, 0x13dead52, 0x29ae26e1, 0x1ad50b99, 0x11a0e7ea, 0xf5ba}}}, -{/*.x =*/{/*.val =*/{0x10cedd26, 0x35d977dd, 0x25715541, 0x322e677a, 0x239e2a3c, 0x360403e5, 0x1ebb2611, 0x120dca58, 0xaf88}}, - /*.y =*/{/*.val =*/{0x30e43f7f, 0x2db9eb4e, 0x3aa41708, 0x15279219, 0x2d2f9654, 0x32ee23af, 0x27030d28, 0x3efe5ec5, 0xdc57}}}, -{/*.x =*/{/*.val =*/{0x10b36a01, 0x1d9fddfc, 0x320812b5, 0x11e9ec5f, 0x2ec63cfc, 0x39ea5901, 0x3177a68a, 0x25375386, 0x853c}}, - /*.y =*/{/*.val =*/{0x27fe4ebe, 0x1f971fa3, 0x72f4fcc, 0x2fe60a00, 0x25123a28, 0x274080f7, 0x1b19530e, 0x33a53b26, 0xa328}}}, -{/*.x =*/{/*.val =*/{0x11da5e12, 0x7b838ce, 0x1cacb297, 0x31829005, 0x1ca2b6a9, 0xca7e4e8, 0x1e31bcda, 0xb8f10de, 0xf750}}, - /*.y =*/{/*.val =*/{0x385f4eb, 0x292e717a, 0x325cebc7, 0x21b4cbbd, 0x1672047b, 0x1c25170f, 0xfafd599, 0x3d7b759f, 0x3c57}}}, -{/*.x =*/{/*.val =*/{0x3e32478e, 0xdcc481c, 0x29ba7ed2, 0x2acc63ca, 0x332b2024, 0x31adfcfc, 0x213880fe, 0x4758041, 0xd420}}, - /*.y =*/{/*.val =*/{0x104e88d4, 0x33815a07, 0x1508cc31, 0x2c92cbcd, 0x3f847b6f, 0x357d7d12, 0x14e0c1b2, 0x353a68df, 0xbae5}}}, -{/*.x =*/{/*.val =*/{0x216ddcd3, 0x1a9c8dee, 0x1ea00355, 0x12c44008, 0x761af04, 0x16fadb2e, 0x299edf7b, 0x2b4dbd93, 0x1ae1}}, - /*.y =*/{/*.val =*/{0x2e7eb2b7, 0x33118674, 0xbb613c7, 0x185ab77f, 0x10448959, 0x1d3ddd48, 0x922059c, 0x15261e8, 0x7016}}}, -{/*.x =*/{/*.val =*/{0x19158bab, 0x264fc10e, 0x12d06caa, 0x4c9b0c6, 0x5a0674c, 0x1f3cf7cb, 0x39b3c419, 0x3d2ec203, 0xe2c6}}, - /*.y =*/{/*.val =*/{0x2d7a27f2, 0x214f3c9e, 0x49fd3f5, 0x6d622e4, 0x3ef5c641, 0xaecd847, 0xb1eabd1, 0x1e18b4f0, 0xfa92}}}, -{/*.x =*/{/*.val =*/{0x3a95a8db, 0x1761dccb, 0x39d36f61, 0xfb03111, 0x1b1723b8, 0x25991a64, 0x3dd0419e, 0x36918c0, 0xe3e9}}, - /*.y =*/{/*.val =*/{0x1b0d1cf9, 0x5b3dfc, 0x984d3d1, 0x2c7be5f3, 0x2e76afb, 0x3eaa431c, 0x178bb00, 0xef0015b, 0xfbe5}}}, -{/*.x =*/{/*.val =*/{0x141d0ce6, 0x13f0f72d, 0x3598d41f, 0x2264a8b3, 0x205fb274, 0x53338ce, 0x1a9412ee, 0x168a4dfc, 0x1429}}, - /*.y =*/{/*.val =*/{0x1738bb86, 0xaa06a2b, 0x35d241a5, 0x2255806, 0x83b131, 0xc711211, 0x150711b0, 0x14d8f7c4, 0xfea7}}}, -{/*.x =*/{/*.val =*/{0xb344f7f, 0x1c633e71, 0xce60c4c, 0x22e27f52, 0x26d410ee, 0x1f8cb2f4, 0x2e0ae0e9, 0x3212f65c, 0x354c}}, - /*.y =*/{/*.val =*/{0x25db82d6, 0x392c46ba, 0x202e0ec7, 0xdb18061, 0x3a88558e, 0x2d24fe6, 0x6b5d675, 0x2fca4a47, 0x9c04}}}, -{/*.x =*/{/*.val =*/{0x1983ce4e, 0x2ecf54dc, 0x1578253f, 0x40f6279, 0x23024a60, 0xeee0d6a, 0x35975f0e, 0x3da7674c, 0x8704}}, - /*.y =*/{/*.val =*/{0x16572c0a, 0x1c256368, 0x302df498, 0x16e840b8, 0x296bac34, 0x231d35d6, 0x2ec26a3, 0x14817389, 0x6b0b}}}, -{/*.x =*/{/*.val =*/{0x3a3979b5, 0xa8666c2, 0x27e829e2, 0xa23e379, 0x240e50ba, 0xdfc2c7b, 0x1e26327f, 0x1f1736b, 0xae22}}, - /*.y =*/{/*.val =*/{0x450fa6f, 0x23cf359a, 0x3d4f8896, 0x2a1edf4d, 0x2d7060fc, 0x3249148e, 0x39f71ad4, 0x3f944301, 0xea91}}}, -{/*.x =*/{/*.val =*/{0x2ce4dd6a, 0x16784787, 0x3221cef5, 0x392728, 0x164c460a, 0x3b28dfa3, 0x12b64bc9, 0x393dec9e, 0x49db}}, - /*.y =*/{/*.val =*/{0x2a9e3eae, 0x4edca90, 0x205bb69b, 0xe154bf2, 0x12255a1c, 0x3f8cf6da, 0x81c72c5, 0x1ca611c1, 0xb8b5}}}, -{/*.x =*/{/*.val =*/{0x34e5f03a, 0x3fa2d6f7, 0x21606d54, 0x1597fac7, 0x3dfe3596, 0x373eccf5, 0x1be33737, 0x13f740a2, 0x80c3}}, - /*.y =*/{/*.val =*/{0x3e3ca504, 0x5fd151b, 0x33245cb1, 0x2cabbc7, 0x1c9a03d3, 0x36d5c01f, 0x1ecd55e, 0x215a9e3, 0x247e}}}, -{/*.x =*/{/*.val =*/{0x29565331, 0x20617fbe, 0x1a915abf, 0x17a2498b, 0xcf1ce93, 0xe7bed50, 0x30c22611, 0x1493240d, 0x9d32}}, - /*.y =*/{/*.val =*/{0x26f06930, 0x758c2a, 0x236934f9, 0x32544bb0, 0x6d2ae5c, 0x3b130b2f, 0x22ebfd7f, 0x15cf49df, 0x3766}}}, -{/*.x =*/{/*.val =*/{0x354b8367, 0x25201cf5, 0x3d506bfe, 0x1d6ddf59, 0x36a5db7, 0x2a975161, 0x2526e40c, 0x252b911, 0x5e5a}}, - /*.y =*/{/*.val =*/{0x11ce85ca, 0x14ca6a76, 0x1e5ffa44, 0x1aaa7bcf, 0x2a4b7a79, 0x2407c55c, 0x15e05c2c, 0x3e32691e, 0xae8a}}}, -{/*.x =*/{/*.val =*/{0xcbcad59, 0x2c17a0d8, 0xe0aaa07, 0x21168169, 0x3902f17c, 0x5f21697, 0x36007aa, 0x1b0454ab, 0x2ed7}}, - /*.y =*/{/*.val =*/{0x4ea66fe, 0x12b1ea27, 0xa7f9411, 0x1cb1804c, 0x1767ed5f, 0x29babb20, 0x5f222cd, 0x135010ee, 0x639f}}}, -{/*.x =*/{/*.val =*/{0x24b84b48, 0xc3d15c7, 0x1e817ea8, 0x2b7d31e6, 0x17f7091, 0x43d5df5, 0x1a4f5419, 0x37c39f51, 0x5fb1}}, - /*.y =*/{/*.val =*/{0x37be8eb8, 0x1fb7a9a8, 0x33f21ad7, 0xa70e421, 0x2d258206, 0x3d191bf9, 0x4d49fbc, 0x3eef2f0f, 0x2152}}}, -{/*.x =*/{/*.val =*/{0x2aa2a748, 0x15d87054, 0x378c403d, 0x2c99f85, 0x2835d8c9, 0x337e7d1a, 0x141486c5, 0x27edac70, 0x135a}}, - /*.y =*/{/*.val =*/{0x38a6cf84, 0xc41675b, 0x3f91ab2d, 0x19b84fa2, 0x9453a65, 0x18b97f9c, 0x15938e7, 0x778b2a8, 0xa869}}}, -{/*.x =*/{/*.val =*/{0xfd69985, 0x2717764, 0x1df72aea, 0xc2732db, 0xccf149f, 0x3da437ef, 0x32f7e788, 0x1d9d73ad, 0xae9}}, - /*.y =*/{/*.val =*/{0x1409a003, 0x2723ad04, 0x2ee1aff8, 0x2e67505e, 0x1a54c5d0, 0x237fb814, 0x8d14e9b, 0x265cfdb9, 0x9121}}}, -{/*.x =*/{/*.val =*/{0x2078afb0, 0x39d6b9e5, 0x1261974, 0x3fc4b1b1, 0x2d170714, 0x3511a319, 0x163b5248, 0x1af35d98, 0x209d}}, - /*.y =*/{/*.val =*/{0x2740b310, 0x1746ddd6, 0x1f4e3e38, 0x3b6de4ce, 0x98a5b01, 0x196eaea6, 0x33280a09, 0x4d0a79e, 0x1a2f}}}, -{/*.x =*/{/*.val =*/{0x1f55a9bf, 0x2f2c0a63, 0x1ea5bf8e, 0x2c057bca, 0x17c578f6, 0xc1fd807, 0x23181810, 0x263ae71b, 0x7262}}, - /*.y =*/{/*.val =*/{0x3c3accae, 0x45be2c2, 0x673b4e, 0x1e5ef2f0, 0x1099e0be, 0xd68bbcf, 0x29bfda98, 0x22006a77, 0x38d4}}}, -{/*.x =*/{/*.val =*/{0x3dbb04fa, 0x5c195a8, 0x118911f9, 0x29c145ac, 0x26b5e114, 0x2e090979, 0x26ed4d7c, 0xb7eecd1, 0x7fe4}}, - /*.y =*/{/*.val =*/{0x21908c89, 0x359d2447, 0x2c1b9c55, 0x3a28a234, 0x334cf0aa, 0x1b22c1e5, 0x5f4330f, 0x1e82d3d7, 0x2eec}}}, -{/*.x =*/{/*.val =*/{0x2e4b3ba0, 0x2167d8d7, 0x18bf1f17, 0xaafbd7c, 0x3f245f5c, 0x385c3cc6, 0x3fb73bef, 0x4414887, 0x4108}}, - /*.y =*/{/*.val =*/{0x17525595, 0x21a58770, 0x1a064554, 0xd926159, 0x2b849813, 0x2996b875, 0x35668f2c, 0x3cda5dbf, 0xdc37}}}, -{/*.x =*/{/*.val =*/{0xe5485, 0x22799a8, 0x1da5df02, 0x4c1a2fd, 0x320f1245, 0x31c2189c, 0x2bdff8e2, 0x1db5e4e8, 0x1cd2}}, - /*.y =*/{/*.val =*/{0x85fbd7f, 0x2973c146, 0x209a4ecc, 0x34389c2c, 0x2e977f99, 0x2cd35154, 0x2af738d4, 0x2f7462cb, 0x6615}}}, -{/*.x =*/{/*.val =*/{0x290bc03e, 0x31d4f566, 0x1e015e33, 0x2c3ce4d4, 0x50f8084, 0x2a497dd1, 0x2072e9e5, 0x363b4b20, 0x2cee}}, - /*.y =*/{/*.val =*/{0x3ab82adc, 0x32dcae2d, 0xd53cd01, 0x77e73c8, 0x7daeb4a, 0x143adebf, 0x1de3ecd8, 0x1ae03a6e, 0xa427}}}, -{/*.x =*/{/*.val =*/{0x3009ee3e, 0x2e71352e, 0x729ead5, 0x9a8799e, 0x272de237, 0x273af1, 0x22ac92b7, 0x216c0cba, 0xb17a}}, - /*.y =*/{/*.val =*/{0x296b911d, 0x18f947b, 0x446fa38, 0x85b29f2, 0x26eda65, 0x63f703, 0x29a65f5c, 0x9a749ac, 0x966e}}}, -{/*.x =*/{/*.val =*/{0xe103dd6, 0x37dc51c8, 0x4859a, 0x1181301f, 0x12a17ac3, 0x84f3f16, 0x203f836a, 0x1ef55690, 0xbc47}}, - /*.y =*/{/*.val =*/{0x16f7c343, 0xe420b63, 0x23b44ac6, 0xa4d5cb1, 0x1ea6395d, 0x2b154b1b, 0xdd526cb, 0x7890a6a, 0xe31e}}}, -{/*.x =*/{/*.val =*/{0x36695f94, 0xb602c60, 0x1627fa59, 0x285a71a4, 0x39a9cf62, 0x32e1a0eb, 0x18f5fd0c, 0x17546d15, 0xb1d2}}, - /*.y =*/{/*.val =*/{0x1ee32736, 0x16dfae69, 0x3863edca, 0x3dbc636a, 0x2ba81760, 0x3a82b066, 0x290b1f7b, 0x369c80c3, 0x706d}}}, -{/*.x =*/{/*.val =*/{0x36f83231, 0x265c4062, 0x20425e34, 0x30c3639d, 0x33fdd0b7, 0x5609d96, 0x2ba26a8d, 0x23314d40, 0x850f}}, - /*.y =*/{/*.val =*/{0x1f2e8373, 0x280c6a75, 0x322d77f4, 0x216fe85d, 0x2cc7890a, 0x3dc21ae0, 0x39053d0b, 0x276f80a9, 0xbc4a}}}, -{/*.x =*/{/*.val =*/{0x39343959, 0xb882f6f, 0x2c9ce78a, 0x28673cbe, 0x1bc1f617, 0x2bfa4c24, 0x651465d, 0x6e01743, 0x2d38}}, - /*.y =*/{/*.val =*/{0x1442fb00, 0x1c432ba8, 0x31e45a43, 0x14b57589, 0x31025f43, 0x2bcbce90, 0x361bf59a, 0x3782534a, 0x5451}}}, -{/*.x =*/{/*.val =*/{0x152da17d, 0x18283e90, 0xd0646b1, 0x3704f6c2, 0x200bc811, 0x139ac17f, 0x18c5f089, 0x3b4783d4, 0x3bea}}, - /*.y =*/{/*.val =*/{0x2cc768d2, 0x39c12617, 0x1fec416c, 0x3379dee3, 0xe1b554, 0x12a2fafa, 0x37acdfef, 0x35fd56bf, 0xc3b0}}}, -{/*.x =*/{/*.val =*/{0x1063e1be, 0x6e6b413, 0x3e39a75c, 0x90a68bd, 0x3cf027a9, 0x185494f6, 0x2b14722, 0x10744758, 0x1316}}, - /*.y =*/{/*.val =*/{0x21fec890, 0x3747fcf8, 0x1745b77f, 0x3ebb03e, 0x3d2bebbd, 0xb8c3f36, 0x39f06a4, 0x36985e58, 0x4c3b}}}, -{/*.x =*/{/*.val =*/{0x3c46e079, 0x4a80d49, 0x1e9c78dd, 0x19a4c2e1, 0x2ba374ab, 0x3dd6b6c0, 0x3ac530fe, 0x30ab4ab3, 0xab86}}, - /*.y =*/{/*.val =*/{0x3636ffe1, 0x310a2f05, 0x50d7c0e, 0x1dca3a12, 0x3200c9ce, 0x311b535c, 0x329abcf5, 0x30a18067, 0x1209}}}, -{/*.x =*/{/*.val =*/{0x17d37248, 0x227c6075, 0x117ceae4, 0x20d6d947, 0x2b2787bc, 0x1bac891a, 0x36d5aa4d, 0x946f0fb, 0xadc4}}, - /*.y =*/{/*.val =*/{0x2adcbc1b, 0x1811f2b3, 0x50bebc8, 0x37156ec5, 0x16f70b9, 0x18f8d8a4, 0x1e7eb5d0, 0x2dd8b8f1, 0xb0f3}}}, -{/*.x =*/{/*.val =*/{0xeca5f51, 0x85ac826, 0xfc9aebf, 0x3a85c6e5, 0x5b5cfdd, 0x3b5acafc, 0x2e6962c6, 0x35453767, 0xdde9}}, - /*.y =*/{/*.val =*/{0x10c638f7, 0x2b5a69cf, 0x289571f9, 0x3fbafa37, 0x3f8f0950, 0x7cd2c29, 0x28111d89, 0x1a44cf38, 0xb84e}}}, -{/*.x =*/{/*.val =*/{0x209b0cca, 0x3331a956, 0xa4d6f01, 0x115d6249, 0x28da59a3, 0x1153da28, 0xf4c8d5c, 0x232c76ec, 0xd53}}, - /*.y =*/{/*.val =*/{0xc929e05, 0xc6c51f8, 0x9134c97, 0xd336676, 0x2ed7cf85, 0x2a357103, 0x2c110cb0, 0x1aeb1e8f, 0xc819}}}, -{/*.x =*/{/*.val =*/{0x2dd7e577, 0x2b8c0f3b, 0x136c4d56, 0x283c95a1, 0x2a2107d3, 0x1811c9c3, 0xf7b25ac, 0x3543e20a, 0xc352}}, - /*.y =*/{/*.val =*/{0x38d9b570, 0x3293fe23, 0x21217063, 0x2a2aecad, 0xe79fb00, 0x354c516f, 0x2b9b96ab, 0xa0e2e9d, 0xbe77}}}, -{/*.x =*/{/*.val =*/{0x23868246, 0x22fcdeb0, 0x6dd2ded, 0x27db62bd, 0x2248ba8, 0x17641f4b, 0x11d600b5, 0x1f82acce, 0xfb9d}}, - /*.y =*/{/*.val =*/{0x2969605a, 0x2760f82b, 0x2a2606d2, 0x34ab4c16, 0x1475f4a6, 0x2a2e05a8, 0x3680cff2, 0x26f807d2, 0xb038}}}, -{/*.x =*/{/*.val =*/{0x3712be3c, 0x1a8b8cb, 0x2146a66b, 0x257c63b6, 0x153472, 0x1c976eac, 0x1b378d3c, 0xd2764cc, 0x39d7}}, - /*.y =*/{/*.val =*/{0x1c6ff65c, 0x30c067d0, 0xa41644c, 0x17bde97b, 0x2812e8ef, 0x9d55319, 0x33bf7fb1, 0x26d3d5bb, 0x8f92}}}, -{/*.x =*/{/*.val =*/{0x37829372, 0x3b02a929, 0xba4553d, 0x26cc0322, 0x5796bc4, 0x189ab94e, 0x20d3b313, 0x273243cf, 0xb431}}, - /*.y =*/{/*.val =*/{0xadd5427, 0x1ca73300, 0x23e11bb7, 0x1ec48572, 0x21c5a270, 0x1ebf8270, 0x3502bffb, 0x3512669b, 0x4707}}}, -{/*.x =*/{/*.val =*/{0xdcbcb9e, 0x12fc449b, 0xd83c3df, 0x3e95a277, 0x143761d6, 0x30c911ff, 0x1337a9ec, 0x4b5c467, 0xcdcb}}, - /*.y =*/{/*.val =*/{0x961cfd1, 0x229616b, 0x18df340a, 0x266bc90d, 0x1e9949a1, 0x3efa825b, 0x1f11fbfe, 0x38b85eee, 0xe699}}}, -{/*.x =*/{/*.val =*/{0xe90bc26, 0x1e074991, 0x364d3aa0, 0x22880f84, 0xacd88a9, 0xf195b1d, 0x27275f3d, 0x385bd96d, 0x5e4d}}, - /*.y =*/{/*.val =*/{0x252f79e, 0x5f546a, 0x1127f9c7, 0x194f732b, 0x3ad55207, 0xebea5e0, 0x1432904e, 0x3cb90d4f, 0x5ac5}}}, -{/*.x =*/{/*.val =*/{0x754dd40, 0x18fa1c55, 0x3466cf8, 0x10898c7f, 0x32f6e9a2, 0x12107f35, 0xdfcf45b, 0x91c0cb0, 0x9729}}, - /*.y =*/{/*.val =*/{0x2aa36143, 0x212d24bc, 0x1acaf493, 0x36ba1495, 0x14df3690, 0x171d772f, 0x3ea1dcd1, 0x28910997, 0x91d1}}}, -{/*.x =*/{/*.val =*/{0xc7a89ee, 0x15f0d4cc, 0x2b6d4f80, 0x36f1671e, 0x18658a4b, 0x182e23f2, 0x179e1128, 0x29389a90, 0x71ef}}, - /*.y =*/{/*.val =*/{0x1366a2e, 0x3d224ca7, 0x25e9a0b4, 0x2abeae23, 0x3294a22a, 0x2cb0cac5, 0x224ae9ef, 0x2a07e2ed, 0x145f}}}, -{/*.x =*/{/*.val =*/{0xde0545f, 0x32c08d26, 0x106c74f5, 0x39897688, 0x3508ac80, 0x17a8012c, 0x7124a37, 0x16f31638, 0x5204}}, - /*.y =*/{/*.val =*/{0x106c3d91, 0x1ba8d301, 0x28fdaf23, 0xee743ca, 0xe312b79, 0x3b67083, 0x3123ad43, 0xc7f3af8, 0x1b3f}}}, -{/*.x =*/{/*.val =*/{0x3ddaa5d5, 0x1873f311, 0x14d4b7ab, 0x27a034e9, 0x16607331, 0x3bf9159a, 0x28c4e4e8, 0x2646e4be, 0x4e9}}, - /*.y =*/{/*.val =*/{0x2cba1c91, 0x35f800ff, 0x255f570d, 0x3827db86, 0x957303c, 0x1ab47630, 0x327f1d9e, 0x577778a, 0x62fc}}}, -{/*.x =*/{/*.val =*/{0x26a06f5e, 0x6902d65, 0x2a083702, 0x1064945b, 0x23b716a3, 0x2c350849, 0x253ac37, 0x93efa85, 0x383b}}, - /*.y =*/{/*.val =*/{0x13c6e772, 0x227d1e1b, 0x38c2b040, 0x3dab9d2e, 0x2a5a19e8, 0x3d59b553, 0x1ba2044c, 0x1c1ab13b, 0x54cf}}}, -{/*.x =*/{/*.val =*/{0x1bcf2dce, 0x4e6d023, 0x1dc6c02, 0x4528417, 0x3f998068, 0x2793264b, 0x6218bd4, 0xb50a4b9, 0x95e6}}, - /*.y =*/{/*.val =*/{0x18c86594, 0xaf77f7d, 0x304d20e6, 0x1ecc180d, 0x28d52e5e, 0x289b8ad0, 0x2875183, 0x20610a5b, 0x6b6}}}, -{/*.x =*/{/*.val =*/{0x17a6257f, 0x20149916, 0x27a6c40b, 0x1cf0ec68, 0x7e78918, 0x909d2ac, 0x14f25a64, 0xd72387d, 0x71e9}}, - /*.y =*/{/*.val =*/{0x11b1e582, 0x2c85d187, 0xf70f7a5, 0x948d503, 0x2e2a52ef, 0x361ae91e, 0x22513de, 0xf967d1f, 0x78d9}}}, -}; #endif diff --git a/secp256k1.h b/secp256k1.h index e3a5f5378..ebeff415a 100644 --- a/secp256k1.h +++ b/secp256k1.h @@ -54,7 +54,6 @@ extern const bignum256 secp256k1_iv[256]; #if USE_PRECOMPUTED_CP extern const curve_point secp256k1_cp[256]; -extern const curve_point secp256k1_cp2[255]; #endif #endif From 019d779a94d5d6780f7636a18f2e5d7450655c12 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 3 Jul 2014 10:09:45 +0200 Subject: [PATCH 107/627] Revert "Revert "add more precomputation to ecdsa signing"" This reverts commit 3747ba432336bf10191a63e84fbfead62e944ddb. --- bignum.c | 130 +++++++------ ecdsa.c | 41 +++-- secp256k1.c | 513 ++++++++++++++++++++++++++++++++++++++++++++++++++++ secp256k1.h | 1 + 4 files changed, 611 insertions(+), 74 deletions(-) diff --git a/bignum.c b/bignum.c index 2fdb52bd8..06e7308bc 100644 --- a/bignum.c +++ b/bignum.c @@ -303,14 +303,20 @@ void bn_inverse(bignum256 *x, const bignum256 *prime) void bn_inverse(bignum256 *x, const bignum256 *prime) { int i, j, k, len1, len2, mask; - uint32_t u[9], v[9], s[10], r[10], temp, temp2; + uint8_t buf[32]; + uint32_t u[8], v[8], s[9], r[10], temp32; + uint64_t temp, temp2; bn_fast_mod(x, prime); bn_mod(x, prime); - for (i = 0; i < 9; i++) { - u[i] = prime->val[i]; - v[i] = x->val[i]; + bn_write_be(prime, buf); + for (i = 0; i < 8; i++) { + u[i] = read_be(buf + 28 - i * 4); + } + bn_write_be(x, buf); + for (i = 0; i < 8; i++) { + v[i] = read_be(buf + 28 - i * 4); } - len1 = 9; + len1 = 8; s[0] = 1; r[0] = 0; len2 = 1; @@ -327,13 +333,13 @@ void bn_inverse(bignum256 *x, const bignum256 *prime) if (i == 0) break; mask = (1 << i) - 1; for (j = 0; j + 1 < len1; j++) { - u[j] = (u[j] >> i) | ((u[j + 1] & mask) << (30 - i)); + u[j] = (u[j] >> i) | ((u[j + 1] & mask) << (32 - i)); } u[j] = (u[j] >> i); - mask = (1 << (30 - i)) - 1; - s[len2] = s[len2 - 1] >> (30 - i); + mask = (1 << (32 - i)) - 1; + s[len2] = s[len2 - 1] >> (32 - i); for (j = len2 - 1; j > 0; j--) { - s[j] = (s[j - 1] >> (30 - i)) | ((s[j] & mask) << i); + s[j] = (s[j - 1] >> (32 - i)) | ((s[j] & mask) << i); } s[0] = (s[0] & mask) << i; if (s[len2]) { @@ -349,13 +355,13 @@ void bn_inverse(bignum256 *x, const bignum256 *prime) if (i == 0) break; mask = (1 << i) - 1; for (j = 0; j + 1 < len1; j++) { - v[j] = (v[j] >> i) | ((v[j + 1] & mask) << (30 - i)); + v[j] = (v[j] >> i) | ((v[j + 1] & mask) << (32 - i)); } v[j] = (v[j] >> i); - mask = (1 << (30 - i)) - 1; - r[len2] = r[len2 - 1] >> (30 - i); + mask = (1 << (32 - i)) - 1; + r[len2] = r[len2 - 1] >> (32 - i); for (j = len2 - 1; j > 0; j--) { - r[j] = (r[j - 1] >> (30 - i)) | ((r[j] & mask) << i); + r[j] = (r[j - 1] >> (32 - i)) | ((r[j] & mask) << i); } r[0] = (r[0] & mask) << i; if (r[len2]) { @@ -368,23 +374,25 @@ void bn_inverse(bignum256 *x, const bignum256 *prime) i = len1 - 1; while (i > 0 && u[i] == v[i]) i--; if (u[i] > v[i]) { - temp = 0x40000000u + u[0] - v[0]; - u[0] = (temp >> 1) & 0x1FFFFFFF; - temp >>= 30; + temp = 0x100000000ull + u[0] - v[0]; + u[0] = (temp >> 1) & 0x7FFFFFFF; + temp >>= 32; for (i = 1; i < len1; i++) { - temp += 0x3FFFFFFFu + u[i] - v[i]; - u[i - 1] += (temp & 1) << 29; - u[i] = (temp >> 1) & 0x1FFFFFFF; - temp >>= 30; + temp += 0xFFFFFFFFull + u[i] - v[i]; + u[i - 1] += (temp & 1) << 31; + u[i] = (temp >> 1) & 0x7FFFFFFF; + temp >>= 32; } temp = temp2 = 0; for (i = 0; i < len2; i++) { - temp += s[i] + r[i]; - temp2 += s[i] << 1; - r[i] = temp & 0x3FFFFFFF; - s[i] = temp2 & 0x3FFFFFFF; - temp >>= 30; - temp2 >>= 30; + temp += s[i]; + temp += r[i]; + temp2 += s[i]; + temp2 += s[i]; + r[i] = temp; + s[i] = temp2; + temp >>= 32; + temp2 >>= 32; } if (temp != 0 || temp2 != 0) { r[len2] = temp; @@ -392,23 +400,25 @@ void bn_inverse(bignum256 *x, const bignum256 *prime) len2++; } } else { - temp = 0x40000000u + v[0] - u[0]; - v[0] = (temp >> 1) & 0x1FFFFFFF; - temp >>= 30; + temp = 0x100000000ull + v[0] - u[0]; + v[0] = (temp >> 1) & 0x7FFFFFFF; + temp >>= 32; for (i = 1; i < len1; i++) { - temp += 0x3FFFFFFFu + v[i] - u[i]; - v[i - 1] += (temp & 1) << 29; - v[i] = (temp >> 1) & 0x1FFFFFFF; - temp >>= 30; + temp += 0xFFFFFFFFull + v[i] - u[i]; + v[i - 1] += (temp & 1) << 31; + v[i] = (temp >> 1) & 0x7FFFFFFF; + temp >>= 32; } temp = temp2 = 0; for (i = 0; i < len2; i++) { - temp += s[i] + r[i]; - temp2 += r[i] << 1; - s[i] = temp & 0x3FFFFFFF; - r[i] = temp2 & 0x3FFFFFFF; - temp >>= 30; - temp2 >>= 30; + temp += s[i]; + temp += r[i]; + temp2 += r[i]; + temp2 += r[i]; + s[i] = temp; + r[i] = temp2; + temp >>= 32; + temp2 >>= 32; } if (temp != 0 || temp2 != 0) { s[len2] = temp; @@ -419,21 +429,33 @@ void bn_inverse(bignum256 *x, const bignum256 *prime) if (u[len1 - 1] == 0 && v[len1 - 1] == 0) len1--; k++; } + + j = r[0] >> 30; + r[0] = r[0] & 0x3FFFFFFFu; + for (i = 1; i < len2; i++) { + uint32_t q = r[i] >> (30 - 2 * i); + r[i] = ((r[i] << (2 * i)) & 0x3FFFFFFFu) + j; + j=q; + } + r[i] = j; + i++; + for (; i < 9; i++) r[i] = 0; + i = 8; while (i > 0 && r[i] == prime->val[i]) i--; if (r[i] >= prime->val[i]) { - temp = 1; + temp32 = 1; for (i = 0; i < 9; i++) { - temp += 0x3FFFFFFF + r[i] - prime->val[i]; - r[i] = temp & 0x3FFFFFFF; - temp >>= 30; + temp32 += 0x3FFFFFFF + r[i] - prime->val[i]; + r[i] = temp32 & 0x3FFFFFFF; + temp32 >>= 30; } } - temp = 1; + temp32 = 1; for (i = 0; i < 9; i++) { - temp += 0x3FFFFFFF + prime->val[i] - r[i]; - r[i] = temp & 0x3FFFFFFF; - temp >>= 30; + temp32 += 0x3FFFFFFF + prime->val[i] - r[i]; + r[i] = temp32 & 0x3FFFFFFF; + temp32 >>= 30; } int done = 0; #if USE_PRECOMPUTED_IV @@ -449,14 +471,14 @@ void bn_inverse(bignum256 *x, const bignum256 *prime) if (!done) { for (j = 0; j < k; j++) { if (r[0] & 1) { - temp = r[0] + prime->val[0]; - r[0] = (temp >> 1) & 0x1FFFFFFF; - temp >>= 30; + temp32 = r[0] + prime->val[0]; + r[0] = (temp32 >> 1) & 0x1FFFFFFF; + temp32 >>= 30; for (i = 1; i < 9; i++) { - temp += r[i] + prime->val[i]; - r[i - 1] += (temp & 1) << 29; - r[i] = (temp >> 1) & 0x1FFFFFFF; - temp >>= 30; + temp32 += r[i] + prime->val[i]; + r[i - 1] += (temp32 & 1) << 29; + r[i] = (temp32 >> 1) & 0x1FFFFFFF; + temp32 >>= 30; } } else { for (i = 0; i < 8; i++) { diff --git a/ecdsa.c b/ecdsa.c index 499356c1e..e8d5cdad2 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -123,38 +123,39 @@ void point_multiply(const bignum256 *k, const curve_point *p, curve_point *res) // res = k * G void scalar_multiply(const bignum256 *k, curve_point *res) { - int i, j; + int i; // result is zero int is_zero = 1; -#if USE_PRECOMPUTED_CP - int exp = 0; -#else curve_point curr; // initial res memcpy(&curr, &G256k1, sizeof(curve_point)); -#endif - for (i = 0; i < 9; i++) { - for (j = 0; j < 30; j++) { - if (i == 8 && (k->val[i] >> j) == 0) break; - if (k->val[i] & (1u << j)) { - if (is_zero) { + for (i = 0; i < 256; i++) { + if (k->val[i / 30] & (1u << (i % 30))) { + if (is_zero) { #if USE_PRECOMPUTED_CP - memcpy(res, secp256k1_cp + exp, sizeof(curve_point)); + if (i < 255 && (k->val[(i + 1) / 30] & (1u << ((i + 1) % 30)))) { + memcpy(res, secp256k1_cp2 + i, sizeof(curve_point)); + i++; + } else { + memcpy(res, secp256k1_cp + i, sizeof(curve_point)); + } #else - memcpy(res, &curr, sizeof(curve_point)); + memcpy(res, &curr, sizeof(curve_point)); #endif - is_zero = 0; - } else { + is_zero = 0; + } else { #if USE_PRECOMPUTED_CP - point_add(secp256k1_cp + exp, res); + if (i < 255 && (k->val[(i + 1) / 30] & (1u << ((i + 1) % 30)))) { + point_add(secp256k1_cp2 + i, res); + i++; + } else { + point_add(secp256k1_cp + i, res); + } #else - point_add(&curr, res); + point_add(&curr, res); #endif - } } -#if USE_PRECOMPUTED_CP - exp++; -#else +#if ! USE_PRECOMPUTED_CP point_double(&curr); #endif } diff --git a/secp256k1.c b/secp256k1.c index b941937d2..40aa97281 100644 --- a/secp256k1.c +++ b/secp256k1.c @@ -815,4 +815,517 @@ const curve_point secp256k1_cp[256] = { {/*.x =*/{/*.val =*/{0x3f8be384, 0x22f4c810, 0x31db6c3e, 0x3b02ab68, 0x1ef07271, 0x2b5b253f, 0x23e1b251, 0x24290af9, 0xb237}}, /*.y =*/{/*.val =*/{0x2b19880e, 0x4291cf7, 0x9ecb58d, 0x3c013d05, 0x1f94517, 0x143e22aa, 0x15edbe8d, 0x1a524675, 0xfc6b}}}, }; + +const curve_point secp256k1_cp2[255] = { +{/*.x =*/{/*.val =*/{0x3ce036f9, 0x1807c44e, 0x36f99b08, 0xc721160, 0x1d5229b5, 0x113e17e2, 0xc310493, 0x22806496, 0xf930}}, + /*.y =*/{/*.val =*/{0x4b8e672, 0x32e7f5d6, 0xc2231b6, 0x2a664d, 0x37f35665, 0xcdf98a8, 0x1e8140fe, 0x1ec3d8cb, 0x388f}}}, +{/*.x =*/{/*.val =*/{0x20297556, 0x3c15e851, 0x168a18b2, 0x3d91cbe1, 0x1235d382, 0x14e850d5, 0x2eea4204, 0x1ef55d57, 0xfff9}}, + /*.y =*/{/*.val =*/{0x3075f297, 0x321c30da, 0x18fe4a03, 0x203c3d94, 0x5c560de, 0x3a5805fd, 0x3b620f3b, 0x1ddeab3e, 0xae12}}}, +{/*.x =*/{/*.val =*/{0x30afe85a, 0x16c3d1c1, 0x220095bc, 0x1f3d1065, 0x33463368, 0xe3c0135, 0x3561b15c, 0x5755239, 0xd011}}, + /*.y =*/{/*.val =*/{0x34062327, 0x2c146c4f, 0x1a86d526, 0x8e31776, 0x3bd81579, 0x1914df85, 0x1e0d7a8b, 0x13ff7205, 0xa9f3}}}, +{/*.x =*/{/*.val =*/{0x3202e6ce, 0x140af6a2, 0x162b7940, 0xc8550e7, 0x3a8b0968, 0x2724586, 0x133d48ac, 0x310d504f, 0xfe72}}, + /*.y =*/{/*.val =*/{0xf58c5bf, 0x1e3b4bef, 0x34a9d229, 0x372238da, 0x32998101, 0x2d1f8275, 0x24a68d3a, 0x37819ffc, 0x6851}}}, +{/*.x =*/{/*.val =*/{0x1118e5c3, 0x2f61c2a8, 0x12bebc19, 0x15e6c9d1, 0x265b4bfc, 0x595bbd3, 0x1307db44, 0xcd76591, 0x6eca}}, + /*.y =*/{/*.val =*/{0x5a08668, 0x2628bde0, 0x3f8ec344, 0x125a8e8e, 0x3875a03a, 0x3d5e41d2, 0x20710592, 0x8ed5e9e, 0xd501}}}, +{/*.x =*/{/*.val =*/{0x3f8cb0e3, 0xe4ceb29, 0x1efe3a44, 0xbad4ff8, 0x2eb72ea2, 0x1938112c, 0x16d8f8fa, 0x20395d11, 0x3f0e}}, + /*.y =*/{/*.val =*/{0x2a5f404f, 0x2c0a278b, 0x25b53a4c, 0x494ea9, 0x1d01b395, 0x2e702121, 0xbc91e90, 0x35f5ca5b, 0xcb66}}}, +{/*.x =*/{/*.val =*/{0x33ce1752, 0x1edd43dc, 0x3cd204ec, 0x20f1e5f5, 0x1c9aeae7, 0x377d9366, 0x1c635812, 0x36963407, 0xd7a0}}, + /*.y =*/{/*.val =*/{0x762cef4, 0x2f009ce0, 0x62b742b, 0x38102a30, 0x2284650b, 0xa4a0d03, 0x8032f6f, 0x1c381a00, 0x9127}}}, +{/*.x =*/{/*.val =*/{0x35476085, 0x2422dc06, 0x2eb9f84a, 0x1c539de5, 0xed1afb5, 0xeab5a9e, 0xcd3e10d, 0x29c19e82, 0x3443}}, + /*.y =*/{/*.val =*/{0xb8f52d8, 0x34d212f6, 0xc2b67f6, 0x2292c9f4, 0x3e1da901, 0x3a312e31, 0x36f854f6, 0x1e97e0a6, 0x661a}}}, +{/*.x =*/{/*.val =*/{0x257e8dfa, 0x33f032e7, 0x3c7e184f, 0x20246468, 0x298ca009, 0x28c3e2b2, 0x19c4c0d9, 0x33cbfc1e, 0x8262}}, + /*.y =*/{/*.val =*/{0x3bac376a, 0x173fe363, 0x314c4783, 0x2dbb4cca, 0x334f3457, 0x3b88bb16, 0x9e4e66f, 0x25788244, 0x83fd}}}, +{/*.x =*/{/*.val =*/{0x3c70620c, 0x5f307c9, 0x3c288d9d, 0x26312faa, 0x27178049, 0x374c68ad, 0x236dc60, 0x2a29234b, 0x1653}}, + /*.y =*/{/*.val =*/{0x315b32cd, 0x328ba074, 0x3d3dc526, 0xabdd237, 0x3a701c01, 0x2a651d3b, 0x37f7aeaf, 0xa424d6b, 0x338}}}, +{/*.x =*/{/*.val =*/{0x271dabcd, 0x1f50ae9b, 0x1e5cb4f4, 0x34ff9262, 0x35373f54, 0x22b8c982, 0x3f43c609, 0x393edad8, 0xd49e}}, + /*.y =*/{/*.val =*/{0x16603c2, 0x19aa433c, 0x2ff7031e, 0x271424c4, 0x1bf35612, 0x21fa9e98, 0x1490dd7c, 0x38e48269, 0x531}}}, +{/*.x =*/{/*.val =*/{0xc8c828a, 0xfcc2ae4, 0x16ae41f5, 0xbac90b2, 0x281c7513, 0x1283605f, 0x9e750e4, 0x21472905, 0x5f94}}, + /*.y =*/{/*.val =*/{0x37344d80, 0x3fac28fc, 0x3c68b04b, 0x19b7dd53, 0x2f35e8c, 0x1e5f622, 0x1fee8e5f, 0x30ee2be8, 0x26b8}}}, +{/*.x =*/{/*.val =*/{0x5041216, 0x16dfe3c7, 0x2b836a6, 0x1ccd7da1, 0x2fed523f, 0x2d67bf70, 0x3acf4128, 0xc5ec87d, 0xda75}}, + /*.y =*/{/*.val =*/{0x2e708572, 0x2bb4ca61, 0x37acedad, 0x2ab01eb9, 0x2d7fc6e9, 0x27886cd0, 0x2d5f0df1, 0x2811afdc, 0x73f8}}}, +{/*.x =*/{/*.val =*/{0x3c62bac0, 0x1414c93c, 0x1f0ab069, 0x54377d4, 0x28b70e19, 0x12df4b0f, 0x3469c136, 0x3c3e408f, 0x9530}}, + /*.y =*/{/*.val =*/{0x3618e309, 0x1e2af6a5, 0x31fdc684, 0x16cca14b, 0x3333e0e2, 0x34bdfd66, 0x321e234d, 0xc16a3e7, 0x8f3c}}}, +{/*.x =*/{/*.val =*/{0x1c3c9c8f, 0x19c10e17, 0x24367b20, 0x205bfb8f, 0x2332b0f2, 0x27fd0eaa, 0x298fd6f0, 0xb72f90, 0x67be}}, + /*.y =*/{/*.val =*/{0x193652d9, 0x14e12661, 0x388c2be5, 0x264efd82, 0x291693cd, 0x2516d820, 0x1ef84a2c, 0x1569cf93, 0x7a9b}}}, +{/*.x =*/{/*.val =*/{0x10aaa33a, 0x7e6f2f8, 0x17b9ca51, 0x24b74a70, 0x1718368c, 0x1a404ef1, 0x3876adf5, 0x924bd3b, 0x893b}}, + /*.y =*/{/*.val =*/{0x11af3445, 0x1ee02e2b, 0x3ceeb426, 0xe7a2884, 0x107f32a4, 0xe801d99, 0x1c89ef41, 0x14ad9cb4, 0xcdb1}}}, +{/*.x =*/{/*.val =*/{0x36e55dc8, 0x2e24485b, 0x2ca04394, 0x3e56adba, 0x1094426f, 0x12910301, 0x1ffb2ba8, 0x1011e431, 0x4431}}, + /*.y =*/{/*.val =*/{0x1be323b3, 0x76512bb, 0x2aa2e503, 0x1a8a6de7, 0x2fed7a6, 0x260dfd59, 0x366f8fe9, 0x3050b994, 0x96b0}}}, +{/*.x =*/{/*.val =*/{0x33f0e9aa, 0x3ad78658, 0x11bd34b3, 0x449ddac, 0x138d268, 0x92b8356, 0x326adb79, 0x3fa15d7, 0xe538}}, + /*.y =*/{/*.val =*/{0x82720f, 0x12e904d9, 0x68318ec, 0x2e53977d, 0xc8e016f, 0x244d8e49, 0x3b41d5b6, 0x361ce421, 0xb97f}}}, +{/*.x =*/{/*.val =*/{0x2ebc61d6, 0x2bb4d86f, 0x1ff42de1, 0x23f4e9f6, 0x2b1f518a, 0x17c34575, 0x19af0c39, 0x3cf928fb, 0x939f}}, + /*.y =*/{/*.val =*/{0x23f5cb70, 0x1d7a919a, 0x38c7f82e, 0x2fc9bad, 0x16c0498, 0x1bf13bbc, 0x3a90e9d4, 0xef3c22d, 0xdeab}}}, +{/*.x =*/{/*.val =*/{0x497e0df, 0x5b84d37, 0xf76f530, 0xeed0dbb, 0x2029a04c, 0x161e17f9, 0x3293078, 0xf94ab8e, 0xfdc6}}, + /*.y =*/{/*.val =*/{0x1b9eb19f, 0x1811127, 0x335d9d5f, 0x2fac8bef, 0x22e8b87b, 0x3dc50a2b, 0x3bb52e3d, 0x2b59eb3a, 0x292d}}}, +{/*.x =*/{/*.val =*/{0x355812dd, 0x28a960b, 0x12d30e2a, 0x1119c8d5, 0x18f78e3d, 0x2afb5b01, 0x3352f0b6, 0x2f5ea4bf, 0x7029}}, + /*.y =*/{/*.val =*/{0x1a2d2927, 0x87319ac, 0x3b2c73c7, 0x36ba1090, 0x683ac47, 0x19512b8c, 0xb3d27dd, 0x3eb6bf7a, 0xb0ee}}}, +{/*.x =*/{/*.val =*/{0x3181fdc2, 0x336affe6, 0xc62364d, 0xbd8aed7, 0x234e7edd, 0x992e062, 0x26e474aa, 0x40abd1f, 0xf42c}}, + /*.y =*/{/*.val =*/{0x2485d7fd, 0x7c0024e, 0x22acf268, 0x5540b66, 0x2fe22a4c, 0x2b4172e1, 0x2806c78f, 0xead1b3f, 0x5750}}}, +{/*.x =*/{/*.val =*/{0x2edd7dd6, 0x219b51f7, 0x1e1968c3, 0xddbf899, 0x3cfdec49, 0x29e103b9, 0x3524bca5, 0x33da8931, 0x32cf}}, + /*.y =*/{/*.val =*/{0x3e08e330, 0x17f512bb, 0x349a08b2, 0x3633480, 0x1f561e7a, 0x2025a902, 0x27748620, 0x1a8d25da, 0x2184}}}, +{/*.x =*/{/*.val =*/{0x21231d11, 0x399d20c4, 0x2aaad7c, 0x2acdb18f, 0x37c39822, 0x455731d, 0x388e433d, 0x3507a2e4, 0x3514}}, + /*.y =*/{/*.val =*/{0x23855df5, 0xf5bed03, 0x2f79ebe5, 0x213cc742, 0x39eff93, 0x1344795a, 0x17eb8ef4, 0xc940580, 0x89a8}}}, +{/*.x =*/{/*.val =*/{0x633cb1, 0x159f827a, 0x1d021132, 0x168892da, 0x181fcb57, 0x189cc848, 0x2cad400c, 0x273cc5ea, 0x6dde}}, + /*.y =*/{/*.val =*/{0x27ce6b34, 0x1f7526a9, 0x3859ef35, 0x2c9ff6b3, 0x3a66a880, 0x27be1a86, 0x3e41d5c9, 0x3ef9e9c1, 0x9188}}}, +{/*.x =*/{/*.val =*/{0x4e5467d, 0x342f5da9, 0x1bbface4, 0x2422ae06, 0x970e940, 0x7d8b83b, 0x1a1222c2, 0x193c3f1a, 0x97d0}}, + /*.y =*/{/*.val =*/{0x1e9cb3fa, 0x25cc03f4, 0xf17ccd7, 0x17ecee15, 0x10861fda, 0x1f19bea1, 0x2cc03f, 0x13cbb4cd, 0x8997}}}, +{/*.x =*/{/*.val =*/{0x13613bec, 0x32a072e4, 0x1cfe67c, 0x2d7f2744, 0xf972a8b, 0x6ccf71d, 0x137bdedf, 0x32ae324e, 0x2dcf}}, + /*.y =*/{/*.val =*/{0x1a039215, 0x39cc2492, 0x33f5f383, 0xcb3eeb4, 0x36c6f437, 0x222df5b, 0xa41265f, 0x3137651d, 0x46db}}}, +{/*.x =*/{/*.val =*/{0x7fb9e1a, 0x1f345c21, 0x22a32961, 0x39d2dd37, 0x2b0e767f, 0xaf26ee, 0x2c5a8f1a, 0x1052a923, 0x1bec}}, + /*.y =*/{/*.val =*/{0x349c0443, 0x1fdb845d, 0xc9796e5, 0x4e176ba, 0x54b0f68, 0x26f15cc3, 0x266678a7, 0x19c11c04, 0xe358}}}, +{/*.x =*/{/*.val =*/{0x3b7ceceb, 0xfd9e3fe, 0x97faf0f, 0x2967e4e2, 0x2e681473, 0x3ee049bd, 0x2d45036f, 0x2188109d, 0x437a}}, + /*.y =*/{/*.val =*/{0x16c181e1, 0xd8ef30d, 0x8f97827, 0x883f3f7, 0x1297ff87, 0x23fada67, 0x2c32f69b, 0x1ae84fba, 0xb91}}}, +{/*.x =*/{/*.val =*/{0x1cbf00eb, 0x3276761f, 0x18d02274, 0x2d3a62f0, 0x230bc241, 0x385bda86, 0x2d4dc49b, 0x1c2ba5ba, 0xb890}}, + /*.y =*/{/*.val =*/{0x1b0e664e, 0x2dfc6f34, 0x2b96a671, 0x362c1ad, 0x4a766cb, 0xa539307, 0x2d88f472, 0x3230b228, 0x6f24}}}, +{/*.x =*/{/*.val =*/{0x36fbe7b2, 0x275bfe6a, 0x18d65a3b, 0x2b7b7051, 0x2884605e, 0x1aeec6ca, 0x41f8f33, 0x21d9a72d, 0x2648}}, + /*.y =*/{/*.val =*/{0x21bc2a34, 0xca9e2f0, 0x20eb6039, 0xe36605a, 0x2ddf1856, 0x3cb72b40, 0x144988f2, 0x36ad2c80, 0x9e15}}}, +{/*.x =*/{/*.val =*/{0x2b038315, 0x1a434c18, 0x1310e6f9, 0x2b310cda, 0x14b8629c, 0x1a038e5e, 0x312221e4, 0x15a1d59d, 0xaba5}}, + /*.y =*/{/*.val =*/{0x2e25fc0a, 0x26800fe6, 0xb63338f, 0x2fed4cb6, 0x130d6f3f, 0x15c3d894, 0x25edb63d, 0x1761ea8d, 0xa0e7}}}, +{/*.x =*/{/*.val =*/{0x15bc15b4, 0x32e684d2, 0x25a2ee69, 0x1d40a391, 0x17ca8d92, 0x163ba73b, 0x2adc9ed8, 0x38b947b, 0x10e9}}, + /*.y =*/{/*.val =*/{0x18aa258d, 0x13af9825, 0x2bb6a883, 0x296258c0, 0x2d1f754c, 0x1ea3185a, 0x1e0424d5, 0xdc0e035, 0xc68a}}}, +{/*.x =*/{/*.val =*/{0x3a1c0a80, 0x3d8aaf21, 0x25a9c740, 0x18945631, 0x2ff9c34d, 0x326f9c00, 0xcca5b17, 0x169a2985, 0xb6b1}}, + /*.y =*/{/*.val =*/{0x1ce0a03, 0x1b340441, 0x2e16eeb, 0x2684acc2, 0x2536d49c, 0x3888fbbd, 0x1b61ea54, 0xb8535b3, 0xfae6}}}, +{/*.x =*/{/*.val =*/{0x12b062d4, 0x1f2a942a, 0x3b6a141a, 0x1739f966, 0x2a227a7a, 0x2c5c4a0f, 0x2eaca06f, 0xfa90c95, 0x3596}}, + /*.y =*/{/*.val =*/{0x3bb25302, 0x42a9346, 0xde59b1a, 0x1020ae59, 0x8a96d0, 0x33865be7, 0x1e5c9bfc, 0x38515254, 0xf65b}}}, +{/*.x =*/{/*.val =*/{0x1d33fd27, 0x282fd714, 0x246cc62f, 0x17d5cf6d, 0x2361b44, 0x8e23b6a, 0x3e84cd02, 0xfc24898, 0x9ed7}}, + /*.y =*/{/*.val =*/{0x2716c458, 0x25cacb78, 0x2e449345, 0x2a08f96c, 0x6725494, 0x16d3cd09, 0x1eeeaee7, 0x2259faec, 0xb631}}}, +{/*.x =*/{/*.val =*/{0x2f028d83, 0x1e588ebb, 0x27439615, 0x25649b6e, 0x1e69db61, 0x2af96857, 0x385ec6a5, 0x3df138f1, 0xa7eb}}, + /*.y =*/{/*.val =*/{0x19d0bed1, 0x1900e4ae, 0x30539199, 0x28e249d2, 0x4804b47, 0x271cddc1, 0x362d5cfd, 0x54beff8, 0x6205}}}, +{/*.x =*/{/*.val =*/{0x3bb61ee5, 0xa21104d, 0x31f0c13f, 0x13c138be, 0x34ae6eda, 0x18e33625, 0x321b8662, 0xc8c3321, 0xd493}}, + /*.y =*/{/*.val =*/{0x25d694a8, 0x18b69343, 0x2438ddc6, 0x344b2316, 0xafb5e1a, 0x317a747b, 0x29d23edc, 0x26afd46, 0x21c}}}, +{/*.x =*/{/*.val =*/{0x2c04554a, 0xc3772f3, 0x288cffe5, 0x373feed1, 0x10a2ecaa, 0x194b09e8, 0x3d1a0474, 0xdf2261c, 0x896f}}, + /*.y =*/{/*.val =*/{0x129138df, 0x1a3e7f86, 0xc417dcd, 0x216d86b, 0x11bf1e6, 0x8aec13a, 0x2c4acda6, 0x8f9c892, 0x3804}}}, +{/*.x =*/{/*.val =*/{0x343fca26, 0x101df46a, 0x3bc23678, 0x3ee10768, 0x3578a27d, 0x308276fc, 0x36d6cca6, 0x2e5fddd2, 0x11b3}}, + /*.y =*/{/*.val =*/{0x1b679d58, 0xec9fabd, 0x39f9d42d, 0x2b88c712, 0x36d3bb3b, 0x159430bc, 0xc508cd, 0x7e7eb98, 0x6533}}}, +{/*.x =*/{/*.val =*/{0x8dfd587, 0x1e4d86ed, 0x1b026560, 0x312e8e32, 0x35a12d5e, 0x19eaa8b3, 0x508b348, 0x2d06eb3d, 0x5084}}, + /*.y =*/{/*.val =*/{0x11470e89, 0x39e7a5fe, 0x91f5606, 0x2dbd581a, 0x2927475d, 0x2a9b2154, 0xd31619, 0x18c68766, 0x34a9}}}, +{/*.x =*/{/*.val =*/{0x2c953fa9, 0x341655b5, 0xb8c3db4, 0x2ac98a7c, 0x118c0628, 0x3d21752f, 0x393233a5, 0x3443aaaa, 0xa49e}}, + /*.y =*/{/*.val =*/{0x6fb4c72, 0x1ecaf489, 0x28e181b6, 0x3a1d4d25, 0x1fddfb5a, 0x11db0283, 0x35398e03, 0x2e251983, 0xcc72}}}, +{/*.x =*/{/*.val =*/{0x27a1d916, 0x3025b4ff, 0x11f1f3a3, 0x16c28e57, 0x1bb07031, 0x18562997, 0x19d0cbac, 0x3e6b2db5, 0x650e}}, + /*.y =*/{/*.val =*/{0x3068387b, 0x16127299, 0x36c26ba8, 0x2ed18229, 0x1b82c558, 0x2702e49e, 0x2b11870e, 0x47c8458, 0x85d}}}, +{/*.x =*/{/*.val =*/{0x36fb2940, 0x37f07501, 0x2534042f, 0x7f01a6c, 0x2b8fbd71, 0x1d04e10a, 0x1c82fecb, 0x283bf680, 0x5083}}, + /*.y =*/{/*.val =*/{0x36ceee44, 0x378c0ed9, 0x2cdddf3b, 0x1a849b87, 0xdf19b08, 0x3ef7e189, 0x782bba8, 0x2bbe3ff9, 0xf064}}}, +{/*.x =*/{/*.val =*/{0x15bc8a44, 0x3bf74194, 0x3e151a19, 0x10405df2, 0x1a5fc768, 0x159692e9, 0xeda3d38, 0x20160f3f, 0x4d01}}, + /*.y =*/{/*.val =*/{0x1adbc09e, 0x3c7e5324, 0x182da362, 0x250811a1, 0x16381396, 0x26ea001f, 0xf5d367e, 0x31b0632d, 0x3a33}}}, +{/*.x =*/{/*.val =*/{0x135b4eb8, 0x14884f92, 0x38b5a3cf, 0x3d55fc6a, 0x2f2dce07, 0x3d528f32, 0x32256f0f, 0x1a390eb7, 0xc119}}, + /*.y =*/{/*.val =*/{0x2f911add, 0x11265b5, 0x2a7149b7, 0x3e2d2504, 0x366f8242, 0x27607f99, 0x2458f837, 0x39a4dde1, 0xbff5}}}, +{/*.x =*/{/*.val =*/{0x19dffc96, 0x256e8425, 0x3ac58572, 0xa33696b, 0x17eb0192, 0x26ce5720, 0x3deaf6f, 0x1b2fb852, 0x161c}}, + /*.y =*/{/*.val =*/{0x1b492de4, 0x24ef3d84, 0x2af8621c, 0x258d324b, 0x3183059b, 0x964e472, 0x1ff985bd, 0x32a4a9ae, 0x8a26}}}, +{/*.x =*/{/*.val =*/{0x369671d5, 0x35f9c967, 0x14eb83e3, 0xbbabd6d, 0x2bc96056, 0x7906af5, 0x39596d76, 0x3b1580f3, 0xa8c1}}, + /*.y =*/{/*.val =*/{0x333db746, 0xf22a034, 0x18f8b182, 0x2997eccc, 0x141c5924, 0x31cc9a4, 0x345ac755, 0x181447a7, 0x5fc3}}}, +{/*.x =*/{/*.val =*/{0x8a2050e, 0x6b10bf9, 0x15f8a677, 0xbbd55d8, 0x79b8974, 0x1da731b9, 0x731896b, 0x93f492f, 0x6737}}, + /*.y =*/{/*.val =*/{0x61d3d70, 0x24326924, 0x3349cc2b, 0x1aeb3f50, 0x86b6dbe, 0x120b026a, 0x24a20203, 0x2095e25a, 0xe4cf}}}, +{/*.x =*/{/*.val =*/{0x29a78179, 0x133d807e, 0x20d6afe3, 0x143a4149, 0x9ed9f6b, 0x291ccd88, 0x1b8dc905, 0x29fcdc20, 0x995c}}, + /*.y =*/{/*.val =*/{0x2fec1f47, 0xc7eed32, 0x2b64e529, 0x332155a6, 0x12863abb, 0xd362012, 0x3573ab5e, 0x167a5554, 0xd9a0}}}, +{/*.x =*/{/*.val =*/{0x49135d3, 0xf636176, 0x2e431fc1, 0x80f3404, 0x30b16a74, 0x4d0a504, 0x2a85a65c, 0x2f1fbe0, 0x594}}, + /*.y =*/{/*.val =*/{0x162255d2, 0xb5d146, 0x1902391d, 0xa18ca32, 0x36687af1, 0x16c31eaa, 0x3ab612f7, 0x1e617ad3, 0x9053}}}, +{/*.x =*/{/*.val =*/{0x39e68f51, 0x3de3a89e, 0x16b6e1d0, 0x1b87f2ae, 0xd870cf5, 0x301895ca, 0x26fcb74d, 0x116b276e, 0xc755}}, + /*.y =*/{/*.val =*/{0x38cfbbc1, 0x7120e25, 0x22ddf68d, 0x7246272, 0x168bf725, 0x163b6ca8, 0x855c2a7, 0xf11a8ef, 0x7c80}}}, +{/*.x =*/{/*.val =*/{0x41ead4b, 0x3fa21e68, 0x11b03c1f, 0x1d7b7eda, 0x3e76be3a, 0x11cd3beb, 0x3337ec71, 0x3032323, 0xbfc9}}, + /*.y =*/{/*.val =*/{0x6fedaed, 0x114b1bc2, 0x2e0ae3e7, 0x11a3bfcc, 0x42d36fb, 0x29c63754, 0xded24db, 0x206c7827, 0x7a94}}}, +{/*.x =*/{/*.val =*/{0x25b7ad0d, 0x253215bb, 0x1d0d1d36, 0x3b9d9f2a, 0x116c4476, 0x362925b, 0x1e00dc2d, 0x1a436aed, 0x3a55}}, + /*.y =*/{/*.val =*/{0x32e8c407, 0x1b261e42, 0x2c31218d, 0x32b2e2b2, 0x2f99f301, 0x7eeb25f, 0x657bfb2, 0x23865d68, 0xc3e2}}}, +{/*.x =*/{/*.val =*/{0x19b2df82, 0x9e91ec2, 0x3104fb19, 0x179e8591, 0x232c04ec, 0xb463b33, 0x3b92ccc9, 0x191718af, 0x405a}}, + /*.y =*/{/*.val =*/{0x9307dbf, 0x368a0d28, 0x2dc462b5, 0x3ea76cb3, 0x37e7122f, 0x2b298788, 0x196e0f5c, 0x2d053d13, 0xbc3c}}}, +{/*.x =*/{/*.val =*/{0x18f4033f, 0x9f0f311, 0x20ab6d3a, 0x12b3c96c, 0x28f817cc, 0x2c835e83, 0x3cfb3d2a, 0x51ad0e6, 0x10ba}}, + /*.y =*/{/*.val =*/{0x76d1fbf, 0x173dae53, 0x1c78b4ea, 0x6dacdfa, 0x129f3677, 0x283c19a8, 0xaef4b2a, 0x19b9747, 0xade1}}}, +{/*.x =*/{/*.val =*/{0x36e2d9b3, 0x12f4c1aa, 0x338d6351, 0x36e4a0c6, 0xf845641, 0xba984e7, 0x305e75e1, 0x53ce5f1, 0x19a3}}, + /*.y =*/{/*.val =*/{0xbaaaf33, 0x154bb897, 0x4be56d, 0x874749, 0x3528b3a5, 0x2597e21f, 0x328dd234, 0x363d76b1, 0x6cac}}}, +{/*.x =*/{/*.val =*/{0x23a52264, 0xb9cdf65, 0x1400b375, 0x2b7f00c5, 0x251cffd0, 0x1b8aa6ab, 0x7fe9a80, 0x37037a06, 0x85ff}}, + /*.y =*/{/*.val =*/{0x2da2082, 0x231f4a6a, 0x3179d049, 0x2060b24a, 0x14706c67, 0x15a3d415, 0x2948d0be, 0xc061eb8, 0x3fee}}}, +{/*.x =*/{/*.val =*/{0x36a88c9c, 0x307fd692, 0x149df069, 0x1eda198c, 0x2caa2aa3, 0x766b25c, 0x391398b2, 0x24207951, 0x7865}}, + /*.y =*/{/*.val =*/{0x35a7d19b, 0x38164d15, 0x3ab6a155, 0x33e466c0, 0x28196112, 0x23e9c897, 0x30d2b69e, 0xc1de4a8, 0x59a2}}}, +{/*.x =*/{/*.val =*/{0x1e8f7605, 0x374b71e3, 0x3ed2d35b, 0x13bde7d7, 0xff48bd4, 0x2ce44ba2, 0x159def16, 0x1100533a, 0x21ce}}, + /*.y =*/{/*.val =*/{0x955155f, 0xd791446, 0x46602c1, 0x38cd259a, 0x1da46ef4, 0x1bf5987c, 0xfaf75d9, 0x19c08e8b, 0x323a}}}, +{/*.x =*/{/*.val =*/{0x121ce204, 0x13b5d7a3, 0x26763d52, 0x29c96390, 0x26f72fb2, 0x1d361672, 0x3c64fb83, 0x107458ac, 0x43ca}}, + /*.y =*/{/*.val =*/{0x134a8f6b, 0x1494113a, 0x2a4a468e, 0x2db1eccf, 0x1ba31f9a, 0x143e4863, 0x23fa1c6, 0x16a0b8dc, 0xdcea}}}, +{/*.x =*/{/*.val =*/{0x14978583, 0x2ce90c80, 0x61613f5, 0x35ba6bbc, 0x392214cd, 0x21066643, 0x23137497, 0x3e26e73c, 0x30ab}}, + /*.y =*/{/*.val =*/{0x1dc75777, 0x118600d4, 0x3b584ac4, 0x483a88e, 0x21ab8063, 0x1ed3cb43, 0x37498cdf, 0x144551df, 0x4b03}}}, +{/*.x =*/{/*.val =*/{0x2c288015, 0x268df98f, 0x2dc99cc3, 0x1cfe14fb, 0x1b6aa646, 0x3eb18681, 0x2de6f681, 0x13aab64d, 0xaa01}}, + /*.y =*/{/*.val =*/{0x6c1006f, 0x3e053999, 0x3cecad9d, 0x12e6c1d0, 0x3b0f63ef, 0xa9f90fd, 0x2be9ac3f, 0x4f0118d, 0x3de9}}}, +{/*.x =*/{/*.val =*/{0x185bfe2, 0x34231245, 0xe5e42d3, 0x37e8ab9e, 0x2679cb5e, 0x2a82a0b3, 0xa0b0b56, 0x576fcdf, 0xe526}}, + /*.y =*/{/*.val =*/{0x2a0e5888, 0x33c042f, 0x245a9c44, 0x1dbfcb72, 0x32c1a284, 0x7e54a27, 0x488520f, 0xcd459b4, 0x5403}}}, +{/*.x =*/{/*.val =*/{0x59ab499, 0x2f674fc8, 0x273c330a, 0x4ca671b, 0x3f01bc0b, 0x65acf19, 0x5ba5d2, 0x2bfcc057, 0x78ba}}, + /*.y =*/{/*.val =*/{0x3ee097fd, 0x20748c63, 0x11251996, 0x18cbbba3, 0x2082e91, 0x2a1383b6, 0x2c0afafc, 0x3736f6c1, 0xad4b}}}, +{/*.x =*/{/*.val =*/{0x25cd5379, 0xc18ccc2, 0x70bcadc, 0x2de50e16, 0x24d2232d, 0x9206e2a, 0x11382a78, 0x1cb55af7, 0x17c0}}, + /*.y =*/{/*.val =*/{0x3108cd25, 0x1f2b8146, 0x25bad0df, 0x166b1d89, 0x1d034f89, 0x30491ebc, 0x1a064e77, 0x2f7d0a0f, 0xd901}}}, +{/*.x =*/{/*.val =*/{0xa2d8dae, 0x1e4f0063, 0x3d25ea95, 0xca97e47, 0x32256eac, 0x2c97be72, 0x192f9ba6, 0x7009884, 0x8827}}, + /*.y =*/{/*.val =*/{0x3e1e77d9, 0x2d09b03c, 0x317d099f, 0x21db71, 0x2bf5acc3, 0x322ceb96, 0x176aa401, 0x3754d41c, 0xd719}}}, +{/*.x =*/{/*.val =*/{0x1ee503a6, 0x2543ebf4, 0x124e1fba, 0x7a1493c, 0x2ec5ab43, 0x2a0c4661, 0x24a29aa6, 0x1fa04b8f, 0xceb6}}, + /*.y =*/{/*.val =*/{0xe98c4d1, 0x3ff50365, 0x269e2f31, 0x225b657b, 0x1cd86b4b, 0xf7de042, 0x10613b82, 0x21516b0e, 0x5e6a}}}, +{/*.x =*/{/*.val =*/{0x3ba9000, 0x37c1c8ea, 0x25e8b6f, 0x21cbe71a, 0x143dc4, 0x21d81d61, 0x1d8c1684, 0x1d3e7ffc, 0xac38}}, + /*.y =*/{/*.val =*/{0x2f10cf0a, 0x368f1f65, 0x366e9fa4, 0x178d435f, 0x117f9308, 0xb77a250, 0x1c069b86, 0x3a48c228, 0xaa65}}}, +{/*.x =*/{/*.val =*/{0x17ba402e, 0x39758c2c, 0x1042989a, 0x2e06970b, 0x8e3c3c3, 0x3ab43121, 0x3a02a58b, 0x6d73463, 0x8e89}}, + /*.y =*/{/*.val =*/{0x4fad9e0, 0x386d89e7, 0x157a7ee8, 0x19430908, 0x32a306af, 0x23439013, 0x2c6680b3, 0x3839aa7, 0xe5d3}}}, +{/*.x =*/{/*.val =*/{0x136bcfe8, 0x187b5879, 0x29b7bb3e, 0x305e7b5, 0x2b319a0e, 0x32a3c8c1, 0x2999b472, 0x3e2f0731, 0x1332}}, + /*.y =*/{/*.val =*/{0x1ae78402, 0x6c374b3, 0x1a8c2145, 0x24ed0935, 0x1c0681ba, 0x19f114d7, 0x2ed713f, 0x31fb8a58, 0xc39d}}}, +{/*.x =*/{/*.val =*/{0x2fddec6, 0x3fffb0cd, 0x111222c7, 0xb00f7df, 0x3f461492, 0x3678cde4, 0x220b4e9c, 0x7fead4f, 0x9f13}}, + /*.y =*/{/*.val =*/{0x9df8052, 0x3855dbc6, 0x3918eac6, 0x28c8d510, 0xec8d7d3, 0x34d25302, 0x326f4fef, 0x5302c, 0x3b21}}}, +{/*.x =*/{/*.val =*/{0x38c8ac7f, 0xa0bf97e, 0x1e2aa527, 0x490bb99, 0x16f84964, 0xce5b481, 0x22bbcb5c, 0x2cbef8e0, 0x9945}}, + /*.y =*/{/*.val =*/{0x29aea3b0, 0x1b650e85, 0x2dacdfa9, 0xbde88fb, 0x28eff528, 0x36d13fec, 0x3282d607, 0x3b6092c3, 0x3eef}}}, +{/*.x =*/{/*.val =*/{0x12fccf64, 0x2ea92662, 0x181318e3, 0x349e3789, 0x95dbf3b, 0x21dcb1df, 0x637db06, 0x45703ad, 0xc7d}}, + /*.y =*/{/*.val =*/{0x2878fee0, 0xfdb4ecc, 0x19ae68d5, 0x1e1760e5, 0xaf14548, 0x1092e11e, 0x1b0447aa, 0x1d1ec649, 0x4aa8}}}, +{/*.x =*/{/*.val =*/{0x148d5622, 0x2d6baeb1, 0x251bd2e8, 0x36c1fbde, 0x33381be1, 0x161aa06f, 0x9535a39, 0x3047985a, 0x5fc6}}, + /*.y =*/{/*.val =*/{0x1ac1683, 0x34361004, 0x2c7bf300, 0x16b4239, 0x367acb0e, 0x26e8b6c0, 0x1d9db9c1, 0x39526a8, 0x10e8}}}, +{/*.x =*/{/*.val =*/{0x33c85ecf, 0x1a5916ce, 0x15dacd7, 0x6e08398, 0xff0807d, 0xbd69fa, 0x23e20844, 0x22f56a48, 0x23dd}}, + /*.y =*/{/*.val =*/{0x274504ad, 0x1c2702ae, 0xec98f6f, 0x274c6013, 0x10d4b7fc, 0x7b4bf9c, 0x3d26f710, 0x26ef0094, 0x52d}}}, +{/*.x =*/{/*.val =*/{0x1136602, 0x2c2e9195, 0x19e3a5bb, 0x311bd203, 0x333b3d38, 0x1624dfc8, 0x2dfc33d0, 0x9ca0120, 0x87d1}}, + /*.y =*/{/*.val =*/{0x18af6aac, 0x3da0f107, 0x3d3bf7c4, 0x2a211d1b, 0x27745387, 0x289db3fd, 0x203de926, 0x921c296, 0x71ce}}}, +{/*.x =*/{/*.val =*/{0x30e74459, 0x1d28d722, 0x3ddb6dd6, 0x3c8dd8e1, 0x3c8a91fe, 0x3d1961c4, 0x5680590, 0x1e0753b0, 0x28df}}, + /*.y =*/{/*.val =*/{0x2f5e656f, 0x3781f303, 0x1ae6f0a8, 0x1e56e940, 0x322794a3, 0x36c5e243, 0x30f17cb0, 0x27a99a84, 0xf149}}}, +{/*.x =*/{/*.val =*/{0x29c71143, 0x11b67714, 0xf057ea3, 0x1fab6b11, 0x23fa352e, 0x1f33e400, 0x3ea103ca, 0x17e588ae, 0xeb4}}, + /*.y =*/{/*.val =*/{0xb70b136, 0x22a33688, 0x22b1bf4c, 0x165a7a9a, 0x1e2857d6, 0x1807d640, 0xbd0f573, 0xbd6160e, 0x52c4}}}, +{/*.x =*/{/*.val =*/{0x1507a7e6, 0x37cdaf22, 0x305f129b, 0x25896ebd, 0x310c41c0, 0xa1458cd, 0x1ad0d5f4, 0x142c15d1, 0x232d}}, + /*.y =*/{/*.val =*/{0x152b5892, 0x1c202084, 0x6459ccb, 0x18303bed, 0x2257f712, 0xe22b7c1, 0x33f6b086, 0xeb14d79, 0x780f}}}, +{/*.x =*/{/*.val =*/{0x177e7775, 0x222a29b8, 0xed95f63, 0x385564e2, 0x1291aeb5, 0x150eeb3d, 0x233cee58, 0x1a8ebfe5, 0x9d89}}, + /*.y =*/{/*.val =*/{0x3a056691, 0x3f3db4ea, 0x299253be, 0x26735fb8, 0x10927de8, 0x2593b5c9, 0x1bf0b94e, 0x2a790fd2, 0xdd91}}}, +{/*.x =*/{/*.val =*/{0xc904ed3, 0x1655fc7a, 0x5857841, 0xa9d1624, 0x272384df, 0x3e3990c4, 0x18dff97, 0x230b4b6e, 0xcf}}, + /*.y =*/{/*.val =*/{0x396f77c1, 0x2658ed, 0x32f6827b, 0x26475e74, 0x1bd81122, 0x35706f54, 0x1d44119d, 0x3a9e0, 0xaaad}}}, +{/*.x =*/{/*.val =*/{0xcf8cffd, 0x2cad6622, 0x3a45ae61, 0xb9ac56d, 0x1bdd8943, 0x2bee23de, 0x38c1bd45, 0x26dfc7f9, 0x80}}, + /*.y =*/{/*.val =*/{0xdb5f32f, 0x24751686, 0x12b9f93d, 0x28d03eb6, 0x12fdc912, 0x2320db79, 0x1a863028, 0x3808afd0, 0xf817}}}, +{/*.x =*/{/*.val =*/{0x2dc7a626, 0x11f741e6, 0x33cdcc02, 0x1772ade, 0x46b0734, 0x32bc48c9, 0x806bce4, 0x1b28b13e, 0x2f45}}, + /*.y =*/{/*.val =*/{0x25279532, 0x2b3ac002, 0x16eaea9e, 0x13236f70, 0x9f5302, 0x47ed991, 0x50544d2, 0x1c69e919, 0xf8cf}}}, +{/*.x =*/{/*.val =*/{0x1a328d6a, 0x2eaa0623, 0x1adc18bd, 0x135dcea5, 0x308fa7b2, 0x1a264616, 0x34e00a34, 0x3016e988, 0xc663}}, + /*.y =*/{/*.val =*/{0x3ec9b8c0, 0xec2edaa, 0x12bf9cc2, 0x21547a94, 0x171317dd, 0x2bf73c9d, 0x21c38d39, 0x3a6357dc, 0x3331}}}, +{/*.x =*/{/*.val =*/{0x22143fb0, 0x370d6995, 0x3c205dd6, 0x3ee4a0c2, 0x399597a9, 0x2bfcce51, 0x383790cf, 0x37070ceb, 0x292a}}, + /*.y =*/{/*.val =*/{0x236ad01c, 0x2a76d8f3, 0x35e9d4d8, 0xf998b5c, 0x4ecf6d8, 0x65a2833, 0xb647f3f, 0x1986f3b8, 0xa072}}}, +{/*.x =*/{/*.val =*/{0x30b90e0b, 0x27b079b0, 0x3094a458, 0x3fc74e7e, 0x675b3d6, 0x32012967, 0x67d3fed, 0x1fe6b55, 0xa435}}, + /*.y =*/{/*.val =*/{0x3a1fdc20, 0x3c002e64, 0x3599b5a3, 0xa880d94, 0xbe8c0dc, 0x341f32d0, 0x3d71a142, 0xb72530f, 0x7c8f}}}, +{/*.x =*/{/*.val =*/{0x188f4d82, 0x2e7474ad, 0x159204ac, 0x9937676, 0x21d6fcaf, 0x170c09b0, 0x1c515b0e, 0x1665c1b9, 0x6dd5}}, + /*.y =*/{/*.val =*/{0x14132ad3, 0x287aadab, 0x15927be5, 0x3db9c11b, 0x2d0f9478, 0x3346376d, 0x1233dd46, 0x109ff54d, 0xbc92}}}, +{/*.x =*/{/*.val =*/{0x1e05dccc, 0xcb60046, 0x19a93e5, 0xfe8fb53, 0x13d172ae, 0x1b825ae5, 0x1a030954, 0x3db85d4f, 0xb8ce}}, + /*.y =*/{/*.val =*/{0xc6d5750, 0x52833f, 0x26b68133, 0x1d5ff0da, 0x12bd99df, 0x3529d393, 0x9bbf6a4, 0x229829b3, 0x302b}}}, +{/*.x =*/{/*.val =*/{0x286df50d, 0x313bb405, 0x6f92bd0, 0x179e4a87, 0x82060cd, 0x361d10b0, 0x1f02d6f, 0x58c24d7, 0x3a57}}, + /*.y =*/{/*.val =*/{0x2859679b, 0x8562ca3, 0x3781a11d, 0x2abe07ae, 0x30a0dde0, 0x3cffcb95, 0x1f32f516, 0xe1ced66, 0x85e1}}}, +{/*.x =*/{/*.val =*/{0x388f7e09, 0xaa8ad9f, 0x27d92cde, 0x280dde6e, 0x1dc0beb3, 0x384b9691, 0x5fcbbd8, 0x218f53c8, 0x5e6a}}, + /*.y =*/{/*.val =*/{0x8dfca97, 0x2f58a19d, 0x3b4cfe3b, 0x23940dc8, 0x140234a6, 0x12a347da, 0x8edfc44, 0x681e28e, 0xc257}}}, +{/*.x =*/{/*.val =*/{0x1df66583, 0x3b2a229b, 0x25580609, 0x6433e68, 0x1ea87603, 0x38bdfbf, 0x2fd019c1, 0x1c6d48f0, 0x5281}}, + /*.y =*/{/*.val =*/{0x3f480c26, 0x3407b39, 0x3de01414, 0x8104f71, 0x1e8fb495, 0x2f3a351a, 0x27a6598, 0xe575ec3, 0x7b2c}}}, +{/*.x =*/{/*.val =*/{0x2521b3ff, 0x38a61193, 0x1aa750ce, 0xf01c5fa, 0x2e24a523, 0x1134afa6, 0x1455c75e, 0x138c0432, 0x248}}, + /*.y =*/{/*.val =*/{0x269da7e, 0x306b92e4, 0x23ac8bbc, 0x1c01b7a4, 0x2d0eebad, 0x30acf0ac, 0x3e30d07e, 0x34282a88, 0x9619}}}, +{/*.x =*/{/*.val =*/{0x692fd1, 0x2c982585, 0x3d90dfe2, 0x3d0f1b32, 0x1f190edc, 0x2ab7bd2c, 0x1ff800e0, 0x322d2640, 0x4e53}}, + /*.y =*/{/*.val =*/{0x328625e0, 0xd24c39c, 0x3fc97539, 0x1e943695, 0x219da1a8, 0x335c269c, 0x1a01e186, 0xf93d350, 0xdd6e}}}, +{/*.x =*/{/*.val =*/{0x3549827b, 0x2338d5f6, 0x121bd614, 0x313dfcf8, 0x2ce311fc, 0x4b81b78, 0x375f3a82, 0x343d7834, 0xce47}}, + /*.y =*/{/*.val =*/{0x2faed097, 0xf32697f, 0x5769df4, 0x39964bfc, 0x39ad0f29, 0x244e7f96, 0x30d49d58, 0x263ee658, 0x15c6}}}, +{/*.x =*/{/*.val =*/{0xc43da59, 0x3747b53a, 0x3a48ca2f, 0x6911b8a, 0x6cf9bc9, 0x1c4ebfe0, 0x21a3319b, 0x1f592302, 0x7115}}, + /*.y =*/{/*.val =*/{0x248d28ac, 0x1f7884ad, 0xcb6ad56, 0x33c28fe9, 0x11ab13fc, 0x28440e45, 0x303053f2, 0x35451759, 0x3d53}}}, +{/*.x =*/{/*.val =*/{0x3e889756, 0x37606ba6, 0x3004bb25, 0x1ed9265e, 0x1899f3f2, 0x3365ec9c, 0x1fea8226, 0x22f0cc84, 0x762e}}, + /*.y =*/{/*.val =*/{0x3ca6b774, 0x17896781, 0x84fa5e2, 0x1cb6cc52, 0x2e34719, 0x3313c526, 0x3e97c3c7, 0x250982bc, 0xc028}}}, +{/*.x =*/{/*.val =*/{0x26714560, 0x1d560296, 0x256c6c28, 0x1fc8409f, 0x25a85c24, 0x1fbd93c6, 0x2d36b9d4, 0xa9d55e6, 0x38b8}}, + /*.y =*/{/*.val =*/{0x2774299e, 0x36a1ccd2, 0x3716284a, 0x253c8efb, 0x2434597d, 0x3d58d185, 0x21ef428b, 0x29a5dbc9, 0xf9d8}}}, +{/*.x =*/{/*.val =*/{0x1b720b26, 0x188bac12, 0xccfcd07, 0x3ca0d7e6, 0x39062026, 0x1aefb504, 0x168ee1f4, 0x316ba6b2, 0x3e10}}, + /*.y =*/{/*.val =*/{0x2dd92db5, 0x11ba631e, 0x3e09e433, 0x3fde6936, 0x215e28e2, 0x1996ca1c, 0x288915a8, 0x31b3ff90, 0xc735}}}, +{/*.x =*/{/*.val =*/{0xc15cf94, 0x3710a097, 0x12082845, 0xff5aa0, 0x3569f8bd, 0x1bdc4615, 0xd97eb79, 0x2979dbec, 0x1dc5}}, + /*.y =*/{/*.val =*/{0x140ef8a2, 0x3e95399e, 0x25d97f94, 0xb6f12d6, 0x72d0c65, 0x1ccc46a4, 0x367d6019, 0x22b89d5f, 0x855b}}}, +{/*.x =*/{/*.val =*/{0x78ee8d, 0x3c142473, 0x6919442, 0x2fc83394, 0x1b4ff64e, 0x3dc98eaa, 0x1a9be25f, 0x15eb6167, 0xd08e}}, + /*.y =*/{/*.val =*/{0x2da63e86, 0x265fd370, 0x22ed9de, 0xfbdf3e5, 0x3e6df412, 0x5cbb9d5, 0x88d72d6, 0x25e612ad, 0x852e}}}, +{/*.x =*/{/*.val =*/{0xe9c22bc, 0x10eb950c, 0x1bcc42fd, 0x3699f5a4, 0x3c7be601, 0x2cd11366, 0x2eb23765, 0x33a97a67, 0x5335}}, + /*.y =*/{/*.val =*/{0xbdacb60, 0x30b099cb, 0xa1f19b3, 0x30c308db, 0xeb86ac8, 0x1fc203c3, 0x5224a06, 0x34081da7, 0x3bf8}}}, +{/*.x =*/{/*.val =*/{0xff4de54, 0x2f079885, 0x1d3c2be5, 0x32af647a, 0xa2858a5, 0x100c73c5, 0x202a2c3b, 0x370d577c, 0x5716}}, + /*.y =*/{/*.val =*/{0x10100fa5, 0xfa93f55, 0x47e417d, 0x3cffb334, 0x1324c5eb, 0x2a9986a6, 0x383f391e, 0x1b100296, 0x985f}}}, +{/*.x =*/{/*.val =*/{0x2336a875, 0x108cff13, 0x19d064c1, 0x3b71c748, 0x2f1b5099, 0x15be606, 0x2d4dd947, 0x16786af8, 0x24a6}}, + /*.y =*/{/*.val =*/{0x1112057c, 0x3cffa170, 0x1e0b96ab, 0x2911927a, 0x1cf34f69, 0xcc6f51f, 0x27240468, 0x2beb142f, 0xd3e1}}}, +{/*.x =*/{/*.val =*/{0x761d58d, 0x12eabcce, 0xd60e2f3, 0x1326f902, 0x20df7aca, 0x9028d5c, 0x3614610a, 0x1849e08f, 0xb8c4}}, + /*.y =*/{/*.val =*/{0x1d1051a4, 0xe3a82ea, 0x2107c5b6, 0x1d411e17, 0x33c5053f, 0x1163da5f, 0xe37d14a, 0x365b145c, 0x8f9e}}}, +{/*.x =*/{/*.val =*/{0x1166ff40, 0x537a868, 0x1fff36da, 0x3bafd290, 0x80a2eca, 0x20497639, 0x18d2b7c7, 0x100cc620, 0x6b00}}, + /*.y =*/{/*.val =*/{0x1d71b847, 0x2dd04c3a, 0x3f3ede9e, 0x1a20fdb9, 0xbf2f007, 0x250e8164, 0x2fac9968, 0x6ceba2a, 0x41cd}}}, +{/*.x =*/{/*.val =*/{0xd6bf1f, 0x114841ae, 0x24fcbb0, 0x2f40cfa6, 0x3346b946, 0x87a49da, 0xb83ca35, 0x1cd0d147, 0xc333}}, + /*.y =*/{/*.val =*/{0x3cb01f48, 0x25796108, 0x2266162f, 0x2e8d9083, 0x2c315598, 0x3fcc6bdc, 0x12cda13d, 0x3a4e46e0, 0x2eef}}}, +{/*.x =*/{/*.val =*/{0x34d9279c, 0x12d43f2a, 0x99a0075, 0x1e171e64, 0x3a845c28, 0x15c0bb20, 0x22c5776b, 0x38539f8a, 0x7121}}, + /*.y =*/{/*.val =*/{0x2f97b82e, 0x1c80a5f8, 0x1100d1ec, 0x3e8a0cd2, 0x35046e47, 0x2e865b4c, 0x105ca520, 0x30028c67, 0xf194}}}, +{/*.x =*/{/*.val =*/{0x2127b756, 0x2ea1ffd, 0x3a097048, 0x10a2f92a, 0x20b41603, 0xd8b6941, 0x1f12672d, 0x1e0bdc5b, 0x6d8c}}, + /*.y =*/{/*.val =*/{0x3f172571, 0x1547dd2a, 0x17cdcca6, 0xea9b68b, 0x134daf4e, 0x26a0b4db, 0x1b911145, 0x37c225bf, 0x99ae}}}, +{/*.x =*/{/*.val =*/{0x11a3c43c, 0x1312cb15, 0x2cee258e, 0x3dc072a3, 0x2e67140d, 0x307cad2a, 0x2cd5b48c, 0x36a519f2, 0x56c9}}, + /*.y =*/{/*.val =*/{0x20d7c9ed, 0x9362df4, 0x2edcaa18, 0x3503fe4c, 0xb685241, 0x31e59377, 0x39ec2f33, 0x1ab2d0b1, 0x38d4}}}, +{/*.x =*/{/*.val =*/{0x2df771c8, 0x27892740, 0x2094c87b, 0x1694847b, 0x1f875033, 0xb0acf00, 0x1c9029d3, 0x151b648b, 0xb71e}}, + /*.y =*/{/*.val =*/{0x13f48c51, 0x114e89be, 0x1bba2862, 0x2f548ad5, 0x2288f426, 0x4a93333, 0x1f900789, 0x3bea33b2, 0xe7cc}}}, +{/*.x =*/{/*.val =*/{0x2ee40896, 0x27f5e5b0, 0x1177f5bf, 0x2b8dea49, 0x261e6aa1, 0x1b819399, 0x36de46bb, 0x3c06c124, 0x7a0d}}, + /*.y =*/{/*.val =*/{0x44a7569, 0xb6393bc, 0x117da7f2, 0x8a28a35, 0x290e9aaa, 0x35abfd7a, 0x2fcd1b2a, 0x1d6038d5, 0xb446}}}, +{/*.x =*/{/*.val =*/{0x6e1346b, 0x28661277, 0x5af1c5e, 0x2f9ec40e, 0x1152c05a, 0x31d87c53, 0x2d10be54, 0x1a3fc260, 0x690}}, + /*.y =*/{/*.val =*/{0x17226c13, 0x2ed62953, 0xc6026e7, 0x3da24e65, 0x6442aa4, 0x176caf42, 0x3de26da8, 0x38f8242f, 0xb863}}}, +{/*.x =*/{/*.val =*/{0x3235c795, 0x2138aef1, 0x3d541d75, 0x362563a, 0x1c89d70b, 0x2c16cdf4, 0x3974b393, 0x11890d7b, 0x63c}}, + /*.y =*/{/*.val =*/{0x1b110258, 0x3ccb7025, 0x249a9bd3, 0x12b2eb3e, 0x1c85b69e, 0x3d98364c, 0x38404431, 0x26ee44c0, 0xe27f}}}, +{/*.x =*/{/*.val =*/{0x2c1cbaab, 0x34de9fc5, 0x33d564cf, 0x32ae1e40, 0x30635c1a, 0x2adb0629, 0x16071598, 0x2ba63ecd, 0xd031}}, + /*.y =*/{/*.val =*/{0x5116b26, 0x30e411fe, 0x3d65fdc4, 0x3ed293f6, 0xb4dcf6d, 0x39301ab7, 0x584e8e6, 0x25ad3a55, 0x4151}}}, +{/*.x =*/{/*.val =*/{0x1affca70, 0x3f44d85f, 0x14ce5fd1, 0x1addc21d, 0x12d1f999, 0x3565346a, 0x3861d3ff, 0x47bce91, 0xd4c0}}, + /*.y =*/{/*.val =*/{0x3d9c4777, 0x31fcb8a5, 0x256ebb09, 0xbd1ec15, 0x2b2906b2, 0x1d086400, 0x21566287, 0x12e620e9, 0x90b2}}}, +{/*.x =*/{/*.val =*/{0x17592d55, 0x300d67b3, 0xe350192, 0x356e51d0, 0x3ce3b106, 0x3fbda58c, 0x1052608a, 0x31b6f128, 0x5d2e}}, + /*.y =*/{/*.val =*/{0x2f5183a7, 0x19b9743a, 0x11151742, 0xa9ef36b, 0xcd6950e, 0x1c43e89a, 0x245eb58f, 0x337e271b, 0xa92}}}, +{/*.x =*/{/*.val =*/{0x255bf84c, 0x1d12e3e3, 0x30d9027a, 0x1931bb55, 0x3cae4fd9, 0x34f09488, 0x16cc8e5d, 0xa2673ae, 0x6278}}, + /*.y =*/{/*.val =*/{0x1f15fa2a, 0x3d473ead, 0x1d176ed6, 0x8379f7, 0x3267839a, 0x1525c8a5, 0x1a28901c, 0x2b290244, 0xd670}}}, +{/*.x =*/{/*.val =*/{0x339715c2, 0x2651c743, 0x18a529a3, 0x19487e, 0x33fedd69, 0x7de33a8, 0x23d85b41, 0x27a23c66, 0x2f18}}, + /*.y =*/{/*.val =*/{0x171dfea, 0x1a98d611, 0x36854f06, 0xcccf8b0, 0x10f9f7eb, 0x211d7b4, 0x1d7cfdf7, 0xe7e3cf1, 0xc91a}}}, +{/*.x =*/{/*.val =*/{0xa222636, 0xd7de0d8, 0x299b9d3, 0x1e81212d, 0x2f88e93a, 0x3ac63cd9, 0x8f0e572, 0x2fb8c76f, 0xe583}}, + /*.y =*/{/*.val =*/{0x36b01c43, 0x3ac98e19, 0x18800b01, 0xfa7944d, 0x1dc3ac25, 0x9d40507, 0x1ddd7416, 0x1479107b, 0x75b0}}}, +{/*.x =*/{/*.val =*/{0x138011fc, 0x1c049c00, 0x17285626, 0x165a99eb, 0x200a4d83, 0x2c4cc208, 0x1eb11156, 0x4e8c205, 0x6e83}}, + /*.y =*/{/*.val =*/{0x3f15ab7d, 0x2b2da7e8, 0x1c51f9a6, 0x2be456ba, 0x1ac30426, 0x4b6c807, 0xf204c1a, 0x2062f709, 0xc147}}}, +{/*.x =*/{/*.val =*/{0x195b6f7e, 0x25527d71, 0x38b2021f, 0x2ccad4f4, 0x1876cdbe, 0x14eab42, 0x1a30c83a, 0x1f474133, 0xa5ac}}, + /*.y =*/{/*.val =*/{0xab19c84, 0x236edcc2, 0x1818a484, 0x38e4583d, 0x19ee1b99, 0x30f2491f, 0xf55b36c, 0x2282ad50, 0xdf0b}}}, +{/*.x =*/{/*.val =*/{0xe81c1bc, 0x24e92b93, 0x2bb5b33b, 0x14d97962, 0xce767d2, 0x2056e35a, 0x4635ad, 0x3c15197, 0x336}}, + /*.y =*/{/*.val =*/{0x166cbedd, 0x1b74a259, 0x8115017, 0x5ca3ad7, 0x30675323, 0x1a710944, 0x350014ff, 0x2d7e4315, 0x7e48}}}, +{/*.x =*/{/*.val =*/{0x14bc0324, 0x2a208b00, 0x24d2cfc5, 0x21fc0a35, 0x2f119155, 0x198968d9, 0xe7c338e, 0x299908fa, 0xb96b}}, + /*.y =*/{/*.val =*/{0x36c2ee15, 0x2d3afff6, 0x25ba8374, 0x33948a51, 0x1876b383, 0x3119268a, 0x285dfbea, 0xb336cee, 0xe83c}}}, +{/*.x =*/{/*.val =*/{0x30b7b678, 0x9d76cce, 0xf638166, 0xf10c46f, 0x2b6c76f1, 0x21af2909, 0x231ba19, 0x125ccd39, 0x186e}}, + /*.y =*/{/*.val =*/{0x38d91fc1, 0x1e81dbcb, 0x9535dca, 0x1dc8951, 0x37e67e11, 0x3f209702, 0x3bd84aa7, 0x18392601, 0xc0d4}}}, +{/*.x =*/{/*.val =*/{0xbb9dc8f, 0x23226e1, 0x1edd333d, 0x2a7a4fbd, 0x2787d1ab, 0x3dc0d4d4, 0x26864248, 0x1073b870, 0xfd99}}, + /*.y =*/{/*.val =*/{0x259780d5, 0x10fab94f, 0x2fe938d7, 0x1cacbf7b, 0x859e678, 0x25f815e2, 0xe6f46de, 0x3b1d6f50, 0x7a41}}}, +{/*.x =*/{/*.val =*/{0x3b963645, 0xfa50cb0, 0x271f1f8e, 0x336ca01f, 0x3132fb2d, 0x11e068b8, 0xa63e6e7, 0x2553ec6e, 0xc5f0}}, + /*.y =*/{/*.val =*/{0x8be2dd, 0x2fe21d3c, 0x47be4ed, 0xc140ac0, 0x20d7e6a3, 0xf2d1009, 0xb6fb18a, 0x34c4086c, 0xd552}}}, +{/*.x =*/{/*.val =*/{0x3b6aa206, 0x370ed72e, 0x31c19bce, 0xd5807fd, 0x1ac744bd, 0x4e3fc55, 0x1f7d2ec7, 0x215da31f, 0x9dac}}, + /*.y =*/{/*.val =*/{0x13b30b86, 0x235f518a, 0x23ff64cc, 0x1aaae446, 0x3bde77fa, 0x90ceda, 0x37bba791, 0x32b82b93, 0xb23c}}}, +{/*.x =*/{/*.val =*/{0x123809fa, 0x238ae3b7, 0x1d954be1, 0x21172cd4, 0x51f08fd, 0x24cd8fc9, 0x9f228ba, 0x76f8b94, 0x3838}}, + /*.y =*/{/*.val =*/{0x331fed52, 0x35c1d460, 0x2d8f24db, 0x207f32cc, 0xeb1cc36, 0x10169548, 0x117dcb09, 0xb4283ee, 0xe4a3}}}, +{/*.x =*/{/*.val =*/{0x3663da4, 0x2059b064, 0x35d0b81f, 0x28d8a467, 0x4aa2ba5, 0x229bb5f1, 0x1705e680, 0x128d5aa9, 0x6a66}}, + /*.y =*/{/*.val =*/{0x33fc22c4, 0xa0c4fec, 0x26c04c9c, 0x2645849f, 0x3f0cd508, 0x21bb065a, 0x1e98b29f, 0x496553f, 0x449a}}}, +{/*.x =*/{/*.val =*/{0x5ed815e, 0x3dc0b54, 0x1c017b47, 0x3d102af0, 0x147ad166, 0x17eb4865, 0x34a32ebb, 0x36b19e7d, 0x5568}}, + /*.y =*/{/*.val =*/{0x602df0, 0x26efd930, 0x2582151d, 0x17dfbb8, 0x73f2beb, 0x35bf8074, 0xba64580, 0x3e1d09e2, 0x7a85}}}, +{/*.x =*/{/*.val =*/{0x1ee840f8, 0x105d4ebc, 0x13c98f26, 0x4070980, 0x325cbe11, 0x2752e0a5, 0x3be4ecfc, 0x16a03720, 0x8719}}, + /*.y =*/{/*.val =*/{0x27eed395, 0x8a09a41, 0xa8dfa80, 0x22709c24, 0x1a2138dd, 0x3db76d2a, 0xe3aeb15, 0x773265b, 0x603}}}, +{/*.x =*/{/*.val =*/{0x2bf05bd6, 0xe67c139, 0x12a99465, 0x3d5b80c8, 0x70deca2, 0xbd47fad, 0x4fe9083, 0xc906fb9, 0x900c}}, + /*.y =*/{/*.val =*/{0x300d358b, 0x394ab4ef, 0x4efb15d, 0x2614d60f, 0xb2439d6, 0x31c8115c, 0x1f0f5f95, 0x3e7a3a2c, 0x6c31}}}, +{/*.x =*/{/*.val =*/{0x272e294d, 0x39becbde, 0xd0dd5b, 0x163ae8fc, 0x37edc6f1, 0xa27abb7, 0x134b91a6, 0x39201735, 0x29df}}, + /*.y =*/{/*.val =*/{0x2c469b52, 0x104dc983, 0x129ee694, 0x3c65870e, 0x205e4dd1, 0xd39d622, 0x272e19b4, 0x3609b401, 0xbf66}}}, +{/*.x =*/{/*.val =*/{0x33773f7, 0x31fc011b, 0x1b599953, 0x3513f4d1, 0x2372a150, 0x10430027, 0x1236d3e1, 0xc89bd77, 0x355b}}, + /*.y =*/{/*.val =*/{0x1887c182, 0x14f0ffc, 0xe251090, 0x977de33, 0x21fcb81e, 0x43bb774, 0x303ad49f, 0x29201c11, 0x8ec}}}, +{/*.x =*/{/*.val =*/{0x141fcc76, 0x10109c92, 0x227146b3, 0x34d666d9, 0x278a558d, 0x2ca70c2, 0x2d4ad848, 0x30c91061, 0x2a1e}}, + /*.y =*/{/*.val =*/{0x2451553f, 0x2837c990, 0x382a3120, 0x1549d580, 0x3e3b61b2, 0x2fb05054, 0x1cacf4c1, 0x20b9a3d9, 0xe01e}}}, +{/*.x =*/{/*.val =*/{0x2bfd913d, 0xfe5580f, 0x254c9eac, 0x29a039bb, 0x2a8d2050, 0x1e82130, 0x3ddf874d, 0xaa9fa41, 0x3636}}, + /*.y =*/{/*.val =*/{0x52e243d, 0x113e6bab, 0x2b2faafc, 0xc2ec435, 0x1a2a82d8, 0x18910dc3, 0xafd5341, 0x1e19db2e, 0x48f2}}}, +{/*.x =*/{/*.val =*/{0x375732c0, 0x1661934d, 0x33777aa8, 0xbf979c8, 0x31096e20, 0x29746df2, 0x34b9b624, 0x33cc7e2d, 0x8f3c}}, + /*.y =*/{/*.val =*/{0x25b9415b, 0x1cef7979, 0x858825e, 0x39a1dd5, 0xe53d8a9, 0x3d1b665f, 0x1e53189e, 0x334f8b4e, 0x67f1}}}, +{/*.x =*/{/*.val =*/{0x34889f3f, 0xa87e0e4, 0x1095da7f, 0x3faca2d1, 0x29b0ebc4, 0x28d1a6c5, 0x2119621e, 0x409bc6c, 0x8799}}, + /*.y =*/{/*.val =*/{0x3bb792b, 0x278b7e6f, 0x286037b4, 0xcbd86fc, 0x3f279de9, 0xbcb2dc5, 0x11d96213, 0x2e53296a, 0xddea}}}, +{/*.x =*/{/*.val =*/{0x2fa4e07e, 0x37614061, 0x3423bec4, 0xb29d215, 0x337d9a49, 0x7040ffe, 0x35718422, 0x2be545f7, 0x37d7}}, + /*.y =*/{/*.val =*/{0x2e020165, 0x24db61da, 0x18a65a4c, 0x8faa25e, 0x19c556c4, 0xecd4b18, 0x133c8f47, 0x1ea4a06a, 0x35bc}}}, +{/*.x =*/{/*.val =*/{0x3aee42db, 0x3e7f4af, 0x330714a7, 0x2eef16d1, 0x2cbfc1d9, 0x2dbb6e47, 0x19150fc7, 0x9f9f66d, 0xcc34}}, + /*.y =*/{/*.val =*/{0x15d87bdb, 0x188a7004, 0x272422dc, 0x3972eb63, 0x21520010, 0x38ff4fec, 0x1c6a1885, 0x26106948, 0xea24}}}, +{/*.x =*/{/*.val =*/{0x2e96e4f1, 0x2c29c594, 0x2e80030c, 0x17c05802, 0x1efccaff, 0x1ddc20cd, 0x197e201, 0x523c066, 0x56bb}}, + /*.y =*/{/*.val =*/{0x2eb0582e, 0x2227c067, 0x4af0eb5, 0x4f47480, 0x30ea9f73, 0xfb62f8, 0xa33beb, 0x2129584c, 0xa095}}}, +{/*.x =*/{/*.val =*/{0x1f23d1f, 0x1315fd66, 0xc036d8a, 0x2c97f5c8, 0x18a0a6b6, 0x3522787f, 0x30bbbbd3, 0x3a054f59, 0xb398}}, + /*.y =*/{/*.val =*/{0x32ff3fc, 0x160faffe, 0x26156cd1, 0x1e4762b4, 0xba52ea, 0x1ffacbec, 0x1f47f07f, 0x270895cb, 0x69f5}}}, +{/*.x =*/{/*.val =*/{0x34fb6a39, 0x9f576c6, 0x2ac90ecd, 0x235ab493, 0x1e119b8b, 0x3f4a59c, 0x1ea6e43e, 0x25abd5e5, 0x459}}, + /*.y =*/{/*.val =*/{0x725bb62, 0x30ab6de8, 0x20010535, 0x388a2d03, 0x2eef0373, 0x218a0837, 0x26c33672, 0x2b8338e0, 0xd3f9}}}, +{/*.x =*/{/*.val =*/{0x319888e9, 0xe73c9e4, 0x2448a8b4, 0x4ae9afc, 0x2681673d, 0x1834c0a5, 0x3a6e2dde, 0x3a9dceb0, 0x1f90}}, + /*.y =*/{/*.val =*/{0x2f113b79, 0x1bf7f25f, 0x19522e65, 0xdd47fb9, 0x2b96a821, 0x54f49c7, 0x2a10e958, 0xd9f0576, 0x89be}}}, +{/*.x =*/{/*.val =*/{0x1bf6c42, 0xfaacf77, 0x19887539, 0x1e4f66c4, 0xee74ef7, 0x1195205b, 0x105c7ee7, 0x6cf35b0, 0xd02e}}, + /*.y =*/{/*.val =*/{0x7bc54cc, 0xcd8ca3e, 0x31b6aac1, 0x2961e6e4, 0x124526bc, 0xc89c343, 0x22258127, 0x1d3cf2a3, 0x9a0b}}}, +{/*.x =*/{/*.val =*/{0xf6c15c2, 0x7bd1fc6, 0xf38f1ca, 0x39d90532, 0x1143483d, 0x1ce604e7, 0x1757fea1, 0x2a14af28, 0x8456}}, + /*.y =*/{/*.val =*/{0xb174134, 0x3c7bf0ca, 0x16fb671f, 0x3243c261, 0x79e7f4c, 0x127b0dc4, 0x2cdefd3, 0x3691b521, 0xe1b9}}}, +{/*.x =*/{/*.val =*/{0x27df614a, 0x1d47ebb3, 0x24705eb2, 0x27f39a4c, 0x3e1804d7, 0x91aa7fa, 0x33049180, 0x3966340b, 0xa7d2}}, + /*.y =*/{/*.val =*/{0x159b4c8d, 0x3c32f0e5, 0x19bc8656, 0x3c01de54, 0x3fa2de53, 0x207bb042, 0x10172c79, 0x33512f0, 0x62a2}}}, +{/*.x =*/{/*.val =*/{0xca1c4f9, 0x16d0aa86, 0x2b7e2823, 0x13bf8d32, 0x1f16f44f, 0x2e0f698, 0x1728c4c4, 0x3de3c8af, 0x7815}}, + /*.y =*/{/*.val =*/{0x3778bc15, 0x2ac7a8da, 0x177d1e19, 0x2d0b7985, 0x18c35d5c, 0x24f3cc51, 0x1af6a7dd, 0x7a334e, 0xc1c6}}}, +{/*.x =*/{/*.val =*/{0x3ed5996, 0x37933a2d, 0x360af53b, 0xc7f9664, 0x1b92468, 0x3ef240ca, 0x1a4ea492, 0x2dfa7fa6, 0x1a46}}, + /*.y =*/{/*.val =*/{0x28c85cae, 0x3b93b447, 0x352745c2, 0x21e52a7b, 0x23ebf550, 0x3b821281, 0x1dc570e3, 0x3a07a8fc, 0x683c}}}, +{/*.x =*/{/*.val =*/{0x2e2e607b, 0x3d34d673, 0xf36aa1, 0x2a87bb1b, 0x3fdd2b88, 0x447d595, 0x1772c20d, 0xfd9ff4c, 0x773}}, + /*.y =*/{/*.val =*/{0xc614763, 0x28bcc477, 0x3e017d26, 0x38ef7816, 0x3156f489, 0x18ea316e, 0x38285eae, 0x3a3eeb05, 0xfd9f}}}, +{/*.x =*/{/*.val =*/{0x354d61d1, 0x3ecb8807, 0x30b99baf, 0x549d76f, 0x1bf21517, 0x23e67901, 0x3ed8b9c5, 0x4f91d89, 0x875e}}, + /*.y =*/{/*.val =*/{0x945747, 0x12a27470, 0x273c5309, 0x277543a5, 0x399e3601, 0x1b784f4d, 0x56e8f64, 0x37712a59, 0x2d8f}}}, +{/*.x =*/{/*.val =*/{0x2fd53ed3, 0x17245d60, 0x1a56ccef, 0xfdd3ee7, 0x1f7c4916, 0x3d82e4c7, 0x372ad5b8, 0x2f56659, 0x2084}}, + /*.y =*/{/*.val =*/{0x1a7a7132, 0x1c50ff94, 0xe708998, 0x21f11ce5, 0x3afac254, 0x2f51da9a, 0x18243487, 0xd25f3b0, 0xf299}}}, +{/*.x =*/{/*.val =*/{0x2032f9a2, 0x122e38a4, 0x21fc6ccc, 0x159bd43e, 0x3f8f63ce, 0xdd32cc7, 0x32640ed2, 0x31af669a, 0x25aa}}, + /*.y =*/{/*.val =*/{0x2b51d4f0, 0x1d88c284, 0x19f3d9e, 0x2620eef1, 0x3190f655, 0xcbd53d3, 0x546c16f, 0x318ee991, 0xf5a6}}}, +{/*.x =*/{/*.val =*/{0x14445a7a, 0x4c72ea, 0x1cf1ec59, 0x254d7c20, 0x1c8d5df, 0x3c46db18, 0x2c6bfb12, 0x3bef27c1, 0xf82f}}, + /*.y =*/{/*.val =*/{0x242a7a98, 0x18eb3861, 0x240d1e59, 0x720ed91, 0xb4a4b5, 0xe50b065, 0x36b67550, 0xdef71be, 0x94bb}}}, +{/*.x =*/{/*.val =*/{0x362b8df9, 0xcb7ede8, 0x1da21c57, 0x7f6d47d, 0x11c8bd49, 0xcb74b72, 0x1c0cd9a8, 0x37634fb7, 0x11c4}}, + /*.y =*/{/*.val =*/{0x296edd30, 0x60c9e79, 0x2ec5448f, 0x2df9f498, 0x10fb6417, 0xd810e22, 0xac2aae4, 0x361da2fd, 0x45b3}}}, +{/*.x =*/{/*.val =*/{0x1def001d, 0x13c89769, 0x9ba27ef, 0x3e6ef5a6, 0x23b64b21, 0x2f47027, 0x22caf20e, 0x28cb6c9f, 0xa549}}, + /*.y =*/{/*.val =*/{0x30624783, 0x3576c69f, 0x2c9705ad, 0x5078a98, 0x259456eb, 0x330c3b62, 0x166cbdf4, 0x1e9e41b6, 0x799b}}}, +{/*.x =*/{/*.val =*/{0x206e37a, 0x91de2b1, 0x504731a, 0x23062523, 0x1a274f4d, 0x3a0fd1ad, 0x28002cf4, 0x2ae1fca1, 0xb526}}, + /*.y =*/{/*.val =*/{0x30c5ccab, 0x3cd9e3ff, 0xfa392ab, 0x3394e6c0, 0x26f18d28, 0x2ab3b582, 0xd8ed5c, 0xd75de04, 0x641f}}}, +{/*.x =*/{/*.val =*/{0x39d9123f, 0x3a4e0c7a, 0x388ba7d7, 0x3f1e46c7, 0x3d1e9129, 0x17e3b2be, 0x26a6f2f9, 0x14e3dcaa, 0x341b}}, + /*.y =*/{/*.val =*/{0x18bb9a40, 0x27a82abc, 0x12a26ed1, 0x37b9a9c1, 0x24d9ac72, 0x3cbc1044, 0x1c59eba6, 0x491c670, 0x5858}}}, +{/*.x =*/{/*.val =*/{0x760cb4d, 0x25763239, 0x33a69b68, 0x21f81500, 0x30673803, 0x154bafb0, 0x9df521a, 0x1fb94e37, 0xbca3}}, + /*.y =*/{/*.val =*/{0x24e10d88, 0x29dc18da, 0x8df9cf3, 0x5d5563c, 0x2ffbad9f, 0x22e020ee, 0x2d4b2263, 0xec707ef, 0x3ce0}}}, +{/*.x =*/{/*.val =*/{0xfb64db3, 0x1ee6354e, 0x1dd53841, 0x3b79328e, 0x13b8d6a7, 0x2ee0fef9, 0x1ccb740b, 0x8e48a6f, 0xc114}}, + /*.y =*/{/*.val =*/{0x3c0259be, 0x8c33a7f, 0x14567d1e, 0x1d602413, 0x178bd1a8, 0x3b3793fa, 0x6fc2a5c, 0x3db716d2, 0x1237}}}, +{/*.x =*/{/*.val =*/{0x311349e2, 0x20cab77, 0x3524c058, 0x38fb3d05, 0x1ad78d60, 0x51fa690, 0x1c2e7e62, 0x20c931ae, 0xf805}}, + /*.y =*/{/*.val =*/{0x1b2025fc, 0x3eb11a79, 0x26de88d5, 0x25262d58, 0x21122350, 0x206a983a, 0x56cdcde, 0x39682a2, 0x95c6}}}, +{/*.x =*/{/*.val =*/{0x2e548418, 0x1cdc7446, 0x9839231, 0x39221f62, 0x3a341adc, 0x1cac14d, 0x17e292fb, 0x2c327920, 0x2e6d}}, + /*.y =*/{/*.val =*/{0x10a2b918, 0x1a5e4b00, 0x1c3f5f1e, 0x23875cf8, 0x2911644b, 0xc5225e2, 0x36fbfa21, 0x1a90475d, 0x74eb}}}, +{/*.x =*/{/*.val =*/{0x3ccbdf95, 0x2b8fa3b1, 0xa5853b4, 0x8ac7291, 0x22f5494, 0x360c0ab2, 0x313050f, 0xbb60387, 0xcea0}}, + /*.y =*/{/*.val =*/{0x324a006c, 0x39954baa, 0x2ecc53d9, 0x2e8a1483, 0x10b433b2, 0x3301f5b, 0x34a6f04e, 0x1b1b61df, 0xfc00}}}, +{/*.x =*/{/*.val =*/{0x171c032b, 0x3536858a, 0x3afdc980, 0x1ad9a285, 0x766c5ff, 0x46d7f7f, 0x2603dd, 0x2a3f35b8, 0x71eb}}, + /*.y =*/{/*.val =*/{0x1668359f, 0x1ead6a38, 0x34b4755e, 0x24c6b45d, 0xcbb7f71, 0x18145bd5, 0x1d39def6, 0x49892d8, 0xd2ff}}}, +{/*.x =*/{/*.val =*/{0x3aaa138b, 0x37c367dc, 0x3786cd66, 0x3bee82fb, 0x671ff63, 0xfaf0631, 0x3ae28794, 0x389274f0, 0x417f}}, + /*.y =*/{/*.val =*/{0xa1ae869, 0x7246ccd, 0x5566afd, 0x276bf7b0, 0x3a9e57c1, 0x2974a7c3, 0x23e38c20, 0x2275ef34, 0x235}}}, +{/*.x =*/{/*.val =*/{0x307e636, 0x38562d04, 0x21611d97, 0x29df79cc, 0x2112c8b4, 0x2f0a6f68, 0x76443dd, 0x3c58058e, 0x2219}}, + /*.y =*/{/*.val =*/{0x31f15109, 0x1e86cb5, 0x373af55e, 0x35c8c34f, 0x230bd6d, 0x1b53c6e, 0x2a2f61b8, 0x212b172d, 0x4a9}}}, +{/*.x =*/{/*.val =*/{0x377220dc, 0x14ca7db7, 0x16023891, 0x27c96229, 0xe83bbd4, 0x27b40409, 0x2a8ad6a5, 0x3e507c9e, 0xffb2}}, + /*.y =*/{/*.val =*/{0x1b32b3bc, 0x26083b0c, 0x35e5f9f3, 0x3948efcf, 0x59d2f2c, 0x3e5e242, 0x3be7a03c, 0x34ffe08a, 0xf97e}}}, +{/*.x =*/{/*.val =*/{0xd9ed6c1, 0x1a2bad63, 0x3d593d6b, 0x139d16f0, 0x1edd0ec2, 0x3f061dc1, 0xf53e80b, 0xcdb72dd, 0x328}}, + /*.y =*/{/*.val =*/{0x38fafeee, 0x3b1baf9b, 0x1cb494ad, 0x16fd37c9, 0xd7c8c26, 0x35650e88, 0x19f28c46, 0x260e04bf, 0x71a8}}}, +{/*.x =*/{/*.val =*/{0x26da57e4, 0x2dd59229, 0x1cdd9f86, 0x31265bbf, 0x31bc1e98, 0x3a8a9d18, 0x118b9dbd, 0x36b8e60e, 0x690c}}, + /*.y =*/{/*.val =*/{0x133f33bb, 0x2d8656d2, 0x295a3d42, 0x18f63ef3, 0x15894df8, 0x3f646fd6, 0x379a47a9, 0x371e59de, 0x840a}}}, +{/*.x =*/{/*.val =*/{0x1cfb8036, 0x3e6262a9, 0xda35085, 0x3426a4b0, 0x167e833a, 0x45f747f, 0x247b48ae, 0x9d47ec5, 0xcff6}}, + /*.y =*/{/*.val =*/{0x24f59de0, 0x10fced68, 0x20328258, 0x2962763d, 0x2143c678, 0x38d2d621, 0x2d1ac5f, 0x3b49af55, 0xcdf4}}}, +{/*.x =*/{/*.val =*/{0x20ebec47, 0x1da4a12b, 0x142ca23d, 0x381398c4, 0x3b4ea72e, 0x10de9936, 0x27df9761, 0xe5dc744, 0xe8b6}}, + /*.y =*/{/*.val =*/{0x2eb3d8a7, 0x32a7875c, 0x15fe035, 0x398b696, 0x3ff204be, 0x6555e5f, 0x32e11ae7, 0xb7e8107, 0x5f38}}}, +{/*.x =*/{/*.val =*/{0x3319c869, 0x3df1bab8, 0x21eb2702, 0x2a7e575d, 0xcacdc18, 0x20e408bf, 0x33fc8d01, 0x1176605, 0x3018}}, + /*.y =*/{/*.val =*/{0x12b856f0, 0x3031db27, 0x23d9a7bf, 0xaa13292, 0x222e3bca, 0x1890c835, 0x3b7b6f86, 0x315e0940, 0xac5f}}}, +{/*.x =*/{/*.val =*/{0x18953133, 0x11df726c, 0x8721ae6, 0x2ced0a9d, 0xcdfa97f, 0xa01b03f, 0x1dd23881, 0xad3fb43, 0xa0b}}, + /*.y =*/{/*.val =*/{0x34af0fc9, 0x2f0928dc, 0xed4ba94, 0x28e13a2c, 0x58c8d6f, 0x71b2a19, 0x2bf2f03c, 0x60b3ed6, 0xcda1}}}, +{/*.x =*/{/*.val =*/{0x1f0a2a53, 0x3abc3b03, 0x16611e7, 0x772acfe, 0x29b892d5, 0xe515d0e, 0x3997c3a8, 0x146341f0, 0x6f86}}, + /*.y =*/{/*.val =*/{0x333bfeb2, 0x4e695d1, 0x2a05f351, 0x153ddcba, 0x309968bf, 0x1dbaa569, 0x182f29b7, 0x3d85bf51, 0xd50a}}}, +{/*.x =*/{/*.val =*/{0x278b4a0d, 0x1e78672f, 0x8c9be06, 0x3ed83c9f, 0x1c73ace4, 0xf5d6ed2, 0x3db4e1cb, 0x10bae9a8, 0x2f98}}, + /*.y =*/{/*.val =*/{0x33f39758, 0xd4cafba, 0x3d54f320, 0x23bab9da, 0xbb8f48b, 0x32489c59, 0x355552a1, 0x35a4c2f7, 0x4774}}}, +{/*.x =*/{/*.val =*/{0x3874b839, 0x444a1d5, 0x13d2b418, 0x10456ce5, 0x30b6aebe, 0x37c37ec8, 0x1e5a8053, 0x2e07f038, 0x3e03}}, + /*.y =*/{/*.val =*/{0x3c0594ba, 0x3073959, 0x1ab5b8da, 0x39717c3f, 0x198f667d, 0x3d981d5c, 0x7f42c44, 0x3858f7fc, 0xd13a}}}, +{/*.x =*/{/*.val =*/{0x39a7d197, 0x2eba434e, 0xea59459, 0x20ea3062, 0x2c234b5e, 0x23ff8288, 0x1f639477, 0x22950a03, 0xc2c5}}, + /*.y =*/{/*.val =*/{0x9eeb5e9, 0x390732fe, 0x1ad82484, 0x11fb1151, 0x2d39a60a, 0x106ad8b, 0x20927573, 0xca20d9b, 0x72ea}}}, +{/*.x =*/{/*.val =*/{0x23369217, 0x1d379b65, 0x6611ead, 0x70e5a40, 0x4eacdca, 0x289e3d50, 0xd624a21, 0x143ff2e9, 0x42dc}}, + /*.y =*/{/*.val =*/{0x3e2dbc57, 0x30c25f88, 0xe01e841, 0x284e7b2a, 0xba853a7, 0x1e3d7c58, 0x5b1d7ed, 0x2687d98e, 0xa5ba}}}, +{/*.x =*/{/*.val =*/{0x19251fa2, 0x1e7e8b49, 0x3c26cc92, 0x337ea0ae, 0x13d5e1bb, 0x1d1678dc, 0x1a1202b0, 0x31d972a4, 0x417}}, + /*.y =*/{/*.val =*/{0x3ebc52fa, 0x24c1240a, 0x161ee899, 0x292c61dd, 0x6283ad9, 0x1a19d99f, 0x357f5349, 0x397544b1, 0x72d7}}}, +{/*.x =*/{/*.val =*/{0x2cde4cf3, 0x26554187, 0x38a066ab, 0x10394d51, 0x1d9ae793, 0x30b49b45, 0x22c3be7, 0x2ad2b045, 0x384d}}, + /*.y =*/{/*.val =*/{0x252d0566, 0x1f1e5ac8, 0x351ba73b, 0x10c28ce5, 0x34c6f01f, 0x13b5b68a, 0x1ca43bfb, 0x316f346e, 0xd6e3}}}, +{/*.x =*/{/*.val =*/{0xa972627, 0x290d9a82, 0x2521e1f8, 0x24858100, 0x441a0e1, 0x2307bf2f, 0x3e15c819, 0x21c2526f, 0x8a31}}, + /*.y =*/{/*.val =*/{0x6bb8af9, 0x1ed1ed59, 0x3efcbcce, 0x110d96b0, 0x7baa417, 0x1dfb4a16, 0x3a64d095, 0x1f21da3d, 0x64bb}}}, +{/*.x =*/{/*.val =*/{0xa3a1550, 0x2951319f, 0x2ffdf279, 0x76a67e3, 0x38b75180, 0xc25db87, 0x157412dd, 0x1a6acd01, 0xebfc}}, + /*.y =*/{/*.val =*/{0x1362f6e, 0x7d0afd9, 0x28c0b195, 0x20f20639, 0x34fd0779, 0x3c6676df, 0xb540a3d, 0x3a336e67, 0xe2ff}}}, +{/*.x =*/{/*.val =*/{0x14f24bf1, 0x3e2ba88c, 0x2c500d25, 0x15500782, 0xe78708e, 0x1cdd2f0d, 0x2d024ec7, 0xeaf6dad, 0x6299}}, + /*.y =*/{/*.val =*/{0x108d1b1d, 0x34eb50c5, 0x148c6775, 0x24d4c0b2, 0x3c429b1d, 0x34b2bf8c, 0x29b93a00, 0x1cac2bab, 0x86fb}}}, +{/*.x =*/{/*.val =*/{0x39d681f9, 0x164153f9, 0x8feb9fc, 0x3383bbeb, 0x2c94b066, 0x1ffc9780, 0x3230888b, 0x3f7c9dd7, 0xc745}}, + /*.y =*/{/*.val =*/{0x3bbb1247, 0xc5cd0d, 0x27d45c76, 0x36f4cd71, 0x2818678c, 0x4e531c3, 0x1e5e78a7, 0x8bcbdae, 0x5902}}}, +{/*.x =*/{/*.val =*/{0x249a2115, 0x1dff54d1, 0x3a565ebe, 0x1e580245, 0x981aec, 0x1ab2a759, 0xc6c6dd4, 0x3014ac65, 0xfd73}}, + /*.y =*/{/*.val =*/{0x26ba6cda, 0x1272adee, 0x29d421f0, 0x3d80558b, 0x37d6d904, 0x2aeac09b, 0x38844020, 0x1a307205, 0x6207}}}, +{/*.x =*/{/*.val =*/{0x1b816b2f, 0x36e1b0d4, 0x228ee11f, 0x32de104, 0x2c5d5dee, 0x597f849, 0x11a676e8, 0x11b75965, 0x5a4d}}, + /*.y =*/{/*.val =*/{0x33e86c60, 0x3e5ebae1, 0x33ecceba, 0x39b317e, 0x3dfcd6b5, 0xf89fe3c, 0x260ab028, 0x8e5b283, 0x77c9}}}, +{/*.x =*/{/*.val =*/{0x31ce59e7, 0x110131b, 0x2d9919f3, 0x1db4e753, 0x324e6906, 0x359f05b6, 0x1f964c25, 0xbde79a8, 0x1bbc}}, + /*.y =*/{/*.val =*/{0x379aa297, 0x14c8648, 0x3839618d, 0x2265bd03, 0x1bc5a36c, 0x36c5beb4, 0x1f1a8781, 0x32d32375, 0x281f}}}, +{/*.x =*/{/*.val =*/{0x3bb80fa7, 0xd12172c, 0x30413886, 0x29f69aed, 0x20819f3a, 0x681af4c, 0xc2fbc0d, 0x38c7d8c2, 0x857}}, + /*.y =*/{/*.val =*/{0x9366b2d, 0x3660847c, 0xd7016ab, 0xb8dc10f, 0xb714717, 0x1f327477, 0x172092d, 0x24d08eb8, 0xf643}}}, +{/*.x =*/{/*.val =*/{0x3b6d6cd3, 0xe802af9, 0x38937883, 0x5984740, 0x25239734, 0x1a6e1c15, 0x3818481a, 0x19859fca, 0xea12}}, + /*.y =*/{/*.val =*/{0x34f450be, 0x2b98a497, 0x3be1a88a, 0x325d4b7a, 0x145e25b1, 0x3844afc4, 0x2e3fdaac, 0x38b941e3, 0x21a4}}}, +{/*.x =*/{/*.val =*/{0x1cff55c5, 0x1c48f509, 0x2275ec97, 0x13bf4a06, 0x2b4b635f, 0x4b079e0, 0x1442ca6c, 0x2b7f7ec9, 0xcf36}}, + /*.y =*/{/*.val =*/{0x21a0228e, 0x3289e214, 0xd2706a, 0x151fb097, 0x19f207a7, 0xbd62cef, 0x768649c, 0x4859ab8, 0xd16a}}}, +{/*.x =*/{/*.val =*/{0x125cb53b, 0x17a9e02b, 0x365eb3d0, 0x23f15763, 0x6272dab, 0x994c755, 0x25414494, 0x728acf7, 0xf474}}, + /*.y =*/{/*.val =*/{0x295a4b7e, 0x39769e65, 0x1f86e5c1, 0x5aa3ad, 0x2c8f9c0d, 0x3ec3609e, 0x1f2f01c8, 0x1bd03c89, 0xc48d}}}, +{/*.x =*/{/*.val =*/{0x3f2e070d, 0x160ff4e8, 0x12a6a98f, 0x2aadc731, 0x1047e229, 0x1cc70ee1, 0x34abff48, 0x297a410b, 0x4b72}}, + /*.y =*/{/*.val =*/{0x296dd780, 0x112ea0bb, 0x2948c3de, 0x2d197774, 0xf3c10b0, 0x1deecdb4, 0x2e1cf602, 0x753875a, 0x599e}}}, +{/*.x =*/{/*.val =*/{0x385912ec, 0xa1c0283, 0x6091134, 0x3e728139, 0x2f054327, 0x1265a52a, 0x35b786ab, 0x87538fe, 0xaa71}}, + /*.y =*/{/*.val =*/{0xae35978, 0x4532c99, 0x2056cbdb, 0x384d2a33, 0x22edebfe, 0x1499ae5a, 0x9509c50, 0x3c1df6b4, 0xc690}}}, +{/*.x =*/{/*.val =*/{0x3fd292dc, 0x2e01a893, 0x17714ce1, 0x1789a02c, 0x3d79d977, 0x201c34de, 0xf934ba4, 0x554cdc8, 0x4b99}}, + /*.y =*/{/*.val =*/{0x17095ca6, 0xce97ff9, 0x3376afd4, 0x20c8f116, 0x301f5793, 0x3029d2d7, 0x3a226df, 0x1d525844, 0xe327}}}, +{/*.x =*/{/*.val =*/{0x384da233, 0x2a560e3a, 0x1f362cd4, 0x13c36a04, 0x336ed9cf, 0x26f4ce3f, 0x25316a20, 0x32d365c7, 0x1eb7}}, + /*.y =*/{/*.val =*/{0x17c43f18, 0x2e3a954c, 0x1cf0ae9c, 0xdb26660, 0x1ed0aba3, 0x3cef342f, 0x84ff826, 0xca2b91f, 0xd984}}}, +{/*.x =*/{/*.val =*/{0x3bea0c68, 0x321042bc, 0x37b392b5, 0x10c048d9, 0x396faf09, 0x26f23a34, 0x2a3a2494, 0x258d3855, 0x3e41}}, + /*.y =*/{/*.val =*/{0x1a45edb6, 0x32edbfdc, 0x3cda1ab, 0x2846518c, 0x693062f, 0xf2ff8dc, 0x321f7f37, 0x31676492, 0x123}}}, +{/*.x =*/{/*.val =*/{0x17d4b84a, 0x2a605310, 0x1f433e69, 0x777d23c, 0x5070462, 0xa924b4a, 0x32fcb0c6, 0x26796371, 0xf13a}}, + /*.y =*/{/*.val =*/{0x13fd1c81, 0x16643f15, 0xf2d9628, 0x38df51c4, 0x3fe06eb6, 0x2e473478, 0x3e995aa6, 0x323343c2, 0x33c2}}}, +{/*.x =*/{/*.val =*/{0xe735a1e, 0x3c30ec51, 0x3e61fa05, 0xf8259a, 0x1202fc40, 0x23376b58, 0x356cb46b, 0x31f01e66, 0x678a}}, + /*.y =*/{/*.val =*/{0x12f7c055, 0xd8e97dc, 0x1371457a, 0x1fffeccf, 0x105e8e59, 0x3fcf55c, 0x1285b7a7, 0x138cf669, 0x851}}}, +{/*.x =*/{/*.val =*/{0x14c426d5, 0x30e07974, 0x22adf265, 0x29543e1e, 0x1fa93ab7, 0x1210c7e3, 0x2b66bd4c, 0x1d467823, 0x364c}}, + /*.y =*/{/*.val =*/{0x1a5876c0, 0x21b51ca9, 0x7db7191, 0x231357c5, 0x2d95be16, 0x2c62c634, 0x1fa52f1e, 0x2d65d0b2, 0xfaa8}}}, +{/*.x =*/{/*.val =*/{0x12fea1f9, 0x2c5f2ef1, 0x452b94, 0x3fc2d423, 0x106531c4, 0x3f76ad9c, 0x1f2e83bc, 0x22029574, 0xa6dc}}, + /*.y =*/{/*.val =*/{0x3bc345e9, 0x2c705391, 0x268f7e63, 0x1ee276df, 0x2cbc5005, 0x1a0e845a, 0x367c3038, 0x2a151f70, 0x7ef1}}}, +{/*.x =*/{/*.val =*/{0x1c7985c4, 0x2d84f9dc, 0x39e2b108, 0x12ff1256, 0x374c3413, 0xa10a00b, 0x19b7ce54, 0x2d72bded, 0x2320}}, + /*.y =*/{/*.val =*/{0xc2c6d44, 0x3fd3c77d, 0xd9eb8d4, 0x1bc40847, 0x1bca93d9, 0x1c86e07e, 0x3e94318c, 0x250f7222, 0xc79f}}}, +{/*.x =*/{/*.val =*/{0xa3a809c, 0x27f82c2f, 0x398346d7, 0x2d98bd75, 0x14a89eda, 0x33e5f909, 0x3df56bfb, 0x1fb20e4c, 0x125e}}, + /*.y =*/{/*.val =*/{0x149e70d9, 0x2a32402a, 0x7fca3dd, 0x138ecbbc, 0x321a371e, 0x1d1f2bd5, 0xcb38887, 0x3dbb7895, 0xe0d3}}}, +{/*.x =*/{/*.val =*/{0x208a7b1f, 0x3215fe35, 0x2a1ee514, 0x162bea6d, 0x3bc587f7, 0x141eb357, 0x37eb0079, 0x20efd263, 0x5ac}}, + /*.y =*/{/*.val =*/{0x165ccb98, 0x2198dd7e, 0x75d0f82, 0x3bc0ecc4, 0x2ac6f5b3, 0x33d08917, 0x2e6fb0fa, 0x271b3dd5, 0xe379}}}, +{/*.x =*/{/*.val =*/{0x27315443, 0x364e1ce0, 0x2e867299, 0x1e6ef552, 0x2142a13d, 0x32266082, 0x935ff42, 0x1b010198, 0xfc69}}, + /*.y =*/{/*.val =*/{0x17d28960, 0x1243582d, 0x9bd1b17, 0x1ffd2184, 0x1677b548, 0x387375a, 0x35892bbf, 0x9fafe0e, 0xe0ce}}}, +{/*.x =*/{/*.val =*/{0x3c6b5b56, 0x3cd857f5, 0x1888b607, 0x21722abb, 0x3200e541, 0x161fb4ef, 0x34338cdf, 0x2195c03b, 0xa0e8}}, + /*.y =*/{/*.val =*/{0x3a1d7518, 0x5af7944, 0x858a51a, 0x1ae1c75c, 0x13dead52, 0x29ae26e1, 0x1ad50b99, 0x11a0e7ea, 0xf5ba}}}, +{/*.x =*/{/*.val =*/{0x10cedd26, 0x35d977dd, 0x25715541, 0x322e677a, 0x239e2a3c, 0x360403e5, 0x1ebb2611, 0x120dca58, 0xaf88}}, + /*.y =*/{/*.val =*/{0x30e43f7f, 0x2db9eb4e, 0x3aa41708, 0x15279219, 0x2d2f9654, 0x32ee23af, 0x27030d28, 0x3efe5ec5, 0xdc57}}}, +{/*.x =*/{/*.val =*/{0x10b36a01, 0x1d9fddfc, 0x320812b5, 0x11e9ec5f, 0x2ec63cfc, 0x39ea5901, 0x3177a68a, 0x25375386, 0x853c}}, + /*.y =*/{/*.val =*/{0x27fe4ebe, 0x1f971fa3, 0x72f4fcc, 0x2fe60a00, 0x25123a28, 0x274080f7, 0x1b19530e, 0x33a53b26, 0xa328}}}, +{/*.x =*/{/*.val =*/{0x11da5e12, 0x7b838ce, 0x1cacb297, 0x31829005, 0x1ca2b6a9, 0xca7e4e8, 0x1e31bcda, 0xb8f10de, 0xf750}}, + /*.y =*/{/*.val =*/{0x385f4eb, 0x292e717a, 0x325cebc7, 0x21b4cbbd, 0x1672047b, 0x1c25170f, 0xfafd599, 0x3d7b759f, 0x3c57}}}, +{/*.x =*/{/*.val =*/{0x3e32478e, 0xdcc481c, 0x29ba7ed2, 0x2acc63ca, 0x332b2024, 0x31adfcfc, 0x213880fe, 0x4758041, 0xd420}}, + /*.y =*/{/*.val =*/{0x104e88d4, 0x33815a07, 0x1508cc31, 0x2c92cbcd, 0x3f847b6f, 0x357d7d12, 0x14e0c1b2, 0x353a68df, 0xbae5}}}, +{/*.x =*/{/*.val =*/{0x216ddcd3, 0x1a9c8dee, 0x1ea00355, 0x12c44008, 0x761af04, 0x16fadb2e, 0x299edf7b, 0x2b4dbd93, 0x1ae1}}, + /*.y =*/{/*.val =*/{0x2e7eb2b7, 0x33118674, 0xbb613c7, 0x185ab77f, 0x10448959, 0x1d3ddd48, 0x922059c, 0x15261e8, 0x7016}}}, +{/*.x =*/{/*.val =*/{0x19158bab, 0x264fc10e, 0x12d06caa, 0x4c9b0c6, 0x5a0674c, 0x1f3cf7cb, 0x39b3c419, 0x3d2ec203, 0xe2c6}}, + /*.y =*/{/*.val =*/{0x2d7a27f2, 0x214f3c9e, 0x49fd3f5, 0x6d622e4, 0x3ef5c641, 0xaecd847, 0xb1eabd1, 0x1e18b4f0, 0xfa92}}}, +{/*.x =*/{/*.val =*/{0x3a95a8db, 0x1761dccb, 0x39d36f61, 0xfb03111, 0x1b1723b8, 0x25991a64, 0x3dd0419e, 0x36918c0, 0xe3e9}}, + /*.y =*/{/*.val =*/{0x1b0d1cf9, 0x5b3dfc, 0x984d3d1, 0x2c7be5f3, 0x2e76afb, 0x3eaa431c, 0x178bb00, 0xef0015b, 0xfbe5}}}, +{/*.x =*/{/*.val =*/{0x141d0ce6, 0x13f0f72d, 0x3598d41f, 0x2264a8b3, 0x205fb274, 0x53338ce, 0x1a9412ee, 0x168a4dfc, 0x1429}}, + /*.y =*/{/*.val =*/{0x1738bb86, 0xaa06a2b, 0x35d241a5, 0x2255806, 0x83b131, 0xc711211, 0x150711b0, 0x14d8f7c4, 0xfea7}}}, +{/*.x =*/{/*.val =*/{0xb344f7f, 0x1c633e71, 0xce60c4c, 0x22e27f52, 0x26d410ee, 0x1f8cb2f4, 0x2e0ae0e9, 0x3212f65c, 0x354c}}, + /*.y =*/{/*.val =*/{0x25db82d6, 0x392c46ba, 0x202e0ec7, 0xdb18061, 0x3a88558e, 0x2d24fe6, 0x6b5d675, 0x2fca4a47, 0x9c04}}}, +{/*.x =*/{/*.val =*/{0x1983ce4e, 0x2ecf54dc, 0x1578253f, 0x40f6279, 0x23024a60, 0xeee0d6a, 0x35975f0e, 0x3da7674c, 0x8704}}, + /*.y =*/{/*.val =*/{0x16572c0a, 0x1c256368, 0x302df498, 0x16e840b8, 0x296bac34, 0x231d35d6, 0x2ec26a3, 0x14817389, 0x6b0b}}}, +{/*.x =*/{/*.val =*/{0x3a3979b5, 0xa8666c2, 0x27e829e2, 0xa23e379, 0x240e50ba, 0xdfc2c7b, 0x1e26327f, 0x1f1736b, 0xae22}}, + /*.y =*/{/*.val =*/{0x450fa6f, 0x23cf359a, 0x3d4f8896, 0x2a1edf4d, 0x2d7060fc, 0x3249148e, 0x39f71ad4, 0x3f944301, 0xea91}}}, +{/*.x =*/{/*.val =*/{0x2ce4dd6a, 0x16784787, 0x3221cef5, 0x392728, 0x164c460a, 0x3b28dfa3, 0x12b64bc9, 0x393dec9e, 0x49db}}, + /*.y =*/{/*.val =*/{0x2a9e3eae, 0x4edca90, 0x205bb69b, 0xe154bf2, 0x12255a1c, 0x3f8cf6da, 0x81c72c5, 0x1ca611c1, 0xb8b5}}}, +{/*.x =*/{/*.val =*/{0x34e5f03a, 0x3fa2d6f7, 0x21606d54, 0x1597fac7, 0x3dfe3596, 0x373eccf5, 0x1be33737, 0x13f740a2, 0x80c3}}, + /*.y =*/{/*.val =*/{0x3e3ca504, 0x5fd151b, 0x33245cb1, 0x2cabbc7, 0x1c9a03d3, 0x36d5c01f, 0x1ecd55e, 0x215a9e3, 0x247e}}}, +{/*.x =*/{/*.val =*/{0x29565331, 0x20617fbe, 0x1a915abf, 0x17a2498b, 0xcf1ce93, 0xe7bed50, 0x30c22611, 0x1493240d, 0x9d32}}, + /*.y =*/{/*.val =*/{0x26f06930, 0x758c2a, 0x236934f9, 0x32544bb0, 0x6d2ae5c, 0x3b130b2f, 0x22ebfd7f, 0x15cf49df, 0x3766}}}, +{/*.x =*/{/*.val =*/{0x354b8367, 0x25201cf5, 0x3d506bfe, 0x1d6ddf59, 0x36a5db7, 0x2a975161, 0x2526e40c, 0x252b911, 0x5e5a}}, + /*.y =*/{/*.val =*/{0x11ce85ca, 0x14ca6a76, 0x1e5ffa44, 0x1aaa7bcf, 0x2a4b7a79, 0x2407c55c, 0x15e05c2c, 0x3e32691e, 0xae8a}}}, +{/*.x =*/{/*.val =*/{0xcbcad59, 0x2c17a0d8, 0xe0aaa07, 0x21168169, 0x3902f17c, 0x5f21697, 0x36007aa, 0x1b0454ab, 0x2ed7}}, + /*.y =*/{/*.val =*/{0x4ea66fe, 0x12b1ea27, 0xa7f9411, 0x1cb1804c, 0x1767ed5f, 0x29babb20, 0x5f222cd, 0x135010ee, 0x639f}}}, +{/*.x =*/{/*.val =*/{0x24b84b48, 0xc3d15c7, 0x1e817ea8, 0x2b7d31e6, 0x17f7091, 0x43d5df5, 0x1a4f5419, 0x37c39f51, 0x5fb1}}, + /*.y =*/{/*.val =*/{0x37be8eb8, 0x1fb7a9a8, 0x33f21ad7, 0xa70e421, 0x2d258206, 0x3d191bf9, 0x4d49fbc, 0x3eef2f0f, 0x2152}}}, +{/*.x =*/{/*.val =*/{0x2aa2a748, 0x15d87054, 0x378c403d, 0x2c99f85, 0x2835d8c9, 0x337e7d1a, 0x141486c5, 0x27edac70, 0x135a}}, + /*.y =*/{/*.val =*/{0x38a6cf84, 0xc41675b, 0x3f91ab2d, 0x19b84fa2, 0x9453a65, 0x18b97f9c, 0x15938e7, 0x778b2a8, 0xa869}}}, +{/*.x =*/{/*.val =*/{0xfd69985, 0x2717764, 0x1df72aea, 0xc2732db, 0xccf149f, 0x3da437ef, 0x32f7e788, 0x1d9d73ad, 0xae9}}, + /*.y =*/{/*.val =*/{0x1409a003, 0x2723ad04, 0x2ee1aff8, 0x2e67505e, 0x1a54c5d0, 0x237fb814, 0x8d14e9b, 0x265cfdb9, 0x9121}}}, +{/*.x =*/{/*.val =*/{0x2078afb0, 0x39d6b9e5, 0x1261974, 0x3fc4b1b1, 0x2d170714, 0x3511a319, 0x163b5248, 0x1af35d98, 0x209d}}, + /*.y =*/{/*.val =*/{0x2740b310, 0x1746ddd6, 0x1f4e3e38, 0x3b6de4ce, 0x98a5b01, 0x196eaea6, 0x33280a09, 0x4d0a79e, 0x1a2f}}}, +{/*.x =*/{/*.val =*/{0x1f55a9bf, 0x2f2c0a63, 0x1ea5bf8e, 0x2c057bca, 0x17c578f6, 0xc1fd807, 0x23181810, 0x263ae71b, 0x7262}}, + /*.y =*/{/*.val =*/{0x3c3accae, 0x45be2c2, 0x673b4e, 0x1e5ef2f0, 0x1099e0be, 0xd68bbcf, 0x29bfda98, 0x22006a77, 0x38d4}}}, +{/*.x =*/{/*.val =*/{0x3dbb04fa, 0x5c195a8, 0x118911f9, 0x29c145ac, 0x26b5e114, 0x2e090979, 0x26ed4d7c, 0xb7eecd1, 0x7fe4}}, + /*.y =*/{/*.val =*/{0x21908c89, 0x359d2447, 0x2c1b9c55, 0x3a28a234, 0x334cf0aa, 0x1b22c1e5, 0x5f4330f, 0x1e82d3d7, 0x2eec}}}, +{/*.x =*/{/*.val =*/{0x2e4b3ba0, 0x2167d8d7, 0x18bf1f17, 0xaafbd7c, 0x3f245f5c, 0x385c3cc6, 0x3fb73bef, 0x4414887, 0x4108}}, + /*.y =*/{/*.val =*/{0x17525595, 0x21a58770, 0x1a064554, 0xd926159, 0x2b849813, 0x2996b875, 0x35668f2c, 0x3cda5dbf, 0xdc37}}}, +{/*.x =*/{/*.val =*/{0xe5485, 0x22799a8, 0x1da5df02, 0x4c1a2fd, 0x320f1245, 0x31c2189c, 0x2bdff8e2, 0x1db5e4e8, 0x1cd2}}, + /*.y =*/{/*.val =*/{0x85fbd7f, 0x2973c146, 0x209a4ecc, 0x34389c2c, 0x2e977f99, 0x2cd35154, 0x2af738d4, 0x2f7462cb, 0x6615}}}, +{/*.x =*/{/*.val =*/{0x290bc03e, 0x31d4f566, 0x1e015e33, 0x2c3ce4d4, 0x50f8084, 0x2a497dd1, 0x2072e9e5, 0x363b4b20, 0x2cee}}, + /*.y =*/{/*.val =*/{0x3ab82adc, 0x32dcae2d, 0xd53cd01, 0x77e73c8, 0x7daeb4a, 0x143adebf, 0x1de3ecd8, 0x1ae03a6e, 0xa427}}}, +{/*.x =*/{/*.val =*/{0x3009ee3e, 0x2e71352e, 0x729ead5, 0x9a8799e, 0x272de237, 0x273af1, 0x22ac92b7, 0x216c0cba, 0xb17a}}, + /*.y =*/{/*.val =*/{0x296b911d, 0x18f947b, 0x446fa38, 0x85b29f2, 0x26eda65, 0x63f703, 0x29a65f5c, 0x9a749ac, 0x966e}}}, +{/*.x =*/{/*.val =*/{0xe103dd6, 0x37dc51c8, 0x4859a, 0x1181301f, 0x12a17ac3, 0x84f3f16, 0x203f836a, 0x1ef55690, 0xbc47}}, + /*.y =*/{/*.val =*/{0x16f7c343, 0xe420b63, 0x23b44ac6, 0xa4d5cb1, 0x1ea6395d, 0x2b154b1b, 0xdd526cb, 0x7890a6a, 0xe31e}}}, +{/*.x =*/{/*.val =*/{0x36695f94, 0xb602c60, 0x1627fa59, 0x285a71a4, 0x39a9cf62, 0x32e1a0eb, 0x18f5fd0c, 0x17546d15, 0xb1d2}}, + /*.y =*/{/*.val =*/{0x1ee32736, 0x16dfae69, 0x3863edca, 0x3dbc636a, 0x2ba81760, 0x3a82b066, 0x290b1f7b, 0x369c80c3, 0x706d}}}, +{/*.x =*/{/*.val =*/{0x36f83231, 0x265c4062, 0x20425e34, 0x30c3639d, 0x33fdd0b7, 0x5609d96, 0x2ba26a8d, 0x23314d40, 0x850f}}, + /*.y =*/{/*.val =*/{0x1f2e8373, 0x280c6a75, 0x322d77f4, 0x216fe85d, 0x2cc7890a, 0x3dc21ae0, 0x39053d0b, 0x276f80a9, 0xbc4a}}}, +{/*.x =*/{/*.val =*/{0x39343959, 0xb882f6f, 0x2c9ce78a, 0x28673cbe, 0x1bc1f617, 0x2bfa4c24, 0x651465d, 0x6e01743, 0x2d38}}, + /*.y =*/{/*.val =*/{0x1442fb00, 0x1c432ba8, 0x31e45a43, 0x14b57589, 0x31025f43, 0x2bcbce90, 0x361bf59a, 0x3782534a, 0x5451}}}, +{/*.x =*/{/*.val =*/{0x152da17d, 0x18283e90, 0xd0646b1, 0x3704f6c2, 0x200bc811, 0x139ac17f, 0x18c5f089, 0x3b4783d4, 0x3bea}}, + /*.y =*/{/*.val =*/{0x2cc768d2, 0x39c12617, 0x1fec416c, 0x3379dee3, 0xe1b554, 0x12a2fafa, 0x37acdfef, 0x35fd56bf, 0xc3b0}}}, +{/*.x =*/{/*.val =*/{0x1063e1be, 0x6e6b413, 0x3e39a75c, 0x90a68bd, 0x3cf027a9, 0x185494f6, 0x2b14722, 0x10744758, 0x1316}}, + /*.y =*/{/*.val =*/{0x21fec890, 0x3747fcf8, 0x1745b77f, 0x3ebb03e, 0x3d2bebbd, 0xb8c3f36, 0x39f06a4, 0x36985e58, 0x4c3b}}}, +{/*.x =*/{/*.val =*/{0x3c46e079, 0x4a80d49, 0x1e9c78dd, 0x19a4c2e1, 0x2ba374ab, 0x3dd6b6c0, 0x3ac530fe, 0x30ab4ab3, 0xab86}}, + /*.y =*/{/*.val =*/{0x3636ffe1, 0x310a2f05, 0x50d7c0e, 0x1dca3a12, 0x3200c9ce, 0x311b535c, 0x329abcf5, 0x30a18067, 0x1209}}}, +{/*.x =*/{/*.val =*/{0x17d37248, 0x227c6075, 0x117ceae4, 0x20d6d947, 0x2b2787bc, 0x1bac891a, 0x36d5aa4d, 0x946f0fb, 0xadc4}}, + /*.y =*/{/*.val =*/{0x2adcbc1b, 0x1811f2b3, 0x50bebc8, 0x37156ec5, 0x16f70b9, 0x18f8d8a4, 0x1e7eb5d0, 0x2dd8b8f1, 0xb0f3}}}, +{/*.x =*/{/*.val =*/{0xeca5f51, 0x85ac826, 0xfc9aebf, 0x3a85c6e5, 0x5b5cfdd, 0x3b5acafc, 0x2e6962c6, 0x35453767, 0xdde9}}, + /*.y =*/{/*.val =*/{0x10c638f7, 0x2b5a69cf, 0x289571f9, 0x3fbafa37, 0x3f8f0950, 0x7cd2c29, 0x28111d89, 0x1a44cf38, 0xb84e}}}, +{/*.x =*/{/*.val =*/{0x209b0cca, 0x3331a956, 0xa4d6f01, 0x115d6249, 0x28da59a3, 0x1153da28, 0xf4c8d5c, 0x232c76ec, 0xd53}}, + /*.y =*/{/*.val =*/{0xc929e05, 0xc6c51f8, 0x9134c97, 0xd336676, 0x2ed7cf85, 0x2a357103, 0x2c110cb0, 0x1aeb1e8f, 0xc819}}}, +{/*.x =*/{/*.val =*/{0x2dd7e577, 0x2b8c0f3b, 0x136c4d56, 0x283c95a1, 0x2a2107d3, 0x1811c9c3, 0xf7b25ac, 0x3543e20a, 0xc352}}, + /*.y =*/{/*.val =*/{0x38d9b570, 0x3293fe23, 0x21217063, 0x2a2aecad, 0xe79fb00, 0x354c516f, 0x2b9b96ab, 0xa0e2e9d, 0xbe77}}}, +{/*.x =*/{/*.val =*/{0x23868246, 0x22fcdeb0, 0x6dd2ded, 0x27db62bd, 0x2248ba8, 0x17641f4b, 0x11d600b5, 0x1f82acce, 0xfb9d}}, + /*.y =*/{/*.val =*/{0x2969605a, 0x2760f82b, 0x2a2606d2, 0x34ab4c16, 0x1475f4a6, 0x2a2e05a8, 0x3680cff2, 0x26f807d2, 0xb038}}}, +{/*.x =*/{/*.val =*/{0x3712be3c, 0x1a8b8cb, 0x2146a66b, 0x257c63b6, 0x153472, 0x1c976eac, 0x1b378d3c, 0xd2764cc, 0x39d7}}, + /*.y =*/{/*.val =*/{0x1c6ff65c, 0x30c067d0, 0xa41644c, 0x17bde97b, 0x2812e8ef, 0x9d55319, 0x33bf7fb1, 0x26d3d5bb, 0x8f92}}}, +{/*.x =*/{/*.val =*/{0x37829372, 0x3b02a929, 0xba4553d, 0x26cc0322, 0x5796bc4, 0x189ab94e, 0x20d3b313, 0x273243cf, 0xb431}}, + /*.y =*/{/*.val =*/{0xadd5427, 0x1ca73300, 0x23e11bb7, 0x1ec48572, 0x21c5a270, 0x1ebf8270, 0x3502bffb, 0x3512669b, 0x4707}}}, +{/*.x =*/{/*.val =*/{0xdcbcb9e, 0x12fc449b, 0xd83c3df, 0x3e95a277, 0x143761d6, 0x30c911ff, 0x1337a9ec, 0x4b5c467, 0xcdcb}}, + /*.y =*/{/*.val =*/{0x961cfd1, 0x229616b, 0x18df340a, 0x266bc90d, 0x1e9949a1, 0x3efa825b, 0x1f11fbfe, 0x38b85eee, 0xe699}}}, +{/*.x =*/{/*.val =*/{0xe90bc26, 0x1e074991, 0x364d3aa0, 0x22880f84, 0xacd88a9, 0xf195b1d, 0x27275f3d, 0x385bd96d, 0x5e4d}}, + /*.y =*/{/*.val =*/{0x252f79e, 0x5f546a, 0x1127f9c7, 0x194f732b, 0x3ad55207, 0xebea5e0, 0x1432904e, 0x3cb90d4f, 0x5ac5}}}, +{/*.x =*/{/*.val =*/{0x754dd40, 0x18fa1c55, 0x3466cf8, 0x10898c7f, 0x32f6e9a2, 0x12107f35, 0xdfcf45b, 0x91c0cb0, 0x9729}}, + /*.y =*/{/*.val =*/{0x2aa36143, 0x212d24bc, 0x1acaf493, 0x36ba1495, 0x14df3690, 0x171d772f, 0x3ea1dcd1, 0x28910997, 0x91d1}}}, +{/*.x =*/{/*.val =*/{0xc7a89ee, 0x15f0d4cc, 0x2b6d4f80, 0x36f1671e, 0x18658a4b, 0x182e23f2, 0x179e1128, 0x29389a90, 0x71ef}}, + /*.y =*/{/*.val =*/{0x1366a2e, 0x3d224ca7, 0x25e9a0b4, 0x2abeae23, 0x3294a22a, 0x2cb0cac5, 0x224ae9ef, 0x2a07e2ed, 0x145f}}}, +{/*.x =*/{/*.val =*/{0xde0545f, 0x32c08d26, 0x106c74f5, 0x39897688, 0x3508ac80, 0x17a8012c, 0x7124a37, 0x16f31638, 0x5204}}, + /*.y =*/{/*.val =*/{0x106c3d91, 0x1ba8d301, 0x28fdaf23, 0xee743ca, 0xe312b79, 0x3b67083, 0x3123ad43, 0xc7f3af8, 0x1b3f}}}, +{/*.x =*/{/*.val =*/{0x3ddaa5d5, 0x1873f311, 0x14d4b7ab, 0x27a034e9, 0x16607331, 0x3bf9159a, 0x28c4e4e8, 0x2646e4be, 0x4e9}}, + /*.y =*/{/*.val =*/{0x2cba1c91, 0x35f800ff, 0x255f570d, 0x3827db86, 0x957303c, 0x1ab47630, 0x327f1d9e, 0x577778a, 0x62fc}}}, +{/*.x =*/{/*.val =*/{0x26a06f5e, 0x6902d65, 0x2a083702, 0x1064945b, 0x23b716a3, 0x2c350849, 0x253ac37, 0x93efa85, 0x383b}}, + /*.y =*/{/*.val =*/{0x13c6e772, 0x227d1e1b, 0x38c2b040, 0x3dab9d2e, 0x2a5a19e8, 0x3d59b553, 0x1ba2044c, 0x1c1ab13b, 0x54cf}}}, +{/*.x =*/{/*.val =*/{0x1bcf2dce, 0x4e6d023, 0x1dc6c02, 0x4528417, 0x3f998068, 0x2793264b, 0x6218bd4, 0xb50a4b9, 0x95e6}}, + /*.y =*/{/*.val =*/{0x18c86594, 0xaf77f7d, 0x304d20e6, 0x1ecc180d, 0x28d52e5e, 0x289b8ad0, 0x2875183, 0x20610a5b, 0x6b6}}}, +{/*.x =*/{/*.val =*/{0x17a6257f, 0x20149916, 0x27a6c40b, 0x1cf0ec68, 0x7e78918, 0x909d2ac, 0x14f25a64, 0xd72387d, 0x71e9}}, + /*.y =*/{/*.val =*/{0x11b1e582, 0x2c85d187, 0xf70f7a5, 0x948d503, 0x2e2a52ef, 0x361ae91e, 0x22513de, 0xf967d1f, 0x78d9}}}, +}; #endif diff --git a/secp256k1.h b/secp256k1.h index ebeff415a..e3a5f5378 100644 --- a/secp256k1.h +++ b/secp256k1.h @@ -54,6 +54,7 @@ extern const bignum256 secp256k1_iv[256]; #if USE_PRECOMPUTED_CP extern const curve_point secp256k1_cp[256]; +extern const curve_point secp256k1_cp2[255]; #endif #endif From eec5f7df15f1c78e9dba2e78a8f92d859975c9d9 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 3 Jul 2014 10:16:19 +0200 Subject: [PATCH 108/627] fix bug in unoptimized branch of code --- ecdsa.c | 4 ++-- tests.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ecdsa.c b/ecdsa.c index e8d5cdad2..6d639312f 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -155,10 +155,10 @@ void scalar_multiply(const bignum256 *k, curve_point *res) point_add(&curr, res); #endif } + } #if ! USE_PRECOMPUTED_CP - point_double(&curr); + point_double(&curr); #endif - } } bn_mod(&(res->x), &prime256k1); bn_mod(&(res->y), &prime256k1); diff --git a/tests.c b/tests.c index a6e33305c..af80c74a5 100644 --- a/tests.c +++ b/tests.c @@ -325,7 +325,7 @@ START_TEST(test_bip32_compare) int i, r; hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, &node1); hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, &node2); - for (i = 0; i < 300; i++) { + for (i = 0; i < 100; i++) { memcpy(&node3, &node1, sizeof(HDNode)); r = hdnode_private_ckd(&node1, i); ck_assert_int_eq(r, 1); r = hdnode_public_ckd(&node2, i); ck_assert_int_eq(r, 1); From abf717831995ffce7ad0bc2bb7d1e34aa7e3e27d Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 3 Jul 2014 16:59:41 +0200 Subject: [PATCH 109/627] add "small" switch to makefile --- Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Makefile b/Makefile index 60e9f4a8d..5dd5c3657 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,8 @@ CC = gcc CFLAGS = -Wall -Wextra -Os -Wno-sequence-point +ifdef SMALL +CFLAGS += -DUSE_PRECOMPUTED_IV=0 -DUSE_PRECOMPUTED_CP=0 +endif OBJS = bignum.o ecdsa.o secp256k1.o rand.o hmac.o bip32.o bip39.o pbkdf2.o base58.o OBJS += ripemd160.o OBJS += sha2.o From 82ed3f31dbc08ba6500bf3ea13a3c4ad094251cb Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 4 Jul 2014 15:07:02 +0200 Subject: [PATCH 110/627] fix comparison of points --- ecdsa.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ecdsa.c b/ecdsa.c index 6d639312f..62d1cfbde 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -460,9 +460,9 @@ int ecdsa_verify_digest(const uint8_t *pub_key, const uint8_t *sig, const uint8_ for (j = 0; j < 30; j++) { if (i == 8 && (s.val[i] >> j) == 0) break; if (s.val[i] & (1u << j)) { - bn_mod(&(pub.y), &prime256k1); - bn_mod(&(res.y), &prime256k1); - if (bn_is_equal(&(pub.y), &(res.y))) { + bn_mod(&(pub.x), &prime256k1); + bn_mod(&(res.x), &prime256k1); + if (bn_is_equal(&(pub.x), &(res.x))) { // this is not a failure, but a very inprobable case // that we don't handle because of its inprobability return 4; From da6a09880d1a144e34d8963552594619a650f22a Mon Sep 17 00:00:00 2001 From: Ondrej Mikle Date: Fri, 4 Jul 2014 15:12:58 +0200 Subject: [PATCH 111/627] Handling of special cases in EC arithmetic. --- ecdsa.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ecdsa.h | 4 ++++ 2 files changed, 64 insertions(+) diff --git a/ecdsa.c b/ecdsa.c index 62d1cfbde..2706a559e 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -33,12 +33,38 @@ #include "ecdsa.h" #include "base58.h" +// Set cp2 = cp1 +void point_copy(const curve_point *cp1, curve_point *cp2) +{ + memcpy(&(cp2->x), &(cp1->x), sizeof(bignum256)); + memcpy(&(cp2->y), &(cp1->y), sizeof(bignum256)); +} + // cp2 = cp1 + cp2 void point_add(const curve_point *cp1, curve_point *cp2) { int i; uint32_t temp; bignum256 lambda, inv, xr, yr; + + if (point_is_infinity(cp1)) { + return; + } + if (point_is_infinity(cp2)) { + point_copy(cp1, cp2); + return; + } + if (point_is_equal(cp1, cp2)) { + point_double(cp2); + return; + } + if (point_is_negative_of(cp1, cp2)) { + // set to point at infinity + bn_zero(&(cp2->x)); + bn_zero(&(cp2->y)); + return; + } + bn_substract(&(cp2->x), &(cp1->x), &inv); bn_inverse(&inv, &prime256k1); bn_substract(&(cp2->y), &(cp1->y), &lambda); @@ -68,6 +94,11 @@ void point_double(curve_point *cp) int i; uint32_t temp; bignum256 lambda, inverse_y, xr, yr; + + if (point_is_infinity(cp)) { + return; + } + memcpy(&inverse_y, &(cp->y), sizeof(bignum256)); bn_inverse(&inverse_y, &prime256k1); memcpy(&lambda, &three_over_two256k1, sizeof(bignum256)); @@ -120,6 +151,35 @@ void point_multiply(const bignum256 *k, const curve_point *p, curve_point *res) bn_mod(&(res->y), &prime256k1); } +// return true iff p represent point at infinity +// both coords are zero in internal representation +int point_is_infinity(const curve_point *p) +{ + return bn_is_zero(&(p->x)) && bn_is_zero(&(p->y)); +} + +// return true iff both points are equal +int point_is_equal(const curve_point *p, const curve_point *q) +{ + return bn_is_equal(&(p->x), &(q->x)) && bn_is_equal(&(p->y), &(q->y)); +} + +// returns true iff p == -q +int point_is_negative_of(const curve_point *p, const curve_point *q) +{ + // if P == (x, y), then -P would be (x, -y) on this curve + bignum256 y_added; + + if (!bn_is_equal(&(p->x), &(q->x))) { + return 0; + } + + memcpy(&y_added, &(p->y), sizeof(bignum256)); + bn_addmod(&y_added, &(q->y), &prime256k1); + + return bn_is_zero(&y_added); +} + // res = k * G void scalar_multiply(const bignum256 *k, curve_point *res) { diff --git a/ecdsa.h b/ecdsa.h index 3e2dede55..40eef61cb 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -32,9 +32,13 @@ #define USE_RFC6979 1 #endif +void point_copy(const curve_point *cp1, curve_point *cp2); void point_add(const curve_point *cp1, curve_point *cp2); void point_double(curve_point *cp); void point_multiply(const bignum256 *k, const curve_point *p, curve_point *res); +int point_is_infinity(const curve_point *p); +int point_is_equal(const curve_point *p, const curve_point *q); +int point_is_negative_of(const curve_point *p, const curve_point *q); void scalar_multiply(const bignum256 *k, curve_point *res); void uncompress_coords(uint8_t odd, const bignum256 *x, bignum256 *y); From 6d61cefdb38659634c7fd9d99bc60708b6b78236 Mon Sep 17 00:00:00 2001 From: Ondrej Mikle Date: Fri, 4 Jul 2014 15:50:29 +0200 Subject: [PATCH 112/627] Removed test for point equality in ecdsa_verify_digest, point_add() already handles that. --- ecdsa.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/ecdsa.c b/ecdsa.c index 2706a559e..7a98fcb5b 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -520,13 +520,6 @@ int ecdsa_verify_digest(const uint8_t *pub_key, const uint8_t *sig, const uint8_ for (j = 0; j < 30; j++) { if (i == 8 && (s.val[i] >> j) == 0) break; if (s.val[i] & (1u << j)) { - bn_mod(&(pub.x), &prime256k1); - bn_mod(&(res.x), &prime256k1); - if (bn_is_equal(&(pub.x), &(res.x))) { - // this is not a failure, but a very inprobable case - // that we don't handle because of its inprobability - return 4; - } point_add(&pub, &res); } point_double(&pub); From d827b2c862fd305d9d8d4bae762ae0e23bb339db Mon Sep 17 00:00:00 2001 From: Ondrej Mikle Date: Fri, 4 Jul 2014 17:40:07 +0200 Subject: [PATCH 113/627] Account for case when point.y == 0 when doubling. --- ecdsa.c | 21 +++++++++++++++------ ecdsa.h | 1 + 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/ecdsa.c b/ecdsa.c index 7a98fcb5b..20ef26c25 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -54,14 +54,12 @@ void point_add(const curve_point *cp1, curve_point *cp2) point_copy(cp1, cp2); return; } - if (point_is_equal(cp1, cp2)) { - point_double(cp2); + if (point_is_negative_of(cp1, cp2)) { + point_set_infinity(cp2); return; } - if (point_is_negative_of(cp1, cp2)) { - // set to point at infinity - bn_zero(&(cp2->x)); - bn_zero(&(cp2->y)); + if (point_is_equal(cp1, cp2)) { + point_double(cp2); return; } @@ -98,6 +96,10 @@ void point_double(curve_point *cp) if (point_is_infinity(cp)) { return; } + if (bn_is_zero(&(cp->y))) { + point_set_infinity(cp); + return; + } memcpy(&inverse_y, &(cp->y), sizeof(bignum256)); bn_inverse(&inverse_y, &prime256k1); @@ -151,6 +153,13 @@ void point_multiply(const bignum256 *k, const curve_point *p, curve_point *res) bn_mod(&(res->y), &prime256k1); } +// set point to internal representation of point at infinity +void point_set_infinity(curve_point *p) +{ + bn_zero(&(p->x)); + bn_zero(&(p->y)); +} + // return true iff p represent point at infinity // both coords are zero in internal representation int point_is_infinity(const curve_point *p) diff --git a/ecdsa.h b/ecdsa.h index 40eef61cb..5aaf7d633 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -36,6 +36,7 @@ void point_copy(const curve_point *cp1, curve_point *cp2); void point_add(const curve_point *cp1, curve_point *cp2); void point_double(curve_point *cp); void point_multiply(const bignum256 *k, const curve_point *p, curve_point *res); +void point_set_infinity(curve_point *p); int point_is_infinity(const curve_point *p); int point_is_equal(const curve_point *p, const curve_point *q); int point_is_negative_of(const curve_point *p, const curve_point *q); From 70da2c6be35aeafd7fadcd4393a89db5a9c6ab03 Mon Sep 17 00:00:00 2001 From: Dustin Laurence Date: Fri, 4 Jul 2014 14:11:27 -0500 Subject: [PATCH 114/627] Add required libraries to build on Linux --- Makefile | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 5dd5c3657..00521f6c5 100644 --- a/Makefile +++ b/Makefile @@ -8,16 +8,19 @@ OBJS += ripemd160.o OBJS += sha2.o OBJS += aescrypt.o aeskey.o aestab.o aes_modes.o +TESTLIBS = -lcheck -lrt -lpthread -lm +TESTSSLLIBS = -lcrypto + all: tests test-openssl %.o: %.c %.h $(CC) $(CFLAGS) -o $@ -c $< tests: tests.o $(OBJS) - gcc tests.o $(OBJS) -lcheck -o tests + gcc tests.o $(OBJS) $(TESTLIBS) -o tests test-openssl: test-openssl.o $(OBJS) - gcc test-openssl.o $(OBJS) -o test-openssl -lcrypto + gcc test-openssl.o $(OBJS) $(TESTSSLLIBS) -o test-openssl clean: rm -f *.o tests test-openssl From 6f7bb6fb6bf27b90dbcb4b16583836c851c35324 Mon Sep 17 00:00:00 2001 From: Dustin Laurence Date: Fri, 4 Jul 2014 14:53:32 -0500 Subject: [PATCH 115/627] Add Makefile comments --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index 00521f6c5..7bbdce123 100644 --- a/Makefile +++ b/Makefile @@ -8,9 +8,11 @@ OBJS += ripemd160.o OBJS += sha2.o OBJS += aescrypt.o aeskey.o aestab.o aes_modes.o +# Required libraries for Linux TESTLIBS = -lcheck -lrt -lpthread -lm TESTSSLLIBS = -lcrypto + all: tests test-openssl %.o: %.c %.h From 323da2d4343971f200380fbb0360d87879fb1f06 Mon Sep 17 00:00:00 2001 From: Ondrej Mikle Date: Sat, 5 Jul 2014 22:07:03 +0200 Subject: [PATCH 116/627] Keep results after point_add() and point_double() inside the finite field. Simplified point_is_negative_of(). --- ecdsa.c | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/ecdsa.c b/ecdsa.c index 20ef26c25..0016441f0 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -54,14 +54,14 @@ void point_add(const curve_point *cp1, curve_point *cp2) point_copy(cp1, cp2); return; } - if (point_is_negative_of(cp1, cp2)) { - point_set_infinity(cp2); - return; - } if (point_is_equal(cp1, cp2)) { point_double(cp2); return; } + if (point_is_negative_of(cp1, cp2)) { + point_set_infinity(cp2); + return; + } bn_substract(&(cp2->x), &(cp1->x), &inv); bn_inverse(&inv, &prime256k1); @@ -84,6 +84,8 @@ void point_add(const curve_point *cp1, curve_point *cp2) bn_fast_mod(&yr, &prime256k1); memcpy(&(cp2->x), &xr, sizeof(bignum256)); memcpy(&(cp2->y), &yr, sizeof(bignum256)); + bn_mod(&(cp2->x), &prime256k1); + bn_mod(&(cp2->y), &prime256k1); } // cp = cp + cp @@ -124,6 +126,8 @@ void point_double(curve_point *cp) bn_fast_mod(&yr, &prime256k1); memcpy(&(cp->x), &xr, sizeof(bignum256)); memcpy(&(cp->y), &yr, sizeof(bignum256)); + bn_mod(&(cp->x), &prime256k1); + bn_mod(&(cp->y), &prime256k1); } // res = k * p @@ -174,19 +178,20 @@ int point_is_equal(const curve_point *p, const curve_point *q) } // returns true iff p == -q +// expects p and q be valid points on curve other than point at infinity int point_is_negative_of(const curve_point *p, const curve_point *q) { // if P == (x, y), then -P would be (x, -y) on this curve - bignum256 y_added; - if (!bn_is_equal(&(p->x), &(q->x))) { return 0; } - - memcpy(&y_added, &(p->y), sizeof(bignum256)); - bn_addmod(&y_added, &(q->y), &prime256k1); - - return bn_is_zero(&y_added); + + // we shouldn't hit this for a valid point + if (bn_is_zero(&(p->y))) { + return 0; + } + + return !bn_is_equal(&(p->y), &(q->y)); } // res = k * G From 7fd81a1e0c967cfe505f6fda66d9488b93694f77 Mon Sep 17 00:00:00 2001 From: Ondrej Mikle Date: Sun, 6 Jul 2014 14:50:12 +0200 Subject: [PATCH 117/627] Removed superfluous bn_mod, it's done now in point_add and point_double. --- ecdsa.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/ecdsa.c b/ecdsa.c index 0016441f0..8dcfd0748 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -153,8 +153,6 @@ void point_multiply(const bignum256 *k, const curve_point *p, curve_point *res) point_double(&curr); } } - bn_mod(&(res->x), &prime256k1); - bn_mod(&(res->y), &prime256k1); } // set point to internal representation of point at infinity @@ -234,8 +232,6 @@ void scalar_multiply(const bignum256 *k, curve_point *res) point_double(&curr); #endif } - bn_mod(&(res->x), &prime256k1); - bn_mod(&(res->y), &prime256k1); } // generate random K for signing @@ -540,7 +536,6 @@ int ecdsa_verify_digest(const uint8_t *pub_key, const uint8_t *sig, const uint8_ } } - bn_mod(&(res.x), &prime256k1); bn_mod(&(res.x), &order256k1); // signature does not match From 03fee345506b6e2ac10fd5caff3afbf4938cee28 Mon Sep 17 00:00:00 2001 From: Ondrej Mikle Date: Mon, 7 Jul 2014 14:38:14 +0200 Subject: [PATCH 118/627] Validating of public key curve point. --- ecdsa.c | 47 +++++++++++++++++++++++++++++++++++++++++++++-- ecdsa.h | 1 + 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/ecdsa.c b/ecdsa.c index 8dcfd0748..14d1d9914 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -459,17 +459,60 @@ int ecdsa_read_pubkey(const uint8_t *pub_key, curve_point *pub) if (pub_key[0] == 0x04) { bn_read_be(pub_key + 1, &(pub->x)); bn_read_be(pub_key + 33, &(pub->y)); - return 1; + return ecdsa_validate_pubkey(pub); } if (pub_key[0] == 0x02 || pub_key[0] == 0x03) { // compute missing y coords bn_read_be(pub_key + 1, &(pub->x)); uncompress_coords(pub_key[0], &(pub->x), &(pub->y)); - return 1; + return ecdsa_validate_pubkey(pub); } // error return 0; } +// Verifies that: +// - pub is not the point at infinity. +// - pub->x and pub->y are in range [0,p-1]. +// - pub is on the curve. +// - n*pub is the point at infinity. + +int ecdsa_validate_pubkey(const curve_point *pub) +{ + bignum256 y_2, x_3_b; + curve_point temp; + + if (point_is_infinity(pub)) { + return 0; + } + + if (!bn_is_less(&(pub->x), &prime256k1) || !bn_is_less(&(pub->y), &prime256k1)) { + return 0; + } + + memcpy(&y_2, &(pub->y), sizeof(bignum256)); + memcpy(&x_3_b, &(pub->x), sizeof(bignum256)); + + // y^2 + bn_multiply(&(pub->y), &y_2, &prime256k1); + // x^3 + b + bn_multiply(&(pub->x), &x_3_b, &prime256k1); + bn_multiply(&(pub->x), &x_3_b, &prime256k1); + bn_addmodi(&x_3_b, 7, &prime256k1); + + if (!bn_is_equal(&x_3_b, &y_2)) { + return 0; + } + + point_copy(pub, &temp); + point_multiply(&order256k1, pub, &temp); + + if (!point_is_infinity(&temp)) { + return 0; + } + + return 1; +} + // uses secp256k1 curve // pub_key - 65 bytes uncompressed key // signature - 64 bytes signature diff --git a/ecdsa.h b/ecdsa.h index 5aaf7d633..b1a1e7e37 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -53,6 +53,7 @@ void ecdsa_get_address(const uint8_t *pub_key, uint8_t version, char *addr); void ecdsa_get_wif(const uint8_t *priv_key, uint8_t version, char *wif); int ecdsa_address_decode(const char *addr, uint8_t *out); int ecdsa_read_pubkey(const uint8_t *pub_key, curve_point *pub); +int ecdsa_validate_pubkey(const curve_point *pub); int ecdsa_verify(const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, uint32_t msg_len); int ecdsa_verify_double(const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, uint32_t msg_len); int ecdsa_verify_digest(const uint8_t *pub_key, const uint8_t *sig, const uint8_t *digest); From 02048f88b5b99d6ad3a630b461c5be956f00bb30 Mon Sep 17 00:00:00 2001 From: Ondrej Mikle Date: Mon, 7 Jul 2014 15:13:36 +0200 Subject: [PATCH 119/627] Tests for public key validity check. --- tests.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/tests.c b/tests.c index af80c74a5..a3f45fd5a 100644 --- a/tests.c +++ b/tests.c @@ -852,6 +852,54 @@ START_TEST(test_address) } END_TEST +START_TEST(test_pubkey_validity) +{ + uint8_t pub_key[65]; + curve_point pub; + int res; + + memcpy(pub_key, fromhex("0226659c1cf7321c178c07437150639ff0c5b7679c7ea195253ed9abda2e081a37"), 33); + res = ecdsa_read_pubkey(pub_key, &pub); + ck_assert_int_eq(res, 1); + + memcpy(pub_key, fromhex("025b1654a0e78d28810094f6c5a96b8efb8a65668b578f170ac2b1f83bc63ba856"), 33); + res = ecdsa_read_pubkey(pub_key, &pub); + ck_assert_int_eq(res, 1); + + memcpy(pub_key, fromhex("03433f246a12e6486a51ff08802228c61cf895175a9b49ed4766ea9a9294a3c7fe"), 33); + res = ecdsa_read_pubkey(pub_key, &pub); + ck_assert_int_eq(res, 1); + + memcpy(pub_key, fromhex("03aeb03abeee0f0f8b4f7a5d65ce31f9570cef9f72c2dd8a19b4085a30ab033d48"), 33); + res = ecdsa_read_pubkey(pub_key, &pub); + ck_assert_int_eq(res, 1); + + memcpy(pub_key, fromhex("0496e8f2093f018aff6c2e2da5201ee528e2c8accbf9cac51563d33a7bb74a016054201c025e2a5d96b1629b95194e806c63eb96facaedc733b1a4b70ab3b33e3a"), 65); + res = ecdsa_read_pubkey(pub_key, &pub); + ck_assert_int_eq(res, 1); + + memcpy(pub_key, fromhex("0498010f8a687439ff497d3074beb4519754e72c4b6220fb669224749591dde416f3961f8ece18f8689bb32235e436874d2174048b86118a00afbd5a4f33a24f0f"), 65); + res = ecdsa_read_pubkey(pub_key, &pub); + ck_assert_int_eq(res, 1); + + memcpy(pub_key, fromhex("04f80490839af36d13701ec3f9eebdac901b51c362119d74553a3c537faff31b17e2a59ebddbdac9e87b816307a7ed5b826b8f40b92719086238e1bebf19b77a4d"), 65); + res = ecdsa_read_pubkey(pub_key, &pub); + ck_assert_int_eq(res, 1); + + memcpy(pub_key, fromhex("04f80490839af36d13701ec3f9eebdac901b51c362119d74553a3c537faff31b17e2a59ebddbdac9e87b816307a7ed5b826b8f40b92719086238e1bebf00000000"), 65); + res = ecdsa_read_pubkey(pub_key, &pub); + ck_assert_int_eq(res, 0); + + memcpy(pub_key, fromhex("04f80490839af36d13701ec3f9eebdac901b51c362119d74553a3c537faff31b17e2a59ebddbdac9e87b816307a7ed5b8211111111111111111111111111111111"), 65); + res = ecdsa_read_pubkey(pub_key, &pub); + ck_assert_int_eq(res, 0); + + memcpy(pub_key, fromhex("00"), 1); + res = ecdsa_read_pubkey(pub_key, &pub); + ck_assert_int_eq(res, 0); +} +END_TEST + START_TEST(test_wif) { uint8_t priv_key[32]; @@ -1031,6 +1079,10 @@ Suite *test_suite(void) tcase_add_test(tc, test_mnemonic_check); suite_add_tcase(s, tc); + tc = tcase_create("pubkey_validity"); + tcase_add_test(tc, test_pubkey_validity); + suite_add_tcase(s, tc); + return s; } From b34516bc49cb9dbae6fb6eeb95e325a03a11c036 Mon Sep 17 00:00:00 2001 From: Ondrej Mikle Date: Mon, 7 Jul 2014 16:35:53 +0200 Subject: [PATCH 120/627] Removed unnessary point copy. --- ecdsa.c | 1 - 1 file changed, 1 deletion(-) diff --git a/ecdsa.c b/ecdsa.c index 14d1d9914..df7847533 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -503,7 +503,6 @@ int ecdsa_validate_pubkey(const curve_point *pub) return 0; } - point_copy(pub, &temp); point_multiply(&order256k1, pub, &temp); if (!point_is_infinity(&temp)) { From b9d589617418ec5394a90879f7365eaec43cd85d Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 7 Jul 2014 20:14:15 +0200 Subject: [PATCH 121/627] make pubkey validation optional, extract options to separate header --- Makefile | 4 ++-- bignum.h | 20 +------------------- ecdsa.c | 8 ++++++++ ecdsa.h | 6 +----- options.h | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ tests.c | 9 ++++++--- 6 files changed, 74 insertions(+), 29 deletions(-) create mode 100644 options.h diff --git a/Makefile b/Makefile index 00521f6c5..746306110 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ CC = gcc CFLAGS = -Wall -Wextra -Os -Wno-sequence-point ifdef SMALL -CFLAGS += -DUSE_PRECOMPUTED_IV=0 -DUSE_PRECOMPUTED_CP=0 +CFLAGS += -DUSE_PRECOMPUTED_IV=0 -DUSE_PRECOMPUTED_CP=0 -DUSE_PUBKEY_VALIDATE=0 endif OBJS = bignum.o ecdsa.o secp256k1.o rand.o hmac.o bip32.o bip39.o pbkdf2.o base58.o OBJS += ripemd160.o @@ -13,7 +13,7 @@ TESTSSLLIBS = -lcrypto all: tests test-openssl -%.o: %.c %.h +%.o: %.c %.h options.h $(CC) $(CFLAGS) -o $@ -c $< tests: tests.o $(OBJS) diff --git a/bignum.h b/bignum.h index 2e3a3917a..2fa65568c 100644 --- a/bignum.h +++ b/bignum.h @@ -25,21 +25,7 @@ #define __BIGNUM_H__ #include - -// use precomputed Inverse Values of powers of two -#ifndef USE_PRECOMPUTED_IV -#define USE_PRECOMPUTED_IV 1 -#endif - -// use precomputed Curve Points (some scalar multiples of curve base point G) -#ifndef USE_PRECOMPUTED_CP -#define USE_PRECOMPUTED_CP 1 -#endif - -// use fast inverse method -#ifndef USE_INVERSE_FAST -#define USE_INVERSE_FAST 1 -#endif +#include "options.h" // bignum256 are 256 bits stored as 8*30 bit + 1*16 bit // val[0] are lowest 30 bits, val[8] highest 16 bits @@ -97,10 +83,6 @@ void bn_substract_noprime(const bignum256 *a, const bignum256 *b, bignum256 *res void bn_divmod58(bignum256 *a, uint32_t *r); -#ifndef BN_PRINT -#define BN_PRINT 0 -#endif - #if BN_PRINT void bn_print(const bignum256 *a); void bn_print_raw(const bignum256 *a); diff --git a/ecdsa.c b/ecdsa.c index df7847533..f5cd4f226 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -459,12 +459,20 @@ int ecdsa_read_pubkey(const uint8_t *pub_key, curve_point *pub) if (pub_key[0] == 0x04) { bn_read_be(pub_key + 1, &(pub->x)); bn_read_be(pub_key + 33, &(pub->y)); +#ifdef USE_PUBKEY_VALIDATE return ecdsa_validate_pubkey(pub); +#else + return 1; +#endif } if (pub_key[0] == 0x02 || pub_key[0] == 0x03) { // compute missing y coords bn_read_be(pub_key + 1, &(pub->x)); uncompress_coords(pub_key[0], &(pub->x), &(pub->y)); +#ifdef USE_PUBKEY_VALIDATE return ecdsa_validate_pubkey(pub); +#else + return 1; +#endif } // error return 0; diff --git a/ecdsa.h b/ecdsa.h index b1a1e7e37..2de5bcdfa 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -25,13 +25,9 @@ #define __ECDSA_H__ #include - +#include "options.h" #include "secp256k1.h" -#ifndef USE_RFC6979 -#define USE_RFC6979 1 -#endif - void point_copy(const curve_point *cp1, curve_point *cp2); void point_add(const curve_point *cp1, curve_point *cp2); void point_double(curve_point *cp); diff --git a/options.h b/options.h new file mode 100644 index 000000000..85285e395 --- /dev/null +++ b/options.h @@ -0,0 +1,56 @@ +/** + * Copyright (c) 2013-2014 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __OPTIONS_H__ +#define __OPTIONS_H__ + +// use precomputed Inverse Values of powers of two +#ifndef USE_PRECOMPUTED_IV +#define USE_PRECOMPUTED_IV 1 +#endif + +// use precomputed Curve Points (some scalar multiples of curve base point G) +#ifndef USE_PRECOMPUTED_CP +#define USE_PRECOMPUTED_CP 1 +#endif + +// use fast inverse method +#ifndef USE_INVERSE_FAST +#define USE_INVERSE_FAST 1 +#endif + +// support for printing bignum256 structures via printf +#ifndef BN_PRINT +#define BN_PRINT 0 +#endif + +// use deterministic signatures +#ifndef USE_RFC6979 +#define USE_RFC6979 1 +#endif + +// check public key for validity +#ifndef USE_PUBKEY_VALIDATE +#define USE_PUBKEY_VALIDATE 1 +#endif + +#endif diff --git a/tests.c b/tests.c index a3f45fd5a..7d7a1310e 100644 --- a/tests.c +++ b/tests.c @@ -34,6 +34,7 @@ #include "ecdsa.h" #include "pbkdf2.h" #include "sha2.h" +#include "options.h" uint8_t *fromhex(const char *str) { @@ -415,7 +416,7 @@ START_TEST(test_verify_speed) memcpy(pub_key33, fromhex("024054fd18aeb277aeedea01d3f3986ff4e5be18092a04339dcf4e524e2c0a0974"), 33); memcpy(pub_key65, fromhex("044054fd18aeb277aeedea01d3f3986ff4e5be18092a04339dcf4e524e2c0a09746c7083ed2097011b1223a17a644e81f59aa3de22dac119fd980b36a8ff29a244"), 65); - for (i = 0 ; i < 50; i++) { + for (i = 0 ; i < 25; i++) { res = ecdsa_verify(pub_key65, sig, msg, sizeof(msg)); ck_assert_int_eq(res, 0); res = ecdsa_verify(pub_key33, sig, msg, sizeof(msg)); @@ -426,14 +427,14 @@ START_TEST(test_verify_speed) memcpy(pub_key33, fromhex("03ff45a5561a76be930358457d113f25fac790794ec70317eff3b97d7080d45719"), 33); memcpy(pub_key65, fromhex("04ff45a5561a76be930358457d113f25fac790794ec70317eff3b97d7080d457196235193a15778062ddaa44aef7e6901b781763e52147f2504e268b2d572bf197"), 65); - for (i = 0 ; i < 50; i++) { + for (i = 0 ; i < 25; i++) { res = ecdsa_verify(pub_key65, sig, msg, sizeof(msg)); ck_assert_int_eq(res, 0); res = ecdsa_verify(pub_key33, sig, msg, sizeof(msg)); ck_assert_int_eq(res, 0); } - printf("Verifying speed: %0.2f sig/s\n", 200.0f / ((float)(clock() - t) / CLOCKS_PER_SEC)); + printf("Verifying speed: %0.2f sig/s\n", 100.0f / ((float)(clock() - t) / CLOCKS_PER_SEC)); } END_TEST @@ -886,6 +887,7 @@ START_TEST(test_pubkey_validity) res = ecdsa_read_pubkey(pub_key, &pub); ck_assert_int_eq(res, 1); +#ifdef USE_PUBKEY_VALIDATE memcpy(pub_key, fromhex("04f80490839af36d13701ec3f9eebdac901b51c362119d74553a3c537faff31b17e2a59ebddbdac9e87b816307a7ed5b826b8f40b92719086238e1bebf00000000"), 65); res = ecdsa_read_pubkey(pub_key, &pub); ck_assert_int_eq(res, 0); @@ -893,6 +895,7 @@ START_TEST(test_pubkey_validity) memcpy(pub_key, fromhex("04f80490839af36d13701ec3f9eebdac901b51c362119d74553a3c537faff31b17e2a59ebddbdac9e87b816307a7ed5b8211111111111111111111111111111111"), 65); res = ecdsa_read_pubkey(pub_key, &pub); ck_assert_int_eq(res, 0); +#endif memcpy(pub_key, fromhex("00"), 1); res = ecdsa_read_pubkey(pub_key, &pub); From 0fe1857513804f6fe6c7dc9e7ffe1faf5def9e2f Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 7 Jul 2014 21:11:25 +0200 Subject: [PATCH 122/627] normalize y^2 in pubkey validation fix last commit --- ecdsa.c | 7 ++++--- tests.c | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/ecdsa.c b/ecdsa.c index f5cd4f226..760afe61b 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -459,7 +459,7 @@ int ecdsa_read_pubkey(const uint8_t *pub_key, curve_point *pub) if (pub_key[0] == 0x04) { bn_read_be(pub_key + 1, &(pub->x)); bn_read_be(pub_key + 33, &(pub->y)); -#ifdef USE_PUBKEY_VALIDATE +#if USE_PUBKEY_VALIDATE return ecdsa_validate_pubkey(pub); #else return 1; @@ -468,7 +468,7 @@ int ecdsa_read_pubkey(const uint8_t *pub_key, curve_point *pub) if (pub_key[0] == 0x02 || pub_key[0] == 0x03) { // compute missing y coords bn_read_be(pub_key + 1, &(pub->x)); uncompress_coords(pub_key[0], &(pub->x), &(pub->y)); -#ifdef USE_PUBKEY_VALIDATE +#if USE_PUBKEY_VALIDATE return ecdsa_validate_pubkey(pub); #else return 1; @@ -502,6 +502,8 @@ int ecdsa_validate_pubkey(const curve_point *pub) // y^2 bn_multiply(&(pub->y), &y_2, &prime256k1); + bn_mod(&y_2, &prime256k1); + // x^3 + b bn_multiply(&(pub->x), &x_3_b, &prime256k1); bn_multiply(&(pub->x), &x_3_b, &prime256k1); @@ -542,7 +544,6 @@ int ecdsa_verify_double(const uint8_t *pub_key, const uint8_t *sig, const uint8_ } // returns 0 if verification succeeded -// it is assumed that public key is valid otherwise calling this does not make much sense int ecdsa_verify_digest(const uint8_t *pub_key, const uint8_t *sig, const uint8_t *digest) { int i, j; diff --git a/tests.c b/tests.c index 7d7a1310e..b6d818d27 100644 --- a/tests.c +++ b/tests.c @@ -887,7 +887,7 @@ START_TEST(test_pubkey_validity) res = ecdsa_read_pubkey(pub_key, &pub); ck_assert_int_eq(res, 1); -#ifdef USE_PUBKEY_VALIDATE +#if USE_PUBKEY_VALIDATE memcpy(pub_key, fromhex("04f80490839af36d13701ec3f9eebdac901b51c362119d74553a3c537faff31b17e2a59ebddbdac9e87b816307a7ed5b826b8f40b92719086238e1bebf00000000"), 65); res = ecdsa_read_pubkey(pub_key, &pub); ck_assert_int_eq(res, 0); From 03a8925e0f0789c2d26414dcddec7ba50cb20e38 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 7 Jul 2014 21:24:10 +0200 Subject: [PATCH 123/627] rename BN_PRINT define to USE_BN_PRINT --- Makefile | 2 +- bignum.c | 2 +- bignum.h | 2 +- options.h | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 746306110..e6029f404 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ CC = gcc -CFLAGS = -Wall -Wextra -Os -Wno-sequence-point +CFLAGS = -Os -Wall -Wextra -Wno-sequence-point -Wundef ifdef SMALL CFLAGS += -DUSE_PRECOMPUTED_IV=0 -DUSE_PRECOMPUTED_CP=0 -DUSE_PUBKEY_VALIDATE=0 endif diff --git a/bignum.c b/bignum.c index 06e7308bc..d94dc6fcc 100644 --- a/bignum.c +++ b/bignum.c @@ -563,7 +563,7 @@ void bn_divmod58(bignum256 *a, uint32_t *r) *r = rem; } -#if BN_PRINT +#if USE_BN_PRINT void bn_print(const bignum256 *a) { printf("%04x", a->val[8] & 0x0000FFFF); diff --git a/bignum.h b/bignum.h index 2fa65568c..168354643 100644 --- a/bignum.h +++ b/bignum.h @@ -83,7 +83,7 @@ void bn_substract_noprime(const bignum256 *a, const bignum256 *b, bignum256 *res void bn_divmod58(bignum256 *a, uint32_t *r); -#if BN_PRINT +#if USE_BN_PRINT void bn_print(const bignum256 *a); void bn_print_raw(const bignum256 *a); #endif diff --git a/options.h b/options.h index 85285e395..53cdb2df5 100644 --- a/options.h +++ b/options.h @@ -39,8 +39,8 @@ #endif // support for printing bignum256 structures via printf -#ifndef BN_PRINT -#define BN_PRINT 0 +#ifndef USE_BN_PRINT +#define USE_BN_PRINT 0 #endif // use deterministic signatures From bb739369599e374295291ea41d9fbcb5ee3c78b1 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 7 Jul 2014 21:34:54 +0200 Subject: [PATCH 124/627] use more warnings from trezor-mcu --- Makefile | 31 +++++++++++++++++++++++++++++-- test-openssl.c | 2 +- tests.c | 2 +- 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index e6029f404..db65f6776 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,35 @@ -CC = gcc -CFLAGS = -Os -Wall -Wextra -Wno-sequence-point -Wundef +CC = gcc + +OPTFLAGS = -Os -g + +CFLAGS += $(OPTFLAGS) \ + -W \ + -Wall \ + -Wextra \ + -Wimplicit-function-declaration \ + -Wredundant-decls \ + -Wstrict-prototypes \ + -Wundef \ + -Wshadow \ + -Wpointer-arith \ + -Wformat \ + -Wreturn-type \ + -Wsign-compare \ + -Wmultichar \ + -Wformat-nonliteral \ + -Winit-self \ + -Wuninitialized \ + -Wformat-security \ + -Werror + +# disable sequence point warning because of AES code +CFLAGS += -Wno-sequence-point + +# disable certain optimizations and features when small footprint is required ifdef SMALL CFLAGS += -DUSE_PRECOMPUTED_IV=0 -DUSE_PRECOMPUTED_CP=0 -DUSE_PUBKEY_VALIDATE=0 endif + OBJS = bignum.o ecdsa.o secp256k1.o rand.o hmac.o bip32.o bip39.o pbkdf2.o base58.o OBJS += ripemd160.o OBJS += sha2.o diff --git a/test-openssl.c b/test-openssl.c index 696563833..ef36b9eea 100644 --- a/test-openssl.c +++ b/test-openssl.c @@ -30,7 +30,7 @@ #include "ecdsa.h" #include "rand.h" -int main() +int main(void) { uint8_t sig[64], pub_key33[33], pub_key65[65], priv_key[32], msg[256], buffer[1000], hash[32], *p; uint32_t i, j, msg_len; diff --git a/tests.c b/tests.c index b6d818d27..d35655c43 100644 --- a/tests.c +++ b/tests.c @@ -1090,7 +1090,7 @@ Suite *test_suite(void) } // run suite -int main() +int main(void) { int number_failed; Suite *s = test_suite(); From 3329b6b6aa1ded34a7b3dcd3e597e877b34b4fbd Mon Sep 17 00:00:00 2001 From: Dustin Laurence Date: Wed, 16 Jul 2014 08:06:15 -0500 Subject: [PATCH 125/627] Test fread return value --- .gitignore | 2 ++ rand.c | 10 +++++++--- rand.h | 2 +- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index eca727cdd..d0ebc6ee0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ *.o +*.exe +*~ test-openssl tests diff --git a/rand.c b/rand.c index bc9c72043..cf5dec110 100644 --- a/rand.c +++ b/rand.c @@ -22,6 +22,7 @@ */ #include +#include #include "rand.h" @@ -35,11 +36,14 @@ void init_rand(void) uint32_t random32(void) { uint32_t r; - fread(&r, 1, sizeof(r), f); + size_t len = sizeof(r); + size_t len_read = fread(&r, 1, len, f); + assert(len_read == len); return r; } -void random_buffer(uint8_t *buf, uint32_t len) +void random_buffer(uint8_t *buf, size_t len) { - fread(buf, 1, len, f); + size_t len_read = fread(buf, 1, len, f); + assert(len_read == len); } diff --git a/rand.h b/rand.h index 3d49e68db..fb80ea43b 100644 --- a/rand.h +++ b/rand.h @@ -28,6 +28,6 @@ void init_rand(void); uint32_t random32(void); -void random_buffer(uint8_t *buf, uint32_t len); +void random_buffer(uint8_t *buf, size_t len); #endif From e0b083a0b0682f45a4efbfcd1f2035b26f667dad Mon Sep 17 00:00:00 2001 From: Dustin Laurence Date: Wed, 16 Jul 2014 13:39:02 -0500 Subject: [PATCH 126/627] Make CMakeLists.txt build tests --- CMakeLists.txt | 10 ++++++++++ test-openssl.c | 12 ++++++++++-- tests.c | 2 +- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 007f1a6c7..1f84a4e15 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,3 +3,13 @@ if(MSVC) set_source_files_properties(${SOURCES} PROPERTIES LANGUAGE CXX) endif(MSVC) add_library(TrezorCrypto STATIC ${SOURCES}) + +# disable sequence point warning because of AES code +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-sequence-point") +add_executable(tests tests.c aescrypt.c aeskey.c aestab.c aes_modes.c) +target_link_libraries(tests TrezorCrypto check rt pthread m crypto) +add_test(NAME trezor-crypto COMMAND tests) + +add_executable(test-openssl test-openssl.c) +target_link_libraries(test-openssl TrezorCrypto check rt pthread m crypto) +add_test(NAME trezor-crypto-openssl COMMAND test-openssl 100) diff --git a/test-openssl.c b/test-openssl.c index ef36b9eea..caf3b9a11 100644 --- a/test-openssl.c +++ b/test-openssl.c @@ -30,7 +30,7 @@ #include "ecdsa.h" #include "rand.h" -int main(void) +int main(int argc, char *argv[]) { uint8_t sig[64], pub_key33[33], pub_key65[65], priv_key[32], msg[256], buffer[1000], hash[32], *p; uint32_t i, j, msg_len; @@ -41,7 +41,14 @@ int main(void) init_rand(); ecgroup = EC_GROUP_new_by_curve_name(NID_secp256k1); - for (;;) { + unsigned long max_iterations = -1; + if (argc == 2) { + sscanf(argv[1], "%lu", &max_iterations); + } else if (argc > 2) { + puts("Zero or one command-line arguments only, exiting...."); + } + unsigned long iterations = 0; + while (argc == 1 || iterations < max_iterations) { // random message len between 1 and 256 msg_len = (random32() & 0xFF) + 1; // create random message @@ -113,6 +120,7 @@ int main(void) EC_KEY_free(eckey); cnt++; if ((cnt % 100) == 0) printf("Passed ... %d\n", cnt); + ++iterations; } EC_GROUP_free(ecgroup); return 0; diff --git a/tests.c b/tests.c index d35655c43..8dc7c8d94 100644 --- a/tests.c +++ b/tests.c @@ -54,7 +54,7 @@ uint8_t *fromhex(const char *str) return buf; } -inline char *tohex(const uint8_t *bin, size_t l) +char *tohex(const uint8_t *bin, size_t l) { char *buf = (char *)malloc(l * 2 + 1); static char digits[] = "0123456789abcdef"; From 7570ea8c0c42a82e8b2f95a5087a00be22fc30eb Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 17 Jul 2014 16:59:14 +0200 Subject: [PATCH 127/627] update CMakeLists.txt --- CMakeLists.txt | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1f84a4e15..a8e3bba82 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,12 +1,15 @@ -set(SOURCES bignum.c ecdsa.c secp256k1.c sha2.c rand.c hmac.c bip32.c ripemd160.c bip39.c pbkdf2.c base58.c) +cmake_minimum_required(VERSION 2.6) + +set(SOURCES aescrypt.c aeskey.c aes_modes.c aestab.c base58.c bignum.c bip32.c bip39.c ecdsa.c hmac.c pbkdf2.c rand.c ripemd160.c secp256k1.c sha2.c) if(MSVC) set_source_files_properties(${SOURCES} PROPERTIES LANGUAGE CXX) endif(MSVC) add_library(TrezorCrypto STATIC ${SOURCES}) # disable sequence point warning because of AES code -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-sequence-point") -add_executable(tests tests.c aescrypt.c aeskey.c aestab.c aes_modes.c) +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-sequence-point") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-sequence-point") +add_executable(tests tests.c) target_link_libraries(tests TrezorCrypto check rt pthread m crypto) add_test(NAME trezor-crypto COMMAND tests) From 6cd85668a35695a71eaf3fc3c7afaca99bc4a40e Mon Sep 17 00:00:00 2001 From: Dustin Laurence Date: Thu, 17 Jul 2014 12:51:00 -0500 Subject: [PATCH 128/627] Make test build optional in CMake --- CMakeLists.txt | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a8e3bba82..f5f3293a6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,18 +1,24 @@ cmake_minimum_required(VERSION 2.6) set(SOURCES aescrypt.c aeskey.c aes_modes.c aestab.c base58.c bignum.c bip32.c bip39.c ecdsa.c hmac.c pbkdf2.c rand.c ripemd160.c secp256k1.c sha2.c) + +# disable sequence point warnings where they are expected +set_source_files_properties(aeskey.c PROPERTIES + COMPILE_FLAGS -Wno-sequence-point) + if(MSVC) set_source_files_properties(${SOURCES} PROPERTIES LANGUAGE CXX) endif(MSVC) + add_library(TrezorCrypto STATIC ${SOURCES}) -# disable sequence point warning because of AES code -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-sequence-point") -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-sequence-point") -add_executable(tests tests.c) -target_link_libraries(tests TrezorCrypto check rt pthread m crypto) -add_test(NAME trezor-crypto COMMAND tests) +# Build trezor-crypto tests (requires OpenSSL) +if (TREZOR_CRYPTO_TESTS) + add_executable(tests tests.c) + target_link_libraries(tests TrezorCrypto check rt pthread m crypto) + add_test(NAME trezor-crypto COMMAND tests) -add_executable(test-openssl test-openssl.c) -target_link_libraries(test-openssl TrezorCrypto check rt pthread m crypto) -add_test(NAME trezor-crypto-openssl COMMAND test-openssl 100) + add_executable(test-openssl test-openssl.c) + target_link_libraries(test-openssl TrezorCrypto check rt pthread m crypto) + add_test(NAME trezor-crypto-openssl COMMAND test-openssl 100) +endif() \ No newline at end of file From 5315f490a0612ed86efc35d7ccbb23de94c4f8ff Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 17 Jul 2014 20:15:14 +0200 Subject: [PATCH 129/627] don't use AES_NI nor VIA_ACE --- aesopt.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aesopt.h b/aesopt.h index 89bb01eb1..b15632fa2 100644 --- a/aesopt.h +++ b/aesopt.h @@ -185,7 +185,7 @@ Issue Date: 20/12/2007 AES_REV_DKS must NOT be defined when such assembler files are built */ -#if 1 && defined( _WIN64 ) && defined( _MSC_VER ) +#if 0 && defined( _WIN64 ) && defined( _MSC_VER ) # define INTEL_AES_POSSIBLE #endif @@ -210,7 +210,7 @@ Issue Date: 20/12/2007 AES_REV_DKS must be set for assembler code used with a VIA ACE build */ -#if 1 && defined( VIA_ACE_POSSIBLE ) && !defined( USE_VIA_ACE_IF_PRESENT ) +#if 0 && defined( VIA_ACE_POSSIBLE ) && !defined( USE_VIA_ACE_IF_PRESENT ) # define USE_VIA_ACE_IF_PRESENT #endif From b9ed9a9cd4142e3ea3f779f5888ccafe9429545e Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 24 Jul 2014 15:26:50 +0200 Subject: [PATCH 130/627] don't include aescpp.h --- aesopt.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/aesopt.h b/aesopt.h index b15632fa2..ee96215b2 100644 --- a/aesopt.h +++ b/aesopt.h @@ -87,11 +87,7 @@ Issue Date: 20/12/2007 #if !defined( _AESOPT_H ) #define _AESOPT_H -#if defined( __cplusplus ) -#include "aescpp.h" -#else #include "aes.h" -#endif /* PLATFORM SPECIFIC INCLUDES */ From 8820ae9873832ffd6201fa7599562d1358f6d640 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 7 Aug 2014 14:34:33 +0200 Subject: [PATCH 131/627] add more checks for improbable cases; rework gui testing app --- .gitignore | 1 + bip32.c | 46 +++++++++++++++++++++--- bip32.h | 6 ++-- gui/mainwindow.cpp | 18 ++++++---- gui/mainwindow.h | 2 +- gui/mainwindow.ui | 88 +++++++++++++++++++++++++++++++++------------- 6 files changed, 122 insertions(+), 39 deletions(-) diff --git a/.gitignore b/.gitignore index d0ebc6ee0..34397a4c0 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ *~ test-openssl tests +build-*/ diff --git a/bip32.c b/bip32.c index d9b25eee3..2e6c57d01 100644 --- a/bip32.c +++ b/bip32.c @@ -31,27 +31,38 @@ #include "ripemd160.h" #include "base58.h" -void hdnode_from_xpub(uint32_t depth, uint32_t fingerprint, uint32_t child_num, uint8_t *chain_code, uint8_t *public_key, HDNode *out) +int hdnode_from_xpub(uint32_t depth, uint32_t fingerprint, uint32_t child_num, uint8_t *chain_code, uint8_t *public_key, HDNode *out) { + curve_point c; + if (!ecdsa_read_pubkey(public_key, &c)) { // invalid pubkey + return 0; + } out->depth = depth; out->fingerprint = fingerprint; out->child_num = child_num; memcpy(out->chain_code, chain_code, 32); memset(out->private_key, 0, 32); memcpy(out->public_key, public_key, 33); + return 1; } -void hdnode_from_xprv(uint32_t depth, uint32_t fingerprint, uint32_t child_num, uint8_t *chain_code, uint8_t *private_key, HDNode *out) +int hdnode_from_xprv(uint32_t depth, uint32_t fingerprint, uint32_t child_num, uint8_t *chain_code, uint8_t *private_key, HDNode *out) { + bignum256 a; + bn_read_be(private_key, &a); + if (bn_is_zero(&a) || !bn_is_less(&a, &order256k1)) { // == 0 or >= order + return 0; + } out->depth = depth; out->fingerprint = fingerprint; out->child_num = child_num; memcpy(out->chain_code, chain_code, 32); memcpy(out->private_key, private_key, 32); hdnode_fill_public_key(out); + return 1; } -void hdnode_from_seed(uint8_t *seed, int seed_len, HDNode *out) +int hdnode_from_seed(uint8_t *seed, int seed_len, HDNode *out) { uint8_t I[32 + 32]; memset(out, 0, sizeof(HDNode)); @@ -59,9 +70,15 @@ void hdnode_from_seed(uint8_t *seed, int seed_len, HDNode *out) out->fingerprint = 0x00000000; out->child_num = 0; hmac_sha512((uint8_t *)"Bitcoin seed", 12, seed, seed_len, I); - memcpy(out->chain_code, I + 32, 32); memcpy(out->private_key, I, 32); + bignum256 a; + bn_read_be(out->private_key, &a); + if (bn_is_zero(&a) || !bn_is_less(&a, &order256k1)) { // == 0 or >= order + return 0; + } + memcpy(out->chain_code, I + 32, 32); hdnode_fill_public_key(out); + return 1; } int hdnode_private_ckd(HDNode *inout, uint32_t i) @@ -90,8 +107,17 @@ int hdnode_private_ckd(HDNode *inout, uint32_t i) memcpy(inout->private_key, I, 32); bn_read_be(inout->private_key, &b); + + if (!bn_is_less(&b, &order256k1)) { // >= order + return 0; + } + bn_addmod(&a, &b, &order256k1); + if (bn_is_zero(&a)) { + return 0; + } + inout->depth++; inout->child_num = i; bn_write_be(&a, inout->private_key); @@ -128,8 +154,20 @@ int hdnode_public_ckd(HDNode *inout, uint32_t i) hmac_sha512(inout->chain_code, 32, data, sizeof(data), I); memcpy(inout->chain_code, I + 32, 32); bn_read_be(I, &c); + + if (!bn_is_less(&c, &order256k1)) { // >= order + return 0; + } + scalar_multiply(&c, &b); // b = c * G point_add(&a, &b); // b = a + b + +#if USE_PUBKEY_VALIDATE + if (!ecdsa_validate_pubkey(&b)) { + return 0; + } +#endif + inout->public_key[0] = 0x02 | (b.y.val[0] & 0x01); bn_write_be(&b.x, inout->public_key + 1); diff --git a/bip32.h b/bip32.h index 49c9676e6..f3ce6568b 100644 --- a/bip32.h +++ b/bip32.h @@ -35,11 +35,11 @@ typedef struct { uint8_t public_key[33]; } HDNode; -void hdnode_from_xpub(uint32_t depth, uint32_t fingerprint, uint32_t child_num, uint8_t *chain_code, uint8_t *public_key, HDNode *out); +int hdnode_from_xpub(uint32_t depth, uint32_t fingerprint, uint32_t child_num, uint8_t *chain_code, uint8_t *public_key, HDNode *out); -void hdnode_from_xprv(uint32_t depth, uint32_t fingerprint, uint32_t child_num, uint8_t *chain_code, uint8_t *private_key, HDNode *out); +int hdnode_from_xprv(uint32_t depth, uint32_t fingerprint, uint32_t child_num, uint8_t *chain_code, uint8_t *private_key, HDNode *out); -void hdnode_from_seed(uint8_t *seed, int seed_len, HDNode *out); +int hdnode_from_seed(uint8_t *seed, int seed_len, HDNode *out); #define hdnode_private_ckd_prime(X, I) hdnode_private_ckd((X), ((I) | 0x80000000)) diff --git a/gui/mainwindow.cpp b/gui/mainwindow.cpp index 1e88b2f35..b3a19296f 100644 --- a/gui/mainwindow.cpp +++ b/gui/mainwindow.cpp @@ -7,6 +7,7 @@ extern "C" { #include "../ecdsa.h" } +bool root_set = false; HDNode root; MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) @@ -28,7 +29,6 @@ MainWindow::~MainWindow() void MainWindow::on_buttonLoad_clicked() { - ui->listAccount->clear(); if (!mnemonic_check(ui->editMnemonic->text().toLocal8Bit().data())) { QMessageBox::critical(this, "Error", "Text is not a valid BIP39 mnemonic.", QMessageBox::Ok); return; @@ -36,22 +36,26 @@ void MainWindow::on_buttonLoad_clicked() uint8_t seed[64]; mnemonic_to_seed(ui->editMnemonic->text().toLocal8Bit().data(), ui->editPassphrase->text().toLocal8Bit().data(), seed, 0); hdnode_from_seed(seed, 64, &root); - for (int i = 1; i <= 10; i++) { - ui->listAccount->addItem(QString("Account #") + QString::number(i)); - } + root_set = true; + ui->spinAccount->setValue(1); + on_spinAccount_valueChanged(1); } -void MainWindow::on_listAccount_clicked(const QModelIndex &index) +void MainWindow::on_spinAccount_valueChanged(int arg1) { + if (!root_set) return; const char addr_version = 0x00, wif_version = 0x80; - char buf[64]; + char buf[128]; HDNode node; // external chain for (int chain = 0; chain < 2; chain++) { QTableWidget *list = chain == 0 ? ui->listAddress : ui->listChange; node = root; hdnode_private_ckd(&node, 44 | 0x80000000); - hdnode_private_ckd(&node, index.row() | 0x80000000); + hdnode_private_ckd(&node, 0 | 0x80000000); // bitcoin + hdnode_private_ckd(&node, (arg1 - 1) | 0x80000000); + hdnode_serialize_private(&node, buf); QString xprv = QString(buf); ui->lineXprv->setText(xprv); + hdnode_serialize_public(&node, buf); QString xpub = QString(buf); ui->lineXpub->setText(xpub); hdnode_private_ckd(&node, chain); // external / internal for (int i = 0; i < 100; i++) { HDNode node2 = node; diff --git a/gui/mainwindow.h b/gui/mainwindow.h index ef7dc1b4d..7275167da 100644 --- a/gui/mainwindow.h +++ b/gui/mainwindow.h @@ -18,7 +18,7 @@ public: private slots: void on_buttonLoad_clicked(); - void on_listAccount_clicked(const QModelIndex &index); + void on_spinAccount_valueChanged(int arg1); private: Ui::MainWindow *ui; diff --git a/gui/mainwindow.ui b/gui/mainwindow.ui index 1b1782b6f..465669907 100644 --- a/gui/mainwindow.ui +++ b/gui/mainwindow.ui @@ -6,13 +6,14 @@ 0 0 - 800 + 1000 600 DejaVu Sans Mono + 8 @@ -20,10 +21,10 @@ - - + + - + @@ -33,7 +34,7 @@ - + @@ -52,23 +53,7 @@ - - - - - 0 - 0 - - - - - 140 - 16777215 - - - - - + @@ -87,7 +72,7 @@ - + @@ -106,15 +91,70 @@ + + + + Mnemonic: + + + + + + + Passphrase: + + + + + + + External Chain: + + + + + + + Internal Chain: + + + + + + + + 130 + 16777215 + + + + Account # + + + 1 + + + 2147483647 + + + + + + + + + editMnemonic + editPassphrase buttonLoad - listAccount + spinAccount listAddress + listChange From ad8e618ed28f4dca108461a9afdbbaadeb26746c Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 11 Aug 2014 02:04:42 +0200 Subject: [PATCH 132/627] use $(CC) instead of gcc in Makefile --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index db65f6776..95ab8f846 100644 --- a/Makefile +++ b/Makefile @@ -44,10 +44,10 @@ all: tests test-openssl $(CC) $(CFLAGS) -o $@ -c $< tests: tests.o $(OBJS) - gcc tests.o $(OBJS) $(TESTLIBS) -o tests + $(CC) tests.o $(OBJS) $(TESTLIBS) -o tests test-openssl: test-openssl.o $(OBJS) - gcc test-openssl.o $(OBJS) $(TESTSSLLIBS) -o test-openssl + $(CC) test-openssl.o $(OBJS) $(TESTSSLLIBS) -o test-openssl clean: rm -f *.o tests test-openssl From f6560c7d1303a50d215cffab87acc7fc8c8964a4 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 30 Oct 2014 01:35:13 +0100 Subject: [PATCH 133/627] split pbkdf2 into pbkdf2_hmac_sha256 and pbkdf2_hmac_sha512 --- bip39.c | 2 +- pbkdf2.c | 45 ++++++++++++++++++++++++++++++++++++++------- pbkdf2.h | 4 +++- tests.c | 38 +++++++++++++++++++++++++++++++------- 4 files changed, 73 insertions(+), 16 deletions(-) diff --git a/bip39.c b/bip39.c index fe0d4f121..019259386 100644 --- a/bip39.c +++ b/bip39.c @@ -152,7 +152,7 @@ void mnemonic_to_seed(const char *mnemonic, const char *passphrase, uint8_t seed memcpy(salt, "mnemonic", 8); memcpy(salt + 8, passphrase, saltlen); saltlen += 8; - pbkdf2((const uint8_t *)mnemonic, strlen(mnemonic), salt, saltlen, BIP39_PBKDF2_ROUNDS, seed, 512 / 8, progress_callback); + pbkdf2_hmac_sha512((const uint8_t *)mnemonic, strlen(mnemonic), salt, saltlen, BIP39_PBKDF2_ROUNDS, seed, 512 / 8, progress_callback); } const char **mnemonic_wordlist(void) diff --git a/pbkdf2.c b/pbkdf2.c index 02699a0e9..2271f997c 100644 --- a/pbkdf2.c +++ b/pbkdf2.c @@ -25,11 +25,42 @@ #include "pbkdf2.h" #include "hmac.h" -#define HMACFUNC hmac_sha512 -#define HMACLEN (512/8) +void pbkdf2_hmac_sha256(const uint8_t *pass, int passlen, uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key, int keylen, void (*progress_callback)(uint32_t current, uint32_t total)) +{ + const uint32_t HMACLEN = 256/8; + uint32_t i, j, k; + uint8_t f[HMACLEN], g[HMACLEN]; + uint32_t blocks = keylen / HMACLEN; + if (keylen & (HMACLEN - 1)) { + blocks++; + } + for (i = 1; i <= blocks; i++) { + salt[saltlen ] = (i >> 24) & 0xFF; + salt[saltlen + 1] = (i >> 16) & 0xFF; + salt[saltlen + 2] = (i >> 8) & 0xFF; + salt[saltlen + 3] = i & 0xFF; + hmac_sha256(pass, passlen, salt, saltlen + 4, g); + memcpy(f, g, HMACLEN); + for (j = 1; j < iterations; j++) { + hmac_sha256(pass, passlen, g, HMACLEN, g); + for (k = 0; k < HMACLEN; k++) { + f[k] ^= g[k]; + } + if (progress_callback && (j % 256 == 255)) { + progress_callback(j + 1, iterations); + } + } + if (i == blocks && (keylen & (HMACLEN - 1))) { + memcpy(key + HMACLEN * (i - 1), f, keylen & (HMACLEN - 1)); + } else { + memcpy(key + HMACLEN * (i - 1), f, HMACLEN); + } + } +} -void pbkdf2(const uint8_t *pass, int passlen, uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key, int keylen, void (*progress_callback)(uint32_t current, uint32_t total)) +void pbkdf2_hmac_sha512(const uint8_t *pass, int passlen, uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key, int keylen, void (*progress_callback)(uint32_t current, uint32_t total)) { + const uint32_t HMACLEN = 512/8; uint32_t i, j, k; uint8_t f[HMACLEN], g[HMACLEN]; uint32_t blocks = keylen / HMACLEN; @@ -41,18 +72,18 @@ void pbkdf2(const uint8_t *pass, int passlen, uint8_t *salt, int saltlen, uint32 salt[saltlen + 1] = (i >> 16) & 0xFF; salt[saltlen + 2] = (i >> 8) & 0xFF; salt[saltlen + 3] = i & 0xFF; - HMACFUNC(pass, passlen, salt, saltlen + 4, g); + hmac_sha512(pass, passlen, salt, saltlen + 4, g); memcpy(f, g, HMACLEN); for (j = 1; j < iterations; j++) { - HMACFUNC(pass, passlen, g, HMACLEN, g); + hmac_sha512(pass, passlen, g, HMACLEN, g); for (k = 0; k < HMACLEN; k++) { f[k] ^= g[k]; } - if (progress_callback && j % 256 == 255) { + if (progress_callback && (j % 256 == 255)) { progress_callback(j + 1, iterations); } } - if (i == blocks - 1 && (keylen & (HMACLEN - 1))) { + if (i == blocks && (keylen & (HMACLEN - 1))) { memcpy(key + HMACLEN * (i - 1), f, keylen & (HMACLEN - 1)); } else { memcpy(key + HMACLEN * (i - 1), f, HMACLEN); diff --git a/pbkdf2.h b/pbkdf2.h index 8e88955a8..6fe09788b 100644 --- a/pbkdf2.h +++ b/pbkdf2.h @@ -27,6 +27,8 @@ #include // salt needs to have 4 extra bytes available beyond saltlen -void pbkdf2(const uint8_t *pass, int passlen, uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key, int keylen, void (*progress_callback)(uint32_t current, uint32_t total)); +void pbkdf2_hmac_sha256(const uint8_t *pass, int passlen, uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key, int keylen, void (*progress_callback)(uint32_t current, uint32_t total)); +// salt needs to have 4 extra bytes available beyond saltlen +void pbkdf2_hmac_sha512(const uint8_t *pass, int passlen, uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key, int keylen, void (*progress_callback)(uint32_t current, uint32_t total)); #endif diff --git a/tests.c b/tests.c index 8dc7c8d94..dc72b373d 100644 --- a/tests.c +++ b/tests.c @@ -587,25 +587,48 @@ START_TEST(test_aes) } END_TEST +// test vectors from https://stackoverflow.com/questions/5130513/pbkdf2-hmac-sha2-test-vectors +START_TEST(test_pbkdf2_hmac_sha256) +{ + uint8_t k[40], s[40]; + + strcpy((char *)s, "salt"); + pbkdf2_hmac_sha256((uint8_t *)"password", 8, s, 4, 1, k, 32, 0); + ck_assert_mem_eq(k, fromhex("120fb6cffcf8b32c43e7225256c4f837a86548c92ccc35480805987cb70be17b"), 32); + + strcpy((char *)s, "salt"); + pbkdf2_hmac_sha256((uint8_t *)"password", 8, s, 4, 2, k, 32, 0); + ck_assert_mem_eq(k, fromhex("ae4d0c95af6b46d32d0adff928f06dd02a303f8ef3c251dfd6e2d85a95474c43"), 32); + + strcpy((char *)s, "salt"); + pbkdf2_hmac_sha256((uint8_t *)"password", 8, s, 4, 4096, k, 32, 0); + ck_assert_mem_eq(k, fromhex("c5e478d59288c841aa530db6845c4c8d962893a001ce4e11a4963873aa98134a"), 32); + + strcpy((char *)s, "saltSALTsaltSALTsaltSALTsaltSALTsalt"); + pbkdf2_hmac_sha256((uint8_t *)"passwordPASSWORDpassword", 3*8, s, 9*4, 4096, k, 64, 0); + ck_assert_mem_eq(k, fromhex("348c89dbcbd32b2f32d814b8116e84cf2b17347ebc1800181c4e2a1fb8dd53e1c635518c7dac47e9"), 40); +} +END_TEST + // test vectors from http://stackoverflow.com/questions/15593184/pbkdf2-hmac-sha-512-test-vectors -START_TEST(test_pbkdf2) +START_TEST(test_pbkdf2_hmac_sha512) { - uint8_t k[64], s[64]; + uint8_t k[64], s[40]; strcpy((char *)s, "salt"); - pbkdf2((uint8_t *)"password", 8, s, 4, 1, k, 64, 0); + pbkdf2_hmac_sha512((uint8_t *)"password", 8, s, 4, 1, k, 64, 0); ck_assert_mem_eq(k, fromhex("867f70cf1ade02cff3752599a3a53dc4af34c7a669815ae5d513554e1c8cf252c02d470a285a0501bad999bfe943c08f050235d7d68b1da55e63f73b60a57fce"), 64); strcpy((char *)s, "salt"); - pbkdf2((uint8_t *)"password", 8, s, 4, 2, k, 64, 0); + pbkdf2_hmac_sha512((uint8_t *)"password", 8, s, 4, 2, k, 64, 0); ck_assert_mem_eq(k, fromhex("e1d9c16aa681708a45f5c7c4e215ceb66e011a2e9f0040713f18aefdb866d53cf76cab2868a39b9f7840edce4fef5a82be67335c77a6068e04112754f27ccf4e"), 64); strcpy((char *)s, "salt"); - pbkdf2((uint8_t *)"password", 8, s, 4, 4096, k, 64, 0); + pbkdf2_hmac_sha512((uint8_t *)"password", 8, s, 4, 4096, k, 64, 0); ck_assert_mem_eq(k, fromhex("d197b1b33db0143e018b12f3d1d1479e6cdebdcc97c5c0f87f6902e072f457b5143f30602641b3d55cd335988cb36b84376060ecd532e039b742a239434af2d5"), 64); strcpy((char *)s, "saltSALTsaltSALTsaltSALTsaltSALTsalt"); - pbkdf2((uint8_t *)"passwordPASSWORDpassword", 3*8, s, 9*4, 4096, k, 64, 0); + pbkdf2_hmac_sha512((uint8_t *)"passwordPASSWORDpassword", 3*8, s, 9*4, 4096, k, 64, 0); ck_assert_mem_eq(k, fromhex("8c0511f4c6e597c6ac6315d8f0362e225f3c501495ba23b868c005174dc4ee71115b59f9e60cd9532fa33e0f75aefe30225c583a186cd82bd4daea9724a3d3b8"), 64); } END_TEST @@ -1074,7 +1097,8 @@ Suite *test_suite(void) suite_add_tcase(s, tc); tc = tcase_create("pbkdf2"); - tcase_add_test(tc, test_pbkdf2); + tcase_add_test(tc, test_pbkdf2_hmac_sha256); + tcase_add_test(tc, test_pbkdf2_hmac_sha512); suite_add_tcase(s, tc); tc = tcase_create("bip39"); From c5d9b2ea2fd7694afc2c6df38dbc0c205aff22a0 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 16 Nov 2014 21:00:52 +0100 Subject: [PATCH 134/627] remove forgotten declaration --- bip32.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/bip32.h b/bip32.h index f3ce6568b..7fa810c0a 100644 --- a/bip32.h +++ b/bip32.h @@ -49,8 +49,6 @@ int hdnode_public_ckd(HDNode *inout, uint32_t i); void hdnode_fill_public_key(HDNode *node); -void hdnode_fill_address(HDNode *node); - void hdnode_serialize_public(const HDNode *node, char *str); void hdnode_serialize_private(const HDNode *node, char *str); From df3606dd5ec42c588993e87664be2b8631ce3c96 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 16 Nov 2014 21:17:39 +0100 Subject: [PATCH 135/627] introduce ecdsa_get_address_raw --- ecdsa.c | 13 +++++++++---- ecdsa.h | 1 + 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/ecdsa.c b/ecdsa.c index 760afe61b..a9bedadd6 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -418,12 +418,17 @@ void ecdsa_get_pubkeyhash(const uint8_t *pub_key, uint8_t *pubkeyhash) ripemd160(h, 32, pubkeyhash); } +void ecdsa_get_address_raw(const uint8_t *pub_key, uint8_t version, uint8_t *addr_raw) +{ + addr_raw[0] = version; + ecdsa_get_pubkeyhash(pub_key, addr_raw + 1); +} + void ecdsa_get_address(const uint8_t *pub_key, uint8_t version, char *addr) { - uint8_t data[21]; - data[0] = version; - ecdsa_get_pubkeyhash(pub_key, data + 1); - base58_encode_check(data, 21, addr); + uint8_t raw[21]; + ecdsa_get_address_raw(pub_key, version, raw); + base58_encode_check(raw, 21, addr); } void ecdsa_get_wif(const uint8_t *priv_key, uint8_t version, char *wif) diff --git a/ecdsa.h b/ecdsa.h index 2de5bcdfa..0596d9031 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -45,6 +45,7 @@ int ecdsa_sign_digest(const uint8_t *priv_key, const uint8_t *digest, uint8_t *s void ecdsa_get_public_key33(const uint8_t *priv_key, uint8_t *pub_key); void ecdsa_get_public_key65(const uint8_t *priv_key, uint8_t *pub_key); void ecdsa_get_pubkeyhash(const uint8_t *pub_key, uint8_t *pubkeyhash); +void ecdsa_get_address_raw(const uint8_t *pub_key, uint8_t version, uint8_t *addr_raw); void ecdsa_get_address(const uint8_t *pub_key, uint8_t version, char *addr); void ecdsa_get_wif(const uint8_t *priv_key, uint8_t version, char *wif); int ecdsa_address_decode(const char *addr, uint8_t *out); From 9469a64a0a1ec032b829e7a1465d0e4b2996cd61 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 17 Nov 2014 17:17:14 +0100 Subject: [PATCH 136/627] use bn_is_zero and bn_is_equal where possible --- ecdsa.c | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/ecdsa.c b/ecdsa.c index a9bedadd6..44c4b8be5 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -343,12 +343,7 @@ int ecdsa_sign_digest(const uint8_t *priv_key, const uint8_t *digest, uint8_t *s // r = (rx mod n) bn_mod(&R.x, &order256k1); // if r is zero, we fail - for (i = 0; i < 9; i++) { - if (R.x.val[i] != 0) break; - } - if (i == 9) { - return 2; - } + if (bn_is_zero(&R.x)) return 2; bn_inverse(&k, &order256k1); bn_read_be(priv_key, da); bn_multiply(&R.x, da, &order256k1); @@ -360,13 +355,8 @@ int ecdsa_sign_digest(const uint8_t *priv_key, const uint8_t *digest, uint8_t *s da->val[8] += z.val[8]; bn_multiply(da, &k, &order256k1); bn_mod(&k, &order256k1); - for (i = 0; i < 9; i++) { - if (k.val[i] != 0) break; - } // if k is zero, we fail - if (i == 9) { - return 3; - } + if (bn_is_zero(&k)) return 3; // if S > order/2 => S = -S if (bn_is_less(&order256k1_half, &k)) { @@ -595,11 +585,7 @@ int ecdsa_verify_digest(const uint8_t *pub_key, const uint8_t *sig, const uint8_ bn_mod(&(res.x), &order256k1); // signature does not match - for (i = 0; i < 9; i++) { - if (res.x.val[i] != r.val[i]) { - return 5; - } - } + if (!bn_is_equal(&res.x, &r)) return 5; // all OK return 0; From b4cdba8489201e623b948469609a48495f2eeed2 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 8 Dec 2014 20:17:47 +0100 Subject: [PATCH 137/627] export pby from ecdsa_sign functions --- ecdsa.c | 13 ++++++++----- ecdsa.h | 6 +++--- test-openssl.c | 2 +- tests.c | 4 ++-- 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/ecdsa.c b/ecdsa.c index 44c4b8be5..9e16447fc 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -296,28 +296,28 @@ int generate_k_rfc6979(bignum256 *secret, const uint8_t *priv_key, const uint8_t // msg is a data to be signed // msg_len is the message length -int ecdsa_sign(const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig) +int ecdsa_sign(const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby) { uint8_t hash[32]; sha256_Raw(msg, msg_len, hash); - return ecdsa_sign_digest(priv_key, hash, sig); + return ecdsa_sign_digest(priv_key, hash, sig, pby); } // msg is a data to be signed // msg_len is the message length -int ecdsa_sign_double(const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig) +int ecdsa_sign_double(const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby) { uint8_t hash[32]; sha256_Raw(msg, msg_len, hash); sha256_Raw(hash, 32, hash); - return ecdsa_sign_digest(priv_key, hash, sig); + return ecdsa_sign_digest(priv_key, hash, sig, pby); } // uses secp256k1 curve // priv_key is a 32 byte big endian stored number // sig is 64 bytes long array for the signature // digest is 32 bytes of digest -int ecdsa_sign_digest(const uint8_t *priv_key, const uint8_t *digest, uint8_t *sig) +int ecdsa_sign_digest(const uint8_t *priv_key, const uint8_t *digest, uint8_t *sig, uint8_t *pby) { uint32_t i; curve_point R; @@ -340,6 +340,9 @@ int ecdsa_sign_digest(const uint8_t *priv_key, const uint8_t *digest, uint8_t *s // compute k*G scalar_multiply(&k, &R); + if (pby) { + *pby = R.y.val[0] & 1; + } // r = (rx mod n) bn_mod(&R.x, &order256k1); // if r is zero, we fail diff --git a/ecdsa.h b/ecdsa.h index 0596d9031..292aeaf58 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -39,9 +39,9 @@ int point_is_negative_of(const curve_point *p, const curve_point *q); void scalar_multiply(const bignum256 *k, curve_point *res); void uncompress_coords(uint8_t odd, const bignum256 *x, bignum256 *y); -int ecdsa_sign(const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig); -int ecdsa_sign_double(const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig); -int ecdsa_sign_digest(const uint8_t *priv_key, const uint8_t *digest, uint8_t *sig); +int ecdsa_sign(const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby); +int ecdsa_sign_double(const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby); +int ecdsa_sign_digest(const uint8_t *priv_key, const uint8_t *digest, uint8_t *sig, uint8_t *pby); void ecdsa_get_public_key33(const uint8_t *priv_key, uint8_t *pub_key); void ecdsa_get_public_key65(const uint8_t *priv_key, uint8_t *pub_key); void ecdsa_get_pubkeyhash(const uint8_t *pub_key, uint8_t *pubkeyhash); diff --git a/test-openssl.c b/test-openssl.c index caf3b9a11..ccef802ce 100644 --- a/test-openssl.c +++ b/test-openssl.c @@ -82,7 +82,7 @@ int main(int argc, char *argv[]) } // use our ECDSA signer to sign the message with the key - if (ecdsa_sign(priv_key, msg, msg_len, sig) != 0) { + if (ecdsa_sign(priv_key, msg, msg_len, sig, 0) != 0) { printf("trezor-crypto signing failed\n"); break; } diff --git a/tests.c b/tests.c index dc72b373d..91115ea1d 100644 --- a/tests.c +++ b/tests.c @@ -386,13 +386,13 @@ START_TEST(test_sign_speed) memcpy(priv_key, fromhex("c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd5"), 32); for (i = 0 ; i < 250; i++) { - res = ecdsa_sign(priv_key, msg, sizeof(msg), sig); + res = ecdsa_sign(priv_key, msg, sizeof(msg), sig, 0); ck_assert_int_eq(res, 0); } memcpy(priv_key, fromhex("509a0382ff5da48e402967a671bdcde70046d07f0df52cff12e8e3883b426a0a"), 32); for (i = 0 ; i < 250; i++) { - res = ecdsa_sign(priv_key, msg, sizeof(msg), sig); + res = ecdsa_sign(priv_key, msg, sizeof(msg), sig, 0); ck_assert_int_eq(res, 0); } From 10a92c3c6276d5b1955331b7a33ebe9d6a32c37e Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 13 Dec 2014 19:54:01 +0100 Subject: [PATCH 138/627] use const in hdnode_from_* methods --- bip32.c | 6 +++--- bip32.h | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/bip32.c b/bip32.c index 2e6c57d01..ae4ffc5b2 100644 --- a/bip32.c +++ b/bip32.c @@ -31,7 +31,7 @@ #include "ripemd160.h" #include "base58.h" -int hdnode_from_xpub(uint32_t depth, uint32_t fingerprint, uint32_t child_num, uint8_t *chain_code, uint8_t *public_key, HDNode *out) +int hdnode_from_xpub(uint32_t depth, uint32_t fingerprint, uint32_t child_num, const uint8_t *chain_code, const uint8_t *public_key, HDNode *out) { curve_point c; if (!ecdsa_read_pubkey(public_key, &c)) { // invalid pubkey @@ -46,7 +46,7 @@ int hdnode_from_xpub(uint32_t depth, uint32_t fingerprint, uint32_t child_num, u return 1; } -int hdnode_from_xprv(uint32_t depth, uint32_t fingerprint, uint32_t child_num, uint8_t *chain_code, uint8_t *private_key, HDNode *out) +int hdnode_from_xprv(uint32_t depth, uint32_t fingerprint, uint32_t child_num, const uint8_t *chain_code, const uint8_t *private_key, HDNode *out) { bignum256 a; bn_read_be(private_key, &a); @@ -62,7 +62,7 @@ int hdnode_from_xprv(uint32_t depth, uint32_t fingerprint, uint32_t child_num, u return 1; } -int hdnode_from_seed(uint8_t *seed, int seed_len, HDNode *out) +int hdnode_from_seed(const uint8_t *seed, int seed_len, HDNode *out) { uint8_t I[32 + 32]; memset(out, 0, sizeof(HDNode)); diff --git a/bip32.h b/bip32.h index 7fa810c0a..33218b0db 100644 --- a/bip32.h +++ b/bip32.h @@ -35,11 +35,11 @@ typedef struct { uint8_t public_key[33]; } HDNode; -int hdnode_from_xpub(uint32_t depth, uint32_t fingerprint, uint32_t child_num, uint8_t *chain_code, uint8_t *public_key, HDNode *out); +int hdnode_from_xpub(uint32_t depth, uint32_t fingerprint, uint32_t child_num, const uint8_t *chain_code, const uint8_t *public_key, HDNode *out); -int hdnode_from_xprv(uint32_t depth, uint32_t fingerprint, uint32_t child_num, uint8_t *chain_code, uint8_t *private_key, HDNode *out); +int hdnode_from_xprv(uint32_t depth, uint32_t fingerprint, uint32_t child_num, const uint8_t *chain_code, const uint8_t *private_key, HDNode *out); -int hdnode_from_seed(uint8_t *seed, int seed_len, HDNode *out); +int hdnode_from_seed(const uint8_t *seed, int seed_len, HDNode *out); #define hdnode_private_ckd_prime(X, I) hdnode_private_ckd((X), ((I) | 0x80000000)) From c6ca89a8507bd9310c0c92c180525989629fb7d4 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 20 Dec 2014 00:49:14 +0100 Subject: [PATCH 139/627] simplify check in hdnode_from_xpub --- bip32.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bip32.c b/bip32.c index ae4ffc5b2..6af1b8840 100644 --- a/bip32.c +++ b/bip32.c @@ -33,8 +33,7 @@ int hdnode_from_xpub(uint32_t depth, uint32_t fingerprint, uint32_t child_num, const uint8_t *chain_code, const uint8_t *public_key, HDNode *out) { - curve_point c; - if (!ecdsa_read_pubkey(public_key, &c)) { // invalid pubkey + if (public_key[0] != 0x02 && public_key[0] != 0x03) { // invalid pubkey return 0; } out->depth = depth; From 89a7d7797b806face0d023095c6f39c7869c5ff1 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 23 Dec 2014 01:17:58 +0100 Subject: [PATCH 140/627] replace base58 implementation --- base58.c | 277 ++++++++++++++++++++++++++++++++++++------------------- base58.h | 4 +- bip32.c | 14 +-- bip32.h | 4 +- ecdsa.c | 12 +-- ecdsa.h | 4 +- tests.c | 202 ++++++++++++++++++++++++++++------------ 7 files changed, 343 insertions(+), 174 deletions(-) diff --git a/base58.c b/base58.c index c4bdd2544..217264e30 100644 --- a/base58.c +++ b/base58.c @@ -1,5 +1,5 @@ /** - * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2012-2014 Luke Dashjr * Copyright (c) 2013-2014 Pavol Rusnak * * Permission is hereby granted, free of charge, to any person obtaining @@ -22,117 +22,202 @@ */ #include +#include +#include #include "base58.h" #include "sha2.h" -int base58_encode_check(const uint8_t *data, int len, char *str) +static const int8_t b58digits_map[] = { + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8,-1,-1,-1,-1,-1,-1, + -1, 9,10,11,12,13,14,15,16,-1,17,18,19,20,21,-1, + 22,23,24,25,26,27,28,29,30,31,32,-1,-1,-1,-1,-1, + -1,33,34,35,36,37,38,39,40,41,42,43,-1,44,45,46, + 47,48,49,50,51,52,53,54,55,56,57,-1,-1,-1,-1,-1, +}; + +bool b58tobin(void *bin, size_t *binszp, const char *b58) { - int outlen; - switch (len) { - case 78: // xpub/xprv 78 - outlen = 111; - break; - case 34: // WIF privkey 1+32+1 - outlen = 52; + size_t binsz = *binszp; + const unsigned char *b58u = (void*)b58; + unsigned char *binu = bin; + size_t outisz = (binsz + 3) / 4; + uint32_t outi[outisz]; + uint64_t t; + uint32_t c; + size_t i, j; + uint8_t bytesleft = binsz % 4; + uint32_t zeromask = bytesleft ? (0xffffffff << (bytesleft * 8)) : 0; + unsigned zerocount = 0; + size_t b58sz; + + b58sz = strlen(b58); + + memset(outi, 0, outisz * sizeof(*outi)); + + // Leading zeros, just count + for (i = 0; i < b58sz && !b58digits_map[b58u[i]]; ++i) + ++zerocount; + + for ( ; i < b58sz; ++i) + { + if (b58u[i] & 0x80) + // High-bit set on invalid digit + return false; + if (b58digits_map[b58u[i]] == -1) + // Invalid base58 digit + return false; + c = (unsigned)b58digits_map[b58u[i]]; + for (j = outisz; j--; ) + { + t = ((uint64_t)outi[j]) * 58 + c; + c = (t & 0x3f00000000) >> 32; + outi[j] = t & 0xffffffff; + } + if (c) + // Output number too big (carry to the next int32) + return false; + if (outi[0] & zeromask) + // Output number too big (last int32 filled too far) + return false; + } + + j = 0; + switch (bytesleft) { + case 3: + *(binu++) = (outi[0] & 0xff0000) >> 16; + case 2: + *(binu++) = (outi[0] & 0xff00) >> 8; + case 1: + *(binu++) = (outi[0] & 0xff); + ++j; + default: break; - case 21: // address 1+20 - outlen = 34; + } + + for (; j < outisz; ++j) + { + *(binu++) = (outi[j] >> 0x18) & 0xff; + *(binu++) = (outi[j] >> 0x10) & 0xff; + *(binu++) = (outi[j] >> 8) & 0xff; + *(binu++) = (outi[j] >> 0) & 0xff; + } + + // Count canonical base58 byte count + binu = bin; + for (i = 0; i < binsz; ++i) + { + if (binu[i]) break; - default: - return 0; + --*binszp; } - uint8_t mydata[82], hash[32]; - sha256_Raw(data, len, hash); - sha256_Raw(hash, 32, hash); - memcpy(mydata, data, len); - memcpy(mydata + len, hash, 4); // checksum - uint32_t rem, tmp; - const char code[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; - int i, j; - for (j = 0; j < outlen; j++) { - rem = mydata[0] % 58; - mydata[0] /= 58; - for (i = 1; i < len + 4; i++) { - tmp = rem * 24 + mydata[i]; // 2^8 == 4*58 + 24 - mydata[i] = rem * 4 + (tmp / 58); - rem = tmp % 58; + *binszp += zerocount; + + return true; +} + +int b58check(const void *bin, size_t binsz, const char *base58str) +{ + unsigned char buf[32]; + const uint8_t *binc = bin; + unsigned i; + if (binsz < 4) + return -4; + sha256_Raw(bin, binsz - 4, buf); + sha256_Raw(buf, 32, buf); + if (memcmp(&binc[binsz - 4], buf, 4)) + return -1; + + // Check number of zeros is correct AFTER verifying checksum (to avoid possibility of accessing base58str beyond the end) + for (i = 0; binc[i] == '\0' && base58str[i] == '1'; ++i) + {} // Just finding the end of zeros, nothing to do in loop + if (binc[i] == '\0' || base58str[i] == '1') + return -3; + + return binc[0]; +} + +static const char b58digits_ordered[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; + +bool b58enc(char *b58, size_t *b58sz, const void *data, size_t binsz) +{ + const uint8_t *bin = data; + int carry; + ssize_t i, j, high, zcount = 0; + size_t size; + + while (zcount < (ssize_t)binsz && !bin[zcount]) + ++zcount; + + size = (binsz - zcount) * 138 / 100 + 1; + uint8_t buf[size]; + memset(buf, 0, size); + + for (i = zcount, high = size - 1; i < (ssize_t)binsz; ++i, high = j) + { + for (carry = bin[i], j = size - 1; (j > high) || carry; --j) + { + carry += 256 * buf[j]; + buf[j] = carry % 58; + carry /= 58; } - str[j] = code[rem]; } - // remove duplicite 1s at the end - while (outlen > 1 && str[outlen - 1] == code[0] && str[outlen - 2] == code[0]) { - outlen--; + + for (j = 0; j < (ssize_t)size && !buf[j]; ++j); + + if (*b58sz <= zcount + size - j) + { + *b58sz = zcount + size - j + 1; + return false; } - str[outlen] = 0; - char s; - // reverse string - for (i = 0; i < outlen / 2; i++) { - s = str[i]; - str[i] = str[outlen - 1 - i]; - str[outlen - 1 - i] = s; + + if (zcount) + memset(b58, '1', zcount); + for (i = zcount; j < (ssize_t)size; ++i, ++j) + b58[i] = b58digits_ordered[buf[j]]; + b58[i] = '\0'; + *b58sz = i + 1; + + return true; +} + +#include + +int base58_encode_check(const uint8_t *data, int datalen, char *str, int strsize) +{ + if (datalen > 128) { + return 0; + } + uint8_t buf[datalen + 32]; + uint8_t *hash = buf + datalen; + memcpy(buf, data, datalen); + sha256_Raw(data, datalen, hash); + sha256_Raw(hash, 32, hash); + size_t res = strsize; + if (b58enc(str, &res, buf, datalen + 4) != true) { + return 0; } - return outlen; + return res; } -int base58_decode_check(const char *str, uint8_t *data) +int base58_decode_check(const char *str, uint8_t *data, int datalen) { - const char decode[] = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, - 4, 5, 6, 7, 8, -1, -1, -1, -1, -1, -1, -1, 9, 10, 11, - 12, 13, 14, 15, 16, -1, 17, 18, 19, 20, 21, -1, 22, - 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, -1, -1, -1, - -1, -1, -1, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, - 43, -1, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, - 55, 56, 57 - }; - int outlen; - switch (strlen(str)) { - case 111: // xpub/xprv - outlen = 78; - break; - case 52: // WIF privkey - outlen = 35; - break; - case 27: // address - case 28: - case 29: - case 30: - case 31: - case 32: - case 33: - case 34: - outlen = 21; - break; - default: - return 0; + if (datalen > 128) { + return 0; } - uint8_t mydata[82], hash[32]; - memset(mydata, 0, sizeof(mydata)); - int i, j, k; - while (*str) { - i = *str; - if (i < 0 || i >= (int)sizeof(decode)) { // invalid character - return 0; - } - k = decode[i]; - if (k == -1) { // invalid character - return 0; - } - for (j = outlen + 4 - 1; j >= 0; j--) { - k += mydata[j] * 58; - mydata[j] = k & 0xFF; - k >>= 8; - } - str++; + uint8_t d[datalen + 4]; + size_t res = datalen + 4; + if (b58tobin(d, &res, str) != true) { + return 0; } - sha256_Raw(mydata, outlen, hash); - sha256_Raw(hash, 32, hash); - if (memcmp(mydata + outlen, hash, 4)) { // wrong checksum + if (res != (size_t)datalen + 4) { + return 0; + } + if (b58check(d, res, str) < 0) { return 0; } - memcpy(data, mydata, outlen); - return outlen; + memcpy(data, d, datalen); + return datalen; } diff --git a/base58.h b/base58.h index 491f248bf..1f3eadfbc 100644 --- a/base58.h +++ b/base58.h @@ -26,7 +26,7 @@ #include -int base58_encode_check(const uint8_t *data, int len, char *str); -int base58_decode_check(const char *str, uint8_t *data); +int base58_encode_check(const uint8_t *data, int len, char *str, int strsize); +int base58_decode_check(const char *str, uint8_t *data, int datalen); #endif diff --git a/bip32.c b/bip32.c index 6af1b8840..f4a021d57 100644 --- a/bip32.c +++ b/bip32.c @@ -181,7 +181,7 @@ void hdnode_fill_public_key(HDNode *node) ecdsa_get_public_key33(node->private_key, node->public_key); } -void hdnode_serialize(const HDNode *node, uint32_t version, char use_public, char *str) +void hdnode_serialize(const HDNode *node, uint32_t version, char use_public, char *str, int strsize) { uint8_t node_data[78]; write_be(node_data, version); @@ -195,17 +195,17 @@ void hdnode_serialize(const HDNode *node, uint32_t version, char use_public, cha node_data[45] = 0; memcpy(node_data + 46, node->private_key, 32); } - base58_encode_check(node_data, 78, str); + base58_encode_check(node_data, 78, str, strsize); } -void hdnode_serialize_public(const HDNode *node, char *str) +void hdnode_serialize_public(const HDNode *node, char *str, int strsize) { - hdnode_serialize(node, 0x0488B21E, 1, str); + hdnode_serialize(node, 0x0488B21E, 1, str, strsize); } -void hdnode_serialize_private(const HDNode *node, char *str) +void hdnode_serialize_private(const HDNode *node, char *str, int strsize) { - hdnode_serialize(node, 0x0488ADE4, 0, str); + hdnode_serialize(node, 0x0488ADE4, 0, str, strsize); } // check for validity of curve point in case of public data not performed @@ -213,7 +213,7 @@ int hdnode_deserialize(const char *str, HDNode *node) { uint8_t node_data[78]; memset(node, 0, sizeof(HDNode)); - if (!base58_decode_check(str, node_data)) { + if (!base58_decode_check(str, node_data, sizeof(node_data))) { return -1; } uint32_t version = read_be(node_data); diff --git a/bip32.h b/bip32.h index 33218b0db..131d005ae 100644 --- a/bip32.h +++ b/bip32.h @@ -49,9 +49,9 @@ int hdnode_public_ckd(HDNode *inout, uint32_t i); void hdnode_fill_public_key(HDNode *node); -void hdnode_serialize_public(const HDNode *node, char *str); +void hdnode_serialize_public(const HDNode *node, char *str, int strsize); -void hdnode_serialize_private(const HDNode *node, char *str); +void hdnode_serialize_private(const HDNode *node, char *str, int strsize); int hdnode_deserialize(const char *str, HDNode *node); diff --git a/ecdsa.c b/ecdsa.c index 9e16447fc..9de0531a2 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -417,26 +417,26 @@ void ecdsa_get_address_raw(const uint8_t *pub_key, uint8_t version, uint8_t *add ecdsa_get_pubkeyhash(pub_key, addr_raw + 1); } -void ecdsa_get_address(const uint8_t *pub_key, uint8_t version, char *addr) +void ecdsa_get_address(const uint8_t *pub_key, uint8_t version, char *addr, int addrsize) { uint8_t raw[21]; ecdsa_get_address_raw(pub_key, version, raw); - base58_encode_check(raw, 21, addr); + base58_encode_check(raw, 21, addr, addrsize); } -void ecdsa_get_wif(const uint8_t *priv_key, uint8_t version, char *wif) +void ecdsa_get_wif(const uint8_t *priv_key, uint8_t version, char *wif, int wifsize) { uint8_t data[34]; data[0] = version; memcpy(data + 1, priv_key, 32); - data[33 ] = 0x01; - base58_encode_check(data, 34, wif); + data[33] = 0x01; + base58_encode_check(data, 34, wif, wifsize); } int ecdsa_address_decode(const char *addr, uint8_t *out) { if (!addr) return 0; - return base58_decode_check(addr, out) == 21; + return base58_decode_check(addr, out, 21) == 21; } void uncompress_coords(uint8_t odd, const bignum256 *x, bignum256 *y) diff --git a/ecdsa.h b/ecdsa.h index 292aeaf58..9f57268f9 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -46,8 +46,8 @@ void ecdsa_get_public_key33(const uint8_t *priv_key, uint8_t *pub_key); void ecdsa_get_public_key65(const uint8_t *priv_key, uint8_t *pub_key); void ecdsa_get_pubkeyhash(const uint8_t *pub_key, uint8_t *pubkeyhash); void ecdsa_get_address_raw(const uint8_t *pub_key, uint8_t version, uint8_t *addr_raw); -void ecdsa_get_address(const uint8_t *pub_key, uint8_t version, char *addr); -void ecdsa_get_wif(const uint8_t *priv_key, uint8_t version, char *wif); +void ecdsa_get_address(const uint8_t *pub_key, uint8_t version, char *addr, int addrsize); +void ecdsa_get_wif(const uint8_t *priv_key, uint8_t version, char *wif, int wifsize); int ecdsa_address_decode(const char *addr, uint8_t *out); int ecdsa_read_pubkey(const uint8_t *pub_key, curve_point *pub); int ecdsa_validate_pubkey(const curve_point *pub); diff --git a/tests.c b/tests.c index 91115ea1d..3f960d32e 100644 --- a/tests.c +++ b/tests.c @@ -29,6 +29,7 @@ #include "aes.h" #include "bignum.h" +#include "base58.h" #include "bip32.h" #include "bip39.h" #include "ecdsa.h" @@ -77,6 +78,85 @@ char *tohex(const uint8_t *bin, size_t l) #define ck_assert_mem_eq(X, Y, L) _ck_assert_mem(X, Y, L, ==) #define ck_assert_mem_ne(X, Y, L) _ck_assert_mem(X, Y, L, !=) +// from https://github.com/bitcoin/bitcoin/blob/master/src/test/data/base58_keys_valid.json +START_TEST(test_base58) +{ + static const char *base58_vector[] = { + "0065a16059864a2fdbc7c99a4723a8395bc6f188eb", "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i", + "0574f209f6ea907e2ea48f74fae05782ae8a665257", "3CMNFxN1oHBc4R1EpboAL5yzHGgE611Xou", + "6f53c0307d6851aa0ce7825ba883c6bd9ad242b486", "mo9ncXisMeAoXwqcV5EWuyncbmCcQN4rVs", + "c46349a418fc4578d10a372b54b45c280cc8c4382f", "2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br", + "80eddbdc1168f1daeadbd3e44c1e3f8f5a284c2029f78ad26af98583a499de5b19", "5Kd3NBUAdUnhyzenEwVLy9pBKxSwXvE9FMPyR4UKZvpe6E3AgLr", + "8055c9bccb9ed68446d1b75273bbce89d7fe013a8acd1625514420fb2aca1a21c401", "Kz6UJmQACJmLtaQj5A3JAge4kVTNQ8gbvXuwbmCj7bsaabudb3RD", + "ef36cb93b9ab1bdabf7fb9f2c04f1b9cc879933530ae7842398eef5a63a56800c2", "9213qJab2HNEpMpYNBa7wHGFKKbkDn24jpANDs2huN3yi4J11ko", + "efb9f4892c9e8282028fea1d2667c4dc5213564d41fc5783896a0d843fc15089f301", "cTpB4YiyKiBcPxnefsDpbnDxFDffjqJob8wGCEDXxgQ7zQoMXJdH", + "006d23156cbbdcc82a5a47eee4c2c7c583c18b6bf4", "1Ax4gZtb7gAit2TivwejZHYtNNLT18PUXJ", + "05fcc5460dd6e2487c7d75b1963625da0e8f4c5975", "3QjYXhTkvuj8qPaXHTTWb5wjXhdsLAAWVy", + "6ff1d470f9b02370fdec2e6b708b08ac431bf7a5f7", "n3ZddxzLvAY9o7184TB4c6FJasAybsw4HZ", + "c4c579342c2c4c9220205e2cdc285617040c924a0a", "2NBFNJTktNa7GZusGbDbGKRZTxdK9VVez3n", + "80a326b95ebae30164217d7a7f57d72ab2b54e3be64928a19da0210b9568d4015e", "5K494XZwps2bGyeL71pWid4noiSNA2cfCibrvRWqcHSptoFn7rc", + "807d998b45c219a1e38e99e7cbd312ef67f77a455a9b50c730c27f02c6f730dfb401", "L1RrrnXkcKut5DEMwtDthjwRcTTwED36thyL1DebVrKuwvohjMNi", + "efd6bca256b5abc5602ec2e1c121a08b0da2556587430bcf7e1898af2224885203", "93DVKyFYwSN6wEo3E2fCrFPUp17FtrtNi2Lf7n4G3garFb16CRj", + "efa81ca4e8f90181ec4b61b6a7eb998af17b2cb04de8a03b504b9e34c4c61db7d901", "cTDVKtMGVYWTHCb1AFjmVbEbWjvKpKqKgMaR3QJxToMSQAhmCeTN", + "007987ccaa53d02c8873487ef919677cd3db7a6912", "1C5bSj1iEGUgSTbziymG7Cn18ENQuT36vv", + "0563bcc565f9e68ee0189dd5cc67f1b0e5f02f45cb", "3AnNxabYGoTxYiTEZwFEnerUoeFXK2Zoks", + "6fef66444b5b17f14e8fae6e7e19b045a78c54fd79", "n3LnJXCqbPjghuVs8ph9CYsAe4Sh4j97wk", + "c4c3e55fceceaa4391ed2a9677f4a4d34eacd021a0", "2NB72XtkjpnATMggui83aEtPawyyKvnbX2o", + "80e75d936d56377f432f404aabb406601f892fd49da90eb6ac558a733c93b47252", "5KaBW9vNtWNhc3ZEDyNCiXLPdVPHCikRxSBWwV9NrpLLa4LsXi9", + "808248bd0375f2f75d7e274ae544fb920f51784480866b102384190b1addfbaa5c01", "L1axzbSyynNYA8mCAhzxkipKkfHtAXYF4YQnhSKcLV8YXA874fgT", + "ef44c4f6a096eac5238291a94cc24c01e3b19b8d8cef72874a079e00a242237a52", "927CnUkUbasYtDwYwVn2j8GdTuACNnKkjZ1rpZd2yBB1CLcnXpo", + "efd1de707020a9059d6d3abaf85e17967c6555151143db13dbb06db78df0f15c6901", "cUcfCMRjiQf85YMzzQEk9d1s5A4K7xL5SmBCLrezqXFuTVefyhY7", + "00adc1cc2081a27206fae25792f28bbc55b831549d", "1Gqk4Tv79P91Cc1STQtU3s1W6277M2CVWu", + "05188f91a931947eddd7432d6e614387e32b244709", "33vt8ViH5jsr115AGkW6cEmEz9MpvJSwDk", + "6f1694f5bc1a7295b600f40018a618a6ea48eeb498", "mhaMcBxNh5cqXm4aTQ6EcVbKtfL6LGyK2H", + "c43b9b3fd7a50d4f08d1a5b0f62f644fa7115ae2f3", "2MxgPqX1iThW3oZVk9KoFcE5M4JpiETssVN", + "80091035445ef105fa1bb125eccfb1882f3fe69592265956ade751fd095033d8d0", "5HtH6GdcwCJA4ggWEL1B3jzBBUB8HPiBi9SBc5h9i4Wk4PSeApR", + "80ab2b4bcdfc91d34dee0ae2a8c6b6668dadaeb3a88b9859743156f462325187af01", "L2xSYmMeVo3Zek3ZTsv9xUrXVAmrWxJ8Ua4cw8pkfbQhcEFhkXT8", + "efb4204389cef18bbe2b353623cbf93e8678fbc92a475b664ae98ed594e6cf0856", "92xFEve1Z9N8Z641KQQS7ByCSb8kGjsDzw6fAmjHN1LZGKQXyMq", + "efe7b230133f1b5489843260236b06edca25f66adb1be455fbd38d4010d48faeef01", "cVM65tdYu1YK37tNoAyGoJTR13VBYFva1vg9FLuPAsJijGvG6NEA", + "00c4c1b72491ede1eedaca00618407ee0b772cad0d", "1JwMWBVLtiqtscbaRHai4pqHokhFCbtoB4", + "05f6fe69bcb548a829cce4c57bf6fff8af3a5981f9", "3QCzvfL4ZRvmJFiWWBVwxfdaNBT8EtxB5y", + "6f261f83568a098a8638844bd7aeca039d5f2352c0", "mizXiucXRCsEriQCHUkCqef9ph9qtPbZZ6", + "c4e930e1834a4d234702773951d627cce82fbb5d2e", "2NEWDzHWwY5ZZp8CQWbB7ouNMLqCia6YRda", + "80d1fab7ab7385ad26872237f1eb9789aa25cc986bacc695e07ac571d6cdac8bc0", "5KQmDryMNDcisTzRp3zEq9e4awRmJrEVU1j5vFRTKpRNYPqYrMg", + "80b0bbede33ef254e8376aceb1510253fc3550efd0fcf84dcd0c9998b288f166b301", "L39Fy7AC2Hhj95gh3Yb2AU5YHh1mQSAHgpNixvm27poizcJyLtUi", + "ef037f4192c630f399d9271e26c575269b1d15be553ea1a7217f0cb8513cef41cb", "91cTVUcgydqyZLgaANpf1fvL55FH53QMm4BsnCADVNYuWuqdVys", + "ef6251e205e8ad508bab5596bee086ef16cd4b239e0cc0c5d7c4e6035441e7d5de01", "cQspfSzsgLeiJGB2u8vrAiWpCU4MxUT6JseWo2SjXy4Qbzn2fwDw", + "005eadaf9bb7121f0f192561a5a62f5e5f54210292", "19dcawoKcZdQz365WpXWMhX6QCUpR9SY4r", + "053f210e7277c899c3a155cc1c90f4106cbddeec6e", "37Sp6Rv3y4kVd1nQ1JV5pfqXccHNyZm1x3", + "6fc8a3c2a09a298592c3e180f02487cd91ba3400b5", "myoqcgYiehufrsnnkqdqbp69dddVDMopJu", + "c499b31df7c9068d1481b596578ddbb4d3bd90baeb", "2N7FuwuUuoTBrDFdrAZ9KxBmtqMLxce9i1C", + "80c7666842503db6dc6ea061f092cfb9c388448629a6fe868d068c42a488b478ae", "5KL6zEaMtPRXZKo1bbMq7JDjjo1bJuQcsgL33je3oY8uSJCR5b4", + "8007f0803fc5399e773555ab1e8939907e9badacc17ca129e67a2f5f2ff84351dd01", "KwV9KAfwbwt51veZWNscRTeZs9CKpojyu1MsPnaKTF5kz69H1UN2", + "efea577acfb5d1d14d3b7b195c321566f12f87d2b77ea3a53f68df7ebf8604a801", "93N87D6uxSBzwXvpokpzg8FFmfQPmvX4xHoWQe3pLdYpbiwT5YV", + "ef0b3b34f0958d8a268193a9814da92c3e8b58b4a4378a542863e34ac289cd830c01", "cMxXusSihaX58wpJ3tNuuUcZEQGt6DKJ1wEpxys88FFaQCYjku9h", + "001ed467017f043e91ed4c44b4e8dd674db211c4e6", "13p1ijLwsnrcuyqcTvJXkq2ASdXqcnEBLE", + "055ece0cadddc415b1980f001785947120acdb36fc", "3ALJH9Y951VCGcVZYAdpA3KchoP9McEj1G", + 0, 0, + }; + const char **raw = base58_vector; + const char **str = base58_vector + 1; + uint8_t rawn[34]; + char strn[53]; + int r; + while (*raw && *str) { + int len = strlen(*raw) / 2; + + memcpy(rawn, fromhex(*raw), len); + r = base58_encode_check(rawn, len, strn, sizeof(strn)); + ck_assert_int_eq(r, strlen(*str) + 1); + ck_assert_str_eq(strn, *str); + + r = base58_decode_check(strn, rawn, len); + ck_assert_int_eq(r, len); + ck_assert_mem_eq(rawn, fromhex(*raw), len); + + raw += 2; str += 2; + } +} +END_TEST + + // test vector 1 from https://en.bitcoin.it/wiki/BIP_0032_TestVectors START_TEST(test_bip32_vector_1) { @@ -92,11 +172,11 @@ START_TEST(test_bip32_vector_1) ck_assert_mem_eq(node.chain_code, fromhex("873dff81c02f525623fd1fe5167eac3a55a049de3d314bb42ee227ffed37d508"), 32); ck_assert_mem_eq(node.private_key, fromhex("e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35"), 32); ck_assert_mem_eq(node.public_key, fromhex("0339a36013301597daef41fbe593a02cc513d0b55527ec2df1050e2e8ff49c85c2"), 33); - hdnode_serialize_private(&node, str); + hdnode_serialize_private(&node, str, sizeof(str)); ck_assert_str_eq(str, "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi"); r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); ck_assert_int_eq(r, 0); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, str); + hdnode_serialize_public(&node, str, sizeof(str)); ck_assert_str_eq(str, "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8"); r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); @@ -109,11 +189,11 @@ START_TEST(test_bip32_vector_1) ck_assert_mem_eq(node.chain_code, fromhex("47fdacbd0f1097043b78c63c20c34ef4ed9a111d980047ad16282c7ae6236141"), 32); ck_assert_mem_eq(node.private_key, fromhex("edb2e14f9ee77d26dd93b4ecede8d16ed408ce149b6cd80b0715a2d911a0afea"), 32); ck_assert_mem_eq(node.public_key, fromhex("035a784662a4a20a65bf6aab9ae98a6c068a81c52e4b032c0fb5400c706cfccc56"), 33); - hdnode_serialize_private(&node, str); + hdnode_serialize_private(&node, str, sizeof(str)); ck_assert_str_eq(str, "xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7"); r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, str); + hdnode_serialize_public(&node, str, sizeof(str)); ck_assert_str_eq(str, "xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw"); r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); @@ -126,11 +206,11 @@ START_TEST(test_bip32_vector_1) ck_assert_mem_eq(node.chain_code, fromhex("2a7857631386ba23dacac34180dd1983734e444fdbf774041578e9b6adb37c19"), 32); ck_assert_mem_eq(node.private_key, fromhex("3c6cb8d0f6a264c91ea8b5030fadaa8e538b020f0a387421a12de9319dc93368"), 32); ck_assert_mem_eq(node.public_key, fromhex("03501e454bf00751f24b1b489aa925215d66af2234e3891c3b21a52bedb3cd711c"), 33); - hdnode_serialize_private(&node, str); + hdnode_serialize_private(&node, str, sizeof(str)); ck_assert_str_eq(str, "xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs"); r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, str); + hdnode_serialize_public(&node, str, sizeof(str)); ck_assert_str_eq(str, "xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFHKkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ"); r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); @@ -143,11 +223,11 @@ START_TEST(test_bip32_vector_1) ck_assert_mem_eq(node.chain_code, fromhex("04466b9cc8e161e966409ca52986c584f07e9dc81f735db683c3ff6ec7b1503f"), 32); ck_assert_mem_eq(node.private_key, fromhex("cbce0d719ecf7431d88e6a89fa1483e02e35092af60c042b1df2ff59fa424dca"), 32); ck_assert_mem_eq(node.public_key, fromhex("0357bfe1e341d01c69fe5654309956cbea516822fba8a601743a012a7896ee8dc2"), 33); - hdnode_serialize_private(&node, str); + hdnode_serialize_private(&node, str, sizeof(str)); ck_assert_str_eq(str, "xprv9z4pot5VBttmtdRTWfWQmoH1taj2axGVzFqSb8C9xaxKymcFzXBDptWmT7FwuEzG3ryjH4ktypQSAewRiNMjANTtpgP4mLTj34bhnZX7UiM"); r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, str); + hdnode_serialize_public(&node, str, sizeof(str)); ck_assert_str_eq(str, "xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5"); r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); @@ -160,11 +240,11 @@ START_TEST(test_bip32_vector_1) ck_assert_mem_eq(node.chain_code, fromhex("cfb71883f01676f587d023cc53a35bc7f88f724b1f8c2892ac1275ac822a3edd"), 32); ck_assert_mem_eq(node.private_key, fromhex("0f479245fb19a38a1954c5c7c0ebab2f9bdfd96a17563ef28a6a4b1a2a764ef4"), 32); ck_assert_mem_eq(node.public_key, fromhex("02e8445082a72f29b75ca48748a914df60622a609cacfce8ed0e35804560741d29"), 33); - hdnode_serialize_private(&node, str); + hdnode_serialize_private(&node, str, sizeof(str)); ck_assert_str_eq(str, "xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334"); r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, str); + hdnode_serialize_public(&node, str, sizeof(str)); ck_assert_str_eq(str, "xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV"); r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); @@ -177,11 +257,11 @@ START_TEST(test_bip32_vector_1) ck_assert_mem_eq(node.chain_code, fromhex("c783e67b921d2beb8f6b389cc646d7263b4145701dadd2161548a8b078e65e9e"), 32); ck_assert_mem_eq(node.private_key, fromhex("471b76e389e528d6de6d816857e012c5455051cad6660850e58372a6c3e6e7c8"), 32); ck_assert_mem_eq(node.public_key, fromhex("022a471424da5e657499d1ff51cb43c47481a03b1e77f951fe64cec9f5a48f7011"), 33); - hdnode_serialize_private(&node, str); + hdnode_serialize_private(&node, str, sizeof(str)); ck_assert_str_eq(str, "xprvA41z7zogVVwxVSgdKUHDy1SKmdb533PjDz7J6N6mV6uS3ze1ai8FHa8kmHScGpWmj4WggLyQjgPie1rFSruoUihUZREPSL39UNdE3BBDu76"); r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, str); + hdnode_serialize_public(&node, str, sizeof(str)); ck_assert_str_eq(str, "xpub6H1LXWLaKsWFhvm6RVpEL9P4KfRZSW7abD2ttkWP3SSQvnyA8FSVqNTEcYFgJS2UaFcxupHiYkro49S8yGasTvXEYBVPamhGW6cFJodrTHy"); r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); @@ -205,11 +285,11 @@ START_TEST(test_bip32_vector_2) ck_assert_mem_eq(node.chain_code, fromhex("60499f801b896d83179a4374aeb7822aaeaceaa0db1f85ee3e904c4defbd9689"), 32); ck_assert_mem_eq(node.private_key, fromhex("4b03d6fc340455b363f51020ad3ecca4f0850280cf436c70c727923f6db46c3e"), 32); ck_assert_mem_eq(node.public_key, fromhex("03cbcaa9c98c877a26977d00825c956a238e8dddfbd322cce4f74b0b5bd6ace4a7"), 33); - hdnode_serialize_private(&node, str); + hdnode_serialize_private(&node, str, sizeof(str)); ck_assert_str_eq(str, "xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U"); r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, str); + hdnode_serialize_public(&node, str, sizeof(str)); ck_assert_str_eq(str, "xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB"); r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); @@ -223,11 +303,11 @@ START_TEST(test_bip32_vector_2) ck_assert_mem_eq(node.chain_code, fromhex("f0909affaa7ee7abe5dd4e100598d4dc53cd709d5a5c2cac40e7412f232f7c9c"), 32); ck_assert_mem_eq(node.private_key, fromhex("abe74a98f6c7eabee0428f53798f0ab8aa1bd37873999041703c742f15ac7e1e"), 32); ck_assert_mem_eq(node.public_key, fromhex("02fc9e5af0ac8d9b3cecfe2a888e2117ba3d089d8585886c9c826b6b22a98d12ea"), 33); - hdnode_serialize_private(&node, str); + hdnode_serialize_private(&node, str, sizeof(str)); ck_assert_str_eq(str, "xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt"); r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, str); + hdnode_serialize_public(&node, str, sizeof(str)); ck_assert_str_eq(str, "xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH"); r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); @@ -241,11 +321,11 @@ START_TEST(test_bip32_vector_2) ck_assert_mem_eq(node.chain_code, fromhex("be17a268474a6bb9c61e1d720cf6215e2a88c5406c4aee7b38547f585c9a37d9"), 32); ck_assert_mem_eq(node.private_key, fromhex("877c779ad9687164e9c2f4f0f4ff0340814392330693ce95a58fe18fd52e6e93"), 32); ck_assert_mem_eq(node.public_key, fromhex("03c01e7425647bdefa82b12d9bad5e3e6865bee0502694b94ca58b666abc0a5c3b"), 33); - hdnode_serialize_private(&node, str); + hdnode_serialize_private(&node, str, sizeof(str)); ck_assert_str_eq(str, "xprv9wSp6B7kry3Vj9m1zSnLvN3xH8RdsPP1Mh7fAaR7aRLcQMKTR2vidYEeEg2mUCTAwCd6vnxVrcjfy2kRgVsFawNzmjuHc2YmYRmagcEPdU9"); r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, str); + hdnode_serialize_public(&node, str, sizeof(str)); ck_assert_str_eq(str, "xpub6ASAVgeehLbnwdqV6UKMHVzgqAG8Gr6riv3Fxxpj8ksbH9ebxaEyBLZ85ySDhKiLDBrQSARLq1uNRts8RuJiHjaDMBU4Zn9h8LZNnBC5y4a"); r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); @@ -259,11 +339,11 @@ START_TEST(test_bip32_vector_2) ck_assert_mem_eq(node.chain_code, fromhex("f366f48f1ea9f2d1d3fe958c95ca84ea18e4c4ddb9366c336c927eb246fb38cb"), 32); ck_assert_mem_eq(node.private_key, fromhex("704addf544a06e5ee4bea37098463c23613da32020d604506da8c0518e1da4b7"), 32); ck_assert_mem_eq(node.public_key, fromhex("03a7d1d856deb74c508e05031f9895dab54626251b3806e16b4bd12e781a7df5b9"), 33); - hdnode_serialize_private(&node, str); + hdnode_serialize_private(&node, str, sizeof(str)); ck_assert_str_eq(str, "xprv9zFnWC6h2cLgpmSA46vutJzBcfJ8yaJGg8cX1e5StJh45BBciYTRXSd25UEPVuesF9yog62tGAQtHjXajPPdbRCHuWS6T8XA2ECKADdw4Ef"); r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, str); + hdnode_serialize_public(&node, str, sizeof(str)); ck_assert_str_eq(str, "xpub6DF8uhdarytz3FWdA8TvFSvvAh8dP3283MY7p2V4SeE2wyWmG5mg5EwVvmdMVCQcoNJxGoWaU9DCWh89LojfZ537wTfunKau47EL2dhHKon"); r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); @@ -277,11 +357,11 @@ START_TEST(test_bip32_vector_2) ck_assert_mem_eq(node.chain_code, fromhex("637807030d55d01f9a0cb3a7839515d796bd07706386a6eddf06cc29a65a0e29"), 32); ck_assert_mem_eq(node.private_key, fromhex("f1c7c871a54a804afe328b4c83a1c33b8e5ff48f5087273f04efa83b247d6a2d"), 32); ck_assert_mem_eq(node.public_key, fromhex("02d2b36900396c9282fa14628566582f206a5dd0bcc8d5e892611806cafb0301f0"), 33); - hdnode_serialize_private(&node, str); + hdnode_serialize_private(&node, str, sizeof(str)); ck_assert_str_eq(str, "xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc"); r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, str); + hdnode_serialize_public(&node, str, sizeof(str)); ck_assert_str_eq(str, "xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL"); r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); @@ -295,11 +375,11 @@ START_TEST(test_bip32_vector_2) ck_assert_mem_eq(node.chain_code, fromhex("9452b549be8cea3ecb7a84bec10dcfd94afe4d129ebfd3b3cb58eedf394ed271"), 32); ck_assert_mem_eq(node.private_key, fromhex("bb7d39bdb83ecf58f2fd82b6d918341cbef428661ef01ab97c28a4842125ac23"), 32); ck_assert_mem_eq(node.public_key, fromhex("024d902e1a2fc7a8755ab5b694c575fce742c48d9ff192e63df5193e4c7afe1f9c"), 33); - hdnode_serialize_private(&node, str); + hdnode_serialize_private(&node, str, sizeof(str)); ck_assert_str_eq(str, "xprvA2nrNbFZABcdryreWet9Ea4LvTJcGsqrMzxHx98MMrotbir7yrKCEXw7nadnHM8Dq38EGfSh6dqA9QWTyefMLEcBYJUuekgW4BYPJcr9E7j"); r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, str); + hdnode_serialize_public(&node, str, sizeof(str)); ck_assert_str_eq(str, "xpub6FnCn6nSzZAw5Tw7cgR9bi15UV96gLZhjDstkXXxvCLsUXBGXPdSnLFbdpq8p9HmGsApME5hQTZ3emM2rnY5agb9rXpVGyy3bdW6EEgAtqt"); r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); @@ -829,50 +909,50 @@ END_TEST START_TEST(test_address) { - char address[35]; + char address[36]; uint8_t pub_key[65]; memcpy(pub_key, fromhex("0226659c1cf7321c178c07437150639ff0c5b7679c7ea195253ed9abda2e081a37"), 33); - ecdsa_get_address(pub_key, 0, address); ck_assert_str_eq(address, "139MaMHp3Vjo8o4x8N1ZLWEtovLGvBsg6s"); - ecdsa_get_address(pub_key, 111, address); ck_assert_str_eq(address, "mhfJsQNnrXB3uuYZqvywARTDfuvyjg4RBh"); - ecdsa_get_address(pub_key, 52, address); ck_assert_str_eq(address, "MxiimznnxsqMfLKTQBL8Z2PoY9jKpjgkCu"); - ecdsa_get_address(pub_key, 48, address); ck_assert_str_eq(address, "LMNJqZbe89yrPbm7JVzrcXJf28hZ1rKPaH"); + ecdsa_get_address(pub_key, 0, address, sizeof(address)); ck_assert_str_eq(address, "139MaMHp3Vjo8o4x8N1ZLWEtovLGvBsg6s"); + ecdsa_get_address(pub_key, 111, address, sizeof(address)); ck_assert_str_eq(address, "mhfJsQNnrXB3uuYZqvywARTDfuvyjg4RBh"); + ecdsa_get_address(pub_key, 52, address, sizeof(address)); ck_assert_str_eq(address, "MxiimznnxsqMfLKTQBL8Z2PoY9jKpjgkCu"); + ecdsa_get_address(pub_key, 48, address, sizeof(address)); ck_assert_str_eq(address, "LMNJqZbe89yrPbm7JVzrcXJf28hZ1rKPaH"); memcpy(pub_key, fromhex("025b1654a0e78d28810094f6c5a96b8efb8a65668b578f170ac2b1f83bc63ba856"), 33); - ecdsa_get_address(pub_key, 0, address); ck_assert_str_eq(address, "19Ywfm3witp6C1yBMy4NRYHY2347WCRBfQ"); - ecdsa_get_address(pub_key, 111, address); ck_assert_str_eq(address, "mp4txp8vXvFLy8So5Y2kFTVrt2epN6YzdP"); - ecdsa_get_address(pub_key, 52, address); ck_assert_str_eq(address, "N58JsQYveGueiZDgdnNwe4SSkGTAToutAY"); - ecdsa_get_address(pub_key, 48, address); ck_assert_str_eq(address, "LTmtvyMmoZ49SpfLY73fhZMJEFRPdyohKh"); + ecdsa_get_address(pub_key, 0, address, sizeof(address)); ck_assert_str_eq(address, "19Ywfm3witp6C1yBMy4NRYHY2347WCRBfQ"); + ecdsa_get_address(pub_key, 111, address, sizeof(address)); ck_assert_str_eq(address, "mp4txp8vXvFLy8So5Y2kFTVrt2epN6YzdP"); + ecdsa_get_address(pub_key, 52, address, sizeof(address)); ck_assert_str_eq(address, "N58JsQYveGueiZDgdnNwe4SSkGTAToutAY"); + ecdsa_get_address(pub_key, 48, address, sizeof(address)); ck_assert_str_eq(address, "LTmtvyMmoZ49SpfLY73fhZMJEFRPdyohKh"); memcpy(pub_key, fromhex("03433f246a12e6486a51ff08802228c61cf895175a9b49ed4766ea9a9294a3c7fe"), 33); - ecdsa_get_address(pub_key, 0, address); ck_assert_str_eq(address, "1FWE2bn3MWhc4QidcF6AvEWpK77sSi2cAP"); - ecdsa_get_address(pub_key, 111, address); ck_assert_str_eq(address, "mv2BKes2AY8rqXCFKp4Yk9j9B6iaMfWRLN"); - ecdsa_get_address(pub_key, 52, address); ck_assert_str_eq(address, "NB5bEFH2GtoAawy8t4Qk8kfj3LWvQs3MhB"); - ecdsa_get_address(pub_key, 48, address); ck_assert_str_eq(address, "LZjBHp5sSAwfKDQnnP5UCFaaXKV9YheGxQ"); + ecdsa_get_address(pub_key, 0, address, sizeof(address)); ck_assert_str_eq(address, "1FWE2bn3MWhc4QidcF6AvEWpK77sSi2cAP"); + ecdsa_get_address(pub_key, 111, address, sizeof(address)); ck_assert_str_eq(address, "mv2BKes2AY8rqXCFKp4Yk9j9B6iaMfWRLN"); + ecdsa_get_address(pub_key, 52, address, sizeof(address)); ck_assert_str_eq(address, "NB5bEFH2GtoAawy8t4Qk8kfj3LWvQs3MhB"); + ecdsa_get_address(pub_key, 48, address, sizeof(address)); ck_assert_str_eq(address, "LZjBHp5sSAwfKDQnnP5UCFaaXKV9YheGxQ"); memcpy(pub_key, fromhex("03aeb03abeee0f0f8b4f7a5d65ce31f9570cef9f72c2dd8a19b4085a30ab033d48"), 33); - ecdsa_get_address(pub_key, 0, address); ck_assert_str_eq(address, "1yrZb8dhdevoqpUEGi2tUccUEeiMKeLcs"); - ecdsa_get_address(pub_key, 111, address); ck_assert_str_eq(address, "mgVoreDcWf6BaxJ5wqgQiPpwLEFRLSr8U8"); - ecdsa_get_address(pub_key, 52, address); ck_assert_str_eq(address, "MwZDmEdcd1kVLP4yW62c6zmXCU3mNbveDo"); - ecdsa_get_address(pub_key, 48, address); ck_assert_str_eq(address, "LLCopoSTnHtz4eWdQQhLAVgNgT1zTi4QBK"); + ecdsa_get_address(pub_key, 0, address, sizeof(address)); ck_assert_str_eq(address, "1yrZb8dhdevoqpUEGi2tUccUEeiMKeLcs"); + ecdsa_get_address(pub_key, 111, address, sizeof(address)); ck_assert_str_eq(address, "mgVoreDcWf6BaxJ5wqgQiPpwLEFRLSr8U8"); + ecdsa_get_address(pub_key, 52, address, sizeof(address)); ck_assert_str_eq(address, "MwZDmEdcd1kVLP4yW62c6zmXCU3mNbveDo"); + ecdsa_get_address(pub_key, 48, address, sizeof(address)); ck_assert_str_eq(address, "LLCopoSTnHtz4eWdQQhLAVgNgT1zTi4QBK"); memcpy(pub_key, fromhex("0496e8f2093f018aff6c2e2da5201ee528e2c8accbf9cac51563d33a7bb74a016054201c025e2a5d96b1629b95194e806c63eb96facaedc733b1a4b70ab3b33e3a"), 65); - ecdsa_get_address(pub_key, 0, address); ck_assert_str_eq(address, "194SZbL75xCCGBbKtMsyWLE5r9s2V6mhVM"); - ecdsa_get_address(pub_key, 111, address); ck_assert_str_eq(address, "moaPreR5tydT3J4wbvrMLFSQi9TjPCiZc6"); - ecdsa_get_address(pub_key, 52, address); ck_assert_str_eq(address, "N4domEq61LHkniqqABCYirNzaPG5NRU8GH"); - ecdsa_get_address(pub_key, 48, address); ck_assert_str_eq(address, "LTHPpodwAcSFWzHV4VsGnMHr4NEJajMnKX"); + ecdsa_get_address(pub_key, 0, address, sizeof(address)); ck_assert_str_eq(address, "194SZbL75xCCGBbKtMsyWLE5r9s2V6mhVM"); + ecdsa_get_address(pub_key, 111, address, sizeof(address)); ck_assert_str_eq(address, "moaPreR5tydT3J4wbvrMLFSQi9TjPCiZc6"); + ecdsa_get_address(pub_key, 52, address, sizeof(address)); ck_assert_str_eq(address, "N4domEq61LHkniqqABCYirNzaPG5NRU8GH"); + ecdsa_get_address(pub_key, 48, address, sizeof(address)); ck_assert_str_eq(address, "LTHPpodwAcSFWzHV4VsGnMHr4NEJajMnKX"); memcpy(pub_key, fromhex("0498010f8a687439ff497d3074beb4519754e72c4b6220fb669224749591dde416f3961f8ece18f8689bb32235e436874d2174048b86118a00afbd5a4f33a24f0f"), 65); - ecdsa_get_address(pub_key, 0, address); ck_assert_str_eq(address, "1A2WfBD4BJFwYHFPc5KgktqtbdJLBuVKc4"); - ecdsa_get_address(pub_key, 111, address); ck_assert_str_eq(address, "mpYTxEJ2zKhCKPj1KeJ4ap4DTcu39T3uzD"); - ecdsa_get_address(pub_key, 52, address); ck_assert_str_eq(address, "N5bsrpi36gMW4pVtsteFyQzoKrhPE7nkxK"); - ecdsa_get_address(pub_key, 48, address); ck_assert_str_eq(address, "LUFTvPWtFxVzo5wYnDJz2uueoqfcMYiuxH"); + ecdsa_get_address(pub_key, 0, address, sizeof(address)); ck_assert_str_eq(address, "1A2WfBD4BJFwYHFPc5KgktqtbdJLBuVKc4"); + ecdsa_get_address(pub_key, 111, address, sizeof(address)); ck_assert_str_eq(address, "mpYTxEJ2zKhCKPj1KeJ4ap4DTcu39T3uzD"); + ecdsa_get_address(pub_key, 52, address, sizeof(address)); ck_assert_str_eq(address, "N5bsrpi36gMW4pVtsteFyQzoKrhPE7nkxK"); + ecdsa_get_address(pub_key, 48, address, sizeof(address)); ck_assert_str_eq(address, "LUFTvPWtFxVzo5wYnDJz2uueoqfcMYiuxH"); memcpy(pub_key, fromhex("04f80490839af36d13701ec3f9eebdac901b51c362119d74553a3c537faff31b17e2a59ebddbdac9e87b816307a7ed5b826b8f40b92719086238e1bebf19b77a4d"), 65); - ecdsa_get_address(pub_key, 0, address); ck_assert_str_eq(address, "19J81hrPnQxg9UGx45ibTieCkb2ttm8CLL"); - ecdsa_get_address(pub_key, 111, address); ck_assert_str_eq(address, "mop5JkwNbSPvvakZmegyHdrXcadbjLazww"); - ecdsa_get_address(pub_key, 52, address); ck_assert_str_eq(address, "N4sVDMMNho4Eg1XTKu3AgEo7UpRwq3aNbn"); - ecdsa_get_address(pub_key, 48, address); ck_assert_str_eq(address, "LTX5GvADs5CjQGy7EDhtjjhxxoQB2Uhicd"); + ecdsa_get_address(pub_key, 0, address, sizeof(address)); ck_assert_str_eq(address, "19J81hrPnQxg9UGx45ibTieCkb2ttm8CLL"); + ecdsa_get_address(pub_key, 111, address, sizeof(address)); ck_assert_str_eq(address, "mop5JkwNbSPvvakZmegyHdrXcadbjLazww"); + ecdsa_get_address(pub_key, 52, address, sizeof(address)); ck_assert_str_eq(address, "N4sVDMMNho4Eg1XTKu3AgEo7UpRwq3aNbn"); + ecdsa_get_address(pub_key, 48, address, sizeof(address)); ck_assert_str_eq(address, "LTX5GvADs5CjQGy7EDhtjjhxxoQB2Uhicd"); } END_TEST @@ -932,16 +1012,16 @@ START_TEST(test_wif) char wif[53]; memcpy(priv_key, fromhex("1111111111111111111111111111111111111111111111111111111111111111"), 32); - ecdsa_get_wif(priv_key, 0x80, wif); ck_assert_str_eq(wif, "KwntMbt59tTsj8xqpqYqRRWufyjGunvhSyeMo3NTYpFYzZbXJ5Hp"); - ecdsa_get_wif(priv_key, 0xEF, wif); ck_assert_str_eq(wif, "cN9spWsvaxA8taS7DFMxnk1yJD2gaF2PX1npuTpy3vuZFJdwavaw"); + ecdsa_get_wif(priv_key, 0x80, wif, sizeof(wif)); ck_assert_str_eq(wif, "KwntMbt59tTsj8xqpqYqRRWufyjGunvhSyeMo3NTYpFYzZbXJ5Hp"); + ecdsa_get_wif(priv_key, 0xEF, wif, sizeof(wif)); ck_assert_str_eq(wif, "cN9spWsvaxA8taS7DFMxnk1yJD2gaF2PX1npuTpy3vuZFJdwavaw"); memcpy(priv_key, fromhex("dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"), 32); - ecdsa_get_wif(priv_key, 0x80, wif); ck_assert_str_eq(wif, "L4ezQvyC6QoBhxB4GVs9fAPhUKtbaXYUn8YTqoeXwbevQq4U92vN"); - ecdsa_get_wif(priv_key, 0xEF, wif); ck_assert_str_eq(wif, "cV1ysqy3XUVSsPeKeugH2Utm6ZC1EyeArAgvxE73SiJvfa6AJng7"); + ecdsa_get_wif(priv_key, 0x80, wif, sizeof(wif)); ck_assert_str_eq(wif, "L4ezQvyC6QoBhxB4GVs9fAPhUKtbaXYUn8YTqoeXwbevQq4U92vN"); + ecdsa_get_wif(priv_key, 0xEF, wif, sizeof(wif)); ck_assert_str_eq(wif, "cV1ysqy3XUVSsPeKeugH2Utm6ZC1EyeArAgvxE73SiJvfa6AJng7"); memcpy(priv_key, fromhex("47f7616ea6f9b923076625b4488115de1ef1187f760e65f89eb6f4f7ff04b012"), 32); - ecdsa_get_wif(priv_key, 0x80, wif); ck_assert_str_eq(wif, "KydbzBtk6uc7M6dXwEgTEH2sphZxSPbmDSz6kUUHi4eUpSQuhEbq"); - ecdsa_get_wif(priv_key, 0xEF, wif); ck_assert_str_eq(wif, "cPzbT6tbXyJNWY6oKeVabbXwSvsN6qhTHV8ZrtvoDBJV5BRY1G5Q"); + ecdsa_get_wif(priv_key, 0x80, wif, sizeof(wif)); ck_assert_str_eq(wif, "KydbzBtk6uc7M6dXwEgTEH2sphZxSPbmDSz6kUUHi4eUpSQuhEbq"); + ecdsa_get_wif(priv_key, 0xEF, wif, sizeof(wif)); ck_assert_str_eq(wif, "cPzbT6tbXyJNWY6oKeVabbXwSvsN6qhTHV8ZrtvoDBJV5BRY1G5Q"); } END_TEST @@ -1061,6 +1141,10 @@ Suite *test_suite(void) Suite *s = suite_create("trezor-crypto"); TCase *tc; + tc = tcase_create("base58"); + tcase_add_test(tc, test_base58); + suite_add_tcase(s, tc); + tc = tcase_create("bip32"); tcase_add_test(tc, test_bip32_vector_1); tcase_add_test(tc, test_bip32_vector_2); From 795579cbacb5e4bd072d7cef2a2638f1d44c2d0d Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 23 Dec 2014 18:13:33 +0100 Subject: [PATCH 141/627] invert pby when normalizing S during signing --- ecdsa.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ecdsa.c b/ecdsa.c index 9de0531a2..a4a6c1acc 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -364,6 +364,9 @@ int ecdsa_sign_digest(const uint8_t *priv_key, const uint8_t *digest, uint8_t *s // if S > order/2 => S = -S if (bn_is_less(&order256k1_half, &k)) { bn_substract_noprime(&order256k1, &k, &k); + if (pby) { + *pby = !*pby; + } } // we are done, R.x and k is the result signature From 280310c8a01084667d4f5c431c6cf3fc365b993b Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 24 Dec 2014 01:26:39 +0100 Subject: [PATCH 142/627] add xpubaddrgen utility --- tools/.gitignore | 1 + tools/Makefile | 37 +++++++++++++++++++++++++++++++++++++ tools/README | 36 ++++++++++++++++++++++++++++++++++++ tools/xpubaddrgen.c | 43 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 117 insertions(+) create mode 100644 tools/.gitignore create mode 100644 tools/Makefile create mode 100644 tools/README create mode 100644 tools/xpubaddrgen.c diff --git a/tools/.gitignore b/tools/.gitignore new file mode 100644 index 000000000..ac00e6bcd --- /dev/null +++ b/tools/.gitignore @@ -0,0 +1 @@ +xpubaddrgen diff --git a/tools/Makefile b/tools/Makefile new file mode 100644 index 000000000..67c652637 --- /dev/null +++ b/tools/Makefile @@ -0,0 +1,37 @@ +CC = gcc + +OPTFLAGS = -O3 + +CFLAGS += $(OPTFLAGS) \ + -W \ + -Wall \ + -Wextra \ + -Wimplicit-function-declaration \ + -Wredundant-decls \ + -Wstrict-prototypes \ + -Wundef \ + -Wshadow \ + -Wpointer-arith \ + -Wformat \ + -Wreturn-type \ + -Wsign-compare \ + -Wmultichar \ + -Wformat-nonliteral \ + -Winit-self \ + -Wuninitialized \ + -Wformat-security \ + -Werror \ + -I.. + +all: xpubaddrgen + +OBJS = ../bip32.o ../ecdsa.o ../sha2.o ../bignum.o ../base58.o ../secp256k1.o ../ripemd160.o ../hmac.o ../rand.o + +%.o: %.c %.h options.h + $(CC) $(CFLAGS) -o $@ -c $< + +xpubaddrgen: xpubaddrgen.o $(OBJS) + $(CC) xpubaddrgen.o $(OBJS) -o xpubaddrgen + +clean: + rm -f *.o xpubaddrgen diff --git a/tools/README b/tools/README new file mode 100644 index 000000000..c401ed873 --- /dev/null +++ b/tools/README @@ -0,0 +1,36 @@ +trezor-crypto tools +=================== + +Set of small utilities using the trezor-crypto library. + +xpubaddrgen +----------- + +xpubaddrgen reads job specification from stdin in format: + + + +and prints the results to stdout in format: + +
+ +Example input: + +23 xpub6BcjTvRCYD4VvFQ8whztSXhbNyhS56eTd5P3g9Zvd3zPEeUeL5CUqBYX8NSd1b6Thitr8bZcSnesmXZH7KerMcc4tUkenBShYCtQ1L8ebVe 0 0 5 +42 xpub6AT2YrLinU4Be5UWUxMaUz3zTA99CSGvXt1jt2Lgym8PqXbTzmpQ8MHjoLnx8YJiMMUP5iEfR97YQVmgF6B2tAhbCZrXqn65ur526NkZ6ey 1 1000 1005 + +Example output: + +23 0 14vb5Cws75p2i5rmSiF5CKMyezUX4hxSb9 +23 1 1Lf4ciA36dsi1niF6smVcpCiHcpj2skaPq +23 2 1LraByp7gQAipvHnFS1gTSzixBtYaVyQGp +23 3 1Hy6n56qZj1EefLVfDAeEpmveNteY9jpiG +23 4 183Nn4mrUjPizM3xu8C6SrmViaWrk8YyRS +42 1000 12eAFGAqGUtszc9R7euRqk7DUcQNXvQZSg +42 1001 1BrLbFCD3MNYedJaz92U9iqy9ukHrtQ1A6 +42 1002 1Jhv33bJy229ThM7HKxUa92cMK5gi7DyPC +42 1003 13LxbTjQPByisj4F4sZEivUBdnJwigzg6R +42 1004 1BWBpSWkPwcKxVr2WDyUqQbmvk5SGihcx9 + +It will print " error" when there was an error processing job . +It will print "error" when it encountered a malformed line. diff --git a/tools/xpubaddrgen.c b/tools/xpubaddrgen.c new file mode 100644 index 000000000..9830d6fa4 --- /dev/null +++ b/tools/xpubaddrgen.c @@ -0,0 +1,43 @@ +#include +#include +#include +#include +#include +#include + +void process_job(uint32_t jobid, const char *xpub, uint32_t change, uint32_t from, uint32_t to) +{ + HDNode node, child; + if (change > 1 || to <= from || hdnode_deserialize(xpub, &node) != 0) { + printf("%d error\n", jobid); + return; + } + hdnode_public_ckd(&node, change); + uint32_t i; + char address[36]; + for (i = from; i < to; i++) { + memcpy(&child, &node, sizeof(HDNode)); + hdnode_public_ckd(&child, i); + ecdsa_get_address(child.public_key, 0, address, sizeof(address)); + printf("%d %d %s\n", jobid, i, address); + } +} + +int main(void) +{ + char line[1024], xpub[1024]; + uint32_t jobid, change, from, to; + int r; + for (;;) { + fgets(line, sizeof(line), stdin); + r = sscanf(line, "%u %s %u %u %u\n", &jobid, xpub, &change, &from, &to); + if (r < 1) { + printf("error\n"); + } else if (r != 5) { + printf("%d error\n", jobid); + } else { + process_job(jobid, xpub, change, from, to); + } + } + return 0; +} From 27a496a3709bf3c1c50bfbf73b3e5203b81d4e43 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 24 Dec 2014 01:27:20 +0100 Subject: [PATCH 143/627] README -> README.md --- README => README.md | 0 tools/{README => README.md} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename README => README.md (100%) rename tools/{README => README.md} (100%) diff --git a/README b/README.md similarity index 100% rename from README rename to README.md diff --git a/tools/README b/tools/README.md similarity index 100% rename from tools/README rename to tools/README.md From 9fea8f8ab377dc514e40c6fd1f7c89a74c1d8dc6 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 24 Dec 2014 01:29:26 +0100 Subject: [PATCH 144/627] more fixes to readme --- tools/README.md | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/tools/README.md b/tools/README.md index c401ed873..8f24f19ab 100644 --- a/tools/README.md +++ b/tools/README.md @@ -8,19 +8,26 @@ xpubaddrgen xpubaddrgen reads job specification from stdin in format: +``` +``` and prints the results to stdout in format: +```
+``` Example input: +``` 23 xpub6BcjTvRCYD4VvFQ8whztSXhbNyhS56eTd5P3g9Zvd3zPEeUeL5CUqBYX8NSd1b6Thitr8bZcSnesmXZH7KerMcc4tUkenBShYCtQ1L8ebVe 0 0 5 42 xpub6AT2YrLinU4Be5UWUxMaUz3zTA99CSGvXt1jt2Lgym8PqXbTzmpQ8MHjoLnx8YJiMMUP5iEfR97YQVmgF6B2tAhbCZrXqn65ur526NkZ6ey 1 1000 1005 +``` Example output: +``` 23 0 14vb5Cws75p2i5rmSiF5CKMyezUX4hxSb9 23 1 1Lf4ciA36dsi1niF6smVcpCiHcpj2skaPq 23 2 1LraByp7gQAipvHnFS1gTSzixBtYaVyQGp @@ -31,6 +38,8 @@ Example output: 42 1002 1Jhv33bJy229ThM7HKxUa92cMK5gi7DyPC 42 1003 13LxbTjQPByisj4F4sZEivUBdnJwigzg6R 42 1004 1BWBpSWkPwcKxVr2WDyUqQbmvk5SGihcx9 +``` -It will print " error" when there was an error processing job . -It will print "error" when it encountered a malformed line. +It will print ``` error``` when there was an error processing job jobid. + +It will print ```error``` when it encountered a malformed line. From 2880a2e3db2a75d1c6d6abeb3cd25312ab08ff55 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 11 Jan 2015 02:46:45 +0100 Subject: [PATCH 145/627] add break condition to xpubaddrgen --- tools/xpubaddrgen.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/xpubaddrgen.c b/tools/xpubaddrgen.c index 9830d6fa4..42f87826f 100644 --- a/tools/xpubaddrgen.c +++ b/tools/xpubaddrgen.c @@ -29,7 +29,7 @@ int main(void) uint32_t jobid, change, from, to; int r; for (;;) { - fgets(line, sizeof(line), stdin); + if (!fgets(line, sizeof(line), stdin)) break; r = sscanf(line, "%u %s %u %u %u\n", &jobid, xpub, &change, &from, &to); if (r < 1) { printf("error\n"); From 8c23d62c5ea23c0a5d07e28f199c60c7e4ece4fd Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 11 Jan 2015 02:56:33 +0100 Subject: [PATCH 146/627] don't verify pubkey in xpubaddrgen --- tools/Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/Makefile b/tools/Makefile index 67c652637..8b83089f9 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -23,6 +23,8 @@ CFLAGS += $(OPTFLAGS) \ -Werror \ -I.. +CFLAGS += -DUSE_PUBKEY_VALIDATE=0 + all: xpubaddrgen OBJS = ../bip32.o ../ecdsa.o ../sha2.o ../bignum.o ../base58.o ../secp256k1.o ../ripemd160.o ../hmac.o ../rand.o From 0331a1c4540ab2e18351ddbe51360d4b74f5fb27 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 11 Jan 2015 16:43:07 +0100 Subject: [PATCH 147/627] first try of cythonizing the library --- cython/.gitignore | 2 ++ cython/TrezorCrypto.pyx | 38 ++++++++++++++++++++++++++++++++++++++ cython/c.pxd | 22 ++++++++++++++++++++++ cython/setup.py | 36 ++++++++++++++++++++++++++++++++++++ cython/test.py | 10 ++++++++++ 5 files changed, 108 insertions(+) create mode 100644 cython/.gitignore create mode 100644 cython/TrezorCrypto.pyx create mode 100644 cython/c.pxd create mode 100644 cython/setup.py create mode 100755 cython/test.py diff --git a/cython/.gitignore b/cython/.gitignore new file mode 100644 index 000000000..feaa147ef --- /dev/null +++ b/cython/.gitignore @@ -0,0 +1,2 @@ +build/ +*.c diff --git a/cython/TrezorCrypto.pyx b/cython/TrezorCrypto.pyx new file mode 100644 index 000000000..17e3f8f01 --- /dev/null +++ b/cython/TrezorCrypto.pyx @@ -0,0 +1,38 @@ +cimport c +cimport cython + +cdef class HDNode: + + cdef c.HDNode node + + def __init__(self, initializer): + if isinstance(initializer, HDNode): + self.node = (initializer).node + elif isinstance(initializer, str) : + if c.hdnode_deserialize(initializer, cython.address(self.node)) != 0: + raise Exception('Invalid xpub/xprv provided') + + def xpub(self): + cdef char[120] string + c.hdnode_serialize_public(cython.address(self.node), string, 120) + return str(string) + + def xprv(self): + cdef char[120] string + c.hdnode_serialize_private(cython.address(self.node), string, 120) + return str(string) + + def address(self): + cdef char[40] string + c.ecdsa_get_address(self.node.public_key, 0, string, 40) + return str(string) + + def public_ckd(self, int i): + x = HDNode(self) + c.hdnode_public_ckd(cython.address(x.node), i) + return x + + def private_ckd(self, int i): + x = HDNode(self) + c.hdnode_private_ckd(cython.address(x.node), i) + return x diff --git a/cython/c.pxd b/cython/c.pxd new file mode 100644 index 000000000..2e85d8ef4 --- /dev/null +++ b/cython/c.pxd @@ -0,0 +1,22 @@ +from libc.stdint cimport uint32_t, uint8_t + +cdef extern from "../bip32.h": + + ctypedef struct HDNode: + uint8_t public_key[33] + + int hdnode_from_seed(const uint8_t *seed, int seed_len, HDNode *out) + + int hdnode_private_ckd(HDNode *inout, uint32_t i) + + int hdnode_public_ckd(HDNode *inout, uint32_t i) + + void hdnode_serialize_public(const HDNode *node, char *str, int strsize) + + void hdnode_serialize_private(const HDNode *node, char *str, int strsize) + + int hdnode_deserialize(const char *str, HDNode *node) + +cdef extern from "../ecdsa.h": + + void ecdsa_get_address(const uint8_t *pub_key, uint8_t version, char *addr, int addrsize) diff --git a/cython/setup.py b/cython/setup.py new file mode 100644 index 000000000..dec830a7f --- /dev/null +++ b/cython/setup.py @@ -0,0 +1,36 @@ +from distutils.core import setup +from distutils.extension import Extension +from Cython.Build import cythonize +from Cython.Distutils import build_ext + +crypto_srcs = [ + 'base58.c', + 'bignum.c', + 'bip32.c', + 'ecdsa.c', + 'hmac.c', + 'rand.c', + 'ripemd160.c', + 'secp256k1.c', + 'sha2.c', +] + +crypto_srcs = [ '../%s' % x for x in crypto_srcs ] + +extensions = [ + Extension('TrezorCrypto', + sources = ['TrezorCrypto.pyx', 'c.pxd'] + crypto_srcs, + extra_compile_args = ['-DUSE_PUBKEY_VALIDATE=0'], + ) +] + +setup( + name = 'TrezorCrypto', + version = '0', + description = 'Cython wrapper around trezor-crypto library', + author = 'Pavol Rusnak', + author_email = 'stick@satoshilabs.com', + url = 'https://github.com/trezor/trezor-crypto', + cmdclass = {'build_ext': build_ext}, + ext_modules = cythonize(extensions), +) diff --git a/cython/test.py b/cython/test.py new file mode 100755 index 000000000..088616d22 --- /dev/null +++ b/cython/test.py @@ -0,0 +1,10 @@ +#!/usr/bin/python +from TrezorCrypto import HDNode + +x = HDNode('xpub6BcjTvRCYD4VvFQ8whztSXhbNyhS56eTd5P3g9Zvd3zPEeUeL5CUqBYX8NSd1b6Thitr8bZcSnesmXZH7KerMcc4tUkenBShYCtQ1L8ebVe') + +y = x.public_ckd(0) + +for i in range(1000): + z = y.public_ckd(i) + print i, z.address() From 5cd45313122b5d7eb74b9de379367255cc133f2a Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 11 Jan 2015 20:05:40 +0100 Subject: [PATCH 148/627] make constructor of cython HDNode struct more explicit --- cython/TrezorCrypto.pyx | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/cython/TrezorCrypto.pyx b/cython/TrezorCrypto.pyx index 17e3f8f01..64903ff38 100644 --- a/cython/TrezorCrypto.pyx +++ b/cython/TrezorCrypto.pyx @@ -5,12 +5,14 @@ cdef class HDNode: cdef c.HDNode node - def __init__(self, initializer): - if isinstance(initializer, HDNode): - self.node = (initializer).node - elif isinstance(initializer, str) : - if c.hdnode_deserialize(initializer, cython.address(self.node)) != 0: + def __init__(self, str serialized = None, HDNode copyfrom = None): + if copyfrom is not None: + self.node = copyfrom.node + elif serialized is not None: + if c.hdnode_deserialize(serialized, cython.address(self.node)) != 0: raise Exception('Invalid xpub/xprv provided') + else: + raise Exception('Need to provide serialized or node parameter') def xpub(self): cdef char[120] string @@ -28,11 +30,11 @@ cdef class HDNode: return str(string) def public_ckd(self, int i): - x = HDNode(self) + x = HDNode(copyfrom=self) c.hdnode_public_ckd(cython.address(x.node), i) return x def private_ckd(self, int i): - x = HDNode(self) + x = HDNode(copyfrom=self) c.hdnode_private_ckd(cython.address(x.node), i) return x From fb747384a026c20b54a1acf15e0916fb998b2779 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 12 Jan 2015 19:11:43 +0100 Subject: [PATCH 149/627] prepare cython-TrezorCrypto for pip release --- .gitignore | 4 +++ MANIFEST.in | 2 ++ cython/TrezorCrypto.pyx => TrezorCrypto.pyx | 0 cython/c.pxd => c.pxd | 4 +-- cython/.gitignore | 2 -- cython/setup.py => setup.py | 27 ++++++++++----------- cython/test.py => test.py | 0 7 files changed, 21 insertions(+), 18 deletions(-) create mode 100644 MANIFEST.in rename cython/TrezorCrypto.pyx => TrezorCrypto.pyx (100%) rename cython/c.pxd => c.pxd (90%) delete mode 100644 cython/.gitignore rename cython/setup.py => setup.py (67%) mode change 100644 => 100755 rename cython/test.py => test.py (100%) diff --git a/.gitignore b/.gitignore index 34397a4c0..c7749f130 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,7 @@ test-openssl tests build-*/ +build/ +dist/ +MANIFEST +TrezorCrypto.c diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 000000000..637fe68f5 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,2 @@ +include *.h +include *.pyx diff --git a/cython/TrezorCrypto.pyx b/TrezorCrypto.pyx similarity index 100% rename from cython/TrezorCrypto.pyx rename to TrezorCrypto.pyx diff --git a/cython/c.pxd b/c.pxd similarity index 90% rename from cython/c.pxd rename to c.pxd index 2e85d8ef4..6a445d660 100644 --- a/cython/c.pxd +++ b/c.pxd @@ -1,6 +1,6 @@ from libc.stdint cimport uint32_t, uint8_t -cdef extern from "../bip32.h": +cdef extern from "bip32.h": ctypedef struct HDNode: uint8_t public_key[33] @@ -17,6 +17,6 @@ cdef extern from "../bip32.h": int hdnode_deserialize(const char *str, HDNode *node) -cdef extern from "../ecdsa.h": +cdef extern from "ecdsa.h": void ecdsa_get_address(const uint8_t *pub_key, uint8_t version, char *addr, int addrsize) diff --git a/cython/.gitignore b/cython/.gitignore deleted file mode 100644 index feaa147ef..000000000 --- a/cython/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -build/ -*.c diff --git a/cython/setup.py b/setup.py old mode 100644 new mode 100755 similarity index 67% rename from cython/setup.py rename to setup.py index dec830a7f..592976a21 --- a/cython/setup.py +++ b/setup.py @@ -1,32 +1,31 @@ +#!/usr/bin/python from distutils.core import setup from distutils.extension import Extension from Cython.Build import cythonize from Cython.Distutils import build_ext -crypto_srcs = [ - 'base58.c', - 'bignum.c', - 'bip32.c', - 'ecdsa.c', - 'hmac.c', - 'rand.c', - 'ripemd160.c', - 'secp256k1.c', - 'sha2.c', +srcs = [ + 'base58', + 'bignum', + 'bip32', + 'ecdsa', + 'hmac', + 'rand', + 'ripemd160', + 'secp256k1', + 'sha2', ] -crypto_srcs = [ '../%s' % x for x in crypto_srcs ] - extensions = [ Extension('TrezorCrypto', - sources = ['TrezorCrypto.pyx', 'c.pxd'] + crypto_srcs, + sources = ['TrezorCrypto.pyx', 'c.pxd'] + [ x + '.c' for x in srcs ], extra_compile_args = ['-DUSE_PUBKEY_VALIDATE=0'], ) ] setup( name = 'TrezorCrypto', - version = '0', + version = '0.0.0', description = 'Cython wrapper around trezor-crypto library', author = 'Pavol Rusnak', author_email = 'stick@satoshilabs.com', diff --git a/cython/test.py b/test.py similarity index 100% rename from cython/test.py rename to test.py From 661751ab4b8d0ec2b65154bf2547b24295e48cfa Mon Sep 17 00:00:00 2001 From: Dustin Laurence Date: Fri, 19 Dec 2014 19:24:59 -0800 Subject: [PATCH 150/627] Add finalize_rand() --- rand.c | 6 ++++++ rand.h | 1 + 2 files changed, 7 insertions(+) diff --git a/rand.c b/rand.c index cf5dec110..7c80c13af 100644 --- a/rand.c +++ b/rand.c @@ -33,6 +33,12 @@ void init_rand(void) f = fopen("/dev/urandom", "r"); } +void finalize_rand(void) +{ + fclose(f); + f = NULL; +} + uint32_t random32(void) { uint32_t r; diff --git a/rand.h b/rand.h index fb80ea43b..cd281aa53 100644 --- a/rand.h +++ b/rand.h @@ -27,6 +27,7 @@ #include void init_rand(void); +void finalize_rand(void); uint32_t random32(void); void random_buffer(uint8_t *buf, size_t len); From ce67a85d392cafd8b5078a1daeb855001fc637c5 Mon Sep 17 00:00:00 2001 From: Dustin Laurence Date: Sat, 20 Dec 2014 10:57:38 -0800 Subject: [PATCH 151/627] Add finalize_rand() to prove we have no leaks --- rand.c | 6 ++++-- rand.h | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/rand.c b/rand.c index 7c80c13af..7251826c8 100644 --- a/rand.c +++ b/rand.c @@ -33,10 +33,12 @@ void init_rand(void) f = fopen("/dev/urandom", "r"); } -void finalize_rand(void) +int finalize_rand(void) { - fclose(f); + int err = fclose(f); f = NULL; + + return err; } uint32_t random32(void) diff --git a/rand.h b/rand.h index cd281aa53..e626d7816 100644 --- a/rand.h +++ b/rand.h @@ -27,7 +27,7 @@ #include void init_rand(void); -void finalize_rand(void); +int finalize_rand(void); uint32_t random32(void); void random_buffer(uint8_t *buf, size_t len); From 8ce1f3423300473dd034efd63dcdb13b0d7604bb Mon Sep 17 00:00:00 2001 From: Dustin Laurence Date: Fri, 23 Jan 2015 11:27:33 -0800 Subject: [PATCH 152/627] Add prototypes for private functions --- base58.h | 5 +++++ bip32.h | 3 +++ ecdsa.h | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/base58.h b/base58.h index 1f3eadfbc..4f5aedfbf 100644 --- a/base58.h +++ b/base58.h @@ -29,4 +29,9 @@ int base58_encode_check(const uint8_t *data, int len, char *str, int strsize); int base58_decode_check(const char *str, uint8_t *data, int datalen); +// Private +bool b58tobin(void *bin, size_t *binszp, const char *b58); +int b58check(const void *bin, size_t binsz, const char *base58str); +bool b58enc(char *b58, size_t *b58sz, const void *data, size_t binsz); + #endif diff --git a/bip32.h b/bip32.h index 131d005ae..ab9791d04 100644 --- a/bip32.h +++ b/bip32.h @@ -55,4 +55,7 @@ void hdnode_serialize_private(const HDNode *node, char *str, int strsize); int hdnode_deserialize(const char *str, HDNode *node); +// Private +void hdnode_serialize(const HDNode *node, uint32_t version, char use_public, char *str, int strsize); + #endif diff --git a/ecdsa.h b/ecdsa.h index 9f57268f9..be8cfcd46 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -56,4 +56,8 @@ int ecdsa_verify_double(const uint8_t *pub_key, const uint8_t *sig, const uint8_ int ecdsa_verify_digest(const uint8_t *pub_key, const uint8_t *sig, const uint8_t *digest); int ecdsa_sig_to_der(const uint8_t *sig, uint8_t *der); +// Private +int generate_k_rfc6979(bignum256 *secret, const uint8_t *priv_key, const uint8_t *hash); +int generate_k_random(bignum256 *k); + #endif From a16992a89370eb19d00dc64f42deb1fd9fc37228 Mon Sep 17 00:00:00 2001 From: Dustin Laurence Date: Fri, 23 Jan 2015 11:30:38 -0800 Subject: [PATCH 153/627] Add stdbool.h --- base58.h | 1 + 1 file changed, 1 insertion(+) diff --git a/base58.h b/base58.h index 4f5aedfbf..a53e4385b 100644 --- a/base58.h +++ b/base58.h @@ -25,6 +25,7 @@ #define __BASE58_H__ #include +#include int base58_encode_check(const uint8_t *data, int len, char *str, int strsize); int base58_decode_check(const char *str, uint8_t *data, int datalen); From 1c672dca2b9b40493f7b7a7f14d2a33d26df24b2 Mon Sep 17 00:00:00 2001 From: Dustin Laurence Date: Sun, 25 Jan 2015 08:49:52 -0800 Subject: [PATCH 154/627] Remove now-redundant embedded header --- tests.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests.c b/tests.c index 3f960d32e..580bf02ce 100644 --- a/tests.c +++ b/tests.c @@ -427,8 +427,6 @@ START_TEST(test_bip32_compare) } END_TEST -int generate_k_rfc6979(bignum256 *secret, const uint8_t *priv_key, const uint8_t *hash); - #define test_deterministic(KEY, MSG, K) do { \ sha256_Raw((uint8_t *)MSG, strlen(MSG), buf); \ res = generate_k_rfc6979(&k, fromhex(KEY), buf); \ From f4e6010e18180645dfe1940e0d8cf9df12b2e2ee Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 26 Jan 2015 19:09:00 +0100 Subject: [PATCH 155/627] implement BIP32 cache --- bip32.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ bip32.h | 7 ++++++ options.h | 7 ++++++ tests.c | 48 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 130 insertions(+) diff --git a/bip32.c b/bip32.c index f4a021d57..fb603dfa5 100644 --- a/bip32.c +++ b/bip32.c @@ -22,6 +22,7 @@ */ #include +#include #include "bignum.h" #include "hmac.h" @@ -176,6 +177,73 @@ int hdnode_public_ckd(HDNode *inout, uint32_t i) return 1; } +#if USE_BIP32_CACHE + +static bool private_ckd_cache_root_set = false; +static HDNode private_ckd_cache_root; +static int private_ckd_cache_index = 0; + +static struct { + bool set; + size_t depth; + uint32_t i[BIP32_CACHE_MAXDEPTH]; + HDNode node; +} private_ckd_cache[BIP32_CACHE_SIZE]; + +int hdnode_private_ckd_cached(HDNode *inout, const uint32_t *i, size_t i_count) +{ + if (i_count == 0) { + return 1; + } + if (i_count == 1) { + if (hdnode_private_ckd(inout, i[0]) == 0) return 0; + return 1; + } + + bool found = false; + // if root is not set or not the same + if (!private_ckd_cache_root_set || memcmp(&private_ckd_cache_root, inout, sizeof(HDNode)) != 0) { + // clear the cache + private_ckd_cache_index = 0; + memset(private_ckd_cache, 0, sizeof(private_ckd_cache)); + // setup new root + memcpy(&private_ckd_cache_root, inout, sizeof(HDNode)); + private_ckd_cache_root_set = true; + } else { + // try to find parent + int j; + for (j = 0; j < BIP32_CACHE_SIZE; j++) { + if (private_ckd_cache[j].set && + private_ckd_cache[j].depth == i_count - 1 && + memcmp(private_ckd_cache[j].i, i, (i_count - 1) * sizeof(uint32_t)) == 0) { + memcpy(inout, &(private_ckd_cache[j].node), sizeof(HDNode)); + found = true; + break; + } + } + } + + // else derive parent + if (!found) { + size_t k; + for (k = 0; k < i_count - 1; k++) { + if (hdnode_private_ckd(inout, i[k]) == 0) return 0; + } + // and save it + private_ckd_cache[private_ckd_cache_index].set = true; + private_ckd_cache[private_ckd_cache_index].depth = i_count - 1; + memcpy(private_ckd_cache[private_ckd_cache_index].i, i, (i_count - 1) * sizeof(uint32_t)); + memcpy(&(private_ckd_cache[private_ckd_cache_index].node), inout, sizeof(HDNode)); + private_ckd_cache_index = (private_ckd_cache_index + 1) % BIP32_CACHE_SIZE; + } + + if (hdnode_private_ckd(inout, i[i_count - 1]) == 0) return 0; + + return 1; +} + +#endif + void hdnode_fill_public_key(HDNode *node) { ecdsa_get_public_key33(node->private_key, node->public_key); diff --git a/bip32.h b/bip32.h index ab9791d04..fbf7b1a61 100644 --- a/bip32.h +++ b/bip32.h @@ -25,6 +25,7 @@ #define __BIP32_H__ #include +#include "options.h" typedef struct { uint32_t depth; @@ -47,6 +48,12 @@ int hdnode_private_ckd(HDNode *inout, uint32_t i); int hdnode_public_ckd(HDNode *inout, uint32_t i); +#if USE_BIP32_CACHE + +int hdnode_private_ckd_cached(HDNode *inout, const uint32_t *i, size_t i_count); + +#endif + void hdnode_fill_public_key(HDNode *node); void hdnode_serialize_public(const HDNode *node, char *str, int strsize); diff --git a/options.h b/options.h index 53cdb2df5..0e68178c2 100644 --- a/options.h +++ b/options.h @@ -53,4 +53,11 @@ #define USE_PUBKEY_VALIDATE 1 #endif +// implement BIP32 caching +#ifndef USE_BIP32_CACHE +#define USE_BIP32_CACHE 1 +#define BIP32_CACHE_SIZE 10 +#define BIP32_CACHE_MAXDEPTH 8 +#endif + #endif diff --git a/tests.c b/tests.c index 580bf02ce..fdfea7a5b 100644 --- a/tests.c +++ b/tests.c @@ -427,6 +427,52 @@ START_TEST(test_bip32_compare) } END_TEST +START_TEST(test_bip32_cache) +{ + HDNode node1, node2; + int r; + + // test 1 .. 8 + hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, &node1); + hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, &node2); + + uint32_t i; + for (i = 1; i < 8; i++) { + r = hdnode_private_ckd(&node1, i); ck_assert_int_eq(r, 1); + } + r = hdnode_private_ckd(&node1, 8); ck_assert_int_eq(r, 1); + + uint32_t ii[] = {1, 2, 3, 4, 5, 6, 7, 8}; + r = hdnode_private_ckd_cached(&node2, ii, 8); ck_assert_int_eq(r, 1); + ck_assert_mem_eq(&node1, &node2, sizeof(HDNode)); + + // test 1 .. 7, 20 + hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, &node1); + hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, &node2); + + for (i = 1; i < 8; i++) { + r = hdnode_private_ckd(&node1, i); ck_assert_int_eq(r, 1); + } + r = hdnode_private_ckd(&node1, 20); ck_assert_int_eq(r, 1); + + ii[7] = 20; + r = hdnode_private_ckd_cached(&node2, ii, 8); ck_assert_int_eq(r, 1); + ck_assert_mem_eq(&node1, &node2, sizeof(HDNode)); + + // test different root node + hdnode_from_seed(fromhex("000000002ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, &node1); + hdnode_from_seed(fromhex("000000002ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, &node2); + + for (i = 1; i < 8; i++) { + r = hdnode_private_ckd(&node1, i); ck_assert_int_eq(r, 1); + } + r = hdnode_private_ckd(&node1, 20); ck_assert_int_eq(r, 1); + + r = hdnode_private_ckd_cached(&node2, ii, 8); ck_assert_int_eq(r, 1); + ck_assert_mem_eq(&node1, &node2, sizeof(HDNode)); +} +END_TEST + #define test_deterministic(KEY, MSG, K) do { \ sha256_Raw((uint8_t *)MSG, strlen(MSG), buf); \ res = generate_k_rfc6979(&k, fromhex(KEY), buf); \ @@ -1139,6 +1185,7 @@ Suite *test_suite(void) Suite *s = suite_create("trezor-crypto"); TCase *tc; + tc = tcase_create("base58"); tcase_add_test(tc, test_base58); suite_add_tcase(s, tc); @@ -1147,6 +1194,7 @@ Suite *test_suite(void) tcase_add_test(tc, test_bip32_vector_1); tcase_add_test(tc, test_bip32_vector_2); tcase_add_test(tc, test_bip32_compare); + tcase_add_test(tc, test_bip32_cache); suite_add_tcase(s, tc); tc = tcase_create("rfc6979"); From aa1833ba3fd9301dd275c1c34c1ce5dd9ae703be Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 26 Jan 2015 19:12:22 +0100 Subject: [PATCH 156/627] add stdlib to header --- bip32.h | 1 + 1 file changed, 1 insertion(+) diff --git a/bip32.h b/bip32.h index fbf7b1a61..c05f6ccc8 100644 --- a/bip32.h +++ b/bip32.h @@ -25,6 +25,7 @@ #define __BIP32_H__ #include +#include #include "options.h" typedef struct { From cb6f976b0dd871866a0a28ee83a146a46cf0bad2 Mon Sep 17 00:00:00 2001 From: Adam Mackler Date: Tue, 27 Jan 2015 19:22:42 -0500 Subject: [PATCH 157/627] Remove unused static variable sha384_initial_hash_value. --- sha2.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/sha2.c b/sha2.c index 3e21cdaa9..74c67daf8 100644 --- a/sha2.c +++ b/sha2.c @@ -256,18 +256,6 @@ static const sha2_word64 K512[80] = { 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL }; -/* Initial hash value H for SHA-384 */ -static const sha2_word64 sha384_initial_hash_value[8] = { - 0xcbbb9d5dc1059ed8ULL, - 0x629a292a367cd507ULL, - 0x9159015a3070dd17ULL, - 0x152fecd8f70e5939ULL, - 0x67332667ffc00b31ULL, - 0x8eb44a8768581511ULL, - 0xdb0c2e0d64f98fa7ULL, - 0x47b5481dbefa4fa4ULL -}; - /* Initial hash value H for SHA-512 */ static const sha2_word64 sha512_initial_hash_value[8] = { 0x6a09e667f3bcc908ULL, From 82ea549661f657e5925808355322ad6606808428 Mon Sep 17 00:00:00 2001 From: Adam Mackler Date: Tue, 27 Jan 2015 21:44:48 -0500 Subject: [PATCH 158/627] Add `stdlib.h` to header. Needed for `size_t`. --- rand.h | 1 + 1 file changed, 1 insertion(+) diff --git a/rand.h b/rand.h index e626d7816..2c7893963 100644 --- a/rand.h +++ b/rand.h @@ -24,6 +24,7 @@ #ifndef __RAND_H__ #define __RAND_H__ +#include #include void init_rand(void); From ed9d8c1ebb2845e8b8913727dba7b0bc746f0168 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Fri, 30 Jan 2015 22:27:18 +0100 Subject: [PATCH 159/627] Fix RFC6979 generation of k. The standard says: step h: Set T to the empty sequence. while tlen < qlen V = HMAC_K(V) T = T || V k = bits2int(T) in this case (HMAC-SHA256, qlen=256bit) this simplifies to V = HMAC_K(V) T = V k = bits2int(T) and T can be omitted. The old code (wrong) did: T = HMAC_K(V) k = bits2int(T) Note that V will only be used again if the first k is out of range. Thus, the old code produced the right result with a very high probability. --- ecdsa.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ecdsa.c b/ecdsa.c index a4a6c1acc..e17a4a7e9 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -256,7 +256,7 @@ int generate_k_random(bignum256 *k) { int generate_k_rfc6979(bignum256 *secret, const uint8_t *priv_key, const uint8_t *hash) { int i; - uint8_t v[32], k[32], bx[2*32], buf[32 + 1 + sizeof(bx)], t[32]; + uint8_t v[32], k[32], bx[2*32], buf[32 + 1 + sizeof(bx)]; bignum256 z1; memcpy(bx, priv_key, 32); @@ -280,8 +280,8 @@ int generate_k_rfc6979(bignum256 *secret, const uint8_t *priv_key, const uint8_t hmac_sha256(k, sizeof(k), v, sizeof(k), v); for (i = 0; i < 10000; i++) { - hmac_sha256(k, sizeof(k), v, sizeof(v), t); - bn_read_be(t, secret); + hmac_sha256(k, sizeof(k), v, sizeof(v), v); + bn_read_be(v, secret); if ( !bn_is_zero(secret) && bn_is_less(secret, &order256k1) ) { return 0; // good number -> no error } From 7e7b40b434aef2a6eeb7337044699572211ed79a Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Sat, 14 Feb 2015 12:00:44 +0100 Subject: [PATCH 160/627] Make word list const This makes the pointers to the words constant. It moves 8kb from ram to flash. It changes the return type of mnemonic_wordlist() to reflect this change. Everyone calling it should also change the type to `const char * const *`. --- bip39.c | 2 +- bip39.h | 2 +- bip39_english.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bip39.c b/bip39.c index 019259386..7c7858580 100644 --- a/bip39.c +++ b/bip39.c @@ -155,7 +155,7 @@ void mnemonic_to_seed(const char *mnemonic, const char *passphrase, uint8_t seed pbkdf2_hmac_sha512((const uint8_t *)mnemonic, strlen(mnemonic), salt, saltlen, BIP39_PBKDF2_ROUNDS, seed, 512 / 8, progress_callback); } -const char **mnemonic_wordlist(void) +const char * const *mnemonic_wordlist(void) { return wordlist; } diff --git a/bip39.h b/bip39.h index cad7a66d3..fe4d99e8a 100644 --- a/bip39.h +++ b/bip39.h @@ -36,6 +36,6 @@ int mnemonic_check(const char *mnemonic); void mnemonic_to_seed(const char *mnemonic, const char *passphrase, uint8_t seed[512 / 8], void (*progress_callback)(uint32_t current, uint32_t total)); -const char **mnemonic_wordlist(void); +const char * const *mnemonic_wordlist(void); #endif diff --git a/bip39_english.h b/bip39_english.h index 4ecddba4b..233acc2f8 100644 --- a/bip39_english.h +++ b/bip39_english.h @@ -21,7 +21,7 @@ * OTHER DEALINGS IN THE SOFTWARE. */ -const char *wordlist[] = { +const char * const wordlist[] = { "abandon", "ability", "able", From 92ab7504b29ec89d13ae996c0855d8cbacd61e70 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 4 Mar 2015 15:43:14 +0100 Subject: [PATCH 161/627] add one more bip32_cache test --- bip32.c | 1 + tests.c | 66 ++++++++++++++++++++++++++++++++++++++++----------------- 2 files changed, 47 insertions(+), 20 deletions(-) diff --git a/bip32.c b/bip32.c index fb603dfa5..43218aed9 100644 --- a/bip32.c +++ b/bip32.c @@ -230,6 +230,7 @@ int hdnode_private_ckd_cached(HDNode *inout, const uint32_t *i, size_t i_count) if (hdnode_private_ckd(inout, i[k]) == 0) return 0; } // and save it + memset(&(private_ckd_cache[private_ckd_cache_index]), 0, sizeof(private_ckd_cache[private_ckd_cache_index])); private_ckd_cache[private_ckd_cache_index].set = true; private_ckd_cache[private_ckd_cache_index].depth = i_count - 1; memcpy(private_ckd_cache[private_ckd_cache_index].i, i, (i_count - 1) * sizeof(uint32_t)); diff --git a/tests.c b/tests.c index fdfea7a5b..57431da19 100644 --- a/tests.c +++ b/tests.c @@ -427,35 +427,31 @@ START_TEST(test_bip32_compare) } END_TEST -START_TEST(test_bip32_cache) +START_TEST(test_bip32_cache_1) { HDNode node1, node2; - int r; + int i, r; // test 1 .. 8 hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, &node1); hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, &node2); - uint32_t i; - for (i = 1; i < 8; i++) { - r = hdnode_private_ckd(&node1, i); ck_assert_int_eq(r, 1); - } - r = hdnode_private_ckd(&node1, 8); ck_assert_int_eq(r, 1); + uint32_t ii[] = {0x80000001, 0x80000002, 0x80000003, 0x80000004, 0x80000005, 0x80000006, 0x80000007, 0x80000008}; - uint32_t ii[] = {1, 2, 3, 4, 5, 6, 7, 8}; + for (i = 0; i < 8; i++) { + r = hdnode_private_ckd(&node1, ii[i]); ck_assert_int_eq(r, 1); + } r = hdnode_private_ckd_cached(&node2, ii, 8); ck_assert_int_eq(r, 1); ck_assert_mem_eq(&node1, &node2, sizeof(HDNode)); - // test 1 .. 7, 20 hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, &node1); hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, &node2); - for (i = 1; i < 8; i++) { - r = hdnode_private_ckd(&node1, i); ck_assert_int_eq(r, 1); - } - r = hdnode_private_ckd(&node1, 20); ck_assert_int_eq(r, 1); - + // test 1 .. 7, 20 ii[7] = 20; + for (i = 0; i < 8; i++) { + r = hdnode_private_ckd(&node1, ii[i]); ck_assert_int_eq(r, 1); + } r = hdnode_private_ckd_cached(&node2, ii, 8); ck_assert_int_eq(r, 1); ck_assert_mem_eq(&node1, &node2, sizeof(HDNode)); @@ -463,16 +459,46 @@ START_TEST(test_bip32_cache) hdnode_from_seed(fromhex("000000002ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, &node1); hdnode_from_seed(fromhex("000000002ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, &node2); - for (i = 1; i < 8; i++) { - r = hdnode_private_ckd(&node1, i); ck_assert_int_eq(r, 1); + for (i = 0; i < 8; i++) { + r = hdnode_private_ckd(&node1, ii[i]); ck_assert_int_eq(r, 1); } - r = hdnode_private_ckd(&node1, 20); ck_assert_int_eq(r, 1); - r = hdnode_private_ckd_cached(&node2, ii, 8); ck_assert_int_eq(r, 1); ck_assert_mem_eq(&node1, &node2, sizeof(HDNode)); } END_TEST +START_TEST(test_bip32_cache_2) +{ + HDNode nodea[9], nodeb[9]; + int i, j, r; + + for (j = 0; j < 9; j++) { + hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, &(nodea[j])); + hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, &(nodeb[j])); + } + + uint32_t ii[] = {0x80000001, 0x80000002, 0x80000003, 0x80000004, 0x80000005, 0x80000006, 0x80000007, 0x80000008}; + for (j = 0; j < 9; j++) { + // non cached + for (i = 1; i <= j; i++) { + r = hdnode_private_ckd(&(nodea[j]), ii[i - 1]); ck_assert_int_eq(r, 1); + } + // cached + r = hdnode_private_ckd_cached(&(nodeb[j]), ii, j); ck_assert_int_eq(r, 1); + } + + ck_assert_mem_eq(&(nodea[0]), &(nodeb[0]), sizeof(HDNode)); + ck_assert_mem_eq(&(nodea[1]), &(nodeb[1]), sizeof(HDNode)); + ck_assert_mem_eq(&(nodea[2]), &(nodeb[2]), sizeof(HDNode)); + ck_assert_mem_eq(&(nodea[3]), &(nodeb[3]), sizeof(HDNode)); + ck_assert_mem_eq(&(nodea[4]), &(nodeb[4]), sizeof(HDNode)); + ck_assert_mem_eq(&(nodea[5]), &(nodeb[5]), sizeof(HDNode)); + ck_assert_mem_eq(&(nodea[6]), &(nodeb[6]), sizeof(HDNode)); + ck_assert_mem_eq(&(nodea[7]), &(nodeb[7]), sizeof(HDNode)); + ck_assert_mem_eq(&(nodea[8]), &(nodeb[8]), sizeof(HDNode)); +} +END_TEST + #define test_deterministic(KEY, MSG, K) do { \ sha256_Raw((uint8_t *)MSG, strlen(MSG), buf); \ res = generate_k_rfc6979(&k, fromhex(KEY), buf); \ @@ -1185,7 +1211,6 @@ Suite *test_suite(void) Suite *s = suite_create("trezor-crypto"); TCase *tc; - tc = tcase_create("base58"); tcase_add_test(tc, test_base58); suite_add_tcase(s, tc); @@ -1194,7 +1219,8 @@ Suite *test_suite(void) tcase_add_test(tc, test_bip32_vector_1); tcase_add_test(tc, test_bip32_vector_2); tcase_add_test(tc, test_bip32_compare); - tcase_add_test(tc, test_bip32_cache); + tcase_add_test(tc, test_bip32_cache_1); + tcase_add_test(tc, test_bip32_cache_2); suite_add_tcase(s, tc); tc = tcase_create("rfc6979"); From e2dd0b8e8d5ec713ccece967a0d669c7fe453409 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Sun, 8 Mar 2015 20:24:59 +0100 Subject: [PATCH 162/627] Always check for validity in ecdsa_read_pubkey. An invalid point may crash the implementation or, worse, reveal information about the private key if used in a ECDH context (e.g. cryptoMessageEn/Decrypt). Therefore, check all user supplied points even if USE_PUBKEY_VALIDATE is not set. To improve speed, we don't check if the point lies in the main group, since the secp256k1 curve does not have any other subgroup. --- ecdsa.c | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/ecdsa.c b/ecdsa.c index e17a4a7e9..831098cb2 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -460,20 +460,12 @@ int ecdsa_read_pubkey(const uint8_t *pub_key, curve_point *pub) if (pub_key[0] == 0x04) { bn_read_be(pub_key + 1, &(pub->x)); bn_read_be(pub_key + 33, &(pub->y)); -#if USE_PUBKEY_VALIDATE return ecdsa_validate_pubkey(pub); -#else - return 1; -#endif } if (pub_key[0] == 0x02 || pub_key[0] == 0x03) { // compute missing y coords bn_read_be(pub_key + 1, &(pub->x)); uncompress_coords(pub_key[0], &(pub->x), &(pub->y)); -#if USE_PUBKEY_VALIDATE return ecdsa_validate_pubkey(pub); -#else - return 1; -#endif } // error return 0; @@ -483,12 +475,10 @@ int ecdsa_read_pubkey(const uint8_t *pub_key, curve_point *pub) // - pub is not the point at infinity. // - pub->x and pub->y are in range [0,p-1]. // - pub is on the curve. -// - n*pub is the point at infinity. int ecdsa_validate_pubkey(const curve_point *pub) { bignum256 y_2, x_3_b; - curve_point temp; if (point_is_infinity(pub)) { return 0; @@ -514,12 +504,6 @@ int ecdsa_validate_pubkey(const curve_point *pub) return 0; } - point_multiply(&order256k1, pub, &temp); - - if (!point_is_infinity(&temp)) { - return 0; - } - return 1; } From 7e98c02afd2b2c788d68cbc51e903d33a8c98894 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Mon, 9 Mar 2015 10:54:00 +0100 Subject: [PATCH 163/627] Added comments to the tricky algorithms. Added invariants for bn_multiply and bn_inverse. Explain that bn_multiply and bn_fast_mod doesn't work for an arbitrary modulus. The modulus must be close to 2^256. --- bignum.c | 141 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 137 insertions(+), 4 deletions(-) diff --git a/bignum.c b/bignum.c index d94dc6fcc..60846195a 100644 --- a/bignum.c +++ b/bignum.c @@ -177,8 +177,11 @@ void bn_muli(bignum256 *a, uint32_t b) a->val[8] += t; } -// x = k * x -// both inputs and result may be bigger than prime but not bigger than 2 * prime +// Compute x := k * x (mod prime) +// both inputs must be smaller than 2 * prime. +// result is reduced to 0 <= x < 2 * prime +// This only works for primes between 2^256-2^196 and 2^256. +// this particular implementation accepts inputs up to 2^263 or 128*prime. void bn_multiply(const bignum256 *k, bignum256 *x, const bignum256 *prime) { int i, j; @@ -204,11 +207,21 @@ void bn_multiply(const bignum256 *k, bignum256 *x, const bignum256 *prime) temp >>= 30; } res[17] = temp; + // res = k * x is a normalized number (every limb < 2^30) + // 0 <= res < 2^526. // compute modulo p division is only estimated so this may give result greater than prime but not bigger than 2 * prime for (i = 16; i >= 8; i--) { + // let k = i-8. + // invariants: + // res[0..(i+1)] = k * x (mod prime) + // 0 <= res < 2^(30k + 256) * (2^30 + 1) // estimate (res / prime) coef = (res[i] >> 16) + (res[i + 1] << 14); - // substract (coef * prime) from res + + // coef = res / 2^(30k + 256) rounded down + // 0 <= coef <= 2^30 + // subtract (coef * 2^(30k) * prime) from res + // note that we unrolled the first iteration temp = 0x1000000000000000ull + res[i - 8] - prime->val[0] * (uint64_t)coef; res[i - 8] = temp & 0x3FFFFFFF; for (j = 1; j < 9; j++) { @@ -216,6 +229,16 @@ void bn_multiply(const bignum256 *k, bignum256 *x, const bignum256 *prime) temp += 0xFFFFFFFC0000000ull + res[i - 8 + j] - prime->val[j] * (uint64_t)coef; res[i - 8 + j] = temp & 0x3FFFFFFF; } + // we don't clear res[i+1] but we never read it again. + + // we rely on the fact that prime > 2^256 - 2^196 + // res = oldres - coef*2^(30k) * prime; + // and + // coef * 2^(30k + 256) <= oldres < (coef+1) * 2^(30k + 256) + // Hence, 0 <= res < 2^30k (2^256 + coef * (2^256 - prime)) + // Since coef * (2^256 - prime) < 2^226, we get + // 0 <= res < 2^(30k + 226) (2^30 + 1) + // Thus the invariant holds again. } // store the result for (i = 0; i < 9; i++) { @@ -223,6 +246,8 @@ void bn_multiply(const bignum256 *k, bignum256 *x, const bignum256 *prime) } } +// input x can be any normalized number that fits (0 <= x < 2^270). +// prime must be between (2^256 - 2^196) and 2^256 // result is smaller than 2*prime void bn_fast_mod(bignum256 *x, const bignum256 *prime) { @@ -233,6 +258,7 @@ void bn_fast_mod(bignum256 *x, const bignum256 *prime) coef = x->val[8] >> 16; if (!coef) return; // substract (coef * prime) from x + // note that we unrolled the first iteration temp = 0x1000000000000000ull + x->val[0] - prime->val[0] * (uint64_t)coef; x->val[0] = temp & 0x3FFFFFFF; for (j = 1; j < 9; j++) { @@ -246,16 +272,26 @@ void bn_fast_mod(bignum256 *x, const bignum256 *prime) // http://en.wikipedia.org/wiki/Quadratic_residue#Prime_or_prime_power_modulus void bn_sqrt(bignum256 *x, const bignum256 *prime) { + // this method compute x^1/2 = x^(prime+1)/4 uint32_t i, j, limb; bignum256 res, p; bn_zero(&res); res.val[0] = 1; + // compute p = (prime+1)/4 memcpy(&p, prime, sizeof(bignum256)); p.val[0] += 1; bn_rshift(&p); bn_rshift(&p); for (i = 0; i < 9; i++) { + // invariants: + // x = old(x)^(2^(i*30)) + // res = old(x)^(p % 2^(i*30)) + // get the i-th limb of prime - 2 limb = p.val[i]; for (j = 0; j < 30; j++) { + // invariants: + // x = old(x)^(2^(i*30+j)) + // res = old(x)^(p % 2^(i*30+j)) + // limb = (p % 2^(i*30+30)) / 2^(i*30+j) if (i == 8 && limb == 0) break; if (limb & 1) { bn_multiply(x, &res, prime); @@ -277,14 +313,24 @@ void bn_sqrt(bignum256 *x, const bignum256 *prime) // in field G_prime, small but slow void bn_inverse(bignum256 *x, const bignum256 *prime) { + // this method compute x^-1 = x^(prime-2) uint32_t i, j, limb; bignum256 res; bn_zero(&res); res.val[0] = 1; for (i = 0; i < 9; i++) { + // invariants: + // x = old(x)^(2^(i*30)) + // res = old(x)^((prime-2) % 2^(i*30)) + // get the i-th limb of prime - 2 limb = prime->val[i]; // this is not enough in general but fine for secp256k1 because prime->val[0] > 1 if (i == 0) limb -= 2; for (j = 0; j < 30; j++) { + // invariants: + // x = old(x)^(2^(i*30+j)) + // res = old(x)^((prime-2) % 2^(i*30+j)) + // limb = ((prime-2) % 2^(i*30+30)) / 2^(i*30+j) + // early abort when only zero bits follow if (i == 8 && limb == 0) break; if (limb & 1) { bn_multiply(x, &res, prime); @@ -300,14 +346,18 @@ void bn_inverse(bignum256 *x, const bignum256 *prime) #else // in field G_prime, big but fast +// this algorithm is based on the Euklidean algorithm +// the result is smaller than 2*prime void bn_inverse(bignum256 *x, const bignum256 *prime) { int i, j, k, len1, len2, mask; uint8_t buf[32]; uint32_t u[8], v[8], s[9], r[10], temp32; uint64_t temp, temp2; + // reduce x modulo prime bn_fast_mod(x, prime); bn_mod(x, prime); + // convert x and prime it to 8x32 bit limb form bn_write_be(prime, buf); for (i = 0; i < 8; i++) { u[i] = read_be(buf + 28 - i * 4); @@ -321,59 +371,98 @@ void bn_inverse(bignum256 *x, const bignum256 *prime) r[0] = 0; len2 = 1; k = 0; + // u = prime, v = x len1 = numlimbs(u,v) + // r = 0 , s = 1 len2 = numlimbs(r,s) + // k = 0 for (;;) { + // invariants: + // r,s,u,v >= 0 + // x*-r = u*2^k mod prime + // x*s = v*2^k mod prime + // u*s + v*r = prime + // floor(log2(u)) + floor(log2(v)) + k <= 510 + // max(u,v) <= 2^k + // gcd(u,v) = 1 + // len1 = numlimbs(u,v) + // len2 = numlimbs(r,s) + // + // first u,v are large and s,r small + // later u,v are small and s,r large + + // if (is_zero(v)) break; for (i = 0; i < len1; i++) { if (v[i]) break; } if (i == len1) break; + + // reduce u while it is even for (;;) { + // count up to 30 zero bits of u. for (i = 0; i < 30; i++) { if (u[0] & (1 << i)) break; } + // if u was odd break if (i == 0) break; + + // shift u right by i bits. mask = (1 << i) - 1; for (j = 0; j + 1 < len1; j++) { u[j] = (u[j] >> i) | ((u[j + 1] & mask) << (32 - i)); } u[j] = (u[j] >> i); + + // shift s left by i bits. mask = (1 << (32 - i)) - 1; s[len2] = s[len2 - 1] >> (32 - i); for (j = len2 - 1; j > 0; j--) { s[j] = (s[j - 1] >> (32 - i)) | ((s[j] & mask) << i); } s[0] = (s[0] & mask) << i; + // update len2 if necessary if (s[len2]) { r[len2] = 0; len2++; } + // add i bits to k. k += i; } + // reduce v while it is even for (;;) { + // count up to 30 zero bits of v. for (i = 0; i < 30; i++) { if (v[0] & (1 << i)) break; } + // if v was odd break if (i == 0) break; + + // shift v right by i bits. mask = (1 << i) - 1; for (j = 0; j + 1 < len1; j++) { v[j] = (v[j] >> i) | ((v[j + 1] & mask) << (32 - i)); } v[j] = (v[j] >> i); mask = (1 << (32 - i)) - 1; + // shift r left by i bits. r[len2] = r[len2 - 1] >> (32 - i); for (j = len2 - 1; j > 0; j--) { r[j] = (r[j - 1] >> (32 - i)) | ((r[j] & mask) << i); } r[0] = (r[0] & mask) << i; + // update len2 if necessary if (r[len2]) { s[len2] = 0; len2++; } + // add i bits to k. k += i; } + // invariant is reestablished. i = len1 - 1; while (i > 0 && u[i] == v[i]) i--; if (u[i] > v[i]) { + // u > v: + // u = (u - v)/2; temp = 0x100000000ull + u[0] - v[0]; u[0] = (temp >> 1) & 0x7FFFFFFF; temp >>= 32; @@ -384,6 +473,8 @@ void bn_inverse(bignum256 *x, const bignum256 *prime) temp >>= 32; } temp = temp2 = 0; + // r += s; + // s += s; for (i = 0; i < len2; i++) { temp += s[i]; temp += r[i]; @@ -394,12 +485,19 @@ void bn_inverse(bignum256 *x, const bignum256 *prime) temp >>= 32; temp2 >>= 32; } + // expand if necessary. if (temp != 0 || temp2 != 0) { r[len2] = temp; s[len2] = temp2; len2++; } + // note that + // u'2^(k+1) = (u - v) 2^k = x -(r + s) = x -r' mod prime + // v'2^(k+1) = 2*v 2^k = x (s + s) = x s' mod prime + // u's' + v'r' = (u-v)/2(2s) + v(r+s) = us + vr } else { + // v >= u: + // v = v - u; temp = 0x100000000ull + v[0] - u[0]; v[0] = (temp >> 1) & 0x7FFFFFFF; temp >>= 32; @@ -409,6 +507,8 @@ void bn_inverse(bignum256 *x, const bignum256 *prime) v[i] = (temp >> 1) & 0x7FFFFFFF; temp >>= 32; } + // s = s + r + // r = r + r temp = temp2 = 0; for (i = 0; i < len2; i++) { temp += s[i]; @@ -425,11 +525,28 @@ void bn_inverse(bignum256 *x, const bignum256 *prime) r[len2] = temp2; len2++; } + // note that + // u'2^(k+1) = 2*u 2^k = x -(r + r) = x -r' mod prime + // v'2^(k+1) = (v - u) 2^k = x (s + r) = x s' mod prime + // u's' + v'r' = u(r+s) + (v-u)/2(2r) = us + vr } + // adjust len1 if possible. if (u[len1 - 1] == 0 && v[len1 - 1] == 0) len1--; + // increase k k++; } - + // In the last iteration just before the comparison and subtraction + // we had u=1, v=1, s+r = prime, k <= 510, 2^k > max(s,r) >= prime/2 + // hence 0 <= r < prime and 255 <= k <= 510. + // + // Afterwards r is doubled, k is incremented by 1. + // Hence 0 <= r < 2*prime and 256 <= k < 512. + // + // The invariants give us x*-r = 2^k mod prime, + // hence r = -2^k * x^-1 mod prime. + // We need to compute -r/2^k mod prime. + + // convert r to bignum style j = r[0] >> 30; r[0] = r[0] & 0x3FFFFFFFu; for (i = 1; i < len2; i++) { @@ -441,6 +558,7 @@ void bn_inverse(bignum256 *x, const bignum256 *prime) i++; for (; i < 9; i++) r[i] = 0; + // r = r mod prime, note that r<2*prime. i = 8; while (i > 0 && r[i] == prime->val[i]) i--; if (r[i] >= prime->val[i]) { @@ -451,26 +569,39 @@ void bn_inverse(bignum256 *x, const bignum256 *prime) temp32 >>= 30; } } + // negate r: r = prime - r temp32 = 1; for (i = 0; i < 9; i++) { temp32 += 0x3FFFFFFF + prime->val[i] - r[i]; r[i] = temp32 & 0x3FFFFFFF; temp32 >>= 30; } + // now: r = 2^k * x^-1 mod prime + // compute r/2^k, 256 <= k < 511 int done = 0; #if USE_PRECOMPUTED_IV if (prime == &prime256k1) { for (j = 0; j < 9; j++) { x->val[j] = r[j]; } + // secp256k1_iv[k-256] = 2^-k mod prime bn_multiply(secp256k1_iv + k - 256, x, prime); + // bn_fast_mod is unnecessary as bn_multiply already + // guarantees x < 2*prime bn_fast_mod(x, prime); + // We don't guarantee x < prime! + // the slow variant and the slow case below guarantee + // this. done = 1; } #endif if (!done) { + // compute r = r/2^k mod prime for (j = 0; j < k; j++) { + // invariant: r = 2^(k-j) * x^-1 mod prime + // in each iteration divide r by 2 modulo prime. if (r[0] & 1) { + // r is odd; compute r = (prime + r)/2 temp32 = r[0] + prime->val[0]; r[0] = (temp32 >> 1) & 0x1FFFFFFF; temp32 >>= 30; @@ -481,12 +612,14 @@ void bn_inverse(bignum256 *x, const bignum256 *prime) temp32 >>= 30; } } else { + // r = r / 2 for (i = 0; i < 8; i++) { r[i] = (r[i] >> 1) | ((r[i + 1] & 1) << 29); } r[8] = r[8] >> 1; } } + // r = x^-1 mod prime, since j = k for (j = 0; j < 9; j++) { x->val[j] = r[j]; } From cb9ccc5cf4ea3992172f31e8d1506f1a5b791157 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 12 Mar 2015 15:53:41 +0100 Subject: [PATCH 164/627] remove all references to USE_PUBKEY_VALIDATE --- Makefile | 2 +- bip32.c | 2 -- options.h | 5 ----- setup.py | 2 +- tests.c | 2 -- tools/Makefile | 2 -- 6 files changed, 2 insertions(+), 13 deletions(-) diff --git a/Makefile b/Makefile index 95ab8f846..f24d375da 100644 --- a/Makefile +++ b/Makefile @@ -27,7 +27,7 @@ CFLAGS += -Wno-sequence-point # disable certain optimizations and features when small footprint is required ifdef SMALL -CFLAGS += -DUSE_PRECOMPUTED_IV=0 -DUSE_PRECOMPUTED_CP=0 -DUSE_PUBKEY_VALIDATE=0 +CFLAGS += -DUSE_PRECOMPUTED_IV=0 -DUSE_PRECOMPUTED_CP=0 endif OBJS = bignum.o ecdsa.o secp256k1.o rand.o hmac.o bip32.o bip39.o pbkdf2.o base58.o diff --git a/bip32.c b/bip32.c index 43218aed9..daf500b8c 100644 --- a/bip32.c +++ b/bip32.c @@ -162,11 +162,9 @@ int hdnode_public_ckd(HDNode *inout, uint32_t i) scalar_multiply(&c, &b); // b = c * G point_add(&a, &b); // b = a + b -#if USE_PUBKEY_VALIDATE if (!ecdsa_validate_pubkey(&b)) { return 0; } -#endif inout->public_key[0] = 0x02 | (b.y.val[0] & 0x01); bn_write_be(&b.x, inout->public_key + 1); diff --git a/options.h b/options.h index 0e68178c2..8c8a329dc 100644 --- a/options.h +++ b/options.h @@ -48,11 +48,6 @@ #define USE_RFC6979 1 #endif -// check public key for validity -#ifndef USE_PUBKEY_VALIDATE -#define USE_PUBKEY_VALIDATE 1 -#endif - // implement BIP32 caching #ifndef USE_BIP32_CACHE #define USE_BIP32_CACHE 1 diff --git a/setup.py b/setup.py index 592976a21..106171681 100755 --- a/setup.py +++ b/setup.py @@ -19,7 +19,7 @@ srcs = [ extensions = [ Extension('TrezorCrypto', sources = ['TrezorCrypto.pyx', 'c.pxd'] + [ x + '.c' for x in srcs ], - extra_compile_args = ['-DUSE_PUBKEY_VALIDATE=0'], + extra_compile_args = [], ) ] diff --git a/tests.c b/tests.c index 57431da19..57dc0c9b0 100644 --- a/tests.c +++ b/tests.c @@ -1060,7 +1060,6 @@ START_TEST(test_pubkey_validity) res = ecdsa_read_pubkey(pub_key, &pub); ck_assert_int_eq(res, 1); -#if USE_PUBKEY_VALIDATE memcpy(pub_key, fromhex("04f80490839af36d13701ec3f9eebdac901b51c362119d74553a3c537faff31b17e2a59ebddbdac9e87b816307a7ed5b826b8f40b92719086238e1bebf00000000"), 65); res = ecdsa_read_pubkey(pub_key, &pub); ck_assert_int_eq(res, 0); @@ -1068,7 +1067,6 @@ START_TEST(test_pubkey_validity) memcpy(pub_key, fromhex("04f80490839af36d13701ec3f9eebdac901b51c362119d74553a3c537faff31b17e2a59ebddbdac9e87b816307a7ed5b8211111111111111111111111111111111"), 65); res = ecdsa_read_pubkey(pub_key, &pub); ck_assert_int_eq(res, 0); -#endif memcpy(pub_key, fromhex("00"), 1); res = ecdsa_read_pubkey(pub_key, &pub); diff --git a/tools/Makefile b/tools/Makefile index 8b83089f9..67c652637 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -23,8 +23,6 @@ CFLAGS += $(OPTFLAGS) \ -Werror \ -I.. -CFLAGS += -DUSE_PUBKEY_VALIDATE=0 - all: xpubaddrgen OBJS = ../bip32.o ../ecdsa.o ../sha2.o ../bignum.o ../base58.o ../secp256k1.o ../ripemd160.o ../hmac.o ../rand.o From e37ba822e627550a453a1678d180f7e056b3d98f Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 17 Mar 2015 14:15:38 +0100 Subject: [PATCH 165/627] bn_substract -> bn_subtractmod, bn_substract_noprime -> bn_subtract remove dead code --- bignum.c | 27 ++------------------------- bignum.h | 8 ++------ ecdsa.c | 16 ++++++++-------- 3 files changed, 12 insertions(+), 39 deletions(-) diff --git a/bignum.c b/bignum.c index 60846195a..7c1484962 100644 --- a/bignum.c +++ b/bignum.c @@ -154,29 +154,6 @@ void bn_mod(bignum256 *x, const bignum256 *prime) } } -// a = a + b -void bn_addi(bignum256 *a, uint32_t b) -{ - uint64_t t = a->val[0]; - t += b; - a->val[0] = t & 0x3FFFFFFFu; - t >>= 30; - a->val[1] += t; -} - -// a = a * b -void bn_muli(bignum256 *a, uint32_t b) -{ - uint64_t t = 0; - int i; - for (i = 0; i < 8; i++) { - t = (uint64_t)(a->val[i]) * b + t; - a->val[i] = t & 0x3FFFFFFFu; - t >>= 30; - } - a->val[8] += t; -} - // Compute x := k * x (mod prime) // both inputs must be smaller than 2 * prime. // result is reduced to 0 <= x < 2 * prime @@ -657,7 +634,7 @@ void bn_addmodi(bignum256 *a, uint32_t b, const bignum256 *prime) { // res = a - b // b < 2*prime; result not normalized -void bn_substract(const bignum256 *a, const bignum256 *b, bignum256 *res) +void bn_subtractmod(const bignum256 *a, const bignum256 *b, bignum256 *res) { int i; uint32_t temp = 0; @@ -669,7 +646,7 @@ void bn_substract(const bignum256 *a, const bignum256 *b, bignum256 *res) } // res = a - b ; a > b -void bn_substract_noprime(const bignum256 *a, const bignum256 *b, bignum256 *res) +void bn_subtract(const bignum256 *a, const bignum256 *b, bignum256 *res) { int i; uint32_t tmp = 1; diff --git a/bignum.h b/bignum.h index 168354643..de71fba0e 100644 --- a/bignum.h +++ b/bignum.h @@ -59,10 +59,6 @@ void bn_rshift(bignum256 *a); void bn_mod(bignum256 *x, const bignum256 *prime); -void bn_addi(bignum256 *a, uint32_t b); - -void bn_muli(bignum256 *a, uint32_t b); - void bn_multiply(const bignum256 *k, bignum256 *x, const bignum256 *prime); void bn_fast_mod(bignum256 *x, const bignum256 *prime); @@ -77,9 +73,9 @@ void bn_addmod(bignum256 *a, const bignum256 *b, const bignum256 *prime); void bn_addmodi(bignum256 *a, uint32_t b, const bignum256 *prime); -void bn_substract(const bignum256 *a, const bignum256 *b, bignum256 *res); +void bn_subtractmod(const bignum256 *a, const bignum256 *b, bignum256 *res); -void bn_substract_noprime(const bignum256 *a, const bignum256 *b, bignum256 *res); +void bn_subtract(const bignum256 *a, const bignum256 *b, bignum256 *res); void bn_divmod58(bignum256 *a, uint32_t *r); diff --git a/ecdsa.c b/ecdsa.c index 831098cb2..0c5b5a625 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -63,9 +63,9 @@ void point_add(const curve_point *cp1, curve_point *cp2) return; } - bn_substract(&(cp2->x), &(cp1->x), &inv); + bn_subtractmod(&(cp2->x), &(cp1->x), &inv); bn_inverse(&inv, &prime256k1); - bn_substract(&(cp2->y), &(cp1->y), &lambda); + bn_subtractmod(&(cp2->y), &(cp1->y), &lambda); bn_multiply(&inv, &lambda, &prime256k1); memcpy(&xr, &lambda, sizeof(bignum256)); bn_multiply(&xr, &xr, &prime256k1); @@ -76,11 +76,11 @@ void point_add(const curve_point *cp1, curve_point *cp2) temp >>= 30; } bn_fast_mod(&xr, &prime256k1); - bn_substract(&(cp1->x), &xr, &yr); + bn_subtractmod(&(cp1->x), &xr, &yr); // no need to fast_mod here // bn_fast_mod(&yr); bn_multiply(&lambda, &yr, &prime256k1); - bn_substract(&yr, &(cp1->y), &yr); + bn_subtractmod(&yr, &(cp1->y), &yr); bn_fast_mod(&yr, &prime256k1); memcpy(&(cp2->x), &xr, sizeof(bignum256)); memcpy(&(cp2->y), &yr, sizeof(bignum256)); @@ -118,11 +118,11 @@ void point_double(curve_point *cp) temp >>= 30; } bn_fast_mod(&xr, &prime256k1); - bn_substract(&(cp->x), &xr, &yr); + bn_subtractmod(&(cp->x), &xr, &yr); // no need to fast_mod here // bn_fast_mod(&yr); bn_multiply(&lambda, &yr, &prime256k1); - bn_substract(&yr, &(cp->y), &yr); + bn_subtractmod(&yr, &(cp->y), &yr); bn_fast_mod(&yr, &prime256k1); memcpy(&(cp->x), &xr, sizeof(bignum256)); memcpy(&(cp->y), &yr, sizeof(bignum256)); @@ -363,7 +363,7 @@ int ecdsa_sign_digest(const uint8_t *priv_key, const uint8_t *digest, uint8_t *s // if S > order/2 => S = -S if (bn_is_less(&order256k1_half, &k)) { - bn_substract_noprime(&order256k1, &k, &k); + bn_subtract(&order256k1, &k, &k); if (pby) { *pby = !*pby; } @@ -451,7 +451,7 @@ void uncompress_coords(uint8_t odd, const bignum256 *x, bignum256 *y) bn_addmodi(y, 7, &prime256k1); // y is x^3 + 7 bn_sqrt(y, &prime256k1); // y = sqrt(y) if ((odd & 0x01) != (y->val[0] & 1)) { - bn_substract_noprime(&prime256k1, y, y); // y = -y + bn_subtract(&prime256k1, y, y); // y = -y } } From 7d4cf5cedd6a70a387cde86d87120ba0a44fc3b2 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Thu, 12 Mar 2015 10:40:49 +0100 Subject: [PATCH 166/627] Optimized the bn_inverse method. The new method needs about 30 % less time for prime256k1 and is about twice as fast for other moduli. The base algorithm is the same. The code is also a bit smaller and doesn't need the 8 kb precomputed table. Important canges: 1. even/odd distinction so that we need to test only one of the numbers for being even. This also leads to less duplicated code. 2. Allow for shifting by 32 bits at a time in the even test. 3. Pack u,s and v,r into the same array, which saves a bit of stack memory. 4. Don't divide by two after subtraction; this simplifies code. 5. Abort as soon as u,v are equal, instead of subtracting them. 6. Use s instead of r after the loop; no negation needed. 7. New code that divides by 2^k fast without any precomputed values. --- bignum.c | 475 +++++++++++++++++++++++++--------------------------- options.h | 5 - secp256k1.c | 261 ----------------------------- secp256k1.h | 4 - 4 files changed, 230 insertions(+), 515 deletions(-) diff --git a/bignum.c b/bignum.c index 7c1484962..b22518d9a 100644 --- a/bignum.c +++ b/bignum.c @@ -23,6 +23,7 @@ #include #include +#include #include "bignum.h" #include "secp256k1.h" @@ -283,10 +284,6 @@ void bn_sqrt(bignum256 *x, const bignum256 *prime) #if ! USE_INVERSE_FAST -#if USE_PRECOMPUTED_IV -#warning USE_PRECOMPUTED_IV will not be used -#endif - // in field G_prime, small but slow void bn_inverse(bignum256 *x, const bignum256 *prime) { @@ -322,285 +319,273 @@ void bn_inverse(bignum256 *x, const bignum256 *prime) #else -// in field G_prime, big but fast -// this algorithm is based on the Euklidean algorithm -// the result is smaller than 2*prime +// in field G_prime, big and complicated but fast +// the input must not be 0 mod prime. +// the result is smaller than prime void bn_inverse(bignum256 *x, const bignum256 *prime) { - int i, j, k, len1, len2, mask; - uint8_t buf[32]; - uint32_t u[8], v[8], s[9], r[10], temp32; - uint64_t temp, temp2; - // reduce x modulo prime + int i, j, k, cmp; + struct combo { + uint32_t a[9]; + int len1; + } us, vr, *odd, *even; + uint32_t pp[8]; + uint32_t temp32; + uint64_t temp; + + // The algorithm is based on Schroeppel et. al. "Almost Modular Inverse" + // algorithm. We keep four values u,v,r,s in the combo registers + // us and vr. us stores u in the first len1 limbs (little endian) + // and v in the last 9-len1 limbs (big endian). vr stores v and s. + // This is because both u*s and v*r are guaranteed to fit in 8 limbs, so + // their components are guaranteed to fit in 9. During the algorithm, + // the length of u and v shrinks while r and s grow. + // u,v,r,s correspond to F,G,B,C in Schroeppel's algorithm. + + // reduce x modulo prime. This is necessary as it has to fit in 8 limbs. bn_fast_mod(x, prime); bn_mod(x, prime); - // convert x and prime it to 8x32 bit limb form - bn_write_be(prime, buf); + // convert x and prime to 8x32 bit limb form + temp32 = prime->val[0]; for (i = 0; i < 8; i++) { - u[i] = read_be(buf + 28 - i * 4); + temp32 |= prime->val[i + 1] << (30-2*i); + us.a[i] = pp[i] = temp32; + temp32 = prime->val[i + 1] >> (2+2*i); } - bn_write_be(x, buf); + temp32 = x->val[0]; for (i = 0; i < 8; i++) { - v[i] = read_be(buf + 28 - i * 4); + temp32 |= x->val[i + 1] << (30-2*i); + vr.a[i] = temp32; + temp32 = x->val[i + 1] >> (2+2*i); } - len1 = 8; - s[0] = 1; - r[0] = 0; - len2 = 1; + us.len1 = 8; + vr.len1 = 8; + // set s = 1 and r = 0 + us.a[8] = 1; + vr.a[8] = 0; + // set k = 0. k = 0; - // u = prime, v = x len1 = numlimbs(u,v) - // r = 0 , s = 1 len2 = numlimbs(r,s) + + // only one of the numbers u,v can be even at any time. We + // let even point to that number and odd to the other. + // Initially the prime u is guaranteed to be odd. + odd = &us; + even = &vr; + + // u = prime, v = x + // r = 0 , s = 1 // k = 0 for (;;) { // invariants: - // r,s,u,v >= 0 + // let u = limbs us.a[0..u.len1-1] in little endian, + // let s = limbs us.a[u.len..8] in big endian, + // let v = limbs vr.a[0..u.len1-1] in little endian, + // let r = limbs vr.a[u.len..8] in big endian, + // r,s >= 0 ; u,v >= 1 // x*-r = u*2^k mod prime // x*s = v*2^k mod prime // u*s + v*r = prime // floor(log2(u)) + floor(log2(v)) + k <= 510 - // max(u,v) <= 2^k + // max(u,v) <= 2^k (*) see comment at end of loop // gcd(u,v) = 1 - // len1 = numlimbs(u,v) - // len2 = numlimbs(r,s) + // {odd,even} = {&us, &vr} + // odd->a[0] and odd->a[8] are odd + // even->a[0] or even->a[8] is even // - // first u,v are large and s,r small - // later u,v are small and s,r large - - // if (is_zero(v)) break; - for (i = 0; i < len1; i++) { - if (v[i]) break; + // first u/v are large and r/s small + // later u/v are small and r/s large + assert(odd->a[0] & 1); + assert(odd->a[8] & 1); + + // adjust length of even. + while (even->a[even->len1 - 1] == 0) { + even->len1--; + // if input was 0, return. + // This simple check prevents crashing with stack underflow + // or worse undesired behaviour for illegal input. + if (even->len1 < 0) + return; } - if (i == len1) break; - - // reduce u while it is even - for (;;) { - // count up to 30 zero bits of u. - for (i = 0; i < 30; i++) { - if (u[0] & (1 << i)) break; - } - // if u was odd break - if (i == 0) break; - // shift u right by i bits. - mask = (1 << i) - 1; - for (j = 0; j + 1 < len1; j++) { - u[j] = (u[j] >> i) | ((u[j + 1] & mask) << (32 - i)); - } - u[j] = (u[j] >> i); - - // shift s left by i bits. - mask = (1 << (32 - i)) - 1; - s[len2] = s[len2 - 1] >> (32 - i); - for (j = len2 - 1; j > 0; j--) { - s[j] = (s[j - 1] >> (32 - i)) | ((s[j] & mask) << i); - } - s[0] = (s[0] & mask) << i; - // update len2 if necessary - if (s[len2]) { - r[len2] = 0; - len2++; + // reduce even->a while it is even + while (even->a[0] == 0) { + // shift right first part of even by a limb + // and shift left second part of even by a limb. + for (i = 0; i < 8; i++) { + even->a[i] = even->a[i+1]; } - // add i bits to k. - k += i; + even->a[i] = 0; + even->len1--; + k += 32; } - // reduce v while it is even - for (;;) { - // count up to 30 zero bits of v. - for (i = 0; i < 30; i++) { - if (v[0] & (1 << i)) break; - } - // if v was odd break - if (i == 0) break; - - // shift v right by i bits. - mask = (1 << i) - 1; - for (j = 0; j + 1 < len1; j++) { - v[j] = (v[j] >> i) | ((v[j + 1] & mask) << (32 - i)); + // count up to 32 zero bits of even->a. + j = 0; + while ((even->a[0] & (1 << j)) == 0) { + j++; + } + if (j > 0) { + // shift first part of even right by j bits. + for (i = 0; i + 1 < even->len1; i++) { + even->a[i] = (even->a[i] >> j) | (even->a[i + 1] << (32 - j)); } - v[j] = (v[j] >> i); - mask = (1 << (32 - i)) - 1; - // shift r left by i bits. - r[len2] = r[len2 - 1] >> (32 - i); - for (j = len2 - 1; j > 0; j--) { - r[j] = (r[j - 1] >> (32 - i)) | ((r[j] & mask) << i); + even->a[i] = (even->a[i] >> j); + if (even->a[i] == 0) { + even->len1--; + } else { + i++; } - r[0] = (r[0] & mask) << i; - // update len2 if necessary - if (r[len2]) { - s[len2] = 0; - len2++; + + // shift second part of even left by j bits. + for (; i < 8; i++) { + even->a[i] = (even->a[i] << j) | (even->a[i + 1] >> (32 - j)); } - // add i bits to k. - k += i; + even->a[i] = (even->a[i] << j); + // add j bits to k. + k += j; } - // invariant is reestablished. - i = len1 - 1; - while (i > 0 && u[i] == v[i]) i--; - if (u[i] > v[i]) { - // u > v: - // u = (u - v)/2; - temp = 0x100000000ull + u[0] - v[0]; - u[0] = (temp >> 1) & 0x7FFFFFFF; - temp >>= 32; - for (i = 1; i < len1; i++) { - temp += 0xFFFFFFFFull + u[i] - v[i]; - u[i - 1] += (temp & 1) << 31; - u[i] = (temp >> 1) & 0x7FFFFFFF; - temp >>= 32; - } - temp = temp2 = 0; - // r += s; - // s += s; - for (i = 0; i < len2; i++) { - temp += s[i]; - temp += r[i]; - temp2 += s[i]; - temp2 += s[i]; - r[i] = temp; - s[i] = temp2; - temp >>= 32; - temp2 >>= 32; - } - // expand if necessary. - if (temp != 0 || temp2 != 0) { - r[len2] = temp; - s[len2] = temp2; - len2++; - } - // note that - // u'2^(k+1) = (u - v) 2^k = x -(r + s) = x -r' mod prime - // v'2^(k+1) = 2*v 2^k = x (s + s) = x s' mod prime - // u's' + v'r' = (u-v)/2(2s) + v(r+s) = us + vr + // now both a[0] are odd. + assert(odd->a[0] & 1); + assert(odd->a[8] & 1); + assert(even->a[0] & 1); + assert((even->a[8] & 1) == 0); + + // cmp > 0 if us.a[0..len1-1] > vr.a[0..len1-1], + // cmp = 0 if equal, < 0 if less. + cmp = us.len1 - vr.len1; + if (cmp == 0) { + i = us.len1 - 1; + while (i >= 0 && us.a[i] == vr.a[i]) i--; + // both are equal to 1 and we are done. + if (i == -1) + break; + cmp = us.a[i] > vr.a[i] ? 1 : -1; + } + if (cmp > 0) { + even = &us; + odd = &vr; } else { - // v >= u: - // v = v - u; - temp = 0x100000000ull + v[0] - u[0]; - v[0] = (temp >> 1) & 0x7FFFFFFF; + even = &vr; + odd = &us; + } + + // now even > odd. + + // even->a[0..len1-1] = (even->a[0..len1-1] - odd->a[0..len1-1]); + temp = 1; + for (i = 0; i < odd->len1; i++) { + temp += 0xFFFFFFFFull + even->a[i] - odd->a[i]; + even->a[i] = temp & 0xFFFFFFFF; temp >>= 32; - for (i = 1; i < len1; i++) { - temp += 0xFFFFFFFFull + v[i] - u[i]; - v[i - 1] += (temp & 1) << 31; - v[i] = (temp >> 1) & 0x7FFFFFFF; - temp >>= 32; - } - // s = s + r - // r = r + r - temp = temp2 = 0; - for (i = 0; i < len2; i++) { - temp += s[i]; - temp += r[i]; - temp2 += r[i]; - temp2 += r[i]; - s[i] = temp; - r[i] = temp2; - temp >>= 32; - temp2 >>= 32; - } - if (temp != 0 || temp2 != 0) { - s[len2] = temp; - r[len2] = temp2; - len2++; - } - // note that - // u'2^(k+1) = 2*u 2^k = x -(r + r) = x -r' mod prime - // v'2^(k+1) = (v - u) 2^k = x (s + r) = x s' mod prime - // u's' + v'r' = u(r+s) + (v-u)/2(2r) = us + vr } - // adjust len1 if possible. - if (u[len1 - 1] == 0 && v[len1 - 1] == 0) len1--; - // increase k - k++; + for (; i < even->len1; i++) { + temp += 0xFFFFFFFFull + even->a[i]; + even->a[i] = temp & 0xFFFFFFFF; + temp >>= 32; + } + // odd->a[len1..8] = (odd->b[len1..8] + even->b[len1..8]); + temp = 0; + for (i = 8; i >= even->len1; i--) { + temp += (uint64_t) odd->a[i] + even->a[i]; + odd->a[i] = temp & 0xFFFFFFFF; + temp >>= 32; + } + for (; i >= odd->len1; i--) { + temp += (uint64_t) odd->a[i]; + odd->a[i] = temp & 0xFFFFFFFF; + temp >>= 32; + } + // note that + // if u > v: + // u'2^k = (u - v) 2^k = x(-r) - xs = x(-(r+s)) = x(-r') mod prime + // u's' + v'r' = (u-v)s + v(r+s) = us + vr + // if u < v: + // v'2^k = (v - u) 2^k = xs - x(-r) = x(s+r) = xs' mod prime + // u's' + v'r' = u(s+r) + (v-u)r = us + vr + + // even->a[0] is difference between two odd numbers, hence even. + // odd->a[8] is sum of even and odd number, hence odd. + assert(odd->a[0] & 1); + assert(odd->a[8] & 1); + assert((even->a[0] & 1) == 0); + + // The invariants are (almost) reestablished. + // The invariant max(u,v) <= 2^k can be invalidated at this point, + // because odd->a[len1..8] was changed. We only have + // + // odd->a[len1..8] <= 2^{k+1} + // + // Since even->a[0] is even, k will be incremented at the beginning + // of the next loop while odd->a[len1..8] remains unchanged. + // So after that, odd->a[len1..8] <= 2^k will hold again. } - // In the last iteration just before the comparison and subtraction - // we had u=1, v=1, s+r = prime, k <= 510, 2^k > max(s,r) >= prime/2 - // hence 0 <= r < prime and 255 <= k <= 510. - // - // Afterwards r is doubled, k is incremented by 1. - // Hence 0 <= r < 2*prime and 256 <= k < 512. + // In the last iteration we had u = v and gcd(u,v) = 1. + // Hence, u=1, v=1, s+r = prime, k <= 510, 2^k > max(s,r) >= prime/2 + // This implies 0 <= s < prime and 255 <= k <= 510. // - // The invariants give us x*-r = 2^k mod prime, - // hence r = -2^k * x^-1 mod prime. - // We need to compute -r/2^k mod prime. - - // convert r to bignum style - j = r[0] >> 30; - r[0] = r[0] & 0x3FFFFFFFu; - for (i = 1; i < len2; i++) { - uint32_t q = r[i] >> (30 - 2 * i); - r[i] = ((r[i] << (2 * i)) & 0x3FFFFFFFu) + j; - j=q; + // The invariants also give us x*s = 2^k mod prime, + // hence s = -2^k * x^-1 mod prime. + // We need to compute -s/2^k mod prime. + + // First we compute inverse = -prime^-1 mod 2^32, which we need later. + // We use the Explicit Quadratic Modular inverse algorithm. + // http://arxiv.org/pdf/1209.6626.pdf + // a^-1 = (2-a) * PROD_i (1 + (a - 1)^(2^i)) mod 2^32 + // the product will converge quickly, because (a-1)^(2^i) will be + // zero mod 2^32 after at most five iterations. + // We want to compute -prime^-1 so we start with (pp[0]-2). + assert(pp[0] & 1); + uint32_t amone = pp[0]-1; + uint32_t inverse = pp[0] - 2; + while (amone) { + amone *= amone; + inverse *= (amone + 1); } - r[i] = j; - i++; - for (; i < 9; i++) r[i] = 0; - - // r = r mod prime, note that r<2*prime. - i = 8; - while (i > 0 && r[i] == prime->val[i]) i--; - if (r[i] >= prime->val[i]) { - temp32 = 1; - for (i = 0; i < 9; i++) { - temp32 += 0x3FFFFFFF + r[i] - prime->val[i]; - r[i] = temp32 & 0x3FFFFFFF; - temp32 >>= 30; + + while (k >= 32) { + // compute s / 2^32 modulo prime. + // Idea: compute factor, such that + // s + factor*prime mod 2^32 == 0 + // i.e. factor = s * -1/prime mod 2^32. + // Then compute s + factor*prime and shift right by 32 bits. + uint32_t factor = (inverse * us.a[8]) & 0xffffffff; + temp = us.a[8] + (uint64_t) pp[0] * factor; + // printf("%lx %x %x %x\n", temp, us.b[0], inverse, factor); + assert((temp & 0xffffffff) == 0); + temp >>= 32; + for (i = 0; i < 7; i++) { + temp += us.a[8-(i+1)] + (uint64_t) pp[i+1] * factor; + us.a[8-i] = temp & 0xffffffff; + temp >>= 32; } + us.a[8-i] = temp & 0xffffffff; + k -= 32; } - // negate r: r = prime - r - temp32 = 1; - for (i = 0; i < 9; i++) { - temp32 += 0x3FFFFFFF + prime->val[i] - r[i]; - r[i] = temp32 & 0x3FFFFFFF; - temp32 >>= 30; - } - // now: r = 2^k * x^-1 mod prime - // compute r/2^k, 256 <= k < 511 - int done = 0; -#if USE_PRECOMPUTED_IV - if (prime == &prime256k1) { - for (j = 0; j < 9; j++) { - x->val[j] = r[j]; + if (k > 0) { + // compute s / 2^k modulo prime. + // Same idea: compute factor, such that + // s + factor*prime mod 2^k == 0 + // i.e. factor = s * -1/prime mod 2^k. + // Then compute s + factor*prime and shift right by k bits. + uint32_t mask = (1 << k) - 1; + uint32_t factor = (inverse * us.a[8]) & mask; + temp = (us.a[8] + (uint64_t) pp[0] * factor) >> k; + assert(((us.a[8] + pp[0] * factor) & mask) == 0); + for (i = 0; i < 7; i++) { + temp += (us.a[8-(i+1)] + (uint64_t) pp[i+1] * factor) << (32 - k); + us.a[8-i] = temp & 0xffffffff; + temp >>= 32; } - // secp256k1_iv[k-256] = 2^-k mod prime - bn_multiply(secp256k1_iv + k - 256, x, prime); - // bn_fast_mod is unnecessary as bn_multiply already - // guarantees x < 2*prime - bn_fast_mod(x, prime); - // We don't guarantee x < prime! - // the slow variant and the slow case below guarantee - // this. - done = 1; + us.a[8-i] = temp & 0xffffffff; } -#endif - if (!done) { - // compute r = r/2^k mod prime - for (j = 0; j < k; j++) { - // invariant: r = 2^(k-j) * x^-1 mod prime - // in each iteration divide r by 2 modulo prime. - if (r[0] & 1) { - // r is odd; compute r = (prime + r)/2 - temp32 = r[0] + prime->val[0]; - r[0] = (temp32 >> 1) & 0x1FFFFFFF; - temp32 >>= 30; - for (i = 1; i < 9; i++) { - temp32 += r[i] + prime->val[i]; - r[i - 1] += (temp32 & 1) << 29; - r[i] = (temp32 >> 1) & 0x1FFFFFFF; - temp32 >>= 30; - } - } else { - // r = r / 2 - for (i = 0; i < 8; i++) { - r[i] = (r[i] >> 1) | ((r[i + 1] & 1) << 29); - } - r[8] = r[8] >> 1; - } - } - // r = x^-1 mod prime, since j = k - for (j = 0; j < 9; j++) { - x->val[j] = r[j]; - } + + // convert s to bignum style + temp32 = 0; + for (i = 0; i < 8; i++) { + x->val[i] = ((us.a[8-i] << (2 * i)) & 0x3FFFFFFFu) | temp32; + temp32 = us.a[8-i] >> (30 - 2 * i); } + x->val[i] = temp32; } #endif diff --git a/options.h b/options.h index 8c8a329dc..9612fdfcf 100644 --- a/options.h +++ b/options.h @@ -23,11 +23,6 @@ #ifndef __OPTIONS_H__ #define __OPTIONS_H__ -// use precomputed Inverse Values of powers of two -#ifndef USE_PRECOMPUTED_IV -#define USE_PRECOMPUTED_IV 1 -#endif - // use precomputed Curve Points (some scalar multiples of curve base point G) #ifndef USE_PRECOMPUTED_CP #define USE_PRECOMPUTED_CP 1 diff --git a/secp256k1.c b/secp256k1.c index 40aa97281..4baf6d617 100644 --- a/secp256k1.c +++ b/secp256k1.c @@ -39,267 +39,6 @@ const bignum256 order256k1_half = { const bignum256 three_over_two256k1 = { /*.val =*/{0x3ffffe19, 0x3ffffffd, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x7fff}}; -#if USE_PRECOMPUTED_IV -const bignum256 secp256k1_iv[256] = { -{/*.val =*/{0x868192a, 0x20e02474, 0x24a059d, 0x2c88ffb7, 0x32b761bc, 0x1b0b0a57, 0x383999c4, 0x6414554, 0xc9bd}}, -{/*.val =*/{0x4340c95, 0x3070123a, 0x212502ce, 0x16447fdb, 0x395bb0de, 0xd85852b, 0x1c1ccce2, 0x2320a2aa, 0x64de}}, -{/*.val =*/{0x21a0462, 0x1838091b, 0x30928167, 0xb223fed, 0x3cadd86f, 0x6c2c295, 0xe0e6671, 0x11905155, 0xb26f}}, -{/*.val =*/{0x210d0231, 0x2c1c048d, 0x384940b3, 0x25911ff6, 0x3e56ec37, 0x2361614a, 0x27073338, 0x28c828aa, 0x5937}}, -{/*.val =*/{0x30867f30, 0x360e0244, 0x1c24a059, 0x32c88ffb, 0x1f2b761b, 0x11b0b0a5, 0x1383999c, 0x34641455, 0xac9b}}, -{/*.val =*/{0x18433f98, 0x3b070122, 0x2e12502c, 0x396447fd, 0x2f95bb0d, 0x8d85852, 0x29c1ccce, 0x3a320a2a, 0x564d}}, -{/*.val =*/{0xc219fcc, 0x1d838091, 0x37092816, 0x3cb223fe, 0x17cadd86, 0x46c2c29, 0x14e0e667, 0x3d190515, 0x2b26}}, -{/*.val =*/{0x2610cfe6, 0xec1c048, 0x1b84940b, 0x1e5911ff, 0x2be56ec3, 0x22361614, 0x2a707333, 0x1e8c828a, 0x1593}}, -{/*.val =*/{0x130867f3, 0x2760e024, 0x2dc24a05, 0x2f2c88ff, 0x15f2b761, 0x311b0b0a, 0x15383999, 0x2f464145, 0xac9}}, -{/*.val =*/{0x9843211, 0x33b07010, 0x36e12502, 0x3796447f, 0xaf95bb0, 0x388d8585, 0x2a9c1ccc, 0x37a320a2, 0x8564}}, -{/*.val =*/{0x4c21720, 0x19d83806, 0x3b709281, 0x1bcb223f, 0x257cadd8, 0x1c46c2c2, 0x154e0e66, 0x1bd19051, 0xc2b2}}, -{/*.val =*/{0x2610b90, 0x2cec1c03, 0x3db84940, 0xde5911f, 0x12be56ec, 0xe236161, 0x2aa70733, 0xde8c828, 0x6159}}, -{/*.val =*/{0x213085c8, 0x16760e01, 0x3edc24a0, 0x6f2c88f, 0x295f2b76, 0x2711b0b0, 0x15538399, 0x26f46414, 0x30ac}}, -{/*.val =*/{0x309842e4, 0xb3b0700, 0x3f6e1250, 0x3796447, 0x14af95bb, 0x3388d858, 0xaa9c1cc, 0x137a320a, 0x1856}}, -{/*.val =*/{0x184c2172, 0x59d8380, 0x3fb70928, 0x21bcb223, 0xa57cadd, 0x19c46c2c, 0x554e0e6, 0x9bd1905, 0xc2b}}, -{/*.val =*/{0xc2610b9, 0x2cec1c0, 0x3fdb8494, 0x30de5911, 0x52be56e, 0xce23616, 0x22aa7073, 0x24de8c82, 0x615}}, -{/*.val =*/{0x6130674, 0x16760de, 0x3fedc24a, 0x186f2c88, 0x295f2b7, 0x26711b0b, 0x11553839, 0x326f4641, 0x830a}}, -{/*.val =*/{0x309833a, 0xb3b06f, 0x1ff6e125, 0x2c379644, 0x214af95b, 0x33388d85, 0x28aa9c1c, 0x1937a320, 0x4185}}, -{/*.val =*/{0x2184c19d, 0x2059d837, 0xffb7092, 0x361bcb22, 0x30a57cad, 0x199c46c2, 0x14554e0e, 0x2c9bd190, 0x20c2}}, -{/*.val =*/{0x30c25ee6, 0x102cec19, 0x7fdb849, 0x3b0de591, 0x1852be56, 0xcce2361, 0xa2aa707, 0x164de8c8, 0x9061}}, -{/*.val =*/{0x38612f73, 0x2816760c, 0x23fedc24, 0x1d86f2c8, 0x2c295f2b, 0x266711b0, 0x5155383, 0x2b26f464, 0x4830}}, -{/*.val =*/{0x1c3095d1, 0x140b3b04, 0x11ff6e12, 0x2ec37964, 0x1614af95, 0x333388d8, 0x28aa9c1, 0x15937a32, 0xa418}}, -{/*.val =*/{0xe184900, 0xa059d80, 0x8ffb709, 0x3761bcb2, 0xb0a57ca, 0x3999c46c, 0x14554e0, 0xac9bd19, 0xd20c}}, -{/*.val =*/{0x70c2480, 0x2502cec0, 0x47fdb84, 0x1bb0de59, 0x5852be5, 0x1ccce236, 0x20a2aa70, 0x564de8c, 0x6906}}, -{/*.val =*/{0x3861240, 0x12816760, 0x223fedc2, 0x2dd86f2c, 0x2c295f2, 0xe66711b, 0x10515538, 0x2b26f46, 0x3483}}, -{/*.val =*/{0x1c30920, 0x940b3b0, 0x111ff6e1, 0x16ec3796, 0x21614af9, 0x733388d, 0x828aa9c, 0x215937a3, 0x1a41}}, -{/*.val =*/{0xe18490, 0x24a059d8, 0x88ffb70, 0x2b761bcb, 0x30b0a57c, 0x3999c46, 0x2414554e, 0x30ac9bd1, 0xd20}}, -{/*.val =*/{0x70c248, 0x12502cec, 0x2447fdb8, 0x15bb0de5, 0x185852be, 0x1ccce23, 0x320a2aa7, 0x18564de8, 0x690}}, -{/*.val =*/{0x386124, 0x9281676, 0x3223fedc, 0xadd86f2, 0x2c2c295f, 0x20e66711, 0x19051553, 0xc2b26f4, 0x348}}, -{/*.val =*/{0x1c3092, 0x4940b3b, 0x1911ff6e, 0x256ec379, 0x361614af, 0x30733388, 0xc828aa9, 0x615937a, 0x1a4}}, -{/*.val =*/{0x200e1849, 0x24a059d, 0x2c88ffb7, 0x32b761bc, 0x1b0b0a57, 0x383999c4, 0x6414554, 0x30ac9bd, 0xd2}}, -{/*.val =*/{0x30070a3c, 0x212502cc, 0x16447fdb, 0x395bb0de, 0xd85852b, 0x1c1ccce2, 0x2320a2aa, 0x18564de, 0x8069}}, -{/*.val =*/{0x1803851e, 0x30928166, 0xb223fed, 0x3cadd86f, 0x6c2c295, 0xe0e6671, 0x11905155, 0x20c2b26f, 0x4034}}, -{/*.val =*/{0xc01c28f, 0x384940b3, 0x25911ff6, 0x3e56ec37, 0x2361614a, 0x27073338, 0x28c828aa, 0x10615937, 0x201a}}, -{/*.val =*/{0x2600df5f, 0x1c24a057, 0x32c88ffb, 0x1f2b761b, 0x11b0b0a5, 0x1383999c, 0x34641455, 0x830ac9b, 0x900d}}, -{/*.val =*/{0x33006dc7, 0x2e125029, 0x396447fd, 0x2f95bb0d, 0x8d85852, 0x29c1ccce, 0x3a320a2a, 0x2418564d, 0xc806}}, -{/*.val =*/{0x398034fb, 0x37092812, 0x3cb223fe, 0x17cadd86, 0x46c2c29, 0x14e0e667, 0x3d190515, 0x120c2b26, 0xe403}}, -{/*.val =*/{0x1cc01895, 0x1b849407, 0x1e5911ff, 0x2be56ec3, 0x22361614, 0x2a707333, 0x1e8c828a, 0x29061593, 0xf201}}, -{/*.val =*/{0x2e600a62, 0x2dc24a01, 0x2f2c88ff, 0x15f2b761, 0x311b0b0a, 0x15383999, 0x2f464145, 0x34830ac9, 0xf900}}, -{/*.val =*/{0x37300531, 0x36e12500, 0x3796447f, 0xaf95bb0, 0x388d8585, 0x2a9c1ccc, 0x37a320a2, 0x1a418564, 0x7c80}}, -{/*.val =*/{0x1b9800b0, 0x3b70927e, 0x1bcb223f, 0x257cadd8, 0x1c46c2c2, 0x154e0e66, 0x1bd19051, 0xd20c2b2, 0xbe40}}, -{/*.val =*/{0xdcc0058, 0x3db8493f, 0xde5911f, 0x12be56ec, 0xe236161, 0x2aa70733, 0xde8c828, 0x6906159, 0x5f20}}, -{/*.val =*/{0x26e6002c, 0x3edc249f, 0x6f2c88f, 0x295f2b76, 0x2711b0b0, 0x15538399, 0x26f46414, 0x34830ac, 0x2f90}}, -{/*.val =*/{0x33730016, 0x3f6e124f, 0x3796447, 0x14af95bb, 0x3388d858, 0xaa9c1cc, 0x137a320a, 0x1a41856, 0x17c8}}, -{/*.val =*/{0x39b9800b, 0x3fb70927, 0x21bcb223, 0xa57cadd, 0x19c46c2c, 0x554e0e6, 0x9bd1905, 0xd20c2b, 0xbe4}}, -{/*.val =*/{0x3cdcbe1d, 0x3fdb8491, 0x30de5911, 0x52be56e, 0xce23616, 0x22aa7073, 0x24de8c82, 0x690615, 0x85f2}}, -{/*.val =*/{0x3e6e5d26, 0x3fedc246, 0x186f2c88, 0x295f2b7, 0x26711b0b, 0x11553839, 0x326f4641, 0x34830a, 0xc2f9}}, -{/*.val =*/{0x1f372e93, 0x1ff6e123, 0x2c379644, 0x214af95b, 0x33388d85, 0x28aa9c1c, 0x1937a320, 0x201a4185, 0x617c}}, -{/*.val =*/{0x2f9b9561, 0xffb708f, 0x361bcb22, 0x30a57cad, 0x199c46c2, 0x14554e0e, 0x2c9bd190, 0x100d20c2, 0xb0be}}, -{/*.val =*/{0x37cdc8c8, 0x7fdb845, 0x3b0de591, 0x1852be56, 0xcce2361, 0xa2aa707, 0x164de8c8, 0x8069061, 0xd85f}}, -{/*.val =*/{0x3be6e464, 0x23fedc22, 0x1d86f2c8, 0x2c295f2b, 0x266711b0, 0x5155383, 0x2b26f464, 0x24034830, 0x6c2f}}, -{/*.val =*/{0x1df37232, 0x11ff6e11, 0x2ec37964, 0x1614af95, 0x333388d8, 0x28aa9c1, 0x15937a32, 0x3201a418, 0x3617}}, -{/*.val =*/{0x2ef9b919, 0x8ffb708, 0x3761bcb2, 0xb0a57ca, 0x3999c46c, 0x14554e0, 0xac9bd19, 0x3900d20c, 0x1b0b}}, -{/*.val =*/{0x177cdaa4, 0x47fdb82, 0x1bb0de59, 0x5852be5, 0x1ccce236, 0x20a2aa70, 0x564de8c, 0x3c806906, 0x8d85}}, -{/*.val =*/{0xbbe6d52, 0x223fedc1, 0x2dd86f2c, 0x2c295f2, 0xe66711b, 0x10515538, 0x2b26f46, 0x3e403483, 0x46c2}}, -{/*.val =*/{0x25df36a9, 0x111ff6e0, 0x16ec3796, 0x21614af9, 0x733388d, 0x828aa9c, 0x215937a3, 0x1f201a41, 0x2361}}, -{/*.val =*/{0x12ef996c, 0x88ffb6e, 0x2b761bcb, 0x30b0a57c, 0x3999c46, 0x2414554e, 0x30ac9bd1, 0x2f900d20, 0x91b0}}, -{/*.val =*/{0x977ccb6, 0x2447fdb7, 0x15bb0de5, 0x185852be, 0x1ccce23, 0x320a2aa7, 0x18564de8, 0x17c80690, 0x48d8}}, -{/*.val =*/{0x24bbe65b, 0x3223fedb, 0xadd86f2, 0x2c2c295f, 0x20e66711, 0x19051553, 0xc2b26f4, 0xbe40348, 0x246c}}, -{/*.val =*/{0x325df145, 0x1911ff6b, 0x256ec379, 0x361614af, 0x30733388, 0xc828aa9, 0x615937a, 0x5f201a4, 0x9236}}, -{/*.val =*/{0x392ef6ba, 0x2c88ffb3, 0x32b761bc, 0x1b0b0a57, 0x383999c4, 0x6414554, 0x30ac9bd, 0x2f900d2, 0xc91b}}, -{/*.val =*/{0x3c977b5d, 0x16447fd9, 0x395bb0de, 0xd85852b, 0x1c1ccce2, 0x2320a2aa, 0x18564de, 0x217c8069, 0x648d}}, -{/*.val =*/{0x3e4bbbc6, 0xb223fea, 0x3cadd86f, 0x6c2c295, 0xe0e6671, 0x11905155, 0x20c2b26f, 0x30be4034, 0xb246}}, -{/*.val =*/{0x1f25dde3, 0x25911ff5, 0x3e56ec37, 0x2361614a, 0x27073338, 0x28c828aa, 0x10615937, 0x185f201a, 0x5923}}, -{/*.val =*/{0x2f92ed09, 0x32c88ff8, 0x1f2b761b, 0x11b0b0a5, 0x1383999c, 0x34641455, 0x830ac9b, 0x2c2f900d, 0xac91}}, -{/*.val =*/{0x17c9749c, 0x396447fa, 0x2f95bb0d, 0x8d85852, 0x29c1ccce, 0x3a320a2a, 0x2418564d, 0x3617c806, 0xd648}}, -{/*.val =*/{0xbe4ba4e, 0x3cb223fd, 0x17cadd86, 0x46c2c29, 0x14e0e667, 0x3d190515, 0x120c2b26, 0x1b0be403, 0x6b24}}, -{/*.val =*/{0x25f25d27, 0x1e5911fe, 0x2be56ec3, 0x22361614, 0x2a707333, 0x1e8c828a, 0x29061593, 0xd85f201, 0x3592}}, -{/*.val =*/{0x12f92cab, 0x2f2c88fd, 0x15f2b761, 0x311b0b0a, 0x15383999, 0x2f464145, 0x34830ac9, 0x6c2f900, 0x9ac9}}, -{/*.val =*/{0x297c946d, 0x3796447c, 0xaf95bb0, 0x388d8585, 0x2a9c1ccc, 0x37a320a2, 0x1a418564, 0x23617c80, 0xcd64}}, -{/*.val =*/{0x14be484e, 0x1bcb223c, 0x257cadd8, 0x1c46c2c2, 0x154e0e66, 0x1bd19051, 0xd20c2b2, 0x11b0be40, 0xe6b2}}, -{/*.val =*/{0xa5f2427, 0xde5911e, 0x12be56ec, 0xe236161, 0x2aa70733, 0xde8c828, 0x6906159, 0x8d85f20, 0x7359}}, -{/*.val =*/{0x52f902b, 0x6f2c88d, 0x295f2b76, 0x2711b0b0, 0x15538399, 0x26f46414, 0x34830ac, 0x246c2f90, 0xb9ac}}, -{/*.val =*/{0x2297c62d, 0x3796444, 0x14af95bb, 0x3388d858, 0xaa9c1cc, 0x137a320a, 0x1a41856, 0x123617c8, 0xdcd6}}, -{/*.val =*/{0x114be12e, 0x21bcb220, 0xa57cadd, 0x19c46c2c, 0x554e0e6, 0x9bd1905, 0xd20c2b, 0x91b0be4, 0xee6b}}, -{/*.val =*/{0x8a5f097, 0x30de5910, 0x52be56e, 0xce23616, 0x22aa7073, 0x24de8c82, 0x690615, 0x248d85f2, 0x7735}}, -{/*.val =*/{0x452f663, 0x186f2c86, 0x295f2b7, 0x26711b0b, 0x11553839, 0x326f4641, 0x34830a, 0x3246c2f9, 0xbb9a}}, -{/*.val =*/{0x2297949, 0x2c379641, 0x214af95b, 0x33388d85, 0x28aa9c1c, 0x1937a320, 0x201a4185, 0x1923617c, 0xddcd}}, -{/*.val =*/{0x2114babc, 0x361bcb1e, 0x30a57cad, 0x199c46c2, 0x14554e0e, 0x2c9bd190, 0x100d20c2, 0x2c91b0be, 0xeee6}}, -{/*.val =*/{0x108a5d5e, 0x3b0de58f, 0x1852be56, 0xcce2361, 0xa2aa707, 0x164de8c8, 0x8069061, 0x1648d85f, 0x7773}}, -{/*.val =*/{0x28452eaf, 0x1d86f2c7, 0x2c295f2b, 0x266711b0, 0x5155383, 0x2b26f464, 0x24034830, 0x2b246c2f, 0x3bb9}}, -{/*.val =*/{0x3422956f, 0x2ec37961, 0x1614af95, 0x333388d8, 0x28aa9c1, 0x15937a32, 0x3201a418, 0x35923617, 0x9ddc}}, -{/*.val =*/{0x3a1148cf, 0x3761bcae, 0xb0a57ca, 0x3999c46c, 0x14554e0, 0xac9bd19, 0x3900d20c, 0x1ac91b0b, 0xceee}}, -{/*.val =*/{0x1d08a27f, 0x1bb0de55, 0x5852be5, 0x1ccce236, 0x20a2aa70, 0x564de8c, 0x3c806906, 0xd648d85, 0xe777}}, -{/*.val =*/{0x2e844f57, 0x2dd86f28, 0x2c295f2, 0xe66711b, 0x10515538, 0x2b26f46, 0x3e403483, 0x26b246c2, 0xf3bb}}, -{/*.val =*/{0x174225c3, 0x16ec3792, 0x21614af9, 0x733388d, 0x828aa9c, 0x215937a3, 0x1f201a41, 0x33592361, 0xf9dd}}, -{/*.val =*/{0xba110f9, 0x2b761bc7, 0x30b0a57c, 0x3999c46, 0x2414554e, 0x30ac9bd1, 0x2f900d20, 0x39ac91b0, 0xfcee}}, -{/*.val =*/{0x25d08694, 0x15bb0de1, 0x185852be, 0x1ccce23, 0x320a2aa7, 0x18564de8, 0x17c80690, 0x1cd648d8, 0xfe77}}, -{/*.val =*/{0x32e8434a, 0xadd86f0, 0x2c2c295f, 0x20e66711, 0x19051553, 0xc2b26f4, 0xbe40348, 0x2e6b246c, 0x7f3b}}, -{/*.val =*/{0x197421a5, 0x256ec378, 0x361614af, 0x30733388, 0xc828aa9, 0x615937a, 0x5f201a4, 0x37359236, 0x3f9d}}, -{/*.val =*/{0xcba0eea, 0x32b761ba, 0x1b0b0a57, 0x383999c4, 0x6414554, 0x30ac9bd, 0x2f900d2, 0x3b9ac91b, 0x9fce}}, -{/*.val =*/{0x65d0775, 0x395bb0dd, 0xd85852b, 0x1c1ccce2, 0x2320a2aa, 0x18564de, 0x217c8069, 0x1dcd648d, 0x4fe7}}, -{/*.val =*/{0x232e81d2, 0x3cadd86c, 0x6c2c295, 0xe0e6671, 0x11905155, 0x20c2b26f, 0x30be4034, 0x2ee6b246, 0xa7f3}}, -{/*.val =*/{0x119740e9, 0x3e56ec36, 0x2361614a, 0x27073338, 0x28c828aa, 0x10615937, 0x185f201a, 0x37735923, 0x53f9}}, -{/*.val =*/{0x8cb9e8c, 0x1f2b7619, 0x11b0b0a5, 0x1383999c, 0x34641455, 0x830ac9b, 0x2c2f900d, 0x3bb9ac91, 0xa9fc}}, -{/*.val =*/{0x2465cf46, 0x2f95bb0c, 0x8d85852, 0x29c1ccce, 0x3a320a2a, 0x2418564d, 0x3617c806, 0x1ddcd648, 0x54fe}}, -{/*.val =*/{0x1232e7a3, 0x17cadd86, 0x46c2c29, 0x14e0e667, 0x3d190515, 0x120c2b26, 0x1b0be403, 0xeee6b24, 0x2a7f}}, -{/*.val =*/{0x91971e9, 0x2be56ec1, 0x22361614, 0x2a707333, 0x1e8c828a, 0x29061593, 0xd85f201, 0x27773592, 0x953f}}, -{/*.val =*/{0x248cb70c, 0x15f2b75e, 0x311b0b0a, 0x15383999, 0x2f464145, 0x34830ac9, 0x6c2f900, 0x33bb9ac9, 0xca9f}}, -{/*.val =*/{0x12465b86, 0xaf95baf, 0x388d8585, 0x2a9c1ccc, 0x37a320a2, 0x1a418564, 0x23617c80, 0x39ddcd64, 0x654f}}, -{/*.val =*/{0x29232dc3, 0x257cadd7, 0x1c46c2c2, 0x154e0e66, 0x1bd19051, 0xd20c2b2, 0x11b0be40, 0x3ceee6b2, 0x32a7}}, -{/*.val =*/{0x349194f9, 0x12be56e9, 0xe236161, 0x2aa70733, 0xde8c828, 0x6906159, 0x8d85f20, 0x3e777359, 0x9953}}, -{/*.val =*/{0x3a48c894, 0x295f2b72, 0x2711b0b0, 0x15538399, 0x26f46414, 0x34830ac, 0x246c2f90, 0x3f3bb9ac, 0xcca9}}, -{/*.val =*/{0x1d24644a, 0x14af95b9, 0x3388d858, 0xaa9c1cc, 0x137a320a, 0x1a41856, 0x123617c8, 0x3f9ddcd6, 0x6654}}, -{/*.val =*/{0x2e923225, 0xa57cadc, 0x19c46c2c, 0x554e0e6, 0x9bd1905, 0xd20c2b, 0x91b0be4, 0x1fceee6b, 0x332a}}, -{/*.val =*/{0x1749172a, 0x52be56c, 0xce23616, 0x22aa7073, 0x24de8c82, 0x690615, 0x248d85f2, 0xfe77735, 0x9995}}, -{/*.val =*/{0xba48b95, 0x295f2b6, 0x26711b0b, 0x11553839, 0x326f4641, 0x34830a, 0x3246c2f9, 0x27f3bb9a, 0x4cca}}, -{/*.val =*/{0x5d243e2, 0x214af959, 0x33388d85, 0x28aa9c1c, 0x1937a320, 0x201a4185, 0x1923617c, 0x13f9ddcd, 0xa665}}, -{/*.val =*/{0x22e921f1, 0x30a57cac, 0x199c46c2, 0x14554e0e, 0x2c9bd190, 0x100d20c2, 0x2c91b0be, 0x29fceee6, 0x5332}}, -{/*.val =*/{0x11748f10, 0x1852be54, 0xcce2361, 0xa2aa707, 0x164de8c8, 0x8069061, 0x1648d85f, 0x14fe7773, 0xa999}}, -{/*.val =*/{0x8ba4788, 0x2c295f2a, 0x266711b0, 0x5155383, 0x2b26f464, 0x24034830, 0x2b246c2f, 0x2a7f3bb9, 0x54cc}}, -{/*.val =*/{0x45d23c4, 0x1614af95, 0x333388d8, 0x28aa9c1, 0x15937a32, 0x3201a418, 0x35923617, 0x153f9ddc, 0x2a66}}, -{/*.val =*/{0x222e91e2, 0xb0a57ca, 0x3999c46c, 0x14554e0, 0xac9bd19, 0x3900d20c, 0x1ac91b0b, 0xa9fceee, 0x1533}}, -{/*.val =*/{0x111748f1, 0x5852be5, 0x1ccce236, 0x20a2aa70, 0x564de8c, 0x3c806906, 0xd648d85, 0x254fe777, 0xa99}}, -{/*.val =*/{0x288ba290, 0x2c295f0, 0xe66711b, 0x10515538, 0x2b26f46, 0x3e403483, 0x26b246c2, 0x32a7f3bb, 0x854c}}, -{/*.val =*/{0x1445d148, 0x21614af8, 0x733388d, 0x828aa9c, 0x215937a3, 0x1f201a41, 0x33592361, 0x1953f9dd, 0x42a6}}, -{/*.val =*/{0xa22e8a4, 0x30b0a57c, 0x3999c46, 0x2414554e, 0x30ac9bd1, 0x2f900d20, 0x39ac91b0, 0xca9fcee, 0x2153}}, -{/*.val =*/{0x5117452, 0x185852be, 0x1ccce23, 0x320a2aa7, 0x18564de8, 0x17c80690, 0x1cd648d8, 0x2654fe77, 0x10a9}}, -{/*.val =*/{0x288ba29, 0x2c2c295f, 0x20e66711, 0x19051553, 0xc2b26f4, 0xbe40348, 0x2e6b246c, 0x332a7f3b, 0x854}}, -{/*.val =*/{0x21445b2c, 0x361614ad, 0x30733388, 0xc828aa9, 0x615937a, 0x5f201a4, 0x37359236, 0x19953f9d, 0x842a}}, -{/*.val =*/{0x30a22d96, 0x1b0b0a56, 0x383999c4, 0x6414554, 0x30ac9bd, 0x2f900d2, 0x3b9ac91b, 0xcca9fce, 0x4215}}, -{/*.val =*/{0x185116cb, 0xd85852b, 0x1c1ccce2, 0x2320a2aa, 0x18564de, 0x217c8069, 0x1dcd648d, 0x26654fe7, 0x210a}}, -{/*.val =*/{0x2c28897d, 0x6c2c293, 0xe0e6671, 0x11905155, 0x20c2b26f, 0x30be4034, 0x2ee6b246, 0x1332a7f3, 0x9085}}, -{/*.val =*/{0x361442d6, 0x23616147, 0x27073338, 0x28c828aa, 0x10615937, 0x185f201a, 0x37735923, 0x299953f9, 0xc842}}, -{/*.val =*/{0x3b0a216b, 0x11b0b0a3, 0x1383999c, 0x34641455, 0x830ac9b, 0x2c2f900d, 0x3bb9ac91, 0x14cca9fc, 0x6421}}, -{/*.val =*/{0x3d850ecd, 0x8d8584f, 0x29c1ccce, 0x3a320a2a, 0x2418564d, 0x3617c806, 0x1ddcd648, 0x2a6654fe, 0xb210}}, -{/*.val =*/{0x3ec2857e, 0x46c2c25, 0x14e0e667, 0x3d190515, 0x120c2b26, 0x1b0be403, 0xeee6b24, 0x15332a7f, 0xd908}}, -{/*.val =*/{0x3f6142bf, 0x22361612, 0x2a707333, 0x1e8c828a, 0x29061593, 0xd85f201, 0x27773592, 0xa99953f, 0x6c84}}, -{/*.val =*/{0x1fb09f77, 0x311b0b07, 0x15383999, 0x2f464145, 0x34830ac9, 0x6c2f900, 0x33bb9ac9, 0x54cca9f, 0xb642}}, -{/*.val =*/{0x2fd84dd3, 0x388d8581, 0x2a9c1ccc, 0x37a320a2, 0x1a418564, 0x23617c80, 0x39ddcd64, 0x2a6654f, 0xdb21}}, -{/*.val =*/{0x37ec2501, 0x1c46c2be, 0x154e0e66, 0x1bd19051, 0xd20c2b2, 0x11b0be40, 0x3ceee6b2, 0x215332a7, 0xed90}}, -{/*.val =*/{0x1bf61098, 0xe23615d, 0x2aa70733, 0xde8c828, 0x6906159, 0x8d85f20, 0x3e777359, 0x10a99953, 0xf6c8}}, -{/*.val =*/{0x2dfb084c, 0x2711b0ae, 0x15538399, 0x26f46414, 0x34830ac, 0x246c2f90, 0x3f3bb9ac, 0x854cca9, 0x7b64}}, -{/*.val =*/{0x16fd8426, 0x3388d857, 0xaa9c1cc, 0x137a320a, 0x1a41856, 0x123617c8, 0x3f9ddcd6, 0x42a6654, 0x3db2}}, -{/*.val =*/{0x2b7ec213, 0x19c46c2b, 0x554e0e6, 0x9bd1905, 0xd20c2b, 0x91b0be4, 0x1fceee6b, 0x215332a, 0x1ed9}}, -{/*.val =*/{0x35bf5f21, 0xce23613, 0x22aa7073, 0x24de8c82, 0x690615, 0x248d85f2, 0xfe77735, 0x210a9995, 0x8f6c}}, -{/*.val =*/{0x3adfada8, 0x26711b07, 0x11553839, 0x326f4641, 0x34830a, 0x3246c2f9, 0x27f3bb9a, 0x10854cca, 0xc7b6}}, -{/*.val =*/{0x3d6fd6d4, 0x33388d83, 0x28aa9c1c, 0x1937a320, 0x201a4185, 0x1923617c, 0x13f9ddcd, 0x842a665, 0x63db}}, -{/*.val =*/{0x3eb7eb6a, 0x199c46c1, 0x14554e0e, 0x2c9bd190, 0x100d20c2, 0x2c91b0be, 0x29fceee6, 0x24215332, 0x31ed}}, -{/*.val =*/{0x3f5bf5b5, 0xcce2360, 0xa2aa707, 0x164de8c8, 0x8069061, 0x1648d85f, 0x14fe7773, 0x3210a999, 0x18f6}}, -{/*.val =*/{0x1fadf8f2, 0x266711ae, 0x5155383, 0x2b26f464, 0x24034830, 0x2b246c2f, 0x2a7f3bb9, 0x190854cc, 0x8c7b}}, -{/*.val =*/{0xfd6fc79, 0x333388d7, 0x28aa9c1, 0x15937a32, 0x3201a418, 0x35923617, 0x153f9ddc, 0x2c842a66, 0x463d}}, -{/*.val =*/{0x27eb7c54, 0x3999c469, 0x14554e0, 0xac9bd19, 0x3900d20c, 0x1ac91b0b, 0xa9fceee, 0x36421533, 0xa31e}}, -{/*.val =*/{0x33f5be2a, 0x1ccce234, 0x20a2aa70, 0x564de8c, 0x3c806906, 0xd648d85, 0x254fe777, 0x1b210a99, 0x518f}}, -{/*.val =*/{0x19fadf15, 0xe66711a, 0x10515538, 0x2b26f46, 0x3e403483, 0x26b246c2, 0x32a7f3bb, 0x2d90854c, 0x28c7}}, -{/*.val =*/{0xcfd6da2, 0x733388b, 0x828aa9c, 0x215937a3, 0x1f201a41, 0x33592361, 0x1953f9dd, 0x36c842a6, 0x9463}}, -{/*.val =*/{0x267eb6d1, 0x3999c45, 0x2414554e, 0x30ac9bd1, 0x2f900d20, 0x39ac91b0, 0xca9fcee, 0x3b642153, 0x4a31}}, -{/*.val =*/{0x333f5980, 0x1ccce20, 0x320a2aa7, 0x18564de8, 0x17c80690, 0x1cd648d8, 0x2654fe77, 0x3db210a9, 0xa518}}, -{/*.val =*/{0x199facc0, 0x20e66710, 0x19051553, 0xc2b26f4, 0xbe40348, 0x2e6b246c, 0x332a7f3b, 0x1ed90854, 0x528c}}, -{/*.val =*/{0xccfd660, 0x30733388, 0xc828aa9, 0x615937a, 0x5f201a4, 0x37359236, 0x19953f9d, 0xf6c842a, 0x2946}}, -{/*.val =*/{0x667eb30, 0x383999c4, 0x6414554, 0x30ac9bd, 0x2f900d2, 0x3b9ac91b, 0xcca9fce, 0x7b64215, 0x14a3}}, -{/*.val =*/{0x333f598, 0x1c1ccce2, 0x2320a2aa, 0x18564de, 0x217c8069, 0x1dcd648d, 0x26654fe7, 0x23db210a, 0xa51}}, -{/*.val =*/{0x199facc, 0xe0e6671, 0x11905155, 0x20c2b26f, 0x30be4034, 0x2ee6b246, 0x1332a7f3, 0x31ed9085, 0x528}}, -{/*.val =*/{0x20ccfd66, 0x27073338, 0x28c828aa, 0x10615937, 0x185f201a, 0x37735923, 0x299953f9, 0x18f6c842, 0x294}}, -{/*.val =*/{0x10667eb3, 0x1383999c, 0x34641455, 0x830ac9b, 0x2c2f900d, 0x3bb9ac91, 0x14cca9fc, 0xc7b6421, 0x14a}}, -{/*.val =*/{0x8333d71, 0x29c1cccc, 0x3a320a2a, 0x2418564d, 0x3617c806, 0x1ddcd648, 0x2a6654fe, 0x63db210, 0x80a5}}, -{/*.val =*/{0x4199cd0, 0x14e0e664, 0x3d190515, 0x120c2b26, 0x1b0be403, 0xeee6b24, 0x15332a7f, 0x231ed908, 0xc052}}, -{/*.val =*/{0x20cce68, 0x2a707332, 0x1e8c828a, 0x29061593, 0xd85f201, 0x27773592, 0xa99953f, 0x118f6c84, 0x6029}}, -{/*.val =*/{0x1066734, 0x15383999, 0x2f464145, 0x34830ac9, 0x6c2f900, 0x33bb9ac9, 0x54cca9f, 0x28c7b642, 0x3014}}, -{/*.val =*/{0x2083339a, 0x2a9c1ccc, 0x37a320a2, 0x1a418564, 0x23617c80, 0x39ddcd64, 0x2a6654f, 0x1463db21, 0x180a}}, -{/*.val =*/{0x104199cd, 0x154e0e66, 0x1bd19051, 0xd20c2b2, 0x11b0be40, 0x3ceee6b2, 0x215332a7, 0xa31ed90, 0xc05}}, -{/*.val =*/{0x820cafe, 0x2aa70731, 0xde8c828, 0x6906159, 0x8d85f20, 0x3e777359, 0x10a99953, 0x2518f6c8, 0x8602}}, -{/*.val =*/{0x2410657f, 0x15538398, 0x26f46414, 0x34830ac, 0x246c2f90, 0x3f3bb9ac, 0x854cca9, 0x128c7b64, 0x4301}}, -{/*.val =*/{0x120830d7, 0xaa9c1ca, 0x137a320a, 0x1a41856, 0x123617c8, 0x3f9ddcd6, 0x42a6654, 0x29463db2, 0xa180}}, -{/*.val =*/{0x9041683, 0x554e0e3, 0x9bd1905, 0xd20c2b, 0x91b0be4, 0x1fceee6b, 0x215332a, 0x14a31ed9, 0xd0c0}}, -{/*.val =*/{0x24820959, 0x22aa706f, 0x24de8c82, 0x690615, 0x248d85f2, 0xfe77735, 0x210a9995, 0xa518f6c, 0xe860}}, -{/*.val =*/{0x324102c4, 0x11553835, 0x326f4641, 0x34830a, 0x3246c2f9, 0x27f3bb9a, 0x10854cca, 0x528c7b6, 0xf430}}, -{/*.val =*/{0x39208162, 0x28aa9c1a, 0x1937a320, 0x201a4185, 0x1923617c, 0x13f9ddcd, 0x842a665, 0x29463db, 0x7a18}}, -{/*.val =*/{0x1c9040b1, 0x14554e0d, 0x2c9bd190, 0x100d20c2, 0x2c91b0be, 0x29fceee6, 0x24215332, 0x14a31ed, 0x3d0c}}, -{/*.val =*/{0x2e481e70, 0xa2aa704, 0x164de8c8, 0x8069061, 0x1648d85f, 0x14fe7773, 0x3210a999, 0xa518f6, 0x9e86}}, -{/*.val =*/{0x17240f38, 0x5155382, 0x2b26f464, 0x24034830, 0x2b246c2f, 0x2a7f3bb9, 0x190854cc, 0x528c7b, 0x4f43}}, -{/*.val =*/{0xb92079c, 0x28aa9c1, 0x15937a32, 0x3201a418, 0x35923617, 0x153f9ddc, 0x2c842a66, 0x2029463d, 0x27a1}}, -{/*.val =*/{0x25c903ce, 0x14554e0, 0xac9bd19, 0x3900d20c, 0x1ac91b0b, 0xa9fceee, 0x36421533, 0x3014a31e, 0x13d0}}, -{/*.val =*/{0x12e481e7, 0x20a2aa70, 0x564de8c, 0x3c806906, 0xd648d85, 0x254fe777, 0x1b210a99, 0x180a518f, 0x9e8}}, -{/*.val =*/{0x9723f0b, 0x10515536, 0x2b26f46, 0x3e403483, 0x26b246c2, 0x32a7f3bb, 0x2d90854c, 0xc0528c7, 0x84f4}}, -{/*.val =*/{0x4b91d9d, 0x828aa99, 0x215937a3, 0x1f201a41, 0x33592361, 0x1953f9dd, 0x36c842a6, 0x6029463, 0xc27a}}, -{/*.val =*/{0x225c8ce6, 0x2414554a, 0x30ac9bd1, 0x2f900d20, 0x39ac91b0, 0xca9fcee, 0x3b642153, 0x3014a31, 0xe13d}}, -{/*.val =*/{0x112e4673, 0x320a2aa5, 0x18564de8, 0x17c80690, 0x1cd648d8, 0x2654fe77, 0x3db210a9, 0x2180a518, 0x709e}}, -{/*.val =*/{0x28972151, 0x19051550, 0xc2b26f4, 0xbe40348, 0x2e6b246c, 0x332a7f3b, 0x1ed90854, 0x10c0528c, 0xb84f}}, -{/*.val =*/{0x144b8ec0, 0xc828aa6, 0x615937a, 0x5f201a4, 0x37359236, 0x19953f9d, 0xf6c842a, 0x28602946, 0xdc27}}, -{/*.val =*/{0xa25c760, 0x6414553, 0x30ac9bd, 0x2f900d2, 0x3b9ac91b, 0xcca9fce, 0x7b64215, 0x343014a3, 0x6e13}}, -{/*.val =*/{0x2512e3b0, 0x2320a2a9, 0x18564de, 0x217c8069, 0x1dcd648d, 0x26654fe7, 0x23db210a, 0x3a180a51, 0x3709}}, -{/*.val =*/{0x328971d8, 0x11905154, 0x20c2b26f, 0x30be4034, 0x2ee6b246, 0x1332a7f3, 0x31ed9085, 0x3d0c0528, 0x1b84}}, -{/*.val =*/{0x1944b8ec, 0x28c828aa, 0x10615937, 0x185f201a, 0x37735923, 0x299953f9, 0x18f6c842, 0x1e860294, 0xdc2}}, -{/*.val =*/{0xca25c76, 0x34641455, 0x830ac9b, 0x2c2f900d, 0x3bb9ac91, 0x14cca9fc, 0xc7b6421, 0xf43014a, 0x6e1}}, -{/*.val =*/{0x26512e3b, 0x3a320a2a, 0x2418564d, 0x3617c806, 0x1ddcd648, 0x2a6654fe, 0x63db210, 0x27a180a5, 0x370}}, -{/*.val =*/{0x13289535, 0x3d190513, 0x120c2b26, 0x1b0be403, 0xeee6b24, 0x15332a7f, 0x231ed908, 0x13d0c052, 0x81b8}}, -{/*.val =*/{0x299448b2, 0x1e8c8287, 0x29061593, 0xd85f201, 0x27773592, 0xa99953f, 0x118f6c84, 0x9e86029, 0xc0dc}}, -{/*.val =*/{0x34ca2459, 0x2f464143, 0x34830ac9, 0x6c2f900, 0x33bb9ac9, 0x54cca9f, 0x28c7b642, 0x4f43014, 0x606e}}, -{/*.val =*/{0x3a651044, 0x37a3209f, 0x1a418564, 0x23617c80, 0x39ddcd64, 0x2a6654f, 0x1463db21, 0x27a180a, 0xb037}}, -{/*.val =*/{0x3d328822, 0x1bd1904f, 0xd20c2b2, 0x11b0be40, 0x3ceee6b2, 0x215332a7, 0xa31ed90, 0x213d0c05, 0x581b}}, -{/*.val =*/{0x3e994411, 0xde8c827, 0x6906159, 0x8d85f20, 0x3e777359, 0x10a99953, 0x2518f6c8, 0x309e8602, 0x2c0d}}, -{/*.val =*/{0x3f4ca020, 0x26f46411, 0x34830ac, 0x246c2f90, 0x3f3bb9ac, 0x854cca9, 0x128c7b64, 0x384f4301, 0x9606}}, -{/*.val =*/{0x3fa65010, 0x137a3208, 0x1a41856, 0x123617c8, 0x3f9ddcd6, 0x42a6654, 0x29463db2, 0x1c27a180, 0x4b03}}, -{/*.val =*/{0x1fd32808, 0x9bd1904, 0xd20c2b, 0x91b0be4, 0x1fceee6b, 0x215332a, 0x14a31ed9, 0x2e13d0c0, 0x2581}}, -{/*.val =*/{0xfe99404, 0x24de8c82, 0x690615, 0x248d85f2, 0xfe77735, 0x210a9995, 0xa518f6c, 0x3709e860, 0x12c0}}, -{/*.val =*/{0x7f4ca02, 0x326f4641, 0x34830a, 0x3246c2f9, 0x27f3bb9a, 0x10854cca, 0x528c7b6, 0x1b84f430, 0x960}}, -{/*.val =*/{0x23fa6501, 0x1937a320, 0x201a4185, 0x1923617c, 0x13f9ddcd, 0x842a665, 0x29463db, 0xdc27a18, 0x4b0}}, -{/*.val =*/{0x11fd3098, 0x2c9bd18e, 0x100d20c2, 0x2c91b0be, 0x29fceee6, 0x24215332, 0x14a31ed, 0x6e13d0c, 0x8258}}, -{/*.val =*/{0x8fe984c, 0x164de8c7, 0x8069061, 0x1648d85f, 0x14fe7773, 0x3210a999, 0xa518f6, 0x3709e86, 0x412c}}, -{/*.val =*/{0x247f4c26, 0x2b26f463, 0x24034830, 0x2b246c2f, 0x2a7f3bb9, 0x190854cc, 0x528c7b, 0x1b84f43, 0x2096}}, -{/*.val =*/{0x323fa613, 0x15937a31, 0x3201a418, 0x35923617, 0x153f9ddc, 0x2c842a66, 0x2029463d, 0xdc27a1, 0x104b}}, -{/*.val =*/{0x391fd121, 0xac9bd16, 0x3900d20c, 0x1ac91b0b, 0xa9fceee, 0x36421533, 0x3014a31e, 0x206e13d0, 0x8825}}, -{/*.val =*/{0x1c8fe6a8, 0x564de89, 0x3c806906, 0xd648d85, 0x254fe777, 0x1b210a99, 0x180a518f, 0x303709e8, 0xc412}}, -{/*.val =*/{0x2e47f354, 0x2b26f44, 0x3e403483, 0x26b246c2, 0x32a7f3bb, 0x2d90854c, 0xc0528c7, 0x181b84f4, 0x6209}}, -{/*.val =*/{0x1723f9aa, 0x215937a2, 0x1f201a41, 0x33592361, 0x1953f9dd, 0x36c842a6, 0x6029463, 0x2c0dc27a, 0x3104}}, -{/*.val =*/{0xb91fcd5, 0x30ac9bd1, 0x2f900d20, 0x39ac91b0, 0xca9fcee, 0x3b642153, 0x3014a31, 0x1606e13d, 0x1882}}, -{/*.val =*/{0x25c8fc82, 0x18564de6, 0x17c80690, 0x1cd648d8, 0x2654fe77, 0x3db210a9, 0x2180a518, 0xb03709e, 0x8c41}}, -{/*.val =*/{0x12e47e41, 0xc2b26f3, 0xbe40348, 0x2e6b246c, 0x332a7f3b, 0x1ed90854, 0x10c0528c, 0x2581b84f, 0x4620}}, -{/*.val =*/{0x29723d38, 0x6159377, 0x5f201a4, 0x37359236, 0x19953f9d, 0xf6c842a, 0x28602946, 0x12c0dc27, 0xa310}}, -{/*.val =*/{0x34b91e9c, 0x30ac9bb, 0x2f900d2, 0x3b9ac91b, 0xcca9fce, 0x7b64215, 0x343014a3, 0x9606e13, 0x5188}}, -{/*.val =*/{0x3a5c8f4e, 0x18564dd, 0x217c8069, 0x1dcd648d, 0x26654fe7, 0x23db210a, 0x3a180a51, 0x4b03709, 0x28c4}}, -{/*.val =*/{0x3d2e47a7, 0x20c2b26e, 0x30be4034, 0x2ee6b246, 0x1332a7f3, 0x31ed9085, 0x3d0c0528, 0x2581b84, 0x1462}}, -{/*.val =*/{0x1e9721eb, 0x10615935, 0x185f201a, 0x37735923, 0x299953f9, 0x18f6c842, 0x1e860294, 0x12c0dc2, 0x8a31}}, -{/*.val =*/{0x2f4b8f0d, 0x830ac98, 0x2c2f900d, 0x3bb9ac91, 0x14cca9fc, 0xc7b6421, 0xf43014a, 0x209606e1, 0xc518}}, -{/*.val =*/{0x17a5c59e, 0x2418564a, 0x3617c806, 0x1ddcd648, 0x2a6654fe, 0x63db210, 0x27a180a5, 0x104b0370, 0xe28c}}, -{/*.val =*/{0xbd2e2cf, 0x120c2b25, 0x1b0be403, 0xeee6b24, 0x15332a7f, 0x231ed908, 0x13d0c052, 0x82581b8, 0x7146}}, -{/*.val =*/{0x25e96f7f, 0x29061590, 0xd85f201, 0x27773592, 0xa99953f, 0x118f6c84, 0x9e86029, 0x412c0dc, 0xb8a3}}, -{/*.val =*/{0x12f4b5d7, 0x34830ac6, 0x6c2f900, 0x33bb9ac9, 0x54cca9f, 0x28c7b642, 0x4f43014, 0x2209606e, 0xdc51}}, -{/*.val =*/{0x97a5903, 0x1a418561, 0x23617c80, 0x39ddcd64, 0x2a6654f, 0x1463db21, 0x27a180a, 0x3104b037, 0xee28}}, -{/*.val =*/{0x24bd2a99, 0xd20c2ae, 0x11b0be40, 0x3ceee6b2, 0x215332a7, 0xa31ed90, 0x213d0c05, 0x1882581b, 0xf714}}, -{/*.val =*/{0x125e9364, 0x6906155, 0x8d85f20, 0x3e777359, 0x10a99953, 0x2518f6c8, 0x309e8602, 0xc412c0d, 0xfb8a}}, -{/*.val =*/{0x292f49b2, 0x34830aa, 0x246c2f90, 0x3f3bb9ac, 0x854cca9, 0x128c7b64, 0x384f4301, 0x6209606, 0x7dc5}}, -{/*.val =*/{0x1497a4d9, 0x1a41855, 0x123617c8, 0x3f9ddcd6, 0x42a6654, 0x29463db2, 0x1c27a180, 0x23104b03, 0x3ee2}}, -{/*.val =*/{0x2a4bd084, 0xd20c28, 0x91b0be4, 0x1fceee6b, 0x215332a, 0x14a31ed9, 0x2e13d0c0, 0x11882581, 0x9f71}}, -{/*.val =*/{0x1525e842, 0x690614, 0x248d85f2, 0xfe77735, 0x210a9995, 0xa518f6c, 0x3709e860, 0x28c412c0, 0x4fb8}}, -{/*.val =*/{0xa92f421, 0x34830a, 0x3246c2f9, 0x27f3bb9a, 0x10854cca, 0x528c7b6, 0x1b84f430, 0x14620960, 0x27dc}}, -{/*.val =*/{0x5497828, 0x201a4183, 0x1923617c, 0x13f9ddcd, 0x842a665, 0x29463db, 0xdc27a18, 0xa3104b0, 0x93ee}}, -{/*.val =*/{0x22a4bc14, 0x100d20c1, 0x2c91b0be, 0x29fceee6, 0x24215332, 0x14a31ed, 0x6e13d0c, 0x5188258, 0x49f7}}, -{/*.val =*/{0x31525e0a, 0x8069060, 0x1648d85f, 0x14fe7773, 0x3210a999, 0xa518f6, 0x3709e86, 0x228c412c, 0x24fb}}, -{/*.val =*/{0x18a92f05, 0x24034830, 0x2b246c2f, 0x2a7f3bb9, 0x190854cc, 0x528c7b, 0x1b84f43, 0x31462096, 0x127d}}, -{/*.val =*/{0xc54959a, 0x3201a416, 0x35923617, 0x153f9ddc, 0x2c842a66, 0x2029463d, 0xdc27a1, 0x38a3104b, 0x893e}}, -{/*.val =*/{0x62a4acd, 0x3900d20b, 0x1ac91b0b, 0xa9fceee, 0x36421533, 0x3014a31e, 0x206e13d0, 0x1c518825, 0x449f}}, -{/*.val =*/{0x2315237e, 0x3c806903, 0xd648d85, 0x254fe777, 0x1b210a99, 0x180a518f, 0x303709e8, 0x2e28c412, 0xa24f}}, -{/*.val =*/{0x318a91bf, 0x3e403481, 0x26b246c2, 0x32a7f3bb, 0x2d90854c, 0xc0528c7, 0x181b84f4, 0x37146209, 0x5127}}, -{/*.val =*/{0x38c546f7, 0x1f201a3e, 0x33592361, 0x1953f9dd, 0x36c842a6, 0x6029463, 0x2c0dc27a, 0x3b8a3104, 0xa893}}, -{/*.val =*/{0x1c62a193, 0x2f900d1d, 0x39ac91b0, 0xca9fcee, 0x3b642153, 0x3014a31, 0x1606e13d, 0x3dc51882, 0xd449}}, -{/*.val =*/{0x2e314ee1, 0x17c8068c, 0x1cd648d8, 0x2654fe77, 0x3db210a9, 0x2180a518, 0xb03709e, 0x3ee28c41, 0xea24}}, -{/*.val =*/{0x1718a588, 0xbe40344, 0x2e6b246c, 0x332a7f3b, 0x1ed90854, 0x10c0528c, 0x2581b84f, 0x1f714620, 0xf512}}, -{/*.val =*/{0xb8c52c4, 0x5f201a2, 0x37359236, 0x19953f9d, 0xf6c842a, 0x28602946, 0x12c0dc27, 0xfb8a310, 0x7a89}}, -{/*.val =*/{0x5c62962, 0x2f900d1, 0x3b9ac91b, 0xcca9fce, 0x7b64215, 0x343014a3, 0x9606e13, 0x27dc5188, 0x3d44}}, -{/*.val =*/{0x22e314b1, 0x217c8068, 0x1dcd648d, 0x26654fe7, 0x23db210a, 0x3a180a51, 0x4b03709, 0x13ee28c4, 0x1ea2}}, -{/*.val =*/{0x11718870, 0x30be4032, 0x2ee6b246, 0x1332a7f3, 0x31ed9085, 0x3d0c0528, 0x2581b84, 0x9f71462, 0x8f51}}, -{/*.val =*/{0x8b8c438, 0x185f2019, 0x37735923, 0x299953f9, 0x18f6c842, 0x1e860294, 0x12c0dc2, 0x24fb8a31, 0x47a8}}, -{/*.val =*/{0x245c621c, 0x2c2f900c, 0x3bb9ac91, 0x14cca9fc, 0xc7b6421, 0xf43014a, 0x209606e1, 0x127dc518, 0x23d4}}, -{/*.val =*/{0x122e310e, 0x3617c806, 0x1ddcd648, 0x2a6654fe, 0x63db210, 0x27a180a5, 0x104b0370, 0x93ee28c, 0x11ea}}, -{/*.val =*/{0x9171887, 0x1b0be403, 0xeee6b24, 0x15332a7f, 0x231ed908, 0x13d0c052, 0x82581b8, 0x49f7146, 0x8f5}}, -{/*.val =*/{0x248b8a5b, 0xd85f1ff, 0x27773592, 0xa99953f, 0x118f6c84, 0x9e86029, 0x412c0dc, 0x224fb8a3, 0x847a}}, -{/*.val =*/{0x3245c345, 0x6c2f8fd, 0x33bb9ac9, 0x54cca9f, 0x28c7b642, 0x4f43014, 0x2209606e, 0x1127dc51, 0xc23d}}, -{/*.val =*/{0x3922dfba, 0x23617c7c, 0x39ddcd64, 0x2a6654f, 0x1463db21, 0x27a180a, 0x3104b037, 0x2893ee28, 0xe11e}}, -{/*.val =*/{0x1c916fdd, 0x11b0be3e, 0x3ceee6b2, 0x215332a7, 0xa31ed90, 0x213d0c05, 0x1882581b, 0x1449f714, 0x708f}}, -{/*.val =*/{0xe48b606, 0x8d85f1d, 0x3e777359, 0x10a99953, 0x2518f6c8, 0x309e8602, 0xc412c0d, 0x2a24fb8a, 0xb847}}, -{/*.val =*/{0x27245b03, 0x246c2f8e, 0x3f3bb9ac, 0x854cca9, 0x128c7b64, 0x384f4301, 0x6209606, 0x35127dc5, 0x5c23}}, -{/*.val =*/{0x13922b99, 0x123617c5, 0x3f9ddcd6, 0x42a6654, 0x29463db2, 0x1c27a180, 0x23104b03, 0x3a893ee2, 0xae11}}, -{/*.val =*/{0x29c913e4, 0x91b0be0, 0x1fceee6b, 0x215332a, 0x14a31ed9, 0x2e13d0c0, 0x11882581, 0x3d449f71, 0xd708}}, -{/*.val =*/{0x14e489f2, 0x248d85f0, 0xfe77735, 0x210a9995, 0xa518f6c, 0x3709e860, 0x28c412c0, 0x1ea24fb8, 0x6b84}}, -}; -#endif - #if USE_PRECOMPUTED_CP const curve_point secp256k1_cp[256] = { {/*.x =*/{/*.val =*/{0x16f81798, 0x27ca056c, 0x1ce28d95, 0x26ff36cb, 0x70b0702, 0x18a573a, 0xbbac55a, 0x199fbe77, 0x79be}}, diff --git a/secp256k1.h b/secp256k1.h index e3a5f5378..071e7cfd8 100644 --- a/secp256k1.h +++ b/secp256k1.h @@ -48,10 +48,6 @@ extern const bignum256 order256k1_half; // 3/2 in G_p extern const bignum256 three_over_two256k1; -#if USE_PRECOMPUTED_IV -extern const bignum256 secp256k1_iv[256]; -#endif - #if USE_PRECOMPUTED_CP extern const curve_point secp256k1_cp[256]; extern const curve_point secp256k1_cp2[255]; From 62b95ee41484ef92d1c49fc5c1785754f5730698 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Sun, 15 Mar 2015 12:06:35 +0100 Subject: [PATCH 167/627] Optimized conversion functions. Also added a few more comments --- bignum.c | 43 ++++++++++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 13 deletions(-) diff --git a/bignum.c b/bignum.c index b22518d9a..b243d0280 100644 --- a/bignum.c +++ b/bignum.c @@ -43,27 +43,37 @@ inline void write_be(uint8_t *data, uint32_t x) data[3] = x; } +// convert a raw bigendian 256 bit number to a normalized bignum void bn_read_be(const uint8_t *in_number, bignum256 *out_number) { int i; - uint64_t temp = 0; + uint32_t temp = 0; for (i = 0; i < 8; i++) { - temp += (((uint64_t)read_be(in_number + (7 - i) * 4)) << (2 * i)); + // invariant: temp = (in_number % 2^(32i)) >> 30i + // get next limb = (in_number % 2^(32(i+1))) >> 32i + uint32_t limb = read_be(in_number + (7 - i) * 4); + // temp = (in_number % 2^(32(i+1))) << 30i + temp |= limb << (2*i); + // store 30 bits into val[i] out_number->val[i]= temp & 0x3FFFFFFF; - temp >>= 30; + // prepare temp for next round + temp = limb >> (30 - 2*i); } out_number->val[8] = temp; } +// convert a normalized bignum to a raw bigendian 256 bit number. +// in_number must be normalized and < 2^256. void bn_write_be(const bignum256 *in_number, uint8_t *out_number) { - int i, shift = 30 + 16 - 32; - uint64_t temp = in_number->val[8]; + int i; + uint32_t temp = in_number->val[8] << 16; for (i = 0; i < 8; i++) { - temp <<= 30; - temp |= in_number->val[7 - i]; - write_be(out_number + i * 4, temp >> shift); - shift -= 2; + // invariant: temp = (in_number >> 30*(8-i)) << (16 + 2i) + uint32_t limb = in_number->val[7 - i]; + temp |= limb >> (14 - 2*i); + write_be(out_number + i * 4, temp); + temp = limb << (18 + 2*i); } } @@ -336,7 +346,7 @@ void bn_inverse(bignum256 *x, const bignum256 *prime) // The algorithm is based on Schroeppel et. al. "Almost Modular Inverse" // algorithm. We keep four values u,v,r,s in the combo registers // us and vr. us stores u in the first len1 limbs (little endian) - // and v in the last 9-len1 limbs (big endian). vr stores v and s. + // and s in the last 9-len1 limbs (big endian). vr stores v and r. // This is because both u*s and v*r are guaranteed to fit in 8 limbs, so // their components are guaranteed to fit in 9. During the algorithm, // the length of u and v shrinks while r and s grow. @@ -524,8 +534,8 @@ void bn_inverse(bignum256 *x, const bignum256 *prime) // This implies 0 <= s < prime and 255 <= k <= 510. // // The invariants also give us x*s = 2^k mod prime, - // hence s = -2^k * x^-1 mod prime. - // We need to compute -s/2^k mod prime. + // hence s = 2^k * x^-1 mod prime. + // We need to compute s/2^k mod prime. // First we compute inverse = -prime^-1 mod 2^32, which we need later. // We use the Explicit Quadratic Modular inverse algorithm. @@ -550,7 +560,6 @@ void bn_inverse(bignum256 *x, const bignum256 *prime) // Then compute s + factor*prime and shift right by 32 bits. uint32_t factor = (inverse * us.a[8]) & 0xffffffff; temp = us.a[8] + (uint64_t) pp[0] * factor; - // printf("%lx %x %x %x\n", temp, us.b[0], inverse, factor); assert((temp & 0xffffffff) == 0); temp >>= 32; for (i = 0; i < 7; i++) { @@ -650,9 +659,17 @@ void bn_divmod58(bignum256 *a, uint32_t *r) rem = a->val[8] % 58; a->val[8] /= 58; for (i = 7; i >= 0; i--) { + // invariants: + // rem = old(a) >> 30(i+1) % 58 + // a[i+1..8] = old(a[i+1..8])/58 + // a[0..i] = old(a[0..i]) // 2^30 == 18512790*58 + 4 tmp = rem * 4 + a->val[i]; + // set a[i] = (rem * 2^30 + a[i])/58 + // = rem * 18512790 + (rem * 4 + a[i])/58 a->val[i] = rem * 18512790 + (tmp / 58); + // set rem = (rem * 2^30 + a[i]) mod 58 + // = (rem * 4 + a[i]) mod 58 rem = tmp % 58; } *r = rem; From d4788bddfdf66d18232aa32b904ebb57a9155666 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Sun, 15 Mar 2015 13:24:50 +0100 Subject: [PATCH 168/627] Added modulus to bn_subtractmod --- bignum.c | 9 +++++---- bignum.h | 2 +- ecdsa.c | 20 ++++++++++---------- 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/bignum.c b/bignum.c index b243d0280..45778856b 100644 --- a/bignum.c +++ b/bignum.c @@ -626,14 +626,15 @@ void bn_addmodi(bignum256 *a, uint32_t b, const bignum256 *prime) { bn_mod(a, prime); } -// res = a - b -// b < 2*prime; result not normalized -void bn_subtractmod(const bignum256 *a, const bignum256 *b, bignum256 *res) +// res = a - b mod prime. More exactly res = a + (2*prime - b). +// precondition: 0 <= b < 2*prime, 0 <= a < prime +// res < 3*prime +void bn_subtractmod(const bignum256 *a, const bignum256 *b, bignum256 *res, const bignum256 *prime) { int i; uint32_t temp = 0; for (i = 0; i < 9; i++) { - temp += a->val[i] + 2u * prime256k1.val[i] - b->val[i]; + temp += a->val[i] + 2u * prime->val[i] - b->val[i]; res->val[i] = temp & 0x3FFFFFFF; temp >>= 30; } diff --git a/bignum.h b/bignum.h index de71fba0e..97471b7b1 100644 --- a/bignum.h +++ b/bignum.h @@ -73,7 +73,7 @@ void bn_addmod(bignum256 *a, const bignum256 *b, const bignum256 *prime); void bn_addmodi(bignum256 *a, uint32_t b, const bignum256 *prime); -void bn_subtractmod(const bignum256 *a, const bignum256 *b, bignum256 *res); +void bn_subtractmod(const bignum256 *a, const bignum256 *b, bignum256 *res, const bignum256 *prime); void bn_subtract(const bignum256 *a, const bignum256 *b, bignum256 *res); diff --git a/ecdsa.c b/ecdsa.c index 0c5b5a625..7ecb44cac 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -63,24 +63,24 @@ void point_add(const curve_point *cp1, curve_point *cp2) return; } - bn_subtractmod(&(cp2->x), &(cp1->x), &inv); + bn_subtractmod(&(cp2->x), &(cp1->x), &inv, &prime256k1); bn_inverse(&inv, &prime256k1); - bn_subtractmod(&(cp2->y), &(cp1->y), &lambda); + bn_subtractmod(&(cp2->y), &(cp1->y), &lambda, &prime256k1); bn_multiply(&inv, &lambda, &prime256k1); memcpy(&xr, &lambda, sizeof(bignum256)); bn_multiply(&xr, &xr, &prime256k1); - temp = 0; + temp = 1; for (i = 0; i < 9; i++) { - temp += xr.val[i] + 3u * prime256k1.val[i] - cp1->x.val[i] - cp2->x.val[i]; + temp += 0x3FFFFFFF + xr.val[i] + 2u * prime256k1.val[i] - cp1->x.val[i] - cp2->x.val[i]; xr.val[i] = temp & 0x3FFFFFFF; temp >>= 30; } bn_fast_mod(&xr, &prime256k1); - bn_subtractmod(&(cp1->x), &xr, &yr); + bn_subtractmod(&(cp1->x), &xr, &yr, &prime256k1); // no need to fast_mod here // bn_fast_mod(&yr); bn_multiply(&lambda, &yr, &prime256k1); - bn_subtractmod(&yr, &(cp1->y), &yr); + bn_subtractmod(&yr, &(cp1->y), &yr, &prime256k1); bn_fast_mod(&yr, &prime256k1); memcpy(&(cp2->x), &xr, sizeof(bignum256)); memcpy(&(cp2->y), &yr, sizeof(bignum256)); @@ -111,18 +111,18 @@ void point_double(curve_point *cp) bn_multiply(&(cp->x), &lambda, &prime256k1); memcpy(&xr, &lambda, sizeof(bignum256)); bn_multiply(&xr, &xr, &prime256k1); - temp = 0; + temp = 1; for (i = 0; i < 9; i++) { - temp += xr.val[i] + 3u * prime256k1.val[i] - 2u * cp->x.val[i]; + temp += 0x3FFFFFFF + xr.val[i] + 2u * (prime256k1.val[i] - cp->x.val[i]); xr.val[i] = temp & 0x3FFFFFFF; temp >>= 30; } bn_fast_mod(&xr, &prime256k1); - bn_subtractmod(&(cp->x), &xr, &yr); + bn_subtractmod(&(cp->x), &xr, &yr, &prime256k1); // no need to fast_mod here // bn_fast_mod(&yr); bn_multiply(&lambda, &yr, &prime256k1); - bn_subtractmod(&yr, &(cp->y), &yr); + bn_subtractmod(&yr, &(cp->y), &yr, &prime256k1); bn_fast_mod(&yr, &prime256k1); memcpy(&(cp->x), &xr, sizeof(bignum256)); memcpy(&(cp->y), &yr, sizeof(bignum256)); From eb6e74f3613b60be86f7ff6dfa82c1ed006ebfaf Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Sun, 15 Mar 2015 21:14:43 +0100 Subject: [PATCH 169/627] Improve speed of scalar_multiply. We also allow for substracting values to be able to do 3 bits at a time. --- ecdsa.c | 77 ++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 57 insertions(+), 20 deletions(-) diff --git a/ecdsa.c b/ecdsa.c index 7ecb44cac..b54ee947e 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "bignum.h" #include "rand.h" @@ -192,42 +193,78 @@ int point_is_negative_of(const curve_point *p, const curve_point *q) return !bn_is_equal(&(p->y), &(q->y)); } +#if USE_PRECOMPUTED_CP +#define BITS_AT_A_TIME 3 +#else +#define BITS_AT_A_TIME 2 +#endif + // res = k * G void scalar_multiply(const bignum256 *k, curve_point *res) { int i; // result is zero int is_zero = 1; - curve_point curr; +#if !USE_PRECOMPUTED_CP + curve_point curr = G256k1; +#endif + assert (bn_is_less(k, &order256k1)); + bignum256 a = *k; + int sign = 1; + if ((a.val[8] & 0x8000) != 0) { + // negate k if it is large + bn_subtract(&order256k1, &a, &a); + sign = -sign; + } // initial res - memcpy(&curr, &G256k1, sizeof(curve_point)); + point_set_infinity(res); for (i = 0; i < 256; i++) { - if (k->val[i / 30] & (1u << (i % 30))) { - if (is_zero) { + int lowbits = a.val[0] & ((1 << BITS_AT_A_TIME) - 1); + if ((lowbits & 1) != 0) { + int tsign = sign; + int factor = lowbits & 3; + + if ((lowbits & (1 << (BITS_AT_A_TIME - 1))) != 0) { + lowbits |= ~((1 << BITS_AT_A_TIME) - 1); + factor ^= ~1; + tsign = -sign; + } + + int j = 0; + uint32_t carry = -lowbits; + while (carry) { + carry += a.val[j]; + a.val[j] = carry & 0x3fffffff; + carry >>= 30; + j++; + } + + const curve_point *summand; #if USE_PRECOMPUTED_CP - if (i < 255 && (k->val[(i + 1) / 30] & (1u << ((i + 1) % 30)))) { - memcpy(res, secp256k1_cp2 + i, sizeof(curve_point)); - i++; - } else { - memcpy(res, secp256k1_cp + i, sizeof(curve_point)); - } + summand = ((factor & 2) != 0 ? secp256k1_cp2 : secp256k1_cp) + i; #else - memcpy(res, &curr, sizeof(curve_point)); + summand = &curr; #endif + // negate summand if necessary + if (is_zero) { + if (tsign < 0) { + res->x = summand->x; + bn_subtract(&prime256k1, &summand->y, &res->y); + } else { + *res = *summand; + } is_zero = 0; } else { -#if USE_PRECOMPUTED_CP - if (i < 255 && (k->val[(i + 1) / 30] & (1u << ((i + 1) % 30)))) { - point_add(secp256k1_cp2 + i, res); - i++; - } else { - point_add(secp256k1_cp + i, res); + curve_point temp; + if (tsign < 0) { + temp.x = summand->x; + bn_subtract(&prime256k1, &summand->y, &temp.y); + summand = &temp; } -#else - point_add(&curr, res); -#endif + point_add(summand, res); } } + bn_rshift(&a); #if ! USE_PRECOMPUTED_CP point_double(&curr); #endif From ec057a5102efad6ddea12986de000867fd84dd82 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Mon, 16 Mar 2015 16:29:29 +0100 Subject: [PATCH 170/627] "More" constant time point multiplication About the same speed, about the same precomputation table requirements. Simpler code. --- ecdsa.c | 108 +-- secp256k1.c | 2691 +++++++++++++++++++++++++++++++-------------------- secp256k1.h | 3 +- 3 files changed, 1711 insertions(+), 1091 deletions(-) diff --git a/ecdsa.c b/ecdsa.c index b54ee947e..0b012ecb0 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -194,83 +194,65 @@ int point_is_negative_of(const curve_point *p, const curve_point *q) } #if USE_PRECOMPUTED_CP -#define BITS_AT_A_TIME 3 -#else -#define BITS_AT_A_TIME 2 -#endif // res = k * G void scalar_multiply(const bignum256 *k, curve_point *res) { - int i; + int i, j; // result is zero - int is_zero = 1; -#if !USE_PRECOMPUTED_CP - curve_point curr = G256k1; -#endif assert (bn_is_less(k, &order256k1)); bignum256 a = *k; - int sign = 1; - if ((a.val[8] & 0x8000) != 0) { - // negate k if it is large + int sign = (a.val[0] & 1) ^ 1; + uint32_t lowbits; + // make number odd + if (sign) { bn_subtract(&order256k1, &a, &a); - sign = -sign; } - // initial res - point_set_infinity(res); - for (i = 0; i < 256; i++) { - int lowbits = a.val[0] & ((1 << BITS_AT_A_TIME) - 1); - if ((lowbits & 1) != 0) { - int tsign = sign; - int factor = lowbits & 3; - - if ((lowbits & (1 << (BITS_AT_A_TIME - 1))) != 0) { - lowbits |= ~((1 << BITS_AT_A_TIME) - 1); - factor ^= ~1; - tsign = -sign; - } - - int j = 0; - uint32_t carry = -lowbits; - while (carry) { - carry += a.val[j]; - a.val[j] = carry & 0x3fffffff; - carry >>= 30; - j++; - } + a.val[8] |= 0x10000; + assert((a.val[0] & 1) != 0); + assert((a.val[8] & 0x10000) != 0); - const curve_point *summand; -#if USE_PRECOMPUTED_CP - summand = ((factor & 2) != 0 ? secp256k1_cp2 : secp256k1_cp) + i; -#else - summand = &curr; -#endif - // negate summand if necessary - if (is_zero) { - if (tsign < 0) { - res->x = summand->x; - bn_subtract(&prime256k1, &summand->y, &res->y); - } else { - *res = *summand; - } - is_zero = 0; - } else { - curve_point temp; - if (tsign < 0) { - temp.x = summand->x; - bn_subtract(&prime256k1, &summand->y, &temp.y); - summand = &temp; - } - point_add(summand, res); - } + // now compute res = a *G step by step. + // initial res + lowbits = a.val[0] & ((1 << 5) - 1); + lowbits ^= (lowbits >> 4) - 1; + lowbits &= 15; + *res = secp256k1_cp[0][lowbits >> 1]; + for (i = 1; i < 64; i ++) { + // invariant res = abs((a % 2*16^i) - 16^i) * G + + for (j = 0; j < 8; j++) { + a.val[j] = (a.val[j] >> 4) | ((a.val[j + 1] & 0xf) << 26); } - bn_rshift(&a); -#if ! USE_PRECOMPUTED_CP - point_double(&curr); -#endif + a.val[j] >>= 4; + + lowbits = a.val[0] & ((1 << 5) - 1); + lowbits ^= (lowbits >> 4) - 1; + lowbits &= 15; + if ((lowbits & 1) == 0) { + // negate last result to make signs of this round and the + // last round equal. + bn_subtract(&prime256k1, &res->y, &res->y); + } + + // add odd factor + point_add(&secp256k1_cp[i][lowbits >> 1], res); + } + if (sign) { + // negate + bn_subtract(&prime256k1, &res->y, &res->y); } } +#else + +void scalar_multiply(const bignum256 *k, curve_point *res) +{ + point_multiply(k, &G256k1, res); +} + +#endif + // generate random K for signing int generate_k_random(bignum256 *k) { int i, j; diff --git a/secp256k1.c b/secp256k1.c index 4baf6d617..b96448dd8 100644 --- a/secp256k1.c +++ b/secp256k1.c @@ -40,1031 +40,1670 @@ const bignum256 three_over_two256k1 = { /*.val =*/{0x3ffffe19, 0x3ffffffd, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x7fff}}; #if USE_PRECOMPUTED_CP -const curve_point secp256k1_cp[256] = { -{/*.x =*/{/*.val =*/{0x16f81798, 0x27ca056c, 0x1ce28d95, 0x26ff36cb, 0x70b0702, 0x18a573a, 0xbbac55a, 0x199fbe77, 0x79be}}, - /*.y =*/{/*.val =*/{0x3b10d4b8, 0x311f423f, 0x28554199, 0x5ed1229, 0x1108a8fd, 0x13eff038, 0x3c4655da, 0x369dc9a8, 0x483a}}}, -{/*.x =*/{/*.val =*/{0x1c709ee5, 0x2eb026e5, 0xef3ca7a, 0x1de392e3, 0x7cd85c, 0x1501ba57, 0x17d6d304, 0x1fe5107b, 0xc604}}, - /*.y =*/{/*.val =*/{0x10cfe52a, 0xd90c6a5, 0x266d0e12, 0x3d8c994c, 0x2ceaeef7, 0x16106519, 0x1c339a3c, 0x1a3fa98f, 0x1ae1}}}, -{/*.x =*/{/*.val =*/{0x28c4cd13, 0x13ea52af, 0x2e075847, 0x1b04e403, 0xb1404cc, 0x3924124c, 0x180f3581, 0x36fc7043, 0xe493}}, - /*.y =*/{/*.val =*/{0x7739922, 0x3fa5ef71, 0x3bdfe40c, 0x19eb8cef, 0x251448d9, 0xb88263a, 0x55b7564, 0x264fa835, 0x51ed}}}, -{/*.x =*/{/*.val =*/{0x210a2a01, 0x1de13bcf, 0x1af888a6, 0x6f74179, 0xf3c2f0a, 0xe10fedc, 0x2351daff, 0x39785732, 0x2f01}}, - /*.y =*/{/*.val =*/{0x2cbde904, 0x1768b2dd, 0x25b7617b, 0x3884f5ae, 0x2d13b4c2, 0x3420a84c, 0x39949293, 0x2a29d054, 0x5c4d}}}, -{/*.x =*/{/*.val =*/{0x2a6dec0a, 0x113ba278, 0x7a5ae9c, 0x28c4da6e, 0x23e97b2, 0x6aaf087, 0x29ec5301, 0x33a4ed67, 0xe60f}}, - /*.y =*/{/*.val =*/{0x29616821, 0x7ccb339, 0xd23f0be, 0x25a24791, 0x39371012, 0x267cd3d5, 0x195929db, 0x141ce679, 0xf7e3}}}, -{/*.x =*/{/*.val =*/{0x7143e65, 0x17436f50, 0x104a61d7, 0x33ff2e26, 0x3378ceda, 0x1b81538b, 0x1a22d47b, 0x2675d3ed, 0xd301}}, - /*.y =*/{/*.val =*/{0x24106ab9, 0x16cffc7c, 0xed81960, 0x1d8330d9, 0x380651f, 0x1b7b27a6, 0x3d5c3b3d, 0x236742b8, 0x9503}}}, -{/*.x =*/{/*.val =*/{0x3874ef8b, 0xde4639b, 0x1bafd81e, 0x131bc773, 0x32823cfc, 0x147abe0, 0x2eab70b1, 0x30550b45, 0xbf23}}, - /*.y =*/{/*.val =*/{0x26831d9f, 0x370dfbf9, 0x11e2f784, 0x8bf1520, 0x1392e4c5, 0x24a282e9, 0x3737ad, 0x219bf0cc, 0x5cb3}}}, -{/*.x =*/{/*.val =*/{0x2769a24e, 0x11c1dd15, 0x5356556, 0x3d5735c0, 0x11671cbc, 0x30f427df, 0x37a06696, 0xef900cf, 0x34ff}}, - /*.y =*/{/*.val =*/{0x33cc2f1a, 0x124419e9, 0xf8b6818, 0x37c5b0fa, 0x32098c55, 0x18676260, 0x36c553f6, 0x4588e88, 0x5d9d}}}, -{/*.x =*/{/*.val =*/{0x15f51508, 0x191b88ff, 0x1ac1ca10, 0x30e72af5, 0x2de238d8, 0x29b8f85c, 0x209d9ea2, 0x98c84b1, 0x8282}}, - /*.y =*/{/*.val =*/{0x36e26caf, 0xc6dbabf, 0x37b17bed, 0x3584eb0b, 0x360ace62, 0x95ba0c2, 0x3dfe45e8, 0x2a026155, 0x11f8}}}, -{/*.x =*/{/*.val =*/{0x2f34a24d, 0x9b8b003, 0x1e159d09, 0x36f25a36, 0x3918d50a, 0x2a15ea73, 0x39ff3905, 0x1c2ca1e9, 0x4653}}, - /*.y =*/{/*.val =*/{0x333887f4, 0xbe3ec82, 0x1d37a10a, 0x23826c85, 0x2ec2c158, 0x3e2f6bf7, 0xc082a4a, 0xc6ce0da, 0x35e5}}}, -{/*.x =*/{/*.val =*/{0x2285131f, 0x16e406cb, 0x13b088d, 0x3b1bb372, 0x2d6240aa, 0x12863d9a, 0xbd77d66, 0x3aee388f, 0x241f}}, - /*.y =*/{/*.val =*/{0x2750026d, 0x2ecf99bc, 0x10cb5afa, 0x143f43ef, 0x181df8cd, 0x1082f44e, 0xf8d3d6c, 0x1e367fe5, 0x5133}}}, -{/*.x =*/{/*.val =*/{0x1b920471, 0x372d8c1a, 0x23de0de, 0xc62e17d, 0x18f8d9fc, 0x1330a60f, 0x2fa79fce, 0x36d3a85c, 0x5d1b}}, - /*.y =*/{/*.val =*/{0x37b83103, 0xcc199b, 0x2c56e7b7, 0x3ac7a665, 0x22265679, 0x2ee650e2, 0x39e2e794, 0x2099de4d, 0x2843}}}, -{/*.x =*/{/*.val =*/{0x11e5b739, 0xff396d5, 0x12222ed7, 0x2e4e0cff, 0x3c846de0, 0x26731b1b, 0x3865a72f, 0x567dca2, 0x175e}}, - /*.y =*/{/*.val =*/{0x29fed695, 0x3be9bffb, 0x124345c6, 0x2d6556b7, 0x371f5eac, 0x3e5e947f, 0x79eba4e, 0x1b83678f, 0xd350}}}, -{/*.x =*/{/*.val =*/{0x6bc47d6, 0x39e01279, 0x2da121bc, 0x3f7fad71, 0x39c62130, 0x3ef32384, 0x332d7a5f, 0x4fc0ff, 0x423a}}, - /*.y =*/{/*.val =*/{0xb548a34, 0x48db9b6, 0x24f009ed, 0x363b0d4, 0x36b3c772, 0x1e7deeeb, 0x1d970a11, 0x3803f878, 0xb91a}}}, -{/*.x =*/{/*.val =*/{0x416824a, 0xb7dbde, 0x33e27413, 0x37d98bce, 0x16877649, 0x1e9eaf3, 0x3b905089, 0x1a916b07, 0x111d}}, - /*.y =*/{/*.val =*/{0x2108e9d0, 0x26844750, 0x2daca4ca, 0x1c002265, 0x65952f0, 0x35236ffc, 0x2affbb90, 0x244711e3, 0x696}}}, -{/*.x =*/{/*.val =*/{0x1bced775, 0x2d7b7780, 0x2f74e56a, 0x242da297, 0x39dcff72, 0x2576faf2, 0x3c8b8ad7, 0x1b725eb1, 0x4a4a}}, - /*.y =*/{/*.val =*/{0x278dd66d, 0xafe3da2, 0x24742acb, 0x3a4336d0, 0xf4571d, 0x3be7dce7, 0x31e72943, 0x46c0598, 0x5299}}}, -{/*.x =*/{/*.val =*/{0x3ff4640, 0x9aeb63e, 0x1552ffe5, 0x11071f95, 0x262ee053, 0x3ab016d8, 0xc9c99c, 0x243511ec, 0x363d}}, - /*.y =*/{/*.val =*/{0x3bee9de9, 0x800f1fc, 0x199ecb6, 0x2e6a2402, 0x33363145, 0x2d114e5f, 0x32221953, 0x1ceb7f1c, 0x4e2}}}, -{/*.x =*/{/*.val =*/{0x2f92c541, 0x9c4a972, 0x2dfb59dd, 0x18bec04b, 0x3b02bf0b, 0x25cf1b24, 0x27e9b553, 0x2619bb66, 0x4c1b}}, - /*.y =*/{/*.val =*/{0x68fe020, 0xb13cff7, 0x3eb1ad7, 0x14bab5f9, 0x16e69cc6, 0x32dd4f39, 0x28a0f7fb, 0x24b4c82f, 0xc1f7}}}, -{/*.x =*/{/*.val =*/{0x3eaaf3d1, 0x323ca32, 0x228f135e, 0xcfb6f06, 0xb54e32, 0x28bcf01e, 0x3b12b529, 0xe1deea0, 0xa408}}, - /*.y =*/{/*.val =*/{0x30b254b9, 0x4ad4d37, 0x2d1ef90b, 0x79d5db, 0x21b3e220, 0x3e0f5a4d, 0x3bc79b8b, 0x3d84bfbb, 0x40e9}}}, -{/*.x =*/{/*.val =*/{0x3940d33a, 0x334f6d69, 0x14203b98, 0x3620291, 0x16c86f6e, 0x38f868bd, 0xc0b53a4, 0x319074a3, 0xa804}}, - /*.y =*/{/*.val =*/{0x2d46967a, 0xf3a57e9, 0xf736a94, 0x3c632a27, 0x2047e81a, 0x30a10b05, 0x3a6d03de, 0x20c94acb, 0x95be}}}, -{/*.x =*/{/*.val =*/{0x1ffdf80c, 0x27de6957, 0x15bcd1b6, 0x3929e068, 0x5638843, 0x912d6dd, 0x3c2be8c6, 0x17c5977c, 0x8b4b}}, - /*.y =*/{/*.val =*/{0x1fd4fd36, 0xfbfc319, 0x162ee56b, 0x38cd9518, 0x30da04f9, 0x2f5e04ea, 0x308b4b3f, 0x29bda34, 0x4aad}}}, -{/*.x =*/{/*.val =*/{0x755e4be, 0x2cfc99c5, 0x17c997ab, 0x2bd93b90, 0x3c611071, 0x5f1fb20, 0x291718ce, 0x1739384c, 0xed0c}}, - /*.y =*/{/*.val =*/{0x207bf42f, 0xfe7e9ba, 0x23ddab16, 0x364e495d, 0x3ea68049, 0x36b5fd69, 0x345bdbf3, 0x27f1ef08, 0x221a}}}, -{/*.x =*/{/*.val =*/{0x7cec8ab, 0x12db9b20, 0x20552ced, 0xc95159b, 0x31fae8e5, 0x570fe0f, 0xe694b3b, 0x2c04f113, 0xfaec}}, - /*.y =*/{/*.val =*/{0x2b155070, 0x26077f66, 0x5e2e2e8, 0xcaca1ae, 0x2fb13d9c, 0x380b1bb0, 0x2cb57fc2, 0x2d7a43a7, 0xcc09}}}, -{/*.x =*/{/*.val =*/{0x1ad1b1f7, 0x1fd93aba, 0x323cd3e0, 0x2cb76093, 0xbcafdb3, 0xc682cdf, 0x2d2f2c87, 0x2284cb72, 0x9bb}}, - /*.y =*/{/*.val =*/{0x3811c80, 0x104c189f, 0x752d536, 0x152a103d, 0x63e850f, 0x2774a13e, 0x2e3b9b6f, 0x2cacabfb, 0x945b}}}, -{/*.x =*/{/*.val =*/{0x1232fcda, 0x2d845649, 0x2c0e77bc, 0x36ffe9, 0x1548c7b7, 0x1dc7002f, 0x3996d6bf, 0x2ea9b976, 0x723c}}, - /*.y =*/{/*.val =*/{0x1eb39f5f, 0x7701a76, 0x37949480, 0x1828194d, 0x24d6e26, 0x44dd222, 0xc498a92, 0x19ed5657, 0x96e8}}}, -{/*.x =*/{/*.val =*/{0xca030d5, 0x3f4e0f58, 0x39849071, 0x90290c1, 0x33a3c62d, 0x35f7115d, 0x3744d343, 0x29e190de, 0x57ef}}, - /*.y =*/{/*.val =*/{0x34b02f9e, 0x1ead109, 0x1e9974ab, 0x26db4ab9, 0x1e03ec68, 0x189f24a3, 0x8518893, 0x36c2f46d, 0xd712}}}, -{/*.x =*/{/*.val =*/{0xc584dd5, 0x3ebf1ddc, 0x27b012a7, 0x2015df8c, 0x226cb910, 0x3dfa7354, 0xbc42a2d, 0x2f50da8a, 0x264b}}, - /*.y =*/{/*.val =*/{0x3704ab11, 0x18489e4d, 0x17b8d8de, 0x46090dc, 0x33be226a, 0x1d738930, 0x93b4d4f, 0x1bea53b8, 0xd87c}}}, -{/*.x =*/{/*.val =*/{0xb2438e8, 0x2fc9af61, 0x1bdec9d2, 0x22f187f5, 0x36a79da7, 0x21701588, 0xd2bbdac, 0x19492f50, 0xa94c}}, - /*.y =*/{/*.val =*/{0x318661f4, 0xb8b236f, 0xe39b2bc, 0x174f1828, 0x19e3a7e, 0x24865414, 0x16280fd7, 0x7f664be, 0xb520}}}, -{/*.x =*/{/*.val =*/{0xe7dd7fa, 0x294cfb28, 0x3a919839, 0x11e5848d, 0x2d3b509, 0x3fbb204b, 0x2bf98ba5, 0x293524ef, 0xeebf}}, - /*.y =*/{/*.val =*/{0x21de8999, 0x37f53f6b, 0x311f712d, 0x393370e9, 0x38089d9a, 0x39fb6bc5, 0x2f0f269e, 0x2328e5c3, 0x5d9a}}}, -{/*.x =*/{/*.val =*/{0x7d297fd, 0x1afba421, 0x36766d67, 0x3a92f023, 0x18495fc4, 0x3180c704, 0x17bfda61, 0x12b5e9ea, 0x381c}}, - /*.y =*/{/*.val =*/{0x3d493fc5, 0xeb38c61, 0x3939c009, 0x11440cb6, 0x115eccf0, 0x397e9c26, 0x2eee48f3, 0x3d4ec8e3, 0x936a}}}, -{/*.x =*/{/*.val =*/{0x2ede454c, 0x1235c108, 0x3dd08b24, 0x3c7417fb, 0x138c479c, 0x420c765, 0x1c63bcce, 0x2e73416b, 0xe1ef}}, - /*.y =*/{/*.val =*/{0x28913797, 0x367f48ce, 0x3a2d4c6a, 0x138c9129, 0x7712346, 0x15307ff9, 0x39be7b01, 0x114c362b, 0xecb}}}, -{/*.x =*/{/*.val =*/{0x29eb99a4, 0xcffbacc, 0x3d47b18d, 0x395067cc, 0x3475a8c7, 0x308d7a6b, 0x17010c5a, 0x3e6c689a, 0x5318}}, - /*.y =*/{/*.val =*/{0x3e91f92d, 0x31c9bbbb, 0x1e3ec652, 0x7cad034, 0x3405e8a4, 0xb64ebae, 0x1a419577, 0x33fad2fb, 0xf44c}}}, -{/*.x =*/{/*.val =*/{0x39a48db0, 0x3f5e0d6c, 0x33c03bfe, 0x48568a6, 0x3bde459f, 0x742826d, 0x27167279, 0x11369a5b, 0x100f}}, - /*.y =*/{/*.val =*/{0x2bc65a09, 0x3ef57358, 0x35195ac0, 0x3fd2863f, 0x90666b7, 0x23ccc030, 0xb772ec, 0x384c64a8, 0xcdd9}}}, -{/*.x =*/{/*.val =*/{0x1e4df706, 0x2c14a13c, 0x37d08084, 0x36723e48, 0xc4199d8, 0x577fcad, 0x1c771a84, 0x227cb3ad, 0x8c09}}, - /*.y =*/{/*.val =*/{0x1d72fa98, 0xdab168d, 0x16511aa7, 0x379afd45, 0x1c966c60, 0x85cb2e7, 0x32034ffd, 0x2f4113d0, 0xfb4d}}}, -{/*.x =*/{/*.val =*/{0x1c47bffd, 0x798f0cf, 0x95bc1bb, 0x14a14e6f, 0x22c0259c, 0x1205d0c9, 0x26704c4a, 0x54f1789, 0xfb8f}}, - /*.y =*/{/*.val =*/{0x1949b095, 0x24291777, 0x5426130, 0x3784e26b, 0x3ccd531d, 0x284766d2, 0x621816f, 0x1ea77178, 0x6ca2}}}, -{/*.x =*/{/*.val =*/{0xbb2629a, 0x23e86e2d, 0x337a7b8b, 0x280b161d, 0x28708465, 0x3327c29c, 0x151755a0, 0xccff5d7, 0xe747}}, - /*.y =*/{/*.val =*/{0x2946f6d6, 0x3e365869, 0x21a969a9, 0x20ddaa9b, 0xc2581c8, 0x10d80e01, 0x30c114cc, 0x3f805141, 0xf2af}}}, -{/*.x =*/{/*.val =*/{0x2534fd2d, 0x322b379b, 0xf3b3852, 0x1fe35119, 0x4c017a7, 0x2489e928, 0x3ed1b1dc, 0x6f898b1, 0xe103}}, - /*.y =*/{/*.val =*/{0x1456a00d, 0x113c63ca, 0x21ced79a, 0x24b75067, 0x17535af2, 0x1a905d96, 0x405e6bb, 0x1864a250, 0x9d70}}}, -{/*.x =*/{/*.val =*/{0x295c8356, 0x1389f8da, 0x294d8578, 0x229ab177, 0x29b2c902, 0x2577343c, 0x89eab9f, 0xfc89320, 0xf4b9}}, - /*.y =*/{/*.val =*/{0x3e001fd3, 0x356186e6, 0x115609ab, 0x1fbc4d12, 0xeee90c3, 0x17da9e90, 0x162dfb0e, 0x24bb018a, 0xa67a}}}, -{/*.x =*/{/*.val =*/{0x3b160e8a, 0x358bf85, 0x17e696c2, 0x7a144be, 0x1b08b0d5, 0x188ba809, 0x15236b19, 0x2b287f39, 0x9d1}}, - /*.y =*/{/*.val =*/{0x3ca04c44, 0x13814315, 0x212b5e53, 0x3a783ba4, 0x18c27e6f, 0x19a4b383, 0x1f0c63e5, 0x623d440, 0x1153}}}, -{/*.x =*/{/*.val =*/{0x35ba7fc2, 0x25f5f411, 0x3c39562e, 0x22cea4ef, 0x21cde751, 0xab5e4e0, 0x2b9e18a, 0x16731153, 0xc66c}}, - /*.y =*/{/*.val =*/{0x375f5956, 0x3b0f1a73, 0x15955977, 0x298376c, 0x10cb2f0, 0x13cf3aab, 0x30fcfbea, 0xbf8afec, 0xd959}}}, -{/*.x =*/{/*.val =*/{0x1094696d, 0x3579a236, 0x1d6af52, 0x3e2c99a9, 0x3bd7ec5c, 0xa0e7c50, 0x15b530ac, 0x1b2b91b5, 0xfeea}}, - /*.y =*/{/*.val =*/{0x18090088, 0x5577afc, 0x41442d3, 0x72255f3, 0x3ecd5c98, 0x39384afc, 0xe1bab06, 0x1adb25f7, 0xe57c}}}, -{/*.x =*/{/*.val =*/{0x2e752b08, 0x2a90102b, 0x331a1870, 0x7b2b82c, 0x32e17914, 0x986be76, 0x387e1c53, 0x2d886b6, 0x4d00}}, - /*.y =*/{/*.val =*/{0x8302cea, 0x39ca147d, 0x1c7293a3, 0x1f7d7c46, 0x1972cccb, 0x3609560b, 0xd255cb6, 0x16e3c638, 0x6a0d}}}, -{/*.x =*/{/*.val =*/{0x75c58ef, 0x22658bf5, 0x21f1b77f, 0x15e8100f, 0x317128d6, 0x28988451, 0x1a05dd6a, 0x1c32880f, 0x71f5}}, - /*.y =*/{/*.val =*/{0x135d420e, 0x219269cb, 0x3363e7df, 0x11174030, 0x95b8df2, 0x155cd16f, 0x880dd25, 0x1056e577, 0xeb42}}}, -{/*.x =*/{/*.val =*/{0x3ff8359, 0x122c181, 0x25e76516, 0x2d208771, 0x1da01446, 0xa0ad708, 0x3d253b7d, 0x2cd8a7de, 0xa2b7}}, - /*.y =*/{/*.val =*/{0x3e86fec2, 0x8e5ffb3, 0x6f3835a, 0x34420d41, 0x1e29c910, 0x24de8fdc, 0x1122d57a, 0xe2505a5, 0x6930}}}, -{/*.x =*/{/*.val =*/{0x1ec6cb1, 0xfea5e2f, 0x8583de3, 0x3b595f60, 0x3fca3cfe, 0x1ef92f9b, 0x9cdcb36, 0x2a476441, 0xda67}}, - /*.y =*/{/*.val =*/{0x3a68be1d, 0x3a7aa389, 0xf740a17, 0x31eb7142, 0x1780e5de, 0x118fdfb2, 0x242bc41f, 0x2a8d5205, 0x9bac}}}, -{/*.x =*/{/*.val =*/{0x1fe741c9, 0x3b8f3208, 0xea5a835, 0x2f67cd73, 0xd8718b, 0x3033eabc, 0x1ef587c0, 0x334d97e8, 0x4dba}}, - /*.y =*/{/*.val =*/{0x338eb623, 0x2f843e0, 0x3c0535f6, 0x30e12827, 0x38299d0c, 0x33f567a0, 0x1892e7fd, 0x1503a294, 0x16c3}}}, -{/*.x =*/{/*.val =*/{0x34e218da, 0x1fb6a2ea, 0x26860508, 0x13217c54, 0x1c2590f, 0x3c5f63fd, 0x9beee68, 0x3ff12054, 0x13d1}}, - /*.y =*/{/*.val =*/{0x1b191c19, 0x36d0677, 0x15bd127e, 0x2b40481b, 0x3758bda4, 0x2e4cdec6, 0x1961dcec, 0xe47ea64, 0x6008}}}, -{/*.x =*/{/*.val =*/{0x22e96db8, 0xced032a, 0x229dbff1, 0x327645b3, 0x30533b3c, 0x271e7116, 0x6000765, 0x13e73bdb, 0x219b}}, - /*.y =*/{/*.val =*/{0xd3b6bc7, 0x1f7c069e, 0x29057652, 0x13e2b14f, 0x372a6e39, 0x11060300, 0x1efeaf5a, 0x31817656, 0x24d9}}}, -{/*.x =*/{/*.val =*/{0x1a37b7c0, 0x1d517330, 0x311069f5, 0x2343dee, 0x322151ec, 0x24d7b, 0x34cdda6e, 0x13ea82cc, 0x5390}}, - /*.y =*/{/*.val =*/{0x22771c8, 0x372c25ac, 0x14434699, 0x26666078, 0xd3c1c13, 0x27b32b08, 0x106d88c, 0x21f42f20, 0x5bc0}}}, -{/*.x =*/{/*.val =*/{0x38a47ca9, 0x1f343c7c, 0x10f85ad5, 0x1bb9eaab, 0x16995d2a, 0x2644658c, 0x146753cf, 0x1d6be750, 0x1a5}}, - /*.y =*/{/*.val =*/{0x37ebcdb7, 0x1f177cb9, 0x34d7ea66, 0x2e4f1767, 0x3b8698bd, 0x17f14b86, 0x20dc3cc5, 0x3c72e2ac, 0x3038}}}, -{/*.x =*/{/*.val =*/{0x2315565b, 0xc275d57, 0x3c20c6ee, 0x2986a0f4, 0x2155d6d3, 0x7d706dd, 0x1d439ca7, 0x3810dd88, 0xf5f0}}, - /*.y =*/{/*.val =*/{0x1d2ecc82, 0x1e10c2bf, 0x2d7e40a6, 0x2fd86fcf, 0x37101aa5, 0x6245837, 0x2052bf62, 0x1398af96, 0x6b9f}}}, -{/*.x =*/{/*.val =*/{0x35362d33, 0x2f9e0767, 0x2227642c, 0x32f24851, 0xca4e347, 0x1fcdb65c, 0x36e9a57a, 0x1bc2db02, 0x8f50}}, - /*.y =*/{/*.val =*/{0x7fa243f, 0x121f432, 0x3bb8eaf3, 0x33e49750, 0x1c336848, 0x315093c, 0x26171953, 0x25574abe, 0x469f}}}, -{/*.x =*/{/*.val =*/{0x3ad86047, 0x3fe567d0, 0x29b8bcae, 0x2d4e810e, 0xa906779, 0x3329dd93, 0x183a7719, 0x3342f4d6, 0x8e7b}}, - /*.y =*/{/*.val =*/{0x460372a, 0x284011fa, 0x3fd68b3e, 0x3a238b91, 0x29514579, 0xc410832, 0x1a4b3940, 0x1dc2ca8f, 0x10b7}}}, -{/*.x =*/{/*.val =*/{0x313f0351, 0x1f4a022f, 0x10389e77, 0x3056e34f, 0x2950df3b, 0x3cc6665, 0x2729dc35, 0x16ea8657, 0x33b3}}, - /*.y =*/{/*.val =*/{0xb8d7418, 0x2f140f33, 0x889b702, 0x19583bef, 0xd52bcaa, 0x1900d892, 0x2bf87f94, 0x615902, 0xa58a}}}, -{/*.x =*/{/*.val =*/{0x414bb36, 0x1c771ec9, 0x2d7bca6d, 0x3db84272, 0x1f7e2256, 0x20eb481c, 0x13f955cb, 0x3bab88b2, 0x374d}}, - /*.y =*/{/*.val =*/{0xdaf734a, 0x21d6faa6, 0xe543217, 0xa3598c0, 0x6f72938, 0xcb01be0, 0x14f99160, 0x196d93f3, 0x1711}}}, -{/*.x =*/{/*.val =*/{0x2ae7d616, 0x3a2992b5, 0x22a9f0c5, 0x136ebcad, 0x2eb0dc94, 0x1b81ce56, 0x2eae57c4, 0x30271fce, 0x2380}}, - /*.y =*/{/*.val =*/{0x161bbc1a, 0x266f920, 0x38467560, 0x2be48523, 0x9b09a93, 0x262bbf54, 0x956af15, 0x21864d19, 0x6f8e}}}, -{/*.x =*/{/*.val =*/{0x19c43862, 0x2a107856, 0x397e6690, 0x29fd3c60, 0x381bde71, 0x2061a26, 0x1ff21e6d, 0x3b4d3073, 0x385e}}, - /*.y =*/{/*.val =*/{0x142e5453, 0x1163f95, 0x86dc8cc, 0xc13bb08, 0x2bf4576b, 0x77867a7, 0x223f5670, 0x3af0fa3a, 0x283b}}}, -{/*.x =*/{/*.val =*/{0x38f2827c, 0x320e89c1, 0x2fc1ce2d, 0x320990af, 0x1f67d147, 0x1af84d35, 0x35480045, 0x8820f6b, 0xf6f6}}, - /*.y =*/{/*.val =*/{0x20aaa102, 0x56c82d4, 0x321bf6d, 0x15f29d12, 0x27cee7e6, 0x315c56cd, 0x33a0faf2, 0x13a05f79, 0x1bcd}}}, -{/*.x =*/{/*.val =*/{0x315adcb6, 0x3624c825, 0x18c6f369, 0x2470f39f, 0x1fc255cd, 0x32cf0f4, 0x13de2bd7, 0x394623e5, 0xfb26}}, - /*.y =*/{/*.val =*/{0x18ba68f3, 0x276f28ed, 0xb7ab544, 0x34b2cc6e, 0x10176916, 0x211a9c67, 0x2a34d58e, 0xa204404, 0xf3e1}}}, -{/*.x =*/{/*.val =*/{0x20788c1e, 0x35136dd5, 0x28bd1d7e, 0x230dc183, 0x3ceab7d1, 0x171af1d8, 0x1132d28f, 0x896446e, 0x8991}}, - /*.y =*/{/*.val =*/{0xe8f0ef1, 0xd71088a, 0x1ef9e116, 0x25a7213f, 0x3136fa36, 0x21d8d566, 0x1ac9b27b, 0x13661f32, 0xda8b}}}, -{/*.x =*/{/*.val =*/{0x3fac3a7, 0x181bb61b, 0x147fbc9c, 0x377e1296, 0x3dfa180f, 0x31ce9104, 0xf191637, 0x366e00fb, 0x6f9}}, - /*.y =*/{/*.val =*/{0x3a842160, 0x21a24180, 0x281002d, 0x29374bd7, 0x5c4d47e, 0x238a8c39, 0x59ba69b, 0x31a3980c, 0x7c80}}}, -{/*.x =*/{/*.val =*/{0xb7fd72d, 0x327489d1, 0x3e4da175, 0x5d17969, 0x82939da, 0x30db0a11, 0x3411c1cd, 0x3bba894a, 0xae86}}, - /*.y =*/{/*.val =*/{0xeee38bc, 0xcd32de9, 0x72f7282, 0x24845545, 0x1ff0e98d, 0x2c2b3962, 0x302f962a, 0x24f25c1c, 0x19e9}}}, -{/*.x =*/{/*.val =*/{0x3c169290, 0x2851d099, 0x336f2ee7, 0x62f9d73, 0x1c2c4887, 0x34be315b, 0x3ff55e61, 0x327e42ef, 0x2248}}, - /*.y =*/{/*.val =*/{0x83ea257, 0x1a76284a, 0x1da2be23, 0x18dd408d, 0x35ba18e1, 0x1aed56d0, 0x1eed7a50, 0x251a4b48, 0xfa05}}}, -{/*.x =*/{/*.val =*/{0x350964e3, 0x3436b12e, 0x11c6f76f, 0x27c21df7, 0x85d0a9, 0x46d2365, 0x44074ac, 0x1b85b817, 0xe11a}}, - /*.y =*/{/*.val =*/{0x682bfc8, 0x19fefe2c, 0x318c6f7, 0x2b71b84e, 0x30af2417, 0x3578965b, 0x2d430e1a, 0x196e1e8, 0x87d6}}}, -{/*.x =*/{/*.val =*/{0x2d0e6bd, 0xedf839d, 0x30f5e531, 0x1d3458f6, 0xd6ecbf7, 0x851f041, 0x4e2582a, 0x3500490f, 0x3322}}, - /*.y =*/{/*.val =*/{0x2c28b2a0, 0x13ce8ba5, 0x2873af62, 0x17d8fa8, 0x1af9b728, 0x66f137, 0x24ef5bfb, 0x1e5fa59, 0x56e7}}}, -{/*.x =*/{/*.val =*/{0xade462, 0x31a5b4cb, 0x2dbcf29f, 0x1337723a, 0x80cd50d, 0x3bcc6c13, 0x2bdae120, 0x8009433, 0x8d26}}, - /*.y =*/{/*.val =*/{0xf26470c, 0x2382a2e4, 0x2678b3ad, 0x12bed39c, 0x2e36ba1d, 0x3dbcb70f, 0x3f437d31, 0xeed1c56, 0xebed}}}, -{/*.x =*/{/*.val =*/{0x1516e633, 0x59190f8, 0x32d9c8b9, 0x3524c341, 0x14d03b8e, 0x1a287d6, 0x2bea9ce4, 0x301d9bab, 0x1238}}, - /*.y =*/{/*.val =*/{0x77b7805, 0x1736dca3, 0x7402280, 0x11894b73, 0x3dc1709, 0x25e78b47, 0x31359d6c, 0x2c0b6ec9, 0x8a9d}}}, -{/*.x =*/{/*.val =*/{0x388e7a66, 0x26c05549, 0x30ec2161, 0x3735ca0a, 0x2a11b9cd, 0xba9d629, 0x39c15e7b, 0x16c1dc32, 0x271d}}, - /*.y =*/{/*.val =*/{0x203c9727, 0x2a35c963, 0x8a824e7, 0x281978d4, 0x2c877fe2, 0x1f426526, 0x3f491e45, 0x29160d39, 0x5d3a}}}, -{/*.x =*/{/*.val =*/{0x134ab83, 0x875d34a, 0x36433977, 0x6cfe6bd, 0x26586874, 0x5dc3625, 0xb7da2bd, 0xb1f4b78, 0x8567}}, - /*.y =*/{/*.val =*/{0x390313a6, 0x238c253d, 0x1298f44c, 0x1fc5ff31, 0x22c2e5e7, 0x10126fe9, 0x3b2eb637, 0x6e6d6d0, 0x7c48}}}, -{/*.x =*/{/*.val =*/{0x1f17fc25, 0x262e42f0, 0x32e6d969, 0x227a91b7, 0x8a61f3b, 0x6184857, 0x39ec036c, 0x33dadd03, 0x534c}}, - /*.y =*/{/*.val =*/{0xfe86e76, 0x1c71fdbb, 0x3dd28ddd, 0x38f49def, 0x1543550a, 0x2b8f74cb, 0x32ddb462, 0x172c2722, 0xd571}}}, -{/*.x =*/{/*.val =*/{0x28bee8b6, 0x1c5c248f, 0xfbc8d2c, 0x8351fb, 0x38aaed79, 0x38508063, 0x3b7f3081, 0x7d73ba1, 0xa91d}}, - /*.y =*/{/*.val =*/{0x10644c1, 0xf45aa9, 0x28cb2250, 0x15a7d8, 0x1ad3b2f8, 0x6272377, 0x38ee15a7, 0xc93b8b7, 0x748a}}}, -{/*.x =*/{/*.val =*/{0x1984cf74, 0x28687095, 0x2f61f10a, 0xd6b916f, 0x14383c07, 0x853778b, 0x8e35c1a, 0x2308f643, 0xc15c}}, - /*.y =*/{/*.val =*/{0x39ccb000, 0x12923360, 0xb015a2c, 0x2fddcb54, 0x1fd7ba47, 0x31bd1789, 0x22235c8d, 0x15360a14, 0x2ba9}}}, -{/*.x =*/{/*.val =*/{0x20c82a0a, 0x3f6566bd, 0x3668832f, 0x2489b183, 0x1413b10f, 0x1b27c646, 0x188a46b0, 0x2fe026c6, 0x948}}, - /*.y =*/{/*.val =*/{0x18c8e589, 0x132dfe23, 0x17cd2bed, 0x137fc232, 0x3418c6d, 0x2dd31747, 0x36646dc6, 0x18a15b72, 0x53a5}}}, -{/*.x =*/{/*.val =*/{0x3e8b000a, 0x25bac115, 0x2825e513, 0x5b04cc7, 0x11f0b6ef, 0x3393198a, 0x259360d5, 0xb1fcdcb, 0x2695}}, - /*.y =*/{/*.val =*/{0x5ef705a, 0x30f5007c, 0x13d67318, 0x2f8e63d9, 0x288422de, 0x3224f4b5, 0xa68862b, 0x3a931600, 0xf513}}}, -{/*.x =*/{/*.val =*/{0x36134f96, 0x4096225, 0x2d6b0e9f, 0x846595c, 0x1ff243f5, 0xafa2c4c, 0x3c5bdbef, 0x1639bf08, 0xc62e}}, - /*.y =*/{/*.val =*/{0x114cf97e, 0x89dfb53, 0x3731c3e8, 0x3ee14d58, 0x141fc5bc, 0x359d9d4c, 0x1a1678c3, 0x209f516c, 0x4397}}}, -{/*.x =*/{/*.val =*/{0xb188cbb, 0x1a1be200, 0x7de973, 0x700c802, 0x2622b0b8, 0xcca69c5, 0x5c74168, 0x181483bb, 0x1074}}, - /*.y =*/{/*.val =*/{0x1f272124, 0x75ed8d8, 0x1ce3da60, 0xb835d23, 0x354a1124, 0x9ae6e73, 0x1598c353, 0x35302688, 0xabe5}}}, -{/*.x =*/{/*.val =*/{0x338fd8e8, 0x33b36067, 0x69752ac, 0x2c39137f, 0x2873a8f1, 0x19f383c0, 0x1c34f0, 0x339fd186, 0x6260}}, - /*.y =*/{/*.val =*/{0x32b4ae17, 0x6a13a56, 0x51c198c, 0x34a488e0, 0x2a1ef7ec, 0x24125dd, 0x1b571a7f, 0x2a0adbe9, 0xbc2d}}}, -{/*.x =*/{/*.val =*/{0x3d477c2d, 0x1d99d1bc, 0x2aad27e0, 0x39971465, 0xf1a1316, 0x21026fa1, 0x11a73dec, 0x3691d22b, 0x85d8}}, - /*.y =*/{/*.val =*/{0x7d1dd70, 0x1e605bf, 0x3c4d5a62, 0x2c28080c, 0x2fc7bc94, 0x2d4d94c7, 0x6690586, 0x22d4d997, 0x5894}}}, -{/*.x =*/{/*.val =*/{0x2c0b80d9, 0x2140c4b5, 0x3dc47f04, 0x79f8403, 0x3ee3ee4d, 0x224ba730, 0x4b968c0, 0x1c59b9fb, 0x8e2a}}, - /*.y =*/{/*.val =*/{0x16b29f50, 0x27187cab, 0x306349a4, 0x25eda235, 0x2a9d4852, 0x374a6dc5, 0xbe592ce, 0x2ea6b8b, 0xeadb}}}, -{/*.x =*/{/*.val =*/{0x2c4561be, 0x2487e8f4, 0x359d90f9, 0x12acba04, 0xf8950ee, 0xd9bb35e, 0x3f58edc8, 0x31d610af, 0x769b}}, - /*.y =*/{/*.val =*/{0x30d9685f, 0x16482ffe, 0x37873add, 0x285ddd9e, 0x3f5d4741, 0x33933bdc, 0x383bac8d, 0x5cd8bf9, 0x4bf8}}}, -{/*.x =*/{/*.val =*/{0x2037fa2d, 0x254f3234, 0x1bfdc432, 0xfb23d5d, 0x3f410304, 0xd21052e, 0x1d8d43d8, 0x1f782bf0, 0xe503}}, - /*.y =*/{/*.val =*/{0x1d755bda, 0x3977210, 0x481f10e, 0x17d6c0fb, 0x190bddbd, 0x263427ee, 0xd3b5f9f, 0x14d2eaa5, 0x4571}}}, -{/*.x =*/{/*.val =*/{0x1e3d34ef, 0x318f231e, 0x12a2ddb8, 0x2ac85f1e, 0x161b3ec3, 0x2db3df4b, 0x15494f40, 0x36919ff, 0xa5e0}}, - /*.y =*/{/*.val =*/{0x2f7adb4c, 0x21571738, 0x10900acb, 0x18373f9e, 0x3f43d25b, 0x1c9bfa66, 0x8555421, 0x397d7958, 0x98f}}}, -{/*.x =*/{/*.val =*/{0x17b91252, 0x19cdc583, 0x77572ae, 0x12bf4b91, 0x1bfbc46d, 0x27d2ec72, 0x22b40351, 0x57d7bce, 0xa994}}, - /*.y =*/{/*.val =*/{0xbedc264, 0xe8ddeb1, 0x10f4ddd7, 0x2685ab56, 0x36f6b689, 0xbc43c93, 0x1f84bb9e, 0x39932ba0, 0x82d0}}}, -{/*.x =*/{/*.val =*/{0x2a540f17, 0x231196d9, 0x30c132bd, 0x1d435c17, 0x3935f84c, 0x3b778263, 0x3d1fc7d8, 0x13a7e793, 0xb56f}}, - /*.y =*/{/*.val =*/{0x200102d, 0x1a8bf2b8, 0x3cca8544, 0x350a58f2, 0x182d1d21, 0x3046b7c1, 0xa856d3d, 0x394d0a73, 0x32e8}}}, -{/*.x =*/{/*.val =*/{0x24fce725, 0x1619a82b, 0x2a6c5b72, 0x3a36f471, 0x1771b4e7, 0x2a417a3c, 0x207adf5e, 0x1cac3d28, 0xe063}}, - /*.y =*/{/*.val =*/{0xeee31dd, 0x9c0d3e5, 0x3104870b, 0x12129de1, 0x1a488cd7, 0x9eecab5, 0x18cfe12a, 0x225d2f38, 0x7a90}}}, -{/*.x =*/{/*.val =*/{0x3ed2ff3e, 0x3826bb90, 0x2c6ed3cf, 0x17aff6d3, 0x2d3f3c04, 0x36f4c13e, 0x6b8f9c8, 0x4d32881, 0xeac}}, - /*.y =*/{/*.val =*/{0x3d210988, 0x5c81881, 0x3f21376e, 0x67da5ad, 0x311799ac, 0x3c40efca, 0x19b4245b, 0x36f9e4d, 0x4963}}}, -{/*.x =*/{/*.val =*/{0x1fbfa4dc, 0x1d9c1b93, 0xc85b174, 0x25229e01, 0x1bb41ff5, 0x84675eb, 0x3ea19839, 0x21641cc7, 0xd678}}, - /*.y =*/{/*.val =*/{0x3d3b5406, 0x29ef35ae, 0x1c9a07cc, 0x1bc7137, 0x1c13aa62, 0x3bd71b48, 0x63c4940, 0x2a322754, 0x28ea}}}, -{/*.x =*/{/*.val =*/{0x248ff9b3, 0x9d7ed03, 0x199b01a7, 0x2c698815, 0x371d4bc7, 0x3c843c4a, 0x40974ab, 0x3f32f668, 0x6930}}, - /*.y =*/{/*.val =*/{0xee96a4e, 0x3f76ad7e, 0xacc51ac, 0x3e6c4f9, 0x1f6d7809, 0x3f36e1d, 0x301eada3, 0x2ba52e51, 0x7f02}}}, -{/*.x =*/{/*.val =*/{0x10559754, 0x2b5a423, 0x2a3f5854, 0x2c42f778, 0xce02204, 0x2efe770, 0x1d45358d, 0x1e9c5735, 0x213c}}, - /*.y =*/{/*.val =*/{0x34b458f2, 0x3fcb09d4, 0x36a7eedd, 0x12143d7c, 0x1ba190bb, 0xeb41891, 0x6250701, 0x2b42d6b9, 0x4b6d}}}, -{/*.x =*/{/*.val =*/{0xec87fac, 0x264e2578, 0x22e7cf08, 0x6ae5d18, 0x23480e0d, 0x3a7fb60c, 0x9a7f66a, 0x15204cad, 0x1c5e}}, - /*.y =*/{/*.val =*/{0x1fc2d4ef, 0x1575ecf5, 0x2fe324c5, 0x37ab3ac9, 0xc2ad3a3, 0x2567e875, 0x3468f2bb, 0x3d83e0df, 0x4ffc}}}, -{/*.x =*/{/*.val =*/{0x14531dbc, 0x83f2e87, 0x2d5c970e, 0x2407067f, 0x3bc7ce1f, 0x1ba50842, 0x1668ddef, 0x1b4180b1, 0x4627}}, - /*.y =*/{/*.val =*/{0x1686b8e2, 0x3e1cc026, 0x3e1bc99a, 0x22eb7eff, 0xded9949, 0x248a1d5c, 0x75b84a2, 0x1fc93513, 0xe0f}}}, -{/*.x =*/{/*.val =*/{0x122f001d, 0x453bc4d, 0x78d8996, 0x14382b37, 0x31916368, 0x17ac8470, 0x2c24f4e6, 0x1a3b29e9, 0xefea}}, - /*.y =*/{/*.val =*/{0x33bc4415, 0x4a1067d, 0x3848771c, 0x4e567ec, 0x319a17e4, 0x140c1e8d, 0x3c14da1, 0x11e1a756, 0xaab8}}}, -{/*.x =*/{/*.val =*/{0x8fbd53c, 0x330e8ec, 0x1c62cddf, 0x20e31c2b, 0x19a87e2, 0x2e4d4a95, 0xb34e8db, 0x9ca9ebd, 0x4e7c}}, - /*.y =*/{/*.val =*/{0x17dcaae6, 0x2ce5060, 0x3f7dd33e, 0x2e5852f, 0x2f681b53, 0x3f427db7, 0x10b18e16, 0x271d9b27, 0x1774}}}, -{/*.x =*/{/*.val =*/{0x3c6e1b4d, 0xa0879b9, 0x3ef8790e, 0x47c9686, 0x385d9c9b, 0x289a7d38, 0x2888f268, 0x5ec09a5, 0x8990}}, - /*.y =*/{/*.val =*/{0x1814ab2b, 0x26baf6b, 0x132b2120, 0x3946f03e, 0x358bfae4, 0x15e60cd8, 0x334f0bb4, 0xb36ad6c, 0x43ae}}}, -{/*.x =*/{/*.val =*/{0x3e5f712f, 0x3c98d685, 0x1b583a8a, 0xc7d6fe4, 0x227f0e28, 0x11ca398c, 0x5fd4a8f, 0x113ddba4, 0x67f6}}, - /*.y =*/{/*.val =*/{0x307160e5, 0x1a2b2d79, 0x3d36198d, 0x385223d, 0x6cf785e, 0x2b7aded6, 0x5d04f05, 0x35a3d991, 0xb833}}}, -{/*.x =*/{/*.val =*/{0x3b89a762, 0x4098fb4, 0x2ee6b8dc, 0x3724c04, 0xb471293, 0x281525a, 0x12555fa8, 0x21db24d9, 0x327f}}, - /*.y =*/{/*.val =*/{0x39203301, 0x327f6566, 0x2bd7dfe9, 0x14d41c3f, 0x1997b975, 0x25a49578, 0x24026b09, 0x13aacd4, 0xb2d4}}}, -{/*.x =*/{/*.val =*/{0xfb27b6, 0x909f8a1, 0x24305763, 0x1b8f6caf, 0x286aa5c7, 0x8e2b585, 0x38b1b10f, 0x138f6f9d, 0xfea7}}, - /*.y =*/{/*.val =*/{0x323cb96f, 0x74f6df, 0x33f7b777, 0x1ad65ae5, 0x36af9312, 0x19d37b32, 0x313297cf, 0x1a36e6c2, 0x6e05}}}, -{/*.x =*/{/*.val =*/{0x1f9756e4, 0x3f65f258, 0x23730488, 0x15c3b977, 0x28cd0ebb, 0x380f6143, 0x280ff180, 0x10720c10, 0xed94}}, - /*.y =*/{/*.val =*/{0x3f3abfae, 0x3c3827e4, 0x24de98bf, 0x3c8ddd3f, 0x13911e09, 0x5d84a2c, 0x3fa19afa, 0x27a7bfa2, 0x3dbe}}}, -{/*.x =*/{/*.val =*/{0x151cf119, 0x16eb40cf, 0x3ab4d301, 0x42f7613, 0x3487515b, 0x3b4fd892, 0x27c3fc9f, 0x1a63b99e, 0x29d9}}, - /*.y =*/{/*.val =*/{0x35056339, 0x3221d015, 0x3a7c2963, 0x272503a4, 0x31c96fb8, 0x28495013, 0x2b45277, 0xb145f72, 0x7fd0}}}, -{/*.x =*/{/*.val =*/{0x3f422491, 0x19f1114d, 0x2060cff4, 0x114f92a1, 0x180a31fd, 0x3edef4cd, 0x3936d6f3, 0x15f41404, 0x126b}}, - /*.y =*/{/*.val =*/{0x1da3ef84, 0x3e8c7c66, 0x3f39347a, 0x122eb0c2, 0x3f3fb0e1, 0x128fae8a, 0x262c2e3c, 0x3704c185, 0xc1a7}}}, -{/*.x =*/{/*.val =*/{0x17bdde39, 0xb00a910, 0x36043295, 0x11385e6d, 0x1968d315, 0x95c3566, 0x3cf0e10a, 0x1044fd9d, 0x76e6}}, - /*.y =*/{/*.val =*/{0x1901ac01, 0x12c5d4b4, 0x16d2032b, 0xa8cf4ad, 0x1f0d35e, 0x19b5c1a, 0x295cf577, 0x37e37b93, 0xc90d}}}, -{/*.x =*/{/*.val =*/{0x3a1187a5, 0x33e666a0, 0x29ae691, 0x1755d88b, 0x21c81000, 0x1f276205, 0x2c73bee8, 0x14c3a794, 0x708a}}, - /*.y =*/{/*.val =*/{0x73db9c0, 0x2293c66d, 0x1353e8a5, 0x3369cf1b, 0x2d38283e, 0x195b72ed, 0x1a897fa9, 0x1204787e, 0x9b88}}}, -{/*.x =*/{/*.val =*/{0xde4f5be, 0x386c5b1b, 0x2b2b59e2, 0xdd2db61, 0x2462cf9f, 0x35920e57, 0x33be219b, 0xd3f122, 0x19cf}}, - /*.y =*/{/*.val =*/{0x2f321af2, 0x2a454cad, 0x30f1c0c0, 0x2474724f, 0x181947ef, 0x12f9a2ac, 0x2b466c3b, 0xac1a856, 0x28e3}}}, -{/*.x =*/{/*.val =*/{0x117cf3e8, 0xeaf0827, 0x3ea2219e, 0x24ef40d2, 0x17f576ee, 0x670be0e, 0x35f0d7c7, 0x11281e32, 0xaf6c}}, - /*.y =*/{/*.val =*/{0x1751baea, 0x22b74180, 0xa0d435b, 0xd8aba9f, 0x3246dfec, 0x39cc54f2, 0x14b30af9, 0x25bfa17, 0x784}}}, -{/*.x =*/{/*.val =*/{0x2bcbb891, 0x2ac54090, 0x326cbee3, 0x1f3190f7, 0x3f8f9a8f, 0x206ea9d0, 0x2abe1e82, 0x315ac0ec, 0xc738}}, - /*.y =*/{/*.val =*/{0x299a84c3, 0x1f9cd765, 0x80cfe91, 0xc53bbde, 0x3fbbbb82, 0x63cbab2, 0x2d2537f7, 0x2d5e2546, 0x893f}}}, -{/*.x =*/{/*.val =*/{0x662ab1b, 0x36aac1e1, 0x1b8c9e4d, 0x1c65fa92, 0x27aa9464, 0xca9a64b, 0x37435b, 0x2117b35f, 0x5578}}, - /*.y =*/{/*.val =*/{0x56f3511, 0x5b463cc, 0x25d64de3, 0x14e9dd1a, 0x2a4053f6, 0x1b429474, 0x1e2c3cea, 0x1e5e2db, 0xe61d}}}, -{/*.x =*/{/*.val =*/{0x148b6c29, 0x13e1a6e2, 0xe399609, 0x3c48d53f, 0xceccd22, 0x3e8ef074, 0x364cc4ab, 0xe0e2228, 0x47f3}}, - /*.y =*/{/*.val =*/{0xe537ef9, 0x3b7b8448, 0xf994a81, 0x2ed26562, 0x16c7118, 0x39219d6d, 0x32937190, 0x26a343c0, 0x48ca}}}, -{/*.x =*/{/*.val =*/{0x5ff4adb, 0x2069b23c, 0xbef768a, 0x3d5c35bf, 0x25d5f614, 0x1ad3271a, 0x1b8cfe46, 0x7cd2b90, 0xc0c0}}, - /*.y =*/{/*.val =*/{0x2c351065, 0x313bfdce, 0xd15b85f, 0x2f10f45c, 0x35b8cecd, 0xde82d01, 0x17f5c7c9, 0x3d6fb90d, 0xb84}}}, -{/*.x =*/{/*.val =*/{0x8f6c14b, 0x1cba7d96, 0x29250143, 0x35cb97ce, 0x172877d1, 0x131d8df2, 0x25b81e26, 0x1899522d, 0xd895}}, - /*.y =*/{/*.val =*/{0x1d7d991f, 0x24d8fb5d, 0x3b067e17, 0x10a358ca, 0x340eb03, 0x3b182063, 0x7eae728, 0x2a8e3caf, 0xfebf}}}, -{/*.x =*/{/*.val =*/{0x37078424, 0x296d652d, 0x2c40c3fb, 0x3b2bde83, 0x3a26703, 0x290d8880, 0x1044e8a3, 0x1bbbe25c, 0xfd13}}, - /*.y =*/{/*.val =*/{0x671ddf1, 0x3587bbbf, 0x22adfa8c, 0x3cac7de2, 0x5efa57c, 0x74646d7, 0x252cc67a, 0x2a0d3cf1, 0x218d}}}, -{/*.x =*/{/*.val =*/{0xdb1cb3c, 0x3c7613b2, 0x3f024a5, 0x1c00e835, 0x119f861b, 0x33294d9d, 0x38d140e9, 0x23a77658, 0xd99e}}, - /*.y =*/{/*.val =*/{0x2b8637a7, 0x2228a78d, 0x3c8765cd, 0x21bfbe3f, 0xeba6e62, 0x16ecc86f, 0xa3a7a94, 0x66b4730, 0x36dc}}}, -{/*.x =*/{/*.val =*/{0x3c385172, 0x351bda34, 0x40e636f, 0xcd4781, 0x309191d2, 0x36295396, 0x18317a1b, 0x3c586686, 0x3fd}}, - /*.y =*/{/*.val =*/{0x3ccb9794, 0x26b19fc3, 0xe7232b7, 0x26e4a7a4, 0x573755b, 0x1c31f4f2, 0x12c3fe4, 0xb01b97, 0x408d}}}, -{/*.x =*/{/*.val =*/{0xf676e03, 0x24542959, 0x3e84edd4, 0x3ff1cda4, 0x1e8761ce, 0x3d90cd5c, 0x17518eb0, 0x2500caa5, 0xb8da}}, - /*.y =*/{/*.val =*/{0xefdf6e7, 0x1223939d, 0x1ff3b511, 0x33161365, 0x2808b092, 0x267325d8, 0x1a1e4d7c, 0x37e91201, 0x2804}}}, -{/*.x =*/{/*.val =*/{0x5af726a, 0x104fd053, 0x25bf6e6d, 0x268f972c, 0x3620f946, 0xb2da62a, 0xc5ce53f, 0x34417b63, 0x6d36}}, - /*.y =*/{/*.val =*/{0x13f9fc7d, 0x15c12468, 0x108a35c, 0x31664dad, 0x50029dc, 0x2319b257, 0x3669e72d, 0x170d38dd, 0xe4ba}}}, -{/*.x =*/{/*.val =*/{0x2540db99, 0x1b8a8c32, 0x34b81228, 0x4c27014, 0x30b0e3eb, 0x220fe99b, 0x3ac0cd06, 0x2f784334, 0x3ab6}}, - /*.y =*/{/*.val =*/{0x1bda78a3, 0x1a1cff8c, 0x369c043e, 0x344dec38, 0x13e99c38, 0x45ea5a8, 0x71d7fc3, 0x1881e6fa, 0xbaca}}}, -{/*.x =*/{/*.val =*/{0x1f1048da, 0x1ddefc9e, 0x3ddd3ba7, 0xbf53cdc, 0x7bce2ba, 0x281a7674, 0x156f0fdb, 0xd38fc6b, 0x7966}}, - /*.y =*/{/*.val =*/{0x2106cf01, 0x23e6f892, 0x3d74862e, 0x95db633, 0x3927f253, 0x39d1cd69, 0x20b8956d, 0x38adb3ec, 0x4d8e}}}, -{/*.x =*/{/*.val =*/{0x23c0df5d, 0x6845de3, 0x156a792f, 0x67bfed4, 0x1d7fab20, 0x2b6ae51d, 0x3b33a7d8, 0x3a851107, 0xe80f}}, - /*.y =*/{/*.val =*/{0x2ac9ec78, 0x32d0a46d, 0x3322ea9f, 0x557a02b, 0xa94472d, 0x25da328f, 0x200771e8, 0x379fd8e3, 0xeed1}}}, -{/*.x =*/{/*.val =*/{0xf83cd58, 0x36c39e2c, 0x3d2f9162, 0xb730e1d, 0x3e7a3712, 0x2b13b47b, 0x1265981, 0x287c23a9, 0x440c}}, - /*.y =*/{/*.val =*/{0x388a3f4b, 0x1ef01a6, 0x1c0a260b, 0x793509a, 0xe2f02a2, 0x25537275, 0x2e122af8, 0x2c34b357, 0xa6c8}}}, -{/*.x =*/{/*.val =*/{0x12998b10, 0x206f689c, 0x1b229d9e, 0x31c3af30, 0x2907819b, 0x1fe0a74e, 0x26c1cc5f, 0x32ebcae5, 0xf694}}, - /*.y =*/{/*.val =*/{0xf05e51, 0x19e22c5c, 0x3c2a47f, 0x1b1930c6, 0x6d82aeb, 0x317feb31, 0x2f03d633, 0xfae986f, 0x40a6}}}, -{/*.x =*/{/*.val =*/{0xdd553fd, 0x25684cd6, 0x8b6414f, 0x2afda570, 0x22595047, 0x1b53d0e6, 0x2684850b, 0x218a8d55, 0x8b6e}}, - /*.y =*/{/*.val =*/{0x3e9be5ed, 0x200f6b4c, 0x3383d0d, 0x2b0f1686, 0x2b9fa124, 0x2f0b7d3, 0x11cb40d1, 0x22443b4, 0xea5e}}}, -{/*.x =*/{/*.val =*/{0x4e16070, 0x3701eef3, 0x2fd6915d, 0x286080c7, 0x167543f2, 0x29239475, 0x1704313b, 0x1a5ef7f3, 0xa301}}, - /*.y =*/{/*.val =*/{0x1e177ea1, 0x30346810, 0xa11a130, 0xd76fdf0, 0x140f9b17, 0x2027e897, 0x3e4f5081, 0x3e473ed9, 0x7370}}}, -{/*.x =*/{/*.val =*/{0x324ba5ae, 0x5080c5b, 0x34b5d81, 0xe594013, 0xbff74b4, 0x23490678, 0x1f049f3e, 0x39673fde, 0x27e1}}, - /*.y =*/{/*.val =*/{0x83a45b3, 0x1296ffba, 0x2fa63f78, 0x122869a6, 0x39df05df, 0x2d78f3f1, 0xe209ee1, 0x9a9b201, 0x310b}}}, -{/*.x =*/{/*.val =*/{0x1caed7ae, 0x25a45d72, 0xfbfb4f9, 0xe6b77a1, 0x2d7e4f5a, 0x223b0e24, 0x24aee165, 0x39e97da1, 0xc712}}, - /*.y =*/{/*.val =*/{0x6156294, 0x134522a9, 0x30ce6378, 0x3639512, 0x1dd9e538, 0x352e08c4, 0x363b365e, 0x1041d458, 0x4964}}}, -{/*.x =*/{/*.val =*/{0x4a6db03, 0x2d0f87f9, 0x275d791, 0x32175bd6, 0x675fcb2, 0x303509ae, 0x3235d065, 0x141292c, 0xbfc}}, - /*.y =*/{/*.val =*/{0x64b8542, 0x22b23469, 0x5d4f055, 0x109c65cd, 0x26c99237, 0x23b1fe52, 0xf3453fb, 0x119e9b0d, 0x1955}}}, -{/*.x =*/{/*.val =*/{0x3fb04ed4, 0x2deb18f8, 0x1307fffa, 0x330cc2c4, 0x278de208, 0x3e741449, 0x2b936463, 0x216ce275, 0x90ad}}, - /*.y =*/{/*.val =*/{0xb6ef150, 0x24753523, 0x182894d9, 0x2bbeaf85, 0x3222b839, 0x372f6509, 0x38261aff, 0x1e8d8828, 0xe50}}}, -{/*.x =*/{/*.val =*/{0x27dc0151, 0x2062c3b6, 0x2707bad2, 0x496f991, 0x25e3d7e, 0x2c745521, 0x14077f44, 0x3503be32, 0x7e2c}}, - /*.y =*/{/*.val =*/{0x20721ec7, 0x28ef14e4, 0x2ee082c9, 0x26fb902b, 0x1ef95d88, 0x186a2cc8, 0xfab382a, 0x1d420ab7, 0x905b}}}, -{/*.x =*/{/*.val =*/{0x1345e597, 0x3840eb90, 0x3853cf90, 0x18dafe76, 0x2f52a79c, 0x25d6ef47, 0x2dace21c, 0x3d48656f, 0xa146}}, - /*.y =*/{/*.val =*/{0x345a770a, 0x19d59dab, 0x1f094b07, 0x19e96c88, 0x331b40ea, 0x25774b6e, 0x3feb09ae, 0x26c2ac14, 0xa5a9}}}, -{/*.x =*/{/*.val =*/{0xce45444, 0x32ed4ff1, 0x2ccc4e20, 0x379087bf, 0x1a8114db, 0x2fe76ac9, 0x193b9bcf, 0x1d6873c6, 0xd24c}}, - /*.y =*/{/*.val =*/{0x7dd4a57, 0x2e4c91a6, 0x1f1e524c, 0x1d64fd26, 0x25a78abf, 0x2df46043, 0x1c1d1cfc, 0x74b7a13, 0x58fe}}}, -{/*.x =*/{/*.val =*/{0x1ec4c0da, 0x2ded1132, 0x23ea3351, 0x23159e1c, 0x1f162ee8, 0x2706b660, 0x35f33923, 0x2e74bd8e, 0x8f68}}, - /*.y =*/{/*.val =*/{0x101fff82, 0x8f2fde5, 0x1510bfdf, 0x3a8b3fa5, 0x3e215dbb, 0x36430ada, 0x23986de1, 0x27cb6e81, 0x662a}}}, -{/*.x =*/{/*.val =*/{0xcf27076, 0x1a11f7e1, 0x3627eaee, 0x26162b79, 0x19af59d8, 0x3faf9dff, 0x28158fca, 0x2bbf5e13, 0x4d49}}, - /*.y =*/{/*.val =*/{0x3aa781e, 0x2e42d988, 0x1f4d8466, 0x3cb469f, 0x1ca6f06e, 0xfc840d6, 0x1d135e72, 0x3f166843, 0xcd32}}}, -{/*.x =*/{/*.val =*/{0x29b62026, 0x236f2d5c, 0x9d1d4ee, 0xa8f7822, 0x1c5aa78d, 0x1986787d, 0x16f8537d, 0x14e7a175, 0x7564}}, - /*.y =*/{/*.val =*/{0x1ace0cf3, 0x5cb23eb, 0xb79f334, 0x12ab3655, 0x32292568, 0x77d4929, 0x1b3c6523, 0x21504dd2, 0xc1d6}}}, -{/*.x =*/{/*.val =*/{0x17b4a278, 0xd936b35, 0x3f4082b5, 0x3d8697c7, 0x19ccc878, 0x1bfcc06b, 0x32779674, 0x245eb677, 0x210a}}, - /*.y =*/{/*.val =*/{0xc7b2231, 0x3c9c4ff4, 0x3f20bfc7, 0x227986ab, 0x16737d37, 0x26fa07e3, 0x1e57b7a3, 0x6d5142d, 0x670e}}}, -{/*.x =*/{/*.val =*/{0x13231e11, 0x1a1bf541, 0x3681e3e6, 0x123a1940, 0xc36091f, 0x267fe466, 0x385d65ff, 0x3ec05dab, 0xe4f3}}, - /*.y =*/{/*.val =*/{0x2feb73bc, 0x8b0e15d, 0x151d1c98, 0x31f9d3b2, 0x2b7286c, 0x69b43a8, 0x34f1c166, 0x18ceb43b, 0x1e63}}}, -{/*.x =*/{/*.val =*/{0x3bcdaf2f, 0x2ffb888c, 0x3a172953, 0x14c6a096, 0x1b362f88, 0x190442af, 0x373e01ec, 0x32edda19, 0x4b30}}, - /*.y =*/{/*.val =*/{0x3d26b5b7, 0x200cf518, 0x3485756, 0x37cf2079, 0x3c4a91f, 0x38b15ddf, 0x3629b6f9, 0xd40996e, 0x74c6}}}, -{/*.x =*/{/*.val =*/{0x2673059f, 0x3ffa70a6, 0xe0fa192, 0x45c5414, 0x64817ec, 0x16c82c5d, 0x1700dcd1, 0xd2a9eb8, 0xcbb4}}, - /*.y =*/{/*.val =*/{0x227c070c, 0x1f6a5908, 0x2d5f845b, 0x351793c2, 0x35dfad41, 0x35248ce2, 0x2bd17562, 0x802ad36, 0x4a1a}}}, -{/*.x =*/{/*.val =*/{0x6de12c0, 0x351e1b84, 0x34610e94, 0x2736b161, 0x17244c6d, 0x35ec79d5, 0x2c1cd06, 0x15b6704, 0xf478}}, - /*.y =*/{/*.val =*/{0xa5361fe, 0x269db39b, 0x1ab92d76, 0x305fbd82, 0x28694c26, 0x2578041, 0x23946e68, 0x39843ccf, 0x7f09}}}, -{/*.x =*/{/*.val =*/{0x20eae29e, 0x1bedbab8, 0x14e1d071, 0xd3cbc3, 0x1a4266c7, 0x1854de91, 0x3f331eb9, 0x3ea6c63a, 0x8c00}}, - /*.y =*/{/*.val =*/{0x2702414b, 0x1f4a9319, 0x1e36c54e, 0x3eb6bea0, 0x36c974c2, 0x30d0e8dc, 0x121a1a9d, 0x1c99ffa9, 0xefa4}}}, -{/*.x =*/{/*.val =*/{0x18ada5f, 0x21326ac3, 0x1122fb3e, 0x1f8a5fca, 0x2be1effd, 0x2d6fe58d, 0x2b46fa8b, 0x3005db68, 0x24cf}}, - /*.y =*/{/*.val =*/{0x178a586b, 0x23e984e6, 0xf814f26, 0x25672869, 0x2da927ed, 0x21c53577, 0x61a6986, 0x23eec1e7, 0xebff}}}, -{/*.x =*/{/*.val =*/{0x14679da2, 0x40c6256, 0x3f057edf, 0x37759ff1, 0x292ec616, 0x37b5ca84, 0x1bc82ea2, 0x1f56352e, 0x4a}}, - /*.y =*/{/*.val =*/{0x379ffe26, 0x21dfd211, 0x23fa28a4, 0x30ed2525, 0x71b3b71, 0x76051fb, 0x2cb75e6b, 0x316dd9c0, 0xb98a}}}, -{/*.x =*/{/*.val =*/{0x87c4b65, 0x33cd3ab7, 0x207b2a9c, 0x3e202287, 0x26ce4996, 0x1b178b01, 0x1c7fc7, 0x1a7132f4, 0xee7d}}, - /*.y =*/{/*.val =*/{0x1136a95a, 0xfa3d13b, 0x2e942e52, 0xfa2666e, 0xf2ee2c3, 0x24aafc0c, 0x13821a1, 0x189bb069, 0xecc8}}}, -{/*.x =*/{/*.val =*/{0x20cb3e41, 0x25ff77f1, 0x8b92c09, 0xf4213cc, 0x298ed314, 0x33b02a7, 0x829f3e1, 0x1b39a775, 0xe7a2}}, - /*.y =*/{/*.val =*/{0xf2cfd51, 0x3a2a5087, 0x20e83e20, 0x29acb010, 0x2fbb18d0, 0x2c01a86a, 0x3984b471, 0x238c03e9, 0x2a75}}}, -{/*.x =*/{/*.val =*/{0x3b4ae861, 0x25f96e45, 0x2e32fa9d, 0xf0d7935, 0x2089f520, 0x22fed9dc, 0x3f8d00d3, 0x3eae80da, 0xf5ca}}, - /*.y =*/{/*.val =*/{0xd82239c, 0x32708e70, 0x12f05f3c, 0xecaa715, 0x839159b, 0x3e641190, 0x26d817bf, 0xee2808a, 0x19e8}}}, -{/*.x =*/{/*.val =*/{0x3d2a9651, 0x13f5335e, 0x14c98208, 0x27942712, 0x2805428f, 0x3d455b5f, 0x23f1f12d, 0x240933ad, 0xe938}}, - /*.y =*/{/*.val =*/{0x1e786824, 0x3bf78add, 0x2770bfef, 0x1c4433b1, 0x31aaf18d, 0x21eaebd9, 0x26595f92, 0x1a21c8dc, 0x8648}}}, -{/*.x =*/{/*.val =*/{0x3cddab8b, 0x3cb506b9, 0x3c68e6fc, 0x3934494, 0x2d0c379f, 0x5a40360, 0x1256bed1, 0x16761e0a, 0x2645}}, - /*.y =*/{/*.val =*/{0x1de473, 0x27d92d14, 0x1caf1e6c, 0x218c6bce, 0x72d77a, 0x2f18dc0d, 0x3512cef7, 0x2f4649b4, 0x79e5}}}, -{/*.x =*/{/*.val =*/{0x1e6b80ef, 0x33ca7acf, 0x179424f3, 0x32f2e59f, 0x3cbdc571, 0x1503088e, 0x22ec8d23, 0x2783b8d9, 0xb645}}, - /*.y =*/{/*.val =*/{0x1a71ba45, 0xc2fc2d8, 0xe35b2ff, 0x2ceb9b52, 0x261db3c4, 0x2b7c5b95, 0x3e06de1d, 0x21db41bc, 0x67c}}}, -{/*.x =*/{/*.val =*/{0x33eb51f, 0x14fbcdd4, 0x279c2112, 0x22415daf, 0x341593b6, 0xdbdcc07, 0x23c88e4d, 0x3a3c3660, 0xe5d8}}, - /*.y =*/{/*.val =*/{0x1a62a2d9, 0x2756f659, 0x1f0f5497, 0x27711b6, 0x3eeef0e5, 0x5a95f63, 0x23e04abb, 0x3a6de187, 0x4dc1}}}, -{/*.x =*/{/*.val =*/{0xf155e64, 0x1e99d920, 0xa301173, 0x19af93ea, 0x3ae0ddab, 0x2c3dcc86, 0x8c3dc56, 0x9fddf6f, 0xa9ca}}, - /*.y =*/{/*.val =*/{0x161b3297, 0x3cfcccf1, 0x3caf0ae1, 0x17506086, 0x2d00487, 0x1f4891b0, 0x314d4d19, 0xcd59e3e, 0xf4bb}}}, -{/*.x =*/{/*.val =*/{0x16ee247c, 0x352f18a7, 0x351cee06, 0x11e3a11f, 0xfe7591f, 0x28415847, 0x2d7f25eb, 0x1c6001a1, 0x68fb}}, - /*.y =*/{/*.val =*/{0x1a01865d, 0x387e08b4, 0xc73c9da, 0x235602c1, 0x1b0c079a, 0xd509d40, 0x19636737, 0x348d18b7, 0xcd12}}}, -{/*.x =*/{/*.val =*/{0x96943e8, 0x3b683d6d, 0x273c5a5d, 0x1bc7f19f, 0xf06231d, 0x8d2a846, 0x3b840793, 0x20320a02, 0xd68a}}, - /*.y =*/{/*.val =*/{0x2b133120, 0x25321099, 0x45295a2, 0x39ee3de, 0x30e28b5b, 0x2c7e45de, 0x186d00c4, 0x2a7ffd2d, 0xdb8b}}}, -{/*.x =*/{/*.val =*/{0x2412b6fd, 0x2f6888b2, 0x3702b828, 0x3b414f1b, 0x12373cac, 0x3e3becdd, 0x240be402, 0x102719de, 0xf16a}}, - /*.y =*/{/*.val =*/{0x2ca052da, 0x1a36b9df, 0x9ebca42, 0x15019649, 0x230e4e16, 0x1a9d69d3, 0x32799d7a, 0xc45c514, 0x2a41}}}, -{/*.x =*/{/*.val =*/{0x326dd4e4, 0x30682db8, 0x3ed98325, 0x27d3cbda, 0x36f84db8, 0xdfda665, 0x26f42fbe, 0x2d41aadd, 0x4154}}, - /*.y =*/{/*.val =*/{0x75ded1c, 0x32164a54, 0x1e22dd46, 0x13aa7674, 0x25ff641, 0x1b913584, 0x1988894c, 0x1d410f1, 0x23ad}}}, -{/*.x =*/{/*.val =*/{0x3f7f0246, 0x31469e98, 0x727ddf4, 0x3a1b927f, 0x1956ea93, 0x2a35342d, 0x95c1080, 0x1949da73, 0xb73c}}, - /*.y =*/{/*.val =*/{0x2a2a407b, 0x25f94593, 0x2e554e55, 0x35cb931, 0x36c1ea1a, 0xd624f16, 0xca9d4b5, 0x36c41c5d, 0x9a67}}}, -{/*.x =*/{/*.val =*/{0x28d3d5d, 0x256603f, 0x3449cea4, 0x4abae5c, 0x3a30b096, 0x3009c241, 0x804252d, 0x3b5f7d97, 0x324a}}, - /*.y =*/{/*.val =*/{0x16ab7c84, 0x19c892be, 0x23328439, 0x84ec31f, 0x2c1f4f19, 0x3030d6b, 0x21f2ff13, 0xd95dd2d, 0x648a}}}, -{/*.x =*/{/*.val =*/{0x32919749, 0x23ce0e06, 0x1e0db1fa, 0xacf92a3, 0xd7203f7, 0xc9a0620, 0x3490228d, 0xcc7a89b, 0x32c9}}, - /*.y =*/{/*.val =*/{0x3290b5e3, 0xc7a5ec3, 0x239ab096, 0x2292af6b, 0x33dbb826, 0x28bc0adb, 0x9cb5695, 0x9cacd08, 0xd7cd}}}, -{/*.x =*/{/*.val =*/{0x3b9795e4, 0x38708949, 0x1846b8e1, 0x30586db8, 0x2c6b1c69, 0xbda9c3f, 0x37854a0, 0xbcecee6, 0xeb29}}, - /*.y =*/{/*.val =*/{0x2e53a0fe, 0x2dfa74be, 0x1111c6f5, 0x4c75d42, 0x5835b57, 0x198d2bc5, 0x2be80169, 0x3096a5bb, 0x8c43}}}, -{/*.x =*/{/*.val =*/{0x9303fdd, 0x3a8e755e, 0x1d1ed35a, 0x1c515fc6, 0x9fbe14d, 0x350c401, 0x35ef2e62, 0xe8077ce, 0xa65a}}, - /*.y =*/{/*.val =*/{0x2e68703, 0x2b512a34, 0x3aed3cad, 0x21874093, 0x2d2c7686, 0x10f63643, 0x35c6fb8f, 0x2825033f, 0x798e}}}, -{/*.x =*/{/*.val =*/{0x3d054c96, 0x3a2f4dcf, 0xd1ca888, 0x31050eea, 0x3ee5dcee, 0x77f6f97, 0x1e61f6d5, 0x30524673, 0x4df9}}, - /*.y =*/{/*.val =*/{0xad10d5d, 0xbaeb01b, 0x28849019, 0x3541b370, 0x1d85d4b5, 0x25d308e8, 0x18728050, 0x3b14424b, 0x35}}}, -{/*.x =*/{/*.val =*/{0x1da49e04, 0x31ac3f0, 0x17a8d70c, 0x37915539, 0x387088e9, 0xc5f5392, 0x998cd25, 0x32b634b3, 0xed32}}, - /*.y =*/{/*.val =*/{0x3c1db9e0, 0x18c48345, 0x9fab7db, 0x36a7eb2d, 0x19d20b52, 0x728dd61, 0x30204a54, 0x3bd7c740, 0x129f}}}, -{/*.x =*/{/*.val =*/{0x2883f855, 0x2dd06353, 0x3c34016c, 0x30db72d8, 0x30366e28, 0x27904471, 0x360f1804, 0x2adc9358, 0xe821}}, - /*.y =*/{/*.val =*/{0x19852ddf, 0x353831a9, 0xec23efe, 0xec67185, 0x16cf598b, 0x3504550, 0x13ce367d, 0x32fe18fd, 0xadef}}}, -{/*.x =*/{/*.val =*/{0x3441742e, 0x2ffd67ba, 0x33806e9f, 0x52951eb, 0x1693a72f, 0x1514bef2, 0x2d212f45, 0x22653946, 0x3f0d}}, - /*.y =*/{/*.val =*/{0xfecadbe, 0x3194d8ef, 0x2d13d958, 0x8178b0e, 0x3a6e0b1e, 0x172c3a11, 0x3dc445e, 0x1b08fca3, 0xfbd7}}}, -{/*.x =*/{/*.val =*/{0x2c1f98cd, 0x2ff26722, 0x17f0308c, 0xd224153, 0x6602152, 0x362a7073, 0x34870fae, 0x66a1291, 0x9c39}}, - /*.y =*/{/*.val =*/{0x14fc599d, 0x39f9780f, 0x64c8e6b, 0x14c9bddb, 0x20e64190, 0x3c112fc9, 0x1dd57584, 0x13c3d293, 0xddb8}}}, -{/*.x =*/{/*.val =*/{0x294a09ec, 0xd7beded, 0x28535f04, 0x34c9a94f, 0x92aa40c, 0xbf1a757, 0x1d80f0a4, 0x14c9895, 0x2e3c}}, - /*.y =*/{/*.val =*/{0x8c7327e, 0x14d21a06, 0x7b66512, 0x12294f1c, 0x2fc1abe0, 0x2b8902e0, 0x6fb5bdd, 0x3e24595b, 0x1f}}}, -{/*.x =*/{/*.val =*/{0x2b9c7ce6, 0x17c668a, 0x19089342, 0x1c40c5a8, 0x24dda433, 0x17edf8f8, 0x1587ae1, 0x289333e9, 0xe8e2}}, - /*.y =*/{/*.val =*/{0x836267c, 0xb007ada, 0x1c27a73b, 0x27980ed, 0x2e20596e, 0x3cacacef, 0x35d1b4ca, 0x20f3831b, 0x46c9}}}, -{/*.x =*/{/*.val =*/{0xac7b3c2, 0x2c34e59a, 0x3d5b5f5, 0x2b2be48e, 0x32a212, 0x28e2c5c, 0x173c2b2f, 0x26ab1761, 0xa754}}, - /*.y =*/{/*.val =*/{0x1287eaef, 0x283245c6, 0x37116dff, 0x1ad44554, 0x147d2b5d, 0x2875c306, 0x2415335, 0x346e4347, 0xbd17}}}, -{/*.x =*/{/*.val =*/{0x20a959e5, 0x2884e084, 0x391d4cc5, 0x38524ea2, 0xe06bb91, 0x17ca076, 0x12fdf8de, 0x5c2c774, 0x6057}}, - /*.y =*/{/*.val =*/{0x2385a2a8, 0x2266fa4c, 0x2e24c65e, 0x1454af0f, 0x1df26246, 0x268b6bdc, 0x24807add, 0x3c2c9a9a, 0x9a1a}}}, -{/*.x =*/{/*.val =*/{0x2fd545c, 0x22672976, 0xa28e661, 0x4cfe375, 0x1c85df7c, 0x1044291b, 0x2e064039, 0x3f59df14, 0x6773}}, - /*.y =*/{/*.val =*/{0x147eb1ae, 0x231fc0d2, 0x1c6cf98e, 0x35e03d68, 0x2b246bea, 0x3c972774, 0x3652f0f0, 0x2db63365, 0x444e}}}, -{/*.x =*/{/*.val =*/{0xb86f021, 0x1cf185ac, 0x4680503, 0x1d390e04, 0xc87c203, 0x31e6ab38, 0xe565237, 0x1b65345f, 0xe0f8}}, - /*.y =*/{/*.val =*/{0x35bf325a, 0x2dade732, 0x15fc45b3, 0x202f3004, 0x89a2c9a, 0x7a0cbc7, 0x2bcf47a9, 0x71cdcc2, 0xc57}}}, -{/*.x =*/{/*.val =*/{0x2da6e03, 0x2b41dcb0, 0xcad6038, 0x9df7e42, 0x296f4f4c, 0x247864f5, 0x5041ce9, 0x56ae7c9, 0x42ca}}, - /*.y =*/{/*.val =*/{0xc347793, 0xda227ea, 0x106bea78, 0x1ba169a0, 0x3800eed6, 0x339347f2, 0x57c9647, 0x3bc9b207, 0x68d2}}}, -{/*.x =*/{/*.val =*/{0x2cb94266, 0x69a5cfb, 0x3d4df12b, 0x33bc3ee9, 0xda31880, 0x10e69146, 0x8411421, 0x37e388e8, 0xa576}}, - /*.y =*/{/*.val =*/{0x21b28ec8, 0x3a2f846b, 0x114d9f3e, 0xb8429fd, 0xcd82c43, 0x2e5ebf96, 0x240b2c92, 0x2fc839d9, 0x40a6}}}, -{/*.x =*/{/*.val =*/{0x1a704896, 0x3b15c96f, 0x1acfb8dc, 0xee818f2, 0x271bae6f, 0x148219ef, 0x35a3b546, 0x3318bbce, 0x9e5d}}, - /*.y =*/{/*.val =*/{0xa82c835, 0x23c9da77, 0x30f5124, 0x18174618, 0x7612279, 0x34e88553, 0x25f3ea5f, 0x344b76e4, 0x6fed}}}, -{/*.x =*/{/*.val =*/{0x4bf7ea0, 0x14fb561d, 0xef58339, 0xd896817, 0x303b20e3, 0x1ba7e5db, 0x345adf8d, 0x20dd6e1, 0xa7de}}, - /*.y =*/{/*.val =*/{0x1bbcabaa, 0x130154e, 0x2bc5aa2e, 0x1691f03f, 0x88e9a64, 0x1282ccd2, 0x1a5e5210, 0x25ac15eb, 0xa63d}}}, -{/*.x =*/{/*.val =*/{0xad916fb, 0x27e3e841, 0x149e4a3a, 0x20197f7a, 0xff4cbe6, 0x30d6b007, 0x80c9c13, 0x19639a24, 0xc266}}, - /*.y =*/{/*.val =*/{0x20887814, 0x1abbd4ae, 0x36113885, 0x23fb37fa, 0x627ab6b, 0x2605c2c9, 0x3daab0f7, 0x164e1539, 0xe7e8}}}, -{/*.x =*/{/*.val =*/{0x3e58ad71, 0x3dd8e226, 0x39a3a208, 0xc347d73, 0x1e8c38bb, 0x17fa58a7, 0x2c3e30a0, 0x29e30a37, 0x7778}}, - /*.y =*/{/*.val =*/{0x3d9f43ac, 0x2d44ff07, 0x324ac563, 0x2ce1047f, 0x3f580087, 0x26384bcb, 0x1b22ff70, 0x1b66ad69, 0x3462}}}, -{/*.x =*/{/*.val =*/{0x1073e879, 0x1fa87094, 0x104eea7a, 0x3c5a96b8, 0xfe3932c, 0x3d20b5fc, 0x6d1632, 0x1e5ad728, 0xe7b9}}, - /*.y =*/{/*.val =*/{0x3aa89d98, 0x239c4226, 0x1a98af33, 0x2d6fc97b, 0x3cc1ca9c, 0x840a9cd, 0x29e2fdf4, 0x26230645, 0x12b8}}}, -{/*.x =*/{/*.val =*/{0x32628f0f, 0x1975c8af, 0x2aee9198, 0x108f6abc, 0x209a7365, 0x2456892f, 0x36203c2c, 0x3c061421, 0x71b}}, - /*.y =*/{/*.val =*/{0x5a1c334, 0x15f172f5, 0x31c80bbb, 0x23e71a88, 0x84ce209, 0x1802f070, 0x1cf4ae33, 0x28575413, 0x527a}}}, -{/*.x =*/{/*.val =*/{0x239620e1, 0x3d8ddb7e, 0x1213786, 0x6447214, 0x3c39e5b, 0xcb96530, 0x3e56833a, 0xd0eb2e6, 0x218}}, - /*.y =*/{/*.val =*/{0x106998b5, 0x380667d9, 0x343c9ec5, 0xca6690b, 0x2fbfc044, 0x3c93f580, 0x250beaf3, 0x75225c2, 0xbea8}}}, -{/*.x =*/{/*.val =*/{0x6d903ac, 0x27b6a70, 0x1ad7e5cb, 0x3e589d39, 0x3afd2ed5, 0xa7f4c39, 0x3a844637, 0x2557b98d, 0x928}}, - /*.y =*/{/*.val =*/{0x1bcd091f, 0x14603a4d, 0xa8d83fc, 0xf49bbea, 0x3a95eeac, 0x1e284c24, 0x342a827b, 0x8400f4f, 0xc256}}}, -{/*.x =*/{/*.val =*/{0xf59dd9e, 0xc411e98, 0x358f0e72, 0x397a7156, 0x318ad67c, 0x58ec132, 0x1d350dad, 0x2f7b8ddc, 0x4f89}}, - /*.y =*/{/*.val =*/{0x156b049, 0x5ab8c8, 0x238df5c1, 0x12209419, 0x3bb2471e, 0x2ebd3010, 0x21f695c4, 0x14b5489e, 0xca79}}}, -{/*.x =*/{/*.val =*/{0x3ff01197, 0xa70c533, 0x1a245bf5, 0x2d9a3c1e, 0x3c4c994, 0x25aeb28b, 0x3c5a80c3, 0x20c132b8, 0xcb9e}}, - /*.y =*/{/*.val =*/{0x3b989c1d, 0xcd381d8, 0x15e0a24c, 0x2cb46300, 0x8891741, 0x96337fc, 0xe6a127, 0x34a007ae, 0x62c7}}}, -{/*.x =*/{/*.val =*/{0x108d2cc2, 0x17e7ff09, 0x48c58c1, 0x2fbb51c, 0x330dc58e, 0x33ca9041, 0x69bd3c8, 0x126c3e27, 0xe2f3}}, - /*.y =*/{/*.val =*/{0x20d4c04f, 0x38d1ef63, 0x9cbdb37, 0xd12fa38, 0x215ba42, 0x182bb1d8, 0x27237818, 0xbca03e0, 0x1feb}}}, -{/*.x =*/{/*.val =*/{0x23d82751, 0x1eab9d45, 0x3ad35452, 0x116d2a41, 0x23b28556, 0x193ce83, 0x1b109399, 0x3fbcfb1b, 0x85d0}}, - /*.y =*/{/*.val =*/{0xeb1f962, 0xb08de89, 0x7733158, 0x21d47a5a, 0x2cf5663e, 0x3525b960, 0x38c0be29, 0x192104e8, 0x1f03}}}, -{/*.x =*/{/*.val =*/{0x1d5fcade, 0x18d5b450, 0x1711ff75, 0x2d20b802, 0x11df0468, 0x1e9b3f34, 0xc4f4f60, 0x3d2c669, 0x6b79}}, - /*.y =*/{/*.val =*/{0x338d3ff, 0x1bffe1bf, 0x3e26b0ab, 0xfe96d1e, 0x2e09cba8, 0x19987e72, 0x1eb3ef29, 0x2606cbfe, 0xd03a}}}, -{/*.x =*/{/*.val =*/{0x23a3e0cb, 0x2c3336af, 0x1978be0b, 0x91e77a1, 0x4f8fe3d, 0xb0d9eb3, 0x2bed3c16, 0x26cb0b5f, 0x4114}}, - /*.y =*/{/*.val =*/{0x339033a8, 0x3a4ba60, 0x3490f247, 0x3b1e017b, 0x2cf28b3, 0x5726e64, 0x30542b4, 0x16e4b6df, 0xc90d}}}, -{/*.x =*/{/*.val =*/{0x23f3d3fc, 0x237774a3, 0x1c29cebf, 0x12a6e081, 0x32a7ba66, 0x30f7f8a1, 0x849dfae, 0x353e939f, 0xd1fa}}, - /*.y =*/{/*.val =*/{0x10f3704d, 0x3488d0f1, 0x3f37326e, 0x34dc4c7b, 0xb7818ba, 0xfdc3a16, 0xfdfe547, 0x25c528d2, 0x8fe1}}}, -{/*.x =*/{/*.val =*/{0x526087e, 0x3d501209, 0x2da20308, 0x3edb6220, 0x18b85dfd, 0x26d8105e, 0x2ce97c1c, 0x373a5fb, 0xff2b}}, - /*.y =*/{/*.val =*/{0x30c29907, 0x32547807, 0x10e2ceb2, 0x2dfb5bee, 0x107936c7, 0x13137153, 0xba188af, 0x4ffbd49, 0x493d}}}, -{/*.x =*/{/*.val =*/{0x3149f8ef, 0x2f4ea6bc, 0x238b4583, 0x3ad713b9, 0x31bb223d, 0xa7aefb2, 0x26c9f78e, 0x36ef17cd, 0x2982}}, - /*.y =*/{/*.val =*/{0x16c7a248, 0x1b9c9ac0, 0x2e3ed845, 0x176e6504, 0x35bc9d09, 0x294ce71e, 0x2220ab9f, 0x16fa6bd9, 0xa61b}}}, -{/*.x =*/{/*.val =*/{0x2380441b, 0x14a27d84, 0xe176588, 0x47d160, 0x17db5860, 0x1bad6412, 0xc0f6b43, 0x39410abc, 0x1a28}}, - /*.y =*/{/*.val =*/{0x452af25, 0x17d81aa, 0x2ee67aeb, 0x2cf9d6d1, 0x36f0ed04, 0x20ca6a25, 0x19dab7c7, 0x269e65b1, 0x5577}}}, -{/*.x =*/{/*.val =*/{0x221e30a7, 0x3bbc38e5, 0x5d83242, 0x3757ade6, 0x3f20142e, 0x143302f4, 0x330601d2, 0x20fa54d7, 0xc8b}}, - /*.y =*/{/*.val =*/{0x1ff688de, 0x3afdefae, 0x187134db, 0x32b48dee, 0x3dc854aa, 0x38fc5fb, 0x3dac7b85, 0x1c1dc197, 0xdcc}}}, -{/*.x =*/{/*.val =*/{0x3856e241, 0x203978b3, 0xd6dd287, 0x3c7b8523, 0x1b212b57, 0xacb98c0, 0x80ea9ed, 0x2ef92c7a, 0x827f}}, - /*.y =*/{/*.val =*/{0x2ec293ec, 0x1816da2e, 0x2903166d, 0x3de98c61, 0x1d12687f, 0x3bcb19f4, 0x27b0b71b, 0x27248f1c, 0xc60f}}}, -{/*.x =*/{/*.val =*/{0xcb1815d, 0x3db912dc, 0xb87461e, 0x11c2a486, 0x2e6b3660, 0x35f2355d, 0x16b973e2, 0x4a9f739, 0xb77f}}, - /*.y =*/{/*.val =*/{0xe57dbc5, 0x2e8f4af2, 0x244816d6, 0x10bc3e46, 0xc2e654c, 0x33becdcf, 0x2acc43f0, 0x216c53e1, 0x4b6f}}}, -{/*.x =*/{/*.val =*/{0x45565ec, 0x3f976b4b, 0x177c5970, 0x163637d2, 0x39f956d8, 0xc22cb2d, 0xbf1247b, 0xee50c06, 0x4897}}, - /*.y =*/{/*.val =*/{0x3aed07e9, 0x2e1e41d7, 0x477b83, 0x6cd6596, 0x45af151, 0x1eece805, 0xdc1b643, 0x1d5a13cf, 0x761f}}}, -{/*.x =*/{/*.val =*/{0x3bfd71fa, 0x13535d0a, 0x34527d4a, 0x1dd68996, 0x304c170b, 0x25c9ca29, 0x1559c6d6, 0x963a3ad, 0xe931}}, - /*.y =*/{/*.val =*/{0x174d3307, 0x366f434c, 0x35e35f33, 0x251b386e, 0x154b40b3, 0x3ad05a72, 0x3dee0e85, 0xccd930f, 0xfb1e}}}, -{/*.x =*/{/*.val =*/{0x2120e2b3, 0x3ced63e8, 0x347f9aa7, 0x163f739f, 0x26e5217a, 0x392b8d33, 0x1bdbae7b, 0x127c87d4, 0xeaa6}}, - /*.y =*/{/*.val =*/{0x3a5ad93d, 0x11e94c16, 0x13f7e59d, 0x29ae597c, 0x39aa5a01, 0x2a03e261, 0x3b03ac69, 0x1e7b56ee, 0xbe32}}}, -{/*.x =*/{/*.val =*/{0x1fc9b0a8, 0xf6f0730, 0x5f3db45, 0xcded71c, 0x2279ea9e, 0x8fa9400, 0x197eec26, 0x276cefae, 0x3adb}}, - /*.y =*/{/*.val =*/{0x305bbdda, 0x6b9e5d7, 0x30266cc6, 0x36723e61, 0x95ff6aa, 0x1d3781f0, 0x34e713c7, 0xb5b6bb9, 0x374e}}}, -{/*.x =*/{/*.val =*/{0x10ae86f9, 0x153a7832, 0x23e7caf0, 0x3f7fd5a5, 0x5fc69fe, 0x255795b, 0x29cbb7e1, 0x14eb10a3, 0x129e}}, - /*.y =*/{/*.val =*/{0x1e89c85d, 0x8bbf734, 0x2b3e01b8, 0x288cbf45, 0x12183fb2, 0x288456dc, 0x29a29b2d, 0x32e562bb, 0x415e}}}, -{/*.x =*/{/*.val =*/{0x2855b8da, 0x8890f57, 0x28947119, 0x15899f44, 0x210956c7, 0x17b2dabb, 0x294485b8, 0x1125323d, 0x6014}}, - /*.y =*/{/*.val =*/{0x334e4bbd, 0x35401643, 0x23f2a4ba, 0xe55709f, 0x32e65b54, 0x2f87f644, 0x1e6469e8, 0x359a7da0, 0x8bb5}}}, -{/*.x =*/{/*.val =*/{0x1a34d24f, 0x388d8cb7, 0x1a137401, 0x2db63c32, 0x342ee541, 0x77db7b3, 0x3169d939, 0xb50f173, 0xe4a4}}, - /*.y =*/{/*.val =*/{0x1eba9414, 0x29fdc4c7, 0xd8e4f13, 0x21bbb7ea, 0xad34ce8, 0x326733ee, 0x1c73526f, 0x24b9c5b4, 0x4d9f}}}, -{/*.x =*/{/*.val =*/{0x3e8f62bb, 0xfcba8c, 0x3ae4d2a3, 0x14f158bd, 0x4ef4d05, 0x2b3e15b, 0x3b18d3ef, 0x147ee133, 0xfd64}}, - /*.y =*/{/*.val =*/{0x132c0911, 0x2b64218, 0x200e83fd, 0xaad24b4, 0x344ccfa, 0x39e9706f, 0x31578b6f, 0x33acac61, 0xe745}}}, -{/*.x =*/{/*.val =*/{0x15fe696b, 0x28747ee7, 0xf3c7a1f, 0x10b8b577, 0x1edbbb00, 0x3a0681be, 0x86bc716, 0x81f2c90, 0x1eee}}, - /*.y =*/{/*.val =*/{0x3429337b, 0x2d159c39, 0x2fd694eb, 0x818b82, 0x21c95f7a, 0x65b4491, 0x2269cd2b, 0x2f466bbd, 0x652c}}}, -{/*.x =*/{/*.val =*/{0x2f94c0d5, 0x23503c67, 0x5725790, 0x303f005f, 0x2e2111e1, 0x16acb0d1, 0x1eb14d46, 0x28cfaa2a, 0xcc0e}}, - /*.y =*/{/*.val =*/{0x2f452fe6, 0x3aaf965e, 0x113f543d, 0x1d3c998, 0x3be663f6, 0x37480ed7, 0x8a2fb23, 0x1e8edc47, 0xf990}}}, -{/*.x =*/{/*.val =*/{0x300bf19, 0x1c5cee75, 0x8fea494, 0x2d4d5daa, 0x352b6b92, 0x183eb6ac, 0xbdd9541, 0x3fbcd83, 0x1ec8}}, - /*.y =*/{/*.val =*/{0x107cefd, 0x1c737073, 0x295a07b6, 0x11b9dfd8, 0x2bbf5e01, 0x2925629e, 0x1340d2f3, 0x3a4dd5ad, 0xaeef}}}, -{/*.x =*/{/*.val =*/{0x14ff9e4, 0x36ba0175, 0x3d890560, 0x2118bdba, 0x3c90bb8e, 0x3aa80d13, 0x4bc6cbe, 0x3a8d467c, 0x5be7}}, - /*.y =*/{/*.val =*/{0x7e0bdbb, 0xc2c1e1, 0x119a3094, 0x26718c08, 0x1ab7fe0e, 0x3e243d95, 0xe605477, 0xbb0fd8e, 0x32f3}}}, -{/*.x =*/{/*.val =*/{0xddb7bb8, 0xfed517d, 0x3853991e, 0xa1927, 0x1f7f5cd5, 0xff21a63, 0x24e65081, 0x26445bab, 0x58f0}}, - /*.y =*/{/*.val =*/{0x2e5b2d6e, 0x37b1cd60, 0x1174302b, 0x1fb9018b, 0x23806650, 0xbfdd851, 0x2111a0d6, 0xaabff, 0x7e07}}}, -{/*.x =*/{/*.val =*/{0xc9a8e2c, 0x4f0581b, 0xc1a1c14, 0xf634693, 0x20cb0f82, 0x33013f61, 0x390b633b, 0x392e6ca5, 0xb0f9}}, - /*.y =*/{/*.val =*/{0x1f3d0db4, 0x30819b13, 0x171cee76, 0x143300b0, 0x3de3f033, 0x2ec2e41b, 0x2de6d41c, 0xafc610e, 0x49e8}}}, -{/*.x =*/{/*.val =*/{0x366642be, 0x376d64a0, 0x158ba889, 0xd241c5f, 0xdfa8bce, 0x2bd1a0, 0x30c2f91b, 0x1de30119, 0x146a}}, - /*.y =*/{/*.val =*/{0x3d83efd0, 0x2ca5d20, 0x37e5ed1d, 0x2aa5c74b, 0x14b2870a, 0x1a609fe7, 0x28add6, 0x383b0cd5, 0xb318}}}, -{/*.x =*/{/*.val =*/{0x39de5cac, 0x6c8d955, 0x2cb26191, 0x3f260f1f, 0xd14cfee, 0x1c2d702f, 0x17e24e56, 0x3c33a296, 0x574e}}, - /*.y =*/{/*.val =*/{0x75a4805, 0x3966ba9b, 0x310008ca, 0x9829efb, 0x1b78451a, 0x1ab6815a, 0x319c73bd, 0x264c0a07, 0x9b9}}}, -{/*.x =*/{/*.val =*/{0x260966d3, 0x230b5d0, 0x2ff86458, 0x29dc306b, 0xc835d10, 0x24e5ee6, 0x3f9f85d9, 0x1f9e6762, 0xd3d9}}, - /*.y =*/{/*.val =*/{0x33c2e52, 0x377ae142, 0x28dc4eeb, 0x3921c46f, 0x3ad3b5, 0x2a249d75, 0x2c95e6aa, 0x2d18ddae, 0x8ddb}}}, -{/*.x =*/{/*.val =*/{0x168c6d4b, 0x103ee4e, 0x3494c120, 0x2f9e33e3, 0x3bee0ab2, 0x1d39e0b2, 0x318987b9, 0x194ca22c, 0xb1aa}}, - /*.y =*/{/*.val =*/{0x2891ac51, 0xf6798ab, 0x1623cc38, 0x2876427, 0x23a83b10, 0x12aa38b5, 0x10d71268, 0x1c71820, 0x7ed6}}}, -{/*.x =*/{/*.val =*/{0x3180eef9, 0x35daa1e4, 0x228b9776, 0x48826, 0x207b128d, 0x2b3aec6a, 0x2e5f07e3, 0x303d8748, 0xfa50}}, - /*.y =*/{/*.val =*/{0x3f4f2811, 0x233635f4, 0x17a213b3, 0x1a0ca4e9, 0x1a68a5e, 0x334a1c8a, 0x3eba9b72, 0x31a488e5, 0x6b84}}}, -{/*.x =*/{/*.val =*/{0x187f5048, 0x2716f88c, 0x8386d45, 0x8ca3491, 0x290836e7, 0x503f80b, 0x74e0780, 0x13bb9864, 0x6396}}, - /*.y =*/{/*.val =*/{0x9309df8, 0x20e8a136, 0x1de6c843, 0x1602e4d3, 0xbfbc93d, 0x3fe6c70d, 0x1cf41a39, 0x3ece9ae2, 0x3b6c}}}, -{/*.x =*/{/*.val =*/{0x3adb2a65, 0x2052e87a, 0x3cbda31f, 0x35fc4ab4, 0x3c9f75af, 0x11a777c3, 0x1b7e22d1, 0x3896d345, 0x5a3c}}, - /*.y =*/{/*.val =*/{0x1d327f1d, 0x22c5c33c, 0x25fe8ed, 0x38a2f0f6, 0x3f99af3e, 0x29b6fefc, 0x5f63873, 0x496e4b8, 0x8b34}}}, -{/*.x =*/{/*.val =*/{0xa9f44d0, 0x1a9ccdd5, 0x1a8fa001, 0x36f2db9a, 0x1e41ff85, 0x2f8d3c3, 0x13eda691, 0x16be63e, 0x5ce6}}, - /*.y =*/{/*.val =*/{0x9d30105, 0x3417cd2, 0x32eccc6c, 0xf2c6fe8, 0x76c58ab, 0x15af40c7, 0x26bfe7ba, 0x33e6fb08, 0x4cdd}}}, -{/*.x =*/{/*.val =*/{0x1f067ec2, 0x394f4cad, 0x1bba5220, 0xa22ad75, 0x8e8421a, 0x16fdadf6, 0x21a11b1a, 0x1874329c, 0xda1d}}, - /*.y =*/{/*.val =*/{0x1ad836f1, 0x157ee83c, 0x279b48a6, 0x29ce2674, 0x91e2966, 0x1d98587, 0x1306c79c, 0x3d569f26, 0x8157}}}, -{/*.x =*/{/*.val =*/{0x2cd3c369, 0xf084348, 0x1f8e934b, 0x181520f8, 0x1283a23, 0x1757d877, 0xc444df8, 0x3802d3bd, 0x9c7b}}, - /*.y =*/{/*.val =*/{0x22329515, 0x27b8ffae, 0x2769cbd2, 0xc454e85, 0x2401483e, 0x9b51573, 0x20d2052a, 0x30379d2c, 0x9220}}}, -{/*.x =*/{/*.val =*/{0x3bb8c9e3, 0x1af364b5, 0x141178e7, 0x3741a9c1, 0xcc49174, 0x1992c8e3, 0x1263bb55, 0x20fd0a09, 0xfcd}}, - /*.y =*/{/*.val =*/{0x1f4aa9ad, 0x21b557ef, 0x1627bf4e, 0x2fabb37c, 0x3db683ad, 0x208cb797, 0x1fbced1d, 0x3073fab1, 0x6c0b}}}, -{/*.x =*/{/*.val =*/{0x326b64f1, 0x33ce6512, 0x1476d995, 0x3b73ca3d, 0x11e59db7, 0x36931894, 0xf010d4c, 0x101fc6d6, 0x7175}}, - /*.y =*/{/*.val =*/{0x324234d5, 0x9b9fbea, 0x471d2a4, 0x7fa2ddd, 0xcc86eb0, 0x34d0044d, 0x3d550f36, 0x1550d138, 0x43b4}}}, -{/*.x =*/{/*.val =*/{0xd064e13, 0x29cec184, 0x6f1e062, 0xc477811, 0x3d416615, 0x17fe63a3, 0x30690721, 0x20bfc325, 0xa8e2}}, - /*.y =*/{/*.val =*/{0x11f4cc0c, 0x3bdf1cc4, 0xdd6bd6c, 0x19e68f94, 0x2515888b, 0x2dfcf16c, 0x1c09abf, 0xd56e36e, 0x7f97}}}, -{/*.x =*/{/*.val =*/{0x3f7653a1, 0x57ae7a9, 0x13d67c1c, 0x2fa7aa9d, 0x266e63ef, 0x1dbe017a, 0x3aecbcb8, 0x3cb9f89f, 0xcac6}}, - /*.y =*/{/*.val =*/{0x3ec5e556, 0x23042b43, 0x8103a06, 0x3a0eb95a, 0x2a345081, 0x2d976690, 0x26f194cd, 0x5b978aa, 0xf7d4}}}, -{/*.x =*/{/*.val =*/{0x624003d, 0x327d2ac2, 0x238cb11c, 0x2dd9ca50, 0xe43254a, 0x3164cb96, 0x3d206efb, 0x3791bb8d, 0xe6df}}, - /*.y =*/{/*.val =*/{0x2216b93b, 0x15219438, 0x27fd7dd7, 0x7397a94, 0xf92203b, 0x3d23dee2, 0x139498f2, 0x2cedefa4, 0x8727}}}, -{/*.x =*/{/*.val =*/{0x8dce109, 0x38440d5, 0xf211d3b, 0x1438c527, 0x96082e2, 0x1033f1eb, 0x2823d66a, 0x2273669, 0x3c4e}}, - /*.y =*/{/*.val =*/{0x3a19aeea, 0xafd9648, 0x17fe697e, 0x1e7850b6, 0x364d3795, 0x15ef2855, 0x191b4807, 0x2f99a7f8, 0x43fb}}}, -{/*.x =*/{/*.val =*/{0x319497c, 0xbce0b7a, 0x12508c02, 0x166c7e94, 0x13cab15d, 0x2795b9a4, 0x285872d3, 0x14ee7268, 0x174a}}, - /*.y =*/{/*.val =*/{0x79afa73, 0xf684eb0, 0xb985438, 0x1ace8763, 0x7f9e664, 0x10557cb1, 0x9c1657b, 0x370deaff, 0xccc9}}}, -{/*.x =*/{/*.val =*/{0x40dd273, 0x3d768dbe, 0x24501115, 0xf4a0383, 0x392ea3d5, 0x1c1c7bc6, 0x6bb630c, 0x38b9e5a5, 0x20e6}}, - /*.y =*/{/*.val =*/{0x3b46b593, 0x1f3f456, 0x1a8693cc, 0x7b25e4f, 0x7465581, 0x2e86b65e, 0x159e44a0, 0x1ebf93c5, 0xd3ad}}}, -{/*.x =*/{/*.val =*/{0x1a077674, 0x1ed53cc0, 0xc24ca3e, 0x2b9a04db, 0x31db7035, 0xa0281f9, 0x351dba80, 0x2a0935e8, 0x8e0c}}, - /*.y =*/{/*.val =*/{0x12b7ed98, 0x2e132fb0, 0x2f910290, 0x3d810674, 0x22cf57cf, 0x1a749369, 0x12d41dc5, 0x1581d646, 0x4ec}}}, -{/*.x =*/{/*.val =*/{0x28192441, 0x25abf17a, 0x321b4afe, 0x36d60868, 0x3d66c1af, 0x298d54f8, 0x182d1c5f, 0x14369472, 0xf7bb}}, - /*.y =*/{/*.val =*/{0x145165ae, 0x31903a87, 0x3c4c74bb, 0x33f707ee, 0x26485db1, 0x2f18ef77, 0xa526311, 0xef8c0cd, 0x93cc}}}, -{/*.x =*/{/*.val =*/{0x1475b7ba, 0x213f7fc2, 0x918b3d8, 0xe79cc39, 0x18cdbe0, 0x395fb7d4, 0x3785c3d3, 0x25a60650, 0x9593}}, - /*.y =*/{/*.val =*/{0x3524f2fd, 0x26e2afe1, 0x709385e, 0x194fd932, 0x1cd6849c, 0xe1a92e, 0x331dd8ba, 0x154a2230, 0x2e7e}}}, -{/*.x =*/{/*.val =*/{0xbc8f53b, 0x1c9d6a50, 0x11747c70, 0x889ace, 0x33d95ed7, 0xcb29f75, 0x1a7deafe, 0x5017fc3, 0xcbee}}, - /*.y =*/{/*.val =*/{0x38c87f45, 0x248b9ac9, 0x126f7282, 0x27fd3da0, 0x294cf0d, 0x3cf9a26e, 0x1f902b51, 0x7d3d39d, 0xf621}}}, -{/*.x =*/{/*.val =*/{0x14b311dd, 0xddf222c, 0x3d71b9cf, 0x38efabbe, 0x2252e03d, 0x202fe82e, 0x2f5acdd5, 0x2eb4a3ea, 0xadd5}}, - /*.y =*/{/*.val =*/{0x9d6c38d, 0xbe60bcd, 0x29b9b890, 0x353879d9, 0x19814f52, 0x390d3e0d, 0x1c3a5974, 0xf3d368f, 0xe9c4}}}, -{/*.x =*/{/*.val =*/{0xd7c0979, 0x17d90028, 0x5a8c96f, 0xa6cc52f, 0x1ced24a, 0x277cf7fd, 0x317143fa, 0x10caea05, 0x53f2}}, - /*.y =*/{/*.val =*/{0x137b36a2, 0x27dfa431, 0x1e8b845f, 0x35693d72, 0x1b07de4b, 0x138f8244, 0x79b7ccd, 0x3bfef07c, 0xbd52}}}, -{/*.x =*/{/*.val =*/{0x1d82b151, 0x2d44d032, 0x21fba2db, 0x28290f55, 0x109a8fcc, 0x168454ec, 0x1e56d64, 0xe942b90, 0xd2a6}}, - /*.y =*/{/*.val =*/{0x1cf89405, 0x105085d3, 0x84ca52d, 0x3dd42bd, 0x148220a7, 0x2bb962ca, 0x3fcb7565, 0x21bed910, 0xe82d}}}, -{/*.x =*/{/*.val =*/{0xa72da5f, 0x31b12eb3, 0x2c413497, 0x2e735acd, 0x3725f922, 0x31c8080c, 0x525e23b, 0x20e9d840, 0xbaf1}}, - /*.y =*/{/*.val =*/{0x28f2a0cf, 0x1df398a2, 0x27393613, 0x8cdb172, 0x29b1d18e, 0x22f56375, 0x34d33568, 0x27efa732, 0xdeac}}}, -{/*.x =*/{/*.val =*/{0x56c3943, 0x296b2963, 0x2b76a5ff, 0x36f40b55, 0x8f6fd5a, 0xcca41b9, 0x40238f9, 0x3e29f8e1, 0xf7ae}}, - /*.y =*/{/*.val =*/{0x2cf442f1, 0xc7d89fe, 0xdcd0034, 0x30c0612a, 0x2b3fcfee, 0x10aef70e, 0x3da797c4, 0x2d1357f, 0x4e3b}}}, -{/*.x =*/{/*.val =*/{0x11924459, 0x3eb2515c, 0x3c7a78c1, 0x3cbe8968, 0x1dbb1f7a, 0xb8a7c37, 0x19036c5a, 0x11f2c400, 0xdfb5}}, - /*.y =*/{/*.val =*/{0xc65fd9e, 0x28817837, 0x1c031dcf, 0x2bc24c39, 0x864cc22, 0xe273a77, 0x347088b8, 0x34aa6e83, 0x9acc}}}, -{/*.x =*/{/*.val =*/{0x1617e073, 0x10dbe6d1, 0x39317b3, 0x2b2f6f4e, 0xfdc866b, 0x39e25b5f, 0x31eb890e, 0x1f88cd51, 0x6458}}, - /*.y =*/{/*.val =*/{0x1faf6589, 0x20a6797a, 0x33aeab35, 0x2e428e44, 0x299a185, 0x1b75911f, 0x102e2ae9, 0x33756fda, 0xd99f}}}, -{/*.x =*/{/*.val =*/{0x384480d, 0x12f36231, 0x291f2ef4, 0x382da88a, 0x2f0c1294, 0xa2d5324, 0x3940f2cf, 0x35ac50b7, 0xb866}}, - /*.y =*/{/*.val =*/{0xc4cafa8, 0x39966d1c, 0x31d86d60, 0x3948a012, 0x1ad7ac24, 0x9e35faa, 0x2eb7089a, 0x2c2cd09a, 0x1914}}}, -{/*.x =*/{/*.val =*/{0x1db20d6c, 0x8a736a0, 0x14fe455d, 0x354ab93b, 0x2ba87e2, 0x27459184, 0x2819ec4d, 0x2e242177, 0xec2b}}, - /*.y =*/{/*.val =*/{0x229cf4a0, 0x3a67135, 0x7efa98a, 0x288d92fa, 0x940c633, 0x3d9bc194, 0x13a1332, 0x305d9878, 0xccec}}}, -{/*.x =*/{/*.val =*/{0x23b09d0f, 0x22983b2c, 0x350becf3, 0x141903, 0x145905e5, 0x35d7bd79, 0x296ced39, 0x29f8e278, 0x71c4}}, - /*.y =*/{/*.val =*/{0x320ddb62, 0xdec7c05, 0x262ffc76, 0x1bcac212, 0x3810aa78, 0xf828a4b, 0x2f3ba0af, 0x3eb6dcde, 0x1313}}}, -{/*.x =*/{/*.val =*/{0x1d45e458, 0x1635b21b, 0x250e7fd3, 0x2a9b3a8, 0x9de042f, 0x151b4f95, 0xd885b3a, 0x2f783939, 0x8481}}, - /*.y =*/{/*.val =*/{0x1779057e, 0x3592c6d6, 0x3262e556, 0x29e710a, 0x2cb2ca90, 0x96fce73, 0x4dd84a, 0x1ee32e95, 0x38ee}}}, -{/*.x =*/{/*.val =*/{0x2ce9f114, 0x1510cd49, 0x19561dde, 0xbb5814a, 0x1492bf39, 0x10f1b347, 0x3a8b9fd, 0x29142f4e, 0x9629}}, - /*.y =*/{/*.val =*/{0x224aa391, 0x28e5cb12, 0x56af8dc, 0x9564f97, 0xef64db9, 0x2fbf4883, 0x3b6d7576, 0x26ca0317, 0xbf43}}}, -{/*.x =*/{/*.val =*/{0x26ca6cc3, 0xf4e3658, 0x187e1838, 0x1df5d1f8, 0x893df14, 0x1cc369f3, 0x24688eb1, 0x711fbc7, 0xb73b}}, - /*.y =*/{/*.val =*/{0x254fdba3, 0x2b0d75da, 0x1757f5af, 0x8a89482, 0x8050973, 0x1f592ef3, 0x122a90a5, 0x572ca52, 0x5843}}}, -{/*.x =*/{/*.val =*/{0x138f93e0, 0x31b8864b, 0x276899f9, 0x16ca8eed, 0x22fef7d0, 0x2624801e, 0x180311f, 0x5acb6d0, 0xedfe}}, - /*.y =*/{/*.val =*/{0x229405ad, 0x3405e4f7, 0x6e227e3, 0xf544031, 0x5d0d25b, 0x1d3ea92c, 0x1db3694d, 0xbc7f29, 0xee69}}}, -{/*.x =*/{/*.val =*/{0x2caf666b, 0x3358c0fd, 0xb1ce30b, 0x3f3fb4f1, 0x17f4637f, 0x1a5e6ba0, 0x102aa62b, 0x1295e9e0, 0x1346}}, - /*.y =*/{/*.val =*/{0x3f6ecc27, 0x3d256a41, 0x10942e13, 0x3cc02a07, 0xcb0ca48, 0x390cd14f, 0x14580ef7, 0x5640118, 0x69be}}}, -{/*.x =*/{/*.val =*/{0x65084ae, 0x1d612718, 0x2abe577c, 0x20af9f73, 0x3e12d191, 0x17223217, 0x5362ec0, 0x3e3d4c89, 0xeb3c}}, - /*.y =*/{/*.val =*/{0x396b9480, 0x3d9f07ff, 0x3dbd2a66, 0xad17179, 0x1ca4a1f5, 0x398f73bf, 0x1d70043f, 0x31e088b6, 0xc833}}}, -{/*.x =*/{/*.val =*/{0x2e9a5d0, 0x2396f2f3, 0xa201d9f, 0x1dbf3e61, 0x519b2a5, 0x2983c861, 0x199974f7, 0x299f424b, 0xbdf1}}, - /*.y =*/{/*.val =*/{0x562ff7b, 0x36d3dc06, 0x1626461c, 0xa02d879, 0x3f7baaa6, 0x2f952a1a, 0x1a1aaa80, 0x240aead9, 0x4095}}}, -{/*.x =*/{/*.val =*/{0x3b27e771, 0x3797f05c, 0x37da62ab, 0xed06591, 0x483b48c, 0x2f899ed9, 0xec29cd5, 0x1a9bb771, 0x6885}}, - /*.y =*/{/*.val =*/{0x7bbdab6, 0x46358a8, 0x3b0733a6, 0x748bca4, 0x1f7b4a33, 0x1bf52706, 0x1a1fb13b, 0xf7c53de, 0x77a3}}}, -{/*.x =*/{/*.val =*/{0x2d83f366, 0x2b68e834, 0x2f28588c, 0x36733b78, 0x1dc97a0c, 0x3d0c2f30, 0x3fe2e9ae, 0x277d6dc4, 0xbc4a}}, - /*.y =*/{/*.val =*/{0x181f33c1, 0x1d635999, 0x2547b16d, 0x3a2a7efe, 0x3798caa6, 0x24deb7d2, 0x5c06383, 0x20729b9e, 0xd3a}}}, -{/*.x =*/{/*.val =*/{0x33fceb19, 0x20b79517, 0x385c4092, 0x226c887d, 0x27bab42e, 0x171d89b3, 0x2ccc0abc, 0xf578473, 0xda43}}, - /*.y =*/{/*.val =*/{0x26f5cc64, 0x2139c482, 0x227b2776, 0x1dff0b64, 0x15e5218e, 0x2ef712be, 0x10301de, 0x36f4c86a, 0xe498}}}, -{/*.x =*/{/*.val =*/{0x1acf692a, 0x13789d71, 0x2207e065, 0x3120e29c, 0x16efdbc, 0x3045a607, 0xc7ec1c1, 0x2387ba7a, 0x31e}}, - /*.y =*/{/*.val =*/{0x316f667a, 0x330aa13a, 0x1bf73b09, 0x192609f1, 0x16743b70, 0x25c0a43, 0x3353dd9d, 0x1fd6d196, 0xad7e}}}, -{/*.x =*/{/*.val =*/{0x1f488b6, 0xaef5ffe, 0x3c7a9159, 0x326fcd8f, 0x257f73e9, 0x38036189, 0x161155d3, 0x2181ea23, 0xa987}}, - /*.y =*/{/*.val =*/{0x31dab1d, 0x2569eeec, 0xad5c6d4, 0x343c0659, 0x157c2239, 0x18f9f208, 0x95d61c0, 0x286af562, 0xd181}}}, -{/*.x =*/{/*.val =*/{0x25324caa, 0x152acc3f, 0x29472a39, 0x12d978c2, 0x12a32e69, 0x3631d251, 0x18bc0d23, 0x2a5efe0a, 0x8c28}}, - /*.y =*/{/*.val =*/{0xbef9482, 0x39c771cf, 0x11cb9459, 0x39e13c11, 0x3cc0eb7a, 0x3fb7cc7d, 0x5193378, 0x118e8cc, 0x40a3}}}, -{/*.x =*/{/*.val =*/{0x3611d8e2, 0x37ec807d, 0x249fc4d5, 0x4c3fa37, 0x3f0da2c8, 0x3b569811, 0xa2f196b, 0x3061ca8e, 0xab1a}}, - /*.y =*/{/*.val =*/{0x429d15b, 0x69607cf, 0x21e545f0, 0x3be4f4cf, 0x2a42b6f7, 0x297ce76d, 0x117a1e9a, 0x28de8c93, 0x13f4}}}, -{/*.x =*/{/*.val =*/{0x2651b3fa, 0x9abb990, 0x32df4342, 0x286cd95d, 0x3f31ef8e, 0xe981c94, 0x2f82d370, 0x3fa6d6fb, 0x2564}}, - /*.y =*/{/*.val =*/{0x1e5122d, 0x2e0b9a8c, 0x379816ed, 0x3cdf6ada, 0x3925f14, 0x2852b848, 0x389095f, 0x3de9819e, 0x8ad9}}}, -{/*.x =*/{/*.val =*/{0x2e180068, 0x5e38f4e, 0xbd3103b, 0x28f55b08, 0xdc01a7e, 0x1b17030c, 0x5b0cbfc, 0x184dbfeb, 0xff3d}}, - /*.y =*/{/*.val =*/{0x188c6077, 0x29aedb8, 0x1f5e67, 0x1d9dbc90, 0x16adc154, 0xdcb376, 0xe40d, 0xe6fa139, 0x1332}}}, -{/*.x =*/{/*.val =*/{0x1faccae0, 0x2312e844, 0x24bb3374, 0x22cd4316, 0x71fd23c, 0x3653393c, 0x127a8c1d, 0x259984e5, 0x8ea}}, - /*.y =*/{/*.val =*/{0xe62b945, 0x16bcd28c, 0xf0f8e95, 0x2de0efa7, 0x15c5d735, 0x39f033ee, 0x22782e24, 0x3eaef23b, 0x620e}}}, -{/*.x =*/{/*.val =*/{0x2190b632, 0xa4c4c76, 0xab5ab9a, 0x33ca88e9, 0x159d8263, 0x19b7cc55, 0x20cd9f3a, 0x18dc5d88, 0xc25f}}, - /*.y =*/{/*.val =*/{0x3c9590cf, 0x3bafcf5b, 0x2027a1d6, 0x27c13fe7, 0x9d7980a, 0x12640e0, 0x12873989, 0x13fb7a53, 0x5315}}}, -{/*.x =*/{/*.val =*/{0x1466d561, 0xb32cedf, 0x1978b4de, 0x1ed5770c, 0x8544c0c, 0xb60a95a, 0x26bab3e8, 0x237f8f33, 0x2a9e}}, - /*.y =*/{/*.val =*/{0x12e76373, 0x25b33d49, 0x3a02182f, 0x7abb05, 0xb96cf5e, 0x1ed6b582, 0x2651fbac, 0x3b69705b, 0x1df}}}, -{/*.x =*/{/*.val =*/{0x3f8be384, 0x22f4c810, 0x31db6c3e, 0x3b02ab68, 0x1ef07271, 0x2b5b253f, 0x23e1b251, 0x24290af9, 0xb237}}, - /*.y =*/{/*.val =*/{0x2b19880e, 0x4291cf7, 0x9ecb58d, 0x3c013d05, 0x1f94517, 0x143e22aa, 0x15edbe8d, 0x1a524675, 0xfc6b}}}, -}; - -const curve_point secp256k1_cp2[255] = { -{/*.x =*/{/*.val =*/{0x3ce036f9, 0x1807c44e, 0x36f99b08, 0xc721160, 0x1d5229b5, 0x113e17e2, 0xc310493, 0x22806496, 0xf930}}, - /*.y =*/{/*.val =*/{0x4b8e672, 0x32e7f5d6, 0xc2231b6, 0x2a664d, 0x37f35665, 0xcdf98a8, 0x1e8140fe, 0x1ec3d8cb, 0x388f}}}, -{/*.x =*/{/*.val =*/{0x20297556, 0x3c15e851, 0x168a18b2, 0x3d91cbe1, 0x1235d382, 0x14e850d5, 0x2eea4204, 0x1ef55d57, 0xfff9}}, - /*.y =*/{/*.val =*/{0x3075f297, 0x321c30da, 0x18fe4a03, 0x203c3d94, 0x5c560de, 0x3a5805fd, 0x3b620f3b, 0x1ddeab3e, 0xae12}}}, -{/*.x =*/{/*.val =*/{0x30afe85a, 0x16c3d1c1, 0x220095bc, 0x1f3d1065, 0x33463368, 0xe3c0135, 0x3561b15c, 0x5755239, 0xd011}}, - /*.y =*/{/*.val =*/{0x34062327, 0x2c146c4f, 0x1a86d526, 0x8e31776, 0x3bd81579, 0x1914df85, 0x1e0d7a8b, 0x13ff7205, 0xa9f3}}}, -{/*.x =*/{/*.val =*/{0x3202e6ce, 0x140af6a2, 0x162b7940, 0xc8550e7, 0x3a8b0968, 0x2724586, 0x133d48ac, 0x310d504f, 0xfe72}}, - /*.y =*/{/*.val =*/{0xf58c5bf, 0x1e3b4bef, 0x34a9d229, 0x372238da, 0x32998101, 0x2d1f8275, 0x24a68d3a, 0x37819ffc, 0x6851}}}, -{/*.x =*/{/*.val =*/{0x1118e5c3, 0x2f61c2a8, 0x12bebc19, 0x15e6c9d1, 0x265b4bfc, 0x595bbd3, 0x1307db44, 0xcd76591, 0x6eca}}, - /*.y =*/{/*.val =*/{0x5a08668, 0x2628bde0, 0x3f8ec344, 0x125a8e8e, 0x3875a03a, 0x3d5e41d2, 0x20710592, 0x8ed5e9e, 0xd501}}}, -{/*.x =*/{/*.val =*/{0x3f8cb0e3, 0xe4ceb29, 0x1efe3a44, 0xbad4ff8, 0x2eb72ea2, 0x1938112c, 0x16d8f8fa, 0x20395d11, 0x3f0e}}, - /*.y =*/{/*.val =*/{0x2a5f404f, 0x2c0a278b, 0x25b53a4c, 0x494ea9, 0x1d01b395, 0x2e702121, 0xbc91e90, 0x35f5ca5b, 0xcb66}}}, -{/*.x =*/{/*.val =*/{0x33ce1752, 0x1edd43dc, 0x3cd204ec, 0x20f1e5f5, 0x1c9aeae7, 0x377d9366, 0x1c635812, 0x36963407, 0xd7a0}}, - /*.y =*/{/*.val =*/{0x762cef4, 0x2f009ce0, 0x62b742b, 0x38102a30, 0x2284650b, 0xa4a0d03, 0x8032f6f, 0x1c381a00, 0x9127}}}, -{/*.x =*/{/*.val =*/{0x35476085, 0x2422dc06, 0x2eb9f84a, 0x1c539de5, 0xed1afb5, 0xeab5a9e, 0xcd3e10d, 0x29c19e82, 0x3443}}, - /*.y =*/{/*.val =*/{0xb8f52d8, 0x34d212f6, 0xc2b67f6, 0x2292c9f4, 0x3e1da901, 0x3a312e31, 0x36f854f6, 0x1e97e0a6, 0x661a}}}, -{/*.x =*/{/*.val =*/{0x257e8dfa, 0x33f032e7, 0x3c7e184f, 0x20246468, 0x298ca009, 0x28c3e2b2, 0x19c4c0d9, 0x33cbfc1e, 0x8262}}, - /*.y =*/{/*.val =*/{0x3bac376a, 0x173fe363, 0x314c4783, 0x2dbb4cca, 0x334f3457, 0x3b88bb16, 0x9e4e66f, 0x25788244, 0x83fd}}}, -{/*.x =*/{/*.val =*/{0x3c70620c, 0x5f307c9, 0x3c288d9d, 0x26312faa, 0x27178049, 0x374c68ad, 0x236dc60, 0x2a29234b, 0x1653}}, - /*.y =*/{/*.val =*/{0x315b32cd, 0x328ba074, 0x3d3dc526, 0xabdd237, 0x3a701c01, 0x2a651d3b, 0x37f7aeaf, 0xa424d6b, 0x338}}}, -{/*.x =*/{/*.val =*/{0x271dabcd, 0x1f50ae9b, 0x1e5cb4f4, 0x34ff9262, 0x35373f54, 0x22b8c982, 0x3f43c609, 0x393edad8, 0xd49e}}, - /*.y =*/{/*.val =*/{0x16603c2, 0x19aa433c, 0x2ff7031e, 0x271424c4, 0x1bf35612, 0x21fa9e98, 0x1490dd7c, 0x38e48269, 0x531}}}, -{/*.x =*/{/*.val =*/{0xc8c828a, 0xfcc2ae4, 0x16ae41f5, 0xbac90b2, 0x281c7513, 0x1283605f, 0x9e750e4, 0x21472905, 0x5f94}}, - /*.y =*/{/*.val =*/{0x37344d80, 0x3fac28fc, 0x3c68b04b, 0x19b7dd53, 0x2f35e8c, 0x1e5f622, 0x1fee8e5f, 0x30ee2be8, 0x26b8}}}, -{/*.x =*/{/*.val =*/{0x5041216, 0x16dfe3c7, 0x2b836a6, 0x1ccd7da1, 0x2fed523f, 0x2d67bf70, 0x3acf4128, 0xc5ec87d, 0xda75}}, - /*.y =*/{/*.val =*/{0x2e708572, 0x2bb4ca61, 0x37acedad, 0x2ab01eb9, 0x2d7fc6e9, 0x27886cd0, 0x2d5f0df1, 0x2811afdc, 0x73f8}}}, -{/*.x =*/{/*.val =*/{0x3c62bac0, 0x1414c93c, 0x1f0ab069, 0x54377d4, 0x28b70e19, 0x12df4b0f, 0x3469c136, 0x3c3e408f, 0x9530}}, - /*.y =*/{/*.val =*/{0x3618e309, 0x1e2af6a5, 0x31fdc684, 0x16cca14b, 0x3333e0e2, 0x34bdfd66, 0x321e234d, 0xc16a3e7, 0x8f3c}}}, -{/*.x =*/{/*.val =*/{0x1c3c9c8f, 0x19c10e17, 0x24367b20, 0x205bfb8f, 0x2332b0f2, 0x27fd0eaa, 0x298fd6f0, 0xb72f90, 0x67be}}, - /*.y =*/{/*.val =*/{0x193652d9, 0x14e12661, 0x388c2be5, 0x264efd82, 0x291693cd, 0x2516d820, 0x1ef84a2c, 0x1569cf93, 0x7a9b}}}, -{/*.x =*/{/*.val =*/{0x10aaa33a, 0x7e6f2f8, 0x17b9ca51, 0x24b74a70, 0x1718368c, 0x1a404ef1, 0x3876adf5, 0x924bd3b, 0x893b}}, - /*.y =*/{/*.val =*/{0x11af3445, 0x1ee02e2b, 0x3ceeb426, 0xe7a2884, 0x107f32a4, 0xe801d99, 0x1c89ef41, 0x14ad9cb4, 0xcdb1}}}, -{/*.x =*/{/*.val =*/{0x36e55dc8, 0x2e24485b, 0x2ca04394, 0x3e56adba, 0x1094426f, 0x12910301, 0x1ffb2ba8, 0x1011e431, 0x4431}}, - /*.y =*/{/*.val =*/{0x1be323b3, 0x76512bb, 0x2aa2e503, 0x1a8a6de7, 0x2fed7a6, 0x260dfd59, 0x366f8fe9, 0x3050b994, 0x96b0}}}, -{/*.x =*/{/*.val =*/{0x33f0e9aa, 0x3ad78658, 0x11bd34b3, 0x449ddac, 0x138d268, 0x92b8356, 0x326adb79, 0x3fa15d7, 0xe538}}, - /*.y =*/{/*.val =*/{0x82720f, 0x12e904d9, 0x68318ec, 0x2e53977d, 0xc8e016f, 0x244d8e49, 0x3b41d5b6, 0x361ce421, 0xb97f}}}, -{/*.x =*/{/*.val =*/{0x2ebc61d6, 0x2bb4d86f, 0x1ff42de1, 0x23f4e9f6, 0x2b1f518a, 0x17c34575, 0x19af0c39, 0x3cf928fb, 0x939f}}, - /*.y =*/{/*.val =*/{0x23f5cb70, 0x1d7a919a, 0x38c7f82e, 0x2fc9bad, 0x16c0498, 0x1bf13bbc, 0x3a90e9d4, 0xef3c22d, 0xdeab}}}, -{/*.x =*/{/*.val =*/{0x497e0df, 0x5b84d37, 0xf76f530, 0xeed0dbb, 0x2029a04c, 0x161e17f9, 0x3293078, 0xf94ab8e, 0xfdc6}}, - /*.y =*/{/*.val =*/{0x1b9eb19f, 0x1811127, 0x335d9d5f, 0x2fac8bef, 0x22e8b87b, 0x3dc50a2b, 0x3bb52e3d, 0x2b59eb3a, 0x292d}}}, -{/*.x =*/{/*.val =*/{0x355812dd, 0x28a960b, 0x12d30e2a, 0x1119c8d5, 0x18f78e3d, 0x2afb5b01, 0x3352f0b6, 0x2f5ea4bf, 0x7029}}, - /*.y =*/{/*.val =*/{0x1a2d2927, 0x87319ac, 0x3b2c73c7, 0x36ba1090, 0x683ac47, 0x19512b8c, 0xb3d27dd, 0x3eb6bf7a, 0xb0ee}}}, -{/*.x =*/{/*.val =*/{0x3181fdc2, 0x336affe6, 0xc62364d, 0xbd8aed7, 0x234e7edd, 0x992e062, 0x26e474aa, 0x40abd1f, 0xf42c}}, - /*.y =*/{/*.val =*/{0x2485d7fd, 0x7c0024e, 0x22acf268, 0x5540b66, 0x2fe22a4c, 0x2b4172e1, 0x2806c78f, 0xead1b3f, 0x5750}}}, -{/*.x =*/{/*.val =*/{0x2edd7dd6, 0x219b51f7, 0x1e1968c3, 0xddbf899, 0x3cfdec49, 0x29e103b9, 0x3524bca5, 0x33da8931, 0x32cf}}, - /*.y =*/{/*.val =*/{0x3e08e330, 0x17f512bb, 0x349a08b2, 0x3633480, 0x1f561e7a, 0x2025a902, 0x27748620, 0x1a8d25da, 0x2184}}}, -{/*.x =*/{/*.val =*/{0x21231d11, 0x399d20c4, 0x2aaad7c, 0x2acdb18f, 0x37c39822, 0x455731d, 0x388e433d, 0x3507a2e4, 0x3514}}, - /*.y =*/{/*.val =*/{0x23855df5, 0xf5bed03, 0x2f79ebe5, 0x213cc742, 0x39eff93, 0x1344795a, 0x17eb8ef4, 0xc940580, 0x89a8}}}, -{/*.x =*/{/*.val =*/{0x633cb1, 0x159f827a, 0x1d021132, 0x168892da, 0x181fcb57, 0x189cc848, 0x2cad400c, 0x273cc5ea, 0x6dde}}, - /*.y =*/{/*.val =*/{0x27ce6b34, 0x1f7526a9, 0x3859ef35, 0x2c9ff6b3, 0x3a66a880, 0x27be1a86, 0x3e41d5c9, 0x3ef9e9c1, 0x9188}}}, -{/*.x =*/{/*.val =*/{0x4e5467d, 0x342f5da9, 0x1bbface4, 0x2422ae06, 0x970e940, 0x7d8b83b, 0x1a1222c2, 0x193c3f1a, 0x97d0}}, - /*.y =*/{/*.val =*/{0x1e9cb3fa, 0x25cc03f4, 0xf17ccd7, 0x17ecee15, 0x10861fda, 0x1f19bea1, 0x2cc03f, 0x13cbb4cd, 0x8997}}}, -{/*.x =*/{/*.val =*/{0x13613bec, 0x32a072e4, 0x1cfe67c, 0x2d7f2744, 0xf972a8b, 0x6ccf71d, 0x137bdedf, 0x32ae324e, 0x2dcf}}, - /*.y =*/{/*.val =*/{0x1a039215, 0x39cc2492, 0x33f5f383, 0xcb3eeb4, 0x36c6f437, 0x222df5b, 0xa41265f, 0x3137651d, 0x46db}}}, -{/*.x =*/{/*.val =*/{0x7fb9e1a, 0x1f345c21, 0x22a32961, 0x39d2dd37, 0x2b0e767f, 0xaf26ee, 0x2c5a8f1a, 0x1052a923, 0x1bec}}, - /*.y =*/{/*.val =*/{0x349c0443, 0x1fdb845d, 0xc9796e5, 0x4e176ba, 0x54b0f68, 0x26f15cc3, 0x266678a7, 0x19c11c04, 0xe358}}}, -{/*.x =*/{/*.val =*/{0x3b7ceceb, 0xfd9e3fe, 0x97faf0f, 0x2967e4e2, 0x2e681473, 0x3ee049bd, 0x2d45036f, 0x2188109d, 0x437a}}, - /*.y =*/{/*.val =*/{0x16c181e1, 0xd8ef30d, 0x8f97827, 0x883f3f7, 0x1297ff87, 0x23fada67, 0x2c32f69b, 0x1ae84fba, 0xb91}}}, -{/*.x =*/{/*.val =*/{0x1cbf00eb, 0x3276761f, 0x18d02274, 0x2d3a62f0, 0x230bc241, 0x385bda86, 0x2d4dc49b, 0x1c2ba5ba, 0xb890}}, - /*.y =*/{/*.val =*/{0x1b0e664e, 0x2dfc6f34, 0x2b96a671, 0x362c1ad, 0x4a766cb, 0xa539307, 0x2d88f472, 0x3230b228, 0x6f24}}}, -{/*.x =*/{/*.val =*/{0x36fbe7b2, 0x275bfe6a, 0x18d65a3b, 0x2b7b7051, 0x2884605e, 0x1aeec6ca, 0x41f8f33, 0x21d9a72d, 0x2648}}, - /*.y =*/{/*.val =*/{0x21bc2a34, 0xca9e2f0, 0x20eb6039, 0xe36605a, 0x2ddf1856, 0x3cb72b40, 0x144988f2, 0x36ad2c80, 0x9e15}}}, -{/*.x =*/{/*.val =*/{0x2b038315, 0x1a434c18, 0x1310e6f9, 0x2b310cda, 0x14b8629c, 0x1a038e5e, 0x312221e4, 0x15a1d59d, 0xaba5}}, - /*.y =*/{/*.val =*/{0x2e25fc0a, 0x26800fe6, 0xb63338f, 0x2fed4cb6, 0x130d6f3f, 0x15c3d894, 0x25edb63d, 0x1761ea8d, 0xa0e7}}}, -{/*.x =*/{/*.val =*/{0x15bc15b4, 0x32e684d2, 0x25a2ee69, 0x1d40a391, 0x17ca8d92, 0x163ba73b, 0x2adc9ed8, 0x38b947b, 0x10e9}}, - /*.y =*/{/*.val =*/{0x18aa258d, 0x13af9825, 0x2bb6a883, 0x296258c0, 0x2d1f754c, 0x1ea3185a, 0x1e0424d5, 0xdc0e035, 0xc68a}}}, -{/*.x =*/{/*.val =*/{0x3a1c0a80, 0x3d8aaf21, 0x25a9c740, 0x18945631, 0x2ff9c34d, 0x326f9c00, 0xcca5b17, 0x169a2985, 0xb6b1}}, - /*.y =*/{/*.val =*/{0x1ce0a03, 0x1b340441, 0x2e16eeb, 0x2684acc2, 0x2536d49c, 0x3888fbbd, 0x1b61ea54, 0xb8535b3, 0xfae6}}}, -{/*.x =*/{/*.val =*/{0x12b062d4, 0x1f2a942a, 0x3b6a141a, 0x1739f966, 0x2a227a7a, 0x2c5c4a0f, 0x2eaca06f, 0xfa90c95, 0x3596}}, - /*.y =*/{/*.val =*/{0x3bb25302, 0x42a9346, 0xde59b1a, 0x1020ae59, 0x8a96d0, 0x33865be7, 0x1e5c9bfc, 0x38515254, 0xf65b}}}, -{/*.x =*/{/*.val =*/{0x1d33fd27, 0x282fd714, 0x246cc62f, 0x17d5cf6d, 0x2361b44, 0x8e23b6a, 0x3e84cd02, 0xfc24898, 0x9ed7}}, - /*.y =*/{/*.val =*/{0x2716c458, 0x25cacb78, 0x2e449345, 0x2a08f96c, 0x6725494, 0x16d3cd09, 0x1eeeaee7, 0x2259faec, 0xb631}}}, -{/*.x =*/{/*.val =*/{0x2f028d83, 0x1e588ebb, 0x27439615, 0x25649b6e, 0x1e69db61, 0x2af96857, 0x385ec6a5, 0x3df138f1, 0xa7eb}}, - /*.y =*/{/*.val =*/{0x19d0bed1, 0x1900e4ae, 0x30539199, 0x28e249d2, 0x4804b47, 0x271cddc1, 0x362d5cfd, 0x54beff8, 0x6205}}}, -{/*.x =*/{/*.val =*/{0x3bb61ee5, 0xa21104d, 0x31f0c13f, 0x13c138be, 0x34ae6eda, 0x18e33625, 0x321b8662, 0xc8c3321, 0xd493}}, - /*.y =*/{/*.val =*/{0x25d694a8, 0x18b69343, 0x2438ddc6, 0x344b2316, 0xafb5e1a, 0x317a747b, 0x29d23edc, 0x26afd46, 0x21c}}}, -{/*.x =*/{/*.val =*/{0x2c04554a, 0xc3772f3, 0x288cffe5, 0x373feed1, 0x10a2ecaa, 0x194b09e8, 0x3d1a0474, 0xdf2261c, 0x896f}}, - /*.y =*/{/*.val =*/{0x129138df, 0x1a3e7f86, 0xc417dcd, 0x216d86b, 0x11bf1e6, 0x8aec13a, 0x2c4acda6, 0x8f9c892, 0x3804}}}, -{/*.x =*/{/*.val =*/{0x343fca26, 0x101df46a, 0x3bc23678, 0x3ee10768, 0x3578a27d, 0x308276fc, 0x36d6cca6, 0x2e5fddd2, 0x11b3}}, - /*.y =*/{/*.val =*/{0x1b679d58, 0xec9fabd, 0x39f9d42d, 0x2b88c712, 0x36d3bb3b, 0x159430bc, 0xc508cd, 0x7e7eb98, 0x6533}}}, -{/*.x =*/{/*.val =*/{0x8dfd587, 0x1e4d86ed, 0x1b026560, 0x312e8e32, 0x35a12d5e, 0x19eaa8b3, 0x508b348, 0x2d06eb3d, 0x5084}}, - /*.y =*/{/*.val =*/{0x11470e89, 0x39e7a5fe, 0x91f5606, 0x2dbd581a, 0x2927475d, 0x2a9b2154, 0xd31619, 0x18c68766, 0x34a9}}}, -{/*.x =*/{/*.val =*/{0x2c953fa9, 0x341655b5, 0xb8c3db4, 0x2ac98a7c, 0x118c0628, 0x3d21752f, 0x393233a5, 0x3443aaaa, 0xa49e}}, - /*.y =*/{/*.val =*/{0x6fb4c72, 0x1ecaf489, 0x28e181b6, 0x3a1d4d25, 0x1fddfb5a, 0x11db0283, 0x35398e03, 0x2e251983, 0xcc72}}}, -{/*.x =*/{/*.val =*/{0x27a1d916, 0x3025b4ff, 0x11f1f3a3, 0x16c28e57, 0x1bb07031, 0x18562997, 0x19d0cbac, 0x3e6b2db5, 0x650e}}, - /*.y =*/{/*.val =*/{0x3068387b, 0x16127299, 0x36c26ba8, 0x2ed18229, 0x1b82c558, 0x2702e49e, 0x2b11870e, 0x47c8458, 0x85d}}}, -{/*.x =*/{/*.val =*/{0x36fb2940, 0x37f07501, 0x2534042f, 0x7f01a6c, 0x2b8fbd71, 0x1d04e10a, 0x1c82fecb, 0x283bf680, 0x5083}}, - /*.y =*/{/*.val =*/{0x36ceee44, 0x378c0ed9, 0x2cdddf3b, 0x1a849b87, 0xdf19b08, 0x3ef7e189, 0x782bba8, 0x2bbe3ff9, 0xf064}}}, -{/*.x =*/{/*.val =*/{0x15bc8a44, 0x3bf74194, 0x3e151a19, 0x10405df2, 0x1a5fc768, 0x159692e9, 0xeda3d38, 0x20160f3f, 0x4d01}}, - /*.y =*/{/*.val =*/{0x1adbc09e, 0x3c7e5324, 0x182da362, 0x250811a1, 0x16381396, 0x26ea001f, 0xf5d367e, 0x31b0632d, 0x3a33}}}, -{/*.x =*/{/*.val =*/{0x135b4eb8, 0x14884f92, 0x38b5a3cf, 0x3d55fc6a, 0x2f2dce07, 0x3d528f32, 0x32256f0f, 0x1a390eb7, 0xc119}}, - /*.y =*/{/*.val =*/{0x2f911add, 0x11265b5, 0x2a7149b7, 0x3e2d2504, 0x366f8242, 0x27607f99, 0x2458f837, 0x39a4dde1, 0xbff5}}}, -{/*.x =*/{/*.val =*/{0x19dffc96, 0x256e8425, 0x3ac58572, 0xa33696b, 0x17eb0192, 0x26ce5720, 0x3deaf6f, 0x1b2fb852, 0x161c}}, - /*.y =*/{/*.val =*/{0x1b492de4, 0x24ef3d84, 0x2af8621c, 0x258d324b, 0x3183059b, 0x964e472, 0x1ff985bd, 0x32a4a9ae, 0x8a26}}}, -{/*.x =*/{/*.val =*/{0x369671d5, 0x35f9c967, 0x14eb83e3, 0xbbabd6d, 0x2bc96056, 0x7906af5, 0x39596d76, 0x3b1580f3, 0xa8c1}}, - /*.y =*/{/*.val =*/{0x333db746, 0xf22a034, 0x18f8b182, 0x2997eccc, 0x141c5924, 0x31cc9a4, 0x345ac755, 0x181447a7, 0x5fc3}}}, -{/*.x =*/{/*.val =*/{0x8a2050e, 0x6b10bf9, 0x15f8a677, 0xbbd55d8, 0x79b8974, 0x1da731b9, 0x731896b, 0x93f492f, 0x6737}}, - /*.y =*/{/*.val =*/{0x61d3d70, 0x24326924, 0x3349cc2b, 0x1aeb3f50, 0x86b6dbe, 0x120b026a, 0x24a20203, 0x2095e25a, 0xe4cf}}}, -{/*.x =*/{/*.val =*/{0x29a78179, 0x133d807e, 0x20d6afe3, 0x143a4149, 0x9ed9f6b, 0x291ccd88, 0x1b8dc905, 0x29fcdc20, 0x995c}}, - /*.y =*/{/*.val =*/{0x2fec1f47, 0xc7eed32, 0x2b64e529, 0x332155a6, 0x12863abb, 0xd362012, 0x3573ab5e, 0x167a5554, 0xd9a0}}}, -{/*.x =*/{/*.val =*/{0x49135d3, 0xf636176, 0x2e431fc1, 0x80f3404, 0x30b16a74, 0x4d0a504, 0x2a85a65c, 0x2f1fbe0, 0x594}}, - /*.y =*/{/*.val =*/{0x162255d2, 0xb5d146, 0x1902391d, 0xa18ca32, 0x36687af1, 0x16c31eaa, 0x3ab612f7, 0x1e617ad3, 0x9053}}}, -{/*.x =*/{/*.val =*/{0x39e68f51, 0x3de3a89e, 0x16b6e1d0, 0x1b87f2ae, 0xd870cf5, 0x301895ca, 0x26fcb74d, 0x116b276e, 0xc755}}, - /*.y =*/{/*.val =*/{0x38cfbbc1, 0x7120e25, 0x22ddf68d, 0x7246272, 0x168bf725, 0x163b6ca8, 0x855c2a7, 0xf11a8ef, 0x7c80}}}, -{/*.x =*/{/*.val =*/{0x41ead4b, 0x3fa21e68, 0x11b03c1f, 0x1d7b7eda, 0x3e76be3a, 0x11cd3beb, 0x3337ec71, 0x3032323, 0xbfc9}}, - /*.y =*/{/*.val =*/{0x6fedaed, 0x114b1bc2, 0x2e0ae3e7, 0x11a3bfcc, 0x42d36fb, 0x29c63754, 0xded24db, 0x206c7827, 0x7a94}}}, -{/*.x =*/{/*.val =*/{0x25b7ad0d, 0x253215bb, 0x1d0d1d36, 0x3b9d9f2a, 0x116c4476, 0x362925b, 0x1e00dc2d, 0x1a436aed, 0x3a55}}, - /*.y =*/{/*.val =*/{0x32e8c407, 0x1b261e42, 0x2c31218d, 0x32b2e2b2, 0x2f99f301, 0x7eeb25f, 0x657bfb2, 0x23865d68, 0xc3e2}}}, -{/*.x =*/{/*.val =*/{0x19b2df82, 0x9e91ec2, 0x3104fb19, 0x179e8591, 0x232c04ec, 0xb463b33, 0x3b92ccc9, 0x191718af, 0x405a}}, - /*.y =*/{/*.val =*/{0x9307dbf, 0x368a0d28, 0x2dc462b5, 0x3ea76cb3, 0x37e7122f, 0x2b298788, 0x196e0f5c, 0x2d053d13, 0xbc3c}}}, -{/*.x =*/{/*.val =*/{0x18f4033f, 0x9f0f311, 0x20ab6d3a, 0x12b3c96c, 0x28f817cc, 0x2c835e83, 0x3cfb3d2a, 0x51ad0e6, 0x10ba}}, - /*.y =*/{/*.val =*/{0x76d1fbf, 0x173dae53, 0x1c78b4ea, 0x6dacdfa, 0x129f3677, 0x283c19a8, 0xaef4b2a, 0x19b9747, 0xade1}}}, -{/*.x =*/{/*.val =*/{0x36e2d9b3, 0x12f4c1aa, 0x338d6351, 0x36e4a0c6, 0xf845641, 0xba984e7, 0x305e75e1, 0x53ce5f1, 0x19a3}}, - /*.y =*/{/*.val =*/{0xbaaaf33, 0x154bb897, 0x4be56d, 0x874749, 0x3528b3a5, 0x2597e21f, 0x328dd234, 0x363d76b1, 0x6cac}}}, -{/*.x =*/{/*.val =*/{0x23a52264, 0xb9cdf65, 0x1400b375, 0x2b7f00c5, 0x251cffd0, 0x1b8aa6ab, 0x7fe9a80, 0x37037a06, 0x85ff}}, - /*.y =*/{/*.val =*/{0x2da2082, 0x231f4a6a, 0x3179d049, 0x2060b24a, 0x14706c67, 0x15a3d415, 0x2948d0be, 0xc061eb8, 0x3fee}}}, -{/*.x =*/{/*.val =*/{0x36a88c9c, 0x307fd692, 0x149df069, 0x1eda198c, 0x2caa2aa3, 0x766b25c, 0x391398b2, 0x24207951, 0x7865}}, - /*.y =*/{/*.val =*/{0x35a7d19b, 0x38164d15, 0x3ab6a155, 0x33e466c0, 0x28196112, 0x23e9c897, 0x30d2b69e, 0xc1de4a8, 0x59a2}}}, -{/*.x =*/{/*.val =*/{0x1e8f7605, 0x374b71e3, 0x3ed2d35b, 0x13bde7d7, 0xff48bd4, 0x2ce44ba2, 0x159def16, 0x1100533a, 0x21ce}}, - /*.y =*/{/*.val =*/{0x955155f, 0xd791446, 0x46602c1, 0x38cd259a, 0x1da46ef4, 0x1bf5987c, 0xfaf75d9, 0x19c08e8b, 0x323a}}}, -{/*.x =*/{/*.val =*/{0x121ce204, 0x13b5d7a3, 0x26763d52, 0x29c96390, 0x26f72fb2, 0x1d361672, 0x3c64fb83, 0x107458ac, 0x43ca}}, - /*.y =*/{/*.val =*/{0x134a8f6b, 0x1494113a, 0x2a4a468e, 0x2db1eccf, 0x1ba31f9a, 0x143e4863, 0x23fa1c6, 0x16a0b8dc, 0xdcea}}}, -{/*.x =*/{/*.val =*/{0x14978583, 0x2ce90c80, 0x61613f5, 0x35ba6bbc, 0x392214cd, 0x21066643, 0x23137497, 0x3e26e73c, 0x30ab}}, - /*.y =*/{/*.val =*/{0x1dc75777, 0x118600d4, 0x3b584ac4, 0x483a88e, 0x21ab8063, 0x1ed3cb43, 0x37498cdf, 0x144551df, 0x4b03}}}, -{/*.x =*/{/*.val =*/{0x2c288015, 0x268df98f, 0x2dc99cc3, 0x1cfe14fb, 0x1b6aa646, 0x3eb18681, 0x2de6f681, 0x13aab64d, 0xaa01}}, - /*.y =*/{/*.val =*/{0x6c1006f, 0x3e053999, 0x3cecad9d, 0x12e6c1d0, 0x3b0f63ef, 0xa9f90fd, 0x2be9ac3f, 0x4f0118d, 0x3de9}}}, -{/*.x =*/{/*.val =*/{0x185bfe2, 0x34231245, 0xe5e42d3, 0x37e8ab9e, 0x2679cb5e, 0x2a82a0b3, 0xa0b0b56, 0x576fcdf, 0xe526}}, - /*.y =*/{/*.val =*/{0x2a0e5888, 0x33c042f, 0x245a9c44, 0x1dbfcb72, 0x32c1a284, 0x7e54a27, 0x488520f, 0xcd459b4, 0x5403}}}, -{/*.x =*/{/*.val =*/{0x59ab499, 0x2f674fc8, 0x273c330a, 0x4ca671b, 0x3f01bc0b, 0x65acf19, 0x5ba5d2, 0x2bfcc057, 0x78ba}}, - /*.y =*/{/*.val =*/{0x3ee097fd, 0x20748c63, 0x11251996, 0x18cbbba3, 0x2082e91, 0x2a1383b6, 0x2c0afafc, 0x3736f6c1, 0xad4b}}}, -{/*.x =*/{/*.val =*/{0x25cd5379, 0xc18ccc2, 0x70bcadc, 0x2de50e16, 0x24d2232d, 0x9206e2a, 0x11382a78, 0x1cb55af7, 0x17c0}}, - /*.y =*/{/*.val =*/{0x3108cd25, 0x1f2b8146, 0x25bad0df, 0x166b1d89, 0x1d034f89, 0x30491ebc, 0x1a064e77, 0x2f7d0a0f, 0xd901}}}, -{/*.x =*/{/*.val =*/{0xa2d8dae, 0x1e4f0063, 0x3d25ea95, 0xca97e47, 0x32256eac, 0x2c97be72, 0x192f9ba6, 0x7009884, 0x8827}}, - /*.y =*/{/*.val =*/{0x3e1e77d9, 0x2d09b03c, 0x317d099f, 0x21db71, 0x2bf5acc3, 0x322ceb96, 0x176aa401, 0x3754d41c, 0xd719}}}, -{/*.x =*/{/*.val =*/{0x1ee503a6, 0x2543ebf4, 0x124e1fba, 0x7a1493c, 0x2ec5ab43, 0x2a0c4661, 0x24a29aa6, 0x1fa04b8f, 0xceb6}}, - /*.y =*/{/*.val =*/{0xe98c4d1, 0x3ff50365, 0x269e2f31, 0x225b657b, 0x1cd86b4b, 0xf7de042, 0x10613b82, 0x21516b0e, 0x5e6a}}}, -{/*.x =*/{/*.val =*/{0x3ba9000, 0x37c1c8ea, 0x25e8b6f, 0x21cbe71a, 0x143dc4, 0x21d81d61, 0x1d8c1684, 0x1d3e7ffc, 0xac38}}, - /*.y =*/{/*.val =*/{0x2f10cf0a, 0x368f1f65, 0x366e9fa4, 0x178d435f, 0x117f9308, 0xb77a250, 0x1c069b86, 0x3a48c228, 0xaa65}}}, -{/*.x =*/{/*.val =*/{0x17ba402e, 0x39758c2c, 0x1042989a, 0x2e06970b, 0x8e3c3c3, 0x3ab43121, 0x3a02a58b, 0x6d73463, 0x8e89}}, - /*.y =*/{/*.val =*/{0x4fad9e0, 0x386d89e7, 0x157a7ee8, 0x19430908, 0x32a306af, 0x23439013, 0x2c6680b3, 0x3839aa7, 0xe5d3}}}, -{/*.x =*/{/*.val =*/{0x136bcfe8, 0x187b5879, 0x29b7bb3e, 0x305e7b5, 0x2b319a0e, 0x32a3c8c1, 0x2999b472, 0x3e2f0731, 0x1332}}, - /*.y =*/{/*.val =*/{0x1ae78402, 0x6c374b3, 0x1a8c2145, 0x24ed0935, 0x1c0681ba, 0x19f114d7, 0x2ed713f, 0x31fb8a58, 0xc39d}}}, -{/*.x =*/{/*.val =*/{0x2fddec6, 0x3fffb0cd, 0x111222c7, 0xb00f7df, 0x3f461492, 0x3678cde4, 0x220b4e9c, 0x7fead4f, 0x9f13}}, - /*.y =*/{/*.val =*/{0x9df8052, 0x3855dbc6, 0x3918eac6, 0x28c8d510, 0xec8d7d3, 0x34d25302, 0x326f4fef, 0x5302c, 0x3b21}}}, -{/*.x =*/{/*.val =*/{0x38c8ac7f, 0xa0bf97e, 0x1e2aa527, 0x490bb99, 0x16f84964, 0xce5b481, 0x22bbcb5c, 0x2cbef8e0, 0x9945}}, - /*.y =*/{/*.val =*/{0x29aea3b0, 0x1b650e85, 0x2dacdfa9, 0xbde88fb, 0x28eff528, 0x36d13fec, 0x3282d607, 0x3b6092c3, 0x3eef}}}, -{/*.x =*/{/*.val =*/{0x12fccf64, 0x2ea92662, 0x181318e3, 0x349e3789, 0x95dbf3b, 0x21dcb1df, 0x637db06, 0x45703ad, 0xc7d}}, - /*.y =*/{/*.val =*/{0x2878fee0, 0xfdb4ecc, 0x19ae68d5, 0x1e1760e5, 0xaf14548, 0x1092e11e, 0x1b0447aa, 0x1d1ec649, 0x4aa8}}}, -{/*.x =*/{/*.val =*/{0x148d5622, 0x2d6baeb1, 0x251bd2e8, 0x36c1fbde, 0x33381be1, 0x161aa06f, 0x9535a39, 0x3047985a, 0x5fc6}}, - /*.y =*/{/*.val =*/{0x1ac1683, 0x34361004, 0x2c7bf300, 0x16b4239, 0x367acb0e, 0x26e8b6c0, 0x1d9db9c1, 0x39526a8, 0x10e8}}}, -{/*.x =*/{/*.val =*/{0x33c85ecf, 0x1a5916ce, 0x15dacd7, 0x6e08398, 0xff0807d, 0xbd69fa, 0x23e20844, 0x22f56a48, 0x23dd}}, - /*.y =*/{/*.val =*/{0x274504ad, 0x1c2702ae, 0xec98f6f, 0x274c6013, 0x10d4b7fc, 0x7b4bf9c, 0x3d26f710, 0x26ef0094, 0x52d}}}, -{/*.x =*/{/*.val =*/{0x1136602, 0x2c2e9195, 0x19e3a5bb, 0x311bd203, 0x333b3d38, 0x1624dfc8, 0x2dfc33d0, 0x9ca0120, 0x87d1}}, - /*.y =*/{/*.val =*/{0x18af6aac, 0x3da0f107, 0x3d3bf7c4, 0x2a211d1b, 0x27745387, 0x289db3fd, 0x203de926, 0x921c296, 0x71ce}}}, -{/*.x =*/{/*.val =*/{0x30e74459, 0x1d28d722, 0x3ddb6dd6, 0x3c8dd8e1, 0x3c8a91fe, 0x3d1961c4, 0x5680590, 0x1e0753b0, 0x28df}}, - /*.y =*/{/*.val =*/{0x2f5e656f, 0x3781f303, 0x1ae6f0a8, 0x1e56e940, 0x322794a3, 0x36c5e243, 0x30f17cb0, 0x27a99a84, 0xf149}}}, -{/*.x =*/{/*.val =*/{0x29c71143, 0x11b67714, 0xf057ea3, 0x1fab6b11, 0x23fa352e, 0x1f33e400, 0x3ea103ca, 0x17e588ae, 0xeb4}}, - /*.y =*/{/*.val =*/{0xb70b136, 0x22a33688, 0x22b1bf4c, 0x165a7a9a, 0x1e2857d6, 0x1807d640, 0xbd0f573, 0xbd6160e, 0x52c4}}}, -{/*.x =*/{/*.val =*/{0x1507a7e6, 0x37cdaf22, 0x305f129b, 0x25896ebd, 0x310c41c0, 0xa1458cd, 0x1ad0d5f4, 0x142c15d1, 0x232d}}, - /*.y =*/{/*.val =*/{0x152b5892, 0x1c202084, 0x6459ccb, 0x18303bed, 0x2257f712, 0xe22b7c1, 0x33f6b086, 0xeb14d79, 0x780f}}}, -{/*.x =*/{/*.val =*/{0x177e7775, 0x222a29b8, 0xed95f63, 0x385564e2, 0x1291aeb5, 0x150eeb3d, 0x233cee58, 0x1a8ebfe5, 0x9d89}}, - /*.y =*/{/*.val =*/{0x3a056691, 0x3f3db4ea, 0x299253be, 0x26735fb8, 0x10927de8, 0x2593b5c9, 0x1bf0b94e, 0x2a790fd2, 0xdd91}}}, -{/*.x =*/{/*.val =*/{0xc904ed3, 0x1655fc7a, 0x5857841, 0xa9d1624, 0x272384df, 0x3e3990c4, 0x18dff97, 0x230b4b6e, 0xcf}}, - /*.y =*/{/*.val =*/{0x396f77c1, 0x2658ed, 0x32f6827b, 0x26475e74, 0x1bd81122, 0x35706f54, 0x1d44119d, 0x3a9e0, 0xaaad}}}, -{/*.x =*/{/*.val =*/{0xcf8cffd, 0x2cad6622, 0x3a45ae61, 0xb9ac56d, 0x1bdd8943, 0x2bee23de, 0x38c1bd45, 0x26dfc7f9, 0x80}}, - /*.y =*/{/*.val =*/{0xdb5f32f, 0x24751686, 0x12b9f93d, 0x28d03eb6, 0x12fdc912, 0x2320db79, 0x1a863028, 0x3808afd0, 0xf817}}}, -{/*.x =*/{/*.val =*/{0x2dc7a626, 0x11f741e6, 0x33cdcc02, 0x1772ade, 0x46b0734, 0x32bc48c9, 0x806bce4, 0x1b28b13e, 0x2f45}}, - /*.y =*/{/*.val =*/{0x25279532, 0x2b3ac002, 0x16eaea9e, 0x13236f70, 0x9f5302, 0x47ed991, 0x50544d2, 0x1c69e919, 0xf8cf}}}, -{/*.x =*/{/*.val =*/{0x1a328d6a, 0x2eaa0623, 0x1adc18bd, 0x135dcea5, 0x308fa7b2, 0x1a264616, 0x34e00a34, 0x3016e988, 0xc663}}, - /*.y =*/{/*.val =*/{0x3ec9b8c0, 0xec2edaa, 0x12bf9cc2, 0x21547a94, 0x171317dd, 0x2bf73c9d, 0x21c38d39, 0x3a6357dc, 0x3331}}}, -{/*.x =*/{/*.val =*/{0x22143fb0, 0x370d6995, 0x3c205dd6, 0x3ee4a0c2, 0x399597a9, 0x2bfcce51, 0x383790cf, 0x37070ceb, 0x292a}}, - /*.y =*/{/*.val =*/{0x236ad01c, 0x2a76d8f3, 0x35e9d4d8, 0xf998b5c, 0x4ecf6d8, 0x65a2833, 0xb647f3f, 0x1986f3b8, 0xa072}}}, -{/*.x =*/{/*.val =*/{0x30b90e0b, 0x27b079b0, 0x3094a458, 0x3fc74e7e, 0x675b3d6, 0x32012967, 0x67d3fed, 0x1fe6b55, 0xa435}}, - /*.y =*/{/*.val =*/{0x3a1fdc20, 0x3c002e64, 0x3599b5a3, 0xa880d94, 0xbe8c0dc, 0x341f32d0, 0x3d71a142, 0xb72530f, 0x7c8f}}}, -{/*.x =*/{/*.val =*/{0x188f4d82, 0x2e7474ad, 0x159204ac, 0x9937676, 0x21d6fcaf, 0x170c09b0, 0x1c515b0e, 0x1665c1b9, 0x6dd5}}, - /*.y =*/{/*.val =*/{0x14132ad3, 0x287aadab, 0x15927be5, 0x3db9c11b, 0x2d0f9478, 0x3346376d, 0x1233dd46, 0x109ff54d, 0xbc92}}}, -{/*.x =*/{/*.val =*/{0x1e05dccc, 0xcb60046, 0x19a93e5, 0xfe8fb53, 0x13d172ae, 0x1b825ae5, 0x1a030954, 0x3db85d4f, 0xb8ce}}, - /*.y =*/{/*.val =*/{0xc6d5750, 0x52833f, 0x26b68133, 0x1d5ff0da, 0x12bd99df, 0x3529d393, 0x9bbf6a4, 0x229829b3, 0x302b}}}, -{/*.x =*/{/*.val =*/{0x286df50d, 0x313bb405, 0x6f92bd0, 0x179e4a87, 0x82060cd, 0x361d10b0, 0x1f02d6f, 0x58c24d7, 0x3a57}}, - /*.y =*/{/*.val =*/{0x2859679b, 0x8562ca3, 0x3781a11d, 0x2abe07ae, 0x30a0dde0, 0x3cffcb95, 0x1f32f516, 0xe1ced66, 0x85e1}}}, -{/*.x =*/{/*.val =*/{0x388f7e09, 0xaa8ad9f, 0x27d92cde, 0x280dde6e, 0x1dc0beb3, 0x384b9691, 0x5fcbbd8, 0x218f53c8, 0x5e6a}}, - /*.y =*/{/*.val =*/{0x8dfca97, 0x2f58a19d, 0x3b4cfe3b, 0x23940dc8, 0x140234a6, 0x12a347da, 0x8edfc44, 0x681e28e, 0xc257}}}, -{/*.x =*/{/*.val =*/{0x1df66583, 0x3b2a229b, 0x25580609, 0x6433e68, 0x1ea87603, 0x38bdfbf, 0x2fd019c1, 0x1c6d48f0, 0x5281}}, - /*.y =*/{/*.val =*/{0x3f480c26, 0x3407b39, 0x3de01414, 0x8104f71, 0x1e8fb495, 0x2f3a351a, 0x27a6598, 0xe575ec3, 0x7b2c}}}, -{/*.x =*/{/*.val =*/{0x2521b3ff, 0x38a61193, 0x1aa750ce, 0xf01c5fa, 0x2e24a523, 0x1134afa6, 0x1455c75e, 0x138c0432, 0x248}}, - /*.y =*/{/*.val =*/{0x269da7e, 0x306b92e4, 0x23ac8bbc, 0x1c01b7a4, 0x2d0eebad, 0x30acf0ac, 0x3e30d07e, 0x34282a88, 0x9619}}}, -{/*.x =*/{/*.val =*/{0x692fd1, 0x2c982585, 0x3d90dfe2, 0x3d0f1b32, 0x1f190edc, 0x2ab7bd2c, 0x1ff800e0, 0x322d2640, 0x4e53}}, - /*.y =*/{/*.val =*/{0x328625e0, 0xd24c39c, 0x3fc97539, 0x1e943695, 0x219da1a8, 0x335c269c, 0x1a01e186, 0xf93d350, 0xdd6e}}}, -{/*.x =*/{/*.val =*/{0x3549827b, 0x2338d5f6, 0x121bd614, 0x313dfcf8, 0x2ce311fc, 0x4b81b78, 0x375f3a82, 0x343d7834, 0xce47}}, - /*.y =*/{/*.val =*/{0x2faed097, 0xf32697f, 0x5769df4, 0x39964bfc, 0x39ad0f29, 0x244e7f96, 0x30d49d58, 0x263ee658, 0x15c6}}}, -{/*.x =*/{/*.val =*/{0xc43da59, 0x3747b53a, 0x3a48ca2f, 0x6911b8a, 0x6cf9bc9, 0x1c4ebfe0, 0x21a3319b, 0x1f592302, 0x7115}}, - /*.y =*/{/*.val =*/{0x248d28ac, 0x1f7884ad, 0xcb6ad56, 0x33c28fe9, 0x11ab13fc, 0x28440e45, 0x303053f2, 0x35451759, 0x3d53}}}, -{/*.x =*/{/*.val =*/{0x3e889756, 0x37606ba6, 0x3004bb25, 0x1ed9265e, 0x1899f3f2, 0x3365ec9c, 0x1fea8226, 0x22f0cc84, 0x762e}}, - /*.y =*/{/*.val =*/{0x3ca6b774, 0x17896781, 0x84fa5e2, 0x1cb6cc52, 0x2e34719, 0x3313c526, 0x3e97c3c7, 0x250982bc, 0xc028}}}, -{/*.x =*/{/*.val =*/{0x26714560, 0x1d560296, 0x256c6c28, 0x1fc8409f, 0x25a85c24, 0x1fbd93c6, 0x2d36b9d4, 0xa9d55e6, 0x38b8}}, - /*.y =*/{/*.val =*/{0x2774299e, 0x36a1ccd2, 0x3716284a, 0x253c8efb, 0x2434597d, 0x3d58d185, 0x21ef428b, 0x29a5dbc9, 0xf9d8}}}, -{/*.x =*/{/*.val =*/{0x1b720b26, 0x188bac12, 0xccfcd07, 0x3ca0d7e6, 0x39062026, 0x1aefb504, 0x168ee1f4, 0x316ba6b2, 0x3e10}}, - /*.y =*/{/*.val =*/{0x2dd92db5, 0x11ba631e, 0x3e09e433, 0x3fde6936, 0x215e28e2, 0x1996ca1c, 0x288915a8, 0x31b3ff90, 0xc735}}}, -{/*.x =*/{/*.val =*/{0xc15cf94, 0x3710a097, 0x12082845, 0xff5aa0, 0x3569f8bd, 0x1bdc4615, 0xd97eb79, 0x2979dbec, 0x1dc5}}, - /*.y =*/{/*.val =*/{0x140ef8a2, 0x3e95399e, 0x25d97f94, 0xb6f12d6, 0x72d0c65, 0x1ccc46a4, 0x367d6019, 0x22b89d5f, 0x855b}}}, -{/*.x =*/{/*.val =*/{0x78ee8d, 0x3c142473, 0x6919442, 0x2fc83394, 0x1b4ff64e, 0x3dc98eaa, 0x1a9be25f, 0x15eb6167, 0xd08e}}, - /*.y =*/{/*.val =*/{0x2da63e86, 0x265fd370, 0x22ed9de, 0xfbdf3e5, 0x3e6df412, 0x5cbb9d5, 0x88d72d6, 0x25e612ad, 0x852e}}}, -{/*.x =*/{/*.val =*/{0xe9c22bc, 0x10eb950c, 0x1bcc42fd, 0x3699f5a4, 0x3c7be601, 0x2cd11366, 0x2eb23765, 0x33a97a67, 0x5335}}, - /*.y =*/{/*.val =*/{0xbdacb60, 0x30b099cb, 0xa1f19b3, 0x30c308db, 0xeb86ac8, 0x1fc203c3, 0x5224a06, 0x34081da7, 0x3bf8}}}, -{/*.x =*/{/*.val =*/{0xff4de54, 0x2f079885, 0x1d3c2be5, 0x32af647a, 0xa2858a5, 0x100c73c5, 0x202a2c3b, 0x370d577c, 0x5716}}, - /*.y =*/{/*.val =*/{0x10100fa5, 0xfa93f55, 0x47e417d, 0x3cffb334, 0x1324c5eb, 0x2a9986a6, 0x383f391e, 0x1b100296, 0x985f}}}, -{/*.x =*/{/*.val =*/{0x2336a875, 0x108cff13, 0x19d064c1, 0x3b71c748, 0x2f1b5099, 0x15be606, 0x2d4dd947, 0x16786af8, 0x24a6}}, - /*.y =*/{/*.val =*/{0x1112057c, 0x3cffa170, 0x1e0b96ab, 0x2911927a, 0x1cf34f69, 0xcc6f51f, 0x27240468, 0x2beb142f, 0xd3e1}}}, -{/*.x =*/{/*.val =*/{0x761d58d, 0x12eabcce, 0xd60e2f3, 0x1326f902, 0x20df7aca, 0x9028d5c, 0x3614610a, 0x1849e08f, 0xb8c4}}, - /*.y =*/{/*.val =*/{0x1d1051a4, 0xe3a82ea, 0x2107c5b6, 0x1d411e17, 0x33c5053f, 0x1163da5f, 0xe37d14a, 0x365b145c, 0x8f9e}}}, -{/*.x =*/{/*.val =*/{0x1166ff40, 0x537a868, 0x1fff36da, 0x3bafd290, 0x80a2eca, 0x20497639, 0x18d2b7c7, 0x100cc620, 0x6b00}}, - /*.y =*/{/*.val =*/{0x1d71b847, 0x2dd04c3a, 0x3f3ede9e, 0x1a20fdb9, 0xbf2f007, 0x250e8164, 0x2fac9968, 0x6ceba2a, 0x41cd}}}, -{/*.x =*/{/*.val =*/{0xd6bf1f, 0x114841ae, 0x24fcbb0, 0x2f40cfa6, 0x3346b946, 0x87a49da, 0xb83ca35, 0x1cd0d147, 0xc333}}, - /*.y =*/{/*.val =*/{0x3cb01f48, 0x25796108, 0x2266162f, 0x2e8d9083, 0x2c315598, 0x3fcc6bdc, 0x12cda13d, 0x3a4e46e0, 0x2eef}}}, -{/*.x =*/{/*.val =*/{0x34d9279c, 0x12d43f2a, 0x99a0075, 0x1e171e64, 0x3a845c28, 0x15c0bb20, 0x22c5776b, 0x38539f8a, 0x7121}}, - /*.y =*/{/*.val =*/{0x2f97b82e, 0x1c80a5f8, 0x1100d1ec, 0x3e8a0cd2, 0x35046e47, 0x2e865b4c, 0x105ca520, 0x30028c67, 0xf194}}}, -{/*.x =*/{/*.val =*/{0x2127b756, 0x2ea1ffd, 0x3a097048, 0x10a2f92a, 0x20b41603, 0xd8b6941, 0x1f12672d, 0x1e0bdc5b, 0x6d8c}}, - /*.y =*/{/*.val =*/{0x3f172571, 0x1547dd2a, 0x17cdcca6, 0xea9b68b, 0x134daf4e, 0x26a0b4db, 0x1b911145, 0x37c225bf, 0x99ae}}}, -{/*.x =*/{/*.val =*/{0x11a3c43c, 0x1312cb15, 0x2cee258e, 0x3dc072a3, 0x2e67140d, 0x307cad2a, 0x2cd5b48c, 0x36a519f2, 0x56c9}}, - /*.y =*/{/*.val =*/{0x20d7c9ed, 0x9362df4, 0x2edcaa18, 0x3503fe4c, 0xb685241, 0x31e59377, 0x39ec2f33, 0x1ab2d0b1, 0x38d4}}}, -{/*.x =*/{/*.val =*/{0x2df771c8, 0x27892740, 0x2094c87b, 0x1694847b, 0x1f875033, 0xb0acf00, 0x1c9029d3, 0x151b648b, 0xb71e}}, - /*.y =*/{/*.val =*/{0x13f48c51, 0x114e89be, 0x1bba2862, 0x2f548ad5, 0x2288f426, 0x4a93333, 0x1f900789, 0x3bea33b2, 0xe7cc}}}, -{/*.x =*/{/*.val =*/{0x2ee40896, 0x27f5e5b0, 0x1177f5bf, 0x2b8dea49, 0x261e6aa1, 0x1b819399, 0x36de46bb, 0x3c06c124, 0x7a0d}}, - /*.y =*/{/*.val =*/{0x44a7569, 0xb6393bc, 0x117da7f2, 0x8a28a35, 0x290e9aaa, 0x35abfd7a, 0x2fcd1b2a, 0x1d6038d5, 0xb446}}}, -{/*.x =*/{/*.val =*/{0x6e1346b, 0x28661277, 0x5af1c5e, 0x2f9ec40e, 0x1152c05a, 0x31d87c53, 0x2d10be54, 0x1a3fc260, 0x690}}, - /*.y =*/{/*.val =*/{0x17226c13, 0x2ed62953, 0xc6026e7, 0x3da24e65, 0x6442aa4, 0x176caf42, 0x3de26da8, 0x38f8242f, 0xb863}}}, -{/*.x =*/{/*.val =*/{0x3235c795, 0x2138aef1, 0x3d541d75, 0x362563a, 0x1c89d70b, 0x2c16cdf4, 0x3974b393, 0x11890d7b, 0x63c}}, - /*.y =*/{/*.val =*/{0x1b110258, 0x3ccb7025, 0x249a9bd3, 0x12b2eb3e, 0x1c85b69e, 0x3d98364c, 0x38404431, 0x26ee44c0, 0xe27f}}}, -{/*.x =*/{/*.val =*/{0x2c1cbaab, 0x34de9fc5, 0x33d564cf, 0x32ae1e40, 0x30635c1a, 0x2adb0629, 0x16071598, 0x2ba63ecd, 0xd031}}, - /*.y =*/{/*.val =*/{0x5116b26, 0x30e411fe, 0x3d65fdc4, 0x3ed293f6, 0xb4dcf6d, 0x39301ab7, 0x584e8e6, 0x25ad3a55, 0x4151}}}, -{/*.x =*/{/*.val =*/{0x1affca70, 0x3f44d85f, 0x14ce5fd1, 0x1addc21d, 0x12d1f999, 0x3565346a, 0x3861d3ff, 0x47bce91, 0xd4c0}}, - /*.y =*/{/*.val =*/{0x3d9c4777, 0x31fcb8a5, 0x256ebb09, 0xbd1ec15, 0x2b2906b2, 0x1d086400, 0x21566287, 0x12e620e9, 0x90b2}}}, -{/*.x =*/{/*.val =*/{0x17592d55, 0x300d67b3, 0xe350192, 0x356e51d0, 0x3ce3b106, 0x3fbda58c, 0x1052608a, 0x31b6f128, 0x5d2e}}, - /*.y =*/{/*.val =*/{0x2f5183a7, 0x19b9743a, 0x11151742, 0xa9ef36b, 0xcd6950e, 0x1c43e89a, 0x245eb58f, 0x337e271b, 0xa92}}}, -{/*.x =*/{/*.val =*/{0x255bf84c, 0x1d12e3e3, 0x30d9027a, 0x1931bb55, 0x3cae4fd9, 0x34f09488, 0x16cc8e5d, 0xa2673ae, 0x6278}}, - /*.y =*/{/*.val =*/{0x1f15fa2a, 0x3d473ead, 0x1d176ed6, 0x8379f7, 0x3267839a, 0x1525c8a5, 0x1a28901c, 0x2b290244, 0xd670}}}, -{/*.x =*/{/*.val =*/{0x339715c2, 0x2651c743, 0x18a529a3, 0x19487e, 0x33fedd69, 0x7de33a8, 0x23d85b41, 0x27a23c66, 0x2f18}}, - /*.y =*/{/*.val =*/{0x171dfea, 0x1a98d611, 0x36854f06, 0xcccf8b0, 0x10f9f7eb, 0x211d7b4, 0x1d7cfdf7, 0xe7e3cf1, 0xc91a}}}, -{/*.x =*/{/*.val =*/{0xa222636, 0xd7de0d8, 0x299b9d3, 0x1e81212d, 0x2f88e93a, 0x3ac63cd9, 0x8f0e572, 0x2fb8c76f, 0xe583}}, - /*.y =*/{/*.val =*/{0x36b01c43, 0x3ac98e19, 0x18800b01, 0xfa7944d, 0x1dc3ac25, 0x9d40507, 0x1ddd7416, 0x1479107b, 0x75b0}}}, -{/*.x =*/{/*.val =*/{0x138011fc, 0x1c049c00, 0x17285626, 0x165a99eb, 0x200a4d83, 0x2c4cc208, 0x1eb11156, 0x4e8c205, 0x6e83}}, - /*.y =*/{/*.val =*/{0x3f15ab7d, 0x2b2da7e8, 0x1c51f9a6, 0x2be456ba, 0x1ac30426, 0x4b6c807, 0xf204c1a, 0x2062f709, 0xc147}}}, -{/*.x =*/{/*.val =*/{0x195b6f7e, 0x25527d71, 0x38b2021f, 0x2ccad4f4, 0x1876cdbe, 0x14eab42, 0x1a30c83a, 0x1f474133, 0xa5ac}}, - /*.y =*/{/*.val =*/{0xab19c84, 0x236edcc2, 0x1818a484, 0x38e4583d, 0x19ee1b99, 0x30f2491f, 0xf55b36c, 0x2282ad50, 0xdf0b}}}, -{/*.x =*/{/*.val =*/{0xe81c1bc, 0x24e92b93, 0x2bb5b33b, 0x14d97962, 0xce767d2, 0x2056e35a, 0x4635ad, 0x3c15197, 0x336}}, - /*.y =*/{/*.val =*/{0x166cbedd, 0x1b74a259, 0x8115017, 0x5ca3ad7, 0x30675323, 0x1a710944, 0x350014ff, 0x2d7e4315, 0x7e48}}}, -{/*.x =*/{/*.val =*/{0x14bc0324, 0x2a208b00, 0x24d2cfc5, 0x21fc0a35, 0x2f119155, 0x198968d9, 0xe7c338e, 0x299908fa, 0xb96b}}, - /*.y =*/{/*.val =*/{0x36c2ee15, 0x2d3afff6, 0x25ba8374, 0x33948a51, 0x1876b383, 0x3119268a, 0x285dfbea, 0xb336cee, 0xe83c}}}, -{/*.x =*/{/*.val =*/{0x30b7b678, 0x9d76cce, 0xf638166, 0xf10c46f, 0x2b6c76f1, 0x21af2909, 0x231ba19, 0x125ccd39, 0x186e}}, - /*.y =*/{/*.val =*/{0x38d91fc1, 0x1e81dbcb, 0x9535dca, 0x1dc8951, 0x37e67e11, 0x3f209702, 0x3bd84aa7, 0x18392601, 0xc0d4}}}, -{/*.x =*/{/*.val =*/{0xbb9dc8f, 0x23226e1, 0x1edd333d, 0x2a7a4fbd, 0x2787d1ab, 0x3dc0d4d4, 0x26864248, 0x1073b870, 0xfd99}}, - /*.y =*/{/*.val =*/{0x259780d5, 0x10fab94f, 0x2fe938d7, 0x1cacbf7b, 0x859e678, 0x25f815e2, 0xe6f46de, 0x3b1d6f50, 0x7a41}}}, -{/*.x =*/{/*.val =*/{0x3b963645, 0xfa50cb0, 0x271f1f8e, 0x336ca01f, 0x3132fb2d, 0x11e068b8, 0xa63e6e7, 0x2553ec6e, 0xc5f0}}, - /*.y =*/{/*.val =*/{0x8be2dd, 0x2fe21d3c, 0x47be4ed, 0xc140ac0, 0x20d7e6a3, 0xf2d1009, 0xb6fb18a, 0x34c4086c, 0xd552}}}, -{/*.x =*/{/*.val =*/{0x3b6aa206, 0x370ed72e, 0x31c19bce, 0xd5807fd, 0x1ac744bd, 0x4e3fc55, 0x1f7d2ec7, 0x215da31f, 0x9dac}}, - /*.y =*/{/*.val =*/{0x13b30b86, 0x235f518a, 0x23ff64cc, 0x1aaae446, 0x3bde77fa, 0x90ceda, 0x37bba791, 0x32b82b93, 0xb23c}}}, -{/*.x =*/{/*.val =*/{0x123809fa, 0x238ae3b7, 0x1d954be1, 0x21172cd4, 0x51f08fd, 0x24cd8fc9, 0x9f228ba, 0x76f8b94, 0x3838}}, - /*.y =*/{/*.val =*/{0x331fed52, 0x35c1d460, 0x2d8f24db, 0x207f32cc, 0xeb1cc36, 0x10169548, 0x117dcb09, 0xb4283ee, 0xe4a3}}}, -{/*.x =*/{/*.val =*/{0x3663da4, 0x2059b064, 0x35d0b81f, 0x28d8a467, 0x4aa2ba5, 0x229bb5f1, 0x1705e680, 0x128d5aa9, 0x6a66}}, - /*.y =*/{/*.val =*/{0x33fc22c4, 0xa0c4fec, 0x26c04c9c, 0x2645849f, 0x3f0cd508, 0x21bb065a, 0x1e98b29f, 0x496553f, 0x449a}}}, -{/*.x =*/{/*.val =*/{0x5ed815e, 0x3dc0b54, 0x1c017b47, 0x3d102af0, 0x147ad166, 0x17eb4865, 0x34a32ebb, 0x36b19e7d, 0x5568}}, - /*.y =*/{/*.val =*/{0x602df0, 0x26efd930, 0x2582151d, 0x17dfbb8, 0x73f2beb, 0x35bf8074, 0xba64580, 0x3e1d09e2, 0x7a85}}}, -{/*.x =*/{/*.val =*/{0x1ee840f8, 0x105d4ebc, 0x13c98f26, 0x4070980, 0x325cbe11, 0x2752e0a5, 0x3be4ecfc, 0x16a03720, 0x8719}}, - /*.y =*/{/*.val =*/{0x27eed395, 0x8a09a41, 0xa8dfa80, 0x22709c24, 0x1a2138dd, 0x3db76d2a, 0xe3aeb15, 0x773265b, 0x603}}}, -{/*.x =*/{/*.val =*/{0x2bf05bd6, 0xe67c139, 0x12a99465, 0x3d5b80c8, 0x70deca2, 0xbd47fad, 0x4fe9083, 0xc906fb9, 0x900c}}, - /*.y =*/{/*.val =*/{0x300d358b, 0x394ab4ef, 0x4efb15d, 0x2614d60f, 0xb2439d6, 0x31c8115c, 0x1f0f5f95, 0x3e7a3a2c, 0x6c31}}}, -{/*.x =*/{/*.val =*/{0x272e294d, 0x39becbde, 0xd0dd5b, 0x163ae8fc, 0x37edc6f1, 0xa27abb7, 0x134b91a6, 0x39201735, 0x29df}}, - /*.y =*/{/*.val =*/{0x2c469b52, 0x104dc983, 0x129ee694, 0x3c65870e, 0x205e4dd1, 0xd39d622, 0x272e19b4, 0x3609b401, 0xbf66}}}, -{/*.x =*/{/*.val =*/{0x33773f7, 0x31fc011b, 0x1b599953, 0x3513f4d1, 0x2372a150, 0x10430027, 0x1236d3e1, 0xc89bd77, 0x355b}}, - /*.y =*/{/*.val =*/{0x1887c182, 0x14f0ffc, 0xe251090, 0x977de33, 0x21fcb81e, 0x43bb774, 0x303ad49f, 0x29201c11, 0x8ec}}}, -{/*.x =*/{/*.val =*/{0x141fcc76, 0x10109c92, 0x227146b3, 0x34d666d9, 0x278a558d, 0x2ca70c2, 0x2d4ad848, 0x30c91061, 0x2a1e}}, - /*.y =*/{/*.val =*/{0x2451553f, 0x2837c990, 0x382a3120, 0x1549d580, 0x3e3b61b2, 0x2fb05054, 0x1cacf4c1, 0x20b9a3d9, 0xe01e}}}, -{/*.x =*/{/*.val =*/{0x2bfd913d, 0xfe5580f, 0x254c9eac, 0x29a039bb, 0x2a8d2050, 0x1e82130, 0x3ddf874d, 0xaa9fa41, 0x3636}}, - /*.y =*/{/*.val =*/{0x52e243d, 0x113e6bab, 0x2b2faafc, 0xc2ec435, 0x1a2a82d8, 0x18910dc3, 0xafd5341, 0x1e19db2e, 0x48f2}}}, -{/*.x =*/{/*.val =*/{0x375732c0, 0x1661934d, 0x33777aa8, 0xbf979c8, 0x31096e20, 0x29746df2, 0x34b9b624, 0x33cc7e2d, 0x8f3c}}, - /*.y =*/{/*.val =*/{0x25b9415b, 0x1cef7979, 0x858825e, 0x39a1dd5, 0xe53d8a9, 0x3d1b665f, 0x1e53189e, 0x334f8b4e, 0x67f1}}}, -{/*.x =*/{/*.val =*/{0x34889f3f, 0xa87e0e4, 0x1095da7f, 0x3faca2d1, 0x29b0ebc4, 0x28d1a6c5, 0x2119621e, 0x409bc6c, 0x8799}}, - /*.y =*/{/*.val =*/{0x3bb792b, 0x278b7e6f, 0x286037b4, 0xcbd86fc, 0x3f279de9, 0xbcb2dc5, 0x11d96213, 0x2e53296a, 0xddea}}}, -{/*.x =*/{/*.val =*/{0x2fa4e07e, 0x37614061, 0x3423bec4, 0xb29d215, 0x337d9a49, 0x7040ffe, 0x35718422, 0x2be545f7, 0x37d7}}, - /*.y =*/{/*.val =*/{0x2e020165, 0x24db61da, 0x18a65a4c, 0x8faa25e, 0x19c556c4, 0xecd4b18, 0x133c8f47, 0x1ea4a06a, 0x35bc}}}, -{/*.x =*/{/*.val =*/{0x3aee42db, 0x3e7f4af, 0x330714a7, 0x2eef16d1, 0x2cbfc1d9, 0x2dbb6e47, 0x19150fc7, 0x9f9f66d, 0xcc34}}, - /*.y =*/{/*.val =*/{0x15d87bdb, 0x188a7004, 0x272422dc, 0x3972eb63, 0x21520010, 0x38ff4fec, 0x1c6a1885, 0x26106948, 0xea24}}}, -{/*.x =*/{/*.val =*/{0x2e96e4f1, 0x2c29c594, 0x2e80030c, 0x17c05802, 0x1efccaff, 0x1ddc20cd, 0x197e201, 0x523c066, 0x56bb}}, - /*.y =*/{/*.val =*/{0x2eb0582e, 0x2227c067, 0x4af0eb5, 0x4f47480, 0x30ea9f73, 0xfb62f8, 0xa33beb, 0x2129584c, 0xa095}}}, -{/*.x =*/{/*.val =*/{0x1f23d1f, 0x1315fd66, 0xc036d8a, 0x2c97f5c8, 0x18a0a6b6, 0x3522787f, 0x30bbbbd3, 0x3a054f59, 0xb398}}, - /*.y =*/{/*.val =*/{0x32ff3fc, 0x160faffe, 0x26156cd1, 0x1e4762b4, 0xba52ea, 0x1ffacbec, 0x1f47f07f, 0x270895cb, 0x69f5}}}, -{/*.x =*/{/*.val =*/{0x34fb6a39, 0x9f576c6, 0x2ac90ecd, 0x235ab493, 0x1e119b8b, 0x3f4a59c, 0x1ea6e43e, 0x25abd5e5, 0x459}}, - /*.y =*/{/*.val =*/{0x725bb62, 0x30ab6de8, 0x20010535, 0x388a2d03, 0x2eef0373, 0x218a0837, 0x26c33672, 0x2b8338e0, 0xd3f9}}}, -{/*.x =*/{/*.val =*/{0x319888e9, 0xe73c9e4, 0x2448a8b4, 0x4ae9afc, 0x2681673d, 0x1834c0a5, 0x3a6e2dde, 0x3a9dceb0, 0x1f90}}, - /*.y =*/{/*.val =*/{0x2f113b79, 0x1bf7f25f, 0x19522e65, 0xdd47fb9, 0x2b96a821, 0x54f49c7, 0x2a10e958, 0xd9f0576, 0x89be}}}, -{/*.x =*/{/*.val =*/{0x1bf6c42, 0xfaacf77, 0x19887539, 0x1e4f66c4, 0xee74ef7, 0x1195205b, 0x105c7ee7, 0x6cf35b0, 0xd02e}}, - /*.y =*/{/*.val =*/{0x7bc54cc, 0xcd8ca3e, 0x31b6aac1, 0x2961e6e4, 0x124526bc, 0xc89c343, 0x22258127, 0x1d3cf2a3, 0x9a0b}}}, -{/*.x =*/{/*.val =*/{0xf6c15c2, 0x7bd1fc6, 0xf38f1ca, 0x39d90532, 0x1143483d, 0x1ce604e7, 0x1757fea1, 0x2a14af28, 0x8456}}, - /*.y =*/{/*.val =*/{0xb174134, 0x3c7bf0ca, 0x16fb671f, 0x3243c261, 0x79e7f4c, 0x127b0dc4, 0x2cdefd3, 0x3691b521, 0xe1b9}}}, -{/*.x =*/{/*.val =*/{0x27df614a, 0x1d47ebb3, 0x24705eb2, 0x27f39a4c, 0x3e1804d7, 0x91aa7fa, 0x33049180, 0x3966340b, 0xa7d2}}, - /*.y =*/{/*.val =*/{0x159b4c8d, 0x3c32f0e5, 0x19bc8656, 0x3c01de54, 0x3fa2de53, 0x207bb042, 0x10172c79, 0x33512f0, 0x62a2}}}, -{/*.x =*/{/*.val =*/{0xca1c4f9, 0x16d0aa86, 0x2b7e2823, 0x13bf8d32, 0x1f16f44f, 0x2e0f698, 0x1728c4c4, 0x3de3c8af, 0x7815}}, - /*.y =*/{/*.val =*/{0x3778bc15, 0x2ac7a8da, 0x177d1e19, 0x2d0b7985, 0x18c35d5c, 0x24f3cc51, 0x1af6a7dd, 0x7a334e, 0xc1c6}}}, -{/*.x =*/{/*.val =*/{0x3ed5996, 0x37933a2d, 0x360af53b, 0xc7f9664, 0x1b92468, 0x3ef240ca, 0x1a4ea492, 0x2dfa7fa6, 0x1a46}}, - /*.y =*/{/*.val =*/{0x28c85cae, 0x3b93b447, 0x352745c2, 0x21e52a7b, 0x23ebf550, 0x3b821281, 0x1dc570e3, 0x3a07a8fc, 0x683c}}}, -{/*.x =*/{/*.val =*/{0x2e2e607b, 0x3d34d673, 0xf36aa1, 0x2a87bb1b, 0x3fdd2b88, 0x447d595, 0x1772c20d, 0xfd9ff4c, 0x773}}, - /*.y =*/{/*.val =*/{0xc614763, 0x28bcc477, 0x3e017d26, 0x38ef7816, 0x3156f489, 0x18ea316e, 0x38285eae, 0x3a3eeb05, 0xfd9f}}}, -{/*.x =*/{/*.val =*/{0x354d61d1, 0x3ecb8807, 0x30b99baf, 0x549d76f, 0x1bf21517, 0x23e67901, 0x3ed8b9c5, 0x4f91d89, 0x875e}}, - /*.y =*/{/*.val =*/{0x945747, 0x12a27470, 0x273c5309, 0x277543a5, 0x399e3601, 0x1b784f4d, 0x56e8f64, 0x37712a59, 0x2d8f}}}, -{/*.x =*/{/*.val =*/{0x2fd53ed3, 0x17245d60, 0x1a56ccef, 0xfdd3ee7, 0x1f7c4916, 0x3d82e4c7, 0x372ad5b8, 0x2f56659, 0x2084}}, - /*.y =*/{/*.val =*/{0x1a7a7132, 0x1c50ff94, 0xe708998, 0x21f11ce5, 0x3afac254, 0x2f51da9a, 0x18243487, 0xd25f3b0, 0xf299}}}, -{/*.x =*/{/*.val =*/{0x2032f9a2, 0x122e38a4, 0x21fc6ccc, 0x159bd43e, 0x3f8f63ce, 0xdd32cc7, 0x32640ed2, 0x31af669a, 0x25aa}}, - /*.y =*/{/*.val =*/{0x2b51d4f0, 0x1d88c284, 0x19f3d9e, 0x2620eef1, 0x3190f655, 0xcbd53d3, 0x546c16f, 0x318ee991, 0xf5a6}}}, -{/*.x =*/{/*.val =*/{0x14445a7a, 0x4c72ea, 0x1cf1ec59, 0x254d7c20, 0x1c8d5df, 0x3c46db18, 0x2c6bfb12, 0x3bef27c1, 0xf82f}}, - /*.y =*/{/*.val =*/{0x242a7a98, 0x18eb3861, 0x240d1e59, 0x720ed91, 0xb4a4b5, 0xe50b065, 0x36b67550, 0xdef71be, 0x94bb}}}, -{/*.x =*/{/*.val =*/{0x362b8df9, 0xcb7ede8, 0x1da21c57, 0x7f6d47d, 0x11c8bd49, 0xcb74b72, 0x1c0cd9a8, 0x37634fb7, 0x11c4}}, - /*.y =*/{/*.val =*/{0x296edd30, 0x60c9e79, 0x2ec5448f, 0x2df9f498, 0x10fb6417, 0xd810e22, 0xac2aae4, 0x361da2fd, 0x45b3}}}, -{/*.x =*/{/*.val =*/{0x1def001d, 0x13c89769, 0x9ba27ef, 0x3e6ef5a6, 0x23b64b21, 0x2f47027, 0x22caf20e, 0x28cb6c9f, 0xa549}}, - /*.y =*/{/*.val =*/{0x30624783, 0x3576c69f, 0x2c9705ad, 0x5078a98, 0x259456eb, 0x330c3b62, 0x166cbdf4, 0x1e9e41b6, 0x799b}}}, -{/*.x =*/{/*.val =*/{0x206e37a, 0x91de2b1, 0x504731a, 0x23062523, 0x1a274f4d, 0x3a0fd1ad, 0x28002cf4, 0x2ae1fca1, 0xb526}}, - /*.y =*/{/*.val =*/{0x30c5ccab, 0x3cd9e3ff, 0xfa392ab, 0x3394e6c0, 0x26f18d28, 0x2ab3b582, 0xd8ed5c, 0xd75de04, 0x641f}}}, -{/*.x =*/{/*.val =*/{0x39d9123f, 0x3a4e0c7a, 0x388ba7d7, 0x3f1e46c7, 0x3d1e9129, 0x17e3b2be, 0x26a6f2f9, 0x14e3dcaa, 0x341b}}, - /*.y =*/{/*.val =*/{0x18bb9a40, 0x27a82abc, 0x12a26ed1, 0x37b9a9c1, 0x24d9ac72, 0x3cbc1044, 0x1c59eba6, 0x491c670, 0x5858}}}, -{/*.x =*/{/*.val =*/{0x760cb4d, 0x25763239, 0x33a69b68, 0x21f81500, 0x30673803, 0x154bafb0, 0x9df521a, 0x1fb94e37, 0xbca3}}, - /*.y =*/{/*.val =*/{0x24e10d88, 0x29dc18da, 0x8df9cf3, 0x5d5563c, 0x2ffbad9f, 0x22e020ee, 0x2d4b2263, 0xec707ef, 0x3ce0}}}, -{/*.x =*/{/*.val =*/{0xfb64db3, 0x1ee6354e, 0x1dd53841, 0x3b79328e, 0x13b8d6a7, 0x2ee0fef9, 0x1ccb740b, 0x8e48a6f, 0xc114}}, - /*.y =*/{/*.val =*/{0x3c0259be, 0x8c33a7f, 0x14567d1e, 0x1d602413, 0x178bd1a8, 0x3b3793fa, 0x6fc2a5c, 0x3db716d2, 0x1237}}}, -{/*.x =*/{/*.val =*/{0x311349e2, 0x20cab77, 0x3524c058, 0x38fb3d05, 0x1ad78d60, 0x51fa690, 0x1c2e7e62, 0x20c931ae, 0xf805}}, - /*.y =*/{/*.val =*/{0x1b2025fc, 0x3eb11a79, 0x26de88d5, 0x25262d58, 0x21122350, 0x206a983a, 0x56cdcde, 0x39682a2, 0x95c6}}}, -{/*.x =*/{/*.val =*/{0x2e548418, 0x1cdc7446, 0x9839231, 0x39221f62, 0x3a341adc, 0x1cac14d, 0x17e292fb, 0x2c327920, 0x2e6d}}, - /*.y =*/{/*.val =*/{0x10a2b918, 0x1a5e4b00, 0x1c3f5f1e, 0x23875cf8, 0x2911644b, 0xc5225e2, 0x36fbfa21, 0x1a90475d, 0x74eb}}}, -{/*.x =*/{/*.val =*/{0x3ccbdf95, 0x2b8fa3b1, 0xa5853b4, 0x8ac7291, 0x22f5494, 0x360c0ab2, 0x313050f, 0xbb60387, 0xcea0}}, - /*.y =*/{/*.val =*/{0x324a006c, 0x39954baa, 0x2ecc53d9, 0x2e8a1483, 0x10b433b2, 0x3301f5b, 0x34a6f04e, 0x1b1b61df, 0xfc00}}}, -{/*.x =*/{/*.val =*/{0x171c032b, 0x3536858a, 0x3afdc980, 0x1ad9a285, 0x766c5ff, 0x46d7f7f, 0x2603dd, 0x2a3f35b8, 0x71eb}}, - /*.y =*/{/*.val =*/{0x1668359f, 0x1ead6a38, 0x34b4755e, 0x24c6b45d, 0xcbb7f71, 0x18145bd5, 0x1d39def6, 0x49892d8, 0xd2ff}}}, -{/*.x =*/{/*.val =*/{0x3aaa138b, 0x37c367dc, 0x3786cd66, 0x3bee82fb, 0x671ff63, 0xfaf0631, 0x3ae28794, 0x389274f0, 0x417f}}, - /*.y =*/{/*.val =*/{0xa1ae869, 0x7246ccd, 0x5566afd, 0x276bf7b0, 0x3a9e57c1, 0x2974a7c3, 0x23e38c20, 0x2275ef34, 0x235}}}, -{/*.x =*/{/*.val =*/{0x307e636, 0x38562d04, 0x21611d97, 0x29df79cc, 0x2112c8b4, 0x2f0a6f68, 0x76443dd, 0x3c58058e, 0x2219}}, - /*.y =*/{/*.val =*/{0x31f15109, 0x1e86cb5, 0x373af55e, 0x35c8c34f, 0x230bd6d, 0x1b53c6e, 0x2a2f61b8, 0x212b172d, 0x4a9}}}, -{/*.x =*/{/*.val =*/{0x377220dc, 0x14ca7db7, 0x16023891, 0x27c96229, 0xe83bbd4, 0x27b40409, 0x2a8ad6a5, 0x3e507c9e, 0xffb2}}, - /*.y =*/{/*.val =*/{0x1b32b3bc, 0x26083b0c, 0x35e5f9f3, 0x3948efcf, 0x59d2f2c, 0x3e5e242, 0x3be7a03c, 0x34ffe08a, 0xf97e}}}, -{/*.x =*/{/*.val =*/{0xd9ed6c1, 0x1a2bad63, 0x3d593d6b, 0x139d16f0, 0x1edd0ec2, 0x3f061dc1, 0xf53e80b, 0xcdb72dd, 0x328}}, - /*.y =*/{/*.val =*/{0x38fafeee, 0x3b1baf9b, 0x1cb494ad, 0x16fd37c9, 0xd7c8c26, 0x35650e88, 0x19f28c46, 0x260e04bf, 0x71a8}}}, -{/*.x =*/{/*.val =*/{0x26da57e4, 0x2dd59229, 0x1cdd9f86, 0x31265bbf, 0x31bc1e98, 0x3a8a9d18, 0x118b9dbd, 0x36b8e60e, 0x690c}}, - /*.y =*/{/*.val =*/{0x133f33bb, 0x2d8656d2, 0x295a3d42, 0x18f63ef3, 0x15894df8, 0x3f646fd6, 0x379a47a9, 0x371e59de, 0x840a}}}, -{/*.x =*/{/*.val =*/{0x1cfb8036, 0x3e6262a9, 0xda35085, 0x3426a4b0, 0x167e833a, 0x45f747f, 0x247b48ae, 0x9d47ec5, 0xcff6}}, - /*.y =*/{/*.val =*/{0x24f59de0, 0x10fced68, 0x20328258, 0x2962763d, 0x2143c678, 0x38d2d621, 0x2d1ac5f, 0x3b49af55, 0xcdf4}}}, -{/*.x =*/{/*.val =*/{0x20ebec47, 0x1da4a12b, 0x142ca23d, 0x381398c4, 0x3b4ea72e, 0x10de9936, 0x27df9761, 0xe5dc744, 0xe8b6}}, - /*.y =*/{/*.val =*/{0x2eb3d8a7, 0x32a7875c, 0x15fe035, 0x398b696, 0x3ff204be, 0x6555e5f, 0x32e11ae7, 0xb7e8107, 0x5f38}}}, -{/*.x =*/{/*.val =*/{0x3319c869, 0x3df1bab8, 0x21eb2702, 0x2a7e575d, 0xcacdc18, 0x20e408bf, 0x33fc8d01, 0x1176605, 0x3018}}, - /*.y =*/{/*.val =*/{0x12b856f0, 0x3031db27, 0x23d9a7bf, 0xaa13292, 0x222e3bca, 0x1890c835, 0x3b7b6f86, 0x315e0940, 0xac5f}}}, -{/*.x =*/{/*.val =*/{0x18953133, 0x11df726c, 0x8721ae6, 0x2ced0a9d, 0xcdfa97f, 0xa01b03f, 0x1dd23881, 0xad3fb43, 0xa0b}}, - /*.y =*/{/*.val =*/{0x34af0fc9, 0x2f0928dc, 0xed4ba94, 0x28e13a2c, 0x58c8d6f, 0x71b2a19, 0x2bf2f03c, 0x60b3ed6, 0xcda1}}}, -{/*.x =*/{/*.val =*/{0x1f0a2a53, 0x3abc3b03, 0x16611e7, 0x772acfe, 0x29b892d5, 0xe515d0e, 0x3997c3a8, 0x146341f0, 0x6f86}}, - /*.y =*/{/*.val =*/{0x333bfeb2, 0x4e695d1, 0x2a05f351, 0x153ddcba, 0x309968bf, 0x1dbaa569, 0x182f29b7, 0x3d85bf51, 0xd50a}}}, -{/*.x =*/{/*.val =*/{0x278b4a0d, 0x1e78672f, 0x8c9be06, 0x3ed83c9f, 0x1c73ace4, 0xf5d6ed2, 0x3db4e1cb, 0x10bae9a8, 0x2f98}}, - /*.y =*/{/*.val =*/{0x33f39758, 0xd4cafba, 0x3d54f320, 0x23bab9da, 0xbb8f48b, 0x32489c59, 0x355552a1, 0x35a4c2f7, 0x4774}}}, -{/*.x =*/{/*.val =*/{0x3874b839, 0x444a1d5, 0x13d2b418, 0x10456ce5, 0x30b6aebe, 0x37c37ec8, 0x1e5a8053, 0x2e07f038, 0x3e03}}, - /*.y =*/{/*.val =*/{0x3c0594ba, 0x3073959, 0x1ab5b8da, 0x39717c3f, 0x198f667d, 0x3d981d5c, 0x7f42c44, 0x3858f7fc, 0xd13a}}}, -{/*.x =*/{/*.val =*/{0x39a7d197, 0x2eba434e, 0xea59459, 0x20ea3062, 0x2c234b5e, 0x23ff8288, 0x1f639477, 0x22950a03, 0xc2c5}}, - /*.y =*/{/*.val =*/{0x9eeb5e9, 0x390732fe, 0x1ad82484, 0x11fb1151, 0x2d39a60a, 0x106ad8b, 0x20927573, 0xca20d9b, 0x72ea}}}, -{/*.x =*/{/*.val =*/{0x23369217, 0x1d379b65, 0x6611ead, 0x70e5a40, 0x4eacdca, 0x289e3d50, 0xd624a21, 0x143ff2e9, 0x42dc}}, - /*.y =*/{/*.val =*/{0x3e2dbc57, 0x30c25f88, 0xe01e841, 0x284e7b2a, 0xba853a7, 0x1e3d7c58, 0x5b1d7ed, 0x2687d98e, 0xa5ba}}}, -{/*.x =*/{/*.val =*/{0x19251fa2, 0x1e7e8b49, 0x3c26cc92, 0x337ea0ae, 0x13d5e1bb, 0x1d1678dc, 0x1a1202b0, 0x31d972a4, 0x417}}, - /*.y =*/{/*.val =*/{0x3ebc52fa, 0x24c1240a, 0x161ee899, 0x292c61dd, 0x6283ad9, 0x1a19d99f, 0x357f5349, 0x397544b1, 0x72d7}}}, -{/*.x =*/{/*.val =*/{0x2cde4cf3, 0x26554187, 0x38a066ab, 0x10394d51, 0x1d9ae793, 0x30b49b45, 0x22c3be7, 0x2ad2b045, 0x384d}}, - /*.y =*/{/*.val =*/{0x252d0566, 0x1f1e5ac8, 0x351ba73b, 0x10c28ce5, 0x34c6f01f, 0x13b5b68a, 0x1ca43bfb, 0x316f346e, 0xd6e3}}}, -{/*.x =*/{/*.val =*/{0xa972627, 0x290d9a82, 0x2521e1f8, 0x24858100, 0x441a0e1, 0x2307bf2f, 0x3e15c819, 0x21c2526f, 0x8a31}}, - /*.y =*/{/*.val =*/{0x6bb8af9, 0x1ed1ed59, 0x3efcbcce, 0x110d96b0, 0x7baa417, 0x1dfb4a16, 0x3a64d095, 0x1f21da3d, 0x64bb}}}, -{/*.x =*/{/*.val =*/{0xa3a1550, 0x2951319f, 0x2ffdf279, 0x76a67e3, 0x38b75180, 0xc25db87, 0x157412dd, 0x1a6acd01, 0xebfc}}, - /*.y =*/{/*.val =*/{0x1362f6e, 0x7d0afd9, 0x28c0b195, 0x20f20639, 0x34fd0779, 0x3c6676df, 0xb540a3d, 0x3a336e67, 0xe2ff}}}, -{/*.x =*/{/*.val =*/{0x14f24bf1, 0x3e2ba88c, 0x2c500d25, 0x15500782, 0xe78708e, 0x1cdd2f0d, 0x2d024ec7, 0xeaf6dad, 0x6299}}, - /*.y =*/{/*.val =*/{0x108d1b1d, 0x34eb50c5, 0x148c6775, 0x24d4c0b2, 0x3c429b1d, 0x34b2bf8c, 0x29b93a00, 0x1cac2bab, 0x86fb}}}, -{/*.x =*/{/*.val =*/{0x39d681f9, 0x164153f9, 0x8feb9fc, 0x3383bbeb, 0x2c94b066, 0x1ffc9780, 0x3230888b, 0x3f7c9dd7, 0xc745}}, - /*.y =*/{/*.val =*/{0x3bbb1247, 0xc5cd0d, 0x27d45c76, 0x36f4cd71, 0x2818678c, 0x4e531c3, 0x1e5e78a7, 0x8bcbdae, 0x5902}}}, -{/*.x =*/{/*.val =*/{0x249a2115, 0x1dff54d1, 0x3a565ebe, 0x1e580245, 0x981aec, 0x1ab2a759, 0xc6c6dd4, 0x3014ac65, 0xfd73}}, - /*.y =*/{/*.val =*/{0x26ba6cda, 0x1272adee, 0x29d421f0, 0x3d80558b, 0x37d6d904, 0x2aeac09b, 0x38844020, 0x1a307205, 0x6207}}}, -{/*.x =*/{/*.val =*/{0x1b816b2f, 0x36e1b0d4, 0x228ee11f, 0x32de104, 0x2c5d5dee, 0x597f849, 0x11a676e8, 0x11b75965, 0x5a4d}}, - /*.y =*/{/*.val =*/{0x33e86c60, 0x3e5ebae1, 0x33ecceba, 0x39b317e, 0x3dfcd6b5, 0xf89fe3c, 0x260ab028, 0x8e5b283, 0x77c9}}}, -{/*.x =*/{/*.val =*/{0x31ce59e7, 0x110131b, 0x2d9919f3, 0x1db4e753, 0x324e6906, 0x359f05b6, 0x1f964c25, 0xbde79a8, 0x1bbc}}, - /*.y =*/{/*.val =*/{0x379aa297, 0x14c8648, 0x3839618d, 0x2265bd03, 0x1bc5a36c, 0x36c5beb4, 0x1f1a8781, 0x32d32375, 0x281f}}}, -{/*.x =*/{/*.val =*/{0x3bb80fa7, 0xd12172c, 0x30413886, 0x29f69aed, 0x20819f3a, 0x681af4c, 0xc2fbc0d, 0x38c7d8c2, 0x857}}, - /*.y =*/{/*.val =*/{0x9366b2d, 0x3660847c, 0xd7016ab, 0xb8dc10f, 0xb714717, 0x1f327477, 0x172092d, 0x24d08eb8, 0xf643}}}, -{/*.x =*/{/*.val =*/{0x3b6d6cd3, 0xe802af9, 0x38937883, 0x5984740, 0x25239734, 0x1a6e1c15, 0x3818481a, 0x19859fca, 0xea12}}, - /*.y =*/{/*.val =*/{0x34f450be, 0x2b98a497, 0x3be1a88a, 0x325d4b7a, 0x145e25b1, 0x3844afc4, 0x2e3fdaac, 0x38b941e3, 0x21a4}}}, -{/*.x =*/{/*.val =*/{0x1cff55c5, 0x1c48f509, 0x2275ec97, 0x13bf4a06, 0x2b4b635f, 0x4b079e0, 0x1442ca6c, 0x2b7f7ec9, 0xcf36}}, - /*.y =*/{/*.val =*/{0x21a0228e, 0x3289e214, 0xd2706a, 0x151fb097, 0x19f207a7, 0xbd62cef, 0x768649c, 0x4859ab8, 0xd16a}}}, -{/*.x =*/{/*.val =*/{0x125cb53b, 0x17a9e02b, 0x365eb3d0, 0x23f15763, 0x6272dab, 0x994c755, 0x25414494, 0x728acf7, 0xf474}}, - /*.y =*/{/*.val =*/{0x295a4b7e, 0x39769e65, 0x1f86e5c1, 0x5aa3ad, 0x2c8f9c0d, 0x3ec3609e, 0x1f2f01c8, 0x1bd03c89, 0xc48d}}}, -{/*.x =*/{/*.val =*/{0x3f2e070d, 0x160ff4e8, 0x12a6a98f, 0x2aadc731, 0x1047e229, 0x1cc70ee1, 0x34abff48, 0x297a410b, 0x4b72}}, - /*.y =*/{/*.val =*/{0x296dd780, 0x112ea0bb, 0x2948c3de, 0x2d197774, 0xf3c10b0, 0x1deecdb4, 0x2e1cf602, 0x753875a, 0x599e}}}, -{/*.x =*/{/*.val =*/{0x385912ec, 0xa1c0283, 0x6091134, 0x3e728139, 0x2f054327, 0x1265a52a, 0x35b786ab, 0x87538fe, 0xaa71}}, - /*.y =*/{/*.val =*/{0xae35978, 0x4532c99, 0x2056cbdb, 0x384d2a33, 0x22edebfe, 0x1499ae5a, 0x9509c50, 0x3c1df6b4, 0xc690}}}, -{/*.x =*/{/*.val =*/{0x3fd292dc, 0x2e01a893, 0x17714ce1, 0x1789a02c, 0x3d79d977, 0x201c34de, 0xf934ba4, 0x554cdc8, 0x4b99}}, - /*.y =*/{/*.val =*/{0x17095ca6, 0xce97ff9, 0x3376afd4, 0x20c8f116, 0x301f5793, 0x3029d2d7, 0x3a226df, 0x1d525844, 0xe327}}}, -{/*.x =*/{/*.val =*/{0x384da233, 0x2a560e3a, 0x1f362cd4, 0x13c36a04, 0x336ed9cf, 0x26f4ce3f, 0x25316a20, 0x32d365c7, 0x1eb7}}, - /*.y =*/{/*.val =*/{0x17c43f18, 0x2e3a954c, 0x1cf0ae9c, 0xdb26660, 0x1ed0aba3, 0x3cef342f, 0x84ff826, 0xca2b91f, 0xd984}}}, -{/*.x =*/{/*.val =*/{0x3bea0c68, 0x321042bc, 0x37b392b5, 0x10c048d9, 0x396faf09, 0x26f23a34, 0x2a3a2494, 0x258d3855, 0x3e41}}, - /*.y =*/{/*.val =*/{0x1a45edb6, 0x32edbfdc, 0x3cda1ab, 0x2846518c, 0x693062f, 0xf2ff8dc, 0x321f7f37, 0x31676492, 0x123}}}, -{/*.x =*/{/*.val =*/{0x17d4b84a, 0x2a605310, 0x1f433e69, 0x777d23c, 0x5070462, 0xa924b4a, 0x32fcb0c6, 0x26796371, 0xf13a}}, - /*.y =*/{/*.val =*/{0x13fd1c81, 0x16643f15, 0xf2d9628, 0x38df51c4, 0x3fe06eb6, 0x2e473478, 0x3e995aa6, 0x323343c2, 0x33c2}}}, -{/*.x =*/{/*.val =*/{0xe735a1e, 0x3c30ec51, 0x3e61fa05, 0xf8259a, 0x1202fc40, 0x23376b58, 0x356cb46b, 0x31f01e66, 0x678a}}, - /*.y =*/{/*.val =*/{0x12f7c055, 0xd8e97dc, 0x1371457a, 0x1fffeccf, 0x105e8e59, 0x3fcf55c, 0x1285b7a7, 0x138cf669, 0x851}}}, -{/*.x =*/{/*.val =*/{0x14c426d5, 0x30e07974, 0x22adf265, 0x29543e1e, 0x1fa93ab7, 0x1210c7e3, 0x2b66bd4c, 0x1d467823, 0x364c}}, - /*.y =*/{/*.val =*/{0x1a5876c0, 0x21b51ca9, 0x7db7191, 0x231357c5, 0x2d95be16, 0x2c62c634, 0x1fa52f1e, 0x2d65d0b2, 0xfaa8}}}, -{/*.x =*/{/*.val =*/{0x12fea1f9, 0x2c5f2ef1, 0x452b94, 0x3fc2d423, 0x106531c4, 0x3f76ad9c, 0x1f2e83bc, 0x22029574, 0xa6dc}}, - /*.y =*/{/*.val =*/{0x3bc345e9, 0x2c705391, 0x268f7e63, 0x1ee276df, 0x2cbc5005, 0x1a0e845a, 0x367c3038, 0x2a151f70, 0x7ef1}}}, -{/*.x =*/{/*.val =*/{0x1c7985c4, 0x2d84f9dc, 0x39e2b108, 0x12ff1256, 0x374c3413, 0xa10a00b, 0x19b7ce54, 0x2d72bded, 0x2320}}, - /*.y =*/{/*.val =*/{0xc2c6d44, 0x3fd3c77d, 0xd9eb8d4, 0x1bc40847, 0x1bca93d9, 0x1c86e07e, 0x3e94318c, 0x250f7222, 0xc79f}}}, -{/*.x =*/{/*.val =*/{0xa3a809c, 0x27f82c2f, 0x398346d7, 0x2d98bd75, 0x14a89eda, 0x33e5f909, 0x3df56bfb, 0x1fb20e4c, 0x125e}}, - /*.y =*/{/*.val =*/{0x149e70d9, 0x2a32402a, 0x7fca3dd, 0x138ecbbc, 0x321a371e, 0x1d1f2bd5, 0xcb38887, 0x3dbb7895, 0xe0d3}}}, -{/*.x =*/{/*.val =*/{0x208a7b1f, 0x3215fe35, 0x2a1ee514, 0x162bea6d, 0x3bc587f7, 0x141eb357, 0x37eb0079, 0x20efd263, 0x5ac}}, - /*.y =*/{/*.val =*/{0x165ccb98, 0x2198dd7e, 0x75d0f82, 0x3bc0ecc4, 0x2ac6f5b3, 0x33d08917, 0x2e6fb0fa, 0x271b3dd5, 0xe379}}}, -{/*.x =*/{/*.val =*/{0x27315443, 0x364e1ce0, 0x2e867299, 0x1e6ef552, 0x2142a13d, 0x32266082, 0x935ff42, 0x1b010198, 0xfc69}}, - /*.y =*/{/*.val =*/{0x17d28960, 0x1243582d, 0x9bd1b17, 0x1ffd2184, 0x1677b548, 0x387375a, 0x35892bbf, 0x9fafe0e, 0xe0ce}}}, -{/*.x =*/{/*.val =*/{0x3c6b5b56, 0x3cd857f5, 0x1888b607, 0x21722abb, 0x3200e541, 0x161fb4ef, 0x34338cdf, 0x2195c03b, 0xa0e8}}, - /*.y =*/{/*.val =*/{0x3a1d7518, 0x5af7944, 0x858a51a, 0x1ae1c75c, 0x13dead52, 0x29ae26e1, 0x1ad50b99, 0x11a0e7ea, 0xf5ba}}}, -{/*.x =*/{/*.val =*/{0x10cedd26, 0x35d977dd, 0x25715541, 0x322e677a, 0x239e2a3c, 0x360403e5, 0x1ebb2611, 0x120dca58, 0xaf88}}, - /*.y =*/{/*.val =*/{0x30e43f7f, 0x2db9eb4e, 0x3aa41708, 0x15279219, 0x2d2f9654, 0x32ee23af, 0x27030d28, 0x3efe5ec5, 0xdc57}}}, -{/*.x =*/{/*.val =*/{0x10b36a01, 0x1d9fddfc, 0x320812b5, 0x11e9ec5f, 0x2ec63cfc, 0x39ea5901, 0x3177a68a, 0x25375386, 0x853c}}, - /*.y =*/{/*.val =*/{0x27fe4ebe, 0x1f971fa3, 0x72f4fcc, 0x2fe60a00, 0x25123a28, 0x274080f7, 0x1b19530e, 0x33a53b26, 0xa328}}}, -{/*.x =*/{/*.val =*/{0x11da5e12, 0x7b838ce, 0x1cacb297, 0x31829005, 0x1ca2b6a9, 0xca7e4e8, 0x1e31bcda, 0xb8f10de, 0xf750}}, - /*.y =*/{/*.val =*/{0x385f4eb, 0x292e717a, 0x325cebc7, 0x21b4cbbd, 0x1672047b, 0x1c25170f, 0xfafd599, 0x3d7b759f, 0x3c57}}}, -{/*.x =*/{/*.val =*/{0x3e32478e, 0xdcc481c, 0x29ba7ed2, 0x2acc63ca, 0x332b2024, 0x31adfcfc, 0x213880fe, 0x4758041, 0xd420}}, - /*.y =*/{/*.val =*/{0x104e88d4, 0x33815a07, 0x1508cc31, 0x2c92cbcd, 0x3f847b6f, 0x357d7d12, 0x14e0c1b2, 0x353a68df, 0xbae5}}}, -{/*.x =*/{/*.val =*/{0x216ddcd3, 0x1a9c8dee, 0x1ea00355, 0x12c44008, 0x761af04, 0x16fadb2e, 0x299edf7b, 0x2b4dbd93, 0x1ae1}}, - /*.y =*/{/*.val =*/{0x2e7eb2b7, 0x33118674, 0xbb613c7, 0x185ab77f, 0x10448959, 0x1d3ddd48, 0x922059c, 0x15261e8, 0x7016}}}, -{/*.x =*/{/*.val =*/{0x19158bab, 0x264fc10e, 0x12d06caa, 0x4c9b0c6, 0x5a0674c, 0x1f3cf7cb, 0x39b3c419, 0x3d2ec203, 0xe2c6}}, - /*.y =*/{/*.val =*/{0x2d7a27f2, 0x214f3c9e, 0x49fd3f5, 0x6d622e4, 0x3ef5c641, 0xaecd847, 0xb1eabd1, 0x1e18b4f0, 0xfa92}}}, -{/*.x =*/{/*.val =*/{0x3a95a8db, 0x1761dccb, 0x39d36f61, 0xfb03111, 0x1b1723b8, 0x25991a64, 0x3dd0419e, 0x36918c0, 0xe3e9}}, - /*.y =*/{/*.val =*/{0x1b0d1cf9, 0x5b3dfc, 0x984d3d1, 0x2c7be5f3, 0x2e76afb, 0x3eaa431c, 0x178bb00, 0xef0015b, 0xfbe5}}}, -{/*.x =*/{/*.val =*/{0x141d0ce6, 0x13f0f72d, 0x3598d41f, 0x2264a8b3, 0x205fb274, 0x53338ce, 0x1a9412ee, 0x168a4dfc, 0x1429}}, - /*.y =*/{/*.val =*/{0x1738bb86, 0xaa06a2b, 0x35d241a5, 0x2255806, 0x83b131, 0xc711211, 0x150711b0, 0x14d8f7c4, 0xfea7}}}, -{/*.x =*/{/*.val =*/{0xb344f7f, 0x1c633e71, 0xce60c4c, 0x22e27f52, 0x26d410ee, 0x1f8cb2f4, 0x2e0ae0e9, 0x3212f65c, 0x354c}}, - /*.y =*/{/*.val =*/{0x25db82d6, 0x392c46ba, 0x202e0ec7, 0xdb18061, 0x3a88558e, 0x2d24fe6, 0x6b5d675, 0x2fca4a47, 0x9c04}}}, -{/*.x =*/{/*.val =*/{0x1983ce4e, 0x2ecf54dc, 0x1578253f, 0x40f6279, 0x23024a60, 0xeee0d6a, 0x35975f0e, 0x3da7674c, 0x8704}}, - /*.y =*/{/*.val =*/{0x16572c0a, 0x1c256368, 0x302df498, 0x16e840b8, 0x296bac34, 0x231d35d6, 0x2ec26a3, 0x14817389, 0x6b0b}}}, -{/*.x =*/{/*.val =*/{0x3a3979b5, 0xa8666c2, 0x27e829e2, 0xa23e379, 0x240e50ba, 0xdfc2c7b, 0x1e26327f, 0x1f1736b, 0xae22}}, - /*.y =*/{/*.val =*/{0x450fa6f, 0x23cf359a, 0x3d4f8896, 0x2a1edf4d, 0x2d7060fc, 0x3249148e, 0x39f71ad4, 0x3f944301, 0xea91}}}, -{/*.x =*/{/*.val =*/{0x2ce4dd6a, 0x16784787, 0x3221cef5, 0x392728, 0x164c460a, 0x3b28dfa3, 0x12b64bc9, 0x393dec9e, 0x49db}}, - /*.y =*/{/*.val =*/{0x2a9e3eae, 0x4edca90, 0x205bb69b, 0xe154bf2, 0x12255a1c, 0x3f8cf6da, 0x81c72c5, 0x1ca611c1, 0xb8b5}}}, -{/*.x =*/{/*.val =*/{0x34e5f03a, 0x3fa2d6f7, 0x21606d54, 0x1597fac7, 0x3dfe3596, 0x373eccf5, 0x1be33737, 0x13f740a2, 0x80c3}}, - /*.y =*/{/*.val =*/{0x3e3ca504, 0x5fd151b, 0x33245cb1, 0x2cabbc7, 0x1c9a03d3, 0x36d5c01f, 0x1ecd55e, 0x215a9e3, 0x247e}}}, -{/*.x =*/{/*.val =*/{0x29565331, 0x20617fbe, 0x1a915abf, 0x17a2498b, 0xcf1ce93, 0xe7bed50, 0x30c22611, 0x1493240d, 0x9d32}}, - /*.y =*/{/*.val =*/{0x26f06930, 0x758c2a, 0x236934f9, 0x32544bb0, 0x6d2ae5c, 0x3b130b2f, 0x22ebfd7f, 0x15cf49df, 0x3766}}}, -{/*.x =*/{/*.val =*/{0x354b8367, 0x25201cf5, 0x3d506bfe, 0x1d6ddf59, 0x36a5db7, 0x2a975161, 0x2526e40c, 0x252b911, 0x5e5a}}, - /*.y =*/{/*.val =*/{0x11ce85ca, 0x14ca6a76, 0x1e5ffa44, 0x1aaa7bcf, 0x2a4b7a79, 0x2407c55c, 0x15e05c2c, 0x3e32691e, 0xae8a}}}, -{/*.x =*/{/*.val =*/{0xcbcad59, 0x2c17a0d8, 0xe0aaa07, 0x21168169, 0x3902f17c, 0x5f21697, 0x36007aa, 0x1b0454ab, 0x2ed7}}, - /*.y =*/{/*.val =*/{0x4ea66fe, 0x12b1ea27, 0xa7f9411, 0x1cb1804c, 0x1767ed5f, 0x29babb20, 0x5f222cd, 0x135010ee, 0x639f}}}, -{/*.x =*/{/*.val =*/{0x24b84b48, 0xc3d15c7, 0x1e817ea8, 0x2b7d31e6, 0x17f7091, 0x43d5df5, 0x1a4f5419, 0x37c39f51, 0x5fb1}}, - /*.y =*/{/*.val =*/{0x37be8eb8, 0x1fb7a9a8, 0x33f21ad7, 0xa70e421, 0x2d258206, 0x3d191bf9, 0x4d49fbc, 0x3eef2f0f, 0x2152}}}, -{/*.x =*/{/*.val =*/{0x2aa2a748, 0x15d87054, 0x378c403d, 0x2c99f85, 0x2835d8c9, 0x337e7d1a, 0x141486c5, 0x27edac70, 0x135a}}, - /*.y =*/{/*.val =*/{0x38a6cf84, 0xc41675b, 0x3f91ab2d, 0x19b84fa2, 0x9453a65, 0x18b97f9c, 0x15938e7, 0x778b2a8, 0xa869}}}, -{/*.x =*/{/*.val =*/{0xfd69985, 0x2717764, 0x1df72aea, 0xc2732db, 0xccf149f, 0x3da437ef, 0x32f7e788, 0x1d9d73ad, 0xae9}}, - /*.y =*/{/*.val =*/{0x1409a003, 0x2723ad04, 0x2ee1aff8, 0x2e67505e, 0x1a54c5d0, 0x237fb814, 0x8d14e9b, 0x265cfdb9, 0x9121}}}, -{/*.x =*/{/*.val =*/{0x2078afb0, 0x39d6b9e5, 0x1261974, 0x3fc4b1b1, 0x2d170714, 0x3511a319, 0x163b5248, 0x1af35d98, 0x209d}}, - /*.y =*/{/*.val =*/{0x2740b310, 0x1746ddd6, 0x1f4e3e38, 0x3b6de4ce, 0x98a5b01, 0x196eaea6, 0x33280a09, 0x4d0a79e, 0x1a2f}}}, -{/*.x =*/{/*.val =*/{0x1f55a9bf, 0x2f2c0a63, 0x1ea5bf8e, 0x2c057bca, 0x17c578f6, 0xc1fd807, 0x23181810, 0x263ae71b, 0x7262}}, - /*.y =*/{/*.val =*/{0x3c3accae, 0x45be2c2, 0x673b4e, 0x1e5ef2f0, 0x1099e0be, 0xd68bbcf, 0x29bfda98, 0x22006a77, 0x38d4}}}, -{/*.x =*/{/*.val =*/{0x3dbb04fa, 0x5c195a8, 0x118911f9, 0x29c145ac, 0x26b5e114, 0x2e090979, 0x26ed4d7c, 0xb7eecd1, 0x7fe4}}, - /*.y =*/{/*.val =*/{0x21908c89, 0x359d2447, 0x2c1b9c55, 0x3a28a234, 0x334cf0aa, 0x1b22c1e5, 0x5f4330f, 0x1e82d3d7, 0x2eec}}}, -{/*.x =*/{/*.val =*/{0x2e4b3ba0, 0x2167d8d7, 0x18bf1f17, 0xaafbd7c, 0x3f245f5c, 0x385c3cc6, 0x3fb73bef, 0x4414887, 0x4108}}, - /*.y =*/{/*.val =*/{0x17525595, 0x21a58770, 0x1a064554, 0xd926159, 0x2b849813, 0x2996b875, 0x35668f2c, 0x3cda5dbf, 0xdc37}}}, -{/*.x =*/{/*.val =*/{0xe5485, 0x22799a8, 0x1da5df02, 0x4c1a2fd, 0x320f1245, 0x31c2189c, 0x2bdff8e2, 0x1db5e4e8, 0x1cd2}}, - /*.y =*/{/*.val =*/{0x85fbd7f, 0x2973c146, 0x209a4ecc, 0x34389c2c, 0x2e977f99, 0x2cd35154, 0x2af738d4, 0x2f7462cb, 0x6615}}}, -{/*.x =*/{/*.val =*/{0x290bc03e, 0x31d4f566, 0x1e015e33, 0x2c3ce4d4, 0x50f8084, 0x2a497dd1, 0x2072e9e5, 0x363b4b20, 0x2cee}}, - /*.y =*/{/*.val =*/{0x3ab82adc, 0x32dcae2d, 0xd53cd01, 0x77e73c8, 0x7daeb4a, 0x143adebf, 0x1de3ecd8, 0x1ae03a6e, 0xa427}}}, -{/*.x =*/{/*.val =*/{0x3009ee3e, 0x2e71352e, 0x729ead5, 0x9a8799e, 0x272de237, 0x273af1, 0x22ac92b7, 0x216c0cba, 0xb17a}}, - /*.y =*/{/*.val =*/{0x296b911d, 0x18f947b, 0x446fa38, 0x85b29f2, 0x26eda65, 0x63f703, 0x29a65f5c, 0x9a749ac, 0x966e}}}, -{/*.x =*/{/*.val =*/{0xe103dd6, 0x37dc51c8, 0x4859a, 0x1181301f, 0x12a17ac3, 0x84f3f16, 0x203f836a, 0x1ef55690, 0xbc47}}, - /*.y =*/{/*.val =*/{0x16f7c343, 0xe420b63, 0x23b44ac6, 0xa4d5cb1, 0x1ea6395d, 0x2b154b1b, 0xdd526cb, 0x7890a6a, 0xe31e}}}, -{/*.x =*/{/*.val =*/{0x36695f94, 0xb602c60, 0x1627fa59, 0x285a71a4, 0x39a9cf62, 0x32e1a0eb, 0x18f5fd0c, 0x17546d15, 0xb1d2}}, - /*.y =*/{/*.val =*/{0x1ee32736, 0x16dfae69, 0x3863edca, 0x3dbc636a, 0x2ba81760, 0x3a82b066, 0x290b1f7b, 0x369c80c3, 0x706d}}}, -{/*.x =*/{/*.val =*/{0x36f83231, 0x265c4062, 0x20425e34, 0x30c3639d, 0x33fdd0b7, 0x5609d96, 0x2ba26a8d, 0x23314d40, 0x850f}}, - /*.y =*/{/*.val =*/{0x1f2e8373, 0x280c6a75, 0x322d77f4, 0x216fe85d, 0x2cc7890a, 0x3dc21ae0, 0x39053d0b, 0x276f80a9, 0xbc4a}}}, -{/*.x =*/{/*.val =*/{0x39343959, 0xb882f6f, 0x2c9ce78a, 0x28673cbe, 0x1bc1f617, 0x2bfa4c24, 0x651465d, 0x6e01743, 0x2d38}}, - /*.y =*/{/*.val =*/{0x1442fb00, 0x1c432ba8, 0x31e45a43, 0x14b57589, 0x31025f43, 0x2bcbce90, 0x361bf59a, 0x3782534a, 0x5451}}}, -{/*.x =*/{/*.val =*/{0x152da17d, 0x18283e90, 0xd0646b1, 0x3704f6c2, 0x200bc811, 0x139ac17f, 0x18c5f089, 0x3b4783d4, 0x3bea}}, - /*.y =*/{/*.val =*/{0x2cc768d2, 0x39c12617, 0x1fec416c, 0x3379dee3, 0xe1b554, 0x12a2fafa, 0x37acdfef, 0x35fd56bf, 0xc3b0}}}, -{/*.x =*/{/*.val =*/{0x1063e1be, 0x6e6b413, 0x3e39a75c, 0x90a68bd, 0x3cf027a9, 0x185494f6, 0x2b14722, 0x10744758, 0x1316}}, - /*.y =*/{/*.val =*/{0x21fec890, 0x3747fcf8, 0x1745b77f, 0x3ebb03e, 0x3d2bebbd, 0xb8c3f36, 0x39f06a4, 0x36985e58, 0x4c3b}}}, -{/*.x =*/{/*.val =*/{0x3c46e079, 0x4a80d49, 0x1e9c78dd, 0x19a4c2e1, 0x2ba374ab, 0x3dd6b6c0, 0x3ac530fe, 0x30ab4ab3, 0xab86}}, - /*.y =*/{/*.val =*/{0x3636ffe1, 0x310a2f05, 0x50d7c0e, 0x1dca3a12, 0x3200c9ce, 0x311b535c, 0x329abcf5, 0x30a18067, 0x1209}}}, -{/*.x =*/{/*.val =*/{0x17d37248, 0x227c6075, 0x117ceae4, 0x20d6d947, 0x2b2787bc, 0x1bac891a, 0x36d5aa4d, 0x946f0fb, 0xadc4}}, - /*.y =*/{/*.val =*/{0x2adcbc1b, 0x1811f2b3, 0x50bebc8, 0x37156ec5, 0x16f70b9, 0x18f8d8a4, 0x1e7eb5d0, 0x2dd8b8f1, 0xb0f3}}}, -{/*.x =*/{/*.val =*/{0xeca5f51, 0x85ac826, 0xfc9aebf, 0x3a85c6e5, 0x5b5cfdd, 0x3b5acafc, 0x2e6962c6, 0x35453767, 0xdde9}}, - /*.y =*/{/*.val =*/{0x10c638f7, 0x2b5a69cf, 0x289571f9, 0x3fbafa37, 0x3f8f0950, 0x7cd2c29, 0x28111d89, 0x1a44cf38, 0xb84e}}}, -{/*.x =*/{/*.val =*/{0x209b0cca, 0x3331a956, 0xa4d6f01, 0x115d6249, 0x28da59a3, 0x1153da28, 0xf4c8d5c, 0x232c76ec, 0xd53}}, - /*.y =*/{/*.val =*/{0xc929e05, 0xc6c51f8, 0x9134c97, 0xd336676, 0x2ed7cf85, 0x2a357103, 0x2c110cb0, 0x1aeb1e8f, 0xc819}}}, -{/*.x =*/{/*.val =*/{0x2dd7e577, 0x2b8c0f3b, 0x136c4d56, 0x283c95a1, 0x2a2107d3, 0x1811c9c3, 0xf7b25ac, 0x3543e20a, 0xc352}}, - /*.y =*/{/*.val =*/{0x38d9b570, 0x3293fe23, 0x21217063, 0x2a2aecad, 0xe79fb00, 0x354c516f, 0x2b9b96ab, 0xa0e2e9d, 0xbe77}}}, -{/*.x =*/{/*.val =*/{0x23868246, 0x22fcdeb0, 0x6dd2ded, 0x27db62bd, 0x2248ba8, 0x17641f4b, 0x11d600b5, 0x1f82acce, 0xfb9d}}, - /*.y =*/{/*.val =*/{0x2969605a, 0x2760f82b, 0x2a2606d2, 0x34ab4c16, 0x1475f4a6, 0x2a2e05a8, 0x3680cff2, 0x26f807d2, 0xb038}}}, -{/*.x =*/{/*.val =*/{0x3712be3c, 0x1a8b8cb, 0x2146a66b, 0x257c63b6, 0x153472, 0x1c976eac, 0x1b378d3c, 0xd2764cc, 0x39d7}}, - /*.y =*/{/*.val =*/{0x1c6ff65c, 0x30c067d0, 0xa41644c, 0x17bde97b, 0x2812e8ef, 0x9d55319, 0x33bf7fb1, 0x26d3d5bb, 0x8f92}}}, -{/*.x =*/{/*.val =*/{0x37829372, 0x3b02a929, 0xba4553d, 0x26cc0322, 0x5796bc4, 0x189ab94e, 0x20d3b313, 0x273243cf, 0xb431}}, - /*.y =*/{/*.val =*/{0xadd5427, 0x1ca73300, 0x23e11bb7, 0x1ec48572, 0x21c5a270, 0x1ebf8270, 0x3502bffb, 0x3512669b, 0x4707}}}, -{/*.x =*/{/*.val =*/{0xdcbcb9e, 0x12fc449b, 0xd83c3df, 0x3e95a277, 0x143761d6, 0x30c911ff, 0x1337a9ec, 0x4b5c467, 0xcdcb}}, - /*.y =*/{/*.val =*/{0x961cfd1, 0x229616b, 0x18df340a, 0x266bc90d, 0x1e9949a1, 0x3efa825b, 0x1f11fbfe, 0x38b85eee, 0xe699}}}, -{/*.x =*/{/*.val =*/{0xe90bc26, 0x1e074991, 0x364d3aa0, 0x22880f84, 0xacd88a9, 0xf195b1d, 0x27275f3d, 0x385bd96d, 0x5e4d}}, - /*.y =*/{/*.val =*/{0x252f79e, 0x5f546a, 0x1127f9c7, 0x194f732b, 0x3ad55207, 0xebea5e0, 0x1432904e, 0x3cb90d4f, 0x5ac5}}}, -{/*.x =*/{/*.val =*/{0x754dd40, 0x18fa1c55, 0x3466cf8, 0x10898c7f, 0x32f6e9a2, 0x12107f35, 0xdfcf45b, 0x91c0cb0, 0x9729}}, - /*.y =*/{/*.val =*/{0x2aa36143, 0x212d24bc, 0x1acaf493, 0x36ba1495, 0x14df3690, 0x171d772f, 0x3ea1dcd1, 0x28910997, 0x91d1}}}, -{/*.x =*/{/*.val =*/{0xc7a89ee, 0x15f0d4cc, 0x2b6d4f80, 0x36f1671e, 0x18658a4b, 0x182e23f2, 0x179e1128, 0x29389a90, 0x71ef}}, - /*.y =*/{/*.val =*/{0x1366a2e, 0x3d224ca7, 0x25e9a0b4, 0x2abeae23, 0x3294a22a, 0x2cb0cac5, 0x224ae9ef, 0x2a07e2ed, 0x145f}}}, -{/*.x =*/{/*.val =*/{0xde0545f, 0x32c08d26, 0x106c74f5, 0x39897688, 0x3508ac80, 0x17a8012c, 0x7124a37, 0x16f31638, 0x5204}}, - /*.y =*/{/*.val =*/{0x106c3d91, 0x1ba8d301, 0x28fdaf23, 0xee743ca, 0xe312b79, 0x3b67083, 0x3123ad43, 0xc7f3af8, 0x1b3f}}}, -{/*.x =*/{/*.val =*/{0x3ddaa5d5, 0x1873f311, 0x14d4b7ab, 0x27a034e9, 0x16607331, 0x3bf9159a, 0x28c4e4e8, 0x2646e4be, 0x4e9}}, - /*.y =*/{/*.val =*/{0x2cba1c91, 0x35f800ff, 0x255f570d, 0x3827db86, 0x957303c, 0x1ab47630, 0x327f1d9e, 0x577778a, 0x62fc}}}, -{/*.x =*/{/*.val =*/{0x26a06f5e, 0x6902d65, 0x2a083702, 0x1064945b, 0x23b716a3, 0x2c350849, 0x253ac37, 0x93efa85, 0x383b}}, - /*.y =*/{/*.val =*/{0x13c6e772, 0x227d1e1b, 0x38c2b040, 0x3dab9d2e, 0x2a5a19e8, 0x3d59b553, 0x1ba2044c, 0x1c1ab13b, 0x54cf}}}, -{/*.x =*/{/*.val =*/{0x1bcf2dce, 0x4e6d023, 0x1dc6c02, 0x4528417, 0x3f998068, 0x2793264b, 0x6218bd4, 0xb50a4b9, 0x95e6}}, - /*.y =*/{/*.val =*/{0x18c86594, 0xaf77f7d, 0x304d20e6, 0x1ecc180d, 0x28d52e5e, 0x289b8ad0, 0x2875183, 0x20610a5b, 0x6b6}}}, -{/*.x =*/{/*.val =*/{0x17a6257f, 0x20149916, 0x27a6c40b, 0x1cf0ec68, 0x7e78918, 0x909d2ac, 0x14f25a64, 0xd72387d, 0x71e9}}, - /*.y =*/{/*.val =*/{0x11b1e582, 0x2c85d187, 0xf70f7a5, 0x948d503, 0x2e2a52ef, 0x361ae91e, 0x22513de, 0xf967d1f, 0x78d9}}}, +const curve_point secp256k1_cp[64][8] = { + { + /* 1*16^0*G: */ + {{{0x16f81798, 0x27ca056c, 0x1ce28d95, 0x26ff36cb, 0x070b0702, 0x018a573a, 0x0bbac55a, 0x199fbe77, 0x79be}}, + {{0x3b10d4b8, 0x311f423f, 0x28554199, 0x05ed1229, 0x1108a8fd, 0x13eff038, 0x3c4655da, 0x369dc9a8, 0x483a}}}, + /* 3*16^0*G: */ + {{{0x3ce036f9, 0x1807c44e, 0x36f99b08, 0x0c721160, 0x1d5229b5, 0x113e17e2, 0x0c310493, 0x22806496, 0xf930}}, + {{0x04b8e672, 0x32e7f5d6, 0x0c2231b6, 0x002a664d, 0x37f35665, 0x0cdf98a8, 0x1e8140fe, 0x1ec3d8cb, 0x388f}}}, + /* 5*16^0*G: */ + {{{0x3240efe4, 0x2ea355a6, 0x0619ab7c, 0x22e12f77, 0x1c5128e8, 0x129c9429, 0x3209355b, 0x37934681, 0x2f8b}}, + {{0x26ac62d6, 0x32a1f4ea, 0x30d6840d, 0x2209c6ea, 0x09c426f7, 0x2ea7769b, 0x1e3d6d4d, 0x08898db9, 0xd8ac}}}, + /* 7*16^0*G: */ + {{{0x0ac4f9bc, 0x24af77b7, 0x330e39ce, 0x1066df80, 0x2a7a0e3d, 0x23cd97cb, 0x1b4eaa39, 0x3c191b97, 0x5cbd}}, + {{0x087264da, 0x142098a0, 0x3fde7b5a, 0x04f42e04, 0x1a54dba8, 0x1e35b618, 0x15960a31, 0x32902e89, 0x6aeb}}}, + /* 9*16^0*G: */ + {{{0x3c27ccbe, 0x0d7c4437, 0x057e714c, 0x25e5a5d3, 0x159abde0, 0x345e2a7d, 0x3f65309a, 0x2138bc31, 0xacd4}}, + {{0x064f9c37, 0x173098ab, 0x35f8e0f0, 0x3622290d, 0x3b61e9ad, 0x2025c5d8, 0x3d9fd643, 0x22486c29, 0xcc33}}}, + /* 11*16^0*G: */ + {{{0x1da008cb, 0x2fb05e25, 0x1c17891b, 0x126602f9, 0x065aac56, 0x1091adc3, 0x1411e5ef, 0x39fe162a, 0x774a}}, + {{0x0953c61b, 0x0075d327, 0x3f9d6a83, 0x0b6c78b7, 0x37b36537, 0x0f755b5e, 0x35e19024, 0x280cbada, 0xd984}}}, + /* 13*16^0*G: */ + {{{0x19405aa8, 0x3bb77e3c, 0x10e58cdd, 0x1d7ef198, 0x348651b0, 0x0748170d, 0x1288bc7d, 0x1cf0b65d, 0xf287}}, + {{0x1b03ed81, 0x26d72d4b, 0x21fa91f2, 0x0681b694, 0x0daf473a, 0x084bad97, 0x00a89758, 0x240ba362, 0x0ab0}}}, + /* 15*16^0*G: */ + {{{0x227e080e, 0x12b6f3e3, 0x085f79e4, 0x39651bcf, 0x1ff41131, 0x196b8c25, 0x3ea965a4, 0x1353df50, 0xd792}}, + {{0x36a26b58, 0x1413727f, 0x096d3a5c, 0x102bcaf6, 0x0c6defea, 0x10bb08a3, 0x072a6838, 0x0a1caa1b, 0x581e}}} + }, + { + /* 1*16^1*G: */ + {{{0x2a6dec0a, 0x113ba278, 0x07a5ae9c, 0x28c4da6e, 0x023e97b2, 0x06aaf087, 0x29ec5301, 0x33a4ed67, 0xe60f}}, + {{0x29616821, 0x07ccb339, 0x0d23f0be, 0x25a24791, 0x39371012, 0x267cd3d5, 0x195929db, 0x141ce679, 0xf7e3}}}, + /* 3*16^1*G: */ + {{{0x1118e5c3, 0x2f61c2a8, 0x12bebc19, 0x15e6c9d1, 0x265b4bfc, 0x0595bbd3, 0x1307db44, 0x0cd76591, 0x6eca}}, + {{0x05a08668, 0x2628bde0, 0x3f8ec344, 0x125a8e8e, 0x3875a03a, 0x3d5e41d2, 0x20710592, 0x08ed5e9e, 0xd501}}}, + /* 5*16^1*G: */ + {{{0x0f87f62e, 0x3b34c785, 0x37161270, 0x39b98e18, 0x0659f010, 0x31d13b4d, 0x390ec0d7, 0x0eefbc6f, 0xe962}}, + {{0x244ee737, 0x0c04fabe, 0x168844e5, 0x1810f277, 0x1aa929fe, 0x3a54ea3b, 0x299e9e0f, 0x1d0ed2f0, 0x38a9}}}, + /* 7*16^1*G: */ + {{{0x2a8d733c, 0x2c2ab7e0, 0x2fca8f9e, 0x309d2fd8, 0x00d682ff, 0x128dbc82, 0x21dba088, 0x375cf945, 0xbc82}}, + {{0x347797f0, 0x39e18413, 0x33897301, 0x24e82eb9, 0x1f02dfae, 0x26d2fdc6, 0x31cac54a, 0x230e8112, 0xe5f2}}}, + /* 9*16^1*G: */ + {{{0x1fbc7671, 0x1fbf88c5, 0x2858e32d, 0x0fc6f214, 0x18f49074, 0x0a47385e, 0x17211d20, 0x049231d9, 0x8e3d}}, + {{0x18717dec, 0x3bc77190, 0x23e144a7, 0x0d4aeaa9, 0x13e90eb9, 0x1203864e, 0x3cb81f64, 0x123843b3, 0x099a}}}, + /* 11*16^1*G: */ + {{{0x3eb31db2, 0x0ca1d0ca, 0x0f506a0f, 0x32ba09e2, 0x08a2b68f, 0x2864fb42, 0x0a498896, 0x246a888d, 0x78a8}}, + {{0x39fa4343, 0x01a7588e, 0x000b82d3, 0x0de6f376, 0x302df654, 0x17c9549c, 0x035cbfcf, 0x28d6fad4, 0x6912}}}, + /* 13*16^1*G: */ + {{{0x0db0e595, 0x14d23dde, 0x3a082bb6, 0x058f2e7e, 0x2076eba7, 0x38dd9605, 0x31b17d7c, 0x1e061576, 0x7d86}}, + {{0x3c733de8, 0x265478ea, 0x225d5329, 0x0de11383, 0x0f883829, 0x18b8afb5, 0x2f8772e5, 0x26b7fb21, 0xe2b9}}}, + /* 15*16^1*G: */ + {{{0x16060dfc, 0x023fbe14, 0x05e6a2a0, 0x1517e108, 0x1ab08676, 0x252e7710, 0x02ac8484, 0x0c43c016, 0xddc5}}, + {{0x27820ca8, 0x2d7e2adb, 0x3d04730f, 0x36ebf1aa, 0x0f0e9041, 0x06adb732, 0x19692019, 0x0bcebc83, 0xba0d}}} + }, + { + /* 1*16^2*G: */ + {{{0x15f51508, 0x191b88ff, 0x1ac1ca10, 0x30e72af5, 0x2de238d8, 0x29b8f85c, 0x209d9ea2, 0x098c84b1, 0x8282}}, + {{0x36e26caf, 0x0c6dbabf, 0x37b17bed, 0x3584eb0b, 0x360ace62, 0x095ba0c2, 0x3dfe45e8, 0x2a026155, 0x11f8}}}, + /* 3*16^2*G: */ + {{{0x257e8dfa, 0x33f032e7, 0x3c7e184f, 0x20246468, 0x298ca009, 0x28c3e2b2, 0x19c4c0d9, 0x33cbfc1e, 0x8262}}, + {{0x3bac376a, 0x173fe363, 0x314c4783, 0x2dbb4cca, 0x334f3457, 0x3b88bb16, 0x09e4e66f, 0x25788244, 0x83fd}}}, + /* 5*16^2*G: */ + {{{0x026bdb6f, 0x014b922c, 0x3734b949, 0x2906f51e, 0x299c877c, 0x0416c933, 0x0ddd5168, 0x1722c768, 0x1982}}, + {{0x049cfc9b, 0x177dc213, 0x0f6d3a6b, 0x3a7bb323, 0x359f6ceb, 0x09873253, 0x0878f320, 0x0c43c353, 0x6294}}}, + /* 7*16^2*G: */ + {{{0x3d82824c, 0x03b42548, 0x21534e65, 0x29638d17, 0x02999edf, 0x17d5bb1b, 0x0191443c, 0x361b0458, 0x6f12}}, + {{0x06eb34d0, 0x15e70d20, 0x054bc5b8, 0x07249042, 0x22376939, 0x2653cff5, 0x3bfa0875, 0x3dfd12ac, 0x5c4f}}}, + /* 9*16^2*G: */ + {{{0x1b453629, 0x1db7700b, 0x359e6030, 0x33f73703, 0x3abef645, 0x189c5a88, 0x2aa5d142, 0x231be682, 0x203a}}, + {{0x3ff89f84, 0x25c71e14, 0x1285ed45, 0x1b7ac971, 0x01061268, 0x31db457d, 0x1d9b936c, 0x02d4f797, 0x3b0f}}}, + /* 11*16^2*G: */ + {{{0x246c7ecb, 0x20c4c377, 0x1bb4ce97, 0x0ebb4ff9, 0x26e1ec9d, 0x3bdccd21, 0x34181c81, 0x32bacf40, 0x6e2a}}, + {{0x2ebc8720, 0x1124807b, 0x367512c8, 0x31c1ae46, 0x3b643afa, 0x03136bc3, 0x3ee149d8, 0x2919e5fb, 0x9e61}}}, + /* 13*16^2*G: */ + {{{0x30a4147e, 0x2dc063cf, 0x375f201e, 0x11f762fd, 0x090a5827, 0x05c5fa29, 0x1156baf6, 0x0124ba7a, 0xd5a7}}, + {{0x33fb65ff, 0x392cf2e0, 0x167f57f8, 0x3136611e, 0x1e0532f4, 0x242641d9, 0x389c6fc4, 0x09bd76ea, 0x9db5}}}, + /* 15*16^2*G: */ + {{{0x18edcec6, 0x3b76d1af, 0x3634f454, 0x018730b4, 0x2cdac6a1, 0x0fbf18c0, 0x18ba8052, 0x0466aaf8, 0x38c5}}, + {{0x1933db08, 0x15b82fec, 0x35530a64, 0x285b208a, 0x1f282f28, 0x32cb689d, 0x1732a668, 0x3748a176, 0xe649}}} + }, + { + /* 1*16^3*G: */ + {{{0x11e5b739, 0x0ff396d5, 0x12222ed7, 0x2e4e0cff, 0x3c846de0, 0x26731b1b, 0x3865a72f, 0x0567dca2, 0x175e}}, + {{0x29fed695, 0x3be9bffb, 0x124345c6, 0x2d6556b7, 0x371f5eac, 0x3e5e947f, 0x079eba4e, 0x1b83678f, 0xd350}}}, + /* 3*16^3*G: */ + {{{0x05041216, 0x16dfe3c7, 0x02b836a6, 0x1ccd7da1, 0x2fed523f, 0x2d67bf70, 0x3acf4128, 0x0c5ec87d, 0xda75}}, + {{0x2e708572, 0x2bb4ca61, 0x37acedad, 0x2ab01eb9, 0x2d7fc6e9, 0x27886cd0, 0x2d5f0df1, 0x2811afdc, 0x73f8}}}, + /* 5*16^3*G: */ + {{{0x2465a930, 0x0050f9c7, 0x31352fdb, 0x21fc705a, 0x02eb1e25, 0x0f16312a, 0x349d7057, 0x316d23a5, 0x1c71}}, + {{0x034638b5, 0x361cfdb3, 0x3174d471, 0x0d178fed, 0x0bb68c79, 0x0fc7ca09, 0x1fa0c271, 0x30cd3a3d, 0x4a91}}}, + /* 7*16^3*G: */ + {{{0x3adb6ee7, 0x0c636b96, 0x344a077e, 0x143750c9, 0x1b4c9c78, 0x3a0dea42, 0x1a566936, 0x12bf07cc, 0xd84e}}, + {{0x142ebed2, 0x0b555b9b, 0x2a3e6498, 0x362b25d2, 0x25de4dfd, 0x0e3563d5, 0x379ce12a, 0x20269f1e, 0xe525}}}, + /* 9*16^3*G: */ + {{{0x249e6d10, 0x253a7b3e, 0x2ac99d23, 0x02b7fceb, 0x3f6ed3f6, 0x08ae4a17, 0x2814d41b, 0x1112f799, 0xf3d4}}, + {{0x1347da3f, 0x280e3301, 0x29d6c630, 0x06b69433, 0x0a4b5bfc, 0x2e56b066, 0x0163d4ba, 0x0937e9bc, 0x0a43}}}, + /* 11*16^3*G: */ + {{{0x29d33a07, 0x232cd01b, 0x239bcab4, 0x1cbb822a, 0x3df4044e, 0x21548336, 0x01d89f90, 0x194b2767, 0xae30}}, + {{0x20a0b2a6, 0x121c303d, 0x3d7e95c7, 0x270dfd77, 0x38d5cf1c, 0x339f4cf6, 0x3fe57efc, 0x3670e358, 0x6cb9}}}, + /* 13*16^3*G: */ + {{{0x0c28caca, 0x165952e4, 0x08281da7, 0x1a71eef3, 0x388c9a18, 0x05f9d60c, 0x1e1c815e, 0x06ca96f5, 0xd8dc}}, + {{0x23b3ec7a, 0x36d9dba8, 0x08128f6c, 0x0c574b3b, 0x247d947d, 0x36369080, 0x2c7d58c6, 0x02b649f3, 0x8cec}}}, + /* 15*16^3*G: */ + {{{0x3bc4416f, 0x2487ed98, 0x30b04028, 0x2bbf48fc, 0x32f31da7, 0x1096a340, 0x04eccd59, 0x38a4b17e, 0x2749}}, + {{0x3c6bbd8e, 0x3a62f78b, 0x2e961057, 0x27a7ed97, 0x0adb3ef5, 0x3652643f, 0x32bc4403, 0x0b538dd9, 0x50cc}}} + }, + { + /* 1*16^4*G: */ + {{{0x03ff4640, 0x09aeb63e, 0x1552ffe5, 0x11071f95, 0x262ee053, 0x3ab016d8, 0x00c9c99c, 0x243511ec, 0x363d}}, + {{0x3bee9de9, 0x0800f1fc, 0x0199ecb6, 0x2e6a2402, 0x33363145, 0x2d114e5f, 0x32221953, 0x1ceb7f1c, 0x04e2}}}, + /* 3*16^4*G: */ + {{{0x36e55dc8, 0x2e24485b, 0x2ca04394, 0x3e56adba, 0x1094426f, 0x12910301, 0x1ffb2ba8, 0x1011e431, 0x4431}}, + {{0x1be323b3, 0x076512bb, 0x2aa2e503, 0x1a8a6de7, 0x02fed7a6, 0x260dfd59, 0x366f8fe9, 0x3050b994, 0x96b0}}}, + /* 5*16^4*G: */ + {{{0x301b23a8, 0x3fa52175, 0x287ee0ad, 0x1edf51c2, 0x21089dab, 0x090f56e4, 0x0a87c126, 0x3fa3619b, 0x9e22}}, + {{0x0884edae, 0x1e904f14, 0x3511cecf, 0x3df2527e, 0x1c1533c0, 0x3cfc0826, 0x22d10177, 0x3c3a7284, 0xfd2f}}}, + /* 7*16^4*G: */ + {{{0x071a70e4, 0x35d022fc, 0x35cf475d, 0x17b947d7, 0x05306dcd, 0x35a7991c, 0x22a8d2ed, 0x3db540f3, 0x508d}}, + {{0x29950984, 0x3cb96fdc, 0x28aadfed, 0x300c8a3b, 0x3e49c54e, 0x0c12a9cc, 0x3c42d777, 0x10e6e4ce, 0x154c}}}, + /* 9*16^4*G: */ + {{{0x0e1abe11, 0x3abf69db, 0x1cb220f6, 0x2e487096, 0x0125b2da, 0x37d6064c, 0x09763338, 0x3fe11544, 0xe3db}}, + {{0x1fa8de63, 0x2d26b552, 0x06b5c414, 0x325f640f, 0x0a8ef3d3, 0x23e9d76e, 0x01421643, 0x3e42668d, 0x06f2}}}, + /* 11*16^4*G: */ + {{{0x03593449, 0x33c6c8d8, 0x02a46ffd, 0x06df04b9, 0x3d014af6, 0x36704e81, 0x2940d878, 0x381931f7, 0x19ac}}, + {{0x2df83631, 0x29052e4e, 0x084068a3, 0x1c42e7d0, 0x002c46ac, 0x2f5ce765, 0x0a333bfe, 0x2480d49a, 0xe379}}}, + /* 13*16^4*G: */ + {{{0x0cba6b63, 0x38fa624b, 0x10b3bb5e, 0x03f99d3f, 0x288e310a, 0x30cc8a3a, 0x07daa108, 0x033b083e, 0xd874}}, + {{0x2934c5f3, 0x3ba8db01, 0x381694ab, 0x0413d730, 0x3ac37d40, 0x29bba640, 0x132bf378, 0x304cf1ae, 0x6472}}}, + /* 15*16^4*G: */ + {{{0x1b3ec038, 0x0653fcb0, 0x20c6b276, 0x3f545ab9, 0x290a50d9, 0x20f9d8bc, 0x06083648, 0x0cce46d4, 0x58ac}}, + {{0x10246279, 0x1baa8fc4, 0x34fbbca1, 0x06410f02, 0x11fe9702, 0x1e4927a6, 0x092d9787, 0x35c1b557, 0x9163}}} + }, + { + /* 1*16^5*G: */ + {{{0x1ffdf80c, 0x27de6957, 0x15bcd1b6, 0x3929e068, 0x05638843, 0x0912d6dd, 0x3c2be8c6, 0x17c5977c, 0x8b4b}}, + {{0x1fd4fd36, 0x0fbfc319, 0x162ee56b, 0x38cd9518, 0x30da04f9, 0x2f5e04ea, 0x308b4b3f, 0x029bda34, 0x4aad}}}, + /* 3*16^5*G: */ + {{{0x355812dd, 0x028a960b, 0x12d30e2a, 0x1119c8d5, 0x18f78e3d, 0x2afb5b01, 0x3352f0b6, 0x2f5ea4bf, 0x7029}}, + {{0x1a2d2927, 0x087319ac, 0x3b2c73c7, 0x36ba1090, 0x0683ac47, 0x19512b8c, 0x0b3d27dd, 0x3eb6bf7a, 0xb0ee}}}, + /* 5*16^5*G: */ + {{{0x3d486ed1, 0x27395a0e, 0x1565b6a4, 0x116fae92, 0x0f756057, 0x35042763, 0x25c99009, 0x3b72bab9, 0x9ccf}}, + {{0x35e95d8d, 0x3db567b5, 0x1592aa24, 0x0859d65a, 0x0b341124, 0x08920480, 0x232cfb61, 0x135c4f5a, 0x7c2f}}}, + /* 7*16^5*G: */ + {{{0x1bd0eaca, 0x081ac69d, 0x22d4ab7a, 0x31d15dae, 0x24df19d0, 0x23f78cf2, 0x1414335a, 0x12e1d8d0, 0xcd9a}}, + {{0x2bff4acc, 0x39bebed6, 0x16f634f6, 0x09ece3bb, 0x3ea08b01, 0x1222ba4c, 0x0f23e815, 0x161e687a, 0xf045}}}, + /* 9*16^5*G: */ + {{{0x07bc57c6, 0x08254e8f, 0x2b276cbf, 0x00f5e88f, 0x16309449, 0x3cb4ba4f, 0x19bea884, 0x220be23b, 0xad09}}, + {{0x2e4a0ab8, 0x28cb03b6, 0x190e2d3c, 0x0c474dcd, 0x1abe5f7b, 0x061b1ca7, 0x3a52ba28, 0x302310be, 0x7243}}}, + /* 11*16^5*G: */ + {{{0x2ba56302, 0x2a0c31ca, 0x30f1862e, 0x01aa4deb, 0x3ad2e0f5, 0x368b4aa7, 0x0a41f1ea, 0x0a42bacf, 0xd9d1}}, + {{0x08291c29, 0x2ab76bea, 0x3a74f2ae, 0x0e6bb367, 0x2386e417, 0x1c5719c9, 0x13eed029, 0x0c44fb0b, 0x7eb5}}}, + /* 13*16^5*G: */ + {{{0x34d1243a, 0x2b34dc13, 0x354a5fdb, 0x2c49808f, 0x3f558402, 0x3486b018, 0x16cef91c, 0x1e7794e7, 0xbc50}}, + {{0x055db68a, 0x172545a2, 0x1f47169f, 0x1fb93d6c, 0x3fc8d75f, 0x31cae537, 0x05cbb8ee, 0x0a8ece9c, 0x6506}}}, + /* 15*16^5*G: */ + {{{0x374a3f9f, 0x2349139a, 0x00981690, 0x21e99977, 0x32625ac2, 0x37aab9f6, 0x3c7e8913, 0x29df9417, 0x4d31}}, + {{0x301e0ba7, 0x3f2c0904, 0x2e00a754, 0x3dbed46d, 0x002753cb, 0x063ce31e, 0x0575b06b, 0x07b25826, 0x2224}}} + }, + { + /* 1*16^6*G: */ + {{{0x1232fcda, 0x2d845649, 0x2c0e77bc, 0x0036ffe9, 0x1548c7b7, 0x1dc7002f, 0x3996d6bf, 0x2ea9b976, 0x723c}}, + {{0x1eb39f5f, 0x07701a76, 0x37949480, 0x1828194d, 0x024d6e26, 0x044dd222, 0x0c498a92, 0x19ed5657, 0x96e8}}}, + /* 3*16^6*G: */ + {{{0x00633cb1, 0x159f827a, 0x1d021132, 0x168892da, 0x181fcb57, 0x189cc848, 0x2cad400c, 0x273cc5ea, 0x6dde}}, + {{0x27ce6b34, 0x1f7526a9, 0x3859ef35, 0x2c9ff6b3, 0x3a66a880, 0x27be1a86, 0x3e41d5c9, 0x3ef9e9c1, 0x9188}}}, + /* 5*16^6*G: */ + {{{0x2933f3c5, 0x06694634, 0x1f125224, 0x1683dc45, 0x07b85008, 0x12edfe39, 0x1cde813c, 0x29cb356d, 0x486f}}, + {{0x0afb0f53, 0x2b529c6b, 0x30f23b79, 0x366de0f3, 0x08f19f62, 0x3122ebb3, 0x3dd43e48, 0x08c67d5a, 0x62e1}}}, + /* 7*16^6*G: */ + {{{0x1e99f728, 0x2f565089, 0x2f12204e, 0x1cdd7ef9, 0x2a530367, 0x13fc9edd, 0x0af4fb66, 0x1a5d2a25, 0x2479}}, + {{0x2baaebff, 0x1e80145b, 0x175a2d83, 0x36fcf025, 0x0d664a5a, 0x0ba1f9f6, 0x33001ec5, 0x23511a23, 0xe3d7}}}, + /* 9*16^6*G: */ + {{{0x2fb0079a, 0x27831b50, 0x3926049c, 0x1be7bdc8, 0x33832491, 0x2967b9da, 0x15ff0631, 0x32f6a8f5, 0x2f39}}, + {{0x2c5690ba, 0x388a5cc0, 0x02a0230f, 0x3ecfef22, 0x0da58b9b, 0x24db409e, 0x239834da, 0x36f784e1, 0xabea}}}, + /* 11*16^6*G: */ + {{{0x24f7ab73, 0x24cc02cb, 0x14443a77, 0x38f53aa7, 0x34aed262, 0x0e7a1b14, 0x161ba56a, 0x075b0c9f, 0xe5a3}}, + {{0x30561f42, 0x244e8ff1, 0x00cba213, 0x2311126a, 0x0ece5dbf, 0x062a5de9, 0x29d7a0c1, 0x230f6347, 0x3778}}}, + /* 13*16^6*G: */ + {{{0x014dcd86, 0x23e4a68f, 0x2bf71b58, 0x31750825, 0x11dcf11f, 0x03766081, 0x13447df5, 0x27528345, 0xcc38}}, + {{0x08f0a873, 0x23adb767, 0x27e78746, 0x315f863f, 0x2910ca05, 0x1a2f6efa, 0x2bbed9b5, 0x13f5983d, 0x93ae}}}, + /* 15*16^6*G: */ + {{{0x38819311, 0x13e71bad, 0x08771472, 0x0f87b884, 0x35ed1f0b, 0x0285f833, 0x1e902375, 0x2472275c, 0x7f92}}, + {{0x2c2eb125, 0x2a7e6d5e, 0x086a174a, 0x02aa9027, 0x2415b612, 0x037a3114, 0x03ef0f5d, 0x034418fb, 0x9da0}}} + }, + { + /* 1*16^7*G: */ + {{{0x0e7dd7fa, 0x294cfb28, 0x3a919839, 0x11e5848d, 0x02d3b509, 0x3fbb204b, 0x2bf98ba5, 0x293524ef, 0xeebf}}, + {{0x21de8999, 0x37f53f6b, 0x311f712d, 0x393370e9, 0x38089d9a, 0x39fb6bc5, 0x2f0f269e, 0x2328e5c3, 0x5d9a}}}, + /* 3*16^7*G: */ + {{{0x3b7ceceb, 0x0fd9e3fe, 0x097faf0f, 0x2967e4e2, 0x2e681473, 0x3ee049bd, 0x2d45036f, 0x2188109d, 0x437a}}, + {{0x16c181e1, 0x0d8ef30d, 0x08f97827, 0x0883f3f7, 0x1297ff87, 0x23fada67, 0x2c32f69b, 0x1ae84fba, 0x0b91}}}, + /* 5*16^7*G: */ + {{{0x097f96f2, 0x1635ca78, 0x2c8735cd, 0x208d4a74, 0x3cc27335, 0x2df8ee68, 0x089bc83c, 0x27c4f8a9, 0xa9ef}}, + {{0x16c04be4, 0x00f556c1, 0x29b4702c, 0x13e26bd6, 0x3b613db7, 0x1bb8583a, 0x19d7cd95, 0x33396515, 0xe814}}}, + /* 7*16^7*G: */ + {{{0x350cf77e, 0x302ad684, 0x0a8ab0db, 0x36fd5d15, 0x2a064207, 0x209f5a7e, 0x135be553, 0x01507b87, 0x66d8}}, + {{0x20eaa3a6, 0x297e5ebe, 0x3b1b76d2, 0x112d0ead, 0x1613f694, 0x0750814d, 0x3fb42c3f, 0x37f9ccbf, 0x51cf}}}, + /* 9*16^7*G: */ + {{{0x07213a5a, 0x0d5218a2, 0x05fa62b9, 0x1cc8129e, 0x0cc3c80b, 0x14228719, 0x03fa2bf3, 0x01784d94, 0x62ac}}, + {{0x346a9e45, 0x04348703, 0x17994efc, 0x16424060, 0x292579e5, 0x179e781e, 0x1a6e4d39, 0x2f7ce834, 0x236f}}}, + /* 11*16^7*G: */ + {{{0x27bad12b, 0x0c3f5261, 0x2f66e1ec, 0x357a803a, 0x2f2db385, 0x184ebd71, 0x08f5b5bf, 0x31125c91, 0xca13}}, + {{0x1723b0f2, 0x25a67d1a, 0x1a575668, 0x1c2adc44, 0x2da3d663, 0x17e993aa, 0x287c8ac1, 0x0260d870, 0x83aa}}}, + /* 13*16^7*G: */ + {{{0x1c80414e, 0x36bb97e5, 0x166cf7fd, 0x3be2a18b, 0x209e4914, 0x04713d11, 0x12ae85ac, 0x2c4069c1, 0x1cec}}, + {{0x12169a3b, 0x32ba524b, 0x07231d0d, 0x1d55f951, 0x2dad1690, 0x2a8ca0d7, 0x17cfb4e5, 0x1819a582, 0xf343}}}, + /* 15*16^7*G: */ + {{{0x0ed810a9, 0x13d6f231, 0x0700155c, 0x22274fcf, 0x1f23924f, 0x036bd7c7, 0x38f9cc95, 0x241d4135, 0x2a69}}, + {{0x3a9b4728, 0x3e1ace23, 0x2c145c7c, 0x1f51fa5f, 0x3b04fc66, 0x3161a553, 0x1ffdac3e, 0x00e6db0f, 0x54f9}}} + }, + { + /* 1*16^8*G: */ + {{{0x39a48db0, 0x3f5e0d6c, 0x33c03bfe, 0x048568a6, 0x3bde459f, 0x0742826d, 0x27167279, 0x11369a5b, 0x100f}}, + {{0x2bc65a09, 0x3ef57358, 0x35195ac0, 0x3fd2863f, 0x090666b7, 0x23ccc030, 0x00b772ec, 0x384c64a8, 0xcdd9}}}, + /* 3*16^8*G: */ + {{{0x15bc15b4, 0x32e684d2, 0x25a2ee69, 0x1d40a391, 0x17ca8d92, 0x163ba73b, 0x2adc9ed8, 0x038b947b, 0x10e9}}, + {{0x18aa258d, 0x13af9825, 0x2bb6a883, 0x296258c0, 0x2d1f754c, 0x1ea3185a, 0x1e0424d5, 0x0dc0e035, 0xc68a}}}, + /* 5*16^8*G: */ + {{{0x3fe75269, 0x374ff0c0, 0x13d33182, 0x1de8f301, 0x0b7dcda3, 0x16e42dc5, 0x01638457, 0x0bd0b695, 0xf742}}, + {{0x17e49bd5, 0x22603a1c, 0x0a398e01, 0x2ce88dfd, 0x3635977f, 0x339f72e7, 0x3093fd18, 0x0bc68cc4, 0x406c}}}, + /* 7*16^8*G: */ + {{{0x35a7175f, 0x14ed9a5b, 0x31cf42a6, 0x2e39dc74, 0x15debbed, 0x1e69560b, 0x03cff728, 0x2b4105f5, 0x2d8c}}, + {{0x3b9d592a, 0x3cdeee46, 0x0b5e5e0c, 0x211aff67, 0x2c9d377a, 0x08cbe984, 0x0a94a7bb, 0x0ee0cc63, 0xc73f}}}, + /* 9*16^8*G: */ + {{{0x14b51045, 0x0d326f0e, 0x31c25b3e, 0x31b225bc, 0x28cf73bb, 0x1cf53ac7, 0x26ea58ae, 0x3f476e62, 0x1ecb}}, + {{0x02c70026, 0x0e99c404, 0x036422d5, 0x240191ad, 0x1a9b38b1, 0x342ec612, 0x1c3a6447, 0x388c22e6, 0x1cf6}}}, + /* 11*16^8*G: */ + {{{0x29358533, 0x1eb35d9b, 0x0fb4b9df, 0x2a4cfe75, 0x132a8c10, 0x25568a47, 0x3752883e, 0x25317f95, 0x9a08}}, + {{0x0360ba08, 0x2cf87177, 0x380ddadf, 0x29b96f6e, 0x0fc32165, 0x05f57e55, 0x38fc31f9, 0x20f10806, 0xa798}}}, + /* 13*16^8*G: */ + {{{0x198ef7f6, 0x25101758, 0x2078f9f6, 0x08fcfdde, 0x38aea659, 0x272149ce, 0x3d2e35bd, 0x361276d3, 0x664d}}, + {{0x1d1eac94, 0x1d25bfcd, 0x38e6ecee, 0x0f4eacc6, 0x0458cffc, 0x12339774, 0x27932a14, 0x0805c5fc, 0xad51}}}, + /* 15*16^8*G: */ + {{{0x03c934b3, 0x03029adf, 0x30ae2c4e, 0x0c7d6016, 0x11a7022b, 0x07659a60, 0x0b863823, 0x0ea4ddf4, 0x8211}}, + {{0x042c6a0f, 0x1f9798ab, 0x24468037, 0x07df09a6, 0x20c628aa, 0x19b3cad6, 0x23666084, 0x2e36b26b, 0x8da1}}} + }, + { + /* 1*16^9*G: */ + {{{0x2534fd2d, 0x322b379b, 0x0f3b3852, 0x1fe35119, 0x04c017a7, 0x2489e928, 0x3ed1b1dc, 0x06f898b1, 0xe103}}, + {{0x1456a00d, 0x113c63ca, 0x21ced79a, 0x24b75067, 0x17535af2, 0x1a905d96, 0x0405e6bb, 0x1864a250, 0x9d70}}}, + /* 3*16^9*G: */ + {{{0x2f028d83, 0x1e588ebb, 0x27439615, 0x25649b6e, 0x1e69db61, 0x2af96857, 0x385ec6a5, 0x3df138f1, 0xa7eb}}, + {{0x19d0bed1, 0x1900e4ae, 0x30539199, 0x28e249d2, 0x04804b47, 0x271cddc1, 0x362d5cfd, 0x054beff8, 0x6205}}}, + /* 5*16^9*G: */ + {{{0x27dd5cfa, 0x2b839008, 0x309d4b5b, 0x227144df, 0x2346336a, 0x31a94d09, 0x24f4c1cd, 0x282372c0, 0x5b5c}}, + {{0x1e48e98c, 0x19929be6, 0x33269d3e, 0x3419f32b, 0x069094bf, 0x07c33aa2, 0x15825e99, 0x2dbdc2a8, 0x3ecc}}}, + /* 7*16^9*G: */ + {{{0x23531f82, 0x2e54a38c, 0x10c2c9f2, 0x144c9aec, 0x022c29ff, 0x3cf9d227, 0x14bb5cce, 0x09ab3044, 0x046f}}, + {{0x0bceda07, 0x1417f22c, 0x2b55c7fa, 0x09651736, 0x032579d0, 0x0dc2b0bf, 0x382eace2, 0x12cc58d6, 0x6b80}}}, + /* 9*16^9*G: */ + {{{0x10432711, 0x02c550dc, 0x1916b906, 0x0502cbf7, 0x19645acf, 0x25bc3c22, 0x0efb535f, 0x09b64c78, 0xc119}}, + {{0x2fe2610c, 0x1249878b, 0x0f34055e, 0x2ae48b28, 0x0cc6cf83, 0x252fc61b, 0x1b689184, 0x3e331f49, 0x8be1}}}, + /* 11*16^9*G: */ + {{{0x21257963, 0x05e61d3e, 0x34aa861c, 0x006354b0, 0x0979c45b, 0x2ed52d4e, 0x08f2e6cd, 0x11ba7ada, 0x6908}}, + {{0x066f9835, 0x295d9665, 0x1c92b253, 0x2f0f2a08, 0x2fbb7f6c, 0x05c093e4, 0x3ebc5b40, 0x17f2dfcf, 0xe248}}}, + /* 13*16^9*G: */ + {{{0x1ee23ace, 0x3444e52f, 0x14dd2fd2, 0x321f196d, 0x232915de, 0x1d54b7d2, 0x220babba, 0x3dfee324, 0xfb3d}}, + {{0x1722e8de, 0x0277bd32, 0x2d27f5ee, 0x1c9c50bf, 0x3ab58a9e, 0x09455036, 0x33c5652a, 0x0a6f0471, 0x510e}}}, + /* 15*16^9*G: */ + {{{0x10272351, 0x181f3fbd, 0x19ff1098, 0x1cd2cf7e, 0x31cd4170, 0x228facea, 0x0518b3eb, 0x17b093d7, 0x6dd8}}, + {{0x3fc7664b, 0x2c1fe8ad, 0x3e0817c9, 0x1f1bfdf0, 0x1c41b787, 0x101fe6bd, 0x3427e09d, 0x19fd0487, 0x16ea}}} + }, + { + /* 1*16^10*G: */ + {{{0x1094696d, 0x3579a236, 0x01d6af52, 0x3e2c99a9, 0x3bd7ec5c, 0x0a0e7c50, 0x15b530ac, 0x1b2b91b5, 0xfeea}}, + {{0x18090088, 0x05577afc, 0x041442d3, 0x072255f3, 0x3ecd5c98, 0x39384afc, 0x0e1bab06, 0x1adb25f7, 0xe57c}}}, + /* 3*16^10*G: */ + {{{0x08dfd587, 0x1e4d86ed, 0x1b026560, 0x312e8e32, 0x35a12d5e, 0x19eaa8b3, 0x0508b348, 0x2d06eb3d, 0x5084}}, + {{0x11470e89, 0x39e7a5fe, 0x091f5606, 0x2dbd581a, 0x2927475d, 0x2a9b2154, 0x00d31619, 0x18c68766, 0x34a9}}}, + /* 5*16^10*G: */ + {{{0x3ab34cc6, 0x0208c985, 0x0f30a12d, 0x030a5d9f, 0x0d7128c8, 0x2cfc7f46, 0x2d5ea53f, 0x300f8190, 0x4f14}}, + {{0x187e681f, 0x17b094be, 0x281dd022, 0x378f33a3, 0x262540b9, 0x0e9c3d0e, 0x0e894c65, 0x342a32a9, 0x7b53}}}, + /* 7*16^10*G: */ + {{{0x1241d90d, 0x109dc404, 0x32444f83, 0x073c5076, 0x1dd363e8, 0x10d8257b, 0x39ed1d41, 0x2e1f9271, 0xa74d}}, + {{0x3f7adad4, 0x0c9462e0, 0x0a0a313f, 0x3b9424d1, 0x0171c8a9, 0x37422962, 0x3eef327f, 0x24736bc8, 0xf786}}}, + /* 9*16^10*G: */ + {{{0x31c1ae1f, 0x17b32888, 0x2cd40b2a, 0x1b9631a2, 0x23565845, 0x373513ae, 0x2a2cf9ac, 0x3e95d12e, 0x6901}}, + {{0x122838b0, 0x3e0cc197, 0x1c77a930, 0x27cee979, 0x1c900dd7, 0x2d4e030a, 0x3c212461, 0x1722089c, 0x35de}}}, + /* 11*16^10*G: */ + {{{0x327a4bdb, 0x2c0c4206, 0x1494cac4, 0x1a9b410d, 0x3ba35d04, 0x12d90fc6, 0x38127a24, 0x360b4750, 0x8d3c}}, + {{0x269a8a2c, 0x0f4d31f3, 0x30ad296c, 0x38e01f4d, 0x36236ed4, 0x3efe7401, 0x241f470c, 0x0958603b, 0x9bd4}}}, + /* 13*16^10*G: */ + {{{0x34ec1d2d, 0x10334f1a, 0x27d8f454, 0x0267d71b, 0x3b691fd9, 0x2759ca59, 0x24739afe, 0x20d8f581, 0xeaf9}}, + {{0x0c838452, 0x33f9d581, 0x3e84b53f, 0x3d4b5515, 0x3199aaa9, 0x08a2839a, 0x38d22775, 0x060e9ff9, 0xe518}}}, + /* 15*16^10*G: */ + {{{0x045ae767, 0x32cd6fdc, 0x289771cb, 0x1cea72e7, 0x06e5d8c2, 0x103814b0, 0x1b63466f, 0x2f458ebb, 0xfb95}}, + {{0x3bbf0e11, 0x214fa82b, 0x259f1341, 0x05bd1c62, 0x02275bb8, 0x013674da, 0x0ddbc520, 0x0536046a, 0x664c}}} + }, + { + /* 1*16^11*G: */ + {{{0x01ec6cb1, 0x0fea5e2f, 0x08583de3, 0x3b595f60, 0x3fca3cfe, 0x1ef92f9b, 0x09cdcb36, 0x2a476441, 0xda67}}, + {{0x3a68be1d, 0x3a7aa389, 0x0f740a17, 0x31eb7142, 0x1780e5de, 0x118fdfb2, 0x242bc41f, 0x2a8d5205, 0x9bac}}}, + /* 3*16^11*G: */ + {{{0x15bc8a44, 0x3bf74194, 0x3e151a19, 0x10405df2, 0x1a5fc768, 0x159692e9, 0x0eda3d38, 0x20160f3f, 0x4d01}}, + {{0x1adbc09e, 0x3c7e5324, 0x182da362, 0x250811a1, 0x16381396, 0x26ea001f, 0x0f5d367e, 0x31b0632d, 0x3a33}}}, + /* 5*16^11*G: */ + {{{0x25daeb00, 0x306ad4a1, 0x2645f76b, 0x08fac933, 0x36e9d159, 0x32da89ce, 0x0f957082, 0x0541f7d7, 0x2f66}}, + {{0x033992c0, 0x089d9e26, 0x15d308c1, 0x337b89c6, 0x00add06e, 0x254dea08, 0x2b33f6ef, 0x0484dbd4, 0xfd5c}}}, + /* 7*16^11*G: */ + {{{0x116aa6d9, 0x20aa4282, 0x3702dcf1, 0x18b22d91, 0x035a3836, 0x3c5d3686, 0x247d2254, 0x045f417f, 0xf594}}, + {{0x3f2e50cf, 0x1f41a5ba, 0x26b5b86c, 0x249de20f, 0x14bceb7a, 0x176f6ac2, 0x31b12cf6, 0x18695ba5, 0xcaa7}}}, + /* 9*16^11*G: */ + {{{0x3ac6f4c0, 0x2ab80e55, 0x04bdc4cc, 0x13a37a33, 0x16711dda, 0x070e2f9a, 0x19cdec4e, 0x135fc7d3, 0x0f2d}}, + {{0x32339b58, 0x1f9eeeb5, 0x0242656e, 0x1a8429e4, 0x01e71e8f, 0x2c9ff7ce, 0x3de4d17f, 0x27e15fa4, 0x3ec8}}}, + /* 11*16^11*G: */ + {{{0x1f428cb2, 0x215414ff, 0x2a22b55d, 0x0e08bf59, 0x18d0f123, 0x1e860565, 0x14bbd1eb, 0x33b0b8a8, 0x1d5d}}, + {{0x095b189b, 0x397b4402, 0x36044a51, 0x0fa44be1, 0x2f0b88bd, 0x1e1e0921, 0x2c8c50d0, 0x1020ec50, 0x6e5c}}}, + /* 13*16^11*G: */ + {{{0x28381273, 0x2c3aa23e, 0x293dae5f, 0x10dda581, 0x0126ced8, 0x3aa6cb31, 0x167439fd, 0x28bf4c02, 0x89d9}}, + {{0x1309773d, 0x00facfbb, 0x1127324a, 0x1875a02b, 0x0f62f58f, 0x2abc81db, 0x26f50377, 0x096d1475, 0xdfca}}}, + /* 15*16^11*G: */ + {{{0x35c71d91, 0x330cacb2, 0x2894fd21, 0x25178b8a, 0x1afece23, 0x28704c45, 0x10ae1c52, 0x06e1e0e9, 0x8319}}, + {{0x22148a61, 0x02e7b023, 0x10445ee7, 0x2847d45d, 0x3cae8a17, 0x1b784f45, 0x01b709e0, 0x1fc55ce0, 0xe0ac}}} + }, + { + /* 1*16^12*G: */ + {{{0x1a37b7c0, 0x1d517330, 0x311069f5, 0x02343dee, 0x322151ec, 0x00024d7b, 0x34cdda6e, 0x13ea82cc, 0x5390}}, + {{0x022771c8, 0x372c25ac, 0x14434699, 0x26666078, 0x0d3c1c13, 0x27b32b08, 0x0106d88c, 0x21f42f20, 0x5bc0}}}, + /* 3*16^12*G: */ + {{{0x08a2050e, 0x06b10bf9, 0x15f8a677, 0x0bbd55d8, 0x079b8974, 0x1da731b9, 0x0731896b, 0x093f492f, 0x6737}}, + {{0x061d3d70, 0x24326924, 0x3349cc2b, 0x1aeb3f50, 0x086b6dbe, 0x120b026a, 0x24a20203, 0x2095e25a, 0xe4cf}}}, + /* 5*16^12*G: */ + {{{0x02de63bf, 0x2fdb920e, 0x3261c66c, 0x0ebd4ca1, 0x2166a8e0, 0x26298c7d, 0x34c309e5, 0x3be91cb7, 0x4366}}, + {{0x217924cd, 0x0b1a9023, 0x2aa6d6b0, 0x0ec31496, 0x0268eaf3, 0x094df84c, 0x2d7ce2ee, 0x36426fb8, 0x2e7d}}}, + /* 7*16^12*G: */ + {{{0x06f96190, 0x04149ffc, 0x3c9525ef, 0x3c0b7a41, 0x3aa75fd1, 0x3955a599, 0x1ab1f97b, 0x14d89e64, 0x7bd7}}, + {{0x2bda00f6, 0x0f45c812, 0x20ea695a, 0x03f31707, 0x3827d6ce, 0x3591d250, 0x26309d5e, 0x3cacf6ee, 0x8336}}}, + /* 9*16^12*G: */ + {{{0x16ad41ed, 0x0ec54c55, 0x0f035243, 0x022b0d7d, 0x18dc9203, 0x0d067a24, 0x2d5c1afa, 0x249ef76a, 0x4f7e}}, + {{0x3e642d57, 0x3d0d5e19, 0x2af775bd, 0x1cc51c53, 0x28f6a62e, 0x26037d4e, 0x08b10552, 0x1d1455aa, 0xdfe7}}}, + /* 11*16^12*G: */ + {{{0x27748690, 0x3e981449, 0x0630b01c, 0x15e41376, 0x133d007d, 0x114ac7b7, 0x11ccc94b, 0x32e19f4a, 0x2355}}, + {{0x0c89582b, 0x1f11d4c5, 0x11c93914, 0x0a1a1633, 0x2a7c5858, 0x2e17b056, 0x1e1f8f55, 0x3c62969c, 0x21c2}}}, + /* 13*16^12*G: */ + {{{0x0ade7f16, 0x36ba8858, 0x0be028c6, 0x272eba4f, 0x275d24ae, 0x164aadb0, 0x1a56c013, 0x2096e6cf, 0x0b66}}, + {{0x08c56217, 0x251109a1, 0x3e7cd2bd, 0x090f037c, 0x17a97fb7, 0x29daea2d, 0x09b3fef3, 0x282e0638, 0xa1fb}}}, + /* 15*16^12*G: */ + {{{0x19060d5b, 0x241ac08a, 0x03a3a7c2, 0x1184ec47, 0x3951cb90, 0x026cbf67, 0x1022cb61, 0x010f3c2f, 0xf602}}, + {{0x1af88f13, 0x1bdbd42c, 0x3dd1a3f7, 0x2a95b4ad, 0x0f7bea37, 0x2a3d92b1, 0x0cf19881, 0x2dc1b07c, 0xf036}}} + }, + { + /* 1*16^13*G: */ + {{{0x3ad86047, 0x3fe567d0, 0x29b8bcae, 0x2d4e810e, 0x0a906779, 0x3329dd93, 0x183a7719, 0x3342f4d6, 0x8e7b}}, + {{0x0460372a, 0x284011fa, 0x3fd68b3e, 0x3a238b91, 0x29514579, 0x0c410832, 0x1a4b3940, 0x1dc2ca8f, 0x10b7}}}, + /* 3*16^13*G: */ + {{{0x041ead4b, 0x3fa21e68, 0x11b03c1f, 0x1d7b7eda, 0x3e76be3a, 0x11cd3beb, 0x3337ec71, 0x03032323, 0xbfc9}}, + {{0x06fedaed, 0x114b1bc2, 0x2e0ae3e7, 0x11a3bfcc, 0x042d36fb, 0x29c63754, 0x0ded24db, 0x206c7827, 0x7a94}}}, + /* 5*16^13*G: */ + {{{0x35bb3b3e, 0x1b9ef41d, 0x39f73cb2, 0x1d4d85fb, 0x2d3f5b50, 0x1664fa30, 0x3aaa4dca, 0x3c472f8f, 0x732d}}, + {{0x17366693, 0x315df87b, 0x0c58436c, 0x276b5b59, 0x253916e6, 0x38956100, 0x39977cb7, 0x240fb7a3, 0x7f41}}}, + /* 7*16^13*G: */ + {{{0x088dc3b9, 0x17d6cf06, 0x1774c99c, 0x299a493a, 0x17ef6019, 0x2a210332, 0x147b428d, 0x252e580e, 0x4ce0}}, + {{0x25c0de52, 0x3053dedb, 0x1ea06502, 0x0816c832, 0x36aca216, 0x2d360329, 0x29b3ed57, 0x03eeafc6, 0x0539}}}, + /* 9*16^13*G: */ + {{{0x0aaafe5a, 0x30dd782c, 0x109aedd4, 0x151c2ce9, 0x023fd0e2, 0x229aa56c, 0x267de96d, 0x23addbf1, 0x9a96}}, + {{0x0ed975c0, 0x39aff509, 0x1e70cc0c, 0x2d620299, 0x061d0ee7, 0x319b40f6, 0x3ba2954f, 0x3ec1e9b4, 0xabf6}}}, + /* 11*16^13*G: */ + {{{0x334c6397, 0x1d472fe7, 0x074cd093, 0x374f6d40, 0x36b22107, 0x2bbe0094, 0x161954f0, 0x3efb405c, 0xd3c6}}, + {{0x28cb3f9c, 0x07f23415, 0x05e0e00b, 0x031dc224, 0x2ab6468a, 0x20e5364b, 0x22af1945, 0x34b15797, 0x4a0d}}}, + /* 13*16^13*G: */ + {{{0x0ac3137e, 0x26e0964c, 0x1af64461, 0x2496d8a9, 0x2b3953fe, 0x3c1a9daa, 0x243b8e02, 0x38e604a4, 0x4cbd}}, + {{0x2ec02fe6, 0x0023c573, 0x08ead60c, 0x24e9eb96, 0x14c370d1, 0x24a84d2e, 0x36159500, 0x151823c4, 0x6ce5}}}, + /* 15*16^13*G: */ + {{{0x20fbf84b, 0x1e88c1b3, 0x03f0b8a4, 0x3123f2ef, 0x14cebb03, 0x3671cc30, 0x16247b8b, 0x0ccf20ac, 0x4b9d}}, + {{0x236c3c48, 0x0e7b92d2, 0x2f5b5e62, 0x19b550f8, 0x39b7eb67, 0x04f66099, 0x0c152553, 0x31fef893, 0xfd7f}}} + }, + { + /* 1*16^14*G: */ + {{{0x19c43862, 0x2a107856, 0x397e6690, 0x29fd3c60, 0x381bde71, 0x02061a26, 0x1ff21e6d, 0x3b4d3073, 0x385e}}, + {{0x142e5453, 0x01163f95, 0x086dc8cc, 0x0c13bb08, 0x2bf4576b, 0x077867a7, 0x223f5670, 0x3af0fa3a, 0x283b}}}, + /* 3*16^14*G: */ + {{{0x36e2d9b3, 0x12f4c1aa, 0x338d6351, 0x36e4a0c6, 0x0f845641, 0x0ba984e7, 0x305e75e1, 0x053ce5f1, 0x19a3}}, + {{0x0baaaf33, 0x154bb897, 0x004be56d, 0x00874749, 0x3528b3a5, 0x2597e21f, 0x328dd234, 0x363d76b1, 0x6cac}}}, + /* 5*16^14*G: */ + {{{0x12f00480, 0x36161fac, 0x100dcee7, 0x0d620128, 0x36721920, 0x32618d93, 0x0daa355d, 0x3b52e56a, 0x5840}}, + {{0x3e22cf9e, 0x164b578a, 0x2ae38721, 0x1d489514, 0x1dd8daba, 0x1a37aa85, 0x3f141079, 0x369ac882, 0x670c}}}, + /* 7*16^14*G: */ + {{{0x23f54c42, 0x12137ba0, 0x29a3dc8e, 0x37068f09, 0x0e532545, 0x16307d3b, 0x118fb1dc, 0x00694d1a, 0x9f57}}, + {{0x2feb6a21, 0x18387124, 0x219e5278, 0x3b9e12ac, 0x29bfdd89, 0x256dad5c, 0x19e57bfb, 0x23ee2007, 0xce7b}}}, + /* 9*16^14*G: */ + {{{0x1522461a, 0x3a504cca, 0x3c718327, 0x2cc28996, 0x3ef9a0bc, 0x2e1c0419, 0x28cfc01b, 0x045a48d6, 0x27f6}}, + {{0x07301a2d, 0x2a932be7, 0x28639446, 0x2606c836, 0x028ee8e4, 0x2315849d, 0x26ad2ea4, 0x3c6a6402, 0xe512}}}, + /* 11*16^14*G: */ + {{{0x114f36b9, 0x338b26cb, 0x3b9f390c, 0x2632aed8, 0x34a98125, 0x2fcbd0d7, 0x2f941261, 0x1e615b3b, 0x6407}}, + {{0x24b4b50a, 0x252c7ba7, 0x19ceeb28, 0x36821c12, 0x1a7b6c8c, 0x035d7f61, 0x16efaef9, 0x24a3d139, 0xda61}}}, + /* 13*16^14*G: */ + {{{0x14d6b76f, 0x3bd8f7e6, 0x0c815dbc, 0x396a7eed, 0x1dfeae7f, 0x3dc22f02, 0x1669f452, 0x1438c721, 0xa237}}, + {{0x0dcca8da, 0x0764b332, 0x1b848d14, 0x1c1f047f, 0x011113e7, 0x0be8f935, 0x3de6dac3, 0x26c529b9, 0xf733}}}, + /* 15*16^14*G: */ + {{{0x3ceee475, 0x0bba7193, 0x0ed782b1, 0x1ab20a10, 0x0aff41ab, 0x0f0087cf, 0x2378d5ed, 0x2b01e8fc, 0xbbf1}}, + {{0x07fe5067, 0x1188a802, 0x38b41d68, 0x3ae76250, 0x315fe324, 0x20f320da, 0x060e6108, 0x2e37bab5, 0xb4bf}}} + }, + { + /* 1*16^15*G: */ + {{{0x03fac3a7, 0x181bb61b, 0x147fbc9c, 0x377e1296, 0x3dfa180f, 0x31ce9104, 0x0f191637, 0x366e00fb, 0x06f9}}, + {{0x3a842160, 0x21a24180, 0x0281002d, 0x29374bd7, 0x05c4d47e, 0x238a8c39, 0x059ba69b, 0x31a3980c, 0x7c80}}}, + /* 3*16^15*G: */ + {{{0x121ce204, 0x13b5d7a3, 0x26763d52, 0x29c96390, 0x26f72fb2, 0x1d361672, 0x3c64fb83, 0x107458ac, 0x43ca}}, + {{0x134a8f6b, 0x1494113a, 0x2a4a468e, 0x2db1eccf, 0x1ba31f9a, 0x143e4863, 0x023fa1c6, 0x16a0b8dc, 0xdcea}}}, + /* 5*16^15*G: */ + {{{0x2be6efda, 0x13f3a4b3, 0x07280596, 0x0b53fcfe, 0x1a506d92, 0x1bdc8de1, 0x12bf5b66, 0x01bbc8a2, 0x9c3e}}, + {{0x27aefc7d, 0x3c503cca, 0x336fdf7d, 0x0ef21a1e, 0x226fd5d4, 0x02cb5133, 0x2923d8af, 0x027979d8, 0xa7b7}}}, + /* 7*16^15*G: */ + {{{0x06c88be2, 0x2449ead7, 0x06ee5e27, 0x0b1e0834, 0x30775bea, 0x1c9d6760, 0x20f033bb, 0x22a8c4f8, 0x5d6f}}, + {{0x0d7ad75d, 0x24b954fc, 0x2bf92c28, 0x2adbe3a9, 0x08bc20ed, 0x2abcceac, 0x2d4e8c71, 0x2c636355, 0xadc4}}}, + /* 9*16^15*G: */ + {{{0x12d1b844, 0x0a24d46e, 0x173e484f, 0x2700e0b0, 0x388bc5c6, 0x2c570f04, 0x20d5fc86, 0x0d70c129, 0xf57d}}, + {{0x21266837, 0x192eaef5, 0x0915c6a4, 0x01a5c80c, 0x24634c70, 0x134fd6a7, 0x2f4d9790, 0x0f67aa63, 0x707f}}}, + /* 11*16^15*G: */ + {{{0x3cc7cb09, 0x0d3401fc, 0x1d1b4352, 0x31fada28, 0x1871463b, 0x1b87fb8f, 0x194a5f59, 0x181e8e99, 0x13e7}}, + {{0x08079160, 0x2f9d6a28, 0x2b576411, 0x3ab8aed9, 0x34299d65, 0x17f7616c, 0x3b8b1e32, 0x32237a3e, 0x284d}}}, + /* 13*16^15*G: */ + {{{0x18cdee05, 0x01833849, 0x32ec3b90, 0x1d87ec85, 0x06901da8, 0x00942c6c, 0x182e6240, 0x28c895a0, 0x29be}}, + {{0x262651c8, 0x39280d66, 0x0c698e39, 0x3f0c6db2, 0x305ec7f9, 0x026cfee1, 0x29a0ea90, 0x36689a43, 0x7c40}}}, + /* 15*16^15*G: */ + {{{0x12f18ada, 0x06db1d58, 0x3dbdbcc1, 0x182f64ee, 0x3d4a59d4, 0x0dbebfcc, 0x288e7d9c, 0x1e1b48e0, 0xf521}}, + {{0x23953516, 0x375a2bf4, 0x05bf0981, 0x17bd28db, 0x11d1d6aa, 0x09840af3, 0x0db57ecc, 0x1befd80e, 0xe068}}} + }, + { + /* 1*16^16*G: */ + {{{0x02d0e6bd, 0x0edf839d, 0x30f5e531, 0x1d3458f6, 0x0d6ecbf7, 0x0851f041, 0x04e2582a, 0x3500490f, 0x3322}}, + {{0x2c28b2a0, 0x13ce8ba5, 0x2873af62, 0x017d8fa8, 0x1af9b728, 0x0066f137, 0x24ef5bfb, 0x01e5fa59, 0x56e7}}}, + /* 3*16^16*G: */ + {{{0x059ab499, 0x2f674fc8, 0x273c330a, 0x04ca671b, 0x3f01bc0b, 0x065acf19, 0x005ba5d2, 0x2bfcc057, 0x78ba}}, + {{0x3ee097fd, 0x20748c63, 0x11251996, 0x18cbbba3, 0x02082e91, 0x2a1383b6, 0x2c0afafc, 0x3736f6c1, 0xad4b}}}, + /* 5*16^16*G: */ + {{{0x3d06ace6, 0x124f85b3, 0x03a20ca4, 0x1c26cdbe, 0x29ab1a23, 0x2e126124, 0x2e3d4c20, 0x3c846852, 0x6f70}}, + {{0x3602d5de, 0x122fb4d2, 0x25ac5ee0, 0x0ca559af, 0x399f5075, 0x1763cd1e, 0x27b736f9, 0x228c2500, 0x791e}}}, + /* 7*16^16*G: */ + {{{0x20ee1b40, 0x323b8fb9, 0x1e96247d, 0x3b5216dc, 0x03ccd48c, 0x2527c644, 0x2a415f80, 0x276ca75a, 0xe159}}, + {{0x178f93a6, 0x0758997b, 0x032999de, 0x0d8e9d2f, 0x2fc7cfa6, 0x3e252aa8, 0x1d4a0efa, 0x1888caa0, 0x7933}}}, + /* 9*16^16*G: */ + {{{0x09c00c3e, 0x2077e8a1, 0x11208e2f, 0x03a3c0f2, 0x051859f0, 0x158b4cf5, 0x06956436, 0x0125c110, 0xbb0b}}, + {{0x11955a35, 0x266a60b4, 0x05dc90a7, 0x19c113a4, 0x31b052fe, 0x34be85ea, 0x39f63655, 0x391614eb, 0x4067}}}, + /* 11*16^16*G: */ + {{{0x05dd32e6, 0x039d6e70, 0x13e5ee7e, 0x18ed546d, 0x1a5fbfc6, 0x1276f81d, 0x1789e9b6, 0x10555065, 0xdc5a}}, + {{0x354a99b9, 0x039f6de9, 0x2e49bcf8, 0x3cbba41d, 0x3f59442f, 0x3a978806, 0x367a76dc, 0x2a298fe7, 0x4af3}}}, + /* 13*16^16*G: */ + {{{0x0544e7cb, 0x3b516eb1, 0x12960359, 0x0190896d, 0x014e99a1, 0x0d5295c4, 0x33b9dbe3, 0x065c0e61, 0x156e}}, + {{0x2d250a37, 0x354e4b02, 0x2b439cd6, 0x25b56357, 0x034be894, 0x255ca98e, 0x1907da93, 0x2367e3cc, 0x6bc0}}}, + /* 15*16^16*G: */ + {{{0x059853ca, 0x2fef0a73, 0x319bf54d, 0x3a589ae7, 0x27161348, 0x29da88a3, 0x043826bc, 0x2f33b2da, 0x4269}}, + {{0x35b8d367, 0x2a563bd4, 0x1e5a8a3d, 0x0e50297e, 0x31a409fd, 0x2132a710, 0x016b723c, 0x0706a0b0, 0xed2b}}} + }, + { + /* 1*16^17*G: */ + {{{0x0134ab83, 0x0875d34a, 0x36433977, 0x06cfe6bd, 0x26586874, 0x05dc3625, 0x0b7da2bd, 0x0b1f4b78, 0x8567}}, + {{0x390313a6, 0x238c253d, 0x1298f44c, 0x1fc5ff31, 0x22c2e5e7, 0x10126fe9, 0x3b2eb637, 0x06e6d6d0, 0x7c48}}}, + /* 3*16^17*G: */ + {{{0x03ba9000, 0x37c1c8ea, 0x025e8b6f, 0x21cbe71a, 0x00143dc4, 0x21d81d61, 0x1d8c1684, 0x1d3e7ffc, 0xac38}}, + {{0x2f10cf0a, 0x368f1f65, 0x366e9fa4, 0x178d435f, 0x117f9308, 0x0b77a250, 0x1c069b86, 0x3a48c228, 0xaa65}}}, + /* 5*16^17*G: */ + {{{0x2d06dbd4, 0x2981bd9b, 0x0a20d081, 0x038fe15e, 0x23e729ec, 0x0501d7a6, 0x070139ad, 0x1739ea9a, 0x570d}}, + {{0x3d1ed495, 0x2996fb3a, 0x2460bed5, 0x20e8db71, 0x101bbbb6, 0x19b99c47, 0x202f605b, 0x14d25083, 0xa6ae}}}, + /* 7*16^17*G: */ + {{{0x092d230e, 0x0d307e48, 0x29339284, 0x3b8ca834, 0x366ef5da, 0x308a7b80, 0x28bb6f87, 0x3e1c0a09, 0x75b5}}, + {{0x151570b8, 0x0df2f7ef, 0x111f8fb0, 0x19e92c01, 0x1dfa8e02, 0x1e1d1553, 0x3852363d, 0x338878e9, 0x527c}}}, + /* 9*16^17*G: */ + {{{0x034fcc0e, 0x1edafdab, 0x3e3884c4, 0x1fc4290a, 0x1259c892, 0x16e0389f, 0x1dec2b0a, 0x23beb87b, 0x44fc}}, + {{0x319c420a, 0x33fc0c79, 0x0d0489d9, 0x03a5292f, 0x33d3d772, 0x099f9e20, 0x31367e49, 0x37a52ea6, 0xd2c7}}}, + /* 11*16^17*G: */ + {{{0x0bb69991, 0x169207f2, 0x3307175d, 0x3ecfe8b0, 0x02f535ff, 0x28598838, 0x27bc6866, 0x2e91eeb3, 0xdea2}}, + {{0x316fe2df, 0x019d0aa7, 0x21ed9bc7, 0x27736cd8, 0x37b9e722, 0x32ffb213, 0x028e4ac5, 0x2ff5b643, 0xae28}}}, + /* 13*16^17*G: */ + {{{0x114fc9cc, 0x30903409, 0x1a461658, 0x3402af0a, 0x38a83626, 0x073db312, 0x168d6efc, 0x3f2629b8, 0x3968}}, + {{0x1fad37dd, 0x064e5225, 0x388f3340, 0x05195dbf, 0x2d32c91a, 0x1e60b46a, 0x35928123, 0x2ef436d2, 0x789c}}}, + /* 15*16^17*G: */ + {{{0x2e0c85f1, 0x2bb08646, 0x03a3a250, 0x294b94d8, 0x3945d5a6, 0x0977c255, 0x06a2926b, 0x2441a638, 0x6896}}, + {{0x2dc1de21, 0x31d208cc, 0x0d503922, 0x10306768, 0x05d72d1f, 0x0c170761, 0x0979256f, 0x0fed2ce3, 0xaefd}}} + }, + { + /* 1*16^18*G: */ + {{{0x20c82a0a, 0x3f6566bd, 0x3668832f, 0x2489b183, 0x1413b10f, 0x1b27c646, 0x188a46b0, 0x2fe026c6, 0x0948}}, + {{0x18c8e589, 0x132dfe23, 0x17cd2bed, 0x137fc232, 0x03418c6d, 0x2dd31747, 0x36646dc6, 0x18a15b72, 0x53a5}}}, + /* 3*16^18*G: */ + {{{0x38c8ac7f, 0x0a0bf97e, 0x1e2aa527, 0x0490bb99, 0x16f84964, 0x0ce5b481, 0x22bbcb5c, 0x2cbef8e0, 0x9945}}, + {{0x29aea3b0, 0x1b650e85, 0x2dacdfa9, 0x0bde88fb, 0x28eff528, 0x36d13fec, 0x3282d607, 0x3b6092c3, 0x3eef}}}, + /* 5*16^18*G: */ + {{{0x169e353a, 0x3475e78e, 0x2bbe1f6e, 0x28110214, 0x07d5fe10, 0x3e0889c4, 0x070e6235, 0x131ac816, 0x2a31}}, + {{0x25746067, 0x09649b87, 0x32658bfc, 0x22952ab6, 0x2a1ba013, 0x18f91dae, 0x227ac1a4, 0x2b02fcd6, 0x15a4}}}, + /* 7*16^18*G: */ + {{{0x29b84966, 0x278bd27b, 0x17f3ff98, 0x13d041b7, 0x2b6c911b, 0x2dbebce9, 0x3fc2d498, 0x29402dc0, 0x5959}}, + {{0x07473a6a, 0x02998c86, 0x0fe24264, 0x00373023, 0x082a7091, 0x0c4a0837, 0x0a897f94, 0x399d07d7, 0x0370}}}, + /* 9*16^18*G: */ + {{{0x2bc6b173, 0x2c326e48, 0x2ed3feb3, 0x36188f1f, 0x1b5f9d7d, 0x183118c1, 0x22fe8e11, 0x0c4e4dc8, 0x9eeb}}, + {{0x1723a71d, 0x14e58836, 0x0e70c4b9, 0x29c6afb4, 0x3a1ae30e, 0x2aaff6ee, 0x2d58d952, 0x3c780443, 0xe121}}}, + /* 11*16^18*G: */ + {{{0x3ec805f3, 0x1dc910fd, 0x1d995915, 0x3903dd42, 0x2e97887d, 0x2ec8e201, 0x318f516e, 0x13f931fd, 0x39cc}}, + {{0x3a3c48d3, 0x06468304, 0x3c912e4d, 0x2e55cdcf, 0x02de7dbb, 0x399a4f3d, 0x2f8f3151, 0x11cb1691, 0xecb1}}}, + /* 13*16^18*G: */ + {{{0x0e22580e, 0x0f58bed7, 0x2d6f8879, 0x04ca25b4, 0x1bd4d2c7, 0x0bff7993, 0x0dc69689, 0x201d19bb, 0xf94c}}, + {{0x3127db82, 0x07948fd9, 0x2371d4e8, 0x21fb114c, 0x1a81f698, 0x12ffdaad, 0x1225a919, 0x1ff719e1, 0x5e9c}}}, + /* 15*16^18*G: */ + {{{0x10c4f21f, 0x2f902eb4, 0x103da7a6, 0x092a5653, 0x1999d250, 0x0081a36c, 0x1d162fcc, 0x2e1b1ab5, 0x8ccc}}, + {{0x329dfea0, 0x1fc49ba9, 0x264be28f, 0x24b72b20, 0x0758a54b, 0x2fbd5272, 0x11c43699, 0x2596189d, 0x57f8}}} + }, + { + /* 1*16^19*G: */ + {{{0x338fd8e8, 0x33b36067, 0x069752ac, 0x2c39137f, 0x2873a8f1, 0x19f383c0, 0x001c34f0, 0x339fd186, 0x6260}}, + {{0x32b4ae17, 0x06a13a56, 0x051c198c, 0x34a488e0, 0x2a1ef7ec, 0x024125dd, 0x1b571a7f, 0x2a0adbe9, 0xbc2d}}}, + /* 3*16^19*G: */ + {{{0x01136602, 0x2c2e9195, 0x19e3a5bb, 0x311bd203, 0x333b3d38, 0x1624dfc8, 0x2dfc33d0, 0x09ca0120, 0x87d1}}, + {{0x18af6aac, 0x3da0f107, 0x3d3bf7c4, 0x2a211d1b, 0x27745387, 0x289db3fd, 0x203de926, 0x0921c296, 0x71ce}}}, + /* 5*16^19*G: */ + {{{0x08c5a916, 0x2c8175cd, 0x35610f25, 0x17110354, 0x354aa13f, 0x2b318f6a, 0x1e9746b0, 0x1f4ff898, 0xfd5d}}, + {{0x3adb8bda, 0x052cdec1, 0x1cf6faab, 0x35ce052f, 0x07b52fe5, 0x10f299e7, 0x15b07d2b, 0x0fb43bad, 0x0dd8}}}, + /* 7*16^19*G: */ + {{{0x35f7529c, 0x17664258, 0x1bd51dd4, 0x1d96e62d, 0x34438138, 0x114f0cb4, 0x026122ba, 0x35042607, 0xde0d}}, + {{0x24cd88fe, 0x0f08300b, 0x09b77406, 0x224931a2, 0x3a357017, 0x042608b5, 0x2145f9b2, 0x1ba74428, 0xd70a}}}, + /* 9*16^19*G: */ + {{{0x38f76d11, 0x320bd234, 0x38515573, 0x044003ef, 0x0292a215, 0x16fbf0e7, 0x0f44e69c, 0x0822b693, 0xb26c}}, + {{0x23b7356b, 0x307002c7, 0x182624bd, 0x000c1967, 0x0d643305, 0x13a1f643, 0x1d33cf0c, 0x3e208252, 0x1f1c}}}, + /* 11*16^19*G: */ + {{{0x269e22db, 0x2538ec19, 0x39c8933f, 0x264ffd67, 0x0c294eac, 0x0ef4a406, 0x3f523a7e, 0x052e3f1f, 0xfceb}}, + {{0x1c2260a1, 0x3d5cb6c9, 0x24ebe4cb, 0x15439e4e, 0x1f0924ad, 0x22969d49, 0x2b8d1fcd, 0x1ace9035, 0x64aa}}}, + /* 13*16^19*G: */ + {{{0x238a2755, 0x3c2105e6, 0x149c5506, 0x1c869c59, 0x107faa53, 0x05d5dd2d, 0x15cac55c, 0x26988f33, 0x4e90}}, + {{0x23cca3de, 0x3de927d8, 0x229800ca, 0x3354e534, 0x3559dbb6, 0x091b7541, 0x235aecef, 0x36a1e333, 0xae56}}}, + /* 15*16^19*G: */ + {{{0x183ba64d, 0x20962566, 0x0c595a3a, 0x3983dde2, 0x0e40e2bd, 0x028517ae, 0x04c03bfb, 0x115708b8, 0xc367}}, + {{0x2a2181fd, 0x053323e5, 0x1778f146, 0x189aab28, 0x1964c742, 0x3839ba13, 0x36033080, 0x02b41a72, 0x3a52}}} + }, + { + /* 1*16^20*G: */ + {{{0x2037fa2d, 0x254f3234, 0x1bfdc432, 0x0fb23d5d, 0x3f410304, 0x0d21052e, 0x1d8d43d8, 0x1f782bf0, 0xe503}}, + {{0x1d755bda, 0x03977210, 0x0481f10e, 0x17d6c0fb, 0x190bddbd, 0x263427ee, 0x0d3b5f9f, 0x14d2eaa5, 0x4571}}}, + /* 3*16^20*G: */ + {{{0x177e7775, 0x222a29b8, 0x0ed95f63, 0x385564e2, 0x1291aeb5, 0x150eeb3d, 0x233cee58, 0x1a8ebfe5, 0x9d89}}, + {{0x3a056691, 0x3f3db4ea, 0x299253be, 0x26735fb8, 0x10927de8, 0x2593b5c9, 0x1bf0b94e, 0x2a790fd2, 0xdd91}}}, + /* 5*16^20*G: */ + {{{0x3c2a3293, 0x3f781378, 0x103476c5, 0x222e1bba, 0x02f4cd56, 0x2c295cca, 0x23792d0e, 0x2e3b9c45, 0x8327}}, + {{0x0e0df9bd, 0x2f215386, 0x2326a416, 0x2bf6ad3b, 0x39708496, 0x2cfa9989, 0x0a98e18b, 0x1f899bb8, 0x0499}}}, + /* 7*16^20*G: */ + {{{0x0562c042, 0x1086c9b1, 0x38dfb1a2, 0x0b48c8d2, 0x1a8ed609, 0x1998763e, 0x1b16897d, 0x0aaa8a9b, 0x5ae4}}, + {{0x0f79269c, 0x2417337e, 0x07cd8dbf, 0x3836e544, 0x389d4a94, 0x30777180, 0x3051eab5, 0x0e9f017f, 0x99d9}}}, + /* 9*16^20*G: */ + {{{0x1e85af61, 0x0d2204a1, 0x14ae766b, 0x23b5c8b7, 0x021b0f4e, 0x3ada3fdb, 0x1c8eb59a, 0x0eb909a8, 0x92c2}}, + {{0x036a2b09, 0x39c8d9a7, 0x2286fed4, 0x08eb60ad, 0x38d5792d, 0x085f571c, 0x11bb409f, 0x3e23c055, 0x414c}}}, + /* 11*16^20*G: */ + {{{0x07b5eba8, 0x38abc6cb, 0x118ea36c, 0x2afb71fe, 0x38df422d, 0x03d05dab, 0x3df1088d, 0x18231dab, 0xfee5}}, + {{0x0d0b9b5c, 0x3d4574da, 0x39054793, 0x203fd0af, 0x07c14ee3, 0x100be64a, 0x258afb11, 0x16644d3f, 0x3807}}}, + /* 13*16^20*G: */ + {{{0x3c63caf4, 0x078ee92c, 0x0f53d528, 0x23fceaca, 0x2a6afca2, 0x044ed318, 0x267e620a, 0x113ae4b9, 0x42e5}}, + {{0x169c29c8, 0x21ebb026, 0x3efc5f11, 0x29439eda, 0x015e7873, 0x3c88305d, 0x0c671f71, 0x15383e47, 0x9ff8}}}, + /* 15*16^20*G: */ + {{{0x1e0f09a1, 0x028af661, 0x14032838, 0x28427c6e, 0x300efef0, 0x25bb4a91, 0x32ce3839, 0x20ed9954, 0x7aed}}, + {{0x05857d73, 0x1176337a, 0x33f4a540, 0x22cbcc03, 0x032d8ed8, 0x2bf42ac4, 0x1ef7c7dd, 0x1517e68c, 0xf5b8}}} + }, + { + /* 1*16^21*G: */ + {{{0x24fce725, 0x1619a82b, 0x2a6c5b72, 0x3a36f471, 0x1771b4e7, 0x2a417a3c, 0x207adf5e, 0x1cac3d28, 0xe063}}, + {{0x0eee31dd, 0x09c0d3e5, 0x3104870b, 0x12129de1, 0x1a488cd7, 0x09eecab5, 0x18cfe12a, 0x225d2f38, 0x7a90}}}, + /* 3*16^21*G: */ + {{{0x1a328d6a, 0x2eaa0623, 0x1adc18bd, 0x135dcea5, 0x308fa7b2, 0x1a264616, 0x34e00a34, 0x3016e988, 0xc663}}, + {{0x3ec9b8c0, 0x0ec2edaa, 0x12bf9cc2, 0x21547a94, 0x171317dd, 0x2bf73c9d, 0x21c38d39, 0x3a6357dc, 0x3331}}}, + /* 5*16^21*G: */ + {{{0x3996de2f, 0x32472120, 0x0b25114b, 0x33b7cbb8, 0x0fe4e977, 0x2cc37ba8, 0x06a459ce, 0x09a0b7ee, 0xd3fc}}, + {{0x14526f8c, 0x31248907, 0x37abf168, 0x166d2637, 0x3781da4e, 0x2d1d5353, 0x30a18f68, 0x37e66917, 0xc4f0}}}, + /* 7*16^21*G: */ + {{{0x03e697ea, 0x31b12344, 0x05f83e85, 0x399e3ee6, 0x3fabd19c, 0x287fb268, 0x2c0237dc, 0x12d0ffac, 0xc17a}}, + {{0x1edc6c87, 0x3b8ee1f7, 0x39f02ab0, 0x38686d5f, 0x201fae96, 0x05e3dc65, 0x35954cae, 0x170b556a, 0x3935}}}, + /* 9*16^21*G: */ + {{{0x3163da1b, 0x0b4b0c08, 0x393a3118, 0x03b7b983, 0x011fde9a, 0x24d275ff, 0x390b468c, 0x22df2899, 0x8f61}}, + {{0x03bdd76e, 0x1fcc4844, 0x249b6e7c, 0x14319a8c, 0x2c5a4264, 0x2f69d35e, 0x3eb6eb5f, 0x0fc97c22, 0x7823}}}, + /* 11*16^21*G: */ + {{{0x0ec8ae90, 0x3a1643f8, 0x0bbc5dee, 0x2c9ae4ba, 0x03f1b8cf, 0x356e36b2, 0x21e6eb86, 0x303c56de, 0x9798}}, + {{0x252844d3, 0x2a6b0bab, 0x03188e27, 0x392596f4, 0x1c73bee2, 0x3b25253e, 0x02ed3dd2, 0x38aa9d69, 0xba40}}}, + /* 13*16^21*G: */ + {{{0x11d66b7f, 0x16865e3c, 0x187dc810, 0x29a49414, 0x1284757a, 0x3c6e42e2, 0x22d6747c, 0x1bb8fed6, 0xfdfa}}, + {{0x38e5178b, 0x2aa3e019, 0x3d78de9d, 0x11be7744, 0x1a18c4d8, 0x0307268f, 0x198db93c, 0x3cc78892, 0x4d9c}}}, + /* 15*16^21*G: */ + {{{0x1265bcf0, 0x201d5e12, 0x11c7d30b, 0x338ade10, 0x0f220e69, 0x3aa69187, 0x29e43add, 0x338e3788, 0xfd58}}, + {{0x2b996292, 0x0cf9ea73, 0x0f1cd1df, 0x0986ff8a, 0x05e4fb87, 0x20aae692, 0x3215bd53, 0x29794dd8, 0xffe0}}} + }, + { + /* 1*16^22*G: */ + {{{0x10559754, 0x02b5a423, 0x2a3f5854, 0x2c42f778, 0x0ce02204, 0x02efe770, 0x1d45358d, 0x1e9c5735, 0x213c}}, + {{0x34b458f2, 0x3fcb09d4, 0x36a7eedd, 0x12143d7c, 0x1ba190bb, 0x0eb41891, 0x06250701, 0x2b42d6b9, 0x4b6d}}}, + /* 3*16^22*G: */ + {{{0x1e05dccc, 0x0cb60046, 0x019a93e5, 0x0fe8fb53, 0x13d172ae, 0x1b825ae5, 0x1a030954, 0x3db85d4f, 0xb8ce}}, + {{0x0c6d5750, 0x0052833f, 0x26b68133, 0x1d5ff0da, 0x12bd99df, 0x3529d393, 0x09bbf6a4, 0x229829b3, 0x302b}}}, + /* 5*16^22*G: */ + {{{0x373bb31a, 0x16f7fb84, 0x3db97b48, 0x07dedad7, 0x3b5f4970, 0x282f78ba, 0x07385e02, 0x0cf9de6d, 0x03fb}}, + {{0x3d215c9e, 0x0d32f9a5, 0x07640d4e, 0x169f1db1, 0x3b572bc6, 0x30586aae, 0x2fe281e0, 0x36549523, 0xf36a}}}, + /* 7*16^22*G: */ + {{{0x1d9a4ab4, 0x16d457af, 0x15bb7c0a, 0x1f0db061, 0x0f7a3671, 0x05bded34, 0x03e1161f, 0x1f34427b, 0x4b17}}, + {{0x235ab6f7, 0x2ab77f91, 0x1741f558, 0x0df8957c, 0x226b486e, 0x23d9ca4d, 0x2fa65fda, 0x19ba6978, 0x3ec9}}}, + /* 9*16^22*G: */ + {{{0x301c23a4, 0x3d1beca6, 0x3a49cf56, 0x0a905611, 0x39cd75c2, 0x00e0a6e6, 0x27a06c2a, 0x00d481a8, 0x5e87}}, + {{0x10d986f9, 0x085e65ac, 0x24ccfda1, 0x05c761d2, 0x2c6e2da2, 0x1d5746b8, 0x09221e71, 0x1913bee7, 0x5b96}}}, + /* 11*16^22*G: */ + {{{0x007b0c66, 0x3cfcd748, 0x16c86fb1, 0x29ffb919, 0x2ceb7434, 0x08913d82, 0x1680a447, 0x30c064c3, 0xe545}}, + {{0x31f2d470, 0x21fd5f49, 0x35a239dd, 0x3960a386, 0x19bcbf97, 0x31bf68e5, 0x2955e7e5, 0x0d03a318, 0xe06a}}}, + /* 13*16^22*G: */ + {{{0x03648bba, 0x2960642e, 0x1c3c7444, 0x283c2c1a, 0x01b39882, 0x0fb8897c, 0x0f580a13, 0x10855e95, 0xb2a4}}, + {{0x00fb6452, 0x11bead28, 0x09c17bb2, 0x36154547, 0x3d7e31c0, 0x3ef25e3e, 0x366619e9, 0x17f0ada4, 0xfe4f}}}, + /* 15*16^22*G: */ + {{{0x2bab27d0, 0x3db748bb, 0x045103fc, 0x02d07e8b, 0x197007f7, 0x25c06463, 0x138651ba, 0x2383cf51, 0x1b90}}, + {{0x00d3d110, 0x07a19d79, 0x07e51b57, 0x2ef2a4d6, 0x3c4b9ab5, 0x15f24605, 0x26b5e6f3, 0x1897bb11, 0x9b6d}}} + }, + { + /* 1*16^23*G: */ + {{{0x08fbd53c, 0x0330e8ec, 0x1c62cddf, 0x20e31c2b, 0x019a87e2, 0x2e4d4a95, 0x0b34e8db, 0x09ca9ebd, 0x4e7c}}, + {{0x17dcaae6, 0x02ce5060, 0x3f7dd33e, 0x02e5852f, 0x2f681b53, 0x3f427db7, 0x10b18e16, 0x271d9b27, 0x1774}}}, + /* 3*16^23*G: */ + {{{0x2521b3ff, 0x38a61193, 0x1aa750ce, 0x0f01c5fa, 0x2e24a523, 0x1134afa6, 0x1455c75e, 0x138c0432, 0x0248}}, + {{0x0269da7e, 0x306b92e4, 0x23ac8bbc, 0x1c01b7a4, 0x2d0eebad, 0x30acf0ac, 0x3e30d07e, 0x34282a88, 0x9619}}}, + /* 5*16^23*G: */ + {{{0x004ba7b9, 0x25ade7ea, 0x0741751f, 0x35a91c0c, 0x2c954e20, 0x26dc359c, 0x2ce57ef7, 0x3149b3ed, 0x16c1}}, + {{0x1c5bd741, 0x1d6f8e94, 0x1c9a9cc4, 0x1d57006f, 0x0a94deec, 0x189d1672, 0x31439062, 0x1fdf0d00, 0xdb15}}}, + /* 7*16^23*G: */ + {{{0x236683fa, 0x20d921ea, 0x0ec0825e, 0x2086d4e0, 0x127b6695, 0x22739dd1, 0x131af87a, 0x0f35d4fe, 0x0397}}, + {{0x3f4a577f, 0x3d7ecadd, 0x3e981ded, 0x1e213863, 0x35a26cd7, 0x384ad8ca, 0x0a3a3643, 0x168b30c3, 0x38cf}}}, + /* 9*16^23*G: */ + {{{0x00bf6f06, 0x202ce667, 0x1043b571, 0x0f04cc89, 0x20576571, 0x3013d2c0, 0x0f1511c2, 0x26ee9cbb, 0xba6a}}, + {{0x381db551, 0x0cafbdc1, 0x0697aafe, 0x17453deb, 0x18bd8e9e, 0x082fcb95, 0x211b0320, 0x078e2cd2, 0x1377}}}, + /* 11*16^23*G: */ + {{{0x31231a43, 0x347be7c1, 0x1ad43b9f, 0x35453599, 0x1e442f44, 0x3b654193, 0x04dd2d8a, 0x2f3309f3, 0x35c5}}, + {{0x1620c8f6, 0x36dcb914, 0x23cf0ae7, 0x3de93301, 0x3a589d4c, 0x396082db, 0x346ce734, 0x1d5c8ee5, 0x0e36}}}, + /* 13*16^23*G: */ + {{{0x3dd40609, 0x3d02f15b, 0x181cd76b, 0x10642603, 0x08356ac7, 0x0bc4bf16, 0x186bca12, 0x27091715, 0xfd47}}, + {{0x2a64ca53, 0x378bc4d9, 0x21ca4739, 0x04ebb5c9, 0x1841fd91, 0x2b5e90f2, 0x0afeff2c, 0x33ed49a5, 0x3069}}}, + /* 15*16^23*G: */ + {{{0x2b799a7f, 0x36dc0bd4, 0x3b8e8424, 0x062db354, 0x2c7d544f, 0x363ae6bc, 0x0d864bde, 0x000a8eb3, 0x6c40}}, + {{0x13c81e32, 0x2d7320b3, 0x20483f68, 0x1eaf5320, 0x1ddcbdc0, 0x2e0da838, 0x235be690, 0x37054c2d, 0x95c2}}} + }, + { + /* 1*16^24*G: */ + {{{0x00fb27b6, 0x0909f8a1, 0x24305763, 0x1b8f6caf, 0x286aa5c7, 0x08e2b585, 0x38b1b10f, 0x138f6f9d, 0xfea7}}, + {{0x323cb96f, 0x0074f6df, 0x33f7b777, 0x1ad65ae5, 0x36af9312, 0x19d37b32, 0x313297cf, 0x1a36e6c2, 0x6e05}}}, + /* 3*16^24*G: */ + {{{0x3e889756, 0x37606ba6, 0x3004bb25, 0x1ed9265e, 0x1899f3f2, 0x3365ec9c, 0x1fea8226, 0x22f0cc84, 0x762e}}, + {{0x3ca6b774, 0x17896781, 0x084fa5e2, 0x1cb6cc52, 0x02e34719, 0x3313c526, 0x3e97c3c7, 0x250982bc, 0xc028}}}, + /* 5*16^24*G: */ + {{{0x0975d2ea, 0x1bdd7a5c, 0x014e8ea2, 0x14ab3e84, 0x08f4a91e, 0x26f6ec8c, 0x095348e1, 0x1f51f7d8, 0xdf07}}, + {{0x31936f95, 0x28f0b678, 0x3bdd277a, 0x07b16e13, 0x22527c8a, 0x21097262, 0x37f4424c, 0x1ea2003b, 0xf861}}}, + /* 7*16^24*G: */ + {{{0x3c4c92d7, 0x2e1247ee, 0x14391b45, 0x36d35bb9, 0x0b142935, 0x1f7aa0cd, 0x3da032e1, 0x1f5d62f4, 0x9f3e}}, + {{0x314906dd, 0x32eeff3e, 0x294e1186, 0x0a88c0f5, 0x2b150245, 0x18ac872e, 0x1466b588, 0x2107a9df, 0xecd2}}}, + /* 9*16^24*G: */ + {{{0x32a8c483, 0x2b835cca, 0x1040ac35, 0x12c32231, 0x39528117, 0x230f48bb, 0x0cf9edc3, 0x1e575ed7, 0xa0cc}}, + {{0x12cc6ba9, 0x0259d156, 0x36936055, 0x0d23c6f7, 0x31df786b, 0x1d3f25c8, 0x3873ee23, 0x0048be2c, 0xabc3}}}, + /* 11*16^24*G: */ + {{{0x05dd3aee, 0x1c3c6daf, 0x396d2f21, 0x054ea2a3, 0x2976ca13, 0x08aa6b1a, 0x3c7cce0e, 0x14294554, 0x6d1c}}, + {{0x3df597f7, 0x3b8d5393, 0x0ed53adf, 0x078c42aa, 0x07d47485, 0x09c8008a, 0x3dfdc977, 0x052381aa, 0xafff}}}, + /* 13*16^24*G: */ + {{{0x24a6d0bb, 0x1e32a6df, 0x1a1afdc6, 0x274c48bd, 0x26418f65, 0x069b62a2, 0x3f9f3f31, 0x075862e5, 0x5e5f}}, + {{0x1033eaf9, 0x1a0e11e4, 0x06f653a1, 0x1557cb94, 0x2721da72, 0x3daf3413, 0x3e6f7358, 0x140ac1a9, 0xd7b1}}}, + /* 15*16^24*G: */ + {{{0x0f005e3f, 0x36a6d791, 0x2c39bd2d, 0x3da38c6f, 0x01a1495a, 0x0f2e6b38, 0x2427fffd, 0x229acf05, 0xf813}}, + {{0x2f357eb7, 0x0b5f8080, 0x14be2134, 0x3b106f55, 0x25cb51f4, 0x005795ea, 0x0ebd9f9d, 0x23cefbed, 0xca75}}} + }, + { + /* 1*16^25*G: */ + {{{0x17bdde39, 0x0b00a910, 0x36043295, 0x11385e6d, 0x1968d315, 0x095c3566, 0x3cf0e10a, 0x1044fd9d, 0x76e6}}, + {{0x1901ac01, 0x12c5d4b4, 0x16d2032b, 0x0a8cf4ad, 0x01f0d35e, 0x019b5c1a, 0x295cf577, 0x37e37b93, 0xc90d}}}, + /* 3*16^25*G: */ + {{{0x0078ee8d, 0x3c142473, 0x06919442, 0x2fc83394, 0x1b4ff64e, 0x3dc98eaa, 0x1a9be25f, 0x15eb6167, 0xd08e}}, + {{0x2da63e86, 0x265fd370, 0x022ed9de, 0x0fbdf3e5, 0x3e6df412, 0x05cbb9d5, 0x088d72d6, 0x25e612ad, 0x852e}}}, + /* 5*16^25*G: */ + {{{0x029129ec, 0x164519c1, 0x24825481, 0x2b8eb3c7, 0x131d080c, 0x22fa03b3, 0x04d275f5, 0x30217935, 0x7da6}}, + {{0x2cd9ff0e, 0x2d42bb8a, 0x0ca586ae, 0x12302195, 0x1627bf04, 0x34081d24, 0x01857511, 0x051aee7d, 0xf498}}}, + /* 7*16^25*G: */ + {{{0x11654f22, 0x3e0f5255, 0x31aaee94, 0x3dfce508, 0x29d94fb2, 0x3a4006f9, 0x1be6e21b, 0x2433fd70, 0x90d0}}, + {{0x201a43e1, 0x3d77815d, 0x1a3f8740, 0x358d594f, 0x3f70336d, 0x3c08781a, 0x0f61a953, 0x26874aeb, 0xcd56}}}, + /* 9*16^25*G: */ + {{{0x076b19fa, 0x2dbbd947, 0x28819d71, 0x35b81b41, 0x21292ed9, 0x08b0c420, 0x1d1ecc73, 0x26161f3c, 0xda47}}, + {{0x326f5af7, 0x2a89bbac, 0x153fc206, 0x1ef44fa5, 0x16569ea6, 0x0da41df8, 0x0af01d17, 0x35de26f3, 0xebb1}}}, + /* 11*16^25*G: */ + {{{0x39135dbd, 0x364bed96, 0x1d8631ec, 0x3021ebce, 0x29897cf0, 0x1eabd60b, 0x1ee6ad81, 0x1d412a37, 0xe3e4}}, + {{0x0748045d, 0x241abcf9, 0x2c95da96, 0x2880bfd7, 0x383ffea5, 0x2320654a, 0x3c6c40b9, 0x16fe0272, 0x930a}}}, + /* 13*16^25*G: */ + {{{0x0dee455f, 0x2fc2e797, 0x0ce4075c, 0x19fff9ba, 0x0bdb4aff, 0x114ce3e0, 0x0a9b0a47, 0x195bfa1c, 0x7e8c}}, + {{0x171b9cba, 0x1cf7a660, 0x2f466271, 0x28b459d1, 0x03a53b4a, 0x3dd83d20, 0x0740f2a3, 0x318cb28c, 0xbddd}}}, + /* 15*16^25*G: */ + {{{0x2698b59e, 0x1de5ae6d, 0x13447a43, 0x0cd64962, 0x23c7260a, 0x2c0d6acf, 0x15eb15be, 0x107e246a, 0x3df8}}, + {{0x2b92baf5, 0x33e399e5, 0x14949f8b, 0x3f219ec8, 0x1cf3867b, 0x0aeba3c4, 0x090c1da0, 0x39b7e62c, 0xb38f}}} + }, + { + /* 1*16^26*G: */ + {{{0x2bcbb891, 0x2ac54090, 0x326cbee3, 0x1f3190f7, 0x3f8f9a8f, 0x206ea9d0, 0x2abe1e82, 0x315ac0ec, 0xc738}}, + {{0x299a84c3, 0x1f9cd765, 0x080cfe91, 0x0c53bbde, 0x3fbbbb82, 0x063cbab2, 0x2d2537f7, 0x2d5e2546, 0x893f}}}, + /* 3*16^26*G: */ + {{{0x0761d58d, 0x12eabcce, 0x0d60e2f3, 0x1326f902, 0x20df7aca, 0x09028d5c, 0x3614610a, 0x1849e08f, 0xb8c4}}, + {{0x1d1051a4, 0x0e3a82ea, 0x2107c5b6, 0x1d411e17, 0x33c5053f, 0x1163da5f, 0x0e37d14a, 0x365b145c, 0x8f9e}}}, + /* 5*16^26*G: */ + {{{0x050b0040, 0x36c2cc10, 0x0134adc2, 0x3d1f6e7c, 0x1a3671f3, 0x03264ffa, 0x271f7a35, 0x1ba7dc40, 0x08d5}}, + {{0x1b3fd0a1, 0x163899e9, 0x21782beb, 0x35f11c83, 0x39b285f6, 0x34542a35, 0x29aa21ff, 0x216baf42, 0xa121}}}, + /* 7*16^26*G: */ + {{{0x13573b7f, 0x15958f7c, 0x30b6270f, 0x268717b4, 0x265a3788, 0x083e5def, 0x3ce6341e, 0x3c8cb50b, 0xdc13}}, + {{0x0c1f2ba6, 0x0ab348a1, 0x3404b1c4, 0x11551c05, 0x290a7670, 0x10436a12, 0x2340c3c7, 0x2ea010a7, 0xc909}}}, + /* 9*16^26*G: */ + {{{0x07ae9ceb, 0x00bd642e, 0x0ef2d14b, 0x1b087a9c, 0x2119a822, 0x0655976c, 0x37f073af, 0x0b798077, 0x25c0}}, + {{0x0bc6e275, 0x1c24344d, 0x26587264, 0x319077c2, 0x2d11d537, 0x2138373e, 0x2383c0c8, 0x3ab4b204, 0x8a9f}}}, + /* 11*16^26*G: */ + {{{0x2c5a3c34, 0x3e0263db, 0x15949fe1, 0x33a0b00a, 0x2e3e58ae, 0x2e7d329e, 0x0e49ce8a, 0x2746cb3e, 0xfedd}}, + {{0x213d7714, 0x0ad52fd3, 0x1bf82976, 0x2bad51a6, 0x0f4b00ad, 0x3a14c4b2, 0x3b8e0b0b, 0x0930c614, 0xa52e}}}, + /* 13*16^26*G: */ + {{{0x2ab6a396, 0x2d395346, 0x11360769, 0x0086e468, 0x0488b373, 0x38b5fd7a, 0x2a48c2de, 0x0ca1af1b, 0x3e0e}}, + {{0x1980e27e, 0x3acc7923, 0x3468f6a2, 0x2c04107c, 0x053fc66a, 0x07f877ad, 0x337964f3, 0x205cbe8e, 0xca44}}}, + /* 15*16^26*G: */ + {{{0x341023ec, 0x2bcd6188, 0x3ecf570a, 0x11763ddb, 0x02b9af56, 0x0b808026, 0x32d28498, 0x2e4c2030, 0x344a}}, + {{0x1e1eeb87, 0x13e260a4, 0x03995d70, 0x13a5dabf, 0x114c5ffc, 0x23cb47a9, 0x0462a73f, 0x0ac10ac9, 0x6e1c}}} + }, + { + /* 1*16^27*G: */ + {{{0x08f6c14b, 0x1cba7d96, 0x29250143, 0x35cb97ce, 0x172877d1, 0x131d8df2, 0x25b81e26, 0x1899522d, 0xd895}}, + {{0x1d7d991f, 0x24d8fb5d, 0x3b067e17, 0x10a358ca, 0x0340eb03, 0x3b182063, 0x07eae728, 0x2a8e3caf, 0xfebf}}}, + /* 3*16^27*G: */ + {{{0x2127b756, 0x02ea1ffd, 0x3a097048, 0x10a2f92a, 0x20b41603, 0x0d8b6941, 0x1f12672d, 0x1e0bdc5b, 0x6d8c}}, + {{0x3f172571, 0x1547dd2a, 0x17cdcca6, 0x0ea9b68b, 0x134daf4e, 0x26a0b4db, 0x1b911145, 0x37c225bf, 0x99ae}}}, + /* 5*16^27*G: */ + {{{0x358cf17a, 0x37b869cd, 0x18823524, 0x3e1772e9, 0x0097f8f1, 0x166bbc6d, 0x37aca8d0, 0x2fb7656f, 0xebca}}, + {{0x1caa0ccd, 0x11b3717d, 0x0ace95c4, 0x3eb484b4, 0x032e6b10, 0x00286d9f, 0x2b9cb02c, 0x3383e3c8, 0x47d3}}}, + /* 7*16^27*G: */ + {{{0x2c855c5b, 0x33bb9456, 0x17c8afbb, 0x21588680, 0x17fc2811, 0x0c68da78, 0x0ce24453, 0x134b92f5, 0xe8df}}, + {{0x2e465650, 0x27579cb0, 0x21e4d7d5, 0x18ed57c7, 0x2f32c596, 0x136d3d67, 0x39b26444, 0x3f5c311f, 0x6c57}}}, + /* 9*16^27*G: */ + {{{0x12e7e454, 0x023d6f69, 0x30e6150d, 0x0cbbfbc3, 0x181662fe, 0x121808ea, 0x0a832912, 0x34f5c63b, 0x4068}}, + {{0x18ef191e, 0x1e6b3797, 0x3c373327, 0x23487b44, 0x1d38d198, 0x305165f6, 0x247aab9e, 0x14edc952, 0x8cd8}}}, + /* 11*16^27*G: */ + {{{0x06c5d939, 0x215eb7e1, 0x3a933de0, 0x1d68a1de, 0x0a027ea4, 0x2fccb983, 0x025e0b55, 0x03b36c76, 0x1255}}, + {{0x19e757c9, 0x0a9d3f15, 0x0d8d4319, 0x22dd07fb, 0x324a7283, 0x2390f05d, 0x2d7a7544, 0x20cd3e1c, 0x7b8f}}}, + /* 13*16^27*G: */ + {{{0x16c8a56f, 0x2342ab19, 0x0f374213, 0x024f150d, 0x3ad08f85, 0x2eded4eb, 0x185d4c69, 0x19c6b0ed, 0x944d}}, + {{0x1a7be289, 0x27d37197, 0x106517eb, 0x35305d37, 0x3ac61967, 0x10e4d84c, 0x01fff4c1, 0x1965ded4, 0xa710}}}, + /* 15*16^27*G: */ + {{{0x2e08f15a, 0x3bae2862, 0x012900ba, 0x1a795b72, 0x13c305fd, 0x2c0d956b, 0x19a0cfe6, 0x13a47342, 0x86a5}}, + {{0x01388308, 0x1493479f, 0x335254d3, 0x04a74496, 0x35686777, 0x0aa341b5, 0x384603a7, 0x18520de9, 0xcfee}}} + }, + { + /* 1*16^28*G: */ + {{{0x0f676e03, 0x24542959, 0x3e84edd4, 0x3ff1cda4, 0x1e8761ce, 0x3d90cd5c, 0x17518eb0, 0x2500caa5, 0xb8da}}, + {{0x0efdf6e7, 0x1223939d, 0x1ff3b511, 0x33161365, 0x2808b092, 0x267325d8, 0x1a1e4d7c, 0x37e91201, 0x2804}}}, + /* 3*16^28*G: */ + {{{0x06e1346b, 0x28661277, 0x05af1c5e, 0x2f9ec40e, 0x1152c05a, 0x31d87c53, 0x2d10be54, 0x1a3fc260, 0x0690}}, + {{0x17226c13, 0x2ed62953, 0x0c6026e7, 0x3da24e65, 0x06442aa4, 0x176caf42, 0x3de26da8, 0x38f8242f, 0xb863}}}, + /* 5*16^28*G: */ + {{{0x1ca1f6a1, 0x039a47f3, 0x08cff1a3, 0x232f450d, 0x286ce106, 0x1b7172c7, 0x19761528, 0x0d24f2c9, 0x898c}}, + {{0x164f647c, 0x12b7083c, 0x32bd79ca, 0x29f3e5e7, 0x2c6e93b2, 0x1150914a, 0x2a5549d8, 0x1661aad5, 0x75f7}}}, + /* 7*16^28*G: */ + {{{0x3d1e3998, 0x29a780f0, 0x3a04328a, 0x15b22e45, 0x2a274e5e, 0x0a675c08, 0x18bf01a5, 0x38bfb4a4, 0xb213}}, + {{0x325fb81e, 0x30b2f718, 0x3ded175e, 0x0d0596fa, 0x243bc3d5, 0x187afe0e, 0x13c12c3d, 0x23b083cb, 0x229f}}}, + /* 9*16^28*G: */ + {{{0x225be234, 0x02f87fb2, 0x1df35070, 0x20f8f9c3, 0x206e060e, 0x342e9a45, 0x3f93e5d1, 0x0eb605b1, 0x4b3b}}, + {{0x120e8362, 0x18edf80e, 0x3211b840, 0x39ff64b3, 0x0cc04c41, 0x17a5b7f6, 0x2bc9c787, 0x008ee176, 0x5eec}}}, + /* 11*16^28*G: */ + {{{0x2289f55e, 0x2598d29f, 0x2c76707b, 0x1dac3c38, 0x0965be29, 0x0946c09e, 0x04f96020, 0x222db76c, 0x9f7b}}, + {{0x3e1e4bde, 0x0f34ed97, 0x310a2b1b, 0x394db83a, 0x0fc71fc0, 0x051ad0a6, 0x010f7be3, 0x3de131c1, 0x32f9}}}, + /* 13*16^28*G: */ + {{{0x1dfe1d2b, 0x19527230, 0x16878e51, 0x24fd4279, 0x3b73a4c4, 0x332b7f4f, 0x048e3e76, 0x10fa72dd, 0xd58a}}, + {{0x0cd50922, 0x33c9e56e, 0x0bd6fbff, 0x366e8857, 0x28276b54, 0x1ca44ca0, 0x083cf10a, 0x219ae816, 0xfc17}}}, + /* 15*16^28*G: */ + {{{0x249c795e, 0x090546f8, 0x1ce805e1, 0x1101aaa6, 0x27ea4eed, 0x365a70f0, 0x18310cd6, 0x1c4e5c44, 0x21d2}}, + {{0x19208ece, 0x0004bb0e, 0x2dfb761b, 0x1c651292, 0x2bb4c3d6, 0x0d6e1548, 0x1acea177, 0x3e6d2c1d, 0x94c5}}} + }, + { + /* 1*16^29*G: */ + {{{0x23c0df5d, 0x06845de3, 0x156a792f, 0x067bfed4, 0x1d7fab20, 0x2b6ae51d, 0x3b33a7d8, 0x3a851107, 0xe80f}}, + {{0x2ac9ec78, 0x32d0a46d, 0x3322ea9f, 0x0557a02b, 0x0a94472d, 0x25da328f, 0x200771e8, 0x379fd8e3, 0xeed1}}}, + /* 3*16^29*G: */ + {{{0x17592d55, 0x300d67b3, 0x0e350192, 0x356e51d0, 0x3ce3b106, 0x3fbda58c, 0x1052608a, 0x31b6f128, 0x5d2e}}, + {{0x2f5183a7, 0x19b9743a, 0x11151742, 0x0a9ef36b, 0x0cd6950e, 0x1c43e89a, 0x245eb58f, 0x337e271b, 0x0a92}}}, + /* 5*16^29*G: */ + {{{0x3e8f9f5c, 0x247d2d27, 0x1880a519, 0x187c7856, 0x1f404d73, 0x32b8d085, 0x3f742fe2, 0x0770ec46, 0xac37}}, + {{0x325a503c, 0x1ea0ffcc, 0x2751e1d1, 0x254d163b, 0x14e73522, 0x04079cc9, 0x1a477ff2, 0x05b061c2, 0xc516}}}, + /* 7*16^29*G: */ + {{{0x19e33446, 0x12872354, 0x2af385df, 0x224ef114, 0x22a17a40, 0x2302f408, 0x1840c934, 0x000e853c, 0x8942}}, + {{0x26387689, 0x034e2803, 0x1e74f984, 0x3f5dcd9e, 0x3de4e06b, 0x2cb5b43b, 0x1077a4d8, 0x00e56569, 0xa9fd}}}, + /* 9*16^29*G: */ + {{{0x3913cb26, 0x35ca3256, 0x13bd6d03, 0x3ad06700, 0x105c9899, 0x36913fd5, 0x342a8a2c, 0x099acc28, 0x2770}}, + {{0x3348a7a2, 0x3f9c5ccf, 0x0815bebb, 0x103246f3, 0x32b324e9, 0x0b49341f, 0x0db1a555, 0x2f179e6c, 0xf649}}}, + /* 11*16^29*G: */ + {{{0x195e8247, 0x02aa8085, 0x286cd1af, 0x2ff71155, 0x38ba9097, 0x179b8073, 0x3ed2178e, 0x3434e0f2, 0x75e4}}, + {{0x19982d22, 0x288ff675, 0x29ad893c, 0x36ad6dba, 0x3726d47d, 0x3e5c3b1e, 0x10990741, 0x10a85d50, 0x1fce}}}, + /* 13*16^29*G: */ + {{{0x26333323, 0x11e7d136, 0x0f4abf47, 0x2eef071a, 0x04da849c, 0x08358166, 0x1bbf03f0, 0x2d8e0cd8, 0x3ed1}}, + {{0x35d61ba3, 0x2c4ff122, 0x378f7294, 0x2dca2842, 0x0f929ea9, 0x1f2625a2, 0x34ee75d9, 0x0b6922d6, 0xd84f}}}, + /* 15*16^29*G: */ + {{{0x333980bf, 0x09415f52, 0x0dd00baf, 0x28dc0b94, 0x08dd4368, 0x1bf5dc8d, 0x18181b84, 0x34bc1a9d, 0x70fd}}, + {{0x20b75785, 0x0bbaa33a, 0x1d74a561, 0x040d60e1, 0x2e596b0a, 0x29043447, 0x18696957, 0x32b03435, 0x5edf}}} + }, + { + /* 1*16^30*G: */ + {{{0x04e16070, 0x3701eef3, 0x2fd6915d, 0x286080c7, 0x167543f2, 0x29239475, 0x1704313b, 0x1a5ef7f3, 0xa301}}, + {{0x1e177ea1, 0x30346810, 0x0a11a130, 0x0d76fdf0, 0x140f9b17, 0x2027e897, 0x3e4f5081, 0x3e473ed9, 0x7370}}}, + /* 3*16^30*G: */ + {{{0x138011fc, 0x1c049c00, 0x17285626, 0x165a99eb, 0x200a4d83, 0x2c4cc208, 0x1eb11156, 0x04e8c205, 0x6e83}}, + {{0x3f15ab7d, 0x2b2da7e8, 0x1c51f9a6, 0x2be456ba, 0x1ac30426, 0x04b6c807, 0x0f204c1a, 0x2062f709, 0xc147}}}, + /* 5*16^30*G: */ + {{{0x100e6ba7, 0x0e9d26e3, 0x0916f7f5, 0x0dbb16d1, 0x19e1b43d, 0x0780e293, 0x0851f2bd, 0x2a4265e1, 0xf952}}, + {{0x0175e4c1, 0x36ebbb94, 0x062a2b98, 0x15c59ed3, 0x3fa0f655, 0x0dda8b89, 0x3cebf861, 0x0e96c22a, 0xd8a9}}}, + /* 7*16^30*G: */ + {{{0x03aa0e93, 0x2401968a, 0x2fb1f626, 0x0b8e50eb, 0x1e893a8f, 0x00c68676, 0x3fee7504, 0x1b578c74, 0x9401}}, + {{0x07addac2, 0x23bb49a2, 0x257b07a3, 0x210dceea, 0x2e6fd7f4, 0x1574d53b, 0x14d96403, 0x0cbb9711, 0x6750}}}, + /* 9*16^30*G: */ + {{{0x0266b17b, 0x03d218b8, 0x262bb32b, 0x0d5a2880, 0x1f09c202, 0x25e211aa, 0x3b2891bb, 0x345d3567, 0xef22}}, + {{0x39dac83e, 0x0a9b810d, 0x1c341b73, 0x39c9dbdc, 0x34a1073e, 0x27330eb8, 0x24c7568f, 0x21325eac, 0xbc57}}}, + /* 11*16^30*G: */ + {{{0x12d382a0, 0x0c4c056a, 0x2ecd9ae2, 0x2372ef38, 0x2df927f2, 0x2b31e02c, 0x3892d39c, 0x3bf3933a, 0xb5f7}}, + {{0x25b4b532, 0x28bc2aee, 0x1acf8c5b, 0x3ec25b4a, 0x0bddd371, 0x255f1b83, 0x3f2353c0, 0x1516d470, 0x6843}}}, + /* 13*16^30*G: */ + {{{0x012cffa5, 0x39a49191, 0x28cc5c47, 0x3b508219, 0x14624389, 0x1d5363ef, 0x31076408, 0x30f4acb9, 0x1cdd}}, + {{0x1521954e, 0x379b6273, 0x336b528a, 0x0726109a, 0x02b08ac4, 0x2c49afe5, 0x1f8a63fd, 0x1a832cbc, 0x1e47}}}, + /* 15*16^30*G: */ + {{{0x34a9f22f, 0x0d7f90e4, 0x17a8e2ad, 0x02067148, 0x0835b0cc, 0x3e2e2e52, 0x0e939f21, 0x2cd67c97, 0x2acc}}, + {{0x375c4927, 0x2dd772ce, 0x1ba550b7, 0x12f5efb1, 0x30edf115, 0x04e8dfb7, 0x2d2e5192, 0x293a5622, 0xd518}}} + }, + { + /* 1*16^31*G: */ + {{{0x3fb04ed4, 0x2deb18f8, 0x1307fffa, 0x330cc2c4, 0x278de208, 0x3e741449, 0x2b936463, 0x216ce275, 0x90ad}}, + {{0x0b6ef150, 0x24753523, 0x182894d9, 0x2bbeaf85, 0x3222b839, 0x372f6509, 0x38261aff, 0x1e8d8828, 0x0e50}}}, + /* 3*16^31*G: */ + {{{0x30b7b678, 0x09d76cce, 0x0f638166, 0x0f10c46f, 0x2b6c76f1, 0x21af2909, 0x0231ba19, 0x125ccd39, 0x186e}}, + {{0x38d91fc1, 0x1e81dbcb, 0x09535dca, 0x01dc8951, 0x37e67e11, 0x3f209702, 0x3bd84aa7, 0x18392601, 0xc0d4}}}, + /* 5*16^31*G: */ + {{{0x33421fb8, 0x3c1b972e, 0x35a55d0c, 0x125c7cbb, 0x37241298, 0x01acd30e, 0x1bf62e7e, 0x2360d3db, 0x061c}}, + {{0x0e3ccd80, 0x257bd9a1, 0x26fcdd29, 0x19c4d2ce, 0x05eb5c80, 0x0e496438, 0x3b4b7ba9, 0x1ab66400, 0x6dfc}}}, + /* 7*16^31*G: */ + {{{0x2f6b35a4, 0x0492f862, 0x327fb487, 0x27cde9aa, 0x3a68ad88, 0x18c901cc, 0x2e513b73, 0x2d8e8823, 0xf6a6}}, + {{0x01f422a6, 0x2badbfb2, 0x1ee1862c, 0x355d5b9d, 0x20186f19, 0x34dc13d5, 0x1138b1ca, 0x322a000b, 0x3df7}}}, + /* 9*16^31*G: */ + {{{0x26954c11, 0x25a08fa2, 0x160d018b, 0x2a290f05, 0x0778ff7f, 0x346c3c54, 0x2c376220, 0x3f0a30a1, 0x87a2}}, + {{0x272a8b45, 0x15b8ccb8, 0x278124b7, 0x1224cfca, 0x127532cc, 0x06523683, 0x2ecef97b, 0x1462d16a, 0x33ad}}}, + /* 11*16^31*G: */ + {{{0x22706ab6, 0x391d1cab, 0x2e53c0da, 0x02cd0774, 0x384cfe3c, 0x15bbf2f0, 0x081a6845, 0x0b811b9e, 0xe147}}, + {{0x1d58de05, 0x1ba1a85a, 0x13cd2753, 0x16275551, 0x0621f8aa, 0x1a465e32, 0x18fc683f, 0x24aa91f1, 0x82cd}}}, + /* 13*16^31*G: */ + {{{0x07a84fb6, 0x2feb9508, 0x3a15021e, 0x08da1d43, 0x08b9ebc4, 0x2d358079, 0x0aef5de8, 0x24b2013e, 0x1caf}}, + {{0x27149109, 0x1ac60640, 0x22ce6761, 0x07305a5a, 0x101622ec, 0x2993e3fc, 0x2e53a481, 0x2e16b25d, 0xbc24}}}, + /* 15*16^31*G: */ + {{{0x0a955911, 0x1da33f85, 0x0ded52db, 0x1f85a898, 0x17839710, 0x27bfa6cf, 0x1650d258, 0x3f5a6bc2, 0x705b}}, + {{0x3fd200e4, 0x2edf1a4f, 0x242e72d8, 0x1fced48a, 0x0051fa29, 0x18f607d5, 0x3f990a7e, 0x2904c2dc, 0xe14a}}} + }, + { + /* 1*16^32*G: */ + {{{0x1ec4c0da, 0x2ded1132, 0x23ea3351, 0x23159e1c, 0x1f162ee8, 0x2706b660, 0x35f33923, 0x2e74bd8e, 0x8f68}}, + {{0x101fff82, 0x08f2fde5, 0x1510bfdf, 0x3a8b3fa5, 0x3e215dbb, 0x36430ada, 0x23986de1, 0x27cb6e81, 0x662a}}}, + /* 3*16^32*G: */ + {{{0x123809fa, 0x238ae3b7, 0x1d954be1, 0x21172cd4, 0x051f08fd, 0x24cd8fc9, 0x09f228ba, 0x076f8b94, 0x3838}}, + {{0x331fed52, 0x35c1d460, 0x2d8f24db, 0x207f32cc, 0x0eb1cc36, 0x10169548, 0x117dcb09, 0x0b4283ee, 0xe4a3}}}, + /* 5*16^32*G: */ + {{{0x17c2a310, 0x3a909922, 0x01226303, 0x21aba950, 0x0699a1f1, 0x086e0aa9, 0x32ae6f69, 0x09c9390d, 0x4926}}, + {{0x1e27ded0, 0x3106da05, 0x35ff8ce0, 0x058d84a9, 0x14303b6d, 0x33e95a5c, 0x3abf95a2, 0x39dcef29, 0x1337}}}, + /* 7*16^32*G: */ + {{{0x0ebd2d31, 0x0e12c1e7, 0x306db8d1, 0x330695bf, 0x37e2f84d, 0x094ecf91, 0x00c90d5e, 0x15a30689, 0xe306}}, + {{0x12546e44, 0x24ad020e, 0x23738266, 0x2f2010af, 0x3d0db6ff, 0x3cac41fd, 0x34260888, 0x1bf8de24, 0x0eac}}}, + /* 9*16^32*G: */ + {{{0x363136b0, 0x14c30e78, 0x2b41dd9c, 0x3afe366a, 0x3bd63374, 0x2c39d88f, 0x0cefc271, 0x0403890a, 0x3b9e}}, + {{0x2cdbbc8a, 0x14fb05bd, 0x2d31f819, 0x2b8a28ce, 0x075b26a2, 0x14cfae3d, 0x2bb71df1, 0x26054b45, 0xfafb}}}, + /* 11*16^32*G: */ + {{{0x2f485d3f, 0x1823c11c, 0x107beee9, 0x3281da20, 0x1edef717, 0x1b2a03d7, 0x2c9a92b7, 0x2b525c4a, 0xbb0a}}, + {{0x3ca2f975, 0x1e4e4940, 0x1670bffe, 0x1696be8c, 0x17da3489, 0x34807dca, 0x354798ec, 0x2714f160, 0xea69}}}, + /* 13*16^32*G: */ + {{{0x36718dc9, 0x2bbb4ce8, 0x01123de4, 0x3962d36c, 0x3e0113e1, 0x23ac65eb, 0x2fcc0d4e, 0x02b2393b, 0x7909}}, + {{0x1cfae7c5, 0x18cc8ac4, 0x3a9008b9, 0x0dabedc2, 0x1aaa56dd, 0x205b2f36, 0x05b8f13d, 0x1c8ae464, 0xeaab}}}, + /* 15*16^32*G: */ + {{{0x3f60c7d1, 0x09a5a531, 0x1775ad2a, 0x35c779f3, 0x09ba668d, 0x0f6ef395, 0x17b551c0, 0x206b7a7e, 0xe77c}}, + {{0x02d72449, 0x3b1607ca, 0x02986d34, 0x051c3dc7, 0x28154363, 0x30ecc8fa, 0x01321c5f, 0x051e3bbe, 0x3acf}}} + }, + { + /* 1*16^33*G: */ + {{{0x13231e11, 0x1a1bf541, 0x3681e3e6, 0x123a1940, 0x0c36091f, 0x267fe466, 0x385d65ff, 0x3ec05dab, 0xe4f3}}, + {{0x2feb73bc, 0x08b0e15d, 0x151d1c98, 0x31f9d3b2, 0x02b7286c, 0x069b43a8, 0x34f1c166, 0x18ceb43b, 0x1e63}}}, + /* 3*16^33*G: */ + {{{0x2bf05bd6, 0x0e67c139, 0x12a99465, 0x3d5b80c8, 0x070deca2, 0x0bd47fad, 0x04fe9083, 0x0c906fb9, 0x900c}}, + {{0x300d358b, 0x394ab4ef, 0x04efb15d, 0x2614d60f, 0x0b2439d6, 0x31c8115c, 0x1f0f5f95, 0x3e7a3a2c, 0x6c31}}}, + /* 5*16^33*G: */ + {{{0x1f105c50, 0x29f0a332, 0x31385257, 0x3837bbde, 0x0233cd82, 0x2330d00f, 0x190aad62, 0x00d8aac1, 0x5a8d}}, + {{0x38a4cde9, 0x326c8060, 0x2d013c35, 0x017da299, 0x03ff74a6, 0x29adc905, 0x0e536936, 0x3aac44f5, 0xc059}}}, + /* 7*16^33*G: */ + {{{0x32d64feb, 0x11f862e6, 0x292292c6, 0x1cbe2964, 0x0ba4e837, 0x3ce95ddb, 0x2f60a48e, 0x1340c48c, 0xd93f}}, + {{0x34698359, 0x2c3ef564, 0x2c90da37, 0x3810c2fb, 0x1c8c4d93, 0x1cc47153, 0x32733a23, 0x15575172, 0x7925}}}, + /* 9*16^33*G: */ + {{{0x039fbc84, 0x08881335, 0x057a0167, 0x1c18a458, 0x2ac65b7e, 0x138af198, 0x328441b1, 0x1a71b8db, 0x2f07}}, + {{0x1c201bec, 0x3ee40b78, 0x04dd5d73, 0x29e6da93, 0x0e2149cc, 0x37c01e64, 0x3bdddfa5, 0x3cdc935c, 0xb434}}}, + /* 11*16^33*G: */ + {{{0x06a758ea, 0x14dfab32, 0x27f19c4d, 0x0620c624, 0x016e3991, 0x1a256855, 0x20309958, 0x19e01567, 0xfe7e}}, + {{0x1b7ab649, 0x13c8b657, 0x03120d1e, 0x2005c1d1, 0x09251f3b, 0x02385a61, 0x1dcb988c, 0x1a59e8a0, 0x38aa}}}, + /* 13*16^33*G: */ + {{{0x0cfffefa, 0x39c5589a, 0x0651afad, 0x060113dc, 0x03af8510, 0x3dbe4543, 0x03127d6d, 0x3d729d4e, 0x91ba}}, + {{0x1f7f6faf, 0x1f4dbcd3, 0x2fd303dc, 0x2fbcc439, 0x1d3d92f4, 0x25a7c49f, 0x3bcebe5d, 0x33c464d1, 0x04e5}}}, + /* 15*16^33*G: */ + {{{0x0d33c546, 0x3f0245fa, 0x05edaf32, 0x15d7ecca, 0x35ddd782, 0x314dcf83, 0x378a7cb2, 0x104872cf, 0x4458}}, + {{0x000b4fd4, 0x029b461c, 0x32ca7366, 0x0bc28f3e, 0x1ada2085, 0x097ab8e4, 0x0753a772, 0x24ddfcfe, 0x308d}}} + }, + { + /* 1*16^34*G: */ + {{{0x20eae29e, 0x1bedbab8, 0x14e1d071, 0x00d3cbc3, 0x1a4266c7, 0x1854de91, 0x3f331eb9, 0x3ea6c63a, 0x8c00}}, + {{0x2702414b, 0x1f4a9319, 0x1e36c54e, 0x3eb6bea0, 0x36c974c2, 0x30d0e8dc, 0x121a1a9d, 0x1c99ffa9, 0xefa4}}}, + /* 3*16^34*G: */ + {{{0x2bfd913d, 0x0fe5580f, 0x254c9eac, 0x29a039bb, 0x2a8d2050, 0x01e82130, 0x3ddf874d, 0x0aa9fa41, 0x3636}}, + {{0x052e243d, 0x113e6bab, 0x2b2faafc, 0x0c2ec435, 0x1a2a82d8, 0x18910dc3, 0x0afd5341, 0x1e19db2e, 0x48f2}}}, + /* 5*16^34*G: */ + {{{0x2d132896, 0x32aeafe6, 0x3bc6c967, 0x2c78eead, 0x19200dfc, 0x16b658b7, 0x21e02f29, 0x25db7cca, 0x4487}}, + {{0x2f685248, 0x23006c4a, 0x276aa7a4, 0x2d035698, 0x161a3306, 0x26a41dd1, 0x1afe1efc, 0x16183445, 0x27bd}}}, + /* 7*16^34*G: */ + {{{0x3fa2670c, 0x02055bda, 0x06273e6e, 0x003e0ae8, 0x35032474, 0x2a72aa0c, 0x383788b6, 0x0eb0a2f2, 0x4a4d}}, + {{0x16c1764d, 0x022e7ff7, 0x329beed8, 0x0c16532f, 0x302b9d49, 0x1dc4777b, 0x05a4f17e, 0x2e470061, 0x70ab}}}, + /* 9*16^34*G: */ + {{{0x0cb24aa7, 0x365abf89, 0x1345c530, 0x0c42318e, 0x38fe1890, 0x39bf627f, 0x11802c3a, 0x0b4642ba, 0x5f7b}}, + {{0x0a693d7d, 0x35e01d0d, 0x3c81d0c6, 0x237adc24, 0x267c47ce, 0x0fe028f3, 0x1f2b330a, 0x0d80313f, 0x0770}}}, + /* 11*16^34*G: */ + {{{0x2f7fb8bd, 0x0646f17c, 0x3e4090a4, 0x31192857, 0x0886d87b, 0x30939b65, 0x190d02ae, 0x1d144ce7, 0x5139}}, + {{0x03908c0f, 0x0252b0b6, 0x3f98d5a8, 0x3f0cb4f8, 0x015c47fa, 0x23fbf6ba, 0x03bf34b8, 0x050f91d9, 0xfcd7}}}, + /* 13*16^34*G: */ + {{{0x2e36ca73, 0x0add2457, 0x3bbf3ede, 0x321934da, 0x014887ea, 0x0a444afc, 0x3dfb8aa4, 0x05b58afe, 0xcf83}}, + {{0x2ec25534, 0x2d248650, 0x08d710f5, 0x25856636, 0x1cca681c, 0x11142243, 0x19d73e38, 0x2d637ad7, 0x09fe}}}, + /* 15*16^34*G: */ + {{{0x3752f97d, 0x3224df5a, 0x33476613, 0x0bbef1d7, 0x0fa6165a, 0x274a19a3, 0x3b49de53, 0x37a69312, 0x8610}}, + {{0x1f1b1af2, 0x015f7350, 0x05543e08, 0x2ad367d5, 0x33f99e57, 0x33666c94, 0x30bbc937, 0x25e80ad8, 0xd319}}} + }, + { + /* 1*16^35*G: */ + {{{0x20cb3e41, 0x25ff77f1, 0x08b92c09, 0x0f4213cc, 0x298ed314, 0x033b02a7, 0x0829f3e1, 0x1b39a775, 0xe7a2}}, + {{0x0f2cfd51, 0x3a2a5087, 0x20e83e20, 0x29acb010, 0x2fbb18d0, 0x2c01a86a, 0x3984b471, 0x238c03e9, 0x2a75}}}, + /* 3*16^35*G: */ + {{{0x3aee42db, 0x03e7f4af, 0x330714a7, 0x2eef16d1, 0x2cbfc1d9, 0x2dbb6e47, 0x19150fc7, 0x09f9f66d, 0xcc34}}, + {{0x15d87bdb, 0x188a7004, 0x272422dc, 0x3972eb63, 0x21520010, 0x38ff4fec, 0x1c6a1885, 0x26106948, 0xea24}}}, + /* 5*16^35*G: */ + {{{0x3ed4a086, 0x3d0d9b19, 0x29c410ef, 0x35d70563, 0x0b5cf4b1, 0x0f1617ef, 0x0445dec8, 0x016eb366, 0x948f}}, + {{0x1e2bca4b, 0x0a86003e, 0x03fa2d1a, 0x08ca29c7, 0x1139411c, 0x11429980, 0x22a3382f, 0x2a27fed6, 0x864c}}}, + /* 7*16^35*G: */ + {{{0x37542c21, 0x032fa9b2, 0x2a64c15c, 0x067d34a3, 0x1d6d43ae, 0x1bf11514, 0x19ac9065, 0x0658a4a4, 0x2584}}, + {{0x272bfabf, 0x2faf8c65, 0x0c2ad7b3, 0x38e861b9, 0x3513d5f3, 0x176a9331, 0x3244801e, 0x16c7c736, 0xfcb3}}}, + /* 9*16^35*G: */ + {{{0x0c1ecbf8, 0x0f1187d0, 0x2eed7ca4, 0x227c37a6, 0x28421f64, 0x25d53307, 0x3c52522a, 0x337104dc, 0x7e12}}, + {{0x30bed615, 0x3516e336, 0x3e1d9f59, 0x1a7d8763, 0x0d1259c9, 0x3e536af9, 0x1c837143, 0x13e22223, 0x7128}}}, + /* 11*16^35*G: */ + {{{0x14557d86, 0x1f999470, 0x2667ff41, 0x3fbb11e3, 0x05a6cf1c, 0x2e4729e8, 0x342a6772, 0x30bfca8d, 0x4b8e}}, + {{0x35167eb9, 0x3766c646, 0x3c3f692b, 0x357cbbc3, 0x27ac5f28, 0x101cb794, 0x157ab14a, 0x30ffc130, 0xfde6}}}, + /* 13*16^35*G: */ + {{{0x0780763c, 0x0ae0b4ed, 0x265691d5, 0x229b57a4, 0x3ac07e5f, 0x10db71a5, 0x23a42532, 0x3041cce5, 0xfcd5}}, + {{0x38e851cb, 0x1539d080, 0x16463a4b, 0x066c8b9c, 0x32e38cb1, 0x0836cd7d, 0x22c463b7, 0x2af8b954, 0x18dd}}}, + /* 15*16^35*G: */ + {{{0x1d8ef686, 0x338ef8c1, 0x2272e66b, 0x23923d00, 0x266e53f6, 0x22976be0, 0x3cbe5223, 0x0b3b9610, 0x900f}}, + {{0x2121a8cf, 0x1ce9259f, 0x09156d50, 0x1b37fd0f, 0x09d11059, 0x31546c4d, 0x0425ad61, 0x30557b18, 0x732a}}} + }, + { + /* 1*16^36*G: */ + {{{0x1e6b80ef, 0x33ca7acf, 0x179424f3, 0x32f2e59f, 0x3cbdc571, 0x1503088e, 0x22ec8d23, 0x2783b8d9, 0xb645}}, + {{0x1a71ba45, 0x0c2fc2d8, 0x0e35b2ff, 0x2ceb9b52, 0x261db3c4, 0x2b7c5b95, 0x3e06de1d, 0x21db41bc, 0x067c}}}, + /* 3*16^36*G: */ + {{{0x319888e9, 0x0e73c9e4, 0x2448a8b4, 0x04ae9afc, 0x2681673d, 0x1834c0a5, 0x3a6e2dde, 0x3a9dceb0, 0x1f90}}, + {{0x2f113b79, 0x1bf7f25f, 0x19522e65, 0x0dd47fb9, 0x2b96a821, 0x054f49c7, 0x2a10e958, 0x0d9f0576, 0x89be}}}, + /* 5*16^36*G: */ + {{{0x3562222c, 0x217bedbc, 0x1e6f2c60, 0x00d11e64, 0x0b52bade, 0x00aeb4cd, 0x3e0ad6e7, 0x39537b7f, 0x13a4}}, + {{0x28200145, 0x32c59a32, 0x1c904c08, 0x3e715deb, 0x209a52d4, 0x2b0be075, 0x2e813b2c, 0x1f539605, 0xc9d6}}}, + /* 7*16^36*G: */ + {{{0x343b46bb, 0x0df93703, 0x2c925254, 0x3b4e98fe, 0x055dbd12, 0x01f01761, 0x0aadd1d4, 0x07afc8cf, 0x6199}}, + {{0x0c20a848, 0x123d6407, 0x12ecd8ef, 0x2a1ca729, 0x3badf11c, 0x3ce1c59b, 0x1e492952, 0x38c23cff, 0x01c5}}}, + /* 9*16^36*G: */ + {{{0x121add3b, 0x396f8f77, 0x1727d8f7, 0x26a513d1, 0x1626118b, 0x0e736c34, 0x3d387490, 0x2ba92de1, 0xea27}}, + {{0x368ce7dd, 0x2d78a476, 0x24e1be71, 0x2c84b5a3, 0x1c2f6278, 0x0f3ac8c9, 0x217de572, 0x3c79b90a, 0xc70f}}}, + /* 11*16^36*G: */ + {{{0x211ff757, 0x3a2be2ed, 0x04c226e6, 0x133a5d07, 0x22b6da9b, 0x0043e2db, 0x3fd54ba9, 0x144d5adf, 0x5946}}, + {{0x094d031a, 0x2299bb2a, 0x3bffe3b2, 0x06ef1edf, 0x0406f996, 0x00e34057, 0x32750042, 0x0d833977, 0x3611}}}, + /* 13*16^36*G: */ + {{{0x236160b5, 0x1d89628d, 0x0e7ebc06, 0x314fc91c, 0x091ec0cc, 0x0ebde5c0, 0x33290e84, 0x1b8e457d, 0x16b2}}, + {{0x18a1dc0e, 0x11897efd, 0x0ba3ef81, 0x0d8eab1c, 0x3654d4e1, 0x190d4918, 0x2ef8bb63, 0x159698c0, 0x060f}}}, + /* 15*16^36*G: */ + {{{0x37b32db8, 0x25934a24, 0x247791f3, 0x07b5d27d, 0x2cea85c9, 0x2850f210, 0x19f931be, 0x14a57115, 0x024b}}, + {{0x2a64f760, 0x25153eaa, 0x05b81a95, 0x2ada0448, 0x1e5be862, 0x38a08731, 0x3309c7b6, 0x3be3d6ff, 0x609f}}} + }, + { + /* 1*16^37*G: */ + {{{0x096943e8, 0x3b683d6d, 0x273c5a5d, 0x1bc7f19f, 0x0f06231d, 0x08d2a846, 0x3b840793, 0x20320a02, 0xd68a}}, + {{0x2b133120, 0x25321099, 0x045295a2, 0x039ee3de, 0x30e28b5b, 0x2c7e45de, 0x186d00c4, 0x2a7ffd2d, 0xdb8b}}}, + /* 3*16^37*G: */ + {{{0x0ca1c4f9, 0x16d0aa86, 0x2b7e2823, 0x13bf8d32, 0x1f16f44f, 0x02e0f698, 0x1728c4c4, 0x3de3c8af, 0x7815}}, + {{0x3778bc15, 0x2ac7a8da, 0x177d1e19, 0x2d0b7985, 0x18c35d5c, 0x24f3cc51, 0x1af6a7dd, 0x007a334e, 0xc1c6}}}, + /* 5*16^37*G: */ + {{{0x2e8c8530, 0x349b870f, 0x38f4d8e6, 0x0b7da07b, 0x2a6c6d51, 0x1df19005, 0x040176e3, 0x1cf3683b, 0xc392}}, + {{0x398446c7, 0x100c3c3d, 0x2eed715c, 0x3b7f2f68, 0x03199850, 0x074e5107, 0x33c8e9d0, 0x2f9095d0, 0x8c41}}}, + /* 7*16^37*G: */ + {{{0x237a26c1, 0x07c902ec, 0x0dbf6a53, 0x1b1b9630, 0x103b2516, 0x0890c707, 0x011b0275, 0x1d11fd61, 0xda31}}, + {{0x2cf74d6f, 0x1460dbb3, 0x3a81525f, 0x1a0db175, 0x19d8b7d3, 0x21059f09, 0x18c69d23, 0x25ee1fd7, 0x753b}}}, + /* 9*16^37*G: */ + {{{0x3739dc49, 0x0ad8a2a4, 0x2f55603d, 0x24e4b699, 0x3f231a23, 0x12b1422f, 0x30e6c106, 0x39b2c0ab, 0x6a4b}}, + {{0x32edd5cf, 0x39a8ae77, 0x14a4a4d3, 0x1f8ad32c, 0x3a8058ab, 0x059b8d83, 0x107597dc, 0x23ea8aa2, 0xf15d}}}, + /* 11*16^37*G: */ + {{{0x06987fac, 0x22fa2831, 0x0a86f679, 0x3243e190, 0x098a3c8b, 0x260980fb, 0x27f1344e, 0x31a7c4eb, 0x01f7}}, + {{0x19174c68, 0x3e479ce0, 0x1f6bc263, 0x1fd77886, 0x1ab6f9cb, 0x040db8ca, 0x1a22de5b, 0x330fcdbf, 0x9d4e}}}, + /* 13*16^37*G: */ + {{{0x36daba4d, 0x34ce86f5, 0x03196261, 0x197ec388, 0x3a2bcb9c, 0x018bb763, 0x3d381cb7, 0x25005d87, 0x557e}}, + {{0x37a52316, 0x04dd286e, 0x243590a5, 0x3a6e3d7e, 0x0cbc86c5, 0x0d73e857, 0x3a7e046d, 0x23ce9807, 0x7a7e}}}, + /* 15*16^37*G: */ + {{{0x29f5341a, 0x0e3d4bfc, 0x29636b80, 0x31e8cb19, 0x3101419c, 0x27503a9e, 0x085a93b2, 0x36a08666, 0x3ada}}, + {{0x2586c6cc, 0x1456024d, 0x05e8fbcb, 0x35b4b96d, 0x2b1017e9, 0x38d6fcda, 0x1369f552, 0x0788a266, 0xbfea}}} + }, + { + /* 1*16^38*G: */ + {{{0x028d3d5d, 0x0256603f, 0x3449cea4, 0x04abae5c, 0x3a30b096, 0x3009c241, 0x0804252d, 0x3b5f7d97, 0x324a}}, + {{0x16ab7c84, 0x19c892be, 0x23328439, 0x084ec31f, 0x2c1f4f19, 0x03030d6b, 0x21f2ff13, 0x0d95dd2d, 0x648a}}}, + /* 3*16^38*G: */ + {{{0x2fd53ed3, 0x17245d60, 0x1a56ccef, 0x0fdd3ee7, 0x1f7c4916, 0x3d82e4c7, 0x372ad5b8, 0x02f56659, 0x2084}}, + {{0x1a7a7132, 0x1c50ff94, 0x0e708998, 0x21f11ce5, 0x3afac254, 0x2f51da9a, 0x18243487, 0x0d25f3b0, 0xf299}}}, + /* 5*16^38*G: */ + {{{0x08a35b35, 0x2f4b2ed6, 0x00a121ed, 0x2d762297, 0x08ebfd1a, 0x0f40a796, 0x339bbbd1, 0x2ffd83ac, 0xe6b6}}, + {{0x1c1007bd, 0x15ca4f6e, 0x3e999c7c, 0x0edb274e, 0x1961ddfe, 0x3d0f8e0d, 0x0d2f3266, 0x3caf4cc0, 0x1a5f}}}, + /* 7*16^38*G: */ + {{{0x00360dd3, 0x353be34b, 0x050e2090, 0x2a2a0db6, 0x0ce3bb47, 0x02e021b8, 0x099b288b, 0x05dd16f9, 0xe053}}, + {{0x3c24f87b, 0x0abb3644, 0x0103dc2b, 0x2e61f7a6, 0x36a01461, 0x02560ad6, 0x12f39cd8, 0x0edc6976, 0xdc1c}}}, + /* 9*16^38*G: */ + {{{0x1098dfea, 0x3051998b, 0x2a678797, 0x372cf24b, 0x3a5e57fa, 0x23974aa0, 0x06c59e01, 0x0ece9de2, 0xa815}}, + {{0x2e6d892f, 0x2926a77d, 0x2daf4158, 0x2d783dd0, 0x053e03b1, 0x236e715e, 0x060fc53d, 0x0e591874, 0x2a47}}}, + /* 11*16^38*G: */ + {{{0x0bcecfa5, 0x29f9de92, 0x316bb020, 0x0358b686, 0x0eda3b2a, 0x11a5718e, 0x0addadeb, 0x30ecc3fb, 0x4f05}}, + {{0x15d37b53, 0x3b34092a, 0x01b48cd2, 0x1fb90c7c, 0x1534b944, 0x18c8d856, 0x1426fadd, 0x267a980f, 0x53a4}}}, + /* 13*16^38*G: */ + {{{0x084b96aa, 0x1879d964, 0x22abcce4, 0x0a618d54, 0x3b980ed0, 0x101786a8, 0x3a91be26, 0x26ae67d9, 0xd930}}, + {{0x02b28a86, 0x09b13cdf, 0x3cfe978f, 0x2db27eeb, 0x34cb5fd3, 0x043c1989, 0x2c557d7e, 0x26caa6d3, 0x6ef9}}}, + /* 15*16^38*G: */ + {{{0x1f8fcf0e, 0x3dee3416, 0x3c4a6fac, 0x16dbff79, 0x2a3411d6, 0x30d11b7a, 0x22d35ba9, 0x1f284e15, 0x7d58}}, + {{0x18bc9459, 0x00706827, 0x323780a5, 0x18e402b4, 0x3d6ad0c4, 0x0d002db3, 0x04c61272, 0x1700e20c, 0xa729}}} + }, + { + /* 1*16^39*G: */ + {{{0x3d054c96, 0x3a2f4dcf, 0x0d1ca888, 0x31050eea, 0x3ee5dcee, 0x077f6f97, 0x1e61f6d5, 0x30524673, 0x4df9}}, + {{0x0ad10d5d, 0x0baeb01b, 0x28849019, 0x3541b370, 0x1d85d4b5, 0x25d308e8, 0x18728050, 0x3b14424b, 0x0035}}}, + /* 3*16^39*G: */ + {{{0x1def001d, 0x13c89769, 0x09ba27ef, 0x3e6ef5a6, 0x23b64b21, 0x02f47027, 0x22caf20e, 0x28cb6c9f, 0xa549}}, + {{0x30624783, 0x3576c69f, 0x2c9705ad, 0x05078a98, 0x259456eb, 0x330c3b62, 0x166cbdf4, 0x1e9e41b6, 0x799b}}}, + /* 5*16^39*G: */ + {{{0x052ed4cb, 0x16bbc797, 0x009ec5a0, 0x1537becf, 0x132e6ec9, 0x022f660d, 0x3ecd123f, 0x23cc3681, 0x7e79}}, + {{0x14bb9462, 0x15c5981e, 0x39f37a12, 0x1cd5c6ff, 0x32f057b1, 0x2a55277b, 0x1ac83041, 0x33312893, 0xd23d}}}, + /* 7*16^39*G: */ + {{{0x13630834, 0x37ce83ef, 0x3dac067f, 0x18fc4a18, 0x0c810884, 0x2e7a5aea, 0x14783ad5, 0x28800c54, 0x224f}}, + {{0x047a2272, 0x34f11cdf, 0x0a50f75c, 0x18a493b0, 0x1d09f53d, 0x2dc3e8e4, 0x2da5c3c4, 0x138caecf, 0xbbe5}}}, + /* 9*16^39*G: */ + {{{0x183c19d7, 0x19d92745, 0x02cf57bb, 0x2ed7916b, 0x228ef2bb, 0x28973390, 0x239e4129, 0x28331802, 0xc2d4}}, + {{0x0507928d, 0x0bca2e0b, 0x3345c977, 0x2012a0c5, 0x01260d26, 0x20ed7dfd, 0x06294d41, 0x283e7020, 0x65ad}}}, + /* 11*16^39*G: */ + {{{0x3c940c9a, 0x13202b52, 0x2f423308, 0x33cf384e, 0x0ddc2113, 0x161789d1, 0x1f3190e5, 0x0a9fb0c1, 0x2ec2}}, + {{0x051e7a4d, 0x34653f66, 0x1a35bdac, 0x101460f6, 0x1c7feb12, 0x3893d40a, 0x379684c2, 0x291a378c, 0x8b1d}}}, + /* 13*16^39*G: */ + {{{0x1d683eeb, 0x29c3b97f, 0x08d3133a, 0x0dbace28, 0x04b8f33e, 0x2bd94942, 0x28cecab1, 0x1a5ce3e6, 0xafc6}}, + {{0x30cd4509, 0x078a72ac, 0x1eddfdc9, 0x02ead549, 0x239c1657, 0x1671ff28, 0x22752bc3, 0x0865db74, 0x002c}}}, + /* 15*16^39*G: */ + {{{0x376f4293, 0x28807e1e, 0x13c5139e, 0x3a5e2d59, 0x0b282e10, 0x2f233cdc, 0x03309121, 0x1ed6a7cd, 0xd255}}, + {{0x1282740a, 0x36c61e89, 0x2405a5f1, 0x12da0e37, 0x0ad21fe3, 0x20bc1bad, 0x027f0126, 0x2cd0d579, 0xa787}}} + }, + { + /* 1*16^40*G: */ + {{{0x2c1f98cd, 0x2ff26722, 0x17f0308c, 0x0d224153, 0x06602152, 0x362a7073, 0x34870fae, 0x066a1291, 0x9c39}}, + {{0x14fc599d, 0x39f9780f, 0x064c8e6b, 0x14c9bddb, 0x20e64190, 0x3c112fc9, 0x1dd57584, 0x13c3d293, 0xddb8}}}, + /* 3*16^40*G: */ + {{{0x0fb64db3, 0x1ee6354e, 0x1dd53841, 0x3b79328e, 0x13b8d6a7, 0x2ee0fef9, 0x1ccb740b, 0x08e48a6f, 0xc114}}, + {{0x3c0259be, 0x08c33a7f, 0x14567d1e, 0x1d602413, 0x178bd1a8, 0x3b3793fa, 0x06fc2a5c, 0x3db716d2, 0x1237}}}, + /* 5*16^40*G: */ + {{{0x03081e46, 0x3b7b60d0, 0x14559ea1, 0x14886315, 0x2634713a, 0x3670b064, 0x37224082, 0x12fe0c69, 0x6c5b}}, + {{0x0bfbcd70, 0x347e72e0, 0x2c22a62e, 0x3433e09a, 0x2be47841, 0x11e18f38, 0x2d42fb23, 0x04dc5249, 0xcb05}}}, + /* 7*16^40*G: */ + {{{0x064dcd4b, 0x32b96bb1, 0x111c124d, 0x0c31f566, 0x310a450c, 0x1c19972a, 0x0ade4b56, 0x2a1599c3, 0xe1e9}}, + {{0x3b041f2c, 0x342d897a, 0x0a16b292, 0x113466ab, 0x2577927f, 0x310d666c, 0x1c531b7a, 0x02a55115, 0x562b}}}, + /* 9*16^40*G: */ + {{{0x2badd73c, 0x0161dbf8, 0x2a64b7d0, 0x36737640, 0x1c14208f, 0x29d390bb, 0x1b099778, 0x0695eb44, 0x51b2}}, + {{0x2b36d8d1, 0x3df52b87, 0x0c734ba6, 0x0804c3ca, 0x2c1cfa6c, 0x281fc074, 0x3d3e5d54, 0x0c040007, 0x0079}}}, + /* 11*16^40*G: */ + {{{0x3b09f34b, 0x35d742dc, 0x0cc66ce6, 0x221cf982, 0x339d61e5, 0x2d8a5bcf, 0x0b79861a, 0x3ce98ec7, 0x9701}}, + {{0x00df5793, 0x33721433, 0x3dcc794a, 0x012f0e5f, 0x16833771, 0x00c6d4c5, 0x30ed15d7, 0x12eee32b, 0x3dd4}}}, + /* 13*16^40*G: */ + {{{0x3f1e2f46, 0x1739888e, 0x32778301, 0x1c3dc7a1, 0x163c5752, 0x164b8103, 0x266cc445, 0x2d074b27, 0xa036}}, + {{0x1effb349, 0x1cc789a5, 0x3f0b1f4f, 0x2038a0b3, 0x1eb08d06, 0x07daa91e, 0x16b3d7df, 0x246800fa, 0xc3bf}}}, + /* 15*16^40*G: */ + {{{0x0c4cea08, 0x3362e40e, 0x20ea21db, 0x12d62e83, 0x00465265, 0x298454d0, 0x28c506f4, 0x3eb6ea93, 0x6a85}}, + {{0x1862f4f3, 0x0677b396, 0x3d721b6a, 0x09c692d0, 0x3e6230b4, 0x24cf0523, 0x0659d531, 0x11812eb9, 0x00b6}}} + }, + { + /* 1*16^41*G: */ + {{{0x20a959e5, 0x2884e084, 0x391d4cc5, 0x38524ea2, 0x0e06bb91, 0x017ca076, 0x12fdf8de, 0x05c2c774, 0x6057}}, + {{0x2385a2a8, 0x2266fa4c, 0x2e24c65e, 0x1454af0f, 0x1df26246, 0x268b6bdc, 0x24807add, 0x3c2c9a9a, 0x9a1a}}}, + /* 3*16^41*G: */ + {{{0x171c032b, 0x3536858a, 0x3afdc980, 0x1ad9a285, 0x0766c5ff, 0x046d7f7f, 0x002603dd, 0x2a3f35b8, 0x71eb}}, + {{0x1668359f, 0x1ead6a38, 0x34b4755e, 0x24c6b45d, 0x0cbb7f71, 0x18145bd5, 0x1d39def6, 0x049892d8, 0xd2ff}}}, + /* 5*16^41*G: */ + {{{0x2a03a61c, 0x01b91d14, 0x1070574d, 0x1e1a3d1a, 0x2a9dd050, 0x05d10aea, 0x09d232ca, 0x30c16cc9, 0x855e}}, + {{0x065dfc07, 0x37f1baab, 0x17e44965, 0x0cbdd3a8, 0x02fb4ed3, 0x0f2ffe6d, 0x01c17f54, 0x174bb17c, 0x0dd8}}}, + /* 7*16^41*G: */ + {{{0x1f32d706, 0x00302920, 0x06a0678b, 0x0633291d, 0x15bfa206, 0x034a68c2, 0x3fbf1f15, 0x121aaeac, 0x3ce4}}, + {{0x3c7fd9e4, 0x02dcd8df, 0x161e89f4, 0x345590f3, 0x094906ed, 0x3f411ac4, 0x3785288e, 0x10236ab8, 0xe775}}}, + /* 9*16^41*G: */ + {{{0x391cd3fb, 0x36d032ed, 0x329be686, 0x0a8cff65, 0x0844eb4a, 0x380c863e, 0x237faf02, 0x31450fd3, 0x11cc}}, + {{0x15160d86, 0x24dc5ae9, 0x0dd3472a, 0x02c7bf4b, 0x0cc239fa, 0x2389124e, 0x311deb52, 0x1acaa40a, 0x4aa5}}}, + /* 11*16^41*G: */ + {{{0x218f7552, 0x21ee4465, 0x0054fac3, 0x1044e2e6, 0x2382ddbd, 0x25ddd3e0, 0x09c6f43b, 0x2ec5f945, 0x0250}}, + {{0x3510b14d, 0x3c212588, 0x33d6f1e3, 0x001bcf0c, 0x29d817da, 0x35f7dd7f, 0x28082342, 0x0c3f26ef, 0x7319}}}, + /* 13*16^41*G: */ + {{{0x1f725d12, 0x1744fa4e, 0x0b5f4750, 0x1190aef7, 0x022fbfd9, 0x28e73828, 0x27fd3ab4, 0x27222cd1, 0x1a74}}, + {{0x23ac56e4, 0x04d94534, 0x190daa70, 0x1c821a62, 0x2f3d8f60, 0x22f9d70a, 0x00e2cf45, 0x34655cfb, 0x7e91}}}, + /* 15*16^41*G: */ + {{{0x29fae458, 0x18412394, 0x26ec97fd, 0x0297109d, 0x3b7b328b, 0x3455a977, 0x0218c109, 0x1a16f83e, 0xc750}}, + {{0x1757b598, 0x005a1065, 0x35951a2b, 0x1772940c, 0x32c7b40a, 0x0bd05319, 0x21e05fb5, 0x257e33e4, 0xead7}}} + }, + { + /* 1*16^42*G: */ + {{{0x2cb94266, 0x069a5cfb, 0x3d4df12b, 0x33bc3ee9, 0x0da31880, 0x10e69146, 0x08411421, 0x37e388e8, 0xa576}}, + {{0x21b28ec8, 0x3a2f846b, 0x114d9f3e, 0x0b8429fd, 0x0cd82c43, 0x2e5ebf96, 0x240b2c92, 0x2fc839d9, 0x40a6}}}, + /* 3*16^42*G: */ + {{{0x0d9ed6c1, 0x1a2bad63, 0x3d593d6b, 0x139d16f0, 0x1edd0ec2, 0x3f061dc1, 0x0f53e80b, 0x0cdb72dd, 0x0328}}, + {{0x38fafeee, 0x3b1baf9b, 0x1cb494ad, 0x16fd37c9, 0x0d7c8c26, 0x35650e88, 0x19f28c46, 0x260e04bf, 0x71a8}}}, + /* 5*16^42*G: */ + {{{0x3235983a, 0x066a6a34, 0x13bceb29, 0x22840dc0, 0x3e1531e3, 0x0e49b5c3, 0x11c54dc6, 0x13aba2e4, 0xce4f}}, + {{0x0d3cdecf, 0x33f5ac64, 0x2bf740ae, 0x1b1948a3, 0x30754352, 0x37809279, 0x0fbbb3ea, 0x3e5cf0e4, 0xf3c9}}}, + /* 7*16^42*G: */ + {{{0x15b0e6c9, 0x1b6aad99, 0x06e4c89a, 0x17fe73de, 0x38bcbddb, 0x0a3ecdb7, 0x0622278e, 0x2fe952e6, 0x4dbe}}, + {{0x1eb2cc25, 0x2529e155, 0x0504efae, 0x24c46caf, 0x2229f358, 0x2989b9b8, 0x13aedf45, 0x39ec0f24, 0x10fe}}}, + /* 9*16^42*G: */ + {{{0x25857295, 0x13806846, 0x3433f016, 0x32391fc0, 0x1ca12069, 0x38463f28, 0x05c218b2, 0x0902ffbd, 0xa42a}}, + {{0x0a7eb9c1, 0x1acddffb, 0x15193955, 0x28708b34, 0x1da4c427, 0x1ac8ac93, 0x05d4567a, 0x2cfc9840, 0x3aa0}}}, + /* 11*16^42*G: */ + {{{0x2fcdc098, 0x0883fd55, 0x2e468032, 0x02b803da, 0x0499c155, 0x3c7e1b03, 0x322267a7, 0x0acbe5be, 0x34e1}}, + {{0x2a7474e2, 0x132c6b79, 0x19883f66, 0x37d44c3c, 0x3972db04, 0x132f2105, 0x1d322d97, 0x30b775ed, 0xa64a}}}, + /* 13*16^42*G: */ + {{{0x0f173b92, 0x335bad7a, 0x29fb7611, 0x1f9cbd05, 0x0d65683b, 0x0c68863d, 0x391f29be, 0x3490366e, 0x10f4}}, + {{0x233146c2, 0x240801b5, 0x086adb7c, 0x2edda745, 0x3908ba90, 0x2c96968c, 0x353ad211, 0x0b654245, 0x850e}}}, + /* 15*16^42*G: */ + {{{0x28d84958, 0x39bf4766, 0x0acc5cae, 0x0477ac5b, 0x00cc866a, 0x066e5db5, 0x277e749f, 0x3a02da6d, 0xe846}}, + {{0x3882cf9f, 0x031191ed, 0x1e0c1a64, 0x1468cd9c, 0x18b76fad, 0x2f64411e, 0x07e2541d, 0x2e3f2253, 0xa29c}}} + }, + { + /* 1*16^43*G: */ + {{{0x3e58ad71, 0x3dd8e226, 0x39a3a208, 0x0c347d73, 0x1e8c38bb, 0x17fa58a7, 0x2c3e30a0, 0x29e30a37, 0x7778}}, + {{0x3d9f43ac, 0x2d44ff07, 0x324ac563, 0x2ce1047f, 0x3f580087, 0x26384bcb, 0x1b22ff70, 0x1b66ad69, 0x3462}}}, + /* 3*16^43*G: */ + {{{0x3319c869, 0x3df1bab8, 0x21eb2702, 0x2a7e575d, 0x0cacdc18, 0x20e408bf, 0x33fc8d01, 0x01176605, 0x3018}}, + {{0x12b856f0, 0x3031db27, 0x23d9a7bf, 0x0aa13292, 0x222e3bca, 0x1890c835, 0x3b7b6f86, 0x315e0940, 0xac5f}}}, + /* 5*16^43*G: */ + {{{0x25ed29b5, 0x319a61be, 0x12add1b4, 0x20c2d81c, 0x23c885f5, 0x2d9f6e69, 0x17ef343a, 0x206d87b9, 0x3228}}, + {{0x3cd15ad2, 0x3d3c49b9, 0x0ee7604e, 0x20ebaae5, 0x1531e1ca, 0x02c677d0, 0x0344eb11, 0x00a105e8, 0x1677}}}, + /* 7*16^43*G: */ + {{{0x06c96100, 0x2fea101e, 0x2e9c8e63, 0x18c046a9, 0x33dbcca1, 0x0f766cb7, 0x31b9ffb4, 0x11ceb03e, 0x3f38}}, + {{0x32624707, 0x078ab06f, 0x375f1bcf, 0x15c71f02, 0x079ce566, 0x131118bc, 0x00395253, 0x27157d75, 0x70c6}}}, + /* 9*16^43*G: */ + {{{0x3d22d2ac, 0x0d31bb1b, 0x1caace02, 0x377f849b, 0x05df2f10, 0x0f03825e, 0x3a76dcb4, 0x04f17f49, 0x2881}}, + {{0x0f42a268, 0x207ad57e, 0x148c8fd0, 0x30f51285, 0x176137dd, 0x1ddc9832, 0x3c5c8f20, 0x3ac0563e, 0xa1a7}}}, + /* 11*16^43*G: */ + {{{0x245f8ea8, 0x12ea0374, 0x24d2900d, 0x1c9238e5, 0x119fe5d1, 0x3d36575c, 0x23a2a553, 0x28803211, 0xf963}}, + {{0x19bc99eb, 0x2f157ec1, 0x18b60824, 0x2e3c8d67, 0x3427208b, 0x1c88c07f, 0x383c0a3b, 0x2509a31f, 0x9c85}}}, + /* 13*16^43*G: */ + {{{0x2606a315, 0x386a20c4, 0x26963ad9, 0x1c981cbc, 0x0e097e40, 0x362ca964, 0x0d9a7f98, 0x08933fdc, 0xa5d9}}, + {{0x1e3b68d1, 0x0d584cd6, 0x111a7c9d, 0x13434d1f, 0x180de9ed, 0x0c1aaf5e, 0x0da5b343, 0x22c00ec8, 0x8732}}}, + /* 15*16^43*G: */ + {{{0x06231493, 0x336ded50, 0x0cc4d469, 0x1046a0c3, 0x25e6a496, 0x13907403, 0x3c3604eb, 0x260b86dc, 0xf1fe}}, + {{0x358848c1, 0x25aa6699, 0x25ff0d01, 0x1cfecd1b, 0x3d99d3f1, 0x34f0817d, 0x24ddc216, 0x067abb66, 0x2e20}}} + }, + { + /* 1*16^44*G: */ + {{{0x06d903ac, 0x027b6a70, 0x1ad7e5cb, 0x3e589d39, 0x3afd2ed5, 0x0a7f4c39, 0x3a844637, 0x2557b98d, 0x0928}}, + {{0x1bcd091f, 0x14603a4d, 0x0a8d83fc, 0x0f49bbea, 0x3a95eeac, 0x1e284c24, 0x342a827b, 0x08400f4f, 0xc256}}}, + /* 3*16^44*G: */ + {{{0x3874b839, 0x0444a1d5, 0x13d2b418, 0x10456ce5, 0x30b6aebe, 0x37c37ec8, 0x1e5a8053, 0x2e07f038, 0x3e03}}, + {{0x3c0594ba, 0x03073959, 0x1ab5b8da, 0x39717c3f, 0x198f667d, 0x3d981d5c, 0x07f42c44, 0x3858f7fc, 0xd13a}}}, + /* 5*16^44*G: */ + {{{0x0357a513, 0x28fde39a, 0x1b3023f3, 0x146f44d1, 0x2922c5f1, 0x3e8a0ea8, 0x0492cd62, 0x302de8bd, 0xe662}}, + {{0x2017d07e, 0x24a88072, 0x1538d891, 0x00d73589, 0x21a419d8, 0x2b882284, 0x2452305d, 0x064f3984, 0xab0b}}}, + /* 7*16^44*G: */ + {{{0x1f37d242, 0x2657dfbf, 0x39c14b04, 0x27fb2981, 0x23587dc2, 0x218b1f2f, 0x0f6cb843, 0x202c7253, 0x40bf}}, + {{0x26405088, 0x347609e6, 0x2bd35583, 0x0c87ae90, 0x26fe1274, 0x0ffa6c6c, 0x2aaf04f5, 0x374d7615, 0xb579}}}, + /* 9*16^44*G: */ + {{{0x195a3558, 0x2bcacd91, 0x234a7f2b, 0x01c7e178, 0x1b59f6ac, 0x3e5e04e3, 0x1ca70806, 0x3fa5d807, 0x3d14}}, + {{0x2443df4c, 0x1ab6ceb1, 0x3c1d727c, 0x3828b851, 0x356e1482, 0x26a4c76f, 0x281ef8f2, 0x2f75ba11, 0x16c6}}}, + /* 11*16^44*G: */ + {{{0x02b1fc24, 0x37a7d6b6, 0x23f7570e, 0x0a36071f, 0x12486525, 0x06b134b2, 0x265251cc, 0x29503a0b, 0xdd6f}}, + {{0x0e9b74ca, 0x290c7118, 0x17322304, 0x04379afb, 0x257e77ec, 0x1bc7afc5, 0x3186fe36, 0x0adfac74, 0x67e6}}}, + /* 13*16^44*G: */ + {{{0x3dd08e02, 0x07aa4564, 0x1adf0288, 0x2151edff, 0x3d1e8010, 0x1a5266a8, 0x15d780f8, 0x0b6a0b79, 0x13fa}}, + {{0x3cb03410, 0x29550770, 0x1a42b97d, 0x112beec6, 0x3432c7e6, 0x0d5881ae, 0x1da72313, 0x0e2c1155, 0x1363}}}, + /* 15*16^44*G: */ + {{{0x144ee41a, 0x308ceae6, 0x37d69a6a, 0x26d5b74e, 0x06828287, 0x3042d9cb, 0x30a443f7, 0x121474f1, 0xd06c}}, + {{0x0b295e6f, 0x3c7e13a6, 0x162ee252, 0x1ee10d18, 0x3630919b, 0x02b353d3, 0x0d0adbbb, 0x3f530161, 0x5815}}} + }, + { + /* 1*16^45*G: */ + {{{0x23d82751, 0x1eab9d45, 0x3ad35452, 0x116d2a41, 0x23b28556, 0x0193ce83, 0x1b109399, 0x3fbcfb1b, 0x85d0}}, + {{0x0eb1f962, 0x0b08de89, 0x07733158, 0x21d47a5a, 0x2cf5663e, 0x3525b960, 0x38c0be29, 0x192104e8, 0x1f03}}}, + /* 3*16^45*G: */ + {{{0x2cde4cf3, 0x26554187, 0x38a066ab, 0x10394d51, 0x1d9ae793, 0x30b49b45, 0x022c3be7, 0x2ad2b045, 0x384d}}, + {{0x252d0566, 0x1f1e5ac8, 0x351ba73b, 0x10c28ce5, 0x34c6f01f, 0x13b5b68a, 0x1ca43bfb, 0x316f346e, 0xd6e3}}}, + /* 5*16^45*G: */ + {{{0x1e5238c2, 0x22bcfa48, 0x00ecb8b9, 0x0d57d70e, 0x02ed4840, 0x05842d3a, 0x015aa41b, 0x3b03adf5, 0x14f0}}, + {{0x12f07922, 0x3a1a8d1e, 0x304939d6, 0x17003600, 0x02747fd2, 0x3f1cf8e1, 0x35d80921, 0x354f7520, 0xab12}}}, + /* 7*16^45*G: */ + {{{0x1543e94d, 0x3d8d4bbf, 0x2f98e188, 0x04c0a9d5, 0x1a0ddadd, 0x30d19e29, 0x0287ec41, 0x3ceede0b, 0xeb42}}, + {{0x05924d89, 0x01567791, 0x20d6d424, 0x3611a379, 0x0dfb774c, 0x03755cbf, 0x1d92dc9a, 0x1b41d3c9, 0x234a}}}, + /* 9*16^45*G: */ + {{{0x3e19aaed, 0x0c9396d5, 0x06673270, 0x26eb37a3, 0x06a92045, 0x3b00bdb8, 0x020d9a9e, 0x0e32945a, 0x1cf1}}, + {{0x292f400e, 0x04dba975, 0x3c77ffbc, 0x27bbe3fb, 0x2dde1747, 0x0dca99ad, 0x063865f4, 0x36bcc5c7, 0xd6ff}}}, + /* 11*16^45*G: */ + {{{0x36a8aa39, 0x3db03a7e, 0x278fac55, 0x2998ded2, 0x1990d937, 0x16825a12, 0x0d412c87, 0x21af97d0, 0xb586}}, + {{0x2b493c1f, 0x3f1e4d74, 0x2db347b8, 0x2f6be639, 0x00a91dab, 0x11e35153, 0x38c2c149, 0x3550c931, 0x5632}}}, + /* 13*16^45*G: */ + {{{0x303b4cc5, 0x3a47af8e, 0x21c77c2e, 0x0a0c6e96, 0x33a80257, 0x16f13f9f, 0x3cc2b67b, 0x276c1ae2, 0x5fc1}}, + {{0x25b57c28, 0x0ece7ee1, 0x0087ec4a, 0x1dbd40f3, 0x3a5ef492, 0x084e3e68, 0x0c7c66ee, 0x21303b26, 0xec8e}}}, + /* 15*16^45*G: */ + {{{0x0cb38cb5, 0x2d2e15f5, 0x1388948b, 0x02dff7d3, 0x3eea1be1, 0x2a2903f4, 0x1e289deb, 0x2dc350bb, 0xb88f}}, + {{0x1965f3d7, 0x1efe9d59, 0x3af8c719, 0x13cf8489, 0x35a8e24d, 0x12ee652c, 0x23280603, 0x0dab51ba, 0xd6c7}}} + }, + { + /* 1*16^46*G: */ + {{{0x0526087e, 0x3d501209, 0x2da20308, 0x3edb6220, 0x18b85dfd, 0x26d8105e, 0x2ce97c1c, 0x0373a5fb, 0xff2b}}, + {{0x30c29907, 0x32547807, 0x10e2ceb2, 0x2dfb5bee, 0x107936c7, 0x13137153, 0x0ba188af, 0x04ffbd49, 0x493d}}}, + /* 3*16^46*G: */ + {{{0x39d681f9, 0x164153f9, 0x08feb9fc, 0x3383bbeb, 0x2c94b066, 0x1ffc9780, 0x3230888b, 0x3f7c9dd7, 0xc745}}, + {{0x3bbb1247, 0x00c5cd0d, 0x27d45c76, 0x36f4cd71, 0x2818678c, 0x04e531c3, 0x1e5e78a7, 0x08bcbdae, 0x5902}}}, + /* 5*16^46*G: */ + {{{0x35cd0ea3, 0x38133bb4, 0x0cac4815, 0x111e3a08, 0x32e7f2b3, 0x16797ad9, 0x1050b27a, 0x1e7cea5d, 0xabb2}}, + {{0x3c307bce, 0x1c24c4cd, 0x202f3b64, 0x25da4167, 0x078ed47c, 0x12f8300c, 0x3970d9fb, 0x040eefc5, 0x5dee}}}, + /* 7*16^46*G: */ + {{{0x1bc9ee3e, 0x30b8bcfc, 0x3e7382c5, 0x27e86a58, 0x27ed11ea, 0x2baa9d09, 0x0682827f, 0x0542d67f, 0x3f81}}, + {{0x199aae06, 0x33ab6c31, 0x0da81603, 0x08ecb73f, 0x39566276, 0x06facf11, 0x3a82d467, 0x229a3f6f, 0x19c8}}}, + /* 9*16^46*G: */ + {{{0x38e4a007, 0x05c6fbeb, 0x0bb358b6, 0x3b3bb3c2, 0x16c7ec15, 0x12e8cea9, 0x02de6959, 0x04cb7402, 0x5cf8}}, + {{0x1068b883, 0x398fc242, 0x39c7fe8c, 0x251be5b1, 0x0c3df6c8, 0x35056212, 0x1fa0df4a, 0x3b970358, 0xb45a}}}, + /* 11*16^46*G: */ + {{{0x26c2d4a7, 0x255bf9ec, 0x3cfffb10, 0x30dbe4ce, 0x004ed21b, 0x38ce5cf1, 0x3a494653, 0x3f934352, 0xb6d5}}, + {{0x3ae86371, 0x063739f8, 0x35e3cc81, 0x16df939b, 0x3ffd8e74, 0x33e48277, 0x3d6c14df, 0x1ce84eae, 0x47f3}}}, + /* 13*16^46*G: */ + {{{0x3c66dd33, 0x024cd88b, 0x1dc76dc5, 0x23ef23fc, 0x29b022ea, 0x2c6c5400, 0x3588706b, 0x2ef019b3, 0x61c8}}, + {{0x36f10bfa, 0x0eeea7ce, 0x2820c8ca, 0x1441bab0, 0x05d3fb6a, 0x1a6652e6, 0x0f703446, 0x2788e795, 0x9359}}}, + /* 15*16^46*G: */ + {{{0x1d6b2ff8, 0x2016df33, 0x286c8fa9, 0x18cdb05c, 0x03bdf187, 0x27d4dcfb, 0x2785187c, 0x0ae95d09, 0x94e3}}, + {{0x2ce1af3e, 0x37521554, 0x26bfe13a, 0x0ebc1094, 0x2d9e8cb3, 0x07922198, 0x204e192f, 0x1122d0f6, 0x0d1b}}} + }, + { + /* 1*16^47*G: */ + {{{0x3856e241, 0x203978b3, 0x0d6dd287, 0x3c7b8523, 0x1b212b57, 0x0acb98c0, 0x080ea9ed, 0x2ef92c7a, 0x827f}}, + {{0x2ec293ec, 0x1816da2e, 0x2903166d, 0x3de98c61, 0x1d12687f, 0x3bcb19f4, 0x27b0b71b, 0x27248f1c, 0xc60f}}}, + /* 3*16^47*G: */ + {{{0x3bb80fa7, 0x0d12172c, 0x30413886, 0x29f69aed, 0x20819f3a, 0x0681af4c, 0x0c2fbc0d, 0x38c7d8c2, 0x0857}}, + {{0x09366b2d, 0x3660847c, 0x0d7016ab, 0x0b8dc10f, 0x0b714717, 0x1f327477, 0x0172092d, 0x24d08eb8, 0xf643}}}, + /* 5*16^47*G: */ + {{{0x09c70e63, 0x1740b0e8, 0x353d496f, 0x2ee2de39, 0x0a672e9c, 0x171955d9, 0x16004354, 0x333a95af, 0x28aa}}, + {{0x3057da4e, 0x27c0e20b, 0x04da1e8b, 0x3f167391, 0x28ebb7f5, 0x22599f1d, 0x20e1567a, 0x0c8bbe06, 0x2b69}}}, + /* 7*16^47*G: */ + {{{0x33e674b5, 0x007714bd, 0x3060aac6, 0x363da739, 0x2b8a4f92, 0x36cb26f3, 0x1a66145d, 0x2d896815, 0xa2f3}}, + {{0x0e937941, 0x024e3238, 0x033fa53b, 0x08be8c5f, 0x2a7c4b92, 0x112a43cc, 0x068ae800, 0x28565853, 0x620e}}}, + /* 9*16^47*G: */ + {{{0x191eb056, 0x1d8058c7, 0x2cfd386c, 0x00bbf6e3, 0x3515f5a0, 0x22d71a8f, 0x259231d9, 0x20f27aab, 0x3c4f}}, + {{0x205cecab, 0x109624f6, 0x1cf6b877, 0x20ad5120, 0x32788019, 0x3595cf0e, 0x28b6a33a, 0x2401d452, 0x9447}}}, + /* 11*16^47*G: */ + {{{0x3d86dfa9, 0x24187f6e, 0x1b993a71, 0x0e2d2902, 0x103baadc, 0x30780fa0, 0x167d4e29, 0x384a22a6, 0xaff8}}, + {{0x01d12681, 0x1c40f0db, 0x019f9c70, 0x045b6a51, 0x0f53f4f9, 0x0faea87f, 0x37c3fd3d, 0x12ecc84d, 0x8d8b}}}, + /* 13*16^47*G: */ + {{{0x189ba9c1, 0x23c9cdae, 0x09d338e2, 0x03df2968, 0x0ee579e4, 0x16098abb, 0x000b3e84, 0x1e114a37, 0xd3fb}}, + {{0x2b51b267, 0x186e237f, 0x011ade00, 0x073b7570, 0x370fe634, 0x32815d62, 0x2b4e7ca7, 0x350d3be9, 0xf894}}}, + /* 15*16^47*G: */ + {{{0x0f2bb909, 0x36a5b074, 0x3598d999, 0x24409f14, 0x187d7f63, 0x1ca620e4, 0x1aa88ff4, 0x0c0382b2, 0x4ec9}}, + {{0x24cf4071, 0x2228e0fe, 0x1ac3827b, 0x0b85a083, 0x0c49bad5, 0x03711461, 0x304dc5c8, 0x2841af86, 0x782b}}} + }, + { + /* 1*16^48*G: */ + {{{0x2120e2b3, 0x3ced63e8, 0x347f9aa7, 0x163f739f, 0x26e5217a, 0x392b8d33, 0x1bdbae7b, 0x127c87d4, 0xeaa6}}, + {{0x3a5ad93d, 0x11e94c16, 0x13f7e59d, 0x29ae597c, 0x39aa5a01, 0x2a03e261, 0x3b03ac69, 0x1e7b56ee, 0xbe32}}}, + /* 3*16^48*G: */ + {{{0x3f2e070d, 0x160ff4e8, 0x12a6a98f, 0x2aadc731, 0x1047e229, 0x1cc70ee1, 0x34abff48, 0x297a410b, 0x4b72}}, + {{0x296dd780, 0x112ea0bb, 0x2948c3de, 0x2d197774, 0x0f3c10b0, 0x1deecdb4, 0x2e1cf602, 0x0753875a, 0x599e}}}, + /* 5*16^48*G: */ + {{{0x0a02591c, 0x2739ff61, 0x05125a1e, 0x3d526596, 0x21fd613e, 0x1afefad7, 0x1c8e285a, 0x24ff194e, 0xa9fc}}, + {{0x29bec2dc, 0x242b77bd, 0x3cf72537, 0x22231057, 0x1165e5ca, 0x1305e86a, 0x387173e8, 0x39ce7714, 0x9c2c}}}, + /* 7*16^48*G: */ + {{{0x2d968b59, 0x0401b838, 0x3cbbc2e1, 0x28a2eb84, 0x1b027709, 0x35eb0482, 0x39f0a6a7, 0x005f069b, 0xc940}}, + {{0x0de572fb, 0x3bf5d902, 0x390c9c8f, 0x210b2d90, 0x35742ce2, 0x2286fe96, 0x3862013b, 0x08940326, 0x39d9}}}, + /* 9*16^48*G: */ + {{{0x326b3332, 0x0a1cccd5, 0x3ee5de6a, 0x00e2341c, 0x0bf8e031, 0x1e4e97dc, 0x10024ec6, 0x2ee75fbb, 0x1f84}}, + {{0x14e8d52e, 0x1510a28c, 0x36dc3a25, 0x2f338b50, 0x39edf0c2, 0x1f09fdd6, 0x29ecc254, 0x1b41caf2, 0xee72}}}, + /* 11*16^48*G: */ + {{{0x0defa98e, 0x336a952b, 0x1ac27995, 0x12111a04, 0x11e9c772, 0x2055ece6, 0x1fcd06ca, 0x38224251, 0x0f13}}, + {{0x3e286767, 0x0229dda6, 0x2ceaccdc, 0x1f9c1785, 0x3362db28, 0x0fe2c29e, 0x27c5035e, 0x087c5d93, 0xadd5}}}, + /* 13*16^48*G: */ + {{{0x29f59b6b, 0x178700ef, 0x1888e2fa, 0x2ce318f0, 0x1826d3e9, 0x0a2874b5, 0x1ec7db37, 0x24695477, 0xdde1}}, + {{0x26cb1410, 0x1ab658a4, 0x3154fecf, 0x15ce2ef9, 0x12e14e8b, 0x1d5f5871, 0x275cbe0a, 0x3ede00a0, 0x5b2b}}}, + /* 15*16^48*G: */ + {{{0x09c6b699, 0x1a3157f7, 0x3e46871b, 0x1bd5cd5a, 0x341682a8, 0x1b5efe5e, 0x36f7a5a1, 0x004bbb60, 0x5fab}}, + {{0x01c6c3aa, 0x05cc854b, 0x2883519b, 0x2ac45ffa, 0x162f7b90, 0x2ed044c3, 0x3d144e9e, 0x3e9c28f0, 0x2d9b}}} + }, + { + /* 1*16^49*G: */ + {{{0x1a34d24f, 0x388d8cb7, 0x1a137401, 0x2db63c32, 0x342ee541, 0x077db7b3, 0x3169d939, 0x0b50f173, 0xe4a4}}, + {{0x1eba9414, 0x29fdc4c7, 0x0d8e4f13, 0x21bbb7ea, 0x0ad34ce8, 0x326733ee, 0x1c73526f, 0x24b9c5b4, 0x4d9f}}}, + /* 3*16^49*G: */ + {{{0x3bea0c68, 0x321042bc, 0x37b392b5, 0x10c048d9, 0x396faf09, 0x26f23a34, 0x2a3a2494, 0x258d3855, 0x3e41}}, + {{0x1a45edb6, 0x32edbfdc, 0x03cda1ab, 0x2846518c, 0x0693062f, 0x0f2ff8dc, 0x321f7f37, 0x31676492, 0x0123}}}, + /* 5*16^49*G: */ + {{{0x139824d7, 0x3dd748f2, 0x11c9897a, 0x2ded930d, 0x3f0b576e, 0x128f98bd, 0x17508eed, 0x0e3d5157, 0x8d94}}, + {{0x1366489f, 0x28013d22, 0x26b063d8, 0x2e78ae0c, 0x36ef6f8f, 0x182f4c6a, 0x26c2a2ca, 0x381cd3fb, 0x3261}}}, + /* 7*16^49*G: */ + {{{0x18d713de, 0x39201c6a, 0x028e6208, 0x1830bedd, 0x25454393, 0x2a44a8bf, 0x254420d4, 0x0931563b, 0xb725}}, + {{0x1b8350e9, 0x1bff9496, 0x04a5fcb7, 0x20b49bf9, 0x16941504, 0x0b460ba7, 0x03e45104, 0x2ce6a28a, 0x4c51}}}, + /* 9*16^49*G: */ + {{{0x3e3b2cb4, 0x331b0a4f, 0x37210402, 0x127cd6fc, 0x21149e30, 0x31db8e04, 0x112519ad, 0x17d6885b, 0x3de4}}, + {{0x307eb02f, 0x1878ceb0, 0x287044cf, 0x0f8a3996, 0x3c910682, 0x022a92a5, 0x2addc50e, 0x21661017, 0xba2a}}}, + /* 11*16^49*G: */ + {{{0x2ce4e5bf, 0x08d1d9bd, 0x09005b17, 0x19f2a1a8, 0x0906ae9b, 0x0ff38dd2, 0x1be87c1e, 0x3c71a256, 0x8511}}, + {{0x01789c08, 0x3f24a513, 0x05365262, 0x2a1e226f, 0x2a00232d, 0x377dfb1a, 0x0d4874c1, 0x3d73e46f, 0xecdf}}}, + /* 13*16^49*G: */ + {{{0x3d3258ab, 0x06d59a28, 0x2bc14dc3, 0x3490a062, 0x14ab5957, 0x2871cbb8, 0x360222cf, 0x014ba073, 0x8c5a}}, + {{0x022d0f8f, 0x15f8214c, 0x0d944ade, 0x36ba3e70, 0x0c08c246, 0x2a031e41, 0x3bda1079, 0x36d2ed10, 0x6811}}}, + /* 15*16^49*G: */ + {{{0x3f91bcee, 0x1630a82a, 0x20c0d841, 0x33c763c7, 0x2bf137f5, 0x18f3b155, 0x13560bdc, 0x3e05b7af, 0xcef7}}, + {{0x01966b33, 0x2ed36a7e, 0x172f6ac6, 0x0f92c0a8, 0x1d245fa6, 0x0ecce700, 0x08701246, 0x1320d8dd, 0x67e7}}} + }, + { + /* 1*16^50*G: */ + {{{0x0300bf19, 0x1c5cee75, 0x08fea494, 0x2d4d5daa, 0x352b6b92, 0x183eb6ac, 0x0bdd9541, 0x03fbcd83, 0x1ec8}}, + {{0x0107cefd, 0x1c737073, 0x295a07b6, 0x11b9dfd8, 0x2bbf5e01, 0x2925629e, 0x1340d2f3, 0x3a4dd5ad, 0xaeef}}}, + /* 3*16^50*G: */ + {{{0x12fea1f9, 0x2c5f2ef1, 0x00452b94, 0x3fc2d423, 0x106531c4, 0x3f76ad9c, 0x1f2e83bc, 0x22029574, 0xa6dc}}, + {{0x3bc345e9, 0x2c705391, 0x268f7e63, 0x1ee276df, 0x2cbc5005, 0x1a0e845a, 0x367c3038, 0x2a151f70, 0x7ef1}}}, + /* 5*16^50*G: */ + {{{0x06d6c9b3, 0x235030fc, 0x0865637c, 0x1b133a1d, 0x2481ba8c, 0x308a71e2, 0x245992bd, 0x2a4ffa90, 0xfe6b}}, + {{0x2948bdfb, 0x30b1e23e, 0x1c2e9b00, 0x203c6fc1, 0x013b56d9, 0x2d06cd15, 0x39872b6b, 0x0635d014, 0x7ee9}}}, + /* 7*16^50*G: */ + {{{0x0cf95151, 0x08bc41cc, 0x02c4b644, 0x19201b91, 0x08ded1b9, 0x03230b70, 0x098bfb02, 0x38bc51bf, 0x15d5}}, + {{0x2ff8ecf2, 0x20a81f30, 0x1d8c0f94, 0x0813ee5f, 0x1023f9bb, 0x038425e2, 0x3d4ec7f9, 0x0b8c6457, 0xa5b7}}}, + /* 9*16^50*G: */ + {{{0x296a5658, 0x35e042e4, 0x1ef65643, 0x052c9490, 0x2e29be38, 0x1f80249e, 0x0447ad8c, 0x3a1c95a2, 0x84c0}}, + {{0x181b80d1, 0x3659ca6f, 0x34f1fd22, 0x2986a607, 0x13725ed3, 0x1f8c6419, 0x022c4a08, 0x20e03058, 0x2659}}}, + /* 11*16^50*G: */ + {{{0x14dc6a0f, 0x1d6ed722, 0x2fe15753, 0x10d06450, 0x0077c274, 0x09939e8b, 0x3731d565, 0x2c71c6a4, 0xfed6}}, + {{0x176fc7e0, 0x32e35cb6, 0x23fc409c, 0x1d3564c2, 0x13ae2313, 0x24606b93, 0x3ff0a847, 0x2af9ac3f, 0x8de2}}}, + /* 13*16^50*G: */ + {{{0x18e29355, 0x2ce217c4, 0x1720d86d, 0x0723a4ce, 0x23b9d82f, 0x3be18100, 0x3cbc70fc, 0x137664b4, 0x2a6a}}, + {{0x35cc2872, 0x014f803e, 0x0c4c76c0, 0x24168e99, 0x28f90dfe, 0x3f720789, 0x27e0c760, 0x37ee9f12, 0x8677}}}, + /* 15*16^50*G: */ + {{{0x2148dabf, 0x3e7ea23f, 0x09d78eb1, 0x2b74ae4d, 0x3ae735c1, 0x193b08d7, 0x27546d97, 0x24c09b24, 0xe42d}}, + {{0x011e1361, 0x1dcb1d5a, 0x1e77eb9d, 0x1c9d5c06, 0x33853032, 0x0e33aff7, 0x184b0d8b, 0x218b1b8b, 0x6413}}} + }, + { + /* 1*16^51*G: */ + {{{0x366642be, 0x376d64a0, 0x158ba889, 0x0d241c5f, 0x0dfa8bce, 0x002bd1a0, 0x30c2f91b, 0x1de30119, 0x146a}}, + {{0x3d83efd0, 0x02ca5d20, 0x37e5ed1d, 0x2aa5c74b, 0x14b2870a, 0x1a609fe7, 0x0028add6, 0x383b0cd5, 0xb318}}}, + /* 3*16^51*G: */ + {{{0x27315443, 0x364e1ce0, 0x2e867299, 0x1e6ef552, 0x2142a13d, 0x32266082, 0x0935ff42, 0x1b010198, 0xfc69}}, + {{0x17d28960, 0x1243582d, 0x09bd1b17, 0x1ffd2184, 0x1677b548, 0x0387375a, 0x35892bbf, 0x09fafe0e, 0xe0ce}}}, + /* 5*16^51*G: */ + {{{0x16fdb4eb, 0x06ecbd70, 0x22e6a79d, 0x28f75e71, 0x3eb0928f, 0x15a8d58a, 0x3f2ad1ae, 0x3c887fd3, 0x974a}}, + {{0x29f6f484, 0x10270f7e, 0x3ffc2348, 0x0715ca8e, 0x0090ed11, 0x0790f40b, 0x003ca64d, 0x0e1f54d4, 0x5552}}}, + /* 7*16^51*G: */ + {{{0x1d5aeee3, 0x0e412b6d, 0x258c8137, 0x0a12f0d9, 0x1270c5e8, 0x086ce99a, 0x2398b091, 0x2d66d277, 0x5baa}}, + {{0x30f69717, 0x0b4a6bed, 0x3d31eed8, 0x1777276a, 0x3fdaf721, 0x28021987, 0x37e856e5, 0x1fd85f03, 0x8a57}}}, + /* 9*16^51*G: */ + {{{0x35726890, 0x146c7913, 0x0837d158, 0x24097fab, 0x110a0ee5, 0x0cbf3afe, 0x1c43d010, 0x17e9fad2, 0xfb68}}, + {{0x3835783a, 0x01baa3ce, 0x10e79b26, 0x29b2c4ba, 0x24ba094f, 0x3285b661, 0x25e2e869, 0x37c8b263, 0xd750}}}, + /* 11*16^51*G: */ + {{{0x28bca48a, 0x1192fc4e, 0x03df62f5, 0x2d357d3a, 0x07f71d78, 0x09ee470a, 0x2995a0ab, 0x23fd9678, 0x5de5}}, + {{0x12fd41cd, 0x21e53a03, 0x20f8aa95, 0x396f6713, 0x2d3c843f, 0x2988f094, 0x19b55309, 0x0ecf600d, 0x685a}}}, + /* 13*16^51*G: */ + {{{0x25ef63b6, 0x378e0d13, 0x31b182eb, 0x2d34059c, 0x0fc1c85a, 0x2dff68ed, 0x218bfaf1, 0x09737ab5, 0x6f18}}, + {{0x05c655f3, 0x0b211b3d, 0x27f94541, 0x22569900, 0x3334553c, 0x108135e0, 0x1911b98f, 0x1f9f7564, 0xff09}}}, + /* 15*16^51*G: */ + {{{0x34a63f3b, 0x2d411fb7, 0x178f9727, 0x080ec066, 0x36c76583, 0x1c457d79, 0x2a376b58, 0x2e257dd8, 0xc5ec}}, + {{0x05005024, 0x14fcdd1a, 0x230bee5b, 0x3ad97b97, 0x1233ec8b, 0x290163fe, 0x081f374e, 0x0946065e, 0x2225}}} + }, + { + /* 1*16^52*G: */ + {{{0x3180eef9, 0x35daa1e4, 0x228b9776, 0x00048826, 0x207b128d, 0x2b3aec6a, 0x2e5f07e3, 0x303d8748, 0xfa50}}, + {{0x3f4f2811, 0x233635f4, 0x17a213b3, 0x1a0ca4e9, 0x01a68a5e, 0x334a1c8a, 0x3eba9b72, 0x31a488e5, 0x6b84}}}, + /* 3*16^52*G: */ + {{{0x11da5e12, 0x07b838ce, 0x1cacb297, 0x31829005, 0x1ca2b6a9, 0x0ca7e4e8, 0x1e31bcda, 0x0b8f10de, 0xf750}}, + {{0x0385f4eb, 0x292e717a, 0x325cebc7, 0x21b4cbbd, 0x1672047b, 0x1c25170f, 0x0fafd599, 0x3d7b759f, 0x3c57}}}, + /* 5*16^52*G: */ + {{{0x10b7d105, 0x01d24cc4, 0x0e57c9f2, 0x329712e5, 0x3455b3f4, 0x13d98938, 0x25862a3a, 0x1e3e60eb, 0x12fe}}, + {{0x1f794a60, 0x162b1bee, 0x2ee90b84, 0x3b389975, 0x27cb771d, 0x2d6a8666, 0x2bcf7786, 0x3c68ce35, 0x2062}}}, + /* 7*16^52*G: */ + {{{0x1e0c5d05, 0x188760ce, 0x2572daff, 0x039b142a, 0x084b1a48, 0x12ec40a0, 0x3473d58c, 0x30c4d1f7, 0x76aa}}, + {{0x11ece63e, 0x159866dd, 0x15e6ee35, 0x048973c0, 0x02625f4b, 0x3ccb20c8, 0x070efabe, 0x1dbbc357, 0xef55}}}, + /* 9*16^52*G: */ + {{{0x3c53c086, 0x389bd217, 0x09a1aec9, 0x2d570d27, 0x288104c6, 0x1830c517, 0x05ccc87e, 0x3f96ef97, 0xa663}}, + {{0x25016201, 0x1a7140ca, 0x3994fc0e, 0x07b3295c, 0x023dc399, 0x2c40b226, 0x11fbf5d1, 0x265fdac8, 0xb541}}}, + /* 11*16^52*G: */ + {{{0x0b758574, 0x2b6007b5, 0x34f9c6e9, 0x0c99a250, 0x22bdf3d8, 0x328409eb, 0x2cd825b7, 0x149e8081, 0xde95}}, + {{0x3b67232a, 0x2df7c7f3, 0x15a2deb4, 0x39a84145, 0x169ed7ba, 0x077211fc, 0x3d14e4e2, 0x3815ab24, 0x4cd3}}}, + /* 13*16^52*G: */ + {{{0x3d85474f, 0x1de6e2af, 0x1634668d, 0x13128ae2, 0x385aea89, 0x3732f911, 0x32addbfe, 0x2f3819b4, 0x8da6}}, + {{0x3d7b4ef7, 0x3f7e71f4, 0x1dbdd7a5, 0x073164c1, 0x1dfff10b, 0x377d741c, 0x2d4ff84f, 0x1b1abcc7, 0x13fc}}}, + /* 15*16^52*G: */ + {{{0x3dd042ea, 0x2d750959, 0x18eafd06, 0x3e89a991, 0x3c93beeb, 0x3599278c, 0x3ba39b1b, 0x2b31f3ec, 0x7329}}, + {{0x2f5c94a1, 0x36a33fb0, 0x1fab4f0a, 0x1225dcc7, 0x2b68ee18, 0x2139e53e, 0x36f14892, 0x124d506d, 0x9272}}} + }, + { + /* 1*16^53*G: */ + {{{0x1f067ec2, 0x394f4cad, 0x1bba5220, 0x0a22ad75, 0x08e8421a, 0x16fdadf6, 0x21a11b1a, 0x1874329c, 0xda1d}}, + {{0x1ad836f1, 0x157ee83c, 0x279b48a6, 0x29ce2674, 0x091e2966, 0x01d98587, 0x1306c79c, 0x3d569f26, 0x8157}}}, + /* 3*16^53*G: */ + {{{0x3a95a8db, 0x1761dccb, 0x39d36f61, 0x0fb03111, 0x1b1723b8, 0x25991a64, 0x3dd0419e, 0x036918c0, 0xe3e9}}, + {{0x1b0d1cf9, 0x005b3dfc, 0x0984d3d1, 0x2c7be5f3, 0x02e76afb, 0x3eaa431c, 0x0178bb00, 0x0ef0015b, 0xfbe5}}}, + /* 5*16^53*G: */ + {{{0x112ee214, 0x1eabf590, 0x19315401, 0x0a93a5e5, 0x00c01c78, 0x19437f57, 0x3d775a8b, 0x3fb1ccb8, 0x9f4f}}, + {{0x1085f37a, 0x3bd10889, 0x3c880283, 0x066da4c2, 0x35c69d97, 0x259a0bf5, 0x22f2e60e, 0x38b84c63, 0x639c}}}, + /* 7*16^53*G: */ + {{{0x1f61a0a5, 0x22da0514, 0x3c14e3ef, 0x0494f86c, 0x040b2c4b, 0x0682907d, 0x34ac1b17, 0x188b5044, 0x431f}}, + {{0x38cef899, 0x1adedff9, 0x15657724, 0x2eaa810d, 0x23aa7241, 0x3799465c, 0x2438f6d6, 0x0c9ff9ea, 0xa298}}}, + /* 9*16^53*G: */ + {{{0x27748503, 0x2b099f55, 0x31328e7c, 0x1b8391dc, 0x0a12ac0e, 0x18bbce7e, 0x38fb86cb, 0x2eb77b39, 0x993d}}, + {{0x3eb0cee2, 0x2e9cd84d, 0x38adaa49, 0x3e1efda6, 0x21f51a17, 0x3de11e1e, 0x1eeeb785, 0x2a7ba15a, 0xa521}}}, + /* 11*16^53*G: */ + {{{0x26d23d80, 0x37a889d6, 0x2474d478, 0x02f447c9, 0x0962c0e1, 0x250c72e4, 0x15ea5a33, 0x1eae81ab, 0x75f1}}, + {{0x280dd57e, 0x21aa16c0, 0x34ea5909, 0x0bfefb6e, 0x1b629237, 0x31f42fc6, 0x39a80c7f, 0x18bf8558, 0xa07a}}}, + /* 13*16^53*G: */ + {{{0x21ad3413, 0x38ae6db5, 0x327d684a, 0x2e700100, 0x387b7a8d, 0x257d2172, 0x1f4a0a6e, 0x15578476, 0x6678}}, + {{0x3ebca672, 0x09204081, 0x2dc66601, 0x338b454e, 0x0bdf9ea6, 0x099b649f, 0x0f646925, 0x368f789e, 0x510d}}}, + /* 15*16^53*G: */ + {{{0x06cc8563, 0x3002bd6c, 0x3e101eaa, 0x0937d6ff, 0x16368892, 0x320af606, 0x27748ada, 0x128d8b36, 0xebdc}}, + {{0x2394ccfa, 0x26c5ef3a, 0x1204f924, 0x3101e492, 0x1d4f07be, 0x3b8d79b3, 0x2d35f9b1, 0x0c513a15, 0x659a}}} + }, + { + /* 1*16^54*G: */ + {{{0x0d064e13, 0x29cec184, 0x06f1e062, 0x0c477811, 0x3d416615, 0x17fe63a3, 0x30690721, 0x20bfc325, 0xa8e2}}, + {{0x11f4cc0c, 0x3bdf1cc4, 0x0dd6bd6c, 0x19e68f94, 0x2515888b, 0x2dfcf16c, 0x01c09abf, 0x0d56e36e, 0x7f97}}}, + /* 3*16^54*G: */ + {{{0x3a3979b5, 0x0a8666c2, 0x27e829e2, 0x0a23e379, 0x240e50ba, 0x0dfc2c7b, 0x1e26327f, 0x01f1736b, 0xae22}}, + {{0x0450fa6f, 0x23cf359a, 0x3d4f8896, 0x2a1edf4d, 0x2d7060fc, 0x3249148e, 0x39f71ad4, 0x3f944301, 0xea91}}}, + /* 5*16^54*G: */ + {{{0x0efca824, 0x10406440, 0x22164fae, 0x2f8313fa, 0x185461e0, 0x31504019, 0x2ace59ce, 0x3b432b5c, 0xcb8d}}, + {{0x0f227361, 0x0502f416, 0x3931742f, 0x2b47f7f1, 0x2ccbc496, 0x05b121e8, 0x188c85b3, 0x0023dd03, 0x33a5}}}, + /* 7*16^54*G: */ + {{{0x3bcbd327, 0x1046d368, 0x1e4aaee9, 0x13821488, 0x276ed6b0, 0x2524035f, 0x1836708e, 0x0eca62bc, 0xb0c5}}, + {{0x2d7be436, 0x185af128, 0x0636a0f1, 0x0a88831d, 0x26b2afd8, 0x3da9806d, 0x17ea1638, 0x25d007ef, 0xee2a}}}, + /* 9*16^54*G: */ + {{{0x17b836a1, 0x39bbed8e, 0x3679ef7d, 0x019017fd, 0x37f526c8, 0x2218bb39, 0x1b920d4d, 0x29cfcca7, 0x6f6b}}, + {{0x06832b84, 0x36f7cbec, 0x0e1ff934, 0x264314a2, 0x3ee9c0d8, 0x02e29016, 0x3c18e3db, 0x2285ffd7, 0xdc77}}}, + /* 11*16^54*G: */ + {{{0x1eb39ede, 0x2bb8d082, 0x30612d42, 0x02200cb5, 0x02436031, 0x3fd19f84, 0x22af4bbc, 0x069f71d0, 0x7d47}}, + {{0x2bf6607e, 0x326f3652, 0x022a8fd0, 0x2573df47, 0x3c86fa77, 0x2088c7bf, 0x2856507b, 0x1ec67ce9, 0x004a}}}, + /* 13*16^54*G: */ + {{{0x165eb1c1, 0x15b52789, 0x1ae5c5aa, 0x335d59f3, 0x02f0967f, 0x03f30c66, 0x33fac707, 0x1458fe6d, 0xf002}}, + {{0x2dde2ae0, 0x369f5c11, 0x2cd11e57, 0x1dbfd735, 0x26afed85, 0x1ad29768, 0x120df4c6, 0x2a7a220f, 0x054e}}}, + /* 15*16^54*G: */ + {{{0x1ac32c64, 0x33cd424f, 0x0ae4bf84, 0x0dbf80fb, 0x07715e0e, 0x013a543d, 0x123aa0f7, 0x0500007b, 0xac12}}, + {{0x1eb1a867, 0x204ab6eb, 0x253f0898, 0x16974e96, 0x0499a3ed, 0x02da55cc, 0x38baf187, 0x2f32eb0c, 0xce8e}}} + }, + { + /* 1*16^55*G: */ + {{{0x0319497c, 0x0bce0b7a, 0x12508c02, 0x166c7e94, 0x13cab15d, 0x2795b9a4, 0x285872d3, 0x14ee7268, 0x174a}}, + {{0x079afa73, 0x0f684eb0, 0x0b985438, 0x1ace8763, 0x07f9e664, 0x10557cb1, 0x09c1657b, 0x370deaff, 0xccc9}}}, + /* 3*16^55*G: */ + {{{0x354b8367, 0x25201cf5, 0x3d506bfe, 0x1d6ddf59, 0x036a5db7, 0x2a975161, 0x2526e40c, 0x0252b911, 0x5e5a}}, + {{0x11ce85ca, 0x14ca6a76, 0x1e5ffa44, 0x1aaa7bcf, 0x2a4b7a79, 0x2407c55c, 0x15e05c2c, 0x3e32691e, 0xae8a}}}, + /* 5*16^55*G: */ + {{{0x17b10d9d, 0x06615e4e, 0x11f8fcaf, 0x294bc627, 0x0cb82de6, 0x332e0cc4, 0x02e859de, 0x382b6e5c, 0x00d4}}, + {{0x3140dced, 0x20840121, 0x0e2d923e, 0x1626325e, 0x2287f70b, 0x0be1190c, 0x3640947d, 0x0066060d, 0x87b8}}}, + /* 7*16^55*G: */ + {{{0x1c9caee8, 0x02046982, 0x1a270bb2, 0x0b88116c, 0x04a66763, 0x1e866bbb, 0x374c0f6f, 0x1484da3b, 0x0366}}, + {{0x3772b711, 0x2a7b1a8e, 0x295ba7f0, 0x32ea624c, 0x26944501, 0x27f1a06e, 0x3ded9994, 0x30cacaa4, 0x1f18}}}, + /* 9*16^55*G: */ + {{{0x1446c85c, 0x0ffe5d46, 0x201c0635, 0x0df78239, 0x36c6eade, 0x19db114f, 0x38f1faa0, 0x24415bf6, 0x0e58}}, + {{0x2148972e, 0x3db1df9c, 0x0cddadd5, 0x2408d3a0, 0x081898f4, 0x1d062ebd, 0x27bda0ec, 0x1217c47e, 0xe39a}}}, + /* 11*16^55*G: */ + {{{0x022e1259, 0x3c62b7cf, 0x281362af, 0x05ce6901, 0x07777193, 0x33d7ea80, 0x1463f2b6, 0x049b49bc, 0xa740}}, + {{0x334a5f43, 0x3ddc5c90, 0x31d6dad5, 0x21979d4e, 0x3c7ee517, 0x17c5d299, 0x0f1ff1b0, 0x3feebc65, 0x05a9}}}, + /* 13*16^55*G: */ + {{{0x0b08f1fe, 0x22285e8f, 0x3a087bfd, 0x339fb9c2, 0x02d177d7, 0x1015d976, 0x074e4a65, 0x2e085b65, 0x87e4}}, + {{0x2ed5e2ec, 0x17dd2b26, 0x2786d9d7, 0x0bc8f6f5, 0x38c2cc6e, 0x35fe3a8b, 0x348cecd7, 0x0eb01d98, 0xf74e}}}, + /* 15*16^55*G: */ + {{{0x21c4d15c, 0x2a1c039a, 0x3c0e74b9, 0x17a9efc1, 0x254a4410, 0x308b0304, 0x279a5a92, 0x06d18ffa, 0x35ea}}, + {{0x3f3fe1ea, 0x324e6ebd, 0x065095ed, 0x18cea80c, 0x0d3b185d, 0x23e97f5d, 0x2d2cd788, 0x245946e7, 0xad21}}} + }, + { + /* 1*16^56*G: */ + {{{0x1475b7ba, 0x213f7fc2, 0x0918b3d8, 0x0e79cc39, 0x018cdbe0, 0x395fb7d4, 0x3785c3d3, 0x25a60650, 0x9593}}, + {{0x3524f2fd, 0x26e2afe1, 0x0709385e, 0x194fd932, 0x1cd6849c, 0x00e1a92e, 0x331dd8ba, 0x154a2230, 0x2e7e}}}, + /* 3*16^56*G: */ + {{{0x0fd69985, 0x02717764, 0x1df72aea, 0x0c2732db, 0x0ccf149f, 0x3da437ef, 0x32f7e788, 0x1d9d73ad, 0x0ae9}}, + {{0x1409a003, 0x2723ad04, 0x2ee1aff8, 0x2e67505e, 0x1a54c5d0, 0x237fb814, 0x08d14e9b, 0x265cfdb9, 0x9121}}}, + /* 5*16^56*G: */ + {{{0x19262b90, 0x37064f7f, 0x23cc29a9, 0x08f1307f, 0x025d1fb7, 0x197c5de0, 0x1612ec9b, 0x218a96b0, 0x2b15}}, + {{0x083d7557, 0x24665b99, 0x19489a49, 0x14d25c3e, 0x0749066f, 0x0c354b6a, 0x233faa7a, 0x014f6a82, 0x2eb0}}}, + /* 7*16^56*G: */ + {{{0x28e7be40, 0x0fe5c532, 0x1040ee59, 0x34b22524, 0x24769af2, 0x2570585b, 0x2ee677ee, 0x3abb46a5, 0x6af9}}, + {{0x2e387e1c, 0x2905b809, 0x0f59569f, 0x38fd99a8, 0x07dc8145, 0x27a90a0d, 0x06649670, 0x0a845a40, 0xb381}}}, + /* 9*16^56*G: */ + {{{0x3482801e, 0x09adbe83, 0x1bd4155d, 0x1e53e2f1, 0x38d6f940, 0x2aad0932, 0x0144eeb3, 0x1a3b8111, 0x5966}}, + {{0x04870c37, 0x11dc523c, 0x3d3535ad, 0x2db072d8, 0x31304e8d, 0x23e5821d, 0x2ef5f1ec, 0x282a16ee, 0x949a}}}, + /* 11*16^56*G: */ + {{{0x032c19fd, 0x1326cb9f, 0x18028c3e, 0x32ae3a41, 0x170b5b4a, 0x3d345ead, 0x050762fd, 0x346206d4, 0xbe84}}, + {{0x32f1281f, 0x1da5294d, 0x250dc376, 0x1569fd57, 0x08399479, 0x3997d20c, 0x050944d1, 0x1832ccb7, 0xeff9}}}, + /* 13*16^56*G: */ + {{{0x16c69482, 0x346dd7f5, 0x32fa167b, 0x3aad5004, 0x32bc88cb, 0x15c9d32b, 0x17ee541f, 0x280c5303, 0x9867}}, + {{0x2f792cd7, 0x1bc18451, 0x15628a91, 0x189173d4, 0x3a99639e, 0x24b556c6, 0x0834f9c7, 0x18568ec4, 0xd02e}}}, + /* 15*16^56*G: */ + {{{0x1d557aa1, 0x2288e764, 0x101fc297, 0x0764bfb3, 0x19d6abdf, 0x1fcba802, 0x0815a592, 0x3c915036, 0xa866}}, + {{0x01430634, 0x2606eed3, 0x0611a4b7, 0x3ada719f, 0x30e13961, 0x0f63e976, 0x22b44d79, 0x0e7daa00, 0xb587}}} + }, + { + /* 1*16^57*G: */ + {{{0x1d82b151, 0x2d44d032, 0x21fba2db, 0x28290f55, 0x109a8fcc, 0x168454ec, 0x01e56d64, 0x0e942b90, 0xd2a6}}, + {{0x1cf89405, 0x105085d3, 0x084ca52d, 0x03dd42bd, 0x148220a7, 0x2bb962ca, 0x3fcb7565, 0x21bed910, 0xe82d}}}, + /* 3*16^57*G: */ + {{{0x2e4b3ba0, 0x2167d8d7, 0x18bf1f17, 0x0aafbd7c, 0x3f245f5c, 0x385c3cc6, 0x3fb73bef, 0x04414887, 0x4108}}, + {{0x17525595, 0x21a58770, 0x1a064554, 0x0d926159, 0x2b849813, 0x2996b875, 0x35668f2c, 0x3cda5dbf, 0xdc37}}}, + /* 5*16^57*G: */ + {{{0x13d98ded, 0x18a726e2, 0x38a02184, 0x37c8a0ce, 0x31d65edb, 0x3c8a6414, 0x0c0c8c8c, 0x2884285b, 0x63a2}}, + {{0x20d1cfc2, 0x06465f53, 0x1c7873a5, 0x2afda802, 0x2d94461f, 0x140cc953, 0x2c76fd06, 0x10b8b9ff, 0x882b}}}, + /* 7*16^57*G: */ + {{{0x38045445, 0x2a186942, 0x01e8d7ee, 0x3fdcdc64, 0x17bef080, 0x04b8b975, 0x167ca3df, 0x20575127, 0x0c15}}, + {{0x0054a206, 0x053e1f55, 0x258cea32, 0x0c15390d, 0x23cd28ba, 0x24f0ed99, 0x14115d0a, 0x35828eba, 0x2f30}}}, + /* 9*16^57*G: */ + {{{0x03857faf, 0x3a448e73, 0x29619701, 0x0bf2b787, 0x28ef7f88, 0x1eea3d20, 0x28a9c0d5, 0x3adae26b, 0xc757}}, + {{0x20584ca4, 0x07676c32, 0x01894c10, 0x1f4c4344, 0x3ec61b62, 0x0da7c822, 0x3ff36257, 0x1673f348, 0xf03a}}}, + /* 11*16^57*G: */ + {{{0x1459225d, 0x3934613d, 0x18858d10, 0x3ebddf8b, 0x1c02a244, 0x17502646, 0x3a0d0f81, 0x18ebab6b, 0xfa80}}, + {{0x3ece1507, 0x28adf8ed, 0x007c59c3, 0x0adb0db4, 0x0c425c0a, 0x37888209, 0x0c069160, 0x07e415f0, 0x0ba7}}}, + /* 13*16^57*G: */ + {{{0x16f0d044, 0x19e7fa50, 0x09e61a79, 0x2ea7f524, 0x2ee0a5aa, 0x3da73e18, 0x257a89e2, 0x28f16740, 0x658c}}, + {{0x37cb872d, 0x3747ccbb, 0x018ce89a, 0x2859d8f1, 0x3bd37655, 0x197589c4, 0x225460f1, 0x304ddeba, 0xae5c}}}, + /* 15*16^57*G: */ + {{{0x3696756d, 0x2d6b255c, 0x2561417a, 0x1abc5815, 0x3f305c67, 0x30660d74, 0x1f2bace4, 0x12d2abe4, 0x31c9}}, + {{0x1e08ae78, 0x2f117a37, 0x2ad1070a, 0x2bb7f2b9, 0x34160683, 0x2e2d66ab, 0x283a9bf4, 0x2212d55b, 0xf80f}}} + }, + { + /* 1*16^58*G: */ + {{{0x1617e073, 0x10dbe6d1, 0x039317b3, 0x2b2f6f4e, 0x0fdc866b, 0x39e25b5f, 0x31eb890e, 0x1f88cd51, 0x6458}}, + {{0x1faf6589, 0x20a6797a, 0x33aeab35, 0x2e428e44, 0x0299a185, 0x1b75911f, 0x102e2ae9, 0x33756fda, 0xd99f}}}, + /* 3*16^58*G: */ + {{{0x0e103dd6, 0x37dc51c8, 0x0004859a, 0x1181301f, 0x12a17ac3, 0x084f3f16, 0x203f836a, 0x1ef55690, 0xbc47}}, + {{0x16f7c343, 0x0e420b63, 0x23b44ac6, 0x0a4d5cb1, 0x1ea6395d, 0x2b154b1b, 0x0dd526cb, 0x07890a6a, 0xe31e}}}, + /* 5*16^58*G: */ + {{{0x144eab31, 0x34370ec3, 0x0e634907, 0x316bc501, 0x3bf8e80a, 0x0ed08c99, 0x3b838030, 0x2d3f969a, 0x589d}}, + {{0x11361f6a, 0x106baf9d, 0x148f8db9, 0x18439548, 0x3d90f31f, 0x1c188092, 0x2a2a4f60, 0x11170422, 0x6255}}}, + /* 7*16^58*G: */ + {{{0x1a0c2c41, 0x2fe585ca, 0x20336c67, 0x20c70715, 0x2edb7c42, 0x286182b5, 0x22fa2ea8, 0x2ccdf45b, 0x1339}}, + {{0x29f1bc2b, 0x217c152e, 0x1e923a41, 0x0489fe1f, 0x13a3406b, 0x0c903f44, 0x3ae5ba7a, 0x0a58d8b1, 0x9f9b}}}, + /* 9*16^58*G: */ + {{{0x18fc47af, 0x1c12c7e1, 0x2c0cdec3, 0x377fb20c, 0x01b568a8, 0x00ca6d40, 0x3cf17cc5, 0x2ee844d8, 0x7ff3}}, + {{0x39ba43a7, 0x3e185933, 0x18bac297, 0x294ec6b4, 0x33446b17, 0x32246dd1, 0x0a629a0b, 0x29eba006, 0x1f6b}}}, + /* 11*16^58*G: */ + {{{0x15213775, 0x06135802, 0x3d42a990, 0x2d0a4ec8, 0x2c7f6100, 0x07a4e57f, 0x360bb614, 0x1c118f3a, 0x8ec6}}, + {{0x3841ffff, 0x38043cf9, 0x0cf51e90, 0x36a6282f, 0x2dee0e71, 0x190d0573, 0x25be306e, 0x299be836, 0x8f58}}}, + /* 13*16^58*G: */ + {{{0x3452abbb, 0x32cffe34, 0x2b95c2e3, 0x1aa9cbf8, 0x15d495ae, 0x2eb0ffb6, 0x301bb89d, 0x186d1079, 0x83de}}, + {{0x054eb66e, 0x28145dac, 0x3ce42918, 0x2717cdae, 0x0e1563d7, 0x3edabe31, 0x0609fa6b, 0x38cd28d3, 0x32f0}}}, + /* 15*16^58*G: */ + {{{0x359276f1, 0x25a2309b, 0x2a17b15e, 0x2b896ca4, 0x3cd86833, 0x2ed7003d, 0x0c1db1a8, 0x18e263d4, 0x3d76}}, + {{0x059cbcb3, 0x0792996e, 0x1b197860, 0x08660806, 0x18333ef3, 0x1db8d36b, 0x07ddb609, 0x1a5cde86, 0xd376}}} + }, + { + /* 1*16^59*G: */ + {{{0x1d45e458, 0x1635b21b, 0x250e7fd3, 0x02a9b3a8, 0x09de042f, 0x151b4f95, 0x0d885b3a, 0x2f783939, 0x8481}}, + {{0x1779057e, 0x3592c6d6, 0x3262e556, 0x029e710a, 0x2cb2ca90, 0x096fce73, 0x004dd84a, 0x1ee32e95, 0x38ee}}}, + /* 3*16^59*G: */ + {{{0x152da17d, 0x18283e90, 0x0d0646b1, 0x3704f6c2, 0x200bc811, 0x139ac17f, 0x18c5f089, 0x3b4783d4, 0x3bea}}, + {{0x2cc768d2, 0x39c12617, 0x1fec416c, 0x3379dee3, 0x00e1b554, 0x12a2fafa, 0x37acdfef, 0x35fd56bf, 0xc3b0}}}, + /* 5*16^59*G: */ + {{{0x3a4edcc5, 0x0d3e85f6, 0x20311b72, 0x138c8850, 0x275997e7, 0x0b7f00e4, 0x09d61875, 0x36e832f7, 0x6e73}}, + {{0x159da0e4, 0x2cc7df37, 0x00679037, 0x229df69c, 0x02869327, 0x11542222, 0x2cc48bea, 0x307f127b, 0xee0a}}}, + /* 7*16^59*G: */ + {{{0x0a80b979, 0x02713109, 0x29abb314, 0x243d7e8c, 0x07c31004, 0x1f65faa9, 0x1b592762, 0x37624df9, 0x7706}}, + {{0x0126cfde, 0x133d2041, 0x17efe321, 0x3e828d3f, 0x2a9c7117, 0x2375e647, 0x3b714777, 0x2a609f56, 0x8a02}}}, + /* 9*16^59*G: */ + {{{0x326fe285, 0x336e712d, 0x13ef127d, 0x16eb0a50, 0x39e06aa4, 0x3cf1e907, 0x3c0f80d2, 0x08b164a6, 0x16d4}}, + {{0x0155b441, 0x0f83ff9b, 0x3364d423, 0x0fc3044d, 0x3531b1e9, 0x2df9a698, 0x22641a8a, 0x223e9478, 0x0df8}}}, + /* 11*16^59*G: */ + {{{0x3acfa513, 0x38c42f2a, 0x260e3aea, 0x0901e7e6, 0x356a9c4e, 0x28d11d43, 0x36d63aa5, 0x0391fbb1, 0x1fcc}}, + {{0x107afc9c, 0x141d6e90, 0x09839187, 0x3b7b7459, 0x39f9b44b, 0x38e1d50c, 0x35478b48, 0x30681078, 0x165d}}}, + /* 13*16^59*G: */ + {{{0x3edc69b2, 0x0689c1f3, 0x26b77172, 0x0298226c, 0x0aa386a5, 0x190c10d7, 0x0b8a1730, 0x241ceb5b, 0xc12b}}, + {{0x20dd41dd, 0x0caba6c0, 0x127b2a00, 0x3b876f8f, 0x094976b8, 0x1cb7227e, 0x0cdf1d97, 0x310ff94d, 0x3173}}}, + /* 15*16^59*G: */ + {{{0x3961fe4d, 0x2dbd6177, 0x3107197a, 0x05221be2, 0x2ca73e8a, 0x0fa4c4c4, 0x27a8fa3f, 0x2fe1770c, 0xd059}}, + {{0x2ae823c2, 0x264d6c19, 0x0dab64cb, 0x0e22e87d, 0x0955b4fd, 0x01d97721, 0x3525e3fe, 0x1e983022, 0x4510}}} + }, + { + /* 1*16^60*G: */ + {{{0x2caf666b, 0x3358c0fd, 0x0b1ce30b, 0x3f3fb4f1, 0x17f4637f, 0x1a5e6ba0, 0x102aa62b, 0x1295e9e0, 0x1346}}, + {{0x3f6ecc27, 0x3d256a41, 0x10942e13, 0x3cc02a07, 0x0cb0ca48, 0x390cd14f, 0x14580ef7, 0x05640118, 0x69be}}}, + /* 3*16^60*G: */ + {{{0x0eca5f51, 0x085ac826, 0x0fc9aebf, 0x3a85c6e5, 0x05b5cfdd, 0x3b5acafc, 0x2e6962c6, 0x35453767, 0xdde9}}, + {{0x10c638f7, 0x2b5a69cf, 0x289571f9, 0x3fbafa37, 0x3f8f0950, 0x07cd2c29, 0x28111d89, 0x1a44cf38, 0xb84e}}}, + /* 5*16^60*G: */ + {{{0x199c88e4, 0x3e41ac16, 0x0ad46ec2, 0x3b544f88, 0x204b179a, 0x3d01bac4, 0x193736e9, 0x188408da, 0xfd1a}}, + {{0x195bc8df, 0x27232459, 0x1cc00f29, 0x1adc7525, 0x177782dc, 0x0f01a552, 0x0c20bfb1, 0x1ed52e72, 0x1ac9}}}, + /* 7*16^60*G: */ + {{{0x1f8018ce, 0x35456d6d, 0x1892d68b, 0x0b695ce3, 0x086dc7cf, 0x3ff393cb, 0x296b9f13, 0x214c7630, 0x4ee4}}, + {{0x1e48381f, 0x30d6986c, 0x0e806013, 0x01d25c6d, 0x07c5e671, 0x2d102343, 0x3f8b5fc7, 0x27b52042, 0xb68f}}}, + /* 9*16^60*G: */ + {{{0x31473678, 0x0a14ba47, 0x14392f70, 0x2815e542, 0x38c070cb, 0x38c53156, 0x000dbff5, 0x33270d31, 0xfd76}}, + {{0x0d144f4f, 0x38593baa, 0x001c8437, 0x18a3bb85, 0x032cd660, 0x3b829cf4, 0x143dae0f, 0x1950de1c, 0xf204}}}, + /* 11*16^60*G: */ + {{{0x0d7a2193, 0x3c02dc52, 0x197546ed, 0x1a47913c, 0x34ea212c, 0x1b3a09d2, 0x3b40219e, 0x2ae8cc48, 0x85a2}}, + {{0x30cdcf3a, 0x3c320f52, 0x03b12427, 0x31b6b7e7, 0x0c029fe1, 0x31820b47, 0x30516d82, 0x2615faca, 0x9c12}}}, + /* 13*16^60*G: */ + {{{0x377568b0, 0x16c0c16c, 0x1e03b053, 0x2ba37406, 0x03650f35, 0x2db5b15e, 0x3fe74440, 0x36ff1cf3, 0xd25d}}, + {{0x1f39929c, 0x0284e49b, 0x23c3f006, 0x089ce207, 0x27d92b83, 0x2bbdd337, 0x048938be, 0x3fdd64fe, 0x7a3a}}}, + /* 15*16^60*G: */ + {{{0x271d7c13, 0x17f94462, 0x20ffa385, 0x06ad7dfe, 0x2ac80564, 0x01fa6a5e, 0x14a7255f, 0x0d4c50fa, 0x4581}}, + {{0x3aff63cf, 0x18e2f154, 0x2bd96b99, 0x08019550, 0x1d69c970, 0x3d43c5df, 0x39ad8b57, 0x163b0525, 0x9f58}}} + }, + { + /* 1*16^61*G: */ + {{{0x2d83f366, 0x2b68e834, 0x2f28588c, 0x36733b78, 0x1dc97a0c, 0x3d0c2f30, 0x3fe2e9ae, 0x277d6dc4, 0xbc4a}}, + {{0x181f33c1, 0x1d635999, 0x2547b16d, 0x3a2a7efe, 0x3798caa6, 0x24deb7d2, 0x05c06383, 0x20729b9e, 0x0d3a}}}, + /* 3*16^61*G: */ + {{{0x3712be3c, 0x01a8b8cb, 0x2146a66b, 0x257c63b6, 0x00153472, 0x1c976eac, 0x1b378d3c, 0x0d2764cc, 0x39d7}}, + {{0x1c6ff65c, 0x30c067d0, 0x0a41644c, 0x17bde97b, 0x2812e8ef, 0x09d55319, 0x33bf7fb1, 0x26d3d5bb, 0x8f92}}}, + /* 5*16^61*G: */ + {{{0x1f77f22b, 0x2ab93ef3, 0x0f82e035, 0x265c8e65, 0x15af26c6, 0x0735b0a6, 0x01dd09e5, 0x2985fdf7, 0xf0cb}}, + {{0x1909a03c, 0x3f238b1d, 0x0a095661, 0x3c631fa4, 0x16d04004, 0x0c9b0d94, 0x1df989ef, 0x2ad0c4fe, 0x1a25}}}, + /* 7*16^61*G: */ + {{{0x06509c12, 0x22b37353, 0x3d1f4765, 0x1aff88d6, 0x3268ed8d, 0x05c3a361, 0x154d321d, 0x1eae76c8, 0x381d}}, + {{0x2eb46102, 0x1190aa38, 0x0e6eaf75, 0x160a161b, 0x2581e720, 0x34915ce9, 0x23da9eb5, 0x2ad6dff6, 0xa47a}}}, + /* 9*16^61*G: */ + {{{0x384fe955, 0x36ced358, 0x063bce48, 0x2655a968, 0x0c8a53f6, 0x0edcf9a5, 0x387e6479, 0x3c1519ea, 0xa703}}, + {{0x161344bd, 0x09acbbef, 0x197277fa, 0x27858a71, 0x19199b53, 0x29e4b5ac, 0x047adc0e, 0x3e4d68ac, 0xd500}}}, + /* 11*16^61*G: */ + {{{0x06eace58, 0x126595b0, 0x2f3211d3, 0x1f9158e8, 0x13a03f1b, 0x1ab435c1, 0x150d746c, 0x2cf16ab5, 0x73c6}}, + {{0x2af8654e, 0x05c2a45c, 0x3b8d2917, 0x1aa1e36e, 0x2d91c6aa, 0x242644d9, 0x24f741ba, 0x2d291cce, 0x3a2f}}}, + /* 13*16^61*G: */ + {{{0x00181d5e, 0x12ce22fc, 0x15aaf205, 0x1c6cea6e, 0x0eddb8de, 0x0034e870, 0x147fda1d, 0x3cf9d41b, 0xc627}}, + {{0x369f886d, 0x09e40298, 0x1cbe2c39, 0x3dac0152, 0x21f7d68e, 0x1a5804e2, 0x02a63b2d, 0x2775c791, 0xd78f}}}, + /* 15*16^61*G: */ + {{{0x37828b16, 0x138a367e, 0x0a4847f3, 0x11e563ca, 0x06de53a0, 0x17d029bc, 0x3d233fa2, 0x3eaf83b7, 0xbb88}}, + {{0x0aea5df7, 0x1451ce88, 0x3a1e969c, 0x12a05d38, 0x159163ec, 0x37165804, 0x1e8dd345, 0x1dacc13d, 0xb736}}} + }, + { + /* 1*16^62*G: */ + {{{0x25324caa, 0x152acc3f, 0x29472a39, 0x12d978c2, 0x12a32e69, 0x3631d251, 0x18bc0d23, 0x2a5efe0a, 0x8c28}}, + {{0x0bef9482, 0x39c771cf, 0x11cb9459, 0x39e13c11, 0x3cc0eb7a, 0x3fb7cc7d, 0x05193378, 0x0118e8cc, 0x40a3}}}, + /* 3*16^62*G: */ + {{{0x0754dd40, 0x18fa1c55, 0x03466cf8, 0x10898c7f, 0x32f6e9a2, 0x12107f35, 0x0dfcf45b, 0x091c0cb0, 0x9729}}, + {{0x2aa36143, 0x212d24bc, 0x1acaf493, 0x36ba1495, 0x14df3690, 0x171d772f, 0x3ea1dcd1, 0x28910997, 0x91d1}}}, + /* 5*16^62*G: */ + {{{0x0c2ca7ff, 0x30b60bae, 0x1df021a3, 0x00d91765, 0x2f27af18, 0x1e46b568, 0x2796e050, 0x1fe5d602, 0x8963}}, + {{0x30493e68, 0x3b505785, 0x242eab7b, 0x1ef1a8e3, 0x357489f8, 0x2e73c550, 0x08424d57, 0x38492322, 0x2d1f}}}, + /* 7*16^62*G: */ + {{{0x0ca8dd7f, 0x061b58e8, 0x2a1381a6, 0x31ca00d5, 0x1357421b, 0x327680f5, 0x25e092fd, 0x0e39c6f8, 0x3081}}, + {{0x0a92c7f2, 0x1057c91e, 0x34ad915e, 0x05959190, 0x008e18c8, 0x27b11745, 0x0fc925e3, 0x38b4a20a, 0x28d1}}}, + /* 9*16^62*G: */ + {{{0x066a3fb1, 0x037315a2, 0x192e206c, 0x30024a06, 0x36862f6e, 0x15d43216, 0x1eb65d1e, 0x313a0a9b, 0x575f}}, + {{0x102655ad, 0x26e3a42a, 0x2a3af2f0, 0x0ced5cf1, 0x0e87daed, 0x076f0a5e, 0x2fca2d67, 0x36e410a9, 0x6f6e}}}, + /* 11*16^62*G: */ + {{{0x390117df, 0x06daa291, 0x22010292, 0x094eeef3, 0x2a2a8fda, 0x3c9be07b, 0x2ab7a227, 0x240dad93, 0xa5ec}}, + {{0x386462fe, 0x204a04cf, 0x214a363d, 0x21187c15, 0x1fa0f71c, 0x25e60eb4, 0x140400c5, 0x319897b0, 0xb79d}}}, + /* 13*16^62*G: */ + {{{0x172ad712, 0x2c3e5d70, 0x21047290, 0x0e632c37, 0x2349b95a, 0x39e5d851, 0x10b0949d, 0x37fa44cc, 0xa153}}, + {{0x0d48fdd2, 0x2297d94e, 0x2f0b329c, 0x014fca16, 0x31b89abd, 0x0c6357c7, 0x05b2fc48, 0x36104fec, 0xfd94}}}, + /* 15*16^62*G: */ + {{{0x11cf5b3a, 0x0c30dc04, 0x1b5a7810, 0x10cea0ef, 0x2dc824c4, 0x30d34223, 0x14615935, 0x06b1abde, 0x9a54}}, + {{0x36a44ae4, 0x0fd55d7c, 0x21ea52d6, 0x123fb894, 0x0f475f55, 0x386bcda2, 0x06ab7caf, 0x123072c4, 0xb661}}} + }, + { + /* 1*16^63*G: */ + {{{0x1faccae0, 0x2312e844, 0x24bb3374, 0x22cd4316, 0x071fd23c, 0x3653393c, 0x127a8c1d, 0x259984e5, 0x08ea}}, + {{0x0e62b945, 0x16bcd28c, 0x0f0f8e95, 0x2de0efa7, 0x15c5d735, 0x39f033ee, 0x22782e24, 0x3eaef23b, 0x620e}}}, + /* 3*16^63*G: */ + {{{0x26a06f5e, 0x06902d65, 0x2a083702, 0x1064945b, 0x23b716a3, 0x2c350849, 0x0253ac37, 0x093efa85, 0x383b}}, + {{0x13c6e772, 0x227d1e1b, 0x38c2b040, 0x3dab9d2e, 0x2a5a19e8, 0x3d59b553, 0x1ba2044c, 0x1c1ab13b, 0x54cf}}}, + /* 5*16^63*G: */ + {{{0x0638a136, 0x1e5d7075, 0x2838195c, 0x034738cd, 0x0d790c2b, 0x39671ad8, 0x2ed6d789, 0x0cb40f80, 0xe684}}, + {{0x0c6c2584, 0x2bf46042, 0x3357336a, 0x0278faf6, 0x01e6472e, 0x0a9cc0e8, 0x35a6624d, 0x3904e638, 0xca5b}}}, + /* 7*16^63*G: */ + {{{0x16e8c10c, 0x33a1f110, 0x11bd6807, 0x1ca617ce, 0x306e7fb4, 0x3ef7b39c, 0x25c2a0ee, 0x355678bf, 0x395d}}, + {{0x05fe638e, 0x30f5b64c, 0x066922cb, 0x24270137, 0x3a4e274c, 0x04fa1ebf, 0x12ac5d04, 0x37352d16, 0xfd62}}}, + /* 9*16^63*G: */ + {{{0x0d6c14ef, 0x059936c8, 0x2f93c8f5, 0x163f1d41, 0x22648008, 0x3bb56fbb, 0x25dcb9f6, 0x12b70d54, 0x7a51}}, + {{0x0b3fbd13, 0x2b4f861c, 0x2a6e24f7, 0x2fabbdca, 0x0f5c3729, 0x1fc2e532, 0x2e4d8e89, 0x347fb454, 0x56ed}}}, + /* 11*16^63*G: */ + {{{0x0f6d65eb, 0x2a518f41, 0x04021524, 0x26441dd5, 0x108f235a, 0x23bcefd2, 0x1d90d8ea, 0x3f5610c9, 0x1ee1}}, + {{0x1d22941c, 0x380dae49, 0x23582b11, 0x0cbd3a61, 0x02fcfaca, 0x2ae7f13d, 0x2c73c1cf, 0x0a246f75, 0xbb69}}}, + /* 13*16^63*G: */ + {{{0x0e36cb44, 0x3c6543bc, 0x1ca20191, 0x1fa2db23, 0x03357d61, 0x163f4362, 0x3aaa8bc0, 0x158d34e3, 0x1551}}, + {{0x1f495a68, 0x0a6bd194, 0x020c1e53, 0x30dc5d7c, 0x23205da8, 0x038fc2d1, 0x35215e37, 0x3ff1d555, 0xab4f}}}, + /* 15*16^63*G: */ + {{{0x3427bacc, 0x07e51841, 0x12d62e15, 0x1ccc5937, 0x0dc4aa9e, 0x163ac256, 0x35201363, 0x2f1911af, 0x3bc6}}, + {{0x2ad6fda6, 0x130cff57, 0x28beb471, 0x06dd6948, 0x16c02bd7, 0x18bb889b, 0x2c305cdb, 0x17301c5d, 0x8e30}}} + }, }; #endif diff --git a/secp256k1.h b/secp256k1.h index 071e7cfd8..c381776e8 100644 --- a/secp256k1.h +++ b/secp256k1.h @@ -49,8 +49,7 @@ extern const bignum256 order256k1_half; extern const bignum256 three_over_two256k1; #if USE_PRECOMPUTED_CP -extern const curve_point secp256k1_cp[256]; -extern const curve_point secp256k1_cp2[255]; +extern const curve_point secp256k1_cp[64][8]; #endif #endif From 2c38929d03846689c4999865c2b34b1269a78c7b Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Tue, 17 Mar 2015 10:34:19 +0100 Subject: [PATCH 171/627] Make scalar_multiply timing attack safe. This should make side-channel attacks much more difficult. However, 1. Timing of bn_inverse, which is used in point_add depends on input. 2. Timing of reading secp256k1_cp may depend on input due to cache. 3. The conditions in point_add are not timing attack safe. However point_add is always a straight addition, never double or some other special case. In the long run, I would like to use a specialized point_add using Jacobian representation plus a randomization when converting the first point to Jacobian representation. The Jacobian representation would also make the procedure a bit faster. --- ecdsa.c | 90 +++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 69 insertions(+), 21 deletions(-) diff --git a/ecdsa.c b/ecdsa.c index 0b012ecb0..85a3fab24 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -195,53 +195,101 @@ int point_is_negative_of(const curve_point *p, const curve_point *q) #if USE_PRECOMPUTED_CP +// Negate a (modulo prime) if cond is 0xffffffff, keep it if cond is 0. +// The timing of this function does not depend on cond. +static void conditional_negate(uint32_t cond, bignum256 *a, const bignum256 *prime) +{ + int j; + uint32_t tmp = 1; + for (j = 0; j < 8; j++) { + tmp += 0x3fffffff + prime->val[j] - a->val[j]; + a->val[j] = ((tmp & 0x3fffffff) & cond) | (a->val[j] & ~cond); + tmp >>= 30; + } + tmp += 0x3fffffff + prime->val[j] - a->val[j]; + a->val[j] = ((tmp & 0x3fffffff) & cond) | (a->val[j] & ~cond); +} + // res = k * G +// k must be a normalized number with 0 <= k < order256k1 void scalar_multiply(const bignum256 *k, curve_point *res) { - int i, j; - // result is zero assert (bn_is_less(k, &order256k1)); - bignum256 a = *k; - int sign = (a.val[0] & 1) ^ 1; + + int i, j; + bignum256 a; + uint32_t is_even = (k->val[0] & 1) - 1; uint32_t lowbits; - // make number odd - if (sign) { - bn_subtract(&order256k1, &a, &a); + + // is_even = 0xffffffff if k is even, 0 otherwise. + + // add 2^256. + // make number odd: subtract order256k1 if even + uint32_t tmp = 1; + uint32_t is_non_zero = 0; + for (j = 0; j < 8; j++) { + is_non_zero |= k->val[j]; + tmp += 0x3fffffff + k->val[j] - (order256k1.val[j] & is_even); + a.val[j] = tmp & 0x3fffffff; + tmp >>= 30; } - a.val[8] |= 0x10000; + is_non_zero |= k->val[j]; + a.val[j] = tmp + 0xffff + k->val[j] - (order256k1.val[j] & is_even); assert((a.val[0] & 1) != 0); - assert((a.val[8] & 0x10000) != 0); - // now compute res = a *G step by step. - // initial res + // special case 0*G: just return zero. We don't care about constant time. + if (!is_non_zero) { + point_set_infinity(res); + return; + } + + // Now a = k + 2^256 (mod order256k1) and a is odd. + // + // The idea is to bring the new a into the form. + // sum_{i=0..64} a[i] 16^i, where |a[i]| < 16 and a[i] is odd. + // a[0] is odd, since a is odd. If a[i] would be even, we can + // add 1 to it and subtract 16 from a[i-1]. Afterwards, + // a[64] = 1, which is the 2^256 that we added before. + // + // Since k = a - 2^256 (mod order256k1), we can compute + // k*G = sum_{i=0..63} a[i] 16^i * G + // + // We have a big table secp256k1_cp that stores all possible + // values of |a[i]| 16^i * G. + // secp256k1_cp[i][j] = (2*j+1) * 16^i * G + + // now compute res = sum_{i=0..63} a[i] * 16^i * G step by step. + // initial res = |a[0]| * G. Note that a[0] = a & 0xf if (a&0x10) != 0 + // and - (16 - (a & 0xf)) otherwise. We can compute this as + // ((a ^ (((a >> 4) & 1) - 1)) & 0xf) >> 1 + // since a is odd. lowbits = a.val[0] & ((1 << 5) - 1); lowbits ^= (lowbits >> 4) - 1; lowbits &= 15; *res = secp256k1_cp[0][lowbits >> 1]; for (i = 1; i < 64; i ++) { - // invariant res = abs((a % 2*16^i) - 16^i) * G + // invariant res = sign(a[i-1]) sum_{j=0..i-1} (a[j] * 16^j * G) + // Note that sign(a[i-1] + // shift a by 4 places. for (j = 0; j < 8; j++) { a.val[j] = (a.val[j] >> 4) | ((a.val[j + 1] & 0xf) << 26); } a.val[j] >>= 4; + // a = old(a)>>(4*i) + // a is even iff sign(a[i-1]) = -1 lowbits = a.val[0] & ((1 << 5) - 1); lowbits ^= (lowbits >> 4) - 1; lowbits &= 15; - if ((lowbits & 1) == 0) { - // negate last result to make signs of this round and the - // last round equal. - bn_subtract(&prime256k1, &res->y, &res->y); - } + // negate last result to make signs of this round and the + // last round equal. + conditional_negate((lowbits & 1) - 1, &res->y, &prime256k1); // add odd factor point_add(&secp256k1_cp[i][lowbits >> 1], res); } - if (sign) { - // negate - bn_subtract(&prime256k1, &res->y, &res->y); - } + conditional_negate(((a.val[0] >> 4) & 1) - 1, &res->y, &prime256k1); } #else From 1700caf2ad0c6cae388e60e60c9ca0c3daf60227 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Tue, 17 Mar 2015 17:41:41 +0100 Subject: [PATCH 172/627] scalar_mult based on Jacobian representation This version of scalar_mult should be faster and much better against side-channel attacks. Except bn_inverse and bn_mod all functions are constant time. bn_inverse is only used in the last step and its input is randomized. The function bn_mod is only taking extra time in 2^32/2^256 cases, so in practise it should not occur at all. The input to bn_mod is also depending on the random value. There is secret dependent array access in scalar_multiply, so cache may be an issue. --- bignum.c | 1 - ecdsa.c | 155 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- tests.c | 2 + 3 files changed, 153 insertions(+), 5 deletions(-) diff --git a/bignum.c b/bignum.c index 45778856b..02060ad3e 100644 --- a/bignum.c +++ b/bignum.c @@ -244,7 +244,6 @@ void bn_fast_mod(bignum256 *x, const bignum256 *prime) uint64_t temp; coef = x->val[8] >> 16; - if (!coef) return; // substract (coef * prime) from x // note that we unrolled the first iteration temp = 0x1000000000000000ull + x->val[0] - prime->val[0] * (uint64_t)coef; diff --git a/ecdsa.c b/ecdsa.c index 85a3fab24..aa2cf46e2 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -210,6 +210,151 @@ static void conditional_negate(uint32_t cond, bignum256 *a, const bignum256 *pri a->val[j] = ((tmp & 0x3fffffff) & cond) | (a->val[j] & ~cond); } +typedef struct jacobian_curve_point { + bignum256 x, y, z; +} jacobian_curve_point; + +static void curve_to_jacobian(const curve_point *p, jacobian_curve_point *jp) { + int i; + // randomize z coordinate + for (i = 0; i < 8; i++) { + jp->z.val[i] = random32() & 0x3FFFFFFF; + } + jp->z.val[8] = (random32() & 0x7fff) + 1; + + jp->x = jp->z; + bn_multiply(&jp->z, &jp->x, &prime256k1); + // x = z^2 + jp->y = jp->x; + bn_multiply(&jp->z, &jp->y, &prime256k1); + // y = z^3 + + bn_multiply(&p->x, &jp->x, &prime256k1); + bn_multiply(&p->y, &jp->y, &prime256k1); + bn_mod(&jp->x, &prime256k1); + bn_mod(&jp->y, &prime256k1); +} + +static void jacobian_to_curve(const jacobian_curve_point *jp, curve_point *p) { + p->y = jp->z; + bn_mod(&p->y, &prime256k1); + bn_inverse(&p->y, &prime256k1); + // p->y = z^-1 + p->x = p->y; + bn_multiply(&p->x, &p->x, &prime256k1); + // p->x = z^-2 + bn_multiply(&p->x, &p->y, &prime256k1); + // p->y = z^-3 + bn_multiply(&jp->x, &p->x, &prime256k1); + // p->x = jp->x * z^-2 + bn_multiply(&jp->y, &p->y, &prime256k1); + // p->y = jp->y * z^-3 + bn_mod(&p->x, &prime256k1); + bn_mod(&p->y, &prime256k1); +} + +static void point_jacobian_add(const curve_point *p1, jacobian_curve_point *p2) { + bignum256 r, h; + bignum256 rsq, hcb, hcby2, hsqx2; + int j; + uint64_t tmp1, tmp2; + + /* usual algorithm: + * + * lambda = (y1 - y2/z2^3) / (x1 - x2/z2^2) + * x3/z3^2 = lambda^2 - x1 - x2/z2^2 + * y3/z3^3 = lambda * (x3/z3 - x2/z2) - y2/z2^3 + * + * to get rid of fraction we set + * r = (y1 * z2^3 - y2) (the numerator of lambda * z2^3) + * h = (x1 * z2^2 - x2) (the denominator of lambda * z2^2) + * Hence, + * lambda = r / (h*z2) + * + * With z3 = h*z2 (the denominator of lambda) + * we get x3 = lambda^2*z3^2 - x1*z3^2 - x2/z2^2*z3^2 + * = r^2 - x1*h^2*z2^2 - x2*h^2 + * = r^2 - h^2*(x1*z2^2 + x2) + * = r^2 - h^2*(h + 2*x2) + * = r^2 - h^3 - 2*h^2*x2 + * and y3 = (lambda * (x2/z2^2 - x3/z3^2) - y2/z2^3) * z3^3 + * = r * (h^2*x2 - x3) - h^3*y2 + */ + + + /* h = x1*z2^2 - x2 + * r = y1*z2^3 - y2 + * x3 = r^2 - h^3 - 2*h^2*x2 + * y3 = r*(h^2*x2 - x3) - h^3*y2 + * z3 = h*z2 + */ + + // h = x1 * z2^2 - x2; + // r = y1 * z2^3 - y2; + h = p2->z; + bn_multiply(&h, &h, &prime256k1); // h = z2^2 + r = p2->z; + bn_multiply(&h, &r, &prime256k1); // r = z2^3 + + bn_multiply(&p1->x, &h, &prime256k1); + bn_subtractmod(&h, &p2->x, &h, &prime256k1); + // h = x1 * z2^2 - x2; + + bn_multiply(&p1->y, &r, &prime256k1); + bn_subtractmod(&r, &p2->y, &r, &prime256k1); + // r = y1 * z2^3 - y2; + + // hsqx2 = h^2 + hsqx2 = h; + bn_multiply(&hsqx2, &hsqx2, &prime256k1); + + // hcb = h^3 + hcb = h; + bn_multiply(&hsqx2, &hcb, &prime256k1); + + // hsqx2 = h^2 * x2 + bn_multiply(&p2->x, &hsqx2, &prime256k1); + + // hcby2 = h^3 * y2 + hcby2 = hcb; + bn_multiply(&p2->y, &hcby2, &prime256k1); + + // rsq = r^2 + rsq = r; + bn_multiply(&rsq, &rsq, &prime256k1); + + // z3 = h*z2 + bn_multiply(&h, &p2->z, &prime256k1); + + // x3 = r^2 - h^3 - 2h^2x2 + // y3 = r*(h^2x2 - x3) - h^3y2 + // compute h^2x2 - x3 = h^3 + 3h^2x2 - r^2 first. + tmp1 = 0; + tmp2 = 0; + for (j = 0; j < 9; j++) { + tmp1 += (uint64_t) rsq.val[j] + 4*prime256k1.val[j] - hcb.val[j] - 2*hsqx2.val[j]; + tmp2 += (uint64_t) hcb.val[j] + 3*hsqx2.val[j] + 2*prime256k1.val[j] - rsq.val[j]; + assert(tmp1 < 5 * 0x40000000ull); + assert(tmp2 < 6 * 0x40000000ull); + p2->x.val[j] = tmp1 & 0x3fffffff; + p2->y.val[j] = tmp2 & 0x3fffffff; + tmp1 >>= 30; + tmp2 >>= 30; + } + + // y3 = r*(h^2x2 - x3) - y2*h^3 + bn_multiply(&r, &p2->y, &prime256k1); + bn_subtractmod(&p2->y, &hcby2, &p2->y, &prime256k1); + + // normalize the numbers + bn_fast_mod(&p2->x, &prime256k1); + bn_mod(&p2->x, &prime256k1); + bn_fast_mod(&p2->y, &prime256k1); + bn_mod(&p2->y, &prime256k1); + bn_mod(&p2->z, &prime256k1); +} + + // res = k * G // k must be a normalized number with 0 <= k < order256k1 void scalar_multiply(const bignum256 *k, curve_point *res) @@ -220,6 +365,7 @@ void scalar_multiply(const bignum256 *k, curve_point *res) bignum256 a; uint32_t is_even = (k->val[0] & 1) - 1; uint32_t lowbits; + jacobian_curve_point jres; // is_even = 0xffffffff if k is even, 0 otherwise. @@ -266,7 +412,7 @@ void scalar_multiply(const bignum256 *k, curve_point *res) lowbits = a.val[0] & ((1 << 5) - 1); lowbits ^= (lowbits >> 4) - 1; lowbits &= 15; - *res = secp256k1_cp[0][lowbits >> 1]; + curve_to_jacobian(&secp256k1_cp[0][lowbits >> 1], &jres); for (i = 1; i < 64; i ++) { // invariant res = sign(a[i-1]) sum_{j=0..i-1} (a[j] * 16^j * G) // Note that sign(a[i-1] @@ -284,12 +430,13 @@ void scalar_multiply(const bignum256 *k, curve_point *res) lowbits &= 15; // negate last result to make signs of this round and the // last round equal. - conditional_negate((lowbits & 1) - 1, &res->y, &prime256k1); + conditional_negate((lowbits & 1) - 1, &jres.y, &prime256k1); // add odd factor - point_add(&secp256k1_cp[i][lowbits >> 1], res); + point_jacobian_add(&secp256k1_cp[i][lowbits >> 1], &jres); } - conditional_negate(((a.val[0] >> 4) & 1) - 1, &res->y, &prime256k1); + conditional_negate(((a.val[0] >> 4) & 1) - 1, &jres.y, &prime256k1); + jacobian_to_curve(&jres, res); } #else diff --git a/tests.c b/tests.c index 57dc0c9b0..982582adc 100644 --- a/tests.c +++ b/tests.c @@ -34,6 +34,7 @@ #include "bip39.h" #include "ecdsa.h" #include "pbkdf2.h" +#include "rand.h" #include "sha2.h" #include "options.h" @@ -1271,6 +1272,7 @@ Suite *test_suite(void) int main(void) { int number_failed; + init_rand(); // needed for scalar_multiply() Suite *s = test_suite(); SRunner *sr = srunner_create(s); srunner_run_all(sr, CK_VERBOSE); From 1b42fde8527f13d957a88da35829bd72e82b2b65 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Fri, 20 Mar 2015 21:36:01 +0100 Subject: [PATCH 173/627] Off by one error in word length. This could lead to a buffer overrun if the final 0 byte is written to current_word[j] after the loop. Also document the limit of passphrase in mnemonic_to_seed. --- bip39.c | 3 ++- bip39.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/bip39.c b/bip39.c index 7c7858580..5985fe819 100644 --- a/bip39.c +++ b/bip39.c @@ -103,7 +103,7 @@ int mnemonic_check(const char *mnemonic) while (mnemonic[i]) { j = 0; while (mnemonic[i] != ' ' && mnemonic[i] != 0) { - if (j >= sizeof(current_word)) { + if (j >= sizeof(current_word) - 1) { return 0; } current_word[j] = mnemonic[i]; @@ -145,6 +145,7 @@ int mnemonic_check(const char *mnemonic) return 0; } +// passphrase must be at most 256 characters or code may crash void mnemonic_to_seed(const char *mnemonic, const char *passphrase, uint8_t seed[512 / 8], void (*progress_callback)(uint32_t current, uint32_t total)) { uint8_t salt[8 + 256 + 4]; diff --git a/bip39.h b/bip39.h index fe4d99e8a..24a5b8d1b 100644 --- a/bip39.h +++ b/bip39.h @@ -34,6 +34,7 @@ const char *mnemonic_from_data(const uint8_t *data, int len); int mnemonic_check(const char *mnemonic); +// passphrase must be at most 256 characters or code may crash void mnemonic_to_seed(const char *mnemonic, const char *passphrase, uint8_t seed[512 / 8], void (*progress_callback)(uint32_t current, uint32_t total)); const char * const *mnemonic_wordlist(void); From edf0fc4902fa4b4eeadce1341531f43a377f1cbd Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Sat, 21 Mar 2015 20:59:23 +0100 Subject: [PATCH 174/627] New fast variant of point_multiply. Use a similar algorithm for `point_multiply` as for `scalar_multiply` but with less precomputation. Added double for points in Jacobian coordinates. Simplified `point_jacobian_add` a little. --- ecdsa.c | 244 +++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 190 insertions(+), 54 deletions(-) diff --git a/ecdsa.c b/ecdsa.c index aa2cf46e2..fcb0c3a64 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -131,31 +131,6 @@ void point_double(curve_point *cp) bn_mod(&(cp->y), &prime256k1); } -// res = k * p -void point_multiply(const bignum256 *k, const curve_point *p, curve_point *res) -{ - int i, j; - // result is zero - int is_zero = 1; - curve_point curr; - // initial res - memcpy(&curr, p, sizeof(curve_point)); - for (i = 0; i < 9; i++) { - for (j = 0; j < 30; j++) { - if (i == 8 && (k->val[i] >> j) == 0) break; - if (k->val[i] & (1u << j)) { - if (is_zero) { - memcpy(res, &curr, sizeof(curve_point)); - is_zero = 0; - } else { - point_add(&curr, res); - } - } - point_double(&curr); - } - } -} - // set point to internal representation of point at infinity void point_set_infinity(curve_point *p) { @@ -193,8 +168,6 @@ int point_is_negative_of(const curve_point *p, const curve_point *q) return !bn_is_equal(&(p->y), &(q->y)); } -#if USE_PRECOMPUTED_CP - // Negate a (modulo prime) if cond is 0xffffffff, keep it if cond is 0. // The timing of this function does not depend on cond. static void conditional_negate(uint32_t cond, bignum256 *a, const bignum256 *prime) @@ -257,13 +230,13 @@ static void point_jacobian_add(const curve_point *p1, jacobian_curve_point *p2) bignum256 r, h; bignum256 rsq, hcb, hcby2, hsqx2; int j; - uint64_t tmp1, tmp2; + uint64_t tmp1; /* usual algorithm: * * lambda = (y1 - y2/z2^3) / (x1 - x2/z2^2) * x3/z3^2 = lambda^2 - x1 - x2/z2^2 - * y3/z3^3 = lambda * (x3/z3 - x2/z2) - y2/z2^3 + * y3/z3^3 = lambda * (x2/z2^2 - x3/z3^2) - y2/z2^3 * * to get rid of fraction we set * r = (y1 * z2^3 - y2) (the numerator of lambda * z2^3) @@ -325,35 +298,208 @@ static void point_jacobian_add(const curve_point *p1, jacobian_curve_point *p2) // z3 = h*z2 bn_multiply(&h, &p2->z, &prime256k1); + bn_mod(&p2->z, &prime256k1); // x3 = r^2 - h^3 - 2h^2x2 - // y3 = r*(h^2x2 - x3) - h^3y2 - // compute h^2x2 - x3 = h^3 + 3h^2x2 - r^2 first. tmp1 = 0; - tmp2 = 0; for (j = 0; j < 9; j++) { tmp1 += (uint64_t) rsq.val[j] + 4*prime256k1.val[j] - hcb.val[j] - 2*hsqx2.val[j]; - tmp2 += (uint64_t) hcb.val[j] + 3*hsqx2.val[j] + 2*prime256k1.val[j] - rsq.val[j]; assert(tmp1 < 5 * 0x40000000ull); - assert(tmp2 < 6 * 0x40000000ull); p2->x.val[j] = tmp1 & 0x3fffffff; - p2->y.val[j] = tmp2 & 0x3fffffff; tmp1 >>= 30; - tmp2 >>= 30; } - + bn_fast_mod(&p2->x, &prime256k1); + bn_mod(&p2->x, &prime256k1); + // y3 = r*(h^2x2 - x3) - y2*h^3 + bn_subtractmod(&hsqx2, &p2->x, &p2->y, &prime256k1); bn_multiply(&r, &p2->y, &prime256k1); bn_subtractmod(&p2->y, &hcby2, &p2->y, &prime256k1); - - // normalize the numbers - bn_fast_mod(&p2->x, &prime256k1); - bn_mod(&p2->x, &prime256k1); bn_fast_mod(&p2->y, &prime256k1); bn_mod(&p2->y, &prime256k1); - bn_mod(&p2->z, &prime256k1); } +static void point_jacobian_double(jacobian_curve_point *p) { + bignum256 m, msq, ysq, xysq; + int j; + uint32_t tmp1, tmp2; + uint32_t modd; + + /* usual algorithm: + * + * lambda = (3(x/z^2)^2 / 2y/z^3) = 3x^2/2yz + * x3/z3^2 = lambda^2 - 2x/z^2 + * y3/z3^3 = lambda * (x/z^2 - x3/z3^2) - y/z^3 + * + * to get rid of fraction we set + * m = 3/2 x^2 + * Hence, + * lambda = m / yz + * + * With z3 = 2yz (the denominator of lambda) + * we get x3 = lambda^2*z3^2 - 2*x/z^2*z3^2 + * = m^2 - 2*xy^2 + * and y3 = (lambda * (x/z^2 - x3/z3^2) - y/z^3) * z3^3 + * = m * (xy^2 - x3) - y^4 + */ + + + /* m = 3/2*x*x + * x3 = m^2 - 2*xy^2 + * y3 = m*(xy^2 - x3) - 8y^4 + * z3 = y*z + */ + + m = p->x; + bn_multiply(&m, &m, &prime256k1); + modd = -(m.val[0] & 1); + // compute m = 3*m/2 mod prime + // if m is odd compute (3*m+prime)/2 + tmp1 = (3*m.val[0] + (prime256k1.val[0] & modd)) >> 1; + for (j = 0; j < 8; j++) { + tmp2 = (3*m.val[j+1] + (prime256k1.val[j+1] & modd)); + tmp1 += (tmp2 & 1) << 29; + m.val[j] = tmp1 & 0x3fffffff; + tmp1 >>= 30; + tmp1 += tmp2 >> 1; + } + m.val[8] = tmp1; + + // msq = m^2 + msq = m; + bn_multiply(&msq, &msq, &prime256k1); + // ysq = y^2 + ysq = p->y; + bn_multiply(&ysq, &ysq, &prime256k1); + // xysq = xy^2 + xysq = p->x; + bn_multiply(&ysq, &xysq, &prime256k1); + bn_multiply(&p->y, &p->z, &prime256k1); + bn_mod(&p->z, &prime256k1); + + // x3 = m^2 - 2*xy^2 + tmp1 = 0; + for (j = 0; j < 9; j++) { + tmp1 += msq.val[j] + 3*prime256k1.val[j] - 2*xysq.val[j]; + p->x.val[j] = tmp1 & 0x3fffffff; + tmp1 >>= 30; + } + bn_fast_mod(&p->x, &prime256k1); + bn_mod(&p->x, &prime256k1); + + // y = m*(xy^2 - x3) - y^4 + bn_subtractmod(&xysq, &p->x, &p->y, &prime256k1); + bn_multiply(&m, &p->y, &prime256k1); + bn_multiply(&ysq, &ysq, &prime256k1); + bn_subtractmod(&p->y, &ysq, &p->y, &prime256k1); + bn_fast_mod(&p->y, &prime256k1); + bn_mod(&p->y, &prime256k1); +} + +// res = k * p +void point_multiply(const bignum256 *k, const curve_point *p, curve_point *res) +{ + // this algorithm is loosely based on + // Katsuyuki Okeya and Tsuyoshi Takagi, The Width-w NAF Method Provides + // Small Memory and Fast Elliptic Scalar Multiplications Secure against + // Side Channel Attacks. + assert (bn_is_less(k, &order256k1)); + + int i, j; + int pos, shift; + bignum256 a; + uint32_t is_even = (k->val[0] & 1) - 1; + uint32_t bits, sign, nsign; + jacobian_curve_point jres; + curve_point pmult[8]; + + // is_even = 0xffffffff if k is even, 0 otherwise. + + // add 2^256. + // make number odd: subtract order256k1 if even + uint32_t tmp = 1; + uint32_t is_non_zero = 0; + for (j = 0; j < 8; j++) { + is_non_zero |= k->val[j]; + tmp += 0x3fffffff + k->val[j] - (order256k1.val[j] & is_even); + a.val[j] = tmp & 0x3fffffff; + tmp >>= 30; + } + is_non_zero |= k->val[j]; + a.val[j] = tmp + 0xffff + k->val[j] - (order256k1.val[j] & is_even); + assert((a.val[0] & 1) != 0); + + // special case 0*p: just return zero. We don't care about constant time. + if (!is_non_zero) { + point_set_infinity(res); + return; + } + + // Now a = k + 2^256 (mod order256k1) and a is odd. + // + // The idea is to bring the new a into the form. + // sum_{i=0..64} a[i] 16^i, where |a[i]| < 16 and a[i] is odd. + // a[0] is odd, since a is odd. If a[i] would be even, we can + // add 1 to it and subtract 16 from a[i-1]. Afterwards, + // a[64] = 1, which is the 2^256 that we added before. + // + // Since k = a - 2^256 (mod order256k1), we can compute + // k*p = sum_{i=0..63} a[i] 16^i * p + // + // We compute |a[i]| * p in advance for all possible + // values of |a[i]| * p. pmult[i] = (2*i+1) * p + // We compute p, 3*p, ..., 15*p and store it in the table pmult. + // store p^2 temporarily in pmult[7] + pmult[7] = *p; + point_double(&pmult[7]); + // compute 3*p, etc by repeatedly adding p^2. + pmult[0] = *p; + for (i = 1; i < 8; i++) { + pmult[i] = pmult[7]; + point_add(&pmult[i-1], &pmult[i]); + } + + // now compute res = sum_{i=0..63} a[i] * 16^i * p step by step, + // starting with i = 63. + // initialize jres = |a[63]| * p. + // Note that a[i] = a>>(4*i) & 0xf if (a&0x10) != 0 + // and - (16 - (a>>(4*i) & 0xf)) otherwise. We can compute this as + // ((a ^ (((a >> 4) & 1) - 1)) & 0xf) >> 1 + // since a is odd. + bits = a.val[8] >> 12; + sign = (bits >> 4) - 1; + bits ^= sign; + bits &= 15; + curve_to_jacobian(&pmult[bits>>1], &jres); + for (i = 62; i >= 0; i--) { + // sign = sign(a[i+1]) (0xffffffff for negative, 0 for positive) + // invariant jres = (-1)^sign sum_{j=i+1..63} (a[j] * 16^{j-i-1} * p) + + point_jacobian_double(&jres); + point_jacobian_double(&jres); + point_jacobian_double(&jres); + point_jacobian_double(&jres); + + // get lowest 5 bits of a >> (i*4). + pos = i*4/30; shift = i*4 % 30; + bits = (a.val[pos+1]<<(30-shift) | a.val[pos] >> shift) & 31; + nsign = (bits >> 4) - 1; + bits ^= nsign; + bits &= 15; + + // negate last result to make signs of this round and the + // last round equal. + conditional_negate(sign ^ nsign, &jres.z, &prime256k1); + + // add odd factor + point_jacobian_add(&pmult[bits >> 1], &jres); + sign = nsign; + } + conditional_negate(sign, &jres.z, &prime256k1); + jacobian_to_curve(&jres, res); +} + +#if USE_PRECOMPUTED_CP // res = k * G // k must be a normalized number with 0 <= k < order256k1 @@ -415,7 +561,6 @@ void scalar_multiply(const bignum256 *k, curve_point *res) curve_to_jacobian(&secp256k1_cp[0][lowbits >> 1], &jres); for (i = 1; i < 64; i ++) { // invariant res = sign(a[i-1]) sum_{j=0..i-1} (a[j] * 16^j * G) - // Note that sign(a[i-1] // shift a by 4 places. for (j = 0; j < 8; j++) { @@ -745,7 +890,6 @@ int ecdsa_verify_double(const uint8_t *pub_key, const uint8_t *sig, const uint8_ // returns 0 if verification succeeded int ecdsa_verify_digest(const uint8_t *pub_key, const uint8_t *sig, const uint8_t *digest) { - int i, j; curve_point pub, res; bignum256 r, s, z; @@ -776,16 +920,8 @@ int ecdsa_verify_digest(const uint8_t *pub_key, const uint8_t *sig, const uint8_ } // both pub and res can be infinity, can have y = 0 OR can be equal -> false negative - for (i = 0; i < 9; i++) { - for (j = 0; j < 30; j++) { - if (i == 8 && (s.val[i] >> j) == 0) break; - if (s.val[i] & (1u << j)) { - point_add(&pub, &res); - } - point_double(&pub); - } - } - + point_multiply(&s, &pub, &pub); + point_add(&pub, &res); bn_mod(&(res.x), &order256k1); // signature does not match From 56f5777b687a99995c92523c39e9ce6390f527a5 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Sun, 22 Mar 2015 17:55:01 +0100 Subject: [PATCH 175/627] Refactored code for point doubling. New function `bn_mult_3_2` that multiplies by 3/2. This function is used in point_double and point_jacobian_double. Cleaned up point_add and point_double, more comments. --- bignum.c | 20 ++++++++++++++++ bignum.h | 2 ++ ecdsa.c | 73 ++++++++++++++++++++++++++------------------------------ 3 files changed, 56 insertions(+), 39 deletions(-) diff --git a/bignum.c b/bignum.c index 02060ad3e..26cb93814 100644 --- a/bignum.c +++ b/bignum.c @@ -139,6 +139,26 @@ void bn_rshift(bignum256 *a) a->val[8] >>= 1; } +// multiply x by 3/2 modulo prime. +// assumes x < 2*prime, +// guarantees x < 4*prime on exit. +void bn_mult_3_2(bignum256 * x, const bignum256 *prime) +{ + int j; + uint32_t xodd = -(x->val[0] & 1); + // compute x = 3*x/2 mod prime + // if x is odd compute (3*x+prime)/2 + uint32_t tmp1 = (3*x->val[0] + (prime->val[0] & xodd)) >> 1; + for (j = 0; j < 8; j++) { + uint32_t tmp2 = (3*x->val[j+1] + (prime->val[j+1] & xodd)); + tmp1 += (tmp2 & 1) << 29; + x->val[j] = tmp1 & 0x3fffffff; + tmp1 >>= 30; + tmp1 += tmp2 >> 1; + } + x->val[8] = tmp1; +} + // assumes x < 2*prime, result < prime void bn_mod(bignum256 *x, const bignum256 *prime) { diff --git a/bignum.h b/bignum.h index 97471b7b1..fa733cd06 100644 --- a/bignum.h +++ b/bignum.h @@ -57,6 +57,8 @@ void bn_lshift(bignum256 *a); void bn_rshift(bignum256 *a); +void bn_mult_3_2(bignum256 *x, const bignum256 *prime); + void bn_mod(bignum256 *x, const bignum256 *prime); void bn_multiply(const bignum256 *k, bignum256 *x, const bignum256 *prime); diff --git a/ecdsa.c b/ecdsa.c index fcb0c3a64..6f076f279 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -37,8 +37,7 @@ // Set cp2 = cp1 void point_copy(const curve_point *cp1, curve_point *cp2) { - memcpy(&(cp2->x), &(cp1->x), sizeof(bignum256)); - memcpy(&(cp2->y), &(cp1->y), sizeof(bignum256)); + *cp2 = *cp1; } // cp2 = cp1 + cp2 @@ -68,7 +67,9 @@ void point_add(const curve_point *cp1, curve_point *cp2) bn_inverse(&inv, &prime256k1); bn_subtractmod(&(cp2->y), &(cp1->y), &lambda, &prime256k1); bn_multiply(&inv, &lambda, &prime256k1); - memcpy(&xr, &lambda, sizeof(bignum256)); + + // xr = lambda^2 - x1 - x2 + xr = lambda; bn_multiply(&xr, &xr, &prime256k1); temp = 1; for (i = 0; i < 9; i++) { @@ -77,16 +78,17 @@ void point_add(const curve_point *cp1, curve_point *cp2) temp >>= 30; } bn_fast_mod(&xr, &prime256k1); + bn_mod(&xr, &prime256k1); + + // yr = lambda (x1 - xr) - y1 bn_subtractmod(&(cp1->x), &xr, &yr, &prime256k1); - // no need to fast_mod here - // bn_fast_mod(&yr); bn_multiply(&lambda, &yr, &prime256k1); bn_subtractmod(&yr, &(cp1->y), &yr, &prime256k1); bn_fast_mod(&yr, &prime256k1); - memcpy(&(cp2->x), &xr, sizeof(bignum256)); - memcpy(&(cp2->y), &yr, sizeof(bignum256)); - bn_mod(&(cp2->x), &prime256k1); - bn_mod(&(cp2->y), &prime256k1); + bn_mod(&yr, &prime256k1); + + cp2->x = xr; + cp2->y = yr; } // cp = cp + cp @@ -94,7 +96,7 @@ void point_double(curve_point *cp) { int i; uint32_t temp; - bignum256 lambda, inverse_y, xr, yr; + bignum256 lambda, xr, yr; if (point_is_infinity(cp)) { return; @@ -104,13 +106,15 @@ void point_double(curve_point *cp) return; } - memcpy(&inverse_y, &(cp->y), sizeof(bignum256)); - bn_inverse(&inverse_y, &prime256k1); - memcpy(&lambda, &three_over_two256k1, sizeof(bignum256)); - bn_multiply(&inverse_y, &lambda, &prime256k1); - bn_multiply(&(cp->x), &lambda, &prime256k1); - bn_multiply(&(cp->x), &lambda, &prime256k1); - memcpy(&xr, &lambda, sizeof(bignum256)); + // lambda = 3/2 x^2 / y + lambda = cp->y; + bn_inverse(&lambda, &prime256k1); + bn_multiply(&cp->x, &lambda, &prime256k1); + bn_multiply(&cp->x, &lambda, &prime256k1); + bn_mult_3_2(&lambda, &prime256k1); + + // xr = lambda^2 - 2*x + xr = lambda; bn_multiply(&xr, &xr, &prime256k1); temp = 1; for (i = 0; i < 9; i++) { @@ -119,16 +123,17 @@ void point_double(curve_point *cp) temp >>= 30; } bn_fast_mod(&xr, &prime256k1); + bn_mod(&xr, &prime256k1); + + // yr = lambda (x - xr) - y bn_subtractmod(&(cp->x), &xr, &yr, &prime256k1); - // no need to fast_mod here - // bn_fast_mod(&yr); bn_multiply(&lambda, &yr, &prime256k1); bn_subtractmod(&yr, &(cp->y), &yr, &prime256k1); bn_fast_mod(&yr, &prime256k1); - memcpy(&(cp->x), &xr, sizeof(bignum256)); - memcpy(&(cp->y), &yr, sizeof(bignum256)); - bn_mod(&(cp->x), &prime256k1); - bn_mod(&(cp->y), &prime256k1); + bn_mod(&yr, &prime256k1); + + cp->x = xr; + cp->y = yr; } // set point to internal representation of point at infinity @@ -322,8 +327,7 @@ static void point_jacobian_add(const curve_point *p1, jacobian_curve_point *p2) static void point_jacobian_double(jacobian_curve_point *p) { bignum256 m, msq, ysq, xysq; int j; - uint32_t tmp1, tmp2; - uint32_t modd; + uint32_t tmp1; /* usual algorithm: * @@ -336,7 +340,7 @@ static void point_jacobian_double(jacobian_curve_point *p) { * Hence, * lambda = m / yz * - * With z3 = 2yz (the denominator of lambda) + * With z3 = yz (the denominator of lambda) * we get x3 = lambda^2*z3^2 - 2*x/z^2*z3^2 * = m^2 - 2*xy^2 * and y3 = (lambda * (x/z^2 - x3/z3^2) - y/z^3) * z3^3 @@ -352,18 +356,7 @@ static void point_jacobian_double(jacobian_curve_point *p) { m = p->x; bn_multiply(&m, &m, &prime256k1); - modd = -(m.val[0] & 1); - // compute m = 3*m/2 mod prime - // if m is odd compute (3*m+prime)/2 - tmp1 = (3*m.val[0] + (prime256k1.val[0] & modd)) >> 1; - for (j = 0; j < 8; j++) { - tmp2 = (3*m.val[j+1] + (prime256k1.val[j+1] & modd)); - tmp1 += (tmp2 & 1) << 29; - m.val[j] = tmp1 & 0x3fffffff; - tmp1 >>= 30; - tmp1 += tmp2 >> 1; - } - m.val[8] = tmp1; + bn_mult_3_2(&m, &prime256k1); // msq = m^2 msq = m; @@ -374,6 +367,8 @@ static void point_jacobian_double(jacobian_curve_point *p) { // xysq = xy^2 xysq = p->x; bn_multiply(&ysq, &xysq, &prime256k1); + + // z3 = yz bn_multiply(&p->y, &p->z, &prime256k1); bn_mod(&p->z, &prime256k1); @@ -387,7 +382,7 @@ static void point_jacobian_double(jacobian_curve_point *p) { bn_fast_mod(&p->x, &prime256k1); bn_mod(&p->x, &prime256k1); - // y = m*(xy^2 - x3) - y^4 + // y3 = m*(xy^2 - x3) - y^4 bn_subtractmod(&xysq, &p->x, &p->y, &prime256k1); bn_multiply(&m, &p->y, &prime256k1); bn_multiply(&ysq, &ysq, &prime256k1); From a5a4333a8e5cb2dbc7460dead15173cd4a0fac44 Mon Sep 17 00:00:00 2001 From: Oleg Andreev Date: Mon, 30 Mar 2015 17:25:34 +0200 Subject: [PATCH 176/627] typo fix (no, this was not a bug) --- ecdsa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ecdsa.c b/ecdsa.c index 0c5b5a625..e910a03f5 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -277,7 +277,7 @@ int generate_k_rfc6979(bignum256 *secret, const uint8_t *priv_key, const uint8_t buf[sizeof(v)] = 0x01; memcpy(buf + sizeof(v) + 1, bx, 64); hmac_sha256(k, sizeof(k), buf, sizeof(buf), k); - hmac_sha256(k, sizeof(k), v, sizeof(k), v); + hmac_sha256(k, sizeof(k), v, sizeof(v), v); for (i = 0; i < 10000; i++) { hmac_sha256(k, sizeof(k), v, sizeof(v), v); From 196cabe0120ffc34a9b160426001fc377fe1ab33 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 30 Mar 2015 17:45:34 +0200 Subject: [PATCH 177/627] import random_uniform and random_permute functions from TREZOR codebase --- rand.c | 26 ++++++++++++++++++++++---- rand.h | 4 +++- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/rand.c b/rand.c index 7251826c8..4b921cabb 100644 --- a/rand.c +++ b/rand.c @@ -35,10 +35,9 @@ void init_rand(void) int finalize_rand(void) { - int err = fclose(f); - f = NULL; - - return err; + int err = fclose(f); + f = NULL; + return err; } uint32_t random32(void) @@ -50,8 +49,27 @@ uint32_t random32(void) return r; } +uint32_t random_uniform(uint32_t n) +{ + uint32_t x, max = 0xFFFFFFFF - (0xFFFFFFFF % n); + while ((x = random32()) >= max); + return x / (max / n); +} + void random_buffer(uint8_t *buf, size_t len) { size_t len_read = fread(buf, 1, len, f); assert(len_read == len); } + +void random_permute(char *str, size_t len) +{ + int i, j; + char t; + for (i = len - 1; i >= 1; i--) { + j = random_uniform(i + 1); + t = str[j]; + str[j] = str[i]; + str[i] = t; + } +} diff --git a/rand.h b/rand.h index 2c7893963..8d8160887 100644 --- a/rand.h +++ b/rand.h @@ -24,12 +24,14 @@ #ifndef __RAND_H__ #define __RAND_H__ -#include #include +#include void init_rand(void); int finalize_rand(void); uint32_t random32(void); +uint32_t random_uniform(uint32_t n); void random_buffer(uint8_t *buf, size_t len); +void random_permute(char *buf, size_t len); #endif From aeefea054ab3419105ce5b6b0dfe00004091530f Mon Sep 17 00:00:00 2001 From: netanelkl Date: Wed, 8 Apr 2015 15:07:15 -0400 Subject: [PATCH 178/627] Added some private key nullification so that they won't be uncontrolled in the stack --- bip32.c | 38 +++++++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/bip32.c b/bip32.c index daf500b8c..a04ae7fcb 100644 --- a/bip32.c +++ b/bip32.c @@ -32,6 +32,8 @@ #include "ripemd160.h" #include "base58.h" +#define MEMSET_BZERO(p,l) memset((p), 0, (l)) + int hdnode_from_xpub(uint32_t depth, uint32_t fingerprint, uint32_t child_num, const uint8_t *chain_code, const uint8_t *public_key, HDNode *out) { if (public_key[0] != 0x02 && public_key[0] != 0x03) { // invalid pubkey @@ -41,7 +43,7 @@ int hdnode_from_xpub(uint32_t depth, uint32_t fingerprint, uint32_t child_num, c out->fingerprint = fingerprint; out->child_num = child_num; memcpy(out->chain_code, chain_code, 32); - memset(out->private_key, 0, 32); + MEMSET_BZERO(out->private_key, 32); memcpy(out->public_key, public_key, 33); return 1; } @@ -50,9 +52,20 @@ int hdnode_from_xprv(uint32_t depth, uint32_t fingerprint, uint32_t child_num, c { bignum256 a; bn_read_be(private_key, &a); - if (bn_is_zero(&a) || !bn_is_less(&a, &order256k1)) { // == 0 or >= order + + bool failed = false; + if (bn_is_zero(&a)) { + failed = true; + } + else if( !bn_is_less(&a, &order256k1)) { // == 0 or >= order + MEMSET_BZERO(&a,sizeof(a)); + failed = true; + } + + if(failed) { return 0; } + out->depth = depth; out->fingerprint = fingerprint; out->child_num = child_num; @@ -73,12 +86,23 @@ int hdnode_from_seed(const uint8_t *seed, int seed_len, HDNode *out) memcpy(out->private_key, I, 32); bignum256 a; bn_read_be(out->private_key, &a); - if (bn_is_zero(&a) || !bn_is_less(&a, &order256k1)) { // == 0 or >= order - return 0; + + bool failed = false; + if (bn_is_zero(&a)) { + failed = true; } - memcpy(out->chain_code, I + 32, 32); - hdnode_fill_public_key(out); - return 1; + else if( !bn_is_less(&a, &order256k1)) { // == 0 or >= order + MEMSET_BZERO(&a,sizeof(a)); + failed = true; + } + + if(!failed) { + memcpy(out->chain_code, I + 32, 32); + hdnode_fill_public_key(out); + } + + MEMSET_BZERO(I,sizeof(I)); + return failed ? 0 : 1; } int hdnode_private_ckd(HDNode *inout, uint32_t i) From 70dc71c87e5d149d2ace69ab6fac400101d384c3 Mon Sep 17 00:00:00 2001 From: netanelkl Date: Thu, 9 Apr 2015 14:14:37 -0400 Subject: [PATCH 179/627] Some more stack memory wipe before leaving functions. Note that I preferred to change the multiple returns to multiple checks of a boolean to concentrate the erase into the last part of the functions. --- base58.c | 9 ++--- bip32.c | 96 +++++++++++++++++++++++++++++++++++---------------- macro_utils.h | 8 +++++ 3 files changed, 80 insertions(+), 33 deletions(-) create mode 100644 macro_utils.h diff --git a/base58.c b/base58.c index 217264e30..444d69596 100644 --- a/base58.c +++ b/base58.c @@ -26,6 +26,7 @@ #include #include "base58.h" #include "sha2.h" +#include "macro_utils.h" static const int8_t b58digits_map[] = { -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, @@ -196,10 +197,10 @@ int base58_encode_check(const uint8_t *data, int datalen, char *str, int strsize sha256_Raw(data, datalen, hash); sha256_Raw(hash, 32, hash); size_t res = strsize; - if (b58enc(str, &res, buf, datalen + 4) != true) { - return 0; - } - return res; + bool fSuccess = b58enc(str, &res, buf, datalen + 4); + + MEMSET_BZERO(buf, sizeof(buf)); + return fSuccess ? res : 0; } int base58_decode_check(const char *str, uint8_t *data, int datalen) diff --git a/bip32.c b/bip32.c index a04ae7fcb..4137e6818 100644 --- a/bip32.c +++ b/bip32.c @@ -31,8 +31,7 @@ #include "sha2.h" #include "ripemd160.h" #include "base58.h" - -#define MEMSET_BZERO(p,l) memset((p), 0, (l)) +#include "macro_utils.h" int hdnode_from_xpub(uint32_t depth, uint32_t fingerprint, uint32_t child_num, const uint8_t *chain_code, const uint8_t *public_key, HDNode *out) { @@ -91,9 +90,14 @@ int hdnode_from_seed(const uint8_t *seed, int seed_len, HDNode *out) if (bn_is_zero(&a)) { failed = true; } - else if( !bn_is_less(&a, &order256k1)) { // == 0 or >= order + else + { + if( !bn_is_less(&a, &order256k1)) { // == 0 or >= order + failed = true; + } + + // Making sure a is wiped. MEMSET_BZERO(&a,sizeof(a)); - failed = true; } if(!failed) { @@ -132,23 +136,36 @@ int hdnode_private_ckd(HDNode *inout, uint32_t i) bn_read_be(inout->private_key, &b); + bool failed = false; + if (!bn_is_less(&b, &order256k1)) { // >= order - return 0; + failed = true; } + if(!failed) { - bn_addmod(&a, &b, &order256k1); + bn_addmod(&a, &b, &order256k1); - if (bn_is_zero(&a)) { - return 0; + if (bn_is_zero(&a)) { + failed = true; + } } - inout->depth++; - inout->child_num = i; - bn_write_be(&a, inout->private_key); + if(!failed) + { + inout->depth++; + inout->child_num = i; + bn_write_be(&a, inout->private_key); - hdnode_fill_public_key(inout); + hdnode_fill_public_key(inout); + } - return 1; + // Making sure to wipe our memory! + MEMSET_BZERO(&a,sizeof(a)); + MEMSET_BZERO(&b,sizeof(b)); + MEMSET_BZERO(I,sizeof(I)); + MEMSET_BZERO(fingerprint,sizeof(fingerprint)); + MEMSET_BZERO(data,sizeof(data)); + return failed ? 0 : 1; } int hdnode_public_ckd(HDNode *inout, uint32_t i) @@ -171,32 +188,51 @@ int hdnode_public_ckd(HDNode *inout, uint32_t i) inout->fingerprint = (fingerprint[0] << 24) + (fingerprint[1] << 16) + (fingerprint[2] << 8) + fingerprint[3]; memset(inout->private_key, 0, 32); + + bool failed = false; if (!ecdsa_read_pubkey(inout->public_key, &a)) { - return 0; + failed = true; } - hmac_sha512(inout->chain_code, 32, data, sizeof(data), I); - memcpy(inout->chain_code, I + 32, 32); - bn_read_be(I, &c); + if(!failed) + { + hmac_sha512(inout->chain_code, 32, data, sizeof(data), I); + memcpy(inout->chain_code, I + 32, 32); + bn_read_be(I, &c); - if (!bn_is_less(&c, &order256k1)) { // >= order - return 0; + if (!bn_is_less(&c, &order256k1)) { // >= order + failed = true; + } } - scalar_multiply(&c, &b); // b = c * G - point_add(&a, &b); // b = a + b + if(!failed) + { + scalar_multiply(&c, &b); // b = c * G + point_add(&a, &b); // b = a + b - if (!ecdsa_validate_pubkey(&b)) { - return 0; + if (!ecdsa_validate_pubkey(&b)) { + failed = true; + } } - inout->public_key[0] = 0x02 | (b.y.val[0] & 0x01); - bn_write_be(&b.x, inout->public_key + 1); + if(!failed) + { + inout->public_key[0] = 0x02 | (b.y.val[0] & 0x01); + bn_write_be(&b.x, inout->public_key + 1); - inout->depth++; - inout->child_num = i; + inout->depth++; + inout->child_num = i; + } - return 1; + // Wipe all stack data. + MEMSET_BZERO(data,sizeof(data)); + MEMSET_BZERO(I,sizeof(I)); + MEMSET_BZERO(fingerprint,sizeof(fingerprint)); + MEMSET_BZERO(&a,sizeof(a)); + MEMSET_BZERO(&b,sizeof(b)); + MEMSET_BZERO(&c,sizeof(c)); + + return failed ? 0 : 1; } #if USE_BIP32_CACHE @@ -286,7 +322,9 @@ void hdnode_serialize(const HDNode *node, uint32_t version, char use_public, cha node_data[45] = 0; memcpy(node_data + 46, node->private_key, 32); } - base58_encode_check(node_data, 78, str, strsize); + base58_encode_check(node_data, sizeof(node_data), str, strsize); + + MEMSET_BZERO(node_data, sizeof(node_data)); } void hdnode_serialize_public(const HDNode *node, char *str, int strsize) diff --git a/macro_utils.h b/macro_utils.h new file mode 100644 index 000000000..54634f8d1 --- /dev/null +++ b/macro_utils.h @@ -0,0 +1,8 @@ + +#if !defined( _MACRO_UTILS_H ) +#define _MACRO_UTILS_H + +#define MEMSET_BZERO(p,l) memset((p), 0, (l)) + + +#endif From 3fd32df8edf9f22b630c7beac64aa4be5077e1db Mon Sep 17 00:00:00 2001 From: netanelkl Date: Thu, 9 Apr 2015 15:05:28 -0400 Subject: [PATCH 180/627] More of the same. --- bignum.c | 12 +++++ ecdsa.c | 134 ++++++++++++++++++++++++++++++++++++++----------------- hmac.c | 9 ++++ pbkdf2.c | 7 +++ 4 files changed, 122 insertions(+), 40 deletions(-) diff --git a/bignum.c b/bignum.c index 26cb93814..134f8ee08 100644 --- a/bignum.c +++ b/bignum.c @@ -26,6 +26,7 @@ #include #include "bignum.h" #include "secp256k1.h" +#include "macro_utils.h" inline uint32_t read_be(const uint8_t *data) { @@ -252,6 +253,8 @@ void bn_multiply(const bignum256 *k, bignum256 *x, const bignum256 *prime) for (i = 0; i < 9; i++) { x->val[i] = res[i]; } + + MEMSET_BZERO(res,sizeof(res)); } // input x can be any normalized number that fits (0 <= x < 2^270). @@ -309,6 +312,10 @@ void bn_sqrt(bignum256 *x, const bignum256 *prime) } bn_mod(&res, prime); memcpy(x, &res, sizeof(bignum256)); + + MEMSET_BZERO(&res, sizeof(res)); + MEMSET_BZERO(&p, sizeof(p)); + } #if ! USE_INVERSE_FAST @@ -614,6 +621,11 @@ void bn_inverse(bignum256 *x, const bignum256 *prime) temp32 = us.a[8-i] >> (30 - 2 * i); } x->val[i] = temp32; + + // Let's wipe all temp buffers. + MEMSET_BZERO(pp, sizeof(pp)); + MEMSET_BZERO(&us, sizeof(us)); + MEMSET_BZERO(&vr, sizeof(vr)); } #endif diff --git a/ecdsa.c b/ecdsa.c index 05efc9771..8fe28f7f5 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -33,6 +33,7 @@ #include "hmac.h" #include "ecdsa.h" #include "base58.h" +#include "macro_utils.h" // Set cp2 = cp1 void point_copy(const curve_point *cp1, curve_point *cp2) @@ -654,7 +655,11 @@ int ecdsa_sign(const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, ui { uint8_t hash[32]; sha256_Raw(msg, msg_len, hash); - return ecdsa_sign_digest(priv_key, hash, sig, pby); + int res = ecdsa_sign_digest(priv_key, hash, sig, pby); + + MEMSET_BZERO(hash, sizeof(hash)); + return res; + } // msg is a data to be signed @@ -664,7 +669,11 @@ int ecdsa_sign_double(const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_ uint8_t hash[32]; sha256_Raw(msg, msg_len, hash); sha256_Raw(hash, 32, hash); - return ecdsa_sign_digest(priv_key, hash, sig, pby); + int res = ecdsa_sign_digest(priv_key, hash, sig, pby); + + MEMSET_BZERO(hash, sizeof(hash)); + + return res; } // uses secp256k1 curve @@ -677,56 +686,71 @@ int ecdsa_sign_digest(const uint8_t *priv_key, const uint8_t *digest, uint8_t *s curve_point R; bignum256 k, z; bignum256 *da = &R.y; - + int result = 0; bn_read_be(digest, &z); #if USE_RFC6979 // generate K deterministically if (generate_k_rfc6979(&k, priv_key, digest) != 0) { - return 1; + result = 1; } #else // generate random number k if (generate_k_random(&k) != 0) { - return 1; + result = 1; } #endif - // compute k*G - scalar_multiply(&k, &R); - if (pby) { - *pby = R.y.val[0] & 1; - } - // r = (rx mod n) - bn_mod(&R.x, &order256k1); - // if r is zero, we fail - if (bn_is_zero(&R.x)) return 2; - bn_inverse(&k, &order256k1); - bn_read_be(priv_key, da); - bn_multiply(&R.x, da, &order256k1); - for (i = 0; i < 8; i++) { - da->val[i] += z.val[i]; - da->val[i + 1] += (da->val[i] >> 30); - da->val[i] &= 0x3FFFFFFF; - } - da->val[8] += z.val[8]; - bn_multiply(da, &k, &order256k1); - bn_mod(&k, &order256k1); - // if k is zero, we fail - if (bn_is_zero(&k)) return 3; - - // if S > order/2 => S = -S - if (bn_is_less(&order256k1_half, &k)) { - bn_subtract(&order256k1, &k, &k); + if(result == 0) { + // compute k*G + scalar_multiply(&k, &R); if (pby) { - *pby = !*pby; + *pby = R.y.val[0] & 1; + } + // r = (rx mod n) + bn_mod(&R.x, &order256k1); + // if r is zero, we fail + if (bn_is_zero(&R.x)) + { + result = 2; + } + } + + if(result == 0) { + bn_inverse(&k, &order256k1); + bn_read_be(priv_key, da); + bn_multiply(&R.x, da, &order256k1); + for (i = 0; i < 8; i++) { + da->val[i] += z.val[i]; + da->val[i + 1] += (da->val[i] >> 30); + da->val[i] &= 0x3FFFFFFF; + } + da->val[8] += z.val[8]; + bn_multiply(da, &k, &order256k1); + bn_mod(&k, &order256k1); + // if k is zero, we fail + if (bn_is_zero(&k)) { + result = 3; } } - // we are done, R.x and k is the result signature - bn_write_be(&R.x, sig); - bn_write_be(&k, sig + 32); + if(result == 0) + { + // if S > order/2 => S = -S + if (bn_is_less(&order256k1_half, &k)) { + bn_subtract(&order256k1, &k, &k); + if (pby) { + *pby = !*pby; + } + } + // we are done, R.x and k is the result signature + bn_write_be(&R.x, sig); + bn_write_be(&k, sig + 32); + } + MEMSET_BZERO(&k,sizeof(k)); + MEMSET_BZERO(&z,sizeof(z)); + MEMSET_BZERO(&R,sizeof(R)); return 0; } @@ -740,6 +764,8 @@ void ecdsa_get_public_key33(const uint8_t *priv_key, uint8_t *pub_key) scalar_multiply(&k, &R); pub_key[0] = 0x02 | (R.y.val[0] & 0x01); bn_write_be(&R.x, pub_key + 1); + MEMSET_BZERO(&R,sizeof(R)); + MEMSET_BZERO(&k,sizeof(k)); } void ecdsa_get_public_key65(const uint8_t *priv_key, uint8_t *pub_key) @@ -753,6 +779,8 @@ void ecdsa_get_public_key65(const uint8_t *priv_key, uint8_t *pub_key) pub_key[0] = 0x04; bn_write_be(&R.x, pub_key + 1); bn_write_be(&R.y, pub_key + 33); + MEMSET_BZERO(&R,sizeof(R)); + MEMSET_BZERO(&k,sizeof(k)); } void ecdsa_get_pubkeyhash(const uint8_t *pub_key, uint8_t *pubkeyhash) @@ -766,6 +794,7 @@ void ecdsa_get_pubkeyhash(const uint8_t *pub_key, uint8_t *pubkeyhash) sha256_Raw(pub_key, 33, h); // expecting compressed format } ripemd160(h, 32, pubkeyhash); + MEMSET_BZERO(h,sizeof(h)); } void ecdsa_get_address_raw(const uint8_t *pub_key, uint8_t version, uint8_t *addr_raw) @@ -779,6 +808,9 @@ void ecdsa_get_address(const uint8_t *pub_key, uint8_t version, char *addr, int uint8_t raw[21]; ecdsa_get_address_raw(pub_key, version, raw); base58_encode_check(raw, 21, addr, addrsize); + + // Not as important to clear this one, but we might as well. + MEMSET_BZERO(raw,sizeof(raw)); } void ecdsa_get_wif(const uint8_t *priv_key, uint8_t version, char *wif, int wifsize) @@ -788,6 +820,9 @@ void ecdsa_get_wif(const uint8_t *priv_key, uint8_t version, char *wif, int wifs memcpy(data + 1, priv_key, 32); data[33] = 0x01; base58_encode_check(data, 34, wif, wifsize); + + // This private keys running around our stack can cause trouble! + MEMSET_BZERO(data,sizeof(data)); } int ecdsa_address_decode(const char *addr, uint8_t *out) @@ -871,7 +906,10 @@ int ecdsa_verify(const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, { uint8_t hash[32]; sha256_Raw(msg, msg_len, hash); - return ecdsa_verify_digest(pub_key, sig, hash); + int res = ecdsa_verify_digest(pub_key, sig, hash); + + MEMSET_BZERO(hash,sizeof(hash)); + return res; } int ecdsa_verify_double(const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, uint32_t msg_len) @@ -879,7 +917,11 @@ int ecdsa_verify_double(const uint8_t *pub_key, const uint8_t *sig, const uint8_ uint8_t hash[32]; sha256_Raw(msg, msg_len, hash); sha256_Raw(hash, 32, hash); - return ecdsa_verify_digest(pub_key, sig, hash); + + int res = ecdsa_verify_digest(pub_key, sig, hash); + + MEMSET_BZERO(hash,sizeof(hash)); + return res; } // returns 0 if verification succeeded @@ -906,24 +948,36 @@ int ecdsa_verify_digest(const uint8_t *pub_key, const uint8_t *sig, const uint8_ bn_mod(&z, &order256k1); bn_multiply(&r, &s, &order256k1); // r*s^-1 bn_mod(&s, &order256k1); + + int result = 0; if (bn_is_zero(&z)) { // our message hashes to zero // I don't expect this to happen any time soon - return 3; + result = 3; } else { scalar_multiply(&z, &res); } + if(result == 0) { + // both pub and res can be infinity, can have y = 0 OR can be equal -> false negative point_multiply(&s, &pub, &pub); point_add(&pub, &res); bn_mod(&(res.x), &order256k1); // signature does not match - if (!bn_is_equal(&res.x, &r)) return 5; + if (!bn_is_equal(&res.x, &r)) { + result = 5; + } + } + MEMSET_BZERO(&pub,sizeof(pub)); + MEMSET_BZERO(&res,sizeof(res)); + MEMSET_BZERO(&r,sizeof(r)); + MEMSET_BZERO(&s,sizeof(s)); + MEMSET_BZERO(&z,sizeof(z)); // all OK - return 0; + return result; } int ecdsa_sig_to_der(const uint8_t *sig, uint8_t *der) diff --git a/hmac.c b/hmac.c index a8d95ff8d..a43d2a7a6 100644 --- a/hmac.c +++ b/hmac.c @@ -25,6 +25,7 @@ #include "hmac.h" #include "sha2.h" +#include "macro_utils.h" void hmac_sha256(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, const uint32_t msglen, uint8_t *hmac) { @@ -53,6 +54,10 @@ void hmac_sha256(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, sha256_Update(&ctx, o_key_pad, SHA256_BLOCK_LENGTH); sha256_Update(&ctx, buf, SHA256_DIGEST_LENGTH); sha256_Final(hmac, &ctx); + MEMSET_BZERO(buf,sizeof(buf)); + MEMSET_BZERO(o_key_pad,sizeof(o_key_pad)); + MEMSET_BZERO(i_key_pad,sizeof(i_key_pad)); + } void hmac_sha512(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, const uint32_t msglen, uint8_t *hmac) @@ -82,4 +87,8 @@ void hmac_sha512(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, sha512_Update(&ctx, o_key_pad, SHA512_BLOCK_LENGTH); sha512_Update(&ctx, buf, SHA512_DIGEST_LENGTH); sha512_Final(hmac, &ctx); + + MEMSET_BZERO(buf,sizeof(buf)); + MEMSET_BZERO(o_key_pad,sizeof(o_key_pad)); + MEMSET_BZERO(i_key_pad,sizeof(i_key_pad)); } diff --git a/pbkdf2.c b/pbkdf2.c index 2271f997c..256ef86e1 100644 --- a/pbkdf2.c +++ b/pbkdf2.c @@ -24,6 +24,7 @@ #include #include "pbkdf2.h" #include "hmac.h" +#include "macro_utils.h" void pbkdf2_hmac_sha256(const uint8_t *pass, int passlen, uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key, int keylen, void (*progress_callback)(uint32_t current, uint32_t total)) { @@ -56,6 +57,9 @@ void pbkdf2_hmac_sha256(const uint8_t *pass, int passlen, uint8_t *salt, int sal memcpy(key + HMACLEN * (i - 1), f, HMACLEN); } } + + MEMSET_BZERO(f,sizeof(f)); + MEMSET_BZERO(g, sizeof(g)); } void pbkdf2_hmac_sha512(const uint8_t *pass, int passlen, uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key, int keylen, void (*progress_callback)(uint32_t current, uint32_t total)) @@ -89,4 +93,7 @@ void pbkdf2_hmac_sha512(const uint8_t *pass, int passlen, uint8_t *salt, int sal memcpy(key + HMACLEN * (i - 1), f, HMACLEN); } } + + MEMSET_BZERO(f,sizeof(f)); + MEMSET_BZERO(g, sizeof(g)); } From e432d772c70e824837b966c809dc1754335d84bd Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Fri, 10 Apr 2015 19:14:59 +0200 Subject: [PATCH 181/627] Program to precompute the table for scalar_mult This program pre-computes the table and prints then in the form that can be included in secp256k1.c --- tools/.gitignore | 1 + tools/Makefile | 7 ++++-- tools/README.md | 8 ++++++ tools/mksecptable.c | 59 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 73 insertions(+), 2 deletions(-) create mode 100644 tools/mksecptable.c diff --git a/tools/.gitignore b/tools/.gitignore index ac00e6bcd..3073e2e52 100644 --- a/tools/.gitignore +++ b/tools/.gitignore @@ -1 +1,2 @@ xpubaddrgen +mksecptable diff --git a/tools/Makefile b/tools/Makefile index 67c652637..519bb1de9 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -23,7 +23,7 @@ CFLAGS += $(OPTFLAGS) \ -Werror \ -I.. -all: xpubaddrgen +all: xpubaddrgen mksecptable OBJS = ../bip32.o ../ecdsa.o ../sha2.o ../bignum.o ../base58.o ../secp256k1.o ../ripemd160.o ../hmac.o ../rand.o @@ -33,5 +33,8 @@ OBJS = ../bip32.o ../ecdsa.o ../sha2.o ../bignum.o ../base58.o ../secp256k1.o .. xpubaddrgen: xpubaddrgen.o $(OBJS) $(CC) xpubaddrgen.o $(OBJS) -o xpubaddrgen +mksecptable: mksecptable.o $(OBJS) + $(CC) mksecptable.o $(OBJS) -o mksecptable + clean: - rm -f *.o xpubaddrgen + rm -f *.o xpubaddrgen mksecptable diff --git a/tools/README.md b/tools/README.md index 8f24f19ab..93ea9fb1d 100644 --- a/tools/README.md +++ b/tools/README.md @@ -43,3 +43,11 @@ Example output: It will print ``` error``` when there was an error processing job jobid. It will print ```error``` when it encountered a malformed line. + + +mksecptable +----------- + +mksecptable computes the points of the form `(2*j+1)*16^i*G` and prints them in the format to be included in `secp256k1.c`. These points are used by the fast ECC multiplication. + +It is only meant to be run if the `scalar_mult` algorithm changes. diff --git a/tools/mksecptable.c b/tools/mksecptable.c new file mode 100644 index 000000000..e6a1997d9 --- /dev/null +++ b/tools/mksecptable.c @@ -0,0 +1,59 @@ +#include +#include +#include "bignum.h" +#include "ecdsa.h" +#include "secp256k1.h" +#include "rand.h" + +/* + * This program prints the contents of the secp256k1_cp array. + * The entry secp256k1_cp[i][j] contains the number (2*j+1)*16^i*G, + * where G is the generator of secp256k1. + */ +int main(int __attribute__((unused)) argc, char __attribute__((unused)) **argv) { + int i,j,k; + curve_point ng = G256k1; + curve_point pow2ig = G256k1; +#ifndef NDEBUG + init_rand(); // needed for point_multiply() +#endif + for (i = 0; i < 64; i++) { + // invariants: + // pow2ig = 16^i * G + // ng = pow2ig + printf("\t{\n"); + for (j = 0; j < 8; j++) { + // invariants: + // pow2ig = 16^i * G + // ng = (2*j+1) * 16^i * G +#ifndef NDEBUG + curve_point checkresult; + bignum256 a; + bn_zero(&a); + a.val[(4*i) / 30] = ((uint32_t) 2*j+1) << ((4*i) % 30); + bn_normalize(&a); + point_multiply(&a, &G256k1, &checkresult); + assert(point_is_equal(&checkresult, &ng)); +#endif + printf("\t\t/* %2d*16^%d*G: */\n\t\t{{{", 2*j + 1, i); + // print x coordinate + for (k = 0; k < 9; k++) { + printf((k < 8 ? "0x%08x, " : "0x%04x"), ng.x.val[k]); + } + printf("}},\n\t\t {{"); + // print y coordinate + for (k = 0; k < 9; k++) { + printf((k < 8 ? "0x%08x, " : "0x%04x"), ng.y.val[k]); + } + if (j == 7) { + printf("}}}\n\t},\n"); + } else { + printf("}}},\n"); + point_add(&pow2ig, &ng); + } + point_add(&pow2ig, &ng); + } + pow2ig = ng; + } + return 0; +} From c90f79bce232ed4e0161f3f7e705824a14f439c0 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Sat, 11 Apr 2015 12:48:24 +0200 Subject: [PATCH 182/627] Added new tests for point multiplication --- tests.c | 174 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 173 insertions(+), 1 deletion(-) diff --git a/tests.c b/tests.c index 982582adc..d359fa7af 100644 --- a/tests.c +++ b/tests.c @@ -1030,7 +1030,7 @@ END_TEST START_TEST(test_pubkey_validity) { uint8_t pub_key[65]; - curve_point pub; + curve_point pub; int res; memcpy(pub_key, fromhex("0226659c1cf7321c178c07437150639ff0c5b7679c7ea195253ed9abda2e081a37"), 33); @@ -1203,6 +1203,157 @@ START_TEST(test_ecdsa_der) } END_TEST +START_TEST(test_secp256k1_cp) { + int i, j; + bignum256 a; + curve_point p, p1; + for (i = 0; i < 64; i++) { + for (j = 0; j < 8; j++) { + bn_zero(&a); + a.val[(4*i)/30] = (2*j+1) << (4*i % 30); + bn_normalize(&a); + // note that this is not a trivial test. We add 64 curve + // points in the table to get that particular curve point. + scalar_multiply(&a, &p); + ck_assert_mem_eq(&p, &secp256k1_cp[i][j], sizeof(curve_point)); + bn_zero(&p.y); // test that point_multiply is not a noop + point_multiply(&a, &G256k1, &p); + ck_assert_mem_eq(&p, &secp256k1_cp[i][j], sizeof(curve_point)); + + // even/odd has different behaviour; + // increment by one and test again + p1 = p; + point_add(&G256k1, &p1); + bn_addmodi(&a, 1, &order256k1); + scalar_multiply(&a, &p); + ck_assert_mem_eq(&p, &p1, sizeof(curve_point)); + bn_zero(&p.y); // test that point_multiply is not a noop + point_multiply(&a, &G256k1, &p); + ck_assert_mem_eq(&p, &p1, sizeof(curve_point)); + } + } +} +END_TEST + +START_TEST(test_mult_border_cases) { + bignum256 a; + curve_point p; + curve_point expected; + bn_zero(&a); // a == 0 + scalar_multiply(&a, &p); + ck_assert(point_is_infinity(&p)); + point_multiply(&a, &p, &p); + ck_assert(point_is_infinity(&p)); + point_multiply(&a, &G256k1, &p); + ck_assert(point_is_infinity(&p)); + + bn_addmodi(&a, 1, &order256k1); // a == 1 + scalar_multiply(&a, &p); + ck_assert_mem_eq(&p, &G256k1, sizeof(curve_point)); + point_multiply(&a, &G256k1, &p); + ck_assert_mem_eq(&p, &G256k1, sizeof(curve_point)); + + bn_subtract(&order256k1, &a, &a); // a == -1 + expected = G256k1; + bn_subtract(&prime256k1, &expected.y, &expected.y); + scalar_multiply(&a, &p); + ck_assert_mem_eq(&p, &expected, sizeof(curve_point)); + point_multiply(&a, &G256k1, &p); + ck_assert_mem_eq(&p, &expected, sizeof(curve_point)); + + bn_subtract(&order256k1, &a, &a); + bn_addmodi(&a, 1, &order256k1); // a == 2 + expected = G256k1; + point_add(&expected, &expected); + scalar_multiply(&a, &p); + ck_assert_mem_eq(&p, &expected, sizeof(curve_point)); + point_multiply(&a, &G256k1, &p); + ck_assert_mem_eq(&p, &expected, sizeof(curve_point)); + + bn_subtract(&order256k1, &a, &a); // a == -2 + expected = G256k1; + point_add(&expected, &expected); + bn_subtract(&prime256k1, &expected.y, &expected.y); + scalar_multiply(&a, &p); + ck_assert_mem_eq(&p, &expected, sizeof(curve_point)); + point_multiply(&a, &G256k1, &p); + ck_assert_mem_eq(&p, &expected, sizeof(curve_point)); +} +END_TEST + +START_TEST(test_scalar_mult) { + int i; + // get two "random" numbers + bignum256 a = G256k1.x; + bignum256 b = G256k1.y; + curve_point p1, p2, p3; + for (i = 0; i < 1000; i++) { + /* test distributivity: (a + b)G = aG + bG */ + scalar_multiply(&a, &p1); + scalar_multiply(&b, &p2); + bn_addmod(&a, &b, &order256k1); + scalar_multiply(&a, &p3); + point_add(&p1, &p2); + ck_assert_mem_eq(&p2, &p3, sizeof(curve_point)); + // new "random" numbers + a = p3.x; + b = p3.y; + } +} +END_TEST + +START_TEST(test_point_mult) { + int i; + // get two "random" numbers and a "random" point + bignum256 a = G256k1.x; + bignum256 b = G256k1.y; + curve_point p = G256k1; + curve_point p1, p2, p3; + for (i = 0; i < 200; i++) { + /* test distributivity: (a + b)P = aP + bP */ + point_multiply(&a, &p, &p1); + point_multiply(&b, &p, &p2); + bn_addmod(&a, &b, &order256k1); + point_multiply(&a, &p, &p3); + point_add(&p1, &p2); + ck_assert_mem_eq(&p2, &p3, sizeof(curve_point)); + // new "random" numbers and a "random" point + a = p1.x; + b = p1.y; + p = p3; + } +} +END_TEST + +START_TEST(test_scalar_point_mult) { + int i; + // get two "random" numbers + bignum256 a = G256k1.x; + bignum256 b = G256k1.y; + curve_point p1, p2; + for (i = 0; i < 200; i++) { + /* test commutativity and associativity: + * a(bG) = (ab)G = b(aG) + */ + scalar_multiply(&a, &p1); + point_multiply(&b, &p1, &p1); + + scalar_multiply(&b, &p2); + point_multiply(&a, &p2, &p2); + + ck_assert_mem_eq(&p1, &p2, sizeof(curve_point)); + + bn_multiply(&a, &b, &order256k1); + scalar_multiply(&b, &p2); + + ck_assert_mem_eq(&p1, &p2, sizeof(curve_point)); + + // new "random" numbers + a = p1.x; + b = p1.y; + } +} +END_TEST // define test suite and cases Suite *test_suite(void) @@ -1265,6 +1416,25 @@ Suite *test_suite(void) tcase_add_test(tc, test_pubkey_validity); suite_add_tcase(s, tc); + tc = tcase_create("secp256k1_cp"); + tcase_add_test(tc, test_secp256k1_cp); + suite_add_tcase(s, tc); + + tc = tcase_create("mult_border_cases"); + tcase_add_test(tc, test_mult_border_cases); + suite_add_tcase(s, tc); + + tc = tcase_create("scalar_mult"); + tcase_add_test(tc, test_scalar_mult); + suite_add_tcase(s, tc); + + tc = tcase_create("point_mult"); + tcase_add_test(tc, test_point_mult); + suite_add_tcase(s, tc); + + tc = tcase_create("scalar_point_mult"); + tcase_add_test(tc, test_scalar_point_mult); + suite_add_tcase(s, tc); return s; } @@ -1278,5 +1448,7 @@ int main(void) srunner_run_all(sr, CK_VERBOSE); number_failed = srunner_ntests_failed(sr); srunner_free(sr); + if (number_failed == 0) + printf("PASSED ALL TESTS\n"); return number_failed; } From f1b8f55d923d3b09bdd19d5adc33ae36ff71db8d Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 11 Apr 2015 20:01:45 +0200 Subject: [PATCH 183/627] use curly braces in if block --- tests.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests.c b/tests.c index d359fa7af..0f58c09fd 100644 --- a/tests.c +++ b/tests.c @@ -1448,7 +1448,8 @@ int main(void) srunner_run_all(sr, CK_VERBOSE); number_failed = srunner_ntests_failed(sr); srunner_free(sr); - if (number_failed == 0) + if (number_failed == 0) { printf("PASSED ALL TESTS\n"); + } return number_failed; } From 21d0bb437aef571eda6cdef340541fb216a8a268 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 13 Apr 2015 18:19:33 +0200 Subject: [PATCH 184/627] cleanup coding style --- base58.c | 9 ++---- bignum.c | 25 +++++++--------- bip32.c | 76 ++++++++++++++++++++---------------------------- ecdsa.c | 80 ++++++++++++++++++++++----------------------------- hmac.c | 15 +++++----- macro_utils.h | 8 ------ macros.h | 6 ++++ pbkdf2.c | 8 ++---- tests.c | 2 +- 9 files changed, 97 insertions(+), 132 deletions(-) delete mode 100644 macro_utils.h create mode 100644 macros.h diff --git a/base58.c b/base58.c index 444d69596..d8252aefc 100644 --- a/base58.c +++ b/base58.c @@ -26,7 +26,7 @@ #include #include "base58.h" #include "sha2.h" -#include "macro_utils.h" +#include "macros.h" static const int8_t b58digits_map[] = { -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, @@ -184,8 +184,6 @@ bool b58enc(char *b58, size_t *b58sz, const void *data, size_t binsz) return true; } -#include - int base58_encode_check(const uint8_t *data, int datalen, char *str, int strsize) { if (datalen > 128) { @@ -197,10 +195,9 @@ int base58_encode_check(const uint8_t *data, int datalen, char *str, int strsize sha256_Raw(data, datalen, hash); sha256_Raw(hash, 32, hash); size_t res = strsize; - bool fSuccess = b58enc(str, &res, buf, datalen + 4); - + bool success = b58enc(str, &res, buf, datalen + 4); MEMSET_BZERO(buf, sizeof(buf)); - return fSuccess ? res : 0; + return success ? res : 0; } int base58_decode_check(const char *str, uint8_t *data, int datalen) diff --git a/bignum.c b/bignum.c index 134f8ee08..3bc847862 100644 --- a/bignum.c +++ b/bignum.c @@ -26,7 +26,7 @@ #include #include "bignum.h" #include "secp256k1.h" -#include "macro_utils.h" +#include "macros.h" inline uint32_t read_be(const uint8_t *data) { @@ -226,7 +226,7 @@ void bn_multiply(const bignum256 *k, bignum256 *x, const bignum256 *prime) // 0 <= res < 2^(30k + 256) * (2^30 + 1) // estimate (res / prime) coef = (res[i] >> 16) + (res[i + 1] << 14); - + // coef = res / 2^(30k + 256) rounded down // 0 <= coef <= 2^30 // subtract (coef * 2^(30k) * prime) from res @@ -239,7 +239,7 @@ void bn_multiply(const bignum256 *k, bignum256 *x, const bignum256 *prime) res[i - 8 + j] = temp & 0x3FFFFFFF; } // we don't clear res[i+1] but we never read it again. - + // we rely on the fact that prime > 2^256 - 2^196 // res = oldres - coef*2^(30k) * prime; // and @@ -253,8 +253,7 @@ void bn_multiply(const bignum256 *k, bignum256 *x, const bignum256 *prime) for (i = 0; i < 9; i++) { x->val[i] = res[i]; } - - MEMSET_BZERO(res,sizeof(res)); + MEMSET_BZERO(res, sizeof(res)); } // input x can be any normalized number that fits (0 <= x < 2^270). @@ -312,10 +311,8 @@ void bn_sqrt(bignum256 *x, const bignum256 *prime) } bn_mod(&res, prime); memcpy(x, &res, sizeof(bignum256)); - MEMSET_BZERO(&res, sizeof(res)); MEMSET_BZERO(&p, sizeof(p)); - } #if ! USE_INVERSE_FAST @@ -408,14 +405,14 @@ void bn_inverse(bignum256 *x, const bignum256 *prime) odd = &us; even = &vr; - // u = prime, v = x + // u = prime, v = x // r = 0 , s = 1 // k = 0 for (;;) { // invariants: - // let u = limbs us.a[0..u.len1-1] in little endian, + // let u = limbs us.a[0..u.len1-1] in little endian, // let s = limbs us.a[u.len..8] in big endian, - // let v = limbs vr.a[0..u.len1-1] in little endian, + // let v = limbs vr.a[0..u.len1-1] in little endian, // let r = limbs vr.a[u.len..8] in big endian, // r,s >= 0 ; u,v >= 1 // x*-r = u*2^k mod prime @@ -425,7 +422,7 @@ void bn_inverse(bignum256 *x, const bignum256 *prime) // max(u,v) <= 2^k (*) see comment at end of loop // gcd(u,v) = 1 // {odd,even} = {&us, &vr} - // odd->a[0] and odd->a[8] are odd + // odd->a[0] and odd->a[8] are odd // even->a[0] or even->a[8] is even // // first u/v are large and r/s small @@ -486,7 +483,7 @@ void bn_inverse(bignum256 *x, const bignum256 *prime) assert(even->a[0] & 1); assert((even->a[8] & 1) == 0); - // cmp > 0 if us.a[0..len1-1] > vr.a[0..len1-1], + // cmp > 0 if us.a[0..len1-1] > vr.a[0..len1-1], // cmp = 0 if equal, < 0 if less. cmp = us.len1 - vr.len1; if (cmp == 0) { @@ -567,7 +564,7 @@ void bn_inverse(bignum256 *x, const bignum256 *prime) // We use the Explicit Quadratic Modular inverse algorithm. // http://arxiv.org/pdf/1209.6626.pdf // a^-1 = (2-a) * PROD_i (1 + (a - 1)^(2^i)) mod 2^32 - // the product will converge quickly, because (a-1)^(2^i) will be + // the product will converge quickly, because (a-1)^(2^i) will be // zero mod 2^32 after at most five iterations. // We want to compute -prime^-1 so we start with (pp[0]-2). assert(pp[0] & 1); @@ -622,7 +619,7 @@ void bn_inverse(bignum256 *x, const bignum256 *prime) } x->val[i] = temp32; - // Let's wipe all temp buffers. + // let's wipe all temp buffers MEMSET_BZERO(pp, sizeof(pp)); MEMSET_BZERO(&us, sizeof(us)); MEMSET_BZERO(&vr, sizeof(vr)); diff --git a/bip32.c b/bip32.c index 4137e6818..fb8b816d7 100644 --- a/bip32.c +++ b/bip32.c @@ -31,7 +31,7 @@ #include "sha2.h" #include "ripemd160.h" #include "base58.h" -#include "macro_utils.h" +#include "macros.h" int hdnode_from_xpub(uint32_t depth, uint32_t fingerprint, uint32_t child_num, const uint8_t *chain_code, const uint8_t *public_key, HDNode *out) { @@ -53,15 +53,16 @@ int hdnode_from_xprv(uint32_t depth, uint32_t fingerprint, uint32_t child_num, c bn_read_be(private_key, &a); bool failed = false; - if (bn_is_zero(&a)) { - failed = true; - } - else if( !bn_is_less(&a, &order256k1)) { // == 0 or >= order - MEMSET_BZERO(&a,sizeof(a)); + if (bn_is_zero(&a)) { // == 0 failed = true; + } else { + if (!bn_is_less(&a, &order256k1)) { // >= order + failed = true; + } + MEMSET_BZERO(&a, sizeof(a)); } - if(failed) { + if (failed) { return 0; } @@ -87,25 +88,21 @@ int hdnode_from_seed(const uint8_t *seed, int seed_len, HDNode *out) bn_read_be(out->private_key, &a); bool failed = false; - if (bn_is_zero(&a)) { + if (bn_is_zero(&a)) { // == 0 failed = true; - } - else - { - if( !bn_is_less(&a, &order256k1)) { // == 0 or >= order + } else { + if (!bn_is_less(&a, &order256k1)) { // >= order failed = true; } - - // Making sure a is wiped. - MEMSET_BZERO(&a,sizeof(a)); + MEMSET_BZERO(&a, sizeof(a)); } - if(!failed) { + if (!failed) { memcpy(out->chain_code, I + 32, 32); hdnode_fill_public_key(out); } - MEMSET_BZERO(I,sizeof(I)); + MEMSET_BZERO(I, sizeof(I)); return failed ? 0 : 1; } @@ -141,30 +138,25 @@ int hdnode_private_ckd(HDNode *inout, uint32_t i) if (!bn_is_less(&b, &order256k1)) { // >= order failed = true; } - if(!failed) { - + if (!failed) { bn_addmod(&a, &b, &order256k1); - if (bn_is_zero(&a)) { failed = true; } } - - if(!failed) - { + if (!failed) { inout->depth++; inout->child_num = i; bn_write_be(&a, inout->private_key); - hdnode_fill_public_key(inout); } - // Making sure to wipe our memory! - MEMSET_BZERO(&a,sizeof(a)); - MEMSET_BZERO(&b,sizeof(b)); - MEMSET_BZERO(I,sizeof(I)); - MEMSET_BZERO(fingerprint,sizeof(fingerprint)); - MEMSET_BZERO(data,sizeof(data)); + // making sure to wipe our memory + MEMSET_BZERO(&a, sizeof(a)); + MEMSET_BZERO(&b, sizeof(b)); + MEMSET_BZERO(I, sizeof(I)); + MEMSET_BZERO(fingerprint, sizeof(fingerprint)); + MEMSET_BZERO(data, sizeof(data)); return failed ? 0 : 1; } @@ -194,43 +186,37 @@ int hdnode_public_ckd(HDNode *inout, uint32_t i) failed = true; } - if(!failed) - { + if (!failed) { hmac_sha512(inout->chain_code, 32, data, sizeof(data), I); memcpy(inout->chain_code, I + 32, 32); bn_read_be(I, &c); - if (!bn_is_less(&c, &order256k1)) { // >= order failed = true; } } - if(!failed) - { + if (!failed) { scalar_multiply(&c, &b); // b = c * G point_add(&a, &b); // b = a + b - if (!ecdsa_validate_pubkey(&b)) { failed = true; } } - if(!failed) - { + if (!failed) { inout->public_key[0] = 0x02 | (b.y.val[0] & 0x01); bn_write_be(&b.x, inout->public_key + 1); - inout->depth++; inout->child_num = i; } // Wipe all stack data. - MEMSET_BZERO(data,sizeof(data)); - MEMSET_BZERO(I,sizeof(I)); - MEMSET_BZERO(fingerprint,sizeof(fingerprint)); - MEMSET_BZERO(&a,sizeof(a)); - MEMSET_BZERO(&b,sizeof(b)); - MEMSET_BZERO(&c,sizeof(c)); + MEMSET_BZERO(data, sizeof(data)); + MEMSET_BZERO(I, sizeof(I)); + MEMSET_BZERO(fingerprint, sizeof(fingerprint)); + MEMSET_BZERO(&a, sizeof(a)); + MEMSET_BZERO(&b, sizeof(b)); + MEMSET_BZERO(&c, sizeof(c)); return failed ? 0 : 1; } diff --git a/ecdsa.c b/ecdsa.c index 8fe28f7f5..1462ad5eb 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -33,7 +33,7 @@ #include "hmac.h" #include "ecdsa.h" #include "base58.h" -#include "macro_utils.h" +#include "macros.h" // Set cp2 = cp1 void point_copy(const curve_point *cp1, curve_point *cp2) @@ -165,12 +165,12 @@ int point_is_negative_of(const curve_point *p, const curve_point *q) if (!bn_is_equal(&(p->x), &(q->x))) { return 0; } - + // we shouldn't hit this for a valid point if (bn_is_zero(&(p->y))) { return 0; } - + return !bn_is_equal(&(p->y), &(q->y)); } @@ -200,7 +200,7 @@ static void curve_to_jacobian(const curve_point *p, jacobian_curve_point *jp) { jp->z.val[i] = random32() & 0x3FFFFFFF; } jp->z.val[8] = (random32() & 0x7fff) + 1; - + jp->x = jp->z; bn_multiply(&jp->z, &jp->x, &prime256k1); // x = z^2 @@ -259,7 +259,6 @@ static void point_jacobian_add(const curve_point *p1, jacobian_curve_point *p2) * and y3 = (lambda * (x2/z2^2 - x3/z3^2) - y2/z2^3) * z3^3 * = r * (h^2*x2 - x3) - h^3*y2 */ - /* h = x1*z2^2 - x2 * r = y1*z2^3 - y2 @@ -347,7 +346,6 @@ static void point_jacobian_double(jacobian_curve_point *p) { * and y3 = (lambda * (x/z^2 - x3/z3^2) - y/z^3) * z3^3 * = m * (xy^2 - x3) - y^4 */ - /* m = 3/2*x*x * x3 = m^2 - 2*xy^2 @@ -486,7 +484,7 @@ void point_multiply(const bignum256 *k, const curve_point *p, curve_point *res) // negate last result to make signs of this round and the // last round equal. conditional_negate(sign ^ nsign, &jres.z, &prime256k1); - + // add odd factor point_jacobian_add(&pmult[bits >> 1], &jres); sign = nsign; @@ -572,7 +570,7 @@ void scalar_multiply(const bignum256 *k, curve_point *res) // negate last result to make signs of this round and the // last round equal. conditional_negate((lowbits & 1) - 1, &jres.y, &prime256k1); - + // add odd factor point_jacobian_add(&secp256k1_cp[i][lowbits >> 1], &jres); } @@ -656,7 +654,6 @@ int ecdsa_sign(const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, ui uint8_t hash[32]; sha256_Raw(msg, msg_len, hash); int res = ecdsa_sign_digest(priv_key, hash, sig, pby); - MEMSET_BZERO(hash, sizeof(hash)); return res; @@ -670,9 +667,7 @@ int ecdsa_sign_double(const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_ sha256_Raw(msg, msg_len, hash); sha256_Raw(hash, 32, hash); int res = ecdsa_sign_digest(priv_key, hash, sig, pby); - MEMSET_BZERO(hash, sizeof(hash)); - return res; } @@ -701,7 +696,7 @@ int ecdsa_sign_digest(const uint8_t *priv_key, const uint8_t *digest, uint8_t *s } #endif - if(result == 0) { + if (result == 0) { // compute k*G scalar_multiply(&k, &R); if (pby) { @@ -716,7 +711,7 @@ int ecdsa_sign_digest(const uint8_t *priv_key, const uint8_t *digest, uint8_t *s } } - if(result == 0) { + if (result == 0) { bn_inverse(&k, &order256k1); bn_read_be(priv_key, da); bn_multiply(&R.x, da, &order256k1); @@ -734,8 +729,7 @@ int ecdsa_sign_digest(const uint8_t *priv_key, const uint8_t *digest, uint8_t *s } } - if(result == 0) - { + if (result == 0) { // if S > order/2 => S = -S if (bn_is_less(&order256k1_half, &k)) { bn_subtract(&order256k1, &k, &k); @@ -748,9 +742,9 @@ int ecdsa_sign_digest(const uint8_t *priv_key, const uint8_t *digest, uint8_t *s bn_write_be(&k, sig + 32); } - MEMSET_BZERO(&k,sizeof(k)); - MEMSET_BZERO(&z,sizeof(z)); - MEMSET_BZERO(&R,sizeof(R)); + MEMSET_BZERO(&k, sizeof(k)); + MEMSET_BZERO(&z, sizeof(z)); + MEMSET_BZERO(&R, sizeof(R)); return 0; } @@ -764,8 +758,8 @@ void ecdsa_get_public_key33(const uint8_t *priv_key, uint8_t *pub_key) scalar_multiply(&k, &R); pub_key[0] = 0x02 | (R.y.val[0] & 0x01); bn_write_be(&R.x, pub_key + 1); - MEMSET_BZERO(&R,sizeof(R)); - MEMSET_BZERO(&k,sizeof(k)); + MEMSET_BZERO(&R, sizeof(R)); + MEMSET_BZERO(&k, sizeof(k)); } void ecdsa_get_public_key65(const uint8_t *priv_key, uint8_t *pub_key) @@ -779,8 +773,8 @@ void ecdsa_get_public_key65(const uint8_t *priv_key, uint8_t *pub_key) pub_key[0] = 0x04; bn_write_be(&R.x, pub_key + 1); bn_write_be(&R.y, pub_key + 33); - MEMSET_BZERO(&R,sizeof(R)); - MEMSET_BZERO(&k,sizeof(k)); + MEMSET_BZERO(&R, sizeof(R)); + MEMSET_BZERO(&k, sizeof(k)); } void ecdsa_get_pubkeyhash(const uint8_t *pub_key, uint8_t *pubkeyhash) @@ -794,7 +788,7 @@ void ecdsa_get_pubkeyhash(const uint8_t *pub_key, uint8_t *pubkeyhash) sha256_Raw(pub_key, 33, h); // expecting compressed format } ripemd160(h, 32, pubkeyhash); - MEMSET_BZERO(h,sizeof(h)); + MEMSET_BZERO(h, sizeof(h)); } void ecdsa_get_address_raw(const uint8_t *pub_key, uint8_t version, uint8_t *addr_raw) @@ -809,8 +803,8 @@ void ecdsa_get_address(const uint8_t *pub_key, uint8_t version, char *addr, int ecdsa_get_address_raw(pub_key, version, raw); base58_encode_check(raw, 21, addr, addrsize); - // Not as important to clear this one, but we might as well. - MEMSET_BZERO(raw,sizeof(raw)); + // not as important to clear this one, but we might as well + MEMSET_BZERO(raw, sizeof(raw)); } void ecdsa_get_wif(const uint8_t *priv_key, uint8_t version, char *wif, int wifsize) @@ -821,8 +815,8 @@ void ecdsa_get_wif(const uint8_t *priv_key, uint8_t version, char *wif, int wifs data[33] = 0x01; base58_encode_check(data, 34, wif, wifsize); - // This private keys running around our stack can cause trouble! - MEMSET_BZERO(data,sizeof(data)); + // private keys running around our stack can cause trouble + MEMSET_BZERO(data, sizeof(data)); } int ecdsa_address_decode(const char *addr, uint8_t *out) @@ -907,8 +901,7 @@ int ecdsa_verify(const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, uint8_t hash[32]; sha256_Raw(msg, msg_len, hash); int res = ecdsa_verify_digest(pub_key, sig, hash); - - MEMSET_BZERO(hash,sizeof(hash)); + MEMSET_BZERO(hash, sizeof(hash)); return res; } @@ -917,10 +910,8 @@ int ecdsa_verify_double(const uint8_t *pub_key, const uint8_t *sig, const uint8_ uint8_t hash[32]; sha256_Raw(msg, msg_len, hash); sha256_Raw(hash, 32, hash); - int res = ecdsa_verify_digest(pub_key, sig, hash); - - MEMSET_BZERO(hash,sizeof(hash)); + MEMSET_BZERO(hash, sizeof(hash)); return res; } @@ -958,24 +949,23 @@ int ecdsa_verify_digest(const uint8_t *pub_key, const uint8_t *sig, const uint8_ scalar_multiply(&z, &res); } - if(result == 0) { - - // both pub and res can be infinity, can have y = 0 OR can be equal -> false negative - point_multiply(&s, &pub, &pub); - point_add(&pub, &res); - bn_mod(&(res.x), &order256k1); - - // signature does not match + if (result == 0) { + // both pub and res can be infinity, can have y = 0 OR can be equal -> false negative + point_multiply(&s, &pub, &pub); + point_add(&pub, &res); + bn_mod(&(res.x), &order256k1); + // signature does not match if (!bn_is_equal(&res.x, &r)) { result = 5; } } - MEMSET_BZERO(&pub,sizeof(pub)); - MEMSET_BZERO(&res,sizeof(res)); - MEMSET_BZERO(&r,sizeof(r)); - MEMSET_BZERO(&s,sizeof(s)); - MEMSET_BZERO(&z,sizeof(z)); + MEMSET_BZERO(&pub, sizeof(pub)); + MEMSET_BZERO(&res, sizeof(res)); + MEMSET_BZERO(&r, sizeof(r)); + MEMSET_BZERO(&s, sizeof(s)); + MEMSET_BZERO(&z, sizeof(z)); + // all OK return result; } diff --git a/hmac.c b/hmac.c index a43d2a7a6..f7b00774c 100644 --- a/hmac.c +++ b/hmac.c @@ -25,7 +25,7 @@ #include "hmac.h" #include "sha2.h" -#include "macro_utils.h" +#include "macros.h" void hmac_sha256(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, const uint32_t msglen, uint8_t *hmac) { @@ -54,10 +54,9 @@ void hmac_sha256(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, sha256_Update(&ctx, o_key_pad, SHA256_BLOCK_LENGTH); sha256_Update(&ctx, buf, SHA256_DIGEST_LENGTH); sha256_Final(hmac, &ctx); - MEMSET_BZERO(buf,sizeof(buf)); - MEMSET_BZERO(o_key_pad,sizeof(o_key_pad)); - MEMSET_BZERO(i_key_pad,sizeof(i_key_pad)); - + MEMSET_BZERO(buf, sizeof(buf)); + MEMSET_BZERO(o_key_pad, sizeof(o_key_pad)); + MEMSET_BZERO(i_key_pad, sizeof(i_key_pad)); } void hmac_sha512(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, const uint32_t msglen, uint8_t *hmac) @@ -88,7 +87,7 @@ void hmac_sha512(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, sha512_Update(&ctx, buf, SHA512_DIGEST_LENGTH); sha512_Final(hmac, &ctx); - MEMSET_BZERO(buf,sizeof(buf)); - MEMSET_BZERO(o_key_pad,sizeof(o_key_pad)); - MEMSET_BZERO(i_key_pad,sizeof(i_key_pad)); + MEMSET_BZERO(buf, sizeof(buf)); + MEMSET_BZERO(o_key_pad, sizeof(o_key_pad)); + MEMSET_BZERO(i_key_pad, sizeof(i_key_pad)); } diff --git a/macro_utils.h b/macro_utils.h deleted file mode 100644 index 54634f8d1..000000000 --- a/macro_utils.h +++ /dev/null @@ -1,8 +0,0 @@ - -#if !defined( _MACRO_UTILS_H ) -#define _MACRO_UTILS_H - -#define MEMSET_BZERO(p,l) memset((p), 0, (l)) - - -#endif diff --git a/macros.h b/macros.h new file mode 100644 index 000000000..041289e7c --- /dev/null +++ b/macros.h @@ -0,0 +1,6 @@ +#ifndef __MACROS_H__ +#define __MACROS_H__ + +#define MEMSET_BZERO(p,l) memset((p), 0, (l)) + +#endif diff --git a/pbkdf2.c b/pbkdf2.c index 256ef86e1..363618e08 100644 --- a/pbkdf2.c +++ b/pbkdf2.c @@ -24,7 +24,7 @@ #include #include "pbkdf2.h" #include "hmac.h" -#include "macro_utils.h" +#include "macros.h" void pbkdf2_hmac_sha256(const uint8_t *pass, int passlen, uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key, int keylen, void (*progress_callback)(uint32_t current, uint32_t total)) { @@ -57,8 +57,7 @@ void pbkdf2_hmac_sha256(const uint8_t *pass, int passlen, uint8_t *salt, int sal memcpy(key + HMACLEN * (i - 1), f, HMACLEN); } } - - MEMSET_BZERO(f,sizeof(f)); + MEMSET_BZERO(f, sizeof(f)); MEMSET_BZERO(g, sizeof(g)); } @@ -93,7 +92,6 @@ void pbkdf2_hmac_sha512(const uint8_t *pass, int passlen, uint8_t *salt, int sal memcpy(key + HMACLEN * (i - 1), f, HMACLEN); } } - - MEMSET_BZERO(f,sizeof(f)); + MEMSET_BZERO(f, sizeof(f)); MEMSET_BZERO(g, sizeof(g)); } diff --git a/tests.c b/tests.c index 0f58c09fd..94c9449e6 100644 --- a/tests.c +++ b/tests.c @@ -1220,7 +1220,7 @@ START_TEST(test_secp256k1_cp) { point_multiply(&a, &G256k1, &p); ck_assert_mem_eq(&p, &secp256k1_cp[i][j], sizeof(curve_point)); - // even/odd has different behaviour; + // even/odd has different behaviour; // increment by one and test again p1 = p; point_add(&G256k1, &p1); From ffedf8a4d0d23f6516370c6ee19a5eb31afccfeb Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 4 May 2015 19:40:15 +0200 Subject: [PATCH 185/627] suppress warning when debug is disabled --- rand.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rand.c b/rand.c index 4b921cabb..eb74ae45a 100644 --- a/rand.c +++ b/rand.c @@ -45,6 +45,7 @@ uint32_t random32(void) uint32_t r; size_t len = sizeof(r); size_t len_read = fread(&r, 1, len, f); + (void)len_read; assert(len_read == len); return r; } @@ -59,6 +60,7 @@ uint32_t random_uniform(uint32_t n) void random_buffer(uint8_t *buf, size_t len) { size_t len_read = fread(buf, 1, len, f); + (void)len_read; assert(len_read == len); } From 00954da5fe9123f4df398568267c07f1273eb712 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 4 May 2015 19:53:06 +0200 Subject: [PATCH 186/627] fix /dev/urandom problem --- rand.c | 22 ++++++++++++---------- rand.h | 1 - test-openssl.c | 1 - tests.c | 1 - 4 files changed, 12 insertions(+), 13 deletions(-) diff --git a/rand.c b/rand.c index eb74ae45a..6bb72c35d 100644 --- a/rand.c +++ b/rand.c @@ -26,17 +26,13 @@ #include "rand.h" -static FILE *f; - -void init_rand(void) -{ - f = fopen("/dev/urandom", "r"); -} +static FILE *frand = NULL; int finalize_rand(void) { - int err = fclose(f); - f = NULL; + if (!frand) return 0; + int err = fclose(frand); + frand = NULL; return err; } @@ -44,7 +40,10 @@ uint32_t random32(void) { uint32_t r; size_t len = sizeof(r); - size_t len_read = fread(&r, 1, len, f); + if (!frand) { + frand = fopen("/dev/urandom", "r"); + } + size_t len_read = fread(&r, 1, len, frand); (void)len_read; assert(len_read == len); return r; @@ -59,7 +58,10 @@ uint32_t random_uniform(uint32_t n) void random_buffer(uint8_t *buf, size_t len) { - size_t len_read = fread(buf, 1, len, f); + if (!frand) { + frand = fopen("/dev/urandom", "r"); + } + size_t len_read = fread(buf, 1, len, frand); (void)len_read; assert(len_read == len); } diff --git a/rand.h b/rand.h index 8d8160887..3c9655999 100644 --- a/rand.h +++ b/rand.h @@ -27,7 +27,6 @@ #include #include -void init_rand(void); int finalize_rand(void); uint32_t random32(void); uint32_t random_uniform(uint32_t n); diff --git a/test-openssl.c b/test-openssl.c index ccef802ce..7103260fe 100644 --- a/test-openssl.c +++ b/test-openssl.c @@ -38,7 +38,6 @@ int main(int argc, char *argv[]) EC_GROUP *ecgroup; int cnt = 0; - init_rand(); ecgroup = EC_GROUP_new_by_curve_name(NID_secp256k1); unsigned long max_iterations = -1; diff --git a/tests.c b/tests.c index 94c9449e6..fc797ee1d 100644 --- a/tests.c +++ b/tests.c @@ -1442,7 +1442,6 @@ Suite *test_suite(void) int main(void) { int number_failed; - init_rand(); // needed for scalar_multiply() Suite *s = test_suite(); SRunner *sr = srunner_create(s); srunner_run_all(sr, CK_VERBOSE); From c58d4e03c5dc74234617a4eef33331758ab46259 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 11 May 2015 14:24:45 +0200 Subject: [PATCH 187/627] add proof of concept bip39 bruteforce benchmark --- tools/.gitignore | 1 + tools/Makefile | 9 ++++-- tools/bip39bruteforce.c | 70 +++++++++++++++++++++++++++++++++++++++++ tools/mksecptable.c | 3 -- 4 files changed, 77 insertions(+), 6 deletions(-) create mode 100644 tools/bip39bruteforce.c diff --git a/tools/.gitignore b/tools/.gitignore index 3073e2e52..497e59540 100644 --- a/tools/.gitignore +++ b/tools/.gitignore @@ -1,2 +1,3 @@ xpubaddrgen mksecptable +bip39bruteforce diff --git a/tools/Makefile b/tools/Makefile index 519bb1de9..bc7168648 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -23,9 +23,9 @@ CFLAGS += $(OPTFLAGS) \ -Werror \ -I.. -all: xpubaddrgen mksecptable +all: xpubaddrgen mksecptable bip39bruteforce -OBJS = ../bip32.o ../ecdsa.o ../sha2.o ../bignum.o ../base58.o ../secp256k1.o ../ripemd160.o ../hmac.o ../rand.o +OBJS = ../bip32.o ../bip39.o ../ecdsa.o ../sha2.o ../bignum.o ../base58.o ../secp256k1.o ../ripemd160.o ../hmac.o ../rand.o ../pbkdf2.o %.o: %.c %.h options.h $(CC) $(CFLAGS) -o $@ -c $< @@ -36,5 +36,8 @@ xpubaddrgen: xpubaddrgen.o $(OBJS) mksecptable: mksecptable.o $(OBJS) $(CC) mksecptable.o $(OBJS) -o mksecptable +bip39bruteforce: bip39bruteforce.o $(OBJS) + $(CC) bip39bruteforce.o $(OBJS) -o bip39bruteforce + clean: - rm -f *.o xpubaddrgen mksecptable + rm -f *.o xpubaddrgen mksecptable bip39bruteforce diff --git a/tools/bip39bruteforce.c b/tools/bip39bruteforce.c new file mode 100644 index 000000000..e6e9be02e --- /dev/null +++ b/tools/bip39bruteforce.c @@ -0,0 +1,70 @@ +#include +#include +#include +#include +#include +#include + +char passphrase[256]; +uint8_t seed[512 / 8]; +uint8_t addr[21], pubkeyhash[20]; +int count = 0, found = 0; +HDNode node; +clock_t start; + +// around 120 tries per second + +// testing data: +// +// mnemonic: "all all all all all all all all all all all all" +// address: "1N3uJ5AU3FTYQ1ZQgTMtYmgSvMBmQiGVBS" +// passphrase: "testing" + +int main(int argc, char **argv) +{ + if (argc != 3) { + fprintf(stderr, "Usage: bip39bruteforce mnemonic address\n"); + return 1; + } + const char *mnemonic = argv[1]; + const char *address = argv[2]; + if (!mnemonic_check(mnemonic)) { + fprintf(stderr, "\"%s\" is not a valid mnemonic\n", mnemonic); + return 2; + } + if (!ecdsa_address_decode(address, addr)) { + fprintf(stderr, "\"%s\" is not a valid address\n", address); + return 3; + } + printf("Reading passphrases from stdin ...\n"); + start = clock(); + for (;;) { + if (fgets(passphrase, 256, stdin) == NULL) break; + int len = strlen(passphrase); + if (len <= 0) { + continue; + } + count++; + passphrase[len - 1] = 0; + mnemonic_to_seed(mnemonic, passphrase, seed, NULL); + hdnode_from_seed(seed, 512 / 8, &node); + hdnode_private_ckd_prime(&node, 44); + hdnode_private_ckd_prime(&node, 0); + hdnode_private_ckd_prime(&node, 0); + hdnode_private_ckd(&node, 0); + hdnode_private_ckd(&node, 0); + ecdsa_get_pubkeyhash(node.public_key, pubkeyhash); + if (memcmp(addr + 1, pubkeyhash, 20) == 0) { + found = 1; + break; + } + } + float dur = (float)(clock() - start) / CLOCKS_PER_SEC; + printf("Tried %d passphrases in %f seconds = %f tries/second\n", count, dur, (float)count/dur); + if (found) { + printf("Correct passphrase found! :-)\n\"%s\"\n", passphrase); + return 0; + } + printf("Correct passphrase not found. :-(\n"); + return 4; +} diff --git a/tools/mksecptable.c b/tools/mksecptable.c index e6a1997d9..b305e4713 100644 --- a/tools/mksecptable.c +++ b/tools/mksecptable.c @@ -14,9 +14,6 @@ int main(int __attribute__((unused)) argc, char __attribute__((unused)) **argv) int i,j,k; curve_point ng = G256k1; curve_point pow2ig = G256k1; -#ifndef NDEBUG - init_rand(); // needed for point_multiply() -#endif for (i = 0; i < 64; i++) { // invariants: // pow2ig = 16^i * G From 85cebfe9682b2fd7144b9d360a99162a27fd252d Mon Sep 17 00:00:00 2001 From: John Dvorak Date: Thu, 18 Jun 2015 09:55:12 -0400 Subject: [PATCH 188/627] Change return value of ecdsa_sign_digest Error codes were not being propagated, always returned as 0. --- ecdsa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ecdsa.c b/ecdsa.c index 1462ad5eb..cb29a82d9 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -745,7 +745,7 @@ int ecdsa_sign_digest(const uint8_t *priv_key, const uint8_t *digest, uint8_t *s MEMSET_BZERO(&k, sizeof(k)); MEMSET_BZERO(&z, sizeof(z)); MEMSET_BZERO(&R, sizeof(R)); - return 0; + return result; } void ecdsa_get_public_key33(const uint8_t *priv_key, uint8_t *pub_key) From 7c58fc11a46361476e3a7862816adb0671de6a74 Mon Sep 17 00:00:00 2001 From: Roman Zeyde Date: Wed, 27 May 2015 17:48:57 +0300 Subject: [PATCH 189/627] Add support for NIST256P1 elliptic curve This enables SSH ECDSA public key authentication. --- .gitignore | 5 + Makefile | 2 +- bignum.c | 120 +- bignum.h | 4 +- bip32.c | 23 +- bip32.h | 1 + ecdsa.c | 440 +++---- ecdsa.h | 57 +- nist256p1.c | 50 + nist256p1.h | 33 + nist256p1.table | 1664 +++++++++++++++++++++++++++ secp256k1.c | 1698 +--------------------------- secp256k1.h | 26 +- secp256k1.table | 1664 +++++++++++++++++++++++++++ test-openssl.c | 17 +- test_curves.py | 304 +++++ tests.c | 107 +- tools/.gitignore | 2 +- tools/Makefile | 10 +- tools/README.md | 5 +- tools/{mksecptable.c => mktable.c} | 23 +- 21 files changed, 4191 insertions(+), 2064 deletions(-) create mode 100644 nist256p1.c create mode 100644 nist256p1.h create mode 100644 nist256p1.table create mode 100644 secp256k1.table create mode 100644 test_curves.py rename tools/{mksecptable.c => mktable.c} (72%) diff --git a/.gitignore b/.gitignore index c7749f130..b6fd2bd1b 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,8 @@ build/ dist/ MANIFEST TrezorCrypto.c +SConstruct +.sconsign.dblite +*.os +*.so +*.pyc diff --git a/Makefile b/Makefile index f24d375da..05882e66c 100644 --- a/Makefile +++ b/Makefile @@ -30,7 +30,7 @@ ifdef SMALL CFLAGS += -DUSE_PRECOMPUTED_IV=0 -DUSE_PRECOMPUTED_CP=0 endif -OBJS = bignum.o ecdsa.o secp256k1.o rand.o hmac.o bip32.o bip39.o pbkdf2.o base58.o +OBJS = bignum.o ecdsa.o secp256k1.o nist256p1.o rand.o hmac.o bip32.o bip39.o pbkdf2.o base58.o OBJS += ripemd160.o OBJS += sha2.o OBJS += aescrypt.o aeskey.o aestab.o aes_modes.o diff --git a/bignum.c b/bignum.c index 3bc847862..050078a09 100644 --- a/bignum.c +++ b/bignum.c @@ -140,18 +140,18 @@ void bn_rshift(bignum256 *a) a->val[8] >>= 1; } -// multiply x by 3/2 modulo prime. +// multiply x by 1/2 modulo prime. // assumes x < 2*prime, // guarantees x < 4*prime on exit. -void bn_mult_3_2(bignum256 * x, const bignum256 *prime) +void bn_mult_half(bignum256 * x, const bignum256 *prime) { int j; uint32_t xodd = -(x->val[0] & 1); - // compute x = 3*x/2 mod prime - // if x is odd compute (3*x+prime)/2 - uint32_t tmp1 = (3*x->val[0] + (prime->val[0] & xodd)) >> 1; + // compute x = x/2 mod prime + // if x is odd compute (x+prime)/2 + uint32_t tmp1 = (x->val[0] + (prime->val[0] & xodd)) >> 1; for (j = 0; j < 8; j++) { - uint32_t tmp2 = (3*x->val[j+1] + (prime->val[j+1] & xodd)); + uint32_t tmp2 = (x->val[j+1] + (prime->val[j+1] & xodd)); tmp1 += (tmp2 & 1) << 29; x->val[j] = tmp1 & 0x3fffffff; tmp1 >>= 30; @@ -160,6 +160,20 @@ void bn_mult_3_2(bignum256 * x, const bignum256 *prime) x->val[8] = tmp1; } +// multiply x by k modulo prime. +// assumes x < prime, +// guarantees x < prime on exit. +void bn_mult_k(bignum256 *x, uint8_t k, const bignum256 *prime) +{ + int j; + for (j = 0; j < 9; j++) { + x->val[j] = k * x->val[j]; + } + bn_normalize(x); + bn_fast_mod(x, prime); + bn_mod(x, prime); +} + // assumes x < 2*prime, result < prime void bn_mod(bignum256 *x, const bignum256 *prime) { @@ -186,16 +200,10 @@ void bn_mod(bignum256 *x, const bignum256 *prime) } } -// Compute x := k * x (mod prime) -// both inputs must be smaller than 2 * prime. -// result is reduced to 0 <= x < 2 * prime -// This only works for primes between 2^256-2^196 and 2^256. -// this particular implementation accepts inputs up to 2^263 or 128*prime. -void bn_multiply(const bignum256 *k, bignum256 *x, const bignum256 *prime) +void bn_multiply_long(const bignum256 *k, const bignum256 *x, uint32_t res[18]) { int i, j; uint64_t temp = 0; - uint32_t res[18], coef; // compute lower half of long multiplication for (i = 0; i < 9; i++) @@ -216,43 +224,69 @@ void bn_multiply(const bignum256 *k, bignum256 *x, const bignum256 *prime) temp >>= 30; } res[17] = temp; +} + +void bn_multiply_reduce_step(uint32_t res[18], const bignum256 *prime, uint32_t i) { + // let k = i-8. + // invariants: + // res[0..(i+1)] = k * x (mod prime) + // 0 <= res < 2^(30k + 256) * (2^30 + 1) + // estimate (res / prime) + // coef = res / 2^(30k + 256) rounded down + // 0 <= coef <= 2^30 + // subtract (coef * 2^(30k) * prime) from res + // note that we unrolled the first iteration + uint32_t j; + uint32_t coef = (res[i] >> 16) + (res[i + 1] << 14); + uint64_t temp = 0x1000000000000000ull + res[i - 8] - prime->val[0] * (uint64_t)coef; + res[i - 8] = temp & 0x3FFFFFFF; + for (j = 1; j < 9; j++) { + temp >>= 30; + temp += 0xFFFFFFFC0000000ull + res[i - 8 + j] - prime->val[j] * (uint64_t)coef; + res[i - 8 + j] = temp & 0x3FFFFFFF; + } + temp >>= 30; + temp += 0xFFFFFFFC0000000ull + res[i - 8 + j]; + res[i - 8 + j] = temp & 0x3FFFFFFF; + // we rely on the fact that prime > 2^256 - 2^196 + // res = oldres - coef*2^(30k) * prime; + // and + // coef * 2^(30k + 256) <= oldres < (coef+1) * 2^(30k + 256) + // Hence, 0 <= res < 2^30k (2^256 + coef * (2^256 - prime)) + // Since coef * (2^256 - prime) < 2^226, we get + // 0 <= res < 2^(30k + 226) (2^30 + 1) + // Thus the invariant holds again. +} + + +void bn_multiply_reduce(bignum256 *x, uint32_t res[18], const bignum256 *prime) +{ + int i; // res = k * x is a normalized number (every limb < 2^30) // 0 <= res < 2^526. // compute modulo p division is only estimated so this may give result greater than prime but not bigger than 2 * prime for (i = 16; i >= 8; i--) { - // let k = i-8. - // invariants: - // res[0..(i+1)] = k * x (mod prime) - // 0 <= res < 2^(30k + 256) * (2^30 + 1) - // estimate (res / prime) - coef = (res[i] >> 16) + (res[i + 1] << 14); - - // coef = res / 2^(30k + 256) rounded down - // 0 <= coef <= 2^30 - // subtract (coef * 2^(30k) * prime) from res - // note that we unrolled the first iteration - temp = 0x1000000000000000ull + res[i - 8] - prime->val[0] * (uint64_t)coef; - res[i - 8] = temp & 0x3FFFFFFF; - for (j = 1; j < 9; j++) { - temp >>= 30; - temp += 0xFFFFFFFC0000000ull + res[i - 8 + j] - prime->val[j] * (uint64_t)coef; - res[i - 8 + j] = temp & 0x3FFFFFFF; - } - // we don't clear res[i+1] but we never read it again. - - // we rely on the fact that prime > 2^256 - 2^196 - // res = oldres - coef*2^(30k) * prime; - // and - // coef * 2^(30k + 256) <= oldres < (coef+1) * 2^(30k + 256) - // Hence, 0 <= res < 2^30k (2^256 + coef * (2^256 - prime)) - // Since coef * (2^256 - prime) < 2^226, we get - // 0 <= res < 2^(30k + 226) (2^30 + 1) - // Thus the invariant holds again. + bn_multiply_reduce_step(res, prime, i); + bn_multiply_reduce_step(res, prime, i); // apply twice, as a hack for NIST256P1 prime. + assert(res[i + 1] == 0); } // store the result for (i = 0; i < 9; i++) { x->val[i] = res[i]; } +} + +// Compute x := k * x (mod prime) +// both inputs must be smaller than 2 * prime. +// result is reduced to 0 <= x < 2 * prime +// This only works for primes between 2^256-2^196 and 2^256. +// this particular implementation accepts inputs up to 2^263 or 128*prime. + +void bn_multiply(const bignum256 *k, bignum256 *x, const bignum256 *prime) +{ + uint32_t res[18] = {0}; + bn_multiply_long(k, x, res); + bn_multiply_reduce(x, res, prime); MEMSET_BZERO(res, sizeof(res)); } @@ -660,9 +694,9 @@ void bn_addmodi(bignum256 *a, uint32_t b, const bignum256 *prime) { void bn_subtractmod(const bignum256 *a, const bignum256 *b, bignum256 *res, const bignum256 *prime) { int i; - uint32_t temp = 0; + uint32_t temp = 1; for (i = 0; i < 9; i++) { - temp += a->val[i] + 2u * prime->val[i] - b->val[i]; + temp += 0x3FFFFFFF + a->val[i] + 2u * prime->val[i] - b->val[i]; res->val[i] = temp & 0x3FFFFFFF; temp >>= 30; } diff --git a/bignum.h b/bignum.h index fa733cd06..4774ca7d3 100644 --- a/bignum.h +++ b/bignum.h @@ -57,7 +57,9 @@ void bn_lshift(bignum256 *a); void bn_rshift(bignum256 *a); -void bn_mult_3_2(bignum256 *x, const bignum256 *prime); +void bn_mult_half(bignum256 *x, const bignum256 *prime); + +void bn_mult_k(bignum256 *x, uint8_t k, const bignum256 *prime); void bn_mod(bignum256 *x, const bignum256 *prime); diff --git a/bip32.c b/bip32.c index fb8b816d7..a8a3c5e12 100644 --- a/bip32.c +++ b/bip32.c @@ -32,6 +32,9 @@ #include "ripemd160.h" #include "base58.h" #include "macros.h" +#include "secp256k1.h" + +static const ecdsa_curve *default_curve = &secp256k1; int hdnode_from_xpub(uint32_t depth, uint32_t fingerprint, uint32_t child_num, const uint8_t *chain_code, const uint8_t *public_key, HDNode *out) { @@ -56,7 +59,7 @@ int hdnode_from_xprv(uint32_t depth, uint32_t fingerprint, uint32_t child_num, c if (bn_is_zero(&a)) { // == 0 failed = true; } else { - if (!bn_is_less(&a, &order256k1)) { // >= order + if (!bn_is_less(&a, &default_curve->order)) { // >= order failed = true; } MEMSET_BZERO(&a, sizeof(a)); @@ -91,7 +94,7 @@ int hdnode_from_seed(const uint8_t *seed, int seed_len, HDNode *out) if (bn_is_zero(&a)) { // == 0 failed = true; } else { - if (!bn_is_less(&a, &order256k1)) { // >= order + if (!bn_is_less(&a, &default_curve->order)) { // >= order failed = true; } MEMSET_BZERO(&a, sizeof(a)); @@ -135,11 +138,11 @@ int hdnode_private_ckd(HDNode *inout, uint32_t i) bool failed = false; - if (!bn_is_less(&b, &order256k1)) { // >= order + if (!bn_is_less(&b, &default_curve->order)) { // >= order failed = true; } if (!failed) { - bn_addmod(&a, &b, &order256k1); + bn_addmod(&a, &b, &default_curve->order); if (bn_is_zero(&a)) { failed = true; } @@ -182,7 +185,7 @@ int hdnode_public_ckd(HDNode *inout, uint32_t i) memset(inout->private_key, 0, 32); bool failed = false; - if (!ecdsa_read_pubkey(inout->public_key, &a)) { + if (!ecdsa_read_pubkey(default_curve, inout->public_key, &a)) { failed = true; } @@ -190,15 +193,15 @@ int hdnode_public_ckd(HDNode *inout, uint32_t i) hmac_sha512(inout->chain_code, 32, data, sizeof(data), I); memcpy(inout->chain_code, I + 32, 32); bn_read_be(I, &c); - if (!bn_is_less(&c, &order256k1)) { // >= order + if (!bn_is_less(&c, &default_curve->order)) { // >= order failed = true; } } if (!failed) { - scalar_multiply(&c, &b); // b = c * G - point_add(&a, &b); // b = a + b - if (!ecdsa_validate_pubkey(&b)) { + scalar_multiply(default_curve, &c, &b); // b = c * G + point_add(default_curve, &a, &b); // b = a + b + if (!ecdsa_validate_pubkey(default_curve, &b)) { failed = true; } } @@ -291,7 +294,7 @@ int hdnode_private_ckd_cached(HDNode *inout, const uint32_t *i, size_t i_count) void hdnode_fill_public_key(HDNode *node) { - ecdsa_get_public_key33(node->private_key, node->public_key); + ecdsa_get_public_key33(default_curve, node->private_key, node->public_key); } void hdnode_serialize(const HDNode *node, uint32_t version, char use_public, char *str, int strsize) diff --git a/bip32.h b/bip32.h index c05f6ccc8..765084fd0 100644 --- a/bip32.h +++ b/bip32.h @@ -26,6 +26,7 @@ #include #include +#include "ecdsa.h" #include "options.h" typedef struct { diff --git a/ecdsa.c b/ecdsa.c index 1462ad5eb..464fe5f3a 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -35,6 +35,9 @@ #include "base58.h" #include "macros.h" +#include "secp256k1.h" +#include "nist256p1.h" + // Set cp2 = cp1 void point_copy(const curve_point *cp1, curve_point *cp2) { @@ -42,10 +45,8 @@ void point_copy(const curve_point *cp1, curve_point *cp2) } // cp2 = cp1 + cp2 -void point_add(const curve_point *cp1, curve_point *cp2) +void point_add(const ecdsa_curve *curve, const curve_point *cp1, curve_point *cp2) { - int i; - uint32_t temp; bignum256 lambda, inv, xr, yr; if (point_is_infinity(cp1)) { @@ -56,7 +57,7 @@ void point_add(const curve_point *cp1, curve_point *cp2) return; } if (point_is_equal(cp1, cp2)) { - point_double(cp2); + point_double(curve, cp2); return; } if (point_is_negative_of(cp1, cp2)) { @@ -64,39 +65,34 @@ void point_add(const curve_point *cp1, curve_point *cp2) return; } - bn_subtractmod(&(cp2->x), &(cp1->x), &inv, &prime256k1); - bn_inverse(&inv, &prime256k1); - bn_subtractmod(&(cp2->y), &(cp1->y), &lambda, &prime256k1); - bn_multiply(&inv, &lambda, &prime256k1); + bn_subtractmod(&(cp2->x), &(cp1->x), &inv, &curve->prime); + bn_inverse(&inv, &curve->prime); + bn_subtractmod(&(cp2->y), &(cp1->y), &lambda, &curve->prime); + bn_multiply(&inv, &lambda, &curve->prime); // xr = lambda^2 - x1 - x2 xr = lambda; - bn_multiply(&xr, &xr, &prime256k1); - temp = 1; - for (i = 0; i < 9; i++) { - temp += 0x3FFFFFFF + xr.val[i] + 2u * prime256k1.val[i] - cp1->x.val[i] - cp2->x.val[i]; - xr.val[i] = temp & 0x3FFFFFFF; - temp >>= 30; - } - bn_fast_mod(&xr, &prime256k1); - bn_mod(&xr, &prime256k1); + bn_multiply(&xr, &xr, &curve->prime); + yr = cp1->x; + bn_addmod(&yr, &(cp2->x), &curve->prime); + bn_subtractmod(&xr, &yr, &xr, &curve->prime); + bn_fast_mod(&xr, &curve->prime); + bn_mod(&xr, &curve->prime); // yr = lambda (x1 - xr) - y1 - bn_subtractmod(&(cp1->x), &xr, &yr, &prime256k1); - bn_multiply(&lambda, &yr, &prime256k1); - bn_subtractmod(&yr, &(cp1->y), &yr, &prime256k1); - bn_fast_mod(&yr, &prime256k1); - bn_mod(&yr, &prime256k1); + bn_subtractmod(&(cp1->x), &xr, &yr, &curve->prime); + bn_multiply(&lambda, &yr, &curve->prime); + bn_subtractmod(&yr, &(cp1->y), &yr, &curve->prime); + bn_fast_mod(&yr, &curve->prime); + bn_mod(&yr, &curve->prime); cp2->x = xr; cp2->y = yr; } // cp = cp + cp -void point_double(curve_point *cp) +void point_double(const ecdsa_curve *curve, curve_point *cp) { - int i; - uint32_t temp; bignum256 lambda, xr, yr; if (point_is_infinity(cp)) { @@ -107,31 +103,32 @@ void point_double(curve_point *cp) return; } - // lambda = 3/2 x^2 / y + // lambda = (3 x^2 + a) / (2 y) lambda = cp->y; - bn_inverse(&lambda, &prime256k1); - bn_multiply(&cp->x, &lambda, &prime256k1); - bn_multiply(&cp->x, &lambda, &prime256k1); - bn_mult_3_2(&lambda, &prime256k1); + bn_mult_k(&lambda, 2, &curve->prime); + bn_inverse(&lambda, &curve->prime); + + xr = cp->x; + bn_multiply(&xr, &xr, &curve->prime); + bn_mult_k(&xr, 3, &curve->prime); + bn_addmod(&xr, &curve->a, &curve->prime); + bn_multiply(&xr, &lambda, &curve->prime); // xr = lambda^2 - 2*x xr = lambda; - bn_multiply(&xr, &xr, &prime256k1); - temp = 1; - for (i = 0; i < 9; i++) { - temp += 0x3FFFFFFF + xr.val[i] + 2u * (prime256k1.val[i] - cp->x.val[i]); - xr.val[i] = temp & 0x3FFFFFFF; - temp >>= 30; - } - bn_fast_mod(&xr, &prime256k1); - bn_mod(&xr, &prime256k1); + bn_multiply(&xr, &xr, &curve->prime); + yr = cp->x; + bn_lshift(&yr); + bn_subtractmod(&xr, &yr, &xr, &curve->prime); + bn_fast_mod(&xr, &curve->prime); + bn_mod(&xr, &curve->prime); // yr = lambda (x - xr) - y - bn_subtractmod(&(cp->x), &xr, &yr, &prime256k1); - bn_multiply(&lambda, &yr, &prime256k1); - bn_subtractmod(&yr, &(cp->y), &yr, &prime256k1); - bn_fast_mod(&yr, &prime256k1); - bn_mod(&yr, &prime256k1); + bn_subtractmod(&(cp->x), &xr, &yr, &curve->prime); + bn_multiply(&lambda, &yr, &curve->prime); + bn_subtractmod(&yr, &(cp->y), &yr, &curve->prime); + bn_fast_mod(&yr, &curve->prime); + bn_mod(&yr, &curve->prime); cp->x = xr; cp->y = yr; @@ -176,7 +173,7 @@ int point_is_negative_of(const curve_point *p, const curve_point *q) // Negate a (modulo prime) if cond is 0xffffffff, keep it if cond is 0. // The timing of this function does not depend on cond. -static void conditional_negate(uint32_t cond, bignum256 *a, const bignum256 *prime) +void conditional_negate(uint32_t cond, bignum256 *a, const bignum256 *prime) { int j; uint32_t tmp = 1; @@ -193,7 +190,7 @@ typedef struct jacobian_curve_point { bignum256 x, y, z; } jacobian_curve_point; -static void curve_to_jacobian(const curve_point *p, jacobian_curve_point *jp) { +void curve_to_jacobian(const curve_point *p, jacobian_curve_point *jp, const bignum256 *prime) { int i; // randomize z coordinate for (i = 0; i < 8; i++) { @@ -202,41 +199,39 @@ static void curve_to_jacobian(const curve_point *p, jacobian_curve_point *jp) { jp->z.val[8] = (random32() & 0x7fff) + 1; jp->x = jp->z; - bn_multiply(&jp->z, &jp->x, &prime256k1); + bn_multiply(&jp->z, &jp->x, prime); // x = z^2 jp->y = jp->x; - bn_multiply(&jp->z, &jp->y, &prime256k1); + bn_multiply(&jp->z, &jp->y, prime); // y = z^3 - bn_multiply(&p->x, &jp->x, &prime256k1); - bn_multiply(&p->y, &jp->y, &prime256k1); - bn_mod(&jp->x, &prime256k1); - bn_mod(&jp->y, &prime256k1); + bn_multiply(&p->x, &jp->x, prime); + bn_multiply(&p->y, &jp->y, prime); + bn_mod(&jp->x, prime); + bn_mod(&jp->y, prime); } -static void jacobian_to_curve(const jacobian_curve_point *jp, curve_point *p) { +void jacobian_to_curve(const jacobian_curve_point *jp, curve_point *p, const bignum256 *prime) { p->y = jp->z; - bn_mod(&p->y, &prime256k1); - bn_inverse(&p->y, &prime256k1); + bn_mod(&p->y, prime); + bn_inverse(&p->y, prime); // p->y = z^-1 p->x = p->y; - bn_multiply(&p->x, &p->x, &prime256k1); + bn_multiply(&p->x, &p->x, prime); // p->x = z^-2 - bn_multiply(&p->x, &p->y, &prime256k1); + bn_multiply(&p->x, &p->y, prime); // p->y = z^-3 - bn_multiply(&jp->x, &p->x, &prime256k1); + bn_multiply(&jp->x, &p->x, prime); // p->x = jp->x * z^-2 - bn_multiply(&jp->y, &p->y, &prime256k1); + bn_multiply(&jp->y, &p->y, prime); // p->y = jp->y * z^-3 - bn_mod(&p->x, &prime256k1); - bn_mod(&p->y, &prime256k1); + bn_mod(&p->x, prime); + bn_mod(&p->y, prime); } -static void point_jacobian_add(const curve_point *p1, jacobian_curve_point *p2) { +void point_jacobian_add(const curve_point *p1, jacobian_curve_point *p2, const bignum256 *prime) { bignum256 r, h; bignum256 rsq, hcb, hcby2, hsqx2; - int j; - uint64_t tmp1; /* usual algorithm: * @@ -270,75 +265,70 @@ static void point_jacobian_add(const curve_point *p1, jacobian_curve_point *p2) // h = x1 * z2^2 - x2; // r = y1 * z2^3 - y2; h = p2->z; - bn_multiply(&h, &h, &prime256k1); // h = z2^2 + bn_multiply(&h, &h, prime); // h = z2^2 r = p2->z; - bn_multiply(&h, &r, &prime256k1); // r = z2^3 + bn_multiply(&h, &r, prime); // r = z2^3 - bn_multiply(&p1->x, &h, &prime256k1); - bn_subtractmod(&h, &p2->x, &h, &prime256k1); + bn_multiply(&p1->x, &h, prime); + bn_subtractmod(&h, &p2->x, &h, prime); // h = x1 * z2^2 - x2; - bn_multiply(&p1->y, &r, &prime256k1); - bn_subtractmod(&r, &p2->y, &r, &prime256k1); + bn_multiply(&p1->y, &r, prime); + bn_subtractmod(&r, &p2->y, &r, prime); // r = y1 * z2^3 - y2; // hsqx2 = h^2 hsqx2 = h; - bn_multiply(&hsqx2, &hsqx2, &prime256k1); + bn_multiply(&hsqx2, &hsqx2, prime); // hcb = h^3 hcb = h; - bn_multiply(&hsqx2, &hcb, &prime256k1); + bn_multiply(&hsqx2, &hcb, prime); // hsqx2 = h^2 * x2 - bn_multiply(&p2->x, &hsqx2, &prime256k1); + bn_multiply(&p2->x, &hsqx2, prime); // hcby2 = h^3 * y2 hcby2 = hcb; - bn_multiply(&p2->y, &hcby2, &prime256k1); + bn_multiply(&p2->y, &hcby2, prime); // rsq = r^2 rsq = r; - bn_multiply(&rsq, &rsq, &prime256k1); + bn_multiply(&rsq, &rsq, prime); // z3 = h*z2 - bn_multiply(&h, &p2->z, &prime256k1); - bn_mod(&p2->z, &prime256k1); + bn_multiply(&h, &p2->z, prime); + bn_mod(&p2->z, prime); // x3 = r^2 - h^3 - 2h^2x2 - tmp1 = 0; - for (j = 0; j < 9; j++) { - tmp1 += (uint64_t) rsq.val[j] + 4*prime256k1.val[j] - hcb.val[j] - 2*hsqx2.val[j]; - assert(tmp1 < 5 * 0x40000000ull); - p2->x.val[j] = tmp1 & 0x3fffffff; - tmp1 >>= 30; - } - bn_fast_mod(&p2->x, &prime256k1); - bn_mod(&p2->x, &prime256k1); + bn_addmod(&hcb, &hsqx2, prime); + bn_addmod(&hcb, &hsqx2, prime); + bn_subtractmod(&rsq, &hcb, &p2->x, prime); + bn_fast_mod(&p2->x, prime); + bn_mod(&p2->x, prime); // y3 = r*(h^2x2 - x3) - y2*h^3 - bn_subtractmod(&hsqx2, &p2->x, &p2->y, &prime256k1); - bn_multiply(&r, &p2->y, &prime256k1); - bn_subtractmod(&p2->y, &hcby2, &p2->y, &prime256k1); - bn_fast_mod(&p2->y, &prime256k1); - bn_mod(&p2->y, &prime256k1); + bn_subtractmod(&hsqx2, &p2->x, &p2->y, prime); + bn_multiply(&r, &p2->y, prime); + bn_subtractmod(&p2->y, &hcby2, &p2->y, prime); + bn_fast_mod(&p2->y, prime); + bn_mod(&p2->y, prime); } -static void point_jacobian_double(jacobian_curve_point *p) { - bignum256 m, msq, ysq, xysq; - int j; - uint32_t tmp1; +void point_jacobian_double(jacobian_curve_point *p, const ecdsa_curve *curve) { + bignum256 az4, m, msq, ysq, xysq; + const bignum256 *prime = &curve->prime; /* usual algorithm: * - * lambda = (3(x/z^2)^2 / 2y/z^3) = 3x^2/2yz + * lambda = (3((x/z^2)^2 + a) / 2y/z^3) = (3x^2 + az^4)/2yz * x3/z3^2 = lambda^2 - 2x/z^2 * y3/z3^3 = lambda * (x/z^2 - x3/z3^2) - y/z^3 * * to get rid of fraction we set - * m = 3/2 x^2 + * m = (3 x^2 + az^4) / 2 * Hence, - * lambda = m / yz + * lambda = m / yz = m / z3 * * With z3 = yz (the denominator of lambda) * we get x3 = lambda^2*z3^2 - 2*x/z^2*z3^2 @@ -347,57 +337,62 @@ static void point_jacobian_double(jacobian_curve_point *p) { * = m * (xy^2 - x3) - y^4 */ - /* m = 3/2*x*x + /* m = (3*x^2 + a z^4) / 2 * x3 = m^2 - 2*xy^2 * y3 = m*(xy^2 - x3) - 8y^4 * z3 = y*z */ m = p->x; - bn_multiply(&m, &m, &prime256k1); - bn_mult_3_2(&m, &prime256k1); + bn_multiply(&m, &m, prime); + bn_mult_k(&m, 3, prime); + + az4 = p->z; + bn_multiply(&az4, &az4, prime); + bn_multiply(&az4, &az4, prime); + bn_multiply(&curve->a, &az4, prime); + bn_addmod(&m, &az4, prime); + bn_mult_half(&m, prime); // msq = m^2 msq = m; - bn_multiply(&msq, &msq, &prime256k1); + bn_multiply(&msq, &msq, prime); // ysq = y^2 ysq = p->y; - bn_multiply(&ysq, &ysq, &prime256k1); + bn_multiply(&ysq, &ysq, prime); // xysq = xy^2 xysq = p->x; - bn_multiply(&ysq, &xysq, &prime256k1); + bn_multiply(&ysq, &xysq, prime); // z3 = yz - bn_multiply(&p->y, &p->z, &prime256k1); - bn_mod(&p->z, &prime256k1); + bn_multiply(&p->y, &p->z, prime); + bn_mod(&p->z, prime); // x3 = m^2 - 2*xy^2 - tmp1 = 0; - for (j = 0; j < 9; j++) { - tmp1 += msq.val[j] + 3*prime256k1.val[j] - 2*xysq.val[j]; - p->x.val[j] = tmp1 & 0x3fffffff; - tmp1 >>= 30; - } - bn_fast_mod(&p->x, &prime256k1); - bn_mod(&p->x, &prime256k1); + p->x = xysq; + bn_mod(&p->x, prime); + bn_lshift(&p->x); + bn_subtractmod(&msq, &p->x, &p->x, prime); + bn_fast_mod(&p->x, prime); + bn_mod(&p->x, prime); // y3 = m*(xy^2 - x3) - y^4 - bn_subtractmod(&xysq, &p->x, &p->y, &prime256k1); - bn_multiply(&m, &p->y, &prime256k1); - bn_multiply(&ysq, &ysq, &prime256k1); - bn_subtractmod(&p->y, &ysq, &p->y, &prime256k1); - bn_fast_mod(&p->y, &prime256k1); - bn_mod(&p->y, &prime256k1); + bn_subtractmod(&xysq, &p->x, &p->y, prime); + bn_multiply(&m, &p->y, prime); + bn_multiply(&ysq, &ysq, prime); + bn_subtractmod(&p->y, &ysq, &p->y, prime); + bn_fast_mod(&p->y, prime); + bn_mod(&p->y, prime); } // res = k * p -void point_multiply(const bignum256 *k, const curve_point *p, curve_point *res) +void point_multiply(const ecdsa_curve *curve, const bignum256 *k, const curve_point *p, curve_point *res) { // this algorithm is loosely based on // Katsuyuki Okeya and Tsuyoshi Takagi, The Width-w NAF Method Provides // Small Memory and Fast Elliptic Scalar Multiplications Secure against // Side Channel Attacks. - assert (bn_is_less(k, &order256k1)); + assert (bn_is_less(k, &curve->order)); int i, j; int pos, shift; @@ -406,21 +401,22 @@ void point_multiply(const bignum256 *k, const curve_point *p, curve_point *res) uint32_t bits, sign, nsign; jacobian_curve_point jres; curve_point pmult[8]; + const bignum256 *prime = &curve->prime; // is_even = 0xffffffff if k is even, 0 otherwise. // add 2^256. - // make number odd: subtract order256k1 if even + // make number odd: subtract curve->order if even uint32_t tmp = 1; uint32_t is_non_zero = 0; for (j = 0; j < 8; j++) { is_non_zero |= k->val[j]; - tmp += 0x3fffffff + k->val[j] - (order256k1.val[j] & is_even); + tmp += 0x3fffffff + k->val[j] - (curve->order.val[j] & is_even); a.val[j] = tmp & 0x3fffffff; tmp >>= 30; } is_non_zero |= k->val[j]; - a.val[j] = tmp + 0xffff + k->val[j] - (order256k1.val[j] & is_even); + a.val[j] = tmp + 0xffff + k->val[j] - (curve->order.val[j] & is_even); assert((a.val[0] & 1) != 0); // special case 0*p: just return zero. We don't care about constant time. @@ -429,7 +425,7 @@ void point_multiply(const bignum256 *k, const curve_point *p, curve_point *res) return; } - // Now a = k + 2^256 (mod order256k1) and a is odd. + // Now a = k + 2^256 (mod curve->order) and a is odd. // // The idea is to bring the new a into the form. // sum_{i=0..64} a[i] 16^i, where |a[i]| < 16 and a[i] is odd. @@ -437,7 +433,7 @@ void point_multiply(const bignum256 *k, const curve_point *p, curve_point *res) // add 1 to it and subtract 16 from a[i-1]. Afterwards, // a[64] = 1, which is the 2^256 that we added before. // - // Since k = a - 2^256 (mod order256k1), we can compute + // Since k = a - 2^256 (mod curve->order), we can compute // k*p = sum_{i=0..63} a[i] 16^i * p // // We compute |a[i]| * p in advance for all possible @@ -445,12 +441,12 @@ void point_multiply(const bignum256 *k, const curve_point *p, curve_point *res) // We compute p, 3*p, ..., 15*p and store it in the table pmult. // store p^2 temporarily in pmult[7] pmult[7] = *p; - point_double(&pmult[7]); + point_double(curve, &pmult[7]); // compute 3*p, etc by repeatedly adding p^2. pmult[0] = *p; for (i = 1; i < 8; i++) { pmult[i] = pmult[7]; - point_add(&pmult[i-1], &pmult[i]); + point_add(curve, &pmult[i-1], &pmult[i]); } // now compute res = sum_{i=0..63} a[i] * 16^i * p step by step, @@ -464,15 +460,15 @@ void point_multiply(const bignum256 *k, const curve_point *p, curve_point *res) sign = (bits >> 4) - 1; bits ^= sign; bits &= 15; - curve_to_jacobian(&pmult[bits>>1], &jres); + curve_to_jacobian(&pmult[bits>>1], &jres, prime); for (i = 62; i >= 0; i--) { // sign = sign(a[i+1]) (0xffffffff for negative, 0 for positive) // invariant jres = (-1)^sign sum_{j=i+1..63} (a[j] * 16^{j-i-1} * p) - point_jacobian_double(&jres); - point_jacobian_double(&jres); - point_jacobian_double(&jres); - point_jacobian_double(&jres); + point_jacobian_double(&jres, curve); + point_jacobian_double(&jres, curve); + point_jacobian_double(&jres, curve); + point_jacobian_double(&jres, curve); // get lowest 5 bits of a >> (i*4). pos = i*4/30; shift = i*4 % 30; @@ -483,44 +479,45 @@ void point_multiply(const bignum256 *k, const curve_point *p, curve_point *res) // negate last result to make signs of this round and the // last round equal. - conditional_negate(sign ^ nsign, &jres.z, &prime256k1); + conditional_negate(sign ^ nsign, &jres.z, prime); // add odd factor - point_jacobian_add(&pmult[bits >> 1], &jres); + point_jacobian_add(&pmult[bits >> 1], &jres, prime); sign = nsign; } - conditional_negate(sign, &jres.z, &prime256k1); - jacobian_to_curve(&jres, res); + conditional_negate(sign, &jres.z, prime); + jacobian_to_curve(&jres, res, prime); } #if USE_PRECOMPUTED_CP // res = k * G -// k must be a normalized number with 0 <= k < order256k1 -void scalar_multiply(const bignum256 *k, curve_point *res) +// k must be a normalized number with 0 <= k < curve->order +void scalar_multiply(const ecdsa_curve *curve, const bignum256 *k, curve_point *res) { - assert (bn_is_less(k, &order256k1)); + assert (bn_is_less(k, &curve->order)); int i, j; bignum256 a; uint32_t is_even = (k->val[0] & 1) - 1; uint32_t lowbits; jacobian_curve_point jres; + const bignum256 *prime = &curve->prime; // is_even = 0xffffffff if k is even, 0 otherwise. // add 2^256. - // make number odd: subtract order256k1 if even + // make number odd: subtract curve->order if even uint32_t tmp = 1; uint32_t is_non_zero = 0; for (j = 0; j < 8; j++) { is_non_zero |= k->val[j]; - tmp += 0x3fffffff + k->val[j] - (order256k1.val[j] & is_even); + tmp += 0x3fffffff + k->val[j] - (curve->order.val[j] & is_even); a.val[j] = tmp & 0x3fffffff; tmp >>= 30; } is_non_zero |= k->val[j]; - a.val[j] = tmp + 0xffff + k->val[j] - (order256k1.val[j] & is_even); + a.val[j] = tmp + 0xffff + k->val[j] - (curve->order.val[j] & is_even); assert((a.val[0] & 1) != 0); // special case 0*G: just return zero. We don't care about constant time. @@ -529,7 +526,7 @@ void scalar_multiply(const bignum256 *k, curve_point *res) return; } - // Now a = k + 2^256 (mod order256k1) and a is odd. + // Now a = k + 2^256 (mod curve->order) and a is odd. // // The idea is to bring the new a into the form. // sum_{i=0..64} a[i] 16^i, where |a[i]| < 16 and a[i] is odd. @@ -537,12 +534,12 @@ void scalar_multiply(const bignum256 *k, curve_point *res) // add 1 to it and subtract 16 from a[i-1]. Afterwards, // a[64] = 1, which is the 2^256 that we added before. // - // Since k = a - 2^256 (mod order256k1), we can compute + // Since k = a - 2^256 (mod curve->order), we can compute // k*G = sum_{i=0..63} a[i] 16^i * G // - // We have a big table secp256k1_cp that stores all possible + // We have a big table curve->cp that stores all possible // values of |a[i]| 16^i * G. - // secp256k1_cp[i][j] = (2*j+1) * 16^i * G + // curve->cp[i][j] = (2*j+1) * 16^i * G // now compute res = sum_{i=0..63} a[i] * 16^i * G step by step. // initial res = |a[0]| * G. Note that a[0] = a & 0xf if (a&0x10) != 0 @@ -552,7 +549,7 @@ void scalar_multiply(const bignum256 *k, curve_point *res) lowbits = a.val[0] & ((1 << 5) - 1); lowbits ^= (lowbits >> 4) - 1; lowbits &= 15; - curve_to_jacobian(&secp256k1_cp[0][lowbits >> 1], &jres); + curve_to_jacobian(&curve->cp[0][lowbits >> 1], &jres, prime); for (i = 1; i < 64; i ++) { // invariant res = sign(a[i-1]) sum_{j=0..i-1} (a[j] * 16^j * G) @@ -569,26 +566,26 @@ void scalar_multiply(const bignum256 *k, curve_point *res) lowbits &= 15; // negate last result to make signs of this round and the // last round equal. - conditional_negate((lowbits & 1) - 1, &jres.y, &prime256k1); + conditional_negate((lowbits & 1) - 1, &jres.y, prime); // add odd factor - point_jacobian_add(&secp256k1_cp[i][lowbits >> 1], &jres); + point_jacobian_add(&curve->cp[i][lowbits >> 1], &jres, prime); } - conditional_negate(((a.val[0] >> 4) & 1) - 1, &jres.y, &prime256k1); - jacobian_to_curve(&jres, res); + conditional_negate(((a.val[0] >> 4) & 1) - 1, &jres.y, prime); + jacobian_to_curve(&jres, res, prime); } #else -void scalar_multiply(const bignum256 *k, curve_point *res) +void scalar_multiply(const ecdsa_curve *curve, const bignum256 *k, curve_point *res) { - point_multiply(k, &G256k1, res); + point_multiply(curve, k, &curve->G, res); } #endif // generate random K for signing -int generate_k_random(bignum256 *k) { +int generate_k_random(const ecdsa_curve *curve, bignum256 *k) { int i, j; for (j = 0; j < 10000; j++) { for (i = 0; i < 8; i++) { @@ -596,7 +593,7 @@ int generate_k_random(bignum256 *k) { } k->val[8] = random32() & 0xFFFF; // if k is too big or too small, we don't like it - if ( !bn_is_zero(k) && bn_is_less(k, &order256k1) ) { + if ( !bn_is_zero(k) && bn_is_less(k, &curve->order) ) { return 0; // good number - no error } } @@ -606,7 +603,7 @@ int generate_k_random(bignum256 *k) { // generate K in a deterministic way, according to RFC6979 // http://tools.ietf.org/html/rfc6979 -int generate_k_rfc6979(bignum256 *secret, const uint8_t *priv_key, const uint8_t *hash) +int generate_k_rfc6979(const ecdsa_curve *curve, bignum256 *secret, const uint8_t *priv_key, const uint8_t *hash) { int i; uint8_t v[32], k[32], bx[2*32], buf[32 + 1 + sizeof(bx)]; @@ -614,7 +611,7 @@ int generate_k_rfc6979(bignum256 *secret, const uint8_t *priv_key, const uint8_t memcpy(bx, priv_key, 32); bn_read_be(hash, &z1); - bn_mod(&z1, &order256k1); + bn_mod(&z1, &curve->order); bn_write_be(&z1, bx + 32); memset(v, 1, sizeof(v)); @@ -635,7 +632,7 @@ int generate_k_rfc6979(bignum256 *secret, const uint8_t *priv_key, const uint8_t for (i = 0; i < 10000; i++) { hmac_sha256(k, sizeof(k), v, sizeof(v), v); bn_read_be(v, secret); - if ( !bn_is_zero(secret) && bn_is_less(secret, &order256k1) ) { + if ( !bn_is_zero(secret) && bn_is_less(secret, &curve->order) ) { return 0; // good number -> no error } memcpy(buf, v, sizeof(v)); @@ -649,11 +646,11 @@ int generate_k_rfc6979(bignum256 *secret, const uint8_t *priv_key, const uint8_t // msg is a data to be signed // msg_len is the message length -int ecdsa_sign(const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby) +int ecdsa_sign(const ecdsa_curve *curve, const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby) { uint8_t hash[32]; sha256_Raw(msg, msg_len, hash); - int res = ecdsa_sign_digest(priv_key, hash, sig, pby); + int res = ecdsa_sign_digest(curve, priv_key, hash, sig, pby); MEMSET_BZERO(hash, sizeof(hash)); return res; @@ -661,12 +658,12 @@ int ecdsa_sign(const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, ui // msg is a data to be signed // msg_len is the message length -int ecdsa_sign_double(const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby) +int ecdsa_sign_double(const ecdsa_curve *curve, const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby) { uint8_t hash[32]; sha256_Raw(msg, msg_len, hash); sha256_Raw(hash, 32, hash); - int res = ecdsa_sign_digest(priv_key, hash, sig, pby); + int res = ecdsa_sign_digest(curve, priv_key, hash, sig, pby); MEMSET_BZERO(hash, sizeof(hash)); return res; } @@ -675,7 +672,7 @@ int ecdsa_sign_double(const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_ // priv_key is a 32 byte big endian stored number // sig is 64 bytes long array for the signature // digest is 32 bytes of digest -int ecdsa_sign_digest(const uint8_t *priv_key, const uint8_t *digest, uint8_t *sig, uint8_t *pby) +int ecdsa_sign_digest(const ecdsa_curve *curve, const uint8_t *priv_key, const uint8_t *digest, uint8_t *sig, uint8_t *pby) { uint32_t i; curve_point R; @@ -686,24 +683,24 @@ int ecdsa_sign_digest(const uint8_t *priv_key, const uint8_t *digest, uint8_t *s #if USE_RFC6979 // generate K deterministically - if (generate_k_rfc6979(&k, priv_key, digest) != 0) { + if (generate_k_rfc6979(curve, &k, priv_key, digest) != 0) { result = 1; } #else // generate random number k - if (generate_k_random(&k) != 0) { + if (generate_k_random(curve, &k) != 0) { result = 1; } #endif if (result == 0) { // compute k*G - scalar_multiply(&k, &R); + scalar_multiply(curve, &k, &R); if (pby) { *pby = R.y.val[0] & 1; } // r = (rx mod n) - bn_mod(&R.x, &order256k1); + bn_mod(&R.x, &curve->order); // if r is zero, we fail if (bn_is_zero(&R.x)) { @@ -712,17 +709,17 @@ int ecdsa_sign_digest(const uint8_t *priv_key, const uint8_t *digest, uint8_t *s } if (result == 0) { - bn_inverse(&k, &order256k1); + bn_inverse(&k, &curve->order); bn_read_be(priv_key, da); - bn_multiply(&R.x, da, &order256k1); + bn_multiply(&R.x, da, &curve->order); for (i = 0; i < 8; i++) { da->val[i] += z.val[i]; da->val[i + 1] += (da->val[i] >> 30); da->val[i] &= 0x3FFFFFFF; } da->val[8] += z.val[8]; - bn_multiply(da, &k, &order256k1); - bn_mod(&k, &order256k1); + bn_multiply(da, &k, &curve->order); + bn_mod(&k, &curve->order); // if k is zero, we fail if (bn_is_zero(&k)) { result = 3; @@ -730,13 +727,6 @@ int ecdsa_sign_digest(const uint8_t *priv_key, const uint8_t *digest, uint8_t *s } if (result == 0) { - // if S > order/2 => S = -S - if (bn_is_less(&order256k1_half, &k)) { - bn_subtract(&order256k1, &k, &k); - if (pby) { - *pby = !*pby; - } - } // we are done, R.x and k is the result signature bn_write_be(&R.x, sig); bn_write_be(&k, sig + 32); @@ -748,28 +738,28 @@ int ecdsa_sign_digest(const uint8_t *priv_key, const uint8_t *digest, uint8_t *s return 0; } -void ecdsa_get_public_key33(const uint8_t *priv_key, uint8_t *pub_key) +void ecdsa_get_public_key33(const ecdsa_curve *curve, const uint8_t *priv_key, uint8_t *pub_key) { curve_point R; bignum256 k; bn_read_be(priv_key, &k); // compute k*G - scalar_multiply(&k, &R); + scalar_multiply(curve, &k, &R); pub_key[0] = 0x02 | (R.y.val[0] & 0x01); bn_write_be(&R.x, pub_key + 1); MEMSET_BZERO(&R, sizeof(R)); MEMSET_BZERO(&k, sizeof(k)); } -void ecdsa_get_public_key65(const uint8_t *priv_key, uint8_t *pub_key) +void ecdsa_get_public_key65(const ecdsa_curve *curve, const uint8_t *priv_key, uint8_t *pub_key) { curve_point R; bignum256 k; bn_read_be(priv_key, &k); // compute k*G - scalar_multiply(&k, &R); + scalar_multiply(curve, &k, &R); pub_key[0] = 0x04; bn_write_be(&R.x, pub_key + 1); bn_write_be(&R.y, pub_key + 33); @@ -825,30 +815,30 @@ int ecdsa_address_decode(const char *addr, uint8_t *out) return base58_decode_check(addr, out, 21) == 21; } -void uncompress_coords(uint8_t odd, const bignum256 *x, bignum256 *y) +void uncompress_coords(const ecdsa_curve *curve, uint8_t odd, const bignum256 *x, bignum256 *y) { // y^2 = x^3 + 0*x + 7 memcpy(y, x, sizeof(bignum256)); // y is x - bn_multiply(x, y, &prime256k1); // y is x^2 - bn_multiply(x, y, &prime256k1); // y is x^3 - bn_addmodi(y, 7, &prime256k1); // y is x^3 + 7 - bn_sqrt(y, &prime256k1); // y = sqrt(y) + bn_multiply(x, y, &curve->prime); // y is x^2 + bn_multiply(x, y, &curve->prime); // y is x^3 + bn_addmodi(y, 7, &curve->prime); // y is x^3 + 7 + bn_sqrt(y, &curve->prime); // y = sqrt(y) if ((odd & 0x01) != (y->val[0] & 1)) { - bn_subtract(&prime256k1, y, y); // y = -y + bn_subtract(&curve->prime, y, y); // y = -y } } -int ecdsa_read_pubkey(const uint8_t *pub_key, curve_point *pub) +int ecdsa_read_pubkey(const ecdsa_curve *curve, const uint8_t *pub_key, curve_point *pub) { if (pub_key[0] == 0x04) { bn_read_be(pub_key + 1, &(pub->x)); bn_read_be(pub_key + 33, &(pub->y)); - return ecdsa_validate_pubkey(pub); + return ecdsa_validate_pubkey(curve, pub); } if (pub_key[0] == 0x02 || pub_key[0] == 0x03) { // compute missing y coords bn_read_be(pub_key + 1, &(pub->x)); - uncompress_coords(pub_key[0], &(pub->x), &(pub->y)); - return ecdsa_validate_pubkey(pub); + uncompress_coords(curve, pub_key[0], &(pub->x), &(pub->y)); + return ecdsa_validate_pubkey(curve, pub); } // error return 0; @@ -859,7 +849,7 @@ int ecdsa_read_pubkey(const uint8_t *pub_key, curve_point *pub) // - pub->x and pub->y are in range [0,p-1]. // - pub is on the curve. -int ecdsa_validate_pubkey(const curve_point *pub) +int ecdsa_validate_pubkey(const ecdsa_curve *curve, const curve_point *pub) { bignum256 y_2, x_3_b; @@ -867,7 +857,7 @@ int ecdsa_validate_pubkey(const curve_point *pub) return 0; } - if (!bn_is_less(&(pub->x), &prime256k1) || !bn_is_less(&(pub->y), &prime256k1)) { + if (!bn_is_less(&(pub->x), &curve->prime) || !bn_is_less(&(pub->y), &curve->prime)) { return 0; } @@ -875,13 +865,13 @@ int ecdsa_validate_pubkey(const curve_point *pub) memcpy(&x_3_b, &(pub->x), sizeof(bignum256)); // y^2 - bn_multiply(&(pub->y), &y_2, &prime256k1); - bn_mod(&y_2, &prime256k1); + bn_multiply(&(pub->y), &y_2, &curve->prime); + bn_mod(&y_2, &curve->prime); // x^3 + b - bn_multiply(&(pub->x), &x_3_b, &prime256k1); - bn_multiply(&(pub->x), &x_3_b, &prime256k1); - bn_addmodi(&x_3_b, 7, &prime256k1); + bn_multiply(&(pub->x), &x_3_b, &curve->prime); + bn_multiply(&(pub->x), &x_3_b, &curve->prime); + bn_addmodi(&x_3_b, 7, &curve->prime); if (!bn_is_equal(&x_3_b, &y_2)) { return 0; @@ -896,32 +886,32 @@ int ecdsa_validate_pubkey(const curve_point *pub) // msg is a data that was signed // msg_len is the message length -int ecdsa_verify(const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, uint32_t msg_len) +int ecdsa_verify(const ecdsa_curve *curve, const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, uint32_t msg_len) { uint8_t hash[32]; sha256_Raw(msg, msg_len, hash); - int res = ecdsa_verify_digest(pub_key, sig, hash); + int res = ecdsa_verify_digest(curve, pub_key, sig, hash); MEMSET_BZERO(hash, sizeof(hash)); return res; } -int ecdsa_verify_double(const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, uint32_t msg_len) +int ecdsa_verify_double(const ecdsa_curve *curve, const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, uint32_t msg_len) { uint8_t hash[32]; sha256_Raw(msg, msg_len, hash); sha256_Raw(hash, 32, hash); - int res = ecdsa_verify_digest(pub_key, sig, hash); + int res = ecdsa_verify_digest(curve, pub_key, sig, hash); MEMSET_BZERO(hash, sizeof(hash)); return res; } // returns 0 if verification succeeded -int ecdsa_verify_digest(const uint8_t *pub_key, const uint8_t *sig, const uint8_t *digest) +int ecdsa_verify_digest(const ecdsa_curve *curve, const uint8_t *pub_key, const uint8_t *sig, const uint8_t *digest) { curve_point pub, res; bignum256 r, s, z; - if (!ecdsa_read_pubkey(pub_key, &pub)) { + if (!ecdsa_read_pubkey(curve, pub_key, &pub)) { return 1; } @@ -931,14 +921,14 @@ int ecdsa_verify_digest(const uint8_t *pub_key, const uint8_t *sig, const uint8_ bn_read_be(digest, &z); if (bn_is_zero(&r) || bn_is_zero(&s) || - (!bn_is_less(&r, &order256k1)) || - (!bn_is_less(&s, &order256k1))) return 2; + (!bn_is_less(&r, &curve->order)) || + (!bn_is_less(&s, &curve->order))) return 2; - bn_inverse(&s, &order256k1); // s^-1 - bn_multiply(&s, &z, &order256k1); // z*s^-1 - bn_mod(&z, &order256k1); - bn_multiply(&r, &s, &order256k1); // r*s^-1 - bn_mod(&s, &order256k1); + bn_inverse(&s, &curve->order); // s^-1 + bn_multiply(&s, &z, &curve->order); // z*s^-1 + bn_mod(&z, &curve->order); + bn_multiply(&r, &s, &curve->order); // r*s^-1 + bn_mod(&s, &curve->order); int result = 0; if (bn_is_zero(&z)) { @@ -946,14 +936,14 @@ int ecdsa_verify_digest(const uint8_t *pub_key, const uint8_t *sig, const uint8_ // I don't expect this to happen any time soon result = 3; } else { - scalar_multiply(&z, &res); + scalar_multiply(curve, &z, &res); } if (result == 0) { // both pub and res can be infinity, can have y = 0 OR can be equal -> false negative - point_multiply(&s, &pub, &pub); - point_add(&pub, &res); - bn_mod(&(res.x), &order256k1); + point_multiply(curve, &s, &pub, &pub); + point_add(curve, &pub, &res); + bn_mod(&(res.x), &curve->order); // signature does not match if (!bn_is_equal(&res.x, &r)) { result = 5; @@ -1006,3 +996,17 @@ int ecdsa_sig_to_der(const uint8_t *sig, uint8_t *der) *len = *len1 + *len2 + 4; return *len + 2; } + + +const ecdsa_curve *get_curve_by_name(const char *curve_name) { + if (curve_name == 0) { + return 0; + } + if (strcmp(curve_name, "secp256k1") == 0) { + return &secp256k1; + } + if (strcmp(curve_name, "nist256p1") == 0) { + return &nist256p1; + } + return 0; +} diff --git a/ecdsa.h b/ecdsa.h index be8cfcd46..85fe434b7 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -26,38 +26,57 @@ #include #include "options.h" -#include "secp256k1.h" +#include "bignum.h" + +// curve point x and y +typedef struct { + bignum256 x, y; +} curve_point; + +typedef struct { + + bignum256 prime; // prime order of the finite field + curve_point G; // initial curve point + bignum256 order; // order of G + bignum256 a; // coefficient 'a' of the elliptic curve + +#if USE_PRECOMPUTED_CP + const curve_point cp[64][8]; +#endif + +} ecdsa_curve; void point_copy(const curve_point *cp1, curve_point *cp2); -void point_add(const curve_point *cp1, curve_point *cp2); -void point_double(curve_point *cp); -void point_multiply(const bignum256 *k, const curve_point *p, curve_point *res); +void point_add(const ecdsa_curve *curve, const curve_point *cp1, curve_point *cp2); +void point_double(const ecdsa_curve *curve, curve_point *cp); +void point_multiply(const ecdsa_curve *curve, const bignum256 *k, const curve_point *p, curve_point *res); void point_set_infinity(curve_point *p); int point_is_infinity(const curve_point *p); int point_is_equal(const curve_point *p, const curve_point *q); int point_is_negative_of(const curve_point *p, const curve_point *q); -void scalar_multiply(const bignum256 *k, curve_point *res); -void uncompress_coords(uint8_t odd, const bignum256 *x, bignum256 *y); - -int ecdsa_sign(const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby); -int ecdsa_sign_double(const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby); -int ecdsa_sign_digest(const uint8_t *priv_key, const uint8_t *digest, uint8_t *sig, uint8_t *pby); -void ecdsa_get_public_key33(const uint8_t *priv_key, uint8_t *pub_key); -void ecdsa_get_public_key65(const uint8_t *priv_key, uint8_t *pub_key); +void scalar_multiply(const ecdsa_curve *curve, const bignum256 *k, curve_point *res); +void uncompress_coords(const ecdsa_curve *curve, uint8_t odd, const bignum256 *x, bignum256 *y); + +int ecdsa_sign(const ecdsa_curve *curve, const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby); +int ecdsa_sign_double(const ecdsa_curve *curve, const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby); +int ecdsa_sign_digest(const ecdsa_curve *curve, const uint8_t *priv_key, const uint8_t *digest, uint8_t *sig, uint8_t *pby); +void ecdsa_get_public_key33(const ecdsa_curve *curve, const uint8_t *priv_key, uint8_t *pub_key); +void ecdsa_get_public_key65(const ecdsa_curve *curve, const uint8_t *priv_key, uint8_t *pub_key); void ecdsa_get_pubkeyhash(const uint8_t *pub_key, uint8_t *pubkeyhash); void ecdsa_get_address_raw(const uint8_t *pub_key, uint8_t version, uint8_t *addr_raw); void ecdsa_get_address(const uint8_t *pub_key, uint8_t version, char *addr, int addrsize); void ecdsa_get_wif(const uint8_t *priv_key, uint8_t version, char *wif, int wifsize); int ecdsa_address_decode(const char *addr, uint8_t *out); -int ecdsa_read_pubkey(const uint8_t *pub_key, curve_point *pub); -int ecdsa_validate_pubkey(const curve_point *pub); -int ecdsa_verify(const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, uint32_t msg_len); -int ecdsa_verify_double(const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, uint32_t msg_len); -int ecdsa_verify_digest(const uint8_t *pub_key, const uint8_t *sig, const uint8_t *digest); +int ecdsa_read_pubkey(const ecdsa_curve *curve, const uint8_t *pub_key, curve_point *pub); +int ecdsa_validate_pubkey(const ecdsa_curve *curve, const curve_point *pub); +int ecdsa_verify(const ecdsa_curve *curve, const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, uint32_t msg_len); +int ecdsa_verify_double(const ecdsa_curve *curve, const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, uint32_t msg_len); +int ecdsa_verify_digest(const ecdsa_curve *curve, const uint8_t *pub_key, const uint8_t *sig, const uint8_t *digest); int ecdsa_sig_to_der(const uint8_t *sig, uint8_t *der); +const ecdsa_curve *get_curve_by_name(const char *curve_name); // Private -int generate_k_rfc6979(bignum256 *secret, const uint8_t *priv_key, const uint8_t *hash); -int generate_k_random(bignum256 *k); +int generate_k_rfc6979(const ecdsa_curve *curve, bignum256 *secret, const uint8_t *priv_key, const uint8_t *hash); +int generate_k_random(const ecdsa_curve *curve, bignum256 *k); #endif diff --git a/nist256p1.c b/nist256p1.c new file mode 100644 index 000000000..f6468b9bf --- /dev/null +++ b/nist256p1.c @@ -0,0 +1,50 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "nist256p1.h" + +const ecdsa_curve nist256p1 = { + /* .prime */ { + /*.val =*/ {0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3f, 0x0, 0x0, 0x1000, 0x3fffc000, 0xffff} + }, + + /* G */ { + /*.x =*/{/*.val =*/{0x1898c296, 0x1284e517, 0x1eb33a0f, 0xdf604b, 0x2440f277, 0x339b958e, 0x4247f8b, 0x347cb84b, 0x6b17}}, + /*.y =*/{/*.val =*/{0x37bf51f5, 0x2ed901a0, 0x3315ecec, 0x338cd5da, 0xf9e162b, 0x1fad29f0, 0x27f9b8ee, 0x10b8bf86, 0x4fe3}} + }, + + /* order */ { + /*.val =*/{0x3c632551, 0xee72b0b, 0x3179e84f, 0x39beab69, 0x3fffffbc, 0x3fffffff, 0xfff, 0x3fffc000, 0xffff} + }, + + /* a */ { + /*.val =*/{0x3ffffffc, 0x3fffffff, 0x3fffffff, 0x3f, 0x0, 0x0, 0x1000, 0x3fffc000, 0xffff} + } +#if USE_PRECOMPUTED_CP + , + /* cp */ { +#include "nist256p1.table" + } +#endif + +}; diff --git a/nist256p1.h b/nist256p1.h new file mode 100644 index 000000000..6afd91005 --- /dev/null +++ b/nist256p1.h @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __NIST256P1_H__ +#define __NIST256P1_H__ + +#include + +#include "ecdsa.h" + +extern const ecdsa_curve nist256p1; + +#endif diff --git a/nist256p1.table b/nist256p1.table new file mode 100644 index 000000000..c4fc22475 --- /dev/null +++ b/nist256p1.table @@ -0,0 +1,1664 @@ + { + /* 1*16^0*G: */ + {{{0x1898c296, 0x1284e517, 0x1eb33a0f, 0x00df604b, 0x2440f277, 0x339b958e, 0x04247f8b, 0x347cb84b, 0x6b17}}, + {{0x37bf51f5, 0x2ed901a0, 0x3315ecec, 0x338cd5da, 0x0f9e162b, 0x1fad29f0, 0x27f9b8ee, 0x10b8bf86, 0x4fe3}}}, + /* 3*16^0*G: */ + {{{0x06e7fd6c, 0x2d05986f, 0x3ada985f, 0x31adc87b, 0x0bf165e6, 0x1fbe5475, 0x30a44c8f, 0x3934698c, 0x5ecb}}, + {{0x227d5032, 0x29e6c49e, 0x04fb83d9, 0x0aac0d8e, 0x24a2ecd8, 0x2c1b3869, 0x0ff7e374, 0x19031266, 0x8734}}}, + /* 5*16^0*G: */ + {{{0x03d033ed, 0x05552837, 0x35be5242, 0x2320bf47, 0x268fdfef, 0x13215821, 0x140d2d78, 0x02de9454, 0x5159}}, + {{0x3da16da4, 0x0742ed13, 0x0d80888d, 0x004bc035, 0x0a79260d, 0x06fcdafe, 0x2727d8ae, 0x1f6a2412, 0xe0c1}}}, + /* 7*16^0*G: */ + {{{0x3187b2a3, 0x0018a1c0, 0x00fef5b3, 0x3e7e2e2a, 0x01fb607e, 0x2cc199f0, 0x37b4625b, 0x0edbe82f, 0x8e53}}, + {{0x01f400b4, 0x15786a1b, 0x3041b21c, 0x31cd8cf2, 0x35900053, 0x1a7e0e9b, 0x318366d0, 0x076f780c, 0x73eb}}}, + /* 9*16^0*G: */ + {{{0x10949ee0, 0x1e7a292e, 0x06df8b3d, 0x02b2e30b, 0x31f8729e, 0x24e35475, 0x30b71878, 0x35edbfb7, 0xea68}}, + {{0x0dd048fa, 0x21688929, 0x0de823fe, 0x1c53faa9, 0x0ea0c84d, 0x052a592a, 0x1fce7870, 0x11325cb2, 0x2a27}}}, + /* 11*16^0*G: */ + {{{0x34bc21d1, 0x0cce474d, 0x15048bf4, 0x1d0bb409, 0x021cda16, 0x20de76c3, 0x34c59063, 0x04ede20e, 0x3ed1}}, + {{0x282a3740, 0x0be3bbf3, 0x29889dae, 0x03413697, 0x34c68a09, 0x210ebe93, 0x0c8a224c, 0x0826b331, 0x9099}}}, + /* 13*16^0*G: */ + {{{0x06072c01, 0x23857675, 0x1ead58a9, 0x0b8a12d9, 0x1ee2fc79, 0x0177cb61, 0x0495a618, 0x20deb82b, 0x177c}}, + {{0x2fc7bfd8, 0x310eef8b, 0x1fb4df39, 0x3b8530e8, 0x0f4e7226, 0x0246b6d0, 0x2a558a24, 0x163353af, 0x63bb}}}, + /* 15*16^0*G: */ + {{{0x259b9d5f, 0x0d9a318f, 0x23a0ef16, 0x00ebe4b7, 0x088265ae, 0x2cde2666, 0x2bae7adf, 0x1371a5c6, 0xf045}}, + {{0x0d034f36, 0x1f967378, 0x1b5fa3f4, 0x0ec8739d, 0x1643e62a, 0x1653947e, 0x22d1f4e6, 0x0fb8d64b, 0xb5b9}}} + }, + { + /* 1*16^1*G: */ + {{{0x21277c6e, 0x17ad1e1f, 0x36ca038a, 0x0a0e4bbf, 0x36315fcd, 0x08718a60, 0x341858b8, 0x1344e29a, 0x76a9}}, + {{0x0b8c5110, 0x3a7775c9, 0x3c78baa0, 0x26680103, 0x1e872085, 0x0286d784, 0x3260e6cb, 0x3f984d07, 0xa985}}}, + /* 3*16^1*G: */ + {{{0x1e4536ca, 0x2fee771a, 0x2201a61a, 0x0ba4a582, 0x30cda11c, 0x39d16f81, 0x139ec8cc, 0x3ec39249, 0x9482}}, + {{0x358cc1c8, 0x3eb618ef, 0x307bfbb1, 0x0f578a55, 0x134e63f6, 0x358e329d, 0x157f91a5, 0x2729d17c, 0x351d}}}, + /* 5*16^1*G: */ + {{{0x15ecff13, 0x26c76b8a, 0x3d0633c4, 0x1d928736, 0x081eeb63, 0x0d69454c, 0x131195b8, 0x2df05eba, 0xb2e1}}, + {{0x32187d44, 0x0ee92626, 0x3dea2e6a, 0x3686a605, 0x1758c387, 0x0e868aab, 0x3ebccf23, 0x1104c4e8, 0xe6c0}}}, + /* 7*16^1*G: */ + {{{0x2ef87286, 0x22eeccd3, 0x02309e43, 0x00fa1f7f, 0x06ee3407, 0x105df72f, 0x36bc2cb3, 0x118b9fc6, 0xb433}}, + {{0x041496d9, 0x2b011fda, 0x22cea4b7, 0x3388201a, 0x292e6f9d, 0x3d39cb05, 0x2b5fe383, 0x15149bb4, 0xa0da}}}, + /* 9*16^1*G: */ + {{{0x19794381, 0x2e61ad6c, 0x2b0c7601, 0x245621d7, 0x167b1918, 0x1ba416d5, 0x1a24cc18, 0x0833934f, 0xa474}}, + {{0x22769c52, 0x25b38e9f, 0x1f6ac786, 0x2970236e, 0x167afff3, 0x37e4d866, 0x1bfe0e73, 0x3ff7def8, 0x2ebb}}}, + /* 11*16^1*G: */ + {{{0x09a5185a, 0x31d11992, 0x35e6f2be, 0x21c2b227, 0x0da3195b, 0x335004ac, 0x091485fe, 0x1e866e74, 0x05ba}}, + {{0x01de3a4e, 0x150f2238, 0x105ae001, 0x018882f2, 0x23d48e76, 0x1e08f893, 0x01896e46, 0x34ad7a0b, 0x30e0}}}, + /* 13*16^1*G: */ + {{{0x399b85fe, 0x2a8e62d7, 0x23a5dfd5, 0x03bfa6ab, 0x03e0b79c, 0x26364602, 0x3e2fd697, 0x1d327437, 0xb29f}}, + {{0x2da604dc, 0x2e990a5d, 0x3f59e80d, 0x3bd8f4c2, 0x17c6d92d, 0x01c4ba5b, 0x29785d5d, 0x16f0e9b0, 0xa3ce}}}, + /* 15*16^1*G: */ + {{{0x07e030ef, 0x1d9d15ba, 0x0d50e962, 0x1acac15f, 0x082b0857, 0x32fc0fc9, 0x1bcf5076, 0x26eaa2e4, 0x9929}}, + {{0x18d9aa9a, 0x3639adf7, 0x34008444, 0x304b1267, 0x0eaa7957, 0x0e04069b, 0x38e18bf3, 0x38f4cccf, 0x5cc2}}} + }, + { + /* 1*16^2*G: */ + {{{0x12d0441b, 0x36cb8d7c, 0x16a564c2, 0x0342dc43, 0x03ed6119, 0x3f454a18, 0x1165987f, 0x3528ec02, 0x34a2}}, + {{0x1e93b146, 0x10939e11, 0x2ddd81db, 0x35d9ae77, 0x377fc0e7, 0x29c411b9, 0x1e3c22bc, 0x3b5a94e8, 0xbeaa}}}, + /* 3*16^2*G: */ + {{{0x3da08424, 0x3392b8ce, 0x0f644a9d, 0x2fedeadd, 0x1d23ed3a, 0x2317fea5, 0x359aa1b5, 0x0281eb70, 0xa98b}}, + {{0x2831800c, 0x184a1e83, 0x0df582d3, 0x0afa02e8, 0x1d132075, 0x067a3238, 0x19b66e53, 0x3191c892, 0x4754}}}, + /* 5*16^2*G: */ + {{{0x083c2d6a, 0x14b5f97a, 0x1bd29b3b, 0x0be46360, 0x1a696dd2, 0x2dade321, 0x1aac5d21, 0x3c027223, 0xa034}}, + {{0x02c30e72, 0x10cdbbcb, 0x2267e7cf, 0x0180d7c5, 0x2ceb06be, 0x36e15173, 0x19c1fb0c, 0x000db2a2, 0xfe1b}}}, + /* 7*16^2*G: */ + {{{0x28be8c78, 0x05a94774, 0x3793e4d7, 0x025b3e0a, 0x22e9a14a, 0x1b8ad025, 0x14401a07, 0x09bfcc67, 0xb522}}, + {{0x11686903, 0x00cd9f29, 0x1b58ff32, 0x27dff239, 0x12851a81, 0x2cd9a5fa, 0x1f540ca1, 0x38327d4e, 0x701e}}}, + /* 9*16^2*G: */ + {{{0x2058b5a4, 0x0103f902, 0x131979b7, 0x11193e1e, 0x0c4713de, 0x233b33f3, 0x205b3d96, 0x221861a3, 0xa3e3}}, + {{0x27113aef, 0x3cc1b643, 0x371a2948, 0x3ba116ed, 0x17e68f3c, 0x239aceba, 0x0d12c384, 0x15e21f7c, 0xcfd4}}}, + /* 11*16^2*G: */ + {{{0x04a08314, 0x017d7b24, 0x1c7dff7a, 0x3f8db6cb, 0x21197a82, 0x332ae688, 0x3a539333, 0x151284c7, 0x2099}}, + {{0x27573ccc, 0x1fe32717, 0x2fcfe96e, 0x01b969cd, 0x1048dfd4, 0x2ea3972e, 0x33b1890f, 0x0f7f4aa8, 0xa5cf}}}, + /* 13*16^2*G: */ + {{{0x29078c18, 0x00bfe52b, 0x2ede9295, 0x3830f2bb, 0x1fd39b99, 0x3db9caab, 0x0ec70308, 0x1944eb30, 0x751d}}, + {{0x0ece0d67, 0x2635ba57, 0x3e05ac79, 0x02523072, 0x2a2a4ef0, 0x152ebda8, 0x24158853, 0x0fff7292, 0xba9c}}}, + /* 15*16^2*G: */ + {{{0x1e86d900, 0x0b3f3572, 0x3a3db449, 0x17b82745, 0x3a3b3640, 0x120c2280, 0x3801117b, 0x3d489711, 0x5be0}}, + {{0x358a5755, 0x13375a6f, 0x1b34f5ac, 0x085c9490, 0x35423df9, 0x1f8e939e, 0x2c422d34, 0x3679b7fc, 0x83d1}}} + }, + { + /* 1*16^3*G: */ + {{{0x2245573f, 0x01dfa36a, 0x0fd0a64f, 0x219dbcbd, 0x2d6bd250, 0x1e259cb9, 0x29e4d997, 0x2bb4b3c1, 0xe716}}, + {{0x069218d1, 0x017f09ad, 0x207c9b35, 0x0f437cbe, 0x39a851d1, 0x0ac19a1e, 0x072ab591, 0x18f9a53f, 0x3536}}}, + /* 3*16^3*G: */ + {{{0x257008ac, 0x3e61e4c1, 0x329edfb7, 0x3387b3b8, 0x1da22d19, 0x15562930, 0x07ce864e, 0x22635bd4, 0xd2bf}}, + {{0x327beb55, 0x04454d29, 0x1ff07988, 0x273842ad, 0x290c5667, 0x06576cfe, 0x377aa3f8, 0x2c72d69a, 0x69c0}}}, + /* 5*16^3*G: */ + {{{0x382f1580, 0x3435f2a5, 0x0203eb7f, 0x39377b89, 0x3064f8b0, 0x295ce47c, 0x3ce6087f, 0x0c13b960, 0x4d88}}, + {{0x1616edd7, 0x303ec5b5, 0x0eb1e110, 0x3f28ef5a, 0x3d6518aa, 0x1a002263, 0x0636ce8d, 0x139c26ac, 0x28a9}}}, + /* 7*16^3*G: */ + {{{0x20c38e11, 0x3e130f6b, 0x26e26ba5, 0x159086fa, 0x25af9e71, 0x1ce6480b, 0x00eeb326, 0x09c9f23f, 0x17c7}}, + {{0x2e90decd, 0x360d9aee, 0x20cdae3c, 0x14e65169, 0x01802e7e, 0x00bf33a4, 0x24b3c406, 0x293d3f99, 0x95c5}}}, + /* 9*16^3*G: */ + {{{0x232f36ea, 0x2557f62b, 0x13541c3d, 0x13d1a9ca, 0x0cb8b3cd, 0x0ec73f21, 0x050a8846, 0x3f6ab11d, 0x7e03}}, + {{0x0a68b8af, 0x2b308ff2, 0x05009d68, 0x27a5e693, 0x04af9941, 0x39ac5c06, 0x228da668, 0x357c4804, 0xdcf6}}}, + /* 11*16^3*G: */ + {{{0x1953baa9, 0x10f94a9b, 0x1e18de8d, 0x056ba192, 0x20b21426, 0x0deb0772, 0x3cf07616, 0x369a12c6, 0x8ce6}}, + {{0x352689e5, 0x239d70a3, 0x2a9341d7, 0x3ce61aed, 0x21b56807, 0x2cef2401, 0x3120be69, 0x13ee3ea4, 0x3d9f}}}, + /* 13*16^3*G: */ + {{{0x2f22a96a, 0x2ae3614e, 0x06ab8f94, 0x2c6ea767, 0x3ae2b008, 0x14d525d6, 0x0054a20a, 0x39cc1037, 0xb570}}, + {{0x085d1b00, 0x2ccfd987, 0x055cc9cc, 0x326ede96, 0x00cfbda7, 0x30dda6d7, 0x1e77f028, 0x2898e3dc, 0xdcd8}}}, + /* 15*16^3*G: */ + {{{0x189a7509, 0x3903ae51, 0x1fa80549, 0x09c2e590, 0x07f20de1, 0x0468f9d7, 0x3943b04a, 0x10c8f2ea, 0x44d9}}, + {{0x20437234, 0x0828ae6d, 0x14dd126e, 0x24f87f7c, 0x3b93586f, 0x08ef349d, 0x01f0a034, 0x2ce00210, 0xb2c5}}} + }, + { + /* 1*16^4*G: */ + {{{0x2eade3c4, 0x0fa11971, 0x1052a050, 0x12add272, 0x2586b471, 0x3190cd03, 0x1e90d8e5, 0x0d9bd3a4, 0xa018}}, + {{0x2b26e8d0, 0x11710809, 0x0614f37f, 0x3dca1391, 0x1d8369d5, 0x3395e0d2, 0x10b167c6, 0x3b05c504, 0xe2bb}}}, + /* 3*16^4*G: */ + {{{0x19e0af06, 0x38737ab1, 0x2ed958d6, 0x3ce62958, 0x05055c92, 0x34ed69b5, 0x1896450b, 0x07c02e23, 0x9cdf}}, + {{0x2216ade7, 0x35e8cb6d, 0x17ca5468, 0x2148b706, 0x0d94b082, 0x162ef372, 0x2ad664d9, 0x097fb4fc, 0x916d}}}, + /* 5*16^4*G: */ + {{{0x1305097e, 0x04dcae4e, 0x03ba5198, 0x3585c3a1, 0x00448338, 0x2c6cb415, 0x263edab6, 0x36757469, 0x45bf}}, + {{0x108ddc04, 0x12e8163a, 0x3d2c1595, 0x0ee74cef, 0x0ce90868, 0x220c151c, 0x2fd2bbad, 0x3704a156, 0x09d1}}}, + /* 7*16^4*G: */ + {{{0x363bd6df, 0x34c7c682, 0x166aec3c, 0x3f08f0b7, 0x095e6fd1, 0x3a7e700a, 0x2693b671, 0x2b45591d, 0xb599}}, + {{0x0efa09ac, 0x3a873a8e, 0x1134b458, 0x10313da4, 0x23c4166a, 0x1cd82e2c, 0x2b332463, 0x3477b13e, 0x6979}}}, + /* 9*16^4*G: */ + {{{0x27142d62, 0x3e184fcc, 0x03bc26da, 0x269a8d7e, 0x2854c11d, 0x18ac489f, 0x2ac0e926, 0x287c59cc, 0xf4dc}}, + {{0x3a618fc9, 0x327b3301, 0x1cd3d7fa, 0x25e6b3bf, 0x2bc659bb, 0x3ce06e46, 0x0cd46d49, 0x19f96d2d, 0x5511}}}, + /* 11*16^4*G: */ + {{{0x215fae61, 0x3b2c7fd1, 0x3395f821, 0x0571f713, 0x16bb5a7f, 0x1389039c, 0x09b66d9c, 0x1e2839b8, 0xf072}}, + {{0x096376f9, 0x1f432dd2, 0x037eabcf, 0x09c1c56e, 0x18f7d42c, 0x1e820862, 0x31ea5f7d, 0x06cac529, 0x1a68}}}, + /* 13*16^4*G: */ + {{{0x2466591f, 0x31381054, 0x3c68d6a0, 0x05cbaa3f, 0x2858ccbe, 0x0ead4cee, 0x20db0f14, 0x0915ebc2, 0x1fc5}}, + {{0x396f8cdb, 0x13bfbd5c, 0x2ec78224, 0x3e32b08c, 0x034e1629, 0x31dbf96d, 0x2bc11e9e, 0x060e0227, 0x489c}}}, + /* 15*16^4*G: */ + {{{0x322a8ebc, 0x09742e30, 0x0f967151, 0x24736dc6, 0x0a56d5a2, 0x3c2d6cc3, 0x0c5f4fd7, 0x006cc692, 0xfa25}}, + {{0x2a8a775b, 0x03649ed6, 0x0bc83318, 0x1638239b, 0x2fa8cbea, 0x14799869, 0x18962338, 0x0cac53e1, 0x71c9}}} + }, + { + /* 1*16^5*G: */ + {{{0x3d96dff1, 0x3df73b2d, 0x2d5fcfe8, 0x390c706a, 0x0d98d530, 0x1a82d5c3, 0x3e54ffef, 0x0e214507, 0x0ec7}}, + {{0x3c7b552c, 0x3b2106b1, 0x3ed78aa9, 0x149933a1, 0x0652511d, 0x3313bd60, 0x2875d91a, 0x13d3a1eb, 0xd622}}}, + /* 3*16^5*G: */ + {{{0x088d58e9, 0x070c92ac, 0x0e318385, 0x12970719, 0x02a7b6e9, 0x0a91a9f1, 0x24a86e99, 0x30ff71c1, 0x96da}}, + {{0x2ebebc5e, 0x00d24c4a, 0x087e6e38, 0x16fa26e5, 0x02c43968, 0x3312524e, 0x2c1ad856, 0x2bfceb51, 0xcb1f}}}, + /* 5*16^5*G: */ + {{{0x2db29f92, 0x254ab44c, 0x147b2c58, 0x08749c6e, 0x2b8f811d, 0x1770de2b, 0x0f312a10, 0x2c8f3ac5, 0xe297}}, + {{0x25e58ddb, 0x03ca5322, 0x1ed41416, 0x08f3aee1, 0x0d914912, 0x036eaee3, 0x370b4b48, 0x09483e32, 0xe137}}}, + /* 7*16^5*G: */ + {{{0x0ad88c33, 0x3650edee, 0x1746bcaf, 0x06b8e536, 0x24da97d9, 0x1af24834, 0x394b66b0, 0x08ce3eca, 0x1cd2}}, + {{0x248fb1b2, 0x0a3a9e10, 0x2ca1e496, 0x3f944c57, 0x36bc2713, 0x21902ac4, 0x348b096c, 0x337e0e2a, 0xfc3a}}}, + /* 9*16^5*G: */ + {{{0x3b26aa73, 0x14eb2270, 0x063a0e0f, 0x3df846c3, 0x3b1ee0cd, 0x32b4c37f, 0x1fbbfcb1, 0x35eb6e7a, 0xf462}}, + {{0x38479e73, 0x117ab05d, 0x0502cca2, 0x3a3828c0, 0x333c7a49, 0x0ee929a1, 0x053140d5, 0x03469e0d, 0x406a}}}, + /* 11*16^5*G: */ + {{{0x3cd015e3, 0x3b8780aa, 0x26502273, 0x243a565f, 0x095168af, 0x36facf2a, 0x30caf75b, 0x224974fd, 0xe0f6}}, + {{0x12157cce, 0x2a89350b, 0x22936bbd, 0x2e2d4e47, 0x34c77c55, 0x09a5b1c9, 0x03aa9536, 0x078c4392, 0x0853}}}, + /* 13*16^5*G: */ + {{{0x0bb76b12, 0x39b10c45, 0x21927691, 0x239d9dcf, 0x375a00ea, 0x20acc4ab, 0x3f57fc1d, 0x2b70554a, 0x28e4}}, + {{0x2c4747bd, 0x1f914e9f, 0x31628ff5, 0x282983c5, 0x1ea3f703, 0x12d96dae, 0x201b3f4e, 0x1313bf66, 0x14d7}}}, + /* 15*16^5*G: */ + {{{0x276ff697, 0x2fd6007f, 0x20764628, 0x26da2194, 0x2097c636, 0x07b6aece, 0x2805ed27, 0x2e89e52e, 0x85a0}}, + {{0x12142721, 0x027b5369, 0x10a58b93, 0x3a5ffe9e, 0x2daa551d, 0x1e434f73, 0x3e24a554, 0x0b987ab0, 0xadf3}}} + }, + { + /* 1*16^6*G: */ + {{{0x2392d805, 0x1c971773, 0x35405d43, 0x1ea01a61, 0x23449aa8, 0x1536abea, 0x293d7a4a, 0x3733d31a, 0xf8f5}}, + {{0x2cda02fa, 0x09986545, 0x12143ba0, 0x3cf69929, 0x21327351, 0x34f8cd91, 0x23054389, 0x1db3d9b5, 0xe581}}}, + /* 3*16^6*G: */ + {{{0x3fa046f7, 0x2752cc59, 0x207309d1, 0x0443ce40, 0x2e2d4517, 0x212b2251, 0x083a94e0, 0x2392a196, 0xe12c}}, + {{0x212646ad, 0x0e9568a2, 0x33119345, 0x03013844, 0x3126f6dd, 0x2cfb54e4, 0x1a2f3433, 0x011843f6, 0x7cec}}}, + /* 5*16^6*G: */ + {{{0x02853c43, 0x26c49fa3, 0x222e466b, 0x059b15eb, 0x11323648, 0x238bbf8f, 0x292093d0, 0x351d05e5, 0x394b}}, + {{0x2064469d, 0x05e0a332, 0x10fcf0cb, 0x0bd9c4b6, 0x160767d5, 0x38ff0bc7, 0x1c6b9207, 0x1b548547, 0x2b4d}}}, + /* 7*16^6*G: */ + {{{0x3c722e94, 0x30b75ce7, 0x1058961e, 0x36040e5b, 0x1404334e, 0x31995b16, 0x282e9445, 0x0e37ce37, 0xca85}}, + {{0x1049a527, 0x28298b7c, 0x08b26a43, 0x0254ea29, 0x3b9f12f2, 0x1cc49a87, 0x205c311e, 0x3f10bae7, 0x3b27}}}, + /* 9*16^6*G: */ + {{{0x1cad6309, 0x1c5d18a7, 0x239ff488, 0x0687f0bc, 0x267b3dd3, 0x2dd18932, 0x17b75a1b, 0x06967c8d, 0x663e}}, + {{0x09981f28, 0x0ca1ae8e, 0x2eb52bd5, 0x01f51100, 0x1cf918b9, 0x0b060f2c, 0x2a8c3c10, 0x2dcee019, 0x292f}}}, + /* 11*16^6*G: */ + {{{0x22c23d03, 0x09d6c914, 0x3c7ff249, 0x286c1363, 0x3beeab3b, 0x0db08dc1, 0x3667096c, 0x3bf9cc18, 0xa2d9}}, + {{0x3085db74, 0x00b93013, 0x039df451, 0x0269fa56, 0x101b92ea, 0x0c10db1c, 0x01b8f155, 0x148a3321, 0x1cc8}}}, + /* 13*16^6*G: */ + {{{0x07d4c6d1, 0x1d57e59c, 0x2d9fffb1, 0x18b35466, 0x3f35d0f6, 0x2442d49c, 0x1a9efe0b, 0x384ad22c, 0x5657}}, + {{0x0106bdec, 0x20c0fca6, 0x052c1418, 0x3e68d685, 0x2e6a0abf, 0x2ce43cce, 0x149f9acf, 0x2fbd2e37, 0x72b5}}}, + /* 15*16^6*G: */ + {{{0x1933564a, 0x21953755, 0x1e3af44f, 0x1a2d3ebb, 0x2d8d2b7a, 0x13b7199d, 0x2e001086, 0x18857502, 0x5b68}}, + {{0x0204ef63, 0x2d7c1162, 0x078869f3, 0x0abb88a2, 0x1d95de39, 0x0c315346, 0x2264552d, 0x3a9a73ce, 0x76b5}}} + }, + { + /* 1*16^7*G: */ + {{{0x2f922dbd, 0x21288c5d, 0x399218f9, 0x298c4587, 0x0d71b91c, 0x17aab639, 0x1af313f8, 0x2dafff53, 0x6d28}}, + {{0x20ef3cff, 0x12affc0a, 0x04da2994, 0x093a7c2e, 0x0b4a1c4c, 0x2f869873, 0x1d2fa40f, 0x36414507, 0xaf39}}}, + /* 3*16^7*G: */ + {{{0x1b168b64, 0x16437fe6, 0x186c840b, 0x14f40ab1, 0x14467ea1, 0x3c2417f0, 0x3e3ddd3d, 0x055e9fef, 0x7cd3}}, + {{0x1abbb16b, 0x15b034ad, 0x2e02e358, 0x2b1366dc, 0x1bfafb13, 0x1a39e2f3, 0x12c62205, 0x234845ca, 0x9ca0}}}, + /* 5*16^7*G: */ + {{{0x06ef29e8, 0x0ac71be8, 0x1d9aee3b, 0x371552c2, 0x05356264, 0x090c6675, 0x1f8c456b, 0x02f6d7cb, 0xed86}}, + {{0x39b90f8f, 0x00687126, 0x18daa335, 0x18c3d70b, 0x017bb1e7, 0x2fdacd01, 0x1a7fd7c6, 0x39d0dd75, 0xb837}}}, + /* 7*16^7*G: */ + {{{0x3636e617, 0x37e462cf, 0x1f1cf599, 0x37340ef0, 0x272c9d47, 0x3870b9f8, 0x21243735, 0x3323f474, 0x6868}}, + {{0x3cbb3d27, 0x323773cf, 0x0384cd71, 0x3f8c3229, 0x313f0a60, 0x1640e1e4, 0x3f9e6b3c, 0x02296e46, 0xeed0}}}, + /* 9*16^7*G: */ + {{{0x113e2a34, 0x1e768a98, 0x23a11e2c, 0x074b9973, 0x2fd31829, 0x32d27c42, 0x0fe202c5, 0x2cd83ab2, 0xec03}}, + {{0x384566d6, 0x10890fba, 0x1a136b7a, 0x2a055b99, 0x2122728a, 0x3f788404, 0x058437be, 0x03fed828, 0x8602}}}, + /* 11*16^7*G: */ + {{{0x087c1b18, 0x3ab83397, 0x04991a25, 0x078b2d52, 0x1056fa10, 0x0c0d6964, 0x0b90de6a, 0x1928e79e, 0xa794}}, + {{0x3b94809a, 0x3ad61425, 0x1562821b, 0x2637a71c, 0x1a89f60d, 0x295e1e7a, 0x058cc249, 0x3d38fdca, 0x1361}}}, + /* 13*16^7*G: */ + {{{0x1ed10d26, 0x2538a31b, 0x1e595f65, 0x26afbe0a, 0x330ccc5a, 0x247eda53, 0x3bcc790e, 0x3ca02aa3, 0x544e}}, + {{0x36dafcc2, 0x3f093dc9, 0x22c06ae2, 0x0f5be5db, 0x0d70d368, 0x2c77fa36, 0x2c2ce9d6, 0x07277116, 0x95b9}}}, + /* 15*16^7*G: */ + {{{0x37ad18e6, 0x1251e7e2, 0x13cad5e2, 0x2b4f9e63, 0x0aff9b57, 0x14f211ad, 0x0c6214de, 0x1b2217cd, 0xe2c2}}, + {{0x2554cfad, 0x36bf946a, 0x1981de4a, 0x3145729c, 0x17ba113b, 0x3899ba84, 0x0818851c, 0x06ca13d2, 0xb212}}} + }, + { + /* 1*16^8*G: */ + {{{0x185a5943, 0x296a7888, 0x065dfb63, 0x2e464d97, 0x2c71da1a, 0x15acc898, 0x2af89216, 0x1ad02bc8, 0x7fe3}}, + {{0x299ca101, 0x143454b1, 0x38af212d, 0x2cf5619e, 0x1ca6f174, 0x27d0101f, 0x236249f0, 0x3516096d, 0xe697}}}, + /* 3*16^8*G: */ + {{{0x1f0922a8, 0x1a9e0247, 0x05cf8d97, 0x243a7495, 0x2f8b808e, 0x09395808, 0x22d73809, 0x1a9016d3, 0x4b65}}, + {{0x199a80bb, 0x36b72b16, 0x1850f694, 0x1cee78ae, 0x18c4d6d4, 0x01330957, 0x3783920d, 0x28c744b9, 0xee1e}}}, + /* 5*16^8*G: */ + {{{0x29d07e9e, 0x1413e221, 0x2a60c36b, 0x279f287d, 0x3d8e5ea0, 0x2caf83ec, 0x1e13d93d, 0x255baf59, 0x9d78}}, + {{0x03d8c8ee, 0x1375856b, 0x394c7b2f, 0x1828b68e, 0x3210ce74, 0x0aa27074, 0x2a8cd654, 0x279bbd23, 0xd514}}}, + /* 7*16^8*G: */ + {{{0x3dc4950f, 0x19dd4219, 0x13942076, 0x106cab6f, 0x1b631657, 0x0da11b93, 0x13fa9572, 0x049cb84d, 0x4acb}}, + {{0x23d8b4df, 0x1b1b9111, 0x1866ac56, 0x2790a02d, 0x31e29fdf, 0x0a63db31, 0x3cdad8cf, 0x3483edd0, 0x726c}}}, + /* 9*16^8*G: */ + {{{0x2d7e8cbd, 0x1031e9ef, 0x007d816f, 0x199fe2bc, 0x01464a2a, 0x114d5432, 0x317b4234, 0x17afc69a, 0x640c}}, + {{0x3ec5a5db, 0x1b8a40f2, 0x0ff9b020, 0x01a7ec63, 0x1eab9eba, 0x271badc0, 0x0fd2f2ae, 0x223f60a7, 0xd6ae}}}, + /* 11*16^8*G: */ + {{{0x3e86bddc, 0x1c2812c1, 0x35ce3d5f, 0x349ae5e5, 0x1b6b9bf1, 0x158b2437, 0x04b32451, 0x012c6d0a, 0x8bba}}, + {{0x29e349c4, 0x088f1687, 0x0196e5f5, 0x2b3f793d, 0x19437ac6, 0x2fe4859a, 0x08ebf659, 0x26702708, 0xc340}}}, + /* 13*16^8*G: */ + {{{0x0257f582, 0x05c39e01, 0x2c3a258d, 0x26427ab7, 0x1a5fe41f, 0x1a50fdf1, 0x137e210a, 0x15d13fb3, 0x8b0a}}, + {{0x37372d4b, 0x205ffb7c, 0x31607664, 0x36d1ae9e, 0x237d4656, 0x285684df, 0x2c739662, 0x2913b035, 0x9e57}}}, + /* 15*16^8*G: */ + {{{0x185e797e, 0x3c5127e6, 0x23c31683, 0x1b8893cb, 0x1678a6f0, 0x15bd24f6, 0x078971f8, 0x3fe5f099, 0x0a13}}, + {{0x139d666f, 0x0c9eae7d, 0x180c3928, 0x1fdbc29d, 0x21dc3ff2, 0x36063a3e, 0x083d5917, 0x2592c897, 0xeb1a}}} + }, + { + /* 1*16^9*G: */ + {{{0x3dde3445, 0x2bfd3f87, 0x2aea7817, 0x2eea7768, 0x26519e76, 0x1c7f9ffc, 0x061e6853, 0x2d8e135c, 0x6965}}, + {{0x18855113, 0x3310e278, 0x25f99d97, 0x1f398146, 0x332dbef4, 0x392598e1, 0x02511325, 0x36b8e712, 0xd1bc}}}, + /* 3*16^9*G: */ + {{{0x088acfc5, 0x17903e5a, 0x2689789f, 0x3bd626cd, 0x091a71b1, 0x39f76f50, 0x1c7da027, 0x3147779d, 0xe1cb}}, + {{0x2249a225, 0x2f17fb56, 0x2bfba523, 0x34ca4afb, 0x39e23ce7, 0x09d93ff6, 0x3daedb31, 0x20e5f379, 0xec67}}}, + /* 5*16^9*G: */ + {{{0x2107ccc6, 0x163a94ff, 0x03c82287, 0x0e25f855, 0x2900481d, 0x3a74a116, 0x38aa1731, 0x099e5c44, 0x9c3f}}, + {{0x3dea9152, 0x101e5334, 0x1f9b1868, 0x2a3f53a5, 0x3e6eca51, 0x0dd7d2fc, 0x11d9c8be, 0x0306d92d, 0xdaee}}}, + /* 7*16^9*G: */ + {{{0x15a449e7, 0x0717ad0e, 0x13c2be42, 0x28a80d39, 0x00922b2f, 0x3eb05ec5, 0x32d72796, 0x3655df1a, 0x5c30}}, + {{0x2e2677d0, 0x1c3a9206, 0x3ce790e7, 0x179014f0, 0x0592d0b7, 0x2d97de67, 0x21b92164, 0x38ed6c23, 0x8025}}}, + /* 9*16^9*G: */ + {{{0x0b8ceb07, 0x2956300a, 0x3ee271cf, 0x1e494aff, 0x28d99553, 0x138ac1fa, 0x29682afe, 0x2fc8c323, 0xaa3b}}, + {{0x1fd83984, 0x26a118ba, 0x2b3f9eb9, 0x1c6caf1e, 0x1162ec3b, 0x32c3f932, 0x2c26844d, 0x032c2707, 0xe632}}}, + /* 11*16^9*G: */ + {{{0x03bfd1f1, 0x103a9556, 0x1d65732e, 0x0db70d45, 0x0001943a, 0x183f2645, 0x3418179e, 0x0c9444cc, 0xab4a}}, + {{0x08e1c233, 0x044e5843, 0x39e98cf2, 0x1f64c909, 0x2fe057a5, 0x2cef4104, 0x08668b4e, 0x192ec0db, 0xea6c}}}, + /* 13*16^9*G: */ + {{{0x0b1d6d3f, 0x2101b5e0, 0x2eebb890, 0x0dd9a293, 0x25a8105f, 0x0dfd7362, 0x15d77f73, 0x2c96777b, 0xdba9}}, + {{0x09cd8133, 0x10ba4a0a, 0x12bd93cc, 0x2f66f114, 0x2b871448, 0x2a653d3f, 0x35b7b5ac, 0x0b4fd5d4, 0xb386}}}, + /* 15*16^9*G: */ + {{{0x31fa2a6a, 0x1e680e00, 0x30e4b256, 0x3f075616, 0x23cdfe34, 0x375d0ac6, 0x0274507a, 0x3d310ba6, 0x1998}}, + {{0x06415142, 0x01fb6d2f, 0x37258b56, 0x1b008e1e, 0x38a1e94c, 0x03e0022d, 0x2fa10970, 0x105b4642, 0x2ebb}}} + }, + { + /* 1*16^10*G: */ + {{{0x0d9aefbd, 0x163f29b1, 0x3b957752, 0x3f91ec9c, 0x3c43dc1e, 0x2a7c3506, 0x29d7632c, 0x0d072319, 0x0fbc}}, + {{0x13e71ca0, 0x34edbaa7, 0x00a9ff1e, 0x02c1a788, 0x17d3d395, 0x052c7525, 0x20e3fe40, 0x0898cbcd, 0xbd80}}}, + /* 3*16^10*G: */ + {{{0x29434837, 0x1e5b7ffb, 0x220c1bb8, 0x2cc502e1, 0x0fb06dad, 0x1071bfed, 0x07aedb13, 0x062af12a, 0xd76d}}, + {{0x3b215b4c, 0x3ea813e6, 0x1b7ccc24, 0x291639dd, 0x2b933290, 0x390853de, 0x16644de0, 0x1368cbb6, 0xf6bc}}}, + /* 5*16^10*G: */ + {{{0x1c07f222, 0x0ba27c86, 0x060fe7d0, 0x388718eb, 0x1753d1c5, 0x2074687c, 0x3ff604f4, 0x31941859, 0xd5c0}}, + {{0x0c6ffd57, 0x0bbda478, 0x0813a86e, 0x3cfd469e, 0x1f75b9ba, 0x3831dfd2, 0x3b8850cd, 0x02e18205, 0x15a3}}}, + /* 7*16^10*G: */ + {{{0x0e93bfa6, 0x291c5a89, 0x1a1362a4, 0x274a5682, 0x0c9fe0d3, 0x272e99ad, 0x2f62ce54, 0x0d939291, 0x734c}}, + {{0x18d10774, 0x31be9e66, 0x10297c4f, 0x284d8822, 0x0c5f48ec, 0x26078d48, 0x39d049de, 0x0540eaa9, 0x0995}}}, + /* 9*16^10*G: */ + {{{0x1fa194ae, 0x03ad45fd, 0x2054aecf, 0x100a4766, 0x1eb14906, 0x1d7674aa, 0x26a89011, 0x367681ed, 0x79a3}}, + {{0x1fcf634b, 0x3f197a72, 0x379bc4d4, 0x35097ccb, 0x2f03d86b, 0x19c6e162, 0x0b1b34b3, 0x36f29c95, 0x84e1}}}, + /* 11*16^10*G: */ + {{{0x21e8b7fe, 0x2b241800, 0x385b26a6, 0x3438b85d, 0x3c98e05d, 0x3932ab73, 0x305828a3, 0x3f425356, 0x3393}}, + {{0x023c6821, 0x30509108, 0x29b94b70, 0x15acc2a2, 0x1a668d8e, 0x3fabb671, 0x3beb82ea, 0x0defb219, 0x1304}}}, + /* 13*16^10*G: */ + {{{0x21528cf6, 0x0255e755, 0x250694ea, 0x280942bd, 0x1b0a52e6, 0x2d161bb9, 0x227e15e1, 0x0a2184d1, 0xa16b}}, + {{0x3ce93f3b, 0x02e483e7, 0x3cc80138, 0x24fef204, 0x1150f434, 0x33b5e760, 0x3ad99913, 0x262ba14d, 0xf405}}}, + /* 15*16^10*G: */ + {{{0x0c8db2e0, 0x144299ae, 0x30d73583, 0x0f2f7057, 0x1a74f647, 0x3226aea5, 0x3474cbf6, 0x33880638, 0xd317}}, + {{0x274bc9a9, 0x16cd28ac, 0x2b860f3a, 0x289d3408, 0x179136ca, 0x0b0fa38e, 0x3844b99c, 0x0842a424, 0xd61a}}} + }, + { + /* 1*16^11*G: */ + {{{0x23fe67b2, 0x1b8c65ea, 0x22e3338c, 0x2a2ff9c2, 0x3323b234, 0x19ae6ea5, 0x085dcbc6, 0x3090ddcf, 0x6608}}, + {{0x25b47a28, 0x248ff973, 0x0c543081, 0x0ac567d0, 0x06e03fc2, 0x3d90369d, 0x1c168846, 0x05afb148, 0xa1a9}}}, + /* 3*16^11*G: */ + {{{0x2bc73e02, 0x0f9baab4, 0x365312c1, 0x259853ba, 0x17863184, 0x2a6045f5, 0x1dc23206, 0x1ab8a9b1, 0xf095}}, + {{0x0611219d, 0x34b3da66, 0x3ae94572, 0x0b41236e, 0x03935667, 0x08162bca, 0x0e03c76e, 0x39980451, 0x433f}}}, + /* 5*16^11*G: */ + {{{0x1c5fe45c, 0x3788b794, 0x07c0f597, 0x2ca06a0e, 0x37283488, 0x3c9275f3, 0x2a60ca52, 0x3afa8f28, 0xdb98}}, + {{0x3ef45a22, 0x129c0710, 0x2480e1c4, 0x20c813ea, 0x112c8ce9, 0x144a7762, 0x185a2de1, 0x3cc2dd6f, 0xe0c0}}}, + /* 7*16^11*G: */ + {{{0x22128eac, 0x3d679837, 0x0af1ccba, 0x11d63573, 0x2a51690c, 0x29acedf5, 0x1a5f421b, 0x300582b7, 0x0a73}}, + {{0x24f1180d, 0x2164a475, 0x355d9ca3, 0x0dd67c5d, 0x350a7c79, 0x32db7653, 0x2838ca55, 0x36958113, 0x443f}}}, + /* 9*16^11*G: */ + {{{0x23ccbc30, 0x196a4cc5, 0x1349618c, 0x37f97487, 0x0997249e, 0x34dd99e8, 0x34f2370e, 0x0830d1f2, 0x3787}}, + {{0x1315729e, 0x2880c9fc, 0x1348f846, 0x2f3e5574, 0x279b6d16, 0x062b02aa, 0x2538c931, 0x376e73dc, 0x8f1b}}}, + /* 11*16^11*G: */ + {{{0x03bb1b6b, 0x192a3795, 0x07c2bfaa, 0x17fbccbd, 0x15a62157, 0x20463041, 0x31a619d9, 0x34876de2, 0xfe8f}}, + {{0x30eaaf93, 0x1ed766e8, 0x0abf8899, 0x053773fc, 0x2d13c00f, 0x0a3a57d6, 0x16e3769e, 0x08abb0c9, 0x791e}}}, + /* 13*16^11*G: */ + {{{0x344b7cea, 0x20156672, 0x16cf87de, 0x111a5024, 0x33dcca47, 0x010089e2, 0x37e2ee82, 0x07f55e7e, 0x2c33}}, + {{0x15d1c9c2, 0x3f0ad1ab, 0x13094077, 0x249447fc, 0x3dd65061, 0x0fcf630e, 0x21e76fcf, 0x1ec73381, 0x2056}}}, + /* 15*16^11*G: */ + {{{0x0112278c, 0x3e4a6cde, 0x28d9a158, 0x00592742, 0x044b66dd, 0x22d321fe, 0x1a320a34, 0x301b1194, 0x509b}}, + {{0x0e178f66, 0x321d7262, 0x335f945e, 0x197fa1b9, 0x0f64570f, 0x03d3c5ee, 0x246ec176, 0x1a30adc8, 0xb4b1}}} + }, + { + /* 1*16^12*G: */ + {{{0x17e55104, 0x0baebe00, 0x38e9c71c, 0x0ea0d7ee, 0x0b561cf7, 0x3a4f0d36, 0x3873763d, 0x1d9489ed, 0xd8de}}, + {{0x252e08cd, 0x280bbe03, 0x140db1b2, 0x3dcff386, 0x1cf924c2, 0x318a2b47, 0x3f2d15c4, 0x25196f84, 0x2fd2}}}, + /* 3*16^12*G: */ + {{{0x2987bfd3, 0x24e70b1f, 0x0c4284c6, 0x3151cbfd, 0x1dd19187, 0x37efabeb, 0x18e33551, 0x1e1bef54, 0xe3a5}}, + {{0x0cc23e7d, 0x3b4c6db2, 0x128e0817, 0x373cbb36, 0x18210ca3, 0x1ee7fd2b, 0x040e6847, 0x2b4254d6, 0xf74b}}}, + /* 5*16^12*G: */ + {{{0x22d5056e, 0x19e54748, 0x247a07cb, 0x372d69f8, 0x2e5e480e, 0x097ff3a5, 0x120d4115, 0x1c107b29, 0x42a9}}, + {{0x30f7db11, 0x21053722, 0x29fd1fd4, 0x13920f5b, 0x163b26b6, 0x0db749ad, 0x087066ec, 0x1fd9b3c0, 0xf2fc}}}, + /* 7*16^12*G: */ + {{{0x13dafd3b, 0x19d17e47, 0x1cb3956c, 0x2e267c0b, 0x1379d66f, 0x0cb0bb59, 0x3964cfe2, 0x29c6c709, 0x0d6c}}, + {{0x1a6fe6e8, 0x1ab7c508, 0x288771ad, 0x08922afb, 0x07de58a0, 0x1252809c, 0x2293d9fe, 0x0c2ce3f7, 0xa851}}}, + /* 9*16^12*G: */ + {{{0x31131f8b, 0x1afe71ff, 0x3a20d4df, 0x191a5833, 0x031fb469, 0x308b7e71, 0x1a3d97d4, 0x329eb619, 0x05ed}}, + {{0x3a6f779f, 0x3b3c2c66, 0x0e89d490, 0x1494017c, 0x0271be33, 0x275c6d7c, 0x086bc01c, 0x2207923a, 0x9e58}}}, + /* 11*16^12*G: */ + {{{0x2b597e4d, 0x323e7d07, 0x37d1a319, 0x1d3cc979, 0x371c1149, 0x2d168ced, 0x3a0a4121, 0x301582f1, 0x5a13}}, + {{0x241856e0, 0x3df921a7, 0x1136664a, 0x37a1ead6, 0x2d73ce7b, 0x346283c8, 0x397ff51f, 0x0f04e243, 0xc9e7}}}, + /* 13*16^12*G: */ + {{{0x0260faf0, 0x2a9e2585, 0x3e95935d, 0x2ef4d165, 0x0f272ea2, 0x113869a0, 0x36e75431, 0x1595805e, 0x96b2}}, + {{0x2366d412, 0x03909483, 0x07d4f5ac, 0x02efe61c, 0x3f99e189, 0x36395cce, 0x37cac00a, 0x29a8006c, 0xdcf8}}}, + /* 15*16^12*G: */ + {{{0x2ad13276, 0x12686f92, 0x1c043c7a, 0x18d43aba, 0x3771a3ca, 0x04acace1, 0x0de2426f, 0x06443107, 0x0b97}}, + {{0x0a84dadb, 0x0ce3cd08, 0x270fae3b, 0x0f5e4a60, 0x36811f59, 0x0b916cef, 0x2eefbd4e, 0x121bbc01, 0xac28}}} + }, + { + /* 1*16^13*G: */ + {{{0x071e5c83, 0x3a9af248, 0x142a0bee, 0x349fc661, 0x18e5b18b, 0x2116dca9, 0x2d73f20a, 0x32505409, 0x54cc}}, + {{0x140916a1, 0x3f423bdc, 0x18ee496c, 0x2782f317, 0x12bf2292, 0x3e1c576b, 0x145323a8, 0x0fd16d14, 0x1c43}}}, + /* 3*16^13*G: */ + {{{0x2f76167c, 0x3178d88a, 0x07467394, 0x0bd08b31, 0x0cd9f22f, 0x08b1a4b7, 0x2ff9539c, 0x0bb72dcf, 0x8758}}, + {{0x2f4d7ff6, 0x31beed85, 0x3197be86, 0x00a3c19d, 0x3236a888, 0x040b0f0d, 0x24a7bfde, 0x250d42b5, 0x075b}}}, + /* 5*16^13*G: */ + {{{0x34de6611, 0x19c8fba1, 0x3821fb04, 0x3d95ce52, 0x26f11e33, 0x16dcd8d5, 0x336db1c2, 0x1eb287c9, 0x4a10}}, + {{0x18a805fe, 0x0d63afb9, 0x02132ac0, 0x17551e97, 0x00052e07, 0x3993a3dc, 0x3ef3934c, 0x09944018, 0x809b}}}, + /* 7*16^13*G: */ + {{{0x2dcfecb0, 0x32e93b41, 0x0a8d846f, 0x20ff474c, 0x3f49f6e9, 0x28383526, 0x2dfc9654, 0x0bacdcaa, 0xfd40}}, + {{0x2da08de8, 0x0164fcf7, 0x1e65e791, 0x12d3092f, 0x2ba86b1a, 0x1898e26e, 0x23a22e9a, 0x100c3769, 0xd6b3}}}, + /* 9*16^13*G: */ + {{{0x154659ed, 0x2d37583d, 0x15d966e5, 0x2b8f4886, 0x09d0a07f, 0x2e381ffb, 0x075155df, 0x2cd19186, 0x467b}}, + {{0x2800cf83, 0x2c81f42c, 0x1013e009, 0x06f04373, 0x382cd370, 0x0b3561b6, 0x178e8a1f, 0x3ff416aa, 0xd01e}}}, + /* 11*16^13*G: */ + {{{0x1c97e515, 0x3992612b, 0x1885a5fe, 0x0535b0ce, 0x1ec7e569, 0x1e6d8c3a, 0x1c0e46c8, 0x2e63e337, 0xcf66}}, + {{0x006c8a51, 0x160853aa, 0x190033a9, 0x3c1d1636, 0x2c6a7b33, 0x16d040d3, 0x061211c2, 0x1c5ee411, 0x0a70}}}, + /* 13*16^13*G: */ + {{{0x186154e5, 0x2e94a840, 0x2afa0dd3, 0x100a99a6, 0x08677086, 0x32254eb5, 0x3aa34751, 0x14b183ef, 0x3d92}}, + {{0x1603a8a2, 0x1ff24fda, 0x07dd7077, 0x287edf5f, 0x2b4cf3ae, 0x24cd0a25, 0x29d7fc44, 0x007734be, 0x3d0d}}}, + /* 15*16^13*G: */ + {{{0x2a4a8daa, 0x0ed8ed8a, 0x28a5ca3d, 0x041803bc, 0x0a968ce5, 0x3ad6d23d, 0x1769c760, 0x0e2c9a22, 0x2bbe}}, + {{0x1236e49b, 0x3821dd3a, 0x3eb6e7d7, 0x00ace938, 0x16085099, 0x33fbe47e, 0x3b36f5e2, 0x01fd8034, 0xf857}}} + }, + { + /* 1*16^14*G: */ + {{{0x22d32936, 0x0c3eddc4, 0x2847f01c, 0x03340b8c, 0x3d7f38e4, 0x331f4544, 0x0a47d9f6, 0x03165e05, 0xc544}}, + {{0x07cabfd4, 0x290be8dd, 0x1e41e5d9, 0x29b4a18c, 0x2cf4acd8, 0x3078748f, 0x21fa72ed, 0x3a6e8e0f, 0xd27e}}}, + /* 3*16^14*G: */ + {{{0x3989a8e1, 0x361407b1, 0x0ee4bdd7, 0x0765bcdd, 0x1cfe0a7c, 0x03811e6e, 0x3a79b750, 0x00f11737, 0x3e4d}}, + {{0x041c240a, 0x21e44e21, 0x3bd67409, 0x2bc6357c, 0x0aa719ff, 0x045f2b5f, 0x26475aac, 0x11342056, 0x12f7}}}, + /* 5*16^14*G: */ + {{{0x19bb7902, 0x24e6a343, 0x2b7c73f6, 0x309b1ca1, 0x085e9fd8, 0x28927a51, 0x210359a9, 0x21126cf5, 0x01b6}}, + {{0x203ee653, 0x35fd12c7, 0x1836682c, 0x3ac9811c, 0x2d1581fc, 0x0663970d, 0x39c3e0bf, 0x18e87a4d, 0xe590}}}, + /* 7*16^14*G: */ + {{{0x0371d9fe, 0x0a6d5b53, 0x199d6bbc, 0x12cd5b06, 0x2b3a4cf0, 0x25569f0e, 0x09ca2335, 0x0f2c6b33, 0x952c}}, + {{0x0189a13f, 0x1db39b49, 0x008c75ed, 0x11193c46, 0x2ce5d066, 0x3e44dbdb, 0x22f06a7d, 0x2151bdf5, 0x59b9}}}, + /* 9*16^14*G: */ + {{{0x0bc2c885, 0x11fff1da, 0x264e57c8, 0x147b9dd4, 0x17cde515, 0x2601142e, 0x26eac858, 0x13b856c5, 0xdfcb}}, + {{0x1345d92e, 0x1752990c, 0x3abe9757, 0x1dce251e, 0x2c0f411c, 0x13f09b20, 0x213a153c, 0x08e55541, 0x536a}}}, + /* 11*16^14*G: */ + {{{0x3510208e, 0x0e2e14af, 0x0d794387, 0x23338b61, 0x3c97bbdb, 0x1ebce811, 0x2500c8a8, 0x19b026f9, 0x1579}}, + {{0x0d207357, 0x183bb894, 0x2da43dfd, 0x23f1910c, 0x0cbe0700, 0x3fdedeee, 0x2264eabd, 0x1b56adc4, 0x4044}}}, + /* 13*16^14*G: */ + {{{0x0b96fe13, 0x327f32fa, 0x0852ea81, 0x2492b4ed, 0x3f6e23e4, 0x06a3fe04, 0x2990ad6e, 0x078f12c7, 0xc6b2}}, + {{0x37bb1417, 0x001ae5ab, 0x1e6d2d6a, 0x1954245e, 0x2b28a2ff, 0x2de078d3, 0x34d48e54, 0x337630cc, 0x335b}}}, + /* 15*16^14*G: */ + {{{0x03936565, 0x0d96066b, 0x37fa4c7c, 0x29ecdb65, 0x1522d997, 0x2f2a754e, 0x3296f0b4, 0x39311e31, 0xa231}}, + {{0x35ec5f19, 0x2b95a818, 0x2f154268, 0x295b8025, 0x03cf942b, 0x253b1a20, 0x3be91c0d, 0x3262fb1f, 0x80e0}}} + }, + { + /* 1*16^15*G: */ + {{{0x3066fd48, 0x3e7d05ca, 0x0971583b, 0x0dc4072e, 0x3adca61c, 0x1e6e5e9a, 0x3f1c506c, 0x159e9089, 0x241c}}, + {{0x12857b08, 0x3df4b19e, 0x2a366057, 0x2a1c4e2b, 0x3203a48e, 0x0e05f010, 0x02d4b936, 0x0b64f50c, 0x40a6}}}, + /* 3*16^15*G: */ + {{{0x0df9591d, 0x187df6e4, 0x2b4c82a8, 0x3b0eb090, 0x327218dc, 0x034f12ac, 0x178e9cba, 0x348ee09a, 0xde2f}}, + {{0x0457ad84, 0x13865cf4, 0x0c036a4b, 0x26a287e2, 0x392ebbda, 0x32dfb212, 0x243f305e, 0x1c44ced8, 0x400d}}}, + /* 5*16^15*G: */ + {{{0x3562282c, 0x3aa0952b, 0x0fbc3772, 0x0bcebe4e, 0x211340f0, 0x2522c093, 0x0cbdd993, 0x226c0c13, 0x8df8}}, + {{0x21d195cd, 0x095aaf65, 0x2f9bb157, 0x1fdc1133, 0x0af35e24, 0x10798c62, 0x1ceed6c7, 0x16d9cc81, 0x7452}}}, + /* 7*16^15*G: */ + {{{0x0dddb2dd, 0x2754a254, 0x02c0da6f, 0x22193373, 0x12f24507, 0x3ee033c5, 0x380f8001, 0x1d633662, 0xa0fd}}, + {{0x33ede6b2, 0x3f653fe1, 0x1409a7c7, 0x233a5be2, 0x308f311c, 0x247f4c4e, 0x368d5f86, 0x360d704c, 0x53e5}}}, + /* 9*16^15*G: */ + {{{0x0f542e36, 0x0232ea81, 0x13415c2e, 0x08bfebe8, 0x2335d84e, 0x16499e51, 0x1a0f67de, 0x31611cb4, 0x3170}}, + {{0x363288b5, 0x1b11d6bb, 0x199be1bc, 0x1bdd5a56, 0x39773d00, 0x05424ffa, 0x27fe2375, 0x0d84bf0e, 0xb208}}}, + /* 11*16^15*G: */ + {{{0x1c7548e9, 0x266c8e97, 0x092d54c7, 0x376a01c2, 0x063fe5d8, 0x1205a53c, 0x13e029db, 0x2c2a428b, 0x92fa}}, + {{0x0917758f, 0x31c4b341, 0x32d08488, 0x28371a3b, 0x2679ffc8, 0x05c53830, 0x246bcf43, 0x2d1a032c, 0x55e7}}}, + /* 13*16^15*G: */ + {{{0x1498f7f8, 0x0360142e, 0x2411622e, 0x37d9f4c9, 0x2c8712c4, 0x2f846c64, 0x355179d0, 0x196f8600, 0x91b0}}, + {{0x3f23195b, 0x31d03678, 0x389639e3, 0x0b1ed095, 0x17e264df, 0x3fcd2400, 0x31620ff9, 0x1bddfed9, 0x035b}}}, + /* 15*16^15*G: */ + {{{0x0060e322, 0x0772fb89, 0x1c4d14b5, 0x3371cdea, 0x1ab9923e, 0x241a5d22, 0x1cb3a9c3, 0x07d332b2, 0x8e4a}}, + {{0x104619d7, 0x38860f36, 0x14fbfe04, 0x002a6365, 0x2e7bc4fb, 0x017b4901, 0x0d7752fb, 0x2dd7acca, 0x4936}}} + }, + { + /* 1*16^16*G: */ + {{{0x0e14db63, 0x039d72d2, 0x1651f7e9, 0x124eeaab, 0x2e25de29, 0x0964b8c9, 0x1aaa5849, 0x08af0a04, 0x0fa8}}, + {{0x1f462ee7, 0x10449151, 0x0fe82f5e, 0x2c699414, 0x1f188b34, 0x2b52f2cf, 0x3a80d6f4, 0x12ba3d76, 0xbff4}}}, + /* 3*16^16*G: */ + {{{0x3db3cdec, 0x14b114fd, 0x228ebf57, 0x3bce84ac, 0x2a4bc8db, 0x199179ef, 0x12f5ce59, 0x30193fe4, 0x85b2}}, + {{0x0a03f81f, 0x3d342081, 0x24cf8e08, 0x2602cd39, 0x0c6d00dc, 0x1fe8b4bf, 0x1153663c, 0x09e3ce74, 0xf64b}}}, + /* 5*16^16*G: */ + {{{0x0607b030, 0x22296b92, 0x184d6732, 0x36bfd8f9, 0x16f29c24, 0x07eeb3b0, 0x21467785, 0x00ddb100, 0x110b}}, + {{0x33617c3a, 0x10ea844a, 0x3298749f, 0x2f8555be, 0x21c70c87, 0x3ae27e11, 0x2e6734c6, 0x0ae14c63, 0x8443}}}, + /* 7*16^16*G: */ + {{{0x35a76f08, 0x13b76071, 0x3bbed4e5, 0x257c94e2, 0x1caaf832, 0x1b8490ac, 0x071d714f, 0x139127d9, 0x1878}}, + {{0x2b824993, 0x2ce58175, 0x20a25320, 0x275d29e9, 0x31e671fc, 0x1ea3f6b1, 0x21ae7177, 0x3b5fd287, 0x8d76}}}, + /* 9*16^16*G: */ + {{{0x3a6fad81, 0x3a38cf27, 0x00cb03ec, 0x0cd95d23, 0x3a037d9c, 0x15b75dc0, 0x1e6b9aef, 0x3e781f41, 0x58a2}}, + {{0x3b109594, 0x10018578, 0x1300b825, 0x22ecb4cb, 0x3fa6bd79, 0x1a0be1c5, 0x160e0c1b, 0x19316b15, 0x06ab}}}, + /* 11*16^16*G: */ + {{{0x1eb52583, 0x2c8bc47e, 0x10cc13af, 0x22a673b0, 0x0f676fea, 0x39b6ec9e, 0x2bba240e, 0x0837339f, 0x1ef0}}, + {{0x3a3f17ae, 0x16c9e065, 0x012d4cb5, 0x30c03e5c, 0x1695306a, 0x3db03d2e, 0x214b0097, 0x1dac969e, 0x5944}}}, + /* 13*16^16*G: */ + {{{0x30a1958f, 0x1708fb07, 0x3b56643b, 0x0e6d491b, 0x3fa32c4f, 0x345133ea, 0x2a21395d, 0x2058f075, 0x4e4a}}, + {{0x08636f8a, 0x10ecfd45, 0x2c43d66a, 0x010217ec, 0x1c6fa840, 0x3d28fb8a, 0x0c8d1033, 0x2916de7a, 0x2574}}}, + /* 15*16^16*G: */ + {{{0x24935db5, 0x209d6a11, 0x06bdb0ee, 0x05e60987, 0x14519e28, 0x09f83b56, 0x21104e33, 0x1a85ab75, 0xf696}}, + {{0x1d166838, 0x28d20db0, 0x001bf013, 0x1d14e8d1, 0x3c755e2d, 0x17b95cb0, 0x31db2c1a, 0x38c1ea40, 0xba0d}}} + }, + { + /* 1*16^17*G: */ + {{{0x376a6987, 0x23d04c16, 0x3da43ff6, 0x1206ad10, 0x2e1b3f2b, 0x31a6235f, 0x099547dd, 0x0635ea66, 0x54bc}}, + {{0x1b9aae49, 0x3915f341, 0x373b119f, 0x3ae3b52e, 0x33e2fd52, 0x06e146e9, 0x2eaf3739, 0x23048479, 0x4b2c}}}, + /* 3*16^17*G: */ + {{{0x3d1fd820, 0x22fd1fd7, 0x07675003, 0x21e15192, 0x31271b78, 0x0d40898a, 0x1c52aa86, 0x2f3da030, 0xbafb}}, + {{0x1bf074f0, 0x2bb6b548, 0x31fcad6e, 0x070d2848, 0x1bc0fde8, 0x1efd6b22, 0x0dd812ce, 0x265f276d, 0x1487}}}, + /* 5*16^17*G: */ + {{{0x14299b7e, 0x245c204a, 0x186e0d0e, 0x39e7cb42, 0x0220ec24, 0x30eff1d7, 0x389fe2a3, 0x0e3dc40c, 0x9b19}}, + {{0x047b84de, 0x15eca15d, 0x06b8232c, 0x337a147e, 0x2a3ec90a, 0x03a63872, 0x10283314, 0x2a9bbc5c, 0xfb12}}}, + /* 7*16^17*G: */ + {{{0x110cc4c4, 0x35041d03, 0x0a53da0f, 0x074d68b1, 0x361b2cb7, 0x207f7019, 0x175907c3, 0x06617300, 0xa677}}, + {{0x3c976570, 0x083cec8d, 0x2ff3094c, 0x1d15dce9, 0x1d9c3dbc, 0x2f598079, 0x0dd98f29, 0x18617dd4, 0x8550}}}, + /* 9*16^17*G: */ + {{{0x14242a28, 0x104200b5, 0x13ca7715, 0x16f2c849, 0x374eca45, 0x22bde12d, 0x2afc109e, 0x3b54dac3, 0x88b7}}, + {{0x394ed8ce, 0x2e5a07b1, 0x383e347f, 0x0d9a8723, 0x07bd934e, 0x2fe774d6, 0x1345e47f, 0x14c81891, 0x22b0}}}, + /* 11*16^17*G: */ + {{{0x1bc1a94c, 0x058513b2, 0x271daf80, 0x19c74acf, 0x1e875751, 0x35cac089, 0x2b3d2052, 0x05004aa1, 0x0371}}, + {{0x2fc2073c, 0x30302db3, 0x2c424838, 0x14630d8a, 0x105335c8, 0x3086952b, 0x17390ef8, 0x1a4f5477, 0x4d1d}}}, + /* 13*16^17*G: */ + {{{0x077f88ba, 0x3ef47826, 0x29bed36e, 0x2601de7b, 0x2a2cc350, 0x168cba13, 0x0293e34b, 0x08532261, 0xcc98}}, + {{0x07885278, 0x2918bbf2, 0x3354c4e0, 0x3d839fbb, 0x3d63abef, 0x3129919d, 0x1afa9114, 0x2d3a3949, 0x04eb}}}, + /* 15*16^17*G: */ + {{{0x3d70187c, 0x15cc6537, 0x3640c7f1, 0x06b218a6, 0x0f5bf875, 0x139780a4, 0x2a10f981, 0x2b80a690, 0x0ad3}}, + {{0x3fc775a7, 0x37ff3d2c, 0x262a0f67, 0x0d3ec205, 0x2bb33dd0, 0x3157c17e, 0x046e3785, 0x10351d62, 0x2af0}}} + }, + { + /* 1*16^18*G: */ + {{{0x30aae231, 0x02abeb45, 0x1f96b7c6, 0x252e149e, 0x27756f51, 0x09208e49, 0x1e3f285f, 0x325a65d8, 0x1d35}}, + {{0x0cd6ac71, 0x219c18eb, 0x29a66f15, 0x3d62a91c, 0x2bf810ed, 0x182ad88b, 0x208231d6, 0x1b2d8b7d, 0xc722}}}, + /* 3*16^18*G: */ + {{{0x0cfa3fac, 0x3834ff86, 0x32b8193c, 0x2b61a7f0, 0x0d803023, 0x3aed1758, 0x2234ce2c, 0x1011e9b4, 0xdf3d}}, + {{0x0fc7d419, 0x1189b64e, 0x2882975f, 0x358f3925, 0x0f9dbfaf, 0x2887ca70, 0x140db24a, 0x1bd48a7f, 0x48fa}}}, + /* 5*16^18*G: */ + {{{0x1f1322d4, 0x3b6496b8, 0x2ccdcbba, 0x029a5012, 0x11f822cb, 0x39b1328c, 0x16144ea1, 0x2bdaac7e, 0xdbb2}}, + {{0x0a8c5311, 0x2924ad3d, 0x37e3a5fa, 0x27f25e1e, 0x033f9d9a, 0x18347b59, 0x3561aa1b, 0x1d6e4bc4, 0xebae}}}, + /* 7*16^18*G: */ + {{{0x21138f7b, 0x01a68cf2, 0x1f2e8f2f, 0x30724f8b, 0x1b5f0bc4, 0x2a2899fe, 0x21fd4caf, 0x1ed65fc9, 0x1dba}}, + {{0x239bf268, 0x320b631e, 0x18232c0d, 0x0db9ade6, 0x0007f581, 0x06401aee, 0x3efc63ae, 0x1f4f9779, 0x6aaf}}}, + /* 9*16^18*G: */ + {{{0x179a70af, 0x36a1ddc0, 0x364df288, 0x2750a6a6, 0x1305c6ec, 0x2fa0b57d, 0x2919d31b, 0x0b910989, 0x348a}}, + {{0x07b66e82, 0x2a121852, 0x3e13e5ac, 0x29f0b16d, 0x230105b2, 0x11ef3800, 0x23e808c7, 0x3e9e7d56, 0xa1b9}}}, + /* 11*16^18*G: */ + {{{0x04d3a201, 0x1d1db5db, 0x19b9eefc, 0x3a49a93f, 0x1adf5f36, 0x293efe4c, 0x09e1ca86, 0x32146667, 0x3a4e}}, + {{0x28635f89, 0x36165bdd, 0x33cd55bd, 0x34c796bd, 0x374a8b27, 0x00f04691, 0x262de69e, 0x0bbe0bd8, 0xc99a}}}, + /* 13*16^18*G: */ + {{{0x1c978567, 0x3beb9cbf, 0x0dc1f981, 0x1769a210, 0x31f60be1, 0x24d758bf, 0x0d45784e, 0x14b620cd, 0xb1ba}}, + {{0x362dc291, 0x1fe920a8, 0x2fcd40a7, 0x291b2c2e, 0x1bb78fd9, 0x3df3dc4f, 0x143a77c5, 0x2bb1ea1a, 0xa46b}}}, + /* 15*16^18*G: */ + {{{0x12350da1, 0x08a3ba94, 0x175f043d, 0x10531df0, 0x212c2f19, 0x22dee5a5, 0x2aafd271, 0x3acf63bc, 0x0ae6}}, + {{0x30a14bc3, 0x1cf827cd, 0x143da4bc, 0x351a3c3b, 0x0189b566, 0x00d3dff1, 0x06cae2dd, 0x3ba7ed80, 0x99cd}}} + }, + { + /* 1*16^19*G: */ + {{{0x350e4f5f, 0x15cabaa1, 0x167e0e65, 0x3d72a6a9, 0x02f29acb, 0x3fc3dea8, 0x35aef388, 0x2a566112, 0x55d9}}, + {{0x3ca97db0, 0x2163adda, 0x3ad1b15c, 0x2604318c, 0x08ec524c, 0x355d3ef3, 0x2d203766, 0x1fe6a976, 0x69cb}}}, + /* 3*16^19*G: */ + {{{0x3eb142e9, 0x01aa621f, 0x207fcfbc, 0x1dbac191, 0x2ed480c1, 0x361a0e3e, 0x33e11794, 0x10faf91b, 0x4b00}}, + {{0x22c68552, 0x12cb14b5, 0x21258880, 0x08ca43ce, 0x222d870f, 0x1e2118d8, 0x1ac1adb1, 0x33c8e8c3, 0x173c}}}, + /* 5*16^19*G: */ + {{{0x17f1aa96, 0x1b752b9c, 0x0ff6481f, 0x35e97dcd, 0x3463c513, 0x0a372edc, 0x16fc2327, 0x349e64ab, 0x79ea}}, + {{0x0b0a3fb7, 0x02e9c739, 0x1b3955a8, 0x2135c444, 0x256542de, 0x390e4d58, 0x2dabf1a6, 0x3a73feea, 0xa95d}}}, + /* 7*16^19*G: */ + {{{0x393a9ae6, 0x201729cb, 0x077f8adc, 0x382a8167, 0x2d743f8e, 0x1e78d8c6, 0x1a1ceb52, 0x00143c93, 0x318e}}, + {{0x1c447d79, 0x212d5a53, 0x2d3a8ee1, 0x14dbf6eb, 0x104bd094, 0x05f29479, 0x29299f4d, 0x3b844673, 0x2792}}}, + /* 9*16^19*G: */ + {{{0x1d30585a, 0x0de516d3, 0x35014951, 0x3fe286a8, 0x00a4b495, 0x00cbd243, 0x1e43bb88, 0x151c74bc, 0x6bbc}}, + {{0x348b05f3, 0x2be5fbbc, 0x2f9ead96, 0x3c10a040, 0x2226be09, 0x3b8ac57c, 0x129f04a9, 0x0626c305, 0x467b}}}, + /* 11*16^19*G: */ + {{{0x00136275, 0x1893e023, 0x38775352, 0x11f0005c, 0x360d78a6, 0x146a43dd, 0x1fd1189b, 0x12318430, 0x9401}}, + {{0x1997aa47, 0x358e8445, 0x04e1a425, 0x12ceb958, 0x05d6695d, 0x09312ad4, 0x3a4f77aa, 0x3e57c4d9, 0x6967}}}, + /* 13*16^19*G: */ + {{{0x1f0fe850, 0x0e84f74e, 0x111a7bdc, 0x1348c2f9, 0x25f98e86, 0x15b24a36, 0x1b49c91b, 0x0ce4980e, 0xc418}}, + {{0x3d38666d, 0x0d63d11a, 0x01a0af01, 0x169fb278, 0x2fd55806, 0x0257509a, 0x00f7aeb8, 0x3fb27235, 0x3537}}}, + /* 15*16^19*G: */ + {{{0x34937fbe, 0x3f9104dd, 0x051ba6ec, 0x2c13777c, 0x16f546c0, 0x050006be, 0x27d70e0c, 0x28fd89f1, 0x2bab}}, + {{0x173a1df4, 0x0e43955d, 0x0ac81109, 0x0b712c64, 0x0eabc9ec, 0x0ec33649, 0x08b88d78, 0x31d96c88, 0x77e5}}} + }, + { + /* 1*16^20*G: */ + {{{0x0351964c, 0x134f4b79, 0x35412c1d, 0x1a490ddb, 0x355c0834, 0x2af28615, 0x0c47fae5, 0x3e566f8a, 0x6e29}}, + {{0x163fd88f, 0x062092f5, 0x20bfb631, 0x1903149e, 0x04246def, 0x0bb1b306, 0x332f6505, 0x1767d403, 0x3456}}}, + /* 3*16^20*G: */ + {{{0x0c0e49cc, 0x3e54040e, 0x3c5400d3, 0x08cb6a16, 0x3740ed41, 0x0a237b2e, 0x30f6edd8, 0x352a5e25, 0xd691}}, + {{0x100f4152, 0x342ed307, 0x2d043f2d, 0x16f8740a, 0x3e0c52ac, 0x2ef6d5d8, 0x0f397f7f, 0x39e1d2de, 0x7a79}}}, + /* 5*16^20*G: */ + {{{0x2b9b930a, 0x361dae7c, 0x130f58f3, 0x2c4d4a91, 0x3bbc49de, 0x16df7de9, 0x0d7c5dee, 0x1a11a8b8, 0x2a5d}}, + {{0x3b2caeca, 0x1bfcd17c, 0x22716858, 0x16dcd0d7, 0x04ab58ea, 0x33c0e40f, 0x2476de5c, 0x1f025a1d, 0xdc3d}}}, + /* 7*16^20*G: */ + {{{0x016959ef, 0x29f72f4a, 0x01db59af, 0x1e74159d, 0x275df876, 0x10c504b8, 0x3b5262f0, 0x125a8e26, 0x8764}}, + {{0x20cd5010, 0x180c472f, 0x2f9e3f16, 0x15ab505c, 0x2d961f28, 0x2d049e5b, 0x02ffd9e0, 0x1a758740, 0x599b}}}, + /* 9*16^20*G: */ + {{{0x3aef0f84, 0x0e502738, 0x31c75b96, 0x2ed41aa1, 0x2db8cab0, 0x38feb05e, 0x071b133d, 0x24ef2049, 0x94d3}}, + {{0x378ba7c1, 0x16b986e4, 0x0acf12a8, 0x0fd00994, 0x239a07dd, 0x32f0e1ac, 0x363f21e1, 0x1aad3ad2, 0x5a82}}}, + /* 11*16^20*G: */ + {{{0x2ffed1b7, 0x35155e13, 0x24aa3b4e, 0x36f44995, 0x34bd2ee2, 0x1425c0b4, 0x24e2dd17, 0x2d682227, 0x4a72}}, + {{0x1601dc5f, 0x17ca7f62, 0x34d9845b, 0x3992e3b1, 0x08ea9685, 0x0cff011f, 0x120e2c8c, 0x39ba9287, 0x3531}}}, + /* 13*16^20*G: */ + {{{0x10467317, 0x0810fc97, 0x0d9186a0, 0x10771076, 0x1e790091, 0x199bcbeb, 0x31e15a78, 0x073f168d, 0xd7f0}}, + {{0x0f7d014e, 0x32e55f57, 0x17fbd895, 0x2805d0da, 0x15ef5728, 0x0d8501b0, 0x26c26ec7, 0x2ef661dc, 0x888d}}}, + /* 15*16^20*G: */ + {{{0x3dea02c1, 0x2f5d6429, 0x374087c3, 0x3eee6df1, 0x231206e4, 0x02fe7647, 0x0371bbe8, 0x282e7ddf, 0x7e50}}, + {{0x2d45c201, 0x0f251b7f, 0x18e1b283, 0x08e4d3c5, 0x0b951774, 0x31bc776e, 0x3e29c616, 0x174f1383, 0xc340}}} + }, + { + /* 1*16^21*G: */ + {{{0x0cb71280, 0x229f5044, 0x04563112, 0x1070966a, 0x2f458ec1, 0x3cbbc1e5, 0x3eed9c00, 0x1aa7acaf, 0xff04}}, + {{0x1ec33919, 0x3b0c9c7d, 0x128487a7, 0x0adb9baf, 0x0cfcc901, 0x07b76f75, 0x13a170a0, 0x156b3025, 0x432f}}}, + /* 3*16^21*G: */ + {{{0x33ca3ce3, 0x3c9e0aa8, 0x36a77e25, 0x0ac6196a, 0x12231fef, 0x16f07d4c, 0x3dcd31a9, 0x31174534, 0xf717}}, + {{0x10ed88e9, 0x2253336d, 0x0176df06, 0x14f8af77, 0x2dee55af, 0x2d53b42a, 0x1512dca9, 0x101da326, 0x422c}}}, + /* 5*16^21*G: */ + {{{0x1b28cd88, 0x0da10c35, 0x2a9bd9ac, 0x23825d40, 0x11b32c73, 0x3ad589fe, 0x30b20c2f, 0x1a6d3ccd, 0x60e2}}, + {{0x2be2066c, 0x0a6ea290, 0x2c846b0e, 0x11584e31, 0x28df7602, 0x0846225c, 0x1f0a9609, 0x05d6995e, 0xfe00}}}, + /* 7*16^21*G: */ + {{{0x061cc594, 0x14ec64ca, 0x0d0536b1, 0x12f745c1, 0x34685596, 0x16e817f2, 0x399490aa, 0x25e8799c, 0x7992}}, + {{0x0f8d309e, 0x3a444248, 0x3ac6e909, 0x36a1ab82, 0x1fe50127, 0x1a4461e2, 0x3c9b0e10, 0x3c633548, 0x132f}}}, + /* 9*16^21*G: */ + {{{0x172d0aba, 0x32311e89, 0x37e1b16d, 0x34642b71, 0x01241dd8, 0x383bad54, 0x2807079e, 0x3a53bf90, 0x2d9b}}, + {{0x31fa0876, 0x23dcc7ec, 0x0b710e6f, 0x34719e62, 0x19d91bba, 0x3be4d2d8, 0x098a2295, 0x236d7a7a, 0xa970}}}, + /* 11*16^21*G: */ + {{{0x355e8732, 0x0301ed20, 0x06d1e31e, 0x298bb794, 0x12c243cf, 0x2f194c52, 0x2421660c, 0x00e7b220, 0x2127}}, + {{0x20cacc07, 0x1648d7d1, 0x2d7bd68d, 0x24fcfcee, 0x3f0a5cd6, 0x12e76eed, 0x235aa019, 0x271bc8eb, 0x8521}}}, + /* 13*16^21*G: */ + {{{0x32083347, 0x0244d033, 0x31a53226, 0x06b8f99d, 0x02b42b9e, 0x343d6ae8, 0x0e0eb97a, 0x2d52caf6, 0xfab5}}, + {{0x3d38fd2f, 0x33327360, 0x2a69afa9, 0x178de985, 0x0a3eafc0, 0x1eabc898, 0x141503c8, 0x3445861b, 0x5758}}}, + /* 15*16^21*G: */ + {{{0x3f572554, 0x3d9c9853, 0x0f4dab73, 0x210b91c6, 0x3ea56ff3, 0x0259dc2d, 0x31fca579, 0x09d5c9e5, 0x685d}}, + {{0x20979e03, 0x1c6bdb42, 0x0f4cca4b, 0x22aa8ab0, 0x20377cc5, 0x0e720107, 0x345fc06e, 0x2270882a, 0xa82f}}} + }, + { + /* 1*16^22*G: */ + {{{0x05852e50, 0x1f42c933, 0x3570cc5c, 0x0b1f98f3, 0x2e7eff8b, 0x26a88d27, 0x3b058c1f, 0x31f7ffaa, 0xe486}}, + {{0x2ecf107d, 0x1ae8f2b6, 0x392ebd86, 0x1118f58c, 0x11e05a69, 0x2229727d, 0x2a12e9ee, 0x1d7b5581, 0x51fd}}}, + /* 3*16^22*G: */ + {{{0x1c881907, 0x19aa9915, 0x300b1dac, 0x0b219cd6, 0x2e041514, 0x0417319a, 0x3fb7c964, 0x112ee38b, 0x4acf}}, + {{0x363cdafc, 0x249ad15b, 0x0d84b252, 0x0d4acbdf, 0x0a545799, 0x10a16b44, 0x1587b354, 0x2a3f83ff, 0xad99}}}, + /* 5*16^22*G: */ + {{{0x3439383f, 0x0aeb81a5, 0x201a2aa8, 0x3fe958ad, 0x234eec34, 0x2a8a4b20, 0x0a649dd7, 0x08a0d062, 0x4ddf}}, + {{0x23d52337, 0x0cbea060, 0x31f82696, 0x35741144, 0x0c0c6b3d, 0x2eba5f4e, 0x1883d74a, 0x189ec364, 0xe71c}}}, + /* 7*16^22*G: */ + {{{0x1822b4f4, 0x1b722055, 0x065df8f2, 0x0d4ebf3e, 0x3bf39ba5, 0x13a781e5, 0x1879e133, 0x195e44de, 0x58b0}}, + {{0x0c60fbca, 0x181ea084, 0x04e52596, 0x29281dbf, 0x22836c1c, 0x32957c09, 0x22c37027, 0x22a90516, 0x55a9}}}, + /* 9*16^22*G: */ + {{{0x34fe39b0, 0x2caf4430, 0x0b4ded14, 0x0c5cf35d, 0x381f358a, 0x2910708c, 0x33529763, 0x38162992, 0xa345}}, + {{0x2baf79dc, 0x1c25202e, 0x3369df53, 0x231a9d6a, 0x39d949ce, 0x02156ca3, 0x2a70f91f, 0x3569b572, 0x7c6d}}}, + /* 11*16^22*G: */ + {{{0x126695fb, 0x3ef81ee6, 0x03adee13, 0x342ee7f9, 0x16ccb6af, 0x2b2e1d1b, 0x0a2c8201, 0x2fe0c064, 0x3a10}}, + {{0x24eb7e47, 0x1571caca, 0x3d452887, 0x23fa9b10, 0x0a65c5f2, 0x00e121a2, 0x22715762, 0x216cfb06, 0xb5d5}}}, + /* 13*16^22*G: */ + {{{0x3d2c8614, 0x106a3a59, 0x05845962, 0x2c258298, 0x112876a7, 0x33d6b0c2, 0x10433ca5, 0x377eb240, 0x12fb}}, + {{0x18b0b174, 0x01def075, 0x019f495f, 0x109608e7, 0x12cfb54d, 0x36450a33, 0x3806833f, 0x0834a409, 0xa5ff}}}, + /* 15*16^22*G: */ + {{{0x2d9aeeaf, 0x0fdd90c0, 0x05afc865, 0x341e5328, 0x399a3005, 0x2b8e87eb, 0x178777b8, 0x3a1668ae, 0x8bec}}, + {{0x05f9eb5e, 0x168368f2, 0x38980f75, 0x0880e3db, 0x3fc368bb, 0x22442c3b, 0x251fcfbb, 0x0cf13141, 0x35f9}}} + }, + { + /* 1*16^23*G: */ + {{{0x2b519178, 0x12dae3b0, 0x03d1fc58, 0x0ee66629, 0x22ee0ab6, 0x0233e2d7, 0x10430cfe, 0x1fd2ed79, 0xf41d}}, + {{0x0a6a3551, 0x1e859977, 0x119e1f9a, 0x126b30da, 0x282347ab, 0x11b78fea, 0x2f8d6f10, 0x1a6faf66, 0xe6a6}}}, + /* 3*16^23*G: */ + {{{0x1e3501d9, 0x29c4c4f8, 0x361fc8b1, 0x3a0b386e, 0x2d3e611b, 0x0b5a4758, 0x14e7f333, 0x209fb58b, 0xd65f}}, + {{0x2b55759e, 0x2e511b1b, 0x1730be1a, 0x304eab57, 0x2b87fc61, 0x2df29459, 0x290fe537, 0x183f3c26, 0xf24b}}}, + /* 5*16^23*G: */ + {{{0x0f2ed84e, 0x2d8bf890, 0x3e2ea12c, 0x26537cd7, 0x2cc0ade7, 0x1b22d5e0, 0x05c385ee, 0x2d6db7ac, 0x55a9}}, + {{0x146495a3, 0x1e771541, 0x2a0d8f05, 0x3fed35c4, 0x17f43ae8, 0x1d34643b, 0x319ab291, 0x0865ab27, 0xc4f2}}}, + /* 7*16^23*G: */ + {{{0x075495a2, 0x2f4b3e1c, 0x0bc00b29, 0x3787ad92, 0x148bc49f, 0x3b582989, 0x371da1f7, 0x15db71f6, 0x79de}}, + {{0x2aec6fb8, 0x00b231aa, 0x093a7468, 0x053d4259, 0x1c79c683, 0x39b6b91f, 0x06a02785, 0x0f439ac6, 0x3b2d}}}, + /* 9*16^23*G: */ + {{{0x02d1e7bb, 0x3ba4ab32, 0x111964ce, 0x30ffe40d, 0x17e55524, 0x12cda565, 0x004b6e26, 0x138c8589, 0x8fe0}}, + {{0x1a62e84f, 0x29d66b43, 0x3046a8cd, 0x2459191b, 0x0db34e5b, 0x1b3a95ea, 0x2358fe5d, 0x36d408bd, 0x3987}}}, + /* 11*16^23*G: */ + {{{0x29f7c360, 0x00692bb1, 0x08085c21, 0x3f355df9, 0x1224e24e, 0x25298da3, 0x1f8f150a, 0x264255fb, 0x3af4}}, + {{0x287d7a7b, 0x0e770aa9, 0x360895cd, 0x15537589, 0x333c3348, 0x3e1920b9, 0x1d91d531, 0x180c34ec, 0xd170}}}, + /* 13*16^23*G: */ + {{{0x370373be, 0x26948eb9, 0x263d3b53, 0x0f418884, 0x227c4e21, 0x160bcff8, 0x08076c1a, 0x3817188f, 0x31a7}}, + {{0x290950a8, 0x3b5e1e43, 0x1a254308, 0x3a0ae654, 0x23db1e8c, 0x2c2ab8d0, 0x1de67021, 0x0bbcfe34, 0xc23d}}}, + /* 15*16^23*G: */ + {{{0x0b923b45, 0x109843b7, 0x13e24bdb, 0x0ea7effc, 0x198458a3, 0x144d18b7, 0x2d23ed15, 0x199204d5, 0x740a}}, + {{0x11ecaa5f, 0x2304f8e1, 0x3c8480ba, 0x25e64e41, 0x1606cfa8, 0x391e229d, 0x1523f2f4, 0x01230973, 0x7f6d}}} + }, + { + /* 1*16^24*G: */ + {{{0x3512218e, 0x212aa4e5, 0x0ca0141a, 0x29486c1d, 0x22e902e9, 0x202ce862, 0x277a6578, 0x141984a9, 0x4a5b}}, + {{0x0c4f3840, 0x2fab69e9, 0x1e26d9d0, 0x1b6c5506, 0x227d4062, 0x1813ef85, 0x089f1c42, 0x11873ab0, 0xeb13}}}, + /* 3*16^24*G: */ + {{{0x118473fd, 0x0bbd0389, 0x29733915, 0x2e409af1, 0x28a9e3bb, 0x24aae65c, 0x18ba0852, 0x018c8ccc, 0x1064}}, + {{0x385cf805, 0x3e9858b9, 0x021d039a, 0x2f864343, 0x05883ccf, 0x1e0a7996, 0x3a2d8c8e, 0x0ca08ee2, 0x9c68}}}, + /* 5*16^24*G: */ + {{{0x253f30f3, 0x159fbb21, 0x1a238dd3, 0x108fb4bb, 0x083f212b, 0x29043550, 0x327bf5ed, 0x2b63fc17, 0x38c8}}, + {{0x2be9217b, 0x01839d27, 0x159df37a, 0x20fea60a, 0x3d641f65, 0x02595376, 0x0b116f39, 0x185e1db7, 0x83c2}}}, + /* 7*16^24*G: */ + {{{0x36ef1584, 0x10f9a446, 0x3920cbf5, 0x2a68a8e3, 0x35184277, 0x23ef8ff4, 0x0bb09585, 0x232f3a18, 0x6fcb}}, + {{0x1d3110f2, 0x0f27df08, 0x28a4325c, 0x24bdb5a4, 0x30459d59, 0x30208eb0, 0x21d76d54, 0x2a0f62dc, 0xa8f1}}}, + /* 9*16^24*G: */ + {{{0x062255ef, 0x23d44d01, 0x364078ce, 0x35c74d19, 0x05b0ee50, 0x05724379, 0x2e2bd735, 0x342e4fdd, 0x7811}}, + {{0x1be3252e, 0x162fbe6c, 0x2d43768a, 0x07b4144e, 0x385132f5, 0x00ba5006, 0x1ac7a54c, 0x1d8dc2ed, 0x99bb}}}, + /* 11*16^24*G: */ + {{{0x353d2ea7, 0x0f8443c4, 0x3fa86509, 0x3b4208e8, 0x016f2a9e, 0x2dca757e, 0x350ce0c7, 0x0f6512a2, 0xc358}}, + {{0x0b667bbd, 0x2c60fa78, 0x15f1c432, 0x32496994, 0x1fcccdd6, 0x1189fbe2, 0x1e90f596, 0x1eb024e4, 0x5396}}}, + /* 13*16^24*G: */ + {{{0x102e3099, 0x3b77c381, 0x28401658, 0x3c84e998, 0x3ad00d53, 0x03c062ed, 0x2e501f3a, 0x33ca0f37, 0xd591}}, + {{0x055ac5af, 0x0ef09d95, 0x3116fd63, 0x3cbbfe22, 0x0bc5825c, 0x04cc34d4, 0x0e6e44e5, 0x3973f11e, 0x87eb}}}, + /* 15*16^24*G: */ + {{{0x32a940a5, 0x2c995918, 0x014e6b12, 0x10d7ad69, 0x39e8714a, 0x09078693, 0x235c4c01, 0x03584bcc, 0xa0aa}}, + {{0x0b950422, 0x0fe20a9a, 0x3d1bf939, 0x1a473769, 0x181f3e6c, 0x0d33e680, 0x3642819b, 0x03ae9dbd, 0x2234}}} + }, + { + /* 1*16^25*G: */ + {{{0x008e2df0, 0x18a360dc, 0x328e5f76, 0x30ec95d0, 0x3e0f5032, 0x30a77e2e, 0x2b995012, 0x2442f78a, 0x2eb3}}, + {{0x1274eaae, 0x2443313b, 0x0f65f490, 0x1034483b, 0x24999f95, 0x0df4d236, 0x34b3a77d, 0x3008cdd1, 0x3f29}}}, + /* 3*16^25*G: */ + {{{0x282867f0, 0x3c0ae12d, 0x3190a39b, 0x0509b886, 0x0900f0a2, 0x2f45a9e0, 0x07ce22aa, 0x36e23993, 0xf6e9}}, + {{0x0f1861ea, 0x1d6cebc4, 0x170b6234, 0x0106e97e, 0x00d5b127, 0x24eddba3, 0x2ab7481d, 0x1e42deb4, 0x53ca}}}, + /* 5*16^25*G: */ + {{{0x320d6102, 0x2b7410e3, 0x34539409, 0x1b54de28, 0x199a5ef0, 0x3056e6d8, 0x2449d785, 0x36ce1d83, 0xfd1d}}, + {{0x2e003b7c, 0x28299246, 0x1513983d, 0x0f864484, 0x03b70016, 0x287c7de2, 0x0638aeda, 0x2e1ce414, 0xcb54}}}, + /* 7*16^25*G: */ + {{{0x02c77cb7, 0x0fdcd077, 0x2dc15b6f, 0x1b650240, 0x2e698fef, 0x129cf997, 0x1901d9fe, 0x1cf08966, 0x61a2}}, + {{0x1ddb25ed, 0x151847e0, 0x0ae1f748, 0x316b669c, 0x2b0cc9c5, 0x28867d7b, 0x2d3d3f4e, 0x334cd34e, 0x5bba}}}, + /* 9*16^25*G: */ + {{{0x377d8976, 0x266355b8, 0x30f292db, 0x05ce8e38, 0x1d04b55e, 0x00b2608a, 0x201b64cb, 0x23997bdd, 0xcd2e}}, + {{0x0867bc22, 0x05a5bd07, 0x1428c051, 0x03b783cd, 0x06ff68f6, 0x073a3cb5, 0x2a31ffc3, 0x2b4d88d0, 0xf58e}}}, + /* 11*16^25*G: */ + {{{0x2c67c998, 0x026cc1b0, 0x3cf1b866, 0x26c1faa8, 0x304c259a, 0x097aa290, 0x23efb402, 0x07e70e08, 0x9bd6}}, + {{0x28199514, 0x0d02be70, 0x0424b18c, 0x1f6707a4, 0x1450fa92, 0x3c825a5a, 0x06f5c5c8, 0x0102645b, 0x77b2}}}, + /* 13*16^25*G: */ + {{{0x2aafa568, 0x291785ef, 0x01e22766, 0x335ea5dc, 0x17a016b4, 0x389e9044, 0x0777512a, 0x3ad3de5c, 0x7afa}}, + {{0x01c1f2df, 0x3b54e8be, 0x1d390233, 0x0b9a50ca, 0x01365a97, 0x34504d41, 0x3d27d895, 0x39864cfe, 0xc6ef}}}, + /* 15*16^25*G: */ + {{{0x0e59ddeb, 0x1f9c0f94, 0x11e98a8b, 0x0f98a72b, 0x2b0c3b48, 0x36530525, 0x012f9061, 0x00889f89, 0xd9a0}}, + {{0x0f0af5a4, 0x3ce4ffe0, 0x35f18ce5, 0x18aa2f2a, 0x27058185, 0x183e290d, 0x2022c43c, 0x2cbe4ede, 0x975e}}} + }, + { + /* 1*16^26*G: */ + {{{0x3ecca7e0, 0x1ce697a8, 0x343333ec, 0x34b263d9, 0x0d9428a7, 0x3d8cd489, 0x12a0c0fe, 0x3b8f171e, 0x7ef2}}, + {{0x152ac094, 0x00ac8b75, 0x3bd3d203, 0x2c851437, 0x2609db81, 0x19fd4757, 0x0c011a4f, 0x2189cc2b, 0xafb6}}}, + /* 3*16^26*G: */ + {{{0x233f0ffa, 0x0bcd60f6, 0x1807a417, 0x3932b184, 0x19c641ca, 0x1295db27, 0x07acd762, 0x15c9c5a2, 0x3704}}, + {{0x20fa35ac, 0x3fb4ff19, 0x28bf2fc5, 0x2e8fadea, 0x15ff4c57, 0x2ed2ee22, 0x1e74f841, 0x0231869c, 0x5c64}}}, + /* 5*16^26*G: */ + {{{0x32603513, 0x31be6194, 0x14a00953, 0x319371a0, 0x0bb697f6, 0x3aa90b02, 0x0db722d1, 0x1e7950a6, 0xc2a9}}, + {{0x3c3505b9, 0x15d56cb0, 0x01514499, 0x3199b7d2, 0x1bce7e8c, 0x1e02064d, 0x2b5c8542, 0x35d2879b, 0xef9d}}}, + /* 7*16^26*G: */ + {{{0x19fdee3e, 0x191bfec7, 0x0302e01e, 0x07e5dc5b, 0x17afb968, 0x2ec5736c, 0x059e1172, 0x061aac7f, 0xc9f4}}, + {{0x0ced22e7, 0x0799b317, 0x358df4f5, 0x3854c71e, 0x03214344, 0x1cc50ae2, 0x3a3410df, 0x029fcf2c, 0x0942}}}, + /* 9*16^26*G: */ + {{{0x0814f217, 0x032cf99d, 0x356cffaf, 0x368fdee1, 0x3bb6a4a9, 0x280093e0, 0x00256b08, 0x3d56e012, 0x27dc}}, + {{0x0cf2ed4c, 0x13252d62, 0x11fc3bf1, 0x13a3eac6, 0x202a380a, 0x22eac252, 0x15dee0bc, 0x3d53d523, 0xbe18}}}, + /* 11*16^26*G: */ + {{{0x1b9e310c, 0x168a93f5, 0x04cfd4a7, 0x0f396e6e, 0x15918731, 0x3492b0ce, 0x2ea4b9c8, 0x0080ec95, 0x3b8b}}, + {{0x2d19fc9b, 0x25059816, 0x2b305839, 0x3fe012e0, 0x0117a6a8, 0x1db8ddf1, 0x3615bd61, 0x1f13ac0c, 0x9111}}}, + /* 13*16^26*G: */ + {{{0x27615b36, 0x3c7878ae, 0x3f3c15f8, 0x13fc7a31, 0x14c3372a, 0x30901be4, 0x0103a105, 0x0e6316f3, 0xa5e7}}, + {{0x09136d80, 0x3660b8e5, 0x0b613c04, 0x3ff064dc, 0x15f8c547, 0x0e37bca8, 0x0e4ce464, 0x3d63725d, 0x1f3f}}}, + /* 15*16^26*G: */ + {{{0x2d3e10db, 0x2dec10cb, 0x0b87159b, 0x1ccb86b2, 0x2b61fa47, 0x0110ffd3, 0x1532bdee, 0x060d56b2, 0xaad2}}, + {{0x2fa05fb3, 0x0d4d6af5, 0x31cba276, 0x00c9dcac, 0x1f8b4a72, 0x3778a3f5, 0x02e3b3a7, 0x07bbaebe, 0x793b}}} + }, + { + /* 1*16^27*G: */ + {{{0x2c49e853, 0x1c07c243, 0x175e04a6, 0x32d4d4a6, 0x1fa77aa9, 0x009553ad, 0x00aeb578, 0x10590859, 0x0e51}}, + {{0x36405cb2, 0x0db8f44d, 0x0c9ee363, 0x1a0e5064, 0x11030df5, 0x3ad294ea, 0x05469278, 0x073a9964, 0xcf33}}}, + /* 3*16^27*G: */ + {{{0x1dc6afad, 0x1288fc70, 0x1f80f46c, 0x34f648a5, 0x00c6771b, 0x3b497d93, 0x2cf25de8, 0x2819d972, 0x977b}}, + {{0x1d7faa09, 0x358b3714, 0x1da1a154, 0x1d684907, 0x01d9992f, 0x0fea8342, 0x38fa2883, 0x2f10ebb6, 0x1bc3}}}, + /* 5*16^27*G: */ + {{{0x1d81983b, 0x17dd175f, 0x38eab786, 0x0883f40b, 0x3ffacc10, 0x32d81dc7, 0x23abe4c3, 0x0a184a84, 0x3bc3}}, + {{0x11a637b6, 0x3667ca14, 0x3bb848db, 0x0d2216a3, 0x300a7f43, 0x2cc172ab, 0x08a20250, 0x209b7b43, 0xa6b5}}}, + /* 7*16^27*G: */ + {{{0x37c8537b, 0x17ddb07f, 0x01f80617, 0x232b2dd1, 0x396c21ca, 0x2bbf872b, 0x004ac51b, 0x293a3a7b, 0x67cb}}, + {{0x385726da, 0x33ad415c, 0x0403f6e1, 0x37c10fb4, 0x31cc047b, 0x07187cbe, 0x08984a1e, 0x3b7b7a87, 0x5b65}}}, + /* 9*16^27*G: */ + {{{0x0b6a1226, 0x1a08a339, 0x35465393, 0x3e7a722a, 0x28f3922a, 0x1cf5a191, 0x099931a0, 0x23a9b55d, 0xc595}}, + {{0x066961d4, 0x30401a23, 0x22108b91, 0x21db6fae, 0x05bd8296, 0x3865c675, 0x37dd7ecb, 0x2a20bdc3, 0xa031}}}, + /* 11*16^27*G: */ + {{{0x33713a52, 0x1378fe16, 0x03c5417e, 0x31d6e31a, 0x0a5fa025, 0x33030f1d, 0x25ca7c1f, 0x1efe0b90, 0x83f0}}, + {{0x1fb0ffb6, 0x04449cfe, 0x1fb45d2a, 0x2d6dd838, 0x07d3cfca, 0x1e53244b, 0x38bb9049, 0x13c42896, 0xf2ec}}}, + /* 13*16^27*G: */ + {{{0x21ba21b0, 0x2b668244, 0x0c265539, 0x15763480, 0x2e0076d8, 0x1a01a1ba, 0x242d4e6f, 0x2e93e6d6, 0x938d}}, + {{0x0d5b4325, 0x1d366579, 0x32b697c3, 0x3c6efb8f, 0x36b90bcb, 0x2ab6f744, 0x356566e9, 0x302a26bd, 0x48af}}}, + /* 15*16^27*G: */ + {{{0x3f2b24f1, 0x14f92698, 0x3e76bcfb, 0x2bb193d7, 0x349779cf, 0x076ab3ce, 0x031e73a8, 0x226ddb28, 0x7efa}}, + {{0x2f8e4b83, 0x19771752, 0x154a455d, 0x2eb7ceb1, 0x16ab211d, 0x3b488bf0, 0x0aeff78c, 0x3cfb187d, 0xa99f}}} + }, + { + /* 1*16^28*G: */ + {{{0x22f2b734, 0x01a66fe7, 0x101d267f, 0x30eed6d5, 0x16445779, 0x129e1bc4, 0x0c99a063, 0x008a67bb, 0x224a}}, + {{0x11ec7fdf, 0x103d6152, 0x3c7afd08, 0x2dc12d9c, 0x1d7fff07, 0x2822b61c, 0x122b4149, 0x2a34a6db, 0xfa41}}}, + /* 3*16^28*G: */ + {{{0x1d254033, 0x27a4bd1d, 0x2a4707ac, 0x0da0a030, 0x36f24078, 0x2b7e9a22, 0x0ec59fcd, 0x00bb854f, 0xe635}}, + {{0x28f05e3f, 0x3a2aa225, 0x3fcf3607, 0x24568312, 0x09ce482c, 0x13a03c1c, 0x21e11ad7, 0x20dec7d8, 0xa7c5}}}, + /* 5*16^28*G: */ + {{{0x21e08f33, 0x2e5826bf, 0x3982cca2, 0x3f58c772, 0x3000e2b1, 0x2d1714cf, 0x3968712a, 0x37b09cba, 0x5648}}, + {{0x0269f1c9, 0x1bbb66b1, 0x01179512, 0x1caefcb8, 0x37a2693e, 0x23d71935, 0x37043f47, 0x371c1c23, 0x95fd}}}, + /* 7*16^28*G: */ + {{{0x3ab98c43, 0x0ee0802f, 0x23e8aa4e, 0x2e95dd5f, 0x2c8f03c5, 0x14be3b2f, 0x0ed26951, 0x3067cce0, 0x1941}}, + {{0x22abe217, 0x3e884368, 0x0df56398, 0x3d8b4f6e, 0x3b8c53d8, 0x1b6ca923, 0x1b2b6e2b, 0x2e0d1657, 0x8e66}}}, + /* 9*16^28*G: */ + {{{0x02d8c2f4, 0x199c3441, 0x39c0189e, 0x0cc86e7d, 0x0d8a0bd7, 0x1cef78d9, 0x34bd67fa, 0x190c7442, 0xfc58}}, + {{0x3cfd274a, 0x0463223f, 0x3c338b40, 0x38b2c17a, 0x3db4ab29, 0x0f09e79a, 0x2d9564a3, 0x3794b3a2, 0x99fa}}}, + /* 11*16^28*G: */ + {{{0x11ff0f18, 0x0ac1dfc7, 0x149a42d1, 0x382f39c1, 0x32d6c207, 0x3eeb3e6b, 0x0f1dea9b, 0x0ee9ac31, 0xee99}}, + {{0x250782ad, 0x004e1db2, 0x30f2cb18, 0x0d72037d, 0x05bcfeb4, 0x3175633a, 0x0db2c1f6, 0x3536515e, 0xd87f}}}, + /* 13*16^28*G: */ + {{{0x0fdde3fc, 0x11e9fdd5, 0x1628cc9e, 0x2a222781, 0x2f31fbe5, 0x03710694, 0x3e2428da, 0x145eaba7, 0xba49}}, + {{0x2fcb7d01, 0x0fbf48cb, 0x3292caaa, 0x37872078, 0x13359adf, 0x3b90dd80, 0x055950b4, 0x2db872a5, 0xa88f}}}, + /* 15*16^28*G: */ + {{{0x3d14da68, 0x2224a8bd, 0x1d201737, 0x19307e13, 0x3612b54a, 0x0b3e09cd, 0x2f1ba4de, 0x23c5d08a, 0xd339}}, + {{0x15a90e3d, 0x3c1d8c6d, 0x141453a3, 0x31e9e48b, 0x22b020af, 0x094b47a2, 0x13d60eb7, 0x3535347f, 0xa34a}}} + }, + { + /* 1*16^29*G: */ + {{{0x3789b84d, 0x298196b5, 0x1041ce2e, 0x1f57b934, 0x2493fe16, 0x174446d5, 0x34b4ccdb, 0x298515cd, 0x4a89}}, + {{0x018e3ea8, 0x3e6df5fc, 0x0711999e, 0x0b8a018d, 0x2677e6a7, 0x0baa5e7f, 0x00d5c08c, 0x13a1fb52, 0x45b0}}}, + /* 3*16^29*G: */ + {{{0x02e14c34, 0x39dac8dd, 0x33275936, 0x1317af81, 0x1377c983, 0x26cc39e0, 0x0ef92a2a, 0x25922a1c, 0xcc9f}}, + {{0x14be556b, 0x224855ea, 0x28c7e058, 0x2645fc60, 0x2689db29, 0x0598cf6f, 0x0c96f431, 0x3fcb2d7e, 0x829b}}}, + /* 5*16^29*G: */ + {{{0x15de4837, 0x1f79b216, 0x1e5e74e8, 0x10a1b20b, 0x198a758d, 0x1630742b, 0x1041af4f, 0x23687eab, 0x5c61}}, + {{0x234a7dee, 0x02e160ed, 0x02278cac, 0x34d99259, 0x3d9671ec, 0x2038e127, 0x3a19d88b, 0x2445ef3c, 0x4c71}}}, + /* 7*16^29*G: */ + {{{0x16635396, 0x1624d099, 0x28a6c0c2, 0x32b8568d, 0x31c11ef2, 0x178b7799, 0x206a2e58, 0x221aa456, 0xab8a}}, + {{0x3fc92c23, 0x38e3e9a8, 0x3d2d6ad7, 0x0d8160fd, 0x3cd5abb9, 0x23fe0922, 0x04319566, 0x33df1f6a, 0xe773}}}, + /* 9*16^29*G: */ + {{{0x01df49c3, 0x3090f962, 0x1069a35a, 0x3a24219b, 0x15604aa9, 0x1992e2da, 0x1838cdec, 0x32145090, 0x62b7}}, + {{0x36341c21, 0x2f8da03f, 0x07cb5509, 0x2d4ed84e, 0x0922db8f, 0x225aba35, 0x20335594, 0x358854ab, 0xa71e}}}, + /* 11*16^29*G: */ + {{{0x244f47d0, 0x2bc51b8b, 0x09f002f3, 0x167d77a5, 0x1fc9791b, 0x147c21a7, 0x089c5f97, 0x2f6fe917, 0x4897}}, + {{0x0e1320bf, 0x079406ab, 0x0f011958, 0x1b68006a, 0x3b093f52, 0x23b2a505, 0x0138c34e, 0x3083debf, 0xe77d}}}, + /* 13*16^29*G: */ + {{{0x31581bd3, 0x186f3a6d, 0x2190786e, 0x3e8c637d, 0x322f2ecb, 0x0781ef69, 0x06576c45, 0x3f2d5592, 0xeb1c}}, + {{0x1cd98a09, 0x2f3a3661, 0x1bd1a645, 0x273cc671, 0x0d6e3cb3, 0x10017af9, 0x14d20504, 0x339d5c7e, 0xfd47}}}, + /* 15*16^29*G: */ + {{{0x273a3111, 0x0048af6d, 0x34c818f9, 0x2e0b905e, 0x2576a018, 0x152b0b9c, 0x21e09c0d, 0x22eef923, 0xa1fd}}, + {{0x38c704ef, 0x221f9942, 0x3d51169b, 0x3b12516f, 0x0916c0c7, 0x1df81ef0, 0x308569bd, 0x17628d28, 0xad21}}} + }, + { + /* 1*16^30*G: */ + {{{0x32bd05a0, 0x10e32129, 0x31fc80d3, 0x208cdf42, 0x2d1f90ba, 0x0be657cd, 0x1885cedc, 0x248d8e8c, 0xe5e8}}, + {{0x21a69f5d, 0x24db78af, 0x0d099aec, 0x1ce656e7, 0x1b5c3eca, 0x07ac079e, 0x387d2130, 0x27793686, 0x7743}}}, + /* 3*16^30*G: */ + {{{0x01467d6b, 0x3c254a04, 0x2a24b514, 0x1f5c4a54, 0x2cf1d835, 0x06184590, 0x1ccf5d10, 0x24f7e50d, 0x5d23}}, + {{0x31bc5458, 0x1f19cf1a, 0x10473a80, 0x29c1e9d4, 0x1af46d72, 0x2f616cb5, 0x10f7d7ac, 0x18fc98ff, 0xe66e}}}, + /* 5*16^30*G: */ + {{{0x1d159f7a, 0x02c7a4f2, 0x242e590f, 0x3e4ea73c, 0x3f873fec, 0x33ecaf4b, 0x3893f3ad, 0x15e94eaa, 0x4536}}, + {{0x0a02fb78, 0x2708adc2, 0x01dda5d9, 0x2526f53a, 0x01c7286f, 0x3bc244e8, 0x23dc5da2, 0x2bbfe200, 0xbfb5}}}, + /* 7*16^30*G: */ + {{{0x146cb42a, 0x07b7b7cf, 0x32390933, 0x014a14e9, 0x3d73e7bc, 0x12b7aa84, 0x04c464d1, 0x1532c1ec, 0x435b}}, + {{0x1af72dd0, 0x1f8937b7, 0x33949a6b, 0x37131e50, 0x20585d5e, 0x12953307, 0x18a1a49f, 0x300c791c, 0xd726}}}, + /* 9*16^30*G: */ + {{{0x1d2fc263, 0x25f6506c, 0x365d57ba, 0x33e04f96, 0x13da0e89, 0x2f11f138, 0x2dd7e19f, 0x2e067853, 0x1805}}, + {{0x30870ec7, 0x1991c2d3, 0x151ecaf2, 0x2306be39, 0x0b31489c, 0x236aa1af, 0x38171585, 0x190a0250, 0x101f}}}, + /* 11*16^30*G: */ + {{{0x0076d1df, 0x28ac6dc3, 0x27fa1b39, 0x07882050, 0x375f45f4, 0x05ea28a9, 0x3194f406, 0x2bd0d9b4, 0xc73a}}, + {{0x25ad6605, 0x09e7545b, 0x1893720d, 0x16d5e947, 0x3cdcfef7, 0x3806f8ee, 0x3916ef9c, 0x3b1a7b33, 0x9201}}}, + /* 13*16^30*G: */ + {{{0x05a745c7, 0x0da0fde6, 0x17eac07d, 0x2289ce30, 0x1d52c1bc, 0x226dabd8, 0x036d2771, 0x3ba3df57, 0xe3dd}}, + {{0x378efcc2, 0x0e7c2501, 0x3d027b1a, 0x0a30bc5e, 0x3bd8f47c, 0x146e1aa9, 0x32b871be, 0x2674e464, 0x4871}}}, + /* 15*16^30*G: */ + {{{0x0d4170b3, 0x131ccfa1, 0x03a3587f, 0x051055bf, 0x00a1d540, 0x22a8461b, 0x1f1e5af6, 0x2377080d, 0x45c7}}, + {{0x111faa1d, 0x1bbe8fb5, 0x020cc731, 0x2c119819, 0x3b3a512c, 0x06a74513, 0x15c0cb0e, 0x265188e3, 0x11af}}} + }, + { + /* 1*16^31*G: */ + {{{0x3ab5c2cf, 0x055e664b, 0x3b084de2, 0x04bc3087, 0x3a90a453, 0x1d1d0413, 0x21f5071e, 0x1f90c788, 0xe410}}, + {{0x2b955c2b, 0x00a100fc, 0x37b2410d, 0x1e24b73f, 0x1c2b323c, 0x2319a1d0, 0x01c9a394, 0x0479b3dc, 0x1e5f}}}, + /* 3*16^31*G: */ + {{{0x09b67b7e, 0x2ed6d8f0, 0x11c3d485, 0x1adecae4, 0x3c114276, 0x3e5c077a, 0x39f7daac, 0x26997b85, 0x85df}}, + {{0x030a36e3, 0x22ce1a7a, 0x3bc6ea58, 0x3ea52747, 0x0e297386, 0x2df57bfc, 0x36308bb6, 0x2dea8e6b, 0xa6b4}}}, + /* 5*16^31*G: */ + {{{0x0b3510d3, 0x09f3f798, 0x0a1d6e41, 0x34c599c1, 0x2d292885, 0x22861970, 0x3cd08a8d, 0x24ff9fe7, 0x23c4}}, + {{0x3ae89a47, 0x0d18bb10, 0x2b9dbd71, 0x2678d789, 0x3fe6d8f7, 0x1d76793b, 0x014230c2, 0x15aa790d, 0xadf4}}}, + /* 7*16^31*G: */ + {{{0x0b49a71f, 0x331a4602, 0x0227c39a, 0x0dbadb19, 0x3235ddac, 0x264faeab, 0x1d0edde5, 0x1b42cc53, 0x9440}}, + {{0x10b249a9, 0x1c706513, 0x263cf944, 0x389c9872, 0x2fe897d0, 0x01f24241, 0x1f179cd2, 0x39dfa193, 0x61aa}}}, + /* 9*16^31*G: */ + {{{0x20e50c32, 0x17378cf1, 0x0c6873fe, 0x3c425cba, 0x2e8d3877, 0x04db7d6f, 0x06c14337, 0x2fd0f7a2, 0x3c2e}}, + {{0x0a93c124, 0x38be245f, 0x2e8c9989, 0x0b4230e6, 0x2e28e7be, 0x16e4f480, 0x0399c652, 0x3669b17a, 0xa703}}}, + /* 11*16^31*G: */ + {{{0x03a2355a, 0x020f677b, 0x06049907, 0x1946fcd7, 0x055f1299, 0x0796e27b, 0x00eb9f39, 0x0db5c9e5, 0x9875}}, + {{0x1bd05276, 0x031d7130, 0x03adccdf, 0x17db1f1a, 0x257b48b8, 0x02c70527, 0x1117243e, 0x26b59d3c, 0x12f1}}}, + /* 13*16^31*G: */ + {{{0x12f3ec22, 0x03c151f1, 0x1a8f8a6b, 0x3e1b73dc, 0x32ddddd1, 0x34e2c5fb, 0x04468f19, 0x2b102693, 0xd515}}, + {{0x25a2863b, 0x28518bac, 0x31b806ec, 0x355f7c00, 0x12bd464c, 0x17921001, 0x09b2e1ea, 0x12050891, 0x51c0}}}, + /* 15*16^31*G: */ + {{{0x1971c857, 0x16687a69, 0x3e6093fa, 0x32679b6a, 0x21cf3dde, 0x14f30e2d, 0x1b0bae24, 0x27526179, 0x070b}}, + {{0x0ac8dfc1, 0x3e72d8f7, 0x05461aaf, 0x2a0f687b, 0x373cfb33, 0x2042b918, 0x3625086b, 0x1186ffd2, 0xed80}}} + }, + { + /* 1*16^32*G: */ + {{{0x1789bd85, 0x1f213f27, 0x297eac35, 0x0d7fdf70, 0x06766efc, 0x20bf5623, 0x35e67fb9, 0x1ce6fbb6, 0x447d}}, + {{0x32e25b32, 0x31f8cf25, 0x3fae5000, 0x0d26e569, 0x0aaff73d, 0x3a7654e9, 0x131eee12, 0x096ae0d0, 0x2d48}}}, + /* 3*16^32*G: */ + {{{0x1ea6db68, 0x0f86663b, 0x02632c27, 0x3eb61582, 0x1ef4f6dd, 0x0537e597, 0x2017f58b, 0x14cf80f2, 0xf8b6}}, + {{0x2e760da9, 0x26f496c2, 0x05ca0ed6, 0x2f5c3767, 0x2a3ec66b, 0x11b76942, 0x054862f0, 0x13bd7b11, 0xc30f}}}, + /* 5*16^32*G: */ + {{{0x3924e753, 0x1b5753af, 0x0f8727c6, 0x005cc1cb, 0x2dfb755f, 0x3bc61ca7, 0x2847c548, 0x2274d560, 0xf352}}, + {{0x2b13a20c, 0x2916d70b, 0x12d0f04a, 0x18bf15ca, 0x0e1bd8c5, 0x3c2286d4, 0x013fb93d, 0x1e07b17b, 0x75c1}}}, + /* 7*16^32*G: */ + {{{0x3018017e, 0x0e572d9c, 0x2df23d72, 0x0507fff5, 0x334e01af, 0x10617ed9, 0x01716483, 0x1add3691, 0xcfd0}}, + {{0x0e0dff50, 0x02b9ef93, 0x3779777a, 0x0c0c1e1a, 0x1a795000, 0x0ece561f, 0x3a913810, 0x2dea6dca, 0xb647}}}, + /* 9*16^32*G: */ + {{{0x392db860, 0x13206415, 0x29a247b0, 0x0224a20c, 0x15dbe981, 0x0b5b423c, 0x1dcd1151, 0x39d312b5, 0x0755}}, + {{0x20d09849, 0x3598036e, 0x3c2777a7, 0x24dd1933, 0x015bc2b2, 0x26cb608e, 0x19e4dd24, 0x2be9d4eb, 0xfe16}}}, + /* 11*16^32*G: */ + {{{0x2a26ba6b, 0x27bda557, 0x2da12c3a, 0x0b28a925, 0x30bbdedd, 0x043035fa, 0x2c96968a, 0x2a1330dc, 0x88fb}}, + {{0x244972f8, 0x01051e07, 0x00cfdce8, 0x12a78a38, 0x14788d48, 0x1b6916d4, 0x1be0fd26, 0x3bd9274e, 0x512a}}}, + /* 13*16^32*G: */ + {{{0x14720cab, 0x2712290a, 0x339b17e3, 0x07a97505, 0x1c6f2c1a, 0x03db9d55, 0x15beb8e5, 0x2b32fb01, 0xe1a0}}, + {{0x34b185c9, 0x1b514fd5, 0x080254ea, 0x128a9c74, 0x2ebcbf08, 0x1be0c1df, 0x0c854183, 0x1a3edfa6, 0xe079}}}, + /* 15*16^32*G: */ + {{{0x2c26c42a, 0x2a0a3f7f, 0x2b11bb62, 0x26fedf91, 0x27e6a024, 0x2cd624c7, 0x33c7e50d, 0x0ee1b9a9, 0x0ae9}}, + {{0x39f808ca, 0x0418cd0e, 0x1aadb649, 0x228e7bbd, 0x220b3727, 0x0b8fb707, 0x07e13a94, 0x3db7451e, 0x7028}}} + }, + { + /* 1*16^33*G: */ + {{{0x137de736, 0x3af62eb0, 0x288ce241, 0x3e355861, 0x1ec18ea2, 0x1d50ae33, 0x0cf3e893, 0x38c52527, 0x9022}}, + {{0x04c42ecc, 0x13bd7021, 0x0ea7657f, 0x124d9b11, 0x26ce087f, 0x02ec1148, 0x0a39466d, 0x1793ca41, 0x2fae}}}, + /* 3*16^33*G: */ + {{{0x109b01f5, 0x05c1b2e3, 0x273c0519, 0x0fcd460c, 0x37857af7, 0x3cb4fc6b, 0x3e945fb0, 0x1cb8c1db, 0x6e58}}, + {{0x2bcd5fde, 0x0c1d6366, 0x09a85a7c, 0x0c5e7538, 0x3ef0ebc1, 0x30752bce, 0x3717180c, 0x300bb235, 0x4213}}}, + /* 5*16^33*G: */ + {{{0x2fe45b1f, 0x14e6dd1f, 0x26168c2b, 0x34557ecb, 0x17df827b, 0x3478d130, 0x23f504af, 0x082c6976, 0x2922}}, + {{0x134bb026, 0x3f902e2d, 0x0dd41045, 0x30d10c13, 0x298d7ff7, 0x31e57feb, 0x175aee37, 0x2814cafc, 0xe316}}}, + /* 7*16^33*G: */ + {{{0x23abd540, 0x3a14198a, 0x3166de43, 0x20101952, 0x093a340e, 0x093e1c84, 0x04f0ac32, 0x385201e9, 0x3644}}, + {{0x155da631, 0x071bf873, 0x26fa14de, 0x05df3b69, 0x21e29300, 0x0a14c27e, 0x2797611c, 0x245436f0, 0xec5a}}}, + /* 9*16^33*G: */ + {{{0x09142ccb, 0x28bf487a, 0x287ede31, 0x248296b1, 0x3bb4824c, 0x2ce3d264, 0x0d838e55, 0x1f6b85ff, 0xedfe}}, + {{0x2c593d75, 0x2e5474c6, 0x151142eb, 0x2910ada7, 0x15beb81d, 0x1574ad3d, 0x1af21618, 0x24848b83, 0xc886}}}, + /* 11*16^33*G: */ + {{{0x0a41b208, 0x0f69c719, 0x2e27000f, 0x3dd1d737, 0x2a0de8e7, 0x05009af3, 0x1a695987, 0x25a2d016, 0x5311}}, + {{0x048e4b69, 0x24787e78, 0x036877f6, 0x0f077009, 0x33da113b, 0x196078ce, 0x22978a6c, 0x1ccacf70, 0xb78d}}}, + /* 13*16^33*G: */ + {{{0x095daae7, 0x0f406d71, 0x07033bcb, 0x11b9bb1f, 0x20e1d5af, 0x08afdbd5, 0x3a594f7a, 0x347c8bfe, 0xf65d}}, + {{0x02556738, 0x35396a67, 0x2acd9b28, 0x018603e7, 0x3c4cd0eb, 0x1bf98df3, 0x366e820e, 0x2e083386, 0x9d71}}}, + /* 15*16^33*G: */ + {{{0x3afcf1ee, 0x2fbf0578, 0x2069a11a, 0x3eaa011c, 0x2807c60a, 0x2fd202aa, 0x2e248b41, 0x039fb732, 0xa667}}, + {{0x20c67fc8, 0x1e21c2af, 0x13cf38a3, 0x3ce62472, 0x17ac131e, 0x17dcbd25, 0x1c2f3a39, 0x05324e94, 0xa7fd}}} + }, + { + /* 1*16^34*G: */ + {{{0x04cd3397, 0x10451705, 0x1515eb57, 0x0d304186, 0x156deddc, 0x21b3cad4, 0x1a723893, 0x3fc1067b, 0x73ba}}, + {{0x1adcb8e4, 0x07bca84e, 0x02613494, 0x27be4b3e, 0x0f825e77, 0x0347a306, 0x3ac5f6a0, 0x3798d25d, 0x1e97}}}, + /* 3*16^34*G: */ + {{{0x161fb913, 0x3ac3e548, 0x2d312977, 0x04091855, 0x3ed04e3e, 0x0e237912, 0x20a18344, 0x0cc30cf9, 0x45f8}}, + {{0x0c15c3bc, 0x035205f0, 0x2fc33737, 0x1b421e7d, 0x3a7760f0, 0x3a01db62, 0x2906ef80, 0x33db6ff5, 0xc212}}}, + /* 5*16^34*G: */ + {{{0x2e393654, 0x2bbe5a47, 0x3edd7c75, 0x1752f87c, 0x0d599196, 0x1680722f, 0x3bdab65f, 0x37126b35, 0x5544}}, + {{0x0f53206f, 0x0d842efe, 0x3d58e732, 0x07bfa5c0, 0x13519224, 0x3016d6e2, 0x3fd4ac04, 0x21625421, 0xed3e}}}, + /* 7*16^34*G: */ + {{{0x28a15dfd, 0x0fcd6650, 0x1fa9e551, 0x076eb009, 0x22f69574, 0x34bb556b, 0x2e7734b3, 0x2de41867, 0x2757}}, + {{0x3042c341, 0x323a1033, 0x0a7156df, 0x1a25e28f, 0x15500d17, 0x25d484f3, 0x2b12e5cc, 0x34b55530, 0xdf46}}}, + /* 9*16^34*G: */ + {{{0x3f840a5b, 0x3fb7d09a, 0x3ad4984e, 0x232b6974, 0x143ccd14, 0x10873304, 0x22bc8d98, 0x10df7943, 0xe872}}, + {{0x1377e86a, 0x21396154, 0x1396464b, 0x0e8d1b3e, 0x248bf5ac, 0x2f247d98, 0x29616593, 0x2f22449c, 0xf984}}}, + /* 11*16^34*G: */ + {{{0x336afd6a, 0x255aa6e2, 0x1781e3d4, 0x187f1428, 0x33334a92, 0x3bdb579b, 0x375c0392, 0x372ae935, 0xc56c}}, + {{0x33f87c26, 0x1821afbb, 0x28cc723e, 0x3d20ec95, 0x194ef566, 0x3b7ac5fd, 0x2b070cd2, 0x15b8bce1, 0xd160}}}, + /* 13*16^34*G: */ + {{{0x2cfd2cd0, 0x36b66034, 0x19c0c131, 0x2504cd10, 0x08abb123, 0x34a160f9, 0x3f2869cf, 0x399ce3cf, 0xd3d6}}, + {{0x394ae2dc, 0x315e71dd, 0x2f6f8f14, 0x07e95a30, 0x3de59b00, 0x36a3fdcd, 0x19b68536, 0x23d7f345, 0xff44}}}, + /* 15*16^34*G: */ + {{{0x1ab7a64c, 0x25622157, 0x209ab7a0, 0x14235a8e, 0x37d40656, 0x04cb5c88, 0x05c07b03, 0x1de215b9, 0x88f9}}, + {{0x1575f103, 0x017a6384, 0x16d2673a, 0x30c02488, 0x169e5836, 0x0c6bc95e, 0x15c74345, 0x173751ad, 0x4a74}}} + }, + { + /* 1*16^35*G: */ + {{{0x1fa4e33c, 0x38b97ecc, 0x3098cb30, 0x20efb1e2, 0x36fb9826, 0x1111b0a5, 0x025bbc97, 0x11ae4693, 0x9cf6}}, + {{0x0e0d4563, 0x27117818, 0x3c160321, 0x081609fa, 0x021f319e, 0x0238962e, 0x25a891e4, 0x1893707d, 0x37b0}}}, + /* 3*16^35*G: */ + {{{0x06bf1e67, 0x262d8633, 0x25caf63e, 0x1599d27f, 0x364e0f4c, 0x2994e09d, 0x364999d7, 0x10f78546, 0x83cb}}, + {{0x099acc97, 0x09fba2cc, 0x1d1169ea, 0x1d108b2f, 0x0418f828, 0x0601b989, 0x0f6f8efb, 0x232892e6, 0xbce2}}}, + /* 5*16^35*G: */ + {{{0x1c0f057e, 0x0c2b5d23, 0x1d53dd82, 0x3a18a1c0, 0x25022484, 0x103f0578, 0x2b08c033, 0x2cf95833, 0x3ff3}}, + {{0x2817965e, 0x3507df6a, 0x07017622, 0x0408dbb1, 0x067843a0, 0x3f45c15e, 0x2578f6f7, 0x2b5bceed, 0x7f17}}}, + /* 7*16^35*G: */ + {{{0x325e69f1, 0x14452d00, 0x022bcb51, 0x19ea3cb5, 0x16af9963, 0x067785cf, 0x3d83fdda, 0x36cb763f, 0x6e9e}}, + {{0x002b7e9b, 0x08385f8d, 0x19f281b7, 0x1c9d151e, 0x33bff61c, 0x155aad97, 0x3954eab3, 0x0885b3bf, 0xc082}}}, + /* 9*16^35*G: */ + {{{0x2288f038, 0x3c94bd9a, 0x35ff820b, 0x21da253a, 0x2c2d32f0, 0x2f06779b, 0x01c4befa, 0x203a0131, 0x5ee2}}, + {{0x36f1ee6e, 0x316aae1a, 0x0e6c6f41, 0x35e0cea6, 0x09eec011, 0x0161bfb3, 0x3e39284c, 0x1a7e519d, 0xbcd9}}}, + /* 11*16^35*G: */ + {{{0x00c708c8, 0x02fcc95b, 0x370a86aa, 0x0d0c13cb, 0x3e288c2c, 0x38d97647, 0x205736df, 0x059b8170, 0xe1f0}}, + {{0x3896ed38, 0x1c635cec, 0x3b5a00ae, 0x1957c8bb, 0x233016fb, 0x118cafa2, 0x03b52044, 0x194fa45b, 0xe647}}}, + /* 13*16^35*G: */ + {{{0x076edefb, 0x383c2729, 0x00e7d5d7, 0x162f6004, 0x39c7badd, 0x086ad0a5, 0x2345c7f1, 0x25a1eafd, 0x2808}}, + {{0x1d1b0ae0, 0x3bd15c8a, 0x20392122, 0x34c6c1ef, 0x0541c44d, 0x3867af64, 0x33191a67, 0x073ccf4e, 0x5d07}}}, + /* 15*16^35*G: */ + {{{0x3344897a, 0x04b666f3, 0x24c269dd, 0x27b4c1d6, 0x25edab7b, 0x217a1490, 0x104cb705, 0x2c378a06, 0xeb15}}, + {{0x25bfe7ee, 0x3677a0f3, 0x17d0b82a, 0x11a62cbe, 0x332f8581, 0x22abe335, 0x26071089, 0x3745a709, 0x096c}}} + }, + { + /* 1*16^36*G: */ + {{{0x123b716d, 0x09beb701, 0x34e1a6b8, 0x08e259bd, 0x18df9e0d, 0x171e4e34, 0x0a534e8a, 0x16f8e2e3, 0xf81f}}, + {{0x12632401, 0x19000bd4, 0x28783304, 0x01d6140e, 0x0e032866, 0x1b4a74e0, 0x306df1d5, 0x124ca707, 0xdc7f}}}, + /* 3*16^36*G: */ + {{{0x39d19d8a, 0x1315a140, 0x1a552158, 0x1049e254, 0x2d490a3b, 0x1bb0d705, 0x286385af, 0x21143ec4, 0xa600}}, + {{0x190d2c4f, 0x36576ecd, 0x326573df, 0x3f8023e9, 0x29ca84f0, 0x1b5179ef, 0x37c72c8f, 0x1e7019e8, 0x7b4b}}}, + /* 5*16^36*G: */ + {{{0x096cac9f, 0x1a61ece5, 0x044de722, 0x38e33a97, 0x2b0e1c59, 0x3025e63f, 0x1f354c64, 0x20ac659f, 0xde53}}, + {{0x2fa473d3, 0x33820bf6, 0x3d841157, 0x38f8a51c, 0x0f9f2bc2, 0x0ec02647, 0x0918562c, 0x2d9e2da7, 0x9c47}}}, + /* 7*16^36*G: */ + {{{0x06807a23, 0x32ca58de, 0x225ff3e7, 0x0008145a, 0x194ec840, 0x12e67544, 0x2a908534, 0x1ec201fc, 0xa722}}, + {{0x14115894, 0x311c660f, 0x328cdc91, 0x2fe055ed, 0x2075abe7, 0x2a11e482, 0x139e845d, 0x1d497517, 0xf550}}}, + /* 9*16^36*G: */ + {{{0x044d14c0, 0x29e5ff08, 0x1a8f35e5, 0x172ad7e8, 0x261d3900, 0x2af9ce8d, 0x04596465, 0x0ba3508d, 0xcd2b}}, + {{0x22496315, 0x1582b3c8, 0x1accecea, 0x36dbc32e, 0x00f671fd, 0x017bb76b, 0x070a24d5, 0x04b7e6c2, 0xf130}}}, + /* 11*16^36*G: */ + {{{0x399a1566, 0x1bd3ac48, 0x3228f696, 0x171956bf, 0x1f9dd8f2, 0x3ef26e0f, 0x1f7eb4ce, 0x3a1323c3, 0x11b2}}, + {{0x1c56bb73, 0x2692cf01, 0x0d809685, 0x12d56103, 0x3405cc82, 0x0b5a61e5, 0x23175d04, 0x1da76f28, 0x6103}}}, + /* 13*16^36*G: */ + {{{0x1ba6f34a, 0x3427aca3, 0x245c6f87, 0x0a1a83f8, 0x19148531, 0x36828fbe, 0x3a070759, 0x064a57ca, 0xfb6d}}, + {{0x2bcf0452, 0x2d7cf208, 0x1685b1f9, 0x3f3e8b72, 0x2791b9ec, 0x223f5312, 0x346dd9e3, 0x0b4a75ef, 0xf29b}}}, + /* 15*16^36*G: */ + {{{0x0a435427, 0x1328b4a8, 0x3e4db507, 0x24042609, 0x106651a6, 0x3d9d9436, 0x013c10aa, 0x27f3040f, 0xff42}}, + {{0x39853824, 0x39411434, 0x23a0da28, 0x16fb94d2, 0x18687620, 0x10272158, 0x2cdb094d, 0x3e59a293, 0x2add}}} + }, + { + /* 1*16^37*G: */ + {{{0x07354b7a, 0x3b671f9e, 0x3915c978, 0x0bb295b0, 0x3cde1d02, 0x1fd18f94, 0x20848239, 0x151d35df, 0x8568}}, + {{0x116e04c6, 0x255100af, 0x3d6fdbd8, 0x2a247707, 0x2f728706, 0x3244eca9, 0x187b6eeb, 0x03ad42fd, 0x20b5}}}, + /* 3*16^37*G: */ + {{{0x3b26165d, 0x3db31fe9, 0x277137ea, 0x04e8857d, 0x0c92dea7, 0x274824bf, 0x23e6549e, 0x1131d4ac, 0x6173}}, + {{0x06b2a286, 0x126ff72e, 0x37171a4c, 0x266b05b8, 0x0220b298, 0x1f442f46, 0x3835a49b, 0x0585e90d, 0xe990}}}, + /* 5*16^37*G: */ + {{{0x10442770, 0x086fdd99, 0x101bad10, 0x063de9b8, 0x00fc2e90, 0x13076a79, 0x36a22da0, 0x00fb957e, 0xf8ac}}, + {{0x1b00c82d, 0x28a193c4, 0x1041d023, 0x1d80afe5, 0x0e6d17a9, 0x1b1d46cd, 0x11e8ea43, 0x23995667, 0x5a35}}}, + /* 7*16^37*G: */ + {{{0x365460de, 0x2f81b61b, 0x2bf77b8f, 0x1cfe342a, 0x0c8ea60c, 0x32f2f8c3, 0x095c66c6, 0x07ed496f, 0x8a73}}, + {{0x3f8dc207, 0x26166877, 0x2508ee3e, 0x219f8f14, 0x304dc435, 0x0a552ffe, 0x363198f5, 0x157178aa, 0x5858}}}, + /* 9*16^37*G: */ + {{{0x351634a5, 0x10aaeb7e, 0x1ed524e6, 0x3e429e0d, 0x17967f3c, 0x29ae80b3, 0x0f224bf0, 0x18184caa, 0xa20b}}, + {{0x3226afad, 0x1b04de57, 0x0d45edf2, 0x1d1d5f8f, 0x3b315bc6, 0x357fa0dc, 0x1b99dad3, 0x33a7da5f, 0x9c43}}}, + /* 11*16^37*G: */ + {{{0x33ba54a8, 0x010c8912, 0x03aa9707, 0x22c98d58, 0x05cc0ab5, 0x0e3b0d3f, 0x16709914, 0x07e4fc49, 0x016f}}, + {{0x264f2889, 0x35f187e9, 0x2a3b4e6e, 0x0ebc9d51, 0x1ce658d9, 0x26c46f92, 0x151576f2, 0x34d04562, 0x08bc}}}, + /* 13*16^37*G: */ + {{{0x27c16d94, 0x3bb924f3, 0x02845fdd, 0x160742a8, 0x0ec31fe2, 0x23f59f33, 0x034788c0, 0x2199c2f4, 0xe615}}, + {{0x314810ab, 0x2d3b466a, 0x3a443bbf, 0x19734791, 0x36f0ee4e, 0x2cae4fd2, 0x124be8c5, 0x00eba79c, 0x65ca}}}, + /* 15*16^37*G: */ + {{{0x13ce728d, 0x35b72999, 0x071cd0bc, 0x33641f8a, 0x085347f4, 0x2822885b, 0x16a26555, 0x1fc2ce35, 0xdcd3}}, + {{0x17cacbcb, 0x35f44da6, 0x29dabeb8, 0x2b34d1b4, 0x06d6f3ca, 0x0ded8acf, 0x24c1872c, 0x36f5df36, 0x6574}}} + }, + { + /* 1*16^38*G: */ + {{{0x12378c16, 0x371b706c, 0x215622ad, 0x0d81d551, 0x39597d9e, 0x2794b5af, 0x33b11b31, 0x2dd6704a, 0x1136}}, + {{0x33488127, 0x27d66f42, 0x351cce37, 0x052a8a39, 0x29ecb296, 0x02af183f, 0x28fdd09f, 0x03f3d145, 0x7dec}}}, + /* 3*16^38*G: */ + {{{0x3b299740, 0x1c39b609, 0x13db1349, 0x03d19f5c, 0x3aad48f4, 0x2b44de4f, 0x14336cc4, 0x0fadc737, 0x5389}}, + {{0x3fff7509, 0x07a9bc6c, 0x1fde8cd5, 0x284cbbc8, 0x35dc8dd8, 0x0738a3a9, 0x1fbd8384, 0x229fa521, 0x2772}}}, + /* 5*16^38*G: */ + {{{0x338000fc, 0x02cf2559, 0x3f03bc13, 0x0789dc1e, 0x3ae5604e, 0x0ddaebc7, 0x0da2757e, 0x3a775d53, 0xdd64}}, + {{0x1df4ac12, 0x3ea87143, 0x11e48f8b, 0x117408ae, 0x0a79ffbe, 0x2278f867, 0x132c96df, 0x24fac30a, 0x4321}}}, + /* 7*16^38*G: */ + {{{0x33878c4a, 0x3e08545c, 0x151c055e, 0x20f40f21, 0x291b21d8, 0x1a718392, 0x3d516f2c, 0x116a1fbf, 0xff98}}, + {{0x3488df68, 0x2e9a11f5, 0x25cfebc6, 0x3ccdd1ad, 0x35e8ddf1, 0x22923b7f, 0x2428f8fd, 0x26bd2938, 0x835b}}}, + /* 9*16^38*G: */ + {{{0x00f51524, 0x32a6e205, 0x3af86fc8, 0x2bada856, 0x1293de5f, 0x19e8c211, 0x1609ce87, 0x04fa2ee4, 0x954e}}, + {{0x05e30a69, 0x27f6cf65, 0x01e7cbde, 0x3ba90c45, 0x1ecbcfa9, 0x31890d1e, 0x24041d93, 0x0d8ffe4a, 0xecc8}}}, + /* 11*16^38*G: */ + {{{0x04f77287, 0x3de6354f, 0x130d9e31, 0x0a54f0da, 0x18049741, 0x35431707, 0x1fb93dfc, 0x1fbdbe90, 0xb221}}, + {{0x24e7b5da, 0x1e8129dc, 0x05e93cb9, 0x02771ce7, 0x38c843d7, 0x3ef3e234, 0x0f3a2b5d, 0x14f8339f, 0xfb51}}}, + /* 13*16^38*G: */ + {{{0x05c723e9, 0x2bd4e5b2, 0x2a781718, 0x25ceeaa6, 0x1d5c351f, 0x31baba45, 0x1bdad122, 0x142c5ede, 0x3c39}}, + {{0x36834763, 0x38e1dd7d, 0x04906ae5, 0x076b2d5f, 0x06a8b0b0, 0x12edfa86, 0x110dbb49, 0x1cd88824, 0xb99b}}}, + /* 15*16^38*G: */ + {{{0x3c18abeb, 0x1c5f5b88, 0x325d62a3, 0x27734641, 0x3aa944d5, 0x3b4be112, 0x21cdad1d, 0x1e8b33e5, 0x803c}}, + {{0x229bfa78, 0x290e6fc3, 0x26721cd6, 0x1f110f0a, 0x0b4409ed, 0x2b3c5a71, 0x2e9286b1, 0x141029e5, 0x83fb}}} + }, + { + /* 1*16^39*G: */ + {{{0x143e832a, 0x31d8bbc6, 0x386df709, 0x3942ac05, 0x09f18e07, 0x15cea096, 0x2a51a90f, 0x3ca2e9f0, 0x0d2b}}, + {{0x1b20d37c, 0x2098ebc5, 0x05514464, 0x3b276e58, 0x34e7ed27, 0x1e842a52, 0x100ac708, 0x0fd0c4ef, 0x0cac}}}, + /* 3*16^39*G: */ + {{{0x112c9666, 0x07ab12f0, 0x1ffcdf36, 0x3e31b0d9, 0x19531b1c, 0x2f30d6df, 0x3f82cfd9, 0x3a17ae59, 0x34e5}}, + {{0x192a3666, 0x168614f2, 0x1e3a526b, 0x11fb58f0, 0x3c46330f, 0x1195d732, 0x1a36b828, 0x1a0c4c88, 0xc0ce}}}, + /* 5*16^39*G: */ + {{{0x11209502, 0x0594af8d, 0x1d92665c, 0x105c8009, 0x19e15459, 0x124fbc24, 0x0d863a6c, 0x18b3167d, 0x7273}}, + {{0x17042b0d, 0x19df474f, 0x32760bbc, 0x234dfe6e, 0x291d20a1, 0x002e30b3, 0x3ab589f1, 0x3d08a6ea, 0x17b0}}}, + /* 7*16^39*G: */ + {{{0x2447f959, 0x1579e4a2, 0x271d3684, 0x11f6aea0, 0x09eee9f9, 0x285312ed, 0x26cec973, 0x3c980152, 0xa0c3}}, + {{0x168b671f, 0x00e74922, 0x0d272c9b, 0x2d550096, 0x228208b1, 0x3e30432d, 0x32c4f382, 0x1cc24392, 0x508c}}}, + /* 9*16^39*G: */ + {{{0x1b37e1d3, 0x087e7c09, 0x0e4de230, 0x1d86f84f, 0x15fd0410, 0x2d0cef90, 0x1ca7a40c, 0x2c8c7de5, 0x7e81}}, + {{0x0155681a, 0x3d7f2899, 0x1c2e0e03, 0x3212fcac, 0x2c7c4e4e, 0x3a25b3b9, 0x3ed13125, 0x1686c3a6, 0xf385}}}, + /* 11*16^39*G: */ + {{{0x16c051a0, 0x125dc57d, 0x35b3e6dc, 0x37ca491b, 0x0f2abddc, 0x1b639b6c, 0x026d84a3, 0x38871f60, 0x8035}}, + {{0x32d0dd12, 0x007aecbe, 0x18b62356, 0x39f718c2, 0x3dd318b3, 0x36f9a0de, 0x22bef375, 0x042912de, 0x0b88}}}, + /* 13*16^39*G: */ + {{{0x3f12c69e, 0x38030c27, 0x1651963c, 0x396bbd62, 0x04fcecaf, 0x2bc00408, 0x0a53306b, 0x0237f586, 0x1969}}, + {{0x1d114831, 0x34cc6410, 0x3fb886b8, 0x2cb8cdc7, 0x21054eb6, 0x3877ab74, 0x16e040be, 0x2fdacbe4, 0x3f65}}}, + /* 15*16^39*G: */ + {{{0x0b89c5ed, 0x1263807f, 0x17a78c7e, 0x2d4c33de, 0x2d0f3577, 0x1b874842, 0x1a2af46e, 0x3f3ae258, 0xdb77}}, + {{0x2d25b46e, 0x27fc71fb, 0x0899afa5, 0x05b1eada, 0x19ad411f, 0x0ce6f932, 0x2e5ceecf, 0x370e1c73, 0x7fd1}}} + }, + { + /* 1*16^40*G: */ + {{{0x37f82f2a, 0x3ba71d77, 0x2fdf43aa, 0x130d61d2, 0x3713269e, 0x08b7d0dc, 0x33617f56, 0x17d59bb1, 0x8a53}}, + {{0x223094b7, 0x17e682b0, 0x08c7669c, 0x394ce193, 0x1a92bfcd, 0x00a06421, 0x08bd737e, 0x30211a2c, 0x0455}}}, + /* 3*16^40*G: */ + {{{0x2b348fa0, 0x2c53c85e, 0x11541ddf, 0x3f891641, 0x24b4bce0, 0x088c8db0, 0x3882dc2a, 0x324f777a, 0x86ea}}, + {{0x0da51cee, 0x3b8e0255, 0x1cfee8a4, 0x09b658d4, 0x2f46716c, 0x0dbe7a35, 0x04d8d5a4, 0x0e14f2ef, 0x948f}}}, + /* 5*16^40*G: */ + {{{0x19222c03, 0x2bd07ff2, 0x3e5e1037, 0x2339dfa1, 0x19f40794, 0x39f5e121, 0x33aae3f5, 0x27aebe7e, 0x8bf0}}, + {{0x2a72bb54, 0x0517dd0b, 0x220e1d4a, 0x27b03877, 0x25ba309c, 0x22c76f9f, 0x27a733b4, 0x2eabf8b8, 0x509c}}}, + /* 7*16^40*G: */ + {{{0x11ae9300, 0x114e8b07, 0x1c48280b, 0x0711c11d, 0x33735b5e, 0x0c2eb68b, 0x30fc6191, 0x0b72edf9, 0xe85e}}, + {{0x1546e25e, 0x0a837f74, 0x38c31bb7, 0x2df86177, 0x3c2707de, 0x29ed6e08, 0x0e0bfc7b, 0x2be9b547, 0x451a}}}, + /* 9*16^40*G: */ + {{{0x05260cb8, 0x14975558, 0x2b2152f2, 0x1bd2a033, 0x27dbf683, 0x009f686e, 0x12f82a3f, 0x2c3c8a32, 0x3f5f}}, + {{0x1852c964, 0x0bed2d10, 0x05ec3327, 0x0fa1d47f, 0x2783f2fa, 0x237854d9, 0x199870e3, 0x0d36b692, 0xc558}}}, + /* 11*16^40*G: */ + {{{0x1a1cd60f, 0x2a91110b, 0x03092ea4, 0x25a62a73, 0x1a002b9f, 0x3b41d2d3, 0x1999657a, 0x1588ac63, 0x3368}}, + {{0x0fd57d67, 0x2fdcdd94, 0x050b8b24, 0x3bd6932f, 0x27af175f, 0x1630037a, 0x07cd9ba8, 0x1427bc49, 0xd42f}}}, + /* 13*16^40*G: */ + {{{0x37576342, 0x014edbae, 0x199222af, 0x0b2220ce, 0x0979d95b, 0x03e76258, 0x00080f7d, 0x3ad7023c, 0x4813}}, + {{0x17376316, 0x130557ae, 0x06a904f6, 0x0b719f54, 0x33524aca, 0x005a1238, 0x24240f66, 0x0ff508ce, 0x0004}}}, + /* 15*16^40*G: */ + {{{0x3f69b2be, 0x3d9c5c77, 0x01111c09, 0x107dd3b7, 0x386e56ba, 0x08b6eeb8, 0x2997af13, 0x3c7e696b, 0x80c3}}, + {{0x0102d2f5, 0x2412e5f1, 0x0b7a8bf8, 0x12dd2cd7, 0x1d5a9bf1, 0x0389d96c, 0x1de85298, 0x08502802, 0x0a93}}} + }, + { + /* 1*16^41*G: */ + {{{0x2476c81d, 0x320dfd3f, 0x1e53d5e9, 0x28c0c3a6, 0x28a366b7, 0x1f349cf6, 0x01a019af, 0x2437f72d, 0xad60}}, + {{0x2e6705dd, 0x062af213, 0x33048df8, 0x0ff70d93, 0x1bd8a839, 0x35d70b31, 0x0c91eacc, 0x3477523d, 0x77b5}}}, + /* 3*16^41*G: */ + {{{0x22725490, 0x2891cdf3, 0x3cb59900, 0x30c90188, 0x09863c4a, 0x36a94cec, 0x1697ca2a, 0x116edc6b, 0xd90b}}, + {{0x2feb1299, 0x03e13e12, 0x3c466ccb, 0x3701effc, 0x38cbd80c, 0x22d5a1cd, 0x3350f09d, 0x24a3b06e, 0x3326}}}, + /* 5*16^41*G: */ + {{{0x3e933668, 0x1dace995, 0x06babf0a, 0x00b6133e, 0x1f06befb, 0x14e4ebe8, 0x13fc7ac0, 0x2485cc48, 0xac25}}, + {{0x32776fb5, 0x1b9dfd9c, 0x29e1e7a1, 0x21906271, 0x18ed7c6f, 0x3b04fbaf, 0x3a8ba850, 0x280e1c36, 0x6c79}}}, + /* 7*16^41*G: */ + {{{0x128de7e3, 0x2985f048, 0x3ea996d9, 0x210ab0ea, 0x3431bf86, 0x083ef69e, 0x1f3a8873, 0x0dd2ba5e, 0x7bc3}}, + {{0x2e6e5e29, 0x1e82ccba, 0x0c0ccf06, 0x3cb6ce6d, 0x0bacbd55, 0x31deb9b9, 0x14e5de00, 0x3c091821, 0xb431}}}, + /* 9*16^41*G: */ + {{{0x035e057d, 0x2b2c8c8e, 0x2d89a5b4, 0x33c436bd, 0x01119329, 0x321cbf0d, 0x202b268b, 0x052514eb, 0xbf9c}}, + {{0x2da20fea, 0x3d592ca0, 0x05c479b6, 0x02e78607, 0x07a54244, 0x14c4fc17, 0x23be0f38, 0x2e27c97c, 0x92ac}}}, + /* 11*16^41*G: */ + {{{0x021d6584, 0x0ab35f08, 0x3b3d9e5d, 0x1c175910, 0x1f014ef2, 0x25f68d6b, 0x04f8a96e, 0x020e6d5e, 0x55bf}}, + {{0x0ed744ea, 0x35593d0a, 0x2e5a5a80, 0x2785080a, 0x3c7dcf08, 0x32fdaea2, 0x21ccf27a, 0x01ccf92d, 0x3d98}}}, + /* 13*16^41*G: */ + {{{0x01068c5e, 0x35a77db9, 0x3e573d0d, 0x117b9b92, 0x15d4872a, 0x2b8539e0, 0x38d519f2, 0x138594cd, 0xfcf2}}, + {{0x27c19d75, 0x187d14fc, 0x014855b7, 0x05da92ca, 0x12e7aee9, 0x1d7886d6, 0x3ffe35c6, 0x2c394cdb, 0x186b}}}, + /* 15*16^41*G: */ + {{{0x220da860, 0x2df657c1, 0x049d1008, 0x0d146a92, 0x191f2f84, 0x36d94d0f, 0x167eca1f, 0x20340bd4, 0x7bc2}}, + {{0x07aac76d, 0x38a44104, 0x0c1632eb, 0x38668bf7, 0x1ee6e0f2, 0x09afe9c1, 0x131e5e26, 0x1b5deeef, 0xb33f}}} + }, + { + /* 1*16^42*G: */ + {{{0x13c4a205, 0x14bcb0da, 0x110a848a, 0x06b7e27d, 0x3929fcde, 0x1955c1d6, 0x1bbc4e46, 0x1b1458c1, 0xb6e0}}, + {{0x1db36d05, 0x0dfd3619, 0x02a9f875, 0x3e65066a, 0x1ed73b63, 0x07c49b9e, 0x323f5c5e, 0x09df086c, 0xbdb4}}}, + /* 3*16^42*G: */ + {{{0x39e27907, 0x0be087db, 0x0d9e4d69, 0x06b52ce2, 0x1fbd6877, 0x257575bf, 0x01c4e6b3, 0x390fe109, 0x0ed9}}, + {{0x2e78c4fb, 0x04fd3d41, 0x0ba1905f, 0x05473fae, 0x120e0ce9, 0x303f63ac, 0x32347f5b, 0x21d2bfda, 0xb5af}}}, + /* 5*16^42*G: */ + {{{0x35b38f54, 0x1b415c94, 0x0af07ce3, 0x0aa18397, 0x3ee1f92e, 0x09a36d23, 0x18f7dc55, 0x390401db, 0x57a7}}, + {{0x245f2809, 0x3e9e0798, 0x107eba75, 0x35db8e6a, 0x02dd21df, 0x32288ef2, 0x0ad24194, 0x03c0f23b, 0xfd7f}}}, + /* 7*16^42*G: */ + {{{0x27a79593, 0x1bfaefe6, 0x25c49794, 0x1e9c9274, 0x0a5cf334, 0x366c9633, 0x35dbef52, 0x26b8bcfb, 0x2479}}, + {{0x10920d55, 0x18e235d7, 0x3eb1398d, 0x250d87e6, 0x23e30099, 0x0f46a74d, 0x07b7b32c, 0x2d498bb2, 0x9436}}}, + /* 9*16^42*G: */ + {{{0x0bf5abdc, 0x0085bad4, 0x10b65066, 0x1b34ebef, 0x0d5d6045, 0x04472c20, 0x07026ed3, 0x05f1a213, 0xf150}}, + {{0x2def85b7, 0x1d778ae2, 0x3b85584b, 0x3719d709, 0x05e232cb, 0x20d078ff, 0x302a8ecd, 0x3bc70b17, 0xdea7}}}, + /* 11*16^42*G: */ + {{{0x3e78e9b1, 0x27c94ac7, 0x2c141e86, 0x1e39b713, 0x12dfcc89, 0x3e0c7dd4, 0x0beaa6e0, 0x3883e26d, 0xe196}}, + {{0x0a77eed7, 0x105d587f, 0x2ed35f44, 0x234044af, 0x32ed9a90, 0x1022f9da, 0x285a62a6, 0x1b617e06, 0xa5d6}}}, + /* 13*16^42*G: */ + {{{0x3b1cb64b, 0x1bb8cf95, 0x18ac3d57, 0x02794958, 0x39ed14d6, 0x1ff35c54, 0x30302f39, 0x3d779b06, 0x7779}}, + {{0x3aba3aab, 0x23863472, 0x0aa9533d, 0x2a0a508f, 0x22e3fae2, 0x2ac4d29e, 0x03ebeadf, 0x108fd1d3, 0x09a8}}}, + /* 15*16^42*G: */ + {{{0x11d1b492, 0x3b6161da, 0x019a6f53, 0x28186308, 0x328ce8df, 0x3db66aba, 0x3a2f11e5, 0x2e52f908, 0x8605}}, + {{0x38ac6598, 0x1c75defd, 0x01e925c5, 0x08d49b52, 0x03d1a8ee, 0x3db83085, 0x35758f3e, 0x184a1f79, 0xa8e5}}} + }, + { + /* 1*16^43*G: */ + {{{0x29aa52df, 0x3357d392, 0x02a627f3, 0x3114ac6d, 0x11ece618, 0x31062766, 0x08bf76db, 0x04725fd8, 0x45a5}}, + {{0x125ec16c, 0x2d4af448, 0x22955ce7, 0x2466c9f4, 0x225ad25a, 0x0ccdff2d, 0x29b6d3fe, 0x03b1dcfa, 0x73be}}}, + /* 3*16^43*G: */ + {{{0x2e75bc7f, 0x159d4fbe, 0x2f7fb1f6, 0x31c5c36d, 0x0d4c7b95, 0x103c485f, 0x393438ef, 0x2b13f9ca, 0x0b57}}, + {{0x0972e9a9, 0x13c5cb74, 0x049fc620, 0x3e5b0390, 0x3e94fab1, 0x30d33e95, 0x1f3b5f28, 0x2fe09dea, 0xceed}}}, + /* 5*16^43*G: */ + {{{0x033125ff, 0x0dd0cf3e, 0x25a81421, 0x1155ec16, 0x1cae9935, 0x1a0b6728, 0x3d148cf4, 0x2cfedb92, 0x1178}}, + {{0x18486abd, 0x203e5c27, 0x0e54d1be, 0x322b7342, 0x310ed10d, 0x3798dfa8, 0x3d95b382, 0x25faa6ea, 0xdfd6}}}, + /* 7*16^43*G: */ + {{{0x3662d955, 0x2cda5733, 0x08ce44f3, 0x1135a16d, 0x27569384, 0x20edfa34, 0x0e907f8a, 0x28209be5, 0x8ac7}}, + {{0x246b3dae, 0x31a8b6f9, 0x16c138db, 0x3d20716f, 0x359ad9e3, 0x1f948d32, 0x3231cc9d, 0x102483cc, 0xc80f}}}, + /* 9*16^43*G: */ + {{{0x288803e5, 0x3361e6b7, 0x13465cb7, 0x06adf383, 0x169e02cc, 0x1fea1c01, 0x1f2111ab, 0x22ca1677, 0xc0f4}}, + {{0x076619ee, 0x1a4c880a, 0x3828edba, 0x0b9381c2, 0x20d7d393, 0x2991c9f9, 0x3ca369c9, 0x09adbe20, 0x3d43}}}, + /* 11*16^43*G: */ + {{{0x1e1f515c, 0x25b59c26, 0x16539afa, 0x2d228c88, 0x37b8c0e2, 0x2723843f, 0x1766da01, 0x1c03c0d4, 0x2ce8}}, + {{0x052eed6e, 0x1464d926, 0x2c3d52c9, 0x2a7734f8, 0x2f5d2ca7, 0x2cbd0bdf, 0x2c4a7bac, 0x27d3ced7, 0x7387}}}, + /* 13*16^43*G: */ + {{{0x24dcf274, 0x16a8ddd7, 0x0acea244, 0x1c801a0b, 0x3cca1d80, 0x386ec3f5, 0x3c109145, 0x1098772d, 0xfac4}}, + {{0x312f0472, 0x0da61803, 0x34594b16, 0x0809f189, 0x2e97bd73, 0x1c8f5753, 0x2a8a87cc, 0x3f718559, 0x9713}}}, + /* 15*16^43*G: */ + {{{0x3dc39d21, 0x2d792daa, 0x09adc682, 0x0dcfaf50, 0x19281368, 0x24790e86, 0x03e00465, 0x398596d0, 0xf891}}, + {{0x05ca579f, 0x1642385f, 0x1460254d, 0x2a5fb13d, 0x1bc43b73, 0x3ae2a38b, 0x1fced18a, 0x14ec4aef, 0x129f}}} + }, + { + /* 1*16^44*G: */ + {{{0x1076f57b, 0x233c6ae6, 0x2cac6072, 0x02e1b8f3, 0x32a53f03, 0x1f8d4073, 0x0c79cb92, 0x06159220, 0x20e1}}, + {{0x2da7afe6, 0x160efb6e, 0x0e1b71e8, 0x383726d0, 0x2de9979f, 0x370f8fed, 0x37ef731b, 0x2cd4ab10, 0xff67}}}, + /* 3*16^44*G: */ + {{{0x0b661da4, 0x1278ebb5, 0x0a84a5c8, 0x02946b19, 0x061a2194, 0x31ff640c, 0x206ce8f7, 0x0a96ee19, 0xffca}}, + {{0x2f9b8a5a, 0x26120d7a, 0x1687f6f8, 0x23e1eb79, 0x346c8c47, 0x33268523, 0x1cdc8a53, 0x2c38cadc, 0xce1c}}}, + /* 5*16^44*G: */ + {{{0x1c8cfd22, 0x32b0784e, 0x236be583, 0x0ac19c6d, 0x2d354a4e, 0x14d45436, 0x116ab636, 0x273b7ff0, 0xff20}}, + {{0x13bc5535, 0x0e26c53a, 0x1684b942, 0x13d2e4b2, 0x0ff1c80d, 0x35074933, 0x10f7e207, 0x3ce5d1a7, 0xad79}}}, + /* 7*16^44*G: */ + {{{0x0f4e983e, 0x201f9616, 0x017f77ce, 0x279bb21c, 0x3b4b156d, 0x0102034c, 0x39ba9586, 0x3c0b42c1, 0x33d5}}, + {{0x11ea37a9, 0x35c36e1e, 0x1630c956, 0x1c6aa496, 0x3ba1eb7a, 0x0f585956, 0x0478473c, 0x169db4e7, 0x01eb}}}, + /* 9*16^44*G: */ + {{{0x21e52a73, 0x1a569e7d, 0x305a1bcb, 0x38c45b25, 0x3b5e65d0, 0x25d366b6, 0x21690a9e, 0x348f6989, 0x8f1b}}, + {{0x2bea8f2e, 0x1f685147, 0x31850a85, 0x0140b992, 0x03eade59, 0x1a790c1d, 0x1a8b8b87, 0x23d8e4eb, 0x4c7a}}}, + /* 11*16^44*G: */ + {{{0x3d2bc078, 0x210bfb0b, 0x1f3ef5a5, 0x281d814a, 0x1880aec4, 0x0a62df6b, 0x237f3ee6, 0x327fbded, 0x963b}}, + {{0x1afb8657, 0x376c8c7d, 0x043a3c27, 0x3b010a3d, 0x00a4f1c5, 0x0f9424a6, 0x2762280a, 0x0e0ff347, 0x7ed3}}}, + /* 13*16^44*G: */ + {{{0x2fb608ad, 0x21c79dba, 0x08fd93a6, 0x20159536, 0x08bc4974, 0x06b772df, 0x1a844e63, 0x1b6b6187, 0x89fe}}, + {{0x064d4dad, 0x00501b9e, 0x0f0a87b6, 0x2a7544f8, 0x25df39ae, 0x15f7fedc, 0x0e8fc87b, 0x09e08c7d, 0x2898}}}, + /* 15*16^44*G: */ + {{{0x19ae4a29, 0x1c62606c, 0x2232a0b0, 0x0bf69ba8, 0x166984df, 0x35eb1384, 0x39759510, 0x011fcef5, 0xc348}}, + {{0x0eb09235, 0x12566b13, 0x149aebf3, 0x08ba67c1, 0x0dae9a84, 0x2a374838, 0x21c5613d, 0x207c815a, 0x5847}}} + }, + { + /* 1*16^45*G: */ + {{{0x19273a8f, 0x34514ba2, 0x14fd54ad, 0x3751e39a, 0x17dac93f, 0x23b1ff7f, 0x2027b031, 0x313e1c8e, 0x5c9c}}, + {{0x1ce80d6e, 0x376b29a5, 0x11acab5a, 0x000d9d68, 0x08af964f, 0x1d6274dc, 0x2d259a82, 0x381e877f, 0x84ef}}}, + /* 3*16^45*G: */ + {{{0x0883e382, 0x32326151, 0x15536f38, 0x1813f3bd, 0x007431d0, 0x0900e548, 0x3d85c5be, 0x3864aef7, 0x5ac8}}, + {{0x1dfeaadc, 0x04dcf66f, 0x14d9d2e5, 0x1dbb284f, 0x163976de, 0x23ffcbc2, 0x28c8039c, 0x3940131e, 0xfcb7}}}, + /* 5*16^45*G: */ + {{{0x2f01a3e8, 0x3290c1df, 0x248094eb, 0x3ad950cb, 0x167362c6, 0x05751383, 0x121182d5, 0x01a62de4, 0x99dc}}, + {{0x00f61114, 0x0a1917f9, 0x3f8f2945, 0x299c0d35, 0x180044b7, 0x2b1c45c7, 0x182bc697, 0x273748ee, 0x67c6}}}, + /* 7*16^45*G: */ + {{{0x0cd535ab, 0x20fdec01, 0x0764dc33, 0x093620fa, 0x0fb9f377, 0x090d5f3f, 0x00616440, 0x3cd86381, 0xabe2}}, + {{0x117b9c1a, 0x01c46cd1, 0x3ac8dd99, 0x379e8630, 0x2df7957f, 0x36fcac80, 0x1b293de0, 0x35932dd5, 0x4f02}}}, + /* 9*16^45*G: */ + {{{0x2909970c, 0x2d2d9acd, 0x1e6e4e0d, 0x0636e966, 0x26099e45, 0x1bec7ddf, 0x1e72137c, 0x3435e30e, 0x227c}}, + {{0x1f809727, 0x21692b8c, 0x2b99ec42, 0x043b0fdf, 0x3f5defa2, 0x1b21d073, 0x1391d87d, 0x39dc7206, 0x2225}}}, + /* 11*16^45*G: */ + {{{0x09e65b59, 0x366b7f26, 0x144ff77c, 0x10408bdf, 0x0d053b7a, 0x3ba4c2a3, 0x1c5b6827, 0x11a082bb, 0x3631}}, + {{0x29b4c2cf, 0x20285909, 0x1c5b6e9c, 0x10f240ed, 0x227fc1c1, 0x09e3e480, 0x172928e8, 0x36d885e2, 0x1d87}}}, + /* 13*16^45*G: */ + {{{0x0d4c2506, 0x05ec562f, 0x19e9faf0, 0x1b1771fc, 0x1d1fec5b, 0x29a33862, 0x318a3e74, 0x35ad9a1a, 0xf65e}}, + {{0x3913dfac, 0x314b7094, 0x0d6542bc, 0x0a3bf0d3, 0x36e7bd41, 0x1770bf4d, 0x3aae8525, 0x2f1a0ca2, 0xd6d0}}}, + /* 15*16^45*G: */ + {{{0x3b47a80b, 0x0793e5d4, 0x02497578, 0x25f16999, 0x2bdba8ff, 0x36709dbe, 0x2135729d, 0x37be847d, 0x66a0}}, + {{0x3f795e8b, 0x3dc657e3, 0x26edd200, 0x0c290a14, 0x2ef474c2, 0x237c9586, 0x2ca41cad, 0x2a9b78de, 0x3e24}}} + }, + { + /* 1*16^46*G: */ + {{{0x28523eb3, 0x1f766acc, 0x16c6c4ae, 0x068e9d55, 0x3dcde335, 0x3061113c, 0x0b5ab46a, 0x353afe2a, 0xbaff}}, + {{0x15acf387, 0x25e0c033, 0x348b6ee1, 0x144733ef, 0x1ac09c24, 0x2a3acde5, 0x15e83003, 0x0f7176f2, 0x0fa9}}}, + /* 3*16^46*G: */ + {{{0x34737641, 0x00266d3b, 0x2c2e13ad, 0x3eb03059, 0x163fb71a, 0x22d448d9, 0x089ed777, 0x11489107, 0x91b4}}, + {{0x2101bbe0, 0x0944aca7, 0x2077d03f, 0x35f7199b, 0x2fb428c9, 0x0c8d6ac0, 0x1a9762c1, 0x18ef4dff, 0x3f44}}}, + /* 5*16^46*G: */ + {{{0x26dd01df, 0x1a8aeae0, 0x38fefb9c, 0x0fbfdd94, 0x28916574, 0x3a9b1f21, 0x1b07aa37, 0x04d77a0b, 0x296d}}, + {{0x2a3a0dc8, 0x25434c82, 0x1e66f604, 0x3ebd8639, 0x0777cadf, 0x1c4a5ddb, 0x145e42b8, 0x13b764b8, 0x1405}}}, + /* 7*16^46*G: */ + {{{0x1650f5dd, 0x19f9bc1b, 0x191b2c8c, 0x3ff84908, 0x1e4a9654, 0x0f0bc7c6, 0x27a318f1, 0x10bce44d, 0x4b09}}, + {{0x3aeddc6d, 0x0ba96f31, 0x0e73a62c, 0x0f19e0b9, 0x13c25f02, 0x17040558, 0x0abc0e05, 0x2aa98d9b, 0x7432}}}, + /* 9*16^46*G: */ + {{{0x04e4a96f, 0x28dd7a3c, 0x1655b147, 0x2218ad0d, 0x12e4af18, 0x3b6e3f13, 0x0c11a833, 0x1de98bfb, 0x0363}}, + {{0x11e08cdb, 0x2ebedf81, 0x30913268, 0x02630850, 0x14626384, 0x0c3155e1, 0x3df838d9, 0x06474d53, 0xa1de}}}, + /* 11*16^46*G: */ + {{{0x279b5a59, 0x107f4f85, 0x269e62a1, 0x087a27ac, 0x183251c6, 0x2fb55c27, 0x1e162bcb, 0x06bdcc3d, 0xa104}}, + {{0x2c5514a3, 0x234ad008, 0x2ac66d9d, 0x0c1a4387, 0x3c2afbfb, 0x194361ce, 0x18b19422, 0x05daaa3d, 0xad42}}}, + /* 13*16^46*G: */ + {{{0x0ddd597b, 0x2ba36c1b, 0x085758de, 0x224c5c33, 0x292007d8, 0x1c6b43e7, 0x25647033, 0x19eb42c7, 0xda21}}, + {{0x3de7fa04, 0x1a05c9f8, 0x04f9f462, 0x378a9485, 0x18ebf6cd, 0x19c03a9e, 0x2ed361ff, 0x24ad8951, 0xa219}}}, + /* 15*16^46*G: */ + {{{0x33f7dbb0, 0x24d2888a, 0x2bf29c09, 0x3b88f709, 0x24f29df4, 0x18ee1c85, 0x2c678bc8, 0x36f08dfd, 0x1c3f}}, + {{0x32e16d32, 0x1932f725, 0x020f8add, 0x01918e00, 0x0b18d41f, 0x3a94e529, 0x29813f0a, 0x03c40de4, 0x3926}}} + }, + { + /* 1*16^47*G: */ + {{{0x3a111101, 0x0d482362, 0x2db3c5f8, 0x27c2c69d, 0x3e4c9647, 0x0a8d3495, 0x2d766ed2, 0x0a8263f3, 0x06ad}}, + {{0x1fb37ef4, 0x069eea75, 0x30e89aec, 0x10a760ad, 0x2b62a0de, 0x13006ee7, 0x05e3559a, 0x22c7163e, 0x2d5b}}}, + /* 3*16^47*G: */ + {{{0x302bef6f, 0x1bf0e11d, 0x131ee437, 0x2b93c611, 0x18d475bb, 0x1e2f59af, 0x3cd7204f, 0x32955b0e, 0xf1a2}}, + {{0x0f6c1ca3, 0x06cb47f6, 0x3d52b401, 0x2d1faa07, 0x020168b0, 0x15505f70, 0x0313edf4, 0x166bc122, 0xb39b}}}, + /* 5*16^47*G: */ + {{{0x20455367, 0x0180a3f2, 0x0d613e08, 0x313cb209, 0x3f1851e6, 0x2405963a, 0x38030ee1, 0x2b527f8e, 0xe924}}, + {{0x28257e92, 0x3f4633e0, 0x3a6752b5, 0x368c6a93, 0x2fbb6f52, 0x0214e4f5, 0x03ed5752, 0x1f65e685, 0xfcc9}}}, + /* 7*16^47*G: */ + {{{0x02f8f1e7, 0x247c24e5, 0x1d1f9e2e, 0x352a9753, 0x3b22f68d, 0x2e4d4417, 0x3026fa00, 0x271f717d, 0xf49d}}, + {{0x114d9972, 0x088a2ac6, 0x24d7a839, 0x2c004f13, 0x14f67901, 0x174ecee6, 0x3acae6ae, 0x175080f8, 0xf558}}}, + /* 9*16^47*G: */ + {{{0x3b219a79, 0x2cea59df, 0x29827a77, 0x1335105f, 0x1189e65c, 0x0f0d55d5, 0x29d48b0e, 0x1340f91a, 0x28b0}}, + {{0x102dbe24, 0x22fdf364, 0x2004be5f, 0x059b33e1, 0x3e206b86, 0x3f95c860, 0x0cf1459c, 0x36a79685, 0xf658}}}, + /* 11*16^47*G: */ + {{{0x17774af9, 0x0a08b671, 0x1460ad8b, 0x05ae9944, 0x2aefb54c, 0x140e4a21, 0x1fe93d68, 0x19af9f30, 0x3f47}}, + {{0x1d4de990, 0x1f35fd93, 0x1b7326ff, 0x2a533f7e, 0x2e5f511c, 0x05e241b9, 0x31cba3ab, 0x0375a9cc, 0xcc81}}}, + /* 13*16^47*G: */ + {{{0x08e57705, 0x21067c79, 0x04d598e7, 0x33adfeb2, 0x2f361721, 0x2b6ad075, 0x0ee791f2, 0x2780b03e, 0xe324}}, + {{0x38caec0c, 0x252c67a0, 0x27384220, 0x065175c5, 0x086b5a50, 0x1de307c9, 0x29507dcb, 0x1961c04d, 0xa666}}}, + /* 15*16^47*G: */ + {{{0x325b93ac, 0x1e2f3abe, 0x187f8d2c, 0x38809441, 0x3bb4e917, 0x279da4f7, 0x3961cbdf, 0x1602f7ed, 0xa689}}, + {{0x2f589aab, 0x28f47135, 0x1c4fd3ae, 0x3c7e05f6, 0x059ff2fc, 0x3cbc057c, 0x0783eaa7, 0x32a52d3c, 0x4657}}} + }, + { + /* 1*16^48*G: */ + {{{0x313728be, 0x33c83fec, 0x3c6b94a6, 0x10e56468, 0x315fc596, 0x1bfe0d10, 0x09276273, 0x259de9e1, 0xa6d3}}, + {{0x0357f5f4, 0x0aeae0cf, 0x284059bf, 0x12a48308, 0x27ecdf82, 0x22eaf4b4, 0x3881666b, 0x211d26c2, 0x674f}}}, + /* 3*16^48*G: */ + {{{0x0f15d864, 0x0152d5a7, 0x1cc8d3cc, 0x01bf71a8, 0x26cf3524, 0x23b39ef8, 0x2db0dafc, 0x19b5f177, 0x07ef}}, + {{0x340907fe, 0x1189509d, 0x0ce4a8b5, 0x11c38ec7, 0x3d505e9f, 0x10314887, 0x1e6a506d, 0x0c976e27, 0x2db3}}}, + /* 5*16^48*G: */ + {{{0x17c7c05e, 0x1a5450f0, 0x0e5416ac, 0x20f2e54b, 0x328c0bb2, 0x0e9cbdd7, 0x1c46014f, 0x1397f01b, 0x82df}}, + {{0x18fff26b, 0x2584f40b, 0x02db300b, 0x057651a1, 0x17cbd1cf, 0x08588448, 0x2420a275, 0x22326325, 0xe4e1}}}, + /* 7*16^48*G: */ + {{{0x140368b0, 0x02b87505, 0x3ee949d8, 0x09308be3, 0x247a6213, 0x396e34e3, 0x30c6a7d9, 0x3f26f04a, 0x261e}}, + {{0x3deb011f, 0x0eb49566, 0x39b5d301, 0x0d02f878, 0x0fff797e, 0x2214b359, 0x2fce9fdc, 0x0ab6f8e1, 0x8a9d}}}, + /* 9*16^48*G: */ + {{{0x15eb8034, 0x040cfa54, 0x2e8ca4af, 0x02ccd7d5, 0x27692df3, 0x29f96767, 0x0279149a, 0x37f5de8b, 0x6d48}}, + {{0x1ab0ce30, 0x21cc21e9, 0x23e8961e, 0x00843a8a, 0x05476308, 0x39e59278, 0x1d12f3d5, 0x1c914597, 0x3cb4}}}, + /* 11*16^48*G: */ + {{{0x140535c8, 0x1450f7f1, 0x08db13eb, 0x3c2958c3, 0x054e6f65, 0x048fed3f, 0x18923a49, 0x30079eee, 0x93a5}}, + {{0x3d59b844, 0x1255d020, 0x35bedffc, 0x28588124, 0x15a5c166, 0x2a10d638, 0x0c2f4c16, 0x03a41260, 0x2d44}}}, + /* 13*16^48*G: */ + {{{0x1e2047ba, 0x0986959a, 0x3b0f652a, 0x11c1265a, 0x167031e5, 0x3683805f, 0x272bbb35, 0x2e4a4584, 0x3fb0}}, + {{0x1db24158, 0x1ffb353b, 0x17009d35, 0x1082b9dc, 0x266dc86c, 0x09887265, 0x3df94ca7, 0x1eb9a085, 0x9d46}}}, + /* 15*16^48*G: */ + {{{0x22df71c1, 0x02f6f6eb, 0x3bb723a0, 0x0c61afab, 0x33e4381c, 0x18eea778, 0x283d5d07, 0x250e7823, 0xdab0}}, + {{0x24c3a1e3, 0x21cd2104, 0x0b44e3bb, 0x258cc329, 0x120b3d6e, 0x2ba1bc83, 0x21cef385, 0x2f079513, 0x763c}}} + }, + { + /* 1*16^49*G: */ + {{{0x0514c6fd, 0x3bbd8bfd, 0x1ab013e6, 0x1a0ed343, 0x3f5936fd, 0x136d5c43, 0x0f4e033d, 0x36a00227, 0xac25}}, + {{0x05830541, 0x02d4e5dc, 0x03bf37a6, 0x0260fa09, 0x1b338c81, 0x36a4c4a8, 0x04c7b883, 0x2766172d, 0xebc6}}}, + /* 3*16^49*G: */ + {{{0x32fd0e3d, 0x065071f8, 0x027ad608, 0x0c793715, 0x165547e6, 0x1d219c78, 0x23c8bb4d, 0x399b126e, 0xeea7}}, + {{0x191d5868, 0x01047da3, 0x019e3cc1, 0x32eb688c, 0x1b7d985a, 0x10fc9efa, 0x09261288, 0x3516e7e2, 0x83fe}}}, + /* 5*16^49*G: */ + {{{0x2ccb63b3, 0x067c53c9, 0x0408e5d1, 0x37ff9b11, 0x03c67b7d, 0x0652cd50, 0x221bdbad, 0x38b4fa4f, 0x9a3d}}, + {{0x3df93fcf, 0x0714ca5d, 0x35822600, 0x300767fb, 0x013c4c49, 0x3c9cdbba, 0x112c8809, 0x26e41844, 0x2f80}}}, + /* 7*16^49*G: */ + {{{0x163f1117, 0x13b28d37, 0x27f6d8be, 0x225bdc2e, 0x3fadaf34, 0x0034c048, 0x392db051, 0x20bd2d4e, 0xa7c3}}, + {{0x1934cb9a, 0x04883178, 0x3c4a68cc, 0x13addbb4, 0x1dcfb5ae, 0x27ddddc1, 0x1bf88045, 0x394459d8, 0x1b91}}}, + /* 9*16^49*G: */ + {{{0x26774a96, 0x02f20716, 0x038e3e85, 0x08c7f646, 0x26f497e8, 0x10eff20e, 0x21213871, 0x2a663361, 0x555a}}, + {{0x06db0e34, 0x35025cb6, 0x0e26fa69, 0x035752f2, 0x10bbb89a, 0x11079c4d, 0x3bc6999d, 0x0a1a3481, 0xb053}}}, + /* 11*16^49*G: */ + {{{0x2f7dac7d, 0x0bdfbbce, 0x12412123, 0x15cae484, 0x37c36916, 0x335e3e35, 0x27ad7b58, 0x0bd6cd22, 0x01a4}}, + {{0x0195e46e, 0x1e2528c6, 0x0cea96b2, 0x0abca4ca, 0x3f921617, 0x1fe552e2, 0x07781349, 0x270e1548, 0x957a}}}, + /* 13*16^49*G: */ + {{{0x202afc36, 0x00ae8750, 0x03071d3e, 0x137bb545, 0x05d3a313, 0x2c27bc6d, 0x1ce3d3a5, 0x3d4dfac1, 0x4b47}}, + {{0x2f8133ff, 0x3a27dda9, 0x25fbda34, 0x16b2fa6c, 0x0df57334, 0x2c1be83a, 0x05f0c2dc, 0x1140e672, 0xf2fc}}}, + /* 15*16^49*G: */ + {{{0x37d17f68, 0x2afcb8f1, 0x38bad86a, 0x056877f2, 0x2e418f79, 0x145bd4da, 0x0e8ced56, 0x3b273149, 0x6b3d}}, + {{0x09232402, 0x3eb9e883, 0x2dccb68c, 0x3caa5aa9, 0x0d5d4747, 0x2606d05b, 0x3d9ef050, 0x0e4dff7b, 0xb865}}} + }, + { + /* 1*16^50*G: */ + {{{0x2fd20bae, 0x17538de8, 0x1b4a8115, 0x00d59cb5, 0x2d343a26, 0x2ee8485d, 0x0fcd9027, 0x143b70ef, 0x2852}}, + {{0x14e0ab97, 0x27791569, 0x1eff323f, 0x26c68b3c, 0x06c1716e, 0x0a12b441, 0x17ea83f7, 0x3021bd2b, 0x7866}}}, + /* 3*16^50*G: */ + {{{0x2636a50b, 0x3221daae, 0x3b75196c, 0x0bbd85aa, 0x38baf65d, 0x1be84bf1, 0x1a75c583, 0x31595175, 0xf1e3}}, + {{0x2b3128b6, 0x3dde453a, 0x22d7a6ed, 0x1fe95db4, 0x25f3136b, 0x0da99fda, 0x2fce76c7, 0x211e9b87, 0x12b8}}}, + /* 5*16^50*G: */ + {{{0x0e583340, 0x05fc4c85, 0x134f3b25, 0x1706dad7, 0x1b228cf4, 0x1f36afea, 0x134a76d8, 0x1ca72078, 0x584d}}, + {{0x34fb24b9, 0x0bdb97a5, 0x094c0707, 0x05dc2999, 0x30affa8f, 0x01f164c0, 0x180abcd3, 0x20291583, 0x2fdd}}}, + /* 7*16^50*G: */ + {{{0x0235809b, 0x0b20fb78, 0x1eb81739, 0x15cb7c2d, 0x383c453c, 0x380a3708, 0x3df7d1e2, 0x2b80320d, 0xbaae}}, + {{0x0154fd62, 0x35876297, 0x1d2e7e5c, 0x170f10a8, 0x09f29983, 0x08c1ef2d, 0x24b80b4a, 0x2220cfcc, 0x3257}}}, + /* 9*16^50*G: */ + {{{0x0d612268, 0x18010b10, 0x25ed016f, 0x33d677c2, 0x14b8b906, 0x0e7be90e, 0x2131a651, 0x3918d830, 0x06c7}}, + {{0x260166a0, 0x32d2d804, 0x02e7098b, 0x2362969e, 0x3453ca23, 0x3f1d738b, 0x1d8cd747, 0x35577dcb, 0xcb6a}}}, + /* 11*16^50*G: */ + {{{0x012fbdc8, 0x350e8d6e, 0x2c0e2a3b, 0x278832a8, 0x11a36db8, 0x0bb31edc, 0x2643e5bc, 0x0c77aaf5, 0x0641}}, + {{0x29f99380, 0x34ffcc26, 0x1fb020a5, 0x0eb89a2c, 0x15759860, 0x0e0364d2, 0x27028f2b, 0x1feb0cb5, 0x882c}}}, + /* 13*16^50*G: */ + {{{0x0bac9f32, 0x17ac0019, 0x1689b067, 0x0e087316, 0x1b640044, 0x1905bf86, 0x1c2378a1, 0x2deb309d, 0x366b}}, + {{0x3c85d47d, 0x0bc3973e, 0x3f0268a4, 0x37394301, 0x21cfc01f, 0x1e0eae35, 0x1af064f0, 0x1edc21e1, 0x7d10}}}, + /* 15*16^50*G: */ + {{{0x06dd27eb, 0x0f2d494a, 0x33b56230, 0x231570de, 0x3e32ecb9, 0x1f438e6e, 0x33c006b2, 0x36c95f31, 0xb767}}, + {{0x0f65dac4, 0x1548691f, 0x0600ed41, 0x2dc02d12, 0x19d85b64, 0x2b2e05ae, 0x229cb5ce, 0x0230c984, 0xdc13}}} + }, + { + /* 1*16^51*G: */ + {{{0x3e07e4f1, 0x1c7ce8a8, 0x0dc267c1, 0x31451f74, 0x38890e1f, 0x37af01fb, 0x0366f818, 0x30418bb4, 0xc472}}, + {{0x06b0daa9, 0x1c71a0f6, 0x22b5d8a5, 0x3cedec78, 0x1667d885, 0x0aad6a13, 0x370e9643, 0x03806517, 0x4182}}}, + /* 3*16^51*G: */ + {{{0x22f8acb1, 0x0da54d2a, 0x13f053f4, 0x27595518, 0x2cc31eb3, 0x06de92e3, 0x1e3d685e, 0x23ce6551, 0x86f8}}, + {{0x05098a19, 0x12c10b44, 0x11652711, 0x3a98afba, 0x11b1214e, 0x325e3ed6, 0x238d6b37, 0x375a69a0, 0x2ccf}}}, + /* 5*16^51*G: */ + {{{0x3cadab66, 0x220ddedb, 0x1d35602d, 0x31a8cf0f, 0x19f9a0e1, 0x1d9a5983, 0x08e747df, 0x2f87f265, 0xa2a3}}, + {{0x0c1aeb12, 0x3d284921, 0x080ad25e, 0x0b7a294d, 0x235ee1fb, 0x01fb5d34, 0x0be67065, 0x3639ad49, 0xa93b}}}, + /* 7*16^51*G: */ + {{{0x207c25bf, 0x2274884c, 0x22d8097b, 0x3ef1ddef, 0x0080be82, 0x384919df, 0x38db9367, 0x1f3b55b9, 0x354e}}, + {{0x1a864211, 0x048e8e65, 0x1a0aa215, 0x35d5b2c1, 0x0fe5585f, 0x2f609297, 0x14070e6e, 0x18ba6ee6, 0x629d}}}, + /* 9*16^51*G: */ + {{{0x35e1dad8, 0x29f60b81, 0x2c4bd2e4, 0x2029e161, 0x099f498b, 0x173dc830, 0x2805b79b, 0x326abd77, 0xc751}}, + {{0x2e4afc8b, 0x04dacd84, 0x20a8c02d, 0x3e25c28e, 0x09a4ffe6, 0x1307f5b7, 0x19de2beb, 0x190dff1e, 0xcb98}}}, + /* 11*16^51*G: */ + {{{0x099d9ba2, 0x0c486c84, 0x3aaa757d, 0x3d95f5a5, 0x0f9ca80c, 0x2d4a1ad4, 0x1d02178a, 0x33106e74, 0xaee9}}, + {{0x3ed2ad58, 0x2358120e, 0x217490e7, 0x0b9a389a, 0x06b1f531, 0x25efec03, 0x2a36f7be, 0x3cc0b6d4, 0xb72c}}}, + /* 13*16^51*G: */ + {{{0x094d208d, 0x0ffc2092, 0x3f391a46, 0x036a3fc3, 0x1ff0cefb, 0x3d82bcac, 0x12ec56bf, 0x0fd1a9e4, 0x0d0d}}, + {{0x1d45d1b1, 0x18bd4fde, 0x31ddabfd, 0x04f03469, 0x109ff0b2, 0x1d36997e, 0x37169b04, 0x06e02b87, 0xdc37}}}, + /* 15*16^51*G: */ + {{{0x19cfd890, 0x1ba08b20, 0x0071145c, 0x0db0dcdf, 0x1441e1cb, 0x3360e1f9, 0x37535f47, 0x051ad104, 0x778d}}, + {{0x16f057f2, 0x26a1fe9f, 0x2d20acac, 0x32915223, 0x06cd3796, 0x09c6365e, 0x11af72a5, 0x2e84cec0, 0x3c85}}} + }, + { + /* 1*16^52*G: */ + {{{0x039bb85f, 0x083c270e, 0x050e62c3, 0x007ec1a8, 0x15345801, 0x160b266b, 0x2432b557, 0x0e634599, 0x55d5}}, + {{0x0fed936f, 0x1fd8c461, 0x033d9e1f, 0x035a9fc6, 0x3aa72ad9, 0x31aa7a3a, 0x38e2d059, 0x08a4127f, 0x576e}}}, + /* 3*16^52*G: */ + {{{0x12ea285a, 0x01f8ae48, 0x3b910d1c, 0x007079bd, 0x00a7a39f, 0x20163777, 0x3888b785, 0x19022053, 0x1bb4}}, + {{0x107dc702, 0x303229e6, 0x12fa94ed, 0x14a8d2e6, 0x34a4fc1e, 0x3f66e24a, 0x21125a40, 0x05afebeb, 0x8a30}}}, + /* 5*16^52*G: */ + {{{0x1539785a, 0x1404a403, 0x0297f014, 0x22341dae, 0x227a548c, 0x1cf899e1, 0x3a14ee09, 0x139c380b, 0x04bc}}, + {{0x0a62e3bb, 0x0e6411d7, 0x23275c35, 0x1c05dc9e, 0x3dfb4f87, 0x16873cfc, 0x34cc3a5f, 0x3c892e32, 0x5729}}}, + /* 7*16^52*G: */ + {{{0x2114cfb5, 0x04b52ec7, 0x3d5a6a31, 0x0d8626a8, 0x1f0876d1, 0x1ce786df, 0x08173587, 0x24bf707e, 0xd3e4}}, + {{0x297f7045, 0x33ae6a95, 0x2754eefb, 0x223c1b91, 0x15fea39c, 0x3899dafc, 0x0c48b1fe, 0x29c29cfe, 0x3604}}}, + /* 9*16^52*G: */ + {{{0x2c55ddff, 0x2899d2ee, 0x0d4b7871, 0x2b46cfd9, 0x0dc1791d, 0x3948c43f, 0x042538a4, 0x3095618a, 0xbebf}}, + {{0x3ea2f303, 0x3536c328, 0x10baa706, 0x32a08b59, 0x36576c3c, 0x284712dd, 0x204ce8a3, 0x38997025, 0x850d}}}, + /* 11*16^52*G: */ + {{{0x099ead51, 0x06bd0793, 0x1d9224e9, 0x28d50e88, 0x0784715d, 0x0a4c7458, 0x20d602fb, 0x21371cf4, 0x36e9}}, + {{0x2e0e5e3e, 0x1bee7509, 0x04280afc, 0x2aefb05c, 0x232b203b, 0x2f7f26b3, 0x3485f4bf, 0x1c51c86f, 0x1437}}}, + /* 13*16^52*G: */ + {{{0x23093df0, 0x2a2ddeec, 0x376464d7, 0x17892059, 0x1793af78, 0x1451e553, 0x204aef31, 0x1d4010fd, 0x91b6}}, + {{0x12cc9f14, 0x337a30df, 0x1caf67f5, 0x0da17e3e, 0x221c5d93, 0x31eb6a5b, 0x0a00d477, 0x36c79609, 0x07fe}}}, + /* 15*16^52*G: */ + {{{0x3b7b8dc4, 0x08d9ee1b, 0x29b3848a, 0x0d24c0a2, 0x202fac5b, 0x25f8680d, 0x0883e7c4, 0x30f1e871, 0xc5d9}}, + {{0x1b2df0ea, 0x35925e34, 0x1fd4936e, 0x363dcbf4, 0x050af3d0, 0x230e1817, 0x1b79e580, 0x2e78973f, 0x3e59}}} + }, + { + /* 1*16^53*G: */ + {{{0x32513926, 0x18b6f270, 0x3ec85ecc, 0x09a2503b, 0x3c3383cc, 0x3aeac92f, 0x0872694f, 0x21918f28, 0x8842}}, + {{0x2fb8a54d, 0x3b90a0aa, 0x3dbc15a0, 0x03ac48ba, 0x181207ce, 0x1836cd97, 0x2dd5a696, 0x10a70070, 0xf778}}}, + /* 3*16^53*G: */ + {{{0x2520f1f1, 0x34aeb065, 0x07f7da4e, 0x3c6d2799, 0x0f6f4ad7, 0x17f45a33, 0x30819d5a, 0x274dbddb, 0x3bad}}, + {{0x1698df4d, 0x2865c1c9, 0x2b672586, 0x26606893, 0x2c0e8049, 0x27e9f677, 0x0e659bcd, 0x2778cf89, 0x49f9}}}, + /* 5*16^53*G: */ + {{{0x3185ae66, 0x2c7912a2, 0x3a783df0, 0x3b05b6fb, 0x24118ba6, 0x1f7d4f44, 0x0c46d67a, 0x292c6b6c, 0xa6b3}}, + {{0x0bfbf21b, 0x2fad54fe, 0x1b248dd7, 0x2fc2977d, 0x29e8d8bc, 0x06a47365, 0x09623136, 0x3a35d8e2, 0x0cb6}}}, + /* 7*16^53*G: */ + {{{0x2c630e3a, 0x25a13393, 0x3f3f1c2a, 0x0418305f, 0x3f10c1f6, 0x1f8e9f61, 0x114a4e22, 0x23d69b24, 0x1f84}}, + {{0x06ca610a, 0x3bb67fda, 0x2359724a, 0x28e49aff, 0x1da4264b, 0x2720f46a, 0x2f963862, 0x154b3341, 0xa028}}}, + /* 9*16^53*G: */ + {{{0x041bcd10, 0x37fbcf37, 0x1b44e154, 0x2e555d91, 0x0a2eb211, 0x2899df1b, 0x1c3588b1, 0x3952fa52, 0xcfd1}}, + {{0x2a62e732, 0x30057ae6, 0x0553965a, 0x36645742, 0x052fafac, 0x1d46f56c, 0x158bb9c5, 0x07d7d802, 0xf4e3}}}, + /* 11*16^53*G: */ + {{{0x228da5fb, 0x3e987648, 0x2870e724, 0x392fd78a, 0x31291b90, 0x1e578f9d, 0x09e5512c, 0x1cc3011b, 0x4b3e}}, + {{0x3c169e48, 0x3fc298e2, 0x023472bb, 0x28e84727, 0x20b48c65, 0x32e81ee3, 0x260e9e80, 0x2593688d, 0x8c40}}}, + /* 13*16^53*G: */ + {{{0x1f894780, 0x23a46962, 0x09aec5db, 0x3a7328d6, 0x02d8f737, 0x12e2952d, 0x38fe71d5, 0x0577dd10, 0xafe9}}, + {{0x1511d444, 0x3e5a554f, 0x2c0af452, 0x27a2f9ce, 0x3f2e3690, 0x2d0d08cc, 0x04686a94, 0x30d02348, 0x3cae}}}, + /* 15*16^53*G: */ + {{{0x1182fa6e, 0x168c7f2f, 0x181c8aff, 0x298cb75a, 0x35c9e7c0, 0x1a8e8db4, 0x3ac85586, 0x120a043f, 0x0c05}}, + {{0x261cd145, 0x3af3faad, 0x376d01f6, 0x39991612, 0x1d602bf5, 0x2a2e2519, 0x1f533d1a, 0x34b2b43c, 0x2f9c}}} + }, + { + /* 1*16^54*G: */ + {{{0x14441fbb, 0x382d756b, 0x1ed115e3, 0x2aa14829, 0x3925559e, 0x183157b6, 0x221d47fb, 0x23138877, 0xb495}}, + {{0x0add7118, 0x31f8f27d, 0x14638414, 0x2e7d84cb, 0x0cb7e12d, 0x0107ef0e, 0x240efe5c, 0x39efe659, 0xfcd6}}}, + /* 3*16^54*G: */ + {{{0x371f07f1, 0x2bb5a130, 0x0d70c4a5, 0x233b6dcc, 0x06684b87, 0x3a82d918, 0x0444d232, 0x0fd79ec8, 0xb3a4}}, + {{0x201dfda5, 0x0f348bd3, 0x1cb0ecc5, 0x1e1de833, 0x175ee7ec, 0x0c89cda6, 0x3d6b8418, 0x13d6c923, 0x34c6}}}, + /* 5*16^54*G: */ + {{{0x2b559d49, 0x3df25e91, 0x1dc9b44f, 0x386d1a43, 0x0008b148, 0x18bff613, 0x3e14ac26, 0x261a691a, 0x452e}}, + {{0x1a0d6ba7, 0x11f1811b, 0x31ee4257, 0x20a15b0e, 0x21ee5259, 0x0015ed9d, 0x380d0f5c, 0x22a3c657, 0x8c5e}}}, + /* 7*16^54*G: */ + {{{0x13ce94da, 0x0de99fad, 0x2829e605, 0x2c93d095, 0x0474ee8b, 0x378370eb, 0x162bb51c, 0x3d75231b, 0x19a7}}, + {{0x3025e7bb, 0x0c111c58, 0x225eb037, 0x1894c1ab, 0x00a2e8fb, 0x29475108, 0x075c32f6, 0x12e9ea4c, 0xa250}}}, + /* 9*16^54*G: */ + {{{0x147dc697, 0x25a5b31b, 0x1e15b9bb, 0x3b862bed, 0x3c6fa417, 0x3ac2cad7, 0x334dc011, 0x16c08293, 0xbdaf}}, + {{0x06a479e2, 0x24472f9e, 0x1b7a477b, 0x048b9e21, 0x17aa0855, 0x15d791ed, 0x2836c8cf, 0x031b2f7e, 0x3cec}}}, + /* 11*16^54*G: */ + {{{0x2ce05e10, 0x2802e46d, 0x3e106202, 0x3bdf27d0, 0x0e70db8a, 0x12dffa13, 0x1d15dab8, 0x2eba57ce, 0x265d}}, + {{0x171324f4, 0x3dfc062c, 0x164c67ff, 0x18fce4cf, 0x0b5dcb06, 0x0f3a2d5b, 0x037adf3b, 0x18f4268c, 0x58df}}}, + /* 13*16^54*G: */ + {{{0x33fe5938, 0x3456f156, 0x236d7cde, 0x320c0f6d, 0x1668669e, 0x1d2754e9, 0x2639689f, 0x020fc5f9, 0xc43e}}, + {{0x183732f3, 0x19e5d5bb, 0x24407477, 0x188c1c58, 0x04402eab, 0x240c0eaf, 0x3cc58350, 0x00a48e7e, 0x54c6}}}, + /* 15*16^54*G: */ + {{{0x1dd52975, 0x0c71c3de, 0x2b44180c, 0x33c3f4c1, 0x3266ba2b, 0x314369de, 0x3848665a, 0x3c5c028f, 0x7868}}, + {{0x3c626fac, 0x005bb540, 0x29690443, 0x3dbe7b29, 0x11276c68, 0x3e871b6c, 0x17ee1113, 0x25f3cc48, 0xe890}}} + }, + { + /* 1*16^55*G: */ + {{{0x2e12e1df, 0x3093990d, 0x1761d04a, 0x29ff42df, 0x06027cd8, 0x12fc4ecd, 0x132b6413, 0x2465a23a, 0xd0e0}}, + {{0x1fd28fbe, 0x2995136e, 0x046b8df6, 0x13312f66, 0x1bf86754, 0x2d82da47, 0x11452b4e, 0x26967f9f, 0x069c}}}, + /* 3*16^55*G: */ + {{{0x084aa098, 0x2c361440, 0x16e3e02b, 0x3040502a, 0x01fa8509, 0x29f6b2ff, 0x308eb398, 0x2915284c, 0xb517}}, + {{0x0540efbf, 0x0012d67d, 0x12447fd6, 0x3522d51a, 0x326fa3a4, 0x28f8bec3, 0x3879a60e, 0x21df4307, 0x0a3d}}}, + /* 5*16^55*G: */ + {{{0x0744bfa1, 0x3656b2a9, 0x093643d6, 0x09b49f38, 0x33e387cc, 0x089c4b63, 0x166f67bc, 0x050e12d4, 0xf8ec}}, + {{0x32b65f6d, 0x1a49398c, 0x3900060c, 0x18deb170, 0x160f610a, 0x1a3ec9a7, 0x3b9a6323, 0x0d2c844f, 0x7611}}}, + /* 7*16^55*G: */ + {{{0x3227a4bb, 0x18b0efa4, 0x38d99f2f, 0x39ac7c03, 0x14f2e64b, 0x1d3ab487, 0x3fae794e, 0x3fde36de, 0x320c}}, + {{0x30f3d2d4, 0x2073241a, 0x1e2f9705, 0x11c8dd02, 0x3f629960, 0x1e5a8953, 0x28692ab7, 0x3a3501ca, 0xaf9f}}}, + /* 9*16^55*G: */ + {{{0x1c2ca683, 0x2d6d6979, 0x295a7373, 0x1b3cd782, 0x03426a20, 0x377732d5, 0x2ed8517e, 0x379f1a9e, 0x0c08}}, + {{0x3db5f259, 0x0901b6d5, 0x0ea68c69, 0x3235edf8, 0x0e0e79c3, 0x20a6737f, 0x16e19b7c, 0x1b6157a8, 0xddb7}}}, + /* 11*16^55*G: */ + {{{0x252ae5cd, 0x319eb3e0, 0x0fdd7861, 0x2d94bebd, 0x24390995, 0x1bde9133, 0x07c3d18e, 0x31dab431, 0xd1f8}}, + {{0x3e6d2dda, 0x3ae5ef0f, 0x189f4fc7, 0x2eba055a, 0x21203239, 0x265ec07d, 0x0e802ac7, 0x17719848, 0x74d4}}}, + /* 13*16^55*G: */ + {{{0x2bdc603f, 0x1e4019aa, 0x3dffe5ab, 0x1b597359, 0x3620d8c9, 0x0cfb1899, 0x090c093e, 0x20da4fce, 0xa6cb}}, + {{0x096befcc, 0x2b380f83, 0x0661735c, 0x07b05a93, 0x110b72fb, 0x366f6931, 0x3cafc8f2, 0x3239187c, 0xd823}}}, + /* 15*16^55*G: */ + {{{0x22c374b0, 0x278e984b, 0x170db4a2, 0x16cd662d, 0x024ef0bf, 0x3b25c549, 0x0332136b, 0x27247a9b, 0x8a6c}}, + {{0x378c08bd, 0x2fdf3e36, 0x00f4d583, 0x054d3d0d, 0x0132a046, 0x1e217724, 0x1ffaf79a, 0x1fd3d973, 0xe4bc}}} + }, + { + /* 1*16^56*G: */ + {{{0x2895df07, 0x29c0fc43, 0x1876bd86, 0x1d7cfe80, 0x208ffefd, 0x2c1b9c33, 0x3dfeeeb5, 0x2e1509e0, 0x68f6}}, + {{0x38712655, 0x031dbe29, 0x310bf7f9, 0x14a4f4bc, 0x245028cf, 0x201137f6, 0x00ce6fbc, 0x3faea4b9, 0xcbe1}}}, + /* 3*16^56*G: */ + {{{0x3aa89692, 0x1063e88c, 0x14c2308e, 0x0ec235be, 0x18a77671, 0x1b990490, 0x28f4de99, 0x329c6059, 0x3bdf}}, + {{0x1a510308, 0x0f6f6d0c, 0x1e2ef139, 0x370318d1, 0x1a5333c7, 0x098546bb, 0x167b8494, 0x07da1594, 0x0a72}}}, + /* 5*16^56*G: */ + {{{0x037ea1d7, 0x1e6c8d0b, 0x09aae4d0, 0x0e4d963e, 0x0d9e4fb2, 0x0a154946, 0x21056353, 0x2b256dd4, 0xaca8}}, + {{0x1ba973a2, 0x37bec412, 0x13935e9d, 0x3b6ff710, 0x072189e1, 0x01312e4a, 0x1cc20943, 0x3159f75d, 0x7f12}}}, + /* 7*16^56*G: */ + {{{0x13245b7f, 0x36c9e073, 0x0597fbf5, 0x1f59a5a4, 0x185311a3, 0x3086be63, 0x27c0e206, 0x11c136d9, 0xfa90}}, + {{0x0ddf6bef, 0x3e0cf7c5, 0x24f1d47e, 0x27bb3498, 0x31c189cb, 0x3e8fb503, 0x036a42d6, 0x230d9d2a, 0x1a1c}}}, + /* 9*16^56*G: */ + {{{0x37f0953a, 0x187de3f5, 0x315439ab, 0x124520ff, 0x3a92a818, 0x0ae3874b, 0x17d8cd67, 0x06aae47d, 0x1d43}}, + {{0x1d68f260, 0x1f1675da, 0x0707e7c1, 0x238a6a42, 0x15fae0f4, 0x0c320f38, 0x1121ebc5, 0x19f0efc6, 0x08d6}}}, + /* 11*16^56*G: */ + {{{0x25227c70, 0x28c45c4d, 0x3a3ea705, 0x0afaaccc, 0x31c60ff3, 0x12cd6cb8, 0x21137dda, 0x3a83568f, 0x6dee}}, + {{0x0369b9b7, 0x35b68e04, 0x29083dba, 0x1ebb0795, 0x2acc8428, 0x132ebfbd, 0x03e40001, 0x0fc3f1d1, 0xcbb9}}}, + /* 13*16^56*G: */ + {{{0x0421b54d, 0x2d7f57a2, 0x1564a4ff, 0x26cae0e9, 0x3a9dca57, 0x3274aec7, 0x178d8d4a, 0x170418d5, 0x2813}}, + {{0x0ee5d868, 0x3733c26e, 0x1e310d8a, 0x01253324, 0x3f8c15ef, 0x2a75d041, 0x1be1506f, 0x12af8e14, 0x9ed8}}}, + /* 15*16^56*G: */ + {{{0x28e4ac10, 0x05f95647, 0x0e24a9a9, 0x25aa04ab, 0x3fb56879, 0x0f316827, 0x1077bd6c, 0x015d882c, 0x339a}}, + {{0x0d1312a0, 0x1db6a191, 0x01cc66ef, 0x0e79e23d, 0x0f553e50, 0x1537de2b, 0x2947f438, 0x17efb75a, 0xca98}}} + }, + { + /* 1*16^57*G: */ + {{{0x27ea1f34, 0x0d36ac5d, 0x0739e0dd, 0x1af4d501, 0x3353d664, 0x10745e4e, 0x34b66c3b, 0x18288f51, 0x7f94}}, + {{0x0d9063ec, 0x22fb0b2b, 0x0e34ffc5, 0x3fe05449, 0x076661c6, 0x07cafe3c, 0x0618769f, 0x059de3ec, 0xd0d5}}}, + /* 3*16^57*G: */ + {{{0x3dfc0a9d, 0x316dd326, 0x0f77aa0d, 0x1108d6c5, 0x20a2a2de, 0x038d91ab, 0x29e022a6, 0x39fe130c, 0xdb43}}, + {{0x1e9ad713, 0x02c424ea, 0x2d2f054f, 0x0e411cd5, 0x2f9fa488, 0x15b20533, 0x2b591b8a, 0x2368af8d, 0xb016}}}, + /* 5*16^57*G: */ + {{{0x0283808d, 0x02f2c5dd, 0x1643a893, 0x23c1f38d, 0x3a78980f, 0x057a4487, 0x121aeb85, 0x0c207b83, 0xe9af}}, + {{0x39b39d33, 0x19b0be38, 0x1136d199, 0x1ae49445, 0x2f497197, 0x3c99543f, 0x3126085a, 0x32122711, 0xa976}}}, + /* 7*16^57*G: */ + {{{0x2d8426df, 0x1a4bd0b2, 0x26f8a0a2, 0x104e5693, 0x3883590f, 0x2b24e0ef, 0x06980703, 0x0cd8cb20, 0x6eb7}}, + {{0x200b4267, 0x3fdd67b8, 0x3fe1b833, 0x14ba5f20, 0x008e8d92, 0x392cb3b3, 0x07a9a030, 0x1bb045cc, 0x96c5}}}, + /* 9*16^57*G: */ + {{{0x1a16453d, 0x1f45b5f0, 0x21033dbf, 0x1fa1ef9d, 0x34d0e68b, 0x106e47e2, 0x15f45e17, 0x275781e7, 0xd397}}, + {{0x27b6d737, 0x0f2ee0c5, 0x26961a4f, 0x377d98a2, 0x32456917, 0x02495d4d, 0x1adb9a4d, 0x24cd75e6, 0xc55f}}}, + /* 11*16^57*G: */ + {{{0x2d326504, 0x3a866697, 0x3b5202cc, 0x16a6d189, 0x2efc12f6, 0x20ee2306, 0x0c2342c3, 0x24a7396e, 0x54c3}}, + {{0x3ec9e107, 0x2fc047e9, 0x08a67268, 0x294f6798, 0x14ab4447, 0x26a8a124, 0x216d0c48, 0x0c09583a, 0x4696}}}, + /* 13*16^57*G: */ + {{{0x3b5ecce7, 0x0113d5da, 0x00d21353, 0x0a0562c3, 0x1659c873, 0x3a3a0f06, 0x2d6c5b84, 0x3a6ca199, 0x3744}}, + {{0x2a247721, 0x004c8505, 0x2a6f8392, 0x3a2d7c14, 0x29ec3c28, 0x39a55bac, 0x047aa0e0, 0x383e3664, 0x9546}}}, + /* 15*16^57*G: */ + {{{0x05fef996, 0x0324a379, 0x04253515, 0x01a3d8e5, 0x33f2de14, 0x3342907b, 0x16d53324, 0x0f85f8d9, 0x1134}}, + {{0x1792aded, 0x00542b9d, 0x086f18e4, 0x33935968, 0x273765d0, 0x377e4c18, 0x28eeeb04, 0x212037ae, 0x4a9e}}} + }, + { + /* 1*16^58*G: */ + {{{0x0e6d8483, 0x3b26d35e, 0x2967f0dc, 0x3cb5ea11, 0x2ee94582, 0x23d27c6d, 0x1563d295, 0x32d828cf, 0x9c39}}, + {{0x2b2c50fb, 0x12ccd5bd, 0x1be43689, 0x2b794bcf, 0x216546bb, 0x065adef2, 0x3e51003d, 0x2fc7b924, 0xf097}}}, + /* 3*16^58*G: */ + {{{0x07a14dda, 0x1570c7e1, 0x34b4df3f, 0x1b410a59, 0x01308360, 0x1da3dc90, 0x2dad7443, 0x1eb3243a, 0x18f3}}, + {{0x25ac8364, 0x08bf370c, 0x28536cbe, 0x363df1e2, 0x1bcd0b77, 0x2fffb3b8, 0x12c26d7b, 0x12eeaa82, 0x2f94}}}, + /* 5*16^58*G: */ + {{{0x0c7d59be, 0x19d3a3a3, 0x20932fb5, 0x3a861623, 0x32736b98, 0x17ffb91d, 0x279da4ec, 0x0d630a07, 0x5413}}, + {{0x24f80590, 0x35fa87db, 0x100b3672, 0x3896c572, 0x24515a53, 0x123f4805, 0x0b024e7c, 0x3537a5a7, 0x680f}}}, + /* 7*16^58*G: */ + {{{0x076051a8, 0x3ae0327e, 0x2457ea58, 0x35dce58e, 0x385280be, 0x3f068f06, 0x194f05dc, 0x3449a46c, 0x4e2f}}, + {{0x29cc9005, 0x2bfb1d3f, 0x2c4fe2e6, 0x2e2ea964, 0x0a31bceb, 0x2cd68542, 0x0fbb2371, 0x2ef6fd7d, 0x122a}}}, + /* 9*16^58*G: */ + {{{0x16a80e09, 0x19f2a3e9, 0x225f5fe3, 0x1d7c3dd9, 0x008fa0a2, 0x13d5a04f, 0x31b59200, 0x16352fbf, 0x2de7}}, + {{0x036a1cd3, 0x358bb7d5, 0x1dad6c99, 0x06b719a5, 0x1e64a07a, 0x00cac099, 0x0ee67d7c, 0x33cc5df6, 0xdd9a}}}, + /* 11*16^58*G: */ + {{{0x3a3628ac, 0x0940d6cb, 0x35b564ec, 0x22ee8b37, 0x2e12a456, 0x1685cf1b, 0x14a5728c, 0x282b3707, 0xf597}}, + {{0x2cd3550f, 0x3a80c435, 0x012106e7, 0x0bb3e475, 0x222cc077, 0x06edca25, 0x3d4557bb, 0x05a38cca, 0x0db9}}}, + /* 13*16^58*G: */ + {{{0x2b75d6c3, 0x235a0f52, 0x13a28567, 0x0a9515f5, 0x3e40f3c4, 0x041c6086, 0x04fb908a, 0x0aa1b5bd, 0xaa22}}, + {{0x244cb028, 0x0c996939, 0x1a8c8f61, 0x1c7f252d, 0x22df4260, 0x122896bb, 0x28e76ce4, 0x21e4c006, 0x5637}}}, + /* 15*16^58*G: */ + {{{0x235790c9, 0x3ea15ce4, 0x3f3c5037, 0x006e45dc, 0x335e2e9e, 0x03190e4b, 0x315b756f, 0x2c9af365, 0x8568}}, + {{0x26b1f5ac, 0x34fd54e0, 0x385479fd, 0x11797e3e, 0x363ce801, 0x1e382b90, 0x1d2ade90, 0x09869613, 0xd3f2}}} + }, + { + /* 1*16^59*G: */ + {{{0x1c38d4e4, 0x376a5f15, 0x1b173747, 0x3f597c6c, 0x181e25e2, 0x19b9d0c0, 0x29938975, 0x21498448, 0x3d92}}, + {{0x00ccf0d3, 0x3eabbc03, 0x17abc7f6, 0x02ac4e06, 0x2869eacc, 0x015c0d70, 0x0eab53ff, 0x2829751a, 0xd32c}}}, + /* 3*16^59*G: */ + {{{0x0dd7718a, 0x01c8c960, 0x1be4e4ed, 0x3206d946, 0x36dff891, 0x05668979, 0x02fc3f7c, 0x038dcae4, 0x3b18}}, + {{0x1afd82db, 0x099898a6, 0x02d14d07, 0x1244559c, 0x05211e58, 0x12f274a4, 0x358aafaa, 0x2c45fcda, 0xf2b6}}}, + /* 5*16^59*G: */ + {{{0x13d3653d, 0x2a069446, 0x0e467d5f, 0x13b12c9d, 0x283eb213, 0x3d3d0262, 0x29c9f45e, 0x3fc0e475, 0xf352}}, + {{0x0a44f28e, 0x27999e32, 0x2c582d07, 0x06657e5c, 0x26d5055c, 0x2f5cf7f6, 0x05ebd020, 0x189b32db, 0x4472}}}, + /* 7*16^59*G: */ + {{{0x2d4478da, 0x19877c6b, 0x00e0154d, 0x173db089, 0x393ca1f1, 0x2d1736fd, 0x18c230af, 0x391c40d3, 0x670e}}, + {{0x34f563f0, 0x0a3ff93f, 0x3f247706, 0x30ee0583, 0x0750e81c, 0x19816c4e, 0x022ca254, 0x31d096e8, 0x5ca0}}}, + /* 9*16^59*G: */ + {{{0x03dbd581, 0x3138a411, 0x0d6b35ba, 0x3face20a, 0x2c6fa93c, 0x2fe8c2b3, 0x19bdbefb, 0x38d50d27, 0x96f2}}, + {{0x28f59952, 0x36693ffb, 0x04f5d454, 0x2863c754, 0x0dbaf435, 0x17638e58, 0x126cf4fe, 0x36022175, 0x09fc}}}, + /* 11*16^59*G: */ + {{{0x24e9c2fc, 0x3acd0c92, 0x3bd706a1, 0x0b3c33cb, 0x209a35e7, 0x06082c51, 0x399ac804, 0x1b945fa0, 0xc494}}, + {{0x26398ce8, 0x10d1d8dd, 0x14623123, 0x22fce3b4, 0x3b8237e4, 0x283da3d1, 0x18a4ce99, 0x00482c61, 0x7489}}}, + /* 13*16^59*G: */ + {{{0x04960b03, 0x32e45cfa, 0x0808e8f5, 0x2b0eac32, 0x094d8fb6, 0x232315e0, 0x233dbfa4, 0x2d936a6f, 0x1653}}, + {{0x30f73c69, 0x201a953a, 0x1b564e7f, 0x0e383928, 0x15a8948b, 0x2caf60fa, 0x1d5609f4, 0x1c205a79, 0xa583}}}, + /* 15*16^59*G: */ + {{{0x3b63640e, 0x155df8c6, 0x0c72df2c, 0x26edfca4, 0x05cbf497, 0x319e729a, 0x3153f500, 0x1b75fb4b, 0x5107}}, + {{0x02e4476c, 0x3da5ca1e, 0x320ef021, 0x2fa93a79, 0x20fda6c8, 0x399405cb, 0x1df76aeb, 0x09d28b5b, 0xb397}}} + }, + { + /* 1*16^60*G: */ + {{{0x244e8de3, 0x018c12c6, 0x2cc1e076, 0x02259a8b, 0x3d17915c, 0x29f73c22, 0x010b73a5, 0x266dd1a2, 0xf50b}}, + {{0x1b7f3588, 0x28fcee9b, 0x1721e854, 0x1d7c6348, 0x2dcebbe9, 0x265ce8b7, 0x18f0c878, 0x0187957c, 0xe2b5}}}, + /* 3*16^60*G: */ + {{{0x02accf8b, 0x3771adae, 0x2816fa7d, 0x34a66460, 0x39430481, 0x3cc38944, 0x05770645, 0x1fd86954, 0x598d}}, + {{0x0f6cb808, 0x2e119cf0, 0x13540b91, 0x0a26a3cd, 0x33ebcad2, 0x31458ac9, 0x32609546, 0x087dd3e3, 0x9f31}}}, + /* 5*16^60*G: */ + {{{0x24aa7b3e, 0x3ece6951, 0x16c9cea9, 0x313bc6c1, 0x1c581013, 0x34824550, 0x34c4d64f, 0x0804bd27, 0x715a}}, + {{0x3c7d081d, 0x268ce512, 0x08b47d0d, 0x06f1622a, 0x113b6242, 0x24a23e2a, 0x06c0a1f7, 0x2cec6a98, 0x5922}}}, + /* 7*16^60*G: */ + {{{0x220db220, 0x06f6da5d, 0x287ace4d, 0x0732c405, 0x387876c7, 0x273a25fe, 0x1b125c40, 0x23179aaa, 0x49ec}}, + {{0x277338c2, 0x26e2b281, 0x13b9cce9, 0x0b0c1cf9, 0x1f542984, 0x2730d219, 0x2629b3da, 0x1f53f97a, 0x99a9}}}, + /* 9*16^60*G: */ + {{{0x1e771268, 0x07af28c5, 0x10a65685, 0x13c529f6, 0x207b7a2f, 0x3c643817, 0x0b4483e6, 0x2dc35214, 0x1f8f}}, + {{0x0909c8dd, 0x2bf4c043, 0x092b3ab1, 0x074f0c47, 0x2192a14e, 0x0bb5d1c9, 0x3a2bf12c, 0x1eb6d186, 0xf53e}}}, + /* 11*16^60*G: */ + {{{0x28d9819e, 0x17b03cac, 0x02dab1a5, 0x019e4bdd, 0x38732cd6, 0x3450ae99, 0x3f61fdd5, 0x31c69925, 0xb8d5}}, + {{0x29138ac4, 0x31e2fa3a, 0x1d45c3cd, 0x3d27c4d8, 0x23dc79e2, 0x3b90d66d, 0x37f823b6, 0x13bc4c84, 0x1cd1}}}, + /* 13*16^60*G: */ + {{{0x20bca3f3, 0x2a4f6f99, 0x16004906, 0x2cd0d451, 0x00d8c4ec, 0x0fad8722, 0x2ae3ddd6, 0x2d6b196e, 0x2265}}, + {{0x117409ff, 0x160a71b1, 0x2393d5a2, 0x202984b4, 0x0964983c, 0x0c4e8ec4, 0x0fe0f61a, 0x262fd72b, 0x97a1}}}, + /* 15*16^60*G: */ + {{{0x05bac36e, 0x1cb48ffd, 0x175dcd03, 0x26265166, 0x09abcb59, 0x362a7d7f, 0x0492521f, 0x073440d6, 0xaf38}}, + {{0x31b119a9, 0x3cf621ea, 0x34d4a90f, 0x26e0bc7b, 0x1a264858, 0x15fc8a54, 0x30fbdc94, 0x021fedf7, 0x681a}}} + }, + { + /* 1*16^61*G: */ + {{{0x2037cfb4, 0x38665015, 0x3cdaa859, 0x003c91b0, 0x20b0e074, 0x1fd22036, 0x1ed0b0d7, 0x0c608ffd, 0x0425}}, + {{0x18775d23, 0x02dcc97b, 0x0ec5dd40, 0x28f93d4d, 0x261facee, 0x32934321, 0x00f7e628, 0x22f33eb8, 0xc90e}}}, + /* 3*16^61*G: */ + {{{0x06c34577, 0x213d9cd5, 0x2a52af77, 0x1027b239, 0x00e4bde6, 0x178c23a3, 0x3ca48b1f, 0x1ea838c2, 0x2755}}, + {{0x0416193c, 0x37fae6e0, 0x0c4380ba, 0x28b29cdd, 0x3d34f318, 0x235d6927, 0x05b3b77c, 0x31d61184, 0x8399}}}, + /* 5*16^61*G: */ + {{{0x2401f4d3, 0x3963f6da, 0x295b301e, 0x1b0b943a, 0x21d7decf, 0x01e0efd5, 0x073648e5, 0x1e05f496, 0x8e68}}, + {{0x0294d86b, 0x00a07a51, 0x2a191289, 0x02e5bc4b, 0x2d3cae90, 0x20268141, 0x09bfa62f, 0x2ae21b8b, 0x989c}}}, + /* 7*16^61*G: */ + {{{0x2d2aa8e6, 0x1658f789, 0x0effe2dc, 0x14d67f10, 0x27dbee20, 0x0da00f29, 0x25cf6d10, 0x05d1894f, 0x98a4}}, + {{0x206cf75b, 0x25d02fb5, 0x37ed2196, 0x0085feaa, 0x35cec9e3, 0x150bd68b, 0x063d6b11, 0x31a51f8d, 0x579a}}}, + /* 9*16^61*G: */ + {{{0x352c2d31, 0x328b323d, 0x061eecd7, 0x002aec23, 0x21a94618, 0x05b910f8, 0x140fd922, 0x151088c1, 0xe168}}, + {{0x24a50fec, 0x32e20da0, 0x09983941, 0x1d864afe, 0x2bc9343e, 0x0b990b40, 0x272142fb, 0x215724a3, 0x0700}}}, + /* 11*16^61*G: */ + {{{0x33a7cdad, 0x28ceeb8d, 0x10bcfaf4, 0x2b60f4b9, 0x0951a53c, 0x0a8b94ce, 0x113ea1ca, 0x0c52c275, 0xbfa6}}, + {{0x295cb953, 0x17e224c0, 0x04047a1c, 0x04643e32, 0x2ed1a726, 0x3e16eec7, 0x02c782a5, 0x3a065320, 0xb452}}}, + /* 13*16^61*G: */ + {{{0x0ade0fb7, 0x36f32140, 0x26518d8e, 0x1b71d37a, 0x198e200c, 0x025d79b7, 0x21cd3ecf, 0x020b42a5, 0xe687}}, + {{0x1d4d6ece, 0x05e783cc, 0x08c22599, 0x307a17be, 0x11a72117, 0x3c394c87, 0x095555e5, 0x29121a13, 0x2135}}}, + /* 15*16^61*G: */ + {{{0x0e432daf, 0x20f2d7c3, 0x2827ac9c, 0x2fb6822a, 0x074975f3, 0x30a35e54, 0x1a9e94bf, 0x1bbe18aa, 0x7ab1}}, + {{0x271bdc48, 0x045d622a, 0x34fdb013, 0x3a738eb9, 0x1ba7c5c7, 0x2460f8a3, 0x328b1a35, 0x0382a5f0, 0x584e}}} + }, + { + /* 1*16^62*G: */ + {{{0x085fbd44, 0x01d1c4a6, 0x326267ac, 0x30b2a8e7, 0x15222c89, 0x11c7385b, 0x35905e05, 0x01b6b66a, 0x9bbf}}, + {{0x3a1d3e88, 0x0d11f7e9, 0x1036ed2a, 0x352f7705, 0x2f47e8c0, 0x176bcc29, 0x120a3675, 0x1fea1378, 0x1bcc}}}, + /* 3*16^62*G: */ + {{{0x34a7b506, 0x2deb9e4a, 0x3860be08, 0x1d62eeb9, 0x100ee922, 0x33ecab9d, 0x35bd3429, 0x3dfd96ce, 0x646f}}, + {{0x2b36f946, 0x25e70494, 0x08e6995c, 0x0b7f13f0, 0x0a8fe849, 0x078cc601, 0x218a55a6, 0x0aa74192, 0xbc11}}}, + /* 5*16^62*G: */ + {{{0x0103b553, 0x152dc727, 0x3385a801, 0x183a89e0, 0x3e507ebe, 0x304002c9, 0x3d39a9d0, 0x151ea985, 0x7cc0}}, + {{0x0d45a526, 0x1e672e8f, 0x0228b7d5, 0x061682ab, 0x3c94c400, 0x1ca32ce7, 0x0045abdd, 0x27af48ca, 0x7b32}}}, + /* 7*16^62*G: */ + {{{0x19e717a4, 0x30bbd150, 0x0f01b81a, 0x368af6ab, 0x2ee15468, 0x0fb54db6, 0x1db4e056, 0x146642f0, 0x9468}}, + {{0x3526dea3, 0x1d7c3f46, 0x30acd9ca, 0x2665643d, 0x267dc057, 0x23439ac9, 0x191a8b3b, 0x1e108371, 0xca5c}}}, + /* 9*16^62*G: */ + {{{0x08362735, 0x3e0b0dbc, 0x12b327bd, 0x3e2cdfbc, 0x12d1f5df, 0x163e3a91, 0x0e8fab12, 0x23c6f9f8, 0xe1b9}}, + {{0x0ecb11b7, 0x2584e327, 0x374090af, 0x067b8cf7, 0x3b2ba27e, 0x16d26a0e, 0x36a0b7e0, 0x3a6b66a5, 0xca83}}}, + /* 11*16^62*G: */ + {{{0x39046346, 0x2d02ef60, 0x01440083, 0x296379cc, 0x27962d56, 0x2281af65, 0x207ef6d0, 0x3c9723f5, 0x3536}}, + {{0x0c14fea6, 0x100418af, 0x2d9b3e29, 0x1b0f47a8, 0x29e1c39e, 0x285a8694, 0x3509e73b, 0x07f85f78, 0x1e27}}}, + /* 13*16^62*G: */ + {{{0x2847f6f8, 0x3ffe0fb5, 0x140ef530, 0x0a6d47ef, 0x3f8c3c10, 0x0547cd2d, 0x3d4de690, 0x0091af88, 0x0df5}}, + {{0x3b1633a6, 0x1332a29a, 0x1df3449b, 0x1b8599a2, 0x2174ab4c, 0x0cb13ef0, 0x2f1ca2b2, 0x011fca76, 0x2107}}}, + /* 15*16^62*G: */ + {{{0x3d4f1b81, 0x2173abb7, 0x0f4bb151, 0x1a69e923, 0x129330ad, 0x378eccd9, 0x13398f69, 0x3575133d, 0xca9d}}, + {{0x02b7c8bd, 0x3318b2b9, 0x2ada10f8, 0x325d82fe, 0x067b3e66, 0x11c7ed11, 0x22c56402, 0x2621946f, 0x6e4b}}} + }, + { + /* 1*16^63*G: */ + {{{0x044c0448, 0x3ab4c8cd, 0x10319e31, 0x0d5da1b0, 0x3893e796, 0x0ff32ced, 0x3dfa5494, 0x2b7d4a50, 0xb12f}}, + {{0x3369de57, 0x195d79da, 0x2fc4df29, 0x0179c0cc, 0x32a6a71d, 0x3e3d99de, 0x0f4ace96, 0x1165666c, 0x02e2}}}, + /* 3*16^63*G: */ + {{{0x24e9151f, 0x14db1151, 0x00d8418f, 0x3a8ce672, 0x18fb3e67, 0x15776a47, 0x10568432, 0x238d3c71, 0x4838}}, + {{0x0d7a9434, 0x2fb927b7, 0x3de83101, 0x2c504454, 0x082bcc99, 0x14ce4c55, 0x04e9e6a2, 0x18eafd39, 0xb0ec}}}, + /* 5*16^63*G: */ + {{{0x0e5b833d, 0x1f7ed296, 0x20b2419d, 0x0e801cf2, 0x0109c959, 0x177e0414, 0x053da5e6, 0x1911eb85, 0xde8e}}, + {{0x214c5cc7, 0x03f3066a, 0x101c6c9f, 0x1f80c4ca, 0x2de26598, 0x08a232f5, 0x113d8e33, 0x118f0542, 0x05e1}}}, + /* 7*16^63*G: */ + {{{0x01f7df48, 0x38964fab, 0x071317b3, 0x19d1cfae, 0x18f385b2, 0x156d3939, 0x07e9e8e5, 0x04b4293b, 0xb18b}}, + {{0x2846b546, 0x06cf5643, 0x3d1e5599, 0x20fdf920, 0x2cc33b3c, 0x3109af16, 0x1fb445ce, 0x0648a8d6, 0xff53}}}, + /* 9*16^63*G: */ + {{{0x19c9fd24, 0x094eb71a, 0x1211e0df, 0x33762611, 0x28694402, 0x072a931c, 0x09433c7c, 0x2b5c7237, 0x5f51}}, + {{0x2d2ffd3a, 0x30eeba21, 0x224a9969, 0x087d8911, 0x2e4d0387, 0x0c17ef30, 0x2714a0cd, 0x3bc477df, 0x2bbb}}}, + /* 11*16^63*G: */ + {{{0x17cec42e, 0x0f1018ff, 0x2e3bdb7e, 0x0f724cfb, 0x06d8556f, 0x208bb90d, 0x01ebbfa5, 0x10364dcc, 0xfdf3}}, + {{0x0db6908b, 0x23d8d2df, 0x0de30c83, 0x1b9aafd4, 0x0ad2c445, 0x307f9ce3, 0x0c6e1d70, 0x2698e5a3, 0xa3e5}}}, + /* 13*16^63*G: */ + {{{0x21dc4fe8, 0x30625153, 0x2072415f, 0x3a284ea5, 0x3dc983f9, 0x114a45ed, 0x25d79ec6, 0x3af22e7a, 0xe3ca}}, + {{0x1307b403, 0x1ad82dc8, 0x14f86a11, 0x0c00d968, 0x01f97651, 0x00d72e2c, 0x05928d22, 0x24f49efc, 0x97f0}}}, + /* 15*16^63*G: */ + {{{0x3c119eff, 0x10535974, 0x29f9b846, 0x240b8302, 0x0fa00339, 0x10697396, 0x065b89af, 0x0b6e50aa, 0x0331}}, + {{0x38b1b950, 0x3a568ea7, 0x3515585f, 0x3b1676d7, 0x09e86f0a, 0x3ba8c5e0, 0x324df104, 0x36991acd, 0x6e3e}}} + }, diff --git a/secp256k1.c b/secp256k1.c index b96448dd8..cbd21fbd4 100644 --- a/secp256k1.c +++ b/secp256k1.c @@ -23,1687 +23,27 @@ #include "secp256k1.h" -const bignum256 prime256k1 = { -/*.val =*/{0x3ffffc2f, 0x3ffffffb, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0xffff}}; - -const curve_point G256k1 = { -/*.x =*/{/*.val =*/{0x16f81798, 0x27ca056c, 0x1ce28d95, 0x26ff36cb, 0x70b0702, 0x18a573a, 0xbbac55a, 0x199fbe77, 0x79be}}, -/*.y =*/{/*.val =*/{0x3b10d4b8, 0x311f423f, 0x28554199, 0x5ed1229, 0x1108a8fd, 0x13eff038, 0x3c4655da, 0x369dc9a8, 0x483a}}}; - -const bignum256 order256k1 = { -/*.val =*/{0x10364141, 0x3f497a33, 0x348a03bb, 0x2bb739ab, 0x3ffffeba, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0xffff}}; +const ecdsa_curve secp256k1 = { + /* .prime */ { + /*.val =*/ {0x3ffffc2f, 0x3ffffffb, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0xffff} + }, -const bignum256 order256k1_half = { -/*.val =*/{0x281b20a0, 0x3fa4bd19, 0x3a4501dd, 0x15db9cd5, 0x3fffff5d, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x7fff}}; + /* G */ { + /*.x =*/{/*.val =*/{0x16f81798, 0x27ca056c, 0x1ce28d95, 0x26ff36cb, 0x70b0702, 0x18a573a, 0xbbac55a, 0x199fbe77, 0x79be}}, + /*.y =*/{/*.val =*/{0x3b10d4b8, 0x311f423f, 0x28554199, 0x5ed1229, 0x1108a8fd, 0x13eff038, 0x3c4655da, 0x369dc9a8, 0x483a}} + }, -const bignum256 three_over_two256k1 = { -/*.val =*/{0x3ffffe19, 0x3ffffffd, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x7fff}}; + /* order */ { + /*.val =*/{0x10364141, 0x3f497a33, 0x348a03bb, 0x2bb739ab, 0x3ffffeba, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0xffff} + }, + /* a */ { + /*.val =*/{0} + } #if USE_PRECOMPUTED_CP -const curve_point secp256k1_cp[64][8] = { - { - /* 1*16^0*G: */ - {{{0x16f81798, 0x27ca056c, 0x1ce28d95, 0x26ff36cb, 0x070b0702, 0x018a573a, 0x0bbac55a, 0x199fbe77, 0x79be}}, - {{0x3b10d4b8, 0x311f423f, 0x28554199, 0x05ed1229, 0x1108a8fd, 0x13eff038, 0x3c4655da, 0x369dc9a8, 0x483a}}}, - /* 3*16^0*G: */ - {{{0x3ce036f9, 0x1807c44e, 0x36f99b08, 0x0c721160, 0x1d5229b5, 0x113e17e2, 0x0c310493, 0x22806496, 0xf930}}, - {{0x04b8e672, 0x32e7f5d6, 0x0c2231b6, 0x002a664d, 0x37f35665, 0x0cdf98a8, 0x1e8140fe, 0x1ec3d8cb, 0x388f}}}, - /* 5*16^0*G: */ - {{{0x3240efe4, 0x2ea355a6, 0x0619ab7c, 0x22e12f77, 0x1c5128e8, 0x129c9429, 0x3209355b, 0x37934681, 0x2f8b}}, - {{0x26ac62d6, 0x32a1f4ea, 0x30d6840d, 0x2209c6ea, 0x09c426f7, 0x2ea7769b, 0x1e3d6d4d, 0x08898db9, 0xd8ac}}}, - /* 7*16^0*G: */ - {{{0x0ac4f9bc, 0x24af77b7, 0x330e39ce, 0x1066df80, 0x2a7a0e3d, 0x23cd97cb, 0x1b4eaa39, 0x3c191b97, 0x5cbd}}, - {{0x087264da, 0x142098a0, 0x3fde7b5a, 0x04f42e04, 0x1a54dba8, 0x1e35b618, 0x15960a31, 0x32902e89, 0x6aeb}}}, - /* 9*16^0*G: */ - {{{0x3c27ccbe, 0x0d7c4437, 0x057e714c, 0x25e5a5d3, 0x159abde0, 0x345e2a7d, 0x3f65309a, 0x2138bc31, 0xacd4}}, - {{0x064f9c37, 0x173098ab, 0x35f8e0f0, 0x3622290d, 0x3b61e9ad, 0x2025c5d8, 0x3d9fd643, 0x22486c29, 0xcc33}}}, - /* 11*16^0*G: */ - {{{0x1da008cb, 0x2fb05e25, 0x1c17891b, 0x126602f9, 0x065aac56, 0x1091adc3, 0x1411e5ef, 0x39fe162a, 0x774a}}, - {{0x0953c61b, 0x0075d327, 0x3f9d6a83, 0x0b6c78b7, 0x37b36537, 0x0f755b5e, 0x35e19024, 0x280cbada, 0xd984}}}, - /* 13*16^0*G: */ - {{{0x19405aa8, 0x3bb77e3c, 0x10e58cdd, 0x1d7ef198, 0x348651b0, 0x0748170d, 0x1288bc7d, 0x1cf0b65d, 0xf287}}, - {{0x1b03ed81, 0x26d72d4b, 0x21fa91f2, 0x0681b694, 0x0daf473a, 0x084bad97, 0x00a89758, 0x240ba362, 0x0ab0}}}, - /* 15*16^0*G: */ - {{{0x227e080e, 0x12b6f3e3, 0x085f79e4, 0x39651bcf, 0x1ff41131, 0x196b8c25, 0x3ea965a4, 0x1353df50, 0xd792}}, - {{0x36a26b58, 0x1413727f, 0x096d3a5c, 0x102bcaf6, 0x0c6defea, 0x10bb08a3, 0x072a6838, 0x0a1caa1b, 0x581e}}} - }, - { - /* 1*16^1*G: */ - {{{0x2a6dec0a, 0x113ba278, 0x07a5ae9c, 0x28c4da6e, 0x023e97b2, 0x06aaf087, 0x29ec5301, 0x33a4ed67, 0xe60f}}, - {{0x29616821, 0x07ccb339, 0x0d23f0be, 0x25a24791, 0x39371012, 0x267cd3d5, 0x195929db, 0x141ce679, 0xf7e3}}}, - /* 3*16^1*G: */ - {{{0x1118e5c3, 0x2f61c2a8, 0x12bebc19, 0x15e6c9d1, 0x265b4bfc, 0x0595bbd3, 0x1307db44, 0x0cd76591, 0x6eca}}, - {{0x05a08668, 0x2628bde0, 0x3f8ec344, 0x125a8e8e, 0x3875a03a, 0x3d5e41d2, 0x20710592, 0x08ed5e9e, 0xd501}}}, - /* 5*16^1*G: */ - {{{0x0f87f62e, 0x3b34c785, 0x37161270, 0x39b98e18, 0x0659f010, 0x31d13b4d, 0x390ec0d7, 0x0eefbc6f, 0xe962}}, - {{0x244ee737, 0x0c04fabe, 0x168844e5, 0x1810f277, 0x1aa929fe, 0x3a54ea3b, 0x299e9e0f, 0x1d0ed2f0, 0x38a9}}}, - /* 7*16^1*G: */ - {{{0x2a8d733c, 0x2c2ab7e0, 0x2fca8f9e, 0x309d2fd8, 0x00d682ff, 0x128dbc82, 0x21dba088, 0x375cf945, 0xbc82}}, - {{0x347797f0, 0x39e18413, 0x33897301, 0x24e82eb9, 0x1f02dfae, 0x26d2fdc6, 0x31cac54a, 0x230e8112, 0xe5f2}}}, - /* 9*16^1*G: */ - {{{0x1fbc7671, 0x1fbf88c5, 0x2858e32d, 0x0fc6f214, 0x18f49074, 0x0a47385e, 0x17211d20, 0x049231d9, 0x8e3d}}, - {{0x18717dec, 0x3bc77190, 0x23e144a7, 0x0d4aeaa9, 0x13e90eb9, 0x1203864e, 0x3cb81f64, 0x123843b3, 0x099a}}}, - /* 11*16^1*G: */ - {{{0x3eb31db2, 0x0ca1d0ca, 0x0f506a0f, 0x32ba09e2, 0x08a2b68f, 0x2864fb42, 0x0a498896, 0x246a888d, 0x78a8}}, - {{0x39fa4343, 0x01a7588e, 0x000b82d3, 0x0de6f376, 0x302df654, 0x17c9549c, 0x035cbfcf, 0x28d6fad4, 0x6912}}}, - /* 13*16^1*G: */ - {{{0x0db0e595, 0x14d23dde, 0x3a082bb6, 0x058f2e7e, 0x2076eba7, 0x38dd9605, 0x31b17d7c, 0x1e061576, 0x7d86}}, - {{0x3c733de8, 0x265478ea, 0x225d5329, 0x0de11383, 0x0f883829, 0x18b8afb5, 0x2f8772e5, 0x26b7fb21, 0xe2b9}}}, - /* 15*16^1*G: */ - {{{0x16060dfc, 0x023fbe14, 0x05e6a2a0, 0x1517e108, 0x1ab08676, 0x252e7710, 0x02ac8484, 0x0c43c016, 0xddc5}}, - {{0x27820ca8, 0x2d7e2adb, 0x3d04730f, 0x36ebf1aa, 0x0f0e9041, 0x06adb732, 0x19692019, 0x0bcebc83, 0xba0d}}} - }, - { - /* 1*16^2*G: */ - {{{0x15f51508, 0x191b88ff, 0x1ac1ca10, 0x30e72af5, 0x2de238d8, 0x29b8f85c, 0x209d9ea2, 0x098c84b1, 0x8282}}, - {{0x36e26caf, 0x0c6dbabf, 0x37b17bed, 0x3584eb0b, 0x360ace62, 0x095ba0c2, 0x3dfe45e8, 0x2a026155, 0x11f8}}}, - /* 3*16^2*G: */ - {{{0x257e8dfa, 0x33f032e7, 0x3c7e184f, 0x20246468, 0x298ca009, 0x28c3e2b2, 0x19c4c0d9, 0x33cbfc1e, 0x8262}}, - {{0x3bac376a, 0x173fe363, 0x314c4783, 0x2dbb4cca, 0x334f3457, 0x3b88bb16, 0x09e4e66f, 0x25788244, 0x83fd}}}, - /* 5*16^2*G: */ - {{{0x026bdb6f, 0x014b922c, 0x3734b949, 0x2906f51e, 0x299c877c, 0x0416c933, 0x0ddd5168, 0x1722c768, 0x1982}}, - {{0x049cfc9b, 0x177dc213, 0x0f6d3a6b, 0x3a7bb323, 0x359f6ceb, 0x09873253, 0x0878f320, 0x0c43c353, 0x6294}}}, - /* 7*16^2*G: */ - {{{0x3d82824c, 0x03b42548, 0x21534e65, 0x29638d17, 0x02999edf, 0x17d5bb1b, 0x0191443c, 0x361b0458, 0x6f12}}, - {{0x06eb34d0, 0x15e70d20, 0x054bc5b8, 0x07249042, 0x22376939, 0x2653cff5, 0x3bfa0875, 0x3dfd12ac, 0x5c4f}}}, - /* 9*16^2*G: */ - {{{0x1b453629, 0x1db7700b, 0x359e6030, 0x33f73703, 0x3abef645, 0x189c5a88, 0x2aa5d142, 0x231be682, 0x203a}}, - {{0x3ff89f84, 0x25c71e14, 0x1285ed45, 0x1b7ac971, 0x01061268, 0x31db457d, 0x1d9b936c, 0x02d4f797, 0x3b0f}}}, - /* 11*16^2*G: */ - {{{0x246c7ecb, 0x20c4c377, 0x1bb4ce97, 0x0ebb4ff9, 0x26e1ec9d, 0x3bdccd21, 0x34181c81, 0x32bacf40, 0x6e2a}}, - {{0x2ebc8720, 0x1124807b, 0x367512c8, 0x31c1ae46, 0x3b643afa, 0x03136bc3, 0x3ee149d8, 0x2919e5fb, 0x9e61}}}, - /* 13*16^2*G: */ - {{{0x30a4147e, 0x2dc063cf, 0x375f201e, 0x11f762fd, 0x090a5827, 0x05c5fa29, 0x1156baf6, 0x0124ba7a, 0xd5a7}}, - {{0x33fb65ff, 0x392cf2e0, 0x167f57f8, 0x3136611e, 0x1e0532f4, 0x242641d9, 0x389c6fc4, 0x09bd76ea, 0x9db5}}}, - /* 15*16^2*G: */ - {{{0x18edcec6, 0x3b76d1af, 0x3634f454, 0x018730b4, 0x2cdac6a1, 0x0fbf18c0, 0x18ba8052, 0x0466aaf8, 0x38c5}}, - {{0x1933db08, 0x15b82fec, 0x35530a64, 0x285b208a, 0x1f282f28, 0x32cb689d, 0x1732a668, 0x3748a176, 0xe649}}} - }, - { - /* 1*16^3*G: */ - {{{0x11e5b739, 0x0ff396d5, 0x12222ed7, 0x2e4e0cff, 0x3c846de0, 0x26731b1b, 0x3865a72f, 0x0567dca2, 0x175e}}, - {{0x29fed695, 0x3be9bffb, 0x124345c6, 0x2d6556b7, 0x371f5eac, 0x3e5e947f, 0x079eba4e, 0x1b83678f, 0xd350}}}, - /* 3*16^3*G: */ - {{{0x05041216, 0x16dfe3c7, 0x02b836a6, 0x1ccd7da1, 0x2fed523f, 0x2d67bf70, 0x3acf4128, 0x0c5ec87d, 0xda75}}, - {{0x2e708572, 0x2bb4ca61, 0x37acedad, 0x2ab01eb9, 0x2d7fc6e9, 0x27886cd0, 0x2d5f0df1, 0x2811afdc, 0x73f8}}}, - /* 5*16^3*G: */ - {{{0x2465a930, 0x0050f9c7, 0x31352fdb, 0x21fc705a, 0x02eb1e25, 0x0f16312a, 0x349d7057, 0x316d23a5, 0x1c71}}, - {{0x034638b5, 0x361cfdb3, 0x3174d471, 0x0d178fed, 0x0bb68c79, 0x0fc7ca09, 0x1fa0c271, 0x30cd3a3d, 0x4a91}}}, - /* 7*16^3*G: */ - {{{0x3adb6ee7, 0x0c636b96, 0x344a077e, 0x143750c9, 0x1b4c9c78, 0x3a0dea42, 0x1a566936, 0x12bf07cc, 0xd84e}}, - {{0x142ebed2, 0x0b555b9b, 0x2a3e6498, 0x362b25d2, 0x25de4dfd, 0x0e3563d5, 0x379ce12a, 0x20269f1e, 0xe525}}}, - /* 9*16^3*G: */ - {{{0x249e6d10, 0x253a7b3e, 0x2ac99d23, 0x02b7fceb, 0x3f6ed3f6, 0x08ae4a17, 0x2814d41b, 0x1112f799, 0xf3d4}}, - {{0x1347da3f, 0x280e3301, 0x29d6c630, 0x06b69433, 0x0a4b5bfc, 0x2e56b066, 0x0163d4ba, 0x0937e9bc, 0x0a43}}}, - /* 11*16^3*G: */ - {{{0x29d33a07, 0x232cd01b, 0x239bcab4, 0x1cbb822a, 0x3df4044e, 0x21548336, 0x01d89f90, 0x194b2767, 0xae30}}, - {{0x20a0b2a6, 0x121c303d, 0x3d7e95c7, 0x270dfd77, 0x38d5cf1c, 0x339f4cf6, 0x3fe57efc, 0x3670e358, 0x6cb9}}}, - /* 13*16^3*G: */ - {{{0x0c28caca, 0x165952e4, 0x08281da7, 0x1a71eef3, 0x388c9a18, 0x05f9d60c, 0x1e1c815e, 0x06ca96f5, 0xd8dc}}, - {{0x23b3ec7a, 0x36d9dba8, 0x08128f6c, 0x0c574b3b, 0x247d947d, 0x36369080, 0x2c7d58c6, 0x02b649f3, 0x8cec}}}, - /* 15*16^3*G: */ - {{{0x3bc4416f, 0x2487ed98, 0x30b04028, 0x2bbf48fc, 0x32f31da7, 0x1096a340, 0x04eccd59, 0x38a4b17e, 0x2749}}, - {{0x3c6bbd8e, 0x3a62f78b, 0x2e961057, 0x27a7ed97, 0x0adb3ef5, 0x3652643f, 0x32bc4403, 0x0b538dd9, 0x50cc}}} - }, - { - /* 1*16^4*G: */ - {{{0x03ff4640, 0x09aeb63e, 0x1552ffe5, 0x11071f95, 0x262ee053, 0x3ab016d8, 0x00c9c99c, 0x243511ec, 0x363d}}, - {{0x3bee9de9, 0x0800f1fc, 0x0199ecb6, 0x2e6a2402, 0x33363145, 0x2d114e5f, 0x32221953, 0x1ceb7f1c, 0x04e2}}}, - /* 3*16^4*G: */ - {{{0x36e55dc8, 0x2e24485b, 0x2ca04394, 0x3e56adba, 0x1094426f, 0x12910301, 0x1ffb2ba8, 0x1011e431, 0x4431}}, - {{0x1be323b3, 0x076512bb, 0x2aa2e503, 0x1a8a6de7, 0x02fed7a6, 0x260dfd59, 0x366f8fe9, 0x3050b994, 0x96b0}}}, - /* 5*16^4*G: */ - {{{0x301b23a8, 0x3fa52175, 0x287ee0ad, 0x1edf51c2, 0x21089dab, 0x090f56e4, 0x0a87c126, 0x3fa3619b, 0x9e22}}, - {{0x0884edae, 0x1e904f14, 0x3511cecf, 0x3df2527e, 0x1c1533c0, 0x3cfc0826, 0x22d10177, 0x3c3a7284, 0xfd2f}}}, - /* 7*16^4*G: */ - {{{0x071a70e4, 0x35d022fc, 0x35cf475d, 0x17b947d7, 0x05306dcd, 0x35a7991c, 0x22a8d2ed, 0x3db540f3, 0x508d}}, - {{0x29950984, 0x3cb96fdc, 0x28aadfed, 0x300c8a3b, 0x3e49c54e, 0x0c12a9cc, 0x3c42d777, 0x10e6e4ce, 0x154c}}}, - /* 9*16^4*G: */ - {{{0x0e1abe11, 0x3abf69db, 0x1cb220f6, 0x2e487096, 0x0125b2da, 0x37d6064c, 0x09763338, 0x3fe11544, 0xe3db}}, - {{0x1fa8de63, 0x2d26b552, 0x06b5c414, 0x325f640f, 0x0a8ef3d3, 0x23e9d76e, 0x01421643, 0x3e42668d, 0x06f2}}}, - /* 11*16^4*G: */ - {{{0x03593449, 0x33c6c8d8, 0x02a46ffd, 0x06df04b9, 0x3d014af6, 0x36704e81, 0x2940d878, 0x381931f7, 0x19ac}}, - {{0x2df83631, 0x29052e4e, 0x084068a3, 0x1c42e7d0, 0x002c46ac, 0x2f5ce765, 0x0a333bfe, 0x2480d49a, 0xe379}}}, - /* 13*16^4*G: */ - {{{0x0cba6b63, 0x38fa624b, 0x10b3bb5e, 0x03f99d3f, 0x288e310a, 0x30cc8a3a, 0x07daa108, 0x033b083e, 0xd874}}, - {{0x2934c5f3, 0x3ba8db01, 0x381694ab, 0x0413d730, 0x3ac37d40, 0x29bba640, 0x132bf378, 0x304cf1ae, 0x6472}}}, - /* 15*16^4*G: */ - {{{0x1b3ec038, 0x0653fcb0, 0x20c6b276, 0x3f545ab9, 0x290a50d9, 0x20f9d8bc, 0x06083648, 0x0cce46d4, 0x58ac}}, - {{0x10246279, 0x1baa8fc4, 0x34fbbca1, 0x06410f02, 0x11fe9702, 0x1e4927a6, 0x092d9787, 0x35c1b557, 0x9163}}} - }, - { - /* 1*16^5*G: */ - {{{0x1ffdf80c, 0x27de6957, 0x15bcd1b6, 0x3929e068, 0x05638843, 0x0912d6dd, 0x3c2be8c6, 0x17c5977c, 0x8b4b}}, - {{0x1fd4fd36, 0x0fbfc319, 0x162ee56b, 0x38cd9518, 0x30da04f9, 0x2f5e04ea, 0x308b4b3f, 0x029bda34, 0x4aad}}}, - /* 3*16^5*G: */ - {{{0x355812dd, 0x028a960b, 0x12d30e2a, 0x1119c8d5, 0x18f78e3d, 0x2afb5b01, 0x3352f0b6, 0x2f5ea4bf, 0x7029}}, - {{0x1a2d2927, 0x087319ac, 0x3b2c73c7, 0x36ba1090, 0x0683ac47, 0x19512b8c, 0x0b3d27dd, 0x3eb6bf7a, 0xb0ee}}}, - /* 5*16^5*G: */ - {{{0x3d486ed1, 0x27395a0e, 0x1565b6a4, 0x116fae92, 0x0f756057, 0x35042763, 0x25c99009, 0x3b72bab9, 0x9ccf}}, - {{0x35e95d8d, 0x3db567b5, 0x1592aa24, 0x0859d65a, 0x0b341124, 0x08920480, 0x232cfb61, 0x135c4f5a, 0x7c2f}}}, - /* 7*16^5*G: */ - {{{0x1bd0eaca, 0x081ac69d, 0x22d4ab7a, 0x31d15dae, 0x24df19d0, 0x23f78cf2, 0x1414335a, 0x12e1d8d0, 0xcd9a}}, - {{0x2bff4acc, 0x39bebed6, 0x16f634f6, 0x09ece3bb, 0x3ea08b01, 0x1222ba4c, 0x0f23e815, 0x161e687a, 0xf045}}}, - /* 9*16^5*G: */ - {{{0x07bc57c6, 0x08254e8f, 0x2b276cbf, 0x00f5e88f, 0x16309449, 0x3cb4ba4f, 0x19bea884, 0x220be23b, 0xad09}}, - {{0x2e4a0ab8, 0x28cb03b6, 0x190e2d3c, 0x0c474dcd, 0x1abe5f7b, 0x061b1ca7, 0x3a52ba28, 0x302310be, 0x7243}}}, - /* 11*16^5*G: */ - {{{0x2ba56302, 0x2a0c31ca, 0x30f1862e, 0x01aa4deb, 0x3ad2e0f5, 0x368b4aa7, 0x0a41f1ea, 0x0a42bacf, 0xd9d1}}, - {{0x08291c29, 0x2ab76bea, 0x3a74f2ae, 0x0e6bb367, 0x2386e417, 0x1c5719c9, 0x13eed029, 0x0c44fb0b, 0x7eb5}}}, - /* 13*16^5*G: */ - {{{0x34d1243a, 0x2b34dc13, 0x354a5fdb, 0x2c49808f, 0x3f558402, 0x3486b018, 0x16cef91c, 0x1e7794e7, 0xbc50}}, - {{0x055db68a, 0x172545a2, 0x1f47169f, 0x1fb93d6c, 0x3fc8d75f, 0x31cae537, 0x05cbb8ee, 0x0a8ece9c, 0x6506}}}, - /* 15*16^5*G: */ - {{{0x374a3f9f, 0x2349139a, 0x00981690, 0x21e99977, 0x32625ac2, 0x37aab9f6, 0x3c7e8913, 0x29df9417, 0x4d31}}, - {{0x301e0ba7, 0x3f2c0904, 0x2e00a754, 0x3dbed46d, 0x002753cb, 0x063ce31e, 0x0575b06b, 0x07b25826, 0x2224}}} - }, - { - /* 1*16^6*G: */ - {{{0x1232fcda, 0x2d845649, 0x2c0e77bc, 0x0036ffe9, 0x1548c7b7, 0x1dc7002f, 0x3996d6bf, 0x2ea9b976, 0x723c}}, - {{0x1eb39f5f, 0x07701a76, 0x37949480, 0x1828194d, 0x024d6e26, 0x044dd222, 0x0c498a92, 0x19ed5657, 0x96e8}}}, - /* 3*16^6*G: */ - {{{0x00633cb1, 0x159f827a, 0x1d021132, 0x168892da, 0x181fcb57, 0x189cc848, 0x2cad400c, 0x273cc5ea, 0x6dde}}, - {{0x27ce6b34, 0x1f7526a9, 0x3859ef35, 0x2c9ff6b3, 0x3a66a880, 0x27be1a86, 0x3e41d5c9, 0x3ef9e9c1, 0x9188}}}, - /* 5*16^6*G: */ - {{{0x2933f3c5, 0x06694634, 0x1f125224, 0x1683dc45, 0x07b85008, 0x12edfe39, 0x1cde813c, 0x29cb356d, 0x486f}}, - {{0x0afb0f53, 0x2b529c6b, 0x30f23b79, 0x366de0f3, 0x08f19f62, 0x3122ebb3, 0x3dd43e48, 0x08c67d5a, 0x62e1}}}, - /* 7*16^6*G: */ - {{{0x1e99f728, 0x2f565089, 0x2f12204e, 0x1cdd7ef9, 0x2a530367, 0x13fc9edd, 0x0af4fb66, 0x1a5d2a25, 0x2479}}, - {{0x2baaebff, 0x1e80145b, 0x175a2d83, 0x36fcf025, 0x0d664a5a, 0x0ba1f9f6, 0x33001ec5, 0x23511a23, 0xe3d7}}}, - /* 9*16^6*G: */ - {{{0x2fb0079a, 0x27831b50, 0x3926049c, 0x1be7bdc8, 0x33832491, 0x2967b9da, 0x15ff0631, 0x32f6a8f5, 0x2f39}}, - {{0x2c5690ba, 0x388a5cc0, 0x02a0230f, 0x3ecfef22, 0x0da58b9b, 0x24db409e, 0x239834da, 0x36f784e1, 0xabea}}}, - /* 11*16^6*G: */ - {{{0x24f7ab73, 0x24cc02cb, 0x14443a77, 0x38f53aa7, 0x34aed262, 0x0e7a1b14, 0x161ba56a, 0x075b0c9f, 0xe5a3}}, - {{0x30561f42, 0x244e8ff1, 0x00cba213, 0x2311126a, 0x0ece5dbf, 0x062a5de9, 0x29d7a0c1, 0x230f6347, 0x3778}}}, - /* 13*16^6*G: */ - {{{0x014dcd86, 0x23e4a68f, 0x2bf71b58, 0x31750825, 0x11dcf11f, 0x03766081, 0x13447df5, 0x27528345, 0xcc38}}, - {{0x08f0a873, 0x23adb767, 0x27e78746, 0x315f863f, 0x2910ca05, 0x1a2f6efa, 0x2bbed9b5, 0x13f5983d, 0x93ae}}}, - /* 15*16^6*G: */ - {{{0x38819311, 0x13e71bad, 0x08771472, 0x0f87b884, 0x35ed1f0b, 0x0285f833, 0x1e902375, 0x2472275c, 0x7f92}}, - {{0x2c2eb125, 0x2a7e6d5e, 0x086a174a, 0x02aa9027, 0x2415b612, 0x037a3114, 0x03ef0f5d, 0x034418fb, 0x9da0}}} - }, - { - /* 1*16^7*G: */ - {{{0x0e7dd7fa, 0x294cfb28, 0x3a919839, 0x11e5848d, 0x02d3b509, 0x3fbb204b, 0x2bf98ba5, 0x293524ef, 0xeebf}}, - {{0x21de8999, 0x37f53f6b, 0x311f712d, 0x393370e9, 0x38089d9a, 0x39fb6bc5, 0x2f0f269e, 0x2328e5c3, 0x5d9a}}}, - /* 3*16^7*G: */ - {{{0x3b7ceceb, 0x0fd9e3fe, 0x097faf0f, 0x2967e4e2, 0x2e681473, 0x3ee049bd, 0x2d45036f, 0x2188109d, 0x437a}}, - {{0x16c181e1, 0x0d8ef30d, 0x08f97827, 0x0883f3f7, 0x1297ff87, 0x23fada67, 0x2c32f69b, 0x1ae84fba, 0x0b91}}}, - /* 5*16^7*G: */ - {{{0x097f96f2, 0x1635ca78, 0x2c8735cd, 0x208d4a74, 0x3cc27335, 0x2df8ee68, 0x089bc83c, 0x27c4f8a9, 0xa9ef}}, - {{0x16c04be4, 0x00f556c1, 0x29b4702c, 0x13e26bd6, 0x3b613db7, 0x1bb8583a, 0x19d7cd95, 0x33396515, 0xe814}}}, - /* 7*16^7*G: */ - {{{0x350cf77e, 0x302ad684, 0x0a8ab0db, 0x36fd5d15, 0x2a064207, 0x209f5a7e, 0x135be553, 0x01507b87, 0x66d8}}, - {{0x20eaa3a6, 0x297e5ebe, 0x3b1b76d2, 0x112d0ead, 0x1613f694, 0x0750814d, 0x3fb42c3f, 0x37f9ccbf, 0x51cf}}}, - /* 9*16^7*G: */ - {{{0x07213a5a, 0x0d5218a2, 0x05fa62b9, 0x1cc8129e, 0x0cc3c80b, 0x14228719, 0x03fa2bf3, 0x01784d94, 0x62ac}}, - {{0x346a9e45, 0x04348703, 0x17994efc, 0x16424060, 0x292579e5, 0x179e781e, 0x1a6e4d39, 0x2f7ce834, 0x236f}}}, - /* 11*16^7*G: */ - {{{0x27bad12b, 0x0c3f5261, 0x2f66e1ec, 0x357a803a, 0x2f2db385, 0x184ebd71, 0x08f5b5bf, 0x31125c91, 0xca13}}, - {{0x1723b0f2, 0x25a67d1a, 0x1a575668, 0x1c2adc44, 0x2da3d663, 0x17e993aa, 0x287c8ac1, 0x0260d870, 0x83aa}}}, - /* 13*16^7*G: */ - {{{0x1c80414e, 0x36bb97e5, 0x166cf7fd, 0x3be2a18b, 0x209e4914, 0x04713d11, 0x12ae85ac, 0x2c4069c1, 0x1cec}}, - {{0x12169a3b, 0x32ba524b, 0x07231d0d, 0x1d55f951, 0x2dad1690, 0x2a8ca0d7, 0x17cfb4e5, 0x1819a582, 0xf343}}}, - /* 15*16^7*G: */ - {{{0x0ed810a9, 0x13d6f231, 0x0700155c, 0x22274fcf, 0x1f23924f, 0x036bd7c7, 0x38f9cc95, 0x241d4135, 0x2a69}}, - {{0x3a9b4728, 0x3e1ace23, 0x2c145c7c, 0x1f51fa5f, 0x3b04fc66, 0x3161a553, 0x1ffdac3e, 0x00e6db0f, 0x54f9}}} - }, - { - /* 1*16^8*G: */ - {{{0x39a48db0, 0x3f5e0d6c, 0x33c03bfe, 0x048568a6, 0x3bde459f, 0x0742826d, 0x27167279, 0x11369a5b, 0x100f}}, - {{0x2bc65a09, 0x3ef57358, 0x35195ac0, 0x3fd2863f, 0x090666b7, 0x23ccc030, 0x00b772ec, 0x384c64a8, 0xcdd9}}}, - /* 3*16^8*G: */ - {{{0x15bc15b4, 0x32e684d2, 0x25a2ee69, 0x1d40a391, 0x17ca8d92, 0x163ba73b, 0x2adc9ed8, 0x038b947b, 0x10e9}}, - {{0x18aa258d, 0x13af9825, 0x2bb6a883, 0x296258c0, 0x2d1f754c, 0x1ea3185a, 0x1e0424d5, 0x0dc0e035, 0xc68a}}}, - /* 5*16^8*G: */ - {{{0x3fe75269, 0x374ff0c0, 0x13d33182, 0x1de8f301, 0x0b7dcda3, 0x16e42dc5, 0x01638457, 0x0bd0b695, 0xf742}}, - {{0x17e49bd5, 0x22603a1c, 0x0a398e01, 0x2ce88dfd, 0x3635977f, 0x339f72e7, 0x3093fd18, 0x0bc68cc4, 0x406c}}}, - /* 7*16^8*G: */ - {{{0x35a7175f, 0x14ed9a5b, 0x31cf42a6, 0x2e39dc74, 0x15debbed, 0x1e69560b, 0x03cff728, 0x2b4105f5, 0x2d8c}}, - {{0x3b9d592a, 0x3cdeee46, 0x0b5e5e0c, 0x211aff67, 0x2c9d377a, 0x08cbe984, 0x0a94a7bb, 0x0ee0cc63, 0xc73f}}}, - /* 9*16^8*G: */ - {{{0x14b51045, 0x0d326f0e, 0x31c25b3e, 0x31b225bc, 0x28cf73bb, 0x1cf53ac7, 0x26ea58ae, 0x3f476e62, 0x1ecb}}, - {{0x02c70026, 0x0e99c404, 0x036422d5, 0x240191ad, 0x1a9b38b1, 0x342ec612, 0x1c3a6447, 0x388c22e6, 0x1cf6}}}, - /* 11*16^8*G: */ - {{{0x29358533, 0x1eb35d9b, 0x0fb4b9df, 0x2a4cfe75, 0x132a8c10, 0x25568a47, 0x3752883e, 0x25317f95, 0x9a08}}, - {{0x0360ba08, 0x2cf87177, 0x380ddadf, 0x29b96f6e, 0x0fc32165, 0x05f57e55, 0x38fc31f9, 0x20f10806, 0xa798}}}, - /* 13*16^8*G: */ - {{{0x198ef7f6, 0x25101758, 0x2078f9f6, 0x08fcfdde, 0x38aea659, 0x272149ce, 0x3d2e35bd, 0x361276d3, 0x664d}}, - {{0x1d1eac94, 0x1d25bfcd, 0x38e6ecee, 0x0f4eacc6, 0x0458cffc, 0x12339774, 0x27932a14, 0x0805c5fc, 0xad51}}}, - /* 15*16^8*G: */ - {{{0x03c934b3, 0x03029adf, 0x30ae2c4e, 0x0c7d6016, 0x11a7022b, 0x07659a60, 0x0b863823, 0x0ea4ddf4, 0x8211}}, - {{0x042c6a0f, 0x1f9798ab, 0x24468037, 0x07df09a6, 0x20c628aa, 0x19b3cad6, 0x23666084, 0x2e36b26b, 0x8da1}}} - }, - { - /* 1*16^9*G: */ - {{{0x2534fd2d, 0x322b379b, 0x0f3b3852, 0x1fe35119, 0x04c017a7, 0x2489e928, 0x3ed1b1dc, 0x06f898b1, 0xe103}}, - {{0x1456a00d, 0x113c63ca, 0x21ced79a, 0x24b75067, 0x17535af2, 0x1a905d96, 0x0405e6bb, 0x1864a250, 0x9d70}}}, - /* 3*16^9*G: */ - {{{0x2f028d83, 0x1e588ebb, 0x27439615, 0x25649b6e, 0x1e69db61, 0x2af96857, 0x385ec6a5, 0x3df138f1, 0xa7eb}}, - {{0x19d0bed1, 0x1900e4ae, 0x30539199, 0x28e249d2, 0x04804b47, 0x271cddc1, 0x362d5cfd, 0x054beff8, 0x6205}}}, - /* 5*16^9*G: */ - {{{0x27dd5cfa, 0x2b839008, 0x309d4b5b, 0x227144df, 0x2346336a, 0x31a94d09, 0x24f4c1cd, 0x282372c0, 0x5b5c}}, - {{0x1e48e98c, 0x19929be6, 0x33269d3e, 0x3419f32b, 0x069094bf, 0x07c33aa2, 0x15825e99, 0x2dbdc2a8, 0x3ecc}}}, - /* 7*16^9*G: */ - {{{0x23531f82, 0x2e54a38c, 0x10c2c9f2, 0x144c9aec, 0x022c29ff, 0x3cf9d227, 0x14bb5cce, 0x09ab3044, 0x046f}}, - {{0x0bceda07, 0x1417f22c, 0x2b55c7fa, 0x09651736, 0x032579d0, 0x0dc2b0bf, 0x382eace2, 0x12cc58d6, 0x6b80}}}, - /* 9*16^9*G: */ - {{{0x10432711, 0x02c550dc, 0x1916b906, 0x0502cbf7, 0x19645acf, 0x25bc3c22, 0x0efb535f, 0x09b64c78, 0xc119}}, - {{0x2fe2610c, 0x1249878b, 0x0f34055e, 0x2ae48b28, 0x0cc6cf83, 0x252fc61b, 0x1b689184, 0x3e331f49, 0x8be1}}}, - /* 11*16^9*G: */ - {{{0x21257963, 0x05e61d3e, 0x34aa861c, 0x006354b0, 0x0979c45b, 0x2ed52d4e, 0x08f2e6cd, 0x11ba7ada, 0x6908}}, - {{0x066f9835, 0x295d9665, 0x1c92b253, 0x2f0f2a08, 0x2fbb7f6c, 0x05c093e4, 0x3ebc5b40, 0x17f2dfcf, 0xe248}}}, - /* 13*16^9*G: */ - {{{0x1ee23ace, 0x3444e52f, 0x14dd2fd2, 0x321f196d, 0x232915de, 0x1d54b7d2, 0x220babba, 0x3dfee324, 0xfb3d}}, - {{0x1722e8de, 0x0277bd32, 0x2d27f5ee, 0x1c9c50bf, 0x3ab58a9e, 0x09455036, 0x33c5652a, 0x0a6f0471, 0x510e}}}, - /* 15*16^9*G: */ - {{{0x10272351, 0x181f3fbd, 0x19ff1098, 0x1cd2cf7e, 0x31cd4170, 0x228facea, 0x0518b3eb, 0x17b093d7, 0x6dd8}}, - {{0x3fc7664b, 0x2c1fe8ad, 0x3e0817c9, 0x1f1bfdf0, 0x1c41b787, 0x101fe6bd, 0x3427e09d, 0x19fd0487, 0x16ea}}} - }, - { - /* 1*16^10*G: */ - {{{0x1094696d, 0x3579a236, 0x01d6af52, 0x3e2c99a9, 0x3bd7ec5c, 0x0a0e7c50, 0x15b530ac, 0x1b2b91b5, 0xfeea}}, - {{0x18090088, 0x05577afc, 0x041442d3, 0x072255f3, 0x3ecd5c98, 0x39384afc, 0x0e1bab06, 0x1adb25f7, 0xe57c}}}, - /* 3*16^10*G: */ - {{{0x08dfd587, 0x1e4d86ed, 0x1b026560, 0x312e8e32, 0x35a12d5e, 0x19eaa8b3, 0x0508b348, 0x2d06eb3d, 0x5084}}, - {{0x11470e89, 0x39e7a5fe, 0x091f5606, 0x2dbd581a, 0x2927475d, 0x2a9b2154, 0x00d31619, 0x18c68766, 0x34a9}}}, - /* 5*16^10*G: */ - {{{0x3ab34cc6, 0x0208c985, 0x0f30a12d, 0x030a5d9f, 0x0d7128c8, 0x2cfc7f46, 0x2d5ea53f, 0x300f8190, 0x4f14}}, - {{0x187e681f, 0x17b094be, 0x281dd022, 0x378f33a3, 0x262540b9, 0x0e9c3d0e, 0x0e894c65, 0x342a32a9, 0x7b53}}}, - /* 7*16^10*G: */ - {{{0x1241d90d, 0x109dc404, 0x32444f83, 0x073c5076, 0x1dd363e8, 0x10d8257b, 0x39ed1d41, 0x2e1f9271, 0xa74d}}, - {{0x3f7adad4, 0x0c9462e0, 0x0a0a313f, 0x3b9424d1, 0x0171c8a9, 0x37422962, 0x3eef327f, 0x24736bc8, 0xf786}}}, - /* 9*16^10*G: */ - {{{0x31c1ae1f, 0x17b32888, 0x2cd40b2a, 0x1b9631a2, 0x23565845, 0x373513ae, 0x2a2cf9ac, 0x3e95d12e, 0x6901}}, - {{0x122838b0, 0x3e0cc197, 0x1c77a930, 0x27cee979, 0x1c900dd7, 0x2d4e030a, 0x3c212461, 0x1722089c, 0x35de}}}, - /* 11*16^10*G: */ - {{{0x327a4bdb, 0x2c0c4206, 0x1494cac4, 0x1a9b410d, 0x3ba35d04, 0x12d90fc6, 0x38127a24, 0x360b4750, 0x8d3c}}, - {{0x269a8a2c, 0x0f4d31f3, 0x30ad296c, 0x38e01f4d, 0x36236ed4, 0x3efe7401, 0x241f470c, 0x0958603b, 0x9bd4}}}, - /* 13*16^10*G: */ - {{{0x34ec1d2d, 0x10334f1a, 0x27d8f454, 0x0267d71b, 0x3b691fd9, 0x2759ca59, 0x24739afe, 0x20d8f581, 0xeaf9}}, - {{0x0c838452, 0x33f9d581, 0x3e84b53f, 0x3d4b5515, 0x3199aaa9, 0x08a2839a, 0x38d22775, 0x060e9ff9, 0xe518}}}, - /* 15*16^10*G: */ - {{{0x045ae767, 0x32cd6fdc, 0x289771cb, 0x1cea72e7, 0x06e5d8c2, 0x103814b0, 0x1b63466f, 0x2f458ebb, 0xfb95}}, - {{0x3bbf0e11, 0x214fa82b, 0x259f1341, 0x05bd1c62, 0x02275bb8, 0x013674da, 0x0ddbc520, 0x0536046a, 0x664c}}} - }, - { - /* 1*16^11*G: */ - {{{0x01ec6cb1, 0x0fea5e2f, 0x08583de3, 0x3b595f60, 0x3fca3cfe, 0x1ef92f9b, 0x09cdcb36, 0x2a476441, 0xda67}}, - {{0x3a68be1d, 0x3a7aa389, 0x0f740a17, 0x31eb7142, 0x1780e5de, 0x118fdfb2, 0x242bc41f, 0x2a8d5205, 0x9bac}}}, - /* 3*16^11*G: */ - {{{0x15bc8a44, 0x3bf74194, 0x3e151a19, 0x10405df2, 0x1a5fc768, 0x159692e9, 0x0eda3d38, 0x20160f3f, 0x4d01}}, - {{0x1adbc09e, 0x3c7e5324, 0x182da362, 0x250811a1, 0x16381396, 0x26ea001f, 0x0f5d367e, 0x31b0632d, 0x3a33}}}, - /* 5*16^11*G: */ - {{{0x25daeb00, 0x306ad4a1, 0x2645f76b, 0x08fac933, 0x36e9d159, 0x32da89ce, 0x0f957082, 0x0541f7d7, 0x2f66}}, - {{0x033992c0, 0x089d9e26, 0x15d308c1, 0x337b89c6, 0x00add06e, 0x254dea08, 0x2b33f6ef, 0x0484dbd4, 0xfd5c}}}, - /* 7*16^11*G: */ - {{{0x116aa6d9, 0x20aa4282, 0x3702dcf1, 0x18b22d91, 0x035a3836, 0x3c5d3686, 0x247d2254, 0x045f417f, 0xf594}}, - {{0x3f2e50cf, 0x1f41a5ba, 0x26b5b86c, 0x249de20f, 0x14bceb7a, 0x176f6ac2, 0x31b12cf6, 0x18695ba5, 0xcaa7}}}, - /* 9*16^11*G: */ - {{{0x3ac6f4c0, 0x2ab80e55, 0x04bdc4cc, 0x13a37a33, 0x16711dda, 0x070e2f9a, 0x19cdec4e, 0x135fc7d3, 0x0f2d}}, - {{0x32339b58, 0x1f9eeeb5, 0x0242656e, 0x1a8429e4, 0x01e71e8f, 0x2c9ff7ce, 0x3de4d17f, 0x27e15fa4, 0x3ec8}}}, - /* 11*16^11*G: */ - {{{0x1f428cb2, 0x215414ff, 0x2a22b55d, 0x0e08bf59, 0x18d0f123, 0x1e860565, 0x14bbd1eb, 0x33b0b8a8, 0x1d5d}}, - {{0x095b189b, 0x397b4402, 0x36044a51, 0x0fa44be1, 0x2f0b88bd, 0x1e1e0921, 0x2c8c50d0, 0x1020ec50, 0x6e5c}}}, - /* 13*16^11*G: */ - {{{0x28381273, 0x2c3aa23e, 0x293dae5f, 0x10dda581, 0x0126ced8, 0x3aa6cb31, 0x167439fd, 0x28bf4c02, 0x89d9}}, - {{0x1309773d, 0x00facfbb, 0x1127324a, 0x1875a02b, 0x0f62f58f, 0x2abc81db, 0x26f50377, 0x096d1475, 0xdfca}}}, - /* 15*16^11*G: */ - {{{0x35c71d91, 0x330cacb2, 0x2894fd21, 0x25178b8a, 0x1afece23, 0x28704c45, 0x10ae1c52, 0x06e1e0e9, 0x8319}}, - {{0x22148a61, 0x02e7b023, 0x10445ee7, 0x2847d45d, 0x3cae8a17, 0x1b784f45, 0x01b709e0, 0x1fc55ce0, 0xe0ac}}} - }, - { - /* 1*16^12*G: */ - {{{0x1a37b7c0, 0x1d517330, 0x311069f5, 0x02343dee, 0x322151ec, 0x00024d7b, 0x34cdda6e, 0x13ea82cc, 0x5390}}, - {{0x022771c8, 0x372c25ac, 0x14434699, 0x26666078, 0x0d3c1c13, 0x27b32b08, 0x0106d88c, 0x21f42f20, 0x5bc0}}}, - /* 3*16^12*G: */ - {{{0x08a2050e, 0x06b10bf9, 0x15f8a677, 0x0bbd55d8, 0x079b8974, 0x1da731b9, 0x0731896b, 0x093f492f, 0x6737}}, - {{0x061d3d70, 0x24326924, 0x3349cc2b, 0x1aeb3f50, 0x086b6dbe, 0x120b026a, 0x24a20203, 0x2095e25a, 0xe4cf}}}, - /* 5*16^12*G: */ - {{{0x02de63bf, 0x2fdb920e, 0x3261c66c, 0x0ebd4ca1, 0x2166a8e0, 0x26298c7d, 0x34c309e5, 0x3be91cb7, 0x4366}}, - {{0x217924cd, 0x0b1a9023, 0x2aa6d6b0, 0x0ec31496, 0x0268eaf3, 0x094df84c, 0x2d7ce2ee, 0x36426fb8, 0x2e7d}}}, - /* 7*16^12*G: */ - {{{0x06f96190, 0x04149ffc, 0x3c9525ef, 0x3c0b7a41, 0x3aa75fd1, 0x3955a599, 0x1ab1f97b, 0x14d89e64, 0x7bd7}}, - {{0x2bda00f6, 0x0f45c812, 0x20ea695a, 0x03f31707, 0x3827d6ce, 0x3591d250, 0x26309d5e, 0x3cacf6ee, 0x8336}}}, - /* 9*16^12*G: */ - {{{0x16ad41ed, 0x0ec54c55, 0x0f035243, 0x022b0d7d, 0x18dc9203, 0x0d067a24, 0x2d5c1afa, 0x249ef76a, 0x4f7e}}, - {{0x3e642d57, 0x3d0d5e19, 0x2af775bd, 0x1cc51c53, 0x28f6a62e, 0x26037d4e, 0x08b10552, 0x1d1455aa, 0xdfe7}}}, - /* 11*16^12*G: */ - {{{0x27748690, 0x3e981449, 0x0630b01c, 0x15e41376, 0x133d007d, 0x114ac7b7, 0x11ccc94b, 0x32e19f4a, 0x2355}}, - {{0x0c89582b, 0x1f11d4c5, 0x11c93914, 0x0a1a1633, 0x2a7c5858, 0x2e17b056, 0x1e1f8f55, 0x3c62969c, 0x21c2}}}, - /* 13*16^12*G: */ - {{{0x0ade7f16, 0x36ba8858, 0x0be028c6, 0x272eba4f, 0x275d24ae, 0x164aadb0, 0x1a56c013, 0x2096e6cf, 0x0b66}}, - {{0x08c56217, 0x251109a1, 0x3e7cd2bd, 0x090f037c, 0x17a97fb7, 0x29daea2d, 0x09b3fef3, 0x282e0638, 0xa1fb}}}, - /* 15*16^12*G: */ - {{{0x19060d5b, 0x241ac08a, 0x03a3a7c2, 0x1184ec47, 0x3951cb90, 0x026cbf67, 0x1022cb61, 0x010f3c2f, 0xf602}}, - {{0x1af88f13, 0x1bdbd42c, 0x3dd1a3f7, 0x2a95b4ad, 0x0f7bea37, 0x2a3d92b1, 0x0cf19881, 0x2dc1b07c, 0xf036}}} - }, - { - /* 1*16^13*G: */ - {{{0x3ad86047, 0x3fe567d0, 0x29b8bcae, 0x2d4e810e, 0x0a906779, 0x3329dd93, 0x183a7719, 0x3342f4d6, 0x8e7b}}, - {{0x0460372a, 0x284011fa, 0x3fd68b3e, 0x3a238b91, 0x29514579, 0x0c410832, 0x1a4b3940, 0x1dc2ca8f, 0x10b7}}}, - /* 3*16^13*G: */ - {{{0x041ead4b, 0x3fa21e68, 0x11b03c1f, 0x1d7b7eda, 0x3e76be3a, 0x11cd3beb, 0x3337ec71, 0x03032323, 0xbfc9}}, - {{0x06fedaed, 0x114b1bc2, 0x2e0ae3e7, 0x11a3bfcc, 0x042d36fb, 0x29c63754, 0x0ded24db, 0x206c7827, 0x7a94}}}, - /* 5*16^13*G: */ - {{{0x35bb3b3e, 0x1b9ef41d, 0x39f73cb2, 0x1d4d85fb, 0x2d3f5b50, 0x1664fa30, 0x3aaa4dca, 0x3c472f8f, 0x732d}}, - {{0x17366693, 0x315df87b, 0x0c58436c, 0x276b5b59, 0x253916e6, 0x38956100, 0x39977cb7, 0x240fb7a3, 0x7f41}}}, - /* 7*16^13*G: */ - {{{0x088dc3b9, 0x17d6cf06, 0x1774c99c, 0x299a493a, 0x17ef6019, 0x2a210332, 0x147b428d, 0x252e580e, 0x4ce0}}, - {{0x25c0de52, 0x3053dedb, 0x1ea06502, 0x0816c832, 0x36aca216, 0x2d360329, 0x29b3ed57, 0x03eeafc6, 0x0539}}}, - /* 9*16^13*G: */ - {{{0x0aaafe5a, 0x30dd782c, 0x109aedd4, 0x151c2ce9, 0x023fd0e2, 0x229aa56c, 0x267de96d, 0x23addbf1, 0x9a96}}, - {{0x0ed975c0, 0x39aff509, 0x1e70cc0c, 0x2d620299, 0x061d0ee7, 0x319b40f6, 0x3ba2954f, 0x3ec1e9b4, 0xabf6}}}, - /* 11*16^13*G: */ - {{{0x334c6397, 0x1d472fe7, 0x074cd093, 0x374f6d40, 0x36b22107, 0x2bbe0094, 0x161954f0, 0x3efb405c, 0xd3c6}}, - {{0x28cb3f9c, 0x07f23415, 0x05e0e00b, 0x031dc224, 0x2ab6468a, 0x20e5364b, 0x22af1945, 0x34b15797, 0x4a0d}}}, - /* 13*16^13*G: */ - {{{0x0ac3137e, 0x26e0964c, 0x1af64461, 0x2496d8a9, 0x2b3953fe, 0x3c1a9daa, 0x243b8e02, 0x38e604a4, 0x4cbd}}, - {{0x2ec02fe6, 0x0023c573, 0x08ead60c, 0x24e9eb96, 0x14c370d1, 0x24a84d2e, 0x36159500, 0x151823c4, 0x6ce5}}}, - /* 15*16^13*G: */ - {{{0x20fbf84b, 0x1e88c1b3, 0x03f0b8a4, 0x3123f2ef, 0x14cebb03, 0x3671cc30, 0x16247b8b, 0x0ccf20ac, 0x4b9d}}, - {{0x236c3c48, 0x0e7b92d2, 0x2f5b5e62, 0x19b550f8, 0x39b7eb67, 0x04f66099, 0x0c152553, 0x31fef893, 0xfd7f}}} - }, - { - /* 1*16^14*G: */ - {{{0x19c43862, 0x2a107856, 0x397e6690, 0x29fd3c60, 0x381bde71, 0x02061a26, 0x1ff21e6d, 0x3b4d3073, 0x385e}}, - {{0x142e5453, 0x01163f95, 0x086dc8cc, 0x0c13bb08, 0x2bf4576b, 0x077867a7, 0x223f5670, 0x3af0fa3a, 0x283b}}}, - /* 3*16^14*G: */ - {{{0x36e2d9b3, 0x12f4c1aa, 0x338d6351, 0x36e4a0c6, 0x0f845641, 0x0ba984e7, 0x305e75e1, 0x053ce5f1, 0x19a3}}, - {{0x0baaaf33, 0x154bb897, 0x004be56d, 0x00874749, 0x3528b3a5, 0x2597e21f, 0x328dd234, 0x363d76b1, 0x6cac}}}, - /* 5*16^14*G: */ - {{{0x12f00480, 0x36161fac, 0x100dcee7, 0x0d620128, 0x36721920, 0x32618d93, 0x0daa355d, 0x3b52e56a, 0x5840}}, - {{0x3e22cf9e, 0x164b578a, 0x2ae38721, 0x1d489514, 0x1dd8daba, 0x1a37aa85, 0x3f141079, 0x369ac882, 0x670c}}}, - /* 7*16^14*G: */ - {{{0x23f54c42, 0x12137ba0, 0x29a3dc8e, 0x37068f09, 0x0e532545, 0x16307d3b, 0x118fb1dc, 0x00694d1a, 0x9f57}}, - {{0x2feb6a21, 0x18387124, 0x219e5278, 0x3b9e12ac, 0x29bfdd89, 0x256dad5c, 0x19e57bfb, 0x23ee2007, 0xce7b}}}, - /* 9*16^14*G: */ - {{{0x1522461a, 0x3a504cca, 0x3c718327, 0x2cc28996, 0x3ef9a0bc, 0x2e1c0419, 0x28cfc01b, 0x045a48d6, 0x27f6}}, - {{0x07301a2d, 0x2a932be7, 0x28639446, 0x2606c836, 0x028ee8e4, 0x2315849d, 0x26ad2ea4, 0x3c6a6402, 0xe512}}}, - /* 11*16^14*G: */ - {{{0x114f36b9, 0x338b26cb, 0x3b9f390c, 0x2632aed8, 0x34a98125, 0x2fcbd0d7, 0x2f941261, 0x1e615b3b, 0x6407}}, - {{0x24b4b50a, 0x252c7ba7, 0x19ceeb28, 0x36821c12, 0x1a7b6c8c, 0x035d7f61, 0x16efaef9, 0x24a3d139, 0xda61}}}, - /* 13*16^14*G: */ - {{{0x14d6b76f, 0x3bd8f7e6, 0x0c815dbc, 0x396a7eed, 0x1dfeae7f, 0x3dc22f02, 0x1669f452, 0x1438c721, 0xa237}}, - {{0x0dcca8da, 0x0764b332, 0x1b848d14, 0x1c1f047f, 0x011113e7, 0x0be8f935, 0x3de6dac3, 0x26c529b9, 0xf733}}}, - /* 15*16^14*G: */ - {{{0x3ceee475, 0x0bba7193, 0x0ed782b1, 0x1ab20a10, 0x0aff41ab, 0x0f0087cf, 0x2378d5ed, 0x2b01e8fc, 0xbbf1}}, - {{0x07fe5067, 0x1188a802, 0x38b41d68, 0x3ae76250, 0x315fe324, 0x20f320da, 0x060e6108, 0x2e37bab5, 0xb4bf}}} - }, - { - /* 1*16^15*G: */ - {{{0x03fac3a7, 0x181bb61b, 0x147fbc9c, 0x377e1296, 0x3dfa180f, 0x31ce9104, 0x0f191637, 0x366e00fb, 0x06f9}}, - {{0x3a842160, 0x21a24180, 0x0281002d, 0x29374bd7, 0x05c4d47e, 0x238a8c39, 0x059ba69b, 0x31a3980c, 0x7c80}}}, - /* 3*16^15*G: */ - {{{0x121ce204, 0x13b5d7a3, 0x26763d52, 0x29c96390, 0x26f72fb2, 0x1d361672, 0x3c64fb83, 0x107458ac, 0x43ca}}, - {{0x134a8f6b, 0x1494113a, 0x2a4a468e, 0x2db1eccf, 0x1ba31f9a, 0x143e4863, 0x023fa1c6, 0x16a0b8dc, 0xdcea}}}, - /* 5*16^15*G: */ - {{{0x2be6efda, 0x13f3a4b3, 0x07280596, 0x0b53fcfe, 0x1a506d92, 0x1bdc8de1, 0x12bf5b66, 0x01bbc8a2, 0x9c3e}}, - {{0x27aefc7d, 0x3c503cca, 0x336fdf7d, 0x0ef21a1e, 0x226fd5d4, 0x02cb5133, 0x2923d8af, 0x027979d8, 0xa7b7}}}, - /* 7*16^15*G: */ - {{{0x06c88be2, 0x2449ead7, 0x06ee5e27, 0x0b1e0834, 0x30775bea, 0x1c9d6760, 0x20f033bb, 0x22a8c4f8, 0x5d6f}}, - {{0x0d7ad75d, 0x24b954fc, 0x2bf92c28, 0x2adbe3a9, 0x08bc20ed, 0x2abcceac, 0x2d4e8c71, 0x2c636355, 0xadc4}}}, - /* 9*16^15*G: */ - {{{0x12d1b844, 0x0a24d46e, 0x173e484f, 0x2700e0b0, 0x388bc5c6, 0x2c570f04, 0x20d5fc86, 0x0d70c129, 0xf57d}}, - {{0x21266837, 0x192eaef5, 0x0915c6a4, 0x01a5c80c, 0x24634c70, 0x134fd6a7, 0x2f4d9790, 0x0f67aa63, 0x707f}}}, - /* 11*16^15*G: */ - {{{0x3cc7cb09, 0x0d3401fc, 0x1d1b4352, 0x31fada28, 0x1871463b, 0x1b87fb8f, 0x194a5f59, 0x181e8e99, 0x13e7}}, - {{0x08079160, 0x2f9d6a28, 0x2b576411, 0x3ab8aed9, 0x34299d65, 0x17f7616c, 0x3b8b1e32, 0x32237a3e, 0x284d}}}, - /* 13*16^15*G: */ - {{{0x18cdee05, 0x01833849, 0x32ec3b90, 0x1d87ec85, 0x06901da8, 0x00942c6c, 0x182e6240, 0x28c895a0, 0x29be}}, - {{0x262651c8, 0x39280d66, 0x0c698e39, 0x3f0c6db2, 0x305ec7f9, 0x026cfee1, 0x29a0ea90, 0x36689a43, 0x7c40}}}, - /* 15*16^15*G: */ - {{{0x12f18ada, 0x06db1d58, 0x3dbdbcc1, 0x182f64ee, 0x3d4a59d4, 0x0dbebfcc, 0x288e7d9c, 0x1e1b48e0, 0xf521}}, - {{0x23953516, 0x375a2bf4, 0x05bf0981, 0x17bd28db, 0x11d1d6aa, 0x09840af3, 0x0db57ecc, 0x1befd80e, 0xe068}}} - }, - { - /* 1*16^16*G: */ - {{{0x02d0e6bd, 0x0edf839d, 0x30f5e531, 0x1d3458f6, 0x0d6ecbf7, 0x0851f041, 0x04e2582a, 0x3500490f, 0x3322}}, - {{0x2c28b2a0, 0x13ce8ba5, 0x2873af62, 0x017d8fa8, 0x1af9b728, 0x0066f137, 0x24ef5bfb, 0x01e5fa59, 0x56e7}}}, - /* 3*16^16*G: */ - {{{0x059ab499, 0x2f674fc8, 0x273c330a, 0x04ca671b, 0x3f01bc0b, 0x065acf19, 0x005ba5d2, 0x2bfcc057, 0x78ba}}, - {{0x3ee097fd, 0x20748c63, 0x11251996, 0x18cbbba3, 0x02082e91, 0x2a1383b6, 0x2c0afafc, 0x3736f6c1, 0xad4b}}}, - /* 5*16^16*G: */ - {{{0x3d06ace6, 0x124f85b3, 0x03a20ca4, 0x1c26cdbe, 0x29ab1a23, 0x2e126124, 0x2e3d4c20, 0x3c846852, 0x6f70}}, - {{0x3602d5de, 0x122fb4d2, 0x25ac5ee0, 0x0ca559af, 0x399f5075, 0x1763cd1e, 0x27b736f9, 0x228c2500, 0x791e}}}, - /* 7*16^16*G: */ - {{{0x20ee1b40, 0x323b8fb9, 0x1e96247d, 0x3b5216dc, 0x03ccd48c, 0x2527c644, 0x2a415f80, 0x276ca75a, 0xe159}}, - {{0x178f93a6, 0x0758997b, 0x032999de, 0x0d8e9d2f, 0x2fc7cfa6, 0x3e252aa8, 0x1d4a0efa, 0x1888caa0, 0x7933}}}, - /* 9*16^16*G: */ - {{{0x09c00c3e, 0x2077e8a1, 0x11208e2f, 0x03a3c0f2, 0x051859f0, 0x158b4cf5, 0x06956436, 0x0125c110, 0xbb0b}}, - {{0x11955a35, 0x266a60b4, 0x05dc90a7, 0x19c113a4, 0x31b052fe, 0x34be85ea, 0x39f63655, 0x391614eb, 0x4067}}}, - /* 11*16^16*G: */ - {{{0x05dd32e6, 0x039d6e70, 0x13e5ee7e, 0x18ed546d, 0x1a5fbfc6, 0x1276f81d, 0x1789e9b6, 0x10555065, 0xdc5a}}, - {{0x354a99b9, 0x039f6de9, 0x2e49bcf8, 0x3cbba41d, 0x3f59442f, 0x3a978806, 0x367a76dc, 0x2a298fe7, 0x4af3}}}, - /* 13*16^16*G: */ - {{{0x0544e7cb, 0x3b516eb1, 0x12960359, 0x0190896d, 0x014e99a1, 0x0d5295c4, 0x33b9dbe3, 0x065c0e61, 0x156e}}, - {{0x2d250a37, 0x354e4b02, 0x2b439cd6, 0x25b56357, 0x034be894, 0x255ca98e, 0x1907da93, 0x2367e3cc, 0x6bc0}}}, - /* 15*16^16*G: */ - {{{0x059853ca, 0x2fef0a73, 0x319bf54d, 0x3a589ae7, 0x27161348, 0x29da88a3, 0x043826bc, 0x2f33b2da, 0x4269}}, - {{0x35b8d367, 0x2a563bd4, 0x1e5a8a3d, 0x0e50297e, 0x31a409fd, 0x2132a710, 0x016b723c, 0x0706a0b0, 0xed2b}}} - }, - { - /* 1*16^17*G: */ - {{{0x0134ab83, 0x0875d34a, 0x36433977, 0x06cfe6bd, 0x26586874, 0x05dc3625, 0x0b7da2bd, 0x0b1f4b78, 0x8567}}, - {{0x390313a6, 0x238c253d, 0x1298f44c, 0x1fc5ff31, 0x22c2e5e7, 0x10126fe9, 0x3b2eb637, 0x06e6d6d0, 0x7c48}}}, - /* 3*16^17*G: */ - {{{0x03ba9000, 0x37c1c8ea, 0x025e8b6f, 0x21cbe71a, 0x00143dc4, 0x21d81d61, 0x1d8c1684, 0x1d3e7ffc, 0xac38}}, - {{0x2f10cf0a, 0x368f1f65, 0x366e9fa4, 0x178d435f, 0x117f9308, 0x0b77a250, 0x1c069b86, 0x3a48c228, 0xaa65}}}, - /* 5*16^17*G: */ - {{{0x2d06dbd4, 0x2981bd9b, 0x0a20d081, 0x038fe15e, 0x23e729ec, 0x0501d7a6, 0x070139ad, 0x1739ea9a, 0x570d}}, - {{0x3d1ed495, 0x2996fb3a, 0x2460bed5, 0x20e8db71, 0x101bbbb6, 0x19b99c47, 0x202f605b, 0x14d25083, 0xa6ae}}}, - /* 7*16^17*G: */ - {{{0x092d230e, 0x0d307e48, 0x29339284, 0x3b8ca834, 0x366ef5da, 0x308a7b80, 0x28bb6f87, 0x3e1c0a09, 0x75b5}}, - {{0x151570b8, 0x0df2f7ef, 0x111f8fb0, 0x19e92c01, 0x1dfa8e02, 0x1e1d1553, 0x3852363d, 0x338878e9, 0x527c}}}, - /* 9*16^17*G: */ - {{{0x034fcc0e, 0x1edafdab, 0x3e3884c4, 0x1fc4290a, 0x1259c892, 0x16e0389f, 0x1dec2b0a, 0x23beb87b, 0x44fc}}, - {{0x319c420a, 0x33fc0c79, 0x0d0489d9, 0x03a5292f, 0x33d3d772, 0x099f9e20, 0x31367e49, 0x37a52ea6, 0xd2c7}}}, - /* 11*16^17*G: */ - {{{0x0bb69991, 0x169207f2, 0x3307175d, 0x3ecfe8b0, 0x02f535ff, 0x28598838, 0x27bc6866, 0x2e91eeb3, 0xdea2}}, - {{0x316fe2df, 0x019d0aa7, 0x21ed9bc7, 0x27736cd8, 0x37b9e722, 0x32ffb213, 0x028e4ac5, 0x2ff5b643, 0xae28}}}, - /* 13*16^17*G: */ - {{{0x114fc9cc, 0x30903409, 0x1a461658, 0x3402af0a, 0x38a83626, 0x073db312, 0x168d6efc, 0x3f2629b8, 0x3968}}, - {{0x1fad37dd, 0x064e5225, 0x388f3340, 0x05195dbf, 0x2d32c91a, 0x1e60b46a, 0x35928123, 0x2ef436d2, 0x789c}}}, - /* 15*16^17*G: */ - {{{0x2e0c85f1, 0x2bb08646, 0x03a3a250, 0x294b94d8, 0x3945d5a6, 0x0977c255, 0x06a2926b, 0x2441a638, 0x6896}}, - {{0x2dc1de21, 0x31d208cc, 0x0d503922, 0x10306768, 0x05d72d1f, 0x0c170761, 0x0979256f, 0x0fed2ce3, 0xaefd}}} - }, - { - /* 1*16^18*G: */ - {{{0x20c82a0a, 0x3f6566bd, 0x3668832f, 0x2489b183, 0x1413b10f, 0x1b27c646, 0x188a46b0, 0x2fe026c6, 0x0948}}, - {{0x18c8e589, 0x132dfe23, 0x17cd2bed, 0x137fc232, 0x03418c6d, 0x2dd31747, 0x36646dc6, 0x18a15b72, 0x53a5}}}, - /* 3*16^18*G: */ - {{{0x38c8ac7f, 0x0a0bf97e, 0x1e2aa527, 0x0490bb99, 0x16f84964, 0x0ce5b481, 0x22bbcb5c, 0x2cbef8e0, 0x9945}}, - {{0x29aea3b0, 0x1b650e85, 0x2dacdfa9, 0x0bde88fb, 0x28eff528, 0x36d13fec, 0x3282d607, 0x3b6092c3, 0x3eef}}}, - /* 5*16^18*G: */ - {{{0x169e353a, 0x3475e78e, 0x2bbe1f6e, 0x28110214, 0x07d5fe10, 0x3e0889c4, 0x070e6235, 0x131ac816, 0x2a31}}, - {{0x25746067, 0x09649b87, 0x32658bfc, 0x22952ab6, 0x2a1ba013, 0x18f91dae, 0x227ac1a4, 0x2b02fcd6, 0x15a4}}}, - /* 7*16^18*G: */ - {{{0x29b84966, 0x278bd27b, 0x17f3ff98, 0x13d041b7, 0x2b6c911b, 0x2dbebce9, 0x3fc2d498, 0x29402dc0, 0x5959}}, - {{0x07473a6a, 0x02998c86, 0x0fe24264, 0x00373023, 0x082a7091, 0x0c4a0837, 0x0a897f94, 0x399d07d7, 0x0370}}}, - /* 9*16^18*G: */ - {{{0x2bc6b173, 0x2c326e48, 0x2ed3feb3, 0x36188f1f, 0x1b5f9d7d, 0x183118c1, 0x22fe8e11, 0x0c4e4dc8, 0x9eeb}}, - {{0x1723a71d, 0x14e58836, 0x0e70c4b9, 0x29c6afb4, 0x3a1ae30e, 0x2aaff6ee, 0x2d58d952, 0x3c780443, 0xe121}}}, - /* 11*16^18*G: */ - {{{0x3ec805f3, 0x1dc910fd, 0x1d995915, 0x3903dd42, 0x2e97887d, 0x2ec8e201, 0x318f516e, 0x13f931fd, 0x39cc}}, - {{0x3a3c48d3, 0x06468304, 0x3c912e4d, 0x2e55cdcf, 0x02de7dbb, 0x399a4f3d, 0x2f8f3151, 0x11cb1691, 0xecb1}}}, - /* 13*16^18*G: */ - {{{0x0e22580e, 0x0f58bed7, 0x2d6f8879, 0x04ca25b4, 0x1bd4d2c7, 0x0bff7993, 0x0dc69689, 0x201d19bb, 0xf94c}}, - {{0x3127db82, 0x07948fd9, 0x2371d4e8, 0x21fb114c, 0x1a81f698, 0x12ffdaad, 0x1225a919, 0x1ff719e1, 0x5e9c}}}, - /* 15*16^18*G: */ - {{{0x10c4f21f, 0x2f902eb4, 0x103da7a6, 0x092a5653, 0x1999d250, 0x0081a36c, 0x1d162fcc, 0x2e1b1ab5, 0x8ccc}}, - {{0x329dfea0, 0x1fc49ba9, 0x264be28f, 0x24b72b20, 0x0758a54b, 0x2fbd5272, 0x11c43699, 0x2596189d, 0x57f8}}} - }, - { - /* 1*16^19*G: */ - {{{0x338fd8e8, 0x33b36067, 0x069752ac, 0x2c39137f, 0x2873a8f1, 0x19f383c0, 0x001c34f0, 0x339fd186, 0x6260}}, - {{0x32b4ae17, 0x06a13a56, 0x051c198c, 0x34a488e0, 0x2a1ef7ec, 0x024125dd, 0x1b571a7f, 0x2a0adbe9, 0xbc2d}}}, - /* 3*16^19*G: */ - {{{0x01136602, 0x2c2e9195, 0x19e3a5bb, 0x311bd203, 0x333b3d38, 0x1624dfc8, 0x2dfc33d0, 0x09ca0120, 0x87d1}}, - {{0x18af6aac, 0x3da0f107, 0x3d3bf7c4, 0x2a211d1b, 0x27745387, 0x289db3fd, 0x203de926, 0x0921c296, 0x71ce}}}, - /* 5*16^19*G: */ - {{{0x08c5a916, 0x2c8175cd, 0x35610f25, 0x17110354, 0x354aa13f, 0x2b318f6a, 0x1e9746b0, 0x1f4ff898, 0xfd5d}}, - {{0x3adb8bda, 0x052cdec1, 0x1cf6faab, 0x35ce052f, 0x07b52fe5, 0x10f299e7, 0x15b07d2b, 0x0fb43bad, 0x0dd8}}}, - /* 7*16^19*G: */ - {{{0x35f7529c, 0x17664258, 0x1bd51dd4, 0x1d96e62d, 0x34438138, 0x114f0cb4, 0x026122ba, 0x35042607, 0xde0d}}, - {{0x24cd88fe, 0x0f08300b, 0x09b77406, 0x224931a2, 0x3a357017, 0x042608b5, 0x2145f9b2, 0x1ba74428, 0xd70a}}}, - /* 9*16^19*G: */ - {{{0x38f76d11, 0x320bd234, 0x38515573, 0x044003ef, 0x0292a215, 0x16fbf0e7, 0x0f44e69c, 0x0822b693, 0xb26c}}, - {{0x23b7356b, 0x307002c7, 0x182624bd, 0x000c1967, 0x0d643305, 0x13a1f643, 0x1d33cf0c, 0x3e208252, 0x1f1c}}}, - /* 11*16^19*G: */ - {{{0x269e22db, 0x2538ec19, 0x39c8933f, 0x264ffd67, 0x0c294eac, 0x0ef4a406, 0x3f523a7e, 0x052e3f1f, 0xfceb}}, - {{0x1c2260a1, 0x3d5cb6c9, 0x24ebe4cb, 0x15439e4e, 0x1f0924ad, 0x22969d49, 0x2b8d1fcd, 0x1ace9035, 0x64aa}}}, - /* 13*16^19*G: */ - {{{0x238a2755, 0x3c2105e6, 0x149c5506, 0x1c869c59, 0x107faa53, 0x05d5dd2d, 0x15cac55c, 0x26988f33, 0x4e90}}, - {{0x23cca3de, 0x3de927d8, 0x229800ca, 0x3354e534, 0x3559dbb6, 0x091b7541, 0x235aecef, 0x36a1e333, 0xae56}}}, - /* 15*16^19*G: */ - {{{0x183ba64d, 0x20962566, 0x0c595a3a, 0x3983dde2, 0x0e40e2bd, 0x028517ae, 0x04c03bfb, 0x115708b8, 0xc367}}, - {{0x2a2181fd, 0x053323e5, 0x1778f146, 0x189aab28, 0x1964c742, 0x3839ba13, 0x36033080, 0x02b41a72, 0x3a52}}} - }, - { - /* 1*16^20*G: */ - {{{0x2037fa2d, 0x254f3234, 0x1bfdc432, 0x0fb23d5d, 0x3f410304, 0x0d21052e, 0x1d8d43d8, 0x1f782bf0, 0xe503}}, - {{0x1d755bda, 0x03977210, 0x0481f10e, 0x17d6c0fb, 0x190bddbd, 0x263427ee, 0x0d3b5f9f, 0x14d2eaa5, 0x4571}}}, - /* 3*16^20*G: */ - {{{0x177e7775, 0x222a29b8, 0x0ed95f63, 0x385564e2, 0x1291aeb5, 0x150eeb3d, 0x233cee58, 0x1a8ebfe5, 0x9d89}}, - {{0x3a056691, 0x3f3db4ea, 0x299253be, 0x26735fb8, 0x10927de8, 0x2593b5c9, 0x1bf0b94e, 0x2a790fd2, 0xdd91}}}, - /* 5*16^20*G: */ - {{{0x3c2a3293, 0x3f781378, 0x103476c5, 0x222e1bba, 0x02f4cd56, 0x2c295cca, 0x23792d0e, 0x2e3b9c45, 0x8327}}, - {{0x0e0df9bd, 0x2f215386, 0x2326a416, 0x2bf6ad3b, 0x39708496, 0x2cfa9989, 0x0a98e18b, 0x1f899bb8, 0x0499}}}, - /* 7*16^20*G: */ - {{{0x0562c042, 0x1086c9b1, 0x38dfb1a2, 0x0b48c8d2, 0x1a8ed609, 0x1998763e, 0x1b16897d, 0x0aaa8a9b, 0x5ae4}}, - {{0x0f79269c, 0x2417337e, 0x07cd8dbf, 0x3836e544, 0x389d4a94, 0x30777180, 0x3051eab5, 0x0e9f017f, 0x99d9}}}, - /* 9*16^20*G: */ - {{{0x1e85af61, 0x0d2204a1, 0x14ae766b, 0x23b5c8b7, 0x021b0f4e, 0x3ada3fdb, 0x1c8eb59a, 0x0eb909a8, 0x92c2}}, - {{0x036a2b09, 0x39c8d9a7, 0x2286fed4, 0x08eb60ad, 0x38d5792d, 0x085f571c, 0x11bb409f, 0x3e23c055, 0x414c}}}, - /* 11*16^20*G: */ - {{{0x07b5eba8, 0x38abc6cb, 0x118ea36c, 0x2afb71fe, 0x38df422d, 0x03d05dab, 0x3df1088d, 0x18231dab, 0xfee5}}, - {{0x0d0b9b5c, 0x3d4574da, 0x39054793, 0x203fd0af, 0x07c14ee3, 0x100be64a, 0x258afb11, 0x16644d3f, 0x3807}}}, - /* 13*16^20*G: */ - {{{0x3c63caf4, 0x078ee92c, 0x0f53d528, 0x23fceaca, 0x2a6afca2, 0x044ed318, 0x267e620a, 0x113ae4b9, 0x42e5}}, - {{0x169c29c8, 0x21ebb026, 0x3efc5f11, 0x29439eda, 0x015e7873, 0x3c88305d, 0x0c671f71, 0x15383e47, 0x9ff8}}}, - /* 15*16^20*G: */ - {{{0x1e0f09a1, 0x028af661, 0x14032838, 0x28427c6e, 0x300efef0, 0x25bb4a91, 0x32ce3839, 0x20ed9954, 0x7aed}}, - {{0x05857d73, 0x1176337a, 0x33f4a540, 0x22cbcc03, 0x032d8ed8, 0x2bf42ac4, 0x1ef7c7dd, 0x1517e68c, 0xf5b8}}} - }, - { - /* 1*16^21*G: */ - {{{0x24fce725, 0x1619a82b, 0x2a6c5b72, 0x3a36f471, 0x1771b4e7, 0x2a417a3c, 0x207adf5e, 0x1cac3d28, 0xe063}}, - {{0x0eee31dd, 0x09c0d3e5, 0x3104870b, 0x12129de1, 0x1a488cd7, 0x09eecab5, 0x18cfe12a, 0x225d2f38, 0x7a90}}}, - /* 3*16^21*G: */ - {{{0x1a328d6a, 0x2eaa0623, 0x1adc18bd, 0x135dcea5, 0x308fa7b2, 0x1a264616, 0x34e00a34, 0x3016e988, 0xc663}}, - {{0x3ec9b8c0, 0x0ec2edaa, 0x12bf9cc2, 0x21547a94, 0x171317dd, 0x2bf73c9d, 0x21c38d39, 0x3a6357dc, 0x3331}}}, - /* 5*16^21*G: */ - {{{0x3996de2f, 0x32472120, 0x0b25114b, 0x33b7cbb8, 0x0fe4e977, 0x2cc37ba8, 0x06a459ce, 0x09a0b7ee, 0xd3fc}}, - {{0x14526f8c, 0x31248907, 0x37abf168, 0x166d2637, 0x3781da4e, 0x2d1d5353, 0x30a18f68, 0x37e66917, 0xc4f0}}}, - /* 7*16^21*G: */ - {{{0x03e697ea, 0x31b12344, 0x05f83e85, 0x399e3ee6, 0x3fabd19c, 0x287fb268, 0x2c0237dc, 0x12d0ffac, 0xc17a}}, - {{0x1edc6c87, 0x3b8ee1f7, 0x39f02ab0, 0x38686d5f, 0x201fae96, 0x05e3dc65, 0x35954cae, 0x170b556a, 0x3935}}}, - /* 9*16^21*G: */ - {{{0x3163da1b, 0x0b4b0c08, 0x393a3118, 0x03b7b983, 0x011fde9a, 0x24d275ff, 0x390b468c, 0x22df2899, 0x8f61}}, - {{0x03bdd76e, 0x1fcc4844, 0x249b6e7c, 0x14319a8c, 0x2c5a4264, 0x2f69d35e, 0x3eb6eb5f, 0x0fc97c22, 0x7823}}}, - /* 11*16^21*G: */ - {{{0x0ec8ae90, 0x3a1643f8, 0x0bbc5dee, 0x2c9ae4ba, 0x03f1b8cf, 0x356e36b2, 0x21e6eb86, 0x303c56de, 0x9798}}, - {{0x252844d3, 0x2a6b0bab, 0x03188e27, 0x392596f4, 0x1c73bee2, 0x3b25253e, 0x02ed3dd2, 0x38aa9d69, 0xba40}}}, - /* 13*16^21*G: */ - {{{0x11d66b7f, 0x16865e3c, 0x187dc810, 0x29a49414, 0x1284757a, 0x3c6e42e2, 0x22d6747c, 0x1bb8fed6, 0xfdfa}}, - {{0x38e5178b, 0x2aa3e019, 0x3d78de9d, 0x11be7744, 0x1a18c4d8, 0x0307268f, 0x198db93c, 0x3cc78892, 0x4d9c}}}, - /* 15*16^21*G: */ - {{{0x1265bcf0, 0x201d5e12, 0x11c7d30b, 0x338ade10, 0x0f220e69, 0x3aa69187, 0x29e43add, 0x338e3788, 0xfd58}}, - {{0x2b996292, 0x0cf9ea73, 0x0f1cd1df, 0x0986ff8a, 0x05e4fb87, 0x20aae692, 0x3215bd53, 0x29794dd8, 0xffe0}}} - }, - { - /* 1*16^22*G: */ - {{{0x10559754, 0x02b5a423, 0x2a3f5854, 0x2c42f778, 0x0ce02204, 0x02efe770, 0x1d45358d, 0x1e9c5735, 0x213c}}, - {{0x34b458f2, 0x3fcb09d4, 0x36a7eedd, 0x12143d7c, 0x1ba190bb, 0x0eb41891, 0x06250701, 0x2b42d6b9, 0x4b6d}}}, - /* 3*16^22*G: */ - {{{0x1e05dccc, 0x0cb60046, 0x019a93e5, 0x0fe8fb53, 0x13d172ae, 0x1b825ae5, 0x1a030954, 0x3db85d4f, 0xb8ce}}, - {{0x0c6d5750, 0x0052833f, 0x26b68133, 0x1d5ff0da, 0x12bd99df, 0x3529d393, 0x09bbf6a4, 0x229829b3, 0x302b}}}, - /* 5*16^22*G: */ - {{{0x373bb31a, 0x16f7fb84, 0x3db97b48, 0x07dedad7, 0x3b5f4970, 0x282f78ba, 0x07385e02, 0x0cf9de6d, 0x03fb}}, - {{0x3d215c9e, 0x0d32f9a5, 0x07640d4e, 0x169f1db1, 0x3b572bc6, 0x30586aae, 0x2fe281e0, 0x36549523, 0xf36a}}}, - /* 7*16^22*G: */ - {{{0x1d9a4ab4, 0x16d457af, 0x15bb7c0a, 0x1f0db061, 0x0f7a3671, 0x05bded34, 0x03e1161f, 0x1f34427b, 0x4b17}}, - {{0x235ab6f7, 0x2ab77f91, 0x1741f558, 0x0df8957c, 0x226b486e, 0x23d9ca4d, 0x2fa65fda, 0x19ba6978, 0x3ec9}}}, - /* 9*16^22*G: */ - {{{0x301c23a4, 0x3d1beca6, 0x3a49cf56, 0x0a905611, 0x39cd75c2, 0x00e0a6e6, 0x27a06c2a, 0x00d481a8, 0x5e87}}, - {{0x10d986f9, 0x085e65ac, 0x24ccfda1, 0x05c761d2, 0x2c6e2da2, 0x1d5746b8, 0x09221e71, 0x1913bee7, 0x5b96}}}, - /* 11*16^22*G: */ - {{{0x007b0c66, 0x3cfcd748, 0x16c86fb1, 0x29ffb919, 0x2ceb7434, 0x08913d82, 0x1680a447, 0x30c064c3, 0xe545}}, - {{0x31f2d470, 0x21fd5f49, 0x35a239dd, 0x3960a386, 0x19bcbf97, 0x31bf68e5, 0x2955e7e5, 0x0d03a318, 0xe06a}}}, - /* 13*16^22*G: */ - {{{0x03648bba, 0x2960642e, 0x1c3c7444, 0x283c2c1a, 0x01b39882, 0x0fb8897c, 0x0f580a13, 0x10855e95, 0xb2a4}}, - {{0x00fb6452, 0x11bead28, 0x09c17bb2, 0x36154547, 0x3d7e31c0, 0x3ef25e3e, 0x366619e9, 0x17f0ada4, 0xfe4f}}}, - /* 15*16^22*G: */ - {{{0x2bab27d0, 0x3db748bb, 0x045103fc, 0x02d07e8b, 0x197007f7, 0x25c06463, 0x138651ba, 0x2383cf51, 0x1b90}}, - {{0x00d3d110, 0x07a19d79, 0x07e51b57, 0x2ef2a4d6, 0x3c4b9ab5, 0x15f24605, 0x26b5e6f3, 0x1897bb11, 0x9b6d}}} - }, - { - /* 1*16^23*G: */ - {{{0x08fbd53c, 0x0330e8ec, 0x1c62cddf, 0x20e31c2b, 0x019a87e2, 0x2e4d4a95, 0x0b34e8db, 0x09ca9ebd, 0x4e7c}}, - {{0x17dcaae6, 0x02ce5060, 0x3f7dd33e, 0x02e5852f, 0x2f681b53, 0x3f427db7, 0x10b18e16, 0x271d9b27, 0x1774}}}, - /* 3*16^23*G: */ - {{{0x2521b3ff, 0x38a61193, 0x1aa750ce, 0x0f01c5fa, 0x2e24a523, 0x1134afa6, 0x1455c75e, 0x138c0432, 0x0248}}, - {{0x0269da7e, 0x306b92e4, 0x23ac8bbc, 0x1c01b7a4, 0x2d0eebad, 0x30acf0ac, 0x3e30d07e, 0x34282a88, 0x9619}}}, - /* 5*16^23*G: */ - {{{0x004ba7b9, 0x25ade7ea, 0x0741751f, 0x35a91c0c, 0x2c954e20, 0x26dc359c, 0x2ce57ef7, 0x3149b3ed, 0x16c1}}, - {{0x1c5bd741, 0x1d6f8e94, 0x1c9a9cc4, 0x1d57006f, 0x0a94deec, 0x189d1672, 0x31439062, 0x1fdf0d00, 0xdb15}}}, - /* 7*16^23*G: */ - {{{0x236683fa, 0x20d921ea, 0x0ec0825e, 0x2086d4e0, 0x127b6695, 0x22739dd1, 0x131af87a, 0x0f35d4fe, 0x0397}}, - {{0x3f4a577f, 0x3d7ecadd, 0x3e981ded, 0x1e213863, 0x35a26cd7, 0x384ad8ca, 0x0a3a3643, 0x168b30c3, 0x38cf}}}, - /* 9*16^23*G: */ - {{{0x00bf6f06, 0x202ce667, 0x1043b571, 0x0f04cc89, 0x20576571, 0x3013d2c0, 0x0f1511c2, 0x26ee9cbb, 0xba6a}}, - {{0x381db551, 0x0cafbdc1, 0x0697aafe, 0x17453deb, 0x18bd8e9e, 0x082fcb95, 0x211b0320, 0x078e2cd2, 0x1377}}}, - /* 11*16^23*G: */ - {{{0x31231a43, 0x347be7c1, 0x1ad43b9f, 0x35453599, 0x1e442f44, 0x3b654193, 0x04dd2d8a, 0x2f3309f3, 0x35c5}}, - {{0x1620c8f6, 0x36dcb914, 0x23cf0ae7, 0x3de93301, 0x3a589d4c, 0x396082db, 0x346ce734, 0x1d5c8ee5, 0x0e36}}}, - /* 13*16^23*G: */ - {{{0x3dd40609, 0x3d02f15b, 0x181cd76b, 0x10642603, 0x08356ac7, 0x0bc4bf16, 0x186bca12, 0x27091715, 0xfd47}}, - {{0x2a64ca53, 0x378bc4d9, 0x21ca4739, 0x04ebb5c9, 0x1841fd91, 0x2b5e90f2, 0x0afeff2c, 0x33ed49a5, 0x3069}}}, - /* 15*16^23*G: */ - {{{0x2b799a7f, 0x36dc0bd4, 0x3b8e8424, 0x062db354, 0x2c7d544f, 0x363ae6bc, 0x0d864bde, 0x000a8eb3, 0x6c40}}, - {{0x13c81e32, 0x2d7320b3, 0x20483f68, 0x1eaf5320, 0x1ddcbdc0, 0x2e0da838, 0x235be690, 0x37054c2d, 0x95c2}}} - }, - { - /* 1*16^24*G: */ - {{{0x00fb27b6, 0x0909f8a1, 0x24305763, 0x1b8f6caf, 0x286aa5c7, 0x08e2b585, 0x38b1b10f, 0x138f6f9d, 0xfea7}}, - {{0x323cb96f, 0x0074f6df, 0x33f7b777, 0x1ad65ae5, 0x36af9312, 0x19d37b32, 0x313297cf, 0x1a36e6c2, 0x6e05}}}, - /* 3*16^24*G: */ - {{{0x3e889756, 0x37606ba6, 0x3004bb25, 0x1ed9265e, 0x1899f3f2, 0x3365ec9c, 0x1fea8226, 0x22f0cc84, 0x762e}}, - {{0x3ca6b774, 0x17896781, 0x084fa5e2, 0x1cb6cc52, 0x02e34719, 0x3313c526, 0x3e97c3c7, 0x250982bc, 0xc028}}}, - /* 5*16^24*G: */ - {{{0x0975d2ea, 0x1bdd7a5c, 0x014e8ea2, 0x14ab3e84, 0x08f4a91e, 0x26f6ec8c, 0x095348e1, 0x1f51f7d8, 0xdf07}}, - {{0x31936f95, 0x28f0b678, 0x3bdd277a, 0x07b16e13, 0x22527c8a, 0x21097262, 0x37f4424c, 0x1ea2003b, 0xf861}}}, - /* 7*16^24*G: */ - {{{0x3c4c92d7, 0x2e1247ee, 0x14391b45, 0x36d35bb9, 0x0b142935, 0x1f7aa0cd, 0x3da032e1, 0x1f5d62f4, 0x9f3e}}, - {{0x314906dd, 0x32eeff3e, 0x294e1186, 0x0a88c0f5, 0x2b150245, 0x18ac872e, 0x1466b588, 0x2107a9df, 0xecd2}}}, - /* 9*16^24*G: */ - {{{0x32a8c483, 0x2b835cca, 0x1040ac35, 0x12c32231, 0x39528117, 0x230f48bb, 0x0cf9edc3, 0x1e575ed7, 0xa0cc}}, - {{0x12cc6ba9, 0x0259d156, 0x36936055, 0x0d23c6f7, 0x31df786b, 0x1d3f25c8, 0x3873ee23, 0x0048be2c, 0xabc3}}}, - /* 11*16^24*G: */ - {{{0x05dd3aee, 0x1c3c6daf, 0x396d2f21, 0x054ea2a3, 0x2976ca13, 0x08aa6b1a, 0x3c7cce0e, 0x14294554, 0x6d1c}}, - {{0x3df597f7, 0x3b8d5393, 0x0ed53adf, 0x078c42aa, 0x07d47485, 0x09c8008a, 0x3dfdc977, 0x052381aa, 0xafff}}}, - /* 13*16^24*G: */ - {{{0x24a6d0bb, 0x1e32a6df, 0x1a1afdc6, 0x274c48bd, 0x26418f65, 0x069b62a2, 0x3f9f3f31, 0x075862e5, 0x5e5f}}, - {{0x1033eaf9, 0x1a0e11e4, 0x06f653a1, 0x1557cb94, 0x2721da72, 0x3daf3413, 0x3e6f7358, 0x140ac1a9, 0xd7b1}}}, - /* 15*16^24*G: */ - {{{0x0f005e3f, 0x36a6d791, 0x2c39bd2d, 0x3da38c6f, 0x01a1495a, 0x0f2e6b38, 0x2427fffd, 0x229acf05, 0xf813}}, - {{0x2f357eb7, 0x0b5f8080, 0x14be2134, 0x3b106f55, 0x25cb51f4, 0x005795ea, 0x0ebd9f9d, 0x23cefbed, 0xca75}}} - }, - { - /* 1*16^25*G: */ - {{{0x17bdde39, 0x0b00a910, 0x36043295, 0x11385e6d, 0x1968d315, 0x095c3566, 0x3cf0e10a, 0x1044fd9d, 0x76e6}}, - {{0x1901ac01, 0x12c5d4b4, 0x16d2032b, 0x0a8cf4ad, 0x01f0d35e, 0x019b5c1a, 0x295cf577, 0x37e37b93, 0xc90d}}}, - /* 3*16^25*G: */ - {{{0x0078ee8d, 0x3c142473, 0x06919442, 0x2fc83394, 0x1b4ff64e, 0x3dc98eaa, 0x1a9be25f, 0x15eb6167, 0xd08e}}, - {{0x2da63e86, 0x265fd370, 0x022ed9de, 0x0fbdf3e5, 0x3e6df412, 0x05cbb9d5, 0x088d72d6, 0x25e612ad, 0x852e}}}, - /* 5*16^25*G: */ - {{{0x029129ec, 0x164519c1, 0x24825481, 0x2b8eb3c7, 0x131d080c, 0x22fa03b3, 0x04d275f5, 0x30217935, 0x7da6}}, - {{0x2cd9ff0e, 0x2d42bb8a, 0x0ca586ae, 0x12302195, 0x1627bf04, 0x34081d24, 0x01857511, 0x051aee7d, 0xf498}}}, - /* 7*16^25*G: */ - {{{0x11654f22, 0x3e0f5255, 0x31aaee94, 0x3dfce508, 0x29d94fb2, 0x3a4006f9, 0x1be6e21b, 0x2433fd70, 0x90d0}}, - {{0x201a43e1, 0x3d77815d, 0x1a3f8740, 0x358d594f, 0x3f70336d, 0x3c08781a, 0x0f61a953, 0x26874aeb, 0xcd56}}}, - /* 9*16^25*G: */ - {{{0x076b19fa, 0x2dbbd947, 0x28819d71, 0x35b81b41, 0x21292ed9, 0x08b0c420, 0x1d1ecc73, 0x26161f3c, 0xda47}}, - {{0x326f5af7, 0x2a89bbac, 0x153fc206, 0x1ef44fa5, 0x16569ea6, 0x0da41df8, 0x0af01d17, 0x35de26f3, 0xebb1}}}, - /* 11*16^25*G: */ - {{{0x39135dbd, 0x364bed96, 0x1d8631ec, 0x3021ebce, 0x29897cf0, 0x1eabd60b, 0x1ee6ad81, 0x1d412a37, 0xe3e4}}, - {{0x0748045d, 0x241abcf9, 0x2c95da96, 0x2880bfd7, 0x383ffea5, 0x2320654a, 0x3c6c40b9, 0x16fe0272, 0x930a}}}, - /* 13*16^25*G: */ - {{{0x0dee455f, 0x2fc2e797, 0x0ce4075c, 0x19fff9ba, 0x0bdb4aff, 0x114ce3e0, 0x0a9b0a47, 0x195bfa1c, 0x7e8c}}, - {{0x171b9cba, 0x1cf7a660, 0x2f466271, 0x28b459d1, 0x03a53b4a, 0x3dd83d20, 0x0740f2a3, 0x318cb28c, 0xbddd}}}, - /* 15*16^25*G: */ - {{{0x2698b59e, 0x1de5ae6d, 0x13447a43, 0x0cd64962, 0x23c7260a, 0x2c0d6acf, 0x15eb15be, 0x107e246a, 0x3df8}}, - {{0x2b92baf5, 0x33e399e5, 0x14949f8b, 0x3f219ec8, 0x1cf3867b, 0x0aeba3c4, 0x090c1da0, 0x39b7e62c, 0xb38f}}} - }, - { - /* 1*16^26*G: */ - {{{0x2bcbb891, 0x2ac54090, 0x326cbee3, 0x1f3190f7, 0x3f8f9a8f, 0x206ea9d0, 0x2abe1e82, 0x315ac0ec, 0xc738}}, - {{0x299a84c3, 0x1f9cd765, 0x080cfe91, 0x0c53bbde, 0x3fbbbb82, 0x063cbab2, 0x2d2537f7, 0x2d5e2546, 0x893f}}}, - /* 3*16^26*G: */ - {{{0x0761d58d, 0x12eabcce, 0x0d60e2f3, 0x1326f902, 0x20df7aca, 0x09028d5c, 0x3614610a, 0x1849e08f, 0xb8c4}}, - {{0x1d1051a4, 0x0e3a82ea, 0x2107c5b6, 0x1d411e17, 0x33c5053f, 0x1163da5f, 0x0e37d14a, 0x365b145c, 0x8f9e}}}, - /* 5*16^26*G: */ - {{{0x050b0040, 0x36c2cc10, 0x0134adc2, 0x3d1f6e7c, 0x1a3671f3, 0x03264ffa, 0x271f7a35, 0x1ba7dc40, 0x08d5}}, - {{0x1b3fd0a1, 0x163899e9, 0x21782beb, 0x35f11c83, 0x39b285f6, 0x34542a35, 0x29aa21ff, 0x216baf42, 0xa121}}}, - /* 7*16^26*G: */ - {{{0x13573b7f, 0x15958f7c, 0x30b6270f, 0x268717b4, 0x265a3788, 0x083e5def, 0x3ce6341e, 0x3c8cb50b, 0xdc13}}, - {{0x0c1f2ba6, 0x0ab348a1, 0x3404b1c4, 0x11551c05, 0x290a7670, 0x10436a12, 0x2340c3c7, 0x2ea010a7, 0xc909}}}, - /* 9*16^26*G: */ - {{{0x07ae9ceb, 0x00bd642e, 0x0ef2d14b, 0x1b087a9c, 0x2119a822, 0x0655976c, 0x37f073af, 0x0b798077, 0x25c0}}, - {{0x0bc6e275, 0x1c24344d, 0x26587264, 0x319077c2, 0x2d11d537, 0x2138373e, 0x2383c0c8, 0x3ab4b204, 0x8a9f}}}, - /* 11*16^26*G: */ - {{{0x2c5a3c34, 0x3e0263db, 0x15949fe1, 0x33a0b00a, 0x2e3e58ae, 0x2e7d329e, 0x0e49ce8a, 0x2746cb3e, 0xfedd}}, - {{0x213d7714, 0x0ad52fd3, 0x1bf82976, 0x2bad51a6, 0x0f4b00ad, 0x3a14c4b2, 0x3b8e0b0b, 0x0930c614, 0xa52e}}}, - /* 13*16^26*G: */ - {{{0x2ab6a396, 0x2d395346, 0x11360769, 0x0086e468, 0x0488b373, 0x38b5fd7a, 0x2a48c2de, 0x0ca1af1b, 0x3e0e}}, - {{0x1980e27e, 0x3acc7923, 0x3468f6a2, 0x2c04107c, 0x053fc66a, 0x07f877ad, 0x337964f3, 0x205cbe8e, 0xca44}}}, - /* 15*16^26*G: */ - {{{0x341023ec, 0x2bcd6188, 0x3ecf570a, 0x11763ddb, 0x02b9af56, 0x0b808026, 0x32d28498, 0x2e4c2030, 0x344a}}, - {{0x1e1eeb87, 0x13e260a4, 0x03995d70, 0x13a5dabf, 0x114c5ffc, 0x23cb47a9, 0x0462a73f, 0x0ac10ac9, 0x6e1c}}} - }, - { - /* 1*16^27*G: */ - {{{0x08f6c14b, 0x1cba7d96, 0x29250143, 0x35cb97ce, 0x172877d1, 0x131d8df2, 0x25b81e26, 0x1899522d, 0xd895}}, - {{0x1d7d991f, 0x24d8fb5d, 0x3b067e17, 0x10a358ca, 0x0340eb03, 0x3b182063, 0x07eae728, 0x2a8e3caf, 0xfebf}}}, - /* 3*16^27*G: */ - {{{0x2127b756, 0x02ea1ffd, 0x3a097048, 0x10a2f92a, 0x20b41603, 0x0d8b6941, 0x1f12672d, 0x1e0bdc5b, 0x6d8c}}, - {{0x3f172571, 0x1547dd2a, 0x17cdcca6, 0x0ea9b68b, 0x134daf4e, 0x26a0b4db, 0x1b911145, 0x37c225bf, 0x99ae}}}, - /* 5*16^27*G: */ - {{{0x358cf17a, 0x37b869cd, 0x18823524, 0x3e1772e9, 0x0097f8f1, 0x166bbc6d, 0x37aca8d0, 0x2fb7656f, 0xebca}}, - {{0x1caa0ccd, 0x11b3717d, 0x0ace95c4, 0x3eb484b4, 0x032e6b10, 0x00286d9f, 0x2b9cb02c, 0x3383e3c8, 0x47d3}}}, - /* 7*16^27*G: */ - {{{0x2c855c5b, 0x33bb9456, 0x17c8afbb, 0x21588680, 0x17fc2811, 0x0c68da78, 0x0ce24453, 0x134b92f5, 0xe8df}}, - {{0x2e465650, 0x27579cb0, 0x21e4d7d5, 0x18ed57c7, 0x2f32c596, 0x136d3d67, 0x39b26444, 0x3f5c311f, 0x6c57}}}, - /* 9*16^27*G: */ - {{{0x12e7e454, 0x023d6f69, 0x30e6150d, 0x0cbbfbc3, 0x181662fe, 0x121808ea, 0x0a832912, 0x34f5c63b, 0x4068}}, - {{0x18ef191e, 0x1e6b3797, 0x3c373327, 0x23487b44, 0x1d38d198, 0x305165f6, 0x247aab9e, 0x14edc952, 0x8cd8}}}, - /* 11*16^27*G: */ - {{{0x06c5d939, 0x215eb7e1, 0x3a933de0, 0x1d68a1de, 0x0a027ea4, 0x2fccb983, 0x025e0b55, 0x03b36c76, 0x1255}}, - {{0x19e757c9, 0x0a9d3f15, 0x0d8d4319, 0x22dd07fb, 0x324a7283, 0x2390f05d, 0x2d7a7544, 0x20cd3e1c, 0x7b8f}}}, - /* 13*16^27*G: */ - {{{0x16c8a56f, 0x2342ab19, 0x0f374213, 0x024f150d, 0x3ad08f85, 0x2eded4eb, 0x185d4c69, 0x19c6b0ed, 0x944d}}, - {{0x1a7be289, 0x27d37197, 0x106517eb, 0x35305d37, 0x3ac61967, 0x10e4d84c, 0x01fff4c1, 0x1965ded4, 0xa710}}}, - /* 15*16^27*G: */ - {{{0x2e08f15a, 0x3bae2862, 0x012900ba, 0x1a795b72, 0x13c305fd, 0x2c0d956b, 0x19a0cfe6, 0x13a47342, 0x86a5}}, - {{0x01388308, 0x1493479f, 0x335254d3, 0x04a74496, 0x35686777, 0x0aa341b5, 0x384603a7, 0x18520de9, 0xcfee}}} - }, - { - /* 1*16^28*G: */ - {{{0x0f676e03, 0x24542959, 0x3e84edd4, 0x3ff1cda4, 0x1e8761ce, 0x3d90cd5c, 0x17518eb0, 0x2500caa5, 0xb8da}}, - {{0x0efdf6e7, 0x1223939d, 0x1ff3b511, 0x33161365, 0x2808b092, 0x267325d8, 0x1a1e4d7c, 0x37e91201, 0x2804}}}, - /* 3*16^28*G: */ - {{{0x06e1346b, 0x28661277, 0x05af1c5e, 0x2f9ec40e, 0x1152c05a, 0x31d87c53, 0x2d10be54, 0x1a3fc260, 0x0690}}, - {{0x17226c13, 0x2ed62953, 0x0c6026e7, 0x3da24e65, 0x06442aa4, 0x176caf42, 0x3de26da8, 0x38f8242f, 0xb863}}}, - /* 5*16^28*G: */ - {{{0x1ca1f6a1, 0x039a47f3, 0x08cff1a3, 0x232f450d, 0x286ce106, 0x1b7172c7, 0x19761528, 0x0d24f2c9, 0x898c}}, - {{0x164f647c, 0x12b7083c, 0x32bd79ca, 0x29f3e5e7, 0x2c6e93b2, 0x1150914a, 0x2a5549d8, 0x1661aad5, 0x75f7}}}, - /* 7*16^28*G: */ - {{{0x3d1e3998, 0x29a780f0, 0x3a04328a, 0x15b22e45, 0x2a274e5e, 0x0a675c08, 0x18bf01a5, 0x38bfb4a4, 0xb213}}, - {{0x325fb81e, 0x30b2f718, 0x3ded175e, 0x0d0596fa, 0x243bc3d5, 0x187afe0e, 0x13c12c3d, 0x23b083cb, 0x229f}}}, - /* 9*16^28*G: */ - {{{0x225be234, 0x02f87fb2, 0x1df35070, 0x20f8f9c3, 0x206e060e, 0x342e9a45, 0x3f93e5d1, 0x0eb605b1, 0x4b3b}}, - {{0x120e8362, 0x18edf80e, 0x3211b840, 0x39ff64b3, 0x0cc04c41, 0x17a5b7f6, 0x2bc9c787, 0x008ee176, 0x5eec}}}, - /* 11*16^28*G: */ - {{{0x2289f55e, 0x2598d29f, 0x2c76707b, 0x1dac3c38, 0x0965be29, 0x0946c09e, 0x04f96020, 0x222db76c, 0x9f7b}}, - {{0x3e1e4bde, 0x0f34ed97, 0x310a2b1b, 0x394db83a, 0x0fc71fc0, 0x051ad0a6, 0x010f7be3, 0x3de131c1, 0x32f9}}}, - /* 13*16^28*G: */ - {{{0x1dfe1d2b, 0x19527230, 0x16878e51, 0x24fd4279, 0x3b73a4c4, 0x332b7f4f, 0x048e3e76, 0x10fa72dd, 0xd58a}}, - {{0x0cd50922, 0x33c9e56e, 0x0bd6fbff, 0x366e8857, 0x28276b54, 0x1ca44ca0, 0x083cf10a, 0x219ae816, 0xfc17}}}, - /* 15*16^28*G: */ - {{{0x249c795e, 0x090546f8, 0x1ce805e1, 0x1101aaa6, 0x27ea4eed, 0x365a70f0, 0x18310cd6, 0x1c4e5c44, 0x21d2}}, - {{0x19208ece, 0x0004bb0e, 0x2dfb761b, 0x1c651292, 0x2bb4c3d6, 0x0d6e1548, 0x1acea177, 0x3e6d2c1d, 0x94c5}}} - }, - { - /* 1*16^29*G: */ - {{{0x23c0df5d, 0x06845de3, 0x156a792f, 0x067bfed4, 0x1d7fab20, 0x2b6ae51d, 0x3b33a7d8, 0x3a851107, 0xe80f}}, - {{0x2ac9ec78, 0x32d0a46d, 0x3322ea9f, 0x0557a02b, 0x0a94472d, 0x25da328f, 0x200771e8, 0x379fd8e3, 0xeed1}}}, - /* 3*16^29*G: */ - {{{0x17592d55, 0x300d67b3, 0x0e350192, 0x356e51d0, 0x3ce3b106, 0x3fbda58c, 0x1052608a, 0x31b6f128, 0x5d2e}}, - {{0x2f5183a7, 0x19b9743a, 0x11151742, 0x0a9ef36b, 0x0cd6950e, 0x1c43e89a, 0x245eb58f, 0x337e271b, 0x0a92}}}, - /* 5*16^29*G: */ - {{{0x3e8f9f5c, 0x247d2d27, 0x1880a519, 0x187c7856, 0x1f404d73, 0x32b8d085, 0x3f742fe2, 0x0770ec46, 0xac37}}, - {{0x325a503c, 0x1ea0ffcc, 0x2751e1d1, 0x254d163b, 0x14e73522, 0x04079cc9, 0x1a477ff2, 0x05b061c2, 0xc516}}}, - /* 7*16^29*G: */ - {{{0x19e33446, 0x12872354, 0x2af385df, 0x224ef114, 0x22a17a40, 0x2302f408, 0x1840c934, 0x000e853c, 0x8942}}, - {{0x26387689, 0x034e2803, 0x1e74f984, 0x3f5dcd9e, 0x3de4e06b, 0x2cb5b43b, 0x1077a4d8, 0x00e56569, 0xa9fd}}}, - /* 9*16^29*G: */ - {{{0x3913cb26, 0x35ca3256, 0x13bd6d03, 0x3ad06700, 0x105c9899, 0x36913fd5, 0x342a8a2c, 0x099acc28, 0x2770}}, - {{0x3348a7a2, 0x3f9c5ccf, 0x0815bebb, 0x103246f3, 0x32b324e9, 0x0b49341f, 0x0db1a555, 0x2f179e6c, 0xf649}}}, - /* 11*16^29*G: */ - {{{0x195e8247, 0x02aa8085, 0x286cd1af, 0x2ff71155, 0x38ba9097, 0x179b8073, 0x3ed2178e, 0x3434e0f2, 0x75e4}}, - {{0x19982d22, 0x288ff675, 0x29ad893c, 0x36ad6dba, 0x3726d47d, 0x3e5c3b1e, 0x10990741, 0x10a85d50, 0x1fce}}}, - /* 13*16^29*G: */ - {{{0x26333323, 0x11e7d136, 0x0f4abf47, 0x2eef071a, 0x04da849c, 0x08358166, 0x1bbf03f0, 0x2d8e0cd8, 0x3ed1}}, - {{0x35d61ba3, 0x2c4ff122, 0x378f7294, 0x2dca2842, 0x0f929ea9, 0x1f2625a2, 0x34ee75d9, 0x0b6922d6, 0xd84f}}}, - /* 15*16^29*G: */ - {{{0x333980bf, 0x09415f52, 0x0dd00baf, 0x28dc0b94, 0x08dd4368, 0x1bf5dc8d, 0x18181b84, 0x34bc1a9d, 0x70fd}}, - {{0x20b75785, 0x0bbaa33a, 0x1d74a561, 0x040d60e1, 0x2e596b0a, 0x29043447, 0x18696957, 0x32b03435, 0x5edf}}} - }, - { - /* 1*16^30*G: */ - {{{0x04e16070, 0x3701eef3, 0x2fd6915d, 0x286080c7, 0x167543f2, 0x29239475, 0x1704313b, 0x1a5ef7f3, 0xa301}}, - {{0x1e177ea1, 0x30346810, 0x0a11a130, 0x0d76fdf0, 0x140f9b17, 0x2027e897, 0x3e4f5081, 0x3e473ed9, 0x7370}}}, - /* 3*16^30*G: */ - {{{0x138011fc, 0x1c049c00, 0x17285626, 0x165a99eb, 0x200a4d83, 0x2c4cc208, 0x1eb11156, 0x04e8c205, 0x6e83}}, - {{0x3f15ab7d, 0x2b2da7e8, 0x1c51f9a6, 0x2be456ba, 0x1ac30426, 0x04b6c807, 0x0f204c1a, 0x2062f709, 0xc147}}}, - /* 5*16^30*G: */ - {{{0x100e6ba7, 0x0e9d26e3, 0x0916f7f5, 0x0dbb16d1, 0x19e1b43d, 0x0780e293, 0x0851f2bd, 0x2a4265e1, 0xf952}}, - {{0x0175e4c1, 0x36ebbb94, 0x062a2b98, 0x15c59ed3, 0x3fa0f655, 0x0dda8b89, 0x3cebf861, 0x0e96c22a, 0xd8a9}}}, - /* 7*16^30*G: */ - {{{0x03aa0e93, 0x2401968a, 0x2fb1f626, 0x0b8e50eb, 0x1e893a8f, 0x00c68676, 0x3fee7504, 0x1b578c74, 0x9401}}, - {{0x07addac2, 0x23bb49a2, 0x257b07a3, 0x210dceea, 0x2e6fd7f4, 0x1574d53b, 0x14d96403, 0x0cbb9711, 0x6750}}}, - /* 9*16^30*G: */ - {{{0x0266b17b, 0x03d218b8, 0x262bb32b, 0x0d5a2880, 0x1f09c202, 0x25e211aa, 0x3b2891bb, 0x345d3567, 0xef22}}, - {{0x39dac83e, 0x0a9b810d, 0x1c341b73, 0x39c9dbdc, 0x34a1073e, 0x27330eb8, 0x24c7568f, 0x21325eac, 0xbc57}}}, - /* 11*16^30*G: */ - {{{0x12d382a0, 0x0c4c056a, 0x2ecd9ae2, 0x2372ef38, 0x2df927f2, 0x2b31e02c, 0x3892d39c, 0x3bf3933a, 0xb5f7}}, - {{0x25b4b532, 0x28bc2aee, 0x1acf8c5b, 0x3ec25b4a, 0x0bddd371, 0x255f1b83, 0x3f2353c0, 0x1516d470, 0x6843}}}, - /* 13*16^30*G: */ - {{{0x012cffa5, 0x39a49191, 0x28cc5c47, 0x3b508219, 0x14624389, 0x1d5363ef, 0x31076408, 0x30f4acb9, 0x1cdd}}, - {{0x1521954e, 0x379b6273, 0x336b528a, 0x0726109a, 0x02b08ac4, 0x2c49afe5, 0x1f8a63fd, 0x1a832cbc, 0x1e47}}}, - /* 15*16^30*G: */ - {{{0x34a9f22f, 0x0d7f90e4, 0x17a8e2ad, 0x02067148, 0x0835b0cc, 0x3e2e2e52, 0x0e939f21, 0x2cd67c97, 0x2acc}}, - {{0x375c4927, 0x2dd772ce, 0x1ba550b7, 0x12f5efb1, 0x30edf115, 0x04e8dfb7, 0x2d2e5192, 0x293a5622, 0xd518}}} - }, - { - /* 1*16^31*G: */ - {{{0x3fb04ed4, 0x2deb18f8, 0x1307fffa, 0x330cc2c4, 0x278de208, 0x3e741449, 0x2b936463, 0x216ce275, 0x90ad}}, - {{0x0b6ef150, 0x24753523, 0x182894d9, 0x2bbeaf85, 0x3222b839, 0x372f6509, 0x38261aff, 0x1e8d8828, 0x0e50}}}, - /* 3*16^31*G: */ - {{{0x30b7b678, 0x09d76cce, 0x0f638166, 0x0f10c46f, 0x2b6c76f1, 0x21af2909, 0x0231ba19, 0x125ccd39, 0x186e}}, - {{0x38d91fc1, 0x1e81dbcb, 0x09535dca, 0x01dc8951, 0x37e67e11, 0x3f209702, 0x3bd84aa7, 0x18392601, 0xc0d4}}}, - /* 5*16^31*G: */ - {{{0x33421fb8, 0x3c1b972e, 0x35a55d0c, 0x125c7cbb, 0x37241298, 0x01acd30e, 0x1bf62e7e, 0x2360d3db, 0x061c}}, - {{0x0e3ccd80, 0x257bd9a1, 0x26fcdd29, 0x19c4d2ce, 0x05eb5c80, 0x0e496438, 0x3b4b7ba9, 0x1ab66400, 0x6dfc}}}, - /* 7*16^31*G: */ - {{{0x2f6b35a4, 0x0492f862, 0x327fb487, 0x27cde9aa, 0x3a68ad88, 0x18c901cc, 0x2e513b73, 0x2d8e8823, 0xf6a6}}, - {{0x01f422a6, 0x2badbfb2, 0x1ee1862c, 0x355d5b9d, 0x20186f19, 0x34dc13d5, 0x1138b1ca, 0x322a000b, 0x3df7}}}, - /* 9*16^31*G: */ - {{{0x26954c11, 0x25a08fa2, 0x160d018b, 0x2a290f05, 0x0778ff7f, 0x346c3c54, 0x2c376220, 0x3f0a30a1, 0x87a2}}, - {{0x272a8b45, 0x15b8ccb8, 0x278124b7, 0x1224cfca, 0x127532cc, 0x06523683, 0x2ecef97b, 0x1462d16a, 0x33ad}}}, - /* 11*16^31*G: */ - {{{0x22706ab6, 0x391d1cab, 0x2e53c0da, 0x02cd0774, 0x384cfe3c, 0x15bbf2f0, 0x081a6845, 0x0b811b9e, 0xe147}}, - {{0x1d58de05, 0x1ba1a85a, 0x13cd2753, 0x16275551, 0x0621f8aa, 0x1a465e32, 0x18fc683f, 0x24aa91f1, 0x82cd}}}, - /* 13*16^31*G: */ - {{{0x07a84fb6, 0x2feb9508, 0x3a15021e, 0x08da1d43, 0x08b9ebc4, 0x2d358079, 0x0aef5de8, 0x24b2013e, 0x1caf}}, - {{0x27149109, 0x1ac60640, 0x22ce6761, 0x07305a5a, 0x101622ec, 0x2993e3fc, 0x2e53a481, 0x2e16b25d, 0xbc24}}}, - /* 15*16^31*G: */ - {{{0x0a955911, 0x1da33f85, 0x0ded52db, 0x1f85a898, 0x17839710, 0x27bfa6cf, 0x1650d258, 0x3f5a6bc2, 0x705b}}, - {{0x3fd200e4, 0x2edf1a4f, 0x242e72d8, 0x1fced48a, 0x0051fa29, 0x18f607d5, 0x3f990a7e, 0x2904c2dc, 0xe14a}}} - }, - { - /* 1*16^32*G: */ - {{{0x1ec4c0da, 0x2ded1132, 0x23ea3351, 0x23159e1c, 0x1f162ee8, 0x2706b660, 0x35f33923, 0x2e74bd8e, 0x8f68}}, - {{0x101fff82, 0x08f2fde5, 0x1510bfdf, 0x3a8b3fa5, 0x3e215dbb, 0x36430ada, 0x23986de1, 0x27cb6e81, 0x662a}}}, - /* 3*16^32*G: */ - {{{0x123809fa, 0x238ae3b7, 0x1d954be1, 0x21172cd4, 0x051f08fd, 0x24cd8fc9, 0x09f228ba, 0x076f8b94, 0x3838}}, - {{0x331fed52, 0x35c1d460, 0x2d8f24db, 0x207f32cc, 0x0eb1cc36, 0x10169548, 0x117dcb09, 0x0b4283ee, 0xe4a3}}}, - /* 5*16^32*G: */ - {{{0x17c2a310, 0x3a909922, 0x01226303, 0x21aba950, 0x0699a1f1, 0x086e0aa9, 0x32ae6f69, 0x09c9390d, 0x4926}}, - {{0x1e27ded0, 0x3106da05, 0x35ff8ce0, 0x058d84a9, 0x14303b6d, 0x33e95a5c, 0x3abf95a2, 0x39dcef29, 0x1337}}}, - /* 7*16^32*G: */ - {{{0x0ebd2d31, 0x0e12c1e7, 0x306db8d1, 0x330695bf, 0x37e2f84d, 0x094ecf91, 0x00c90d5e, 0x15a30689, 0xe306}}, - {{0x12546e44, 0x24ad020e, 0x23738266, 0x2f2010af, 0x3d0db6ff, 0x3cac41fd, 0x34260888, 0x1bf8de24, 0x0eac}}}, - /* 9*16^32*G: */ - {{{0x363136b0, 0x14c30e78, 0x2b41dd9c, 0x3afe366a, 0x3bd63374, 0x2c39d88f, 0x0cefc271, 0x0403890a, 0x3b9e}}, - {{0x2cdbbc8a, 0x14fb05bd, 0x2d31f819, 0x2b8a28ce, 0x075b26a2, 0x14cfae3d, 0x2bb71df1, 0x26054b45, 0xfafb}}}, - /* 11*16^32*G: */ - {{{0x2f485d3f, 0x1823c11c, 0x107beee9, 0x3281da20, 0x1edef717, 0x1b2a03d7, 0x2c9a92b7, 0x2b525c4a, 0xbb0a}}, - {{0x3ca2f975, 0x1e4e4940, 0x1670bffe, 0x1696be8c, 0x17da3489, 0x34807dca, 0x354798ec, 0x2714f160, 0xea69}}}, - /* 13*16^32*G: */ - {{{0x36718dc9, 0x2bbb4ce8, 0x01123de4, 0x3962d36c, 0x3e0113e1, 0x23ac65eb, 0x2fcc0d4e, 0x02b2393b, 0x7909}}, - {{0x1cfae7c5, 0x18cc8ac4, 0x3a9008b9, 0x0dabedc2, 0x1aaa56dd, 0x205b2f36, 0x05b8f13d, 0x1c8ae464, 0xeaab}}}, - /* 15*16^32*G: */ - {{{0x3f60c7d1, 0x09a5a531, 0x1775ad2a, 0x35c779f3, 0x09ba668d, 0x0f6ef395, 0x17b551c0, 0x206b7a7e, 0xe77c}}, - {{0x02d72449, 0x3b1607ca, 0x02986d34, 0x051c3dc7, 0x28154363, 0x30ecc8fa, 0x01321c5f, 0x051e3bbe, 0x3acf}}} - }, - { - /* 1*16^33*G: */ - {{{0x13231e11, 0x1a1bf541, 0x3681e3e6, 0x123a1940, 0x0c36091f, 0x267fe466, 0x385d65ff, 0x3ec05dab, 0xe4f3}}, - {{0x2feb73bc, 0x08b0e15d, 0x151d1c98, 0x31f9d3b2, 0x02b7286c, 0x069b43a8, 0x34f1c166, 0x18ceb43b, 0x1e63}}}, - /* 3*16^33*G: */ - {{{0x2bf05bd6, 0x0e67c139, 0x12a99465, 0x3d5b80c8, 0x070deca2, 0x0bd47fad, 0x04fe9083, 0x0c906fb9, 0x900c}}, - {{0x300d358b, 0x394ab4ef, 0x04efb15d, 0x2614d60f, 0x0b2439d6, 0x31c8115c, 0x1f0f5f95, 0x3e7a3a2c, 0x6c31}}}, - /* 5*16^33*G: */ - {{{0x1f105c50, 0x29f0a332, 0x31385257, 0x3837bbde, 0x0233cd82, 0x2330d00f, 0x190aad62, 0x00d8aac1, 0x5a8d}}, - {{0x38a4cde9, 0x326c8060, 0x2d013c35, 0x017da299, 0x03ff74a6, 0x29adc905, 0x0e536936, 0x3aac44f5, 0xc059}}}, - /* 7*16^33*G: */ - {{{0x32d64feb, 0x11f862e6, 0x292292c6, 0x1cbe2964, 0x0ba4e837, 0x3ce95ddb, 0x2f60a48e, 0x1340c48c, 0xd93f}}, - {{0x34698359, 0x2c3ef564, 0x2c90da37, 0x3810c2fb, 0x1c8c4d93, 0x1cc47153, 0x32733a23, 0x15575172, 0x7925}}}, - /* 9*16^33*G: */ - {{{0x039fbc84, 0x08881335, 0x057a0167, 0x1c18a458, 0x2ac65b7e, 0x138af198, 0x328441b1, 0x1a71b8db, 0x2f07}}, - {{0x1c201bec, 0x3ee40b78, 0x04dd5d73, 0x29e6da93, 0x0e2149cc, 0x37c01e64, 0x3bdddfa5, 0x3cdc935c, 0xb434}}}, - /* 11*16^33*G: */ - {{{0x06a758ea, 0x14dfab32, 0x27f19c4d, 0x0620c624, 0x016e3991, 0x1a256855, 0x20309958, 0x19e01567, 0xfe7e}}, - {{0x1b7ab649, 0x13c8b657, 0x03120d1e, 0x2005c1d1, 0x09251f3b, 0x02385a61, 0x1dcb988c, 0x1a59e8a0, 0x38aa}}}, - /* 13*16^33*G: */ - {{{0x0cfffefa, 0x39c5589a, 0x0651afad, 0x060113dc, 0x03af8510, 0x3dbe4543, 0x03127d6d, 0x3d729d4e, 0x91ba}}, - {{0x1f7f6faf, 0x1f4dbcd3, 0x2fd303dc, 0x2fbcc439, 0x1d3d92f4, 0x25a7c49f, 0x3bcebe5d, 0x33c464d1, 0x04e5}}}, - /* 15*16^33*G: */ - {{{0x0d33c546, 0x3f0245fa, 0x05edaf32, 0x15d7ecca, 0x35ddd782, 0x314dcf83, 0x378a7cb2, 0x104872cf, 0x4458}}, - {{0x000b4fd4, 0x029b461c, 0x32ca7366, 0x0bc28f3e, 0x1ada2085, 0x097ab8e4, 0x0753a772, 0x24ddfcfe, 0x308d}}} - }, - { - /* 1*16^34*G: */ - {{{0x20eae29e, 0x1bedbab8, 0x14e1d071, 0x00d3cbc3, 0x1a4266c7, 0x1854de91, 0x3f331eb9, 0x3ea6c63a, 0x8c00}}, - {{0x2702414b, 0x1f4a9319, 0x1e36c54e, 0x3eb6bea0, 0x36c974c2, 0x30d0e8dc, 0x121a1a9d, 0x1c99ffa9, 0xefa4}}}, - /* 3*16^34*G: */ - {{{0x2bfd913d, 0x0fe5580f, 0x254c9eac, 0x29a039bb, 0x2a8d2050, 0x01e82130, 0x3ddf874d, 0x0aa9fa41, 0x3636}}, - {{0x052e243d, 0x113e6bab, 0x2b2faafc, 0x0c2ec435, 0x1a2a82d8, 0x18910dc3, 0x0afd5341, 0x1e19db2e, 0x48f2}}}, - /* 5*16^34*G: */ - {{{0x2d132896, 0x32aeafe6, 0x3bc6c967, 0x2c78eead, 0x19200dfc, 0x16b658b7, 0x21e02f29, 0x25db7cca, 0x4487}}, - {{0x2f685248, 0x23006c4a, 0x276aa7a4, 0x2d035698, 0x161a3306, 0x26a41dd1, 0x1afe1efc, 0x16183445, 0x27bd}}}, - /* 7*16^34*G: */ - {{{0x3fa2670c, 0x02055bda, 0x06273e6e, 0x003e0ae8, 0x35032474, 0x2a72aa0c, 0x383788b6, 0x0eb0a2f2, 0x4a4d}}, - {{0x16c1764d, 0x022e7ff7, 0x329beed8, 0x0c16532f, 0x302b9d49, 0x1dc4777b, 0x05a4f17e, 0x2e470061, 0x70ab}}}, - /* 9*16^34*G: */ - {{{0x0cb24aa7, 0x365abf89, 0x1345c530, 0x0c42318e, 0x38fe1890, 0x39bf627f, 0x11802c3a, 0x0b4642ba, 0x5f7b}}, - {{0x0a693d7d, 0x35e01d0d, 0x3c81d0c6, 0x237adc24, 0x267c47ce, 0x0fe028f3, 0x1f2b330a, 0x0d80313f, 0x0770}}}, - /* 11*16^34*G: */ - {{{0x2f7fb8bd, 0x0646f17c, 0x3e4090a4, 0x31192857, 0x0886d87b, 0x30939b65, 0x190d02ae, 0x1d144ce7, 0x5139}}, - {{0x03908c0f, 0x0252b0b6, 0x3f98d5a8, 0x3f0cb4f8, 0x015c47fa, 0x23fbf6ba, 0x03bf34b8, 0x050f91d9, 0xfcd7}}}, - /* 13*16^34*G: */ - {{{0x2e36ca73, 0x0add2457, 0x3bbf3ede, 0x321934da, 0x014887ea, 0x0a444afc, 0x3dfb8aa4, 0x05b58afe, 0xcf83}}, - {{0x2ec25534, 0x2d248650, 0x08d710f5, 0x25856636, 0x1cca681c, 0x11142243, 0x19d73e38, 0x2d637ad7, 0x09fe}}}, - /* 15*16^34*G: */ - {{{0x3752f97d, 0x3224df5a, 0x33476613, 0x0bbef1d7, 0x0fa6165a, 0x274a19a3, 0x3b49de53, 0x37a69312, 0x8610}}, - {{0x1f1b1af2, 0x015f7350, 0x05543e08, 0x2ad367d5, 0x33f99e57, 0x33666c94, 0x30bbc937, 0x25e80ad8, 0xd319}}} - }, - { - /* 1*16^35*G: */ - {{{0x20cb3e41, 0x25ff77f1, 0x08b92c09, 0x0f4213cc, 0x298ed314, 0x033b02a7, 0x0829f3e1, 0x1b39a775, 0xe7a2}}, - {{0x0f2cfd51, 0x3a2a5087, 0x20e83e20, 0x29acb010, 0x2fbb18d0, 0x2c01a86a, 0x3984b471, 0x238c03e9, 0x2a75}}}, - /* 3*16^35*G: */ - {{{0x3aee42db, 0x03e7f4af, 0x330714a7, 0x2eef16d1, 0x2cbfc1d9, 0x2dbb6e47, 0x19150fc7, 0x09f9f66d, 0xcc34}}, - {{0x15d87bdb, 0x188a7004, 0x272422dc, 0x3972eb63, 0x21520010, 0x38ff4fec, 0x1c6a1885, 0x26106948, 0xea24}}}, - /* 5*16^35*G: */ - {{{0x3ed4a086, 0x3d0d9b19, 0x29c410ef, 0x35d70563, 0x0b5cf4b1, 0x0f1617ef, 0x0445dec8, 0x016eb366, 0x948f}}, - {{0x1e2bca4b, 0x0a86003e, 0x03fa2d1a, 0x08ca29c7, 0x1139411c, 0x11429980, 0x22a3382f, 0x2a27fed6, 0x864c}}}, - /* 7*16^35*G: */ - {{{0x37542c21, 0x032fa9b2, 0x2a64c15c, 0x067d34a3, 0x1d6d43ae, 0x1bf11514, 0x19ac9065, 0x0658a4a4, 0x2584}}, - {{0x272bfabf, 0x2faf8c65, 0x0c2ad7b3, 0x38e861b9, 0x3513d5f3, 0x176a9331, 0x3244801e, 0x16c7c736, 0xfcb3}}}, - /* 9*16^35*G: */ - {{{0x0c1ecbf8, 0x0f1187d0, 0x2eed7ca4, 0x227c37a6, 0x28421f64, 0x25d53307, 0x3c52522a, 0x337104dc, 0x7e12}}, - {{0x30bed615, 0x3516e336, 0x3e1d9f59, 0x1a7d8763, 0x0d1259c9, 0x3e536af9, 0x1c837143, 0x13e22223, 0x7128}}}, - /* 11*16^35*G: */ - {{{0x14557d86, 0x1f999470, 0x2667ff41, 0x3fbb11e3, 0x05a6cf1c, 0x2e4729e8, 0x342a6772, 0x30bfca8d, 0x4b8e}}, - {{0x35167eb9, 0x3766c646, 0x3c3f692b, 0x357cbbc3, 0x27ac5f28, 0x101cb794, 0x157ab14a, 0x30ffc130, 0xfde6}}}, - /* 13*16^35*G: */ - {{{0x0780763c, 0x0ae0b4ed, 0x265691d5, 0x229b57a4, 0x3ac07e5f, 0x10db71a5, 0x23a42532, 0x3041cce5, 0xfcd5}}, - {{0x38e851cb, 0x1539d080, 0x16463a4b, 0x066c8b9c, 0x32e38cb1, 0x0836cd7d, 0x22c463b7, 0x2af8b954, 0x18dd}}}, - /* 15*16^35*G: */ - {{{0x1d8ef686, 0x338ef8c1, 0x2272e66b, 0x23923d00, 0x266e53f6, 0x22976be0, 0x3cbe5223, 0x0b3b9610, 0x900f}}, - {{0x2121a8cf, 0x1ce9259f, 0x09156d50, 0x1b37fd0f, 0x09d11059, 0x31546c4d, 0x0425ad61, 0x30557b18, 0x732a}}} - }, - { - /* 1*16^36*G: */ - {{{0x1e6b80ef, 0x33ca7acf, 0x179424f3, 0x32f2e59f, 0x3cbdc571, 0x1503088e, 0x22ec8d23, 0x2783b8d9, 0xb645}}, - {{0x1a71ba45, 0x0c2fc2d8, 0x0e35b2ff, 0x2ceb9b52, 0x261db3c4, 0x2b7c5b95, 0x3e06de1d, 0x21db41bc, 0x067c}}}, - /* 3*16^36*G: */ - {{{0x319888e9, 0x0e73c9e4, 0x2448a8b4, 0x04ae9afc, 0x2681673d, 0x1834c0a5, 0x3a6e2dde, 0x3a9dceb0, 0x1f90}}, - {{0x2f113b79, 0x1bf7f25f, 0x19522e65, 0x0dd47fb9, 0x2b96a821, 0x054f49c7, 0x2a10e958, 0x0d9f0576, 0x89be}}}, - /* 5*16^36*G: */ - {{{0x3562222c, 0x217bedbc, 0x1e6f2c60, 0x00d11e64, 0x0b52bade, 0x00aeb4cd, 0x3e0ad6e7, 0x39537b7f, 0x13a4}}, - {{0x28200145, 0x32c59a32, 0x1c904c08, 0x3e715deb, 0x209a52d4, 0x2b0be075, 0x2e813b2c, 0x1f539605, 0xc9d6}}}, - /* 7*16^36*G: */ - {{{0x343b46bb, 0x0df93703, 0x2c925254, 0x3b4e98fe, 0x055dbd12, 0x01f01761, 0x0aadd1d4, 0x07afc8cf, 0x6199}}, - {{0x0c20a848, 0x123d6407, 0x12ecd8ef, 0x2a1ca729, 0x3badf11c, 0x3ce1c59b, 0x1e492952, 0x38c23cff, 0x01c5}}}, - /* 9*16^36*G: */ - {{{0x121add3b, 0x396f8f77, 0x1727d8f7, 0x26a513d1, 0x1626118b, 0x0e736c34, 0x3d387490, 0x2ba92de1, 0xea27}}, - {{0x368ce7dd, 0x2d78a476, 0x24e1be71, 0x2c84b5a3, 0x1c2f6278, 0x0f3ac8c9, 0x217de572, 0x3c79b90a, 0xc70f}}}, - /* 11*16^36*G: */ - {{{0x211ff757, 0x3a2be2ed, 0x04c226e6, 0x133a5d07, 0x22b6da9b, 0x0043e2db, 0x3fd54ba9, 0x144d5adf, 0x5946}}, - {{0x094d031a, 0x2299bb2a, 0x3bffe3b2, 0x06ef1edf, 0x0406f996, 0x00e34057, 0x32750042, 0x0d833977, 0x3611}}}, - /* 13*16^36*G: */ - {{{0x236160b5, 0x1d89628d, 0x0e7ebc06, 0x314fc91c, 0x091ec0cc, 0x0ebde5c0, 0x33290e84, 0x1b8e457d, 0x16b2}}, - {{0x18a1dc0e, 0x11897efd, 0x0ba3ef81, 0x0d8eab1c, 0x3654d4e1, 0x190d4918, 0x2ef8bb63, 0x159698c0, 0x060f}}}, - /* 15*16^36*G: */ - {{{0x37b32db8, 0x25934a24, 0x247791f3, 0x07b5d27d, 0x2cea85c9, 0x2850f210, 0x19f931be, 0x14a57115, 0x024b}}, - {{0x2a64f760, 0x25153eaa, 0x05b81a95, 0x2ada0448, 0x1e5be862, 0x38a08731, 0x3309c7b6, 0x3be3d6ff, 0x609f}}} - }, - { - /* 1*16^37*G: */ - {{{0x096943e8, 0x3b683d6d, 0x273c5a5d, 0x1bc7f19f, 0x0f06231d, 0x08d2a846, 0x3b840793, 0x20320a02, 0xd68a}}, - {{0x2b133120, 0x25321099, 0x045295a2, 0x039ee3de, 0x30e28b5b, 0x2c7e45de, 0x186d00c4, 0x2a7ffd2d, 0xdb8b}}}, - /* 3*16^37*G: */ - {{{0x0ca1c4f9, 0x16d0aa86, 0x2b7e2823, 0x13bf8d32, 0x1f16f44f, 0x02e0f698, 0x1728c4c4, 0x3de3c8af, 0x7815}}, - {{0x3778bc15, 0x2ac7a8da, 0x177d1e19, 0x2d0b7985, 0x18c35d5c, 0x24f3cc51, 0x1af6a7dd, 0x007a334e, 0xc1c6}}}, - /* 5*16^37*G: */ - {{{0x2e8c8530, 0x349b870f, 0x38f4d8e6, 0x0b7da07b, 0x2a6c6d51, 0x1df19005, 0x040176e3, 0x1cf3683b, 0xc392}}, - {{0x398446c7, 0x100c3c3d, 0x2eed715c, 0x3b7f2f68, 0x03199850, 0x074e5107, 0x33c8e9d0, 0x2f9095d0, 0x8c41}}}, - /* 7*16^37*G: */ - {{{0x237a26c1, 0x07c902ec, 0x0dbf6a53, 0x1b1b9630, 0x103b2516, 0x0890c707, 0x011b0275, 0x1d11fd61, 0xda31}}, - {{0x2cf74d6f, 0x1460dbb3, 0x3a81525f, 0x1a0db175, 0x19d8b7d3, 0x21059f09, 0x18c69d23, 0x25ee1fd7, 0x753b}}}, - /* 9*16^37*G: */ - {{{0x3739dc49, 0x0ad8a2a4, 0x2f55603d, 0x24e4b699, 0x3f231a23, 0x12b1422f, 0x30e6c106, 0x39b2c0ab, 0x6a4b}}, - {{0x32edd5cf, 0x39a8ae77, 0x14a4a4d3, 0x1f8ad32c, 0x3a8058ab, 0x059b8d83, 0x107597dc, 0x23ea8aa2, 0xf15d}}}, - /* 11*16^37*G: */ - {{{0x06987fac, 0x22fa2831, 0x0a86f679, 0x3243e190, 0x098a3c8b, 0x260980fb, 0x27f1344e, 0x31a7c4eb, 0x01f7}}, - {{0x19174c68, 0x3e479ce0, 0x1f6bc263, 0x1fd77886, 0x1ab6f9cb, 0x040db8ca, 0x1a22de5b, 0x330fcdbf, 0x9d4e}}}, - /* 13*16^37*G: */ - {{{0x36daba4d, 0x34ce86f5, 0x03196261, 0x197ec388, 0x3a2bcb9c, 0x018bb763, 0x3d381cb7, 0x25005d87, 0x557e}}, - {{0x37a52316, 0x04dd286e, 0x243590a5, 0x3a6e3d7e, 0x0cbc86c5, 0x0d73e857, 0x3a7e046d, 0x23ce9807, 0x7a7e}}}, - /* 15*16^37*G: */ - {{{0x29f5341a, 0x0e3d4bfc, 0x29636b80, 0x31e8cb19, 0x3101419c, 0x27503a9e, 0x085a93b2, 0x36a08666, 0x3ada}}, - {{0x2586c6cc, 0x1456024d, 0x05e8fbcb, 0x35b4b96d, 0x2b1017e9, 0x38d6fcda, 0x1369f552, 0x0788a266, 0xbfea}}} - }, - { - /* 1*16^38*G: */ - {{{0x028d3d5d, 0x0256603f, 0x3449cea4, 0x04abae5c, 0x3a30b096, 0x3009c241, 0x0804252d, 0x3b5f7d97, 0x324a}}, - {{0x16ab7c84, 0x19c892be, 0x23328439, 0x084ec31f, 0x2c1f4f19, 0x03030d6b, 0x21f2ff13, 0x0d95dd2d, 0x648a}}}, - /* 3*16^38*G: */ - {{{0x2fd53ed3, 0x17245d60, 0x1a56ccef, 0x0fdd3ee7, 0x1f7c4916, 0x3d82e4c7, 0x372ad5b8, 0x02f56659, 0x2084}}, - {{0x1a7a7132, 0x1c50ff94, 0x0e708998, 0x21f11ce5, 0x3afac254, 0x2f51da9a, 0x18243487, 0x0d25f3b0, 0xf299}}}, - /* 5*16^38*G: */ - {{{0x08a35b35, 0x2f4b2ed6, 0x00a121ed, 0x2d762297, 0x08ebfd1a, 0x0f40a796, 0x339bbbd1, 0x2ffd83ac, 0xe6b6}}, - {{0x1c1007bd, 0x15ca4f6e, 0x3e999c7c, 0x0edb274e, 0x1961ddfe, 0x3d0f8e0d, 0x0d2f3266, 0x3caf4cc0, 0x1a5f}}}, - /* 7*16^38*G: */ - {{{0x00360dd3, 0x353be34b, 0x050e2090, 0x2a2a0db6, 0x0ce3bb47, 0x02e021b8, 0x099b288b, 0x05dd16f9, 0xe053}}, - {{0x3c24f87b, 0x0abb3644, 0x0103dc2b, 0x2e61f7a6, 0x36a01461, 0x02560ad6, 0x12f39cd8, 0x0edc6976, 0xdc1c}}}, - /* 9*16^38*G: */ - {{{0x1098dfea, 0x3051998b, 0x2a678797, 0x372cf24b, 0x3a5e57fa, 0x23974aa0, 0x06c59e01, 0x0ece9de2, 0xa815}}, - {{0x2e6d892f, 0x2926a77d, 0x2daf4158, 0x2d783dd0, 0x053e03b1, 0x236e715e, 0x060fc53d, 0x0e591874, 0x2a47}}}, - /* 11*16^38*G: */ - {{{0x0bcecfa5, 0x29f9de92, 0x316bb020, 0x0358b686, 0x0eda3b2a, 0x11a5718e, 0x0addadeb, 0x30ecc3fb, 0x4f05}}, - {{0x15d37b53, 0x3b34092a, 0x01b48cd2, 0x1fb90c7c, 0x1534b944, 0x18c8d856, 0x1426fadd, 0x267a980f, 0x53a4}}}, - /* 13*16^38*G: */ - {{{0x084b96aa, 0x1879d964, 0x22abcce4, 0x0a618d54, 0x3b980ed0, 0x101786a8, 0x3a91be26, 0x26ae67d9, 0xd930}}, - {{0x02b28a86, 0x09b13cdf, 0x3cfe978f, 0x2db27eeb, 0x34cb5fd3, 0x043c1989, 0x2c557d7e, 0x26caa6d3, 0x6ef9}}}, - /* 15*16^38*G: */ - {{{0x1f8fcf0e, 0x3dee3416, 0x3c4a6fac, 0x16dbff79, 0x2a3411d6, 0x30d11b7a, 0x22d35ba9, 0x1f284e15, 0x7d58}}, - {{0x18bc9459, 0x00706827, 0x323780a5, 0x18e402b4, 0x3d6ad0c4, 0x0d002db3, 0x04c61272, 0x1700e20c, 0xa729}}} - }, - { - /* 1*16^39*G: */ - {{{0x3d054c96, 0x3a2f4dcf, 0x0d1ca888, 0x31050eea, 0x3ee5dcee, 0x077f6f97, 0x1e61f6d5, 0x30524673, 0x4df9}}, - {{0x0ad10d5d, 0x0baeb01b, 0x28849019, 0x3541b370, 0x1d85d4b5, 0x25d308e8, 0x18728050, 0x3b14424b, 0x0035}}}, - /* 3*16^39*G: */ - {{{0x1def001d, 0x13c89769, 0x09ba27ef, 0x3e6ef5a6, 0x23b64b21, 0x02f47027, 0x22caf20e, 0x28cb6c9f, 0xa549}}, - {{0x30624783, 0x3576c69f, 0x2c9705ad, 0x05078a98, 0x259456eb, 0x330c3b62, 0x166cbdf4, 0x1e9e41b6, 0x799b}}}, - /* 5*16^39*G: */ - {{{0x052ed4cb, 0x16bbc797, 0x009ec5a0, 0x1537becf, 0x132e6ec9, 0x022f660d, 0x3ecd123f, 0x23cc3681, 0x7e79}}, - {{0x14bb9462, 0x15c5981e, 0x39f37a12, 0x1cd5c6ff, 0x32f057b1, 0x2a55277b, 0x1ac83041, 0x33312893, 0xd23d}}}, - /* 7*16^39*G: */ - {{{0x13630834, 0x37ce83ef, 0x3dac067f, 0x18fc4a18, 0x0c810884, 0x2e7a5aea, 0x14783ad5, 0x28800c54, 0x224f}}, - {{0x047a2272, 0x34f11cdf, 0x0a50f75c, 0x18a493b0, 0x1d09f53d, 0x2dc3e8e4, 0x2da5c3c4, 0x138caecf, 0xbbe5}}}, - /* 9*16^39*G: */ - {{{0x183c19d7, 0x19d92745, 0x02cf57bb, 0x2ed7916b, 0x228ef2bb, 0x28973390, 0x239e4129, 0x28331802, 0xc2d4}}, - {{0x0507928d, 0x0bca2e0b, 0x3345c977, 0x2012a0c5, 0x01260d26, 0x20ed7dfd, 0x06294d41, 0x283e7020, 0x65ad}}}, - /* 11*16^39*G: */ - {{{0x3c940c9a, 0x13202b52, 0x2f423308, 0x33cf384e, 0x0ddc2113, 0x161789d1, 0x1f3190e5, 0x0a9fb0c1, 0x2ec2}}, - {{0x051e7a4d, 0x34653f66, 0x1a35bdac, 0x101460f6, 0x1c7feb12, 0x3893d40a, 0x379684c2, 0x291a378c, 0x8b1d}}}, - /* 13*16^39*G: */ - {{{0x1d683eeb, 0x29c3b97f, 0x08d3133a, 0x0dbace28, 0x04b8f33e, 0x2bd94942, 0x28cecab1, 0x1a5ce3e6, 0xafc6}}, - {{0x30cd4509, 0x078a72ac, 0x1eddfdc9, 0x02ead549, 0x239c1657, 0x1671ff28, 0x22752bc3, 0x0865db74, 0x002c}}}, - /* 15*16^39*G: */ - {{{0x376f4293, 0x28807e1e, 0x13c5139e, 0x3a5e2d59, 0x0b282e10, 0x2f233cdc, 0x03309121, 0x1ed6a7cd, 0xd255}}, - {{0x1282740a, 0x36c61e89, 0x2405a5f1, 0x12da0e37, 0x0ad21fe3, 0x20bc1bad, 0x027f0126, 0x2cd0d579, 0xa787}}} - }, - { - /* 1*16^40*G: */ - {{{0x2c1f98cd, 0x2ff26722, 0x17f0308c, 0x0d224153, 0x06602152, 0x362a7073, 0x34870fae, 0x066a1291, 0x9c39}}, - {{0x14fc599d, 0x39f9780f, 0x064c8e6b, 0x14c9bddb, 0x20e64190, 0x3c112fc9, 0x1dd57584, 0x13c3d293, 0xddb8}}}, - /* 3*16^40*G: */ - {{{0x0fb64db3, 0x1ee6354e, 0x1dd53841, 0x3b79328e, 0x13b8d6a7, 0x2ee0fef9, 0x1ccb740b, 0x08e48a6f, 0xc114}}, - {{0x3c0259be, 0x08c33a7f, 0x14567d1e, 0x1d602413, 0x178bd1a8, 0x3b3793fa, 0x06fc2a5c, 0x3db716d2, 0x1237}}}, - /* 5*16^40*G: */ - {{{0x03081e46, 0x3b7b60d0, 0x14559ea1, 0x14886315, 0x2634713a, 0x3670b064, 0x37224082, 0x12fe0c69, 0x6c5b}}, - {{0x0bfbcd70, 0x347e72e0, 0x2c22a62e, 0x3433e09a, 0x2be47841, 0x11e18f38, 0x2d42fb23, 0x04dc5249, 0xcb05}}}, - /* 7*16^40*G: */ - {{{0x064dcd4b, 0x32b96bb1, 0x111c124d, 0x0c31f566, 0x310a450c, 0x1c19972a, 0x0ade4b56, 0x2a1599c3, 0xe1e9}}, - {{0x3b041f2c, 0x342d897a, 0x0a16b292, 0x113466ab, 0x2577927f, 0x310d666c, 0x1c531b7a, 0x02a55115, 0x562b}}}, - /* 9*16^40*G: */ - {{{0x2badd73c, 0x0161dbf8, 0x2a64b7d0, 0x36737640, 0x1c14208f, 0x29d390bb, 0x1b099778, 0x0695eb44, 0x51b2}}, - {{0x2b36d8d1, 0x3df52b87, 0x0c734ba6, 0x0804c3ca, 0x2c1cfa6c, 0x281fc074, 0x3d3e5d54, 0x0c040007, 0x0079}}}, - /* 11*16^40*G: */ - {{{0x3b09f34b, 0x35d742dc, 0x0cc66ce6, 0x221cf982, 0x339d61e5, 0x2d8a5bcf, 0x0b79861a, 0x3ce98ec7, 0x9701}}, - {{0x00df5793, 0x33721433, 0x3dcc794a, 0x012f0e5f, 0x16833771, 0x00c6d4c5, 0x30ed15d7, 0x12eee32b, 0x3dd4}}}, - /* 13*16^40*G: */ - {{{0x3f1e2f46, 0x1739888e, 0x32778301, 0x1c3dc7a1, 0x163c5752, 0x164b8103, 0x266cc445, 0x2d074b27, 0xa036}}, - {{0x1effb349, 0x1cc789a5, 0x3f0b1f4f, 0x2038a0b3, 0x1eb08d06, 0x07daa91e, 0x16b3d7df, 0x246800fa, 0xc3bf}}}, - /* 15*16^40*G: */ - {{{0x0c4cea08, 0x3362e40e, 0x20ea21db, 0x12d62e83, 0x00465265, 0x298454d0, 0x28c506f4, 0x3eb6ea93, 0x6a85}}, - {{0x1862f4f3, 0x0677b396, 0x3d721b6a, 0x09c692d0, 0x3e6230b4, 0x24cf0523, 0x0659d531, 0x11812eb9, 0x00b6}}} - }, - { - /* 1*16^41*G: */ - {{{0x20a959e5, 0x2884e084, 0x391d4cc5, 0x38524ea2, 0x0e06bb91, 0x017ca076, 0x12fdf8de, 0x05c2c774, 0x6057}}, - {{0x2385a2a8, 0x2266fa4c, 0x2e24c65e, 0x1454af0f, 0x1df26246, 0x268b6bdc, 0x24807add, 0x3c2c9a9a, 0x9a1a}}}, - /* 3*16^41*G: */ - {{{0x171c032b, 0x3536858a, 0x3afdc980, 0x1ad9a285, 0x0766c5ff, 0x046d7f7f, 0x002603dd, 0x2a3f35b8, 0x71eb}}, - {{0x1668359f, 0x1ead6a38, 0x34b4755e, 0x24c6b45d, 0x0cbb7f71, 0x18145bd5, 0x1d39def6, 0x049892d8, 0xd2ff}}}, - /* 5*16^41*G: */ - {{{0x2a03a61c, 0x01b91d14, 0x1070574d, 0x1e1a3d1a, 0x2a9dd050, 0x05d10aea, 0x09d232ca, 0x30c16cc9, 0x855e}}, - {{0x065dfc07, 0x37f1baab, 0x17e44965, 0x0cbdd3a8, 0x02fb4ed3, 0x0f2ffe6d, 0x01c17f54, 0x174bb17c, 0x0dd8}}}, - /* 7*16^41*G: */ - {{{0x1f32d706, 0x00302920, 0x06a0678b, 0x0633291d, 0x15bfa206, 0x034a68c2, 0x3fbf1f15, 0x121aaeac, 0x3ce4}}, - {{0x3c7fd9e4, 0x02dcd8df, 0x161e89f4, 0x345590f3, 0x094906ed, 0x3f411ac4, 0x3785288e, 0x10236ab8, 0xe775}}}, - /* 9*16^41*G: */ - {{{0x391cd3fb, 0x36d032ed, 0x329be686, 0x0a8cff65, 0x0844eb4a, 0x380c863e, 0x237faf02, 0x31450fd3, 0x11cc}}, - {{0x15160d86, 0x24dc5ae9, 0x0dd3472a, 0x02c7bf4b, 0x0cc239fa, 0x2389124e, 0x311deb52, 0x1acaa40a, 0x4aa5}}}, - /* 11*16^41*G: */ - {{{0x218f7552, 0x21ee4465, 0x0054fac3, 0x1044e2e6, 0x2382ddbd, 0x25ddd3e0, 0x09c6f43b, 0x2ec5f945, 0x0250}}, - {{0x3510b14d, 0x3c212588, 0x33d6f1e3, 0x001bcf0c, 0x29d817da, 0x35f7dd7f, 0x28082342, 0x0c3f26ef, 0x7319}}}, - /* 13*16^41*G: */ - {{{0x1f725d12, 0x1744fa4e, 0x0b5f4750, 0x1190aef7, 0x022fbfd9, 0x28e73828, 0x27fd3ab4, 0x27222cd1, 0x1a74}}, - {{0x23ac56e4, 0x04d94534, 0x190daa70, 0x1c821a62, 0x2f3d8f60, 0x22f9d70a, 0x00e2cf45, 0x34655cfb, 0x7e91}}}, - /* 15*16^41*G: */ - {{{0x29fae458, 0x18412394, 0x26ec97fd, 0x0297109d, 0x3b7b328b, 0x3455a977, 0x0218c109, 0x1a16f83e, 0xc750}}, - {{0x1757b598, 0x005a1065, 0x35951a2b, 0x1772940c, 0x32c7b40a, 0x0bd05319, 0x21e05fb5, 0x257e33e4, 0xead7}}} - }, - { - /* 1*16^42*G: */ - {{{0x2cb94266, 0x069a5cfb, 0x3d4df12b, 0x33bc3ee9, 0x0da31880, 0x10e69146, 0x08411421, 0x37e388e8, 0xa576}}, - {{0x21b28ec8, 0x3a2f846b, 0x114d9f3e, 0x0b8429fd, 0x0cd82c43, 0x2e5ebf96, 0x240b2c92, 0x2fc839d9, 0x40a6}}}, - /* 3*16^42*G: */ - {{{0x0d9ed6c1, 0x1a2bad63, 0x3d593d6b, 0x139d16f0, 0x1edd0ec2, 0x3f061dc1, 0x0f53e80b, 0x0cdb72dd, 0x0328}}, - {{0x38fafeee, 0x3b1baf9b, 0x1cb494ad, 0x16fd37c9, 0x0d7c8c26, 0x35650e88, 0x19f28c46, 0x260e04bf, 0x71a8}}}, - /* 5*16^42*G: */ - {{{0x3235983a, 0x066a6a34, 0x13bceb29, 0x22840dc0, 0x3e1531e3, 0x0e49b5c3, 0x11c54dc6, 0x13aba2e4, 0xce4f}}, - {{0x0d3cdecf, 0x33f5ac64, 0x2bf740ae, 0x1b1948a3, 0x30754352, 0x37809279, 0x0fbbb3ea, 0x3e5cf0e4, 0xf3c9}}}, - /* 7*16^42*G: */ - {{{0x15b0e6c9, 0x1b6aad99, 0x06e4c89a, 0x17fe73de, 0x38bcbddb, 0x0a3ecdb7, 0x0622278e, 0x2fe952e6, 0x4dbe}}, - {{0x1eb2cc25, 0x2529e155, 0x0504efae, 0x24c46caf, 0x2229f358, 0x2989b9b8, 0x13aedf45, 0x39ec0f24, 0x10fe}}}, - /* 9*16^42*G: */ - {{{0x25857295, 0x13806846, 0x3433f016, 0x32391fc0, 0x1ca12069, 0x38463f28, 0x05c218b2, 0x0902ffbd, 0xa42a}}, - {{0x0a7eb9c1, 0x1acddffb, 0x15193955, 0x28708b34, 0x1da4c427, 0x1ac8ac93, 0x05d4567a, 0x2cfc9840, 0x3aa0}}}, - /* 11*16^42*G: */ - {{{0x2fcdc098, 0x0883fd55, 0x2e468032, 0x02b803da, 0x0499c155, 0x3c7e1b03, 0x322267a7, 0x0acbe5be, 0x34e1}}, - {{0x2a7474e2, 0x132c6b79, 0x19883f66, 0x37d44c3c, 0x3972db04, 0x132f2105, 0x1d322d97, 0x30b775ed, 0xa64a}}}, - /* 13*16^42*G: */ - {{{0x0f173b92, 0x335bad7a, 0x29fb7611, 0x1f9cbd05, 0x0d65683b, 0x0c68863d, 0x391f29be, 0x3490366e, 0x10f4}}, - {{0x233146c2, 0x240801b5, 0x086adb7c, 0x2edda745, 0x3908ba90, 0x2c96968c, 0x353ad211, 0x0b654245, 0x850e}}}, - /* 15*16^42*G: */ - {{{0x28d84958, 0x39bf4766, 0x0acc5cae, 0x0477ac5b, 0x00cc866a, 0x066e5db5, 0x277e749f, 0x3a02da6d, 0xe846}}, - {{0x3882cf9f, 0x031191ed, 0x1e0c1a64, 0x1468cd9c, 0x18b76fad, 0x2f64411e, 0x07e2541d, 0x2e3f2253, 0xa29c}}} - }, - { - /* 1*16^43*G: */ - {{{0x3e58ad71, 0x3dd8e226, 0x39a3a208, 0x0c347d73, 0x1e8c38bb, 0x17fa58a7, 0x2c3e30a0, 0x29e30a37, 0x7778}}, - {{0x3d9f43ac, 0x2d44ff07, 0x324ac563, 0x2ce1047f, 0x3f580087, 0x26384bcb, 0x1b22ff70, 0x1b66ad69, 0x3462}}}, - /* 3*16^43*G: */ - {{{0x3319c869, 0x3df1bab8, 0x21eb2702, 0x2a7e575d, 0x0cacdc18, 0x20e408bf, 0x33fc8d01, 0x01176605, 0x3018}}, - {{0x12b856f0, 0x3031db27, 0x23d9a7bf, 0x0aa13292, 0x222e3bca, 0x1890c835, 0x3b7b6f86, 0x315e0940, 0xac5f}}}, - /* 5*16^43*G: */ - {{{0x25ed29b5, 0x319a61be, 0x12add1b4, 0x20c2d81c, 0x23c885f5, 0x2d9f6e69, 0x17ef343a, 0x206d87b9, 0x3228}}, - {{0x3cd15ad2, 0x3d3c49b9, 0x0ee7604e, 0x20ebaae5, 0x1531e1ca, 0x02c677d0, 0x0344eb11, 0x00a105e8, 0x1677}}}, - /* 7*16^43*G: */ - {{{0x06c96100, 0x2fea101e, 0x2e9c8e63, 0x18c046a9, 0x33dbcca1, 0x0f766cb7, 0x31b9ffb4, 0x11ceb03e, 0x3f38}}, - {{0x32624707, 0x078ab06f, 0x375f1bcf, 0x15c71f02, 0x079ce566, 0x131118bc, 0x00395253, 0x27157d75, 0x70c6}}}, - /* 9*16^43*G: */ - {{{0x3d22d2ac, 0x0d31bb1b, 0x1caace02, 0x377f849b, 0x05df2f10, 0x0f03825e, 0x3a76dcb4, 0x04f17f49, 0x2881}}, - {{0x0f42a268, 0x207ad57e, 0x148c8fd0, 0x30f51285, 0x176137dd, 0x1ddc9832, 0x3c5c8f20, 0x3ac0563e, 0xa1a7}}}, - /* 11*16^43*G: */ - {{{0x245f8ea8, 0x12ea0374, 0x24d2900d, 0x1c9238e5, 0x119fe5d1, 0x3d36575c, 0x23a2a553, 0x28803211, 0xf963}}, - {{0x19bc99eb, 0x2f157ec1, 0x18b60824, 0x2e3c8d67, 0x3427208b, 0x1c88c07f, 0x383c0a3b, 0x2509a31f, 0x9c85}}}, - /* 13*16^43*G: */ - {{{0x2606a315, 0x386a20c4, 0x26963ad9, 0x1c981cbc, 0x0e097e40, 0x362ca964, 0x0d9a7f98, 0x08933fdc, 0xa5d9}}, - {{0x1e3b68d1, 0x0d584cd6, 0x111a7c9d, 0x13434d1f, 0x180de9ed, 0x0c1aaf5e, 0x0da5b343, 0x22c00ec8, 0x8732}}}, - /* 15*16^43*G: */ - {{{0x06231493, 0x336ded50, 0x0cc4d469, 0x1046a0c3, 0x25e6a496, 0x13907403, 0x3c3604eb, 0x260b86dc, 0xf1fe}}, - {{0x358848c1, 0x25aa6699, 0x25ff0d01, 0x1cfecd1b, 0x3d99d3f1, 0x34f0817d, 0x24ddc216, 0x067abb66, 0x2e20}}} - }, - { - /* 1*16^44*G: */ - {{{0x06d903ac, 0x027b6a70, 0x1ad7e5cb, 0x3e589d39, 0x3afd2ed5, 0x0a7f4c39, 0x3a844637, 0x2557b98d, 0x0928}}, - {{0x1bcd091f, 0x14603a4d, 0x0a8d83fc, 0x0f49bbea, 0x3a95eeac, 0x1e284c24, 0x342a827b, 0x08400f4f, 0xc256}}}, - /* 3*16^44*G: */ - {{{0x3874b839, 0x0444a1d5, 0x13d2b418, 0x10456ce5, 0x30b6aebe, 0x37c37ec8, 0x1e5a8053, 0x2e07f038, 0x3e03}}, - {{0x3c0594ba, 0x03073959, 0x1ab5b8da, 0x39717c3f, 0x198f667d, 0x3d981d5c, 0x07f42c44, 0x3858f7fc, 0xd13a}}}, - /* 5*16^44*G: */ - {{{0x0357a513, 0x28fde39a, 0x1b3023f3, 0x146f44d1, 0x2922c5f1, 0x3e8a0ea8, 0x0492cd62, 0x302de8bd, 0xe662}}, - {{0x2017d07e, 0x24a88072, 0x1538d891, 0x00d73589, 0x21a419d8, 0x2b882284, 0x2452305d, 0x064f3984, 0xab0b}}}, - /* 7*16^44*G: */ - {{{0x1f37d242, 0x2657dfbf, 0x39c14b04, 0x27fb2981, 0x23587dc2, 0x218b1f2f, 0x0f6cb843, 0x202c7253, 0x40bf}}, - {{0x26405088, 0x347609e6, 0x2bd35583, 0x0c87ae90, 0x26fe1274, 0x0ffa6c6c, 0x2aaf04f5, 0x374d7615, 0xb579}}}, - /* 9*16^44*G: */ - {{{0x195a3558, 0x2bcacd91, 0x234a7f2b, 0x01c7e178, 0x1b59f6ac, 0x3e5e04e3, 0x1ca70806, 0x3fa5d807, 0x3d14}}, - {{0x2443df4c, 0x1ab6ceb1, 0x3c1d727c, 0x3828b851, 0x356e1482, 0x26a4c76f, 0x281ef8f2, 0x2f75ba11, 0x16c6}}}, - /* 11*16^44*G: */ - {{{0x02b1fc24, 0x37a7d6b6, 0x23f7570e, 0x0a36071f, 0x12486525, 0x06b134b2, 0x265251cc, 0x29503a0b, 0xdd6f}}, - {{0x0e9b74ca, 0x290c7118, 0x17322304, 0x04379afb, 0x257e77ec, 0x1bc7afc5, 0x3186fe36, 0x0adfac74, 0x67e6}}}, - /* 13*16^44*G: */ - {{{0x3dd08e02, 0x07aa4564, 0x1adf0288, 0x2151edff, 0x3d1e8010, 0x1a5266a8, 0x15d780f8, 0x0b6a0b79, 0x13fa}}, - {{0x3cb03410, 0x29550770, 0x1a42b97d, 0x112beec6, 0x3432c7e6, 0x0d5881ae, 0x1da72313, 0x0e2c1155, 0x1363}}}, - /* 15*16^44*G: */ - {{{0x144ee41a, 0x308ceae6, 0x37d69a6a, 0x26d5b74e, 0x06828287, 0x3042d9cb, 0x30a443f7, 0x121474f1, 0xd06c}}, - {{0x0b295e6f, 0x3c7e13a6, 0x162ee252, 0x1ee10d18, 0x3630919b, 0x02b353d3, 0x0d0adbbb, 0x3f530161, 0x5815}}} - }, - { - /* 1*16^45*G: */ - {{{0x23d82751, 0x1eab9d45, 0x3ad35452, 0x116d2a41, 0x23b28556, 0x0193ce83, 0x1b109399, 0x3fbcfb1b, 0x85d0}}, - {{0x0eb1f962, 0x0b08de89, 0x07733158, 0x21d47a5a, 0x2cf5663e, 0x3525b960, 0x38c0be29, 0x192104e8, 0x1f03}}}, - /* 3*16^45*G: */ - {{{0x2cde4cf3, 0x26554187, 0x38a066ab, 0x10394d51, 0x1d9ae793, 0x30b49b45, 0x022c3be7, 0x2ad2b045, 0x384d}}, - {{0x252d0566, 0x1f1e5ac8, 0x351ba73b, 0x10c28ce5, 0x34c6f01f, 0x13b5b68a, 0x1ca43bfb, 0x316f346e, 0xd6e3}}}, - /* 5*16^45*G: */ - {{{0x1e5238c2, 0x22bcfa48, 0x00ecb8b9, 0x0d57d70e, 0x02ed4840, 0x05842d3a, 0x015aa41b, 0x3b03adf5, 0x14f0}}, - {{0x12f07922, 0x3a1a8d1e, 0x304939d6, 0x17003600, 0x02747fd2, 0x3f1cf8e1, 0x35d80921, 0x354f7520, 0xab12}}}, - /* 7*16^45*G: */ - {{{0x1543e94d, 0x3d8d4bbf, 0x2f98e188, 0x04c0a9d5, 0x1a0ddadd, 0x30d19e29, 0x0287ec41, 0x3ceede0b, 0xeb42}}, - {{0x05924d89, 0x01567791, 0x20d6d424, 0x3611a379, 0x0dfb774c, 0x03755cbf, 0x1d92dc9a, 0x1b41d3c9, 0x234a}}}, - /* 9*16^45*G: */ - {{{0x3e19aaed, 0x0c9396d5, 0x06673270, 0x26eb37a3, 0x06a92045, 0x3b00bdb8, 0x020d9a9e, 0x0e32945a, 0x1cf1}}, - {{0x292f400e, 0x04dba975, 0x3c77ffbc, 0x27bbe3fb, 0x2dde1747, 0x0dca99ad, 0x063865f4, 0x36bcc5c7, 0xd6ff}}}, - /* 11*16^45*G: */ - {{{0x36a8aa39, 0x3db03a7e, 0x278fac55, 0x2998ded2, 0x1990d937, 0x16825a12, 0x0d412c87, 0x21af97d0, 0xb586}}, - {{0x2b493c1f, 0x3f1e4d74, 0x2db347b8, 0x2f6be639, 0x00a91dab, 0x11e35153, 0x38c2c149, 0x3550c931, 0x5632}}}, - /* 13*16^45*G: */ - {{{0x303b4cc5, 0x3a47af8e, 0x21c77c2e, 0x0a0c6e96, 0x33a80257, 0x16f13f9f, 0x3cc2b67b, 0x276c1ae2, 0x5fc1}}, - {{0x25b57c28, 0x0ece7ee1, 0x0087ec4a, 0x1dbd40f3, 0x3a5ef492, 0x084e3e68, 0x0c7c66ee, 0x21303b26, 0xec8e}}}, - /* 15*16^45*G: */ - {{{0x0cb38cb5, 0x2d2e15f5, 0x1388948b, 0x02dff7d3, 0x3eea1be1, 0x2a2903f4, 0x1e289deb, 0x2dc350bb, 0xb88f}}, - {{0x1965f3d7, 0x1efe9d59, 0x3af8c719, 0x13cf8489, 0x35a8e24d, 0x12ee652c, 0x23280603, 0x0dab51ba, 0xd6c7}}} - }, - { - /* 1*16^46*G: */ - {{{0x0526087e, 0x3d501209, 0x2da20308, 0x3edb6220, 0x18b85dfd, 0x26d8105e, 0x2ce97c1c, 0x0373a5fb, 0xff2b}}, - {{0x30c29907, 0x32547807, 0x10e2ceb2, 0x2dfb5bee, 0x107936c7, 0x13137153, 0x0ba188af, 0x04ffbd49, 0x493d}}}, - /* 3*16^46*G: */ - {{{0x39d681f9, 0x164153f9, 0x08feb9fc, 0x3383bbeb, 0x2c94b066, 0x1ffc9780, 0x3230888b, 0x3f7c9dd7, 0xc745}}, - {{0x3bbb1247, 0x00c5cd0d, 0x27d45c76, 0x36f4cd71, 0x2818678c, 0x04e531c3, 0x1e5e78a7, 0x08bcbdae, 0x5902}}}, - /* 5*16^46*G: */ - {{{0x35cd0ea3, 0x38133bb4, 0x0cac4815, 0x111e3a08, 0x32e7f2b3, 0x16797ad9, 0x1050b27a, 0x1e7cea5d, 0xabb2}}, - {{0x3c307bce, 0x1c24c4cd, 0x202f3b64, 0x25da4167, 0x078ed47c, 0x12f8300c, 0x3970d9fb, 0x040eefc5, 0x5dee}}}, - /* 7*16^46*G: */ - {{{0x1bc9ee3e, 0x30b8bcfc, 0x3e7382c5, 0x27e86a58, 0x27ed11ea, 0x2baa9d09, 0x0682827f, 0x0542d67f, 0x3f81}}, - {{0x199aae06, 0x33ab6c31, 0x0da81603, 0x08ecb73f, 0x39566276, 0x06facf11, 0x3a82d467, 0x229a3f6f, 0x19c8}}}, - /* 9*16^46*G: */ - {{{0x38e4a007, 0x05c6fbeb, 0x0bb358b6, 0x3b3bb3c2, 0x16c7ec15, 0x12e8cea9, 0x02de6959, 0x04cb7402, 0x5cf8}}, - {{0x1068b883, 0x398fc242, 0x39c7fe8c, 0x251be5b1, 0x0c3df6c8, 0x35056212, 0x1fa0df4a, 0x3b970358, 0xb45a}}}, - /* 11*16^46*G: */ - {{{0x26c2d4a7, 0x255bf9ec, 0x3cfffb10, 0x30dbe4ce, 0x004ed21b, 0x38ce5cf1, 0x3a494653, 0x3f934352, 0xb6d5}}, - {{0x3ae86371, 0x063739f8, 0x35e3cc81, 0x16df939b, 0x3ffd8e74, 0x33e48277, 0x3d6c14df, 0x1ce84eae, 0x47f3}}}, - /* 13*16^46*G: */ - {{{0x3c66dd33, 0x024cd88b, 0x1dc76dc5, 0x23ef23fc, 0x29b022ea, 0x2c6c5400, 0x3588706b, 0x2ef019b3, 0x61c8}}, - {{0x36f10bfa, 0x0eeea7ce, 0x2820c8ca, 0x1441bab0, 0x05d3fb6a, 0x1a6652e6, 0x0f703446, 0x2788e795, 0x9359}}}, - /* 15*16^46*G: */ - {{{0x1d6b2ff8, 0x2016df33, 0x286c8fa9, 0x18cdb05c, 0x03bdf187, 0x27d4dcfb, 0x2785187c, 0x0ae95d09, 0x94e3}}, - {{0x2ce1af3e, 0x37521554, 0x26bfe13a, 0x0ebc1094, 0x2d9e8cb3, 0x07922198, 0x204e192f, 0x1122d0f6, 0x0d1b}}} - }, - { - /* 1*16^47*G: */ - {{{0x3856e241, 0x203978b3, 0x0d6dd287, 0x3c7b8523, 0x1b212b57, 0x0acb98c0, 0x080ea9ed, 0x2ef92c7a, 0x827f}}, - {{0x2ec293ec, 0x1816da2e, 0x2903166d, 0x3de98c61, 0x1d12687f, 0x3bcb19f4, 0x27b0b71b, 0x27248f1c, 0xc60f}}}, - /* 3*16^47*G: */ - {{{0x3bb80fa7, 0x0d12172c, 0x30413886, 0x29f69aed, 0x20819f3a, 0x0681af4c, 0x0c2fbc0d, 0x38c7d8c2, 0x0857}}, - {{0x09366b2d, 0x3660847c, 0x0d7016ab, 0x0b8dc10f, 0x0b714717, 0x1f327477, 0x0172092d, 0x24d08eb8, 0xf643}}}, - /* 5*16^47*G: */ - {{{0x09c70e63, 0x1740b0e8, 0x353d496f, 0x2ee2de39, 0x0a672e9c, 0x171955d9, 0x16004354, 0x333a95af, 0x28aa}}, - {{0x3057da4e, 0x27c0e20b, 0x04da1e8b, 0x3f167391, 0x28ebb7f5, 0x22599f1d, 0x20e1567a, 0x0c8bbe06, 0x2b69}}}, - /* 7*16^47*G: */ - {{{0x33e674b5, 0x007714bd, 0x3060aac6, 0x363da739, 0x2b8a4f92, 0x36cb26f3, 0x1a66145d, 0x2d896815, 0xa2f3}}, - {{0x0e937941, 0x024e3238, 0x033fa53b, 0x08be8c5f, 0x2a7c4b92, 0x112a43cc, 0x068ae800, 0x28565853, 0x620e}}}, - /* 9*16^47*G: */ - {{{0x191eb056, 0x1d8058c7, 0x2cfd386c, 0x00bbf6e3, 0x3515f5a0, 0x22d71a8f, 0x259231d9, 0x20f27aab, 0x3c4f}}, - {{0x205cecab, 0x109624f6, 0x1cf6b877, 0x20ad5120, 0x32788019, 0x3595cf0e, 0x28b6a33a, 0x2401d452, 0x9447}}}, - /* 11*16^47*G: */ - {{{0x3d86dfa9, 0x24187f6e, 0x1b993a71, 0x0e2d2902, 0x103baadc, 0x30780fa0, 0x167d4e29, 0x384a22a6, 0xaff8}}, - {{0x01d12681, 0x1c40f0db, 0x019f9c70, 0x045b6a51, 0x0f53f4f9, 0x0faea87f, 0x37c3fd3d, 0x12ecc84d, 0x8d8b}}}, - /* 13*16^47*G: */ - {{{0x189ba9c1, 0x23c9cdae, 0x09d338e2, 0x03df2968, 0x0ee579e4, 0x16098abb, 0x000b3e84, 0x1e114a37, 0xd3fb}}, - {{0x2b51b267, 0x186e237f, 0x011ade00, 0x073b7570, 0x370fe634, 0x32815d62, 0x2b4e7ca7, 0x350d3be9, 0xf894}}}, - /* 15*16^47*G: */ - {{{0x0f2bb909, 0x36a5b074, 0x3598d999, 0x24409f14, 0x187d7f63, 0x1ca620e4, 0x1aa88ff4, 0x0c0382b2, 0x4ec9}}, - {{0x24cf4071, 0x2228e0fe, 0x1ac3827b, 0x0b85a083, 0x0c49bad5, 0x03711461, 0x304dc5c8, 0x2841af86, 0x782b}}} - }, - { - /* 1*16^48*G: */ - {{{0x2120e2b3, 0x3ced63e8, 0x347f9aa7, 0x163f739f, 0x26e5217a, 0x392b8d33, 0x1bdbae7b, 0x127c87d4, 0xeaa6}}, - {{0x3a5ad93d, 0x11e94c16, 0x13f7e59d, 0x29ae597c, 0x39aa5a01, 0x2a03e261, 0x3b03ac69, 0x1e7b56ee, 0xbe32}}}, - /* 3*16^48*G: */ - {{{0x3f2e070d, 0x160ff4e8, 0x12a6a98f, 0x2aadc731, 0x1047e229, 0x1cc70ee1, 0x34abff48, 0x297a410b, 0x4b72}}, - {{0x296dd780, 0x112ea0bb, 0x2948c3de, 0x2d197774, 0x0f3c10b0, 0x1deecdb4, 0x2e1cf602, 0x0753875a, 0x599e}}}, - /* 5*16^48*G: */ - {{{0x0a02591c, 0x2739ff61, 0x05125a1e, 0x3d526596, 0x21fd613e, 0x1afefad7, 0x1c8e285a, 0x24ff194e, 0xa9fc}}, - {{0x29bec2dc, 0x242b77bd, 0x3cf72537, 0x22231057, 0x1165e5ca, 0x1305e86a, 0x387173e8, 0x39ce7714, 0x9c2c}}}, - /* 7*16^48*G: */ - {{{0x2d968b59, 0x0401b838, 0x3cbbc2e1, 0x28a2eb84, 0x1b027709, 0x35eb0482, 0x39f0a6a7, 0x005f069b, 0xc940}}, - {{0x0de572fb, 0x3bf5d902, 0x390c9c8f, 0x210b2d90, 0x35742ce2, 0x2286fe96, 0x3862013b, 0x08940326, 0x39d9}}}, - /* 9*16^48*G: */ - {{{0x326b3332, 0x0a1cccd5, 0x3ee5de6a, 0x00e2341c, 0x0bf8e031, 0x1e4e97dc, 0x10024ec6, 0x2ee75fbb, 0x1f84}}, - {{0x14e8d52e, 0x1510a28c, 0x36dc3a25, 0x2f338b50, 0x39edf0c2, 0x1f09fdd6, 0x29ecc254, 0x1b41caf2, 0xee72}}}, - /* 11*16^48*G: */ - {{{0x0defa98e, 0x336a952b, 0x1ac27995, 0x12111a04, 0x11e9c772, 0x2055ece6, 0x1fcd06ca, 0x38224251, 0x0f13}}, - {{0x3e286767, 0x0229dda6, 0x2ceaccdc, 0x1f9c1785, 0x3362db28, 0x0fe2c29e, 0x27c5035e, 0x087c5d93, 0xadd5}}}, - /* 13*16^48*G: */ - {{{0x29f59b6b, 0x178700ef, 0x1888e2fa, 0x2ce318f0, 0x1826d3e9, 0x0a2874b5, 0x1ec7db37, 0x24695477, 0xdde1}}, - {{0x26cb1410, 0x1ab658a4, 0x3154fecf, 0x15ce2ef9, 0x12e14e8b, 0x1d5f5871, 0x275cbe0a, 0x3ede00a0, 0x5b2b}}}, - /* 15*16^48*G: */ - {{{0x09c6b699, 0x1a3157f7, 0x3e46871b, 0x1bd5cd5a, 0x341682a8, 0x1b5efe5e, 0x36f7a5a1, 0x004bbb60, 0x5fab}}, - {{0x01c6c3aa, 0x05cc854b, 0x2883519b, 0x2ac45ffa, 0x162f7b90, 0x2ed044c3, 0x3d144e9e, 0x3e9c28f0, 0x2d9b}}} - }, - { - /* 1*16^49*G: */ - {{{0x1a34d24f, 0x388d8cb7, 0x1a137401, 0x2db63c32, 0x342ee541, 0x077db7b3, 0x3169d939, 0x0b50f173, 0xe4a4}}, - {{0x1eba9414, 0x29fdc4c7, 0x0d8e4f13, 0x21bbb7ea, 0x0ad34ce8, 0x326733ee, 0x1c73526f, 0x24b9c5b4, 0x4d9f}}}, - /* 3*16^49*G: */ - {{{0x3bea0c68, 0x321042bc, 0x37b392b5, 0x10c048d9, 0x396faf09, 0x26f23a34, 0x2a3a2494, 0x258d3855, 0x3e41}}, - {{0x1a45edb6, 0x32edbfdc, 0x03cda1ab, 0x2846518c, 0x0693062f, 0x0f2ff8dc, 0x321f7f37, 0x31676492, 0x0123}}}, - /* 5*16^49*G: */ - {{{0x139824d7, 0x3dd748f2, 0x11c9897a, 0x2ded930d, 0x3f0b576e, 0x128f98bd, 0x17508eed, 0x0e3d5157, 0x8d94}}, - {{0x1366489f, 0x28013d22, 0x26b063d8, 0x2e78ae0c, 0x36ef6f8f, 0x182f4c6a, 0x26c2a2ca, 0x381cd3fb, 0x3261}}}, - /* 7*16^49*G: */ - {{{0x18d713de, 0x39201c6a, 0x028e6208, 0x1830bedd, 0x25454393, 0x2a44a8bf, 0x254420d4, 0x0931563b, 0xb725}}, - {{0x1b8350e9, 0x1bff9496, 0x04a5fcb7, 0x20b49bf9, 0x16941504, 0x0b460ba7, 0x03e45104, 0x2ce6a28a, 0x4c51}}}, - /* 9*16^49*G: */ - {{{0x3e3b2cb4, 0x331b0a4f, 0x37210402, 0x127cd6fc, 0x21149e30, 0x31db8e04, 0x112519ad, 0x17d6885b, 0x3de4}}, - {{0x307eb02f, 0x1878ceb0, 0x287044cf, 0x0f8a3996, 0x3c910682, 0x022a92a5, 0x2addc50e, 0x21661017, 0xba2a}}}, - /* 11*16^49*G: */ - {{{0x2ce4e5bf, 0x08d1d9bd, 0x09005b17, 0x19f2a1a8, 0x0906ae9b, 0x0ff38dd2, 0x1be87c1e, 0x3c71a256, 0x8511}}, - {{0x01789c08, 0x3f24a513, 0x05365262, 0x2a1e226f, 0x2a00232d, 0x377dfb1a, 0x0d4874c1, 0x3d73e46f, 0xecdf}}}, - /* 13*16^49*G: */ - {{{0x3d3258ab, 0x06d59a28, 0x2bc14dc3, 0x3490a062, 0x14ab5957, 0x2871cbb8, 0x360222cf, 0x014ba073, 0x8c5a}}, - {{0x022d0f8f, 0x15f8214c, 0x0d944ade, 0x36ba3e70, 0x0c08c246, 0x2a031e41, 0x3bda1079, 0x36d2ed10, 0x6811}}}, - /* 15*16^49*G: */ - {{{0x3f91bcee, 0x1630a82a, 0x20c0d841, 0x33c763c7, 0x2bf137f5, 0x18f3b155, 0x13560bdc, 0x3e05b7af, 0xcef7}}, - {{0x01966b33, 0x2ed36a7e, 0x172f6ac6, 0x0f92c0a8, 0x1d245fa6, 0x0ecce700, 0x08701246, 0x1320d8dd, 0x67e7}}} - }, - { - /* 1*16^50*G: */ - {{{0x0300bf19, 0x1c5cee75, 0x08fea494, 0x2d4d5daa, 0x352b6b92, 0x183eb6ac, 0x0bdd9541, 0x03fbcd83, 0x1ec8}}, - {{0x0107cefd, 0x1c737073, 0x295a07b6, 0x11b9dfd8, 0x2bbf5e01, 0x2925629e, 0x1340d2f3, 0x3a4dd5ad, 0xaeef}}}, - /* 3*16^50*G: */ - {{{0x12fea1f9, 0x2c5f2ef1, 0x00452b94, 0x3fc2d423, 0x106531c4, 0x3f76ad9c, 0x1f2e83bc, 0x22029574, 0xa6dc}}, - {{0x3bc345e9, 0x2c705391, 0x268f7e63, 0x1ee276df, 0x2cbc5005, 0x1a0e845a, 0x367c3038, 0x2a151f70, 0x7ef1}}}, - /* 5*16^50*G: */ - {{{0x06d6c9b3, 0x235030fc, 0x0865637c, 0x1b133a1d, 0x2481ba8c, 0x308a71e2, 0x245992bd, 0x2a4ffa90, 0xfe6b}}, - {{0x2948bdfb, 0x30b1e23e, 0x1c2e9b00, 0x203c6fc1, 0x013b56d9, 0x2d06cd15, 0x39872b6b, 0x0635d014, 0x7ee9}}}, - /* 7*16^50*G: */ - {{{0x0cf95151, 0x08bc41cc, 0x02c4b644, 0x19201b91, 0x08ded1b9, 0x03230b70, 0x098bfb02, 0x38bc51bf, 0x15d5}}, - {{0x2ff8ecf2, 0x20a81f30, 0x1d8c0f94, 0x0813ee5f, 0x1023f9bb, 0x038425e2, 0x3d4ec7f9, 0x0b8c6457, 0xa5b7}}}, - /* 9*16^50*G: */ - {{{0x296a5658, 0x35e042e4, 0x1ef65643, 0x052c9490, 0x2e29be38, 0x1f80249e, 0x0447ad8c, 0x3a1c95a2, 0x84c0}}, - {{0x181b80d1, 0x3659ca6f, 0x34f1fd22, 0x2986a607, 0x13725ed3, 0x1f8c6419, 0x022c4a08, 0x20e03058, 0x2659}}}, - /* 11*16^50*G: */ - {{{0x14dc6a0f, 0x1d6ed722, 0x2fe15753, 0x10d06450, 0x0077c274, 0x09939e8b, 0x3731d565, 0x2c71c6a4, 0xfed6}}, - {{0x176fc7e0, 0x32e35cb6, 0x23fc409c, 0x1d3564c2, 0x13ae2313, 0x24606b93, 0x3ff0a847, 0x2af9ac3f, 0x8de2}}}, - /* 13*16^50*G: */ - {{{0x18e29355, 0x2ce217c4, 0x1720d86d, 0x0723a4ce, 0x23b9d82f, 0x3be18100, 0x3cbc70fc, 0x137664b4, 0x2a6a}}, - {{0x35cc2872, 0x014f803e, 0x0c4c76c0, 0x24168e99, 0x28f90dfe, 0x3f720789, 0x27e0c760, 0x37ee9f12, 0x8677}}}, - /* 15*16^50*G: */ - {{{0x2148dabf, 0x3e7ea23f, 0x09d78eb1, 0x2b74ae4d, 0x3ae735c1, 0x193b08d7, 0x27546d97, 0x24c09b24, 0xe42d}}, - {{0x011e1361, 0x1dcb1d5a, 0x1e77eb9d, 0x1c9d5c06, 0x33853032, 0x0e33aff7, 0x184b0d8b, 0x218b1b8b, 0x6413}}} - }, - { - /* 1*16^51*G: */ - {{{0x366642be, 0x376d64a0, 0x158ba889, 0x0d241c5f, 0x0dfa8bce, 0x002bd1a0, 0x30c2f91b, 0x1de30119, 0x146a}}, - {{0x3d83efd0, 0x02ca5d20, 0x37e5ed1d, 0x2aa5c74b, 0x14b2870a, 0x1a609fe7, 0x0028add6, 0x383b0cd5, 0xb318}}}, - /* 3*16^51*G: */ - {{{0x27315443, 0x364e1ce0, 0x2e867299, 0x1e6ef552, 0x2142a13d, 0x32266082, 0x0935ff42, 0x1b010198, 0xfc69}}, - {{0x17d28960, 0x1243582d, 0x09bd1b17, 0x1ffd2184, 0x1677b548, 0x0387375a, 0x35892bbf, 0x09fafe0e, 0xe0ce}}}, - /* 5*16^51*G: */ - {{{0x16fdb4eb, 0x06ecbd70, 0x22e6a79d, 0x28f75e71, 0x3eb0928f, 0x15a8d58a, 0x3f2ad1ae, 0x3c887fd3, 0x974a}}, - {{0x29f6f484, 0x10270f7e, 0x3ffc2348, 0x0715ca8e, 0x0090ed11, 0x0790f40b, 0x003ca64d, 0x0e1f54d4, 0x5552}}}, - /* 7*16^51*G: */ - {{{0x1d5aeee3, 0x0e412b6d, 0x258c8137, 0x0a12f0d9, 0x1270c5e8, 0x086ce99a, 0x2398b091, 0x2d66d277, 0x5baa}}, - {{0x30f69717, 0x0b4a6bed, 0x3d31eed8, 0x1777276a, 0x3fdaf721, 0x28021987, 0x37e856e5, 0x1fd85f03, 0x8a57}}}, - /* 9*16^51*G: */ - {{{0x35726890, 0x146c7913, 0x0837d158, 0x24097fab, 0x110a0ee5, 0x0cbf3afe, 0x1c43d010, 0x17e9fad2, 0xfb68}}, - {{0x3835783a, 0x01baa3ce, 0x10e79b26, 0x29b2c4ba, 0x24ba094f, 0x3285b661, 0x25e2e869, 0x37c8b263, 0xd750}}}, - /* 11*16^51*G: */ - {{{0x28bca48a, 0x1192fc4e, 0x03df62f5, 0x2d357d3a, 0x07f71d78, 0x09ee470a, 0x2995a0ab, 0x23fd9678, 0x5de5}}, - {{0x12fd41cd, 0x21e53a03, 0x20f8aa95, 0x396f6713, 0x2d3c843f, 0x2988f094, 0x19b55309, 0x0ecf600d, 0x685a}}}, - /* 13*16^51*G: */ - {{{0x25ef63b6, 0x378e0d13, 0x31b182eb, 0x2d34059c, 0x0fc1c85a, 0x2dff68ed, 0x218bfaf1, 0x09737ab5, 0x6f18}}, - {{0x05c655f3, 0x0b211b3d, 0x27f94541, 0x22569900, 0x3334553c, 0x108135e0, 0x1911b98f, 0x1f9f7564, 0xff09}}}, - /* 15*16^51*G: */ - {{{0x34a63f3b, 0x2d411fb7, 0x178f9727, 0x080ec066, 0x36c76583, 0x1c457d79, 0x2a376b58, 0x2e257dd8, 0xc5ec}}, - {{0x05005024, 0x14fcdd1a, 0x230bee5b, 0x3ad97b97, 0x1233ec8b, 0x290163fe, 0x081f374e, 0x0946065e, 0x2225}}} - }, - { - /* 1*16^52*G: */ - {{{0x3180eef9, 0x35daa1e4, 0x228b9776, 0x00048826, 0x207b128d, 0x2b3aec6a, 0x2e5f07e3, 0x303d8748, 0xfa50}}, - {{0x3f4f2811, 0x233635f4, 0x17a213b3, 0x1a0ca4e9, 0x01a68a5e, 0x334a1c8a, 0x3eba9b72, 0x31a488e5, 0x6b84}}}, - /* 3*16^52*G: */ - {{{0x11da5e12, 0x07b838ce, 0x1cacb297, 0x31829005, 0x1ca2b6a9, 0x0ca7e4e8, 0x1e31bcda, 0x0b8f10de, 0xf750}}, - {{0x0385f4eb, 0x292e717a, 0x325cebc7, 0x21b4cbbd, 0x1672047b, 0x1c25170f, 0x0fafd599, 0x3d7b759f, 0x3c57}}}, - /* 5*16^52*G: */ - {{{0x10b7d105, 0x01d24cc4, 0x0e57c9f2, 0x329712e5, 0x3455b3f4, 0x13d98938, 0x25862a3a, 0x1e3e60eb, 0x12fe}}, - {{0x1f794a60, 0x162b1bee, 0x2ee90b84, 0x3b389975, 0x27cb771d, 0x2d6a8666, 0x2bcf7786, 0x3c68ce35, 0x2062}}}, - /* 7*16^52*G: */ - {{{0x1e0c5d05, 0x188760ce, 0x2572daff, 0x039b142a, 0x084b1a48, 0x12ec40a0, 0x3473d58c, 0x30c4d1f7, 0x76aa}}, - {{0x11ece63e, 0x159866dd, 0x15e6ee35, 0x048973c0, 0x02625f4b, 0x3ccb20c8, 0x070efabe, 0x1dbbc357, 0xef55}}}, - /* 9*16^52*G: */ - {{{0x3c53c086, 0x389bd217, 0x09a1aec9, 0x2d570d27, 0x288104c6, 0x1830c517, 0x05ccc87e, 0x3f96ef97, 0xa663}}, - {{0x25016201, 0x1a7140ca, 0x3994fc0e, 0x07b3295c, 0x023dc399, 0x2c40b226, 0x11fbf5d1, 0x265fdac8, 0xb541}}}, - /* 11*16^52*G: */ - {{{0x0b758574, 0x2b6007b5, 0x34f9c6e9, 0x0c99a250, 0x22bdf3d8, 0x328409eb, 0x2cd825b7, 0x149e8081, 0xde95}}, - {{0x3b67232a, 0x2df7c7f3, 0x15a2deb4, 0x39a84145, 0x169ed7ba, 0x077211fc, 0x3d14e4e2, 0x3815ab24, 0x4cd3}}}, - /* 13*16^52*G: */ - {{{0x3d85474f, 0x1de6e2af, 0x1634668d, 0x13128ae2, 0x385aea89, 0x3732f911, 0x32addbfe, 0x2f3819b4, 0x8da6}}, - {{0x3d7b4ef7, 0x3f7e71f4, 0x1dbdd7a5, 0x073164c1, 0x1dfff10b, 0x377d741c, 0x2d4ff84f, 0x1b1abcc7, 0x13fc}}}, - /* 15*16^52*G: */ - {{{0x3dd042ea, 0x2d750959, 0x18eafd06, 0x3e89a991, 0x3c93beeb, 0x3599278c, 0x3ba39b1b, 0x2b31f3ec, 0x7329}}, - {{0x2f5c94a1, 0x36a33fb0, 0x1fab4f0a, 0x1225dcc7, 0x2b68ee18, 0x2139e53e, 0x36f14892, 0x124d506d, 0x9272}}} - }, - { - /* 1*16^53*G: */ - {{{0x1f067ec2, 0x394f4cad, 0x1bba5220, 0x0a22ad75, 0x08e8421a, 0x16fdadf6, 0x21a11b1a, 0x1874329c, 0xda1d}}, - {{0x1ad836f1, 0x157ee83c, 0x279b48a6, 0x29ce2674, 0x091e2966, 0x01d98587, 0x1306c79c, 0x3d569f26, 0x8157}}}, - /* 3*16^53*G: */ - {{{0x3a95a8db, 0x1761dccb, 0x39d36f61, 0x0fb03111, 0x1b1723b8, 0x25991a64, 0x3dd0419e, 0x036918c0, 0xe3e9}}, - {{0x1b0d1cf9, 0x005b3dfc, 0x0984d3d1, 0x2c7be5f3, 0x02e76afb, 0x3eaa431c, 0x0178bb00, 0x0ef0015b, 0xfbe5}}}, - /* 5*16^53*G: */ - {{{0x112ee214, 0x1eabf590, 0x19315401, 0x0a93a5e5, 0x00c01c78, 0x19437f57, 0x3d775a8b, 0x3fb1ccb8, 0x9f4f}}, - {{0x1085f37a, 0x3bd10889, 0x3c880283, 0x066da4c2, 0x35c69d97, 0x259a0bf5, 0x22f2e60e, 0x38b84c63, 0x639c}}}, - /* 7*16^53*G: */ - {{{0x1f61a0a5, 0x22da0514, 0x3c14e3ef, 0x0494f86c, 0x040b2c4b, 0x0682907d, 0x34ac1b17, 0x188b5044, 0x431f}}, - {{0x38cef899, 0x1adedff9, 0x15657724, 0x2eaa810d, 0x23aa7241, 0x3799465c, 0x2438f6d6, 0x0c9ff9ea, 0xa298}}}, - /* 9*16^53*G: */ - {{{0x27748503, 0x2b099f55, 0x31328e7c, 0x1b8391dc, 0x0a12ac0e, 0x18bbce7e, 0x38fb86cb, 0x2eb77b39, 0x993d}}, - {{0x3eb0cee2, 0x2e9cd84d, 0x38adaa49, 0x3e1efda6, 0x21f51a17, 0x3de11e1e, 0x1eeeb785, 0x2a7ba15a, 0xa521}}}, - /* 11*16^53*G: */ - {{{0x26d23d80, 0x37a889d6, 0x2474d478, 0x02f447c9, 0x0962c0e1, 0x250c72e4, 0x15ea5a33, 0x1eae81ab, 0x75f1}}, - {{0x280dd57e, 0x21aa16c0, 0x34ea5909, 0x0bfefb6e, 0x1b629237, 0x31f42fc6, 0x39a80c7f, 0x18bf8558, 0xa07a}}}, - /* 13*16^53*G: */ - {{{0x21ad3413, 0x38ae6db5, 0x327d684a, 0x2e700100, 0x387b7a8d, 0x257d2172, 0x1f4a0a6e, 0x15578476, 0x6678}}, - {{0x3ebca672, 0x09204081, 0x2dc66601, 0x338b454e, 0x0bdf9ea6, 0x099b649f, 0x0f646925, 0x368f789e, 0x510d}}}, - /* 15*16^53*G: */ - {{{0x06cc8563, 0x3002bd6c, 0x3e101eaa, 0x0937d6ff, 0x16368892, 0x320af606, 0x27748ada, 0x128d8b36, 0xebdc}}, - {{0x2394ccfa, 0x26c5ef3a, 0x1204f924, 0x3101e492, 0x1d4f07be, 0x3b8d79b3, 0x2d35f9b1, 0x0c513a15, 0x659a}}} - }, - { - /* 1*16^54*G: */ - {{{0x0d064e13, 0x29cec184, 0x06f1e062, 0x0c477811, 0x3d416615, 0x17fe63a3, 0x30690721, 0x20bfc325, 0xa8e2}}, - {{0x11f4cc0c, 0x3bdf1cc4, 0x0dd6bd6c, 0x19e68f94, 0x2515888b, 0x2dfcf16c, 0x01c09abf, 0x0d56e36e, 0x7f97}}}, - /* 3*16^54*G: */ - {{{0x3a3979b5, 0x0a8666c2, 0x27e829e2, 0x0a23e379, 0x240e50ba, 0x0dfc2c7b, 0x1e26327f, 0x01f1736b, 0xae22}}, - {{0x0450fa6f, 0x23cf359a, 0x3d4f8896, 0x2a1edf4d, 0x2d7060fc, 0x3249148e, 0x39f71ad4, 0x3f944301, 0xea91}}}, - /* 5*16^54*G: */ - {{{0x0efca824, 0x10406440, 0x22164fae, 0x2f8313fa, 0x185461e0, 0x31504019, 0x2ace59ce, 0x3b432b5c, 0xcb8d}}, - {{0x0f227361, 0x0502f416, 0x3931742f, 0x2b47f7f1, 0x2ccbc496, 0x05b121e8, 0x188c85b3, 0x0023dd03, 0x33a5}}}, - /* 7*16^54*G: */ - {{{0x3bcbd327, 0x1046d368, 0x1e4aaee9, 0x13821488, 0x276ed6b0, 0x2524035f, 0x1836708e, 0x0eca62bc, 0xb0c5}}, - {{0x2d7be436, 0x185af128, 0x0636a0f1, 0x0a88831d, 0x26b2afd8, 0x3da9806d, 0x17ea1638, 0x25d007ef, 0xee2a}}}, - /* 9*16^54*G: */ - {{{0x17b836a1, 0x39bbed8e, 0x3679ef7d, 0x019017fd, 0x37f526c8, 0x2218bb39, 0x1b920d4d, 0x29cfcca7, 0x6f6b}}, - {{0x06832b84, 0x36f7cbec, 0x0e1ff934, 0x264314a2, 0x3ee9c0d8, 0x02e29016, 0x3c18e3db, 0x2285ffd7, 0xdc77}}}, - /* 11*16^54*G: */ - {{{0x1eb39ede, 0x2bb8d082, 0x30612d42, 0x02200cb5, 0x02436031, 0x3fd19f84, 0x22af4bbc, 0x069f71d0, 0x7d47}}, - {{0x2bf6607e, 0x326f3652, 0x022a8fd0, 0x2573df47, 0x3c86fa77, 0x2088c7bf, 0x2856507b, 0x1ec67ce9, 0x004a}}}, - /* 13*16^54*G: */ - {{{0x165eb1c1, 0x15b52789, 0x1ae5c5aa, 0x335d59f3, 0x02f0967f, 0x03f30c66, 0x33fac707, 0x1458fe6d, 0xf002}}, - {{0x2dde2ae0, 0x369f5c11, 0x2cd11e57, 0x1dbfd735, 0x26afed85, 0x1ad29768, 0x120df4c6, 0x2a7a220f, 0x054e}}}, - /* 15*16^54*G: */ - {{{0x1ac32c64, 0x33cd424f, 0x0ae4bf84, 0x0dbf80fb, 0x07715e0e, 0x013a543d, 0x123aa0f7, 0x0500007b, 0xac12}}, - {{0x1eb1a867, 0x204ab6eb, 0x253f0898, 0x16974e96, 0x0499a3ed, 0x02da55cc, 0x38baf187, 0x2f32eb0c, 0xce8e}}} - }, - { - /* 1*16^55*G: */ - {{{0x0319497c, 0x0bce0b7a, 0x12508c02, 0x166c7e94, 0x13cab15d, 0x2795b9a4, 0x285872d3, 0x14ee7268, 0x174a}}, - {{0x079afa73, 0x0f684eb0, 0x0b985438, 0x1ace8763, 0x07f9e664, 0x10557cb1, 0x09c1657b, 0x370deaff, 0xccc9}}}, - /* 3*16^55*G: */ - {{{0x354b8367, 0x25201cf5, 0x3d506bfe, 0x1d6ddf59, 0x036a5db7, 0x2a975161, 0x2526e40c, 0x0252b911, 0x5e5a}}, - {{0x11ce85ca, 0x14ca6a76, 0x1e5ffa44, 0x1aaa7bcf, 0x2a4b7a79, 0x2407c55c, 0x15e05c2c, 0x3e32691e, 0xae8a}}}, - /* 5*16^55*G: */ - {{{0x17b10d9d, 0x06615e4e, 0x11f8fcaf, 0x294bc627, 0x0cb82de6, 0x332e0cc4, 0x02e859de, 0x382b6e5c, 0x00d4}}, - {{0x3140dced, 0x20840121, 0x0e2d923e, 0x1626325e, 0x2287f70b, 0x0be1190c, 0x3640947d, 0x0066060d, 0x87b8}}}, - /* 7*16^55*G: */ - {{{0x1c9caee8, 0x02046982, 0x1a270bb2, 0x0b88116c, 0x04a66763, 0x1e866bbb, 0x374c0f6f, 0x1484da3b, 0x0366}}, - {{0x3772b711, 0x2a7b1a8e, 0x295ba7f0, 0x32ea624c, 0x26944501, 0x27f1a06e, 0x3ded9994, 0x30cacaa4, 0x1f18}}}, - /* 9*16^55*G: */ - {{{0x1446c85c, 0x0ffe5d46, 0x201c0635, 0x0df78239, 0x36c6eade, 0x19db114f, 0x38f1faa0, 0x24415bf6, 0x0e58}}, - {{0x2148972e, 0x3db1df9c, 0x0cddadd5, 0x2408d3a0, 0x081898f4, 0x1d062ebd, 0x27bda0ec, 0x1217c47e, 0xe39a}}}, - /* 11*16^55*G: */ - {{{0x022e1259, 0x3c62b7cf, 0x281362af, 0x05ce6901, 0x07777193, 0x33d7ea80, 0x1463f2b6, 0x049b49bc, 0xa740}}, - {{0x334a5f43, 0x3ddc5c90, 0x31d6dad5, 0x21979d4e, 0x3c7ee517, 0x17c5d299, 0x0f1ff1b0, 0x3feebc65, 0x05a9}}}, - /* 13*16^55*G: */ - {{{0x0b08f1fe, 0x22285e8f, 0x3a087bfd, 0x339fb9c2, 0x02d177d7, 0x1015d976, 0x074e4a65, 0x2e085b65, 0x87e4}}, - {{0x2ed5e2ec, 0x17dd2b26, 0x2786d9d7, 0x0bc8f6f5, 0x38c2cc6e, 0x35fe3a8b, 0x348cecd7, 0x0eb01d98, 0xf74e}}}, - /* 15*16^55*G: */ - {{{0x21c4d15c, 0x2a1c039a, 0x3c0e74b9, 0x17a9efc1, 0x254a4410, 0x308b0304, 0x279a5a92, 0x06d18ffa, 0x35ea}}, - {{0x3f3fe1ea, 0x324e6ebd, 0x065095ed, 0x18cea80c, 0x0d3b185d, 0x23e97f5d, 0x2d2cd788, 0x245946e7, 0xad21}}} - }, - { - /* 1*16^56*G: */ - {{{0x1475b7ba, 0x213f7fc2, 0x0918b3d8, 0x0e79cc39, 0x018cdbe0, 0x395fb7d4, 0x3785c3d3, 0x25a60650, 0x9593}}, - {{0x3524f2fd, 0x26e2afe1, 0x0709385e, 0x194fd932, 0x1cd6849c, 0x00e1a92e, 0x331dd8ba, 0x154a2230, 0x2e7e}}}, - /* 3*16^56*G: */ - {{{0x0fd69985, 0x02717764, 0x1df72aea, 0x0c2732db, 0x0ccf149f, 0x3da437ef, 0x32f7e788, 0x1d9d73ad, 0x0ae9}}, - {{0x1409a003, 0x2723ad04, 0x2ee1aff8, 0x2e67505e, 0x1a54c5d0, 0x237fb814, 0x08d14e9b, 0x265cfdb9, 0x9121}}}, - /* 5*16^56*G: */ - {{{0x19262b90, 0x37064f7f, 0x23cc29a9, 0x08f1307f, 0x025d1fb7, 0x197c5de0, 0x1612ec9b, 0x218a96b0, 0x2b15}}, - {{0x083d7557, 0x24665b99, 0x19489a49, 0x14d25c3e, 0x0749066f, 0x0c354b6a, 0x233faa7a, 0x014f6a82, 0x2eb0}}}, - /* 7*16^56*G: */ - {{{0x28e7be40, 0x0fe5c532, 0x1040ee59, 0x34b22524, 0x24769af2, 0x2570585b, 0x2ee677ee, 0x3abb46a5, 0x6af9}}, - {{0x2e387e1c, 0x2905b809, 0x0f59569f, 0x38fd99a8, 0x07dc8145, 0x27a90a0d, 0x06649670, 0x0a845a40, 0xb381}}}, - /* 9*16^56*G: */ - {{{0x3482801e, 0x09adbe83, 0x1bd4155d, 0x1e53e2f1, 0x38d6f940, 0x2aad0932, 0x0144eeb3, 0x1a3b8111, 0x5966}}, - {{0x04870c37, 0x11dc523c, 0x3d3535ad, 0x2db072d8, 0x31304e8d, 0x23e5821d, 0x2ef5f1ec, 0x282a16ee, 0x949a}}}, - /* 11*16^56*G: */ - {{{0x032c19fd, 0x1326cb9f, 0x18028c3e, 0x32ae3a41, 0x170b5b4a, 0x3d345ead, 0x050762fd, 0x346206d4, 0xbe84}}, - {{0x32f1281f, 0x1da5294d, 0x250dc376, 0x1569fd57, 0x08399479, 0x3997d20c, 0x050944d1, 0x1832ccb7, 0xeff9}}}, - /* 13*16^56*G: */ - {{{0x16c69482, 0x346dd7f5, 0x32fa167b, 0x3aad5004, 0x32bc88cb, 0x15c9d32b, 0x17ee541f, 0x280c5303, 0x9867}}, - {{0x2f792cd7, 0x1bc18451, 0x15628a91, 0x189173d4, 0x3a99639e, 0x24b556c6, 0x0834f9c7, 0x18568ec4, 0xd02e}}}, - /* 15*16^56*G: */ - {{{0x1d557aa1, 0x2288e764, 0x101fc297, 0x0764bfb3, 0x19d6abdf, 0x1fcba802, 0x0815a592, 0x3c915036, 0xa866}}, - {{0x01430634, 0x2606eed3, 0x0611a4b7, 0x3ada719f, 0x30e13961, 0x0f63e976, 0x22b44d79, 0x0e7daa00, 0xb587}}} - }, - { - /* 1*16^57*G: */ - {{{0x1d82b151, 0x2d44d032, 0x21fba2db, 0x28290f55, 0x109a8fcc, 0x168454ec, 0x01e56d64, 0x0e942b90, 0xd2a6}}, - {{0x1cf89405, 0x105085d3, 0x084ca52d, 0x03dd42bd, 0x148220a7, 0x2bb962ca, 0x3fcb7565, 0x21bed910, 0xe82d}}}, - /* 3*16^57*G: */ - {{{0x2e4b3ba0, 0x2167d8d7, 0x18bf1f17, 0x0aafbd7c, 0x3f245f5c, 0x385c3cc6, 0x3fb73bef, 0x04414887, 0x4108}}, - {{0x17525595, 0x21a58770, 0x1a064554, 0x0d926159, 0x2b849813, 0x2996b875, 0x35668f2c, 0x3cda5dbf, 0xdc37}}}, - /* 5*16^57*G: */ - {{{0x13d98ded, 0x18a726e2, 0x38a02184, 0x37c8a0ce, 0x31d65edb, 0x3c8a6414, 0x0c0c8c8c, 0x2884285b, 0x63a2}}, - {{0x20d1cfc2, 0x06465f53, 0x1c7873a5, 0x2afda802, 0x2d94461f, 0x140cc953, 0x2c76fd06, 0x10b8b9ff, 0x882b}}}, - /* 7*16^57*G: */ - {{{0x38045445, 0x2a186942, 0x01e8d7ee, 0x3fdcdc64, 0x17bef080, 0x04b8b975, 0x167ca3df, 0x20575127, 0x0c15}}, - {{0x0054a206, 0x053e1f55, 0x258cea32, 0x0c15390d, 0x23cd28ba, 0x24f0ed99, 0x14115d0a, 0x35828eba, 0x2f30}}}, - /* 9*16^57*G: */ - {{{0x03857faf, 0x3a448e73, 0x29619701, 0x0bf2b787, 0x28ef7f88, 0x1eea3d20, 0x28a9c0d5, 0x3adae26b, 0xc757}}, - {{0x20584ca4, 0x07676c32, 0x01894c10, 0x1f4c4344, 0x3ec61b62, 0x0da7c822, 0x3ff36257, 0x1673f348, 0xf03a}}}, - /* 11*16^57*G: */ - {{{0x1459225d, 0x3934613d, 0x18858d10, 0x3ebddf8b, 0x1c02a244, 0x17502646, 0x3a0d0f81, 0x18ebab6b, 0xfa80}}, - {{0x3ece1507, 0x28adf8ed, 0x007c59c3, 0x0adb0db4, 0x0c425c0a, 0x37888209, 0x0c069160, 0x07e415f0, 0x0ba7}}}, - /* 13*16^57*G: */ - {{{0x16f0d044, 0x19e7fa50, 0x09e61a79, 0x2ea7f524, 0x2ee0a5aa, 0x3da73e18, 0x257a89e2, 0x28f16740, 0x658c}}, - {{0x37cb872d, 0x3747ccbb, 0x018ce89a, 0x2859d8f1, 0x3bd37655, 0x197589c4, 0x225460f1, 0x304ddeba, 0xae5c}}}, - /* 15*16^57*G: */ - {{{0x3696756d, 0x2d6b255c, 0x2561417a, 0x1abc5815, 0x3f305c67, 0x30660d74, 0x1f2bace4, 0x12d2abe4, 0x31c9}}, - {{0x1e08ae78, 0x2f117a37, 0x2ad1070a, 0x2bb7f2b9, 0x34160683, 0x2e2d66ab, 0x283a9bf4, 0x2212d55b, 0xf80f}}} - }, - { - /* 1*16^58*G: */ - {{{0x1617e073, 0x10dbe6d1, 0x039317b3, 0x2b2f6f4e, 0x0fdc866b, 0x39e25b5f, 0x31eb890e, 0x1f88cd51, 0x6458}}, - {{0x1faf6589, 0x20a6797a, 0x33aeab35, 0x2e428e44, 0x0299a185, 0x1b75911f, 0x102e2ae9, 0x33756fda, 0xd99f}}}, - /* 3*16^58*G: */ - {{{0x0e103dd6, 0x37dc51c8, 0x0004859a, 0x1181301f, 0x12a17ac3, 0x084f3f16, 0x203f836a, 0x1ef55690, 0xbc47}}, - {{0x16f7c343, 0x0e420b63, 0x23b44ac6, 0x0a4d5cb1, 0x1ea6395d, 0x2b154b1b, 0x0dd526cb, 0x07890a6a, 0xe31e}}}, - /* 5*16^58*G: */ - {{{0x144eab31, 0x34370ec3, 0x0e634907, 0x316bc501, 0x3bf8e80a, 0x0ed08c99, 0x3b838030, 0x2d3f969a, 0x589d}}, - {{0x11361f6a, 0x106baf9d, 0x148f8db9, 0x18439548, 0x3d90f31f, 0x1c188092, 0x2a2a4f60, 0x11170422, 0x6255}}}, - /* 7*16^58*G: */ - {{{0x1a0c2c41, 0x2fe585ca, 0x20336c67, 0x20c70715, 0x2edb7c42, 0x286182b5, 0x22fa2ea8, 0x2ccdf45b, 0x1339}}, - {{0x29f1bc2b, 0x217c152e, 0x1e923a41, 0x0489fe1f, 0x13a3406b, 0x0c903f44, 0x3ae5ba7a, 0x0a58d8b1, 0x9f9b}}}, - /* 9*16^58*G: */ - {{{0x18fc47af, 0x1c12c7e1, 0x2c0cdec3, 0x377fb20c, 0x01b568a8, 0x00ca6d40, 0x3cf17cc5, 0x2ee844d8, 0x7ff3}}, - {{0x39ba43a7, 0x3e185933, 0x18bac297, 0x294ec6b4, 0x33446b17, 0x32246dd1, 0x0a629a0b, 0x29eba006, 0x1f6b}}}, - /* 11*16^58*G: */ - {{{0x15213775, 0x06135802, 0x3d42a990, 0x2d0a4ec8, 0x2c7f6100, 0x07a4e57f, 0x360bb614, 0x1c118f3a, 0x8ec6}}, - {{0x3841ffff, 0x38043cf9, 0x0cf51e90, 0x36a6282f, 0x2dee0e71, 0x190d0573, 0x25be306e, 0x299be836, 0x8f58}}}, - /* 13*16^58*G: */ - {{{0x3452abbb, 0x32cffe34, 0x2b95c2e3, 0x1aa9cbf8, 0x15d495ae, 0x2eb0ffb6, 0x301bb89d, 0x186d1079, 0x83de}}, - {{0x054eb66e, 0x28145dac, 0x3ce42918, 0x2717cdae, 0x0e1563d7, 0x3edabe31, 0x0609fa6b, 0x38cd28d3, 0x32f0}}}, - /* 15*16^58*G: */ - {{{0x359276f1, 0x25a2309b, 0x2a17b15e, 0x2b896ca4, 0x3cd86833, 0x2ed7003d, 0x0c1db1a8, 0x18e263d4, 0x3d76}}, - {{0x059cbcb3, 0x0792996e, 0x1b197860, 0x08660806, 0x18333ef3, 0x1db8d36b, 0x07ddb609, 0x1a5cde86, 0xd376}}} - }, - { - /* 1*16^59*G: */ - {{{0x1d45e458, 0x1635b21b, 0x250e7fd3, 0x02a9b3a8, 0x09de042f, 0x151b4f95, 0x0d885b3a, 0x2f783939, 0x8481}}, - {{0x1779057e, 0x3592c6d6, 0x3262e556, 0x029e710a, 0x2cb2ca90, 0x096fce73, 0x004dd84a, 0x1ee32e95, 0x38ee}}}, - /* 3*16^59*G: */ - {{{0x152da17d, 0x18283e90, 0x0d0646b1, 0x3704f6c2, 0x200bc811, 0x139ac17f, 0x18c5f089, 0x3b4783d4, 0x3bea}}, - {{0x2cc768d2, 0x39c12617, 0x1fec416c, 0x3379dee3, 0x00e1b554, 0x12a2fafa, 0x37acdfef, 0x35fd56bf, 0xc3b0}}}, - /* 5*16^59*G: */ - {{{0x3a4edcc5, 0x0d3e85f6, 0x20311b72, 0x138c8850, 0x275997e7, 0x0b7f00e4, 0x09d61875, 0x36e832f7, 0x6e73}}, - {{0x159da0e4, 0x2cc7df37, 0x00679037, 0x229df69c, 0x02869327, 0x11542222, 0x2cc48bea, 0x307f127b, 0xee0a}}}, - /* 7*16^59*G: */ - {{{0x0a80b979, 0x02713109, 0x29abb314, 0x243d7e8c, 0x07c31004, 0x1f65faa9, 0x1b592762, 0x37624df9, 0x7706}}, - {{0x0126cfde, 0x133d2041, 0x17efe321, 0x3e828d3f, 0x2a9c7117, 0x2375e647, 0x3b714777, 0x2a609f56, 0x8a02}}}, - /* 9*16^59*G: */ - {{{0x326fe285, 0x336e712d, 0x13ef127d, 0x16eb0a50, 0x39e06aa4, 0x3cf1e907, 0x3c0f80d2, 0x08b164a6, 0x16d4}}, - {{0x0155b441, 0x0f83ff9b, 0x3364d423, 0x0fc3044d, 0x3531b1e9, 0x2df9a698, 0x22641a8a, 0x223e9478, 0x0df8}}}, - /* 11*16^59*G: */ - {{{0x3acfa513, 0x38c42f2a, 0x260e3aea, 0x0901e7e6, 0x356a9c4e, 0x28d11d43, 0x36d63aa5, 0x0391fbb1, 0x1fcc}}, - {{0x107afc9c, 0x141d6e90, 0x09839187, 0x3b7b7459, 0x39f9b44b, 0x38e1d50c, 0x35478b48, 0x30681078, 0x165d}}}, - /* 13*16^59*G: */ - {{{0x3edc69b2, 0x0689c1f3, 0x26b77172, 0x0298226c, 0x0aa386a5, 0x190c10d7, 0x0b8a1730, 0x241ceb5b, 0xc12b}}, - {{0x20dd41dd, 0x0caba6c0, 0x127b2a00, 0x3b876f8f, 0x094976b8, 0x1cb7227e, 0x0cdf1d97, 0x310ff94d, 0x3173}}}, - /* 15*16^59*G: */ - {{{0x3961fe4d, 0x2dbd6177, 0x3107197a, 0x05221be2, 0x2ca73e8a, 0x0fa4c4c4, 0x27a8fa3f, 0x2fe1770c, 0xd059}}, - {{0x2ae823c2, 0x264d6c19, 0x0dab64cb, 0x0e22e87d, 0x0955b4fd, 0x01d97721, 0x3525e3fe, 0x1e983022, 0x4510}}} - }, - { - /* 1*16^60*G: */ - {{{0x2caf666b, 0x3358c0fd, 0x0b1ce30b, 0x3f3fb4f1, 0x17f4637f, 0x1a5e6ba0, 0x102aa62b, 0x1295e9e0, 0x1346}}, - {{0x3f6ecc27, 0x3d256a41, 0x10942e13, 0x3cc02a07, 0x0cb0ca48, 0x390cd14f, 0x14580ef7, 0x05640118, 0x69be}}}, - /* 3*16^60*G: */ - {{{0x0eca5f51, 0x085ac826, 0x0fc9aebf, 0x3a85c6e5, 0x05b5cfdd, 0x3b5acafc, 0x2e6962c6, 0x35453767, 0xdde9}}, - {{0x10c638f7, 0x2b5a69cf, 0x289571f9, 0x3fbafa37, 0x3f8f0950, 0x07cd2c29, 0x28111d89, 0x1a44cf38, 0xb84e}}}, - /* 5*16^60*G: */ - {{{0x199c88e4, 0x3e41ac16, 0x0ad46ec2, 0x3b544f88, 0x204b179a, 0x3d01bac4, 0x193736e9, 0x188408da, 0xfd1a}}, - {{0x195bc8df, 0x27232459, 0x1cc00f29, 0x1adc7525, 0x177782dc, 0x0f01a552, 0x0c20bfb1, 0x1ed52e72, 0x1ac9}}}, - /* 7*16^60*G: */ - {{{0x1f8018ce, 0x35456d6d, 0x1892d68b, 0x0b695ce3, 0x086dc7cf, 0x3ff393cb, 0x296b9f13, 0x214c7630, 0x4ee4}}, - {{0x1e48381f, 0x30d6986c, 0x0e806013, 0x01d25c6d, 0x07c5e671, 0x2d102343, 0x3f8b5fc7, 0x27b52042, 0xb68f}}}, - /* 9*16^60*G: */ - {{{0x31473678, 0x0a14ba47, 0x14392f70, 0x2815e542, 0x38c070cb, 0x38c53156, 0x000dbff5, 0x33270d31, 0xfd76}}, - {{0x0d144f4f, 0x38593baa, 0x001c8437, 0x18a3bb85, 0x032cd660, 0x3b829cf4, 0x143dae0f, 0x1950de1c, 0xf204}}}, - /* 11*16^60*G: */ - {{{0x0d7a2193, 0x3c02dc52, 0x197546ed, 0x1a47913c, 0x34ea212c, 0x1b3a09d2, 0x3b40219e, 0x2ae8cc48, 0x85a2}}, - {{0x30cdcf3a, 0x3c320f52, 0x03b12427, 0x31b6b7e7, 0x0c029fe1, 0x31820b47, 0x30516d82, 0x2615faca, 0x9c12}}}, - /* 13*16^60*G: */ - {{{0x377568b0, 0x16c0c16c, 0x1e03b053, 0x2ba37406, 0x03650f35, 0x2db5b15e, 0x3fe74440, 0x36ff1cf3, 0xd25d}}, - {{0x1f39929c, 0x0284e49b, 0x23c3f006, 0x089ce207, 0x27d92b83, 0x2bbdd337, 0x048938be, 0x3fdd64fe, 0x7a3a}}}, - /* 15*16^60*G: */ - {{{0x271d7c13, 0x17f94462, 0x20ffa385, 0x06ad7dfe, 0x2ac80564, 0x01fa6a5e, 0x14a7255f, 0x0d4c50fa, 0x4581}}, - {{0x3aff63cf, 0x18e2f154, 0x2bd96b99, 0x08019550, 0x1d69c970, 0x3d43c5df, 0x39ad8b57, 0x163b0525, 0x9f58}}} - }, - { - /* 1*16^61*G: */ - {{{0x2d83f366, 0x2b68e834, 0x2f28588c, 0x36733b78, 0x1dc97a0c, 0x3d0c2f30, 0x3fe2e9ae, 0x277d6dc4, 0xbc4a}}, - {{0x181f33c1, 0x1d635999, 0x2547b16d, 0x3a2a7efe, 0x3798caa6, 0x24deb7d2, 0x05c06383, 0x20729b9e, 0x0d3a}}}, - /* 3*16^61*G: */ - {{{0x3712be3c, 0x01a8b8cb, 0x2146a66b, 0x257c63b6, 0x00153472, 0x1c976eac, 0x1b378d3c, 0x0d2764cc, 0x39d7}}, - {{0x1c6ff65c, 0x30c067d0, 0x0a41644c, 0x17bde97b, 0x2812e8ef, 0x09d55319, 0x33bf7fb1, 0x26d3d5bb, 0x8f92}}}, - /* 5*16^61*G: */ - {{{0x1f77f22b, 0x2ab93ef3, 0x0f82e035, 0x265c8e65, 0x15af26c6, 0x0735b0a6, 0x01dd09e5, 0x2985fdf7, 0xf0cb}}, - {{0x1909a03c, 0x3f238b1d, 0x0a095661, 0x3c631fa4, 0x16d04004, 0x0c9b0d94, 0x1df989ef, 0x2ad0c4fe, 0x1a25}}}, - /* 7*16^61*G: */ - {{{0x06509c12, 0x22b37353, 0x3d1f4765, 0x1aff88d6, 0x3268ed8d, 0x05c3a361, 0x154d321d, 0x1eae76c8, 0x381d}}, - {{0x2eb46102, 0x1190aa38, 0x0e6eaf75, 0x160a161b, 0x2581e720, 0x34915ce9, 0x23da9eb5, 0x2ad6dff6, 0xa47a}}}, - /* 9*16^61*G: */ - {{{0x384fe955, 0x36ced358, 0x063bce48, 0x2655a968, 0x0c8a53f6, 0x0edcf9a5, 0x387e6479, 0x3c1519ea, 0xa703}}, - {{0x161344bd, 0x09acbbef, 0x197277fa, 0x27858a71, 0x19199b53, 0x29e4b5ac, 0x047adc0e, 0x3e4d68ac, 0xd500}}}, - /* 11*16^61*G: */ - {{{0x06eace58, 0x126595b0, 0x2f3211d3, 0x1f9158e8, 0x13a03f1b, 0x1ab435c1, 0x150d746c, 0x2cf16ab5, 0x73c6}}, - {{0x2af8654e, 0x05c2a45c, 0x3b8d2917, 0x1aa1e36e, 0x2d91c6aa, 0x242644d9, 0x24f741ba, 0x2d291cce, 0x3a2f}}}, - /* 13*16^61*G: */ - {{{0x00181d5e, 0x12ce22fc, 0x15aaf205, 0x1c6cea6e, 0x0eddb8de, 0x0034e870, 0x147fda1d, 0x3cf9d41b, 0xc627}}, - {{0x369f886d, 0x09e40298, 0x1cbe2c39, 0x3dac0152, 0x21f7d68e, 0x1a5804e2, 0x02a63b2d, 0x2775c791, 0xd78f}}}, - /* 15*16^61*G: */ - {{{0x37828b16, 0x138a367e, 0x0a4847f3, 0x11e563ca, 0x06de53a0, 0x17d029bc, 0x3d233fa2, 0x3eaf83b7, 0xbb88}}, - {{0x0aea5df7, 0x1451ce88, 0x3a1e969c, 0x12a05d38, 0x159163ec, 0x37165804, 0x1e8dd345, 0x1dacc13d, 0xb736}}} - }, - { - /* 1*16^62*G: */ - {{{0x25324caa, 0x152acc3f, 0x29472a39, 0x12d978c2, 0x12a32e69, 0x3631d251, 0x18bc0d23, 0x2a5efe0a, 0x8c28}}, - {{0x0bef9482, 0x39c771cf, 0x11cb9459, 0x39e13c11, 0x3cc0eb7a, 0x3fb7cc7d, 0x05193378, 0x0118e8cc, 0x40a3}}}, - /* 3*16^62*G: */ - {{{0x0754dd40, 0x18fa1c55, 0x03466cf8, 0x10898c7f, 0x32f6e9a2, 0x12107f35, 0x0dfcf45b, 0x091c0cb0, 0x9729}}, - {{0x2aa36143, 0x212d24bc, 0x1acaf493, 0x36ba1495, 0x14df3690, 0x171d772f, 0x3ea1dcd1, 0x28910997, 0x91d1}}}, - /* 5*16^62*G: */ - {{{0x0c2ca7ff, 0x30b60bae, 0x1df021a3, 0x00d91765, 0x2f27af18, 0x1e46b568, 0x2796e050, 0x1fe5d602, 0x8963}}, - {{0x30493e68, 0x3b505785, 0x242eab7b, 0x1ef1a8e3, 0x357489f8, 0x2e73c550, 0x08424d57, 0x38492322, 0x2d1f}}}, - /* 7*16^62*G: */ - {{{0x0ca8dd7f, 0x061b58e8, 0x2a1381a6, 0x31ca00d5, 0x1357421b, 0x327680f5, 0x25e092fd, 0x0e39c6f8, 0x3081}}, - {{0x0a92c7f2, 0x1057c91e, 0x34ad915e, 0x05959190, 0x008e18c8, 0x27b11745, 0x0fc925e3, 0x38b4a20a, 0x28d1}}}, - /* 9*16^62*G: */ - {{{0x066a3fb1, 0x037315a2, 0x192e206c, 0x30024a06, 0x36862f6e, 0x15d43216, 0x1eb65d1e, 0x313a0a9b, 0x575f}}, - {{0x102655ad, 0x26e3a42a, 0x2a3af2f0, 0x0ced5cf1, 0x0e87daed, 0x076f0a5e, 0x2fca2d67, 0x36e410a9, 0x6f6e}}}, - /* 11*16^62*G: */ - {{{0x390117df, 0x06daa291, 0x22010292, 0x094eeef3, 0x2a2a8fda, 0x3c9be07b, 0x2ab7a227, 0x240dad93, 0xa5ec}}, - {{0x386462fe, 0x204a04cf, 0x214a363d, 0x21187c15, 0x1fa0f71c, 0x25e60eb4, 0x140400c5, 0x319897b0, 0xb79d}}}, - /* 13*16^62*G: */ - {{{0x172ad712, 0x2c3e5d70, 0x21047290, 0x0e632c37, 0x2349b95a, 0x39e5d851, 0x10b0949d, 0x37fa44cc, 0xa153}}, - {{0x0d48fdd2, 0x2297d94e, 0x2f0b329c, 0x014fca16, 0x31b89abd, 0x0c6357c7, 0x05b2fc48, 0x36104fec, 0xfd94}}}, - /* 15*16^62*G: */ - {{{0x11cf5b3a, 0x0c30dc04, 0x1b5a7810, 0x10cea0ef, 0x2dc824c4, 0x30d34223, 0x14615935, 0x06b1abde, 0x9a54}}, - {{0x36a44ae4, 0x0fd55d7c, 0x21ea52d6, 0x123fb894, 0x0f475f55, 0x386bcda2, 0x06ab7caf, 0x123072c4, 0xb661}}} - }, - { - /* 1*16^63*G: */ - {{{0x1faccae0, 0x2312e844, 0x24bb3374, 0x22cd4316, 0x071fd23c, 0x3653393c, 0x127a8c1d, 0x259984e5, 0x08ea}}, - {{0x0e62b945, 0x16bcd28c, 0x0f0f8e95, 0x2de0efa7, 0x15c5d735, 0x39f033ee, 0x22782e24, 0x3eaef23b, 0x620e}}}, - /* 3*16^63*G: */ - {{{0x26a06f5e, 0x06902d65, 0x2a083702, 0x1064945b, 0x23b716a3, 0x2c350849, 0x0253ac37, 0x093efa85, 0x383b}}, - {{0x13c6e772, 0x227d1e1b, 0x38c2b040, 0x3dab9d2e, 0x2a5a19e8, 0x3d59b553, 0x1ba2044c, 0x1c1ab13b, 0x54cf}}}, - /* 5*16^63*G: */ - {{{0x0638a136, 0x1e5d7075, 0x2838195c, 0x034738cd, 0x0d790c2b, 0x39671ad8, 0x2ed6d789, 0x0cb40f80, 0xe684}}, - {{0x0c6c2584, 0x2bf46042, 0x3357336a, 0x0278faf6, 0x01e6472e, 0x0a9cc0e8, 0x35a6624d, 0x3904e638, 0xca5b}}}, - /* 7*16^63*G: */ - {{{0x16e8c10c, 0x33a1f110, 0x11bd6807, 0x1ca617ce, 0x306e7fb4, 0x3ef7b39c, 0x25c2a0ee, 0x355678bf, 0x395d}}, - {{0x05fe638e, 0x30f5b64c, 0x066922cb, 0x24270137, 0x3a4e274c, 0x04fa1ebf, 0x12ac5d04, 0x37352d16, 0xfd62}}}, - /* 9*16^63*G: */ - {{{0x0d6c14ef, 0x059936c8, 0x2f93c8f5, 0x163f1d41, 0x22648008, 0x3bb56fbb, 0x25dcb9f6, 0x12b70d54, 0x7a51}}, - {{0x0b3fbd13, 0x2b4f861c, 0x2a6e24f7, 0x2fabbdca, 0x0f5c3729, 0x1fc2e532, 0x2e4d8e89, 0x347fb454, 0x56ed}}}, - /* 11*16^63*G: */ - {{{0x0f6d65eb, 0x2a518f41, 0x04021524, 0x26441dd5, 0x108f235a, 0x23bcefd2, 0x1d90d8ea, 0x3f5610c9, 0x1ee1}}, - {{0x1d22941c, 0x380dae49, 0x23582b11, 0x0cbd3a61, 0x02fcfaca, 0x2ae7f13d, 0x2c73c1cf, 0x0a246f75, 0xbb69}}}, - /* 13*16^63*G: */ - {{{0x0e36cb44, 0x3c6543bc, 0x1ca20191, 0x1fa2db23, 0x03357d61, 0x163f4362, 0x3aaa8bc0, 0x158d34e3, 0x1551}}, - {{0x1f495a68, 0x0a6bd194, 0x020c1e53, 0x30dc5d7c, 0x23205da8, 0x038fc2d1, 0x35215e37, 0x3ff1d555, 0xab4f}}}, - /* 15*16^63*G: */ - {{{0x3427bacc, 0x07e51841, 0x12d62e15, 0x1ccc5937, 0x0dc4aa9e, 0x163ac256, 0x35201363, 0x2f1911af, 0x3bc6}}, - {{0x2ad6fda6, 0x130cff57, 0x28beb471, 0x06dd6948, 0x16c02bd7, 0x18bb889b, 0x2c305cdb, 0x17301c5d, 0x8e30}}} - }, -}; + , + /* cp */ { +#include "secp256k1.table" + } #endif +}; diff --git a/secp256k1.h b/secp256k1.h index c381776e8..349ca2435 100644 --- a/secp256k1.h +++ b/secp256k1.h @@ -26,30 +26,8 @@ #include -#include "bignum.h" +#include "ecdsa.h" -// curve point x and y -typedef struct { - bignum256 x, y; -} curve_point; - -// secp256k1 prime -extern const bignum256 prime256k1; - -// secp256k1 initial curve point -extern const curve_point G256k1; - -// secp256k1 order of G -extern const bignum256 order256k1; - -// secp256k1 order of G / 2 -extern const bignum256 order256k1_half; - -// 3/2 in G_p -extern const bignum256 three_over_two256k1; - -#if USE_PRECOMPUTED_CP -extern const curve_point secp256k1_cp[64][8]; -#endif +extern const ecdsa_curve secp256k1; #endif diff --git a/secp256k1.table b/secp256k1.table new file mode 100644 index 000000000..9fd3c728c --- /dev/null +++ b/secp256k1.table @@ -0,0 +1,1664 @@ + { + /* 1*16^0*G: */ + {{{0x16f81798, 0x27ca056c, 0x1ce28d95, 0x26ff36cb, 0x070b0702, 0x018a573a, 0x0bbac55a, 0x199fbe77, 0x79be}}, + {{0x3b10d4b8, 0x311f423f, 0x28554199, 0x05ed1229, 0x1108a8fd, 0x13eff038, 0x3c4655da, 0x369dc9a8, 0x483a}}}, + /* 3*16^0*G: */ + {{{0x3ce036f9, 0x1807c44e, 0x36f99b08, 0x0c721160, 0x1d5229b5, 0x113e17e2, 0x0c310493, 0x22806496, 0xf930}}, + {{0x04b8e672, 0x32e7f5d6, 0x0c2231b6, 0x002a664d, 0x37f35665, 0x0cdf98a8, 0x1e8140fe, 0x1ec3d8cb, 0x388f}}}, + /* 5*16^0*G: */ + {{{0x3240efe4, 0x2ea355a6, 0x0619ab7c, 0x22e12f77, 0x1c5128e8, 0x129c9429, 0x3209355b, 0x37934681, 0x2f8b}}, + {{0x26ac62d6, 0x32a1f4ea, 0x30d6840d, 0x2209c6ea, 0x09c426f7, 0x2ea7769b, 0x1e3d6d4d, 0x08898db9, 0xd8ac}}}, + /* 7*16^0*G: */ + {{{0x0ac4f9bc, 0x24af77b7, 0x330e39ce, 0x1066df80, 0x2a7a0e3d, 0x23cd97cb, 0x1b4eaa39, 0x3c191b97, 0x5cbd}}, + {{0x087264da, 0x142098a0, 0x3fde7b5a, 0x04f42e04, 0x1a54dba8, 0x1e35b618, 0x15960a31, 0x32902e89, 0x6aeb}}}, + /* 9*16^0*G: */ + {{{0x3c27ccbe, 0x0d7c4437, 0x057e714c, 0x25e5a5d3, 0x159abde0, 0x345e2a7d, 0x3f65309a, 0x2138bc31, 0xacd4}}, + {{0x064f9c37, 0x173098ab, 0x35f8e0f0, 0x3622290d, 0x3b61e9ad, 0x2025c5d8, 0x3d9fd643, 0x22486c29, 0xcc33}}}, + /* 11*16^0*G: */ + {{{0x1da008cb, 0x2fb05e25, 0x1c17891b, 0x126602f9, 0x065aac56, 0x1091adc3, 0x1411e5ef, 0x39fe162a, 0x774a}}, + {{0x0953c61b, 0x0075d327, 0x3f9d6a83, 0x0b6c78b7, 0x37b36537, 0x0f755b5e, 0x35e19024, 0x280cbada, 0xd984}}}, + /* 13*16^0*G: */ + {{{0x19405aa8, 0x3bb77e3c, 0x10e58cdd, 0x1d7ef198, 0x348651b0, 0x0748170d, 0x1288bc7d, 0x1cf0b65d, 0xf287}}, + {{0x1b03ed81, 0x26d72d4b, 0x21fa91f2, 0x0681b694, 0x0daf473a, 0x084bad97, 0x00a89758, 0x240ba362, 0x0ab0}}}, + /* 15*16^0*G: */ + {{{0x227e080e, 0x12b6f3e3, 0x085f79e4, 0x39651bcf, 0x1ff41131, 0x196b8c25, 0x3ea965a4, 0x1353df50, 0xd792}}, + {{0x36a26b58, 0x1413727f, 0x096d3a5c, 0x102bcaf6, 0x0c6defea, 0x10bb08a3, 0x072a6838, 0x0a1caa1b, 0x581e}}} + }, + { + /* 1*16^1*G: */ + {{{0x2a6dec0a, 0x113ba278, 0x07a5ae9c, 0x28c4da6e, 0x023e97b2, 0x06aaf087, 0x29ec5301, 0x33a4ed67, 0xe60f}}, + {{0x29616821, 0x07ccb339, 0x0d23f0be, 0x25a24791, 0x39371012, 0x267cd3d5, 0x195929db, 0x141ce679, 0xf7e3}}}, + /* 3*16^1*G: */ + {{{0x1118e5c3, 0x2f61c2a8, 0x12bebc19, 0x15e6c9d1, 0x265b4bfc, 0x0595bbd3, 0x1307db44, 0x0cd76591, 0x6eca}}, + {{0x05a08668, 0x2628bde0, 0x3f8ec344, 0x125a8e8e, 0x3875a03a, 0x3d5e41d2, 0x20710592, 0x08ed5e9e, 0xd501}}}, + /* 5*16^1*G: */ + {{{0x0f87f62e, 0x3b34c785, 0x37161270, 0x39b98e18, 0x0659f010, 0x31d13b4d, 0x390ec0d7, 0x0eefbc6f, 0xe962}}, + {{0x244ee737, 0x0c04fabe, 0x168844e5, 0x1810f277, 0x1aa929fe, 0x3a54ea3b, 0x299e9e0f, 0x1d0ed2f0, 0x38a9}}}, + /* 7*16^1*G: */ + {{{0x2a8d733c, 0x2c2ab7e0, 0x2fca8f9e, 0x309d2fd8, 0x00d682ff, 0x128dbc82, 0x21dba088, 0x375cf945, 0xbc82}}, + {{0x347797f0, 0x39e18413, 0x33897301, 0x24e82eb9, 0x1f02dfae, 0x26d2fdc6, 0x31cac54a, 0x230e8112, 0xe5f2}}}, + /* 9*16^1*G: */ + {{{0x1fbc7671, 0x1fbf88c5, 0x2858e32d, 0x0fc6f214, 0x18f49074, 0x0a47385e, 0x17211d20, 0x049231d9, 0x8e3d}}, + {{0x18717dec, 0x3bc77190, 0x23e144a7, 0x0d4aeaa9, 0x13e90eb9, 0x1203864e, 0x3cb81f64, 0x123843b3, 0x099a}}}, + /* 11*16^1*G: */ + {{{0x3eb31db2, 0x0ca1d0ca, 0x0f506a0f, 0x32ba09e2, 0x08a2b68f, 0x2864fb42, 0x0a498896, 0x246a888d, 0x78a8}}, + {{0x39fa4343, 0x01a7588e, 0x000b82d3, 0x0de6f376, 0x302df654, 0x17c9549c, 0x035cbfcf, 0x28d6fad4, 0x6912}}}, + /* 13*16^1*G: */ + {{{0x0db0e595, 0x14d23dde, 0x3a082bb6, 0x058f2e7e, 0x2076eba7, 0x38dd9605, 0x31b17d7c, 0x1e061576, 0x7d86}}, + {{0x3c733de8, 0x265478ea, 0x225d5329, 0x0de11383, 0x0f883829, 0x18b8afb5, 0x2f8772e5, 0x26b7fb21, 0xe2b9}}}, + /* 15*16^1*G: */ + {{{0x16060dfc, 0x023fbe14, 0x05e6a2a0, 0x1517e108, 0x1ab08676, 0x252e7710, 0x02ac8484, 0x0c43c016, 0xddc5}}, + {{0x27820ca8, 0x2d7e2adb, 0x3d04730f, 0x36ebf1aa, 0x0f0e9041, 0x06adb732, 0x19692019, 0x0bcebc83, 0xba0d}}} + }, + { + /* 1*16^2*G: */ + {{{0x15f51508, 0x191b88ff, 0x1ac1ca10, 0x30e72af5, 0x2de238d8, 0x29b8f85c, 0x209d9ea2, 0x098c84b1, 0x8282}}, + {{0x36e26caf, 0x0c6dbabf, 0x37b17bed, 0x3584eb0b, 0x360ace62, 0x095ba0c2, 0x3dfe45e8, 0x2a026155, 0x11f8}}}, + /* 3*16^2*G: */ + {{{0x257e8dfa, 0x33f032e7, 0x3c7e184f, 0x20246468, 0x298ca009, 0x28c3e2b2, 0x19c4c0d9, 0x33cbfc1e, 0x8262}}, + {{0x3bac376a, 0x173fe363, 0x314c4783, 0x2dbb4cca, 0x334f3457, 0x3b88bb16, 0x09e4e66f, 0x25788244, 0x83fd}}}, + /* 5*16^2*G: */ + {{{0x026bdb6f, 0x014b922c, 0x3734b949, 0x2906f51e, 0x299c877c, 0x0416c933, 0x0ddd5168, 0x1722c768, 0x1982}}, + {{0x049cfc9b, 0x177dc213, 0x0f6d3a6b, 0x3a7bb323, 0x359f6ceb, 0x09873253, 0x0878f320, 0x0c43c353, 0x6294}}}, + /* 7*16^2*G: */ + {{{0x3d82824c, 0x03b42548, 0x21534e65, 0x29638d17, 0x02999edf, 0x17d5bb1b, 0x0191443c, 0x361b0458, 0x6f12}}, + {{0x06eb34d0, 0x15e70d20, 0x054bc5b8, 0x07249042, 0x22376939, 0x2653cff5, 0x3bfa0875, 0x3dfd12ac, 0x5c4f}}}, + /* 9*16^2*G: */ + {{{0x1b453629, 0x1db7700b, 0x359e6030, 0x33f73703, 0x3abef645, 0x189c5a88, 0x2aa5d142, 0x231be682, 0x203a}}, + {{0x3ff89f84, 0x25c71e14, 0x1285ed45, 0x1b7ac971, 0x01061268, 0x31db457d, 0x1d9b936c, 0x02d4f797, 0x3b0f}}}, + /* 11*16^2*G: */ + {{{0x246c7ecb, 0x20c4c377, 0x1bb4ce97, 0x0ebb4ff9, 0x26e1ec9d, 0x3bdccd21, 0x34181c81, 0x32bacf40, 0x6e2a}}, + {{0x2ebc8720, 0x1124807b, 0x367512c8, 0x31c1ae46, 0x3b643afa, 0x03136bc3, 0x3ee149d8, 0x2919e5fb, 0x9e61}}}, + /* 13*16^2*G: */ + {{{0x30a4147e, 0x2dc063cf, 0x375f201e, 0x11f762fd, 0x090a5827, 0x05c5fa29, 0x1156baf6, 0x0124ba7a, 0xd5a7}}, + {{0x33fb65ff, 0x392cf2e0, 0x167f57f8, 0x3136611e, 0x1e0532f4, 0x242641d9, 0x389c6fc4, 0x09bd76ea, 0x9db5}}}, + /* 15*16^2*G: */ + {{{0x18edcec6, 0x3b76d1af, 0x3634f454, 0x018730b4, 0x2cdac6a1, 0x0fbf18c0, 0x18ba8052, 0x0466aaf8, 0x38c5}}, + {{0x1933db08, 0x15b82fec, 0x35530a64, 0x285b208a, 0x1f282f28, 0x32cb689d, 0x1732a668, 0x3748a176, 0xe649}}} + }, + { + /* 1*16^3*G: */ + {{{0x11e5b739, 0x0ff396d5, 0x12222ed7, 0x2e4e0cff, 0x3c846de0, 0x26731b1b, 0x3865a72f, 0x0567dca2, 0x175e}}, + {{0x29fed695, 0x3be9bffb, 0x124345c6, 0x2d6556b7, 0x371f5eac, 0x3e5e947f, 0x079eba4e, 0x1b83678f, 0xd350}}}, + /* 3*16^3*G: */ + {{{0x05041216, 0x16dfe3c7, 0x02b836a6, 0x1ccd7da1, 0x2fed523f, 0x2d67bf70, 0x3acf4128, 0x0c5ec87d, 0xda75}}, + {{0x2e708572, 0x2bb4ca61, 0x37acedad, 0x2ab01eb9, 0x2d7fc6e9, 0x27886cd0, 0x2d5f0df1, 0x2811afdc, 0x73f8}}}, + /* 5*16^3*G: */ + {{{0x2465a930, 0x0050f9c7, 0x31352fdb, 0x21fc705a, 0x02eb1e25, 0x0f16312a, 0x349d7057, 0x316d23a5, 0x1c71}}, + {{0x034638b5, 0x361cfdb3, 0x3174d471, 0x0d178fed, 0x0bb68c79, 0x0fc7ca09, 0x1fa0c271, 0x30cd3a3d, 0x4a91}}}, + /* 7*16^3*G: */ + {{{0x3adb6ee7, 0x0c636b96, 0x344a077e, 0x143750c9, 0x1b4c9c78, 0x3a0dea42, 0x1a566936, 0x12bf07cc, 0xd84e}}, + {{0x142ebed2, 0x0b555b9b, 0x2a3e6498, 0x362b25d2, 0x25de4dfd, 0x0e3563d5, 0x379ce12a, 0x20269f1e, 0xe525}}}, + /* 9*16^3*G: */ + {{{0x249e6d10, 0x253a7b3e, 0x2ac99d23, 0x02b7fceb, 0x3f6ed3f6, 0x08ae4a17, 0x2814d41b, 0x1112f799, 0xf3d4}}, + {{0x1347da3f, 0x280e3301, 0x29d6c630, 0x06b69433, 0x0a4b5bfc, 0x2e56b066, 0x0163d4ba, 0x0937e9bc, 0x0a43}}}, + /* 11*16^3*G: */ + {{{0x29d33a07, 0x232cd01b, 0x239bcab4, 0x1cbb822a, 0x3df4044e, 0x21548336, 0x01d89f90, 0x194b2767, 0xae30}}, + {{0x20a0b2a6, 0x121c303d, 0x3d7e95c7, 0x270dfd77, 0x38d5cf1c, 0x339f4cf6, 0x3fe57efc, 0x3670e358, 0x6cb9}}}, + /* 13*16^3*G: */ + {{{0x0c28caca, 0x165952e4, 0x08281da7, 0x1a71eef3, 0x388c9a18, 0x05f9d60c, 0x1e1c815e, 0x06ca96f5, 0xd8dc}}, + {{0x23b3ec7a, 0x36d9dba8, 0x08128f6c, 0x0c574b3b, 0x247d947d, 0x36369080, 0x2c7d58c6, 0x02b649f3, 0x8cec}}}, + /* 15*16^3*G: */ + {{{0x3bc4416f, 0x2487ed98, 0x30b04028, 0x2bbf48fc, 0x32f31da7, 0x1096a340, 0x04eccd59, 0x38a4b17e, 0x2749}}, + {{0x3c6bbd8e, 0x3a62f78b, 0x2e961057, 0x27a7ed97, 0x0adb3ef5, 0x3652643f, 0x32bc4403, 0x0b538dd9, 0x50cc}}} + }, + { + /* 1*16^4*G: */ + {{{0x03ff4640, 0x09aeb63e, 0x1552ffe5, 0x11071f95, 0x262ee053, 0x3ab016d8, 0x00c9c99c, 0x243511ec, 0x363d}}, + {{0x3bee9de9, 0x0800f1fc, 0x0199ecb6, 0x2e6a2402, 0x33363145, 0x2d114e5f, 0x32221953, 0x1ceb7f1c, 0x04e2}}}, + /* 3*16^4*G: */ + {{{0x36e55dc8, 0x2e24485b, 0x2ca04394, 0x3e56adba, 0x1094426f, 0x12910301, 0x1ffb2ba8, 0x1011e431, 0x4431}}, + {{0x1be323b3, 0x076512bb, 0x2aa2e503, 0x1a8a6de7, 0x02fed7a6, 0x260dfd59, 0x366f8fe9, 0x3050b994, 0x96b0}}}, + /* 5*16^4*G: */ + {{{0x301b23a8, 0x3fa52175, 0x287ee0ad, 0x1edf51c2, 0x21089dab, 0x090f56e4, 0x0a87c126, 0x3fa3619b, 0x9e22}}, + {{0x0884edae, 0x1e904f14, 0x3511cecf, 0x3df2527e, 0x1c1533c0, 0x3cfc0826, 0x22d10177, 0x3c3a7284, 0xfd2f}}}, + /* 7*16^4*G: */ + {{{0x071a70e4, 0x35d022fc, 0x35cf475d, 0x17b947d7, 0x05306dcd, 0x35a7991c, 0x22a8d2ed, 0x3db540f3, 0x508d}}, + {{0x29950984, 0x3cb96fdc, 0x28aadfed, 0x300c8a3b, 0x3e49c54e, 0x0c12a9cc, 0x3c42d777, 0x10e6e4ce, 0x154c}}}, + /* 9*16^4*G: */ + {{{0x0e1abe11, 0x3abf69db, 0x1cb220f6, 0x2e487096, 0x0125b2da, 0x37d6064c, 0x09763338, 0x3fe11544, 0xe3db}}, + {{0x1fa8de63, 0x2d26b552, 0x06b5c414, 0x325f640f, 0x0a8ef3d3, 0x23e9d76e, 0x01421643, 0x3e42668d, 0x06f2}}}, + /* 11*16^4*G: */ + {{{0x03593449, 0x33c6c8d8, 0x02a46ffd, 0x06df04b9, 0x3d014af6, 0x36704e81, 0x2940d878, 0x381931f7, 0x19ac}}, + {{0x2df83631, 0x29052e4e, 0x084068a3, 0x1c42e7d0, 0x002c46ac, 0x2f5ce765, 0x0a333bfe, 0x2480d49a, 0xe379}}}, + /* 13*16^4*G: */ + {{{0x0cba6b63, 0x38fa624b, 0x10b3bb5e, 0x03f99d3f, 0x288e310a, 0x30cc8a3a, 0x07daa108, 0x033b083e, 0xd874}}, + {{0x2934c5f3, 0x3ba8db01, 0x381694ab, 0x0413d730, 0x3ac37d40, 0x29bba640, 0x132bf378, 0x304cf1ae, 0x6472}}}, + /* 15*16^4*G: */ + {{{0x1b3ec038, 0x0653fcb0, 0x20c6b276, 0x3f545ab9, 0x290a50d9, 0x20f9d8bc, 0x06083648, 0x0cce46d4, 0x58ac}}, + {{0x10246279, 0x1baa8fc4, 0x34fbbca1, 0x06410f02, 0x11fe9702, 0x1e4927a6, 0x092d9787, 0x35c1b557, 0x9163}}} + }, + { + /* 1*16^5*G: */ + {{{0x1ffdf80c, 0x27de6957, 0x15bcd1b6, 0x3929e068, 0x05638843, 0x0912d6dd, 0x3c2be8c6, 0x17c5977c, 0x8b4b}}, + {{0x1fd4fd36, 0x0fbfc319, 0x162ee56b, 0x38cd9518, 0x30da04f9, 0x2f5e04ea, 0x308b4b3f, 0x029bda34, 0x4aad}}}, + /* 3*16^5*G: */ + {{{0x355812dd, 0x028a960b, 0x12d30e2a, 0x1119c8d5, 0x18f78e3d, 0x2afb5b01, 0x3352f0b6, 0x2f5ea4bf, 0x7029}}, + {{0x1a2d2927, 0x087319ac, 0x3b2c73c7, 0x36ba1090, 0x0683ac47, 0x19512b8c, 0x0b3d27dd, 0x3eb6bf7a, 0xb0ee}}}, + /* 5*16^5*G: */ + {{{0x3d486ed1, 0x27395a0e, 0x1565b6a4, 0x116fae92, 0x0f756057, 0x35042763, 0x25c99009, 0x3b72bab9, 0x9ccf}}, + {{0x35e95d8d, 0x3db567b5, 0x1592aa24, 0x0859d65a, 0x0b341124, 0x08920480, 0x232cfb61, 0x135c4f5a, 0x7c2f}}}, + /* 7*16^5*G: */ + {{{0x1bd0eaca, 0x081ac69d, 0x22d4ab7a, 0x31d15dae, 0x24df19d0, 0x23f78cf2, 0x1414335a, 0x12e1d8d0, 0xcd9a}}, + {{0x2bff4acc, 0x39bebed6, 0x16f634f6, 0x09ece3bb, 0x3ea08b01, 0x1222ba4c, 0x0f23e815, 0x161e687a, 0xf045}}}, + /* 9*16^5*G: */ + {{{0x07bc57c6, 0x08254e8f, 0x2b276cbf, 0x00f5e88f, 0x16309449, 0x3cb4ba4f, 0x19bea884, 0x220be23b, 0xad09}}, + {{0x2e4a0ab8, 0x28cb03b6, 0x190e2d3c, 0x0c474dcd, 0x1abe5f7b, 0x061b1ca7, 0x3a52ba28, 0x302310be, 0x7243}}}, + /* 11*16^5*G: */ + {{{0x2ba56302, 0x2a0c31ca, 0x30f1862e, 0x01aa4deb, 0x3ad2e0f5, 0x368b4aa7, 0x0a41f1ea, 0x0a42bacf, 0xd9d1}}, + {{0x08291c29, 0x2ab76bea, 0x3a74f2ae, 0x0e6bb367, 0x2386e417, 0x1c5719c9, 0x13eed029, 0x0c44fb0b, 0x7eb5}}}, + /* 13*16^5*G: */ + {{{0x34d1243a, 0x2b34dc13, 0x354a5fdb, 0x2c49808f, 0x3f558402, 0x3486b018, 0x16cef91c, 0x1e7794e7, 0xbc50}}, + {{0x055db68a, 0x172545a2, 0x1f47169f, 0x1fb93d6c, 0x3fc8d75f, 0x31cae537, 0x05cbb8ee, 0x0a8ece9c, 0x6506}}}, + /* 15*16^5*G: */ + {{{0x374a3f9f, 0x2349139a, 0x00981690, 0x21e99977, 0x32625ac2, 0x37aab9f6, 0x3c7e8913, 0x29df9417, 0x4d31}}, + {{0x301e0ba7, 0x3f2c0904, 0x2e00a754, 0x3dbed46d, 0x002753cb, 0x063ce31e, 0x0575b06b, 0x07b25826, 0x2224}}} + }, + { + /* 1*16^6*G: */ + {{{0x1232fcda, 0x2d845649, 0x2c0e77bc, 0x0036ffe9, 0x1548c7b7, 0x1dc7002f, 0x3996d6bf, 0x2ea9b976, 0x723c}}, + {{0x1eb39f5f, 0x07701a76, 0x37949480, 0x1828194d, 0x024d6e26, 0x044dd222, 0x0c498a92, 0x19ed5657, 0x96e8}}}, + /* 3*16^6*G: */ + {{{0x00633cb1, 0x159f827a, 0x1d021132, 0x168892da, 0x181fcb57, 0x189cc848, 0x2cad400c, 0x273cc5ea, 0x6dde}}, + {{0x27ce6b34, 0x1f7526a9, 0x3859ef35, 0x2c9ff6b3, 0x3a66a880, 0x27be1a86, 0x3e41d5c9, 0x3ef9e9c1, 0x9188}}}, + /* 5*16^6*G: */ + {{{0x2933f3c5, 0x06694634, 0x1f125224, 0x1683dc45, 0x07b85008, 0x12edfe39, 0x1cde813c, 0x29cb356d, 0x486f}}, + {{0x0afb0f53, 0x2b529c6b, 0x30f23b79, 0x366de0f3, 0x08f19f62, 0x3122ebb3, 0x3dd43e48, 0x08c67d5a, 0x62e1}}}, + /* 7*16^6*G: */ + {{{0x1e99f728, 0x2f565089, 0x2f12204e, 0x1cdd7ef9, 0x2a530367, 0x13fc9edd, 0x0af4fb66, 0x1a5d2a25, 0x2479}}, + {{0x2baaebff, 0x1e80145b, 0x175a2d83, 0x36fcf025, 0x0d664a5a, 0x0ba1f9f6, 0x33001ec5, 0x23511a23, 0xe3d7}}}, + /* 9*16^6*G: */ + {{{0x2fb0079a, 0x27831b50, 0x3926049c, 0x1be7bdc8, 0x33832491, 0x2967b9da, 0x15ff0631, 0x32f6a8f5, 0x2f39}}, + {{0x2c5690ba, 0x388a5cc0, 0x02a0230f, 0x3ecfef22, 0x0da58b9b, 0x24db409e, 0x239834da, 0x36f784e1, 0xabea}}}, + /* 11*16^6*G: */ + {{{0x24f7ab73, 0x24cc02cb, 0x14443a77, 0x38f53aa7, 0x34aed262, 0x0e7a1b14, 0x161ba56a, 0x075b0c9f, 0xe5a3}}, + {{0x30561f42, 0x244e8ff1, 0x00cba213, 0x2311126a, 0x0ece5dbf, 0x062a5de9, 0x29d7a0c1, 0x230f6347, 0x3778}}}, + /* 13*16^6*G: */ + {{{0x014dcd86, 0x23e4a68f, 0x2bf71b58, 0x31750825, 0x11dcf11f, 0x03766081, 0x13447df5, 0x27528345, 0xcc38}}, + {{0x08f0a873, 0x23adb767, 0x27e78746, 0x315f863f, 0x2910ca05, 0x1a2f6efa, 0x2bbed9b5, 0x13f5983d, 0x93ae}}}, + /* 15*16^6*G: */ + {{{0x38819311, 0x13e71bad, 0x08771472, 0x0f87b884, 0x35ed1f0b, 0x0285f833, 0x1e902375, 0x2472275c, 0x7f92}}, + {{0x2c2eb125, 0x2a7e6d5e, 0x086a174a, 0x02aa9027, 0x2415b612, 0x037a3114, 0x03ef0f5d, 0x034418fb, 0x9da0}}} + }, + { + /* 1*16^7*G: */ + {{{0x0e7dd7fa, 0x294cfb28, 0x3a919839, 0x11e5848d, 0x02d3b509, 0x3fbb204b, 0x2bf98ba5, 0x293524ef, 0xeebf}}, + {{0x21de8999, 0x37f53f6b, 0x311f712d, 0x393370e9, 0x38089d9a, 0x39fb6bc5, 0x2f0f269e, 0x2328e5c3, 0x5d9a}}}, + /* 3*16^7*G: */ + {{{0x3b7ceceb, 0x0fd9e3fe, 0x097faf0f, 0x2967e4e2, 0x2e681473, 0x3ee049bd, 0x2d45036f, 0x2188109d, 0x437a}}, + {{0x16c181e1, 0x0d8ef30d, 0x08f97827, 0x0883f3f7, 0x1297ff87, 0x23fada67, 0x2c32f69b, 0x1ae84fba, 0x0b91}}}, + /* 5*16^7*G: */ + {{{0x097f96f2, 0x1635ca78, 0x2c8735cd, 0x208d4a74, 0x3cc27335, 0x2df8ee68, 0x089bc83c, 0x27c4f8a9, 0xa9ef}}, + {{0x16c04be4, 0x00f556c1, 0x29b4702c, 0x13e26bd6, 0x3b613db7, 0x1bb8583a, 0x19d7cd95, 0x33396515, 0xe814}}}, + /* 7*16^7*G: */ + {{{0x350cf77e, 0x302ad684, 0x0a8ab0db, 0x36fd5d15, 0x2a064207, 0x209f5a7e, 0x135be553, 0x01507b87, 0x66d8}}, + {{0x20eaa3a6, 0x297e5ebe, 0x3b1b76d2, 0x112d0ead, 0x1613f694, 0x0750814d, 0x3fb42c3f, 0x37f9ccbf, 0x51cf}}}, + /* 9*16^7*G: */ + {{{0x07213a5a, 0x0d5218a2, 0x05fa62b9, 0x1cc8129e, 0x0cc3c80b, 0x14228719, 0x03fa2bf3, 0x01784d94, 0x62ac}}, + {{0x346a9e45, 0x04348703, 0x17994efc, 0x16424060, 0x292579e5, 0x179e781e, 0x1a6e4d39, 0x2f7ce834, 0x236f}}}, + /* 11*16^7*G: */ + {{{0x27bad12b, 0x0c3f5261, 0x2f66e1ec, 0x357a803a, 0x2f2db385, 0x184ebd71, 0x08f5b5bf, 0x31125c91, 0xca13}}, + {{0x1723b0f2, 0x25a67d1a, 0x1a575668, 0x1c2adc44, 0x2da3d663, 0x17e993aa, 0x287c8ac1, 0x0260d870, 0x83aa}}}, + /* 13*16^7*G: */ + {{{0x1c80414e, 0x36bb97e5, 0x166cf7fd, 0x3be2a18b, 0x209e4914, 0x04713d11, 0x12ae85ac, 0x2c4069c1, 0x1cec}}, + {{0x12169a3b, 0x32ba524b, 0x07231d0d, 0x1d55f951, 0x2dad1690, 0x2a8ca0d7, 0x17cfb4e5, 0x1819a582, 0xf343}}}, + /* 15*16^7*G: */ + {{{0x0ed810a9, 0x13d6f231, 0x0700155c, 0x22274fcf, 0x1f23924f, 0x036bd7c7, 0x38f9cc95, 0x241d4135, 0x2a69}}, + {{0x3a9b4728, 0x3e1ace23, 0x2c145c7c, 0x1f51fa5f, 0x3b04fc66, 0x3161a553, 0x1ffdac3e, 0x00e6db0f, 0x54f9}}} + }, + { + /* 1*16^8*G: */ + {{{0x39a48db0, 0x3f5e0d6c, 0x33c03bfe, 0x048568a6, 0x3bde459f, 0x0742826d, 0x27167279, 0x11369a5b, 0x100f}}, + {{0x2bc65a09, 0x3ef57358, 0x35195ac0, 0x3fd2863f, 0x090666b7, 0x23ccc030, 0x00b772ec, 0x384c64a8, 0xcdd9}}}, + /* 3*16^8*G: */ + {{{0x15bc15b4, 0x32e684d2, 0x25a2ee69, 0x1d40a391, 0x17ca8d92, 0x163ba73b, 0x2adc9ed8, 0x038b947b, 0x10e9}}, + {{0x18aa258d, 0x13af9825, 0x2bb6a883, 0x296258c0, 0x2d1f754c, 0x1ea3185a, 0x1e0424d5, 0x0dc0e035, 0xc68a}}}, + /* 5*16^8*G: */ + {{{0x3fe75269, 0x374ff0c0, 0x13d33182, 0x1de8f301, 0x0b7dcda3, 0x16e42dc5, 0x01638457, 0x0bd0b695, 0xf742}}, + {{0x17e49bd5, 0x22603a1c, 0x0a398e01, 0x2ce88dfd, 0x3635977f, 0x339f72e7, 0x3093fd18, 0x0bc68cc4, 0x406c}}}, + /* 7*16^8*G: */ + {{{0x35a7175f, 0x14ed9a5b, 0x31cf42a6, 0x2e39dc74, 0x15debbed, 0x1e69560b, 0x03cff728, 0x2b4105f5, 0x2d8c}}, + {{0x3b9d592a, 0x3cdeee46, 0x0b5e5e0c, 0x211aff67, 0x2c9d377a, 0x08cbe984, 0x0a94a7bb, 0x0ee0cc63, 0xc73f}}}, + /* 9*16^8*G: */ + {{{0x14b51045, 0x0d326f0e, 0x31c25b3e, 0x31b225bc, 0x28cf73bb, 0x1cf53ac7, 0x26ea58ae, 0x3f476e62, 0x1ecb}}, + {{0x02c70026, 0x0e99c404, 0x036422d5, 0x240191ad, 0x1a9b38b1, 0x342ec612, 0x1c3a6447, 0x388c22e6, 0x1cf6}}}, + /* 11*16^8*G: */ + {{{0x29358533, 0x1eb35d9b, 0x0fb4b9df, 0x2a4cfe75, 0x132a8c10, 0x25568a47, 0x3752883e, 0x25317f95, 0x9a08}}, + {{0x0360ba08, 0x2cf87177, 0x380ddadf, 0x29b96f6e, 0x0fc32165, 0x05f57e55, 0x38fc31f9, 0x20f10806, 0xa798}}}, + /* 13*16^8*G: */ + {{{0x198ef7f6, 0x25101758, 0x2078f9f6, 0x08fcfdde, 0x38aea659, 0x272149ce, 0x3d2e35bd, 0x361276d3, 0x664d}}, + {{0x1d1eac94, 0x1d25bfcd, 0x38e6ecee, 0x0f4eacc6, 0x0458cffc, 0x12339774, 0x27932a14, 0x0805c5fc, 0xad51}}}, + /* 15*16^8*G: */ + {{{0x03c934b3, 0x03029adf, 0x30ae2c4e, 0x0c7d6016, 0x11a7022b, 0x07659a60, 0x0b863823, 0x0ea4ddf4, 0x8211}}, + {{0x042c6a0f, 0x1f9798ab, 0x24468037, 0x07df09a6, 0x20c628aa, 0x19b3cad6, 0x23666084, 0x2e36b26b, 0x8da1}}} + }, + { + /* 1*16^9*G: */ + {{{0x2534fd2d, 0x322b379b, 0x0f3b3852, 0x1fe35119, 0x04c017a7, 0x2489e928, 0x3ed1b1dc, 0x06f898b1, 0xe103}}, + {{0x1456a00d, 0x113c63ca, 0x21ced79a, 0x24b75067, 0x17535af2, 0x1a905d96, 0x0405e6bb, 0x1864a250, 0x9d70}}}, + /* 3*16^9*G: */ + {{{0x2f028d83, 0x1e588ebb, 0x27439615, 0x25649b6e, 0x1e69db61, 0x2af96857, 0x385ec6a5, 0x3df138f1, 0xa7eb}}, + {{0x19d0bed1, 0x1900e4ae, 0x30539199, 0x28e249d2, 0x04804b47, 0x271cddc1, 0x362d5cfd, 0x054beff8, 0x6205}}}, + /* 5*16^9*G: */ + {{{0x27dd5cfa, 0x2b839008, 0x309d4b5b, 0x227144df, 0x2346336a, 0x31a94d09, 0x24f4c1cd, 0x282372c0, 0x5b5c}}, + {{0x1e48e98c, 0x19929be6, 0x33269d3e, 0x3419f32b, 0x069094bf, 0x07c33aa2, 0x15825e99, 0x2dbdc2a8, 0x3ecc}}}, + /* 7*16^9*G: */ + {{{0x23531f82, 0x2e54a38c, 0x10c2c9f2, 0x144c9aec, 0x022c29ff, 0x3cf9d227, 0x14bb5cce, 0x09ab3044, 0x046f}}, + {{0x0bceda07, 0x1417f22c, 0x2b55c7fa, 0x09651736, 0x032579d0, 0x0dc2b0bf, 0x382eace2, 0x12cc58d6, 0x6b80}}}, + /* 9*16^9*G: */ + {{{0x10432711, 0x02c550dc, 0x1916b906, 0x0502cbf7, 0x19645acf, 0x25bc3c22, 0x0efb535f, 0x09b64c78, 0xc119}}, + {{0x2fe2610c, 0x1249878b, 0x0f34055e, 0x2ae48b28, 0x0cc6cf83, 0x252fc61b, 0x1b689184, 0x3e331f49, 0x8be1}}}, + /* 11*16^9*G: */ + {{{0x21257963, 0x05e61d3e, 0x34aa861c, 0x006354b0, 0x0979c45b, 0x2ed52d4e, 0x08f2e6cd, 0x11ba7ada, 0x6908}}, + {{0x066f9835, 0x295d9665, 0x1c92b253, 0x2f0f2a08, 0x2fbb7f6c, 0x05c093e4, 0x3ebc5b40, 0x17f2dfcf, 0xe248}}}, + /* 13*16^9*G: */ + {{{0x1ee23ace, 0x3444e52f, 0x14dd2fd2, 0x321f196d, 0x232915de, 0x1d54b7d2, 0x220babba, 0x3dfee324, 0xfb3d}}, + {{0x1722e8de, 0x0277bd32, 0x2d27f5ee, 0x1c9c50bf, 0x3ab58a9e, 0x09455036, 0x33c5652a, 0x0a6f0471, 0x510e}}}, + /* 15*16^9*G: */ + {{{0x10272351, 0x181f3fbd, 0x19ff1098, 0x1cd2cf7e, 0x31cd4170, 0x228facea, 0x0518b3eb, 0x17b093d7, 0x6dd8}}, + {{0x3fc7664b, 0x2c1fe8ad, 0x3e0817c9, 0x1f1bfdf0, 0x1c41b787, 0x101fe6bd, 0x3427e09d, 0x19fd0487, 0x16ea}}} + }, + { + /* 1*16^10*G: */ + {{{0x1094696d, 0x3579a236, 0x01d6af52, 0x3e2c99a9, 0x3bd7ec5c, 0x0a0e7c50, 0x15b530ac, 0x1b2b91b5, 0xfeea}}, + {{0x18090088, 0x05577afc, 0x041442d3, 0x072255f3, 0x3ecd5c98, 0x39384afc, 0x0e1bab06, 0x1adb25f7, 0xe57c}}}, + /* 3*16^10*G: */ + {{{0x08dfd587, 0x1e4d86ed, 0x1b026560, 0x312e8e32, 0x35a12d5e, 0x19eaa8b3, 0x0508b348, 0x2d06eb3d, 0x5084}}, + {{0x11470e89, 0x39e7a5fe, 0x091f5606, 0x2dbd581a, 0x2927475d, 0x2a9b2154, 0x00d31619, 0x18c68766, 0x34a9}}}, + /* 5*16^10*G: */ + {{{0x3ab34cc6, 0x0208c985, 0x0f30a12d, 0x030a5d9f, 0x0d7128c8, 0x2cfc7f46, 0x2d5ea53f, 0x300f8190, 0x4f14}}, + {{0x187e681f, 0x17b094be, 0x281dd022, 0x378f33a3, 0x262540b9, 0x0e9c3d0e, 0x0e894c65, 0x342a32a9, 0x7b53}}}, + /* 7*16^10*G: */ + {{{0x1241d90d, 0x109dc404, 0x32444f83, 0x073c5076, 0x1dd363e8, 0x10d8257b, 0x39ed1d41, 0x2e1f9271, 0xa74d}}, + {{0x3f7adad4, 0x0c9462e0, 0x0a0a313f, 0x3b9424d1, 0x0171c8a9, 0x37422962, 0x3eef327f, 0x24736bc8, 0xf786}}}, + /* 9*16^10*G: */ + {{{0x31c1ae1f, 0x17b32888, 0x2cd40b2a, 0x1b9631a2, 0x23565845, 0x373513ae, 0x2a2cf9ac, 0x3e95d12e, 0x6901}}, + {{0x122838b0, 0x3e0cc197, 0x1c77a930, 0x27cee979, 0x1c900dd7, 0x2d4e030a, 0x3c212461, 0x1722089c, 0x35de}}}, + /* 11*16^10*G: */ + {{{0x327a4bdb, 0x2c0c4206, 0x1494cac4, 0x1a9b410d, 0x3ba35d04, 0x12d90fc6, 0x38127a24, 0x360b4750, 0x8d3c}}, + {{0x269a8a2c, 0x0f4d31f3, 0x30ad296c, 0x38e01f4d, 0x36236ed4, 0x3efe7401, 0x241f470c, 0x0958603b, 0x9bd4}}}, + /* 13*16^10*G: */ + {{{0x34ec1d2d, 0x10334f1a, 0x27d8f454, 0x0267d71b, 0x3b691fd9, 0x2759ca59, 0x24739afe, 0x20d8f581, 0xeaf9}}, + {{0x0c838452, 0x33f9d581, 0x3e84b53f, 0x3d4b5515, 0x3199aaa9, 0x08a2839a, 0x38d22775, 0x060e9ff9, 0xe518}}}, + /* 15*16^10*G: */ + {{{0x045ae767, 0x32cd6fdc, 0x289771cb, 0x1cea72e7, 0x06e5d8c2, 0x103814b0, 0x1b63466f, 0x2f458ebb, 0xfb95}}, + {{0x3bbf0e11, 0x214fa82b, 0x259f1341, 0x05bd1c62, 0x02275bb8, 0x013674da, 0x0ddbc520, 0x0536046a, 0x664c}}} + }, + { + /* 1*16^11*G: */ + {{{0x01ec6cb1, 0x0fea5e2f, 0x08583de3, 0x3b595f60, 0x3fca3cfe, 0x1ef92f9b, 0x09cdcb36, 0x2a476441, 0xda67}}, + {{0x3a68be1d, 0x3a7aa389, 0x0f740a17, 0x31eb7142, 0x1780e5de, 0x118fdfb2, 0x242bc41f, 0x2a8d5205, 0x9bac}}}, + /* 3*16^11*G: */ + {{{0x15bc8a44, 0x3bf74194, 0x3e151a19, 0x10405df2, 0x1a5fc768, 0x159692e9, 0x0eda3d38, 0x20160f3f, 0x4d01}}, + {{0x1adbc09e, 0x3c7e5324, 0x182da362, 0x250811a1, 0x16381396, 0x26ea001f, 0x0f5d367e, 0x31b0632d, 0x3a33}}}, + /* 5*16^11*G: */ + {{{0x25daeb00, 0x306ad4a1, 0x2645f76b, 0x08fac933, 0x36e9d159, 0x32da89ce, 0x0f957082, 0x0541f7d7, 0x2f66}}, + {{0x033992c0, 0x089d9e26, 0x15d308c1, 0x337b89c6, 0x00add06e, 0x254dea08, 0x2b33f6ef, 0x0484dbd4, 0xfd5c}}}, + /* 7*16^11*G: */ + {{{0x116aa6d9, 0x20aa4282, 0x3702dcf1, 0x18b22d91, 0x035a3836, 0x3c5d3686, 0x247d2254, 0x045f417f, 0xf594}}, + {{0x3f2e50cf, 0x1f41a5ba, 0x26b5b86c, 0x249de20f, 0x14bceb7a, 0x176f6ac2, 0x31b12cf6, 0x18695ba5, 0xcaa7}}}, + /* 9*16^11*G: */ + {{{0x3ac6f4c0, 0x2ab80e55, 0x04bdc4cc, 0x13a37a33, 0x16711dda, 0x070e2f9a, 0x19cdec4e, 0x135fc7d3, 0x0f2d}}, + {{0x32339b58, 0x1f9eeeb5, 0x0242656e, 0x1a8429e4, 0x01e71e8f, 0x2c9ff7ce, 0x3de4d17f, 0x27e15fa4, 0x3ec8}}}, + /* 11*16^11*G: */ + {{{0x1f428cb2, 0x215414ff, 0x2a22b55d, 0x0e08bf59, 0x18d0f123, 0x1e860565, 0x14bbd1eb, 0x33b0b8a8, 0x1d5d}}, + {{0x095b189b, 0x397b4402, 0x36044a51, 0x0fa44be1, 0x2f0b88bd, 0x1e1e0921, 0x2c8c50d0, 0x1020ec50, 0x6e5c}}}, + /* 13*16^11*G: */ + {{{0x28381273, 0x2c3aa23e, 0x293dae5f, 0x10dda581, 0x0126ced8, 0x3aa6cb31, 0x167439fd, 0x28bf4c02, 0x89d9}}, + {{0x1309773d, 0x00facfbb, 0x1127324a, 0x1875a02b, 0x0f62f58f, 0x2abc81db, 0x26f50377, 0x096d1475, 0xdfca}}}, + /* 15*16^11*G: */ + {{{0x35c71d91, 0x330cacb2, 0x2894fd21, 0x25178b8a, 0x1afece23, 0x28704c45, 0x10ae1c52, 0x06e1e0e9, 0x8319}}, + {{0x22148a61, 0x02e7b023, 0x10445ee7, 0x2847d45d, 0x3cae8a17, 0x1b784f45, 0x01b709e0, 0x1fc55ce0, 0xe0ac}}} + }, + { + /* 1*16^12*G: */ + {{{0x1a37b7c0, 0x1d517330, 0x311069f5, 0x02343dee, 0x322151ec, 0x00024d7b, 0x34cdda6e, 0x13ea82cc, 0x5390}}, + {{0x022771c8, 0x372c25ac, 0x14434699, 0x26666078, 0x0d3c1c13, 0x27b32b08, 0x0106d88c, 0x21f42f20, 0x5bc0}}}, + /* 3*16^12*G: */ + {{{0x08a2050e, 0x06b10bf9, 0x15f8a677, 0x0bbd55d8, 0x079b8974, 0x1da731b9, 0x0731896b, 0x093f492f, 0x6737}}, + {{0x061d3d70, 0x24326924, 0x3349cc2b, 0x1aeb3f50, 0x086b6dbe, 0x120b026a, 0x24a20203, 0x2095e25a, 0xe4cf}}}, + /* 5*16^12*G: */ + {{{0x02de63bf, 0x2fdb920e, 0x3261c66c, 0x0ebd4ca1, 0x2166a8e0, 0x26298c7d, 0x34c309e5, 0x3be91cb7, 0x4366}}, + {{0x217924cd, 0x0b1a9023, 0x2aa6d6b0, 0x0ec31496, 0x0268eaf3, 0x094df84c, 0x2d7ce2ee, 0x36426fb8, 0x2e7d}}}, + /* 7*16^12*G: */ + {{{0x06f96190, 0x04149ffc, 0x3c9525ef, 0x3c0b7a41, 0x3aa75fd1, 0x3955a599, 0x1ab1f97b, 0x14d89e64, 0x7bd7}}, + {{0x2bda00f6, 0x0f45c812, 0x20ea695a, 0x03f31707, 0x3827d6ce, 0x3591d250, 0x26309d5e, 0x3cacf6ee, 0x8336}}}, + /* 9*16^12*G: */ + {{{0x16ad41ed, 0x0ec54c55, 0x0f035243, 0x022b0d7d, 0x18dc9203, 0x0d067a24, 0x2d5c1afa, 0x249ef76a, 0x4f7e}}, + {{0x3e642d57, 0x3d0d5e19, 0x2af775bd, 0x1cc51c53, 0x28f6a62e, 0x26037d4e, 0x08b10552, 0x1d1455aa, 0xdfe7}}}, + /* 11*16^12*G: */ + {{{0x27748690, 0x3e981449, 0x0630b01c, 0x15e41376, 0x133d007d, 0x114ac7b7, 0x11ccc94b, 0x32e19f4a, 0x2355}}, + {{0x0c89582b, 0x1f11d4c5, 0x11c93914, 0x0a1a1633, 0x2a7c5858, 0x2e17b056, 0x1e1f8f55, 0x3c62969c, 0x21c2}}}, + /* 13*16^12*G: */ + {{{0x0ade7f16, 0x36ba8858, 0x0be028c6, 0x272eba4f, 0x275d24ae, 0x164aadb0, 0x1a56c013, 0x2096e6cf, 0x0b66}}, + {{0x08c56217, 0x251109a1, 0x3e7cd2bd, 0x090f037c, 0x17a97fb7, 0x29daea2d, 0x09b3fef3, 0x282e0638, 0xa1fb}}}, + /* 15*16^12*G: */ + {{{0x19060d5b, 0x241ac08a, 0x03a3a7c2, 0x1184ec47, 0x3951cb90, 0x026cbf67, 0x1022cb61, 0x010f3c2f, 0xf602}}, + {{0x1af88f13, 0x1bdbd42c, 0x3dd1a3f7, 0x2a95b4ad, 0x0f7bea37, 0x2a3d92b1, 0x0cf19881, 0x2dc1b07c, 0xf036}}} + }, + { + /* 1*16^13*G: */ + {{{0x3ad86047, 0x3fe567d0, 0x29b8bcae, 0x2d4e810e, 0x0a906779, 0x3329dd93, 0x183a7719, 0x3342f4d6, 0x8e7b}}, + {{0x0460372a, 0x284011fa, 0x3fd68b3e, 0x3a238b91, 0x29514579, 0x0c410832, 0x1a4b3940, 0x1dc2ca8f, 0x10b7}}}, + /* 3*16^13*G: */ + {{{0x041ead4b, 0x3fa21e68, 0x11b03c1f, 0x1d7b7eda, 0x3e76be3a, 0x11cd3beb, 0x3337ec71, 0x03032323, 0xbfc9}}, + {{0x06fedaed, 0x114b1bc2, 0x2e0ae3e7, 0x11a3bfcc, 0x042d36fb, 0x29c63754, 0x0ded24db, 0x206c7827, 0x7a94}}}, + /* 5*16^13*G: */ + {{{0x35bb3b3e, 0x1b9ef41d, 0x39f73cb2, 0x1d4d85fb, 0x2d3f5b50, 0x1664fa30, 0x3aaa4dca, 0x3c472f8f, 0x732d}}, + {{0x17366693, 0x315df87b, 0x0c58436c, 0x276b5b59, 0x253916e6, 0x38956100, 0x39977cb7, 0x240fb7a3, 0x7f41}}}, + /* 7*16^13*G: */ + {{{0x088dc3b9, 0x17d6cf06, 0x1774c99c, 0x299a493a, 0x17ef6019, 0x2a210332, 0x147b428d, 0x252e580e, 0x4ce0}}, + {{0x25c0de52, 0x3053dedb, 0x1ea06502, 0x0816c832, 0x36aca216, 0x2d360329, 0x29b3ed57, 0x03eeafc6, 0x0539}}}, + /* 9*16^13*G: */ + {{{0x0aaafe5a, 0x30dd782c, 0x109aedd4, 0x151c2ce9, 0x023fd0e2, 0x229aa56c, 0x267de96d, 0x23addbf1, 0x9a96}}, + {{0x0ed975c0, 0x39aff509, 0x1e70cc0c, 0x2d620299, 0x061d0ee7, 0x319b40f6, 0x3ba2954f, 0x3ec1e9b4, 0xabf6}}}, + /* 11*16^13*G: */ + {{{0x334c6397, 0x1d472fe7, 0x074cd093, 0x374f6d40, 0x36b22107, 0x2bbe0094, 0x161954f0, 0x3efb405c, 0xd3c6}}, + {{0x28cb3f9c, 0x07f23415, 0x05e0e00b, 0x031dc224, 0x2ab6468a, 0x20e5364b, 0x22af1945, 0x34b15797, 0x4a0d}}}, + /* 13*16^13*G: */ + {{{0x0ac3137e, 0x26e0964c, 0x1af64461, 0x2496d8a9, 0x2b3953fe, 0x3c1a9daa, 0x243b8e02, 0x38e604a4, 0x4cbd}}, + {{0x2ec02fe6, 0x0023c573, 0x08ead60c, 0x24e9eb96, 0x14c370d1, 0x24a84d2e, 0x36159500, 0x151823c4, 0x6ce5}}}, + /* 15*16^13*G: */ + {{{0x20fbf84b, 0x1e88c1b3, 0x03f0b8a4, 0x3123f2ef, 0x14cebb03, 0x3671cc30, 0x16247b8b, 0x0ccf20ac, 0x4b9d}}, + {{0x236c3c48, 0x0e7b92d2, 0x2f5b5e62, 0x19b550f8, 0x39b7eb67, 0x04f66099, 0x0c152553, 0x31fef893, 0xfd7f}}} + }, + { + /* 1*16^14*G: */ + {{{0x19c43862, 0x2a107856, 0x397e6690, 0x29fd3c60, 0x381bde71, 0x02061a26, 0x1ff21e6d, 0x3b4d3073, 0x385e}}, + {{0x142e5453, 0x01163f95, 0x086dc8cc, 0x0c13bb08, 0x2bf4576b, 0x077867a7, 0x223f5670, 0x3af0fa3a, 0x283b}}}, + /* 3*16^14*G: */ + {{{0x36e2d9b3, 0x12f4c1aa, 0x338d6351, 0x36e4a0c6, 0x0f845641, 0x0ba984e7, 0x305e75e1, 0x053ce5f1, 0x19a3}}, + {{0x0baaaf33, 0x154bb897, 0x004be56d, 0x00874749, 0x3528b3a5, 0x2597e21f, 0x328dd234, 0x363d76b1, 0x6cac}}}, + /* 5*16^14*G: */ + {{{0x12f00480, 0x36161fac, 0x100dcee7, 0x0d620128, 0x36721920, 0x32618d93, 0x0daa355d, 0x3b52e56a, 0x5840}}, + {{0x3e22cf9e, 0x164b578a, 0x2ae38721, 0x1d489514, 0x1dd8daba, 0x1a37aa85, 0x3f141079, 0x369ac882, 0x670c}}}, + /* 7*16^14*G: */ + {{{0x23f54c42, 0x12137ba0, 0x29a3dc8e, 0x37068f09, 0x0e532545, 0x16307d3b, 0x118fb1dc, 0x00694d1a, 0x9f57}}, + {{0x2feb6a21, 0x18387124, 0x219e5278, 0x3b9e12ac, 0x29bfdd89, 0x256dad5c, 0x19e57bfb, 0x23ee2007, 0xce7b}}}, + /* 9*16^14*G: */ + {{{0x1522461a, 0x3a504cca, 0x3c718327, 0x2cc28996, 0x3ef9a0bc, 0x2e1c0419, 0x28cfc01b, 0x045a48d6, 0x27f6}}, + {{0x07301a2d, 0x2a932be7, 0x28639446, 0x2606c836, 0x028ee8e4, 0x2315849d, 0x26ad2ea4, 0x3c6a6402, 0xe512}}}, + /* 11*16^14*G: */ + {{{0x114f36b9, 0x338b26cb, 0x3b9f390c, 0x2632aed8, 0x34a98125, 0x2fcbd0d7, 0x2f941261, 0x1e615b3b, 0x6407}}, + {{0x24b4b50a, 0x252c7ba7, 0x19ceeb28, 0x36821c12, 0x1a7b6c8c, 0x035d7f61, 0x16efaef9, 0x24a3d139, 0xda61}}}, + /* 13*16^14*G: */ + {{{0x14d6b76f, 0x3bd8f7e6, 0x0c815dbc, 0x396a7eed, 0x1dfeae7f, 0x3dc22f02, 0x1669f452, 0x1438c721, 0xa237}}, + {{0x0dcca8da, 0x0764b332, 0x1b848d14, 0x1c1f047f, 0x011113e7, 0x0be8f935, 0x3de6dac3, 0x26c529b9, 0xf733}}}, + /* 15*16^14*G: */ + {{{0x3ceee475, 0x0bba7193, 0x0ed782b1, 0x1ab20a10, 0x0aff41ab, 0x0f0087cf, 0x2378d5ed, 0x2b01e8fc, 0xbbf1}}, + {{0x07fe5067, 0x1188a802, 0x38b41d68, 0x3ae76250, 0x315fe324, 0x20f320da, 0x060e6108, 0x2e37bab5, 0xb4bf}}} + }, + { + /* 1*16^15*G: */ + {{{0x03fac3a7, 0x181bb61b, 0x147fbc9c, 0x377e1296, 0x3dfa180f, 0x31ce9104, 0x0f191637, 0x366e00fb, 0x06f9}}, + {{0x3a842160, 0x21a24180, 0x0281002d, 0x29374bd7, 0x05c4d47e, 0x238a8c39, 0x059ba69b, 0x31a3980c, 0x7c80}}}, + /* 3*16^15*G: */ + {{{0x121ce204, 0x13b5d7a3, 0x26763d52, 0x29c96390, 0x26f72fb2, 0x1d361672, 0x3c64fb83, 0x107458ac, 0x43ca}}, + {{0x134a8f6b, 0x1494113a, 0x2a4a468e, 0x2db1eccf, 0x1ba31f9a, 0x143e4863, 0x023fa1c6, 0x16a0b8dc, 0xdcea}}}, + /* 5*16^15*G: */ + {{{0x2be6efda, 0x13f3a4b3, 0x07280596, 0x0b53fcfe, 0x1a506d92, 0x1bdc8de1, 0x12bf5b66, 0x01bbc8a2, 0x9c3e}}, + {{0x27aefc7d, 0x3c503cca, 0x336fdf7d, 0x0ef21a1e, 0x226fd5d4, 0x02cb5133, 0x2923d8af, 0x027979d8, 0xa7b7}}}, + /* 7*16^15*G: */ + {{{0x06c88be2, 0x2449ead7, 0x06ee5e27, 0x0b1e0834, 0x30775bea, 0x1c9d6760, 0x20f033bb, 0x22a8c4f8, 0x5d6f}}, + {{0x0d7ad75d, 0x24b954fc, 0x2bf92c28, 0x2adbe3a9, 0x08bc20ed, 0x2abcceac, 0x2d4e8c71, 0x2c636355, 0xadc4}}}, + /* 9*16^15*G: */ + {{{0x12d1b844, 0x0a24d46e, 0x173e484f, 0x2700e0b0, 0x388bc5c6, 0x2c570f04, 0x20d5fc86, 0x0d70c129, 0xf57d}}, + {{0x21266837, 0x192eaef5, 0x0915c6a4, 0x01a5c80c, 0x24634c70, 0x134fd6a7, 0x2f4d9790, 0x0f67aa63, 0x707f}}}, + /* 11*16^15*G: */ + {{{0x3cc7cb09, 0x0d3401fc, 0x1d1b4352, 0x31fada28, 0x1871463b, 0x1b87fb8f, 0x194a5f59, 0x181e8e99, 0x13e7}}, + {{0x08079160, 0x2f9d6a28, 0x2b576411, 0x3ab8aed9, 0x34299d65, 0x17f7616c, 0x3b8b1e32, 0x32237a3e, 0x284d}}}, + /* 13*16^15*G: */ + {{{0x18cdee05, 0x01833849, 0x32ec3b90, 0x1d87ec85, 0x06901da8, 0x00942c6c, 0x182e6240, 0x28c895a0, 0x29be}}, + {{0x262651c8, 0x39280d66, 0x0c698e39, 0x3f0c6db2, 0x305ec7f9, 0x026cfee1, 0x29a0ea90, 0x36689a43, 0x7c40}}}, + /* 15*16^15*G: */ + {{{0x12f18ada, 0x06db1d58, 0x3dbdbcc1, 0x182f64ee, 0x3d4a59d4, 0x0dbebfcc, 0x288e7d9c, 0x1e1b48e0, 0xf521}}, + {{0x23953516, 0x375a2bf4, 0x05bf0981, 0x17bd28db, 0x11d1d6aa, 0x09840af3, 0x0db57ecc, 0x1befd80e, 0xe068}}} + }, + { + /* 1*16^16*G: */ + {{{0x02d0e6bd, 0x0edf839d, 0x30f5e531, 0x1d3458f6, 0x0d6ecbf7, 0x0851f041, 0x04e2582a, 0x3500490f, 0x3322}}, + {{0x2c28b2a0, 0x13ce8ba5, 0x2873af62, 0x017d8fa8, 0x1af9b728, 0x0066f137, 0x24ef5bfb, 0x01e5fa59, 0x56e7}}}, + /* 3*16^16*G: */ + {{{0x059ab499, 0x2f674fc8, 0x273c330a, 0x04ca671b, 0x3f01bc0b, 0x065acf19, 0x005ba5d2, 0x2bfcc057, 0x78ba}}, + {{0x3ee097fd, 0x20748c63, 0x11251996, 0x18cbbba3, 0x02082e91, 0x2a1383b6, 0x2c0afafc, 0x3736f6c1, 0xad4b}}}, + /* 5*16^16*G: */ + {{{0x3d06ace6, 0x124f85b3, 0x03a20ca4, 0x1c26cdbe, 0x29ab1a23, 0x2e126124, 0x2e3d4c20, 0x3c846852, 0x6f70}}, + {{0x3602d5de, 0x122fb4d2, 0x25ac5ee0, 0x0ca559af, 0x399f5075, 0x1763cd1e, 0x27b736f9, 0x228c2500, 0x791e}}}, + /* 7*16^16*G: */ + {{{0x20ee1b40, 0x323b8fb9, 0x1e96247d, 0x3b5216dc, 0x03ccd48c, 0x2527c644, 0x2a415f80, 0x276ca75a, 0xe159}}, + {{0x178f93a6, 0x0758997b, 0x032999de, 0x0d8e9d2f, 0x2fc7cfa6, 0x3e252aa8, 0x1d4a0efa, 0x1888caa0, 0x7933}}}, + /* 9*16^16*G: */ + {{{0x09c00c3e, 0x2077e8a1, 0x11208e2f, 0x03a3c0f2, 0x051859f0, 0x158b4cf5, 0x06956436, 0x0125c110, 0xbb0b}}, + {{0x11955a35, 0x266a60b4, 0x05dc90a7, 0x19c113a4, 0x31b052fe, 0x34be85ea, 0x39f63655, 0x391614eb, 0x4067}}}, + /* 11*16^16*G: */ + {{{0x05dd32e6, 0x039d6e70, 0x13e5ee7e, 0x18ed546d, 0x1a5fbfc6, 0x1276f81d, 0x1789e9b6, 0x10555065, 0xdc5a}}, + {{0x354a99b9, 0x039f6de9, 0x2e49bcf8, 0x3cbba41d, 0x3f59442f, 0x3a978806, 0x367a76dc, 0x2a298fe7, 0x4af3}}}, + /* 13*16^16*G: */ + {{{0x0544e7cb, 0x3b516eb1, 0x12960359, 0x0190896d, 0x014e99a1, 0x0d5295c4, 0x33b9dbe3, 0x065c0e61, 0x156e}}, + {{0x2d250a37, 0x354e4b02, 0x2b439cd6, 0x25b56357, 0x034be894, 0x255ca98e, 0x1907da93, 0x2367e3cc, 0x6bc0}}}, + /* 15*16^16*G: */ + {{{0x059853ca, 0x2fef0a73, 0x319bf54d, 0x3a589ae7, 0x27161348, 0x29da88a3, 0x043826bc, 0x2f33b2da, 0x4269}}, + {{0x35b8d367, 0x2a563bd4, 0x1e5a8a3d, 0x0e50297e, 0x31a409fd, 0x2132a710, 0x016b723c, 0x0706a0b0, 0xed2b}}} + }, + { + /* 1*16^17*G: */ + {{{0x0134ab83, 0x0875d34a, 0x36433977, 0x06cfe6bd, 0x26586874, 0x05dc3625, 0x0b7da2bd, 0x0b1f4b78, 0x8567}}, + {{0x390313a6, 0x238c253d, 0x1298f44c, 0x1fc5ff31, 0x22c2e5e7, 0x10126fe9, 0x3b2eb637, 0x06e6d6d0, 0x7c48}}}, + /* 3*16^17*G: */ + {{{0x03ba9000, 0x37c1c8ea, 0x025e8b6f, 0x21cbe71a, 0x00143dc4, 0x21d81d61, 0x1d8c1684, 0x1d3e7ffc, 0xac38}}, + {{0x2f10cf0a, 0x368f1f65, 0x366e9fa4, 0x178d435f, 0x117f9308, 0x0b77a250, 0x1c069b86, 0x3a48c228, 0xaa65}}}, + /* 5*16^17*G: */ + {{{0x2d06dbd4, 0x2981bd9b, 0x0a20d081, 0x038fe15e, 0x23e729ec, 0x0501d7a6, 0x070139ad, 0x1739ea9a, 0x570d}}, + {{0x3d1ed495, 0x2996fb3a, 0x2460bed5, 0x20e8db71, 0x101bbbb6, 0x19b99c47, 0x202f605b, 0x14d25083, 0xa6ae}}}, + /* 7*16^17*G: */ + {{{0x092d230e, 0x0d307e48, 0x29339284, 0x3b8ca834, 0x366ef5da, 0x308a7b80, 0x28bb6f87, 0x3e1c0a09, 0x75b5}}, + {{0x151570b8, 0x0df2f7ef, 0x111f8fb0, 0x19e92c01, 0x1dfa8e02, 0x1e1d1553, 0x3852363d, 0x338878e9, 0x527c}}}, + /* 9*16^17*G: */ + {{{0x034fcc0e, 0x1edafdab, 0x3e3884c4, 0x1fc4290a, 0x1259c892, 0x16e0389f, 0x1dec2b0a, 0x23beb87b, 0x44fc}}, + {{0x319c420a, 0x33fc0c79, 0x0d0489d9, 0x03a5292f, 0x33d3d772, 0x099f9e20, 0x31367e49, 0x37a52ea6, 0xd2c7}}}, + /* 11*16^17*G: */ + {{{0x0bb69991, 0x169207f2, 0x3307175d, 0x3ecfe8b0, 0x02f535ff, 0x28598838, 0x27bc6866, 0x2e91eeb3, 0xdea2}}, + {{0x316fe2df, 0x019d0aa7, 0x21ed9bc7, 0x27736cd8, 0x37b9e722, 0x32ffb213, 0x028e4ac5, 0x2ff5b643, 0xae28}}}, + /* 13*16^17*G: */ + {{{0x114fc9cc, 0x30903409, 0x1a461658, 0x3402af0a, 0x38a83626, 0x073db312, 0x168d6efc, 0x3f2629b8, 0x3968}}, + {{0x1fad37dd, 0x064e5225, 0x388f3340, 0x05195dbf, 0x2d32c91a, 0x1e60b46a, 0x35928123, 0x2ef436d2, 0x789c}}}, + /* 15*16^17*G: */ + {{{0x2e0c85f1, 0x2bb08646, 0x03a3a250, 0x294b94d8, 0x3945d5a6, 0x0977c255, 0x06a2926b, 0x2441a638, 0x6896}}, + {{0x2dc1de21, 0x31d208cc, 0x0d503922, 0x10306768, 0x05d72d1f, 0x0c170761, 0x0979256f, 0x0fed2ce3, 0xaefd}}} + }, + { + /* 1*16^18*G: */ + {{{0x20c82a0a, 0x3f6566bd, 0x3668832f, 0x2489b183, 0x1413b10f, 0x1b27c646, 0x188a46b0, 0x2fe026c6, 0x0948}}, + {{0x18c8e589, 0x132dfe23, 0x17cd2bed, 0x137fc232, 0x03418c6d, 0x2dd31747, 0x36646dc6, 0x18a15b72, 0x53a5}}}, + /* 3*16^18*G: */ + {{{0x38c8ac7f, 0x0a0bf97e, 0x1e2aa527, 0x0490bb99, 0x16f84964, 0x0ce5b481, 0x22bbcb5c, 0x2cbef8e0, 0x9945}}, + {{0x29aea3b0, 0x1b650e85, 0x2dacdfa9, 0x0bde88fb, 0x28eff528, 0x36d13fec, 0x3282d607, 0x3b6092c3, 0x3eef}}}, + /* 5*16^18*G: */ + {{{0x169e353a, 0x3475e78e, 0x2bbe1f6e, 0x28110214, 0x07d5fe10, 0x3e0889c4, 0x070e6235, 0x131ac816, 0x2a31}}, + {{0x25746067, 0x09649b87, 0x32658bfc, 0x22952ab6, 0x2a1ba013, 0x18f91dae, 0x227ac1a4, 0x2b02fcd6, 0x15a4}}}, + /* 7*16^18*G: */ + {{{0x29b84966, 0x278bd27b, 0x17f3ff98, 0x13d041b7, 0x2b6c911b, 0x2dbebce9, 0x3fc2d498, 0x29402dc0, 0x5959}}, + {{0x07473a6a, 0x02998c86, 0x0fe24264, 0x00373023, 0x082a7091, 0x0c4a0837, 0x0a897f94, 0x399d07d7, 0x0370}}}, + /* 9*16^18*G: */ + {{{0x2bc6b173, 0x2c326e48, 0x2ed3feb3, 0x36188f1f, 0x1b5f9d7d, 0x183118c1, 0x22fe8e11, 0x0c4e4dc8, 0x9eeb}}, + {{0x1723a71d, 0x14e58836, 0x0e70c4b9, 0x29c6afb4, 0x3a1ae30e, 0x2aaff6ee, 0x2d58d952, 0x3c780443, 0xe121}}}, + /* 11*16^18*G: */ + {{{0x3ec805f3, 0x1dc910fd, 0x1d995915, 0x3903dd42, 0x2e97887d, 0x2ec8e201, 0x318f516e, 0x13f931fd, 0x39cc}}, + {{0x3a3c48d3, 0x06468304, 0x3c912e4d, 0x2e55cdcf, 0x02de7dbb, 0x399a4f3d, 0x2f8f3151, 0x11cb1691, 0xecb1}}}, + /* 13*16^18*G: */ + {{{0x0e22580e, 0x0f58bed7, 0x2d6f8879, 0x04ca25b4, 0x1bd4d2c7, 0x0bff7993, 0x0dc69689, 0x201d19bb, 0xf94c}}, + {{0x3127db82, 0x07948fd9, 0x2371d4e8, 0x21fb114c, 0x1a81f698, 0x12ffdaad, 0x1225a919, 0x1ff719e1, 0x5e9c}}}, + /* 15*16^18*G: */ + {{{0x10c4f21f, 0x2f902eb4, 0x103da7a6, 0x092a5653, 0x1999d250, 0x0081a36c, 0x1d162fcc, 0x2e1b1ab5, 0x8ccc}}, + {{0x329dfea0, 0x1fc49ba9, 0x264be28f, 0x24b72b20, 0x0758a54b, 0x2fbd5272, 0x11c43699, 0x2596189d, 0x57f8}}} + }, + { + /* 1*16^19*G: */ + {{{0x338fd8e8, 0x33b36067, 0x069752ac, 0x2c39137f, 0x2873a8f1, 0x19f383c0, 0x001c34f0, 0x339fd186, 0x6260}}, + {{0x32b4ae17, 0x06a13a56, 0x051c198c, 0x34a488e0, 0x2a1ef7ec, 0x024125dd, 0x1b571a7f, 0x2a0adbe9, 0xbc2d}}}, + /* 3*16^19*G: */ + {{{0x01136602, 0x2c2e9195, 0x19e3a5bb, 0x311bd203, 0x333b3d38, 0x1624dfc8, 0x2dfc33d0, 0x09ca0120, 0x87d1}}, + {{0x18af6aac, 0x3da0f107, 0x3d3bf7c4, 0x2a211d1b, 0x27745387, 0x289db3fd, 0x203de926, 0x0921c296, 0x71ce}}}, + /* 5*16^19*G: */ + {{{0x08c5a916, 0x2c8175cd, 0x35610f25, 0x17110354, 0x354aa13f, 0x2b318f6a, 0x1e9746b0, 0x1f4ff898, 0xfd5d}}, + {{0x3adb8bda, 0x052cdec1, 0x1cf6faab, 0x35ce052f, 0x07b52fe5, 0x10f299e7, 0x15b07d2b, 0x0fb43bad, 0x0dd8}}}, + /* 7*16^19*G: */ + {{{0x35f7529c, 0x17664258, 0x1bd51dd4, 0x1d96e62d, 0x34438138, 0x114f0cb4, 0x026122ba, 0x35042607, 0xde0d}}, + {{0x24cd88fe, 0x0f08300b, 0x09b77406, 0x224931a2, 0x3a357017, 0x042608b5, 0x2145f9b2, 0x1ba74428, 0xd70a}}}, + /* 9*16^19*G: */ + {{{0x38f76d11, 0x320bd234, 0x38515573, 0x044003ef, 0x0292a215, 0x16fbf0e7, 0x0f44e69c, 0x0822b693, 0xb26c}}, + {{0x23b7356b, 0x307002c7, 0x182624bd, 0x000c1967, 0x0d643305, 0x13a1f643, 0x1d33cf0c, 0x3e208252, 0x1f1c}}}, + /* 11*16^19*G: */ + {{{0x269e22db, 0x2538ec19, 0x39c8933f, 0x264ffd67, 0x0c294eac, 0x0ef4a406, 0x3f523a7e, 0x052e3f1f, 0xfceb}}, + {{0x1c2260a1, 0x3d5cb6c9, 0x24ebe4cb, 0x15439e4e, 0x1f0924ad, 0x22969d49, 0x2b8d1fcd, 0x1ace9035, 0x64aa}}}, + /* 13*16^19*G: */ + {{{0x238a2755, 0x3c2105e6, 0x149c5506, 0x1c869c59, 0x107faa53, 0x05d5dd2d, 0x15cac55c, 0x26988f33, 0x4e90}}, + {{0x23cca3de, 0x3de927d8, 0x229800ca, 0x3354e534, 0x3559dbb6, 0x091b7541, 0x235aecef, 0x36a1e333, 0xae56}}}, + /* 15*16^19*G: */ + {{{0x183ba64d, 0x20962566, 0x0c595a3a, 0x3983dde2, 0x0e40e2bd, 0x028517ae, 0x04c03bfb, 0x115708b8, 0xc367}}, + {{0x2a2181fd, 0x053323e5, 0x1778f146, 0x189aab28, 0x1964c742, 0x3839ba13, 0x36033080, 0x02b41a72, 0x3a52}}} + }, + { + /* 1*16^20*G: */ + {{{0x2037fa2d, 0x254f3234, 0x1bfdc432, 0x0fb23d5d, 0x3f410304, 0x0d21052e, 0x1d8d43d8, 0x1f782bf0, 0xe503}}, + {{0x1d755bda, 0x03977210, 0x0481f10e, 0x17d6c0fb, 0x190bddbd, 0x263427ee, 0x0d3b5f9f, 0x14d2eaa5, 0x4571}}}, + /* 3*16^20*G: */ + {{{0x177e7775, 0x222a29b8, 0x0ed95f63, 0x385564e2, 0x1291aeb5, 0x150eeb3d, 0x233cee58, 0x1a8ebfe5, 0x9d89}}, + {{0x3a056691, 0x3f3db4ea, 0x299253be, 0x26735fb8, 0x10927de8, 0x2593b5c9, 0x1bf0b94e, 0x2a790fd2, 0xdd91}}}, + /* 5*16^20*G: */ + {{{0x3c2a3293, 0x3f781378, 0x103476c5, 0x222e1bba, 0x02f4cd56, 0x2c295cca, 0x23792d0e, 0x2e3b9c45, 0x8327}}, + {{0x0e0df9bd, 0x2f215386, 0x2326a416, 0x2bf6ad3b, 0x39708496, 0x2cfa9989, 0x0a98e18b, 0x1f899bb8, 0x0499}}}, + /* 7*16^20*G: */ + {{{0x0562c042, 0x1086c9b1, 0x38dfb1a2, 0x0b48c8d2, 0x1a8ed609, 0x1998763e, 0x1b16897d, 0x0aaa8a9b, 0x5ae4}}, + {{0x0f79269c, 0x2417337e, 0x07cd8dbf, 0x3836e544, 0x389d4a94, 0x30777180, 0x3051eab5, 0x0e9f017f, 0x99d9}}}, + /* 9*16^20*G: */ + {{{0x1e85af61, 0x0d2204a1, 0x14ae766b, 0x23b5c8b7, 0x021b0f4e, 0x3ada3fdb, 0x1c8eb59a, 0x0eb909a8, 0x92c2}}, + {{0x036a2b09, 0x39c8d9a7, 0x2286fed4, 0x08eb60ad, 0x38d5792d, 0x085f571c, 0x11bb409f, 0x3e23c055, 0x414c}}}, + /* 11*16^20*G: */ + {{{0x07b5eba8, 0x38abc6cb, 0x118ea36c, 0x2afb71fe, 0x38df422d, 0x03d05dab, 0x3df1088d, 0x18231dab, 0xfee5}}, + {{0x0d0b9b5c, 0x3d4574da, 0x39054793, 0x203fd0af, 0x07c14ee3, 0x100be64a, 0x258afb11, 0x16644d3f, 0x3807}}}, + /* 13*16^20*G: */ + {{{0x3c63caf4, 0x078ee92c, 0x0f53d528, 0x23fceaca, 0x2a6afca2, 0x044ed318, 0x267e620a, 0x113ae4b9, 0x42e5}}, + {{0x169c29c8, 0x21ebb026, 0x3efc5f11, 0x29439eda, 0x015e7873, 0x3c88305d, 0x0c671f71, 0x15383e47, 0x9ff8}}}, + /* 15*16^20*G: */ + {{{0x1e0f09a1, 0x028af661, 0x14032838, 0x28427c6e, 0x300efef0, 0x25bb4a91, 0x32ce3839, 0x20ed9954, 0x7aed}}, + {{0x05857d73, 0x1176337a, 0x33f4a540, 0x22cbcc03, 0x032d8ed8, 0x2bf42ac4, 0x1ef7c7dd, 0x1517e68c, 0xf5b8}}} + }, + { + /* 1*16^21*G: */ + {{{0x24fce725, 0x1619a82b, 0x2a6c5b72, 0x3a36f471, 0x1771b4e7, 0x2a417a3c, 0x207adf5e, 0x1cac3d28, 0xe063}}, + {{0x0eee31dd, 0x09c0d3e5, 0x3104870b, 0x12129de1, 0x1a488cd7, 0x09eecab5, 0x18cfe12a, 0x225d2f38, 0x7a90}}}, + /* 3*16^21*G: */ + {{{0x1a328d6a, 0x2eaa0623, 0x1adc18bd, 0x135dcea5, 0x308fa7b2, 0x1a264616, 0x34e00a34, 0x3016e988, 0xc663}}, + {{0x3ec9b8c0, 0x0ec2edaa, 0x12bf9cc2, 0x21547a94, 0x171317dd, 0x2bf73c9d, 0x21c38d39, 0x3a6357dc, 0x3331}}}, + /* 5*16^21*G: */ + {{{0x3996de2f, 0x32472120, 0x0b25114b, 0x33b7cbb8, 0x0fe4e977, 0x2cc37ba8, 0x06a459ce, 0x09a0b7ee, 0xd3fc}}, + {{0x14526f8c, 0x31248907, 0x37abf168, 0x166d2637, 0x3781da4e, 0x2d1d5353, 0x30a18f68, 0x37e66917, 0xc4f0}}}, + /* 7*16^21*G: */ + {{{0x03e697ea, 0x31b12344, 0x05f83e85, 0x399e3ee6, 0x3fabd19c, 0x287fb268, 0x2c0237dc, 0x12d0ffac, 0xc17a}}, + {{0x1edc6c87, 0x3b8ee1f7, 0x39f02ab0, 0x38686d5f, 0x201fae96, 0x05e3dc65, 0x35954cae, 0x170b556a, 0x3935}}}, + /* 9*16^21*G: */ + {{{0x3163da1b, 0x0b4b0c08, 0x393a3118, 0x03b7b983, 0x011fde9a, 0x24d275ff, 0x390b468c, 0x22df2899, 0x8f61}}, + {{0x03bdd76e, 0x1fcc4844, 0x249b6e7c, 0x14319a8c, 0x2c5a4264, 0x2f69d35e, 0x3eb6eb5f, 0x0fc97c22, 0x7823}}}, + /* 11*16^21*G: */ + {{{0x0ec8ae90, 0x3a1643f8, 0x0bbc5dee, 0x2c9ae4ba, 0x03f1b8cf, 0x356e36b2, 0x21e6eb86, 0x303c56de, 0x9798}}, + {{0x252844d3, 0x2a6b0bab, 0x03188e27, 0x392596f4, 0x1c73bee2, 0x3b25253e, 0x02ed3dd2, 0x38aa9d69, 0xba40}}}, + /* 13*16^21*G: */ + {{{0x11d66b7f, 0x16865e3c, 0x187dc810, 0x29a49414, 0x1284757a, 0x3c6e42e2, 0x22d6747c, 0x1bb8fed6, 0xfdfa}}, + {{0x38e5178b, 0x2aa3e019, 0x3d78de9d, 0x11be7744, 0x1a18c4d8, 0x0307268f, 0x198db93c, 0x3cc78892, 0x4d9c}}}, + /* 15*16^21*G: */ + {{{0x1265bcf0, 0x201d5e12, 0x11c7d30b, 0x338ade10, 0x0f220e69, 0x3aa69187, 0x29e43add, 0x338e3788, 0xfd58}}, + {{0x2b996292, 0x0cf9ea73, 0x0f1cd1df, 0x0986ff8a, 0x05e4fb87, 0x20aae692, 0x3215bd53, 0x29794dd8, 0xffe0}}} + }, + { + /* 1*16^22*G: */ + {{{0x10559754, 0x02b5a423, 0x2a3f5854, 0x2c42f778, 0x0ce02204, 0x02efe770, 0x1d45358d, 0x1e9c5735, 0x213c}}, + {{0x34b458f2, 0x3fcb09d4, 0x36a7eedd, 0x12143d7c, 0x1ba190bb, 0x0eb41891, 0x06250701, 0x2b42d6b9, 0x4b6d}}}, + /* 3*16^22*G: */ + {{{0x1e05dccc, 0x0cb60046, 0x019a93e5, 0x0fe8fb53, 0x13d172ae, 0x1b825ae5, 0x1a030954, 0x3db85d4f, 0xb8ce}}, + {{0x0c6d5750, 0x0052833f, 0x26b68133, 0x1d5ff0da, 0x12bd99df, 0x3529d393, 0x09bbf6a4, 0x229829b3, 0x302b}}}, + /* 5*16^22*G: */ + {{{0x373bb31a, 0x16f7fb84, 0x3db97b48, 0x07dedad7, 0x3b5f4970, 0x282f78ba, 0x07385e02, 0x0cf9de6d, 0x03fb}}, + {{0x3d215c9e, 0x0d32f9a5, 0x07640d4e, 0x169f1db1, 0x3b572bc6, 0x30586aae, 0x2fe281e0, 0x36549523, 0xf36a}}}, + /* 7*16^22*G: */ + {{{0x1d9a4ab4, 0x16d457af, 0x15bb7c0a, 0x1f0db061, 0x0f7a3671, 0x05bded34, 0x03e1161f, 0x1f34427b, 0x4b17}}, + {{0x235ab6f7, 0x2ab77f91, 0x1741f558, 0x0df8957c, 0x226b486e, 0x23d9ca4d, 0x2fa65fda, 0x19ba6978, 0x3ec9}}}, + /* 9*16^22*G: */ + {{{0x301c23a4, 0x3d1beca6, 0x3a49cf56, 0x0a905611, 0x39cd75c2, 0x00e0a6e6, 0x27a06c2a, 0x00d481a8, 0x5e87}}, + {{0x10d986f9, 0x085e65ac, 0x24ccfda1, 0x05c761d2, 0x2c6e2da2, 0x1d5746b8, 0x09221e71, 0x1913bee7, 0x5b96}}}, + /* 11*16^22*G: */ + {{{0x007b0c66, 0x3cfcd748, 0x16c86fb1, 0x29ffb919, 0x2ceb7434, 0x08913d82, 0x1680a447, 0x30c064c3, 0xe545}}, + {{0x31f2d470, 0x21fd5f49, 0x35a239dd, 0x3960a386, 0x19bcbf97, 0x31bf68e5, 0x2955e7e5, 0x0d03a318, 0xe06a}}}, + /* 13*16^22*G: */ + {{{0x03648bba, 0x2960642e, 0x1c3c7444, 0x283c2c1a, 0x01b39882, 0x0fb8897c, 0x0f580a13, 0x10855e95, 0xb2a4}}, + {{0x00fb6452, 0x11bead28, 0x09c17bb2, 0x36154547, 0x3d7e31c0, 0x3ef25e3e, 0x366619e9, 0x17f0ada4, 0xfe4f}}}, + /* 15*16^22*G: */ + {{{0x2bab27d0, 0x3db748bb, 0x045103fc, 0x02d07e8b, 0x197007f7, 0x25c06463, 0x138651ba, 0x2383cf51, 0x1b90}}, + {{0x00d3d110, 0x07a19d79, 0x07e51b57, 0x2ef2a4d6, 0x3c4b9ab5, 0x15f24605, 0x26b5e6f3, 0x1897bb11, 0x9b6d}}} + }, + { + /* 1*16^23*G: */ + {{{0x08fbd53c, 0x0330e8ec, 0x1c62cddf, 0x20e31c2b, 0x019a87e2, 0x2e4d4a95, 0x0b34e8db, 0x09ca9ebd, 0x4e7c}}, + {{0x17dcaae6, 0x02ce5060, 0x3f7dd33e, 0x02e5852f, 0x2f681b53, 0x3f427db7, 0x10b18e16, 0x271d9b27, 0x1774}}}, + /* 3*16^23*G: */ + {{{0x2521b3ff, 0x38a61193, 0x1aa750ce, 0x0f01c5fa, 0x2e24a523, 0x1134afa6, 0x1455c75e, 0x138c0432, 0x0248}}, + {{0x0269da7e, 0x306b92e4, 0x23ac8bbc, 0x1c01b7a4, 0x2d0eebad, 0x30acf0ac, 0x3e30d07e, 0x34282a88, 0x9619}}}, + /* 5*16^23*G: */ + {{{0x004ba7b9, 0x25ade7ea, 0x0741751f, 0x35a91c0c, 0x2c954e20, 0x26dc359c, 0x2ce57ef7, 0x3149b3ed, 0x16c1}}, + {{0x1c5bd741, 0x1d6f8e94, 0x1c9a9cc4, 0x1d57006f, 0x0a94deec, 0x189d1672, 0x31439062, 0x1fdf0d00, 0xdb15}}}, + /* 7*16^23*G: */ + {{{0x236683fa, 0x20d921ea, 0x0ec0825e, 0x2086d4e0, 0x127b6695, 0x22739dd1, 0x131af87a, 0x0f35d4fe, 0x0397}}, + {{0x3f4a577f, 0x3d7ecadd, 0x3e981ded, 0x1e213863, 0x35a26cd7, 0x384ad8ca, 0x0a3a3643, 0x168b30c3, 0x38cf}}}, + /* 9*16^23*G: */ + {{{0x00bf6f06, 0x202ce667, 0x1043b571, 0x0f04cc89, 0x20576571, 0x3013d2c0, 0x0f1511c2, 0x26ee9cbb, 0xba6a}}, + {{0x381db551, 0x0cafbdc1, 0x0697aafe, 0x17453deb, 0x18bd8e9e, 0x082fcb95, 0x211b0320, 0x078e2cd2, 0x1377}}}, + /* 11*16^23*G: */ + {{{0x31231a43, 0x347be7c1, 0x1ad43b9f, 0x35453599, 0x1e442f44, 0x3b654193, 0x04dd2d8a, 0x2f3309f3, 0x35c5}}, + {{0x1620c8f6, 0x36dcb914, 0x23cf0ae7, 0x3de93301, 0x3a589d4c, 0x396082db, 0x346ce734, 0x1d5c8ee5, 0x0e36}}}, + /* 13*16^23*G: */ + {{{0x3dd40609, 0x3d02f15b, 0x181cd76b, 0x10642603, 0x08356ac7, 0x0bc4bf16, 0x186bca12, 0x27091715, 0xfd47}}, + {{0x2a64ca53, 0x378bc4d9, 0x21ca4739, 0x04ebb5c9, 0x1841fd91, 0x2b5e90f2, 0x0afeff2c, 0x33ed49a5, 0x3069}}}, + /* 15*16^23*G: */ + {{{0x2b799a7f, 0x36dc0bd4, 0x3b8e8424, 0x062db354, 0x2c7d544f, 0x363ae6bc, 0x0d864bde, 0x000a8eb3, 0x6c40}}, + {{0x13c81e32, 0x2d7320b3, 0x20483f68, 0x1eaf5320, 0x1ddcbdc0, 0x2e0da838, 0x235be690, 0x37054c2d, 0x95c2}}} + }, + { + /* 1*16^24*G: */ + {{{0x00fb27b6, 0x0909f8a1, 0x24305763, 0x1b8f6caf, 0x286aa5c7, 0x08e2b585, 0x38b1b10f, 0x138f6f9d, 0xfea7}}, + {{0x323cb96f, 0x0074f6df, 0x33f7b777, 0x1ad65ae5, 0x36af9312, 0x19d37b32, 0x313297cf, 0x1a36e6c2, 0x6e05}}}, + /* 3*16^24*G: */ + {{{0x3e889756, 0x37606ba6, 0x3004bb25, 0x1ed9265e, 0x1899f3f2, 0x3365ec9c, 0x1fea8226, 0x22f0cc84, 0x762e}}, + {{0x3ca6b774, 0x17896781, 0x084fa5e2, 0x1cb6cc52, 0x02e34719, 0x3313c526, 0x3e97c3c7, 0x250982bc, 0xc028}}}, + /* 5*16^24*G: */ + {{{0x0975d2ea, 0x1bdd7a5c, 0x014e8ea2, 0x14ab3e84, 0x08f4a91e, 0x26f6ec8c, 0x095348e1, 0x1f51f7d8, 0xdf07}}, + {{0x31936f95, 0x28f0b678, 0x3bdd277a, 0x07b16e13, 0x22527c8a, 0x21097262, 0x37f4424c, 0x1ea2003b, 0xf861}}}, + /* 7*16^24*G: */ + {{{0x3c4c92d7, 0x2e1247ee, 0x14391b45, 0x36d35bb9, 0x0b142935, 0x1f7aa0cd, 0x3da032e1, 0x1f5d62f4, 0x9f3e}}, + {{0x314906dd, 0x32eeff3e, 0x294e1186, 0x0a88c0f5, 0x2b150245, 0x18ac872e, 0x1466b588, 0x2107a9df, 0xecd2}}}, + /* 9*16^24*G: */ + {{{0x32a8c483, 0x2b835cca, 0x1040ac35, 0x12c32231, 0x39528117, 0x230f48bb, 0x0cf9edc3, 0x1e575ed7, 0xa0cc}}, + {{0x12cc6ba9, 0x0259d156, 0x36936055, 0x0d23c6f7, 0x31df786b, 0x1d3f25c8, 0x3873ee23, 0x0048be2c, 0xabc3}}}, + /* 11*16^24*G: */ + {{{0x05dd3aee, 0x1c3c6daf, 0x396d2f21, 0x054ea2a3, 0x2976ca13, 0x08aa6b1a, 0x3c7cce0e, 0x14294554, 0x6d1c}}, + {{0x3df597f7, 0x3b8d5393, 0x0ed53adf, 0x078c42aa, 0x07d47485, 0x09c8008a, 0x3dfdc977, 0x052381aa, 0xafff}}}, + /* 13*16^24*G: */ + {{{0x24a6d0bb, 0x1e32a6df, 0x1a1afdc6, 0x274c48bd, 0x26418f65, 0x069b62a2, 0x3f9f3f31, 0x075862e5, 0x5e5f}}, + {{0x1033eaf9, 0x1a0e11e4, 0x06f653a1, 0x1557cb94, 0x2721da72, 0x3daf3413, 0x3e6f7358, 0x140ac1a9, 0xd7b1}}}, + /* 15*16^24*G: */ + {{{0x0f005e3f, 0x36a6d791, 0x2c39bd2d, 0x3da38c6f, 0x01a1495a, 0x0f2e6b38, 0x2427fffd, 0x229acf05, 0xf813}}, + {{0x2f357eb7, 0x0b5f8080, 0x14be2134, 0x3b106f55, 0x25cb51f4, 0x005795ea, 0x0ebd9f9d, 0x23cefbed, 0xca75}}} + }, + { + /* 1*16^25*G: */ + {{{0x17bdde39, 0x0b00a910, 0x36043295, 0x11385e6d, 0x1968d315, 0x095c3566, 0x3cf0e10a, 0x1044fd9d, 0x76e6}}, + {{0x1901ac01, 0x12c5d4b4, 0x16d2032b, 0x0a8cf4ad, 0x01f0d35e, 0x019b5c1a, 0x295cf577, 0x37e37b93, 0xc90d}}}, + /* 3*16^25*G: */ + {{{0x0078ee8d, 0x3c142473, 0x06919442, 0x2fc83394, 0x1b4ff64e, 0x3dc98eaa, 0x1a9be25f, 0x15eb6167, 0xd08e}}, + {{0x2da63e86, 0x265fd370, 0x022ed9de, 0x0fbdf3e5, 0x3e6df412, 0x05cbb9d5, 0x088d72d6, 0x25e612ad, 0x852e}}}, + /* 5*16^25*G: */ + {{{0x029129ec, 0x164519c1, 0x24825481, 0x2b8eb3c7, 0x131d080c, 0x22fa03b3, 0x04d275f5, 0x30217935, 0x7da6}}, + {{0x2cd9ff0e, 0x2d42bb8a, 0x0ca586ae, 0x12302195, 0x1627bf04, 0x34081d24, 0x01857511, 0x051aee7d, 0xf498}}}, + /* 7*16^25*G: */ + {{{0x11654f22, 0x3e0f5255, 0x31aaee94, 0x3dfce508, 0x29d94fb2, 0x3a4006f9, 0x1be6e21b, 0x2433fd70, 0x90d0}}, + {{0x201a43e1, 0x3d77815d, 0x1a3f8740, 0x358d594f, 0x3f70336d, 0x3c08781a, 0x0f61a953, 0x26874aeb, 0xcd56}}}, + /* 9*16^25*G: */ + {{{0x076b19fa, 0x2dbbd947, 0x28819d71, 0x35b81b41, 0x21292ed9, 0x08b0c420, 0x1d1ecc73, 0x26161f3c, 0xda47}}, + {{0x326f5af7, 0x2a89bbac, 0x153fc206, 0x1ef44fa5, 0x16569ea6, 0x0da41df8, 0x0af01d17, 0x35de26f3, 0xebb1}}}, + /* 11*16^25*G: */ + {{{0x39135dbd, 0x364bed96, 0x1d8631ec, 0x3021ebce, 0x29897cf0, 0x1eabd60b, 0x1ee6ad81, 0x1d412a37, 0xe3e4}}, + {{0x0748045d, 0x241abcf9, 0x2c95da96, 0x2880bfd7, 0x383ffea5, 0x2320654a, 0x3c6c40b9, 0x16fe0272, 0x930a}}}, + /* 13*16^25*G: */ + {{{0x0dee455f, 0x2fc2e797, 0x0ce4075c, 0x19fff9ba, 0x0bdb4aff, 0x114ce3e0, 0x0a9b0a47, 0x195bfa1c, 0x7e8c}}, + {{0x171b9cba, 0x1cf7a660, 0x2f466271, 0x28b459d1, 0x03a53b4a, 0x3dd83d20, 0x0740f2a3, 0x318cb28c, 0xbddd}}}, + /* 15*16^25*G: */ + {{{0x2698b59e, 0x1de5ae6d, 0x13447a43, 0x0cd64962, 0x23c7260a, 0x2c0d6acf, 0x15eb15be, 0x107e246a, 0x3df8}}, + {{0x2b92baf5, 0x33e399e5, 0x14949f8b, 0x3f219ec8, 0x1cf3867b, 0x0aeba3c4, 0x090c1da0, 0x39b7e62c, 0xb38f}}} + }, + { + /* 1*16^26*G: */ + {{{0x2bcbb891, 0x2ac54090, 0x326cbee3, 0x1f3190f7, 0x3f8f9a8f, 0x206ea9d0, 0x2abe1e82, 0x315ac0ec, 0xc738}}, + {{0x299a84c3, 0x1f9cd765, 0x080cfe91, 0x0c53bbde, 0x3fbbbb82, 0x063cbab2, 0x2d2537f7, 0x2d5e2546, 0x893f}}}, + /* 3*16^26*G: */ + {{{0x0761d58d, 0x12eabcce, 0x0d60e2f3, 0x1326f902, 0x20df7aca, 0x09028d5c, 0x3614610a, 0x1849e08f, 0xb8c4}}, + {{0x1d1051a4, 0x0e3a82ea, 0x2107c5b6, 0x1d411e17, 0x33c5053f, 0x1163da5f, 0x0e37d14a, 0x365b145c, 0x8f9e}}}, + /* 5*16^26*G: */ + {{{0x050b0040, 0x36c2cc10, 0x0134adc2, 0x3d1f6e7c, 0x1a3671f3, 0x03264ffa, 0x271f7a35, 0x1ba7dc40, 0x08d5}}, + {{0x1b3fd0a1, 0x163899e9, 0x21782beb, 0x35f11c83, 0x39b285f6, 0x34542a35, 0x29aa21ff, 0x216baf42, 0xa121}}}, + /* 7*16^26*G: */ + {{{0x13573b7f, 0x15958f7c, 0x30b6270f, 0x268717b4, 0x265a3788, 0x083e5def, 0x3ce6341e, 0x3c8cb50b, 0xdc13}}, + {{0x0c1f2ba6, 0x0ab348a1, 0x3404b1c4, 0x11551c05, 0x290a7670, 0x10436a12, 0x2340c3c7, 0x2ea010a7, 0xc909}}}, + /* 9*16^26*G: */ + {{{0x07ae9ceb, 0x00bd642e, 0x0ef2d14b, 0x1b087a9c, 0x2119a822, 0x0655976c, 0x37f073af, 0x0b798077, 0x25c0}}, + {{0x0bc6e275, 0x1c24344d, 0x26587264, 0x319077c2, 0x2d11d537, 0x2138373e, 0x2383c0c8, 0x3ab4b204, 0x8a9f}}}, + /* 11*16^26*G: */ + {{{0x2c5a3c34, 0x3e0263db, 0x15949fe1, 0x33a0b00a, 0x2e3e58ae, 0x2e7d329e, 0x0e49ce8a, 0x2746cb3e, 0xfedd}}, + {{0x213d7714, 0x0ad52fd3, 0x1bf82976, 0x2bad51a6, 0x0f4b00ad, 0x3a14c4b2, 0x3b8e0b0b, 0x0930c614, 0xa52e}}}, + /* 13*16^26*G: */ + {{{0x2ab6a396, 0x2d395346, 0x11360769, 0x0086e468, 0x0488b373, 0x38b5fd7a, 0x2a48c2de, 0x0ca1af1b, 0x3e0e}}, + {{0x1980e27e, 0x3acc7923, 0x3468f6a2, 0x2c04107c, 0x053fc66a, 0x07f877ad, 0x337964f3, 0x205cbe8e, 0xca44}}}, + /* 15*16^26*G: */ + {{{0x341023ec, 0x2bcd6188, 0x3ecf570a, 0x11763ddb, 0x02b9af56, 0x0b808026, 0x32d28498, 0x2e4c2030, 0x344a}}, + {{0x1e1eeb87, 0x13e260a4, 0x03995d70, 0x13a5dabf, 0x114c5ffc, 0x23cb47a9, 0x0462a73f, 0x0ac10ac9, 0x6e1c}}} + }, + { + /* 1*16^27*G: */ + {{{0x08f6c14b, 0x1cba7d96, 0x29250143, 0x35cb97ce, 0x172877d1, 0x131d8df2, 0x25b81e26, 0x1899522d, 0xd895}}, + {{0x1d7d991f, 0x24d8fb5d, 0x3b067e17, 0x10a358ca, 0x0340eb03, 0x3b182063, 0x07eae728, 0x2a8e3caf, 0xfebf}}}, + /* 3*16^27*G: */ + {{{0x2127b756, 0x02ea1ffd, 0x3a097048, 0x10a2f92a, 0x20b41603, 0x0d8b6941, 0x1f12672d, 0x1e0bdc5b, 0x6d8c}}, + {{0x3f172571, 0x1547dd2a, 0x17cdcca6, 0x0ea9b68b, 0x134daf4e, 0x26a0b4db, 0x1b911145, 0x37c225bf, 0x99ae}}}, + /* 5*16^27*G: */ + {{{0x358cf17a, 0x37b869cd, 0x18823524, 0x3e1772e9, 0x0097f8f1, 0x166bbc6d, 0x37aca8d0, 0x2fb7656f, 0xebca}}, + {{0x1caa0ccd, 0x11b3717d, 0x0ace95c4, 0x3eb484b4, 0x032e6b10, 0x00286d9f, 0x2b9cb02c, 0x3383e3c8, 0x47d3}}}, + /* 7*16^27*G: */ + {{{0x2c855c5b, 0x33bb9456, 0x17c8afbb, 0x21588680, 0x17fc2811, 0x0c68da78, 0x0ce24453, 0x134b92f5, 0xe8df}}, + {{0x2e465650, 0x27579cb0, 0x21e4d7d5, 0x18ed57c7, 0x2f32c596, 0x136d3d67, 0x39b26444, 0x3f5c311f, 0x6c57}}}, + /* 9*16^27*G: */ + {{{0x12e7e454, 0x023d6f69, 0x30e6150d, 0x0cbbfbc3, 0x181662fe, 0x121808ea, 0x0a832912, 0x34f5c63b, 0x4068}}, + {{0x18ef191e, 0x1e6b3797, 0x3c373327, 0x23487b44, 0x1d38d198, 0x305165f6, 0x247aab9e, 0x14edc952, 0x8cd8}}}, + /* 11*16^27*G: */ + {{{0x06c5d939, 0x215eb7e1, 0x3a933de0, 0x1d68a1de, 0x0a027ea4, 0x2fccb983, 0x025e0b55, 0x03b36c76, 0x1255}}, + {{0x19e757c9, 0x0a9d3f15, 0x0d8d4319, 0x22dd07fb, 0x324a7283, 0x2390f05d, 0x2d7a7544, 0x20cd3e1c, 0x7b8f}}}, + /* 13*16^27*G: */ + {{{0x16c8a56f, 0x2342ab19, 0x0f374213, 0x024f150d, 0x3ad08f85, 0x2eded4eb, 0x185d4c69, 0x19c6b0ed, 0x944d}}, + {{0x1a7be289, 0x27d37197, 0x106517eb, 0x35305d37, 0x3ac61967, 0x10e4d84c, 0x01fff4c1, 0x1965ded4, 0xa710}}}, + /* 15*16^27*G: */ + {{{0x2e08f15a, 0x3bae2862, 0x012900ba, 0x1a795b72, 0x13c305fd, 0x2c0d956b, 0x19a0cfe6, 0x13a47342, 0x86a5}}, + {{0x01388308, 0x1493479f, 0x335254d3, 0x04a74496, 0x35686777, 0x0aa341b5, 0x384603a7, 0x18520de9, 0xcfee}}} + }, + { + /* 1*16^28*G: */ + {{{0x0f676e03, 0x24542959, 0x3e84edd4, 0x3ff1cda4, 0x1e8761ce, 0x3d90cd5c, 0x17518eb0, 0x2500caa5, 0xb8da}}, + {{0x0efdf6e7, 0x1223939d, 0x1ff3b511, 0x33161365, 0x2808b092, 0x267325d8, 0x1a1e4d7c, 0x37e91201, 0x2804}}}, + /* 3*16^28*G: */ + {{{0x06e1346b, 0x28661277, 0x05af1c5e, 0x2f9ec40e, 0x1152c05a, 0x31d87c53, 0x2d10be54, 0x1a3fc260, 0x0690}}, + {{0x17226c13, 0x2ed62953, 0x0c6026e7, 0x3da24e65, 0x06442aa4, 0x176caf42, 0x3de26da8, 0x38f8242f, 0xb863}}}, + /* 5*16^28*G: */ + {{{0x1ca1f6a1, 0x039a47f3, 0x08cff1a3, 0x232f450d, 0x286ce106, 0x1b7172c7, 0x19761528, 0x0d24f2c9, 0x898c}}, + {{0x164f647c, 0x12b7083c, 0x32bd79ca, 0x29f3e5e7, 0x2c6e93b2, 0x1150914a, 0x2a5549d8, 0x1661aad5, 0x75f7}}}, + /* 7*16^28*G: */ + {{{0x3d1e3998, 0x29a780f0, 0x3a04328a, 0x15b22e45, 0x2a274e5e, 0x0a675c08, 0x18bf01a5, 0x38bfb4a4, 0xb213}}, + {{0x325fb81e, 0x30b2f718, 0x3ded175e, 0x0d0596fa, 0x243bc3d5, 0x187afe0e, 0x13c12c3d, 0x23b083cb, 0x229f}}}, + /* 9*16^28*G: */ + {{{0x225be234, 0x02f87fb2, 0x1df35070, 0x20f8f9c3, 0x206e060e, 0x342e9a45, 0x3f93e5d1, 0x0eb605b1, 0x4b3b}}, + {{0x120e8362, 0x18edf80e, 0x3211b840, 0x39ff64b3, 0x0cc04c41, 0x17a5b7f6, 0x2bc9c787, 0x008ee176, 0x5eec}}}, + /* 11*16^28*G: */ + {{{0x2289f55e, 0x2598d29f, 0x2c76707b, 0x1dac3c38, 0x0965be29, 0x0946c09e, 0x04f96020, 0x222db76c, 0x9f7b}}, + {{0x3e1e4bde, 0x0f34ed97, 0x310a2b1b, 0x394db83a, 0x0fc71fc0, 0x051ad0a6, 0x010f7be3, 0x3de131c1, 0x32f9}}}, + /* 13*16^28*G: */ + {{{0x1dfe1d2b, 0x19527230, 0x16878e51, 0x24fd4279, 0x3b73a4c4, 0x332b7f4f, 0x048e3e76, 0x10fa72dd, 0xd58a}}, + {{0x0cd50922, 0x33c9e56e, 0x0bd6fbff, 0x366e8857, 0x28276b54, 0x1ca44ca0, 0x083cf10a, 0x219ae816, 0xfc17}}}, + /* 15*16^28*G: */ + {{{0x249c795e, 0x090546f8, 0x1ce805e1, 0x1101aaa6, 0x27ea4eed, 0x365a70f0, 0x18310cd6, 0x1c4e5c44, 0x21d2}}, + {{0x19208ece, 0x0004bb0e, 0x2dfb761b, 0x1c651292, 0x2bb4c3d6, 0x0d6e1548, 0x1acea177, 0x3e6d2c1d, 0x94c5}}} + }, + { + /* 1*16^29*G: */ + {{{0x23c0df5d, 0x06845de3, 0x156a792f, 0x067bfed4, 0x1d7fab20, 0x2b6ae51d, 0x3b33a7d8, 0x3a851107, 0xe80f}}, + {{0x2ac9ec78, 0x32d0a46d, 0x3322ea9f, 0x0557a02b, 0x0a94472d, 0x25da328f, 0x200771e8, 0x379fd8e3, 0xeed1}}}, + /* 3*16^29*G: */ + {{{0x17592d55, 0x300d67b3, 0x0e350192, 0x356e51d0, 0x3ce3b106, 0x3fbda58c, 0x1052608a, 0x31b6f128, 0x5d2e}}, + {{0x2f5183a7, 0x19b9743a, 0x11151742, 0x0a9ef36b, 0x0cd6950e, 0x1c43e89a, 0x245eb58f, 0x337e271b, 0x0a92}}}, + /* 5*16^29*G: */ + {{{0x3e8f9f5c, 0x247d2d27, 0x1880a519, 0x187c7856, 0x1f404d73, 0x32b8d085, 0x3f742fe2, 0x0770ec46, 0xac37}}, + {{0x325a503c, 0x1ea0ffcc, 0x2751e1d1, 0x254d163b, 0x14e73522, 0x04079cc9, 0x1a477ff2, 0x05b061c2, 0xc516}}}, + /* 7*16^29*G: */ + {{{0x19e33446, 0x12872354, 0x2af385df, 0x224ef114, 0x22a17a40, 0x2302f408, 0x1840c934, 0x000e853c, 0x8942}}, + {{0x26387689, 0x034e2803, 0x1e74f984, 0x3f5dcd9e, 0x3de4e06b, 0x2cb5b43b, 0x1077a4d8, 0x00e56569, 0xa9fd}}}, + /* 9*16^29*G: */ + {{{0x3913cb26, 0x35ca3256, 0x13bd6d03, 0x3ad06700, 0x105c9899, 0x36913fd5, 0x342a8a2c, 0x099acc28, 0x2770}}, + {{0x3348a7a2, 0x3f9c5ccf, 0x0815bebb, 0x103246f3, 0x32b324e9, 0x0b49341f, 0x0db1a555, 0x2f179e6c, 0xf649}}}, + /* 11*16^29*G: */ + {{{0x195e8247, 0x02aa8085, 0x286cd1af, 0x2ff71155, 0x38ba9097, 0x179b8073, 0x3ed2178e, 0x3434e0f2, 0x75e4}}, + {{0x19982d22, 0x288ff675, 0x29ad893c, 0x36ad6dba, 0x3726d47d, 0x3e5c3b1e, 0x10990741, 0x10a85d50, 0x1fce}}}, + /* 13*16^29*G: */ + {{{0x26333323, 0x11e7d136, 0x0f4abf47, 0x2eef071a, 0x04da849c, 0x08358166, 0x1bbf03f0, 0x2d8e0cd8, 0x3ed1}}, + {{0x35d61ba3, 0x2c4ff122, 0x378f7294, 0x2dca2842, 0x0f929ea9, 0x1f2625a2, 0x34ee75d9, 0x0b6922d6, 0xd84f}}}, + /* 15*16^29*G: */ + {{{0x333980bf, 0x09415f52, 0x0dd00baf, 0x28dc0b94, 0x08dd4368, 0x1bf5dc8d, 0x18181b84, 0x34bc1a9d, 0x70fd}}, + {{0x20b75785, 0x0bbaa33a, 0x1d74a561, 0x040d60e1, 0x2e596b0a, 0x29043447, 0x18696957, 0x32b03435, 0x5edf}}} + }, + { + /* 1*16^30*G: */ + {{{0x04e16070, 0x3701eef3, 0x2fd6915d, 0x286080c7, 0x167543f2, 0x29239475, 0x1704313b, 0x1a5ef7f3, 0xa301}}, + {{0x1e177ea1, 0x30346810, 0x0a11a130, 0x0d76fdf0, 0x140f9b17, 0x2027e897, 0x3e4f5081, 0x3e473ed9, 0x7370}}}, + /* 3*16^30*G: */ + {{{0x138011fc, 0x1c049c00, 0x17285626, 0x165a99eb, 0x200a4d83, 0x2c4cc208, 0x1eb11156, 0x04e8c205, 0x6e83}}, + {{0x3f15ab7d, 0x2b2da7e8, 0x1c51f9a6, 0x2be456ba, 0x1ac30426, 0x04b6c807, 0x0f204c1a, 0x2062f709, 0xc147}}}, + /* 5*16^30*G: */ + {{{0x100e6ba7, 0x0e9d26e3, 0x0916f7f5, 0x0dbb16d1, 0x19e1b43d, 0x0780e293, 0x0851f2bd, 0x2a4265e1, 0xf952}}, + {{0x0175e4c1, 0x36ebbb94, 0x062a2b98, 0x15c59ed3, 0x3fa0f655, 0x0dda8b89, 0x3cebf861, 0x0e96c22a, 0xd8a9}}}, + /* 7*16^30*G: */ + {{{0x03aa0e93, 0x2401968a, 0x2fb1f626, 0x0b8e50eb, 0x1e893a8f, 0x00c68676, 0x3fee7504, 0x1b578c74, 0x9401}}, + {{0x07addac2, 0x23bb49a2, 0x257b07a3, 0x210dceea, 0x2e6fd7f4, 0x1574d53b, 0x14d96403, 0x0cbb9711, 0x6750}}}, + /* 9*16^30*G: */ + {{{0x0266b17b, 0x03d218b8, 0x262bb32b, 0x0d5a2880, 0x1f09c202, 0x25e211aa, 0x3b2891bb, 0x345d3567, 0xef22}}, + {{0x39dac83e, 0x0a9b810d, 0x1c341b73, 0x39c9dbdc, 0x34a1073e, 0x27330eb8, 0x24c7568f, 0x21325eac, 0xbc57}}}, + /* 11*16^30*G: */ + {{{0x12d382a0, 0x0c4c056a, 0x2ecd9ae2, 0x2372ef38, 0x2df927f2, 0x2b31e02c, 0x3892d39c, 0x3bf3933a, 0xb5f7}}, + {{0x25b4b532, 0x28bc2aee, 0x1acf8c5b, 0x3ec25b4a, 0x0bddd371, 0x255f1b83, 0x3f2353c0, 0x1516d470, 0x6843}}}, + /* 13*16^30*G: */ + {{{0x012cffa5, 0x39a49191, 0x28cc5c47, 0x3b508219, 0x14624389, 0x1d5363ef, 0x31076408, 0x30f4acb9, 0x1cdd}}, + {{0x1521954e, 0x379b6273, 0x336b528a, 0x0726109a, 0x02b08ac4, 0x2c49afe5, 0x1f8a63fd, 0x1a832cbc, 0x1e47}}}, + /* 15*16^30*G: */ + {{{0x34a9f22f, 0x0d7f90e4, 0x17a8e2ad, 0x02067148, 0x0835b0cc, 0x3e2e2e52, 0x0e939f21, 0x2cd67c97, 0x2acc}}, + {{0x375c4927, 0x2dd772ce, 0x1ba550b7, 0x12f5efb1, 0x30edf115, 0x04e8dfb7, 0x2d2e5192, 0x293a5622, 0xd518}}} + }, + { + /* 1*16^31*G: */ + {{{0x3fb04ed4, 0x2deb18f8, 0x1307fffa, 0x330cc2c4, 0x278de208, 0x3e741449, 0x2b936463, 0x216ce275, 0x90ad}}, + {{0x0b6ef150, 0x24753523, 0x182894d9, 0x2bbeaf85, 0x3222b839, 0x372f6509, 0x38261aff, 0x1e8d8828, 0x0e50}}}, + /* 3*16^31*G: */ + {{{0x30b7b678, 0x09d76cce, 0x0f638166, 0x0f10c46f, 0x2b6c76f1, 0x21af2909, 0x0231ba19, 0x125ccd39, 0x186e}}, + {{0x38d91fc1, 0x1e81dbcb, 0x09535dca, 0x01dc8951, 0x37e67e11, 0x3f209702, 0x3bd84aa7, 0x18392601, 0xc0d4}}}, + /* 5*16^31*G: */ + {{{0x33421fb8, 0x3c1b972e, 0x35a55d0c, 0x125c7cbb, 0x37241298, 0x01acd30e, 0x1bf62e7e, 0x2360d3db, 0x061c}}, + {{0x0e3ccd80, 0x257bd9a1, 0x26fcdd29, 0x19c4d2ce, 0x05eb5c80, 0x0e496438, 0x3b4b7ba9, 0x1ab66400, 0x6dfc}}}, + /* 7*16^31*G: */ + {{{0x2f6b35a4, 0x0492f862, 0x327fb487, 0x27cde9aa, 0x3a68ad88, 0x18c901cc, 0x2e513b73, 0x2d8e8823, 0xf6a6}}, + {{0x01f422a6, 0x2badbfb2, 0x1ee1862c, 0x355d5b9d, 0x20186f19, 0x34dc13d5, 0x1138b1ca, 0x322a000b, 0x3df7}}}, + /* 9*16^31*G: */ + {{{0x26954c11, 0x25a08fa2, 0x160d018b, 0x2a290f05, 0x0778ff7f, 0x346c3c54, 0x2c376220, 0x3f0a30a1, 0x87a2}}, + {{0x272a8b45, 0x15b8ccb8, 0x278124b7, 0x1224cfca, 0x127532cc, 0x06523683, 0x2ecef97b, 0x1462d16a, 0x33ad}}}, + /* 11*16^31*G: */ + {{{0x22706ab6, 0x391d1cab, 0x2e53c0da, 0x02cd0774, 0x384cfe3c, 0x15bbf2f0, 0x081a6845, 0x0b811b9e, 0xe147}}, + {{0x1d58de05, 0x1ba1a85a, 0x13cd2753, 0x16275551, 0x0621f8aa, 0x1a465e32, 0x18fc683f, 0x24aa91f1, 0x82cd}}}, + /* 13*16^31*G: */ + {{{0x07a84fb6, 0x2feb9508, 0x3a15021e, 0x08da1d43, 0x08b9ebc4, 0x2d358079, 0x0aef5de8, 0x24b2013e, 0x1caf}}, + {{0x27149109, 0x1ac60640, 0x22ce6761, 0x07305a5a, 0x101622ec, 0x2993e3fc, 0x2e53a481, 0x2e16b25d, 0xbc24}}}, + /* 15*16^31*G: */ + {{{0x0a955911, 0x1da33f85, 0x0ded52db, 0x1f85a898, 0x17839710, 0x27bfa6cf, 0x1650d258, 0x3f5a6bc2, 0x705b}}, + {{0x3fd200e4, 0x2edf1a4f, 0x242e72d8, 0x1fced48a, 0x0051fa29, 0x18f607d5, 0x3f990a7e, 0x2904c2dc, 0xe14a}}} + }, + { + /* 1*16^32*G: */ + {{{0x1ec4c0da, 0x2ded1132, 0x23ea3351, 0x23159e1c, 0x1f162ee8, 0x2706b660, 0x35f33923, 0x2e74bd8e, 0x8f68}}, + {{0x101fff82, 0x08f2fde5, 0x1510bfdf, 0x3a8b3fa5, 0x3e215dbb, 0x36430ada, 0x23986de1, 0x27cb6e81, 0x662a}}}, + /* 3*16^32*G: */ + {{{0x123809fa, 0x238ae3b7, 0x1d954be1, 0x21172cd4, 0x051f08fd, 0x24cd8fc9, 0x09f228ba, 0x076f8b94, 0x3838}}, + {{0x331fed52, 0x35c1d460, 0x2d8f24db, 0x207f32cc, 0x0eb1cc36, 0x10169548, 0x117dcb09, 0x0b4283ee, 0xe4a3}}}, + /* 5*16^32*G: */ + {{{0x17c2a310, 0x3a909922, 0x01226303, 0x21aba950, 0x0699a1f1, 0x086e0aa9, 0x32ae6f69, 0x09c9390d, 0x4926}}, + {{0x1e27ded0, 0x3106da05, 0x35ff8ce0, 0x058d84a9, 0x14303b6d, 0x33e95a5c, 0x3abf95a2, 0x39dcef29, 0x1337}}}, + /* 7*16^32*G: */ + {{{0x0ebd2d31, 0x0e12c1e7, 0x306db8d1, 0x330695bf, 0x37e2f84d, 0x094ecf91, 0x00c90d5e, 0x15a30689, 0xe306}}, + {{0x12546e44, 0x24ad020e, 0x23738266, 0x2f2010af, 0x3d0db6ff, 0x3cac41fd, 0x34260888, 0x1bf8de24, 0x0eac}}}, + /* 9*16^32*G: */ + {{{0x363136b0, 0x14c30e78, 0x2b41dd9c, 0x3afe366a, 0x3bd63374, 0x2c39d88f, 0x0cefc271, 0x0403890a, 0x3b9e}}, + {{0x2cdbbc8a, 0x14fb05bd, 0x2d31f819, 0x2b8a28ce, 0x075b26a2, 0x14cfae3d, 0x2bb71df1, 0x26054b45, 0xfafb}}}, + /* 11*16^32*G: */ + {{{0x2f485d3f, 0x1823c11c, 0x107beee9, 0x3281da20, 0x1edef717, 0x1b2a03d7, 0x2c9a92b7, 0x2b525c4a, 0xbb0a}}, + {{0x3ca2f975, 0x1e4e4940, 0x1670bffe, 0x1696be8c, 0x17da3489, 0x34807dca, 0x354798ec, 0x2714f160, 0xea69}}}, + /* 13*16^32*G: */ + {{{0x36718dc9, 0x2bbb4ce8, 0x01123de4, 0x3962d36c, 0x3e0113e1, 0x23ac65eb, 0x2fcc0d4e, 0x02b2393b, 0x7909}}, + {{0x1cfae7c5, 0x18cc8ac4, 0x3a9008b9, 0x0dabedc2, 0x1aaa56dd, 0x205b2f36, 0x05b8f13d, 0x1c8ae464, 0xeaab}}}, + /* 15*16^32*G: */ + {{{0x3f60c7d1, 0x09a5a531, 0x1775ad2a, 0x35c779f3, 0x09ba668d, 0x0f6ef395, 0x17b551c0, 0x206b7a7e, 0xe77c}}, + {{0x02d72449, 0x3b1607ca, 0x02986d34, 0x051c3dc7, 0x28154363, 0x30ecc8fa, 0x01321c5f, 0x051e3bbe, 0x3acf}}} + }, + { + /* 1*16^33*G: */ + {{{0x13231e11, 0x1a1bf541, 0x3681e3e6, 0x123a1940, 0x0c36091f, 0x267fe466, 0x385d65ff, 0x3ec05dab, 0xe4f3}}, + {{0x2feb73bc, 0x08b0e15d, 0x151d1c98, 0x31f9d3b2, 0x02b7286c, 0x069b43a8, 0x34f1c166, 0x18ceb43b, 0x1e63}}}, + /* 3*16^33*G: */ + {{{0x2bf05bd6, 0x0e67c139, 0x12a99465, 0x3d5b80c8, 0x070deca2, 0x0bd47fad, 0x04fe9083, 0x0c906fb9, 0x900c}}, + {{0x300d358b, 0x394ab4ef, 0x04efb15d, 0x2614d60f, 0x0b2439d6, 0x31c8115c, 0x1f0f5f95, 0x3e7a3a2c, 0x6c31}}}, + /* 5*16^33*G: */ + {{{0x1f105c50, 0x29f0a332, 0x31385257, 0x3837bbde, 0x0233cd82, 0x2330d00f, 0x190aad62, 0x00d8aac1, 0x5a8d}}, + {{0x38a4cde9, 0x326c8060, 0x2d013c35, 0x017da299, 0x03ff74a6, 0x29adc905, 0x0e536936, 0x3aac44f5, 0xc059}}}, + /* 7*16^33*G: */ + {{{0x32d64feb, 0x11f862e6, 0x292292c6, 0x1cbe2964, 0x0ba4e837, 0x3ce95ddb, 0x2f60a48e, 0x1340c48c, 0xd93f}}, + {{0x34698359, 0x2c3ef564, 0x2c90da37, 0x3810c2fb, 0x1c8c4d93, 0x1cc47153, 0x32733a23, 0x15575172, 0x7925}}}, + /* 9*16^33*G: */ + {{{0x039fbc84, 0x08881335, 0x057a0167, 0x1c18a458, 0x2ac65b7e, 0x138af198, 0x328441b1, 0x1a71b8db, 0x2f07}}, + {{0x1c201bec, 0x3ee40b78, 0x04dd5d73, 0x29e6da93, 0x0e2149cc, 0x37c01e64, 0x3bdddfa5, 0x3cdc935c, 0xb434}}}, + /* 11*16^33*G: */ + {{{0x06a758ea, 0x14dfab32, 0x27f19c4d, 0x0620c624, 0x016e3991, 0x1a256855, 0x20309958, 0x19e01567, 0xfe7e}}, + {{0x1b7ab649, 0x13c8b657, 0x03120d1e, 0x2005c1d1, 0x09251f3b, 0x02385a61, 0x1dcb988c, 0x1a59e8a0, 0x38aa}}}, + /* 13*16^33*G: */ + {{{0x0cfffefa, 0x39c5589a, 0x0651afad, 0x060113dc, 0x03af8510, 0x3dbe4543, 0x03127d6d, 0x3d729d4e, 0x91ba}}, + {{0x1f7f6faf, 0x1f4dbcd3, 0x2fd303dc, 0x2fbcc439, 0x1d3d92f4, 0x25a7c49f, 0x3bcebe5d, 0x33c464d1, 0x04e5}}}, + /* 15*16^33*G: */ + {{{0x0d33c546, 0x3f0245fa, 0x05edaf32, 0x15d7ecca, 0x35ddd782, 0x314dcf83, 0x378a7cb2, 0x104872cf, 0x4458}}, + {{0x000b4fd4, 0x029b461c, 0x32ca7366, 0x0bc28f3e, 0x1ada2085, 0x097ab8e4, 0x0753a772, 0x24ddfcfe, 0x308d}}} + }, + { + /* 1*16^34*G: */ + {{{0x20eae29e, 0x1bedbab8, 0x14e1d071, 0x00d3cbc3, 0x1a4266c7, 0x1854de91, 0x3f331eb9, 0x3ea6c63a, 0x8c00}}, + {{0x2702414b, 0x1f4a9319, 0x1e36c54e, 0x3eb6bea0, 0x36c974c2, 0x30d0e8dc, 0x121a1a9d, 0x1c99ffa9, 0xefa4}}}, + /* 3*16^34*G: */ + {{{0x2bfd913d, 0x0fe5580f, 0x254c9eac, 0x29a039bb, 0x2a8d2050, 0x01e82130, 0x3ddf874d, 0x0aa9fa41, 0x3636}}, + {{0x052e243d, 0x113e6bab, 0x2b2faafc, 0x0c2ec435, 0x1a2a82d8, 0x18910dc3, 0x0afd5341, 0x1e19db2e, 0x48f2}}}, + /* 5*16^34*G: */ + {{{0x2d132896, 0x32aeafe6, 0x3bc6c967, 0x2c78eead, 0x19200dfc, 0x16b658b7, 0x21e02f29, 0x25db7cca, 0x4487}}, + {{0x2f685248, 0x23006c4a, 0x276aa7a4, 0x2d035698, 0x161a3306, 0x26a41dd1, 0x1afe1efc, 0x16183445, 0x27bd}}}, + /* 7*16^34*G: */ + {{{0x3fa2670c, 0x02055bda, 0x06273e6e, 0x003e0ae8, 0x35032474, 0x2a72aa0c, 0x383788b6, 0x0eb0a2f2, 0x4a4d}}, + {{0x16c1764d, 0x022e7ff7, 0x329beed8, 0x0c16532f, 0x302b9d49, 0x1dc4777b, 0x05a4f17e, 0x2e470061, 0x70ab}}}, + /* 9*16^34*G: */ + {{{0x0cb24aa7, 0x365abf89, 0x1345c530, 0x0c42318e, 0x38fe1890, 0x39bf627f, 0x11802c3a, 0x0b4642ba, 0x5f7b}}, + {{0x0a693d7d, 0x35e01d0d, 0x3c81d0c6, 0x237adc24, 0x267c47ce, 0x0fe028f3, 0x1f2b330a, 0x0d80313f, 0x0770}}}, + /* 11*16^34*G: */ + {{{0x2f7fb8bd, 0x0646f17c, 0x3e4090a4, 0x31192857, 0x0886d87b, 0x30939b65, 0x190d02ae, 0x1d144ce7, 0x5139}}, + {{0x03908c0f, 0x0252b0b6, 0x3f98d5a8, 0x3f0cb4f8, 0x015c47fa, 0x23fbf6ba, 0x03bf34b8, 0x050f91d9, 0xfcd7}}}, + /* 13*16^34*G: */ + {{{0x2e36ca73, 0x0add2457, 0x3bbf3ede, 0x321934da, 0x014887ea, 0x0a444afc, 0x3dfb8aa4, 0x05b58afe, 0xcf83}}, + {{0x2ec25534, 0x2d248650, 0x08d710f5, 0x25856636, 0x1cca681c, 0x11142243, 0x19d73e38, 0x2d637ad7, 0x09fe}}}, + /* 15*16^34*G: */ + {{{0x3752f97d, 0x3224df5a, 0x33476613, 0x0bbef1d7, 0x0fa6165a, 0x274a19a3, 0x3b49de53, 0x37a69312, 0x8610}}, + {{0x1f1b1af2, 0x015f7350, 0x05543e08, 0x2ad367d5, 0x33f99e57, 0x33666c94, 0x30bbc937, 0x25e80ad8, 0xd319}}} + }, + { + /* 1*16^35*G: */ + {{{0x20cb3e41, 0x25ff77f1, 0x08b92c09, 0x0f4213cc, 0x298ed314, 0x033b02a7, 0x0829f3e1, 0x1b39a775, 0xe7a2}}, + {{0x0f2cfd51, 0x3a2a5087, 0x20e83e20, 0x29acb010, 0x2fbb18d0, 0x2c01a86a, 0x3984b471, 0x238c03e9, 0x2a75}}}, + /* 3*16^35*G: */ + {{{0x3aee42db, 0x03e7f4af, 0x330714a7, 0x2eef16d1, 0x2cbfc1d9, 0x2dbb6e47, 0x19150fc7, 0x09f9f66d, 0xcc34}}, + {{0x15d87bdb, 0x188a7004, 0x272422dc, 0x3972eb63, 0x21520010, 0x38ff4fec, 0x1c6a1885, 0x26106948, 0xea24}}}, + /* 5*16^35*G: */ + {{{0x3ed4a086, 0x3d0d9b19, 0x29c410ef, 0x35d70563, 0x0b5cf4b1, 0x0f1617ef, 0x0445dec8, 0x016eb366, 0x948f}}, + {{0x1e2bca4b, 0x0a86003e, 0x03fa2d1a, 0x08ca29c7, 0x1139411c, 0x11429980, 0x22a3382f, 0x2a27fed6, 0x864c}}}, + /* 7*16^35*G: */ + {{{0x37542c21, 0x032fa9b2, 0x2a64c15c, 0x067d34a3, 0x1d6d43ae, 0x1bf11514, 0x19ac9065, 0x0658a4a4, 0x2584}}, + {{0x272bfabf, 0x2faf8c65, 0x0c2ad7b3, 0x38e861b9, 0x3513d5f3, 0x176a9331, 0x3244801e, 0x16c7c736, 0xfcb3}}}, + /* 9*16^35*G: */ + {{{0x0c1ecbf8, 0x0f1187d0, 0x2eed7ca4, 0x227c37a6, 0x28421f64, 0x25d53307, 0x3c52522a, 0x337104dc, 0x7e12}}, + {{0x30bed615, 0x3516e336, 0x3e1d9f59, 0x1a7d8763, 0x0d1259c9, 0x3e536af9, 0x1c837143, 0x13e22223, 0x7128}}}, + /* 11*16^35*G: */ + {{{0x14557d86, 0x1f999470, 0x2667ff41, 0x3fbb11e3, 0x05a6cf1c, 0x2e4729e8, 0x342a6772, 0x30bfca8d, 0x4b8e}}, + {{0x35167eb9, 0x3766c646, 0x3c3f692b, 0x357cbbc3, 0x27ac5f28, 0x101cb794, 0x157ab14a, 0x30ffc130, 0xfde6}}}, + /* 13*16^35*G: */ + {{{0x0780763c, 0x0ae0b4ed, 0x265691d5, 0x229b57a4, 0x3ac07e5f, 0x10db71a5, 0x23a42532, 0x3041cce5, 0xfcd5}}, + {{0x38e851cb, 0x1539d080, 0x16463a4b, 0x066c8b9c, 0x32e38cb1, 0x0836cd7d, 0x22c463b7, 0x2af8b954, 0x18dd}}}, + /* 15*16^35*G: */ + {{{0x1d8ef686, 0x338ef8c1, 0x2272e66b, 0x23923d00, 0x266e53f6, 0x22976be0, 0x3cbe5223, 0x0b3b9610, 0x900f}}, + {{0x2121a8cf, 0x1ce9259f, 0x09156d50, 0x1b37fd0f, 0x09d11059, 0x31546c4d, 0x0425ad61, 0x30557b18, 0x732a}}} + }, + { + /* 1*16^36*G: */ + {{{0x1e6b80ef, 0x33ca7acf, 0x179424f3, 0x32f2e59f, 0x3cbdc571, 0x1503088e, 0x22ec8d23, 0x2783b8d9, 0xb645}}, + {{0x1a71ba45, 0x0c2fc2d8, 0x0e35b2ff, 0x2ceb9b52, 0x261db3c4, 0x2b7c5b95, 0x3e06de1d, 0x21db41bc, 0x067c}}}, + /* 3*16^36*G: */ + {{{0x319888e9, 0x0e73c9e4, 0x2448a8b4, 0x04ae9afc, 0x2681673d, 0x1834c0a5, 0x3a6e2dde, 0x3a9dceb0, 0x1f90}}, + {{0x2f113b79, 0x1bf7f25f, 0x19522e65, 0x0dd47fb9, 0x2b96a821, 0x054f49c7, 0x2a10e958, 0x0d9f0576, 0x89be}}}, + /* 5*16^36*G: */ + {{{0x3562222c, 0x217bedbc, 0x1e6f2c60, 0x00d11e64, 0x0b52bade, 0x00aeb4cd, 0x3e0ad6e7, 0x39537b7f, 0x13a4}}, + {{0x28200145, 0x32c59a32, 0x1c904c08, 0x3e715deb, 0x209a52d4, 0x2b0be075, 0x2e813b2c, 0x1f539605, 0xc9d6}}}, + /* 7*16^36*G: */ + {{{0x343b46bb, 0x0df93703, 0x2c925254, 0x3b4e98fe, 0x055dbd12, 0x01f01761, 0x0aadd1d4, 0x07afc8cf, 0x6199}}, + {{0x0c20a848, 0x123d6407, 0x12ecd8ef, 0x2a1ca729, 0x3badf11c, 0x3ce1c59b, 0x1e492952, 0x38c23cff, 0x01c5}}}, + /* 9*16^36*G: */ + {{{0x121add3b, 0x396f8f77, 0x1727d8f7, 0x26a513d1, 0x1626118b, 0x0e736c34, 0x3d387490, 0x2ba92de1, 0xea27}}, + {{0x368ce7dd, 0x2d78a476, 0x24e1be71, 0x2c84b5a3, 0x1c2f6278, 0x0f3ac8c9, 0x217de572, 0x3c79b90a, 0xc70f}}}, + /* 11*16^36*G: */ + {{{0x211ff757, 0x3a2be2ed, 0x04c226e6, 0x133a5d07, 0x22b6da9b, 0x0043e2db, 0x3fd54ba9, 0x144d5adf, 0x5946}}, + {{0x094d031a, 0x2299bb2a, 0x3bffe3b2, 0x06ef1edf, 0x0406f996, 0x00e34057, 0x32750042, 0x0d833977, 0x3611}}}, + /* 13*16^36*G: */ + {{{0x236160b5, 0x1d89628d, 0x0e7ebc06, 0x314fc91c, 0x091ec0cc, 0x0ebde5c0, 0x33290e84, 0x1b8e457d, 0x16b2}}, + {{0x18a1dc0e, 0x11897efd, 0x0ba3ef81, 0x0d8eab1c, 0x3654d4e1, 0x190d4918, 0x2ef8bb63, 0x159698c0, 0x060f}}}, + /* 15*16^36*G: */ + {{{0x37b32db8, 0x25934a24, 0x247791f3, 0x07b5d27d, 0x2cea85c9, 0x2850f210, 0x19f931be, 0x14a57115, 0x024b}}, + {{0x2a64f760, 0x25153eaa, 0x05b81a95, 0x2ada0448, 0x1e5be862, 0x38a08731, 0x3309c7b6, 0x3be3d6ff, 0x609f}}} + }, + { + /* 1*16^37*G: */ + {{{0x096943e8, 0x3b683d6d, 0x273c5a5d, 0x1bc7f19f, 0x0f06231d, 0x08d2a846, 0x3b840793, 0x20320a02, 0xd68a}}, + {{0x2b133120, 0x25321099, 0x045295a2, 0x039ee3de, 0x30e28b5b, 0x2c7e45de, 0x186d00c4, 0x2a7ffd2d, 0xdb8b}}}, + /* 3*16^37*G: */ + {{{0x0ca1c4f9, 0x16d0aa86, 0x2b7e2823, 0x13bf8d32, 0x1f16f44f, 0x02e0f698, 0x1728c4c4, 0x3de3c8af, 0x7815}}, + {{0x3778bc15, 0x2ac7a8da, 0x177d1e19, 0x2d0b7985, 0x18c35d5c, 0x24f3cc51, 0x1af6a7dd, 0x007a334e, 0xc1c6}}}, + /* 5*16^37*G: */ + {{{0x2e8c8530, 0x349b870f, 0x38f4d8e6, 0x0b7da07b, 0x2a6c6d51, 0x1df19005, 0x040176e3, 0x1cf3683b, 0xc392}}, + {{0x398446c7, 0x100c3c3d, 0x2eed715c, 0x3b7f2f68, 0x03199850, 0x074e5107, 0x33c8e9d0, 0x2f9095d0, 0x8c41}}}, + /* 7*16^37*G: */ + {{{0x237a26c1, 0x07c902ec, 0x0dbf6a53, 0x1b1b9630, 0x103b2516, 0x0890c707, 0x011b0275, 0x1d11fd61, 0xda31}}, + {{0x2cf74d6f, 0x1460dbb3, 0x3a81525f, 0x1a0db175, 0x19d8b7d3, 0x21059f09, 0x18c69d23, 0x25ee1fd7, 0x753b}}}, + /* 9*16^37*G: */ + {{{0x3739dc49, 0x0ad8a2a4, 0x2f55603d, 0x24e4b699, 0x3f231a23, 0x12b1422f, 0x30e6c106, 0x39b2c0ab, 0x6a4b}}, + {{0x32edd5cf, 0x39a8ae77, 0x14a4a4d3, 0x1f8ad32c, 0x3a8058ab, 0x059b8d83, 0x107597dc, 0x23ea8aa2, 0xf15d}}}, + /* 11*16^37*G: */ + {{{0x06987fac, 0x22fa2831, 0x0a86f679, 0x3243e190, 0x098a3c8b, 0x260980fb, 0x27f1344e, 0x31a7c4eb, 0x01f7}}, + {{0x19174c68, 0x3e479ce0, 0x1f6bc263, 0x1fd77886, 0x1ab6f9cb, 0x040db8ca, 0x1a22de5b, 0x330fcdbf, 0x9d4e}}}, + /* 13*16^37*G: */ + {{{0x36daba4d, 0x34ce86f5, 0x03196261, 0x197ec388, 0x3a2bcb9c, 0x018bb763, 0x3d381cb7, 0x25005d87, 0x557e}}, + {{0x37a52316, 0x04dd286e, 0x243590a5, 0x3a6e3d7e, 0x0cbc86c5, 0x0d73e857, 0x3a7e046d, 0x23ce9807, 0x7a7e}}}, + /* 15*16^37*G: */ + {{{0x29f5341a, 0x0e3d4bfc, 0x29636b80, 0x31e8cb19, 0x3101419c, 0x27503a9e, 0x085a93b2, 0x36a08666, 0x3ada}}, + {{0x2586c6cc, 0x1456024d, 0x05e8fbcb, 0x35b4b96d, 0x2b1017e9, 0x38d6fcda, 0x1369f552, 0x0788a266, 0xbfea}}} + }, + { + /* 1*16^38*G: */ + {{{0x028d3d5d, 0x0256603f, 0x3449cea4, 0x04abae5c, 0x3a30b096, 0x3009c241, 0x0804252d, 0x3b5f7d97, 0x324a}}, + {{0x16ab7c84, 0x19c892be, 0x23328439, 0x084ec31f, 0x2c1f4f19, 0x03030d6b, 0x21f2ff13, 0x0d95dd2d, 0x648a}}}, + /* 3*16^38*G: */ + {{{0x2fd53ed3, 0x17245d60, 0x1a56ccef, 0x0fdd3ee7, 0x1f7c4916, 0x3d82e4c7, 0x372ad5b8, 0x02f56659, 0x2084}}, + {{0x1a7a7132, 0x1c50ff94, 0x0e708998, 0x21f11ce5, 0x3afac254, 0x2f51da9a, 0x18243487, 0x0d25f3b0, 0xf299}}}, + /* 5*16^38*G: */ + {{{0x08a35b35, 0x2f4b2ed6, 0x00a121ed, 0x2d762297, 0x08ebfd1a, 0x0f40a796, 0x339bbbd1, 0x2ffd83ac, 0xe6b6}}, + {{0x1c1007bd, 0x15ca4f6e, 0x3e999c7c, 0x0edb274e, 0x1961ddfe, 0x3d0f8e0d, 0x0d2f3266, 0x3caf4cc0, 0x1a5f}}}, + /* 7*16^38*G: */ + {{{0x00360dd3, 0x353be34b, 0x050e2090, 0x2a2a0db6, 0x0ce3bb47, 0x02e021b8, 0x099b288b, 0x05dd16f9, 0xe053}}, + {{0x3c24f87b, 0x0abb3644, 0x0103dc2b, 0x2e61f7a6, 0x36a01461, 0x02560ad6, 0x12f39cd8, 0x0edc6976, 0xdc1c}}}, + /* 9*16^38*G: */ + {{{0x1098dfea, 0x3051998b, 0x2a678797, 0x372cf24b, 0x3a5e57fa, 0x23974aa0, 0x06c59e01, 0x0ece9de2, 0xa815}}, + {{0x2e6d892f, 0x2926a77d, 0x2daf4158, 0x2d783dd0, 0x053e03b1, 0x236e715e, 0x060fc53d, 0x0e591874, 0x2a47}}}, + /* 11*16^38*G: */ + {{{0x0bcecfa5, 0x29f9de92, 0x316bb020, 0x0358b686, 0x0eda3b2a, 0x11a5718e, 0x0addadeb, 0x30ecc3fb, 0x4f05}}, + {{0x15d37b53, 0x3b34092a, 0x01b48cd2, 0x1fb90c7c, 0x1534b944, 0x18c8d856, 0x1426fadd, 0x267a980f, 0x53a4}}}, + /* 13*16^38*G: */ + {{{0x084b96aa, 0x1879d964, 0x22abcce4, 0x0a618d54, 0x3b980ed0, 0x101786a8, 0x3a91be26, 0x26ae67d9, 0xd930}}, + {{0x02b28a86, 0x09b13cdf, 0x3cfe978f, 0x2db27eeb, 0x34cb5fd3, 0x043c1989, 0x2c557d7e, 0x26caa6d3, 0x6ef9}}}, + /* 15*16^38*G: */ + {{{0x1f8fcf0e, 0x3dee3416, 0x3c4a6fac, 0x16dbff79, 0x2a3411d6, 0x30d11b7a, 0x22d35ba9, 0x1f284e15, 0x7d58}}, + {{0x18bc9459, 0x00706827, 0x323780a5, 0x18e402b4, 0x3d6ad0c4, 0x0d002db3, 0x04c61272, 0x1700e20c, 0xa729}}} + }, + { + /* 1*16^39*G: */ + {{{0x3d054c96, 0x3a2f4dcf, 0x0d1ca888, 0x31050eea, 0x3ee5dcee, 0x077f6f97, 0x1e61f6d5, 0x30524673, 0x4df9}}, + {{0x0ad10d5d, 0x0baeb01b, 0x28849019, 0x3541b370, 0x1d85d4b5, 0x25d308e8, 0x18728050, 0x3b14424b, 0x0035}}}, + /* 3*16^39*G: */ + {{{0x1def001d, 0x13c89769, 0x09ba27ef, 0x3e6ef5a6, 0x23b64b21, 0x02f47027, 0x22caf20e, 0x28cb6c9f, 0xa549}}, + {{0x30624783, 0x3576c69f, 0x2c9705ad, 0x05078a98, 0x259456eb, 0x330c3b62, 0x166cbdf4, 0x1e9e41b6, 0x799b}}}, + /* 5*16^39*G: */ + {{{0x052ed4cb, 0x16bbc797, 0x009ec5a0, 0x1537becf, 0x132e6ec9, 0x022f660d, 0x3ecd123f, 0x23cc3681, 0x7e79}}, + {{0x14bb9462, 0x15c5981e, 0x39f37a12, 0x1cd5c6ff, 0x32f057b1, 0x2a55277b, 0x1ac83041, 0x33312893, 0xd23d}}}, + /* 7*16^39*G: */ + {{{0x13630834, 0x37ce83ef, 0x3dac067f, 0x18fc4a18, 0x0c810884, 0x2e7a5aea, 0x14783ad5, 0x28800c54, 0x224f}}, + {{0x047a2272, 0x34f11cdf, 0x0a50f75c, 0x18a493b0, 0x1d09f53d, 0x2dc3e8e4, 0x2da5c3c4, 0x138caecf, 0xbbe5}}}, + /* 9*16^39*G: */ + {{{0x183c19d7, 0x19d92745, 0x02cf57bb, 0x2ed7916b, 0x228ef2bb, 0x28973390, 0x239e4129, 0x28331802, 0xc2d4}}, + {{0x0507928d, 0x0bca2e0b, 0x3345c977, 0x2012a0c5, 0x01260d26, 0x20ed7dfd, 0x06294d41, 0x283e7020, 0x65ad}}}, + /* 11*16^39*G: */ + {{{0x3c940c9a, 0x13202b52, 0x2f423308, 0x33cf384e, 0x0ddc2113, 0x161789d1, 0x1f3190e5, 0x0a9fb0c1, 0x2ec2}}, + {{0x051e7a4d, 0x34653f66, 0x1a35bdac, 0x101460f6, 0x1c7feb12, 0x3893d40a, 0x379684c2, 0x291a378c, 0x8b1d}}}, + /* 13*16^39*G: */ + {{{0x1d683eeb, 0x29c3b97f, 0x08d3133a, 0x0dbace28, 0x04b8f33e, 0x2bd94942, 0x28cecab1, 0x1a5ce3e6, 0xafc6}}, + {{0x30cd4509, 0x078a72ac, 0x1eddfdc9, 0x02ead549, 0x239c1657, 0x1671ff28, 0x22752bc3, 0x0865db74, 0x002c}}}, + /* 15*16^39*G: */ + {{{0x376f4293, 0x28807e1e, 0x13c5139e, 0x3a5e2d59, 0x0b282e10, 0x2f233cdc, 0x03309121, 0x1ed6a7cd, 0xd255}}, + {{0x1282740a, 0x36c61e89, 0x2405a5f1, 0x12da0e37, 0x0ad21fe3, 0x20bc1bad, 0x027f0126, 0x2cd0d579, 0xa787}}} + }, + { + /* 1*16^40*G: */ + {{{0x2c1f98cd, 0x2ff26722, 0x17f0308c, 0x0d224153, 0x06602152, 0x362a7073, 0x34870fae, 0x066a1291, 0x9c39}}, + {{0x14fc599d, 0x39f9780f, 0x064c8e6b, 0x14c9bddb, 0x20e64190, 0x3c112fc9, 0x1dd57584, 0x13c3d293, 0xddb8}}}, + /* 3*16^40*G: */ + {{{0x0fb64db3, 0x1ee6354e, 0x1dd53841, 0x3b79328e, 0x13b8d6a7, 0x2ee0fef9, 0x1ccb740b, 0x08e48a6f, 0xc114}}, + {{0x3c0259be, 0x08c33a7f, 0x14567d1e, 0x1d602413, 0x178bd1a8, 0x3b3793fa, 0x06fc2a5c, 0x3db716d2, 0x1237}}}, + /* 5*16^40*G: */ + {{{0x03081e46, 0x3b7b60d0, 0x14559ea1, 0x14886315, 0x2634713a, 0x3670b064, 0x37224082, 0x12fe0c69, 0x6c5b}}, + {{0x0bfbcd70, 0x347e72e0, 0x2c22a62e, 0x3433e09a, 0x2be47841, 0x11e18f38, 0x2d42fb23, 0x04dc5249, 0xcb05}}}, + /* 7*16^40*G: */ + {{{0x064dcd4b, 0x32b96bb1, 0x111c124d, 0x0c31f566, 0x310a450c, 0x1c19972a, 0x0ade4b56, 0x2a1599c3, 0xe1e9}}, + {{0x3b041f2c, 0x342d897a, 0x0a16b292, 0x113466ab, 0x2577927f, 0x310d666c, 0x1c531b7a, 0x02a55115, 0x562b}}}, + /* 9*16^40*G: */ + {{{0x2badd73c, 0x0161dbf8, 0x2a64b7d0, 0x36737640, 0x1c14208f, 0x29d390bb, 0x1b099778, 0x0695eb44, 0x51b2}}, + {{0x2b36d8d1, 0x3df52b87, 0x0c734ba6, 0x0804c3ca, 0x2c1cfa6c, 0x281fc074, 0x3d3e5d54, 0x0c040007, 0x0079}}}, + /* 11*16^40*G: */ + {{{0x3b09f34b, 0x35d742dc, 0x0cc66ce6, 0x221cf982, 0x339d61e5, 0x2d8a5bcf, 0x0b79861a, 0x3ce98ec7, 0x9701}}, + {{0x00df5793, 0x33721433, 0x3dcc794a, 0x012f0e5f, 0x16833771, 0x00c6d4c5, 0x30ed15d7, 0x12eee32b, 0x3dd4}}}, + /* 13*16^40*G: */ + {{{0x3f1e2f46, 0x1739888e, 0x32778301, 0x1c3dc7a1, 0x163c5752, 0x164b8103, 0x266cc445, 0x2d074b27, 0xa036}}, + {{0x1effb349, 0x1cc789a5, 0x3f0b1f4f, 0x2038a0b3, 0x1eb08d06, 0x07daa91e, 0x16b3d7df, 0x246800fa, 0xc3bf}}}, + /* 15*16^40*G: */ + {{{0x0c4cea08, 0x3362e40e, 0x20ea21db, 0x12d62e83, 0x00465265, 0x298454d0, 0x28c506f4, 0x3eb6ea93, 0x6a85}}, + {{0x1862f4f3, 0x0677b396, 0x3d721b6a, 0x09c692d0, 0x3e6230b4, 0x24cf0523, 0x0659d531, 0x11812eb9, 0x00b6}}} + }, + { + /* 1*16^41*G: */ + {{{0x20a959e5, 0x2884e084, 0x391d4cc5, 0x38524ea2, 0x0e06bb91, 0x017ca076, 0x12fdf8de, 0x05c2c774, 0x6057}}, + {{0x2385a2a8, 0x2266fa4c, 0x2e24c65e, 0x1454af0f, 0x1df26246, 0x268b6bdc, 0x24807add, 0x3c2c9a9a, 0x9a1a}}}, + /* 3*16^41*G: */ + {{{0x171c032b, 0x3536858a, 0x3afdc980, 0x1ad9a285, 0x0766c5ff, 0x046d7f7f, 0x002603dd, 0x2a3f35b8, 0x71eb}}, + {{0x1668359f, 0x1ead6a38, 0x34b4755e, 0x24c6b45d, 0x0cbb7f71, 0x18145bd5, 0x1d39def6, 0x049892d8, 0xd2ff}}}, + /* 5*16^41*G: */ + {{{0x2a03a61c, 0x01b91d14, 0x1070574d, 0x1e1a3d1a, 0x2a9dd050, 0x05d10aea, 0x09d232ca, 0x30c16cc9, 0x855e}}, + {{0x065dfc07, 0x37f1baab, 0x17e44965, 0x0cbdd3a8, 0x02fb4ed3, 0x0f2ffe6d, 0x01c17f54, 0x174bb17c, 0x0dd8}}}, + /* 7*16^41*G: */ + {{{0x1f32d706, 0x00302920, 0x06a0678b, 0x0633291d, 0x15bfa206, 0x034a68c2, 0x3fbf1f15, 0x121aaeac, 0x3ce4}}, + {{0x3c7fd9e4, 0x02dcd8df, 0x161e89f4, 0x345590f3, 0x094906ed, 0x3f411ac4, 0x3785288e, 0x10236ab8, 0xe775}}}, + /* 9*16^41*G: */ + {{{0x391cd3fb, 0x36d032ed, 0x329be686, 0x0a8cff65, 0x0844eb4a, 0x380c863e, 0x237faf02, 0x31450fd3, 0x11cc}}, + {{0x15160d86, 0x24dc5ae9, 0x0dd3472a, 0x02c7bf4b, 0x0cc239fa, 0x2389124e, 0x311deb52, 0x1acaa40a, 0x4aa5}}}, + /* 11*16^41*G: */ + {{{0x218f7552, 0x21ee4465, 0x0054fac3, 0x1044e2e6, 0x2382ddbd, 0x25ddd3e0, 0x09c6f43b, 0x2ec5f945, 0x0250}}, + {{0x3510b14d, 0x3c212588, 0x33d6f1e3, 0x001bcf0c, 0x29d817da, 0x35f7dd7f, 0x28082342, 0x0c3f26ef, 0x7319}}}, + /* 13*16^41*G: */ + {{{0x1f725d12, 0x1744fa4e, 0x0b5f4750, 0x1190aef7, 0x022fbfd9, 0x28e73828, 0x27fd3ab4, 0x27222cd1, 0x1a74}}, + {{0x23ac56e4, 0x04d94534, 0x190daa70, 0x1c821a62, 0x2f3d8f60, 0x22f9d70a, 0x00e2cf45, 0x34655cfb, 0x7e91}}}, + /* 15*16^41*G: */ + {{{0x29fae458, 0x18412394, 0x26ec97fd, 0x0297109d, 0x3b7b328b, 0x3455a977, 0x0218c109, 0x1a16f83e, 0xc750}}, + {{0x1757b598, 0x005a1065, 0x35951a2b, 0x1772940c, 0x32c7b40a, 0x0bd05319, 0x21e05fb5, 0x257e33e4, 0xead7}}} + }, + { + /* 1*16^42*G: */ + {{{0x2cb94266, 0x069a5cfb, 0x3d4df12b, 0x33bc3ee9, 0x0da31880, 0x10e69146, 0x08411421, 0x37e388e8, 0xa576}}, + {{0x21b28ec8, 0x3a2f846b, 0x114d9f3e, 0x0b8429fd, 0x0cd82c43, 0x2e5ebf96, 0x240b2c92, 0x2fc839d9, 0x40a6}}}, + /* 3*16^42*G: */ + {{{0x0d9ed6c1, 0x1a2bad63, 0x3d593d6b, 0x139d16f0, 0x1edd0ec2, 0x3f061dc1, 0x0f53e80b, 0x0cdb72dd, 0x0328}}, + {{0x38fafeee, 0x3b1baf9b, 0x1cb494ad, 0x16fd37c9, 0x0d7c8c26, 0x35650e88, 0x19f28c46, 0x260e04bf, 0x71a8}}}, + /* 5*16^42*G: */ + {{{0x3235983a, 0x066a6a34, 0x13bceb29, 0x22840dc0, 0x3e1531e3, 0x0e49b5c3, 0x11c54dc6, 0x13aba2e4, 0xce4f}}, + {{0x0d3cdecf, 0x33f5ac64, 0x2bf740ae, 0x1b1948a3, 0x30754352, 0x37809279, 0x0fbbb3ea, 0x3e5cf0e4, 0xf3c9}}}, + /* 7*16^42*G: */ + {{{0x15b0e6c9, 0x1b6aad99, 0x06e4c89a, 0x17fe73de, 0x38bcbddb, 0x0a3ecdb7, 0x0622278e, 0x2fe952e6, 0x4dbe}}, + {{0x1eb2cc25, 0x2529e155, 0x0504efae, 0x24c46caf, 0x2229f358, 0x2989b9b8, 0x13aedf45, 0x39ec0f24, 0x10fe}}}, + /* 9*16^42*G: */ + {{{0x25857295, 0x13806846, 0x3433f016, 0x32391fc0, 0x1ca12069, 0x38463f28, 0x05c218b2, 0x0902ffbd, 0xa42a}}, + {{0x0a7eb9c1, 0x1acddffb, 0x15193955, 0x28708b34, 0x1da4c427, 0x1ac8ac93, 0x05d4567a, 0x2cfc9840, 0x3aa0}}}, + /* 11*16^42*G: */ + {{{0x2fcdc098, 0x0883fd55, 0x2e468032, 0x02b803da, 0x0499c155, 0x3c7e1b03, 0x322267a7, 0x0acbe5be, 0x34e1}}, + {{0x2a7474e2, 0x132c6b79, 0x19883f66, 0x37d44c3c, 0x3972db04, 0x132f2105, 0x1d322d97, 0x30b775ed, 0xa64a}}}, + /* 13*16^42*G: */ + {{{0x0f173b92, 0x335bad7a, 0x29fb7611, 0x1f9cbd05, 0x0d65683b, 0x0c68863d, 0x391f29be, 0x3490366e, 0x10f4}}, + {{0x233146c2, 0x240801b5, 0x086adb7c, 0x2edda745, 0x3908ba90, 0x2c96968c, 0x353ad211, 0x0b654245, 0x850e}}}, + /* 15*16^42*G: */ + {{{0x28d84958, 0x39bf4766, 0x0acc5cae, 0x0477ac5b, 0x00cc866a, 0x066e5db5, 0x277e749f, 0x3a02da6d, 0xe846}}, + {{0x3882cf9f, 0x031191ed, 0x1e0c1a64, 0x1468cd9c, 0x18b76fad, 0x2f64411e, 0x07e2541d, 0x2e3f2253, 0xa29c}}} + }, + { + /* 1*16^43*G: */ + {{{0x3e58ad71, 0x3dd8e226, 0x39a3a208, 0x0c347d73, 0x1e8c38bb, 0x17fa58a7, 0x2c3e30a0, 0x29e30a37, 0x7778}}, + {{0x3d9f43ac, 0x2d44ff07, 0x324ac563, 0x2ce1047f, 0x3f580087, 0x26384bcb, 0x1b22ff70, 0x1b66ad69, 0x3462}}}, + /* 3*16^43*G: */ + {{{0x3319c869, 0x3df1bab8, 0x21eb2702, 0x2a7e575d, 0x0cacdc18, 0x20e408bf, 0x33fc8d01, 0x01176605, 0x3018}}, + {{0x12b856f0, 0x3031db27, 0x23d9a7bf, 0x0aa13292, 0x222e3bca, 0x1890c835, 0x3b7b6f86, 0x315e0940, 0xac5f}}}, + /* 5*16^43*G: */ + {{{0x25ed29b5, 0x319a61be, 0x12add1b4, 0x20c2d81c, 0x23c885f5, 0x2d9f6e69, 0x17ef343a, 0x206d87b9, 0x3228}}, + {{0x3cd15ad2, 0x3d3c49b9, 0x0ee7604e, 0x20ebaae5, 0x1531e1ca, 0x02c677d0, 0x0344eb11, 0x00a105e8, 0x1677}}}, + /* 7*16^43*G: */ + {{{0x06c96100, 0x2fea101e, 0x2e9c8e63, 0x18c046a9, 0x33dbcca1, 0x0f766cb7, 0x31b9ffb4, 0x11ceb03e, 0x3f38}}, + {{0x32624707, 0x078ab06f, 0x375f1bcf, 0x15c71f02, 0x079ce566, 0x131118bc, 0x00395253, 0x27157d75, 0x70c6}}}, + /* 9*16^43*G: */ + {{{0x3d22d2ac, 0x0d31bb1b, 0x1caace02, 0x377f849b, 0x05df2f10, 0x0f03825e, 0x3a76dcb4, 0x04f17f49, 0x2881}}, + {{0x0f42a268, 0x207ad57e, 0x148c8fd0, 0x30f51285, 0x176137dd, 0x1ddc9832, 0x3c5c8f20, 0x3ac0563e, 0xa1a7}}}, + /* 11*16^43*G: */ + {{{0x245f8ea8, 0x12ea0374, 0x24d2900d, 0x1c9238e5, 0x119fe5d1, 0x3d36575c, 0x23a2a553, 0x28803211, 0xf963}}, + {{0x19bc99eb, 0x2f157ec1, 0x18b60824, 0x2e3c8d67, 0x3427208b, 0x1c88c07f, 0x383c0a3b, 0x2509a31f, 0x9c85}}}, + /* 13*16^43*G: */ + {{{0x2606a315, 0x386a20c4, 0x26963ad9, 0x1c981cbc, 0x0e097e40, 0x362ca964, 0x0d9a7f98, 0x08933fdc, 0xa5d9}}, + {{0x1e3b68d1, 0x0d584cd6, 0x111a7c9d, 0x13434d1f, 0x180de9ed, 0x0c1aaf5e, 0x0da5b343, 0x22c00ec8, 0x8732}}}, + /* 15*16^43*G: */ + {{{0x06231493, 0x336ded50, 0x0cc4d469, 0x1046a0c3, 0x25e6a496, 0x13907403, 0x3c3604eb, 0x260b86dc, 0xf1fe}}, + {{0x358848c1, 0x25aa6699, 0x25ff0d01, 0x1cfecd1b, 0x3d99d3f1, 0x34f0817d, 0x24ddc216, 0x067abb66, 0x2e20}}} + }, + { + /* 1*16^44*G: */ + {{{0x06d903ac, 0x027b6a70, 0x1ad7e5cb, 0x3e589d39, 0x3afd2ed5, 0x0a7f4c39, 0x3a844637, 0x2557b98d, 0x0928}}, + {{0x1bcd091f, 0x14603a4d, 0x0a8d83fc, 0x0f49bbea, 0x3a95eeac, 0x1e284c24, 0x342a827b, 0x08400f4f, 0xc256}}}, + /* 3*16^44*G: */ + {{{0x3874b839, 0x0444a1d5, 0x13d2b418, 0x10456ce5, 0x30b6aebe, 0x37c37ec8, 0x1e5a8053, 0x2e07f038, 0x3e03}}, + {{0x3c0594ba, 0x03073959, 0x1ab5b8da, 0x39717c3f, 0x198f667d, 0x3d981d5c, 0x07f42c44, 0x3858f7fc, 0xd13a}}}, + /* 5*16^44*G: */ + {{{0x0357a513, 0x28fde39a, 0x1b3023f3, 0x146f44d1, 0x2922c5f1, 0x3e8a0ea8, 0x0492cd62, 0x302de8bd, 0xe662}}, + {{0x2017d07e, 0x24a88072, 0x1538d891, 0x00d73589, 0x21a419d8, 0x2b882284, 0x2452305d, 0x064f3984, 0xab0b}}}, + /* 7*16^44*G: */ + {{{0x1f37d242, 0x2657dfbf, 0x39c14b04, 0x27fb2981, 0x23587dc2, 0x218b1f2f, 0x0f6cb843, 0x202c7253, 0x40bf}}, + {{0x26405088, 0x347609e6, 0x2bd35583, 0x0c87ae90, 0x26fe1274, 0x0ffa6c6c, 0x2aaf04f5, 0x374d7615, 0xb579}}}, + /* 9*16^44*G: */ + {{{0x195a3558, 0x2bcacd91, 0x234a7f2b, 0x01c7e178, 0x1b59f6ac, 0x3e5e04e3, 0x1ca70806, 0x3fa5d807, 0x3d14}}, + {{0x2443df4c, 0x1ab6ceb1, 0x3c1d727c, 0x3828b851, 0x356e1482, 0x26a4c76f, 0x281ef8f2, 0x2f75ba11, 0x16c6}}}, + /* 11*16^44*G: */ + {{{0x02b1fc24, 0x37a7d6b6, 0x23f7570e, 0x0a36071f, 0x12486525, 0x06b134b2, 0x265251cc, 0x29503a0b, 0xdd6f}}, + {{0x0e9b74ca, 0x290c7118, 0x17322304, 0x04379afb, 0x257e77ec, 0x1bc7afc5, 0x3186fe36, 0x0adfac74, 0x67e6}}}, + /* 13*16^44*G: */ + {{{0x3dd08e02, 0x07aa4564, 0x1adf0288, 0x2151edff, 0x3d1e8010, 0x1a5266a8, 0x15d780f8, 0x0b6a0b79, 0x13fa}}, + {{0x3cb03410, 0x29550770, 0x1a42b97d, 0x112beec6, 0x3432c7e6, 0x0d5881ae, 0x1da72313, 0x0e2c1155, 0x1363}}}, + /* 15*16^44*G: */ + {{{0x144ee41a, 0x308ceae6, 0x37d69a6a, 0x26d5b74e, 0x06828287, 0x3042d9cb, 0x30a443f7, 0x121474f1, 0xd06c}}, + {{0x0b295e6f, 0x3c7e13a6, 0x162ee252, 0x1ee10d18, 0x3630919b, 0x02b353d3, 0x0d0adbbb, 0x3f530161, 0x5815}}} + }, + { + /* 1*16^45*G: */ + {{{0x23d82751, 0x1eab9d45, 0x3ad35452, 0x116d2a41, 0x23b28556, 0x0193ce83, 0x1b109399, 0x3fbcfb1b, 0x85d0}}, + {{0x0eb1f962, 0x0b08de89, 0x07733158, 0x21d47a5a, 0x2cf5663e, 0x3525b960, 0x38c0be29, 0x192104e8, 0x1f03}}}, + /* 3*16^45*G: */ + {{{0x2cde4cf3, 0x26554187, 0x38a066ab, 0x10394d51, 0x1d9ae793, 0x30b49b45, 0x022c3be7, 0x2ad2b045, 0x384d}}, + {{0x252d0566, 0x1f1e5ac8, 0x351ba73b, 0x10c28ce5, 0x34c6f01f, 0x13b5b68a, 0x1ca43bfb, 0x316f346e, 0xd6e3}}}, + /* 5*16^45*G: */ + {{{0x1e5238c2, 0x22bcfa48, 0x00ecb8b9, 0x0d57d70e, 0x02ed4840, 0x05842d3a, 0x015aa41b, 0x3b03adf5, 0x14f0}}, + {{0x12f07922, 0x3a1a8d1e, 0x304939d6, 0x17003600, 0x02747fd2, 0x3f1cf8e1, 0x35d80921, 0x354f7520, 0xab12}}}, + /* 7*16^45*G: */ + {{{0x1543e94d, 0x3d8d4bbf, 0x2f98e188, 0x04c0a9d5, 0x1a0ddadd, 0x30d19e29, 0x0287ec41, 0x3ceede0b, 0xeb42}}, + {{0x05924d89, 0x01567791, 0x20d6d424, 0x3611a379, 0x0dfb774c, 0x03755cbf, 0x1d92dc9a, 0x1b41d3c9, 0x234a}}}, + /* 9*16^45*G: */ + {{{0x3e19aaed, 0x0c9396d5, 0x06673270, 0x26eb37a3, 0x06a92045, 0x3b00bdb8, 0x020d9a9e, 0x0e32945a, 0x1cf1}}, + {{0x292f400e, 0x04dba975, 0x3c77ffbc, 0x27bbe3fb, 0x2dde1747, 0x0dca99ad, 0x063865f4, 0x36bcc5c7, 0xd6ff}}}, + /* 11*16^45*G: */ + {{{0x36a8aa39, 0x3db03a7e, 0x278fac55, 0x2998ded2, 0x1990d937, 0x16825a12, 0x0d412c87, 0x21af97d0, 0xb586}}, + {{0x2b493c1f, 0x3f1e4d74, 0x2db347b8, 0x2f6be639, 0x00a91dab, 0x11e35153, 0x38c2c149, 0x3550c931, 0x5632}}}, + /* 13*16^45*G: */ + {{{0x303b4cc5, 0x3a47af8e, 0x21c77c2e, 0x0a0c6e96, 0x33a80257, 0x16f13f9f, 0x3cc2b67b, 0x276c1ae2, 0x5fc1}}, + {{0x25b57c28, 0x0ece7ee1, 0x0087ec4a, 0x1dbd40f3, 0x3a5ef492, 0x084e3e68, 0x0c7c66ee, 0x21303b26, 0xec8e}}}, + /* 15*16^45*G: */ + {{{0x0cb38cb5, 0x2d2e15f5, 0x1388948b, 0x02dff7d3, 0x3eea1be1, 0x2a2903f4, 0x1e289deb, 0x2dc350bb, 0xb88f}}, + {{0x1965f3d7, 0x1efe9d59, 0x3af8c719, 0x13cf8489, 0x35a8e24d, 0x12ee652c, 0x23280603, 0x0dab51ba, 0xd6c7}}} + }, + { + /* 1*16^46*G: */ + {{{0x0526087e, 0x3d501209, 0x2da20308, 0x3edb6220, 0x18b85dfd, 0x26d8105e, 0x2ce97c1c, 0x0373a5fb, 0xff2b}}, + {{0x30c29907, 0x32547807, 0x10e2ceb2, 0x2dfb5bee, 0x107936c7, 0x13137153, 0x0ba188af, 0x04ffbd49, 0x493d}}}, + /* 3*16^46*G: */ + {{{0x39d681f9, 0x164153f9, 0x08feb9fc, 0x3383bbeb, 0x2c94b066, 0x1ffc9780, 0x3230888b, 0x3f7c9dd7, 0xc745}}, + {{0x3bbb1247, 0x00c5cd0d, 0x27d45c76, 0x36f4cd71, 0x2818678c, 0x04e531c3, 0x1e5e78a7, 0x08bcbdae, 0x5902}}}, + /* 5*16^46*G: */ + {{{0x35cd0ea3, 0x38133bb4, 0x0cac4815, 0x111e3a08, 0x32e7f2b3, 0x16797ad9, 0x1050b27a, 0x1e7cea5d, 0xabb2}}, + {{0x3c307bce, 0x1c24c4cd, 0x202f3b64, 0x25da4167, 0x078ed47c, 0x12f8300c, 0x3970d9fb, 0x040eefc5, 0x5dee}}}, + /* 7*16^46*G: */ + {{{0x1bc9ee3e, 0x30b8bcfc, 0x3e7382c5, 0x27e86a58, 0x27ed11ea, 0x2baa9d09, 0x0682827f, 0x0542d67f, 0x3f81}}, + {{0x199aae06, 0x33ab6c31, 0x0da81603, 0x08ecb73f, 0x39566276, 0x06facf11, 0x3a82d467, 0x229a3f6f, 0x19c8}}}, + /* 9*16^46*G: */ + {{{0x38e4a007, 0x05c6fbeb, 0x0bb358b6, 0x3b3bb3c2, 0x16c7ec15, 0x12e8cea9, 0x02de6959, 0x04cb7402, 0x5cf8}}, + {{0x1068b883, 0x398fc242, 0x39c7fe8c, 0x251be5b1, 0x0c3df6c8, 0x35056212, 0x1fa0df4a, 0x3b970358, 0xb45a}}}, + /* 11*16^46*G: */ + {{{0x26c2d4a7, 0x255bf9ec, 0x3cfffb10, 0x30dbe4ce, 0x004ed21b, 0x38ce5cf1, 0x3a494653, 0x3f934352, 0xb6d5}}, + {{0x3ae86371, 0x063739f8, 0x35e3cc81, 0x16df939b, 0x3ffd8e74, 0x33e48277, 0x3d6c14df, 0x1ce84eae, 0x47f3}}}, + /* 13*16^46*G: */ + {{{0x3c66dd33, 0x024cd88b, 0x1dc76dc5, 0x23ef23fc, 0x29b022ea, 0x2c6c5400, 0x3588706b, 0x2ef019b3, 0x61c8}}, + {{0x36f10bfa, 0x0eeea7ce, 0x2820c8ca, 0x1441bab0, 0x05d3fb6a, 0x1a6652e6, 0x0f703446, 0x2788e795, 0x9359}}}, + /* 15*16^46*G: */ + {{{0x1d6b2ff8, 0x2016df33, 0x286c8fa9, 0x18cdb05c, 0x03bdf187, 0x27d4dcfb, 0x2785187c, 0x0ae95d09, 0x94e3}}, + {{0x2ce1af3e, 0x37521554, 0x26bfe13a, 0x0ebc1094, 0x2d9e8cb3, 0x07922198, 0x204e192f, 0x1122d0f6, 0x0d1b}}} + }, + { + /* 1*16^47*G: */ + {{{0x3856e241, 0x203978b3, 0x0d6dd287, 0x3c7b8523, 0x1b212b57, 0x0acb98c0, 0x080ea9ed, 0x2ef92c7a, 0x827f}}, + {{0x2ec293ec, 0x1816da2e, 0x2903166d, 0x3de98c61, 0x1d12687f, 0x3bcb19f4, 0x27b0b71b, 0x27248f1c, 0xc60f}}}, + /* 3*16^47*G: */ + {{{0x3bb80fa7, 0x0d12172c, 0x30413886, 0x29f69aed, 0x20819f3a, 0x0681af4c, 0x0c2fbc0d, 0x38c7d8c2, 0x0857}}, + {{0x09366b2d, 0x3660847c, 0x0d7016ab, 0x0b8dc10f, 0x0b714717, 0x1f327477, 0x0172092d, 0x24d08eb8, 0xf643}}}, + /* 5*16^47*G: */ + {{{0x09c70e63, 0x1740b0e8, 0x353d496f, 0x2ee2de39, 0x0a672e9c, 0x171955d9, 0x16004354, 0x333a95af, 0x28aa}}, + {{0x3057da4e, 0x27c0e20b, 0x04da1e8b, 0x3f167391, 0x28ebb7f5, 0x22599f1d, 0x20e1567a, 0x0c8bbe06, 0x2b69}}}, + /* 7*16^47*G: */ + {{{0x33e674b5, 0x007714bd, 0x3060aac6, 0x363da739, 0x2b8a4f92, 0x36cb26f3, 0x1a66145d, 0x2d896815, 0xa2f3}}, + {{0x0e937941, 0x024e3238, 0x033fa53b, 0x08be8c5f, 0x2a7c4b92, 0x112a43cc, 0x068ae800, 0x28565853, 0x620e}}}, + /* 9*16^47*G: */ + {{{0x191eb056, 0x1d8058c7, 0x2cfd386c, 0x00bbf6e3, 0x3515f5a0, 0x22d71a8f, 0x259231d9, 0x20f27aab, 0x3c4f}}, + {{0x205cecab, 0x109624f6, 0x1cf6b877, 0x20ad5120, 0x32788019, 0x3595cf0e, 0x28b6a33a, 0x2401d452, 0x9447}}}, + /* 11*16^47*G: */ + {{{0x3d86dfa9, 0x24187f6e, 0x1b993a71, 0x0e2d2902, 0x103baadc, 0x30780fa0, 0x167d4e29, 0x384a22a6, 0xaff8}}, + {{0x01d12681, 0x1c40f0db, 0x019f9c70, 0x045b6a51, 0x0f53f4f9, 0x0faea87f, 0x37c3fd3d, 0x12ecc84d, 0x8d8b}}}, + /* 13*16^47*G: */ + {{{0x189ba9c1, 0x23c9cdae, 0x09d338e2, 0x03df2968, 0x0ee579e4, 0x16098abb, 0x000b3e84, 0x1e114a37, 0xd3fb}}, + {{0x2b51b267, 0x186e237f, 0x011ade00, 0x073b7570, 0x370fe634, 0x32815d62, 0x2b4e7ca7, 0x350d3be9, 0xf894}}}, + /* 15*16^47*G: */ + {{{0x0f2bb909, 0x36a5b074, 0x3598d999, 0x24409f14, 0x187d7f63, 0x1ca620e4, 0x1aa88ff4, 0x0c0382b2, 0x4ec9}}, + {{0x24cf4071, 0x2228e0fe, 0x1ac3827b, 0x0b85a083, 0x0c49bad5, 0x03711461, 0x304dc5c8, 0x2841af86, 0x782b}}} + }, + { + /* 1*16^48*G: */ + {{{0x2120e2b3, 0x3ced63e8, 0x347f9aa7, 0x163f739f, 0x26e5217a, 0x392b8d33, 0x1bdbae7b, 0x127c87d4, 0xeaa6}}, + {{0x3a5ad93d, 0x11e94c16, 0x13f7e59d, 0x29ae597c, 0x39aa5a01, 0x2a03e261, 0x3b03ac69, 0x1e7b56ee, 0xbe32}}}, + /* 3*16^48*G: */ + {{{0x3f2e070d, 0x160ff4e8, 0x12a6a98f, 0x2aadc731, 0x1047e229, 0x1cc70ee1, 0x34abff48, 0x297a410b, 0x4b72}}, + {{0x296dd780, 0x112ea0bb, 0x2948c3de, 0x2d197774, 0x0f3c10b0, 0x1deecdb4, 0x2e1cf602, 0x0753875a, 0x599e}}}, + /* 5*16^48*G: */ + {{{0x0a02591c, 0x2739ff61, 0x05125a1e, 0x3d526596, 0x21fd613e, 0x1afefad7, 0x1c8e285a, 0x24ff194e, 0xa9fc}}, + {{0x29bec2dc, 0x242b77bd, 0x3cf72537, 0x22231057, 0x1165e5ca, 0x1305e86a, 0x387173e8, 0x39ce7714, 0x9c2c}}}, + /* 7*16^48*G: */ + {{{0x2d968b59, 0x0401b838, 0x3cbbc2e1, 0x28a2eb84, 0x1b027709, 0x35eb0482, 0x39f0a6a7, 0x005f069b, 0xc940}}, + {{0x0de572fb, 0x3bf5d902, 0x390c9c8f, 0x210b2d90, 0x35742ce2, 0x2286fe96, 0x3862013b, 0x08940326, 0x39d9}}}, + /* 9*16^48*G: */ + {{{0x326b3332, 0x0a1cccd5, 0x3ee5de6a, 0x00e2341c, 0x0bf8e031, 0x1e4e97dc, 0x10024ec6, 0x2ee75fbb, 0x1f84}}, + {{0x14e8d52e, 0x1510a28c, 0x36dc3a25, 0x2f338b50, 0x39edf0c2, 0x1f09fdd6, 0x29ecc254, 0x1b41caf2, 0xee72}}}, + /* 11*16^48*G: */ + {{{0x0defa98e, 0x336a952b, 0x1ac27995, 0x12111a04, 0x11e9c772, 0x2055ece6, 0x1fcd06ca, 0x38224251, 0x0f13}}, + {{0x3e286767, 0x0229dda6, 0x2ceaccdc, 0x1f9c1785, 0x3362db28, 0x0fe2c29e, 0x27c5035e, 0x087c5d93, 0xadd5}}}, + /* 13*16^48*G: */ + {{{0x29f59b6b, 0x178700ef, 0x1888e2fa, 0x2ce318f0, 0x1826d3e9, 0x0a2874b5, 0x1ec7db37, 0x24695477, 0xdde1}}, + {{0x26cb1410, 0x1ab658a4, 0x3154fecf, 0x15ce2ef9, 0x12e14e8b, 0x1d5f5871, 0x275cbe0a, 0x3ede00a0, 0x5b2b}}}, + /* 15*16^48*G: */ + {{{0x09c6b699, 0x1a3157f7, 0x3e46871b, 0x1bd5cd5a, 0x341682a8, 0x1b5efe5e, 0x36f7a5a1, 0x004bbb60, 0x5fab}}, + {{0x01c6c3aa, 0x05cc854b, 0x2883519b, 0x2ac45ffa, 0x162f7b90, 0x2ed044c3, 0x3d144e9e, 0x3e9c28f0, 0x2d9b}}} + }, + { + /* 1*16^49*G: */ + {{{0x1a34d24f, 0x388d8cb7, 0x1a137401, 0x2db63c32, 0x342ee541, 0x077db7b3, 0x3169d939, 0x0b50f173, 0xe4a4}}, + {{0x1eba9414, 0x29fdc4c7, 0x0d8e4f13, 0x21bbb7ea, 0x0ad34ce8, 0x326733ee, 0x1c73526f, 0x24b9c5b4, 0x4d9f}}}, + /* 3*16^49*G: */ + {{{0x3bea0c68, 0x321042bc, 0x37b392b5, 0x10c048d9, 0x396faf09, 0x26f23a34, 0x2a3a2494, 0x258d3855, 0x3e41}}, + {{0x1a45edb6, 0x32edbfdc, 0x03cda1ab, 0x2846518c, 0x0693062f, 0x0f2ff8dc, 0x321f7f37, 0x31676492, 0x0123}}}, + /* 5*16^49*G: */ + {{{0x139824d7, 0x3dd748f2, 0x11c9897a, 0x2ded930d, 0x3f0b576e, 0x128f98bd, 0x17508eed, 0x0e3d5157, 0x8d94}}, + {{0x1366489f, 0x28013d22, 0x26b063d8, 0x2e78ae0c, 0x36ef6f8f, 0x182f4c6a, 0x26c2a2ca, 0x381cd3fb, 0x3261}}}, + /* 7*16^49*G: */ + {{{0x18d713de, 0x39201c6a, 0x028e6208, 0x1830bedd, 0x25454393, 0x2a44a8bf, 0x254420d4, 0x0931563b, 0xb725}}, + {{0x1b8350e9, 0x1bff9496, 0x04a5fcb7, 0x20b49bf9, 0x16941504, 0x0b460ba7, 0x03e45104, 0x2ce6a28a, 0x4c51}}}, + /* 9*16^49*G: */ + {{{0x3e3b2cb4, 0x331b0a4f, 0x37210402, 0x127cd6fc, 0x21149e30, 0x31db8e04, 0x112519ad, 0x17d6885b, 0x3de4}}, + {{0x307eb02f, 0x1878ceb0, 0x287044cf, 0x0f8a3996, 0x3c910682, 0x022a92a5, 0x2addc50e, 0x21661017, 0xba2a}}}, + /* 11*16^49*G: */ + {{{0x2ce4e5bf, 0x08d1d9bd, 0x09005b17, 0x19f2a1a8, 0x0906ae9b, 0x0ff38dd2, 0x1be87c1e, 0x3c71a256, 0x8511}}, + {{0x01789c08, 0x3f24a513, 0x05365262, 0x2a1e226f, 0x2a00232d, 0x377dfb1a, 0x0d4874c1, 0x3d73e46f, 0xecdf}}}, + /* 13*16^49*G: */ + {{{0x3d3258ab, 0x06d59a28, 0x2bc14dc3, 0x3490a062, 0x14ab5957, 0x2871cbb8, 0x360222cf, 0x014ba073, 0x8c5a}}, + {{0x022d0f8f, 0x15f8214c, 0x0d944ade, 0x36ba3e70, 0x0c08c246, 0x2a031e41, 0x3bda1079, 0x36d2ed10, 0x6811}}}, + /* 15*16^49*G: */ + {{{0x3f91bcee, 0x1630a82a, 0x20c0d841, 0x33c763c7, 0x2bf137f5, 0x18f3b155, 0x13560bdc, 0x3e05b7af, 0xcef7}}, + {{0x01966b33, 0x2ed36a7e, 0x172f6ac6, 0x0f92c0a8, 0x1d245fa6, 0x0ecce700, 0x08701246, 0x1320d8dd, 0x67e7}}} + }, + { + /* 1*16^50*G: */ + {{{0x0300bf19, 0x1c5cee75, 0x08fea494, 0x2d4d5daa, 0x352b6b92, 0x183eb6ac, 0x0bdd9541, 0x03fbcd83, 0x1ec8}}, + {{0x0107cefd, 0x1c737073, 0x295a07b6, 0x11b9dfd8, 0x2bbf5e01, 0x2925629e, 0x1340d2f3, 0x3a4dd5ad, 0xaeef}}}, + /* 3*16^50*G: */ + {{{0x12fea1f9, 0x2c5f2ef1, 0x00452b94, 0x3fc2d423, 0x106531c4, 0x3f76ad9c, 0x1f2e83bc, 0x22029574, 0xa6dc}}, + {{0x3bc345e9, 0x2c705391, 0x268f7e63, 0x1ee276df, 0x2cbc5005, 0x1a0e845a, 0x367c3038, 0x2a151f70, 0x7ef1}}}, + /* 5*16^50*G: */ + {{{0x06d6c9b3, 0x235030fc, 0x0865637c, 0x1b133a1d, 0x2481ba8c, 0x308a71e2, 0x245992bd, 0x2a4ffa90, 0xfe6b}}, + {{0x2948bdfb, 0x30b1e23e, 0x1c2e9b00, 0x203c6fc1, 0x013b56d9, 0x2d06cd15, 0x39872b6b, 0x0635d014, 0x7ee9}}}, + /* 7*16^50*G: */ + {{{0x0cf95151, 0x08bc41cc, 0x02c4b644, 0x19201b91, 0x08ded1b9, 0x03230b70, 0x098bfb02, 0x38bc51bf, 0x15d5}}, + {{0x2ff8ecf2, 0x20a81f30, 0x1d8c0f94, 0x0813ee5f, 0x1023f9bb, 0x038425e2, 0x3d4ec7f9, 0x0b8c6457, 0xa5b7}}}, + /* 9*16^50*G: */ + {{{0x296a5658, 0x35e042e4, 0x1ef65643, 0x052c9490, 0x2e29be38, 0x1f80249e, 0x0447ad8c, 0x3a1c95a2, 0x84c0}}, + {{0x181b80d1, 0x3659ca6f, 0x34f1fd22, 0x2986a607, 0x13725ed3, 0x1f8c6419, 0x022c4a08, 0x20e03058, 0x2659}}}, + /* 11*16^50*G: */ + {{{0x14dc6a0f, 0x1d6ed722, 0x2fe15753, 0x10d06450, 0x0077c274, 0x09939e8b, 0x3731d565, 0x2c71c6a4, 0xfed6}}, + {{0x176fc7e0, 0x32e35cb6, 0x23fc409c, 0x1d3564c2, 0x13ae2313, 0x24606b93, 0x3ff0a847, 0x2af9ac3f, 0x8de2}}}, + /* 13*16^50*G: */ + {{{0x18e29355, 0x2ce217c4, 0x1720d86d, 0x0723a4ce, 0x23b9d82f, 0x3be18100, 0x3cbc70fc, 0x137664b4, 0x2a6a}}, + {{0x35cc2872, 0x014f803e, 0x0c4c76c0, 0x24168e99, 0x28f90dfe, 0x3f720789, 0x27e0c760, 0x37ee9f12, 0x8677}}}, + /* 15*16^50*G: */ + {{{0x2148dabf, 0x3e7ea23f, 0x09d78eb1, 0x2b74ae4d, 0x3ae735c1, 0x193b08d7, 0x27546d97, 0x24c09b24, 0xe42d}}, + {{0x011e1361, 0x1dcb1d5a, 0x1e77eb9d, 0x1c9d5c06, 0x33853032, 0x0e33aff7, 0x184b0d8b, 0x218b1b8b, 0x6413}}} + }, + { + /* 1*16^51*G: */ + {{{0x366642be, 0x376d64a0, 0x158ba889, 0x0d241c5f, 0x0dfa8bce, 0x002bd1a0, 0x30c2f91b, 0x1de30119, 0x146a}}, + {{0x3d83efd0, 0x02ca5d20, 0x37e5ed1d, 0x2aa5c74b, 0x14b2870a, 0x1a609fe7, 0x0028add6, 0x383b0cd5, 0xb318}}}, + /* 3*16^51*G: */ + {{{0x27315443, 0x364e1ce0, 0x2e867299, 0x1e6ef552, 0x2142a13d, 0x32266082, 0x0935ff42, 0x1b010198, 0xfc69}}, + {{0x17d28960, 0x1243582d, 0x09bd1b17, 0x1ffd2184, 0x1677b548, 0x0387375a, 0x35892bbf, 0x09fafe0e, 0xe0ce}}}, + /* 5*16^51*G: */ + {{{0x16fdb4eb, 0x06ecbd70, 0x22e6a79d, 0x28f75e71, 0x3eb0928f, 0x15a8d58a, 0x3f2ad1ae, 0x3c887fd3, 0x974a}}, + {{0x29f6f484, 0x10270f7e, 0x3ffc2348, 0x0715ca8e, 0x0090ed11, 0x0790f40b, 0x003ca64d, 0x0e1f54d4, 0x5552}}}, + /* 7*16^51*G: */ + {{{0x1d5aeee3, 0x0e412b6d, 0x258c8137, 0x0a12f0d9, 0x1270c5e8, 0x086ce99a, 0x2398b091, 0x2d66d277, 0x5baa}}, + {{0x30f69717, 0x0b4a6bed, 0x3d31eed8, 0x1777276a, 0x3fdaf721, 0x28021987, 0x37e856e5, 0x1fd85f03, 0x8a57}}}, + /* 9*16^51*G: */ + {{{0x35726890, 0x146c7913, 0x0837d158, 0x24097fab, 0x110a0ee5, 0x0cbf3afe, 0x1c43d010, 0x17e9fad2, 0xfb68}}, + {{0x3835783a, 0x01baa3ce, 0x10e79b26, 0x29b2c4ba, 0x24ba094f, 0x3285b661, 0x25e2e869, 0x37c8b263, 0xd750}}}, + /* 11*16^51*G: */ + {{{0x28bca48a, 0x1192fc4e, 0x03df62f5, 0x2d357d3a, 0x07f71d78, 0x09ee470a, 0x2995a0ab, 0x23fd9678, 0x5de5}}, + {{0x12fd41cd, 0x21e53a03, 0x20f8aa95, 0x396f6713, 0x2d3c843f, 0x2988f094, 0x19b55309, 0x0ecf600d, 0x685a}}}, + /* 13*16^51*G: */ + {{{0x25ef63b6, 0x378e0d13, 0x31b182eb, 0x2d34059c, 0x0fc1c85a, 0x2dff68ed, 0x218bfaf1, 0x09737ab5, 0x6f18}}, + {{0x05c655f3, 0x0b211b3d, 0x27f94541, 0x22569900, 0x3334553c, 0x108135e0, 0x1911b98f, 0x1f9f7564, 0xff09}}}, + /* 15*16^51*G: */ + {{{0x34a63f3b, 0x2d411fb7, 0x178f9727, 0x080ec066, 0x36c76583, 0x1c457d79, 0x2a376b58, 0x2e257dd8, 0xc5ec}}, + {{0x05005024, 0x14fcdd1a, 0x230bee5b, 0x3ad97b97, 0x1233ec8b, 0x290163fe, 0x081f374e, 0x0946065e, 0x2225}}} + }, + { + /* 1*16^52*G: */ + {{{0x3180eef9, 0x35daa1e4, 0x228b9776, 0x00048826, 0x207b128d, 0x2b3aec6a, 0x2e5f07e3, 0x303d8748, 0xfa50}}, + {{0x3f4f2811, 0x233635f4, 0x17a213b3, 0x1a0ca4e9, 0x01a68a5e, 0x334a1c8a, 0x3eba9b72, 0x31a488e5, 0x6b84}}}, + /* 3*16^52*G: */ + {{{0x11da5e12, 0x07b838ce, 0x1cacb297, 0x31829005, 0x1ca2b6a9, 0x0ca7e4e8, 0x1e31bcda, 0x0b8f10de, 0xf750}}, + {{0x0385f4eb, 0x292e717a, 0x325cebc7, 0x21b4cbbd, 0x1672047b, 0x1c25170f, 0x0fafd599, 0x3d7b759f, 0x3c57}}}, + /* 5*16^52*G: */ + {{{0x10b7d105, 0x01d24cc4, 0x0e57c9f2, 0x329712e5, 0x3455b3f4, 0x13d98938, 0x25862a3a, 0x1e3e60eb, 0x12fe}}, + {{0x1f794a60, 0x162b1bee, 0x2ee90b84, 0x3b389975, 0x27cb771d, 0x2d6a8666, 0x2bcf7786, 0x3c68ce35, 0x2062}}}, + /* 7*16^52*G: */ + {{{0x1e0c5d05, 0x188760ce, 0x2572daff, 0x039b142a, 0x084b1a48, 0x12ec40a0, 0x3473d58c, 0x30c4d1f7, 0x76aa}}, + {{0x11ece63e, 0x159866dd, 0x15e6ee35, 0x048973c0, 0x02625f4b, 0x3ccb20c8, 0x070efabe, 0x1dbbc357, 0xef55}}}, + /* 9*16^52*G: */ + {{{0x3c53c086, 0x389bd217, 0x09a1aec9, 0x2d570d27, 0x288104c6, 0x1830c517, 0x05ccc87e, 0x3f96ef97, 0xa663}}, + {{0x25016201, 0x1a7140ca, 0x3994fc0e, 0x07b3295c, 0x023dc399, 0x2c40b226, 0x11fbf5d1, 0x265fdac8, 0xb541}}}, + /* 11*16^52*G: */ + {{{0x0b758574, 0x2b6007b5, 0x34f9c6e9, 0x0c99a250, 0x22bdf3d8, 0x328409eb, 0x2cd825b7, 0x149e8081, 0xde95}}, + {{0x3b67232a, 0x2df7c7f3, 0x15a2deb4, 0x39a84145, 0x169ed7ba, 0x077211fc, 0x3d14e4e2, 0x3815ab24, 0x4cd3}}}, + /* 13*16^52*G: */ + {{{0x3d85474f, 0x1de6e2af, 0x1634668d, 0x13128ae2, 0x385aea89, 0x3732f911, 0x32addbfe, 0x2f3819b4, 0x8da6}}, + {{0x3d7b4ef7, 0x3f7e71f4, 0x1dbdd7a5, 0x073164c1, 0x1dfff10b, 0x377d741c, 0x2d4ff84f, 0x1b1abcc7, 0x13fc}}}, + /* 15*16^52*G: */ + {{{0x3dd042ea, 0x2d750959, 0x18eafd06, 0x3e89a991, 0x3c93beeb, 0x3599278c, 0x3ba39b1b, 0x2b31f3ec, 0x7329}}, + {{0x2f5c94a1, 0x36a33fb0, 0x1fab4f0a, 0x1225dcc7, 0x2b68ee18, 0x2139e53e, 0x36f14892, 0x124d506d, 0x9272}}} + }, + { + /* 1*16^53*G: */ + {{{0x1f067ec2, 0x394f4cad, 0x1bba5220, 0x0a22ad75, 0x08e8421a, 0x16fdadf6, 0x21a11b1a, 0x1874329c, 0xda1d}}, + {{0x1ad836f1, 0x157ee83c, 0x279b48a6, 0x29ce2674, 0x091e2966, 0x01d98587, 0x1306c79c, 0x3d569f26, 0x8157}}}, + /* 3*16^53*G: */ + {{{0x3a95a8db, 0x1761dccb, 0x39d36f61, 0x0fb03111, 0x1b1723b8, 0x25991a64, 0x3dd0419e, 0x036918c0, 0xe3e9}}, + {{0x1b0d1cf9, 0x005b3dfc, 0x0984d3d1, 0x2c7be5f3, 0x02e76afb, 0x3eaa431c, 0x0178bb00, 0x0ef0015b, 0xfbe5}}}, + /* 5*16^53*G: */ + {{{0x112ee214, 0x1eabf590, 0x19315401, 0x0a93a5e5, 0x00c01c78, 0x19437f57, 0x3d775a8b, 0x3fb1ccb8, 0x9f4f}}, + {{0x1085f37a, 0x3bd10889, 0x3c880283, 0x066da4c2, 0x35c69d97, 0x259a0bf5, 0x22f2e60e, 0x38b84c63, 0x639c}}}, + /* 7*16^53*G: */ + {{{0x1f61a0a5, 0x22da0514, 0x3c14e3ef, 0x0494f86c, 0x040b2c4b, 0x0682907d, 0x34ac1b17, 0x188b5044, 0x431f}}, + {{0x38cef899, 0x1adedff9, 0x15657724, 0x2eaa810d, 0x23aa7241, 0x3799465c, 0x2438f6d6, 0x0c9ff9ea, 0xa298}}}, + /* 9*16^53*G: */ + {{{0x27748503, 0x2b099f55, 0x31328e7c, 0x1b8391dc, 0x0a12ac0e, 0x18bbce7e, 0x38fb86cb, 0x2eb77b39, 0x993d}}, + {{0x3eb0cee2, 0x2e9cd84d, 0x38adaa49, 0x3e1efda6, 0x21f51a17, 0x3de11e1e, 0x1eeeb785, 0x2a7ba15a, 0xa521}}}, + /* 11*16^53*G: */ + {{{0x26d23d80, 0x37a889d6, 0x2474d478, 0x02f447c9, 0x0962c0e1, 0x250c72e4, 0x15ea5a33, 0x1eae81ab, 0x75f1}}, + {{0x280dd57e, 0x21aa16c0, 0x34ea5909, 0x0bfefb6e, 0x1b629237, 0x31f42fc6, 0x39a80c7f, 0x18bf8558, 0xa07a}}}, + /* 13*16^53*G: */ + {{{0x21ad3413, 0x38ae6db5, 0x327d684a, 0x2e700100, 0x387b7a8d, 0x257d2172, 0x1f4a0a6e, 0x15578476, 0x6678}}, + {{0x3ebca672, 0x09204081, 0x2dc66601, 0x338b454e, 0x0bdf9ea6, 0x099b649f, 0x0f646925, 0x368f789e, 0x510d}}}, + /* 15*16^53*G: */ + {{{0x06cc8563, 0x3002bd6c, 0x3e101eaa, 0x0937d6ff, 0x16368892, 0x320af606, 0x27748ada, 0x128d8b36, 0xebdc}}, + {{0x2394ccfa, 0x26c5ef3a, 0x1204f924, 0x3101e492, 0x1d4f07be, 0x3b8d79b3, 0x2d35f9b1, 0x0c513a15, 0x659a}}} + }, + { + /* 1*16^54*G: */ + {{{0x0d064e13, 0x29cec184, 0x06f1e062, 0x0c477811, 0x3d416615, 0x17fe63a3, 0x30690721, 0x20bfc325, 0xa8e2}}, + {{0x11f4cc0c, 0x3bdf1cc4, 0x0dd6bd6c, 0x19e68f94, 0x2515888b, 0x2dfcf16c, 0x01c09abf, 0x0d56e36e, 0x7f97}}}, + /* 3*16^54*G: */ + {{{0x3a3979b5, 0x0a8666c2, 0x27e829e2, 0x0a23e379, 0x240e50ba, 0x0dfc2c7b, 0x1e26327f, 0x01f1736b, 0xae22}}, + {{0x0450fa6f, 0x23cf359a, 0x3d4f8896, 0x2a1edf4d, 0x2d7060fc, 0x3249148e, 0x39f71ad4, 0x3f944301, 0xea91}}}, + /* 5*16^54*G: */ + {{{0x0efca824, 0x10406440, 0x22164fae, 0x2f8313fa, 0x185461e0, 0x31504019, 0x2ace59ce, 0x3b432b5c, 0xcb8d}}, + {{0x0f227361, 0x0502f416, 0x3931742f, 0x2b47f7f1, 0x2ccbc496, 0x05b121e8, 0x188c85b3, 0x0023dd03, 0x33a5}}}, + /* 7*16^54*G: */ + {{{0x3bcbd327, 0x1046d368, 0x1e4aaee9, 0x13821488, 0x276ed6b0, 0x2524035f, 0x1836708e, 0x0eca62bc, 0xb0c5}}, + {{0x2d7be436, 0x185af128, 0x0636a0f1, 0x0a88831d, 0x26b2afd8, 0x3da9806d, 0x17ea1638, 0x25d007ef, 0xee2a}}}, + /* 9*16^54*G: */ + {{{0x17b836a1, 0x39bbed8e, 0x3679ef7d, 0x019017fd, 0x37f526c8, 0x2218bb39, 0x1b920d4d, 0x29cfcca7, 0x6f6b}}, + {{0x06832b84, 0x36f7cbec, 0x0e1ff934, 0x264314a2, 0x3ee9c0d8, 0x02e29016, 0x3c18e3db, 0x2285ffd7, 0xdc77}}}, + /* 11*16^54*G: */ + {{{0x1eb39ede, 0x2bb8d082, 0x30612d42, 0x02200cb5, 0x02436031, 0x3fd19f84, 0x22af4bbc, 0x069f71d0, 0x7d47}}, + {{0x2bf6607e, 0x326f3652, 0x022a8fd0, 0x2573df47, 0x3c86fa77, 0x2088c7bf, 0x2856507b, 0x1ec67ce9, 0x004a}}}, + /* 13*16^54*G: */ + {{{0x165eb1c1, 0x15b52789, 0x1ae5c5aa, 0x335d59f3, 0x02f0967f, 0x03f30c66, 0x33fac707, 0x1458fe6d, 0xf002}}, + {{0x2dde2ae0, 0x369f5c11, 0x2cd11e57, 0x1dbfd735, 0x26afed85, 0x1ad29768, 0x120df4c6, 0x2a7a220f, 0x054e}}}, + /* 15*16^54*G: */ + {{{0x1ac32c64, 0x33cd424f, 0x0ae4bf84, 0x0dbf80fb, 0x07715e0e, 0x013a543d, 0x123aa0f7, 0x0500007b, 0xac12}}, + {{0x1eb1a867, 0x204ab6eb, 0x253f0898, 0x16974e96, 0x0499a3ed, 0x02da55cc, 0x38baf187, 0x2f32eb0c, 0xce8e}}} + }, + { + /* 1*16^55*G: */ + {{{0x0319497c, 0x0bce0b7a, 0x12508c02, 0x166c7e94, 0x13cab15d, 0x2795b9a4, 0x285872d3, 0x14ee7268, 0x174a}}, + {{0x079afa73, 0x0f684eb0, 0x0b985438, 0x1ace8763, 0x07f9e664, 0x10557cb1, 0x09c1657b, 0x370deaff, 0xccc9}}}, + /* 3*16^55*G: */ + {{{0x354b8367, 0x25201cf5, 0x3d506bfe, 0x1d6ddf59, 0x036a5db7, 0x2a975161, 0x2526e40c, 0x0252b911, 0x5e5a}}, + {{0x11ce85ca, 0x14ca6a76, 0x1e5ffa44, 0x1aaa7bcf, 0x2a4b7a79, 0x2407c55c, 0x15e05c2c, 0x3e32691e, 0xae8a}}}, + /* 5*16^55*G: */ + {{{0x17b10d9d, 0x06615e4e, 0x11f8fcaf, 0x294bc627, 0x0cb82de6, 0x332e0cc4, 0x02e859de, 0x382b6e5c, 0x00d4}}, + {{0x3140dced, 0x20840121, 0x0e2d923e, 0x1626325e, 0x2287f70b, 0x0be1190c, 0x3640947d, 0x0066060d, 0x87b8}}}, + /* 7*16^55*G: */ + {{{0x1c9caee8, 0x02046982, 0x1a270bb2, 0x0b88116c, 0x04a66763, 0x1e866bbb, 0x374c0f6f, 0x1484da3b, 0x0366}}, + {{0x3772b711, 0x2a7b1a8e, 0x295ba7f0, 0x32ea624c, 0x26944501, 0x27f1a06e, 0x3ded9994, 0x30cacaa4, 0x1f18}}}, + /* 9*16^55*G: */ + {{{0x1446c85c, 0x0ffe5d46, 0x201c0635, 0x0df78239, 0x36c6eade, 0x19db114f, 0x38f1faa0, 0x24415bf6, 0x0e58}}, + {{0x2148972e, 0x3db1df9c, 0x0cddadd5, 0x2408d3a0, 0x081898f4, 0x1d062ebd, 0x27bda0ec, 0x1217c47e, 0xe39a}}}, + /* 11*16^55*G: */ + {{{0x022e1259, 0x3c62b7cf, 0x281362af, 0x05ce6901, 0x07777193, 0x33d7ea80, 0x1463f2b6, 0x049b49bc, 0xa740}}, + {{0x334a5f43, 0x3ddc5c90, 0x31d6dad5, 0x21979d4e, 0x3c7ee517, 0x17c5d299, 0x0f1ff1b0, 0x3feebc65, 0x05a9}}}, + /* 13*16^55*G: */ + {{{0x0b08f1fe, 0x22285e8f, 0x3a087bfd, 0x339fb9c2, 0x02d177d7, 0x1015d976, 0x074e4a65, 0x2e085b65, 0x87e4}}, + {{0x2ed5e2ec, 0x17dd2b26, 0x2786d9d7, 0x0bc8f6f5, 0x38c2cc6e, 0x35fe3a8b, 0x348cecd7, 0x0eb01d98, 0xf74e}}}, + /* 15*16^55*G: */ + {{{0x21c4d15c, 0x2a1c039a, 0x3c0e74b9, 0x17a9efc1, 0x254a4410, 0x308b0304, 0x279a5a92, 0x06d18ffa, 0x35ea}}, + {{0x3f3fe1ea, 0x324e6ebd, 0x065095ed, 0x18cea80c, 0x0d3b185d, 0x23e97f5d, 0x2d2cd788, 0x245946e7, 0xad21}}} + }, + { + /* 1*16^56*G: */ + {{{0x1475b7ba, 0x213f7fc2, 0x0918b3d8, 0x0e79cc39, 0x018cdbe0, 0x395fb7d4, 0x3785c3d3, 0x25a60650, 0x9593}}, + {{0x3524f2fd, 0x26e2afe1, 0x0709385e, 0x194fd932, 0x1cd6849c, 0x00e1a92e, 0x331dd8ba, 0x154a2230, 0x2e7e}}}, + /* 3*16^56*G: */ + {{{0x0fd69985, 0x02717764, 0x1df72aea, 0x0c2732db, 0x0ccf149f, 0x3da437ef, 0x32f7e788, 0x1d9d73ad, 0x0ae9}}, + {{0x1409a003, 0x2723ad04, 0x2ee1aff8, 0x2e67505e, 0x1a54c5d0, 0x237fb814, 0x08d14e9b, 0x265cfdb9, 0x9121}}}, + /* 5*16^56*G: */ + {{{0x19262b90, 0x37064f7f, 0x23cc29a9, 0x08f1307f, 0x025d1fb7, 0x197c5de0, 0x1612ec9b, 0x218a96b0, 0x2b15}}, + {{0x083d7557, 0x24665b99, 0x19489a49, 0x14d25c3e, 0x0749066f, 0x0c354b6a, 0x233faa7a, 0x014f6a82, 0x2eb0}}}, + /* 7*16^56*G: */ + {{{0x28e7be40, 0x0fe5c532, 0x1040ee59, 0x34b22524, 0x24769af2, 0x2570585b, 0x2ee677ee, 0x3abb46a5, 0x6af9}}, + {{0x2e387e1c, 0x2905b809, 0x0f59569f, 0x38fd99a8, 0x07dc8145, 0x27a90a0d, 0x06649670, 0x0a845a40, 0xb381}}}, + /* 9*16^56*G: */ + {{{0x3482801e, 0x09adbe83, 0x1bd4155d, 0x1e53e2f1, 0x38d6f940, 0x2aad0932, 0x0144eeb3, 0x1a3b8111, 0x5966}}, + {{0x04870c37, 0x11dc523c, 0x3d3535ad, 0x2db072d8, 0x31304e8d, 0x23e5821d, 0x2ef5f1ec, 0x282a16ee, 0x949a}}}, + /* 11*16^56*G: */ + {{{0x032c19fd, 0x1326cb9f, 0x18028c3e, 0x32ae3a41, 0x170b5b4a, 0x3d345ead, 0x050762fd, 0x346206d4, 0xbe84}}, + {{0x32f1281f, 0x1da5294d, 0x250dc376, 0x1569fd57, 0x08399479, 0x3997d20c, 0x050944d1, 0x1832ccb7, 0xeff9}}}, + /* 13*16^56*G: */ + {{{0x16c69482, 0x346dd7f5, 0x32fa167b, 0x3aad5004, 0x32bc88cb, 0x15c9d32b, 0x17ee541f, 0x280c5303, 0x9867}}, + {{0x2f792cd7, 0x1bc18451, 0x15628a91, 0x189173d4, 0x3a99639e, 0x24b556c6, 0x0834f9c7, 0x18568ec4, 0xd02e}}}, + /* 15*16^56*G: */ + {{{0x1d557aa1, 0x2288e764, 0x101fc297, 0x0764bfb3, 0x19d6abdf, 0x1fcba802, 0x0815a592, 0x3c915036, 0xa866}}, + {{0x01430634, 0x2606eed3, 0x0611a4b7, 0x3ada719f, 0x30e13961, 0x0f63e976, 0x22b44d79, 0x0e7daa00, 0xb587}}} + }, + { + /* 1*16^57*G: */ + {{{0x1d82b151, 0x2d44d032, 0x21fba2db, 0x28290f55, 0x109a8fcc, 0x168454ec, 0x01e56d64, 0x0e942b90, 0xd2a6}}, + {{0x1cf89405, 0x105085d3, 0x084ca52d, 0x03dd42bd, 0x148220a7, 0x2bb962ca, 0x3fcb7565, 0x21bed910, 0xe82d}}}, + /* 3*16^57*G: */ + {{{0x2e4b3ba0, 0x2167d8d7, 0x18bf1f17, 0x0aafbd7c, 0x3f245f5c, 0x385c3cc6, 0x3fb73bef, 0x04414887, 0x4108}}, + {{0x17525595, 0x21a58770, 0x1a064554, 0x0d926159, 0x2b849813, 0x2996b875, 0x35668f2c, 0x3cda5dbf, 0xdc37}}}, + /* 5*16^57*G: */ + {{{0x13d98ded, 0x18a726e2, 0x38a02184, 0x37c8a0ce, 0x31d65edb, 0x3c8a6414, 0x0c0c8c8c, 0x2884285b, 0x63a2}}, + {{0x20d1cfc2, 0x06465f53, 0x1c7873a5, 0x2afda802, 0x2d94461f, 0x140cc953, 0x2c76fd06, 0x10b8b9ff, 0x882b}}}, + /* 7*16^57*G: */ + {{{0x38045445, 0x2a186942, 0x01e8d7ee, 0x3fdcdc64, 0x17bef080, 0x04b8b975, 0x167ca3df, 0x20575127, 0x0c15}}, + {{0x0054a206, 0x053e1f55, 0x258cea32, 0x0c15390d, 0x23cd28ba, 0x24f0ed99, 0x14115d0a, 0x35828eba, 0x2f30}}}, + /* 9*16^57*G: */ + {{{0x03857faf, 0x3a448e73, 0x29619701, 0x0bf2b787, 0x28ef7f88, 0x1eea3d20, 0x28a9c0d5, 0x3adae26b, 0xc757}}, + {{0x20584ca4, 0x07676c32, 0x01894c10, 0x1f4c4344, 0x3ec61b62, 0x0da7c822, 0x3ff36257, 0x1673f348, 0xf03a}}}, + /* 11*16^57*G: */ + {{{0x1459225d, 0x3934613d, 0x18858d10, 0x3ebddf8b, 0x1c02a244, 0x17502646, 0x3a0d0f81, 0x18ebab6b, 0xfa80}}, + {{0x3ece1507, 0x28adf8ed, 0x007c59c3, 0x0adb0db4, 0x0c425c0a, 0x37888209, 0x0c069160, 0x07e415f0, 0x0ba7}}}, + /* 13*16^57*G: */ + {{{0x16f0d044, 0x19e7fa50, 0x09e61a79, 0x2ea7f524, 0x2ee0a5aa, 0x3da73e18, 0x257a89e2, 0x28f16740, 0x658c}}, + {{0x37cb872d, 0x3747ccbb, 0x018ce89a, 0x2859d8f1, 0x3bd37655, 0x197589c4, 0x225460f1, 0x304ddeba, 0xae5c}}}, + /* 15*16^57*G: */ + {{{0x3696756d, 0x2d6b255c, 0x2561417a, 0x1abc5815, 0x3f305c67, 0x30660d74, 0x1f2bace4, 0x12d2abe4, 0x31c9}}, + {{0x1e08ae78, 0x2f117a37, 0x2ad1070a, 0x2bb7f2b9, 0x34160683, 0x2e2d66ab, 0x283a9bf4, 0x2212d55b, 0xf80f}}} + }, + { + /* 1*16^58*G: */ + {{{0x1617e073, 0x10dbe6d1, 0x039317b3, 0x2b2f6f4e, 0x0fdc866b, 0x39e25b5f, 0x31eb890e, 0x1f88cd51, 0x6458}}, + {{0x1faf6589, 0x20a6797a, 0x33aeab35, 0x2e428e44, 0x0299a185, 0x1b75911f, 0x102e2ae9, 0x33756fda, 0xd99f}}}, + /* 3*16^58*G: */ + {{{0x0e103dd6, 0x37dc51c8, 0x0004859a, 0x1181301f, 0x12a17ac3, 0x084f3f16, 0x203f836a, 0x1ef55690, 0xbc47}}, + {{0x16f7c343, 0x0e420b63, 0x23b44ac6, 0x0a4d5cb1, 0x1ea6395d, 0x2b154b1b, 0x0dd526cb, 0x07890a6a, 0xe31e}}}, + /* 5*16^58*G: */ + {{{0x144eab31, 0x34370ec3, 0x0e634907, 0x316bc501, 0x3bf8e80a, 0x0ed08c99, 0x3b838030, 0x2d3f969a, 0x589d}}, + {{0x11361f6a, 0x106baf9d, 0x148f8db9, 0x18439548, 0x3d90f31f, 0x1c188092, 0x2a2a4f60, 0x11170422, 0x6255}}}, + /* 7*16^58*G: */ + {{{0x1a0c2c41, 0x2fe585ca, 0x20336c67, 0x20c70715, 0x2edb7c42, 0x286182b5, 0x22fa2ea8, 0x2ccdf45b, 0x1339}}, + {{0x29f1bc2b, 0x217c152e, 0x1e923a41, 0x0489fe1f, 0x13a3406b, 0x0c903f44, 0x3ae5ba7a, 0x0a58d8b1, 0x9f9b}}}, + /* 9*16^58*G: */ + {{{0x18fc47af, 0x1c12c7e1, 0x2c0cdec3, 0x377fb20c, 0x01b568a8, 0x00ca6d40, 0x3cf17cc5, 0x2ee844d8, 0x7ff3}}, + {{0x39ba43a7, 0x3e185933, 0x18bac297, 0x294ec6b4, 0x33446b17, 0x32246dd1, 0x0a629a0b, 0x29eba006, 0x1f6b}}}, + /* 11*16^58*G: */ + {{{0x15213775, 0x06135802, 0x3d42a990, 0x2d0a4ec8, 0x2c7f6100, 0x07a4e57f, 0x360bb614, 0x1c118f3a, 0x8ec6}}, + {{0x3841ffff, 0x38043cf9, 0x0cf51e90, 0x36a6282f, 0x2dee0e71, 0x190d0573, 0x25be306e, 0x299be836, 0x8f58}}}, + /* 13*16^58*G: */ + {{{0x3452abbb, 0x32cffe34, 0x2b95c2e3, 0x1aa9cbf8, 0x15d495ae, 0x2eb0ffb6, 0x301bb89d, 0x186d1079, 0x83de}}, + {{0x054eb66e, 0x28145dac, 0x3ce42918, 0x2717cdae, 0x0e1563d7, 0x3edabe31, 0x0609fa6b, 0x38cd28d3, 0x32f0}}}, + /* 15*16^58*G: */ + {{{0x359276f1, 0x25a2309b, 0x2a17b15e, 0x2b896ca4, 0x3cd86833, 0x2ed7003d, 0x0c1db1a8, 0x18e263d4, 0x3d76}}, + {{0x059cbcb3, 0x0792996e, 0x1b197860, 0x08660806, 0x18333ef3, 0x1db8d36b, 0x07ddb609, 0x1a5cde86, 0xd376}}} + }, + { + /* 1*16^59*G: */ + {{{0x1d45e458, 0x1635b21b, 0x250e7fd3, 0x02a9b3a8, 0x09de042f, 0x151b4f95, 0x0d885b3a, 0x2f783939, 0x8481}}, + {{0x1779057e, 0x3592c6d6, 0x3262e556, 0x029e710a, 0x2cb2ca90, 0x096fce73, 0x004dd84a, 0x1ee32e95, 0x38ee}}}, + /* 3*16^59*G: */ + {{{0x152da17d, 0x18283e90, 0x0d0646b1, 0x3704f6c2, 0x200bc811, 0x139ac17f, 0x18c5f089, 0x3b4783d4, 0x3bea}}, + {{0x2cc768d2, 0x39c12617, 0x1fec416c, 0x3379dee3, 0x00e1b554, 0x12a2fafa, 0x37acdfef, 0x35fd56bf, 0xc3b0}}}, + /* 5*16^59*G: */ + {{{0x3a4edcc5, 0x0d3e85f6, 0x20311b72, 0x138c8850, 0x275997e7, 0x0b7f00e4, 0x09d61875, 0x36e832f7, 0x6e73}}, + {{0x159da0e4, 0x2cc7df37, 0x00679037, 0x229df69c, 0x02869327, 0x11542222, 0x2cc48bea, 0x307f127b, 0xee0a}}}, + /* 7*16^59*G: */ + {{{0x0a80b979, 0x02713109, 0x29abb314, 0x243d7e8c, 0x07c31004, 0x1f65faa9, 0x1b592762, 0x37624df9, 0x7706}}, + {{0x0126cfde, 0x133d2041, 0x17efe321, 0x3e828d3f, 0x2a9c7117, 0x2375e647, 0x3b714777, 0x2a609f56, 0x8a02}}}, + /* 9*16^59*G: */ + {{{0x326fe285, 0x336e712d, 0x13ef127d, 0x16eb0a50, 0x39e06aa4, 0x3cf1e907, 0x3c0f80d2, 0x08b164a6, 0x16d4}}, + {{0x0155b441, 0x0f83ff9b, 0x3364d423, 0x0fc3044d, 0x3531b1e9, 0x2df9a698, 0x22641a8a, 0x223e9478, 0x0df8}}}, + /* 11*16^59*G: */ + {{{0x3acfa513, 0x38c42f2a, 0x260e3aea, 0x0901e7e6, 0x356a9c4e, 0x28d11d43, 0x36d63aa5, 0x0391fbb1, 0x1fcc}}, + {{0x107afc9c, 0x141d6e90, 0x09839187, 0x3b7b7459, 0x39f9b44b, 0x38e1d50c, 0x35478b48, 0x30681078, 0x165d}}}, + /* 13*16^59*G: */ + {{{0x3edc69b2, 0x0689c1f3, 0x26b77172, 0x0298226c, 0x0aa386a5, 0x190c10d7, 0x0b8a1730, 0x241ceb5b, 0xc12b}}, + {{0x20dd41dd, 0x0caba6c0, 0x127b2a00, 0x3b876f8f, 0x094976b8, 0x1cb7227e, 0x0cdf1d97, 0x310ff94d, 0x3173}}}, + /* 15*16^59*G: */ + {{{0x3961fe4d, 0x2dbd6177, 0x3107197a, 0x05221be2, 0x2ca73e8a, 0x0fa4c4c4, 0x27a8fa3f, 0x2fe1770c, 0xd059}}, + {{0x2ae823c2, 0x264d6c19, 0x0dab64cb, 0x0e22e87d, 0x0955b4fd, 0x01d97721, 0x3525e3fe, 0x1e983022, 0x4510}}} + }, + { + /* 1*16^60*G: */ + {{{0x2caf666b, 0x3358c0fd, 0x0b1ce30b, 0x3f3fb4f1, 0x17f4637f, 0x1a5e6ba0, 0x102aa62b, 0x1295e9e0, 0x1346}}, + {{0x3f6ecc27, 0x3d256a41, 0x10942e13, 0x3cc02a07, 0x0cb0ca48, 0x390cd14f, 0x14580ef7, 0x05640118, 0x69be}}}, + /* 3*16^60*G: */ + {{{0x0eca5f51, 0x085ac826, 0x0fc9aebf, 0x3a85c6e5, 0x05b5cfdd, 0x3b5acafc, 0x2e6962c6, 0x35453767, 0xdde9}}, + {{0x10c638f7, 0x2b5a69cf, 0x289571f9, 0x3fbafa37, 0x3f8f0950, 0x07cd2c29, 0x28111d89, 0x1a44cf38, 0xb84e}}}, + /* 5*16^60*G: */ + {{{0x199c88e4, 0x3e41ac16, 0x0ad46ec2, 0x3b544f88, 0x204b179a, 0x3d01bac4, 0x193736e9, 0x188408da, 0xfd1a}}, + {{0x195bc8df, 0x27232459, 0x1cc00f29, 0x1adc7525, 0x177782dc, 0x0f01a552, 0x0c20bfb1, 0x1ed52e72, 0x1ac9}}}, + /* 7*16^60*G: */ + {{{0x1f8018ce, 0x35456d6d, 0x1892d68b, 0x0b695ce3, 0x086dc7cf, 0x3ff393cb, 0x296b9f13, 0x214c7630, 0x4ee4}}, + {{0x1e48381f, 0x30d6986c, 0x0e806013, 0x01d25c6d, 0x07c5e671, 0x2d102343, 0x3f8b5fc7, 0x27b52042, 0xb68f}}}, + /* 9*16^60*G: */ + {{{0x31473678, 0x0a14ba47, 0x14392f70, 0x2815e542, 0x38c070cb, 0x38c53156, 0x000dbff5, 0x33270d31, 0xfd76}}, + {{0x0d144f4f, 0x38593baa, 0x001c8437, 0x18a3bb85, 0x032cd660, 0x3b829cf4, 0x143dae0f, 0x1950de1c, 0xf204}}}, + /* 11*16^60*G: */ + {{{0x0d7a2193, 0x3c02dc52, 0x197546ed, 0x1a47913c, 0x34ea212c, 0x1b3a09d2, 0x3b40219e, 0x2ae8cc48, 0x85a2}}, + {{0x30cdcf3a, 0x3c320f52, 0x03b12427, 0x31b6b7e7, 0x0c029fe1, 0x31820b47, 0x30516d82, 0x2615faca, 0x9c12}}}, + /* 13*16^60*G: */ + {{{0x377568b0, 0x16c0c16c, 0x1e03b053, 0x2ba37406, 0x03650f35, 0x2db5b15e, 0x3fe74440, 0x36ff1cf3, 0xd25d}}, + {{0x1f39929c, 0x0284e49b, 0x23c3f006, 0x089ce207, 0x27d92b83, 0x2bbdd337, 0x048938be, 0x3fdd64fe, 0x7a3a}}}, + /* 15*16^60*G: */ + {{{0x271d7c13, 0x17f94462, 0x20ffa385, 0x06ad7dfe, 0x2ac80564, 0x01fa6a5e, 0x14a7255f, 0x0d4c50fa, 0x4581}}, + {{0x3aff63cf, 0x18e2f154, 0x2bd96b99, 0x08019550, 0x1d69c970, 0x3d43c5df, 0x39ad8b57, 0x163b0525, 0x9f58}}} + }, + { + /* 1*16^61*G: */ + {{{0x2d83f366, 0x2b68e834, 0x2f28588c, 0x36733b78, 0x1dc97a0c, 0x3d0c2f30, 0x3fe2e9ae, 0x277d6dc4, 0xbc4a}}, + {{0x181f33c1, 0x1d635999, 0x2547b16d, 0x3a2a7efe, 0x3798caa6, 0x24deb7d2, 0x05c06383, 0x20729b9e, 0x0d3a}}}, + /* 3*16^61*G: */ + {{{0x3712be3c, 0x01a8b8cb, 0x2146a66b, 0x257c63b6, 0x00153472, 0x1c976eac, 0x1b378d3c, 0x0d2764cc, 0x39d7}}, + {{0x1c6ff65c, 0x30c067d0, 0x0a41644c, 0x17bde97b, 0x2812e8ef, 0x09d55319, 0x33bf7fb1, 0x26d3d5bb, 0x8f92}}}, + /* 5*16^61*G: */ + {{{0x1f77f22b, 0x2ab93ef3, 0x0f82e035, 0x265c8e65, 0x15af26c6, 0x0735b0a6, 0x01dd09e5, 0x2985fdf7, 0xf0cb}}, + {{0x1909a03c, 0x3f238b1d, 0x0a095661, 0x3c631fa4, 0x16d04004, 0x0c9b0d94, 0x1df989ef, 0x2ad0c4fe, 0x1a25}}}, + /* 7*16^61*G: */ + {{{0x06509c12, 0x22b37353, 0x3d1f4765, 0x1aff88d6, 0x3268ed8d, 0x05c3a361, 0x154d321d, 0x1eae76c8, 0x381d}}, + {{0x2eb46102, 0x1190aa38, 0x0e6eaf75, 0x160a161b, 0x2581e720, 0x34915ce9, 0x23da9eb5, 0x2ad6dff6, 0xa47a}}}, + /* 9*16^61*G: */ + {{{0x384fe955, 0x36ced358, 0x063bce48, 0x2655a968, 0x0c8a53f6, 0x0edcf9a5, 0x387e6479, 0x3c1519ea, 0xa703}}, + {{0x161344bd, 0x09acbbef, 0x197277fa, 0x27858a71, 0x19199b53, 0x29e4b5ac, 0x047adc0e, 0x3e4d68ac, 0xd500}}}, + /* 11*16^61*G: */ + {{{0x06eace58, 0x126595b0, 0x2f3211d3, 0x1f9158e8, 0x13a03f1b, 0x1ab435c1, 0x150d746c, 0x2cf16ab5, 0x73c6}}, + {{0x2af8654e, 0x05c2a45c, 0x3b8d2917, 0x1aa1e36e, 0x2d91c6aa, 0x242644d9, 0x24f741ba, 0x2d291cce, 0x3a2f}}}, + /* 13*16^61*G: */ + {{{0x00181d5e, 0x12ce22fc, 0x15aaf205, 0x1c6cea6e, 0x0eddb8de, 0x0034e870, 0x147fda1d, 0x3cf9d41b, 0xc627}}, + {{0x369f886d, 0x09e40298, 0x1cbe2c39, 0x3dac0152, 0x21f7d68e, 0x1a5804e2, 0x02a63b2d, 0x2775c791, 0xd78f}}}, + /* 15*16^61*G: */ + {{{0x37828b16, 0x138a367e, 0x0a4847f3, 0x11e563ca, 0x06de53a0, 0x17d029bc, 0x3d233fa2, 0x3eaf83b7, 0xbb88}}, + {{0x0aea5df7, 0x1451ce88, 0x3a1e969c, 0x12a05d38, 0x159163ec, 0x37165804, 0x1e8dd345, 0x1dacc13d, 0xb736}}} + }, + { + /* 1*16^62*G: */ + {{{0x25324caa, 0x152acc3f, 0x29472a39, 0x12d978c2, 0x12a32e69, 0x3631d251, 0x18bc0d23, 0x2a5efe0a, 0x8c28}}, + {{0x0bef9482, 0x39c771cf, 0x11cb9459, 0x39e13c11, 0x3cc0eb7a, 0x3fb7cc7d, 0x05193378, 0x0118e8cc, 0x40a3}}}, + /* 3*16^62*G: */ + {{{0x0754dd40, 0x18fa1c55, 0x03466cf8, 0x10898c7f, 0x32f6e9a2, 0x12107f35, 0x0dfcf45b, 0x091c0cb0, 0x9729}}, + {{0x2aa36143, 0x212d24bc, 0x1acaf493, 0x36ba1495, 0x14df3690, 0x171d772f, 0x3ea1dcd1, 0x28910997, 0x91d1}}}, + /* 5*16^62*G: */ + {{{0x0c2ca7ff, 0x30b60bae, 0x1df021a3, 0x00d91765, 0x2f27af18, 0x1e46b568, 0x2796e050, 0x1fe5d602, 0x8963}}, + {{0x30493e68, 0x3b505785, 0x242eab7b, 0x1ef1a8e3, 0x357489f8, 0x2e73c550, 0x08424d57, 0x38492322, 0x2d1f}}}, + /* 7*16^62*G: */ + {{{0x0ca8dd7f, 0x061b58e8, 0x2a1381a6, 0x31ca00d5, 0x1357421b, 0x327680f5, 0x25e092fd, 0x0e39c6f8, 0x3081}}, + {{0x0a92c7f2, 0x1057c91e, 0x34ad915e, 0x05959190, 0x008e18c8, 0x27b11745, 0x0fc925e3, 0x38b4a20a, 0x28d1}}}, + /* 9*16^62*G: */ + {{{0x066a3fb1, 0x037315a2, 0x192e206c, 0x30024a06, 0x36862f6e, 0x15d43216, 0x1eb65d1e, 0x313a0a9b, 0x575f}}, + {{0x102655ad, 0x26e3a42a, 0x2a3af2f0, 0x0ced5cf1, 0x0e87daed, 0x076f0a5e, 0x2fca2d67, 0x36e410a9, 0x6f6e}}}, + /* 11*16^62*G: */ + {{{0x390117df, 0x06daa291, 0x22010292, 0x094eeef3, 0x2a2a8fda, 0x3c9be07b, 0x2ab7a227, 0x240dad93, 0xa5ec}}, + {{0x386462fe, 0x204a04cf, 0x214a363d, 0x21187c15, 0x1fa0f71c, 0x25e60eb4, 0x140400c5, 0x319897b0, 0xb79d}}}, + /* 13*16^62*G: */ + {{{0x172ad712, 0x2c3e5d70, 0x21047290, 0x0e632c37, 0x2349b95a, 0x39e5d851, 0x10b0949d, 0x37fa44cc, 0xa153}}, + {{0x0d48fdd2, 0x2297d94e, 0x2f0b329c, 0x014fca16, 0x31b89abd, 0x0c6357c7, 0x05b2fc48, 0x36104fec, 0xfd94}}}, + /* 15*16^62*G: */ + {{{0x11cf5b3a, 0x0c30dc04, 0x1b5a7810, 0x10cea0ef, 0x2dc824c4, 0x30d34223, 0x14615935, 0x06b1abde, 0x9a54}}, + {{0x36a44ae4, 0x0fd55d7c, 0x21ea52d6, 0x123fb894, 0x0f475f55, 0x386bcda2, 0x06ab7caf, 0x123072c4, 0xb661}}} + }, + { + /* 1*16^63*G: */ + {{{0x1faccae0, 0x2312e844, 0x24bb3374, 0x22cd4316, 0x071fd23c, 0x3653393c, 0x127a8c1d, 0x259984e5, 0x08ea}}, + {{0x0e62b945, 0x16bcd28c, 0x0f0f8e95, 0x2de0efa7, 0x15c5d735, 0x39f033ee, 0x22782e24, 0x3eaef23b, 0x620e}}}, + /* 3*16^63*G: */ + {{{0x26a06f5e, 0x06902d65, 0x2a083702, 0x1064945b, 0x23b716a3, 0x2c350849, 0x0253ac37, 0x093efa85, 0x383b}}, + {{0x13c6e772, 0x227d1e1b, 0x38c2b040, 0x3dab9d2e, 0x2a5a19e8, 0x3d59b553, 0x1ba2044c, 0x1c1ab13b, 0x54cf}}}, + /* 5*16^63*G: */ + {{{0x0638a136, 0x1e5d7075, 0x2838195c, 0x034738cd, 0x0d790c2b, 0x39671ad8, 0x2ed6d789, 0x0cb40f80, 0xe684}}, + {{0x0c6c2584, 0x2bf46042, 0x3357336a, 0x0278faf6, 0x01e6472e, 0x0a9cc0e8, 0x35a6624d, 0x3904e638, 0xca5b}}}, + /* 7*16^63*G: */ + {{{0x16e8c10c, 0x33a1f110, 0x11bd6807, 0x1ca617ce, 0x306e7fb4, 0x3ef7b39c, 0x25c2a0ee, 0x355678bf, 0x395d}}, + {{0x05fe638e, 0x30f5b64c, 0x066922cb, 0x24270137, 0x3a4e274c, 0x04fa1ebf, 0x12ac5d04, 0x37352d16, 0xfd62}}}, + /* 9*16^63*G: */ + {{{0x0d6c14ef, 0x059936c8, 0x2f93c8f5, 0x163f1d41, 0x22648008, 0x3bb56fbb, 0x25dcb9f6, 0x12b70d54, 0x7a51}}, + {{0x0b3fbd13, 0x2b4f861c, 0x2a6e24f7, 0x2fabbdca, 0x0f5c3729, 0x1fc2e532, 0x2e4d8e89, 0x347fb454, 0x56ed}}}, + /* 11*16^63*G: */ + {{{0x0f6d65eb, 0x2a518f41, 0x04021524, 0x26441dd5, 0x108f235a, 0x23bcefd2, 0x1d90d8ea, 0x3f5610c9, 0x1ee1}}, + {{0x1d22941c, 0x380dae49, 0x23582b11, 0x0cbd3a61, 0x02fcfaca, 0x2ae7f13d, 0x2c73c1cf, 0x0a246f75, 0xbb69}}}, + /* 13*16^63*G: */ + {{{0x0e36cb44, 0x3c6543bc, 0x1ca20191, 0x1fa2db23, 0x03357d61, 0x163f4362, 0x3aaa8bc0, 0x158d34e3, 0x1551}}, + {{0x1f495a68, 0x0a6bd194, 0x020c1e53, 0x30dc5d7c, 0x23205da8, 0x038fc2d1, 0x35215e37, 0x3ff1d555, 0xab4f}}}, + /* 15*16^63*G: */ + {{{0x3427bacc, 0x07e51841, 0x12d62e15, 0x1ccc5937, 0x0dc4aa9e, 0x163ac256, 0x35201363, 0x2f1911af, 0x3bc6}}, + {{0x2ad6fda6, 0x130cff57, 0x28beb471, 0x06dd6948, 0x16c02bd7, 0x18bb889b, 0x2c305cdb, 0x17301c5d, 0x8e30}}} + }, diff --git a/test-openssl.c b/test-openssl.c index 7103260fe..cd52a0948 100644 --- a/test-openssl.c +++ b/test-openssl.c @@ -29,6 +29,13 @@ #include "ecdsa.h" #include "rand.h" +#include "secp256k1.h" + +#define CURVE (&secp256k1) +#define prime256k1 (secp256k1.prime) +#define G256k1 (secp256k1.G) +#define order256k1 (secp256k1.order) +#define secp256k1_cp (secp256k1.cp) int main(int argc, char *argv[]) { @@ -81,21 +88,21 @@ int main(int argc, char *argv[]) } // use our ECDSA signer to sign the message with the key - if (ecdsa_sign(priv_key, msg, msg_len, sig, 0) != 0) { + if (ecdsa_sign(CURVE, priv_key, msg, msg_len, sig, 0) != 0) { printf("trezor-crypto signing failed\n"); break; } // generate public key from private key - ecdsa_get_public_key33(priv_key, pub_key33); - ecdsa_get_public_key65(priv_key, pub_key65); + ecdsa_get_public_key33(&secp256k1, priv_key, pub_key33); + ecdsa_get_public_key65(&secp256k1, priv_key, pub_key65); // use our ECDSA verifier to verify the message signature - if (ecdsa_verify(pub_key65, sig, msg, msg_len) != 0) { + if (ecdsa_verify(CURVE, pub_key65, sig, msg, msg_len) != 0) { printf("trezor-crypto verification failed (pub_key_len = 65)\n"); break; } - if (ecdsa_verify(pub_key33, sig, msg, msg_len) != 0) { + if (ecdsa_verify(CURVE, pub_key33, sig, msg, msg_len) != 0) { printf("trezor-crypto verification failed (pub_key_len = 33)\n"); break; } diff --git a/test_curves.py b/test_curves.py new file mode 100644 index 000000000..83d8c2ba9 --- /dev/null +++ b/test_curves.py @@ -0,0 +1,304 @@ +import ctypes as c +import random +import ecdsa +import hashlib +import subprocess +import binascii +import pytest +import os + + +def bytes2num(s): + res = 0 + for i, b in enumerate(reversed(bytearray(s))): + res += b << (i * 8) + return res + + +curves = { + 'nist256p1': ecdsa.curves.NIST256p, + 'secp256k1': ecdsa.curves.SECP256k1 +} + +random_iters = int(os.environ.get('ITERS', 1)) + +scons_file = ''' +srcs = 'ecdsa bignum secp256k1 nist256p1 sha2 rand hmac ripemd160 base58' +srcs = [(s + '.c') for s in srcs.split()] +flags = ('-Os -g -W -Wall -Wextra -Wimplicit-function-declaration ' + '-Wredundant-decls -Wstrict-prototypes -Wundef -Wshadow ' + '-Wpointer-arith -Wformat -Wreturn-type -Wsign-compare -Wmultichar ' + '-Wformat-nonliteral -Winit-self -Wuninitialized -Wformat-security ' + '-Werror -Wno-sequence-point ') +SharedLibrary('ecdsa', srcs, CCFLAGS=flags) +''' +open('SConstruct', 'w').write(scons_file) + +subprocess.check_call('scons -s', shell=True) +lib = c.cdll.LoadLibrary('./libecdsa.so') + +lib.get_curve_by_name.restype = c.c_void_p + +BIGNUM = c.c_uint32 * 9 + + +class Random(random.Random): + def randbytes(self, n): + buf = (c.c_uint8 * n)() + for i in range(n): + buf[i] = self.randrange(0, 256) + return buf + + def randpoint(self, curve): + k = self.randrange(0, curve.order) + return k * curve.generator + + +def int2bn(x, bn_type=BIGNUM): + b = bn_type() + b._int = x + for i in range(len(b)): + b[i] = x % (1 << 30) + x = x >> 30 + return b + + +def bn2int(b): + x = 0 + for i in range(len(b)): + x += (b[i] << (30 * i)) + return x + + +@pytest.fixture(params=range(random_iters)) +def r(request): + seed = request.param + return Random(seed + int(os.environ.get('SEED', 0))) + + +@pytest.fixture(params=list(sorted(curves))) +def curve(request): + name = request.param + curve_ptr = lib.get_curve_by_name(name) + assert curve_ptr, 'curve {} not found'.format(name) + curve_obj = curves[name] + curve_obj.ptr = c.c_void_p(curve_ptr) + curve_obj.p = curve_obj.curve.p() # shorthand + return curve_obj + + +def test_inverse(curve, r): + x = r.randrange(1, curve.p) + y = int2bn(x) + lib.bn_inverse(y, int2bn(curve.p)) + y = bn2int(y) + y_ = ecdsa.numbertheory.inverse_mod(x, curve.p) + assert y == y_ + + +def test_inverse(curve, r): + x = r.randrange(0, 2*curve.p) + y = int2bn(x) + lib.bn_mult_half(y, int2bn(curve.p)) + y = bn2int(y) + if y > curve.p: + y -= curve.p + half = ecdsa.numbertheory.inverse_mod(2, curve.p) + assert y == (x * half) % curve.p + + +def test_subtractmod(curve, r): + x = r.randrange(0, 2 ** 256) + y = r.randrange(0, 2 ** 256) + z = int2bn(0) + lib.bn_subtractmod(int2bn(x), int2bn(y), z, int2bn(curve.p)) + z = bn2int(z) + z_ = x + 2*curve.p - y + assert z == z_ + + +def test_subtract2(r): + x = r.randrange(0, 2 ** 256) + y = r.randrange(0, 2 ** 256) + x, y = max(x, y), min(x, y) + z = int2bn(0) + lib.bn_subtract(int2bn(x), int2bn(y), z) + z = bn2int(z) + z_ = x - y + assert z == z_ + + +def test_addmod(curve, r): + x = r.randrange(0, 2 ** 256) + y = r.randrange(0, 2 ** 256) + z_ = (x + y) % curve.p + z = int2bn(x) + lib.bn_addmod(z, int2bn(y), int2bn(curve.p)) + z = bn2int(z) + + assert z == z_ + + +def test_multiply(curve, r): + k = r.randrange(0, 2 * curve.p) + x = r.randrange(0, 2 * curve.p) + z = (k * x) % curve.p + k = int2bn(k) + z_ = int2bn(x) + p_ = int2bn(curve.p) + lib.bn_multiply(k, z_, p_) + z_ = bn2int(z_) + assert z_ < 2*curve.p + if z_ >= curve.p: + z_ = z_ - curve.p + assert z_ == z + + +def test_multiply1(curve, r): + k = r.randrange(0, 2 * curve.p) + x = r.randrange(0, 2 * curve.p) + kx = k * x + res = int2bn(0, bn_type=(c.c_uint32 * 18)) + lib.bn_multiply_long(int2bn(k), int2bn(x), res) + res = bn2int(res) + assert res == kx + + +def test_multiply2(curve, r): + x = int2bn(0) + s = r.randrange(0, 2 ** 526) + res = int2bn(s, bn_type=(c.c_uint32 * 18)) + prime = int2bn(curve.p) + lib.bn_multiply_reduce(x, res, prime) + + x = bn2int(x) + x_ = s % curve.p + + assert x == x_ + + +def test_fast_mod(curve, r): + x = r.randrange(0, 128*curve.p) + y = int2bn(x) + lib.bn_fast_mod(y, int2bn(curve.p)) + y = bn2int(y) + assert y < 2*curve.p + if y >= curve.p: + y -= curve.p + assert x % curve.p == y + + +def test_mod(curve, r): + x = r.randrange(0, 2*curve.p) + y = int2bn(x) + lib.bn_mod(y, int2bn(curve.p)) + assert bn2int(y) == x % curve.p + +POINT = BIGNUM * 2 +to_POINT = lambda p: POINT(int2bn(p.x()), int2bn(p.y())) +from_POINT = lambda p: (bn2int(p[0]), bn2int(p[1])) + +JACOBIAN = BIGNUM * 3 +to_JACOBIAN = lambda jp: JACOBIAN(int2bn(jp[0]), int2bn(jp[1]), int2bn(jp[2])) +from_JACOBIAN = lambda p: (bn2int(p[0]), bn2int(p[1]), bn2int(p[2])) + + +def test_point_multiply(curve, r): + p = r.randpoint(curve) + k = r.randrange(0, 2 ** 256) + kp = k * p + res = POINT(int2bn(0), int2bn(0)) + lib.point_multiply(curve.ptr, int2bn(k), to_POINT(p), res) + res = from_POINT(res) + assert res == (kp.x(), kp.y()) + + +def test_point_add(curve, r): + p1 = r.randpoint(curve) + p2 = r.randpoint(curve) + #print '-' * 80 + q = p1 + p2 + q1 = to_POINT(p1) + q2 = to_POINT(p2) + lib.point_add(curve.ptr, q1, q2) + q_ = from_POINT(q2) + assert q_ == (q.x(), q.y()) + + +def test_point_double(curve, r): + p = r.randpoint(curve) + q = p.double() + q_ = to_POINT(p) + lib.point_double(curve.ptr, q_) + q_ = from_POINT(q_) + assert q_ == (q.x(), q.y()) + + +def test_point_to_jacobian(curve, r): + p = r.randpoint(curve) + jp = JACOBIAN() + lib.curve_to_jacobian(to_POINT(p), jp, int2bn(curve.p)) + jx, jy, jz = from_JACOBIAN(jp) + assert jx == (p.x() * jz ** 2) % curve.p + assert jy == (p.y() * jz ** 3) % curve.p + + q = POINT() + lib.jacobian_to_curve(jp, q, int2bn(curve.p)) + q = from_POINT(q) + assert q == (p.x(), p.y()) + + +def test_cond_negate(curve, r): + x = r.randrange(0, curve.p) + a = int2bn(x) + lib.conditional_negate(0, a, int2bn(curve.p)) + assert bn2int(a) == x + lib.conditional_negate(-1, a, int2bn(curve.p)) + assert bn2int(a) == curve.p - x + + +def test_jacobian_add(curve, r): + p1 = r.randpoint(curve) + p2 = r.randpoint(curve) + prime = int2bn(curve.p) + q = POINT() + jp2 = JACOBIAN() + lib.curve_to_jacobian(to_POINT(p2), jp2, prime) + lib.point_jacobian_add(to_POINT(p1), jp2, prime) + lib.jacobian_to_curve(jp2, q, prime) + q = from_POINT(q) + p_ = p1 + p2 + assert (p_.x(), p_.y()) == q + +def test_jacobian_double(curve, r): + p = r.randpoint(curve) + p2 = p.double() + prime = int2bn(curve.p) + q = POINT() + jp = JACOBIAN() + lib.curve_to_jacobian(to_POINT(p), jp, prime) + lib.point_jacobian_double(jp, curve.ptr) + lib.jacobian_to_curve(jp, q, prime) + q = from_POINT(q) + assert (p2.x(), p2.y()) == q + +def sigdecode(sig, _): + return map(bytes2num, [sig[:32], sig[32:]]) + + +def test_sign(curve, r): + priv = r.randbytes(32) + digest = r.randbytes(32) + sig = r.randbytes(64) + + lib.ecdsa_sign_digest(curve.ptr, priv, digest, sig, c.c_void_p(0)) + + exp = bytes2num(priv) + sk = ecdsa.SigningKey.from_secret_exponent(exp, curve, + hashfunc=hashlib.sha256) + vk = sk.get_verifying_key() + + sig_ref = sk.sign_digest_deterministic(digest, hashfunc=hashlib.sha256) + assert binascii.hexlify(sig) == binascii.hexlify(sig_ref) + + assert vk.verify_digest(sig, digest, sigdecode) diff --git a/tests.c b/tests.c index fc797ee1d..9b40d83c5 100644 --- a/tests.c +++ b/tests.c @@ -37,6 +37,13 @@ #include "rand.h" #include "sha2.h" #include "options.h" +#include "secp256k1.h" + +#define CURVE (&secp256k1) +#define prime256k1 (secp256k1.prime) +#define G256k1 (secp256k1.G) +#define order256k1 (secp256k1.order) +#define secp256k1_cp (secp256k1.cp) uint8_t *fromhex(const char *str) { @@ -502,7 +509,7 @@ END_TEST #define test_deterministic(KEY, MSG, K) do { \ sha256_Raw((uint8_t *)MSG, strlen(MSG), buf); \ - res = generate_k_rfc6979(&k, fromhex(KEY), buf); \ + res = generate_k_rfc6979(CURVE, &k, fromhex(KEY), buf); \ ck_assert_int_eq(res, 0); \ bn_write_be(&k, buf); \ ck_assert_mem_eq(buf, fromhex(K), 32); \ @@ -537,13 +544,13 @@ START_TEST(test_sign_speed) memcpy(priv_key, fromhex("c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd5"), 32); for (i = 0 ; i < 250; i++) { - res = ecdsa_sign(priv_key, msg, sizeof(msg), sig, 0); + res = ecdsa_sign(CURVE, priv_key, msg, sizeof(msg), sig, 0); ck_assert_int_eq(res, 0); } memcpy(priv_key, fromhex("509a0382ff5da48e402967a671bdcde70046d07f0df52cff12e8e3883b426a0a"), 32); for (i = 0 ; i < 250; i++) { - res = ecdsa_sign(priv_key, msg, sizeof(msg), sig, 0); + res = ecdsa_sign(CURVE, priv_key, msg, sizeof(msg), sig, 0); ck_assert_int_eq(res, 0); } @@ -568,9 +575,9 @@ START_TEST(test_verify_speed) memcpy(pub_key65, fromhex("044054fd18aeb277aeedea01d3f3986ff4e5be18092a04339dcf4e524e2c0a09746c7083ed2097011b1223a17a644e81f59aa3de22dac119fd980b36a8ff29a244"), 65); for (i = 0 ; i < 25; i++) { - res = ecdsa_verify(pub_key65, sig, msg, sizeof(msg)); + res = ecdsa_verify(CURVE, pub_key65, sig, msg, sizeof(msg)); ck_assert_int_eq(res, 0); - res = ecdsa_verify(pub_key33, sig, msg, sizeof(msg)); + res = ecdsa_verify(CURVE, pub_key33, sig, msg, sizeof(msg)); ck_assert_int_eq(res, 0); } @@ -579,9 +586,9 @@ START_TEST(test_verify_speed) memcpy(pub_key65, fromhex("04ff45a5561a76be930358457d113f25fac790794ec70317eff3b97d7080d457196235193a15778062ddaa44aef7e6901b781763e52147f2504e268b2d572bf197"), 65); for (i = 0 ; i < 25; i++) { - res = ecdsa_verify(pub_key65, sig, msg, sizeof(msg)); + res = ecdsa_verify(CURVE, pub_key65, sig, msg, sizeof(msg)); ck_assert_int_eq(res, 0); - res = ecdsa_verify(pub_key33, sig, msg, sizeof(msg)); + res = ecdsa_verify(CURVE, pub_key33, sig, msg, sizeof(msg)); ck_assert_int_eq(res, 0); } @@ -1034,43 +1041,43 @@ START_TEST(test_pubkey_validity) int res; memcpy(pub_key, fromhex("0226659c1cf7321c178c07437150639ff0c5b7679c7ea195253ed9abda2e081a37"), 33); - res = ecdsa_read_pubkey(pub_key, &pub); + res = ecdsa_read_pubkey(CURVE, pub_key, &pub); ck_assert_int_eq(res, 1); memcpy(pub_key, fromhex("025b1654a0e78d28810094f6c5a96b8efb8a65668b578f170ac2b1f83bc63ba856"), 33); - res = ecdsa_read_pubkey(pub_key, &pub); + res = ecdsa_read_pubkey(CURVE, pub_key, &pub); ck_assert_int_eq(res, 1); memcpy(pub_key, fromhex("03433f246a12e6486a51ff08802228c61cf895175a9b49ed4766ea9a9294a3c7fe"), 33); - res = ecdsa_read_pubkey(pub_key, &pub); + res = ecdsa_read_pubkey(CURVE, pub_key, &pub); ck_assert_int_eq(res, 1); memcpy(pub_key, fromhex("03aeb03abeee0f0f8b4f7a5d65ce31f9570cef9f72c2dd8a19b4085a30ab033d48"), 33); - res = ecdsa_read_pubkey(pub_key, &pub); + res = ecdsa_read_pubkey(CURVE, pub_key, &pub); ck_assert_int_eq(res, 1); memcpy(pub_key, fromhex("0496e8f2093f018aff6c2e2da5201ee528e2c8accbf9cac51563d33a7bb74a016054201c025e2a5d96b1629b95194e806c63eb96facaedc733b1a4b70ab3b33e3a"), 65); - res = ecdsa_read_pubkey(pub_key, &pub); + res = ecdsa_read_pubkey(CURVE, pub_key, &pub); ck_assert_int_eq(res, 1); memcpy(pub_key, fromhex("0498010f8a687439ff497d3074beb4519754e72c4b6220fb669224749591dde416f3961f8ece18f8689bb32235e436874d2174048b86118a00afbd5a4f33a24f0f"), 65); - res = ecdsa_read_pubkey(pub_key, &pub); + res = ecdsa_read_pubkey(CURVE, pub_key, &pub); ck_assert_int_eq(res, 1); memcpy(pub_key, fromhex("04f80490839af36d13701ec3f9eebdac901b51c362119d74553a3c537faff31b17e2a59ebddbdac9e87b816307a7ed5b826b8f40b92719086238e1bebf19b77a4d"), 65); - res = ecdsa_read_pubkey(pub_key, &pub); + res = ecdsa_read_pubkey(CURVE, pub_key, &pub); ck_assert_int_eq(res, 1); memcpy(pub_key, fromhex("04f80490839af36d13701ec3f9eebdac901b51c362119d74553a3c537faff31b17e2a59ebddbdac9e87b816307a7ed5b826b8f40b92719086238e1bebf00000000"), 65); - res = ecdsa_read_pubkey(pub_key, &pub); + res = ecdsa_read_pubkey(CURVE, pub_key, &pub); ck_assert_int_eq(res, 0); memcpy(pub_key, fromhex("04f80490839af36d13701ec3f9eebdac901b51c362119d74553a3c537faff31b17e2a59ebddbdac9e87b816307a7ed5b8211111111111111111111111111111111"), 65); - res = ecdsa_read_pubkey(pub_key, &pub); + res = ecdsa_read_pubkey(CURVE, pub_key, &pub); ck_assert_int_eq(res, 0); memcpy(pub_key, fromhex("00"), 1); - res = ecdsa_read_pubkey(pub_key, &pub); + res = ecdsa_read_pubkey(CURVE, pub_key, &pub); ck_assert_int_eq(res, 0); } END_TEST @@ -1214,21 +1221,21 @@ START_TEST(test_secp256k1_cp) { bn_normalize(&a); // note that this is not a trivial test. We add 64 curve // points in the table to get that particular curve point. - scalar_multiply(&a, &p); + scalar_multiply(CURVE, &a, &p); ck_assert_mem_eq(&p, &secp256k1_cp[i][j], sizeof(curve_point)); - bn_zero(&p.y); // test that point_multiply is not a noop - point_multiply(&a, &G256k1, &p); + bn_zero(&p.y); // test that point_multiply CURVE, is not a noop + point_multiply(CURVE, &a, &G256k1, &p); ck_assert_mem_eq(&p, &secp256k1_cp[i][j], sizeof(curve_point)); // even/odd has different behaviour; // increment by one and test again p1 = p; - point_add(&G256k1, &p1); + point_add(CURVE, &G256k1, &p1); bn_addmodi(&a, 1, &order256k1); - scalar_multiply(&a, &p); + scalar_multiply(CURVE, &a, &p); ck_assert_mem_eq(&p, &p1, sizeof(curve_point)); - bn_zero(&p.y); // test that point_multiply is not a noop - point_multiply(&a, &G256k1, &p); + bn_zero(&p.y); // test that point_multiply CURVE, is not a noop + point_multiply(CURVE, &a, &G256k1, &p); ck_assert_mem_eq(&p, &p1, sizeof(curve_point)); } } @@ -1240,43 +1247,43 @@ START_TEST(test_mult_border_cases) { curve_point p; curve_point expected; bn_zero(&a); // a == 0 - scalar_multiply(&a, &p); + scalar_multiply(CURVE, &a, &p); ck_assert(point_is_infinity(&p)); - point_multiply(&a, &p, &p); + point_multiply(CURVE, &a, &p, &p); ck_assert(point_is_infinity(&p)); - point_multiply(&a, &G256k1, &p); + point_multiply(CURVE, &a, &G256k1, &p); ck_assert(point_is_infinity(&p)); bn_addmodi(&a, 1, &order256k1); // a == 1 - scalar_multiply(&a, &p); + scalar_multiply(CURVE, &a, &p); ck_assert_mem_eq(&p, &G256k1, sizeof(curve_point)); - point_multiply(&a, &G256k1, &p); + point_multiply(CURVE, &a, &G256k1, &p); ck_assert_mem_eq(&p, &G256k1, sizeof(curve_point)); bn_subtract(&order256k1, &a, &a); // a == -1 expected = G256k1; bn_subtract(&prime256k1, &expected.y, &expected.y); - scalar_multiply(&a, &p); + scalar_multiply(CURVE, &a, &p); ck_assert_mem_eq(&p, &expected, sizeof(curve_point)); - point_multiply(&a, &G256k1, &p); + point_multiply(CURVE, &a, &G256k1, &p); ck_assert_mem_eq(&p, &expected, sizeof(curve_point)); bn_subtract(&order256k1, &a, &a); bn_addmodi(&a, 1, &order256k1); // a == 2 expected = G256k1; - point_add(&expected, &expected); - scalar_multiply(&a, &p); + point_add(CURVE, &expected, &expected); + scalar_multiply(CURVE, &a, &p); ck_assert_mem_eq(&p, &expected, sizeof(curve_point)); - point_multiply(&a, &G256k1, &p); + point_multiply(CURVE, &a, &G256k1, &p); ck_assert_mem_eq(&p, &expected, sizeof(curve_point)); bn_subtract(&order256k1, &a, &a); // a == -2 expected = G256k1; - point_add(&expected, &expected); + point_add(CURVE, &expected, &expected); bn_subtract(&prime256k1, &expected.y, &expected.y); - scalar_multiply(&a, &p); + scalar_multiply(CURVE, &a, &p); ck_assert_mem_eq(&p, &expected, sizeof(curve_point)); - point_multiply(&a, &G256k1, &p); + point_multiply(CURVE, &a, &G256k1, &p); ck_assert_mem_eq(&p, &expected, sizeof(curve_point)); } END_TEST @@ -1289,11 +1296,11 @@ START_TEST(test_scalar_mult) { curve_point p1, p2, p3; for (i = 0; i < 1000; i++) { /* test distributivity: (a + b)G = aG + bG */ - scalar_multiply(&a, &p1); - scalar_multiply(&b, &p2); + scalar_multiply(CURVE, &a, &p1); + scalar_multiply(CURVE, &b, &p2); bn_addmod(&a, &b, &order256k1); - scalar_multiply(&a, &p3); - point_add(&p1, &p2); + scalar_multiply(CURVE, &a, &p3); + point_add(CURVE, &p1, &p2); ck_assert_mem_eq(&p2, &p3, sizeof(curve_point)); // new "random" numbers a = p3.x; @@ -1311,11 +1318,11 @@ START_TEST(test_point_mult) { curve_point p1, p2, p3; for (i = 0; i < 200; i++) { /* test distributivity: (a + b)P = aP + bP */ - point_multiply(&a, &p, &p1); - point_multiply(&b, &p, &p2); + point_multiply(CURVE, &a, &p, &p1); + point_multiply(CURVE, &b, &p, &p2); bn_addmod(&a, &b, &order256k1); - point_multiply(&a, &p, &p3); - point_add(&p1, &p2); + point_multiply(CURVE, &a, &p, &p3); + point_add(CURVE, &p1, &p2); ck_assert_mem_eq(&p2, &p3, sizeof(curve_point)); // new "random" numbers and a "random" point a = p1.x; @@ -1335,16 +1342,16 @@ START_TEST(test_scalar_point_mult) { /* test commutativity and associativity: * a(bG) = (ab)G = b(aG) */ - scalar_multiply(&a, &p1); - point_multiply(&b, &p1, &p1); + scalar_multiply(CURVE, &a, &p1); + point_multiply(CURVE, &b, &p1, &p1); - scalar_multiply(&b, &p2); - point_multiply(&a, &p2, &p2); + scalar_multiply(CURVE, &b, &p2); + point_multiply(CURVE, &a, &p2, &p2); ck_assert_mem_eq(&p1, &p2, sizeof(curve_point)); bn_multiply(&a, &b, &order256k1); - scalar_multiply(&b, &p2); + scalar_multiply(CURVE, &b, &p2); ck_assert_mem_eq(&p1, &p2, sizeof(curve_point)); diff --git a/tools/.gitignore b/tools/.gitignore index 497e59540..da1bc3702 100644 --- a/tools/.gitignore +++ b/tools/.gitignore @@ -1,3 +1,3 @@ xpubaddrgen -mksecptable +mktable bip39bruteforce diff --git a/tools/Makefile b/tools/Makefile index bc7168648..61032e658 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -23,9 +23,9 @@ CFLAGS += $(OPTFLAGS) \ -Werror \ -I.. -all: xpubaddrgen mksecptable bip39bruteforce +all: xpubaddrgen mktable bip39bruteforce -OBJS = ../bip32.o ../bip39.o ../ecdsa.o ../sha2.o ../bignum.o ../base58.o ../secp256k1.o ../ripemd160.o ../hmac.o ../rand.o ../pbkdf2.o +OBJS = ../bip32.o ../bip39.o ../ecdsa.o ../sha2.o ../bignum.o ../base58.o ../secp256k1.o ../nist256p1.o ../ripemd160.o ../hmac.o ../rand.o ../pbkdf2.o %.o: %.c %.h options.h $(CC) $(CFLAGS) -o $@ -c $< @@ -33,11 +33,11 @@ OBJS = ../bip32.o ../bip39.o ../ecdsa.o ../sha2.o ../bignum.o ../base58.o ../sec xpubaddrgen: xpubaddrgen.o $(OBJS) $(CC) xpubaddrgen.o $(OBJS) -o xpubaddrgen -mksecptable: mksecptable.o $(OBJS) - $(CC) mksecptable.o $(OBJS) -o mksecptable +mktable: mktable.o $(OBJS) + $(CC) mktable.o $(OBJS) -o mktable bip39bruteforce: bip39bruteforce.o $(OBJS) $(CC) bip39bruteforce.o $(OBJS) -o bip39bruteforce clean: - rm -f *.o xpubaddrgen mksecptable bip39bruteforce + rm -f *.o xpubaddrgen mktable bip39bruteforce diff --git a/tools/README.md b/tools/README.md index 93ea9fb1d..7786244de 100644 --- a/tools/README.md +++ b/tools/README.md @@ -45,9 +45,10 @@ It will print ``` error``` when there was an error processing job jobid. It will print ```error``` when it encountered a malformed line. -mksecptable +mktable ----------- -mksecptable computes the points of the form `(2*j+1)*16^i*G` and prints them in the format to be included in `secp256k1.c`. These points are used by the fast ECC multiplication. +mktable computes the points of the form `(2*j+1)*16^i*G` and prints them in the format to be included in `secp256k1.c` and `nist256p1.c`. +These points are used by the fast ECC multiplication. It is only meant to be run if the `scalar_mult` algorithm changes. diff --git a/tools/mksecptable.c b/tools/mktable.c similarity index 72% rename from tools/mksecptable.c rename to tools/mktable.c index b305e4713..f509a941d 100644 --- a/tools/mksecptable.c +++ b/tools/mktable.c @@ -10,10 +10,21 @@ * The entry secp256k1_cp[i][j] contains the number (2*j+1)*16^i*G, * where G is the generator of secp256k1. */ -int main(int __attribute__((unused)) argc, char __attribute__((unused)) **argv) { +int main(int argc, char **argv) { int i,j,k; - curve_point ng = G256k1; - curve_point pow2ig = G256k1; + if (argc != 2) { + printf("Usage: %s CURVE_NAME\n", argv[0]); + return 1; + } + const char *name = argv[1]; + const ecdsa_curve *curve = get_curve_by_name(name); + if (curve == 0) { + printf("Unknown curve '%s'\n", name); + return 1; + } + + curve_point ng = curve->G; + curve_point pow2ig = curve->G; for (i = 0; i < 64; i++) { // invariants: // pow2ig = 16^i * G @@ -29,7 +40,7 @@ int main(int __attribute__((unused)) argc, char __attribute__((unused)) **argv) bn_zero(&a); a.val[(4*i) / 30] = ((uint32_t) 2*j+1) << ((4*i) % 30); bn_normalize(&a); - point_multiply(&a, &G256k1, &checkresult); + point_multiply(curve, &a, &curve->G, &checkresult); assert(point_is_equal(&checkresult, &ng)); #endif printf("\t\t/* %2d*16^%d*G: */\n\t\t{{{", 2*j + 1, i); @@ -46,9 +57,9 @@ int main(int __attribute__((unused)) argc, char __attribute__((unused)) **argv) printf("}}}\n\t},\n"); } else { printf("}}},\n"); - point_add(&pow2ig, &ng); + point_add(curve, &pow2ig, &ng); } - point_add(&pow2ig, &ng); + point_add(curve, &pow2ig, &ng); } pow2ig = ng; } From 36847ac0d7789c514a17168d49f8bd56b35b71aa Mon Sep 17 00:00:00 2001 From: Roman Zeyde Date: Sat, 27 Jun 2015 10:08:18 +0300 Subject: [PATCH 190/627] ecdsa: generate_k_rfc6979() should cleanup its stack before exit --- ecdsa.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/ecdsa.c b/ecdsa.c index 1462ad5eb..afdd95773 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -608,7 +608,7 @@ int generate_k_random(bignum256 *k) { // http://tools.ietf.org/html/rfc6979 int generate_k_rfc6979(bignum256 *secret, const uint8_t *priv_key, const uint8_t *hash) { - int i; + int i, error; uint8_t v[32], k[32], bx[2*32], buf[32 + 1 + sizeof(bx)]; bignum256 z1; @@ -632,11 +632,13 @@ int generate_k_rfc6979(bignum256 *secret, const uint8_t *priv_key, const uint8_t hmac_sha256(k, sizeof(k), buf, sizeof(buf), k); hmac_sha256(k, sizeof(k), v, sizeof(v), v); + error = 1; for (i = 0; i < 10000; i++) { hmac_sha256(k, sizeof(k), v, sizeof(v), v); bn_read_be(v, secret); if ( !bn_is_zero(secret) && bn_is_less(secret, &order256k1) ) { - return 0; // good number -> no error + error = 0; // good number -> no error + break; } memcpy(buf, v, sizeof(v)); buf[sizeof(v)] = 0x00; @@ -644,7 +646,12 @@ int generate_k_rfc6979(bignum256 *secret, const uint8_t *priv_key, const uint8_t hmac_sha256(k, sizeof(k), v, sizeof(v), v); } // we generated 10000 numbers, none of them is good -> fail - return 1; + + MEMSET_BZERO(v, sizeof(v)); + MEMSET_BZERO(k, sizeof(k)); + MEMSET_BZERO(bx, sizeof(bx)); + MEMSET_BZERO(buf, sizeof(buf)); + return error; } // msg is a data to be signed From d2120d6da1a93dcdb443d0b13a9a3817363db320 Mon Sep 17 00:00:00 2001 From: Josh Billings Date: Mon, 6 Jul 2015 12:43:30 -0400 Subject: [PATCH 191/627] two bugfixes: 1. nist256p1.c was not included in setup.py, causing import errors when using TrezorCrypto.so in Python. 2. if you attempted a hardened derivation in python using the compiled TrezorCrypto module, an IntegerOverflowError would occur because Python ints are always signed. one-line fix by changing int to unsigned int in the pyx file --- TrezorCrypto.pyx | 3 +-- setup.py | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/TrezorCrypto.pyx b/TrezorCrypto.pyx index 64903ff38..2babddb32 100644 --- a/TrezorCrypto.pyx +++ b/TrezorCrypto.pyx @@ -1,6 +1,5 @@ cimport c cimport cython - cdef class HDNode: cdef c.HDNode node @@ -34,7 +33,7 @@ cdef class HDNode: c.hdnode_public_ckd(cython.address(x.node), i) return x - def private_ckd(self, int i): + def private_ckd(self, unsigned int i): x = HDNode(copyfrom=self) c.hdnode_private_ckd(cython.address(x.node), i) return x diff --git a/setup.py b/setup.py index 106171681..0aadea8e2 100755 --- a/setup.py +++ b/setup.py @@ -5,6 +5,7 @@ from Cython.Build import cythonize from Cython.Distutils import build_ext srcs = [ + 'nist256p1', 'base58', 'bignum', 'bip32', From cb0b5169c5aa82d3e62416cf041d7485b9e2405b Mon Sep 17 00:00:00 2001 From: Josh Billings Date: Mon, 6 Jul 2015 12:48:11 -0400 Subject: [PATCH 192/627] whitespace --- TrezorCrypto.pyx | 1 + setup.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/TrezorCrypto.pyx b/TrezorCrypto.pyx index 2babddb32..71490f8f9 100644 --- a/TrezorCrypto.pyx +++ b/TrezorCrypto.pyx @@ -1,5 +1,6 @@ cimport c cimport cython + cdef class HDNode: cdef c.HDNode node diff --git a/setup.py b/setup.py index 0aadea8e2..a06f57cb1 100755 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ from Cython.Build import cythonize from Cython.Distutils import build_ext srcs = [ - 'nist256p1', + 'nist256p1', 'base58', 'bignum', 'bip32', From 587d6a65ea84f8927c9795d7051a2db791bc0154 Mon Sep 17 00:00:00 2001 From: Roman Zeyde Date: Tue, 7 Jul 2015 10:38:16 +0300 Subject: [PATCH 193/627] Update documentation regarding ECDSA curves support --- README.md | 2 +- bignum.c | 2 +- tools/mktable.c | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index f694357fa..435f9f1ad 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ These include: - Big Number (256 bit) Arithmetics - BIP32 Hierarchical Deterministic Wallets - BIP39 Mnemonic code -- ECDSA signing/verifying (only hardcoded secp256k1 curve, +- ECDSA signing/verifying (supports secp256k1 and nist256p1 curves, uses RFC6979 for deterministic signatures) - ECDSA public key derivation + Base58 address representation - HMAC-SHA256 and HMAC-SHA512 diff --git a/bignum.c b/bignum.c index 050078a09..dee2f72a0 100644 --- a/bignum.c +++ b/bignum.c @@ -364,7 +364,7 @@ void bn_inverse(bignum256 *x, const bignum256 *prime) // res = old(x)^((prime-2) % 2^(i*30)) // get the i-th limb of prime - 2 limb = prime->val[i]; - // this is not enough in general but fine for secp256k1 because prime->val[0] > 1 + // this is not enough in general but fine for secp256k1 & nist256p1 because prime->val[0] > 1 if (i == 0) limb -= 2; for (j = 0; j < 30; j++) { // invariants: diff --git a/tools/mktable.c b/tools/mktable.c index f509a941d..e7ff12c26 100644 --- a/tools/mktable.c +++ b/tools/mktable.c @@ -6,9 +6,9 @@ #include "rand.h" /* - * This program prints the contents of the secp256k1_cp array. - * The entry secp256k1_cp[i][j] contains the number (2*j+1)*16^i*G, - * where G is the generator of secp256k1. + * This program prints the contents of the ecdsa_curve.cp array. + * The entry cp[i][j] contains the number (2*j+1)*16^i*G, + * where G is the generator of the specified elliptic curve. */ int main(int argc, char **argv) { int i,j,k; From ea16aa0b86761c1393c203aec7176976966fee74 Mon Sep 17 00:00:00 2001 From: Roman Zeyde Date: Tue, 7 Jul 2015 10:39:12 +0300 Subject: [PATCH 194/627] Remove unnecessary #include "secp256k1.h" --- bignum.c | 1 - tools/mktable.c | 1 - 2 files changed, 2 deletions(-) diff --git a/bignum.c b/bignum.c index dee2f72a0..694df3c7c 100644 --- a/bignum.c +++ b/bignum.c @@ -25,7 +25,6 @@ #include #include #include "bignum.h" -#include "secp256k1.h" #include "macros.h" inline uint32_t read_be(const uint8_t *data) diff --git a/tools/mktable.c b/tools/mktable.c index e7ff12c26..77997039d 100644 --- a/tools/mktable.c +++ b/tools/mktable.c @@ -2,7 +2,6 @@ #include #include "bignum.h" #include "ecdsa.h" -#include "secp256k1.h" #include "rand.h" /* From 749cf8b75fbbe4995d3840866ece79b992f86261 Mon Sep 17 00:00:00 2001 From: Roman Zeyde Date: Tue, 7 Jul 2015 10:58:08 +0300 Subject: [PATCH 195/627] gui: fixup after ECDSA updates --- gui/gui.pro | 2 +- gui/mainwindow.cpp | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/gui/gui.pro b/gui/gui.pro index 9b9c73af9..2ac6ec09a 100644 --- a/gui/gui.pro +++ b/gui/gui.pro @@ -4,7 +4,7 @@ greaterThan(QT_MAJOR_VERSION, 4): QT += widgets TARGET = gui TEMPLATE = app -SOURCES += ../bip32.c ../bip39.c ../sha2.c ../pbkdf2.c ../hmac.c ../rand.c ../bignum.c ../ecdsa.c ../ripemd160.c ../base58.c ../secp256k1.c mainwindow.cpp main.cpp +SOURCES += ../bip32.c ../bip39.c ../sha2.c ../pbkdf2.c ../hmac.c ../rand.c ../bignum.c ../ecdsa.c ../ripemd160.c ../base58.c ../secp256k1.c ../nist256p1.c mainwindow.cpp main.cpp HEADERS += mainwindow.h ../bip32.h ../bip39.h diff --git a/gui/mainwindow.cpp b/gui/mainwindow.cpp index b3a19296f..a67d28857 100644 --- a/gui/mainwindow.cpp +++ b/gui/mainwindow.cpp @@ -45,7 +45,8 @@ void MainWindow::on_spinAccount_valueChanged(int arg1) { if (!root_set) return; const char addr_version = 0x00, wif_version = 0x80; - char buf[128]; + const size_t buflen = 128; + char buf[buflen + 1]; HDNode node; // external chain for (int chain = 0; chain < 2; chain++) { @@ -54,14 +55,14 @@ void MainWindow::on_spinAccount_valueChanged(int arg1) hdnode_private_ckd(&node, 44 | 0x80000000); hdnode_private_ckd(&node, 0 | 0x80000000); // bitcoin hdnode_private_ckd(&node, (arg1 - 1) | 0x80000000); - hdnode_serialize_private(&node, buf); QString xprv = QString(buf); ui->lineXprv->setText(xprv); - hdnode_serialize_public(&node, buf); QString xpub = QString(buf); ui->lineXpub->setText(xpub); + hdnode_serialize_private(&node, buf, buflen); QString xprv = QString(buf); ui->lineXprv->setText(xprv); + hdnode_serialize_public(&node, buf, buflen); QString xpub = QString(buf); ui->lineXpub->setText(xpub); hdnode_private_ckd(&node, chain); // external / internal for (int i = 0; i < 100; i++) { HDNode node2 = node; hdnode_private_ckd(&node2, i); - ecdsa_get_address(node2.public_key, addr_version, buf); QString address = QString(buf); - ecdsa_get_wif(node2.private_key, wif_version, buf); QString wif = QString(buf); + ecdsa_get_address(node2.public_key, addr_version, buf, buflen); QString address = QString(buf); + ecdsa_get_wif(node2.private_key, wif_version, buf, buflen); QString wif = QString(buf); list->setItem(i, 0, new QTableWidgetItem(address)); list->setItem(i, 1, new QTableWidgetItem(wif)); list->setItem(i, 2, new QTableWidgetItem("0.0")); From 9c3e51074be962995fa3934f910721283567f94d Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 7 Jul 2015 18:30:33 +0200 Subject: [PATCH 196/627] use -O3 instead of -Os --- Makefile | 2 +- test_curves.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) mode change 100644 => 100755 test_curves.py diff --git a/Makefile b/Makefile index 05882e66c..ebf87be6c 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ CC = gcc -OPTFLAGS = -Os -g +OPTFLAGS = -O3 -g CFLAGS += $(OPTFLAGS) \ -W \ diff --git a/test_curves.py b/test_curves.py old mode 100644 new mode 100755 index 83d8c2ba9..4a73b24b9 --- a/test_curves.py +++ b/test_curves.py @@ -1,3 +1,4 @@ +#!/usr/bin/python import ctypes as c import random import ecdsa @@ -25,7 +26,7 @@ random_iters = int(os.environ.get('ITERS', 1)) scons_file = ''' srcs = 'ecdsa bignum secp256k1 nist256p1 sha2 rand hmac ripemd160 base58' srcs = [(s + '.c') for s in srcs.split()] -flags = ('-Os -g -W -Wall -Wextra -Wimplicit-function-declaration ' +flags = ('-O3 -g -W -Wall -Wextra -Wimplicit-function-declaration ' '-Wredundant-decls -Wstrict-prototypes -Wundef -Wshadow ' '-Wpointer-arith -Wformat -Wreturn-type -Wsign-compare -Wmultichar ' '-Wformat-nonliteral -Winit-self -Wuninitialized -Wformat-security ' From e569b019c413a780732dc8c10a8fa4fb3e997307 Mon Sep 17 00:00:00 2001 From: Roman Zeyde Date: Fri, 24 Jul 2015 10:44:56 +0300 Subject: [PATCH 197/627] test_curves: fix test case name typo --- test_curves.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test_curves.py b/test_curves.py index 4a73b24b9..2ee15e90b 100755 --- a/test_curves.py +++ b/test_curves.py @@ -97,7 +97,7 @@ def test_inverse(curve, r): assert y == y_ -def test_inverse(curve, r): +def test_mult_half(curve, r): x = r.randrange(0, 2*curve.p) y = int2bn(x) lib.bn_mult_half(y, int2bn(curve.p)) From f9df01c6e64b5ddc32d3d48e4055094774c0e718 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 29 Jul 2015 16:35:10 +0200 Subject: [PATCH 198/627] add CONTRIBUTORS file generated using the following: git log --format='%aN <%aE>' --no-merges | sort | uniq -c | sort -nr --- CONTRIBUTORS | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 CONTRIBUTORS diff --git a/CONTRIBUTORS b/CONTRIBUTORS new file mode 100644 index 000000000..7e5175b01 --- /dev/null +++ b/CONTRIBUTORS @@ -0,0 +1,14 @@ +Tomas Dzetkulic +Pavol Rusnak +Jochen Hoenicke +Dustin Laurence +Ondrej Mikle +Roman Zeyde +netanelkl +Jan Pochyla +Ondrej Mikle +Josh Billings +Adam Mackler +Oleg Andreev +mog +John Dvorak From 1163992e5c94319bb669527abf44f378fc2a50b3 Mon Sep 17 00:00:00 2001 From: Roman Zeyde Date: Wed, 29 Jul 2015 20:52:42 +0300 Subject: [PATCH 199/627] travis: add simple tests --- .travis.yml | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..822dd87a6 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,9 @@ +language: c + + +install: + - sudo apt-get install check + +script: + - make tests + - ./tests From 0164137786fd17df65fb0ad2723aa26bdf1c372e Mon Sep 17 00:00:00 2001 From: Roman Zeyde Date: Wed, 29 Jul 2015 21:49:00 +0300 Subject: [PATCH 200/627] tests: fix signedness error --- tests.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests.c b/tests.c index 9b40d83c5..511993df1 100644 --- a/tests.c +++ b/tests.c @@ -152,7 +152,7 @@ START_TEST(test_base58) memcpy(rawn, fromhex(*raw), len); r = base58_encode_check(rawn, len, strn, sizeof(strn)); - ck_assert_int_eq(r, strlen(*str) + 1); + ck_assert_int_eq((size_t)r, strlen(*str) + 1); ck_assert_str_eq(strn, *str); r = base58_decode_check(strn, rawn, len); From f91e912dd211929d9a172e33b5df312356074028 Mon Sep 17 00:00:00 2001 From: Roman Zeyde Date: Wed, 29 Jul 2015 21:53:36 +0300 Subject: [PATCH 201/627] README: add travis badge --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 435f9f1ad..90dbf421a 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ trezor-crypto ============= +[![Build Status](https://travis-ci.org/trezor/trezor-crypto.svg?branch=master)](https://travis-ci.org/trezor/trezor-crypto) + Heavily optimized cryptography algorithms for embedded devices. These include: From cfbd09d158bd26e12d4b563f9c2d6fb445f319fd Mon Sep 17 00:00:00 2001 From: Roman Zeyde Date: Fri, 31 Jul 2015 10:55:06 +0300 Subject: [PATCH 202/627] travis: use container-based infrastructure --- .travis.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 822dd87a6..b83b41ad8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,10 @@ +sudo: false language: c - -install: - - sudo apt-get install check +addons: + apt: + packages: + - check script: - make tests From 8a3ee52d63f8ba45a3268c293a7ebbf21c1a86f8 Mon Sep 17 00:00:00 2001 From: Roman Zeyde Date: Fri, 31 Jul 2015 11:09:15 +0300 Subject: [PATCH 203/627] travis: add openssl tests --- .travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index b83b41ad8..c0182b5eb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,9 @@ addons: apt: packages: - check + - libssl-dev script: - - make tests + - make - ./tests + - ./test-openssl 1000 From 558b3fd65b367956bab6ecf149750b711a45ebdd Mon Sep 17 00:00:00 2001 From: Roman Zeyde Date: Fri, 31 Jul 2015 11:16:30 +0300 Subject: [PATCH 204/627] travis: add pytest (for test_curves.py) --- .travis.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.travis.yml b/.travis.yml index c0182b5eb..c36250fc8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,8 +6,13 @@ addons: packages: - check - libssl-dev + - python-pip + +install: + - pip install --user pytest ecdsa script: - make - ./tests - ./test-openssl 1000 + - ITERS=10 py.test From 793234a0ec4ea887aed1a4290cc1522f0b7b1473 Mon Sep 17 00:00:00 2001 From: Roman Zeyde Date: Sun, 2 Aug 2015 22:01:49 +0300 Subject: [PATCH 205/627] bignum: use constant time comparisons --- bignum.c | 18 +++++++++++------- test_curves.py | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 7 deletions(-) diff --git a/bignum.c b/bignum.c index 694df3c7c..7796a0e09 100644 --- a/bignum.c +++ b/bignum.c @@ -88,28 +88,32 @@ void bn_zero(bignum256 *a) int bn_is_zero(const bignum256 *a) { int i; + uint32_t result = 0; for (i = 0; i < 9; i++) { - if (a->val[i] != 0) return 0; + result |= a->val[i]; } - return 1; + return !result; } int bn_is_less(const bignum256 *a, const bignum256 *b) { int i; + uint32_t res1 = 0; + uint32_t res2 = 0; for (i = 8; i >= 0; i--) { - if (a->val[i] < b->val[i]) return 1; - if (a->val[i] > b->val[i]) return 0; + res1 = (res1 << 1) | (a->val[i] < b->val[i]); + res2 = (res2 << 1) | (a->val[i] > b->val[i]); } - return 0; + return res1 > res2; } int bn_is_equal(const bignum256 *a, const bignum256 *b) { int i; + uint32_t result = 0; for (i = 0; i < 9; i++) { - if (a->val[i] != b->val[i]) return 0; + result |= (a->val[i] ^ b->val[i]); } - return 1; + return !result; } int bn_bitlen(const bignum256 *a) { diff --git a/test_curves.py b/test_curves.py index 2ee15e90b..57df5e946 100755 --- a/test_curves.py +++ b/test_curves.py @@ -97,6 +97,48 @@ def test_inverse(curve, r): assert y == y_ +def test_is_less(curve, r): + x = r.randrange(0, curve.p) + y = r.randrange(0, curve.p) + x_ = int2bn(x) + y_ = int2bn(y) + + res = lib.bn_is_less(x_, y_) + assert res == (x < y) + + res = lib.bn_is_less(y_, x_) + assert res == (y < x) + + +def test_is_equal(curve, r): + x = r.randrange(0, curve.p) + y = r.randrange(0, curve.p) + x_ = int2bn(x) + y_ = int2bn(y) + + assert lib.bn_is_equal(x_, y_) == (x == y) + assert lib.bn_is_equal(x_, x_) == 1 + assert lib.bn_is_equal(y_, y_) == 1 + + +def test_is_zero(curve, r): + x = r.randrange(0, curve.p); + assert lib.bn_is_zero(int2bn(x)) == (not x) + + +def test_simple_comparisons(): + assert lib.bn_is_zero(int2bn(0)) == 1 + assert lib.bn_is_zero(int2bn(1)) == 0 + + assert lib.bn_is_less(int2bn(0), int2bn(0)) == 0 + assert lib.bn_is_less(int2bn(1), int2bn(0)) == 0 + assert lib.bn_is_less(int2bn(0), int2bn(1)) == 1 + + assert lib.bn_is_equal(int2bn(0), int2bn(0)) == 1 + assert lib.bn_is_equal(int2bn(1), int2bn(0)) == 0 + assert lib.bn_is_equal(int2bn(0), int2bn(1)) == 0 + + def test_mult_half(curve, r): x = r.randrange(0, 2*curve.p) y = int2bn(x) From d659fd49a56992c8e903f7957bd3b221e3bc0f12 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 3 Aug 2015 21:31:15 +0200 Subject: [PATCH 206/627] return back normalization of signatures --- ecdsa.c | 7 +++++++ ecdsa.h | 9 +++++---- nist256p1.c | 4 ++++ secp256k1.c | 4 ++++ 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/ecdsa.c b/ecdsa.c index ac5aa3d8c..380ddaabf 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -734,6 +734,13 @@ int ecdsa_sign_digest(const ecdsa_curve *curve, const uint8_t *priv_key, const u } if (result == 0) { + // if S > order/2 => S = -S + if (bn_is_less(&curve->order_half, &k)) { + bn_subtract(&curve->order, &k, &k); + if (pby) { + *pby = !*pby; + } + } // we are done, R.x and k is the result signature bn_write_be(&R.x, sig); bn_write_be(&k, sig + 32); diff --git a/ecdsa.h b/ecdsa.h index 85fe434b7..cb78206fd 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -35,10 +35,11 @@ typedef struct { typedef struct { - bignum256 prime; // prime order of the finite field - curve_point G; // initial curve point - bignum256 order; // order of G - bignum256 a; // coefficient 'a' of the elliptic curve + bignum256 prime; // prime order of the finite field + curve_point G; // initial curve point + bignum256 order; // order of G + bignum256 order_half; // order of G divided by 2 + bignum256 a; // coefficient 'a' of the elliptic curve #if USE_PRECOMPUTED_CP const curve_point cp[64][8]; diff --git a/nist256p1.c b/nist256p1.c index f6468b9bf..8aedb2c13 100644 --- a/nist256p1.c +++ b/nist256p1.c @@ -37,6 +37,10 @@ const ecdsa_curve nist256p1 = { /*.val =*/{0x3c632551, 0xee72b0b, 0x3179e84f, 0x39beab69, 0x3fffffbc, 0x3fffffff, 0xfff, 0x3fffc000, 0xffff} }, + /* order_half */ { + /*.val =*/{0x3e3192a8, 0x27739585, 0x38bcf427, 0x1cdf55b4, 0x3fffffde, 0x3fffffff, 0x7ff, 0x3fffe000, 0x7fff} + }, + /* a */ { /*.val =*/{0x3ffffffc, 0x3fffffff, 0x3fffffff, 0x3f, 0x0, 0x0, 0x1000, 0x3fffc000, 0xffff} } diff --git a/secp256k1.c b/secp256k1.c index cbd21fbd4..72a9fe3f0 100644 --- a/secp256k1.c +++ b/secp256k1.c @@ -37,6 +37,10 @@ const ecdsa_curve secp256k1 = { /*.val =*/{0x10364141, 0x3f497a33, 0x348a03bb, 0x2bb739ab, 0x3ffffeba, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0xffff} }, + /* order_half */ { + /*.val =*/{0x281b20a0, 0x3fa4bd19, 0x3a4501dd, 0x15db9cd5, 0x3fffff5d, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x7fff} + }, + /* a */ { /*.val =*/{0} } From cbbc0bdc7197e74d647aedcbfd064c43544318cf Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 4 Aug 2015 00:41:50 +0200 Subject: [PATCH 207/627] fix curves unit test by using canonize version of sigencode --- test_curves.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test_curves.py b/test_curves.py index 57df5e946..7bd125b5a 100755 --- a/test_curves.py +++ b/test_curves.py @@ -8,7 +8,6 @@ import binascii import pytest import os - def bytes2num(s): res = 0 for i, b in enumerate(reversed(bytearray(s))): @@ -341,7 +340,7 @@ def test_sign(curve, r): hashfunc=hashlib.sha256) vk = sk.get_verifying_key() - sig_ref = sk.sign_digest_deterministic(digest, hashfunc=hashlib.sha256) + sig_ref = sk.sign_digest_deterministic(digest, hashfunc=hashlib.sha256, sigencode=ecdsa.util.sigencode_string_canonize) assert binascii.hexlify(sig) == binascii.hexlify(sig_ref) assert vk.verify_digest(sig, digest, sigdecode) From 418e86c293b3cda66e56c317528451f38a8eccf6 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 5 Aug 2015 16:16:24 +0200 Subject: [PATCH 208/627] remove scons dependency, build shared library with Makefile --- .gitignore | 2 -- Makefile | 17 +++++++++++------ test_curves.py | 18 ++---------------- 3 files changed, 13 insertions(+), 24 deletions(-) diff --git a/.gitignore b/.gitignore index b6fd2bd1b..589679feb 100644 --- a/.gitignore +++ b/.gitignore @@ -8,8 +8,6 @@ build/ dist/ MANIFEST TrezorCrypto.c -SConstruct -.sconsign.dblite *.os *.so *.pyc diff --git a/Makefile b/Makefile index ebf87be6c..12cb05b79 100644 --- a/Makefile +++ b/Makefile @@ -30,15 +30,17 @@ ifdef SMALL CFLAGS += -DUSE_PRECOMPUTED_IV=0 -DUSE_PRECOMPUTED_CP=0 endif -OBJS = bignum.o ecdsa.o secp256k1.o nist256p1.o rand.o hmac.o bip32.o bip39.o pbkdf2.o base58.o -OBJS += ripemd160.o -OBJS += sha2.o -OBJS += aescrypt.o aeskey.o aestab.o aes_modes.o +SRCS = bignum.c ecdsa.c secp256k1.c nist256p1.c rand.c hmac.c bip32.c bip39.c pbkdf2.c base58.c +SRCS += ripemd160.c +SRCS += sha2.c +SRCS += aescrypt.c aeskey.c aestab.c aes_modes.c + +OBJS = $(SRCS:.c=.o) TESTLIBS = -lcheck -lrt -lpthread -lm TESTSSLLIBS = -lcrypto -all: tests test-openssl +all: tests test-openssl libtrezor-crypto.so %.o: %.c %.h options.h $(CC) $(CFLAGS) -o $@ -c $< @@ -49,5 +51,8 @@ tests: tests.o $(OBJS) test-openssl: test-openssl.o $(OBJS) $(CC) test-openssl.o $(OBJS) $(TESTSSLLIBS) -o test-openssl +libtrezor-crypto.so: $(SRCS) + $(CC) $(CFLAGS) -fPIC -shared $(SRCS) -o libtrezor-crypto.so + clean: - rm -f *.o tests test-openssl + rm -f *.o tests test-openssl libtrezor-crypto.so diff --git a/test_curves.py b/test_curves.py index 7bd125b5a..34af8d460 100755 --- a/test_curves.py +++ b/test_curves.py @@ -3,10 +3,9 @@ import ctypes as c import random import ecdsa import hashlib -import subprocess import binascii -import pytest import os +import pytest def bytes2num(s): res = 0 @@ -22,20 +21,7 @@ curves = { random_iters = int(os.environ.get('ITERS', 1)) -scons_file = ''' -srcs = 'ecdsa bignum secp256k1 nist256p1 sha2 rand hmac ripemd160 base58' -srcs = [(s + '.c') for s in srcs.split()] -flags = ('-O3 -g -W -Wall -Wextra -Wimplicit-function-declaration ' - '-Wredundant-decls -Wstrict-prototypes -Wundef -Wshadow ' - '-Wpointer-arith -Wformat -Wreturn-type -Wsign-compare -Wmultichar ' - '-Wformat-nonliteral -Winit-self -Wuninitialized -Wformat-security ' - '-Werror -Wno-sequence-point ') -SharedLibrary('ecdsa', srcs, CCFLAGS=flags) -''' -open('SConstruct', 'w').write(scons_file) - -subprocess.check_call('scons -s', shell=True) -lib = c.cdll.LoadLibrary('./libecdsa.so') +lib = c.cdll.LoadLibrary('./libtrezor-crypto.so') lib.get_curve_by_name.restype = c.c_void_p From 2e09a9ff35aea3e3b4519109da95f7d6b18971a0 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 5 Aug 2015 18:06:10 +0200 Subject: [PATCH 209/627] add b to ecdsa_curve structure --- ecdsa.h | 1 + nist256p1.c | 5 ++++- secp256k1.c | 4 ++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/ecdsa.h b/ecdsa.h index cb78206fd..647a1f11f 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -40,6 +40,7 @@ typedef struct { bignum256 order; // order of G bignum256 order_half; // order of G divided by 2 bignum256 a; // coefficient 'a' of the elliptic curve + bignum256 b; // coefficient 'b' of the elliptic curve #if USE_PRECOMPUTED_CP const curve_point cp[64][8]; diff --git a/nist256p1.c b/nist256p1.c index 8aedb2c13..00648faa6 100644 --- a/nist256p1.c +++ b/nist256p1.c @@ -43,6 +43,10 @@ const ecdsa_curve nist256p1 = { /* a */ { /*.val =*/{0x3ffffffc, 0x3fffffff, 0x3fffffff, 0x3f, 0x0, 0x0, 0x1000, 0x3fffc000, 0xffff} + }, + + /* b */ { + /*.val =*/{0x27d2604b, 0x2f38f0f8, 0x53b0f63, 0x741ac33, 0x1886bc65, 0x2ef555da, 0x293e7b3e, 0xd762a8e, 0x5ac6} } #if USE_PRECOMPUTED_CP , @@ -50,5 +54,4 @@ const ecdsa_curve nist256p1 = { #include "nist256p1.table" } #endif - }; diff --git a/secp256k1.c b/secp256k1.c index 72a9fe3f0..6c1ba774e 100644 --- a/secp256k1.c +++ b/secp256k1.c @@ -43,6 +43,10 @@ const ecdsa_curve secp256k1 = { /* a */ { /*.val =*/{0} + }, + + /* b */ { + /*.val =*/{7} } #if USE_PRECOMPUTED_CP , From 6ba4d288b06202cd4c1d55734001432e08a30de6 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Thu, 23 Jul 2015 13:00:54 -0700 Subject: [PATCH 210/627] Cleaned up bignum code 1. Fixed bn_multiply_step to handle small primes. 2. Removed many calls to bn_mod to prevent side-channel leakage. --- bignum.c | 43 ++++++++++++++++++++----------------------- bignum.h | 2 +- ecdsa.c | 15 +++------------ tests.c | 14 +++++++------- 4 files changed, 31 insertions(+), 43 deletions(-) diff --git a/bignum.c b/bignum.c index 7796a0e09..f17db05c6 100644 --- a/bignum.c +++ b/bignum.c @@ -172,9 +172,7 @@ void bn_mult_k(bignum256 *x, uint8_t k, const bignum256 *prime) for (j = 0; j < 9; j++) { x->val[j] = k * x->val[j]; } - bn_normalize(x); bn_fast_mod(x, prime); - bn_mod(x, prime); } // assumes x < 2*prime, result < prime @@ -233,31 +231,35 @@ void bn_multiply_reduce_step(uint32_t res[18], const bignum256 *prime, uint32_t // let k = i-8. // invariants: // res[0..(i+1)] = k * x (mod prime) - // 0 <= res < 2^(30k + 256) * (2^30 + 1) + // 0 <= res < 2^(30k + 256) * (2^31) // estimate (res / prime) // coef = res / 2^(30k + 256) rounded down - // 0 <= coef <= 2^30 + // 0 <= coef < 2^31 // subtract (coef * 2^(30k) * prime) from res // note that we unrolled the first iteration uint32_t j; uint32_t coef = (res[i] >> 16) + (res[i + 1] << 14); - uint64_t temp = 0x1000000000000000ull + res[i - 8] - prime->val[0] * (uint64_t)coef; + uint64_t temp = 0x2000000000000000ull + res[i - 8] - prime->val[0] * (uint64_t)coef; + assert (coef < 0x80000000u); res[i - 8] = temp & 0x3FFFFFFF; for (j = 1; j < 9; j++) { temp >>= 30; - temp += 0xFFFFFFFC0000000ull + res[i - 8 + j] - prime->val[j] * (uint64_t)coef; + // Note: coeff * prime->val <= (2^31-1) * (2^30-1) + // Hence, this addition will not underflow. + temp += 0x1FFFFFFF80000000ull + res[i - 8 + j] - prime->val[j] * (uint64_t)coef; res[i - 8 + j] = temp & 0x3FFFFFFF; + // 0 <= temp < 2^61 } - temp >>= 30; - temp += 0xFFFFFFFC0000000ull + res[i - 8 + j]; - res[i - 8 + j] = temp & 0x3FFFFFFF; - // we rely on the fact that prime > 2^256 - 2^196 + temp >>= 30; + temp += 0x1FFFFFFF80000000ull + res[i - 8 + j]; + res[i - 8 + j] = temp & 0x3FFFFFFF; + // we rely on the fact that prime > 2^256 - 2^224 // res = oldres - coef*2^(30k) * prime; // and // coef * 2^(30k + 256) <= oldres < (coef+1) * 2^(30k + 256) // Hence, 0 <= res < 2^30k (2^256 + coef * (2^256 - prime)) - // Since coef * (2^256 - prime) < 2^226, we get - // 0 <= res < 2^(30k + 226) (2^30 + 1) + // Since coef * (2^256 - prime) < 2^256, we get + // 0 <= res < 2^(30k + 226) (2^31) // Thus the invariant holds again. } @@ -269,9 +271,8 @@ void bn_multiply_reduce(bignum256 *x, uint32_t res[18], const bignum256 *prime) // 0 <= res < 2^526. // compute modulo p division is only estimated so this may give result greater than prime but not bigger than 2 * prime for (i = 16; i >= 8; i--) { - bn_multiply_reduce_step(res, prime, i); - bn_multiply_reduce_step(res, prime, i); // apply twice, as a hack for NIST256P1 prime. - assert(res[i + 1] == 0); + bn_multiply_reduce_step(res, prime, i); + assert(res[i + 1] == 0); } // store the result for (i = 0; i < 9; i++) { @@ -294,7 +295,7 @@ void bn_multiply(const bignum256 *k, bignum256 *x, const bignum256 *prime) } // input x can be any normalized number that fits (0 <= x < 2^270). -// prime must be between (2^256 - 2^196) and 2^256 +// prime must be between (2^256 - 2^224) and 2^256 // result is smaller than 2*prime void bn_fast_mod(bignum256 *x, const bignum256 *prime) { @@ -305,11 +306,11 @@ void bn_fast_mod(bignum256 *x, const bignum256 *prime) coef = x->val[8] >> 16; // substract (coef * prime) from x // note that we unrolled the first iteration - temp = 0x1000000000000000ull + x->val[0] - prime->val[0] * (uint64_t)coef; + temp = 0x2000000000000000ull + x->val[0] - prime->val[0] * (uint64_t)coef; x->val[0] = temp & 0x3FFFFFFF; for (j = 1; j < 9; j++) { temp >>= 30; - temp += 0xFFFFFFFC0000000ull + x->val[j] - prime->val[j] * (uint64_t)coef; + temp += 0x1FFFFFFF80000000ull + x->val[j] - prime->val[j] * (uint64_t)coef; x->val[j] = temp & 0x3FFFFFFF; } } @@ -679,16 +680,12 @@ void bn_addmod(bignum256 *a, const bignum256 *b, const bignum256 *prime) for (i = 0; i < 9; i++) { a->val[i] += b->val[i]; } - bn_normalize(a); bn_fast_mod(a, prime); - bn_mod(a, prime); } -void bn_addmodi(bignum256 *a, uint32_t b, const bignum256 *prime) { +void bn_addi(bignum256 *a, uint32_t b) { a->val[0] += b; bn_normalize(a); - bn_fast_mod(a, prime); - bn_mod(a, prime); } // res = a - b mod prime. More exactly res = a + (2*prime - b). diff --git a/bignum.h b/bignum.h index 4774ca7d3..8851305aa 100644 --- a/bignum.h +++ b/bignum.h @@ -75,7 +75,7 @@ void bn_normalize(bignum256 *a); void bn_addmod(bignum256 *a, const bignum256 *b, const bignum256 *prime); -void bn_addmodi(bignum256 *a, uint32_t b, const bignum256 *prime); +void bn_addi(bignum256 *a, uint32_t b); void bn_subtractmod(const bignum256 *a, const bignum256 *b, bignum256 *res, const bignum256 *prime); diff --git a/ecdsa.c b/ecdsa.c index 380ddaabf..3f2e4d429 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -207,13 +207,10 @@ void curve_to_jacobian(const curve_point *p, jacobian_curve_point *jp, const big bn_multiply(&p->x, &jp->x, prime); bn_multiply(&p->y, &jp->y, prime); - bn_mod(&jp->x, prime); - bn_mod(&jp->y, prime); } void jacobian_to_curve(const jacobian_curve_point *jp, curve_point *p, const bignum256 *prime) { p->y = jp->z; - bn_mod(&p->y, prime); bn_inverse(&p->y, prime); // p->y = z^-1 p->x = p->y; @@ -298,21 +295,18 @@ void point_jacobian_add(const curve_point *p1, jacobian_curve_point *p2, const b // z3 = h*z2 bn_multiply(&h, &p2->z, prime); - bn_mod(&p2->z, prime); // x3 = r^2 - h^3 - 2h^2x2 bn_addmod(&hcb, &hsqx2, prime); bn_addmod(&hcb, &hsqx2, prime); bn_subtractmod(&rsq, &hcb, &p2->x, prime); bn_fast_mod(&p2->x, prime); - bn_mod(&p2->x, prime); // y3 = r*(h^2x2 - x3) - y2*h^3 bn_subtractmod(&hsqx2, &p2->x, &p2->y, prime); bn_multiply(&r, &p2->y, prime); bn_subtractmod(&p2->y, &hcby2, &p2->y, prime); bn_fast_mod(&p2->y, prime); - bn_mod(&p2->y, prime); } void point_jacobian_double(jacobian_curve_point *p, const ecdsa_curve *curve) { @@ -366,15 +360,13 @@ void point_jacobian_double(jacobian_curve_point *p, const ecdsa_curve *curve) { // z3 = yz bn_multiply(&p->y, &p->z, prime); - bn_mod(&p->z, prime); // x3 = m^2 - 2*xy^2 p->x = xysq; - bn_mod(&p->x, prime); bn_lshift(&p->x); + bn_fast_mod(&p->x, prime); bn_subtractmod(&msq, &p->x, &p->x, prime); bn_fast_mod(&p->x, prime); - bn_mod(&p->x, prime); // y3 = m*(xy^2 - x3) - y^4 bn_subtractmod(&xysq, &p->x, &p->y, prime); @@ -382,7 +374,6 @@ void point_jacobian_double(jacobian_curve_point *p, const ecdsa_curve *curve) { bn_multiply(&ysq, &ysq, prime); bn_subtractmod(&p->y, &ysq, &p->y, prime); bn_fast_mod(&p->y, prime); - bn_mod(&p->y, prime); } // res = k * p @@ -835,7 +826,7 @@ void uncompress_coords(const ecdsa_curve *curve, uint8_t odd, const bignum256 *x memcpy(y, x, sizeof(bignum256)); // y is x bn_multiply(x, y, &curve->prime); // y is x^2 bn_multiply(x, y, &curve->prime); // y is x^3 - bn_addmodi(y, 7, &curve->prime); // y is x^3 + 7 + bn_addi(y, 7); // y is x^3 + 7 bn_sqrt(y, &curve->prime); // y = sqrt(y) if ((odd & 0x01) != (y->val[0] & 1)) { bn_subtract(&curve->prime, y, y); // y = -y @@ -885,7 +876,7 @@ int ecdsa_validate_pubkey(const ecdsa_curve *curve, const curve_point *pub) // x^3 + b bn_multiply(&(pub->x), &x_3_b, &curve->prime); bn_multiply(&(pub->x), &x_3_b, &curve->prime); - bn_addmodi(&x_3_b, 7, &curve->prime); + bn_addi(&x_3_b, 7); if (!bn_is_equal(&x_3_b, &y_2)) { return 0; diff --git a/tests.c b/tests.c index 511993df1..4401c31c1 100644 --- a/tests.c +++ b/tests.c @@ -40,10 +40,10 @@ #include "secp256k1.h" #define CURVE (&secp256k1) -#define prime256k1 (secp256k1.prime) -#define G256k1 (secp256k1.G) -#define order256k1 (secp256k1.order) -#define secp256k1_cp (secp256k1.cp) +#define prime256k1 (CURVE->prime) +#define G256k1 (CURVE->G) +#define order256k1 (CURVE->order) +#define secp256k1_cp (CURVE->cp) uint8_t *fromhex(const char *str) { @@ -1231,7 +1231,7 @@ START_TEST(test_secp256k1_cp) { // increment by one and test again p1 = p; point_add(CURVE, &G256k1, &p1); - bn_addmodi(&a, 1, &order256k1); + bn_addi(&a, 1); scalar_multiply(CURVE, &a, &p); ck_assert_mem_eq(&p, &p1, sizeof(curve_point)); bn_zero(&p.y); // test that point_multiply CURVE, is not a noop @@ -1254,7 +1254,7 @@ START_TEST(test_mult_border_cases) { point_multiply(CURVE, &a, &G256k1, &p); ck_assert(point_is_infinity(&p)); - bn_addmodi(&a, 1, &order256k1); // a == 1 + bn_addi(&a, 1); // a == 1 scalar_multiply(CURVE, &a, &p); ck_assert_mem_eq(&p, &G256k1, sizeof(curve_point)); point_multiply(CURVE, &a, &G256k1, &p); @@ -1269,7 +1269,7 @@ START_TEST(test_mult_border_cases) { ck_assert_mem_eq(&p, &expected, sizeof(curve_point)); bn_subtract(&order256k1, &a, &a); - bn_addmodi(&a, 1, &order256k1); // a == 2 + bn_addi(&a, 1); // a == 2 expected = G256k1; point_add(CURVE, &expected, &expected); scalar_multiply(CURVE, &a, &p); From 60e36dac3b9df54dd51f2a08d6a1b8121dd2c32b Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Thu, 23 Jul 2015 16:04:14 -0700 Subject: [PATCH 211/627] Fixed conditional_negate for larger numbers Without the bn_mod the numbers get larger (but still < 2*prime), so conditional_negate should handle this. --- ecdsa.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ecdsa.c b/ecdsa.c index 3f2e4d429..f18a13397 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -177,13 +177,15 @@ void conditional_negate(uint32_t cond, bignum256 *a, const bignum256 *prime) { int j; uint32_t tmp = 1; + assert(a->val[8] < 0x20000); for (j = 0; j < 8; j++) { - tmp += 0x3fffffff + prime->val[j] - a->val[j]; + tmp += 0x3fffffff + 2*prime->val[j] - a->val[j]; a->val[j] = ((tmp & 0x3fffffff) & cond) | (a->val[j] & ~cond); tmp >>= 30; } - tmp += 0x3fffffff + prime->val[j] - a->val[j]; + tmp += 0x3fffffff + 2*prime->val[j] - a->val[j]; a->val[j] = ((tmp & 0x3fffffff) & cond) | (a->val[j] & ~cond); + assert(a->val[8] < 0x20000); } typedef struct jacobian_curve_point { From f2081d88d84b4ea9251fff636ab206358444880a Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Wed, 5 Aug 2015 19:32:20 +0200 Subject: [PATCH 212/627] New jacobian_add that handles doubling. Fix bug where jacobian_add is called with two identical points. --- bignum.c | 22 +++++++ bignum.h | 4 ++ ecdsa.c | 166 +++++++++++++++++++++++++++++++--------------------- ecdsa.h | 3 +- nist256p1.c | 4 +- secp256k1.c | 4 +- 6 files changed, 130 insertions(+), 73 deletions(-) diff --git a/bignum.c b/bignum.c index f17db05c6..6df05474a 100644 --- a/bignum.c +++ b/bignum.c @@ -116,6 +116,19 @@ int bn_is_equal(const bignum256 *a, const bignum256 *b) { return !result; } +void bn_cmov(bignum256 *res, int cond, const bignum256 *truecase, const bignum256 *falsecase) +{ + int i; + uint32_t tmask = (uint32_t) -cond; + uint32_t fmask = ~tmask; + + assert (cond == 1 || cond == 0); + for (i = 0; i < 9; i++) { + res->val[i] = (truecase->val[i] & tmask) | + (falsecase->val[i] & fmask); + } +} + int bn_bitlen(const bignum256 *a) { int i = 8, j; while (i >= 0 && a->val[i] == 0) i--; @@ -688,6 +701,15 @@ void bn_addi(bignum256 *a, uint32_t b) { bn_normalize(a); } +void bn_subi(bignum256 *a, uint32_t b, const bignum256 *prime) { + int i; + for (i = 0; i < 9; i++) { + a->val[i] += prime->val[i]; + } + a->val[0] -= b; + bn_fast_mod(a, prime); +} + // res = a - b mod prime. More exactly res = a + (2*prime - b). // precondition: 0 <= b < 2*prime, 0 <= a < prime // res < 3*prime diff --git a/bignum.h b/bignum.h index 8851305aa..119063ac2 100644 --- a/bignum.h +++ b/bignum.h @@ -51,6 +51,8 @@ int bn_is_less(const bignum256 *a, const bignum256 *b); int bn_is_equal(const bignum256 *a, const bignum256 *b); +void bn_cmov(bignum256 *res, int cond, const bignum256 *truecase, const bignum256 *falsecase); + int bn_bitlen(const bignum256 *a); void bn_lshift(bignum256 *a); @@ -77,6 +79,8 @@ void bn_addmod(bignum256 *a, const bignum256 *b, const bignum256 *prime); void bn_addi(bignum256 *a, uint32_t b); +void bn_subi(bignum256 *a, uint32_t b, const bignum256 *prime); + void bn_subtractmod(const bignum256 *a, const bignum256 *b, bignum256 *res, const bignum256 *prime); void bn_subtract(const bignum256 *a, const bignum256 *b, bignum256 *res); diff --git a/ecdsa.c b/ecdsa.c index f18a13397..333d36148 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -111,7 +111,7 @@ void point_double(const ecdsa_curve *curve, curve_point *cp) xr = cp->x; bn_multiply(&xr, &xr, &curve->prime); bn_mult_k(&xr, 3, &curve->prime); - bn_addmod(&xr, &curve->a, &curve->prime); + bn_subi(&xr, -curve->a, &curve->prime); bn_multiply(&xr, &lambda, &curve->prime); // xr = lambda^2 - 2*x @@ -228,86 +228,118 @@ void jacobian_to_curve(const jacobian_curve_point *jp, curve_point *p, const big bn_mod(&p->y, prime); } -void point_jacobian_add(const curve_point *p1, jacobian_curve_point *p2, const bignum256 *prime) { - bignum256 r, h; - bignum256 rsq, hcb, hcby2, hsqx2; +void point_jacobian_add(const curve_point *p1, jacobian_curve_point *p2, const ecdsa_curve *curve) { + bignum256 r, h, r2; + bignum256 hcby, hsqx; + bignum256 xz, yz, az; + int is_doubling; + const bignum256 *prime = &curve->prime; + int a = curve->a; - /* usual algorithm: + assert (-3 <= a && a <= 0); + + /* First we bring p1 to the same denominator: + * x1' := x1 * z2^2 + * y1' := y1 * z2^3 + */ + /* + * lambda = ((y1' - y2)/z2^3) / ((x1' - x2)/z2^2) + * = (y1' - y2) / (x1' - x2) z2 + * x3/z3^2 = lambda^2 - (x1' + x2)/z2^2 + * y3/z3^3 = 1/2 lambda * (2x3/z3^2 - (x1' + x2)/z2^2) + (y1'+y2)/z2^3 * - * lambda = (y1 - y2/z2^3) / (x1 - x2/z2^2) - * x3/z3^2 = lambda^2 - x1 - x2/z2^2 - * y3/z3^3 = lambda * (x2/z2^2 - x3/z3^2) - y2/z2^3 + * For the special case x1=x2, y1=y2 (doubling) we have + * lambda = 3/2 ((x2/z2^2)^2 + a) / (y2/z2^3) + * = 3/2 (x2^2 + a*z2^4) / y2*z2) * - * to get rid of fraction we set - * r = (y1 * z2^3 - y2) (the numerator of lambda * z2^3) - * h = (x1 * z2^2 - x2) (the denominator of lambda * z2^2) - * Hence, - * lambda = r / (h*z2) + * to get rid of fraction we write lambda as + * lambda = r / (h*z2) + * with r = is_doubling ? 3/2 x2^2 + az2^4 : (y1 - y2) + * h = is_doubling ? y1+y2 : (x1 - x2) * * With z3 = h*z2 (the denominator of lambda) - * we get x3 = lambda^2*z3^2 - x1*z3^2 - x2/z2^2*z3^2 - * = r^2 - x1*h^2*z2^2 - x2*h^2 - * = r^2 - h^2*(x1*z2^2 + x2) - * = r^2 - h^2*(h + 2*x2) - * = r^2 - h^3 - 2*h^2*x2 - * and y3 = (lambda * (x2/z2^2 - x3/z3^2) - y2/z2^3) * z3^3 - * = r * (h^2*x2 - x3) - h^3*y2 + * we get x3 = lambda^2*z3^2 - (x1' + x2)/z2^2*z3^2 + * = r^2 - h^2 * (x1' + x2) + * and y3 = 1/2 r * (2x3 - h^2*(x1' + x2)) + h^3*(y1' + y2) */ - /* h = x1*z2^2 - x2 - * r = y1*z2^3 - y2 + /* h = x1 - x2 + * r = y1 - y2 * x3 = r^2 - h^3 - 2*h^2*x2 * y3 = r*(h^2*x2 - x3) - h^3*y2 * z3 = h*z2 */ - // h = x1 * z2^2 - x2; - // r = y1 * z2^3 - y2; - h = p2->z; - bn_multiply(&h, &h, prime); // h = z2^2 - r = p2->z; - bn_multiply(&h, &r, prime); // r = z2^3 - - bn_multiply(&p1->x, &h, prime); + xz = p2->z; + bn_multiply(&xz, &xz, prime); // xz = z2^2 + yz = p2->z; + bn_multiply(&xz, &yz, prime); // yz = z2^3 + + if (a != 0) { + az = xz; + bn_multiply(&az, &az, prime); // az = z2^4 + bn_mult_k(&az, -a, prime); // az = -az2^4 + } + + bn_multiply(&p1->x, &xz, prime); // xz = x1' = x1*z2^2; + h = xz; bn_subtractmod(&h, &p2->x, &h, prime); - // h = x1 * z2^2 - x2; + bn_fast_mod(&h, prime); + // h = x1' - x2; + + bn_addmod(&xz, &p2->x, prime); + // xz = x1' + x2 - bn_multiply(&p1->y, &r, prime); - bn_subtractmod(&r, &p2->y, &r, prime); - // r = y1 * z2^3 - y2; + is_doubling = bn_is_zero(&h) | bn_is_equal(&h, prime); - // hsqx2 = h^2 - hsqx2 = h; - bn_multiply(&hsqx2, &hsqx2, prime); + bn_multiply(&p1->y, &yz, prime); // yz = y1' = y1*z2^3; + bn_subtractmod(&yz, &p2->y, &r, prime); + // r = y1' - y2; + + bn_addmod(&yz, &p2->y, prime); + // yz = y1' + y2 + + r2 = p2->x; + bn_multiply(&r2, &r2, prime); + bn_mult_k(&r2, 3, prime); + + if (a != 0) { + // subtract -a z2^4, i.e, add a z2^4 + bn_subtractmod(&r2, &az, &r2, prime); + } + bn_cmov(&r, is_doubling, &r2, &r); + bn_cmov(&h, is_doubling, &yz, &h); + - // hcb = h^3 - hcb = h; - bn_multiply(&hsqx2, &hcb, prime); + // hsqx = h^2 + hsqx = h; + bn_multiply(&hsqx, &hsqx, prime); - // hsqx2 = h^2 * x2 - bn_multiply(&p2->x, &hsqx2, prime); + // hcby = h^3 + hcby = h; + bn_multiply(&hsqx, &hcby, prime); - // hcby2 = h^3 * y2 - hcby2 = hcb; - bn_multiply(&p2->y, &hcby2, prime); + // hsqx = h^2 * (x1 + x2) + bn_multiply(&xz, &hsqx, prime); - // rsq = r^2 - rsq = r; - bn_multiply(&rsq, &rsq, prime); + // hcby = h^3 * (y1 + y2) + bn_multiply(&yz, &hcby, prime); // z3 = h*z2 bn_multiply(&h, &p2->z, prime); - // x3 = r^2 - h^3 - 2h^2x2 - bn_addmod(&hcb, &hsqx2, prime); - bn_addmod(&hcb, &hsqx2, prime); - bn_subtractmod(&rsq, &hcb, &p2->x, prime); + // x3 = r^2 - h^2 (x1 + x2) + p2->x = r; + bn_multiply(&p2->x, &p2->x, prime); + bn_subtractmod(&p2->x, &hsqx, &p2->x, prime); bn_fast_mod(&p2->x, prime); - // y3 = r*(h^2x2 - x3) - y2*h^3 - bn_subtractmod(&hsqx2, &p2->x, &p2->y, prime); + // y3 = 1/2 (r*(h^2 (x1 + x2) - 2x3) - h^3 (y1 + y2)) + bn_subtractmod(&hsqx, &p2->x, &p2->y, prime); + bn_subtractmod(&p2->y, &p2->x, &p2->y, prime); bn_multiply(&r, &p2->y, prime); - bn_subtractmod(&p2->y, &hcby2, &p2->y, prime); + bn_subtractmod(&p2->y, &hcby, &p2->y, prime); + bn_mult_half(&p2->y, prime); bn_fast_mod(&p2->y, prime); } @@ -346,8 +378,8 @@ void point_jacobian_double(jacobian_curve_point *p, const ecdsa_curve *curve) { az4 = p->z; bn_multiply(&az4, &az4, prime); bn_multiply(&az4, &az4, prime); - bn_multiply(&curve->a, &az4, prime); - bn_addmod(&m, &az4, prime); + bn_mult_k(&az4, -curve->a, prime); + bn_subtractmod(&m, &az4, &m, prime); bn_mult_half(&m, prime); // msq = m^2 @@ -475,7 +507,7 @@ void point_multiply(const ecdsa_curve *curve, const bignum256 *k, const curve_po conditional_negate(sign ^ nsign, &jres.z, prime); // add odd factor - point_jacobian_add(&pmult[bits >> 1], &jres, prime); + point_jacobian_add(&pmult[bits >> 1], &jres, curve); sign = nsign; } conditional_negate(sign, &jres.z, prime); @@ -562,7 +594,7 @@ void scalar_multiply(const ecdsa_curve *curve, const bignum256 *k, curve_point * conditional_negate((lowbits & 1) - 1, &jres.y, prime); // add odd factor - point_jacobian_add(&curve->cp[i][lowbits >> 1], &jres, prime); + point_jacobian_add(&curve->cp[i][lowbits >> 1], &jres, curve); } conditional_negate(((a.val[0] >> 4) & 1) - 1, &jres.y, prime); jacobian_to_curve(&jres, res, prime); @@ -825,10 +857,11 @@ int ecdsa_address_decode(const char *addr, uint8_t *out) void uncompress_coords(const ecdsa_curve *curve, uint8_t odd, const bignum256 *x, bignum256 *y) { // y^2 = x^3 + 0*x + 7 - memcpy(y, x, sizeof(bignum256)); // y is x + memcpy(y, x, sizeof(bignum256)); // y is x bn_multiply(x, y, &curve->prime); // y is x^2 - bn_multiply(x, y, &curve->prime); // y is x^3 - bn_addi(y, 7); // y is x^3 + 7 + bn_subi(y, -curve->a, &curve->prime); // y is x^2 + a + bn_multiply(x, y, &curve->prime); // y is x^3 + ax + bn_addmod(y, &curve->b, &curve->prime); // y is x^3 + ax + b bn_sqrt(y, &curve->prime); // y = sqrt(y) if ((odd & 0x01) != (y->val[0] & 1)) { bn_subtract(&curve->prime, y, y); // y = -y @@ -875,10 +908,11 @@ int ecdsa_validate_pubkey(const ecdsa_curve *curve, const curve_point *pub) bn_multiply(&(pub->y), &y_2, &curve->prime); bn_mod(&y_2, &curve->prime); - // x^3 + b - bn_multiply(&(pub->x), &x_3_b, &curve->prime); - bn_multiply(&(pub->x), &x_3_b, &curve->prime); - bn_addi(&x_3_b, 7); + // x^3 + ax + b + bn_multiply(&(pub->x), &x_3_b, &curve->prime); // x^2 + bn_subi(&x_3_b, -curve->a, &curve->prime); // x^2 + a + bn_multiply(&(pub->x), &x_3_b, &curve->prime); // x^3 + ax + bn_addmod(&x_3_b, &curve->b, &curve->prime); // x^3 + ax + b if (!bn_is_equal(&x_3_b, &y_2)) { return 0; diff --git a/ecdsa.h b/ecdsa.h index 647a1f11f..4bdc04115 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -39,7 +39,7 @@ typedef struct { curve_point G; // initial curve point bignum256 order; // order of G bignum256 order_half; // order of G divided by 2 - bignum256 a; // coefficient 'a' of the elliptic curve + int a; // coefficient 'a' of the elliptic curve bignum256 b; // coefficient 'b' of the elliptic curve #if USE_PRECOMPUTED_CP @@ -68,6 +68,7 @@ void ecdsa_get_pubkeyhash(const uint8_t *pub_key, uint8_t *pubkeyhash); void ecdsa_get_address_raw(const uint8_t *pub_key, uint8_t version, uint8_t *addr_raw); void ecdsa_get_address(const uint8_t *pub_key, uint8_t version, char *addr, int addrsize); void ecdsa_get_wif(const uint8_t *priv_key, uint8_t version, char *wif, int wifsize); + int ecdsa_address_decode(const char *addr, uint8_t *out); int ecdsa_read_pubkey(const ecdsa_curve *curve, const uint8_t *pub_key, curve_point *pub); int ecdsa_validate_pubkey(const ecdsa_curve *curve, const curve_point *pub); diff --git a/nist256p1.c b/nist256p1.c index 00648faa6..28d5714b5 100644 --- a/nist256p1.c +++ b/nist256p1.c @@ -41,9 +41,7 @@ const ecdsa_curve nist256p1 = { /*.val =*/{0x3e3192a8, 0x27739585, 0x38bcf427, 0x1cdf55b4, 0x3fffffde, 0x3fffffff, 0x7ff, 0x3fffe000, 0x7fff} }, - /* a */ { - /*.val =*/{0x3ffffffc, 0x3fffffff, 0x3fffffff, 0x3f, 0x0, 0x0, 0x1000, 0x3fffc000, 0xffff} - }, + /* a */ -3, /* b */ { /*.val =*/{0x27d2604b, 0x2f38f0f8, 0x53b0f63, 0x741ac33, 0x1886bc65, 0x2ef555da, 0x293e7b3e, 0xd762a8e, 0x5ac6} diff --git a/secp256k1.c b/secp256k1.c index 6c1ba774e..b2711e650 100644 --- a/secp256k1.c +++ b/secp256k1.c @@ -41,9 +41,7 @@ const ecdsa_curve secp256k1 = { /*.val =*/{0x281b20a0, 0x3fa4bd19, 0x3a4501dd, 0x15db9cd5, 0x3fffff5d, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x7fff} }, - /* a */ { - /*.val =*/{0} - }, + /* a */ 0, /* b */ { /*.val =*/{7} From e1347fcdf87d702773d3bb107263587e4ca76d21 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Wed, 5 Aug 2015 21:42:40 +0200 Subject: [PATCH 213/627] New Unit Tests - Added unit tests for the NIST curve. - Fix some missing bn_mod in unit tests. - New tests for tricky 2 (2j+1) 2^{4i} exponents. --- tests.c | 216 ++++++++++++++++++++++++++++++++------------------------ 1 file changed, 125 insertions(+), 91 deletions(-) diff --git a/tests.c b/tests.c index 4401c31c1..f7c578915 100644 --- a/tests.c +++ b/tests.c @@ -38,12 +38,7 @@ #include "sha2.h" #include "options.h" #include "secp256k1.h" - -#define CURVE (&secp256k1) -#define prime256k1 (CURVE->prime) -#define G256k1 (CURVE->G) -#define order256k1 (CURVE->order) -#define secp256k1_cp (CURVE->cp) +#include "nist256p1.h" uint8_t *fromhex(const char *str) { @@ -509,7 +504,7 @@ END_TEST #define test_deterministic(KEY, MSG, K) do { \ sha256_Raw((uint8_t *)MSG, strlen(MSG), buf); \ - res = generate_k_rfc6979(CURVE, &k, fromhex(KEY), buf); \ + res = generate_k_rfc6979(curve, &k, fromhex(KEY), buf); \ ck_assert_int_eq(res, 0); \ bn_write_be(&k, buf); \ ck_assert_mem_eq(buf, fromhex(K), 32); \ @@ -520,6 +515,7 @@ START_TEST(test_rfc6979) int res; bignum256 k; uint8_t buf[32]; + const ecdsa_curve *curve = &secp256k1; test_deterministic("cca9fbcc1b41e5a95d369eaa6ddcff73b61a4efaa279cfc6567e8daa39cbaf50", "sample", "2df40ca70e639d89528a6b670d9d48d9165fdc0febc0974056bdce192b8e16a3"); test_deterministic("0000000000000000000000000000000000000000000000000000000000000001", "Satoshi Nakamoto", "8f8a276c19f4149656b280621e358cce24f5f52542772691ee69063b74f15d15"); @@ -535,6 +531,7 @@ START_TEST(test_sign_speed) uint8_t sig[64], priv_key[32], msg[256]; size_t i; int res; + const ecdsa_curve *curve = &secp256k1; for (i = 0; i < sizeof(msg); i++) { msg[i] = i * 1103515245; @@ -544,13 +541,13 @@ START_TEST(test_sign_speed) memcpy(priv_key, fromhex("c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd5"), 32); for (i = 0 ; i < 250; i++) { - res = ecdsa_sign(CURVE, priv_key, msg, sizeof(msg), sig, 0); + res = ecdsa_sign(curve, priv_key, msg, sizeof(msg), sig, 0); ck_assert_int_eq(res, 0); } memcpy(priv_key, fromhex("509a0382ff5da48e402967a671bdcde70046d07f0df52cff12e8e3883b426a0a"), 32); for (i = 0 ; i < 250; i++) { - res = ecdsa_sign(CURVE, priv_key, msg, sizeof(msg), sig, 0); + res = ecdsa_sign(curve, priv_key, msg, sizeof(msg), sig, 0); ck_assert_int_eq(res, 0); } @@ -563,6 +560,7 @@ START_TEST(test_verify_speed) uint8_t sig[64], pub_key33[33], pub_key65[65], msg[256]; size_t i; int res; + const ecdsa_curve *curve = &secp256k1; for (i = 0; i < sizeof(msg); i++) { msg[i] = i * 1103515245; @@ -575,9 +573,9 @@ START_TEST(test_verify_speed) memcpy(pub_key65, fromhex("044054fd18aeb277aeedea01d3f3986ff4e5be18092a04339dcf4e524e2c0a09746c7083ed2097011b1223a17a644e81f59aa3de22dac119fd980b36a8ff29a244"), 65); for (i = 0 ; i < 25; i++) { - res = ecdsa_verify(CURVE, pub_key65, sig, msg, sizeof(msg)); + res = ecdsa_verify(curve, pub_key65, sig, msg, sizeof(msg)); ck_assert_int_eq(res, 0); - res = ecdsa_verify(CURVE, pub_key33, sig, msg, sizeof(msg)); + res = ecdsa_verify(curve, pub_key33, sig, msg, sizeof(msg)); ck_assert_int_eq(res, 0); } @@ -586,9 +584,9 @@ START_TEST(test_verify_speed) memcpy(pub_key65, fromhex("04ff45a5561a76be930358457d113f25fac790794ec70317eff3b97d7080d457196235193a15778062ddaa44aef7e6901b781763e52147f2504e268b2d572bf197"), 65); for (i = 0 ; i < 25; i++) { - res = ecdsa_verify(CURVE, pub_key65, sig, msg, sizeof(msg)); + res = ecdsa_verify(curve, pub_key65, sig, msg, sizeof(msg)); ck_assert_int_eq(res, 0); - res = ecdsa_verify(CURVE, pub_key33, sig, msg, sizeof(msg)); + res = ecdsa_verify(curve, pub_key33, sig, msg, sizeof(msg)); ck_assert_int_eq(res, 0); } @@ -1039,45 +1037,46 @@ START_TEST(test_pubkey_validity) uint8_t pub_key[65]; curve_point pub; int res; + const ecdsa_curve *curve = &secp256k1; memcpy(pub_key, fromhex("0226659c1cf7321c178c07437150639ff0c5b7679c7ea195253ed9abda2e081a37"), 33); - res = ecdsa_read_pubkey(CURVE, pub_key, &pub); + res = ecdsa_read_pubkey(curve, pub_key, &pub); ck_assert_int_eq(res, 1); memcpy(pub_key, fromhex("025b1654a0e78d28810094f6c5a96b8efb8a65668b578f170ac2b1f83bc63ba856"), 33); - res = ecdsa_read_pubkey(CURVE, pub_key, &pub); + res = ecdsa_read_pubkey(curve, pub_key, &pub); ck_assert_int_eq(res, 1); memcpy(pub_key, fromhex("03433f246a12e6486a51ff08802228c61cf895175a9b49ed4766ea9a9294a3c7fe"), 33); - res = ecdsa_read_pubkey(CURVE, pub_key, &pub); + res = ecdsa_read_pubkey(curve, pub_key, &pub); ck_assert_int_eq(res, 1); memcpy(pub_key, fromhex("03aeb03abeee0f0f8b4f7a5d65ce31f9570cef9f72c2dd8a19b4085a30ab033d48"), 33); - res = ecdsa_read_pubkey(CURVE, pub_key, &pub); + res = ecdsa_read_pubkey(curve, pub_key, &pub); ck_assert_int_eq(res, 1); memcpy(pub_key, fromhex("0496e8f2093f018aff6c2e2da5201ee528e2c8accbf9cac51563d33a7bb74a016054201c025e2a5d96b1629b95194e806c63eb96facaedc733b1a4b70ab3b33e3a"), 65); - res = ecdsa_read_pubkey(CURVE, pub_key, &pub); + res = ecdsa_read_pubkey(curve, pub_key, &pub); ck_assert_int_eq(res, 1); memcpy(pub_key, fromhex("0498010f8a687439ff497d3074beb4519754e72c4b6220fb669224749591dde416f3961f8ece18f8689bb32235e436874d2174048b86118a00afbd5a4f33a24f0f"), 65); - res = ecdsa_read_pubkey(CURVE, pub_key, &pub); + res = ecdsa_read_pubkey(curve, pub_key, &pub); ck_assert_int_eq(res, 1); memcpy(pub_key, fromhex("04f80490839af36d13701ec3f9eebdac901b51c362119d74553a3c537faff31b17e2a59ebddbdac9e87b816307a7ed5b826b8f40b92719086238e1bebf19b77a4d"), 65); - res = ecdsa_read_pubkey(CURVE, pub_key, &pub); + res = ecdsa_read_pubkey(curve, pub_key, &pub); ck_assert_int_eq(res, 1); memcpy(pub_key, fromhex("04f80490839af36d13701ec3f9eebdac901b51c362119d74553a3c537faff31b17e2a59ebddbdac9e87b816307a7ed5b826b8f40b92719086238e1bebf00000000"), 65); - res = ecdsa_read_pubkey(CURVE, pub_key, &pub); + res = ecdsa_read_pubkey(curve, pub_key, &pub); ck_assert_int_eq(res, 0); memcpy(pub_key, fromhex("04f80490839af36d13701ec3f9eebdac901b51c362119d74553a3c537faff31b17e2a59ebddbdac9e87b816307a7ed5b8211111111111111111111111111111111"), 65); - res = ecdsa_read_pubkey(CURVE, pub_key, &pub); + res = ecdsa_read_pubkey(curve, pub_key, &pub); ck_assert_int_eq(res, 0); memcpy(pub_key, fromhex("00"), 1); - res = ecdsa_read_pubkey(CURVE, pub_key, &pub); + res = ecdsa_read_pubkey(curve, pub_key, &pub); ck_assert_int_eq(res, 0); } END_TEST @@ -1210,7 +1209,7 @@ START_TEST(test_ecdsa_der) } END_TEST -START_TEST(test_secp256k1_cp) { +static void test_codepoints_curve(const ecdsa_curve *curve) { int i, j; bignum256 a; curve_point p, p1; @@ -1221,108 +1220,130 @@ START_TEST(test_secp256k1_cp) { bn_normalize(&a); // note that this is not a trivial test. We add 64 curve // points in the table to get that particular curve point. - scalar_multiply(CURVE, &a, &p); - ck_assert_mem_eq(&p, &secp256k1_cp[i][j], sizeof(curve_point)); - bn_zero(&p.y); // test that point_multiply CURVE, is not a noop - point_multiply(CURVE, &a, &G256k1, &p); - ck_assert_mem_eq(&p, &secp256k1_cp[i][j], sizeof(curve_point)); - - // even/odd has different behaviour; - // increment by one and test again - p1 = p; - point_add(CURVE, &G256k1, &p1); - bn_addi(&a, 1); - scalar_multiply(CURVE, &a, &p); + scalar_multiply(curve, &a, &p); + ck_assert_mem_eq(&p, &curve->cp[i][j], sizeof(curve_point)); + bn_zero(&p.y); // test that point_multiply curve, is not a noop + point_multiply(curve, &a, &curve->G, &p); + ck_assert_mem_eq(&p, &curve->cp[i][j], sizeof(curve_point)); + // mul 2 test. this should catch bugs + bn_lshift(&a); + bn_mod(&a, &curve->order); + p1 = curve->cp[i][j]; + point_double(curve, &p1); + // note that this is not a trivial test. We add 64 curve + // points in the table to get that particular curve point. + scalar_multiply(curve, &a, &p); ck_assert_mem_eq(&p, &p1, sizeof(curve_point)); - bn_zero(&p.y); // test that point_multiply CURVE, is not a noop - point_multiply(CURVE, &a, &G256k1, &p); + bn_zero(&p.y); // test that point_multiply curve, is not a noop + point_multiply(curve, &a, &curve->G, &p); ck_assert_mem_eq(&p, &p1, sizeof(curve_point)); } } } + +START_TEST(test_codepoints) { + test_codepoints_curve(&secp256k1); + test_codepoints_curve(&nist256p1); +} END_TEST -START_TEST(test_mult_border_cases) { +static void test_mult_border_cases_curve(const ecdsa_curve *curve) { bignum256 a; curve_point p; curve_point expected; bn_zero(&a); // a == 0 - scalar_multiply(CURVE, &a, &p); + scalar_multiply(curve, &a, &p); ck_assert(point_is_infinity(&p)); - point_multiply(CURVE, &a, &p, &p); + point_multiply(curve, &a, &p, &p); ck_assert(point_is_infinity(&p)); - point_multiply(CURVE, &a, &G256k1, &p); + point_multiply(curve, &a, &curve->G, &p); ck_assert(point_is_infinity(&p)); bn_addi(&a, 1); // a == 1 - scalar_multiply(CURVE, &a, &p); - ck_assert_mem_eq(&p, &G256k1, sizeof(curve_point)); - point_multiply(CURVE, &a, &G256k1, &p); - ck_assert_mem_eq(&p, &G256k1, sizeof(curve_point)); - - bn_subtract(&order256k1, &a, &a); // a == -1 - expected = G256k1; - bn_subtract(&prime256k1, &expected.y, &expected.y); - scalar_multiply(CURVE, &a, &p); + scalar_multiply(curve, &a, &p); + ck_assert_mem_eq(&p, &curve->G, sizeof(curve_point)); + point_multiply(curve, &a, &curve->G, &p); + ck_assert_mem_eq(&p, &curve->G, sizeof(curve_point)); + + bn_subtract(&curve->order, &a, &a); // a == -1 + expected = curve->G; + bn_subtract(&curve->prime, &expected.y, &expected.y); + scalar_multiply(curve, &a, &p); ck_assert_mem_eq(&p, &expected, sizeof(curve_point)); - point_multiply(CURVE, &a, &G256k1, &p); + point_multiply(curve, &a, &curve->G, &p); ck_assert_mem_eq(&p, &expected, sizeof(curve_point)); - bn_subtract(&order256k1, &a, &a); + bn_subtract(&curve->order, &a, &a); bn_addi(&a, 1); // a == 2 - expected = G256k1; - point_add(CURVE, &expected, &expected); - scalar_multiply(CURVE, &a, &p); + expected = curve->G; + point_add(curve, &expected, &expected); + scalar_multiply(curve, &a, &p); ck_assert_mem_eq(&p, &expected, sizeof(curve_point)); - point_multiply(CURVE, &a, &G256k1, &p); + point_multiply(curve, &a, &curve->G, &p); ck_assert_mem_eq(&p, &expected, sizeof(curve_point)); - bn_subtract(&order256k1, &a, &a); // a == -2 - expected = G256k1; - point_add(CURVE, &expected, &expected); - bn_subtract(&prime256k1, &expected.y, &expected.y); - scalar_multiply(CURVE, &a, &p); + bn_subtract(&curve->order, &a, &a); // a == -2 + expected = curve->G; + point_add(curve, &expected, &expected); + bn_subtract(&curve->prime, &expected.y, &expected.y); + scalar_multiply(curve, &a, &p); ck_assert_mem_eq(&p, &expected, sizeof(curve_point)); - point_multiply(CURVE, &a, &G256k1, &p); + point_multiply(curve, &a, &curve->G, &p); ck_assert_mem_eq(&p, &expected, sizeof(curve_point)); } + +START_TEST(test_mult_border_cases) { + test_mult_border_cases_curve(&secp256k1); + test_mult_border_cases_curve(&nist256p1); +} END_TEST -START_TEST(test_scalar_mult) { +static void test_scalar_mult_curve(const ecdsa_curve *curve) { int i; // get two "random" numbers - bignum256 a = G256k1.x; - bignum256 b = G256k1.y; + bignum256 a = curve->G.x; + bignum256 b = curve->G.y; curve_point p1, p2, p3; for (i = 0; i < 1000; i++) { /* test distributivity: (a + b)G = aG + bG */ - scalar_multiply(CURVE, &a, &p1); - scalar_multiply(CURVE, &b, &p2); - bn_addmod(&a, &b, &order256k1); - scalar_multiply(CURVE, &a, &p3); - point_add(CURVE, &p1, &p2); + bn_mod(&a, &curve->order); + bn_mod(&b, &curve->order); + scalar_multiply(curve, &a, &p1); + scalar_multiply(curve, &b, &p2); + bn_addmod(&a, &b, &curve->order); + bn_mod(&a, &curve->order); + scalar_multiply(curve, &a, &p3); + point_add(curve, &p1, &p2); ck_assert_mem_eq(&p2, &p3, sizeof(curve_point)); // new "random" numbers a = p3.x; b = p3.y; } } + +START_TEST(test_scalar_mult) { + test_scalar_mult_curve(&secp256k1); + test_scalar_mult_curve(&nist256p1); +} END_TEST -START_TEST(test_point_mult) { +static void test_point_mult_curve(const ecdsa_curve *curve) { int i; // get two "random" numbers and a "random" point - bignum256 a = G256k1.x; - bignum256 b = G256k1.y; - curve_point p = G256k1; + bignum256 a = curve->G.x; + bignum256 b = curve->G.y; + curve_point p = curve->G; curve_point p1, p2, p3; for (i = 0; i < 200; i++) { /* test distributivity: (a + b)P = aP + bP */ - point_multiply(CURVE, &a, &p, &p1); - point_multiply(CURVE, &b, &p, &p2); - bn_addmod(&a, &b, &order256k1); - point_multiply(CURVE, &a, &p, &p3); - point_add(CURVE, &p1, &p2); + bn_mod(&a, &curve->order); + bn_mod(&b, &curve->order); + point_multiply(curve, &a, &p, &p1); + point_multiply(curve, &b, &p, &p2); + bn_addmod(&a, &b, &curve->order); + bn_mod(&a, &curve->order); + point_multiply(curve, &a, &p, &p3); + point_add(curve, &p1, &p2); ck_assert_mem_eq(&p2, &p3, sizeof(curve_point)); // new "random" numbers and a "random" point a = p1.x; @@ -1330,28 +1351,36 @@ START_TEST(test_point_mult) { p = p3; } } + +START_TEST(test_point_mult) { + test_point_mult_curve(&secp256k1); + test_point_mult_curve(&nist256p1); +} END_TEST -START_TEST(test_scalar_point_mult) { +static void test_scalar_point_mult_curve(const ecdsa_curve *curve) { int i; // get two "random" numbers - bignum256 a = G256k1.x; - bignum256 b = G256k1.y; + bignum256 a = curve->G.x; + bignum256 b = curve->G.y; curve_point p1, p2; for (i = 0; i < 200; i++) { /* test commutativity and associativity: * a(bG) = (ab)G = b(aG) */ - scalar_multiply(CURVE, &a, &p1); - point_multiply(CURVE, &b, &p1, &p1); + bn_mod(&a, &curve->order); + bn_mod(&b, &curve->order); + scalar_multiply(curve, &a, &p1); + point_multiply(curve, &b, &p1, &p1); - scalar_multiply(CURVE, &b, &p2); - point_multiply(CURVE, &a, &p2, &p2); + scalar_multiply(curve, &b, &p2); + point_multiply(curve, &a, &p2, &p2); ck_assert_mem_eq(&p1, &p2, sizeof(curve_point)); - bn_multiply(&a, &b, &order256k1); - scalar_multiply(CURVE, &b, &p2); + bn_multiply(&a, &b, &curve->order); + bn_mod(&b, &curve->order); + scalar_multiply(curve, &b, &p2); ck_assert_mem_eq(&p1, &p2, sizeof(curve_point)); @@ -1360,6 +1389,11 @@ START_TEST(test_scalar_point_mult) { b = p1.y; } } + +START_TEST(test_scalar_point_mult) { + test_scalar_point_mult_curve(&secp256k1); + test_scalar_point_mult_curve(&nist256p1); +} END_TEST // define test suite and cases @@ -1423,8 +1457,8 @@ Suite *test_suite(void) tcase_add_test(tc, test_pubkey_validity); suite_add_tcase(s, tc); - tc = tcase_create("secp256k1_cp"); - tcase_add_test(tc, test_secp256k1_cp); + tc = tcase_create("codepoints"); + tcase_add_test(tc, test_codepoints); suite_add_tcase(s, tc); tc = tcase_create("mult_border_cases"); From a9b98a3671e8378e9ef82b22cb8b551e7a916dbe Mon Sep 17 00:00:00 2001 From: Roman Zeyde Date: Fri, 24 Jul 2015 18:31:18 +0300 Subject: [PATCH 214/627] test_curves: generalize UT for bignum cleanup --- test_curves.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/test_curves.py b/test_curves.py index 34af8d460..bf6d20634 100755 --- a/test_curves.py +++ b/test_curves.py @@ -199,7 +199,7 @@ def test_multiply2(curve, r): prime = int2bn(curve.p) lib.bn_multiply_reduce(x, res, prime) - x = bn2int(x) + x = bn2int(x) % curve.p x_ = s % curve.p assert x == x_ @@ -263,17 +263,17 @@ def test_point_double(curve, r): def test_point_to_jacobian(curve, r): - p = r.randpoint(curve) - jp = JACOBIAN() - lib.curve_to_jacobian(to_POINT(p), jp, int2bn(curve.p)) - jx, jy, jz = from_JACOBIAN(jp) - assert jx == (p.x() * jz ** 2) % curve.p - assert jy == (p.y() * jz ** 3) % curve.p + p = r.randpoint(curve) + jp = JACOBIAN() + lib.curve_to_jacobian(to_POINT(p), jp, int2bn(curve.p)) + jx, jy, jz = from_JACOBIAN(jp) + assert jx % curve.p == (p.x() * jz ** 2) % curve.p + assert jy % curve.p == (p.y() * jz ** 3) % curve.p - q = POINT() - lib.jacobian_to_curve(jp, q, int2bn(curve.p)) - q = from_POINT(q) - assert q == (p.x(), p.y()) + q = POINT() + lib.jacobian_to_curve(jp, q, int2bn(curve.p)) + q = from_POINT(q) + assert q == (p.x(), p.y()) def test_cond_negate(curve, r): @@ -282,7 +282,7 @@ def test_cond_negate(curve, r): lib.conditional_negate(0, a, int2bn(curve.p)) assert bn2int(a) == x lib.conditional_negate(-1, a, int2bn(curve.p)) - assert bn2int(a) == curve.p - x + assert bn2int(a) == 2*curve.p - x def test_jacobian_add(curve, r): From a1408fc5a08072822da65ea33a1a69eb90fbd82d Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Wed, 5 Aug 2015 22:26:50 +0200 Subject: [PATCH 215/627] Fix unit test for point_jacobian_add --- test_curves.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test_curves.py b/test_curves.py index bf6d20634..6aa4cb4ad 100755 --- a/test_curves.py +++ b/test_curves.py @@ -292,7 +292,7 @@ def test_jacobian_add(curve, r): q = POINT() jp2 = JACOBIAN() lib.curve_to_jacobian(to_POINT(p2), jp2, prime) - lib.point_jacobian_add(to_POINT(p1), jp2, prime) + lib.point_jacobian_add(to_POINT(p1), jp2, curve.ptr) lib.jacobian_to_curve(jp2, q, prime) q = from_POINT(q) p_ = p1 + p2 From 53fa580b81c733df549d6820e44d2d684a3377a0 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Wed, 5 Aug 2015 22:29:34 +0200 Subject: [PATCH 216/627] Added more unit tests - Added Romanz's validate_pubkey test. - Added special test to check that jacobin_point_add can double. --- test_curves.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/test_curves.py b/test_curves.py index 6aa4cb4ad..25e07dfb1 100755 --- a/test_curves.py +++ b/test_curves.py @@ -298,6 +298,19 @@ def test_jacobian_add(curve, r): p_ = p1 + p2 assert (p_.x(), p_.y()) == q +def test_jacobian_add_double(curve, r): + p1 = r.randpoint(curve) + p2 = p1 + prime = int2bn(curve.p) + q = POINT() + jp2 = JACOBIAN() + lib.curve_to_jacobian(to_POINT(p2), jp2, prime) + lib.point_jacobian_add(to_POINT(p1), jp2, curve.ptr) + lib.jacobian_to_curve(jp2, q, prime) + q = from_POINT(q) + p_ = p1 + p2 + assert (p_.x(), p_.y()) == q + def test_jacobian_double(curve, r): p = r.randpoint(curve) p2 = p.double() @@ -330,3 +343,7 @@ def test_sign(curve, r): assert binascii.hexlify(sig) == binascii.hexlify(sig_ref) assert vk.verify_digest(sig, digest, sigdecode) + +def test_validate_pubkey(curve, r): + p = r.randpoint(curve) + assert lib.ecdsa_validate_pubkey(curve.ptr, to_POINT(p)) From f93b003cbc411538456aaa5ef0276c1c32f310f5 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Thu, 6 Aug 2015 18:37:55 +0200 Subject: [PATCH 217/627] Extended comments, new function bn_add, a bug fix. Describe normalized, partly reduced and reduced numbers. Comment which function expects which kind of input. Removed unused bn_bitlen. Add bn_add that does not reduce. Bug fix in ecdsa_validate_pubkey: bn_mod before bn_is_equal. Bug fix in hdnode_private_ckd: bn_mod after bn_addmod. --- bignum.c | 150 ++++++++++++++++++++++++++++++++++++++----------------- bignum.h | 4 +- bip32.c | 1 + ecdsa.c | 22 ++++---- 4 files changed, 120 insertions(+), 57 deletions(-) diff --git a/bignum.c b/bignum.c index 6df05474a..90978abca 100644 --- a/bignum.c +++ b/bignum.c @@ -27,6 +27,31 @@ #include "bignum.h" #include "macros.h" +/* big number library */ + +/* The structure bignum256 is an array of nine 32-bit values, which + * are digits in base 2^30 representation. I.e. the number + * bignum256 a; + * represents the value + * sum_{i=0}^8 a.val[i] * 2^{30 i}. + * + * The number is *normalized* iff every digit is < 2^30. + * + * As the name suggests, a bignum256 is intended to represent a 256 + * bit number, but it can represent 270 bits. Numbers are usually + * reduced using a prime, either the group order or the field prime. + * The reduction is often partly done by bn_fast_mod, and similarly + * implicitly in bn_multiply. A *partly reduced number* is a + * normalized number between 0 (inclusive) and 2*prime (exclusive). + * + * A partly reduced number can be fully reduced by calling bn_mod. + * Only a fully reduced number is guaranteed to fit in 256 bit. + * + * All functions assume that the prime in question is slightly smaller + * than 2^256. In particular it must be between 2^256-2^224 and + * 2^256 and it must be a prime number. + */ + inline uint32_t read_be(const uint8_t *data) { return (((uint32_t)data[0]) << 24) | @@ -43,7 +68,8 @@ inline void write_be(uint8_t *data, uint32_t x) data[3] = x; } -// convert a raw bigendian 256 bit number to a normalized bignum +// convert a raw bigendian 256 bit value into a normalized bignum. +// out_number is partly reduced (since it fits in 256 bit). void bn_read_be(const uint8_t *in_number, bignum256 *out_number) { int i; @@ -63,7 +89,7 @@ void bn_read_be(const uint8_t *in_number, bignum256 *out_number) } // convert a normalized bignum to a raw bigendian 256 bit number. -// in_number must be normalized and < 2^256. +// in_number must be fully reduced. void bn_write_be(const bignum256 *in_number, uint8_t *out_number) { int i; @@ -77,6 +103,7 @@ void bn_write_be(const bignum256 *in_number, uint8_t *out_number) } } +// sets a bignum to zero. void bn_zero(bignum256 *a) { int i; @@ -85,6 +112,9 @@ void bn_zero(bignum256 *a) } } +// checks that a bignum is zero. +// a must be normalized +// function is constant time (on some architectures, in particular ARM). int bn_is_zero(const bignum256 *a) { int i; @@ -95,6 +125,9 @@ int bn_is_zero(const bignum256 *a) return !result; } +// Check whether a < b +// a and b must be normalized +// function is constant time (on some architectures, in particular ARM). int bn_is_less(const bignum256 *a, const bignum256 *b) { int i; @@ -107,6 +140,9 @@ int bn_is_less(const bignum256 *a, const bignum256 *b) return res1 > res2; } +// Check whether a == b +// a and b must be normalized +// function is constant time (on some architectures, in particular ARM). int bn_is_equal(const bignum256 *a, const bignum256 *b) { int i; uint32_t result = 0; @@ -116,6 +152,9 @@ int bn_is_equal(const bignum256 *a, const bignum256 *b) { return !result; } +// Assigns res = cond ? truecase : falsecase +// assumes that cond is either 0 or 1. +// function is constant time. void bn_cmov(bignum256 *res, int cond, const bignum256 *truecase, const bignum256 *falsecase) { int i; @@ -129,15 +168,8 @@ void bn_cmov(bignum256 *res, int cond, const bignum256 *truecase, const bignum25 } } -int bn_bitlen(const bignum256 *a) { - int i = 8, j; - while (i >= 0 && a->val[i] == 0) i--; - if (i == -1) return 0; - j = 29; - while ((a->val[i] & (1 << j)) == 0) j--; - return i * 30 + j + 1; -} - +// shift number to the left, i.e multiply it by 2. +// a must be normalized. The result is normalized but not reduced. void bn_lshift(bignum256 *a) { int i; @@ -147,6 +179,8 @@ void bn_lshift(bignum256 *a) a->val[0] = (a->val[0] << 1) & 0x3FFFFFFF; } +// shift number to the right, i.e divide by 2 while rounding down. +// a must be normalized. The result is normalized. void bn_rshift(bignum256 *a) { int i; @@ -157,8 +191,10 @@ void bn_rshift(bignum256 *a) } // multiply x by 1/2 modulo prime. -// assumes x < 2*prime, -// guarantees x < 4*prime on exit. +// it computes x = (x & 1) ? (x + prime) >> 1 : x >> 1. +// assumes x is normalized. +// if x was partly reduced, it is also partly reduced on exit. +// function is constant time. void bn_mult_half(bignum256 * x, const bignum256 *prime) { int j; @@ -177,8 +213,8 @@ void bn_mult_half(bignum256 * x, const bignum256 *prime) } // multiply x by k modulo prime. -// assumes x < prime, -// guarantees x < prime on exit. +// assumes x is normalized, 0 <= k <= 4. +// guarantees x is partly reduced. void bn_mult_k(bignum256 *x, uint8_t k, const bignum256 *prime) { int j; @@ -188,7 +224,8 @@ void bn_mult_k(bignum256 *x, uint8_t k, const bignum256 *prime) bn_fast_mod(x, prime); } -// assumes x < 2*prime, result < prime +// compute x = x mod prime by computing x >= prime ? x - prime : x. +// assumes x partly reduced, guarantees x fully reduced. void bn_mod(bignum256 *x, const bignum256 *prime) { int i = 8; @@ -214,6 +251,9 @@ void bn_mod(bignum256 *x, const bignum256 *prime) } } +// auxiliary function for multiplication. +// compute k * x as a 540 bit number in base 2^30 (normalized). +// assumes that k and x are normalized. void bn_multiply_long(const bignum256 *k, const bignum256 *x, uint32_t res[18]) { int i, j; @@ -223,6 +263,7 @@ void bn_multiply_long(const bignum256 *k, const bignum256 *x, uint32_t res[18]) for (i = 0; i < 9; i++) { for (j = 0; j <= i; j++) { + // no overflow, since 9*2^60 < 2^64 temp += k->val[j] * (uint64_t)x->val[i - j]; } res[i] = temp & 0x3FFFFFFFu; @@ -232,6 +273,7 @@ void bn_multiply_long(const bignum256 *k, const bignum256 *x, uint32_t res[18]) for (; i < 17; i++) { for (j = i - 8; j < 9 ; j++) { + // no overflow, since 9*2^60 < 2^64 temp += k->val[j] * (uint64_t)x->val[i - j]; } res[i] = temp & 0x3FFFFFFFu; @@ -240,13 +282,16 @@ void bn_multiply_long(const bignum256 *k, const bignum256 *x, uint32_t res[18]) res[17] = temp; } +// auxiliary function for multiplication. +// reduces res modulo prime. +// assumes res normalized, res < 2^(30(i-7)) * 2 * prime +// guarantees res normalized, res < 2^(30(i-8)) * 2 * prime void bn_multiply_reduce_step(uint32_t res[18], const bignum256 *prime, uint32_t i) { // let k = i-8. - // invariants: - // res[0..(i+1)] = k * x (mod prime) - // 0 <= res < 2^(30k + 256) * (2^31) - // estimate (res / prime) - // coef = res / 2^(30k + 256) rounded down + // on entry: + // 0 <= res < 2^(30k + 31) * prime + // estimate coef = (res / prime / 2^30k) + // by coef = res / 2^(30k + 256) rounded down // 0 <= coef < 2^31 // subtract (coef * 2^(30k) * prime) from res // note that we unrolled the first iteration @@ -257,11 +302,11 @@ void bn_multiply_reduce_step(uint32_t res[18], const bignum256 *prime, uint32_t res[i - 8] = temp & 0x3FFFFFFF; for (j = 1; j < 9; j++) { temp >>= 30; - // Note: coeff * prime->val <= (2^31-1) * (2^30-1) + // Note: coeff * prime->val[j] <= (2^31-1) * (2^30-1) // Hence, this addition will not underflow. temp += 0x1FFFFFFF80000000ull + res[i - 8 + j] - prime->val[j] * (uint64_t)coef; res[i - 8 + j] = temp & 0x3FFFFFFF; - // 0 <= temp < 2^61 + // 0 <= temp < 2^61 + 2^30 } temp >>= 30; temp += 0x1FFFFFFF80000000ull + res[i - 8 + j]; @@ -271,18 +316,20 @@ void bn_multiply_reduce_step(uint32_t res[18], const bignum256 *prime, uint32_t // and // coef * 2^(30k + 256) <= oldres < (coef+1) * 2^(30k + 256) // Hence, 0 <= res < 2^30k (2^256 + coef * (2^256 - prime)) - // Since coef * (2^256 - prime) < 2^256, we get - // 0 <= res < 2^(30k + 226) (2^31) - // Thus the invariant holds again. + // < 2^30k (2^256 + 2^31 * 2^224) + // < 2^30k (2 * prime) } +// auxiliary function for multiplication. +// reduces x = res modulo prime. +// assumes res normalized, res < 2^270 * 2 * prime +// guarantees x partly reduced, i.e., x < 2 * prime void bn_multiply_reduce(bignum256 *x, uint32_t res[18], const bignum256 *prime) { int i; // res = k * x is a normalized number (every limb < 2^30) - // 0 <= res < 2^526. - // compute modulo p division is only estimated so this may give result greater than prime but not bigger than 2 * prime + // 0 <= res < 2^270 * 2 * prime. for (i = 16; i >= 8; i--) { bn_multiply_reduce_step(res, prime, i); assert(res[i + 1] == 0); @@ -294,11 +341,9 @@ void bn_multiply_reduce(bignum256 *x, uint32_t res[18], const bignum256 *prime) } // Compute x := k * x (mod prime) -// both inputs must be smaller than 2 * prime. -// result is reduced to 0 <= x < 2 * prime -// This only works for primes between 2^256-2^196 and 2^256. -// this particular implementation accepts inputs up to 2^263 or 128*prime. - +// both inputs must be smaller than 180 * prime. +// result is partly reduced (0 <= x < 2 * prime) +// This only works for primes between 2^256-2^224 and 2^256. void bn_multiply(const bignum256 *k, bignum256 *x, const bignum256 *prime) { uint32_t res[18] = {0}; @@ -307,9 +352,11 @@ void bn_multiply(const bignum256 *k, bignum256 *x, const bignum256 *prime) MEMSET_BZERO(res, sizeof(res)); } -// input x can be any normalized number that fits (0 <= x < 2^270). +// partly reduce x modulo prime +// input x does not have to be normalized. +// x can be any number that fits. // prime must be between (2^256 - 2^224) and 2^256 -// result is smaller than 2*prime +// result is partly reduced, smaller than 2*prime void bn_fast_mod(bignum256 *x, const bignum256 *prime) { int j; @@ -330,6 +377,8 @@ void bn_fast_mod(bignum256 *x, const bignum256 *prime) // square root of x = x^((p+1)/4) // http://en.wikipedia.org/wiki/Quadratic_residue#Prime_or_prime_power_modulus +// assumes x is normalized but not necessarily reduced. +// guarantees x is reduced void bn_sqrt(bignum256 *x, const bignum256 *prime) { // this method compute x^1/2 = x^(prime+1)/4 @@ -678,10 +727,18 @@ void bn_inverse(bignum256 *x, const bignum256 *prime) #endif void bn_normalize(bignum256 *a) { + bn_addi(a, 0); +} + +// add two numbers a = a + b +// assumes that a, b are normalized +// guarantees that a is normalized +void bn_add(bignum256 *a, const bignum256 *b) +{ int i; uint32_t tmp = 0; for (i = 0; i < 9; i++) { - tmp += a->val[i]; + tmp += a->val[i] + b->val[i]; a->val[i] = tmp & 0x3FFFFFFF; tmp >>= 30; } @@ -697,22 +754,25 @@ void bn_addmod(bignum256 *a, const bignum256 *b, const bignum256 *prime) } void bn_addi(bignum256 *a, uint32_t b) { - a->val[0] += b; - bn_normalize(a); -} - -void bn_subi(bignum256 *a, uint32_t b, const bignum256 *prime) { int i; + uint32_t tmp = b; for (i = 0; i < 9; i++) { - a->val[i] += prime->val[i]; + tmp += a->val[i]; + a->val[i] = tmp & 0x3FFFFFFF; + tmp >>= 30; } +} + +void bn_subi(bignum256 *a, uint32_t b, const bignum256 *prime) { + assert (b <= prime->val[0]); + // the possible underflow will be taken care of when adding the prime a->val[0] -= b; - bn_fast_mod(a, prime); + bn_add(a, prime); } // res = a - b mod prime. More exactly res = a + (2*prime - b). -// precondition: 0 <= b < 2*prime, 0 <= a < prime -// res < 3*prime +// b must be a partly reduced number +// result is normalized but not reduced. void bn_subtractmod(const bignum256 *a, const bignum256 *b, bignum256 *res, const bignum256 *prime) { int i; diff --git a/bignum.h b/bignum.h index 119063ac2..8778aec7b 100644 --- a/bignum.h +++ b/bignum.h @@ -53,8 +53,6 @@ int bn_is_equal(const bignum256 *a, const bignum256 *b); void bn_cmov(bignum256 *res, int cond, const bignum256 *truecase, const bignum256 *falsecase); -int bn_bitlen(const bignum256 *a); - void bn_lshift(bignum256 *a); void bn_rshift(bignum256 *a); @@ -75,6 +73,8 @@ void bn_inverse(bignum256 *x, const bignum256 *prime); void bn_normalize(bignum256 *a); +void bn_add(bignum256 *a, const bignum256 *b); + void bn_addmod(bignum256 *a, const bignum256 *b, const bignum256 *prime); void bn_addi(bignum256 *a, uint32_t b); diff --git a/bip32.c b/bip32.c index a8a3c5e12..3aa6d27df 100644 --- a/bip32.c +++ b/bip32.c @@ -143,6 +143,7 @@ int hdnode_private_ckd(HDNode *inout, uint32_t i) } if (!failed) { bn_addmod(&a, &b, &default_curve->order); + bn_mod(&a, &default_curve->order); if (bn_is_zero(&a)) { failed = true; } diff --git a/ecdsa.c b/ecdsa.c index 333d36148..c757c31ff 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -287,7 +287,7 @@ void point_jacobian_add(const curve_point *p1, jacobian_curve_point *p2, const e bn_fast_mod(&h, prime); // h = x1' - x2; - bn_addmod(&xz, &p2->x, prime); + bn_add(&xz, &p2->x); // xz = x1' + x2 is_doubling = bn_is_zero(&h) | bn_is_equal(&h, prime); @@ -296,7 +296,7 @@ void point_jacobian_add(const curve_point *p1, jacobian_curve_point *p2, const e bn_subtractmod(&yz, &p2->y, &r, prime); // r = y1' - y2; - bn_addmod(&yz, &p2->y, prime); + bn_add(&yz, &p2->y); // yz = y1' + y2 r2 = p2->x; @@ -347,6 +347,7 @@ void point_jacobian_double(jacobian_curve_point *p, const ecdsa_curve *curve) { bignum256 az4, m, msq, ysq, xysq; const bignum256 *prime = &curve->prime; + assert (-3 <= curve->a && curve->a <= 0); /* usual algorithm: * * lambda = (3((x/z^2)^2 + a) / 2y/z^3) = (3x^2 + az^4)/2yz @@ -861,7 +862,7 @@ void uncompress_coords(const ecdsa_curve *curve, uint8_t odd, const bignum256 *x bn_multiply(x, y, &curve->prime); // y is x^2 bn_subi(y, -curve->a, &curve->prime); // y is x^2 + a bn_multiply(x, y, &curve->prime); // y is x^3 + ax - bn_addmod(y, &curve->b, &curve->prime); // y is x^3 + ax + b + bn_add(y, &curve->b); // y is x^3 + ax + b bn_sqrt(y, &curve->prime); // y = sqrt(y) if ((odd & 0x01) != (y->val[0] & 1)) { bn_subtract(&curve->prime, y, y); // y = -y @@ -891,7 +892,7 @@ int ecdsa_read_pubkey(const ecdsa_curve *curve, const uint8_t *pub_key, curve_po int ecdsa_validate_pubkey(const ecdsa_curve *curve, const curve_point *pub) { - bignum256 y_2, x_3_b; + bignum256 y_2, x3_ax_b; if (point_is_infinity(pub)) { return 0; @@ -902,19 +903,20 @@ int ecdsa_validate_pubkey(const ecdsa_curve *curve, const curve_point *pub) } memcpy(&y_2, &(pub->y), sizeof(bignum256)); - memcpy(&x_3_b, &(pub->x), sizeof(bignum256)); + memcpy(&x3_ax_b, &(pub->x), sizeof(bignum256)); // y^2 bn_multiply(&(pub->y), &y_2, &curve->prime); bn_mod(&y_2, &curve->prime); // x^3 + ax + b - bn_multiply(&(pub->x), &x_3_b, &curve->prime); // x^2 - bn_subi(&x_3_b, -curve->a, &curve->prime); // x^2 + a - bn_multiply(&(pub->x), &x_3_b, &curve->prime); // x^3 + ax - bn_addmod(&x_3_b, &curve->b, &curve->prime); // x^3 + ax + b + bn_multiply(&(pub->x), &x3_ax_b, &curve->prime); // x^2 + bn_subi(&x3_ax_b, -curve->a, &curve->prime); // x^2 + a + bn_multiply(&(pub->x), &x3_ax_b, &curve->prime); // x^3 + ax + bn_addmod(&x3_ax_b, &curve->b, &curve->prime); // x^3 + ax + b + bn_mod(&x3_ax_b, &curve->prime); - if (!bn_is_equal(&x_3_b, &y_2)) { + if (!bn_is_equal(&x3_ax_b, &y_2)) { return 0; } From 11d14a3946e28db596b0511f1b848528d5fa62c3 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Fri, 7 Aug 2015 11:15:10 +0200 Subject: [PATCH 218/627] Fixed unit test for addmod added test for add. - bn_addmod: now only guarantees result < 2*prime. - bn_add: new test - bn_mult_half: fixed normalization of prime -> 0. --- test_curves.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/test_curves.py b/test_curves.py index 25e07dfb1..a05e2638f 100755 --- a/test_curves.py +++ b/test_curves.py @@ -129,7 +129,7 @@ def test_mult_half(curve, r): y = int2bn(x) lib.bn_mult_half(y, int2bn(curve.p)) y = bn2int(y) - if y > curve.p: + if y >= curve.p: y -= curve.p half = ecdsa.numbertheory.inverse_mod(2, curve.p) assert y == (x * half) % curve.p @@ -156,6 +156,17 @@ def test_subtract2(r): assert z == z_ +def test_add(curve, r): + x = r.randrange(0, 2 ** 256) + y = r.randrange(0, 2 ** 256) + z_ = x + y + z = int2bn(x) + lib.bn_add(z, int2bn(y)) + z = bn2int(z) + + assert z == z_ + + def test_addmod(curve, r): x = r.randrange(0, 2 ** 256) y = r.randrange(0, 2 ** 256) @@ -163,7 +174,8 @@ def test_addmod(curve, r): z = int2bn(x) lib.bn_addmod(z, int2bn(y), int2bn(curve.p)) z = bn2int(z) - + if z >= curve.p: + z = z - curve.p assert z == z_ From 774ac9cb22ab84d0523219661c900e1574928c3e Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Fri, 7 Aug 2015 11:26:00 +0200 Subject: [PATCH 219/627] Simplified test for doubling in point_jacobian_add --- ecdsa.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ecdsa.c b/ecdsa.c index c757c31ff..bf4446339 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -290,7 +290,11 @@ void point_jacobian_add(const curve_point *p1, jacobian_curve_point *p2, const e bn_add(&xz, &p2->x); // xz = x1' + x2 - is_doubling = bn_is_zero(&h) | bn_is_equal(&h, prime); + // check for h == 0 % prime. Note that h never normalizes to + // zero, since h = x1' + 2*prime - x2 > 0 and a positive + // multiple of prime is always normalized to prime by + // bn_fast_mod. + is_doubling = bn_is_equal(&h, prime); bn_multiply(&p1->y, &yz, prime); // yz = y1' = y1*z2^3; bn_subtractmod(&yz, &p2->y, &r, prime); From 50428bb37bbc7a708248daf109d33d4d9fefe042 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Wed, 19 Aug 2015 21:23:36 +0200 Subject: [PATCH 220/627] Added more tests for specific points. Some points designed to test for underflow of x^3-ax. --- test_curves.py | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/test_curves.py b/test_curves.py index a05e2638f..67d180809 100755 --- a/test_curves.py +++ b/test_curves.py @@ -19,6 +19,24 @@ curves = { 'secp256k1': ecdsa.curves.SECP256k1 } +class Point: + def __init__(self, name, x, y): + self.curve = name + self.x = x + self.y = y + +points = [ + Point('secp256k1', 0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798, 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8), + Point('secp256k1', 0x1, 0x4218f20ae6c646b363db68605822fb14264ca8d2587fdd6fbc750d587e76a7ee), + Point('secp256k1', 0x2, 0x66fbe727b2ba09e09f5a98d70a5efce8424c5fa425bbda1c511f860657b8535e), + Point('secp256k1', 0x1b,0x1adcea1cf831b0ad1653e769d1a229091d0cc68d4b0328691b9caacc76e37c90), + Point('nist256p1', 0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296, 0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5), + Point('nist256p1', 0x0, 0x66485c780e2f83d72433bd5d84a06bb6541c2af31dae871728bf856a174f93f4), + Point('nist256p1', 0x0, 0x99b7a386f1d07c29dbcc42a27b5f9449abe3d50de25178e8d7407a95e8b06c0b), + Point('nist256p1', 0xaf8bbdfe8cdd5577acbf345b543d28cf402f4e94d3865b97ea0787f2d3aa5d22,0x35802b8b376b995265918b078bc109c21a535176585c40f519aca52d6afc147c), + Point('nist256p1', 0x80000, 0x580610071f440f0dcc14a22e2d5d5afc1224c0cd11a3b4b51b8ecd2224ee1ce2) +] + random_iters = int(os.environ.get('ITERS', 1)) lib = c.cdll.LoadLibrary('./libtrezor-crypto.so') @@ -72,6 +90,15 @@ def curve(request): curve_obj.p = curve_obj.curve.p() # shorthand return curve_obj +@pytest.fixture(params=points) +def point(request): + name = request.param.curve + curve_ptr = lib.get_curve_by_name(name) + assert curve_ptr, 'curve {} not found'.format(name) + curve_obj = curves[name] + curve_obj.ptr = c.c_void_p(curve_ptr) + curve_obj.p = ecdsa.ellipticcurve.Point(curve_obj.curve, request.param.x, request.param.y) + return curve_obj def test_inverse(curve, r): x = r.randrange(1, curve.p) @@ -359,3 +386,7 @@ def test_sign(curve, r): def test_validate_pubkey(curve, r): p = r.randpoint(curve) assert lib.ecdsa_validate_pubkey(curve.ptr, to_POINT(p)) + + +def test_validate_pubkey_direct(point): + assert lib.ecdsa_validate_pubkey(point.ptr, to_POINT(point.p)) From 472b90d8edae65b08a7584d6818507cc5430bf6e Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Wed, 19 Aug 2015 21:45:21 +0200 Subject: [PATCH 221/627] Added myself to copyright lines. --- bignum.c | 1 + ecdsa.c | 1 + 2 files changed, 2 insertions(+) diff --git a/bignum.c b/bignum.c index 90978abca..2ba8afe5e 100644 --- a/bignum.c +++ b/bignum.c @@ -1,6 +1,7 @@ /** * Copyright (c) 2013-2014 Tomas Dzetkulic * Copyright (c) 2013-2014 Pavol Rusnak + * Copyright (c) 2015 Jochen Hoenicke * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the "Software"), diff --git a/ecdsa.c b/ecdsa.c index bf4446339..8d4e8df3e 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -1,6 +1,7 @@ /** * Copyright (c) 2013-2014 Tomas Dzetkulic * Copyright (c) 2013-2014 Pavol Rusnak + * Copyright (c) 2015 Jochen Hoenicke * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the "Software"), From 437f8b385604bbfaa09af8f148b61f7c28a88686 Mon Sep 17 00:00:00 2001 From: Roman Zeyde Date: Mon, 31 Aug 2015 20:55:02 +0300 Subject: [PATCH 222/627] bignum: constant time implementation for bn_mod() --- bignum.c | 25 ++++--------------------- 1 file changed, 4 insertions(+), 21 deletions(-) diff --git a/bignum.c b/bignum.c index 2ba8afe5e..05a867ab5 100644 --- a/bignum.c +++ b/bignum.c @@ -229,27 +229,10 @@ void bn_mult_k(bignum256 *x, uint8_t k, const bignum256 *prime) // assumes x partly reduced, guarantees x fully reduced. void bn_mod(bignum256 *x, const bignum256 *prime) { - int i = 8; - uint32_t temp; - // compare numbers - while (i >= 0 && prime->val[i] == x->val[i]) i--; - // if equal - if (i == -1) { - // set x to zero - bn_zero(x); - } else { - // if x is greater - if (x->val[i] > prime->val[i]) { - // substract p from x - temp = 0x40000000u; - for (i = 0; i < 9; i++) { - temp += x->val[i] - prime->val[i]; - x->val[i] = temp & 0x3FFFFFFF; - temp >>= 30; - temp += 0x3FFFFFFFu; - } - } - } + const int flag = bn_is_less(x, prime); // x < prime + bignum256 temp; + bn_subtract(x, prime, &temp); // temp = x - prime + bn_cmov(x, flag, x, &temp); } // auxiliary function for multiplication. From 12c3b1ccf6a4014da077a9c1427faec588af0be1 Mon Sep 17 00:00:00 2001 From: Roman Zeyde Date: Mon, 31 Aug 2015 21:11:24 +0300 Subject: [PATCH 223/627] bignum: add specific tests for bn_mod() edge cases --- test_curves.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test_curves.py b/test_curves.py index 67d180809..c511bbc97 100755 --- a/test_curves.py +++ b/test_curves.py @@ -261,6 +261,13 @@ def test_mod(curve, r): lib.bn_mod(y, int2bn(curve.p)) assert bn2int(y) == x % curve.p +def test_mod_specific(curve): + p = curve.p + for x in [0, 1, 2, p - 2, p - 1, p, p + 1, p + 2, 2*p - 2, 2*p - 1]: + y = int2bn(x) + lib.bn_mod(y, int2bn(curve.p)) + assert bn2int(y) == x % p + POINT = BIGNUM * 2 to_POINT = lambda p: POINT(int2bn(p.x()), int2bn(p.y())) from_POINT = lambda p: (bn2int(p[0]), bn2int(p[1])) From 1d7fb4e38fa41abb5e65c957845f3db74755f3b2 Mon Sep 17 00:00:00 2001 From: 251 <251io@users.noreply.github.com> Date: Mon, 21 Sep 2015 23:51:10 +0200 Subject: [PATCH 224/627] Fixes a bug in the test_pbkdf2_hmac_sha256 test. This bug fix sets the length of the derived key in the last test_pbkdf2_hmac_sha256 test to 40 bytes to fix a buffer overflow, which is caused by the call to the pbkdf2_hmac_sha256 function, on the memory reserved by the local variable k. --- tests.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests.c b/tests.c index f7c578915..47d5724eb 100644 --- a/tests.c +++ b/tests.c @@ -761,7 +761,7 @@ START_TEST(test_pbkdf2_hmac_sha256) ck_assert_mem_eq(k, fromhex("c5e478d59288c841aa530db6845c4c8d962893a001ce4e11a4963873aa98134a"), 32); strcpy((char *)s, "saltSALTsaltSALTsaltSALTsaltSALTsalt"); - pbkdf2_hmac_sha256((uint8_t *)"passwordPASSWORDpassword", 3*8, s, 9*4, 4096, k, 64, 0); + pbkdf2_hmac_sha256((uint8_t *)"passwordPASSWORDpassword", 3*8, s, 9*4, 4096, k, 40, 0); ck_assert_mem_eq(k, fromhex("348c89dbcbd32b2f32d814b8116e84cf2b17347ebc1800181c4e2a1fb8dd53e1c635518c7dac47e9"), 40); } END_TEST From 3556c74740b64484eeec4716d57c197828b330a0 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 14 Dec 2015 22:50:09 +0100 Subject: [PATCH 225/627] fix build on _WIN32 --- rand.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/rand.c b/rand.c index 6bb72c35d..2770c30ec 100644 --- a/rand.c +++ b/rand.c @@ -22,7 +22,11 @@ */ #include +#ifdef _WIN32 +#include +#else #include +#endif #include "rand.h" @@ -30,14 +34,22 @@ static FILE *frand = NULL; int finalize_rand(void) { +#ifdef _WIN32 + return 0; +#else if (!frand) return 0; int err = fclose(frand); frand = NULL; return err; +#endif } uint32_t random32(void) { +#ifdef _WIN32 + srand((unsigned)time(NULL)); + return ((rand() % 0xFF) | ((rand() % 0xFF) << 8) | ((rand() % 0xFF) << 16) | ((rand() % 0xFF) << 24)); +#else uint32_t r; size_t len = sizeof(r); if (!frand) { @@ -47,6 +59,7 @@ uint32_t random32(void) (void)len_read; assert(len_read == len); return r; +#endif } uint32_t random_uniform(uint32_t n) @@ -58,12 +71,20 @@ uint32_t random_uniform(uint32_t n) void random_buffer(uint8_t *buf, size_t len) { +#ifdef _WIN32 + srand((unsigned)time(NULL)); + size_t i; + for (i = 0; i < len; i++) { + buf[i] = rand() % 0xFF; + } +#else if (!frand) { frand = fopen("/dev/urandom", "r"); } size_t len_read = fread(buf, 1, len, frand); (void)len_read; assert(len_read == len); +#endif } void random_permute(char *str, size_t len) From 9a8e982153d3acab75c0707e3c88872f6c5c781c Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 19 Jan 2016 15:11:57 +0100 Subject: [PATCH 226/627] implement bip39 cache --- bip39.c | 47 +++++++++++++++++++++++++++++++++++++++++++---- options.h | 6 ++++++ tests.c | 5 +++++ 3 files changed, 54 insertions(+), 4 deletions(-) diff --git a/bip39.c b/bip39.c index 5985fe819..aa9ad9e1d 100644 --- a/bip39.c +++ b/bip39.c @@ -22,6 +22,7 @@ */ #include +#include #include "bip39.h" #include "hmac.h" @@ -29,6 +30,20 @@ #include "sha2.h" #include "pbkdf2.h" #include "bip39_english.h" +#include "options.h" + +#if USE_BIP39_CACHE + +static int bip39_cache_index = 0; + +static struct { + bool set; + char mnemonic[256]; + char passphrase[64]; + uint8_t seed[512 / 8]; +} bip39_cache[BIP39_CACHE_SIZE]; + +#endif const char *mnemonic_generate(int strength) { @@ -148,12 +163,36 @@ int mnemonic_check(const char *mnemonic) // passphrase must be at most 256 characters or code may crash void mnemonic_to_seed(const char *mnemonic, const char *passphrase, uint8_t seed[512 / 8], void (*progress_callback)(uint32_t current, uint32_t total)) { + int passphraselen = strlen(passphrase); +#if USE_BIP39_CACHE + int mnemoniclen = strlen(mnemonic); + // check cache + if (mnemoniclen < 256 && passphraselen < 64) { + int i; + for (i = 0; i < BIP39_CACHE_SIZE; i++) { + if (!bip39_cache[i].set) continue; + if (strcmp(bip39_cache[i].mnemonic, mnemonic) != 0) continue; + if (strcmp(bip39_cache[i].passphrase, passphrase) != 0) continue; + // found the correct entry + memcpy(seed, bip39_cache[i].seed, 512 / 8); + return; + } + } +#endif uint8_t salt[8 + 256 + 4]; - int saltlen = strlen(passphrase); memcpy(salt, "mnemonic", 8); - memcpy(salt + 8, passphrase, saltlen); - saltlen += 8; - pbkdf2_hmac_sha512((const uint8_t *)mnemonic, strlen(mnemonic), salt, saltlen, BIP39_PBKDF2_ROUNDS, seed, 512 / 8, progress_callback); + memcpy(salt + 8, passphrase, passphraselen); + pbkdf2_hmac_sha512((const uint8_t *)mnemonic, strlen(mnemonic), salt, passphraselen + 8, BIP39_PBKDF2_ROUNDS, seed, 512 / 8, progress_callback); +#if USE_BIP39_CACHE + // store to cache + if (mnemoniclen < 256 && passphraselen < 64) { + bip39_cache[bip39_cache_index].set = true; + strcpy(bip39_cache[bip39_cache_index].mnemonic, mnemonic); + strcpy(bip39_cache[bip39_cache_index].passphrase, passphrase); + memcpy(bip39_cache[bip39_cache_index].seed, seed, 512 / 8); + bip39_cache_index = (bip39_cache_index + 1) % BIP39_CACHE_SIZE; + } +#endif } const char * const *mnemonic_wordlist(void) diff --git a/options.h b/options.h index 9612fdfcf..d5ac4ab33 100644 --- a/options.h +++ b/options.h @@ -50,4 +50,10 @@ #define BIP32_CACHE_MAXDEPTH 8 #endif +// implement BIP39 caching +#ifndef USE_BIP39_CACHE +#define USE_BIP39_CACHE 1 +#define BIP39_CACHE_SIZE 4 +#endif + #endif diff --git a/tests.c b/tests.c index 47d5724eb..8c34b48e5 100644 --- a/tests.c +++ b/tests.c @@ -880,6 +880,11 @@ START_TEST(test_mnemonic) ck_assert_str_eq(m, *b); mnemonic_to_seed(m, "TREZOR", seed, 0); ck_assert_mem_eq(seed, fromhex(*c), strlen(*c) / 2); +#if USE_BIP39_CACHE + // try second time to check whether caching results work + mnemonic_to_seed(m, "TREZOR", seed, 0); + ck_assert_mem_eq(seed, fromhex(*c), strlen(*c) / 2); +#endif a += 3; b += 3; c += 3; } } From fbc0df736a6583d1fa3b89d4e57889bd9ad3a191 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 19 Jan 2016 15:34:31 +0100 Subject: [PATCH 227/627] call progress callback at the beginning of pbkdf2 calculation --- pbkdf2.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pbkdf2.c b/pbkdf2.c index 363618e08..d4beef77b 100644 --- a/pbkdf2.c +++ b/pbkdf2.c @@ -42,6 +42,9 @@ void pbkdf2_hmac_sha256(const uint8_t *pass, int passlen, uint8_t *salt, int sal salt[saltlen + 3] = i & 0xFF; hmac_sha256(pass, passlen, salt, saltlen + 4, g); memcpy(f, g, HMACLEN); + if (progress_callback) { + progress_callback(0, iterations); + } for (j = 1; j < iterations; j++) { hmac_sha256(pass, passlen, g, HMACLEN, g); for (k = 0; k < HMACLEN; k++) { @@ -77,6 +80,9 @@ void pbkdf2_hmac_sha512(const uint8_t *pass, int passlen, uint8_t *salt, int sal salt[saltlen + 3] = i & 0xFF; hmac_sha512(pass, passlen, salt, saltlen + 4, g); memcpy(f, g, HMACLEN); + if (progress_callback) { + progress_callback(0, iterations); + } for (j = 1; j < iterations; j++) { hmac_sha512(pass, passlen, g, HMACLEN, g); for (k = 0; k < HMACLEN; k++) { From 2b5859ca47aee498bc667934abac0852e7736387 Mon Sep 17 00:00:00 2001 From: Karel Bilek Date: Tue, 26 Jan 2016 20:07:45 +0100 Subject: [PATCH 228/627] Adding nist256p1 to CMakeLists --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f5f3293a6..0c80b4899 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 2.6) -set(SOURCES aescrypt.c aeskey.c aes_modes.c aestab.c base58.c bignum.c bip32.c bip39.c ecdsa.c hmac.c pbkdf2.c rand.c ripemd160.c secp256k1.c sha2.c) +set(SOURCES aescrypt.c aeskey.c aes_modes.c aestab.c base58.c bignum.c bip32.c bip39.c ecdsa.c hmac.c nist256p1.c pbkdf2.c rand.c ripemd160.c secp256k1.c sha2.c) # disable sequence point warnings where they are expected set_source_files_properties(aeskey.c PROPERTIES From b1a73ed9847473178c8c367bcdae70d1b2df39cd Mon Sep 17 00:00:00 2001 From: Karel Bilek Date: Tue, 26 Jan 2016 22:15:38 +0100 Subject: [PATCH 229/627] Adding cmake to travis Not 100% if it will work, let's see --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index c36250fc8..d270aea8b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,3 +16,6 @@ script: - ./tests - ./test-openssl 1000 - ITERS=10 py.test + - mkdir _build && cd _build + - cmake .. + - make From bb52cb4ac93dd36e22bac7fef003f5b5488f2e08 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 31 Jan 2016 12:16:02 +0100 Subject: [PATCH 230/627] adjust format of LICENSE --- LICENSE | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/LICENSE b/LICENSE index f43bfa74c..1ea1df703 100644 --- a/LICENSE +++ b/LICENSE @@ -1,20 +1,22 @@ +The MIT License (MIT) + Copyright (c) 2013 Tomas Dzetkulic Copyright (c) 2013 Pavol Rusnak -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the "Software"), -to deal in the Software without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following conditions: +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Software. +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES -OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. From 86d6a0b782cc0d61eb37ead53e5aa37f8de7aa0e Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 14 Apr 2016 10:58:08 +0200 Subject: [PATCH 231/627] adopt ripemd160 from mbedtls --- ripemd160.c | 626 +++++++++++++++++++++++++++------------------------- ripemd160.h | 11 +- 2 files changed, 341 insertions(+), 296 deletions(-) diff --git a/ripemd160.c b/ripemd160.c index 1d767b7e1..4b2ce88aa 100644 --- a/ripemd160.c +++ b/ripemd160.c @@ -1,303 +1,339 @@ -#include +/* + * RIPE MD-160 implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +/* + * The RIPEMD-160 algorithm was designed by RIPE in 1996 + * http://homes.esat.kuleuven.be/~bosselae/ripemd160.html + * http://ehash.iaik.tugraz.at/wiki/RIPEMD-160 + */ #include "ripemd160.h" +#include + +/* + * 32-bit integer manipulation macros (little endian) + */ +#ifndef GET_UINT32_LE +#define GET_UINT32_LE(n,b,i) \ +{ \ + (n) = ( (uint32_t) (b)[(i) ] ) \ + | ( (uint32_t) (b)[(i) + 1] << 8 ) \ + | ( (uint32_t) (b)[(i) + 2] << 16 ) \ + | ( (uint32_t) (b)[(i) + 3] << 24 ); \ +} +#endif + +#ifndef PUT_UINT32_LE +#define PUT_UINT32_LE(n,b,i) \ +{ \ + (b)[(i) ] = (uint8_t) ( ( (n) ) & 0xFF ); \ + (b)[(i) + 1] = (uint8_t) ( ( (n) >> 8 ) & 0xFF ); \ + (b)[(i) + 2] = (uint8_t) ( ( (n) >> 16 ) & 0xFF ); \ + (b)[(i) + 3] = (uint8_t) ( ( (n) >> 24 ) & 0xFF ); \ +} +#endif + +/* + * RIPEMD-160 context setup + */ +void ripemd160_init(RIPEMD160_CTX *ctx) +{ + memset(ctx, 0, sizeof(RIPEMD160_CTX)); + ctx->total[0] = 0; + ctx->total[1] = 0; + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xEFCDAB89; + ctx->state[2] = 0x98BADCFE; + ctx->state[3] = 0x10325476; + ctx->state[4] = 0xC3D2E1F0; +} + +#if !defined(MBEDTLS_RIPEMD160_PROCESS_ALT) +/* + * Process one block + */ +void ripemd160_process( RIPEMD160_CTX *ctx, const uint8_t data[64] ) +{ + uint32_t A, B, C, D, E, Ap, Bp, Cp, Dp, Ep, X[16]; + + GET_UINT32_LE( X[ 0], data, 0 ); + GET_UINT32_LE( X[ 1], data, 4 ); + GET_UINT32_LE( X[ 2], data, 8 ); + GET_UINT32_LE( X[ 3], data, 12 ); + GET_UINT32_LE( X[ 4], data, 16 ); + GET_UINT32_LE( X[ 5], data, 20 ); + GET_UINT32_LE( X[ 6], data, 24 ); + GET_UINT32_LE( X[ 7], data, 28 ); + GET_UINT32_LE( X[ 8], data, 32 ); + GET_UINT32_LE( X[ 9], data, 36 ); + GET_UINT32_LE( X[10], data, 40 ); + GET_UINT32_LE( X[11], data, 44 ); + GET_UINT32_LE( X[12], data, 48 ); + GET_UINT32_LE( X[13], data, 52 ); + GET_UINT32_LE( X[14], data, 56 ); + GET_UINT32_LE( X[15], data, 60 ); + + A = Ap = ctx->state[0]; + B = Bp = ctx->state[1]; + C = Cp = ctx->state[2]; + D = Dp = ctx->state[3]; + E = Ep = ctx->state[4]; + +#define F1( x, y, z ) ( x ^ y ^ z ) +#define F2( x, y, z ) ( ( x & y ) | ( ~x & z ) ) +#define F3( x, y, z ) ( ( x | ~y ) ^ z ) +#define F4( x, y, z ) ( ( x & z ) | ( y & ~z ) ) +#define F5( x, y, z ) ( x ^ ( y | ~z ) ) + +#define S( x, n ) ( ( x << n ) | ( x >> (32 - n) ) ) + +#define P( a, b, c, d, e, r, s, f, k ) \ + a += f( b, c, d ) + X[r] + k; \ + a = S( a, s ) + e; \ + c = S( c, 10 ); + +#define P2( a, b, c, d, e, r, s, rp, sp ) \ + P( a, b, c, d, e, r, s, F, K ); \ + P( a ## p, b ## p, c ## p, d ## p, e ## p, rp, sp, Fp, Kp ); + +#define F F1 +#define K 0x00000000 +#define Fp F5 +#define Kp 0x50A28BE6 + P2( A, B, C, D, E, 0, 11, 5, 8 ); + P2( E, A, B, C, D, 1, 14, 14, 9 ); + P2( D, E, A, B, C, 2, 15, 7, 9 ); + P2( C, D, E, A, B, 3, 12, 0, 11 ); + P2( B, C, D, E, A, 4, 5, 9, 13 ); + P2( A, B, C, D, E, 5, 8, 2, 15 ); + P2( E, A, B, C, D, 6, 7, 11, 15 ); + P2( D, E, A, B, C, 7, 9, 4, 5 ); + P2( C, D, E, A, B, 8, 11, 13, 7 ); + P2( B, C, D, E, A, 9, 13, 6, 7 ); + P2( A, B, C, D, E, 10, 14, 15, 8 ); + P2( E, A, B, C, D, 11, 15, 8, 11 ); + P2( D, E, A, B, C, 12, 6, 1, 14 ); + P2( C, D, E, A, B, 13, 7, 10, 14 ); + P2( B, C, D, E, A, 14, 9, 3, 12 ); + P2( A, B, C, D, E, 15, 8, 12, 6 ); +#undef F +#undef K +#undef Fp +#undef Kp + +#define F F2 +#define K 0x5A827999 +#define Fp F4 +#define Kp 0x5C4DD124 + P2( E, A, B, C, D, 7, 7, 6, 9 ); + P2( D, E, A, B, C, 4, 6, 11, 13 ); + P2( C, D, E, A, B, 13, 8, 3, 15 ); + P2( B, C, D, E, A, 1, 13, 7, 7 ); + P2( A, B, C, D, E, 10, 11, 0, 12 ); + P2( E, A, B, C, D, 6, 9, 13, 8 ); + P2( D, E, A, B, C, 15, 7, 5, 9 ); + P2( C, D, E, A, B, 3, 15, 10, 11 ); + P2( B, C, D, E, A, 12, 7, 14, 7 ); + P2( A, B, C, D, E, 0, 12, 15, 7 ); + P2( E, A, B, C, D, 9, 15, 8, 12 ); + P2( D, E, A, B, C, 5, 9, 12, 7 ); + P2( C, D, E, A, B, 2, 11, 4, 6 ); + P2( B, C, D, E, A, 14, 7, 9, 15 ); + P2( A, B, C, D, E, 11, 13, 1, 13 ); + P2( E, A, B, C, D, 8, 12, 2, 11 ); +#undef F +#undef K +#undef Fp +#undef Kp + +#define F F3 +#define K 0x6ED9EBA1 +#define Fp F3 +#define Kp 0x6D703EF3 + P2( D, E, A, B, C, 3, 11, 15, 9 ); + P2( C, D, E, A, B, 10, 13, 5, 7 ); + P2( B, C, D, E, A, 14, 6, 1, 15 ); + P2( A, B, C, D, E, 4, 7, 3, 11 ); + P2( E, A, B, C, D, 9, 14, 7, 8 ); + P2( D, E, A, B, C, 15, 9, 14, 6 ); + P2( C, D, E, A, B, 8, 13, 6, 6 ); + P2( B, C, D, E, A, 1, 15, 9, 14 ); + P2( A, B, C, D, E, 2, 14, 11, 12 ); + P2( E, A, B, C, D, 7, 8, 8, 13 ); + P2( D, E, A, B, C, 0, 13, 12, 5 ); + P2( C, D, E, A, B, 6, 6, 2, 14 ); + P2( B, C, D, E, A, 13, 5, 10, 13 ); + P2( A, B, C, D, E, 11, 12, 0, 13 ); + P2( E, A, B, C, D, 5, 7, 4, 7 ); + P2( D, E, A, B, C, 12, 5, 13, 5 ); +#undef F +#undef K +#undef Fp +#undef Kp -#define ROL(x, n) (((x) << (n)) | ((x) >> (32-(n)))) - -#define F(x, y, z) ((x) ^ (y) ^ (z)) -#define G(x, y, z) (((x) & (y)) | (~(x) & (z))) -#define H(x, y, z) (((x) | ~(y)) ^ (z)) -#define IQ(x, y, z) (((x) & (z)) | ((y) & ~(z))) -#define J(x, y, z) ((x) ^ ((y) | ~(z))) - -#define FF(a, b, c, d, e, x, s) {\ - (a) += F((b), (c), (d)) + (x);\ - (a) = ROL((a), (s)) + (e);\ - (c) = ROL((c), 10);\ - } -#define GG(a, b, c, d, e, x, s) {\ - (a) += G((b), (c), (d)) + (x) + 0x5a827999UL;\ - (a) = ROL((a), (s)) + (e);\ - (c) = ROL((c), 10);\ - } -#define HH(a, b, c, d, e, x, s) {\ - (a) += H((b), (c), (d)) + (x) + 0x6ed9eba1UL;\ - (a) = ROL((a), (s)) + (e);\ - (c) = ROL((c), 10);\ - } -#define II(a, b, c, d, e, x, s) {\ - (a) += IQ((b), (c), (d)) + (x) + 0x8f1bbcdcUL;\ - (a) = ROL((a), (s)) + (e);\ - (c) = ROL((c), 10);\ - } -#define JJ(a, b, c, d, e, x, s) {\ - (a) += J((b), (c), (d)) + (x) + 0xa953fd4eUL;\ - (a) = ROL((a), (s)) + (e);\ - (c) = ROL((c), 10);\ - } -#define FFF(a, b, c, d, e, x, s) {\ - (a) += F((b), (c), (d)) + (x);\ - (a) = ROL((a), (s)) + (e);\ - (c) = ROL((c), 10);\ - } -#define GGG(a, b, c, d, e, x, s) {\ - (a) += G((b), (c), (d)) + (x) + 0x7a6d76e9UL;\ - (a) = ROL((a), (s)) + (e);\ - (c) = ROL((c), 10);\ - } -#define HHH(a, b, c, d, e, x, s) {\ - (a) += H((b), (c), (d)) + (x) + 0x6d703ef3UL;\ - (a) = ROL((a), (s)) + (e);\ - (c) = ROL((c), 10);\ - } -#define III(a, b, c, d, e, x, s) {\ - (a) += IQ((b), (c), (d)) + (x) + 0x5c4dd124UL;\ - (a) = ROL((a), (s)) + (e);\ - (c) = ROL((c), 10);\ - } -#define JJJ(a, b, c, d, e, x, s) {\ - (a) += J((b), (c), (d)) + (x) + 0x50a28be6UL;\ - (a) = ROL((a), (s)) + (e);\ - (c) = ROL((c), 10);\ - } - -static void compress(uint32_t *MDbuf, uint32_t *X) +#define F F4 +#define K 0x8F1BBCDC +#define Fp F2 +#define Kp 0x7A6D76E9 + P2( C, D, E, A, B, 1, 11, 8, 15 ); + P2( B, C, D, E, A, 9, 12, 6, 5 ); + P2( A, B, C, D, E, 11, 14, 4, 8 ); + P2( E, A, B, C, D, 10, 15, 1, 11 ); + P2( D, E, A, B, C, 0, 14, 3, 14 ); + P2( C, D, E, A, B, 8, 15, 11, 14 ); + P2( B, C, D, E, A, 12, 9, 15, 6 ); + P2( A, B, C, D, E, 4, 8, 0, 14 ); + P2( E, A, B, C, D, 13, 9, 5, 6 ); + P2( D, E, A, B, C, 3, 14, 12, 9 ); + P2( C, D, E, A, B, 7, 5, 2, 12 ); + P2( B, C, D, E, A, 15, 6, 13, 9 ); + P2( A, B, C, D, E, 14, 8, 9, 12 ); + P2( E, A, B, C, D, 5, 6, 7, 5 ); + P2( D, E, A, B, C, 6, 5, 10, 15 ); + P2( C, D, E, A, B, 2, 12, 14, 8 ); +#undef F +#undef K +#undef Fp +#undef Kp + +#define F F5 +#define K 0xA953FD4E +#define Fp F1 +#define Kp 0x00000000 + P2( B, C, D, E, A, 4, 9, 12, 8 ); + P2( A, B, C, D, E, 0, 15, 15, 5 ); + P2( E, A, B, C, D, 5, 5, 10, 12 ); + P2( D, E, A, B, C, 9, 11, 4, 9 ); + P2( C, D, E, A, B, 7, 6, 1, 12 ); + P2( B, C, D, E, A, 12, 8, 5, 5 ); + P2( A, B, C, D, E, 2, 13, 8, 14 ); + P2( E, A, B, C, D, 10, 12, 7, 6 ); + P2( D, E, A, B, C, 14, 5, 6, 8 ); + P2( C, D, E, A, B, 1, 12, 2, 13 ); + P2( B, C, D, E, A, 3, 13, 13, 6 ); + P2( A, B, C, D, E, 8, 14, 14, 5 ); + P2( E, A, B, C, D, 11, 11, 0, 15 ); + P2( D, E, A, B, C, 6, 8, 3, 13 ); + P2( C, D, E, A, B, 15, 5, 9, 11 ); + P2( B, C, D, E, A, 13, 6, 11, 11 ); +#undef F +#undef K +#undef Fp +#undef Kp + + C = ctx->state[1] + C + Dp; + ctx->state[1] = ctx->state[2] + D + Ep; + ctx->state[2] = ctx->state[3] + E + Ap; + ctx->state[3] = ctx->state[4] + A + Bp; + ctx->state[4] = ctx->state[0] + B + Cp; + ctx->state[0] = C; +} +#endif /* !MBEDTLS_RIPEMD160_PROCESS_ALT */ + +/* + * RIPEMD-160 process buffer + */ +void ripemd160_update( RIPEMD160_CTX *ctx, const uint8_t *input, uint32_t ilen ) { - uint32_t aa = MDbuf[0], bb = MDbuf[1], cc = MDbuf[2], dd = MDbuf[3], ee = MDbuf[4]; - uint32_t aaa = MDbuf[0], bbb = MDbuf[1], ccc = MDbuf[2], ddd = MDbuf[3], eee = MDbuf[4]; - - /* round 1 */ - FF(aa, bb, cc, dd, ee, X[ 0], 11); - FF(ee, aa, bb, cc, dd, X[ 1], 14); - FF(dd, ee, aa, bb, cc, X[ 2], 15); - FF(cc, dd, ee, aa, bb, X[ 3], 12); - FF(bb, cc, dd, ee, aa, X[ 4], 5); - FF(aa, bb, cc, dd, ee, X[ 5], 8); - FF(ee, aa, bb, cc, dd, X[ 6], 7); - FF(dd, ee, aa, bb, cc, X[ 7], 9); - FF(cc, dd, ee, aa, bb, X[ 8], 11); - FF(bb, cc, dd, ee, aa, X[ 9], 13); - FF(aa, bb, cc, dd, ee, X[10], 14); - FF(ee, aa, bb, cc, dd, X[11], 15); - FF(dd, ee, aa, bb, cc, X[12], 6); - FF(cc, dd, ee, aa, bb, X[13], 7); - FF(bb, cc, dd, ee, aa, X[14], 9); - FF(aa, bb, cc, dd, ee, X[15], 8); - - /* round 2 */ - GG(ee, aa, bb, cc, dd, X[ 7], 7); - GG(dd, ee, aa, bb, cc, X[ 4], 6); - GG(cc, dd, ee, aa, bb, X[13], 8); - GG(bb, cc, dd, ee, aa, X[ 1], 13); - GG(aa, bb, cc, dd, ee, X[10], 11); - GG(ee, aa, bb, cc, dd, X[ 6], 9); - GG(dd, ee, aa, bb, cc, X[15], 7); - GG(cc, dd, ee, aa, bb, X[ 3], 15); - GG(bb, cc, dd, ee, aa, X[12], 7); - GG(aa, bb, cc, dd, ee, X[ 0], 12); - GG(ee, aa, bb, cc, dd, X[ 9], 15); - GG(dd, ee, aa, bb, cc, X[ 5], 9); - GG(cc, dd, ee, aa, bb, X[ 2], 11); - GG(bb, cc, dd, ee, aa, X[14], 7); - GG(aa, bb, cc, dd, ee, X[11], 13); - GG(ee, aa, bb, cc, dd, X[ 8], 12); - - /* round 3 */ - HH(dd, ee, aa, bb, cc, X[ 3], 11); - HH(cc, dd, ee, aa, bb, X[10], 13); - HH(bb, cc, dd, ee, aa, X[14], 6); - HH(aa, bb, cc, dd, ee, X[ 4], 7); - HH(ee, aa, bb, cc, dd, X[ 9], 14); - HH(dd, ee, aa, bb, cc, X[15], 9); - HH(cc, dd, ee, aa, bb, X[ 8], 13); - HH(bb, cc, dd, ee, aa, X[ 1], 15); - HH(aa, bb, cc, dd, ee, X[ 2], 14); - HH(ee, aa, bb, cc, dd, X[ 7], 8); - HH(dd, ee, aa, bb, cc, X[ 0], 13); - HH(cc, dd, ee, aa, bb, X[ 6], 6); - HH(bb, cc, dd, ee, aa, X[13], 5); - HH(aa, bb, cc, dd, ee, X[11], 12); - HH(ee, aa, bb, cc, dd, X[ 5], 7); - HH(dd, ee, aa, bb, cc, X[12], 5); - - /* round 4 */ - II(cc, dd, ee, aa, bb, X[ 1], 11); - II(bb, cc, dd, ee, aa, X[ 9], 12); - II(aa, bb, cc, dd, ee, X[11], 14); - II(ee, aa, bb, cc, dd, X[10], 15); - II(dd, ee, aa, bb, cc, X[ 0], 14); - II(cc, dd, ee, aa, bb, X[ 8], 15); - II(bb, cc, dd, ee, aa, X[12], 9); - II(aa, bb, cc, dd, ee, X[ 4], 8); - II(ee, aa, bb, cc, dd, X[13], 9); - II(dd, ee, aa, bb, cc, X[ 3], 14); - II(cc, dd, ee, aa, bb, X[ 7], 5); - II(bb, cc, dd, ee, aa, X[15], 6); - II(aa, bb, cc, dd, ee, X[14], 8); - II(ee, aa, bb, cc, dd, X[ 5], 6); - II(dd, ee, aa, bb, cc, X[ 6], 5); - II(cc, dd, ee, aa, bb, X[ 2], 12); - - /* round 5 */ - JJ(bb, cc, dd, ee, aa, X[ 4], 9); - JJ(aa, bb, cc, dd, ee, X[ 0], 15); - JJ(ee, aa, bb, cc, dd, X[ 5], 5); - JJ(dd, ee, aa, bb, cc, X[ 9], 11); - JJ(cc, dd, ee, aa, bb, X[ 7], 6); - JJ(bb, cc, dd, ee, aa, X[12], 8); - JJ(aa, bb, cc, dd, ee, X[ 2], 13); - JJ(ee, aa, bb, cc, dd, X[10], 12); - JJ(dd, ee, aa, bb, cc, X[14], 5); - JJ(cc, dd, ee, aa, bb, X[ 1], 12); - JJ(bb, cc, dd, ee, aa, X[ 3], 13); - JJ(aa, bb, cc, dd, ee, X[ 8], 14); - JJ(ee, aa, bb, cc, dd, X[11], 11); - JJ(dd, ee, aa, bb, cc, X[ 6], 8); - JJ(cc, dd, ee, aa, bb, X[15], 5); - JJ(bb, cc, dd, ee, aa, X[13], 6); - - /* parallel round 1 */ - JJJ(aaa, bbb, ccc, ddd, eee, X[ 5], 8); - JJJ(eee, aaa, bbb, ccc, ddd, X[14], 9); - JJJ(ddd, eee, aaa, bbb, ccc, X[ 7], 9); - JJJ(ccc, ddd, eee, aaa, bbb, X[ 0], 11); - JJJ(bbb, ccc, ddd, eee, aaa, X[ 9], 13); - JJJ(aaa, bbb, ccc, ddd, eee, X[ 2], 15); - JJJ(eee, aaa, bbb, ccc, ddd, X[11], 15); - JJJ(ddd, eee, aaa, bbb, ccc, X[ 4], 5); - JJJ(ccc, ddd, eee, aaa, bbb, X[13], 7); - JJJ(bbb, ccc, ddd, eee, aaa, X[ 6], 7); - JJJ(aaa, bbb, ccc, ddd, eee, X[15], 8); - JJJ(eee, aaa, bbb, ccc, ddd, X[ 8], 11); - JJJ(ddd, eee, aaa, bbb, ccc, X[ 1], 14); - JJJ(ccc, ddd, eee, aaa, bbb, X[10], 14); - JJJ(bbb, ccc, ddd, eee, aaa, X[ 3], 12); - JJJ(aaa, bbb, ccc, ddd, eee, X[12], 6); - - /* parallel round 2 */ - III(eee, aaa, bbb, ccc, ddd, X[ 6], 9); - III(ddd, eee, aaa, bbb, ccc, X[11], 13); - III(ccc, ddd, eee, aaa, bbb, X[ 3], 15); - III(bbb, ccc, ddd, eee, aaa, X[ 7], 7); - III(aaa, bbb, ccc, ddd, eee, X[ 0], 12); - III(eee, aaa, bbb, ccc, ddd, X[13], 8); - III(ddd, eee, aaa, bbb, ccc, X[ 5], 9); - III(ccc, ddd, eee, aaa, bbb, X[10], 11); - III(bbb, ccc, ddd, eee, aaa, X[14], 7); - III(aaa, bbb, ccc, ddd, eee, X[15], 7); - III(eee, aaa, bbb, ccc, ddd, X[ 8], 12); - III(ddd, eee, aaa, bbb, ccc, X[12], 7); - III(ccc, ddd, eee, aaa, bbb, X[ 4], 6); - III(bbb, ccc, ddd, eee, aaa, X[ 9], 15); - III(aaa, bbb, ccc, ddd, eee, X[ 1], 13); - III(eee, aaa, bbb, ccc, ddd, X[ 2], 11); - - /* parallel round 3 */ - HHH(ddd, eee, aaa, bbb, ccc, X[15], 9); - HHH(ccc, ddd, eee, aaa, bbb, X[ 5], 7); - HHH(bbb, ccc, ddd, eee, aaa, X[ 1], 15); - HHH(aaa, bbb, ccc, ddd, eee, X[ 3], 11); - HHH(eee, aaa, bbb, ccc, ddd, X[ 7], 8); - HHH(ddd, eee, aaa, bbb, ccc, X[14], 6); - HHH(ccc, ddd, eee, aaa, bbb, X[ 6], 6); - HHH(bbb, ccc, ddd, eee, aaa, X[ 9], 14); - HHH(aaa, bbb, ccc, ddd, eee, X[11], 12); - HHH(eee, aaa, bbb, ccc, ddd, X[ 8], 13); - HHH(ddd, eee, aaa, bbb, ccc, X[12], 5); - HHH(ccc, ddd, eee, aaa, bbb, X[ 2], 14); - HHH(bbb, ccc, ddd, eee, aaa, X[10], 13); - HHH(aaa, bbb, ccc, ddd, eee, X[ 0], 13); - HHH(eee, aaa, bbb, ccc, ddd, X[ 4], 7); - HHH(ddd, eee, aaa, bbb, ccc, X[13], 5); - - /* parallel round 4 */ - GGG(ccc, ddd, eee, aaa, bbb, X[ 8], 15); - GGG(bbb, ccc, ddd, eee, aaa, X[ 6], 5); - GGG(aaa, bbb, ccc, ddd, eee, X[ 4], 8); - GGG(eee, aaa, bbb, ccc, ddd, X[ 1], 11); - GGG(ddd, eee, aaa, bbb, ccc, X[ 3], 14); - GGG(ccc, ddd, eee, aaa, bbb, X[11], 14); - GGG(bbb, ccc, ddd, eee, aaa, X[15], 6); - GGG(aaa, bbb, ccc, ddd, eee, X[ 0], 14); - GGG(eee, aaa, bbb, ccc, ddd, X[ 5], 6); - GGG(ddd, eee, aaa, bbb, ccc, X[12], 9); - GGG(ccc, ddd, eee, aaa, bbb, X[ 2], 12); - GGG(bbb, ccc, ddd, eee, aaa, X[13], 9); - GGG(aaa, bbb, ccc, ddd, eee, X[ 9], 12); - GGG(eee, aaa, bbb, ccc, ddd, X[ 7], 5); - GGG(ddd, eee, aaa, bbb, ccc, X[10], 15); - GGG(ccc, ddd, eee, aaa, bbb, X[14], 8); - - /* parallel round 5 */ - FFF(bbb, ccc, ddd, eee, aaa, X[12] , 8); - FFF(aaa, bbb, ccc, ddd, eee, X[15] , 5); - FFF(eee, aaa, bbb, ccc, ddd, X[10] , 12); - FFF(ddd, eee, aaa, bbb, ccc, X[ 4] , 9); - FFF(ccc, ddd, eee, aaa, bbb, X[ 1] , 12); - FFF(bbb, ccc, ddd, eee, aaa, X[ 5] , 5); - FFF(aaa, bbb, ccc, ddd, eee, X[ 8] , 14); - FFF(eee, aaa, bbb, ccc, ddd, X[ 7] , 6); - FFF(ddd, eee, aaa, bbb, ccc, X[ 6] , 8); - FFF(ccc, ddd, eee, aaa, bbb, X[ 2] , 13); - FFF(bbb, ccc, ddd, eee, aaa, X[13] , 6); - FFF(aaa, bbb, ccc, ddd, eee, X[14] , 5); - FFF(eee, aaa, bbb, ccc, ddd, X[ 0] , 15); - FFF(ddd, eee, aaa, bbb, ccc, X[ 3] , 13); - FFF(ccc, ddd, eee, aaa, bbb, X[ 9] , 11); - FFF(bbb, ccc, ddd, eee, aaa, X[11] , 11); - - /* combine results */ - ddd += cc + MDbuf[1]; - MDbuf[1] = MDbuf[2] + dd + eee; - MDbuf[2] = MDbuf[3] + ee + aaa; - MDbuf[3] = MDbuf[4] + aa + bbb; - MDbuf[4] = MDbuf[0] + bb + ccc; - MDbuf[0] = ddd; + uint32_t fill; + uint32_t left; + + if( ilen == 0 ) + return; + + left = ctx->total[0] & 0x3F; + fill = 64 - left; + + ctx->total[0] += (uint32_t) ilen; + ctx->total[0] &= 0xFFFFFFFF; + + if( ctx->total[0] < (uint32_t) ilen ) + ctx->total[1]++; + + if( left && ilen >= fill ) + { + memcpy( (void *) (ctx->buffer + left), input, fill ); + ripemd160_process( ctx, ctx->buffer ); + input += fill; + ilen -= fill; + left = 0; + } + + while( ilen >= 64 ) + { + ripemd160_process( ctx, input ); + input += 64; + ilen -= 64; + } + + if( ilen > 0 ) + { + memcpy( (void *) (ctx->buffer + left), input, ilen ); + } +} + +static const uint8_t ripemd160_padding[64] = +{ + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* + * RIPEMD-160 final digest + */ +void ripemd160_finish( RIPEMD160_CTX *ctx, uint8_t output[20] ) +{ + uint32_t last, padn; + uint32_t high, low; + uint8_t msglen[8]; + + high = ( ctx->total[0] >> 29 ) + | ( ctx->total[1] << 3 ); + low = ( ctx->total[0] << 3 ); + + PUT_UINT32_LE( low, msglen, 0 ); + PUT_UINT32_LE( high, msglen, 4 ); + + last = ctx->total[0] & 0x3F; + padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); + + ripemd160_update( ctx, ripemd160_padding, padn ); + ripemd160_update( ctx, msglen, 8 ); + + PUT_UINT32_LE( ctx->state[0], output, 0 ); + PUT_UINT32_LE( ctx->state[1], output, 4 ); + PUT_UINT32_LE( ctx->state[2], output, 8 ); + PUT_UINT32_LE( ctx->state[3], output, 12 ); + PUT_UINT32_LE( ctx->state[4], output, 16 ); } -void ripemd160(const uint8_t *msg, uint32_t msg_len, uint8_t *hash) +/* + * output = RIPEMD-160( input buffer ) + */ +void ripemd160(const uint8_t *msg, uint32_t msg_len, uint8_t hash[20]) { - uint32_t i; - int j; - uint32_t digest[5] = {0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0UL}; - - for (i = 0; i < (msg_len >> 6); ++i) { - uint32_t chunk[16]; - - for (j = 0; j < 16; ++j) { - chunk[j] = (uint32_t)(*(msg++)); - chunk[j] |= (uint32_t)(*(msg++)) << 8; - chunk[j] |= (uint32_t)(*(msg++)) << 16; - chunk[j] |= (uint32_t)(*(msg++)) << 24; - } - - compress (digest, chunk); - } - - // Last chunk - { - uint32_t chunk[16] = {0}; - - for (i = 0; i < (msg_len & 63); ++i) { - chunk[i >> 2] ^= (uint32_t) *msg++ << ((i&3) << 3); - } - - chunk[(msg_len >> 2)&15] ^= (uint32_t)1 << (8*(msg_len&3) + 7); - - if ((msg_len & 63) > 55) { - compress (digest, chunk); - memset (chunk, 0, 64); - } - - chunk[14] = msg_len << 3; - chunk[15] = (msg_len >> 29); - compress (digest, chunk); - } - - for (i = 0; i < 5; ++i) { - *(hash++) = digest[i]; - *(hash++) = digest[i] >> 8; - *(hash++) = digest[i] >> 16; - *(hash++) = digest[i] >> 24; - } + RIPEMD160_CTX ctx; + ripemd160_init( &ctx ); + ripemd160_update( &ctx, msg, msg_len ); + ripemd160_finish( &ctx, hash ); } diff --git a/ripemd160.h b/ripemd160.h index 2c634f16c..033f6c123 100644 --- a/ripemd160.h +++ b/ripemd160.h @@ -3,6 +3,15 @@ #include -void ripemd160(const uint8_t *msg, uint32_t msg_len, uint8_t *hash); +typedef struct _RIPEMD160_CTX { + uint32_t total[2]; /*!< number of bytes processed */ + uint32_t state[5]; /*!< intermediate digest state */ + uint8_t buffer[64]; /*!< data block being processed */ +} RIPEMD160_CTX; + +void ripemd160_init(RIPEMD160_CTX *ctx); +void ripemd160_update(RIPEMD160_CTX *ctx, const uint8_t *input, uint32_t ilen); +void ripemd160_finish(RIPEMD160_CTX *ctx, uint8_t output[20]); +void ripemd160(const uint8_t *msg, uint32_t msg_len, uint8_t hash[20]); #endif From f4dd151eb9ef989b88dc79218a2b0115934e4268 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 14 Apr 2016 17:28:46 +0200 Subject: [PATCH 232/627] change ripemd160 function names to match sha2 functions --- ripemd160.c | 16 ++++++++-------- ripemd160.h | 6 +++--- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/ripemd160.c b/ripemd160.c index 4b2ce88aa..4fdf2e930 100644 --- a/ripemd160.c +++ b/ripemd160.c @@ -54,7 +54,7 @@ /* * RIPEMD-160 context setup */ -void ripemd160_init(RIPEMD160_CTX *ctx) +void ripemd160_Init(RIPEMD160_CTX *ctx) { memset(ctx, 0, sizeof(RIPEMD160_CTX)); ctx->total[0] = 0; @@ -251,7 +251,7 @@ void ripemd160_process( RIPEMD160_CTX *ctx, const uint8_t data[64] ) /* * RIPEMD-160 process buffer */ -void ripemd160_update( RIPEMD160_CTX *ctx, const uint8_t *input, uint32_t ilen ) +void ripemd160_Update( RIPEMD160_CTX *ctx, const uint8_t *input, uint32_t ilen ) { uint32_t fill; uint32_t left; @@ -301,7 +301,7 @@ static const uint8_t ripemd160_padding[64] = /* * RIPEMD-160 final digest */ -void ripemd160_finish( RIPEMD160_CTX *ctx, uint8_t output[20] ) +void ripemd160_Final( uint8_t output[20], RIPEMD160_CTX *ctx ) { uint32_t last, padn; uint32_t high, low; @@ -317,8 +317,8 @@ void ripemd160_finish( RIPEMD160_CTX *ctx, uint8_t output[20] ) last = ctx->total[0] & 0x3F; padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); - ripemd160_update( ctx, ripemd160_padding, padn ); - ripemd160_update( ctx, msglen, 8 ); + ripemd160_Update( ctx, ripemd160_padding, padn ); + ripemd160_Update( ctx, msglen, 8 ); PUT_UINT32_LE( ctx->state[0], output, 0 ); PUT_UINT32_LE( ctx->state[1], output, 4 ); @@ -333,7 +333,7 @@ void ripemd160_finish( RIPEMD160_CTX *ctx, uint8_t output[20] ) void ripemd160(const uint8_t *msg, uint32_t msg_len, uint8_t hash[20]) { RIPEMD160_CTX ctx; - ripemd160_init( &ctx ); - ripemd160_update( &ctx, msg, msg_len ); - ripemd160_finish( &ctx, hash ); + ripemd160_Init( &ctx ); + ripemd160_Update( &ctx, msg, msg_len ); + ripemd160_Final( hash, &ctx ); } diff --git a/ripemd160.h b/ripemd160.h index 033f6c123..159baeb61 100644 --- a/ripemd160.h +++ b/ripemd160.h @@ -9,9 +9,9 @@ typedef struct _RIPEMD160_CTX { uint8_t buffer[64]; /*!< data block being processed */ } RIPEMD160_CTX; -void ripemd160_init(RIPEMD160_CTX *ctx); -void ripemd160_update(RIPEMD160_CTX *ctx, const uint8_t *input, uint32_t ilen); -void ripemd160_finish(RIPEMD160_CTX *ctx, uint8_t output[20]); +void ripemd160_Init(RIPEMD160_CTX *ctx); +void ripemd160_Update(RIPEMD160_CTX *ctx, const uint8_t *input, uint32_t ilen); +void ripemd160_Final(uint8_t output[20], RIPEMD160_CTX *ctx); void ripemd160(const uint8_t *msg, uint32_t msg_len, uint8_t hash[20]); #endif From c983afd72f40a8c65355af076afd9c132878e8a5 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Tue, 19 Apr 2016 18:21:56 +0200 Subject: [PATCH 233/627] Added curve type to HDNode Every curve gets it's own hierarchy and the curve is remembered in HD node. Fixed the private/public key derivations to use the right modulus. --- bip32.c | 36 +++++++++++++++++++----------------- bip32.h | 7 ++++--- nist256p1.c | 1 + nist256p1.h | 1 + secp256k1.c | 2 ++ secp256k1.h | 1 + 6 files changed, 28 insertions(+), 20 deletions(-) diff --git a/bip32.c b/bip32.c index 3aa6d27df..18c96252f 100644 --- a/bip32.c +++ b/bip32.c @@ -34,9 +34,7 @@ #include "macros.h" #include "secp256k1.h" -static const ecdsa_curve *default_curve = &secp256k1; - -int hdnode_from_xpub(uint32_t depth, uint32_t fingerprint, uint32_t child_num, const uint8_t *chain_code, const uint8_t *public_key, HDNode *out) +int hdnode_from_xpub(uint32_t depth, uint32_t fingerprint, uint32_t child_num, const uint8_t *chain_code, const uint8_t *public_key, const char* curve, HDNode *out) { if (public_key[0] != 0x02 && public_key[0] != 0x03) { // invalid pubkey return 0; @@ -47,19 +45,21 @@ int hdnode_from_xpub(uint32_t depth, uint32_t fingerprint, uint32_t child_num, c memcpy(out->chain_code, chain_code, 32); MEMSET_BZERO(out->private_key, 32); memcpy(out->public_key, public_key, 33); + out->curve = get_curve_by_name(curve); return 1; } -int hdnode_from_xprv(uint32_t depth, uint32_t fingerprint, uint32_t child_num, const uint8_t *chain_code, const uint8_t *private_key, HDNode *out) +int hdnode_from_xprv(uint32_t depth, uint32_t fingerprint, uint32_t child_num, const uint8_t *chain_code, const uint8_t *private_key, const char* curve, HDNode *out) { bignum256 a; bn_read_be(private_key, &a); + out->curve = get_curve_by_name(curve); bool failed = false; if (bn_is_zero(&a)) { // == 0 failed = true; } else { - if (!bn_is_less(&a, &default_curve->order)) { // >= order + if (!bn_is_less(&a, &out->curve->order)) { // >= order failed = true; } MEMSET_BZERO(&a, sizeof(a)); @@ -78,13 +78,14 @@ int hdnode_from_xprv(uint32_t depth, uint32_t fingerprint, uint32_t child_num, c return 1; } -int hdnode_from_seed(const uint8_t *seed, int seed_len, HDNode *out) +int hdnode_from_seed(const uint8_t *seed, int seed_len, const char* curve, HDNode *out) { uint8_t I[32 + 32]; memset(out, 0, sizeof(HDNode)); out->depth = 0; out->fingerprint = 0x00000000; out->child_num = 0; + out->curve = get_curve_by_name(curve); hmac_sha512((uint8_t *)"Bitcoin seed", 12, seed, seed_len, I); memcpy(out->private_key, I, 32); bignum256 a; @@ -94,7 +95,7 @@ int hdnode_from_seed(const uint8_t *seed, int seed_len, HDNode *out) if (bn_is_zero(&a)) { // == 0 failed = true; } else { - if (!bn_is_less(&a, &default_curve->order)) { // >= order + if (!bn_is_less(&a, &out->curve->order)) { // >= order failed = true; } MEMSET_BZERO(&a, sizeof(a)); @@ -138,12 +139,12 @@ int hdnode_private_ckd(HDNode *inout, uint32_t i) bool failed = false; - if (!bn_is_less(&b, &default_curve->order)) { // >= order + if (!bn_is_less(&b, &inout->curve->order)) { // >= order failed = true; } if (!failed) { - bn_addmod(&a, &b, &default_curve->order); - bn_mod(&a, &default_curve->order); + bn_addmod(&a, &b, &inout->curve->order); + bn_mod(&a, &inout->curve->order); if (bn_is_zero(&a)) { failed = true; } @@ -186,7 +187,7 @@ int hdnode_public_ckd(HDNode *inout, uint32_t i) memset(inout->private_key, 0, 32); bool failed = false; - if (!ecdsa_read_pubkey(default_curve, inout->public_key, &a)) { + if (!ecdsa_read_pubkey(inout->curve, inout->public_key, &a)) { failed = true; } @@ -194,15 +195,15 @@ int hdnode_public_ckd(HDNode *inout, uint32_t i) hmac_sha512(inout->chain_code, 32, data, sizeof(data), I); memcpy(inout->chain_code, I + 32, 32); bn_read_be(I, &c); - if (!bn_is_less(&c, &default_curve->order)) { // >= order + if (!bn_is_less(&c, &inout->curve->order)) { // >= order failed = true; } } if (!failed) { - scalar_multiply(default_curve, &c, &b); // b = c * G - point_add(default_curve, &a, &b); // b = a + b - if (!ecdsa_validate_pubkey(default_curve, &b)) { + scalar_multiply(inout->curve, &c, &b); // b = c * G + point_add(inout->curve, &a, &b); // b = a + b + if (!ecdsa_validate_pubkey(inout->curve, &b)) { failed = true; } } @@ -263,7 +264,8 @@ int hdnode_private_ckd_cached(HDNode *inout, const uint32_t *i, size_t i_count) for (j = 0; j < BIP32_CACHE_SIZE; j++) { if (private_ckd_cache[j].set && private_ckd_cache[j].depth == i_count - 1 && - memcmp(private_ckd_cache[j].i, i, (i_count - 1) * sizeof(uint32_t)) == 0) { + memcmp(private_ckd_cache[j].i, i, (i_count - 1) * sizeof(uint32_t)) == 0 && + private_ckd_cache[j].node.curve == inout->curve) { memcpy(inout, &(private_ckd_cache[j].node), sizeof(HDNode)); found = true; break; @@ -295,7 +297,7 @@ int hdnode_private_ckd_cached(HDNode *inout, const uint32_t *i, size_t i_count) void hdnode_fill_public_key(HDNode *node) { - ecdsa_get_public_key33(default_curve, node->private_key, node->public_key); + ecdsa_get_public_key33(node->curve, node->private_key, node->public_key); } void hdnode_serialize(const HDNode *node, uint32_t version, char use_public, char *str, int strsize) diff --git a/bip32.h b/bip32.h index 765084fd0..2d2e46b6f 100644 --- a/bip32.h +++ b/bip32.h @@ -36,13 +36,14 @@ typedef struct { uint8_t chain_code[32]; uint8_t private_key[32]; uint8_t public_key[33]; + const ecdsa_curve *curve; } HDNode; -int hdnode_from_xpub(uint32_t depth, uint32_t fingerprint, uint32_t child_num, const uint8_t *chain_code, const uint8_t *public_key, HDNode *out); +int hdnode_from_xpub(uint32_t depth, uint32_t fingerprint, uint32_t child_num, const uint8_t *chain_code, const uint8_t *public_key, const char *curve, HDNode *out); -int hdnode_from_xprv(uint32_t depth, uint32_t fingerprint, uint32_t child_num, const uint8_t *chain_code, const uint8_t *private_key, HDNode *out); +int hdnode_from_xprv(uint32_t depth, uint32_t fingerprint, uint32_t child_num, const uint8_t *chain_code, const uint8_t *private_key, const char *curve, HDNode *out); -int hdnode_from_seed(const uint8_t *seed, int seed_len, HDNode *out); +int hdnode_from_seed(const uint8_t *seed, int seed_len, const char *curve, HDNode *out); #define hdnode_private_ckd_prime(X, I) hdnode_private_ckd((X), ((I) | 0x80000000)) diff --git a/nist256p1.c b/nist256p1.c index 28d5714b5..deb457737 100644 --- a/nist256p1.c +++ b/nist256p1.c @@ -23,6 +23,7 @@ #include "nist256p1.h" +const char NIST256P1_NAME[] = "nist256p1"; const ecdsa_curve nist256p1 = { /* .prime */ { /*.val =*/ {0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3f, 0x0, 0x0, 0x1000, 0x3fffc000, 0xffff} diff --git a/nist256p1.h b/nist256p1.h index 6afd91005..22bd895b8 100644 --- a/nist256p1.h +++ b/nist256p1.h @@ -28,6 +28,7 @@ #include "ecdsa.h" +extern const char NIST256P1_NAME[]; extern const ecdsa_curve nist256p1; #endif diff --git a/secp256k1.c b/secp256k1.c index b2711e650..b157bae6a 100644 --- a/secp256k1.c +++ b/secp256k1.c @@ -23,6 +23,8 @@ #include "secp256k1.h" +const char SECP256K1_NAME[] = "secp256k1"; + const ecdsa_curve secp256k1 = { /* .prime */ { /*.val =*/ {0x3ffffc2f, 0x3ffffffb, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0xffff} diff --git a/secp256k1.h b/secp256k1.h index 349ca2435..c07a2823e 100644 --- a/secp256k1.h +++ b/secp256k1.h @@ -28,6 +28,7 @@ #include "ecdsa.h" +extern const char SECP256K1_NAME[]; extern const ecdsa_curve secp256k1; #endif From 0bc1b70c4aa32b730da41ca16e3b11f570e49ffc Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Wed, 20 Apr 2016 10:30:33 +0200 Subject: [PATCH 234/627] Use different seed modifier for different curves --- bip32.c | 4 +++- ecdsa.c | 4 ++-- ecdsa.h | 1 + nist256p1.c | 6 +++++- secp256k1.c | 6 +++++- 5 files changed, 16 insertions(+), 5 deletions(-) diff --git a/bip32.c b/bip32.c index 18c96252f..0fdc28e42 100644 --- a/bip32.c +++ b/bip32.c @@ -86,7 +86,8 @@ int hdnode_from_seed(const uint8_t *seed, int seed_len, const char* curve, HDNod out->fingerprint = 0x00000000; out->child_num = 0; out->curve = get_curve_by_name(curve); - hmac_sha512((uint8_t *)"Bitcoin seed", 12, seed, seed_len, I); + hmac_sha512((const uint8_t*) out->curve->bip32_name, + strlen(out->curve->bip32_name), seed, seed_len, I); memcpy(out->private_key, I, 32); bignum256 a; bn_read_be(out->private_key, &a); @@ -337,6 +338,7 @@ int hdnode_deserialize(const char *str, HDNode *node) if (!base58_decode_check(str, node_data, sizeof(node_data))) { return -1; } + node->curve = get_curve_by_name(SECP256K1_NAME); uint32_t version = read_be(node_data); if (version == 0x0488B21E) { // public node memcpy(node->public_key, node_data + 45, 33); diff --git a/ecdsa.c b/ecdsa.c index 8d4e8df3e..4b8a36bdb 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -1050,10 +1050,10 @@ const ecdsa_curve *get_curve_by_name(const char *curve_name) { if (curve_name == 0) { return 0; } - if (strcmp(curve_name, "secp256k1") == 0) { + if (strcmp(curve_name, SECP256K1_NAME) == 0) { return &secp256k1; } - if (strcmp(curve_name, "nist256p1") == 0) { + if (strcmp(curve_name, NIST256P1_NAME) == 0) { return &nist256p1; } return 0; diff --git a/ecdsa.h b/ecdsa.h index 4bdc04115..85b6cd058 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -41,6 +41,7 @@ typedef struct { bignum256 order_half; // order of G divided by 2 int a; // coefficient 'a' of the elliptic curve bignum256 b; // coefficient 'b' of the elliptic curve + const char *bip32_name;// string used for generating BIP32 xprv from seed #if USE_PRECOMPUTED_CP const curve_point cp[64][8]; diff --git a/nist256p1.c b/nist256p1.c index deb457737..5ec461776 100644 --- a/nist256p1.c +++ b/nist256p1.c @@ -46,7 +46,11 @@ const ecdsa_curve nist256p1 = { /* b */ { /*.val =*/{0x27d2604b, 0x2f38f0f8, 0x53b0f63, 0x741ac33, 0x1886bc65, 0x2ef555da, 0x293e7b3e, 0xd762a8e, 0x5ac6} - } + }, + + /* bip32_name */ + "Nist256p1 seed" + #if USE_PRECOMPUTED_CP , /* cp */ { diff --git a/secp256k1.c b/secp256k1.c index b157bae6a..804837697 100644 --- a/secp256k1.c +++ b/secp256k1.c @@ -47,7 +47,11 @@ const ecdsa_curve secp256k1 = { /* b */ { /*.val =*/{7} - } + }, + + /* bip32_name */ + "Bitcoin seed" + #if USE_PRECOMPUTED_CP , /* cp */ { From b34be66a9c9be623630ce55ba0773b2edba4ca77 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Wed, 20 Apr 2016 10:43:53 +0200 Subject: [PATCH 235/627] Updated tests --- tests.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/tests.c b/tests.c index 8c34b48e5..8b89b9493 100644 --- a/tests.c +++ b/tests.c @@ -168,7 +168,7 @@ START_TEST(test_bip32_vector_1) int r; // init m - hdnode_from_seed(fromhex("000102030405060708090a0b0c0d0e0f"), 16, &node); + hdnode_from_seed(fromhex("000102030405060708090a0b0c0d0e0f"), 16, SECP256K1_NAME, &node); // [Chain m] ck_assert_int_eq(node.fingerprint, 0x00000000); @@ -281,7 +281,7 @@ START_TEST(test_bip32_vector_2) int r; // init m - hdnode_from_seed(fromhex("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), 64, &node); + hdnode_from_seed(fromhex("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), 64, SECP256K1_NAME, &node); // [Chain m] ck_assert_int_eq(node.fingerprint, 0x00000000); @@ -390,7 +390,7 @@ START_TEST(test_bip32_vector_2) ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); // init m - hdnode_from_seed(fromhex("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), 64, &node); + hdnode_from_seed(fromhex("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), 64, SECP256K1_NAME, &node); // test public derivation // [Chain m/0] @@ -407,8 +407,8 @@ START_TEST(test_bip32_compare) { HDNode node1, node2, node3; int i, r; - hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, &node1); - hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, &node2); + hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, SECP256K1_NAME, &node1); + hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, SECP256K1_NAME, &node2); for (i = 0; i < 100; i++) { memcpy(&node3, &node1, sizeof(HDNode)); r = hdnode_private_ckd(&node1, i); ck_assert_int_eq(r, 1); @@ -436,8 +436,8 @@ START_TEST(test_bip32_cache_1) int i, r; // test 1 .. 8 - hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, &node1); - hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, &node2); + hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, SECP256K1_NAME, &node1); + hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, SECP256K1_NAME, &node2); uint32_t ii[] = {0x80000001, 0x80000002, 0x80000003, 0x80000004, 0x80000005, 0x80000006, 0x80000007, 0x80000008}; @@ -447,8 +447,8 @@ START_TEST(test_bip32_cache_1) r = hdnode_private_ckd_cached(&node2, ii, 8); ck_assert_int_eq(r, 1); ck_assert_mem_eq(&node1, &node2, sizeof(HDNode)); - hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, &node1); - hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, &node2); + hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, SECP256K1_NAME, &node1); + hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, SECP256K1_NAME, &node2); // test 1 .. 7, 20 ii[7] = 20; @@ -459,8 +459,8 @@ START_TEST(test_bip32_cache_1) ck_assert_mem_eq(&node1, &node2, sizeof(HDNode)); // test different root node - hdnode_from_seed(fromhex("000000002ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, &node1); - hdnode_from_seed(fromhex("000000002ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, &node2); + hdnode_from_seed(fromhex("000000002ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, SECP256K1_NAME, &node1); + hdnode_from_seed(fromhex("000000002ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, SECP256K1_NAME, &node2); for (i = 0; i < 8; i++) { r = hdnode_private_ckd(&node1, ii[i]); ck_assert_int_eq(r, 1); @@ -476,8 +476,8 @@ START_TEST(test_bip32_cache_2) int i, j, r; for (j = 0; j < 9; j++) { - hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, &(nodea[j])); - hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, &(nodeb[j])); + hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, SECP256K1_NAME, &(nodea[j])); + hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, SECP256K1_NAME, &(nodeb[j])); } uint32_t ii[] = {0x80000001, 0x80000002, 0x80000003, 0x80000004, 0x80000005, 0x80000006, 0x80000007, 0x80000008}; From 533c3beb63af0daf1856627dc0e800eb93d028fd Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Wed, 20 Apr 2016 15:09:11 +0200 Subject: [PATCH 236/627] Fixed uncompress_coords for NIST curve The bn_sqrti was broken. It didn't handle primes where all bits are set in the lowest limb. --- bignum.c | 2 +- ecdsa.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bignum.c b/bignum.c index 05a867ab5..6de4a3c22 100644 --- a/bignum.c +++ b/bignum.c @@ -371,7 +371,7 @@ void bn_sqrt(bignum256 *x, const bignum256 *prime) bn_zero(&res); res.val[0] = 1; // compute p = (prime+1)/4 memcpy(&p, prime, sizeof(bignum256)); - p.val[0] += 1; + bn_addi(&p, 1); bn_rshift(&p); bn_rshift(&p); for (i = 0; i < 9; i++) { diff --git a/ecdsa.c b/ecdsa.c index 4b8a36bdb..14637da15 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -862,7 +862,7 @@ int ecdsa_address_decode(const char *addr, uint8_t *out) void uncompress_coords(const ecdsa_curve *curve, uint8_t odd, const bignum256 *x, bignum256 *y) { - // y^2 = x^3 + 0*x + 7 + // y^2 = x^3 + a*x + b memcpy(y, x, sizeof(bignum256)); // y is x bn_multiply(x, y, &curve->prime); // y is x^2 bn_subi(y, -curve->a, &curve->prime); // y is x^2 + a From d577410fc4a87262c107fb25657158f8f8ba720e Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Wed, 20 Apr 2016 15:13:40 +0200 Subject: [PATCH 237/627] Unit tests for the NIST256P1 curve --- tests.c | 154 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 153 insertions(+), 1 deletion(-) diff --git a/tests.c b/tests.c index 8b89b9493..1e69e824e 100644 --- a/tests.c +++ b/tests.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include "aes.h" @@ -502,7 +503,152 @@ START_TEST(test_bip32_cache_2) } END_TEST -#define test_deterministic(KEY, MSG, K) do { \ +START_TEST(test_bip32_nist_vector_1) +{ + HDNode node; + + // init m + hdnode_from_seed(fromhex("000102030405060708090a0b0c0d0e0f"), 16, NIST256P1_NAME, &node); + + // [Chain m] + ck_assert_int_eq(node.fingerprint, 0x00000000); + ck_assert_mem_eq(node.chain_code, fromhex("beeb672fe4621673f722f38529c07392fecaa61015c80c34f29ce8b41b3cb6ea"), 32); + ck_assert_mem_eq(node.private_key, fromhex("612091aaa12e22dd2abef664f8a01a82cae99ad7441b7ef8110424915c268bc2"), 32); + ck_assert_mem_eq(node.public_key, fromhex("0266874dc6ade47b3ecd096745ca09bcd29638dd52c2c12117b11ed3e458cfa9e8"), 33); + + // [Chain m/0'] + hdnode_private_ckd_prime(&node, 0); + ck_assert_int_eq(node.fingerprint, 0xbe6105b5); + ck_assert_mem_eq(node.chain_code, fromhex("3460cea53e6a6bb5fb391eeef3237ffd8724bf0a40e94943c98b83825342ee11"), 32); + ck_assert_mem_eq(node.private_key, fromhex("6939694369114c67917a182c59ddb8cafc3004e63ca5d3b84403ba8613debc0c"), 32); + ck_assert_mem_eq(node.public_key, fromhex("0384610f5ecffe8fda089363a41f56a5c7ffc1d81b59a612d0d649b2d22355590c"), 33); + + // [Chain m/0'/1] + hdnode_private_ckd(&node, 1); + ck_assert_int_eq(node.fingerprint, 0x9b02312f); + ck_assert_mem_eq(node.chain_code, fromhex("4187afff1aafa8445010097fb99d23aee9f599450c7bd140b6826ac22ba21d0c"), 32); + ck_assert_mem_eq(node.private_key, fromhex("284e9d38d07d21e4e281b645089a94f4cf5a5a81369acf151a1c3a57f18b2129"), 32); + ck_assert_mem_eq(node.public_key, fromhex("03526c63f8d0b4bbbf9c80df553fe66742df4676b241dabefdef67733e070f6844"), 33); + + // [Chain m/0'/1/2'] + hdnode_private_ckd_prime(&node, 2); + ck_assert_int_eq(node.fingerprint, 0xb98005c1); + ck_assert_mem_eq(node.chain_code, fromhex("98c7514f562e64e74170cc3cf304ee1ce54d6b6da4f880f313e8204c2a185318"), 32); + ck_assert_mem_eq(node.private_key, fromhex("694596e8a54f252c960eb771a3c41e7e32496d03b954aeb90f61635b8e092aa7"), 32); + ck_assert_mem_eq(node.public_key, fromhex("0359cf160040778a4b14c5f4d7b76e327ccc8c4a6086dd9451b7482b5a4972dda0"), 33); + + // [Chain m/0'/1/2'/2] + hdnode_private_ckd(&node, 2); + ck_assert_int_eq(node.fingerprint, 0x0e9f3274); + ck_assert_mem_eq(node.chain_code, fromhex("ba96f776a5c3907d7fd48bde5620ee374d4acfd540378476019eab70790c63a0"), 32); + ck_assert_mem_eq(node.private_key, fromhex("5996c37fd3dd2679039b23ed6f70b506c6b56b3cb5e424681fb0fa64caf82aaa"), 32); + ck_assert_mem_eq(node.public_key, fromhex("029f871f4cb9e1c97f9f4de9ccd0d4a2f2a171110c61178f84430062230833ff20"), 33); + + // [Chain m/0'/1/2'/2/1000000000] + hdnode_private_ckd(&node, 1000000000); + ck_assert_int_eq(node.fingerprint, 0x8b2b5c4b); + ck_assert_mem_eq(node.chain_code, fromhex("b9b7b82d326bb9cb5b5b121066feea4eb93d5241103c9e7a18aad40f1dde8059"), 32); + ck_assert_mem_eq(node.private_key, fromhex("21c4f269ef0a5fd1badf47eeacebeeaa3de22eb8e5b0adcd0f27dd99d34d0119"), 32); + ck_assert_mem_eq(node.public_key, fromhex("02216cd26d31147f72427a453c443ed2cde8a1e53c9cc44e5ddf739725413fe3f4"), 33); +} +END_TEST + +START_TEST(test_bip32_nist_vector_2) +{ + HDNode node; + int r; + + // init m + hdnode_from_seed(fromhex("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), 64, NIST256P1_NAME, &node); + + // [Chain m] + ck_assert_int_eq(node.fingerprint, 0x00000000); + ck_assert_mem_eq(node.chain_code, fromhex("96cd4465a9644e31528eda3592aa35eb39a9527769ce1855beafc1b81055e75d"), 32); + ck_assert_mem_eq(node.private_key, fromhex("eaa31c2e46ca2962227cf21d73a7ef0ce8b31c756897521eb6c7b39796633357"), 32); + ck_assert_mem_eq(node.public_key, fromhex("02c9e16154474b3ed5b38218bb0463e008f89ee03e62d22fdcc8014beab25b48fa"), 33); + + // [Chain m/0] + r = hdnode_private_ckd(&node, 0); + ck_assert_int_eq(r, 1); + ck_assert_int_eq(node.fingerprint, 0x607f628f); + ck_assert_mem_eq(node.chain_code, fromhex("84e9c258bb8557a40e0d041115b376dd55eda99c0042ce29e81ebe4efed9b86a"), 32); + ck_assert_mem_eq(node.private_key, fromhex("d7d065f63a62624888500cdb4f88b6d59c2927fee9e6d0cdff9cad555884df6e"), 32); + ck_assert_mem_eq(node.public_key, fromhex("039b6df4bece7b6c81e2adfeea4bcf5c8c8a6e40ea7ffa3cf6e8494c61a1fc82cc"), 33); + + // [Chain m/0/2147483647'] + r = hdnode_private_ckd_prime(&node, 2147483647); + ck_assert_int_eq(r, 1); + ck_assert_int_eq(node.fingerprint, 0x946d2a54); + ck_assert_mem_eq(node.chain_code, fromhex("f235b2bc5c04606ca9c30027a84f353acf4e4683edbd11f635d0dcc1cd106ea6"), 32); + ck_assert_mem_eq(node.private_key, fromhex("96d2ec9316746a75e7793684ed01e3d51194d81a42a3276858a5b7376d4b94b9"), 32); + ck_assert_mem_eq(node.public_key, fromhex("02f89c5deb1cae4fedc9905f98ae6cbf6cbab120d8cb85d5bd9a91a72f4c068c76"), 33); + + // [Chain m/0/2147483647'/1] + r = hdnode_private_ckd(&node, 1); + ck_assert_int_eq(r, 1); + ck_assert_int_eq(node.fingerprint, 0x218182d8); + ck_assert_mem_eq(node.chain_code, fromhex("7c0b833106235e452eba79d2bdd58d4086e663bc8cc55e9773d2b5eeda313f3b"), 32); + ck_assert_mem_eq(node.private_key, fromhex("974f9096ea6873a915910e82b29d7c338542ccde39d2064d1cc228f371542bbc"), 32); + ck_assert_mem_eq(node.public_key, fromhex("03abe0ad54c97c1d654c1852dfdc32d6d3e487e75fa16f0fd6304b9ceae4220c64"), 33); + + // [Chain m/0/2147483647'/1/2147483646'] + r = hdnode_private_ckd_prime(&node, 2147483646); + ck_assert_int_eq(r, 1); + ck_assert_int_eq(node.fingerprint, 0x931223e4); + ck_assert_mem_eq(node.chain_code, fromhex("5794e616eadaf33413aa309318a26ee0fd5163b70466de7a4512fd4b1a5c9e6a"), 32); + ck_assert_mem_eq(node.private_key, fromhex("da29649bbfaff095cd43819eda9a7be74236539a29094cd8336b07ed8d4eff63"), 32); + ck_assert_mem_eq(node.public_key, fromhex("03cb8cb067d248691808cd6b5a5a06b48e34ebac4d965cba33e6dc46fe13d9b933"), 33); + + // [Chain m/0/2147483647'/1/2147483646'/2] + r = hdnode_private_ckd(&node, 2); + ck_assert_int_eq(r, 1); + ck_assert_int_eq(node.fingerprint, 0x956c4629); + ck_assert_mem_eq(node.chain_code, fromhex("3bfb29ee8ac4484f09db09c2079b520ea5616df7820f071a20320366fbe226a7"), 32); + ck_assert_mem_eq(node.private_key, fromhex("bb0a77ba01cc31d77205d51d08bd313b979a71ef4de9b062f8958297e746bd67"), 32); + ck_assert_mem_eq(node.public_key, fromhex("020ee02e18967237cf62672983b253ee62fa4dd431f8243bfeccdf39dbe181387f"), 33); + + // init m + hdnode_from_seed(fromhex("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), 64, NIST256P1_NAME, &node); + + // test public derivation + // [Chain m/0] + r = hdnode_public_ckd(&node, 0); + ck_assert_int_eq(r, 1); + ck_assert_int_eq(node.fingerprint, 0x607f628f); + ck_assert_mem_eq(node.chain_code, fromhex("84e9c258bb8557a40e0d041115b376dd55eda99c0042ce29e81ebe4efed9b86a"), 32); + ck_assert_mem_eq(node.private_key, fromhex("0000000000000000000000000000000000000000000000000000000000000000"), 32); + ck_assert_mem_eq(node.public_key, fromhex("039b6df4bece7b6c81e2adfeea4bcf5c8c8a6e40ea7ffa3cf6e8494c61a1fc82cc"), 33); +} +END_TEST + +START_TEST(test_bip32_nist_compare) +{ + HDNode node1, node2, node3; + int i, r; + hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, NIST256P1_NAME, &node1); + hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, NIST256P1_NAME, &node2); + for (i = 0; i < 100; i++) { + memcpy(&node3, &node1, sizeof(HDNode)); + r = hdnode_private_ckd(&node1, i); ck_assert_int_eq(r, 1); + r = hdnode_public_ckd(&node2, i); ck_assert_int_eq(r, 1); + r = hdnode_public_ckd(&node3, i); ck_assert_int_eq(r, 1); + ck_assert_int_eq(node1.depth, node2.depth); + ck_assert_int_eq(node1.depth, node3.depth); + ck_assert_int_eq(node1.fingerprint, node2.fingerprint); + ck_assert_int_eq(node1.fingerprint, node3.fingerprint); + ck_assert_int_eq(node1.child_num, node2.child_num); + ck_assert_int_eq(node1.child_num, node3.child_num); + ck_assert_mem_eq(node1.chain_code, node2.chain_code, 32); + ck_assert_mem_eq(node1.chain_code, node3.chain_code, 32); + ck_assert_mem_eq(node2.private_key, fromhex("0000000000000000000000000000000000000000000000000000000000000000"), 32); + ck_assert_mem_eq(node3.private_key, fromhex("0000000000000000000000000000000000000000000000000000000000000000"), 32); + ck_assert_mem_eq(node1.public_key, node2.public_key, 33); + ck_assert_mem_eq(node1.public_key, node3.public_key, 33); + } +} +END_TEST + +#define test_deterministic(KEY, MSG, K) do { \ sha256_Raw((uint8_t *)MSG, strlen(MSG), buf); \ res = generate_k_rfc6979(curve, &k, fromhex(KEY), buf); \ ck_assert_int_eq(res, 0); \ @@ -1419,6 +1565,12 @@ Suite *test_suite(void) tcase_add_test(tc, test_bip32_cache_2); suite_add_tcase(s, tc); + tc = tcase_create("bip32-nist"); + tcase_add_test(tc, test_bip32_nist_vector_1); + tcase_add_test(tc, test_bip32_nist_vector_2); + tcase_add_test(tc, test_bip32_nist_compare); + suite_add_tcase(s, tc); + tc = tcase_create("rfc6979"); tcase_add_test(tc, test_rfc6979); suite_add_tcase(s, tc); From f8ac99ebb7e7ae9d9216b689b53a6a47f62ed317 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Wed, 20 Apr 2016 19:54:18 +0200 Subject: [PATCH 238/627] Check for error from get_curve_by_name. --- bip32.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/bip32.c b/bip32.c index 0fdc28e42..dc1f2264d 100644 --- a/bip32.c +++ b/bip32.c @@ -36,16 +36,20 @@ int hdnode_from_xpub(uint32_t depth, uint32_t fingerprint, uint32_t child_num, const uint8_t *chain_code, const uint8_t *public_key, const char* curve, HDNode *out) { + const ecdsa_curve *curve_info = get_curve_by_name(curve); + if (curve_info == 0) { + return 0; + } if (public_key[0] != 0x02 && public_key[0] != 0x03) { // invalid pubkey return 0; } + out->curve = curve_info; out->depth = depth; out->fingerprint = fingerprint; out->child_num = child_num; memcpy(out->chain_code, chain_code, 32); MEMSET_BZERO(out->private_key, 32); memcpy(out->public_key, public_key, 33); - out->curve = get_curve_by_name(curve); return 1; } @@ -53,10 +57,12 @@ int hdnode_from_xprv(uint32_t depth, uint32_t fingerprint, uint32_t child_num, c { bignum256 a; bn_read_be(private_key, &a); - out->curve = get_curve_by_name(curve); bool failed = false; - if (bn_is_zero(&a)) { // == 0 + const ecdsa_curve *curve_info = get_curve_by_name(curve); + if (curve_info == 0) { + failed = true; + } else if (bn_is_zero(&a)) { // == 0 failed = true; } else { if (!bn_is_less(&a, &out->curve->order)) { // >= order @@ -69,6 +75,7 @@ int hdnode_from_xprv(uint32_t depth, uint32_t fingerprint, uint32_t child_num, c return 0; } + out->curve = curve_info; out->depth = depth; out->fingerprint = fingerprint; out->child_num = child_num; @@ -86,6 +93,9 @@ int hdnode_from_seed(const uint8_t *seed, int seed_len, const char* curve, HDNod out->fingerprint = 0x00000000; out->child_num = 0; out->curve = get_curve_by_name(curve); + if (out->curve == 0) { + return 0; + } hmac_sha512((const uint8_t*) out->curve->bip32_name, strlen(out->curve->bip32_name), seed, seed_len, I); memcpy(out->private_key, I, 32); From 16ff4387ae79429e629a5454708abf7385b3a9a3 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Wed, 20 Apr 2016 20:30:10 +0200 Subject: [PATCH 239/627] New test case for a bip32 hole in nist256 --- tests.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tests.c b/tests.c index 1e69e824e..0694fcc2a 100644 --- a/tests.c +++ b/tests.c @@ -648,6 +648,33 @@ START_TEST(test_bip32_nist_compare) } END_TEST +START_TEST(test_bip32_nist_invalid) +{ + HDNode node, node2; + int r; + + // init m + hdnode_from_seed(fromhex("000102030405060708090a0b0c0d0e0f"), 16, NIST256P1_NAME, &node); + + // [Chain m/28578'] + r = hdnode_private_ckd_prime(&node, 28578); + ck_assert_int_eq(r, 1); + ck_assert_int_eq(node.fingerprint, 0xbe6105b5); + ck_assert_mem_eq(node.chain_code, fromhex("e94c8ebe30c2250a14713212f6449b20f3329105ea15b652ca5bdfc68f6c65c2"), 32); + ck_assert_mem_eq(node.private_key, fromhex("06f0db126f023755d0b8d86d4591718a5210dd8d024e3e14b6159d63f53aa669"), 32); + ck_assert_mem_eq(node.public_key, fromhex("02519b5554a4872e8c9c1c847115363051ec43e93400e030ba3c36b52a3e70a5b7"), 33); + + memcpy(&node2, &node, sizeof(HDNode)); + r = hdnode_private_ckd(&node2, 33941); + ck_assert_int_eq(r, 0); + + memcpy(&node2, &node, sizeof(HDNode)); + memset(&node2.private_key, 0, 32); + r = hdnode_public_ckd(&node2, 33941); + ck_assert_int_eq(r, 0); +} +END_TEST + #define test_deterministic(KEY, MSG, K) do { \ sha256_Raw((uint8_t *)MSG, strlen(MSG), buf); \ res = generate_k_rfc6979(curve, &k, fromhex(KEY), buf); \ @@ -1569,6 +1596,7 @@ Suite *test_suite(void) tcase_add_test(tc, test_bip32_nist_vector_1); tcase_add_test(tc, test_bip32_nist_vector_2); tcase_add_test(tc, test_bip32_nist_compare); + tcase_add_test(tc, test_bip32_nist_invalid); suite_add_tcase(s, tc); tc = tcase_create("rfc6979"); From 698f40f38509a4cce1d64fbca559d6205869fa82 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Fri, 22 Apr 2016 14:48:24 +0200 Subject: [PATCH 240/627] BIP-32 without gaps, prepare non-ecdsa curves * Split ecdsa_curve into curve_info and ecdsa_curve to support bip32 on curves that don't have a ecdsa_curve. * Don't fail in key derivation but retry with a new hash. * Adapted test case accordingly --- bip32.c | 175 +++++++++++++++++++++++++++++++--------------------- bip32.h | 9 ++- ecdsa.c | 17 ----- ecdsa.h | 2 - nist256p1.c | 11 ++-- nist256p1.h | 2 + secp256k1.c | 11 ++-- secp256k1.h | 2 + tests.c | 15 +++-- 9 files changed, 141 insertions(+), 103 deletions(-) diff --git a/bip32.c b/bip32.c index dc1f2264d..d6ee70df1 100644 --- a/bip32.c +++ b/bip32.c @@ -1,6 +1,7 @@ /** - * Copyright (c) 2013-2014 Tomas Dzetkulic - * Copyright (c) 2013-2014 Pavol Rusnak + * Copyright (c) 2013-2016 Tomas Dzetkulic + * Copyright (c) 2013-2016 Pavol Rusnak + * Copyright (c) 2015-2016 Jochen Hoenicke * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the "Software"), @@ -33,17 +34,18 @@ #include "base58.h" #include "macros.h" #include "secp256k1.h" +#include "nist256p1.h" int hdnode_from_xpub(uint32_t depth, uint32_t fingerprint, uint32_t child_num, const uint8_t *chain_code, const uint8_t *public_key, const char* curve, HDNode *out) { - const ecdsa_curve *curve_info = get_curve_by_name(curve); - if (curve_info == 0) { + const curve_info *info = get_curve_by_name(curve); + if (info == 0) { return 0; } if (public_key[0] != 0x02 && public_key[0] != 0x03) { // invalid pubkey return 0; } - out->curve = curve_info; + out->curve = info; out->depth = depth; out->fingerprint = fingerprint; out->child_num = child_num; @@ -55,18 +57,19 @@ int hdnode_from_xpub(uint32_t depth, uint32_t fingerprint, uint32_t child_num, c int hdnode_from_xprv(uint32_t depth, uint32_t fingerprint, uint32_t child_num, const uint8_t *chain_code, const uint8_t *private_key, const char* curve, HDNode *out) { - bignum256 a; - bn_read_be(private_key, &a); - bool failed = false; - const ecdsa_curve *curve_info = get_curve_by_name(curve); - if (curve_info == 0) { - failed = true; - } else if (bn_is_zero(&a)) { // == 0 + const curve_info *info = get_curve_by_name(curve); + if (info == 0) { failed = true; } else { - if (!bn_is_less(&a, &out->curve->order)) { // >= order + bignum256 a; + bn_read_be(private_key, &a); + if (bn_is_zero(&a)) { // == 0 failed = true; + } else { + if (!bn_is_less(&a, &info->params->order)) { // >= order + failed = true; + } } MEMSET_BZERO(&a, sizeof(a)); } @@ -75,7 +78,7 @@ int hdnode_from_xprv(uint32_t depth, uint32_t fingerprint, uint32_t child_num, c return 0; } - out->curve = curve_info; + out->curve = info; out->depth = depth; out->fingerprint = fingerprint; out->child_num = child_num; @@ -98,27 +101,27 @@ int hdnode_from_seed(const uint8_t *seed, int seed_len, const char* curve, HDNod } hmac_sha512((const uint8_t*) out->curve->bip32_name, strlen(out->curve->bip32_name), seed, seed_len, I); - memcpy(out->private_key, I, 32); - bignum256 a; - bn_read_be(out->private_key, &a); - bool failed = false; - if (bn_is_zero(&a)) { // == 0 - failed = true; - } else { - if (!bn_is_less(&a, &out->curve->order)) { // >= order - failed = true; + if (out->curve->params) { + bignum256 a; + while (true) { + bn_read_be(I, &a); + if (!bn_is_zero(&a) // != 0 + && bn_is_less(&a, &out->curve->params->order)) { // < order + + break; + } + hmac_sha512((const uint8_t*) out->curve->bip32_name, + strlen(out->curve->bip32_name), I, sizeof(I), I); } MEMSET_BZERO(&a, sizeof(a)); } - - if (!failed) { - memcpy(out->chain_code, I + 32, 32); - hdnode_fill_public_key(out); - } + memcpy(out->private_key, I, 32); + memcpy(out->chain_code, I + 32, 32); + hdnode_fill_public_key(out); MEMSET_BZERO(I, sizeof(I)); - return failed ? 0 : 1; + return 1; } int hdnode_private_ckd(HDNode *inout, uint32_t i) @@ -132,6 +135,9 @@ int hdnode_private_ckd(HDNode *inout, uint32_t i) data[0] = 0; memcpy(data + 1, inout->private_key, 32); } else { // public derivation + if (!inout->curve->params) { + return 0; + } memcpy(data, inout->public_key, 33); } write_be(data + 33, i); @@ -143,29 +149,37 @@ int hdnode_private_ckd(HDNode *inout, uint32_t i) bn_read_be(inout->private_key, &a); hmac_sha512(inout->chain_code, 32, data, sizeof(data), I); - memcpy(inout->chain_code, I + 32, 32); - memcpy(inout->private_key, I, 32); - - bn_read_be(inout->private_key, &b); - - bool failed = false; + if (inout->curve->params) { + while (true) { + bool failed = false; + bn_read_be(I, &b); + if (!bn_is_less(&b, &inout->curve->params->order)) { // >= order + failed = true; + } else { + bn_addmod(&b, &a, &inout->curve->params->order); + bn_mod(&b, &inout->curve->params->order); + if (bn_is_zero(&b)) { + failed = true; + } + } + + if (!failed) { + bn_write_be(&b, inout->private_key); + break; + } - if (!bn_is_less(&b, &inout->curve->order)) { // >= order - failed = true; - } - if (!failed) { - bn_addmod(&a, &b, &inout->curve->order); - bn_mod(&a, &inout->curve->order); - if (bn_is_zero(&a)) { - failed = true; + data[0] = 1; + memcpy(data + 1, I + 32, 32); + hmac_sha512(inout->chain_code, 32, data, sizeof(data), I); } + } else { + memcpy(inout->private_key, I, 32); } - if (!failed) { - inout->depth++; - inout->child_num = i; - bn_write_be(&a, inout->private_key); - hdnode_fill_public_key(inout); - } + + memcpy(inout->chain_code, I + 32, 32); + inout->depth++; + inout->child_num = i; + hdnode_fill_public_key(inout); // making sure to wipe our memory MEMSET_BZERO(&a, sizeof(a)); @@ -173,7 +187,7 @@ int hdnode_private_ckd(HDNode *inout, uint32_t i) MEMSET_BZERO(I, sizeof(I)); MEMSET_BZERO(fingerprint, sizeof(fingerprint)); MEMSET_BZERO(data, sizeof(data)); - return failed ? 0 : 1; + return 1; } int hdnode_public_ckd(HDNode *inout, uint32_t i) @@ -187,6 +201,9 @@ int hdnode_public_ckd(HDNode *inout, uint32_t i) if (i & 0x80000000) { // private derivation return 0; } else { // public derivation + if (!inout->curve->params) { + return 0; + } memcpy(data, inout->public_key, 33); } write_be(data + 33, i); @@ -197,35 +214,38 @@ int hdnode_public_ckd(HDNode *inout, uint32_t i) memset(inout->private_key, 0, 32); - bool failed = false; - if (!ecdsa_read_pubkey(inout->curve, inout->public_key, &a)) { - failed = true; + if (!ecdsa_read_pubkey(inout->curve->params, inout->public_key, &a)) { + return 0; } - if (!failed) { + while (true) { + bool failed = false; hmac_sha512(inout->chain_code, 32, data, sizeof(data), I); - memcpy(inout->chain_code, I + 32, 32); bn_read_be(I, &c); - if (!bn_is_less(&c, &inout->curve->order)) { // >= order + if (!bn_is_less(&c, &inout->curve->params->order)) { // >= order failed = true; + } else { + scalar_multiply(inout->curve->params, &c, &b); // b = c * G + point_add(inout->curve->params, &a, &b); // b = a + b + if (point_is_infinity(&b)) { + failed = true; + } } - } - - if (!failed) { - scalar_multiply(inout->curve, &c, &b); // b = c * G - point_add(inout->curve, &a, &b); // b = a + b - if (!ecdsa_validate_pubkey(inout->curve, &b)) { - failed = true; + + if (!failed) { + inout->public_key[0] = 0x02 | (b.y.val[0] & 0x01); + bn_write_be(&b.x, inout->public_key + 1); + break; } - } - if (!failed) { - inout->public_key[0] = 0x02 | (b.y.val[0] & 0x01); - bn_write_be(&b.x, inout->public_key + 1); - inout->depth++; - inout->child_num = i; + data[0] = 1; + memcpy(data + 1, I + 32, 32); } + inout->depth++; + inout->child_num = i; + memcpy(inout->chain_code, I + 32, 32); + // Wipe all stack data. MEMSET_BZERO(data, sizeof(data)); MEMSET_BZERO(I, sizeof(I)); @@ -234,7 +254,7 @@ int hdnode_public_ckd(HDNode *inout, uint32_t i) MEMSET_BZERO(&b, sizeof(b)); MEMSET_BZERO(&c, sizeof(c)); - return failed ? 0 : 1; + return 1; } #if USE_BIP32_CACHE @@ -308,7 +328,7 @@ int hdnode_private_ckd_cached(HDNode *inout, const uint32_t *i, size_t i_count) void hdnode_fill_public_key(HDNode *node) { - ecdsa_get_public_key33(node->curve, node->private_key, node->public_key); + ecdsa_get_public_key33(node->curve->params, node->private_key, node->public_key); } void hdnode_serialize(const HDNode *node, uint32_t version, char use_public, char *str, int strsize) @@ -367,3 +387,16 @@ int hdnode_deserialize(const char *str, HDNode *node) memcpy(node->chain_code, node_data + 13, 32); return 0; } + +const curve_info *get_curve_by_name(const char *curve_name) { + if (curve_name == 0) { + return 0; + } + if (strcmp(curve_name, SECP256K1_NAME) == 0) { + return &secp256k1_info; + } + if (strcmp(curve_name, NIST256P1_NAME) == 0) { + return &nist256p1_info; + } + return 0; +} diff --git a/bip32.h b/bip32.h index 2d2e46b6f..f8e864d7e 100644 --- a/bip32.h +++ b/bip32.h @@ -29,6 +29,11 @@ #include "ecdsa.h" #include "options.h" +typedef struct { + const char *bip32_name; // string for generating BIP32 xprv from seed + const ecdsa_curve *params; // ecdsa curve parameters, null for ed25519 +} curve_info; + typedef struct { uint32_t depth; uint32_t fingerprint; @@ -36,7 +41,7 @@ typedef struct { uint8_t chain_code[32]; uint8_t private_key[32]; uint8_t public_key[33]; - const ecdsa_curve *curve; + const curve_info *curve; } HDNode; int hdnode_from_xpub(uint32_t depth, uint32_t fingerprint, uint32_t child_num, const uint8_t *chain_code, const uint8_t *public_key, const char *curve, HDNode *out); @@ -68,4 +73,6 @@ int hdnode_deserialize(const char *str, HDNode *node); // Private void hdnode_serialize(const HDNode *node, uint32_t version, char use_public, char *str, int strsize); +const curve_info *get_curve_by_name(const char *curve_name); + #endif diff --git a/ecdsa.c b/ecdsa.c index 14637da15..0a46190b7 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -36,9 +36,6 @@ #include "base58.h" #include "macros.h" -#include "secp256k1.h" -#include "nist256p1.h" - // Set cp2 = cp1 void point_copy(const curve_point *cp1, curve_point *cp2) { @@ -1044,17 +1041,3 @@ int ecdsa_sig_to_der(const uint8_t *sig, uint8_t *der) *len = *len1 + *len2 + 4; return *len + 2; } - - -const ecdsa_curve *get_curve_by_name(const char *curve_name) { - if (curve_name == 0) { - return 0; - } - if (strcmp(curve_name, SECP256K1_NAME) == 0) { - return &secp256k1; - } - if (strcmp(curve_name, NIST256P1_NAME) == 0) { - return &nist256p1; - } - return 0; -} diff --git a/ecdsa.h b/ecdsa.h index 85b6cd058..2a6edde65 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -41,7 +41,6 @@ typedef struct { bignum256 order_half; // order of G divided by 2 int a; // coefficient 'a' of the elliptic curve bignum256 b; // coefficient 'b' of the elliptic curve - const char *bip32_name;// string used for generating BIP32 xprv from seed #if USE_PRECOMPUTED_CP const curve_point cp[64][8]; @@ -77,7 +76,6 @@ int ecdsa_verify(const ecdsa_curve *curve, const uint8_t *pub_key, const uint8_t int ecdsa_verify_double(const ecdsa_curve *curve, const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, uint32_t msg_len); int ecdsa_verify_digest(const ecdsa_curve *curve, const uint8_t *pub_key, const uint8_t *sig, const uint8_t *digest); int ecdsa_sig_to_der(const uint8_t *sig, uint8_t *der); -const ecdsa_curve *get_curve_by_name(const char *curve_name); // Private int generate_k_rfc6979(const ecdsa_curve *curve, bignum256 *secret, const uint8_t *priv_key, const uint8_t *hash); diff --git a/nist256p1.c b/nist256p1.c index 5ec461776..166fda801 100644 --- a/nist256p1.c +++ b/nist256p1.c @@ -46,10 +46,7 @@ const ecdsa_curve nist256p1 = { /* b */ { /*.val =*/{0x27d2604b, 0x2f38f0f8, 0x53b0f63, 0x741ac33, 0x1886bc65, 0x2ef555da, 0x293e7b3e, 0xd762a8e, 0x5ac6} - }, - - /* bip32_name */ - "Nist256p1 seed" + } #if USE_PRECOMPUTED_CP , @@ -58,3 +55,9 @@ const ecdsa_curve nist256p1 = { } #endif }; + +const curve_info nist256p1_info = { + /* bip32_name */ + "Nist256p1 seed", + &nist256p1 +}; diff --git a/nist256p1.h b/nist256p1.h index 22bd895b8..347fe86dc 100644 --- a/nist256p1.h +++ b/nist256p1.h @@ -27,8 +27,10 @@ #include #include "ecdsa.h" +#include "bip32.h" extern const char NIST256P1_NAME[]; extern const ecdsa_curve nist256p1; +extern const curve_info nist256p1_info; #endif diff --git a/secp256k1.c b/secp256k1.c index 804837697..a5f4507f1 100644 --- a/secp256k1.c +++ b/secp256k1.c @@ -47,10 +47,7 @@ const ecdsa_curve secp256k1 = { /* b */ { /*.val =*/{7} - }, - - /* bip32_name */ - "Bitcoin seed" + } #if USE_PRECOMPUTED_CP , @@ -59,3 +56,9 @@ const ecdsa_curve secp256k1 = { } #endif }; + +const curve_info secp256k1_info = { + /* bip32_name */ + "Bitcoin seed", + &secp256k1 +}; diff --git a/secp256k1.h b/secp256k1.h index c07a2823e..e7ef6bf4a 100644 --- a/secp256k1.h +++ b/secp256k1.h @@ -27,8 +27,10 @@ #include #include "ecdsa.h" +#include "bip32.h" extern const char SECP256K1_NAME[]; extern const ecdsa_curve secp256k1; +extern const curve_info secp256k1_info; #endif diff --git a/tests.c b/tests.c index 0694fcc2a..264882377 100644 --- a/tests.c +++ b/tests.c @@ -648,7 +648,7 @@ START_TEST(test_bip32_nist_compare) } END_TEST -START_TEST(test_bip32_nist_invalid) +START_TEST(test_bip32_nist_repeat) { HDNode node, node2; int r; @@ -666,12 +666,19 @@ START_TEST(test_bip32_nist_invalid) memcpy(&node2, &node, sizeof(HDNode)); r = hdnode_private_ckd(&node2, 33941); - ck_assert_int_eq(r, 0); + ck_assert_int_eq(r, 1); + ck_assert_int_eq(node2.fingerprint, 0x3e2b7bc6); + ck_assert_mem_eq(node2.chain_code, fromhex("9e87fe95031f14736774cd82f25fd885065cb7c358c1edf813c72af535e83071"), 32); + ck_assert_mem_eq(node2.private_key, fromhex("092154eed4af83e078ff9b84322015aefe5769e31270f62c3f66c33888335f3a"), 32); + ck_assert_mem_eq(node2.public_key, fromhex("0235bfee614c0d5b2cae260000bb1d0d84b270099ad790022c1ae0b2e782efe120"), 33); memcpy(&node2, &node, sizeof(HDNode)); memset(&node2.private_key, 0, 32); r = hdnode_public_ckd(&node2, 33941); - ck_assert_int_eq(r, 0); + ck_assert_int_eq(r, 1); + ck_assert_int_eq(node2.fingerprint, 0x3e2b7bc6); + ck_assert_mem_eq(node2.chain_code, fromhex("9e87fe95031f14736774cd82f25fd885065cb7c358c1edf813c72af535e83071"), 32); + ck_assert_mem_eq(node2.public_key, fromhex("0235bfee614c0d5b2cae260000bb1d0d84b270099ad790022c1ae0b2e782efe120"), 33); } END_TEST @@ -1596,7 +1603,7 @@ Suite *test_suite(void) tcase_add_test(tc, test_bip32_nist_vector_1); tcase_add_test(tc, test_bip32_nist_vector_2); tcase_add_test(tc, test_bip32_nist_compare); - tcase_add_test(tc, test_bip32_nist_invalid); + tcase_add_test(tc, test_bip32_nist_repeat); suite_add_tcase(s, tc); tc = tcase_create("rfc6979"); From 55edf71e274c4b803f9b0acb2847df51532fa302 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Fri, 22 Apr 2016 17:47:48 +0200 Subject: [PATCH 241/627] ed25519 support --- Makefile | 8 +- bip32.c | 42 +- bip32.h | 3 + curves.c | 25 + curves.h | 30 + ed25519-donna/README.md | 183 +++ ed25519-donna/curve25519-donna-32bit.h | 579 +++++++++ ed25519-donna/curve25519-donna-64bit.h | 413 ++++++ ed25519-donna/curve25519-donna-helpers.h | 67 + ed25519-donna/curve25519-donna-sse2.h | 1112 +++++++++++++++++ ed25519-donna/ed25519-donna-32bit-sse2.h | 513 ++++++++ ed25519-donna/ed25519-donna-32bit-tables.h | 61 + ed25519-donna/ed25519-donna-64bit-sse2.h | 436 +++++++ ed25519-donna/ed25519-donna-64bit-tables.h | 53 + ed25519-donna/ed25519-donna-64bit-x86-32bit.h | 435 +++++++ ed25519-donna/ed25519-donna-64bit-x86.h | 351 ++++++ ed25519-donna/ed25519-donna-basepoint-table.h | 259 ++++ ed25519-donna/ed25519-donna-batchverify.h | 275 ++++ ed25519-donna/ed25519-donna-impl-base.h | 364 ++++++ ed25519-donna/ed25519-donna-impl-sse2.h | 390 ++++++ .../ed25519-donna-portable-identify.h | 103 ++ ed25519-donna/ed25519-donna-portable.h | 135 ++ ed25519-donna/ed25519-donna.h | 115 ++ ed25519-donna/ed25519-hash-custom.h | 18 + ed25519-donna/ed25519-hash.h | 219 ++++ ed25519-donna/ed25519-randombytes-custom.h | 12 + ed25519-donna/ed25519-randombytes.h | 91 ++ ed25519-donna/ed25519.c | 150 +++ ed25519-donna/ed25519.h | 30 + ed25519-donna/modm-donna-32bit.h | 469 +++++++ ed25519-donna/modm-donna-64bit.h | 361 ++++++ nist256p1.c | 1 - nist256p1.h | 1 - secp256k1.c | 2 - secp256k1.h | 1 - tests.c | 26 + 36 files changed, 7324 insertions(+), 9 deletions(-) create mode 100644 curves.c create mode 100644 curves.h create mode 100644 ed25519-donna/README.md create mode 100644 ed25519-donna/curve25519-donna-32bit.h create mode 100644 ed25519-donna/curve25519-donna-64bit.h create mode 100644 ed25519-donna/curve25519-donna-helpers.h create mode 100644 ed25519-donna/curve25519-donna-sse2.h create mode 100644 ed25519-donna/ed25519-donna-32bit-sse2.h create mode 100644 ed25519-donna/ed25519-donna-32bit-tables.h create mode 100644 ed25519-donna/ed25519-donna-64bit-sse2.h create mode 100644 ed25519-donna/ed25519-donna-64bit-tables.h create mode 100644 ed25519-donna/ed25519-donna-64bit-x86-32bit.h create mode 100644 ed25519-donna/ed25519-donna-64bit-x86.h create mode 100644 ed25519-donna/ed25519-donna-basepoint-table.h create mode 100644 ed25519-donna/ed25519-donna-batchverify.h create mode 100644 ed25519-donna/ed25519-donna-impl-base.h create mode 100644 ed25519-donna/ed25519-donna-impl-sse2.h create mode 100644 ed25519-donna/ed25519-donna-portable-identify.h create mode 100644 ed25519-donna/ed25519-donna-portable.h create mode 100644 ed25519-donna/ed25519-donna.h create mode 100644 ed25519-donna/ed25519-hash-custom.h create mode 100644 ed25519-donna/ed25519-hash.h create mode 100644 ed25519-donna/ed25519-randombytes-custom.h create mode 100644 ed25519-donna/ed25519-randombytes.h create mode 100644 ed25519-donna/ed25519.c create mode 100644 ed25519-donna/ed25519.h create mode 100644 ed25519-donna/modm-donna-32bit.h create mode 100644 ed25519-donna/modm-donna-64bit.h diff --git a/Makefile b/Makefile index 12cb05b79..7ae782975 100644 --- a/Makefile +++ b/Makefile @@ -24,18 +24,22 @@ CFLAGS += $(OPTFLAGS) \ # disable sequence point warning because of AES code CFLAGS += -Wno-sequence-point +CFLAGS += -DED25519_CUSTOMRANDOM=1 +CFLAGS += -DED25519_CUSTOMHASH=1 +CFLAGS += -Ied25519-donna -I. # disable certain optimizations and features when small footprint is required ifdef SMALL CFLAGS += -DUSE_PRECOMPUTED_IV=0 -DUSE_PRECOMPUTED_CP=0 endif -SRCS = bignum.c ecdsa.c secp256k1.c nist256p1.c rand.c hmac.c bip32.c bip39.c pbkdf2.c base58.c +SRCS = bignum.c ecdsa.c curves.c secp256k1.c nist256p1.c rand.c hmac.c bip32.c bip39.c pbkdf2.c base58.c SRCS += ripemd160.c SRCS += sha2.c SRCS += aescrypt.c aeskey.c aestab.c aes_modes.c OBJS = $(SRCS:.c=.o) +OBJS += ed25519-donna/ed25519.o TESTLIBS = -lcheck -lrt -lpthread -lm TESTSSLLIBS = -lcrypto @@ -55,4 +59,4 @@ libtrezor-crypto.so: $(SRCS) $(CC) $(CFLAGS) -fPIC -shared $(SRCS) -o libtrezor-crypto.so clean: - rm -f *.o tests test-openssl libtrezor-crypto.so + rm -f *.o ed25519-donna/*.o tests test-openssl libtrezor-crypto.so diff --git a/bip32.c b/bip32.c index d6ee70df1..064a5e0c1 100644 --- a/bip32.c +++ b/bip32.c @@ -33,8 +33,16 @@ #include "ripemd160.h" #include "base58.h" #include "macros.h" +#include "curves.h" #include "secp256k1.h" #include "nist256p1.h" +#include "ed25519.h" + +const curve_info ed25519_info = { + /* bip32_name */ + "ed25519 seed", + 0 +}; int hdnode_from_xpub(uint32_t depth, uint32_t fingerprint, uint32_t child_num, const uint8_t *chain_code, const uint8_t *public_key, const char* curve, HDNode *out) { @@ -108,7 +116,6 @@ int hdnode_from_seed(const uint8_t *seed, int seed_len, const char* curve, HDNod bn_read_be(I, &a); if (!bn_is_zero(&a) // != 0 && bn_is_less(&a, &out->curve->params->order)) { // < order - break; } hmac_sha512((const uint8_t*) out->curve->bip32_name, @@ -328,9 +335,37 @@ int hdnode_private_ckd_cached(HDNode *inout, const uint32_t *i, size_t i_count) void hdnode_fill_public_key(HDNode *node) { - ecdsa_get_public_key33(node->curve->params, node->private_key, node->public_key); + if (node->curve == &ed25519_info) { + node->public_key[0] = 0; + ed25519_publickey(node->private_key, node->public_key + 1); + } else { + ecdsa_get_public_key33(node->curve->params, node->private_key, node->public_key); + } +} + +// msg is a data to be signed +// msg_len is the message length +int hdnode_sign(const HDNode *node, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby) +{ + if (node->curve == &ed25519_info) { + ed25519_sign(msg, msg_len, node->private_key, node->public_key + 1, sig); + return 0; + } else { + return ecdsa_sign(node->curve->params, node->private_key, msg, msg_len, sig, pby); + } +} + +int hdnode_sign_digest(const HDNode *node, const uint8_t *digest, uint8_t *sig, uint8_t *pby) +{ + if (node->curve == &ed25519_info) { + ed25519_sign(digest, 32, node->private_key, node->public_key + 1, sig); + return 0; + } else { + return ecdsa_sign_digest(node->curve->params, node->private_key, digest, sig, pby); + } } + void hdnode_serialize(const HDNode *node, uint32_t version, char use_public, char *str, int strsize) { uint8_t node_data[78]; @@ -398,5 +433,8 @@ const curve_info *get_curve_by_name(const char *curve_name) { if (strcmp(curve_name, NIST256P1_NAME) == 0) { return &nist256p1_info; } + if (strcmp(curve_name, ED25519_NAME) == 0) { + return &ed25519_info; + } return 0; } diff --git a/bip32.h b/bip32.h index f8e864d7e..2f7dca3e1 100644 --- a/bip32.h +++ b/bip32.h @@ -64,6 +64,9 @@ int hdnode_private_ckd_cached(HDNode *inout, const uint32_t *i, size_t i_count); void hdnode_fill_public_key(HDNode *node); +int hdnode_sign(const HDNode *node, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby); +int hdnode_sign_digest(const HDNode *node, const uint8_t *digest, uint8_t *sig, uint8_t *pby); + void hdnode_serialize_public(const HDNode *node, char *str, int strsize); void hdnode_serialize_private(const HDNode *node, char *str, int strsize); diff --git a/curves.c b/curves.c new file mode 100644 index 000000000..86b671a2d --- /dev/null +++ b/curves.c @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2016 Jochen Hoenicke + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +const char SECP256K1_NAME[] = "secp256k1"; +const char NIST256P1_NAME[] = "nist256p1"; +const char ED25519_NAME[] = "ed25519"; diff --git a/curves.h b/curves.h new file mode 100644 index 000000000..be841b688 --- /dev/null +++ b/curves.h @@ -0,0 +1,30 @@ +/** + * Copyright (c) 2016 Jochen Hoenicke + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __CURVES_H__ +#define __CURVES_H__ + +extern const char SECP256K1_NAME[]; +extern const char NIST256P1_NAME[]; +extern const char ED25519_NAME[]; + +#endif diff --git a/ed25519-donna/README.md b/ed25519-donna/README.md new file mode 100644 index 000000000..e09fc27e3 --- /dev/null +++ b/ed25519-donna/README.md @@ -0,0 +1,183 @@ +[ed25519](http://ed25519.cr.yp.to/) is an +[Elliptic Curve Digital Signature Algortithm](http://en.wikipedia.org/wiki/Elliptic_Curve_DSA), +developed by [Dan Bernstein](http://cr.yp.to/djb.html), +[Niels Duif](http://www.nielsduif.nl/), +[Tanja Lange](http://hyperelliptic.org/tanja), +[Peter Schwabe](http://www.cryptojedi.org/users/peter/), +and [Bo-Yin Yang](http://www.iis.sinica.edu.tw/pages/byyang/). + +This project provides performant, portable 32-bit & 64-bit implementations. All implementations are +of course constant time in regard to secret data. + +#### Performance + +SSE2 code and benches have not been updated yet. I will do those next. + +Compilers versions are gcc 4.6.3, icc 13.1.1, clang 3.4-1~exp1. + +Batch verification time (in parentheses) is the average time per 1 verification in a batch of 64 signatures. Counts are in thousands of cycles. + +Note that SSE2 performance may be less impressive on AMD & older CPUs with slower SSE ops! + +Visual Studio performance for `ge25519_scalarmult_base_niels` will lag behind a bit until optimized assembler versions of `ge25519_scalarmult_base_choose_niels` +are made. + +##### E5200 @ 2.5ghz, march=core2 + + + + + + + + + + + +
ImplementationSigngcciccclangVerifygcciccclang
ed25519-donna 64bit 100k110k137k327k (144k) 342k (163k) 422k (194k)
amd64-64-24k 102k 355k (158k)
ed25519-donna-sse2 64bit108k111k116k353k (155k) 345k (154k) 360k (161k)
amd64-51-32k 116k 380k (175k)
ed25519-donna-sse2 32bit147k147k156k380k (178k) 381k (173k) 430k (192k)
ed25519-donna 32bit 597k335k380k1693k (720k)1052k (453k)1141k (493k)
+ +##### E3-1270 @ 3.4ghz, march=corei7-avx + + + + + + + + + + + +
ImplementationSigngcciccclangVerifygcciccclang
amd64-64-24k 68k 225k (104k)
ed25519-donna 64bit 71k 75k 90k226k (105k) 226k (112k) 277k (125k)
amd64-51-32k 72k 218k (107k)
ed25519-donna-sse2 64bit 79k 82k 92k252k (122k) 259k (124k) 282k (131k)
ed25519-donna-sse2 32bit 94k 95k103k296k (146k) 294k (137k) 306k (147k)
ed25519-donna 32bit 525k299k316k1502k (645k)959k (418k) 954k (416k)
+ +#### Compilation + +No configuration is needed **if you are compiling against OpenSSL**. + +##### Hash Options + +If you are not compiling aginst OpenSSL, you will need a hash function. + +To use a simple/**slow** implementation of SHA-512, use `-DED25519_REFHASH` when compiling `ed25519.c`. +This should never be used except to verify the code works when OpenSSL is not available. + +To use a custom hash function, use `-DED25519_CUSTOMHASH` when compiling `ed25519.c` and put your +custom hash implementation in ed25519-hash-custom.h. The hash must have a 512bit digest and implement + + struct ed25519_hash_context; + + void ed25519_hash_init(ed25519_hash_context *ctx); + void ed25519_hash_update(ed25519_hash_context *ctx, const uint8_t *in, size_t inlen); + void ed25519_hash_final(ed25519_hash_context *ctx, uint8_t *hash); + void ed25519_hash(uint8_t *hash, const uint8_t *in, size_t inlen); + +##### Random Options + +If you are not compiling aginst OpenSSL, you will need a random function for batch verification. + +To use a custom random function, use `-DED25519_CUSTOMRANDOM` when compiling `ed25519.c` and put your +custom hash implementation in ed25519-randombytes-custom.h. The random function must implement: + + void ED25519_FN(ed25519_randombytes_unsafe) (void *p, size_t len); + +Use `-DED25519_TEST` when compiling `ed25519.c` to use a deterministically seeded, non-thread safe CSPRNG +variant of Bob Jenkins [ISAAC](http://en.wikipedia.org/wiki/ISAAC_%28cipher%29) + +##### Minor options + +Use `-DED25519_INLINE_ASM` to disable the use of custom assembler routines and instead rely on portable C. + +Use `-DED25519_FORCE_32BIT` to force the use of 32 bit routines even when compiling for 64 bit. + +##### 32-bit + + gcc ed25519.c -m32 -O3 -c + +##### 64-bit + + gcc ed25519.c -m64 -O3 -c + +##### SSE2 + + gcc ed25519.c -m32 -O3 -c -DED25519_SSE2 -msse2 + gcc ed25519.c -m64 -O3 -c -DED25519_SSE2 + +clang and icc are also supported + + +#### Usage + +To use the code, link against `ed25519.o -mbits` and: + + #include "ed25519.h" + +Add `-lssl -lcrypto` when using OpenSSL (Some systems don't need -lcrypto? It might be trial and error). + +To generate a private key, simply generate 32 bytes from a secure +cryptographic source: + + ed25519_secret_key sk; + randombytes(sk, sizeof(ed25519_secret_key)); + +To generate a public key: + + ed25519_public_key pk; + ed25519_publickey(sk, pk); + +To sign a message: + + ed25519_signature sig; + ed25519_sign(message, message_len, sk, pk, signature); + +To verify a signature: + + int valid = ed25519_sign_open(message, message_len, pk, signature) == 0; + +To batch verify signatures: + + const unsigned char *mp[num] = {message1, message2..} + size_t ml[num] = {message_len1, message_len2..} + const unsigned char *pkp[num] = {pk1, pk2..} + const unsigned char *sigp[num] = {signature1, signature2..} + int valid[num] + + /* valid[i] will be set to 1 if the individual signature was valid, 0 otherwise */ + int all_valid = ed25519_sign_open_batch(mp, ml, pkp, sigp, num, valid) == 0; + +**Note**: Batch verification uses `ed25519_randombytes_unsafe`, implemented in +`ed25519-randombytes.h`, to generate random scalars for the verification code. +The default implementation now uses OpenSSLs `RAND_bytes`. + +Unlike the [SUPERCOP](http://bench.cr.yp.to/supercop.html) version, signatures are +not appended to messages, and there is no need for padding in front of messages. +Additionally, the secret key does not contain a copy of the public key, so it is +32 bytes instead of 64 bytes, and the public key must be provided to the signing +function. + +##### Curve25519 + +Curve25519 public keys can be generated thanks to +[Adam Langley](http://www.imperialviolet.org/2013/05/10/fastercurve25519.html) +leveraging Ed25519's precomputed basepoint scalar multiplication. + + curved25519_key sk, pk; + randombytes(sk, sizeof(curved25519_key)); + curved25519_scalarmult_basepoint(pk, sk); + +Note the name is curved25519, a combination of curve and ed25519, to prevent +name clashes. Performance is slightly faster than short message ed25519 +signing due to both using the same code for the scalar multiply. + +#### Testing + +Fuzzing against reference implemenations is now available. See [fuzz/README](fuzz/README.md). + +Building `ed25519.c` with `-DED25519_TEST` and linking with `test.c` will run basic sanity tests +and benchmark each function. `test-batch.c` has been incorporated in to `test.c`. + +`test-internals.c` is standalone and built the same way as `ed25519.c`. It tests the math primitives +with extreme values to ensure they function correctly. SSE2 is now supported. + +#### Papers + +[Available on the Ed25519 website](http://ed25519.cr.yp.to/papers.html) \ No newline at end of file diff --git a/ed25519-donna/curve25519-donna-32bit.h b/ed25519-donna/curve25519-donna-32bit.h new file mode 100644 index 000000000..b0861acf0 --- /dev/null +++ b/ed25519-donna/curve25519-donna-32bit.h @@ -0,0 +1,579 @@ +/* + Public domain by Andrew M. + See: https://github.com/floodyberry/curve25519-donna + + 32 bit integer curve25519 implementation +*/ + +typedef uint32_t bignum25519[10]; +typedef uint32_t bignum25519align16[12]; + +static const uint32_t reduce_mask_25 = (1 << 25) - 1; +static const uint32_t reduce_mask_26 = (1 << 26) - 1; + + +/* out = in */ +DONNA_INLINE static void +curve25519_copy(bignum25519 out, const bignum25519 in) { + out[0] = in[0]; + out[1] = in[1]; + out[2] = in[2]; + out[3] = in[3]; + out[4] = in[4]; + out[5] = in[5]; + out[6] = in[6]; + out[7] = in[7]; + out[8] = in[8]; + out[9] = in[9]; +} + +/* out = a + b */ +DONNA_INLINE static void +curve25519_add(bignum25519 out, const bignum25519 a, const bignum25519 b) { + out[0] = a[0] + b[0]; + out[1] = a[1] + b[1]; + out[2] = a[2] + b[2]; + out[3] = a[3] + b[3]; + out[4] = a[4] + b[4]; + out[5] = a[5] + b[5]; + out[6] = a[6] + b[6]; + out[7] = a[7] + b[7]; + out[8] = a[8] + b[8]; + out[9] = a[9] + b[9]; +} + +DONNA_INLINE static void +curve25519_add_after_basic(bignum25519 out, const bignum25519 a, const bignum25519 b) { + uint32_t c; + out[0] = a[0] + b[0] ; c = (out[0] >> 26); out[0] &= reduce_mask_26; + out[1] = a[1] + b[1] + c; c = (out[1] >> 25); out[1] &= reduce_mask_25; + out[2] = a[2] + b[2] + c; c = (out[2] >> 26); out[2] &= reduce_mask_26; + out[3] = a[3] + b[3] + c; c = (out[3] >> 25); out[3] &= reduce_mask_25; + out[4] = a[4] + b[4] + c; c = (out[4] >> 26); out[4] &= reduce_mask_26; + out[5] = a[5] + b[5] + c; c = (out[5] >> 25); out[5] &= reduce_mask_25; + out[6] = a[6] + b[6] + c; c = (out[6] >> 26); out[6] &= reduce_mask_26; + out[7] = a[7] + b[7] + c; c = (out[7] >> 25); out[7] &= reduce_mask_25; + out[8] = a[8] + b[8] + c; c = (out[8] >> 26); out[8] &= reduce_mask_26; + out[9] = a[9] + b[9] + c; c = (out[9] >> 25); out[9] &= reduce_mask_25; + out[0] += 19 * c; +} + +DONNA_INLINE static void +curve25519_add_reduce(bignum25519 out, const bignum25519 a, const bignum25519 b) { + uint32_t c; + out[0] = a[0] + b[0] ; c = (out[0] >> 26); out[0] &= reduce_mask_26; + out[1] = a[1] + b[1] + c; c = (out[1] >> 25); out[1] &= reduce_mask_25; + out[2] = a[2] + b[2] + c; c = (out[2] >> 26); out[2] &= reduce_mask_26; + out[3] = a[3] + b[3] + c; c = (out[3] >> 25); out[3] &= reduce_mask_25; + out[4] = a[4] + b[4] + c; c = (out[4] >> 26); out[4] &= reduce_mask_26; + out[5] = a[5] + b[5] + c; c = (out[5] >> 25); out[5] &= reduce_mask_25; + out[6] = a[6] + b[6] + c; c = (out[6] >> 26); out[6] &= reduce_mask_26; + out[7] = a[7] + b[7] + c; c = (out[7] >> 25); out[7] &= reduce_mask_25; + out[8] = a[8] + b[8] + c; c = (out[8] >> 26); out[8] &= reduce_mask_26; + out[9] = a[9] + b[9] + c; c = (out[9] >> 25); out[9] &= reduce_mask_25; + out[0] += 19 * c; +} + +/* multiples of p */ +static const uint32_t twoP0 = 0x07ffffda; +static const uint32_t twoP13579 = 0x03fffffe; +static const uint32_t twoP2468 = 0x07fffffe; +static const uint32_t fourP0 = 0x0fffffb4; +static const uint32_t fourP13579 = 0x07fffffc; +static const uint32_t fourP2468 = 0x0ffffffc; + +/* out = a - b */ +DONNA_INLINE static void +curve25519_sub(bignum25519 out, const bignum25519 a, const bignum25519 b) { + uint32_t c; + out[0] = twoP0 + a[0] - b[0] ; c = (out[0] >> 26); out[0] &= reduce_mask_26; + out[1] = twoP13579 + a[1] - b[1] + c; c = (out[1] >> 25); out[1] &= reduce_mask_25; + out[2] = twoP2468 + a[2] - b[2] + c; c = (out[2] >> 26); out[2] &= reduce_mask_26; + out[3] = twoP13579 + a[3] - b[3] + c; c = (out[3] >> 25); out[3] &= reduce_mask_25; + out[4] = twoP2468 + a[4] - b[4] + c; + out[5] = twoP13579 + a[5] - b[5] ; + out[6] = twoP2468 + a[6] - b[6] ; + out[7] = twoP13579 + a[7] - b[7] ; + out[8] = twoP2468 + a[8] - b[8] ; + out[9] = twoP13579 + a[9] - b[9] ; +} + +/* out = a - b, where a is the result of a basic op (add,sub) */ +DONNA_INLINE static void +curve25519_sub_after_basic(bignum25519 out, const bignum25519 a, const bignum25519 b) { + uint32_t c; + out[0] = fourP0 + a[0] - b[0] ; c = (out[0] >> 26); out[0] &= reduce_mask_26; + out[1] = fourP13579 + a[1] - b[1] + c; c = (out[1] >> 25); out[1] &= reduce_mask_25; + out[2] = fourP2468 + a[2] - b[2] + c; c = (out[2] >> 26); out[2] &= reduce_mask_26; + out[3] = fourP13579 + a[3] - b[3] + c; c = (out[3] >> 25); out[3] &= reduce_mask_25; + out[4] = fourP2468 + a[4] - b[4] + c; c = (out[4] >> 26); out[4] &= reduce_mask_26; + out[5] = fourP13579 + a[5] - b[5] + c; c = (out[5] >> 25); out[5] &= reduce_mask_25; + out[6] = fourP2468 + a[6] - b[6] + c; c = (out[6] >> 26); out[6] &= reduce_mask_26; + out[7] = fourP13579 + a[7] - b[7] + c; c = (out[7] >> 25); out[7] &= reduce_mask_25; + out[8] = fourP2468 + a[8] - b[8] + c; c = (out[8] >> 26); out[8] &= reduce_mask_26; + out[9] = fourP13579 + a[9] - b[9] + c; c = (out[9] >> 25); out[9] &= reduce_mask_25; + out[0] += 19 * c; +} + +DONNA_INLINE static void +curve25519_sub_reduce(bignum25519 out, const bignum25519 a, const bignum25519 b) { + uint32_t c; + out[0] = fourP0 + a[0] - b[0] ; c = (out[0] >> 26); out[0] &= reduce_mask_26; + out[1] = fourP13579 + a[1] - b[1] + c; c = (out[1] >> 25); out[1] &= reduce_mask_25; + out[2] = fourP2468 + a[2] - b[2] + c; c = (out[2] >> 26); out[2] &= reduce_mask_26; + out[3] = fourP13579 + a[3] - b[3] + c; c = (out[3] >> 25); out[3] &= reduce_mask_25; + out[4] = fourP2468 + a[4] - b[4] + c; c = (out[4] >> 26); out[4] &= reduce_mask_26; + out[5] = fourP13579 + a[5] - b[5] + c; c = (out[5] >> 25); out[5] &= reduce_mask_25; + out[6] = fourP2468 + a[6] - b[6] + c; c = (out[6] >> 26); out[6] &= reduce_mask_26; + out[7] = fourP13579 + a[7] - b[7] + c; c = (out[7] >> 25); out[7] &= reduce_mask_25; + out[8] = fourP2468 + a[8] - b[8] + c; c = (out[8] >> 26); out[8] &= reduce_mask_26; + out[9] = fourP13579 + a[9] - b[9] + c; c = (out[9] >> 25); out[9] &= reduce_mask_25; + out[0] += 19 * c; +} + +/* out = -a */ +DONNA_INLINE static void +curve25519_neg(bignum25519 out, const bignum25519 a) { + uint32_t c; + out[0] = twoP0 - a[0] ; c = (out[0] >> 26); out[0] &= reduce_mask_26; + out[1] = twoP13579 - a[1] + c; c = (out[1] >> 25); out[1] &= reduce_mask_25; + out[2] = twoP2468 - a[2] + c; c = (out[2] >> 26); out[2] &= reduce_mask_26; + out[3] = twoP13579 - a[3] + c; c = (out[3] >> 25); out[3] &= reduce_mask_25; + out[4] = twoP2468 - a[4] + c; c = (out[4] >> 26); out[4] &= reduce_mask_26; + out[5] = twoP13579 - a[5] + c; c = (out[5] >> 25); out[5] &= reduce_mask_25; + out[6] = twoP2468 - a[6] + c; c = (out[6] >> 26); out[6] &= reduce_mask_26; + out[7] = twoP13579 - a[7] + c; c = (out[7] >> 25); out[7] &= reduce_mask_25; + out[8] = twoP2468 - a[8] + c; c = (out[8] >> 26); out[8] &= reduce_mask_26; + out[9] = twoP13579 - a[9] + c; c = (out[9] >> 25); out[9] &= reduce_mask_25; + out[0] += 19 * c; +} + +/* out = a * b */ +#define curve25519_mul_noinline curve25519_mul +static void +curve25519_mul(bignum25519 out, const bignum25519 a, const bignum25519 b) { + uint32_t r0,r1,r2,r3,r4,r5,r6,r7,r8,r9; + uint32_t s0,s1,s2,s3,s4,s5,s6,s7,s8,s9; + uint64_t m0,m1,m2,m3,m4,m5,m6,m7,m8,m9,c; + uint32_t p; + + r0 = b[0]; + r1 = b[1]; + r2 = b[2]; + r3 = b[3]; + r4 = b[4]; + r5 = b[5]; + r6 = b[6]; + r7 = b[7]; + r8 = b[8]; + r9 = b[9]; + + s0 = a[0]; + s1 = a[1]; + s2 = a[2]; + s3 = a[3]; + s4 = a[4]; + s5 = a[5]; + s6 = a[6]; + s7 = a[7]; + s8 = a[8]; + s9 = a[9]; + + m1 = mul32x32_64(r0, s1) + mul32x32_64(r1, s0); + m3 = mul32x32_64(r0, s3) + mul32x32_64(r1, s2) + mul32x32_64(r2, s1) + mul32x32_64(r3, s0); + m5 = mul32x32_64(r0, s5) + mul32x32_64(r1, s4) + mul32x32_64(r2, s3) + mul32x32_64(r3, s2) + mul32x32_64(r4, s1) + mul32x32_64(r5, s0); + m7 = mul32x32_64(r0, s7) + mul32x32_64(r1, s6) + mul32x32_64(r2, s5) + mul32x32_64(r3, s4) + mul32x32_64(r4, s3) + mul32x32_64(r5, s2) + mul32x32_64(r6, s1) + mul32x32_64(r7, s0); + m9 = mul32x32_64(r0, s9) + mul32x32_64(r1, s8) + mul32x32_64(r2, s7) + mul32x32_64(r3, s6) + mul32x32_64(r4, s5) + mul32x32_64(r5, s4) + mul32x32_64(r6, s3) + mul32x32_64(r7, s2) + mul32x32_64(r8, s1) + mul32x32_64(r9, s0); + + r1 *= 2; + r3 *= 2; + r5 *= 2; + r7 *= 2; + + m0 = mul32x32_64(r0, s0); + m2 = mul32x32_64(r0, s2) + mul32x32_64(r1, s1) + mul32x32_64(r2, s0); + m4 = mul32x32_64(r0, s4) + mul32x32_64(r1, s3) + mul32x32_64(r2, s2) + mul32x32_64(r3, s1) + mul32x32_64(r4, s0); + m6 = mul32x32_64(r0, s6) + mul32x32_64(r1, s5) + mul32x32_64(r2, s4) + mul32x32_64(r3, s3) + mul32x32_64(r4, s2) + mul32x32_64(r5, s1) + mul32x32_64(r6, s0); + m8 = mul32x32_64(r0, s8) + mul32x32_64(r1, s7) + mul32x32_64(r2, s6) + mul32x32_64(r3, s5) + mul32x32_64(r4, s4) + mul32x32_64(r5, s3) + mul32x32_64(r6, s2) + mul32x32_64(r7, s1) + mul32x32_64(r8, s0); + + r1 *= 19; + r2 *= 19; + r3 = (r3 / 2) * 19; + r4 *= 19; + r5 = (r5 / 2) * 19; + r6 *= 19; + r7 = (r7 / 2) * 19; + r8 *= 19; + r9 *= 19; + + m1 += (mul32x32_64(r9, s2) + mul32x32_64(r8, s3) + mul32x32_64(r7, s4) + mul32x32_64(r6, s5) + mul32x32_64(r5, s6) + mul32x32_64(r4, s7) + mul32x32_64(r3, s8) + mul32x32_64(r2, s9)); + m3 += (mul32x32_64(r9, s4) + mul32x32_64(r8, s5) + mul32x32_64(r7, s6) + mul32x32_64(r6, s7) + mul32x32_64(r5, s8) + mul32x32_64(r4, s9)); + m5 += (mul32x32_64(r9, s6) + mul32x32_64(r8, s7) + mul32x32_64(r7, s8) + mul32x32_64(r6, s9)); + m7 += (mul32x32_64(r9, s8) + mul32x32_64(r8, s9)); + + r3 *= 2; + r5 *= 2; + r7 *= 2; + r9 *= 2; + + m0 += (mul32x32_64(r9, s1) + mul32x32_64(r8, s2) + mul32x32_64(r7, s3) + mul32x32_64(r6, s4) + mul32x32_64(r5, s5) + mul32x32_64(r4, s6) + mul32x32_64(r3, s7) + mul32x32_64(r2, s8) + mul32x32_64(r1, s9)); + m2 += (mul32x32_64(r9, s3) + mul32x32_64(r8, s4) + mul32x32_64(r7, s5) + mul32x32_64(r6, s6) + mul32x32_64(r5, s7) + mul32x32_64(r4, s8) + mul32x32_64(r3, s9)); + m4 += (mul32x32_64(r9, s5) + mul32x32_64(r8, s6) + mul32x32_64(r7, s7) + mul32x32_64(r6, s8) + mul32x32_64(r5, s9)); + m6 += (mul32x32_64(r9, s7) + mul32x32_64(r8, s8) + mul32x32_64(r7, s9)); + m8 += (mul32x32_64(r9, s9)); + + r0 = (uint32_t)m0 & reduce_mask_26; c = (m0 >> 26); + m1 += c; r1 = (uint32_t)m1 & reduce_mask_25; c = (m1 >> 25); + m2 += c; r2 = (uint32_t)m2 & reduce_mask_26; c = (m2 >> 26); + m3 += c; r3 = (uint32_t)m3 & reduce_mask_25; c = (m3 >> 25); + m4 += c; r4 = (uint32_t)m4 & reduce_mask_26; c = (m4 >> 26); + m5 += c; r5 = (uint32_t)m5 & reduce_mask_25; c = (m5 >> 25); + m6 += c; r6 = (uint32_t)m6 & reduce_mask_26; c = (m6 >> 26); + m7 += c; r7 = (uint32_t)m7 & reduce_mask_25; c = (m7 >> 25); + m8 += c; r8 = (uint32_t)m8 & reduce_mask_26; c = (m8 >> 26); + m9 += c; r9 = (uint32_t)m9 & reduce_mask_25; p = (uint32_t)(m9 >> 25); + m0 = r0 + mul32x32_64(p,19); r0 = (uint32_t)m0 & reduce_mask_26; p = (uint32_t)(m0 >> 26); + r1 += p; + + out[0] = r0; + out[1] = r1; + out[2] = r2; + out[3] = r3; + out[4] = r4; + out[5] = r5; + out[6] = r6; + out[7] = r7; + out[8] = r8; + out[9] = r9; +} + +/* out = in*in */ +static void +curve25519_square(bignum25519 out, const bignum25519 in) { + uint32_t r0,r1,r2,r3,r4,r5,r6,r7,r8,r9; + uint32_t d6,d7,d8,d9; + uint64_t m0,m1,m2,m3,m4,m5,m6,m7,m8,m9,c; + uint32_t p; + + r0 = in[0]; + r1 = in[1]; + r2 = in[2]; + r3 = in[3]; + r4 = in[4]; + r5 = in[5]; + r6 = in[6]; + r7 = in[7]; + r8 = in[8]; + r9 = in[9]; + + m0 = mul32x32_64(r0, r0); + r0 *= 2; + m1 = mul32x32_64(r0, r1); + m2 = mul32x32_64(r0, r2) + mul32x32_64(r1, r1 * 2); + r1 *= 2; + m3 = mul32x32_64(r0, r3) + mul32x32_64(r1, r2 ); + m4 = mul32x32_64(r0, r4) + mul32x32_64(r1, r3 * 2) + mul32x32_64(r2, r2); + r2 *= 2; + m5 = mul32x32_64(r0, r5) + mul32x32_64(r1, r4 ) + mul32x32_64(r2, r3); + m6 = mul32x32_64(r0, r6) + mul32x32_64(r1, r5 * 2) + mul32x32_64(r2, r4) + mul32x32_64(r3, r3 * 2); + r3 *= 2; + m7 = mul32x32_64(r0, r7) + mul32x32_64(r1, r6 ) + mul32x32_64(r2, r5) + mul32x32_64(r3, r4 ); + m8 = mul32x32_64(r0, r8) + mul32x32_64(r1, r7 * 2) + mul32x32_64(r2, r6) + mul32x32_64(r3, r5 * 2) + mul32x32_64(r4, r4 ); + m9 = mul32x32_64(r0, r9) + mul32x32_64(r1, r8 ) + mul32x32_64(r2, r7) + mul32x32_64(r3, r6 ) + mul32x32_64(r4, r5 * 2); + + d6 = r6 * 19; + d7 = r7 * 2 * 19; + d8 = r8 * 19; + d9 = r9 * 2 * 19; + + m0 += (mul32x32_64(d9, r1 ) + mul32x32_64(d8, r2 ) + mul32x32_64(d7, r3 ) + mul32x32_64(d6, r4 * 2) + mul32x32_64(r5, r5 * 2 * 19)); + m1 += (mul32x32_64(d9, r2 / 2) + mul32x32_64(d8, r3 ) + mul32x32_64(d7, r4 ) + mul32x32_64(d6, r5 * 2)); + m2 += (mul32x32_64(d9, r3 ) + mul32x32_64(d8, r4 * 2) + mul32x32_64(d7, r5 * 2) + mul32x32_64(d6, r6 )); + m3 += (mul32x32_64(d9, r4 ) + mul32x32_64(d8, r5 * 2) + mul32x32_64(d7, r6 )); + m4 += (mul32x32_64(d9, r5 * 2) + mul32x32_64(d8, r6 * 2) + mul32x32_64(d7, r7 )); + m5 += (mul32x32_64(d9, r6 ) + mul32x32_64(d8, r7 * 2)); + m6 += (mul32x32_64(d9, r7 * 2) + mul32x32_64(d8, r8 )); + m7 += (mul32x32_64(d9, r8 )); + m8 += (mul32x32_64(d9, r9 )); + + r0 = (uint32_t)m0 & reduce_mask_26; c = (m0 >> 26); + m1 += c; r1 = (uint32_t)m1 & reduce_mask_25; c = (m1 >> 25); + m2 += c; r2 = (uint32_t)m2 & reduce_mask_26; c = (m2 >> 26); + m3 += c; r3 = (uint32_t)m3 & reduce_mask_25; c = (m3 >> 25); + m4 += c; r4 = (uint32_t)m4 & reduce_mask_26; c = (m4 >> 26); + m5 += c; r5 = (uint32_t)m5 & reduce_mask_25; c = (m5 >> 25); + m6 += c; r6 = (uint32_t)m6 & reduce_mask_26; c = (m6 >> 26); + m7 += c; r7 = (uint32_t)m7 & reduce_mask_25; c = (m7 >> 25); + m8 += c; r8 = (uint32_t)m8 & reduce_mask_26; c = (m8 >> 26); + m9 += c; r9 = (uint32_t)m9 & reduce_mask_25; p = (uint32_t)(m9 >> 25); + m0 = r0 + mul32x32_64(p,19); r0 = (uint32_t)m0 & reduce_mask_26; p = (uint32_t)(m0 >> 26); + r1 += p; + + out[0] = r0; + out[1] = r1; + out[2] = r2; + out[3] = r3; + out[4] = r4; + out[5] = r5; + out[6] = r6; + out[7] = r7; + out[8] = r8; + out[9] = r9; +} + + +/* out = in ^ (2 * count) */ +static void +curve25519_square_times(bignum25519 out, const bignum25519 in, int count) { + uint32_t r0,r1,r2,r3,r4,r5,r6,r7,r8,r9; + uint32_t d6,d7,d8,d9; + uint64_t m0,m1,m2,m3,m4,m5,m6,m7,m8,m9,c; + uint32_t p; + + r0 = in[0]; + r1 = in[1]; + r2 = in[2]; + r3 = in[3]; + r4 = in[4]; + r5 = in[5]; + r6 = in[6]; + r7 = in[7]; + r8 = in[8]; + r9 = in[9]; + + do { + m0 = mul32x32_64(r0, r0); + r0 *= 2; + m1 = mul32x32_64(r0, r1); + m2 = mul32x32_64(r0, r2) + mul32x32_64(r1, r1 * 2); + r1 *= 2; + m3 = mul32x32_64(r0, r3) + mul32x32_64(r1, r2 ); + m4 = mul32x32_64(r0, r4) + mul32x32_64(r1, r3 * 2) + mul32x32_64(r2, r2); + r2 *= 2; + m5 = mul32x32_64(r0, r5) + mul32x32_64(r1, r4 ) + mul32x32_64(r2, r3); + m6 = mul32x32_64(r0, r6) + mul32x32_64(r1, r5 * 2) + mul32x32_64(r2, r4) + mul32x32_64(r3, r3 * 2); + r3 *= 2; + m7 = mul32x32_64(r0, r7) + mul32x32_64(r1, r6 ) + mul32x32_64(r2, r5) + mul32x32_64(r3, r4 ); + m8 = mul32x32_64(r0, r8) + mul32x32_64(r1, r7 * 2) + mul32x32_64(r2, r6) + mul32x32_64(r3, r5 * 2) + mul32x32_64(r4, r4 ); + m9 = mul32x32_64(r0, r9) + mul32x32_64(r1, r8 ) + mul32x32_64(r2, r7) + mul32x32_64(r3, r6 ) + mul32x32_64(r4, r5 * 2); + + d6 = r6 * 19; + d7 = r7 * 2 * 19; + d8 = r8 * 19; + d9 = r9 * 2 * 19; + + m0 += (mul32x32_64(d9, r1 ) + mul32x32_64(d8, r2 ) + mul32x32_64(d7, r3 ) + mul32x32_64(d6, r4 * 2) + mul32x32_64(r5, r5 * 2 * 19)); + m1 += (mul32x32_64(d9, r2 / 2) + mul32x32_64(d8, r3 ) + mul32x32_64(d7, r4 ) + mul32x32_64(d6, r5 * 2)); + m2 += (mul32x32_64(d9, r3 ) + mul32x32_64(d8, r4 * 2) + mul32x32_64(d7, r5 * 2) + mul32x32_64(d6, r6 )); + m3 += (mul32x32_64(d9, r4 ) + mul32x32_64(d8, r5 * 2) + mul32x32_64(d7, r6 )); + m4 += (mul32x32_64(d9, r5 * 2) + mul32x32_64(d8, r6 * 2) + mul32x32_64(d7, r7 )); + m5 += (mul32x32_64(d9, r6 ) + mul32x32_64(d8, r7 * 2)); + m6 += (mul32x32_64(d9, r7 * 2) + mul32x32_64(d8, r8 )); + m7 += (mul32x32_64(d9, r8 )); + m8 += (mul32x32_64(d9, r9 )); + + r0 = (uint32_t)m0 & reduce_mask_26; c = (m0 >> 26); + m1 += c; r1 = (uint32_t)m1 & reduce_mask_25; c = (m1 >> 25); + m2 += c; r2 = (uint32_t)m2 & reduce_mask_26; c = (m2 >> 26); + m3 += c; r3 = (uint32_t)m3 & reduce_mask_25; c = (m3 >> 25); + m4 += c; r4 = (uint32_t)m4 & reduce_mask_26; c = (m4 >> 26); + m5 += c; r5 = (uint32_t)m5 & reduce_mask_25; c = (m5 >> 25); + m6 += c; r6 = (uint32_t)m6 & reduce_mask_26; c = (m6 >> 26); + m7 += c; r7 = (uint32_t)m7 & reduce_mask_25; c = (m7 >> 25); + m8 += c; r8 = (uint32_t)m8 & reduce_mask_26; c = (m8 >> 26); + m9 += c; r9 = (uint32_t)m9 & reduce_mask_25; p = (uint32_t)(m9 >> 25); + m0 = r0 + mul32x32_64(p,19); r0 = (uint32_t)m0 & reduce_mask_26; p = (uint32_t)(m0 >> 26); + r1 += p; + } while (--count); + + out[0] = r0; + out[1] = r1; + out[2] = r2; + out[3] = r3; + out[4] = r4; + out[5] = r5; + out[6] = r6; + out[7] = r7; + out[8] = r8; + out[9] = r9; +} + +/* Take a little-endian, 32-byte number and expand it into polynomial form */ +static void +curve25519_expand(bignum25519 out, const unsigned char in[32]) { + static const union { uint8_t b[2]; uint16_t s; } endian_check = {{1,0}}; + uint32_t x0,x1,x2,x3,x4,x5,x6,x7; + + if (endian_check.s == 1) { + x0 = *(uint32_t *)(in + 0); + x1 = *(uint32_t *)(in + 4); + x2 = *(uint32_t *)(in + 8); + x3 = *(uint32_t *)(in + 12); + x4 = *(uint32_t *)(in + 16); + x5 = *(uint32_t *)(in + 20); + x6 = *(uint32_t *)(in + 24); + x7 = *(uint32_t *)(in + 28); + } else { + #define F(s) \ + ((((uint32_t)in[s + 0]) ) | \ + (((uint32_t)in[s + 1]) << 8) | \ + (((uint32_t)in[s + 2]) << 16) | \ + (((uint32_t)in[s + 3]) << 24)) + x0 = F(0); + x1 = F(4); + x2 = F(8); + x3 = F(12); + x4 = F(16); + x5 = F(20); + x6 = F(24); + x7 = F(28); + #undef F + } + + out[0] = ( x0 ) & 0x3ffffff; + out[1] = ((((uint64_t)x1 << 32) | x0) >> 26) & 0x1ffffff; + out[2] = ((((uint64_t)x2 << 32) | x1) >> 19) & 0x3ffffff; + out[3] = ((((uint64_t)x3 << 32) | x2) >> 13) & 0x1ffffff; + out[4] = (( x3) >> 6) & 0x3ffffff; + out[5] = ( x4 ) & 0x1ffffff; + out[6] = ((((uint64_t)x5 << 32) | x4) >> 25) & 0x3ffffff; + out[7] = ((((uint64_t)x6 << 32) | x5) >> 19) & 0x1ffffff; + out[8] = ((((uint64_t)x7 << 32) | x6) >> 12) & 0x3ffffff; + out[9] = (( x7) >> 6) & 0x1ffffff; +} + +/* Take a fully reduced polynomial form number and contract it into a + * little-endian, 32-byte array + */ +static void +curve25519_contract(unsigned char out[32], const bignum25519 in) { + bignum25519 f; + curve25519_copy(f, in); + + #define carry_pass() \ + f[1] += f[0] >> 26; f[0] &= reduce_mask_26; \ + f[2] += f[1] >> 25; f[1] &= reduce_mask_25; \ + f[3] += f[2] >> 26; f[2] &= reduce_mask_26; \ + f[4] += f[3] >> 25; f[3] &= reduce_mask_25; \ + f[5] += f[4] >> 26; f[4] &= reduce_mask_26; \ + f[6] += f[5] >> 25; f[5] &= reduce_mask_25; \ + f[7] += f[6] >> 26; f[6] &= reduce_mask_26; \ + f[8] += f[7] >> 25; f[7] &= reduce_mask_25; \ + f[9] += f[8] >> 26; f[8] &= reduce_mask_26; + + #define carry_pass_full() \ + carry_pass() \ + f[0] += 19 * (f[9] >> 25); f[9] &= reduce_mask_25; + + #define carry_pass_final() \ + carry_pass() \ + f[9] &= reduce_mask_25; + + carry_pass_full() + carry_pass_full() + + /* now t is between 0 and 2^255-1, properly carried. */ + /* case 1: between 0 and 2^255-20. case 2: between 2^255-19 and 2^255-1. */ + f[0] += 19; + carry_pass_full() + + /* now between 19 and 2^255-1 in both cases, and offset by 19. */ + f[0] += (reduce_mask_26 + 1) - 19; + f[1] += (reduce_mask_25 + 1) - 1; + f[2] += (reduce_mask_26 + 1) - 1; + f[3] += (reduce_mask_25 + 1) - 1; + f[4] += (reduce_mask_26 + 1) - 1; + f[5] += (reduce_mask_25 + 1) - 1; + f[6] += (reduce_mask_26 + 1) - 1; + f[7] += (reduce_mask_25 + 1) - 1; + f[8] += (reduce_mask_26 + 1) - 1; + f[9] += (reduce_mask_25 + 1) - 1; + + /* now between 2^255 and 2^256-20, and offset by 2^255. */ + carry_pass_final() + + #undef carry_pass + #undef carry_full + #undef carry_final + + f[1] <<= 2; + f[2] <<= 3; + f[3] <<= 5; + f[4] <<= 6; + f[6] <<= 1; + f[7] <<= 3; + f[8] <<= 4; + f[9] <<= 6; + + #define F(i, s) \ + out[s+0] |= (unsigned char )(f[i] & 0xff); \ + out[s+1] = (unsigned char )((f[i] >> 8) & 0xff); \ + out[s+2] = (unsigned char )((f[i] >> 16) & 0xff); \ + out[s+3] = (unsigned char )((f[i] >> 24) & 0xff); + + out[0] = 0; + out[16] = 0; + F(0,0); + F(1,3); + F(2,6); + F(3,9); + F(4,12); + F(5,16); + F(6,19); + F(7,22); + F(8,25); + F(9,28); + #undef F +} + + +/* out = (flag) ? in : out */ +DONNA_INLINE static void +curve25519_move_conditional_bytes(uint8_t out[96], const uint8_t in[96], uint32_t flag) { + const uint32_t nb = flag - 1, b = ~nb; + const uint32_t *inl = (const uint32_t *)in; + uint32_t *outl = (uint32_t *)out; + outl[0] = (outl[0] & nb) | (inl[0] & b); + outl[1] = (outl[1] & nb) | (inl[1] & b); + outl[2] = (outl[2] & nb) | (inl[2] & b); + outl[3] = (outl[3] & nb) | (inl[3] & b); + outl[4] = (outl[4] & nb) | (inl[4] & b); + outl[5] = (outl[5] & nb) | (inl[5] & b); + outl[6] = (outl[6] & nb) | (inl[6] & b); + outl[7] = (outl[7] & nb) | (inl[7] & b); + outl[8] = (outl[8] & nb) | (inl[8] & b); + outl[9] = (outl[9] & nb) | (inl[9] & b); + outl[10] = (outl[10] & nb) | (inl[10] & b); + outl[11] = (outl[11] & nb) | (inl[11] & b); + outl[12] = (outl[12] & nb) | (inl[12] & b); + outl[13] = (outl[13] & nb) | (inl[13] & b); + outl[14] = (outl[14] & nb) | (inl[14] & b); + outl[15] = (outl[15] & nb) | (inl[15] & b); + outl[16] = (outl[16] & nb) | (inl[16] & b); + outl[17] = (outl[17] & nb) | (inl[17] & b); + outl[18] = (outl[18] & nb) | (inl[18] & b); + outl[19] = (outl[19] & nb) | (inl[19] & b); + outl[20] = (outl[20] & nb) | (inl[20] & b); + outl[21] = (outl[21] & nb) | (inl[21] & b); + outl[22] = (outl[22] & nb) | (inl[22] & b); + outl[23] = (outl[23] & nb) | (inl[23] & b); + +} + +/* if (iswap) swap(a, b) */ +DONNA_INLINE static void +curve25519_swap_conditional(bignum25519 a, bignum25519 b, uint32_t iswap) { + const uint32_t swap = (uint32_t)(-(int32_t)iswap); + uint32_t x0,x1,x2,x3,x4,x5,x6,x7,x8,x9; + + x0 = swap & (a[0] ^ b[0]); a[0] ^= x0; b[0] ^= x0; + x1 = swap & (a[1] ^ b[1]); a[1] ^= x1; b[1] ^= x1; + x2 = swap & (a[2] ^ b[2]); a[2] ^= x2; b[2] ^= x2; + x3 = swap & (a[3] ^ b[3]); a[3] ^= x3; b[3] ^= x3; + x4 = swap & (a[4] ^ b[4]); a[4] ^= x4; b[4] ^= x4; + x5 = swap & (a[5] ^ b[5]); a[5] ^= x5; b[5] ^= x5; + x6 = swap & (a[6] ^ b[6]); a[6] ^= x6; b[6] ^= x6; + x7 = swap & (a[7] ^ b[7]); a[7] ^= x7; b[7] ^= x7; + x8 = swap & (a[8] ^ b[8]); a[8] ^= x8; b[8] ^= x8; + x9 = swap & (a[9] ^ b[9]); a[9] ^= x9; b[9] ^= x9; +} diff --git a/ed25519-donna/curve25519-donna-64bit.h b/ed25519-donna/curve25519-donna-64bit.h new file mode 100644 index 000000000..2941d1bcd --- /dev/null +++ b/ed25519-donna/curve25519-donna-64bit.h @@ -0,0 +1,413 @@ +/* + Public domain by Adam Langley & + Andrew M. + See: https://github.com/floodyberry/curve25519-donna + + 64bit integer curve25519 implementation +*/ + +typedef uint64_t bignum25519[5]; + +static const uint64_t reduce_mask_40 = ((uint64_t)1 << 40) - 1; +static const uint64_t reduce_mask_51 = ((uint64_t)1 << 51) - 1; +static const uint64_t reduce_mask_56 = ((uint64_t)1 << 56) - 1; + +/* out = in */ +DONNA_INLINE static void +curve25519_copy(bignum25519 out, const bignum25519 in) { + out[0] = in[0]; + out[1] = in[1]; + out[2] = in[2]; + out[3] = in[3]; + out[4] = in[4]; +} + +/* out = a + b */ +DONNA_INLINE static void +curve25519_add(bignum25519 out, const bignum25519 a, const bignum25519 b) { + out[0] = a[0] + b[0]; + out[1] = a[1] + b[1]; + out[2] = a[2] + b[2]; + out[3] = a[3] + b[3]; + out[4] = a[4] + b[4]; +} + +/* out = a + b, where a and/or b are the result of a basic op (add,sub) */ +DONNA_INLINE static void +curve25519_add_after_basic(bignum25519 out, const bignum25519 a, const bignum25519 b) { + out[0] = a[0] + b[0]; + out[1] = a[1] + b[1]; + out[2] = a[2] + b[2]; + out[3] = a[3] + b[3]; + out[4] = a[4] + b[4]; +} + +DONNA_INLINE static void +curve25519_add_reduce(bignum25519 out, const bignum25519 a, const bignum25519 b) { + uint64_t c; + out[0] = a[0] + b[0] ; c = (out[0] >> 51); out[0] &= reduce_mask_51; + out[1] = a[1] + b[1] + c; c = (out[1] >> 51); out[1] &= reduce_mask_51; + out[2] = a[2] + b[2] + c; c = (out[2] >> 51); out[2] &= reduce_mask_51; + out[3] = a[3] + b[3] + c; c = (out[3] >> 51); out[3] &= reduce_mask_51; + out[4] = a[4] + b[4] + c; c = (out[4] >> 51); out[4] &= reduce_mask_51; + out[0] += c * 19; +} + +/* multiples of p */ +static const uint64_t twoP0 = 0x0fffffffffffda; +static const uint64_t twoP1234 = 0x0ffffffffffffe; +static const uint64_t fourP0 = 0x1fffffffffffb4; +static const uint64_t fourP1234 = 0x1ffffffffffffc; + +/* out = a - b */ +DONNA_INLINE static void +curve25519_sub(bignum25519 out, const bignum25519 a, const bignum25519 b) { + out[0] = a[0] + twoP0 - b[0]; + out[1] = a[1] + twoP1234 - b[1]; + out[2] = a[2] + twoP1234 - b[2]; + out[3] = a[3] + twoP1234 - b[3]; + out[4] = a[4] + twoP1234 - b[4]; +} + +/* out = a - b, where a and/or b are the result of a basic op (add,sub) */ +DONNA_INLINE static void +curve25519_sub_after_basic(bignum25519 out, const bignum25519 a, const bignum25519 b) { + out[0] = a[0] + fourP0 - b[0]; + out[1] = a[1] + fourP1234 - b[1]; + out[2] = a[2] + fourP1234 - b[2]; + out[3] = a[3] + fourP1234 - b[3]; + out[4] = a[4] + fourP1234 - b[4]; +} + +DONNA_INLINE static void +curve25519_sub_reduce(bignum25519 out, const bignum25519 a, const bignum25519 b) { + uint64_t c; + out[0] = a[0] + fourP0 - b[0] ; c = (out[0] >> 51); out[0] &= reduce_mask_51; + out[1] = a[1] + fourP1234 - b[1] + c; c = (out[1] >> 51); out[1] &= reduce_mask_51; + out[2] = a[2] + fourP1234 - b[2] + c; c = (out[2] >> 51); out[2] &= reduce_mask_51; + out[3] = a[3] + fourP1234 - b[3] + c; c = (out[3] >> 51); out[3] &= reduce_mask_51; + out[4] = a[4] + fourP1234 - b[4] + c; c = (out[4] >> 51); out[4] &= reduce_mask_51; + out[0] += c * 19; +} + +/* out = -a */ +DONNA_INLINE static void +curve25519_neg(bignum25519 out, const bignum25519 a) { + uint64_t c; + out[0] = twoP0 - a[0] ; c = (out[0] >> 51); out[0] &= reduce_mask_51; + out[1] = twoP1234 - a[1] + c; c = (out[1] >> 51); out[1] &= reduce_mask_51; + out[2] = twoP1234 - a[2] + c; c = (out[2] >> 51); out[2] &= reduce_mask_51; + out[3] = twoP1234 - a[3] + c; c = (out[3] >> 51); out[3] &= reduce_mask_51; + out[4] = twoP1234 - a[4] + c; c = (out[4] >> 51); out[4] &= reduce_mask_51; + out[0] += c * 19; +} + +/* out = a * b */ +DONNA_INLINE static void +curve25519_mul(bignum25519 out, const bignum25519 in2, const bignum25519 in) { +#if !defined(HAVE_NATIVE_UINT128) + uint128_t mul; +#endif + uint128_t t[5]; + uint64_t r0,r1,r2,r3,r4,s0,s1,s2,s3,s4,c; + + r0 = in[0]; + r1 = in[1]; + r2 = in[2]; + r3 = in[3]; + r4 = in[4]; + + s0 = in2[0]; + s1 = in2[1]; + s2 = in2[2]; + s3 = in2[3]; + s4 = in2[4]; + +#if defined(HAVE_NATIVE_UINT128) + t[0] = ((uint128_t) r0) * s0; + t[1] = ((uint128_t) r0) * s1 + ((uint128_t) r1) * s0; + t[2] = ((uint128_t) r0) * s2 + ((uint128_t) r2) * s0 + ((uint128_t) r1) * s1; + t[3] = ((uint128_t) r0) * s3 + ((uint128_t) r3) * s0 + ((uint128_t) r1) * s2 + ((uint128_t) r2) * s1; + t[4] = ((uint128_t) r0) * s4 + ((uint128_t) r4) * s0 + ((uint128_t) r3) * s1 + ((uint128_t) r1) * s3 + ((uint128_t) r2) * s2; +#else + mul64x64_128(t[0], r0, s0) + mul64x64_128(t[1], r0, s1) mul64x64_128(mul, r1, s0) add128(t[1], mul) + mul64x64_128(t[2], r0, s2) mul64x64_128(mul, r2, s0) add128(t[2], mul) mul64x64_128(mul, r1, s1) add128(t[2], mul) + mul64x64_128(t[3], r0, s3) mul64x64_128(mul, r3, s0) add128(t[3], mul) mul64x64_128(mul, r1, s2) add128(t[3], mul) mul64x64_128(mul, r2, s1) add128(t[3], mul) + mul64x64_128(t[4], r0, s4) mul64x64_128(mul, r4, s0) add128(t[4], mul) mul64x64_128(mul, r3, s1) add128(t[4], mul) mul64x64_128(mul, r1, s3) add128(t[4], mul) mul64x64_128(mul, r2, s2) add128(t[4], mul) +#endif + + r1 *= 19; + r2 *= 19; + r3 *= 19; + r4 *= 19; + +#if defined(HAVE_NATIVE_UINT128) + t[0] += ((uint128_t) r4) * s1 + ((uint128_t) r1) * s4 + ((uint128_t) r2) * s3 + ((uint128_t) r3) * s2; + t[1] += ((uint128_t) r4) * s2 + ((uint128_t) r2) * s4 + ((uint128_t) r3) * s3; + t[2] += ((uint128_t) r4) * s3 + ((uint128_t) r3) * s4; + t[3] += ((uint128_t) r4) * s4; +#else + mul64x64_128(mul, r4, s1) add128(t[0], mul) mul64x64_128(mul, r1, s4) add128(t[0], mul) mul64x64_128(mul, r2, s3) add128(t[0], mul) mul64x64_128(mul, r3, s2) add128(t[0], mul) + mul64x64_128(mul, r4, s2) add128(t[1], mul) mul64x64_128(mul, r2, s4) add128(t[1], mul) mul64x64_128(mul, r3, s3) add128(t[1], mul) + mul64x64_128(mul, r4, s3) add128(t[2], mul) mul64x64_128(mul, r3, s4) add128(t[2], mul) + mul64x64_128(mul, r4, s4) add128(t[3], mul) +#endif + + + r0 = lo128(t[0]) & reduce_mask_51; shr128(c, t[0], 51); + add128_64(t[1], c) r1 = lo128(t[1]) & reduce_mask_51; shr128(c, t[1], 51); + add128_64(t[2], c) r2 = lo128(t[2]) & reduce_mask_51; shr128(c, t[2], 51); + add128_64(t[3], c) r3 = lo128(t[3]) & reduce_mask_51; shr128(c, t[3], 51); + add128_64(t[4], c) r4 = lo128(t[4]) & reduce_mask_51; shr128(c, t[4], 51); + r0 += c * 19; c = r0 >> 51; r0 = r0 & reduce_mask_51; + r1 += c; + + out[0] = r0; + out[1] = r1; + out[2] = r2; + out[3] = r3; + out[4] = r4; +} + +DONNA_NOINLINE static void +curve25519_mul_noinline(bignum25519 out, const bignum25519 in2, const bignum25519 in) { + curve25519_mul(out, in2, in); +} + +/* out = in^(2 * count) */ +DONNA_NOINLINE static void +curve25519_square_times(bignum25519 out, const bignum25519 in, uint64_t count) { +#if !defined(HAVE_NATIVE_UINT128) + uint128_t mul; +#endif + uint128_t t[5]; + uint64_t r0,r1,r2,r3,r4,c; + uint64_t d0,d1,d2,d4,d419; + + r0 = in[0]; + r1 = in[1]; + r2 = in[2]; + r3 = in[3]; + r4 = in[4]; + + do { + d0 = r0 * 2; + d1 = r1 * 2; + d2 = r2 * 2 * 19; + d419 = r4 * 19; + d4 = d419 * 2; + +#if defined(HAVE_NATIVE_UINT128) + t[0] = ((uint128_t) r0) * r0 + ((uint128_t) d4) * r1 + (((uint128_t) d2) * (r3 )); + t[1] = ((uint128_t) d0) * r1 + ((uint128_t) d4) * r2 + (((uint128_t) r3) * (r3 * 19)); + t[2] = ((uint128_t) d0) * r2 + ((uint128_t) r1) * r1 + (((uint128_t) d4) * (r3 )); + t[3] = ((uint128_t) d0) * r3 + ((uint128_t) d1) * r2 + (((uint128_t) r4) * (d419 )); + t[4] = ((uint128_t) d0) * r4 + ((uint128_t) d1) * r3 + (((uint128_t) r2) * (r2 )); +#else + mul64x64_128(t[0], r0, r0) mul64x64_128(mul, d4, r1) add128(t[0], mul) mul64x64_128(mul, d2, r3) add128(t[0], mul) + mul64x64_128(t[1], d0, r1) mul64x64_128(mul, d4, r2) add128(t[1], mul) mul64x64_128(mul, r3, r3 * 19) add128(t[1], mul) + mul64x64_128(t[2], d0, r2) mul64x64_128(mul, r1, r1) add128(t[2], mul) mul64x64_128(mul, d4, r3) add128(t[2], mul) + mul64x64_128(t[3], d0, r3) mul64x64_128(mul, d1, r2) add128(t[3], mul) mul64x64_128(mul, r4, d419) add128(t[3], mul) + mul64x64_128(t[4], d0, r4) mul64x64_128(mul, d1, r3) add128(t[4], mul) mul64x64_128(mul, r2, r2) add128(t[4], mul) +#endif + + r0 = lo128(t[0]) & reduce_mask_51; + r1 = lo128(t[1]) & reduce_mask_51; shl128(c, t[0], 13); r1 += c; + r2 = lo128(t[2]) & reduce_mask_51; shl128(c, t[1], 13); r2 += c; + r3 = lo128(t[3]) & reduce_mask_51; shl128(c, t[2], 13); r3 += c; + r4 = lo128(t[4]) & reduce_mask_51; shl128(c, t[3], 13); r4 += c; + shl128(c, t[4], 13); r0 += c * 19; + c = r0 >> 51; r0 &= reduce_mask_51; + r1 += c ; c = r1 >> 51; r1 &= reduce_mask_51; + r2 += c ; c = r2 >> 51; r2 &= reduce_mask_51; + r3 += c ; c = r3 >> 51; r3 &= reduce_mask_51; + r4 += c ; c = r4 >> 51; r4 &= reduce_mask_51; + r0 += c * 19; + } while(--count); + + out[0] = r0; + out[1] = r1; + out[2] = r2; + out[3] = r3; + out[4] = r4; +} + +DONNA_INLINE static void +curve25519_square(bignum25519 out, const bignum25519 in) { +#if !defined(HAVE_NATIVE_UINT128) + uint128_t mul; +#endif + uint128_t t[5]; + uint64_t r0,r1,r2,r3,r4,c; + uint64_t d0,d1,d2,d4,d419; + + r0 = in[0]; + r1 = in[1]; + r2 = in[2]; + r3 = in[3]; + r4 = in[4]; + + d0 = r0 * 2; + d1 = r1 * 2; + d2 = r2 * 2 * 19; + d419 = r4 * 19; + d4 = d419 * 2; + +#if defined(HAVE_NATIVE_UINT128) + t[0] = ((uint128_t) r0) * r0 + ((uint128_t) d4) * r1 + (((uint128_t) d2) * (r3 )); + t[1] = ((uint128_t) d0) * r1 + ((uint128_t) d4) * r2 + (((uint128_t) r3) * (r3 * 19)); + t[2] = ((uint128_t) d0) * r2 + ((uint128_t) r1) * r1 + (((uint128_t) d4) * (r3 )); + t[3] = ((uint128_t) d0) * r3 + ((uint128_t) d1) * r2 + (((uint128_t) r4) * (d419 )); + t[4] = ((uint128_t) d0) * r4 + ((uint128_t) d1) * r3 + (((uint128_t) r2) * (r2 )); +#else + mul64x64_128(t[0], r0, r0) mul64x64_128(mul, d4, r1) add128(t[0], mul) mul64x64_128(mul, d2, r3) add128(t[0], mul) + mul64x64_128(t[1], d0, r1) mul64x64_128(mul, d4, r2) add128(t[1], mul) mul64x64_128(mul, r3, r3 * 19) add128(t[1], mul) + mul64x64_128(t[2], d0, r2) mul64x64_128(mul, r1, r1) add128(t[2], mul) mul64x64_128(mul, d4, r3) add128(t[2], mul) + mul64x64_128(t[3], d0, r3) mul64x64_128(mul, d1, r2) add128(t[3], mul) mul64x64_128(mul, r4, d419) add128(t[3], mul) + mul64x64_128(t[4], d0, r4) mul64x64_128(mul, d1, r3) add128(t[4], mul) mul64x64_128(mul, r2, r2) add128(t[4], mul) +#endif + + r0 = lo128(t[0]) & reduce_mask_51; shr128(c, t[0], 51); + add128_64(t[1], c) r1 = lo128(t[1]) & reduce_mask_51; shr128(c, t[1], 51); + add128_64(t[2], c) r2 = lo128(t[2]) & reduce_mask_51; shr128(c, t[2], 51); + add128_64(t[3], c) r3 = lo128(t[3]) & reduce_mask_51; shr128(c, t[3], 51); + add128_64(t[4], c) r4 = lo128(t[4]) & reduce_mask_51; shr128(c, t[4], 51); + r0 += c * 19; c = r0 >> 51; r0 = r0 & reduce_mask_51; + r1 += c; + + out[0] = r0; + out[1] = r1; + out[2] = r2; + out[3] = r3; + out[4] = r4; +} + +/* Take a little-endian, 32-byte number and expand it into polynomial form */ +DONNA_INLINE static void +curve25519_expand(bignum25519 out, const unsigned char *in) { + static const union { uint8_t b[2]; uint16_t s; } endian_check = {{1,0}}; + uint64_t x0,x1,x2,x3; + + if (endian_check.s == 1) { + x0 = *(uint64_t *)(in + 0); + x1 = *(uint64_t *)(in + 8); + x2 = *(uint64_t *)(in + 16); + x3 = *(uint64_t *)(in + 24); + } else { + #define F(s) \ + ((((uint64_t)in[s + 0]) ) | \ + (((uint64_t)in[s + 1]) << 8) | \ + (((uint64_t)in[s + 2]) << 16) | \ + (((uint64_t)in[s + 3]) << 24) | \ + (((uint64_t)in[s + 4]) << 32) | \ + (((uint64_t)in[s + 5]) << 40) | \ + (((uint64_t)in[s + 6]) << 48) | \ + (((uint64_t)in[s + 7]) << 56)) + + x0 = F(0); + x1 = F(8); + x2 = F(16); + x3 = F(24); + } + + out[0] = x0 & reduce_mask_51; x0 = (x0 >> 51) | (x1 << 13); + out[1] = x0 & reduce_mask_51; x1 = (x1 >> 38) | (x2 << 26); + out[2] = x1 & reduce_mask_51; x2 = (x2 >> 25) | (x3 << 39); + out[3] = x2 & reduce_mask_51; x3 = (x3 >> 12); + out[4] = x3 & reduce_mask_51; +} + +/* Take a fully reduced polynomial form number and contract it into a + * little-endian, 32-byte array + */ +DONNA_INLINE static void +curve25519_contract(unsigned char *out, const bignum25519 input) { + uint64_t t[5]; + uint64_t f, i; + + t[0] = input[0]; + t[1] = input[1]; + t[2] = input[2]; + t[3] = input[3]; + t[4] = input[4]; + + #define curve25519_contract_carry() \ + t[1] += t[0] >> 51; t[0] &= reduce_mask_51; \ + t[2] += t[1] >> 51; t[1] &= reduce_mask_51; \ + t[3] += t[2] >> 51; t[2] &= reduce_mask_51; \ + t[4] += t[3] >> 51; t[3] &= reduce_mask_51; + + #define curve25519_contract_carry_full() curve25519_contract_carry() \ + t[0] += 19 * (t[4] >> 51); t[4] &= reduce_mask_51; + + #define curve25519_contract_carry_final() curve25519_contract_carry() \ + t[4] &= reduce_mask_51; + + curve25519_contract_carry_full() + curve25519_contract_carry_full() + + /* now t is between 0 and 2^255-1, properly carried. */ + /* case 1: between 0 and 2^255-20. case 2: between 2^255-19 and 2^255-1. */ + t[0] += 19; + curve25519_contract_carry_full() + + /* now between 19 and 2^255-1 in both cases, and offset by 19. */ + t[0] += (reduce_mask_51 + 1) - 19; + t[1] += (reduce_mask_51 + 1) - 1; + t[2] += (reduce_mask_51 + 1) - 1; + t[3] += (reduce_mask_51 + 1) - 1; + t[4] += (reduce_mask_51 + 1) - 1; + + /* now between 2^255 and 2^256-20, and offset by 2^255. */ + curve25519_contract_carry_final() + + #define write51full(n,shift) \ + f = ((t[n] >> shift) | (t[n+1] << (51 - shift))); \ + for (i = 0; i < 8; i++, f >>= 8) *out++ = (unsigned char)f; + #define write51(n) write51full(n,13*n) + write51(0) + write51(1) + write51(2) + write51(3) +} + +#if !defined(ED25519_GCC_64BIT_CHOOSE) + +/* out = (flag) ? in : out */ +DONNA_INLINE static void +curve25519_move_conditional_bytes(uint8_t out[96], const uint8_t in[96], uint64_t flag) { + const uint64_t nb = flag - 1, b = ~nb; + const uint64_t *inq = (const uint64_t *)in; + uint64_t *outq = (uint64_t *)out; + outq[0] = (outq[0] & nb) | (inq[0] & b); + outq[1] = (outq[1] & nb) | (inq[1] & b); + outq[2] = (outq[2] & nb) | (inq[2] & b); + outq[3] = (outq[3] & nb) | (inq[3] & b); + outq[4] = (outq[4] & nb) | (inq[4] & b); + outq[5] = (outq[5] & nb) | (inq[5] & b); + outq[6] = (outq[6] & nb) | (inq[6] & b); + outq[7] = (outq[7] & nb) | (inq[7] & b); + outq[8] = (outq[8] & nb) | (inq[8] & b); + outq[9] = (outq[9] & nb) | (inq[9] & b); + outq[10] = (outq[10] & nb) | (inq[10] & b); + outq[11] = (outq[11] & nb) | (inq[11] & b); +} + +/* if (iswap) swap(a, b) */ +DONNA_INLINE static void +curve25519_swap_conditional(bignum25519 a, bignum25519 b, uint64_t iswap) { + const uint64_t swap = (uint64_t)(-(int64_t)iswap); + uint64_t x0,x1,x2,x3,x4; + + x0 = swap & (a[0] ^ b[0]); a[0] ^= x0; b[0] ^= x0; + x1 = swap & (a[1] ^ b[1]); a[1] ^= x1; b[1] ^= x1; + x2 = swap & (a[2] ^ b[2]); a[2] ^= x2; b[2] ^= x2; + x3 = swap & (a[3] ^ b[3]); a[3] ^= x3; b[3] ^= x3; + x4 = swap & (a[4] ^ b[4]); a[4] ^= x4; b[4] ^= x4; +} + +#endif /* ED25519_GCC_64BIT_CHOOSE */ + +#define ED25519_64BIT_TABLES + diff --git a/ed25519-donna/curve25519-donna-helpers.h b/ed25519-donna/curve25519-donna-helpers.h new file mode 100644 index 000000000..e4058ff5e --- /dev/null +++ b/ed25519-donna/curve25519-donna-helpers.h @@ -0,0 +1,67 @@ +/* + Public domain by Andrew M. + See: https://github.com/floodyberry/curve25519-donna + + Curve25519 implementation agnostic helpers +*/ + +/* + * In: b = 2^5 - 2^0 + * Out: b = 2^250 - 2^0 + */ +static void +curve25519_pow_two5mtwo0_two250mtwo0(bignum25519 b) { + bignum25519 ALIGN(16) t0,c; + + /* 2^5 - 2^0 */ /* b */ + /* 2^10 - 2^5 */ curve25519_square_times(t0, b, 5); + /* 2^10 - 2^0 */ curve25519_mul_noinline(b, t0, b); + /* 2^20 - 2^10 */ curve25519_square_times(t0, b, 10); + /* 2^20 - 2^0 */ curve25519_mul_noinline(c, t0, b); + /* 2^40 - 2^20 */ curve25519_square_times(t0, c, 20); + /* 2^40 - 2^0 */ curve25519_mul_noinline(t0, t0, c); + /* 2^50 - 2^10 */ curve25519_square_times(t0, t0, 10); + /* 2^50 - 2^0 */ curve25519_mul_noinline(b, t0, b); + /* 2^100 - 2^50 */ curve25519_square_times(t0, b, 50); + /* 2^100 - 2^0 */ curve25519_mul_noinline(c, t0, b); + /* 2^200 - 2^100 */ curve25519_square_times(t0, c, 100); + /* 2^200 - 2^0 */ curve25519_mul_noinline(t0, t0, c); + /* 2^250 - 2^50 */ curve25519_square_times(t0, t0, 50); + /* 2^250 - 2^0 */ curve25519_mul_noinline(b, t0, b); +} + +/* + * z^(p - 2) = z(2^255 - 21) + */ +static void +curve25519_recip(bignum25519 out, const bignum25519 z) { + bignum25519 ALIGN(16) a,t0,b; + + /* 2 */ curve25519_square_times(a, z, 1); /* a = 2 */ + /* 8 */ curve25519_square_times(t0, a, 2); + /* 9 */ curve25519_mul_noinline(b, t0, z); /* b = 9 */ + /* 11 */ curve25519_mul_noinline(a, b, a); /* a = 11 */ + /* 22 */ curve25519_square_times(t0, a, 1); + /* 2^5 - 2^0 = 31 */ curve25519_mul_noinline(b, t0, b); + /* 2^250 - 2^0 */ curve25519_pow_two5mtwo0_two250mtwo0(b); + /* 2^255 - 2^5 */ curve25519_square_times(b, b, 5); + /* 2^255 - 21 */ curve25519_mul_noinline(out, b, a); +} + +/* + * z^((p-5)/8) = z^(2^252 - 3) + */ +static void +curve25519_pow_two252m3(bignum25519 two252m3, const bignum25519 z) { + bignum25519 ALIGN(16) b,c,t0; + + /* 2 */ curve25519_square_times(c, z, 1); /* c = 2 */ + /* 8 */ curve25519_square_times(t0, c, 2); /* t0 = 8 */ + /* 9 */ curve25519_mul_noinline(b, t0, z); /* b = 9 */ + /* 11 */ curve25519_mul_noinline(c, b, c); /* c = 11 */ + /* 22 */ curve25519_square_times(t0, c, 1); + /* 2^5 - 2^0 = 31 */ curve25519_mul_noinline(b, t0, b); + /* 2^250 - 2^0 */ curve25519_pow_two5mtwo0_two250mtwo0(b); + /* 2^252 - 2^2 */ curve25519_square_times(b, b, 2); + /* 2^252 - 3 */ curve25519_mul_noinline(two252m3, b, z); +} diff --git a/ed25519-donna/curve25519-donna-sse2.h b/ed25519-donna/curve25519-donna-sse2.h new file mode 100644 index 000000000..1dbfd44d8 --- /dev/null +++ b/ed25519-donna/curve25519-donna-sse2.h @@ -0,0 +1,1112 @@ +/* + Public domain by Andrew M. + See: https://github.com/floodyberry/curve25519-donna + + SSE2 curve25519 implementation +*/ + +#include +typedef __m128i xmmi; + +typedef union packedelem8_t { + unsigned char u[16]; + xmmi v; +} packedelem8; + +typedef union packedelem32_t { + uint32_t u[4]; + xmmi v; +} packedelem32; + +typedef union packedelem64_t { + uint64_t u[2]; + xmmi v; +} packedelem64; + +/* 10 elements + an extra 2 to fit in 3 xmm registers */ +typedef uint32_t bignum25519[12]; +typedef packedelem32 packed32bignum25519[5]; +typedef packedelem64 packed64bignum25519[10]; + +static const packedelem32 bot32bitmask = {{0xffffffff, 0x00000000, 0xffffffff, 0x00000000}}; +static const packedelem32 top32bitmask = {{0x00000000, 0xffffffff, 0x00000000, 0xffffffff}}; +static const packedelem32 top64bitmask = {{0x00000000, 0x00000000, 0xffffffff, 0xffffffff}}; +static const packedelem32 bot64bitmask = {{0xffffffff, 0xffffffff, 0x00000000, 0x00000000}}; + +/* reduction masks */ +static const packedelem64 packedmask26 = {{0x03ffffff, 0x03ffffff}}; +static const packedelem64 packedmask25 = {{0x01ffffff, 0x01ffffff}}; +static const packedelem32 packedmask2625 = {{0x3ffffff,0,0x1ffffff,0}}; +static const packedelem32 packedmask26262626 = {{0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff}}; +static const packedelem32 packedmask25252525 = {{0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff}}; + +/* multipliers */ +static const packedelem64 packednineteen = {{19, 19}}; +static const packedelem64 packednineteenone = {{19, 1}}; +static const packedelem64 packedthirtyeight = {{38, 38}}; +static const packedelem64 packed3819 = {{19*2,19}}; +static const packedelem64 packed9638 = {{19*4,19*2}}; + +/* 121666,121665 */ +static const packedelem64 packed121666121665 = {{121666, 121665}}; + +/* 2*(2^255 - 19) = 0 mod p */ +static const packedelem32 packed2p0 = {{0x7ffffda,0x3fffffe,0x7fffffe,0x3fffffe}}; +static const packedelem32 packed2p1 = {{0x7fffffe,0x3fffffe,0x7fffffe,0x3fffffe}}; +static const packedelem32 packed2p2 = {{0x7fffffe,0x3fffffe,0x0000000,0x0000000}}; + +static const packedelem32 packed32packed2p0 = {{0x7ffffda,0x7ffffda,0x3fffffe,0x3fffffe}}; +static const packedelem32 packed32packed2p1 = {{0x7fffffe,0x7fffffe,0x3fffffe,0x3fffffe}}; + +/* 4*(2^255 - 19) = 0 mod p */ +static const packedelem32 packed4p0 = {{0xfffffb4,0x7fffffc,0xffffffc,0x7fffffc}}; +static const packedelem32 packed4p1 = {{0xffffffc,0x7fffffc,0xffffffc,0x7fffffc}}; +static const packedelem32 packed4p2 = {{0xffffffc,0x7fffffc,0x0000000,0x0000000}}; + +static const packedelem32 packed32packed4p0 = {{0xfffffb4,0xfffffb4,0x7fffffc,0x7fffffc}}; +static const packedelem32 packed32packed4p1 = {{0xffffffc,0xffffffc,0x7fffffc,0x7fffffc}}; + +/* out = in */ +DONNA_INLINE static void +curve25519_copy(bignum25519 out, const bignum25519 in) { + xmmi x0,x1,x2; + x0 = _mm_load_si128((xmmi*)in + 0); + x1 = _mm_load_si128((xmmi*)in + 1); + x2 = _mm_load_si128((xmmi*)in + 2); + _mm_store_si128((xmmi*)out + 0, x0); + _mm_store_si128((xmmi*)out + 1, x1); + _mm_store_si128((xmmi*)out + 2, x2); +} + +/* out = a + b */ +DONNA_INLINE static void +curve25519_add(bignum25519 out, const bignum25519 a, const bignum25519 b) { + xmmi a0,a1,a2,b0,b1,b2; + a0 = _mm_load_si128((xmmi*)a + 0); + a1 = _mm_load_si128((xmmi*)a + 1); + a2 = _mm_load_si128((xmmi*)a + 2); + b0 = _mm_load_si128((xmmi*)b + 0); + b1 = _mm_load_si128((xmmi*)b + 1); + b2 = _mm_load_si128((xmmi*)b + 2); + a0 = _mm_add_epi32(a0, b0); + a1 = _mm_add_epi32(a1, b1); + a2 = _mm_add_epi32(a2, b2); + _mm_store_si128((xmmi*)out + 0, a0); + _mm_store_si128((xmmi*)out + 1, a1); + _mm_store_si128((xmmi*)out + 2, a2); +} + +#define curve25519_add_after_basic curve25519_add_reduce +DONNA_INLINE static void +curve25519_add_reduce(bignum25519 out, const bignum25519 a, const bignum25519 b) { + xmmi a0,a1,a2,b0,b1,b2; + xmmi c1,c2,c3; + xmmi r0,r1,r2,r3,r4,r5; + + a0 = _mm_load_si128((xmmi*)a + 0); + a1 = _mm_load_si128((xmmi*)a + 1); + a2 = _mm_load_si128((xmmi*)a + 2); + b0 = _mm_load_si128((xmmi*)b + 0); + b1 = _mm_load_si128((xmmi*)b + 1); + b2 = _mm_load_si128((xmmi*)b + 2); + a0 = _mm_add_epi32(a0, b0); + a1 = _mm_add_epi32(a1, b1); + a2 = _mm_add_epi32(a2, b2); + + r0 = _mm_and_si128(_mm_unpacklo_epi64(a0, a1), bot32bitmask.v); + r1 = _mm_srli_epi64(_mm_unpacklo_epi64(a0, a1), 32); + r2 = _mm_and_si128(_mm_unpackhi_epi64(a0, a1), bot32bitmask.v); + r3 = _mm_srli_epi64(_mm_unpackhi_epi64(a0, a1), 32); + r4 = _mm_and_si128(_mm_unpacklo_epi64(_mm_setzero_si128(), a2), bot32bitmask.v); + r5 = _mm_srli_epi64(_mm_unpacklo_epi64(_mm_setzero_si128(), a2), 32); + + c1 = _mm_srli_epi64(r0, 26); c2 = _mm_srli_epi64(r2, 26); r0 = _mm_and_si128(r0, packedmask26.v); r2 = _mm_and_si128(r2, packedmask26.v); r1 = _mm_add_epi64(r1, c1); r3 = _mm_add_epi64(r3, c2); + c1 = _mm_srli_epi64(r1, 25); c2 = _mm_srli_epi64(r3, 25); r1 = _mm_and_si128(r1, packedmask25.v); r3 = _mm_and_si128(r3, packedmask25.v); r2 = _mm_add_epi64(r2, c1); r4 = _mm_add_epi64(r4, c2); c3 = _mm_slli_si128(c2, 8); + c1 = _mm_srli_epi64(r4, 26); r4 = _mm_and_si128(r4, packedmask26.v); r5 = _mm_add_epi64(r5, c1); + c1 = _mm_srli_epi64(r5, 25); r5 = _mm_and_si128(r5, packedmask25.v); r0 = _mm_add_epi64(r0, _mm_unpackhi_epi64(_mm_mul_epu32(c1, packednineteen.v), c3)); + c1 = _mm_srli_epi64(r0, 26); c2 = _mm_srli_epi64(r2, 26); r0 = _mm_and_si128(r0, packedmask26.v); r2 = _mm_and_si128(r2, packedmask26.v); r1 = _mm_add_epi64(r1, c1); r3 = _mm_add_epi64(r3, c2); + + _mm_store_si128((xmmi*)out + 0, _mm_unpacklo_epi64(_mm_unpacklo_epi32(r0, r1), _mm_unpacklo_epi32(r2, r3))); + _mm_store_si128((xmmi*)out + 1, _mm_unpacklo_epi64(_mm_unpackhi_epi32(r0, r1), _mm_unpackhi_epi32(r2, r3))); + _mm_store_si128((xmmi*)out + 2, _mm_unpackhi_epi32(r4, r5)); +} + +DONNA_INLINE static void +curve25519_sub(bignum25519 out, const bignum25519 a, const bignum25519 b) { + xmmi a0,a1,a2,b0,b1,b2; + xmmi c1,c2; + xmmi r0,r1; + + a0 = _mm_load_si128((xmmi*)a + 0); + a1 = _mm_load_si128((xmmi*)a + 1); + a2 = _mm_load_si128((xmmi*)a + 2); + a0 = _mm_add_epi32(a0, packed2p0.v); + a1 = _mm_add_epi32(a1, packed2p1.v); + a2 = _mm_add_epi32(a2, packed2p2.v); + b0 = _mm_load_si128((xmmi*)b + 0); + b1 = _mm_load_si128((xmmi*)b + 1); + b2 = _mm_load_si128((xmmi*)b + 2); + a0 = _mm_sub_epi32(a0, b0); + a1 = _mm_sub_epi32(a1, b1); + a2 = _mm_sub_epi32(a2, b2); + + r0 = _mm_and_si128(_mm_shuffle_epi32(a0, _MM_SHUFFLE(2,2,0,0)), bot32bitmask.v); + r1 = _mm_and_si128(_mm_shuffle_epi32(a0, _MM_SHUFFLE(3,3,1,1)), bot32bitmask.v); + + c1 = _mm_srli_epi32(r0, 26); + c2 = _mm_srli_epi32(r1, 25); + r0 = _mm_and_si128(r0, packedmask26.v); + r1 = _mm_and_si128(r1, packedmask25.v); + r0 = _mm_add_epi32(r0, _mm_slli_si128(c2, 8)); + r1 = _mm_add_epi32(r1, c1); + + a0 = _mm_unpacklo_epi64(_mm_unpacklo_epi32(r0, r1), _mm_unpackhi_epi32(r0, r1)); + a1 = _mm_add_epi32(a1, _mm_srli_si128(c2, 8)); + + _mm_store_si128((xmmi*)out + 0, a0); + _mm_store_si128((xmmi*)out + 1, a1); + _mm_store_si128((xmmi*)out + 2, a2); +} + +DONNA_INLINE static void +curve25519_sub_after_basic(bignum25519 out, const bignum25519 a, const bignum25519 b) { + xmmi a0,a1,a2,b0,b1,b2; + xmmi c1,c2,c3; + xmmi r0,r1,r2,r3,r4,r5; + + a0 = _mm_load_si128((xmmi*)a + 0); + a1 = _mm_load_si128((xmmi*)a + 1); + a2 = _mm_load_si128((xmmi*)a + 2); + a0 = _mm_add_epi32(a0, packed4p0.v); + a1 = _mm_add_epi32(a1, packed4p1.v); + a2 = _mm_add_epi32(a2, packed4p2.v); + b0 = _mm_load_si128((xmmi*)b + 0); + b1 = _mm_load_si128((xmmi*)b + 1); + b2 = _mm_load_si128((xmmi*)b + 2); + a0 = _mm_sub_epi32(a0, b0); + a1 = _mm_sub_epi32(a1, b1); + a2 = _mm_sub_epi32(a2, b2); + + r0 = _mm_and_si128(_mm_unpacklo_epi64(a0, a1), bot32bitmask.v); + r1 = _mm_srli_epi64(_mm_unpacklo_epi64(a0, a1), 32); + r2 = _mm_and_si128(_mm_unpackhi_epi64(a0, a1), bot32bitmask.v); + r3 = _mm_srli_epi64(_mm_unpackhi_epi64(a0, a1), 32); + r4 = _mm_and_si128(_mm_unpacklo_epi64(_mm_setzero_si128(), a2), bot32bitmask.v); + r5 = _mm_srli_epi64(_mm_unpacklo_epi64(_mm_setzero_si128(), a2), 32); + + c1 = _mm_srli_epi64(r0, 26); c2 = _mm_srli_epi64(r2, 26); r0 = _mm_and_si128(r0, packedmask26.v); r2 = _mm_and_si128(r2, packedmask26.v); r1 = _mm_add_epi64(r1, c1); r3 = _mm_add_epi64(r3, c2); + c1 = _mm_srli_epi64(r1, 25); c2 = _mm_srli_epi64(r3, 25); r1 = _mm_and_si128(r1, packedmask25.v); r3 = _mm_and_si128(r3, packedmask25.v); r2 = _mm_add_epi64(r2, c1); r4 = _mm_add_epi64(r4, c2); c3 = _mm_slli_si128(c2, 8); + c1 = _mm_srli_epi64(r4, 26); r4 = _mm_and_si128(r4, packedmask26.v); r5 = _mm_add_epi64(r5, c1); + c1 = _mm_srli_epi64(r5, 25); r5 = _mm_and_si128(r5, packedmask25.v); r0 = _mm_add_epi64(r0, _mm_unpackhi_epi64(_mm_mul_epu32(c1, packednineteen.v), c3)); + c1 = _mm_srli_epi64(r0, 26); c2 = _mm_srli_epi64(r2, 26); r0 = _mm_and_si128(r0, packedmask26.v); r2 = _mm_and_si128(r2, packedmask26.v); r1 = _mm_add_epi64(r1, c1); r3 = _mm_add_epi64(r3, c2); + + _mm_store_si128((xmmi*)out + 0, _mm_unpacklo_epi64(_mm_unpacklo_epi32(r0, r1), _mm_unpacklo_epi32(r2, r3))); + _mm_store_si128((xmmi*)out + 1, _mm_unpacklo_epi64(_mm_unpackhi_epi32(r0, r1), _mm_unpackhi_epi32(r2, r3))); + _mm_store_si128((xmmi*)out + 2, _mm_unpackhi_epi32(r4, r5)); +} + +DONNA_INLINE static void +curve25519_sub_reduce(bignum25519 out, const bignum25519 a, const bignum25519 b) { + xmmi a0,a1,a2,b0,b1,b2; + xmmi c1,c2,c3; + xmmi r0,r1,r2,r3,r4,r5; + + a0 = _mm_load_si128((xmmi*)a + 0); + a1 = _mm_load_si128((xmmi*)a + 1); + a2 = _mm_load_si128((xmmi*)a + 2); + a0 = _mm_add_epi32(a0, packed2p0.v); + a1 = _mm_add_epi32(a1, packed2p1.v); + a2 = _mm_add_epi32(a2, packed2p2.v); + b0 = _mm_load_si128((xmmi*)b + 0); + b1 = _mm_load_si128((xmmi*)b + 1); + b2 = _mm_load_si128((xmmi*)b + 2); + a0 = _mm_sub_epi32(a0, b0); + a1 = _mm_sub_epi32(a1, b1); + a2 = _mm_sub_epi32(a2, b2); + + r0 = _mm_and_si128(_mm_unpacklo_epi64(a0, a1), bot32bitmask.v); + r1 = _mm_srli_epi64(_mm_unpacklo_epi64(a0, a1), 32); + r2 = _mm_and_si128(_mm_unpackhi_epi64(a0, a1), bot32bitmask.v); + r3 = _mm_srli_epi64(_mm_unpackhi_epi64(a0, a1), 32); + r4 = _mm_and_si128(_mm_unpacklo_epi64(_mm_setzero_si128(), a2), bot32bitmask.v); + r5 = _mm_srli_epi64(_mm_unpacklo_epi64(_mm_setzero_si128(), a2), 32); + + c1 = _mm_srli_epi64(r0, 26); c2 = _mm_srli_epi64(r2, 26); r0 = _mm_and_si128(r0, packedmask26.v); r2 = _mm_and_si128(r2, packedmask26.v); r1 = _mm_add_epi64(r1, c1); r3 = _mm_add_epi64(r3, c2); + c1 = _mm_srli_epi64(r1, 25); c2 = _mm_srli_epi64(r3, 25); r1 = _mm_and_si128(r1, packedmask25.v); r3 = _mm_and_si128(r3, packedmask25.v); r2 = _mm_add_epi64(r2, c1); r4 = _mm_add_epi64(r4, c2); c3 = _mm_slli_si128(c2, 8); + c1 = _mm_srli_epi64(r4, 26); r4 = _mm_and_si128(r4, packedmask26.v); r5 = _mm_add_epi64(r5, c1); + c1 = _mm_srli_epi64(r5, 25); r5 = _mm_and_si128(r5, packedmask25.v); r0 = _mm_add_epi64(r0, _mm_unpackhi_epi64(_mm_mul_epu32(c1, packednineteen.v), c3)); + c1 = _mm_srli_epi64(r0, 26); c2 = _mm_srli_epi64(r2, 26); r0 = _mm_and_si128(r0, packedmask26.v); r2 = _mm_and_si128(r2, packedmask26.v); r1 = _mm_add_epi64(r1, c1); r3 = _mm_add_epi64(r3, c2); + + _mm_store_si128((xmmi*)out + 0, _mm_unpacklo_epi64(_mm_unpacklo_epi32(r0, r1), _mm_unpacklo_epi32(r2, r3))); + _mm_store_si128((xmmi*)out + 1, _mm_unpacklo_epi64(_mm_unpackhi_epi32(r0, r1), _mm_unpackhi_epi32(r2, r3))); + _mm_store_si128((xmmi*)out + 2, _mm_unpackhi_epi32(r4, r5)); +} + + +DONNA_INLINE static void +curve25519_neg(bignum25519 out, const bignum25519 b) { + xmmi a0,a1,a2,b0,b1,b2; + xmmi c1,c2,c3; + xmmi r0,r1,r2,r3,r4,r5; + + a0 = packed2p0.v; + a1 = packed2p1.v; + a2 = packed2p2.v; + b0 = _mm_load_si128((xmmi*)b + 0); + b1 = _mm_load_si128((xmmi*)b + 1); + b2 = _mm_load_si128((xmmi*)b + 2); + a0 = _mm_sub_epi32(a0, b0); + a1 = _mm_sub_epi32(a1, b1); + a2 = _mm_sub_epi32(a2, b2); + + r0 = _mm_and_si128(_mm_unpacklo_epi64(a0, a1), bot32bitmask.v); + r1 = _mm_srli_epi64(_mm_unpacklo_epi64(a0, a1), 32); + r2 = _mm_and_si128(_mm_unpackhi_epi64(a0, a1), bot32bitmask.v); + r3 = _mm_srli_epi64(_mm_unpackhi_epi64(a0, a1), 32); + r4 = _mm_and_si128(_mm_unpacklo_epi64(_mm_setzero_si128(), a2), bot32bitmask.v); + r5 = _mm_srli_epi64(_mm_unpacklo_epi64(_mm_setzero_si128(), a2), 32); + + c1 = _mm_srli_epi64(r0, 26); c2 = _mm_srli_epi64(r2, 26); r0 = _mm_and_si128(r0, packedmask26.v); r2 = _mm_and_si128(r2, packedmask26.v); r1 = _mm_add_epi64(r1, c1); r3 = _mm_add_epi64(r3, c2); + c1 = _mm_srli_epi64(r1, 25); c2 = _mm_srli_epi64(r3, 25); r1 = _mm_and_si128(r1, packedmask25.v); r3 = _mm_and_si128(r3, packedmask25.v); r2 = _mm_add_epi64(r2, c1); r4 = _mm_add_epi64(r4, c2); c3 = _mm_slli_si128(c2, 8); + c1 = _mm_srli_epi64(r4, 26); r4 = _mm_and_si128(r4, packedmask26.v); r5 = _mm_add_epi64(r5, c1); + c1 = _mm_srli_epi64(r5, 25); r5 = _mm_and_si128(r5, packedmask25.v); r0 = _mm_add_epi64(r0, _mm_unpackhi_epi64(_mm_mul_epu32(c1, packednineteen.v), c3)); + c1 = _mm_srli_epi64(r0, 26); c2 = _mm_srli_epi64(r2, 26); r0 = _mm_and_si128(r0, packedmask26.v); r2 = _mm_and_si128(r2, packedmask26.v); r1 = _mm_add_epi64(r1, c1); r3 = _mm_add_epi64(r3, c2); + + _mm_store_si128((xmmi*)out + 0, _mm_unpacklo_epi64(_mm_unpacklo_epi32(r0, r1), _mm_unpacklo_epi32(r2, r3))); + _mm_store_si128((xmmi*)out + 1, _mm_unpacklo_epi64(_mm_unpackhi_epi32(r0, r1), _mm_unpackhi_epi32(r2, r3))); + _mm_store_si128((xmmi*)out + 2, _mm_unpackhi_epi32(r4, r5)); +} + + +/* Multiply two numbers: out = in2 * in */ +static void +curve25519_mul(bignum25519 out, const bignum25519 r, const bignum25519 s) { + xmmi m01,m23,m45,m67,m89; + xmmi m0123,m4567; + xmmi s0123,s4567; + xmmi s01,s23,s45,s67,s89; + xmmi s12,s34,s56,s78,s9; + xmmi r0,r2,r4,r6,r8; + xmmi r1,r3,r5,r7,r9; + xmmi r119,r219,r319,r419,r519,r619,r719,r819,r919; + xmmi c1,c2,c3; + + s0123 = _mm_load_si128((xmmi*)s + 0); + s01 = _mm_shuffle_epi32(s0123,_MM_SHUFFLE(3,1,2,0)); + s12 = _mm_shuffle_epi32(s0123, _MM_SHUFFLE(2,2,1,1)); + s23 = _mm_shuffle_epi32(s0123,_MM_SHUFFLE(3,3,2,2)); + s4567 = _mm_load_si128((xmmi*)s + 1); + s34 = _mm_unpacklo_epi64(_mm_srli_si128(s0123,12),s4567); + s45 = _mm_shuffle_epi32(s4567,_MM_SHUFFLE(3,1,2,0)); + s56 = _mm_shuffle_epi32(s4567, _MM_SHUFFLE(2,2,1,1)); + s67 = _mm_shuffle_epi32(s4567,_MM_SHUFFLE(3,3,2,2)); + s89 = _mm_load_si128((xmmi*)s + 2); + s78 = _mm_unpacklo_epi64(_mm_srli_si128(s4567,12),s89); + s89 = _mm_shuffle_epi32(s89,_MM_SHUFFLE(3,1,2,0)); + s9 = _mm_shuffle_epi32(s89, _MM_SHUFFLE(3,3,2,2)); + + r0 = _mm_load_si128((xmmi*)r + 0); + r1 = _mm_shuffle_epi32(r0, _MM_SHUFFLE(1,1,1,1)); + r1 = _mm_add_epi64(r1, _mm_and_si128(r1, top64bitmask.v)); + r2 = _mm_shuffle_epi32(r0, _MM_SHUFFLE(2,2,2,2)); + r3 = _mm_shuffle_epi32(r0, _MM_SHUFFLE(3,3,3,3)); + r3 = _mm_add_epi64(r3, _mm_and_si128(r3, top64bitmask.v)); + r0 = _mm_shuffle_epi32(r0, _MM_SHUFFLE(0,0,0,0)); + r4 = _mm_load_si128((xmmi*)r + 1); + r5 = _mm_shuffle_epi32(r4, _MM_SHUFFLE(1,1,1,1)); + r5 = _mm_add_epi64(r5, _mm_and_si128(r5, top64bitmask.v)); + r6 = _mm_shuffle_epi32(r4, _MM_SHUFFLE(2,2,2,2)); + r7 = _mm_shuffle_epi32(r4, _MM_SHUFFLE(3,3,3,3)); + r7 = _mm_add_epi64(r7, _mm_and_si128(r7, top64bitmask.v)); + r4 = _mm_shuffle_epi32(r4, _MM_SHUFFLE(0,0,0,0)); + r8 = _mm_load_si128((xmmi*)r + 2); + r9 = _mm_shuffle_epi32(r8, _MM_SHUFFLE(3,1,3,1)); + r9 = _mm_add_epi64(r9, _mm_and_si128(r9, top64bitmask.v)); + r8 = _mm_shuffle_epi32(r8, _MM_SHUFFLE(3,0,3,0)); + + m01 = _mm_mul_epu32(r1,s01); + m23 = _mm_mul_epu32(r1,s23); + m45 = _mm_mul_epu32(r1,s45); + m67 = _mm_mul_epu32(r1,s67); + m23 = _mm_add_epi64(m23,_mm_mul_epu32(r3,s01)); + m45 = _mm_add_epi64(m45,_mm_mul_epu32(r3,s23)); + m67 = _mm_add_epi64(m67,_mm_mul_epu32(r3,s45)); + m89 = _mm_mul_epu32(r1,s89); + m45 = _mm_add_epi64(m45,_mm_mul_epu32(r5,s01)); + m67 = _mm_add_epi64(m67,_mm_mul_epu32(r5,s23)); + m89 = _mm_add_epi64(m89,_mm_mul_epu32(r3,s67)); + m67 = _mm_add_epi64(m67,_mm_mul_epu32(r7,s01)); + m89 = _mm_add_epi64(m89,_mm_mul_epu32(r5,s45)); + m89 = _mm_add_epi64(m89,_mm_mul_epu32(r7,s23)); + m89 = _mm_add_epi64(m89,_mm_mul_epu32(r9,s01)); + + /* shift up */ + m89 = _mm_unpackhi_epi64(m67,_mm_slli_si128(m89,8)); + m67 = _mm_unpackhi_epi64(m45,_mm_slli_si128(m67,8)); + m45 = _mm_unpackhi_epi64(m23,_mm_slli_si128(m45,8)); + m23 = _mm_unpackhi_epi64(m01,_mm_slli_si128(m23,8)); + m01 = _mm_unpackhi_epi64(_mm_setzero_si128(),_mm_slli_si128(m01,8)); + + m01 = _mm_add_epi64(m01,_mm_mul_epu32(r0,s01)); + m23 = _mm_add_epi64(m23,_mm_mul_epu32(r0,s23)); + m45 = _mm_add_epi64(m45,_mm_mul_epu32(r0,s45)); + m67 = _mm_add_epi64(m67,_mm_mul_epu32(r0,s67)); + m23 = _mm_add_epi64(m23,_mm_mul_epu32(r2,s01)); + m45 = _mm_add_epi64(m45,_mm_mul_epu32(r2,s23)); + m67 = _mm_add_epi64(m67,_mm_mul_epu32(r4,s23)); + m89 = _mm_add_epi64(m89,_mm_mul_epu32(r0,s89)); + m45 = _mm_add_epi64(m45,_mm_mul_epu32(r4,s01)); + m67 = _mm_add_epi64(m67,_mm_mul_epu32(r2,s45)); + m89 = _mm_add_epi64(m89,_mm_mul_epu32(r2,s67)); + m67 = _mm_add_epi64(m67,_mm_mul_epu32(r6,s01)); + m89 = _mm_add_epi64(m89,_mm_mul_epu32(r4,s45)); + m89 = _mm_add_epi64(m89,_mm_mul_epu32(r6,s23)); + m89 = _mm_add_epi64(m89,_mm_mul_epu32(r8,s01)); + + r219 = _mm_mul_epu32(r2, packednineteen.v); + r419 = _mm_mul_epu32(r4, packednineteen.v); + r619 = _mm_mul_epu32(r6, packednineteen.v); + r819 = _mm_mul_epu32(r8, packednineteen.v); + r119 = _mm_shuffle_epi32(r1,_MM_SHUFFLE(0,0,2,2)); r119 = _mm_mul_epu32(r119, packednineteen.v); + r319 = _mm_shuffle_epi32(r3,_MM_SHUFFLE(0,0,2,2)); r319 = _mm_mul_epu32(r319, packednineteen.v); + r519 = _mm_shuffle_epi32(r5,_MM_SHUFFLE(0,0,2,2)); r519 = _mm_mul_epu32(r519, packednineteen.v); + r719 = _mm_shuffle_epi32(r7,_MM_SHUFFLE(0,0,2,2)); r719 = _mm_mul_epu32(r719, packednineteen.v); + r919 = _mm_shuffle_epi32(r9,_MM_SHUFFLE(0,0,2,2)); r919 = _mm_mul_epu32(r919, packednineteen.v); + + m01 = _mm_add_epi64(m01,_mm_mul_epu32(r919,s12)); + m23 = _mm_add_epi64(m23,_mm_mul_epu32(r919,s34)); + m45 = _mm_add_epi64(m45,_mm_mul_epu32(r919,s56)); + m67 = _mm_add_epi64(m67,_mm_mul_epu32(r919,s78)); + m01 = _mm_add_epi64(m01,_mm_mul_epu32(r719,s34)); + m23 = _mm_add_epi64(m23,_mm_mul_epu32(r719,s56)); + m45 = _mm_add_epi64(m45,_mm_mul_epu32(r719,s78)); + m67 = _mm_add_epi64(m67,_mm_mul_epu32(r719,s9)); + m01 = _mm_add_epi64(m01,_mm_mul_epu32(r519,s56)); + m23 = _mm_add_epi64(m23,_mm_mul_epu32(r519,s78)); + m45 = _mm_add_epi64(m45,_mm_mul_epu32(r519,s9)); + m67 = _mm_add_epi64(m67,_mm_mul_epu32(r819,s89)); + m01 = _mm_add_epi64(m01,_mm_mul_epu32(r319,s78)); + m23 = _mm_add_epi64(m23,_mm_mul_epu32(r319,s9)); + m45 = _mm_add_epi64(m45,_mm_mul_epu32(r619,s89)); + m89 = _mm_add_epi64(m89,_mm_mul_epu32(r919,s9)); + m01 = _mm_add_epi64(m01,_mm_mul_epu32(r819,s23)); + m23 = _mm_add_epi64(m23,_mm_mul_epu32(r819,s45)); + m45 = _mm_add_epi64(m45,_mm_mul_epu32(r819,s67)); + m01 = _mm_add_epi64(m01,_mm_mul_epu32(r619,s45)); + m23 = _mm_add_epi64(m23,_mm_mul_epu32(r619,s67)); + m01 = _mm_add_epi64(m01,_mm_mul_epu32(r419,s67)); + m23 = _mm_add_epi64(m23,_mm_mul_epu32(r419,s89)); + m01 = _mm_add_epi64(m01,_mm_mul_epu32(r219,s89)); + m01 = _mm_add_epi64(m01,_mm_mul_epu32(r119,s9)); + + r0 = _mm_unpacklo_epi64(m01, m45); + r1 = _mm_unpackhi_epi64(m01, m45); + r2 = _mm_unpacklo_epi64(m23, m67); + r3 = _mm_unpackhi_epi64(m23, m67); + r4 = _mm_unpacklo_epi64(m89, m89); + r5 = _mm_unpackhi_epi64(m89, m89); + + c1 = _mm_srli_epi64(r0, 26); c2 = _mm_srli_epi64(r2, 26); r0 = _mm_and_si128(r0, packedmask26.v); r2 = _mm_and_si128(r2, packedmask26.v); r1 = _mm_add_epi64(r1, c1); r3 = _mm_add_epi64(r3, c2); + c1 = _mm_srli_epi64(r1, 25); c2 = _mm_srli_epi64(r3, 25); r1 = _mm_and_si128(r1, packedmask25.v); r3 = _mm_and_si128(r3, packedmask25.v); r2 = _mm_add_epi64(r2, c1); r4 = _mm_add_epi64(r4, c2); c3 = _mm_slli_si128(c2, 8); + c1 = _mm_srli_epi64(r4, 26); r4 = _mm_and_si128(r4, packedmask26.v); r5 = _mm_add_epi64(r5, c1); + c1 = _mm_srli_epi64(r5, 25); r5 = _mm_and_si128(r5, packedmask25.v); r0 = _mm_add_epi64(r0, _mm_unpackhi_epi64(_mm_mul_epu32(c1, packednineteen.v), c3)); + c1 = _mm_srli_epi64(r0, 26); c2 = _mm_srli_epi64(r2, 26); r0 = _mm_and_si128(r0, packedmask26.v); r2 = _mm_and_si128(r2, packedmask26.v); r1 = _mm_add_epi64(r1, c1); r3 = _mm_add_epi64(r3, c2); + + m0123 = _mm_unpacklo_epi32(r0, r1); + m4567 = _mm_unpackhi_epi32(r0, r1); + m0123 = _mm_unpacklo_epi64(m0123, _mm_unpacklo_epi32(r2, r3)); + m4567 = _mm_unpacklo_epi64(m4567, _mm_unpackhi_epi32(r2, r3)); + m89 = _mm_unpackhi_epi32(r4, r5); + + _mm_store_si128((xmmi*)out + 0, m0123); + _mm_store_si128((xmmi*)out + 1, m4567); + _mm_store_si128((xmmi*)out + 2, m89); +} + +DONNA_NOINLINE static void +curve25519_mul_noinline(bignum25519 out, const bignum25519 r, const bignum25519 s) { + curve25519_mul(out, r, s); +} + +#define curve25519_square(r, n) curve25519_square_times(r, n, 1) +static void +curve25519_square_times(bignum25519 r, const bignum25519 in, int count) { + xmmi m01,m23,m45,m67,m89; + xmmi r0,r1,r2,r3,r4,r5,r6,r7,r8,r9; + xmmi r0a,r1a,r2a,r3a,r7a,r9a; + xmmi r0123,r4567; + xmmi r01,r23,r45,r67,r6x,r89,r8x; + xmmi r12,r34,r56,r78,r9x; + xmmi r5619; + xmmi c1,c2,c3; + + r0123 = _mm_load_si128((xmmi*)in + 0); + r01 = _mm_shuffle_epi32(r0123,_MM_SHUFFLE(3,1,2,0)); + r23 = _mm_shuffle_epi32(r0123,_MM_SHUFFLE(3,3,2,2)); + r4567 = _mm_load_si128((xmmi*)in + 1); + r45 = _mm_shuffle_epi32(r4567,_MM_SHUFFLE(3,1,2,0)); + r67 = _mm_shuffle_epi32(r4567,_MM_SHUFFLE(3,3,2,2)); + r89 = _mm_load_si128((xmmi*)in + 2); + r89 = _mm_shuffle_epi32(r89,_MM_SHUFFLE(3,1,2,0)); + + do { + r12 = _mm_unpackhi_epi64(r01, _mm_slli_si128(r23, 8)); + r0 = _mm_shuffle_epi32(r01, _MM_SHUFFLE(0,0,0,0)); + r0 = _mm_add_epi64(r0, _mm_and_si128(r0, top64bitmask.v)); + r0a = _mm_shuffle_epi32(r0,_MM_SHUFFLE(3,2,1,2)); + r1 = _mm_shuffle_epi32(r01, _MM_SHUFFLE(2,2,2,2)); + r2 = _mm_shuffle_epi32(r23, _MM_SHUFFLE(0,0,0,0)); + r2 = _mm_add_epi64(r2, _mm_and_si128(r2, top64bitmask.v)); + r2a = _mm_shuffle_epi32(r2,_MM_SHUFFLE(3,2,1,2)); + r3 = _mm_shuffle_epi32(r23, _MM_SHUFFLE(2,2,2,2)); + r34 = _mm_unpackhi_epi64(r23, _mm_slli_si128(r45, 8)); + r4 = _mm_shuffle_epi32(r45, _MM_SHUFFLE(0,0,0,0)); + r4 = _mm_add_epi64(r4, _mm_and_si128(r4, top64bitmask.v)); + r56 = _mm_unpackhi_epi64(r45, _mm_slli_si128(r67, 8)); + r5619 = _mm_mul_epu32(r56, packednineteen.v); + r5 = _mm_shuffle_epi32(r5619, _MM_SHUFFLE(1,1,1,0)); + r6 = _mm_shuffle_epi32(r5619, _MM_SHUFFLE(3,2,3,2)); + r78 = _mm_unpackhi_epi64(r67, _mm_slli_si128(r89, 8)); + r6x = _mm_unpacklo_epi64(r67, _mm_setzero_si128()); + r7 = _mm_shuffle_epi32(r67, _MM_SHUFFLE(2,2,2,2)); + r7 = _mm_mul_epu32(r7, packed3819.v); + r7a = _mm_shuffle_epi32(r7, _MM_SHUFFLE(3,3,3,2)); + r8x = _mm_unpacklo_epi64(r89, _mm_setzero_si128()); + r8 = _mm_shuffle_epi32(r89, _MM_SHUFFLE(0,0,0,0)); + r8 = _mm_mul_epu32(r8, packednineteen.v); + r9 = _mm_shuffle_epi32(r89, _MM_SHUFFLE(2,2,2,2)); + r9x = _mm_slli_epi32(_mm_shuffle_epi32(r89, _MM_SHUFFLE(3,3,3,2)), 1); + r9 = _mm_mul_epu32(r9, packed3819.v); + r9a = _mm_shuffle_epi32(r9, _MM_SHUFFLE(2,2,2,2)); + + m01 = _mm_mul_epu32(r01, r0); + m23 = _mm_mul_epu32(r23, r0a); + m45 = _mm_mul_epu32(r45, r0a); + m45 = _mm_add_epi64(m45, _mm_mul_epu32(r23, r2)); + r23 = _mm_slli_epi32(r23, 1); + m67 = _mm_mul_epu32(r67, r0a); + m67 = _mm_add_epi64(m67, _mm_mul_epu32(r45, r2a)); + m89 = _mm_mul_epu32(r89, r0a); + m89 = _mm_add_epi64(m89, _mm_mul_epu32(r67, r2a)); + r67 = _mm_slli_epi32(r67, 1); + m89 = _mm_add_epi64(m89, _mm_mul_epu32(r45, r4)); + r45 = _mm_slli_epi32(r45, 1); + + r1 = _mm_slli_epi32(r1, 1); + r3 = _mm_slli_epi32(r3, 1); + r1a = _mm_add_epi64(r1, _mm_and_si128(r1, bot64bitmask.v)); + r3a = _mm_add_epi64(r3, _mm_and_si128(r3, bot64bitmask.v)); + + m23 = _mm_add_epi64(m23, _mm_mul_epu32(r12, r1)); + m45 = _mm_add_epi64(m45, _mm_mul_epu32(r34, r1a)); + m67 = _mm_add_epi64(m67, _mm_mul_epu32(r56, r1a)); + m67 = _mm_add_epi64(m67, _mm_mul_epu32(r34, r3)); + r34 = _mm_slli_epi32(r34, 1); + m89 = _mm_add_epi64(m89, _mm_mul_epu32(r78, r1a)); + r78 = _mm_slli_epi32(r78, 1); + m89 = _mm_add_epi64(m89, _mm_mul_epu32(r56, r3a)); + r56 = _mm_slli_epi32(r56, 1); + + m01 = _mm_add_epi64(m01, _mm_mul_epu32(_mm_slli_epi32(r12, 1), r9)); + m01 = _mm_add_epi64(m01, _mm_mul_epu32(r34, r7)); + m23 = _mm_add_epi64(m23, _mm_mul_epu32(r34, r9)); + m01 = _mm_add_epi64(m01, _mm_mul_epu32(r56, r5)); + m23 = _mm_add_epi64(m23, _mm_mul_epu32(r56, r7)); + m45 = _mm_add_epi64(m45, _mm_mul_epu32(r56, r9)); + m01 = _mm_add_epi64(m01, _mm_mul_epu32(r23, r8)); + m01 = _mm_add_epi64(m01, _mm_mul_epu32(r45, r6)); + m23 = _mm_add_epi64(m23, _mm_mul_epu32(r45, r8)); + m23 = _mm_add_epi64(m23, _mm_mul_epu32(r6x, r6)); + m45 = _mm_add_epi64(m45, _mm_mul_epu32(r78, r7a)); + m67 = _mm_add_epi64(m67, _mm_mul_epu32(r78, r9)); + m45 = _mm_add_epi64(m45, _mm_mul_epu32(r67, r8)); + m67 = _mm_add_epi64(m67, _mm_mul_epu32(r8x, r8)); + m89 = _mm_add_epi64(m89, _mm_mul_epu32(r9x, r9a)); + + r0 = _mm_unpacklo_epi64(m01, m45); + r1 = _mm_unpackhi_epi64(m01, m45); + r2 = _mm_unpacklo_epi64(m23, m67); + r3 = _mm_unpackhi_epi64(m23, m67); + r4 = _mm_unpacklo_epi64(m89, m89); + r5 = _mm_unpackhi_epi64(m89, m89); + + c1 = _mm_srli_epi64(r0, 26); c2 = _mm_srli_epi64(r2, 26); r0 = _mm_and_si128(r0, packedmask26.v); r2 = _mm_and_si128(r2, packedmask26.v); r1 = _mm_add_epi64(r1, c1); r3 = _mm_add_epi64(r3, c2); + c1 = _mm_srli_epi64(r1, 25); c2 = _mm_srli_epi64(r3, 25); r1 = _mm_and_si128(r1, packedmask25.v); r3 = _mm_and_si128(r3, packedmask25.v); r2 = _mm_add_epi64(r2, c1); r4 = _mm_add_epi64(r4, c2); c3 = _mm_slli_si128(c2, 8); + c1 = _mm_srli_epi64(r4, 26); r4 = _mm_and_si128(r4, packedmask26.v); r5 = _mm_add_epi64(r5, c1); + c1 = _mm_srli_epi64(r5, 25); r5 = _mm_and_si128(r5, packedmask25.v); r0 = _mm_add_epi64(r0, _mm_unpackhi_epi64(_mm_mul_epu32(c1, packednineteen.v), c3)); + c1 = _mm_srli_epi64(r0, 26); c2 = _mm_srli_epi64(r2, 26); r0 = _mm_and_si128(r0, packedmask26.v); r2 = _mm_and_si128(r2, packedmask26.v); r1 = _mm_add_epi64(r1, c1); r3 = _mm_add_epi64(r3, c2); + + r01 = _mm_unpacklo_epi64(r0, r1); + r45 = _mm_unpackhi_epi64(r0, r1); + r23 = _mm_unpacklo_epi64(r2, r3); + r67 = _mm_unpackhi_epi64(r2, r3); + r89 = _mm_unpackhi_epi64(r4, r5); + } while (--count); + + r0123 = _mm_shuffle_epi32(r23, _MM_SHUFFLE(2,0,3,3)); + r4567 = _mm_shuffle_epi32(r67, _MM_SHUFFLE(2,0,3,3)); + r0123 = _mm_or_si128(r0123, _mm_shuffle_epi32(r01, _MM_SHUFFLE(3,3,2,0))); + r4567 = _mm_or_si128(r4567, _mm_shuffle_epi32(r45, _MM_SHUFFLE(3,3,2,0))); + r89 = _mm_shuffle_epi32(r89, _MM_SHUFFLE(3,3,2,0)); + + _mm_store_si128((xmmi*)r + 0, r0123); + _mm_store_si128((xmmi*)r + 1, r4567); + _mm_store_si128((xmmi*)r + 2, r89); +} + +DONNA_INLINE static void +curve25519_tangle32(packedelem32 *out, const bignum25519 x, const bignum25519 z) { + xmmi x0,x1,x2,z0,z1,z2; + + x0 = _mm_load_si128((xmmi *)(x + 0)); + x1 = _mm_load_si128((xmmi *)(x + 4)); + x2 = _mm_load_si128((xmmi *)(x + 8)); + z0 = _mm_load_si128((xmmi *)(z + 0)); + z1 = _mm_load_si128((xmmi *)(z + 4)); + z2 = _mm_load_si128((xmmi *)(z + 8)); + + out[0].v = _mm_unpacklo_epi32(x0, z0); + out[1].v = _mm_unpackhi_epi32(x0, z0); + out[2].v = _mm_unpacklo_epi32(x1, z1); + out[3].v = _mm_unpackhi_epi32(x1, z1); + out[4].v = _mm_unpacklo_epi32(x2, z2); +} + +DONNA_INLINE static void +curve25519_untangle32(bignum25519 x, bignum25519 z, const packedelem32 *in) { + xmmi t0,t1,t2,t3,t4,zero; + + t0 = _mm_shuffle_epi32(in[0].v, _MM_SHUFFLE(3,1,2,0)); + t1 = _mm_shuffle_epi32(in[1].v, _MM_SHUFFLE(3,1,2,0)); + t2 = _mm_shuffle_epi32(in[2].v, _MM_SHUFFLE(3,1,2,0)); + t3 = _mm_shuffle_epi32(in[3].v, _MM_SHUFFLE(3,1,2,0)); + t4 = _mm_shuffle_epi32(in[4].v, _MM_SHUFFLE(3,1,2,0)); + zero = _mm_setzero_si128(); + _mm_store_si128((xmmi *)x + 0, _mm_unpacklo_epi64(t0, t1)); + _mm_store_si128((xmmi *)x + 1, _mm_unpacklo_epi64(t2, t3)); + _mm_store_si128((xmmi *)x + 2, _mm_unpacklo_epi64(t4, zero)); + _mm_store_si128((xmmi *)z + 0, _mm_unpackhi_epi64(t0, t1)); + _mm_store_si128((xmmi *)z + 1, _mm_unpackhi_epi64(t2, t3)); + _mm_store_si128((xmmi *)z + 2, _mm_unpackhi_epi64(t4, zero)); +} + +DONNA_INLINE static void +curve25519_add_reduce_packed32(packedelem32 *out, const packedelem32 *r, const packedelem32 *s) { + xmmi r0,r1,r2,r3,r4; + xmmi s0,s1,s2,s3,s4,s5; + xmmi c1,c2; + + r0 = _mm_add_epi32(r[0].v, s[0].v); + r1 = _mm_add_epi32(r[1].v, s[1].v); + r2 = _mm_add_epi32(r[2].v, s[2].v); + r3 = _mm_add_epi32(r[3].v, s[3].v); + r4 = _mm_add_epi32(r[4].v, s[4].v); + + s0 = _mm_unpacklo_epi64(r0, r2); /* 00 44 */ + s1 = _mm_unpackhi_epi64(r0, r2); /* 11 55 */ + s2 = _mm_unpacklo_epi64(r1, r3); /* 22 66 */ + s3 = _mm_unpackhi_epi64(r1, r3); /* 33 77 */ + s4 = _mm_unpacklo_epi64(_mm_setzero_si128(), r4); /* 00 88 */ + s5 = _mm_unpackhi_epi64(_mm_setzero_si128(), r4); /* 00 99 */ + + c1 = _mm_srli_epi32(s0, 26); c2 = _mm_srli_epi32(s2, 26); s0 = _mm_and_si128(s0, packedmask26262626.v); s2 = _mm_and_si128(s2, packedmask26262626.v); s1 = _mm_add_epi32(s1, c1); s3 = _mm_add_epi32(s3, c2); + c1 = _mm_srli_epi32(s1, 25); c2 = _mm_srli_epi32(s3, 25); s1 = _mm_and_si128(s1, packedmask25252525.v); s3 = _mm_and_si128(s3, packedmask25252525.v); s2 = _mm_add_epi32(s2, c1); s4 = _mm_add_epi32(s4, _mm_unpackhi_epi64(_mm_setzero_si128(), c2)); s0 = _mm_add_epi32(s0, _mm_unpacklo_epi64(_mm_setzero_si128(), c2)); + c1 = _mm_srli_epi32(s2, 26); c2 = _mm_srli_epi32(s4, 26); s2 = _mm_and_si128(s2, packedmask26262626.v); s4 = _mm_and_si128(s4, packedmask26262626.v); s3 = _mm_add_epi32(s3, c1); s5 = _mm_add_epi32(s5, c2); + c1 = _mm_srli_epi32(s3, 25); c2 = _mm_srli_epi32(s5, 25); s3 = _mm_and_si128(s3, packedmask25252525.v); s5 = _mm_and_si128(s5, packedmask25252525.v); s4 = _mm_add_epi32(s4, c1); s0 = _mm_add_epi32(s0, _mm_or_si128(_mm_slli_si128(c1, 8), _mm_srli_si128(_mm_add_epi32(_mm_add_epi32(_mm_slli_epi32(c2, 4), _mm_slli_epi32(c2, 1)), c2), 8))); + c1 = _mm_srli_epi32(s0, 26); c2 = _mm_srli_epi32(s2, 26); s0 = _mm_and_si128(s0, packedmask26262626.v); s2 = _mm_and_si128(s2, packedmask26262626.v); s1 = _mm_add_epi32(s1, c1); s3 = _mm_add_epi32(s3, c2); + + out[0].v = _mm_unpacklo_epi64(s0, s1); /* 00 11 */ + out[1].v = _mm_unpacklo_epi64(s2, s3); /* 22 33 */ + out[2].v = _mm_unpackhi_epi64(s0, s1); /* 44 55 */ + out[3].v = _mm_unpackhi_epi64(s2, s3); /* 66 77 */ + out[4].v = _mm_unpackhi_epi64(s4, s5); /* 88 99 */ +} + +DONNA_INLINE static void +curve25519_add_packed32(packedelem32 *out, const packedelem32 *r, const packedelem32 *s) { + out[0].v = _mm_add_epi32(r[0].v, s[0].v); + out[1].v = _mm_add_epi32(r[1].v, s[1].v); + out[2].v = _mm_add_epi32(r[2].v, s[2].v); + out[3].v = _mm_add_epi32(r[3].v, s[3].v); + out[4].v = _mm_add_epi32(r[4].v, s[4].v); +} + +DONNA_INLINE static void +curve25519_sub_packed32(packedelem32 *out, const packedelem32 *r, const packedelem32 *s) { + xmmi r0,r1,r2,r3,r4; + xmmi s0,s1,s2,s3; + xmmi c1,c2; + + r0 = _mm_add_epi32(r[0].v, packed32packed2p0.v); + r1 = _mm_add_epi32(r[1].v, packed32packed2p1.v); + r2 = _mm_add_epi32(r[2].v, packed32packed2p1.v); + r3 = _mm_add_epi32(r[3].v, packed32packed2p1.v); + r4 = _mm_add_epi32(r[4].v, packed32packed2p1.v); + r0 = _mm_sub_epi32(r0, s[0].v); /* 00 11 */ + r1 = _mm_sub_epi32(r1, s[1].v); /* 22 33 */ + r2 = _mm_sub_epi32(r2, s[2].v); /* 44 55 */ + r3 = _mm_sub_epi32(r3, s[3].v); /* 66 77 */ + r4 = _mm_sub_epi32(r4, s[4].v); /* 88 99 */ + + s0 = _mm_unpacklo_epi64(r0, r2); /* 00 44 */ + s1 = _mm_unpackhi_epi64(r0, r2); /* 11 55 */ + s2 = _mm_unpacklo_epi64(r1, r3); /* 22 66 */ + s3 = _mm_unpackhi_epi64(r1, r3); /* 33 77 */ + + c1 = _mm_srli_epi32(s0, 26); c2 = _mm_srli_epi32(s2, 26); s0 = _mm_and_si128(s0, packedmask26262626.v); s2 = _mm_and_si128(s2, packedmask26262626.v); s1 = _mm_add_epi32(s1, c1); s3 = _mm_add_epi32(s3, c2); + c1 = _mm_srli_epi32(s1, 25); c2 = _mm_srli_epi32(s3, 25); s1 = _mm_and_si128(s1, packedmask25252525.v); s3 = _mm_and_si128(s3, packedmask25252525.v); s2 = _mm_add_epi32(s2, c1); r4 = _mm_add_epi32(r4, _mm_srli_si128(c2, 8)); s0 = _mm_add_epi32(s0, _mm_slli_si128(c2, 8)); + + out[0].v = _mm_unpacklo_epi64(s0, s1); /* 00 11 */ + out[1].v = _mm_unpacklo_epi64(s2, s3); /* 22 33 */ + out[2].v = _mm_unpackhi_epi64(s0, s1); /* 44 55 */ + out[3].v = _mm_unpackhi_epi64(s2, s3); /* 66 77 */ + out[4].v = r4; +} + +DONNA_INLINE static void +curve25519_sub_after_basic_packed32(packedelem32 *out, const packedelem32 *r, const packedelem32 *s) { + xmmi r0,r1,r2,r3,r4; + xmmi s0,s1,s2,s3,s4,s5; + xmmi c1,c2; + + r0 = _mm_add_epi32(r[0].v, packed32packed4p0.v); + r1 = _mm_add_epi32(r[1].v, packed32packed4p1.v); + r2 = _mm_add_epi32(r[2].v, packed32packed4p1.v); + r3 = _mm_add_epi32(r[3].v, packed32packed4p1.v); + r4 = _mm_add_epi32(r[4].v, packed32packed4p1.v); + r0 = _mm_sub_epi32(r0, s[0].v); /* 00 11 */ + r1 = _mm_sub_epi32(r1, s[1].v); /* 22 33 */ + r2 = _mm_sub_epi32(r2, s[2].v); /* 44 55 */ + r3 = _mm_sub_epi32(r3, s[3].v); /* 66 77 */ + r4 = _mm_sub_epi32(r4, s[4].v); /* 88 99 */ + + s0 = _mm_unpacklo_epi64(r0, r2); /* 00 44 */ + s1 = _mm_unpackhi_epi64(r0, r2); /* 11 55 */ + s2 = _mm_unpacklo_epi64(r1, r3); /* 22 66 */ + s3 = _mm_unpackhi_epi64(r1, r3); /* 33 77 */ + s4 = _mm_unpacklo_epi64(_mm_setzero_si128(), r4); /* 00 88 */ + s5 = _mm_unpackhi_epi64(_mm_setzero_si128(), r4); /* 00 99 */ + + c1 = _mm_srli_epi32(s0, 26); c2 = _mm_srli_epi32(s2, 26); s0 = _mm_and_si128(s0, packedmask26262626.v); s2 = _mm_and_si128(s2, packedmask26262626.v); s1 = _mm_add_epi32(s1, c1); s3 = _mm_add_epi32(s3, c2); + c1 = _mm_srli_epi32(s1, 25); c2 = _mm_srli_epi32(s3, 25); s1 = _mm_and_si128(s1, packedmask25252525.v); s3 = _mm_and_si128(s3, packedmask25252525.v); s2 = _mm_add_epi32(s2, c1); s4 = _mm_add_epi32(s4, _mm_unpackhi_epi64(_mm_setzero_si128(), c2)); s0 = _mm_add_epi32(s0, _mm_unpacklo_epi64(_mm_setzero_si128(), c2)); + c1 = _mm_srli_epi32(s2, 26); c2 = _mm_srli_epi32(s4, 26); s2 = _mm_and_si128(s2, packedmask26262626.v); s4 = _mm_and_si128(s4, packedmask26262626.v); s3 = _mm_add_epi32(s3, c1); s5 = _mm_add_epi32(s5, c2); + c1 = _mm_srli_epi32(s3, 25); c2 = _mm_srli_epi32(s5, 25); s3 = _mm_and_si128(s3, packedmask25252525.v); s5 = _mm_and_si128(s5, packedmask25252525.v); s4 = _mm_add_epi32(s4, c1); s0 = _mm_add_epi32(s0, _mm_or_si128(_mm_slli_si128(c1, 8), _mm_srli_si128(_mm_add_epi32(_mm_add_epi32(_mm_slli_epi32(c2, 4), _mm_slli_epi32(c2, 1)), c2), 8))); + c1 = _mm_srli_epi32(s0, 26); c2 = _mm_srli_epi32(s2, 26); s0 = _mm_and_si128(s0, packedmask26262626.v); s2 = _mm_and_si128(s2, packedmask26262626.v); s1 = _mm_add_epi32(s1, c1); s3 = _mm_add_epi32(s3, c2); + + out[0].v = _mm_unpacklo_epi64(s0, s1); /* 00 11 */ + out[1].v = _mm_unpacklo_epi64(s2, s3); /* 22 33 */ + out[2].v = _mm_unpackhi_epi64(s0, s1); /* 44 55 */ + out[3].v = _mm_unpackhi_epi64(s2, s3); /* 66 77 */ + out[4].v = _mm_unpackhi_epi64(s4, s5); /* 88 99 */ +} + +DONNA_INLINE static void +curve25519_tangle64_from32(packedelem64 *a, packedelem64 *b, const packedelem32 *c, const packedelem32 *d) { + xmmi c0,c1,c2,c3,c4,c5,t; + xmmi d0,d1,d2,d3,d4,d5; + xmmi t0,t1,t2,t3,t4,zero; + + t0 = _mm_shuffle_epi32(c[0].v, _MM_SHUFFLE(3,1,2,0)); + t1 = _mm_shuffle_epi32(c[1].v, _MM_SHUFFLE(3,1,2,0)); + t2 = _mm_shuffle_epi32(d[0].v, _MM_SHUFFLE(3,1,2,0)); + t3 = _mm_shuffle_epi32(d[1].v, _MM_SHUFFLE(3,1,2,0)); + c0 = _mm_unpacklo_epi64(t0, t1); + c3 = _mm_unpackhi_epi64(t0, t1); + d0 = _mm_unpacklo_epi64(t2, t3); + d3 = _mm_unpackhi_epi64(t2, t3); + t = _mm_unpacklo_epi64(c0, d0); a[0].v = t; a[1].v = _mm_srli_epi64(t, 32); + t = _mm_unpackhi_epi64(c0, d0); a[2].v = t; a[3].v = _mm_srli_epi64(t, 32); + t = _mm_unpacklo_epi64(c3, d3); b[0].v = t; b[1].v = _mm_srli_epi64(t, 32); + t = _mm_unpackhi_epi64(c3, d3); b[2].v = t; b[3].v = _mm_srli_epi64(t, 32); + + t0 = _mm_shuffle_epi32(c[2].v, _MM_SHUFFLE(3,1,2,0)); + t1 = _mm_shuffle_epi32(c[3].v, _MM_SHUFFLE(3,1,2,0)); + t2 = _mm_shuffle_epi32(d[2].v, _MM_SHUFFLE(3,1,2,0)); + t3 = _mm_shuffle_epi32(d[3].v, _MM_SHUFFLE(3,1,2,0)); + c1 = _mm_unpacklo_epi64(t0, t1); + c4 = _mm_unpackhi_epi64(t0, t1); + d1 = _mm_unpacklo_epi64(t2, t3); + d4 = _mm_unpackhi_epi64(t2, t3); + t = _mm_unpacklo_epi64(c1, d1); a[4].v = t; a[5].v = _mm_srli_epi64(t, 32); + t = _mm_unpackhi_epi64(c1, d1); a[6].v = t; a[7].v = _mm_srli_epi64(t, 32); + t = _mm_unpacklo_epi64(c4, d4); b[4].v = t; b[5].v = _mm_srli_epi64(t, 32); + t = _mm_unpackhi_epi64(c4, d4); b[6].v = t; b[7].v = _mm_srli_epi64(t, 32); + + t4 = _mm_shuffle_epi32(c[4].v, _MM_SHUFFLE(3,1,2,0)); + zero = _mm_setzero_si128(); + c2 = _mm_unpacklo_epi64(t4, zero); + c5 = _mm_unpackhi_epi64(t4, zero); + t4 = _mm_shuffle_epi32(d[4].v, _MM_SHUFFLE(3,1,2,0)); + d2 = _mm_unpacklo_epi64(t4, zero); + d5 = _mm_unpackhi_epi64(t4, zero); + t = _mm_unpacklo_epi64(c2, d2); a[8].v = t; a[9].v = _mm_srli_epi64(t, 32); + t = _mm_unpacklo_epi64(c5, d5); b[8].v = t; b[9].v = _mm_srli_epi64(t, 32); +} + +DONNA_INLINE static void +curve25519_tangle64(packedelem64 *out, const bignum25519 x, const bignum25519 z) { + xmmi x0,x1,x2,z0,z1,z2,t; + + x0 = _mm_load_si128((xmmi *)x + 0); + x1 = _mm_load_si128((xmmi *)x + 1); + x2 = _mm_load_si128((xmmi *)x + 2); + z0 = _mm_load_si128((xmmi *)z + 0); + z1 = _mm_load_si128((xmmi *)z + 1); + z2 = _mm_load_si128((xmmi *)z + 2); + + t = _mm_unpacklo_epi64(x0, z0); out[0].v = t; out[1].v = _mm_srli_epi64(t, 32); + t = _mm_unpackhi_epi64(x0, z0); out[2].v = t; out[3].v = _mm_srli_epi64(t, 32); + t = _mm_unpacklo_epi64(x1, z1); out[4].v = t; out[5].v = _mm_srli_epi64(t, 32); + t = _mm_unpackhi_epi64(x1, z1); out[6].v = t; out[7].v = _mm_srli_epi64(t, 32); + t = _mm_unpacklo_epi64(x2, z2); out[8].v = t; out[9].v = _mm_srli_epi64(t, 32); +} + +DONNA_INLINE static void +curve25519_tangleone64(packedelem64 *out, const bignum25519 x) { + xmmi x0,x1,x2; + + x0 = _mm_load_si128((xmmi *)(x + 0)); + x1 = _mm_load_si128((xmmi *)(x + 4)); + x2 = _mm_load_si128((xmmi *)(x + 8)); + + out[0].v = _mm_shuffle_epi32(x0, _MM_SHUFFLE(0,0,0,0)); + out[1].v = _mm_shuffle_epi32(x0, _MM_SHUFFLE(1,1,1,1)); + out[2].v = _mm_shuffle_epi32(x0, _MM_SHUFFLE(2,2,2,2)); + out[3].v = _mm_shuffle_epi32(x0, _MM_SHUFFLE(3,3,3,3)); + out[4].v = _mm_shuffle_epi32(x1, _MM_SHUFFLE(0,0,0,0)); + out[5].v = _mm_shuffle_epi32(x1, _MM_SHUFFLE(1,1,1,1)); + out[6].v = _mm_shuffle_epi32(x1, _MM_SHUFFLE(2,2,2,2)); + out[7].v = _mm_shuffle_epi32(x1, _MM_SHUFFLE(3,3,3,3)); + out[8].v = _mm_shuffle_epi32(x2, _MM_SHUFFLE(0,0,0,0)); + out[9].v = _mm_shuffle_epi32(x2, _MM_SHUFFLE(1,1,1,1)); +} + +DONNA_INLINE static void +curve25519_swap64(packedelem64 *out) { + out[0].v = _mm_shuffle_epi32(out[0].v, _MM_SHUFFLE(1,0,3,2)); + out[1].v = _mm_shuffle_epi32(out[1].v, _MM_SHUFFLE(1,0,3,2)); + out[2].v = _mm_shuffle_epi32(out[2].v, _MM_SHUFFLE(1,0,3,2)); + out[3].v = _mm_shuffle_epi32(out[3].v, _MM_SHUFFLE(1,0,3,2)); + out[4].v = _mm_shuffle_epi32(out[4].v, _MM_SHUFFLE(1,0,3,2)); + out[5].v = _mm_shuffle_epi32(out[5].v, _MM_SHUFFLE(1,0,3,2)); + out[6].v = _mm_shuffle_epi32(out[6].v, _MM_SHUFFLE(1,0,3,2)); + out[7].v = _mm_shuffle_epi32(out[7].v, _MM_SHUFFLE(1,0,3,2)); + out[8].v = _mm_shuffle_epi32(out[8].v, _MM_SHUFFLE(1,0,3,2)); + out[9].v = _mm_shuffle_epi32(out[9].v, _MM_SHUFFLE(1,0,3,2)); +} + +DONNA_INLINE static void +curve25519_untangle64(bignum25519 x, bignum25519 z, const packedelem64 *in) { + _mm_store_si128((xmmi *)(x + 0), _mm_unpacklo_epi64(_mm_unpacklo_epi32(in[0].v, in[1].v), _mm_unpacklo_epi32(in[2].v, in[3].v))); + _mm_store_si128((xmmi *)(x + 4), _mm_unpacklo_epi64(_mm_unpacklo_epi32(in[4].v, in[5].v), _mm_unpacklo_epi32(in[6].v, in[7].v))); + _mm_store_si128((xmmi *)(x + 8), _mm_unpacklo_epi32(in[8].v, in[9].v) ); + _mm_store_si128((xmmi *)(z + 0), _mm_unpacklo_epi64(_mm_unpackhi_epi32(in[0].v, in[1].v), _mm_unpackhi_epi32(in[2].v, in[3].v))); + _mm_store_si128((xmmi *)(z + 4), _mm_unpacklo_epi64(_mm_unpackhi_epi32(in[4].v, in[5].v), _mm_unpackhi_epi32(in[6].v, in[7].v))); + _mm_store_si128((xmmi *)(z + 8), _mm_unpackhi_epi32(in[8].v, in[9].v) ); +} + +DONNA_INLINE static void +curve25519_mul_packed64(packedelem64 *out, const packedelem64 *r, const packedelem64 *s) { + xmmi r1,r2,r3,r4,r5,r6,r7,r8,r9; + xmmi r1_2,r3_2,r5_2,r7_2,r9_2; + xmmi c1,c2; + + out[0].v = _mm_mul_epu32(r[0].v, s[0].v); + out[1].v = _mm_add_epi64(_mm_mul_epu32(r[0].v, s[1].v), _mm_mul_epu32(r[1].v, s[0].v)); + r1_2 = _mm_slli_epi32(r[1].v, 1); + out[2].v = _mm_add_epi64(_mm_mul_epu32(r[0].v, s[2].v), _mm_add_epi64(_mm_mul_epu32(r1_2 , s[1].v), _mm_mul_epu32(r[2].v, s[0].v))); + out[3].v = _mm_add_epi64(_mm_mul_epu32(r[0].v, s[3].v), _mm_add_epi64(_mm_mul_epu32(r[1].v, s[2].v), _mm_add_epi64(_mm_mul_epu32(r[2].v, s[1].v), _mm_mul_epu32(r[3].v, s[0].v)))); + r3_2 = _mm_slli_epi32(r[3].v, 1); + out[4].v = _mm_add_epi64(_mm_mul_epu32(r[0].v, s[4].v), _mm_add_epi64(_mm_mul_epu32(r1_2 , s[3].v), _mm_add_epi64(_mm_mul_epu32(r[2].v, s[2].v), _mm_add_epi64(_mm_mul_epu32(r3_2 , s[1].v), _mm_mul_epu32(r[4].v, s[0].v))))); + out[5].v = _mm_add_epi64(_mm_mul_epu32(r[0].v, s[5].v), _mm_add_epi64(_mm_mul_epu32(r[1].v, s[4].v), _mm_add_epi64(_mm_mul_epu32(r[2].v, s[3].v), _mm_add_epi64(_mm_mul_epu32(r[3].v, s[2].v), _mm_add_epi64(_mm_mul_epu32(r[4].v, s[1].v), _mm_mul_epu32(r[5].v, s[0].v)))))); + r5_2 = _mm_slli_epi32(r[5].v, 1); + out[6].v = _mm_add_epi64(_mm_mul_epu32(r[0].v, s[6].v), _mm_add_epi64(_mm_mul_epu32(r1_2 , s[5].v), _mm_add_epi64(_mm_mul_epu32(r[2].v, s[4].v), _mm_add_epi64(_mm_mul_epu32(r3_2 , s[3].v), _mm_add_epi64(_mm_mul_epu32(r[4].v, s[2].v), _mm_add_epi64(_mm_mul_epu32(r5_2 , s[1].v), _mm_mul_epu32(r[6].v, s[0].v))))))); + out[7].v = _mm_add_epi64(_mm_mul_epu32(r[0].v, s[7].v), _mm_add_epi64(_mm_mul_epu32(r[1].v, s[6].v), _mm_add_epi64(_mm_mul_epu32(r[2].v, s[5].v), _mm_add_epi64(_mm_mul_epu32(r[3].v, s[4].v), _mm_add_epi64(_mm_mul_epu32(r[4].v, s[3].v), _mm_add_epi64(_mm_mul_epu32(r[5].v, s[2].v), _mm_add_epi64(_mm_mul_epu32(r[6].v, s[1].v), _mm_mul_epu32(r[7].v , s[0].v)))))))); + r7_2 = _mm_slli_epi32(r[7].v, 1); + out[8].v = _mm_add_epi64(_mm_mul_epu32(r[0].v, s[8].v), _mm_add_epi64(_mm_mul_epu32(r1_2 , s[7].v), _mm_add_epi64(_mm_mul_epu32(r[2].v, s[6].v), _mm_add_epi64(_mm_mul_epu32(r3_2 , s[5].v), _mm_add_epi64(_mm_mul_epu32(r[4].v, s[4].v), _mm_add_epi64(_mm_mul_epu32(r5_2 , s[3].v), _mm_add_epi64(_mm_mul_epu32(r[6].v, s[2].v), _mm_add_epi64(_mm_mul_epu32(r7_2 , s[1].v), _mm_mul_epu32(r[8].v, s[0].v))))))))); + out[9].v = _mm_add_epi64(_mm_mul_epu32(r[0].v, s[9].v), _mm_add_epi64(_mm_mul_epu32(r[1].v, s[8].v), _mm_add_epi64(_mm_mul_epu32(r[2].v, s[7].v), _mm_add_epi64(_mm_mul_epu32(r[3].v, s[6].v), _mm_add_epi64(_mm_mul_epu32(r[4].v, s[5].v), _mm_add_epi64(_mm_mul_epu32(r[5].v, s[4].v), _mm_add_epi64(_mm_mul_epu32(r[6].v, s[3].v), _mm_add_epi64(_mm_mul_epu32(r[7].v, s[2].v), _mm_add_epi64(_mm_mul_epu32(r[8].v, s[1].v), _mm_mul_epu32(r[9].v, s[0].v)))))))))); + + r1 = _mm_mul_epu32(r[1].v, packednineteen.v); + r2 = _mm_mul_epu32(r[2].v, packednineteen.v); + r1_2 = _mm_slli_epi32(r1, 1); + r3 = _mm_mul_epu32(r[3].v, packednineteen.v); + r4 = _mm_mul_epu32(r[4].v, packednineteen.v); + r3_2 = _mm_slli_epi32(r3, 1); + r5 = _mm_mul_epu32(r[5].v, packednineteen.v); + r6 = _mm_mul_epu32(r[6].v, packednineteen.v); + r5_2 = _mm_slli_epi32(r5, 1); + r7 = _mm_mul_epu32(r[7].v, packednineteen.v); + r8 = _mm_mul_epu32(r[8].v, packednineteen.v); + r7_2 = _mm_slli_epi32(r7, 1); + r9 = _mm_mul_epu32(r[9].v, packednineteen.v); + r9_2 = _mm_slli_epi32(r9, 1); + + out[0].v = _mm_add_epi64(out[0].v, _mm_add_epi64(_mm_mul_epu32(r9_2, s[1].v), _mm_add_epi64(_mm_mul_epu32(r8, s[2].v), _mm_add_epi64(_mm_mul_epu32(r7_2, s[3].v), _mm_add_epi64(_mm_mul_epu32(r6, s[4].v), _mm_add_epi64(_mm_mul_epu32(r5_2, s[5].v), _mm_add_epi64(_mm_mul_epu32(r4, s[6].v), _mm_add_epi64(_mm_mul_epu32(r3_2, s[7].v), _mm_add_epi64(_mm_mul_epu32(r2, s[8].v), _mm_mul_epu32(r1_2, s[9].v)))))))))); + out[1].v = _mm_add_epi64(out[1].v, _mm_add_epi64(_mm_mul_epu32(r9 , s[2].v), _mm_add_epi64(_mm_mul_epu32(r8, s[3].v), _mm_add_epi64(_mm_mul_epu32(r7 , s[4].v), _mm_add_epi64(_mm_mul_epu32(r6, s[5].v), _mm_add_epi64(_mm_mul_epu32(r5 , s[6].v), _mm_add_epi64(_mm_mul_epu32(r4, s[7].v), _mm_add_epi64(_mm_mul_epu32(r3 , s[8].v), _mm_mul_epu32(r2, s[9].v))))))))); + out[2].v = _mm_add_epi64(out[2].v, _mm_add_epi64(_mm_mul_epu32(r9_2, s[3].v), _mm_add_epi64(_mm_mul_epu32(r8, s[4].v), _mm_add_epi64(_mm_mul_epu32(r7_2, s[5].v), _mm_add_epi64(_mm_mul_epu32(r6, s[6].v), _mm_add_epi64(_mm_mul_epu32(r5_2, s[7].v), _mm_add_epi64(_mm_mul_epu32(r4, s[8].v), _mm_mul_epu32(r3_2, s[9].v)))))))); + out[3].v = _mm_add_epi64(out[3].v, _mm_add_epi64(_mm_mul_epu32(r9 , s[4].v), _mm_add_epi64(_mm_mul_epu32(r8, s[5].v), _mm_add_epi64(_mm_mul_epu32(r7 , s[6].v), _mm_add_epi64(_mm_mul_epu32(r6, s[7].v), _mm_add_epi64(_mm_mul_epu32(r5 , s[8].v), _mm_mul_epu32(r4, s[9].v))))))); + out[4].v = _mm_add_epi64(out[4].v, _mm_add_epi64(_mm_mul_epu32(r9_2, s[5].v), _mm_add_epi64(_mm_mul_epu32(r8, s[6].v), _mm_add_epi64(_mm_mul_epu32(r7_2, s[7].v), _mm_add_epi64(_mm_mul_epu32(r6, s[8].v), _mm_mul_epu32(r5_2, s[9].v)))))); + out[5].v = _mm_add_epi64(out[5].v, _mm_add_epi64(_mm_mul_epu32(r9 , s[6].v), _mm_add_epi64(_mm_mul_epu32(r8, s[7].v), _mm_add_epi64(_mm_mul_epu32(r7 , s[8].v), _mm_mul_epu32(r6, s[9].v))))); + out[6].v = _mm_add_epi64(out[6].v, _mm_add_epi64(_mm_mul_epu32(r9_2, s[7].v), _mm_add_epi64(_mm_mul_epu32(r8, s[8].v), _mm_mul_epu32(r7_2, s[9].v)))); + out[7].v = _mm_add_epi64(out[7].v, _mm_add_epi64(_mm_mul_epu32(r9 , s[8].v), _mm_mul_epu32(r8, s[9].v))); + out[8].v = _mm_add_epi64(out[8].v, _mm_mul_epu32(r9_2, s[9].v)); + + c1 = _mm_srli_epi64(out[0].v, 26); c2 = _mm_srli_epi64(out[4].v, 26); out[0].v = _mm_and_si128(out[0].v, packedmask26.v); out[4].v = _mm_and_si128(out[4].v, packedmask26.v); out[1].v = _mm_add_epi64(out[1].v, c1); out[5].v = _mm_add_epi64(out[5].v, c2); + c1 = _mm_srli_epi64(out[1].v, 25); c2 = _mm_srli_epi64(out[5].v, 25); out[1].v = _mm_and_si128(out[1].v, packedmask25.v); out[5].v = _mm_and_si128(out[5].v, packedmask25.v); out[2].v = _mm_add_epi64(out[2].v, c1); out[6].v = _mm_add_epi64(out[6].v, c2); + c1 = _mm_srli_epi64(out[2].v, 26); c2 = _mm_srli_epi64(out[6].v, 26); out[2].v = _mm_and_si128(out[2].v, packedmask26.v); out[6].v = _mm_and_si128(out[6].v, packedmask26.v); out[3].v = _mm_add_epi64(out[3].v, c1); out[7].v = _mm_add_epi64(out[7].v, c2); + c1 = _mm_srli_epi64(out[3].v, 25); c2 = _mm_srli_epi64(out[7].v, 25); out[3].v = _mm_and_si128(out[3].v, packedmask25.v); out[7].v = _mm_and_si128(out[7].v, packedmask25.v); out[4].v = _mm_add_epi64(out[4].v, c1); out[8].v = _mm_add_epi64(out[8].v, c2); + c2 = _mm_srli_epi64(out[8].v, 26); out[8].v = _mm_and_si128(out[8].v, packedmask26.v); out[9].v = _mm_add_epi64(out[9].v, c2); + c2 = _mm_srli_epi64(out[9].v, 25); out[9].v = _mm_and_si128(out[9].v, packedmask25.v); out[0].v = _mm_add_epi64(out[0].v, _mm_mul_epu32(c2, packednineteen.v)); + c1 = _mm_srli_epi64(out[0].v, 26); c2 = _mm_srli_epi64(out[4].v, 26); out[0].v = _mm_and_si128(out[0].v, packedmask26.v); out[4].v = _mm_and_si128(out[4].v, packedmask26.v); out[1].v = _mm_add_epi64(out[1].v, c1); out[5].v = _mm_add_epi64(out[5].v, c2); +} + +DONNA_INLINE static void +curve25519_square_packed64(packedelem64 *out, const packedelem64 *r) { + xmmi r0,r1,r2,r3; + xmmi r1_2,r3_2,r4_2,r5_2,r6_2,r7_2; + xmmi d5,d6,d7,d8,d9; + xmmi c1,c2; + + r0 = r[0].v; + r1 = r[1].v; + r2 = r[2].v; + r3 = r[3].v; + + out[0].v = _mm_mul_epu32(r0, r0); + r0 = _mm_slli_epi32(r0, 1); + out[1].v = _mm_mul_epu32(r0, r1); + r1_2 = _mm_slli_epi32(r1, 1); + out[2].v = _mm_add_epi64(_mm_mul_epu32(r0, r2 ), _mm_mul_epu32(r1, r1_2)); + r1 = r1_2; + out[3].v = _mm_add_epi64(_mm_mul_epu32(r0, r3 ), _mm_mul_epu32(r1, r2 )); + r3_2 = _mm_slli_epi32(r3, 1); + out[4].v = _mm_add_epi64(_mm_mul_epu32(r0, r[4].v), _mm_add_epi64(_mm_mul_epu32(r1, r3_2 ), _mm_mul_epu32(r2, r2))); + r2 = _mm_slli_epi32(r2, 1); + out[5].v = _mm_add_epi64(_mm_mul_epu32(r0, r[5].v), _mm_add_epi64(_mm_mul_epu32(r1, r[4].v), _mm_mul_epu32(r2, r3))); + r5_2 = _mm_slli_epi32(r[5].v, 1); + out[6].v = _mm_add_epi64(_mm_mul_epu32(r0, r[6].v), _mm_add_epi64(_mm_mul_epu32(r1, r5_2 ), _mm_add_epi64(_mm_mul_epu32(r2, r[4].v), _mm_mul_epu32(r3, r3_2 )))); + r3 = r3_2; + out[7].v = _mm_add_epi64(_mm_mul_epu32(r0, r[7].v), _mm_add_epi64(_mm_mul_epu32(r1, r[6].v), _mm_add_epi64(_mm_mul_epu32(r2, r[5].v), _mm_mul_epu32(r3, r[4].v)))); + r7_2 = _mm_slli_epi32(r[7].v, 1); + out[8].v = _mm_add_epi64(_mm_mul_epu32(r0, r[8].v), _mm_add_epi64(_mm_mul_epu32(r1, r7_2 ), _mm_add_epi64(_mm_mul_epu32(r2, r[6].v), _mm_add_epi64(_mm_mul_epu32(r3, r5_2 ), _mm_mul_epu32(r[4].v, r[4].v))))); + out[9].v = _mm_add_epi64(_mm_mul_epu32(r0, r[9].v), _mm_add_epi64(_mm_mul_epu32(r1, r[8].v), _mm_add_epi64(_mm_mul_epu32(r2, r[7].v), _mm_add_epi64(_mm_mul_epu32(r3, r[6].v), _mm_mul_epu32(r[4].v, r5_2 ))))); + + d5 = _mm_mul_epu32(r[5].v, packedthirtyeight.v); + d6 = _mm_mul_epu32(r[6].v, packednineteen.v); + d7 = _mm_mul_epu32(r[7].v, packedthirtyeight.v); + d8 = _mm_mul_epu32(r[8].v, packednineteen.v); + d9 = _mm_mul_epu32(r[9].v, packedthirtyeight.v); + + r4_2 = _mm_slli_epi32(r[4].v, 1); + r6_2 = _mm_slli_epi32(r[6].v, 1); + out[0].v = _mm_add_epi64(out[0].v, _mm_add_epi64(_mm_mul_epu32(d9, r1 ), _mm_add_epi64(_mm_mul_epu32(d8, r2 ), _mm_add_epi64(_mm_mul_epu32(d7, r3 ), _mm_add_epi64(_mm_mul_epu32(d6, r4_2), _mm_mul_epu32(d5, r[5].v)))))); + out[1].v = _mm_add_epi64(out[1].v, _mm_add_epi64(_mm_mul_epu32(d9, _mm_srli_epi32(r2, 1)), _mm_add_epi64(_mm_mul_epu32(d8, r3 ), _mm_add_epi64(_mm_mul_epu32(d7, r[4].v), _mm_mul_epu32(d6, r5_2 ))))); + out[2].v = _mm_add_epi64(out[2].v, _mm_add_epi64(_mm_mul_epu32(d9, r3 ), _mm_add_epi64(_mm_mul_epu32(d8, r4_2), _mm_add_epi64(_mm_mul_epu32(d7, r5_2 ), _mm_mul_epu32(d6, r[6].v))))); + out[3].v = _mm_add_epi64(out[3].v, _mm_add_epi64(_mm_mul_epu32(d9, r[4].v ), _mm_add_epi64(_mm_mul_epu32(d8, r5_2), _mm_mul_epu32(d7, r[6].v)))); + out[4].v = _mm_add_epi64(out[4].v, _mm_add_epi64(_mm_mul_epu32(d9, r5_2 ), _mm_add_epi64(_mm_mul_epu32(d8, r6_2), _mm_mul_epu32(d7, r[7].v)))); + out[5].v = _mm_add_epi64(out[5].v, _mm_add_epi64(_mm_mul_epu32(d9, r[6].v ), _mm_mul_epu32(d8, r7_2 ))); + out[6].v = _mm_add_epi64(out[6].v, _mm_add_epi64(_mm_mul_epu32(d9, r7_2 ), _mm_mul_epu32(d8, r[8].v))); + out[7].v = _mm_add_epi64(out[7].v, _mm_mul_epu32(d9, r[8].v)); + out[8].v = _mm_add_epi64(out[8].v, _mm_mul_epu32(d9, r[9].v)); + + c1 = _mm_srli_epi64(out[0].v, 26); c2 = _mm_srli_epi64(out[4].v, 26); out[0].v = _mm_and_si128(out[0].v, packedmask26.v); out[4].v = _mm_and_si128(out[4].v, packedmask26.v); out[1].v = _mm_add_epi64(out[1].v, c1); out[5].v = _mm_add_epi64(out[5].v, c2); + c1 = _mm_srli_epi64(out[1].v, 25); c2 = _mm_srli_epi64(out[5].v, 25); out[1].v = _mm_and_si128(out[1].v, packedmask25.v); out[5].v = _mm_and_si128(out[5].v, packedmask25.v); out[2].v = _mm_add_epi64(out[2].v, c1); out[6].v = _mm_add_epi64(out[6].v, c2); + c1 = _mm_srli_epi64(out[2].v, 26); c2 = _mm_srli_epi64(out[6].v, 26); out[2].v = _mm_and_si128(out[2].v, packedmask26.v); out[6].v = _mm_and_si128(out[6].v, packedmask26.v); out[3].v = _mm_add_epi64(out[3].v, c1); out[7].v = _mm_add_epi64(out[7].v, c2); + c1 = _mm_srli_epi64(out[3].v, 25); c2 = _mm_srli_epi64(out[7].v, 25); out[3].v = _mm_and_si128(out[3].v, packedmask25.v); out[7].v = _mm_and_si128(out[7].v, packedmask25.v); out[4].v = _mm_add_epi64(out[4].v, c1); out[8].v = _mm_add_epi64(out[8].v, c2); + c2 = _mm_srli_epi64(out[8].v, 26); out[8].v = _mm_and_si128(out[8].v, packedmask26.v); out[9].v = _mm_add_epi64(out[9].v, c2); + c2 = _mm_srli_epi64(out[9].v, 25); out[9].v = _mm_and_si128(out[9].v, packedmask25.v); out[0].v = _mm_add_epi64(out[0].v, _mm_mul_epu32(c2, packednineteen.v)); + c1 = _mm_srli_epi64(out[0].v, 26); c2 = _mm_srli_epi64(out[4].v, 26); out[0].v = _mm_and_si128(out[0].v, packedmask26.v); out[4].v = _mm_and_si128(out[4].v, packedmask26.v); out[1].v = _mm_add_epi64(out[1].v, c1); out[5].v = _mm_add_epi64(out[5].v, c2); +} + + +/* Take a little-endian, 32-byte number and expand it into polynomial form */ +static void +curve25519_expand(bignum25519 out, const unsigned char in[32]) { + uint32_t x0,x1,x2,x3,x4,x5,x6,x7; + + x0 = *(uint32_t *)(in + 0); + x1 = *(uint32_t *)(in + 4); + x2 = *(uint32_t *)(in + 8); + x3 = *(uint32_t *)(in + 12); + x4 = *(uint32_t *)(in + 16); + x5 = *(uint32_t *)(in + 20); + x6 = *(uint32_t *)(in + 24); + x7 = *(uint32_t *)(in + 28); + + out[0] = ( x0 ) & 0x3ffffff; + out[1] = ((((uint64_t)x1 << 32) | x0) >> 26) & 0x1ffffff; + out[2] = ((((uint64_t)x2 << 32) | x1) >> 19) & 0x3ffffff; + out[3] = ((((uint64_t)x3 << 32) | x2) >> 13) & 0x1ffffff; + out[4] = (( x3) >> 6) & 0x3ffffff; + out[5] = ( x4 ) & 0x1ffffff; + out[6] = ((((uint64_t)x5 << 32) | x4) >> 25) & 0x3ffffff; + out[7] = ((((uint64_t)x6 << 32) | x5) >> 19) & 0x1ffffff; + out[8] = ((((uint64_t)x7 << 32) | x6) >> 12) & 0x3ffffff; + out[9] = (( x7) >> 6) & 0x1ffffff; + out[10] = 0; + out[11] = 0; +} + +/* Take a fully reduced polynomial form number and contract it into a + * little-endian, 32-byte array + */ +static void +curve25519_contract(unsigned char out[32], const bignum25519 in) { + bignum25519 ALIGN(16) f; + curve25519_copy(f, in); + + #define carry_pass() \ + f[1] += f[0] >> 26; f[0] &= 0x3ffffff; \ + f[2] += f[1] >> 25; f[1] &= 0x1ffffff; \ + f[3] += f[2] >> 26; f[2] &= 0x3ffffff; \ + f[4] += f[3] >> 25; f[3] &= 0x1ffffff; \ + f[5] += f[4] >> 26; f[4] &= 0x3ffffff; \ + f[6] += f[5] >> 25; f[5] &= 0x1ffffff; \ + f[7] += f[6] >> 26; f[6] &= 0x3ffffff; \ + f[8] += f[7] >> 25; f[7] &= 0x1ffffff; \ + f[9] += f[8] >> 26; f[8] &= 0x3ffffff; + + #define carry_pass_full() \ + carry_pass() \ + f[0] += 19 * (f[9] >> 25); f[9] &= 0x1ffffff; + + #define carry_pass_final() \ + carry_pass() \ + f[9] &= 0x1ffffff; + + carry_pass_full() + carry_pass_full() + + /* now t is between 0 and 2^255-1, properly carried. */ + /* case 1: between 0 and 2^255-20. case 2: between 2^255-19 and 2^255-1. */ + f[0] += 19; + carry_pass_full() + + /* now between 19 and 2^255-1 in both cases, and offset by 19. */ + f[0] += (1 << 26) - 19; + f[1] += (1 << 25) - 1; + f[2] += (1 << 26) - 1; + f[3] += (1 << 25) - 1; + f[4] += (1 << 26) - 1; + f[5] += (1 << 25) - 1; + f[6] += (1 << 26) - 1; + f[7] += (1 << 25) - 1; + f[8] += (1 << 26) - 1; + f[9] += (1 << 25) - 1; + + /* now between 2^255 and 2^256-20, and offset by 2^255. */ + carry_pass_final() + + #undef carry_pass + #undef carry_full + #undef carry_final + + f[1] <<= 2; + f[2] <<= 3; + f[3] <<= 5; + f[4] <<= 6; + f[6] <<= 1; + f[7] <<= 3; + f[8] <<= 4; + f[9] <<= 6; + + #define F(i, s) \ + out[s+0] |= (unsigned char )(f[i] & 0xff); \ + out[s+1] = (unsigned char )((f[i] >> 8) & 0xff); \ + out[s+2] = (unsigned char )((f[i] >> 16) & 0xff); \ + out[s+3] = (unsigned char )((f[i] >> 24) & 0xff); + + out[0] = 0; + out[16] = 0; + F(0,0); + F(1,3); + F(2,6); + F(3,9); + F(4,12); + F(5,16); + F(6,19); + F(7,22); + F(8,25); + F(9,28); + #undef F +} + +/* if (iswap) swap(a, b) */ +DONNA_INLINE static void +curve25519_swap_conditional(bignum25519 a, bignum25519 b, uint32_t iswap) { + const uint32_t swap = (uint32_t)(-(int32_t)iswap); + xmmi a0,a1,a2,b0,b1,b2,x0,x1,x2; + xmmi mask = _mm_cvtsi32_si128(swap); + mask = _mm_shuffle_epi32(mask, 0); + a0 = _mm_load_si128((xmmi *)a + 0); + a1 = _mm_load_si128((xmmi *)a + 1); + b0 = _mm_load_si128((xmmi *)b + 0); + b1 = _mm_load_si128((xmmi *)b + 1); + b0 = _mm_xor_si128(a0, b0); + b1 = _mm_xor_si128(a1, b1); + x0 = _mm_and_si128(b0, mask); + x1 = _mm_and_si128(b1, mask); + x0 = _mm_xor_si128(x0, a0); + x1 = _mm_xor_si128(x1, a1); + a0 = _mm_xor_si128(x0, b0); + a1 = _mm_xor_si128(x1, b1); + _mm_store_si128((xmmi *)a + 0, x0); + _mm_store_si128((xmmi *)a + 1, x1); + _mm_store_si128((xmmi *)b + 0, a0); + _mm_store_si128((xmmi *)b + 1, a1); + + a2 = _mm_load_si128((xmmi *)a + 2); + b2 = _mm_load_si128((xmmi *)b + 2); + b2 = _mm_xor_si128(a2, b2); + x2 = _mm_and_si128(b2, mask); + x2 = _mm_xor_si128(x2, a2); + a2 = _mm_xor_si128(x2, b2); + _mm_store_si128((xmmi *)b + 2, a2); + _mm_store_si128((xmmi *)a + 2, x2); +} + +/* out = (flag) ? out : in */ +DONNA_INLINE static void +curve25519_move_conditional_bytes(uint8_t out[96], const uint8_t in[96], uint32_t flag) { + xmmi a0,a1,a2,a3,a4,a5,b0,b1,b2,b3,b4,b5; + const uint32_t nb = flag - 1; + xmmi masknb = _mm_shuffle_epi32(_mm_cvtsi32_si128(nb),0); + a0 = _mm_load_si128((xmmi *)in + 0); + a1 = _mm_load_si128((xmmi *)in + 1); + a2 = _mm_load_si128((xmmi *)in + 2); + b0 = _mm_load_si128((xmmi *)out + 0); + b1 = _mm_load_si128((xmmi *)out + 1); + b2 = _mm_load_si128((xmmi *)out + 2); + a0 = _mm_andnot_si128(masknb, a0); + a1 = _mm_andnot_si128(masknb, a1); + a2 = _mm_andnot_si128(masknb, a2); + b0 = _mm_and_si128(masknb, b0); + b1 = _mm_and_si128(masknb, b1); + b2 = _mm_and_si128(masknb, b2); + a0 = _mm_or_si128(a0, b0); + a1 = _mm_or_si128(a1, b1); + a2 = _mm_or_si128(a2, b2); + _mm_store_si128((xmmi*)out + 0, a0); + _mm_store_si128((xmmi*)out + 1, a1); + _mm_store_si128((xmmi*)out + 2, a2); + + a3 = _mm_load_si128((xmmi *)in + 3); + a4 = _mm_load_si128((xmmi *)in + 4); + a5 = _mm_load_si128((xmmi *)in + 5); + b3 = _mm_load_si128((xmmi *)out + 3); + b4 = _mm_load_si128((xmmi *)out + 4); + b5 = _mm_load_si128((xmmi *)out + 5); + a3 = _mm_andnot_si128(masknb, a3); + a4 = _mm_andnot_si128(masknb, a4); + a5 = _mm_andnot_si128(masknb, a5); + b3 = _mm_and_si128(masknb, b3); + b4 = _mm_and_si128(masknb, b4); + b5 = _mm_and_si128(masknb, b5); + a3 = _mm_or_si128(a3, b3); + a4 = _mm_or_si128(a4, b4); + a5 = _mm_or_si128(a5, b5); + _mm_store_si128((xmmi*)out + 3, a3); + _mm_store_si128((xmmi*)out + 4, a4); + _mm_store_si128((xmmi*)out + 5, a5); +} + diff --git a/ed25519-donna/ed25519-donna-32bit-sse2.h b/ed25519-donna/ed25519-donna-32bit-sse2.h new file mode 100644 index 000000000..db04a13d3 --- /dev/null +++ b/ed25519-donna/ed25519-donna-32bit-sse2.h @@ -0,0 +1,513 @@ +#if defined(ED25519_GCC_32BIT_SSE_CHOOSE) + +#define HAVE_GE25519_SCALARMULT_BASE_CHOOSE_NIELS + +DONNA_NOINLINE static void +ge25519_scalarmult_base_choose_niels(ge25519_niels *t, const uint8_t table[256][96], uint32_t pos, signed char b) { + int32_t breg = (int32_t)b; + uint32_t sign = (uint32_t)breg >> 31; + uint32_t mask = ~(sign - 1); + uint32_t u = (breg + mask) ^ mask; + + __asm__ __volatile__ ( + /* ysubx+xaddy */ + "movl %0, %%eax ;\n" + "movd %%eax, %%xmm6 ;\n" + "pshufd $0x00, %%xmm6, %%xmm6 ;\n" + "pxor %%xmm0, %%xmm0 ;\n" + "pxor %%xmm1, %%xmm1 ;\n" + "pxor %%xmm2, %%xmm2 ;\n" + "pxor %%xmm3, %%xmm3 ;\n" + + /* 0 */ + "movl $0, %%eax ;\n" + "movd %%eax, %%xmm7 ;\n" + "pshufd $0x00, %%xmm7, %%xmm7 ;\n" + "pcmpeqd %%xmm6, %%xmm7 ;\n" + "movl $1, %%ecx ;\n" + "movd %%ecx, %%xmm4 ;\n" + "pxor %%xmm5, %%xmm5 ;\n" + "pand %%xmm7, %%xmm4 ;\n" + "pand %%xmm7, %%xmm5 ;\n" + "por %%xmm4, %%xmm0 ;\n" + "por %%xmm5, %%xmm1 ;\n" + "por %%xmm4, %%xmm2 ;\n" + "por %%xmm5, %%xmm3 ;\n" + + /* 1 */ + "movl $1, %%eax ;\n" + "movd %%eax, %%xmm7 ;\n" + "pshufd $0x00, %%xmm7, %%xmm7 ;\n" + "pcmpeqd %%xmm6, %%xmm7 ;\n" + "movdqa 0(%1), %%xmm4 ;\n" + "movdqa 16(%1), %%xmm5 ;\n" + "pand %%xmm7, %%xmm4 ;\n" + "pand %%xmm7, %%xmm5 ;\n" + "por %%xmm4, %%xmm0 ;\n" + "por %%xmm5, %%xmm1 ;\n" + "movdqa 32(%1), %%xmm4 ;\n" + "movdqa 48(%1), %%xmm5 ;\n" + "pand %%xmm7, %%xmm4 ;\n" + "pand %%xmm7, %%xmm5 ;\n" + "por %%xmm4, %%xmm2 ;\n" + "por %%xmm5, %%xmm3 ;\n" + + /* 2 */ + "movl $2, %%eax ;\n" + "movd %%eax, %%xmm7 ;\n" + "pshufd $0x00, %%xmm7, %%xmm7 ;\n" + "pcmpeqd %%xmm6, %%xmm7 ;\n" + "movdqa 96(%1), %%xmm4 ;\n" + "movdqa 112(%1), %%xmm5 ;\n" + "pand %%xmm7, %%xmm4 ;\n" + "pand %%xmm7, %%xmm5 ;\n" + "por %%xmm4, %%xmm0 ;\n" + "por %%xmm5, %%xmm1 ;\n" + "movdqa 128(%1), %%xmm4 ;\n" + "movdqa 144(%1), %%xmm5 ;\n" + "pand %%xmm7, %%xmm4 ;\n" + "pand %%xmm7, %%xmm5 ;\n" + "por %%xmm4, %%xmm2 ;\n" + "por %%xmm5, %%xmm3 ;\n" + + /* 3 */ + "movl $3, %%eax ;\n" + "movd %%eax, %%xmm7 ;\n" + "pshufd $0x00, %%xmm7, %%xmm7 ;\n" + "pcmpeqd %%xmm6, %%xmm7 ;\n" + "movdqa 192(%1), %%xmm4 ;\n" + "movdqa 208(%1), %%xmm5 ;\n" + "pand %%xmm7, %%xmm4 ;\n" + "pand %%xmm7, %%xmm5 ;\n" + "por %%xmm4, %%xmm0 ;\n" + "por %%xmm5, %%xmm1 ;\n" + "movdqa 224(%1), %%xmm4 ;\n" + "movdqa 240(%1), %%xmm5 ;\n" + "pand %%xmm7, %%xmm4 ;\n" + "pand %%xmm7, %%xmm5 ;\n" + "por %%xmm4, %%xmm2 ;\n" + "por %%xmm5, %%xmm3 ;\n" + + /* 4 */ + "movl $4, %%eax ;\n" + "movd %%eax, %%xmm7 ;\n" + "pshufd $0x00, %%xmm7, %%xmm7 ;\n" + "pcmpeqd %%xmm6, %%xmm7 ;\n" + "movdqa 288(%1), %%xmm4 ;\n" + "movdqa 304(%1), %%xmm5 ;\n" + "pand %%xmm7, %%xmm4 ;\n" + "pand %%xmm7, %%xmm5 ;\n" + "por %%xmm4, %%xmm0 ;\n" + "por %%xmm5, %%xmm1 ;\n" + "movdqa 320(%1), %%xmm4 ;\n" + "movdqa 336(%1), %%xmm5 ;\n" + "pand %%xmm7, %%xmm4 ;\n" + "pand %%xmm7, %%xmm5 ;\n" + "por %%xmm4, %%xmm2 ;\n" + "por %%xmm5, %%xmm3 ;\n" + + /* 5 */ + "movl $5, %%eax ;\n" + "movd %%eax, %%xmm7 ;\n" + "pshufd $0x00, %%xmm7, %%xmm7 ;\n" + "pcmpeqd %%xmm6, %%xmm7 ;\n" + "movdqa 384(%1), %%xmm4 ;\n" + "movdqa 400(%1), %%xmm5 ;\n" + "pand %%xmm7, %%xmm4 ;\n" + "pand %%xmm7, %%xmm5 ;\n" + "por %%xmm4, %%xmm0 ;\n" + "por %%xmm5, %%xmm1 ;\n" + "movdqa 416(%1), %%xmm4 ;\n" + "movdqa 432(%1), %%xmm5 ;\n" + "pand %%xmm7, %%xmm4 ;\n" + "pand %%xmm7, %%xmm5 ;\n" + "por %%xmm4, %%xmm2 ;\n" + "por %%xmm5, %%xmm3 ;\n" + + /* 6 */ + "movl $6, %%eax ;\n" + "movd %%eax, %%xmm7 ;\n" + "pshufd $0x00, %%xmm7, %%xmm7 ;\n" + "pcmpeqd %%xmm6, %%xmm7 ;\n" + "movdqa 480(%1), %%xmm4 ;\n" + "movdqa 496(%1), %%xmm5 ;\n" + "pand %%xmm7, %%xmm4 ;\n" + "pand %%xmm7, %%xmm5 ;\n" + "por %%xmm4, %%xmm0 ;\n" + "por %%xmm5, %%xmm1 ;\n" + "movdqa 512(%1), %%xmm4 ;\n" + "movdqa 528(%1), %%xmm5 ;\n" + "pand %%xmm7, %%xmm4 ;\n" + "pand %%xmm7, %%xmm5 ;\n" + "por %%xmm4, %%xmm2 ;\n" + "por %%xmm5, %%xmm3 ;\n" + + /* 7 */ + "movl $7, %%eax ;\n" + "movd %%eax, %%xmm7 ;\n" + "pshufd $0x00, %%xmm7, %%xmm7 ;\n" + "pcmpeqd %%xmm6, %%xmm7 ;\n" + "movdqa 576(%1), %%xmm4 ;\n" + "movdqa 592(%1), %%xmm5 ;\n" + "pand %%xmm7, %%xmm4 ;\n" + "pand %%xmm7, %%xmm5 ;\n" + "por %%xmm4, %%xmm0 ;\n" + "por %%xmm5, %%xmm1 ;\n" + "movdqa 608(%1), %%xmm4 ;\n" + "movdqa 624(%1), %%xmm5 ;\n" + "pand %%xmm7, %%xmm4 ;\n" + "pand %%xmm7, %%xmm5 ;\n" + "por %%xmm4, %%xmm2 ;\n" + "por %%xmm5, %%xmm3 ;\n" + + /* 8 */ + "movl $8, %%eax ;\n" + "movd %%eax, %%xmm7 ;\n" + "pshufd $0x00, %%xmm7, %%xmm7 ;\n" + "pcmpeqd %%xmm6, %%xmm7 ;\n" + "movdqa 672(%1), %%xmm4 ;\n" + "movdqa 688(%1), %%xmm5 ;\n" + "pand %%xmm7, %%xmm4 ;\n" + "pand %%xmm7, %%xmm5 ;\n" + "por %%xmm4, %%xmm0 ;\n" + "por %%xmm5, %%xmm1 ;\n" + "movdqa 704(%1), %%xmm4 ;\n" + "movdqa 720(%1), %%xmm5 ;\n" + "pand %%xmm7, %%xmm4 ;\n" + "pand %%xmm7, %%xmm5 ;\n" + "por %%xmm4, %%xmm2 ;\n" + "por %%xmm5, %%xmm3 ;\n" + + /* conditional swap based on sign */ + "movl %3, %%ecx ;\n" + "movl %2, %%eax ;\n" + "xorl $1, %%ecx ;\n" + "movd %%ecx, %%xmm6 ;\n" + "pxor %%xmm7, %%xmm7 ;\n" + "pshufd $0x00, %%xmm6, %%xmm6 ;\n" + "pxor %%xmm0, %%xmm2 ;\n" + "pxor %%xmm1, %%xmm3 ;\n" + "pcmpeqd %%xmm6, %%xmm7 ;\n" + "movdqa %%xmm2, %%xmm4 ;\n" + "movdqa %%xmm3, %%xmm5 ;\n" + "pand %%xmm7, %%xmm4 ;\n" + "pand %%xmm7, %%xmm5 ;\n" + "pxor %%xmm4, %%xmm0 ;\n" + "pxor %%xmm5, %%xmm1 ;\n" + "pxor %%xmm0, %%xmm2 ;\n" + "pxor %%xmm1, %%xmm3 ;\n" + + /* store ysubx */ + "movd %%xmm0, %%ecx ;\n" + "movl %%ecx, %%edx ;\n" + "pshufd $0x39, %%xmm0, %%xmm0 ;\n" + "andl $0x3ffffff, %%ecx ;\n" + "movl %%ecx, 0(%%eax) ;\n" + "movd %%xmm0, %%ecx ;\n" + "pshufd $0x39, %%xmm0, %%xmm0 ;\n" + "shrdl $26, %%ecx, %%edx ;\n" + "andl $0x1ffffff, %%edx ;\n" + "movl %%edx, 4(%%eax) ;\n" + "movd %%xmm0, %%edx ;\n" + "pshufd $0x39, %%xmm0, %%xmm0 ;\n" + "shrdl $19, %%edx, %%ecx ;\n" + "andl $0x3ffffff, %%ecx ;\n" + "movl %%ecx, 8(%%eax) ;\n" + "movd %%xmm0, %%ecx ;\n" + "shrdl $13, %%ecx, %%edx ;\n" + "andl $0x1ffffff, %%edx ;\n" + "movl %%edx, 12(%%eax) ;\n" + "movd %%xmm1, %%edx ;\n" + "pshufd $0x39, %%xmm1, %%xmm1 ;\n" + "shrl $6, %%ecx ;\n" + "andl $0x3ffffff, %%ecx ;\n" + "movl %%ecx, 16(%%eax) ;\n" + "movl %%edx, %%ecx ;\n" + "andl $0x1ffffff, %%edx ;\n" + "movl %%edx, 20(%%eax) ;\n" + "movd %%xmm1, %%edx ;\n" + "pshufd $0x39, %%xmm1, %%xmm1 ;\n" + "shrdl $25, %%edx, %%ecx ;\n" + "andl $0x3ffffff, %%ecx ;\n" + "movl %%ecx, 24(%%eax) ;\n" + "movd %%xmm1, %%ecx ;\n" + "pshufd $0x39, %%xmm1, %%xmm1 ;\n" + "shrdl $19, %%ecx, %%edx ;\n" + "andl $0x1ffffff, %%edx ;\n" + "movl %%edx, 28(%%eax) ;\n" + "movd %%xmm1, %%edx ;\n" + "shrdl $12, %%edx, %%ecx ;\n" + "andl $0x3ffffff, %%ecx ;\n" + "movl %%ecx, 32(%%eax) ;\n" + "shrl $6, %%edx ;\n" + "andl $0x1ffffff, %%edx ;\n" + "xorl %%ecx, %%ecx ;\n" + "movl %%edx, 36(%%eax) ;\n" + "movl %%ecx, 40(%%eax) ;\n" + "movl %%ecx, 44(%%eax) ;\n" + + /* store xaddy */ + "addl $48, %%eax ;\n" + "movdqa %%xmm2, %%xmm0 ;\n" + "movdqa %%xmm3, %%xmm1 ;\n" + "movd %%xmm0, %%ecx ;\n" + "movl %%ecx, %%edx ;\n" + "pshufd $0x39, %%xmm0, %%xmm0 ;\n" + "andl $0x3ffffff, %%ecx ;\n" + "movl %%ecx, 0(%%eax) ;\n" + "movd %%xmm0, %%ecx ;\n" + "pshufd $0x39, %%xmm0, %%xmm0 ;\n" + "shrdl $26, %%ecx, %%edx ;\n" + "andl $0x1ffffff, %%edx ;\n" + "movl %%edx, 4(%%eax) ;\n" + "movd %%xmm0, %%edx ;\n" + "pshufd $0x39, %%xmm0, %%xmm0 ;\n" + "shrdl $19, %%edx, %%ecx ;\n" + "andl $0x3ffffff, %%ecx ;\n" + "movl %%ecx, 8(%%eax) ;\n" + "movd %%xmm0, %%ecx ;\n" + "shrdl $13, %%ecx, %%edx ;\n" + "andl $0x1ffffff, %%edx ;\n" + "movl %%edx, 12(%%eax) ;\n" + "movd %%xmm1, %%edx ;\n" + "pshufd $0x39, %%xmm1, %%xmm1 ;\n" + "shrl $6, %%ecx ;\n" + "andl $0x3ffffff, %%ecx ;\n" + "movl %%ecx, 16(%%eax) ;\n" + "movl %%edx, %%ecx ;\n" + "andl $0x1ffffff, %%edx ;\n" + "movl %%edx, 20(%%eax) ;\n" + "movd %%xmm1, %%edx ;\n" + "pshufd $0x39, %%xmm1, %%xmm1 ;\n" + "shrdl $25, %%edx, %%ecx ;\n" + "andl $0x3ffffff, %%ecx ;\n" + "movl %%ecx, 24(%%eax) ;\n" + "movd %%xmm1, %%ecx ;\n" + "pshufd $0x39, %%xmm1, %%xmm1 ;\n" + "shrdl $19, %%ecx, %%edx ;\n" + "andl $0x1ffffff, %%edx ;\n" + "movl %%edx, 28(%%eax) ;\n" + "movd %%xmm1, %%edx ;\n" + "shrdl $12, %%edx, %%ecx ;\n" + "andl $0x3ffffff, %%ecx ;\n" + "movl %%ecx, 32(%%eax) ;\n" + "shrl $6, %%edx ;\n" + "andl $0x1ffffff, %%edx ;\n" + "xorl %%ecx, %%ecx ;\n" + "movl %%edx, 36(%%eax) ;\n" + "movl %%ecx, 40(%%eax) ;\n" + "movl %%ecx, 44(%%eax) ;\n" + + /* t2d */ + "movl %0, %%eax ;\n" + "movd %%eax, %%xmm6 ;\n" + "pshufd $0x00, %%xmm6, %%xmm6 ;\n" + "pxor %%xmm0, %%xmm0 ;\n" + "pxor %%xmm1, %%xmm1 ;\n" + + /* 0 */ + "movl $0, %%eax ;\n" + "movd %%eax, %%xmm7 ;\n" + "pshufd $0x00, %%xmm7, %%xmm7 ;\n" + "pcmpeqd %%xmm6, %%xmm7 ;\n" + "pxor %%xmm0, %%xmm0 ;\n" + "pxor %%xmm1, %%xmm1 ;\n" + + /* 1 */ + "movl $1, %%eax ;\n" + "movd %%eax, %%xmm7 ;\n" + "pshufd $0x00, %%xmm7, %%xmm7 ;\n" + "pcmpeqd %%xmm6, %%xmm7 ;\n" + "movdqa 64(%1), %%xmm3 ;\n" + "movdqa 80(%1), %%xmm4 ;\n" + "pand %%xmm7, %%xmm3 ;\n" + "pand %%xmm7, %%xmm4 ;\n" + "por %%xmm3, %%xmm0 ;\n" + "por %%xmm4, %%xmm1 ;\n" + + /* 2 */ + "movl $2, %%eax ;\n" + "movd %%eax, %%xmm7 ;\n" + "pshufd $0x00, %%xmm7, %%xmm7 ;\n" + "pcmpeqd %%xmm6, %%xmm7 ;\n" + "movdqa 160(%1), %%xmm3 ;\n" + "movdqa 176(%1), %%xmm4 ;\n" + "pand %%xmm7, %%xmm3 ;\n" + "pand %%xmm7, %%xmm4 ;\n" + "por %%xmm3, %%xmm0 ;\n" + "por %%xmm4, %%xmm1 ;\n" + + /* 3 */ + "movl $3, %%eax ;\n" + "movd %%eax, %%xmm7 ;\n" + "pshufd $0x00, %%xmm7, %%xmm7 ;\n" + "pcmpeqd %%xmm6, %%xmm7 ;\n" + "movdqa 256(%1), %%xmm3 ;\n" + "movdqa 272(%1), %%xmm4 ;\n" + "pand %%xmm7, %%xmm3 ;\n" + "pand %%xmm7, %%xmm4 ;\n" + "por %%xmm3, %%xmm0 ;\n" + "por %%xmm4, %%xmm1 ;\n" + + /* 4 */ + "movl $4, %%eax ;\n" + "movd %%eax, %%xmm7 ;\n" + "pshufd $0x00, %%xmm7, %%xmm7 ;\n" + "pcmpeqd %%xmm6, %%xmm7 ;\n" + "movdqa 352(%1), %%xmm3 ;\n" + "movdqa 368(%1), %%xmm4 ;\n" + "pand %%xmm7, %%xmm3 ;\n" + "pand %%xmm7, %%xmm4 ;\n" + "por %%xmm3, %%xmm0 ;\n" + "por %%xmm4, %%xmm1 ;\n" + + /* 5 */ + "movl $5, %%eax ;\n" + "movd %%eax, %%xmm7 ;\n" + "pshufd $0x00, %%xmm7, %%xmm7 ;\n" + "pcmpeqd %%xmm6, %%xmm7 ;\n" + "movdqa 448(%1), %%xmm3 ;\n" + "movdqa 464(%1), %%xmm4 ;\n" + "pand %%xmm7, %%xmm3 ;\n" + "pand %%xmm7, %%xmm4 ;\n" + "por %%xmm3, %%xmm0 ;\n" + "por %%xmm4, %%xmm1 ;\n" + + /* 6 */ + "movl $6, %%eax ;\n" + "movd %%eax, %%xmm7 ;\n" + "pshufd $0x00, %%xmm7, %%xmm7 ;\n" + "pcmpeqd %%xmm6, %%xmm7 ;\n" + "movdqa 544(%1), %%xmm3 ;\n" + "movdqa 560(%1), %%xmm4 ;\n" + "pand %%xmm7, %%xmm3 ;\n" + "pand %%xmm7, %%xmm4 ;\n" + "por %%xmm3, %%xmm0 ;\n" + "por %%xmm4, %%xmm1 ;\n" + + /* 7 */ + "movl $7, %%eax ;\n" + "movd %%eax, %%xmm7 ;\n" + "pshufd $0x00, %%xmm7, %%xmm7 ;\n" + "pcmpeqd %%xmm6, %%xmm7 ;\n" + "movdqa 640(%1), %%xmm3 ;\n" + "movdqa 656(%1), %%xmm4 ;\n" + "pand %%xmm7, %%xmm3 ;\n" + "pand %%xmm7, %%xmm4 ;\n" + "por %%xmm3, %%xmm0 ;\n" + "por %%xmm4, %%xmm1 ;\n" + + /* 8 */ + "movl $8, %%eax ;\n" + "movd %%eax, %%xmm7 ;\n" + "pshufd $0x00, %%xmm7, %%xmm7 ;\n" + "pcmpeqd %%xmm6, %%xmm7 ;\n" + "movdqa 736(%1), %%xmm3 ;\n" + "movdqa 752(%1), %%xmm4 ;\n" + "pand %%xmm7, %%xmm3 ;\n" + "pand %%xmm7, %%xmm4 ;\n" + "por %%xmm3, %%xmm0 ;\n" + "por %%xmm4, %%xmm1 ;\n" + + /* store t2d */ + "movl %2, %%eax ;\n" + "addl $96, %%eax ;\n" + "movd %%xmm0, %%ecx ;\n" + "movl %%ecx, %%edx ;\n" + "pshufd $0x39, %%xmm0, %%xmm0 ;\n" + "andl $0x3ffffff, %%ecx ;\n" + "movl %%ecx, 0(%%eax) ;\n" + "movd %%xmm0, %%ecx ;\n" + "pshufd $0x39, %%xmm0, %%xmm0 ;\n" + "shrdl $26, %%ecx, %%edx ;\n" + "andl $0x1ffffff, %%edx ;\n" + "movl %%edx, 4(%%eax) ;\n" + "movd %%xmm0, %%edx ;\n" + "pshufd $0x39, %%xmm0, %%xmm0 ;\n" + "shrdl $19, %%edx, %%ecx ;\n" + "andl $0x3ffffff, %%ecx ;\n" + "movl %%ecx, 8(%%eax) ;\n" + "movd %%xmm0, %%ecx ;\n" + "shrdl $13, %%ecx, %%edx ;\n" + "andl $0x1ffffff, %%edx ;\n" + "movl %%edx, 12(%%eax) ;\n" + "movd %%xmm1, %%edx ;\n" + "pshufd $0x39, %%xmm1, %%xmm1 ;\n" + "shrl $6, %%ecx ;\n" + "andl $0x3ffffff, %%ecx ;\n" + "movl %%ecx, 16(%%eax) ;\n" + "movl %%edx, %%ecx ;\n" + "andl $0x1ffffff, %%edx ;\n" + "movl %%edx, 20(%%eax) ;\n" + "movd %%xmm1, %%edx ;\n" + "pshufd $0x39, %%xmm1, %%xmm1 ;\n" + "shrdl $25, %%edx, %%ecx ;\n" + "andl $0x3ffffff, %%ecx ;\n" + "movl %%ecx, 24(%%eax) ;\n" + "movd %%xmm1, %%ecx ;\n" + "pshufd $0x39, %%xmm1, %%xmm1 ;\n" + "shrdl $19, %%ecx, %%edx ;\n" + "andl $0x1ffffff, %%edx ;\n" + "movl %%edx, 28(%%eax) ;\n" + "movd %%xmm1, %%edx ;\n" + "movd %%xmm1, %%edx ;\n" + "shrdl $12, %%edx, %%ecx ;\n" + "andl $0x3ffffff, %%ecx ;\n" + "movl %%ecx, 32(%%eax) ;\n" + "shrl $6, %%edx ;\n" + "andl $0x1ffffff, %%edx ;\n" + "xorl %%ecx, %%ecx ;\n" + "movl %%edx, 36(%%eax) ;\n" + "movl %%ecx, 40(%%eax) ;\n" + "movl %%ecx, 44(%%eax) ;\n" + "movdqa 0(%%eax), %%xmm0 ;\n" + "movdqa 16(%%eax), %%xmm1 ;\n" + "movdqa 32(%%eax), %%xmm2 ;\n" + + /* conditionally negate t2d */ + + /* set up 2p in to 3/4 */ + "movl $0x7ffffda, %%ecx ;\n" + "movl $0x3fffffe, %%edx ;\n" + "movd %%ecx, %%xmm3 ;\n" + "movd %%edx, %%xmm5 ;\n" + "movl $0x7fffffe, %%ecx ;\n" + "movd %%ecx, %%xmm4 ;\n" + "punpckldq %%xmm5, %%xmm3 ;\n" + "punpckldq %%xmm5, %%xmm4 ;\n" + "punpcklqdq %%xmm4, %%xmm3 ;\n" + "movdqa %%xmm4, %%xmm5 ;\n" + "punpcklqdq %%xmm4, %%xmm4 ;\n" + + /* subtract and conditionally move */ + "movl %3, %%ecx ;\n" + "sub $1, %%ecx ;\n" + "movd %%ecx, %%xmm6 ;\n" + "pshufd $0x00, %%xmm6, %%xmm6 ;\n" + "movdqa %%xmm6, %%xmm7 ;\n" + "psubd %%xmm0, %%xmm3 ;\n" + "psubd %%xmm1, %%xmm4 ;\n" + "psubd %%xmm2, %%xmm5 ;\n" + "pand %%xmm6, %%xmm0 ;\n" + "pand %%xmm6, %%xmm1 ;\n" + "pand %%xmm6, %%xmm2 ;\n" + "pandn %%xmm3, %%xmm6 ;\n" + "movdqa %%xmm7, %%xmm3 ;\n" + "pandn %%xmm4, %%xmm7 ;\n" + "pandn %%xmm5, %%xmm3 ;\n" + "por %%xmm6, %%xmm0 ;\n" + "por %%xmm7, %%xmm1 ;\n" + "por %%xmm3, %%xmm2 ;\n" + + /* store */ + "movdqa %%xmm0, 0(%%eax) ;\n" + "movdqa %%xmm1, 16(%%eax) ;\n" + "movdqa %%xmm2, 32(%%eax) ;\n" + : + : "m"(u), "r"(&table[pos * 8]), "m"(t), "m"(sign) /* %0 = u, %1 = table, %2 = t, %3 = sign */ + : "%eax", "%ecx", "%edx", "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "%xmm7", "cc", "memory" + ); +} + +#endif /* defined(ED25519_GCC_32BIT_SSE_CHOOSE) */ + diff --git a/ed25519-donna/ed25519-donna-32bit-tables.h b/ed25519-donna/ed25519-donna-32bit-tables.h new file mode 100644 index 000000000..c977c26eb --- /dev/null +++ b/ed25519-donna/ed25519-donna-32bit-tables.h @@ -0,0 +1,61 @@ +static const ge25519 ALIGN(16) ge25519_basepoint = { + {0x0325d51a,0x018b5823,0x00f6592a,0x0104a92d,0x01a4b31d,0x01d6dc5c,0x027118fe,0x007fd814,0x013cd6e5,0x0085a4db}, + {0x02666658,0x01999999,0x00cccccc,0x01333333,0x01999999,0x00666666,0x03333333,0x00cccccc,0x02666666,0x01999999}, + {0x00000001,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000}, + {0x01b7dda3,0x01a2ace9,0x025eadbb,0x0003ba8a,0x0083c27e,0x00abe37d,0x01274732,0x00ccacdd,0x00fd78b7,0x019e1d7c} +}; + +/* + d +*/ + +static const bignum25519 ALIGN(16) ge25519_ecd = { + 0x035978a3,0x00d37284,0x03156ebd,0x006a0a0e,0x0001c029,0x0179e898,0x03a03cbb,0x01ce7198,0x02e2b6ff,0x01480db3 +}; + +static const bignum25519 ALIGN(16) ge25519_ec2d = { + 0x02b2f159,0x01a6e509,0x022add7a,0x00d4141d,0x00038052,0x00f3d130,0x03407977,0x019ce331,0x01c56dff,0x00901b67 +}; + +/* + sqrt(-1) +*/ + +static const bignum25519 ALIGN(16) ge25519_sqrtneg1 = { + 0x020ea0b0,0x0186c9d2,0x008f189d,0x0035697f,0x00bd0c60,0x01fbd7a7,0x02804c9e,0x01e16569,0x0004fc1d,0x00ae0c92 +}; + +static const ge25519_niels ALIGN(16) ge25519_niels_sliding_multiples[32] = { + {{0x0340913e,0x000e4175,0x03d673a2,0x002e8a05,0x03f4e67c,0x008f8a09,0x00c21a34,0x004cf4b8,0x01298f81,0x0113f4be},{0x018c3b85,0x0124f1bd,0x01c325f7,0x0037dc60,0x033e4cb7,0x003d42c2,0x01a44c32,0x014ca4e1,0x03a33d4b,0x001f3e74},{0x037aaa68,0x00448161,0x0093d579,0x011e6556,0x009b67a0,0x0143598c,0x01bee5ee,0x00b50b43,0x0289f0c6,0x01bc45ed}}, + {{0x00fcd265,0x0047fa29,0x034faacc,0x01ef2e0d,0x00ef4d4f,0x014bd6bd,0x00f98d10,0x014c5026,0x007555bd,0x00aae456},{0x00ee9730,0x016c2a13,0x017155e4,0x01874432,0x00096a10,0x01016732,0x01a8014f,0x011e9823,0x01b9a80f,0x01e85938},{0x01d0d889,0x01a4cfc3,0x034c4295,0x0110e1ae,0x0162508c,0x00f2db4c,0x0072a2c6,0x0098da2e,0x02f12b9b,0x0168a09a}}, + {{0x0047d6ba,0x0060b0e9,0x0136eff2,0x008a5939,0x03540053,0x0064a087,0x02788e5c,0x00be7c67,0x033eb1b5,0x005529f9},{0x00a5bb33,0x00af1102,0x01a05442,0x001e3af7,0x02354123,0x00bfec44,0x01f5862d,0x00dd7ba3,0x03146e20,0x00a51733},{0x012a8285,0x00f6fc60,0x023f9797,0x003e85ee,0x009c3820,0x01bda72d,0x01b3858d,0x00d35683,0x0296b3bb,0x010eaaf9}}, + {{0x023221b1,0x01cb26aa,0x0074f74d,0x0099ddd1,0x01b28085,0x00192c3a,0x013b27c9,0x00fc13bd,0x01d2e531,0x0075bb75},{0x004ea3bf,0x00973425,0x001a4d63,0x01d59cee,0x01d1c0d4,0x00542e49,0x01294114,0x004fce36,0x029283c9,0x01186fa9},{0x01b8b3a2,0x00db7200,0x00935e30,0x003829f5,0x02cc0d7d,0x0077adf3,0x0220dd2c,0x0014ea53,0x01c6a0f9,0x01ea7eec}}, + {{0x039d8064,0x01885f80,0x00337e6d,0x01b7a902,0x02628206,0x015eb044,0x01e30473,0x0191f2d9,0x011fadc9,0x01270169},{0x02a8632f,0x0199e2a9,0x00d8b365,0x017a8de2,0x02994279,0x0086f5b5,0x0119e4e3,0x01eb39d6,0x0338add7,0x00d2e7b4},{0x0045af1b,0x013a2fe4,0x0245e0d6,0x014538ce,0x038bfe0f,0x01d4cf16,0x037e14c9,0x0160d55e,0x0021b008,0x01cf05c8}}, + {{0x01864348,0x01d6c092,0x0070262b,0x014bb844,0x00fb5acd,0x008deb95,0x003aaab5,0x00eff474,0x00029d5c,0x0062ad66},{0x02802ade,0x01c02122,0x01c4e5f7,0x00781181,0x039767fb,0x01703406,0x0342388b,0x01f5e227,0x022546d8,0x0109d6ab},{0x016089e9,0x00cb317f,0x00949b05,0x01099417,0x000c7ad2,0x011a8622,0x0088ccda,0x01290886,0x022b53df,0x00f71954}}, + {{0x027fbf93,0x01c04ecc,0x01ed6a0d,0x004cdbbb,0x02bbf3af,0x00ad5968,0x01591955,0x0094f3a2,0x02d17602,0x00099e20},{0x02007f6d,0x003088a8,0x03db77ee,0x00d5ade6,0x02fe12ce,0x0107ba07,0x0107097d,0x00482a6f,0x02ec346f,0x008d3f5f},{0x032ea378,0x0028465c,0x028e2a6c,0x018efc6e,0x0090df9a,0x01a7e533,0x039bfc48,0x010c745d,0x03daa097,0x0125ee9b}}, + {{0x028ccf0b,0x00f36191,0x021ac081,0x012154c8,0x034e0a6e,0x01b25192,0x00180403,0x01d7eea1,0x00218d05,0x010ed735},{0x03cfeaa0,0x01b300c4,0x008da499,0x0068c4e1,0x0219230a,0x01f2d4d0,0x02defd60,0x00e565b7,0x017f12de,0x018788a4},{0x03d0b516,0x009d8be6,0x03ddcbb3,0x0071b9fe,0x03ace2bd,0x01d64270,0x032d3ec9,0x01084065,0x0210ae4d,0x01447584}}, + {{0x0020de87,0x00e19211,0x01b68102,0x00b5ac97,0x022873c0,0x01942d25,0x01271394,0x0102073f,0x02fe2482,0x01c69ff9},{0x010e9d81,0x019dbbe5,0x0089f258,0x006e06b8,0x02951883,0x018f1248,0x019b3237,0x00bc7553,0x024ddb85,0x01b4c964},{0x01c8c854,0x0060ae29,0x01406d8e,0x01cff2f9,0x00cff451,0x01778d0c,0x03ac8c41,0x01552e59,0x036559ee,0x011d1b12}}, + {{0x00741147,0x0151b219,0x01092690,0x00e877e6,0x01f4d6bb,0x0072a332,0x01cd3b03,0x00dadff2,0x0097db5e,0x0086598d},{0x01c69a2b,0x01decf1b,0x02c2fa6e,0x013b7c4f,0x037beac8,0x013a16b5,0x028e7bda,0x01f6e8ac,0x01e34fe9,0x01726947},{0x01f10e67,0x003c73de,0x022b7ea2,0x010f32c2,0x03ff776a,0x00142277,0x01d38b88,0x00776138,0x03c60822,0x01201140}}, + {{0x0236d175,0x0008748e,0x03c6476d,0x013f4cdc,0x02eed02a,0x00838a47,0x032e7210,0x018bcbb3,0x00858de4,0x01dc7826},{0x00a37fc7,0x0127b40b,0x01957884,0x011d30ad,0x02816683,0x016e0e23,0x00b76be4,0x012db115,0x02516506,0x0154ce62},{0x00451edf,0x00bd749e,0x03997342,0x01cc2c4c,0x00eb6975,0x01a59508,0x03a516cf,0x00c228ef,0x0168ff5a,0x01697b47}}, + {{0x00527359,0x01783156,0x03afd75c,0x00ce56dc,0x00e4b970,0x001cabe9,0x029e0f6d,0x0188850c,0x0135fefd,0x00066d80},{0x02150e83,0x01448abf,0x02bb0232,0x012bf259,0x033c8268,0x00711e20,0x03fc148f,0x005e0e70,0x017d8bf9,0x0112b2e2},{0x02134b83,0x001a0517,0x0182c3cc,0x00792182,0x0313d799,0x001a3ed7,0x0344547e,0x01f24a0d,0x03de6ad2,0x00543127}}, + {{0x00dca868,0x00618f27,0x015a1709,0x00ddc38a,0x0320fd13,0x0036168d,0x0371ab06,0x01783fc7,0x0391e05f,0x01e29b5d},{0x01471138,0x00fca542,0x00ca31cf,0x01ca7bad,0x0175bfbc,0x01a708ad,0x03bce212,0x01244215,0x0075bb99,0x01acad68},{0x03a0b976,0x01dc12d1,0x011aab17,0x00aba0ba,0x029806cd,0x0142f590,0x018fd8ea,0x01a01545,0x03c4ad55,0x01c971ff}}, + {{0x00d098c0,0x000afdc7,0x006cd230,0x01276af3,0x03f905b2,0x0102994c,0x002eb8a4,0x015cfbeb,0x025f855f,0x01335518},{0x01cf99b2,0x0099c574,0x01a69c88,0x00881510,0x01cd4b54,0x0112109f,0x008abdc5,0x0074647a,0x0277cb1f,0x01e53324},{0x02ac5053,0x01b109b0,0x024b095e,0x016997b3,0x02f26bb6,0x00311021,0x00197885,0x01d0a55a,0x03b6fcc8,0x01c020d5}}, + {{0x02584a34,0x00e7eee0,0x03257a03,0x011e95a3,0x011ead91,0x00536202,0x00b1ce24,0x008516c6,0x03669d6d,0x004ea4a8},{0x00773f01,0x0019c9ce,0x019f6171,0x01d4afde,0x02e33323,0x01ad29b6,0x02ead1dc,0x01ed51a5,0x01851ad0,0x001bbdfa},{0x00577de5,0x00ddc730,0x038b9952,0x00f281ae,0x01d50390,0x0002e071,0x000780ec,0x010d448d,0x01f8a2af,0x00f0a5b7}}, + {{0x031f2541,0x00d34bae,0x0323ff9d,0x003a056d,0x02e25443,0x00a1ad05,0x00d1bee8,0x002f7f8e,0x03007477,0x002a24b1},{0x0114a713,0x01457e76,0x032255d5,0x01cc647f,0x02a4bdef,0x0153d730,0x00118bcf,0x00f755ff,0x013490c7,0x01ea674e},{0x02bda3e8,0x00bb490d,0x00f291ea,0x000abf40,0x01dea321,0x002f9ce0,0x00b2b193,0x00fa54b5,0x0128302f,0x00a19d8b}}, + {{0x022ef5bd,0x01638af3,0x038c6f8a,0x01a33a3d,0x039261b2,0x01bb89b8,0x010bcf9d,0x00cf42a9,0x023d6f17,0x01da1bca},{0x00e35b25,0x000d824f,0x0152e9cf,0x00ed935d,0x020b8460,0x01c7b83f,0x00c969e5,0x01a74198,0x0046a9d9,0x00cbc768},{0x01597c6a,0x0144a99b,0x00a57551,0x0018269c,0x023c464c,0x0009b022,0x00ee39e1,0x0114c7f2,0x038a9ad2,0x01584c17}}, + {{0x03b0c0d5,0x00b30a39,0x038a6ce4,0x01ded83a,0x01c277a6,0x01010a61,0x0346d3eb,0x018d995e,0x02f2c57c,0x000c286b},{0x0092aed1,0x0125e37b,0x027ca201,0x001a6b6b,0x03290f55,0x0047ba48,0x018d916c,0x01a59062,0x013e35d4,0x0002abb1},{0x003ad2aa,0x007ddcc0,0x00c10f76,0x0001590b,0x002cfca6,0x000ed23e,0x00ee4329,0x00900f04,0x01c24065,0x0082fa70}}, + {{0x02025e60,0x003912b8,0x0327041c,0x017e5ee5,0x02c0ecec,0x015a0d1c,0x02b1ce7c,0x0062220b,0x0145067e,0x01a5d931},{0x009673a6,0x00e1f609,0x00927c2a,0x016faa37,0x01650ef0,0x016f63b5,0x03cd40e1,0x003bc38f,0x0361f0ac,0x01d42acc},{0x02f81037,0x008ca0e8,0x017e23d1,0x011debfe,0x01bcbb68,0x002e2563,0x03e8add6,0x000816e5,0x03fb7075,0x0153e5ac}}, + {{0x02b11ecd,0x016bf185,0x008f22ef,0x00e7d2bb,0x0225d92e,0x00ece785,0x00508873,0x017e16f5,0x01fbe85d,0x01e39a0e},{0x01669279,0x017c810a,0x024941f5,0x0023ebeb,0x00eb7688,0x005760f1,0x02ca4146,0x0073cde7,0x0052bb75,0x00f5ffa7},{0x03b8856b,0x00cb7dcd,0x02f14e06,0x001820d0,0x01d74175,0x00e59e22,0x03fba550,0x00484641,0x03350088,0x01c3c9a3}}, + {{0x00dcf355,0x0104481c,0x0022e464,0x01f73fe7,0x00e03325,0x0152b698,0x02ef769a,0x00973663,0x00039b8c,0x0101395b},{0x01805f47,0x019160ec,0x03832cd0,0x008b06eb,0x03d4d717,0x004cb006,0x03a75b8f,0x013b3d30,0x01cfad88,0x01f034d1},{0x0078338a,0x01c7d2e3,0x02bc2b23,0x018b3f05,0x0280d9aa,0x005f3d44,0x0220a95a,0x00eeeb97,0x0362aaec,0x00835d51}}, + {{0x01b9f543,0x013fac4d,0x02ad93ae,0x018ef464,0x0212cdf7,0x01138ba9,0x011583ab,0x019c3d26,0x028790b4,0x00e2e2b6},{0x033bb758,0x01f0dbf1,0x03734bd1,0x0129b1e5,0x02b3950e,0x003bc922,0x01a53ec8,0x018c5532,0x006f3cee,0x00ae3c79},{0x0351f95d,0x0012a737,0x03d596b8,0x017658fe,0x00ace54a,0x008b66da,0x0036c599,0x012a63a2,0x032ceba1,0x00126bac}}, + {{0x03dcfe7e,0x019f4f18,0x01c81aee,0x0044bc2b,0x00827165,0x014f7c13,0x03b430f0,0x00bf96cc,0x020c8d62,0x01471997},{0x01fc7931,0x001f42dd,0x00ba754a,0x005bd339,0x003fbe49,0x016b3930,0x012a159c,0x009f83b0,0x03530f67,0x01e57b85},{0x02ecbd81,0x0096c294,0x01fce4a9,0x017701a5,0x0175047d,0x00ee4a31,0x012686e5,0x008efcd4,0x0349dc54,0x01b3466f}}, + {{0x02179ca3,0x01d86414,0x03f0afd0,0x00305964,0x015c7428,0x0099711e,0x015d5442,0x00c71014,0x01b40b2e,0x01d483cf},{0x01afc386,0x01984859,0x036203ff,0x0045c6a8,0x0020a8aa,0x00990baa,0x03313f10,0x007ceede,0x027429e4,0x017806ce},{0x039357a1,0x0142f8f4,0x0294a7b6,0x00eaccf4,0x0259edb3,0x01311e6e,0x004d326f,0x0130c346,0x01ccef3c,0x01c424b2}}, + {{0x0364918c,0x00148fc0,0x01638a7b,0x01a1fd5b,0x028ad013,0x0081e5a4,0x01a54f33,0x0174e101,0x003d0257,0x003a856c},{0x00051dcf,0x00f62b1d,0x0143d0ad,0x0042adbd,0x000fda90,0x01743ceb,0x0173e5e4,0x017bc749,0x03b7137a,0x0105ce96},{0x00f9218a,0x015b8c7c,0x00e102f8,0x0158d7e2,0x0169a5b8,0x00b2f176,0x018b347a,0x014cfef2,0x0214a4e3,0x017f1595}}, + {{0x006d7ae5,0x0195c371,0x0391e26d,0x0062a7c6,0x003f42ab,0x010dad86,0x024f8198,0x01542b2a,0x0014c454,0x0189c471},{0x0390988e,0x00b8799d,0x02e44912,0x0078e2e6,0x00075654,0x01923eed,0x0040cd72,0x00a37c76,0x0009d466,0x00c8531d},{0x02651770,0x00609d01,0x0286c265,0x0134513c,0x00ee9281,0x005d223c,0x035c760c,0x00679b36,0x0073ecb8,0x016faa50}}, + {{0x02c89be4,0x016fc244,0x02f38c83,0x018beb72,0x02b3ce2c,0x0097b065,0x034f017b,0x01dd957f,0x00148f61,0x00eab357},{0x0343d2f8,0x003398fc,0x011e368e,0x00782a1f,0x00019eea,0x00117b6f,0x0128d0d1,0x01a5e6bb,0x01944f1b,0x012b41e1},{0x03318301,0x018ecd30,0x0104d0b1,0x0038398b,0x03726701,0x019da88c,0x002d9769,0x00a7a681,0x031d9028,0x00ebfc32}}, + {{0x0220405e,0x0171face,0x02d930f8,0x017f6d6a,0x023b8c47,0x0129d5f9,0x02972456,0x00a3a524,0x006f4cd2,0x004439fa},{0x00c53505,0x0190c2fd,0x00507244,0x009930f9,0x01a39270,0x01d327c6,0x0399bc47,0x01cfe13d,0x0332bd99,0x00b33e7d},{0x0203f5e4,0x003627b5,0x00018af8,0x01478581,0x004a2218,0x002e3bb7,0x039384d0,0x0146ea62,0x020b9693,0x0017155f}}, + {{0x03c97e6f,0x00738c47,0x03b5db1f,0x01808fcf,0x01e8fc98,0x01ed25dd,0x01bf5045,0x00eb5c2b,0x0178fe98,0x01b85530},{0x01c20eb0,0x01aeec22,0x030b9eee,0x01b7d07e,0x0187e16f,0x014421fb,0x009fa731,0x0040b6d7,0x00841861,0x00a27fbc},{0x02d69abf,0x0058cdbf,0x0129f9ec,0x013c19ae,0x026c5b93,0x013a7fe7,0x004bb2ba,0x0063226f,0x002a95ca,0x01abefd9}}, + {{0x02f5d2c1,0x00378318,0x03734fb5,0x01258073,0x0263f0f6,0x01ad70e0,0x01b56d06,0x01188fbd,0x011b9503,0x0036d2e1},{0x0113a8cc,0x01541c3e,0x02ac2bbc,0x01d95867,0x01f47459,0x00ead489,0x00ab5b48,0x01db3b45,0x00edb801,0x004b024f},{0x00b8190f,0x011fe4c2,0x00621f82,0x010508d7,0x001a5a76,0x00c7d7fd,0x03aab96d,0x019cd9dc,0x019c6635,0x00ceaa1e}}, + {{0x01085cf2,0x01fd47af,0x03e3f5e1,0x004b3e99,0x01e3d46a,0x0060033c,0x015ff0a8,0x0150cdd8,0x029e8e21,0x008cf1bc},{0x00156cb1,0x003d623f,0x01a4f069,0x00d8d053,0x01b68aea,0x01ca5ab6,0x0316ae43,0x0134dc44,0x001c8d58,0x0084b343},{0x0318c781,0x0135441f,0x03a51a5e,0x019293f4,0x0048bb37,0x013d3341,0x0143151e,0x019c74e1,0x00911914,0x0076ddde}}, + {{0x006bc26f,0x00d48e5f,0x00227bbe,0x00629ea8,0x01ea5f8b,0x0179a330,0x027a1d5f,0x01bf8f8e,0x02d26e2a,0x00c6b65e},{0x01701ab6,0x0051da77,0x01b4b667,0x00a0ce7c,0x038ae37b,0x012ac852,0x03a0b0fe,0x0097c2bb,0x00a017d2,0x01eb8b2a},{0x0120b962,0x0005fb42,0x0353b6fd,0x0061f8ce,0x007a1463,0x01560a64,0x00e0a792,0x01907c92,0x013a6622,0x007b47f1}} +}; diff --git a/ed25519-donna/ed25519-donna-64bit-sse2.h b/ed25519-donna/ed25519-donna-64bit-sse2.h new file mode 100644 index 000000000..ca08651d6 --- /dev/null +++ b/ed25519-donna/ed25519-donna-64bit-sse2.h @@ -0,0 +1,436 @@ +#if defined(ED25519_GCC_64BIT_SSE_CHOOSE) + +#define HAVE_GE25519_SCALARMULT_BASE_CHOOSE_NIELS + +DONNA_NOINLINE static void +ge25519_scalarmult_base_choose_niels(ge25519_niels *t, const uint8_t table[256][96], uint32_t pos, signed char b) { + int64_t breg = (int64_t)b; + uint64_t sign = (uint64_t)breg >> 63; + uint64_t mask = ~(sign - 1); + uint64_t u = (breg + mask) ^ mask; + + __asm__ __volatile__ ( + /* ysubx+xaddy+t2d */ + "movq %0, %%rax ;\n" + "movd %%rax, %%xmm14 ;\n" + "pshufd $0x00, %%xmm14, %%xmm14 ;\n" + "pxor %%xmm0, %%xmm0 ;\n" + "pxor %%xmm1, %%xmm1 ;\n" + "pxor %%xmm2, %%xmm2 ;\n" + "pxor %%xmm3, %%xmm3 ;\n" + "pxor %%xmm4, %%xmm4 ;\n" + "pxor %%xmm5, %%xmm5 ;\n" + + /* 0 */ + "movq $0, %%rax ;\n" + "movd %%rax, %%xmm15 ;\n" + "pshufd $0x00, %%xmm15, %%xmm15 ;\n" + "pcmpeqd %%xmm14, %%xmm15 ;\n" + "movq $1, %%rax ;\n" + "movd %%rax, %%xmm6 ;\n" + "pxor %%xmm7, %%xmm7 ;\n" + "pand %%xmm15, %%xmm6 ;\n" + "pand %%xmm15, %%xmm7 ;\n" + "por %%xmm6, %%xmm0 ;\n" + "por %%xmm7, %%xmm1 ;\n" + "por %%xmm6, %%xmm2 ;\n" + "por %%xmm7, %%xmm3 ;\n" + + /* 1 */ + "movq $1, %%rax ;\n" + "movd %%rax, %%xmm15 ;\n" + "pshufd $0x00, %%xmm15, %%xmm15 ;\n" + "pcmpeqd %%xmm14, %%xmm15 ;\n" + "movdqa 0(%1), %%xmm6 ;\n" + "movdqa 16(%1), %%xmm7 ;\n" + "movdqa 32(%1), %%xmm8 ;\n" + "movdqa 48(%1), %%xmm9 ;\n" + "movdqa 64(%1), %%xmm10 ;\n" + "movdqa 80(%1), %%xmm11 ;\n" + "pand %%xmm15, %%xmm6 ;\n" + "pand %%xmm15, %%xmm7 ;\n" + "pand %%xmm15, %%xmm8 ;\n" + "pand %%xmm15, %%xmm9 ;\n" + "pand %%xmm15, %%xmm10 ;\n" + "pand %%xmm15, %%xmm11 ;\n" + "por %%xmm6, %%xmm0 ;\n" + "por %%xmm7, %%xmm1 ;\n" + "por %%xmm8, %%xmm2 ;\n" + "por %%xmm9, %%xmm3 ;\n" + "por %%xmm10, %%xmm4 ;\n" + "por %%xmm11, %%xmm5 ;\n" + + /* 2 */ + "movq $2, %%rax ;\n" + "movd %%rax, %%xmm15 ;\n" + "pshufd $0x00, %%xmm15, %%xmm15 ;\n" + "pcmpeqd %%xmm14, %%xmm15 ;\n" + "movdqa 96(%1), %%xmm6 ;\n" + "movdqa 112(%1), %%xmm7 ;\n" + "movdqa 128(%1), %%xmm8 ;\n" + "movdqa 144(%1), %%xmm9 ;\n" + "movdqa 160(%1), %%xmm10 ;\n" + "movdqa 176(%1), %%xmm11 ;\n" + "pand %%xmm15, %%xmm6 ;\n" + "pand %%xmm15, %%xmm7 ;\n" + "pand %%xmm15, %%xmm8 ;\n" + "pand %%xmm15, %%xmm9 ;\n" + "pand %%xmm15, %%xmm10 ;\n" + "pand %%xmm15, %%xmm11 ;\n" + "por %%xmm6, %%xmm0 ;\n" + "por %%xmm7, %%xmm1 ;\n" + "por %%xmm8, %%xmm2 ;\n" + "por %%xmm9, %%xmm3 ;\n" + "por %%xmm10, %%xmm4 ;\n" + "por %%xmm11, %%xmm5 ;\n" + + /* 3 */ + "movq $3, %%rax ;\n" + "movd %%rax, %%xmm15 ;\n" + "pshufd $0x00, %%xmm15, %%xmm15 ;\n" + "pcmpeqd %%xmm14, %%xmm15 ;\n" + "movdqa 192(%1), %%xmm6 ;\n" + "movdqa 208(%1), %%xmm7 ;\n" + "movdqa 224(%1), %%xmm8 ;\n" + "movdqa 240(%1), %%xmm9 ;\n" + "movdqa 256(%1), %%xmm10 ;\n" + "movdqa 272(%1), %%xmm11 ;\n" + "pand %%xmm15, %%xmm6 ;\n" + "pand %%xmm15, %%xmm7 ;\n" + "pand %%xmm15, %%xmm8 ;\n" + "pand %%xmm15, %%xmm9 ;\n" + "pand %%xmm15, %%xmm10 ;\n" + "pand %%xmm15, %%xmm11 ;\n" + "por %%xmm6, %%xmm0 ;\n" + "por %%xmm7, %%xmm1 ;\n" + "por %%xmm8, %%xmm2 ;\n" + "por %%xmm9, %%xmm3 ;\n" + "por %%xmm10, %%xmm4 ;\n" + "por %%xmm11, %%xmm5 ;\n" + + /* 4 */ + "movq $4, %%rax ;\n" + "movd %%rax, %%xmm15 ;\n" + "pshufd $0x00, %%xmm15, %%xmm15 ;\n" + "pcmpeqd %%xmm14, %%xmm15 ;\n" + "movdqa 288(%1), %%xmm6 ;\n" + "movdqa 304(%1), %%xmm7 ;\n" + "movdqa 320(%1), %%xmm8 ;\n" + "movdqa 336(%1), %%xmm9 ;\n" + "movdqa 352(%1), %%xmm10 ;\n" + "movdqa 368(%1), %%xmm11 ;\n" + "pand %%xmm15, %%xmm6 ;\n" + "pand %%xmm15, %%xmm7 ;\n" + "pand %%xmm15, %%xmm8 ;\n" + "pand %%xmm15, %%xmm9 ;\n" + "pand %%xmm15, %%xmm10 ;\n" + "pand %%xmm15, %%xmm11 ;\n" + "por %%xmm6, %%xmm0 ;\n" + "por %%xmm7, %%xmm1 ;\n" + "por %%xmm8, %%xmm2 ;\n" + "por %%xmm9, %%xmm3 ;\n" + "por %%xmm10, %%xmm4 ;\n" + "por %%xmm11, %%xmm5 ;\n" + + /* 5 */ + "movq $5, %%rax ;\n" + "movd %%rax, %%xmm15 ;\n" + "pshufd $0x00, %%xmm15, %%xmm15 ;\n" + "pcmpeqd %%xmm14, %%xmm15 ;\n" + "movdqa 384(%1), %%xmm6 ;\n" + "movdqa 400(%1), %%xmm7 ;\n" + "movdqa 416(%1), %%xmm8 ;\n" + "movdqa 432(%1), %%xmm9 ;\n" + "movdqa 448(%1), %%xmm10 ;\n" + "movdqa 464(%1), %%xmm11 ;\n" + "pand %%xmm15, %%xmm6 ;\n" + "pand %%xmm15, %%xmm7 ;\n" + "pand %%xmm15, %%xmm8 ;\n" + "pand %%xmm15, %%xmm9 ;\n" + "pand %%xmm15, %%xmm10 ;\n" + "pand %%xmm15, %%xmm11 ;\n" + "por %%xmm6, %%xmm0 ;\n" + "por %%xmm7, %%xmm1 ;\n" + "por %%xmm8, %%xmm2 ;\n" + "por %%xmm9, %%xmm3 ;\n" + "por %%xmm10, %%xmm4 ;\n" + "por %%xmm11, %%xmm5 ;\n" + + /* 6 */ + "movq $6, %%rax ;\n" + "movd %%rax, %%xmm15 ;\n" + "pshufd $0x00, %%xmm15, %%xmm15 ;\n" + "pcmpeqd %%xmm14, %%xmm15 ;\n" + "movdqa 480(%1), %%xmm6 ;\n" + "movdqa 496(%1), %%xmm7 ;\n" + "movdqa 512(%1), %%xmm8 ;\n" + "movdqa 528(%1), %%xmm9 ;\n" + "movdqa 544(%1), %%xmm10 ;\n" + "movdqa 560(%1), %%xmm11 ;\n" + "pand %%xmm15, %%xmm6 ;\n" + "pand %%xmm15, %%xmm7 ;\n" + "pand %%xmm15, %%xmm8 ;\n" + "pand %%xmm15, %%xmm9 ;\n" + "pand %%xmm15, %%xmm10 ;\n" + "pand %%xmm15, %%xmm11 ;\n" + "por %%xmm6, %%xmm0 ;\n" + "por %%xmm7, %%xmm1 ;\n" + "por %%xmm8, %%xmm2 ;\n" + "por %%xmm9, %%xmm3 ;\n" + "por %%xmm10, %%xmm4 ;\n" + "por %%xmm11, %%xmm5 ;\n" + + /* 7 */ + "movq $7, %%rax ;\n" + "movd %%rax, %%xmm15 ;\n" + "pshufd $0x00, %%xmm15, %%xmm15 ;\n" + "pcmpeqd %%xmm14, %%xmm15 ;\n" + "movdqa 576(%1), %%xmm6 ;\n" + "movdqa 592(%1), %%xmm7 ;\n" + "movdqa 608(%1), %%xmm8 ;\n" + "movdqa 624(%1), %%xmm9 ;\n" + "movdqa 640(%1), %%xmm10 ;\n" + "movdqa 656(%1), %%xmm11 ;\n" + "pand %%xmm15, %%xmm6 ;\n" + "pand %%xmm15, %%xmm7 ;\n" + "pand %%xmm15, %%xmm8 ;\n" + "pand %%xmm15, %%xmm9 ;\n" + "pand %%xmm15, %%xmm10 ;\n" + "pand %%xmm15, %%xmm11 ;\n" + "por %%xmm6, %%xmm0 ;\n" + "por %%xmm7, %%xmm1 ;\n" + "por %%xmm8, %%xmm2 ;\n" + "por %%xmm9, %%xmm3 ;\n" + "por %%xmm10, %%xmm4 ;\n" + "por %%xmm11, %%xmm5 ;\n" + + /* 8 */ + "movq $8, %%rax ;\n" + "movd %%rax, %%xmm15 ;\n" + "pshufd $0x00, %%xmm15, %%xmm15 ;\n" + "pcmpeqd %%xmm14, %%xmm15 ;\n" + "movdqa 672(%1), %%xmm6 ;\n" + "movdqa 688(%1), %%xmm7 ;\n" + "movdqa 704(%1), %%xmm8 ;\n" + "movdqa 720(%1), %%xmm9 ;\n" + "movdqa 736(%1), %%xmm10 ;\n" + "movdqa 752(%1), %%xmm11 ;\n" + "pand %%xmm15, %%xmm6 ;\n" + "pand %%xmm15, %%xmm7 ;\n" + "pand %%xmm15, %%xmm8 ;\n" + "pand %%xmm15, %%xmm9 ;\n" + "pand %%xmm15, %%xmm10 ;\n" + "pand %%xmm15, %%xmm11 ;\n" + "por %%xmm6, %%xmm0 ;\n" + "por %%xmm7, %%xmm1 ;\n" + "por %%xmm8, %%xmm2 ;\n" + "por %%xmm9, %%xmm3 ;\n" + "por %%xmm10, %%xmm4 ;\n" + "por %%xmm11, %%xmm5 ;\n" + + /* conditionally swap ysubx and xaddy */ + "movq %3, %%rax ;\n" + "xorq $1, %%rax ;\n" + "movd %%rax, %%xmm14 ;\n" + "pxor %%xmm15, %%xmm15 ;\n" + "pshufd $0x00, %%xmm14, %%xmm14 ;\n" + "pxor %%xmm0, %%xmm2 ;\n" + "pxor %%xmm1, %%xmm3 ;\n" + "pcmpeqd %%xmm14, %%xmm15 ;\n" + "movdqa %%xmm2, %%xmm6 ;\n" + "movdqa %%xmm3, %%xmm7 ;\n" + "pand %%xmm15, %%xmm6 ;\n" + "pand %%xmm15, %%xmm7 ;\n" + "pxor %%xmm6, %%xmm0 ;\n" + "pxor %%xmm7, %%xmm1 ;\n" + "pxor %%xmm0, %%xmm2 ;\n" + "pxor %%xmm1, %%xmm3 ;\n" + + /* store ysubx */ + "xorq %%rax, %%rax ;\n" + "movd %%xmm0, %%rcx ;\n" + "movd %%xmm0, %%r8 ;\n" + "movd %%xmm1, %%rsi ;\n" + "pshufd $0xee, %%xmm0, %%xmm0 ;\n" + "pshufd $0xee, %%xmm1, %%xmm1 ;\n" + "movd %%xmm0, %%rdx ;\n" + "movd %%xmm1, %%rdi ;\n" + "shrdq $51, %%rdx, %%r8 ;\n" + "shrdq $38, %%rsi, %%rdx ;\n" + "shrdq $25, %%rdi, %%rsi ;\n" + "shrq $12, %%rdi ;\n" + "movq %%rcx, %%r9 ;\n" + "movq %%r8, %%r10 ;\n" + "movq %%rdx, %%r11 ;\n" + "movq %%rsi, %%r12 ;\n" + "movq %%rdi, %%r13 ;\n" + "shrq $26, %%r9 ;\n" + "shrq $26, %%r10 ;\n" + "shrq $26, %%r11 ;\n" + "shrq $26, %%r12 ;\n" + "shrq $26, %%r13 ;\n" + "andl $0x3ffffff, %%ecx ;\n" + "andl $0x1ffffff, %%r9d ;\n" + "andl $0x3ffffff, %%r8d ;\n" + "andl $0x1ffffff, %%r10d ;\n" + "andl $0x3ffffff, %%edx ;\n" + "andl $0x1ffffff, %%r11d ;\n" + "andl $0x3ffffff, %%esi ;\n" + "andl $0x1ffffff, %%r12d ;\n" + "andl $0x3ffffff, %%edi ;\n" + "andl $0x1ffffff, %%r13d ;\n" + "movl %%ecx, 0(%2) ;\n" + "movl %%r9d, 4(%2) ;\n" + "movl %%r8d, 8(%2) ;\n" + "movl %%r10d, 12(%2) ;\n" + "movl %%edx, 16(%2) ;\n" + "movl %%r11d, 20(%2) ;\n" + "movl %%esi, 24(%2) ;\n" + "movl %%r12d, 28(%2) ;\n" + "movl %%edi, 32(%2) ;\n" + "movl %%r13d, 36(%2) ;\n" + "movq %%rax, 40(%2) ;\n" + + /* store xaddy */ + "movd %%xmm2, %%rcx ;\n" + "movd %%xmm2, %%r8 ;\n" + "movd %%xmm3, %%rsi ;\n" + "pshufd $0xee, %%xmm2, %%xmm2 ;\n" + "pshufd $0xee, %%xmm3, %%xmm3 ;\n" + "movd %%xmm2, %%rdx ;\n" + "movd %%xmm3, %%rdi ;\n" + "shrdq $51, %%rdx, %%r8 ;\n" + "shrdq $38, %%rsi, %%rdx ;\n" + "shrdq $25, %%rdi, %%rsi ;\n" + "shrq $12, %%rdi ;\n" + "movq %%rcx, %%r9 ;\n" + "movq %%r8, %%r10 ;\n" + "movq %%rdx, %%r11 ;\n" + "movq %%rsi, %%r12 ;\n" + "movq %%rdi, %%r13 ;\n" + "shrq $26, %%r9 ;\n" + "shrq $26, %%r10 ;\n" + "shrq $26, %%r11 ;\n" + "shrq $26, %%r12 ;\n" + "shrq $26, %%r13 ;\n" + "andl $0x3ffffff, %%ecx ;\n" + "andl $0x1ffffff, %%r9d ;\n" + "andl $0x3ffffff, %%r8d ;\n" + "andl $0x1ffffff, %%r10d ;\n" + "andl $0x3ffffff, %%edx ;\n" + "andl $0x1ffffff, %%r11d ;\n" + "andl $0x3ffffff, %%esi ;\n" + "andl $0x1ffffff, %%r12d ;\n" + "andl $0x3ffffff, %%edi ;\n" + "andl $0x1ffffff, %%r13d ;\n" + "movl %%ecx, 48(%2) ;\n" + "movl %%r9d, 52(%2) ;\n" + "movl %%r8d, 56(%2) ;\n" + "movl %%r10d, 60(%2) ;\n" + "movl %%edx, 64(%2) ;\n" + "movl %%r11d, 68(%2) ;\n" + "movl %%esi, 72(%2) ;\n" + "movl %%r12d, 76(%2) ;\n" + "movl %%edi, 80(%2) ;\n" + "movl %%r13d, 84(%2) ;\n" + "movq %%rax, 88(%2) ;\n" + + /* extract t2d */ + "xorq %%rax, %%rax ;\n" + "movd %%xmm4, %%rcx ;\n" + "movd %%xmm4, %%r8 ;\n" + "movd %%xmm5, %%rsi ;\n" + "pshufd $0xee, %%xmm4, %%xmm4 ;\n" + "pshufd $0xee, %%xmm5, %%xmm5 ;\n" + "movd %%xmm4, %%rdx ;\n" + "movd %%xmm5, %%rdi ;\n" + "shrdq $51, %%rdx, %%r8 ;\n" + "shrdq $38, %%rsi, %%rdx ;\n" + "shrdq $25, %%rdi, %%rsi ;\n" + "shrq $12, %%rdi ;\n" + "movq %%rcx, %%r9 ;\n" + "movq %%r8, %%r10 ;\n" + "movq %%rdx, %%r11 ;\n" + "movq %%rsi, %%r12 ;\n" + "movq %%rdi, %%r13 ;\n" + "shrq $26, %%r9 ;\n" + "shrq $26, %%r10 ;\n" + "shrq $26, %%r11 ;\n" + "shrq $26, %%r12 ;\n" + "shrq $26, %%r13 ;\n" + "andl $0x3ffffff, %%ecx ;\n" + "andl $0x1ffffff, %%r9d ;\n" + "andl $0x3ffffff, %%r8d ;\n" + "andl $0x1ffffff, %%r10d ;\n" + "andl $0x3ffffff, %%edx ;\n" + "andl $0x1ffffff, %%r11d ;\n" + "andl $0x3ffffff, %%esi ;\n" + "andl $0x1ffffff, %%r12d ;\n" + "andl $0x3ffffff, %%edi ;\n" + "andl $0x1ffffff, %%r13d ;\n" + "movd %%ecx, %%xmm0 ;\n" + "movd %%r9d, %%xmm4 ;\n" + "movd %%r8d, %%xmm8 ;\n" + "movd %%r10d, %%xmm3 ;\n" + "movd %%edx, %%xmm1 ;\n" + "movd %%r11d, %%xmm5 ;\n" + "movd %%esi, %%xmm6 ;\n" + "movd %%r12d, %%xmm7 ;\n" + "movd %%edi, %%xmm2 ;\n" + "movd %%r13d, %%xmm9 ;\n" + "punpckldq %%xmm4, %%xmm0 ;\n" + "punpckldq %%xmm3, %%xmm8 ;\n" + "punpckldq %%xmm5, %%xmm1 ;\n" + "punpckldq %%xmm7, %%xmm6 ;\n" + "punpckldq %%xmm9, %%xmm2 ;\n" + "punpcklqdq %%xmm8, %%xmm0 ;\n" + "punpcklqdq %%xmm6, %%xmm1 ;\n" + + /* set up 2p in to 3/4 */ + "movl $0x7ffffda, %%ecx ;\n" + "movl $0x3fffffe, %%edx ;\n" + "movl $0x7fffffe, %%eax ;\n" + "movd %%ecx, %%xmm3 ;\n" + "movd %%edx, %%xmm5 ;\n" + "movd %%eax, %%xmm4 ;\n" + "punpckldq %%xmm5, %%xmm3 ;\n" + "punpckldq %%xmm5, %%xmm4 ;\n" + "punpcklqdq %%xmm4, %%xmm3 ;\n" + "movdqa %%xmm4, %%xmm5 ;\n" + "punpcklqdq %%xmm4, %%xmm4 ;\n" + + /* subtract and conditionally move */ + "movl %3, %%ecx ;\n" + "sub $1, %%ecx ;\n" + "movd %%ecx, %%xmm6 ;\n" + "pshufd $0x00, %%xmm6, %%xmm6 ;\n" + "movdqa %%xmm6, %%xmm7 ;\n" + "psubd %%xmm0, %%xmm3 ;\n" + "psubd %%xmm1, %%xmm4 ;\n" + "psubd %%xmm2, %%xmm5 ;\n" + "pand %%xmm6, %%xmm0 ;\n" + "pand %%xmm6, %%xmm1 ;\n" + "pand %%xmm6, %%xmm2 ;\n" + "pandn %%xmm3, %%xmm6 ;\n" + "movdqa %%xmm7, %%xmm3 ;\n" + "pandn %%xmm4, %%xmm7 ;\n" + "pandn %%xmm5, %%xmm3 ;\n" + "por %%xmm6, %%xmm0 ;\n" + "por %%xmm7, %%xmm1 ;\n" + "por %%xmm3, %%xmm2 ;\n" + + /* store t2d */ + "movdqa %%xmm0, 96(%2) ;\n" + "movdqa %%xmm1, 112(%2) ;\n" + "movdqa %%xmm2, 128(%2) ;\n" + : + : "m"(u), "r"(&table[pos * 8]), "r"(t), "m"(sign) /* %0 = u, %1 = table, %2 = t, %3 = sign */ + : + "%rax", "%rcx", "%rdx", "%rdi", "%rsi", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", + "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "%xmm7", "%xmm8", "%xmm9", "%xmm10", "%xmm11", "%xmm14", "%xmm14", + "cc", "memory" + ); +} + +#endif /* defined(ED25519_GCC_64BIT_SSE_CHOOSE) */ + diff --git a/ed25519-donna/ed25519-donna-64bit-tables.h b/ed25519-donna/ed25519-donna-64bit-tables.h new file mode 100644 index 000000000..4a6ff9eda --- /dev/null +++ b/ed25519-donna/ed25519-donna-64bit-tables.h @@ -0,0 +1,53 @@ +static const ge25519 ge25519_basepoint = { + {0x00062d608f25d51a,0x000412a4b4f6592a,0x00075b7171a4b31d,0x0001ff60527118fe,0x000216936d3cd6e5}, + {0x0006666666666658,0x0004cccccccccccc,0x0001999999999999,0x0003333333333333,0x0006666666666666}, + {0x0000000000000001,0x0000000000000000,0x0000000000000000,0x0000000000000000,0x0000000000000000}, + {0x00068ab3a5b7dda3,0x00000eea2a5eadbb,0x0002af8df483c27e,0x000332b375274732,0x00067875f0fd78b7} +}; + +static const bignum25519 ge25519_ecd = { + 0x00034dca135978a3,0x0001a8283b156ebd,0x0005e7a26001c029,0x000739c663a03cbb,0x00052036cee2b6ff +}; + +static const bignum25519 ge25519_ec2d = { + 0x00069b9426b2f159,0x00035050762add7a,0x0003cf44c0038052,0x0006738cc7407977,0x0002406d9dc56dff +}; + +static const bignum25519 ge25519_sqrtneg1 = { + 0x00061b274a0ea0b0,0x0000d5a5fc8f189d,0x0007ef5e9cbd0c60,0x00078595a6804c9e,0x0002b8324804fc1d +}; + +static const ge25519_niels ge25519_niels_sliding_multiples[32] = { + {{0x00003905d740913e,0x0000ba2817d673a2,0x00023e2827f4e67c,0x000133d2e0c21a34,0x00044fd2f9298f81},{0x000493c6f58c3b85,0x0000df7181c325f7,0x0000f50b0b3e4cb7,0x0005329385a44c32,0x00007cf9d3a33d4b},{0x00011205877aaa68,0x000479955893d579,0x00050d66309b67a0,0x0002d42d0dbee5ee,0x0006f117b689f0c6}}, + {{0x00011fe8a4fcd265,0x0007bcb8374faacc,0x00052f5af4ef4d4f,0x0005314098f98d10,0x0002ab91587555bd},{0x0005b0a84cee9730,0x00061d10c97155e4,0x0004059cc8096a10,0x00047a608da8014f,0x0007a164e1b9a80f},{0x0006933f0dd0d889,0x00044386bb4c4295,0x0003cb6d3162508c,0x00026368b872a2c6,0x0005a2826af12b9b}}, + {{0x000182c3a447d6ba,0x00022964e536eff2,0x000192821f540053,0x0002f9f19e788e5c,0x000154a7e73eb1b5},{0x0002bc4408a5bb33,0x000078ebdda05442,0x0002ffb112354123,0x000375ee8df5862d,0x0002945ccf146e20},{0x0003dbf1812a8285,0x0000fa17ba3f9797,0x0006f69cb49c3820,0x00034d5a0db3858d,0x00043aabe696b3bb}}, + {{0x00072c9aaa3221b1,0x000267774474f74d,0x000064b0e9b28085,0x0003f04ef53b27c9,0x0001d6edd5d2e531},{0x00025cd0944ea3bf,0x00075673b81a4d63,0x000150b925d1c0d4,0x00013f38d9294114,0x000461bea69283c9},{0x00036dc801b8b3a2,0x0000e0a7d4935e30,0x0001deb7cecc0d7d,0x000053a94e20dd2c,0x0007a9fbb1c6a0f9}}, + {{0x0006217e039d8064,0x0006dea408337e6d,0x00057ac112628206,0x000647cb65e30473,0x00049c05a51fadc9},{0x0006678aa6a8632f,0x0005ea3788d8b365,0x00021bd6d6994279,0x0007ace75919e4e3,0x00034b9ed338add7},{0x0004e8bf9045af1b,0x000514e33a45e0d6,0x0007533c5b8bfe0f,0x000583557b7e14c9,0x00073c172021b008}}, + {{0x00075b0249864348,0x00052ee11070262b,0x000237ae54fb5acd,0x0003bfd1d03aaab5,0x00018ab598029d5c},{0x000700848a802ade,0x0001e04605c4e5f7,0x0005c0d01b9767fb,0x0007d7889f42388b,0x0004275aae2546d8},{0x00032cc5fd6089e9,0x000426505c949b05,0x00046a18880c7ad2,0x0004a4221888ccda,0x0003dc65522b53df}}, + {{0x0007013b327fbf93,0x0001336eeded6a0d,0x0002b565a2bbf3af,0x000253ce89591955,0x0000267882d17602},{0x0000c222a2007f6d,0x000356b79bdb77ee,0x00041ee81efe12ce,0x000120a9bd07097d,0x000234fd7eec346f},{0x0000a119732ea378,0x00063bf1ba8e2a6c,0x00069f94cc90df9a,0x000431d1779bfc48,0x000497ba6fdaa097}}, + {{0x0003cd86468ccf0b,0x00048553221ac081,0x0006c9464b4e0a6e,0x00075fba84180403,0x00043b5cd4218d05},{0x0006cc0313cfeaa0,0x0001a313848da499,0x0007cb534219230a,0x00039596dedefd60,0x00061e22917f12de},{0x0002762f9bd0b516,0x0001c6e7fbddcbb3,0x00075909c3ace2bd,0x00042101972d3ec9,0x000511d61210ae4d}}, + {{0x000386484420de87,0x0002d6b25db68102,0x000650b4962873c0,0x0004081cfd271394,0x00071a7fe6fe2482},{0x000676ef950e9d81,0x0001b81ae089f258,0x00063c4922951883,0x0002f1d54d9b3237,0x0006d325924ddb85},{0x000182b8a5c8c854,0x00073fcbe5406d8e,0x0005de3430cff451,0x000554b967ac8c41,0x0004746c4b6559ee}}, + {{0x000546c864741147,0x0003a1df99092690,0x0001ca8cc9f4d6bb,0x00036b7fc9cd3b03,0x000219663497db5e},{0x00077b3c6dc69a2b,0x0004edf13ec2fa6e,0x0004e85ad77beac8,0x0007dba2b28e7bda,0x0005c9a51de34fe9},{0x0000f1cf79f10e67,0x00043ccb0a2b7ea2,0x00005089dfff776a,0x0001dd84e1d38b88,0x0004804503c60822}}, + {{0x000021d23a36d175,0x0004fd3373c6476d,0x00020e291eeed02a,0x00062f2ecf2e7210,0x000771e098858de4},{0x00049ed02ca37fc7,0x000474c2b5957884,0x0005b8388e816683,0x0004b6c454b76be4,0x000553398a516506},{0x0002f5d278451edf,0x000730b133997342,0x0006965420eb6975,0x000308a3bfa516cf,0x0005a5ed1d68ff5a}}, + {{0x0005e0c558527359,0x0003395b73afd75c,0x000072afa4e4b970,0x00062214329e0f6d,0x000019b60135fefd},{0x0005122afe150e83,0x0004afc966bb0232,0x0001c478833c8268,0x00017839c3fc148f,0x00044acb897d8bf9},{0x000068145e134b83,0x0001e4860982c3cc,0x000068fb5f13d799,0x0007c9283744547e,0x000150c49fde6ad2}}, + {{0x0001863c9cdca868,0x0003770e295a1709,0x0000d85a3720fd13,0x0005e0ff1f71ab06,0x00078a6d7791e05f},{0x0003f29509471138,0x000729eeb4ca31cf,0x00069c22b575bfbc,0x0004910857bce212,0x0006b2b5a075bb99},{0x0007704b47a0b976,0x0002ae82e91aab17,0x00050bd6429806cd,0x00068055158fd8ea,0x000725c7ffc4ad55}}, + {{0x00002bf71cd098c0,0x00049dabcc6cd230,0x00040a6533f905b2,0x000573efac2eb8a4,0x0004cd54625f855f},{0x00026715d1cf99b2,0x0002205441a69c88,0x000448427dcd4b54,0x0001d191e88abdc5,0x000794cc9277cb1f},{0x0006c426c2ac5053,0x0005a65ece4b095e,0x0000c44086f26bb6,0x0007429568197885,0x0007008357b6fcc8}}, + {{0x00039fbb82584a34,0x00047a568f257a03,0x00014d88091ead91,0x0002145b18b1ce24,0x00013a92a3669d6d},{0x0000672738773f01,0x000752bf799f6171,0x0006b4a6dae33323,0x0007b54696ead1dc,0x00006ef7e9851ad0},{0x0003771cc0577de5,0x0003ca06bb8b9952,0x00000b81c5d50390,0x00043512340780ec,0x0003c296ddf8a2af}}, + {{0x00034d2ebb1f2541,0x0000e815b723ff9d,0x000286b416e25443,0x0000bdfe38d1bee8,0x0000a892c7007477},{0x000515f9d914a713,0x00073191ff2255d5,0x00054f5cc2a4bdef,0x0003dd57fc118bcf,0x0007a99d393490c7},{0x0002ed2436bda3e8,0x00002afd00f291ea,0x0000be7381dea321,0x0003e952d4b2b193,0x000286762d28302f}}, + {{0x00058e2bce2ef5bd,0x00068ce8f78c6f8a,0x0006ee26e39261b2,0x00033d0aa50bcf9d,0x0007686f2a3d6f17},{0x000036093ce35b25,0x0003b64d7552e9cf,0x00071ee0fe0b8460,0x00069d0660c969e5,0x00032f1da046a9d9},{0x000512a66d597c6a,0x0000609a70a57551,0x000026c08a3c464c,0x0004531fc8ee39e1,0x000561305f8a9ad2}}, + {{0x0002cc28e7b0c0d5,0x00077b60eb8a6ce4,0x0004042985c277a6,0x000636657b46d3eb,0x000030a1aef2c57c},{0x0004978dec92aed1,0x000069adae7ca201,0x00011ee923290f55,0x00069641898d916c,0x00000aaec53e35d4},{0x0001f773003ad2aa,0x000005642cc10f76,0x00003b48f82cfca6,0x0002403c10ee4329,0x00020be9c1c24065}}, + {{0x0000e44ae2025e60,0x0005f97b9727041c,0x0005683472c0ecec,0x000188882eb1ce7c,0x00069764c545067e},{0x000387d8249673a6,0x0005bea8dc927c2a,0x0005bd8ed5650ef0,0x0000ef0e3fcd40e1,0x000750ab3361f0ac},{0x00023283a2f81037,0x000477aff97e23d1,0x0000b8958dbcbb68,0x0000205b97e8add6,0x00054f96b3fb7075}}, + {{0x0005afc616b11ecd,0x00039f4aec8f22ef,0x0003b39e1625d92e,0x0005f85bd4508873,0x00078e6839fbe85d},{0x0005f20429669279,0x00008fafae4941f5,0x00015d83c4eb7688,0x0001cf379eca4146,0x0003d7fe9c52bb75},{0x00032df737b8856b,0x0000608342f14e06,0x0003967889d74175,0x0001211907fba550,0x00070f268f350088}}, + {{0x0004112070dcf355,0x0007dcff9c22e464,0x00054ada60e03325,0x00025cd98eef769a,0x000404e56c039b8c},{0x00064583b1805f47,0x00022c1baf832cd0,0x000132c01bd4d717,0x0004ecf4c3a75b8f,0x0007c0d345cfad88},{0x00071f4b8c78338a,0x00062cfc16bc2b23,0x00017cf51280d9aa,0x0003bbae5e20a95a,0x00020d754762aaec}}, + {{0x0004feb135b9f543,0x00063bd192ad93ae,0x00044e2ea612cdf7,0x000670f4991583ab,0x00038b8ada8790b4},{0x0007c36fc73bb758,0x0004a6c797734bd1,0x0000ef248ab3950e,0x00063154c9a53ec8,0x0002b8f1e46f3cee},{0x00004a9cdf51f95d,0x0005d963fbd596b8,0x00022d9b68ace54a,0x0004a98e8836c599,0x000049aeb32ceba1}}, + {{0x00067d3c63dcfe7e,0x000112f0adc81aee,0x00053df04c827165,0x0002fe5b33b430f0,0x00051c665e0c8d62},{0x00007d0b75fc7931,0x00016f4ce4ba754a,0x0005ace4c03fbe49,0x00027e0ec12a159c,0x000795ee17530f67},{0x00025b0a52ecbd81,0x0005dc0695fce4a9,0x0003b928c575047d,0x00023bf3512686e5,0x0006cd19bf49dc54}}, + {{0x0007619052179ca3,0x0000c16593f0afd0,0x000265c4795c7428,0x00031c40515d5442,0x0007520f3db40b2e},{0x0006612165afc386,0x0001171aa36203ff,0x0002642ea820a8aa,0x0001f3bb7b313f10,0x0005e01b3a7429e4},{0x00050be3d39357a1,0x0003ab33d294a7b6,0x0004c479ba59edb3,0x0004c30d184d326f,0x00071092c9ccef3c}}, + {{0x0000523f0364918c,0x000687f56d638a7b,0x00020796928ad013,0x0005d38405a54f33,0x0000ea15b03d0257},{0x0003d8ac74051dcf,0x00010ab6f543d0ad,0x0005d0f3ac0fda90,0x0005ef1d2573e5e4,0x0004173a5bb7137a},{0x00056e31f0f9218a,0x0005635f88e102f8,0x0002cbc5d969a5b8,0x000533fbc98b347a,0x0005fc565614a4e3}}, + {{0x0006570dc46d7ae5,0x00018a9f1b91e26d,0x000436b6183f42ab,0x000550acaa4f8198,0x00062711c414c454},{0x0002e1e67790988e,0x0001e38b9ae44912,0x000648fbb4075654,0x00028df1d840cd72,0x0003214c7409d466},{0x0001827406651770,0x0004d144f286c265,0x00017488f0ee9281,0x00019e6cdb5c760c,0x0005bea94073ecb8}}, + {{0x0005bf0912c89be4,0x00062fadcaf38c83,0x00025ec196b3ce2c,0x00077655ff4f017b,0x0003aacd5c148f61},{0x0000ce63f343d2f8,0x0001e0a87d1e368e,0x000045edbc019eea,0x0006979aed28d0d1,0x0004ad0785944f1b},{0x00063b34c3318301,0x0000e0e62d04d0b1,0x000676a233726701,0x00029e9a042d9769,0x0003aff0cb1d9028}}, + {{0x0005c7eb3a20405e,0x0005fdb5aad930f8,0x0004a757e63b8c47,0x00028e9492972456,0x000110e7e86f4cd2},{0x0006430bf4c53505,0x000264c3e4507244,0x00074c9f19a39270,0x00073f84f799bc47,0x0002ccf9f732bd99},{0x0000d89ed603f5e4,0x00051e1604018af8,0x0000b8eedc4a2218,0x00051ba98b9384d0,0x00005c557e0b9693}}, + {{0x0001ce311fc97e6f,0x0006023f3fb5db1f,0x0007b49775e8fc98,0x0003ad70adbf5045,0x0006e154c178fe98},{0x0006bbb089c20eb0,0x0006df41fb0b9eee,0x00051087ed87e16f,0x000102db5c9fa731,0x000289fef0841861},{0x00016336fed69abf,0x0004f066b929f9ec,0x0004e9ff9e6c5b93,0x00018c89bc4bb2ba,0x0006afbf642a95ca}}, + {{0x0000de0c62f5d2c1,0x00049601cf734fb5,0x0006b5c38263f0f6,0x0004623ef5b56d06,0x0000db4b851b9503},{0x00055070f913a8cc,0x000765619eac2bbc,0x0003ab5225f47459,0x00076ced14ab5b48,0x00012c093cedb801},{0x00047f9308b8190f,0x000414235c621f82,0x00031f5ff41a5a76,0x0006736773aab96d,0x00033aa8799c6635}}, + {{0x0007f51ebd085cf2,0x00012cfa67e3f5e1,0x0001800cf1e3d46a,0x00054337615ff0a8,0x000233c6f29e8e21},{0x0000f588fc156cb1,0x000363414da4f069,0x0007296ad9b68aea,0x0004d3711316ae43,0x000212cd0c1c8d58},{0x0004d5107f18c781,0x00064a4fd3a51a5e,0x0004f4cd0448bb37,0x000671d38543151e,0x0001db7778911914}}, + {{0x000352397c6bc26f,0x00018a7aa0227bbe,0x0005e68cc1ea5f8b,0x0006fe3e3a7a1d5f,0x00031ad97ad26e2a},{0x00014769dd701ab6,0x00028339f1b4b667,0x0004ab214b8ae37b,0x00025f0aefa0b0fe,0x0007ae2ca8a017d2},{0x000017ed0920b962,0x000187e33b53b6fd,0x00055829907a1463,0x000641f248e0a792,0x0001ed1fc53a6622}} +}; diff --git a/ed25519-donna/ed25519-donna-64bit-x86-32bit.h b/ed25519-donna/ed25519-donna-64bit-x86-32bit.h new file mode 100644 index 000000000..1ce109c5b --- /dev/null +++ b/ed25519-donna/ed25519-donna-64bit-x86-32bit.h @@ -0,0 +1,435 @@ +#if defined(ED25519_GCC_64BIT_32BIT_CHOOSE) + +#define HAVE_GE25519_SCALARMULT_BASE_CHOOSE_NIELS + +DONNA_NOINLINE static void +ge25519_scalarmult_base_choose_niels(ge25519_niels *t, const uint8_t table[256][96], uint32_t pos, signed char b) { + int64_t breg = (int64_t)b; + uint64_t sign = (uint64_t)breg >> 63; + uint64_t mask = ~(sign - 1); + uint64_t u = (breg + mask) ^ mask; + + __asm__ __volatile__ ( + /* ysubx+xaddy+t2d */ + "movq %0, %%rax ;\n" + "movd %%rax, %%xmm14 ;\n" + "pshufd $0x00, %%xmm14, %%xmm14 ;\n" + "pxor %%xmm0, %%xmm0 ;\n" + "pxor %%xmm1, %%xmm1 ;\n" + "pxor %%xmm2, %%xmm2 ;\n" + "pxor %%xmm3, %%xmm3 ;\n" + "pxor %%xmm4, %%xmm4 ;\n" + "pxor %%xmm5, %%xmm5 ;\n" + + /* 0 */ + "movq $0, %%rax ;\n" + "movd %%rax, %%xmm15 ;\n" + "pshufd $0x00, %%xmm15, %%xmm15 ;\n" + "pcmpeqd %%xmm14, %%xmm15 ;\n" + "movq $1, %%rax ;\n" + "movd %%rax, %%xmm6 ;\n" + "pxor %%xmm7, %%xmm7 ;\n" + "pand %%xmm15, %%xmm6 ;\n" + "pand %%xmm15, %%xmm7 ;\n" + "por %%xmm6, %%xmm0 ;\n" + "por %%xmm7, %%xmm1 ;\n" + "por %%xmm6, %%xmm2 ;\n" + "por %%xmm7, %%xmm3 ;\n" + + /* 1 */ + "movq $1, %%rax ;\n" + "movd %%rax, %%xmm15 ;\n" + "pshufd $0x00, %%xmm15, %%xmm15 ;\n" + "pcmpeqd %%xmm14, %%xmm15 ;\n" + "movdqa 0(%1), %%xmm6 ;\n" + "movdqa 16(%1), %%xmm7 ;\n" + "movdqa 32(%1), %%xmm8 ;\n" + "movdqa 48(%1), %%xmm9 ;\n" + "movdqa 64(%1), %%xmm10 ;\n" + "movdqa 80(%1), %%xmm11 ;\n" + "pand %%xmm15, %%xmm6 ;\n" + "pand %%xmm15, %%xmm7 ;\n" + "pand %%xmm15, %%xmm8 ;\n" + "pand %%xmm15, %%xmm9 ;\n" + "pand %%xmm15, %%xmm10 ;\n" + "pand %%xmm15, %%xmm11 ;\n" + "por %%xmm6, %%xmm0 ;\n" + "por %%xmm7, %%xmm1 ;\n" + "por %%xmm8, %%xmm2 ;\n" + "por %%xmm9, %%xmm3 ;\n" + "por %%xmm10, %%xmm4 ;\n" + "por %%xmm11, %%xmm5 ;\n" + + /* 2 */ + "movq $2, %%rax ;\n" + "movd %%rax, %%xmm15 ;\n" + "pshufd $0x00, %%xmm15, %%xmm15 ;\n" + "pcmpeqd %%xmm14, %%xmm15 ;\n" + "movdqa 96(%1), %%xmm6 ;\n" + "movdqa 112(%1), %%xmm7 ;\n" + "movdqa 128(%1), %%xmm8 ;\n" + "movdqa 144(%1), %%xmm9 ;\n" + "movdqa 160(%1), %%xmm10 ;\n" + "movdqa 176(%1), %%xmm11 ;\n" + "pand %%xmm15, %%xmm6 ;\n" + "pand %%xmm15, %%xmm7 ;\n" + "pand %%xmm15, %%xmm8 ;\n" + "pand %%xmm15, %%xmm9 ;\n" + "pand %%xmm15, %%xmm10 ;\n" + "pand %%xmm15, %%xmm11 ;\n" + "por %%xmm6, %%xmm0 ;\n" + "por %%xmm7, %%xmm1 ;\n" + "por %%xmm8, %%xmm2 ;\n" + "por %%xmm9, %%xmm3 ;\n" + "por %%xmm10, %%xmm4 ;\n" + "por %%xmm11, %%xmm5 ;\n" + + /* 3 */ + "movq $3, %%rax ;\n" + "movd %%rax, %%xmm15 ;\n" + "pshufd $0x00, %%xmm15, %%xmm15 ;\n" + "pcmpeqd %%xmm14, %%xmm15 ;\n" + "movdqa 192(%1), %%xmm6 ;\n" + "movdqa 208(%1), %%xmm7 ;\n" + "movdqa 224(%1), %%xmm8 ;\n" + "movdqa 240(%1), %%xmm9 ;\n" + "movdqa 256(%1), %%xmm10 ;\n" + "movdqa 272(%1), %%xmm11 ;\n" + "pand %%xmm15, %%xmm6 ;\n" + "pand %%xmm15, %%xmm7 ;\n" + "pand %%xmm15, %%xmm8 ;\n" + "pand %%xmm15, %%xmm9 ;\n" + "pand %%xmm15, %%xmm10 ;\n" + "pand %%xmm15, %%xmm11 ;\n" + "por %%xmm6, %%xmm0 ;\n" + "por %%xmm7, %%xmm1 ;\n" + "por %%xmm8, %%xmm2 ;\n" + "por %%xmm9, %%xmm3 ;\n" + "por %%xmm10, %%xmm4 ;\n" + "por %%xmm11, %%xmm5 ;\n" + + /* 4 */ + "movq $4, %%rax ;\n" + "movd %%rax, %%xmm15 ;\n" + "pshufd $0x00, %%xmm15, %%xmm15 ;\n" + "pcmpeqd %%xmm14, %%xmm15 ;\n" + "movdqa 288(%1), %%xmm6 ;\n" + "movdqa 304(%1), %%xmm7 ;\n" + "movdqa 320(%1), %%xmm8 ;\n" + "movdqa 336(%1), %%xmm9 ;\n" + "movdqa 352(%1), %%xmm10 ;\n" + "movdqa 368(%1), %%xmm11 ;\n" + "pand %%xmm15, %%xmm6 ;\n" + "pand %%xmm15, %%xmm7 ;\n" + "pand %%xmm15, %%xmm8 ;\n" + "pand %%xmm15, %%xmm9 ;\n" + "pand %%xmm15, %%xmm10 ;\n" + "pand %%xmm15, %%xmm11 ;\n" + "por %%xmm6, %%xmm0 ;\n" + "por %%xmm7, %%xmm1 ;\n" + "por %%xmm8, %%xmm2 ;\n" + "por %%xmm9, %%xmm3 ;\n" + "por %%xmm10, %%xmm4 ;\n" + "por %%xmm11, %%xmm5 ;\n" + + /* 5 */ + "movq $5, %%rax ;\n" + "movd %%rax, %%xmm15 ;\n" + "pshufd $0x00, %%xmm15, %%xmm15 ;\n" + "pcmpeqd %%xmm14, %%xmm15 ;\n" + "movdqa 384(%1), %%xmm6 ;\n" + "movdqa 400(%1), %%xmm7 ;\n" + "movdqa 416(%1), %%xmm8 ;\n" + "movdqa 432(%1), %%xmm9 ;\n" + "movdqa 448(%1), %%xmm10 ;\n" + "movdqa 464(%1), %%xmm11 ;\n" + "pand %%xmm15, %%xmm6 ;\n" + "pand %%xmm15, %%xmm7 ;\n" + "pand %%xmm15, %%xmm8 ;\n" + "pand %%xmm15, %%xmm9 ;\n" + "pand %%xmm15, %%xmm10 ;\n" + "pand %%xmm15, %%xmm11 ;\n" + "por %%xmm6, %%xmm0 ;\n" + "por %%xmm7, %%xmm1 ;\n" + "por %%xmm8, %%xmm2 ;\n" + "por %%xmm9, %%xmm3 ;\n" + "por %%xmm10, %%xmm4 ;\n" + "por %%xmm11, %%xmm5 ;\n" + + /* 6 */ + "movq $6, %%rax ;\n" + "movd %%rax, %%xmm15 ;\n" + "pshufd $0x00, %%xmm15, %%xmm15 ;\n" + "pcmpeqd %%xmm14, %%xmm15 ;\n" + "movdqa 480(%1), %%xmm6 ;\n" + "movdqa 496(%1), %%xmm7 ;\n" + "movdqa 512(%1), %%xmm8 ;\n" + "movdqa 528(%1), %%xmm9 ;\n" + "movdqa 544(%1), %%xmm10 ;\n" + "movdqa 560(%1), %%xmm11 ;\n" + "pand %%xmm15, %%xmm6 ;\n" + "pand %%xmm15, %%xmm7 ;\n" + "pand %%xmm15, %%xmm8 ;\n" + "pand %%xmm15, %%xmm9 ;\n" + "pand %%xmm15, %%xmm10 ;\n" + "pand %%xmm15, %%xmm11 ;\n" + "por %%xmm6, %%xmm0 ;\n" + "por %%xmm7, %%xmm1 ;\n" + "por %%xmm8, %%xmm2 ;\n" + "por %%xmm9, %%xmm3 ;\n" + "por %%xmm10, %%xmm4 ;\n" + "por %%xmm11, %%xmm5 ;\n" + + /* 7 */ + "movq $7, %%rax ;\n" + "movd %%rax, %%xmm15 ;\n" + "pshufd $0x00, %%xmm15, %%xmm15 ;\n" + "pcmpeqd %%xmm14, %%xmm15 ;\n" + "movdqa 576(%1), %%xmm6 ;\n" + "movdqa 592(%1), %%xmm7 ;\n" + "movdqa 608(%1), %%xmm8 ;\n" + "movdqa 624(%1), %%xmm9 ;\n" + "movdqa 640(%1), %%xmm10 ;\n" + "movdqa 656(%1), %%xmm11 ;\n" + "pand %%xmm15, %%xmm6 ;\n" + "pand %%xmm15, %%xmm7 ;\n" + "pand %%xmm15, %%xmm8 ;\n" + "pand %%xmm15, %%xmm9 ;\n" + "pand %%xmm15, %%xmm10 ;\n" + "pand %%xmm15, %%xmm11 ;\n" + "por %%xmm6, %%xmm0 ;\n" + "por %%xmm7, %%xmm1 ;\n" + "por %%xmm8, %%xmm2 ;\n" + "por %%xmm9, %%xmm3 ;\n" + "por %%xmm10, %%xmm4 ;\n" + "por %%xmm11, %%xmm5 ;\n" + + /* 8 */ + "movq $8, %%rax ;\n" + "movd %%rax, %%xmm15 ;\n" + "pshufd $0x00, %%xmm15, %%xmm15 ;\n" + "pcmpeqd %%xmm14, %%xmm15 ;\n" + "movdqa 672(%1), %%xmm6 ;\n" + "movdqa 688(%1), %%xmm7 ;\n" + "movdqa 704(%1), %%xmm8 ;\n" + "movdqa 720(%1), %%xmm9 ;\n" + "movdqa 736(%1), %%xmm10 ;\n" + "movdqa 752(%1), %%xmm11 ;\n" + "pand %%xmm15, %%xmm6 ;\n" + "pand %%xmm15, %%xmm7 ;\n" + "pand %%xmm15, %%xmm8 ;\n" + "pand %%xmm15, %%xmm9 ;\n" + "pand %%xmm15, %%xmm10 ;\n" + "pand %%xmm15, %%xmm11 ;\n" + "por %%xmm6, %%xmm0 ;\n" + "por %%xmm7, %%xmm1 ;\n" + "por %%xmm8, %%xmm2 ;\n" + "por %%xmm9, %%xmm3 ;\n" + "por %%xmm10, %%xmm4 ;\n" + "por %%xmm11, %%xmm5 ;\n" + + /* conditionally swap ysubx and xaddy */ + "movq %3, %%rax ;\n" + "xorq $1, %%rax ;\n" + "movd %%rax, %%xmm14 ;\n" + "pxor %%xmm15, %%xmm15 ;\n" + "pshufd $0x00, %%xmm14, %%xmm14 ;\n" + "pxor %%xmm0, %%xmm2 ;\n" + "pxor %%xmm1, %%xmm3 ;\n" + "pcmpeqd %%xmm14, %%xmm15 ;\n" + "movdqa %%xmm2, %%xmm6 ;\n" + "movdqa %%xmm3, %%xmm7 ;\n" + "pand %%xmm15, %%xmm6 ;\n" + "pand %%xmm15, %%xmm7 ;\n" + "pxor %%xmm6, %%xmm0 ;\n" + "pxor %%xmm7, %%xmm1 ;\n" + "pxor %%xmm0, %%xmm2 ;\n" + "pxor %%xmm1, %%xmm3 ;\n" + + /* store ysubx */ + "xorq %%rax, %%rax ;\n" + "movd %%xmm0, %%rcx ;\n" + "movd %%xmm0, %%r8 ;\n" + "movd %%xmm1, %%rsi ;\n" + "pshufd $0xee, %%xmm0, %%xmm0 ;\n" + "pshufd $0xee, %%xmm1, %%xmm1 ;\n" + "movd %%xmm0, %%rdx ;\n" + "movd %%xmm1, %%rdi ;\n" + "shrdq $51, %%rdx, %%r8 ;\n" + "shrdq $38, %%rsi, %%rdx ;\n" + "shrdq $25, %%rdi, %%rsi ;\n" + "shrq $12, %%rdi ;\n" + "movq %%rcx, %%r9 ;\n" + "movq %%r8, %%r10 ;\n" + "movq %%rdx, %%r11 ;\n" + "movq %%rsi, %%r12 ;\n" + "movq %%rdi, %%r13 ;\n" + "shrq $26, %%r9 ;\n" + "shrq $26, %%r10 ;\n" + "shrq $26, %%r11 ;\n" + "shrq $26, %%r12 ;\n" + "shrq $26, %%r13 ;\n" + "andl $0x3ffffff, %%ecx ;\n" + "andl $0x1ffffff, %%r9d ;\n" + "andl $0x3ffffff, %%r8d ;\n" + "andl $0x1ffffff, %%r10d ;\n" + "andl $0x3ffffff, %%edx ;\n" + "andl $0x1ffffff, %%r11d ;\n" + "andl $0x3ffffff, %%esi ;\n" + "andl $0x1ffffff, %%r12d ;\n" + "andl $0x3ffffff, %%edi ;\n" + "andl $0x1ffffff, %%r13d ;\n" + "movl %%ecx, 0(%2) ;\n" + "movl %%r9d, 4(%2) ;\n" + "movl %%r8d, 8(%2) ;\n" + "movl %%r10d, 12(%2) ;\n" + "movl %%edx, 16(%2) ;\n" + "movl %%r11d, 20(%2) ;\n" + "movl %%esi, 24(%2) ;\n" + "movl %%r12d, 28(%2) ;\n" + "movl %%edi, 32(%2) ;\n" + "movl %%r13d, 36(%2) ;\n" + + /* store xaddy */ + "movd %%xmm2, %%rcx ;\n" + "movd %%xmm2, %%r8 ;\n" + "movd %%xmm3, %%rsi ;\n" + "pshufd $0xee, %%xmm2, %%xmm2 ;\n" + "pshufd $0xee, %%xmm3, %%xmm3 ;\n" + "movd %%xmm2, %%rdx ;\n" + "movd %%xmm3, %%rdi ;\n" + "shrdq $51, %%rdx, %%r8 ;\n" + "shrdq $38, %%rsi, %%rdx ;\n" + "shrdq $25, %%rdi, %%rsi ;\n" + "shrq $12, %%rdi ;\n" + "movq %%rcx, %%r9 ;\n" + "movq %%r8, %%r10 ;\n" + "movq %%rdx, %%r11 ;\n" + "movq %%rsi, %%r12 ;\n" + "movq %%rdi, %%r13 ;\n" + "shrq $26, %%r9 ;\n" + "shrq $26, %%r10 ;\n" + "shrq $26, %%r11 ;\n" + "shrq $26, %%r12 ;\n" + "shrq $26, %%r13 ;\n" + "andl $0x3ffffff, %%ecx ;\n" + "andl $0x1ffffff, %%r9d ;\n" + "andl $0x3ffffff, %%r8d ;\n" + "andl $0x1ffffff, %%r10d ;\n" + "andl $0x3ffffff, %%edx ;\n" + "andl $0x1ffffff, %%r11d ;\n" + "andl $0x3ffffff, %%esi ;\n" + "andl $0x1ffffff, %%r12d ;\n" + "andl $0x3ffffff, %%edi ;\n" + "andl $0x1ffffff, %%r13d ;\n" + "movl %%ecx, 40(%2) ;\n" + "movl %%r9d, 44(%2) ;\n" + "movl %%r8d, 48(%2) ;\n" + "movl %%r10d, 52(%2) ;\n" + "movl %%edx, 56(%2) ;\n" + "movl %%r11d, 60(%2) ;\n" + "movl %%esi, 64(%2) ;\n" + "movl %%r12d, 68(%2) ;\n" + "movl %%edi, 72(%2) ;\n" + "movl %%r13d, 76(%2) ;\n" + + /* extract t2d */ + "xorq %%rax, %%rax ;\n" + "movd %%xmm4, %%rcx ;\n" + "movd %%xmm4, %%r8 ;\n" + "movd %%xmm5, %%rsi ;\n" + "pshufd $0xee, %%xmm4, %%xmm4 ;\n" + "pshufd $0xee, %%xmm5, %%xmm5 ;\n" + "movd %%xmm4, %%rdx ;\n" + "movd %%xmm5, %%rdi ;\n" + "shrdq $51, %%rdx, %%r8 ;\n" + "shrdq $38, %%rsi, %%rdx ;\n" + "shrdq $25, %%rdi, %%rsi ;\n" + "shrq $12, %%rdi ;\n" + "movq %%rcx, %%r9 ;\n" + "movq %%r8, %%r10 ;\n" + "movq %%rdx, %%r11 ;\n" + "movq %%rsi, %%r12 ;\n" + "movq %%rdi, %%r13 ;\n" + "shrq $26, %%r9 ;\n" + "shrq $26, %%r10 ;\n" + "shrq $26, %%r11 ;\n" + "shrq $26, %%r12 ;\n" + "shrq $26, %%r13 ;\n" + "andl $0x3ffffff, %%ecx ;\n" + "andl $0x1ffffff, %%r9d ;\n" + "andl $0x3ffffff, %%r8d ;\n" + "andl $0x1ffffff, %%r10d ;\n" + "andl $0x3ffffff, %%edx ;\n" + "andl $0x1ffffff, %%r11d ;\n" + "andl $0x3ffffff, %%esi ;\n" + "andl $0x1ffffff, %%r12d ;\n" + "andl $0x3ffffff, %%edi ;\n" + "andl $0x1ffffff, %%r13d ;\n" + "movd %%ecx, %%xmm0 ;\n" + "movd %%r9d, %%xmm4 ;\n" + "movd %%r8d, %%xmm8 ;\n" + "movd %%r10d, %%xmm3 ;\n" + "movd %%edx, %%xmm1 ;\n" + "movd %%r11d, %%xmm5 ;\n" + "movd %%esi, %%xmm6 ;\n" + "movd %%r12d, %%xmm7 ;\n" + "movd %%edi, %%xmm2 ;\n" + "movd %%r13d, %%xmm9 ;\n" + "punpckldq %%xmm4, %%xmm0 ;\n" + "punpckldq %%xmm3, %%xmm8 ;\n" + "punpckldq %%xmm5, %%xmm1 ;\n" + "punpckldq %%xmm7, %%xmm6 ;\n" + "punpckldq %%xmm9, %%xmm2 ;\n" + "punpcklqdq %%xmm8, %%xmm0 ;\n" + "punpcklqdq %%xmm6, %%xmm1 ;\n" + + /* set up 2p in to 3/4 */ + "movl $0x7ffffda, %%ecx ;\n" + "movl $0x3fffffe, %%edx ;\n" + "movl $0x7fffffe, %%eax ;\n" + "movd %%ecx, %%xmm3 ;\n" + "movd %%edx, %%xmm5 ;\n" + "movd %%eax, %%xmm4 ;\n" + "punpckldq %%xmm5, %%xmm3 ;\n" + "punpckldq %%xmm5, %%xmm4 ;\n" + "punpcklqdq %%xmm4, %%xmm3 ;\n" + "movdqa %%xmm4, %%xmm5 ;\n" + "punpcklqdq %%xmm4, %%xmm4 ;\n" + + /* subtract and conditionally move */ + "movl %3, %%ecx ;\n" + "sub $1, %%ecx ;\n" + "movd %%ecx, %%xmm6 ;\n" + "pshufd $0x00, %%xmm6, %%xmm6 ;\n" + "movdqa %%xmm6, %%xmm7 ;\n" + "psubd %%xmm0, %%xmm3 ;\n" + "psubd %%xmm1, %%xmm4 ;\n" + "psubd %%xmm2, %%xmm5 ;\n" + "pand %%xmm6, %%xmm0 ;\n" + "pand %%xmm6, %%xmm1 ;\n" + "pand %%xmm6, %%xmm2 ;\n" + "pandn %%xmm3, %%xmm6 ;\n" + "movdqa %%xmm7, %%xmm3 ;\n" + "pandn %%xmm4, %%xmm7 ;\n" + "pandn %%xmm5, %%xmm3 ;\n" + "por %%xmm6, %%xmm0 ;\n" + "por %%xmm7, %%xmm1 ;\n" + "por %%xmm3, %%xmm2 ;\n" + + /* store t2d */ + "movdqa %%xmm0, 80(%2) ;\n" + "movdqa %%xmm1, 96(%2) ;\n" + "movd %%xmm2, %%rax ;\n" + "movq %%rax, 112(%2) ;\n" + : + : "m"(u), "r"(&table[pos * 8]), "r"(t), "m"(sign) /* %0 = u, %1 = table, %2 = t, %3 = sign */ + : + "%rax", "%rcx", "%rdx", "%rdi", "%rsi", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", + "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "%xmm7", "%xmm8", "%xmm9", "%xmm10", "%xmm11", "%xmm14", "%xmm14", + "cc", "memory" + ); +} + +#endif /* defined(ED25519_GCC_64BIT_32BIT_CHOOSE) */ + diff --git a/ed25519-donna/ed25519-donna-64bit-x86.h b/ed25519-donna/ed25519-donna-64bit-x86.h new file mode 100644 index 000000000..30bd47276 --- /dev/null +++ b/ed25519-donna/ed25519-donna-64bit-x86.h @@ -0,0 +1,351 @@ +#if defined(ED25519_GCC_64BIT_X86_CHOOSE) + +#define HAVE_GE25519_SCALARMULT_BASE_CHOOSE_NIELS + +DONNA_NOINLINE static void +ge25519_scalarmult_base_choose_niels(ge25519_niels *t, const uint8_t table[256][96], uint32_t pos, signed char b) { + int64_t breg = (int64_t)b; + uint64_t sign = (uint64_t)breg >> 63; + uint64_t mask = ~(sign - 1); + uint64_t u = (breg + mask) ^ mask; + + __asm__ __volatile__ ( + /* ysubx+xaddy+t2d */ + "movq %0, %%rax ;\n" + "movd %%rax, %%xmm14 ;\n" + "pshufd $0x00, %%xmm14, %%xmm14 ;\n" + "pxor %%xmm0, %%xmm0 ;\n" + "pxor %%xmm1, %%xmm1 ;\n" + "pxor %%xmm2, %%xmm2 ;\n" + "pxor %%xmm3, %%xmm3 ;\n" + "pxor %%xmm4, %%xmm4 ;\n" + "pxor %%xmm5, %%xmm5 ;\n" + + /* 0 */ + "movq $0, %%rax ;\n" + "movd %%rax, %%xmm15 ;\n" + "pshufd $0x00, %%xmm15, %%xmm15 ;\n" + "pcmpeqd %%xmm14, %%xmm15 ;\n" + "movq $1, %%rax ;\n" + "movd %%rax, %%xmm6 ;\n" + "pxor %%xmm7, %%xmm7 ;\n" + "pand %%xmm15, %%xmm6 ;\n" + "pand %%xmm15, %%xmm7 ;\n" + "por %%xmm6, %%xmm0 ;\n" + "por %%xmm7, %%xmm1 ;\n" + "por %%xmm6, %%xmm2 ;\n" + "por %%xmm7, %%xmm3 ;\n" + + /* 1 */ + "movq $1, %%rax ;\n" + "movd %%rax, %%xmm15 ;\n" + "pshufd $0x00, %%xmm15, %%xmm15 ;\n" + "pcmpeqd %%xmm14, %%xmm15 ;\n" + "movdqa 0(%1), %%xmm6 ;\n" + "movdqa 16(%1), %%xmm7 ;\n" + "movdqa 32(%1), %%xmm8 ;\n" + "movdqa 48(%1), %%xmm9 ;\n" + "movdqa 64(%1), %%xmm10 ;\n" + "movdqa 80(%1), %%xmm11 ;\n" + "pand %%xmm15, %%xmm6 ;\n" + "pand %%xmm15, %%xmm7 ;\n" + "pand %%xmm15, %%xmm8 ;\n" + "pand %%xmm15, %%xmm9 ;\n" + "pand %%xmm15, %%xmm10 ;\n" + "pand %%xmm15, %%xmm11 ;\n" + "por %%xmm6, %%xmm0 ;\n" + "por %%xmm7, %%xmm1 ;\n" + "por %%xmm8, %%xmm2 ;\n" + "por %%xmm9, %%xmm3 ;\n" + "por %%xmm10, %%xmm4 ;\n" + "por %%xmm11, %%xmm5 ;\n" + + /* 2 */ + "movq $2, %%rax ;\n" + "movd %%rax, %%xmm15 ;\n" + "pshufd $0x00, %%xmm15, %%xmm15 ;\n" + "pcmpeqd %%xmm14, %%xmm15 ;\n" + "movdqa 96(%1), %%xmm6 ;\n" + "movdqa 112(%1), %%xmm7 ;\n" + "movdqa 128(%1), %%xmm8 ;\n" + "movdqa 144(%1), %%xmm9 ;\n" + "movdqa 160(%1), %%xmm10 ;\n" + "movdqa 176(%1), %%xmm11 ;\n" + "pand %%xmm15, %%xmm6 ;\n" + "pand %%xmm15, %%xmm7 ;\n" + "pand %%xmm15, %%xmm8 ;\n" + "pand %%xmm15, %%xmm9 ;\n" + "pand %%xmm15, %%xmm10 ;\n" + "pand %%xmm15, %%xmm11 ;\n" + "por %%xmm6, %%xmm0 ;\n" + "por %%xmm7, %%xmm1 ;\n" + "por %%xmm8, %%xmm2 ;\n" + "por %%xmm9, %%xmm3 ;\n" + "por %%xmm10, %%xmm4 ;\n" + "por %%xmm11, %%xmm5 ;\n" + + /* 3 */ + "movq $3, %%rax ;\n" + "movd %%rax, %%xmm15 ;\n" + "pshufd $0x00, %%xmm15, %%xmm15 ;\n" + "pcmpeqd %%xmm14, %%xmm15 ;\n" + "movdqa 192(%1), %%xmm6 ;\n" + "movdqa 208(%1), %%xmm7 ;\n" + "movdqa 224(%1), %%xmm8 ;\n" + "movdqa 240(%1), %%xmm9 ;\n" + "movdqa 256(%1), %%xmm10 ;\n" + "movdqa 272(%1), %%xmm11 ;\n" + "pand %%xmm15, %%xmm6 ;\n" + "pand %%xmm15, %%xmm7 ;\n" + "pand %%xmm15, %%xmm8 ;\n" + "pand %%xmm15, %%xmm9 ;\n" + "pand %%xmm15, %%xmm10 ;\n" + "pand %%xmm15, %%xmm11 ;\n" + "por %%xmm6, %%xmm0 ;\n" + "por %%xmm7, %%xmm1 ;\n" + "por %%xmm8, %%xmm2 ;\n" + "por %%xmm9, %%xmm3 ;\n" + "por %%xmm10, %%xmm4 ;\n" + "por %%xmm11, %%xmm5 ;\n" + + /* 4 */ + "movq $4, %%rax ;\n" + "movd %%rax, %%xmm15 ;\n" + "pshufd $0x00, %%xmm15, %%xmm15 ;\n" + "pcmpeqd %%xmm14, %%xmm15 ;\n" + "movdqa 288(%1), %%xmm6 ;\n" + "movdqa 304(%1), %%xmm7 ;\n" + "movdqa 320(%1), %%xmm8 ;\n" + "movdqa 336(%1), %%xmm9 ;\n" + "movdqa 352(%1), %%xmm10 ;\n" + "movdqa 368(%1), %%xmm11 ;\n" + "pand %%xmm15, %%xmm6 ;\n" + "pand %%xmm15, %%xmm7 ;\n" + "pand %%xmm15, %%xmm8 ;\n" + "pand %%xmm15, %%xmm9 ;\n" + "pand %%xmm15, %%xmm10 ;\n" + "pand %%xmm15, %%xmm11 ;\n" + "por %%xmm6, %%xmm0 ;\n" + "por %%xmm7, %%xmm1 ;\n" + "por %%xmm8, %%xmm2 ;\n" + "por %%xmm9, %%xmm3 ;\n" + "por %%xmm10, %%xmm4 ;\n" + "por %%xmm11, %%xmm5 ;\n" + + /* 5 */ + "movq $5, %%rax ;\n" + "movd %%rax, %%xmm15 ;\n" + "pshufd $0x00, %%xmm15, %%xmm15 ;\n" + "pcmpeqd %%xmm14, %%xmm15 ;\n" + "movdqa 384(%1), %%xmm6 ;\n" + "movdqa 400(%1), %%xmm7 ;\n" + "movdqa 416(%1), %%xmm8 ;\n" + "movdqa 432(%1), %%xmm9 ;\n" + "movdqa 448(%1), %%xmm10 ;\n" + "movdqa 464(%1), %%xmm11 ;\n" + "pand %%xmm15, %%xmm6 ;\n" + "pand %%xmm15, %%xmm7 ;\n" + "pand %%xmm15, %%xmm8 ;\n" + "pand %%xmm15, %%xmm9 ;\n" + "pand %%xmm15, %%xmm10 ;\n" + "pand %%xmm15, %%xmm11 ;\n" + "por %%xmm6, %%xmm0 ;\n" + "por %%xmm7, %%xmm1 ;\n" + "por %%xmm8, %%xmm2 ;\n" + "por %%xmm9, %%xmm3 ;\n" + "por %%xmm10, %%xmm4 ;\n" + "por %%xmm11, %%xmm5 ;\n" + + /* 6 */ + "movq $6, %%rax ;\n" + "movd %%rax, %%xmm15 ;\n" + "pshufd $0x00, %%xmm15, %%xmm15 ;\n" + "pcmpeqd %%xmm14, %%xmm15 ;\n" + "movdqa 480(%1), %%xmm6 ;\n" + "movdqa 496(%1), %%xmm7 ;\n" + "movdqa 512(%1), %%xmm8 ;\n" + "movdqa 528(%1), %%xmm9 ;\n" + "movdqa 544(%1), %%xmm10 ;\n" + "movdqa 560(%1), %%xmm11 ;\n" + "pand %%xmm15, %%xmm6 ;\n" + "pand %%xmm15, %%xmm7 ;\n" + "pand %%xmm15, %%xmm8 ;\n" + "pand %%xmm15, %%xmm9 ;\n" + "pand %%xmm15, %%xmm10 ;\n" + "pand %%xmm15, %%xmm11 ;\n" + "por %%xmm6, %%xmm0 ;\n" + "por %%xmm7, %%xmm1 ;\n" + "por %%xmm8, %%xmm2 ;\n" + "por %%xmm9, %%xmm3 ;\n" + "por %%xmm10, %%xmm4 ;\n" + "por %%xmm11, %%xmm5 ;\n" + + /* 7 */ + "movq $7, %%rax ;\n" + "movd %%rax, %%xmm15 ;\n" + "pshufd $0x00, %%xmm15, %%xmm15 ;\n" + "pcmpeqd %%xmm14, %%xmm15 ;\n" + "movdqa 576(%1), %%xmm6 ;\n" + "movdqa 592(%1), %%xmm7 ;\n" + "movdqa 608(%1), %%xmm8 ;\n" + "movdqa 624(%1), %%xmm9 ;\n" + "movdqa 640(%1), %%xmm10 ;\n" + "movdqa 656(%1), %%xmm11 ;\n" + "pand %%xmm15, %%xmm6 ;\n" + "pand %%xmm15, %%xmm7 ;\n" + "pand %%xmm15, %%xmm8 ;\n" + "pand %%xmm15, %%xmm9 ;\n" + "pand %%xmm15, %%xmm10 ;\n" + "pand %%xmm15, %%xmm11 ;\n" + "por %%xmm6, %%xmm0 ;\n" + "por %%xmm7, %%xmm1 ;\n" + "por %%xmm8, %%xmm2 ;\n" + "por %%xmm9, %%xmm3 ;\n" + "por %%xmm10, %%xmm4 ;\n" + "por %%xmm11, %%xmm5 ;\n" + + /* 8 */ + "movq $8, %%rax ;\n" + "movd %%rax, %%xmm15 ;\n" + "pshufd $0x00, %%xmm15, %%xmm15 ;\n" + "pcmpeqd %%xmm14, %%xmm15 ;\n" + "movdqa 672(%1), %%xmm6 ;\n" + "movdqa 688(%1), %%xmm7 ;\n" + "movdqa 704(%1), %%xmm8 ;\n" + "movdqa 720(%1), %%xmm9 ;\n" + "movdqa 736(%1), %%xmm10 ;\n" + "movdqa 752(%1), %%xmm11 ;\n" + "pand %%xmm15, %%xmm6 ;\n" + "pand %%xmm15, %%xmm7 ;\n" + "pand %%xmm15, %%xmm8 ;\n" + "pand %%xmm15, %%xmm9 ;\n" + "pand %%xmm15, %%xmm10 ;\n" + "pand %%xmm15, %%xmm11 ;\n" + "por %%xmm6, %%xmm0 ;\n" + "por %%xmm7, %%xmm1 ;\n" + "por %%xmm8, %%xmm2 ;\n" + "por %%xmm9, %%xmm3 ;\n" + "por %%xmm10, %%xmm4 ;\n" + "por %%xmm11, %%xmm5 ;\n" + + /* conditionally swap ysubx and xaddy */ + "movq %3, %%rax ;\n" + "xorq $1, %%rax ;\n" + "movd %%rax, %%xmm14 ;\n" + "pxor %%xmm15, %%xmm15 ;\n" + "pshufd $0x00, %%xmm14, %%xmm14 ;\n" + "pxor %%xmm0, %%xmm2 ;\n" + "pxor %%xmm1, %%xmm3 ;\n" + "pcmpeqd %%xmm14, %%xmm15 ;\n" + "movdqa %%xmm2, %%xmm6 ;\n" + "movdqa %%xmm3, %%xmm7 ;\n" + "pand %%xmm15, %%xmm6 ;\n" + "pand %%xmm15, %%xmm7 ;\n" + "pxor %%xmm6, %%xmm0 ;\n" + "pxor %%xmm7, %%xmm1 ;\n" + "pxor %%xmm0, %%xmm2 ;\n" + "pxor %%xmm1, %%xmm3 ;\n" + + /* store ysubx */ + "movq $0x7ffffffffffff, %%rax ;\n" + "movd %%xmm0, %%rcx ;\n" + "movd %%xmm0, %%r8 ;\n" + "movd %%xmm1, %%rsi ;\n" + "pshufd $0xee, %%xmm0, %%xmm0 ;\n" + "pshufd $0xee, %%xmm1, %%xmm1 ;\n" + "movd %%xmm0, %%rdx ;\n" + "movd %%xmm1, %%rdi ;\n" + "shrdq $51, %%rdx, %%r8 ;\n" + "shrdq $38, %%rsi, %%rdx ;\n" + "shrdq $25, %%rdi, %%rsi ;\n" + "shrq $12, %%rdi ;\n" + "andq %%rax, %%rcx ;\n" + "andq %%rax, %%r8 ;\n" + "andq %%rax, %%rdx ;\n" + "andq %%rax, %%rsi ;\n" + "andq %%rax, %%rdi ;\n" + "movq %%rcx, 0(%2) ;\n" + "movq %%r8, 8(%2) ;\n" + "movq %%rdx, 16(%2) ;\n" + "movq %%rsi, 24(%2) ;\n" + "movq %%rdi, 32(%2) ;\n" + + /* store xaddy */ + "movq $0x7ffffffffffff, %%rax ;\n" + "movd %%xmm2, %%rcx ;\n" + "movd %%xmm2, %%r8 ;\n" + "movd %%xmm3, %%rsi ;\n" + "pshufd $0xee, %%xmm2, %%xmm2 ;\n" + "pshufd $0xee, %%xmm3, %%xmm3 ;\n" + "movd %%xmm2, %%rdx ;\n" + "movd %%xmm3, %%rdi ;\n" + "shrdq $51, %%rdx, %%r8 ;\n" + "shrdq $38, %%rsi, %%rdx ;\n" + "shrdq $25, %%rdi, %%rsi ;\n" + "shrq $12, %%rdi ;\n" + "andq %%rax, %%rcx ;\n" + "andq %%rax, %%r8 ;\n" + "andq %%rax, %%rdx ;\n" + "andq %%rax, %%rsi ;\n" + "andq %%rax, %%rdi ;\n" + "movq %%rcx, 40(%2) ;\n" + "movq %%r8, 48(%2) ;\n" + "movq %%rdx, 56(%2) ;\n" + "movq %%rsi, 64(%2) ;\n" + "movq %%rdi, 72(%2) ;\n" + + /* extract t2d */ + "movq $0x7ffffffffffff, %%rax ;\n" + "movd %%xmm4, %%rcx ;\n" + "movd %%xmm4, %%r8 ;\n" + "movd %%xmm5, %%rsi ;\n" + "pshufd $0xee, %%xmm4, %%xmm4 ;\n" + "pshufd $0xee, %%xmm5, %%xmm5 ;\n" + "movd %%xmm4, %%rdx ;\n" + "movd %%xmm5, %%rdi ;\n" + "shrdq $51, %%rdx, %%r8 ;\n" + "shrdq $38, %%rsi, %%rdx ;\n" + "shrdq $25, %%rdi, %%rsi ;\n" + "shrq $12, %%rdi ;\n" + "andq %%rax, %%rcx ;\n" + "andq %%rax, %%r8 ;\n" + "andq %%rax, %%rdx ;\n" + "andq %%rax, %%rsi ;\n" + "andq %%rax, %%rdi ;\n" + + /* conditionally negate t2d */ + "movq %3, %%rax ;\n" + "movq $0xfffffffffffda, %%r9 ;\n" + "movq $0xffffffffffffe, %%r10 ;\n" + "movq %%r10, %%r11 ;\n" + "movq %%r10, %%r12 ;\n" + "movq %%r10, %%r13 ;\n" + "subq %%rcx, %%r9 ;\n" + "subq %%r8, %%r10 ;\n" + "subq %%rdx, %%r11 ;\n" + "subq %%rsi, %%r12 ;\n" + "subq %%rdi, %%r13 ;\n" + "cmpq $1, %%rax ;\n" + "cmove %%r9, %%rcx ;\n" + "cmove %%r10, %%r8 ;\n" + "cmove %%r11, %%rdx ;\n" + "cmove %%r12, %%rsi ;\n" + "cmove %%r13, %%rdi ;\n" + + /* store t2d */ + "movq %%rcx, 80(%2) ;\n" + "movq %%r8, 88(%2) ;\n" + "movq %%rdx, 96(%2) ;\n" + "movq %%rsi, 104(%2) ;\n" + "movq %%rdi, 112(%2) ;\n" + : + : "m"(u), "r"(&table[pos * 8]), "r"(t), "m"(sign) /* %0 = u, %1 = table, %2 = t, %3 = sign */ + : + "%rax", "%rcx", "%rdx", "%rdi", "%rsi", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", + "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "%xmm7", "%xmm8", "%xmm9", "%xmm10", "%xmm11", "%xmm14", "%xmm14", + "cc", "memory" + ); +} + +#endif /* defined(ED25519_GCC_64BIT_X86_CHOOSE) */ + diff --git a/ed25519-donna/ed25519-donna-basepoint-table.h b/ed25519-donna/ed25519-donna-basepoint-table.h new file mode 100644 index 000000000..41dcd526a --- /dev/null +++ b/ed25519-donna/ed25519-donna-basepoint-table.h @@ -0,0 +1,259 @@ +/* multiples of the base point in packed {ysubx, xaddy, t2d} form */ +static const uint8_t ALIGN(16) ge25519_niels_base_multiples[256][96] = { + {0x3e,0x91,0x40,0xd7,0x05,0x39,0x10,0x9d,0xb3,0xbe,0x40,0xd1,0x05,0x9f,0x39,0xfd,0x09,0x8a,0x8f,0x68,0x34,0x84,0xc1,0xa5,0x67,0x12,0xf8,0x98,0x92,0x2f,0xfd,0x44,0x85,0x3b,0x8c,0xf5,0xc6,0x93,0xbc,0x2f,0x19,0x0e,0x8c,0xfb,0xc6,0x2d,0x93,0xcf,0xc2,0x42,0x3d,0x64,0x98,0x48,0x0b,0x27,0x65,0xba,0xd4,0x33,0x3a,0x9d,0xcf,0x07,0x59,0xbb,0x6f,0x4b,0x67,0x15,0xbd,0xdb,0xea,0xa5,0xa2,0xee,0x00,0x3f,0xe1,0x41,0xfa,0xc6,0x57,0xc9,0x1c,0x9d,0xd4,0xcd,0xca,0xec,0x16,0xaf,0x1f,0xbe,0x0e,0x4f}, + {0xa8,0xd5,0xb4,0x42,0x60,0xa5,0x99,0x8a,0xf6,0xac,0x60,0x4e,0x0c,0x81,0x2b,0x8f,0xaa,0x37,0x6e,0xb1,0x6b,0x23,0x9e,0xe0,0x55,0x25,0xc9,0x69,0xa6,0x95,0xb5,0x6b,0xd7,0x71,0x3c,0x93,0xfc,0xe7,0x24,0x92,0xb5,0xf5,0x0f,0x7a,0x96,0x9d,0x46,0x9f,0x02,0x07,0xd6,0xe1,0x65,0x9a,0xa6,0x5a,0x2e,0x2e,0x7d,0xa8,0x3f,0x06,0x0c,0x59,0x02,0x68,0xd3,0xda,0xaa,0x7e,0x34,0x6e,0x05,0x48,0xee,0x83,0x93,0x59,0xf3,0xba,0x26,0x68,0x07,0xe6,0x10,0xbe,0xca,0x3b,0xb8,0xd1,0x5e,0x16,0x0a,0x4f,0x31,0x49}, + {0x65,0xd2,0xfc,0xa4,0xe8,0x1f,0x61,0x56,0x7d,0xba,0xc1,0xe5,0xfd,0x53,0xd3,0x3b,0xbd,0xd6,0x4b,0x21,0x1a,0xf3,0x31,0x81,0x62,0xda,0x5b,0x55,0x87,0x15,0xb9,0x2a,0x30,0x97,0xee,0x4c,0xa8,0xb0,0x25,0xaf,0x8a,0x4b,0x86,0xe8,0x30,0x84,0x5a,0x02,0x32,0x67,0x01,0x9f,0x02,0x50,0x1b,0xc1,0xf4,0xf8,0x80,0x9a,0x1b,0x4e,0x16,0x7a,0x34,0x48,0x67,0xf1,0xf4,0x11,0xf2,0x9b,0x95,0xf8,0x2d,0xf6,0x17,0x6b,0x4e,0xb8,0x4e,0x2a,0x72,0x5b,0x07,0x6f,0xde,0xd7,0x21,0x2a,0xbb,0x63,0xb9,0x04,0x9a,0x54}, + {0xbf,0x18,0x68,0x05,0x0a,0x05,0xfe,0x95,0xa9,0xfa,0x60,0x56,0x71,0x89,0x7e,0x32,0x73,0x50,0xa0,0x06,0xcd,0xe3,0xe8,0xc3,0x9a,0xa4,0x45,0x74,0x4c,0x3f,0x93,0x27,0x9f,0x09,0xfc,0x8e,0xb9,0x51,0x73,0x28,0x38,0x25,0xfd,0x7d,0xf4,0xc6,0x65,0x67,0x65,0x92,0x0a,0xfb,0x3d,0x8d,0x34,0xca,0x27,0x87,0xe5,0x21,0x03,0x91,0x0e,0x68,0xb0,0x26,0x14,0xe5,0xec,0x45,0x1e,0xbf,0x94,0x0f,0xba,0x6d,0x3d,0xc6,0x2b,0xe3,0xc0,0x52,0xf8,0x8c,0xd5,0x74,0x29,0xe4,0x18,0x4c,0xe6,0xb0,0xb1,0x79,0xf0,0x44}, + {0xba,0xd6,0x47,0xa4,0xc3,0x82,0x91,0x7f,0xb7,0x29,0x27,0x4b,0xd1,0x14,0x00,0xd5,0x87,0xa0,0x64,0xb8,0x1c,0xf1,0x3c,0xe3,0xf3,0x55,0x1b,0xeb,0x73,0x7e,0x4a,0x15,0x33,0xbb,0xa5,0x08,0x44,0xbc,0x12,0xa2,0x02,0xed,0x5e,0xc7,0xc3,0x48,0x50,0x8d,0x44,0xec,0xbf,0x5a,0x0c,0xeb,0x1b,0xdd,0xeb,0x06,0xe2,0x46,0xf1,0xcc,0x45,0x29,0xb3,0x03,0xd0,0xe7,0x79,0xa1,0x32,0xc8,0x7e,0x4d,0x12,0x00,0x0a,0x9d,0x72,0x5f,0xf3,0x8f,0x6d,0x0e,0xa1,0xd4,0xc1,0x62,0x98,0x7a,0xb2,0x38,0x59,0xac,0xb8,0x68}, + {0xa4,0x8c,0x7d,0x7b,0xb6,0x06,0x98,0x49,0x39,0x27,0xd2,0x27,0x84,0xe2,0x5b,0x57,0xb9,0x53,0x45,0x20,0xe7,0x5c,0x08,0xbb,0x84,0x78,0x41,0xae,0x41,0x4c,0xb6,0x38,0x31,0x71,0x15,0x77,0xeb,0xee,0x0c,0x3a,0x88,0xaf,0xc8,0x00,0x89,0x15,0x27,0x9b,0x36,0xa7,0x59,0xda,0x68,0xb6,0x65,0x80,0xbd,0x38,0xcc,0xa2,0xb6,0x7b,0xe5,0x51,0xa4,0xe3,0x9d,0x68,0x91,0xad,0x9d,0x8f,0x37,0x91,0xfb,0xf8,0x28,0x24,0x5f,0x17,0x88,0xb9,0xcf,0x9f,0x32,0xb5,0x0a,0x05,0x9f,0xc0,0x54,0x13,0xa2,0xdf,0x65,0x78}, + {0xb1,0x21,0x32,0xaa,0x9a,0x2c,0x6f,0xba,0xa7,0x23,0xba,0x3b,0x53,0x21,0xa0,0x6c,0x3a,0x2c,0x19,0x92,0x4f,0x76,0xea,0x9d,0xe0,0x17,0x53,0x2e,0x5d,0xdd,0x6e,0x1d,0xbf,0xa3,0x4e,0x94,0xd0,0x5c,0x1a,0x6b,0xd2,0xc0,0x9d,0xb3,0x3a,0x35,0x70,0x74,0x49,0x2e,0x54,0x28,0x82,0x52,0xb2,0x71,0x7e,0x92,0x3c,0x28,0x69,0xea,0x1b,0x46,0x36,0xda,0x0f,0xab,0xac,0x8a,0x7a,0x21,0xc8,0x49,0x35,0x3d,0x54,0xc6,0x28,0xa5,0x68,0x75,0xab,0x13,0x8b,0x5b,0xd0,0x37,0x37,0xbc,0x2c,0x3a,0x62,0xef,0x3c,0x23}, + {0xd9,0x34,0x92,0xf3,0xed,0x5d,0xa7,0xe2,0xf9,0x58,0xb5,0xe1,0x80,0x76,0x3d,0x96,0xfb,0x23,0x3c,0x6e,0xac,0x41,0x27,0x2c,0xc3,0x01,0x0e,0x32,0xa1,0x24,0x90,0x3a,0x8f,0x3e,0xdd,0x04,0x66,0x59,0xb7,0x59,0x2c,0x70,0x88,0xe2,0x77,0x03,0xb3,0x6c,0x23,0xc3,0xd9,0x5e,0x66,0x9c,0x33,0xb1,0x2f,0xe5,0xbc,0x61,0x60,0xe7,0x15,0x09,0x7e,0xa3,0x34,0xa8,0x35,0xe8,0x7d,0xdf,0xea,0x57,0x98,0x68,0xda,0x9c,0xe1,0x8b,0x26,0xb3,0x67,0x71,0x36,0x85,0x11,0x2c,0xc2,0xd5,0xef,0xdb,0xd9,0xb3,0x9e,0x58}, + {0x5e,0x51,0xaa,0x49,0x54,0x63,0x5b,0xed,0x3a,0x82,0xc6,0x0b,0x9f,0xc4,0x65,0xa8,0xc4,0xd1,0x42,0x5b,0xe9,0x1f,0x0c,0x85,0xb9,0x15,0xd3,0x03,0x6f,0x6d,0xd7,0x30,0x1d,0x9c,0x2f,0x63,0x0e,0xdd,0xcc,0x2e,0x15,0x31,0x89,0x76,0x96,0xb6,0xd0,0x51,0x58,0x7a,0x63,0xa8,0x6b,0xb7,0xdf,0x52,0x39,0xef,0x0e,0xa0,0x49,0x7d,0xd3,0x6d,0xc7,0xe4,0x06,0x21,0x17,0x44,0x44,0x6c,0x69,0x7f,0x8d,0x92,0x80,0xd6,0x53,0xfb,0x26,0x3f,0x4d,0x69,0xa4,0x9e,0x73,0xb4,0xb0,0x4b,0x86,0x2e,0x11,0x97,0xc6,0x10}, + {0xde,0x5f,0xbe,0x7d,0x27,0xc4,0x93,0x64,0xa2,0x7e,0xad,0x19,0xad,0x4f,0x5d,0x26,0x90,0x45,0x30,0x46,0xc8,0xdf,0x00,0x0e,0x09,0xfe,0x66,0xed,0xab,0x1c,0xe6,0x25,0x05,0xc8,0x58,0x83,0xa0,0x2a,0xa6,0x0c,0x47,0x42,0x20,0x7a,0xe3,0x4a,0x3d,0x6a,0xdc,0xed,0x11,0x3b,0xa6,0xd3,0x64,0x74,0xef,0x06,0x08,0x55,0xaf,0x9b,0xbf,0x03,0x04,0x66,0x58,0xcc,0x28,0xe1,0x13,0x3f,0x7e,0x74,0x59,0xb4,0xec,0x73,0x58,0x6f,0xf5,0x68,0x12,0xcc,0xed,0x3d,0xb6,0xa0,0x2c,0xe2,0x86,0x45,0x63,0x78,0x6d,0x56}, + {0x34,0x08,0xc1,0x9c,0x9f,0xa4,0x37,0x16,0x51,0xc4,0x9b,0xa8,0xd5,0x56,0x8e,0xbc,0xdb,0xd2,0x7f,0x7f,0x0f,0xec,0xb5,0x1c,0xd9,0x35,0xcc,0x5e,0xca,0x5b,0x97,0x33,0xd0,0x2f,0x5a,0xc6,0x85,0x42,0x05,0xa1,0xc3,0x67,0x16,0xf3,0x2a,0x11,0x64,0x6c,0x58,0xee,0x1a,0x73,0x40,0xe2,0x0a,0x68,0x2a,0xb2,0x93,0x47,0xf3,0xa5,0xfb,0x14,0xd4,0xf7,0x85,0x69,0x16,0x46,0xd7,0x3c,0x57,0x00,0xc8,0xc9,0x84,0x5e,0x3e,0x59,0x1e,0x13,0x61,0x7b,0xb6,0xf2,0xc3,0x2f,0x6c,0x52,0xfc,0x83,0xea,0x9c,0x82,0x14}, + {0xc2,0x95,0xdd,0x97,0x84,0x7b,0x43,0xff,0xa7,0xb5,0x4e,0xaa,0x30,0x4e,0x74,0x6c,0x8b,0xe8,0x85,0x3c,0x61,0x5d,0x0c,0x9e,0x73,0x81,0x75,0x5f,0x1e,0xc7,0xd9,0x2f,0xb8,0xec,0x71,0x4e,0x2f,0x0b,0xe7,0x21,0xe3,0x77,0xa4,0x40,0xb9,0xdd,0x56,0xe6,0x80,0x4f,0x1d,0xce,0xce,0x56,0x65,0xbf,0x7e,0x7b,0x5d,0x53,0xc4,0x3b,0xfc,0x05,0xdd,0xde,0xaf,0x52,0xae,0xb3,0xb8,0x24,0xcf,0x30,0x3b,0xed,0x8c,0x63,0x95,0x34,0x95,0x81,0xbe,0xa9,0x83,0xbc,0xa4,0x33,0x04,0x1f,0x65,0x5c,0x47,0x67,0x37,0x37}, + {0xd9,0xad,0xd1,0x40,0xfd,0x99,0xba,0x2f,0x27,0xd0,0xf4,0x96,0x6f,0x16,0x07,0xb3,0xae,0x3b,0xf0,0x15,0x52,0xf0,0x63,0x43,0x99,0xf9,0x18,0x3b,0x6c,0xa5,0xbe,0x1f,0x90,0x65,0x24,0x14,0xcb,0x95,0x40,0x63,0x35,0x55,0xc1,0x16,0x40,0x14,0x12,0xef,0x60,0xbc,0x10,0x89,0x0c,0x14,0x38,0x9e,0x8c,0x7c,0x90,0x30,0x57,0x90,0xf5,0x6b,0x8a,0x5b,0x41,0xe1,0xf1,0x78,0xa7,0x0f,0x7e,0xa7,0xc3,0xba,0xf7,0x9f,0x40,0x06,0x50,0x9a,0xa2,0x9a,0xb8,0xd7,0x52,0x6f,0x56,0x5a,0x63,0x7a,0xf6,0x1c,0x52,0x02}, + {0x94,0x52,0x9d,0x0a,0x0b,0xee,0x3f,0x51,0x66,0x5a,0xdf,0x0f,0x5c,0xe7,0x98,0x8f,0xce,0x07,0xe1,0xbf,0x88,0x86,0x61,0xd4,0xed,0x2c,0x38,0x71,0x7e,0x0a,0xa0,0x3f,0xe4,0x5e,0x2f,0x77,0x20,0x67,0x14,0xb1,0xce,0x9a,0x07,0x96,0xb1,0x94,0xf8,0xe8,0x4a,0x82,0xac,0x00,0x4d,0x22,0xf8,0x4a,0xc4,0x6c,0xcd,0xf7,0xd9,0x53,0x17,0x00,0x34,0xdb,0x3d,0x96,0x2d,0x23,0x69,0x3c,0x58,0x38,0x97,0xb4,0xda,0x87,0xde,0x1d,0x85,0xf2,0x91,0xa0,0xf9,0xd1,0xd7,0xaa,0xb6,0xed,0x48,0xa0,0x2f,0xfe,0xb5,0x12}, + {0x4d,0xe3,0xfc,0x96,0xc4,0xfb,0xf0,0x71,0xed,0x5b,0xf3,0xad,0x6b,0x82,0xb9,0x73,0x61,0xc5,0x28,0xff,0x61,0x72,0x04,0xd2,0x6f,0x20,0xb1,0x6f,0xf9,0x76,0x9b,0x74,0x92,0x1e,0x6f,0xad,0x26,0x7c,0x2b,0xdf,0x13,0x89,0x4b,0x50,0x23,0xd3,0x66,0x4b,0xc3,0x8b,0x1c,0x75,0xc0,0x9d,0x40,0x8c,0xb8,0xc7,0x96,0x07,0xc2,0x93,0x7e,0x6f,0x05,0xae,0xa6,0xae,0x04,0xf6,0x5a,0x1f,0x99,0x9c,0xe4,0xbe,0xf1,0x51,0x23,0xc1,0x66,0x6b,0xff,0xee,0xb5,0x08,0xa8,0x61,0x51,0x21,0xe0,0x01,0x0f,0xc1,0xce,0x0f}, + {0x44,0x1e,0xfe,0x49,0xa6,0x58,0x4d,0x64,0x7e,0x77,0xad,0x31,0xa2,0xae,0xfc,0x21,0xd2,0xd0,0x7f,0x88,0x5a,0x1c,0x44,0x02,0xf3,0x11,0xc5,0x83,0x71,0xaa,0x01,0x49,0x45,0x4e,0x24,0xc4,0x9d,0xd2,0xf2,0x3d,0x0a,0xde,0xd8,0x93,0x74,0x0e,0x02,0x2b,0x4d,0x21,0x0c,0x82,0x7e,0x06,0xc8,0x6c,0x0a,0xb9,0xea,0x6f,0x16,0x79,0x37,0x41,0xf0,0xf8,0x1a,0x8c,0x54,0xb7,0xb1,0x08,0xb4,0x99,0x62,0x24,0x7c,0x7a,0x0f,0xce,0x39,0xd9,0x06,0x1e,0xf9,0xb0,0x60,0xf7,0x13,0x12,0x6d,0x72,0x7b,0x88,0xbb,0x41}, + {0xbe,0x46,0x43,0x74,0x44,0x7d,0xe8,0x40,0x25,0x2b,0xb5,0x15,0xd4,0xda,0x48,0x1d,0x3e,0x60,0x3b,0xa1,0x18,0x8a,0x3a,0x7c,0xf7,0xbd,0xcd,0x2f,0xc1,0x28,0xb7,0x4e,0xae,0x91,0x66,0x7c,0x59,0x4c,0x23,0x7e,0xc8,0xb4,0x85,0x0a,0x3d,0x9d,0x88,0x64,0xe7,0xfa,0x4a,0x35,0x0c,0xc9,0xe2,0xda,0x1d,0x9e,0x6a,0x0c,0x07,0x1e,0x87,0x0a,0x89,0x89,0xbc,0x4b,0x99,0xb5,0x01,0x33,0x60,0x42,0xdd,0x5b,0x3a,0xae,0x6b,0x73,0x3c,0x9e,0xd5,0x19,0xe2,0xad,0x61,0x0d,0x64,0xd4,0x85,0x26,0x0f,0x30,0xe7,0x3e}, + {0xb7,0xd6,0x7d,0x9e,0xe4,0x55,0xd2,0xf5,0xac,0x1e,0x0b,0x61,0x5c,0x11,0x16,0x80,0xca,0x87,0xe1,0x92,0x5d,0x97,0x99,0x3c,0xc2,0x25,0x91,0x97,0x62,0x57,0x81,0x13,0x18,0x75,0x1e,0x84,0x47,0x79,0xfa,0x43,0xd7,0x46,0x9c,0x63,0x59,0xfa,0xc6,0xe5,0x74,0x2b,0x05,0xe3,0x1d,0x5e,0x06,0xa1,0x30,0x90,0xb8,0xcf,0xa2,0xc6,0x47,0x7d,0xe0,0xd6,0xf0,0x8e,0x14,0xd0,0xda,0x3f,0x3c,0x6f,0x54,0x91,0x9a,0x74,0x3e,0x9d,0x57,0x81,0xbb,0x26,0x10,0x62,0xec,0x71,0x80,0xec,0xc9,0x34,0x8d,0xf5,0x8c,0x14}, + {0x27,0xf0,0x34,0x79,0xf6,0x92,0xa4,0x46,0xa9,0x0a,0x84,0xf6,0xbe,0x84,0x99,0x46,0x54,0x18,0x61,0x89,0x2a,0xbc,0xa1,0x5c,0xd4,0xbb,0x5d,0xbd,0x1e,0xfa,0xf2,0x3f,0x6d,0x75,0xe4,0x9a,0x7d,0x2f,0x57,0xe2,0x7f,0x48,0xf3,0x88,0xbb,0x45,0xc3,0x56,0x8d,0xa8,0x60,0x69,0x6d,0x0b,0xd1,0x9f,0xb9,0xa1,0xae,0x4e,0xad,0xeb,0x8f,0x27,0x66,0x39,0x93,0x8c,0x1f,0x68,0xaa,0xb1,0x98,0x0c,0x29,0x20,0x9c,0x94,0x21,0x8c,0x52,0x3c,0x9d,0x21,0x91,0x52,0x11,0x39,0x7b,0x67,0x9c,0xfe,0x02,0xdd,0x04,0x41}, + {0x2a,0x42,0x24,0x11,0x5e,0xbf,0xb2,0x72,0xb5,0x3a,0xa3,0x98,0x33,0x0c,0xfa,0xa1,0x66,0xb6,0x52,0xfa,0x01,0x61,0xcb,0x94,0xd5,0x53,0xaf,0xaf,0x00,0x3b,0x86,0x2c,0xb8,0x6a,0x09,0xdb,0x06,0x4e,0x21,0x81,0x35,0x4f,0xe4,0x0c,0xc9,0xb6,0xa8,0x21,0xf5,0x2a,0x9e,0x40,0x2a,0xc1,0x24,0x65,0x81,0xa4,0xfc,0x8e,0xa4,0xb5,0x65,0x01,0x76,0x6a,0x84,0xa0,0x74,0xa4,0x90,0xf1,0xc0,0x7c,0x2f,0xcd,0x84,0xf9,0xef,0x12,0x8f,0x2b,0xaa,0x58,0x06,0x29,0x5e,0x69,0xb8,0xc8,0xfe,0xbf,0xd9,0x67,0x1b,0x59}, + {0xfa,0x9b,0xb4,0x80,0x1c,0x0d,0x2f,0x31,0x8a,0xec,0xf3,0xab,0x5e,0x51,0x79,0x59,0x88,0x1c,0xf0,0x9e,0xc0,0x33,0x70,0x72,0xcb,0x7b,0x8f,0xca,0xc7,0x2e,0xe0,0x3d,0x5d,0xb5,0x18,0x9f,0x71,0xb3,0xb9,0x99,0x1e,0x64,0x8c,0xa1,0xfa,0xe5,0x65,0xe4,0xed,0x05,0x9f,0xc2,0x36,0x11,0x08,0x61,0x8b,0x12,0x30,0x70,0x86,0x4f,0x9b,0x48,0xef,0x92,0xeb,0x3a,0x2d,0x10,0x32,0xd2,0x61,0xa8,0x16,0x61,0xb4,0x53,0x62,0xe1,0x24,0xaa,0x0b,0x19,0xe7,0xab,0x7e,0x3d,0xbf,0xbe,0x6c,0x49,0xba,0xfb,0xf5,0x49}, + {0xd4,0xcf,0x5b,0x8a,0x10,0x9a,0x94,0x30,0xeb,0x73,0x64,0xbc,0x70,0xdd,0x40,0xdc,0x1c,0x0d,0x7c,0x30,0xc1,0x94,0xc2,0x92,0x74,0x6e,0xfa,0xcb,0x6d,0xa8,0x04,0x56,0x2e,0x57,0x9c,0x1e,0x8c,0x62,0x5d,0x15,0x41,0x47,0x88,0xc5,0xac,0x86,0x4d,0x8a,0xeb,0x63,0x57,0x51,0xf6,0x52,0xa3,0x91,0x5b,0x51,0x67,0x88,0xc2,0xa6,0xa1,0x06,0xb6,0x64,0x17,0x7c,0xd4,0xd1,0x88,0x72,0x51,0x8b,0x41,0xe0,0x40,0x11,0x54,0x72,0xd1,0xf6,0xac,0x18,0x60,0x1a,0x03,0x9f,0xc6,0x42,0x27,0xfe,0x89,0x9e,0x98,0x20}, + {0x7f,0xcc,0x2d,0x3a,0xfd,0x77,0x97,0x49,0x92,0xd8,0x4f,0xa5,0x2c,0x7c,0x85,0x32,0xa0,0xe3,0x07,0xd2,0x64,0xd8,0x79,0xa2,0x29,0x7e,0xa6,0x0c,0x1d,0xed,0x03,0x04,0x2e,0xec,0xea,0x85,0x8b,0x27,0x74,0x16,0xdf,0x2b,0xcb,0x7a,0x07,0xdc,0x21,0x56,0x5a,0xf4,0xcb,0x61,0x16,0x4c,0x0a,0x64,0xd3,0x95,0x05,0xf7,0x50,0x99,0x0b,0x73,0x52,0xc5,0x4e,0x87,0x35,0x2d,0x4b,0xc9,0x8d,0x6f,0x24,0x98,0xcf,0xc8,0xe6,0xc5,0xce,0x35,0xc0,0x16,0xfa,0x46,0xcb,0xf7,0xcc,0x3d,0x30,0x08,0x43,0x45,0xd7,0x5b}, + {0xc2,0x4c,0xb2,0x28,0x95,0xd1,0x9a,0x7f,0x81,0xc1,0x35,0x63,0x65,0x54,0x6b,0x7f,0x36,0x72,0xc0,0x4f,0x6e,0xb6,0xb8,0x66,0x83,0xad,0x80,0x73,0x00,0x78,0x3a,0x13,0x2a,0x79,0xe7,0x15,0x21,0x93,0xc4,0x85,0xc9,0xdd,0xcd,0xbd,0xa2,0x89,0x4c,0xc6,0x62,0xd7,0xa3,0xad,0xa8,0x3d,0x1e,0x9d,0x2c,0xf8,0x67,0x30,0x12,0xdb,0xb7,0x5b,0xbe,0x62,0xca,0xc6,0x67,0xf4,0x61,0x09,0xee,0x52,0x19,0x21,0xd6,0x21,0xec,0x04,0x70,0x47,0xd5,0x9b,0x77,0x60,0x23,0x18,0xd2,0xe0,0xf0,0x58,0x6d,0xca,0x0d,0x74}, + {0x4e,0xce,0xcf,0x52,0x07,0xee,0x48,0xdf,0xb7,0x08,0xec,0x06,0xf3,0xfa,0xff,0xc3,0xc4,0x59,0x54,0xb9,0x2a,0x0b,0x71,0x05,0x8d,0xa3,0x3e,0x96,0xfa,0x25,0x1d,0x16,0x3c,0x43,0x78,0x04,0x57,0x8c,0x1a,0x23,0x9d,0x43,0x81,0xc2,0x0e,0x27,0xb5,0xb7,0x9f,0x07,0xd9,0xe3,0xea,0x99,0xaa,0xdb,0xd9,0x03,0x2b,0x6c,0x25,0xf5,0x03,0x2c,0x7d,0xa4,0x53,0x7b,0x75,0x18,0x0f,0x79,0x79,0x58,0x0c,0xcf,0x30,0x01,0x7b,0x30,0xf9,0xf7,0x7e,0x25,0x77,0x3d,0x90,0x31,0xaf,0xbb,0x96,0xbd,0xbd,0x68,0x94,0x69}, + {0xcf,0xfe,0xda,0xf4,0x46,0x2f,0x1f,0xbd,0xf7,0xd6,0x7f,0xa4,0x14,0x01,0xef,0x7c,0x7f,0xb3,0x47,0x4a,0xda,0xfd,0x1f,0xd3,0x85,0x57,0x90,0x73,0xa4,0x19,0x52,0x52,0x48,0x19,0xa9,0x6a,0xe6,0x3d,0xdd,0xd8,0xcc,0xd2,0xc0,0x2f,0xc2,0x64,0x50,0x48,0x2f,0xea,0xfd,0x34,0x66,0x24,0x48,0x9b,0x3a,0x2e,0x4a,0x6c,0x4e,0x1c,0x3e,0x29,0xe1,0x12,0x51,0x92,0x4b,0x13,0x6e,0x37,0xa0,0x5d,0xa1,0xdc,0xb5,0x78,0x37,0x70,0x11,0x31,0x1c,0x46,0xaf,0x89,0x45,0xb0,0x23,0x28,0x03,0x7f,0x44,0x5c,0x60,0x5b}, + {0x89,0x7c,0xc4,0x20,0x59,0x80,0x65,0xb9,0xcc,0x8f,0x3b,0x92,0x0c,0x10,0xf0,0xe7,0x77,0xef,0xe2,0x02,0x65,0x25,0x01,0x00,0xee,0xb3,0xae,0xa8,0xce,0x6d,0xa7,0x24,0x4c,0xf0,0xe7,0xf0,0xc6,0xfe,0xe9,0x3b,0x62,0x49,0xe3,0x75,0x9e,0x57,0x6a,0x86,0x1a,0xe6,0x1d,0x1e,0x16,0xef,0x42,0x55,0xd5,0xbd,0x5a,0xcc,0xf4,0xfe,0x12,0x2f,0x40,0xc7,0xc0,0xdf,0xb2,0x22,0x45,0x0a,0x07,0xa4,0xc9,0x40,0x7f,0x6e,0xd0,0x10,0x68,0xf6,0xcf,0x78,0x41,0x14,0xcf,0xc6,0x90,0x37,0xa4,0x18,0x25,0x7b,0x60,0x5e}, + {0x18,0x18,0xdf,0x6c,0x8f,0x1d,0xb3,0x58,0xa2,0x58,0x62,0xc3,0x4f,0xa7,0xcf,0x35,0x6e,0x1d,0xe6,0x66,0x4f,0xff,0xb3,0xe1,0xf7,0xd5,0xcd,0x6c,0xab,0xac,0x67,0x50,0x14,0xcf,0x96,0xa5,0x1c,0x43,0x2c,0xa0,0x00,0xe4,0xd3,0xae,0x40,0x2d,0xc4,0xe3,0xdb,0x26,0x0f,0x2e,0x80,0x26,0x45,0xd2,0x68,0x70,0x45,0x9e,0x13,0x33,0x1f,0x20,0x51,0x9d,0x03,0x08,0x6b,0x7f,0x52,0xfd,0x06,0x00,0x7c,0x01,0x64,0x49,0xb1,0x18,0xa8,0xa4,0x25,0x2e,0xb0,0x0e,0x22,0xd5,0x75,0x03,0x46,0x62,0x88,0xba,0x7c,0x39}, + {0xb2,0x59,0x59,0xf0,0x93,0x30,0xc1,0x30,0x76,0x79,0xa9,0xe9,0x8d,0xa1,0x3a,0xe2,0x26,0x5e,0x1d,0x72,0x91,0xd4,0x2f,0x22,0x3a,0x6c,0x6e,0x76,0x20,0xd3,0x39,0x23,0xe7,0x79,0x13,0xc8,0xfb,0xc3,0x15,0x78,0xf1,0x2a,0xe1,0xdd,0x20,0x94,0x61,0xa6,0xd5,0xfd,0xa8,0x85,0xf8,0xc0,0xa9,0xff,0x52,0xc2,0xe1,0xc1,0x22,0x40,0x1b,0x77,0xa7,0x2f,0x3a,0x51,0x86,0xd9,0x7d,0xd8,0x08,0xcf,0xd4,0xf9,0x71,0x9b,0xac,0xf5,0xb3,0x83,0xa2,0x1e,0x1b,0xc3,0x6b,0xd0,0x76,0x1a,0x97,0x19,0x92,0x18,0x1a,0x33}, + {0xc6,0x80,0x4f,0xfb,0x45,0x6f,0x16,0xf5,0xcf,0x75,0xc7,0x61,0xde,0xc7,0x36,0x9c,0x1c,0xd9,0x41,0x90,0x1b,0xe8,0xd4,0xe3,0x21,0xfe,0xbd,0x83,0x6b,0x7c,0x16,0x31,0xaf,0x72,0x75,0x9d,0x3a,0x2f,0x51,0x26,0x9e,0x4a,0x07,0x68,0x88,0xe2,0xcb,0x5b,0xc4,0xf7,0x80,0x11,0xc1,0xc1,0xed,0x84,0x7b,0xa6,0x49,0xf6,0x9f,0x61,0xc9,0x1a,0x68,0x10,0x4b,0x52,0x42,0x38,0x2b,0xf2,0x87,0xe9,0x9c,0xee,0x3b,0x34,0x68,0x50,0xc8,0x50,0x62,0x4a,0x84,0x71,0x9d,0xfc,0x11,0xb1,0x08,0x1f,0x34,0x36,0x24,0x61}, + {0x8d,0x89,0x4e,0x87,0xdb,0x41,0x9d,0xd9,0x20,0xdc,0x07,0x6c,0xf1,0xa5,0xfe,0x09,0xbc,0x9b,0x0f,0xd0,0x67,0x2c,0x3d,0x79,0x40,0xff,0x5e,0x9e,0x30,0xe2,0xeb,0x46,0x38,0x26,0x2d,0x1a,0xe3,0x49,0x63,0x8b,0x35,0xfd,0xd3,0x9b,0x00,0xb7,0xdf,0x9d,0xa4,0x6b,0xa0,0xa3,0xb8,0xf1,0x8b,0x7f,0x45,0x04,0xd9,0x78,0x31,0xaa,0x22,0x15,0x38,0x49,0x61,0x69,0x53,0x2f,0x38,0x2c,0x10,0x6d,0x2d,0xb7,0x9a,0x40,0xfe,0xda,0x27,0xf2,0x46,0xb6,0x91,0x33,0xc8,0xe8,0x6c,0x30,0x24,0x05,0xf5,0x70,0xfe,0x45}, + {0x8c,0x0b,0x0c,0x96,0xa6,0x75,0x48,0xda,0x20,0x2f,0x0e,0xef,0x76,0xd0,0x68,0x5b,0xd4,0x8f,0x0b,0x3d,0xcf,0x51,0xfb,0x07,0xd4,0x92,0xe3,0xa0,0x23,0x16,0x8d,0x42,0x91,0x14,0x95,0xc8,0x20,0x49,0xf2,0x62,0xa2,0x0c,0x63,0x3f,0xc8,0x07,0xf0,0x05,0xb8,0xd4,0xc9,0xf5,0xd2,0x45,0xbb,0x6f,0x45,0x22,0x7a,0xb5,0x6d,0x9f,0x61,0x16,0xfd,0x08,0xa3,0x01,0x44,0x4a,0x4f,0x08,0xac,0xca,0xa5,0x76,0xc3,0x19,0x22,0xa8,0x7d,0xbc,0xd1,0x43,0x46,0xde,0xb8,0xde,0xc6,0x38,0xbd,0x60,0x2d,0x59,0x81,0x1d}, + {0x5f,0xac,0x0d,0xa6,0x56,0x87,0x36,0x61,0x57,0xdc,0xab,0xeb,0x6a,0x2f,0xe0,0x17,0x7d,0x0f,0xce,0x4c,0x2d,0x3f,0x19,0x7f,0xf0,0xdc,0xec,0x89,0x77,0x4a,0x23,0x20,0xe8,0xc5,0x85,0x7b,0x9f,0xb6,0x65,0x87,0xb2,0xba,0x68,0xd1,0x8b,0x67,0xf0,0x6f,0x9b,0x0f,0x33,0x1d,0x7c,0xe7,0x70,0x3a,0x7c,0x8e,0xaf,0xb0,0x51,0x6d,0x5f,0x3a,0x52,0xb2,0x78,0x71,0xb6,0x0d,0xd2,0x76,0x60,0xd1,0x1e,0xd5,0xf9,0x34,0x1c,0x07,0x70,0x11,0xe4,0xb3,0x20,0x4a,0x2a,0xf6,0x66,0xe3,0xff,0x3c,0x35,0x82,0xd6,0x7c}, + {0xb6,0xfa,0x87,0xd8,0x5b,0xa4,0xe1,0x0b,0x6e,0x3b,0x40,0xba,0x32,0x6a,0x84,0x2a,0x00,0x60,0x6e,0xe9,0x12,0x10,0x92,0xd9,0x43,0x09,0xdc,0x3b,0x86,0xc8,0x38,0x28,0xf3,0xf4,0xac,0x68,0x60,0xcd,0x65,0xa6,0xd3,0xe3,0xd7,0x3c,0x18,0x2d,0xd9,0x42,0xd9,0x25,0x60,0x33,0x9d,0x38,0x59,0x57,0xff,0xd8,0x2c,0x2b,0x3b,0x25,0xf0,0x3e,0x30,0x50,0x46,0x4a,0xcf,0xb0,0x6b,0xd1,0xab,0x77,0xc5,0x15,0x41,0x6b,0x49,0xfa,0x9d,0x41,0xab,0xf4,0x8a,0xae,0xcf,0x82,0x12,0x28,0xa8,0x06,0xa6,0xb8,0xdc,0x21}, + {0xc8,0x9f,0x9d,0x8c,0x46,0x04,0x60,0x5c,0xcb,0xa3,0x2a,0xd4,0x6e,0x09,0x40,0x25,0x9c,0x2f,0xee,0x12,0x4c,0x4d,0x5b,0x12,0xab,0x1d,0xa3,0x94,0x81,0xd0,0xc3,0x0b,0xba,0x31,0x77,0xbe,0xfa,0x00,0x8d,0x9a,0x89,0x18,0x9e,0x62,0x7e,0x60,0x03,0x82,0x7f,0xd9,0xf3,0x43,0x37,0x02,0xcc,0xb2,0x8b,0x67,0x6f,0x6c,0xbf,0x0d,0x84,0x5d,0x8b,0xe1,0x9f,0x30,0x0d,0x38,0x6e,0x70,0xc7,0x65,0xe1,0xb9,0xa6,0x2d,0xb0,0x6e,0xab,0x20,0xae,0x7d,0x99,0xba,0xbb,0x57,0xdd,0x96,0xc1,0x2a,0x23,0x76,0x42,0x3a}, + {0xfa,0x84,0x70,0x8a,0x2c,0x43,0x42,0x4b,0x45,0xe5,0xb9,0xdf,0xe3,0x19,0x8a,0x89,0x5d,0xe4,0x58,0x9c,0x21,0x00,0x9f,0xbe,0xd1,0xeb,0x6d,0xa1,0xce,0x77,0xf1,0x1f,0xcb,0x7e,0x44,0xdb,0x72,0xc1,0xf8,0x3b,0xbd,0x2d,0x28,0xc6,0x1f,0xc4,0xcf,0x5f,0xfe,0x15,0xaa,0x75,0xc0,0xff,0xac,0x80,0xf9,0xa9,0xe1,0x24,0xe8,0xc9,0x70,0x07,0xfd,0xb5,0xb5,0x45,0x9a,0xd9,0x61,0xcf,0x24,0x79,0x3a,0x1b,0xe9,0x84,0x09,0x86,0x89,0x3e,0x3e,0x30,0x19,0x09,0x30,0xe7,0x1e,0x0b,0x50,0x41,0xfd,0x64,0xf2,0x39}, + {0x9c,0xe2,0xe7,0xdb,0x17,0x34,0xad,0xa7,0x9c,0x13,0x9c,0x2b,0x6a,0x37,0x94,0xbd,0xa9,0x7b,0x59,0x93,0x8e,0x1b,0xe9,0xa0,0x40,0x98,0x88,0x68,0x34,0xd7,0x12,0x17,0xe1,0x7b,0x09,0xfe,0xab,0x4a,0x9b,0xd1,0x29,0x19,0xe0,0xdf,0xe1,0xfc,0x6d,0xa4,0xff,0xf1,0xa6,0x2c,0x94,0x08,0xc9,0xc3,0x4e,0xf1,0x35,0x2c,0x27,0x21,0xc6,0x65,0xdd,0x93,0x31,0xce,0xf8,0x89,0x2b,0xe7,0xbb,0xc0,0x25,0xa1,0x56,0x33,0x10,0x4d,0x83,0xfe,0x1c,0x2e,0x3d,0xa9,0x19,0x04,0x72,0xe2,0x9c,0xb1,0x0a,0x80,0xf9,0x22}, + {0xcb,0xf8,0x9e,0x3e,0x8a,0x36,0x5a,0x60,0x15,0x47,0x50,0xa5,0x22,0xc0,0xe9,0xe3,0x8f,0x24,0x24,0x5f,0xb0,0x48,0x3d,0x55,0xe5,0x26,0x76,0x64,0xcd,0x16,0xf4,0x13,0xac,0xfd,0x6e,0x9a,0xdd,0x9f,0x02,0x42,0x41,0x49,0xa5,0x34,0xbe,0xce,0x12,0xb9,0x7b,0xf3,0xbd,0x87,0xb9,0x64,0x0f,0x64,0xb4,0xca,0x98,0x85,0xd3,0xa4,0x71,0x41,0x8c,0x4c,0xc9,0x99,0xaa,0x58,0x27,0xfa,0x07,0xb8,0x00,0xb0,0x6f,0x6f,0x00,0x23,0x92,0x53,0xda,0xad,0xdd,0x91,0xd2,0xfb,0xab,0xd1,0x4b,0x57,0xfa,0x14,0x82,0x50}, + {0x4b,0xfe,0xd6,0x3e,0x15,0x69,0x02,0xc2,0xc4,0x77,0x1d,0x51,0x39,0x67,0x5a,0xa6,0x94,0xaf,0x14,0x2c,0x46,0x26,0xde,0xcb,0x4b,0xa7,0xab,0x6f,0xec,0x60,0xf9,0x22,0xd6,0x03,0xd0,0x53,0xbb,0x15,0x1a,0x46,0x65,0xc9,0xf3,0xbc,0x88,0x28,0x10,0xb2,0x5a,0x3a,0x68,0x6c,0x75,0x76,0xc5,0x27,0x47,0xb4,0x6c,0xc8,0xa4,0x58,0x77,0x3a,0x76,0x50,0xae,0x93,0xf6,0x11,0x81,0x54,0xa6,0x54,0xfd,0x1d,0xdf,0x21,0xae,0x1d,0x65,0x5e,0x11,0xf3,0x90,0x8c,0x24,0x12,0x94,0xf4,0xe7,0x8d,0x5f,0xd1,0x9f,0x5d}, + {0x7f,0x72,0x63,0x6d,0xd3,0x08,0x14,0x03,0x33,0xb5,0xc7,0xd7,0xef,0x9a,0x37,0x6a,0x4b,0xe2,0xae,0xcc,0xc5,0x8f,0xe1,0xa9,0xd3,0xbe,0x8f,0x4f,0x91,0x35,0x2f,0x33,0x1e,0x52,0xd7,0xee,0x2a,0x4d,0x24,0x3f,0x15,0x96,0x2e,0x43,0x28,0x90,0x3a,0x8e,0xd4,0x16,0x9c,0x2e,0x77,0xba,0x64,0xe1,0xd8,0x98,0xeb,0x47,0xfa,0x87,0xc1,0x3b,0x0c,0xc2,0x86,0xea,0x15,0x01,0x47,0x6d,0x25,0xd1,0x46,0x6c,0xcb,0xb7,0x8a,0x99,0x88,0x01,0x66,0x3a,0xb5,0x32,0x78,0xd7,0x03,0xba,0x6f,0x90,0xce,0x81,0x0d,0x45}, + {0x75,0x52,0x20,0xa6,0xa1,0xb6,0x7b,0x6e,0x83,0x8e,0x3c,0x41,0xd7,0x21,0x4f,0xaa,0xb2,0x5c,0x8f,0xe8,0x55,0xd1,0x56,0x6f,0xe1,0x5b,0x34,0xa6,0x4b,0x5d,0xe2,0x2d,0x3f,0x74,0xae,0x1c,0x96,0xd8,0x74,0xd0,0xed,0x63,0x1c,0xee,0xf5,0x18,0x6d,0xf8,0x29,0xed,0xf4,0xe7,0x5b,0xc5,0xbd,0x97,0x08,0xb1,0x3a,0x66,0x79,0xd2,0xba,0x4c,0xcd,0x1f,0xd7,0xa0,0x24,0x90,0xd1,0x80,0xf8,0x8a,0x28,0xfb,0x0a,0xc2,0x25,0xc5,0x19,0x64,0x3a,0x5f,0x4b,0x97,0xa3,0xb1,0x33,0x72,0x00,0xe2,0xef,0xbc,0x7f,0x7d}, + {0x01,0x28,0x6b,0x26,0x6a,0x1e,0xef,0xfa,0x16,0x9f,0x73,0xd5,0xc4,0x68,0x6c,0x86,0x2c,0x76,0x03,0x1b,0xbc,0x2f,0x8a,0xf6,0x8d,0x5a,0xb7,0x87,0x5e,0x43,0x75,0x59,0x94,0x90,0xc2,0xf3,0xc5,0x5d,0x7c,0xcd,0xab,0x05,0x91,0x2a,0x9a,0xa2,0x81,0xc7,0x58,0x30,0x1c,0x42,0x36,0x1d,0xc6,0x80,0xd7,0xd4,0xd8,0xdc,0x96,0xd1,0x9c,0x4f,0x68,0x37,0x7b,0x6a,0xd8,0x97,0x92,0x19,0x63,0x7a,0xd1,0x1a,0x24,0x58,0xd0,0xd0,0x17,0x0c,0x1c,0x5c,0xad,0x9c,0x02,0xba,0x07,0x03,0x7a,0x38,0x84,0xd0,0xcd,0x7c}, + {0x17,0x04,0x26,0x6d,0x2c,0x42,0xa6,0xdc,0xbd,0x40,0x82,0x94,0x50,0x3d,0x15,0xae,0x77,0xc6,0x68,0xfb,0xb4,0xc1,0xc0,0xa9,0x53,0xcf,0xd0,0x61,0xed,0xd0,0x8b,0x42,0x93,0xcc,0x60,0x67,0x18,0x84,0x0c,0x9b,0x99,0x2a,0xb3,0x1a,0x7a,0x00,0xae,0xcd,0x18,0xda,0x0b,0x62,0x86,0xec,0x8d,0xa8,0x44,0xca,0x90,0x81,0x84,0xca,0x93,0x35,0xa7,0x9a,0x84,0x5e,0x9a,0x18,0x13,0x92,0xcd,0xfa,0xd8,0x65,0x35,0xc3,0xd8,0xd4,0xd1,0xbb,0xfd,0x53,0x5b,0x54,0x52,0x8c,0xe6,0x63,0x2d,0xda,0x08,0x83,0x39,0x27}, + {0x13,0xd4,0x5e,0x43,0x28,0x8d,0xc3,0x42,0xc9,0xcc,0x78,0x32,0x60,0xf3,0x50,0xbd,0xef,0x03,0xda,0x79,0x1a,0xab,0x07,0xbb,0x55,0x33,0x8c,0xbe,0xae,0x97,0x95,0x26,0x53,0x24,0x70,0x0a,0x4c,0x0e,0xa1,0xb9,0xde,0x1b,0x7d,0xd5,0x66,0x58,0xa2,0x0f,0xf7,0xda,0x27,0xcd,0xb5,0xd9,0xb9,0xff,0xfd,0x33,0x2c,0x49,0x45,0x29,0x2c,0x57,0xbe,0x30,0xcd,0xd6,0x45,0xc7,0x7f,0xc7,0xfb,0xae,0xba,0xe3,0xd3,0xe8,0xdf,0xe4,0x0c,0xda,0x5d,0xaa,0x30,0x88,0x2c,0xa2,0x80,0xca,0x5b,0xc0,0x98,0x54,0x98,0x7f}, + {0x17,0xe1,0x0b,0x9f,0x88,0xce,0x49,0x38,0x88,0xa2,0x54,0x7b,0x1b,0xad,0x05,0x80,0x1c,0x92,0xfc,0x23,0x9f,0xc3,0xa3,0x3d,0x04,0xf3,0x31,0x0a,0x47,0xec,0xc2,0x76,0x63,0x63,0xbf,0x0f,0x52,0x15,0x56,0xd3,0xa6,0xfb,0x4d,0xcf,0x45,0x5a,0x04,0x08,0xc2,0xa0,0x3f,0x87,0xbc,0x4f,0xc2,0xee,0xe7,0x12,0x9b,0xd6,0x3c,0x65,0xf2,0x30,0x85,0x0c,0xc1,0xaa,0x38,0xc9,0x08,0x8a,0xcb,0x6b,0x27,0xdb,0x60,0x9b,0x17,0x46,0x70,0xac,0x6f,0x0e,0x1e,0xc0,0x20,0xa9,0xda,0x73,0x64,0x59,0xf1,0x73,0x12,0x2f}, + {0x11,0x1e,0xe0,0x8a,0x7c,0xfc,0x39,0x47,0x9f,0xab,0x6a,0x4a,0x90,0x74,0x52,0xfd,0x2e,0x8f,0x72,0x87,0x82,0x8a,0xd9,0x41,0xf2,0x69,0x5b,0xd8,0x2a,0x57,0x9e,0x5d,0xc0,0x0b,0xa7,0x55,0xd7,0x8b,0x48,0x30,0xe7,0x42,0xd4,0xf1,0xa4,0xb5,0xd6,0x06,0x62,0x61,0x59,0xbc,0x9e,0xa6,0xd1,0xea,0x84,0xf7,0xc5,0xed,0x97,0x19,0xac,0x38,0x3b,0xb1,0x51,0xa7,0x17,0xb5,0x66,0x06,0x8c,0x85,0x9b,0x7e,0x86,0x06,0x7d,0x74,0x49,0xde,0x4d,0x45,0x11,0xc0,0xac,0xac,0x9c,0xe6,0xe9,0xbf,0x9c,0xcd,0xdf,0x22}, + {0xd9,0x0c,0x0d,0xc3,0xe0,0xd2,0xdb,0x8d,0x33,0x43,0xbb,0xac,0x5f,0x66,0x8e,0xad,0x1f,0x96,0x2a,0x32,0x8c,0x25,0x6b,0x8f,0xc7,0xc1,0x48,0x54,0xc0,0x16,0x29,0x6b,0xa1,0xe0,0x3b,0x10,0xb4,0x59,0xec,0x56,0x69,0xf9,0x59,0xd2,0xec,0xba,0xe3,0x2e,0x32,0xcd,0xf5,0x13,0x94,0xb2,0x7c,0x79,0x72,0xe4,0xcd,0x24,0x78,0x87,0xe9,0x0f,0x3b,0x91,0xba,0x0a,0xd1,0x34,0xdb,0x7e,0x0e,0xac,0x6d,0x2e,0x82,0xcd,0xa3,0x4e,0x15,0xf8,0x78,0x65,0xff,0x3d,0x08,0x66,0x17,0x0a,0xf0,0x7f,0x30,0x3f,0x30,0x4c}, + {0x85,0x8c,0xb2,0x17,0xd6,0x3b,0x0a,0xd3,0xea,0x3b,0x77,0x39,0xb7,0x77,0xd3,0xc5,0xbf,0x5c,0x6a,0x1e,0x8c,0xe7,0xc6,0xc6,0xc4,0xb7,0x2a,0x8b,0xf7,0xb8,0x61,0x0d,0x00,0x45,0xd9,0x0d,0x58,0x03,0xfc,0x29,0x93,0xec,0xbb,0x6f,0xa4,0x7a,0xd2,0xec,0xf8,0xa7,0xe2,0xc2,0x5f,0x15,0x0a,0x13,0xd5,0xa1,0x06,0xb7,0x1a,0x15,0x6b,0x41,0xb0,0x36,0xc1,0xe9,0xef,0xd7,0xa8,0x56,0x20,0x4b,0xe4,0x58,0xcd,0xe5,0x07,0xbd,0xab,0xe0,0x57,0x1b,0xda,0x2f,0xe6,0xaf,0xd2,0xe8,0x77,0x42,0xf7,0x2a,0x1a,0x19}, + {0x31,0x14,0x3c,0xc5,0x4b,0xf7,0x16,0xce,0xde,0xed,0x72,0x20,0xce,0x25,0x97,0x2b,0xe7,0x3e,0xb2,0xb5,0x6f,0xc3,0xb9,0xb8,0x08,0xc9,0x5c,0x0b,0x45,0x0e,0x2e,0x7e,0xfb,0x0e,0x46,0x4f,0x43,0x2b,0xe6,0x9f,0xd6,0x07,0x36,0xa6,0xd4,0x03,0xd3,0xde,0x24,0xda,0xa0,0xb7,0x0e,0x21,0x52,0xf0,0x93,0x5b,0x54,0x00,0xbe,0x7d,0x7e,0x23,0x30,0xb4,0x01,0x67,0xed,0x75,0x35,0x01,0x10,0xfd,0x0b,0x9f,0xe6,0x94,0x10,0x23,0x22,0x7f,0xe4,0x83,0x15,0x0f,0x32,0x75,0xe3,0x55,0x11,0xb1,0x99,0xa6,0xaf,0x71}, + {0x1d,0xb6,0x53,0x39,0x9b,0x6f,0xce,0x65,0xe6,0x41,0xa1,0xaf,0xea,0x39,0x58,0xc6,0xfe,0x59,0xf7,0xa9,0xfd,0x5f,0x43,0x0f,0x8e,0xc2,0xb1,0xc2,0xe9,0x42,0x11,0x02,0xd6,0x50,0x3b,0x47,0x1c,0x3c,0x42,0xea,0x10,0xef,0x38,0x3b,0x1f,0x7a,0xe8,0x51,0x95,0xbe,0xc9,0xb2,0x5f,0xbf,0x84,0x9b,0x1c,0x9a,0xf8,0x78,0xbc,0x1f,0x73,0x00,0x80,0x18,0xf8,0x48,0x18,0xc7,0x30,0xe4,0x19,0xc1,0xce,0x5e,0x22,0x0c,0x96,0xbf,0xe3,0x15,0xba,0x6b,0x83,0xe0,0xda,0xb6,0x08,0x58,0xe1,0x47,0x33,0x6f,0x4d,0x4c}, + {0xc9,0x1f,0x7d,0xc1,0xcf,0xec,0xf7,0x18,0x14,0x3c,0x40,0x51,0xa6,0xf5,0x75,0x6c,0xdf,0x0c,0xee,0xf7,0x2b,0x71,0xde,0xdb,0x22,0x7a,0xe4,0xa7,0xaa,0xdd,0x3f,0x19,0x70,0x19,0x8f,0x98,0xfc,0xdd,0x0c,0x2f,0x1b,0xf5,0xb9,0xb0,0x27,0x62,0x91,0x6b,0xbe,0x76,0x91,0x77,0xc4,0xb6,0xc7,0x6e,0xa8,0x9f,0x8f,0xa8,0x00,0x95,0xbf,0x38,0x6f,0x87,0xe8,0x37,0x3c,0xc9,0xd2,0x1f,0x2c,0x46,0xd1,0x18,0x5a,0x1e,0xf6,0xa2,0x76,0x12,0x24,0x39,0x82,0xf5,0x80,0x50,0x69,0x49,0x0d,0xbf,0x9e,0xb9,0x6f,0x6a}, + {0xeb,0x55,0x08,0x56,0xbb,0xc1,0x46,0x6a,0x9d,0xf0,0x93,0xf8,0x38,0xbb,0x16,0x24,0xc1,0xac,0x71,0x8f,0x37,0x11,0x1d,0xd7,0xea,0x96,0x18,0xa3,0x14,0x69,0xf7,0x75,0xc6,0x23,0xe4,0xb6,0xb5,0x22,0xb1,0xee,0x8e,0xff,0x86,0xf2,0x10,0x70,0x9d,0x93,0x8c,0x5d,0xcf,0x1d,0x83,0x2a,0xa9,0x90,0x10,0xeb,0xc5,0x42,0x9f,0xda,0x6f,0x13,0xd1,0xbd,0x05,0xa3,0xb1,0xdf,0x4c,0xf9,0x08,0x2c,0xf8,0x9f,0x9d,0x4b,0x36,0x0f,0x8a,0x58,0xbb,0xc3,0xa5,0xd8,0x87,0x2a,0xba,0xdc,0xe8,0x0b,0x51,0x83,0x21,0x02}, + {0x14,0x2d,0xad,0x5e,0x38,0x66,0xf7,0x4a,0x30,0x58,0x7c,0xca,0x80,0xd8,0x8e,0xa0,0x3d,0x1e,0x21,0x10,0xe6,0xa6,0x13,0x0d,0x03,0x6c,0x80,0x7b,0xe1,0x1c,0x07,0x6a,0x7f,0x7a,0x30,0x43,0x01,0x71,0x5a,0x9d,0x5f,0xa4,0x7d,0xc4,0x9e,0xde,0x63,0xb0,0xd3,0x7a,0x92,0xbe,0x52,0xfe,0xbb,0x22,0x6c,0x42,0x40,0xfd,0x41,0xc4,0x87,0x13,0xf8,0x8a,0x97,0x87,0xd1,0xc3,0xd3,0xb5,0x13,0x44,0x0e,0x7f,0x3d,0x5a,0x2b,0x72,0xa0,0x7c,0x47,0xbb,0x48,0x48,0x7b,0x0d,0x92,0xdc,0x1e,0xaf,0x6a,0xb2,0x71,0x31}, + {0xa8,0x4c,0x56,0x97,0x90,0x31,0x2f,0xa9,0x19,0xe1,0x75,0x22,0x4c,0xb8,0x7b,0xff,0x50,0x51,0x87,0xa4,0x37,0xfe,0x55,0x4f,0x5a,0x83,0xf0,0x3c,0x87,0xd4,0x1f,0x22,0xd1,0x47,0x8a,0xb2,0xd8,0xb7,0x0d,0xa6,0xf1,0xa4,0x70,0x17,0xd6,0x14,0xbf,0xa6,0x58,0xbd,0xdd,0x53,0x93,0xf8,0xa1,0xd4,0xe9,0x43,0x42,0x34,0x63,0x4a,0x51,0x6c,0x41,0x63,0x15,0x3a,0x4f,0x20,0x22,0x23,0x2d,0x03,0x0a,0xba,0xe9,0xe0,0x73,0xfb,0x0e,0x03,0x0f,0x41,0x4c,0xdd,0xe0,0xfc,0xaa,0x4a,0x92,0xfb,0x96,0xa5,0xda,0x48}, + {0xc7,0x9c,0xa5,0x5c,0x66,0x8e,0xca,0x6e,0xa0,0xac,0x38,0x2e,0x4b,0x25,0x47,0xa8,0xce,0x17,0x1e,0xd2,0x08,0xc7,0xaf,0x31,0xf7,0x4a,0xd8,0xca,0xfc,0xd6,0x6d,0x67,0x93,0x97,0x4c,0xc8,0x5d,0x1d,0xf6,0x14,0x06,0x82,0x41,0xef,0xe3,0xf9,0x41,0x99,0xac,0x77,0x62,0x34,0x8f,0xb8,0xf5,0xcd,0xa9,0x79,0x8a,0x0e,0xfa,0x37,0xc8,0x58,0x58,0x90,0xfc,0x96,0x85,0x68,0xf9,0x0c,0x1b,0xa0,0x56,0x7b,0xf3,0xbb,0xdc,0x1d,0x6a,0xd6,0x35,0x49,0x7d,0xe7,0xc2,0xdc,0x0a,0x7f,0xa5,0xc6,0xf2,0x73,0x4f,0x1c}, + {0xbb,0xa0,0x5f,0x30,0xbd,0x4f,0x7a,0x0e,0xad,0x63,0xc6,0x54,0xe0,0x4c,0x9d,0x82,0x48,0x38,0xe3,0x2f,0x83,0xc3,0x21,0xf4,0x42,0x4c,0xf6,0x1b,0x0d,0xc8,0x5a,0x79,0x84,0x34,0x7c,0xfc,0x6e,0x70,0x6e,0xb3,0x61,0xcf,0xc1,0xc3,0xb4,0xc9,0xdf,0x73,0xe5,0xc7,0x1c,0x78,0xc9,0x79,0x1d,0xeb,0x5c,0x67,0xaf,0x7d,0xdb,0x9a,0x45,0x70,0xb3,0x2b,0xb4,0x91,0x49,0xdb,0x91,0x1b,0xca,0xdc,0x02,0x4b,0x23,0x96,0x26,0x57,0xdc,0x78,0x8c,0x1f,0xe5,0x9e,0xdf,0x9f,0xd3,0x1f,0xe2,0x8c,0x84,0x62,0xe1,0x5f}, + {0x1a,0x96,0x94,0xe1,0x4f,0x21,0x59,0x4e,0x4f,0xcd,0x71,0x0d,0xc7,0x7d,0xbe,0x49,0x2d,0xf2,0x50,0x3b,0xd2,0xcf,0x00,0x93,0x32,0x72,0x91,0xfc,0x46,0xd4,0x89,0x47,0x08,0xb2,0x7c,0x5d,0x2d,0x85,0x79,0x28,0xe7,0xf2,0x7d,0x68,0x70,0xdd,0xde,0xb8,0x91,0x78,0x68,0x21,0xab,0xff,0x0b,0xdc,0x35,0xaa,0x7d,0x67,0x43,0xc0,0x44,0x2b,0x8e,0xb7,0x4e,0x07,0xab,0x87,0x1c,0x1a,0x67,0xf4,0xda,0x99,0x8e,0xd1,0xc6,0xfa,0x67,0x90,0x4f,0x48,0xcd,0xbb,0xac,0x3e,0xe4,0xa4,0xb9,0x2b,0xef,0x2e,0xc5,0x60}, + {0xf1,0x8b,0xfd,0x3b,0xbc,0x89,0x5d,0x0b,0x1a,0x55,0xf3,0xc9,0x37,0x92,0x6b,0xb0,0xf5,0x28,0x30,0xd5,0xb0,0x16,0x4c,0x0e,0xab,0xca,0xcf,0x2c,0x31,0x9c,0xbc,0x10,0x11,0x6d,0xae,0x7c,0xc2,0xc5,0x2b,0x70,0xab,0x8c,0xa4,0x54,0x9b,0x69,0xc7,0x44,0xb2,0x2e,0x49,0xba,0x56,0x40,0xbc,0xef,0x6d,0x67,0xb6,0xd9,0x48,0x72,0xd7,0x70,0x5b,0xa0,0xc2,0x3e,0x4b,0xe8,0x8a,0xaa,0xe0,0x81,0x17,0xed,0xf4,0x9e,0x69,0x98,0xd1,0x85,0x8e,0x70,0xe4,0x13,0x45,0x79,0x13,0xf4,0x76,0xa9,0xd3,0x5b,0x75,0x63}, + {0x53,0x08,0xd1,0x2a,0x3e,0xa0,0x5f,0xb5,0x69,0x35,0xe6,0x9e,0x90,0x75,0x6f,0x35,0x90,0xb8,0x69,0xbe,0xfd,0xf1,0xf9,0x9f,0x84,0x6f,0xc1,0x8b,0xc4,0xc1,0x8c,0x0d,0xb7,0xac,0xf1,0x97,0x18,0x10,0xc7,0x3d,0xd8,0xbb,0x65,0xc1,0x5e,0x7d,0xda,0x5d,0x0f,0x02,0xa1,0x0f,0x9c,0x5b,0x8e,0x50,0x56,0x2a,0xc5,0x37,0x17,0x75,0x63,0x27,0xa9,0x19,0xb4,0x6e,0xd3,0x02,0x94,0x02,0xa5,0x60,0xb4,0x77,0x7e,0x4e,0xb4,0xf0,0x56,0x49,0x3c,0xd4,0x30,0x62,0xa8,0xcf,0xe7,0x66,0xd1,0x7a,0x8a,0xdd,0xc2,0x70}, + {0x0e,0xec,0x6f,0x9f,0x50,0x94,0x61,0x65,0x8d,0x51,0xc6,0x46,0xa9,0x7e,0x2e,0xee,0x5c,0x9b,0xe0,0x67,0xf3,0xc1,0x33,0x97,0x95,0x84,0x94,0x63,0x63,0xac,0x0f,0x2e,0x13,0x7e,0xed,0xb8,0x7d,0x96,0xd4,0x91,0x7a,0x81,0x76,0xd7,0x0a,0x2f,0x25,0x74,0x64,0x25,0x85,0x0d,0xe0,0x82,0x09,0xe4,0xe5,0x3c,0xa5,0x16,0x38,0x61,0xb8,0x32,0x64,0xcd,0x48,0xe4,0xbe,0xf7,0xe7,0x79,0xd0,0x86,0x78,0x08,0x67,0x3a,0xc8,0x6a,0x2e,0xdb,0xe4,0xa0,0xd9,0xd4,0x9f,0xf8,0x41,0x4f,0x5a,0x73,0x5c,0x21,0x79,0x41}, + {0x2a,0xed,0xdc,0xd7,0xe7,0x94,0x70,0x8c,0x70,0x9c,0xd3,0x47,0xc3,0x8a,0xfb,0x97,0x02,0xd9,0x06,0xa9,0x33,0xe0,0x3b,0xe1,0x76,0x9d,0xd9,0x0c,0xa3,0x44,0x03,0x70,0x34,0xcd,0x6b,0x28,0xb9,0x33,0xae,0xe4,0xdc,0xd6,0x9d,0x55,0xb6,0x7e,0xef,0xb7,0x1f,0x8e,0xd3,0xb3,0x1f,0x14,0x8b,0x27,0x86,0xc2,0x41,0x22,0x66,0x85,0xfa,0x31,0xf4,0x22,0x36,0x2e,0x42,0x6c,0x82,0xaf,0x2d,0x50,0x33,0x98,0x87,0x29,0x20,0xc1,0x23,0x91,0x38,0x2b,0xe1,0xb7,0xc1,0x9b,0x89,0x24,0x95,0xa9,0x12,0x23,0xbb,0x24}, + {0xc3,0x67,0xde,0x32,0x17,0xed,0xa8,0xb1,0x48,0x49,0x1b,0x46,0x18,0x94,0xb4,0x3c,0xd2,0xbc,0xcf,0x76,0x43,0x43,0xbd,0x8e,0x08,0x80,0x18,0x1e,0x87,0x3e,0xee,0x0f,0x6b,0x5c,0xf8,0xf5,0x2a,0x0c,0xf8,0x41,0x94,0x67,0xfa,0x04,0xc3,0x84,0x72,0x68,0xad,0x1b,0xba,0xa3,0x99,0xdf,0x45,0x89,0x16,0x5d,0xeb,0xff,0xf9,0x2a,0x1d,0x0d,0xdf,0x1e,0x62,0x32,0xa1,0x8a,0xda,0xa9,0x79,0x65,0x22,0x59,0xa1,0x22,0xb8,0x30,0x93,0xc1,0x9a,0xa7,0x7b,0x19,0x04,0x40,0x76,0x1d,0x53,0x18,0x97,0xd7,0xac,0x16}, + {0x3d,0x1d,0x9b,0x2d,0xaf,0x72,0xdf,0x72,0x5a,0x24,0x32,0xa4,0x36,0x2a,0x46,0x63,0x37,0x96,0xb3,0x16,0x79,0xa0,0xce,0x3e,0x09,0x23,0x30,0xb9,0xf6,0x0e,0x3e,0x12,0xad,0xb6,0x87,0x78,0xc5,0xc6,0x59,0xc9,0xba,0xfe,0x90,0x5f,0xad,0x9e,0xe1,0x94,0x04,0xf5,0x42,0xa3,0x62,0x4e,0xe2,0x16,0x00,0x17,0x16,0x18,0x4b,0xd3,0x4e,0x16,0x9a,0xe6,0x2f,0x19,0x4c,0xd9,0x7e,0x48,0x13,0x15,0x91,0x3a,0xea,0x2c,0xae,0x61,0x27,0xde,0xa4,0xb9,0xd3,0xf6,0x7b,0x87,0xeb,0xf3,0x73,0x10,0xc6,0x0f,0xda,0x78}, + {0x6a,0xc6,0x2b,0xe5,0x28,0x5d,0xf1,0x5b,0x8e,0x1a,0xf0,0x70,0x18,0xe3,0x47,0x2c,0xdd,0x8b,0xc2,0x06,0xbc,0xaf,0x19,0x24,0x3a,0x17,0x6b,0x25,0xeb,0xde,0x25,0x2d,0x94,0x3a,0x0c,0x68,0xf1,0x80,0x9f,0xa2,0xe6,0xe7,0xe9,0x1a,0x15,0x7e,0xf7,0x71,0x73,0x79,0x01,0x48,0x58,0xf1,0x00,0x11,0xdd,0x8d,0xb3,0x16,0xb3,0xa4,0x4a,0x05,0xb8,0x7c,0x26,0x19,0x8d,0x46,0xc8,0xdf,0xaf,0x4d,0xe5,0x66,0x9c,0x78,0x28,0x0b,0x17,0xec,0x6e,0x66,0x2a,0x1d,0xeb,0x2a,0x60,0xa7,0x7d,0xab,0xa6,0x10,0x46,0x13}, + {0xfe,0xb0,0xf6,0x8d,0xc7,0x8e,0x13,0x51,0x1b,0xf5,0x75,0xe5,0x89,0xda,0x97,0x53,0xb9,0xf1,0x7a,0x71,0x1d,0x7a,0x20,0x09,0x50,0xd6,0x20,0x2b,0xba,0xfd,0x02,0x21,0x15,0xf5,0xd1,0x77,0xe7,0x65,0x2a,0xcd,0xf1,0x60,0xaa,0x8f,0x87,0x91,0x89,0x54,0xe5,0x06,0xbc,0xda,0xbc,0x3b,0xb7,0xb1,0xfb,0xc9,0x7c,0xa9,0xcb,0x78,0x48,0x65,0xa1,0xe6,0x5c,0x05,0x05,0xe4,0x9e,0x96,0x29,0xad,0x51,0x12,0x68,0xa7,0xbc,0x36,0x15,0xa4,0x7d,0xaa,0x17,0xf5,0x1a,0x3a,0xba,0xb2,0xec,0x29,0xdb,0x25,0xd7,0x0a}, + {0x57,0x24,0x4e,0x83,0xb1,0x67,0x42,0xdc,0xc5,0x1b,0xce,0x70,0xb5,0x44,0x75,0xb6,0xd7,0x5e,0xd1,0xf7,0x0b,0x7a,0xf0,0x1a,0x50,0x36,0xa0,0x71,0xfb,0xcf,0xef,0x4a,0x85,0x6f,0x05,0x9b,0x0c,0xbc,0xc7,0xfe,0xd7,0xff,0xf5,0xe7,0x68,0x52,0x7d,0x53,0xfa,0xae,0x12,0x43,0x62,0xc6,0xaf,0x77,0xd9,0x9f,0x39,0x02,0x53,0x5f,0x67,0x4f,0x1e,0x17,0x15,0x04,0x36,0x36,0x2d,0xc3,0x3b,0x48,0x98,0x89,0x11,0xef,0x2b,0xcd,0x10,0x51,0x94,0xd0,0xad,0x6e,0x0a,0x87,0x61,0x65,0xa8,0xa2,0x72,0xbb,0xcc,0x0b}, + {0xc8,0xa9,0xb1,0xea,0x2f,0x96,0x5e,0x18,0xcd,0x7d,0x14,0x65,0x35,0xe6,0xe7,0x86,0xf2,0x6d,0x5b,0xbb,0x31,0xe0,0x92,0xb0,0x3e,0xb7,0xd6,0x59,0xab,0xf0,0x24,0x40,0x96,0x12,0xfe,0x50,0x4c,0x5e,0x6d,0x18,0x7e,0x9f,0xe8,0xfe,0x82,0x7b,0x39,0xe0,0xb0,0x31,0x70,0x50,0xc5,0xf6,0xc7,0x3b,0xc2,0x37,0x8f,0x10,0x69,0xfd,0x78,0x66,0xc2,0x63,0x68,0x63,0x31,0xfa,0x86,0x15,0xf2,0x33,0x2d,0x57,0x48,0x8c,0xf6,0x07,0xfc,0xae,0x9e,0x78,0x9f,0xcc,0x73,0x4f,0x01,0x47,0xad,0x8e,0x10,0xe2,0x42,0x2d}, + {0x9b,0xd2,0xdf,0x94,0x15,0x13,0xf5,0x97,0x6a,0x4c,0x3f,0x31,0x5d,0x98,0x55,0x61,0x10,0x50,0x45,0x08,0x07,0x3f,0xa1,0xeb,0x22,0xd3,0xd2,0xb8,0x08,0x26,0x6b,0x67,0x93,0x75,0x53,0x0f,0x0d,0x7b,0x71,0x21,0x4c,0x06,0x1e,0x13,0x0b,0x69,0x4e,0x91,0x9f,0xe0,0x2a,0x75,0xae,0x87,0xb6,0x1b,0x6e,0x3c,0x42,0x9b,0xa7,0xf3,0x0b,0x42,0x47,0x2b,0x5b,0x1c,0x65,0xba,0x38,0x81,0x80,0x1b,0x1b,0x31,0xec,0xb6,0x71,0x86,0xb0,0x35,0x31,0xbc,0xb1,0x0c,0xff,0x7b,0xe0,0xf1,0x0c,0x9c,0xfa,0x2f,0x5d,0x74}, + {0xbd,0xc8,0xc9,0x2b,0x1e,0x5a,0x52,0xbf,0x81,0x9d,0x47,0x26,0x08,0x26,0x5b,0xea,0xdb,0x55,0x01,0xdf,0x0e,0xc7,0x11,0xd5,0xd0,0xf5,0x0c,0x96,0xeb,0x3c,0xe2,0x1a,0x6a,0x4e,0xd3,0x21,0x57,0xdf,0x36,0x60,0xd0,0xb3,0x7b,0x99,0x27,0x88,0xdb,0xb1,0xfa,0x6a,0x75,0xc8,0xc3,0x09,0xc2,0xd3,0x39,0xc8,0x1d,0x4c,0xe5,0x5b,0xe1,0x06,0x4a,0x99,0x32,0x19,0x87,0x5d,0x72,0x5b,0xb0,0xda,0xb1,0xce,0xb5,0x1c,0x35,0x32,0x05,0xca,0xb7,0xda,0x49,0x15,0xc4,0x7d,0xf7,0xc1,0x8e,0x27,0x61,0xd8,0xde,0x58}, + {0x5c,0xc5,0x66,0xf2,0x93,0x37,0x17,0xd8,0x49,0x4e,0x45,0xcc,0xc5,0x76,0xc9,0xc8,0xa8,0xc3,0x26,0xbc,0xf8,0x82,0xe3,0x5c,0xf9,0xf6,0x85,0x54,0xe8,0x9d,0xf3,0x2f,0xa8,0xc9,0xc2,0xb6,0xa8,0x5b,0xfb,0x2d,0x8c,0x59,0x2c,0xf5,0x8e,0xef,0xee,0x48,0x73,0x15,0x2d,0xf1,0x07,0x91,0x80,0x33,0xd8,0x5b,0x1d,0x53,0x6b,0x69,0xba,0x08,0x7a,0xc5,0xef,0xc3,0xee,0x3e,0xed,0x77,0x11,0x48,0xff,0xd4,0x17,0x55,0xe0,0x04,0xcb,0x71,0xa6,0xf1,0x3f,0x7a,0x3d,0xea,0x54,0xfe,0x7c,0x94,0xb4,0x33,0x06,0x12}, + {0x42,0x00,0x61,0x91,0x78,0x98,0x94,0x0b,0xe8,0xfa,0xeb,0xec,0x3c,0xb1,0xe7,0x4e,0xc0,0xa4,0xf0,0x94,0x95,0x73,0xbe,0x70,0x85,0x91,0xd5,0xb4,0x99,0x0a,0xd3,0x35,0x0a,0x10,0x12,0x49,0x47,0x31,0xbd,0x82,0x06,0xbe,0x6f,0x7e,0x6d,0x7b,0x23,0xde,0xc6,0x79,0xea,0x11,0x19,0x76,0x1e,0xe1,0xde,0x3b,0x39,0xcb,0xe3,0x3b,0x43,0x07,0xf4,0x97,0xe9,0x5c,0xc0,0x44,0x79,0xff,0xa3,0x51,0x5c,0xb0,0xe4,0x3d,0x5d,0x57,0x7c,0x84,0x76,0x5a,0xfd,0x81,0x33,0x58,0x9f,0xda,0xf6,0x7a,0xde,0x3e,0x87,0x2d}, + {0x09,0x34,0x37,0x43,0x64,0x31,0x7a,0x15,0xd9,0x81,0xaa,0xf4,0xee,0xb7,0xb8,0xfa,0x06,0x48,0xa6,0xf5,0xe6,0xfe,0x93,0xb0,0xb6,0xa7,0x7f,0x70,0x54,0x36,0x77,0x2e,0x81,0xf9,0x5d,0x4e,0xe1,0x02,0x62,0xaa,0xf5,0xe1,0x15,0x50,0x17,0x59,0x0d,0xa2,0x6c,0x1d,0xe2,0xba,0xd3,0x75,0xa2,0x18,0x53,0x02,0x60,0x01,0x8a,0x61,0x43,0x05,0xc1,0x23,0x4c,0x97,0xf4,0xbd,0xea,0x0d,0x93,0x46,0xce,0x9d,0x25,0x0a,0x6f,0xaa,0x2c,0xba,0x9a,0xa2,0xb8,0x2c,0x20,0x04,0x0d,0x96,0x07,0x2d,0x36,0x43,0x14,0x4b}, + {0x7a,0x1f,0x6e,0xb6,0xc7,0xb7,0xc4,0xcc,0x7e,0x2f,0x0c,0xf5,0x25,0x7e,0x15,0x44,0x1c,0xaf,0x3e,0x71,0xfc,0x6d,0xf0,0x3e,0xf7,0x63,0xda,0x52,0x67,0x44,0x2f,0x58,0xcb,0x9c,0x52,0x1c,0xe9,0x54,0x7c,0x96,0xfb,0x35,0xc6,0x64,0x92,0x26,0xf6,0x30,0x65,0x19,0x12,0x78,0xf4,0xaf,0x47,0x27,0x5c,0x6f,0xf6,0xea,0x18,0x84,0x03,0x17,0xe4,0x4c,0x32,0x20,0xd3,0x7b,0x31,0xc6,0xc4,0x8b,0x48,0xa4,0xe8,0x42,0x10,0xa8,0x64,0x13,0x5a,0x4e,0x8b,0xf1,0x1e,0xb2,0xc9,0x8d,0xa2,0xcd,0x4b,0x1c,0x2a,0x0c}, + {0x47,0x04,0x1f,0x6f,0xd0,0xc7,0x4d,0xd2,0x59,0xc0,0x87,0xdb,0x3e,0x9e,0x26,0xb2,0x8f,0xd2,0xb2,0xfb,0x72,0x02,0x5b,0xd1,0x77,0x48,0xf6,0xc6,0xd1,0x8b,0x55,0x7c,0x45,0x69,0xbd,0x69,0x48,0x81,0xc4,0xed,0x22,0x8d,0x1c,0xbe,0x7d,0x90,0x6d,0x0d,0xab,0xc5,0x5c,0xd5,0x12,0xd2,0x3b,0xc6,0x83,0xdc,0x14,0xa3,0x30,0x9b,0x6a,0x5a,0x3d,0x46,0x96,0xd3,0x24,0x15,0xec,0xd0,0xf0,0x24,0x5a,0xc3,0x8a,0x62,0xbb,0x12,0xa4,0x5f,0xbc,0x1c,0x79,0x3a,0x0c,0xa5,0xc3,0xaf,0xfb,0x0a,0xca,0xa5,0x04,0x04}, + {0xd6,0x43,0xa7,0x0a,0x07,0x40,0x1f,0x8c,0xe8,0x5e,0x26,0x5b,0xcb,0xd0,0xba,0xcc,0xde,0xd2,0x8f,0x66,0x6b,0x04,0x4b,0x57,0x33,0x96,0xdd,0xca,0xfd,0x5b,0x39,0x46,0xd1,0x6f,0x41,0x2a,0x1b,0x9e,0xbc,0x62,0x8b,0x59,0x50,0xe3,0x28,0xf7,0xc6,0xb5,0x67,0x69,0x5d,0x3d,0xd8,0x3f,0x34,0x04,0x98,0xee,0xf8,0xe7,0x16,0x75,0x52,0x39,0x9c,0x9a,0x5d,0x1a,0x2d,0xdb,0x7f,0x11,0x2a,0x5c,0x00,0xd1,0xbc,0x45,0x77,0x9c,0xea,0x6f,0xd5,0x54,0xf1,0xbe,0xd4,0xef,0x16,0xd0,0x22,0xe8,0x29,0x9a,0x57,0x76}, + {0x17,0x2a,0xc0,0x49,0x7e,0x8e,0xb6,0x45,0x7f,0xa3,0xa9,0xbc,0xa2,0x51,0xcd,0x23,0x1b,0x4c,0x22,0xec,0x11,0x5f,0xd6,0x3e,0xb1,0xbd,0x05,0x9e,0xdc,0x84,0xa3,0x43,0xf2,0x34,0xb4,0x52,0x13,0xb5,0x3c,0x33,0xe1,0x80,0xde,0x93,0x49,0x28,0x32,0xd8,0xce,0x35,0x0d,0x75,0x87,0x28,0x51,0xb5,0xc1,0x77,0x27,0x2a,0xbb,0x14,0xc5,0x02,0x45,0xb6,0xf1,0x8b,0xda,0xd5,0x4b,0x68,0x53,0x4b,0xb5,0xf6,0x7e,0xd3,0x8b,0xfb,0x53,0xd2,0xb0,0xa9,0xd7,0x16,0x39,0x31,0x59,0x80,0x54,0x61,0x09,0x92,0x60,0x11}, + {0xaa,0xcf,0xda,0x29,0x69,0x16,0x4d,0xb4,0x8f,0x59,0x13,0x84,0x4c,0x9f,0x52,0xda,0x59,0x55,0x3d,0x45,0xca,0x63,0xef,0xe9,0x0b,0x8e,0x69,0xc5,0x5b,0x12,0x1e,0x35,0xcd,0x4d,0x9b,0x36,0x16,0x56,0x38,0x7a,0x63,0x35,0x5c,0x65,0xa7,0x2c,0xc0,0x75,0x21,0x80,0xf1,0xd4,0xf9,0x1b,0xc2,0x7d,0x42,0xe0,0xe6,0x91,0x74,0x7d,0x63,0x2f,0xbe,0x7b,0xf6,0x1a,0x46,0x9b,0xb4,0xd4,0x61,0x89,0xab,0xc8,0x7a,0x03,0x03,0xd6,0xfb,0x99,0xa6,0xf9,0x9f,0xe1,0xde,0x71,0x9a,0x2a,0xce,0xe7,0x06,0x2d,0x18,0x7f}, + {0xec,0x68,0x01,0xab,0x64,0x8e,0x7c,0x7a,0x43,0xc5,0xed,0x15,0x55,0x4a,0x5a,0xcb,0xda,0x0e,0xcd,0x47,0xd3,0x19,0x55,0x09,0xb0,0x93,0x3e,0x34,0x8c,0xac,0xd4,0x67,0x22,0x75,0x21,0x8e,0x72,0x4b,0x45,0x09,0xd8,0xb8,0x84,0xd4,0xf4,0xe8,0x58,0xaa,0x3c,0x90,0x46,0x7f,0x4d,0x25,0x58,0xd3,0x17,0x52,0x1c,0x24,0x43,0xc0,0xac,0x44,0x77,0x57,0x7a,0x4f,0xbb,0x6b,0x7d,0x1c,0xe1,0x13,0x83,0x91,0xd4,0xfe,0x35,0x8b,0x84,0x46,0x6b,0xc9,0xc6,0xa1,0xdc,0x4a,0xbd,0x71,0xad,0x12,0x83,0x1c,0x6d,0x55}, + {0x82,0x39,0x8d,0x0c,0xe3,0x40,0xef,0x17,0x34,0xfa,0xa3,0x15,0x3e,0x07,0xf7,0x31,0x6e,0x64,0x73,0x07,0xcb,0xf3,0x21,0x4f,0xff,0x4e,0x82,0x1d,0x6d,0x6c,0x6c,0x74,0x21,0xe8,0x1b,0xb1,0x56,0x67,0xf0,0x81,0xdd,0xf3,0xa3,0x10,0x23,0xf8,0xaf,0x0f,0x5d,0x46,0x99,0x6a,0x55,0xd0,0xb2,0xf8,0x05,0x7f,0x8c,0xcc,0x38,0xbe,0x7a,0x09,0xa4,0x2d,0xa5,0x7e,0x87,0xc9,0x49,0x0c,0x43,0x1d,0xdc,0x9b,0x55,0x69,0x43,0x4c,0xd2,0xeb,0xcc,0xf7,0x09,0x38,0x2c,0x02,0xbd,0x84,0xee,0x4b,0xa3,0x14,0x7e,0x57}, + {0x0a,0x3b,0xa7,0x61,0xac,0x68,0xe2,0xf0,0xf5,0xa5,0x91,0x37,0x10,0xfa,0xfa,0xf2,0xe9,0x00,0x6d,0x6b,0x82,0x3e,0xe1,0xc1,0x42,0x8f,0xd7,0x6f,0xe9,0x7e,0xfa,0x60,0x2b,0xd7,0x4d,0xbd,0xbe,0xce,0xfe,0x94,0x11,0x22,0x0f,0x06,0xda,0x4f,0x6a,0xf4,0xff,0xd1,0xc8,0xc0,0x77,0x59,0x4a,0x12,0x95,0x92,0x00,0xfb,0xb8,0x04,0x53,0x70,0xc6,0x6e,0x29,0x4d,0x35,0x1d,0x3d,0xb6,0xd8,0x31,0xad,0x5f,0x3e,0x05,0xc3,0xf3,0xec,0x42,0xbd,0xb4,0x8c,0x95,0x0b,0x67,0xfd,0x53,0x63,0xa1,0x0c,0x8e,0x39,0x21}, + {0xf3,0x33,0x2b,0x38,0x8a,0x05,0xf5,0x89,0xb4,0xc0,0x48,0xad,0x0b,0xba,0xe2,0x5a,0x6e,0xb3,0x3d,0xa5,0x03,0xb5,0x93,0x8f,0xe6,0x32,0xa2,0x95,0x9d,0xed,0xa3,0x5a,0x01,0x56,0xb7,0xb4,0xf9,0xaa,0x98,0x27,0x72,0xad,0x8d,0x5c,0x13,0x72,0xac,0x5e,0x23,0xa0,0xb7,0x61,0x61,0xaa,0xce,0xd2,0x4e,0x7d,0x8f,0xe9,0x84,0xb2,0xbf,0x1b,0x61,0x65,0xd9,0xc7,0xe9,0x77,0x67,0x65,0x36,0x80,0xc7,0x72,0x54,0x12,0x2b,0xcb,0xee,0x6e,0x50,0xd9,0x99,0x32,0x05,0x65,0xcc,0x57,0x89,0x5e,0x4e,0xe1,0x07,0x4a}, + {0x99,0xf9,0x0d,0x98,0xcb,0x12,0xe4,0x4e,0x71,0xc7,0x6e,0x3c,0x6f,0xd7,0x15,0xa3,0xfd,0x77,0x5c,0x92,0xde,0xed,0xa5,0xbb,0x02,0x34,0x31,0x1d,0x39,0xac,0x0b,0x3f,0x9b,0xa4,0x77,0xc4,0xcd,0x58,0x0b,0x24,0x17,0xf0,0x47,0x64,0xde,0xda,0x38,0xfd,0xad,0x6a,0xc8,0xa7,0x32,0x8d,0x92,0x19,0x81,0xa0,0xaf,0x84,0xed,0x7a,0xaf,0x50,0xe5,0x5b,0xf6,0x15,0x01,0xde,0x4f,0x6e,0xb2,0x09,0x61,0x21,0x21,0x26,0x98,0x29,0xd9,0xd6,0xad,0x0b,0x81,0x05,0x02,0x78,0x06,0xd0,0xeb,0xba,0x16,0xa3,0x21,0x19}, + {0xfc,0x70,0xb8,0xdf,0x7e,0x2f,0x42,0x89,0xbd,0xb3,0x76,0x4f,0xeb,0x6b,0x29,0x2c,0xf7,0x4d,0xc2,0x36,0xd4,0xf1,0x38,0x07,0xb0,0xae,0x73,0xe2,0x41,0xdf,0x58,0x64,0x8b,0xc1,0xf3,0xd9,0x9a,0xad,0x5a,0xd7,0x9c,0xc1,0xb1,0x60,0xef,0x0e,0x6a,0x56,0xd9,0x0e,0x5c,0x25,0xac,0x0b,0x9a,0x3e,0xf5,0xc7,0x62,0xa0,0xec,0x9d,0x04,0x7b,0x83,0x44,0x44,0x35,0x7a,0xe3,0xcb,0xdc,0x93,0xbe,0xed,0x0f,0x33,0x79,0x88,0x75,0x87,0xdd,0xc5,0x12,0xc3,0x04,0x60,0x78,0x64,0x0e,0x95,0xc2,0xcb,0xdc,0x93,0x60}, + {0x6d,0x70,0xe0,0x85,0x85,0x9a,0xf3,0x1f,0x33,0x39,0xe7,0xb3,0xd8,0xa5,0xd0,0x36,0x3b,0x45,0x8f,0x71,0xe1,0xf2,0xb9,0x43,0x7c,0xa9,0x27,0x48,0x08,0xea,0xd1,0x57,0x4b,0x03,0x84,0x60,0xbe,0xee,0xde,0x6b,0x54,0xb8,0x0f,0x78,0xb6,0xc2,0x99,0x31,0x95,0x06,0x2d,0xb6,0xab,0x76,0x33,0x97,0x90,0x7d,0x64,0x8b,0xc9,0x80,0x31,0x6e,0x71,0xb0,0x28,0xa1,0xe7,0xb6,0x7a,0xee,0xaa,0x8b,0xa8,0x93,0x6d,0x59,0xc1,0xa4,0x30,0x61,0x21,0xb2,0x82,0xde,0xb4,0xf7,0x18,0xbd,0x97,0xdd,0x9d,0x99,0x3e,0x36}, + {0xc4,0x1f,0xee,0x35,0xc1,0x43,0xa8,0x96,0xcf,0xc8,0xe4,0x08,0x55,0xb3,0x6e,0x97,0x30,0xd3,0x8c,0xb5,0x01,0x68,0x2f,0xb4,0x2b,0x05,0x3a,0x69,0x78,0x9b,0xee,0x48,0xc6,0xae,0x4b,0xe2,0xdc,0x48,0x18,0x2f,0x60,0xaf,0xbc,0xba,0x55,0x72,0x9b,0x76,0x31,0xe9,0xef,0x3c,0x6e,0x3c,0xcb,0x90,0x55,0xb3,0xf9,0xc6,0x9b,0x97,0x1f,0x23,0xc6,0xf3,0x2a,0xcc,0x4b,0xde,0x31,0x5c,0x1f,0x8d,0x20,0xfe,0x30,0xb0,0x4b,0xb0,0x66,0xb4,0x4f,0xc1,0x09,0x70,0x8d,0xb7,0x13,0x24,0x79,0x08,0x9b,0xfa,0x9b,0x07}, + {0xf4,0x0d,0x30,0xda,0x51,0x3a,0x90,0xe3,0xb0,0x5a,0xa9,0x3d,0x23,0x64,0x39,0x84,0x80,0x64,0x35,0x0b,0x2d,0xf1,0x3c,0xed,0x94,0x71,0x81,0x84,0xf6,0x77,0x8c,0x03,0x45,0x42,0xd5,0xa2,0x80,0xed,0xc9,0xf3,0x52,0x39,0xf6,0x77,0x78,0x8b,0xa0,0x0a,0x75,0x54,0x08,0xd1,0x63,0xac,0x6d,0xd7,0x6b,0x63,0x70,0x94,0x15,0xfb,0xf4,0x1e,0xec,0x7b,0x16,0x5b,0xe6,0x5e,0x4e,0x85,0xc2,0xcd,0xd0,0x96,0x42,0x0a,0x59,0x59,0x99,0x21,0x10,0x98,0x34,0xdf,0xb2,0x72,0x56,0xff,0x0b,0x4a,0x2a,0xe9,0x5e,0x57}, + {0xcf,0x2f,0x18,0x8a,0x90,0x80,0xc0,0xd4,0xbd,0x9d,0x48,0x99,0xc2,0x70,0xe1,0x30,0xde,0x33,0xf7,0x52,0x57,0xbd,0xba,0x05,0x00,0xfd,0xd3,0x2c,0x11,0xe7,0xd4,0x43,0x01,0xd8,0xa4,0x0a,0x45,0xbc,0x46,0x5d,0xd8,0xb9,0x33,0xa5,0x27,0x12,0xaf,0xc3,0xc2,0x06,0x89,0x2b,0x26,0x3b,0x9e,0x38,0x1b,0x58,0x2f,0x38,0x7e,0x1e,0x0a,0x20,0xc5,0x3a,0xf9,0xea,0x67,0xb9,0x8d,0x51,0xc0,0x52,0x66,0x05,0x9b,0x98,0xbc,0x71,0xf5,0x97,0x71,0x56,0xd9,0x85,0x2b,0xfe,0x38,0x4e,0x1e,0x65,0x52,0xca,0x0e,0x05}, + {0x9c,0x0c,0x3f,0x45,0xde,0x1a,0x43,0xc3,0x9b,0x3b,0x70,0xff,0x5e,0x04,0xf5,0xe9,0x3d,0x7b,0x84,0xed,0xc9,0x7a,0xd9,0xfc,0xc6,0xf4,0x58,0x1c,0xc2,0xe6,0x0e,0x4b,0xea,0x68,0xe6,0x60,0x76,0x39,0xac,0x97,0x97,0xb4,0x3a,0x15,0xfe,0xbb,0x19,0x9b,0x9f,0xa7,0xec,0x34,0xb5,0x79,0xb1,0x4c,0x57,0xae,0x31,0xa1,0x9f,0xc0,0x51,0x61,0x96,0x5d,0xf0,0xfd,0x0d,0x5c,0xf5,0x3a,0x7a,0xee,0xb4,0x2a,0xe0,0x2e,0x26,0xdd,0x09,0x17,0x17,0x12,0x87,0xbb,0xb2,0x11,0x0b,0x03,0x0f,0x80,0xfa,0x24,0xef,0x1f}, + {0x96,0x31,0xa7,0x1a,0xfb,0x53,0xd6,0x37,0x18,0x64,0xd7,0x3f,0x30,0x95,0x94,0x0f,0xb2,0x17,0x3a,0xfb,0x09,0x0b,0x20,0xad,0x3e,0x61,0xc8,0x2f,0x29,0x49,0x4d,0x54,0x86,0x6b,0x97,0x30,0xf5,0xaf,0xd2,0x22,0x04,0x46,0xd2,0xc2,0x06,0xb8,0x90,0x8d,0xe5,0xba,0xe5,0x4d,0x6c,0x89,0xa1,0xdc,0x17,0x0c,0x34,0xc8,0xe6,0x5f,0x00,0x28,0x88,0x86,0x52,0x34,0x9f,0xba,0xef,0x6a,0xa1,0x7d,0x10,0x25,0x94,0xff,0x1b,0x5c,0x36,0x4b,0xd9,0x66,0xcd,0xbb,0x5b,0xf7,0xfa,0x6d,0x31,0x0f,0x93,0x72,0xe4,0x72}, + {0x4f,0x08,0x81,0x97,0x8c,0x20,0x95,0x26,0xe1,0x0e,0x45,0x23,0x0b,0x2a,0x50,0xb1,0x02,0xde,0xef,0x03,0xa6,0xae,0x9d,0xfd,0x4c,0xa3,0x33,0x27,0x8c,0x2e,0x9d,0x5a,0x27,0x76,0x2a,0xd3,0x35,0xf6,0xf3,0x07,0xf0,0x66,0x65,0x5f,0x86,0x4d,0xaa,0x7a,0x50,0x44,0xd0,0x28,0x97,0xe7,0x85,0x3c,0x38,0x64,0xe0,0x0f,0x00,0x7f,0xee,0x1f,0xe5,0xf7,0xdb,0x03,0xda,0x05,0x53,0x76,0xbd,0xcd,0x34,0x14,0x49,0xf2,0xda,0xa4,0xec,0x88,0x4a,0xd2,0xcd,0xd5,0x4a,0x7b,0x43,0x05,0x04,0xee,0x51,0x40,0xf9,0x00}, + {0xb2,0x30,0xd3,0xc3,0x23,0x6b,0x35,0x8d,0x06,0x1b,0x47,0xb0,0x9b,0x8b,0x1c,0xf2,0x3c,0xb8,0x42,0x6e,0x6c,0x31,0x6c,0xb3,0x0d,0xb1,0xea,0x8b,0x7e,0x9c,0xd7,0x07,0x53,0x97,0xaf,0x07,0xbb,0x93,0xef,0xd7,0xa7,0x66,0xb7,0x3d,0xcf,0xd0,0x3e,0x58,0xc5,0x1e,0x0b,0x6e,0xbf,0x98,0x69,0xce,0x52,0x04,0xd4,0x5d,0xd2,0xff,0xb7,0x47,0x12,0xdd,0x08,0xbc,0x9c,0xfb,0xfb,0x87,0x9b,0xc2,0xee,0xe1,0x3a,0x6b,0x06,0x8a,0xbf,0xc1,0x1f,0xdb,0x2b,0x24,0x57,0x0d,0xb6,0x4b,0xa6,0x5e,0xa3,0x20,0x35,0x1c}, + {0x4a,0xa3,0xcb,0xbc,0xa6,0x53,0xd2,0x80,0x9b,0x21,0x38,0x38,0xa1,0xc3,0x61,0x3e,0x96,0xe3,0x82,0x98,0x01,0xb6,0xc3,0x90,0x6f,0xe6,0x0e,0x5d,0x77,0x05,0x3d,0x1c,0x59,0xc0,0x6b,0x21,0x40,0x6f,0xa8,0xcd,0x7e,0xd8,0xbc,0x12,0x1d,0x23,0xbb,0x1f,0x90,0x09,0xc7,0x17,0x9e,0x6a,0x95,0xb4,0x55,0x2e,0xd1,0x66,0x3b,0x0c,0x75,0x38,0x1a,0xe5,0x22,0x94,0x40,0xf1,0x2e,0x69,0x71,0xf6,0x5d,0x2b,0x3c,0xc7,0xc0,0xcb,0x29,0xe0,0x4c,0x74,0xe7,0x4f,0x01,0x21,0x7c,0x48,0x30,0xd3,0xc7,0xe2,0x21,0x06}, + {0x8d,0x83,0x59,0x82,0xcc,0x60,0x98,0xaf,0xdc,0x9a,0x9f,0xc6,0xc1,0x48,0xea,0x90,0x30,0x1e,0x58,0x65,0x37,0x48,0x26,0x65,0xbc,0xa5,0xd3,0x7b,0x09,0xd6,0x07,0x00,0xf3,0xf0,0xdb,0xb0,0x96,0x17,0xae,0xb7,0x96,0xe1,0x7c,0xe1,0xb9,0xaf,0xdf,0x54,0xb4,0xa3,0xaa,0xe9,0x71,0x30,0x92,0x25,0x9d,0x2e,0x00,0xa1,0x9c,0x58,0x8e,0x5d,0x4b,0xa9,0x42,0x08,0x95,0x1d,0xbf,0xc0,0x3e,0x2e,0x8f,0x58,0x63,0xc3,0xd3,0xb2,0xef,0xe2,0x51,0xbb,0x38,0x14,0x96,0x0a,0x86,0xbf,0x1c,0x3c,0x78,0xd7,0x83,0x15}, + {0xe1,0x7a,0xa2,0x5d,0xef,0xa2,0xee,0xec,0x74,0x01,0x67,0x55,0x14,0x3a,0x7c,0x59,0x7a,0x16,0x09,0x66,0x12,0x2a,0xa6,0xc9,0x70,0x8f,0xed,0x81,0x2e,0x5f,0x2a,0x25,0xc7,0x28,0x9d,0xcc,0x04,0x47,0x03,0x90,0x8f,0xc5,0x2c,0xf7,0x9e,0x67,0x1b,0x1d,0x26,0x87,0x5b,0xbe,0x5f,0x2b,0xe1,0x16,0x0a,0x58,0xc5,0x83,0x4e,0x06,0x58,0x49,0x0d,0xe8,0x66,0x50,0x26,0x94,0x28,0x0d,0x6b,0x8c,0x7c,0x30,0x85,0xf7,0xc3,0xfc,0xfd,0x12,0x11,0x0c,0x78,0xda,0x53,0x1b,0x88,0xb3,0x43,0xd8,0x0b,0x17,0x9c,0x07}, + {0xff,0x6f,0xfa,0x64,0xe4,0xec,0x06,0x05,0x23,0xe5,0x05,0x62,0x1e,0x43,0xe3,0xbe,0x42,0xea,0xb8,0x51,0x24,0x42,0x79,0x35,0x00,0xfb,0xc9,0x4a,0xe3,0x05,0xec,0x6d,0x56,0xd0,0xd5,0xc0,0x50,0xcd,0xd6,0xcd,0x3b,0x57,0x03,0xbb,0x6d,0x68,0xf7,0x9a,0x48,0xef,0xc3,0xf3,0x3f,0x72,0xa6,0x3c,0xcc,0x8a,0x7b,0x31,0xd7,0xc0,0x68,0x67,0xb3,0xc1,0x55,0xf1,0xe5,0x25,0xb6,0x94,0x91,0x7b,0x7b,0x99,0xa7,0xf3,0x7b,0x41,0x00,0x26,0x6b,0x6d,0xdc,0xbd,0x2c,0xc2,0xf4,0x52,0xcd,0xdd,0x14,0x5e,0x44,0x51}, + {0x51,0x49,0x14,0x3b,0x4b,0x2b,0x50,0x57,0xb3,0xbc,0x4b,0x44,0x6b,0xff,0x67,0x8e,0xdb,0x85,0x63,0x16,0x27,0x69,0xbd,0xb8,0xc8,0x95,0x92,0xe3,0x31,0x6f,0x18,0x13,0x55,0xa4,0xbe,0x2b,0xab,0x47,0x31,0x89,0x29,0x91,0x07,0x92,0x4f,0xa2,0x53,0x8c,0xa7,0xf7,0x30,0xbe,0x48,0xf9,0x49,0x4b,0x3d,0xd4,0x4f,0x6e,0x08,0x90,0xe9,0x12,0x2e,0xbb,0xdf,0x7f,0xb3,0x96,0x0c,0xf1,0xf9,0xea,0x1c,0x12,0x5e,0x93,0x9a,0x9f,0x3f,0x98,0x5b,0x3a,0xc4,0x36,0x11,0xdf,0xaf,0x99,0x3e,0x5d,0xf0,0xe3,0xb2,0x77}, + {0xde,0xc4,0x2e,0x9c,0xc5,0xa9,0x6f,0x29,0xcb,0xf3,0x84,0x4f,0xbf,0x61,0x8b,0xbc,0x08,0xf9,0xa8,0x17,0xd9,0x06,0x77,0x1c,0x5d,0x25,0xd3,0x7a,0xfc,0x95,0xb7,0x63,0xa4,0xb0,0xdd,0x12,0x9c,0x63,0x98,0xd5,0x6b,0x86,0x24,0xc0,0x30,0x9f,0xd1,0xa5,0x60,0xe4,0xfc,0x58,0x03,0x2f,0x7c,0xd1,0x8a,0x5e,0x09,0x2e,0x15,0x95,0xa1,0x07,0xc8,0x5f,0x9e,0x38,0x02,0x8f,0x36,0xa8,0x3b,0xe4,0x8d,0xcf,0x02,0x3b,0x43,0x90,0x43,0x26,0x41,0xc5,0x5d,0xfd,0xa1,0xaf,0x37,0x01,0x2f,0x03,0x3d,0xe8,0x8f,0x3e}, + {0x94,0xa2,0x70,0x05,0xb9,0x15,0x8b,0x2f,0x49,0x45,0x08,0x67,0x70,0x42,0xf2,0x94,0x84,0xfd,0xbb,0x61,0xe1,0x5a,0x1c,0xde,0x07,0x40,0xac,0x7f,0x79,0x3b,0xba,0x75,0x3c,0xd1,0xef,0xe8,0x8d,0x4c,0x70,0x08,0x31,0x37,0xe0,0x33,0x8e,0x1a,0xc5,0xdf,0xe3,0xcd,0x60,0x12,0xa5,0x5d,0x9d,0xa5,0x86,0x8c,0x25,0xa6,0x99,0x08,0xd6,0x22,0x96,0xd1,0xcd,0x70,0xc0,0xdb,0x39,0x62,0x9a,0x8a,0x7d,0x6c,0x8b,0x8a,0xfe,0x60,0x60,0x12,0x40,0xeb,0xbc,0x47,0x88,0xb3,0x5e,0x9e,0x77,0x87,0x7b,0xd0,0x04,0x09}, + {0x9c,0x91,0xba,0xdd,0xd4,0x1f,0xce,0xb4,0xaa,0x8d,0x4c,0xc7,0x3e,0xdb,0x31,0xcf,0x51,0xcc,0x86,0xad,0x63,0xcc,0x63,0x2c,0x07,0xde,0x1d,0xbc,0x3f,0x14,0xe2,0x43,0xb9,0x40,0xf9,0x48,0x66,0x2d,0x32,0xf4,0x39,0x0c,0x2d,0xbd,0x0c,0x2f,0x95,0x06,0x31,0xf9,0x81,0xa0,0xad,0x97,0x76,0x16,0x6c,0x2a,0xf7,0xba,0xce,0xaa,0x40,0x62,0xa0,0x95,0xa2,0x5b,0x9c,0x74,0x34,0xf8,0x5a,0xd2,0x37,0xca,0x5b,0x7c,0x94,0xd6,0x6a,0x31,0xc9,0xe7,0xa7,0x3b,0xf1,0x66,0xac,0x0c,0xb4,0x8d,0x23,0xaf,0xbd,0x56}, + {0xeb,0x33,0x35,0xf5,0xe3,0xb9,0x2a,0x36,0x40,0x3d,0xb9,0x6e,0xd5,0x68,0x85,0x33,0x72,0x55,0x5a,0x1d,0x52,0x14,0x0e,0x9e,0x18,0x13,0x74,0x83,0x6d,0xa8,0x24,0x1d,0xb2,0x3b,0x9d,0xc1,0x6c,0xd3,0x10,0x13,0xb9,0x86,0x23,0x62,0xb7,0x6b,0x2a,0x06,0x5c,0x4f,0xa1,0xd7,0x91,0x85,0x9b,0x7c,0x54,0x57,0x1e,0x7e,0x50,0x31,0xaa,0x03,0x1f,0xce,0xd4,0xff,0x48,0x76,0xec,0xf4,0x1c,0x8c,0xac,0x54,0xf0,0xea,0x45,0xe0,0x7c,0x35,0x09,0x1d,0x82,0x25,0xd2,0x88,0x59,0x48,0xeb,0x9a,0xdc,0x61,0xb2,0x43}, + {0xbb,0x79,0xbb,0x88,0x19,0x1e,0x5b,0xe5,0x9d,0x35,0x7a,0xc1,0x7d,0xd0,0x9e,0xa0,0x33,0xea,0x3d,0x60,0xe2,0x2e,0x2c,0xb0,0xc2,0x6b,0x27,0x5b,0xcf,0x55,0x60,0x32,0x64,0x13,0x95,0x6c,0x8b,0x3d,0x51,0x19,0x7b,0xf4,0x0b,0x00,0x26,0x71,0xfe,0x94,0x67,0x95,0x4f,0xd5,0xdd,0x10,0x8d,0x02,0x64,0x09,0x94,0x42,0xe2,0xd5,0xb4,0x02,0xf2,0x8d,0xd1,0x28,0xcb,0x55,0xa1,0xb4,0x08,0xe5,0x6c,0x18,0x46,0x46,0xcc,0xea,0x89,0x43,0x82,0x6c,0x93,0xf4,0x9c,0xc4,0x10,0x34,0x5d,0xae,0x09,0xc8,0xa6,0x27}, + {0x88,0xb1,0x0d,0x1f,0xcd,0xeb,0xa6,0x8b,0xe8,0x5b,0x5a,0x67,0x3a,0xd7,0xd3,0x37,0x5a,0x58,0xf5,0x15,0xa3,0xdf,0x2e,0xf2,0x7e,0xa1,0x60,0xff,0x74,0x71,0xb6,0x2c,0x54,0x69,0x3d,0xc4,0x0a,0x27,0x2c,0xcd,0xb2,0xca,0x66,0x6a,0x57,0x3e,0x4a,0xdd,0x6c,0x03,0xd7,0x69,0x24,0x59,0xfa,0x79,0x99,0x25,0x8c,0x3d,0x60,0x03,0x15,0x22,0xd0,0xe1,0x0b,0x39,0xf9,0xcd,0xee,0x59,0xf1,0xe3,0x8c,0x72,0x44,0x20,0x42,0xa9,0xf4,0xf0,0x94,0x7a,0x66,0x1c,0x89,0x82,0x36,0xf4,0x90,0x38,0xb7,0xf4,0x1d,0x7b}, + {0x24,0xa2,0xb2,0xb3,0xe0,0xf2,0x92,0xe4,0x60,0x11,0x55,0x2b,0x06,0x9e,0x6c,0x7c,0x0e,0x7b,0x7f,0x0d,0xe2,0x8f,0xeb,0x15,0x92,0x59,0xfc,0x58,0x26,0xef,0xfc,0x61,0x8c,0xf5,0xf8,0x07,0x18,0x22,0x2e,0x5f,0xd4,0x09,0x94,0xd4,0x9f,0x5c,0x55,0xe3,0x30,0xa6,0xb6,0x1f,0x8d,0xa8,0xaa,0xb2,0x3d,0xe0,0x52,0xd3,0x45,0x82,0x69,0x68,0x7a,0x18,0x18,0x2a,0x85,0x5d,0xb1,0xdb,0xd7,0xac,0xdd,0x86,0xd3,0xaa,0xe4,0xf3,0x82,0xc4,0xf6,0x0f,0x81,0xe2,0xba,0x44,0xcf,0x01,0xaf,0x3d,0x47,0x4c,0xcf,0x46}, + {0xf9,0xe5,0xc4,0x9e,0xed,0x25,0x65,0x42,0x03,0x33,0x90,0x16,0x01,0xda,0x5e,0x0e,0xdc,0xca,0xe5,0xcb,0xf2,0xa7,0xb1,0x72,0x40,0x5f,0xeb,0x14,0xcd,0x7b,0x38,0x29,0x40,0x81,0x49,0xf1,0xa7,0x6e,0x3c,0x21,0x54,0x48,0x2b,0x39,0xf8,0x7e,0x1e,0x7c,0xba,0xce,0x29,0x56,0x8c,0xc3,0x88,0x24,0xbb,0xc5,0x8c,0x0d,0xe5,0xaa,0x65,0x10,0x57,0x0d,0x20,0xdf,0x25,0x45,0x2c,0x1c,0x4a,0x67,0xca,0xbf,0xd6,0x2d,0x3b,0x5c,0x30,0x40,0x83,0xe1,0xb1,0xe7,0x07,0x0a,0x16,0xe7,0x1c,0x4f,0xe6,0x98,0xa1,0x69}, + {0xbc,0x78,0x1a,0xd9,0xe0,0xb2,0x62,0x90,0x67,0x96,0x50,0xc8,0x9c,0x88,0xc9,0x47,0xb8,0x70,0x50,0x40,0x66,0x4a,0xf5,0x9d,0xbf,0xa1,0x93,0x24,0xa9,0xe6,0x69,0x73,0xed,0xca,0xc5,0xdc,0x34,0x44,0x01,0xe1,0x33,0xfb,0x84,0x3c,0x96,0x5d,0xed,0x47,0xe7,0xa0,0x86,0xed,0x76,0x95,0x01,0x70,0xe4,0xf9,0x67,0xd2,0x7b,0x69,0xb2,0x25,0x64,0x68,0x98,0x13,0xfb,0x3f,0x67,0x9d,0xb8,0xc7,0x5d,0x41,0xd9,0xfb,0xa5,0x3c,0x5e,0x3b,0x27,0xdf,0x3b,0xcc,0x4e,0xe0,0xd2,0x4c,0x4e,0xb5,0x3d,0x68,0x20,0x14}, + {0x97,0xd1,0x9d,0x24,0x1e,0xbd,0x78,0xb4,0x02,0xc1,0x58,0x5e,0x00,0x35,0x0c,0x62,0x5c,0xac,0xba,0xcc,0x2f,0xd3,0x02,0xfb,0x2d,0xa7,0x08,0xf5,0xeb,0x3b,0xb6,0x60,0xd0,0x5a,0xcc,0xc1,0x6f,0xbb,0xee,0x34,0x8b,0xac,0x46,0x96,0xe9,0x0c,0x1b,0x6a,0x53,0xde,0x6b,0xa6,0x49,0xda,0xb0,0xd3,0xc1,0x81,0xd0,0x61,0x41,0x3b,0xe8,0x31,0x4f,0x2b,0x06,0x9e,0x12,0xc7,0xe8,0x97,0xd8,0x0a,0x32,0x29,0x4f,0x8f,0xe4,0x49,0x3f,0x68,0x18,0x6f,0x4b,0xe1,0xec,0x5b,0x17,0x03,0x55,0x2d,0xb6,0x1e,0xcf,0x55}, + {0x58,0x3d,0xc2,0x65,0x10,0x10,0x79,0x58,0x9c,0x81,0x94,0x50,0x6d,0x08,0x9d,0x8b,0xa7,0x5f,0xc5,0x12,0xa9,0x2f,0x40,0xe2,0xd4,0x91,0x08,0x57,0x64,0x65,0x9a,0x66,0x52,0x8c,0xf5,0x7d,0xe3,0xb5,0x76,0x30,0x36,0xcc,0x99,0xe7,0xdd,0xb9,0x3a,0xd7,0x20,0xee,0x13,0x49,0xe3,0x1c,0x83,0xbd,0x33,0x01,0xba,0x62,0xaa,0xfb,0x56,0x1a,0xec,0xc9,0x9d,0x5c,0x50,0x6b,0x3e,0x94,0x1a,0x37,0x7c,0xa7,0xbb,0x57,0x25,0x30,0x51,0x76,0x34,0x41,0x56,0xae,0x73,0x98,0x5c,0x8a,0xc5,0x99,0x67,0x83,0xc4,0x13}, + {0xb9,0xe1,0xb3,0x5a,0x46,0x5d,0x3a,0x42,0x61,0x3f,0xf1,0xc7,0x87,0xc1,0x13,0xfc,0xb6,0xb9,0xb5,0xec,0x64,0x36,0xf8,0x19,0x07,0xb6,0x37,0xa6,0x93,0x0c,0xf8,0x66,0x80,0xd0,0x8b,0x5d,0x6a,0xfb,0xdc,0xc4,0x42,0x48,0x1a,0x57,0xec,0xc4,0xeb,0xde,0x65,0x53,0xe5,0xb8,0x83,0xe8,0xb2,0xd4,0x27,0xb8,0xe5,0xc8,0x7d,0xc8,0xbd,0x50,0x11,0xe1,0xdf,0x6e,0x83,0x37,0x6d,0x60,0xd9,0xab,0x11,0xf0,0x15,0x3e,0x35,0x32,0x96,0x3b,0xb7,0x25,0xc3,0x3a,0xb0,0x64,0xae,0xd5,0x5f,0x72,0x44,0x64,0xd5,0x1d}, + {0x7d,0x12,0x62,0x33,0xf8,0x7f,0xa4,0x8f,0x15,0x7c,0xcd,0x71,0xc4,0x6a,0x9f,0xbc,0x8b,0x0c,0x22,0x49,0x43,0x45,0x71,0x6e,0x2e,0x73,0x9f,0x21,0x12,0x59,0x64,0x0e,0x9a,0xc8,0xba,0x08,0x00,0xe6,0x97,0xc2,0xe0,0xc3,0xe1,0xea,0x11,0xea,0x4c,0x7d,0x7c,0x97,0xe7,0x9f,0xe1,0x8b,0xe3,0xf3,0xcd,0x05,0xa3,0x63,0x0f,0x45,0x3a,0x3a,0x27,0x46,0x39,0xd8,0x31,0x2f,0x8f,0x07,0x10,0xa5,0x94,0xde,0x83,0x31,0x9d,0x38,0x80,0x6f,0x99,0x17,0x6d,0x6c,0xe3,0xd1,0x7b,0xa8,0xa9,0x93,0x93,0x8d,0x8c,0x31}, + {0x19,0xfe,0xff,0x2a,0x03,0x5d,0x74,0xf2,0x66,0xdb,0x24,0x7f,0x49,0x3c,0x9f,0x0c,0xef,0x98,0x85,0xba,0xe3,0xd3,0x98,0xbc,0x14,0x53,0x1d,0x9a,0x67,0x7c,0x4c,0x22,0x98,0xd3,0x1d,0xab,0x29,0x9e,0x66,0x5d,0x3b,0x9e,0x2d,0x34,0x58,0x16,0x92,0xfc,0xcd,0x73,0x59,0xf3,0xfd,0x1d,0x85,0x55,0xf6,0x0a,0x95,0x25,0xc3,0x41,0x9a,0x50,0xe9,0x25,0xf9,0xa6,0xdc,0x6e,0xc0,0xbd,0x33,0x1f,0x1b,0x64,0xf4,0xf3,0x3e,0x79,0x89,0x3e,0x83,0x9d,0x80,0x12,0xec,0x82,0x89,0x13,0xa1,0x28,0x23,0xf0,0xbf,0x05}, + {0x0b,0xe0,0xca,0x23,0x70,0x13,0x32,0x36,0x59,0xcf,0xac,0xd1,0x0a,0xcf,0x4a,0x54,0x88,0x1c,0x1a,0xd2,0x49,0x10,0x74,0x96,0xa7,0x44,0x2a,0xfa,0xc3,0x8c,0x0b,0x78,0xe4,0x12,0xc5,0x0d,0xdd,0xa0,0x81,0x68,0xfe,0xfa,0xa5,0x44,0xc8,0x0d,0xe7,0x4f,0x40,0x52,0x4a,0x8f,0x6b,0x8e,0x74,0x1f,0xea,0xa3,0x01,0xee,0xcd,0x77,0x62,0x57,0x5f,0x30,0x4f,0x23,0xbc,0x8a,0xf3,0x1e,0x08,0xde,0x05,0x14,0xbd,0x7f,0x57,0x9a,0x0d,0x2a,0xe6,0x34,0x14,0xa5,0x82,0x5e,0xa1,0xb7,0x71,0x62,0x72,0x18,0xf4,0x5f}, + {0x9d,0xdb,0x89,0x17,0x0c,0x08,0x8e,0x39,0xf5,0x78,0xe7,0xf3,0x25,0x20,0x60,0xa7,0x5d,0x03,0xbd,0x06,0x4c,0x89,0x98,0xfa,0xbe,0x66,0xa9,0x25,0xdc,0x03,0x6a,0x10,0x40,0x95,0xb6,0x13,0xe8,0x47,0xdb,0xe5,0xe1,0x10,0x26,0x43,0x3b,0x2a,0x5d,0xf3,0x76,0x12,0x78,0x38,0xe9,0x26,0x1f,0xac,0x69,0xcb,0xa0,0xa0,0x8c,0xdb,0xd4,0x29,0xd0,0x53,0x33,0x33,0xaf,0x0a,0xad,0xd9,0xe5,0x09,0xd3,0xac,0xa5,0x9d,0x66,0x38,0xf0,0xf7,0x88,0xc8,0x8a,0x65,0x57,0x3c,0xfa,0xbe,0x2c,0x05,0x51,0x8a,0xb3,0x4a}, + {0x93,0xd5,0x68,0x67,0x25,0x2b,0x7c,0xda,0x13,0xca,0x22,0x44,0x57,0xc0,0xc1,0x98,0x1d,0xce,0x0a,0xca,0xd5,0x0b,0xa8,0xf1,0x90,0xa6,0x88,0xc0,0xad,0xd1,0xcd,0x29,0x9c,0xc0,0xdd,0x5f,0xef,0xd1,0xcf,0xd6,0xce,0x5d,0x57,0xf7,0xfd,0x3e,0x2b,0xe8,0xc2,0x34,0x16,0x20,0x5d,0x6b,0xd5,0x25,0x9b,0x2b,0xed,0x04,0xbb,0xc6,0x41,0x30,0x48,0xe1,0x56,0xd9,0xf9,0xf2,0xf2,0x0f,0x2e,0x6b,0x35,0x9f,0x75,0x97,0xe7,0xad,0x5c,0x02,0x6c,0x5f,0xbb,0x98,0x46,0x1a,0x7b,0x9a,0x04,0x14,0x68,0xbd,0x4b,0x10}, + {0x67,0xed,0xf1,0x68,0x31,0xfd,0xf0,0x51,0xc2,0x3b,0x6f,0xd8,0xcd,0x1d,0x81,0x2c,0xde,0xf2,0xd2,0x04,0x43,0x5c,0xdc,0x44,0x49,0x71,0x2a,0x09,0x57,0xcc,0xe8,0x5b,0x63,0xf1,0x7f,0xd6,0x5f,0x9a,0x5d,0xa9,0x81,0x56,0xc7,0x4c,0x9d,0xe6,0x2b,0xe9,0x57,0xf2,0x20,0xde,0x4c,0x02,0xf8,0xb7,0xf5,0x2d,0x07,0xfb,0x20,0x2a,0x4f,0x20,0x79,0xb0,0xeb,0x30,0x3d,0x3b,0x14,0xc8,0x30,0x2e,0x65,0xbd,0x5a,0x15,0x89,0x75,0x31,0x5c,0x6d,0x8f,0x31,0x3c,0x3c,0x65,0x1f,0x16,0x79,0xc2,0x17,0xfb,0x70,0x25}, + {0x75,0x15,0xb6,0x2c,0x7f,0x36,0xfa,0x3e,0x6c,0x02,0xd6,0x1c,0x76,0x6f,0xf9,0xf5,0x62,0x25,0xb5,0x65,0x2a,0x14,0xc7,0xe8,0xcd,0x0a,0x03,0x53,0xea,0x65,0xcb,0x3d,0x5a,0x24,0xb8,0x0b,0x55,0xa9,0x2e,0x19,0xd1,0x50,0x90,0x8f,0xa8,0xfb,0xe6,0xc8,0x35,0xc9,0xa4,0x88,0x2d,0xea,0x86,0x79,0x68,0x86,0x01,0xde,0x91,0x5f,0x1c,0x24,0xaa,0x6c,0xde,0x40,0x29,0x17,0xd8,0x28,0x3a,0x73,0xd9,0x22,0xf0,0x2c,0xbf,0x8f,0xd1,0x01,0x5b,0x23,0xdd,0xfc,0xd7,0x16,0xe5,0xf0,0xcd,0x5f,0xdd,0x0e,0x42,0x08}, + {0x4a,0xfa,0x62,0x83,0xab,0x20,0xff,0xcd,0x6e,0x3e,0x1a,0xe2,0xd4,0x18,0xe1,0x57,0x2b,0xe6,0x39,0xfc,0x17,0x96,0x17,0xe3,0xfd,0x69,0x17,0xbc,0xef,0x53,0x9a,0x0d,0xce,0x10,0xf4,0x04,0x4e,0xc3,0x58,0x03,0x85,0x06,0x6e,0x27,0x5a,0x5b,0x13,0xb6,0x21,0x15,0xb9,0xeb,0xc7,0x70,0x96,0x5d,0x9c,0x88,0xdb,0x21,0xf3,0x54,0xd6,0x04,0xd5,0xb5,0xbd,0xdd,0x16,0xc1,0x7d,0x5e,0x2d,0xdd,0xa5,0x8d,0xb6,0xde,0x54,0x29,0x92,0xa2,0x34,0x33,0x17,0x08,0xb6,0x1c,0xd7,0x1a,0x99,0x18,0x26,0x4f,0x7a,0x4a}, + {0x95,0x5f,0xb1,0x5f,0x02,0x18,0xa7,0xf4,0x8f,0x1b,0x5c,0x6b,0x34,0x5f,0xf6,0x3d,0x12,0x11,0xe0,0x00,0x85,0xf0,0xfc,0xcd,0x48,0x18,0xd3,0xdd,0x4c,0x0c,0xb5,0x11,0x4b,0x2a,0x37,0xaf,0x91,0xb2,0xc3,0x24,0xf2,0x47,0x81,0x71,0x70,0x82,0xda,0x93,0xf2,0x9e,0x89,0x86,0x64,0x85,0x84,0xdd,0x33,0xee,0xe0,0x23,0x42,0x31,0x96,0x4a,0xd6,0xff,0xa4,0x08,0x44,0x27,0xe8,0xa6,0xd9,0x76,0x15,0x9c,0x7e,0x17,0x8e,0x73,0xf2,0xb3,0x02,0x3d,0xb6,0x48,0x33,0x77,0x51,0xcc,0x6b,0xce,0x4d,0xce,0x4b,0x4f}, + {0x84,0x25,0x24,0xe2,0x5a,0xce,0x1f,0xa7,0x9e,0x8a,0xf5,0x92,0x56,0x72,0xea,0x26,0xf4,0x3c,0xea,0x1c,0xd7,0x09,0x1a,0xd2,0xe6,0x01,0x1c,0xb7,0x14,0xdd,0xfc,0x73,0x6f,0x0b,0x9d,0xc4,0x6e,0x61,0xe2,0x30,0x17,0x23,0xec,0xca,0x8f,0x71,0x56,0xe4,0xa6,0x4f,0x6b,0xf2,0x9b,0x40,0xeb,0x48,0x37,0x5f,0x59,0x61,0xe5,0xce,0x42,0x30,0x41,0xac,0x9b,0x44,0x79,0x70,0x7e,0x42,0x0a,0x31,0xe2,0xbc,0x6d,0xe3,0x5a,0x85,0x7c,0x1a,0x84,0x5f,0x21,0x76,0xae,0x4c,0xd6,0xe1,0x9c,0x9a,0x0c,0x74,0x9e,0x38}, + {0xce,0xb9,0xdc,0x34,0xae,0xb3,0xfc,0x64,0xad,0xd0,0x48,0xe3,0x23,0x03,0x50,0x97,0x1b,0x38,0xc6,0x62,0x7d,0xf0,0xb3,0x45,0x88,0x67,0x5a,0x46,0x79,0x53,0x54,0x61,0x28,0xac,0x0e,0x57,0xf6,0x78,0xbd,0xc9,0xe1,0x9c,0x91,0x27,0x32,0x0b,0x5b,0xe5,0xed,0x91,0x9b,0xa1,0xab,0x3e,0xfc,0x65,0x90,0x36,0x26,0xd6,0xe5,0x25,0xc4,0x25,0x6e,0xde,0xd7,0xf1,0xa6,0x06,0x3e,0x3f,0x08,0x23,0x06,0x8e,0x27,0x76,0xf9,0x3e,0x77,0x6c,0x8a,0x4e,0x26,0xf6,0x14,0x8c,0x59,0x47,0x48,0x15,0x89,0xa0,0x39,0x65}, + {0x73,0xf7,0xd2,0xc3,0x74,0x1f,0xd2,0xe9,0x45,0x68,0xc4,0x25,0x41,0x54,0x50,0xc1,0x33,0x9e,0xb9,0xf9,0xe8,0x5c,0x4e,0x62,0x6c,0x18,0xcd,0xc5,0xaa,0xe4,0xc5,0x11,0x19,0x4a,0xbb,0x14,0xd4,0xdb,0xc4,0xdd,0x8e,0x4f,0x42,0x98,0x3c,0xbc,0xb2,0x19,0x69,0x71,0xca,0x36,0xd7,0x9f,0xa8,0x48,0x90,0xbd,0x19,0xf0,0x0e,0x32,0x65,0x0f,0xc6,0xe0,0xfd,0xca,0xb1,0xd1,0x86,0xd4,0x81,0x51,0x3b,0x16,0xe3,0xe6,0x3f,0x4f,0x9a,0x93,0xf2,0xfa,0x0d,0xaf,0xa8,0x59,0x2a,0x07,0x33,0xec,0xbd,0xc7,0xab,0x4c}, + {0x2e,0x0a,0x9c,0x08,0x24,0x96,0x9e,0x23,0x38,0x47,0xfe,0x3a,0xc0,0xc4,0x48,0xc7,0x2a,0xa1,0x4f,0x76,0x2a,0xed,0xdb,0x17,0x82,0x85,0x1c,0x32,0xf0,0x93,0x9b,0x63,0x89,0xd2,0x78,0x3f,0x8f,0x78,0x8f,0xc0,0x9f,0x4d,0x40,0xa1,0x2c,0xa7,0x30,0xfe,0x9d,0xcc,0x65,0xcf,0xfc,0x8b,0x77,0xf2,0x21,0x20,0xcb,0x5a,0x16,0x98,0xe4,0x7e,0xc3,0xa1,0x11,0x91,0xe3,0x08,0xd5,0x7b,0x89,0x74,0x90,0x80,0xd4,0x90,0x2b,0x2b,0x19,0xfd,0x72,0xae,0xc2,0xae,0xd2,0xe7,0xa6,0x02,0xb6,0x85,0x3c,0x49,0xdf,0x0e}, + {0x68,0x5a,0x9b,0x59,0x58,0x81,0xcc,0xae,0x0e,0xe2,0xad,0xeb,0x0f,0x4f,0x57,0xea,0x07,0x7f,0xb6,0x22,0x74,0x1d,0xe4,0x4f,0xb4,0x4f,0x9d,0x01,0xe3,0x92,0x3b,0x40,0x13,0x41,0x76,0x84,0xd2,0xc4,0x67,0x67,0x35,0xf8,0xf5,0xf7,0x3f,0x40,0x90,0xa0,0xde,0xbe,0xe6,0xca,0xfa,0xcf,0x8f,0x1c,0x69,0xa3,0xdf,0xd1,0x54,0x0c,0xc0,0x04,0xf8,0x5c,0x46,0x8b,0x81,0x2f,0xc2,0x4d,0xf8,0xef,0x80,0x14,0x5a,0xf3,0xa0,0x71,0x57,0xd6,0xc7,0x04,0xad,0xbf,0xe8,0xae,0xf4,0x76,0x61,0xb2,0x2a,0xb1,0x5b,0x35}, + {0xf4,0xbb,0x93,0x74,0xcc,0x64,0x1e,0xa7,0xc3,0xb0,0xa3,0xec,0xd9,0x84,0xbd,0xe5,0x85,0xe7,0x05,0xfa,0x0c,0xc5,0x6b,0x0a,0x12,0xc3,0x2e,0x18,0x32,0x81,0x9b,0x0f,0x18,0x73,0x8c,0x5a,0xc7,0xda,0x01,0xa3,0x11,0xaa,0xce,0xb3,0x9d,0x03,0x90,0xed,0x2d,0x3f,0xae,0x3b,0xbf,0x7c,0x07,0x6f,0x8e,0xad,0x52,0xe0,0xf8,0xea,0x18,0x75,0x32,0x6c,0x7f,0x1b,0xc4,0x59,0x88,0xa4,0x98,0x32,0x38,0xf4,0xbc,0x60,0x2d,0x0f,0xd9,0xd1,0xb1,0xc9,0x29,0xa9,0x15,0x18,0xc4,0x55,0x17,0xbb,0x1b,0x87,0xc3,0x47}, + {0x48,0x4f,0xec,0x71,0x97,0x53,0x44,0x51,0x6e,0x5d,0x8c,0xc9,0x7d,0xb1,0x05,0xf8,0x6b,0xc6,0xc3,0x47,0x1a,0xc1,0x62,0xf7,0xdc,0x99,0x46,0x76,0x85,0x9b,0xb8,0x00,0xb0,0x66,0x50,0xc8,0x50,0x5d,0xe6,0xfb,0xb0,0x99,0xa2,0xb3,0xb0,0xc4,0xec,0x62,0xe0,0xe8,0x1a,0x44,0xea,0x54,0x37,0xe5,0x5f,0x8d,0xd4,0xe8,0x2c,0xa0,0xfe,0x08,0xd0,0xea,0xde,0x68,0x76,0xdd,0x4d,0x82,0x23,0x5d,0x68,0x4b,0x20,0x45,0x64,0xc8,0x65,0xd6,0x89,0x5d,0xcd,0xcf,0x14,0xb5,0x37,0xd5,0x75,0x4f,0xa7,0x29,0x38,0x47}, + {0x18,0xc4,0x79,0x46,0x75,0xda,0xd2,0x82,0xf0,0x8d,0x61,0xb2,0xd8,0xd7,0x3b,0xe6,0x0a,0xeb,0x47,0xac,0x24,0xef,0x5e,0x35,0xb4,0xc6,0x33,0x48,0x4c,0x68,0x78,0x20,0xc9,0x02,0x39,0xad,0x3a,0x53,0xd9,0x23,0x8f,0x58,0x03,0xef,0xce,0xdd,0xc2,0x64,0xb4,0x2f,0xe1,0xcf,0x90,0x73,0x25,0x15,0x90,0xd3,0xe4,0x44,0x4d,0x8b,0x66,0x6c,0x0c,0x82,0x78,0x7a,0x21,0xcf,0x48,0x3b,0x97,0x3e,0x27,0x81,0xb2,0x0a,0x6a,0xf7,0x7b,0xed,0x8e,0x8c,0xa7,0x65,0x6c,0xa9,0x3f,0x43,0x8a,0x4f,0x05,0xa6,0x11,0x74}, + {0x6d,0xc8,0x9d,0xb9,0x32,0x9d,0x65,0x4d,0x15,0xf1,0x3a,0x60,0x75,0xdc,0x4c,0x04,0x88,0xe4,0xc2,0xdc,0x2c,0x71,0x4c,0xb3,0xff,0x34,0x81,0xfb,0x74,0x65,0x13,0x7c,0xb4,0x75,0xb1,0x18,0x3d,0xe5,0x9a,0x57,0x02,0xa1,0x92,0xf3,0x59,0x31,0x71,0x68,0xf5,0x35,0xef,0x1e,0xba,0xec,0x55,0x84,0x8f,0x39,0x8c,0x45,0x72,0xa8,0xc9,0x1e,0x9b,0x50,0xa2,0x00,0xd4,0xa4,0xe6,0xb8,0xb4,0x82,0xc8,0x0b,0x02,0xd7,0x81,0x9b,0x61,0x75,0x95,0xf1,0x9b,0xcc,0xe7,0x57,0x60,0x64,0xcd,0xc7,0xa5,0x88,0xdd,0x3a}, + {0xf2,0xdc,0x35,0xb6,0x70,0x57,0x89,0xab,0xbc,0x1f,0x6c,0xf6,0x6c,0xef,0xdf,0x02,0x87,0xd1,0xb6,0xbe,0x68,0x02,0x53,0x85,0x74,0x9e,0x87,0xcc,0xfc,0x29,0x99,0x24,0x46,0x30,0x39,0x59,0xd4,0x98,0xc2,0x85,0xec,0x59,0xf6,0x5f,0x98,0x35,0x7e,0x8f,0x3a,0x6e,0xf6,0xf2,0x2a,0xa2,0x2c,0x1d,0x20,0xa7,0x06,0xa4,0x31,0x11,0xba,0x61,0x29,0x90,0x95,0x16,0xf1,0xa0,0xd0,0xa3,0x89,0xbd,0x7e,0xba,0x6c,0x6b,0x3b,0x02,0x07,0x33,0x78,0x26,0x3e,0x5a,0xf1,0x7b,0xe7,0xec,0xd8,0xbb,0x0c,0x31,0x20,0x56}, + {0x43,0xd6,0x34,0x49,0x43,0x93,0x89,0x52,0xf5,0x22,0x12,0xa5,0x06,0xf8,0xdb,0xb9,0x22,0x1c,0xf4,0xc3,0x8f,0x87,0x6d,0x8f,0x30,0x97,0x9d,0x4d,0x2a,0x6a,0x67,0x37,0xd6,0x85,0xe2,0x77,0xf4,0xb5,0x46,0x66,0x93,0x61,0x8f,0x6c,0x67,0xff,0xe8,0x40,0xdd,0x94,0xb5,0xab,0x11,0x73,0xec,0xa6,0x4d,0xec,0x8c,0x65,0xf3,0x46,0xc8,0x7e,0xc7,0x2e,0xa2,0x1d,0x3f,0x8f,0x5e,0x9b,0x13,0xcd,0x01,0x6c,0x77,0x1d,0x0f,0x13,0xb8,0x9f,0x98,0xa2,0xcf,0x8f,0x4c,0x21,0xd5,0x9d,0x9b,0x39,0x23,0xf7,0xaa,0x6d}, + {0x47,0xbe,0x3d,0xeb,0x62,0x75,0x3a,0x5f,0xb8,0xa0,0xbd,0x8e,0x54,0x38,0xea,0xf7,0x99,0x72,0x74,0x45,0x31,0xe5,0xc3,0x00,0x51,0xd5,0x27,0x16,0xe7,0xe9,0x04,0x13,0xa2,0x8e,0xad,0xac,0xbf,0x04,0x3b,0x58,0x84,0xe8,0x8b,0x14,0xe8,0x43,0xb7,0x29,0xdb,0xc5,0x10,0x08,0x3b,0x58,0x1e,0x2b,0xaa,0xbb,0xb3,0x8e,0xe5,0x49,0x54,0x2b,0xfe,0x9c,0xdc,0x6a,0xd2,0x14,0x98,0x78,0x0b,0xdd,0x48,0x8b,0x3f,0xab,0x1b,0x3c,0x0a,0xc6,0x79,0xf9,0xff,0xe1,0x0f,0xda,0x93,0xd6,0x2d,0x7c,0x2d,0xde,0x68,0x44}, + {0x9e,0x46,0x19,0x94,0x5e,0x35,0xbb,0x51,0x54,0xc7,0xdd,0x23,0x4c,0xdc,0xe6,0x33,0x62,0x99,0x7f,0x44,0xd6,0xb6,0xa5,0x93,0x63,0xbd,0x44,0xfb,0x6f,0x7c,0xce,0x6c,0xce,0x07,0x63,0xf8,0xc6,0xd8,0x9a,0x4b,0x28,0x0c,0x5d,0x43,0x31,0x35,0x11,0x21,0x2c,0x77,0x7a,0x65,0xc5,0x66,0xa8,0xd4,0x52,0x73,0x24,0x63,0x7e,0x42,0xa6,0x5d,0xca,0x22,0xac,0xde,0x88,0xc6,0x94,0x1a,0xf8,0x1f,0xae,0xbb,0xf7,0x6e,0x06,0xb9,0x0f,0x58,0x59,0x8d,0x38,0x8c,0xad,0x88,0xa8,0x2c,0x9f,0xe7,0xbf,0x9a,0xf2,0x58}, + {0x68,0x3e,0xe7,0x8d,0xab,0xcf,0x0e,0xe9,0xa5,0x76,0x7e,0x37,0x9f,0x6f,0x03,0x54,0x82,0x59,0x01,0xbe,0x0b,0x5b,0x49,0xf0,0x36,0x1e,0xf4,0xa7,0xc4,0x29,0x76,0x57,0xf6,0xcd,0x0e,0x71,0xbf,0x64,0x5a,0x4b,0x3c,0x29,0x2c,0x46,0x38,0xe5,0x4c,0xb1,0xb9,0x3a,0x0b,0xd5,0x56,0xd0,0x43,0x36,0x70,0x48,0x5b,0x18,0x24,0x37,0xf9,0x6a,0x88,0xa8,0xc6,0x09,0x45,0x02,0x20,0x32,0x73,0x89,0x55,0x4b,0x13,0x36,0xe0,0xd2,0x9f,0x28,0x33,0x3c,0x23,0x36,0xe2,0x83,0x8f,0xc1,0xae,0x0c,0xbb,0x25,0x1f,0x70}, + {0xed,0x6c,0x61,0xe4,0xf8,0xb0,0xa8,0xc3,0x7d,0xa8,0x25,0x9e,0x0e,0x66,0x00,0xf7,0x9c,0xa5,0xbc,0xf4,0x1f,0x06,0xe3,0x61,0xe9,0x0b,0xc4,0xbd,0xbf,0x92,0x0c,0x2e,0x13,0xc1,0xbe,0x7c,0xd9,0xf6,0x18,0x9d,0xe4,0xdb,0xbf,0x74,0xe6,0x06,0x4a,0x84,0xd6,0x60,0x4e,0xac,0x22,0xb5,0xf5,0x20,0x51,0x5e,0x95,0x50,0xc0,0x5b,0x0a,0x72,0x35,0x5a,0x80,0x9b,0x43,0x09,0x3f,0x0c,0xfc,0xab,0x42,0x62,0x37,0x8b,0x4e,0xe8,0x46,0x93,0x22,0x5c,0xf3,0x17,0x14,0x69,0xec,0xf0,0x4e,0x14,0xbb,0x9c,0x9b,0x0e}, + {0xad,0x20,0x57,0xfb,0x8f,0xd4,0xba,0xfb,0x0e,0x0d,0xf9,0xdb,0x6b,0x91,0x81,0xee,0xbf,0x43,0x55,0x63,0x52,0x31,0x81,0xd4,0xd8,0x7b,0x33,0x3f,0xeb,0x04,0x11,0x22,0xee,0xbe,0xb1,0x5d,0xd5,0x9b,0xee,0x8d,0xb9,0x3f,0x72,0x0a,0x37,0xab,0xc3,0xc9,0x91,0xd7,0x68,0x1c,0xbf,0xf1,0xa8,0x44,0xde,0x3c,0xfd,0x1c,0x19,0x44,0x6d,0x36,0x14,0x8c,0xbc,0xf2,0x43,0x17,0x3c,0x9e,0x3b,0x6c,0x85,0xb5,0xfc,0x26,0xda,0x2e,0x97,0xfb,0xa7,0x68,0x0e,0x2f,0xb8,0xcc,0x44,0x32,0x59,0xbc,0xe6,0xa4,0x67,0x41}, + {0x00,0x27,0xf6,0x76,0x28,0x9d,0x3b,0x64,0xeb,0x68,0x76,0x0e,0x40,0x9d,0x1d,0x5d,0x84,0x06,0xfc,0x21,0x03,0x43,0x4b,0x1b,0x6a,0x24,0x55,0x22,0x7e,0xbb,0x38,0x79,0xee,0x8f,0xce,0xf8,0x65,0x26,0xbe,0xc2,0x2c,0xd6,0x80,0xe8,0x14,0xff,0x67,0xe9,0xee,0x4e,0x36,0x2f,0x7e,0x6e,0x2e,0xf1,0xf6,0xd2,0x7e,0xcb,0x70,0x33,0xb3,0x34,0xcc,0xd6,0x81,0x86,0xee,0x91,0xc5,0xcd,0x53,0xa7,0x85,0xed,0x9c,0x10,0x02,0xce,0x83,0x88,0x80,0x58,0xc1,0x85,0x74,0xed,0xe4,0x65,0xfe,0x2d,0x6e,0xfc,0x76,0x11}, + {0x9b,0x61,0x9c,0x5b,0xd0,0x6c,0xaf,0xb4,0x80,0x84,0xa5,0xb2,0xf4,0xc9,0xdf,0x2d,0xc4,0x4d,0xe9,0xeb,0x02,0xa5,0x4f,0x3d,0x34,0x5f,0x7d,0x67,0x4c,0x3a,0xfc,0x08,0xb8,0x0e,0x77,0x49,0x89,0xe2,0x90,0xdb,0xa3,0x40,0xf4,0xac,0x2a,0xcc,0xfb,0x98,0x9b,0x87,0xd7,0xde,0xfe,0x4f,0x35,0x21,0xb6,0x06,0x69,0xf2,0x54,0x3e,0x6a,0x1f,0xea,0x34,0x07,0xd3,0x99,0xc1,0xa4,0x60,0xd6,0x5c,0x16,0x31,0xb6,0x85,0xc0,0x40,0x95,0x82,0x59,0xf7,0x23,0x3e,0x33,0xe2,0xd1,0x00,0xb9,0x16,0x01,0xad,0x2f,0x4f}, + {0x54,0x4e,0xae,0x94,0x41,0xb2,0xbe,0x44,0x6c,0xef,0x57,0x18,0x51,0x1c,0x54,0x5f,0x98,0x04,0x8d,0x36,0x2d,0x6b,0x1e,0xa6,0xab,0xf7,0x2e,0x97,0xa4,0x84,0x54,0x44,0x38,0xb6,0x3b,0xb7,0x1d,0xd9,0x2c,0x96,0x08,0x9c,0x12,0xfc,0xaa,0x77,0x05,0xe6,0x89,0x16,0xb6,0xf3,0x39,0x9b,0x61,0x6f,0x81,0xee,0x44,0x29,0x5f,0x99,0x51,0x34,0x7c,0x7d,0xea,0x9f,0xd0,0xfc,0x52,0x91,0xf6,0x5c,0x93,0xb0,0x94,0x6c,0x81,0x4a,0x40,0x5c,0x28,0x47,0xaa,0x9a,0x8e,0x25,0xb7,0x93,0x28,0x04,0xa6,0x9c,0xb8,0x10}, + {0x9c,0x28,0x18,0x97,0x49,0x47,0x59,0x3d,0x26,0x3f,0x53,0x24,0xc5,0xf8,0xeb,0x12,0x15,0xef,0xc3,0x14,0xcb,0xbf,0x62,0x02,0x8e,0x51,0xb7,0x77,0xd5,0x78,0xb8,0x20,0x6e,0xf0,0x45,0x5a,0xbe,0x41,0x39,0x75,0x65,0x5f,0x9c,0x6d,0xed,0xae,0x7c,0xd0,0xb6,0x51,0xff,0x72,0x9c,0x6b,0x77,0x11,0xa9,0x4d,0x0d,0xef,0xd9,0xd1,0xd2,0x17,0x6a,0x3e,0x3f,0x07,0x18,0xaf,0xf2,0x27,0x69,0x10,0x52,0xd7,0x19,0xe5,0x3f,0xfd,0x22,0x00,0xa6,0x3c,0x2c,0xb7,0xe3,0x22,0xa7,0xc6,0x65,0xcc,0x63,0x4f,0x21,0x72}, + {0x93,0xa6,0x07,0x53,0x40,0x7f,0xe3,0xb4,0x95,0x67,0x33,0x2f,0xd7,0x14,0xa7,0xab,0x99,0x10,0x76,0x73,0xa7,0xd0,0xfb,0xd6,0xc9,0xcb,0x71,0x81,0xc5,0x48,0xdf,0x5f,0xc9,0x29,0x3b,0xf4,0xb9,0xb7,0x9d,0x1d,0x75,0x8f,0x51,0x4f,0x4a,0x82,0x05,0xd6,0xc4,0x9d,0x2f,0x31,0xbd,0x72,0xc0,0xf2,0xb0,0x45,0x15,0x5a,0x85,0xac,0x24,0x1f,0xaa,0x05,0x95,0x8e,0x32,0x08,0xd6,0x24,0xee,0x20,0x14,0x0c,0xd1,0xc1,0x48,0x47,0xa2,0x25,0xfb,0x06,0x5c,0xe4,0xff,0xc7,0xe6,0x95,0xe3,0x2a,0x9e,0x73,0xba,0x00}, + {0xd6,0x90,0x87,0x5c,0xde,0x98,0x2e,0x59,0xdf,0xa2,0xc2,0x45,0xd3,0xb7,0xbf,0xe5,0x22,0x99,0xb4,0xf9,0x60,0x3b,0x5a,0x11,0xf3,0x78,0xad,0x67,0x3e,0x3a,0x28,0x03,0x26,0xbb,0x88,0xea,0xf5,0x26,0x44,0xae,0xfb,0x3b,0x97,0x84,0xd9,0x79,0x06,0x36,0x50,0x4e,0x69,0x26,0x0c,0x03,0x9f,0x5c,0x26,0xd2,0x18,0xd5,0xe7,0x7d,0x29,0x72,0x39,0xb9,0x0c,0xbe,0xc7,0x1d,0x24,0x48,0x80,0x30,0x63,0x8b,0x4d,0x9b,0xf1,0x32,0x08,0x93,0x28,0x02,0x0d,0xc9,0xdf,0xd3,0x45,0x19,0x27,0x46,0x68,0x29,0xe1,0x05}, + {0x5a,0x49,0x9c,0x2d,0xb3,0xee,0x82,0xba,0x7c,0xb9,0x2b,0xf1,0xfc,0xc8,0xef,0xce,0xe0,0xd1,0xb5,0x93,0xae,0xab,0x2d,0xb0,0x9b,0x8d,0x69,0x13,0x9c,0x0c,0xc0,0x39,0x50,0x45,0x2c,0x24,0xc8,0xbb,0xbf,0xad,0xd9,0x81,0x30,0xd0,0xec,0x0c,0xc8,0xbc,0x92,0xdf,0xc8,0xf5,0xa6,0x66,0x35,0x84,0x4c,0xce,0x58,0x82,0xd3,0x25,0xcf,0x78,0x68,0x9d,0x48,0x31,0x8e,0x6b,0xae,0x15,0x87,0xf0,0x2b,0x9c,0xab,0x1c,0x85,0xaa,0x05,0xfa,0x4e,0xf0,0x97,0x5a,0xa7,0xc9,0x32,0xf8,0x3f,0x6b,0x07,0x52,0x6b,0x00}, + {0x1c,0x78,0x95,0x9d,0xe1,0xcf,0xe0,0x29,0xe2,0x10,0x63,0x96,0x18,0xdf,0x81,0xb6,0x39,0x6b,0x51,0x70,0xd3,0x39,0xdf,0x57,0x22,0x61,0xc7,0x3b,0x44,0xe3,0x57,0x4d,0x2d,0x08,0xce,0xb9,0x16,0x7e,0xcb,0xf5,0x29,0xbc,0x7a,0x41,0x4c,0xf1,0x07,0x34,0xab,0xa7,0xf4,0x2b,0xce,0x6b,0xb3,0xd4,0xce,0x75,0x9f,0x1a,0x56,0xe9,0xe2,0x7d,0xcb,0x5e,0xa5,0xb6,0xf4,0xd4,0x70,0xde,0x99,0xdb,0x85,0x5d,0x7f,0x52,0x01,0x48,0x81,0x9a,0xee,0xd3,0x40,0xc4,0xc9,0xdb,0xed,0x29,0x60,0x1a,0xaf,0x90,0x2a,0x6b}, + {0x97,0x1e,0xe6,0x9a,0xfc,0xf4,0x23,0x69,0xd1,0x5f,0x3f,0xe0,0x1d,0x28,0x35,0x57,0x2d,0xd1,0xed,0xe6,0x43,0xae,0x64,0xa7,0x4a,0x3e,0x2d,0xd1,0xe9,0xf4,0xd8,0x5f,0x0a,0xd8,0xb2,0x5b,0x24,0xf3,0xeb,0x77,0x9b,0x07,0xb9,0x2f,0x47,0x1b,0x30,0xd8,0x33,0x73,0xee,0x4c,0xf2,0xe6,0x47,0xc6,0x09,0x21,0x6c,0x27,0xc8,0x12,0x58,0x46,0xd9,0x62,0x10,0x2a,0xb2,0xbe,0x43,0x4d,0x16,0xdc,0x31,0x38,0x75,0xfb,0x65,0x70,0xd7,0x68,0x29,0xde,0x7b,0x4a,0x0d,0x18,0x90,0x67,0xb1,0x1c,0x2b,0x2c,0xb3,0x05}, + {0xfd,0xa8,0x4d,0xd2,0xcc,0x5e,0xc0,0xc8,0x83,0xef,0xdf,0x05,0xac,0x1a,0xcf,0xa1,0x61,0xcd,0xf9,0x7d,0xf2,0xef,0xbe,0xdb,0x99,0x1e,0x47,0x7b,0xa3,0x56,0x55,0x3b,0x95,0x81,0xd5,0x7a,0x2c,0xa4,0xfc,0xf7,0xcc,0xf3,0x33,0x43,0x6e,0x28,0x14,0x32,0x9d,0x97,0x0b,0x34,0x0d,0x9d,0xc2,0xb6,0xe1,0x07,0x73,0x56,0x48,0x1a,0x77,0x31,0x82,0xd4,0x4d,0xe1,0x24,0xc5,0xb0,0x32,0xb6,0xa4,0x2b,0x1a,0x54,0x51,0xb3,0xed,0xf3,0x5a,0x2b,0x28,0x48,0x60,0xd1,0xa3,0xeb,0x36,0x73,0x7a,0xd2,0x79,0xc0,0x4f}, + {0x7f,0x2f,0xbf,0x89,0xb0,0x38,0xc9,0x51,0xa7,0xe9,0xdf,0x02,0x65,0xbd,0x97,0x24,0x53,0xe4,0x80,0x78,0x9c,0xc0,0xff,0xff,0x92,0x8e,0xf9,0xca,0xce,0x67,0x45,0x12,0x0d,0xc5,0x86,0x0c,0x44,0x8b,0x34,0xdc,0x51,0xe6,0x94,0xcc,0xc9,0xcb,0x37,0x13,0xb9,0x3c,0x3e,0x64,0x4d,0xf7,0x22,0x64,0x08,0xcd,0xe3,0xba,0xc2,0x70,0x11,0x24,0xb4,0x73,0xc4,0x0a,0x86,0xab,0xf9,0x3f,0x35,0xe4,0x13,0x01,0xee,0x1d,0x91,0xf0,0xaf,0xc4,0xc6,0xeb,0x60,0x50,0xe7,0x4a,0x0d,0x00,0x87,0x6c,0x96,0x12,0x86,0x3f}, + {0xde,0x0d,0x2a,0x78,0xc9,0x0c,0x9a,0x55,0x85,0x83,0x71,0xea,0xb2,0xcd,0x1d,0x55,0x8c,0x23,0xef,0x31,0x5b,0x86,0x62,0x7f,0x3d,0x61,0x73,0x79,0x76,0xa7,0x4a,0x50,0x13,0x8d,0x04,0x36,0xfa,0xfc,0x18,0x9c,0xdd,0x9d,0x89,0x73,0xb3,0x9d,0x15,0x29,0xaa,0xd0,0x92,0x9f,0x0b,0x35,0x9f,0xdc,0xd4,0x19,0x8a,0x87,0xee,0x7e,0xf5,0x26,0xb1,0xef,0x87,0x56,0xd5,0x2c,0xab,0x0c,0x7b,0xf1,0x7a,0x24,0x62,0xd1,0x80,0x51,0x67,0x24,0x5a,0x4f,0x34,0x5a,0xc1,0x85,0x69,0x30,0xba,0x9d,0x3d,0x94,0x41,0x40}, + {0x96,0xcc,0xeb,0x43,0xba,0xee,0xc0,0xc3,0xaf,0x9c,0xea,0x26,0x9c,0x9c,0x74,0x8d,0xc6,0xcc,0x77,0x1c,0xee,0x95,0xfa,0xd9,0x0f,0x34,0x84,0x76,0xd9,0xa1,0x20,0x14,0xdd,0xaa,0x6c,0xa2,0x43,0x77,0x21,0x4b,0xce,0xb7,0x8a,0x64,0x24,0xb4,0xa6,0x47,0xe3,0xc9,0xfb,0x03,0x7a,0x4f,0x1d,0xcb,0x19,0xd0,0x00,0x98,0x42,0x31,0xd9,0x12,0x4f,0x59,0x37,0xd3,0x99,0x77,0xc6,0x00,0x7b,0xa4,0x3a,0xb2,0x40,0x51,0x3c,0x5e,0x95,0xf3,0x5f,0xe3,0x54,0x28,0x18,0x44,0x12,0xa0,0x59,0x43,0x31,0x92,0x4f,0x1b}, + {0x51,0x09,0x15,0x89,0x9d,0x10,0x5c,0x3e,0x6a,0x69,0xe9,0x2d,0x91,0xfa,0xce,0x39,0x20,0x30,0x5f,0x97,0x3f,0xe4,0xea,0x20,0xae,0x2d,0x13,0x7f,0x2a,0x57,0x9b,0x23,0xb1,0x66,0x98,0xa4,0x30,0x30,0xcf,0x33,0x59,0x48,0x5f,0x21,0xd2,0x73,0x1f,0x25,0xf6,0xf4,0xde,0x51,0x40,0xaa,0x82,0xab,0xf6,0x23,0x9a,0x6f,0xd5,0x91,0xf1,0x5f,0x68,0x90,0x2d,0xac,0x33,0xd4,0x9e,0x81,0x23,0x85,0xc9,0x5f,0x79,0xab,0x83,0x28,0x3d,0xeb,0x93,0x55,0x80,0x72,0x45,0xef,0xcb,0x36,0x8f,0x75,0x6a,0x52,0x0c,0x02}, + {0xbc,0xdb,0xd8,0x9e,0xf8,0x34,0x98,0x77,0x6c,0xa4,0x7c,0xdc,0xf9,0xaa,0xf2,0xc8,0x74,0xb0,0xe1,0xa3,0xdc,0x4c,0x52,0xa9,0x77,0x38,0x31,0x15,0x46,0xcc,0xaa,0x02,0x89,0xcc,0x42,0xf0,0x59,0xef,0x31,0xe9,0xb6,0x4b,0x12,0x8e,0x9d,0x9c,0x58,0x2c,0x97,0x59,0xc7,0xae,0x8a,0xe1,0xc8,0xad,0x0c,0xc5,0x02,0x56,0x0a,0xfe,0x2c,0x45,0xdf,0x77,0x78,0x64,0xa0,0xf7,0xa0,0x86,0x9f,0x7c,0x60,0x0e,0x27,0x64,0xc4,0xbb,0xc9,0x11,0xfb,0xf1,0x25,0xea,0x17,0xab,0x7b,0x87,0x4b,0x30,0x7b,0x7d,0xfb,0x4c}, + {0xfe,0x75,0x9b,0xb8,0x6c,0x3d,0xb4,0x72,0x80,0xdc,0x6a,0x9c,0xd9,0x94,0xc6,0x54,0x9f,0x4c,0xe3,0x3e,0x37,0xaa,0xc3,0xb8,0x64,0x53,0x07,0x39,0x2b,0x62,0xb4,0x14,0x12,0xef,0x89,0x97,0xc2,0x99,0x86,0xe2,0x0d,0x19,0x57,0xdf,0x71,0xcd,0x6e,0x2b,0xd0,0x70,0xc9,0xec,0x57,0xc8,0x43,0xc3,0xc5,0x3a,0x4d,0x43,0xbc,0x4c,0x1d,0x5b,0x26,0x9f,0x0a,0xcc,0x15,0x26,0xfb,0xb6,0xe5,0xcc,0x8d,0xb8,0x2b,0x0e,0x4f,0x3a,0x05,0xa7,0x69,0x33,0x8b,0x49,0x01,0x13,0xd1,0x2d,0x59,0x58,0x12,0xf7,0x98,0x2f}, + {0x56,0x9e,0x0f,0xb5,0x4c,0xa7,0x94,0x0c,0x20,0x13,0x8e,0x8e,0xa9,0xf4,0x1f,0x5b,0x67,0x0f,0x30,0x82,0x21,0xcc,0x2a,0x9a,0xf9,0xaa,0x06,0xd8,0x49,0xe2,0x6a,0x3a,0x01,0xa7,0x54,0x4f,0x44,0xae,0x12,0x2e,0xde,0xd7,0xcb,0xa9,0xf0,0x3e,0xfe,0xfc,0xe0,0x5d,0x83,0x75,0x0d,0x89,0xbf,0xce,0x54,0x45,0x61,0xe7,0xe9,0x62,0x80,0x1d,0x5a,0x7c,0x90,0xa9,0x85,0xda,0x7a,0x65,0x62,0x0f,0xb9,0x91,0xb5,0xa8,0x0e,0x1a,0xe9,0xb4,0x34,0xdf,0xfb,0x1d,0x0e,0x8d,0xf3,0x5f,0xf2,0xae,0xe8,0x8c,0x8b,0x29}, + {0xb2,0x0c,0xf7,0xef,0x53,0x79,0x92,0x2a,0x76,0x70,0x15,0x79,0x2a,0xc9,0x89,0x4b,0x6a,0xcf,0xa7,0x30,0x7a,0x45,0x18,0x94,0x85,0xe4,0x5c,0x4d,0x40,0xa8,0xb8,0x34,0xde,0x65,0x21,0x0a,0xea,0x72,0x7a,0x83,0xf6,0x79,0xcf,0x0b,0xb4,0x07,0xab,0x3f,0x70,0xae,0x38,0x77,0xc7,0x36,0x16,0x52,0xdc,0xd7,0xa7,0x03,0x18,0x27,0xa6,0x6b,0x35,0x33,0x69,0x83,0xb5,0xec,0x6e,0xc2,0xfd,0xfe,0xb5,0x63,0xdf,0x13,0xa8,0xd5,0x73,0x25,0xb2,0xa4,0x9a,0xaa,0x93,0xa2,0x6a,0x1c,0x5e,0x46,0xdd,0x2b,0xd6,0x71}, + {0x80,0xdf,0x78,0xd3,0x28,0xcc,0x33,0x65,0xb4,0xa4,0x0f,0x0a,0x79,0x43,0xdb,0xf6,0x5a,0xda,0x01,0xf7,0xf9,0x5f,0x64,0xe3,0xa4,0x2b,0x17,0xf3,0x17,0xf3,0xd5,0x74,0xf5,0x5e,0xf7,0xb1,0xda,0xb5,0x2d,0xcd,0xf5,0x65,0xb0,0x16,0xcf,0x95,0x7f,0xd7,0x85,0xf0,0x49,0x3f,0xea,0x1f,0x57,0x14,0x3d,0x2b,0x2b,0x26,0x21,0x36,0x33,0x1c,0x81,0xca,0xd9,0x67,0x54,0xe5,0x6f,0xa8,0x37,0x8c,0x29,0x2b,0x75,0x7c,0x8b,0x39,0x3b,0x62,0xac,0xe3,0x92,0x08,0x6d,0xda,0x8c,0xd9,0xe9,0x47,0x45,0xcc,0xeb,0x4a}, + {0xc9,0x01,0x6d,0x27,0x1b,0x07,0xf0,0x12,0x70,0x8c,0xc4,0x86,0xc5,0xba,0xb8,0xe7,0xa9,0xfb,0xd6,0x71,0x9b,0x12,0x08,0x53,0x92,0xb7,0x3d,0x5a,0xf9,0xfb,0x88,0x5d,0x10,0xb6,0x54,0x73,0x9e,0x8d,0x40,0x0b,0x6e,0x5b,0xa8,0x5b,0x53,0x32,0x6b,0x80,0x07,0xa2,0x58,0x4a,0x03,0x3a,0xe6,0xdb,0x2c,0xdf,0xa1,0xc9,0xdd,0xd9,0x3b,0x17,0xdf,0x72,0x58,0xfe,0x1e,0x0f,0x50,0x2b,0xc1,0x18,0x39,0xd4,0x2e,0x58,0xd6,0x58,0xe0,0x3a,0x67,0xc9,0x8e,0x27,0xed,0xe6,0x19,0xa3,0x9e,0xb1,0x13,0xcd,0xe1,0x06}, + {0x23,0x6f,0x16,0x6f,0x51,0xad,0xd0,0x40,0xbe,0x6a,0xab,0x1f,0x93,0x32,0x8e,0x11,0x8e,0x08,0x4d,0xa0,0x14,0x5e,0xe3,0x3f,0x66,0x62,0xe1,0x26,0x35,0x60,0x80,0x30,0x53,0x03,0x5b,0x9e,0x62,0xaf,0x2b,0x47,0x47,0x04,0x8d,0x27,0x90,0x0b,0xaa,0x3b,0x27,0xbf,0x43,0x96,0x46,0x5f,0x78,0x0c,0x13,0x7b,0x83,0x8d,0x1a,0x6a,0x3a,0x7f,0x0b,0x80,0x3d,0x5d,0x39,0x44,0xe6,0xf7,0xf6,0xed,0x01,0xc9,0x55,0xd5,0xa8,0x95,0x39,0x63,0x2c,0x59,0x30,0x78,0xcd,0x68,0x7e,0x30,0x51,0x2e,0xed,0xfd,0xd0,0x30}, + {0xb3,0x33,0x12,0xf2,0x1a,0x4d,0x59,0xe0,0x9c,0x4d,0xcc,0xf0,0x8e,0xe7,0xdb,0x1b,0x77,0x9a,0x49,0x8f,0x7f,0x18,0x65,0x69,0x68,0x98,0x09,0x2c,0x20,0x14,0x92,0x0a,0x50,0x47,0xb8,0x68,0x1e,0x97,0xb4,0x9c,0xcf,0xbb,0x64,0x66,0x29,0x72,0x95,0xa0,0x2b,0x41,0xfa,0x72,0x26,0xe7,0x8d,0x5c,0xd9,0x89,0xc5,0x51,0x43,0x08,0x15,0x46,0x2e,0xa0,0xb9,0xae,0xc0,0x19,0x90,0xbc,0xae,0x4c,0x03,0x16,0x0d,0x11,0xc7,0x55,0xec,0x32,0x99,0x65,0x01,0xf5,0x6d,0x0e,0xfe,0x5d,0xca,0x95,0x28,0x0d,0xca,0x3b}, + {0xa4,0x62,0x5d,0x3c,0xbc,0x31,0xf0,0x40,0x60,0x7a,0xf0,0xcf,0x3e,0x8b,0xfc,0x19,0x45,0xb5,0x0f,0x13,0xa2,0x3d,0x18,0x98,0xcd,0x13,0x8f,0xae,0xdd,0xde,0x31,0x56,0xbf,0x01,0xcc,0x9e,0xb6,0x8e,0x68,0x9c,0x6f,0x89,0x44,0xa6,0xad,0x83,0xbc,0xf0,0xe2,0x9f,0x7a,0x5f,0x5f,0x95,0x2d,0xca,0x41,0x82,0xf2,0x8d,0x03,0xb4,0xa8,0x4e,0x02,0xd2,0xca,0xf1,0x0a,0x46,0xed,0x2a,0x83,0xee,0x8c,0xa4,0x05,0x53,0x30,0x46,0x5f,0x1a,0xf1,0x49,0x45,0x77,0x21,0x91,0x63,0xa4,0x2c,0x54,0x30,0x09,0xce,0x24}, + {0x06,0xc1,0x06,0xfd,0xf5,0x90,0xe8,0x1f,0xf2,0x10,0x88,0x5d,0x35,0x68,0xc4,0xb5,0x3e,0xaf,0x8c,0x6e,0xfe,0x08,0x78,0x82,0x4b,0xd7,0x06,0x8a,0xc2,0xe3,0xd4,0x41,0x85,0x0b,0xf3,0xfd,0x55,0xa1,0xcf,0x3f,0xa4,0x2e,0x37,0x36,0x8e,0x16,0xf7,0xd2,0x44,0xf8,0x92,0x64,0xde,0x64,0xe0,0xb2,0x80,0x42,0x4f,0x32,0xa7,0x28,0x99,0x54,0x2e,0x1a,0xee,0x63,0xa7,0x32,0x6e,0xf2,0xea,0xfd,0x5f,0xd2,0xb7,0xe4,0x91,0xae,0x69,0x4d,0x7f,0xd1,0x3b,0xd3,0x3b,0xbc,0x6a,0xff,0xdc,0xc0,0xde,0x66,0x1b,0x49}, + {0xa7,0x32,0xea,0xc7,0x3d,0xb1,0xf5,0x98,0x98,0xdb,0x16,0x7e,0xcc,0xf8,0xd5,0xe3,0x47,0xd9,0xf8,0xcb,0x52,0xbf,0x0a,0xac,0xac,0xe4,0x5e,0xc8,0xd0,0x38,0xf3,0x08,0xa1,0x64,0xda,0xd0,0x8e,0x4a,0xf0,0x75,0x4b,0x28,0xe2,0x67,0xaf,0x2c,0x22,0xed,0xa4,0x7b,0x7b,0x1f,0x79,0xa3,0x34,0x82,0x67,0x8b,0x01,0xb7,0xb0,0xb8,0xf6,0x4c,0xbd,0x73,0x1a,0x99,0x21,0xa8,0x83,0xc3,0x7a,0x0c,0x32,0xdf,0x01,0xbc,0x27,0xab,0x63,0x70,0x77,0x84,0x1b,0x33,0x3d,0xc1,0x99,0x8a,0x07,0xeb,0x82,0x4a,0x0d,0x53}, + {0x25,0x48,0xf9,0xe1,0x30,0x36,0x4c,0x00,0x5a,0x53,0xab,0x8c,0x26,0x78,0x2d,0x7e,0x8b,0xff,0x84,0xcc,0x23,0x23,0x48,0xc7,0xb9,0x70,0x17,0x10,0x3f,0x75,0xea,0x65,0x9e,0xbf,0x9a,0x6c,0x45,0x73,0x69,0x6d,0x80,0xa8,0x00,0x49,0xfc,0xb2,0x7f,0x25,0x50,0xb8,0xcf,0xc8,0x12,0xf4,0xac,0x2b,0x5b,0xbd,0xbf,0x0c,0xe0,0xe7,0xb3,0x0d,0x63,0x63,0x09,0xe2,0x3e,0xfc,0x66,0x3d,0x6b,0xcb,0xb5,0x61,0x7f,0x2c,0xd6,0x81,0x1a,0x3b,0x44,0x13,0x42,0x04,0xbe,0x0f,0xdb,0xa1,0xe1,0x21,0x19,0xec,0xa4,0x02}, + {0xa2,0xb8,0x24,0x3b,0x9a,0x25,0xe6,0x5c,0xb8,0xa0,0xaf,0x45,0xcc,0x7a,0x57,0xb8,0x37,0x70,0xa0,0x8b,0xe8,0xe6,0xcb,0xcc,0xbf,0x09,0x78,0x12,0x51,0x3c,0x14,0x3d,0x5f,0x79,0xcf,0xf1,0x62,0x61,0xc8,0xf5,0xf2,0x57,0xee,0x26,0x19,0x86,0x8c,0x11,0x78,0x35,0x06,0x1c,0x85,0x24,0x21,0x17,0xcf,0x7f,0x06,0xec,0x5d,0x2b,0xd1,0x36,0x57,0x45,0x15,0x79,0x91,0x27,0x6d,0x12,0x0a,0x3a,0x78,0xfc,0x5c,0x8f,0xe4,0xd5,0xac,0x9b,0x17,0xdf,0xe8,0xb6,0xbd,0x36,0x59,0x28,0xa8,0x5b,0x88,0x17,0xf5,0x2e}, + {0xdc,0xae,0x58,0x8c,0x4e,0x97,0x37,0x46,0xa4,0x41,0xf0,0xab,0xfb,0x22,0xef,0xb9,0x8a,0x71,0x80,0xe9,0x56,0xd9,0x85,0xe1,0xa6,0xa8,0x43,0xb1,0xfa,0x78,0x1b,0x2f,0x51,0x2f,0x5b,0x30,0xfb,0xbf,0xee,0x96,0xb8,0x96,0x95,0x88,0xad,0x38,0xf9,0xd3,0x25,0xdd,0xd5,0x46,0xc7,0x2d,0xf5,0xf0,0x95,0x00,0x3a,0xbb,0x90,0x82,0x96,0x57,0x01,0xe1,0x20,0x0a,0x43,0xb8,0x1a,0xf7,0x47,0xec,0xf0,0x24,0x8d,0x65,0x93,0xf3,0xd1,0xee,0xe2,0x6e,0xa8,0x09,0x75,0xcf,0xe1,0xa3,0x2a,0xdc,0x35,0x3e,0xc4,0x7d}, + {0xc3,0xd9,0x7d,0x88,0x65,0x66,0x96,0x85,0x55,0x53,0xb0,0x4b,0x31,0x9b,0x0f,0xc9,0xb1,0x79,0x20,0xef,0xf8,0x8d,0xe0,0xc6,0x2f,0xc1,0x8c,0x75,0x16,0x20,0xf7,0x7e,0x18,0x97,0x3e,0x27,0x5c,0x2a,0x78,0x5a,0x94,0xfd,0x4e,0x5e,0x99,0xc6,0x76,0x35,0x3e,0x7d,0x23,0x1f,0x05,0xd8,0x2e,0x0f,0x99,0x0a,0xd5,0x82,0x1d,0xb8,0x4f,0x04,0xd9,0xe3,0x07,0xa9,0xc5,0x18,0xdf,0xc1,0x59,0x63,0x4c,0xce,0x1d,0x37,0xb3,0x57,0x49,0xbb,0x01,0xb2,0x34,0x45,0x70,0xca,0x2e,0xdd,0x30,0x9c,0x3f,0x82,0x79,0x7f}, + {0xe8,0x13,0xb5,0xa3,0x39,0xd2,0x34,0x83,0xd8,0xa8,0x1f,0xb9,0xd4,0x70,0x36,0xc1,0x33,0xbd,0x90,0xf5,0x36,0x41,0xb5,0x12,0xb4,0xd9,0x84,0xd7,0x73,0x03,0x4e,0x0a,0xba,0x87,0xf5,0x68,0xf0,0x1f,0x9c,0x6a,0xde,0xc8,0x50,0x00,0x4e,0x89,0x27,0x08,0xe7,0x5b,0xed,0x7d,0x55,0x99,0xbf,0x3c,0xf0,0xd6,0x06,0x1c,0x43,0xb0,0xa9,0x64,0x19,0x29,0x7d,0x5b,0xa1,0xd6,0xb3,0x2e,0x35,0x82,0x3a,0xd5,0xa0,0xf6,0xb4,0xb0,0x47,0x5d,0xa4,0x89,0x43,0xce,0x56,0x71,0x6c,0x34,0x18,0xce,0x0a,0x7d,0x1a,0x07}, + {0x0b,0xba,0x87,0xc8,0xaa,0x2d,0x07,0xd3,0xee,0x62,0xa5,0xbf,0x05,0x29,0x26,0x01,0x8b,0x76,0xef,0xc0,0x02,0x30,0x54,0xcf,0x9c,0x7e,0xea,0x46,0x71,0xcc,0x3b,0x2c,0x31,0x44,0xe1,0x20,0x52,0x35,0x0c,0xcc,0x41,0x51,0xb1,0x09,0x07,0x95,0x65,0x0d,0x36,0x5f,0x9d,0x20,0x1b,0x62,0xf5,0x9a,0xd3,0x55,0x77,0x61,0xf7,0xbc,0x69,0x7c,0x5f,0x29,0xe8,0x04,0xeb,0xd7,0xf0,0x07,0x7d,0xf3,0x50,0x2f,0x25,0x18,0xdb,0x10,0xd7,0x98,0x17,0x17,0xa3,0xa9,0x51,0xe9,0x1d,0xa5,0xac,0x22,0x73,0x9a,0x5a,0x6f}, + {0xc5,0xc6,0x41,0x2f,0x0c,0x00,0xa1,0x8b,0x9b,0xfb,0xfe,0x0c,0xc1,0x79,0x9f,0xc4,0x9f,0x1c,0xc5,0x3c,0x70,0x47,0xfa,0x4e,0xca,0xaf,0x47,0xe1,0xa2,0x21,0x4e,0x49,0xbe,0x44,0xd9,0xa3,0xeb,0xd4,0x29,0xe7,0x9e,0xaf,0x78,0x80,0x40,0x09,0x9e,0x8d,0x03,0x9c,0x86,0x47,0x7a,0x56,0x25,0x45,0x24,0x3b,0x8d,0xee,0x80,0x96,0xab,0x02,0x9a,0x0d,0xe5,0xdd,0x85,0x8a,0xa4,0xef,0x49,0xa2,0xb9,0x0f,0x4e,0x22,0x9a,0x21,0xd9,0xf6,0x1e,0xd9,0x1d,0x1f,0x09,0xfa,0x34,0xbb,0x46,0xea,0xcb,0x76,0x5d,0x6b}, + {0x94,0xd9,0x0c,0xec,0x6c,0x55,0x57,0x88,0xba,0x1d,0xd0,0x5c,0x6f,0xdc,0x72,0x64,0x77,0xb4,0x42,0x8f,0x14,0x69,0x01,0xaf,0x54,0x73,0x27,0x85,0xf6,0x33,0xe3,0x0a,0x22,0x25,0x78,0x1e,0x17,0x41,0xf9,0xe0,0xd3,0x36,0x69,0x03,0x74,0xae,0xe6,0xf1,0x46,0xc7,0xfc,0xd0,0xa2,0x3e,0x8b,0x40,0x3e,0x31,0xdd,0x03,0x9c,0x86,0xfb,0x16,0x62,0x09,0xb6,0x33,0x97,0x19,0x8e,0x28,0x33,0xe1,0xab,0xd8,0xb4,0x72,0xfc,0x24,0x3e,0xd0,0x91,0x09,0xed,0xf7,0x11,0x48,0x75,0xd0,0x70,0x8f,0x8b,0xe3,0x81,0x3f}, + {0xfe,0xaf,0xd9,0x7e,0xcc,0x0f,0x91,0x7f,0x4b,0x87,0x65,0x24,0xa1,0xb8,0x5c,0x54,0x04,0x47,0x0c,0x4b,0xd2,0x7e,0x39,0xa8,0x93,0x09,0xf5,0x04,0xc1,0x0f,0x51,0x50,0x24,0xc8,0x17,0x5f,0x35,0x7f,0xdb,0x0a,0xa4,0x99,0x42,0xd7,0xc3,0x23,0xb9,0x74,0xf7,0xea,0xf8,0xcb,0x8b,0x3e,0x7c,0xd5,0x3d,0xdc,0xde,0x4c,0xd3,0xe2,0xd3,0x0a,0x9d,0x24,0x6e,0x33,0xc5,0x0f,0x0c,0x6f,0xd9,0xcf,0x31,0xc3,0x19,0xde,0x5e,0x74,0x1c,0xfe,0xee,0x09,0x00,0xfd,0xd6,0xf2,0xbe,0x1e,0xfa,0xf0,0x8b,0x15,0x7c,0x12}, + {0xa2,0x79,0x98,0x2e,0x42,0x7c,0x19,0xf6,0x47,0x36,0xca,0x52,0xd4,0xdd,0x4a,0xa4,0xcb,0xac,0x4e,0x4b,0xc1,0x3f,0x41,0x9b,0x68,0x4f,0xef,0x07,0x7d,0xf8,0x4e,0x35,0x74,0xb9,0x51,0xae,0xc4,0x8f,0xa2,0xde,0x96,0xfe,0x4d,0x74,0xd3,0x73,0x99,0x1d,0xa8,0x48,0x38,0x87,0x0b,0x68,0x40,0x62,0x95,0xdf,0x67,0xd1,0x79,0x24,0xd8,0x4e,0x75,0xd9,0xc5,0x60,0x22,0xb5,0xe3,0xfe,0xb8,0xb0,0x41,0xeb,0xfc,0x2e,0x35,0x50,0x3c,0x65,0xf6,0xa9,0x30,0xac,0x08,0x88,0x6d,0x23,0x39,0x05,0xd2,0x92,0x2d,0x30}, + {0x3d,0x28,0xa4,0xbc,0xa2,0xc1,0x13,0x78,0xd9,0x3d,0x86,0xa1,0x91,0xf0,0x62,0xed,0x86,0xfa,0x68,0xc2,0xb8,0xbc,0xc7,0xae,0x4c,0xae,0x1c,0x6f,0xb7,0xd3,0xe5,0x10,0x77,0xf1,0xe0,0xe4,0xb6,0x6f,0xbc,0x2d,0x93,0x6a,0xbd,0xa4,0x29,0xbf,0xe1,0x04,0xe8,0xf6,0x7a,0x78,0xd4,0x66,0x19,0x5e,0x60,0xd0,0x26,0xb4,0x5e,0x5f,0xdc,0x0e,0x67,0x8e,0xda,0x53,0xd6,0xbf,0x53,0x54,0x41,0xf6,0xa9,0x24,0xec,0x1e,0xdc,0xe9,0x23,0x8a,0x57,0x03,0x3b,0x26,0x87,0xbf,0x72,0xba,0x1c,0x36,0x51,0x6c,0xb4,0x45}, + {0xa1,0x7f,0x4f,0x31,0xbf,0x2a,0x40,0xa9,0x50,0xf4,0x8c,0x8e,0xdc,0xf1,0x57,0xe2,0x84,0xbe,0xa8,0x23,0x4b,0xd5,0xbb,0x1d,0x3b,0x71,0xcb,0x6d,0xa3,0xbf,0x77,0x21,0xe4,0xe3,0x7f,0x8a,0xdd,0x4d,0x9d,0xce,0x30,0x0e,0x62,0x76,0x56,0x64,0x13,0xab,0x58,0x99,0x0e,0xb3,0x7b,0x4f,0x59,0x4b,0xdf,0x29,0x12,0x32,0xef,0x0a,0x1c,0x5c,0x8f,0xdb,0x79,0xfa,0xbc,0x1b,0x08,0x37,0xb3,0x59,0x5f,0xc2,0x1e,0x81,0x48,0x60,0x87,0x24,0x83,0x9c,0x65,0x76,0x7a,0x08,0xbb,0xb5,0x8a,0x7d,0x38,0x19,0xe6,0x4a}, + {0x2e,0xa3,0x44,0x53,0xaa,0xf6,0xdb,0x8d,0x78,0x40,0x1b,0xb4,0xb4,0xea,0x88,0x7d,0x60,0x0d,0x13,0x4a,0x97,0xeb,0xb0,0x5e,0x03,0x3e,0xbf,0x17,0x1b,0xd9,0x00,0x1a,0x83,0xfb,0x5b,0x98,0x44,0x7e,0x11,0x61,0x36,0x31,0x96,0x71,0x2a,0x46,0xe0,0xfc,0x4b,0x90,0x25,0xd4,0x48,0x34,0xac,0x83,0x64,0x3d,0xa4,0x5b,0xbe,0x5a,0x68,0x75,0xb2,0xf2,0x61,0xeb,0x33,0x09,0x96,0x6e,0x52,0x49,0xff,0xc9,0xa8,0x0f,0x3d,0x54,0x69,0x65,0xf6,0x7a,0x10,0x75,0x72,0xdf,0xaa,0xe6,0xb0,0x23,0xb6,0x29,0x55,0x13}, + {0x18,0xd5,0xd1,0xad,0xd7,0xdb,0xf0,0x18,0x11,0x1f,0xc1,0xcf,0x88,0x78,0x9f,0x97,0x9b,0x75,0x14,0x71,0xf0,0xe1,0x32,0x87,0x01,0x3a,0xca,0x65,0x1a,0xb8,0xb5,0x79,0xfe,0x83,0x2e,0xe2,0xbc,0x16,0xc7,0xf5,0xc1,0x85,0x09,0xe8,0x19,0xeb,0x2b,0xb4,0xae,0x4a,0x25,0x14,0x37,0xa6,0x9d,0xec,0x13,0xa6,0x90,0x15,0x05,0xea,0x72,0x59,0x11,0x78,0x8f,0xdc,0x20,0xac,0xd4,0x0f,0xa8,0x4f,0x4d,0xac,0x94,0xd2,0x9a,0x9a,0x34,0x04,0x36,0xb3,0x64,0x2d,0x1b,0xc0,0xdb,0x3b,0x5f,0x90,0x95,0x9c,0x7e,0x4f}, + {0x2e,0x30,0x81,0x57,0xbc,0x4b,0x67,0x62,0x0f,0xdc,0xad,0x89,0x39,0x0f,0x52,0xd8,0xc6,0xd9,0xfb,0x53,0xae,0x99,0x29,0x8c,0x4c,0x8e,0x63,0x2e,0xd9,0x3a,0x99,0x31,0xfe,0x99,0x52,0x35,0x3d,0x44,0xc8,0x71,0xd7,0xea,0xeb,0xdb,0x1c,0x3b,0xcd,0x8b,0x66,0x94,0xa4,0xf1,0x9e,0x49,0x92,0x80,0xc8,0xad,0x44,0xa1,0xc4,0xee,0x42,0x19,0x92,0x49,0x23,0xae,0x19,0x53,0xac,0x7d,0x92,0x3e,0xea,0x0c,0x91,0x3d,0x1b,0x2c,0x22,0x11,0x3c,0x25,0x94,0xe4,0x3c,0x55,0x75,0xca,0xf9,0x4e,0x31,0x65,0x0a,0x2a}, + {0xc2,0x27,0xf9,0xf7,0x7f,0x93,0xb7,0x2d,0x35,0xa6,0xd0,0x17,0x06,0x1f,0x74,0xdb,0x76,0xaf,0x55,0x11,0xa2,0xf3,0x82,0x59,0xed,0x2d,0x7c,0x64,0x18,0xe2,0xf6,0x4c,0x3a,0x79,0x1c,0x3c,0xcd,0x1a,0x36,0xcf,0x3b,0xbc,0x35,0x5a,0xac,0xbc,0x9e,0x2f,0xab,0xa6,0xcd,0xa8,0xe9,0x60,0xe8,0x60,0x13,0x1a,0xea,0x6d,0x9b,0xc3,0x5d,0x05,0xb6,0x5b,0x8d,0xc2,0x7c,0x22,0x19,0xb1,0xab,0xff,0x4d,0x77,0xbc,0x4e,0xe2,0x07,0x89,0x2c,0xa3,0xe4,0xce,0x78,0x3c,0xa8,0xb6,0x24,0xaa,0x10,0x77,0x30,0x1a,0x12}, + {0x97,0x4a,0x03,0x9f,0x5e,0x5d,0xdb,0xe4,0x2d,0xbc,0x34,0x30,0x09,0xfc,0x53,0xe1,0xb1,0xd3,0x51,0x95,0x91,0x46,0x05,0x46,0x2d,0xe5,0x40,0x7a,0x6c,0xc7,0x3f,0x33,0xc9,0x83,0x74,0xc7,0x3e,0x71,0x59,0xd6,0xaf,0x96,0x2b,0xb8,0x77,0xe0,0xbf,0x88,0xd3,0xbc,0x97,0x10,0x23,0x28,0x9e,0x28,0x9b,0x3a,0xed,0x6c,0x4a,0xb9,0x7b,0x52,0x2e,0x48,0x5b,0x99,0x2a,0x99,0x3d,0x56,0x01,0x38,0x38,0x6e,0x7c,0xd0,0x05,0x34,0xe5,0xd8,0x64,0x2f,0xde,0x35,0x50,0x48,0xf7,0xa9,0xa7,0x20,0x9b,0x06,0x89,0x6b}, + {0x0d,0x22,0x70,0x62,0x41,0xa0,0x2a,0x81,0x4e,0x5b,0x24,0xf9,0xfa,0x89,0x5a,0x99,0x05,0xef,0x72,0x50,0xce,0xc4,0xad,0xff,0x73,0xeb,0x73,0xaa,0x03,0x21,0xbc,0x23,0x77,0xdb,0xc7,0xb5,0x8c,0xfa,0x82,0x40,0x55,0xc1,0x34,0xc7,0xf8,0x86,0x86,0x06,0x7e,0xa5,0xe7,0xf6,0xd9,0xc8,0xe6,0x29,0xcf,0x9b,0x63,0xa7,0x08,0xd3,0x73,0x04,0x05,0x9e,0x58,0x03,0x26,0x79,0xee,0xca,0x92,0xc4,0xdc,0x46,0x12,0x42,0x4b,0x2b,0x4f,0xa9,0x01,0xe6,0x74,0xef,0xa1,0x02,0x1a,0x34,0x04,0xde,0xbf,0x73,0x2f,0x10}, + {0xc6,0x45,0x57,0x7f,0xab,0xb9,0x18,0xeb,0x90,0xc6,0x87,0x57,0xee,0x8a,0x3a,0x02,0xa9,0xaf,0xf7,0x2d,0xda,0x12,0x27,0xb7,0x3d,0x01,0x5c,0xea,0x25,0x7d,0x59,0x36,0x9a,0x1c,0x51,0xb5,0xe0,0xda,0xb4,0xa2,0x06,0xff,0xff,0x2b,0x29,0x60,0xc8,0x7a,0x34,0x42,0x50,0xf5,0x5d,0x37,0x1f,0x98,0x2d,0xa1,0x4e,0xda,0x25,0xd7,0x6b,0x3f,0xac,0x58,0x60,0x10,0x7b,0x8d,0x4d,0x73,0x5f,0x90,0xc6,0x6f,0x9e,0x57,0x40,0xd9,0x2d,0x93,0x02,0x92,0xf9,0xf8,0x66,0x64,0xd0,0xd6,0x60,0xda,0x19,0xcc,0x7e,0x7b}, + {0x0d,0x69,0x5c,0x69,0x3c,0x37,0xc2,0x78,0x6e,0x90,0x42,0x06,0x66,0x2e,0x25,0xdd,0xd2,0x2b,0xe1,0x4a,0x44,0x44,0x1d,0x95,0x56,0x39,0x74,0x01,0x76,0xad,0x35,0x42,0x9b,0xfa,0x7c,0xa7,0x51,0x4a,0xae,0x6d,0x50,0x86,0xa3,0xe7,0x54,0x36,0x26,0x82,0xdb,0x82,0x2d,0x8f,0xcd,0xff,0xbb,0x09,0xba,0xca,0xf5,0x1b,0x66,0xdc,0xbe,0x03,0xf5,0x75,0x89,0x07,0x0d,0xcb,0x58,0x62,0x98,0xf2,0x89,0x91,0x54,0x42,0x29,0x49,0xe4,0x6e,0xe3,0xe2,0x23,0xb4,0xca,0xa0,0xa1,0x66,0xf0,0xcd,0xb0,0xe2,0x7c,0x0e}, + {0xa3,0x85,0x8c,0xc4,0x3a,0x64,0x94,0xc4,0xad,0x39,0x61,0x3c,0xf4,0x1d,0x36,0xfd,0x48,0x4d,0xe9,0x3a,0xdd,0x17,0xdb,0x09,0x4a,0x67,0xb4,0x8f,0x5d,0x0a,0x6e,0x66,0xf9,0x70,0x4b,0xd9,0xdf,0xfe,0xa6,0xfe,0x2d,0xba,0xfc,0xc1,0x51,0xc0,0x30,0xf1,0x89,0xab,0x2f,0x7f,0x7e,0xd4,0x82,0x48,0xb5,0xee,0xec,0x8a,0x13,0x56,0x52,0x61,0x0d,0xcb,0x70,0x48,0x4e,0xf6,0xbb,0x2a,0x6b,0x8b,0x45,0xaa,0xf0,0xbc,0x65,0xcd,0x5d,0x98,0xe8,0x75,0xba,0x4e,0xbe,0x9a,0xe4,0xde,0x14,0xd5,0x10,0xc8,0x0b,0x7f}, + {0x6f,0x13,0xf4,0x26,0xa4,0x6b,0x00,0xb9,0x35,0x30,0xe0,0x57,0x9e,0x36,0x67,0x8d,0x28,0x3c,0x46,0x4f,0xd9,0xdf,0xc8,0xcb,0xf5,0xdb,0xee,0xf8,0xbc,0x8d,0x1f,0x0d,0xa0,0x13,0x72,0x73,0xad,0x9d,0xac,0x83,0x98,0x2e,0xf7,0x2e,0xba,0xf8,0xf6,0x9f,0x57,0x69,0xec,0x43,0xdd,0x2e,0x1e,0x31,0x75,0xab,0xc5,0xde,0x7d,0x90,0x3a,0x1d,0xdc,0x81,0xd0,0x3e,0x31,0x93,0x16,0xba,0x80,0x34,0x1b,0x85,0xad,0x9f,0x32,0x29,0xcb,0x21,0x03,0x03,0x3c,0x01,0x28,0x01,0xe3,0xfd,0x1b,0xa3,0x44,0x1b,0x01,0x00}, + {0x0c,0x6c,0xc6,0x3f,0x6c,0xa0,0xdf,0x3f,0xd2,0x0d,0xd6,0x4d,0x8e,0xe3,0x40,0x5d,0x71,0x4d,0x8e,0x26,0x38,0x8b,0xe3,0x7a,0xe1,0x57,0x83,0x6e,0x91,0x8d,0xc4,0x3a,0x5c,0xa7,0x0a,0x6a,0x69,0x1f,0x56,0x16,0x6a,0xbd,0x52,0x58,0x5c,0x72,0xbf,0xc1,0xad,0x66,0x79,0x9a,0x7f,0xdd,0xa8,0x11,0x26,0x10,0x85,0xd2,0xa2,0x88,0xd9,0x63,0x2e,0x23,0xbd,0xaf,0x53,0x07,0x12,0x00,0x83,0xf6,0xd8,0xfd,0xb8,0xce,0x2b,0xe9,0x91,0x2b,0xe7,0x84,0xb3,0x69,0x16,0xf8,0x66,0xa0,0x68,0x23,0x2b,0xd5,0xfa,0x33}, + {0x16,0x1e,0xe4,0xc5,0xc6,0x49,0x06,0x54,0x35,0x77,0x3f,0x33,0x30,0x64,0xf8,0x0a,0x46,0xe7,0x05,0xf3,0xd2,0xfc,0xac,0xb2,0xa7,0xdc,0x56,0xa2,0x29,0xf4,0xc0,0x16,0xe8,0xcf,0x22,0xc4,0xd0,0xc8,0x2c,0x8d,0xcb,0x3a,0xa1,0x05,0x7b,0x4f,0x2b,0x07,0x6f,0xa5,0xf6,0xec,0xe6,0xb6,0xfe,0xa3,0xe2,0x71,0x0a,0xb9,0xcc,0x55,0xc3,0x3c,0x31,0x91,0x3e,0x90,0x43,0x94,0xb6,0xe9,0xce,0x37,0x56,0x7a,0xcb,0x94,0xa4,0xb8,0x44,0x92,0xba,0xba,0xa4,0xd1,0x7c,0xc8,0x68,0x75,0xae,0x6b,0x42,0xaf,0x1e,0x63}, + {0x9f,0xfe,0x66,0xda,0x10,0x04,0xe9,0xb3,0xa6,0xe5,0x16,0x6c,0x52,0x4b,0xdd,0x85,0x83,0xbf,0xf9,0x1e,0x61,0x97,0x3d,0xbc,0xb5,0x19,0xa9,0x1e,0x8b,0x64,0x99,0x55,0xe8,0x0d,0x70,0xa3,0xb9,0x75,0xd9,0x47,0x52,0x05,0xf8,0xe2,0xfb,0xc5,0x80,0x72,0xe1,0x5d,0xe4,0x32,0x27,0x8f,0x65,0x53,0xb5,0x80,0x5f,0x66,0x7f,0x2c,0x1f,0x43,0x19,0x7b,0x8f,0x85,0x44,0x63,0x02,0xd6,0x4a,0x51,0xea,0xa1,0x2f,0x35,0xab,0x14,0xd7,0xa9,0x90,0x20,0x1a,0x44,0x00,0x89,0x26,0x3b,0x25,0x91,0x5f,0x71,0x04,0x7b}, + {0x43,0xae,0xf6,0xac,0x28,0xbd,0xed,0x83,0xb4,0x7a,0x5c,0x7d,0x8b,0x7c,0x35,0x86,0x44,0x2c,0xeb,0xb7,0x69,0x47,0x40,0xc0,0x3f,0x58,0xf6,0xc2,0xf5,0x7b,0xb3,0x59,0xc6,0xba,0xe6,0xc4,0x80,0xc2,0x76,0xb3,0x0b,0x9b,0x1d,0x6d,0xdd,0xd3,0x0e,0x97,0x44,0xf9,0x0b,0x45,0x58,0x95,0x9a,0xb0,0x23,0xe2,0xcd,0x57,0xfa,0xac,0xd0,0x48,0x71,0xe6,0xab,0x7d,0xe4,0x26,0x0f,0xb6,0x37,0x3a,0x2f,0x62,0x97,0xa1,0xd1,0xf1,0x94,0x03,0x96,0xe9,0x7e,0xce,0x08,0x42,0xdb,0x3b,0x6d,0x33,0x91,0x41,0x23,0x16}, + {0xf6,0x7f,0x26,0xf6,0xde,0x99,0xe4,0xb9,0x43,0x08,0x2c,0x74,0x7b,0xca,0x72,0x77,0xb1,0xf2,0xa4,0xe9,0x3f,0x15,0xa0,0x23,0x06,0x50,0xd0,0xd5,0xec,0xdf,0xdf,0x2c,0x40,0x86,0xf3,0x1f,0xd6,0x9c,0x49,0xdd,0xa0,0x25,0x36,0x06,0xc3,0x9b,0xcd,0x29,0xc3,0x3d,0xd7,0x3d,0x02,0xd8,0xe2,0x51,0x31,0x92,0x3b,0x20,0x7a,0x70,0x25,0x4a,0x6a,0xed,0xf6,0x53,0x8a,0x66,0xb7,0x2a,0xa1,0x70,0xd1,0x1d,0x58,0x42,0x42,0x30,0x61,0x01,0xe2,0x3a,0x4c,0x14,0x00,0x40,0xfc,0x49,0x8e,0x24,0x6d,0x89,0x21,0x57}, + {0xae,0x1b,0x18,0xfd,0x17,0x55,0x6e,0x0b,0xb4,0x63,0xb9,0x2b,0x9f,0x62,0x22,0x90,0x25,0x46,0x06,0x32,0xe9,0xbc,0x09,0x55,0xda,0x13,0x3c,0xf6,0x74,0xdd,0x8e,0x57,0x4e,0xda,0xd0,0xa1,0x91,0x50,0x5d,0x28,0x08,0x3e,0xfe,0xb5,0xa7,0x6f,0xaa,0x4b,0xb3,0x93,0x93,0xe1,0x7c,0x17,0xe5,0x63,0xfd,0x30,0xb0,0xc4,0xaf,0x35,0xc9,0x03,0x3d,0x0c,0x2b,0x49,0xc6,0x76,0x72,0x99,0xfc,0x05,0xe2,0xdf,0xc4,0xc2,0xcc,0x47,0x3c,0x3a,0x62,0xdd,0x84,0x9b,0xd2,0xdc,0xa2,0xc7,0x88,0x02,0x59,0xab,0xc2,0x3e}, + {0xb9,0x7b,0xd8,0xe4,0x7b,0xd2,0xa0,0xa1,0xed,0x1a,0x39,0x61,0xeb,0x4d,0x8b,0xa9,0x83,0x9b,0xcb,0x73,0xd0,0xdd,0xa0,0x99,0xce,0xca,0x0f,0x20,0x5a,0xc2,0xd5,0x2d,0xcb,0xd1,0x32,0xae,0x09,0x3a,0x21,0xa7,0xd5,0xc2,0xf5,0x40,0xdf,0x87,0x2b,0x0f,0x29,0xab,0x1e,0xe8,0xc6,0xa4,0xae,0x0b,0x5e,0xac,0xdb,0x6a,0x6c,0xf6,0x1b,0x0e,0x7e,0x88,0x2c,0x79,0xe9,0xd5,0xab,0xe2,0x5d,0x6d,0x92,0xcb,0x18,0x00,0x02,0x1a,0x1e,0x5f,0xae,0xba,0xcd,0x69,0xba,0xbf,0x5f,0x8f,0xe8,0x5a,0xb3,0x48,0x05,0x73}, + {0xee,0xb8,0xa8,0xcb,0xa3,0x51,0x35,0xc4,0x16,0x5f,0x11,0xb2,0x1d,0x6f,0xa2,0x65,0x50,0x38,0x8c,0xab,0x52,0x4f,0x0f,0x76,0xca,0xb8,0x1d,0x41,0x3b,0x44,0x43,0x30,0x34,0xe3,0xd6,0xa1,0x4b,0x09,0x5b,0x80,0x19,0x3f,0x35,0x09,0x77,0xf1,0x3e,0xbf,0x2b,0x70,0x22,0x06,0xcb,0x06,0x3f,0x42,0xdd,0x45,0x78,0xd8,0x77,0x22,0x5a,0x58,0x62,0x89,0xd4,0x33,0x82,0x5f,0x8a,0xa1,0x7f,0x25,0x78,0xec,0xb5,0xc4,0x98,0x66,0xff,0x41,0x3e,0x37,0xa5,0x6f,0x8e,0xa7,0x1f,0x98,0xef,0x50,0x89,0x27,0x56,0x76}, + {0xc0,0xc8,0x1f,0xd5,0x59,0xcf,0xc3,0x38,0xf2,0xb6,0x06,0x05,0xfd,0xd2,0xed,0x9b,0x8f,0x0e,0x57,0xab,0x9f,0x10,0xbf,0x26,0xa6,0x46,0xb8,0xc1,0xa8,0x60,0x41,0x3f,0x9d,0xcf,0x86,0xea,0xa3,0x73,0x70,0xe1,0xdc,0x5f,0x15,0x07,0xb7,0xfb,0x8c,0x3a,0x8e,0x8a,0x83,0x31,0xfc,0xe7,0x53,0x48,0x16,0xf6,0x13,0xb6,0x84,0xf4,0xbb,0x28,0x7c,0x6c,0x13,0x6f,0x5c,0x2f,0x61,0xf2,0xbe,0x11,0xdd,0xf6,0x07,0xd1,0xea,0xaf,0x33,0x6f,0xde,0x13,0xd2,0x9a,0x7e,0x52,0x5d,0xf7,0x88,0x81,0x35,0xcb,0x79,0x1e}, + {0xf1,0xe3,0xf7,0xee,0xc3,0x36,0x34,0x01,0xf8,0x10,0x9e,0xfe,0x7f,0x6a,0x8b,0x82,0xfc,0xde,0xf9,0xbc,0xe5,0x08,0xf9,0x7f,0x31,0x38,0x3b,0x3a,0x1b,0x95,0xd7,0x65,0x81,0x81,0xe0,0xf5,0xd8,0x53,0xe9,0x77,0xd9,0xde,0x9d,0x29,0x44,0x0c,0xa5,0x84,0xe5,0x25,0x45,0x86,0x0c,0x2d,0x6c,0xdc,0xf4,0xf2,0xd1,0x39,0x2d,0xb5,0x8a,0x47,0x59,0xd1,0x52,0x92,0xd3,0xa4,0xa6,0x66,0x07,0xc8,0x1a,0x87,0xbc,0xe1,0xdd,0xe5,0x6f,0xc9,0xc1,0xa6,0x40,0x6b,0x2c,0xb8,0x14,0x22,0x21,0x1a,0x41,0x7a,0xd8,0x16}, + {0x15,0x62,0x06,0x42,0x5a,0x7e,0xbd,0xb3,0xc1,0x24,0x5a,0x0c,0xcd,0xe3,0x9b,0x87,0xb7,0x94,0xf9,0xd6,0xb1,0x5d,0xc0,0x57,0xa6,0x8c,0xf3,0x65,0x81,0x7c,0xf8,0x28,0x83,0x05,0x4e,0xd5,0xe2,0xd5,0xa4,0xfb,0xfa,0x99,0xbd,0x2e,0xd7,0xaf,0x1f,0xe2,0x8f,0x77,0xe9,0x6e,0x73,0xc2,0x7a,0x49,0xde,0x6d,0x5a,0x7a,0x57,0x0b,0x99,0x1f,0xd6,0xf7,0xe8,0x1b,0xad,0x4e,0x34,0xa3,0x8f,0x79,0xea,0xac,0xeb,0x50,0x1e,0x7d,0x52,0xe0,0x0d,0x52,0x9e,0x56,0xc6,0x77,0x3e,0x6d,0x4d,0x53,0xe1,0x2f,0x88,0x45}, + {0xd6,0x83,0x79,0x75,0x5d,0x34,0x69,0x66,0xa6,0x11,0xaa,0x17,0x11,0xed,0xb6,0x62,0x8f,0x12,0x5e,0x98,0x57,0x18,0xdd,0x7d,0xdd,0xf6,0x26,0xf6,0xb8,0xe5,0x8f,0x68,0xe4,0x6f,0x3c,0x94,0x29,0x99,0xac,0xd8,0xa2,0x92,0x83,0xa3,0x61,0xf1,0xf9,0xb5,0xf3,0x9a,0xc8,0xbe,0x13,0xdb,0x99,0x26,0x74,0xf0,0x05,0xe4,0x3c,0x84,0xcf,0x7d,0xc0,0x32,0x47,0x4a,0x48,0xd6,0x90,0x6c,0x99,0x32,0x56,0xca,0xfd,0x43,0x21,0xd5,0xe1,0xc6,0x5d,0x91,0xc3,0x28,0xbe,0xb3,0x1b,0x19,0x27,0x73,0x7e,0x68,0x39,0x67}, + {0xa6,0x75,0x56,0x38,0x14,0x20,0x78,0xef,0xe8,0xa9,0xfd,0xaa,0x30,0x9f,0x64,0xa2,0xcb,0xa8,0xdf,0x5c,0x50,0xeb,0xd1,0x4c,0xb3,0xc0,0x4d,0x1d,0xba,0x5a,0x11,0x46,0xc0,0x1a,0x0c,0xc8,0x9d,0xcc,0x6d,0xa6,0x36,0xa4,0x38,0x1b,0xf4,0x5c,0xa0,0x97,0xc6,0xd7,0xdb,0x95,0xbe,0xf3,0xeb,0xa7,0xab,0x7d,0x7e,0x8d,0xf6,0xb8,0xa0,0x7d,0x76,0xda,0xb5,0xc3,0x53,0x19,0x0f,0xd4,0x9b,0x9e,0x11,0x21,0x73,0x6f,0xac,0x1d,0x60,0x59,0xb2,0xfe,0x21,0x60,0xcc,0x03,0x4b,0x4b,0x67,0x83,0x7e,0x88,0x5f,0x5a}, + {0x11,0x3d,0xa1,0x70,0xcf,0x01,0x63,0x8f,0xc4,0xd0,0x0d,0x35,0x15,0xb8,0xce,0xcf,0x7e,0xa4,0xbc,0xa4,0xd4,0x97,0x02,0xf7,0x34,0x14,0x4d,0xe4,0x56,0xb6,0x69,0x36,0xb9,0x43,0xa6,0xa0,0xd3,0x28,0x96,0x9e,0x64,0x20,0xc3,0xe6,0x00,0xcb,0xc3,0xb5,0x32,0xec,0x2d,0x7c,0x89,0x02,0x53,0x9b,0x0c,0xc7,0xd1,0xd5,0xe2,0x7a,0xe3,0x43,0x33,0xe1,0xa6,0xed,0x06,0x3f,0x7e,0x38,0xc0,0x3a,0xa1,0x99,0x51,0x1d,0x30,0x67,0x11,0x38,0x26,0x36,0xf8,0xd8,0x5a,0xbd,0xbe,0xe9,0xd5,0x4f,0xcd,0xe6,0x21,0x6a}, + {0x5f,0xe6,0x46,0x30,0x0a,0x17,0xc6,0xf1,0x24,0x35,0xd2,0x00,0x2a,0x2a,0x71,0x58,0x55,0xb7,0x82,0x8c,0x3c,0xbd,0xdb,0x69,0x57,0xff,0x95,0xa1,0xf1,0xf9,0x6b,0x58,0xe3,0xb2,0x99,0x66,0x12,0x29,0x41,0xef,0x01,0x13,0x8d,0x70,0x47,0x08,0xd3,0x71,0xbd,0xb0,0x82,0x11,0xd0,0x32,0x54,0x32,0x36,0x8b,0x1e,0x00,0x07,0x1b,0x37,0x45,0x0b,0x79,0xf8,0x5e,0x8d,0x08,0xdb,0xa6,0xe5,0x37,0x09,0x61,0xdc,0xf0,0x78,0x52,0xb8,0x6e,0xa1,0x61,0xd2,0x49,0x03,0xac,0x79,0x21,0xe5,0x90,0x37,0xb0,0xaf,0x0e}, + {0x2f,0x04,0x48,0x37,0xc1,0x55,0x05,0x96,0x11,0xaa,0x0b,0x82,0xe6,0x41,0x9a,0x21,0x0c,0x6d,0x48,0x73,0x38,0xf7,0x81,0x1c,0x61,0xc6,0x02,0x5a,0x67,0xcc,0x9a,0x30,0x1d,0xae,0x75,0x0f,0x5e,0x80,0x40,0x51,0x30,0xcc,0x62,0x26,0xe3,0xfb,0x02,0xec,0x6d,0x39,0x92,0xea,0x1e,0xdf,0xeb,0x2c,0xb3,0x5b,0x43,0xc5,0x44,0x33,0xae,0x44,0xee,0x43,0xa5,0xbb,0xb9,0x89,0xf2,0x9c,0x42,0x71,0xc9,0x5a,0x9d,0x0e,0x76,0xf3,0xaa,0x60,0x93,0x4f,0xc6,0xe5,0x82,0x1d,0x8f,0x67,0x94,0x7f,0x1b,0x22,0xd5,0x62}, + {0x6d,0x93,0xd0,0x18,0x9c,0x29,0x4c,0x52,0x0c,0x1a,0x0c,0x8a,0x6c,0xb5,0x6b,0xc8,0x31,0x86,0x4a,0xdb,0x2e,0x05,0x75,0xa3,0x62,0x45,0x75,0xbc,0xe4,0xfd,0x0e,0x5c,0x3c,0x7a,0xf7,0x3a,0x26,0xd4,0x85,0x75,0x4d,0x14,0xe9,0xfe,0x11,0x7b,0xae,0xdf,0x3d,0x19,0xf7,0x59,0x80,0x70,0x06,0xa5,0x37,0x20,0x92,0x83,0x53,0x9a,0xf2,0x14,0xf5,0xd7,0xb2,0x25,0xdc,0x7e,0x71,0xdf,0x40,0x30,0xb5,0x99,0xdb,0x70,0xf9,0x21,0x62,0x4c,0xed,0xc3,0xb7,0x34,0x92,0xda,0x3e,0x09,0xee,0x7b,0x5c,0x36,0x72,0x5e}, + {0x7f,0x21,0x71,0x45,0x07,0xfc,0x5b,0x57,0x5b,0xd9,0x94,0x06,0x5d,0x67,0x79,0x37,0x33,0x1e,0x19,0xf4,0xbb,0x37,0x0a,0x9a,0xbc,0xea,0xb4,0x47,0x4c,0x10,0xf1,0x77,0x3e,0xb3,0x08,0x2f,0x06,0x39,0x93,0x7d,0xbe,0x32,0x9f,0xdf,0xe5,0x59,0x96,0x5b,0xfd,0xbd,0x9e,0x1f,0xad,0x3d,0xff,0xac,0xb7,0x49,0x73,0xcb,0x55,0x05,0xb2,0x70,0x4c,0x2c,0x11,0x55,0xc5,0x13,0x51,0xbe,0xcd,0x1f,0x88,0x9a,0x3a,0x42,0x88,0x66,0x47,0x3b,0x50,0x5e,0x85,0x77,0x66,0x44,0x4a,0x40,0x06,0x4a,0x8f,0x39,0x34,0x0e}, + {0xe8,0xbd,0xce,0x3e,0xd9,0x22,0x7d,0xb6,0x07,0x2f,0x82,0x27,0x41,0xe8,0xb3,0x09,0x8d,0x6d,0x5b,0xb0,0x1f,0xa6,0x3f,0x74,0x72,0x23,0x36,0x8a,0x36,0x05,0x54,0x5e,0x28,0x19,0x4b,0x3e,0x09,0x0b,0x93,0x18,0x40,0xf6,0xf3,0x73,0x0e,0xe1,0xe3,0x7d,0x6f,0x5d,0x39,0x73,0xda,0x17,0x32,0xf4,0x3e,0x9c,0x37,0xca,0xd6,0xde,0x8a,0x6f,0x9a,0xb2,0xb7,0xfd,0x3d,0x12,0x40,0xe3,0x91,0xb2,0x1a,0xa2,0xe1,0x97,0x7b,0x48,0x9e,0x94,0xe6,0xfd,0x02,0x7d,0x96,0xf9,0x97,0xde,0xd3,0xc8,0x2e,0xe7,0x0d,0x78}, + {0xbc,0xe7,0x9a,0x08,0x45,0x85,0xe2,0x0a,0x06,0x4d,0x7f,0x1c,0xcf,0xde,0x8d,0x38,0xb8,0x11,0x48,0x0a,0x51,0x15,0xac,0x38,0xe4,0x8c,0x92,0x71,0xf6,0x8b,0xb2,0x0e,0x72,0x27,0xf4,0x00,0xf3,0xea,0x1f,0x67,0xaa,0x41,0x8c,0x2a,0x2a,0xeb,0x72,0x8f,0x92,0x32,0x37,0x97,0xd7,0x7f,0xa1,0x29,0xa6,0x87,0xb5,0x32,0xad,0xc6,0xef,0x1d,0xa7,0x95,0x51,0xef,0x1a,0xbe,0x5b,0xaf,0xed,0x15,0x7b,0x91,0x77,0x12,0x8c,0x14,0x2e,0xda,0xe5,0x7a,0xfb,0xf7,0x91,0x29,0x67,0x28,0xdd,0xf8,0x1b,0x20,0x7d,0x46}, + {0xad,0x4f,0xef,0x74,0x9a,0x91,0xfe,0x95,0xa2,0x08,0xa3,0xf6,0xec,0x7b,0x82,0x3a,0x01,0x7b,0xa4,0x09,0xd3,0x01,0x4e,0x96,0x97,0xc7,0xa3,0x5b,0x4f,0x3c,0xc4,0x71,0xa9,0xe7,0x7a,0x56,0xbd,0xf4,0x1e,0xbc,0xbd,0x98,0x44,0xd6,0xb2,0x4c,0x62,0x3f,0xc8,0x4e,0x1f,0x2c,0xd2,0x64,0x10,0xe4,0x01,0x40,0x38,0xba,0xa5,0xc5,0xf9,0x2e,0xcd,0x74,0x9e,0xfa,0xf6,0x6d,0xfd,0xb6,0x7a,0x26,0xaf,0xe4,0xbc,0x78,0x82,0xf1,0x0e,0x99,0xef,0xf1,0xd0,0xb3,0x55,0x82,0x93,0xf2,0xc5,0x90,0xa3,0x8c,0x75,0x5a}, + {0x95,0x24,0x46,0xd9,0x10,0x27,0xb7,0xa2,0x03,0x50,0x7d,0xd5,0xd2,0xc6,0xa8,0x3a,0xca,0x87,0xb4,0xa0,0xbf,0x00,0xd4,0xe3,0xec,0x72,0xeb,0xb3,0x44,0xe2,0xba,0x2d,0x94,0xdc,0x61,0x1d,0x8b,0x91,0xe0,0x8c,0x66,0x30,0x81,0x9a,0x46,0x36,0xed,0x8d,0xd3,0xaa,0xe8,0xaf,0x29,0xa8,0xe6,0xd4,0x3f,0xd4,0x39,0xf6,0x27,0x80,0x73,0x0a,0xcc,0xe1,0xff,0x57,0x2f,0x4a,0x0f,0x98,0x43,0x98,0x83,0xe1,0x0d,0x0d,0x67,0x00,0xfd,0x15,0xfb,0x49,0x4a,0x3f,0x5c,0x10,0x9c,0xa6,0x26,0x51,0x63,0xca,0x98,0x26}, + {0x78,0xba,0xb0,0x32,0x88,0x31,0x65,0xe7,0x8b,0xff,0x5c,0x92,0xf7,0x31,0x18,0x38,0xcc,0x1f,0x29,0xa0,0x91,0x1b,0xa8,0x08,0x07,0xeb,0xca,0x49,0xcc,0x3d,0xb4,0x1f,0x0e,0xd9,0x3d,0x5e,0x2f,0x70,0x3d,0x2e,0x86,0x53,0xd2,0xe4,0x18,0x09,0x3f,0x9e,0x6a,0xa9,0x4d,0x02,0xf6,0x3e,0x77,0x5e,0x32,0x33,0xfa,0x4a,0x0c,0x4b,0x00,0x3c,0x2b,0xb8,0xf4,0x06,0xac,0x46,0xa9,0x9a,0xf3,0xc4,0x06,0xa8,0xa5,0x84,0xa2,0x1c,0x87,0x47,0xcd,0xc6,0x5f,0x26,0xd3,0x3e,0x17,0xd2,0x1f,0xcd,0x01,0xfd,0x43,0x6b}, + {0x44,0xc5,0x97,0x46,0x4b,0x5d,0xa7,0xc7,0xbf,0xff,0x0f,0xdf,0x48,0xf8,0xfd,0x15,0x5a,0x78,0x46,0xaa,0xeb,0xb9,0x68,0x28,0x14,0xf7,0x52,0x5b,0x10,0xd7,0x68,0x5a,0xf3,0x0e,0x76,0x3e,0x58,0x42,0xc7,0xb5,0x90,0xb9,0x0a,0xee,0xb9,0x52,0xdc,0x75,0x3f,0x92,0x2b,0x07,0xc2,0x27,0x14,0xbf,0xf0,0xd9,0xf0,0x6f,0x2d,0x0b,0x42,0x73,0x06,0x1e,0x85,0x9e,0xcb,0xf6,0x2c,0xaf,0xc4,0x38,0x22,0xc6,0x13,0x39,0x59,0x8f,0x73,0xf3,0xfb,0x99,0x96,0xb8,0x8a,0xda,0x9e,0xbc,0x34,0xea,0x2f,0x63,0xb5,0x3d}, + {0xd8,0xd9,0x5d,0xf7,0x2b,0xee,0x6e,0xf4,0xa5,0x59,0x67,0x39,0xf6,0xb1,0x17,0x0d,0x73,0x72,0x9e,0x49,0x31,0xd1,0xf2,0x1b,0x13,0x5f,0xd7,0x49,0xdf,0x1a,0x32,0x04,0xd5,0x25,0x98,0x82,0xb1,0x90,0x49,0x2e,0x91,0x89,0x9a,0x3e,0x87,0xeb,0xea,0xed,0xf8,0x4a,0x70,0x4c,0x39,0x3d,0xf0,0xee,0x0e,0x2b,0xdf,0x95,0xa4,0x7e,0x19,0x59,0xae,0x5a,0xe5,0xe4,0x19,0x60,0xe1,0x04,0xe9,0x92,0x2f,0x7e,0x7a,0x43,0x7b,0xe7,0xa4,0x9a,0x15,0x6f,0xc1,0x2d,0xce,0xc7,0xc0,0x0c,0xd7,0xf4,0xc1,0xfd,0xea,0x45}, + {0x2b,0xd7,0x45,0x80,0x85,0x01,0x84,0x69,0x51,0x06,0x2f,0xcf,0xa2,0xfa,0x22,0x4c,0xc6,0x2d,0x22,0x6b,0x65,0x36,0x1a,0x94,0xde,0xda,0x62,0x03,0xc8,0xeb,0x5e,0x5a,0xed,0xb1,0xcc,0xcf,0x24,0x46,0x0e,0xb6,0x95,0x03,0x5c,0xbd,0x92,0xc2,0xdb,0x59,0xc9,0x81,0x04,0xdc,0x1d,0x9d,0xa0,0x31,0x40,0xd9,0x56,0x5d,0xea,0xce,0x73,0x3f,0xc6,0x8d,0x4e,0x0a,0xd1,0xbf,0xa7,0xb7,0x39,0xb3,0xc9,0x44,0x7e,0x00,0x57,0xbe,0xfa,0xae,0x57,0x15,0x7f,0x20,0xc1,0x60,0xdb,0x18,0x62,0x26,0x91,0x88,0x05,0x26}, + {0x04,0xff,0x60,0x83,0xa6,0x04,0xf7,0x59,0xf4,0xe6,0x61,0x76,0xde,0x3f,0xd9,0xc3,0x51,0x35,0x87,0x12,0x73,0x2a,0x1b,0x83,0x57,0x5d,0x61,0x4e,0x2e,0x0c,0xad,0x54,0x42,0xe5,0x76,0xc6,0x3c,0x8e,0x81,0x4c,0xad,0xcc,0xce,0x03,0x93,0x2c,0x42,0x5e,0x08,0x9f,0x12,0xb4,0xca,0xcc,0x07,0xec,0xb8,0x43,0x44,0xb2,0x10,0xfa,0xed,0x0d,0x2a,0x52,0x2b,0xb8,0xd5,0x67,0x3b,0xee,0xeb,0xc1,0xa5,0x9f,0x46,0x63,0xf1,0x36,0xd3,0x9f,0xc1,0x6e,0xf2,0xd2,0xb4,0xa5,0x08,0x94,0x7a,0xa7,0xba,0xb2,0xec,0x62}, + {0x3d,0x2b,0x15,0x61,0x52,0x79,0xed,0xe5,0xd1,0xd7,0xdd,0x0e,0x7d,0x35,0x62,0x49,0x71,0x4c,0x6b,0xb9,0xd0,0xc8,0x82,0x74,0xbe,0xd8,0x66,0xa9,0x19,0xf9,0x59,0x2e,0x74,0x28,0xb6,0xaf,0x36,0x28,0x07,0x92,0xa5,0x04,0xe1,0x79,0x85,0x5e,0xcd,0x5f,0x4a,0xa1,0x30,0xc6,0xad,0x01,0xad,0x5a,0x98,0x3f,0x66,0x75,0x50,0x3d,0x91,0x61,0xda,0x31,0x32,0x1a,0x36,0x2d,0xc6,0x0d,0x70,0x02,0x20,0x94,0x32,0x58,0x47,0xfa,0xce,0x94,0x95,0x3f,0x51,0x01,0xd8,0x02,0x5c,0x5d,0xc0,0x31,0xa1,0xc2,0xdb,0x3d}, + {0x4b,0xc5,0x5e,0xce,0xf9,0x0f,0xdc,0x9a,0x0d,0x13,0x2f,0x8c,0x6b,0x2a,0x9c,0x03,0x15,0x95,0xf8,0xf0,0xc7,0x07,0x80,0x02,0x6b,0xb3,0x04,0xac,0x14,0x83,0x96,0x78,0x14,0xbb,0x96,0x27,0xa2,0x57,0xaa,0xf3,0x21,0xda,0x07,0x9b,0xb7,0xba,0x3a,0x88,0x1c,0x39,0xa0,0x31,0x18,0xe2,0x4b,0xe5,0xf9,0x05,0x32,0xd8,0x38,0xfb,0xe7,0x5e,0x8e,0x6a,0x44,0x41,0xcb,0xfd,0x8d,0x53,0xf9,0x37,0x49,0x43,0xa9,0xfd,0xac,0xa5,0x78,0x8c,0x3c,0x26,0x8d,0x90,0xaf,0x46,0x09,0x0d,0xca,0x9b,0x3c,0x63,0xd0,0x61}, + {0x66,0x25,0xdb,0xff,0x35,0x49,0x74,0x63,0xbb,0x68,0x0b,0x78,0x89,0x6b,0xbd,0xc5,0x03,0xec,0x3e,0x55,0x80,0x32,0x1b,0x6f,0xf5,0xd7,0xae,0x47,0xd8,0x5f,0x96,0x6e,0xdf,0x73,0xfc,0xf8,0xbc,0x28,0xa3,0xad,0xfc,0x37,0xf0,0xa6,0x5d,0x69,0x84,0xee,0x09,0xa9,0xc2,0x38,0xdb,0xb4,0x7f,0x63,0xdc,0x7b,0x06,0xf8,0x2d,0xac,0x23,0x5b,0x7b,0x52,0x80,0xee,0x53,0xb9,0xd2,0x9a,0x8d,0x6d,0xde,0xfa,0xaa,0x19,0x8f,0xe8,0xcf,0x82,0x0e,0x15,0x04,0x17,0x71,0x0e,0xdc,0xde,0x95,0xdd,0xb9,0xbb,0xb9,0x79}, + {0xc2,0x26,0x31,0x6a,0x40,0x55,0xb3,0xeb,0x93,0xc3,0xc8,0x68,0xa8,0x83,0x63,0xd2,0x82,0x7a,0xb9,0xe5,0x29,0x64,0x0c,0x6c,0x47,0x21,0xfd,0xc9,0x58,0xf1,0x65,0x50,0x74,0x73,0x9f,0x8e,0xae,0x7d,0x99,0xd1,0x16,0x08,0xbb,0xcf,0xf8,0xa2,0x32,0xa0,0x0a,0x5f,0x44,0x6d,0x12,0xba,0x6c,0xcd,0x34,0xb8,0xcc,0x0a,0x46,0x11,0xa8,0x1b,0x54,0x99,0x42,0x0c,0xfb,0x69,0x81,0x70,0x67,0xcf,0x6e,0xd7,0xac,0x00,0x46,0xe1,0xba,0x45,0xe6,0x70,0x8a,0xb9,0xaa,0x2e,0xf2,0xfa,0xa4,0x58,0x9e,0xf3,0x81,0x39}, + {0x93,0x0a,0x23,0x59,0x75,0x8a,0xfb,0x18,0x5d,0xf4,0xe6,0x60,0x69,0x8f,0x16,0x1d,0xb5,0x3c,0xa9,0x14,0x45,0xa9,0x85,0x3a,0xfd,0xd0,0xac,0x05,0x37,0x08,0xdc,0x38,0xde,0x6f,0xe6,0x6d,0xa5,0xdf,0x45,0xc8,0x3a,0x48,0x40,0x2c,0x00,0xa5,0x52,0xe1,0x32,0xf6,0xb4,0xc7,0x63,0xe1,0xd2,0xe9,0x65,0x1b,0xbc,0xdc,0x2e,0x45,0xf4,0x30,0x40,0x97,0x75,0xc5,0x82,0x27,0x6d,0x85,0xcc,0xbe,0x9c,0xf9,0x69,0x45,0x13,0xfa,0x71,0x4e,0xea,0xc0,0x73,0xfc,0x44,0x88,0x69,0x24,0x3f,0x59,0x1a,0x9a,0x2d,0x63}, + {0xa6,0xcb,0x07,0xb8,0x15,0x6b,0xbb,0xf6,0xd7,0xf0,0x54,0xbc,0xdf,0xc7,0x23,0x18,0x0b,0x67,0x29,0x6e,0x03,0x97,0x1d,0xbb,0x57,0x4a,0xed,0x47,0x88,0xf4,0x24,0x0b,0xa7,0x84,0x0c,0xed,0x11,0xfd,0x09,0xbf,0x3a,0x69,0x9f,0x0d,0x81,0x71,0xf0,0x63,0x79,0x87,0xcf,0x57,0x2d,0x8c,0x90,0x21,0xa2,0x4b,0xf6,0x8a,0xf2,0x7d,0x5a,0x3a,0xc7,0xea,0x1b,0x51,0xbe,0xd4,0xda,0xdc,0xf2,0xcc,0x26,0xed,0x75,0x80,0x53,0xa4,0x65,0x9a,0x5f,0x00,0x9f,0xff,0x9c,0xe1,0x63,0x1f,0x48,0x75,0x44,0xf7,0xfc,0x34}, + {0xca,0x67,0x97,0x78,0x4c,0xe0,0x97,0xc1,0x7d,0x46,0xd9,0x38,0xcb,0x4d,0x71,0xb8,0xa8,0x5f,0xf9,0x83,0x82,0x88,0xde,0x55,0xf7,0x63,0xfa,0x4d,0x16,0xdc,0x3b,0x3d,0x98,0xaa,0xcf,0x78,0xab,0x1d,0xbb,0xa5,0xf2,0x72,0x0b,0x19,0x67,0xa2,0xed,0x5c,0x8e,0x60,0x92,0x0a,0x11,0xc9,0x09,0x93,0xb0,0x74,0xb3,0x2f,0x04,0xa3,0x19,0x01,0x7d,0x17,0xc2,0xe8,0x9c,0xd8,0xa2,0x67,0xc1,0xd0,0x95,0x68,0xf6,0xa5,0x9d,0x66,0xb0,0xa2,0x82,0xb2,0xe5,0x98,0x65,0xf5,0x73,0x0a,0xe2,0xed,0xf1,0x88,0xc0,0x56}, + {0x17,0x6e,0xa8,0x10,0x11,0x3d,0x6d,0x33,0xfa,0xb2,0x75,0x0b,0x32,0x88,0xf3,0xd7,0x88,0x29,0x07,0x25,0x76,0x33,0x15,0xf9,0x87,0x8b,0x10,0x99,0x6b,0x4c,0x67,0x09,0x02,0x8f,0xf3,0x24,0xac,0x5f,0x1b,0x58,0xbd,0x0c,0xe3,0xba,0xfe,0xe9,0x0b,0xa9,0xf0,0x92,0xcf,0x8a,0x02,0x69,0x21,0x9a,0x8f,0x03,0x59,0x83,0xa4,0x7e,0x8b,0x03,0xf8,0x6f,0x31,0x99,0x21,0xf8,0x4e,0x9f,0x4f,0x8d,0xa7,0xea,0x82,0xd2,0x49,0x2f,0x74,0x31,0xef,0x5a,0xab,0xa5,0x71,0x09,0x65,0xeb,0x69,0x59,0x02,0x31,0x5e,0x6e}, + {0xfb,0x93,0xe5,0x87,0xf5,0x62,0x6c,0xb1,0x71,0x3e,0x5d,0xca,0xde,0xed,0x99,0x49,0x6d,0x3e,0xcc,0x14,0xe0,0xc1,0x91,0xb4,0xa8,0xdb,0xa8,0x89,0x47,0x11,0xf5,0x08,0x22,0x62,0x06,0x63,0x0e,0xfb,0x04,0x33,0x3f,0xba,0xac,0x87,0x89,0x06,0x35,0xfb,0xa3,0x61,0x10,0x8c,0x77,0x24,0x19,0xbd,0x20,0x86,0x83,0xd1,0x43,0xad,0x58,0x30,0xd0,0x63,0x76,0xe5,0xfd,0x0f,0x3c,0x32,0x10,0xa6,0x2e,0xa2,0x38,0xdf,0xc3,0x05,0x9a,0x4f,0x99,0xac,0xbd,0x8a,0xc7,0xbd,0x99,0xdc,0xe3,0xef,0xa4,0x9f,0x54,0x26}, + {0xd6,0xf9,0x6b,0x1e,0x46,0x5a,0x1d,0x74,0x81,0xa5,0x77,0x77,0xfc,0xb3,0x05,0x23,0xd9,0xd3,0x74,0x64,0xa2,0x74,0x55,0xd4,0xff,0xe0,0x01,0x64,0xdc,0xe1,0x26,0x19,0x6e,0x66,0x3f,0xaf,0x49,0x85,0x46,0xdb,0xa5,0x0e,0x4a,0xf1,0x04,0xcf,0x7f,0xd7,0x47,0x0c,0xba,0xa4,0xf7,0x3f,0xf2,0x3d,0x85,0x3c,0xce,0x32,0xe1,0xdf,0x10,0x3a,0xa0,0xce,0x17,0xea,0x8a,0x4e,0x7f,0xe0,0xfd,0xc1,0x1f,0x3a,0x46,0x15,0xd5,0x2f,0xf1,0xc0,0xf2,0x31,0xfd,0x22,0x53,0x17,0x15,0x5d,0x1e,0x86,0x1d,0xd0,0xa1,0x1f}, + {0x32,0x98,0x59,0x7d,0x94,0x55,0x80,0xcc,0x20,0x55,0xf1,0x37,0xda,0x56,0x46,0x1e,0x20,0x93,0x05,0x4e,0x74,0xf7,0xf6,0x99,0x33,0xcf,0x75,0x6a,0xbc,0x63,0x35,0x77,0xab,0x94,0xdf,0xd1,0x00,0xac,0xdc,0x38,0xe9,0x0d,0x08,0xd1,0xdd,0x2b,0x71,0x2e,0x62,0xe2,0xd5,0xfd,0x3e,0xe9,0x13,0x7f,0xe5,0x01,0x9a,0xee,0x18,0xed,0xfc,0x73,0xb3,0x9c,0x13,0x63,0x08,0xe9,0xb1,0x06,0xcd,0x3e,0xa0,0xc5,0x67,0xda,0x93,0xa4,0x32,0x89,0x63,0xad,0xc8,0xce,0x77,0x8d,0x44,0x4f,0x86,0x1b,0x70,0x6b,0x42,0x1f}, + {0x01,0x1c,0x91,0x41,0x4c,0x26,0xc9,0xef,0x25,0x2c,0xa2,0x17,0xb8,0xb7,0xa3,0xf1,0x47,0x14,0x0f,0xf3,0x6b,0xda,0x75,0x58,0x90,0xb0,0x31,0x1d,0x27,0xf5,0x1a,0x4e,0x52,0x25,0xa1,0x91,0xc8,0x35,0x7e,0xf1,0x76,0x9c,0x5e,0x57,0x53,0x81,0x6b,0xb7,0x3e,0x72,0x9b,0x0d,0x6f,0x40,0x83,0xfa,0x38,0xe4,0xa7,0x3f,0x1b,0xbb,0x76,0x0b,0x9b,0x93,0x92,0x7f,0xf9,0xc1,0xb8,0x08,0x6e,0xab,0x44,0xd4,0xcb,0x71,0x67,0xbe,0x17,0x80,0xbb,0x99,0x63,0x64,0xe5,0x22,0x55,0xa9,0x72,0xb7,0x1e,0xd6,0x6d,0x7b}, + {0x92,0x3d,0xf3,0x50,0xe8,0xc1,0xad,0xb7,0xcf,0xd5,0x8c,0x60,0x4f,0xfa,0x98,0x79,0xdb,0x5b,0xfc,0x8d,0xbd,0x2d,0x96,0xad,0x4f,0x2f,0x1d,0xaf,0xce,0x9b,0x3e,0x70,0xc7,0xd2,0x01,0xab,0xf9,0xab,0x30,0x57,0x18,0x3b,0x14,0x40,0xdc,0x76,0xfb,0x16,0x81,0xb2,0xcb,0xa0,0x65,0xbe,0x6c,0x86,0xfe,0x6a,0xff,0x9b,0x65,0x9b,0xfa,0x53,0x55,0x54,0x88,0x94,0xe9,0xc8,0x14,0x6c,0xe5,0xd4,0xae,0x65,0x66,0x5d,0x3a,0x84,0xf1,0x5a,0xd6,0xbc,0x3e,0xb7,0x1b,0x18,0x50,0x1f,0xc6,0xc4,0xe5,0x93,0x8d,0x39}, + {0xf3,0x48,0xe2,0x33,0x67,0xd1,0x4b,0x1c,0x5f,0x0a,0xbf,0x15,0x87,0x12,0x9e,0xbd,0x76,0x03,0x0b,0xa1,0xf0,0x8c,0x3f,0xd4,0x13,0x1b,0x19,0xdf,0x5d,0x9b,0xb0,0x53,0xf2,0xe3,0xe7,0xd2,0x60,0x7c,0x87,0xc3,0xb1,0x8b,0x82,0x30,0xa0,0xaa,0x34,0x3b,0x38,0xf1,0x9e,0x73,0xe7,0x26,0x3e,0x28,0x77,0x05,0xc3,0x02,0x90,0x9c,0x9c,0x69,0xcc,0xf1,0x46,0x59,0x23,0xa7,0x06,0xf3,0x7d,0xd9,0xe5,0xcc,0xb5,0x18,0x17,0x92,0x75,0xe9,0xb4,0x81,0x47,0xd2,0xcd,0x28,0x07,0xd9,0xcd,0x6f,0x0c,0xf3,0xca,0x51}, + {0x0a,0xe0,0x74,0x76,0x42,0xa7,0x0b,0xa6,0xf3,0x7b,0x7a,0xa1,0x70,0x85,0x0e,0x63,0xcc,0x24,0x33,0xcf,0x3d,0x56,0x58,0x37,0xaa,0xfd,0x83,0x23,0x29,0xaa,0x04,0x55,0xc7,0x54,0xac,0x18,0x9a,0xf9,0x7a,0x73,0x0f,0xb3,0x1c,0xc5,0xdc,0x78,0x33,0x90,0xc7,0x0c,0xe1,0x4c,0x33,0xbc,0x89,0x2b,0x9a,0xe9,0xf8,0x89,0xc1,0x29,0xae,0x12,0xcf,0x01,0x0d,0x1f,0xcb,0xc0,0x9e,0xa9,0xae,0xf7,0x34,0x3a,0xcc,0xef,0xd1,0x0d,0x22,0x4e,0x9c,0xd0,0x21,0x75,0xca,0x55,0xea,0xa5,0xeb,0x58,0xe9,0x4f,0xd1,0x5f}, + {0x2c,0xab,0x45,0x28,0xdf,0x2d,0xdc,0xb5,0x93,0xe9,0x7f,0x0a,0xb1,0x91,0x94,0x06,0x46,0xe3,0x02,0x40,0xd6,0xf3,0xaa,0x4d,0xd1,0x74,0x64,0x58,0x6e,0xf2,0x3f,0x09,0x8e,0xcb,0x93,0xbf,0x5e,0xfe,0x42,0x3c,0x5f,0x56,0xd4,0x36,0x51,0xa8,0xdf,0xbe,0xe8,0x20,0x42,0x88,0x9e,0x85,0xf0,0xe0,0x28,0xd1,0x25,0x07,0x96,0x3f,0xd7,0x7d,0x29,0x98,0x05,0x68,0xfe,0x24,0x0d,0xb1,0xe5,0x23,0xaf,0xdb,0x72,0x06,0x73,0x75,0x29,0xac,0x57,0xb4,0x3a,0x25,0x67,0x13,0xa4,0x70,0xb4,0x86,0xbc,0xbc,0x59,0x2f}, + {0x5f,0x13,0x17,0x99,0x42,0x7d,0x84,0x83,0xd7,0x03,0x7d,0x56,0x1f,0x91,0x1b,0xad,0xd1,0xaa,0x77,0xbe,0xd9,0x48,0x77,0x7e,0x4a,0xaf,0x51,0x2e,0x2e,0xb4,0x58,0x54,0x01,0xc3,0x91,0xb6,0x60,0xd5,0x41,0x70,0x1e,0xe7,0xd7,0xad,0x3f,0x1b,0x20,0x85,0x85,0x55,0x33,0x11,0x63,0xe1,0xc2,0x16,0xb1,0x28,0x08,0x01,0x3d,0x5e,0xa5,0x2a,0x4f,0x44,0x07,0x0c,0xe6,0x92,0x51,0xed,0x10,0x1d,0x42,0x74,0x2d,0x4e,0xc5,0x42,0x64,0xc8,0xb5,0xfd,0x82,0x4c,0x2b,0x35,0x64,0x86,0x76,0x8a,0x4a,0x00,0xe9,0x13}, + {0xdb,0xce,0x2f,0x83,0x45,0x88,0x9d,0x73,0x63,0xf8,0x6b,0xae,0xc9,0xd6,0x38,0xfa,0xf7,0xfe,0x4f,0xb7,0xca,0x0d,0xbc,0x32,0x5e,0xe4,0xbc,0x14,0x88,0x7e,0x93,0x73,0x7f,0x87,0x3b,0x19,0xc9,0x00,0x2e,0xbb,0x6b,0x50,0xdc,0xe0,0x90,0xa8,0xe3,0xec,0x9f,0x64,0xde,0x36,0xc0,0xb7,0xf3,0xec,0x1a,0x9e,0xde,0x98,0x08,0x04,0x46,0x5f,0x8d,0xf4,0x7b,0x29,0x16,0x71,0x03,0xb9,0x34,0x68,0xf0,0xd4,0x22,0x3b,0xd1,0xa9,0xc6,0xbd,0x96,0x46,0x57,0x15,0x97,0xe1,0x35,0xe8,0xd5,0x91,0xe8,0xa4,0xf8,0x2c}, + {0x67,0x0f,0x11,0x07,0x87,0xfd,0x93,0x6d,0x49,0xb5,0x38,0x7c,0xd3,0x09,0x4c,0xdd,0x86,0x6a,0x73,0xc2,0x4c,0x6a,0xb1,0x7c,0x09,0x2a,0x25,0x58,0x6e,0xbd,0x49,0x20,0xa2,0x6b,0xd0,0x17,0x7e,0x48,0xb5,0x2c,0x6b,0x19,0x50,0x39,0x1c,0x38,0xd2,0x24,0x30,0x8a,0x97,0x85,0x81,0x9c,0x65,0xd7,0xf6,0xa4,0xd6,0x91,0x28,0x7f,0x6f,0x7a,0x49,0xef,0x9a,0x6a,0x8d,0xfd,0x09,0x7d,0x0b,0xb9,0x3d,0x5b,0xbe,0x60,0xee,0xf0,0xd4,0xbf,0x9e,0x51,0x2c,0xb5,0x21,0x4c,0x1d,0x94,0x45,0xc5,0xdf,0xaa,0x11,0x60}, + {0x3c,0xf8,0x95,0xcf,0x6d,0x92,0x67,0x5f,0x71,0x90,0x28,0x71,0x61,0x85,0x7e,0x7c,0x5b,0x7a,0x8f,0x99,0xf3,0xe7,0xa1,0xd6,0xe0,0xf9,0x62,0x0b,0x1b,0xcc,0xc5,0x6f,0x90,0xf8,0xcb,0x02,0xc8,0xd0,0xde,0x63,0xaa,0x6a,0xff,0x0d,0xca,0x98,0xd0,0xfb,0x99,0xed,0xb6,0xb9,0xfd,0x0a,0x4d,0x62,0x1e,0x0b,0x34,0x79,0xb7,0x18,0xce,0x69,0xcb,0x79,0x98,0xb2,0x28,0x55,0xef,0xd1,0x92,0x90,0x7e,0xd4,0x3c,0xae,0x1a,0xdd,0x52,0x23,0x9f,0x18,0x42,0x04,0x7e,0x12,0xf1,0x01,0x71,0xe5,0x3a,0x6b,0x59,0x15}, + {0xa2,0x79,0x91,0x3f,0xd2,0x39,0x27,0x46,0xcf,0xdd,0xd6,0x97,0x31,0x12,0x83,0xff,0x8a,0x14,0xf2,0x53,0xb5,0xde,0x07,0x13,0xda,0x4d,0x5f,0x7b,0x68,0x37,0x22,0x0d,0xca,0x24,0x51,0x7e,0x16,0x31,0xff,0x09,0xdf,0x45,0xc7,0xd9,0x8b,0x15,0xe4,0x0b,0xe5,0x56,0xf5,0x7e,0x22,0x7d,0x2b,0x29,0x38,0xd1,0xb6,0xaf,0x41,0xe2,0xa4,0x3a,0xf5,0x05,0x33,0x2a,0xbf,0x38,0xc1,0x2c,0xc3,0x26,0xe9,0xa2,0x8f,0x3f,0x58,0x48,0xeb,0xd2,0x49,0x55,0xa2,0xb1,0x3a,0x08,0x6c,0xa3,0x87,0x46,0x6e,0xaa,0xfc,0x32}, + {0xf5,0x9a,0x7d,0xc5,0x8d,0x6e,0xc5,0x7b,0xf2,0xbd,0xf0,0x9d,0xed,0xd2,0x0b,0x3e,0xa3,0xe4,0xef,0x22,0xde,0x14,0xc0,0xaa,0x5c,0x6a,0xbd,0xfe,0xce,0xe9,0x27,0x46,0xdf,0xcc,0x87,0x27,0x73,0xa4,0x07,0x32,0xf8,0xe3,0x13,0xf2,0x08,0x19,0xe3,0x17,0x4e,0x96,0x0d,0xf6,0xd7,0xec,0xb2,0xd5,0xe9,0x0b,0x60,0xc2,0x36,0x63,0x6f,0x74,0x1c,0x97,0x6c,0xab,0x45,0xf3,0x4a,0x3f,0x1f,0x73,0x43,0x99,0x72,0xeb,0x88,0xe2,0x6d,0x18,0x44,0x03,0x8a,0x6a,0x59,0x33,0x93,0x62,0xd6,0x7e,0x00,0x17,0x49,0x7b}, + {0x64,0xb0,0x84,0xab,0x5c,0xfb,0x85,0x2d,0x14,0xbc,0xf3,0x89,0xd2,0x10,0x78,0x49,0x0c,0xce,0x15,0x7b,0x44,0xdc,0x6a,0x47,0x7b,0xfd,0x44,0xf8,0x76,0xa3,0x2b,0x12,0xdd,0xa2,0x53,0xdd,0x28,0x1b,0x34,0x54,0x3f,0xfc,0x42,0xdf,0x5b,0x90,0x17,0xaa,0xf4,0xf8,0xd2,0x4d,0xd9,0x92,0xf5,0x0f,0x7d,0xd3,0x8c,0xe0,0x0f,0x62,0x03,0x1d,0x54,0xe5,0xb4,0xa2,0xcd,0x32,0x02,0xc2,0x7f,0x18,0x5d,0x11,0x42,0xfd,0xd0,0x9e,0xd9,0x79,0xd4,0x7d,0xbe,0xb4,0xab,0x2e,0x4c,0xec,0x68,0x2b,0xf5,0x0b,0xc7,0x02}, + {0xbb,0x2f,0x0b,0x5d,0x4b,0xec,0x87,0xa2,0xca,0x82,0x48,0x07,0x90,0x57,0x5c,0x41,0x5c,0x81,0xd0,0xc1,0x1e,0xa6,0x44,0xe0,0xe0,0xf5,0x9e,0x40,0x0a,0x4f,0x33,0x26,0xe1,0x72,0x8d,0x45,0xbf,0x32,0xe5,0xac,0xb5,0x3c,0xb7,0x7c,0xe0,0x68,0xe7,0x5b,0xe7,0xbd,0x8b,0xee,0x94,0x7d,0xcf,0x56,0x03,0x3a,0xb4,0xfe,0xe3,0x97,0x06,0x6b,0xc0,0xa3,0x62,0xdf,0x4a,0xf0,0xc8,0xb6,0x5d,0xa4,0x6d,0x07,0xef,0x00,0xf0,0x3e,0xa9,0xd2,0xf0,0x49,0x58,0xb9,0x9c,0x9c,0xae,0x2f,0x1b,0x44,0x43,0x7f,0xc3,0x1c}, + {0x4f,0x32,0xc7,0x5c,0x5a,0x56,0x8f,0x50,0x22,0xa9,0x06,0xe5,0xc0,0xc4,0x61,0xd0,0x19,0xac,0x45,0x5c,0xdb,0xab,0x18,0xfb,0x4a,0x31,0x80,0x03,0xc1,0x09,0x68,0x6c,0xb9,0xae,0xce,0xc9,0xf1,0x56,0x66,0xd7,0x6a,0x65,0xe5,0x18,0xf8,0x15,0x5b,0x1c,0x34,0x23,0x4c,0x84,0x32,0x28,0xe7,0x26,0x38,0x68,0x19,0x2f,0x77,0x6f,0x34,0x3a,0xc8,0x6a,0xda,0xe2,0x12,0x51,0xd5,0xd2,0xed,0x51,0xe8,0xb1,0x31,0x03,0xbd,0xe9,0x62,0x72,0xc6,0x8e,0xdd,0x46,0x07,0x96,0xd0,0xc5,0xf7,0x6e,0x9f,0x1b,0x91,0x05}, + {0xbb,0x0e,0xdf,0xf5,0x83,0x99,0x33,0xc1,0xac,0x4c,0x2c,0x51,0x8f,0x75,0xf3,0xc0,0xe1,0x98,0xb3,0x0b,0x0a,0x13,0xf1,0x2c,0x62,0x0c,0x27,0xaa,0xf9,0xec,0x3c,0x6b,0xef,0xea,0x2e,0x51,0xf3,0xac,0x49,0x53,0x49,0xcb,0xc1,0x1c,0xd3,0x41,0xc1,0x20,0x8d,0x68,0x9a,0xa9,0x07,0x0c,0x18,0x24,0x17,0x2d,0x4b,0xc6,0xd1,0xf9,0x5e,0x55,0x08,0xbd,0x73,0x3b,0xba,0x70,0xa7,0x36,0x0c,0xbf,0xaf,0xa3,0x08,0xef,0x4a,0x62,0xf2,0x46,0x09,0xb4,0x98,0xff,0x37,0x57,0x9d,0x74,0x81,0x33,0xe1,0x4d,0x5f,0x67}, + {0xfc,0x82,0x17,0x6b,0x03,0x52,0x2c,0x0e,0xb4,0x83,0xad,0x6c,0x81,0x6c,0x81,0x64,0x3e,0x07,0x64,0x69,0xd9,0xbd,0xdc,0xd0,0x20,0xc5,0x64,0x01,0xf7,0x9d,0xd9,0x13,0x1d,0xb3,0xda,0x3b,0xd9,0xf6,0x2f,0xa1,0xfe,0x2d,0x65,0x9d,0x0f,0xd8,0x25,0x07,0x87,0x94,0xbe,0x9a,0xf3,0x4f,0x9c,0x01,0x43,0x3c,0xcd,0x82,0xb8,0x50,0xf4,0x60,0xca,0xc0,0xe5,0x21,0xc3,0x5e,0x4b,0x01,0xa2,0xbf,0x19,0xd7,0xc9,0x69,0xcb,0x4f,0xa0,0x23,0x00,0x75,0x18,0x1c,0x5f,0x4e,0x80,0xac,0xed,0x55,0x9e,0xde,0x06,0x1c}, + {0xe2,0xc4,0x3e,0xa3,0xd6,0x7a,0x0f,0x99,0x8e,0xe0,0x2e,0xbe,0x38,0xf9,0x08,0x66,0x15,0x45,0x28,0x63,0xc5,0x43,0xa1,0x9c,0x0d,0xb6,0x2d,0xec,0x1f,0x8a,0xf3,0x4c,0xaa,0x69,0x6d,0xff,0x40,0x2b,0xd5,0xff,0xbb,0x49,0x40,0xdc,0x18,0x0b,0x53,0x34,0x97,0x98,0x4d,0xa3,0x2f,0x5c,0x4a,0x5e,0x2d,0xba,0x32,0x7d,0x8e,0x6f,0x09,0x78,0xe7,0x5c,0xfa,0x0d,0x65,0xaa,0xaa,0xa0,0x8c,0x47,0xb5,0x48,0x2a,0x9e,0xc4,0xf9,0x5b,0x72,0x03,0x70,0x7d,0xcc,0x09,0x4f,0xbe,0x1a,0x09,0x26,0x3a,0xad,0x3c,0x37}, + {0x7c,0xf5,0xc9,0x82,0x4d,0x63,0x94,0xb2,0x36,0x45,0x93,0x24,0xe1,0xfd,0xcb,0x1f,0x5a,0xdb,0x8c,0x41,0xb3,0x4d,0x9c,0x9e,0xfc,0x19,0x44,0x45,0xd9,0xf3,0x40,0x00,0xad,0xbb,0xdd,0x89,0xfb,0xa8,0xbe,0xf1,0xcb,0xae,0xae,0x61,0xbc,0x2c,0xcb,0x3b,0x9d,0x8d,0x9b,0x1f,0xbb,0xa7,0x58,0x8f,0x86,0xa6,0x12,0x51,0xda,0x7e,0x54,0x21,0xd3,0x86,0x59,0xfd,0x39,0xe9,0xfd,0xde,0x0c,0x38,0x0a,0x51,0x89,0x2c,0x27,0xf4,0xb9,0x19,0x31,0xbb,0x07,0xa4,0x2b,0xb7,0xf4,0x4d,0x25,0x4a,0x33,0x0a,0x55,0x63}, + {0x37,0xcf,0x69,0xb5,0xed,0xd6,0x07,0x65,0xe1,0x2e,0xa5,0x0c,0xb0,0x29,0x84,0x17,0x5d,0xd6,0x6b,0xeb,0x90,0x00,0x7c,0xea,0x51,0x8f,0xf7,0xda,0xc7,0x62,0xea,0x3e,0x49,0x7b,0x54,0x72,0x45,0x58,0xba,0x9b,0xe0,0x08,0xc4,0xe2,0xfa,0xc6,0x05,0xf3,0x8d,0xf1,0x34,0xc7,0x69,0xfa,0xe8,0x60,0x7a,0x76,0x7d,0xaa,0xaf,0x2b,0xa9,0x39,0x4e,0x27,0x93,0xe6,0x13,0xc7,0x24,0x9d,0x75,0xd3,0xdb,0x68,0x77,0x85,0x63,0x5f,0x9a,0xb3,0x8a,0xeb,0x60,0x55,0x52,0x70,0xcd,0xc4,0xc9,0x65,0x06,0x6a,0x43,0x68}, + {0x27,0x3f,0x2f,0x20,0xe8,0x35,0x02,0xbc,0xb0,0x75,0xf9,0x64,0xe2,0x00,0x5c,0xc7,0x16,0x24,0x8c,0xa3,0xd5,0xe9,0xa4,0x91,0xf9,0x89,0xb7,0x8a,0xf6,0xe7,0xb6,0x17,0x7c,0x10,0x20,0xe8,0x17,0xd3,0x56,0x1e,0x65,0xe9,0x0a,0x84,0x44,0x68,0x26,0xc5,0x7a,0xfc,0x0f,0x32,0xc6,0xa1,0xe0,0xc1,0x72,0x14,0x61,0x91,0x9c,0x66,0x73,0x53,0x57,0x52,0x0e,0x9a,0xab,0x14,0x28,0x5d,0xfc,0xb3,0xca,0xc9,0x84,0x20,0x8f,0x90,0xca,0x1e,0x2d,0x5b,0x88,0xf5,0xca,0xaf,0x11,0x7d,0xf8,0x78,0xa6,0xb5,0xb4,0x1c}, + {0x6c,0xfc,0x4a,0x39,0x6b,0xc0,0x64,0xb6,0xb1,0x5f,0xda,0x98,0x24,0xde,0x88,0x0c,0x34,0xd8,0xca,0x4b,0x16,0x03,0x8d,0x4f,0xa2,0x34,0x74,0xde,0x78,0xca,0x0b,0x33,0xe7,0x07,0xa0,0xa2,0x62,0xaa,0x74,0x6b,0xb1,0xc7,0x71,0xf0,0xb0,0xe0,0x11,0xf3,0x23,0xe2,0x0b,0x00,0x38,0xe4,0x07,0x57,0xac,0x6e,0xef,0x82,0x2d,0xfd,0xc0,0x2d,0x4e,0x74,0x19,0x11,0x84,0xff,0x2e,0x98,0x24,0x47,0x07,0x2b,0x96,0x5e,0x69,0xf9,0xfb,0x53,0xc9,0xbf,0x4f,0xc1,0x8a,0xc5,0xf5,0x1c,0x9f,0x36,0x1b,0xbe,0x31,0x3c}, + {0xee,0x8a,0x94,0x08,0x4d,0x86,0xf4,0xb0,0x6f,0x1c,0xba,0x91,0xee,0x19,0xdc,0x07,0x58,0xa1,0xac,0xa6,0xae,0xcd,0x75,0x79,0xbb,0xd4,0x62,0x42,0x13,0x61,0x0b,0x33,0x72,0x42,0xcb,0xf9,0x93,0xbc,0x68,0xc1,0x98,0xdb,0xce,0xc7,0x1f,0x71,0xb8,0xae,0x7a,0x8d,0xac,0x34,0xaa,0x52,0x0e,0x7f,0xbb,0x55,0x7d,0x7e,0x09,0xc1,0xce,0x41,0x8a,0x80,0x6d,0xa2,0xd7,0x19,0x96,0xf7,0x6d,0x15,0x9e,0x1d,0x9e,0xd4,0x1f,0xbb,0x27,0xdf,0xa1,0xdb,0x6c,0xc3,0xd7,0x73,0x7d,0x77,0x28,0x1f,0xd9,0x4c,0xb4,0x26}, + {0x75,0x74,0x38,0x8f,0x47,0x48,0xf0,0x51,0x3c,0xcb,0xbe,0x9c,0xf4,0xbc,0x5d,0xb2,0x55,0x20,0x9f,0xd9,0x44,0x12,0xab,0x9a,0xd6,0xa5,0x10,0x1c,0x6c,0x9e,0x70,0x2c,0x83,0x03,0x73,0x62,0x93,0xf2,0xb7,0xe1,0x2c,0x8a,0xca,0xeb,0xff,0x79,0x52,0x4b,0x14,0x13,0xd4,0xbf,0x8a,0x77,0xfc,0xda,0x0f,0x61,0x72,0x9c,0x14,0x10,0xeb,0x7d,0x7a,0xee,0x66,0x87,0x6a,0xaf,0x62,0xcb,0x0e,0xcd,0x53,0x55,0x04,0xec,0xcb,0x66,0xb5,0xe4,0x0b,0x0f,0x38,0x01,0x80,0x58,0xea,0xe2,0x2c,0xf6,0x9f,0x8e,0xe6,0x08}, + {0xad,0x30,0xc1,0x4b,0x0a,0x50,0xad,0x34,0x9c,0xd4,0x0b,0x3d,0x49,0xdb,0x38,0x8d,0xbe,0x89,0x0a,0x50,0x98,0x3d,0x5c,0xa2,0x09,0x3b,0xba,0xee,0x87,0x3f,0x1f,0x2f,0xf9,0xf2,0xb8,0x0a,0xd5,0x09,0x2d,0x2f,0xdf,0x23,0x59,0xc5,0x8d,0x21,0xb9,0xac,0xb9,0x6c,0x76,0x73,0x26,0x34,0x8f,0x4a,0xf5,0x19,0xf7,0x38,0xd7,0x3b,0xb1,0x4c,0x4a,0xb6,0x15,0xe5,0x75,0x8c,0x84,0xf7,0x38,0x90,0x4a,0xdb,0xba,0x01,0x95,0xa5,0x50,0x1b,0x75,0x3f,0x3f,0x31,0x0d,0xc2,0xe8,0x2e,0xae,0xc0,0x53,0xe3,0xa1,0x19}, + {0xc3,0x05,0xfa,0xba,0x60,0x75,0x1c,0x7d,0x61,0x5e,0xe5,0xc6,0xa0,0xa0,0xe1,0xb3,0x73,0x64,0xd6,0xc0,0x18,0x97,0x52,0xe3,0x86,0x34,0x0c,0xc2,0x11,0x6b,0x54,0x41,0xbd,0xbd,0x96,0xd5,0xcd,0x72,0x21,0xb4,0x40,0xfc,0xee,0x98,0x43,0x45,0xe0,0x93,0xb5,0x09,0x41,0xb4,0x47,0x53,0xb1,0x9f,0x34,0xae,0x66,0x02,0x99,0xd3,0x6b,0x73,0xb4,0xb3,0x34,0x93,0x50,0x2d,0x53,0x85,0x73,0x65,0x81,0x60,0x4b,0x11,0xfd,0x46,0x75,0x83,0x5c,0x42,0x30,0x5f,0x5f,0xcc,0x5c,0xab,0x7f,0xb8,0xa2,0x95,0x22,0x41}, + {0xe9,0xd6,0x7e,0xf5,0x88,0x9b,0xc9,0x19,0x25,0xc8,0xf8,0x6d,0x26,0xcb,0x93,0x53,0x73,0xd2,0x0a,0xb3,0x13,0x32,0xee,0x5c,0x34,0x2e,0x2d,0xb5,0xeb,0x53,0xe1,0x14,0xc6,0xea,0x93,0xe2,0x61,0x52,0x65,0x2e,0xdb,0xac,0x33,0x21,0x03,0x92,0x5a,0x84,0x6b,0x99,0x00,0x79,0xcb,0x75,0x09,0x46,0x80,0xdd,0x5a,0x19,0x8d,0xbb,0x60,0x07,0x8a,0x81,0xe6,0xcd,0x17,0x1a,0x3e,0x41,0x84,0xa0,0x69,0xed,0xa9,0x6d,0x15,0x57,0xb1,0xcc,0xca,0x46,0x8f,0x26,0xbf,0x2c,0xf2,0xc5,0x3a,0xc3,0x9b,0xbe,0x34,0x6b}, + {0xb2,0xc0,0x78,0x3a,0x64,0x2f,0xdf,0xf3,0x7c,0x02,0x2e,0xf2,0x1e,0x97,0x3e,0x4c,0xa3,0xb5,0xc1,0x49,0x5e,0x1c,0x7d,0xec,0x2d,0xdd,0x22,0x09,0x8f,0xc1,0x12,0x20,0xd3,0xf2,0x71,0x65,0x65,0x69,0xfc,0x11,0x7a,0x73,0x0e,0x53,0x45,0xe8,0xc9,0xc6,0x35,0x50,0xfe,0xd4,0xa2,0xe7,0x3a,0xe3,0x0b,0xd3,0x6d,0x2e,0xb6,0xc7,0xb9,0x01,0x29,0x9d,0xc8,0x5a,0xe5,0x55,0x0b,0x88,0x63,0xa7,0xa0,0x45,0x1f,0x24,0x83,0x14,0x1f,0x6c,0xe7,0xc2,0xdf,0xef,0x36,0x3d,0xe8,0xad,0x4b,0x4e,0x78,0x5b,0xaf,0x08}, + {0x33,0x25,0x1f,0x88,0xdc,0x99,0x34,0x28,0xb6,0x23,0x93,0x77,0xda,0x25,0x05,0x9d,0xf4,0x41,0x34,0x67,0xfb,0xdd,0x7a,0x89,0x8d,0x16,0x3a,0x16,0x71,0x9d,0xb7,0x32,0x4b,0x2c,0xcc,0x89,0xd2,0x14,0x73,0xe2,0x8d,0x17,0x87,0xa2,0x11,0xbd,0xe4,0x4b,0xce,0x64,0x33,0xfa,0xd6,0x28,0xd5,0x18,0x6e,0x82,0xd9,0xaf,0xd5,0xc1,0x23,0x64,0x6a,0xb3,0xfc,0xed,0xd9,0xf8,0x85,0xcc,0xf9,0xe5,0x46,0x37,0x8f,0xc2,0xbc,0x22,0xcd,0xd3,0xe5,0xf9,0x38,0xe3,0x9d,0xe4,0xcc,0x2d,0x3e,0xc1,0xfb,0x5e,0x0a,0x48}, + {0x71,0x20,0x62,0x01,0x0b,0xe7,0x51,0x0b,0xc5,0xaf,0x1d,0x8b,0xcf,0x05,0xb5,0x06,0xcd,0xab,0x5a,0xef,0x61,0xb0,0x6b,0x2c,0x31,0xbf,0xb7,0x0c,0x60,0x27,0xaa,0x47,0x1f,0x22,0xce,0x42,0xe4,0x4c,0x61,0xb6,0x28,0x39,0x05,0x4c,0xcc,0x9d,0x19,0x6e,0x03,0xbe,0x1c,0xdc,0xa4,0xb4,0x3f,0x66,0x06,0x8e,0x1c,0x69,0x47,0x1d,0xb3,0x24,0xc3,0xf8,0x15,0xc0,0xed,0x1e,0x54,0x2a,0x7c,0x3f,0x69,0x7c,0x7e,0xfe,0xa4,0x11,0xd6,0x78,0xa2,0x4e,0x13,0x66,0xaf,0xf0,0x94,0xa0,0xdd,0x14,0x5d,0x58,0x5b,0x54}, + {0x0f,0x3a,0xd4,0xa0,0x5e,0x27,0xbf,0x67,0xbe,0xee,0x9b,0x08,0x34,0x8e,0xe6,0xad,0x2e,0xe7,0x79,0xd4,0x4c,0x13,0x89,0x42,0x54,0x54,0xba,0x32,0xc3,0xf9,0x62,0x0f,0xe1,0x21,0xb3,0xe3,0xd0,0xe4,0x04,0x62,0x95,0x1e,0xff,0x28,0x7a,0x63,0xaa,0x3b,0x9e,0xbd,0x99,0x5b,0xfd,0xcf,0x0c,0x0b,0x71,0xd0,0xc8,0x64,0x3e,0xdc,0x22,0x4d,0x39,0x5f,0x3b,0xd6,0x89,0x65,0xb4,0xfc,0x61,0xcf,0xcb,0x57,0x3f,0x6a,0xae,0x5c,0x05,0xfa,0x3a,0x95,0xd2,0xc2,0xba,0xfe,0x36,0x14,0x37,0x36,0x1a,0xa0,0x0f,0x1c}, + {0xff,0x3d,0x94,0x22,0xb6,0x04,0xc6,0xd2,0xa0,0xb3,0xcf,0x44,0xce,0xbe,0x8c,0xbc,0x78,0x86,0x80,0x97,0xf3,0x4f,0x25,0x5d,0xbf,0xa6,0x1c,0x3b,0x4f,0x61,0xa3,0x0f,0x50,0x6a,0x93,0x8c,0x0e,0x2b,0x08,0x69,0xb6,0xc5,0xda,0xc1,0x35,0xa0,0xc9,0xf9,0x34,0xb6,0xdf,0xc4,0x54,0x3e,0xb7,0x6f,0x40,0xc1,0x2b,0x1d,0x9b,0x41,0x05,0x40,0xf0,0x82,0xbe,0xb9,0xbd,0xfe,0x03,0xa0,0x90,0xac,0x44,0x3a,0xaf,0xc1,0x89,0x20,0x8e,0xfa,0x54,0x19,0x91,0x9f,0x49,0xf8,0x42,0xab,0x40,0xef,0x8a,0x21,0xba,0x1f}, + {0x3e,0xf5,0xc8,0xfa,0x48,0x94,0x54,0xab,0x41,0x37,0xa6,0x7b,0x9a,0xe8,0xf6,0x81,0x01,0x5e,0x2b,0x6c,0x7d,0x6c,0xfd,0x74,0x42,0x6e,0xc8,0xa8,0xca,0x3a,0x2e,0x39,0x94,0x01,0x7b,0x3e,0x04,0x57,0x3e,0x4f,0x7f,0xaf,0xda,0x08,0xee,0x3e,0x1d,0xa8,0xf1,0xde,0xdc,0x99,0xab,0xc6,0x39,0xc8,0xd5,0x61,0x77,0xff,0x13,0x5d,0x53,0x6c,0xaf,0x35,0x8a,0x3e,0xe9,0x34,0xbd,0x4c,0x16,0xe8,0x87,0x58,0x44,0x81,0x07,0x2e,0xab,0xb0,0x9a,0xf2,0x76,0x9c,0x31,0x19,0x3b,0xc1,0x0a,0xd5,0xe4,0x7f,0xe1,0x25}, + {0x76,0xf6,0x04,0x1e,0xd7,0x9b,0x28,0x0a,0x95,0x0f,0x42,0xd6,0x52,0x1c,0x8e,0x20,0xab,0x1f,0x69,0x34,0xb0,0xd8,0x86,0x51,0x51,0xb3,0x9f,0x2a,0x44,0x51,0x57,0x25,0xa7,0x21,0xf1,0x76,0xf5,0x7f,0x5f,0x91,0xe3,0x87,0xcd,0x2f,0x27,0x32,0x4a,0xc3,0x26,0xe5,0x1b,0x4d,0xde,0x2f,0xba,0xcc,0x9b,0x89,0x69,0x89,0x8f,0x82,0xba,0x6b,0x01,0x39,0xfe,0x90,0x66,0xbc,0xd1,0xe2,0xd5,0x7a,0x99,0xa0,0x18,0x4a,0xb5,0x4c,0xd4,0x60,0x84,0xaf,0x14,0x69,0x1d,0x97,0xe4,0x7b,0x6b,0x7f,0x4f,0x50,0x9d,0x55}, + {0xd5,0x54,0xeb,0xb3,0x78,0x83,0x73,0xa7,0x7c,0x3c,0x55,0xa5,0x66,0xd3,0x69,0x1d,0xba,0x00,0x28,0xf9,0x62,0xcf,0x26,0x0a,0x17,0x32,0x7e,0x80,0xd5,0x12,0xab,0x01,0xfd,0x66,0xd2,0xf6,0xe7,0x91,0x48,0x9c,0x1b,0x78,0x07,0x03,0x9b,0xa1,0x44,0x07,0x3b,0xe2,0x61,0x60,0x1d,0x8f,0x38,0x88,0x0e,0xd5,0x4b,0x35,0xa3,0xa6,0x3e,0x12,0x96,0x2d,0xe3,0x41,0x90,0x18,0x8d,0x11,0x48,0x58,0x31,0xd8,0xc2,0xe3,0xed,0xb9,0xd9,0x45,0x32,0xd8,0x71,0x42,0xab,0x1e,0x54,0xa1,0x18,0xc9,0xe2,0x61,0x39,0x4a}, + {0xa0,0xbb,0xe6,0xf8,0xe0,0x3b,0xdc,0x71,0x0a,0xe3,0xff,0x7e,0x34,0xf8,0xce,0xd6,0x6a,0x47,0x3a,0xe1,0x5f,0x42,0x92,0xa9,0x63,0xb7,0x1d,0xfb,0xe3,0xbc,0xd6,0x2c,0x1e,0x3f,0x23,0xf3,0x44,0xd6,0x27,0x03,0x16,0xf0,0xfc,0x34,0x0e,0x26,0x9a,0x49,0x79,0xb9,0xda,0xf2,0x16,0xa7,0xb5,0x83,0x1f,0x11,0xd4,0x9b,0xad,0xee,0xac,0x68,0x10,0xc2,0xd7,0xf3,0x0e,0xc9,0xb4,0x38,0x0c,0x04,0xad,0xb7,0x24,0x6e,0x8e,0x30,0x23,0x3e,0xe7,0xb7,0xf1,0xd9,0x60,0x38,0x97,0xf5,0x08,0xb5,0xd5,0x60,0x57,0x59}, + {0x97,0x63,0xaa,0x04,0xe1,0xbf,0x29,0x61,0xcb,0xfc,0xa7,0xa4,0x08,0x00,0x96,0x8f,0x58,0x94,0x90,0x7d,0x89,0xc0,0x8b,0x3f,0xa9,0x91,0xb2,0xdc,0x3e,0xa4,0x9f,0x70,0x90,0x27,0x02,0xfd,0xeb,0xcb,0x2a,0x88,0x60,0x57,0x11,0xc4,0x05,0x33,0xaf,0x89,0xf4,0x73,0x34,0x7d,0xe3,0x92,0xf4,0x65,0x2b,0x5a,0x51,0x54,0xdf,0xc5,0xb2,0x2c,0xca,0x2a,0xfd,0x63,0x8c,0x5d,0x0a,0xeb,0xff,0x4e,0x69,0x2e,0x66,0xc1,0x2b,0xd2,0x3a,0xb0,0xcb,0xf8,0x6e,0xf3,0x23,0x27,0x1f,0x13,0xc8,0xf0,0xec,0x29,0xf0,0x70}, + {0x33,0x3e,0xed,0x2e,0xb3,0x07,0x13,0x46,0xe7,0x81,0x55,0xa4,0x33,0x2f,0x04,0xae,0x66,0x03,0x5f,0x19,0xd3,0x49,0x44,0xc9,0x58,0x48,0x31,0x6c,0x8a,0x5d,0x7d,0x0b,0xb9,0xb0,0x10,0x5e,0xaa,0xaf,0x6a,0x2a,0xa9,0x1a,0x04,0xef,0x70,0xa3,0xf0,0x78,0x1f,0xd6,0x3a,0xaa,0x77,0xfb,0x3e,0x77,0xe1,0xd9,0x4b,0xa7,0xa2,0xa5,0xec,0x44,0x43,0xd5,0x95,0x7b,0x32,0x48,0xd4,0x25,0x1d,0x0f,0x34,0xa3,0x00,0x83,0xd3,0x70,0x2b,0xc5,0xe1,0x60,0x1c,0x53,0x1c,0xde,0xe4,0xe9,0x7d,0x2c,0x51,0x24,0x22,0x27}, + {0x2e,0x34,0xc5,0x49,0xaf,0x92,0xbc,0x1a,0xd0,0xfa,0xe6,0xb2,0x11,0xd8,0xee,0xff,0x29,0x4e,0xc8,0xfc,0x8d,0x8c,0xa2,0xef,0x43,0xc5,0x4c,0xa4,0x18,0xdf,0xb5,0x11,0xfc,0x75,0xa9,0x42,0x8a,0xbb,0x7b,0xbf,0x58,0xa3,0xad,0x96,0x77,0x39,0x5c,0x8c,0x48,0xaa,0xed,0xcd,0x6f,0xc7,0x7f,0xe2,0xa6,0x20,0xbc,0xf6,0xd7,0x5f,0x73,0x19,0x66,0x42,0xc8,0x42,0xd0,0x90,0xab,0xe3,0x7e,0x54,0x19,0x7f,0x0f,0x8e,0x84,0xeb,0xb9,0x97,0xa4,0x65,0xd0,0xa1,0x03,0x25,0x5f,0x89,0xdf,0x91,0x11,0x91,0xef,0x0f} +}; diff --git a/ed25519-donna/ed25519-donna-batchverify.h b/ed25519-donna/ed25519-donna-batchverify.h new file mode 100644 index 000000000..43c4923b3 --- /dev/null +++ b/ed25519-donna/ed25519-donna-batchverify.h @@ -0,0 +1,275 @@ +/* + Ed25519 batch verification +*/ + +#define max_batch_size 64 +#define heap_batch_size ((max_batch_size * 2) + 1) + +/* which limb is the 128th bit in? */ +static const size_t limb128bits = (128 + bignum256modm_bits_per_limb - 1) / bignum256modm_bits_per_limb; + +typedef size_t heap_index_t; + +typedef struct batch_heap_t { + unsigned char r[heap_batch_size][16]; /* 128 bit random values */ + ge25519 points[heap_batch_size]; + bignum256modm scalars[heap_batch_size]; + heap_index_t heap[heap_batch_size]; + size_t size; +} batch_heap; + +/* swap two values in the heap */ +static void +heap_swap(heap_index_t *heap, size_t a, size_t b) { + heap_index_t temp; + temp = heap[a]; + heap[a] = heap[b]; + heap[b] = temp; +} + +/* add the scalar at the end of the list to the heap */ +static void +heap_insert_next(batch_heap *heap) { + size_t node = heap->size, parent; + heap_index_t *pheap = heap->heap; + bignum256modm *scalars = heap->scalars; + + /* insert at the bottom */ + pheap[node] = (heap_index_t)node; + + /* sift node up to its sorted spot */ + parent = (node - 1) / 2; + while (node && lt256_modm_batch(scalars[pheap[parent]], scalars[pheap[node]], bignum256modm_limb_size - 1)) { + heap_swap(pheap, parent, node); + node = parent; + parent = (node - 1) / 2; + } + heap->size++; +} + +/* update the heap when the root element is updated */ +static void +heap_updated_root(batch_heap *heap, size_t limbsize) { + size_t node, parent, childr, childl; + heap_index_t *pheap = heap->heap; + bignum256modm *scalars = heap->scalars; + + /* sift root to the bottom */ + parent = 0; + node = 1; + childl = 1; + childr = 2; + while ((childr < heap->size)) { + node = lt256_modm_batch(scalars[pheap[childl]], scalars[pheap[childr]], limbsize) ? childr : childl; + heap_swap(pheap, parent, node); + parent = node; + childl = (parent * 2) + 1; + childr = childl + 1; + } + + /* sift root back up to its sorted spot */ + parent = (node - 1) / 2; + while (node && lte256_modm_batch(scalars[pheap[parent]], scalars[pheap[node]], limbsize)) { + heap_swap(pheap, parent, node); + node = parent; + parent = (node - 1) / 2; + } +} + +/* build the heap with count elements, count must be >= 3 */ +static void +heap_build(batch_heap *heap, size_t count) { + heap->heap[0] = 0; + heap->size = 0; + while (heap->size < count) + heap_insert_next(heap); +} + +/* extend the heap to contain new_count elements */ +static void +heap_extend(batch_heap *heap, size_t new_count) { + while (heap->size < new_count) + heap_insert_next(heap); +} + +/* get the top 2 elements of the heap */ +static void +heap_get_top2(batch_heap *heap, heap_index_t *max1, heap_index_t *max2, size_t limbsize) { + heap_index_t h0 = heap->heap[0], h1 = heap->heap[1], h2 = heap->heap[2]; + if (lt256_modm_batch(heap->scalars[h1], heap->scalars[h2], limbsize)) + h1 = h2; + *max1 = h0; + *max2 = h1; +} + +/* */ +static void +ge25519_multi_scalarmult_vartime_final(ge25519 *r, ge25519 *point, bignum256modm scalar) { + const bignum256modm_element_t topbit = ((bignum256modm_element_t)1 << (bignum256modm_bits_per_limb - 1)); + size_t limb = limb128bits; + bignum256modm_element_t flag; + + if (isone256_modm_batch(scalar)) { + /* this will happen most of the time after bos-carter */ + *r = *point; + return; + } else if (iszero256_modm_batch(scalar)) { + /* this will only happen if all scalars == 0 */ + memset(r, 0, sizeof(*r)); + r->y[0] = 1; + r->z[0] = 1; + return; + } + + *r = *point; + + /* find the limb where first bit is set */ + while (!scalar[limb]) + limb--; + + /* find the first bit */ + flag = topbit; + while ((scalar[limb] & flag) == 0) + flag >>= 1; + + /* exponentiate */ + for (;;) { + ge25519_double(r, r); + if (scalar[limb] & flag) + ge25519_add(r, r, point); + + flag >>= 1; + if (!flag) { + if (!limb--) + break; + flag = topbit; + } + } +} + +/* count must be >= 5 */ +static void +ge25519_multi_scalarmult_vartime(ge25519 *r, batch_heap *heap, size_t count) { + heap_index_t max1, max2; + + /* start with the full limb size */ + size_t limbsize = bignum256modm_limb_size - 1; + + /* whether the heap has been extended to include the 128 bit scalars */ + int extended = 0; + + /* grab an odd number of scalars to build the heap, unknown limb sizes */ + heap_build(heap, ((count + 1) / 2) | 1); + + for (;;) { + heap_get_top2(heap, &max1, &max2, limbsize); + + /* only one scalar remaining, we're done */ + if (iszero256_modm_batch(heap->scalars[max2])) + break; + + /* exhausted another limb? */ + if (!heap->scalars[max1][limbsize]) + limbsize -= 1; + + /* can we extend to the 128 bit scalars? */ + if (!extended && isatmost128bits256_modm_batch(heap->scalars[max1])) { + heap_extend(heap, count); + heap_get_top2(heap, &max1, &max2, limbsize); + extended = 1; + } + + sub256_modm_batch(heap->scalars[max1], heap->scalars[max1], heap->scalars[max2], limbsize); + ge25519_add(&heap->points[max2], &heap->points[max2], &heap->points[max1]); + heap_updated_root(heap, limbsize); + } + + ge25519_multi_scalarmult_vartime_final(r, &heap->points[max1], heap->scalars[max1]); +} + +/* not actually used for anything other than testing */ +unsigned char batch_point_buffer[3][32]; + +static int +ge25519_is_neutral_vartime(const ge25519 *p) { + static const unsigned char zero[32] = {0}; + unsigned char point_buffer[3][32]; + curve25519_contract(point_buffer[0], p->x); + curve25519_contract(point_buffer[1], p->y); + curve25519_contract(point_buffer[2], p->z); + memcpy(batch_point_buffer[1], point_buffer[1], 32); + return (memcmp(point_buffer[0], zero, 32) == 0) && (memcmp(point_buffer[1], point_buffer[2], 32) == 0); +} + +int +ED25519_FN(ed25519_sign_open_batch) (const unsigned char **m, size_t *mlen, const unsigned char **pk, const unsigned char **RS, size_t num, int *valid) { + batch_heap ALIGN(16) batch; + ge25519 ALIGN(16) p; + bignum256modm *r_scalars; + size_t i, batchsize; + unsigned char hram[64]; + int ret = 0; + + for (i = 0; i < num; i++) + valid[i] = 1; + + while (num > 3) { + batchsize = (num > max_batch_size) ? max_batch_size : num; + + /* generate r (scalars[batchsize+1]..scalars[2*batchsize] */ + ED25519_FN(ed25519_randombytes_unsafe) (batch.r, batchsize * 16); + r_scalars = &batch.scalars[batchsize + 1]; + for (i = 0; i < batchsize; i++) + expand256_modm(r_scalars[i], batch.r[i], 16); + + /* compute scalars[0] = ((r1s1 + r2s2 + ...)) */ + for (i = 0; i < batchsize; i++) { + expand256_modm(batch.scalars[i], RS[i] + 32, 32); + mul256_modm(batch.scalars[i], batch.scalars[i], r_scalars[i]); + } + for (i = 1; i < batchsize; i++) + add256_modm(batch.scalars[0], batch.scalars[0], batch.scalars[i]); + + /* compute scalars[1]..scalars[batchsize] as r[i]*H(R[i],A[i],m[i]) */ + for (i = 0; i < batchsize; i++) { + ed25519_hram(hram, RS[i], pk[i], m[i], mlen[i]); + expand256_modm(batch.scalars[i+1], hram, 64); + mul256_modm(batch.scalars[i+1], batch.scalars[i+1], r_scalars[i]); + } + + /* compute points */ + batch.points[0] = ge25519_basepoint; + for (i = 0; i < batchsize; i++) + if (!ge25519_unpack_negative_vartime(&batch.points[i+1], pk[i])) + goto fallback; + for (i = 0; i < batchsize; i++) + if (!ge25519_unpack_negative_vartime(&batch.points[batchsize+i+1], RS[i])) + goto fallback; + + ge25519_multi_scalarmult_vartime(&p, &batch, (batchsize * 2) + 1); + if (!ge25519_is_neutral_vartime(&p)) { + ret |= 2; + + fallback: + for (i = 0; i < batchsize; i++) { + valid[i] = ED25519_FN(ed25519_sign_open) (m[i], mlen[i], pk[i], RS[i]) ? 0 : 1; + ret |= (valid[i] ^ 1); + } + } + + m += batchsize; + mlen += batchsize; + pk += batchsize; + RS += batchsize; + num -= batchsize; + valid += batchsize; + } + + for (i = 0; i < num; i++) { + valid[i] = ED25519_FN(ed25519_sign_open) (m[i], mlen[i], pk[i], RS[i]) ? 0 : 1; + ret |= (valid[i] ^ 1); + } + + return ret; +} + diff --git a/ed25519-donna/ed25519-donna-impl-base.h b/ed25519-donna/ed25519-donna-impl-base.h new file mode 100644 index 000000000..48913edcb --- /dev/null +++ b/ed25519-donna/ed25519-donna-impl-base.h @@ -0,0 +1,364 @@ +/* + conversions +*/ + +DONNA_INLINE static void +ge25519_p1p1_to_partial(ge25519 *r, const ge25519_p1p1 *p) { + curve25519_mul(r->x, p->x, p->t); + curve25519_mul(r->y, p->y, p->z); + curve25519_mul(r->z, p->z, p->t); +} + +DONNA_INLINE static void +ge25519_p1p1_to_full(ge25519 *r, const ge25519_p1p1 *p) { + curve25519_mul(r->x, p->x, p->t); + curve25519_mul(r->y, p->y, p->z); + curve25519_mul(r->z, p->z, p->t); + curve25519_mul(r->t, p->x, p->y); +} + +static void +ge25519_full_to_pniels(ge25519_pniels *p, const ge25519 *r) { + curve25519_sub(p->ysubx, r->y, r->x); + curve25519_add(p->xaddy, r->y, r->x); + curve25519_copy(p->z, r->z); + curve25519_mul(p->t2d, r->t, ge25519_ec2d); +} + +/* + adding & doubling +*/ + +static void +ge25519_add_p1p1(ge25519_p1p1 *r, const ge25519 *p, const ge25519 *q) { + bignum25519 a,b,c,d,t,u; + + curve25519_sub(a, p->y, p->x); + curve25519_add(b, p->y, p->x); + curve25519_sub(t, q->y, q->x); + curve25519_add(u, q->y, q->x); + curve25519_mul(a, a, t); + curve25519_mul(b, b, u); + curve25519_mul(c, p->t, q->t); + curve25519_mul(c, c, ge25519_ec2d); + curve25519_mul(d, p->z, q->z); + curve25519_add(d, d, d); + curve25519_sub(r->x, b, a); + curve25519_add(r->y, b, a); + curve25519_add_after_basic(r->z, d, c); + curve25519_sub_after_basic(r->t, d, c); +} + + +static void +ge25519_double_p1p1(ge25519_p1p1 *r, const ge25519 *p) { + bignum25519 a,b,c; + + curve25519_square(a, p->x); + curve25519_square(b, p->y); + curve25519_square(c, p->z); + curve25519_add_reduce(c, c, c); + curve25519_add(r->x, p->x, p->y); + curve25519_square(r->x, r->x); + curve25519_add(r->y, b, a); + curve25519_sub(r->z, b, a); + curve25519_sub_after_basic(r->x, r->x, r->y); + curve25519_sub_after_basic(r->t, c, r->z); +} + +static void +ge25519_nielsadd2_p1p1(ge25519_p1p1 *r, const ge25519 *p, const ge25519_niels *q, unsigned char signbit) { + const bignum25519 *qb = (const bignum25519 *)q; + bignum25519 *rb = (bignum25519 *)r; + bignum25519 a,b,c; + + curve25519_sub(a, p->y, p->x); + curve25519_add(b, p->y, p->x); + curve25519_mul(a, a, qb[signbit]); /* x for +, y for - */ + curve25519_mul(r->x, b, qb[signbit^1]); /* y for +, x for - */ + curve25519_add(r->y, r->x, a); + curve25519_sub(r->x, r->x, a); + curve25519_mul(c, p->t, q->t2d); + curve25519_add_reduce(r->t, p->z, p->z); + curve25519_copy(r->z, r->t); + curve25519_add(rb[2+signbit], rb[2+signbit], c); /* z for +, t for - */ + curve25519_sub(rb[2+(signbit^1)], rb[2+(signbit^1)], c); /* t for +, z for - */ +} + +static void +ge25519_pnielsadd_p1p1(ge25519_p1p1 *r, const ge25519 *p, const ge25519_pniels *q, unsigned char signbit) { + const bignum25519 *qb = (const bignum25519 *)q; + bignum25519 *rb = (bignum25519 *)r; + bignum25519 a,b,c; + + curve25519_sub(a, p->y, p->x); + curve25519_add(b, p->y, p->x); + curve25519_mul(a, a, qb[signbit]); /* ysubx for +, xaddy for - */ + curve25519_mul(r->x, b, qb[signbit^1]); /* xaddy for +, ysubx for - */ + curve25519_add(r->y, r->x, a); + curve25519_sub(r->x, r->x, a); + curve25519_mul(c, p->t, q->t2d); + curve25519_mul(r->t, p->z, q->z); + curve25519_add_reduce(r->t, r->t, r->t); + curve25519_copy(r->z, r->t); + curve25519_add(rb[2+signbit], rb[2+signbit], c); /* z for +, t for - */ + curve25519_sub(rb[2+(signbit^1)], rb[2+(signbit^1)], c); /* t for +, z for - */ +} + +static void +ge25519_double_partial(ge25519 *r, const ge25519 *p) { + ge25519_p1p1 t; + ge25519_double_p1p1(&t, p); + ge25519_p1p1_to_partial(r, &t); +} + +static void +ge25519_double(ge25519 *r, const ge25519 *p) { + ge25519_p1p1 t; + ge25519_double_p1p1(&t, p); + ge25519_p1p1_to_full(r, &t); +} + +static void +ge25519_add(ge25519 *r, const ge25519 *p, const ge25519 *q) { + ge25519_p1p1 t; + ge25519_add_p1p1(&t, p, q); + ge25519_p1p1_to_full(r, &t); +} + +static void +ge25519_nielsadd2(ge25519 *r, const ge25519_niels *q) { + bignum25519 a,b,c,e,f,g,h; + + curve25519_sub(a, r->y, r->x); + curve25519_add(b, r->y, r->x); + curve25519_mul(a, a, q->ysubx); + curve25519_mul(e, b, q->xaddy); + curve25519_add(h, e, a); + curve25519_sub(e, e, a); + curve25519_mul(c, r->t, q->t2d); + curve25519_add(f, r->z, r->z); + curve25519_add_after_basic(g, f, c); + curve25519_sub_after_basic(f, f, c); + curve25519_mul(r->x, e, f); + curve25519_mul(r->y, h, g); + curve25519_mul(r->z, g, f); + curve25519_mul(r->t, e, h); +} + +static void +ge25519_pnielsadd(ge25519_pniels *r, const ge25519 *p, const ge25519_pniels *q) { + bignum25519 a,b,c,x,y,z,t; + + curve25519_sub(a, p->y, p->x); + curve25519_add(b, p->y, p->x); + curve25519_mul(a, a, q->ysubx); + curve25519_mul(x, b, q->xaddy); + curve25519_add(y, x, a); + curve25519_sub(x, x, a); + curve25519_mul(c, p->t, q->t2d); + curve25519_mul(t, p->z, q->z); + curve25519_add(t, t, t); + curve25519_add_after_basic(z, t, c); + curve25519_sub_after_basic(t, t, c); + curve25519_mul(r->xaddy, x, t); + curve25519_mul(r->ysubx, y, z); + curve25519_mul(r->z, z, t); + curve25519_mul(r->t2d, x, y); + curve25519_copy(y, r->ysubx); + curve25519_sub(r->ysubx, r->ysubx, r->xaddy); + curve25519_add(r->xaddy, r->xaddy, y); + curve25519_mul(r->t2d, r->t2d, ge25519_ec2d); +} + + +/* + pack & unpack +*/ + +static void +ge25519_pack(unsigned char r[32], const ge25519 *p) { + bignum25519 tx, ty, zi; + unsigned char parity[32]; + curve25519_recip(zi, p->z); + curve25519_mul(tx, p->x, zi); + curve25519_mul(ty, p->y, zi); + curve25519_contract(r, ty); + curve25519_contract(parity, tx); + r[31] ^= ((parity[0] & 1) << 7); +} + +static int +ge25519_unpack_negative_vartime(ge25519 *r, const unsigned char p[32]) { + static const unsigned char zero[32] = {0}; + static const bignum25519 one = {1}; + unsigned char parity = p[31] >> 7; + unsigned char check[32]; + bignum25519 t, root, num, den, d3; + + curve25519_expand(r->y, p); + curve25519_copy(r->z, one); + curve25519_square(num, r->y); /* x = y^2 */ + curve25519_mul(den, num, ge25519_ecd); /* den = dy^2 */ + curve25519_sub_reduce(num, num, r->z); /* x = y^1 - 1 */ + curve25519_add(den, den, r->z); /* den = dy^2 + 1 */ + + /* Computation of sqrt(num/den) */ + /* 1.: computation of num^((p-5)/8)*den^((7p-35)/8) = (num*den^7)^((p-5)/8) */ + curve25519_square(t, den); + curve25519_mul(d3, t, den); + curve25519_square(r->x, d3); + curve25519_mul(r->x, r->x, den); + curve25519_mul(r->x, r->x, num); + curve25519_pow_two252m3(r->x, r->x); + + /* 2. computation of r->x = num * den^3 * (num*den^7)^((p-5)/8) */ + curve25519_mul(r->x, r->x, d3); + curve25519_mul(r->x, r->x, num); + + /* 3. Check if either of the roots works: */ + curve25519_square(t, r->x); + curve25519_mul(t, t, den); + curve25519_sub_reduce(root, t, num); + curve25519_contract(check, root); + if (!ed25519_verify(check, zero, 32)) { + curve25519_add_reduce(t, t, num); + curve25519_contract(check, t); + if (!ed25519_verify(check, zero, 32)) + return 0; + curve25519_mul(r->x, r->x, ge25519_sqrtneg1); + } + + curve25519_contract(check, r->x); + if ((check[0] & 1) == parity) { + curve25519_copy(t, r->x); + curve25519_neg(r->x, t); + } + curve25519_mul(r->t, r->x, r->y); + return 1; +} + + +/* + scalarmults +*/ + +#define S1_SWINDOWSIZE 5 +#define S1_TABLE_SIZE (1<<(S1_SWINDOWSIZE-2)) +#define S2_SWINDOWSIZE 7 +#define S2_TABLE_SIZE (1<<(S2_SWINDOWSIZE-2)) + +/* computes [s1]p1 + [s2]basepoint */ +static void +ge25519_double_scalarmult_vartime(ge25519 *r, const ge25519 *p1, const bignum256modm s1, const bignum256modm s2) { + signed char slide1[256], slide2[256]; + ge25519_pniels pre1[S1_TABLE_SIZE]; + ge25519 d1; + ge25519_p1p1 t; + int32_t i; + + contract256_slidingwindow_modm(slide1, s1, S1_SWINDOWSIZE); + contract256_slidingwindow_modm(slide2, s2, S2_SWINDOWSIZE); + + ge25519_double(&d1, p1); + ge25519_full_to_pniels(pre1, p1); + for (i = 0; i < S1_TABLE_SIZE - 1; i++) + ge25519_pnielsadd(&pre1[i+1], &d1, &pre1[i]); + + /* set neutral */ + memset(r, 0, sizeof(ge25519)); + r->y[0] = 1; + r->z[0] = 1; + + i = 255; + while ((i >= 0) && !(slide1[i] | slide2[i])) + i--; + + for (; i >= 0; i--) { + ge25519_double_p1p1(&t, r); + + if (slide1[i]) { + ge25519_p1p1_to_full(r, &t); + ge25519_pnielsadd_p1p1(&t, r, &pre1[abs(slide1[i]) / 2], (unsigned char)slide1[i] >> 7); + } + + if (slide2[i]) { + ge25519_p1p1_to_full(r, &t); + ge25519_nielsadd2_p1p1(&t, r, &ge25519_niels_sliding_multiples[abs(slide2[i]) / 2], (unsigned char)slide2[i] >> 7); + } + + ge25519_p1p1_to_partial(r, &t); + } +} + + + +#if !defined(HAVE_GE25519_SCALARMULT_BASE_CHOOSE_NIELS) + +static uint32_t +ge25519_windowb_equal(uint32_t b, uint32_t c) { + return ((b ^ c) - 1) >> 31; +} + +static void +ge25519_scalarmult_base_choose_niels(ge25519_niels *t, const uint8_t table[256][96], uint32_t pos, signed char b) { + bignum25519 neg; + uint32_t sign = (uint32_t)((unsigned char)b >> 7); + uint32_t mask = ~(sign - 1); + uint32_t u = (b + mask) ^ mask; + uint32_t i; + + /* ysubx, xaddy, t2d in packed form. initialize to ysubx = 1, xaddy = 1, t2d = 0 */ + uint8_t packed[96] = {0}; + packed[0] = 1; + packed[32] = 1; + + for (i = 0; i < 8; i++) + curve25519_move_conditional_bytes(packed, table[(pos * 8) + i], ge25519_windowb_equal(u, i + 1)); + + /* expand in to t */ + curve25519_expand(t->ysubx, packed + 0); + curve25519_expand(t->xaddy, packed + 32); + curve25519_expand(t->t2d , packed + 64); + + /* adjust for sign */ + curve25519_swap_conditional(t->ysubx, t->xaddy, sign); + curve25519_neg(neg, t->t2d); + curve25519_swap_conditional(t->t2d, neg, sign); +} + +#endif /* HAVE_GE25519_SCALARMULT_BASE_CHOOSE_NIELS */ + + +/* computes [s]basepoint */ +static void +ge25519_scalarmult_base_niels(ge25519 *r, const uint8_t basepoint_table[256][96], const bignum256modm s) { + signed char b[64]; + uint32_t i; + ge25519_niels t; + + contract256_window4_modm(b, s); + + ge25519_scalarmult_base_choose_niels(&t, basepoint_table, 0, b[1]); + curve25519_sub_reduce(r->x, t.xaddy, t.ysubx); + curve25519_add_reduce(r->y, t.xaddy, t.ysubx); + memset(r->z, 0, sizeof(bignum25519)); + curve25519_copy(r->t, t.t2d); + r->z[0] = 2; + for (i = 3; i < 64; i += 2) { + ge25519_scalarmult_base_choose_niels(&t, basepoint_table, i / 2, b[i]); + ge25519_nielsadd2(r, &t); + } + ge25519_double_partial(r, r); + ge25519_double_partial(r, r); + ge25519_double_partial(r, r); + ge25519_double(r, r); + ge25519_scalarmult_base_choose_niels(&t, basepoint_table, 0, b[0]); + curve25519_mul(t.t2d, t.t2d, ge25519_ecd); + ge25519_nielsadd2(r, &t); + for(i = 2; i < 64; i += 2) { + ge25519_scalarmult_base_choose_niels(&t, basepoint_table, i / 2, b[i]); + ge25519_nielsadd2(r, &t); + } +} + diff --git a/ed25519-donna/ed25519-donna-impl-sse2.h b/ed25519-donna/ed25519-donna-impl-sse2.h new file mode 100644 index 000000000..5fe341638 --- /dev/null +++ b/ed25519-donna/ed25519-donna-impl-sse2.h @@ -0,0 +1,390 @@ +/* + conversions +*/ + +static void +ge25519_p1p1_to_partial(ge25519 *r, const ge25519_p1p1 *p) { + packed64bignum25519 ALIGN(16) xz, tt, xzout; + curve25519_mul(r->y, p->y, p->z); + curve25519_tangle64(xz, p->x, p->z); + curve25519_tangleone64(tt, p->t); + curve25519_mul_packed64(xzout, xz, tt); + curve25519_untangle64(r->x, r->z, xzout); +} + +static void +ge25519_p1p1_to_full(ge25519 *r, const ge25519_p1p1 *p) { + packed64bignum25519 ALIGN(16) zy, xt, xx, zz, ty; + curve25519_tangle64(ty, p->t, p->y); + curve25519_tangleone64(xx, p->x); + curve25519_mul_packed64(xt, xx, ty); + curve25519_untangle64(r->x, r->t, xt); + curve25519_tangleone64(zz, p->z); + curve25519_mul_packed64(zy, zz, ty); + curve25519_untangle64(r->z, r->y, zy); +} + +static void +ge25519_full_to_pniels(ge25519_pniels *p, const ge25519 *r) { + curve25519_sub(p->ysubx, r->y, r->x); + curve25519_add(p->xaddy, r->x, r->y); + curve25519_copy(p->z, r->z); + curve25519_mul(p->t2d, r->t, ge25519_ec2d); +} + +/* + adding & doubling +*/ + +static void +ge25519_add_p1p1(ge25519_p1p1 *r, const ge25519 *p, const ge25519 *q) { + bignum25519 ALIGN(16) a,b,c,d; + packed32bignum25519 ALIGN(16) xx, yy, yypxx, yymxx, bd, ac, bdmac, bdpac; + packed64bignum25519 ALIGN(16) at, bu, atbu, ptz, qtz, cd; + + curve25519_tangle32(yy, p->y, q->y); + curve25519_tangle32(xx, p->x, q->x); + curve25519_add_packed32(yypxx, yy, xx); + curve25519_sub_packed32(yymxx, yy, xx); + curve25519_tangle64_from32(at, bu, yymxx, yypxx); + curve25519_mul_packed64(atbu, at, bu); + curve25519_untangle64(a, b, atbu); + curve25519_tangle64(ptz, p->t, p->z); + curve25519_tangle64(qtz, q->t, q->z); + curve25519_mul_packed64(cd, ptz, qtz); + curve25519_untangle64(c, d, cd); + curve25519_mul(c, c, ge25519_ec2d); + curve25519_add_reduce(d, d, d); + /* reduce, so no after_basic is needed later */ + curve25519_tangle32(bd, b, d); + curve25519_tangle32(ac, a, c); + curve25519_sub_packed32(bdmac, bd, ac); + curve25519_add_packed32(bdpac, bd, ac); + curve25519_untangle32(r->x, r->t, bdmac); + curve25519_untangle32(r->y, r->z, bdpac); +} + + +static void +ge25519_double_p1p1(ge25519_p1p1 *r, const ge25519 *p) { + bignum25519 ALIGN(16) a,b,c,x; + packed64bignum25519 ALIGN(16) xy, zx, ab, cx; + packed32bignum25519 ALIGN(16) xc, yz, xt, yc, ac, bc; + + curve25519_add(x, p->x, p->y); + curve25519_tangle64(xy, p->x, p->y); + curve25519_square_packed64(ab, xy); + curve25519_untangle64(a, b, ab); + curve25519_tangle64(zx, p->z, x); + curve25519_square_packed64(cx, zx); + curve25519_untangle64(c, x, cx); + curve25519_tangle32(bc, b, c); + curve25519_tangle32(ac, a, c); + curve25519_add_reduce_packed32(yc, bc, ac); + curve25519_untangle32(r->y, c, yc); + curve25519_sub(r->z, b, a); + curve25519_tangle32(yz, r->y, r->z); + curve25519_tangle32(xc, x, c); + curve25519_sub_after_basic_packed32(xt, xc, yz); + curve25519_untangle32(r->x, r->t, xt); +} + +static void +ge25519_nielsadd2_p1p1(ge25519_p1p1 *r, const ge25519 *p, const ge25519_niels *q, unsigned char signbit) { + const bignum25519 *qb = (const bignum25519 *)q; + bignum25519 *rb = (bignum25519 *)r; + bignum25519 ALIGN(16) a,b,c; + packed64bignum25519 ALIGN(16) ab, yx, aybx; + packed32bignum25519 ALIGN(16) bd, ac, bdac; + + curve25519_sub(a, p->y, p->x); + curve25519_add(b, p->y, p->x); + curve25519_tangle64(ab, a, b); + curve25519_tangle64(yx, qb[signbit], qb[signbit^1]); + curve25519_mul_packed64(aybx, ab, yx); + curve25519_untangle64(a, b, aybx); + curve25519_add(r->y, b, a); + curve25519_add_reduce(r->t, p->z, p->z); + curve25519_mul(c, p->t, q->t2d); + curve25519_copy(r->z, r->t); + curve25519_add(rb[2+signbit], rb[2+signbit], c); + curve25519_tangle32(bd, b, rb[2+(signbit^1)]); + curve25519_tangle32(ac, a, c); + curve25519_sub_packed32(bdac, bd, ac); + curve25519_untangle32(r->x, rb[2+(signbit^1)], bdac); +} + +static void +ge25519_pnielsadd_p1p1(ge25519_p1p1 *r, const ge25519 *p, const ge25519_pniels *q, unsigned char signbit) { + const bignum25519 *qb = (const bignum25519 *)q; + bignum25519 *rb = (bignum25519 *)r; + bignum25519 ALIGN(16) a,b,c; + packed64bignum25519 ALIGN(16) ab, yx, aybx, zt, zt2d, tc; + packed32bignum25519 ALIGN(16) bd, ac, bdac; + + curve25519_sub(a, p->y, p->x); + curve25519_add(b, p->y, p->x); + curve25519_tangle64(ab, a, b); + curve25519_tangle64(yx, qb[signbit], qb[signbit^1]); + curve25519_mul_packed64(aybx, ab, yx); + curve25519_untangle64(a, b, aybx); + curve25519_add(r->y, b, a); + curve25519_tangle64(zt, p->z, p->t); + curve25519_tangle64(zt2d, q->z, q->t2d); + curve25519_mul_packed64(tc, zt, zt2d); + curve25519_untangle64(r->t, c, tc); + curve25519_add_reduce(r->t, r->t, r->t); + curve25519_copy(r->z, r->t); + curve25519_add(rb[2+signbit], rb[2+signbit], c); + curve25519_tangle32(bd, b, rb[2+(signbit^1)]); + curve25519_tangle32(ac, a, c); + curve25519_sub_packed32(bdac, bd, ac); + curve25519_untangle32(r->x, rb[2+(signbit^1)], bdac); +} + +static void +ge25519_double(ge25519 *r, const ge25519 *p) { + ge25519_p1p1 ALIGN(16) t; + ge25519_double_p1p1(&t, p); + ge25519_p1p1_to_full(r, &t); +} + +static void +ge25519_add(ge25519 *r, const ge25519 *p, const ge25519 *q) { + ge25519_p1p1 ALIGN(16) t; + ge25519_add_p1p1(&t, p, q); + ge25519_p1p1_to_full(r, &t); +} + +static void +ge25519_double_partial(ge25519 *r, const ge25519 *p) { + ge25519_p1p1 ALIGN(16) t; + ge25519_double_p1p1(&t, p); + ge25519_p1p1_to_partial(r, &t); +} + +static void +ge25519_nielsadd2(ge25519 *r, const ge25519_niels *q) { + packed64bignum25519 ALIGN(16) ab, yx, aybx, eg, ff, hh, xz, ty; + packed32bignum25519 ALIGN(16) bd, ac, bdac; + bignum25519 ALIGN(16) a,b,c,d,e,f,g,h; + + curve25519_sub(a, r->y, r->x); + curve25519_add(b, r->y, r->x); + curve25519_tangle64(ab, a, b); + curve25519_tangle64(yx, q->ysubx, q->xaddy); + curve25519_mul_packed64(aybx, ab, yx); + curve25519_untangle64(a, b, aybx); + curve25519_add(h, b, a); + curve25519_add_reduce(d, r->z, r->z); + curve25519_mul(c, r->t, q->t2d); + curve25519_add(g, d, c); /* d is reduced, so no need for after_basic */ + curve25519_tangle32(bd, b, d); + curve25519_tangle32(ac, a, c); + curve25519_sub_packed32(bdac, bd, ac); /* d is reduced, so no need for after_basic */ + curve25519_untangle32(e, f, bdac); + curve25519_tangle64(eg, e, g); + curve25519_tangleone64(ff, f); + curve25519_mul_packed64(xz, eg, ff); + curve25519_untangle64(r->x, r->z, xz); + curve25519_tangleone64(hh, h); + curve25519_mul_packed64(ty, eg, hh); + curve25519_untangle64(r->t, r->y, ty); +} + +static void +ge25519_pnielsadd(ge25519_pniels *r, const ge25519 *p, const ge25519_pniels *q) { + ge25519_p1p1 ALIGN(16) t; + ge25519 ALIGN(16) f; + ge25519_pnielsadd_p1p1(&t, p, q, 0); + ge25519_p1p1_to_full(&f, &t); + ge25519_full_to_pniels(r, &f); +} + +/* + pack & unpack +*/ + +static void +ge25519_pack(unsigned char r[32], const ge25519 *p) { + bignum25519 ALIGN(16) tx, ty, zi; + unsigned char parity[32]; + curve25519_recip(zi, p->z); + curve25519_mul(tx, p->x, zi); + curve25519_mul(ty, p->y, zi); + curve25519_contract(r, ty); + curve25519_contract(parity, tx); + r[31] ^= ((parity[0] & 1) << 7); +} + + +static int +ge25519_unpack_negative_vartime(ge25519 *r, const unsigned char p[32]) { + static const bignum25519 ALIGN(16) one = {1}; + static const unsigned char zero[32] = {0}; + unsigned char parity = p[31] >> 7; + unsigned char check[32]; + bignum25519 ALIGN(16) t, root, num, den, d3; + + curve25519_expand(r->y, p); + curve25519_copy(r->z, one); + curve25519_square_times(num, r->y, 1); /* x = y^2 */ + curve25519_mul(den, num, ge25519_ecd); /* den = dy^2 */ + curve25519_sub_reduce(num, num, r->z); /* x = y^2 - 1 */ + curve25519_add(den, den, r->z); /* den = dy^2 + 1 */ + + /* Computation of sqrt(num/den) */ + /* 1.: computation of num^((p-5)/8)*den^((7p-35)/8) = (num*den^7)^((p-5)/8) */ + curve25519_square_times(t, den, 1); + curve25519_mul(d3, t, den); + curve25519_square_times(r->x, d3, 1); + curve25519_mul(r->x, r->x, den); + curve25519_mul(r->x, r->x, num); + curve25519_pow_two252m3(r->x, r->x); + + /* 2. computation of r->x = t * num * den^3 */ + curve25519_mul(r->x, r->x, d3); + curve25519_mul(r->x, r->x, num); + + /* 3. Check if either of the roots works: */ + curve25519_square_times(t, r->x, 1); + curve25519_mul(t, t, den); + curve25519_copy(root, t); + curve25519_sub_reduce(root, root, num); + curve25519_contract(check, root); + if (!ed25519_verify(check, zero, 32)) { + curve25519_add_reduce(t, t, num); + curve25519_contract(check, t); + if (!ed25519_verify(check, zero, 32)) + return 0; + curve25519_mul(r->x, r->x, ge25519_sqrtneg1); + } + + curve25519_contract(check, r->x); + if ((check[0] & 1) == parity) { + curve25519_copy(t, r->x); + curve25519_neg(r->x, t); + } + curve25519_mul(r->t, r->x, r->y); + return 1; +} + + + +/* + scalarmults +*/ + +#define S1_SWINDOWSIZE 5 +#define S1_TABLE_SIZE (1<<(S1_SWINDOWSIZE-2)) +#define S2_SWINDOWSIZE 7 +#define S2_TABLE_SIZE (1<<(S2_SWINDOWSIZE-2)) + +static void +ge25519_double_scalarmult_vartime(ge25519 *r, const ge25519 *p1, const bignum256modm s1, const bignum256modm s2) { + signed char slide1[256], slide2[256]; + ge25519_pniels ALIGN(16) pre1[S1_TABLE_SIZE]; + ge25519 ALIGN(16) d1; + ge25519_p1p1 ALIGN(16) t; + int32_t i; + + contract256_slidingwindow_modm(slide1, s1, S1_SWINDOWSIZE); + contract256_slidingwindow_modm(slide2, s2, S2_SWINDOWSIZE); + + ge25519_double(&d1, p1); + ge25519_full_to_pniels(pre1, p1); + for (i = 0; i < S1_TABLE_SIZE - 1; i++) + ge25519_pnielsadd(&pre1[i+1], &d1, &pre1[i]); + + /* set neutral */ + memset(r, 0, sizeof(ge25519)); + r->y[0] = 1; + r->z[0] = 1; + + i = 255; + while ((i >= 0) && !(slide1[i] | slide2[i])) + i--; + + for (; i >= 0; i--) { + ge25519_double_p1p1(&t, r); + + if (slide1[i]) { + ge25519_p1p1_to_full(r, &t); + ge25519_pnielsadd_p1p1(&t, r, &pre1[abs(slide1[i]) / 2], (unsigned char)slide1[i] >> 7); + } + + if (slide2[i]) { + ge25519_p1p1_to_full(r, &t); + ge25519_nielsadd2_p1p1(&t, r, &ge25519_niels_sliding_multiples[abs(slide2[i]) / 2], (unsigned char)slide2[i] >> 7); + } + + ge25519_p1p1_to_partial(r, &t); + } +} + +#if !defined(HAVE_GE25519_SCALARMULT_BASE_CHOOSE_NIELS) + +static uint32_t +ge25519_windowb_equal(uint32_t b, uint32_t c) { + return ((b ^ c) - 1) >> 31; +} + +static void +ge25519_scalarmult_base_choose_niels(ge25519_niels *t, const uint8_t table[256][96], uint32_t pos, signed char b) { + bignum25519 ALIGN(16) neg; + uint32_t sign = (uint32_t)((unsigned char)b >> 7); + uint32_t mask = ~(sign - 1); + uint32_t u = (b + mask) ^ mask; + uint32_t i; + + /* ysubx, xaddy, t2d in packed form. initialize to ysubx = 1, xaddy = 1, t2d = 0 */ + uint8_t ALIGN(16) packed[96] = {0}; + packed[0] = 1; + packed[32] = 1; + + for (i = 0; i < 8; i++) + curve25519_move_conditional_bytes(packed, table[(pos * 8) + i], ge25519_windowb_equal(u, i + 1)); + + /* expand in to t */ + curve25519_expand(t->ysubx, packed + 0); + curve25519_expand(t->xaddy, packed + 32); + curve25519_expand(t->t2d , packed + 64); + + /* adjust for sign */ + curve25519_swap_conditional(t->ysubx, t->xaddy, sign); + curve25519_neg(neg, t->t2d); + curve25519_swap_conditional(t->t2d, neg, sign); +} + +#endif /* HAVE_GE25519_SCALARMULT_BASE_CHOOSE_NIELS */ + +static void +ge25519_scalarmult_base_niels(ge25519 *r, const uint8_t table[256][96], const bignum256modm s) { + signed char b[64]; + uint32_t i; + ge25519_niels ALIGN(16) t; + + contract256_window4_modm(b, s); + + ge25519_scalarmult_base_choose_niels(&t, table, 0, b[1]); + curve25519_sub_reduce(r->x, t.xaddy, t.ysubx); + curve25519_add_reduce(r->y, t.xaddy, t.ysubx); + memset(r->z, 0, sizeof(bignum25519)); + r->z[0] = 2; + curve25519_copy(r->t, t.t2d); + for (i = 3; i < 64; i += 2) { + ge25519_scalarmult_base_choose_niels(&t, table, i / 2, b[i]); + ge25519_nielsadd2(r, &t); + } + ge25519_double_partial(r, r); + ge25519_double_partial(r, r); + ge25519_double_partial(r, r); + ge25519_double(r, r); + ge25519_scalarmult_base_choose_niels(&t, table, 0, b[0]); + curve25519_mul(t.t2d, t.t2d, ge25519_ecd); + ge25519_nielsadd2(r, &t); + for(i = 2; i < 64; i += 2) { + ge25519_scalarmult_base_choose_niels(&t, table, i / 2, b[i]); + ge25519_nielsadd2(r, &t); + } +} diff --git a/ed25519-donna/ed25519-donna-portable-identify.h b/ed25519-donna/ed25519-donna-portable-identify.h new file mode 100644 index 000000000..26a264cf9 --- /dev/null +++ b/ed25519-donna/ed25519-donna-portable-identify.h @@ -0,0 +1,103 @@ +/* os */ +#if defined(_WIN32) || defined(_WIN64) || defined(__TOS_WIN__) || defined(__WINDOWS__) + #define OS_WINDOWS +#elif defined(sun) || defined(__sun) || defined(__SVR4) || defined(__svr4__) + #define OS_SOLARIS +#else + #include /* need this to define BSD */ + #define OS_NIX + #if defined(__linux__) + #define OS_LINUX + #elif defined(BSD) + #define OS_BSD + #if defined(MACOS_X) || (defined(__APPLE__) & defined(__MACH__)) + #define OS_OSX + #elif defined(macintosh) || defined(Macintosh) + #define OS_MAC + #elif defined(__OpenBSD__) + #define OS_OPENBSD + #endif + #endif +#endif + + +/* compiler */ +#if defined(_MSC_VER) + #define COMPILER_MSVC +#endif +#if defined(__ICC) + #define COMPILER_INTEL +#endif +#if defined(__GNUC__) + #if (__GNUC__ >= 3) + #define COMPILER_GCC ((__GNUC__ * 10000) + (__GNUC_MINOR__ * 100) + (__GNUC_PATCHLEVEL__)) + #else + #define COMPILER_GCC ((__GNUC__ * 10000) + (__GNUC_MINOR__ * 100) ) + #endif +#endif +#if defined(__PATHCC__) + #define COMPILER_PATHCC +#endif +#if defined(__clang__) + #define COMPILER_CLANG ((__clang_major__ * 10000) + (__clang_minor__ * 100) + (__clang_patchlevel__)) +#endif + + + +/* cpu */ +#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__ ) || defined(_M_X64) + #define CPU_X86_64 +#elif defined(__i586__) || defined(__i686__) || (defined(_M_IX86) && (_M_IX86 >= 500)) + #define CPU_X86 500 +#elif defined(__i486__) || (defined(_M_IX86) && (_M_IX86 >= 400)) + #define CPU_X86 400 +#elif defined(__i386__) || (defined(_M_IX86) && (_M_IX86 >= 300)) || defined(__X86__) || defined(_X86_) || defined(__I86__) + #define CPU_X86 300 +#elif defined(__ia64__) || defined(_IA64) || defined(__IA64__) || defined(_M_IA64) || defined(__ia64) + #define CPU_IA64 +#endif + +#if defined(__sparc__) || defined(__sparc) || defined(__sparcv9) + #define CPU_SPARC + #if defined(__sparcv9) + #define CPU_SPARC64 + #endif +#endif + +#if defined(powerpc) || defined(__PPC__) || defined(__ppc__) || defined(_ARCH_PPC) || defined(__powerpc__) || defined(__powerpc) || defined(POWERPC) || defined(_M_PPC) + #define CPU_PPC + #if defined(_ARCH_PWR7) + #define CPU_POWER7 + #elif defined(__64BIT__) + #define CPU_PPC64 + #else + #define CPU_PPC32 + #endif +#endif + +#if defined(__hppa__) || defined(__hppa) + #define CPU_HPPA +#endif + +#if defined(__alpha__) || defined(__alpha) || defined(_M_ALPHA) + #define CPU_ALPHA +#endif + +/* 64 bit cpu */ +#if defined(CPU_X86_64) || defined(CPU_IA64) || defined(CPU_SPARC64) || defined(__64BIT__) || defined(__LP64__) || defined(_LP64) || (defined(_MIPS_SZLONG) && (_MIPS_SZLONG == 64)) + #define CPU_64BITS +#endif + +#if defined(COMPILER_MSVC) + typedef signed char int8_t; + typedef unsigned char uint8_t; + typedef signed short int16_t; + typedef unsigned short uint16_t; + typedef signed int int32_t; + typedef unsigned int uint32_t; + typedef signed __int64 int64_t; + typedef unsigned __int64 uint64_t; +#else + #include +#endif + diff --git a/ed25519-donna/ed25519-donna-portable.h b/ed25519-donna/ed25519-donna-portable.h new file mode 100644 index 000000000..0a0f7fc3a --- /dev/null +++ b/ed25519-donna/ed25519-donna-portable.h @@ -0,0 +1,135 @@ +#include "ed25519-donna-portable-identify.h" + +#define mul32x32_64(a,b) (((uint64_t)(a))*(b)) + +/* platform */ +#if defined(COMPILER_MSVC) + #include + #if !defined(_DEBUG) + #undef mul32x32_64 + #define mul32x32_64(a,b) __emulu(a,b) + #endif + #undef inline + #define inline __forceinline + #define DONNA_INLINE __forceinline + #define DONNA_NOINLINE __declspec(noinline) + #define ALIGN(x) __declspec(align(x)) + #define ROTL32(a,b) _rotl(a,b) + #define ROTR32(a,b) _rotr(a,b) +#else + #include + #define DONNA_INLINE inline __attribute__((always_inline)) + #define DONNA_NOINLINE __attribute__((noinline)) + #define ALIGN(x) __attribute__((aligned(x))) + #define ROTL32(a,b) (((a) << (b)) | ((a) >> (32 - b))) + #define ROTR32(a,b) (((a) >> (b)) | ((a) << (32 - b))) +#endif + +/* uint128_t */ +#if defined(CPU_64BITS) && !defined(ED25519_FORCE_32BIT) + #if defined(COMPILER_CLANG) && (COMPILER_CLANG >= 30100) + #define HAVE_NATIVE_UINT128 + typedef unsigned __int128 uint128_t; + #elif defined(COMPILER_MSVC) + #define HAVE_UINT128 + typedef struct uint128_t { + uint64_t lo, hi; + } uint128_t; + #define mul64x64_128(out,a,b) out.lo = _umul128(a,b,&out.hi); + #define shr128_pair(out,hi,lo,shift) out = __shiftright128(lo, hi, shift); + #define shl128_pair(out,hi,lo,shift) out = __shiftleft128(lo, hi, shift); + #define shr128(out,in,shift) shr128_pair(out, in.hi, in.lo, shift) + #define shl128(out,in,shift) shl128_pair(out, in.hi, in.lo, shift) + #define add128(a,b) { uint64_t p = a.lo; a.lo += b.lo; a.hi += b.hi + (a.lo < p); } + #define add128_64(a,b) { uint64_t p = a.lo; a.lo += b; a.hi += (a.lo < p); } + #define lo128(a) (a.lo) + #define hi128(a) (a.hi) + #elif defined(COMPILER_GCC) && !defined(HAVE_NATIVE_UINT128) + #if defined(__SIZEOF_INT128__) + #define HAVE_NATIVE_UINT128 + typedef unsigned __int128 uint128_t; + #elif (COMPILER_GCC >= 40400) + #define HAVE_NATIVE_UINT128 + typedef unsigned uint128_t __attribute__((mode(TI))); + #elif defined(CPU_X86_64) + #define HAVE_UINT128 + typedef struct uint128_t { + uint64_t lo, hi; + } uint128_t; + #define mul64x64_128(out,a,b) __asm__ ("mulq %3" : "=a" (out.lo), "=d" (out.hi) : "a" (a), "rm" (b)); + #define shr128_pair(out,hi,lo,shift) __asm__ ("shrdq %2,%1,%0" : "+r" (lo) : "r" (hi), "J" (shift)); out = lo; + #define shl128_pair(out,hi,lo,shift) __asm__ ("shldq %2,%1,%0" : "+r" (hi) : "r" (lo), "J" (shift)); out = hi; + #define shr128(out,in,shift) shr128_pair(out,in.hi, in.lo, shift) + #define shl128(out,in,shift) shl128_pair(out,in.hi, in.lo, shift) + #define add128(a,b) __asm__ ("addq %4,%2; adcq %5,%3" : "=r" (a.hi), "=r" (a.lo) : "1" (a.lo), "0" (a.hi), "rm" (b.lo), "rm" (b.hi) : "cc"); + #define add128_64(a,b) __asm__ ("addq %4,%2; adcq $0,%3" : "=r" (a.hi), "=r" (a.lo) : "1" (a.lo), "0" (a.hi), "rm" (b) : "cc"); + #define lo128(a) (a.lo) + #define hi128(a) (a.hi) + #endif + #endif + + #if defined(HAVE_NATIVE_UINT128) + #define HAVE_UINT128 + #define mul64x64_128(out,a,b) out = (uint128_t)a * b; + #define shr128_pair(out,hi,lo,shift) out = (uint64_t)((((uint128_t)hi << 64) | lo) >> (shift)); + #define shl128_pair(out,hi,lo,shift) out = (uint64_t)(((((uint128_t)hi << 64) | lo) << (shift)) >> 64); + #define shr128(out,in,shift) out = (uint64_t)(in >> (shift)); + #define shl128(out,in,shift) out = (uint64_t)((in << shift) >> 64); + #define add128(a,b) a += b; + #define add128_64(a,b) a += (uint64_t)b; + #define lo128(a) ((uint64_t)a) + #define hi128(a) ((uint64_t)(a >> 64)) + #endif + + #if !defined(HAVE_UINT128) + #error Need a uint128_t implementation! + #endif +#endif + +/* endian */ +#if !defined(ED25519_OPENSSLRNG) +static inline void U32TO8_LE(unsigned char *p, const uint32_t v) { + p[0] = (unsigned char)(v ); + p[1] = (unsigned char)(v >> 8); + p[2] = (unsigned char)(v >> 16); + p[3] = (unsigned char)(v >> 24); +} +#endif + +#if !defined(HAVE_UINT128) +static inline uint32_t U8TO32_LE(const unsigned char *p) { + return + (((uint32_t)(p[0]) ) | + ((uint32_t)(p[1]) << 8) | + ((uint32_t)(p[2]) << 16) | + ((uint32_t)(p[3]) << 24)); +} +#else +static inline uint64_t U8TO64_LE(const unsigned char *p) { + return + (((uint64_t)(p[0]) ) | + ((uint64_t)(p[1]) << 8) | + ((uint64_t)(p[2]) << 16) | + ((uint64_t)(p[3]) << 24) | + ((uint64_t)(p[4]) << 32) | + ((uint64_t)(p[5]) << 40) | + ((uint64_t)(p[6]) << 48) | + ((uint64_t)(p[7]) << 56)); +} + +static inline void U64TO8_LE(unsigned char *p, const uint64_t v) { + p[0] = (unsigned char)(v ); + p[1] = (unsigned char)(v >> 8); + p[2] = (unsigned char)(v >> 16); + p[3] = (unsigned char)(v >> 24); + p[4] = (unsigned char)(v >> 32); + p[5] = (unsigned char)(v >> 40); + p[6] = (unsigned char)(v >> 48); + p[7] = (unsigned char)(v >> 56); +} +#endif + +#include +#include + + diff --git a/ed25519-donna/ed25519-donna.h b/ed25519-donna/ed25519-donna.h new file mode 100644 index 000000000..de1120f46 --- /dev/null +++ b/ed25519-donna/ed25519-donna.h @@ -0,0 +1,115 @@ +/* + Public domain by Andrew M. + Modified from the amd64-51-30k implementation by + Daniel J. Bernstein + Niels Duif + Tanja Lange + Peter Schwabe + Bo-Yin Yang +*/ + + +#include "ed25519-donna-portable.h" + +#if defined(ED25519_SSE2) +#else + #if defined(HAVE_UINT128) && !defined(ED25519_FORCE_32BIT) + #define ED25519_64BIT + #else + #define ED25519_32BIT + #endif +#endif + +#if !defined(ED25519_NO_INLINE_ASM) + /* detect extra features first so un-needed functions can be disabled throughout */ + #if defined(ED25519_SSE2) + #if defined(COMPILER_GCC) && defined(CPU_X86) + #define ED25519_GCC_32BIT_SSE_CHOOSE + #elif defined(COMPILER_GCC) && defined(CPU_X86_64) + #define ED25519_GCC_64BIT_SSE_CHOOSE + #endif + #else + #if defined(CPU_X86_64) + #if defined(COMPILER_GCC) + #if defined(ED25519_64BIT) + #define ED25519_GCC_64BIT_X86_CHOOSE + #else + #define ED25519_GCC_64BIT_32BIT_CHOOSE + #endif + #endif + #endif + #endif +#endif + +#if defined(ED25519_SSE2) + #include "curve25519-donna-sse2.h" +#elif defined(ED25519_64BIT) + #include "curve25519-donna-64bit.h" +#else + #include "curve25519-donna-32bit.h" +#endif + +#include "curve25519-donna-helpers.h" + +/* separate uint128 check for 64 bit sse2 */ +#if defined(HAVE_UINT128) && !defined(ED25519_FORCE_32BIT) + #include "modm-donna-64bit.h" +#else + #include "modm-donna-32bit.h" +#endif + +typedef unsigned char hash_512bits[64]; + +/* + Timing safe memory compare +*/ +static int +ed25519_verify(const unsigned char *x, const unsigned char *y, size_t len) { + size_t differentbits = 0; + while (len--) + differentbits |= (*x++ ^ *y++); + return (int) (1 & ((differentbits - 1) >> 8)); +} + + +/* + * Arithmetic on the twisted Edwards curve -x^2 + y^2 = 1 + dx^2y^2 + * with d = -(121665/121666) = 37095705934669439343138083508754565189542113879843219016388785533085940283555 + * Base point: (15112221349535400772501151409588531511454012693041857206046113283949847762202,46316835694926478169428394003475163141307993866256225615783033603165251855960); + */ + +typedef struct ge25519_t { + bignum25519 x, y, z, t; +} ge25519; + +typedef struct ge25519_p1p1_t { + bignum25519 x, y, z, t; +} ge25519_p1p1; + +typedef struct ge25519_niels_t { + bignum25519 ysubx, xaddy, t2d; +} ge25519_niels; + +typedef struct ge25519_pniels_t { + bignum25519 ysubx, xaddy, z, t2d; +} ge25519_pniels; + +#include "ed25519-donna-basepoint-table.h" + +#if defined(ED25519_64BIT) + #include "ed25519-donna-64bit-tables.h" + #include "ed25519-donna-64bit-x86.h" +#else + #include "ed25519-donna-32bit-tables.h" + #include "ed25519-donna-64bit-x86-32bit.h" +#endif + + +#if defined(ED25519_SSE2) + #include "ed25519-donna-32bit-sse2.h" + #include "ed25519-donna-64bit-sse2.h" + #include "ed25519-donna-impl-sse2.h" +#else + #include "ed25519-donna-impl-base.h" +#endif + diff --git a/ed25519-donna/ed25519-hash-custom.h b/ed25519-donna/ed25519-hash-custom.h new file mode 100644 index 000000000..119f43eaa --- /dev/null +++ b/ed25519-donna/ed25519-hash-custom.h @@ -0,0 +1,18 @@ +/* + a custom hash must have a 512bit digest and implement: + + struct ed25519_hash_context; + + void ed25519_hash_init(ed25519_hash_context *ctx); + void ed25519_hash_update(ed25519_hash_context *ctx, const uint8_t *in, size_t inlen); + void ed25519_hash_final(ed25519_hash_context *ctx, uint8_t *hash); + void ed25519_hash(uint8_t *hash, const uint8_t *in, size_t inlen); +*/ + +#include "sha2.h" + +#define ed25519_hash_context SHA512_CTX +#define ed25519_hash_init(ctx) sha512_Init(ctx) +#define ed25519_hash_update(ctx, in, inlen) sha512_Update((ctx), (in), (inlen)) +#define ed25519_hash_final(ctx, hash) sha512_Final((hash), (ctx)) +#define ed25519_hash(hash, in, inlen) sha512_Raw((in), (inlen), (hash)) diff --git a/ed25519-donna/ed25519-hash.h b/ed25519-donna/ed25519-hash.h new file mode 100644 index 000000000..6ba8f5238 --- /dev/null +++ b/ed25519-donna/ed25519-hash.h @@ -0,0 +1,219 @@ +#if defined(ED25519_REFHASH) + +/* reference/slow SHA-512. really, do not use this */ + +#define HASH_BLOCK_SIZE 128 +#define HASH_DIGEST_SIZE 64 + +typedef struct sha512_state_t { + uint64_t H[8]; + uint64_t T[2]; + uint32_t leftover; + uint8_t buffer[HASH_BLOCK_SIZE]; +} sha512_state; + +typedef sha512_state ed25519_hash_context; + +static const uint64_t sha512_constants[80] = { + 0x428a2f98d728ae22ull, 0x7137449123ef65cdull, 0xb5c0fbcfec4d3b2full, 0xe9b5dba58189dbbcull, + 0x3956c25bf348b538ull, 0x59f111f1b605d019ull, 0x923f82a4af194f9bull, 0xab1c5ed5da6d8118ull, + 0xd807aa98a3030242ull, 0x12835b0145706fbeull, 0x243185be4ee4b28cull, 0x550c7dc3d5ffb4e2ull, + 0x72be5d74f27b896full, 0x80deb1fe3b1696b1ull, 0x9bdc06a725c71235ull, 0xc19bf174cf692694ull, + 0xe49b69c19ef14ad2ull, 0xefbe4786384f25e3ull, 0x0fc19dc68b8cd5b5ull, 0x240ca1cc77ac9c65ull, + 0x2de92c6f592b0275ull, 0x4a7484aa6ea6e483ull, 0x5cb0a9dcbd41fbd4ull, 0x76f988da831153b5ull, + 0x983e5152ee66dfabull, 0xa831c66d2db43210ull, 0xb00327c898fb213full, 0xbf597fc7beef0ee4ull, + 0xc6e00bf33da88fc2ull, 0xd5a79147930aa725ull, 0x06ca6351e003826full, 0x142929670a0e6e70ull, + 0x27b70a8546d22ffcull, 0x2e1b21385c26c926ull, 0x4d2c6dfc5ac42aedull, 0x53380d139d95b3dfull, + 0x650a73548baf63deull, 0x766a0abb3c77b2a8ull, 0x81c2c92e47edaee6ull, 0x92722c851482353bull, + 0xa2bfe8a14cf10364ull, 0xa81a664bbc423001ull, 0xc24b8b70d0f89791ull, 0xc76c51a30654be30ull, + 0xd192e819d6ef5218ull, 0xd69906245565a910ull, 0xf40e35855771202aull, 0x106aa07032bbd1b8ull, + 0x19a4c116b8d2d0c8ull, 0x1e376c085141ab53ull, 0x2748774cdf8eeb99ull, 0x34b0bcb5e19b48a8ull, + 0x391c0cb3c5c95a63ull, 0x4ed8aa4ae3418acbull, 0x5b9cca4f7763e373ull, 0x682e6ff3d6b2b8a3ull, + 0x748f82ee5defb2fcull, 0x78a5636f43172f60ull, 0x84c87814a1f0ab72ull, 0x8cc702081a6439ecull, + 0x90befffa23631e28ull, 0xa4506cebde82bde9ull, 0xbef9a3f7b2c67915ull, 0xc67178f2e372532bull, + 0xca273eceea26619cull, 0xd186b8c721c0c207ull, 0xeada7dd6cde0eb1eull, 0xf57d4f7fee6ed178ull, + 0x06f067aa72176fbaull, 0x0a637dc5a2c898a6ull, 0x113f9804bef90daeull, 0x1b710b35131c471bull, + 0x28db77f523047d84ull, 0x32caab7b40c72493ull, 0x3c9ebe0a15c9bebcull, 0x431d67c49c100d4cull, + 0x4cc5d4becb3e42b6ull, 0x597f299cfc657e2aull, 0x5fcb6fab3ad6faecull, 0x6c44198c4a475817ull +}; + +static uint64_t +sha512_ROTR64(uint64_t x, int k) { + return (x >> k) | (x << (64 - k)); +} + +static uint64_t +sha512_LOAD64_BE(const uint8_t *p) { + return + ((uint64_t)p[0] << 56) | + ((uint64_t)p[1] << 48) | + ((uint64_t)p[2] << 40) | + ((uint64_t)p[3] << 32) | + ((uint64_t)p[4] << 24) | + ((uint64_t)p[5] << 16) | + ((uint64_t)p[6] << 8) | + ((uint64_t)p[7] ); +} + +static void +sha512_STORE64_BE(uint8_t *p, uint64_t v) { + p[0] = (uint8_t)(v >> 56); + p[1] = (uint8_t)(v >> 48); + p[2] = (uint8_t)(v >> 40); + p[3] = (uint8_t)(v >> 32); + p[4] = (uint8_t)(v >> 24); + p[5] = (uint8_t)(v >> 16); + p[6] = (uint8_t)(v >> 8); + p[7] = (uint8_t)(v ); +} + +#define Ch(x,y,z) (z ^ (x & (y ^ z))) +#define Maj(x,y,z) (((x | y) & z) | (x & y)) +#define S0(x) (sha512_ROTR64(x, 28) ^ sha512_ROTR64(x, 34) ^ sha512_ROTR64(x, 39)) +#define S1(x) (sha512_ROTR64(x, 14) ^ sha512_ROTR64(x, 18) ^ sha512_ROTR64(x, 41)) +#define G0(x) (sha512_ROTR64(x, 1) ^ sha512_ROTR64(x, 8) ^ (x >> 7)) +#define G1(x) (sha512_ROTR64(x, 19) ^ sha512_ROTR64(x, 61) ^ (x >> 6)) +#define W0(in,i) (sha512_LOAD64_BE(&in[i * 8])) +#define W1(i) (G1(w[i - 2]) + w[i - 7] + G0(w[i - 15]) + w[i - 16]) +#define STEP(i) \ + t1 = S0(r[0]) + Maj(r[0], r[1], r[2]); \ + t0 = r[7] + S1(r[4]) + Ch(r[4], r[5], r[6]) + sha512_constants[i] + w[i]; \ + r[7] = r[6]; \ + r[6] = r[5]; \ + r[5] = r[4]; \ + r[4] = r[3] + t0; \ + r[3] = r[2]; \ + r[2] = r[1]; \ + r[1] = r[0]; \ + r[0] = t0 + t1; + +static void +sha512_blocks(sha512_state *S, const uint8_t *in, size_t blocks) { + uint64_t r[8], w[80], t0, t1; + size_t i; + + for (i = 0; i < 8; i++) r[i] = S->H[i]; + + while (blocks--) { + for (i = 0; i < 16; i++) { w[i] = W0(in, i); } + for (i = 16; i < 80; i++) { w[i] = W1(i); } + for (i = 0; i < 80; i++) { STEP(i); } + for (i = 0; i < 8; i++) { r[i] += S->H[i]; S->H[i] = r[i]; } + S->T[0] += HASH_BLOCK_SIZE * 8; + S->T[1] += (!S->T[0]) ? 1 : 0; + in += HASH_BLOCK_SIZE; + } +} + +static void +ed25519_hash_init(sha512_state *S) { + S->H[0] = 0x6a09e667f3bcc908ull; + S->H[1] = 0xbb67ae8584caa73bull; + S->H[2] = 0x3c6ef372fe94f82bull; + S->H[3] = 0xa54ff53a5f1d36f1ull; + S->H[4] = 0x510e527fade682d1ull; + S->H[5] = 0x9b05688c2b3e6c1full; + S->H[6] = 0x1f83d9abfb41bd6bull; + S->H[7] = 0x5be0cd19137e2179ull; + S->T[0] = 0; + S->T[1] = 0; + S->leftover = 0; +} + +static void +ed25519_hash_update(sha512_state *S, const uint8_t *in, size_t inlen) { + size_t blocks, want; + + /* handle the previous data */ + if (S->leftover) { + want = (HASH_BLOCK_SIZE - S->leftover); + want = (want < inlen) ? want : inlen; + memcpy(S->buffer + S->leftover, in, want); + S->leftover += (uint32_t)want; + if (S->leftover < HASH_BLOCK_SIZE) + return; + in += want; + inlen -= want; + sha512_blocks(S, S->buffer, 1); + } + + /* handle the current data */ + blocks = (inlen & ~(HASH_BLOCK_SIZE - 1)); + S->leftover = (uint32_t)(inlen - blocks); + if (blocks) { + sha512_blocks(S, in, blocks / HASH_BLOCK_SIZE); + in += blocks; + } + + /* handle leftover data */ + if (S->leftover) + memcpy(S->buffer, in, S->leftover); +} + +static void +ed25519_hash_final(sha512_state *S, uint8_t *hash) { + uint64_t t0 = S->T[0] + (S->leftover * 8), t1 = S->T[1]; + + S->buffer[S->leftover] = 0x80; + if (S->leftover <= 111) { + memset(S->buffer + S->leftover + 1, 0, 111 - S->leftover); + } else { + memset(S->buffer + S->leftover + 1, 0, 127 - S->leftover); + sha512_blocks(S, S->buffer, 1); + memset(S->buffer, 0, 112); + } + + sha512_STORE64_BE(S->buffer + 112, t1); + sha512_STORE64_BE(S->buffer + 120, t0); + sha512_blocks(S, S->buffer, 1); + + sha512_STORE64_BE(&hash[ 0], S->H[0]); + sha512_STORE64_BE(&hash[ 8], S->H[1]); + sha512_STORE64_BE(&hash[16], S->H[2]); + sha512_STORE64_BE(&hash[24], S->H[3]); + sha512_STORE64_BE(&hash[32], S->H[4]); + sha512_STORE64_BE(&hash[40], S->H[5]); + sha512_STORE64_BE(&hash[48], S->H[6]); + sha512_STORE64_BE(&hash[56], S->H[7]); +} + +static void +ed25519_hash(uint8_t *hash, const uint8_t *in, size_t inlen) { + ed25519_hash_context ctx; + ed25519_hash_init(&ctx); + ed25519_hash_update(&ctx, in, inlen); + ed25519_hash_final(&ctx, hash); +} + +#elif defined(ED25519_CUSTOMHASH) + +#include "ed25519-hash-custom.h" + +#else + +#include + +typedef SHA512_CTX ed25519_hash_context; + +static void +ed25519_hash_init(ed25519_hash_context *ctx) { + SHA512_Init(ctx); +} + +static void +ed25519_hash_update(ed25519_hash_context *ctx, const uint8_t *in, size_t inlen) { + SHA512_Update(ctx, in, inlen); +} + +static void +ed25519_hash_final(ed25519_hash_context *ctx, uint8_t *hash) { + SHA512_Final(hash, ctx); +} + +static void +ed25519_hash(uint8_t *hash, const uint8_t *in, size_t inlen) { + SHA512(in, inlen, hash); +} + +#endif + diff --git a/ed25519-donna/ed25519-randombytes-custom.h b/ed25519-donna/ed25519-randombytes-custom.h new file mode 100644 index 000000000..3515158b2 --- /dev/null +++ b/ed25519-donna/ed25519-randombytes-custom.h @@ -0,0 +1,12 @@ +/* + a custom randombytes must implement: + + void ED25519_FN(ed25519_randombytes_unsafe) (void *p, size_t len); + + ed25519_randombytes_unsafe is used by the batch verification function + to create random scalars +*/ + +#include "rand.h" + +#define ed25519_randombytes_unsafe(p, len) random_buffer((uint8_t *)(p), (len)) diff --git a/ed25519-donna/ed25519-randombytes.h b/ed25519-donna/ed25519-randombytes.h new file mode 100644 index 000000000..1dc629028 --- /dev/null +++ b/ed25519-donna/ed25519-randombytes.h @@ -0,0 +1,91 @@ +#if defined(ED25519_TEST) +/* + ISAAC+ "variant", the paper is not clear on operator precedence and other + things. This is the "first in, first out" option! + + Not threadsafe or securely initialized, only for deterministic testing +*/ +typedef struct isaacp_state_t { + uint32_t state[256]; + unsigned char buffer[1024]; + uint32_t a, b, c; + size_t left; +} isaacp_state; + +#define isaacp_step(offset, mix) \ + x = mm[i + offset]; \ + a = (a ^ (mix)) + (mm[(i + offset + 128) & 0xff]); \ + y = (a ^ b) + mm[(x >> 2) & 0xff]; \ + mm[i + offset] = y; \ + b = (x + a) ^ mm[(y >> 10) & 0xff]; \ + U32TO8_LE(out + (i + offset) * 4, b); + +static void +isaacp_mix(isaacp_state *st) { + uint32_t i, x, y; + uint32_t a = st->a, b = st->b, c = st->c; + uint32_t *mm = st->state; + unsigned char *out = st->buffer; + + c = c + 1; + b = b + c; + + for (i = 0; i < 256; i += 4) { + isaacp_step(0, ROTL32(a,13)) + isaacp_step(1, ROTR32(a, 6)) + isaacp_step(2, ROTL32(a, 2)) + isaacp_step(3, ROTR32(a,16)) + } + + st->a = a; + st->b = b; + st->c = c; + st->left = 1024; +} + +static void +isaacp_random(isaacp_state *st, void *p, size_t len) { + size_t use; + unsigned char *c = (unsigned char *)p; + while (len) { + use = (len > st->left) ? st->left : len; + memcpy(c, st->buffer + (sizeof(st->buffer) - st->left), use); + + st->left -= use; + c += use; + len -= use; + + if (!st->left) + isaacp_mix(st); + } +} + +void +ED25519_FN(ed25519_randombytes_unsafe) (void *p, size_t len) { + static int initialized = 0; + static isaacp_state rng; + + if (!initialized) { + memset(&rng, 0, sizeof(rng)); + isaacp_mix(&rng); + isaacp_mix(&rng); + initialized = 1; + } + + isaacp_random(&rng, p, len); +} +#elif defined(ED25519_CUSTOMRANDOM) + +#include "ed25519-randombytes-custom.h" + +#else + +#include + +void +ED25519_FN(ed25519_randombytes_unsafe) (void *p, size_t len) { + + RAND_bytes(p, (int) len); + +} +#endif diff --git a/ed25519-donna/ed25519.c b/ed25519-donna/ed25519.c new file mode 100644 index 000000000..58a755b8d --- /dev/null +++ b/ed25519-donna/ed25519.c @@ -0,0 +1,150 @@ +/* + Public domain by Andrew M. + + Ed25519 reference implementation using Ed25519-donna +*/ + + +/* define ED25519_SUFFIX to have it appended to the end of each public function */ +#if !defined(ED25519_SUFFIX) +#define ED25519_SUFFIX +#endif + +#define ED25519_FN3(fn,suffix) fn##suffix +#define ED25519_FN2(fn,suffix) ED25519_FN3(fn,suffix) +#define ED25519_FN(fn) ED25519_FN2(fn,ED25519_SUFFIX) + +#include "ed25519-donna.h" +#include "ed25519.h" +#include "ed25519-randombytes.h" +#include "ed25519-hash.h" + +/* + Generates a (extsk[0..31]) and aExt (extsk[32..63]) +*/ + +DONNA_INLINE static void +ed25519_extsk(hash_512bits extsk, const ed25519_secret_key sk) { + ed25519_hash(extsk, sk, 32); + extsk[0] &= 248; + extsk[31] &= 127; + extsk[31] |= 64; +} + +static void +ed25519_hram(hash_512bits hram, const ed25519_signature RS, const ed25519_public_key pk, const unsigned char *m, size_t mlen) { + ed25519_hash_context ctx; + ed25519_hash_init(&ctx); + ed25519_hash_update(&ctx, RS, 32); + ed25519_hash_update(&ctx, pk, 32); + ed25519_hash_update(&ctx, m, mlen); + ed25519_hash_final(&ctx, hram); +} + +void +ED25519_FN(ed25519_publickey) (const ed25519_secret_key sk, ed25519_public_key pk) { + bignum256modm a; + ge25519 ALIGN(16) A; + hash_512bits extsk; + + /* A = aB */ + ed25519_extsk(extsk, sk); + expand256_modm(a, extsk, 32); + ge25519_scalarmult_base_niels(&A, ge25519_niels_base_multiples, a); + ge25519_pack(pk, &A); +} + + +void +ED25519_FN(ed25519_sign) (const unsigned char *m, size_t mlen, const ed25519_secret_key sk, const ed25519_public_key pk, ed25519_signature RS) { + ed25519_hash_context ctx; + bignum256modm r, S, a; + ge25519 ALIGN(16) R; + hash_512bits extsk, hashr, hram; + + ed25519_extsk(extsk, sk); + + /* r = H(aExt[32..64], m) */ + ed25519_hash_init(&ctx); + ed25519_hash_update(&ctx, extsk + 32, 32); + ed25519_hash_update(&ctx, m, mlen); + ed25519_hash_final(&ctx, hashr); + expand256_modm(r, hashr, 64); + + /* R = rB */ + ge25519_scalarmult_base_niels(&R, ge25519_niels_base_multiples, r); + ge25519_pack(RS, &R); + + /* S = H(R,A,m).. */ + ed25519_hram(hram, RS, pk, m, mlen); + expand256_modm(S, hram, 64); + + /* S = H(R,A,m)a */ + expand256_modm(a, extsk, 32); + mul256_modm(S, S, a); + + /* S = (r + H(R,A,m)a) */ + add256_modm(S, S, r); + + /* S = (r + H(R,A,m)a) mod L */ + contract256_modm(RS + 32, S); +} + +int +ED25519_FN(ed25519_sign_open) (const unsigned char *m, size_t mlen, const ed25519_public_key pk, const ed25519_signature RS) { + ge25519 ALIGN(16) R, A; + hash_512bits hash; + bignum256modm hram, S; + unsigned char checkR[32]; + + if ((RS[63] & 224) || !ge25519_unpack_negative_vartime(&A, pk)) + return -1; + + /* hram = H(R,A,m) */ + ed25519_hram(hash, RS, pk, m, mlen); + expand256_modm(hram, hash, 64); + + /* S */ + expand256_modm(S, RS + 32, 32); + + /* SB - H(R,A,m)A */ + ge25519_double_scalarmult_vartime(&R, &A, hram, S); + ge25519_pack(checkR, &R); + + /* check that R = SB - H(R,A,m)A */ + return ed25519_verify(RS, checkR, 32) ? 0 : -1; +} + +#include "ed25519-donna-batchverify.h" + +/* + Fast Curve25519 basepoint scalar multiplication +*/ + +void +ED25519_FN(curved25519_scalarmult_basepoint) (curved25519_key pk, const curved25519_key e) { + curved25519_key ec; + bignum256modm s; + bignum25519 ALIGN(16) yplusz, zminusy; + ge25519 ALIGN(16) p; + size_t i; + + /* clamp */ + for (i = 0; i < 32; i++) ec[i] = e[i]; + ec[0] &= 248; + ec[31] &= 127; + ec[31] |= 64; + + expand_raw256_modm(s, ec); + + /* scalar * basepoint */ + ge25519_scalarmult_base_niels(&p, ge25519_niels_base_multiples, s); + + /* u = (y + z) / (z - y) */ + curve25519_add(yplusz, p.y, p.z); + curve25519_sub(zminusy, p.z, p.y); + curve25519_recip(zminusy, zminusy); + curve25519_mul(yplusz, yplusz, zminusy); + curve25519_contract(pk, yplusz); +} + diff --git a/ed25519-donna/ed25519.h b/ed25519-donna/ed25519.h new file mode 100644 index 000000000..dc86675cd --- /dev/null +++ b/ed25519-donna/ed25519.h @@ -0,0 +1,30 @@ +#ifndef ED25519_H +#define ED25519_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +typedef unsigned char ed25519_signature[64]; +typedef unsigned char ed25519_public_key[32]; +typedef unsigned char ed25519_secret_key[32]; + +typedef unsigned char curved25519_key[32]; + +void ed25519_publickey(const ed25519_secret_key sk, ed25519_public_key pk); +int ed25519_sign_open(const unsigned char *m, size_t mlen, const ed25519_public_key pk, const ed25519_signature RS); +void ed25519_sign(const unsigned char *m, size_t mlen, const ed25519_secret_key sk, const ed25519_public_key pk, ed25519_signature RS); + +int ed25519_sign_open_batch(const unsigned char **m, size_t *mlen, const unsigned char **pk, const unsigned char **RS, size_t num, int *valid); + +void ed25519_randombytes_unsafe(void *out, size_t count); + +void curved25519_scalarmult_basepoint(curved25519_key pk, const curved25519_key e); + +#if defined(__cplusplus) +} +#endif + +#endif // ED25519_H diff --git a/ed25519-donna/modm-donna-32bit.h b/ed25519-donna/modm-donna-32bit.h new file mode 100644 index 000000000..dfd76be66 --- /dev/null +++ b/ed25519-donna/modm-donna-32bit.h @@ -0,0 +1,469 @@ +/* + Public domain by Andrew M. +*/ + + +/* + Arithmetic modulo the group order n = 2^252 + 27742317777372353535851937790883648493 = 7237005577332262213973186563042994240857116359379907606001950938285454250989 + + k = 32 + b = 1 << 8 = 256 + m = 2^252 + 27742317777372353535851937790883648493 = 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed + mu = floor( b^(k*2) / m ) = 0xfffffffffffffffffffffffffffffffeb2106215d086329a7ed9ce5a30a2c131b +*/ + +#define bignum256modm_bits_per_limb 30 +#define bignum256modm_limb_size 9 + +typedef uint32_t bignum256modm_element_t; +typedef bignum256modm_element_t bignum256modm[9]; + +static const bignum256modm modm_m = { + 0x1cf5d3ed, 0x20498c69, 0x2f79cd65, 0x37be77a8, + 0x00000014, 0x00000000, 0x00000000, 0x00000000, + 0x00001000 +}; + +static const bignum256modm modm_mu = { + 0x0a2c131b, 0x3673968c, 0x06329a7e, 0x01885742, + 0x3fffeb21, 0x3fffffff, 0x3fffffff, 0x3fffffff, + 0x000fffff +}; + +static bignum256modm_element_t +lt_modm(bignum256modm_element_t a, bignum256modm_element_t b) { + return (a - b) >> 31; +} + +/* see HAC, Alg. 14.42 Step 4 */ +static void +reduce256_modm(bignum256modm r) { + bignum256modm t; + bignum256modm_element_t b = 0, pb, mask; + + /* t = r - m */ + pb = 0; + pb += modm_m[0]; b = lt_modm(r[0], pb); t[0] = (r[0] - pb + (b << 30)); pb = b; + pb += modm_m[1]; b = lt_modm(r[1], pb); t[1] = (r[1] - pb + (b << 30)); pb = b; + pb += modm_m[2]; b = lt_modm(r[2], pb); t[2] = (r[2] - pb + (b << 30)); pb = b; + pb += modm_m[3]; b = lt_modm(r[3], pb); t[3] = (r[3] - pb + (b << 30)); pb = b; + pb += modm_m[4]; b = lt_modm(r[4], pb); t[4] = (r[4] - pb + (b << 30)); pb = b; + pb += modm_m[5]; b = lt_modm(r[5], pb); t[5] = (r[5] - pb + (b << 30)); pb = b; + pb += modm_m[6]; b = lt_modm(r[6], pb); t[6] = (r[6] - pb + (b << 30)); pb = b; + pb += modm_m[7]; b = lt_modm(r[7], pb); t[7] = (r[7] - pb + (b << 30)); pb = b; + pb += modm_m[8]; b = lt_modm(r[8], pb); t[8] = (r[8] - pb + (b << 16)); + + /* keep r if r was smaller than m */ + mask = b - 1; + r[0] ^= mask & (r[0] ^ t[0]); + r[1] ^= mask & (r[1] ^ t[1]); + r[2] ^= mask & (r[2] ^ t[2]); + r[3] ^= mask & (r[3] ^ t[3]); + r[4] ^= mask & (r[4] ^ t[4]); + r[5] ^= mask & (r[5] ^ t[5]); + r[6] ^= mask & (r[6] ^ t[6]); + r[7] ^= mask & (r[7] ^ t[7]); + r[8] ^= mask & (r[8] ^ t[8]); +} + +/* + Barrett reduction, see HAC, Alg. 14.42 + + Instead of passing in x, pre-process in to q1 and r1 for efficiency +*/ +static void +barrett_reduce256_modm(bignum256modm r, const bignum256modm q1, const bignum256modm r1) { + bignum256modm q3, r2; + uint64_t c; + bignum256modm_element_t f, b, pb; + + /* q1 = x >> 248 = 264 bits = 9 30 bit elements + q2 = mu * q1 + q3 = (q2 / 256(32+1)) = q2 / (2^8)^(32+1) = q2 >> 264 */ + c = mul32x32_64(modm_mu[0], q1[7]) + mul32x32_64(modm_mu[1], q1[6]) + mul32x32_64(modm_mu[2], q1[5]) + mul32x32_64(modm_mu[3], q1[4]) + mul32x32_64(modm_mu[4], q1[3]) + mul32x32_64(modm_mu[5], q1[2]) + mul32x32_64(modm_mu[6], q1[1]) + mul32x32_64(modm_mu[7], q1[0]); + c >>= 30; + c += mul32x32_64(modm_mu[0], q1[8]) + mul32x32_64(modm_mu[1], q1[7]) + mul32x32_64(modm_mu[2], q1[6]) + mul32x32_64(modm_mu[3], q1[5]) + mul32x32_64(modm_mu[4], q1[4]) + mul32x32_64(modm_mu[5], q1[3]) + mul32x32_64(modm_mu[6], q1[2]) + mul32x32_64(modm_mu[7], q1[1]) + mul32x32_64(modm_mu[8], q1[0]); + f = (bignum256modm_element_t)c; q3[0] = (f >> 24) & 0x3f; c >>= 30; + c += mul32x32_64(modm_mu[1], q1[8]) + mul32x32_64(modm_mu[2], q1[7]) + mul32x32_64(modm_mu[3], q1[6]) + mul32x32_64(modm_mu[4], q1[5]) + mul32x32_64(modm_mu[5], q1[4]) + mul32x32_64(modm_mu[6], q1[3]) + mul32x32_64(modm_mu[7], q1[2]) + mul32x32_64(modm_mu[8], q1[1]); + f = (bignum256modm_element_t)c; q3[0] |= (f << 6) & 0x3fffffff; q3[1] = (f >> 24) & 0x3f; c >>= 30; + c += mul32x32_64(modm_mu[2], q1[8]) + mul32x32_64(modm_mu[3], q1[7]) + mul32x32_64(modm_mu[4], q1[6]) + mul32x32_64(modm_mu[5], q1[5]) + mul32x32_64(modm_mu[6], q1[4]) + mul32x32_64(modm_mu[7], q1[3]) + mul32x32_64(modm_mu[8], q1[2]); + f = (bignum256modm_element_t)c; q3[1] |= (f << 6) & 0x3fffffff; q3[2] = (f >> 24) & 0x3f; c >>= 30; + c += mul32x32_64(modm_mu[3], q1[8]) + mul32x32_64(modm_mu[4], q1[7]) + mul32x32_64(modm_mu[5], q1[6]) + mul32x32_64(modm_mu[6], q1[5]) + mul32x32_64(modm_mu[7], q1[4]) + mul32x32_64(modm_mu[8], q1[3]); + f = (bignum256modm_element_t)c; q3[2] |= (f << 6) & 0x3fffffff; q3[3] = (f >> 24) & 0x3f; c >>= 30; + c += mul32x32_64(modm_mu[4], q1[8]) + mul32x32_64(modm_mu[5], q1[7]) + mul32x32_64(modm_mu[6], q1[6]) + mul32x32_64(modm_mu[7], q1[5]) + mul32x32_64(modm_mu[8], q1[4]); + f = (bignum256modm_element_t)c; q3[3] |= (f << 6) & 0x3fffffff; q3[4] = (f >> 24) & 0x3f; c >>= 30; + c += mul32x32_64(modm_mu[5], q1[8]) + mul32x32_64(modm_mu[6], q1[7]) + mul32x32_64(modm_mu[7], q1[6]) + mul32x32_64(modm_mu[8], q1[5]); + f = (bignum256modm_element_t)c; q3[4] |= (f << 6) & 0x3fffffff; q3[5] = (f >> 24) & 0x3f; c >>= 30; + c += mul32x32_64(modm_mu[6], q1[8]) + mul32x32_64(modm_mu[7], q1[7]) + mul32x32_64(modm_mu[8], q1[6]); + f = (bignum256modm_element_t)c; q3[5] |= (f << 6) & 0x3fffffff; q3[6] = (f >> 24) & 0x3f; c >>= 30; + c += mul32x32_64(modm_mu[7], q1[8]) + mul32x32_64(modm_mu[8], q1[7]); + f = (bignum256modm_element_t)c; q3[6] |= (f << 6) & 0x3fffffff; q3[7] = (f >> 24) & 0x3f; c >>= 30; + c += mul32x32_64(modm_mu[8], q1[8]); + f = (bignum256modm_element_t)c; q3[7] |= (f << 6) & 0x3fffffff; q3[8] = (bignum256modm_element_t)(c >> 24); + + /* r1 = (x mod 256^(32+1)) = x mod (2^8)(31+1) = x & ((1 << 264) - 1) + r2 = (q3 * m) mod (256^(32+1)) = (q3 * m) & ((1 << 264) - 1) */ + c = mul32x32_64(modm_m[0], q3[0]); + r2[0] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30; + c += mul32x32_64(modm_m[0], q3[1]) + mul32x32_64(modm_m[1], q3[0]); + r2[1] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30; + c += mul32x32_64(modm_m[0], q3[2]) + mul32x32_64(modm_m[1], q3[1]) + mul32x32_64(modm_m[2], q3[0]); + r2[2] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30; + c += mul32x32_64(modm_m[0], q3[3]) + mul32x32_64(modm_m[1], q3[2]) + mul32x32_64(modm_m[2], q3[1]) + mul32x32_64(modm_m[3], q3[0]); + r2[3] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30; + c += mul32x32_64(modm_m[0], q3[4]) + mul32x32_64(modm_m[1], q3[3]) + mul32x32_64(modm_m[2], q3[2]) + mul32x32_64(modm_m[3], q3[1]) + mul32x32_64(modm_m[4], q3[0]); + r2[4] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30; + c += mul32x32_64(modm_m[0], q3[5]) + mul32x32_64(modm_m[1], q3[4]) + mul32x32_64(modm_m[2], q3[3]) + mul32x32_64(modm_m[3], q3[2]) + mul32x32_64(modm_m[4], q3[1]) + mul32x32_64(modm_m[5], q3[0]); + r2[5] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30; + c += mul32x32_64(modm_m[0], q3[6]) + mul32x32_64(modm_m[1], q3[5]) + mul32x32_64(modm_m[2], q3[4]) + mul32x32_64(modm_m[3], q3[3]) + mul32x32_64(modm_m[4], q3[2]) + mul32x32_64(modm_m[5], q3[1]) + mul32x32_64(modm_m[6], q3[0]); + r2[6] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30; + c += mul32x32_64(modm_m[0], q3[7]) + mul32x32_64(modm_m[1], q3[6]) + mul32x32_64(modm_m[2], q3[5]) + mul32x32_64(modm_m[3], q3[4]) + mul32x32_64(modm_m[4], q3[3]) + mul32x32_64(modm_m[5], q3[2]) + mul32x32_64(modm_m[6], q3[1]) + mul32x32_64(modm_m[7], q3[0]); + r2[7] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30; + c += mul32x32_64(modm_m[0], q3[8]) + mul32x32_64(modm_m[1], q3[7]) + mul32x32_64(modm_m[2], q3[6]) + mul32x32_64(modm_m[3], q3[5]) + mul32x32_64(modm_m[4], q3[4]) + mul32x32_64(modm_m[5], q3[3]) + mul32x32_64(modm_m[6], q3[2]) + mul32x32_64(modm_m[7], q3[1]) + mul32x32_64(modm_m[8], q3[0]); + r2[8] = (bignum256modm_element_t)(c & 0xffffff); + + /* r = r1 - r2 + if (r < 0) r += (1 << 264) */ + pb = 0; + pb += r2[0]; b = lt_modm(r1[0], pb); r[0] = (r1[0] - pb + (b << 30)); pb = b; + pb += r2[1]; b = lt_modm(r1[1], pb); r[1] = (r1[1] - pb + (b << 30)); pb = b; + pb += r2[2]; b = lt_modm(r1[2], pb); r[2] = (r1[2] - pb + (b << 30)); pb = b; + pb += r2[3]; b = lt_modm(r1[3], pb); r[3] = (r1[3] - pb + (b << 30)); pb = b; + pb += r2[4]; b = lt_modm(r1[4], pb); r[4] = (r1[4] - pb + (b << 30)); pb = b; + pb += r2[5]; b = lt_modm(r1[5], pb); r[5] = (r1[5] - pb + (b << 30)); pb = b; + pb += r2[6]; b = lt_modm(r1[6], pb); r[6] = (r1[6] - pb + (b << 30)); pb = b; + pb += r2[7]; b = lt_modm(r1[7], pb); r[7] = (r1[7] - pb + (b << 30)); pb = b; + pb += r2[8]; b = lt_modm(r1[8], pb); r[8] = (r1[8] - pb + (b << 24)); + + reduce256_modm(r); + reduce256_modm(r); +} + +/* addition modulo m */ +static void +add256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y) { + bignum256modm_element_t c; + + c = x[0] + y[0]; r[0] = c & 0x3fffffff; c >>= 30; + c += x[1] + y[1]; r[1] = c & 0x3fffffff; c >>= 30; + c += x[2] + y[2]; r[2] = c & 0x3fffffff; c >>= 30; + c += x[3] + y[3]; r[3] = c & 0x3fffffff; c >>= 30; + c += x[4] + y[4]; r[4] = c & 0x3fffffff; c >>= 30; + c += x[5] + y[5]; r[5] = c & 0x3fffffff; c >>= 30; + c += x[6] + y[6]; r[6] = c & 0x3fffffff; c >>= 30; + c += x[7] + y[7]; r[7] = c & 0x3fffffff; c >>= 30; + c += x[8] + y[8]; r[8] = c; + + reduce256_modm(r); +} + +/* multiplication modulo m */ +static void +mul256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y) { + bignum256modm r1, q1; + uint64_t c; + bignum256modm_element_t f; + + /* r1 = (x mod 256^(32+1)) = x mod (2^8)(31+1) = x & ((1 << 264) - 1) + q1 = x >> 248 = 264 bits = 9 30 bit elements */ + c = mul32x32_64(x[0], y[0]); + f = (bignum256modm_element_t)c; r1[0] = (f & 0x3fffffff); c >>= 30; + c += mul32x32_64(x[0], y[1]) + mul32x32_64(x[1], y[0]); + f = (bignum256modm_element_t)c; r1[1] = (f & 0x3fffffff); c >>= 30; + c += mul32x32_64(x[0], y[2]) + mul32x32_64(x[1], y[1]) + mul32x32_64(x[2], y[0]); + f = (bignum256modm_element_t)c; r1[2] = (f & 0x3fffffff); c >>= 30; + c += mul32x32_64(x[0], y[3]) + mul32x32_64(x[1], y[2]) + mul32x32_64(x[2], y[1]) + mul32x32_64(x[3], y[0]); + f = (bignum256modm_element_t)c; r1[3] = (f & 0x3fffffff); c >>= 30; + c += mul32x32_64(x[0], y[4]) + mul32x32_64(x[1], y[3]) + mul32x32_64(x[2], y[2]) + mul32x32_64(x[3], y[1]) + mul32x32_64(x[4], y[0]); + f = (bignum256modm_element_t)c; r1[4] = (f & 0x3fffffff); c >>= 30; + c += mul32x32_64(x[0], y[5]) + mul32x32_64(x[1], y[4]) + mul32x32_64(x[2], y[3]) + mul32x32_64(x[3], y[2]) + mul32x32_64(x[4], y[1]) + mul32x32_64(x[5], y[0]); + f = (bignum256modm_element_t)c; r1[5] = (f & 0x3fffffff); c >>= 30; + c += mul32x32_64(x[0], y[6]) + mul32x32_64(x[1], y[5]) + mul32x32_64(x[2], y[4]) + mul32x32_64(x[3], y[3]) + mul32x32_64(x[4], y[2]) + mul32x32_64(x[5], y[1]) + mul32x32_64(x[6], y[0]); + f = (bignum256modm_element_t)c; r1[6] = (f & 0x3fffffff); c >>= 30; + c += mul32x32_64(x[0], y[7]) + mul32x32_64(x[1], y[6]) + mul32x32_64(x[2], y[5]) + mul32x32_64(x[3], y[4]) + mul32x32_64(x[4], y[3]) + mul32x32_64(x[5], y[2]) + mul32x32_64(x[6], y[1]) + mul32x32_64(x[7], y[0]); + f = (bignum256modm_element_t)c; r1[7] = (f & 0x3fffffff); c >>= 30; + c += mul32x32_64(x[0], y[8]) + mul32x32_64(x[1], y[7]) + mul32x32_64(x[2], y[6]) + mul32x32_64(x[3], y[5]) + mul32x32_64(x[4], y[4]) + mul32x32_64(x[5], y[3]) + mul32x32_64(x[6], y[2]) + mul32x32_64(x[7], y[1]) + mul32x32_64(x[8], y[0]); + f = (bignum256modm_element_t)c; r1[8] = (f & 0x00ffffff); q1[0] = (f >> 8) & 0x3fffff; c >>= 30; + c += mul32x32_64(x[1], y[8]) + mul32x32_64(x[2], y[7]) + mul32x32_64(x[3], y[6]) + mul32x32_64(x[4], y[5]) + mul32x32_64(x[5], y[4]) + mul32x32_64(x[6], y[3]) + mul32x32_64(x[7], y[2]) + mul32x32_64(x[8], y[1]); + f = (bignum256modm_element_t)c; q1[0] = (q1[0] | (f << 22)) & 0x3fffffff; q1[1] = (f >> 8) & 0x3fffff; c >>= 30; + c += mul32x32_64(x[2], y[8]) + mul32x32_64(x[3], y[7]) + mul32x32_64(x[4], y[6]) + mul32x32_64(x[5], y[5]) + mul32x32_64(x[6], y[4]) + mul32x32_64(x[7], y[3]) + mul32x32_64(x[8], y[2]); + f = (bignum256modm_element_t)c; q1[1] = (q1[1] | (f << 22)) & 0x3fffffff; q1[2] = (f >> 8) & 0x3fffff; c >>= 30; + c += mul32x32_64(x[3], y[8]) + mul32x32_64(x[4], y[7]) + mul32x32_64(x[5], y[6]) + mul32x32_64(x[6], y[5]) + mul32x32_64(x[7], y[4]) + mul32x32_64(x[8], y[3]); + f = (bignum256modm_element_t)c; q1[2] = (q1[2] | (f << 22)) & 0x3fffffff; q1[3] = (f >> 8) & 0x3fffff; c >>= 30; + c += mul32x32_64(x[4], y[8]) + mul32x32_64(x[5], y[7]) + mul32x32_64(x[6], y[6]) + mul32x32_64(x[7], y[5]) + mul32x32_64(x[8], y[4]); + f = (bignum256modm_element_t)c; q1[3] = (q1[3] | (f << 22)) & 0x3fffffff; q1[4] = (f >> 8) & 0x3fffff; c >>= 30; + c += mul32x32_64(x[5], y[8]) + mul32x32_64(x[6], y[7]) + mul32x32_64(x[7], y[6]) + mul32x32_64(x[8], y[5]); + f = (bignum256modm_element_t)c; q1[4] = (q1[4] | (f << 22)) & 0x3fffffff; q1[5] = (f >> 8) & 0x3fffff; c >>= 30; + c += mul32x32_64(x[6], y[8]) + mul32x32_64(x[7], y[7]) + mul32x32_64(x[8], y[6]); + f = (bignum256modm_element_t)c; q1[5] = (q1[5] | (f << 22)) & 0x3fffffff; q1[6] = (f >> 8) & 0x3fffff; c >>= 30; + c += mul32x32_64(x[7], y[8]) + mul32x32_64(x[8], y[7]); + f = (bignum256modm_element_t)c; q1[6] = (q1[6] | (f << 22)) & 0x3fffffff; q1[7] = (f >> 8) & 0x3fffff; c >>= 30; + c += mul32x32_64(x[8], y[8]); + f = (bignum256modm_element_t)c; q1[7] = (q1[7] | (f << 22)) & 0x3fffffff; q1[8] = (f >> 8) & 0x3fffff; + + barrett_reduce256_modm(r, q1, r1); +} + +static void +expand256_modm(bignum256modm out, const unsigned char *in, size_t len) { + unsigned char work[64] = {0}; + bignum256modm_element_t x[16]; + bignum256modm q1; + + memcpy(work, in, len); + x[0] = U8TO32_LE(work + 0); + x[1] = U8TO32_LE(work + 4); + x[2] = U8TO32_LE(work + 8); + x[3] = U8TO32_LE(work + 12); + x[4] = U8TO32_LE(work + 16); + x[5] = U8TO32_LE(work + 20); + x[6] = U8TO32_LE(work + 24); + x[7] = U8TO32_LE(work + 28); + x[8] = U8TO32_LE(work + 32); + x[9] = U8TO32_LE(work + 36); + x[10] = U8TO32_LE(work + 40); + x[11] = U8TO32_LE(work + 44); + x[12] = U8TO32_LE(work + 48); + x[13] = U8TO32_LE(work + 52); + x[14] = U8TO32_LE(work + 56); + x[15] = U8TO32_LE(work + 60); + + /* r1 = (x mod 256^(32+1)) = x mod (2^8)(31+1) = x & ((1 << 264) - 1) */ + out[0] = ( x[0]) & 0x3fffffff; + out[1] = ((x[ 0] >> 30) | (x[ 1] << 2)) & 0x3fffffff; + out[2] = ((x[ 1] >> 28) | (x[ 2] << 4)) & 0x3fffffff; + out[3] = ((x[ 2] >> 26) | (x[ 3] << 6)) & 0x3fffffff; + out[4] = ((x[ 3] >> 24) | (x[ 4] << 8)) & 0x3fffffff; + out[5] = ((x[ 4] >> 22) | (x[ 5] << 10)) & 0x3fffffff; + out[6] = ((x[ 5] >> 20) | (x[ 6] << 12)) & 0x3fffffff; + out[7] = ((x[ 6] >> 18) | (x[ 7] << 14)) & 0x3fffffff; + out[8] = ((x[ 7] >> 16) | (x[ 8] << 16)) & 0x00ffffff; + + /* 8*31 = 248 bits, no need to reduce */ + if (len < 32) + return; + + /* q1 = x >> 248 = 264 bits = 9 30 bit elements */ + q1[0] = ((x[ 7] >> 24) | (x[ 8] << 8)) & 0x3fffffff; + q1[1] = ((x[ 8] >> 22) | (x[ 9] << 10)) & 0x3fffffff; + q1[2] = ((x[ 9] >> 20) | (x[10] << 12)) & 0x3fffffff; + q1[3] = ((x[10] >> 18) | (x[11] << 14)) & 0x3fffffff; + q1[4] = ((x[11] >> 16) | (x[12] << 16)) & 0x3fffffff; + q1[5] = ((x[12] >> 14) | (x[13] << 18)) & 0x3fffffff; + q1[6] = ((x[13] >> 12) | (x[14] << 20)) & 0x3fffffff; + q1[7] = ((x[14] >> 10) | (x[15] << 22)) & 0x3fffffff; + q1[8] = ((x[15] >> 8) ); + + barrett_reduce256_modm(out, q1, out); +} + +static void +expand_raw256_modm(bignum256modm out, const unsigned char in[32]) { + bignum256modm_element_t x[8]; + + x[0] = U8TO32_LE(in + 0); + x[1] = U8TO32_LE(in + 4); + x[2] = U8TO32_LE(in + 8); + x[3] = U8TO32_LE(in + 12); + x[4] = U8TO32_LE(in + 16); + x[5] = U8TO32_LE(in + 20); + x[6] = U8TO32_LE(in + 24); + x[7] = U8TO32_LE(in + 28); + + out[0] = ( x[0]) & 0x3fffffff; + out[1] = ((x[ 0] >> 30) | (x[ 1] << 2)) & 0x3fffffff; + out[2] = ((x[ 1] >> 28) | (x[ 2] << 4)) & 0x3fffffff; + out[3] = ((x[ 2] >> 26) | (x[ 3] << 6)) & 0x3fffffff; + out[4] = ((x[ 3] >> 24) | (x[ 4] << 8)) & 0x3fffffff; + out[5] = ((x[ 4] >> 22) | (x[ 5] << 10)) & 0x3fffffff; + out[6] = ((x[ 5] >> 20) | (x[ 6] << 12)) & 0x3fffffff; + out[7] = ((x[ 6] >> 18) | (x[ 7] << 14)) & 0x3fffffff; + out[8] = ((x[ 7] >> 16) ) & 0x0000ffff; +} + +static void +contract256_modm(unsigned char out[32], const bignum256modm in) { + U32TO8_LE(out + 0, (in[0] ) | (in[1] << 30)); + U32TO8_LE(out + 4, (in[1] >> 2) | (in[2] << 28)); + U32TO8_LE(out + 8, (in[2] >> 4) | (in[3] << 26)); + U32TO8_LE(out + 12, (in[3] >> 6) | (in[4] << 24)); + U32TO8_LE(out + 16, (in[4] >> 8) | (in[5] << 22)); + U32TO8_LE(out + 20, (in[5] >> 10) | (in[6] << 20)); + U32TO8_LE(out + 24, (in[6] >> 12) | (in[7] << 18)); + U32TO8_LE(out + 28, (in[7] >> 14) | (in[8] << 16)); +} + + + +static void +contract256_window4_modm(signed char r[64], const bignum256modm in) { + char carry; + signed char *quads = r; + bignum256modm_element_t i, j, v; + + for (i = 0; i < 8; i += 2) { + v = in[i]; + for (j = 0; j < 7; j++) { + *quads++ = (v & 15); + v >>= 4; + } + v |= (in[i+1] << 2); + for (j = 0; j < 8; j++) { + *quads++ = (v & 15); + v >>= 4; + } + } + v = in[8]; + *quads++ = (v & 15); v >>= 4; + *quads++ = (v & 15); v >>= 4; + *quads++ = (v & 15); v >>= 4; + *quads++ = (v & 15); v >>= 4; + + /* making it signed */ + carry = 0; + for(i = 0; i < 63; i++) { + r[i] += carry; + r[i+1] += (r[i] >> 4); + r[i] &= 15; + carry = (r[i] >> 3); + r[i] -= (carry << 4); + } + r[63] += carry; +} + +static void +contract256_slidingwindow_modm(signed char r[256], const bignum256modm s, int windowsize) { + int i,j,k,b; + int m = (1 << (windowsize - 1)) - 1, soplen = 256; + signed char *bits = r; + bignum256modm_element_t v; + + /* first put the binary expansion into r */ + for (i = 0; i < 8; i++) { + v = s[i]; + for (j = 0; j < 30; j++, v >>= 1) + *bits++ = (v & 1); + } + v = s[8]; + for (j = 0; j < 16; j++, v >>= 1) + *bits++ = (v & 1); + + /* Making it sliding window */ + for (j = 0; j < soplen; j++) { + if (!r[j]) + continue; + + for (b = 1; (b < (soplen - j)) && (b <= 6); b++) { + if ((r[j] + (r[j + b] << b)) <= m) { + r[j] += r[j + b] << b; + r[j + b] = 0; + } else if ((r[j] - (r[j + b] << b)) >= -m) { + r[j] -= r[j + b] << b; + for (k = j + b; k < soplen; k++) { + if (!r[k]) { + r[k] = 1; + break; + } + r[k] = 0; + } + } else if (r[j + b]) { + break; + } + } + } +} + + +/* + helpers for batch verifcation, are allowed to be vartime +*/ + +/* out = a - b, a must be larger than b */ +static void +sub256_modm_batch(bignum256modm out, const bignum256modm a, const bignum256modm b, size_t limbsize) { + size_t i = 0; + bignum256modm_element_t carry = 0; + switch (limbsize) { + case 8: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 31); out[i] &= 0x3fffffff; i++; + case 7: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 31); out[i] &= 0x3fffffff; i++; + case 6: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 31); out[i] &= 0x3fffffff; i++; + case 5: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 31); out[i] &= 0x3fffffff; i++; + case 4: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 31); out[i] &= 0x3fffffff; i++; + case 3: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 31); out[i] &= 0x3fffffff; i++; + case 2: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 31); out[i] &= 0x3fffffff; i++; + case 1: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 31); out[i] &= 0x3fffffff; i++; + case 0: + default: out[i] = (a[i] - b[i]) - carry; + } +} + + +/* is a < b */ +static int +lt256_modm_batch(const bignum256modm a, const bignum256modm b, size_t limbsize) { + switch (limbsize) { + case 8: if (a[8] > b[8]) return 0; if (a[8] < b[8]) return 1; + case 7: if (a[7] > b[7]) return 0; if (a[7] < b[7]) return 1; + case 6: if (a[6] > b[6]) return 0; if (a[6] < b[6]) return 1; + case 5: if (a[5] > b[5]) return 0; if (a[5] < b[5]) return 1; + case 4: if (a[4] > b[4]) return 0; if (a[4] < b[4]) return 1; + case 3: if (a[3] > b[3]) return 0; if (a[3] < b[3]) return 1; + case 2: if (a[2] > b[2]) return 0; if (a[2] < b[2]) return 1; + case 1: if (a[1] > b[1]) return 0; if (a[1] < b[1]) return 1; + case 0: if (a[0] > b[0]) return 0; if (a[0] < b[0]) return 1; + } + return 0; +} + +/* is a <= b */ +static int +lte256_modm_batch(const bignum256modm a, const bignum256modm b, size_t limbsize) { + switch (limbsize) { + case 8: if (a[8] > b[8]) return 0; if (a[8] < b[8]) return 1; + case 7: if (a[7] > b[7]) return 0; if (a[7] < b[7]) return 1; + case 6: if (a[6] > b[6]) return 0; if (a[6] < b[6]) return 1; + case 5: if (a[5] > b[5]) return 0; if (a[5] < b[5]) return 1; + case 4: if (a[4] > b[4]) return 0; if (a[4] < b[4]) return 1; + case 3: if (a[3] > b[3]) return 0; if (a[3] < b[3]) return 1; + case 2: if (a[2] > b[2]) return 0; if (a[2] < b[2]) return 1; + case 1: if (a[1] > b[1]) return 0; if (a[1] < b[1]) return 1; + case 0: if (a[0] > b[0]) return 0; if (a[0] < b[0]) return 1; + } + return 1; +} + + +/* is a == 0 */ +static int +iszero256_modm_batch(const bignum256modm a) { + size_t i; + for (i = 0; i < 9; i++) + if (a[i]) + return 0; + return 1; +} + +/* is a == 1 */ +static int +isone256_modm_batch(const bignum256modm a) { + size_t i; + if (a[0] != 1) + return 0; + for (i = 1; i < 9; i++) + if (a[i]) + return 0; + return 1; +} + +/* can a fit in to (at most) 128 bits */ +static int +isatmost128bits256_modm_batch(const bignum256modm a) { + uint32_t mask = + ((a[8] ) | /* 16 */ + (a[7] ) | /* 46 */ + (a[6] ) | /* 76 */ + (a[5] ) | /* 106 */ + (a[4] & 0x3fffff00)); /* 128 */ + + return (mask == 0); +} diff --git a/ed25519-donna/modm-donna-64bit.h b/ed25519-donna/modm-donna-64bit.h new file mode 100644 index 000000000..a47a38a42 --- /dev/null +++ b/ed25519-donna/modm-donna-64bit.h @@ -0,0 +1,361 @@ +/* + Public domain by Andrew M. +*/ + + +/* + Arithmetic modulo the group order n = 2^252 + 27742317777372353535851937790883648493 = 7237005577332262213973186563042994240857116359379907606001950938285454250989 + + k = 32 + b = 1 << 8 = 256 + m = 2^252 + 27742317777372353535851937790883648493 = 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed + mu = floor( b^(k*2) / m ) = 0xfffffffffffffffffffffffffffffffeb2106215d086329a7ed9ce5a30a2c131b +*/ + +#define bignum256modm_bits_per_limb 56 +#define bignum256modm_limb_size 5 + +typedef uint64_t bignum256modm_element_t; +typedef bignum256modm_element_t bignum256modm[5]; + +static const bignum256modm modm_m = { + 0x12631a5cf5d3ed, + 0xf9dea2f79cd658, + 0x000000000014de, + 0x00000000000000, + 0x00000010000000 +}; + +static const bignum256modm modm_mu = { + 0x9ce5a30a2c131b, + 0x215d086329a7ed, + 0xffffffffeb2106, + 0xffffffffffffff, + 0x00000fffffffff +}; + +static bignum256modm_element_t +lt_modm(bignum256modm_element_t a, bignum256modm_element_t b) { + return (a - b) >> 63; +} + +static void +reduce256_modm(bignum256modm r) { + bignum256modm t; + bignum256modm_element_t b = 0, pb, mask; + + /* t = r - m */ + pb = 0; + pb += modm_m[0]; b = lt_modm(r[0], pb); t[0] = (r[0] - pb + (b << 56)); pb = b; + pb += modm_m[1]; b = lt_modm(r[1], pb); t[1] = (r[1] - pb + (b << 56)); pb = b; + pb += modm_m[2]; b = lt_modm(r[2], pb); t[2] = (r[2] - pb + (b << 56)); pb = b; + pb += modm_m[3]; b = lt_modm(r[3], pb); t[3] = (r[3] - pb + (b << 56)); pb = b; + pb += modm_m[4]; b = lt_modm(r[4], pb); t[4] = (r[4] - pb + (b << 32)); + + /* keep r if r was smaller than m */ + mask = b - 1; + + r[0] ^= mask & (r[0] ^ t[0]); + r[1] ^= mask & (r[1] ^ t[1]); + r[2] ^= mask & (r[2] ^ t[2]); + r[3] ^= mask & (r[3] ^ t[3]); + r[4] ^= mask & (r[4] ^ t[4]); +} + +static void +barrett_reduce256_modm(bignum256modm r, const bignum256modm q1, const bignum256modm r1) { + bignum256modm q3, r2; + uint128_t c, mul; + bignum256modm_element_t f, b, pb; + + /* q1 = x >> 248 = 264 bits = 5 56 bit elements + q2 = mu * q1 + q3 = (q2 / 256(32+1)) = q2 / (2^8)^(32+1) = q2 >> 264 */ + mul64x64_128(c, modm_mu[0], q1[3]) mul64x64_128(mul, modm_mu[3], q1[0]) add128(c, mul) mul64x64_128(mul, modm_mu[1], q1[2]) add128(c, mul) mul64x64_128(mul, modm_mu[2], q1[1]) add128(c, mul) shr128(f, c, 56); + mul64x64_128(c, modm_mu[0], q1[4]) add128_64(c, f) mul64x64_128(mul, modm_mu[4], q1[0]) add128(c, mul) mul64x64_128(mul, modm_mu[3], q1[1]) add128(c, mul) mul64x64_128(mul, modm_mu[1], q1[3]) add128(c, mul) mul64x64_128(mul, modm_mu[2], q1[2]) add128(c, mul) + f = lo128(c); q3[0] = (f >> 40) & 0xffff; shr128(f, c, 56); + mul64x64_128(c, modm_mu[4], q1[1]) add128_64(c, f) mul64x64_128(mul, modm_mu[1], q1[4]) add128(c, mul) mul64x64_128(mul, modm_mu[2], q1[3]) add128(c, mul) mul64x64_128(mul, modm_mu[3], q1[2]) add128(c, mul) + f = lo128(c); q3[0] |= (f << 16) & 0xffffffffffffff; q3[1] = (f >> 40) & 0xffff; shr128(f, c, 56); + mul64x64_128(c, modm_mu[4], q1[2]) add128_64(c, f) mul64x64_128(mul, modm_mu[2], q1[4]) add128(c, mul) mul64x64_128(mul, modm_mu[3], q1[3]) add128(c, mul) + f = lo128(c); q3[1] |= (f << 16) & 0xffffffffffffff; q3[2] = (f >> 40) & 0xffff; shr128(f, c, 56); + mul64x64_128(c, modm_mu[4], q1[3]) add128_64(c, f) mul64x64_128(mul, modm_mu[3], q1[4]) add128(c, mul) + f = lo128(c); q3[2] |= (f << 16) & 0xffffffffffffff; q3[3] = (f >> 40) & 0xffff; shr128(f, c, 56); + mul64x64_128(c, modm_mu[4], q1[4]) add128_64(c, f) + f = lo128(c); q3[3] |= (f << 16) & 0xffffffffffffff; q3[4] = (f >> 40) & 0xffff; shr128(f, c, 56); + q3[4] |= (f << 16); + + mul64x64_128(c, modm_m[0], q3[0]) + r2[0] = lo128(c) & 0xffffffffffffff; shr128(f, c, 56); + mul64x64_128(c, modm_m[0], q3[1]) add128_64(c, f) mul64x64_128(mul, modm_m[1], q3[0]) add128(c, mul) + r2[1] = lo128(c) & 0xffffffffffffff; shr128(f, c, 56); + mul64x64_128(c, modm_m[0], q3[2]) add128_64(c, f) mul64x64_128(mul, modm_m[2], q3[0]) add128(c, mul) mul64x64_128(mul, modm_m[1], q3[1]) add128(c, mul) + r2[2] = lo128(c) & 0xffffffffffffff; shr128(f, c, 56); + mul64x64_128(c, modm_m[0], q3[3]) add128_64(c, f) mul64x64_128(mul, modm_m[3], q3[0]) add128(c, mul) mul64x64_128(mul, modm_m[1], q3[2]) add128(c, mul) mul64x64_128(mul, modm_m[2], q3[1]) add128(c, mul) + r2[3] = lo128(c) & 0xffffffffffffff; shr128(f, c, 56); + mul64x64_128(c, modm_m[0], q3[4]) add128_64(c, f) mul64x64_128(mul, modm_m[4], q3[0]) add128(c, mul) mul64x64_128(mul, modm_m[3], q3[1]) add128(c, mul) mul64x64_128(mul, modm_m[1], q3[3]) add128(c, mul) mul64x64_128(mul, modm_m[2], q3[2]) add128(c, mul) + r2[4] = lo128(c) & 0x0000ffffffffff; + + pb = 0; + pb += r2[0]; b = lt_modm(r1[0], pb); r[0] = (r1[0] - pb + (b << 56)); pb = b; + pb += r2[1]; b = lt_modm(r1[1], pb); r[1] = (r1[1] - pb + (b << 56)); pb = b; + pb += r2[2]; b = lt_modm(r1[2], pb); r[2] = (r1[2] - pb + (b << 56)); pb = b; + pb += r2[3]; b = lt_modm(r1[3], pb); r[3] = (r1[3] - pb + (b << 56)); pb = b; + pb += r2[4]; b = lt_modm(r1[4], pb); r[4] = (r1[4] - pb + (b << 40)); + + reduce256_modm(r); + reduce256_modm(r); +} + + +static void +add256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y) { + bignum256modm_element_t c; + + c = x[0] + y[0]; r[0] = c & 0xffffffffffffff; c >>= 56; + c += x[1] + y[1]; r[1] = c & 0xffffffffffffff; c >>= 56; + c += x[2] + y[2]; r[2] = c & 0xffffffffffffff; c >>= 56; + c += x[3] + y[3]; r[3] = c & 0xffffffffffffff; c >>= 56; + c += x[4] + y[4]; r[4] = c; + + reduce256_modm(r); +} + +static void +mul256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y) { + bignum256modm q1, r1; + uint128_t c, mul; + bignum256modm_element_t f; + + mul64x64_128(c, x[0], y[0]) + f = lo128(c); r1[0] = f & 0xffffffffffffff; shr128(f, c, 56); + mul64x64_128(c, x[0], y[1]) add128_64(c, f) mul64x64_128(mul, x[1], y[0]) add128(c, mul) + f = lo128(c); r1[1] = f & 0xffffffffffffff; shr128(f, c, 56); + mul64x64_128(c, x[0], y[2]) add128_64(c, f) mul64x64_128(mul, x[2], y[0]) add128(c, mul) mul64x64_128(mul, x[1], y[1]) add128(c, mul) + f = lo128(c); r1[2] = f & 0xffffffffffffff; shr128(f, c, 56); + mul64x64_128(c, x[0], y[3]) add128_64(c, f) mul64x64_128(mul, x[3], y[0]) add128(c, mul) mul64x64_128(mul, x[1], y[2]) add128(c, mul) mul64x64_128(mul, x[2], y[1]) add128(c, mul) + f = lo128(c); r1[3] = f & 0xffffffffffffff; shr128(f, c, 56); + mul64x64_128(c, x[0], y[4]) add128_64(c, f) mul64x64_128(mul, x[4], y[0]) add128(c, mul) mul64x64_128(mul, x[3], y[1]) add128(c, mul) mul64x64_128(mul, x[1], y[3]) add128(c, mul) mul64x64_128(mul, x[2], y[2]) add128(c, mul) + f = lo128(c); r1[4] = f & 0x0000ffffffffff; q1[0] = (f >> 24) & 0xffffffff; shr128(f, c, 56); + mul64x64_128(c, x[4], y[1]) add128_64(c, f) mul64x64_128(mul, x[1], y[4]) add128(c, mul) mul64x64_128(mul, x[2], y[3]) add128(c, mul) mul64x64_128(mul, x[3], y[2]) add128(c, mul) + f = lo128(c); q1[0] |= (f << 32) & 0xffffffffffffff; q1[1] = (f >> 24) & 0xffffffff; shr128(f, c, 56); + mul64x64_128(c, x[4], y[2]) add128_64(c, f) mul64x64_128(mul, x[2], y[4]) add128(c, mul) mul64x64_128(mul, x[3], y[3]) add128(c, mul) + f = lo128(c); q1[1] |= (f << 32) & 0xffffffffffffff; q1[2] = (f >> 24) & 0xffffffff; shr128(f, c, 56); + mul64x64_128(c, x[4], y[3]) add128_64(c, f) mul64x64_128(mul, x[3], y[4]) add128(c, mul) + f = lo128(c); q1[2] |= (f << 32) & 0xffffffffffffff; q1[3] = (f >> 24) & 0xffffffff; shr128(f, c, 56); + mul64x64_128(c, x[4], y[4]) add128_64(c, f) + f = lo128(c); q1[3] |= (f << 32) & 0xffffffffffffff; q1[4] = (f >> 24) & 0xffffffff; shr128(f, c, 56); + q1[4] |= (f << 32); + + barrett_reduce256_modm(r, q1, r1); +} + +static void +expand256_modm(bignum256modm out, const unsigned char *in, size_t len) { + unsigned char work[64] = {0}; + bignum256modm_element_t x[16]; + bignum256modm q1; + + memcpy(work, in, len); + x[0] = U8TO64_LE(work + 0); + x[1] = U8TO64_LE(work + 8); + x[2] = U8TO64_LE(work + 16); + x[3] = U8TO64_LE(work + 24); + x[4] = U8TO64_LE(work + 32); + x[5] = U8TO64_LE(work + 40); + x[6] = U8TO64_LE(work + 48); + x[7] = U8TO64_LE(work + 56); + + /* r1 = (x mod 256^(32+1)) = x mod (2^8)(31+1) = x & ((1 << 264) - 1) */ + out[0] = ( x[0]) & 0xffffffffffffff; + out[1] = ((x[ 0] >> 56) | (x[ 1] << 8)) & 0xffffffffffffff; + out[2] = ((x[ 1] >> 48) | (x[ 2] << 16)) & 0xffffffffffffff; + out[3] = ((x[ 2] >> 40) | (x[ 3] << 24)) & 0xffffffffffffff; + out[4] = ((x[ 3] >> 32) | (x[ 4] << 32)) & 0x0000ffffffffff; + + /* under 252 bits, no need to reduce */ + if (len < 32) + return; + + /* q1 = x >> 248 = 264 bits */ + q1[0] = ((x[ 3] >> 56) | (x[ 4] << 8)) & 0xffffffffffffff; + q1[1] = ((x[ 4] >> 48) | (x[ 5] << 16)) & 0xffffffffffffff; + q1[2] = ((x[ 5] >> 40) | (x[ 6] << 24)) & 0xffffffffffffff; + q1[3] = ((x[ 6] >> 32) | (x[ 7] << 32)) & 0xffffffffffffff; + q1[4] = ((x[ 7] >> 24) ); + + barrett_reduce256_modm(out, q1, out); +} + +static void +expand_raw256_modm(bignum256modm out, const unsigned char in[32]) { + bignum256modm_element_t x[4]; + + x[0] = U8TO64_LE(in + 0); + x[1] = U8TO64_LE(in + 8); + x[2] = U8TO64_LE(in + 16); + x[3] = U8TO64_LE(in + 24); + + out[0] = ( x[0]) & 0xffffffffffffff; + out[1] = ((x[ 0] >> 56) | (x[ 1] << 8)) & 0xffffffffffffff; + out[2] = ((x[ 1] >> 48) | (x[ 2] << 16)) & 0xffffffffffffff; + out[3] = ((x[ 2] >> 40) | (x[ 3] << 24)) & 0xffffffffffffff; + out[4] = ((x[ 3] >> 32) ) & 0x000000ffffffff; +} + +static void +contract256_modm(unsigned char out[32], const bignum256modm in) { + U64TO8_LE(out + 0, (in[0] ) | (in[1] << 56)); + U64TO8_LE(out + 8, (in[1] >> 8) | (in[2] << 48)); + U64TO8_LE(out + 16, (in[2] >> 16) | (in[3] << 40)); + U64TO8_LE(out + 24, (in[3] >> 24) | (in[4] << 32)); +} + +static void +contract256_window4_modm(signed char r[64], const bignum256modm in) { + char carry; + signed char *quads = r; + bignum256modm_element_t i, j, v, m; + + for (i = 0; i < 5; i++) { + v = in[i]; + m = (i == 4) ? 8 : 14; + for (j = 0; j < m; j++) { + *quads++ = (v & 15); + v >>= 4; + } + } + + /* making it signed */ + carry = 0; + for(i = 0; i < 63; i++) { + r[i] += carry; + r[i+1] += (r[i] >> 4); + r[i] &= 15; + carry = (r[i] >> 3); + r[i] -= (carry << 4); + } + r[63] += carry; +} + +static void +contract256_slidingwindow_modm(signed char r[256], const bignum256modm s, int windowsize) { + int i,j,k,b; + int m = (1 << (windowsize - 1)) - 1, soplen = 256; + signed char *bits = r; + bignum256modm_element_t v; + + /* first put the binary expansion into r */ + for (i = 0; i < 4; i++) { + v = s[i]; + for (j = 0; j < 56; j++, v >>= 1) + *bits++ = (v & 1); + } + v = s[4]; + for (j = 0; j < 32; j++, v >>= 1) + *bits++ = (v & 1); + + /* Making it sliding window */ + for (j = 0; j < soplen; j++) { + if (!r[j]) + continue; + + for (b = 1; (b < (soplen - j)) && (b <= 6); b++) { + if ((r[j] + (r[j + b] << b)) <= m) { + r[j] += r[j + b] << b; + r[j + b] = 0; + } else if ((r[j] - (r[j + b] << b)) >= -m) { + r[j] -= r[j + b] << b; + for (k = j + b; k < soplen; k++) { + if (!r[k]) { + r[k] = 1; + break; + } + r[k] = 0; + } + } else if (r[j + b]) { + break; + } + } + } +} + +/* + helpers for batch verifcation, are allowed to be vartime +*/ + +/* out = a - b, a must be larger than b */ +static void +sub256_modm_batch(bignum256modm out, const bignum256modm a, const bignum256modm b, size_t limbsize) { + size_t i = 0; + bignum256modm_element_t carry = 0; + switch (limbsize) { + case 4: out[i] = (a[i] - b[i]) ; carry = (out[i] >> 63); out[i] &= 0xffffffffffffff; i++; + case 3: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 63); out[i] &= 0xffffffffffffff; i++; + case 2: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 63); out[i] &= 0xffffffffffffff; i++; + case 1: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 63); out[i] &= 0xffffffffffffff; i++; + case 0: + default: out[i] = (a[i] - b[i]) - carry; + } +} + + +/* is a < b */ +static int +lt256_modm_batch(const bignum256modm a, const bignum256modm b, size_t limbsize) { + size_t i = 0; + bignum256modm_element_t t, carry = 0; + switch (limbsize) { + case 4: t = (a[i] - b[i]) ; carry = (t >> 63); i++; + case 3: t = (a[i] - b[i]) - carry; carry = (t >> 63); i++; + case 2: t = (a[i] - b[i]) - carry; carry = (t >> 63); i++; + case 1: t = (a[i] - b[i]) - carry; carry = (t >> 63); i++; + case 0: t = (a[i] - b[i]) - carry; carry = (t >> 63); + } + return (int)carry; +} + +/* is a <= b */ +static int +lte256_modm_batch(const bignum256modm a, const bignum256modm b, size_t limbsize) { + size_t i = 0; + bignum256modm_element_t t, carry = 0; + switch (limbsize) { + case 4: t = (b[i] - a[i]) ; carry = (t >> 63); i++; + case 3: t = (b[i] - a[i]) - carry; carry = (t >> 63); i++; + case 2: t = (b[i] - a[i]) - carry; carry = (t >> 63); i++; + case 1: t = (b[i] - a[i]) - carry; carry = (t >> 63); i++; + case 0: t = (b[i] - a[i]) - carry; carry = (t >> 63); + } + return (int)!carry; +} + +/* is a == 0 */ +static int +iszero256_modm_batch(const bignum256modm a) { + size_t i; + for (i = 0; i < 5; i++) + if (a[i]) + return 0; + return 1; +} + +/* is a == 1 */ +static int +isone256_modm_batch(const bignum256modm a) { + size_t i; + for (i = 0; i < 5; i++) + if (a[i] != ((i) ? 0 : 1)) + return 0; + return 1; +} + +/* can a fit in to (at most) 128 bits */ +static int +isatmost128bits256_modm_batch(const bignum256modm a) { + uint64_t mask = + ((a[4] ) | /* 32 */ + (a[3] ) | /* 88 */ + (a[2] & 0xffffffffff0000)); + + return (mask == 0); +} diff --git a/nist256p1.c b/nist256p1.c index 166fda801..4c1d971bf 100644 --- a/nist256p1.c +++ b/nist256p1.c @@ -23,7 +23,6 @@ #include "nist256p1.h" -const char NIST256P1_NAME[] = "nist256p1"; const ecdsa_curve nist256p1 = { /* .prime */ { /*.val =*/ {0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3f, 0x0, 0x0, 0x1000, 0x3fffc000, 0xffff} diff --git a/nist256p1.h b/nist256p1.h index 347fe86dc..a1a767efd 100644 --- a/nist256p1.h +++ b/nist256p1.h @@ -29,7 +29,6 @@ #include "ecdsa.h" #include "bip32.h" -extern const char NIST256P1_NAME[]; extern const ecdsa_curve nist256p1; extern const curve_info nist256p1_info; diff --git a/secp256k1.c b/secp256k1.c index a5f4507f1..aa4964171 100644 --- a/secp256k1.c +++ b/secp256k1.c @@ -23,8 +23,6 @@ #include "secp256k1.h" -const char SECP256K1_NAME[] = "secp256k1"; - const ecdsa_curve secp256k1 = { /* .prime */ { /*.val =*/ {0x3ffffc2f, 0x3ffffffb, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0xffff} diff --git a/secp256k1.h b/secp256k1.h index e7ef6bf4a..fe82f35e2 100644 --- a/secp256k1.h +++ b/secp256k1.h @@ -29,7 +29,6 @@ #include "ecdsa.h" #include "bip32.h" -extern const char SECP256K1_NAME[]; extern const ecdsa_curve secp256k1; extern const curve_info secp256k1_info; diff --git a/tests.c b/tests.c index 264882377..b66cb6887 100644 --- a/tests.c +++ b/tests.c @@ -38,6 +38,7 @@ #include "rand.h" #include "sha2.h" #include "options.h" +#include "curves.h" #include "secp256k1.h" #include "nist256p1.h" @@ -503,6 +504,30 @@ START_TEST(test_bip32_cache_2) } END_TEST +START_TEST(test_bip32_nist_seed) +{ + HDNode node; + + // init m + hdnode_from_seed(fromhex("a7305bc8df8d0951f0cb224c0e95d7707cbdf2c6ce7e8d481fec69c7ff5e9446"), 32, NIST256P1_NAME, &node); + + // [Chain m] + ck_assert_int_eq(node.fingerprint, 0x00000000); + ck_assert_mem_eq(node.private_key, fromhex("3b8c18469a4634517d6d0b65448f8e6c62091b45540a1743c5846be55d47d88f"), 32); + ck_assert_mem_eq(node.chain_code, fromhex("7762f9729fed06121fd13f326884c82f59aa95c57ac492ce8c9654e60efd130c"), 32); + ck_assert_mem_eq(node.public_key, fromhex("0383619fadcde31063d8c5cb00dbfe1713f3e6fa169d8541a798752a1c1ca0cb20"), 33); + + // init m + hdnode_from_seed(fromhex("aa305bc8df8d0951f0cb29ad4568d7707cbdf2c6ce7e8d481fec69c7ff5e9446"), 32, NIST256P1_NAME, &node); + + // [Chain m] + ck_assert_int_eq(node.fingerprint, 0x00000000); + ck_assert_mem_eq(node.chain_code, fromhex("a81d21f36f987fa0be3b065301bfb6aa9deefbf3dfef6744c37b9a4abc3c68f1"), 32); + ck_assert_mem_eq(node.private_key, fromhex("0e49dc46ce1d8c29d9b80a05e40f5d0cd68cbf02ae98572186f5343be18084bf"), 32); + ck_assert_mem_eq(node.public_key, fromhex("03aaa4c89acd9a98935330773d3dae55122f3591bac4a40942681768de8df6ba63"), 33); +} +END_TEST + START_TEST(test_bip32_nist_vector_1) { HDNode node; @@ -1600,6 +1625,7 @@ Suite *test_suite(void) suite_add_tcase(s, tc); tc = tcase_create("bip32-nist"); + tcase_add_test(tc, test_bip32_nist_seed); tcase_add_test(tc, test_bip32_nist_vector_1); tcase_add_test(tc, test_bip32_nist_vector_2); tcase_add_test(tc, test_bip32_nist_compare); From 295a4938465162c3a88534acb8b18aa27bd1f29f Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Sat, 23 Apr 2016 23:42:53 +0200 Subject: [PATCH 242/627] Test vectors for ed25519 + BIP-0032 / SLIP-0010 --- tests.c | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) diff --git a/tests.c b/tests.c index b66cb6887..10d259835 100644 --- a/tests.c +++ b/tests.c @@ -707,6 +707,114 @@ START_TEST(test_bip32_nist_repeat) } END_TEST +// test vector 1 from https://en.bitcoin.it/wiki/BIP_0032_TestVectors +START_TEST(test_bip32_ed25519_vector_1) +{ + HDNode node; + + // init m + hdnode_from_seed(fromhex("000102030405060708090a0b0c0d0e0f"), 16, ED25519_NAME, &node); + + // [Chain m] + ck_assert_int_eq(node.fingerprint, 0x00000000); + ck_assert_mem_eq(node.chain_code, fromhex("90046a93de5380a72b5e45010748567d5ea02bbf6522f979e05c0d8d8ca9fffb"), 32); + ck_assert_mem_eq(node.private_key, fromhex("2b4be7f19ee27bbf30c667b642d5f4aa69fd169872f8fc3059c08ebae2eb19e7"), 32); + ck_assert_mem_eq(node.public_key, fromhex("00a4b2856bfec510abab89753fac1ac0e1112364e7d250545963f135f2a33188ed"), 33); + + // [Chain m/0'] + hdnode_private_ckd_prime(&node, 0); + ck_assert_int_eq(node.fingerprint, 0xddebc675); + ck_assert_mem_eq(node.chain_code, fromhex("8b59aa11380b624e81507a27fedda59fea6d0b779a778918a2fd3590e16e9c69"), 32); + ck_assert_mem_eq(node.private_key, fromhex("68e0fe46dfb67e368c75379acec591dad19df3cde26e63b93a8e704f1dade7a3"), 32); + ck_assert_mem_eq(node.public_key, fromhex("008c8a13df77a28f3445213a0f432fde644acaa215fc72dcdf300d5efaa85d350c"), 33); + + // [Chain m/0'/1'] + hdnode_private_ckd_prime(&node, 1); + ck_assert_int_eq(node.fingerprint, 0x13dab143); + ck_assert_mem_eq(node.chain_code, fromhex("a320425f77d1b5c2505a6b1b27382b37368ee640e3557c315416801243552f14"), 32); + ck_assert_mem_eq(node.private_key, fromhex("b1d0bad404bf35da785a64ca1ac54b2617211d2777696fbffaf208f746ae84f2"), 32); + ck_assert_mem_eq(node.public_key, fromhex("001932a5270f335bed617d5b935c80aedb1a35bd9fc1e31acafd5372c30f5c1187"), 33); + + // [Chain m/0'/1'/2'] + hdnode_private_ckd_prime(&node, 2); + ck_assert_int_eq(node.fingerprint, 0xebe4cb29); + ck_assert_mem_eq(node.chain_code, fromhex("2e69929e00b5ab250f49c3fb1c12f252de4fed2c1db88387094a0f8c4c9ccd6c"), 32); + ck_assert_mem_eq(node.private_key, fromhex("92a5b23c0b8a99e37d07df3fb9966917f5d06e02ddbd909c7e184371463e9fc9"), 32); + ck_assert_mem_eq(node.public_key, fromhex("00ae98736566d30ed0e9d2f4486a64bc95740d89c7db33f52121f8ea8f76ff0fc1"), 33); + + // [Chain m/0'/1'/2'/2'] + hdnode_private_ckd_prime(&node, 2); + ck_assert_int_eq(node.fingerprint, 0x316ec1c6); + ck_assert_mem_eq(node.chain_code, fromhex("8f6d87f93d750e0efccda017d662a1b31a266e4a6f5993b15f5c1f07f74dd5cc"), 32); + ck_assert_mem_eq(node.private_key, fromhex("30d1dc7e5fc04c31219ab25a27ae00b50f6fd66622f6e9c913253d6511d1e662"), 32); + ck_assert_mem_eq(node.public_key, fromhex("008abae2d66361c879b900d204ad2cc4984fa2aa344dd7ddc46007329ac76c429c"), 33); + + // [Chain m/0'/1'/2'/2'/1000000000'] + hdnode_private_ckd_prime(&node, 1000000000); + ck_assert_int_eq(node.fingerprint, 0xd6322ccd); + ck_assert_mem_eq(node.chain_code, fromhex("68789923a0cac2cd5a29172a475fe9e0fb14cd6adb5ad98a3fa70333e7afa230"), 32); + ck_assert_mem_eq(node.private_key, fromhex("8f94d394a8e8fd6b1bc2f3f49f5c47e385281d5c17e65324b0f62483e37e8793"), 32); + ck_assert_mem_eq(node.public_key, fromhex("003c24da049451555d51a7014a37337aa4e12d41e485abccfa46b47dfb2af54b7a"), 33); +} +END_TEST + +// test vector 2 from https://en.bitcoin.it/wiki/BIP_0032_TestVectors +START_TEST(test_bip32_ed25519_vector_2) +{ + HDNode node; + int r; + + // init m + hdnode_from_seed(fromhex("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), 64, ED25519_NAME, &node); + + // [Chain m] + ck_assert_int_eq(node.fingerprint, 0x00000000); + ck_assert_mem_eq(node.chain_code, fromhex("ef70a74db9c3a5af931b5fe73ed8e1a53464133654fd55e7a66f8570b8e33c3b"), 32); + ck_assert_mem_eq(node.private_key, fromhex("171cb88b1b3c1db25add599712e36245d75bc65a1a5c9e18d76f9f2b1eab4012"), 32); + ck_assert_mem_eq(node.public_key, fromhex("008fe9693f8fa62a4305a140b9764c5ee01e455963744fe18204b4fb948249308a"), 33); + + // [Chain m/0'] + r = hdnode_private_ckd_prime(&node, 0); + ck_assert_int_eq(r, 1); + ck_assert_int_eq(node.fingerprint, 0x31981b50); + ck_assert_mem_eq(node.chain_code, fromhex("0b78a3226f915c082bf118f83618a618ab6dec793752624cbeb622acb562862d"), 32); + ck_assert_mem_eq(node.private_key, fromhex("1559eb2bbec5790b0c65d8693e4d0875b1747f4970ae8b650486ed7470845635"), 32); + ck_assert_mem_eq(node.public_key, fromhex("0086fab68dcb57aa196c77c5f264f215a112c22a912c10d123b0d03c3c28ef1037"), 33); + + // [Chain m/0'/2147483647'] + r = hdnode_private_ckd_prime(&node, 2147483647); + ck_assert_int_eq(r, 1); + ck_assert_int_eq(node.fingerprint, 0x1e9411b1); + ck_assert_mem_eq(node.chain_code, fromhex("138f0b2551bcafeca6ff2aa88ba8ed0ed8de070841f0c4ef0165df8181eaad7f"), 32); + ck_assert_mem_eq(node.private_key, fromhex("ea4f5bfe8694d8bb74b7b59404632fd5968b774ed545e810de9c32a4fb4192f4"), 32); + ck_assert_mem_eq(node.public_key, fromhex("005ba3b9ac6e90e83effcd25ac4e58a1365a9e35a3d3ae5eb07b9e4d90bcf7506d"), 33); + + // [Chain m/0'/2147483647'/1'] + r = hdnode_private_ckd_prime(&node, 1); + ck_assert_int_eq(r, 1); + ck_assert_int_eq(node.fingerprint, 0xfcadf38c); + ck_assert_mem_eq(node.chain_code, fromhex("73bd9fff1cfbde33a1b846c27085f711c0fe2d66fd32e139d3ebc28e5a4a6b90"), 32); + ck_assert_mem_eq(node.private_key, fromhex("3757c7577170179c7868353ada796c839135b3d30554bbb74a4b1e4a5a58505c"), 32); + ck_assert_mem_eq(node.public_key, fromhex("002e66aa57069c86cc18249aecf5cb5a9cebbfd6fadeab056254763874a9352b45"), 33); + + // [Chain m/0'/2147483647'/1'/2147483646'] + r = hdnode_private_ckd_prime(&node, 2147483646); + ck_assert_int_eq(r, 1); + ck_assert_int_eq(node.fingerprint, 0xaca70953); + ck_assert_mem_eq(node.chain_code, fromhex("0902fe8a29f9140480a00ef244bd183e8a13288e4412d8389d140aac1794825a"), 32); + ck_assert_mem_eq(node.private_key, fromhex("5837736c89570de861ebc173b1086da4f505d4adb387c6a1b1342d5e4ac9ec72"), 32); + ck_assert_mem_eq(node.public_key, fromhex("00e33c0f7d81d843c572275f287498e8d408654fdf0d1e065b84e2e6f157aab09b"), 33); + + // [Chain m/0'/2147483647'/1'/2147483646'/2'] + r = hdnode_private_ckd_prime(&node, 2); + ck_assert_int_eq(r, 1); + ck_assert_int_eq(node.fingerprint, 0x422c654b); + ck_assert_mem_eq(node.chain_code, fromhex("5d70af781f3a37b829f0d060924d5e960bdc02e85423494afc0b1a41bbe196d4"), 32); + ck_assert_mem_eq(node.private_key, fromhex("551d333177df541ad876a60ea71f00447931c0a9da16f227c11ea080d7391b8d"), 32); + ck_assert_mem_eq(node.public_key, fromhex("0047150c75db263559a70d5778bf36abbab30fb061ad69f69ece61a72b0cfa4fc0"), 33); +} +END_TEST + #define test_deterministic(KEY, MSG, K) do { \ sha256_Raw((uint8_t *)MSG, strlen(MSG), buf); \ res = generate_k_rfc6979(curve, &k, fromhex(KEY), buf); \ @@ -1632,6 +1740,11 @@ Suite *test_suite(void) tcase_add_test(tc, test_bip32_nist_repeat); suite_add_tcase(s, tc); + tc = tcase_create("bip32-ed25519"); + tcase_add_test(tc, test_bip32_ed25519_vector_1); + tcase_add_test(tc, test_bip32_ed25519_vector_2); + suite_add_tcase(s, tc); + tc = tcase_create("rfc6979"); tcase_add_test(tc, test_rfc6979); suite_add_tcase(s, tc); From 269b779eadb84366ccad8a3c53a66780684e4f62 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Mon, 25 Apr 2016 16:32:38 +0200 Subject: [PATCH 243/627] Updated cmake configuration for ed25519 --- CMakeLists.txt | 3 ++- Makefile | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0c80b4899..1baf39876 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,7 @@ cmake_minimum_required(VERSION 2.6) -set(SOURCES aescrypt.c aeskey.c aes_modes.c aestab.c base58.c bignum.c bip32.c bip39.c ecdsa.c hmac.c nist256p1.c pbkdf2.c rand.c ripemd160.c secp256k1.c sha2.c) +set(SOURCES aescrypt.c aeskey.c aes_modes.c aestab.c base58.c bignum.c bip32.c bip39.c ecdsa.c hmac.c nist256p1.c pbkdf2.c rand.c ripemd160.c secp256k1.c sha2.c ed25519-donna/ed25519.c) +include_directories(ed25519-donna) # disable sequence point warnings where they are expected set_source_files_properties(aeskey.c PROPERTIES diff --git a/Makefile b/Makefile index 7ae782975..bded2f835 100644 --- a/Makefile +++ b/Makefile @@ -37,9 +37,9 @@ SRCS = bignum.c ecdsa.c curves.c secp256k1.c nist256p1.c rand.c hmac.c bip32.c SRCS += ripemd160.c SRCS += sha2.c SRCS += aescrypt.c aeskey.c aestab.c aes_modes.c +SRCS += ed25519-donna/ed25519.c OBJS = $(SRCS:.c=.o) -OBJS += ed25519-donna/ed25519.o TESTLIBS = -lcheck -lrt -lpthread -lm TESTSSLLIBS = -lcrypto From 490fbed289388110f3ea5611389c931d023699bc Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Mon, 25 Apr 2016 17:37:43 +0200 Subject: [PATCH 244/627] Adapted python unit test to new API --- c.pxd | 2 +- test_curves.py | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/c.pxd b/c.pxd index 6a445d660..dc28f9c65 100644 --- a/c.pxd +++ b/c.pxd @@ -5,7 +5,7 @@ cdef extern from "bip32.h": ctypedef struct HDNode: uint8_t public_key[33] - int hdnode_from_seed(const uint8_t *seed, int seed_len, HDNode *out) + int hdnode_from_seed(const uint8_t *seed, int seed_len, const char *curve, HDNode *out) int hdnode_private_ckd(HDNode *inout, uint32_t i) diff --git a/test_curves.py b/test_curves.py index c511bbc97..845c41b0a 100755 --- a/test_curves.py +++ b/test_curves.py @@ -41,11 +41,13 @@ random_iters = int(os.environ.get('ITERS', 1)) lib = c.cdll.LoadLibrary('./libtrezor-crypto.so') -lib.get_curve_by_name.restype = c.c_void_p +class curve_info(c.Structure): + _fields_ = [("bip32_name", c.c_char_p), + ("params", c.c_void_p)] +lib.get_curve_by_name.restype = c.POINTER(curve_info) BIGNUM = c.c_uint32 * 9 - class Random(random.Random): def randbytes(self, n): buf = (c.c_uint8 * n)() @@ -83,7 +85,7 @@ def r(request): @pytest.fixture(params=list(sorted(curves))) def curve(request): name = request.param - curve_ptr = lib.get_curve_by_name(name) + curve_ptr = lib.get_curve_by_name(name).contents.params assert curve_ptr, 'curve {} not found'.format(name) curve_obj = curves[name] curve_obj.ptr = c.c_void_p(curve_ptr) @@ -93,7 +95,7 @@ def curve(request): @pytest.fixture(params=points) def point(request): name = request.param.curve - curve_ptr = lib.get_curve_by_name(name) + curve_ptr = lib.get_curve_by_name(name).contents.params assert curve_ptr, 'curve {} not found'.format(name) curve_obj = curves[name] curve_obj.ptr = c.c_void_p(curve_ptr) From 059019253686db6b0b43815303791911a0df70cf Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 25 Apr 2016 13:03:26 +0200 Subject: [PATCH 245/627] add testcase for ed25519 --- tests.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/tests.c b/tests.c index 10d259835..085b2d0cc 100644 --- a/tests.c +++ b/tests.c @@ -41,10 +41,11 @@ #include "curves.h" #include "secp256k1.h" #include "nist256p1.h" +#include "ed25519.h" uint8_t *fromhex(const char *str) { - static uint8_t buf[128]; + static uint8_t buf[256]; uint8_t c; size_t i; for (i = 0; i < strlen(str) / 2; i++) { @@ -1714,6 +1715,58 @@ START_TEST(test_scalar_point_mult) { } END_TEST +START_TEST(test_ed25519) { + // test vectors from https://github.com/torproject/tor/blob/master/src/test/ed25519_vectors.inc + static const char *vectors[] = { + "26c76712d89d906e6672dafa614c42e5cb1caac8c6568e4d2493087db51f0d36", // secret + "c2247870536a192d142d056abefca68d6193158e7c1a59c1654c954eccaff894", // public + "d23188eac3773a316d46006fa59c095060be8b1a23582a0dd99002a82a0662bd246d8449e172e04c5f46ac0d1404cebe4aabd8a75a1457aa06cae41f3334f104", // selfsig + "fba7a5366b5cb98c2667a18783f5cf8f4f8d1a2ce939ad22a6e685edde85128d", + "1519a3b15816a1aafab0b213892026ebf5c0dc232c58b21088d88cb90e9b940d", + "3a785ac1201c97ee5f6f0d99323960d5f264c7825e61aa7cc81262f15bef75eb4fa5723add9b9d45b12311b6d403eb3ac79ff8e4e631fc3cd51e4ad2185b200b", + "67e3aa7a14fac8445d15e45e38a523481a69ae35513c9e4143eb1c2196729a0e", + "081faa81992e360ea22c06af1aba096e7a73f1c665bc8b3e4e531c46455fd1dd", + "cf431fd0416bfbd20c9d95ef9b723e2acddffb33900edc72195dea95965d52d888d30b7b8a677c0bd8ae1417b1e1a0ec6700deadd5d8b54b6689275e04a04509", + "d51385942033a76dc17f089a59e6a5a7fe80d9c526ae8ddd8c3a506b99d3d0a6", + "73cfa1189a723aad7966137cbffa35140bb40d7e16eae4c40b79b5f0360dd65a", + "2375380cd72d1a6c642aeddff862be8a5804b916acb72c02d9ed052c1561881aa658a5af856fcd6d43113e42f698cd6687c99efeef7f2ce045824440d26c5d00", + "5c8eac469bb3f1b85bc7cd893f52dc42a9ab66f1b02b5ce6a68e9b175d3bb433", + "66c1a77104d86461b6f98f73acf3cd229c80624495d2d74d6fda1e940080a96b", + "2385a472f599ca965bbe4d610e391cdeabeba9c336694b0d6249e551458280be122c2441dd9746a81bbfb9cd619364bab0df37ff4ceb7aefd24469c39d3bc508", + "eda433d483059b6d1ff8b7cfbd0fe406bfb23722c8f3c8252629284573b61b86", + "d21c294db0e64cb2d8976625786ede1d9754186ae8197a64d72f68c792eecc19", + "e500cd0b8cfff35442f88008d894f3a2fa26ef7d3a0ca5714ae0d3e2d40caae58ba7cdf69dd126994dad6be536fcda846d89dd8138d1683cc144c8853dce7607", + "4377c40431c30883c5fbd9bc92ae48d1ed8a47b81d13806beac5351739b5533d", + "c4d58b4cf85a348ff3d410dd936fa460c4f18da962c01b1963792b9dcc8a6ea6", + "d187b9e334b0050154de10bf69b3e4208a584e1a65015ec28b14bcc252cf84b8baa9c94867daa60f2a82d09ba9652d41e8dde292b624afc8d2c26441b95e3c0e", + "c6bbcce615839756aed2cc78b1de13884dd3618f48367a17597a16c1cd7a290b", + "95126f14d86494020665face03f2d42ee2b312a85bc729903eb17522954a1c4a", + "815213640a643d198bd056e02bba74e1c8d2d931643e84497adf3347eb485079c9afe0afce9284cdc084946b561abbb214f1304ca11228ff82702185cf28f60d", + 0, + 0, + 0, + }; + const char **ssk, **spk, **ssig; + ssk = vectors; + spk = vectors + 1; + ssig = vectors + 2; + ed25519_public_key pk; + ed25519_secret_key sk; + ed25519_signature sig; + while (*ssk && *spk && *ssig) { + memcpy(sk, fromhex(*ssk), 32); + ed25519_publickey(sk, pk); + ck_assert_mem_eq(pk, fromhex(*spk), 32); + ed25519_sign(pk, 32, sk, pk, sig); + ck_assert_mem_eq(sig, fromhex(*ssig), 64); + ssk += 3; + spk += 3; + ssig += 3; + } +} +END_TEST + + // define test suite and cases Suite *test_suite(void) { @@ -1807,6 +1860,11 @@ Suite *test_suite(void) tc = tcase_create("scalar_point_mult"); tcase_add_test(tc, test_scalar_point_mult); suite_add_tcase(s, tc); + + tc = tcase_create("ed25519"); + tcase_add_test(tc, test_ed25519); + suite_add_tcase(s, tc); + return s; } From 6f66162e93540653b870161cc4b106f58c341e6d Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 25 Apr 2016 17:15:02 +0200 Subject: [PATCH 246/627] fix tools and gui --- gui/gui.pro | 8 +++++++- gui/mainwindow.cpp | 3 ++- tools/Makefile | 2 +- tools/bip39bruteforce.c | 9 +++++---- tools/mktable.c | 3 ++- tools/xpubaddrgen.c | 4 ++-- 6 files changed, 19 insertions(+), 10 deletions(-) diff --git a/gui/gui.pro b/gui/gui.pro index 2ac6ec09a..2b89a71df 100644 --- a/gui/gui.pro +++ b/gui/gui.pro @@ -4,8 +4,14 @@ greaterThan(QT_MAJOR_VERSION, 4): QT += widgets TARGET = gui TEMPLATE = app -SOURCES += ../bip32.c ../bip39.c ../sha2.c ../pbkdf2.c ../hmac.c ../rand.c ../bignum.c ../ecdsa.c ../ripemd160.c ../base58.c ../secp256k1.c ../nist256p1.c mainwindow.cpp main.cpp +SOURCES += ../bip32.c ../bip39.c ../sha2.c ../pbkdf2.c ../hmac.c ../rand.c ../bignum.c ../ecdsa.c ../ripemd160.c ../base58.c ../secp256k1.c ../nist256p1.c ../curves.c ../ed25519-donna/ed25519.c mainwindow.cpp main.cpp HEADERS += mainwindow.h ../bip32.h ../bip39.h FORMS += mainwindow.ui + +INCLUDEPATH += .. +INCLUDEPATH += ../ed25519-donna + +DEFINES += ED25519_CUSTOMRANDOM=1 +DEFINES += ED25519_CUSTOMHASH=1 diff --git a/gui/mainwindow.cpp b/gui/mainwindow.cpp index a67d28857..fd2d3c312 100644 --- a/gui/mainwindow.cpp +++ b/gui/mainwindow.cpp @@ -5,6 +5,7 @@ extern "C" { #include "../bip32.h" #include "../bip39.h" #include "../ecdsa.h" +#include "../curves.h" } bool root_set = false; @@ -35,7 +36,7 @@ void MainWindow::on_buttonLoad_clicked() } uint8_t seed[64]; mnemonic_to_seed(ui->editMnemonic->text().toLocal8Bit().data(), ui->editPassphrase->text().toLocal8Bit().data(), seed, 0); - hdnode_from_seed(seed, 64, &root); + hdnode_from_seed(seed, 64, SECP256K1_NAME, &root); root_set = true; ui->spinAccount->setValue(1); on_spinAccount_valueChanged(1); diff --git a/tools/Makefile b/tools/Makefile index 61032e658..481a46bcb 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -25,7 +25,7 @@ CFLAGS += $(OPTFLAGS) \ all: xpubaddrgen mktable bip39bruteforce -OBJS = ../bip32.o ../bip39.o ../ecdsa.o ../sha2.o ../bignum.o ../base58.o ../secp256k1.o ../nist256p1.o ../ripemd160.o ../hmac.o ../rand.o ../pbkdf2.o +OBJS = ../bip32.o ../bip39.o ../ecdsa.o ../sha2.o ../bignum.o ../base58.o ../secp256k1.o ../nist256p1.o ../ripemd160.o ../hmac.o ../rand.o ../pbkdf2.o ../curves.o ../ed25519-donna/ed25519.o %.o: %.c %.h options.h $(CC) $(CFLAGS) -o $@ -c $< diff --git a/tools/bip39bruteforce.c b/tools/bip39bruteforce.c index e6e9be02e..a55158828 100644 --- a/tools/bip39bruteforce.c +++ b/tools/bip39bruteforce.c @@ -1,9 +1,10 @@ #include #include #include -#include -#include -#include +#include "bip39.h" +#include "bip32.h" +#include "ecdsa.h" +#include "curves.h" char passphrase[256]; uint8_t seed[512 / 8]; @@ -47,7 +48,7 @@ int main(int argc, char **argv) count++; passphrase[len - 1] = 0; mnemonic_to_seed(mnemonic, passphrase, seed, NULL); - hdnode_from_seed(seed, 512 / 8, &node); + hdnode_from_seed(seed, 512 / 8, SECP256K1_NAME, &node); hdnode_private_ckd_prime(&node, 44); hdnode_private_ckd_prime(&node, 0); hdnode_private_ckd_prime(&node, 0); diff --git a/tools/mktable.c b/tools/mktable.c index 77997039d..292adac9c 100644 --- a/tools/mktable.c +++ b/tools/mktable.c @@ -3,6 +3,7 @@ #include "bignum.h" #include "ecdsa.h" #include "rand.h" +#include "bip32.h" /* * This program prints the contents of the ecdsa_curve.cp array. @@ -16,7 +17,7 @@ int main(int argc, char **argv) { return 1; } const char *name = argv[1]; - const ecdsa_curve *curve = get_curve_by_name(name); + const curve_info *curve = get_curve_by_name(name); if (curve == 0) { printf("Unknown curve '%s'\n", name); return 1; diff --git a/tools/xpubaddrgen.c b/tools/xpubaddrgen.c index 42f87826f..12b350d72 100644 --- a/tools/xpubaddrgen.c +++ b/tools/xpubaddrgen.c @@ -2,8 +2,8 @@ #include #include #include -#include -#include +#include "bip32.h" +#include "ecdsa.h" void process_job(uint32_t jobid, const char *xpub, uint32_t change, uint32_t from, uint32_t to) { From a90257c422b638e115a31b6f481651141afba076 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Mon, 25 Apr 2016 17:49:17 +0200 Subject: [PATCH 247/627] Updated mktable to new api --- tools/mktable.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/mktable.c b/tools/mktable.c index 292adac9c..01ec375c9 100644 --- a/tools/mktable.c +++ b/tools/mktable.c @@ -2,8 +2,8 @@ #include #include "bignum.h" #include "ecdsa.h" -#include "rand.h" #include "bip32.h" +#include "rand.h" /* * This program prints the contents of the ecdsa_curve.cp array. @@ -17,7 +17,8 @@ int main(int argc, char **argv) { return 1; } const char *name = argv[1]; - const curve_info *curve = get_curve_by_name(name); + const curve_info *info = get_curve_by_name(name); + const ecdsa_curve *curve = info->params; if (curve == 0) { printf("Unknown curve '%s'\n", name); return 1; From 409783ba642d46075d16ca58b2e1bb8f17d86620 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Mon, 25 Apr 2016 13:12:53 +0200 Subject: [PATCH 248/627] New function ecdsa_verify_recover Moved the code from Trezor firmware to here for recovering the public key when verifying a bitcoin message. Fixed the signing and verification for the unlikely case the r value overflows. --- ecdsa.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-- ecdsa.h | 1 + 2 files changed, 57 insertions(+), 2 deletions(-) diff --git a/ecdsa.c b/ecdsa.c index 0a46190b7..78eedb49f 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -735,7 +735,12 @@ int ecdsa_sign_digest(const ecdsa_curve *curve, const uint8_t *priv_key, const u *pby = R.y.val[0] & 1; } // r = (rx mod n) - bn_mod(&R.x, &curve->order); + if (!bn_is_less(&R.x, &curve->order)) { + bn_subtract(&R.x, &curve->order, &R.x); + if (pby) { + *pby |= 2; + } + } // if r is zero, we fail if (bn_is_zero(&R.x)) { @@ -766,7 +771,7 @@ int ecdsa_sign_digest(const ecdsa_curve *curve, const uint8_t *priv_key, const u if (bn_is_less(&curve->order_half, &k)) { bn_subtract(&curve->order, &k, &k); if (pby) { - *pby = !*pby; + *pby ^= 1; } } // we are done, R.x and k is the result signature @@ -950,6 +955,55 @@ int ecdsa_verify_double(const ecdsa_curve *curve, const uint8_t *pub_key, const return res; } +// Compute public key from signature and recovery id. +// returns 0 if verification succeeded +int ecdsa_verify_digest_recover(const ecdsa_curve *curve, uint8_t *pub_key, const uint8_t *sig, const uint8_t *digest, int recid) +{ + bignum256 r, s, e; + curve_point cp, cp2; + + // read r and s + bn_read_be(sig, &r); + bn_read_be(sig + 32, &s); + if (!bn_is_less(&r, &curve->order) || bn_is_zero(&r)) { + return 1; + } + if (!bn_is_less(&s, &curve->order) || bn_is_zero(&s)) { + return 1; + } + // cp = R = k * G (k is secret nonce when signing) + memcpy(&cp.x, &r, sizeof(bignum256)); + if (recid & 2) { + bn_add(&cp.x, &curve->order); + if (!bn_is_less(&cp.x, &curve->prime)) { + return 1; + } + } + // compute y from x + uncompress_coords(curve, recid & 1, &cp.x, &cp.y); + if (!ecdsa_validate_pubkey(curve, &cp)) { + return 1; + } + // e = -digest + bn_read_be(digest, &e); + bn_mod(&e, &curve->order); + bn_subtract(&curve->order, &e, &e); + // r := r^-1 + bn_inverse(&r, &curve->order); + // cp := s * R = s * k *G + point_multiply(curve, &s, &cp, &cp); + // cp2 := -digest * G + scalar_multiply(curve, &e, &cp2); + // cp := (s * k - digest) * G = (r*priv) * G = r * Pub + point_add(curve, &cp2, &cp); + // cp := r^{-1} * r * Pub = Pub + point_multiply(curve, &r, &cp, &cp); + pub_key[0] = 0x04; + bn_write_be(&cp.x, pub_key + 1); + bn_write_be(&cp.y, pub_key + 33); + return 0; +} + // returns 0 if verification succeeded int ecdsa_verify_digest(const ecdsa_curve *curve, const uint8_t *pub_key, const uint8_t *sig, const uint8_t *digest) { diff --git a/ecdsa.h b/ecdsa.h index 2a6edde65..45cbb81d5 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -75,6 +75,7 @@ int ecdsa_validate_pubkey(const ecdsa_curve *curve, const curve_point *pub); int ecdsa_verify(const ecdsa_curve *curve, const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, uint32_t msg_len); int ecdsa_verify_double(const ecdsa_curve *curve, const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, uint32_t msg_len); int ecdsa_verify_digest(const ecdsa_curve *curve, const uint8_t *pub_key, const uint8_t *sig, const uint8_t *digest); +int ecdsa_verify_digest_recover(const ecdsa_curve *curve, uint8_t *pub_key, const uint8_t *sig, const uint8_t *digest, int recid); int ecdsa_sig_to_der(const uint8_t *sig, uint8_t *der); // Private From 7b07dff25ca02efb2ce7fd3543f48b38a7fa50a6 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Mon, 25 Apr 2016 22:24:44 +0200 Subject: [PATCH 249/627] Added Unit test, fixed one corner case. --- ecdsa.c | 3 ++- tests.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 1 deletion(-) diff --git a/ecdsa.c b/ecdsa.c index 78eedb49f..bb465a2f4 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -986,8 +986,9 @@ int ecdsa_verify_digest_recover(const ecdsa_curve *curve, uint8_t *pub_key, cons } // e = -digest bn_read_be(digest, &e); + bn_subtractmod(&curve->order, &e, &e, &curve->order); + bn_fast_mod(&e, &curve->order); bn_mod(&e, &curve->order); - bn_subtract(&curve->order, &e, &e); // r := r^-1 bn_inverse(&r, &curve->order); // cp := s * R = s * k *G diff --git a/tests.c b/tests.c index 085b2d0cc..d46c86220 100644 --- a/tests.c +++ b/tests.c @@ -816,6 +816,70 @@ START_TEST(test_bip32_ed25519_vector_2) } END_TEST +START_TEST(test_ecdsa_signature) +{ + int res; + uint8_t digest[32]; + uint8_t pubkey[65]; + const ecdsa_curve *curve = &secp256k1; + + + // sha2(sha2("\x18Bitcoin Signed Message:\n\x0cHello World!")) + memcpy(digest, fromhex("de4e9524586d6fce45667f9ff12f661e79870c4105fa0fb58af976619bb11432"), 32); + // r = 2: Four points should exist + res = ecdsa_verify_digest_recover(curve, pubkey, fromhex("00000000000000000000000000000000000000000000000000000000000000020123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), digest, 0); + ck_assert_int_eq(res, 0); + ck_assert_mem_eq(pubkey, fromhex("043fc5bf5fec35b6ffe6fd246226d312742a8c296bfa57dd22da509a2e348529b7ddb9faf8afe1ecda3c05e7b2bda47ee1f5a87e952742b22afca560b29d972fcf"), 65); + res = ecdsa_verify_digest_recover(curve, pubkey, fromhex("00000000000000000000000000000000000000000000000000000000000000020123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), digest, 1); + ck_assert_int_eq(res, 0); + ck_assert_mem_eq(pubkey, fromhex("0456d8089137b1fd0d890f8c7d4a04d0fd4520a30b19518ee87bd168ea12ed8090329274c4c6c0d9df04515776f2741eeffc30235d596065d718c3973e19711ad0"), 65); + res = ecdsa_verify_digest_recover(curve, pubkey, fromhex("00000000000000000000000000000000000000000000000000000000000000020123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), digest, 2); + ck_assert_int_eq(res, 0); + ck_assert_mem_eq(pubkey, fromhex("04cee0e740f41aab39156844afef0182dea2a8026885b10454a2d539df6f6df9023abfcb0f01c50bef3c0fa8e59a998d07441e18b1c60583ef75cc8b912fb21a15"), 65); + res = ecdsa_verify_digest_recover(curve, pubkey, fromhex("00000000000000000000000000000000000000000000000000000000000000020123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), digest, 3); + ck_assert_int_eq(res, 0); + ck_assert_mem_eq(pubkey, fromhex("0490d2bd2e9a564d6e1d8324fc6ad00aa4ae597684ecf4abea58bdfe7287ea4fa72968c2e5b0b40999ede3d7898d94e82c3f8dc4536a567a4bd45998c826a4c4b2"), 65); + + memcpy(digest, fromhex("0000000000000000000000000000000000000000000000000000000000000000"), 32); + // r = 7: No point P with P.x = 7, but P.x = (order + 7) exists + res = ecdsa_verify_digest_recover(curve, pubkey, fromhex("00000000000000000000000000000000000000000000000000000000000000070123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), digest, 2); + ck_assert_int_eq(res, 0); + ck_assert_mem_eq(pubkey, fromhex("044d81bb47a31ffc6cf1f780ecb1e201ec47214b651650867c07f13ad06e12a1b040de78f8dbda700f4d3cd7ee21b3651a74c7661809699d2be7ea0992b0d39797"), 65); + res = ecdsa_verify_digest_recover(curve, pubkey, fromhex("00000000000000000000000000000000000000000000000000000000000000070123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), digest, 3); + ck_assert_int_eq(res, 0); + ck_assert_mem_eq(pubkey, fromhex("044d81bb47a31ffc6cf1f780ecb1e201ec47214b651650867c07f13ad06e12a1b0bf21870724258ff0b2c32811de4c9ae58b3899e7f69662d41815f66c4f2c6498"), 65); + res = ecdsa_verify_digest_recover(curve, pubkey, fromhex("00000000000000000000000000000000000000000000000000000000000000070123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), digest, 0); + ck_assert_int_eq(res, 1); + + memcpy(digest, fromhex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), 32); + // r = 1: Two points P with P.x = 1, but P.x = (order + 7) doesn't exist + res = ecdsa_verify_digest_recover(curve, pubkey, fromhex("00000000000000000000000000000000000000000000000000000000000000010123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), digest, 0); + ck_assert_int_eq(res, 0); + ck_assert_mem_eq(pubkey, fromhex("045d330b2f89dbfca149828277bae852dd4aebfe136982cb531a88e9e7a89463fe71519f34ea8feb9490c707f14bc38c9ece51762bfd034ea014719b7c85d2871b"), 65); + res = ecdsa_verify_digest_recover(curve, pubkey, fromhex("00000000000000000000000000000000000000000000000000000000000000010123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), digest, 1); + ck_assert_int_eq(res, 0); + ck_assert_mem_eq(pubkey, fromhex("049e609c3950e70d6f3e3f3c81a473b1d5ca72739d51debdd80230ae80cab05134a94285375c834a417e8115c546c41da83a263087b79ef1cae25c7b3c738daa2b"), 65); + + // r = 0 is always invalid + res = ecdsa_verify_digest_recover(curve, pubkey, fromhex("00000000000000000000000000000000000000000000000000000000000000010123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), digest, 2); + ck_assert_int_eq(res, 1); + res = ecdsa_verify_digest_recover(curve, pubkey, fromhex("00000000000000000000000000000000000000000000000000000000000000000123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), digest, 0); + ck_assert_int_eq(res, 1); + // r >= order is always invalid + res = ecdsa_verify_digest_recover(curve, pubkey, fromhex("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641410123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), digest, 0); + ck_assert_int_eq(res, 1); + // check that overflow of r is handled + res = ecdsa_verify_digest_recover(curve, pubkey, fromhex("000000000000000000000000000000014551231950B75FC4402DA1722FC9BAEE0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), digest, 2); + ck_assert_int_eq(res, 1); + // s = 0 is always invalid + res = ecdsa_verify_digest_recover(curve, pubkey, fromhex("00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000"), digest, 0); + ck_assert_int_eq(res, 1); + // s >= order is always invalid + res = ecdsa_verify_digest_recover(curve, pubkey, fromhex("0000000000000000000000000000000000000000000000000000000000000002fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"), digest, 0); + ck_assert_int_eq(res, 1); +} +END_TEST + #define test_deterministic(KEY, MSG, K) do { \ sha256_Raw((uint8_t *)MSG, strlen(MSG), buf); \ res = generate_k_rfc6979(curve, &k, fromhex(KEY), buf); \ @@ -1798,6 +1862,10 @@ Suite *test_suite(void) tcase_add_test(tc, test_bip32_ed25519_vector_2); suite_add_tcase(s, tc); + tc = tcase_create("ecdsa"); + tcase_add_test(tc, test_ecdsa_signature); + suite_add_tcase(s, tc); + tc = tcase_create("rfc6979"); tcase_add_test(tc, test_rfc6979); suite_add_tcase(s, tc); From 0054893b60fb3e8fa4d8ba2ed4a57e394ab96c2c Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 26 Apr 2016 00:17:13 +0200 Subject: [PATCH 250/627] add test speed for nist256p1 curve as well --- tests.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 48 insertions(+), 4 deletions(-) diff --git a/tests.c b/tests.c index 085b2d0cc..6854a74b5 100644 --- a/tests.c +++ b/tests.c @@ -845,12 +845,12 @@ START_TEST(test_sign_speed) uint8_t sig[64], priv_key[32], msg[256]; size_t i; int res; - const ecdsa_curve *curve = &secp256k1; for (i = 0; i < sizeof(msg); i++) { msg[i] = i * 1103515245; } + const ecdsa_curve *curve = &secp256k1; clock_t t = clock(); memcpy(priv_key, fromhex("c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd5"), 32); @@ -865,7 +865,24 @@ START_TEST(test_sign_speed) ck_assert_int_eq(res, 0); } - printf("Signing speed: %0.2f sig/s\n", 500.0f / ((float)(clock() - t) / CLOCKS_PER_SEC)); + printf("SECP256k1 signing speed: %0.2f sig/s\n", 500.0f / ((float)(clock() - t) / CLOCKS_PER_SEC)); + + curve = &nist256p1; + t = clock(); + + memcpy(priv_key, fromhex("c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd5"), 32); + for (i = 0 ; i < 250; i++) { + res = ecdsa_sign(curve, priv_key, msg, sizeof(msg), sig, 0); + ck_assert_int_eq(res, 0); + } + + memcpy(priv_key, fromhex("509a0382ff5da48e402967a671bdcde70046d07f0df52cff12e8e3883b426a0a"), 32); + for (i = 0 ; i < 250; i++) { + res = ecdsa_sign(curve, priv_key, msg, sizeof(msg), sig, 0); + ck_assert_int_eq(res, 0); + } + + printf("NIST256p1 signing speed: %0.2f sig/s\n", 500.0f / ((float)(clock() - t) / CLOCKS_PER_SEC)); } END_TEST @@ -874,12 +891,12 @@ START_TEST(test_verify_speed) uint8_t sig[64], pub_key33[33], pub_key65[65], msg[256]; size_t i; int res; - const ecdsa_curve *curve = &secp256k1; for (i = 0; i < sizeof(msg); i++) { msg[i] = i * 1103515245; } + const ecdsa_curve *curve = &secp256k1; clock_t t = clock(); memcpy(sig, fromhex("88dc0db6bc5efa762e75fbcc802af69b9f1fcdbdffce748d403f687f855556e610ee8035414099ac7d89cff88a3fa246d332dfa3c78d82c801394112dda039c2"), 64); @@ -904,7 +921,34 @@ START_TEST(test_verify_speed) ck_assert_int_eq(res, 0); } - printf("Verifying speed: %0.2f sig/s\n", 100.0f / ((float)(clock() - t) / CLOCKS_PER_SEC)); + printf("SECP256k1 verifying speed: %0.2f sig/s\n", 100.0f / ((float)(clock() - t) / CLOCKS_PER_SEC)); + + curve = &nist256p1; + t = clock(); + + memcpy(sig, fromhex("7ed26b02c7e9664baaaa1e6ab64b3350c65ff685a7502863f357029c21c92a0dd7f2ae56d229262a8c7e97a0bfe1e7f9fd80c29df97355afa52ca07b507cecb9"), 64); + memcpy(pub_key33, fromhex("035662d692de519699000c7f5f04b2714e6a7f358c567fbcc001107ab86e4a7dea"), 33); + memcpy(pub_key65, fromhex("045662d692de519699000c7f5f04b2714e6a7f358c567fbcc001107ab86e4a7dea40523030e793724473d3cd60e436cbfc0a6e4ac5a5d0b340c5d637c6c870c00f"), 65); + + for (i = 0 ; i < 25; i++) { + res = ecdsa_verify(curve, pub_key65, sig, msg, sizeof(msg)); + //ck_assert_int_eq(res, 0); + res = ecdsa_verify(curve, pub_key33, sig, msg, sizeof(msg)); + //ck_assert_int_eq(res, 0); + } + + memcpy(sig, fromhex("6e13956f4227e66264dfcd92cf40b3b253622e96b1e1030392c0b06d9570f725dd1542164a481c0342ceb0b575f3516df536b7b90da57c381dfbd1aac6138c0b"), 64); + memcpy(pub_key33, fromhex("034b17f6b5c42b1be32c09f49056ee793e67f3ff42058123ce72fffc61d7236bc2"), 33); + memcpy(pub_key65, fromhex("044b17f6b5c42b1be32c09f49056ee793e67f3ff42058123ce72fffc61d7236bc29b6c29cbbbb2681d2b2e9c699cde8e591650d02bf4bb577ec53fd229442882e5"), 65); + + for (i = 0 ; i < 25; i++) { + res = ecdsa_verify(curve, pub_key65, sig, msg, sizeof(msg)); + //ck_assert_int_eq(res, 0); + res = ecdsa_verify(curve, pub_key33, sig, msg, sizeof(msg)); + //ck_assert_int_eq(res, 0); + } + + printf("NIST256p1 verifying speed: %0.2f sig/s\n", 100.0f / ((float)(clock() - t) / CLOCKS_PER_SEC)); } END_TEST From 5c4e131ada3d6cab0c689802415d92ccc2eec0fe Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 26 Apr 2016 02:14:47 +0200 Subject: [PATCH 251/627] add speed benchmark (secp256k1 vs ed25519) --- .gitignore | 1 + Makefile | 9 ++++++-- test_speed.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++ tests.c | 6 ++---- 4 files changed, 70 insertions(+), 6 deletions(-) create mode 100644 test_speed.c diff --git a/.gitignore b/.gitignore index 589679feb..f1da71bbc 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ *.exe *~ test-openssl +test_speed tests build-*/ build/ diff --git a/Makefile b/Makefile index bded2f835..683774a26 100644 --- a/Makefile +++ b/Makefile @@ -26,6 +26,8 @@ CFLAGS += $(OPTFLAGS) \ CFLAGS += -Wno-sequence-point CFLAGS += -DED25519_CUSTOMRANDOM=1 CFLAGS += -DED25519_CUSTOMHASH=1 +CFLAGS += -DED25519_NO_INLINE_ASM +CFLAGS += -DED25519_FORCE_32BIT=1 CFLAGS += -Ied25519-donna -I. # disable certain optimizations and features when small footprint is required @@ -44,7 +46,7 @@ OBJS = $(SRCS:.c=.o) TESTLIBS = -lcheck -lrt -lpthread -lm TESTSSLLIBS = -lcrypto -all: tests test-openssl libtrezor-crypto.so +all: tests test-openssl libtrezor-crypto.so test_speed %.o: %.c %.h options.h $(CC) $(CFLAGS) -o $@ -c $< @@ -52,6 +54,9 @@ all: tests test-openssl libtrezor-crypto.so tests: tests.o $(OBJS) $(CC) tests.o $(OBJS) $(TESTLIBS) -o tests +test_speed: test_speed.o $(OBJS) + $(CC) test_speed.o $(OBJS) $(TESTLIBS) -o test_speed + test-openssl: test-openssl.o $(OBJS) $(CC) test-openssl.o $(OBJS) $(TESTSSLLIBS) -o test-openssl @@ -59,4 +64,4 @@ libtrezor-crypto.so: $(SRCS) $(CC) $(CFLAGS) -fPIC -shared $(SRCS) -o libtrezor-crypto.so clean: - rm -f *.o ed25519-donna/*.o tests test-openssl libtrezor-crypto.so + rm -f *.o ed25519-donna/*.o tests test_speed test-openssl libtrezor-crypto.so diff --git a/test_speed.c b/test_speed.c new file mode 100644 index 000000000..0541ef246 --- /dev/null +++ b/test_speed.c @@ -0,0 +1,60 @@ +#include +#include +#include +#include +#include +#include "curves.h" +#include "ecdsa.h" +#include "secp256k1.h" +#include "ed25519.h" + +uint8_t msg[32]; + +void prepare_msg(void) +{ + for (size_t i = 0; i < sizeof(msg); i++) { + msg[i] = i * 1103515245; + } +} + +void bench_secp256k1(void) { + uint8_t sig[64], pub[33], priv[32], pby; + + const ecdsa_curve *curve = &secp256k1; + + memcpy(priv, "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", 32); + ecdsa_get_public_key33(curve, priv, pub); + ecdsa_sign(curve, priv, msg, sizeof(msg), sig, &pby); + + clock_t t = clock(); + for (int i = 0 ; i < 500; i++) { + int res = ecdsa_verify(curve, pub, sig, msg, sizeof(msg)); + assert(res == 0); + } + printf("SECP256k1 verifying speed: %0.2f sig/s\n", 500.0f / ((float)(clock() - t) / CLOCKS_PER_SEC)); +} + +void bench_ed25519(void) { + ed25519_public_key pk; + ed25519_secret_key sk; + ed25519_signature sig; + + memcpy(pk, "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", 32); + ed25519_publickey(sk, pk); + ed25519_sign(msg, sizeof(msg), sk, pk, sig); + + clock_t t = clock(); + for (int i = 0 ; i < 500; i++) { + int res = ed25519_sign_open(msg, sizeof(msg), pk, sig); + assert(res == 0); + } + printf("Ed25519 verifying speed: %0.2f sig/s\n", 500.0f / ((float)(clock() - t) / CLOCKS_PER_SEC)); + +} + +int main(void) { + prepare_msg(); + bench_secp256k1(); + bench_ed25519(); + return 0; +} diff --git a/tests.c b/tests.c index 32cf6be3b..16d64e9c0 100644 --- a/tests.c +++ b/tests.c @@ -47,8 +47,7 @@ uint8_t *fromhex(const char *str) { static uint8_t buf[256]; uint8_t c; - size_t i; - for (i = 0; i < strlen(str) / 2; i++) { + for (size_t i = 0; i < strlen(str) / 2; i++) { c = 0; if (str[i*2] >= '0' && str[i*2] <= '9') c += (str[i*2] - '0') << 4; if (str[i*2] >= 'a' && str[i*2] <= 'f') c += (10 + str[i*2] - 'a') << 4; @@ -65,8 +64,7 @@ char *tohex(const uint8_t *bin, size_t l) { char *buf = (char *)malloc(l * 2 + 1); static char digits[] = "0123456789abcdef"; - size_t i; - for (i = 0; i < l; i++) { + for (size_t i = 0; i < l; i++) { buf[i*2 ] = digits[(bin[i] >> 4) & 0xF]; buf[i*2+1] = digits[bin[i] & 0xF]; } From 76142522e9e3a81fea6086707249adf3ac4484ed Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 26 Apr 2016 02:15:43 +0200 Subject: [PATCH 252/627] mention Ed25519 in the readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 90dbf421a..24f515238 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,7 @@ These include: - ECDSA signing/verifying (supports secp256k1 and nist256p1 curves, uses RFC6979 for deterministic signatures) - ECDSA public key derivation + Base58 address representation +- Ed25519 signing/verifying - HMAC-SHA256 and HMAC-SHA512 - PBKDF2 - RIPEMD-160 From c01be339f5c43d244aa545c444cd060f334f7fe2 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 26 Apr 2016 11:09:29 +0200 Subject: [PATCH 253/627] add sha3 from rhash --- Makefile | 1 + README.md | 1 + sha3.c | 361 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ sha3.h | 73 +++++++++++ 4 files changed, 436 insertions(+) create mode 100644 sha3.c create mode 100644 sha3.h diff --git a/Makefile b/Makefile index 683774a26..981f17b77 100644 --- a/Makefile +++ b/Makefile @@ -38,6 +38,7 @@ endif SRCS = bignum.c ecdsa.c curves.c secp256k1.c nist256p1.c rand.c hmac.c bip32.c bip39.c pbkdf2.c base58.c SRCS += ripemd160.c SRCS += sha2.c +SRCS += sha3.c SRCS += aescrypt.c aeskey.c aestab.c aes_modes.c SRCS += ed25519-donna/ed25519.c diff --git a/README.md b/README.md index 24f515238..593197f90 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,7 @@ These include: - PBKDF2 - RIPEMD-160 - SHA256/SHA512 +- SHA3/Keccak - unit tests (using Check - check.sf.net; in tests.c) - tests against OpenSSL (in test-openssl.c) diff --git a/sha3.c b/sha3.c new file mode 100644 index 000000000..5f3233dd0 --- /dev/null +++ b/sha3.c @@ -0,0 +1,361 @@ +/* sha3.c - an implementation of Secure Hash Algorithm 3 (Keccak). + * based on the + * The Keccak SHA-3 submission. Submission to NIST (Round 3), 2011 + * by Guido Bertoni, Joan Daemen, Michaël Peeters and Gilles Van Assche + * + * Copyright: 2013 Aleksey Kravchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. Use this program at your own risk! + */ + +#include +#include +#include "sha3.h" + +#define I64(x) x##LL +#define ROTL64(qword, n) ((qword) << (n) ^ ((qword) >> (64 - (n)))) +#define le2me_64(x) (x) +#define IS_ALIGNED_64(p) (0 == (7 & ((const char*)(p) - (const char*)0))) +# define me64_to_le_str(to, from, length) memcpy((to), (from), (length)) + +/* constants */ +#define NumberOfRounds 24 + +/* SHA3 (Keccak) constants for 24 rounds */ +static uint64_t keccak_round_constants[NumberOfRounds] = { + I64(0x0000000000000001), I64(0x0000000000008082), I64(0x800000000000808A), I64(0x8000000080008000), + I64(0x000000000000808B), I64(0x0000000080000001), I64(0x8000000080008081), I64(0x8000000000008009), + I64(0x000000000000008A), I64(0x0000000000000088), I64(0x0000000080008009), I64(0x000000008000000A), + I64(0x000000008000808B), I64(0x800000000000008B), I64(0x8000000000008089), I64(0x8000000000008003), + I64(0x8000000000008002), I64(0x8000000000000080), I64(0x000000000000800A), I64(0x800000008000000A), + I64(0x8000000080008081), I64(0x8000000000008080), I64(0x0000000080000001), I64(0x8000000080008008) +}; + +/* Initializing a sha3 context for given number of output bits */ +static void keccak_Init(SHA3_CTX *ctx, unsigned bits) +{ + /* NB: The Keccak capacity parameter = bits * 2 */ + unsigned rate = 1600 - bits * 2; + + memset(ctx, 0, sizeof(SHA3_CTX)); + ctx->block_size = rate / 8; + assert(rate <= 1600 && (rate % 64) == 0); +} + +/** + * Initialize context before calculating hash. + * + * @param ctx context to initialize + */ +void sha3_224_Init(SHA3_CTX *ctx) +{ + keccak_Init(ctx, 224); +} + +/** + * Initialize context before calculating hash. + * + * @param ctx context to initialize + */ +void sha3_256_Init(SHA3_CTX *ctx) +{ + keccak_Init(ctx, 256); +} + +/** + * Initialize context before calculating hash. + * + * @param ctx context to initialize + */ +void sha3_384_Init(SHA3_CTX *ctx) +{ + keccak_Init(ctx, 384); +} + +/** + * Initialize context before calculating hash. + * + * @param ctx context to initialize + */ +void sha3_512_Init(SHA3_CTX *ctx) +{ + keccak_Init(ctx, 512); +} + +/* Keccak theta() transformation */ +static void keccak_theta(uint64_t *A) +{ + unsigned int x; + uint64_t C[5], D[5]; + + for (x = 0; x < 5; x++) { + C[x] = A[x] ^ A[x + 5] ^ A[x + 10] ^ A[x + 15] ^ A[x + 20]; + } + D[0] = ROTL64(C[1], 1) ^ C[4]; + D[1] = ROTL64(C[2], 1) ^ C[0]; + D[2] = ROTL64(C[3], 1) ^ C[1]; + D[3] = ROTL64(C[4], 1) ^ C[2]; + D[4] = ROTL64(C[0], 1) ^ C[3]; + + for (x = 0; x < 5; x++) { + A[x] ^= D[x]; + A[x + 5] ^= D[x]; + A[x + 10] ^= D[x]; + A[x + 15] ^= D[x]; + A[x + 20] ^= D[x]; + } +} + +/* Keccak pi() transformation */ +static void keccak_pi(uint64_t *A) +{ + uint64_t A1; + A1 = A[1]; + A[ 1] = A[ 6]; + A[ 6] = A[ 9]; + A[ 9] = A[22]; + A[22] = A[14]; + A[14] = A[20]; + A[20] = A[ 2]; + A[ 2] = A[12]; + A[12] = A[13]; + A[13] = A[19]; + A[19] = A[23]; + A[23] = A[15]; + A[15] = A[ 4]; + A[ 4] = A[24]; + A[24] = A[21]; + A[21] = A[ 8]; + A[ 8] = A[16]; + A[16] = A[ 5]; + A[ 5] = A[ 3]; + A[ 3] = A[18]; + A[18] = A[17]; + A[17] = A[11]; + A[11] = A[ 7]; + A[ 7] = A[10]; + A[10] = A1; + /* note: A[ 0] is left as is */ +} + +/* Keccak chi() transformation */ +static void keccak_chi(uint64_t *A) +{ + int i; + for (i = 0; i < 25; i += 5) { + uint64_t A0 = A[0 + i], A1 = A[1 + i]; + A[0 + i] ^= ~A1 & A[2 + i]; + A[1 + i] ^= ~A[2 + i] & A[3 + i]; + A[2 + i] ^= ~A[3 + i] & A[4 + i]; + A[3 + i] ^= ~A[4 + i] & A0; + A[4 + i] ^= ~A0 & A1; + } +} + +static void sha3_permutation(uint64_t *state) +{ + int round; + for (round = 0; round < NumberOfRounds; round++) + { + keccak_theta(state); + + /* apply Keccak rho() transformation */ + state[ 1] = ROTL64(state[ 1], 1); + state[ 2] = ROTL64(state[ 2], 62); + state[ 3] = ROTL64(state[ 3], 28); + state[ 4] = ROTL64(state[ 4], 27); + state[ 5] = ROTL64(state[ 5], 36); + state[ 6] = ROTL64(state[ 6], 44); + state[ 7] = ROTL64(state[ 7], 6); + state[ 8] = ROTL64(state[ 8], 55); + state[ 9] = ROTL64(state[ 9], 20); + state[10] = ROTL64(state[10], 3); + state[11] = ROTL64(state[11], 10); + state[12] = ROTL64(state[12], 43); + state[13] = ROTL64(state[13], 25); + state[14] = ROTL64(state[14], 39); + state[15] = ROTL64(state[15], 41); + state[16] = ROTL64(state[16], 45); + state[17] = ROTL64(state[17], 15); + state[18] = ROTL64(state[18], 21); + state[19] = ROTL64(state[19], 8); + state[20] = ROTL64(state[20], 18); + state[21] = ROTL64(state[21], 2); + state[22] = ROTL64(state[22], 61); + state[23] = ROTL64(state[23], 56); + state[24] = ROTL64(state[24], 14); + + keccak_pi(state); + keccak_chi(state); + + /* apply iota(state, round) */ + *state ^= keccak_round_constants[round]; + } +} + +/** + * The core transformation. Process the specified block of data. + * + * @param hash the algorithm state + * @param block the message block to process + * @param block_size the size of the processed block in bytes + */ +static void sha3_process_block(uint64_t hash[25], const uint64_t *block, size_t block_size) +{ + /* expanded loop */ + hash[ 0] ^= le2me_64(block[ 0]); + hash[ 1] ^= le2me_64(block[ 1]); + hash[ 2] ^= le2me_64(block[ 2]); + hash[ 3] ^= le2me_64(block[ 3]); + hash[ 4] ^= le2me_64(block[ 4]); + hash[ 5] ^= le2me_64(block[ 5]); + hash[ 6] ^= le2me_64(block[ 6]); + hash[ 7] ^= le2me_64(block[ 7]); + hash[ 8] ^= le2me_64(block[ 8]); + /* if not sha3-512 */ + if (block_size > 72) { + hash[ 9] ^= le2me_64(block[ 9]); + hash[10] ^= le2me_64(block[10]); + hash[11] ^= le2me_64(block[11]); + hash[12] ^= le2me_64(block[12]); + /* if not sha3-384 */ + if (block_size > 104) { + hash[13] ^= le2me_64(block[13]); + hash[14] ^= le2me_64(block[14]); + hash[15] ^= le2me_64(block[15]); + hash[16] ^= le2me_64(block[16]); + /* if not sha3-256 */ + if (block_size > 136) { + hash[17] ^= le2me_64(block[17]); +#ifdef FULL_SHA3_FAMILY_SUPPORT + /* if not sha3-224 */ + if (block_size > 144) { + hash[18] ^= le2me_64(block[18]); + hash[19] ^= le2me_64(block[19]); + hash[20] ^= le2me_64(block[20]); + hash[21] ^= le2me_64(block[21]); + hash[22] ^= le2me_64(block[22]); + hash[23] ^= le2me_64(block[23]); + hash[24] ^= le2me_64(block[24]); + } +#endif + } + } + } + /* make a permutation of the hash */ + sha3_permutation(hash); +} + +#define SHA3_FINALIZED 0x80000000 + +/** + * Calculate message hash. + * Can be called repeatedly with chunks of the message to be hashed. + * + * @param ctx the algorithm context containing current hashing state + * @param msg message chunk + * @param size length of the message chunk + */ +void sha3_Update(SHA3_CTX *ctx, const unsigned char *msg, size_t size) +{ + size_t index = (size_t)ctx->rest; + size_t block_size = (size_t)ctx->block_size; + + if (ctx->rest & SHA3_FINALIZED) return; /* too late for additional input */ + ctx->rest = (unsigned)((ctx->rest + size) % block_size); + + /* fill partial block */ + if (index) { + size_t left = block_size - index; + memcpy((char*)ctx->message + index, msg, (size < left ? size : left)); + if (size < left) return; + + /* process partial block */ + sha3_process_block(ctx->hash, ctx->message, block_size); + msg += left; + size -= left; + } + while (size >= block_size) { + uint64_t* aligned_message_block; + if (IS_ALIGNED_64(msg)) { + /* the most common case is processing of an already aligned message + without copying it */ + aligned_message_block = (uint64_t*)msg; + } else { + memcpy(ctx->message, msg, block_size); + aligned_message_block = ctx->message; + } + + sha3_process_block(ctx->hash, aligned_message_block, block_size); + msg += block_size; + size -= block_size; + } + if (size) { + memcpy(ctx->message, msg, size); /* save leftovers */ + } +} + +/** + * Store calculated hash into the given array. + * + * @param ctx the algorithm context containing current hashing state + * @param result calculated hash in binary form + */ +void sha3_Final(SHA3_CTX *ctx, unsigned char* result) +{ + size_t digest_length = 100 - ctx->block_size / 2; + const size_t block_size = ctx->block_size; + + if (!(ctx->rest & SHA3_FINALIZED)) + { + /* clear the rest of the data queue */ + memset((char*)ctx->message + ctx->rest, 0, block_size - ctx->rest); + ((char*)ctx->message)[ctx->rest] |= 0x06; + ((char*)ctx->message)[block_size - 1] |= 0x80; + + /* process final block */ + sha3_process_block(ctx->hash, ctx->message, block_size); + ctx->rest = SHA3_FINALIZED; /* mark context as finalized */ + } + + assert(block_size > digest_length); + if (result) me64_to_le_str(result, ctx->hash, digest_length); +} + +#ifdef USE_KECCAK +/** +* Store calculated hash into the given array. +* +* @param ctx the algorithm context containing current hashing state +* @param result calculated hash in binary form +*/ +void keccak_Final(SHA3_CTX *ctx, unsigned char* result) +{ + size_t digest_length = 100 - ctx->block_size / 2; + const size_t block_size = ctx->block_size; + + if (!(ctx->rest & SHA3_FINALIZED)) + { + /* clear the rest of the data queue */ + memset((char*)ctx->message + ctx->rest, 0, block_size - ctx->rest); + ((char*)ctx->message)[ctx->rest] |= 0x01; + ((char*)ctx->message)[block_size - 1] |= 0x80; + + /* process final block */ + sha3_process_block(ctx->hash, ctx->message, block_size); + ctx->rest = SHA3_FINALIZED; /* mark context as finalized */ + } + + assert(block_size > digest_length); + if (result) me64_to_le_str(result, ctx->hash, digest_length); +} +#endif /* USE_KECCAK */ diff --git a/sha3.h b/sha3.h new file mode 100644 index 000000000..b809f3359 --- /dev/null +++ b/sha3.h @@ -0,0 +1,73 @@ +/* sha3.h - an implementation of Secure Hash Algorithm 3 (Keccak). + * based on the + * The Keccak SHA-3 submission. Submission to NIST (Round 3), 2011 + * by Guido Bertoni, Joan Daemen, Michaël Peeters and Gilles Van Assche + * + * Copyright: 2013 Aleksey Kravchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. Use this program at your own risk! + */ + +#ifndef __SHA3_H__ +#define __SHA3_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define sha3_224_hash_size 28 +#define sha3_256_hash_size 32 +#define sha3_384_hash_size 48 +#define sha3_512_hash_size 64 +#define sha3_max_permutation_size 25 +#define sha3_max_rate_in_qwords 24 + +/** + * SHA3 Algorithm context. + */ +typedef struct SHA3_CTX +{ + /* 1600 bits algorithm hashing state */ + uint64_t hash[sha3_max_permutation_size]; + /* 1536-bit buffer for leftovers */ + uint64_t message[sha3_max_rate_in_qwords]; + /* count of bytes in the message[] buffer */ + unsigned rest; + /* size of a message block processed at once */ + unsigned block_size; +} SHA3_CTX; + +/* methods for calculating the hash function */ + +void sha3_224_Init(SHA3_CTX *ctx); +void sha3_256_Init(SHA3_CTX *ctx); +void sha3_384_Init(SHA3_CTX *ctx); +void sha3_512_Init(SHA3_CTX *ctx); +void sha3_Update(SHA3_CTX *ctx, const unsigned char* msg, size_t size); +void sha3_Final(SHA3_CTX *ctx, unsigned char* result); + +#ifdef USE_KECCAK +#define keccak_224_Init sha3_224_Init +#define keccak_256_Init sha3_256_Init +#define keccak_384_Init sha3_384_Init +#define keccak_512_Init sha3_512_Init +#define keccak_Update sha3_Update +void keccak_Final(SHA3_CTX *ctx, unsigned char* result); +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* __SHA3_H__ */ From ed6debf8c4ec5ef9c7ef31a1a7eddf76aa33ccd8 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 26 Apr 2016 11:50:04 +0200 Subject: [PATCH 254/627] reorder parameters of hash_final methods --- ed25519-donna/ed25519-hash-custom.h | 2 +- hmac.c | 8 ++++---- ripemd160.c | 4 ++-- ripemd160.h | 2 +- sha2.c | 12 ++++++------ sha2.h | 4 ++-- 6 files changed, 16 insertions(+), 16 deletions(-) diff --git a/ed25519-donna/ed25519-hash-custom.h b/ed25519-donna/ed25519-hash-custom.h index 119f43eaa..67e00e295 100644 --- a/ed25519-donna/ed25519-hash-custom.h +++ b/ed25519-donna/ed25519-hash-custom.h @@ -14,5 +14,5 @@ #define ed25519_hash_context SHA512_CTX #define ed25519_hash_init(ctx) sha512_Init(ctx) #define ed25519_hash_update(ctx, in, inlen) sha512_Update((ctx), (in), (inlen)) -#define ed25519_hash_final(ctx, hash) sha512_Final((hash), (ctx)) +#define ed25519_hash_final(ctx, hash) sha512_Final((ctx), (hash)) #define ed25519_hash(hash, in, inlen) sha512_Raw((in), (inlen), (hash)) diff --git a/hmac.c b/hmac.c index f7b00774c..e8f704d6b 100644 --- a/hmac.c +++ b/hmac.c @@ -48,12 +48,12 @@ void hmac_sha256(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, sha256_Init(&ctx); sha256_Update(&ctx, i_key_pad, SHA256_BLOCK_LENGTH); sha256_Update(&ctx, msg, msglen); - sha256_Final(buf, &ctx); + sha256_Final(&ctx, buf); sha256_Init(&ctx); sha256_Update(&ctx, o_key_pad, SHA256_BLOCK_LENGTH); sha256_Update(&ctx, buf, SHA256_DIGEST_LENGTH); - sha256_Final(hmac, &ctx); + sha256_Final(&ctx, hmac); MEMSET_BZERO(buf, sizeof(buf)); MEMSET_BZERO(o_key_pad, sizeof(o_key_pad)); MEMSET_BZERO(i_key_pad, sizeof(i_key_pad)); @@ -80,12 +80,12 @@ void hmac_sha512(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, sha512_Init(&ctx); sha512_Update(&ctx, i_key_pad, SHA512_BLOCK_LENGTH); sha512_Update(&ctx, msg, msglen); - sha512_Final(buf, &ctx); + sha512_Final(&ctx, buf); sha512_Init(&ctx); sha512_Update(&ctx, o_key_pad, SHA512_BLOCK_LENGTH); sha512_Update(&ctx, buf, SHA512_DIGEST_LENGTH); - sha512_Final(hmac, &ctx); + sha512_Final(&ctx, hmac); MEMSET_BZERO(buf, sizeof(buf)); MEMSET_BZERO(o_key_pad, sizeof(o_key_pad)); diff --git a/ripemd160.c b/ripemd160.c index 4fdf2e930..ef9e76485 100644 --- a/ripemd160.c +++ b/ripemd160.c @@ -301,7 +301,7 @@ static const uint8_t ripemd160_padding[64] = /* * RIPEMD-160 final digest */ -void ripemd160_Final( uint8_t output[20], RIPEMD160_CTX *ctx ) +void ripemd160_Final( RIPEMD160_CTX *ctx, uint8_t output[20] ) { uint32_t last, padn; uint32_t high, low; @@ -335,5 +335,5 @@ void ripemd160(const uint8_t *msg, uint32_t msg_len, uint8_t hash[20]) RIPEMD160_CTX ctx; ripemd160_Init( &ctx ); ripemd160_Update( &ctx, msg, msg_len ); - ripemd160_Final( hash, &ctx ); + ripemd160_Final( &ctx, hash ); } diff --git a/ripemd160.h b/ripemd160.h index 159baeb61..8b1454bed 100644 --- a/ripemd160.h +++ b/ripemd160.h @@ -11,7 +11,7 @@ typedef struct _RIPEMD160_CTX { void ripemd160_Init(RIPEMD160_CTX *ctx); void ripemd160_Update(RIPEMD160_CTX *ctx, const uint8_t *input, uint32_t ilen); -void ripemd160_Final(uint8_t output[20], RIPEMD160_CTX *ctx); +void ripemd160_Final(RIPEMD160_CTX *ctx, uint8_t output[20]); void ripemd160(const uint8_t *msg, uint32_t msg_len, uint8_t hash[20]); #endif diff --git a/sha2.c b/sha2.c index 74c67daf8..80e3910ef 100644 --- a/sha2.c +++ b/sha2.c @@ -505,7 +505,7 @@ void sha256_Update(SHA256_CTX* context, const sha2_byte *data, size_t len) { usedspace = freespace = 0; } -void sha256_Final(sha2_byte digest[], SHA256_CTX* context) { +void sha256_Final(SHA256_CTX* context, sha2_byte digest[]) { sha2_word32 *d = (sha2_word32*)digest; unsigned int usedspace; @@ -571,7 +571,7 @@ char *sha256_End(SHA256_CTX* context, char buffer[]) { int i; if (buffer != (char*)0) { - sha256_Final(digest, context); + sha256_Final(context, digest); for (i = 0; i < SHA256_DIGEST_LENGTH; i++) { *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; @@ -590,7 +590,7 @@ void sha256_Raw(const sha2_byte* data, size_t len, uint8_t digest[SHA256_DIGEST_ SHA256_CTX context; sha256_Init(&context); sha256_Update(&context, data, len); - sha256_Final(digest, &context); + sha256_Final(&context, digest); } char* sha256_Data(const sha2_byte* data, size_t len, char digest[SHA256_DIGEST_STRING_LENGTH]) { @@ -870,7 +870,7 @@ void sha512_Last(SHA512_CTX* context) { sha512_Transform(context, (sha2_word64*)context->buffer); } -void sha512_Final(sha2_byte digest[], SHA512_CTX* context) { +void sha512_Final(SHA512_CTX* context, sha2_byte digest[]) { sha2_word64 *d = (sha2_word64*)digest; /* If no digest buffer is passed, we don't bother doing this: */ @@ -901,7 +901,7 @@ char *sha512_End(SHA512_CTX* context, char buffer[]) { int i; if (buffer != (char*)0) { - sha512_Final(digest, context); + sha512_Final(context, digest); for (i = 0; i < SHA512_DIGEST_LENGTH; i++) { *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; @@ -920,7 +920,7 @@ void sha512_Raw(const sha2_byte* data, size_t len, uint8_t digest[SHA512_DIGEST_ SHA512_CTX context; sha512_Init(&context); sha512_Update(&context, data, len); - sha512_Final(digest, &context); + sha512_Final(&context, digest); } char* sha512_Data(const sha2_byte* data, size_t len, char digest[SHA512_DIGEST_STRING_LENGTH]) { diff --git a/sha2.h b/sha2.h index e8fae89ba..cc39e23f8 100644 --- a/sha2.h +++ b/sha2.h @@ -54,14 +54,14 @@ typedef struct _SHA512_CTX { void sha256_Init(SHA256_CTX *); void sha256_Update(SHA256_CTX*, const uint8_t*, size_t); -void sha256_Final(uint8_t[SHA256_DIGEST_LENGTH], SHA256_CTX*); +void sha256_Final(SHA256_CTX*, uint8_t[SHA256_DIGEST_LENGTH]); char* sha256_End(SHA256_CTX*, char[SHA256_DIGEST_STRING_LENGTH]); void sha256_Raw(const uint8_t*, size_t, uint8_t[SHA256_DIGEST_LENGTH]); char* sha256_Data(const uint8_t*, size_t, char[SHA256_DIGEST_STRING_LENGTH]); void sha512_Init(SHA512_CTX*); void sha512_Update(SHA512_CTX*, const uint8_t*, size_t); -void sha512_Final(uint8_t[SHA512_DIGEST_LENGTH], SHA512_CTX*); +void sha512_Final(SHA512_CTX*, uint8_t[SHA512_DIGEST_LENGTH]); char* sha512_End(SHA512_CTX*, char[SHA512_DIGEST_STRING_LENGTH]); void sha512_Raw(const uint8_t*, size_t, uint8_t[SHA512_DIGEST_LENGTH]); char* sha512_Data(const uint8_t*, size_t, char[SHA512_DIGEST_STRING_LENGTH]); From 445e85945035a48c2aea4c4257d1232c12fe493f Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 26 Apr 2016 17:10:24 +0200 Subject: [PATCH 255/627] split hmac into init/update/final --- hmac.c | 112 +++++++++++++++++++++++++++++++++------------------------ hmac.h | 20 ++++++++++- 2 files changed, 85 insertions(+), 47 deletions(-) diff --git a/hmac.c b/hmac.c index e8f704d6b..a3f476303 100644 --- a/hmac.c +++ b/hmac.c @@ -24,70 +24,90 @@ #include #include "hmac.h" -#include "sha2.h" #include "macros.h" -void hmac_sha256(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, const uint32_t msglen, uint8_t *hmac) +void hmac_sha256_Init(HMAC_SHA256_CTX *hctx, const uint8_t *key, const uint32_t keylen) { - int i; - uint8_t buf[SHA256_BLOCK_LENGTH], o_key_pad[SHA256_BLOCK_LENGTH], i_key_pad[SHA256_BLOCK_LENGTH]; - SHA256_CTX ctx; - - memset(buf, 0, SHA256_BLOCK_LENGTH); + uint8_t i_key_pad[SHA256_BLOCK_LENGTH]; + memset(i_key_pad, 0, SHA256_BLOCK_LENGTH); if (keylen > SHA256_BLOCK_LENGTH) { - sha256_Raw(key, keylen, buf); + sha256_Raw(key, keylen, i_key_pad); } else { - memcpy(buf, key, keylen); + memcpy(i_key_pad, key, keylen); } - - for (i = 0; i < SHA256_BLOCK_LENGTH; i++) { - o_key_pad[i] = buf[i] ^ 0x5c; - i_key_pad[i] = buf[i] ^ 0x36; + for (int i = 0; i < SHA256_BLOCK_LENGTH; i++) { + hctx->o_key_pad[i] = i_key_pad[i] ^ 0x5c; + i_key_pad[i] ^= 0x36; } + sha256_Init(&(hctx->ctx)); + sha256_Update(&(hctx->ctx), i_key_pad, SHA256_BLOCK_LENGTH); + MEMSET_BZERO(i_key_pad, sizeof(i_key_pad)); +} - sha256_Init(&ctx); - sha256_Update(&ctx, i_key_pad, SHA256_BLOCK_LENGTH); - sha256_Update(&ctx, msg, msglen); - sha256_Final(&ctx, buf); +void hmac_sha256_Update(HMAC_SHA256_CTX *hctx, const uint8_t *msg, const uint32_t msglen) +{ + sha256_Update(&(hctx->ctx), msg, msglen); +} - sha256_Init(&ctx); - sha256_Update(&ctx, o_key_pad, SHA256_BLOCK_LENGTH); - sha256_Update(&ctx, buf, SHA256_DIGEST_LENGTH); - sha256_Final(&ctx, hmac); - MEMSET_BZERO(buf, sizeof(buf)); - MEMSET_BZERO(o_key_pad, sizeof(o_key_pad)); - MEMSET_BZERO(i_key_pad, sizeof(i_key_pad)); +void hmac_sha256_Final(HMAC_SHA256_CTX *hctx, uint8_t *hmac) +{ + uint8_t hash[SHA256_DIGEST_LENGTH]; + sha256_Final(&(hctx->ctx), hash); + sha256_Init(&(hctx->ctx)); + sha256_Update(&(hctx->ctx), hctx->o_key_pad, SHA256_BLOCK_LENGTH); + sha256_Update(&(hctx->ctx), hash, SHA256_DIGEST_LENGTH); + sha256_Final(&(hctx->ctx), hmac); + MEMSET_BZERO(hash, sizeof(hash)); + MEMSET_BZERO(hctx, sizeof(hctx)); } -void hmac_sha512(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, const uint32_t msglen, uint8_t *hmac) +void hmac_sha256(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, const uint32_t msglen, uint8_t *hmac) { - int i; - uint8_t buf[SHA512_BLOCK_LENGTH], o_key_pad[SHA512_BLOCK_LENGTH], i_key_pad[SHA512_BLOCK_LENGTH]; - SHA512_CTX ctx; + HMAC_SHA256_CTX hctx; + hmac_sha256_Init(&hctx, key, keylen); + hmac_sha256_Update(&hctx, msg, msglen); + hmac_sha256_Final(&hctx, hmac); +} - memset(buf, 0, SHA512_BLOCK_LENGTH); +void hmac_sha512_Init(HMAC_SHA512_CTX *hctx, const uint8_t *key, const uint32_t keylen) +{ + uint8_t i_key_pad[SHA512_BLOCK_LENGTH]; + memset(i_key_pad, 0, SHA512_BLOCK_LENGTH); if (keylen > SHA512_BLOCK_LENGTH) { - sha512_Raw(key, keylen, buf); + sha512_Raw(key, keylen, i_key_pad); } else { - memcpy(buf, key, keylen); + memcpy(i_key_pad, key, keylen); } - - for (i = 0; i < SHA512_BLOCK_LENGTH; i++) { - o_key_pad[i] = buf[i] ^ 0x5c; - i_key_pad[i] = buf[i] ^ 0x36; + for (int i = 0; i < SHA512_BLOCK_LENGTH; i++) { + hctx->o_key_pad[i] = i_key_pad[i] ^ 0x5c; + i_key_pad[i] ^= 0x36; } + sha512_Init(&(hctx->ctx)); + sha512_Update(&(hctx->ctx), i_key_pad, SHA512_BLOCK_LENGTH); + MEMSET_BZERO(i_key_pad, sizeof(i_key_pad)); +} - sha512_Init(&ctx); - sha512_Update(&ctx, i_key_pad, SHA512_BLOCK_LENGTH); - sha512_Update(&ctx, msg, msglen); - sha512_Final(&ctx, buf); +void hmac_sha512_Update(HMAC_SHA512_CTX *hctx, const uint8_t *msg, const uint32_t msglen) +{ + sha512_Update(&(hctx->ctx), msg, msglen); +} - sha512_Init(&ctx); - sha512_Update(&ctx, o_key_pad, SHA512_BLOCK_LENGTH); - sha512_Update(&ctx, buf, SHA512_DIGEST_LENGTH); - sha512_Final(&ctx, hmac); +void hmac_sha512_Final(HMAC_SHA512_CTX *hctx, uint8_t *hmac) +{ + uint8_t hash[SHA512_DIGEST_LENGTH]; + sha512_Final(&(hctx->ctx), hash); + sha512_Init(&(hctx->ctx)); + sha512_Update(&(hctx->ctx), hctx->o_key_pad, SHA512_BLOCK_LENGTH); + sha512_Update(&(hctx->ctx), hash, SHA512_DIGEST_LENGTH); + sha512_Final(&(hctx->ctx), hmac); + MEMSET_BZERO(hash, sizeof(hash)); + MEMSET_BZERO(hctx, sizeof(hctx)); +} - MEMSET_BZERO(buf, sizeof(buf)); - MEMSET_BZERO(o_key_pad, sizeof(o_key_pad)); - MEMSET_BZERO(i_key_pad, sizeof(i_key_pad)); +void hmac_sha512(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, const uint32_t msglen, uint8_t *hmac) +{ + HMAC_SHA512_CTX hctx; + hmac_sha512_Init(&hctx, key, keylen); + hmac_sha512_Update(&hctx, msg, msglen); + hmac_sha512_Final(&hctx, hmac); } diff --git a/hmac.h b/hmac.h index 6981b63a7..1374dec4b 100644 --- a/hmac.h +++ b/hmac.h @@ -14,7 +14,7 @@ * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT HMAC_SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR @@ -25,8 +25,26 @@ #define __HMAC_H__ #include +#include "sha2.h" +typedef struct _HMAC_SHA256_CTX { + uint8_t o_key_pad[SHA256_BLOCK_LENGTH]; + SHA256_CTX ctx; +} HMAC_SHA256_CTX; + +typedef struct _HMAC_SHA512_CTX { + uint8_t o_key_pad[SHA512_BLOCK_LENGTH]; + SHA512_CTX ctx; +} HMAC_SHA512_CTX; + +void hmac_sha256_Init(HMAC_SHA256_CTX *hctx, const uint8_t *key, const uint32_t keylen); +void hmac_sha256_Update(HMAC_SHA256_CTX *hctx, const uint8_t *msg, const uint32_t msglen); +void hmac_sha256_Final(HMAC_SHA256_CTX *hctx, uint8_t *hmac); void hmac_sha256(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, const uint32_t msglen, uint8_t *hmac); + +void hmac_sha512_Init(HMAC_SHA512_CTX *hctx, const uint8_t *key, const uint32_t keylen); +void hmac_sha512_Update(HMAC_SHA512_CTX *hctx, const uint8_t *msg, const uint32_t msglen); +void hmac_sha512_Final(HMAC_SHA512_CTX *hctx, uint8_t *hmac); void hmac_sha512(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, const uint32_t msglen, uint8_t *hmac); #endif From 08219ea77ad5651c7bd2641ca13956a90ba96ae6 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 26 Apr 2016 17:43:13 +0200 Subject: [PATCH 256/627] pbkdf2 now uses new hmac api --- pbkdf2.c | 36 ++++++++++++++++++------------------ pbkdf2.h | 2 -- 2 files changed, 18 insertions(+), 20 deletions(-) diff --git a/pbkdf2.c b/pbkdf2.c index d4beef77b..760ef0d98 100644 --- a/pbkdf2.c +++ b/pbkdf2.c @@ -29,25 +29,25 @@ void pbkdf2_hmac_sha256(const uint8_t *pass, int passlen, uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key, int keylen, void (*progress_callback)(uint32_t current, uint32_t total)) { const uint32_t HMACLEN = 256/8; - uint32_t i, j, k; uint8_t f[HMACLEN], g[HMACLEN]; uint32_t blocks = keylen / HMACLEN; if (keylen & (HMACLEN - 1)) { blocks++; } - for (i = 1; i <= blocks; i++) { - salt[saltlen ] = (i >> 24) & 0xFF; - salt[saltlen + 1] = (i >> 16) & 0xFF; - salt[saltlen + 2] = (i >> 8) & 0xFF; - salt[saltlen + 3] = i & 0xFF; - hmac_sha256(pass, passlen, salt, saltlen + 4, g); + for (uint32_t i = 1; i <= blocks; i++) { + HMAC_SHA256_CTX hctx; + hmac_sha256_Init(&hctx, pass, passlen); + hmac_sha256_Update(&hctx, salt, saltlen); + uint32_t ii = ((i & 0xFF000000) >> 24) | ((i & 0x00FF0000) >> 8) | ((i & 0x0000FF00) << 8) | ((i & 0x000000FF) << 24); + hmac_sha256_Update(&hctx, (const uint8_t *)&ii, sizeof(uint32_t)); + hmac_sha256_Final(&hctx, g); memcpy(f, g, HMACLEN); if (progress_callback) { progress_callback(0, iterations); } - for (j = 1; j < iterations; j++) { + for (uint32_t j = 1; j < iterations; j++) { hmac_sha256(pass, passlen, g, HMACLEN, g); - for (k = 0; k < HMACLEN; k++) { + for (uint32_t k = 0; k < HMACLEN; k++) { f[k] ^= g[k]; } if (progress_callback && (j % 256 == 255)) { @@ -67,25 +67,25 @@ void pbkdf2_hmac_sha256(const uint8_t *pass, int passlen, uint8_t *salt, int sal void pbkdf2_hmac_sha512(const uint8_t *pass, int passlen, uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key, int keylen, void (*progress_callback)(uint32_t current, uint32_t total)) { const uint32_t HMACLEN = 512/8; - uint32_t i, j, k; uint8_t f[HMACLEN], g[HMACLEN]; uint32_t blocks = keylen / HMACLEN; if (keylen & (HMACLEN - 1)) { blocks++; } - for (i = 1; i <= blocks; i++) { - salt[saltlen ] = (i >> 24) & 0xFF; - salt[saltlen + 1] = (i >> 16) & 0xFF; - salt[saltlen + 2] = (i >> 8) & 0xFF; - salt[saltlen + 3] = i & 0xFF; - hmac_sha512(pass, passlen, salt, saltlen + 4, g); + for (uint32_t i = 1; i <= blocks; i++) { + HMAC_SHA512_CTX hctx; + hmac_sha512_Init(&hctx, pass, passlen); + hmac_sha512_Update(&hctx, salt, saltlen); + uint32_t ii = ((i & 0xFF000000) >> 24) | ((i & 0x00FF0000) >> 8) | ((i & 0x0000FF00) << 8) | ((i & 0x000000FF) << 24); + hmac_sha512_Update(&hctx, (const uint8_t *)&ii, sizeof(uint32_t)); + hmac_sha512_Final(&hctx, g); memcpy(f, g, HMACLEN); if (progress_callback) { progress_callback(0, iterations); } - for (j = 1; j < iterations; j++) { + for (uint32_t j = 1; j < iterations; j++) { hmac_sha512(pass, passlen, g, HMACLEN, g); - for (k = 0; k < HMACLEN; k++) { + for (uint32_t k = 0; k < HMACLEN; k++) { f[k] ^= g[k]; } if (progress_callback && (j % 256 == 255)) { diff --git a/pbkdf2.h b/pbkdf2.h index 6fe09788b..e8052dbca 100644 --- a/pbkdf2.h +++ b/pbkdf2.h @@ -26,9 +26,7 @@ #include -// salt needs to have 4 extra bytes available beyond saltlen void pbkdf2_hmac_sha256(const uint8_t *pass, int passlen, uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key, int keylen, void (*progress_callback)(uint32_t current, uint32_t total)); -// salt needs to have 4 extra bytes available beyond saltlen void pbkdf2_hmac_sha512(const uint8_t *pass, int passlen, uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key, int keylen, void (*progress_callback)(uint32_t current, uint32_t total)); #endif From 489f09a8434721edebeb3b20713e325fc4b55b78 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 26 Apr 2016 19:51:49 +0200 Subject: [PATCH 257/627] fix sizeof usage --- hmac.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hmac.c b/hmac.c index a3f476303..f334ada7e 100644 --- a/hmac.c +++ b/hmac.c @@ -58,7 +58,7 @@ void hmac_sha256_Final(HMAC_SHA256_CTX *hctx, uint8_t *hmac) sha256_Update(&(hctx->ctx), hash, SHA256_DIGEST_LENGTH); sha256_Final(&(hctx->ctx), hmac); MEMSET_BZERO(hash, sizeof(hash)); - MEMSET_BZERO(hctx, sizeof(hctx)); + MEMSET_BZERO(hctx, sizeof(HMAC_SHA256_CTX)); } void hmac_sha256(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, const uint32_t msglen, uint8_t *hmac) @@ -101,7 +101,7 @@ void hmac_sha512_Final(HMAC_SHA512_CTX *hctx, uint8_t *hmac) sha512_Update(&(hctx->ctx), hash, SHA512_DIGEST_LENGTH); sha512_Final(&(hctx->ctx), hmac); MEMSET_BZERO(hash, sizeof(hash)); - MEMSET_BZERO(hctx, sizeof(hctx)); + MEMSET_BZERO(hctx, sizeof(HMAC_SHA512_CTX)); } void hmac_sha512(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, const uint32_t msglen, uint8_t *hmac) From c6e7d376b71471af4667ddb285a7109cc25c41c4 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Wed, 27 Apr 2016 23:10:35 +0200 Subject: [PATCH 258/627] Handle b58 address with shorter lengths --- base58.c | 14 ++++++-------- bip32.c | 2 +- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/base58.c b/base58.c index d8252aefc..5355fcb1e 100644 --- a/base58.c +++ b/base58.c @@ -42,7 +42,7 @@ static const int8_t b58digits_map[] = { bool b58tobin(void *bin, size_t *binszp, const char *b58) { size_t binsz = *binszp; - const unsigned char *b58u = (void*)b58; + const unsigned char *b58u = (const unsigned char*)b58; unsigned char *binu = bin; size_t outisz = (binsz + 3) / 4; uint32_t outi[outisz]; @@ -59,7 +59,7 @@ bool b58tobin(void *bin, size_t *binszp, const char *b58) memset(outi, 0, outisz * sizeof(*outi)); // Leading zeros, just count - for (i = 0; i < b58sz && !b58digits_map[b58u[i]]; ++i) + for (i = 0; i < b58sz && b58u[i] == '1'; ++i) ++zerocount; for ( ; i < b58sz; ++i) @@ -210,12 +210,10 @@ int base58_decode_check(const char *str, uint8_t *data, int datalen) if (b58tobin(d, &res, str) != true) { return 0; } - if (res != (size_t)datalen + 4) { + uint8_t *nd = d + datalen + 4 - res; + if (b58check(nd, res, str) < 0) { return 0; } - if (b58check(d, res, str) < 0) { - return 0; - } - memcpy(data, d, datalen); - return datalen; + memcpy(data, nd, res - 4); + return res - 4; } diff --git a/bip32.c b/bip32.c index 064a5e0c1..8ecfc6f73 100644 --- a/bip32.c +++ b/bip32.c @@ -400,7 +400,7 @@ int hdnode_deserialize(const char *str, HDNode *node) { uint8_t node_data[78]; memset(node, 0, sizeof(HDNode)); - if (!base58_decode_check(str, node_data, sizeof(node_data))) { + if (base58_decode_check(str, node_data, sizeof(node_data)) != sizeof(node_data)) { return -1; } node->curve = get_curve_by_name(SECP256K1_NAME); From d9ec4344fcd7f924f6aee56f2cf7084df7e02cb4 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 27 Apr 2016 23:32:14 +0200 Subject: [PATCH 259/627] use std=c99 --- CMakeLists.txt | 4 +++- Makefile | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1baf39876..165d7aeb0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,6 +7,8 @@ include_directories(ed25519-donna) set_source_files_properties(aeskey.c PROPERTIES COMPILE_FLAGS -Wno-sequence-point) +set(CMAKE_C_FLAGS "-std=c99") + if(MSVC) set_source_files_properties(${SOURCES} PROPERTIES LANGUAGE CXX) endif(MSVC) @@ -22,4 +24,4 @@ if (TREZOR_CRYPTO_TESTS) add_executable(test-openssl test-openssl.c) target_link_libraries(test-openssl TrezorCrypto check rt pthread m crypto) add_test(NAME trezor-crypto-openssl COMMAND test-openssl 100) -endif() \ No newline at end of file +endif() diff --git a/Makefile b/Makefile index 981f17b77..bdb9b09b2 100644 --- a/Makefile +++ b/Makefile @@ -3,6 +3,7 @@ CC = gcc OPTFLAGS = -O3 -g CFLAGS += $(OPTFLAGS) \ + -std=c99 \ -W \ -Wall \ -Wextra \ From 406022acb4d43a48bb9d8afe392226f1fdeccec2 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 28 Apr 2016 14:34:36 +0200 Subject: [PATCH 260/627] remove tools/Makefile --- Makefile | 14 +++++++++++++- tools/Makefile | 43 ------------------------------------------- 2 files changed, 13 insertions(+), 44 deletions(-) delete mode 100644 tools/Makefile diff --git a/Makefile b/Makefile index bdb9b09b2..8bc75dabd 100644 --- a/Makefile +++ b/Makefile @@ -48,7 +48,7 @@ OBJS = $(SRCS:.c=.o) TESTLIBS = -lcheck -lrt -lpthread -lm TESTSSLLIBS = -lcrypto -all: tests test-openssl libtrezor-crypto.so test_speed +all: tests test-openssl libtrezor-crypto.so test_speed tools %.o: %.c %.h options.h $(CC) $(CFLAGS) -o $@ -c $< @@ -65,5 +65,17 @@ test-openssl: test-openssl.o $(OBJS) libtrezor-crypto.so: $(SRCS) $(CC) $(CFLAGS) -fPIC -shared $(SRCS) -o libtrezor-crypto.so +tools: tools/xpubaddrgen tools/mktable tools/bip39bruteforce + +tools/xpubaddrgen: tools/xpubaddrgen.o $(OBJS) + $(CC) tools/xpubaddrgen.o $(OBJS) -o tools/xpubaddrgen + +tools/mktable: tools/mktable.o $(OBJS) + $(CC) tools/mktable.o $(OBJS) -o tools/mktable + +tools/bip39bruteforce: tools/bip39bruteforce.o $(OBJS) + $(CC) tools/bip39bruteforce.o $(OBJS) -o tools/bip39bruteforce + clean: rm -f *.o ed25519-donna/*.o tests test_speed test-openssl libtrezor-crypto.so + rm -f tools/*.o tools/xpubaddrgen tools/mktable tools/bip39bruteforce diff --git a/tools/Makefile b/tools/Makefile deleted file mode 100644 index 481a46bcb..000000000 --- a/tools/Makefile +++ /dev/null @@ -1,43 +0,0 @@ -CC = gcc - -OPTFLAGS = -O3 - -CFLAGS += $(OPTFLAGS) \ - -W \ - -Wall \ - -Wextra \ - -Wimplicit-function-declaration \ - -Wredundant-decls \ - -Wstrict-prototypes \ - -Wundef \ - -Wshadow \ - -Wpointer-arith \ - -Wformat \ - -Wreturn-type \ - -Wsign-compare \ - -Wmultichar \ - -Wformat-nonliteral \ - -Winit-self \ - -Wuninitialized \ - -Wformat-security \ - -Werror \ - -I.. - -all: xpubaddrgen mktable bip39bruteforce - -OBJS = ../bip32.o ../bip39.o ../ecdsa.o ../sha2.o ../bignum.o ../base58.o ../secp256k1.o ../nist256p1.o ../ripemd160.o ../hmac.o ../rand.o ../pbkdf2.o ../curves.o ../ed25519-donna/ed25519.o - -%.o: %.c %.h options.h - $(CC) $(CFLAGS) -o $@ -c $< - -xpubaddrgen: xpubaddrgen.o $(OBJS) - $(CC) xpubaddrgen.o $(OBJS) -o xpubaddrgen - -mktable: mktable.o $(OBJS) - $(CC) mktable.o $(OBJS) -o mktable - -bip39bruteforce: bip39bruteforce.o $(OBJS) - $(CC) bip39bruteforce.o $(OBJS) -o bip39bruteforce - -clean: - rm -f *.o xpubaddrgen mktable bip39bruteforce From b8ec5567ba701c77379f2111774456eb18b98790 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 29 Apr 2016 17:50:20 +0200 Subject: [PATCH 261/627] undef align for ed25519-donna --- ed25519-donna/ed25519-donna-portable.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ed25519-donna/ed25519-donna-portable.h b/ed25519-donna/ed25519-donna-portable.h index 0a0f7fc3a..cc18822bb 100644 --- a/ed25519-donna/ed25519-donna-portable.h +++ b/ed25519-donna/ed25519-donna-portable.h @@ -13,6 +13,7 @@ #define inline __forceinline #define DONNA_INLINE __forceinline #define DONNA_NOINLINE __declspec(noinline) + #undef ALIGN #define ALIGN(x) __declspec(align(x)) #define ROTL32(a,b) _rotl(a,b) #define ROTR32(a,b) _rotr(a,b) @@ -20,6 +21,7 @@ #include #define DONNA_INLINE inline __attribute__((always_inline)) #define DONNA_NOINLINE __attribute__((noinline)) + #undef ALIGN #define ALIGN(x) __attribute__((aligned(x))) #define ROTL32(a,b) (((a) << (b)) | ((a) >> (32 - b))) #define ROTR32(a,b) (((a) >> (b)) | ((a) << (32 - b))) From 242a5de275d36e2df6792c921a9cd7d8c8e8933b Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 1 May 2016 00:50:12 +0200 Subject: [PATCH 262/627] simplify pbkdf2 (support only klen == hashlen) and split it --- bip39.c | 18 ++++++-- pbkdf2.c | 132 +++++++++++++++++++++++++++---------------------------- pbkdf2.h | 28 +++++++++++- tests.c | 18 ++++---- 4 files changed, 115 insertions(+), 81 deletions(-) diff --git a/bip39.c b/bip39.c index aa9ad9e1d..10d5afa45 100644 --- a/bip39.c +++ b/bip39.c @@ -168,8 +168,7 @@ void mnemonic_to_seed(const char *mnemonic, const char *passphrase, uint8_t seed int mnemoniclen = strlen(mnemonic); // check cache if (mnemoniclen < 256 && passphraselen < 64) { - int i; - for (i = 0; i < BIP39_CACHE_SIZE; i++) { + for (int i = 0; i < BIP39_CACHE_SIZE; i++) { if (!bip39_cache[i].set) continue; if (strcmp(bip39_cache[i].mnemonic, mnemonic) != 0) continue; if (strcmp(bip39_cache[i].passphrase, passphrase) != 0) continue; @@ -179,10 +178,21 @@ void mnemonic_to_seed(const char *mnemonic, const char *passphrase, uint8_t seed } } #endif - uint8_t salt[8 + 256 + 4]; + uint8_t salt[8 + 256]; memcpy(salt, "mnemonic", 8); memcpy(salt + 8, passphrase, passphraselen); - pbkdf2_hmac_sha512((const uint8_t *)mnemonic, strlen(mnemonic), salt, passphraselen + 8, BIP39_PBKDF2_ROUNDS, seed, 512 / 8, progress_callback); + PBKDF2_HMAC_SHA512_CTX pctx; + pbkdf2_hmac_sha512_Init(&pctx, (const uint8_t *)mnemonic, strlen(mnemonic), salt, passphraselen + 8); + if (progress_callback) { + progress_callback(0, BIP39_PBKDF2_ROUNDS); + } + for (int i = 0; i < 8; i++) { + pbkdf2_hmac_sha512_Update(&pctx, BIP39_PBKDF2_ROUNDS / 8); + if (progress_callback) { + progress_callback((i + 1) * BIP39_PBKDF2_ROUNDS / 8, BIP39_PBKDF2_ROUNDS); + } + } + pbkdf2_hmac_sha512_Final(&pctx, seed); #if USE_BIP39_CACHE // store to cache if (mnemoniclen < 256 && passphraselen < 64) { diff --git a/pbkdf2.c b/pbkdf2.c index 760ef0d98..86903204d 100644 --- a/pbkdf2.c +++ b/pbkdf2.c @@ -26,78 +26,78 @@ #include "hmac.h" #include "macros.h" -void pbkdf2_hmac_sha256(const uint8_t *pass, int passlen, uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key, int keylen, void (*progress_callback)(uint32_t current, uint32_t total)) +void pbkdf2_hmac_sha256_Init(PBKDF2_HMAC_SHA256_CTX *pctx, const uint8_t *pass, int passlen, uint8_t *salt, int saltlen) { - const uint32_t HMACLEN = 256/8; - uint8_t f[HMACLEN], g[HMACLEN]; - uint32_t blocks = keylen / HMACLEN; - if (keylen & (HMACLEN - 1)) { - blocks++; - } - for (uint32_t i = 1; i <= blocks; i++) { - HMAC_SHA256_CTX hctx; - hmac_sha256_Init(&hctx, pass, passlen); - hmac_sha256_Update(&hctx, salt, saltlen); - uint32_t ii = ((i & 0xFF000000) >> 24) | ((i & 0x00FF0000) >> 8) | ((i & 0x0000FF00) << 8) | ((i & 0x000000FF) << 24); - hmac_sha256_Update(&hctx, (const uint8_t *)&ii, sizeof(uint32_t)); - hmac_sha256_Final(&hctx, g); - memcpy(f, g, HMACLEN); - if (progress_callback) { - progress_callback(0, iterations); - } - for (uint32_t j = 1; j < iterations; j++) { - hmac_sha256(pass, passlen, g, HMACLEN, g); - for (uint32_t k = 0; k < HMACLEN; k++) { - f[k] ^= g[k]; - } - if (progress_callback && (j % 256 == 255)) { - progress_callback(j + 1, iterations); - } - } - if (i == blocks && (keylen & (HMACLEN - 1))) { - memcpy(key + HMACLEN * (i - 1), f, keylen & (HMACLEN - 1)); - } else { - memcpy(key + HMACLEN * (i - 1), f, HMACLEN); + HMAC_SHA256_CTX hctx; + hmac_sha256_Init(&hctx, pass, passlen); + hmac_sha256_Update(&hctx, salt, saltlen); + hmac_sha256_Update(&hctx, (const uint8_t *)"\x00\x00\x00\x01", 4); + hmac_sha256_Final(&hctx, pctx->g); + memcpy(pctx->f, pctx->g, SHA256_DIGEST_LENGTH); + pctx->pass = pass; + pctx->passlen = passlen; + pctx->first = 1; +} + +void pbkdf2_hmac_sha256_Update(PBKDF2_HMAC_SHA256_CTX *pctx, uint32_t iterations) +{ + for (uint32_t i = pctx->first; i < iterations; i++) { + hmac_sha256(pctx->pass, pctx->passlen, pctx->g, SHA256_DIGEST_LENGTH, pctx->g); + for (uint32_t j = 0; j < SHA256_DIGEST_LENGTH; j++) { + pctx->f[j] ^= pctx->g[j]; } } - MEMSET_BZERO(f, sizeof(f)); - MEMSET_BZERO(g, sizeof(g)); + pctx->first = 0; } -void pbkdf2_hmac_sha512(const uint8_t *pass, int passlen, uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key, int keylen, void (*progress_callback)(uint32_t current, uint32_t total)) +void pbkdf2_hmac_sha256_Final(PBKDF2_HMAC_SHA256_CTX *pctx, uint8_t *key) { - const uint32_t HMACLEN = 512/8; - uint8_t f[HMACLEN], g[HMACLEN]; - uint32_t blocks = keylen / HMACLEN; - if (keylen & (HMACLEN - 1)) { - blocks++; - } - for (uint32_t i = 1; i <= blocks; i++) { - HMAC_SHA512_CTX hctx; - hmac_sha512_Init(&hctx, pass, passlen); - hmac_sha512_Update(&hctx, salt, saltlen); - uint32_t ii = ((i & 0xFF000000) >> 24) | ((i & 0x00FF0000) >> 8) | ((i & 0x0000FF00) << 8) | ((i & 0x000000FF) << 24); - hmac_sha512_Update(&hctx, (const uint8_t *)&ii, sizeof(uint32_t)); - hmac_sha512_Final(&hctx, g); - memcpy(f, g, HMACLEN); - if (progress_callback) { - progress_callback(0, iterations); - } - for (uint32_t j = 1; j < iterations; j++) { - hmac_sha512(pass, passlen, g, HMACLEN, g); - for (uint32_t k = 0; k < HMACLEN; k++) { - f[k] ^= g[k]; - } - if (progress_callback && (j % 256 == 255)) { - progress_callback(j + 1, iterations); - } - } - if (i == blocks && (keylen & (HMACLEN - 1))) { - memcpy(key + HMACLEN * (i - 1), f, keylen & (HMACLEN - 1)); - } else { - memcpy(key + HMACLEN * (i - 1), f, HMACLEN); + memcpy(key, pctx->f, SHA256_DIGEST_LENGTH); + MEMSET_BZERO(pctx, sizeof(PBKDF2_HMAC_SHA256_CTX)); +} + +void pbkdf2_hmac_sha256(const uint8_t *pass, int passlen, uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key) +{ + PBKDF2_HMAC_SHA256_CTX pctx; + pbkdf2_hmac_sha256_Init(&pctx, pass, passlen, salt, saltlen); + pbkdf2_hmac_sha256_Update(&pctx, iterations); + pbkdf2_hmac_sha256_Final(&pctx, key); +} + +void pbkdf2_hmac_sha512_Init(PBKDF2_HMAC_SHA512_CTX *pctx, const uint8_t *pass, int passlen, uint8_t *salt, int saltlen) +{ + HMAC_SHA512_CTX hctx; + hmac_sha512_Init(&hctx, pass, passlen); + hmac_sha512_Update(&hctx, salt, saltlen); + hmac_sha512_Update(&hctx, (const uint8_t *)"\x00\x00\x00\x01", 4); + hmac_sha512_Final(&hctx, pctx->g); + memcpy(pctx->f, pctx->g, SHA512_DIGEST_LENGTH); + pctx->pass = pass; + pctx->passlen = passlen; + pctx->first = 1; +} + +void pbkdf2_hmac_sha512_Update(PBKDF2_HMAC_SHA512_CTX *pctx, uint32_t iterations) +{ + for (uint32_t i = pctx->first; i < iterations; i++) { + hmac_sha512(pctx->pass, pctx->passlen, pctx->g, SHA512_DIGEST_LENGTH, pctx->g); + for (uint32_t j = 0; j < SHA512_DIGEST_LENGTH; j++) { + pctx->f[j] ^= pctx->g[j]; } } - MEMSET_BZERO(f, sizeof(f)); - MEMSET_BZERO(g, sizeof(g)); + pctx->first = 0; +} + +void pbkdf2_hmac_sha512_Final(PBKDF2_HMAC_SHA512_CTX *pctx, uint8_t *key) +{ + memcpy(key, pctx->f, SHA512_DIGEST_LENGTH); + MEMSET_BZERO(pctx, sizeof(PBKDF2_HMAC_SHA512_CTX)); +} + +void pbkdf2_hmac_sha512(const uint8_t *pass, int passlen, uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key) +{ + PBKDF2_HMAC_SHA512_CTX pctx; + pbkdf2_hmac_sha512_Init(&pctx, pass, passlen, salt, saltlen); + pbkdf2_hmac_sha512_Update(&pctx, iterations); + pbkdf2_hmac_sha512_Final(&pctx, key); } diff --git a/pbkdf2.h b/pbkdf2.h index e8052dbca..c3b56b2a0 100644 --- a/pbkdf2.h +++ b/pbkdf2.h @@ -25,8 +25,32 @@ #define __PBKDF2_H__ #include +#include "sha2.h" -void pbkdf2_hmac_sha256(const uint8_t *pass, int passlen, uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key, int keylen, void (*progress_callback)(uint32_t current, uint32_t total)); -void pbkdf2_hmac_sha512(const uint8_t *pass, int passlen, uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key, int keylen, void (*progress_callback)(uint32_t current, uint32_t total)); +typedef struct _PBKDF2_HMAC_SHA256_CTX { + uint8_t f[SHA256_DIGEST_LENGTH]; + uint8_t g[SHA256_DIGEST_LENGTH]; + const uint8_t *pass; + int passlen; + char first; +} PBKDF2_HMAC_SHA256_CTX; + +typedef struct _PBKDF2_HMAC_SHA512_CTX { + uint8_t f[SHA512_DIGEST_LENGTH]; + uint8_t g[SHA512_DIGEST_LENGTH]; + const uint8_t *pass; + int passlen; + char first; +} PBKDF2_HMAC_SHA512_CTX; + +void pbkdf2_hmac_sha256_Init(PBKDF2_HMAC_SHA256_CTX *pctx, const uint8_t *pass, int passlen, uint8_t *salt, int saltlen); +void pbkdf2_hmac_sha256_Update(PBKDF2_HMAC_SHA256_CTX *pctx, uint32_t iterations); +void pbkdf2_hmac_sha256_Final(PBKDF2_HMAC_SHA256_CTX *pctx, uint8_t *key); +void pbkdf2_hmac_sha256(const uint8_t *pass, int passlen, uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key); + +void pbkdf2_hmac_sha512_Init(PBKDF2_HMAC_SHA512_CTX *pctx, const uint8_t *pass, int passlen, uint8_t *salt, int saltlen); +void pbkdf2_hmac_sha512_Update(PBKDF2_HMAC_SHA512_CTX *pctx, uint32_t iterations); +void pbkdf2_hmac_sha512_Final(PBKDF2_HMAC_SHA512_CTX *pctx, uint8_t *key); +void pbkdf2_hmac_sha512(const uint8_t *pass, int passlen, uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key); #endif diff --git a/tests.c b/tests.c index 16d64e9c0..a4012dc8a 100644 --- a/tests.c +++ b/tests.c @@ -1169,20 +1169,20 @@ START_TEST(test_pbkdf2_hmac_sha256) uint8_t k[40], s[40]; strcpy((char *)s, "salt"); - pbkdf2_hmac_sha256((uint8_t *)"password", 8, s, 4, 1, k, 32, 0); + pbkdf2_hmac_sha256((uint8_t *)"password", 8, s, 4, 1, k); ck_assert_mem_eq(k, fromhex("120fb6cffcf8b32c43e7225256c4f837a86548c92ccc35480805987cb70be17b"), 32); strcpy((char *)s, "salt"); - pbkdf2_hmac_sha256((uint8_t *)"password", 8, s, 4, 2, k, 32, 0); + pbkdf2_hmac_sha256((uint8_t *)"password", 8, s, 4, 2, k); ck_assert_mem_eq(k, fromhex("ae4d0c95af6b46d32d0adff928f06dd02a303f8ef3c251dfd6e2d85a95474c43"), 32); strcpy((char *)s, "salt"); - pbkdf2_hmac_sha256((uint8_t *)"password", 8, s, 4, 4096, k, 32, 0); + pbkdf2_hmac_sha256((uint8_t *)"password", 8, s, 4, 4096, k); ck_assert_mem_eq(k, fromhex("c5e478d59288c841aa530db6845c4c8d962893a001ce4e11a4963873aa98134a"), 32); strcpy((char *)s, "saltSALTsaltSALTsaltSALTsaltSALTsalt"); - pbkdf2_hmac_sha256((uint8_t *)"passwordPASSWORDpassword", 3*8, s, 9*4, 4096, k, 40, 0); - ck_assert_mem_eq(k, fromhex("348c89dbcbd32b2f32d814b8116e84cf2b17347ebc1800181c4e2a1fb8dd53e1c635518c7dac47e9"), 40); + pbkdf2_hmac_sha256((uint8_t *)"passwordPASSWORDpassword", 3*8, s, 9*4, 4096, k); + ck_assert_mem_eq(k, fromhex("348c89dbcbd32b2f32d814b8116e84cf2b17347ebc1800181c4e2a1fb8dd53e1"), 32); } END_TEST @@ -1192,19 +1192,19 @@ START_TEST(test_pbkdf2_hmac_sha512) uint8_t k[64], s[40]; strcpy((char *)s, "salt"); - pbkdf2_hmac_sha512((uint8_t *)"password", 8, s, 4, 1, k, 64, 0); + pbkdf2_hmac_sha512((uint8_t *)"password", 8, s, 4, 1, k); ck_assert_mem_eq(k, fromhex("867f70cf1ade02cff3752599a3a53dc4af34c7a669815ae5d513554e1c8cf252c02d470a285a0501bad999bfe943c08f050235d7d68b1da55e63f73b60a57fce"), 64); strcpy((char *)s, "salt"); - pbkdf2_hmac_sha512((uint8_t *)"password", 8, s, 4, 2, k, 64, 0); + pbkdf2_hmac_sha512((uint8_t *)"password", 8, s, 4, 2, k); ck_assert_mem_eq(k, fromhex("e1d9c16aa681708a45f5c7c4e215ceb66e011a2e9f0040713f18aefdb866d53cf76cab2868a39b9f7840edce4fef5a82be67335c77a6068e04112754f27ccf4e"), 64); strcpy((char *)s, "salt"); - pbkdf2_hmac_sha512((uint8_t *)"password", 8, s, 4, 4096, k, 64, 0); + pbkdf2_hmac_sha512((uint8_t *)"password", 8, s, 4, 4096, k); ck_assert_mem_eq(k, fromhex("d197b1b33db0143e018b12f3d1d1479e6cdebdcc97c5c0f87f6902e072f457b5143f30602641b3d55cd335988cb36b84376060ecd532e039b742a239434af2d5"), 64); strcpy((char *)s, "saltSALTsaltSALTsaltSALTsaltSALTsalt"); - pbkdf2_hmac_sha512((uint8_t *)"passwordPASSWORDpassword", 3*8, s, 9*4, 4096, k, 64, 0); + pbkdf2_hmac_sha512((uint8_t *)"passwordPASSWORDpassword", 3*8, s, 9*4, 4096, k); ck_assert_mem_eq(k, fromhex("8c0511f4c6e597c6ac6315d8f0362e225f3c501495ba23b868c005174dc4ee71115b59f9e60cd9532fa33e0f75aefe30225c583a186cd82bd4daea9724a3d3b8"), 64); } END_TEST From 454bebc1629be33adcac142d3e096ae61aef6855 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 11 May 2016 21:15:48 +0200 Subject: [PATCH 263/627] update readme --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 593197f90..26cada68f 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,6 @@ -trezor-crypto -============= +# trezor-crypto -[![Build Status](https://travis-ci.org/trezor/trezor-crypto.svg?branch=master)](https://travis-ci.org/trezor/trezor-crypto) +[![Build Status](https://travis-ci.org/trezor/trezor-crypto.svg?branch=master)](https://travis-ci.org/trezor/trezor-crypto) [![gitter](https://badges.gitter.im/trezor/community.svg)](https://gitter.im/trezor/community) Heavily optimized cryptography algorithms for embedded devices. From 9e5d03a1fc20574875d537c453759040aaec0720 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 12 May 2016 16:16:01 +0200 Subject: [PATCH 264/627] fix alignment in sha functions --- Makefile | 2 +- sha2.c | 30 +++++++++++++++--------------- sha3.c | 2 +- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/Makefile b/Makefile index 8bc75dabd..109019a1c 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ CC = gcc OPTFLAGS = -O3 -g CFLAGS += $(OPTFLAGS) \ - -std=c99 \ + -std=gnu99 \ -W \ -Wall \ -Wextra \ diff --git a/sha2.c b/sha2.c index 80e3910ef..5c3c64fee 100644 --- a/sha2.c +++ b/sha2.c @@ -385,7 +385,7 @@ void sha256_Transform(SHA256_CTX* context, const sha2_word32* data) { sha2_word32 T1, T2, *W256; int j; - W256 = (sha2_word32*)context->buffer; + W256 = (sha2_word32*)(void*)context->buffer; /* Initialize registers with the prev. intermediate value */ a = context->state[0]; @@ -479,7 +479,7 @@ void sha256_Update(SHA256_CTX* context, const sha2_byte *data, size_t len) { context->bitcount += freespace << 3; len -= freespace; data += freespace; - sha256_Transform(context, (sha2_word32*)context->buffer); + sha256_Transform(context, (sha2_word32*)(void*)context->buffer); } else { /* The buffer is not yet full */ MEMCPY_BCOPY(&context->buffer[usedspace], data, len); @@ -491,7 +491,7 @@ void sha256_Update(SHA256_CTX* context, const sha2_byte *data, size_t len) { } while (len >= SHA256_BLOCK_LENGTH) { /* Process as many complete blocks as we can */ - sha256_Transform(context, (sha2_word32*)data); + sha256_Transform(context, (sha2_word32*)(void*)data); context->bitcount += SHA256_BLOCK_LENGTH << 3; len -= SHA256_BLOCK_LENGTH; data += SHA256_BLOCK_LENGTH; @@ -506,7 +506,7 @@ void sha256_Update(SHA256_CTX* context, const sha2_byte *data, size_t len) { } void sha256_Final(SHA256_CTX* context, sha2_byte digest[]) { - sha2_word32 *d = (sha2_word32*)digest; + sha2_word32 *d = (sha2_word32*)(void*)digest; unsigned int usedspace; /* If no digest buffer is passed, we don't bother doing this: */ @@ -528,7 +528,7 @@ void sha256_Final(SHA256_CTX* context, sha2_byte digest[]) { MEMSET_BZERO(&context->buffer[usedspace], SHA256_BLOCK_LENGTH - usedspace); } /* Do second-to-last transform: */ - sha256_Transform(context, (sha2_word32*)context->buffer); + sha256_Transform(context, (sha2_word32*)(void*)context->buffer); /* And set-up for the last transform: */ MEMSET_BZERO(context->buffer, SHA256_SHORT_BLOCK_LENGTH); @@ -541,11 +541,11 @@ void sha256_Final(SHA256_CTX* context, sha2_byte digest[]) { *context->buffer = 0x80; } /* Set the bit count: */ - sha2_word64 *t = (sha2_word64 *)&context->buffer[SHA256_SHORT_BLOCK_LENGTH]; + sha2_word64 *t = (sha2_word64 *)(void*)&context->buffer[SHA256_SHORT_BLOCK_LENGTH]; *t = context->bitcount; /* Final transform: */ - sha256_Transform(context, (sha2_word32*)context->buffer); + sha256_Transform(context, (sha2_word32*)(void*)context->buffer); #if BYTE_ORDER == LITTLE_ENDIAN { @@ -705,7 +705,7 @@ void sha512_Transform(SHA512_CTX* context, const sha2_word64* data) { void sha512_Transform(SHA512_CTX* context, const sha2_word64* data) { sha2_word64 a, b, c, d, e, f, g, h, s0, s1; - sha2_word64 T1, T2, *W512 = (sha2_word64*)context->buffer; + sha2_word64 T1, T2, *W512 = (sha2_word64*)(void*)context->buffer; int j; /* Initialize registers with the prev. intermediate value */ @@ -800,7 +800,7 @@ void sha512_Update(SHA512_CTX* context, const sha2_byte *data, size_t len) { ADDINC128(context->bitcount, freespace << 3); len -= freespace; data += freespace; - sha512_Transform(context, (sha2_word64*)context->buffer); + sha512_Transform(context, (sha2_word64*)(void*)context->buffer); } else { /* The buffer is not yet full */ MEMCPY_BCOPY(&context->buffer[usedspace], data, len); @@ -812,7 +812,7 @@ void sha512_Update(SHA512_CTX* context, const sha2_byte *data, size_t len) { } while (len >= SHA512_BLOCK_LENGTH) { /* Process as many complete blocks as we can */ - sha512_Transform(context, (sha2_word64*)data); + sha512_Transform(context, (sha2_word64*)(void*)data); ADDINC128(context->bitcount, SHA512_BLOCK_LENGTH << 3); len -= SHA512_BLOCK_LENGTH; data += SHA512_BLOCK_LENGTH; @@ -847,7 +847,7 @@ void sha512_Last(SHA512_CTX* context) { MEMSET_BZERO(&context->buffer[usedspace], SHA512_BLOCK_LENGTH - usedspace); } /* Do second-to-last transform: */ - sha512_Transform(context, (sha2_word64*)context->buffer); + sha512_Transform(context, (sha2_word64*)(void*)context->buffer); /* And set-up for the last transform: */ MEMSET_BZERO(context->buffer, SHA512_BLOCK_LENGTH - 2); @@ -861,17 +861,17 @@ void sha512_Last(SHA512_CTX* context) { } /* Store the length of input data (in bits): */ sha2_word64 *t; - t = (sha2_word64 *)&context->buffer[SHA512_SHORT_BLOCK_LENGTH]; + t = (sha2_word64 *)(void*)&context->buffer[SHA512_SHORT_BLOCK_LENGTH]; *t = context->bitcount[1]; - t = (sha2_word64 *)&context->buffer[SHA512_SHORT_BLOCK_LENGTH+8]; + t = (sha2_word64 *)(void*)&context->buffer[SHA512_SHORT_BLOCK_LENGTH+8]; *t = context->bitcount[0]; /* Final transform: */ - sha512_Transform(context, (sha2_word64*)context->buffer); + sha512_Transform(context, (sha2_word64*)(void*)context->buffer); } void sha512_Final(SHA512_CTX* context, sha2_byte digest[]) { - sha2_word64 *d = (sha2_word64*)digest; + sha2_word64 *d = (sha2_word64*)(void*)digest; /* If no digest buffer is passed, we don't bother doing this: */ if (digest != (sha2_byte*)0) { diff --git a/sha3.c b/sha3.c index 5f3233dd0..de6b58066 100644 --- a/sha3.c +++ b/sha3.c @@ -289,7 +289,7 @@ void sha3_Update(SHA3_CTX *ctx, const unsigned char *msg, size_t size) if (IS_ALIGNED_64(msg)) { /* the most common case is processing of an already aligned message without copying it */ - aligned_message_block = (uint64_t*)msg; + aligned_message_block = (uint64_t*)(void*)msg; } else { memcpy(ctx->message, msg, block_size); aligned_message_block = ctx->message; From 778d1b2476446bdc6d01664bad18a827feeb6c88 Mon Sep 17 00:00:00 2001 From: Jan Pochyla Date: Tue, 16 Jun 2015 23:50:43 +0200 Subject: [PATCH 265/627] emcripten skeleton for address derivation See [https://kripken.github.io/emscripten-site/index.html] for a guide. --- emscripten/Makefile | 17 ++++++++++++ emscripten/post.js | 1 + emscripten/pre.js | 0 emscripten/test.js | 67 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 85 insertions(+) create mode 100644 emscripten/Makefile create mode 100644 emscripten/post.js create mode 100644 emscripten/pre.js create mode 100644 emscripten/test.js diff --git a/emscripten/Makefile b/emscripten/Makefile new file mode 100644 index 000000000..81bf4fa72 --- /dev/null +++ b/emscripten/Makefile @@ -0,0 +1,17 @@ +EMFLAGS = \ + -O2 --closure 1 \ + --memory-init-file 0 \ + --pre-js pre.js --post-js post.js \ + -s EXPORTED_FUNCTIONS='["_hdnode_public_ckd", "_ecdsa_get_address"]' \ + +SRC = ../bignum.c ../ecdsa.c ../secp256k1.c ../hmac.c ../bip32.c \ + ../base58.c ../ripemd160.c ../sha2.c ../rand.c + +test: trezor-crypto.js + node test.js + +trezor-crypto.js: $(SRC) + emcc $(EMFLAGS) -o $@ $^ + +clean: + rm -f trezor-crypto.js diff --git a/emscripten/post.js b/emscripten/post.js new file mode 100644 index 000000000..d5b37bd2f --- /dev/null +++ b/emscripten/post.js @@ -0,0 +1 @@ +module.exports = Module; diff --git a/emscripten/pre.js b/emscripten/pre.js new file mode 100644 index 000000000..e69de29bb diff --git a/emscripten/test.js b/emscripten/test.js new file mode 100644 index 000000000..0bc809c9a --- /dev/null +++ b/emscripten/test.js @@ -0,0 +1,67 @@ +var crypto = require('./trezor-crypto'); + +/* typedef struct { + uint32_t depth; + uint32_t fingerprint; + uint32_t child_num; + uint8_t chain_code[32]; + uint8_t private_key[32]; + uint8_t public_key[33]; + } HDNode; +*/ + +var HDNODE_SIZE = 4 + 4 + 4 + 32 + 32 + 33; +var hdnode = crypto._malloc(HDNODE_SIZE); + +var ADDRESS_SIZE = 40; // maximum size +var address = crypto._malloc(ADDRESS_SIZE); + +function prepareNode(n) { + var b = new ArrayBuffer(HDNODE_SIZE); + var u8 = new Uint8Array(b, 0, HDNODE_SIZE); + var u32 = new Uint32Array(b, 0, 12); + + u32[0] = n.depth; + u32[1] = n.parentFingerprint; + u32[2] = n.index; + u8.set(n.chainCode, 12); + u8.set(n.pubKey.toBuffer(), 12 + 32 + 32); + + return u8; +} + +function deriveAddress(pn, i, version) { + crypto.HEAPU8.set(pn, hdnode); + crypto._hdnode_public_ckd(hdnode, i); + crypto._ecdsa_get_address(hdnode + 12 + 32 + 32, version, address, ADDRESS_SIZE); + return crypto.Pointer_stringify(address); +} + +// benching code + +var bitcoin = require('bitcoinjs-lib'); + +var node = bitcoin.HDNode.fromBase58( + 'xpub6AHA9hZDN11k2ijHMeS5QqHx2KP9aMBRhTDqANMnwVtdyw2TDYRm' + + 'F8PjpvwUFcL1Et8Hj59S3gTSMcUQ5gAqTz3Wd8EsMTmF3DChhqPQBnU' +).derive(0); + +timeBitcoinjs(node); +timeTrezorCrypto(node); + +function timeBitcoinjs(n) { + console.time('bitcoinjs') + for (var i = 0; i < 1000; i++) { + n.derive(i).getAddress() + } + console.timeEnd('bitcoinjs') +} + +function timeTrezorCrypto(n) { + var nP = prepareNode(n); + console.time('trezor-crypto') + for (var i = 0; i < 1000; i++) { + deriveAddress(nP, i, 0); + } + console.timeEnd('trezor-crypto') +} From 3f4e50ba22e07144ed0706bc9d94493e1268bd0d Mon Sep 17 00:00:00 2001 From: Jan Pochyla Date: Wed, 17 Jun 2015 00:04:43 +0200 Subject: [PATCH 266/627] add package.json for emscripten test --- emscripten/package.json | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 emscripten/package.json diff --git a/emscripten/package.json b/emscripten/package.json new file mode 100644 index 000000000..9b822bbfd --- /dev/null +++ b/emscripten/package.json @@ -0,0 +1,8 @@ +{ + "name": "trezor-crypto-test", + "version": "1.0.0", + "description": "", + "dependencies": { + "bitcoinjs-lib": "^1.5.7" + } +} From da0a2f8662947ac2c1c0e24b78bf9c4fa7b654fb Mon Sep 17 00:00:00 2001 From: Jan Pochyla Date: Wed, 17 Jun 2015 00:06:53 +0200 Subject: [PATCH 267/627] add npm install to emscripten Makefile --- emscripten/Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/emscripten/Makefile b/emscripten/Makefile index 81bf4fa72..52ac0a29c 100644 --- a/emscripten/Makefile +++ b/emscripten/Makefile @@ -7,11 +7,14 @@ EMFLAGS = \ SRC = ../bignum.c ../ecdsa.c ../secp256k1.c ../hmac.c ../bip32.c \ ../base58.c ../ripemd160.c ../sha2.c ../rand.c -test: trezor-crypto.js +test: node_modules trezor-crypto.js node test.js trezor-crypto.js: $(SRC) emcc $(EMFLAGS) -o $@ $^ +node_modules: + npm install + clean: rm -f trezor-crypto.js From 3c0176a304b59d92e9faeaac0bdc05eef2a4ae86 Mon Sep 17 00:00:00 2001 From: Jan Pochyla Date: Thu, 18 Jun 2015 15:45:25 +0200 Subject: [PATCH 268/627] move interface fns to post.js, add web worker & browserify test --- emscripten/Makefile | 12 ++-- emscripten/post.js | 114 ++++++++++++++++++++++++++++++++++++- emscripten/pre.js | 9 +++ emscripten/test.html | 8 +++ emscripten/test.js | 133 ++++++++++++++++++++++++++----------------- 5 files changed, 220 insertions(+), 56 deletions(-) create mode 100644 emscripten/test.html diff --git a/emscripten/Makefile b/emscripten/Makefile index 52ac0a29c..66e1bf492 100644 --- a/emscripten/Makefile +++ b/emscripten/Makefile @@ -1,15 +1,19 @@ EMFLAGS = \ - -O2 --closure 1 \ + -Os --closure 1 \ --memory-init-file 0 \ --pre-js pre.js --post-js post.js \ - -s EXPORTED_FUNCTIONS='["_hdnode_public_ckd", "_ecdsa_get_address"]' \ + -s EXPORTED_FUNCTIONS='["_hdnode_public_ckd", "_ecdsa_get_address"]' SRC = ../bignum.c ../ecdsa.c ../secp256k1.c ../hmac.c ../bip32.c \ ../base58.c ../ripemd160.c ../sha2.c ../rand.c -test: node_modules trezor-crypto.js +test-node: node_modules trezor-crypto.js test.js node test.js +test-browserify.js: node_modules trezor-crypto.js test.js + browserify test.js -o $@ --noparse=`pwd`/trezor-crypto.js + @echo "open test.html in your favourite browser" + trezor-crypto.js: $(SRC) emcc $(EMFLAGS) -o $@ $^ @@ -17,4 +21,4 @@ node_modules: npm install clean: - rm -f trezor-crypto.js + rm -f trezor-crypto.js test-browserify.js diff --git a/emscripten/post.js b/emscripten/post.js index d5b37bd2f..638121abc 100644 --- a/emscripten/post.js +++ b/emscripten/post.js @@ -1 +1,113 @@ -module.exports = Module; +/* + typedef struct { + uint32_t depth; + uint32_t fingerprint; + uint32_t child_num; + uint8_t chain_code[32]; + uint8_t private_key[32]; + uint8_t public_key[33]; + } HDNode; + */ + +var HEAPU8 = Module['HEAPU8']; +var _malloc = Module['_malloc']; +var _hdnode_public_ckd = Module['_hdnode_public_ckd']; +var _ecdsa_get_address = Module['_ecdsa_get_address']; +var Pointer_stringify = Module['Pointer_stringify']; + +// HDNode struct global +var HDNODE_SIZE = 4 + 4 + 4 + 32 + 32 + 33; +var _hdnode = _malloc(HDNODE_SIZE); + +// address string global +var ADDRESS_SIZE = 40; // maximum size +var _address = _malloc(ADDRESS_SIZE); + +/* + * public library interface + */ + +/** + * @param {HDNode} node HDNode struct, see the definition above + * @return {Uint8Array} + */ +function serializeNode(node) { + var b = new ArrayBuffer(HDNODE_SIZE); + + var u32 = new Uint32Array(b, 0, 12); + u32[0] = node['depth']; + u32[1] = node['fingerprint']; + u32[2] = node['child_num']; + + var u8 = new Uint8Array(b, 0, HDNODE_SIZE); + u8.set(node['chain_code'], 12); + u8.set(node['public_key'], 12 + 32 + 32); + + return u8; +} + +/** + * @param {Uint8Array} sn serialized node, see `serializeNode` + * @param {Number} index BIP32 index of the address + * @param {Number} version address version byte + * @return {String} + */ +function deriveAddress(sn, index, version) { + HEAPU8.set(sn, _hdnode); + _hdnode_public_ckd(_hdnode, index); + _ecdsa_get_address(_hdnode + 12 + 32 + 32, version, _address, ADDRESS_SIZE); + return Pointer_stringify(_address); +} + +/** + * @param {HDNode} node HDNode struct, see the definition above + * @param {Number} from index of the first address + * @param {Number} to index of the last address + * @param {Number} version address version byte + * @return {Array} + */ +function deriveAddressRange(node, from, to, version) { + var addresses = []; + var sn = serializeNode(node); + var i; + for (i = from; i <= to; i++) { + addresses.push(deriveAddress(sn, i, version)); + } + return addresses; +} + +if (typeof module !== 'undefined') { + module['exports'] = { + 'serializeNode': serializeNode, + 'deriveAddress': deriveAddress, + 'deriveAddressRange': deriveAddressRange + }; +} + +/* + * Web worker processing + */ + +function processMessage(event) { + var data = event['data']; + var type = data['type']; + + switch (type) { + case 'deriveAddressRange': + var response = deriveAddressRange( + data['node'], + data['from'], + data['to'], + data['version'] + ); + postMessage(response); + break; + + default: + throw new Error('Unknown message type: ' + type); + } +} + +if (ENVIRONMENT_IS_WORKER) { + this['onmessage'] = processMessage; +} diff --git a/emscripten/pre.js b/emscripten/pre.js index e69de29bb..f1b364afc 100644 --- a/emscripten/pre.js +++ b/emscripten/pre.js @@ -0,0 +1,9 @@ +// stub importScripts for the faulty detection of web worker env +if (typeof importScripts === 'undefined' + && typeof WorkerGlobalScope !== 'undefined' + && this instanceof WorkerGlobalScope + ) { + this.importScripts = function () { + throw new Error('importScripts is a stub'); + }; + } diff --git a/emscripten/test.html b/emscripten/test.html new file mode 100644 index 000000000..9c764a230 --- /dev/null +++ b/emscripten/test.html @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/emscripten/test.js b/emscripten/test.js index 0bc809c9a..31d58f2c3 100644 --- a/emscripten/test.js +++ b/emscripten/test.js @@ -1,67 +1,98 @@ var crypto = require('./trezor-crypto'); +var bitcoin = require('bitcoinjs-lib'); -/* typedef struct { - uint32_t depth; - uint32_t fingerprint; - uint32_t child_num; - uint8_t chain_code[32]; - uint8_t private_key[32]; - uint8_t public_key[33]; - } HDNode; -*/ +var XPUB = + 'xpub6AHA9hZDN11k2ijHMeS5QqHx2KP9aMBRhTDqANMnwVtdyw2TDYRm' + + 'F8PjpvwUFcL1Et8Hj59S3gTSMcUQ5gAqTz3Wd8EsMTmF3DChhqPQBnU'; +var node = bitcoin.HDNode.fromBase58(XPUB).derive(0); -var HDNODE_SIZE = 4 + 4 + 4 + 32 + 32 + 33; -var hdnode = crypto._malloc(HDNODE_SIZE); +var nodeStruct = { + depth: node.depth, + child_num: node.index, + fingerprint: node.parentFingerprint, + chain_code: node.chainCode, + public_key: node.pubKey.toBuffer() +}; +var nodeSerialized = crypto.serializeNode(nodeStruct); -var ADDRESS_SIZE = 40; // maximum size -var address = crypto._malloc(ADDRESS_SIZE); +var suite; +var worker; -function prepareNode(n) { - var b = new ArrayBuffer(HDNODE_SIZE); - var u8 = new Uint8Array(b, 0, HDNODE_SIZE); - var u32 = new Uint32Array(b, 0, 12); +if (typeof Worker !== 'undefined') { + console.log('enabling web worker benchmark'); + worker = new Worker('./trezor-crypto.js'); + worker.onerror = function (error) { + console.error('worker:', error); + }; + suite = [ + // benchBitcoinJS, + // benchBrowserify, + benchWorker + ]; +} else { + suite = [ + benchBitcoinJS, + benchBrowserify + ]; +} - u32[0] = n.depth; - u32[1] = n.parentFingerprint; - u32[2] = n.index; - u8.set(n.chainCode, 12); - u8.set(n.pubKey.toBuffer(), 12 + 32 + 32); +benchmark(suite, 1000, 1000); - return u8; +function benchmark(suite, delay, ops) { + (function cycle(i) { + setTimeout(function () { + var benchmark = suite[i]; + runBenchmark(benchmark, ops, function (runtime) { + printResult(benchmark, ops, runtime); + cycle(i+1 < suite.length ? i+1 : 0); + }); + }, delay); + }(0)); } -function deriveAddress(pn, i, version) { - crypto.HEAPU8.set(pn, hdnode); - crypto._hdnode_public_ckd(hdnode, i); - crypto._ecdsa_get_address(hdnode + 12 + 32 + 32, version, address, ADDRESS_SIZE); - return crypto.Pointer_stringify(address); +function benchBitcoinJS(ops, fn) { + var i; + for (i = 0; i < ops; i++) { + node.derive(i).getAddress(); + } + fn(); } -// benching code - -var bitcoin = require('bitcoinjs-lib'); - -var node = bitcoin.HDNode.fromBase58( - 'xpub6AHA9hZDN11k2ijHMeS5QqHx2KP9aMBRhTDqANMnwVtdyw2TDYRm' + - 'F8PjpvwUFcL1Et8Hj59S3gTSMcUQ5gAqTz3Wd8EsMTmF3DChhqPQBnU' -).derive(0); +function benchBrowserify(ops, fn) { + var i; + for (i = 0; i < ops; i++) { + crypto.deriveAddress(nodeSerialized, i, 0); + } + fn(); +} -timeBitcoinjs(node); -timeTrezorCrypto(node); +function benchWorker(ops, fn) { + worker.onmessage = function (event) { + fn(); + }; + worker.postMessage({ + type: 'deriveAddressRange', + node: nodeStruct, + from: 0, + to: ops - 1, + version: 0 + }); +} -function timeBitcoinjs(n) { - console.time('bitcoinjs') - for (var i = 0; i < 1000; i++) { - n.derive(i).getAddress() - } - console.timeEnd('bitcoinjs') +function runBenchmark(benchmark, ops, fn) { + var start = new Date(); + benchmark(ops, function () { + var end = new Date(); + fn(end - start); + }); } -function timeTrezorCrypto(n) { - var nP = prepareNode(n); - console.time('trezor-crypto') - for (var i = 0; i < 1000; i++) { - deriveAddress(nP, i, 0); - } - console.timeEnd('trezor-crypto') +function printResult(benchmark, ops, runtime) { + var opssec = (ops / runtime) * 1000; + console.log( + benchmark.name, + 'ops #', ops, + 'runtime', runtime / 1000, + 'sec, ops/sec', opssec + ); } From 07200a30e6304366135f46d3ac6341736b488133 Mon Sep 17 00:00:00 2001 From: Jan Pochyla Date: Fri, 6 Nov 2015 14:52:25 +0100 Subject: [PATCH 269/627] upgrade bitcoinjs-lib, rename params --- emscripten/package.json | 2 +- emscripten/post.js | 32 ++++++++++++++++++-------------- emscripten/test.js | 2 +- 3 files changed, 20 insertions(+), 16 deletions(-) diff --git a/emscripten/package.json b/emscripten/package.json index 9b822bbfd..16ad3c5ce 100644 --- a/emscripten/package.json +++ b/emscripten/package.json @@ -3,6 +3,6 @@ "version": "1.0.0", "description": "", "dependencies": { - "bitcoinjs-lib": "^1.5.7" + "bitcoinjs-lib": "^2.1.1" } } diff --git a/emscripten/post.js b/emscripten/post.js index 638121abc..c42c941c1 100644 --- a/emscripten/post.js +++ b/emscripten/post.js @@ -28,7 +28,7 @@ var _address = _malloc(ADDRESS_SIZE); */ /** - * @param {HDNode} node HDNode struct, see the definition above + * @param {HDNode} node HDNode struct, see the definition above * @return {Uint8Array} */ function serializeNode(node) { @@ -47,9 +47,9 @@ function serializeNode(node) { } /** - * @param {Uint8Array} sn serialized node, see `serializeNode` - * @param {Number} index BIP32 index of the address - * @param {Number} version address version byte + * @param {Uint8Array} sn serialized node, see `serializeNode` + * @param {Number} index BIP32 index of the address + * @param {Number} version address version byte * @return {String} */ function deriveAddress(sn, index, version) { @@ -60,17 +60,17 @@ function deriveAddress(sn, index, version) { } /** - * @param {HDNode} node HDNode struct, see the definition above - * @param {Number} from index of the first address - * @param {Number} to index of the last address - * @param {Number} version address version byte + * @param {HDNode} node HDNode struct, see the definition above + * @param {Number} firstIndex index of the first address + * @param {Number} lastIndex index of the last address + * @param {Number} version address version byte * @return {Array} */ -function deriveAddressRange(node, from, to, version) { +function deriveAddressRange(node, firstIndex, lastIndex, version) { var addresses = []; var sn = serializeNode(node); var i; - for (i = from; i <= to; i++) { + for (i = firstIndex; i <= lastIndex; i++) { addresses.push(deriveAddress(sn, i, version)); } return addresses; @@ -94,13 +94,17 @@ function processMessage(event) { switch (type) { case 'deriveAddressRange': - var response = deriveAddressRange( + var addresses = deriveAddressRange( data['node'], - data['from'], - data['to'], + data['firstIndex'], + data['lastIndex'], data['version'] ); - postMessage(response); + postMessage({ + 'addresses': addresses, + 'firstIndex': data['firstIndex'], + 'lastIndex': data['lastIndex'] + }); break; default: diff --git a/emscripten/test.js b/emscripten/test.js index 31d58f2c3..b0a6d1bea 100644 --- a/emscripten/test.js +++ b/emscripten/test.js @@ -11,7 +11,7 @@ var nodeStruct = { child_num: node.index, fingerprint: node.parentFingerprint, chain_code: node.chainCode, - public_key: node.pubKey.toBuffer() + public_key: node.keyPair.getPublicKeyBuffer().toString('hex') }; var nodeSerialized = crypto.serializeNode(nodeStruct); From 3c335be04945f1f8a3f10560c14ce70f5f7062d0 Mon Sep 17 00:00:00 2001 From: Jan Pochyla Date: Wed, 11 Nov 2015 13:35:08 +0100 Subject: [PATCH 270/627] fix typo --- emscripten/test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/emscripten/test.js b/emscripten/test.js index b0a6d1bea..acaeb600c 100644 --- a/emscripten/test.js +++ b/emscripten/test.js @@ -11,7 +11,7 @@ var nodeStruct = { child_num: node.index, fingerprint: node.parentFingerprint, chain_code: node.chainCode, - public_key: node.keyPair.getPublicKeyBuffer().toString('hex') + public_key: node.keyPair.getPublicKeyBuffer() }; var nodeSerialized = crypto.serializeNode(nodeStruct); From 6dd9ed07564af50ec105b132862f00ee155e2bd9 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 12 May 2016 17:19:42 +0200 Subject: [PATCH 271/627] add hdnode_public_ckd_address_optimized --- bip32.c | 39 ++++++++++++++++++++++++++++++ bip32.h | 2 ++ test_speed.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 107 insertions(+), 2 deletions(-) diff --git a/bip32.c b/bip32.c index 8ecfc6f73..d9bda71af 100644 --- a/bip32.c +++ b/bip32.c @@ -264,6 +264,45 @@ int hdnode_public_ckd(HDNode *inout, uint32_t i) return 1; } +int hdnode_public_ckd_address_optimized(const HDNode *in, const curve_point *pub, uint32_t i, uint8_t version, char *addr, int addrsize) +{ + uint8_t data[1 + 32 + 4]; + uint8_t I[32 + 32]; + uint8_t public_key[33]; + curve_point b; + bignum256 c; + + if (i & 0x80000000) { // private derivation + return 0; + } + memcpy(data, in->public_key, 33); + write_be(data + 33, i); + + while (true) { + bool failed = false; + hmac_sha512(in->chain_code, 32, data, sizeof(data), I); + bn_read_be(I, &c); + if (!bn_is_less(&c, &in->curve->params->order)) { // >= order + failed = true; + } else { + scalar_multiply(in->curve->params, &c, &b); // b = c * G + point_add(in->curve->params, pub, &b); // b = a + b + if (point_is_infinity(&b)) { + failed = true; + } + } + if (!failed) { + public_key[0] = 0x02 | (b.y.val[0] & 0x01); + bn_write_be(&b.x, public_key + 1); + break; + } + data[0] = 1; + memcpy(data + 1, I + 32, 32); + } + ecdsa_get_address(public_key, version, addr, addrsize); + return 1; +} + #if USE_BIP32_CACHE static bool private_ckd_cache_root_set = false; diff --git a/bip32.h b/bip32.h index 2f7dca3e1..ed45498bb 100644 --- a/bip32.h +++ b/bip32.h @@ -56,6 +56,8 @@ int hdnode_private_ckd(HDNode *inout, uint32_t i); int hdnode_public_ckd(HDNode *inout, uint32_t i); +int hdnode_public_ckd_address_optimized(const HDNode *in, const curve_point *pub, uint32_t i, uint8_t version, char *addr, int addrsize); + #if USE_BIP32_CACHE int hdnode_private_ckd_cached(HDNode *inout, const uint32_t *i, size_t i_count); diff --git a/test_speed.c b/test_speed.c index 0541ef246..75ccb4d8b 100644 --- a/test_speed.c +++ b/test_speed.c @@ -6,6 +6,7 @@ #include "curves.h" #include "ecdsa.h" #include "secp256k1.h" +#include "nist256p1.h" #include "ed25519.h" uint8_t msg[32]; @@ -34,6 +35,23 @@ void bench_secp256k1(void) { printf("SECP256k1 verifying speed: %0.2f sig/s\n", 500.0f / ((float)(clock() - t) / CLOCKS_PER_SEC)); } +void bench_nist256p1(void) { + uint8_t sig[64], pub[33], priv[32], pby; + + const ecdsa_curve *curve = &nist256p1; + + memcpy(priv, "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", 32); + ecdsa_get_public_key33(curve, priv, pub); + ecdsa_sign(curve, priv, msg, sizeof(msg), sig, &pby); + + clock_t t = clock(); + for (int i = 0 ; i < 500; i++) { + int res = ecdsa_verify(curve, pub, sig, msg, sizeof(msg)); + assert(res == 0); + } + printf("NIST256p1 verifying speed: %0.2f sig/s\n", 500.0f / ((float)(clock() - t) / CLOCKS_PER_SEC)); +} + void bench_ed25519(void) { ed25519_public_key pk; ed25519_secret_key sk; @@ -49,12 +67,58 @@ void bench_ed25519(void) { assert(res == 0); } printf("Ed25519 verifying speed: %0.2f sig/s\n", 500.0f / ((float)(clock() - t) / CLOCKS_PER_SEC)); - } -int main(void) { +void test_verify_speed(void) { prepare_msg(); bench_secp256k1(); + bench_nist256p1(); bench_ed25519(); +} + +HDNode root; + +void prepare_node(void) +{ + hdnode_from_seed((uint8_t *)"NothingToSeeHere", 16, SECP256K1_NAME, &root); +} + +void bench_ckd_normal(void) { + char addr[40]; + clock_t t = clock(); + for (int i = 0; i < 1000; i++) { + HDNode node = root; + hdnode_public_ckd(&node, i); + ecdsa_get_address(node.public_key, 0, addr, 40); + if (i == 0) { + printf("address = %s\n", addr); + } + } + printf("CKD normal speed: %0.2f iter/s\n", 1000.0f / ((float)(clock() - t) / CLOCKS_PER_SEC)); +} + +void bench_ckd_optimized(void) { + char addr[40]; + curve_point pub; + ecdsa_read_pubkey(root.curve->params, root.public_key, &pub); + clock_t t = clock(); + for (int i = 0; i < 1000; i++) { + hdnode_public_ckd_address_optimized(&root, &pub, i, 0, addr, 40); + if (i == 0) { + printf("address = %s\n", addr); + } + } + printf("CKD optim speed: %0.2f iter/s\n", 1000.0f / ((float)(clock() - t) / CLOCKS_PER_SEC)); +} + +void test_ckd_speed(void) { + prepare_node(); + bench_ckd_normal(); + bench_ckd_optimized(); +} + +int main(void) { + test_verify_speed(); + test_ckd_speed(); return 0; } From 110965f31d804f70b7b328007b7567ab77873e84 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 12 May 2016 19:29:24 +0200 Subject: [PATCH 272/627] further optimize emscripten --- bip32.c | 20 ++++++++++---------- bip32.h | 2 +- ecdsa.c | 4 ++++ emscripten/Makefile | 6 +++++- emscripten/post.js | 43 ++++++++++++++++++++----------------------- emscripten/test.js | 4 ++-- test_speed.c | 4 ++-- 7 files changed, 44 insertions(+), 39 deletions(-) diff --git a/bip32.c b/bip32.c index d9bda71af..a9fc2e7f5 100644 --- a/bip32.c +++ b/bip32.c @@ -264,42 +264,42 @@ int hdnode_public_ckd(HDNode *inout, uint32_t i) return 1; } -int hdnode_public_ckd_address_optimized(const HDNode *in, const curve_point *pub, uint32_t i, uint8_t version, char *addr, int addrsize) +int hdnode_public_ckd_address_optimized(const curve_point *pub, const uint8_t *public_key, const uint8_t *chain_code, uint32_t i, uint8_t version, char *addr, int addrsize) { uint8_t data[1 + 32 + 4]; uint8_t I[32 + 32]; - uint8_t public_key[33]; + uint8_t child_pubkey[33]; curve_point b; bignum256 c; if (i & 0x80000000) { // private derivation return 0; } - memcpy(data, in->public_key, 33); + memcpy(data, public_key, 33); write_be(data + 33, i); while (true) { bool failed = false; - hmac_sha512(in->chain_code, 32, data, sizeof(data), I); + hmac_sha512(chain_code, 32, data, sizeof(data), I); bn_read_be(I, &c); - if (!bn_is_less(&c, &in->curve->params->order)) { // >= order + if (!bn_is_less(&c, &secp256k1.order)) { // >= order failed = true; } else { - scalar_multiply(in->curve->params, &c, &b); // b = c * G - point_add(in->curve->params, pub, &b); // b = a + b + scalar_multiply(&secp256k1, &c, &b); // b = c * G + point_add(&secp256k1, pub, &b); // b = a + b if (point_is_infinity(&b)) { failed = true; } } if (!failed) { - public_key[0] = 0x02 | (b.y.val[0] & 0x01); - bn_write_be(&b.x, public_key + 1); + child_pubkey[0] = 0x02 | (b.y.val[0] & 0x01); + bn_write_be(&b.x, child_pubkey + 1); break; } data[0] = 1; memcpy(data + 1, I + 32, 32); } - ecdsa_get_address(public_key, version, addr, addrsize); + ecdsa_get_address(child_pubkey, version, addr, addrsize); return 1; } diff --git a/bip32.h b/bip32.h index ed45498bb..ddabf1869 100644 --- a/bip32.h +++ b/bip32.h @@ -56,7 +56,7 @@ int hdnode_private_ckd(HDNode *inout, uint32_t i); int hdnode_public_ckd(HDNode *inout, uint32_t i); -int hdnode_public_ckd_address_optimized(const HDNode *in, const curve_point *pub, uint32_t i, uint8_t version, char *addr, int addrsize); +int hdnode_public_ckd_address_optimized(const curve_point *pub, const uint8_t *public_key, const uint8_t *chain_code, uint32_t i, uint8_t version, char *addr, int addrsize); #if USE_BIP32_CACHE diff --git a/ecdsa.c b/ecdsa.c index bb465a2f4..9cbd92849 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -35,6 +35,7 @@ #include "ecdsa.h" #include "base58.h" #include "macros.h" +#include "secp256k1.h" // Set cp2 = cp1 void point_copy(const curve_point *cp1, curve_point *cp2) @@ -878,6 +879,9 @@ void uncompress_coords(const ecdsa_curve *curve, uint8_t odd, const bignum256 *x int ecdsa_read_pubkey(const ecdsa_curve *curve, const uint8_t *pub_key, curve_point *pub) { + if (!curve) { + curve = &secp256k1; + } if (pub_key[0] == 0x04) { bn_read_be(pub_key + 1, &(pub->x)); bn_read_be(pub_key + 33, &(pub->y)); diff --git a/emscripten/Makefile b/emscripten/Makefile index 66e1bf492..0424c23b7 100644 --- a/emscripten/Makefile +++ b/emscripten/Makefile @@ -2,7 +2,8 @@ EMFLAGS = \ -Os --closure 1 \ --memory-init-file 0 \ --pre-js pre.js --post-js post.js \ - -s EXPORTED_FUNCTIONS='["_hdnode_public_ckd", "_ecdsa_get_address"]' + -I ../ed25519-donna \ + -s EXPORTED_FUNCTIONS='["_hdnode_public_ckd_address_optimized", "_ecdsa_read_pubkey"]' SRC = ../bignum.c ../ecdsa.c ../secp256k1.c ../hmac.c ../bip32.c \ ../base58.c ../ripemd160.c ../sha2.c ../rand.c @@ -22,3 +23,6 @@ node_modules: clean: rm -f trezor-crypto.js test-browserify.js + +docker: + docker run --rm -i -v $(shell pwd)/..:/src -t apiaryio/emcc /bin/bash diff --git a/emscripten/post.js b/emscripten/post.js index c42c941c1..29942893a 100644 --- a/emscripten/post.js +++ b/emscripten/post.js @@ -11,13 +11,17 @@ var HEAPU8 = Module['HEAPU8']; var _malloc = Module['_malloc']; -var _hdnode_public_ckd = Module['_hdnode_public_ckd']; -var _ecdsa_get_address = Module['_ecdsa_get_address']; +var _hdnode_public_ckd_address_optimized = Module['_hdnode_public_ckd_address_optimized']; +var _ecdsa_read_pubkey = Module['_ecdsa_read_pubkey']; var Pointer_stringify = Module['Pointer_stringify']; -// HDNode struct global -var HDNODE_SIZE = 4 + 4 + 4 + 32 + 32 + 33; -var _hdnode = _malloc(HDNODE_SIZE); +// HDNode structs global +var PUBPOINT_SIZE = 2 * 9 * 4; // (2 * bignum256 (= 9 * uint32_t)) +var _pubpoint = _malloc(PUBPOINT_SIZE); +var PUBKEY_SIZE = 33; +var _pubkey = _malloc(PUBKEY_SIZE); +var CHAINCODE_SIZE = 32; +var _chaincode = _malloc(CHAINCODE_SIZE); // address string global var ADDRESS_SIZE = 40; // maximum size @@ -29,33 +33,26 @@ var _address = _malloc(ADDRESS_SIZE); /** * @param {HDNode} node HDNode struct, see the definition above - * @return {Uint8Array} */ function serializeNode(node) { - var b = new ArrayBuffer(HDNODE_SIZE); + var u8_pubkey = new Uint8Array(33); + u8_pubkey.set(node['public_key'], 0); + HEAPU8.set(u8_pubkey, _pubkey); - var u32 = new Uint32Array(b, 0, 12); - u32[0] = node['depth']; - u32[1] = node['fingerprint']; - u32[2] = node['child_num']; + var u8_chaincode = new Uint8Array(32); + u8_chaincode.set(node['chain_code'], 0); + HEAPU8.set(u8_chaincode, _chaincode); - var u8 = new Uint8Array(b, 0, HDNODE_SIZE); - u8.set(node['chain_code'], 12); - u8.set(node['public_key'], 12 + 32 + 32); - - return u8; + _ecdsa_read_pubkey(0, _pubkey, _pubpoint); } /** - * @param {Uint8Array} sn serialized node, see `serializeNode` * @param {Number} index BIP32 index of the address * @param {Number} version address version byte * @return {String} */ -function deriveAddress(sn, index, version) { - HEAPU8.set(sn, _hdnode); - _hdnode_public_ckd(_hdnode, index); - _ecdsa_get_address(_hdnode + 12 + 32 + 32, version, _address, ADDRESS_SIZE); +function deriveAddress(index, version) { + _hdnode_public_ckd_address_optimized(_pubpoint, _pubkey, _chaincode, index, version, _address, ADDRESS_SIZE); return Pointer_stringify(_address); } @@ -68,10 +65,10 @@ function deriveAddress(sn, index, version) { */ function deriveAddressRange(node, firstIndex, lastIndex, version) { var addresses = []; - var sn = serializeNode(node); + serializeNode(node); var i; for (i = firstIndex; i <= lastIndex; i++) { - addresses.push(deriveAddress(sn, i, version)); + addresses.push(deriveAddress(i, version)); } return addresses; } diff --git a/emscripten/test.js b/emscripten/test.js index acaeb600c..ed7ed8cfc 100644 --- a/emscripten/test.js +++ b/emscripten/test.js @@ -13,7 +13,6 @@ var nodeStruct = { chain_code: node.chainCode, public_key: node.keyPair.getPublicKeyBuffer() }; -var nodeSerialized = crypto.serializeNode(nodeStruct); var suite; var worker; @@ -60,8 +59,9 @@ function benchBitcoinJS(ops, fn) { function benchBrowserify(ops, fn) { var i; + crypto.serializeNode(nodeStruct); for (i = 0; i < ops; i++) { - crypto.deriveAddress(nodeSerialized, i, 0); + crypto.deriveAddress(i, 0); } fn(); } diff --git a/test_speed.c b/test_speed.c index 75ccb4d8b..0378692ef 100644 --- a/test_speed.c +++ b/test_speed.c @@ -100,10 +100,10 @@ void bench_ckd_normal(void) { void bench_ckd_optimized(void) { char addr[40]; curve_point pub; - ecdsa_read_pubkey(root.curve->params, root.public_key, &pub); + ecdsa_read_pubkey(0, root.public_key, &pub); clock_t t = clock(); for (int i = 0; i < 1000; i++) { - hdnode_public_ckd_address_optimized(&root, &pub, i, 0, addr, 40); + hdnode_public_ckd_address_optimized(&pub, root.public_key, root.chain_code, i, 0, addr, 40); if (i == 0) { printf("address = %s\n", addr); } From 75f239662468edece3e076ad8f7f927b8c4722e0 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 12 May 2016 19:57:22 +0200 Subject: [PATCH 273/627] fix makefile for emscripten --- emscripten/Makefile | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/emscripten/Makefile b/emscripten/Makefile index 0424c23b7..ec3853f05 100644 --- a/emscripten/Makefile +++ b/emscripten/Makefile @@ -8,18 +8,19 @@ EMFLAGS = \ SRC = ../bignum.c ../ecdsa.c ../secp256k1.c ../hmac.c ../bip32.c \ ../base58.c ../ripemd160.c ../sha2.c ../rand.c +trezor-crypto.js: $(SRC) + emcc $(EMFLAGS) -o $@ $^ + test-node: node_modules trezor-crypto.js test.js node test.js test-browserify.js: node_modules trezor-crypto.js test.js - browserify test.js -o $@ --noparse=`pwd`/trezor-crypto.js + $(shell npm bin)/browserify test.js -o $@ --noparse=`pwd`/trezor-crypto.js @echo "open test.html in your favourite browser" -trezor-crypto.js: $(SRC) - emcc $(EMFLAGS) -o $@ $^ - node_modules: npm install + npm install browserify clean: rm -f trezor-crypto.js test-browserify.js From 51c0bb09d8f1066555d28ae3824988b318d2f39e Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 12 May 2016 20:57:55 +0200 Subject: [PATCH 274/627] make salt constant in pbkdf2 --- pbkdf2.c | 8 ++++---- pbkdf2.h | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/pbkdf2.c b/pbkdf2.c index 86903204d..86398aa64 100644 --- a/pbkdf2.c +++ b/pbkdf2.c @@ -26,7 +26,7 @@ #include "hmac.h" #include "macros.h" -void pbkdf2_hmac_sha256_Init(PBKDF2_HMAC_SHA256_CTX *pctx, const uint8_t *pass, int passlen, uint8_t *salt, int saltlen) +void pbkdf2_hmac_sha256_Init(PBKDF2_HMAC_SHA256_CTX *pctx, const uint8_t *pass, int passlen, const uint8_t *salt, int saltlen) { HMAC_SHA256_CTX hctx; hmac_sha256_Init(&hctx, pass, passlen); @@ -56,7 +56,7 @@ void pbkdf2_hmac_sha256_Final(PBKDF2_HMAC_SHA256_CTX *pctx, uint8_t *key) MEMSET_BZERO(pctx, sizeof(PBKDF2_HMAC_SHA256_CTX)); } -void pbkdf2_hmac_sha256(const uint8_t *pass, int passlen, uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key) +void pbkdf2_hmac_sha256(const uint8_t *pass, int passlen, const uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key) { PBKDF2_HMAC_SHA256_CTX pctx; pbkdf2_hmac_sha256_Init(&pctx, pass, passlen, salt, saltlen); @@ -64,7 +64,7 @@ void pbkdf2_hmac_sha256(const uint8_t *pass, int passlen, uint8_t *salt, int sal pbkdf2_hmac_sha256_Final(&pctx, key); } -void pbkdf2_hmac_sha512_Init(PBKDF2_HMAC_SHA512_CTX *pctx, const uint8_t *pass, int passlen, uint8_t *salt, int saltlen) +void pbkdf2_hmac_sha512_Init(PBKDF2_HMAC_SHA512_CTX *pctx, const uint8_t *pass, int passlen, const uint8_t *salt, int saltlen) { HMAC_SHA512_CTX hctx; hmac_sha512_Init(&hctx, pass, passlen); @@ -94,7 +94,7 @@ void pbkdf2_hmac_sha512_Final(PBKDF2_HMAC_SHA512_CTX *pctx, uint8_t *key) MEMSET_BZERO(pctx, sizeof(PBKDF2_HMAC_SHA512_CTX)); } -void pbkdf2_hmac_sha512(const uint8_t *pass, int passlen, uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key) +void pbkdf2_hmac_sha512(const uint8_t *pass, int passlen, const uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key) { PBKDF2_HMAC_SHA512_CTX pctx; pbkdf2_hmac_sha512_Init(&pctx, pass, passlen, salt, saltlen); diff --git a/pbkdf2.h b/pbkdf2.h index c3b56b2a0..2a4c26ec8 100644 --- a/pbkdf2.h +++ b/pbkdf2.h @@ -43,14 +43,14 @@ typedef struct _PBKDF2_HMAC_SHA512_CTX { char first; } PBKDF2_HMAC_SHA512_CTX; -void pbkdf2_hmac_sha256_Init(PBKDF2_HMAC_SHA256_CTX *pctx, const uint8_t *pass, int passlen, uint8_t *salt, int saltlen); +void pbkdf2_hmac_sha256_Init(PBKDF2_HMAC_SHA256_CTX *pctx, const uint8_t *pass, int passlen, const uint8_t *salt, int saltlen); void pbkdf2_hmac_sha256_Update(PBKDF2_HMAC_SHA256_CTX *pctx, uint32_t iterations); void pbkdf2_hmac_sha256_Final(PBKDF2_HMAC_SHA256_CTX *pctx, uint8_t *key); -void pbkdf2_hmac_sha256(const uint8_t *pass, int passlen, uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key); +void pbkdf2_hmac_sha256(const uint8_t *pass, int passlen, const uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key); -void pbkdf2_hmac_sha512_Init(PBKDF2_HMAC_SHA512_CTX *pctx, const uint8_t *pass, int passlen, uint8_t *salt, int saltlen); +void pbkdf2_hmac_sha512_Init(PBKDF2_HMAC_SHA512_CTX *pctx, const uint8_t *pass, int passlen, const uint8_t *salt, int saltlen); void pbkdf2_hmac_sha512_Update(PBKDF2_HMAC_SHA512_CTX *pctx, uint32_t iterations); void pbkdf2_hmac_sha512_Final(PBKDF2_HMAC_SHA512_CTX *pctx, uint8_t *key); -void pbkdf2_hmac_sha512(const uint8_t *pass, int passlen, uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key); +void pbkdf2_hmac_sha512(const uint8_t *pass, int passlen, const uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key); #endif From aae96e8285146d284c1e472711bd9e05ffbf8964 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 13 May 2016 19:45:43 +0200 Subject: [PATCH 275/627] add mnemonic generation methods with indexes option --- bip39.c | 40 ++++++++++++++++++++++++++++++++++++++++ bip39.h | 2 ++ 2 files changed, 42 insertions(+) diff --git a/bip39.c b/bip39.c index 10d5afa45..c35fbd76c 100644 --- a/bip39.c +++ b/bip39.c @@ -55,6 +55,16 @@ const char *mnemonic_generate(int strength) return mnemonic_from_data(data, strength / 8); } +const uint16_t *mnemonic_generate_indexes(int strength) +{ + if (strength % 32 || strength < 128 || strength > 256) { + return 0; + } + uint8_t data[32]; + random_buffer(data, 32); + return mnemonic_from_data_indexes(data, strength / 8); +} + const char *mnemonic_from_data(const uint8_t *data, int len) { if (len % 4 || len < 16 || len > 32) { @@ -89,6 +99,36 @@ const char *mnemonic_from_data(const uint8_t *data, int len) return mnemo; } +const uint16_t *mnemonic_from_data_indexes(const uint8_t *data, int len) +{ + if (len % 4 || len < 16 || len > 32) { + return 0; + } + + uint8_t bits[32 + 1]; + + sha256_Raw(data, len, bits); + // checksum + bits[len] = bits[0]; + // data + memcpy(bits, data, len); + + int mlen = len * 3 / 4; + static uint16_t mnemo[24]; + + int i, j, idx; + for (i = 0; i < mlen; i++) { + idx = 0; + for (j = 0; j < 11; j++) { + idx <<= 1; + idx += (bits[(i * 11 + j) / 8] & (1 << (7 - ((i * 11 + j) % 8)))) > 0; + } + mnemo[i] = idx; + } + + return mnemo; +} + int mnemonic_check(const char *mnemonic) { if (!mnemonic) { diff --git a/bip39.h b/bip39.h index 24a5b8d1b..385f3d4fe 100644 --- a/bip39.h +++ b/bip39.h @@ -29,8 +29,10 @@ #define BIP39_PBKDF2_ROUNDS 2048 const char *mnemonic_generate(int strength); // strength in bits +const uint16_t *mnemonic_generate_indexes(int strength); // strength in bits const char *mnemonic_from_data(const uint8_t *data, int len); +const uint16_t *mnemonic_from_data_indexes(const uint8_t *data, int len); int mnemonic_check(const char *mnemonic); From 31e05edca7f972840b1dde80751700b84fe8d349 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 16 May 2016 14:43:09 +0200 Subject: [PATCH 276/627] add script parsing functions --- Makefile | 1 + script.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ script.h | 30 ++++++++++++++++++++++++++ tests.c | 27 ++++++++++++++++++++++++ 4 files changed, 122 insertions(+) create mode 100644 script.c create mode 100644 script.h diff --git a/Makefile b/Makefile index 109019a1c..81ba17785 100644 --- a/Makefile +++ b/Makefile @@ -37,6 +37,7 @@ CFLAGS += -DUSE_PRECOMPUTED_IV=0 -DUSE_PRECOMPUTED_CP=0 endif SRCS = bignum.c ecdsa.c curves.c secp256k1.c nist256p1.c rand.c hmac.c bip32.c bip39.c pbkdf2.c base58.c +SRCS += script.c SRCS += ripemd160.c SRCS += sha2.c SRCS += sha3.c diff --git a/script.c b/script.c new file mode 100644 index 000000000..185d28fae --- /dev/null +++ b/script.c @@ -0,0 +1,64 @@ +/** + * Copyright (c) 2016 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include "base58.h" +#include "script.h" + +int script_output_to_address(const uint8_t *script, int scriptlen, char *addr, int addrsize) +{ + uint8_t raw[35]; + + // P2PKH + if (scriptlen == 25 && script[0] == 0x76 && script[1] == 0xA9 && script[2] == 0x14 && script[23] == 0x88 && script[24] == 0xAC) { + raw[0] = 0x00; + memcpy(raw + 1, script + 3, 20); + return base58_encode_check(raw, 1 + 20, addr, addrsize); + } + + // P2SH + if (scriptlen == 23 && script[0] == 0xA9 && script[1] == 0x14 && script[22] == 0x87) { + raw[0] = 0x05; + memcpy(raw + 1, script + 2, 20); + return base58_encode_check(raw, 1 + 20, addr, addrsize); + } + + // P2WPKH + if (scriptlen == 22 && script[0] == 0x00 && script[1] == 0x14) { + raw[0] = 0x06; + raw[1] = 0x00; + raw[2] = 0x00; + memcpy(raw + 3, script + 2, 20); + return base58_encode_check(raw, 3 + 20, addr, addrsize); + } + + // P2WSH + if (scriptlen == 34 && script[0] == 0x00 && script[1] == 0x20) { + raw[0] = 0x0A; + raw[1] = 0x00; + raw[2] = 0x00; + memcpy(raw + 3, script + 2, 32); + return base58_encode_check(raw, 3 + 32, addr, addrsize); + } + + return 0; +} diff --git a/script.h b/script.h new file mode 100644 index 000000000..9544bf7ca --- /dev/null +++ b/script.h @@ -0,0 +1,30 @@ +/** + * Copyright (c) 2016 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __SCRIPT_H__ +#define __SCRIPT_H__ + +#include + +int script_output_to_address(const uint8_t *script, int scriptlen, char *addr, int addrsize); + +#endif diff --git a/tests.c b/tests.c index a4012dc8a..191cbf35f 100644 --- a/tests.c +++ b/tests.c @@ -42,6 +42,7 @@ #include "secp256k1.h" #include "nist256p1.h" #include "ed25519.h" +#include "script.h" uint8_t *fromhex(const char *str) { @@ -1872,6 +1873,28 @@ START_TEST(test_ed25519) { } END_TEST +START_TEST(test_output_script) { + static const char *vectors[] = { + "76A914010966776006953D5567439E5E39F86A0D273BEE88AC", "16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM", + "A914010966776006953D5567439E5E39F86A0D273BEE87", "31nVrspaydBz8aMpxH9WkS2DuhgqS1fCuG", + "0014010966776006953D5567439E5E39F86A0D273BEE", "p2xtZoXeX5X8BP8JfFhQK2nD3emtjch7UeFm", + "00200102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F20", "7XhPD7te3C6CVKnJWUhrTJbFTwudhHqfrjpS59AS6sMzL4RYFiCNg", + 0, 0, + }; + const char **scr, **adr; + scr = vectors; + adr = vectors + 1; + char address[60]; + while (*scr && *adr) { + int r = script_output_to_address(fromhex(*scr), strlen(*scr)/2, address, 60); + ck_assert_int_eq(r, strlen(*adr) + 1); + ck_assert_str_eq(address, *adr); + scr += 2; + adr += 2; + } +} +END_TEST + // define test suite and cases Suite *test_suite(void) @@ -1975,6 +1998,10 @@ Suite *test_suite(void) tcase_add_test(tc, test_ed25519); suite_add_tcase(s, tc); + tc = tcase_create("script"); + tcase_add_test(tc, test_output_script); + suite_add_tcase(s, tc); + return s; } From fd519eae68d19f9a0051ac531bc18e5a1dd544c4 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 16 May 2016 15:29:29 +0200 Subject: [PATCH 277/627] add node_modules to .gitignore --- emscripten/.gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 emscripten/.gitignore diff --git a/emscripten/.gitignore b/emscripten/.gitignore new file mode 100644 index 000000000..c2658d7d1 --- /dev/null +++ b/emscripten/.gitignore @@ -0,0 +1 @@ +node_modules/ From f60cd681f6c3058275dea68ccfc6ae70f800cb2c Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 16 May 2016 16:42:34 +0200 Subject: [PATCH 278/627] fix sign-compare warning --- tests.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests.c b/tests.c index 191cbf35f..cd931e165 100644 --- a/tests.c +++ b/tests.c @@ -1887,7 +1887,7 @@ START_TEST(test_output_script) { char address[60]; while (*scr && *adr) { int r = script_output_to_address(fromhex(*scr), strlen(*scr)/2, address, 60); - ck_assert_int_eq(r, strlen(*adr) + 1); + ck_assert_int_eq(r, (int)(strlen(*adr) + 1)); ck_assert_str_eq(address, *adr); scr += 2; adr += 2; From 23590c05c652efccdfb7e837a048adbecab5b145 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 16 May 2016 16:59:05 +0200 Subject: [PATCH 279/627] rename index to idx in sha3 to avoid collision with index function in strings.h --- sha3.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sha3.c b/sha3.c index de6b58066..9f23b89d3 100644 --- a/sha3.c +++ b/sha3.c @@ -267,16 +267,16 @@ static void sha3_process_block(uint64_t hash[25], const uint64_t *block, size_t */ void sha3_Update(SHA3_CTX *ctx, const unsigned char *msg, size_t size) { - size_t index = (size_t)ctx->rest; + size_t idx = (size_t)ctx->rest; size_t block_size = (size_t)ctx->block_size; if (ctx->rest & SHA3_FINALIZED) return; /* too late for additional input */ ctx->rest = (unsigned)((ctx->rest + size) % block_size); /* fill partial block */ - if (index) { - size_t left = block_size - index; - memcpy((char*)ctx->message + index, msg, (size < left ? size : left)); + if (idx) { + size_t left = block_size - idx; + memcpy((char*)ctx->message + idx, msg, (size < left ? size : left)); if (size < left) return; /* process partial block */ From d68906ec4eeddf59bb9c67e0a8f8077991cd17c3 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Tue, 17 May 2016 18:10:23 +0100 Subject: [PATCH 280/627] Use proper option for USE_KECCAK via options.h --- options.h | 5 +++++ sha3.c | 2 +- sha3.h | 3 ++- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/options.h b/options.h index d5ac4ab33..4baadf0bd 100644 --- a/options.h +++ b/options.h @@ -56,4 +56,9 @@ #define BIP39_CACHE_SIZE 4 #endif +// support Keccak hashing +#ifndef USE_KECCAK +#define USE_KECCAK 0 +#endif + #endif diff --git a/sha3.c b/sha3.c index 9f23b89d3..fc6d1c8bf 100644 --- a/sha3.c +++ b/sha3.c @@ -331,7 +331,7 @@ void sha3_Final(SHA3_CTX *ctx, unsigned char* result) if (result) me64_to_le_str(result, ctx->hash, digest_length); } -#ifdef USE_KECCAK +#if USE_KECCAK /** * Store calculated hash into the given array. * diff --git a/sha3.h b/sha3.h index b809f3359..b605663ae 100644 --- a/sha3.h +++ b/sha3.h @@ -21,6 +21,7 @@ #define __SHA3_H__ #include +#include "options.h" #ifdef __cplusplus extern "C" { @@ -57,7 +58,7 @@ void sha3_512_Init(SHA3_CTX *ctx); void sha3_Update(SHA3_CTX *ctx, const unsigned char* msg, size_t size); void sha3_Final(SHA3_CTX *ctx, unsigned char* result); -#ifdef USE_KECCAK +#if USE_KECCAK #define keccak_224_Init sha3_224_Init #define keccak_256_Init sha3_256_Init #define keccak_384_Init sha3_384_Init From 7d68a6ee1744972a9115e88f4213f99232d63acf Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Tue, 17 May 2016 18:11:31 +0100 Subject: [PATCH 281/627] Add ecdsa_uncompress_pubkey() Code based on @Arachnid's PR, but has more strict checks --- ecdsa.c | 21 +++++++++++++++++++++ ecdsa.h | 1 + 2 files changed, 22 insertions(+) diff --git a/ecdsa.c b/ecdsa.c index 9cbd92849..2394101f4 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -815,6 +815,27 @@ void ecdsa_get_public_key65(const ecdsa_curve *curve, const uint8_t *priv_key, u MEMSET_BZERO(&k, sizeof(k)); } +int ecdsa_uncompress_pubkey(const ecdsa_curve *curve, const uint8_t *pub_key, uint8_t *uncompressed) +{ + if (pub_key[0] == 2 || pub_key[0] == 3) { + bignum256 x, y; + + bn_read_be(pub_key + 1, &x); + // uncompress_coords will check for pub_key[0] & 1 + uncompress_coords(curve, pub_key[0], &x, &y); + + uncompressed[0] = 4; + memcpy(uncompressed + 1, pub_key + 1, 32); + bn_write_be(&y, uncompressed + 33); + return 1; + } else if (pub_key[0] == 4) { + memcpy(uncompressed, pub_key, 65); + return 1; + } + + return 0; +} + void ecdsa_get_pubkeyhash(const uint8_t *pub_key, uint8_t *pubkeyhash) { uint8_t h[32]; diff --git a/ecdsa.h b/ecdsa.h index 45cbb81d5..b7c22aa4d 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -58,6 +58,7 @@ int point_is_equal(const curve_point *p, const curve_point *q); int point_is_negative_of(const curve_point *p, const curve_point *q); void scalar_multiply(const ecdsa_curve *curve, const bignum256 *k, curve_point *res); void uncompress_coords(const ecdsa_curve *curve, uint8_t odd, const bignum256 *x, bignum256 *y); +int ecdsa_uncompress_pubkey(const ecdsa_curve *curve, const uint8_t *pub_key, uint8_t *uncompressed); int ecdsa_sign(const ecdsa_curve *curve, const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby); int ecdsa_sign_double(const ecdsa_curve *curve, const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby); From 1b8e3d557f4d40559cd710b2d49fd7faf7d0c545 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Tue, 17 May 2016 18:12:13 +0100 Subject: [PATCH 282/627] Implement ecdsa_get_ethereum_pubkeyhash() --- ecdsa.c | 24 ++++++++++++++++++++++++ ecdsa.h | 1 + options.h | 7 ++++++- 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/ecdsa.c b/ecdsa.c index 2394101f4..3cb52ce44 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -36,6 +36,9 @@ #include "base58.h" #include "macros.h" #include "secp256k1.h" +#if USE_ETHEREUM +#include "sha3.h" +#endif // Set cp2 = cp1 void point_copy(const curve_point *cp1, curve_point *cp2) @@ -850,6 +853,27 @@ void ecdsa_get_pubkeyhash(const uint8_t *pub_key, uint8_t *pubkeyhash) MEMSET_BZERO(h, sizeof(h)); } +#if USE_ETHEREUM +int ecdsa_get_ethereum_pubkeyhash(const uint8_t *pub_key, uint8_t *pubkeyhash) +{ + uint8_t h[65]; + SHA3_CTX ctx; + + if (!ecdsa_uncompress_pubkey(&secp256k1, pub_key, h)) { + return 0; + } + + sha3_256_Init(&ctx); + sha3_Update(&ctx, h + 1, 64); + keccak_Final(&ctx, h); + + // least significant 160 bits + memcpy(pubkeyhash, h + 12, 20); + + return 1; +} +#endif + void ecdsa_get_address_raw(const uint8_t *pub_key, uint8_t version, uint8_t *addr_raw) { addr_raw[0] = version; diff --git a/ecdsa.h b/ecdsa.h index b7c22aa4d..2950a314f 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -66,6 +66,7 @@ int ecdsa_sign_digest(const ecdsa_curve *curve, const uint8_t *priv_key, const u void ecdsa_get_public_key33(const ecdsa_curve *curve, const uint8_t *priv_key, uint8_t *pub_key); void ecdsa_get_public_key65(const ecdsa_curve *curve, const uint8_t *priv_key, uint8_t *pub_key); void ecdsa_get_pubkeyhash(const uint8_t *pub_key, uint8_t *pubkeyhash); +int ecdsa_get_ethereum_pubkeyhash(const uint8_t *pub_key, uint8_t *pubkeyhash); void ecdsa_get_address_raw(const uint8_t *pub_key, uint8_t version, uint8_t *addr_raw); void ecdsa_get_address(const uint8_t *pub_key, uint8_t version, char *addr, int addrsize); void ecdsa_get_wif(const uint8_t *priv_key, uint8_t version, char *wif, int wifsize); diff --git a/options.h b/options.h index 4baadf0bd..fabca9f9b 100644 --- a/options.h +++ b/options.h @@ -56,9 +56,14 @@ #define BIP39_CACHE_SIZE 4 #endif +// support Ethereum operations +#ifndef USE_ETHEREUM +#define USE_ETHEREUM 0 +#endif + // support Keccak hashing #ifndef USE_KECCAK -#define USE_KECCAK 0 +#define USE_KECCAK USE_ETHEREUM #endif #endif From aecf8671a126adfd3065199f2ba27339f8b756db Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Tue, 17 May 2016 18:42:54 +0100 Subject: [PATCH 283/627] Add sha3 to cmake --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 165d7aeb0..2f256bb4c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 2.6) -set(SOURCES aescrypt.c aeskey.c aes_modes.c aestab.c base58.c bignum.c bip32.c bip39.c ecdsa.c hmac.c nist256p1.c pbkdf2.c rand.c ripemd160.c secp256k1.c sha2.c ed25519-donna/ed25519.c) +set(SOURCES aescrypt.c aeskey.c aes_modes.c aestab.c base58.c bignum.c bip32.c bip39.c ecdsa.c hmac.c nist256p1.c pbkdf2.c rand.c ripemd160.c secp256k1.c sha2.c ed25519-donna/ed25519.c sha3.c) include_directories(ed25519-donna) # disable sequence point warnings where they are expected From 4e7da75c6e3bfd071edb0feef22db9958c936da0 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Tue, 17 May 2016 19:37:29 +0100 Subject: [PATCH 284/627] Rewrite ecdsa_uncompress_pubkey() using ecdsa_read_pubkey() --- ecdsa.c | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/ecdsa.c b/ecdsa.c index 3cb52ce44..cbb114b8a 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -820,23 +820,17 @@ void ecdsa_get_public_key65(const ecdsa_curve *curve, const uint8_t *priv_key, u int ecdsa_uncompress_pubkey(const ecdsa_curve *curve, const uint8_t *pub_key, uint8_t *uncompressed) { - if (pub_key[0] == 2 || pub_key[0] == 3) { - bignum256 x, y; + curve_point pub; - bn_read_be(pub_key + 1, &x); - // uncompress_coords will check for pub_key[0] & 1 - uncompress_coords(curve, pub_key[0], &x, &y); - - uncompressed[0] = 4; - memcpy(uncompressed + 1, pub_key + 1, 32); - bn_write_be(&y, uncompressed + 33); - return 1; - } else if (pub_key[0] == 4) { - memcpy(uncompressed, pub_key, 65); - return 1; + if (!ecdsa_read_pubkey(curve, pub_key, &pub)) { + return 0; } - return 0; + uncompressed[0] = 4; + bn_write_be(&pub.x, uncompressed + 1); + bn_write_be(&pub.y, uncompressed + 33); + + return 1; } void ecdsa_get_pubkeyhash(const uint8_t *pub_key, uint8_t *pubkeyhash) From ca2fcbf3e3ad13186607f42662d7b980400d5b30 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Mon, 13 Jun 2016 21:59:52 +0100 Subject: [PATCH 285/627] Add tests for ecdsa_uncompress_pubkey() --- tests.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/tests.c b/tests.c index cd931e165..99ae3d4e7 100644 --- a/tests.c +++ b/tests.c @@ -1507,6 +1507,34 @@ START_TEST(test_pubkey_validity) } END_TEST +START_TEST(test_pubkey_uncompress) +{ + uint8_t pub_key[65]; + uint8_t uncompressed[65]; + int res; + const ecdsa_curve *curve = &secp256k1; + + memcpy(pub_key, fromhex("0226659c1cf7321c178c07437150639ff0c5b7679c7ea195253ed9abda2e081a37"), 33); + res = ecdsa_uncompress_pubkey(curve, pub_key, uncompressed); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(uncompressed, fromhex("0426659c1cf7321c178c07437150639ff0c5b7679c7ea195253ed9abda2e081a37b3cfbad6b39a8ce8cb3a675f53b7b57e120fe067b8035d771fd99e3eba7cf4de"), 65); + + memcpy(pub_key, fromhex("03433f246a12e6486a51ff08802228c61cf895175a9b49ed4766ea9a9294a3c7fe"), 33); + res = ecdsa_uncompress_pubkey(curve, pub_key, uncompressed); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(uncompressed, fromhex("04433f246a12e6486a51ff08802228c61cf895175a9b49ed4766ea9a9294a3c7feeb4c25bcb840f720a16e8857a011e6b91e0ab2d03dbb5f9762844bb21a7b8ca7"), 65); + + memcpy(pub_key, fromhex("0496e8f2093f018aff6c2e2da5201ee528e2c8accbf9cac51563d33a7bb74a016054201c025e2a5d96b1629b95194e806c63eb96facaedc733b1a4b70ab3b33e3a"), 65); + res = ecdsa_uncompress_pubkey(curve, pub_key, uncompressed); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(uncompressed, fromhex("0496e8f2093f018aff6c2e2da5201ee528e2c8accbf9cac51563d33a7bb74a016054201c025e2a5d96b1629b95194e806c63eb96facaedc733b1a4b70ab3b33e3a"), 65); + + memcpy(pub_key, fromhex("00"), 1); + res = ecdsa_uncompress_pubkey(curve, pub_key, uncompressed); + ck_assert_int_eq(res, 0); +} +END_TEST + START_TEST(test_wif) { uint8_t priv_key[32]; @@ -1974,6 +2002,10 @@ Suite *test_suite(void) tcase_add_test(tc, test_pubkey_validity); suite_add_tcase(s, tc); + tc = tcase_create("pubkey_uncompress"); + tcase_add_test(tc, test_pubkey_uncompress); + suite_add_tcase(s, tc); + tc = tcase_create("codepoints"); tcase_add_test(tc, test_codepoints); suite_add_tcase(s, tc); From ec7bea43084d7d966beb6385ce1b9ae0e1e95bcb Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Mon, 13 Jun 2016 22:13:37 +0100 Subject: [PATCH 286/627] Add tests for ecdsa_get_ethereum_pubkeyhash() --- Makefile | 1 + tests.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/Makefile b/Makefile index 81ba17785..9c91c9794 100644 --- a/Makefile +++ b/Makefile @@ -30,6 +30,7 @@ CFLAGS += -DED25519_CUSTOMHASH=1 CFLAGS += -DED25519_NO_INLINE_ASM CFLAGS += -DED25519_FORCE_32BIT=1 CFLAGS += -Ied25519-donna -I. +CFLAGS += -DUSE_ETHEREUM=1 # disable certain optimizations and features when small footprint is required ifdef SMALL diff --git a/tests.c b/tests.c index 99ae3d4e7..051f52b9b 100644 --- a/tests.c +++ b/tests.c @@ -1923,6 +1923,53 @@ START_TEST(test_output_script) { } END_TEST +START_TEST(test_ethereum_pubkeyhash) +{ + uint8_t pubkeyhash[20]; + uint8_t pub_key[65]; + int res; + + memcpy(pub_key, fromhex("0226659c1cf7321c178c07437150639ff0c5b7679c7ea195253ed9abda2e081a37"), 33); + res = ecdsa_get_ethereum_pubkeyhash(pub_key, pubkeyhash); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(pubkeyhash, fromhex("dfec07843c46f3fb5e5ef8b70b845231a97ed2c8"), 20); + + memcpy(pub_key, fromhex("025b1654a0e78d28810094f6c5a96b8efb8a65668b578f170ac2b1f83bc63ba856"), 33); + res = ecdsa_get_ethereum_pubkeyhash(pub_key, pubkeyhash); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(pubkeyhash, fromhex("aa2685dbc0a1820fc4bb03c3154d1cc0b26411ee"), 20); + + memcpy(pub_key, fromhex("03433f246a12e6486a51ff08802228c61cf895175a9b49ed4766ea9a9294a3c7fe"), 33); + res = ecdsa_get_ethereum_pubkeyhash(pub_key, pubkeyhash); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(pubkeyhash, fromhex("86193afd976244f39f0e9d42a1d2c090080754f1"), 20); + + memcpy(pub_key, fromhex("03aeb03abeee0f0f8b4f7a5d65ce31f9570cef9f72c2dd8a19b4085a30ab033d48"), 33); + res = ecdsa_get_ethereum_pubkeyhash(pub_key, pubkeyhash); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(pubkeyhash, fromhex("330b7636bff2c8ea728170042ab6af0b826cbdc0"), 20); + + memcpy(pub_key, fromhex("0496e8f2093f018aff6c2e2da5201ee528e2c8accbf9cac51563d33a7bb74a016054201c025e2a5d96b1629b95194e806c63eb96facaedc733b1a4b70ab3b33e3a"), 65); + res = ecdsa_get_ethereum_pubkeyhash(pub_key, pubkeyhash); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(pubkeyhash, fromhex("10027a9bef3e98be693f8fb4c02f4a7421cdf384"), 20); + + memcpy(pub_key, fromhex("0498010f8a687439ff497d3074beb4519754e72c4b6220fb669224749591dde416f3961f8ece18f8689bb32235e436874d2174048b86118a00afbd5a4f33a24f0f"), 65); + res = ecdsa_get_ethereum_pubkeyhash(pub_key, pubkeyhash); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(pubkeyhash, fromhex("6d9baaf3db174b9ea498081707289c228108aa9e"), 20); + + memcpy(pub_key, fromhex("04f80490839af36d13701ec3f9eebdac901b51c362119d74553a3c537faff31b17e2a59ebddbdac9e87b816307a7ed5b826b8f40b92719086238e1bebf19b77a4d"), 65); + res = ecdsa_get_ethereum_pubkeyhash(pub_key, pubkeyhash); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(pubkeyhash, fromhex("addcb46a5ae157c837682689fcd4f80a76bb7740"), 20); + + memcpy(pub_key, fromhex("00"), 1); + res = ecdsa_get_ethereum_pubkeyhash(pub_key, pubkeyhash); + ck_assert_int_eq(res, 0); +} +END_TEST + // define test suite and cases Suite *test_suite(void) @@ -2034,6 +2081,10 @@ Suite *test_suite(void) tcase_add_test(tc, test_output_script); suite_add_tcase(s, tc); + tc = tcase_create("ethereum_pubkeyhash"); + tcase_add_test(tc, test_ethereum_pubkeyhash); + suite_add_tcase(s, tc); + return s; } From 3390fcf89e5502d6087a8b0d182fc9db05bbd759 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Sun, 26 Jun 2016 16:24:50 +0200 Subject: [PATCH 287/627] Compute pubkey only on demand. Remove fingerprint from hdnode structure (if you need it, call hdnode_fingerprint on the parent hdnode). Only compute public_key, when hdnode_fill_public_key is called. --- bip32.c | 69 +++++++++------- bip32.h | 19 +++-- tests.c | 243 ++++++++++++++++++++++++++++++++++++-------------------- 3 files changed, 209 insertions(+), 122 deletions(-) diff --git a/bip32.c b/bip32.c index a9fc2e7f5..40656906f 100644 --- a/bip32.c +++ b/bip32.c @@ -44,7 +44,7 @@ const curve_info ed25519_info = { 0 }; -int hdnode_from_xpub(uint32_t depth, uint32_t fingerprint, uint32_t child_num, const uint8_t *chain_code, const uint8_t *public_key, const char* curve, HDNode *out) +int hdnode_from_xpub(uint32_t depth, uint32_t child_num, const uint8_t *chain_code, const uint8_t *public_key, const char* curve, HDNode *out) { const curve_info *info = get_curve_by_name(curve); if (info == 0) { @@ -55,7 +55,6 @@ int hdnode_from_xpub(uint32_t depth, uint32_t fingerprint, uint32_t child_num, c } out->curve = info; out->depth = depth; - out->fingerprint = fingerprint; out->child_num = child_num; memcpy(out->chain_code, chain_code, 32); MEMSET_BZERO(out->private_key, 32); @@ -63,7 +62,7 @@ int hdnode_from_xpub(uint32_t depth, uint32_t fingerprint, uint32_t child_num, c return 1; } -int hdnode_from_xprv(uint32_t depth, uint32_t fingerprint, uint32_t child_num, const uint8_t *chain_code, const uint8_t *private_key, const char* curve, HDNode *out) +int hdnode_from_xprv(uint32_t depth, uint32_t child_num, const uint8_t *chain_code, const uint8_t *private_key, const char* curve, HDNode *out) { bool failed = false; const curve_info *info = get_curve_by_name(curve); @@ -88,11 +87,10 @@ int hdnode_from_xprv(uint32_t depth, uint32_t fingerprint, uint32_t child_num, c out->curve = info; out->depth = depth; - out->fingerprint = fingerprint; out->child_num = child_num; memcpy(out->chain_code, chain_code, 32); memcpy(out->private_key, private_key, 32); - hdnode_fill_public_key(out); + MEMSET_BZERO(out->public_key, sizeof(out->public_key)); return 1; } @@ -101,7 +99,6 @@ int hdnode_from_seed(const uint8_t *seed, int seed_len, const char* curve, HDNod uint8_t I[32 + 32]; memset(out, 0, sizeof(HDNode)); out->depth = 0; - out->fingerprint = 0x00000000; out->child_num = 0; out->curve = get_curve_by_name(curve); if (out->curve == 0) { @@ -125,17 +122,28 @@ int hdnode_from_seed(const uint8_t *seed, int seed_len, const char* curve, HDNod } memcpy(out->private_key, I, 32); memcpy(out->chain_code, I + 32, 32); - hdnode_fill_public_key(out); MEMSET_BZERO(I, sizeof(I)); return 1; } +uint32_t hdnode_fingerprint(HDNode *node) +{ + uint8_t digest[32]; + uint32_t fingerprint; + + hdnode_fill_public_key(node); + sha256_Raw(node->public_key, 33, digest); + ripemd160(digest, 32, digest); + fingerprint = (digest[0] << 24) + (digest[1] << 16) + (digest[2] << 8) + digest[3]; + MEMSET_BZERO(digest, sizeof(digest)); + return fingerprint; +} + int hdnode_private_ckd(HDNode *inout, uint32_t i) { uint8_t data[1 + 32 + 4]; uint8_t I[32 + 32]; - uint8_t fingerprint[32]; bignum256 a, b; if (i & 0x80000000) { // private derivation @@ -145,14 +153,11 @@ int hdnode_private_ckd(HDNode *inout, uint32_t i) if (!inout->curve->params) { return 0; } + hdnode_fill_public_key(inout); memcpy(data, inout->public_key, 33); } write_be(data + 33, i); - sha256_Raw(inout->public_key, 33, fingerprint); - ripemd160(fingerprint, 32, fingerprint); - inout->fingerprint = (fingerprint[0] << 24) + (fingerprint[1] << 16) + (fingerprint[2] << 8) + fingerprint[3]; - bn_read_be(inout->private_key, &a); hmac_sha512(inout->chain_code, 32, data, sizeof(data), I); @@ -186,13 +191,12 @@ int hdnode_private_ckd(HDNode *inout, uint32_t i) memcpy(inout->chain_code, I + 32, 32); inout->depth++; inout->child_num = i; - hdnode_fill_public_key(inout); + MEMSET_BZERO(inout->public_key, sizeof(inout->public_key)); // making sure to wipe our memory MEMSET_BZERO(&a, sizeof(a)); MEMSET_BZERO(&b, sizeof(b)); MEMSET_BZERO(I, sizeof(I)); - MEMSET_BZERO(fingerprint, sizeof(fingerprint)); MEMSET_BZERO(data, sizeof(data)); return 1; } @@ -214,11 +218,6 @@ int hdnode_public_ckd(HDNode *inout, uint32_t i) memcpy(data, inout->public_key, 33); } write_be(data + 33, i); - - sha256_Raw(inout->public_key, 33, fingerprint); - ripemd160(fingerprint, 32, fingerprint); - inout->fingerprint = (fingerprint[0] << 24) + (fingerprint[1] << 16) + (fingerprint[2] << 8) + fingerprint[3]; - memset(inout->private_key, 0, 32); if (!ecdsa_read_pubkey(inout->curve->params, inout->public_key, &a)) { @@ -372,10 +371,18 @@ int hdnode_private_ckd_cached(HDNode *inout, const uint32_t *i, size_t i_count) #endif +void hdnode_get_address_raw(HDNode *node, uint8_t version, uint8_t *addr_raw) +{ + hdnode_fill_public_key(node); + ecdsa_get_address_raw(node->public_key, version, addr_raw); +} + void hdnode_fill_public_key(HDNode *node) { + if (node->public_key[0] != 0) + return; if (node->curve == &ed25519_info) { - node->public_key[0] = 0; + node->public_key[0] = 1; ed25519_publickey(node->private_key, node->public_key + 1); } else { ecdsa_get_public_key33(node->curve->params, node->private_key, node->public_key); @@ -384,9 +391,10 @@ void hdnode_fill_public_key(HDNode *node) // msg is a data to be signed // msg_len is the message length -int hdnode_sign(const HDNode *node, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby) +int hdnode_sign(HDNode *node, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby) { if (node->curve == &ed25519_info) { + hdnode_fill_public_key(node); ed25519_sign(msg, msg_len, node->private_key, node->public_key + 1, sig); return 0; } else { @@ -394,9 +402,10 @@ int hdnode_sign(const HDNode *node, const uint8_t *msg, uint32_t msg_len, uint8_ } } -int hdnode_sign_digest(const HDNode *node, const uint8_t *digest, uint8_t *sig, uint8_t *pby) +int hdnode_sign_digest(HDNode *node, const uint8_t *digest, uint8_t *sig, uint8_t *pby) { if (node->curve == &ed25519_info) { + hdnode_fill_public_key(node); ed25519_sign(digest, 32, node->private_key, node->public_key + 1, sig); return 0; } else { @@ -405,12 +414,12 @@ int hdnode_sign_digest(const HDNode *node, const uint8_t *digest, uint8_t *sig, } -void hdnode_serialize(const HDNode *node, uint32_t version, char use_public, char *str, int strsize) +void hdnode_serialize(const HDNode *node, uint32_t fpr, uint32_t version, char use_public, char *str, int strsize) { uint8_t node_data[78]; write_be(node_data, version); node_data[4] = node->depth; - write_be(node_data + 5, node->fingerprint); + write_be(node_data + 5, fpr); write_be(node_data + 9, node->child_num); memcpy(node_data + 13, node->chain_code, 32); if (use_public) { @@ -424,14 +433,14 @@ void hdnode_serialize(const HDNode *node, uint32_t version, char use_public, cha MEMSET_BZERO(node_data, sizeof(node_data)); } -void hdnode_serialize_public(const HDNode *node, char *str, int strsize) +void hdnode_serialize_public(const HDNode *node, uint32_t fpr, char *str, int strsize) { - hdnode_serialize(node, 0x0488B21E, 1, str, strsize); + hdnode_serialize(node, fpr, 0x0488B21E, 1, str, strsize); } -void hdnode_serialize_private(const HDNode *node, char *str, int strsize) +void hdnode_serialize_private(const HDNode *node, uint32_t fpr, char *str, int strsize) { - hdnode_serialize(node, 0x0488ADE4, 0, str, strsize); + hdnode_serialize(node, fpr, 0x0488ADE4, 0, str, strsize); } // check for validity of curve point in case of public data not performed @@ -445,18 +454,18 @@ int hdnode_deserialize(const char *str, HDNode *node) node->curve = get_curve_by_name(SECP256K1_NAME); uint32_t version = read_be(node_data); if (version == 0x0488B21E) { // public node + MEMSET_BZERO(node->private_key, sizeof(node->private_key)); memcpy(node->public_key, node_data + 45, 33); } else if (version == 0x0488ADE4) { // private node if (node_data[45]) { // invalid data return -2; } memcpy(node->private_key, node_data + 46, 32); - hdnode_fill_public_key(node); + MEMSET_BZERO(node->public_key, sizeof(node->public_key)); } else { return -3; // invalid version } node->depth = node_data[4]; - node->fingerprint = read_be(node_data + 5); node->child_num = read_be(node_data + 9); memcpy(node->chain_code, node_data + 13, 32); return 0; diff --git a/bip32.h b/bip32.h index ddabf1869..02f92334e 100644 --- a/bip32.h +++ b/bip32.h @@ -36,7 +36,6 @@ typedef struct { typedef struct { uint32_t depth; - uint32_t fingerprint; uint32_t child_num; uint8_t chain_code[32]; uint8_t private_key[32]; @@ -44,9 +43,9 @@ typedef struct { const curve_info *curve; } HDNode; -int hdnode_from_xpub(uint32_t depth, uint32_t fingerprint, uint32_t child_num, const uint8_t *chain_code, const uint8_t *public_key, const char *curve, HDNode *out); +int hdnode_from_xpub(uint32_t depth, uint32_t child_num, const uint8_t *chain_code, const uint8_t *public_key, const char *curve, HDNode *out); -int hdnode_from_xprv(uint32_t depth, uint32_t fingerprint, uint32_t child_num, const uint8_t *chain_code, const uint8_t *private_key, const char *curve, HDNode *out); +int hdnode_from_xprv(uint32_t depth, uint32_t child_num, const uint8_t *chain_code, const uint8_t *private_key, const char *curve, HDNode *out); int hdnode_from_seed(const uint8_t *seed, int seed_len, const char *curve, HDNode *out); @@ -64,19 +63,23 @@ int hdnode_private_ckd_cached(HDNode *inout, const uint32_t *i, size_t i_count); #endif +uint32_t hdnode_fingerprint(HDNode *node); + void hdnode_fill_public_key(HDNode *node); -int hdnode_sign(const HDNode *node, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby); -int hdnode_sign_digest(const HDNode *node, const uint8_t *digest, uint8_t *sig, uint8_t *pby); +int hdnode_sign(HDNode *node, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby); +int hdnode_sign_digest(HDNode *node, const uint8_t *digest, uint8_t *sig, uint8_t *pby); -void hdnode_serialize_public(const HDNode *node, char *str, int strsize); +void hdnode_serialize_public(const HDNode *node, uint32_t fpr, char *str, int strsize); -void hdnode_serialize_private(const HDNode *node, char *str, int strsize); +void hdnode_serialize_private(const HDNode *node, uint32_t fpr, char *str, int strsize); int hdnode_deserialize(const char *str, HDNode *node); // Private -void hdnode_serialize(const HDNode *node, uint32_t version, char use_public, char *str, int strsize); +void hdnode_serialize(const HDNode *node, uint32_t fpr, uint32_t version, char use_public, char *str, int strsize); + +void hdnode_get_address_raw(HDNode *node, uint8_t version, uint8_t *addr_raw); const curve_info *get_curve_by_name(const char *curve_name); diff --git a/tests.c b/tests.c index 051f52b9b..73ae871d8 100644 --- a/tests.c +++ b/tests.c @@ -166,6 +166,7 @@ END_TEST START_TEST(test_bip32_vector_1) { HDNode node, node2, node3; + uint32_t fingerprint; char str[112]; int r; @@ -173,15 +174,18 @@ START_TEST(test_bip32_vector_1) hdnode_from_seed(fromhex("000102030405060708090a0b0c0d0e0f"), 16, SECP256K1_NAME, &node); // [Chain m] - ck_assert_int_eq(node.fingerprint, 0x00000000); + fingerprint = 0; + ck_assert_int_eq(fingerprint, 0x00000000); ck_assert_mem_eq(node.chain_code, fromhex("873dff81c02f525623fd1fe5167eac3a55a049de3d314bb42ee227ffed37d508"), 32); ck_assert_mem_eq(node.private_key, fromhex("e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35"), 32); + hdnode_fill_public_key(&node); ck_assert_mem_eq(node.public_key, fromhex("0339a36013301597daef41fbe593a02cc513d0b55527ec2df1050e2e8ff49c85c2"), 33); - hdnode_serialize_private(&node, str, sizeof(str)); + hdnode_serialize_private(&node, fingerprint, str, sizeof(str)); ck_assert_str_eq(str, "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi"); r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, str, sizeof(str)); + hdnode_serialize_public(&node, fingerprint, str, sizeof(str)); ck_assert_str_eq(str, "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8"); r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); @@ -189,16 +193,19 @@ START_TEST(test_bip32_vector_1) ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); // [Chain m/0'] + fingerprint = hdnode_fingerprint(&node); hdnode_private_ckd_prime(&node, 0); - ck_assert_int_eq(node.fingerprint, 0x3442193e); + ck_assert_int_eq(fingerprint, 0x3442193e); ck_assert_mem_eq(node.chain_code, fromhex("47fdacbd0f1097043b78c63c20c34ef4ed9a111d980047ad16282c7ae6236141"), 32); ck_assert_mem_eq(node.private_key, fromhex("edb2e14f9ee77d26dd93b4ecede8d16ed408ce149b6cd80b0715a2d911a0afea"), 32); + hdnode_fill_public_key(&node); ck_assert_mem_eq(node.public_key, fromhex("035a784662a4a20a65bf6aab9ae98a6c068a81c52e4b032c0fb5400c706cfccc56"), 33); - hdnode_serialize_private(&node, str, sizeof(str)); + hdnode_serialize_private(&node, fingerprint, str, sizeof(str)); ck_assert_str_eq(str, "xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7"); r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, str, sizeof(str)); + hdnode_serialize_public(&node, fingerprint, str, sizeof(str)); ck_assert_str_eq(str, "xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw"); r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); @@ -206,16 +213,19 @@ START_TEST(test_bip32_vector_1) ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); // [Chain m/0'/1] + fingerprint = hdnode_fingerprint(&node); hdnode_private_ckd(&node, 1); - ck_assert_int_eq(node.fingerprint, 0x5c1bd648); + ck_assert_int_eq(fingerprint, 0x5c1bd648); ck_assert_mem_eq(node.chain_code, fromhex("2a7857631386ba23dacac34180dd1983734e444fdbf774041578e9b6adb37c19"), 32); ck_assert_mem_eq(node.private_key, fromhex("3c6cb8d0f6a264c91ea8b5030fadaa8e538b020f0a387421a12de9319dc93368"), 32); + hdnode_fill_public_key(&node); ck_assert_mem_eq(node.public_key, fromhex("03501e454bf00751f24b1b489aa925215d66af2234e3891c3b21a52bedb3cd711c"), 33); - hdnode_serialize_private(&node, str, sizeof(str)); + hdnode_serialize_private(&node, fingerprint, str, sizeof(str)); ck_assert_str_eq(str, "xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs"); r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, str, sizeof(str)); + hdnode_serialize_public(&node, fingerprint, str, sizeof(str)); ck_assert_str_eq(str, "xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFHKkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ"); r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); @@ -223,16 +233,19 @@ START_TEST(test_bip32_vector_1) ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); // [Chain m/0'/1/2'] + fingerprint = hdnode_fingerprint(&node); hdnode_private_ckd_prime(&node, 2); - ck_assert_int_eq(node.fingerprint, 0xbef5a2f9); + ck_assert_int_eq(fingerprint, 0xbef5a2f9); ck_assert_mem_eq(node.chain_code, fromhex("04466b9cc8e161e966409ca52986c584f07e9dc81f735db683c3ff6ec7b1503f"), 32); ck_assert_mem_eq(node.private_key, fromhex("cbce0d719ecf7431d88e6a89fa1483e02e35092af60c042b1df2ff59fa424dca"), 32); + hdnode_fill_public_key(&node); ck_assert_mem_eq(node.public_key, fromhex("0357bfe1e341d01c69fe5654309956cbea516822fba8a601743a012a7896ee8dc2"), 33); - hdnode_serialize_private(&node, str, sizeof(str)); + hdnode_serialize_private(&node, fingerprint, str, sizeof(str)); ck_assert_str_eq(str, "xprv9z4pot5VBttmtdRTWfWQmoH1taj2axGVzFqSb8C9xaxKymcFzXBDptWmT7FwuEzG3ryjH4ktypQSAewRiNMjANTtpgP4mLTj34bhnZX7UiM"); r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, str, sizeof(str)); + hdnode_serialize_public(&node, fingerprint, str, sizeof(str)); ck_assert_str_eq(str, "xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5"); r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); @@ -240,16 +253,19 @@ START_TEST(test_bip32_vector_1) ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); // [Chain m/0'/1/2'/2] + fingerprint = hdnode_fingerprint(&node); hdnode_private_ckd(&node, 2); - ck_assert_int_eq(node.fingerprint, 0xee7ab90c); + ck_assert_int_eq(fingerprint, 0xee7ab90c); ck_assert_mem_eq(node.chain_code, fromhex("cfb71883f01676f587d023cc53a35bc7f88f724b1f8c2892ac1275ac822a3edd"), 32); ck_assert_mem_eq(node.private_key, fromhex("0f479245fb19a38a1954c5c7c0ebab2f9bdfd96a17563ef28a6a4b1a2a764ef4"), 32); + hdnode_fill_public_key(&node); ck_assert_mem_eq(node.public_key, fromhex("02e8445082a72f29b75ca48748a914df60622a609cacfce8ed0e35804560741d29"), 33); - hdnode_serialize_private(&node, str, sizeof(str)); + hdnode_serialize_private(&node, fingerprint, str, sizeof(str)); ck_assert_str_eq(str, "xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334"); r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, str, sizeof(str)); + hdnode_serialize_public(&node, fingerprint, str, sizeof(str)); ck_assert_str_eq(str, "xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV"); r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); @@ -257,16 +273,19 @@ START_TEST(test_bip32_vector_1) ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); // [Chain m/0'/1/2'/2/1000000000] + fingerprint = hdnode_fingerprint(&node); hdnode_private_ckd(&node, 1000000000); - ck_assert_int_eq(node.fingerprint, 0xd880d7d8); + ck_assert_int_eq(fingerprint, 0xd880d7d8); ck_assert_mem_eq(node.chain_code, fromhex("c783e67b921d2beb8f6b389cc646d7263b4145701dadd2161548a8b078e65e9e"), 32); ck_assert_mem_eq(node.private_key, fromhex("471b76e389e528d6de6d816857e012c5455051cad6660850e58372a6c3e6e7c8"), 32); + hdnode_fill_public_key(&node); ck_assert_mem_eq(node.public_key, fromhex("022a471424da5e657499d1ff51cb43c47481a03b1e77f951fe64cec9f5a48f7011"), 33); - hdnode_serialize_private(&node, str, sizeof(str)); + hdnode_serialize_private(&node, fingerprint, str, sizeof(str)); ck_assert_str_eq(str, "xprvA41z7zogVVwxVSgdKUHDy1SKmdb533PjDz7J6N6mV6uS3ze1ai8FHa8kmHScGpWmj4WggLyQjgPie1rFSruoUihUZREPSL39UNdE3BBDu76"); r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, str, sizeof(str)); + hdnode_serialize_public(&node, fingerprint, str, sizeof(str)); ck_assert_str_eq(str, "xpub6H1LXWLaKsWFhvm6RVpEL9P4KfRZSW7abD2ttkWP3SSQvnyA8FSVqNTEcYFgJS2UaFcxupHiYkro49S8yGasTvXEYBVPamhGW6cFJodrTHy"); r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); @@ -279,6 +298,7 @@ END_TEST START_TEST(test_bip32_vector_2) { HDNode node, node2, node3; + uint32_t fingerprint; char str[112]; int r; @@ -286,15 +306,18 @@ START_TEST(test_bip32_vector_2) hdnode_from_seed(fromhex("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), 64, SECP256K1_NAME, &node); // [Chain m] - ck_assert_int_eq(node.fingerprint, 0x00000000); + fingerprint = 0; + ck_assert_int_eq(fingerprint, 0x00000000); ck_assert_mem_eq(node.chain_code, fromhex("60499f801b896d83179a4374aeb7822aaeaceaa0db1f85ee3e904c4defbd9689"), 32); ck_assert_mem_eq(node.private_key, fromhex("4b03d6fc340455b363f51020ad3ecca4f0850280cf436c70c727923f6db46c3e"), 32); + hdnode_fill_public_key(&node); ck_assert_mem_eq(node.public_key, fromhex("03cbcaa9c98c877a26977d00825c956a238e8dddfbd322cce4f74b0b5bd6ace4a7"), 33); - hdnode_serialize_private(&node, str, sizeof(str)); + hdnode_serialize_private(&node, fingerprint, str, sizeof(str)); ck_assert_str_eq(str, "xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U"); r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, str, sizeof(str)); + hdnode_serialize_public(&node, fingerprint, str, sizeof(str)); ck_assert_str_eq(str, "xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB"); r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); @@ -302,17 +325,20 @@ START_TEST(test_bip32_vector_2) ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); // [Chain m/0] + fingerprint = hdnode_fingerprint(&node); r = hdnode_private_ckd(&node, 0); ck_assert_int_eq(r, 1); - ck_assert_int_eq(node.fingerprint, 0xbd16bee5); + ck_assert_int_eq(fingerprint, 0xbd16bee5); ck_assert_mem_eq(node.chain_code, fromhex("f0909affaa7ee7abe5dd4e100598d4dc53cd709d5a5c2cac40e7412f232f7c9c"), 32); ck_assert_mem_eq(node.private_key, fromhex("abe74a98f6c7eabee0428f53798f0ab8aa1bd37873999041703c742f15ac7e1e"), 32); + hdnode_fill_public_key(&node); ck_assert_mem_eq(node.public_key, fromhex("02fc9e5af0ac8d9b3cecfe2a888e2117ba3d089d8585886c9c826b6b22a98d12ea"), 33); - hdnode_serialize_private(&node, str, sizeof(str)); + hdnode_serialize_private(&node, fingerprint, str, sizeof(str)); ck_assert_str_eq(str, "xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt"); r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, str, sizeof(str)); + hdnode_serialize_public(&node, fingerprint, str, sizeof(str)); ck_assert_str_eq(str, "xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH"); r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); @@ -320,17 +346,20 @@ START_TEST(test_bip32_vector_2) ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); // [Chain m/0/2147483647'] + fingerprint = hdnode_fingerprint(&node); r = hdnode_private_ckd_prime(&node, 2147483647); ck_assert_int_eq(r, 1); - ck_assert_int_eq(node.fingerprint, 0x5a61ff8e); + ck_assert_int_eq(fingerprint, 0x5a61ff8e); ck_assert_mem_eq(node.chain_code, fromhex("be17a268474a6bb9c61e1d720cf6215e2a88c5406c4aee7b38547f585c9a37d9"), 32); ck_assert_mem_eq(node.private_key, fromhex("877c779ad9687164e9c2f4f0f4ff0340814392330693ce95a58fe18fd52e6e93"), 32); + hdnode_fill_public_key(&node); ck_assert_mem_eq(node.public_key, fromhex("03c01e7425647bdefa82b12d9bad5e3e6865bee0502694b94ca58b666abc0a5c3b"), 33); - hdnode_serialize_private(&node, str, sizeof(str)); + hdnode_serialize_private(&node, fingerprint, str, sizeof(str)); ck_assert_str_eq(str, "xprv9wSp6B7kry3Vj9m1zSnLvN3xH8RdsPP1Mh7fAaR7aRLcQMKTR2vidYEeEg2mUCTAwCd6vnxVrcjfy2kRgVsFawNzmjuHc2YmYRmagcEPdU9"); r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, str, sizeof(str)); + hdnode_serialize_public(&node, fingerprint, str, sizeof(str)); ck_assert_str_eq(str, "xpub6ASAVgeehLbnwdqV6UKMHVzgqAG8Gr6riv3Fxxpj8ksbH9ebxaEyBLZ85ySDhKiLDBrQSARLq1uNRts8RuJiHjaDMBU4Zn9h8LZNnBC5y4a"); r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); @@ -338,17 +367,20 @@ START_TEST(test_bip32_vector_2) ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); // [Chain m/0/2147483647'/1] + fingerprint = hdnode_fingerprint(&node); r = hdnode_private_ckd(&node, 1); ck_assert_int_eq(r, 1); - ck_assert_int_eq(node.fingerprint, 0xd8ab4937); + ck_assert_int_eq(fingerprint, 0xd8ab4937); ck_assert_mem_eq(node.chain_code, fromhex("f366f48f1ea9f2d1d3fe958c95ca84ea18e4c4ddb9366c336c927eb246fb38cb"), 32); ck_assert_mem_eq(node.private_key, fromhex("704addf544a06e5ee4bea37098463c23613da32020d604506da8c0518e1da4b7"), 32); + hdnode_fill_public_key(&node); ck_assert_mem_eq(node.public_key, fromhex("03a7d1d856deb74c508e05031f9895dab54626251b3806e16b4bd12e781a7df5b9"), 33); - hdnode_serialize_private(&node, str, sizeof(str)); + hdnode_serialize_private(&node, fingerprint, str, sizeof(str)); ck_assert_str_eq(str, "xprv9zFnWC6h2cLgpmSA46vutJzBcfJ8yaJGg8cX1e5StJh45BBciYTRXSd25UEPVuesF9yog62tGAQtHjXajPPdbRCHuWS6T8XA2ECKADdw4Ef"); r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, str, sizeof(str)); + hdnode_serialize_public(&node, fingerprint, str, sizeof(str)); ck_assert_str_eq(str, "xpub6DF8uhdarytz3FWdA8TvFSvvAh8dP3283MY7p2V4SeE2wyWmG5mg5EwVvmdMVCQcoNJxGoWaU9DCWh89LojfZ537wTfunKau47EL2dhHKon"); r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); @@ -356,17 +388,20 @@ START_TEST(test_bip32_vector_2) ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); // [Chain m/0/2147483647'/1/2147483646'] + fingerprint = hdnode_fingerprint(&node); r = hdnode_private_ckd_prime(&node, 2147483646); ck_assert_int_eq(r, 1); - ck_assert_int_eq(node.fingerprint, 0x78412e3a); + ck_assert_int_eq(fingerprint, 0x78412e3a); ck_assert_mem_eq(node.chain_code, fromhex("637807030d55d01f9a0cb3a7839515d796bd07706386a6eddf06cc29a65a0e29"), 32); ck_assert_mem_eq(node.private_key, fromhex("f1c7c871a54a804afe328b4c83a1c33b8e5ff48f5087273f04efa83b247d6a2d"), 32); + hdnode_fill_public_key(&node); ck_assert_mem_eq(node.public_key, fromhex("02d2b36900396c9282fa14628566582f206a5dd0bcc8d5e892611806cafb0301f0"), 33); - hdnode_serialize_private(&node, str, sizeof(str)); + hdnode_serialize_private(&node, fingerprint, str, sizeof(str)); ck_assert_str_eq(str, "xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc"); r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, str, sizeof(str)); + hdnode_serialize_public(&node, fingerprint, str, sizeof(str)); ck_assert_str_eq(str, "xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL"); r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); @@ -374,17 +409,20 @@ START_TEST(test_bip32_vector_2) ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); // [Chain m/0/2147483647'/1/2147483646'/2] + fingerprint = hdnode_fingerprint(&node); r = hdnode_private_ckd(&node, 2); ck_assert_int_eq(r, 1); - ck_assert_int_eq(node.fingerprint, 0x31a507b8); + ck_assert_int_eq(fingerprint, 0x31a507b8); ck_assert_mem_eq(node.chain_code, fromhex("9452b549be8cea3ecb7a84bec10dcfd94afe4d129ebfd3b3cb58eedf394ed271"), 32); ck_assert_mem_eq(node.private_key, fromhex("bb7d39bdb83ecf58f2fd82b6d918341cbef428661ef01ab97c28a4842125ac23"), 32); + hdnode_fill_public_key(&node); ck_assert_mem_eq(node.public_key, fromhex("024d902e1a2fc7a8755ab5b694c575fce742c48d9ff192e63df5193e4c7afe1f9c"), 33); - hdnode_serialize_private(&node, str, sizeof(str)); + hdnode_serialize_private(&node, fingerprint, str, sizeof(str)); ck_assert_str_eq(str, "xprvA2nrNbFZABcdryreWet9Ea4LvTJcGsqrMzxHx98MMrotbir7yrKCEXw7nadnHM8Dq38EGfSh6dqA9QWTyefMLEcBYJUuekgW4BYPJcr9E7j"); r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, str, sizeof(str)); + hdnode_serialize_public(&node, fingerprint, str, sizeof(str)); ck_assert_str_eq(str, "xpub6FnCn6nSzZAw5Tw7cgR9bi15UV96gLZhjDstkXXxvCLsUXBGXPdSnLFbdpq8p9HmGsApME5hQTZ3emM2rnY5agb9rXpVGyy3bdW6EEgAtqt"); r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); @@ -396,11 +434,13 @@ START_TEST(test_bip32_vector_2) // test public derivation // [Chain m/0] + fingerprint = hdnode_fingerprint(&node); r = hdnode_public_ckd(&node, 0); ck_assert_int_eq(r, 1); - ck_assert_int_eq(node.fingerprint, 0xbd16bee5); + ck_assert_int_eq(fingerprint, 0xbd16bee5); ck_assert_mem_eq(node.chain_code, fromhex("f0909affaa7ee7abe5dd4e100598d4dc53cd709d5a5c2cac40e7412f232f7c9c"), 32); ck_assert_mem_eq(node.private_key, fromhex("0000000000000000000000000000000000000000000000000000000000000000"), 32); + hdnode_fill_public_key(&node); ck_assert_mem_eq(node.public_key, fromhex("02fc9e5af0ac8d9b3cecfe2a888e2117ba3d089d8585886c9c826b6b22a98d12ea"), 33); } END_TEST @@ -411,21 +451,22 @@ START_TEST(test_bip32_compare) int i, r; hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, SECP256K1_NAME, &node1); hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, SECP256K1_NAME, &node2); + hdnode_fill_public_key(&node2); for (i = 0; i < 100; i++) { memcpy(&node3, &node1, sizeof(HDNode)); + hdnode_fill_public_key(&node3); r = hdnode_private_ckd(&node1, i); ck_assert_int_eq(r, 1); r = hdnode_public_ckd(&node2, i); ck_assert_int_eq(r, 1); r = hdnode_public_ckd(&node3, i); ck_assert_int_eq(r, 1); ck_assert_int_eq(node1.depth, node2.depth); ck_assert_int_eq(node1.depth, node3.depth); - ck_assert_int_eq(node1.fingerprint, node2.fingerprint); - ck_assert_int_eq(node1.fingerprint, node3.fingerprint); ck_assert_int_eq(node1.child_num, node2.child_num); ck_assert_int_eq(node1.child_num, node3.child_num); ck_assert_mem_eq(node1.chain_code, node2.chain_code, 32); ck_assert_mem_eq(node1.chain_code, node3.chain_code, 32); ck_assert_mem_eq(node2.private_key, fromhex("0000000000000000000000000000000000000000000000000000000000000000"), 32); ck_assert_mem_eq(node3.private_key, fromhex("0000000000000000000000000000000000000000000000000000000000000000"), 32); + hdnode_fill_public_key(&node1); ck_assert_mem_eq(node1.public_key, node2.public_key, 33); ck_assert_mem_eq(node1.public_key, node3.public_key, 33); } @@ -512,18 +553,18 @@ START_TEST(test_bip32_nist_seed) hdnode_from_seed(fromhex("a7305bc8df8d0951f0cb224c0e95d7707cbdf2c6ce7e8d481fec69c7ff5e9446"), 32, NIST256P1_NAME, &node); // [Chain m] - ck_assert_int_eq(node.fingerprint, 0x00000000); ck_assert_mem_eq(node.private_key, fromhex("3b8c18469a4634517d6d0b65448f8e6c62091b45540a1743c5846be55d47d88f"), 32); ck_assert_mem_eq(node.chain_code, fromhex("7762f9729fed06121fd13f326884c82f59aa95c57ac492ce8c9654e60efd130c"), 32); + hdnode_fill_public_key(&node); ck_assert_mem_eq(node.public_key, fromhex("0383619fadcde31063d8c5cb00dbfe1713f3e6fa169d8541a798752a1c1ca0cb20"), 33); // init m hdnode_from_seed(fromhex("aa305bc8df8d0951f0cb29ad4568d7707cbdf2c6ce7e8d481fec69c7ff5e9446"), 32, NIST256P1_NAME, &node); // [Chain m] - ck_assert_int_eq(node.fingerprint, 0x00000000); ck_assert_mem_eq(node.chain_code, fromhex("a81d21f36f987fa0be3b065301bfb6aa9deefbf3dfef6744c37b9a4abc3c68f1"), 32); ck_assert_mem_eq(node.private_key, fromhex("0e49dc46ce1d8c29d9b80a05e40f5d0cd68cbf02ae98572186f5343be18084bf"), 32); + hdnode_fill_public_key(&node); ck_assert_mem_eq(node.public_key, fromhex("03aaa4c89acd9a98935330773d3dae55122f3591bac4a40942681768de8df6ba63"), 33); } END_TEST @@ -531,49 +572,62 @@ END_TEST START_TEST(test_bip32_nist_vector_1) { HDNode node; + uint32_t fingerprint; // init m hdnode_from_seed(fromhex("000102030405060708090a0b0c0d0e0f"), 16, NIST256P1_NAME, &node); // [Chain m] - ck_assert_int_eq(node.fingerprint, 0x00000000); + fingerprint = 0; + ck_assert_int_eq(fingerprint, 0x00000000); ck_assert_mem_eq(node.chain_code, fromhex("beeb672fe4621673f722f38529c07392fecaa61015c80c34f29ce8b41b3cb6ea"), 32); ck_assert_mem_eq(node.private_key, fromhex("612091aaa12e22dd2abef664f8a01a82cae99ad7441b7ef8110424915c268bc2"), 32); + hdnode_fill_public_key(&node); ck_assert_mem_eq(node.public_key, fromhex("0266874dc6ade47b3ecd096745ca09bcd29638dd52c2c12117b11ed3e458cfa9e8"), 33); // [Chain m/0'] + fingerprint = hdnode_fingerprint(&node); hdnode_private_ckd_prime(&node, 0); - ck_assert_int_eq(node.fingerprint, 0xbe6105b5); + ck_assert_int_eq(fingerprint, 0xbe6105b5); ck_assert_mem_eq(node.chain_code, fromhex("3460cea53e6a6bb5fb391eeef3237ffd8724bf0a40e94943c98b83825342ee11"), 32); ck_assert_mem_eq(node.private_key, fromhex("6939694369114c67917a182c59ddb8cafc3004e63ca5d3b84403ba8613debc0c"), 32); + hdnode_fill_public_key(&node); ck_assert_mem_eq(node.public_key, fromhex("0384610f5ecffe8fda089363a41f56a5c7ffc1d81b59a612d0d649b2d22355590c"), 33); // [Chain m/0'/1] + fingerprint = hdnode_fingerprint(&node); hdnode_private_ckd(&node, 1); - ck_assert_int_eq(node.fingerprint, 0x9b02312f); + ck_assert_int_eq(fingerprint, 0x9b02312f); ck_assert_mem_eq(node.chain_code, fromhex("4187afff1aafa8445010097fb99d23aee9f599450c7bd140b6826ac22ba21d0c"), 32); ck_assert_mem_eq(node.private_key, fromhex("284e9d38d07d21e4e281b645089a94f4cf5a5a81369acf151a1c3a57f18b2129"), 32); + hdnode_fill_public_key(&node); ck_assert_mem_eq(node.public_key, fromhex("03526c63f8d0b4bbbf9c80df553fe66742df4676b241dabefdef67733e070f6844"), 33); // [Chain m/0'/1/2'] + fingerprint = hdnode_fingerprint(&node); hdnode_private_ckd_prime(&node, 2); - ck_assert_int_eq(node.fingerprint, 0xb98005c1); + ck_assert_int_eq(fingerprint, 0xb98005c1); ck_assert_mem_eq(node.chain_code, fromhex("98c7514f562e64e74170cc3cf304ee1ce54d6b6da4f880f313e8204c2a185318"), 32); ck_assert_mem_eq(node.private_key, fromhex("694596e8a54f252c960eb771a3c41e7e32496d03b954aeb90f61635b8e092aa7"), 32); + hdnode_fill_public_key(&node); ck_assert_mem_eq(node.public_key, fromhex("0359cf160040778a4b14c5f4d7b76e327ccc8c4a6086dd9451b7482b5a4972dda0"), 33); // [Chain m/0'/1/2'/2] + fingerprint = hdnode_fingerprint(&node); hdnode_private_ckd(&node, 2); - ck_assert_int_eq(node.fingerprint, 0x0e9f3274); + ck_assert_int_eq(fingerprint, 0x0e9f3274); ck_assert_mem_eq(node.chain_code, fromhex("ba96f776a5c3907d7fd48bde5620ee374d4acfd540378476019eab70790c63a0"), 32); ck_assert_mem_eq(node.private_key, fromhex("5996c37fd3dd2679039b23ed6f70b506c6b56b3cb5e424681fb0fa64caf82aaa"), 32); + hdnode_fill_public_key(&node); ck_assert_mem_eq(node.public_key, fromhex("029f871f4cb9e1c97f9f4de9ccd0d4a2f2a171110c61178f84430062230833ff20"), 33); // [Chain m/0'/1/2'/2/1000000000] + fingerprint = hdnode_fingerprint(&node); hdnode_private_ckd(&node, 1000000000); - ck_assert_int_eq(node.fingerprint, 0x8b2b5c4b); + ck_assert_int_eq(fingerprint, 0x8b2b5c4b); ck_assert_mem_eq(node.chain_code, fromhex("b9b7b82d326bb9cb5b5b121066feea4eb93d5241103c9e7a18aad40f1dde8059"), 32); ck_assert_mem_eq(node.private_key, fromhex("21c4f269ef0a5fd1badf47eeacebeeaa3de22eb8e5b0adcd0f27dd99d34d0119"), 32); + hdnode_fill_public_key(&node); ck_assert_mem_eq(node.public_key, fromhex("02216cd26d31147f72427a453c443ed2cde8a1e53c9cc44e5ddf739725413fe3f4"), 33); } END_TEST @@ -581,55 +635,68 @@ END_TEST START_TEST(test_bip32_nist_vector_2) { HDNode node; + uint32_t fingerprint; int r; // init m hdnode_from_seed(fromhex("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), 64, NIST256P1_NAME, &node); // [Chain m] - ck_assert_int_eq(node.fingerprint, 0x00000000); + fingerprint = 0; + ck_assert_int_eq(fingerprint, 0x00000000); ck_assert_mem_eq(node.chain_code, fromhex("96cd4465a9644e31528eda3592aa35eb39a9527769ce1855beafc1b81055e75d"), 32); ck_assert_mem_eq(node.private_key, fromhex("eaa31c2e46ca2962227cf21d73a7ef0ce8b31c756897521eb6c7b39796633357"), 32); + hdnode_fill_public_key(&node); ck_assert_mem_eq(node.public_key, fromhex("02c9e16154474b3ed5b38218bb0463e008f89ee03e62d22fdcc8014beab25b48fa"), 33); // [Chain m/0] + fingerprint = hdnode_fingerprint(&node); r = hdnode_private_ckd(&node, 0); ck_assert_int_eq(r, 1); - ck_assert_int_eq(node.fingerprint, 0x607f628f); + ck_assert_int_eq(fingerprint, 0x607f628f); ck_assert_mem_eq(node.chain_code, fromhex("84e9c258bb8557a40e0d041115b376dd55eda99c0042ce29e81ebe4efed9b86a"), 32); ck_assert_mem_eq(node.private_key, fromhex("d7d065f63a62624888500cdb4f88b6d59c2927fee9e6d0cdff9cad555884df6e"), 32); + hdnode_fill_public_key(&node); ck_assert_mem_eq(node.public_key, fromhex("039b6df4bece7b6c81e2adfeea4bcf5c8c8a6e40ea7ffa3cf6e8494c61a1fc82cc"), 33); // [Chain m/0/2147483647'] + fingerprint = hdnode_fingerprint(&node); r = hdnode_private_ckd_prime(&node, 2147483647); ck_assert_int_eq(r, 1); - ck_assert_int_eq(node.fingerprint, 0x946d2a54); + ck_assert_int_eq(fingerprint, 0x946d2a54); ck_assert_mem_eq(node.chain_code, fromhex("f235b2bc5c04606ca9c30027a84f353acf4e4683edbd11f635d0dcc1cd106ea6"), 32); ck_assert_mem_eq(node.private_key, fromhex("96d2ec9316746a75e7793684ed01e3d51194d81a42a3276858a5b7376d4b94b9"), 32); + hdnode_fill_public_key(&node); ck_assert_mem_eq(node.public_key, fromhex("02f89c5deb1cae4fedc9905f98ae6cbf6cbab120d8cb85d5bd9a91a72f4c068c76"), 33); // [Chain m/0/2147483647'/1] + fingerprint = hdnode_fingerprint(&node); r = hdnode_private_ckd(&node, 1); ck_assert_int_eq(r, 1); - ck_assert_int_eq(node.fingerprint, 0x218182d8); + ck_assert_int_eq(fingerprint, 0x218182d8); ck_assert_mem_eq(node.chain_code, fromhex("7c0b833106235e452eba79d2bdd58d4086e663bc8cc55e9773d2b5eeda313f3b"), 32); ck_assert_mem_eq(node.private_key, fromhex("974f9096ea6873a915910e82b29d7c338542ccde39d2064d1cc228f371542bbc"), 32); + hdnode_fill_public_key(&node); ck_assert_mem_eq(node.public_key, fromhex("03abe0ad54c97c1d654c1852dfdc32d6d3e487e75fa16f0fd6304b9ceae4220c64"), 33); // [Chain m/0/2147483647'/1/2147483646'] + fingerprint = hdnode_fingerprint(&node); r = hdnode_private_ckd_prime(&node, 2147483646); ck_assert_int_eq(r, 1); - ck_assert_int_eq(node.fingerprint, 0x931223e4); + ck_assert_int_eq(fingerprint, 0x931223e4); ck_assert_mem_eq(node.chain_code, fromhex("5794e616eadaf33413aa309318a26ee0fd5163b70466de7a4512fd4b1a5c9e6a"), 32); ck_assert_mem_eq(node.private_key, fromhex("da29649bbfaff095cd43819eda9a7be74236539a29094cd8336b07ed8d4eff63"), 32); + hdnode_fill_public_key(&node); ck_assert_mem_eq(node.public_key, fromhex("03cb8cb067d248691808cd6b5a5a06b48e34ebac4d965cba33e6dc46fe13d9b933"), 33); // [Chain m/0/2147483647'/1/2147483646'/2] + fingerprint = hdnode_fingerprint(&node); r = hdnode_private_ckd(&node, 2); ck_assert_int_eq(r, 1); - ck_assert_int_eq(node.fingerprint, 0x956c4629); + ck_assert_int_eq(fingerprint, 0x956c4629); ck_assert_mem_eq(node.chain_code, fromhex("3bfb29ee8ac4484f09db09c2079b520ea5616df7820f071a20320366fbe226a7"), 32); ck_assert_mem_eq(node.private_key, fromhex("bb0a77ba01cc31d77205d51d08bd313b979a71ef4de9b062f8958297e746bd67"), 32); + hdnode_fill_public_key(&node); ck_assert_mem_eq(node.public_key, fromhex("020ee02e18967237cf62672983b253ee62fa4dd431f8243bfeccdf39dbe181387f"), 33); // init m @@ -637,9 +704,10 @@ START_TEST(test_bip32_nist_vector_2) // test public derivation // [Chain m/0] + fingerprint = hdnode_fingerprint(&node); r = hdnode_public_ckd(&node, 0); ck_assert_int_eq(r, 1); - ck_assert_int_eq(node.fingerprint, 0x607f628f); + ck_assert_int_eq(fingerprint, 0x607f628f); ck_assert_mem_eq(node.chain_code, fromhex("84e9c258bb8557a40e0d041115b376dd55eda99c0042ce29e81ebe4efed9b86a"), 32); ck_assert_mem_eq(node.private_key, fromhex("0000000000000000000000000000000000000000000000000000000000000000"), 32); ck_assert_mem_eq(node.public_key, fromhex("039b6df4bece7b6c81e2adfeea4bcf5c8c8a6e40ea7ffa3cf6e8494c61a1fc82cc"), 33); @@ -652,21 +720,22 @@ START_TEST(test_bip32_nist_compare) int i, r; hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, NIST256P1_NAME, &node1); hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, NIST256P1_NAME, &node2); + hdnode_fill_public_key(&node2); for (i = 0; i < 100; i++) { memcpy(&node3, &node1, sizeof(HDNode)); + hdnode_fill_public_key(&node3); r = hdnode_private_ckd(&node1, i); ck_assert_int_eq(r, 1); r = hdnode_public_ckd(&node2, i); ck_assert_int_eq(r, 1); r = hdnode_public_ckd(&node3, i); ck_assert_int_eq(r, 1); ck_assert_int_eq(node1.depth, node2.depth); ck_assert_int_eq(node1.depth, node3.depth); - ck_assert_int_eq(node1.fingerprint, node2.fingerprint); - ck_assert_int_eq(node1.fingerprint, node3.fingerprint); ck_assert_int_eq(node1.child_num, node2.child_num); ck_assert_int_eq(node1.child_num, node3.child_num); ck_assert_mem_eq(node1.chain_code, node2.chain_code, 32); ck_assert_mem_eq(node1.chain_code, node3.chain_code, 32); ck_assert_mem_eq(node2.private_key, fromhex("0000000000000000000000000000000000000000000000000000000000000000"), 32); ck_assert_mem_eq(node3.private_key, fromhex("0000000000000000000000000000000000000000000000000000000000000000"), 32); + hdnode_fill_public_key(&node1); ck_assert_mem_eq(node1.public_key, node2.public_key, 33); ck_assert_mem_eq(node1.public_key, node3.public_key, 33); } @@ -676,33 +745,39 @@ END_TEST START_TEST(test_bip32_nist_repeat) { HDNode node, node2; + uint32_t fingerprint; int r; // init m hdnode_from_seed(fromhex("000102030405060708090a0b0c0d0e0f"), 16, NIST256P1_NAME, &node); - // [Chain m/28578'] + // [Chain m/28578'] + fingerprint = hdnode_fingerprint(&node); r = hdnode_private_ckd_prime(&node, 28578); ck_assert_int_eq(r, 1); - ck_assert_int_eq(node.fingerprint, 0xbe6105b5); + ck_assert_int_eq(fingerprint, 0xbe6105b5); ck_assert_mem_eq(node.chain_code, fromhex("e94c8ebe30c2250a14713212f6449b20f3329105ea15b652ca5bdfc68f6c65c2"), 32); ck_assert_mem_eq(node.private_key, fromhex("06f0db126f023755d0b8d86d4591718a5210dd8d024e3e14b6159d63f53aa669"), 32); + hdnode_fill_public_key(&node); ck_assert_mem_eq(node.public_key, fromhex("02519b5554a4872e8c9c1c847115363051ec43e93400e030ba3c36b52a3e70a5b7"), 33); memcpy(&node2, &node, sizeof(HDNode)); + fingerprint = hdnode_fingerprint(&node); r = hdnode_private_ckd(&node2, 33941); ck_assert_int_eq(r, 1); - ck_assert_int_eq(node2.fingerprint, 0x3e2b7bc6); + ck_assert_int_eq(fingerprint, 0x3e2b7bc6); ck_assert_mem_eq(node2.chain_code, fromhex("9e87fe95031f14736774cd82f25fd885065cb7c358c1edf813c72af535e83071"), 32); ck_assert_mem_eq(node2.private_key, fromhex("092154eed4af83e078ff9b84322015aefe5769e31270f62c3f66c33888335f3a"), 32); + hdnode_fill_public_key(&node2); ck_assert_mem_eq(node2.public_key, fromhex("0235bfee614c0d5b2cae260000bb1d0d84b270099ad790022c1ae0b2e782efe120"), 33); memcpy(&node2, &node, sizeof(HDNode)); memset(&node2.private_key, 0, 32); r = hdnode_public_ckd(&node2, 33941); ck_assert_int_eq(r, 1); - ck_assert_int_eq(node2.fingerprint, 0x3e2b7bc6); + ck_assert_int_eq(fingerprint, 0x3e2b7bc6); ck_assert_mem_eq(node2.chain_code, fromhex("9e87fe95031f14736774cd82f25fd885065cb7c358c1edf813c72af535e83071"), 32); + hdnode_fill_public_key(&node2); ck_assert_mem_eq(node2.public_key, fromhex("0235bfee614c0d5b2cae260000bb1d0d84b270099ad790022c1ae0b2e782efe120"), 33); } END_TEST @@ -716,45 +791,45 @@ START_TEST(test_bip32_ed25519_vector_1) hdnode_from_seed(fromhex("000102030405060708090a0b0c0d0e0f"), 16, ED25519_NAME, &node); // [Chain m] - ck_assert_int_eq(node.fingerprint, 0x00000000); ck_assert_mem_eq(node.chain_code, fromhex("90046a93de5380a72b5e45010748567d5ea02bbf6522f979e05c0d8d8ca9fffb"), 32); ck_assert_mem_eq(node.private_key, fromhex("2b4be7f19ee27bbf30c667b642d5f4aa69fd169872f8fc3059c08ebae2eb19e7"), 32); - ck_assert_mem_eq(node.public_key, fromhex("00a4b2856bfec510abab89753fac1ac0e1112364e7d250545963f135f2a33188ed"), 33); + hdnode_fill_public_key(&node); + ck_assert_mem_eq(node.public_key, fromhex("01a4b2856bfec510abab89753fac1ac0e1112364e7d250545963f135f2a33188ed"), 33); // [Chain m/0'] hdnode_private_ckd_prime(&node, 0); - ck_assert_int_eq(node.fingerprint, 0xddebc675); ck_assert_mem_eq(node.chain_code, fromhex("8b59aa11380b624e81507a27fedda59fea6d0b779a778918a2fd3590e16e9c69"), 32); ck_assert_mem_eq(node.private_key, fromhex("68e0fe46dfb67e368c75379acec591dad19df3cde26e63b93a8e704f1dade7a3"), 32); - ck_assert_mem_eq(node.public_key, fromhex("008c8a13df77a28f3445213a0f432fde644acaa215fc72dcdf300d5efaa85d350c"), 33); + hdnode_fill_public_key(&node); + ck_assert_mem_eq(node.public_key, fromhex("018c8a13df77a28f3445213a0f432fde644acaa215fc72dcdf300d5efaa85d350c"), 33); // [Chain m/0'/1'] hdnode_private_ckd_prime(&node, 1); - ck_assert_int_eq(node.fingerprint, 0x13dab143); ck_assert_mem_eq(node.chain_code, fromhex("a320425f77d1b5c2505a6b1b27382b37368ee640e3557c315416801243552f14"), 32); ck_assert_mem_eq(node.private_key, fromhex("b1d0bad404bf35da785a64ca1ac54b2617211d2777696fbffaf208f746ae84f2"), 32); - ck_assert_mem_eq(node.public_key, fromhex("001932a5270f335bed617d5b935c80aedb1a35bd9fc1e31acafd5372c30f5c1187"), 33); + hdnode_fill_public_key(&node); + ck_assert_mem_eq(node.public_key, fromhex("011932a5270f335bed617d5b935c80aedb1a35bd9fc1e31acafd5372c30f5c1187"), 33); // [Chain m/0'/1'/2'] hdnode_private_ckd_prime(&node, 2); - ck_assert_int_eq(node.fingerprint, 0xebe4cb29); ck_assert_mem_eq(node.chain_code, fromhex("2e69929e00b5ab250f49c3fb1c12f252de4fed2c1db88387094a0f8c4c9ccd6c"), 32); ck_assert_mem_eq(node.private_key, fromhex("92a5b23c0b8a99e37d07df3fb9966917f5d06e02ddbd909c7e184371463e9fc9"), 32); - ck_assert_mem_eq(node.public_key, fromhex("00ae98736566d30ed0e9d2f4486a64bc95740d89c7db33f52121f8ea8f76ff0fc1"), 33); + hdnode_fill_public_key(&node); + ck_assert_mem_eq(node.public_key, fromhex("01ae98736566d30ed0e9d2f4486a64bc95740d89c7db33f52121f8ea8f76ff0fc1"), 33); // [Chain m/0'/1'/2'/2'] hdnode_private_ckd_prime(&node, 2); - ck_assert_int_eq(node.fingerprint, 0x316ec1c6); ck_assert_mem_eq(node.chain_code, fromhex("8f6d87f93d750e0efccda017d662a1b31a266e4a6f5993b15f5c1f07f74dd5cc"), 32); ck_assert_mem_eq(node.private_key, fromhex("30d1dc7e5fc04c31219ab25a27ae00b50f6fd66622f6e9c913253d6511d1e662"), 32); - ck_assert_mem_eq(node.public_key, fromhex("008abae2d66361c879b900d204ad2cc4984fa2aa344dd7ddc46007329ac76c429c"), 33); + hdnode_fill_public_key(&node); + ck_assert_mem_eq(node.public_key, fromhex("018abae2d66361c879b900d204ad2cc4984fa2aa344dd7ddc46007329ac76c429c"), 33); // [Chain m/0'/1'/2'/2'/1000000000'] hdnode_private_ckd_prime(&node, 1000000000); - ck_assert_int_eq(node.fingerprint, 0xd6322ccd); ck_assert_mem_eq(node.chain_code, fromhex("68789923a0cac2cd5a29172a475fe9e0fb14cd6adb5ad98a3fa70333e7afa230"), 32); ck_assert_mem_eq(node.private_key, fromhex("8f94d394a8e8fd6b1bc2f3f49f5c47e385281d5c17e65324b0f62483e37e8793"), 32); - ck_assert_mem_eq(node.public_key, fromhex("003c24da049451555d51a7014a37337aa4e12d41e485abccfa46b47dfb2af54b7a"), 33); + hdnode_fill_public_key(&node); + ck_assert_mem_eq(node.public_key, fromhex("013c24da049451555d51a7014a37337aa4e12d41e485abccfa46b47dfb2af54b7a"), 33); } END_TEST @@ -768,50 +843,50 @@ START_TEST(test_bip32_ed25519_vector_2) hdnode_from_seed(fromhex("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), 64, ED25519_NAME, &node); // [Chain m] - ck_assert_int_eq(node.fingerprint, 0x00000000); ck_assert_mem_eq(node.chain_code, fromhex("ef70a74db9c3a5af931b5fe73ed8e1a53464133654fd55e7a66f8570b8e33c3b"), 32); ck_assert_mem_eq(node.private_key, fromhex("171cb88b1b3c1db25add599712e36245d75bc65a1a5c9e18d76f9f2b1eab4012"), 32); - ck_assert_mem_eq(node.public_key, fromhex("008fe9693f8fa62a4305a140b9764c5ee01e455963744fe18204b4fb948249308a"), 33); + hdnode_fill_public_key(&node); + ck_assert_mem_eq(node.public_key, fromhex("018fe9693f8fa62a4305a140b9764c5ee01e455963744fe18204b4fb948249308a"), 33); // [Chain m/0'] r = hdnode_private_ckd_prime(&node, 0); ck_assert_int_eq(r, 1); - ck_assert_int_eq(node.fingerprint, 0x31981b50); ck_assert_mem_eq(node.chain_code, fromhex("0b78a3226f915c082bf118f83618a618ab6dec793752624cbeb622acb562862d"), 32); ck_assert_mem_eq(node.private_key, fromhex("1559eb2bbec5790b0c65d8693e4d0875b1747f4970ae8b650486ed7470845635"), 32); - ck_assert_mem_eq(node.public_key, fromhex("0086fab68dcb57aa196c77c5f264f215a112c22a912c10d123b0d03c3c28ef1037"), 33); + hdnode_fill_public_key(&node); + ck_assert_mem_eq(node.public_key, fromhex("0186fab68dcb57aa196c77c5f264f215a112c22a912c10d123b0d03c3c28ef1037"), 33); // [Chain m/0'/2147483647'] r = hdnode_private_ckd_prime(&node, 2147483647); ck_assert_int_eq(r, 1); - ck_assert_int_eq(node.fingerprint, 0x1e9411b1); ck_assert_mem_eq(node.chain_code, fromhex("138f0b2551bcafeca6ff2aa88ba8ed0ed8de070841f0c4ef0165df8181eaad7f"), 32); ck_assert_mem_eq(node.private_key, fromhex("ea4f5bfe8694d8bb74b7b59404632fd5968b774ed545e810de9c32a4fb4192f4"), 32); - ck_assert_mem_eq(node.public_key, fromhex("005ba3b9ac6e90e83effcd25ac4e58a1365a9e35a3d3ae5eb07b9e4d90bcf7506d"), 33); + hdnode_fill_public_key(&node); + ck_assert_mem_eq(node.public_key, fromhex("015ba3b9ac6e90e83effcd25ac4e58a1365a9e35a3d3ae5eb07b9e4d90bcf7506d"), 33); // [Chain m/0'/2147483647'/1'] r = hdnode_private_ckd_prime(&node, 1); ck_assert_int_eq(r, 1); - ck_assert_int_eq(node.fingerprint, 0xfcadf38c); ck_assert_mem_eq(node.chain_code, fromhex("73bd9fff1cfbde33a1b846c27085f711c0fe2d66fd32e139d3ebc28e5a4a6b90"), 32); ck_assert_mem_eq(node.private_key, fromhex("3757c7577170179c7868353ada796c839135b3d30554bbb74a4b1e4a5a58505c"), 32); - ck_assert_mem_eq(node.public_key, fromhex("002e66aa57069c86cc18249aecf5cb5a9cebbfd6fadeab056254763874a9352b45"), 33); + hdnode_fill_public_key(&node); + ck_assert_mem_eq(node.public_key, fromhex("012e66aa57069c86cc18249aecf5cb5a9cebbfd6fadeab056254763874a9352b45"), 33); // [Chain m/0'/2147483647'/1'/2147483646'] r = hdnode_private_ckd_prime(&node, 2147483646); ck_assert_int_eq(r, 1); - ck_assert_int_eq(node.fingerprint, 0xaca70953); ck_assert_mem_eq(node.chain_code, fromhex("0902fe8a29f9140480a00ef244bd183e8a13288e4412d8389d140aac1794825a"), 32); ck_assert_mem_eq(node.private_key, fromhex("5837736c89570de861ebc173b1086da4f505d4adb387c6a1b1342d5e4ac9ec72"), 32); - ck_assert_mem_eq(node.public_key, fromhex("00e33c0f7d81d843c572275f287498e8d408654fdf0d1e065b84e2e6f157aab09b"), 33); + hdnode_fill_public_key(&node); + ck_assert_mem_eq(node.public_key, fromhex("01e33c0f7d81d843c572275f287498e8d408654fdf0d1e065b84e2e6f157aab09b"), 33); // [Chain m/0'/2147483647'/1'/2147483646'/2'] r = hdnode_private_ckd_prime(&node, 2); ck_assert_int_eq(r, 1); - ck_assert_int_eq(node.fingerprint, 0x422c654b); ck_assert_mem_eq(node.chain_code, fromhex("5d70af781f3a37b829f0d060924d5e960bdc02e85423494afc0b1a41bbe196d4"), 32); ck_assert_mem_eq(node.private_key, fromhex("551d333177df541ad876a60ea71f00447931c0a9da16f227c11ea080d7391b8d"), 32); - ck_assert_mem_eq(node.public_key, fromhex("0047150c75db263559a70d5778bf36abbab30fb061ad69f69ece61a72b0cfa4fc0"), 33); + hdnode_fill_public_key(&node); + ck_assert_mem_eq(node.public_key, fromhex("0147150c75db263559a70d5778bf36abbab30fb061ad69f69ece61a72b0cfa4fc0"), 33); } END_TEST From d61a151900a08022f2243808fd28b8b076979d3e Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 28 Jun 2016 20:05:01 +0200 Subject: [PATCH 288/627] add bn_divmod1000 including unit test --- bignum.c | 24 ++++++++++++++++++++++++ bignum.h | 2 ++ tests.c | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+) diff --git a/bignum.c b/bignum.c index 6de4a3c22..20e3718c3 100644 --- a/bignum.c +++ b/bignum.c @@ -804,6 +804,30 @@ void bn_divmod58(bignum256 *a, uint32_t *r) *r = rem; } +// a / 1000 = a (+r) +void bn_divmod1000(bignum256 *a, uint32_t *r) +{ + int i; + uint32_t rem, tmp; + rem = a->val[8] % 1000; + a->val[8] /= 1000; + for (i = 7; i >= 0; i--) { + // invariants: + // rem = old(a) >> 30(i+1) % 1000 + // a[i+1..8] = old(a[i+1..8])/1000 + // a[0..i] = old(a[0..i]) + // 2^30 == 1073741*1000 + 824 + tmp = rem * 824 + a->val[i]; + // set a[i] = (rem * 2^30 + a[i])/1000 + // = rem * 1073741 + (rem * 824 + a[i])/1000 + a->val[i] = rem * 1073741 + (tmp / 1000); + // set rem = (rem * 2^30 + a[i]) mod 1000 + // = (rem * 824 + a[i]) mod 1000 + rem = tmp % 1000; + } + *r = rem; +} + #if USE_BN_PRINT void bn_print(const bignum256 *a) { diff --git a/bignum.h b/bignum.h index 8778aec7b..4b51c5d42 100644 --- a/bignum.h +++ b/bignum.h @@ -87,6 +87,8 @@ void bn_subtract(const bignum256 *a, const bignum256 *b, bignum256 *res); void bn_divmod58(bignum256 *a, uint32_t *r); +void bn_divmod1000(bignum256 *a, uint32_t *r); + #if USE_BN_PRINT void bn_print(const bignum256 *a); void bn_print_raw(const bignum256 *a); diff --git a/tests.c b/tests.c index 051f52b9b..d0148c90b 100644 --- a/tests.c +++ b/tests.c @@ -161,6 +161,35 @@ START_TEST(test_base58) } END_TEST +START_TEST(test_bignum_divmod) +{ + uint32_t r; + int i; + + bignum256 a = { { 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0xffff} }; + uint32_t ar[] = { 15, 14, 55, 29, 44, 24, 53, 49, 18, 55, 2, 28, 5, 4, 12, 43, 18, 37, 28, 14, 30, 46, 12, 11, 17, 10, 10, 13, 24, 45, 4, 33, 44, 42, 2, 46, 34, 43, 45, 28, 21, 18, 13, 17 }; + + i = 0; + while (!bn_is_zero(&a) && i < 44) { + bn_divmod58(&a, &r); + ck_assert_int_eq(r, ar[i]); + i++; + } + ck_assert_int_eq(i, 44); + + bignum256 b = { { 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0xffff} }; + uint32_t br[] = { 935, 639, 129, 913, 7, 584, 457, 39, 564, 640, 665, 984, 269, 853, 907, 687, 8, 985, 570, 423, 195, 316, 237, 89, 792, 115 }; + + i = 0; + while (!bn_is_zero(&b) && i < 26) { + bn_divmod1000(&b, &r); + ck_assert_int_eq(r, br[i]); + i++; + } + ck_assert_int_eq(i, 26); + +} +END_TEST // test vector 1 from https://en.bitcoin.it/wiki/BIP_0032_TestVectors START_TEST(test_bip32_vector_1) @@ -1981,6 +2010,10 @@ Suite *test_suite(void) tcase_add_test(tc, test_base58); suite_add_tcase(s, tc); + tc = tcase_create("bignum_divmod"); + tcase_add_test(tc, test_bignum_divmod); + suite_add_tcase(s, tc); + tc = tcase_create("bip32"); tcase_add_test(tc, test_bip32_vector_1); tcase_add_test(tc, test_bip32_vector_2); From b5f89bb47830189036bfce04ca22adafc852e453 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 4 Jul 2016 17:29:48 +0200 Subject: [PATCH 289/627] fpr -> fingerprint --- bip32.c | 12 ++++++------ bip32.h | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/bip32.c b/bip32.c index 40656906f..f6f4de653 100644 --- a/bip32.c +++ b/bip32.c @@ -414,12 +414,12 @@ int hdnode_sign_digest(HDNode *node, const uint8_t *digest, uint8_t *sig, uint8_ } -void hdnode_serialize(const HDNode *node, uint32_t fpr, uint32_t version, char use_public, char *str, int strsize) +void hdnode_serialize(const HDNode *node, uint32_t fingerprint, uint32_t version, char use_public, char *str, int strsize) { uint8_t node_data[78]; write_be(node_data, version); node_data[4] = node->depth; - write_be(node_data + 5, fpr); + write_be(node_data + 5, fingerprint); write_be(node_data + 9, node->child_num); memcpy(node_data + 13, node->chain_code, 32); if (use_public) { @@ -433,14 +433,14 @@ void hdnode_serialize(const HDNode *node, uint32_t fpr, uint32_t version, char u MEMSET_BZERO(node_data, sizeof(node_data)); } -void hdnode_serialize_public(const HDNode *node, uint32_t fpr, char *str, int strsize) +void hdnode_serialize_public(const HDNode *node, uint32_t fingerprint, char *str, int strsize) { - hdnode_serialize(node, fpr, 0x0488B21E, 1, str, strsize); + hdnode_serialize(node, fingerprint, 0x0488B21E, 1, str, strsize); } -void hdnode_serialize_private(const HDNode *node, uint32_t fpr, char *str, int strsize) +void hdnode_serialize_private(const HDNode *node, uint32_t fingerprint, char *str, int strsize) { - hdnode_serialize(node, fpr, 0x0488ADE4, 0, str, strsize); + hdnode_serialize(node, fingerprint, 0x0488ADE4, 0, str, strsize); } // check for validity of curve point in case of public data not performed diff --git a/bip32.h b/bip32.h index 02f92334e..e674b5d3b 100644 --- a/bip32.h +++ b/bip32.h @@ -70,14 +70,14 @@ void hdnode_fill_public_key(HDNode *node); int hdnode_sign(HDNode *node, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby); int hdnode_sign_digest(HDNode *node, const uint8_t *digest, uint8_t *sig, uint8_t *pby); -void hdnode_serialize_public(const HDNode *node, uint32_t fpr, char *str, int strsize); +void hdnode_serialize_public(const HDNode *node, uint32_t fingerprint, char *str, int strsize); -void hdnode_serialize_private(const HDNode *node, uint32_t fpr, char *str, int strsize); +void hdnode_serialize_private(const HDNode *node, uint32_t fingerprint, char *str, int strsize); int hdnode_deserialize(const char *str, HDNode *node); // Private -void hdnode_serialize(const HDNode *node, uint32_t fpr, uint32_t version, char use_public, char *str, int strsize); +void hdnode_serialize(const HDNode *node, uint32_t fingerprint, uint32_t version, char use_public, char *str, int strsize); void hdnode_get_address_raw(HDNode *node, uint8_t version, uint8_t *addr_raw); From dc167592d547ff067e66376eaba90feee8622ff2 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 4 Jul 2016 17:32:02 +0200 Subject: [PATCH 290/627] increase timeout in test_codepoints --- tests.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tests.c b/tests.c index a0d1c447e..8d653eb38 100644 --- a/tests.c +++ b/tests.c @@ -2163,6 +2163,7 @@ Suite *test_suite(void) tc = tcase_create("codepoints"); tcase_add_test(tc, test_codepoints); + tcase_set_timeout(tc, 8); suite_add_tcase(s, tc); tc = tcase_create("mult_border_cases"); From 9a8df5a4bb5de3b1ebaa28591c2ae0a5bb39348e Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 4 Jul 2016 17:37:05 +0200 Subject: [PATCH 291/627] add __dummy field to HDNode where fingerprint used to be (in order not to binary compatibility) --- bip32.h | 1 + 1 file changed, 1 insertion(+) diff --git a/bip32.h b/bip32.h index e674b5d3b..b1dbc2b7a 100644 --- a/bip32.h +++ b/bip32.h @@ -36,6 +36,7 @@ typedef struct { typedef struct { uint32_t depth; + uint32_t __dummy; uint32_t child_num; uint8_t chain_code[32]; uint8_t private_key[32]; From c80f0fbc52ce0995aac027079c77e59f128726c6 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 4 Jul 2016 18:19:58 +0200 Subject: [PATCH 292/627] remove cpython wrapper - it's broken and nobody uses it --- .gitignore | 5 ----- MANIFEST.in | 2 -- TrezorCrypto.pyx | 40 ---------------------------------------- c.pxd | 22 ---------------------- test.py | 10 ---------- 5 files changed, 79 deletions(-) delete mode 100644 MANIFEST.in delete mode 100644 TrezorCrypto.pyx delete mode 100644 c.pxd delete mode 100755 test.py diff --git a/.gitignore b/.gitignore index f1da71bbc..c4255cff7 100644 --- a/.gitignore +++ b/.gitignore @@ -4,11 +4,6 @@ test-openssl test_speed tests -build-*/ -build/ -dist/ -MANIFEST -TrezorCrypto.c *.os *.so *.pyc diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index 637fe68f5..000000000 --- a/MANIFEST.in +++ /dev/null @@ -1,2 +0,0 @@ -include *.h -include *.pyx diff --git a/TrezorCrypto.pyx b/TrezorCrypto.pyx deleted file mode 100644 index 71490f8f9..000000000 --- a/TrezorCrypto.pyx +++ /dev/null @@ -1,40 +0,0 @@ -cimport c -cimport cython - -cdef class HDNode: - - cdef c.HDNode node - - def __init__(self, str serialized = None, HDNode copyfrom = None): - if copyfrom is not None: - self.node = copyfrom.node - elif serialized is not None: - if c.hdnode_deserialize(serialized, cython.address(self.node)) != 0: - raise Exception('Invalid xpub/xprv provided') - else: - raise Exception('Need to provide serialized or node parameter') - - def xpub(self): - cdef char[120] string - c.hdnode_serialize_public(cython.address(self.node), string, 120) - return str(string) - - def xprv(self): - cdef char[120] string - c.hdnode_serialize_private(cython.address(self.node), string, 120) - return str(string) - - def address(self): - cdef char[40] string - c.ecdsa_get_address(self.node.public_key, 0, string, 40) - return str(string) - - def public_ckd(self, int i): - x = HDNode(copyfrom=self) - c.hdnode_public_ckd(cython.address(x.node), i) - return x - - def private_ckd(self, unsigned int i): - x = HDNode(copyfrom=self) - c.hdnode_private_ckd(cython.address(x.node), i) - return x diff --git a/c.pxd b/c.pxd deleted file mode 100644 index dc28f9c65..000000000 --- a/c.pxd +++ /dev/null @@ -1,22 +0,0 @@ -from libc.stdint cimport uint32_t, uint8_t - -cdef extern from "bip32.h": - - ctypedef struct HDNode: - uint8_t public_key[33] - - int hdnode_from_seed(const uint8_t *seed, int seed_len, const char *curve, HDNode *out) - - int hdnode_private_ckd(HDNode *inout, uint32_t i) - - int hdnode_public_ckd(HDNode *inout, uint32_t i) - - void hdnode_serialize_public(const HDNode *node, char *str, int strsize) - - void hdnode_serialize_private(const HDNode *node, char *str, int strsize) - - int hdnode_deserialize(const char *str, HDNode *node) - -cdef extern from "ecdsa.h": - - void ecdsa_get_address(const uint8_t *pub_key, uint8_t version, char *addr, int addrsize) diff --git a/test.py b/test.py deleted file mode 100755 index 088616d22..000000000 --- a/test.py +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/python -from TrezorCrypto import HDNode - -x = HDNode('xpub6BcjTvRCYD4VvFQ8whztSXhbNyhS56eTd5P3g9Zvd3zPEeUeL5CUqBYX8NSd1b6Thitr8bZcSnesmXZH7KerMcc4tUkenBShYCtQ1L8ebVe') - -y = x.public_ckd(0) - -for i in range(1000): - z = y.public_ckd(i) - print i, z.address() From 4912ac550c7aba91ce46e6e920dc3083107a94e4 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 4 Jul 2016 18:49:25 +0200 Subject: [PATCH 293/627] Revert "add __dummy field to HDNode where fingerprint used to be (in order not to binary compatibility)" This reverts commit 9a8df5a4bb5de3b1ebaa28591c2ae0a5bb39348e. --- bip32.h | 1 - 1 file changed, 1 deletion(-) diff --git a/bip32.h b/bip32.h index b1dbc2b7a..e674b5d3b 100644 --- a/bip32.h +++ b/bip32.h @@ -36,7 +36,6 @@ typedef struct { typedef struct { uint32_t depth; - uint32_t __dummy; uint32_t child_num; uint8_t chain_code[32]; uint8_t private_key[32]; From 32bda8d1d98b0d8ac42406a51aa683a4ad363ccf Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Tue, 12 Jul 2016 13:43:13 +0200 Subject: [PATCH 294/627] Faster PBKDF2 by reusing intermediate results. The old implementation needed 6 sha transformations per iterations: - 2 for computing sha512 of seed, - 2 for computing digests of ipads/opads, - 2 for computing digests of intermediate hashes. The first 4 transformations are the same in every iteration so we cache them. A new function hmac_sha512_prepare computes these digests. We made sha512_Transform visible in pbkdf2 and prevent unneccessary big/little endian conversions back and forth. --- hmac.c | 56 ++++++++ hmac.h | 2 + pbkdf2.c | 80 ++++++++--- pbkdf2.h | 16 +-- sha2.c | 395 ++++++++++++++++++++++++------------------------------- sha2.h | 35 ++++- 6 files changed, 336 insertions(+), 248 deletions(-) diff --git a/hmac.c b/hmac.c index f334ada7e..c866687e2 100644 --- a/hmac.c +++ b/hmac.c @@ -69,6 +69,34 @@ void hmac_sha256(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, hmac_sha256_Final(&hctx, hmac); } +void hmac_sha256_prepare(const uint8_t *key, const uint32_t keylen, uint32_t *opad_digest, uint32_t *ipad_digest) +{ + int i; + uint32_t buf[SHA256_BLOCK_LENGTH/sizeof(uint32_t)]; + uint32_t o_key_pad[16], i_key_pad[16]; + + memset(buf, 0, SHA256_BLOCK_LENGTH); + if (keylen > SHA256_BLOCK_LENGTH) { + sha256_Raw(key, keylen, (uint8_t*) buf); + } else { + memcpy(buf, key, keylen); + } + + for (i = 0; i < 16; i++) { + uint32_t data; +#if BYTE_ORDER == LITTLE_ENDIAN + REVERSE32(buf[i], data); +#else + data = buf[i]; +#endif + o_key_pad[i] = data ^ 0x5c5c5c5c; + i_key_pad[i] = data ^ 0x36363636; + } + + sha256_Transform(sha256_initial_hash_value, o_key_pad, opad_digest); + sha256_Transform(sha256_initial_hash_value, i_key_pad, ipad_digest); +} + void hmac_sha512_Init(HMAC_SHA512_CTX *hctx, const uint8_t *key, const uint32_t keylen) { uint8_t i_key_pad[SHA512_BLOCK_LENGTH]; @@ -111,3 +139,31 @@ void hmac_sha512(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, hmac_sha512_Update(&hctx, msg, msglen); hmac_sha512_Final(&hctx, hmac); } + +void hmac_sha512_prepare(const uint8_t *key, const uint32_t keylen, uint64_t *opad_digest, uint64_t *ipad_digest) +{ + int i; + uint64_t buf[SHA512_BLOCK_LENGTH/sizeof(uint64_t)]; + uint64_t o_key_pad[16], i_key_pad[16]; + + memset(buf, 0, SHA512_BLOCK_LENGTH); + if (keylen > SHA512_BLOCK_LENGTH) { + sha512_Raw(key, keylen, (uint8_t*)buf); + } else { + memcpy(buf, key, keylen); + } + + for (i = 0; i < 16; i++) { + uint64_t data; +#if BYTE_ORDER == LITTLE_ENDIAN + REVERSE64(buf[i], data); +#else + data = buf[i]; +#endif + o_key_pad[i] = data ^ 0x5c5c5c5c5c5c5c5c; + i_key_pad[i] = data ^ 0x3636363636363636; + } + + sha512_Transform(sha512_initial_hash_value, o_key_pad, opad_digest); + sha512_Transform(sha512_initial_hash_value, i_key_pad, ipad_digest); +} diff --git a/hmac.h b/hmac.h index 1374dec4b..3cfc0cd0f 100644 --- a/hmac.h +++ b/hmac.h @@ -41,10 +41,12 @@ void hmac_sha256_Init(HMAC_SHA256_CTX *hctx, const uint8_t *key, const uint32_t void hmac_sha256_Update(HMAC_SHA256_CTX *hctx, const uint8_t *msg, const uint32_t msglen); void hmac_sha256_Final(HMAC_SHA256_CTX *hctx, uint8_t *hmac); void hmac_sha256(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, const uint32_t msglen, uint8_t *hmac); +void hmac_sha256_prepare(const uint8_t *key, const uint32_t keylen, uint32_t *opad_digest, uint32_t *ipad_digest); void hmac_sha512_Init(HMAC_SHA512_CTX *hctx, const uint8_t *key, const uint32_t keylen); void hmac_sha512_Update(HMAC_SHA512_CTX *hctx, const uint8_t *msg, const uint32_t msglen); void hmac_sha512_Final(HMAC_SHA512_CTX *hctx, uint8_t *hmac); void hmac_sha512(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, const uint32_t msglen, uint8_t *hmac); +void hmac_sha512_prepare(const uint8_t *key, const uint32_t keylen, uint64_t *opad_digest, uint64_t *ipad_digest); #endif diff --git a/pbkdf2.c b/pbkdf2.c index 86398aa64..db3e997d5 100644 --- a/pbkdf2.c +++ b/pbkdf2.c @@ -24,26 +24,43 @@ #include #include "pbkdf2.h" #include "hmac.h" +#include "sha2.h" #include "macros.h" void pbkdf2_hmac_sha256_Init(PBKDF2_HMAC_SHA256_CTX *pctx, const uint8_t *pass, int passlen, const uint8_t *salt, int saltlen) { - HMAC_SHA256_CTX hctx; - hmac_sha256_Init(&hctx, pass, passlen); - hmac_sha256_Update(&hctx, salt, saltlen); - hmac_sha256_Update(&hctx, (const uint8_t *)"\x00\x00\x00\x01", 4); - hmac_sha256_Final(&hctx, pctx->g); + SHA256_CTX ctx; + uint32_t blocknr = 1; +#if BYTE_ORDER == LITTLE_ENDIAN + REVERSE32(blocknr, blocknr); +#endif + + hmac_sha256_prepare(pass, passlen, pctx->odig, pctx->idig); + memset(pctx->g, 0, sizeof(pctx->g)); + pctx->g[8] = 0x80000000; + pctx->g[15] = (SHA256_BLOCK_LENGTH + SHA256_DIGEST_LENGTH) * 8; + + memcpy (ctx.state, pctx->idig, sizeof(pctx->idig)); + ctx.bitcount = SHA256_BLOCK_LENGTH * 8; + sha256_Update(&ctx, salt, saltlen); + sha256_Update(&ctx, (uint8_t*)&blocknr, sizeof(blocknr)); + sha256_Final(&ctx, (uint8_t*)pctx->g); +#if BYTE_ORDER == LITTLE_ENDIAN + for (uint32_t k = 0; k < SHA256_DIGEST_LENGTH / sizeof(uint32_t); k++) { + REVERSE32(pctx->g[k], pctx->g[k]); + } +#endif + sha256_Transform(pctx->odig, pctx->g, pctx->g); memcpy(pctx->f, pctx->g, SHA256_DIGEST_LENGTH); - pctx->pass = pass; - pctx->passlen = passlen; pctx->first = 1; } void pbkdf2_hmac_sha256_Update(PBKDF2_HMAC_SHA256_CTX *pctx, uint32_t iterations) { for (uint32_t i = pctx->first; i < iterations; i++) { - hmac_sha256(pctx->pass, pctx->passlen, pctx->g, SHA256_DIGEST_LENGTH, pctx->g); - for (uint32_t j = 0; j < SHA256_DIGEST_LENGTH; j++) { + sha256_Transform(pctx->idig, pctx->g, pctx->g); + sha256_Transform(pctx->odig, pctx->g, pctx->g); + for (uint32_t j = 0; j < SHA256_DIGEST_LENGTH/sizeof(uint32_t); j++) { pctx->f[j] ^= pctx->g[j]; } } @@ -52,6 +69,11 @@ void pbkdf2_hmac_sha256_Update(PBKDF2_HMAC_SHA256_CTX *pctx, uint32_t iterations void pbkdf2_hmac_sha256_Final(PBKDF2_HMAC_SHA256_CTX *pctx, uint8_t *key) { +#if BYTE_ORDER == LITTLE_ENDIAN + for (uint32_t k = 0; k < SHA256_DIGEST_LENGTH/sizeof(uint32_t); k++) { + REVERSE32(pctx->f[k], pctx->f[k]); + } +#endif memcpy(key, pctx->f, SHA256_DIGEST_LENGTH); MEMSET_BZERO(pctx, sizeof(PBKDF2_HMAC_SHA256_CTX)); } @@ -66,22 +88,39 @@ void pbkdf2_hmac_sha256(const uint8_t *pass, int passlen, const uint8_t *salt, i void pbkdf2_hmac_sha512_Init(PBKDF2_HMAC_SHA512_CTX *pctx, const uint8_t *pass, int passlen, const uint8_t *salt, int saltlen) { - HMAC_SHA512_CTX hctx; - hmac_sha512_Init(&hctx, pass, passlen); - hmac_sha512_Update(&hctx, salt, saltlen); - hmac_sha512_Update(&hctx, (const uint8_t *)"\x00\x00\x00\x01", 4); - hmac_sha512_Final(&hctx, pctx->g); + SHA512_CTX ctx; + uint32_t blocknr = 1; +#if BYTE_ORDER == LITTLE_ENDIAN + REVERSE32(blocknr, blocknr); +#endif + + hmac_sha512_prepare(pass, passlen, pctx->odig, pctx->idig); + memset(pctx->g, 0, sizeof(pctx->g)); + pctx->g[8] = 0x8000000000000000; + pctx->g[15] = (SHA512_BLOCK_LENGTH + SHA512_DIGEST_LENGTH) * 8; + + memcpy (ctx.state, pctx->idig, sizeof(pctx->idig)); + ctx.bitcount[0] = SHA512_BLOCK_LENGTH * 8; + ctx.bitcount[1] = 0; + sha512_Update(&ctx, salt, saltlen); + sha512_Update(&ctx, (uint8_t*)&blocknr, sizeof(blocknr)); + sha512_Final(&ctx, (uint8_t*)pctx->g); +#if BYTE_ORDER == LITTLE_ENDIAN + for (uint32_t k = 0; k < SHA512_DIGEST_LENGTH / sizeof(uint64_t); k++) { + REVERSE64(pctx->g[k], pctx->g[k]); + } +#endif + sha512_Transform(pctx->odig, pctx->g, pctx->g); memcpy(pctx->f, pctx->g, SHA512_DIGEST_LENGTH); - pctx->pass = pass; - pctx->passlen = passlen; pctx->first = 1; } void pbkdf2_hmac_sha512_Update(PBKDF2_HMAC_SHA512_CTX *pctx, uint32_t iterations) { for (uint32_t i = pctx->first; i < iterations; i++) { - hmac_sha512(pctx->pass, pctx->passlen, pctx->g, SHA512_DIGEST_LENGTH, pctx->g); - for (uint32_t j = 0; j < SHA512_DIGEST_LENGTH; j++) { + sha512_Transform(pctx->idig, pctx->g, pctx->g); + sha512_Transform(pctx->odig, pctx->g, pctx->g); + for (uint32_t j = 0; j < SHA512_DIGEST_LENGTH / sizeof(uint64_t); j++) { pctx->f[j] ^= pctx->g[j]; } } @@ -90,6 +129,11 @@ void pbkdf2_hmac_sha512_Update(PBKDF2_HMAC_SHA512_CTX *pctx, uint32_t iterations void pbkdf2_hmac_sha512_Final(PBKDF2_HMAC_SHA512_CTX *pctx, uint8_t *key) { +#if BYTE_ORDER == LITTLE_ENDIAN + for (uint32_t k = 0; k < SHA512_DIGEST_LENGTH/sizeof(uint64_t); k++) { + REVERSE64(pctx->f[k], pctx->f[k]); + } +#endif memcpy(key, pctx->f, SHA512_DIGEST_LENGTH); MEMSET_BZERO(pctx, sizeof(PBKDF2_HMAC_SHA512_CTX)); } diff --git a/pbkdf2.h b/pbkdf2.h index 2a4c26ec8..e77f29187 100644 --- a/pbkdf2.h +++ b/pbkdf2.h @@ -28,18 +28,18 @@ #include "sha2.h" typedef struct _PBKDF2_HMAC_SHA256_CTX { - uint8_t f[SHA256_DIGEST_LENGTH]; - uint8_t g[SHA256_DIGEST_LENGTH]; - const uint8_t *pass; - int passlen; + uint32_t odig[SHA256_DIGEST_LENGTH / sizeof(uint32_t)]; + uint32_t idig[SHA256_DIGEST_LENGTH / sizeof(uint32_t)]; + uint32_t f[SHA256_DIGEST_LENGTH / sizeof(uint32_t)]; + uint32_t g[SHA256_BLOCK_LENGTH / sizeof(uint32_t)]; char first; } PBKDF2_HMAC_SHA256_CTX; typedef struct _PBKDF2_HMAC_SHA512_CTX { - uint8_t f[SHA512_DIGEST_LENGTH]; - uint8_t g[SHA512_DIGEST_LENGTH]; - const uint8_t *pass; - int passlen; + uint64_t odig[SHA512_DIGEST_LENGTH / sizeof(uint64_t)]; + uint64_t idig[SHA512_DIGEST_LENGTH / sizeof(uint64_t)]; + uint64_t f[SHA512_DIGEST_LENGTH / sizeof(uint64_t)]; + uint64_t g[SHA512_BLOCK_LENGTH / sizeof(uint64_t)]; char first; } PBKDF2_HMAC_SHA512_CTX; diff --git a/sha2.c b/sha2.c index 5c3c64fee..b3bf14386 100644 --- a/sha2.c +++ b/sha2.c @@ -82,15 +82,6 @@ * made). */ -#ifndef LITTLE_ENDIAN -#define LITTLE_ENDIAN 1234 -#define BIG_ENDIAN 4321 -#endif - -#ifndef BYTE_ORDER -#define BYTE_ORDER LITTLE_ENDIAN -#endif - #if !defined(BYTE_ORDER) || (BYTE_ORDER != LITTLE_ENDIAN && BYTE_ORDER != BIG_ENDIAN) #error Define BYTE_ORDER to be equal to either LITTLE_ENDIAN or BIG_ENDIAN #endif @@ -104,24 +95,6 @@ typedef uint64_t sha2_word64; /* Exactly 8 bytes */ #define SHA256_SHORT_BLOCK_LENGTH (SHA256_BLOCK_LENGTH - 8) #define SHA512_SHORT_BLOCK_LENGTH (SHA512_BLOCK_LENGTH - 16) - -/*** ENDIAN REVERSAL MACROS *******************************************/ -#if BYTE_ORDER == LITTLE_ENDIAN -#define REVERSE32(w,x) { \ - sha2_word32 tmp = (w); \ - tmp = (tmp >> 16) | (tmp << 16); \ - (x) = ((tmp & 0xff00ff00UL) >> 8) | ((tmp & 0x00ff00ffUL) << 8); \ -} -#define REVERSE64(w,x) { \ - sha2_word64 tmp = (w); \ - tmp = (tmp >> 32) | (tmp << 32); \ - tmp = ((tmp & 0xff00ff00ff00ff00ULL) >> 8) | \ - ((tmp & 0x00ff00ff00ff00ffULL) << 8); \ - (x) = ((tmp & 0xffff0000ffff0000ULL) >> 16) | \ - ((tmp & 0x0000ffff0000ffffULL) << 16); \ -} -#endif /* BYTE_ORDER == LITTLE_ENDIAN */ - /* * Macro for incrementally adding the unsigned 64-bit integer n to the * unsigned 128-bit integer (represented using a two-element array of @@ -174,9 +147,7 @@ typedef uint64_t sha2_word64; /* Exactly 8 bytes */ * library -- they are intended for private internal visibility/use * only. */ -void sha512_Last(SHA512_CTX*); -void sha256_Transform(SHA256_CTX*, const sha2_word32*); -void sha512_Transform(SHA512_CTX*, const sha2_word64*); +static void sha512_Last(SHA512_CTX*); /*** SHA-XYZ INITIAL HASH VALUES AND CONSTANTS ************************/ @@ -201,7 +172,7 @@ static const sha2_word32 K256[64] = { }; /* Initial hash value H for SHA-256: */ -static const sha2_word32 sha256_initial_hash_value[8] = { +const sha2_word32 sha256_initial_hash_value[8] = { 0x6a09e667UL, 0xbb67ae85UL, 0x3c6ef372UL, @@ -257,7 +228,7 @@ static const sha2_word64 K512[80] = { }; /* Initial hash value H for SHA-512 */ -static const sha2_word64 sha512_initial_hash_value[8] = { +const sha2_word64 sha512_initial_hash_value[8] = { 0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, 0x3c6ef372fe94f82bULL, @@ -292,7 +263,7 @@ void sha256_Init(SHA256_CTX* context) { #if BYTE_ORDER == LITTLE_ENDIAN #define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \ - REVERSE32(*data++, W256[j]); \ + W256[j] = *data++; \ T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \ K256[j] + W256[j]; \ (d) += T1; \ @@ -322,22 +293,21 @@ void sha256_Init(SHA256_CTX* context) { (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ j++ -void sha256_Transform(SHA256_CTX* context, const sha2_word32* data) { +void sha256_Transform(const sha2_word32* state_in, const sha2_word32* data, sha2_word32* state_out) { sha2_word32 a, b, c, d, e, f, g, h, s0, s1; - sha2_word32 T1, *W256; + sha2_word32 T1; + sha2_word32 W256[16]; int j; - W256 = (sha2_word32*)context->buffer; - /* Initialize registers with the prev. intermediate value */ - a = context->state[0]; - b = context->state[1]; - c = context->state[2]; - d = context->state[3]; - e = context->state[4]; - f = context->state[5]; - g = context->state[6]; - h = context->state[7]; + a = state_in[0]; + b = state_in[1]; + c = state_in[2]; + d = state_in[3]; + e = state_in[4]; + f = state_in[5]; + g = state_in[6]; + h = state_in[7]; j = 0; do { @@ -365,14 +335,14 @@ void sha256_Transform(SHA256_CTX* context, const sha2_word32* data) { } while (j < 64); /* Compute the current intermediate hash value */ - context->state[0] += a; - context->state[1] += b; - context->state[2] += c; - context->state[3] += d; - context->state[4] += e; - context->state[5] += f; - context->state[6] += g; - context->state[7] += h; + state_out[0] = state_in[0] + a; + state_out[1] = state_in[1] + b; + state_out[2] = state_in[2] + c; + state_out[3] = state_in[3] + d; + state_out[4] = state_in[4] + e; + state_out[5] = state_in[5] + f; + state_out[6] = state_in[6] + g; + state_out[7] = state_in[7] + h; /* Clean up */ a = b = c = d = e = f = g = h = T1 = 0; @@ -380,34 +350,25 @@ void sha256_Transform(SHA256_CTX* context, const sha2_word32* data) { #else /* SHA2_UNROLL_TRANSFORM */ -void sha256_Transform(SHA256_CTX* context, const sha2_word32* data) { +void sha256_Transform(const sha2_word32* state_in, const sha2_word32* data, sha2_word32* state_out) { sha2_word32 a, b, c, d, e, f, g, h, s0, s1; - sha2_word32 T1, T2, *W256; + sha2_word32 T1, T2, W256[16]; int j; - W256 = (sha2_word32*)(void*)context->buffer; - /* Initialize registers with the prev. intermediate value */ - a = context->state[0]; - b = context->state[1]; - c = context->state[2]; - d = context->state[3]; - e = context->state[4]; - f = context->state[5]; - g = context->state[6]; - h = context->state[7]; + a = state_in[0]; + b = state_in[1]; + c = state_in[2]; + d = state_in[3]; + e = state_in[4]; + f = state_in[5]; + g = state_in[6]; + h = state_in[7]; j = 0; do { -#if BYTE_ORDER == LITTLE_ENDIAN - /* Copy data while converting to host byte order */ - REVERSE32(*data++,W256[j]); - /* Apply the SHA-256 compression function to update a..h */ - T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + W256[j]; -#else /* BYTE_ORDER == LITTLE_ENDIAN */ /* Apply the SHA-256 compression function to update a..h with copy */ T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + (W256[j] = *data++); -#endif /* BYTE_ORDER == LITTLE_ENDIAN */ T2 = Sigma0_256(a) + Maj(a, b, c); h = g; g = f; @@ -445,14 +406,14 @@ void sha256_Transform(SHA256_CTX* context, const sha2_word32* data) { } while (j < 64); /* Compute the current intermediate hash value */ - context->state[0] += a; - context->state[1] += b; - context->state[2] += c; - context->state[3] += d; - context->state[4] += e; - context->state[5] += f; - context->state[6] += g; - context->state[7] += h; + state_out[0] = state_in[0] + a; + state_out[1] = state_in[1] + b; + state_out[2] = state_in[2] + c; + state_out[3] = state_in[3] + d; + state_out[4] = state_in[4] + e; + state_out[5] = state_in[5] + f; + state_out[6] = state_in[6] + g; + state_out[7] = state_in[7] + h; /* Clean up */ a = b = c = d = e = f = g = h = T1 = T2 = 0; @@ -475,14 +436,20 @@ void sha256_Update(SHA256_CTX* context, const sha2_byte *data, size_t len) { if (len >= freespace) { /* Fill the buffer completely and process it */ - MEMCPY_BCOPY(&context->buffer[usedspace], data, freespace); + MEMCPY_BCOPY(((uint8_t*)context->buffer) + usedspace, data, freespace); context->bitcount += freespace << 3; len -= freespace; data += freespace; - sha256_Transform(context, (sha2_word32*)(void*)context->buffer); +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert TO host byte order */ + for (int j = 0; j < 16; j++) { + REVERSE32(context->buffer[j],context->buffer[j]); + } +#endif + sha256_Transform(context->state, context->buffer, context->state); } else { /* The buffer is not yet full */ - MEMCPY_BCOPY(&context->buffer[usedspace], data, len); + MEMCPY_BCOPY(((uint8_t*)context->buffer) + usedspace, data, len); context->bitcount += len << 3; /* Clean up: */ usedspace = freespace = 0; @@ -491,7 +458,14 @@ void sha256_Update(SHA256_CTX* context, const sha2_byte *data, size_t len) { } while (len >= SHA256_BLOCK_LENGTH) { /* Process as many complete blocks as we can */ - sha256_Transform(context, (sha2_word32*)(void*)data); + MEMCPY_BCOPY(context->buffer, data, SHA256_BLOCK_LENGTH); +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert TO host byte order */ + for (int j = 0; j < 16; j++) { + REVERSE32(context->buffer[j],context->buffer[j]); + } +#endif + sha256_Transform(context->state, context->buffer, context->state); context->bitcount += SHA256_BLOCK_LENGTH << 3; len -= SHA256_BLOCK_LENGTH; data += SHA256_BLOCK_LENGTH; @@ -512,53 +486,49 @@ void sha256_Final(SHA256_CTX* context, sha2_byte digest[]) { /* If no digest buffer is passed, we don't bother doing this: */ if (digest != (sha2_byte*)0) { usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH; + /* Begin padding with a 1 bit: */ + ((uint8_t*)context->buffer)[usedspace++] = 0x80; + + if (usedspace <= SHA256_SHORT_BLOCK_LENGTH) { + /* Set-up for the last transform: */ + MEMSET_BZERO(((uint8_t*)context->buffer) + usedspace, SHA256_SHORT_BLOCK_LENGTH - usedspace); + } else { + if (usedspace < SHA256_BLOCK_LENGTH) { + MEMSET_BZERO(((uint8_t*)context->buffer) + usedspace, SHA256_BLOCK_LENGTH - usedspace); + } #if BYTE_ORDER == LITTLE_ENDIAN - /* Convert FROM host byte order */ - REVERSE64(context->bitcount,context->bitcount); -#endif - if (usedspace > 0) { - /* Begin padding with a 1 bit: */ - context->buffer[usedspace++] = 0x80; - - if (usedspace <= SHA256_SHORT_BLOCK_LENGTH) { - /* Set-up for the last transform: */ - MEMSET_BZERO(&context->buffer[usedspace], SHA256_SHORT_BLOCK_LENGTH - usedspace); - } else { - if (usedspace < SHA256_BLOCK_LENGTH) { - MEMSET_BZERO(&context->buffer[usedspace], SHA256_BLOCK_LENGTH - usedspace); - } - /* Do second-to-last transform: */ - sha256_Transform(context, (sha2_word32*)(void*)context->buffer); - - /* And set-up for the last transform: */ - MEMSET_BZERO(context->buffer, SHA256_SHORT_BLOCK_LENGTH); + /* Convert TO host byte order */ + for (int j = 0; j < 16; j++) { + REVERSE32(context->buffer[j],context->buffer[j]); } - } else { - /* Set-up for the last transform: */ +#endif + /* Do second-to-last transform: */ + sha256_Transform(context->state, context->buffer, context->state); + + /* And set-up for the last transform: */ MEMSET_BZERO(context->buffer, SHA256_SHORT_BLOCK_LENGTH); + } - /* Begin padding with a 1 bit: */ - *context->buffer = 0x80; +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert TO host byte order */ + for (int j = 0; j < 14; j++) { + REVERSE32(context->buffer[j],context->buffer[j]); } +#endif /* Set the bit count: */ - sha2_word64 *t = (sha2_word64 *)(void*)&context->buffer[SHA256_SHORT_BLOCK_LENGTH]; - *t = context->bitcount; + context->buffer[14] = context->bitcount >> 32; + context->buffer[15] = context->bitcount & 0xffffffff; /* Final transform: */ - sha256_Transform(context, (sha2_word32*)(void*)context->buffer); + sha256_Transform(context->state, context->buffer, context->state); #if BYTE_ORDER == LITTLE_ENDIAN - { - /* Convert TO host byte order */ - int j; - for (j = 0; j < 8; j++) { - REVERSE32(context->state[j],context->state[j]); - *d++ = context->state[j]; - } + /* Convert FROM host byte order */ + for (int j = 0; j < 8; j++) { + REVERSE32(context->state[j],context->state[j]); } -#else - MEMCPY_BCOPY(d, context->state, SHA256_DIGEST_LENGTH); #endif + MEMCPY_BCOPY(d, context->state, SHA256_DIGEST_LENGTH); } /* Clean up state data: */ @@ -615,19 +585,6 @@ void sha512_Init(SHA512_CTX* context) { #ifdef SHA2_UNROLL_TRANSFORM /* Unrolled SHA-512 round macros: */ -#if BYTE_ORDER == LITTLE_ENDIAN - -#define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) \ - REVERSE64(*data++, W512[j]); \ - T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \ - K512[j] + W512[j]; \ - (d) += T1, \ - (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)), \ - j++ - - -#else /* BYTE_ORDER == LITTLE_ENDIAN */ - #define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) \ T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \ K512[j] + (W512[j] = *data++); \ @@ -635,8 +592,6 @@ void sha512_Init(SHA512_CTX* context) { (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \ j++ -#endif /* BYTE_ORDER == LITTLE_ENDIAN */ - #define ROUND512(a,b,c,d,e,f,g,h) \ s0 = W512[(j+1)&0x0f]; \ s0 = sigma0_512(s0); \ @@ -648,20 +603,20 @@ void sha512_Init(SHA512_CTX* context) { (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \ j++ -void sha512_Transform(SHA512_CTX* context, const sha2_word64* data) { +void sha512_Transform(const sha2_word64* state_in, const sha2_word64* data, sha2_word64* state_out) { sha2_word64 a, b, c, d, e, f, g, h, s0, s1; - sha2_word64 T1, *W512 = (sha2_word64*)context->buffer; + sha2_word64 T1, W512[16]; int j; /* Initialize registers with the prev. intermediate value */ - a = context->state[0]; - b = context->state[1]; - c = context->state[2]; - d = context->state[3]; - e = context->state[4]; - f = context->state[5]; - g = context->state[6]; - h = context->state[7]; + a = state_in[0]; + b = state_in[1]; + c = state_in[2]; + d = state_in[3]; + e = state_in[4]; + f = state_in[5]; + g = state_in[6]; + h = state_in[7]; j = 0; do { @@ -688,14 +643,14 @@ void sha512_Transform(SHA512_CTX* context, const sha2_word64* data) { } while (j < 80); /* Compute the current intermediate hash value */ - context->state[0] += a; - context->state[1] += b; - context->state[2] += c; - context->state[3] += d; - context->state[4] += e; - context->state[5] += f; - context->state[6] += g; - context->state[7] += h; + state_out[0] = state_in[0] + a; + state_out[1] = state_in[1] + b; + state_out[2] = state_in[2] + c; + state_out[3] = state_in[3] + d; + state_out[4] = state_in[4] + e; + state_out[5] = state_in[5] + f; + state_out[6] = state_in[6] + g; + state_out[7] = state_in[7] + h; /* Clean up */ a = b = c = d = e = f = g = h = T1 = 0; @@ -703,32 +658,25 @@ void sha512_Transform(SHA512_CTX* context, const sha2_word64* data) { #else /* SHA2_UNROLL_TRANSFORM */ -void sha512_Transform(SHA512_CTX* context, const sha2_word64* data) { +void sha512_Transform(const sha2_word64* state_in, const sha2_word64* data, sha2_word64* state_out) { sha2_word64 a, b, c, d, e, f, g, h, s0, s1; - sha2_word64 T1, T2, *W512 = (sha2_word64*)(void*)context->buffer; + sha2_word64 T1, T2, W512[16]; int j; /* Initialize registers with the prev. intermediate value */ - a = context->state[0]; - b = context->state[1]; - c = context->state[2]; - d = context->state[3]; - e = context->state[4]; - f = context->state[5]; - g = context->state[6]; - h = context->state[7]; + a = state_in[0]; + b = state_in[1]; + c = state_in[2]; + d = state_in[3]; + e = state_in[4]; + f = state_in[5]; + g = state_in[6]; + h = state_in[7]; j = 0; do { -#if BYTE_ORDER == LITTLE_ENDIAN - /* Convert TO host byte order */ - REVERSE64(*data++, W512[j]); - /* Apply the SHA-512 compression function to update a..h */ - T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + W512[j]; -#else /* BYTE_ORDER == LITTLE_ENDIAN */ /* Apply the SHA-512 compression function to update a..h with copy */ T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + (W512[j] = *data++); -#endif /* BYTE_ORDER == LITTLE_ENDIAN */ T2 = Sigma0_512(a) + Maj(a, b, c); h = g; g = f; @@ -766,14 +714,14 @@ void sha512_Transform(SHA512_CTX* context, const sha2_word64* data) { } while (j < 80); /* Compute the current intermediate hash value */ - context->state[0] += a; - context->state[1] += b; - context->state[2] += c; - context->state[3] += d; - context->state[4] += e; - context->state[5] += f; - context->state[6] += g; - context->state[7] += h; + state_out[0] = state_in[0] + a; + state_out[1] = state_in[1] + b; + state_out[2] = state_in[2] + c; + state_out[3] = state_in[3] + d; + state_out[4] = state_in[4] + e; + state_out[5] = state_in[5] + f; + state_out[6] = state_in[6] + g; + state_out[7] = state_in[7] + h; /* Clean up */ a = b = c = d = e = f = g = h = T1 = T2 = 0; @@ -796,14 +744,20 @@ void sha512_Update(SHA512_CTX* context, const sha2_byte *data, size_t len) { if (len >= freespace) { /* Fill the buffer completely and process it */ - MEMCPY_BCOPY(&context->buffer[usedspace], data, freespace); + MEMCPY_BCOPY(((uint8_t*)context->buffer) + usedspace, data, freespace); ADDINC128(context->bitcount, freespace << 3); len -= freespace; data += freespace; - sha512_Transform(context, (sha2_word64*)(void*)context->buffer); +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert TO host byte order */ + for (int j = 0; j < 16; j++) { + REVERSE64(context->buffer[j],context->buffer[j]); + } +#endif + sha512_Transform(context->state, context->buffer, context->state); } else { /* The buffer is not yet full */ - MEMCPY_BCOPY(&context->buffer[usedspace], data, len); + MEMCPY_BCOPY(((uint8_t*)context->buffer) + usedspace, data, len); ADDINC128(context->bitcount, len << 3); /* Clean up: */ usedspace = freespace = 0; @@ -812,7 +766,14 @@ void sha512_Update(SHA512_CTX* context, const sha2_byte *data, size_t len) { } while (len >= SHA512_BLOCK_LENGTH) { /* Process as many complete blocks as we can */ - sha512_Transform(context, (sha2_word64*)(void*)data); + MEMCPY_BCOPY(context->buffer, data, SHA512_BLOCK_LENGTH); +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert TO host byte order */ + for (int j = 0; j < 16; j++) { + REVERSE64(((sha2_word64*)data)[j],context->buffer[j]); + } +#endif + sha512_Transform(context->state, context->buffer, context->state); ADDINC128(context->bitcount, SHA512_BLOCK_LENGTH << 3); len -= SHA512_BLOCK_LENGTH; data += SHA512_BLOCK_LENGTH; @@ -826,48 +787,47 @@ void sha512_Update(SHA512_CTX* context, const sha2_byte *data, size_t len) { usedspace = freespace = 0; } -void sha512_Last(SHA512_CTX* context) { +static void sha512_Last(SHA512_CTX* context) { unsigned int usedspace; usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH; + /* Begin padding with a 1 bit: */ + ((uint8_t*)context->buffer)[usedspace++] = 0x80; + + if (usedspace <= SHA512_SHORT_BLOCK_LENGTH) { + /* Set-up for the last transform: */ + MEMSET_BZERO(((uint8_t*)context->buffer) + usedspace, SHA512_SHORT_BLOCK_LENGTH - usedspace); + } else { + if (usedspace < SHA512_BLOCK_LENGTH) { + MEMSET_BZERO(((uint8_t*)context->buffer) + usedspace, SHA512_BLOCK_LENGTH - usedspace); + } #if BYTE_ORDER == LITTLE_ENDIAN - /* Convert FROM host byte order */ - REVERSE64(context->bitcount[0],context->bitcount[0]); - REVERSE64(context->bitcount[1],context->bitcount[1]); + /* Convert TO host byte order */ + for (int j = 0; j < 16; j++) { + REVERSE64(context->buffer[j],context->buffer[j]); + } #endif - if (usedspace > 0) { - /* Begin padding with a 1 bit: */ - context->buffer[usedspace++] = 0x80; + /* Do second-to-last transform: */ + sha512_Transform(context->state, context->buffer, context->state); - if (usedspace <= SHA512_SHORT_BLOCK_LENGTH) { - /* Set-up for the last transform: */ - MEMSET_BZERO(&context->buffer[usedspace], SHA512_SHORT_BLOCK_LENGTH - usedspace); - } else { - if (usedspace < SHA512_BLOCK_LENGTH) { - MEMSET_BZERO(&context->buffer[usedspace], SHA512_BLOCK_LENGTH - usedspace); - } - /* Do second-to-last transform: */ - sha512_Transform(context, (sha2_word64*)(void*)context->buffer); - - /* And set-up for the last transform: */ - MEMSET_BZERO(context->buffer, SHA512_BLOCK_LENGTH - 2); - } - } else { - /* Prepare for final transform: */ - MEMSET_BZERO(context->buffer, SHA512_SHORT_BLOCK_LENGTH); + /* And set-up for the last transform: */ + MEMSET_BZERO(context->buffer, SHA512_BLOCK_LENGTH - 2); + } - /* Begin padding with a 1 bit: */ - *context->buffer = 0x80; +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert TO host byte order */ + for (int j = 0; j < 16; j++) { + REVERSE64(context->buffer[j],context->buffer[j]); } +#endif /* Store the length of input data (in bits): */ sha2_word64 *t; - t = (sha2_word64 *)(void*)&context->buffer[SHA512_SHORT_BLOCK_LENGTH]; - *t = context->bitcount[1]; - t = (sha2_word64 *)(void*)&context->buffer[SHA512_SHORT_BLOCK_LENGTH+8]; - *t = context->bitcount[0]; + t = &context->buffer[SHA512_SHORT_BLOCK_LENGTH/sizeof(sha2_word64)]; + t[0] = context->bitcount[1]; + t[1] = context->bitcount[0]; /* Final transform: */ - sha512_Transform(context, (sha2_word64*)(void*)context->buffer); + sha512_Transform(context->state, context->buffer, context->state); } void sha512_Final(SHA512_CTX* context, sha2_byte digest[]) { @@ -879,17 +839,12 @@ void sha512_Final(SHA512_CTX* context, sha2_byte digest[]) { /* Save the hash data for output: */ #if BYTE_ORDER == LITTLE_ENDIAN - { - /* Convert TO host byte order */ - int j; - for (j = 0; j < 8; j++) { - REVERSE64(context->state[j],context->state[j]); - *d++ = context->state[j]; - } + /* Convert FROM host byte order */ + for (int j = 0; j < 8; j++) { + REVERSE64(context->state[j],context->state[j]); } -#else - MEMCPY_BCOPY(d, context->state, SHA512_DIGEST_LENGTH); #endif + MEMCPY_BCOPY(d, context->state, SHA512_DIGEST_LENGTH); } /* Zero out state data */ diff --git a/sha2.h b/sha2.h index cc39e23f8..7c2a0bd30 100644 --- a/sha2.h +++ b/sha2.h @@ -44,14 +44,44 @@ typedef struct _SHA256_CTX { uint32_t state[8]; uint64_t bitcount; - uint8_t buffer[SHA256_BLOCK_LENGTH]; + uint32_t buffer[SHA256_BLOCK_LENGTH/sizeof(uint32_t)]; } SHA256_CTX; typedef struct _SHA512_CTX { uint64_t state[8]; uint64_t bitcount[2]; - uint8_t buffer[SHA512_BLOCK_LENGTH]; + uint64_t buffer[SHA512_BLOCK_LENGTH/sizeof(uint64_t)]; } SHA512_CTX; +/*** ENDIAN REVERSAL MACROS *******************************************/ +#ifndef LITTLE_ENDIAN +#define LITTLE_ENDIAN 1234 +#define BIG_ENDIAN 4321 +#endif + +#ifndef BYTE_ORDER +#define BYTE_ORDER LITTLE_ENDIAN +#endif + +#if BYTE_ORDER == LITTLE_ENDIAN +#define REVERSE32(w,x) { \ + uint32_t tmp = (w); \ + tmp = (tmp >> 16) | (tmp << 16); \ + (x) = ((tmp & 0xff00ff00UL) >> 8) | ((tmp & 0x00ff00ffUL) << 8); \ +} +#define REVERSE64(w,x) { \ + uint64_t tmp = (w); \ + tmp = (tmp >> 32) | (tmp << 32); \ + tmp = ((tmp & 0xff00ff00ff00ff00ULL) >> 8) | \ + ((tmp & 0x00ff00ff00ff00ffULL) << 8); \ + (x) = ((tmp & 0xffff0000ffff0000ULL) >> 16) | \ + ((tmp & 0x0000ffff0000ffffULL) << 16); \ +} +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ + +extern const uint32_t sha256_initial_hash_value[8]; +extern const uint64_t sha512_initial_hash_value[8]; + +void sha256_Transform(const uint32_t* state_in, const uint32_t* data, uint32_t* state_out); void sha256_Init(SHA256_CTX *); void sha256_Update(SHA256_CTX*, const uint8_t*, size_t); void sha256_Final(SHA256_CTX*, uint8_t[SHA256_DIGEST_LENGTH]); @@ -59,6 +89,7 @@ char* sha256_End(SHA256_CTX*, char[SHA256_DIGEST_STRING_LENGTH]); void sha256_Raw(const uint8_t*, size_t, uint8_t[SHA256_DIGEST_LENGTH]); char* sha256_Data(const uint8_t*, size_t, char[SHA256_DIGEST_STRING_LENGTH]); +void sha512_Transform(const uint64_t* state_in, const uint64_t* data, uint64_t* state_out); void sha512_Init(SHA512_CTX*); void sha512_Update(SHA512_CTX*, const uint8_t*, size_t); void sha512_Final(SHA512_CTX*, uint8_t[SHA512_DIGEST_LENGTH]); From 9101c050aa6724c5af82105d2f2b4f07f3d6e565 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Tue, 12 Jul 2016 15:06:24 +0200 Subject: [PATCH 295/627] Smoother progress bar for wakeup Call interrupt twice as often; makes progress bar smoother. --- bip39.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bip39.c b/bip39.c index c35fbd76c..ef7a40e5f 100644 --- a/bip39.c +++ b/bip39.c @@ -226,10 +226,10 @@ void mnemonic_to_seed(const char *mnemonic, const char *passphrase, uint8_t seed if (progress_callback) { progress_callback(0, BIP39_PBKDF2_ROUNDS); } - for (int i = 0; i < 8; i++) { - pbkdf2_hmac_sha512_Update(&pctx, BIP39_PBKDF2_ROUNDS / 8); + for (int i = 0; i < 16; i++) { + pbkdf2_hmac_sha512_Update(&pctx, BIP39_PBKDF2_ROUNDS / 16); if (progress_callback) { - progress_callback((i + 1) * BIP39_PBKDF2_ROUNDS / 8, BIP39_PBKDF2_ROUNDS); + progress_callback((i + 1) * BIP39_PBKDF2_ROUNDS / 16, BIP39_PBKDF2_ROUNDS); } } pbkdf2_hmac_sha512_Final(&pctx, seed); From d8e17d5d4d06be312fd2fbc319028f456c420eb4 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Wed, 13 Jul 2016 20:40:15 +0200 Subject: [PATCH 296/627] Test cases for sha256 and sha512 --- tests.c | 217 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 217 insertions(+) diff --git a/tests.c b/tests.c index 8d653eb38..baaf0d187 100644 --- a/tests.c +++ b/tests.c @@ -1268,6 +1268,215 @@ START_TEST(test_aes) } END_TEST +#define TEST1 "abc" +#define TEST2_1 \ + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" +#define TEST2_2a \ + "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn" +#define TEST2_2b \ + "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu" +#define TEST2_2 TEST2_2a TEST2_2b +#define TEST3 "a" /* times 1000000 */ +#define TEST4a "01234567012345670123456701234567" +#define TEST4b "01234567012345670123456701234567" + /* an exact multiple of 512 bits */ +#define TEST4 TEST4a TEST4b /* times 10 */ + +#define TEST7_1 \ + "\x49\xb2\xae\xc2\x59\x4b\xbe\x3a\x3b\x11\x75\x42\xd9\x4a\xc8" +#define TEST8_1 \ + "\x9a\x7d\xfd\xf1\xec\xea\xd0\x6e\xd6\x46\xaa\x55\xfe\x75\x71\x46" +#define TEST9_1 \ + "\x65\xf9\x32\x99\x5b\xa4\xce\x2c\xb1\xb4\xa2\xe7\x1a\xe7\x02\x20" \ + "\xaa\xce\xc8\x96\x2d\xd4\x49\x9c\xbd\x7c\x88\x7a\x94\xea\xaa\x10" \ + "\x1e\xa5\xaa\xbc\x52\x9b\x4e\x7e\x43\x66\x5a\x5a\xf2\xcd\x03\xfe" \ + "\x67\x8e\xa6\xa5\x00\x5b\xba\x3b\x08\x22\x04\xc2\x8b\x91\x09\xf4" \ + "\x69\xda\xc9\x2a\xaa\xb3\xaa\x7c\x11\xa1\xb3\x2a" +#define TEST10_1 \ + "\xf7\x8f\x92\x14\x1b\xcd\x17\x0a\xe8\x9b\x4f\xba\x15\xa1\xd5\x9f" \ + "\x3f\xd8\x4d\x22\x3c\x92\x51\xbd\xac\xbb\xae\x61\xd0\x5e\xd1\x15" \ + "\xa0\x6a\x7c\xe1\x17\xb7\xbe\xea\xd2\x44\x21\xde\xd9\xc3\x25\x92" \ + "\xbd\x57\xed\xea\xe3\x9c\x39\xfa\x1f\xe8\x94\x6a\x84\xd0\xcf\x1f" \ + "\x7b\xee\xad\x17\x13\xe2\xe0\x95\x98\x97\x34\x7f\x67\xc8\x0b\x04" \ + "\x00\xc2\x09\x81\x5d\x6b\x10\xa6\x83\x83\x6f\xd5\x56\x2a\x56\xca" \ + "\xb1\xa2\x8e\x81\xb6\x57\x66\x54\x63\x1c\xf1\x65\x66\xb8\x6e\x3b" \ + "\x33\xa1\x08\xb0\x53\x07\xc0\x0a\xff\x14\xa7\x68\xed\x73\x50\x60" \ + "\x6a\x0f\x85\xe6\xa9\x1d\x39\x6f\x5b\x5c\xbe\x57\x7f\x9b\x38\x80" \ + "\x7c\x7d\x52\x3d\x6d\x79\x2f\x6e\xbc\x24\xa4\xec\xf2\xb3\xa4\x27" \ + "\xcd\xbb\xfb" +#define TEST7_256 \ + "\xbe\x27\x46\xc6\xdb\x52\x76\x5f\xdb\x2f\x88\x70\x0f\x9a\x73" +#define TEST8_256 \ + "\xe3\xd7\x25\x70\xdc\xdd\x78\x7c\xe3\x88\x7a\xb2\xcd\x68\x46\x52" +#define TEST9_256 \ + "\x3e\x74\x03\x71\xc8\x10\xc2\xb9\x9f\xc0\x4e\x80\x49\x07\xef\x7c" \ + "\xf2\x6b\xe2\x8b\x57\xcb\x58\xa3\xe2\xf3\xc0\x07\x16\x6e\x49\xc1" \ + "\x2e\x9b\xa3\x4c\x01\x04\x06\x91\x29\xea\x76\x15\x64\x25\x45\x70" \ + "\x3a\x2b\xd9\x01\xe1\x6e\xb0\xe0\x5d\xeb\xa0\x14\xeb\xff\x64\x06" \ + "\xa0\x7d\x54\x36\x4e\xff\x74\x2d\xa7\x79\xb0\xb3" +#define TEST10_256 \ + "\x83\x26\x75\x4e\x22\x77\x37\x2f\x4f\xc1\x2b\x20\x52\x7a\xfe\xf0" \ + "\x4d\x8a\x05\x69\x71\xb1\x1a\xd5\x71\x23\xa7\xc1\x37\x76\x00\x00" \ + "\xd7\xbe\xf6\xf3\xc1\xf7\xa9\x08\x3a\xa3\x9d\x81\x0d\xb3\x10\x77" \ + "\x7d\xab\x8b\x1e\x7f\x02\xb8\x4a\x26\xc7\x73\x32\x5f\x8b\x23\x74" \ + "\xde\x7a\x4b\x5a\x58\xcb\x5c\x5c\xf3\x5b\xce\xe6\xfb\x94\x6e\x5b" \ + "\xd6\x94\xfa\x59\x3a\x8b\xeb\x3f\x9d\x65\x92\xec\xed\xaa\x66\xca" \ + "\x82\xa2\x9d\x0c\x51\xbc\xf9\x33\x62\x30\xe5\xd7\x84\xe4\xc0\xa4" \ + "\x3f\x8d\x79\xa3\x0a\x16\x5c\xba\xbe\x45\x2b\x77\x4b\x9c\x71\x09" \ + "\xa9\x7d\x13\x8f\x12\x92\x28\x96\x6f\x6c\x0a\xdc\x10\x6a\xad\x5a" \ + "\x9f\xdd\x30\x82\x57\x69\xb2\xc6\x71\xaf\x67\x59\xdf\x28\xeb\x39" \ + "\x3d\x54\xd6" +#define length(x) (sizeof(x)-1) + +// test vectors from rfc-4634 +START_TEST(test_sha256) +{ + struct { + const char* test; + int length; + int repeatcount; + int extrabits; + int numberExtrabits; + const char* result; + } tests[] = { + /* 1 */ { TEST1, length(TEST1), 1, 0, 0, "BA7816BF8F01CFEA4141" + "40DE5DAE2223B00361A396177A9CB410FF61F20015AD" }, + /* 2 */ { TEST2_1, length(TEST2_1), 1, 0, 0, "248D6A61D20638B8" + "E5C026930C3E6039A33CE45964FF2167F6ECEDD419DB06C1" }, + /* 3 */ { TEST3, length(TEST3), 1000000, 0, 0, "CDC76E5C9914FB92" + "81A1C7E284D73E67F1809A48A497200E046D39CCC7112CD0" }, + /* 4 */ { TEST4, length(TEST4), 10, 0, 0, "594847328451BDFA" + "85056225462CC1D867D877FB388DF0CE35F25AB5562BFBB5" }, + /* 5 */ { "", 0, 0, 0x68, 5, "D6D3E02A31A84A8CAA9718ED6C2057BE" + "09DB45E7823EB5079CE7A573A3760F95" }, + /* 6 */ { "\x19", 1, 1, 0, 0, "68AA2E2EE5DFF96E3355E6C7EE373E3D" + "6A4E17F75F9518D843709C0C9BC3E3D4" }, + /* 7 */ { TEST7_256, length(TEST7_256), 1, 0x60, 3, "77EC1DC8" + "9C821FF2A1279089FA091B35B8CD960BCAF7DE01C6A7680756BEB972" }, + /* 8 */ { TEST8_256, length(TEST8_256), 1, 0, 0, "175EE69B02BA" + "9B58E2B0A5FD13819CEA573F3940A94F825128CF4209BEABB4E8" }, + /* 9 */ { TEST9_256, length(TEST9_256), 1, 0xA0, 3, "3E9AD646" + "8BBBAD2AC3C2CDC292E018BA5FD70B960CF1679777FCE708FDB066E9" }, + /* 10 */ { TEST10_256, length(TEST10_256), 1, 0, 0, "97DBCA7D" + "F46D62C8A422C941DD7E835B8AD3361763F7E9B2D95F4F0DA6E1CCBC" }, + }; + + for (int i = 0; i < 10; i++) { + SHA256_CTX ctx; + uint8_t digest[SHA256_DIGEST_LENGTH]; + sha256_Init(&ctx); + /* extra bits are not supported */ + if (tests[i].numberExtrabits) + continue; + for (int j = 0; j < tests[i].repeatcount; j++) { + sha256_Update(&ctx, (const uint8_t*) tests[i].test, tests[i].length); + } + sha256_Final(&ctx, digest); + ck_assert_mem_eq(digest, fromhex(tests[i].result), SHA256_DIGEST_LENGTH); + } +} +END_TEST + +#define TEST7_512 \ + "\x08\xec\xb5\x2e\xba\xe1\xf7\x42\x2d\xb6\x2b\xcd\x54\x26\x70" +#define TEST8_512 \ + "\x8d\x4e\x3c\x0e\x38\x89\x19\x14\x91\x81\x6e\x9d\x98\xbf\xf0\xa0" +#define TEST9_512 \ + "\x3a\xdd\xec\x85\x59\x32\x16\xd1\x61\x9a\xa0\x2d\x97\x56\x97\x0b" \ + "\xfc\x70\xac\xe2\x74\x4f\x7c\x6b\x27\x88\x15\x10\x28\xf7\xb6\xa2" \ + "\x55\x0f\xd7\x4a\x7e\x6e\x69\xc2\xc9\xb4\x5f\xc4\x54\x96\x6d\xc3" \ + "\x1d\x2e\x10\xda\x1f\x95\xce\x02\xbe\xb4\xbf\x87\x65\x57\x4c\xbd" \ + "\x6e\x83\x37\xef\x42\x0a\xdc\x98\xc1\x5c\xb6\xd5\xe4\xa0\x24\x1b" \ + "\xa0\x04\x6d\x25\x0e\x51\x02\x31\xca\xc2\x04\x6c\x99\x16\x06\xab" \ + "\x4e\xe4\x14\x5b\xee\x2f\xf4\xbb\x12\x3a\xab\x49\x8d\x9d\x44\x79" \ + "\x4f\x99\xcc\xad\x89\xa9\xa1\x62\x12\x59\xed\xa7\x0a\x5b\x6d\xd4" \ + "\xbd\xd8\x77\x78\xc9\x04\x3b\x93\x84\xf5\x49\x06" +#define TEST10_512 \ + "\xa5\x5f\x20\xc4\x11\xaa\xd1\x32\x80\x7a\x50\x2d\x65\x82\x4e\x31" \ + "\xa2\x30\x54\x32\xaa\x3d\x06\xd3\xe2\x82\xa8\xd8\x4e\x0d\xe1\xde" \ + "\x69\x74\xbf\x49\x54\x69\xfc\x7f\x33\x8f\x80\x54\xd5\x8c\x26\xc4" \ + "\x93\x60\xc3\xe8\x7a\xf5\x65\x23\xac\xf6\xd8\x9d\x03\xe5\x6f\xf2" \ + "\xf8\x68\x00\x2b\xc3\xe4\x31\xed\xc4\x4d\xf2\xf0\x22\x3d\x4b\xb3" \ + "\xb2\x43\x58\x6e\x1a\x7d\x92\x49\x36\x69\x4f\xcb\xba\xf8\x8d\x95" \ + "\x19\xe4\xeb\x50\xa6\x44\xf8\xe4\xf9\x5e\xb0\xea\x95\xbc\x44\x65" \ + "\xc8\x82\x1a\xac\xd2\xfe\x15\xab\x49\x81\x16\x4b\xbb\x6d\xc3\x2f" \ + "\x96\x90\x87\xa1\x45\xb0\xd9\xcc\x9c\x67\xc2\x2b\x76\x32\x99\x41" \ + "\x9c\xc4\x12\x8b\xe9\xa0\x77\xb3\xac\xe6\x34\x06\x4e\x6d\x99\x28" \ + "\x35\x13\xdc\x06\xe7\x51\x5d\x0d\x73\x13\x2e\x9a\x0d\xc6\xd3\xb1" \ + "\xf8\xb2\x46\xf1\xa9\x8a\x3f\xc7\x29\x41\xb1\xe3\xbb\x20\x98\xe8" \ + "\xbf\x16\xf2\x68\xd6\x4f\x0b\x0f\x47\x07\xfe\x1e\xa1\xa1\x79\x1b" \ + "\xa2\xf3\xc0\xc7\x58\xe5\xf5\x51\x86\x3a\x96\xc9\x49\xad\x47\xd7" \ + "\xfb\x40\xd2" + +// test vectors from rfc-4634 +START_TEST(test_sha512) +{ + struct { + const char* test; + int length; + int repeatcount; + int extrabits; + int numberExtrabits; + const char* result; + } tests[] = { + /* 1 */ { TEST1, length(TEST1), 1, 0, 0, + "DDAF35A193617ABACC417349AE20413112E6FA4E89A97EA2" + "0A9EEEE64B55D39A2192992A274FC1A836BA3C23A3FEEBBD" + "454D4423643CE80E2A9AC94FA54CA49F" }, + /* 2 */ { TEST2_2, length(TEST2_2), 1, 0, 0, + "8E959B75DAE313DA8CF4F72814FC143F8F7779C6EB9F7FA1" + "7299AEADB6889018501D289E4900F7E4331B99DEC4B5433A" + "C7D329EEB6DD26545E96E55B874BE909" }, + /* 3 */ { TEST3, length(TEST3), 1000000, 0, 0, + "E718483D0CE769644E2E42C7BC15B4638E1F98B13B204428" + "5632A803AFA973EBDE0FF244877EA60A4CB0432CE577C31B" + "EB009C5C2C49AA2E4EADB217AD8CC09B" }, + /* 4 */ { TEST4, length(TEST4), 10, 0, 0, + "89D05BA632C699C31231DED4FFC127D5A894DAD412C0E024" + "DB872D1ABD2BA8141A0F85072A9BE1E2AA04CF33C765CB51" + "0813A39CD5A84C4ACAA64D3F3FB7BAE9" }, + /* 5 */ { "", 0, 0, 0xB0, 5, + "D4EE29A9E90985446B913CF1D1376C836F4BE2C1CF3CADA0" + "720A6BF4857D886A7ECB3C4E4C0FA8C7F95214E41DC1B0D2" + "1B22A84CC03BF8CE4845F34DD5BDBAD4" }, + /* 6 */ { "\xD0", 1, 1, 0, 0, + "9992202938E882E73E20F6B69E68A0A7149090423D93C81B" + "AB3F21678D4ACEEEE50E4E8CAFADA4C85A54EA8306826C4A" + "D6E74CECE9631BFA8A549B4AB3FBBA15" }, + /* 7 */ { TEST7_512, length(TEST7_512), 1, 0x80, 3, + "ED8DC78E8B01B69750053DBB7A0A9EDA0FB9E9D292B1ED71" + "5E80A7FE290A4E16664FD913E85854400C5AF05E6DAD316B" + "7359B43E64F8BEC3C1F237119986BBB6" }, + /* 8 */ { TEST8_512, length(TEST8_512), 1, 0, 0, + "CB0B67A4B8712CD73C9AABC0B199E9269B20844AFB75ACBD" + "D1C153C9828924C3DDEDAAFE669C5FDD0BC66F630F677398" + "8213EB1B16F517AD0DE4B2F0C95C90F8" }, + /* 9 */ { TEST9_512, length(TEST9_512), 1, 0x80, 3, + "32BA76FC30EAA0208AEB50FFB5AF1864FDBF17902A4DC0A6" + "82C61FCEA6D92B783267B21080301837F59DE79C6B337DB2" + "526F8A0A510E5E53CAFED4355FE7C2F1" }, + /* 10 */ { TEST10_512, length(TEST10_512), 1, 0, 0, + "C665BEFB36DA189D78822D10528CBF3B12B3EEF726039909" + "C1A16A270D48719377966B957A878E720584779A62825C18" + "DA26415E49A7176A894E7510FD1451F5" } + }; + + for (int i = 0; i < 10; i++) { + SHA512_CTX ctx; + uint8_t digest[SHA512_DIGEST_LENGTH]; + sha512_Init(&ctx); + /* extra bits are not supported */ + if (tests[i].numberExtrabits) + continue; + for (int j = 0; j < tests[i].repeatcount; j++) { + sha512_Update(&ctx, (const uint8_t*) tests[i].test, tests[i].length); + } + sha512_Final(&ctx, digest); + ck_assert_mem_eq(digest, fromhex(tests[i].result), SHA512_DIGEST_LENGTH); + } +} +END_TEST + // test vectors from https://stackoverflow.com/questions/5130513/pbkdf2-hmac-sha2-test-vectors START_TEST(test_pbkdf2_hmac_sha256) { @@ -2143,6 +2352,14 @@ Suite *test_suite(void) tcase_add_test(tc, test_aes); suite_add_tcase(s, tc); + tc = tcase_create("sha256"); + tcase_add_test(tc, test_sha256); + suite_add_tcase(s, tc); + + tc = tcase_create("sha512"); + tcase_add_test(tc, test_sha512); + suite_add_tcase(s, tc); + tc = tcase_create("pbkdf2"); tcase_add_test(tc, test_pbkdf2_hmac_sha256); tcase_add_test(tc, test_pbkdf2_hmac_sha512); From 245e2cc23d6c1960434a24ac14fc363b2645949e Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 15 Aug 2016 15:05:32 +0200 Subject: [PATCH 297/627] update bip39bruteforce tool --- tools/bip39bruteforce.c | 46 +++++++++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/tools/bip39bruteforce.c b/tools/bip39bruteforce.c index a55158828..f27007b78 100644 --- a/tools/bip39bruteforce.c +++ b/tools/bip39bruteforce.c @@ -6,30 +6,41 @@ #include "ecdsa.h" #include "curves.h" -char passphrase[256]; +char iter[256]; uint8_t seed[512 / 8]; uint8_t addr[21], pubkeyhash[20]; int count = 0, found = 0; HDNode node; clock_t start; -// around 120 tries per second +// around 280 tries per second // testing data: // // mnemonic: "all all all all all all all all all all all all" +// address: "1JAd7XCBzGudGpJQSDSfpmJhiygtLQWaGL" +// passphrase: "" +// +// mnemonic: "all all all all all all all all all all all all" // address: "1N3uJ5AU3FTYQ1ZQgTMtYmgSvMBmQiGVBS" // passphrase: "testing" int main(int argc, char **argv) { - if (argc != 3) { - fprintf(stderr, "Usage: bip39bruteforce mnemonic address\n"); + if (argc != 2 && argc != 3) { + fprintf(stderr, "Usage: bip39bruteforce address [mnemonic]\n"); return 1; } - const char *mnemonic = argv[1]; - const char *address = argv[2]; - if (!mnemonic_check(mnemonic)) { + const char *address = argv[1]; + const char *mnemonic, *item; + if (argc == 3) { + mnemonic = argv[2]; + item = "passphrase"; + } else { + mnemonic = NULL; + item = "mnemonic"; + } + if (mnemonic && !mnemonic_check(mnemonic)) { fprintf(stderr, "\"%s\" is not a valid mnemonic\n", mnemonic); return 2; } @@ -37,23 +48,28 @@ int main(int argc, char **argv) fprintf(stderr, "\"%s\" is not a valid address\n", address); return 3; } - printf("Reading passphrases from stdin ...\n"); + printf("Reading %ss from stdin ...\n", item); start = clock(); for (;;) { - if (fgets(passphrase, 256, stdin) == NULL) break; - int len = strlen(passphrase); + if (fgets(iter, 256, stdin) == NULL) break; + int len = strlen(iter); if (len <= 0) { continue; } count++; - passphrase[len - 1] = 0; - mnemonic_to_seed(mnemonic, passphrase, seed, NULL); + iter[len - 1] = 0; + if (mnemonic) { + mnemonic_to_seed(mnemonic, iter, seed, NULL); + } else { + mnemonic_to_seed(iter, "", seed, NULL); + } hdnode_from_seed(seed, 512 / 8, SECP256K1_NAME, &node); hdnode_private_ckd_prime(&node, 44); hdnode_private_ckd_prime(&node, 0); hdnode_private_ckd_prime(&node, 0); hdnode_private_ckd(&node, 0); hdnode_private_ckd(&node, 0); + hdnode_fill_public_key(&node); ecdsa_get_pubkeyhash(node.public_key, pubkeyhash); if (memcmp(addr + 1, pubkeyhash, 20) == 0) { found = 1; @@ -61,11 +77,11 @@ int main(int argc, char **argv) } } float dur = (float)(clock() - start) / CLOCKS_PER_SEC; - printf("Tried %d passphrases in %f seconds = %f tries/second\n", count, dur, (float)count/dur); + printf("Tried %d %ss in %f seconds = %f tries/second\n", count, item, dur, (float)count/dur); if (found) { - printf("Correct passphrase found! :-)\n\"%s\"\n", passphrase); + printf("Correct %s found! :-)\n\"%s\"\n", item, iter); return 0; } - printf("Correct passphrase not found. :-(\n"); + printf("Correct %s not found. :-(\n", item); return 4; } From f4ed55377d67b48a94c219313faa3035186369cb Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Thu, 18 Aug 2016 16:21:33 +0200 Subject: [PATCH 298/627] Moved get_ethereum_address from ecdsa to bip32 The new name of the function is `hdnode_get_ethereum_address` and it gets a hdnode as input as opposed to a public key. This also avoids first computing the compressed public key and then uncompressing it. Test cases were adapted to work with new function. The test-vectors are the same as for bip32 and independently checked with an adhoc python implementation. --- bip32.c | 24 ++++++++++++++++ bip32.h | 4 +++ ecdsa.c | 24 ---------------- ecdsa.h | 1 - tests.c | 87 ++++++++++++++++++++++++++++++++++++++++----------------- 5 files changed, 90 insertions(+), 50 deletions(-) diff --git a/bip32.c b/bip32.c index f6f4de653..fac809eac 100644 --- a/bip32.c +++ b/bip32.c @@ -37,6 +37,9 @@ #include "secp256k1.h" #include "nist256p1.h" #include "ed25519.h" +#if USE_ETHEREUM +#include "sha3.h" +#endif const curve_info ed25519_info = { /* bip32_name */ @@ -389,6 +392,27 @@ void hdnode_fill_public_key(HDNode *node) } } +#if USE_ETHEREUM +int hdnode_get_ethereum_pubkeyhash(const HDNode *node, uint8_t *pubkeyhash) +{ + uint8_t buf[65]; + SHA3_CTX ctx; + + /* get uncompressed public key */ + ecdsa_get_public_key65(node->curve->params, node->private_key, buf); + + /* compute sha3 of x and y coordinate without 04 prefix */ + sha3_256_Init(&ctx); + sha3_Update(&ctx, buf + 1, 64); + keccak_Final(&ctx, buf); + + /* result are the least significant 160 bits */ + memcpy(pubkeyhash, buf + 12, 20); + + return 1; +} +#endif + // msg is a data to be signed // msg_len is the message length int hdnode_sign(HDNode *node, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby) diff --git a/bip32.h b/bip32.h index e674b5d3b..1cf031220 100644 --- a/bip32.h +++ b/bip32.h @@ -67,6 +67,10 @@ uint32_t hdnode_fingerprint(HDNode *node); void hdnode_fill_public_key(HDNode *node); +#if USE_ETHEREUM +int hdnode_get_ethereum_pubkeyhash(const HDNode *node, uint8_t *pubkeyhash); +#endif + int hdnode_sign(HDNode *node, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby); int hdnode_sign_digest(HDNode *node, const uint8_t *digest, uint8_t *sig, uint8_t *pby); diff --git a/ecdsa.c b/ecdsa.c index cbb114b8a..fbde6b9a2 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -36,9 +36,6 @@ #include "base58.h" #include "macros.h" #include "secp256k1.h" -#if USE_ETHEREUM -#include "sha3.h" -#endif // Set cp2 = cp1 void point_copy(const curve_point *cp1, curve_point *cp2) @@ -847,27 +844,6 @@ void ecdsa_get_pubkeyhash(const uint8_t *pub_key, uint8_t *pubkeyhash) MEMSET_BZERO(h, sizeof(h)); } -#if USE_ETHEREUM -int ecdsa_get_ethereum_pubkeyhash(const uint8_t *pub_key, uint8_t *pubkeyhash) -{ - uint8_t h[65]; - SHA3_CTX ctx; - - if (!ecdsa_uncompress_pubkey(&secp256k1, pub_key, h)) { - return 0; - } - - sha3_256_Init(&ctx); - sha3_Update(&ctx, h + 1, 64); - keccak_Final(&ctx, h); - - // least significant 160 bits - memcpy(pubkeyhash, h + 12, 20); - - return 1; -} -#endif - void ecdsa_get_address_raw(const uint8_t *pub_key, uint8_t version, uint8_t *addr_raw) { addr_raw[0] = version; diff --git a/ecdsa.h b/ecdsa.h index 2950a314f..b7c22aa4d 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -66,7 +66,6 @@ int ecdsa_sign_digest(const ecdsa_curve *curve, const uint8_t *priv_key, const u void ecdsa_get_public_key33(const ecdsa_curve *curve, const uint8_t *priv_key, uint8_t *pub_key); void ecdsa_get_public_key65(const ecdsa_curve *curve, const uint8_t *priv_key, uint8_t *pub_key); void ecdsa_get_pubkeyhash(const uint8_t *pub_key, uint8_t *pubkeyhash); -int ecdsa_get_ethereum_pubkeyhash(const uint8_t *pub_key, uint8_t *pubkeyhash); void ecdsa_get_address_raw(const uint8_t *pub_key, uint8_t version, uint8_t *addr_raw); void ecdsa_get_address(const uint8_t *pub_key, uint8_t version, char *addr, int addrsize); void ecdsa_get_wif(const uint8_t *priv_key, uint8_t version, char *wif, int wifsize); diff --git a/tests.c b/tests.c index baaf0d187..6dae737c8 100644 --- a/tests.c +++ b/tests.c @@ -2239,47 +2239,84 @@ END_TEST START_TEST(test_ethereum_pubkeyhash) { uint8_t pubkeyhash[20]; - uint8_t pub_key[65]; int res; + HDNode node; - memcpy(pub_key, fromhex("0226659c1cf7321c178c07437150639ff0c5b7679c7ea195253ed9abda2e081a37"), 33); - res = ecdsa_get_ethereum_pubkeyhash(pub_key, pubkeyhash); + // init m + hdnode_from_seed(fromhex("000102030405060708090a0b0c0d0e0f"), 16, SECP256K1_NAME, &node); + + // [Chain m] + res = hdnode_get_ethereum_pubkeyhash(&node, pubkeyhash); ck_assert_int_eq(res, 1); - ck_assert_mem_eq(pubkeyhash, fromhex("dfec07843c46f3fb5e5ef8b70b845231a97ed2c8"), 20); + ck_assert_mem_eq(pubkeyhash, fromhex("056db290f8ba3250ca64a45d16284d04bc6f5fbf"), 20); - memcpy(pub_key, fromhex("025b1654a0e78d28810094f6c5a96b8efb8a65668b578f170ac2b1f83bc63ba856"), 33); - res = ecdsa_get_ethereum_pubkeyhash(pub_key, pubkeyhash); + // [Chain m/0'] + hdnode_private_ckd_prime(&node, 0); + res = hdnode_get_ethereum_pubkeyhash(&node, pubkeyhash); ck_assert_int_eq(res, 1); - ck_assert_mem_eq(pubkeyhash, fromhex("aa2685dbc0a1820fc4bb03c3154d1cc0b26411ee"), 20); + ck_assert_mem_eq(pubkeyhash, fromhex("bf6e48966d0dcf553b53e7b56cb2e0e72dca9e19"), 20); - memcpy(pub_key, fromhex("03433f246a12e6486a51ff08802228c61cf895175a9b49ed4766ea9a9294a3c7fe"), 33); - res = ecdsa_get_ethereum_pubkeyhash(pub_key, pubkeyhash); + // [Chain m/0'/1] + hdnode_private_ckd(&node, 1); + res = hdnode_get_ethereum_pubkeyhash(&node, pubkeyhash); ck_assert_int_eq(res, 1); - ck_assert_mem_eq(pubkeyhash, fromhex("86193afd976244f39f0e9d42a1d2c090080754f1"), 20); + ck_assert_mem_eq(pubkeyhash, fromhex("29379f45f515c494483298225d1b347f73d1babf"), 20); - memcpy(pub_key, fromhex("03aeb03abeee0f0f8b4f7a5d65ce31f9570cef9f72c2dd8a19b4085a30ab033d48"), 33); - res = ecdsa_get_ethereum_pubkeyhash(pub_key, pubkeyhash); + // [Chain m/0'/1/2'] + hdnode_private_ckd_prime(&node, 2); + res = hdnode_get_ethereum_pubkeyhash(&node, pubkeyhash); ck_assert_int_eq(res, 1); - ck_assert_mem_eq(pubkeyhash, fromhex("330b7636bff2c8ea728170042ab6af0b826cbdc0"), 20); + ck_assert_mem_eq(pubkeyhash, fromhex("d8e85fbbb4b3b3c71c4e63a5580d0c12fb4d2f71"), 20); - memcpy(pub_key, fromhex("0496e8f2093f018aff6c2e2da5201ee528e2c8accbf9cac51563d33a7bb74a016054201c025e2a5d96b1629b95194e806c63eb96facaedc733b1a4b70ab3b33e3a"), 65); - res = ecdsa_get_ethereum_pubkeyhash(pub_key, pubkeyhash); + // [Chain m/0'/1/2'/2] + hdnode_private_ckd(&node, 2); + res = hdnode_get_ethereum_pubkeyhash(&node, pubkeyhash); ck_assert_int_eq(res, 1); - ck_assert_mem_eq(pubkeyhash, fromhex("10027a9bef3e98be693f8fb4c02f4a7421cdf384"), 20); + ck_assert_mem_eq(pubkeyhash, fromhex("1d3462d2319ac0bfc1a52e177a9d372492752130"), 20); - memcpy(pub_key, fromhex("0498010f8a687439ff497d3074beb4519754e72c4b6220fb669224749591dde416f3961f8ece18f8689bb32235e436874d2174048b86118a00afbd5a4f33a24f0f"), 65); - res = ecdsa_get_ethereum_pubkeyhash(pub_key, pubkeyhash); + // [Chain m/0'/1/2'/2/1000000000] + hdnode_private_ckd(&node, 1000000000); + res = hdnode_get_ethereum_pubkeyhash(&node, pubkeyhash); ck_assert_int_eq(res, 1); - ck_assert_mem_eq(pubkeyhash, fromhex("6d9baaf3db174b9ea498081707289c228108aa9e"), 20); + ck_assert_mem_eq(pubkeyhash, fromhex("73659c60270d326c06ac204f1a9c63f889a3d14b"), 20); - memcpy(pub_key, fromhex("04f80490839af36d13701ec3f9eebdac901b51c362119d74553a3c537faff31b17e2a59ebddbdac9e87b816307a7ed5b826b8f40b92719086238e1bebf19b77a4d"), 65); - res = ecdsa_get_ethereum_pubkeyhash(pub_key, pubkeyhash); + // init m + hdnode_from_seed(fromhex("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), 64, SECP256K1_NAME, &node); + + // [Chain m] + res = hdnode_get_ethereum_pubkeyhash(&node, pubkeyhash); ck_assert_int_eq(res, 1); - ck_assert_mem_eq(pubkeyhash, fromhex("addcb46a5ae157c837682689fcd4f80a76bb7740"), 20); + ck_assert_mem_eq(pubkeyhash, fromhex("6dd2a6f3b05fd15d901fbeec61b87a34bdcfb843"), 20); - memcpy(pub_key, fromhex("00"), 1); - res = ecdsa_get_ethereum_pubkeyhash(pub_key, pubkeyhash); - ck_assert_int_eq(res, 0); + // [Chain m/0] + hdnode_private_ckd(&node, 0); + res = hdnode_get_ethereum_pubkeyhash(&node, pubkeyhash); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(pubkeyhash, fromhex("abbcd4471a0b6e76a2f6fdc44008fe53831e208e"), 20); + + // [Chain m/0/2147483647'] + hdnode_private_ckd_prime(&node, 2147483647); + res = hdnode_get_ethereum_pubkeyhash(&node, pubkeyhash); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(pubkeyhash, fromhex("40ef2cef1b2588ae862e7a511162ec7ff33c30fd"), 20); + + // [Chain m/0/2147483647'/1] + hdnode_private_ckd(&node, 1); + res = hdnode_get_ethereum_pubkeyhash(&node, pubkeyhash); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(pubkeyhash, fromhex("3f2e8905488f795ebc84a39560d133971ccf9b50"), 20); + + // [Chain m/0/2147483647'/1/2147483646'] + hdnode_private_ckd_prime(&node, 2147483646); + res = hdnode_get_ethereum_pubkeyhash(&node, pubkeyhash); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(pubkeyhash, fromhex("a5016fdf975f767e4e6f355c7a82efa69bf42ea7"), 20); + + // [Chain m/0/2147483647'/1/2147483646'/2] + hdnode_private_ckd(&node, 2); + res = hdnode_get_ethereum_pubkeyhash(&node, pubkeyhash); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(pubkeyhash, fromhex("8ff2a9f7e7917804e8c8ec150d931d9c5a6fbc50"), 20); } END_TEST From a17bac1ab312765099be9f60732d4a71e2fe23b5 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sun, 21 Aug 2016 20:25:35 +0100 Subject: [PATCH 299/627] gitignore: ignore *.d files Makefile in trezor/trezor-mcu uses dependency generation now, without ignoring these files, git marks the submodules as dirty. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index c4255cff7..5b2841e7f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ *.o +*.d *.exe *~ test-openssl From d890f4d859abb2bb64ecc59b93bea13fe7ec5642 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Thu, 25 Aug 2016 22:48:06 +0100 Subject: [PATCH 300/627] tests: include bn_read_be --- tests.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tests.c b/tests.c index 6dae737c8..5666cb8e3 100644 --- a/tests.c +++ b/tests.c @@ -83,6 +83,24 @@ char *tohex(const uint8_t *bin, size_t l) #define ck_assert_mem_eq(X, Y, L) _ck_assert_mem(X, Y, L, ==) #define ck_assert_mem_ne(X, Y, L) _ck_assert_mem(X, Y, L, !=) +START_TEST(test_bignum_read_be) +{ + bignum256 a; + uint8_t input[32]; + + memcpy(input, fromhex("c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd5"), 32); + + bn_read_be(input, &a); + + bignum256 b = { { 0x286d8bd5, 0x380c7c17, 0x3c6a2ec1, 0x2d787ef5, 0x14437cd3, 0x25a043f8, 0x1dd5263f, 0x33a162c3, 0x0000c55e } }; + + for (int i = 0; i < 9; i++) { + ck_assert_int_eq(a.val[i], b.val[i]); + } +} +END_TEST + + // from https://github.com/bitcoin/bitcoin/blob/master/src/test/data/base58_keys_valid.json START_TEST(test_base58) { @@ -2327,6 +2345,10 @@ Suite *test_suite(void) Suite *s = suite_create("trezor-crypto"); TCase *tc; + tc = tcase_create("bignum"); + tcase_add_test(tc, test_bignum_read_be); + suite_add_tcase(s, tc); + tc = tcase_create("base58"); tcase_add_test(tc, test_base58); suite_add_tcase(s, tc); From 8eebfb1986938faf1d891414dcee771f2882ba9c Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Thu, 25 Aug 2016 22:51:34 +0100 Subject: [PATCH 301/627] tests: add bn_write_be --- tests.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests.c b/tests.c index 5666cb8e3..2fb0fb037 100644 --- a/tests.c +++ b/tests.c @@ -100,6 +100,17 @@ START_TEST(test_bignum_read_be) } END_TEST +START_TEST(test_bignum_write_be) +{ + bignum256 a = { { 0x286d8bd5, 0x380c7c17, 0x3c6a2ec1, 0x2d787ef5, 0x14437cd3, 0x25a043f8, 0x1dd5263f, 0x33a162c3, 0x0000c55e } }; + uint8_t tmp[32]; + + bn_write_be(&a, tmp); + + ck_assert_mem_eq(tmp, fromhex("c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd5"), 32); +} +END_TEST + // from https://github.com/bitcoin/bitcoin/blob/master/src/test/data/base58_keys_valid.json START_TEST(test_base58) @@ -2347,6 +2358,7 @@ Suite *test_suite(void) tc = tcase_create("bignum"); tcase_add_test(tc, test_bignum_read_be); + tcase_add_test(tc, test_bignum_write_be); suite_add_tcase(s, tc); tc = tcase_create("base58"); From ec316b6afc21d2c327a163964b113107f7e45734 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Thu, 25 Aug 2016 23:07:28 +0100 Subject: [PATCH 302/627] tests: add bn_is_equal --- tests.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests.c b/tests.c index 2fb0fb037..fc1f83a63 100644 --- a/tests.c +++ b/tests.c @@ -111,6 +111,17 @@ START_TEST(test_bignum_write_be) } END_TEST +START_TEST(test_bignum_equal) +{ + bignum256 a = { { 0x286d8bd5, 0x380c7c17, 0x3c6a2ec1, 0x2d787ef5, 0x14437cd3, 0x25a043f8, 0x1dd5263f, 0x33a162c3, 0x0000c55e } }; + bignum256 b = { { 0x286d8bd5, 0x380c7c17, 0x3c6a2ec1, 0x2d787ef5, 0x14437cd3, 0x25a043f8, 0x1dd5263f, 0x33a162c3, 0x0000c55e } }; + bignum256 c = { { 0, } }; + + ck_assert_int_eq(bn_is_equal(&a, &b), 1); + ck_assert_int_eq(bn_is_equal(&c, &c), 1); + ck_assert_int_eq(bn_is_equal(&a, &c), 0); +} +END_TEST // from https://github.com/bitcoin/bitcoin/blob/master/src/test/data/base58_keys_valid.json START_TEST(test_base58) @@ -2359,6 +2370,7 @@ Suite *test_suite(void) tc = tcase_create("bignum"); tcase_add_test(tc, test_bignum_read_be); tcase_add_test(tc, test_bignum_write_be); + tcase_add_test(tc, test_bignum_equal); suite_add_tcase(s, tc); tc = tcase_create("base58"); From 62a0db8c4e680eafcc48730131216002601f67c0 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Thu, 25 Aug 2016 23:18:24 +0100 Subject: [PATCH 303/627] bignum: introduce read/write_le --- CONTRIBUTORS | 1 + bignum.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ bignum.h | 10 ++++++++++ tests.c | 32 ++++++++++++++++++++++++++++++++ 4 files changed, 95 insertions(+) diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 7e5175b01..b5fc5500a 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -4,6 +4,7 @@ Jochen Hoenicke Dustin Laurence Ondrej Mikle Roman Zeyde +Alex Beregszaszi netanelkl Jan Pochyla Ondrej Mikle diff --git a/bignum.c b/bignum.c index 20e3718c3..d2ebd6350 100644 --- a/bignum.c +++ b/bignum.c @@ -2,6 +2,7 @@ * Copyright (c) 2013-2014 Tomas Dzetkulic * Copyright (c) 2013-2014 Pavol Rusnak * Copyright (c) 2015 Jochen Hoenicke + * Copyright (c) 2016 Alex Beregszaszi * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the "Software"), @@ -69,6 +70,22 @@ inline void write_be(uint8_t *data, uint32_t x) data[3] = x; } +inline uint32_t read_le(const uint8_t *data) +{ + return (((uint32_t)data[3]) << 24) | + (((uint32_t)data[2]) << 16) | + (((uint32_t)data[1]) << 8) | + (((uint32_t)data[0])); +} + +inline void write_le(uint8_t *data, uint32_t x) +{ + data[3] = x >> 24; + data[2] = x >> 16; + data[1] = x >> 8; + data[0] = x; +} + // convert a raw bigendian 256 bit value into a normalized bignum. // out_number is partly reduced (since it fits in 256 bit). void bn_read_be(const uint8_t *in_number, bignum256 *out_number) @@ -104,6 +121,41 @@ void bn_write_be(const bignum256 *in_number, uint8_t *out_number) } } +// convert a raw little endian 256 bit value into a normalized bignum. +// out_number is partly reduced (since it fits in 256 bit). +void bn_read_le(const uint8_t *in_number, bignum256 *out_number) +{ + int i; + uint32_t temp = 0; + for (i = 0; i < 8; i++) { + // invariant: temp = (in_number % 2^(32i)) >> 30i + // get next limb = (in_number % 2^(32(i+1))) >> 32i + uint32_t limb = read_le(in_number + i * 4); + // temp = (in_number % 2^(32(i+1))) << 30i + temp |= limb << (2*i); + // store 30 bits into val[i] + out_number->val[i]= temp & 0x3FFFFFFF; + // prepare temp for next round + temp = limb >> (30 - 2*i); + } + out_number->val[8] = temp; +} + +// convert a normalized bignum to a raw little endian 256 bit number. +// in_number must be fully reduced. +void bn_write_le(const bignum256 *in_number, uint8_t *out_number) +{ + int i; + uint32_t temp = in_number->val[8] << 16; + for (i = 0; i < 8; i++) { + // invariant: temp = (in_number >> 30*(8-i)) << (16 + 2i) + uint32_t limb = in_number->val[7 - i]; + temp |= limb >> (14 - 2*i); + write_le(out_number + (7 - i) * 4, temp); + temp = limb << (18 + 2*i); + } +} + // sets a bignum to zero. void bn_zero(bignum256 *a) { diff --git a/bignum.h b/bignum.h index 4b51c5d42..65bea7ba7 100644 --- a/bignum.h +++ b/bignum.h @@ -39,10 +39,20 @@ uint32_t read_be(const uint8_t *data); // write 4 big endian bytes void write_be(uint8_t *data, uint32_t x); +// read 4 little endian bytes into uint32 +uint32_t read_le(const uint8_t *data); + +// write 4 little endian bytes +void write_le(uint8_t *data, uint32_t x); + void bn_read_be(const uint8_t *in_number, bignum256 *out_number); void bn_write_be(const bignum256 *in_number, uint8_t *out_number); +void bn_read_le(const uint8_t *in_number, bignum256 *out_number); + +void bn_write_le(const bignum256 *in_number, uint8_t *out_number); + void bn_zero(bignum256 *a); int bn_is_zero(const bignum256 *a); diff --git a/tests.c b/tests.c index fc1f83a63..f1e10ba2b 100644 --- a/tests.c +++ b/tests.c @@ -123,6 +123,36 @@ START_TEST(test_bignum_equal) } END_TEST +START_TEST(test_bignum_read_le) +{ + bignum256 a; + bignum256 b; + + bn_read_be(fromhex("c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd5"), &a); + bn_read_le(fromhex("d58b6de8051f031eeca2c6d7fbe1b5d37c4314fe1068f96352dd0d8b85ce5ec5"), &b); + + ck_assert_int_eq(bn_is_equal(&a, &b), 1); +} +END_TEST + +START_TEST(test_bignum_write_le) +{ + bignum256 a; + bignum256 b; + uint8_t tmp[32]; + + bn_read_be(fromhex("c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd5"), &a); + bn_write_le(&a, tmp); + + bn_read_le(tmp, &b); + ck_assert_int_eq(bn_is_equal(&a, &b), 1); + + bn_read_be(fromhex("d58b6de8051f031eeca2c6d7fbe1b5d37c4314fe1068f96352dd0d8b85ce5ec5"), &a); + bn_read_be(tmp, &b); + ck_assert_int_eq(bn_is_equal(&a, &b), 1); +} +END_TEST + // from https://github.com/bitcoin/bitcoin/blob/master/src/test/data/base58_keys_valid.json START_TEST(test_base58) { @@ -2371,6 +2401,8 @@ Suite *test_suite(void) tcase_add_test(tc, test_bignum_read_be); tcase_add_test(tc, test_bignum_write_be); tcase_add_test(tc, test_bignum_equal); + tcase_add_test(tc, test_bignum_read_le); + tcase_add_test(tc, test_bignum_write_le); suite_add_tcase(s, tc); tc = tcase_create("base58"); From dd25a2ee5a93ab5804b08a826258181ab24e46a6 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Thu, 25 Aug 2016 23:20:09 +0100 Subject: [PATCH 304/627] bignum: introduce copy --- bignum.c | 9 +++++++++ bignum.h | 2 ++ tests.c | 13 +++++++++++++ 3 files changed, 24 insertions(+) diff --git a/bignum.c b/bignum.c index d2ebd6350..a0364309b 100644 --- a/bignum.c +++ b/bignum.c @@ -156,6 +156,15 @@ void bn_write_le(const bignum256 *in_number, uint8_t *out_number) } } +// copies number a to b +void bn_copy(bignum256 *a, bignum256 *b) +{ + int i; + for (i = 0; i < 9; i++) { + b->val[i] = a->val[i]; + } +} + // sets a bignum to zero. void bn_zero(bignum256 *a) { diff --git a/bignum.h b/bignum.h index 65bea7ba7..fd040c8dc 100644 --- a/bignum.h +++ b/bignum.h @@ -53,6 +53,8 @@ void bn_read_le(const uint8_t *in_number, bignum256 *out_number); void bn_write_le(const bignum256 *in_number, uint8_t *out_number); +void bn_copy(bignum256 *a, bignum256 *b); + void bn_zero(bignum256 *a); int bn_is_zero(const bignum256 *a); diff --git a/tests.c b/tests.c index f1e10ba2b..82d47ab8c 100644 --- a/tests.c +++ b/tests.c @@ -153,6 +153,18 @@ START_TEST(test_bignum_write_le) } END_TEST +START_TEST(test_bignum_copy) +{ + bignum256 a; + bignum256 b; + + bn_read_be(fromhex("c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd5"), &a); + bn_copy(&a, &b); + + ck_assert_int_eq(bn_is_equal(&a, &b), 1); +} +END_TEST + // from https://github.com/bitcoin/bitcoin/blob/master/src/test/data/base58_keys_valid.json START_TEST(test_base58) { @@ -2403,6 +2415,7 @@ Suite *test_suite(void) tcase_add_test(tc, test_bignum_equal); tcase_add_test(tc, test_bignum_read_le); tcase_add_test(tc, test_bignum_write_le); + tcase_add_test(tc, test_bignum_copy); suite_add_tcase(s, tc); tc = tcase_create("base58"); From 339d2f44a9c124de3e0a592928d90c8b4eb158fd Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Thu, 25 Aug 2016 23:55:40 +0100 Subject: [PATCH 305/627] bignum: introduce is_even/is_odd --- bignum.h | 9 +++++++++ tests.c | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/bignum.h b/bignum.h index fd040c8dc..863b05ccc 100644 --- a/bignum.h +++ b/bignum.h @@ -1,6 +1,7 @@ /** * Copyright (c) 2013-2014 Tomas Dzetkulic * Copyright (c) 2013-2014 Pavol Rusnak + * Copyright (c) 2016 Alex Beregszaszi * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the "Software"), @@ -59,6 +60,14 @@ void bn_zero(bignum256 *a); int bn_is_zero(const bignum256 *a); +static inline int bn_is_even(const bignum256 *a) { + return (a->val[0] & 1) == 0; +} + +static inline int bn_is_odd(const bignum256 *a) { + return (a->val[0] & 1) == 1; +} + int bn_is_less(const bignum256 *a, const bignum256 *b); int bn_is_equal(const bignum256 *a, const bignum256 *b); diff --git a/tests.c b/tests.c index 82d47ab8c..91acb59b4 100644 --- a/tests.c +++ b/tests.c @@ -165,6 +165,36 @@ START_TEST(test_bignum_copy) } END_TEST +START_TEST(test_bignum_is_even) +{ + bignum256 a; + + bn_read_be(fromhex("c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd5"), &a); + ck_assert_int_eq(bn_is_even(&a), 0); + + bn_read_be(fromhex("c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd2"), &a); + ck_assert_int_eq(bn_is_even(&a), 1); + + bn_read_be(fromhex("c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd0"), &a); + ck_assert_int_eq(bn_is_even(&a), 1); +} +END_TEST + +START_TEST(test_bignum_is_odd) +{ + bignum256 a; + + bn_read_be(fromhex("c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd5"), &a); + ck_assert_int_eq(bn_is_odd(&a), 1); + + bn_read_be(fromhex("c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd2"), &a); + ck_assert_int_eq(bn_is_odd(&a), 0); + + bn_read_be(fromhex("c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd0"), &a); + ck_assert_int_eq(bn_is_odd(&a), 0); +} +END_TEST + // from https://github.com/bitcoin/bitcoin/blob/master/src/test/data/base58_keys_valid.json START_TEST(test_base58) { @@ -2416,6 +2446,8 @@ Suite *test_suite(void) tcase_add_test(tc, test_bignum_read_le); tcase_add_test(tc, test_bignum_write_le); tcase_add_test(tc, test_bignum_copy); + tcase_add_test(tc, test_bignum_is_even); + tcase_add_test(tc, test_bignum_is_odd); suite_add_tcase(s, tc); tc = tcase_create("base58"); From d061139da986fa66d171dae555da58922d79a623 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Fri, 26 Aug 2016 00:12:02 +0100 Subject: [PATCH 306/627] bignum: introduce load uint32/uint64 --- bignum.c | 26 ++++++++++++++++++++++++++ bignum.h | 4 ++++ tests.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 82 insertions(+) diff --git a/bignum.c b/bignum.c index a0364309b..23db0d477 100644 --- a/bignum.c +++ b/bignum.c @@ -156,6 +156,32 @@ void bn_write_le(const bignum256 *in_number, uint8_t *out_number) } } +void bn_load_uint32(uint32_t in_number, bignum256 *out_number) +{ + out_number->val[0] = in_number & 0x3FFFFFFF; + out_number->val[1] = in_number >> 30; + out_number->val[2] = 0; + out_number->val[3] = 0; + out_number->val[4] = 0; + out_number->val[5] = 0; + out_number->val[6] = 0; + out_number->val[7] = 0; + out_number->val[8] = 0; +} + +void bn_load_uint64(uint64_t in_number, bignum256 *out_number) +{ + out_number->val[0] = in_number & 0x3FFFFFFF; + out_number->val[1] = (in_number >>= 30) & 0x3FFFFFFF; + out_number->val[2] = in_number >>= 30; + out_number->val[3] = 0; + out_number->val[4] = 0; + out_number->val[5] = 0; + out_number->val[6] = 0; + out_number->val[7] = 0; + out_number->val[8] = 0; +} + // copies number a to b void bn_copy(bignum256 *a, bignum256 *b) { diff --git a/bignum.h b/bignum.h index 863b05ccc..f7ee44d18 100644 --- a/bignum.h +++ b/bignum.h @@ -54,6 +54,10 @@ void bn_read_le(const uint8_t *in_number, bignum256 *out_number); void bn_write_le(const bignum256 *in_number, uint8_t *out_number); +void bn_load_uint32(uint32_t in_number, bignum256 *out_number); + +void bn_load_uint64(uint64_t in_number, bignum256 *out_number); + void bn_copy(bignum256 *a, bignum256 *b); void bn_zero(bignum256 *a); diff --git a/tests.c b/tests.c index 91acb59b4..f61ee039e 100644 --- a/tests.c +++ b/tests.c @@ -153,6 +153,56 @@ START_TEST(test_bignum_write_le) } END_TEST +START_TEST(test_bignum_load_uint32) +{ + bignum256 a; + bignum256 b; + + // lowest 30 bits set + bn_read_be(fromhex("000000000000000000000000000000000000000000000000000000003fffffff"), &a); + bn_load_uint32(0x3fffffff, &b); + + ck_assert_int_eq(bn_is_equal(&a, &b), 1); + + // bit 31 set + bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000040000000"), &a); + bn_load_uint32(0x40000000, &b); + ck_assert_int_eq(bn_is_equal(&a, &b), 1); +} +END_TEST + +START_TEST(test_bignum_load_uint64) +{ + bignum256 a; + bignum256 b; + + // lowest 30 bits set + bn_read_be(fromhex("000000000000000000000000000000000000000000000000000000003fffffff"), &a); + bn_load_uint64(0x3fffffff, &b); + ck_assert_int_eq(bn_is_equal(&a, &b), 1); + + // bit 31 set + bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000040000000"), &a); + bn_load_uint64(0x40000000, &b); + ck_assert_int_eq(bn_is_equal(&a, &b), 1); + + // bit 33 set + bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000100000000"), &a); + bn_load_uint64(0x100000000LL, &b); + ck_assert_int_eq(bn_is_equal(&a, &b), 1); + + // bit 61 set + bn_read_be(fromhex("0000000000000000000000000000000000000000000000002000000000000000"), &a); + bn_load_uint64(0x2000000000000000LL, &b); + ck_assert_int_eq(bn_is_equal(&a, &b), 1); + + // all 64 bits set + bn_read_be(fromhex("000000000000000000000000000000000000000000000000ffffffffffffffff"), &a); + bn_load_uint64(0xffffffffffffffffLL, &b); + ck_assert_int_eq(bn_is_equal(&a, &b), 1); +} +END_TEST + START_TEST(test_bignum_copy) { bignum256 a; @@ -2445,6 +2495,8 @@ Suite *test_suite(void) tcase_add_test(tc, test_bignum_equal); tcase_add_test(tc, test_bignum_read_le); tcase_add_test(tc, test_bignum_write_le); + tcase_add_test(tc, test_bignum_load_uint32); + tcase_add_test(tc, test_bignum_load_uint64); tcase_add_test(tc, test_bignum_copy); tcase_add_test(tc, test_bignum_is_even); tcase_add_test(tc, test_bignum_is_odd); From 97454d9cbc81b81d36ecfbd3a4612bae0ee3acf2 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Fri, 26 Aug 2016 01:06:47 +0100 Subject: [PATCH 307/627] bignum: use the compiler's built in memory copy for bn_copy --- bignum.c | 9 --------- bignum.h | 5 ++++- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/bignum.c b/bignum.c index 23db0d477..7d756e84f 100644 --- a/bignum.c +++ b/bignum.c @@ -182,15 +182,6 @@ void bn_load_uint64(uint64_t in_number, bignum256 *out_number) out_number->val[8] = 0; } -// copies number a to b -void bn_copy(bignum256 *a, bignum256 *b) -{ - int i; - for (i = 0; i < 9; i++) { - b->val[i] = a->val[i]; - } -} - // sets a bignum to zero. void bn_zero(bignum256 *a) { diff --git a/bignum.h b/bignum.h index f7ee44d18..8a770064a 100644 --- a/bignum.h +++ b/bignum.h @@ -58,7 +58,10 @@ void bn_load_uint32(uint32_t in_number, bignum256 *out_number); void bn_load_uint64(uint64_t in_number, bignum256 *out_number); -void bn_copy(bignum256 *a, bignum256 *b); +// copies number a to b +static inline void bn_copy(const bignum256 *a, bignum256 *b) { + *b = *a; +} void bn_zero(bignum256 *a); From 4eb2bd239c1a8e7285d49bff060b071d5fc2b6f9 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Fri, 26 Aug 2016 11:54:55 +0100 Subject: [PATCH 308/627] tests: add bn_zero/bn_is_zero --- tests.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/tests.c b/tests.c index f61ee039e..baefdbf96 100644 --- a/tests.c +++ b/tests.c @@ -123,6 +123,36 @@ START_TEST(test_bignum_equal) } END_TEST +START_TEST(test_bignum_zero) +{ + bignum256 a; + bignum256 b; + + bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000000"), &a); + bn_zero(&b); + + ck_assert_int_eq(bn_is_equal(&a, &b), 1); +} +END_TEST + +START_TEST(test_bignum_is_zero) +{ + bignum256 a; + + bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000000"), &a); + ck_assert_int_eq(bn_is_zero(&a), 1); + + bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000001"), &a); + ck_assert_int_eq(bn_is_zero(&a), 0); + + bn_read_be(fromhex("1000000000000000000000000000000000000000000000000000000000000000"), &a); + ck_assert_int_eq(bn_is_zero(&a), 0); + + bn_read_be(fromhex("f000000000000000000000000000000000000000000000000000000000000000"), &a); + ck_assert_int_eq(bn_is_zero(&a), 0); +} +END_TEST + START_TEST(test_bignum_read_le) { bignum256 a; @@ -2493,6 +2523,8 @@ Suite *test_suite(void) tcase_add_test(tc, test_bignum_read_be); tcase_add_test(tc, test_bignum_write_be); tcase_add_test(tc, test_bignum_equal); + tcase_add_test(tc, test_bignum_zero); + tcase_add_test(tc, test_bignum_is_zero); tcase_add_test(tc, test_bignum_read_le); tcase_add_test(tc, test_bignum_write_le); tcase_add_test(tc, test_bignum_load_uint32); From 29e82018cde093848258f3643ee1775abe3d8985 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Fri, 26 Aug 2016 12:14:01 +0100 Subject: [PATCH 309/627] bignum: rename bn_load_uint* to bn_read_uint* --- bignum.c | 4 ++-- bignum.h | 4 ++-- tests.c | 22 +++++++++++----------- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/bignum.c b/bignum.c index 7d756e84f..7548bd1d3 100644 --- a/bignum.c +++ b/bignum.c @@ -156,7 +156,7 @@ void bn_write_le(const bignum256 *in_number, uint8_t *out_number) } } -void bn_load_uint32(uint32_t in_number, bignum256 *out_number) +void bn_read_uint32(uint32_t in_number, bignum256 *out_number) { out_number->val[0] = in_number & 0x3FFFFFFF; out_number->val[1] = in_number >> 30; @@ -169,7 +169,7 @@ void bn_load_uint32(uint32_t in_number, bignum256 *out_number) out_number->val[8] = 0; } -void bn_load_uint64(uint64_t in_number, bignum256 *out_number) +void bn_read_uint64(uint64_t in_number, bignum256 *out_number) { out_number->val[0] = in_number & 0x3FFFFFFF; out_number->val[1] = (in_number >>= 30) & 0x3FFFFFFF; diff --git a/bignum.h b/bignum.h index 8a770064a..377bf1274 100644 --- a/bignum.h +++ b/bignum.h @@ -54,9 +54,9 @@ void bn_read_le(const uint8_t *in_number, bignum256 *out_number); void bn_write_le(const bignum256 *in_number, uint8_t *out_number); -void bn_load_uint32(uint32_t in_number, bignum256 *out_number); +void bn_read_uint32(uint32_t in_number, bignum256 *out_number); -void bn_load_uint64(uint64_t in_number, bignum256 *out_number); +void bn_read_uint64(uint64_t in_number, bignum256 *out_number); // copies number a to b static inline void bn_copy(const bignum256 *a, bignum256 *b) { diff --git a/tests.c b/tests.c index baefdbf96..804969bbf 100644 --- a/tests.c +++ b/tests.c @@ -183,52 +183,52 @@ START_TEST(test_bignum_write_le) } END_TEST -START_TEST(test_bignum_load_uint32) +START_TEST(test_bignum_read_uint32) { bignum256 a; bignum256 b; // lowest 30 bits set bn_read_be(fromhex("000000000000000000000000000000000000000000000000000000003fffffff"), &a); - bn_load_uint32(0x3fffffff, &b); + bn_read_uint32(0x3fffffff, &b); ck_assert_int_eq(bn_is_equal(&a, &b), 1); // bit 31 set bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000040000000"), &a); - bn_load_uint32(0x40000000, &b); + bn_read_uint32(0x40000000, &b); ck_assert_int_eq(bn_is_equal(&a, &b), 1); } END_TEST -START_TEST(test_bignum_load_uint64) +START_TEST(test_bignum_read_uint64) { bignum256 a; bignum256 b; // lowest 30 bits set bn_read_be(fromhex("000000000000000000000000000000000000000000000000000000003fffffff"), &a); - bn_load_uint64(0x3fffffff, &b); + bn_read_uint64(0x3fffffff, &b); ck_assert_int_eq(bn_is_equal(&a, &b), 1); // bit 31 set bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000040000000"), &a); - bn_load_uint64(0x40000000, &b); + bn_read_uint64(0x40000000, &b); ck_assert_int_eq(bn_is_equal(&a, &b), 1); // bit 33 set bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000100000000"), &a); - bn_load_uint64(0x100000000LL, &b); + bn_read_uint64(0x100000000LL, &b); ck_assert_int_eq(bn_is_equal(&a, &b), 1); // bit 61 set bn_read_be(fromhex("0000000000000000000000000000000000000000000000002000000000000000"), &a); - bn_load_uint64(0x2000000000000000LL, &b); + bn_read_uint64(0x2000000000000000LL, &b); ck_assert_int_eq(bn_is_equal(&a, &b), 1); // all 64 bits set bn_read_be(fromhex("000000000000000000000000000000000000000000000000ffffffffffffffff"), &a); - bn_load_uint64(0xffffffffffffffffLL, &b); + bn_read_uint64(0xffffffffffffffffLL, &b); ck_assert_int_eq(bn_is_equal(&a, &b), 1); } END_TEST @@ -2527,8 +2527,8 @@ Suite *test_suite(void) tcase_add_test(tc, test_bignum_is_zero); tcase_add_test(tc, test_bignum_read_le); tcase_add_test(tc, test_bignum_write_le); - tcase_add_test(tc, test_bignum_load_uint32); - tcase_add_test(tc, test_bignum_load_uint64); + tcase_add_test(tc, test_bignum_read_uint32); + tcase_add_test(tc, test_bignum_read_uint64); tcase_add_test(tc, test_bignum_copy); tcase_add_test(tc, test_bignum_is_even); tcase_add_test(tc, test_bignum_is_odd); From 7956c2f2f133a90b3cccc7742c1fefac34805975 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Fri, 26 Aug 2016 12:31:51 +0100 Subject: [PATCH 310/627] bignum: implement bitcount --- bignum.c | 13 +++++++++++++ bignum.h | 2 ++ tests.c | 19 +++++++++++++++++++ 3 files changed, 34 insertions(+) diff --git a/bignum.c b/bignum.c index 7548bd1d3..1bd65b605 100644 --- a/bignum.c +++ b/bignum.c @@ -182,6 +182,19 @@ void bn_read_uint64(uint64_t in_number, bignum256 *out_number) out_number->val[8] = 0; } +// a must be normalized +int bn_bitcount(const bignum256 *a) +{ + int i; + for (i = 8; i >= 0; i--) { + int tmp = a->val[i]; + if (tmp != 0) { + return i * 30 + (32 - __builtin_clz(tmp)); + } + } + return 0; +} + // sets a bignum to zero. void bn_zero(bignum256 *a) { diff --git a/bignum.h b/bignum.h index 377bf1274..f0877c3e1 100644 --- a/bignum.h +++ b/bignum.h @@ -63,6 +63,8 @@ static inline void bn_copy(const bignum256 *a, bignum256 *b) { *b = *a; } +int bn_bitcount(const bignum256 *a); + void bn_zero(bignum256 *a); int bn_is_zero(const bignum256 *a); diff --git a/tests.c b/tests.c index 804969bbf..b9b87ffc3 100644 --- a/tests.c +++ b/tests.c @@ -275,6 +275,24 @@ START_TEST(test_bignum_is_odd) } END_TEST +START_TEST(test_bignum_bitcount) +{ + bignum256 a; + + bn_zero(&a); + ck_assert_int_eq(bn_bitcount(&a), 0); + + bn_read_uint32(0x3fffffff, &a); + ck_assert_int_eq(bn_bitcount(&a), 30); + + bn_read_uint32(0xffffffff, &a); + ck_assert_int_eq(bn_bitcount(&a), 32); + + bn_read_be(fromhex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), &a); + ck_assert_int_eq(bn_bitcount(&a), 256); +} +END_TEST + // from https://github.com/bitcoin/bitcoin/blob/master/src/test/data/base58_keys_valid.json START_TEST(test_base58) { @@ -2532,6 +2550,7 @@ Suite *test_suite(void) tcase_add_test(tc, test_bignum_copy); tcase_add_test(tc, test_bignum_is_even); tcase_add_test(tc, test_bignum_is_odd); + tcase_add_test(tc, test_bignum_bitcount); suite_add_tcase(s, tc); tc = tcase_create("base58"); From 8581614d66aba51c6f4175eea5192553288037a6 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Fri, 26 Aug 2016 12:41:54 +0100 Subject: [PATCH 311/627] bignum: introduce write uint32/uint64 --- bignum.h | 16 ++++++++++++++++ tests.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/bignum.h b/bignum.h index f0877c3e1..2d7af3c38 100644 --- a/bignum.h +++ b/bignum.h @@ -58,6 +58,22 @@ void bn_read_uint32(uint32_t in_number, bignum256 *out_number); void bn_read_uint64(uint64_t in_number, bignum256 *out_number); +static inline uint32_t bn_write_uint32(const bignum256 *in_number) +{ + return in_number->val[0] | (in_number->val[1] << 30); +} + +static inline uint64_t bn_write_uint64(const bignum256 *in_number) +{ + uint64_t tmp; + tmp = in_number->val[2]; + tmp <<= 30; + tmp |= in_number->val[1]; + tmp <<= 30; + tmp |= in_number->val[0]; + return tmp; +} + // copies number a to b static inline void bn_copy(const bignum256 *a, bignum256 *b) { *b = *a; diff --git a/tests.c b/tests.c index b9b87ffc3..45ef27aa0 100644 --- a/tests.c +++ b/tests.c @@ -233,6 +233,46 @@ START_TEST(test_bignum_read_uint64) } END_TEST +START_TEST(test_bignum_write_uint32) +{ + bignum256 a; + + // lowest 30 bits set + bn_read_be(fromhex("000000000000000000000000000000000000000000000000000000003fffffff"), &a); + ck_assert_int_eq(bn_write_uint32(&a), 0x3fffffff); + + // bit 31 set + bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000040000000"), &a); + ck_assert_int_eq(bn_write_uint32(&a), 0x40000000); +} +END_TEST + +START_TEST(test_bignum_write_uint64) +{ + bignum256 a; + + // lowest 30 bits set + bn_read_be(fromhex("000000000000000000000000000000000000000000000000000000003fffffff"), &a); + ck_assert_int_eq(bn_write_uint64(&a), 0x3fffffff); + + // bit 31 set + bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000040000000"), &a); + ck_assert_int_eq(bn_write_uint64(&a), 0x40000000); + + // bit 33 set + bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000100000000"), &a); + ck_assert_int_eq(bn_write_uint64(&a), 0x100000000LL); + + // bit 61 set + bn_read_be(fromhex("0000000000000000000000000000000000000000000000002000000000000000"), &a); + ck_assert_int_eq(bn_write_uint64(&a), 0x2000000000000000LL); + + // all 64 bits set + bn_read_be(fromhex("000000000000000000000000000000000000000000000000ffffffffffffffff"), &a); + ck_assert_int_eq(bn_write_uint64(&a), 0xffffffffffffffffLL); +} +END_TEST + START_TEST(test_bignum_copy) { bignum256 a; @@ -2547,6 +2587,8 @@ Suite *test_suite(void) tcase_add_test(tc, test_bignum_write_le); tcase_add_test(tc, test_bignum_read_uint32); tcase_add_test(tc, test_bignum_read_uint64); + tcase_add_test(tc, test_bignum_write_uint32); + tcase_add_test(tc, test_bignum_write_uint64); tcase_add_test(tc, test_bignum_copy); tcase_add_test(tc, test_bignum_is_even); tcase_add_test(tc, test_bignum_is_odd); From e1dfa81ec5a8777ba40c52a018aa2bc8bd0aa198 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Sat, 27 Aug 2016 13:07:10 +0100 Subject: [PATCH 312/627] tests: add bn_is_less --- tests.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/tests.c b/tests.c index 45ef27aa0..f2fa3ed3c 100644 --- a/tests.c +++ b/tests.c @@ -111,7 +111,7 @@ START_TEST(test_bignum_write_be) } END_TEST -START_TEST(test_bignum_equal) +START_TEST(test_bignum_is_equal) { bignum256 a = { { 0x286d8bd5, 0x380c7c17, 0x3c6a2ec1, 0x2d787ef5, 0x14437cd3, 0x25a043f8, 0x1dd5263f, 0x33a162c3, 0x0000c55e } }; bignum256 b = { { 0x286d8bd5, 0x380c7c17, 0x3c6a2ec1, 0x2d787ef5, 0x14437cd3, 0x25a043f8, 0x1dd5263f, 0x33a162c3, 0x0000c55e } }; @@ -333,6 +333,25 @@ START_TEST(test_bignum_bitcount) } END_TEST +START_TEST(test_bignum_is_less) +{ + bignum256 a; + bignum256 b; + + bn_read_uint32(0x1234, &a); + bn_read_uint32(0x8765, &b); + + ck_assert_int_eq(bn_is_less(&a, &b), 1); + ck_assert_int_eq(bn_is_less(&b, &a), 0); + + bn_zero(&a); + bn_read_be(fromhex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), &b); + + ck_assert_int_eq(bn_is_less(&a, &b), 1); + ck_assert_int_eq(bn_is_less(&b, &a), 0); +} +END_TEST + // from https://github.com/bitcoin/bitcoin/blob/master/src/test/data/base58_keys_valid.json START_TEST(test_base58) { @@ -2580,7 +2599,7 @@ Suite *test_suite(void) tc = tcase_create("bignum"); tcase_add_test(tc, test_bignum_read_be); tcase_add_test(tc, test_bignum_write_be); - tcase_add_test(tc, test_bignum_equal); + tcase_add_test(tc, test_bignum_is_equal); tcase_add_test(tc, test_bignum_zero); tcase_add_test(tc, test_bignum_is_zero); tcase_add_test(tc, test_bignum_read_le); @@ -2593,6 +2612,7 @@ Suite *test_suite(void) tcase_add_test(tc, test_bignum_is_even); tcase_add_test(tc, test_bignum_is_odd); tcase_add_test(tc, test_bignum_bitcount); + tcase_add_test(tc, test_bignum_is_less); suite_add_tcase(s, tc); tc = tcase_create("base58"); From 7e7e462be71b72d98b8a0dc387dd95b6b99765aa Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Sat, 27 Aug 2016 13:15:20 +0100 Subject: [PATCH 313/627] bignum: introduce bn_one --- bignum.c | 18 ++++++++++++++++-- bignum.h | 2 ++ tests.c | 13 +++++++++++++ 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/bignum.c b/bignum.c index 1bd65b605..eed53d22b 100644 --- a/bignum.c +++ b/bignum.c @@ -204,6 +204,20 @@ void bn_zero(bignum256 *a) } } +// sets a bignum to one. +void bn_one(bignum256 *a) +{ + a->val[0] = 1; + a->val[1] = 0; + a->val[2] = 0; + a->val[3] = 0; + a->val[4] = 0; + a->val[5] = 0; + a->val[6] = 0; + a->val[7] = 0; + a->val[8] = 0; +} + // checks that a bignum is zero. // a must be normalized // function is constant time (on some architectures, in particular ARM). @@ -459,7 +473,7 @@ void bn_sqrt(bignum256 *x, const bignum256 *prime) // this method compute x^1/2 = x^(prime+1)/4 uint32_t i, j, limb; bignum256 res, p; - bn_zero(&res); res.val[0] = 1; + bn_one(&res); // compute p = (prime+1)/4 memcpy(&p, prime, sizeof(bignum256)); bn_addi(&p, 1); @@ -498,7 +512,7 @@ void bn_inverse(bignum256 *x, const bignum256 *prime) // this method compute x^-1 = x^(prime-2) uint32_t i, j, limb; bignum256 res; - bn_zero(&res); res.val[0] = 1; + bn_one(&res); for (i = 0; i < 9; i++) { // invariants: // x = old(x)^(2^(i*30)) diff --git a/bignum.h b/bignum.h index 2d7af3c38..451e34489 100644 --- a/bignum.h +++ b/bignum.h @@ -85,6 +85,8 @@ void bn_zero(bignum256 *a); int bn_is_zero(const bignum256 *a); +void bn_one(bignum256 *a); + static inline int bn_is_even(const bignum256 *a) { return (a->val[0] & 1) == 0; } diff --git a/tests.c b/tests.c index f2fa3ed3c..a19e76155 100644 --- a/tests.c +++ b/tests.c @@ -153,6 +153,18 @@ START_TEST(test_bignum_is_zero) } END_TEST +START_TEST(test_bignum_one) +{ + bignum256 a; + bignum256 b; + + bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000001"), &a); + bn_one(&b); + + ck_assert_int_eq(bn_is_equal(&a, &b), 1); +} +END_TEST + START_TEST(test_bignum_read_le) { bignum256 a; @@ -2602,6 +2614,7 @@ Suite *test_suite(void) tcase_add_test(tc, test_bignum_is_equal); tcase_add_test(tc, test_bignum_zero); tcase_add_test(tc, test_bignum_is_zero); + tcase_add_test(tc, test_bignum_one); tcase_add_test(tc, test_bignum_read_le); tcase_add_test(tc, test_bignum_write_le); tcase_add_test(tc, test_bignum_read_uint32); From b3e6eecfcef37b9e4f91c1ac04ea2219c84c7859 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Mon, 29 Aug 2016 20:33:35 +0200 Subject: [PATCH 314/627] sha2: Fix unaligned access --- sha2.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/sha2.c b/sha2.c index b3bf14386..241265f5e 100644 --- a/sha2.c +++ b/sha2.c @@ -480,7 +480,6 @@ void sha256_Update(SHA256_CTX* context, const sha2_byte *data, size_t len) { } void sha256_Final(SHA256_CTX* context, sha2_byte digest[]) { - sha2_word32 *d = (sha2_word32*)(void*)digest; unsigned int usedspace; /* If no digest buffer is passed, we don't bother doing this: */ @@ -528,7 +527,7 @@ void sha256_Final(SHA256_CTX* context, sha2_byte digest[]) { REVERSE32(context->state[j],context->state[j]); } #endif - MEMCPY_BCOPY(d, context->state, SHA256_DIGEST_LENGTH); + MEMCPY_BCOPY(digest, context->state, SHA256_DIGEST_LENGTH); } /* Clean up state data: */ @@ -770,7 +769,7 @@ void sha512_Update(SHA512_CTX* context, const sha2_byte *data, size_t len) { #if BYTE_ORDER == LITTLE_ENDIAN /* Convert TO host byte order */ for (int j = 0; j < 16; j++) { - REVERSE64(((sha2_word64*)data)[j],context->buffer[j]); + REVERSE64(context->buffer[j],context->buffer[j]); } #endif sha512_Transform(context->state, context->buffer, context->state); @@ -831,8 +830,6 @@ static void sha512_Last(SHA512_CTX* context) { } void sha512_Final(SHA512_CTX* context, sha2_byte digest[]) { - sha2_word64 *d = (sha2_word64*)(void*)digest; - /* If no digest buffer is passed, we don't bother doing this: */ if (digest != (sha2_byte*)0) { sha512_Last(context); @@ -844,7 +841,7 @@ void sha512_Final(SHA512_CTX* context, sha2_byte digest[]) { REVERSE64(context->state[j],context->state[j]); } #endif - MEMCPY_BCOPY(d, context->state, SHA512_DIGEST_LENGTH); + MEMCPY_BCOPY(digest, context->state, SHA512_DIGEST_LENGTH); } /* Zero out state data */ From 19a1f501c4294f25f47b235899b58f78aa2c04c7 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Mon, 29 Aug 2016 21:41:23 +0200 Subject: [PATCH 315/627] Simplified sha256_Final/sha512_Last - Fix the bug where we zero too many bytes in sha512_Last (SHORT_BLOCK_LENGTH != BLOCK_LENGTH -2). - Get rid of an if branch. - Don't reverse the last two words in 512_Last that are written later. - make 256_Final and 512_Last look the same. --- sha2.c | 40 +++++++++++++++++----------------------- 1 file changed, 17 insertions(+), 23 deletions(-) diff --git a/sha2.c b/sha2.c index 241265f5e..5831e3dd9 100644 --- a/sha2.c +++ b/sha2.c @@ -488,13 +488,9 @@ void sha256_Final(SHA256_CTX* context, sha2_byte digest[]) { /* Begin padding with a 1 bit: */ ((uint8_t*)context->buffer)[usedspace++] = 0x80; - if (usedspace <= SHA256_SHORT_BLOCK_LENGTH) { - /* Set-up for the last transform: */ - MEMSET_BZERO(((uint8_t*)context->buffer) + usedspace, SHA256_SHORT_BLOCK_LENGTH - usedspace); - } else { - if (usedspace < SHA256_BLOCK_LENGTH) { - MEMSET_BZERO(((uint8_t*)context->buffer) + usedspace, SHA256_BLOCK_LENGTH - usedspace); - } + if (usedspace > SHA256_SHORT_BLOCK_LENGTH) { + MEMSET_BZERO(((uint8_t*)context->buffer) + usedspace, SHA256_BLOCK_LENGTH - usedspace); + #if BYTE_ORDER == LITTLE_ENDIAN /* Convert TO host byte order */ for (int j = 0; j < 16; j++) { @@ -504,9 +500,11 @@ void sha256_Final(SHA256_CTX* context, sha2_byte digest[]) { /* Do second-to-last transform: */ sha256_Transform(context->state, context->buffer, context->state); - /* And set-up for the last transform: */ - MEMSET_BZERO(context->buffer, SHA256_SHORT_BLOCK_LENGTH); + /* And prepare the last transform: */ + usedspace = 0; } + /* Set-up for the last transform: */ + MEMSET_BZERO(((uint8_t*)context->buffer) + usedspace, SHA256_SHORT_BLOCK_LENGTH - usedspace); #if BYTE_ORDER == LITTLE_ENDIAN /* Convert TO host byte order */ @@ -793,13 +791,9 @@ static void sha512_Last(SHA512_CTX* context) { /* Begin padding with a 1 bit: */ ((uint8_t*)context->buffer)[usedspace++] = 0x80; - if (usedspace <= SHA512_SHORT_BLOCK_LENGTH) { - /* Set-up for the last transform: */ - MEMSET_BZERO(((uint8_t*)context->buffer) + usedspace, SHA512_SHORT_BLOCK_LENGTH - usedspace); - } else { - if (usedspace < SHA512_BLOCK_LENGTH) { - MEMSET_BZERO(((uint8_t*)context->buffer) + usedspace, SHA512_BLOCK_LENGTH - usedspace); - } + if (usedspace > SHA512_SHORT_BLOCK_LENGTH) { + MEMSET_BZERO(((uint8_t*)context->buffer) + usedspace, SHA512_BLOCK_LENGTH - usedspace); + #if BYTE_ORDER == LITTLE_ENDIAN /* Convert TO host byte order */ for (int j = 0; j < 16; j++) { @@ -809,21 +803,21 @@ static void sha512_Last(SHA512_CTX* context) { /* Do second-to-last transform: */ sha512_Transform(context->state, context->buffer, context->state); - /* And set-up for the last transform: */ - MEMSET_BZERO(context->buffer, SHA512_BLOCK_LENGTH - 2); + /* And prepare the last transform: */ + usedspace = 0; } + /* Set-up for the last transform: */ + MEMSET_BZERO(((uint8_t*)context->buffer) + usedspace, SHA512_SHORT_BLOCK_LENGTH - usedspace); #if BYTE_ORDER == LITTLE_ENDIAN /* Convert TO host byte order */ - for (int j = 0; j < 16; j++) { + for (int j = 0; j < 14; j++) { REVERSE64(context->buffer[j],context->buffer[j]); } #endif /* Store the length of input data (in bits): */ - sha2_word64 *t; - t = &context->buffer[SHA512_SHORT_BLOCK_LENGTH/sizeof(sha2_word64)]; - t[0] = context->bitcount[1]; - t[1] = context->bitcount[0]; + context->buffer[14] = context->bitcount[1]; + context->buffer[15] = context->bitcount[0]; /* Final transform: */ sha512_Transform(context->state, context->buffer, context->state); From db1b638cdf8286f084741263105ba062704ba7a9 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sat, 10 Sep 2016 23:35:02 +0100 Subject: [PATCH 316/627] gui: update for newer HDNode API (#68) --- gui/mainwindow.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/gui/mainwindow.cpp b/gui/mainwindow.cpp index fd2d3c312..6fac349eb 100644 --- a/gui/mainwindow.cpp +++ b/gui/mainwindow.cpp @@ -49,6 +49,7 @@ void MainWindow::on_spinAccount_valueChanged(int arg1) const size_t buflen = 128; char buf[buflen + 1]; HDNode node; + uint32_t fingerprint; // external chain for (int chain = 0; chain < 2; chain++) { QTableWidget *list = chain == 0 ? ui->listAddress : ui->listChange; @@ -56,12 +57,14 @@ void MainWindow::on_spinAccount_valueChanged(int arg1) hdnode_private_ckd(&node, 44 | 0x80000000); hdnode_private_ckd(&node, 0 | 0x80000000); // bitcoin hdnode_private_ckd(&node, (arg1 - 1) | 0x80000000); - hdnode_serialize_private(&node, buf, buflen); QString xprv = QString(buf); ui->lineXprv->setText(xprv); - hdnode_serialize_public(&node, buf, buflen); QString xpub = QString(buf); ui->lineXpub->setText(xpub); + fingerprint = hdnode_fingerprint(&node); + hdnode_serialize_private(&node, fingerprint, buf, buflen); QString xprv = QString(buf); ui->lineXprv->setText(xprv); + hdnode_serialize_public(&node, fingerprint, buf, buflen); QString xpub = QString(buf); ui->lineXpub->setText(xpub); hdnode_private_ckd(&node, chain); // external / internal for (int i = 0; i < 100; i++) { HDNode node2 = node; hdnode_private_ckd(&node2, i); + hdnode_fill_public_key(&node2); ecdsa_get_address(node2.public_key, addr_version, buf, buflen); QString address = QString(buf); ecdsa_get_wif(node2.private_key, wif_version, buf, buflen); QString wif = QString(buf); list->setItem(i, 0, new QTableWidgetItem(address)); From 00413c0b6ea66efc334e3bc3bf8507dc2ea0caa3 Mon Sep 17 00:00:00 2001 From: Jan Pochyla Date: Thu, 6 Oct 2016 12:36:23 +0200 Subject: [PATCH 317/627] bip32: serialization returns nu. of written bytes --- bip32.c | 14 +++++++------- bip32.h | 6 +++--- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/bip32.c b/bip32.c index fac809eac..c72a672ac 100644 --- a/bip32.c +++ b/bip32.c @@ -438,7 +438,7 @@ int hdnode_sign_digest(HDNode *node, const uint8_t *digest, uint8_t *sig, uint8_ } -void hdnode_serialize(const HDNode *node, uint32_t fingerprint, uint32_t version, char use_public, char *str, int strsize) +int hdnode_serialize(const HDNode *node, uint32_t fingerprint, uint32_t version, char use_public, char *str, int strsize) { uint8_t node_data[78]; write_be(node_data, version); @@ -452,19 +452,19 @@ void hdnode_serialize(const HDNode *node, uint32_t fingerprint, uint32_t version node_data[45] = 0; memcpy(node_data + 46, node->private_key, 32); } - base58_encode_check(node_data, sizeof(node_data), str, strsize); - + int ret = base58_encode_check(node_data, sizeof(node_data), str, strsize); MEMSET_BZERO(node_data, sizeof(node_data)); + return ret; } -void hdnode_serialize_public(const HDNode *node, uint32_t fingerprint, char *str, int strsize) +int hdnode_serialize_public(const HDNode *node, uint32_t fingerprint, char *str, int strsize) { - hdnode_serialize(node, fingerprint, 0x0488B21E, 1, str, strsize); + return hdnode_serialize(node, fingerprint, 0x0488B21E, 1, str, strsize); } -void hdnode_serialize_private(const HDNode *node, uint32_t fingerprint, char *str, int strsize) +int hdnode_serialize_private(const HDNode *node, uint32_t fingerprint, char *str, int strsize) { - hdnode_serialize(node, fingerprint, 0x0488ADE4, 0, str, strsize); + return hdnode_serialize(node, fingerprint, 0x0488ADE4, 0, str, strsize); } // check for validity of curve point in case of public data not performed diff --git a/bip32.h b/bip32.h index 1cf031220..fe12a1a2f 100644 --- a/bip32.h +++ b/bip32.h @@ -74,14 +74,14 @@ int hdnode_get_ethereum_pubkeyhash(const HDNode *node, uint8_t *pubkeyhash); int hdnode_sign(HDNode *node, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby); int hdnode_sign_digest(HDNode *node, const uint8_t *digest, uint8_t *sig, uint8_t *pby); -void hdnode_serialize_public(const HDNode *node, uint32_t fingerprint, char *str, int strsize); +int hdnode_serialize_public(const HDNode *node, uint32_t fingerprint, char *str, int strsize); -void hdnode_serialize_private(const HDNode *node, uint32_t fingerprint, char *str, int strsize); +int hdnode_serialize_private(const HDNode *node, uint32_t fingerprint, char *str, int strsize); int hdnode_deserialize(const char *str, HDNode *node); // Private -void hdnode_serialize(const HDNode *node, uint32_t fingerprint, uint32_t version, char use_public, char *str, int strsize); +int hdnode_serialize(const HDNode *node, uint32_t fingerprint, uint32_t version, char use_public, char *str, int strsize); void hdnode_get_address_raw(HDNode *node, uint8_t version, uint8_t *addr_raw); From 133c068f374871dcb84715bdd4db3dd69a2a6382 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Thu, 6 Oct 2016 16:54:07 +0200 Subject: [PATCH 318/627] Reworked rfc6979 signing. (#72) This adds an is_canonic parameter to all sign functions. This is a callback that determines if a signature corresponds to some coin specific rules. It is used, e. g., by ethereum (where the recovery byte must be 0 or 1, and not 2 or 3) and or steem signatures (which require both r and s to be between 2^248 and 2^255). This also separates the initialization and the step function of the random number generator, making it easy to restart the signature process with the next random number. --- bip32.c | 8 +- bip32.h | 4 +- ecdsa.c | 214 ++++++++++++++++++++++++------------------------- ecdsa.h | 16 ++-- test-openssl.c | 2 +- test_curves.py | 2 +- test_speed.c | 4 +- tests.c | 15 ++-- 8 files changed, 132 insertions(+), 133 deletions(-) diff --git a/bip32.c b/bip32.c index c72a672ac..de82996a3 100644 --- a/bip32.c +++ b/bip32.c @@ -415,25 +415,25 @@ int hdnode_get_ethereum_pubkeyhash(const HDNode *node, uint8_t *pubkeyhash) // msg is a data to be signed // msg_len is the message length -int hdnode_sign(HDNode *node, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby) +int hdnode_sign(HDNode *node, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64])) { if (node->curve == &ed25519_info) { hdnode_fill_public_key(node); ed25519_sign(msg, msg_len, node->private_key, node->public_key + 1, sig); return 0; } else { - return ecdsa_sign(node->curve->params, node->private_key, msg, msg_len, sig, pby); + return ecdsa_sign(node->curve->params, node->private_key, msg, msg_len, sig, pby, is_canonical); } } -int hdnode_sign_digest(HDNode *node, const uint8_t *digest, uint8_t *sig, uint8_t *pby) +int hdnode_sign_digest(HDNode *node, const uint8_t *digest, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64])) { if (node->curve == &ed25519_info) { hdnode_fill_public_key(node); ed25519_sign(digest, 32, node->private_key, node->public_key + 1, sig); return 0; } else { - return ecdsa_sign_digest(node->curve->params, node->private_key, digest, sig, pby); + return ecdsa_sign_digest(node->curve->params, node->private_key, digest, sig, pby, is_canonical); } } diff --git a/bip32.h b/bip32.h index fe12a1a2f..83e76797b 100644 --- a/bip32.h +++ b/bip32.h @@ -71,8 +71,8 @@ void hdnode_fill_public_key(HDNode *node); int hdnode_get_ethereum_pubkeyhash(const HDNode *node, uint8_t *pubkeyhash); #endif -int hdnode_sign(HDNode *node, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby); -int hdnode_sign_digest(HDNode *node, const uint8_t *digest, uint8_t *sig, uint8_t *pby); +int hdnode_sign(HDNode *node, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64])); +int hdnode_sign_digest(HDNode *node, const uint8_t *digest, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64])); int hdnode_serialize_public(const HDNode *node, uint32_t fingerprint, char *str, int strsize); diff --git a/ecdsa.c b/ecdsa.c index fbde6b9a2..4e39e7105 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -614,79 +614,62 @@ void scalar_multiply(const ecdsa_curve *curve, const bignum256 *k, curve_point * #endif // generate random K for signing -int generate_k_random(const ecdsa_curve *curve, bignum256 *k) { - int i, j; - for (j = 0; j < 10000; j++) { - for (i = 0; i < 8; i++) { - k->val[i] = random32() & 0x3FFFFFFF; - } - k->val[8] = random32() & 0xFFFF; - // if k is too big or too small, we don't like it - if ( !bn_is_zero(k) && bn_is_less(k, &curve->order) ) { - return 0; // good number - no error - } +void generate_k_random(bignum256 *k) { + int i; + for (i = 0; i < 8; i++) { + k->val[i] = random32() & 0x3FFFFFFF; } - // we generated 10000 numbers, none of them is good -> fail - return 1; + k->val[8] = random32() & 0xFFFF; } -// generate K in a deterministic way, according to RFC6979 -// http://tools.ietf.org/html/rfc6979 -int generate_k_rfc6979(const ecdsa_curve *curve, bignum256 *secret, const uint8_t *priv_key, const uint8_t *hash) -{ - int i, error; - uint8_t v[32], k[32], bx[2*32], buf[32 + 1 + sizeof(bx)]; - bignum256 z1; +void init_k_rfc6979(const uint8_t *priv_key, const uint8_t *hash, rfc6979_state *state) { + uint8_t bx[2*32]; + uint8_t buf[32 + 1 + 2*32]; memcpy(bx, priv_key, 32); - bn_read_be(hash, &z1); - bn_mod(&z1, &curve->order); - bn_write_be(&z1, bx + 32); - - memset(v, 1, sizeof(v)); - memset(k, 0, sizeof(k)); - - memcpy(buf, v, sizeof(v)); - buf[sizeof(v)] = 0x00; - memcpy(buf + sizeof(v) + 1, bx, 64); - hmac_sha256(k, sizeof(k), buf, sizeof(buf), k); - hmac_sha256(k, sizeof(k), v, sizeof(v), v); - - memcpy(buf, v, sizeof(v)); - buf[sizeof(v)] = 0x01; - memcpy(buf + sizeof(v) + 1, bx, 64); - hmac_sha256(k, sizeof(k), buf, sizeof(buf), k); - hmac_sha256(k, sizeof(k), v, sizeof(v), v); - - error = 1; - for (i = 0; i < 10000; i++) { - hmac_sha256(k, sizeof(k), v, sizeof(v), v); - bn_read_be(v, secret); - if ( !bn_is_zero(secret) && bn_is_less(secret, &curve->order) ) { - error = 0; // good number -> no error - break; - } - memcpy(buf, v, sizeof(v)); - buf[sizeof(v)] = 0x00; - hmac_sha256(k, sizeof(k), buf, sizeof(v) + 1, k); - hmac_sha256(k, sizeof(k), v, sizeof(v), v); - } - // we generated 10000 numbers, none of them is good -> fail + memcpy(bx+32, hash, 32); + + memset(state->v, 1, sizeof(state->v)); + memset(state->k, 0, sizeof(state->k)); + + memcpy(buf, state->v, sizeof(state->v)); + buf[sizeof(state->v)] = 0x00; + memcpy(buf + sizeof(state->v) + 1, bx, 64); + hmac_sha256(state->k, sizeof(state->k), buf, sizeof(buf), state->k); + hmac_sha256(state->k, sizeof(state->k), state->v, sizeof(state->v), state->v); + + memcpy(buf, state->v, sizeof(state->v)); + buf[sizeof(state->v)] = 0x01; + memcpy(buf + sizeof(state->v) + 1, bx, 64); + hmac_sha256(state->k, sizeof(state->k), buf, sizeof(buf), state->k); + hmac_sha256(state->k, sizeof(state->k), state->v, sizeof(state->v), state->v); - MEMSET_BZERO(v, sizeof(v)); - MEMSET_BZERO(k, sizeof(k)); MEMSET_BZERO(bx, sizeof(bx)); MEMSET_BZERO(buf, sizeof(buf)); - return error; +} + +// generate K in a deterministic way, according to RFC6979 +// http://tools.ietf.org/html/rfc6979 +void generate_k_rfc6979(bignum256 *k, rfc6979_state *state) +{ + uint8_t buf[32 + 1]; + + hmac_sha256(state->k, sizeof(state->k), state->v, sizeof(state->v), state->v); + bn_read_be(state->v, k); + memcpy(buf, state->v, sizeof(state->v)); + buf[sizeof(state->v)] = 0x00; + hmac_sha256(state->k, sizeof(state->k), buf, sizeof(state->v) + 1, state->k); + hmac_sha256(state->k, sizeof(state->k), state->v, sizeof(state->v), state->v); + MEMSET_BZERO(buf, sizeof(buf)); } // msg is a data to be signed // msg_len is the message length -int ecdsa_sign(const ecdsa_curve *curve, const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby) +int ecdsa_sign(const ecdsa_curve *curve, const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64])) { uint8_t hash[32]; sha256_Raw(msg, msg_len, hash); - int res = ecdsa_sign_digest(curve, priv_key, hash, sig, pby); + int res = ecdsa_sign_digest(curve, priv_key, hash, sig, pby, is_canonical); MEMSET_BZERO(hash, sizeof(hash)); return res; @@ -694,12 +677,12 @@ int ecdsa_sign(const ecdsa_curve *curve, const uint8_t *priv_key, const uint8_t // msg is a data to be signed // msg_len is the message length -int ecdsa_sign_double(const ecdsa_curve *curve, const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby) +int ecdsa_sign_double(const ecdsa_curve *curve, const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64])) { uint8_t hash[32]; sha256_Raw(msg, msg_len, hash); sha256_Raw(hash, 32, hash); - int res = ecdsa_sign_digest(curve, priv_key, hash, sig, pby); + int res = ecdsa_sign_digest(curve, priv_key, hash, sig, pby, is_canonical); MEMSET_BZERO(hash, sizeof(hash)); return res; } @@ -708,82 +691,93 @@ int ecdsa_sign_double(const ecdsa_curve *curve, const uint8_t *priv_key, const u // priv_key is a 32 byte big endian stored number // sig is 64 bytes long array for the signature // digest is 32 bytes of digest -int ecdsa_sign_digest(const ecdsa_curve *curve, const uint8_t *priv_key, const uint8_t *digest, uint8_t *sig, uint8_t *pby) +// is_canonical is an optional function that checks if the signature +// conforms to additional coin-specific rules. +int ecdsa_sign_digest(const ecdsa_curve *curve, const uint8_t *priv_key, const uint8_t *digest, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64])) { - uint32_t i; + int i; curve_point R; bignum256 k, z; - bignum256 *da = &R.y; - int result = 0; + bignum256 *s = &R.y; + uint8_t by; // signature recovery byte + +#if USE_RFC6979 + rfc6979_state rng; + init_k_rfc6979(priv_key, digest, &rng); +#endif + bn_read_be(digest, &z); + for (i = 0; i < 10000; i++) { + #if USE_RFC6979 - // generate K deterministically - if (generate_k_rfc6979(curve, &k, priv_key, digest) != 0) { - result = 1; - } + // generate K deterministically + generate_k_rfc6979(&k, &rng); #else - // generate random number k - if (generate_k_random(curve, &k) != 0) { - result = 1; - } + // generate random number k + generate_k_random(&k); #endif + // if k is too big or too small, we don't like it + if (bn_is_zero(&k) || !bn_is_less(&k, &curve->order)) { + continue; + } - if (result == 0) { // compute k*G scalar_multiply(curve, &k, &R); - if (pby) { - *pby = R.y.val[0] & 1; - } + by = R.y.val[0] & 1; // r = (rx mod n) if (!bn_is_less(&R.x, &curve->order)) { bn_subtract(&R.x, &curve->order, &R.x); - if (pby) { - *pby |= 2; - } + by |= 2; } - // if r is zero, we fail - if (bn_is_zero(&R.x)) - { - result = 2; + // if r is zero, we retry + if (bn_is_zero(&R.x)) { + continue; } - } - if (result == 0) { bn_inverse(&k, &curve->order); - bn_read_be(priv_key, da); - bn_multiply(&R.x, da, &curve->order); - for (i = 0; i < 8; i++) { - da->val[i] += z.val[i]; - da->val[i + 1] += (da->val[i] >> 30); - da->val[i] &= 0x3FFFFFFF; + bn_read_be(priv_key, s); + bn_multiply(&R.x, s, &curve->order); + bn_add(s, &z); + bn_multiply(&k, s, &curve->order); + bn_mod(s, &curve->order); + // if s is zero, we retry + if (bn_is_zero(s)) { + continue; } - da->val[8] += z.val[8]; - bn_multiply(da, &k, &curve->order); - bn_mod(&k, &curve->order); - // if k is zero, we fail - if (bn_is_zero(&k)) { - result = 3; - } - } - if (result == 0) { // if S > order/2 => S = -S - if (bn_is_less(&curve->order_half, &k)) { - bn_subtract(&curve->order, &k, &k); - if (pby) { - *pby ^= 1; - } + if (bn_is_less(&curve->order_half, s)) { + bn_subtract(&curve->order, s, s); + by ^= 1; } - // we are done, R.x and k is the result signature + // we are done, R.x and s is the result signature bn_write_be(&R.x, sig); - bn_write_be(&k, sig + 32); + bn_write_be(s, sig + 32); + + // check if the signature is acceptable or retry + if (is_canonical && !is_canonical(by, sig)) { + continue; + } + + if (pby) { + *pby = by; + } + + MEMSET_BZERO(&k, sizeof(k)); +#if USE_RFC6979 + MEMSET_BZERO(&rng, sizeof(rng)); +#endif + return 0; } + // Too many retries without a valid signature + // -> fail with an error MEMSET_BZERO(&k, sizeof(k)); - MEMSET_BZERO(&z, sizeof(z)); - MEMSET_BZERO(&R, sizeof(R)); - return result; +#if USE_RFC6979 + MEMSET_BZERO(&rng, sizeof(rng)); +#endif + return -1; } void ecdsa_get_public_key33(const ecdsa_curve *curve, const uint8_t *priv_key, uint8_t *pub_key) diff --git a/ecdsa.h b/ecdsa.h index b7c22aa4d..c0629d5d5 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -48,6 +48,11 @@ typedef struct { } ecdsa_curve; +// rfc6979 pseudo random number generator state +typedef struct { + uint8_t v[32], k[32]; +} rfc6979_state; + void point_copy(const curve_point *cp1, curve_point *cp2); void point_add(const ecdsa_curve *curve, const curve_point *cp1, curve_point *cp2); void point_double(const ecdsa_curve *curve, curve_point *cp); @@ -60,9 +65,9 @@ void scalar_multiply(const ecdsa_curve *curve, const bignum256 *k, curve_point * void uncompress_coords(const ecdsa_curve *curve, uint8_t odd, const bignum256 *x, bignum256 *y); int ecdsa_uncompress_pubkey(const ecdsa_curve *curve, const uint8_t *pub_key, uint8_t *uncompressed); -int ecdsa_sign(const ecdsa_curve *curve, const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby); -int ecdsa_sign_double(const ecdsa_curve *curve, const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby); -int ecdsa_sign_digest(const ecdsa_curve *curve, const uint8_t *priv_key, const uint8_t *digest, uint8_t *sig, uint8_t *pby); +int ecdsa_sign(const ecdsa_curve *curve, const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64])); +int ecdsa_sign_double(const ecdsa_curve *curve, const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64])); +int ecdsa_sign_digest(const ecdsa_curve *curve, const uint8_t *priv_key, const uint8_t *digest, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64])); void ecdsa_get_public_key33(const ecdsa_curve *curve, const uint8_t *priv_key, uint8_t *pub_key); void ecdsa_get_public_key65(const ecdsa_curve *curve, const uint8_t *priv_key, uint8_t *pub_key); void ecdsa_get_pubkeyhash(const uint8_t *pub_key, uint8_t *pubkeyhash); @@ -80,7 +85,8 @@ int ecdsa_verify_digest_recover(const ecdsa_curve *curve, uint8_t *pub_key, cons int ecdsa_sig_to_der(const uint8_t *sig, uint8_t *der); // Private -int generate_k_rfc6979(const ecdsa_curve *curve, bignum256 *secret, const uint8_t *priv_key, const uint8_t *hash); -int generate_k_random(const ecdsa_curve *curve, bignum256 *k); +void init_k_rfc6979(const uint8_t *priv_key, const uint8_t *hash, rfc6979_state *rng); +void generate_k_rfc6979(bignum256 *k, rfc6979_state *rng); +void generate_k_random(bignum256 *k); #endif diff --git a/test-openssl.c b/test-openssl.c index cd52a0948..2af6286b7 100644 --- a/test-openssl.c +++ b/test-openssl.c @@ -88,7 +88,7 @@ int main(int argc, char *argv[]) } // use our ECDSA signer to sign the message with the key - if (ecdsa_sign(CURVE, priv_key, msg, msg_len, sig, 0) != 0) { + if (ecdsa_sign(CURVE, priv_key, msg, msg_len, sig, NULL, NULL) != 0) { printf("trezor-crypto signing failed\n"); break; } diff --git a/test_curves.py b/test_curves.py index 845c41b0a..0c47dfeec 100755 --- a/test_curves.py +++ b/test_curves.py @@ -380,7 +380,7 @@ def test_sign(curve, r): digest = r.randbytes(32) sig = r.randbytes(64) - lib.ecdsa_sign_digest(curve.ptr, priv, digest, sig, c.c_void_p(0)) + lib.ecdsa_sign_digest(curve.ptr, priv, digest, sig, c.c_void_p(0), c.c_void_p(0)) exp = bytes2num(priv) sk = ecdsa.SigningKey.from_secret_exponent(exp, curve, diff --git a/test_speed.c b/test_speed.c index 0378692ef..23ce4dcc4 100644 --- a/test_speed.c +++ b/test_speed.c @@ -25,7 +25,7 @@ void bench_secp256k1(void) { memcpy(priv, "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", 32); ecdsa_get_public_key33(curve, priv, pub); - ecdsa_sign(curve, priv, msg, sizeof(msg), sig, &pby); + ecdsa_sign(curve, priv, msg, sizeof(msg), sig, &pby, NULL); clock_t t = clock(); for (int i = 0 ; i < 500; i++) { @@ -42,7 +42,7 @@ void bench_nist256p1(void) { memcpy(priv, "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", 32); ecdsa_get_public_key33(curve, priv, pub); - ecdsa_sign(curve, priv, msg, sizeof(msg), sig, &pby); + ecdsa_sign(curve, priv, msg, sizeof(msg), sig, &pby, NULL); clock_t t = clock(); for (int i = 0 ; i < 500; i++) { diff --git a/tests.c b/tests.c index a19e76155..0eda9710e 100644 --- a/tests.c +++ b/tests.c @@ -1266,18 +1266,17 @@ END_TEST #define test_deterministic(KEY, MSG, K) do { \ sha256_Raw((uint8_t *)MSG, strlen(MSG), buf); \ - res = generate_k_rfc6979(curve, &k, fromhex(KEY), buf); \ - ck_assert_int_eq(res, 0); \ + init_k_rfc6979(fromhex(KEY), buf, &rng); \ + generate_k_rfc6979(&k, &rng); \ bn_write_be(&k, buf); \ ck_assert_mem_eq(buf, fromhex(K), 32); \ } while (0) START_TEST(test_rfc6979) { - int res; bignum256 k; uint8_t buf[32]; - const ecdsa_curve *curve = &secp256k1; + rfc6979_state rng; test_deterministic("cca9fbcc1b41e5a95d369eaa6ddcff73b61a4efaa279cfc6567e8daa39cbaf50", "sample", "2df40ca70e639d89528a6b670d9d48d9165fdc0febc0974056bdce192b8e16a3"); test_deterministic("0000000000000000000000000000000000000000000000000000000000000001", "Satoshi Nakamoto", "8f8a276c19f4149656b280621e358cce24f5f52542772691ee69063b74f15d15"); @@ -1303,13 +1302,13 @@ START_TEST(test_sign_speed) memcpy(priv_key, fromhex("c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd5"), 32); for (i = 0 ; i < 250; i++) { - res = ecdsa_sign(curve, priv_key, msg, sizeof(msg), sig, 0); + res = ecdsa_sign(curve, priv_key, msg, sizeof(msg), sig, NULL, NULL); ck_assert_int_eq(res, 0); } memcpy(priv_key, fromhex("509a0382ff5da48e402967a671bdcde70046d07f0df52cff12e8e3883b426a0a"), 32); for (i = 0 ; i < 250; i++) { - res = ecdsa_sign(curve, priv_key, msg, sizeof(msg), sig, 0); + res = ecdsa_sign(curve, priv_key, msg, sizeof(msg), sig, NULL, NULL); ck_assert_int_eq(res, 0); } @@ -1320,13 +1319,13 @@ START_TEST(test_sign_speed) memcpy(priv_key, fromhex("c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd5"), 32); for (i = 0 ; i < 250; i++) { - res = ecdsa_sign(curve, priv_key, msg, sizeof(msg), sig, 0); + res = ecdsa_sign(curve, priv_key, msg, sizeof(msg), sig, NULL, NULL); ck_assert_int_eq(res, 0); } memcpy(priv_key, fromhex("509a0382ff5da48e402967a671bdcde70046d07f0df52cff12e8e3883b426a0a"), 32); for (i = 0 ; i < 250; i++) { - res = ecdsa_sign(curve, priv_key, msg, sizeof(msg), sig, 0); + res = ecdsa_sign(curve, priv_key, msg, sizeof(msg), sig, NULL, NULL); ck_assert_int_eq(res, 0); } From 157caf3763866c386f9bcc287db3a1a472b5d55e Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Thu, 6 Oct 2016 16:54:25 +0200 Subject: [PATCH 319/627] ecdsa: fix out-of-bounds read in point_multiply (#71) Fixes #70. --- ecdsa.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/ecdsa.c b/ecdsa.c index 4e39e7105..2462f1c27 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -424,8 +424,10 @@ void point_multiply(const ecdsa_curve *curve, const bignum256 *k, const curve_po assert (bn_is_less(k, &curve->order)); int i, j; - int pos, shift; bignum256 a; + uint32_t *aptr; + uint32_t abits; + int ashift; uint32_t is_even = (k->val[0] & 1) - 1; uint32_t bits, sign, nsign; jacobian_curve_point jres; @@ -485,7 +487,10 @@ void point_multiply(const ecdsa_curve *curve, const bignum256 *k, const curve_po // and - (16 - (a>>(4*i) & 0xf)) otherwise. We can compute this as // ((a ^ (((a >> 4) & 1) - 1)) & 0xf) >> 1 // since a is odd. - bits = a.val[8] >> 12; + aptr = &a.val[8]; + abits = *aptr; + ashift = 12; + bits = abits >> ashift; sign = (bits >> 4) - 1; bits ^= sign; bits &= 15; @@ -493,6 +498,7 @@ void point_multiply(const ecdsa_curve *curve, const bignum256 *k, const curve_po for (i = 62; i >= 0; i--) { // sign = sign(a[i+1]) (0xffffffff for negative, 0 for positive) // invariant jres = (-1)^sign sum_{j=i+1..63} (a[j] * 16^{j-i-1} * p) + // abits >> (ashift - 4) = lowbits(a >> (i*4)) point_jacobian_double(&jres, curve); point_jacobian_double(&jres, curve); @@ -500,8 +506,18 @@ void point_multiply(const ecdsa_curve *curve, const bignum256 *k, const curve_po point_jacobian_double(&jres, curve); // get lowest 5 bits of a >> (i*4). - pos = i*4/30; shift = i*4 % 30; - bits = (a.val[pos+1]<<(30-shift) | a.val[pos] >> shift) & 31; + ashift -= 4; + if (ashift < 0) { + // the condition only depends on the iteration number and + // leaks no private information to a side-channel. + bits = abits << (-ashift); + abits = *(--aptr); + ashift += 30; + bits |= abits >> ashift; + } else { + bits = abits >> ashift; + } + bits &= 31; nsign = (bits >> 4) - 1; bits ^= nsign; bits &= 15; From d10ec230c0523e0a27c5e470e84f005035e5fb5c Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 8 Oct 2016 17:56:12 +0200 Subject: [PATCH 320/627] add support for multibyte address versions --- bip32.c | 4 +-- bip32.h | 4 +-- ecdsa.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++----------- ecdsa.h | 6 ++--- 4 files changed, 69 insertions(+), 21 deletions(-) diff --git a/bip32.c b/bip32.c index de82996a3..ce617150b 100644 --- a/bip32.c +++ b/bip32.c @@ -266,7 +266,7 @@ int hdnode_public_ckd(HDNode *inout, uint32_t i) return 1; } -int hdnode_public_ckd_address_optimized(const curve_point *pub, const uint8_t *public_key, const uint8_t *chain_code, uint32_t i, uint8_t version, char *addr, int addrsize) +int hdnode_public_ckd_address_optimized(const curve_point *pub, const uint8_t *public_key, const uint8_t *chain_code, uint32_t i, uint32_t version, char *addr, int addrsize) { uint8_t data[1 + 32 + 4]; uint8_t I[32 + 32]; @@ -374,7 +374,7 @@ int hdnode_private_ckd_cached(HDNode *inout, const uint32_t *i, size_t i_count) #endif -void hdnode_get_address_raw(HDNode *node, uint8_t version, uint8_t *addr_raw) +void hdnode_get_address_raw(HDNode *node, uint32_t version, uint8_t *addr_raw) { hdnode_fill_public_key(node); ecdsa_get_address_raw(node->public_key, version, addr_raw); diff --git a/bip32.h b/bip32.h index 83e76797b..4095deb81 100644 --- a/bip32.h +++ b/bip32.h @@ -55,7 +55,7 @@ int hdnode_private_ckd(HDNode *inout, uint32_t i); int hdnode_public_ckd(HDNode *inout, uint32_t i); -int hdnode_public_ckd_address_optimized(const curve_point *pub, const uint8_t *public_key, const uint8_t *chain_code, uint32_t i, uint8_t version, char *addr, int addrsize); +int hdnode_public_ckd_address_optimized(const curve_point *pub, const uint8_t *public_key, const uint8_t *chain_code, uint32_t i, uint32_t version, char *addr, int addrsize); #if USE_BIP32_CACHE @@ -83,7 +83,7 @@ int hdnode_deserialize(const char *str, HDNode *node); // Private int hdnode_serialize(const HDNode *node, uint32_t fingerprint, uint32_t version, char use_public, char *str, int strsize); -void hdnode_get_address_raw(HDNode *node, uint8_t version, uint8_t *addr_raw); +void hdnode_get_address_raw(HDNode *node, uint32_t version, uint8_t *addr_raw); const curve_info *get_curve_by_name(const char *curve_name); diff --git a/ecdsa.c b/ecdsa.c index 2462f1c27..e166ff8f0 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -854,32 +854,80 @@ void ecdsa_get_pubkeyhash(const uint8_t *pub_key, uint8_t *pubkeyhash) MEMSET_BZERO(h, sizeof(h)); } -void ecdsa_get_address_raw(const uint8_t *pub_key, uint8_t version, uint8_t *addr_raw) +void ecdsa_get_address_raw(const uint8_t *pub_key, uint32_t version, uint8_t *addr_raw) { - addr_raw[0] = version; - ecdsa_get_pubkeyhash(pub_key, addr_raw + 1); + if (version <= 0xFF) { + addr_raw[0] = version; + ecdsa_get_pubkeyhash(pub_key, addr_raw + 1); + } else if (version <= 0xFFFF) { + addr_raw[0] = version >> 8; + addr_raw[1] = version & 0xFF; + ecdsa_get_pubkeyhash(pub_key, addr_raw + 2); + } else if (version <= 0xFFFFFF) { + addr_raw[0] = version >> 16; + addr_raw[1] = (version >> 8) & 0xFF; + addr_raw[2] = version & 0xFF; + ecdsa_get_pubkeyhash(pub_key, addr_raw + 3); + } else { + addr_raw[0] = version >> 24; + addr_raw[1] = (version >> 16) & 0xFF; + addr_raw[2] = (version >> 8) & 0xFF; + addr_raw[3] = version & 0xFF; + ecdsa_get_pubkeyhash(pub_key, addr_raw + 4); + } } -void ecdsa_get_address(const uint8_t *pub_key, uint8_t version, char *addr, int addrsize) +void ecdsa_get_address(const uint8_t *pub_key, uint32_t version, char *addr, int addrsize) { - uint8_t raw[21]; + uint8_t raw[20+4]; ecdsa_get_address_raw(pub_key, version, raw); - base58_encode_check(raw, 21, addr, addrsize); - + if (version <= 0xFF) { + base58_encode_check(raw, 21, addr, addrsize); + } else if (version <= 0xFFFF) { + base58_encode_check(raw, 22, addr, addrsize); + } else if (version <= 0xFFFFFF) { + base58_encode_check(raw, 23, addr, addrsize); + } else { + base58_encode_check(raw, 24, addr, addrsize); + } // not as important to clear this one, but we might as well MEMSET_BZERO(raw, sizeof(raw)); } -void ecdsa_get_wif(const uint8_t *priv_key, uint8_t version, char *wif, int wifsize) +void ecdsa_get_wif(const uint8_t *priv_key, uint32_t version, char *wif, int wifsize) { - uint8_t data[34]; - data[0] = version; - memcpy(data + 1, priv_key, 32); - data[33] = 0x01; - base58_encode_check(data, 34, wif, wifsize); + uint8_t wif_raw[4 + 32 + 1]; + + if (version <= 0xFF) { + wif_raw[0] = version; + memcpy(wif_raw + 1, priv_key, 32); + wif_raw[33] = 0x01; + base58_encode_check(wif_raw, 1 + 32 + 1, wif, wifsize); + } else if (version <= 0xFFFF) { + wif_raw[0] = version >> 8; + wif_raw[1] = version & 0xFF; + memcpy(wif_raw + 2, priv_key, 32); + wif_raw[34] = 0x01; + base58_encode_check(wif_raw, 2 + 32 + 1, wif, wifsize); + } else if (version <= 0xFFFFFF) { + wif_raw[0] = version >> 16; + wif_raw[1] = (version >> 8) & 0xFF; + wif_raw[2] = version & 0xFF; + memcpy(wif_raw + 3, priv_key, 32); + wif_raw[35] = 0x01; + base58_encode_check(wif_raw, 3 + 32 + 1, wif, wifsize); + } else { + wif_raw[0] = version >> 24; + wif_raw[1] = (version >> 16) & 0xFF; + wif_raw[2] = (version >> 8) & 0xFF; + wif_raw[3] = version & 0xFF; + memcpy(wif_raw + 4, priv_key, 32); + wif_raw[36] = 0x01; + base58_encode_check(wif_raw, 4 + 32 + 1, wif, wifsize); + } // private keys running around our stack can cause trouble - MEMSET_BZERO(data, sizeof(data)); + MEMSET_BZERO(wif_raw, sizeof(wif_raw)); } int ecdsa_address_decode(const char *addr, uint8_t *out) diff --git a/ecdsa.h b/ecdsa.h index c0629d5d5..a07e418ca 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -71,9 +71,9 @@ int ecdsa_sign_digest(const ecdsa_curve *curve, const uint8_t *priv_key, const u void ecdsa_get_public_key33(const ecdsa_curve *curve, const uint8_t *priv_key, uint8_t *pub_key); void ecdsa_get_public_key65(const ecdsa_curve *curve, const uint8_t *priv_key, uint8_t *pub_key); void ecdsa_get_pubkeyhash(const uint8_t *pub_key, uint8_t *pubkeyhash); -void ecdsa_get_address_raw(const uint8_t *pub_key, uint8_t version, uint8_t *addr_raw); -void ecdsa_get_address(const uint8_t *pub_key, uint8_t version, char *addr, int addrsize); -void ecdsa_get_wif(const uint8_t *priv_key, uint8_t version, char *wif, int wifsize); +void ecdsa_get_address_raw(const uint8_t *pub_key, uint32_t version, uint8_t *addr_raw); +void ecdsa_get_address(const uint8_t *pub_key, uint32_t version, char *addr, int addrsize); +void ecdsa_get_wif(const uint8_t *priv_key, uint32_t version, char *wif, int wifsize); int ecdsa_address_decode(const char *addr, uint8_t *out); int ecdsa_read_pubkey(const ecdsa_curve *curve, const uint8_t *pub_key, curve_point *pub); From 430a5087c8b71791d10d24e0141185a627c88748 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 8 Oct 2016 18:01:44 +0200 Subject: [PATCH 321/627] introduce MAX_ADDR_RAW_SIZE and MAX_WIF_RAW_SIZE macros --- ecdsa.c | 4 ++-- ecdsa.h | 3 +++ tests.c | 5 ++--- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/ecdsa.c b/ecdsa.c index e166ff8f0..1f0e836c9 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -879,7 +879,7 @@ void ecdsa_get_address_raw(const uint8_t *pub_key, uint32_t version, uint8_t *ad void ecdsa_get_address(const uint8_t *pub_key, uint32_t version, char *addr, int addrsize) { - uint8_t raw[20+4]; + uint8_t raw[MAX_ADDR_RAW_SIZE]; ecdsa_get_address_raw(pub_key, version, raw); if (version <= 0xFF) { base58_encode_check(raw, 21, addr, addrsize); @@ -896,7 +896,7 @@ void ecdsa_get_address(const uint8_t *pub_key, uint32_t version, char *addr, int void ecdsa_get_wif(const uint8_t *priv_key, uint32_t version, char *wif, int wifsize) { - uint8_t wif_raw[4 + 32 + 1]; + uint8_t wif_raw[MAX_WIF_RAW_SIZE]; if (version <= 0xFF) { wif_raw[0] = version; diff --git a/ecdsa.h b/ecdsa.h index a07e418ca..5b785617a 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -48,6 +48,9 @@ typedef struct { } ecdsa_curve; +#define MAX_ADDR_RAW_SIZE (4 + 20) +#define MAX_WIF_RAW_SIZE (4 + 32 + 1) + // rfc6979 pseudo random number generator state typedef struct { uint8_t v[32], k[32]; diff --git a/tests.c b/tests.c index 0eda9710e..964e6e11a 100644 --- a/tests.c +++ b/tests.c @@ -2150,9 +2150,8 @@ END_TEST START_TEST(test_address_decode) { int res; - uint8_t decode[21]; - // byte 0 : address type - // bytes 1-20 : pubkey hash 160 + uint8_t decode[MAX_ADDR_RAW_SIZE]; + res = ecdsa_address_decode("1JwSSubhmg6iPtRjtyqhUYYH7bZg3Lfy1T", decode); ck_assert_int_eq(res, 1); ck_assert_mem_eq(decode, fromhex("00c4c5d791fcb4654a1ef5e03fe0ad3d9c598f9827"), 21); From 8764e26368a639f9bd34fa1c8e4378dde938589d Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 8 Oct 2016 18:13:23 +0200 Subject: [PATCH 322/627] ecdsa_address_decode now needs version --- ecdsa.c | 12 ++++++++++-- ecdsa.h | 2 +- tests.c | 24 ++++++++++++++---------- tools/bip39bruteforce.c | 2 +- 4 files changed, 26 insertions(+), 14 deletions(-) diff --git a/ecdsa.c b/ecdsa.c index 1f0e836c9..bbf361053 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -930,10 +930,18 @@ void ecdsa_get_wif(const uint8_t *priv_key, uint32_t version, char *wif, int wif MEMSET_BZERO(wif_raw, sizeof(wif_raw)); } -int ecdsa_address_decode(const char *addr, uint8_t *out) +int ecdsa_address_decode(const char *addr, uint32_t version, uint8_t *out) { if (!addr) return 0; - return base58_decode_check(addr, out, 21) == 21; + if (version <= 0xFF) { + return base58_decode_check(addr, out, 21) == 21 && out[0] == (version & 0xFF); + } else if (version <= 0xFFFF) { + return base58_decode_check(addr, out, 22) == 22 && out[0] == ((version >> 8)) && out[1] == (version & 0xFF); + } else if (version <= 0xFFFF) { + return base58_decode_check(addr, out, 23) == 23 && out[0] == ((version >> 16)) && out[1] == ((version >> 8) & 0xFF) && out[2] == (version & 0xFF); + } else { + return base58_decode_check(addr, out, 24) == 24 && out[0] == (version >> 24) && out[1] == ((version >> 16) & 0xFF) && out[2] == ((version >> 8) & 0xFF) && out[3] == (version & 0xFF); + } } void uncompress_coords(const ecdsa_curve *curve, uint8_t odd, const bignum256 *x, bignum256 *y) diff --git a/ecdsa.h b/ecdsa.h index 5b785617a..f74bf2efc 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -78,7 +78,7 @@ void ecdsa_get_address_raw(const uint8_t *pub_key, uint32_t version, uint8_t *ad void ecdsa_get_address(const uint8_t *pub_key, uint32_t version, char *addr, int addrsize); void ecdsa_get_wif(const uint8_t *priv_key, uint32_t version, char *wif, int wifsize); -int ecdsa_address_decode(const char *addr, uint8_t *out); +int ecdsa_address_decode(const char *addr, uint32_t version, uint8_t *out); int ecdsa_read_pubkey(const ecdsa_curve *curve, const uint8_t *pub_key, curve_point *pub); int ecdsa_validate_pubkey(const ecdsa_curve *curve, const curve_point *pub); int ecdsa_verify(const ecdsa_curve *curve, const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, uint32_t msg_len); diff --git a/tests.c b/tests.c index 964e6e11a..343d3fae1 100644 --- a/tests.c +++ b/tests.c @@ -2152,44 +2152,48 @@ START_TEST(test_address_decode) int res; uint8_t decode[MAX_ADDR_RAW_SIZE]; - res = ecdsa_address_decode("1JwSSubhmg6iPtRjtyqhUYYH7bZg3Lfy1T", decode); + res = ecdsa_address_decode("1JwSSubhmg6iPtRjtyqhUYYH7bZg3Lfy1T", 0, decode); ck_assert_int_eq(res, 1); ck_assert_mem_eq(decode, fromhex("00c4c5d791fcb4654a1ef5e03fe0ad3d9c598f9827"), 21); - res = ecdsa_address_decode("myTPjxggahXyAzuMcYp5JTkbybANyLsYBW", decode); + res = ecdsa_address_decode("myTPjxggahXyAzuMcYp5JTkbybANyLsYBW", 111, decode); ck_assert_int_eq(res, 1); ck_assert_mem_eq(decode, fromhex("6fc4c5d791fcb4654a1ef5e03fe0ad3d9c598f9827"), 21); - res = ecdsa_address_decode("NEWoeZ6gh4CGvRgFAoAGh4hBqpxizGT6gZ", decode); + res = ecdsa_address_decode("NEWoeZ6gh4CGvRgFAoAGh4hBqpxizGT6gZ", 52, decode); ck_assert_int_eq(res, 1); ck_assert_mem_eq(decode, fromhex("34c4c5d791fcb4654a1ef5e03fe0ad3d9c598f9827"), 21); - res = ecdsa_address_decode("LdAPi7uXrLLmeh7u57pzkZc3KovxEDYRJq", decode); + res = ecdsa_address_decode("LdAPi7uXrLLmeh7u57pzkZc3KovxEDYRJq", 48, decode); ck_assert_int_eq(res, 1); ck_assert_mem_eq(decode, fromhex("30c4c5d791fcb4654a1ef5e03fe0ad3d9c598f9827"), 21); - res = ecdsa_address_decode("1C7zdTfnkzmr13HfA2vNm5SJYRK6nEKyq8", decode); + res = ecdsa_address_decode("1C7zdTfnkzmr13HfA2vNm5SJYRK6nEKyq8", 0, decode); ck_assert_int_eq(res, 1); ck_assert_mem_eq(decode, fromhex("0079fbfc3f34e7745860d76137da68f362380c606c"), 21); - res = ecdsa_address_decode("mrdwvWkma2D6n9mGsbtkazedQQuoksnqJV", decode); + res = ecdsa_address_decode("mrdwvWkma2D6n9mGsbtkazedQQuoksnqJV", 111, decode); ck_assert_int_eq(res, 1); ck_assert_mem_eq(decode, fromhex("6f79fbfc3f34e7745860d76137da68f362380c606c"), 21); - res = ecdsa_address_decode("N7hMq7AmgNsQXaYARrEwybbDGei9mcPNqr", decode); + res = ecdsa_address_decode("N7hMq7AmgNsQXaYARrEwybbDGei9mcPNqr", 52, decode); ck_assert_int_eq(res, 1); ck_assert_mem_eq(decode, fromhex("3479fbfc3f34e7745860d76137da68f362380c606c"), 21); - res = ecdsa_address_decode("LWLwtfycqf1uFqypLAug36W4kdgNwrZdNs", decode); + res = ecdsa_address_decode("LWLwtfycqf1uFqypLAug36W4kdgNwrZdNs", 48, decode); ck_assert_int_eq(res, 1); ck_assert_mem_eq(decode, fromhex("3079fbfc3f34e7745860d76137da68f362380c606c"), 21); // invalid char - res = ecdsa_address_decode("1JwSSubhmg6i000jtyqhUYYH7bZg3Lfy1T", decode); + res = ecdsa_address_decode("1JwSSubhmg6i000jtyqhUYYH7bZg3Lfy1T", 0, decode); ck_assert_int_eq(res, 0); // invalid address - res = ecdsa_address_decode("1111Subhmg6iPtRjtyqhUYYH7bZg3Lfy1T", decode); + res = ecdsa_address_decode("1111Subhmg6iPtRjtyqhUYYH7bZg3Lfy1T", 0, decode); + ck_assert_int_eq(res, 0); + + // invalid version + res = ecdsa_address_decode("LWLwtfycqf1uFqypLAug36W4kdgNwrZdNs", 0, decode); ck_assert_int_eq(res, 0); } END_TEST diff --git a/tools/bip39bruteforce.c b/tools/bip39bruteforce.c index f27007b78..7bb2a33f3 100644 --- a/tools/bip39bruteforce.c +++ b/tools/bip39bruteforce.c @@ -44,7 +44,7 @@ int main(int argc, char **argv) fprintf(stderr, "\"%s\" is not a valid mnemonic\n", mnemonic); return 2; } - if (!ecdsa_address_decode(address, addr)) { + if (!ecdsa_address_decode(address, 0, addr)) { fprintf(stderr, "\"%s\" is not a valid address\n", address); return 3; } From 4fb15a13d8a20d687fc6c498329fd402e7dd3ff4 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 8 Oct 2016 18:18:32 +0200 Subject: [PATCH 323/627] add hdnode_get_address --- bip32.c | 6 ++++++ bip32.h | 1 + 2 files changed, 7 insertions(+) diff --git a/bip32.c b/bip32.c index ce617150b..f5b8b3331 100644 --- a/bip32.c +++ b/bip32.c @@ -380,6 +380,12 @@ void hdnode_get_address_raw(HDNode *node, uint32_t version, uint8_t *addr_raw) ecdsa_get_address_raw(node->public_key, version, addr_raw); } +void hdnode_get_address(HDNode *node, uint32_t version, char *addr, int addrsize) +{ + hdnode_fill_public_key(node); + ecdsa_get_address(node->public_key, version, addr, addrsize); +} + void hdnode_fill_public_key(HDNode *node) { if (node->public_key[0] != 0) diff --git a/bip32.h b/bip32.h index 4095deb81..24f674860 100644 --- a/bip32.h +++ b/bip32.h @@ -84,6 +84,7 @@ int hdnode_deserialize(const char *str, HDNode *node); int hdnode_serialize(const HDNode *node, uint32_t fingerprint, uint32_t version, char use_public, char *str, int strsize); void hdnode_get_address_raw(HDNode *node, uint32_t version, uint8_t *addr_raw); +void hdnode_get_address(HDNode *node, uint32_t version, char *addr, int addrsize); const curve_info *get_curve_by_name(const char *curve_name); From ad73c0d4e73fe138ebbbc39d6a335167ba7c9923 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 9 Oct 2016 23:41:48 +0200 Subject: [PATCH 324/627] fix ecdsa_address_decode --- ecdsa.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ecdsa.c b/ecdsa.c index bbf361053..fe73c4866 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -936,9 +936,9 @@ int ecdsa_address_decode(const char *addr, uint32_t version, uint8_t *out) if (version <= 0xFF) { return base58_decode_check(addr, out, 21) == 21 && out[0] == (version & 0xFF); } else if (version <= 0xFFFF) { - return base58_decode_check(addr, out, 22) == 22 && out[0] == ((version >> 8)) && out[1] == (version & 0xFF); - } else if (version <= 0xFFFF) { - return base58_decode_check(addr, out, 23) == 23 && out[0] == ((version >> 16)) && out[1] == ((version >> 8) & 0xFF) && out[2] == (version & 0xFF); + return base58_decode_check(addr, out, 22) == 22 && out[0] == ((version >> 8) & 0xFF) && out[1] == (version & 0xFF); + } else if (version <= 0xFFFFFF) { + return base58_decode_check(addr, out, 23) == 23 && out[0] == ((version >> 16) & 0xFF) && out[1] == ((version >> 8) & 0xFF) && out[2] == (version & 0xFF); } else { return base58_decode_check(addr, out, 24) == 24 && out[0] == (version >> 24) && out[1] == ((version >> 16) & 0xFF) && out[2] == ((version >> 8) & 0xFF) && out[3] == (version & 0xFF); } From b05776be77168738d94ef9963019abb4d80a5356 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 10 Oct 2016 11:22:03 +0200 Subject: [PATCH 325/627] add address related funnctions --- CMakeLists.txt | 2 +- Makefile | 1 + address.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++ address.h | 35 ++++++++++++++++++++++++++++++++ 4 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 address.c create mode 100644 address.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 2f256bb4c..7e25a4551 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 2.6) -set(SOURCES aescrypt.c aeskey.c aes_modes.c aestab.c base58.c bignum.c bip32.c bip39.c ecdsa.c hmac.c nist256p1.c pbkdf2.c rand.c ripemd160.c secp256k1.c sha2.c ed25519-donna/ed25519.c sha3.c) +set(SOURCES address.c aescrypt.c aeskey.c aes_modes.c aestab.c base58.c bignum.c bip32.c bip39.c ecdsa.c hmac.c nist256p1.c pbkdf2.c rand.c ripemd160.c secp256k1.c sha2.c ed25519-donna/ed25519.c sha3.c) include_directories(ed25519-donna) # disable sequence point warnings where they are expected diff --git a/Makefile b/Makefile index 9c91c9794..da15a751c 100644 --- a/Makefile +++ b/Makefile @@ -38,6 +38,7 @@ CFLAGS += -DUSE_PRECOMPUTED_IV=0 -DUSE_PRECOMPUTED_CP=0 endif SRCS = bignum.c ecdsa.c curves.c secp256k1.c nist256p1.c rand.c hmac.c bip32.c bip39.c pbkdf2.c base58.c +SRCS += address.c SRCS += script.c SRCS += ripemd160.c SRCS += sha2.c diff --git a/address.c b/address.c new file mode 100644 index 000000000..2fb8b32dd --- /dev/null +++ b/address.c @@ -0,0 +1,54 @@ +/** + * Copyright (c) 2016 Daira Hopwood + * Copyright (c) 2016 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "address.h" + +size_t address_prefix_bytes_len(uint32_t address_type) +{ + if (address_type <= 0xFF) return 1; + if (address_type <= 0xFFFF) return 2; + if (address_type <= 0xFFFFFF) return 3; + return 4; +} + +void address_write_prefix_bytes(uint32_t address_type, uint8_t *out) +{ + if (address_type > 0xFFFFFF) *(out++) = address_type >> 24; + if (address_type > 0xFFFF) *(out++) = (address_type >> 16) & 0xFF; + if (address_type > 0xFF) *(out++) = (address_type >> 8) & 0xFF; + *(out++) = address_type & 0xFF; +} + +bool address_check_prefix(const uint8_t *addr, uint32_t address_type) +{ + if (address_type <= 0xFF) { + return address_type == (uint32_t)(addr[0]); + } + if (address_type <= 0xFFFF) { + return address_type == ((uint32_t)(addr[0] << 8) | (uint32_t)(addr[1])); + } + if (address_type <= 0xFFFFFF) { + return address_type == ((uint32_t)(addr[0] << 16) | (uint32_t)(addr[1] << 8) | (uint32_t)(addr[2])); + } + return address_type == ((uint32_t)(addr[0] << 24) | (uint32_t)(addr[1] << 16) | (uint32_t)(addr[2] << 8) | (uint32_t)(addr[3])); +} diff --git a/address.h b/address.h new file mode 100644 index 000000000..bd96d61f5 --- /dev/null +++ b/address.h @@ -0,0 +1,35 @@ +/** + * Copyright (c) 2016 Daira Hopwood + * Copyright (c) 2016 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __ADDRESS_H__ +#define __ADDRESS_H__ + +#include +#include +#include + +size_t address_prefix_bytes_len(uint32_t address_type); +void address_write_prefix_bytes(uint32_t address_type, uint8_t *out); +bool address_check_prefix(const uint8_t *addr, uint32_t address_type); + +#endif From cb25b763b732d4b3ed1d70a1a3db59759df88e9d Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 12 Oct 2016 17:36:46 +0200 Subject: [PATCH 326/627] add emcripten outputs to gitignore --- emscripten/.gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/emscripten/.gitignore b/emscripten/.gitignore index c2658d7d1..2d4967cb9 100644 --- a/emscripten/.gitignore +++ b/emscripten/.gitignore @@ -1 +1,3 @@ node_modules/ +test-browserify.js +trezor-crypto.js From 0a158f6c7d2ab2f3854dc255054454fdf49edc34 Mon Sep 17 00:00:00 2001 From: Karel Bilek Date: Wed, 12 Oct 2016 17:50:31 +0200 Subject: [PATCH 327/627] Add compiled output --- emscripten/.gitignore | 1 - emscripten/trezor-crypto.js | 379 ++++++++++++++++++++++++++++++++++++ 2 files changed, 379 insertions(+), 1 deletion(-) create mode 100644 emscripten/trezor-crypto.js diff --git a/emscripten/.gitignore b/emscripten/.gitignore index 2d4967cb9..9bb5de5d2 100644 --- a/emscripten/.gitignore +++ b/emscripten/.gitignore @@ -1,3 +1,2 @@ node_modules/ test-browserify.js -trezor-crypto.js diff --git a/emscripten/trezor-crypto.js b/emscripten/trezor-crypto.js new file mode 100644 index 000000000..02d4a769b --- /dev/null +++ b/emscripten/trezor-crypto.js @@ -0,0 +1,379 @@ +"undefined"===typeof importScripts&&"undefined"!==typeof WorkerGlobalScope&&this instanceof WorkerGlobalScope&&(this.importScripts=function(){throw Error("importScripts is a stub");});var e;e||(e=eval("(function() { try { return Module || {} } catch(e) { return {} } })()"));var aa={},k;for(k in e)e.hasOwnProperty(k)&&(aa[k]=e[k]);var ba=!1,l=!1,m=!1,ca=!1; +if(e.ENVIRONMENT)if("WEB"===e.ENVIRONMENT)ba=!0;else if("WORKER"===e.ENVIRONMENT)l=!0;else if("NODE"===e.ENVIRONMENT)m=!0;else if("SHELL"===e.ENVIRONMENT)ca=!0;else throw Error("The provided Module['ENVIRONMENT'] value is not valid. It must be one of: WEB|WORKER|NODE|SHELL.");else ba="object"===typeof window,l="function"===typeof importScripts,m="object"===typeof process&&"function"===typeof require&&!ba&&!l,ca=!ba&&!m&&!l; +if(m){e.print||(e.print=console.log);e.printErr||(e.printErr=console.warn);var da,ea;e.read=function(a,b){da||(da=require("fs"));ea||(ea=require("path"));a=ea.normalize(a);var c=da.readFileSync(a);return b?c:c.toString()};e.readBinary=function(a){a=e.read(a,!0);a.buffer||(a=new Uint8Array(a));assert(a.buffer);return a};e.load=function(a){fa(read(a))};e.thisProgram||(e.thisProgram=1 0) var gc = undefined");else if(ba||l)e.read=function(a){var b=new XMLHttpRequest;b.open("GET",a,!1);b.send(null);return b.responseText},e.readAsync=function(a,b,c){var d=new XMLHttpRequest;d.open("GET",a,!0);d.responseType="arraybuffer";d.onload=function(){200==d.status||0==d.status&&d.response?b(d.response):c()};d.onerror=c;d.send(null)},"undefined"!= +typeof arguments&&(e.arguments=arguments),"undefined"!==typeof console?(e.print||(e.print=function(a){console.log(a)}),e.printErr||(e.printErr=function(a){console.warn(a)})):e.print||(e.print=function(){}),l&&(e.load=importScripts),"undefined"===typeof e.setWindowTitle&&(e.setWindowTitle=function(a){document.title=a});else throw"Unknown runtime environment. Where are we?";function fa(a){eval.call(null,a)}!e.load&&e.read&&(e.load=function(a){fa(e.read(a))});e.print||(e.print=function(){}); +e.printErr||(e.printErr=e.print);e.arguments||(e.arguments=[]);e.thisProgram||(e.thisProgram="./this.program");e.print=e.print;e.ba=e.printErr;e.preRun=[];e.postRun=[];for(k in aa)aa.hasOwnProperty(k)&&(e[k]=aa[k]); +var aa=void 0,t={Wa:function(a){tempRet0=a},Na:function(){return tempRet0},Q:function(){return p},I:function(a){p=a},va:function(a){switch(a){case "i1":case "i8":return 1;case "i16":return 2;case "i32":return 4;case "i64":return 8;case "float":return 4;case "double":return 8;default:return"*"===a[a.length-1]?t.V:"i"===a[0]?(a=parseInt(a.substr(1)),assert(0===a%8),a/8):0}},Ma:function(a){return Math.max(t.va(a),t.V)},Wc:16,rd:function(a,b){"double"===b||"i64"===b?a&7&&(assert(4===(a&7)),a+=4):assert(0=== +(a&3));return a},ed:function(a,b,c){return c||"i64"!=a&&"double"!=a?a?Math.min(b||(a?t.Ma(a):0),t.V):Math.min(b,8):8},t:function(a,b,c){return c&&c.length?e["dynCall_"+a].apply(null,[b].concat(c)):e["dynCall_"+a].call(null,b)},N:[],Ha:function(a){for(var b=0;b>2];a=(b+a+15|0)&-16;w[x>>2]=a;if(a=a>=ha)ia(),a=!0;return a?(w[x>>2]=b,0):b},ma:function(a,b){return Math.ceil(a/(b?b:16))*(b?b:16)},qd:function(a,b,c){return c?+(a>>>0)+4294967296*+(b>>>0):+(a>>>0)+4294967296*+(b|0)},L:8,V:4,Xc:0};e.Runtime=t;t.addFunction=t.Ha;t.removeFunction=t.Sa;var ja=!1;function assert(a,b){a||z("Assertion failed: "+b)} +function ka(a){var b=e["_"+a];if(!b)try{b=eval("_"+a)}catch(c){}assert(b,"Cannot call unknown function "+a+" (perhaps LLVM optimizations or closure removed it?)");return b}var la,ma; +(function(){function a(a){a=a.toString().match(f).slice(1);return{arguments:a[0],body:a[1],returnValue:a[2]}}function b(){if(!g){g={};for(var b in c)c.hasOwnProperty(b)&&(g[b]=a(c[b]))}}var c={stackSave:function(){t.Q()},stackRestore:function(){t.I()},arrayToC:function(a){var b=t.P(a.length);na(a,b);return b},stringToC:function(a){var b=0;if(null!==a&&void 0!==a&&0!==a){var c=(a.length<<2)+1,b=t.P(c);oa(a,b,c)}return b}},d={string:c.stringToC,array:c.arrayToC};ma=function(a,b,c,f,g){a=ka(a);var y= +[],H=0;if(f)for(var A=0;A>0]=b;break;case "i8":C[a>>0]=b;break;case "i16":qa[a>>1]=b;break;case "i32":w[a>>2]=b;break;case "i64":tempI64=[b>>>0,(tempDouble=b,1<=+ra(tempDouble)?0>>0:~~+ua((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)];w[a>>2]=tempI64[0];w[a+4>>2]=tempI64[1];break;case "float":va[a>>2]=b;break;case "double":wa[a>>3]=b;break;default:z("invalid type for setValue: "+ +c)}}e.setValue=pa;function xa(a,b){b=b||"i8";"*"===b.charAt(b.length-1)&&(b="i32");switch(b){case "i1":return C[a>>0];case "i8":return C[a>>0];case "i16":return qa[a>>1];case "i32":return w[a>>2];case "i64":return w[a>>2];case "float":return va[a>>2];case "double":return wa[a>>3];default:z("invalid type for setValue: "+b)}return null}e.getValue=xa;e.ALLOC_NORMAL=0;e.ALLOC_STACK=1;e.ALLOC_STATIC=2;e.ALLOC_DYNAMIC=3;e.ALLOC_NONE=4; +function D(a,b,c,d){var f,g;"number"===typeof a?(f=!0,g=a):(f=!1,g=a.length);var h="string"===typeof b?b:null;c=4==c?d:["function"===typeof E?E:t.ga,t.P,t.ga,t.qa][void 0===c?2:c](Math.max(g,h?1:b.length));if(f){d=c;assert(0==(c&3));for(a=c+(g&-4);d>2]=0;for(a=c+g;d>0]=0;return c}if("i8"===h)return a.subarray||a.slice?F.set(a,c):F.set(new Uint8Array(a),c),c;d=0;for(var n,u;d>0];c|=d;if(0==d&&!b)break;f++;if(b&&f==b)break}b||(b=f);d="";if(128>c){for(;0>0];if(!c)return b;b+=String.fromCharCode(c)}}; +e.stringToAscii=function(a,b){return Aa(a,b,!1)};var Ba="undefined"!==typeof TextDecoder?new TextDecoder("utf8"):void 0; +function Ca(a,b){for(var c=b;a[c];)++c;if(16d?c+=String.fromCharCode(d):(d-=65536,c+=String.fromCharCode(55296|d>> +10,56320|d&1023)))):c+=String.fromCharCode(d)}}e.UTF8ArrayToString=Ca;e.UTF8ToString=function(a){return Ca(F,a)}; +function Da(a,b,c,d){if(!(0=h&&(h=65536+((h&1023)<<10)|a.charCodeAt(++g)&1023);if(127>=h){if(c>=d)break;b[c++]=h}else{if(2047>=h){if(c+1>=d)break;b[c++]=192|h>>6}else{if(65535>=h){if(c+2>=d)break;b[c++]=224|h>>12}else{if(2097151>=h){if(c+3>=d)break;b[c++]=240|h>>18}else{if(67108863>=h){if(c+4>=d)break;b[c++]=248|h>>24}else{if(c+5>=d)break;b[c++]=252|h>>30;b[c++]=128|h>>24&63}b[c++]=128|h>>18&63}b[c++]=128| +h>>12&63}b[c++]=128|h>>6&63}b[c++]=128|h&63}}b[c]=0;return c-f}e.stringToUTF8Array=Da;function oa(a,b,c){return Da(a,F,b,c)}e.stringToUTF8=oa;function Ea(a){for(var b=0,c=0;c=d&&(d=65536+((d&1023)<<10)|a.charCodeAt(++c)&1023);127>=d?++b:b=2047>=d?b+2:65535>=d?b+3:2097151>=d?b+4:67108863>=d?b+5:b+6}return b}e.lengthBytesUTF8=Ea;"undefined"!==typeof TextDecoder&&new TextDecoder("utf-16le"); +function Fa(a){return a.replace(/__Z[\w\d_]+/g,function(a){var c;a:{if(e.___cxa_demangle)try{var d=a.substr(1),f=Ea(d)+1,g=E(f);oa(d,g,f);var h=E(4),n=e.___cxa_demangle(g,0,0,h);if(0===xa(h,"i32")&&n){c=B(n);break a}}catch(u){}finally{g&&Ga(g),h&&Ga(h),n&&Ga(n)}else t.A("warning: build with -s DEMANGLE_SUPPORT=1 to link in libcxxabi demangling");c=a}return a===c?a:a+" ["+c+"]"})} +function Ha(){var a;a:{a=Error();if(!a.stack){try{throw Error(0);}catch(b){a=b}if(!a.stack){a="(no stack trace available)";break a}}a=a.stack.toString()}e.extraStackTrace&&(a+="\n"+e.extraStackTrace());return Fa(a)}e.stackTrace=Ha;var buffer,C,F,qa,Ia,w,Ja,va,wa,Ka,v,ya,La,p,Ma,Oa,x;Ka=v=La=p=Ma=Oa=x=0;ya=!1; +function ia(){z("Cannot enlarge memory arrays. Either (1) compile with -s TOTAL_MEMORY=X with X higher than the current value "+ha+", (2) compile with -s ALLOW_MEMORY_GROWTH=1 which adjusts the size at runtime but prevents some optimizations, (3) set Module.TOTAL_MEMORY to a higher value before the program runs, or if you want malloc to return NULL (0) instead of this abort, compile with -s ABORTING_MALLOC=0 ")} +for(var Pa=e.TOTAL_STACK||5242880,ha=e.TOTAL_MEMORY||16777216,G=65536;GG?2*G:G+16777216;G!==ha&&(ha=G);e.buffer?buffer=e.buffer:buffer=new ArrayBuffer(ha);e.HEAP8=C=new Int8Array(buffer);e.HEAP16=qa=new Int16Array(buffer);e.HEAP32=w=new Int32Array(buffer);e.HEAPU8=F=new Uint8Array(buffer);e.HEAPU16=Ia=new Uint16Array(buffer);e.HEAPU32=Ja=new Uint32Array(buffer);e.HEAPF32=va=new Float32Array(buffer);e.HEAPF64=wa=new Float64Array(buffer);w[0]=1668509029;qa[1]=25459; +if(115!==F[2]||99!==F[3])throw"Runtime error: expected the system to be little-endian!";e.HEAP=void 0;e.buffer=buffer;e.HEAP8=C;e.HEAP16=qa;e.HEAP32=w;e.HEAPU8=F;e.HEAPU16=Ia;e.HEAPU32=Ja;e.HEAPF32=va;e.HEAPF64=wa;function Qa(a){for(;0>0]=a.charCodeAt(d);c||(C[b>>0]=0)}e.writeAsciiToMemory=Aa;Math.imul&&-5===Math.imul(4294967295,5)||(Math.imul=function(a,b){var c=a&65535,d=b&65535;return c*d+((a>>>16)*d+c*(b>>>16)<<16)|0});Math.ld=Math.imul; +Math.clz32||(Math.clz32=function(a){a=a>>>0;for(var b=0;32>b;b++)if(a&1<<31-b)return b;return 32});Math.bd=Math.clz32;Math.trunc||(Math.trunc=function(a){return 0>a?Math.ceil(a):Math.floor(a)});Math.trunc=Math.trunc;var ra=Math.abs,ua=Math.ceil,ta=Math.floor,sa=Math.min,Ya=0,Za=null,$a=null;function ab(){Ya++;e.monitorRunDependencies&&e.monitorRunDependencies(Ya)}e.addRunDependency=ab; +function bb(){Ya--;e.monitorRunDependencies&&e.monitorRunDependencies(Ya);if(0==Ya&&(null!==Za&&(clearInterval(Za),Za=null),$a)){var a=$a;$a=null;a()}}e.removeRunDependency=bb;e.preloadedImages={};e.preloadedAudios={};Ka=8;v=Ka+40448;Sa.push(); +D([8,201,188,243,103,230,9,106,59,167,202,132,133,174,103,187,43,248,148,254,114,243,110,60,241,54,29,95,58,245,79,165,209,130,230,173,127,82,14,81,31,108,62,43,140,104,5,155,107,189,65,251,171,217,131,31,121,33,126,19,25,205,224,91,34,174,40,215,152,47,138,66,205,101,239,35,145,68,55,113,47,59,77,236,207,251,192,181,188,219,137,129,165,219,181,233,56,181,72,243,91,194,86,57,25,208,5,182,241,17,241,89,155,79,25,175,164,130,63,146,24,129,109,218,213,94,28,171,66,2,3,163,152,170,7,216,190,111,112,69, +1,91,131,18,140,178,228,78,190,133,49,36,226,180,255,213,195,125,12,85,111,137,123,242,116,93,190,114,177,150,22,59,254,177,222,128,53,18,199,37,167,6,220,155,148,38,105,207,116,241,155,193,210,74,241,158,193,105,155,228,227,37,79,56,134,71,190,239,181,213,140,139,198,157,193,15,101,156,172,119,204,161,12,36,117,2,43,89,111,44,233,45,131,228,166,110,170,132,116,74,212,251,65,189,220,169,176,92,181,83,17,131,218,136,249,118,171,223,102,238,82,81,62,152,16,50,180,45,109,198,49,168,63,33,251,152,200, +39,3,176,228,14,239,190,199,127,89,191,194,143,168,61,243,11,224,198,37,167,10,147,71,145,167,213,111,130,3,224,81,99,202,6,112,110,14,10,103,41,41,20,252,47,210,70,133,10,183,39,38,201,38,92,56,33,27,46,237,42,196,90,252,109,44,77,223,179,149,157,19,13,56,83,222,99,175,139,84,115,10,101,168,178,119,60,187,10,106,118,230,174,237,71,46,201,194,129,59,53,130,20,133,44,114,146,100,3,241,76,161,232,191,162,1,48,66,188,75,102,26,168,145,151,248,208,112,139,75,194,48,190,84,6,163,81,108,199,24,82,239,214, +25,232,146,209,16,169,101,85,36,6,153,214,42,32,113,87,133,53,14,244,184,209,187,50,112,160,106,16,200,208,210,184,22,193,164,25,83,171,65,81,8,108,55,30,153,235,142,223,76,119,72,39,168,72,155,225,181,188,176,52,99,90,201,197,179,12,28,57,203,138,65,227,74,170,216,78,115,227,99,119,79,202,156,91,163,184,178,214,243,111,46,104,252,178,239,93,238,130,143,116,96,47,23,67,111,99,165,120,114,171,240,161,20,120,200,132,236,57,100,26,8,2,199,140,40,30,99,35,250,255,190,144,233,189,130,222,235,108,80,164, +21,121,198,178,247,163,249,190,43,83,114,227,242,120,113,198,156,97,38,234,206,62,39,202,7,194,192,33,199,184,134,209,30,235,224,205,214,125,218,234,120,209,110,238,127,79,125,245,186,111,23,114,170,103,240,6,166,152,200,162,197,125,99,10,174,13,249,190,4,152,63,17,27,71,28,19,53,11,113,27,132,125,4,35,245,119,219,40,147,36,199,64,123,171,202,50,188,190,201,21,10,190,158,60,76,13,16,156,196,103,29,67,182,66,62,203,190,212,197,76,42,126,101,252,156,41,127,89,236,250,214,58,171,111,203,95,23,88,71, +74,140,25,68,108,47,252,255,63,251,255,255,63,255,255,255,63,255,255,255,63,255,255,255,63,255,255,255,63,255,255,255,63,255,255,255,63,255,255,0,0,152,23,248,22,108,5,202,39,149,141,226,28,203,54,255,38,2,7,11,7,58,87,138,1,90,197,186,11,119,190,159,25,190,121,0,0,184,212,16,59,63,66,31,49,153,65,85,40,41,18,237,5,253,168,8,17,56,240,239,19,218,85,70,60,168,201,157,54,58,72,0,0,65,65,54,16,51,122,73,63,187,3,138,52,171,57,183,43,186,254,255,63,255,255,255,63,255,255,255,63,255,255,255,63,255,255, +0,0,160,32,27,40,25,189,164,63,221,1,69,58,213,156,219,21,93,255,255,63,255,255,255,63,255,255,255,63,255,255,255,63,255,127,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,152,23,248,22,108,5,202,39,149,141,226,28,203,54,255,38,2,7,11,7,58,87,138,1,90,197,186,11,119,190,159,25,190,121,0,0,184,212,16,59,63,66,31,49,153,65,85,40,41,18,237,5,253,168,8,17,56,240,239,19,218,85,70,60,168,201,157,54,58,72,0,0,249,54,224,60,78,196,7,24,8,155,249,54,96,17,114,12,181,41, +82,29,226,23,62,17,147,4,49,12,150,100,128,34,48,249,0,0,114,230,184,4,214,245,231,50,182,49,34,12,77,102,42,0,101,86,243,55,168,152,223,12,254,64,129,30,203,216,195,30,143,56,0,0,228,239,64,50,166,85,163,46,124,171,25,6,119,47,225,34,232,40,81,28,41,148,156,18,91,53,9,50,129,70,147,55,139,47,0,0,214,98,172,38,234,244,161,50,13,132,214,48,234,198,9,34,247,38,196,9,155,118,167,46,77,109,61,30,185,141,137,8,172,216,0,0,188,249,196,10,183,119,175,36,206,57,14,51,128,223,102,16,61,14,122,42,203,151,205, +35,57,170,78,27,151,27,25,60,189,92,0,0,218,100,114,8,160,152,32,20,90,123,222,63,4,46,244,4,168,219,84,26,24,182,53,30,49,10,150,21,137,46,144,50,235,106,0,0,190,204,39,60,55,68,124,13,76,113,126,5,211,165,229,37,224,189,154,21,125,42,94,52,154,48,101,63,49,188,56,33,212,172,0,0,55,156,79,6,171,152,48,23,240,224,248,53,13,41,34,54,173,233,97,59,216,197,37,32,67,214,159,61,41,108,72,34,51,204,0,0,203,8,160,29,37,94,176,47,27,137,23,28,249,2,102,18,86,172,90,6,195,173,145,16,239,229,17,20,42,22,254, +57,74,119,0,0,27,198,83,9,39,211,117,0,131,106,157,63,183,120,108,11,55,101,179,55,94,91,117,15,36,144,225,53,218,186,12,40,132,217,0,0,168,90,64,25,60,126,183,59,221,140,229,16,152,241,126,29,176,81,134,52,13,23,72,7,125,188,136,18,93,182,240,28,135,242,0,0,129,237,3,27,75,45,215,38,242,145,250,33,148,182,129,6,58,71,175,13,151,173,75,8,88,151,168,0,98,163,11,36,176,10,0,0,14,8,126,34,227,243,182,18,228,121,95,8,207,27,101,57,49,17,244,31,37,140,107,25,164,101,169,62,80,223,83,19,146,215,0,0,88, +107,162,54,127,114,19,20,92,58,109,9,246,202,43,16,234,239,109,12,163,8,187,16,56,104,42,7,27,170,28,10,30,88,0,0,10,236,109,42,120,162,59,17,156,174,165,7,110,218,196,40,178,151,62,2,135,240,170,6,1,83,236,41,103,237,164,51,15,230,0,0,33,104,97,41,57,179,204,7,190,240,35,13,145,71,162,37,18,16,55,57,213,211,124,38,219,41,89,25,121,230,28,20,227,247,0,0,195,229,24,17,168,194,97,47,25,188,190,18,209,201,230,21,252,75,91,38,211,187,149,5,68,219,7,19,145,101,215,12,202,110,0,0,104,134,160,5,224,189, +40,38,68,195,142,63,142,142,90,18,58,160,117,56,210,65,94,61,146,5,113,32,158,94,237,8,1,213,0,0,46,246,135,15,133,199,52,59,112,18,22,55,24,142,185,57,16,240,89,6,77,59,209,49,215,192,14,57,111,188,239,14,98,233,0,0,55,231,78,36,190,250,4,12,229,68,136,22,119,242,16,24,254,41,169,26,59,234,84,58,15,158,158,41,240,210,14,29,169,56,0,0,60,115,141,42,224,183,42,44,158,143,202,47,216,47,157,48,255,130,214,0,130,188,141,18,136,160,219,33,69,249,92,55,130,188,0,0,240,151,119,52,19,132,225,57,1,115,137, +51,185,46,232,36,174,223,2,31,198,253,210,38,74,197,202,49,18,129,14,35,242,229,0,0,113,118,188,31,197,136,191,31,45,227,88,40,20,242,198,15,116,144,244,24,94,56,71,10,32,29,33,23,217,49,146,4,61,142,0,0,236,125,113,24,144,113,199,59,167,68,225,35,169,234,74,13,185,14,233,19,78,134,3,18,100,31,184,60,179,67,56,18,154,9,0,0,178,29,179,62,202,208,161,12,15,106,80,15,226,9,186,50,143,182,162,8,66,251,100,40,150,136,73,10,141,136,106,36,168,120,0,0,67,67,250,57,142,88,167,1,211,130,11,0,118,243,230,13, +84,246,45,48,156,84,201,23,207,191,92,3,212,250,214,40,18,105,0,0,149,229,176,13,222,61,210,20,182,43,8,58,126,46,143,5,167,235,118,32,5,150,221,56,124,125,177,49,118,21,6,30,134,125,0,0,232,61,115,60,234,120,84,38,41,83,93,34,131,19,225,13,41,56,136,15,181,175,184,24,229,114,135,47,33,251,183,38,185,226,0,0,252,13,6,22,20,190,63,2,160,162,230,5,8,225,23,21,118,134,176,26,16,119,46,37,132,132,172,2,22,192,67,12,197,221,0,0,168,12,130,39,219,42,126,45,15,115,4,61,170,241,235,54,65,144,14,15,50,183, +173,6,25,32,105,25,131,188,206,11,13,186,0,0,8,21,245,21,255,136,27,25,16,202,193,26,245,42,231,48,216,56,226,45,92,248,184,41,162,158,157,32,177,132,140,9,130,130,0,0,175,108,226,54,191,186,109,12,237,123,177,55,11,235,132,53,98,206,10,54,194,160,91,9,232,69,254,61,85,97,2,42,248,17,0,0,250,141,126,37,231,50,240,51,79,24,126,60,104,100,36,32,9,160,140,41,178,226,195,40,217,192,196,25,30,252,203,51,98,130,0,0,106,55,172,59,99,227,63,23,131,71,76,49,202,76,187,45,87,52,79,51,22,187,136,59,111,230, +228,9,68,130,120,37,253,131,0,0,111,219,107,2,44,146,75,1,73,185,52,55,30,245,6,41,124,135,156,41,51,201,22,4,104,81,221,13,104,199,34,23,130,25,0,0,155,252,156,4,19,194,125,23,107,58,109,15,35,179,123,58,235,108,159,53,83,50,135,9,32,243,120,8,83,195,67,12,148,98,0,0,76,130,130,61,72,37,180,3,101,78,83,33,23,141,99,41,223,158,153,2,27,187,213,23,60,68,145,1,88,4,27,54,18,111,0,0,208,52,235,6,32,13,231,21,184,197,75,5,66,144,36,7,57,105,55,34,245,207,83,38,117,8,250,59,172,18,253,61,79,92,0,0,41, +54,69,27,11,112,183,29,48,96,158,53,3,55,247,51,69,246,190,58,136,90,156,24,66,209,165,42,130,230,27,35,58,32,0,0,132,159,248,63,20,30,199,37,69,237,133,18,113,201,122,27,104,18,6,1,125,69,219,49,108,147,155,29,151,247,212,2,15,59,0,0,203,126,108,36,119,195,196,32,151,206,180,27,249,79,187,14,157,236,225,38,33,205,220,59,129,28,24,52,64,207,186,50,42,110,0,0,32,135,188,46,123,128,36,17,200,18,117,54,70,174,193,49,250,58,100,59,195,107,19,3,216,73,225,62,251,229,25,41,97,158,0,0,126,20,164,48,207, +99,192,45,30,32,95,55,253,98,247,17,39,88,10,9,41,250,197,5,246,186,86,17,122,186,36,1,167,213,0,0,255,101,251,51,224,242,44,57,248,87,127,22,30,97,54,49,244,50,5,30,217,65,38,36,196,111,156,56,234,118,189,9,181,157,0,0,198,206,237,24,175,209,118,59,84,244,52,54,180,48,135,1,161,198,218,44,192,24,191,15,82,128,186,24,248,170,102,4,197,56,0,0,8,219,51,25,236,47,184,21,100,10,83,53,138,32,91,40,40,47,40,31,157,104,203,50,104,166,50,23,118,161,72,55,73,230,0,0,57,183,229,17,213,150,243,15,215,46,34, +18,255,12,78,46,224,109,132,60,27,27,115,38,47,167,101,56,162,220,103,5,94,23,0,0,149,214,254,41,251,191,233,59,198,69,67,18,183,86,101,45,172,94,31,55,127,148,94,62,78,186,158,7,143,103,131,27,80,211,0,0,22,18,4,5,199,227,223,22,166,54,184,2,161,125,205,28,63,82,237,47,112,191,103,45,40,65,207,58,125,200,94,12,117,218,0,0,114,133,112,46,97,202,180,43,173,237,172,55,185,30,176,42,233,198,127,45,208,108,136,39,241,13,95,45,220,175,17,40,248,115,0,0,48,169,101,36,199,249,80,0,219,47,53,49,90,112,252, +33,37,30,235,2,42,49,22,15,87,112,157,52,165,35,109,49,113,28,0,0,181,56,70,3,179,253,28,54,113,212,116,49,237,143,23,13,121,140,182,11,9,202,199,15,113,194,160,31,61,58,205,48,145,74,0,0,231,110,219,58,150,107,99,12,126,7,74,52,201,80,55,20,120,156,76,27,66,234,13,58,54,105,86,26,204,7,191,18,78,216,0,0,210,190,46,20,155,91,85,11,152,100,62,42,210,37,43,54,253,77,222,37,213,99,53,14,42,225,156,55,30,159,38,32,37,229,0,0,16,109,158,36,62,123,58,37,35,157,201,42,235,252,183,2,246,211,110,63,23,74, +174,8,27,212,20,40,153,247,18,17,212,243,0,0,63,218,71,19,1,51,14,40,48,198,214,41,51,148,182,6,252,91,75,10,102,176,86,46,186,212,99,1,188,233,55,9,67,10,0,0,7,58,211,41,27,208,44,35,180,202,155,35,42,130,187,28,78,4,244,61,54,131,84,33,144,159,216,1,103,39,75,25,48,174,0,0,166,178,160,32,61,48,28,18,199,149,126,61,119,253,13,39,28,207,213,56,246,76,159,51,252,126,229,63,88,227,112,54,185,108,0,0,202,202,40,12,228,82,89,22,167,29,40,8,243,238,113,26,24,154,140,56,12,214,249,5,94,129,28,30,245,150, +202,6,220,216,0,0,122,236,179,35,168,219,217,54,108,143,18,8,59,75,87,12,125,148,125,36,128,144,54,54,198,88,125,44,243,73,182,2,236,140,0,0,111,65,196,59,152,237,135,36,40,64,176,48,252,72,191,43,167,29,243,50,64,163,150,16,89,205,236,4,126,177,164,56,73,39,0,0,142,189,107,60,139,247,98,58,87,16,150,46,151,237,167,39,245,62,219,10,63,100,82,54,3,68,188,50,217,141,83,11,204,80,0,0,64,70,255,3,62,182,174,9,229,255,82,21,149,31,7,17,83,224,46,38,216,22,176,58,156,201,201,0,236,17,53,36,61,54,0,0,233, +157,238,59,252,241,0,8,182,236,153,1,2,36,106,46,69,49,54,51,95,78,17,45,83,25,34,50,28,127,235,28,226,4,0,0,200,93,229,54,91,72,36,46,148,67,160,44,186,173,86,62,111,66,148,16,1,3,145,18,168,43,251,31,49,228,17,16,49,68,0,0,179,35,227,27,187,18,101,7,3,229,162,42,231,109,138,26,166,215,254,2,89,253,13,38,233,143,111,54,148,185,80,48,176,150,0,0,168,35,27,48,117,33,165,63,173,224,126,40,194,81,223,30,171,157,8,33,228,86,15,9,38,193,135,10,155,97,163,63,34,158,0,0,174,237,132,8,20,79,144,30,207,206, +17,53,126,82,242,61,192,51,21,28,38,8,252,60,119,1,209,34,132,114,58,60,47,253,0,0,228,112,26,7,252,34,208,53,93,71,207,53,215,71,185,23,205,109,48,5,28,153,167,53,237,210,168,34,243,64,181,61,141,80,0,0,132,9,149,41,220,111,185,60,237,223,170,40,59,138,12,48,78,197,73,62,204,169,18,12,119,215,66,60,206,228,230,16,76,21,0,0,17,190,26,14,219,105,191,58,246,32,178,28,150,112,72,46,218,178,37,1,76,6,214,55,56,51,118,9,68,21,225,63,219,227,0,0,99,222,168,31,82,181,38,45,20,196,181,6,15,100,95,50,211, +243,142,10,110,215,233,35,67,22,66,1,141,102,66,62,242,6,0,0,73,52,89,3,216,200,198,51,253,111,164,2,185,4,223,6,246,74,1,61,129,78,112,54,120,216,64,41,247,49,25,56,172,25,0,0,49,54,248,45,78,46,5,41,163,104,64,8,208,231,66,28,172,70,44,0,101,231,92,47,254,59,51,10,154,212,128,36,121,227,0,0,99,107,186,12,75,98,250,56,94,187,179,16,63,157,249,3,10,49,142,40,58,138,204,48,8,161,218,7,62,8,59,3,116,216,0,0,243,197,52,41,1,219,168,59,171,148,22,56,48,215,19,4,64,125,195,58,64,166,187,41,120,243,43, +19,174,241,76,48,114,100,0,0,56,192,62,27,176,252,83,6,118,178,198,32,185,90,84,63,217,80,10,41,188,216,249,32,72,54,8,6,212,70,206,12,172,88,0,0,121,98,36,16,196,143,170,27,161,188,251,52,2,15,65,6,2,151,254,17,166,39,73,30,135,151,45,9,87,181,193,53,99,145,0,0,12,248,253,31,87,105,222,39,182,209,188,21,104,224,41,57,67,136,99,5,221,214,18,9,198,232,43,60,124,151,197,23,75,139,0,0,54,253,212,31,25,195,191,15,107,229,46,22,24,149,205,56,249,4,218,48,234,4,94,47,63,75,139,48,52,218,155,2,173,74,0, +0,221,18,88,53,11,150,138,2,42,14,211,18,213,200,25,17,61,142,247,24,1,91,251,42,182,240,82,51,191,164,94,47,41,112,0,0,39,41,45,26,172,25,115,8,199,115,44,59,144,16,186,54,71,172,131,6,140,43,81,25,221,39,61,11,122,191,182,62,238,176,0,0,209,110,72,61,14,90,57,39,164,182,101,21,146,174,111,17,87,96,117,15,99,39,4,53,9,144,201,37,185,186,114,59,207,156,0,0,141,93,233,53,181,103,181,61,36,170,146,21,90,214,89,8,36,17,52,11,128,4,146,8,97,251,44,35,90,79,92,19,47,124,0,0,202,234,208,27,157,198,26,8, +122,171,212,34,174,93,209,49,208,25,223,36,242,140,247,35,90,51,20,20,208,216,225,18,154,205,0,0,204,74,255,43,214,190,190,57,246,52,246,22,187,227,236,9,1,139,160,62,76,186,34,18,21,232,35,15,122,104,30,22,69,240,0,0,198,87,188,7,143,78,37,8,191,108,39,43,143,232,245,0,73,148,48,22,79,186,180,60,132,168,190,25,59,226,11,34,9,173,0,0,184,10,74,46,182,3,203,40,60,45,14,25,205,77,71,12,123,95,190,26,167,28,27,6,40,186,82,58,190,16,35,48,67,114,0,0,2,99,165,43,202,49,12,42,46,134,241,48,235,77,170,1, +245,224,210,58,167,74,139,54,234,241,65,10,207,186,66,10,209,217,0,0,41,28,41,8,234,107,183,42,174,242,116,58,103,179,107,14,23,228,134,35,201,25,87,28,41,208,238,19,11,251,68,12,181,126,0,0,58,36,209,52,19,220,52,43,219,95,74,53,143,128,73,44,2,132,85,63,24,176,134,52,28,249,206,22,231,148,119,30,80,188,0,0,138,182,93,5,162,69,37,23,159,22,71,31,108,61,185,31,95,215,200,63,55,229,202,49,238,184,203,5,156,206,142,10,6,101,0,0,159,63,74,55,154,19,73,35,144,22,152,0,119,153,233,33,194,90,98,50,246, +185,170,55,19,137,126,60,23,148,223,41,49,77,0,0,167,11,30,48,4,9,44,63,84,167,0,46,109,212,190,61,203,83,39,0,30,227,60,6,107,176,117,5,38,88,178,7,36,34,0,0,218,252,50,18,73,86,132,45,188,119,14,44,233,255,54,0,183,199,72,21,47,0,199,29,191,214,150,57,118,185,169,46,60,114,0,0,95,159,179,30,118,26,112,7,128,148,148,55,77,25,40,24,38,110,77,2,34,210,77,4,146,138,73,12,87,86,237,25,232,150,0,0,177,60,99,0,122,130,159,21,50,17,2,29,218,146,136,22,87,203,31,24,72,200,156,24,12,64,173,44,234,197,60, +39,222,109,0,0,52,107,206,39,169,38,117,31,53,239,89,56,179,246,159,44,128,168,102,58,134,26,190,39,201,213,65,62,193,233,249,62,136,145,0,0,197,243,51,41,52,70,105,6,36,82,18,31,69,220,131,22,8,80,184,7,57,254,237,18,60,129,222,28,109,53,203,41,111,72,0,0,83,15,251,10,107,156,82,43,121,59,242,48,243,224,109,54,98,159,241,8,179,235,34,49,72,62,212,61,90,125,198,8,225,98,0,0,40,247,153,30,137,80,86,47,78,32,18,47,249,126,221,28,103,3,83,42,221,158,252,19,102,251,244,10,37,42,93,26,121,36,0,0,255,235, +170,43,91,20,128,30,131,45,90,23,37,240,252,54,90,74,102,13,246,249,161,11,197,30,0,51,35,26,81,35,215,227,0,0,154,7,176,47,80,27,131,39,156,4,38,57,200,189,231,27,145,36,131,51,218,185,103,41,49,6,255,21,245,168,246,50,57,47,0,0,186,144,86,44,192,92,138,56,15,35,160,2,34,239,207,62,155,139,165,13,158,64,219,36,218,52,152,35,225,132,247,54,234,171,0,0,115,171,247,36,203,2,204,36,119,58,68,20,167,58,245,56,98,210,174,52,20,27,122,14,106,165,27,22,159,12,91,7,163,229,0,0,66,31,86,48,241,143,78,36,19, +162,203,0,106,18,17,35,191,93,206,14,233,93,42,6,193,160,215,41,71,99,15,35,120,55,0,0,134,205,77,1,143,166,228,35,88,27,247,43,37,8,117,49,31,241,220,17,129,96,118,3,245,125,68,19,69,131,82,39,56,204,0,0,115,168,240,8,103,183,173,35,70,135,231,39,63,134,95,49,5,202,16,41,250,110,47,26,181,217,190,43,61,152,245,19,174,147,0,0,17,147,129,56,173,27,231,19,114,20,119,8,132,184,135,15,11,31,237,53,51,248,133,2,117,35,144,30,92,39,114,36,146,127,0,0,37,177,46,44,94,109,126,42,74,23,106,8,39,144,170,2, +18,182,21,36,20,49,122,3,93,15,239,3,251,24,68,3,160,157,0,0,250,215,125,14,40,251,76,41,57,152,145,58,141,132,229,17,9,181,211,2,75,32,187,63,165,139,249,43,239,36,53,41,191,238,0,0,153,137,222,33,107,63,245,55,45,113,31,49,233,112,51,57,154,157,8,56,197,107,251,57,158,38,15,47,195,229,40,35,154,93,0,0,235,236,124,59,254,227,217,15,15,175,127,9,226,228,103,41,115,20,104,46,189,73,224,62,111,3,69,45,157,16,136,33,122,67,0,0,225,129,193,22,13,243,142,13,39,120,249,8,247,243,131,8,135,255,151,18,103, +218,250,35,155,246,50,44,186,79,232,26,145,11,0,0,242,150,127,9,120,202,53,22,205,53,135,44,116,74,141,32,53,115,194,60,104,238,248,45,60,200,155,8,169,248,196,39,239,169,0,0,228,75,192,22,193,86,245,0,44,112,180,41,214,107,226,19,183,61,97,59,58,88,184,27,149,205,215,25,21,101,57,51,20,232,0,0,126,247,12,53,132,214,42,48,219,176,138,10,21,93,253,54,7,66,6,42,126,90,159,32,83,229,91,19,135,123,80,1,216,102,0,0,166,163,234,32,190,94,126,41,210,118,27,59,173,14,45,17,148,246,19,22,77,129,80,7,63,44, +180,63,191,204,249,55,207,81,0,0,90,58,33,7,162,24,82,13,185,98,250,5,158,18,200,28,11,200,195,12,25,135,34,20,243,43,250,3,148,77,120,1,172,98,0,0,69,158,106,52,3,135,52,4,252,78,153,23,96,64,66,22,229,121,37,41,30,120,158,23,57,77,110,26,52,232,124,47,111,35,0,0,43,209,186,39,97,82,63,12,236,225,102,47,58,128,122,53,133,179,45,47,113,189,78,24,191,181,245,8,145,92,18,49,19,202,0,0,242,176,35,23,26,125,166,37,104,86,87,26,68,220,42,28,99,214,163,45,170,147,233,23,193,138,124,40,112,216,96,2,170, +131,0,0,78,65,128,28,229,151,187,54,253,247,108,22,139,161,226,59,20,73,158,32,17,61,113,4,172,133,174,18,193,105,64,44,236,28,0,0,59,154,22,18,75,82,186,50,13,29,35,7,81,249,85,29,144,22,173,45,215,160,140,42,229,180,207,23,130,165,25,24,67,243,0,0,169,16,216,14,49,242,214,19,92,21,0,7,207,79,39,34,79,146,35,31,199,215,107,3,149,204,249,56,53,65,29,36,105,42,0,0,40,71,155,58,35,206,26,62,124,92,20,44,95,250,81,31,102,252,4,59,83,165,97,49,62,172,253,31,15,219,230,0,249,84,0,0,176,141,164,57,108, +13,94,63,254,59,192,51,166,104,133,4,159,69,222,59,109,130,66,7,121,114,22,39,91,154,54,17,15,16,0,0,9,90,198,43,88,115,245,62,192,90,25,53,63,134,210,63,183,102,6,9,48,192,204,35,236,114,183,0,168,100,76,56,217,205,0,0,180,21,188,21,210,132,230,50,105,238,162,37,145,163,64,29,146,141,202,23,59,167,59,22,216,158,220,42,123,148,139,3,233,16,0,0,141,37,170,24,37,152,175,19,131,168,182,43,192,88,98,41,76,117,31,45,90,24,163,30,213,36,4,30,53,224,192,13,138,198,0,0,105,82,231,63,192,240,79,55,130,49, +211,19,1,243,232,29,163,205,125,11,197,45,228,22,87,132,99,1,149,182,208,11,66,247,0,0,213,155,228,23,28,58,96,34,1,142,57,10,253,141,232,44,127,151,53,54,231,114,159,51,24,253,147,48,196,140,198,11,108,64,0,0,95,23,167,53,91,154,237,20,166,66,207,49,116,220,57,46,237,187,222,21,11,86,105,30,40,247,207,3,245,5,65,43,140,45,0,0,42,89,157,59,70,238,222,60,12,94,94,11,103,255,26,33,122,55,157,44,132,233,203,8,187,167,148,10,99,204,224,14,63,199,0,0,69,16,181,20,14,111,50,13,62,91,194,49,188,37,178,49, +187,115,207,40,199,58,245,28,174,88,234,38,98,110,71,63,203,30,0,0,38,0,199,2,4,196,153,14,213,34,100,3,173,145,1,36,177,56,155,26,18,198,46,52,71,100,58,28,230,34,140,56,246,28,0,0,51,133,53,41,155,93,179,30,223,185,180,15,117,254,76,42,16,140,42,19,71,138,86,37,62,136,82,55,149,127,49,37,8,154,0,0,8,186,96,3,119,113,248,44,223,218,13,56,110,111,185,41,101,33,195,15,85,126,245,5,249,49,252,56,6,8,241,32,152,167,0,0,246,247,142,25,88,23,16,37,246,249,120,32,222,253,252,8,89,166,174,56,206,73,33,39, +189,53,46,61,211,118,18,54,77,102,0,0,148,172,30,29,205,191,37,29,238,236,230,56,198,172,78,15,252,207,88,4,116,151,51,18,20,42,147,39,252,197,5,8,81,173,0,0,179,52,201,3,223,154,2,3,78,44,174,48,22,96,125,12,43,2,167,17,96,154,101,7,35,56,134,11,244,221,164,14,17,130,0,0,15,106,44,4,171,152,151,31,55,128,70,36,166,9,223,7,170,40,198,32,214,202,179,25,132,96,102,35,107,178,54,46,161,141,0,0,45,253,52,37,155,55,43,50,82,56,59,15,25,81,227,31,167,23,192,4,40,233,137,36,220,177,209,62,177,152,248,6, +3,225,0,0,13,160,86,20,202,99,60,17,154,215,206,33,103,80,183,36,242,90,83,23,150,93,144,26,187,230,5,4,80,162,100,24,112,157,0,0,131,141,2,47,187,142,88,30,21,150,67,39,110,155,100,37,97,219,105,30,87,104,249,42,165,198,94,56,241,56,241,61,235,167,0,0,209,190,208,25,174,228,0,25,153,145,83,48,210,73,226,40,71,75,128,4,193,221,28,39,253,92,45,54,248,239,75,5,5,98,0,0,250,92,221,39,8,144,131,43,91,75,157,48,223,68,113,34,106,51,70,35,9,77,169,49,205,193,244,36,192,114,35,40,92,91,0,0,140,233,72,30, +230,155,146,25,62,157,38,51,43,243,25,52,191,148,144,6,162,58,195,7,153,94,130,21,168,194,189,45,204,62,0,0,130,31,83,35,140,163,84,46,242,201,194,16,236,154,76,20,255,41,44,2,39,210,249,60,206,92,187,20,68,48,171,9,111,4,0,0,7,218,206,11,44,242,23,20,250,199,85,43,54,23,101,9,208,121,37,3,191,176,194,13,226,172,46,56,214,88,204,18,128,107,0,0,17,39,67,16,220,80,197,2,6,185,22,25,247,203,2,5,207,90,100,25,34,60,188,37,95,83,251,14,120,76,182,9,25,193,0,0,12,97,226,47,139,135,73,18,94,5,52,15,40,139, +228,42,131,207,198,12,27,198,47,37,132,145,104,27,73,31,51,62,225,139,0,0,99,121,37,33,62,29,230,5,28,134,170,52,176,84,99,0,91,196,121,9,78,45,213,46,205,230,242,8,218,122,186,17,8,105,0,0,53,152,111,6,101,150,93,41,83,178,146,28,8,42,15,47,108,127,187,47,228,147,192,5,64,91,188,62,207,223,242,23,72,226,0,0,206,58,226,30,47,229,68,52,210,47,221,20,109,25,31,50,222,21,41,35,210,183,84,29,186,171,11,34,36,227,254,61,61,251,0,0,222,232,34,23,50,189,119,2,238,245,39,45,191,80,156,28,158,138,181,58,54, +80,69,9,42,101,197,51,113,4,111,10,14,81,0,0,81,35,39,16,189,63,31,24,152,16,255,25,126,207,210,28,112,65,205,49,234,172,143,34,235,179,24,5,215,147,176,23,216,109,0,0,75,102,199,63,173,232,31,44,201,23,8,62,240,253,27,31,135,183,65,28,189,230,31,16,157,224,39,52,135,4,253,25,234,22,0,0,109,105,148,16,54,162,121,53,82,175,214,1,169,153,44,62,92,236,215,59,80,124,14,10,172,48,181,21,181,145,43,27,234,254,0,0,136,0,9,24,252,122,87,5,211,66,20,4,243,85,34,7,152,92,205,62,252,74,56,57,6,171,27,14,247, +37,219,26,124,229,0,0,135,213,223,8,237,134,77,30,96,101,2,27,50,142,46,49,94,45,161,53,179,168,234,25,72,179,8,5,61,235,6,45,132,80,0,0,137,14,71,17,254,165,231,57,6,86,31,9,26,88,189,45,93,71,39,41,84,33,155,42,25,22,211,0,102,135,198,24,169,52,0,0,198,76,179,58,133,201,8,2,45,161,48,15,159,93,10,3,200,40,113,13,70,127,252,44,63,165,94,45,144,129,15,48,20,79,0,0,31,104,126,24,190,148,176,23,34,208,29,40,163,51,143,55,185,64,37,38,14,61,156,14,101,76,137,14,169,50,42,52,83,123,0,0,13,217,65,18,4, +196,157,16,131,79,68,50,118,80,60,7,232,99,211,29,123,37,216,16,65,29,237,57,113,146,31,46,77,167,0,0,212,218,122,63,224,98,148,12,63,49,10,10,209,36,148,59,169,200,113,1,98,41,66,55,127,50,239,62,200,107,115,36,134,247,0,0,31,174,193,49,136,40,179,23,42,11,212,44,162,49,150,27,69,88,86,35,174,19,53,55,172,249,44,42,46,209,149,62,1,105,0,0,176,56,40,18,151,193,12,62,48,169,119,28,121,233,206,39,215,13,144,28,10,3,78,45,97,36,33,60,156,8,34,23,222,53,0,0,219,75,122,50,6,66,12,44,196,202,148,20,13, +65,155,26,4,93,163,59,198,15,217,18,36,122,18,56,80,71,11,54,60,141,0,0,44,138,154,38,243,49,77,15,108,41,173,48,77,31,224,56,212,110,35,54,1,116,254,62,12,71,31,36,59,96,88,9,212,155,0,0,45,29,236,52,26,79,51,16,84,244,216,39,27,215,103,2,217,31,105,59,89,202,89,39,254,154,115,36,129,245,216,32,249,234,0,0,82,132,131,12,129,213,249,51,63,181,132,62,21,85,75,61,169,170,153,49,154,131,162,8,117,39,210,56,249,159,14,6,24,229,0,0,103,231,90,4,220,111,205,50,203,113,151,40,231,114,234,28,194,216,229, +6,176,20,56,16,111,70,99,27,187,142,69,47,149,251,0,0,17,14,191,59,43,168,79,33,65,19,159,37,98,28,189,5,184,91,39,2,218,116,54,1,32,197,219,13,106,4,54,5,76,102,0,0,177,108,236,1,47,94,234,15,227,61,88,8,96,95,89,59,254,60,202,63,155,47,249,30,54,203,205,9,65,100,71,42,103,218,0,0,29,190,104,58,137,163,122,58,23,10,116,15,66,113,235,49,222,229,128,23,178,223,143,17,31,196,43,36,5,82,141,42,172,155,0,0,68,138,188,21,148,65,247,59,25,26,21,62,242,93,64,16,104,199,95,26,233,146,150,21,56,61,218,14, +63,15,22,32,1,77,0,0,158,192,219,26,36,83,126,60,98,163,45,24,161,17,8,37,150,19,56,22,31,0,234,38,126,54,93,15,45,99,176,49,51,58,0,0,0,235,218,37,161,212,106,48,107,247,69,38,51,201,250,8,89,209,233,54,206,137,218,50,130,112,149,15,215,247,65,5,102,47,0,0,192,146,57,3,38,158,157,8,193,8,211,21,198,137,123,51,110,208,173,0,8,234,77,37,239,246,51,43,212,219,132,4,92,253,0,0,217,166,106,17,130,66,170,32,241,220,2,55,145,45,178,24,54,56,90,3,134,54,93,60,84,34,125,36,127,65,95,4,148,245,0,0,207,80, +46,63,186,165,65,31,108,184,181,38,15,226,157,36,122,235,188,20,194,106,111,23,246,44,177,49,165,91,105,24,167,202,0,0,192,244,198,58,85,14,184,42,204,196,189,4,51,122,163,19,218,29,113,22,154,47,14,7,78,236,205,25,211,199,95,19,45,15,0,0,88,155,51,50,181,238,158,31,110,101,66,2,228,41,132,26,143,30,231,1,206,247,159,44,127,209,228,61,164,95,225,39,200,62,0,0,178,140,66,31,255,20,84,33,93,181,34,42,89,191,8,14,35,241,208,24,101,5,134,30,235,209,187,20,168,184,176,51,93,29,0,0,155,24,91,9,2,68,123, +57,81,74,4,54,225,75,164,15,189,136,11,47,33,9,30,30,208,80,140,44,80,236,32,16,92,110,0,0,115,18,56,40,62,162,58,44,95,174,61,41,129,165,221,16,216,206,38,1,49,203,166,58,253,57,116,22,2,76,191,40,217,137,0,0,61,119,9,19,187,207,250,0,74,50,39,17,43,160,117,24,143,245,98,15,219,129,188,42,119,3,245,38,117,20,109,9,202,223,0,0,145,29,199,53,178,172,12,51,33,253,148,40,138,139,23,37,35,206,254,26,69,76,112,40,82,28,174,16,233,224,225,6,25,131,0,0,97,138,20,34,35,176,231,2,231,94,68,16,93,212,71,40, +23,138,174,60,69,79,120,27,224,9,183,1,224,92,197,31,172,224,0,0,192,183,55,26,48,115,81,29,245,105,16,49,238,61,52,2,236,81,33,50,123,77,2,0,110,218,205,52,204,130,234,19,144,83,0,0,200,113,39,2,172,37,44,55,153,70,67,20,120,96,102,38,19,28,60,13,8,43,179,39,140,216,6,1,32,47,244,33,192,91,0,0,14,5,162,8,249,11,177,6,119,166,248,21,216,85,189,11,116,137,155,7,185,49,167,29,107,137,49,7,47,73,63,9,55,103,0,0,112,61,29,6,36,105,50,36,43,204,73,51,80,63,235,26,190,109,107,8,106,2,11,18,3,2,162,36,90, +226,149,32,207,228,0,0,191,99,222,2,14,146,219,47,108,198,97,50,161,76,189,14,224,168,102,33,125,140,41,38,229,9,195,52,183,28,233,59,102,67,0,0,205,36,121,33,35,144,26,11,176,214,166,42,150,20,195,14,243,234,104,2,76,248,77,9,238,226,124,45,184,111,66,54,125,46,0,0,144,97,249,6,252,159,20,4,239,37,149,60,65,122,11,60,209,95,167,58,153,165,85,57,123,249,177,26,100,158,216,20,215,123,0,0,246,0,218,43,18,200,69,15,90,105,234,32,7,23,243,3,206,214,39,56,80,210,145,53,94,157,48,38,238,246,172,60,54,131, +0,0,237,65,173,22,85,76,197,14,67,82,3,15,125,13,43,2,3,146,220,24,36,122,6,13,250,26,92,45,106,247,158,36,126,79,0,0,87,45,100,62,25,94,13,61,189,117,247,42,83,28,197,28,46,166,246,40,78,125,3,38,82,5,177,8,170,85,20,29,231,223,0,0,144,134,116,39,73,20,152,62,28,176,48,6,118,19,228,21,125,0,61,19,183,199,74,17,75,201,204,17,74,159,225,50,85,35,0,0,43,88,137,12,197,212,17,31,20,57,201,17,51,22,26,10,88,88,124,42,86,176,23,46,85,143,31,30,156,150,98,60,194,33,0,0,22,127,222,10,88,136,186,54,198,40, +224,11,79,186,46,39,174,36,93,39,176,173,74,22,19,192,86,26,207,230,150,32,102,11,0,0,23,98,197,8,161,9,17,37,189,210,124,62,124,3,15,9,183,127,169,23,45,234,218,41,243,254,179,9,56,6,46,40,251,161,0,0,91,13,6,25,138,192,26,36,194,167,163,3,71,236,132,17,144,203,81,57,103,191,108,2,97,203,34,16,47,60,15,1,2,246,0,0,19,143,248,26,44,212,219,27,247,163,209,61,173,180,149,42,55,234,123,15,177,146,61,42,129,152,241,12,124,176,193,45,54,240,0,0,71,96,216,58,208,103,229,63,174,188,184,41,14,129,78,45,121, +103,144,10,147,221,41,51,25,119,58,24,214,244,66,51,123,142,0,0,42,55,96,4,250,17,64,40,62,139,214,63,145,139,35,58,121,69,81,41,50,8,65,12,64,57,75,26,143,202,194,29,183,16,0,0,75,173,30,4,104,30,162,63,31,60,176,17,218,126,123,29,58,190,118,62,235,59,205,17,113,236,55,51,35,35,3,3,201,191,0,0,237,218,254,6,194,27,75,17,231,227,10,46,204,191,163,17,251,54,45,4,84,55,198,41,219,36,237,13,39,120,108,32,148,122,0,0,62,59,187,53,29,244,158,27,178,60,247,57,251,133,77,29,80,91,63,45,48,250,100,22,202, +77,170,58,143,47,71,60,45,115,0,0,147,102,54,23,123,248,93,49,108,67,88,12,89,91,107,39,230,22,57,37,0,97,149,56,183,124,151,57,163,183,15,36,65,127,0,0,185,195,141,8,6,207,214,23,156,201,116,23,58,73,154,41,25,96,239,23,50,3,33,42,141,66,123,20,14,88,46,37,224,76,0,0,82,222,192,37,219,222,83,48,2,101,160,30,50,200,22,8,22,162,172,54,41,3,54,45,87,237,179,41,198,175,238,3,57,5,0,0,90,254,170,10,44,120,221,48,212,237,154,16,233,44,28,21,226,208,63,2,108,165,154,34,109,233,125,38,241,219,173,35,150, +154,0,0,192,117,217,14,9,245,175,57,12,204,112,30,153,2,98,45,231,14,29,6,246,64,155,49,79,149,162,59,180,233,193,62,246,171,0,0,151,99,76,51,231,47,71,29,147,208,76,7,64,109,79,55,7,33,178,54,148,0,190,43,240,84,25,22,92,64,251,62,198,211,0,0,156,63,203,40,21,52,242,7,11,224,224,5,36,194,29,3,138,70,182,42,75,54,229,32,69,25,175,34,151,87,177,52,13,74,0,0,126,19,195,10,76,150,224,38,97,68,246,26,169,216,150,36,254,83,57,43,170,157,26,60,2,142,59,36,164,4,230,56,189,76,0,0,230,47,192,46,115,197,35, +0,12,214,234,8,150,235,233,36,209,112,195,20,46,77,168,36,0,149,21,54,196,35,24,21,229,108,0,0,75,248,251,32,179,193,136,30,164,184,240,3,239,242,35,49,3,187,206,20,48,204,113,54,139,123,36,22,172,32,207,12,157,75,0,0,72,60,108,35,210,146,123,14,98,94,91,47,248,80,181,25,103,235,183,57,153,96,246,4,83,37,21,12,147,248,254,49,127,253,0,0,98,56,196,25,86,120,16,42,144,102,126,57,96,60,253,41,113,222,27,56,38,26,6,2,109,30,242,31,115,48,77,59,94,56,0,0,83,84,46,20,149,63,22,1,204,200,109,8,8,187,19, +12,107,87,244,43,167,103,120,7,112,86,63,34,58,250,240,58,59,40,0,0,179,217,226,54,170,193,244,18,81,99,141,51,198,160,228,54,65,86,132,15,231,132,169,11,225,117,94,48,241,229,60,5,163,25,0,0,51,175,170,11,151,184,75,21,109,229,75,0,73,71,135,0,165,179,40,53,31,226,151,37,52,210,141,50,177,118,61,54,172,108,0,0,128,4,240,18,172,31,22,54,231,206,13,16,40,1,98,13,32,25,114,54,147,141,97,50,93,53,170,13,106,229,82,59,64,88,0,0,158,207,34,62,138,87,75,22,33,135,227,42,20,149,72,29,186,218,216,29,133, +170,55,26,121,16,20,63,130,200,154,54,12,103,0,0,66,76,245,35,160,123,19,18,142,220,163,41,9,143,6,55,69,37,83,14,59,125,48,22,220,177,143,17,26,77,105,0,87,159,0,0,33,106,235,47,36,113,56,24,120,82,158,33,172,18,158,59,137,221,191,41,92,173,109,37,251,123,229,25,7,32,238,35,123,206,0,0,26,70,34,21,202,76,80,58,39,131,113,60,150,137,194,44,188,160,249,62,25,4,28,46,27,192,207,40,214,72,90,4,246,39,0,0,45,26,48,7,231,43,147,42,70,148,99,40,54,200,6,38,228,232,142,2,157,132,21,35,164,46,173,38,2,100, +106,60,18,229,0,0,185,54,79,17,203,38,139,51,12,57,159,59,216,174,50,38,37,129,169,52,215,208,203,47,97,18,148,47,59,91,97,30,7,100,0,0,10,181,180,36,167,123,44,37,40,235,206,25,18,28,130,54,140,108,123,26,97,127,93,3,249,174,239,22,57,209,163,36,97,218,0,0,111,183,214,20,230,247,216,59,188,93,129,12,237,126,106,57,127,174,254,29,2,47,194,61,82,244,105,22,33,199,56,20,55,162,0,0,218,168,204,13,50,179,100,7,20,141,132,27,127,4,31,28,231,19,17,1,53,249,232,11,195,218,230,61,185,41,197,38,51,247,0,0, +117,228,238,60,147,113,186,11,177,130,215,14,16,10,178,26,171,65,255,10,207,135,0,15,237,213,120,35,252,232,1,43,241,187,0,0,103,80,254,7,2,168,136,17,104,29,180,56,80,98,231,58,36,227,95,49,218,32,243,32,8,97,14,6,181,186,55,46,191,180,0,0,167,195,250,3,27,182,27,24,156,188,127,20,150,18,126,55,15,24,250,61,4,145,206,49,55,22,25,15,251,0,110,54,249,6,0,0,96,33,132,58,128,65,162,33,45,0,129,2,215,75,55,41,126,212,196,5,57,140,138,35,155,166,155,5,12,152,163,49,128,124,0,0,4,226,28,18,163,215,181, +19,82,61,118,38,144,99,201,41,178,47,247,38,114,22,54,29,131,251,100,60,172,88,116,16,202,67,0,0,107,143,74,19,58,17,148,20,142,70,74,42,207,236,177,45,154,31,163,27,99,72,62,20,198,161,63,2,220,184,160,22,234,220,0,0,218,239,230,43,179,164,243,19,150,5,40,7,254,252,83,11,146,109,80,26,225,141,220,27,102,91,191,18,162,200,187,1,62,156,0,0,125,252,174,39,202,60,80,60,125,223,111,51,30,26,242,14,212,213,111,34,51,81,203,2,175,216,35,41,216,121,121,2,183,167,0,0,226,139,200,6,215,234,73,36,39,94,238, +6,52,8,30,11,234,91,119,48,96,103,157,28,187,51,240,32,248,196,168,34,111,93,0,0,93,215,122,13,252,84,185,36,40,44,249,43,169,227,219,42,237,32,188,8,172,206,188,42,113,140,78,45,85,99,99,44,196,173,0,0,68,184,209,18,110,212,36,10,79,72,62,23,176,224,0,39,198,197,139,56,4,15,87,44,134,252,213,32,41,193,112,13,125,245,0,0,55,104,38,33,245,174,46,25,164,198,21,9,12,200,165,1,112,76,99,36,167,214,79,19,144,151,77,47,99,170,103,15,127,112,0,0,9,203,199,60,252,1,52,13,82,67,27,29,40,218,250,49,59,70,113, +24,143,251,135,27,89,95,74,25,153,142,30,24,231,19,0,0,96,145,7,8,40,106,157,47,17,100,87,43,217,174,184,58,101,157,41,52,108,97,247,23,50,30,139,59,62,122,35,50,77,40,0,0,5,238,205,24,73,56,131,1,144,59,236,50,133,236,135,29,168,29,144,6,108,44,148,0,64,98,46,24,160,149,200,40,190,41,0,0,200,81,38,38,102,13,40,57,57,142,105,12,178,109,12,63,249,199,94,48,225,254,108,2,144,234,160,41,67,154,104,54,64,124,0,0,218,138,241,18,88,29,219,6,193,188,189,61,238,100,47,24,212,89,74,61,204,191,190,13,156,125, +142,40,224,72,27,30,33,245,0,0,22,53,149,35,244,43,90,55,129,9,191,5,219,40,189,23,170,214,209,17,243,10,132,9,204,126,181,13,14,216,239,27,104,224,0,0,189,230,208,2,157,131,223,14,49,229,245,48,246,88,52,29,247,203,110,13,65,240,81,8,42,88,226,4,15,73,0,53,34,51,0,0,160,178,40,44,165,139,206,19,98,175,115,40,168,143,125,1,40,183,249,26,55,241,102,0,251,91,239,36,89,250,229,1,231,86,0,0,153,180,154,5,200,79,103,47,10,51,60,39,27,103,202,4,11,188,1,63,25,207,90,6,210,165,91],"i8",4,t.L); +D([87,192,252,43,186,120,0,0,253,151,224,62,99,140,116,32,150,25,37,17,163,187,203,24,145,46,8,2,182,131,19,42,252,250,10,44,193,246,54,55,75,173,0,0,230,172,6,61,179,133,79,18,164,12,162,3,190,205,38,28,35,26,171,41,36,97,18,46,32,76,61,46,82,104,132,60,112,111,0,0,222,213,2,54,210,180,47,18,224,94,172,37,175,89,165,12,117,80,159,57,30,205,99,23,249,54,183,39,0,37,140,34,30,121,0,0,64,27,238,32,185,143,59,50,125,36,150,30,220,22,82,59,140,212,204,3,68,198,39,37,128,95,65,42,90,167,108,39,89,225, +0,0,166,147,143,23,123,153,88,7,222,153,41,3,47,157,142,13,166,207,199,47,168,42,37,62,250,14,74,29,160,202,136,24,51,121,0,0,62,12,192,9,161,232,119,32,47,142,32,17,242,192,163,3,240,89,24,5,245,76,139,21,54,100,149,6,16,193,37,1,11,187,0,0,53,90,149,17,180,96,106,38,167,144,220,5,164,19,193,25,254,82,176,49,234,133,190,52,85,54,246,57,235,20,22,57,103,64,0,0,230,50,221,5,112,110,157,3,126,238,229,19,109,84,237,24,198,191,95,26,29,248,118,18,182,233,137,23,101,80,85,16,90,220,0,0,185,153,74,53,233, +109,159,3,248,188,73,46,29,164,187,60,47,68,89,63,6,136,151,58,220,118,122,54,231,143,41,42,243,74,0,0,203,231,68,5,177,110,81,59,89,3,150,18,109,137,144,1,161,153,78,1,196,149,82,13,227,219,185,51,97,14,92,6,110,21,0,0,55,10,37,45,2,75,78,53,214,156,67,43,87,99,181,37,148,232,75,3,142,169,92,37,147,218,7,25,204,227,103,35,192,107,0,0,202,83,152,5,115,10,239,47,77,245,155,49,231,154,88,58,72,19,22,39,163,136,218,41,188,38,56,4,218,178,51,47,105,66,0,0,103,211,184,53,212,59,86,42,61,138,90,30,126, +41,80,14,253,9,164,49,16,167,50,33,60,114,107,1,176,160,6,7,43,237,0,0,131,171,52,1,74,211,117,8,119,57,67,54,189,230,207,6,116,104,88,38,37,54,220,5,189,162,125,11,120,75,31,11,103,133,0,0,166,19,3,57,61,37,140,35,76,244,152,18,49,255,197,31,231,229,194,34,233,111,18,16,55,182,46,59,208,214,230,6,72,124,0,0,0,144,186,3,234,200,193,55,111,139,94,2,26,231,203,33,196,61,20,0,97,29,216,33,132,22,140,29,252,127,62,29,56,172,0,0,10,207,16,47,101,31,143,54,164,159,110,54,95,67,141,23,8,147,127,17,80,162, +119,11,134,155,6,28,40,194,72,58,101,170,0,0,212,219,6,45,155,189,129,41,129,208,32,10,94,225,143,3,236,41,231,35,166,215,1,5,173,57,1,7,154,234,57,23,13,87,0,0,149,212,30,61,58,251,150,41,213,190,96,36,113,219,232,32,182,187,27,16,71,156,185,25,91,96,47,32,131,80,210,20,174,166,0,0,14,35,45,9,72,126,48,13,132,146,51,41,52,168,140,59,218,245,110,54,128,123,138,48,135,111,187,40,9,10,28,62,181,117,0,0,184,112,21,21,239,247,242,13,176,143,31,17,1,44,233,25,2,142,250,29,83,21,29,30,61,54,82,56,233,120, +136,51,124,82,0,0,14,204,79,3,171,253,218,30,196,132,56,62,10,41,196,31,146,200,89,18,159,56,224,22,10,43,236,29,123,184,190,35,252,68,0,0,10,66,156,49,121,12,252,51,217,137,4,13,47,41,165,3,114,215,211,51,32,158,159,9,73,126,54,49,166,46,165,55,199,210,0,0,145,153,182,11,242,7,146,22,93,23,7,51,176,232,207,62,255,53,245,2,56,136,89,40,102,104,188,39,179,238,145,46,162,222,0,0,223,226,111,49,167,10,157,1,199,155,237,33,216,108,115,39,34,231,185,55,19,178,255,50,197,74,142,2,67,182,245,47,40,174,0, +0,204,201,79,17,9,52,144,48,88,22,70,26,10,175,2,52,38,54,168,56,18,179,61,7,252,110,141,22,184,41,38,63,104,57,0,0,221,55,173,31,37,82,78,6,64,51,143,56,191,93,25,5,26,201,50,45,106,180,96,30,35,129,146,53,210,54,244,46,156,120,0,0,241,133,12,46,70,134,176,43,80,162,163,3,216,148,75,41,166,213,69,57,85,194,119,9,107,146,162,6,56,166,65,36,150,104,0,0,33,222,193,45,204,8,210,49,34,57,80,13,104,103,48,16,31,45,215,5,97,7,23,12,111,37,121,9,227,44,237,15,253,174,0,0,10,42,200,32,189,102,101,63,47,131, +104,54,131,177,137,36,15,177,19,20,70,198,39,27,176,70,138,24,198,38,224,47,72,9,0,0,137,229,200,24,35,254,45,19,237,43,205,23,50,194,127,19,109,140,65,3,71,23,211,45,198,109,100,54,114,91,161,24,165,83,0,0,127,172,200,56,126,249,11,10,39,165,42,30,153,187,144,4,100,73,248,22,129,180,229,12,92,203,187,34,224,248,190,44,69,153,0,0,176,163,174,41,133,14,101,27,169,223,172,45,251,136,222,11,40,245,239,40,236,63,209,54,7,214,130,50,195,146,96,59,239,62,0,0,58,53,158,22,142,231,117,52,110,31,190,43,20, +2,17,40,16,254,213,7,196,137,8,62,53,98,14,7,22,200,26,19,49,42,0,0,103,96,116,37,135,155,100,9,252,139,101,50,182,42,149,34,19,160,27,42,174,29,249,24,164,193,122,34,214,252,2,43,164,21,0,0,102,73,184,41,123,210,139,39,152,255,243,23,183,65,208,19,27,145,108,43,233,188,190,45,152,212,194,63,192,45,64,41,89,89,0,0,106,58,71,7,134,140,153,2,100,66,226,15,35,48,55,0,145,112,42,8,55,8,74,12,148,127,137,10,215,7,157,57,112,3,0,0,115,177,198,43,72,110,50,44,179,254,211,46,31,143,24,54,125,157,95,27,193, +24,49,24,17,142,254,34,200,77,78,12,235,158,0,0,29,167,35,23,54,136,229,20,185,196,112,14,180,175,198,41,14,227,26,58,238,246,175,42,82,217,88,45,67,4,120,60,33,225,0,0,243,5,200,62,253,16,201,29,21,89,153,29,66,221,3,57,125,136,151,46,1,226,200,46,110,81,143,49,253,49,249,19,204,57,0,0,211,72,60,58,4,131,70,6,77,46,145,60,207,205,85,46,187,125,222,2,61,79,154,57,81,49,143,47,145,22,203,17,177,236,0,0,14,88,34,14,215,190,88,15,121,136,111,45,180,37,202,4,199,210,212,27,147,121,255,11,137,150,198, +13,187,25,29,32,76,249,0,0,130,219,39,49,217,143,148,7,232,212,113,35,76,17,251,33,152,246,129,26,173,218,255,18,25,169,37,18,225,25,247,31,156,94,0,0,31,242,196,16,180,46,144,47,166,167,61,16,83,86,42,9,80,210,153,25,108,163,129,0,204,47,22,29,181,26,27,46,204,140,0,0,160,254,157,50,169,155,196,31,143,226,75,38,32,43,183,36,75,165,88,7,114,82,189,47,153,54,196,17,157,24,150,37,248,87,0,0,232,216,143,51,103,96,179,51,172,82,151,6,127,19,57,44,241,168,115,40,192,131,243,25,240,52,28,0,134,209,159, +51,96,98,0,0,23,174,180,50,86,58,161,6,140,25,28,5,224,136,164,52,236,247,30,42,221,37,65,2,127,26,87,27,233,219,10,42,45,188,0,0,2,102,19,1,149,145,46,44,187,165,227,25,3,210,27,49,56,61,59,51,200,223,36,22,208,51,252,45,32,1,202,9,209,135,0,0,172,106,175,24,7,241,160,61,196,247,59,61,27,29,33,42,135,83,116,39,253,179,157,40,38,233,61,32,150,194,33,9,206,113,0,0,22,169,197,8,205,117,129,44,37,15,97,53,84,3,17,23,63,161,74,53,106,143,49,43,176,70,151,30,152,248,79,31,93,253,0,0,218,139,219,58,193, +222,44,5,171,250,246,28,47,5,206,53,229,47,181,7,231,153,242,16,43,125,176,21,173,59,180,15,216,13,0,0,156,82,247,53,88,66,102,23,212,29,213,27,45,230,150,29,56,129,67,52,180,12,79,17,186,34,97,2,7,38,4,53,13,222,0,0,254,136,205,36,11,48,8,15,6,116,183,9,162,49,73,34,23,112,53,58,181,8,38,4,178,249,69,33,40,68,167,27,10,215,0,0,17,109,247,56,52,210,11,50,115,85,81,56,239,3,64,4,21,162,146,2,231,240,251,22,156,230,68,15,147,182,34,8,108,178,0,0,107,53,183,35,199,2,112,48,189,36,38,24,103,25,12,0,5, +51,100,13,67,246,161,19,12,207,51,29,82,130,32,62,28,31,0,0,219,34,158,38,25,236,56,37,63,147,200,57,103,253,79,38,172,78,41,12,6,164,244,14,126,58,82,63,31,63,46,5,235,252,0,0,161,96,34,28,201,182,92,61,203,228,235,36,78,158,67,21,173,36,9,31,73,157,150,34,205,31,141,43,53,144,206,26,170,100,0,0,85,39,138,35,230,5,33,60,6,85,156,20,89,156,134,28,83,170,127,16,45,221,213,5,92,197,202,21,51,143,152,38,144,78,0,0,222,163,204,35,216,39,233,61,202,0,152,34,52,229,84,51,182,219,89,53,65,117,27,9,239,236, +90,35,51,227,161,54,86,174,0,0,77,166,59,24,102,37,150,32,58,90,89,12,226,221,131,57,189,226,64,14,174,23,133,2,251,59,192,4,184,8,87,17,103,195,0,0,253,129,33,42,229,35,51,5,70,241,120,23,40,171,154,24,66,199,100,25,19,186,57,56,128,48,3,54,114,26,180,2,82,58,0,0,45,250,55,32,52,50,79,37,50,196,253,27,93,61,178,15,4,3,65,63,46,5,33,13,216,67,141,29,240,43,120,31,3,229,0,0,218,91,117,29,16,114,151,3,14,241,129,4,251,192,214,23,189,221,11,25,238,39,52,38,159,95,59,13,165,234,210,20,113,69,0,0,117, +119,126,23,184,41,42,34,99,95,217,14,226,100,85,56,181,174,145,18,61,235,14,21,88,238,60,35,229,191,142,26,137,157,0,0,145,102,5,58,234,180,61,63,190,83,146,41,184,95,115,38,232,125,146,16,201,181,147,37,78,185,240,27,210,15,121,42,145,221,0,0,147,50,42,60,120,19,120,63,197,118,52,16,186,27,46,34,86,205,244,2,202,92,41,44,14,45,121,35,69,156,59,46,39,131,0,0,189,249,13,14,134,83,33,47,22,164,38,35,59,173,246,43,150,132,112,57,137,153,250,44,139,225,152,10,184,155,137,31,153,4,0,0,66,192,98,5,177, +201,134,16,162,177,223,56,210,200,72,11,9,214,142,26,62,118,152,25,125,137,22,27,155,138,170,10,228,90,0,0,156,38,121,15,126,51,23,36,191,141,205,7,68,229,54,56,148,74,157,56,128,113,119,48,181,234,81,48,127,1,159,14,217,153,0,0,97,175,133,30,161,4,34,13,107,118,174,20,183,200,181,35,78,15,27,2,219,63,218,58,154,181,142,28,168,9,185,14,194,146,0,0,9,43,106,3,167,217,200,57,212,254,134,34,173,96,235,8,45,121,213,56,28,87,95,8,159,64,187,17,85,192,35,62,76,65,0,0,168,235,181,7,203,198,171,56,108,163, +142,17,254,113,251,42,45,66,223,56,171,93,208,3,141,8,241,61,171,29,35,24,229,254,0,0,92,155,11,13,218,116,69,61,147,71,5,57,175,208,63,32,227,78,193,7,74,230,11,16,17,251,138,37,63,77,100,22,7,56,0,0,244,202,99,60,44,233,142,7,40,213,83,15,202,234,252,35,162,252,106,42,24,211,78,4,10,98,126,38,185,228,58,17,229,66,0,0,200,41,156,22,38,176,235,33,17,95,252,62,218,158,67,41,115,120,94,1,93,48,136,60,113,31,103,12,71,62,56,21,248,159,0,0,161,9,15,30,97,246,138,2,56,40,3,20,110,124,66,40,240,254,14, +48,145,74,187,37,57,56,206,50,84,153,237,32,237,122,0,0,115,125,133,5,122,51,118,17,64,165,244,51,3,204,203,34,216,142,45,3,196,42,244,43,221,199,247,30,140,230,23,21,184,245,0,0,37,231,252,36,43,168,25,22,114,91,108,42,113,244,54,58,231,180,113,23,60,122,65,42,94,223,122,32,40,61,172,28,99,224,0,0,221,49,238,14,229,211,192,9,11,135,4,49,225,157,18,18,215,140,72,26,181,202,238,9,42,225,207,24,56,47,93,34,144,122,0,0,106,141,50,26,35,6,170,46,189,24,220,26,165,206,93,19,178,167,143,48,22,70,38,26, +52,10,224,52,136,233,22,48,99,198,0,0,192,184,201,62,170,237,194,14,194,156,191,18,148,122,84,33,221,23,19,23,157,60,247,43,57,141,195,33,220,87,99,58,49,51,0,0,47,222,150,57,32,33,71,50,75,17,37,11,184,203,183,51,119,233,228,15,168,123,195,44,206,89,164,6,238,183,160,9,252,211,0,0,140,111,82,20,7,137,36,49,104,241,171,55,55,38,109,22,78,218,129,55,83,83,29,45,104,143,161,48,23,105,230,55,240,196,0,0,234,151,230,3,68,35,177,49,133,62,248,5,230,62,158,57,156,209,171,63,104,178,127,40,220,55,2,44,172, +255,208,18,122,193,0,0,135,108,220,30,247,225,142,59,176,42,240,57,95,109,104,56,150,174,31,32,101,220,227,5,174,76,149,53,106,85,11,23,53,57,0,0,27,218,99,49,8,12,75,11,24,49,58,57,131,185,183,3,154,222,31,1,255,117,210,36,140,70,11,57,153,40,223,34,97,143,0,0,110,215,189,3,68,72,204,31,124,110,155,36,140,154,49,20,100,66,90,44,94,211,105,47,95,235,182,62,34,124,201,15,35,120,0,0,144,174,200,14,248,67,22,58,238,93,188,11,186,228,154,44,207,184,241,3,178,54,110,53,134,235,230,33,222,86,60,48,152, +151,0,0,211,68,40,37,171,11,107,42,39,142,24,3,244,150,37,57,226,190,115,28,62,37,37,59,210,61,237,2,105,157,170,56,64,186,0,0,127,107,214,17,60,94,134,22,16,200,125,24,20,148,164,41,122,117,132,18,226,66,110,60,124,116,214,34,214,254,184,27,250,253,0,0,139,23,229,56,25,224,163,42,157,222,120,61,68,119,190,17,216,196,24,26,143,38,7,3,60,185,141,25,146,136,199,60,156,77,0,0,240,188,101,18,18,94,29,32,11,211,199,17,16,222,138,51,105,14,34,15,135,145,166,58,221,58,228,41,136,55,142,51,88,253,0,0,146, +98,153,43,115,234,249,12,223,209,28,15,138,255,134,9,135,251,228,5,146,230,170,32,83,189,21,50,216,77,121,41,224,255,0,0,84,151,85,16,35,164,181,2,84,88,63,42,120,247,66,44,4,34,224,12,112,231,239,2,141,53,69,29,53,87,156,30,60,33,0,0,242,88,180,52,212,9,203,63,221,238,167,54,124,61,20,18,187,144,161,27,145,24,180,14,1,7,37,6,185,214,66,43,109,75,0,0,204,220,5,30,70,0,182,12,229,147,154,1,83,251,232,15,174,114,209,19,229,90,130,27,84,9,3,26,79,93,184,61,206,184,0,0,80,87,109,12,63,131,82,0,51,129, +182,38,218,240,95,29,223,153,189,18,147,211,41,53,164,246,187,9,179,41,152,34,43,48,0,0,26,179,59,55,132,251,247,22,72,123,185,61,215,218,222,7,112,73,95,59,186,120,47,40,2,94,56,7,109,222,249,12,251,3,0,0,158,92,33,61,165,249,50,13,78,13,100,7,177,29,159,22,198,43,87,59,174,106,88,48,224,129,226,47,35,149,84,54,106,243,0,0,180,74,154,29,175,87,212,22,10,124,187,21,97,176,13,31,113,54,122,15,52,237,189,5,31,22,225,3,123,66,52,31,23,75,0,0,247,182,90,35,145,127,183,42,88,245,65,23,124,149,248,13,110, +72,107,34,77,202,217,35,218,95,166,47,120,105,186,25,201,62,0,0,164,35,28,48,166,236,27,61,86,207,73,58,17,86,144,10,194,117,205,57,230,166,224,0,42,108,160,39,168,129,212,0,135,94,0,0,249,134,217,16,172,101,94,8,161,253,204,36,210,97,199,5,162,45,110,44,184,70,87,29,113,30,34,9,231,190,19,25,150,91,0,0,102,12,123,0,72,215,252,60,177,111,200,22,25,185,255,41,52,116,235,44,130,61,145,8,71,164,128,22,195,100,192,48,69,229,0,0,112,212,242,49,73,95,253,33,221,57,162,53,134,163,96,57,151,191,188,25,229, +104,191,49,229,231,85,41,24,163,3,13,106,224,0,0,186,139,100,3,46,100,96,41,68,116,60,28,26,44,60,40,130,152,179,1,124,137,184,15,19,10,88,15,149,94,133,16,164,178,0,0,82,100,251,0,40,173,190,17,178,123,193,9,71,69,21,54,192,49,126,61,62,94,242,62,233,25,102,54,164,173,240,23,79,254,0,0,208,39,171,43,187,72,183,61,252,3,81,4,139,126,208,2,247,7,112,25,99,100,192,37,186,81,134,19,81,207,131,35,144,27,0,0,16,209,211,0,121,157,161,7,87,27,229,7,214,164,242,46,181,154,75,60,5,70,242,21,243,230,181,38, +17,187,151,24,109,155,0,0,60,213,251,8,236,232,48,3,223,205,98,28,43,28,227,32,226,135,154,1,149,74,77,46,219,232,52,11,189,158,202,9,124,78,0,0,230,170,220,23,96,80,206,2,62,211,125,63,47,133,229,2,83,27,104,47,183,125,66,63,22,142,177,16,39,155,29,39,116,23,0,0,255,179,33,37,147,17,166,56,206,80,167,26,250,197,1,15,35,165,36,46,166,175,52,17,94,199,85,20,50,4,140,19,72,2,0,0,126,218,105,2,228,146,107,48,188,139,172,35,164,183,1,28,173,235,14,45,172,240,172,48,126,208,48,62,136,42,40,52,25,150,0, +0,185,167,75,0,234,231,173,37,31,117,65,7,12,28,169,53,32,78,149,44,156,53,220,38,247,126,229,44,237,179,73,49,193,22,0,0,65,215,91,28,148,142,111,29,196,156,154,28,111,0,87,29,236,222,148,10,114,22,157,24,98,144,67,49,0,13,223,31,21,219,0,0,250,131,102,35,234,33,217,32,94,130,192,14,224,212,134,32,149,102,123,18,209,157,115,34,122,248,26,19,254,212,53,15,151,3,0,0,127,87,74,63,221,202,126,61,237,29,152,62,99,56,33,30,215,108,162,53,202,216,74,56,67,54,58,10,195,48,139,22,207,56,0,0,6,111,191,0,103, +230,44,32,113,181,67,16,137,204,4,15,113,101,87,32,192,210,19,48,194,17,21,15,187,156,238,38,106,186,0,0,81,181,29,56,193,189,175,12,254,170,151,6,235,61,69,23,158,142,189,24,149,203,47,8,32,3,27,33,210,44,142,7,119,19,0,0,67,26,35,49,193,231,123,52,159,59,212,26,153,53,69,53,68,47,68,30,147,65,101,59,138,45,221,4,243,9,51,47,197,53,0,0,246,200,32,22,20,185,220,54,231,10,207,35,1,51,233,61,76,157,88,58,219,130,96,57,52,231,108,52,229,142,92,29,54,14,0,0,9,6,212,61,91,241,2,61,107,215,28,24,3,38,100, +16,199,106,53,8,22,191,196,11,18,202,107,24,21,23,9,39,71,253,0,0,83,202,100,42,217,196,139,55,57,71,202,33,201,181,235,4,145,253,65,24,242,144,94,43,44,255,254,10,165,73,237,51,105,48,0,0,127,154,121,43,212,11,220,54,36,132,142,59,84,179,45,6,79,84,125,44,188,230,58,54,222,75,134,13,179,142,10,0,64,108,0,0,50,30,200,19,179,32,115,45,104,63,72,32,32,83,175,30,192,189,220,29,56,168,13,46,144,230,91,35,45,76,5,55,194,149,0,0,182,39,251,0,161,248,9,9,99,87,48,36,175,108,143,27,199,165,106,40,133,181, +226,8,15,177,177,56,157,111,143,19,167,254,0,0,111,185,60,50,223,246,116,0,119,183,247,51,229,90,214,26,18,147,175,54,50,123,211,25,207,151,50,49,194,230,54,26,5,110,0,0,86,151,136,62,166,107,96,55,37,187,4,48,94,38,217,30,242,243,153,24,156,236,101,51,38,130,234,31,132,204,240,34,46,118,0,0,116,183,166,60,129,103,137,23,226,165,79,8,82,204,182,28,25,71,227,2,38,197,19,51,199,195,151,62,188,130,9,37,40,192,0,0,234,210,117,9,92,122,221,27,162,142,78,1,132,62,171,20,30,169,244,8,140,236,246,38,225, +72,83,9,216,247,81,31,7,223,0,0,149,111,147,49,120,182,240,40,122,39,221,59,19,110,177,7,138,124,82,34,98,114,9,33,76,66,244,55,59,0,162,30,97,248,0,0,215,146,76,60,238,71,18,46,69,27,57,20,185,91,211,54,53,41,20,11,205,160,122,31,225,50,160,61,244,98,93,31,62,159,0,0,221,6,73,49,62,255,238,50,134,17,78,41,245,192,136,10,69,2,21,43,46,135,172,24,136,181,102,20,223,169,7,33,210,236,0,0,131,196,168,50,202,92,131,43,53,172,64,16,49,34,195,18,23,129,82,57,187,72,15,35,195,237,249,12,215,94,87,30,204, +160,0,0,169,107,204,18,86,209,89,2,85,96,147,54,247,198,35,13,107,120,223,49,200,37,63,29,35,238,115,56,44,190,72,0,195,171,0,0,238,58,221,5,175,109,60,28,33,47,109,57,163,162,78,5,19,202,118,41,26,107,170,8,14,206,124,60,84,69,41,20,28,109,0,0,247,151,245,61,147,83,141,59,223,58,213,14,170,66,140,7,133,116,212,7,138,0,200,9,119,201,253,61,170,129,35,5,255,175,0,0,187,208,166,36,223,166,50,30,198,253,26,26,189,72,76,39,101,143,65,38,162,98,155,6,49,63,159,63,229,98,88,7,95,94,0,0,249,234,51,16,228, +17,14,26,161,83,246,6,148,203,87,21,114,218,33,39,19,52,175,61,88,115,111,62,169,193,10,20,177,215,0,0,63,94,0,15,145,215,166,54,45,189,57,44,111,140,163,61,90,73,161,1,56,107,46,15,253,255,39,36,5,207,154,34,19,248,0,0,183,126,53,47,128,128,95,11,52,33,190,20,85,111,16,59,244,81,203,37,234,149,87,0,157,159,189,14,237,251,206,35,117,202,0,0,57,222,189,23,16,169,0,11,149,50,4,54,109,94,56,17,21,211,104,25,102,53,92,9,10,225,240,60,157,253,68,16,230,118,0,0,1,172,1,25,180,212,197,18,43,3,210,22,173, +244,140,10,94,211,240,1,26,92,155,1,119,245,92,41,147,123,227,55,13,201,0,0,141,238,120,0,115,36,20,60,66,148,145,6,148,51,200,47,78,246,79,27,170,142,201,61,95,226,155,26,103,97,235,21,142,208,0,0,134,62,166,45,112,211,95,38,222,217,46,2,229,243,189,15,18,244,109,62,213,185,203,5,214,114,141,8,173,18,230,37,46,133,0,0,236,41,145,2,193,25,69,22,129,84,130,36,199,179,142,43,12,8,29,19,179,3,250,34,245,117,210,4,53,121,33,48,166,125,0,0,14,255,217,44,138,187,66,45,174,134,165,12,149,33,48,18,4,191, +39,22,36,29,8,52,17,117,133,1,125,238,26,5,152,244,0,0,34,79,101,17,85,82,15,62,148,238,170,49,8,229,252,61,178,79,217,41,249,6,64,58,27,226,230,27,112,253,51,36,208,144,0,0,225,67,26,32,93,129,119,61,64,135,63,26,79,89,141,53,109,51,112,63,26,120,8,60,83,169,97,15,235,74,135,38,86,205,0,0,250,25,107,7,71,217,187,45,113,157,129,40,65,27,184,53,217,46,41,33,32,196,176,8,115,204,30,29,60,31,22,38,71,218,0,0,247,90,111,50,172,187,137,42,6,194,63,21,165,79,244,30,166,158,86,22,248,29,164,13,23,29,240, +10,243,38,222,53,177,235,0,0,189,93,19,57,150,237,75,54,236,49,134,29,206,235,33,48,240,124,137,41,11,214,171,30,129,173,230,30,55,42,65,29,228,227,0,0,93,4,72,7,249,188,26,36,150,218,149,44,215,191,128,40,165,254,63,56,74,101,32,35,185,64,108,60,114,2,254,22,10,147,0,0,95,69,238,13,151,231,194,47,92,7,228,12,186,249,255,25,255,74,219,11,224,227,76,17,71,10,155,10,28,250,91,25,140,126,0,0,186,156,27,23,96,166,247,28,113,98,70,47,209,89,180,40,74,59,165,3,32,61,216,61,163,242,64,7,140,178,140,49,221, +189,0,0,158,181,152,38,109,174,229,29,67,122,68,19,98,73,214,12,10,38,199,35,207,106,13,44,190,21,235,21,106,36,126,16,248,61,0,0,245,186,146,43,229,153,227,51,139,159,148,20,200,158,33,63,123,134,243,28,196,163,235,10,160,29,12,9,44,230,183,57,143,179,0,0,145,184,203,43,144,64,197,42,227,190,108,50,247,144,49,31,143,154,143,63,208,169,110,32,130,30,190,42,236,192,90,49,56,199,0,0,195,132,154,41,101,215,156,31,145,254,12,8,222,187,83,12,130,187,187,63,178,186,60,6,247,55,37,45,70,37,94,45,63,137, +0,0,141,213,97,7,206,188,234,18,243,226,96,13,2,249,38,19,202,122,223,32,92,141,2,9,10,97,20,54,143,224,73,24,196,184,0,0,164,81,16,29,234,130,58,14,182,197,7,33,23,30,65,29,63,5,197,51,95,218,99,17,74,209,55,14,92,20,91,54,158,143,0,0,64,0,11,5,16,204,194,54,194,173,52,1,124,110,31,61,243,113,54,26,250,79,38,3,53,122,31,39,64,220,167,27,213,8,0,0,161,208,63,27,233,153,56,22,235,43,120,33,131,28,241,53,246,133,178,57,53,42,84,52,255,33,170,41,66,175,107,33,33,161,0,0,127,59,87,19,124,143,149,21,15, +39,182,48,180,23,135,38,136,55,90,38,239,93,62,8,30,52,230,60,11,181,140,60,19,220,0,0,166,43,31,12,161,72,179,10,196,177,4,52,5,28,85,17,112,118,10,41,18,106,67,16,199,195,64,35,167,16,160,46,9,201,0,0,235,156,174,7,46,100,189,0,75,209,242,14,156,122,8,27,34,168,25,33,108,151,85,6,175,115,240,55,119,128,121,11,192,37,0,0,117,226,198,11,77,52,36,28,100,114,88,38,194,119,144,49,55,213,17,45,62,55,56,33,200,192,131,35,4,178,180,58,159,138,0,0,52,60,90,44,219,99,2,62,225,159,148,21,10,176,160,51,174, +88,62,46,158,50,125,46,138,206,73,14,62,203,70,39,221,254,0,0,20,119,61,33,211,47,213,10,118,41,248,27,166,81,173,43,173,0,75,15,178,196,20,58,11,11,142,59,20,198,48,9,46,165,0,0,150,163,182,42,70,83,57,45,105,7,54,17,104,228,134,0,115,179,136,4,122,253,181,56,222,194,72,42,27,175,161,12,14,62,0,0,126,226,128,25,35,121,204,58,162,246,104,52,124,16,4,44,106,198,63,5,173,119,248,7,243,100,121,51,142,190,92,32,68,202,0,0,236,35,16,52,136,97,205,43,10,87,207,62,219,61,118,17,86,175,185,2,38,128,128,11, +152,132,210,50,48,32,76,46,74,52,0,0,135,235,30,30,164,96,226,19,112,93,153,3,191,218,165,19,252,95,76,17,169,71,203,35,63,167,98,4,201,10,193,10,28,110,0,0,75,193,246,8,150,125,186,28,67,1,37,41,206,151,203,53,209,119,40,23,242,141,29,19,38,30,184,37,45,82,153,24,149,216,0,0,31,153,125,29,93,251,216,36,23,126,6,59,202,88,163,16,3,235,64,3,99,32,24,59,40,231,234,7,175,60,142,42,191,254,0,0,86,183,39,33,253,31,234,2,72,112,9,58,42,249,162,16,3,22,180,32,65,105,139,13,45,103,18,31,91,220,11,30,140, +109,0,0,113,37,23,63,42,221,71,21,166,204,205,23,139,182,169,14,78,175,77,19,219,180,160,38,69,17,145,27,191,37,194,55,174,153,0,0,122,241,140,53,205,105,184,55,36,53,130,24,233,114,23,62,241,248,151,0,109,188,107,22,208,168,172,55,111,101,183,47,202,235,0,0,205,12,170,28,125,113,179,17,196,149,206,10,180,132,180,62,16,107,46,3,159,109,40,0,44,176,156,43,200,227,131,51,211,71,0,0,91,92,133,44,86,148,187,51,187,175,200,23,128,134,88,33,17,40,252,23,120,218,104,12,83,68,226,12,245,146,75,19,223,232, +0,0,80,86,70,46,176,156,87,39,213,215,228,33,199,87,237,24,150,197,50,47,103,61,109,19,68,100,178,57,31,49,92,63,87,108,0,0,84,228,231,18,105,111,61,2,13,21,230,48,195,251,187,12,254,98,22,24,234,8,24,18,18,41,131,10,59,198,245,52,104,64,0,0,30,25,239,24,151,55,107,30,39,51,55,60,68,123,72,35,152,209,56,29,246,101,81,48,158,171,122,36,82,201,237,20,216,140,0,0,57,217,197,6,225,183,94,33,224,61,147,58,222,161,104,29,164,126,2,10,131,185,204,47,85,11,94,2,118,108,179,3,85,18,0,0,201,87,231,25,21,63, +157,10,25,67,141,13,251,7,221,34,131,114,74,50,93,240,144,35,68,117,122,45,28,62,205,32,143,123,0,0,111,165,200,22,25,171,66,35,19,66,55,15,13,21,79,2,133,143,208,58,235,212,222,46,105,76,93,24,237,176,198,25,77,148,0,0,137,226,123,26,151,113,211,39,235,23,101,16,55,93,48,53,103,25,198,58,76,216,228,16,193,244,255,1,212,222,101,25,16,167,0,0,90,241,8,46,98,40,174,59,186,0,41,1,114,91,121,26,253,5,195,19,107,149,13,44,230,207,160,25,66,115,164,19,165,134,0,0,8,131,56,1,159,71,147,20,211,84,82,51,150, +68,167,4,119,103,104,53,181,65,163,10,167,3,70,56,233,13,82,24,238,207,0,0,3,110,103,15,89,41,84,36,212,237,132,62,164,205,241,63,206,97,135,30,92,205,144,61,176,142,81,23,165,202,0,37,218,184,0,0,231,246,253,14,157,147,35,18,17,181,243,31,101,19,22,51,146,176,8,40,216,37,115,38,124,77,30,26,1,18,233,55,4,40,0,0,107,52,225,6,119,18,102,40,94,28,175,5,14,196,158,47,90,192,82,17,83,124,216,49,84,190,16,45,96,194,63,26,144,6,0,0,19,108,34,23,83,41,214,46,231,38,96,12,101,78,162,61,164,42,68,6,66,175, +108,23,168,109,226,61,47,36,248,56,99,184,0,0,161,246,161,28,243,71,154,3,163,241,207,8,13,69,47,35,6,225,108,40,199,114,113,27,40,21,118,25,201,242,36,13,140,137,0,0,124,100,79,22,60,8,183,18,202,121,189,50,231,229,243,41,178,147,110,44,74,145,80,17,216,73,85,42,213,170,97,22,247,117,0,0,152,57,30,61,240,128,167,41,138,50,4,58,69,46,178,21,94,78,39,42,8,92,103,10,165,1,191,24,164,180,191,56,19,178,0,0,30,184,95,50,24,247,178,48,94,23,237,61,250,150,5,13,213,195,59,36,14,254,122,24,61,44,193,19,203, +131,176,35,159,34,0,0,52,226,91,34,178,127,248,2,112,80,243,29,195,249,248,32,14,6,110,32,69,154,46,52,209,229,147,63,177,5,182,14,59,75,0,0,98,131,14,18,14,248,237,24,64,184,17,50,179,100,255,57,65,76,192,12,246,183,165,23,135,199,201,43,118,225,142,0,236,94,0,0,94,245,137,34,159,210,152,37,123,112,118,44,56,60,172,29,41,190,101,9,158,192,70,9,32,96,249,4,108,183,45,34,123,159,0,0,222,75,30,62,151,237,52,15,27,43,10,49,58,184,77,57,192,31,199,15,166,208,26,5,227,123,15,1,193,49,225,61,249,50,0,0, +43,29,254,29,48,114,82,25,81,142,135,22,121,66,253,36,196,164,115,59,79,127,43,51,118,62,142,4,221,114,250,16,138,213,0,0,34,9,213,12,110,229,201,51,255,251,214,11,87,136,110,54,84,107,39,40,160,76,164,28,10,241,60,8,22,232,154,33,23,252,0,0,94,121,156,36,248,70,5,9,225,5,232,28,166,170,1,17,237,78,234,39,240,112,90,54,214,12,49,24,68,92,78,28,210,33,0,0,206,142,32,25,14,187,4,0,27,118,251,45,146,18,101,28,214,195,180,43,72,21,110,13,119,161,206,26,29,44,109,62,197,148,0,0,93,223,192,35,227,93,132, +6,47,121,106,21,212,254,123,6,32,171,127,29,29,229,106,43,216,167,51,59,7,17,133,58,15,232,0,0,120,236,201,42,109,164,208,50,159,234,34,51,43,160,87,5,45,71,148,10,143,50,218,37,232,113,7,32,227,216,159,55,209,238,0,0,85,45,89,23,179,103,13,48,146,1,53,14,208,81,110,53,6,177,227,60,140,165,189,63,138,96,82,16,40,241,182,49,46,93,0,0,167,131,81,47,58,116,185,25,66,23,21,17,107,243,158,10,14,149,214,12,154,232,67,28,143,181,94,36,27,39,126,51,146,10,0,0,92,159,143,62,39,45,125,36,25,165,128,24,86,120, +124,24,115,77,64,31,133,208,184,50,226,47,116,63,70,236,112,7,55,172,0,0,60,80,90,50,204,255,160,30,209,225,81,39,59,22,77,37,34,53,231,20,201,156,7,4,242,127,71,26,194,97,176,5,22,197,0,0,70,52,227,25,84,35,135,18,223,133,243,42,20,241,78,34,64,122,161,34,8,244,2,35,52,201,64,24,60,133,14,0,66,137,0,0,137,118,56,38,3,40,78,3,132,249,116,30,158,205,93,63,107,224,228,61,59,180,181,44,216,164,119,16,105,101,229,0,253,169,0,0,38,203,19,57,86,50,202,53,3,109,189,19,0,103,208,58,153,152,92,16,213,63,145, +54,44,138,42,52,40,204,154,9,112,39,0,0,162,167,72,51,207,92,156,63,187,190,21,8,243,70,50,16,233,36,179,50,31,52,73,11,85,165,177,13,108,158,23,47,73,246,0,0,71,130,94,25,133,128,170,2,175,209,108,40,85,17,247,47,151,144,186,56,115,128,155,23,142,23,210,62,242,224,52,52,228,117,0,0,34,45,152,25,117,246,143,40,60,137,173,41,186,109,173,54,125,212,38,55,30,59,92,62,65,7,153,16,80,93,168,16,206,31,0,0,35,51,51,38,54,209,231,17,71,191,74,15,26,7,239,46,156,132,218,4,102,129,53,8,240,3,191,27,216,12, +142,45,209,62,0,0,163,27,214,53,34,241,79,44,148,114,143,55,66,40,202,45,169,158,146,15,162,37,38,31,217,117,238,52,214,34,105,11,79,216,0,0,191,128,57,51,82,95,65,9,175,11,208,13,148,11,220,40,104,67,221,8,141,220,245,27,132,27,24,24,157,26,188,52,253,112,0,0,133,87,183,32,58,163,186,11,97,165,116,29,225,96,13,4,10,107,89,46,71,52,4,41,87,105,105,24,53,52,176,50,223,94,0,0,112,96,225,4,243,238,1,55,93,145,214,47,199,128,96,40,242,67,117,22,117,148,35,41,59,49,4,23,243,247,94,26,1,163,0,0,161,126, +23,30,16,104,52,48,48,161,17,10,240,253,118,13,23,155,15,20,151,232,39,32,129,80,79,62,217,62,71,62,112,115,0,0,252,17,128,19,0,156,4,28,38,86,40,23,235,153,90,22,131,77,10,32,8,194,76,44,86,17,177,30,5,194,232,4,131,110,0,0,125,171,21,63,232,167,45,43,166,249,81,28,186,86,228,43,38,4,195,26,7,200,182,4,26,76,32,15,9,247,98,32,71,193,0,0,167,107,14,16,227,38,157,14,245,247,22,9,209,22,187,13,61,180,225,25,147,226,128,7,189,242,81,8,225,101,66,42,82,249,0,0,193,228,117,1,148,187,235,54,152,43,42,6, +211,158,197,21,85,246,160,63,137,139,218,13,97,248,235,60,42,194,150,14,169,216,0,0,147,14,170,3,138,150,1,36,38,246,177,47,235,80,142,11,143,58,137,30,118,134,198,0,4,117,238,63,116,140,87,27,1,148,0,0,194,218,173,7,162,73,187,35,163,7,123,37,234,206,13,33,244,215,111,46,59,213,116,21,3,100,217,20,17,151,187,12,80,103,0,0,123,177,102,2,184,24,210,3,43,179,43,38,128,40,90,13,2,194,9,31,170,17,226,37,187,145,40,59,103,53,93,52,34,239,0,0,62,200,218,57,13,129,155,10,115,27,52,28,220,219,201,57,62,7, +161,52,184,14,51,39,143,86,199,36,172,94,50,33,87,188,0,0,160,130,211,18,106,5,76,12,226,154,205,46,56,239,114,35,242,39,249,45,44,224,49,43,156,211,146,56,58,147,243,59,247,181,0,0,50,181,180,37,238,42,188,40,91,140,207,26,74,91,194,62,113,211,221,11,131,27,95,37,192,83,35,63,112,212,22,21,67,104,0,0,165,255,44,1,145,145,164,57,71,92,204,40,25,130,80,59,137,67,98,20,239,99,83,29,8,100,7,49,185,172,244,48,221,28,0,0,78,149,33,21,115,98,155,55,138,82,107,51,154,16,38,7,196,138,176,2,229,175,73,44, +253,99,138,31,188,44,131,26,71,30,0,0,47,242,169,52,228,144,127,13,173,226,168,23,72,113,6,2,204,176,53,8,82,46,46,62,33,159,147,14,151,124,214,44,204,42,0,0,39,73,92,55,206,114,215,45,183,80,165,27,177,239,245,18,21,241,237,48,183,223,232,4,146,81,46,45,34,86,58,41,24,213,0,0,212,78,176,63,248,24,235,45,250,255,7,19,196,194,12,51,8,226,141,39,73,20,116,62,99,100,147,43,117,226,108,33,173,144,0,0,80,241,110,11,35,53,117,36,217,148,40,24,133,175,190,43,57,184,34,50,9,101,47,55,255,26,38,56,40,136, +141,30,80,14,0,0,120,182,183,48,206,108,215,9,102,129,99,15,111,196,16,15,241,118,108,43,9,41,175,33,25,186,49,2,57,205,92,18,110,24,0,0,193,31,217,56,203,219,129,30,202,93,83,9,81,137,220,1,17,126,230,55,2,151,32,63,167,74,216,59,1,38,57,24,212,192,0,0,184,31,66,51,46,151,27,60,12,93,165,53,187,124,92,18,152,18,36,55,14,211,172,1,126,46,246,27,219,211,96,35,28,6,0,0,128,205,60,14,161,217,123,37,41,221,252,38,206,210,196,25,128,92,235,5,56,100,73,14,169,123,75,59,0,100,182,26,252,109,0,0,164,53,107, +47,98,248,146,4,135,180,127,50,170,233,205,39,136,173,104,58,204,1,201,24,115,59,81,46,35,136,142,45,166,246,0,0,166,34,244,1,178,191,173,43,44,134,225,30,157,91,93,53,25,111,24,32,213,19,220,52,202,177,56,17,11,0,42,50,247,61,0,0,17,76,149,38,162,143,160,37,139,1,13,22,5,15,41,42,127,255,120,7,84,60,108,52,32,98,55,44,161,48,10,63,162,135,0,0,69,139,42,39,184,204,184,21,183,36,129,39,202,207,36,18,204,50,117,18,131,54,82,6,123,249,206,46,106,209,98,20,173,51,0,0,182,106,112,34,171,28,29,57,218,192, +83,46,116,7,205,2,60,254,76,56,240,242,187,21,69,104,26,8,158,27,129,11,71,225,0,0,5,222,88,29,90,168,161,27,83,39,205,19,81,85,39,22,170,248,33,6,50,94,70,26,63,104,252,24,241,145,170,36,205,130,0,0,182,79,168,7,8,149,235,47,30,2,21,58,67,29,218,8,196,235,185,8,121,128,53,45,232,93,239,10,62,1,178,36,175,28,0,0,9,145,20,39,64,6,198,26,97,103,206,34,90,90,48,7,236,34,22,16,252,227,147,41,129,164,83,46,93,178,22,46,36,188,0,0,17,89,149,10,133,63,163,29,219,82,237,13,152,168,133,31,16,151,131,23,207, +166,191,39,88,210,80,22,194,107,90,63,91,112,0,0,228,0,210,63,79,26,223,46,216,114,46,36,138,212,206,31,41,250,81,0,213,7,246,24,126,10,153,63,220,194,4,41,74,225,0,0,218,192,196,30,50,17,237,45,81,51,234,35,28,158,21,35,232,46,22,31,96,182,6,39,35,57,243,53,142,189,116,46,104,143,0,0,130,255,31,16,229,253,242,8,223,191,16,21,165,63,139,58,187,93,33,62,218,10,67,54,225,109,152,35,129,110,203,39,42,102,0,0,250,9,56,18,183,227,138,35,225,75,149,29,212,44,23,33,253,8,31,5,201,143,205,36,186,40,242,9, +148,139,111,7,56,56,0,0,82,237,31,51,96,212,193,53,219,36,143,45,204,50,127,32,54,204,177,14,72,149,22,16,9,203,125,17,238,131,66,11,163,228,0,0,16,163,194,23,34,153,144,58,3,99,34,1,80,169,171,33,241,161,153,6,169,10,110,8,105,111,174,50,13,57,201,9,38,73,0,0,208,222,39,30,5,218,6,49,224,140,255,53,169,132,141,5,109,59,48,20,92,90,233,51,162,149,191,58,41,239,220,57,55,19,0,0,49,45,189,14,231,193,18,14,209,184,109,48,191,149,6,51,77,248,226,55,145,207,78,9,94,13,201,0,137,6,163,21,6,227,0,0,68,110, +84,18,14,2,173,36,102,130,115,35,175,16,32,47,255,182,13,61,253,65,172,60,136,8,38,52,36,222,248,27,172,14,0,0,176,54,49,54,120,14,195,20,156,221,65,43,106,54,254,58,116,51,214,59,143,216,57,44,113,194,239,12,10,137,3,4,158,59,0,0,138,188,219,44,189,5,251,20,25,248,49,45,206,40,138,43,162,38,91,7,61,174,207,20,241,29,183,43,69,75,5,38,251,250,0,0,63,93,72,47,28,193,35,24,233,238,123,16,32,218,129,50,23,247,222,30,215,3,42,27,183,146,154,44,74,92,82,43,10,187,0,0,117,249,162,60,64,73,78,30,254,191, +112,22,140,190,150,22,137,52,218,23,202,125,128,52,236,152,71,53,96,241,20,39,105,234,0,0,201,141,113,54,232,76,187,43,228,61,18,1,108,211,98,57,225,19,1,62,235,101,172,35,78,13,204,47,59,57,178,2,9,121,0,0,197,231,250,28,196,138,204,24,185,8,144,58,194,237,171,13,221,86,170,26,54,47,91,32,61,241,184,5,100,228,138,28,171,234,0,0,209,199,96,63,49,165,165,9,42,173,117,23,243,121,199,53,141,102,186,9,149,243,110,15,192,81,181,23,126,122,107,32,124,231,0,0,73,36,215,2,202,7,22,59,52,109,152,2,199,61, +28,5,99,67,21,40,250,200,236,48,95,28,50,1,190,59,30,5,207,58,0,0,17,30,35,19,65,245,27,26,230,227,129,54,64,25,58,18,31,9,54,12,102,228,127,38,255,101,93,56,171,93,192,62,243,228,0,0,188,115,235,47,93,225,176,8,152,28,29,21,178,211,249,49,108,40,183,2,168,67,155,6,102,193,241,52,59,180,206,24,99,30,0,0,214,91,240,43,57,193,103,14,101,148,169,18,200,128,91,61,162,236,13,7,173,127,212,11,131,144,254,4,185,111,144,12,12,144,0,0,139,53,13,48,239,180,74,57,93,177,239,4,15,214,20,38,214,57,36,11,92,17, +200,49,149,95,15,31,44,58,122,62,49,108,0,0,80,92,16,31,50,163,240,41,87,82,56,49,222,187,55,56,130,205,51,2,15,208,48,35,98,173,10,25,193,170,216,0,141,90,0,0,233,205,164,56,96,128,108,50,53,60,1,45,153,162,125,1,166,116,255,3,5,201,173,41,54,105,83,14,245,68,172,58,89,192,0,0,235,79,214,50,230,98,248,17,198,146,34,41,100,41,190,28,55,232,164,11,219,93,233,60,142,164,96,47,140,196,64,19,63,217,0,0,89,131,105,52,100,245,62,44,55,218,144,44,251,194,16,56,147,77,140,28,83,113,196,28,35,58,115,50,114, +81,87,21,37,121,0,0,132,188,159,3,53,19,136,8,103,1,122,5,88,164,24,28,126,91,198,42,152,241,138,19,177,65,132,50,219,184,113,26,7,47,0,0,236,27,32,28,120,11,228,62,115,93,221,4,147,218,230,41,204,73,33,14,100,30,192,55,165,223,221,59,92,147,220,60,52,180,0,0,234,88,167,6,50,171,223,20,77,156,241,39,36,198,32,6,145,57,110,1,85,104,37,26,88,153,48,32,103,21,224,25,126,254,0,0,73,182,122,27,87,182,200,19,30,13,18,3,209,193,5,32,59,31,37,9,97,90,56,2,140,152,203,29,160,232,89,26,170,56,0,0,250,254,255, +12,154,88,197,57,173,175,81,6,220,19,1,6,16,133,175,3,67,69,190,61,109,125,18,3,78,157,114,61,186,145,0,0,175,111,127,31,211,188,77,31,220,3,211,47,57,196,188,47,244,146,61,29,159,196,167,37,93,190,206,59,209,100,196,51,229,4,0,0,70,197,51,13,250,69,2,63,50,175,237,5,202,236,215,21,130,215,221,53,131,207,77,49,178,124,138,55,207,114,72,16,88,68,0,0,212,79,11,0,28,70,155,2],"i8",4,t.L+10240); +D([102,115,202,50,62,143,194,11,133,32,218,26,228,184,122,9,114,167,83,7,254,252,221,36,141,48,0,0,158,226,234,32,184,186,237,27,113,208,225,20,195,203,211,0,199,102,66,26,145,222,84,24,185,30,51,63,58,198,166,62,0,140,0,0,75,65,2,39,25,147,74,31,78,197,54,30,160,190,182,62,194,116,201,54,220,232,208,48,157,26,26,18,169,255,153,28,164,239,0,0,61,145,253,43,15,88,229,15,172,158,76,37,187,57,160,41,80,32,141,42,48,33,232,1,77,135,223,61,65,250,169,10,54,54,0,0,61,36,46,5,171,107,62,17,252,170,47,43, +53,196,46,12,216,130,42,26,195,13,145,24,65,83,253,10,46,219,25,30,242,72,0,0,150,40,19,45,230,175,174,50,103,201,198,59,173,238,120,44,252,13,32,25,183,88,182,22,41,47,224,33,202,124,219,37,135,68,0,0,72,82,104,47,74,108,0,35,164,167,106,39,152,86,3,45,6,51,26,22,209,29,164,38,252,30,254,26,69,52,24,22,189,39,0,0,12,103,162,63,218,91,5,2,110,62,39,6,232,10,62,0,116,36,3,53,12,170,114,42,182,136,55,56,242,162,176,14,77,74,0,0,77,118,193,22,247,127,46,2,216,238,155,50,47,83,22,12,73,157,43,48,123, +119,196,29,126,241,164,5,97,0,71,46,171,112,0,0,167,74,178,12,137,191,90,54,48,197,69,19,142,49,66,12,144,24,254,56,127,98,191,57,58,44,128,17,186,66,70,11,123,95,0,0,125,61,105,10,13,29,224,53,198,208,129,60,36,220,122,35,206,71,124,38,243,40,224,15,10,51,43,31,63,49,128,13,112,7,0,0,189,184,127,47,124,241,70,6,164,144,64,62,87,40,25,49,123,216,134,8,101,155,147,48,174,2,13,25,231,76,20,29,57,81,0,0,15,140,144,3,182,176,82,2,168,213,152,63,248,180,12,63,250,71,92,1,186,246,251,35,184,52,191,3,217, +145,15,5,215,252,0,0,115,202,54,46,87,36,221,10,222,62,191,59,218,52,25,50,234,135,72,1,252,74,68,10,164,138,251,61,254,138,181,5,131,207,0,0,52,85,194,46,80,134,36,45,245,16,215,8,54,102,133,37,28,104,202,28,67,34,20,17,56,62,215,25,215,122,99,45,254,9,0,0,125,249,82,55,90,223,36,50,19,102,71,51,215,241,190,11,90,22,166,15,163,25,74,39,83,222,73,59,18,147,166,55,16,134,0,0,242,26,27,31,80,115,95,1,8,62,84,5,213,103,211,42,87,158,249,51,148,108,102,51,55,201,187,48,216,10,232,37,25,211,0,0,65,62, +203,32,241,119,255,37,9,44,185,8,204,19,66,15,20,211,142,41,167,2,59,3,225,243,41,8,117,167,57,27,162,231,0,0,81,253,44,15,135,80,42,58,32,62,232,32,16,176,172,41,208,24,187,47,106,168,1,44,113,180,132,57,233,3,140,35,117,42,0,0,219,66,238,58,175,244,231,3,167,20,7,51,209,22,239,46,217,193,191,44,71,110,187,45,199,15,21,25,109,246,249,9,52,204,0,0,219,123,216,21,4,112,138,24,220,34,36,39,99,235,114,57,16,0,82,33,236,79,255,56,133,24,106,28,72,105,16,38,36,234,0,0,134,160,212,62,25,155,13,61,239,16, +196,41,99,5,215,53,177,244,92,11,239,23,22,15,200,222,69,4,102,179,110,1,143,148,0,0,75,202,43,30,62,0,134,10,26,45,250,3,199,41,202,8,28,65,57,17,128,153,66,17,47,56,163,34,214,254,39,42,76,134,0,0,33,44,84,55,178,169,47,3,92,193,100,42,163,52,125,6,174,67,109,29,20,21,241,27,101,144,172,25,164,164,88,6,132,37,0,0,191,250,43,39,101,140,175,47,179,215,42,12,185,97,232,56,243,213,19,53,49,147,106,23,30,128,68,50,54,199,199,22,179,252,0,0,248,203,30,12,208,135,17,15,164,124,237,46,166,55,124,34,100, +31,66,40,7,51,213,37,42,82,82,60,220,4,113,51,18,126,0,0,21,214,190,48,54,227,22,53,89,159,29,62,99,135,125,26,201,89,18,13,249,106,83,62,67,113,131,28,35,34,226,19,40,113,0,0,134,125,85,20,112,148,153,31,65,255,103,38,227,17,187,63,28,207,166,5,232,41,71,46,114,103,42,52,141,202,191,48,142,75,0,0,185,126,22,53,70,198,102,55,43,105,63,60,195,187,124,53,40,95,172,39,148,183,28,16,74,177,122,21,48,193,255,48,230,253,0,0,60,118,128,7,237,180,224,10,213,145,86,38,164,87,155,34,95,126,192,58,165,113,219, +16,50,37,164,35,229,204,65,48,213,252,0,0,203,81,232,56,128,208,57,21,75,58,70,22,156,139,108,6,177,140,227,50,125,205,54,8,183,99,196,34,84,185,248,42,221,24,0,0,134,246,142,29,193,248,142,51,107,230,114,34,0,61,146,35,246,83,110,38,224,107,151,34,35,82,190,60,16,150,59,11,15,144,0,0,207,168,33,33,159,37,233,28,80,109,21,9,15,253,55,27,89,16,209,9,77,108,84,49,97,173,37,4,24,123,85,48,42,115,0,0,239,128,107,30,207,122,202,51,243,36,148,23,159,229,242,50,113,197,189,60,142,8,3,21,35,141,236,34,217, +184,131,39,69,182,0,0,69,186,113,26,216,194,47,12,255,178,53,14,82,155,235,44,196,179,29,38,149,91,124,43,29,222,6,62,188,65,219,33,124,6,0,0,233,136,152,49,228,201,115,14,180,168,72,36,252,154,174,4,61,103,129,38,165,192,52,24,222,45,110,58,176,206,157,58,144,31,0,0,121,59,17,47,95,242,247,27,101,46,82,25,185,127,212,13,33,168,150,43,199,73,79,5,88,233,16,42,118,5,159,13,190,137,0,0,44,34,98,53,188,237,123,33,96,44,111,30,100,30,209,0,222,186,82,11,205,180,174,0,231,214,10,62,127,123,83,57,164,19, +0,0,69,1,32,40,50,154,197,50,8,76,144,28,235,93,113,62,212,82,154,32,117,224,11,43,44,59,129,46,5,150,83,31,214,201,0,0,187,70,59,52,3,55,249,13,84,82,146,44,254,152,78,59,18,189,93,5,97,23,240,1,212,209,173,10,207,200,175,7,153,97,0,0,72,168,32,12,7,100,61,18,239,216,236,18,41,167,28,42,28,241,173,59,155,197,225,60,82,41,73,30,255,60,194,56,197,1,0,0,59,221,26,18,119,143,111,57,247,216,39,23,209,19,165,38,139,17,38,22,52,108,115,14,144,116,56,61,225,45,169,43,39,234,0,0,221,231,140,54,118,164,120, +45,113,190,225,36,163,181,132,44,120,98,47,28,201,200,58,15,114,229,125,33,10,185,121,60,15,199,0,0,87,247,31,33,237,226,43,58,230,38,194,4,7,93,58,19,155,218,182,34,219,226,67,0,169,75,213,63,223,90,77,20,70,89,0,0,26,3,77,9,42,187,153,34,178,227,255,59,223,30,239,6,150,249,6,4,87,64,227,0,66,0,117,50,119,57,131,13,17,54,0,0,181,96,97,35,141,98,137,29,6,188,126,14,28,201,79,49,204,192,30,9,192,229,189,14,132,14,41,51,125,69,142,27,178,22,0,0,14,220,161,24,253,126,137,17,129,239,163,11,28,171,142, +13,225,212,84,54,24,73,13,25,99,187,248,46,192,152,150,21,15,6,0,0,184,45,179,55,36,74,147,37,243,145,119,36,125,210,181,7,201,133,234,44,16,242,80,40,190,49,249,25,21,113,165,20,75,2,0,0,96,247,100,42,170,62,21,37,149,26,184,5,72,4,218,42,98,232,91,30,49,135,160,56,182,199,9,51,255,214,227,59,159,96,0,0,232,67,105,9,109,61,104,59,93,90,60,39,159,241,199,27,29,35,6,15,70,168,210,8,147,7,132,59,2,10,50,32,138,214,0,0,32,49,19,43,153,16,50,37,162,149,82,4,222,227,158,3,91,139,226,48,222,69,126,44,196, +0,109,24,45,253,127,42,139,219,0,0,249,196,161,12,134,170,208,22,35,40,126,43,50,141,191,19,79,244,22,31,152,246,224,2,196,196,40,23,175,200,227,61,21,120,0,0,21,188,120,55,218,168,199,42,25,30,125,23,133,121,11,45,92,93,195,24,81,204,243,36,221,167,246,26,78,51,122,0,198,193,0,0,48,133,140,46,15,135,155,52,230,216,244,56,123,160,125,11,81,109,108,42,5,144,241,29,227,118,1,4,59,104,243,28,146,195,0,0,199,70,132,57,61,60,12,16,92,113,237,46,104,47,127,59,80,152,25,3,7,81,78,7,208,233,200,51,208,149, +144,47,65,140,0,0,193,38,122,35,236,2,201,7,83,106,191,13,48,150,27,27,22,37,59,16,7,199,144,8,117,2,27,1,97,253,17,29,49,218,0,0,111,77,247,44,179,219,96,20,95,82,129,58,117,177,13,26,211,183,216,25,9,159,5,33,35,157,198,24,215,31,238,37,59,117,0,0,73,220,57,55,164,162,216,10,61,96,85,47,153,182,228,36,35,26,35,63,47,66,177,18,6,193,230,48,171,192,178,57,75,106,0,0,207,213,237,50,119,174,168,57,211,164,164,20,44,211,138,31,171,88,128,58,131,141,155,5,220,151,117,16,162,138,234,35,93,241,0,0,172, +127,152,6,49,40,250,34,121,246,134,10,144,225,67,50,139,60,138,9,251,128,9,38,78,52,241,39,235,196,167,49,247,1,0,0,104,76,23,25,224,156,71,62,99,194,107,31,134,120,215,31,203,249,182,26,202,184,13,4,91,222,34,26,191,205,15,51,78,157,0,0,77,186,218,54,245,134,206,52,97,98,25,3,136,195,126,25,156,203,43,58,99,183,139,1,183,28,56,61,135,93,0,37,126,85,0,0,22,35,165,55,110,40,221,4,165,144,53,36,126,61,110,58,197,134,188,12,87,232,115,13,109,4,126,58,7,152,206,35,126,122,0,0,26,52,245,41,252,75,61,14, +128,107,99,41,25,203,232,49,156,65,1,49,158,58,80,39,178,147,90,8,102,134,160,54,218,58,0,0,204,198,134,37,77,2,86,20,203,251,232,5,109,185,180,53,233,23,16,43,218,252,214,56,82,245,105,19,102,162,136,7,234,191,0,0,93,61,141,2,63,96,86,2,164,206,73,52,92,174,171,4,150,176,48,58,65,194,9,48,45,37,4,8,151,125,95,59,74,50,0,0,132,124,171,22,190,146,200,25,57,132,50,35,31,195,78,8,25,79,31,44,107,13,3,3,19,255,242,33,45,221,149,13,138,100,0,0,211,62,213,47,96,93,36,23,239,204,86,26,231,62,221,15,22,73, +124,31,199,228,130,61,184,213,42,55,89,102,245,2,132,32,0,0,50,113,122,26,148,255,80,28,152,137,112,14,229,28,241,33,84,194,250,58,154,218,81,47,135,52,36,24,176,243,37,13,153,242,0,0,53,91,163,8,214,46,75,47,237,33,161,0,151,34,118,45,26,253,235,8,150,167,64,15,209,187,155,51,172,131,253,47,182,230,0,0,189,7,16,28,110,79,202,21,124,156,153,62,78,39,219,14,254,221,97,25,13,142,15,61,102,50,47,13,192,76,175,60,95,26,0,0,211,13,54,0,75,227,59,53,144,32,14,5,182,13,42,42,71,187,227,12,184,33,224,2,139, +40,155,9,249,22,221,5,83,224,0,0,123,248,36,60,68,54,187,10,43,220,3,1,166,247,97,46,97,20,160,54,214,10,86,2,216,156,243,18,118,105,220,14,28,220,0,0,234,223,152,16,139,153,81,48,151,135,103,42,75,242,44,55,250,87,94,58,160,74,151,35,1,158,197,6,226,157,206,14,21,168,0,0,47,137,109,46,125,167,38,41,88,65,175,45,208,61,120,45,177,3,62,5,94,113,110,35,61,197,15,6,116,24,89,14,71,42,0,0,165,207,206,11,146,222,249,41,32,176,107,49,134,182,88,3,42,59,218,14,142,113,165,17,235,173,221,10,251,195,236,48, +5,79,0,0,83,123,211,21,42,9,52,59,210,140,180,1,124,12,185,31,68,185,52,21,86,216,200,24,221,250,38,20,15,152,122,38,164,83,0,0,170,150,75,8,100,217,121,24,228,204,171,34,84,141,97,10,208,14,152,59,168,134,23,16,38,190,145,58,217,103,174,38,48,217,0,0,134,138,178,2,223,60,177,9,143,151,254,60,235,126,178,45,211,95,203,52,137,25,60,4,126,125,85,44,211,166,202,38,249,110,0,0,14,207,143,31,22,52,238,61,172,111,74,60,121,255,219,22,214,17,52,42,122,27,209,48,169,91,211,34,21,78,40,31,88,125,0,0,89,148, +188,24,39,104,112,0,165,128,55,50,180,2,228,24,196,208,106,61,179,45,0,13,114,18,198,4,12,226,0,23,41,167,0,0,150,76,5,61,207,77,47,58,136,168,28,13,234,14,5,49,238,220,229,62,151,111,127,7,213,246,97,30,115,70,82,48,249,77,0,0,93,13,209,10,27,176,174,11,25,144,132,40,112,179,65,53,181,212,133,29,232,8,211,37,80,128,114,24,75,66,20,59,53,0,0,0,29,0,239,29,105,151,200,19,239,39,186,9,166,245,110,62,33,75,182,35,39,112,244,2,14,242,202,34,159,108,203,40,73,165,0,0,131,71,98,48,159,198,118,53,173,5, +151,44,152,138,7,5,235,86,148,37,98,59,12,51,244,189,108,22,182,65,158,30,155,121,0,0,203,212,46,5,151,199,187,22,160,197,158,0,207,190,55,21,201,110,46,19,13,102,47,2,63,18,205,62,129,54,204,35,121,126,0,0,98,148,187,20,30,152,197,21,18,122,243,57,255,198,213,28,177,87,240,50,123,39,85,42,65,48,200,26,147,40,49,51,61,210,0,0,52,8,99,19,239,131,206,55,127,6,172,61,24,74,252,24,132,8,129,12,234,90,122,46,213,58,120,20,84,12,128,40,79,34,0,0,114,34,122,4,223,28,241,52,92,247,80,10,176,147,164,24,61, +245,9,29,228,232,195,45,196,195,165,45,207,174,140,19,229,187,0,0,215,25,60,24,69,39,217,25,187,87,207,2,107,145,215,46,187,242,142,34,144,51,151,40,41,65,158,35,2,24,51,40,212,194,0,0,141,146,7,5,11,46,202,11,119,201,69,51,197,160,18,32,38,13,38,1,253,125,237,32,65,77,41,6,32,112,62,40,173,101,0,0,154,12,148,60,82,43,32,19,8,51,66,47,78,56,207,51,19,33,220,13,209,137,23,22,229,144,49,31,193,176,159,10,194,46,0,0,77,122,30,5,102,63,101,52,172,189,53,26,246,96,20,16,18,235,127,28,10,212,147,56,194, +132,150,55,140,55,26,41,29,139,0,0,235,62,104,29,127,185,195,41,58,19,211,8,40,206,186,13,62,243,184,4,66,73,217,43,177,202,206,40,230,227,92,26,198,175,0,0,9,69,205,48,172,114,138,7,201,253,221,30,73,213,234,2,87,22,156,35,40,255,113,22,195,43,117,34,116,219,101,8,44,0,0,0,147,66,111,55,30,126,128,40,158,19,197,19,89,45,94,58,16,46,40,11,220,60,35,47,33,145,48,3,205,167,214,30,85,210,0,0,10,116,130,18,137,30,198,54,241,165,5,36,55,14,218,18,227,31,210,10,173,27,188,32,38,1,127,2,121,213,208,44,135, +167,0,0,205,152,31,44,34,103,242,47,140,48,240,23,83,65,34,13,82,33,96,6,115,112,42,54,174,15,135,52,145,18,106,6,57,156,0,0,157,89,252,20,15,120,249,57,107,142,76,6,219,189,201,20,144,65,230,32,201,47,17,60,132,117,213,29,147,210,195,19,184,221,0,0,179,77,182,15,78,53,230,30,65,56,213,29,142,50,121,59,167,214,184,19,249,254,224,46,11,116,203,28,111,138,228,8,20,193,0,0,190,89,2,60,127,58,195,8,30,125,86,20,19,36,96,29,168,209,139,23,250,147,55,59,92,42,252,6,210,22,183,61,55,18,0,0,70,30,8,3,208, +96,123,59,161,158,85,20,21,99,136,20,58,113,52,38,100,176,112,54,130,64,34,55,105,12,254,18,91,108,0,0,112,205,251,11,224,114,126,52,46,166,34,44,154,224,51,52,65,120,228,43,56,143,225,17,35,251,66,45,73,82,220,4,5,203,0,0,75,205,77,6,177,107,185,50,77,18,28,17,102,245,49,12,12,69,10,49,42,151,25,28,86,75,222,10,195,153,21,42,233,225,0,0,44,31,4,59,122,137,45,52,146,178,22,10,171,102,52,17,127,146,119,37,108,102,13,49,122,27,83,28,21,81,165,2,43,86,0,0,60,215,173,43,248,219,97,1,208,183,100,42,64, +118,115,54,143,32,20,28,187,144,211,41,120,151,9,27,68,235,149,6,178,81,0,0,209,216,54,43,135,43,245,61,166,75,115,12,202,195,4,8,108,250,28,44,116,192,31,40,84,93,62,61,7,0,4,12,121,0,0,0,75,243,9,59,220,66,215,53,230,108,198,12,130,249,28,34,229,97,157,51,207,91,138,45,26,134,121,11,199,142,233,60,1,151,0,0,147,87,223,0,51,20,114,51,74,121,204,61,95,14,47,1,113,55,131,22,197,212,198,0,215,21,237,48,43,227,238,18,212,61,0,0,70,47,30,63,142,136,57,23,1,131,119,50,161,199,61,28,82,87,60,22,3,129,75, +22,69,196,108,38,39,75,7,45,54,160,0,0,73,179,255,30,165,137,199,28,79,31,11,63,179,160,56,32,6,141,176,30,30,169,218,7,223,215,179,22,250,0,104,36,191,195,0,0,8,234,76,12,14,228,98,51,219,33,234,32,131,46,214,18,101,82,70,0,208,84,132,41,244,6,197,40,147,234,182,62,133,106,0,0,243,244,98,24,150,179,119,6,106,27,114,61,208,146,198,9,180,48,98,62,35,5,207,36,49,213,89,6,185,46,129,17,182,0,0,0,229,89,169,32,132,224,132,40,197,76,29,57,162,78,82,56,145,187,6,14,118,160,124,1,222,248,253,18,116,199, +194,5,87,96,0,0,168,162,133,35,76,250,102,34,94,198,36,46,15,175,84,20,70,98,242,29,220,107,139,38,221,122,128,36,154,154,44,60,26,154,0,0,43,3,28,23,138,133,54,53,128,201,253,58,133,162,217,26,255,197,102,7,127,127,109,4,221,3,38,0,184,53,63,42,235,113,0,0,159,53,104,22,56,106,173,30,94,117,180,52,93,180,198,36,113,127,187,12,213,91,20,24,246,222,57,29,216,146,152,4,255,210,0,0,28,166,3,42,20,29,185,1,77,87,112,16,26,61,26,30,80,208,157,42,234,10,209,5,202,50,210,9,201,108,193,48,94,133,0,0,7,252, +93,6,171,186,241,55,101,73,228,23,168,211,189,12,211,78,251,2,109,254,47,15,84,127,193,1,124,177,75,23,216,13,0,0,6,215,50,31,32,41,48,0,139,103,160,6,29,41,51,6,6,162,191,21,194,104,74,3,21,31,191,63,172,174,26,18,228,60,0,0,228,217,127,60,223,216,220,2,244,137,30,22,243,144,85,52,237,6,73,9,196,26,65,63,142,40,133,55,184,106,35,16,117,231,0,0,251,211,28,57,237,50,208,54,134,230,155,50,101,255,140,10,74,235,68,8,62,134,12,56,2,175,127,35,211,15,69,49,204,17,0,0,134,13,22,21,233,90,220,36,42,71,211, +13,75,191,199,2,250,57,194,12,78,18,137,35,82,235,29,49,10,164,202,26,165,74,0,0,82,117,143,33,101,68,238,33,195,250,84,0,230,226,68,16,189,221,130,35,224,211,221,37,59,244,198,9,69,249,197,46,80,2,0,0,77,177,16,53,136,37,33,60,227,241,214,51,12,207,27,0,218,23,216,41,127,221,247,53,66,35,8,40,239,38,63,12,25,115,0,0,18,93,114,31,78,250,68,23,80,71,95,11,247,174,144,17,217,191,47,2,40,56,231,40,180,58,253,39,209,44,34,39,116,26,0,0,228,86,172,35,52,69,217,4,112,170,13,25,98,26,130,28,96,143,61,47, +10,215,249,34,69,207,226,0,251,92,101,52,145,126,0,0,88,228,250,41,148,35,65,24,253,151,236,38,157,16,151,2,139,50,123,59,119,169,85,52,9,193,24,2,62,248,22,26,80,199,0,0,152,181,87,23,101,16,90,0,43,26,149,53,12,148,114,23,10,180,199,50,25,83,208,11,181,95,224,33,228,51,126,37,215,234,0,0,102,66,185,44,251,92,154,6,43,241,77,61,233,62,188,51,128,24,163,13,70,145,230,16,33,20,65,8,232,136,227,55,118,165,0,0,200,142,178,33,107,132,47,58,62,159,77,17,253,41,132,11,67,44,216,12,150,191,94,46,146,44, +11,36,217,57,200,47,166,64,0,0,193,214,158,13,99,173,43,26,107,61,89,61,240,22,157,19,194,14,221,30,193,29,6,63,11,232,83,15,221,114,219,12,40,3,0,0,238,254,250,56,155,175,27,59,173,148,180,28,201,55,253,22,38,140,124,13,136,14,101,53,70,140,242,25,191,4,14,38,168,113,0,0,58,152,53,50,52,106,106,6,41,235,188,19,192,13,132,34,227,49,21,62,195,181,73,14,198,77,197,17,228,162,171,19,79,206,0,0,207,222,60,13,100,172,245,51,174,64,247,43,163,72,25,27,82,67,117,48,121,146,128,55,234,179,187,15,228,240, +92,62,201,243,0,0,201,230,176,21,153,173,106,27,154,200,228,6,222,115,254,23,219,189,188,56,183,205,62,10,142,39,34,6,230,82,233,47,190,77,0,0,37,204,178,30,85,225,41,37,174,239,4,5,175,108,196,36,88,243,41,34,184,185,137,41,69,223,174,19,36,15,236,57,254,16,0,0,149,114,133,37,70,104,128,19,22,240,51,52,192,31,57,50,105,32,161,28,40,63,70,56,178,24,194,5,189,255,2,9,42,164,0,0,193,185,126,10,251,223,205,26,85,57,25,21,52,139,112,40,39,196,164,29,147,172,200,26,122,86,212,5,64,152,252,44,160,58,0, +0,152,192,205,47,85,253,131,8,50,128,70,46,218,3,184,2,85,193,153,4,3,27,126,60,167,103,34,50,190,229,203,10,225,52,0,0,226,116,116,42,121,107,44,19,102,63,136,25,60,76,212,55,4,219,114,57,5,33,47,19,151,45,50,29,237,117,183,48,74,166,0,0,146,59,23,15,122,173,91,51,17,118,251,41,5,189,156,31,59,104,101,13,61,134,104,12,190,41,31,57,110,54,144,52,244,16,0,0,194,70,49,35,181,1,8,36,124,219,106,8,69,167,221,46,144,186,8,57,140,150,150,44,17,210,58,53,69,66,101,11,14,133,0,0,88,73,216,40,102,71,191,57, +174,92,204,10,91,172,119,4,106,134,204,0,181,93,110,6,159,116,126,39,109,218,2,58,70,232,0,0,159,207,130,56,237,145,17,3,100,26,12,30,156,205,104,20,173,111,183,24,30,65,100,47,29,84,226,7,83,34,63,46,156,162,0,0,113,173,88,62,38,226,216,61,8,162,163,57,115,125,52,12,187,56,140,30,167,88,250,23,160,48,62,44,55,10,227,41,120,119,0,0,172,67,159,61,7,255,68,45,99,197,74,50,127,4,225,44,135,0,88,63,203,75,56,38,112,255,34,27,105,173,102,27,98,52,0,0,105,200,25,51,184,186,241,61,2,39,235,33,93,87,126, +42,24,220,172,12,191,8,228,32,1,141,252,51,5,102,23,1,24,48,0,0,240,86,184,18,39,219,49,48,191,167,217,35,146,50,161,10,202,59,46,34,53,200,144,24,134,111,123,59,64,9,94,49,95,172,0,0,181,41,237,37,190,97,154,49,180,209,173,18,28,216,194,32,245,133,200,35,105,110,159,45,58,52,239,23,185,135,109,32,40,50,0,0,210,90,209,60,185,73,60,61,78,96,231,14,229,170,235,32,202,225,49,21,208,119,198,2,17,235,68,3,232,5,161,0,119,22,0,0,0,97,201,6,30,16,234,47,99,142,156,46,169,70,192,24,161,204,219,51,183,108, +118,15,180,255,185,49,62,176,206,17,56,63,0,0,7,71,98,50,111,176,138,7,207,27,95,55,2,31,199,21,102,229,156,7,188,24,17,19,83,82,57,0,117,125,21,39,198,112,0,0,172,210,34,61,27,187,49,13,2,206,170,28,155,132,127,55,16,47,223,5,94,130,3,15,180,220,118,58,73,127,241,4,129,40,0,0,104,162,66,15,126,213,122,32,208,143,140,20,133,18,245,48,221,55,97,23,50,152,220,29,32,143,92,60,62,86,192,58,167,161,0,0,168,142,95,36,116,3,234,18,13,144,210,36,229,56,146,28,209,229,159,17,92,87,54,61,83,165,162,35,17,50, +128,40,99,249,0,0,235,153,188,25,193,126,21,47,36,8,182,24,103,141,60,46,139,32,39,52,127,192,136,28,59,10,60,56,31,163,9,37,133,156,0,0,21,163,6,38,196,32,106,56,217,58,150,38,188,28,152,28,64,126,9,14,100,169,44,54,152,127,154,13,220,63,147,8,217,165,0,0,209,104,59,30,214,76,88,13,157,124,26,17,31,77,67,19,237,233,13,24,94,175,26,12,67,179,165,13,200,14,192,34,50,135,0,0,147,20,35,6,80,237,109,51,105,212,196,12,195,160,70,16,150,164,230,37,3,116,144,19,235,4,54,60,220,134,11,38,254,241,0,0,193, +72,136,53,153,102,170,37,1,13,255,37,27,205,254,28,241,211,153,61,125,129,240,52,22,194,221,36,102,187,122,6,32,46,0,0,172,3,217,6,112,106,123,2,203,229,215,26,57,157,88,62,213,46,253,58,57,76,127,10,55,70,132,58,141,185,87,37,40,9,0,0,31,9,205,27,77,58,96,20,252,131,141,10,234,187,73,15,172,238,149,58,36,76,40,30,123,130,42,52,79,15,64,8,86,194,0,0,57,184,116,56,213,161,68,4,24,180,210,19,229,108,69,16,190,174,182,48,200,126,195,55,83,128,90,30,56,240,7,46,3,62,0,0,186,148,5,60,89,57,7,3,218,184, +181,26,63,124,113,57,125,102,143,25,92,29,152,61,68,44,244,7,252,247,88,56,58,209,0,0,19,165,87,3,154,227,253,40,243,35,48,27,209,68,111,20,241,197,34,41,168,14,138,62,98,205,146,4,189,232,45,48,98,230,0,0,126,208,23,32,114,128,168,36,145,216,56,21,137,53,215,0,216,25,164,33,132,34,136,43,93,48,82,36,132,57,79,6,11,171,0,0,66,210,55,31,191,223,87,38,4,75,193,57,129,41,251,39,194,125,88,35,47,31,139,33,67,184,108,15,83,114,44,32,191,64,0,0,136,80,64,38,230,9,118,52,131,85,211,43,144,174,135,12,116, +18,254,38,108,108,250,15,245,4,175,42,21,118,77,55,121,181,0,0,88,53,90,25,145,205,202,43,43,127,74,35,120,225,199,1,172,246,89,27,227,4,94,62,6,8,167,28,7,216,165,63,20,61,0,0,76,223,67,36,177,206,182,26,124,114,29,60,81,184,40,56,130,20,110,53,111,199,164,38,242,248,30,40,17,186,117,47,198,22,0,0,36,252,177,2,182,214,167,55,14,87,247,35,31,7,54,10,37,101,72,18,178,52,177,6,204,81,82,38,11,58,80,41,111,221,0,0,202,116,155,14,24,113,12,41,4,35,50,23,251,154,55,4,236,119,126,37,197,175,199,27,54,254, +134,49,116,172,223,10,230,103,0,0,2,142,208,61,100,69,170,7,136,2,223,26,255,237,81,33,16,128,30,61,168,102,82,26,248,128,215,21,121,11,106,11,250,19,0,0,16,52,176,60,112,7,85,41,125,185,66,26,198,238,43,17,230,199,50,52,174,129,88,13,19,35,167,29,85,17,44,14,99,19,0,0,26,228,78,20,230,234,140,48,106,154,214,55,78,183,213,38,135,130,130,6,203,217,66,48,247,67,164,48,241,116,20,18,108,208,0,0,111,94,41,11,166,19,126,60,82,226,46,22,24,13,225,30,155,145,48,54,211,83,179,2,187,219,10,13,97,1,83,63,21, +88,0,0,81,39,216,35,69,157,171,30,82,84,211,58,65,42,109,17,86,133,178,35,131,206,147,1,153,147,16,27,27,251,188,63,208,133,0,0,98,249,177,14,137,222,8,11,88,49,115,7,90,122,212,33,62,102,245,44,96,185,37,53,41,190,192,56,232,4,33,25,3,31,0,0,243,76,222,44,135,65,85,38,171,102,160,56,81,77,57,16,147,231,154,29,69,155,180,48,231,59,44,2,69,176,210,42,77,56,0,0,102,5,45,37,200,90,30,31,59,167,27,53,229,140,194,16,31,240,198,52,138,182,181,19,251,59,164,28,110,52,111,49,227,214,0,0,194,56,82,30,72,250, +188,34,185,184,236,0,14,215,87,13,64,72,237,2,58,45,132,5,27,164,90,1,245,173,3,59,240,20,0,0,34,121,240,18,30,141,26,58,214,57,73,48,0,54,0,23,210,127,116,2,225,248,28,63,33,9,216,53,32,117,79,53,18,171,0,0,77,233,67,21,191,75,141,61,136,225,152,47,213,169,192,4,221,218,13,26,41,158,209,48,65,236,135,2,11,222,238,60,66,235,0,0,137,77,146,5,145,119,86,1,36,212,214,32,121,163,17,54,76,119,251,13,191,92,117,3,154,220,146,29,201,211,65,27,74,35,0,0,237,170,25,62,213,150,147,12,112,50,103,6,163,55,235, +38,69,32,169,6,184,189,0,59,158,154,13,2,90,148,50,14,241,28,0,0,14,64,47,41,117,169,219,4,188,255,119,60,251,227,187,39,71,23,222,45,173,153,202,13,244,101,56,6,199,197,188,54,255,214,0,0,57,170,168,54,126,58,176,61,85,172,143,39,210,222,152,41,55,217,144,25,18,90,130,22,135,44,65,13,208,151,175,33,134,181,0,0,31,60,73,43,116,77,30,63,184,71,179,45,57,230,107,47,171,29,169,0,83,81,227,17,73,193,194,56,49,201,80,53,50,86,0,0,197,76,59,48,142,175,71,58,46,124,199,33,150,110,12,10,87,2,168,51,159,63, +241,22,123,182,194,60,226,26,108,39,193,95,0,0,40,124,181,37,225,126,206,14,74,236,135,0,243,64,189,29,146,244,94,58,104,62,78,8,238,102,124,12,38,59,48,33,142,236,0,0,181,140,179,12,245,21,46,45,139,148,136,19,211,247,223,2,225,27,234,62,244,3,41,42,235,157,40,30,187,80,195,45,143,184,0,0,215,243,101,25,89,157,254,30,25,199,248,58,137,132,207,19,77,226,168,53,44,101,238,18,3,6,40,35,186,81,171,13,199,214,0,0,126,8,38,5,9,18,80,61,8,3,162,45,32,98,219,62,253,93,184,24,94,16,216,38,28,124,233,44,251, +165,115,3,43,255,0,0,7,153,194,48,7,120,84,50,178,206,226,16,238,91,251,45,199,54,121,16,83,113,19,19,175,136,161,11,73,189,255,4,61,73,0,0,249,129,214,57,249,83,65,22,252,185,254,8,235,187,131,51,102,176,148,44,128,151,252,31,139,136,48,50,215,157,124,63,69,199,0,0,71,18,187,59,13,205,197,0,118,92,212,39,113,205,244,54,140,103,24,40,195,49,229,4,167,120,94,30,174,189,188,8,2,89,0,0,163,14,205,53,180,59,19,56,21,72,172,12,8,58,30,17,179,242,231,50,217,122,121,22,122,178,80,16,93,234,124,30,178,171, +0,0,206,123,48,60,205,196,36,28,100,59,47,32,103,65,218,37,124,212,142,7,12,48,248,18,251,217,112,57,197,239,14,4,238,93,0,0,62,238,201,27,252,188,184,48,197,130,115,62,88,106,232,39,234,17,237,39,9,157,170,43,127,130,130,6,127,214,66,5,129,63,0,0,6,174,154,25,49,108,171,51,3,22,168,13,63,183,236,8,118,98,86,57,17,207,250,6,103,212,130,58,111,63,154,34,200,25,0,0,7,160,228,56,235,251,198,5,182,88,179,11,194,179,59,59,21,236,199,22,169,206,232,18,89,105,222,2,2,116,203,4,248,92,0,0,131,184,104,16, +66,194,143,57,140,254,199,57,177,229,27,37,200,246,61,12,18,98,5,53,74,223,160,31,88,3,151,59,90,180,0,0,167,212,194,38,236,249,91,37,16,251,255,60,206,228,219,48,27,210,78,0,241,92,206,56,83,70,73,58,82,67,147,63,213,182,0,0,113,99,232,58,248,57,55,6,129,204,227,53,155,147,223,22,116,142,253,63,119,130,228,51,223,20,108,61,174,78,232,28,243,71,0,0,51,221,102,60,139,216,76,2,197,109,199,29,252,35,239,35,234,34,176,41,0,84,108,44,107,112,136,53,179,25,240,46,200,97,0,0,250,11,241,54,206,167,238,14, +202,200,32,40,176,186,65,20,106,251,211,5,230,82,102,26,70,52,112,15,149,231,136,39,89,147,0,0,248,47,107,29,51,223,22,32,169,143,108,40,92,176,205,24,135,241,189,3,251,220,212,39,124,24,133,39,9,93,233,10,227,148,0,0,62,175,225,44,84,21,82,55,58,225,191,38,148,16,188,14,179,140,158,45,152,33,146,7,47,25,78,32,246,208,34,17,27,13,0,0,65,226,86,56,179,120,57,32,135,210,109,13,35,133,123,60,87,43,33,27,192,152,203,10,237,169,14,8,122,44,249,46,127,130,0,0,236,147,194,46,46,218,22,24,109,22,3,41,97, +140,233,61,127,104,18,29,244,25,203,59,27,183,176,39,28,143,36,39,15,198,0,0,167,15,184,59,44,23,18,13,134,56,65,48,237,154,246,41,58,159,129,32,76,175,129,6,13,188,47,12,194,216,199,56,87,8,0,0,45,107,54,9,124,132,96,54,171,22,112,13,15,193,141,11,23,71,113,11,119,116,50,31,45,9,114,1,184,142,208,36,67,246,0,0,99,14,199,9,232,176,64,23,111,73,61,53,57,222,226,46,156,46,103,10,217,85,25,23,84,67,0,22,175,149,58,51,170,40,0,0,78,218,87,48,11,226,192,39,139,30,218,4,145,115,22,63,245,183,235,40,29, +159,89,34,122,86,225,32,6,190,139,12,105,43,0,0,181,116,230,51,189,20,119,0,198,170,96,48,57,167,61,54,146,79,138,43,243,38,203,54,93,20,102,26,21,104,137,45,243,162,0,0,65,121,147,14,56,50,78,2,59,165,63,3,95,140,190,8,146,75,124,42,204,67,42,17,0,232,138,6,83,88,86,40,14,98,0,0,86,176,30,25,199,88,128,29,108,56,253,44,227,246,187,0,160,245,21,53,143,26,215,34,217,49,146,37,171,122,242,32,79,60,0,0,171,236,92,32,246,36,150,16,119,184,246,28,32,81,173,32,25,128,120,50,14,207,149,53,58,163,182,40, +82,212,1,36,71,148,0,0,169,223,134,61,110,127,24,36,113,58,153,27,2,41,45,14,220,170,59,16,160,15,120,48,41,78,125,22,166,34,74,56,248,175,0,0,129,38,209,1,219,240,64,28,112,156,159,1,81,106,91,4,249,244,83,15,127,168,174,15,61,253,195,55,77,200,236,18,139,141,0,0,193,169,155,24,174,205,201,35,226,56,211,9,104,41,223,3,228,121,229,14,187,138,9,22,132,62,11,0,55,74,17,30,251,211,0,0,103,178,81,43,127,35,110,24,0,222,26,1,112,117,59,7,52,230,15,55,98,93,129,50,167,124,78,43,233,59,13,53,148,248,0,0, +9,185,43,15,116,176,165,54,153,217,152,53,20,159,64,36,99,127,125,24,228,32,166,28,244,143,168,26,178,130,3,12,201,78,0,0,113,64,207,36,254,224,40,34,123,130,195,26,131,160,133,11,213,186,73,12,97,20,113,3,200,197,77,48,134,175,65,40,43,120,0,0,179,226,32,33,232,99,237,60,167,154,127,52,159,115,63,22,122,33,229,38,51,141,43,57,123,174,219,27,212,135,124,18,166,234,0,0,61,217,90,58,22,76,233,17,157,229,247,19,124,89,174,41,1,90,170,57,97,226,3,42,105,172,3,59,238,86,123,30,50,190,0,0,13,7,46,63,232, +244,15,22,143,169,166,18,49,199,173,42,41,226,71,16,225,14,199,28,72,255,171,52,11,65,122,41,114,75,0,0,128,215,109,41,187,160,46,17,222,195,72,41,116,119,25,45,176,16,60,15,180,205,238,29,2,246,28,46,90,135,83,7,158,89,0,0,28,89,2,10,97,255,57,39,30,90,18,5,150,101,82,61,62,97,253,33,215,250,254,26,90,40,142,28,78,25,255,36,252,169,0,0,220,194,190,41,189,119,43,36,55,37,247,60,87,16,35,34,202,229,101,17,106,232,5,19,232,115,113,56,20,119,206,57,44,156,0,0,89,139,150,45,56,184,1,4,225,194,187,60, +132,235,162,40,9,119,2,27,130,4,235,53,167,166,240,57,155,6,95,0,64,201,0,0,251,114,229,13,2,217,245,59,143,156,12,57,144,45,11,33,226,44,116,53,150,254,134,34,59,1,98,56,38,3,148,8,217,57,0,0,50,51,107,50,213,204,28,10,106,222,229,62,28,52,226,0,49,224,248,11,220,151,78,30,198,78,2,16,187,95,231,46,132,31,0,0,46,213,232,20,140,162,16,21,37,58,220,54,80,139,51,47,194,240,237,57,214,253,9,31,84,194,236,41,242,202,65,27,114,238,0,0,142,169,239,13,43,149,106,51,149,121,194,26,4,26,17,18,114,199,233, +17,230,236,85,32,202,6,205,31,81,66,34,56,19,15,0,0,103,103,40,62,166,221,41,2,220,204,234,44,133,23,156,31,40,219,98,51,158,194,226,15,94,3,197,39,147,93,124,8,213,173,0,0,107,155,245,41,239,0,135,23,250,226,136,24,240,24,227,44,233,211,38,24,181,116,40,10,55,219,199,30,119,84,105,36,225,221,0,0,16,20,203,38,164,88,182,26,207,254,84,49,249,46,206,21,139,78,225,18,113,88,95,29,10,190,92,39,160,0,222,62,43,91,0,0,153,182,198,9,247,87,49,26,27,135,70,62,90,205,213,27,168,130,22,52,94,254,94,27,161, +165,247,54,96,187,75,0,171,95,0,0,170,195,198,1,75,133,204,5,155,81,131,40,250,95,196,42,144,123,47,22,195,68,208,46,158,78,20,61,240,40,156,62,155,45,0,0,79,210,52,26,183,140,141,56,1,116,19,26,50,60,182,45,65,229,46,52,179,183,125,7,57,217,105,49,115,241,80,11,164,228,0,0,20,148,186,30,199,196,253,41,19,79,142,13,234,183,187,33,232,76,211,10,238,51,103,50,111,82,115,28,180,197,185,36,159,77,0,0,104,12,234,59,188,66,16,50,181,146,179,55,217,72,192,16,9,175,111,57,52,58,242,38,148,36,58,42,85,56, +141,37,65,62,0,0,182,237,69,26,220,191,237,50,171,161,205,3,140,81,70,40,47,6,147,6,220,248,47,15,55,127,31,50,146,100,103,49,35,1,0,0,215,36,152,19,242,72,215,61,122,137,201,17,13,147,237,45,110,87,11,63,189,152,143,18,237,142,80,23,87,81,61,14,148,141,0,0,159,72,102,19,34,61,1,40,216,99,176,38,12,174,120,46,143,111,239,54,106,76,47,24,202,162,194,38,251,211,28,56,97,50,0,0,222,19,215,24,106,28,32,57,8,98,142,2,221,190,48,24,147,67,69,37,191,168,68,42,212,32,68,37,59,86,49,9,37,183,0,0,233,80,131, +27,150,148,255,27,183,252,165,4,249,155,180,32,4,21,148,22,167,11,70,11,4,81,228,3,138,162,230,44,81,76,0,0,180,44,59,62,79,10,27,51,2,4,33,55,252,214,124,18,48,158,20,33,4,142,219,49,173,25,37,17,91,136,214,23,228,61,0,0,47,176,126,48,176,206,120,24,207,68,112,40,150,57,138,15,130,6,145,60,165,146,42,2,14,197,221,42,23,16,102,33,42,186,0,0,191,229,228,44,189,217,209,8,23,91,0,9,168,161,242,25,155,174,6,9,210,141,243,15,30,124,232,27,86,162,113,60,17,133,0,0,8,156,120,1,19,165,36,63,98,82,54,5,111, +34,30,42,45,35,0,42,26,251,125,55,193,116,72,13,111,228,115,61,223,236,0,0,171,88,50,61,40,154,213,6,195,77,193,43,98,160,144,52,87,89,171,20,184,203,113,40,207,34,2,54,115,160,75,1,90,140,0,0,143,15,45,2,76,33,248,21,222,74,148,13,112,62,186,54,70,194,8,12,65,30,3,42,121,16,218,59,16,237,210,54,17,104,0,0,238,188,145,63,42,168,48,22,65,216,192,32,199,99,199,51,245,55,241,43,85,177,243,24,220,11,86,19,175,183,5,62,247,206,0,0,51,107,150,1,126,106,211,46,198,106,47,23,168,192,146,15,166,95,36,29,0, +231,204,14,70,18,112,8,221,216,32,19,231,103,0,0,25,191,0,3,117,238,92,28,148,164,254,8,170,93,77,45,146,107,43,53,172,182,62,24,65,149,221,11,131,205,251,3,200,30,0,0,253,206,7,1,115,112,115,28,182,7,90,41,216,223,185,17,1,94,191,43,158,98,37,41,243,210,64,19,173,213,77,58,239,174,0,0,249,161,254,18,241,46,95,44,148,43,69,0,35,212,194,63,196,49,101,16,156,173,118,63,188,131,46,31,116,149,2,34,220,166,0,0,233,69,195,59,145,83,112,44,99,126,143,38,223,118,226,30,5,80,188,44,90,132,14,26,56,48,124, +54,112,31,21,42,241,126,0,0,179,201,214,6,252,48,80,35,124,99,101,8,29,58,19,27,140,186,129,36,226,113,138,48,189,146,89,36,144,250,79,42,107,254,0,0,251,189,72,41,62,226,177,48,0,155,46,28,193,111,60,32,217,86,59,1,21,205,6,45,107,43,135,57,20,208,53,6,233,126,0,0,81,81,249,12,204,65,188,8,68,182,196,2,145,27,32,25,185,209,222,8,112,11,35,3,2,251,139,9,191,81,188,56,213,21,0,0,242,236,248,47,48,31,168,32,148,15,140,29,95,238,19,8,187,249,35,16,226,37,132,3,249,199,78,61,87,100,140,11,183,165,0,0, +88,86,106,41,228,66,224,53,67,86,246,30,144,148,44,5,56,190,41,46,158,36,128,31,140,173,71,4,162,149,28,58,192,132,0,0,209,128,27,24,111,202,89,54,34,253,241,52,7,166,134,41,211,94,114,19,25,100,140,31,8,74,44,2,88,48,224,32,89,38,0,0,15,106,220,20,34,215,110,29,83,87,225,47,80,100,208,16,116,194,119,0,139,158,147,9,101,213,49,55,164,198,113,44,214,254,0,0,224,199,111,23,182,92,227,50,156,64,252,35,194,100,53,29,19,35,174,19,147,107,96,36,71,168,240,63,63,172,249,42,226,141,0,0,85,147,226,24,196, +23,226,44,109,216,32,23,206,164,35,7,47,216,185,35,0,129,225,59,252,112,188,60,180,100,118,19,106,42,0,0,114,40,204,53,62,128,79,1,192,118,76,12,153,142,22,36,254,13,249,40,137,7,114,63,96,199,224,39,18,159,238,55,119,134,0,0,191,218,72,33,63,162,126,62,177,142,215,9,77,174,116,43,193,53,231,58,215,8,59,25,151,109,84,39,36,155,192,36,45,228,0,0,97,19,30,1,90,29,203,29,157,235,119,30,6,92,157,28,50,48,133,51,247,175,51,14,139,13,75,24,139,27,139,33,19,100,0,0,190,66,102,54,160,100,109,55,137,168,139, +21,95,28,36,13,206,139,250,13,160,209,43,0,27,249,194,48,25,1,227,29,106,20,0,0,208,239,131,61,32,93,202,2,29,237,229,55,75,199,165,42,10,135,178,20,231,159,96,26,214,173,40,0,213,12,59,56,24,179,0,0,67,84,49,39,224,28,78,54,153,114,134,46,82,245,110,30,61,161,66,33,130,96,38,50,66,255,53,9,152,1,1,27,105,252,0,0,96,137,210,23,45,88,67,18,23,27,189,9,132,33,253,31,72,181,119,22,90,55,135,3,191,43,137,53,14,254,250,9,206,224,0,0,235,180,253,22,112,189,236,6,157,167,230,34,113,94,247,40,143,146,176, +62,138,213,168,21,174,209,42,63,211,127,136,60,74,151,0,0,132,244,246,41,126,15,39,16,72,35,252,63,142,202,21,7,17,237,144,0,11,244,144,7,77,166,60,0,212,84,31,14,82,85,0,0,227,238,90,29,109,43,65,14,55,129,140,37,217,240,18,10,232,197,112,18,154,233,108,8,145,176,152,35,119,210,102,45,170,91,0,0,23,151,246,48,237,107,74,11,216,238,49,61,106,39,119,23,33,247,218,63,135,25,2,40,229,86,232,55,3,95,216,31,87,138,0,0,144,104,114,53,19,121,108,20,88,209,55,8,171,127,9,36,229,14,10,17,254,58,191,12,16, +208,67,28,210,250,233,23,104,251,0,0,58,120,53,56,206,163,186,1,38,155,231,16,186,196,178,41,79,9,186,36,97,182,133,50,105,232,226,37,99,178,200,55,80,215,0,0,138,164,188,40,78,252,146,17,245,98,223,3,58,125,53,45,120,29,247,7,10,71,238,9,171,160,149,41,120,150,253,35,229,93,0,0,205,65,253,18,3,58,229,33,149,170,248,32,19,103,111,57,63,132,60,45,148,240,136,41],"i8",4,t.L+20480); +D([9,83,181,25,13,96,207,14,90,104,0,0,182,99,239,37,19,13,142,55,235,130,177,49,156,5,52,45,90,200,193,15,237,104,255,45,241,250,139,33,181,122,115,9,24,111,0,0,243,85,198,5,61,27,33,11,65,69,249,39,0,153,86,34,60,85,52,51,224,53,129,16,143,185,17,25,100,117,159,31,9,255,0,0,59,63,166,52,183,31,65,45,39,151,143,23,102,192,14,8,131,101,199,54,121,125,69,28,88,107,55,42,216,125,37,46,236,197,0,0,36,80,0,5,26,221,252,20,91,238,11,35,151,123,217,58,139,236,51,18,254,99,1,41,78,55,31,8,94,6,70,9,37,34, +0,0,249,238,128,49,228,161,218,53,118,151,139,34,38,136,4,0,141,18,123,32,106,236,58,43,227,7,95,46,72,135,61,48,80,250,0,0,17,40,79,63,244,53,54,35,179,19,162,23,233,164,12,26,94,138,166,1,138,28,74,51,114,155,186,62,229,136,164,49,132,107,0,0,18,94,218,17,206,56,184,7,151,178,172,28,5,144,130,49,169,182,162,28,232,228,167,12,218,188,49,30,222,16,143,11,80,247,0,0,235,244,133,3,122,113,46,41,199,235,92,50,189,203,180,33,123,4,114,22,15,23,37,28,153,213,175,15,159,117,123,61,87,60,0,0,5,209,183,16, +196,76,210,1,242,201,87,14,229,18,151,50,244,179,85,52,56,137,217,19,58,42,134,37,235,96,62,30,254,18,0,0,96,74,121,31,238,27,43,22,132,11,233,46,117,153,56,59,29,119,203,39,102,134,106,45,134,119,207,43,53,206,104,60,98,32,0,0,5,93,12,30,206,96,135,24,255,218,114,37,42,20,155,3,72,26,75,8,160,64,236,18,140,213,115,52,247,209,196,48,170,118,0,0,62,230,236,17,221,102,152,21,53,238,230,21,192,115,137,4,75,95,98,2,200,32,203,60,190,250,14,7,87,195,187,29,85,239,0,0,134,192,83,60,23,210,155,56,201,174, +161,9,39,13,87,45,198,4,129,40,23,197,48,24,126,200,204,5,151,239,150,63,99,166,0,0,1,98,1,37,202,64,113,26,14,252,148,57,92,41,179,7,153,195,61,2,38,178,64,44,209,245,251,17,200,218,95,38,65,181,0,0,116,133,117,11,181,7,96,43,233,198,249,52,80,162,153,12,216,243,189,34,235,9,132,50,183,37,216,44,129,128,158,20,149,222,0,0,42,35,103,59,243,199,247,45,180,222,162,21,69,65,168,57,186,215,158,22,252,17,114,7,226,228,20,61,36,171,21,56,211,76,0,0,79,71,133,61,175,226,230,29,141,102,52,22,226,138,18,19, +137,234,90,56,17,249,50,55,254,219,173,50,180,25,56,47,166,141,0,0,247,78,123,61,244,113,126,63,165,215,189,29,193,100,49,7,11,241,255,29,28,116,125,55,79,248,79,45,199,188,26,27,252,19,0,0,234,66,208,61,89,9,117,45,6,253,234,24,145,169,137,62,235,190,147,60,140,39,153,53,27,155,163,59,236,243,49,43,41,115,0,0,161,148,92,47,176,63,163,54,10,79,171,31,199,220,37,18,24,238,104,43,62,229,57,33,146,72,241,54,109,80,77,18,114,146,0,0,194,126,6,31,173,76,79,57,32,82,186,27,117,173,34,10,26,66,232,8,246, +173,253,22,26,27,161,33,156,50,116,24,29,218,0,0,241,54,216,26,60,232,126,21,166,72,155,39,116,38,206,41,102,41,30,9,135,133,217,1,156,199,6,19,38,159,86,61,87,129,0,0,219,168,149,58,203,220,97,23,97,111,211,57,17,49,176,15,184,35,23,27,100,26,153,37,158,65,208,61,192,24,105,3,233,227,0,0,249,28,13,27,252,61,91,0,209,211,132,9,243,229,123,44,251,106,231,2,28,67,170,62,0,187,120,1,91,1,240,14,229,251,0,0,20,226,46,17,144,245,171,30,1,84,49,25,229,165,147,10,120,28,192,0,87,127,67,25,139,90,119,61, +184,204,177,63,79,159,0,0,122,243,133,16,137,8,209,59,131,2,136,60,194,164,109,6,151,157,198,53,245,11,154,37,14,230,242,34,99,76,184,56,156,99,0,0,165,160,97,31,20,5,218,34,239,227,20,60,108,248,148,4,75,44,11,4,125,144,130,6,23,27,172,52,68,80,139,24,31,67,0,0,153,248,206,56,249,223,222,26,36,119,101,21,13,129,170,46,65,114,170,35,92,70,153,55,214,246,56,36,234,249,159,12,152,162,0,0,3,133,116,39,85,159,9,43,124,142,50,49,220,145,131,27,14,172,18,10,126,206,187,24,203,134,251,56,57,123,183,46,61, +153,0,0,226,206,176,62,77,216,156,46,73,170,173,56,166,253,30,62,23,26,245,33,30,30,225,61,133,183,238,30,90,161,123,42,33,165,0,0,128,61,210,38,214,137,168,55,120,212,116,36,201,71,244,2,225,192,98,9,228,114,12,37,51,90,234,21,171,129,174,30,241,117,0,0,126,213,13,40,192,22,170,33,9,89,234,52,110,251,254,11,55,146,98,27,198,47,244,49,127,12,168,57,88,133,191,24,122,160,0,0,19,52,173,33,181,109,174,56,74,104,125,50,0,1,112,46,141,122,123,56,114,33,125,37,110,10,74,31,118,132,87,21,120,102,0,0,114, +166,188,62,129,64,32,9,1,102,198,45,78,69,139,51,166,158,223,11,159,100,155,9,37,105,100,15,158,120,143,54,13,81,0,0,99,133,204,6,108,189,2,48,170,30,16,62,255,214,55,9,146,136,54,22,6,246,10,50,218,138,116,39,54,139,141,18,220,235,0,0,250,204,148,35,58,239,197,38,36,249,4,18,146,228,1,49,190,7,79,29,179,121,141,59,177,249,53,45,21,58,81,12,154,101,0,0,19,78,6,13,132,193,206,41,98,224,241,6,17,120,71,12,21,102,65,61,163,99,254,23,33,7,105,48,37,195,191,32,226,168,0,0,12,204,244,17,196,28,223,59,108, +189,214,13,148,143,230,25,139,136,21,37,108,241,252,45,191,154,192,1,110,227,86,13,151,127,0,0,181,121,57,58,194,102,134,10,226,41,232,39,121,227,35,10,186,80,14,36,123,44,252,13,127,50,38,30,107,115,241,1,34,174,0,0,111,250,80,4,154,53,207,35,150,136,79,61,77,223,30,42,252,96,112,45,142,20,73,50,212,26,247,57,1,67,148,63,145,234,0,0,36,168,252,14,64,100,64,16,174,79,22,34,250,19,131,47,224,97,84,24,25,64,80,49,206,89,206,42,92,43,67,59,141,203,0,0,97,115,34,15,22,244,2,5,47,116,49,57,241,247,71, +43,150,196,203,44,232,33,177,5,179,133,140,24,3,221,35,0,165,51,0,0,39,211,203,59,104,211,70,16,233,174,74,30,136,20,130,19,176,214,110,39,95,3,36,37,142,112,54,24,188,98,202,14,197,176,0,0,54,228,123,45,40,241,90,24,241,160,54,6,29,131,136,10,216,175,178,38,109,128,169,61,56,22,234,23,239,7,208,37,42,238,0,0,161,54,184,23,142,237,187,57,125,239,121,54,253,23,144,1,200,38,245,55,57,187,24,34,77,13,146,27,167,204,207,41,107,111,0,0,132,43,131,6,236,203,247,54,52,249,31,14,162,20,67,38,216,192,233, +62,22,144,226,2,219,227,24,60,215,255,133,34,119,220,0,0,222,158,179,30,130,208,184,43,66,45,97,48,181,12,32,2,49,96,67,2,132,159,209,63,188,75,175,34,208,113,159,6,71,125,0,0,126,96,246,43,82,54,111,50,208,143,42,2,71,223,115,37,119,250,134,60,191,199,136,32,123,80,86,40,233,124,198,30,74,0,0,0,193,177,94,22,137,39,181,21,170,197,229,26,243,89,93,51,127,150,240,2,102,12,243,3,7,199,250,51,109,254,88,20,2,240,0,0,224,42,222,45,17,92,159,54,87,30,209,44,53,215,191,29,133,237,175,38,104,151,210,26, +198,244,13,18,15,34,122,42,78,5,0,0,100,44,195,26,79,66,205,51,132,191,228,10,251,128,191,13,14,94,113,7,61,84,58,1,247,160,58,18,123,0,0,5,18,172,0,0,103,168,177,30,235,182,74,32,152,8,63,37,150,78,151,22,237,163,153,4,204,85,218,2,135,241,186,56,12,235,50,47,142,206,0,0,124,73,25,3,122,11,206,11,2,140,80,18,148,126,108,22,93,177,202,19,164,185,149,39,211,114,88,40,104,114,238,20,74,23,0,0,115,250,154,7,176,78,104,15,56,84,152,11,99,135,206,26,100,230,249,7,177,124,85,16,123,101,193,9,255,234,13, +55,201,204,0,0,103,131,75,53,245,28,32,37,254,107,80,61,89,223,109,29,183,93,106,3,97,81,151,42,12,228,38,37,17,185,82,2,90,94,0,0,202,133,206,17,118,106,202,20,68,250,95,30,207,123,170,26,121,122,75,42,92,197,7,36,44,92,224,21,30,105,50,62,138,174,0,0,157,13,177,23,78,94,97,6,175,252,248,17,39,198,75,41,230,45,184,12,196,12,46,51,222,89,232,2,92,110,43,56,212,0,0,0,237,220,64,49,33,1,132,32,62,146,45,14,94,50,38,22,11,247,135,34,12,25,225,11,125,148,64,54,13,6,102,0,184,135,0,0,232,174,156,28,130, +105,4,2,178,11,39,26,108,17,136,11,99,103,166,4,187,107,134,30,111,15,76,55,59,218,132,20,102,3,0,0,17,183,114,55,142,26,123,42,240,167,91,41,76,98,234,50,1,69,148,38,110,160,241,39,148,153,237,61,164,202,202,48,24,31,0,0,92,200,70,20,70,93,254,15,53,6,28,32,57,130,247,13,222,234,198,54,79,17,219,25,160,250,241,56,246,91,65,36,88,14,0,0,46,151,72,33,156,223,177,61,213,173,221,12,160,211,8,36,244,152,24,8,189,46,6,29,236,160,189,39,126,196,23,18,154,227,0,0,89,18,46,2,207,183,98,60,175,98,19,40,1, +105,206,5,147,113,119,7,128,234,215,51,182,242,99,20,188,73,155,4,64,167,0,0,67,95,74,51,144,92,220,61,213,218,214,49,78,157,151,33,23,229,126,60,153,210,197,23,176,241,31,15,101,188,238,63,169,5,0,0,254,241,8,11,143,94,40,34,253,123,8,58,194,185,159,51,215,119,209,2,118,217,21,16,101,74,78,7,101,91,8,46,228,135,0,0,236,226,213,46,38,43,221,23,215,217,134,39,245,246,200,11,110,204,194,56,139,58,254,53,215,236,140,52,152,29,176,14,78,247,0,0,92,209,196,33,154,3,28,42,185,116,14,60,193,239,169,23,16, +68,74,37,4,3,139,48,146,90,154,39,250,143,209,6,234,53,0,0,234,225,63,63,189,110,78,50,237,149,80,6,12,168,206,24,93,24,59,13,93,127,233,35,136,215,44,45,231,70,89,36,33,173,0,0,186,183,117,20,194,127,63,33,216,179,24,9,57,204,121,14,224,219,140,1,212,183,95,57,211,195,133,55,80,6,166,37,147,149,0,0,253,242,36,53,225,175,226,38,94,56,9,7,50,217,79,25,156,132,214,28,46,169,225,0,186,216,29,51,48,34,74,21,126,46,0,0,133,153,214,15,100,119,113,2,234,42,247,29,219,50,39,12,159,20,207,12,239,55,164,61, +136,231,247,50,173,115,157,29,233,10,0,0,3,160,9,20,4,173,35,39,248,175,225,46,94,80,103,46,208,197,84,26,20,184,127,35,155,78,209,8,185,253,92,38,33,145,0,0,144,43,38,25,127,79,6,55,169,41,204,35,127,48,241,8,183,31,93,2,224,93,124,25,155,236,18,22,176,150,138,33,21,43,0,0,87,117,61,8,153,91,102,36,73,154,72,25,62,92,210,20,111,6,73,7,106,75,53,12,122,170,63,35,130,106,79,1,176,46,0,0,64,190,231,40,50,197,229,15,89,238,64,16,36,37,178,52,242,154,118,36,91,88,112,37,238,119,230,46,165,70,187,58,249, +106,0,0,28,126,56,46,9,184,5,41,159,86,89,15,168,153,253,56,69,129,220,7,13,10,169,39,112,150,100,6,64,90,132,10,129,179,0,0,30,128,130,52,131,190,173,9,93,21,212,27,241,226,83,30,64,249,214,56,50,9,173,42,179,238,68,1,17,129,59,26,102,89,0,0,55,12,135,4,60,82,220,17,173,53,53,61,216,114,176,45,141,78,48,49,29,130,229,35,236,241,245,46,238,22,42,40,154,148,0,0,253,25,44,3,159,203,38,19,62,140,2,24,65,58,174,50,74,91,11,23,173,94,52,61,253,98,7,5,212,6,98,52,132,190,0,0,31,40,241,50,77,41,165,29,118, +195,13,37,87,253,105,21,121,148,57,8,12,210,151,57,209,68,9,5,183,204,50,24,249,239,0,0,130,148,198,22,245,215,109,52,123,22,250,50,4,80,173,58,203,136,188,50,43,211,201,21,31,84,238,23,3,83,12,40,103,152,0,0,215,44,121,47,81,132,193,27,145,138,98,21,212,115,145,24,158,99,153,58,198,86,181,36,199,249,52,8,196,142,86,24,46,208,0,0,161,122,85,29,100,231,136,34,151,194,31,16,179,191,100,7,223,171,214,25,2,168,203,31,146,165,21,8,54,80,145,60,102,168,0,0,52,6,67,1,211,238,6,38,183,164,17,6,159,113,218, +58,97,57,225,48,118,233,99,15,121,77,180,34,0,170,125,14,135,181,0,0,81,177,130,29,50,208,68,45,219,162,251,33,85,15,41,40,204,143,154,16,236,84,132,22,100,109,229,1,144,43,148,14,166,210,0,0,5,148,248,28,211,133,80,16,45,165,76,8,189,66,221,3,167,32,130,20,202,98,185,43,101,117,203,63,16,217,190,33,45,232,0,0,160,59,75,46,215,216,103,33,23,31,191,24,124,189,175,10,92,95,36,63,198,60,92,56,239,59,183,63,135,72,65,4,8,65,0,0,149,85,82,23,112,135,165,33,84,69,6,26,89,97,146,13,19,152,132,43,117,184, +150,41,44,143,102,53,191,93,218,60,55,220,0,0,237,141,217,19,226,38,167,24,132,33,160,56,206,160,200,55,219,94,214,49,20,100,138,60,140,140,12,12,91,40,132,40,162,99,0,0,194,207,209,32,83,95,70,6,165,115,120,28,2,168,253,42,31,70,148,45,83,201,12,20,6,253,118,44,255,185,184,16,43,136,0,0,69,84,4,56,66,105,24,42,238,215,232,1,100,220,220,63,128,240,190,23,117,185,184,4,223,163,124,22,39,81,87,32,21,12,0,0,6,162,84,0,85,31,62,5,50,234,140,37,13,57,21,12,186,40,205,35,153,237,240,36,10,93,17,20,186, +142,130,53,48,47,0,0,175,127,133,3,115,142,68,58,1,151,97,41,135,183,242,11,136,127,239,40,32,61,234,30,213,192,169,40,107,226,218,58,87,199,0,0,164,76,88,32,50,108,103,7,16,76,137,1,68,67,76,31,98,27,198,62,34,200,167,13,87,98,243,63,72,243,115,22,58,240,0,0,93,34,89,20,61,97,52,57,16,141,133,24,139,223,189,62,68,162,2,28,70,38,80,23,129,15,13,58,107,171,235,24,128,250,0,0,7,21,206,62,237,248,173,40,195,89,124,0,180,13,219,10,10,92,66,12,9,130,136,55,96,145,6,12,240,21,228,7,167,11,0,0,68,208,240, +22,80,250,231,25,121,26,230,9,36,245,167,46,170,165,224,46,24,62,167,61,226,137,122,37,64,103,241,40,140,101,0,0,45,135,203,55,187,204,71,55,154,232,140,1,241,216,89,40,85,118,211,59,196,137,117,25,241,96,84,34,186,222,77,48,92,174,0,0,109,117,150,54,92,37,107,45,122,65,97,37,21,88,188,26,103,92,48,63,116,13,102,48,228,172,43,31,228,171,210,18,201,49,0,0,120,174,8,30,55,122,17,47,10,7,209,42,185,242,183,43,131,6,22,52,171,102,45,46,244,155,58,40,91,213,18,34,15,248,0,0,115,224,23,22,209,230,219,16, +179,23,147,3,78,111,47,43,107,134,220,15,95,91,226,57,14,137,235,49,81,205,136,31,88,100,0,0,137,101,175,31,122,121,166,32,53,171,174,51,68,142,66,46,133,161,153,2,31,145,117,27,233,42,46,16,218,111,117,51,159,217,0,0,214,61,16,14,200,81,220,55,154,133,4,0,31,48,129,17,195,122,161,18,22,63,79,8,106,131,63,32,144,86,245,30,71,188,0,0,67,195,247,22,99,11,66,14,198,74,180,35,177,92,77,10,93,57,166,30,27,75,21,43,203,38,213,13,106,10,137,7,30,227,0,0,49,171,78,20,195,14,55,52,7,73,99,14,1,197,107,49, +10,232,248,59,153,140,208,14,48,128,131,59,154,150,63,45,157,88,0,0,106,31,54,17,157,175,107,16,185,141,143,20,72,149,67,24,31,243,144,61,146,128,24,28,96,79,42,42,34,4,23,17,85,98,0,0,65,44,12,26,202,133,229,47,103,108,51,32,21,7,199,32,66,124,219,46,181,130,97,40,168,46,250,34,91,244,205,44,57,19,0,0,43,188,241,41,46,21,124,33,65,58,146,30,31,254,137,4,107,64,163,19,68,63,144,12,122,186,229,58,177,216,88,10,155,159,0,0,175,71,252,24,225,199,18,28,195,222,12,44,12,178,127,55,168,104,181,1,64,109, +202,0,197,124,241,60,216,68,232,46,243,127,0,0,167,67,186,57,51,89,24,62,151,194,186,24,180,198,78,41,23,107,68,51,209,109,36,50,11,154,98,10,6,160,235,41,107,31,0,0,117,55,33,21,2,88,19,6,144,169,66,61,200,78,10,45,0,97,127,44,127,229,164,7,20,182,11,54,58,143,17,28,198,142,0,0,255,255,65,56,249,60,4,56,144,30,245,12,47,40,166,54,113,14,238,45,115,5,13,25,110,48,190,37,54,232,155,41,88,143,0,0,187,171,82,52,52,254,207,50,227,194,149,43,248,203,169,26,174,149,212,21,182,255,176,46,157,184,27,48,121, +16,109,24,222,131,0,0,110,182,78,5,172,93,20,40,24,41,228,60,174,205,23,39,215,99,21,14,49,190,218,62,107,250,9,6,211,40,205,56,240,50,0,0,241,118,146,53,155,48,162,37,94,177,23,42,164,108,137,43,51,104,216,60,61,0,215,46,168,177,29,12,212,99,226,24,118,61,0,0,179,188,156,5,110,153,146,7,96,120,25,27,6,8,102,8,243,62,51,24,107,211,184,29,9,182,221,7,134,222,92,26,118,211,0,0,88,228,69,29,27,178,53,22,211,127,14,37,168,179,169,2,47,4,222,9,149,79,27,21,58,91,136,13,57,57,120,47,129,132,0,0,126,5,121, +23,214,198,146,53,86,229,98,50,10,113,158,2,144,202,178,44,115,206,111,9,74,216,77,0,149,46,227,30,238,56,0,0,125,161,45,21,144,62,40,24,177,70,6,13,194,246,4,55,17,200,11,32,127,193,154,19,137,240,197,24,212,131,71,59,234,59,0,0,210,104,199,44,23,38,193,57,108,65,236,31,227,222,121,51,84,181,225,0,250,250,162,18,239,223,172,55,191,86,253,53,176,195,0,0,197,220,78,58,246,133,62,13,114,27,49,32,80,136,140,19,231,151,89,39,228,0,127,11,117,24,214,9,247,50,232,54,115,110,0,0,228,160,157,21,55,223,199, +44,55,144,103,0,156,246,157,34,39,147,134,2,34,34,84,17,234,139,196,44,123,18,127,48,10,238,0,0,121,185,128,10,9,49,113,2,20,179,171,41,140,126,61,36,4,16,195,7,169,250,101,31,98,39,89,27,249,77,98,55,6,119,0,0,222,207,38,1,65,32,61,19,33,227,239,23,63,141,130,62,23,113,156,42,71,230,117,35,119,71,113,59,86,159,96,42,2,138,0,0,133,226,111,50,45,113,110,51,125,18,239,19,80,10,235,22,164,106,224,57,7,233,241,60,210,128,15,60,166,100,177,8,212,22,0,0,65,180,85,1,155,255,131,15,35,212,100,51,77,4,195, +15,233,177,49,53,152,166,249,45,138,26,100,34,120,148,62,34,248,13,0,0,19,165,207,58,42,47,196,56,234,58,14,38,230,231,1,9,78,156,106,53,67,29,209,40,165,58,214,54,177,251,145,3,204,31,0,0,156,252,122,16,144,110,29,20,135,145,131,9,89,116,123,59,75,180,249,57,12,213,225,56,72,139,71,53,120,16,104,48,93,22,0,0,178,105,220,62,243,193,137,6,114,113,183,38,108,34,152,2,165,134,163,10,215,16,12,25,48,23,138,11,91,235,28,36,43,193,0,0,221,65,221,32,192,166,171,12,0,42,123,18,143,111,135,59,184,118,73,9, +126,34,183,28,151,29,223,12,77,249,15,49,115,49,0,0,77,254,97,57,119,97,189,45,122,25,7,49,226,27,34,5,138,62,167,44,196,196,164,15,63,250,168,39,12,119,225,47,89,208,0,0,194,35,232,42,25,108,77,38,203,100,171,13,125,232,34,14,253,180,85,9,33,119,217,1,254,227,37,53,34,48,152,30,16,69,0,0,107,102,175,44,253,192,88,51,11,227,28,11,241,180,63,63,127,99,244,23,160,107,94,26,43,166,42,16,224,233,149,18,70,19,0,0,39,204,110,63,65,106,37,61,19,46,148,16,7,42,192,60,72,202,176,12,79,209,12,57,247,14,88, +20,24,1,100,5,190,105,0,0,81,95,202,14,38,200,90,8,191,174,201,15,229,198,133,58,221,207,181,5,252,202,90,59,198,98,105,46,103,55,69,53,233,221,0,0,247,56,198,16,207,105,90,43,249,113,149,40,55,250,186,63,80,9,143,63,41,44,205,7,137,29,17,40,56,207,68,26,78,184,0,0,228,136,156,25,22,172,65,62,194,110,212,10,136,79,84,59,154,23,75,32,196,186,1,61,233,54,55,25,218,8,132,24,26,253,0,0,223,200,91,25,89,36,35,39,41,15,192,28,37,117,220,26,220,130,119,23,82,165,1,15,177,191,32,12,114,46,213,30,201,26,0, +0,206,24,128,31,109,109,69,53,139,214,146,24,227,92,105,11,207,199,109,8,203,147,243,63,19,159,107,41,48,118,76,33,228,78,0,0,31,56,72,30,108,152,214,48,19,96,128,14,109,92,210,1,113,230,197,7,67,35,16,45,199,95,139,63,66,32,181,39,143,182,0,0,120,54,71,49,71,186,20,10,112,47,57,20,66,229,21,40,203,112,192,56,86,49,197,56,245,191,13,0,49,13,39,51,118,253,0,0,79,79,20,13,170,59,89,56,55,132,28,0,133,187,163,24,96,214,44,3,244,156,130,59,15,174,61,20,28,222,80,25,4,242,0,0,147,33,122,13,82,220,2,60, +237,70,117,25,60,145,71,26,44,33,234,52,210,9,58,27,158,33,64,59,72,204,232,42,162,133,0,0,58,207,205,48,82,15,50,60,39,36,177,3,231,183,182,49,225,159,2,12,71,11,130,49,130,109,81,48,202,250,21,38,18,156,0,0,176,104,117,55,108,193,192,22,83,176,3,30,6,116,163,43,53,15,101,3,94,177,181,45,64,68,231,63,243,28,255,54,93,210,0,0,156,146,57,31,155,228,132,2,6,240,195,35,7,226,156,8,131,43,217,39,55,211,189,43,190,56,137,4,254,100,221,63,58,122,0,0,19,124,29,39,98,68,249,23,133,163,255,32,254,125,173, +6,100,5,200,42,94,106,250,1,95,37,167,20,250,80,76,13,129,69,0,0,207,99,255,58,84,241,226,24,153,107,217,43,80,149,1,8,112,201,105,29,223,197,67,61,87,139,173,57,37,5,59,22,88,159,0,0,102,243,131,45,52,232,104,43,140,88,40,47,120,59,115,54,12,122,201,29,48,47,12,61,174,233,226,63,196,109,125,39,74,188,0,0,193,51,31,24,153,89,99,29,109,177,71,37,254,126,42,58,166,202,152,55,210,183,222,36,131,99,192,5,158,155,114,32,58,13,0,0,60,190,18,55,203,184,168,1,107,166,70,33,182,99,124,37,114,52,21,0,172,110, +151,28,60,141,55,27,204,100,39,13,215,57,0,0,92,246,111,28,208,103,192,48,76,100,65,10,123,233,189,23,239,232,18,40,25,83,213,9,177,127,191,51,187,213,211,38,146,143,0,0,43,242,119,31,243,62,185,42,53,224,130,15,101,142,92,38,198,38,175,21,166,176,53,7,229,9,221,1,247,253,133,41,203,240,0,0,60,160,9,25,29,139,35,63,97,86,9,10,164,31,99,60,4,64,208,22,148,13,155,12,239,137,249,29,254,196,208,42,37,26,0,0,18,156,80,6,83,115,179,34,101,71,31,61,214,136,255,26,141,237,104,50,97,163,195,5,29,50,77,21, +200,118,174,30,29,56,0,0,2,97,180,46,56,170,144,17,117,175,110,14,27,22,10,22,32,231,129,37,233,92,145,52,181,158,218,35,246,223,214,42,122,164,0,0,85,233,79,56,88,211,206,54,72,206,59,6,104,169,85,38,246,83,138,12,165,249,220,14,121,100,126,56,234,25,21,60,3,167,0,0,189,68,19,22,239,187,172,9,250,119,114,25,113,138,133,39,83,155,25,25,172,181,228,41,14,220,122,4,172,104,77,62,0,213,0,0,88,206,234,6,176,149,101,18,211,17,50,47,232,88,145,31,27,63,160,19,193,53,180,26,108,116,13,21,181,106,241,44, +198,115,0,0,78,101,248,42,92,164,194,5,23,41,141,59,110,227,161,26,170,198,145,45,217,68,38,36,186,65,247,36,206,28,41,45,47,58,0,0,94,29,24,0,252,34,206,18,5,242,170,21,110,234,108,28,222,184,221,14,112,232,52,0,29,218,127,20,27,212,249,60,39,198,0,0,109,136,159,54,152,2,228,9,57,44,190,28,82,1,172,61,142,214,247,33,226,4,88,26,45,59,166,2,145,199,117,39,143,215,0,0,22,139,130,55,126,54,138,19,243,71,72,10,202,99,229,17,160,83,222,6,188,41,208,23,162,63,35,61,183,131,175,62,136,187,0,0,247,93,234, +10,136,206,81,20,156,150,30,58,56,93,160,18,236,99,145,21,4,88,22,55,69,211,141,30,61,193,172,29,54,183,0,0,170,76,50,37,63,204,42,21,57,42,71,41,194,120,217,18,105,46,163,18,81,210,49,54,35,13,188,24,10,254,94,42,40,140,0,0,130,148,239,11,207,113,199,57,89,148,203,17,17,60,225,57,122,235,192,60,125,204,183,63,120,51,25,5,204,232,24,1,163,64,0,0,64,221,84,7,85,28,250,24,248,108,70,3,127,140,137,16,162,233,246,50,53,127,16,18,91,244,252,13,176,12,28,9,41,151,0,0,67,97,163,42,188,36,45,33,147,244,202, +26,149,20,186,54,144,54,223,20,47,119,29,23,209,220,161,62,151,9,145,40,209,145,0,0,255,167,44,12,174,11,182,48,163,33,240,29,101,23,217,0,24,175,39,47,104,181,70,30,80,224,150,39,2,214,229,31,99,137,0,0,104,62,73,48,133,87,80,59,123,171,46,36,227,168,241,30,248,137,116,53,80,197,115,46,87,77,66,8,34,35,73,56,31,45,0,0,127,221,168,12,232,88,27,6,166,129,19,42,213,0,202,49,27,66,87,19,245,128,118,50,253,146,224,37,248,198,57,14,129,48,0,0,242,199,146,10,30,201,87,16,94,145,173,52,144,145,149,5,200, +24,142,0,69,23,177,39,227,37,201,15,10,162,180,56,209,40,0,0,177,63,106,6,162,21,115,3,108,32,46,25,6,74,2,48,110,47,134,54,22,50,212,21,30,93,182,30,155,10,58,49,95,87,0,0,173,85,38,16,42,164,227,38,240,242,58,42,241,92,237,12,237,218,135,14,94,10,111,7,103,45,202,47,169,16,228,54,110,111,0,0,223,23,1,57,145,162,218,6,146,2,1,34,243,238,78,9,218,143,42,42,123,224,155,60,39,162,183,42,147,173,13,36,236,165,0,0,254,98,100,56,207,4,74,32,61,54,74,33,21,124,24,33,28,247,160,31,180,14,230,37,197,0,4, +20,176,151,152,49,157,183,0,0,18,215,42,23,112,93,62,44,144,114,4,33,55,44,99,14,90,185,73,35,81,216,229,57,157,148,176,16,204,68,250,55,83,161,0,0,210,253,72,13,78,217,151,34,156,50,11,47,22,202,79,1,189,154,184,49,199,87,99,12,72,252,178,5,236,79,16,54,148,253,0,0,58,91,207,17,4,220,48,12,16,120,90,27,239,160,206,16,196,36,200,45,35,66,211,48,53,89,97,20,222,171,177,6,84,154,0,0,228,74,164,54,124,93,213,15,214,82,234,33,148,184,63,18,85,95,71,15,162,205,107,56,175,124,171,6,196,114,48,18,97,182, +0,0,224,202,172,31,68,232,18,35,116,51,187,36,22,67,205,34,60,210,31,7,60,57,83,54,29,140,122,18,229,132,153,37,234,8,0,0,69,185,98,14,140,210,188,22,149,142,15,15,167,239,224,45,53,215,197,21,238,51,240,57,36,46,120,34,59,242,174,62,14,98,0,0,94,111,160,38,101,45,144,6,2,55,8,42,91,148,100,16,163,22,183,35,73,8,53,44,55,172,83,2,133,250,62,9,59,56,0,0,114,231,198,19,27,30,125,34,64,176,194,56,46,157,171,61,232,25,90,42,83,181,89,61,76,4,162,27,59,177,26,28,207,84,0,0,54,161,56,6,117,112,93,30,92, +25,56,40,205,56,71,3,43,12,121,13,216,26,103,57,137,215,214,46,128,15,180,12,132,230,0,0,132,37,108,12,66,96,244,43,106,51,87,51,246,250,120,2,46,71,230,1,232,192,156,10,77,98,166,53,56,230,4,57,91,202,0,0,12,193,232,22,16,241,161,51,7,104,189,17,206,23,166,28,180,127,110,48,156,179,247,62,238,160,194,37,191,120,86,53,93,57,0,0,142,99,254,5,76,182,245,48,203,34,105,6,55,1,39,36,76,39,78,58,191,30,250,4,4,93,172,18,22,45,53,55,98,253,0,0,239,20,108,13,200,54,153,5,245,200,147,47,65,29,63,22,8,128, +100,34,187,111,181,59,246,185,220,37,84,13,183,18,81,122,0,0,19,189,63,11,28,134,79,43,247,36,110,42,202,189,171,47,41,55,92,15,50,229,194,31,137,142,77,46,84,180,127,52,237,86,0,0,235,101,109,15,65,143,81,42,36,21,2,4,213,29,68,38,90,35,143,16,210,239,188,35,234,216,144,29,201,16,86,63,225,30,0,0,28,148,34,29,73,174,13,56,17,43,88,35,97,58,189,12,202,250,252,2,61,241,231,42,207,193,115,44,117,111,36,10,105,187,0,0,68,203,54,14,188,67,101,60,145,1,162,28,35,219,162,31,97,125,53,3,98,67,63,22,192, +139,170,58,227,52,141,21,81,21,0,0,104,90,73,31,148,209,107,10,83,30,12,2,124,93,220,48,168,93,32,35,209,194,143,3,55,94,33,53,85,213,241,63,79,171,0,0,204,186,39,52,65,24,229,7,21,46,214,18,55,89,204,28,158,170,196,13,86,194,58,22,99,19,32,53,175,17,25,47,198,59,0,0,166,253,214,42,87,255,12,19,113,180,190,40,72,105,221,6,215,43,192,22,155,136,187,24,219,92,48,44,93,28,48,23,48,142,0,0,103,230,9,106,133,174,103,187,114,243,110,60,58,245,79,165,127,82,14,81,140,104,5,155,171,217,131,31,25,205,224, +91,152,47,138,66,145,68,55,113,207,251,192,181,165,219,181,233,91,194,86,57,241,17,241,89,164,130,63,146,213,94,28,171,152,170,7,216,1,91,131,18,190,133,49,36,195,125,12,85,116,93,190,114,254,177,222,128,167,6,220,155,116,241,155,193,193,105,155,228,134,71,190,239,198,157,193,15,204,161,12,36,111,44,233,45,170,132,116,74,220,169,176,92,218,136,249,118,82,81,62,152,109,198,49,168,200,39,3,176,199,127,89,191,243,11,224,198,71,145,167,213,81,99,202,6,103,41,41,20,133,10,183,39,56,33,27,46,252,109,44, +77,19,13,56,83,84,115,10,101,187,10,106,118,46,201,194,129,133,44,114,146,161,232,191,162,75,102,26,168,112,139,75,194,163,81,108,199,25,232,146,209,36,6,153,214,133,53,14,244,112,160,106,16,22,193,164,25,8,108,55,30,76,119,72,39,181,188,176,52,179,12,28,57,74,170,216,78,79,202,156,91,243,111,46,104,238,130,143,116,111,99,165,120,20,120,200,132,8,2,199,140,250,255,190,144,235,108,80,164,247,163,249,190,242,120,113,198,5,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0, +2,0,0,0,244,153,0,0,0,4,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,196,148,0,0,99,111,110,100,32,61,61,32,49,32,124,124,32,99,111,110,100,32,61,61,32,48,0,46,46,47,98,105,103,110,117,109,46,99,0,98,110,95,99,109,111,118,0,99,111,101,102,32,60,32,48,120,56,48,48,48,48,48,48,48,117,0,98,110,95,109,117,108,116,105,112,108,121,95,114,101,100,117,99,101,95,115,116,101,112,0,114,101,115,91,105,32,43,32,49,93,32,61, +61,32,48,0,98,110,95,109,117,108,116,105,112,108,121,95,114,101,100,117,99,101,0,111,100,100,45,62,97,91,48,93,32,38,32,49,0,98,110,95,105,110,118,101,114,115,101,0,111,100,100,45,62,97,91,56,93,32,38,32,49,0,101,118,101,110,45,62,97,91,48,93,32,38,32,49,0,40,101,118,101,110,45,62,97,91,56,93,32,38,32,49,41,32,61,61,32,48,0,40,101,118,101,110,45,62,97,91,48,93,32,38,32,49,41,32,61,61,32,48,0,112,112,91,48,93,32,38,32,49,0,40,116,101,109,112,32,38,32,48,120,102,102,102,102,102,102,102,102,41,32,61, +61,32,48,0,40,40,117,115,46,97,91,56,93,32,43,32,112,112,91,48,93,32,42,32,102,97,99,116,111,114,41,32,38,32,109,97,115,107,41,32,61,61,32,48,0,98,32,60,61,32,112,114,105,109,101,45,62,118,97,108,91,48,93,0,98,110,95,115,117,98,105,0,97,45,62,118,97,108,91,56,93,32,60,32,48,120,50,48,48,48,48,0,46,46,47,101,99,100,115,97,46,99,0,99,111,110,100,105,116,105,111,110,97,108,95,110,101,103,97,116,101,0,45,51,32,60,61,32,97,32,38,38,32,97,32,60,61,32,48,0,112,111,105,110,116,95,106,97,99,111,98,105,97, +110,95,97,100,100,0,98,110,95,105,115,95,108,101,115,115,40,107,44,32,38,99,117,114,118,101,45,62,111,114,100,101,114,41,0,40,97,46,118,97,108,91,48,93,32,38,32,49,41,32,33,61,32,48,0,115,99,97,108,97,114,95,109,117,108,116,105,112,108,121,0,49,50,51,52,53,54,55,56,57,65,66,67,68,69,70,71,72,74,75,76,77,78,80,81,82,83,84,85,86,87,88,89,90,97,98,99,100,101,102,103,104,105,106,107,109,110,111,112,113,114,115,116,117,118,119,120,121,122,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,47,100,101,118,47,117,114,97,110,100,111,109,0,114,0,108,101,110,95,114,101,97,100,32,61,61,32,108,101,110,0,46,46,47,114,97,110,100,46,99,0,114,97,110,100,111,109,51,50,0,114,119,97,0],"i8",4,t.L+30720);var cb=v;v+=16;e._i64Subtract=db;e._memset=eb;function fb(a,b){J.push(function(){t.t("vi",a,[b])});fb.level=J.length}e._bitshift64Lshr=gb;e._bitshift64Shl=hb; +var K={s:1,m:2,Jc:3,Gb:4,p:5,la:6,Za:7,dc:8,J:9,nb:10,ha:11,Tc:11,Ea:12,R:13,zb:14,pc:15,S:16,ia:17,Uc:18,U:19,ja:20,B:21,g:22,Zb:23,Da:24,C:25,Qc:26,Ab:27,lc:28,K:29,Gc:30,Sb:31,zc:32,wb:33,Dc:34,hc:42,Db:43,ob:44,Jb:45,Kb:46,Lb:47,Rb:48,Rc:49,bc:50,Ib:51,tb:35,ec:37,fb:52,ib:53,Vc:54,$b:55,jb:56,kb:57,ub:35,lb:59,nc:60,cc:61,Nc:62,mc:63,ic:64,jc:65,Fc:66,fc:67,bb:68,Kc:69,pb:70,Ac:71,Ub:72,xb:73,hb:74,uc:76,gb:77,Ec:78,Mb:79,Nb:80,Qb:81,Pb:82,Ob:83,oc:38,ka:39,Vb:36,T:40,vc:95,yc:96,sb:104,ac:105, +cb:97,Cc:91,sc:88,kc:92,Hc:108,rb:111,$a:98,qb:103,Yb:101,Wb:100,Oc:110,Bb:112,Cb:113,Fb:115,eb:114,vb:89,Tb:90,Bc:93,Ic:94,ab:99,Xb:102,Hb:106,qc:107,Pc:109,Sc:87,yb:122,Lc:116,tc:95,gc:123,Eb:84,wc:75,mb:125,rc:131,xc:130,Mc:86},ib={0:"Success",1:"Not super-user",2:"No such file or directory",3:"No such process",4:"Interrupted system call",5:"I/O error",6:"No such device or address",7:"Arg list too long",8:"Exec format error",9:"Bad file number",10:"No children",11:"No more processes",12:"Not enough core", +13:"Permission denied",14:"Bad address",15:"Block device required",16:"Mount device busy",17:"File exists",18:"Cross-device link",19:"No such device",20:"Not a directory",21:"Is a directory",22:"Invalid argument",23:"Too many open files in system",24:"Too many open files",25:"Not a typewriter",26:"Text file busy",27:"File too large",28:"No space left on device",29:"Illegal seek",30:"Read only file system",31:"Too many links",32:"Broken pipe",33:"Math arg out of domain of func",34:"Math result not representable", +35:"File locking deadlock error",36:"File or path name too long",37:"No record locks available",38:"Function not implemented",39:"Directory not empty",40:"Too many symbolic links",42:"No message of desired type",43:"Identifier removed",44:"Channel number out of range",45:"Level 2 not synchronized",46:"Level 3 halted",47:"Level 3 reset",48:"Link number out of range",49:"Protocol driver not attached",50:"No CSI structure available",51:"Level 2 halted",52:"Invalid exchange",53:"Invalid request descriptor", +54:"Exchange full",55:"No anode",56:"Invalid request code",57:"Invalid slot",59:"Bad font file fmt",60:"Device not a stream",61:"No data (for no delay io)",62:"Timer expired",63:"Out of streams resources",64:"Machine is not on the network",65:"Package not installed",66:"The object is remote",67:"The link has been severed",68:"Advertise error",69:"Srmount error",70:"Communication error on send",71:"Protocol error",72:"Multihop attempted",73:"Cross mount point (not really error)",74:"Trying to read unreadable message", +75:"Value too large for defined data type",76:"Given log. name not unique",77:"f.d. invalid for this operation",78:"Remote address changed",79:"Can access a needed shared lib",80:"Accessing a corrupted shared lib",81:".lib section in a.out corrupted",82:"Attempting to link in too many libs",83:"Attempting to exec a shared library",84:"Illegal byte sequence",86:"Streams pipe error",87:"Too many users",88:"Socket operation on non-socket",89:"Destination address required",90:"Message too long",91:"Protocol wrong type for socket", +92:"Protocol not available",93:"Unknown protocol",94:"Socket type not supported",95:"Not supported",96:"Protocol family not supported",97:"Address family not supported by protocol family",98:"Address already in use",99:"Address not available",100:"Network interface is not configured",101:"Network is unreachable",102:"Connection reset by network",103:"Connection aborted",104:"Connection reset by peer",105:"No buffer space available",106:"Socket is already connected",107:"Socket is not connected",108:"Can't send after socket shutdown", +109:"Too many references",110:"Connection timed out",111:"Connection refused",112:"Host is down",113:"Host is unreachable",114:"Socket already connected",115:"Connection already in progress",116:"Stale file handle",122:"Quota exceeded",123:"No medium (in tape drive)",125:"Operation canceled",130:"Previous owner died",131:"State not recoverable"};function jb(a){e.___errno_location&&(w[e.___errno_location()>>2]=a);return a} +function kb(a,b){for(var c=0,d=a.length-1;0<=d;d--){var f=a[d];"."===f?a.splice(d,1):".."===f?(a.splice(d,1),c++):c&&(a.splice(d,1),c--)}if(b)for(;c--;c)a.unshift("..");return a}function lb(a){var b="/"===a.charAt(0),c="/"===a.substr(-1);(a=kb(a.split("/").filter(function(a){return!!a}),!b).join("/"))||b||(a=".");a&&c&&(a+="/");return(b?"/":"")+a} +function mb(a){var b=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/.exec(a).slice(1);a=b[0];b=b[1];if(!a&&!b)return".";b&&(b=b.substr(0,b.length-1));return a+b}function nb(a){if("/"===a)return"/";var b=a.lastIndexOf("/");return-1===b?a:a.substr(b+1)}function ob(){var a=Array.prototype.slice.call(arguments,0);return lb(a.join("/"))}function L(a,b){return lb(a+"/"+b)} +function qb(){for(var a="",b=!1,c=arguments.length-1;-1<=c&&!b;c--){b=0<=c?arguments[c]:"/";if("string"!==typeof b)throw new TypeError("Arguments to path.resolve must be strings");if(!b)return"";a=b+"/"+a;b="/"===b.charAt(0)}a=kb(a.split("/").filter(function(a){return!!a}),!b).join("/");return(b?"/":"")+a||"."}var rb=[];function sb(a,b){rb[a]={input:[],output:[],v:b};tb(a,ub)} +var ub={open:function(a){var b=rb[a.c.rdev];if(!b)throw new M(K.U);a.tty=b;a.seekable=!1},close:function(a){a.tty.v.flush(a.tty)},flush:function(a){a.tty.v.flush(a.tty)},read:function(a,b,c,d){if(!a.tty||!a.tty.v.wa)throw new M(K.la);for(var f=0,g=0;ga.b.length&&(a.b=N.La(a),a.f=a.b.length);if(!a.b||a.b.subarray){var c=a.b?a.b.buffer.byteLength:0;c>=b||(b=Math.max(b,c*(1048576>c?2:1.125)|0),0!=c&&(b=Math.max(b,256)),c=a.b,a.b=new Uint8Array(b),0b)a.b.length=b;else for(;a.b.length=a.c.f)return 0;a=Math.min(a.c.f-f,d);assert(0<=a);if(8b)throw new M(K.g);return b},na:function(a,b,c){N.ra(a.c,b+c);a.c.f=Math.max(a.c.f,b+c)},Aa:function(a, +b,c,d,f,g,h){if(32768!==(a.c.mode&61440))throw new M(K.U);c=a.c.b;if(h&2||c.buffer!==b&&c.buffer!==b.buffer){if(0>1)}catch(c){if(!c.code)throw c;throw new M(K[c.code]);}return b.mode},j:function(a){for(var b=[];a.parent!==a;)b.push(a.name),a=a.parent;b.push(a.i.aa.root);b.reverse();return ob.apply(null,b)},sa:{0:"r",1:"r+",2:"r+",64:"r",65:"r+",66:"r+",129:"rx+",193:"rx+",514:"w+",577:"w", +578:"w+",705:"wx",706:"wx+",1024:"a",1025:"a",1026:"a+",1089:"a",1090:"a+",1153:"ax",1154:"ax+",1217:"ax",1218:"ax+",4096:"rs",4098:"rs+"},Ka:function(a){a&=-2099201;a&=-32769;a&=-524289;if(a in Q.sa)return Q.sa[a];throw new M(K.g);},d:{l:function(a){a=Q.j(a);var b;try{b=fs.lstatSync(a)}catch(c){if(!c.code)throw c;throw new M(K[c.code]);}Q.O&&!b.q&&(b.q=4096);Q.O&&!b.blocks&&(b.blocks=(b.size+b.q-1)/b.q|0);return{dev:b.dev,ino:b.ino,mode:b.mode,nlink:b.nlink,uid:b.uid,gid:b.gid,rdev:b.rdev,size:b.size, +atime:b.atime,mtime:b.mtime,ctime:b.ctime,q:b.q,blocks:b.blocks}},h:function(a,b){var c=Q.j(a);try{void 0!==b.mode&&(fs.chmodSync(c,b.mode),a.mode=b.mode),void 0!==b.size&&fs.truncateSync(c,b.size)}catch(d){if(!d.code)throw d;throw new M(K[d.code]);}},lookup:function(a,b){var c=L(Q.j(a),b),c=Q.ua(c);return Q.createNode(a,b,c)},F:function(a,b,c,d){a=Q.createNode(a,b,c,d);b=Q.j(a);try{P(a.mode)?fs.mkdirSync(b,a.mode):fs.writeFileSync(b,"",{mode:a.mode})}catch(f){if(!f.code)throw f;throw new M(K[f.code]); +}return a},rename:function(a,b,c){a=Q.j(a);b=L(Q.j(b),c);try{fs.renameSync(a,b)}catch(d){if(!d.code)throw d;throw new M(K[d.code]);}},unlink:function(a,b){var c=L(Q.j(a),b);try{fs.unlinkSync(c)}catch(d){if(!d.code)throw d;throw new M(K[d.code]);}},rmdir:function(a,b){var c=L(Q.j(a),b);try{fs.rmdirSync(c)}catch(d){if(!d.code)throw d;throw new M(K[d.code]);}},readdir:function(a){a=Q.j(a);try{return fs.readdirSync(a)}catch(b){if(!b.code)throw b;throw new M(K[b.code]);}},symlink:function(a,b,c){a=L(Q.j(a), +b);try{fs.symlinkSync(c,a)}catch(d){if(!d.code)throw d;throw new M(K[d.code]);}},readlink:function(a){var b=Q.j(a);try{return b=fs.readlinkSync(b),b=Bb.relative(Bb.resolve(a.i.aa.root),b)}catch(c){if(!c.code)throw c;throw new M(K[c.code]);}}},e:{open:function(a){var b=Q.j(a.c);try{32768===(a.c.mode&61440)&&(a.H=fs.openSync(b,Q.Ka(a.flags)))}catch(c){if(!c.code)throw c;throw new M(K[c.code]);}},close:function(a){try{32768===(a.c.mode&61440)&&a.H&&fs.closeSync(a.H)}catch(b){if(!b.code)throw b;throw new M(K[b.code]); +}},read:function(a,b,c,d,f){if(0===d)return 0;var g=new Buffer(d),h;try{h=fs.readSync(a.H,g,0,d,f)}catch(n){throw new M(K[n.code]);}if(0b)throw new M(K.g);return b}}};v+=16; +v+=16;v+=16;var Cb=null,Db=[null],Eb=[],Fb=1,R=null,Gb=!0,S={},M=null,zb={}; +function T(a,b){a=qb("/",a);b=b||{};if(!a)return{path:"",c:null};var c={ta:!0,ea:0},d;for(d in c)void 0===b[d]&&(b[d]=c[d]);if(8>>0)%R.length}function Jb(a){var b=Ib(a.parent.id,a.name);a.u=R[b];R[b]=a}function Ab(a,b){var c;if(c=(c=Kb(a,"x"))?c:a.d.lookup?0:K.R)throw new M(c,a);for(c=R[Ib(a.id,b)];c;c=c.u){var d=c.name;if(c.parent.id===a.id&&d===b)return c}return a.d.lookup(a,b)} +function yb(a,b,c,d){Lb||(Lb=function(a,b,c,d){a||(a=this);this.parent=a;this.i=a.i;this.G=null;this.id=Fb++;this.name=b;this.mode=c;this.d={};this.e={};this.rdev=d},Lb.prototype={},Object.defineProperties(Lb.prototype,{read:{get:function(){return 365===(this.mode&365)},set:function(a){a?this.mode|=365:this.mode&=-366}},write:{get:function(){return 146===(this.mode&146)},set:function(a){a?this.mode|=146:this.mode&=-147}},Qa:{get:function(){return P(this.mode)}},Pa:{get:function(){return 8192===(this.mode& +61440)}}}));a=new Lb(a,b,c,d);Jb(a);return a}function P(a){return 16384===(a&61440)}var Mb={r:0,rs:1052672,"r+":2,w:577,wx:705,xw:705,"w+":578,"wx+":706,"xw+":706,a:1089,ax:1217,xa:1217,"a+":1090,"ax+":1218,"xa+":1218};function Nb(a){var b=["r","w","rw"][a&3];a&512&&(b+="w");return b}function Kb(a,b){if(Gb)return 0;if(-1===b.indexOf("r")||a.mode&292){if(-1!==b.indexOf("w")&&!(a.mode&146)||-1!==b.indexOf("x")&&!(a.mode&73))return K.R}else return K.R;return 0} +function Ob(a,b){try{return Ab(a,b),K.ia}catch(c){}return Kb(a,"wx")}function Pb(a){var b;b=4096;for(a=a||0;a<=b;a++)if(!Eb[a])return a;throw new M(K.Da);} +function Qb(a,b){Rb||(Rb=function(){},Rb.prototype={},Object.defineProperties(Rb.prototype,{object:{get:function(){return this.c},set:function(a){this.c=a}},od:{get:function(){return 1!==(this.flags&2097155)}},pd:{get:function(){return 0!==(this.flags&2097155)}},nd:{get:function(){return this.flags&1024}}}));var c=new Rb,d;for(d in a)c[d]=a[d];a=c;c=Pb(b);a.fd=c;return Eb[c]=a}var xb={open:function(a){a.e=Db[a.c.rdev].e;a.e.open&&a.e.open(a)},o:function(){throw new M(K.K);}}; +function tb(a,b){Db[a]={e:b}}function Sb(a,b){var c="/"===b,d=!b,f;if(c&&Cb)throw new M(K.S);if(!c&&!d){f=T(b,{ta:!1});b=f.path;f=f.c;if(f.G)throw new M(K.S);if(!P(f.mode))throw new M(K.ja);}var d={type:a,aa:{},Ba:b,Ra:[]},g=a.i(d);g.i=d;d.root=g;c?Cb=g:f&&(f.G=d,f.i&&f.i.Ra.push(d))}function Tb(a,b,c){var d=T(a,{parent:!0}).c;a=nb(a);if(!a||"."===a||".."===a)throw new M(K.g);var f=Ob(d,a);if(f)throw new M(f);if(!d.d.F)throw new M(K.s);return d.d.F(d,a,b,c)} +function Ub(a,b){b=(void 0!==b?b:438)&4095;b|=32768;return Tb(a,b,0)}function V(a,b){b=(void 0!==b?b:511)&1023;b|=16384;return Tb(a,b,0)}function Vb(a,b,c){"undefined"===typeof c&&(c=b,b=438);return Tb(a,b|8192,c)}function Wb(a,b){if(!qb(a))throw new M(K.m);var c=T(b,{parent:!0}).c;if(!c)throw new M(K.m);var d=nb(b),f=Ob(c,d);if(f)throw new M(f);if(!c.d.symlink)throw new M(K.s);return c.d.symlink(c,d,a)} +function Hb(a){a=T(a).c;if(!a)throw new M(K.m);if(!a.d.readlink)throw new M(K.g);return qb(U(a.parent),a.d.readlink(a))}function Xb(a,b){var c;"string"===typeof a?c=T(a,{X:!0}).c:c=a;if(!c.d.h)throw new M(K.s);c.d.h(c,{mode:b&4095|c.mode&-4096,timestamp:Date.now()})} +function Yb(a,b,c,d){if(""===a)throw new M(K.m);if("string"===typeof b){var f=Mb[b];if("undefined"===typeof f)throw Error("Unknown file open mode: "+b);b=f}c=b&64?("undefined"===typeof c?438:c)&4095|32768:0;var g;if("object"===typeof a)g=a;else{a=lb(a);try{g=T(a,{X:!(b&131072)}).c}catch(h){}}f=!1;if(b&64)if(g){if(b&128)throw new M(K.ia);}else g=Tb(a,c,0),f=!0;if(!g)throw new M(K.m);8192===(g.mode&61440)&&(b&=-513);if(b&65536&&!P(g.mode))throw new M(K.ja);if(!f&&(c=g?40960===(g.mode&61440)?K.T:P(g.mode)&& +("r"!==Nb(b)||b&512)?K.B:Kb(g,Nb(b)):K.m))throw new M(c);if(b&512){c=g;var n;"string"===typeof c?n=T(c,{X:!0}).c:n=c;if(!n.d.h)throw new M(K.s);if(P(n.mode))throw new M(K.B);if(32768!==(n.mode&61440))throw new M(K.g);if(c=Kb(n,"w"))throw new M(c);n.d.h(n,{size:0,timestamp:Date.now()})}b&=-641;d=Qb({c:g,path:U(g),flags:b,seekable:!0,position:0,e:g.e,Ya:[],error:!1},d);d.e.open&&d.e.open(d);!e.logReadFiles||b&1||(Zb||(Zb={}),a in Zb||(Zb[a]=1,e.printErr("read file: "+a)));try{S.onOpenFile&&(g=0,1!== +(b&2097155)&&(g|=1),0!==(b&2097155)&&(g|=2),S.onOpenFile(a,g))}catch(u){console.log("FS.trackingDelegate['onOpenFile']('"+a+"', flags) threw an exception: "+u.message)}return d}function $b(a){a.Z&&(a.Z=null);try{a.e.close&&a.e.close(a)}catch(b){throw b;}finally{Eb[a.fd]=null}}function ac(a,b,c){if(!a.seekable||!a.e.o)throw new M(K.K);a.position=a.e.o(a,b,c);a.Ya=[]} +function bc(a,b,c,d,f,g){if(0>d||0>f)throw new M(K.g);if(0===(a.flags&2097155))throw new M(K.J);if(P(a.c.mode))throw new M(K.B);if(!a.e.write)throw new M(K.g);a.flags&1024&&ac(a,0,2);var h=!0;if("undefined"===typeof f)f=a.position,h=!1;else if(!a.seekable)throw new M(K.K);b=a.e.write(a,b,c,d,f,g);h||(a.position+=b);try{if(a.path&&S.onWriteToFile)S.onWriteToFile(a.path)}catch(n){console.log("FS.trackingDelegate['onWriteToFile']('"+path+"') threw an exception: "+n.message)}return b} +function cc(){M||(M=function(a,b){this.c=b;this.Va=function(a){this.n=a;for(var b in K)if(K[b]===a){this.code=b;break}};this.Va(a);this.message=ib[a]},M.prototype=Error(),M.prototype.constructor=M,[K.m].forEach(function(a){zb[a]=new M(a);zb[a].stack=""}))}var dc;function ec(a,b){var c=0;a&&(c|=365);b&&(c|=146);return c}function fc(a,b,c,d){a=L("string"===typeof a?a:U(a),b);return Ub(a,ec(c,d))} +function gc(a,b,c,d,f,g){a=b?L("string"===typeof a?a:U(a),b):a;d=ec(d,f);f=Ub(a,d);if(c){if("string"===typeof c){a=Array(c.length);b=0;for(var h=c.length;b>2]}function jc(){var a;a=Y();a=Eb[a];if(!a)throw new M(K.J);return a}e.___muldsi3=kc;e.___muldi3=lc;e._i64Add=mc;e._sbrk=nc;function oc(){oc.D||(oc.D=[]);oc.D.push(t.Q());return oc.D.length-1}e._llvm_bswap_i32=pc;e._memcpy=qc;e._pthread_self=rc;cc();R=Array(4096);Sb(N,"/");V("/tmp");V("/home");V("/home/web_user"); +(function(){V("/dev");tb(259,{read:function(){return 0},write:function(a,b,f,g){return g}});Vb("/dev/null",259);sb(1280,vb);sb(1536,wb);Vb("/dev/tty",1280);Vb("/dev/tty1",1536);var a;if("undefined"!==typeof crypto){var b=new Uint8Array(1);a=function(){crypto.getRandomValues(b);return b[0]}}else a=m?function(){return require("crypto").randomBytes(1)[0]}:function(){return 256*Math.random()|0};W("/dev","random",a);W("/dev","urandom",a);V("/dev/shm");V("/dev/shm/tmp")})();V("/proc");V("/proc/self");V("/proc/self/fd"); +Sb({i:function(){var a=yb("/proc/self","fd",16895,73);a.d={lookup:function(a,c){var d=Eb[+c];if(!d)throw new M(K.J);var f={parent:null,i:{Ba:"fake"},d:{readlink:function(){return d.path}}};return f.parent=f}};return a}},"/proc/self/fd"); +Sa.unshift(function(){if(!e.noFSInit&&!dc){assert(!dc,"FS.init was previously called. If you want to initialize later with custom parameters, remove any earlier calls (note that one is automatically added to the generated code)");dc=!0;cc();e.stdin=e.stdin;e.stdout=e.stdout;e.stderr=e.stderr;e.stdin?W("/dev","stdin",e.stdin):Wb("/dev/tty","/dev/stdin");e.stdout?W("/dev","stdout",null,e.stdout):Wb("/dev/tty","/dev/stdout");e.stderr?W("/dev","stderr",null,e.stderr):Wb("/dev/tty1","/dev/stderr");var a= +Yb("/dev/stdin","r");assert(0===a.fd,"invalid handle for stdin ("+a.fd+")");a=Yb("/dev/stdout","w");assert(1===a.fd,"invalid handle for stdout ("+a.fd+")");a=Yb("/dev/stderr","w");assert(2===a.fd,"invalid handle for stderr ("+a.fd+")")}});Ta.push(function(){Gb=!1});J.push(function(){dc=!1;var a=e._fflush;a&&a(0);for(a=0;athis.length-1||0>a)){var b=a%this.chunkSize;return this.ya(a/this.chunkSize|0)[b]}};n.prototype.Ua=function(a){this.ya=a};n.prototype.oa=function(){var a=new XMLHttpRequest;a.open("HEAD",c,!1);a.send(null);if(!(200<=a.status&&300>a.status||304===a.status))throw Error("Couldn't load "+c+". Status: "+a.status);var b=Number(a.getResponseHeader("Content-length")),d,f=(d=a.getResponseHeader("Accept-Ranges"))&& +"bytes"===d,a=(d=a.getResponseHeader("Content-Encoding"))&&"gzip"===d,g=1048576;f||(g=b);var h=this;h.Ua(function(a){var d=a*g,f=(a+1)*g-1,f=Math.min(f,b-1);if("undefined"===typeof h.M[a]){var n=h.M;if(d>f)throw Error("invalid range ("+d+", "+f+") or no bytes requested!");if(f>b-1)throw Error("only "+b+" bytes available! programmer error!");var q=new XMLHttpRequest;q.open("GET",c,!1);b!==g&&q.setRequestHeader("Range","bytes="+d+"-"+f);"undefined"!=typeof Uint8Array&&(q.responseType="arraybuffer"); +q.overrideMimeType&&q.overrideMimeType("text/plain; charset=x-user-defined");q.send(null);if(!(200<=q.status&&300>q.status||304===q.status))throw Error("Couldn't load "+c+". Status: "+q.status);d=void 0!==q.response?new Uint8Array(q.response||[]):Xa(q.responseText||"",!0);n[a]=d}if("undefined"===typeof h.M[a])throw Error("doXHR failed!");return h.M[a]});if(a||!b)g=b=1,g=b=this.ya(0).length,console.log("LazyFiles on gzip forces download of the whole file when length is accessed");this.Ga=b;this.Fa= +g;this.$=!0};if("undefined"!==typeof XMLHttpRequest){if(!l)throw"Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc";g=new n;Object.defineProperties(g,{length:{get:function(){this.$||this.oa();return this.Ga}},chunkSize:{get:function(){this.$||this.oa();return this.Fa}}});h=void 0}else h=c,g=void 0;var u=fc(a,b,d,f);g?u.b=g:h&&(u.b=null,u.url=h);Object.defineProperties(u,{f:{get:function(){return this.b.length}}});var r={};Object.keys(u.e).forEach(function(a){var b= +u.e[a];r[a]=function(){if(!hc(u))throw new M(K.p);return b.apply(null,arguments)}});r.read=function(a,b,c,d,f){if(!hc(u))throw new M(K.p);a=a.c.b;if(f>=a.length)return 0;d=Math.min(a.length-f,d);assert(0<=d);if(a.slice)for(var g=0;g>2]=Oa;ya=!0;e.Ia={Math:Math,Int8Array:Int8Array,Int16Array:Int16Array,Int32Array:Int32Array,Uint8Array:Uint8Array,Uint16Array:Uint16Array,Uint32Array:Uint32Array,Float32Array:Float32Array,Float64Array:Float64Array,NaN:NaN,Infinity:Infinity}; +e.Ja={abort:z,assert:assert,enlargeMemory:function(){ia()},getTotalMemory:function(){return ha},abortOnCannotGrowMemory:ia,invoke_ii:function(a,b){try{return e.dynCall_ii(a,b)}catch(c){if("number"!==typeof c&&"longjmp"!==c)throw c;Z.setThrew(1,0)}},invoke_iiii:function(a,b,c,d){try{return e.dynCall_iiii(a,b,c,d)}catch(f){if("number"!==typeof f&&"longjmp"!==f)throw f;Z.setThrew(1,0)}},invoke_vi:function(a,b){try{e.dynCall_vi(a,b)}catch(c){if("number"!==typeof c&&"longjmp"!==c)throw c;Z.setThrew(1, +0)}},_pthread_cleanup_pop:function(){assert(fb.level==J.length,"cannot pop if something else added meanwhile!");J.pop();fb.level=J.length},___syscall221:function(a,b){X=b;try{var c=jc();switch(Y()){case 0:var d=Y();return 0>d?-K.g:Yb(c.path,c.flags,0,d).fd;case 1:case 2:return 0;case 3:return c.flags;case 4:return d=Y(),c.flags|=d,0;case 12:case 12:return d=Y(),qa[d+0>>1]=2,0;case 13:case 14:case 13:case 14:return 0;case 16:case 8:return-K.g;case 9:return jb(K.g),-1;default:return-K.g}}catch(f){return"undefined"!== +typeof ic&&f instanceof M||z(f),-f.n}},___syscall54:function(a,b){X=b;try{var c=jc(),d=Y();switch(d){case 21505:return c.tty?0:-K.C;case 21506:return c.tty?0:-K.C;case 21519:if(!c.tty)return-K.C;var f=Y();return w[f>>2]=0;case 21520:return c.tty?-K.g:-K.C;case 21531:f=Y();if(!c.e.Oa)throw new M(K.C);return c.e.Oa(c,d,f);default:z("bad ioctl syscall "+d)}}catch(g){return"undefined"!==typeof ic&&g instanceof M||z(g),-g.n}},___lock:function(){},_abort:function(){e.abort()},_pthread_cleanup_push:fb,___syscall6:function(a, +b){X=b;try{var c=jc();$b(c);return 0}catch(d){return"undefined"!==typeof ic&&d instanceof M||z(d),-d.n}},_llvm_stacksave:oc,___syscall140:function(a,b){X=b;try{var c=jc(),d=Y(),f=Y(),g=Y(),h=Y();assert(0===d);ac(c,f,h);w[g>>2]=c.position;c.Z&&0===f&&0===h&&(c.Z=null);return 0}catch(n){return"undefined"!==typeof ic&&n instanceof M||z(n),-n.n}},___syscall5:function(a,b){X=b;try{var c=B(Y()),d=Y(),f=Y();return Yb(c,d,f).fd}catch(g){return"undefined"!==typeof ic&&g instanceof M||z(g),-g.n}},_emscripten_memcpy_big:function(a, +b,c){F.set(F.subarray(b,b+c),a);return a},_llvm_bswap_i64:function(a,b){var c=pc(b)>>>0,d=pc(a)>>>0;return(Z.setTempRet0(d),c)|0},___unlock:function(){},_llvm_stackrestore:function(a){var b=oc.D[a];oc.D.splice(a,1);t.I(b)},___assert_fail:function(a,b,c,d){ja=!0;throw"Assertion failed: "+B(a)+", at: "+[b?B(b):"unknown filename",c,d?B(d):"unknown function"]+" at "+Ha();},___syscall145:function(a,b){X=b;try{var c=jc(),d=Y(),f;a:{for(var g=Y(),h=0,n=0;n>2],r,q=c,y=w[d+8*n>>2], +H=u,A=void 0,I=C;if(0>H||0>A)throw new M(K.g);if(1===(q.flags&2097155))throw new M(K.J);if(P(q.c.mode))throw new M(K.B);if(!q.e.read)throw new M(K.g);var O=!0;if("undefined"===typeof A)A=q.position,O=!1;else if(!q.seekable)throw new M(K.K);var pb=q.e.read(q,I,y,H,A);O||(q.position+=pb);r=pb;if(0>r){f=-1;break a}h+=r;if(r>2],w[d+(8*n+4)>>2],void 0);if(0>u){f=-1;break a}h+=u}f=h}return f}catch(r){return"undefined"!==typeof ic&&r instanceof M||z(r),-r.n}},___setErrNo:jb,STACKTOP:p,STACK_MAX:Ma,DYNAMICTOP_PTR:x,tempDoublePtr:cb,ABORT:ja};// EMSCRIPTEN_START_ASM +var Z=(function(global,env,buffer) { +"use asm";var a=new global.Int8Array(buffer);var b=new global.Int16Array(buffer);var c=new global.Int32Array(buffer);var d=new global.Uint8Array(buffer);var e=new global.Uint16Array(buffer);var f=new global.Uint32Array(buffer);var g=new global.Float32Array(buffer);var h=new global.Float64Array(buffer);var i=env.STACKTOP|0;var j=env.STACK_MAX|0;var k=env.DYNAMICTOP_PTR|0;var l=env.tempDoublePtr|0;var m=env.ABORT|0;var n=0;var o=0;var p=0;var q=0;var r=global.NaN,s=global.Infinity;var t=0,u=0,v=0,w=0,x=0.0,y=0,z=0,A=0,B=0.0;var C=0;var D=global.Math.floor;var E=global.Math.abs;var F=global.Math.sqrt;var G=global.Math.pow;var H=global.Math.cos;var I=global.Math.sin;var J=global.Math.tan;var K=global.Math.acos;var L=global.Math.asin;var M=global.Math.atan;var N=global.Math.atan2;var O=global.Math.exp;var P=global.Math.log;var Q=global.Math.ceil;var R=global.Math.imul;var S=global.Math.min;var T=global.Math.max;var U=global.Math.clz32;var V=env.abort;var W=env.assert;var X=env.enlargeMemory;var Y=env.getTotalMemory;var Z=env.abortOnCannotGrowMemory;var _=env.invoke_ii;var $=env.invoke_iiii;var aa=env.invoke_vi;var ba=env._pthread_cleanup_pop;var ca=env.___syscall221;var da=env.___syscall54;var ea=env.___lock;var fa=env._abort;var ga=env._pthread_cleanup_push;var ha=env.___syscall6;var ia=env._llvm_stacksave;var ja=env.___syscall140;var ka=env.___syscall5;var la=env._emscripten_memcpy_big;var ma=env._llvm_bswap_i64;var na=env.___unlock;var oa=env._llvm_stackrestore;var pa=env.___assert_fail;var qa=env.___syscall145;var ra=env.___syscall146;var sa=env.___setErrNo;var ta=0.0; +// EMSCRIPTEN_START_FUNCS +function xa(a){a=a|0;var b=0;b=i;i=i+a|0;i=i+15&-16;return b|0}function ya(){return i|0}function za(a){a=a|0;i=a}function Aa(a,b){a=a|0;b=b|0;i=a;j=b}function Ba(a,b){a=a|0;b=b|0;if(!n){n=a;o=b}}function Ca(a){a=a|0;C=a}function Da(){return C|0}function Ea(b,c){b=b|0;c=c|0;a[b>>0]=c>>>24;a[b+1>>0]=c>>>16;a[b+2>>0]=c>>>8;a[b+3>>0]=c;return}function Fa(a,b){a=a|0;b=b|0;var e=0,f=0,g=0,h=0;e=0;f=0;do{h=a+(7-f<<2)|0;h=(d[h+1>>0]|0)<<16|(d[h>>0]|0)<<24|(d[h+2>>0]|0)<<8|(d[h+3>>0]|0);g=f<<1;c[b+(f<<2)>>2]=(h<>>(30-g|0);f=f+1|0}while((f|0)!=8);c[b+32>>2]=e;return}function Ga(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0;e=c[b+32>>2]<<16;f=0;while(1){g=c[b+(7-f<<2)>>2]|0;h=f<<1;i=g>>>(14-h|0)|e;e=d+(f<<2)|0;a[e>>0]=i>>>24;a[e+1>>0]=i>>>16;a[e+2>>0]=i>>>8;a[e+3>>0]=i;f=f+1|0;if((f|0)==8)break;else e=g<>2]=0;a=a+4|0}while((a|0)<(b|0));return}function Ia(a){a=a|0;return (c[a+32>>2]|(c[a+28>>2]|(c[a+24>>2]|(c[a+20>>2]|(c[a+16>>2]|(c[a+12>>2]|(c[a+8>>2]|(c[a+4>>2]|c[a>>2])))))))|0)==0|0}function Ja(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0;d=0;e=8;f=0;while(1){h=c[a+(e<<2)>>2]|0;g=c[b+(e<<2)>>2]|0;d=h>>>0>>0|d<<1;f=h>>>0>g>>>0|f<<1;if((e|0)<=0)break;else e=e+-1|0}return d>>>0>f>>>0|0}function Ka(a,b){a=a|0;b=b|0;var d=0,e=0;d=0;e=0;do{e=c[b+(d<<2)>>2]^c[a+(d<<2)>>2]|e;d=d+1|0}while((d|0)!=9);return (e|0)==0|0}function La(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0;g=0-b|0;h=b+-1|0;if((b|1|0)==1)f=0;else pa(38200,38223,270,38235);do{c[a+(f<<2)>>2]=c[e+(f<<2)>>2]&h|c[d+(f<<2)>>2]&g;f=f+1|0}while((f|0)!=9);return}function Ma(a){a=a|0;var b=0,d=0,e=0,f=0;b=8;d=c[a+32>>2]|0;do{e=b;b=b+-1|0;f=d;d=c[a+(b<<2)>>2]|0;c[a+(e<<2)>>2]=d>>>29&1|f<<1&1073741822}while((e|0)>1);c[a>>2]=c[a>>2]<<1&1073741822;return}function Na(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,i=0;d=c[a>>2]|0;f=0-(d&1)|0;d=((c[b>>2]&f)+d|0)>>>1;e=0;do{i=e;e=e+1|0;g=(c[b+(e<<2)>>2]&f)+(c[a+(e<<2)>>2]|0)|0;h=(g<<29&536870912)+d|0;c[a+(i<<2)>>2]=h&1073741823;d=(h>>>30)+(g>>>1)|0}while((e|0)!=8);c[a+32>>2]=d;return}function Oa(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0;e=b&255;b=0;do{f=a+(b<<2)|0;c[f>>2]=R(c[f>>2]|0,e)|0;b=b+1|0}while((b|0)!=9);Pa(a,d);return}function Pa(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0;g=(c[a+32>>2]|0)>>>16;i=c[a>>2]|0;h=mc(c[b>>2]|0,0,g|0,0)|0;d=C;e=hc(i|0,536870912,h|0,d|0)|0;f=C;d=hc(i|0,0,h|0,d|0)|0;c[a>>2]=d&1073741823;d=1;while(1){l=jc(e|0,f|0,30)|0;k=C;i=a+(d<<2)|0;j=c[i>>2]|0;f=mc(c[b+(d<<2)>>2]|0,0,g|0,0)|0;h=C;k=nc(l|0,k|0,-2147483648,536870911)|0;j=nc(k|0,C|0,j|0,0)|0;e=hc(j|0,C|0,f|0,h|0)|0;c[i>>2]=e&1073741823;d=d+1|0;if((d|0)==9)break;else f=C}return}function Qa(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0;h=i;i=i+48|0;g=h;d=0;e=8;f=0;while(1){k=c[a+(e<<2)>>2]|0;j=c[b+(e<<2)>>2]|0;d=k>>>0>>0|d<<1;f=k>>>0>j>>>0|f<<1;if((e|0)<=0)break;else e=e+-1|0}f=d>>>0>f>>>0;e=0;d=1;while(1){d=d+1073741823+(c[a+(e<<2)>>2]|0)-(c[b+(e<<2)>>2]|0)|0;c[g+(e<<2)>>2]=d&1073741823;e=e+1|0;if((e|0)==9)break;else d=d>>>30}La(a,f&1,a,g);i=h;return}function Ra(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0;f=0;e=1;while(1){e=e+1073741823+(c[a+(f<<2)>>2]|0)-(c[b+(f<<2)>>2]|0)|0;c[d+(f<<2)>>2]=e&1073741823;f=f+1|0;if((f|0)==9)break;else e=e>>>30}return}function Sa(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0,j=0;h=0;g=0;e=0;i=1;while(1){f=0;do{j=mc(c[b+(h-f<<2)>>2]|0,0,c[a+(f<<2)>>2]|0,0)|0;g=nc(j|0,C|0,g|0,e|0)|0;e=C;f=f+1|0}while((f|0)!=(i|0));c[d+(h<<2)>>2]=g&1073741823;g=jc(g|0,e|0,30)|0;e=C;h=h+1|0;if((h|0)==9){h=9;break}else i=i+1|0}while(1){f=h+-8|0;if((f|0)<9)do{j=mc(c[b+(h-f<<2)>>2]|0,0,c[a+(f<<2)>>2]|0,0)|0;g=nc(j|0,C|0,g|0,e|0)|0;e=C;f=f+1|0}while((f|0)!=9);c[d+(h<<2)>>2]=g&1073741823;g=jc(g|0,e|0,30)|0;h=h+1|0;if((h|0)==17)break;else e=C}c[d+68>>2]=g;return}function Ta(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0;l=a+(d+1<<2)|0;j=(c[l>>2]<<14)+((c[a+(d<<2)>>2]|0)>>>16)|0;k=d+-8|0;e=a+(k<<2)|0;f=c[e>>2]|0;g=mc(c[b>>2]|0,0,j|0,0)|0;h=C;if((j|0)<=-1)pa(38243,38223,390,38262);i=hc(f|0,536870912,g|0,h|0)|0;m=C;h=hc(f|0,0,g|0,h|0)|0;c[e>>2]=h&1073741823;h=jc(i|0,m|0,30)|0;m=C;i=a+(d+-7<<2)|0;f=nc(c[i>>2]|0,0,-2147483648,536870911)|0;e=1;g=C;d=m;do{m=mc(c[b+(e<<2)>>2]|0,0,j|0,0)|0;m=hc(f|0,g|0,m|0,C|0)|0;m=nc(m|0,C|0,h|0,d|0)|0;c[i>>2]=m&1073741823;e=e+1|0;h=jc(m|0,C|0,30)|0;d=C;i=a+(e+k<<2)|0;f=nc(c[i>>2]|0,0,-2147483648,536870911)|0;g=C}while((e|0)!=9);m=nc(f|0,g|0,h|0,d|0)|0;c[l>>2]=m&1073741823;return}function Ua(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0;e=16;while(1){Ta(b,d,e);if(c[b+(e+1<<2)>>2]|0){g=4;break}e=e+-1|0;if((e|0)<=7){f=0;break}}if((g|0)==4)pa(38286,38223,424,38302);do{c[a+(f<<2)>>2]=c[b+(f<<2)>>2];f=f+1|0}while((f|0)!=9);return}function Va(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0;g=i;i=i+80|0;e=g;f=e;h=f+72|0;do{c[f>>2]=0;f=f+4|0}while((f|0)<(h|0));Sa(a,b,e);Ua(b,e,d);i=g;return}function Wa(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0;n=i;i=i+144|0;k=n+72|0;l=n+36|0;m=n;c[l>>2]=1;h=l+4|0;c[h>>2]=0;c[h+4>>2]=0;c[h+8>>2]=0;c[h+12>>2]=0;c[h+16>>2]=0;c[h+20>>2]=0;c[h+24>>2]=0;c[h+28>>2]=0;h=m;d=b;j=h+36|0;do{c[h>>2]=c[d>>2];h=h+4|0;d=d+4|0}while((h|0)<(j|0));e=0;d=1;while(1){j=m+(e<<2)|0;d=(c[j>>2]|0)+d|0;c[j>>2]=d&1073741823;e=e+1|0;if((e|0)==9)break;else d=d>>>30}d=0;e=c[m>>2]|0;do{j=d;d=d+1|0;h=e;e=c[m+(d<<2)>>2]|0;c[m+(j<<2)>>2]=e<<29&536870912|h>>>1}while((d|0)!=8);e=m+32|0;c[e>>2]=(c[e>>2]|0)>>>1;d=0;f=c[m>>2]|0;do{j=d;d=d+1|0;h=f;f=c[m+(d<<2)>>2]|0;c[m+(j<<2)>>2]=f<<29&536870912|h>>>1}while((d|0)!=8);c[e>>2]=(c[e>>2]|0)>>>1;e=0;do{g=(e|0)==8;d=0;f=c[m+(e<<2)>>2]|0;do{if(g&(f|0)==0)break;if(f&1|0){h=k;j=h+72|0;do{c[h>>2]=0;h=h+4|0}while((h|0)<(j|0));Sa(a,l,k);Ua(l,k,b)}f=f>>>1;h=k;j=h+72|0;do{c[h>>2]=0;h=h+4|0}while((h|0)<(j|0));Sa(a,a,k);Ua(a,k,b);d=d+1|0}while(d>>>0<30);e=e+1|0}while((e|0)!=9);Qa(l,b);h=a;d=l;j=h+36|0;do{c[h>>2]=c[d>>2];h=h+4|0;d=d+4|0}while((h|0)<(j|0));i=n;return}function Xa(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0;v=i;i=i+112|0;d=v+72|0;u=v+32|0;t=v;Pa(a,b);Qa(a,b);e=c[b>>2]|0;f=0;while(1){r=f;f=f+1|0;g=c[b+(f<<2)>>2]|0;h=r<<1;p=g<<30-h|e;c[t+(r<<2)>>2]=p;c[d+(r<<2)>>2]=p;if((f|0)==8)break;else e=g>>>(h+2|0)}e=c[a>>2]|0;f=0;while(1){r=f;f=f+1|0;b=c[a+(f<<2)>>2]|0;g=r<<1;c[u+(r<<2)>>2]=b<<30-g|e;if((f|0)==8)break;else e=b>>>(g+2|0)}o=d+36|0;c[o>>2]=8;p=u+36|0;c[p>>2]=8;r=d+32|0;c[r>>2]=1;c[u+32>>2]=0;f=0;n=u;e=8;g=c[d>>2]|0;b=1;a:while(1){if(!(g&1)){q=7;break}if(!(b&1)){q=10;break}l=n+36|0;b=e;while(1){e=b+-1|0;if(c[n+(e<<2)>>2]|0)break;c[l>>2]=e;if((b|0)<1)break a;else b=e}e=c[n>>2]|0;if(!e){g=n+32|0;do{e=0;do{m=e;e=e+1|0;c[n+(m<<2)>>2]=c[n+(e<<2)>>2]}while((e|0)!=8);c[g>>2]=0;b=(c[l>>2]|0)+-1|0;c[l>>2]=b;f=f+32|0;e=c[n>>2]|0}while((e|0)==0)}k=0;while(1)if(!(e&1<0){e=e>>>k;if((b|0)>1){j=32-k|0;g=1;h=n;while(1){b=n+(g<<2)|0;c[h>>2]=c[b>>2]<>2]|0)>>>k;if((e|0)<(c[l>>2]|0)){g=e;e=h;h=b}else break}}else{g=0;h=e;b=n;e=1}c[b>>2]=h;if(!h)c[l>>2]=(c[l>>2]|0)+-1;else g=e;e=n+(g<<2)|0;b=c[e>>2]<>2]=(c[e>>2]|0)>>>h|b;b=c[e>>2]<>2]=b;m=k+f|0}else m=f;if(!(c[n>>2]&1)){q=32;break}if(c[n+32>>2]&1|0){q=34;break}f=c[o>>2]|0;e=f-(c[p>>2]|0)|0;if(!e){e=f;while(1){b=e+-1|0;if((e|0)<=0){q=38;break}e=c[d+(b<<2)>>2]|0;f=u+(b<<2)|0;if((e|0)==(c[f>>2]|0))e=b;else break}if((q|0)==38){q=0;if(!e){q=56;break}f=u+(b<<2)|0;e=c[d+(b<<2)>>2]|0}e=e>>>0>(c[f>>2]|0)>>>0?1:-1}n=(e|0)>0;l=n?u:d;n=n?d:u;k=l+36|0;h=c[k>>2]|0;if((h|0)>0){e=0;f=1;b=0;while(1){j=n+(e<<2)|0;w=c[j>>2]|0;g=c[l+(e<<2)>>2]|0;f=nc(f|0,b|0,-1,0)|0;f=nc(f|0,C|0,w|0,0)|0;g=hc(f|0,C|0,g|0,0)|0;f=C;c[j>>2]=g;e=e+1|0;if((e|0)<(h|0))b=0;else{b=e;g=0;break}}}else{b=0;f=1;g=0}j=n+36|0;e=c[j>>2]|0;if((b|0)<(e|0)){e=g;while(1){w=n+(b<<2)|0;g=c[w>>2]|0;e=nc(f|0,e|0,-1,0)|0;e=nc(e|0,C|0,g|0,0)|0;c[w>>2]=e;b=b+1|0;e=c[j>>2]|0;if((b|0)>=(e|0))break;else{f=C;e=0}}}if((e|0)>8){f=8;g=0;b=0}else{f=8;g=0;b=0;while(1){w=l+(f<<2)|0;j=c[n+(f<<2)>>2]|0;h=nc(c[w>>2]|0,0,g|0,b|0)|0;j=nc(h|0,C|0,j|0,0)|0;g=C;c[w>>2]=j;w=f;f=f+-1|0;if((w|0)<=(e|0))break;else b=0}h=c[k>>2]|0;b=0}if((f|0)>=(h|0))while(1){w=l+(f<<2)|0;j=nc(c[w>>2]|0,0,g|0,b|0)|0;c[w>>2]=j;if((f|0)>(c[k>>2]|0)){f=f+-1|0;g=C;b=0}else break}g=c[l>>2]|0;if(!(g&1)){q=51;break}b=c[l+32>>2]|0;if(!(b&1)){q=53;break}if(c[n>>2]&1|0){q=55;break}else f=m}if((q|0)==7)pa(38321,38223,619,38335);else if((q|0)==10)pa(38346,38223,620,38335);else if((q|0)==32)pa(38360,38223,672,38335);else if((q|0)==34)pa(38375,38223,673,38335);else if((q|0)==51)pa(38321,38223,730,38335);else if((q|0)==53)pa(38346,38223,731,38335);else if((q|0)==55)pa(38397,38223,732,38335);else if((q|0)==56){l=c[t>>2]|0;if(!(l&1))pa(38419,38223,759,38335);f=l+-1|0;e=l+-2|0;if(!f)k=e;else{do{f=R(f,f)|0;e=R(f+1|0,e)|0}while((f|0)!=0);k=e}b:do if((m|0)>31){j=d+4|0;e=m;while(1){w=c[r>>2]|0;b=R(w,k)|0;q=mc(l|0,0,b|0,0)|0;w=nc(q|0,C|0,w|0,0)|0;if(!((w|0)==0&0==0))break;f=0;g=C;h=0;while(1){w=f;f=f+1|0;o=c[d+(7-w<<2)>>2]|0;p=mc(c[t+(f<<2)>>2]|0,0,b|0,0)|0;q=C;o=nc(o|0,0,g|0,h|0)|0;q=nc(o|0,C|0,p|0,q|0)|0;g=C;c[d+(8-w<<2)>>2]=q;if((f|0)==7)break;else h=0}c[j>>2]=g;e=e+-32|0;if((e|0)<=31){s=e;break b}}pa(38429,38223,775,38335)}else s=m;while(0);if((s|0)>0){w=(1<>2]|0;h=(R(e,k)|0)&w;if((R(h,l)|0)+e&w|0)pa(38454,38223,794,38335);b=mc(h|0,0,l|0,0)|0;b=nc(b|0,C|0,e|0,0)|0;b=jc(b|0,C|0,s|0)|0;f=32-s|0;e=0;g=C;while(1){w=e;e=e+1|0;s=c[d+(7-w<<2)>>2]|0;r=mc(c[t+(e<<2)>>2]|0,0,h|0,0)|0;s=nc(r|0,C|0,s|0,0)|0;s=kc(s|0,C|0,f|0)|0;s=nc(s|0,C|0,b|0,g|0)|0;b=C;c[d+(8-w<<2)>>2]=s;if((e|0)==7)break;else g=0}c[d+4>>2]=b;e=0;f=0}else{e=0;f=0}do{s=c[d+(8-e<<2)>>2]|0;w=e<<1;c[a+(e<<2)>>2]=s<>>(30-w|0);e=e+1|0}while((e|0)!=8);c[a+32>>2]=f;c[t>>2]=0;c[t+4>>2]=0;c[t+8>>2]=0;c[t+12>>2]=0;c[t+16>>2]=0;c[t+20>>2]=0;c[t+24>>2]=0;c[t+28>>2]=0;e=d+40|0;do{c[d>>2]=0;d=d+4|0}while((d|0)<(e|0));d=u;e=d+40|0;do{c[d>>2]=0;d=d+4|0}while((d|0)<(e|0))}i=v;return}function Ya(a,b){a=a|0;b=b|0;var d=0,e=0,f=0;e=0;d=0;while(1){f=a+(e<<2)|0;d=(c[f>>2]|0)+d+(c[b+(e<<2)>>2]|0)|0;c[f>>2]=d&1073741823;e=e+1|0;if((e|0)==9)break;else d=d>>>30}return}function Za(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0;e=0;do{f=a+(e<<2)|0;c[f>>2]=(c[f>>2]|0)+(c[b+(e<<2)>>2]|0);e=e+1|0}while((e|0)!=9);Pa(a,d);return}function _a(a,b,d){a=a|0;b=b|0;d=d|0;var e=0;if((c[d>>2]|0)>>>0>>0)pa(38495,38223,856,38514);b=(c[a>>2]|0)-b|0;c[a>>2]=b;b=b+(c[d>>2]|0)|0;c[a>>2]=b&1073741823;e=1;do{b=(c[a+(e<<2)>>2]|0)+(b>>>30)+(c[d+(e<<2)>>2]|0)|0;c[a+(e<<2)>>2]=b&1073741823;e=e+1|0}while((e|0)!=9);return}function $a(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0;g=0;f=1;while(1){f=f+1073741823+(c[a+(g<<2)>>2]|0)+(c[e+(g<<2)>>2]<<1)-(c[b+(g<<2)>>2]|0)|0;c[d+(g<<2)>>2]=f&1073741823;g=g+1|0;if((g|0)==9)break;else f=f>>>30}return}function ab(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0;n=i;i=i+144|0;k=n+108|0;e=n+72|0;l=n+36|0;m=n;do if(!(bb(b)|0)){if(bb(d)|0){e=d;f=b;g=e+72|0;do{c[e>>2]=c[f>>2];e=e+4|0;f=f+4|0}while((e|0)<(g|0));break}if(cb(b,d)|0){db(a,d);break}if(!(eb(b,d)|0)){$a(d,b,e,a);Xa(e,a);h=d+36|0;j=b+36|0;$a(h,j,k,a);Va(e,k,a);e=l;f=k;g=e+36|0;do{c[e>>2]=c[f>>2];e=e+4|0;f=f+4|0}while((e|0)<(g|0));Va(l,l,a);e=m;f=b;g=e+36|0;do{c[e>>2]=c[f>>2];e=e+4|0;f=f+4|0}while((e|0)<(g|0));Za(m,d,a);$a(l,m,l,a);Pa(l,a);Qa(l,a);$a(b,l,m,a);Va(k,m,a);$a(m,j,m,a);Pa(m,a);Qa(m,a);e=d;f=l;g=e+36|0;do{c[e>>2]=c[f>>2];e=e+4|0;f=f+4|0}while((e|0)<(g|0));e=h;f=m;g=e+36|0;do{c[e>>2]=c[f>>2];e=e+4|0;f=f+4|0}while((e|0)<(g|0));break}else{Ha(d);Ha(d+36|0);break}}while(0);i=n;return}function bb(a){a=a|0;if(!(Ia(a)|0))a=0;else a=(Ia(a+36|0)|0)!=0;return a&1|0}function cb(a,b){a=a|0;b=b|0;if(!(Ka(a,b)|0))a=0;else a=(Ka(a+36|0,b+36|0)|0)!=0;return a&1|0}function db(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0,l=0;j=i;i=i+112|0;d=j+72|0;e=j+36|0;f=j;do if(!(bb(b)|0)){g=b+36|0;if(!(Ia(g)|0)){h=d;k=g;l=h+36|0;do{c[h>>2]=c[k>>2];h=h+4|0;k=k+4|0}while((h|0)<(l|0));Oa(d,2,a);Xa(d,a);h=e;k=b;l=h+36|0;do{c[h>>2]=c[k>>2];h=h+4|0;k=k+4|0}while((h|0)<(l|0));Va(e,e,a);Oa(e,3,a);_a(e,0-(c[a+180>>2]|0)|0,a);Va(e,d,a);h=e;k=d;l=h+36|0;do{c[h>>2]=c[k>>2];h=h+4|0;k=k+4|0}while((h|0)<(l|0));Va(e,e,a);h=f;k=b;l=h+36|0;do{c[h>>2]=c[k>>2];h=h+4|0;k=k+4|0}while((h|0)<(l|0));Ma(f);$a(e,f,e,a);Pa(e,a);Qa(e,a);$a(b,e,f,a);Va(d,f,a);$a(f,g,f,a);Pa(f,a);Qa(f,a);h=b;k=e;l=h+36|0;do{c[h>>2]=c[k>>2];h=h+4|0;k=k+4|0}while((h|0)<(l|0));h=g;k=f;l=h+36|0;do{c[h>>2]=c[k>>2];h=h+4|0;k=k+4|0}while((h|0)<(l|0));break}else{Ha(b);Ha(g);break}}while(0);i=j;return}function eb(a,b){a=a|0;b=b|0;var c=0;if((Ka(a,b)|0)!=0?(c=a+36|0,(Ia(c)|0)==0):0)a=(Ka(c,b+36|0)|0)==0&1;else a=0;return a|0}function fb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0,j=0;g=b+32|0;if((c[g>>2]|0)>>>0>=131072)pa(38522,38542,179,38553);h=a&1073741823;f=~a;a=c[b>>2]|0;e=(c[d>>2]<<1)+1073741824-a|0;c[b>>2]=h&e|a&f;a=0;do{a=a+1|0;i=b+(a<<2)|0;j=c[i>>2]|0;e=(e>>>30)+1073741823+(c[d+(a<<2)>>2]<<1)-j|0;c[i>>2]=h&e|j&f}while((a|0)!=8);if((c[g>>2]|0)>>>0<131072)return;else pa(38522,38542,187,38553)}function gb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0;e=0;f=Jb()|0;do{c[b+72+(e<<2)>>2]=f&1073741823;e=e+1|0;f=Jb()|0}while((e|0)!=8);i=b+72|0;c[b+104>>2]=(f&32767)+1;f=b;g=i;h=f+36|0;do{c[f>>2]=c[g>>2];f=f+4|0;g=g+4|0}while((f|0)<(h|0));Va(i,b,d);e=b+36|0;f=e;g=b;h=f+36|0;do{c[f>>2]=c[g>>2];f=f+4|0;g=g+4|0}while((f|0)<(h|0));Va(i,e,d);Va(a,b,d);Va(a+36|0,e,d);return}function hb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0;e=b+36|0;f=e;g=a+72|0;h=f+36|0;do{c[f>>2]=c[g>>2];f=f+4|0;g=g+4|0}while((f|0)<(h|0));Xa(e,d);f=b;g=e;h=f+36|0;do{c[f>>2]=c[g>>2];f=f+4|0;g=g+4|0}while((f|0)<(h|0));Va(b,b,d);Va(b,e,d);Va(a,b,d);Va(a+36|0,e,d);Qa(b,d);Qa(e,d);return}function ib(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0;s=i;i=i+288|0;k=s+252|0;l=s+216|0;m=s+180|0;n=s+144|0;o=s+108|0;p=s+72|0;q=s+36|0;g=s;e=c[d+180>>2]|0;if((e+3|0)>>>0>=4)pa(38572,38542,238,38590);h=b+72|0;r=p;t=h;u=r+36|0;do{c[r>>2]=c[t>>2];r=r+4|0;t=t+4|0}while((r|0)<(u|0));Va(p,p,d);r=q;t=h;u=r+36|0;do{c[r>>2]=c[t>>2];r=r+4|0;t=t+4|0}while((r|0)<(u|0));Va(p,q,d);j=(e|0)!=0;if(j){e=0-e|0;r=g;t=p;u=r+36|0;do{c[r>>2]=c[t>>2];r=r+4|0;t=t+4|0}while((r|0)<(u|0));Va(g,g,d);Oa(g,e&255,d)}Va(a,p,d);r=l;t=p;u=r+36|0;do{c[r>>2]=c[t>>2];r=r+4|0;t=t+4|0}while((r|0)<(u|0));$a(l,b,l,d);Pa(l,d);Ya(p,b);f=Ka(l,d)|0;Va(a+36|0,q,d);e=b+36|0;$a(q,e,k,d);Ya(q,e);r=m;t=b;u=r+36|0;do{c[r>>2]=c[t>>2];r=r+4|0;t=t+4|0}while((r|0)<(u|0));Va(m,m,d);Oa(m,3,d);if(j)$a(m,g,m,d);La(k,f,m,k);La(l,f,q,l);r=o;t=l;u=r+36|0;do{c[r>>2]=c[t>>2];r=r+4|0;t=t+4|0}while((r|0)<(u|0));Va(o,o,d);r=n;t=l;u=r+36|0;do{c[r>>2]=c[t>>2];r=r+4|0;t=t+4|0}while((r|0)<(u|0));Va(o,n,d);Va(p,o,d);Va(q,n,d);Va(l,h,d);r=b;t=k;u=r+36|0;do{c[r>>2]=c[t>>2];r=r+4|0;t=t+4|0}while((r|0)<(u|0));Va(b,b,d);$a(b,o,b,d);Pa(b,d);$a(o,b,e,d);$a(e,b,e,d);Va(k,e,d);$a(e,n,e,d);Na(e,d);Pa(e,d);i=s;return}function jb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0;n=i;i=i+144|0;l=n+108|0;m=n;if(!(Ja(b,a+108|0)|0))pa(38609,38542,543,38658);j=c[b>>2]|0;g=(j&1)+-1|0;f=1;e=0;h=j;do{k=f+1073741823+h-(c[a+108+(e<<2)>>2]&g)|0;c[l+(e<<2)>>2]=k&1073741823;f=k>>>30;e=e+1|0;h=c[b+(e<<2)>>2]|0;j=h|j}while((e|0)!=8);k=l+32|0;c[k>>2]=f+65535+h-(c[a+140>>2]&g);e=c[l>>2]|0;if(!(e&1))pa(38638,38542,566,38658);if(!j){Ha(d);Ha(d+36|0)}else{gb(a+220+((((e>>>4&1)+15^e)>>>1&7)*72|0)|0,m,a);h=m+36|0;g=1;do{f=0;e=e>>>4;b=l;do{f=f+1|0;j=b;b=l+(f<<2)|0;c[j>>2]=c[b>>2]<<26&1006632960|e;e=(c[b>>2]|0)>>>4}while((f|0)!=8);c[k>>2]=e;e=c[l>>2]|0;b=e>>>4&1;j=b+15^e;fb((j&1)+-1|0,h,a);ib(a+220+(g*576|0)+((j>>>1&7)*72|0)|0,m,a);g=g+1|0}while((g|0)!=64);fb(b+-1|0,h,a);hb(m,d,a)}i=n;return}function kb(b,c,d){b=b|0;c=c|0;d=d|0;b=(b|0)==0?712:b;switch(a[c>>0]|0){case 4:{Fa(c+1|0,d);Fa(c+33|0,d+36|0);b=lb(b,d)|0;break}case 3:case 2:{Fa(c+1|0,d);mb(b,a[c>>0]|0,d,d+36|0);b=lb(b,d)|0;break}default:b=0}return b|0}function lb(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0;k=i;i=i+80|0;d=k+36|0;e=k;if(((bb(b)|0)==0?(Ja(b,a)|0)!=0:0)?(f=b+36|0,(Ja(f,a)|0)!=0):0){g=d;h=f;j=g+36|0;do{c[g>>2]=c[h>>2];g=g+4|0;h=h+4|0}while((g|0)<(j|0));g=e;h=b;j=g+36|0;do{c[g>>2]=c[h>>2];g=g+4|0;h=h+4|0}while((g|0)<(j|0));Va(f,d,a);Qa(d,a);Va(b,e,a);_a(e,0-(c[a+180>>2]|0)|0,a);Va(b,e,a);Za(e,a+184|0,a);Qa(e,a);a=(Ka(e,d)|0)!=0&1}else a=0;i=k;return a|0}function mb(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0;f=e;g=d;h=f+36|0;do{c[f>>2]=c[g>>2];f=f+4|0;g=g+4|0}while((f|0)<(h|0));Va(d,e,a);_a(e,0-(c[a+180>>2]|0)|0,a);Va(d,e,a);Ya(e,a+184|0);Wa(e,a);if((c[e>>2]^b&255)&1|0)Ra(a,e,e);return}function nb(b,c){b=b|0;c=c|0;var d=0,e=0;e=i;i=i+32|0;d=e;switch(a[b>>0]|0){case 4:{Db(b,65,d);break}case 0:{Db(b,1,d);break}default:Db(b,33,d)}zb(d,32,c);i=e;return}function ob(b,c,d){b=b|0;c=c|0;d=d|0;do if(c>>>0>=256){if(c>>>0<65536){a[d>>0]=c>>>8;a[d+1>>0]=c;nb(b,d+2|0);break}if(c>>>0<16777216){a[d>>0]=c>>>16;a[d+1>>0]=c>>>8;a[d+2>>0]=c;nb(b,d+3|0);break}else{a[d>>0]=c>>>24;a[d+1>>0]=c>>>16;a[d+2>>0]=c>>>8;a[d+3>>0]=c;nb(b,d+4|0);break}}else{a[d>>0]=c;nb(b,d+1|0)}while(0);return}function pb(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0,f=0;f=i;i=i+32|0;e=f;ob(a,b,e);do if(b>>>0>=256){if(b>>>0<65536){vb(e,22,c,d)|0;break}if(b>>>0<16777216){vb(e,23,c,d)|0;break}else{vb(e,24,c,d)|0;break}}else vb(e,21,c,d)|0;while(0);i=f;return}function qb(b,c,e){b=b|0;c=c|0;e=e|0;var f=0,g=0,h=0,j=0;j=i;i=i+128|0;h=j;f=h;g=f+128|0;do{a[f>>0]=0;f=f+1|0}while((f|0)<(g|0));if(e>>>0>128){Ib(c,e,h);c=0}else{qc(h|0,c|0,e|0)|0;c=0}do{g=h+c|0;f=d[g>>0]|0;a[b+c>>0]=f^92;a[g>>0]=f^54;c=c+1|0}while((c|0)!=128);b=b+128|0;Eb(b);Gb(b,h,128);i=j;return}function rb(a,b){a=a|0;b=b|0;var c=0,d=0,e=0;c=i;i=i+64|0;e=c;d=a+128|0;Hb(d,e);Eb(d);Gb(d,a,128);Gb(d,e,64);Hb(d,b);ic(a|0,0,336)|0;i=c;return}function sb(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;var f=0,g=0;f=i;i=i+336|0;g=f;qb(g,a,b);Gb(g+128|0,c,d);rb(g,e);i=f;return}function tb(b,d,e,f,g,h,j){b=b|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;j=j|0;var k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0;s=i;i=i+256|0;o=s+216|0;p=s+152|0;q=s+112|0;m=s+40|0;n=s;if((f|0)<0)d=0;else{r=o;l=r+33|0;do{a[r>>0]=a[d>>0]|0;r=r+1|0;d=d+1|0}while((r|0)<(l|0));Ea(o+33|0,f);f=o+1|0;k=p+32|0;while(1){sb(e,32,o,37,p);Fa(p,n);if(Ja(n,820)|0?(jb(712,n,m),ab(712,b,m),(bb(m)|0)==0):0)break;a[o>>0]=1;r=f;d=k;l=r+32|0;do{a[r>>0]=a[d>>0]|0;r=r+1|0;d=d+1|0}while((r|0)<(l|0))}a[q>>0]=c[m+36>>2]&1|2;Ga(m,q+1|0);pb(q,g,h,j);d=1}i=s;return d|0}function ub(b,e,f,g){b=b|0;e=e|0;f=f|0;g=g|0;var h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0;q=i;a:do if((g|0)>0){h=0;do{if(a[f+h>>0]|0)break a;h=h+1|0}while((h|0)<(g|0))}else h=0;while(0);o=(((g-h|0)*138|0)>>>0)/100|0;n=o+1|0;p=i;i=i+((1*n|0)+15&-16)|0;ic(p|0,0,n|0)|0;if((h|0)<(g|0)){j=o;m=h;do{k=a[f+m>>0]|0;if((o|0)>(j|0)|k<<24>>24!=0){k=k&255;l=o;while(1){r=p+l|0;k=(d[r>>0]<<8)+k|0;a[r>>0]=(k|0)%58|0;l=l+-1|0;if((l|0)>(j|0)|(k+57|0)>>>0>114)k=(k|0)/58|0;else{j=l;break}}}else j=o;m=m+1|0}while((m|0)!=(g|0));j=0}else j=0;while(1){if(a[p+j>>0]|0)break;k=j+1|0;if((j|0)<(o|0))j=k;else{j=k;break}}k=n+h-j|0;if((c[e>>2]|0)>>>0>k>>>0){if(!h)h=0;else ic(b|0,49,h|0)|0;if((j|0)<=(o|0))while(1){a[b+h>>0]=a[38674+(d[p+j>>0]|0)>>0]|0;h=h+1|0;if((j|0)<(o|0))j=j+1|0;else break}a[b+h>>0]=0;j=1}else{j=0;h=k}c[e>>2]=h+1;i=q;return j|0}function vb(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,j=0,k=0,l=0;g=i;i=i+16|0;f=g;if((b|0)>128)a=0;else{j=b+32|0;h=ia()|0;k=i;i=i+((1*j|0)+15&-16)|0;l=k+b|0;qc(k|0,a|0,b|0)|0;Db(a,b,l);Db(l,32,l);c[f>>2]=e;a=ub(d,f,k,b+4|0)|0;ic(k|0,0,j|0)|0;a=a?c[f>>2]|0:0;oa(h|0)}i=g;return a|0}function wb(a,b){a=a|0;b=b|0;var e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0;s=(d[b+1>>0]|0)<<8|(d[b>>0]|0)|(d[b+2>>0]|0)<<16|(d[b+3>>0]|0)<<24;D=(d[b+5>>0]|0)<<8|(d[b+4>>0]|0)|(d[b+6>>0]|0)<<16|(d[b+7>>0]|0)<<24;v=(d[b+9>>0]|0)<<8|(d[b+8>>0]|0)|(d[b+10>>0]|0)<<16|(d[b+11>>0]|0)<<24;f=(d[b+13>>0]|0)<<8|(d[b+12>>0]|0)|(d[b+14>>0]|0)<<16|(d[b+15>>0]|0)<<24;x=(d[b+17>>0]|0)<<8|(d[b+16>>0]|0)|(d[b+18>>0]|0)<<16|(d[b+19>>0]|0)<<24;t=(d[b+21>>0]|0)<<8|(d[b+20>>0]|0)|(d[b+22>>0]|0)<<16|(d[b+23>>0]|0)<<24;y=(d[b+25>>0]|0)<<8|(d[b+24>>0]|0)|(d[b+26>>0]|0)<<16|(d[b+27>>0]|0)<<24;z=(d[b+29>>0]|0)<<8|(d[b+28>>0]|0)|(d[b+30>>0]|0)<<16|(d[b+31>>0]|0)<<24;B=(d[b+33>>0]|0)<<8|(d[b+32>>0]|0)|(d[b+34>>0]|0)<<16|(d[b+35>>0]|0)<<24;i=(d[b+37>>0]|0)<<8|(d[b+36>>0]|0)|(d[b+38>>0]|0)<<16|(d[b+39>>0]|0)<<24;F=(d[b+41>>0]|0)<<8|(d[b+40>>0]|0)|(d[b+42>>0]|0)<<16|(d[b+43>>0]|0)<<24;l=(d[b+45>>0]|0)<<8|(d[b+44>>0]|0)|(d[b+46>>0]|0)<<16|(d[b+47>>0]|0)<<24;H=(d[b+49>>0]|0)<<8|(d[b+48>>0]|0)|(d[b+50>>0]|0)<<16|(d[b+51>>0]|0)<<24;u=(d[b+53>>0]|0)<<8|(d[b+52>>0]|0)|(d[b+54>>0]|0)<<16|(d[b+55>>0]|0)<<24;m=(d[b+57>>0]|0)<<8|(d[b+56>>0]|0)|(d[b+58>>0]|0)<<16|(d[b+59>>0]|0)<<24;w=(d[b+61>>0]|0)<<8|(d[b+60>>0]|0)|(d[b+62>>0]|0)<<16|(d[b+63>>0]|0)<<24;b=a+8|0;A=c[b>>2]|0;p=a+12|0;e=c[p>>2]|0;n=a+16|0;r=c[n>>2]|0;k=a+20|0;I=c[k>>2]|0;g=a+24|0;E=c[g>>2]|0;j=A+s+(r^e^I)|0;j=(j<<11|j>>>21)+E|0;C=r<<10|r>>>22;A=t+1352829926+A+((r|~I)^e)|0;A=(A<<8|A>>>24)+E|0;o=E+D+(C^e^j)|0;o=(o<<14|o>>>18)+I|0;G=e<<10|e>>>22;E=m+1352829926+E+(A^(e|~C))|0;E=(E<<9|E>>>23)+I|0;J=I+v+(j^G^o)|0;J=(J<<15|J>>>17)+C|0;j=j<<10|j>>>22;I=z+1352829926+I+(E^(A|~G))|0;I=(I<<9|I>>>23)+C|0;A=A<<10|A>>>22;a=C+f+(o^j^J)|0;a=(a<<12|a>>>20)+G|0;o=o<<10|o>>>22;C=s+1352829926+C+(I^(E|~A))|0;C=(C<<11|C>>>21)+G|0;E=E<<10|E>>>22;h=G+x+(J^o^a)|0;h=(h<<5|h>>>27)+j|0;J=J<<10|J>>>22;G=i+1352829926+G+(C^(I|~E))|0;G=(G<<13|G>>>19)+A|0;I=I<<10|I>>>22;j=j+t+(a^J^h)|0;j=(j<<8|j>>>24)+o|0;a=a<<10|a>>>22;A=v+1352829926+A+(G^(C|~I))|0;A=(A<<15|A>>>17)+E|0;C=C<<10|C>>>22;o=o+y+(h^a^j)|0;o=(o<<7|o>>>25)+J|0;h=h<<10|h>>>22;E=l+1352829926+E+(A^(G|~C))|0;E=(E<<15|E>>>17)+I|0;G=G<<10|G>>>22;J=J+z+(j^h^o)|0;J=(J<<9|J>>>23)+a|0;j=j<<10|j>>>22;I=x+1352829926+I+(E^(A|~G))|0;I=(I<<5|I>>>27)+C|0;A=A<<10|A>>>22;a=a+B+(o^j^J)|0;a=(a<<11|a>>>21)+h|0;o=o<<10|o>>>22;C=u+1352829926+C+(I^(E|~A))|0;C=(C<<7|C>>>25)+G|0;E=E<<10|E>>>22;h=h+i+(J^o^a)|0;h=(h<<13|h>>>19)+j|0;J=J<<10|J>>>22;G=y+1352829926+G+(C^(I|~E))|0;G=(G<<7|G>>>25)+A|0;I=I<<10|I>>>22;j=j+F+(a^J^h)|0;j=(j<<14|j>>>18)+o|0;a=a<<10|a>>>22;A=w+1352829926+A+(G^(C|~I))|0;A=(A<<8|A>>>24)+E|0;C=C<<10|C>>>22;o=o+l+(h^a^j)|0;o=(o<<15|o>>>17)+J|0;h=h<<10|h>>>22;E=B+1352829926+E+(A^(G|~C))|0;E=(E<<11|E>>>21)+I|0;G=G<<10|G>>>22;J=J+H+(j^h^o)|0;J=(J<<6|J>>>26)+a|0;j=j<<10|j>>>22;I=D+1352829926+I+(E^(A|~G))|0;I=(I<<14|I>>>18)+C|0;A=A<<10|A>>>22;a=a+u+(o^j^J)|0;a=(a<<7|a>>>25)+h|0;o=o<<10|o>>>22;C=F+1352829926+C+(I^(E|~A))|0;C=(C<<14|C>>>18)+G|0;E=E<<10|E>>>22;h=h+m+(J^o^a)|0;h=(h<<9|h>>>23)+j|0;J=J<<10|J>>>22;G=f+1352829926+G+(C^(I|~E))|0;G=(G<<12|G>>>20)+A|0;I=I<<10|I>>>22;j=j+w+(a^J^h)|0;j=(j<<8|j>>>24)+o|0;a=a<<10|a>>>22;A=H+1352829926+A+(G^(C|~I))|0;A=(A<<6|A>>>26)+E|0;C=C<<10|C>>>22;o=z+1518500249+o+(j&h|a&~j)|0;o=(o<<7|o>>>25)+J|0;h=h<<10|h>>>22;E=y+1548603684+E+(A&C|G&~C)|0;E=(E<<9|E>>>23)+I|0;G=G<<10|G>>>22;J=x+1518500249+J+(o&j|h&~o)|0;J=(J<<6|J>>>26)+a|0;j=j<<10|j>>>22;I=l+1548603684+I+(E&G|A&~G)|0;I=(I<<13|I>>>19)+C|0;A=A<<10|A>>>22;a=u+1518500249+a+(J&o|j&~J)|0;a=(a<<8|a>>>24)+h|0;o=o<<10|o>>>22;C=f+1548603684+C+(I&A|E&~A)|0;C=(C<<15|C>>>17)+G|0;E=E<<10|E>>>22;h=D+1518500249+h+(a&J|o&~a)|0;h=(h<<13|h>>>19)+j|0;J=J<<10|J>>>22;G=z+1548603684+G+(C&E|I&~E)|0;G=(G<<7|G>>>25)+A|0;I=I<<10|I>>>22;j=F+1518500249+j+(h&a|J&~h)|0;j=(j<<11|j>>>21)+o|0;a=a<<10|a>>>22;A=s+1548603684+A+(G&I|C&~I)|0;A=(A<<12|A>>>20)+E|0;C=C<<10|C>>>22;o=y+1518500249+o+(j&h|a&~j)|0;o=(o<<9|o>>>23)+J|0;h=h<<10|h>>>22;E=u+1548603684+E+(A&C|G&~C)|0;E=(E<<8|E>>>24)+I|0;G=G<<10|G>>>22;J=w+1518500249+J+(o&j|h&~o)|0;J=(J<<7|J>>>25)+a|0;j=j<<10|j>>>22;I=t+1548603684+I+(E&G|A&~G)|0;I=(I<<9|I>>>23)+C|0;A=A<<10|A>>>22;a=f+1518500249+a+(J&o|j&~J)|0;a=(a<<15|a>>>17)+h|0;o=o<<10|o>>>22;C=F+1548603684+C+(I&A|E&~A)|0;C=(C<<11|C>>>21)+G|0;E=E<<10|E>>>22;h=H+1518500249+h+(a&J|o&~a)|0;h=(h<<7|h>>>25)+j|0;J=J<<10|J>>>22;G=m+1548603684+G+(C&E|I&~E)|0;G=(G<<7|G>>>25)+A|0;I=I<<10|I>>>22;j=s+1518500249+j+(h&a|J&~h)|0;j=(j<<12|j>>>20)+o|0;a=a<<10|a>>>22;A=w+1548603684+A+(G&I|C&~I)|0;A=(A<<7|A>>>25)+E|0;C=C<<10|C>>>22;o=i+1518500249+o+(j&h|a&~j)|0;o=(o<<15|o>>>17)+J|0;h=h<<10|h>>>22;E=B+1548603684+E+(A&C|G&~C)|0;E=(E<<12|E>>>20)+I|0;G=G<<10|G>>>22;J=t+1518500249+J+(o&j|h&~o)|0;J=(J<<9|J>>>23)+a|0;j=j<<10|j>>>22;I=H+1548603684+I+(E&G|A&~G)|0;I=(I<<7|I>>>25)+C|0;A=A<<10|A>>>22;a=v+1518500249+a+(J&o|j&~J)|0;a=(a<<11|a>>>21)+h|0;o=o<<10|o>>>22;C=x+1548603684+C+(I&A|E&~A)|0;C=(C<<6|C>>>26)+G|0;E=E<<10|E>>>22;h=m+1518500249+h+(a&J|o&~a)|0;h=(h<<7|h>>>25)+j|0;J=J<<10|J>>>22;G=i+1548603684+G+(C&E|I&~E)|0;G=(G<<15|G>>>17)+A|0;I=I<<10|I>>>22;j=l+1518500249+j+(h&a|J&~h)|0;j=(j<<13|j>>>19)+o|0;a=a<<10|a>>>22;A=D+1548603684+A+(G&I|C&~I)|0;A=(A<<13|A>>>19)+E|0;C=C<<10|C>>>22;q=~j;o=B+1518500249+o+(j&h|a&q)|0;o=(o<<12|o>>>20)+J|0;h=h<<10|h>>>22;E=v+1548603684+E+(A&C|G&~C)|0;E=(E<<11|E>>>21)+I|0;G=G<<10|G>>>22;q=f+1859775393+J+((o|q)^h)|0;q=(q<<11|q>>>21)+a|0;j=j<<10|j>>>22;I=w+1836072691+I+((E|~A)^G)|0;I=(I<<9|I>>>23)+C|0;A=A<<10|A>>>22;a=F+1859775393+a+((q|~o)^j)|0;a=(a<<13|a>>>19)+h|0;o=o<<10|o>>>22;C=t+1836072691+C+((I|~E)^A)|0;C=(C<<7|C>>>25)+G|0;E=E<<10|E>>>22;h=m+1859775393+h+((a|~q)^o)|0;h=(h<<6|h>>>26)+j|0;q=q<<10|q>>>22;G=D+1836072691+G+((C|~I)^E)|0;G=(G<<15|G>>>17)+A|0;I=I<<10|I>>>22;j=x+1859775393+j+((h|~a)^q)|0;j=(j<<7|j>>>25)+o|0;a=a<<10|a>>>22;A=f+1836072691+A+((G|~C)^I)|0;A=(A<<11|A>>>21)+E|0;C=C<<10|C>>>22;o=i+1859775393+o+((j|~h)^a)|0;o=(o<<14|o>>>18)+q|0;h=h<<10|h>>>22;E=z+1836072691+E+((A|~G)^C)|0;E=(E<<8|E>>>24)+I|0;G=G<<10|G>>>22;q=w+1859775393+q+((o|~j)^h)|0;q=(q<<9|q>>>23)+a|0;j=j<<10|j>>>22;I=m+1836072691+I+((E|~A)^G)|0;I=(I<<6|I>>>26)+C|0;A=A<<10|A>>>22;a=B+1859775393+a+((q|~o)^j)|0;a=(a<<13|a>>>19)+h|0;o=o<<10|o>>>22;C=y+1836072691+C+((I|~E)^A)|0;C=(C<<6|C>>>26)+G|0;E=E<<10|E>>>22;h=D+1859775393+h+((a|~q)^o)|0;h=(h<<15|h>>>17)+j|0;q=q<<10|q>>>22;G=i+1836072691+G+((C|~I)^E)|0;G=(G<<14|G>>>18)+A|0;I=I<<10|I>>>22;j=v+1859775393+j+((h|~a)^q)|0;j=(j<<14|j>>>18)+o|0;a=a<<10|a>>>22;A=l+1836072691+A+((G|~C)^I)|0;A=(A<<12|A>>>20)+E|0;C=C<<10|C>>>22;o=z+1859775393+o+((j|~h)^a)|0;o=(o<<8|o>>>24)+q|0;h=h<<10|h>>>22;E=B+1836072691+E+((A|~G)^C)|0;E=(E<<13|E>>>19)+I|0;G=G<<10|G>>>22;q=s+1859775393+q+((o|~j)^h)|0;q=(q<<13|q>>>19)+a|0;j=j<<10|j>>>22;I=H+1836072691+I+((E|~A)^G)|0;I=(I<<5|I>>>27)+C|0;A=A<<10|A>>>22;a=y+1859775393+a+((q|~o)^j)|0;a=(a<<6|a>>>26)+h|0;o=o<<10|o>>>22;C=v+1836072691+C+((I|~E)^A)|0;C=(C<<14|C>>>18)+G|0;E=E<<10|E>>>22;h=u+1859775393+h+((a|~q)^o)|0;h=(h<<5|h>>>27)+j|0;q=q<<10|q>>>22;G=F+1836072691+G+((C|~I)^E)|0;G=(G<<13|G>>>19)+A|0;I=I<<10|I>>>22;j=l+1859775393+j+((h|~a)^q)|0;j=(j<<12|j>>>20)+o|0;a=a<<10|a>>>22;A=s+1836072691+A+((G|~C)^I)|0;A=(A<<13|A>>>19)+E|0;C=C<<10|C>>>22;o=t+1859775393+o+((j|~h)^a)|0;o=(o<<7|o>>>25)+q|0;h=h<<10|h>>>22;E=x+1836072691+E+((A|~G)^C)|0;E=(E<<7|E>>>25)+I|0;G=G<<10|G>>>22;q=H+1859775393+q+((o|~j)^h)|0;q=(q<<5|q>>>27)+a|0;j=j<<10|j>>>22;I=u+1836072691+I+((E|~A)^G)|0;I=(I<<5|I>>>27)+C|0;A=A<<10|A>>>22;a=D+-1894007588+a+(q&j|o&~j)|0;a=(a<<11|a>>>21)+h|0;o=o<<10|o>>>22;C=B+2053994217+C+(I&E|A&~I)|0;C=(C<<15|C>>>17)+G|0;E=E<<10|E>>>22;h=i+-1894007588+h+(a&o|q&~o)|0;h=(h<<12|h>>>20)+j|0;q=q<<10|q>>>22;G=y+2053994217+G+(C&I|E&~C)|0;G=(G<<5|G>>>27)+A|0;I=I<<10|I>>>22;j=l+-1894007588+j+(h&q|a&~q)|0;j=(j<<14|j>>>18)+o|0;a=a<<10|a>>>22;A=x+2053994217+A+(G&C|I&~G)|0;A=(A<<8|A>>>24)+E|0;C=C<<10|C>>>22;o=F+-1894007588+o+(j&a|h&~a)|0;o=(o<<15|o>>>17)+q|0;h=h<<10|h>>>22;E=D+2053994217+E+(A&G|C&~A)|0;E=(E<<11|E>>>21)+I|0;G=G<<10|G>>>22;q=s+-1894007588+q+(o&h|j&~h)|0;q=(q<<14|q>>>18)+a|0;j=j<<10|j>>>22;I=f+2053994217+I+(E&A|G&~E)|0;I=(I<<14|I>>>18)+C|0;A=A<<10|A>>>22;a=B+-1894007588+a+(q&j|o&~j)|0;a=(a<<15|a>>>17)+h|0;o=o<<10|o>>>22;C=l+2053994217+C+(I&E|A&~I)|0;C=(C<<14|C>>>18)+G|0;E=E<<10|E>>>22;h=H+-1894007588+h+(a&o|q&~o)|0;h=(h<<9|h>>>23)+j|0;q=q<<10|q>>>22;G=w+2053994217+G+(C&I|E&~C)|0;G=(G<<6|G>>>26)+A|0;I=I<<10|I>>>22;j=x+-1894007588+j+(h&q|a&~q)|0;j=(j<<8|j>>>24)+o|0;a=a<<10|a>>>22;A=s+2053994217+A+(G&C|I&~G)|0;A=(A<<14|A>>>18)+E|0;C=C<<10|C>>>22;o=u+-1894007588+o+(j&a|h&~a)|0;o=(o<<9|o>>>23)+q|0;h=h<<10|h>>>22;E=t+2053994217+E+(A&G|C&~A)|0;E=(E<<6|E>>>26)+I|0;G=G<<10|G>>>22;q=f+-1894007588+q+(o&h|j&~h)|0;q=(q<<14|q>>>18)+a|0;j=j<<10|j>>>22;I=H+2053994217+I+(E&A|G&~E)|0;I=(I<<9|I>>>23)+C|0;A=A<<10|A>>>22;a=z+-1894007588+a+(q&j|o&~j)|0;a=(a<<5|a>>>27)+h|0;o=o<<10|o>>>22;C=v+2053994217+C+(I&E|A&~I)|0;C=(C<<12|C>>>20)+G|0;E=E<<10|E>>>22;h=w+-1894007588+h+(a&o|q&~o)|0;h=(h<<6|h>>>26)+j|0;q=q<<10|q>>>22;G=u+2053994217+G+(C&I|E&~C)|0;G=(G<<9|G>>>23)+A|0;I=I<<10|I>>>22;j=m+-1894007588+j+(h&q|a&~q)|0;j=(j<<8|j>>>24)+o|0;a=a<<10|a>>>22;A=i+2053994217+A+(G&C|I&~G)|0;A=(A<<12|A>>>20)+E|0;C=C<<10|C>>>22;o=t+-1894007588+o+(j&a|h&~a)|0;o=(o<<6|o>>>26)+q|0;h=h<<10|h>>>22;E=z+2053994217+E+(A&G|C&~A)|0;E=(E<<5|E>>>27)+I|0;G=G<<10|G>>>22;q=y+-1894007588+q+(o&h|j&~h)|0;q=(q<<5|q>>>27)+a|0;j=j<<10|j>>>22;I=F+2053994217+I+(E&A|G&~E)|0;I=(I<<15|I>>>17)+C|0;A=A<<10|A>>>22;a=v+-1894007588+a+(q&j|o&~j)|0;a=(a<<12|a>>>20)+h|0;o=o<<10|o>>>22;C=m+2053994217+C+(I&E|A&~I)|0;C=(C<<8|C>>>24)+G|0;E=E<<10|E>>>22;h=x+-1454113458+h+(a^(q|~o))|0;h=(h<<9|h>>>23)+j|0;q=q<<10|q>>>22;G=G+H+(I^E^C)|0;G=(G<<8|G>>>24)+A|0;I=I<<10|I>>>22;j=s+-1454113458+j+(h^(a|~q))|0;j=(j<<15|j>>>17)+o|0;a=a<<10|a>>>22;A=A+w+(C^I^G)|0;A=(A<<5|A>>>27)+E|0;C=C<<10|C>>>22;o=t+-1454113458+o+(j^(h|~a))|0;o=(o<<5|o>>>27)+q|0;h=h<<10|h>>>22;E=E+F+(G^C^A)|0;E=(E<<12|E>>>20)+I|0;G=G<<10|G>>>22;q=i+-1454113458+q+(o^(j|~h))|0;q=(q<<11|q>>>21)+a|0;j=j<<10|j>>>22;x=I+x+(A^G^E)|0;x=(x<<9|x>>>23)+C|0;A=A<<10|A>>>22;a=z+-1454113458+a+(q^(o|~j))|0;a=(a<<6|a>>>26)+h|0;o=o<<10|o>>>22;C=C+D+(E^A^x)|0;C=(C<<12|C>>>20)+G|0;E=E<<10|E>>>22;h=H+-1454113458+h+(a^(q|~o))|0;h=(h<<8|h>>>24)+j|0;q=q<<10|q>>>22;t=G+t+(x^E^C)|0;t=(t<<5|t>>>27)+A|0;x=x<<10|x>>>22;j=v+-1454113458+j+(h^(a|~q))|0;j=(j<<13|j>>>19)+o|0;a=a<<10|a>>>22;A=A+B+(C^x^t)|0;A=(A<<14|A>>>18)+E|0;C=C<<10|C>>>22;o=F+-1454113458+o+(j^(h|~a))|0;o=(o<<12|o>>>20)+q|0;h=h<<10|h>>>22;z=E+z+(t^C^A)|0;z=(z<<6|z>>>26)+x|0;t=t<<10|t>>>22;q=m+-1454113458+q+(o^(j|~h))|0;q=(q<<5|q>>>27)+a|0;j=j<<10|j>>>22;x=x+y+(A^t^z)|0;x=(x<<8|x>>>24)+C|0;A=A<<10|A>>>22;a=D+-1454113458+a+(q^(o|~j))|0;a=(a<<12|a>>>20)+h|0;o=o<<10|o>>>22;v=C+v+(z^A^x)|0;v=(v<<13|v>>>19)+t|0;z=z<<10|z>>>22;h=f+-1454113458+h+(a^(q|~o))|0;h=(h<<13|h>>>19)+j|0;q=q<<10|q>>>22;t=t+u+(x^z^v)|0;t=(t<<6|t>>>26)+A|0;x=x<<10|x>>>22;j=B+-1454113458+j+(h^(a|~q))|0;j=(j<<14|j>>>18)+o|0;a=a<<10|a>>>22;m=A+m+(v^x^t)|0;m=(m<<5|m>>>27)+z|0;v=v<<10|v>>>22;o=l+-1454113458+o+(j^(h|~a))|0;o=(o<<11|o>>>21)+q|0;h=h<<10|h>>>22;s=z+s+(t^v^m)|0;s=(s<<15|s>>>17)+x|0;t=t<<10|t>>>22;q=y+-1454113458+q+(o^(j|~h))|0;q=(q<<8|q>>>24)+a|0;j=j<<10|j>>>22;f=x+f+(m^t^s)|0;f=(f<<13|f>>>19)+v|0;m=m<<10|m>>>22;a=w+-1454113458+a+(q^(o|~j))|0;a=(a<<5|a>>>27)+h|0;o=o<<10|o>>>22;i=v+i+(s^m^f)|0;i=(i<<11|i>>>21)+t|0;s=s<<10|s>>>22;h=u+-1454113458+h+(a^(q|~o))|0;l=t+l+(f^s^i)|0;c[p>>2]=s+r+(q<<10|q>>>22);c[n>>2]=m+(c[k>>2]|0)+o;c[k>>2]=j+(c[g>>2]|0)+m+(l<<11|l>>>21);c[g>>2]=j+(c[b>>2]|0)+i+(h<<6|h>>>26);c[b>>2]=(f<<10|f>>>22)+e+a;return}function xb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0;if(d|0){h=c[a>>2]|0;e=h&63;f=64-e|0;h=h+d|0;c[a>>2]=h;if(h>>>0>>0){h=a+4|0;c[h>>2]=(c[h>>2]|0)+1}if(!((e|0)==0|f>>>0>d>>>0)){qc(a+28+e|0,b|0,f|0)|0;wb(a,a+28|0);e=0;b=b+f|0;d=d-f|0}if(d>>>0>63){g=d+-64|0;h=g&-64;f=b+(h+64)|0;while(1){wb(a,b);d=d+-64|0;if(d>>>0<=63)break;else b=b+64|0}b=f;d=g-h|0}if(d|0)qc(a+28+e|0,b|0,d|0)|0}return}function yb(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0;e=i;i=i+16|0;f=e;g=c[b>>2]|0;h=c[b+4>>2]|0;a[f>>0]=g<<3;a[f+1>>0]=g>>>5;a[f+2>>0]=g>>>13;a[f+3>>0]=g>>>21;a[f+4>>0]=h<<3|g>>>29;a[f+5>>0]=h>>>5;a[f+6>>0]=h>>>13;a[f+7>>0]=h>>>21;g=g&63;xb(b,38733,(g>>>0<56?56:120)-g|0);xb(b,f,8);f=b+8|0;a[d>>0]=c[f>>2];a[d+1>>0]=(c[f>>2]|0)>>>8;a[d+2>>0]=(c[f>>2]|0)>>>16;a[d+3>>0]=(c[f>>2]|0)>>>24;f=b+12|0;a[d+4>>0]=c[f>>2];a[d+5>>0]=(c[f>>2]|0)>>>8;a[d+6>>0]=(c[f>>2]|0)>>>16;a[d+7>>0]=(c[f>>2]|0)>>>24;f=b+16|0;a[d+8>>0]=c[f>>2];a[d+9>>0]=(c[f>>2]|0)>>>8;a[d+10>>0]=(c[f>>2]|0)>>>16;a[d+11>>0]=(c[f>>2]|0)>>>24;f=b+20|0;a[d+12>>0]=c[f>>2];a[d+13>>0]=(c[f>>2]|0)>>>8;a[d+14>>0]=(c[f>>2]|0)>>>16;a[d+15>>0]=(c[f>>2]|0)>>>24;b=b+24|0;a[d+16>>0]=c[b>>2];a[d+17>>0]=(c[b>>2]|0)>>>8;a[d+18>>0]=(c[b>>2]|0)>>>16;a[d+19>>0]=(c[b>>2]|0)>>>24;i=e;return}function zb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0;h=i;i=i+96|0;e=h;f=e+8|0;g=e;j=g+92|0;do{c[g>>2]=0;g=g+4|0}while((g|0)<(j|0));c[f>>2]=1732584193;c[e+12>>2]=-271733879;c[e+16>>2]=-1732584194;c[e+20>>2]=271733878;c[e+24>>2]=-1009589776;xb(e,a,b);yb(e,d);i=h;return}function Ab(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0;y=i;i=i+64|0;t=y;u=c[a>>2]|0;v=a+4|0;w=a+8|0;x=a+12|0;q=a+16|0;r=a+20|0;s=a+24|0;p=a+28|0;g=0;o=u;a=c[p>>2]|0;h=c[s>>2]|0;j=c[r>>2]|0;k=c[q>>2]|0;e=c[x>>2]|0;l=c[w>>2]|0;f=c[v>>2]|0;while(1){n=((k>>>6|k<<26)^(k>>>11|k<<21)^(k>>>25|k<<7))+a+(h&~k^j&k)+(c[37828+(g<<2)>>2]|0)|0;a=c[b>>2]|0;c[t+(g<<2)>>2]=a;a=n+a|0;e=a+e|0;a=((o>>>2|o<<30)^(o>>>13|o<<19)^(o>>>22|o<<10))+(o&(l^f)^l&f)+a|0;g=g+1|0;if((g|0)==16){n=16;m=a;g=e;a=l;e=o;break}else{C=o;B=f;A=l;z=k;m=j;n=h;b=b+4|0;o=a;k=e;f=C;l=B;e=A;j=z;h=m;a=n}}while(1){A=n;n=n+1|0;z=c[t+((n&15)<<2)>>2]|0;b=c[t+((A+14&15)<<2)>>2]|0;C=((g>>>6|g<<26)^(g>>>11|g<<21)^(g>>>25|g<<7))+h+(j&~g^k&g)+(c[37828+(A<<2)>>2]|0)|0;B=t+((A&15)<<2)|0;b=((z>>>18|z<<14)^z>>>3^(z>>>7|z<<25))+(c[t+((A+9&15)<<2)>>2]|0)+(c[B>>2]|0)+((b>>>19|b<<13)^b>>>10^(b>>>17|b<<15))|0;c[B>>2]=b;b=C+b|0;a=b+a|0;b=((m>>>2|m<<30)^(m>>>13|m<<19)^(m>>>22|m<<10))+(m&(f^e)^f&e)+b|0;if((n|0)==64)break;else{o=m;z=e;A=f;B=g;C=k;h=j;m=b;g=a;e=o;f=z;a=A;k=B;j=C}}c[d>>2]=u+b;c[d+4>>2]=(c[v>>2]|0)+m;c[d+8>>2]=(c[w>>2]|0)+e;c[d+12>>2]=(c[x>>2]|0)+f;c[d+16>>2]=(c[q>>2]|0)+a;c[d+20>>2]=(c[r>>2]|0)+g;c[d+24>>2]=(c[s>>2]|0)+k;c[d+28>>2]=(c[p>>2]|0)+j;i=y;return}function Bb(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0;do if(e|0){n=b+32|0;g=n;h=c[g>>2]|0;g=c[g+4>>2]|0;f=jc(h|0,g|0,3)|0;f=f&63;if(f){i=64-f|0;j=b+40|0;f=j+f|0;if(i>>>0>e>>>0){qc(f|0,d|0,e|0)|0;b=nc(h|0,g|0,e<<3|0,0)|0;c[n>>2]=b;c[n+4>>2]=C;break}qc(f|0,d|0,i|0)|0;m=nc(h|0,g|0,i<<3|0,0)|0;f=n;c[f>>2]=m;c[f+4>>2]=C;e=e-i|0;f=0;do{m=b+40+(f<<2)|0;c[m>>2]=pc(c[m>>2]|0)|0;f=f+1|0}while((f|0)!=16);Ab(b,j,b);d=d+i|0}if(e>>>0>63){j=b+40|0;l=e+-64|0;m=l&-64;k=m+64|0;i=d;while(1){f=j;g=i;h=f+64|0;do{a[f>>0]=a[g>>0]|0;f=f+1|0;g=g+1|0}while((f|0)<(h|0));f=0;do{h=b+40+(f<<2)|0;c[h>>2]=pc(c[h>>2]|0)|0;f=f+1|0}while((f|0)!=16);Ab(b,j,b);g=n;g=nc(c[g>>2]|0,c[g+4>>2]|0,512,0)|0;h=n;c[h>>2]=g;c[h+4>>2]=C;e=e+-64|0;if(e>>>0<=63)break;else i=i+64|0}d=d+k|0;e=l-m|0}if(e|0){qc(b+40|0,d|0,e|0)|0;b=n;b=nc(c[b>>2]|0,c[b+4>>2]|0,e<<3|0,0)|0;c[n>>2]=b;c[n+4>>2]=C}}while(0);return}function Cb(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0;if(d){h=b+32|0;f=h;f=jc(c[f>>2]|0,c[f+4>>2]|0,3)|0;f=f&63;e=f+1|0;g=b+40|0;a[g+f>>0]=-128;if(e>>>0>56){ic(g+e|0,0,f^63|0)|0;e=0;do{f=b+40+(e<<2)|0;c[f>>2]=pc(c[f>>2]|0)|0;e=e+1|0}while((e|0)!=16);Ab(b,g,b);e=0}ic(g+e|0,0,56-e|0)|0;e=0;do{f=b+40+(e<<2)|0;c[f>>2]=pc(c[f>>2]|0)|0;e=e+1|0}while((e|0)!=14);e=c[h>>2]|0;c[b+96>>2]=c[h+4>>2];c[b+100>>2]=e;Ab(b,g,b);e=0;do{h=b+(e<<2)|0;c[h>>2]=pc(c[h>>2]|0)|0;e=e+1|0}while((e|0)!=8);e=d;f=b;g=e+32|0;do{a[e>>0]=a[f>>0]|0;e=e+1|0;f=f+1|0}while((e|0)<(g|0))}e=b;g=e+104|0;do{c[e>>2]=0;e=e+4|0}while((e|0)<(g|0));return}function Db(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0;g=i;i=i+112|0;e=g;c[e>>2]=c[9449];c[e+4>>2]=c[9450];c[e+8>>2]=c[9451];c[e+12>>2]=c[9452];c[e+16>>2]=c[9453];c[e+20>>2]=c[9454];c[e+24>>2]=c[9455];c[e+28>>2]=c[9456];f=e+32|0;h=f+72|0;do{c[f>>2]=0;f=f+4|0}while((f|0)<(h|0));Bb(e,a,b);Cb(e,d);i=g;return}function Eb(a){a=a|0;var b=0,d=0,e=0;if(a|0){b=a;d=8;e=b+64|0;do{c[b>>2]=c[d>>2];b=b+4|0;d=d+4|0}while((b|0)<(e|0));ic(a+64|0,0,144)|0}return}function Fb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0,X=0,Y=0,Z=0,_=0;L=i;i=i+128|0;F=L;K=a;J=c[K>>2]|0;K=c[K+4>>2]|0;B=a+8|0;w=B;D=a+16|0;e=D;E=a+24|0;f=E;G=a+32|0;p=G;H=a+40|0;q=H;I=a+48|0;m=I;A=a+56|0;h=A;j=0;l=J;u=K;t=c[w>>2]|0;z=c[e>>2]|0;w=c[w+4>>2]|0;a=c[e+4>>2]|0;e=c[f>>2]|0;f=c[f+4>>2]|0;o=c[p>>2]|0;p=c[p+4>>2]|0;g=c[h>>2]|0;h=c[h+4>>2]|0;r=c[q>>2]|0;q=c[q+4>>2]|0;k=c[m>>2]|0;m=c[m+4>>2]|0;while(1){v=jc(o|0,p|0,14)|0;N=C;x=kc(o|0,p|0,50)|0;N=N|C;y=jc(o|0,p|0,18)|0;O=C;M=kc(o|0,p|0,46)|0;O=N^(O|C);N=jc(o|0,p|0,41)|0;n=C;s=kc(o|0,p|0,23)|0;n=nc((v|x)^(y|M)^(N|s)|0,O^(n|C)|0,g|0,h|0)|0;n=nc(n|0,C|0,k&~o^r&o|0,m&~p^q&p|0)|0;O=72+(j<<3)|0;O=nc(n|0,C|0,c[O>>2]|0,c[O+4>>2]|0)|0;n=b;g=c[n>>2]|0;n=c[n+4>>2]|0;s=F+(j<<3)|0;c[s>>2]=g;c[s+4>>2]=n;n=nc(O|0,C|0,g|0,n|0)|0;g=C;O=jc(l|0,u|0,28)|0;s=C;N=kc(l|0,u|0,36)|0;s=s|C;M=jc(l|0,u|0,34)|0;y=C;h=kc(l|0,u|0,30)|0;y=s^(y|C);s=jc(l|0,u|0,39)|0;x=C;v=kc(l|0,u|0,25)|0;x=nc((O|N)^(M|h)^(s|v)|0,y^(x|C)|0,l&(z^t)^z&t|0,u&(a^w)^a&w|0)|0;y=C;e=nc(n|0,g|0,e|0,f|0)|0;f=C;g=nc(x|0,y|0,n|0,g|0)|0;n=C;j=j+1|0;if((j|0)==16){y=16;x=e;v=f;s=p;p=g;j=t;h=u;g=w;b=z;break}else{x=p;y=o;h=m;M=k;N=u;O=l;b=b+8|0;l=g;u=n;o=e;p=f;m=q;k=r;q=x;r=y;g=M;f=a;e=z;a=w;w=N;z=t;t=O}}while(1){t=y;y=y+1|0;T=F+((y&15)<<3)|0;W=c[T>>2]|0;T=c[T+4>>2]|0;S=jc(W|0,T|0,1)|0;Q=C;R=kc(W|0,T|0,63)|0;Q=Q|C;V=jc(W|0,T|0,8)|0;O=C;U=kc(W|0,T|0,56)|0;O=O|C;T=jc(W|0,T|0,7)|0;Q=O^C^Q;O=F+((t+14&15)<<3)|0;W=c[O>>2]|0;O=c[O+4>>2]|0;u=jc(W|0,O|0,19)|0;e=C;f=kc(W|0,O|0,45)|0;e=e|C;N=jc(W|0,O|0,61)|0;_=C;w=kc(W|0,O|0,3)|0;_=_|C;O=jc(W|0,O|0,6)|0;e=_^C^e;_=jc(x|0,v|0,14)|0;W=C;Z=kc(x|0,v|0,50)|0;W=W|C;Y=jc(x|0,v|0,18)|0;P=C;X=kc(x|0,v|0,46)|0;P=W^(P|C);W=jc(x|0,v|0,41)|0;z=C;M=kc(x|0,v|0,23)|0;m=nc((_|Z)^(Y|X)^(W|M)|0,P^(z|C)|0,k|0,m|0)|0;m=nc(m|0,C|0,r&~x^o&x|0,q&~v^s&v|0)|0;z=72+(t<<3)|0;z=nc(m|0,C|0,c[z>>2]|0,c[z+4>>2]|0)|0;m=C;P=F+((t+9&15)<<3)|0;t=F+((t&15)<<3)|0;M=t;k=c[M>>2]|0;M=c[M+4>>2]|0;P=nc((V|U)^T^(S|R)|0,Q|0,c[P>>2]|0,c[P+4>>2]|0)|0;M=nc(P|0,C|0,k|0,M|0)|0;e=nc(M|0,C|0,(N|w)^O^(u|f)|0,e|0)|0;f=C;c[t>>2]=e;c[t+4>>2]=f;f=nc(z|0,m|0,e|0,f|0)|0;e=C;m=jc(p|0,n|0,28)|0;z=C;t=kc(p|0,n|0,36)|0;z=z|C;u=jc(p|0,n|0,34)|0;O=C;w=kc(p|0,n|0,30)|0;O=z^(O|C);z=jc(p|0,n|0,39)|0;N=C;M=kc(p|0,n|0,25)|0;N=nc((m|t)^(u|w)^(z|M)|0,O^(N|C)|0,p&(j^l)^j&l|0,n&(g^h)^g&h|0)|0;O=C;a=nc(f|0,e|0,b|0,a|0)|0;b=C;e=nc(N|0,O|0,f|0,e|0)|0;f=C;if((y|0)==80)break;else{X=n;Y=p;Z=v;_=x;m=q;k=r;x=a;v=b;p=e;n=f;a=g;b=j;g=h;h=X;j=l;l=Y;q=s;r=o;s=Z;o=_}}_=nc(J|0,K|0,e|0,f|0)|0;Z=d;c[Z>>2]=_;c[Z+4>>2]=C;Z=B;Z=nc(c[Z>>2]|0,c[Z+4>>2]|0,p|0,n|0)|0;_=d+8|0;c[_>>2]=Z;c[_+4>>2]=C;_=D;_=nc(c[_>>2]|0,c[_+4>>2]|0,l|0,h|0)|0;Z=d+16|0;c[Z>>2]=_;c[Z+4>>2]=C;Z=E;Z=nc(c[Z>>2]|0,c[Z+4>>2]|0,j|0,g|0)|0;_=d+24|0;c[_>>2]=Z;c[_+4>>2]=C;_=G;_=nc(c[_>>2]|0,c[_+4>>2]|0,a|0,b|0)|0;Z=d+32|0;c[Z>>2]=_;c[Z+4>>2]=C;Z=H;Z=nc(c[Z>>2]|0,c[Z+4>>2]|0,x|0,v|0)|0;_=d+40|0;c[_>>2]=Z;c[_+4>>2]=C;_=I;_=nc(c[_>>2]|0,c[_+4>>2]|0,o|0,s|0)|0;Z=d+48|0;c[Z>>2]=_;c[Z+4>>2]=C;Z=A;Z=nc(c[Z>>2]|0,c[Z+4>>2]|0,r|0,q|0)|0;_=d+56|0;c[_>>2]=Z;c[_+4>>2]=C;i=L;return}function Gb(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0;do if(e|0){o=b+64|0;g=o;h=c[g>>2]|0;g=c[g+4>>2]|0;f=jc(h|0,g|0,3)|0;f=f&127;if(f){i=128-f|0;j=b+80|0;f=j+f|0;if(i>>>0>e>>>0){qc(f|0,d|0,e|0)|0;n=e<<3;m=nc(h|0,g|0,n|0,0)|0;l=C;c[o>>2]=m;c[o+4>>2]=l;if(!(l>>>0<0|(l|0)==0&m>>>0>>0))break;o=b+72|0;b=o;b=nc(c[b>>2]|0,c[b+4>>2]|0,1,0)|0;c[o>>2]=b;c[o+4>>2]=C;break}qc(f|0,d|0,i|0)|0;n=i<<3;m=nc(h|0,g|0,n|0,0)|0;l=C;k=o;c[k>>2]=m;c[k+4>>2]=l;if(l>>>0<0|(l|0)==0&m>>>0>>0){n=b+72|0;m=n;m=nc(c[m>>2]|0,c[m+4>>2]|0,1,0)|0;c[n>>2]=m;c[n+4>>2]=C}e=e-i|0;f=0;do{n=b+80+(f<<3)|0;m=n;m=ma(c[m>>2]|0,c[m+4>>2]|0)|0;c[n>>2]=m;c[n+4>>2]=C;f=f+1|0}while((f|0)!=16);Fb(b,j,b);d=d+i|0}if(e>>>0>127){j=b+80|0;k=b+72|0;m=e+-128|0;n=m&-128;l=n+128|0;i=d;while(1){f=j;g=i;h=f+128|0;do{a[f>>0]=a[g>>0]|0;f=f+1|0;g=g+1|0}while((f|0)<(h|0));f=0;do{h=b+80+(f<<3)|0;g=h;g=ma(c[g>>2]|0,c[g+4>>2]|0)|0;c[h>>2]=g;c[h+4>>2]=C;f=f+1|0}while((f|0)!=16);Fb(b,j,b);g=o;h=c[g>>2]|0;g=c[g+4>>2]|0;p=nc(h|0,g|0,1024,0)|0;f=o;c[f>>2]=p;c[f+4>>2]=C;if(g>>>0>4294967295|(g|0)==-1&h>>>0>4294966271){h=k;h=nc(c[h>>2]|0,c[h+4>>2]|0,1,0)|0;p=k;c[p>>2]=h;c[p+4>>2]=C}e=e+-128|0;if(e>>>0<=127)break;else i=i+128|0}d=d+l|0;e=m-n|0}if(e|0?(qc(b+80|0,d|0,e|0)|0,p=e<<3,n=o,n=nc(c[n>>2]|0,c[n+4>>2]|0,p|0,0)|0,m=C,o,c[o>>2]=n,c[o+4>>2]=m,m>>>0<0|(m|0)==0&n>>>0

>>0):0){p=b+72|0;o=p;o=nc(c[o>>2]|0,c[o+4>>2]|0,1,0)|0;c[p>>2]=o;c[p+4>>2]=C}}while(0);return}function Hb(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0;if(d){h=b+64|0;f=h;f=jc(c[f>>2]|0,c[f+4>>2]|0,3)|0;f=f&127;e=f+1|0;g=b+80|0;a[g+f>>0]=-128;if(e>>>0>112){ic(g+e|0,0,f^127|0)|0;e=0;do{f=b+80+(e<<3)|0;i=f;i=ma(c[i>>2]|0,c[i+4>>2]|0)|0;c[f>>2]=i;c[f+4>>2]=C;e=e+1|0}while((e|0)!=16);Fb(b,g,b);e=0}ic(g+e|0,0,112-e|0)|0;e=0;do{i=b+80+(e<<3)|0;f=i;f=ma(c[f>>2]|0,c[f+4>>2]|0)|0;c[i>>2]=f;c[i+4>>2]=C;e=e+1|0}while((e|0)!=14);f=b+72|0;e=c[f+4>>2]|0;i=b+192|0;c[i>>2]=c[f>>2];c[i+4>>2]=e;i=c[h+4>>2]|0;e=b+200|0;c[e>>2]=c[h>>2];c[e+4>>2]=i;Fb(b,g,b);e=0;do{i=b+(e<<3)|0;h=i;h=ma(c[h>>2]|0,c[h+4>>2]|0)|0;c[i>>2]=h;c[i+4>>2]=C;e=e+1|0}while((e|0)!=8);e=d;f=b;g=e+64|0;do{a[e>>0]=a[f>>0]|0;e=e+1|0;f=f+1|0}while((e|0)<(g|0))}ic(b|0,0,208)|0;return}function Ib(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0;g=i;i=i+208|0;e=g;f=e;h=8;j=f+64|0;do{c[f>>2]=c[h>>2];f=f+4|0;h=h+4|0}while((f|0)<(j|0));ic(e+64|0,0,144)|0;Gb(e,a,b);Hb(e,d);i=g;return}function Jb(){var a=0,b=0,d=0;d=i;i=i+16|0;b=d;a=c[9714]|0;if(!a){a=bc(38797,38810)|0;c[9714]=a}if((dc(b,1,4,a)|0)==4){i=d;return c[b>>2]|0}else pa(38812,38828,60,38838);return 0}function Kb(a){a=a|0;var b=0,d=0;b=i;i=i+16|0;d=b;c[d>>2]=c[a+60>>2];a=Nb(ha(6,d|0)|0)|0;i=b;return a|0}function Lb(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0;m=i;i=i+48|0;h=m+16|0;g=m;f=m+32|0;c[f>>2]=d;j=f+4|0;l=b+48|0;n=c[l>>2]|0;c[j>>2]=e-((n|0)!=0&1);k=b+44|0;c[f+8>>2]=c[k>>2];c[f+12>>2]=n;if(!(c[9715]|0)){c[h>>2]=c[b+60>>2];c[h+4>>2]=f;c[h+8>>2]=2;f=Nb(qa(145,h|0)|0)|0}else{ga(1,b|0);c[g>>2]=c[b+60>>2];c[g+4>>2]=f;c[g+8>>2]=2;f=Nb(qa(145,g|0)|0)|0;ba(0)}if((f|0)>=1){j=c[j>>2]|0;if(f>>>0>j>>>0){g=c[k>>2]|0;h=b+4|0;c[h>>2]=g;c[b+8>>2]=g+(f-j);if(!(c[l>>2]|0))f=e;else{c[h>>2]=g+1;a[d+(e+-1)>>0]=a[g>>0]|0;f=e}}}else{c[b>>2]=c[b>>2]|f&48^16;c[b+8>>2]=0;c[b+4>>2]=0}i=m;return f|0}function Mb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0;f=i;i=i+32|0;g=f;e=f+20|0;c[g>>2]=c[a+60>>2];c[g+4>>2]=0;c[g+8>>2]=b;c[g+12>>2]=e;c[g+16>>2]=d;if((Nb(ja(140,g|0)|0)|0)<0){c[e>>2]=-1;a=-1}else a=c[e>>2]|0;i=f;return a|0}function Nb(a){a=a|0;if(a>>>0>4294963200){c[(Ob()|0)>>2]=0-a;a=-1}return a|0}function Ob(){var a=0;if(!(c[9715]|0))a=38904;else a=c[(rc()|0)+64>>2]|0;return a|0}function Pb(a){a=a|0;if(!(c[a+68>>2]|0))Qb(a);return}function Qb(a){a=a|0;return}function Rb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0;q=i;i=i+48|0;n=q+16|0;m=q;j=q+32|0;o=a+28|0;h=c[o>>2]|0;c[j>>2]=h;p=a+20|0;h=(c[p>>2]|0)-h|0;c[j+4>>2]=h;c[j+8>>2]=b;c[j+12>>2]=d;k=a+60|0;l=a+44|0;g=2;b=h+d|0;while(1){if(!(c[9715]|0)){c[n>>2]=c[k>>2];c[n+4>>2]=j;c[n+8>>2]=g;f=Nb(ra(146,n|0)|0)|0}else{ga(2,a|0);c[m>>2]=c[k>>2];c[m+4>>2]=j;c[m+8>>2]=g;f=Nb(ra(146,m|0)|0)|0;ba(0)}if((b|0)==(f|0)){b=6;break}if((f|0)<0){b=8;break}b=b-f|0;e=c[j+4>>2]|0;if(f>>>0<=e>>>0)if((g|0)==2){c[o>>2]=(c[o>>2]|0)+f;g=2;h=j}else h=j;else{h=c[l>>2]|0;c[o>>2]=h;c[p>>2]=h;f=f-e|0;g=g+-1|0;h=j+8|0;e=c[j+12>>2]|0}c[h>>2]=(c[h>>2]|0)+f;c[h+4>>2]=e-f;j=h}if((b|0)==6){n=c[l>>2]|0;c[a+16>>2]=n+(c[a+48>>2]|0);a=n;c[o>>2]=a;c[p>>2]=a}else if((b|0)==8){c[a+16>>2]=0;c[o>>2]=0;c[p>>2]=0;c[a>>2]=c[a>>2]|32;if((g|0)==2)d=0;else d=d-(c[j+4>>2]|0)|0}i=q;return d|0}function Sb(a){a=a|0;if(!(c[a+68>>2]|0))Qb(a);return}function Tb(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0;g=i;i=i+80|0;f=g;c[b+36>>2]=3;if((c[b>>2]&64|0)==0?(c[f>>2]=c[b+60>>2],c[f+4>>2]=21505,c[f+8>>2]=g+12,da(54,f|0)|0):0)a[b+75>>0]=-1;f=Rb(b,d,e)|0;i=g;return f|0}function Ub(b){b=b|0;var d=0,e=0,f=0;f=b;a:do if(!(f&3))e=4;else{d=f;while(1){if(!(a[b>>0]|0)){b=d;break a}b=b+1|0;d=b;if(!(d&3)){e=4;break}}}while(0);if((e|0)==4){while(1){d=c[b>>2]|0;if(!((d&-2139062144^-2139062144)&d+-16843009))b=b+4|0;else break}if((d&255)<<24>>24)do b=b+1|0;while((a[b>>0]|0)!=0)}return b-f|0}function Vb(a){a=a|0;return 0}function Wb(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,i=0;h=d&255;f=(e|0)!=0;a:do if(f&(b&3|0)!=0){g=d&255;while(1){if((a[b>>0]|0)==g<<24>>24){i=6;break a}b=b+1|0;e=e+-1|0;f=(e|0)!=0;if(!(f&(b&3|0)!=0)){i=5;break}}}else i=5;while(0);if((i|0)==5)if(f)i=6;else e=0;b:do if((i|0)==6){g=d&255;if((a[b>>0]|0)!=g<<24>>24){f=R(h,16843009)|0;c:do if(e>>>0>3)while(1){h=c[b>>2]^f;if((h&-2139062144^-2139062144)&h+-16843009|0)break;b=b+4|0;e=e+-4|0;if(e>>>0<=3){i=11;break c}}else i=11;while(0);if((i|0)==11)if(!e){e=0;break}while(1){if((a[b>>0]|0)==g<<24>>24)break b;b=b+1|0;e=e+-1|0;if(!e){e=0;break}}}}while(0);return (e|0?b:0)|0}function Xb(a){a=a|0;var b=0,d=0;do if(a){if((c[a+76>>2]|0)<=-1){b=Yb(a)|0;break}d=(Vb(a)|0)==0;b=Yb(a)|0;if(!d)Qb(a)}else{if(!(c[9549]|0))b=0;else b=Xb(c[9549]|0)|0;ea(38888);a=c[9721]|0;if(a)do{if((c[a+76>>2]|0)>-1)d=Vb(a)|0;else d=0;if((c[a+20>>2]|0)>>>0>(c[a+28>>2]|0)>>>0)b=Yb(a)|0|b;if(d|0)Qb(a);a=c[a+56>>2]|0}while((a|0)!=0);na(38888)}while(0);return b|0}function Yb(a){a=a|0;var b=0,d=0,e=0,f=0,g=0,h=0;b=a+20|0;h=a+28|0;if((c[b>>2]|0)>>>0>(c[h>>2]|0)>>>0?(va[c[a+36>>2]&7](a,0,0)|0,(c[b>>2]|0)==0):0)a=-1;else{d=a+4|0;e=c[d>>2]|0;f=a+8|0;g=c[f>>2]|0;if(e>>>0>>0)va[c[a+40>>2]&7](a,e-g|0,1)|0;c[a+16>>2]=0;c[h>>2]=0;c[b>>2]=0;c[f>>2]=0;c[d>>2]=0;a=0}return a|0}function Zb(b){b=b|0;var d=0,e=0;d=b+74|0;e=a[d>>0]|0;a[d>>0]=e+255|e;d=b+20|0;e=b+44|0;if((c[d>>2]|0)>>>0>(c[e>>2]|0)>>>0)va[c[b+36>>2]&7](b,0,0)|0;c[b+16>>2]=0;c[b+28>>2]=0;c[d>>2]=0;d=c[b>>2]|0;if(d&20)if(!(d&4))d=-1;else{c[b>>2]=d|32;d=-1}else{d=c[e>>2]|0;c[b+8>>2]=d;c[b+4>>2]=d;d=0}return d|0}function _b(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0;o=i;i=i+112|0;n=o+40|0;l=o+24|0;k=o+16|0;g=o;m=o+52|0;f=a[d>>0]|0;if(Wb(38847,f<<24>>24,4)|0){e=ec(1144)|0;if(!e)e=0;else{h=e;j=h+112|0;do{c[h>>2]=0;h=h+4|0}while((h|0)<(j|0));if(!($b(d,43)|0))c[e>>2]=f<<24>>24==114?8:4;if($b(d,101)|0){c[g>>2]=b;c[g+4>>2]=2;c[g+8>>2]=1;ca(221,g|0)|0;f=a[d>>0]|0}if(f<<24>>24==97){c[k>>2]=b;c[k+4>>2]=3;f=ca(221,k|0)|0;if(!(f&1024)){c[l>>2]=b;c[l+4>>2]=4;c[l+8>>2]=f|1024;ca(221,l|0)|0}d=c[e>>2]|128;c[e>>2]=d}else d=c[e>>2]|0;c[e+60>>2]=b;c[e+44>>2]=e+120;c[e+48>>2]=1024;f=e+75|0;a[f>>0]=-1;if((d&8|0)==0?(c[n>>2]=b,c[n+4>>2]=21505,c[n+8>>2]=m,(da(54,n|0)|0)==0):0)a[f>>0]=10;c[e+32>>2]=4;c[e+36>>2]=3;c[e+40>>2]=2;c[e+12>>2]=1;if(!(c[9716]|0))c[e+76>>2]=-1;ea(38888);f=c[9721]|0;c[e+56>>2]=f;if(f|0)c[f+52>>2]=e;c[9721]=e;na(38888)}}else{c[(Ob()|0)>>2]=22;e=0}i=o;return e|0}function $b(b,c){b=b|0;c=c|0;b=ac(b,c)|0;return ((a[b>>0]|0)==(c&255)<<24>>24?b:0)|0}function ac(b,d){b=b|0;d=d|0;var e=0,f=0,g=0;f=d&255;a:do if(!f)b=b+(Ub(b)|0)|0;else{if(b&3){e=d&255;do{g=a[b>>0]|0;if(g<<24>>24==0?1:g<<24>>24==e<<24>>24)break a;b=b+1|0}while((b&3|0)!=0)}f=R(f,16843009)|0;e=c[b>>2]|0;b:do if(!((e&-2139062144^-2139062144)&e+-16843009))do{g=e^f;if((g&-2139062144^-2139062144)&g+-16843009|0)break b;b=b+4|0;e=c[b>>2]|0}while(!((e&-2139062144^-2139062144)&e+-16843009|0));while(0);e=d&255;while(1){g=a[b>>0]|0;if(g<<24>>24==0?1:g<<24>>24==e<<24>>24)break;else b=b+1|0}}while(0);return b|0}function bc(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0;g=i;i=i+32|0;f=g+16|0;e=g;if(Wb(38847,a[d>>0]|0,4)|0){h=cc(d)|0|32768;c[e>>2]=b;c[e+4>>2]=h;c[e+8>>2]=438;e=Nb(ka(5,e|0)|0)|0;if((e|0)>=0){b=_b(e,d)|0;if(!b){c[f>>2]=e;ha(6,f|0)|0;b=0}}else b=0}else{c[(Ob()|0)>>2]=22;b=0}i=g;return b|0}function cc(b){b=b|0;var c=0,d=0,e=0;d=($b(b,43)|0)==0;c=a[b>>0]|0;d=d?c<<24>>24!=114&1:2;e=($b(b,120)|0)==0;d=e?d:d|128;b=($b(b,101)|0)==0;b=b?d:d|524288;b=c<<24>>24==114?b:b|64;b=c<<24>>24==119?b|512:b;return (c<<24>>24==97?b|1024:b)|0}function dc(b,d,e,f){b=b|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,i=0,j=0,k=0,l=0;k=R(e,d)|0;if((c[f+76>>2]|0)>-1)j=Vb(f)|0;else j=0;g=f+74|0;i=a[g>>0]|0;a[g>>0]=i+255|i;g=f+4|0;i=c[g>>2]|0;h=(c[f+8>>2]|0)-i|0;if((h|0)>0){h=h>>>0>>0?h:k;qc(b|0,i|0,h|0)|0;c[g>>2]=i+h;g=k-h|0;b=b+h|0}else g=k;a:do if(!g)l=13;else{i=f+32|0;while(1){if(Zb(f)|0)break;h=va[c[i>>2]&7](f,b,g)|0;if((h+1|0)>>>0<2)break;g=g-h|0;if(!g){l=13;break a}else b=b+h|0}if(j|0)Qb(f);e=((k-g|0)>>>0)/(d>>>0)|0}while(0);if((l|0)==13)if(j)Qb(f);return e|0}function ec(a){a=a|0;var b=0,d=0,e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0;L=i;i=i+16|0;p=L;do if(a>>>0<245){o=a>>>0<11?16:a+11&-8;a=o>>>3;t=c[9727]|0;d=t>>>a;if(d&3|0){a=(d&1^1)+a|0;d=38948+(a<<1<<2)|0;e=d+8|0;f=c[e>>2]|0;g=f+8|0;h=c[g>>2]|0;do if((d|0)!=(h|0)){if(h>>>0<(c[9731]|0)>>>0)fa();b=h+12|0;if((c[b>>2]|0)==(f|0)){c[b>>2]=d;c[e>>2]=h;break}else fa()}else c[9727]=t&~(1<>2]=K|3;K=f+K+4|0;c[K>>2]=c[K>>2]|1;K=g;i=L;return K|0}s=c[9729]|0;if(o>>>0>s>>>0){if(d|0){j=2<>>12&16;a=a>>>j;e=a>>>5&8;a=a>>>e;g=a>>>2&4;a=a>>>g;d=a>>>1&2;a=a>>>d;b=a>>>1&1;b=(e|j|g|d|b)+(a>>>b)|0;a=38948+(b<<1<<2)|0;d=a+8|0;g=c[d>>2]|0;j=g+8|0;e=c[j>>2]|0;do if((a|0)!=(e|0)){if(e>>>0<(c[9731]|0)>>>0)fa();f=e+12|0;if((c[f>>2]|0)==(g|0)){c[f>>2]=a;c[d>>2]=e;k=t;break}else fa()}else{k=t&~(1<>2]=o|3;e=g+o|0;c[e+4>>2]=h|1;c[e+h>>2]=h;if(s|0){f=c[9732]|0;b=s>>>3;d=38948+(b<<1<<2)|0;b=1<>2]|0;if(a>>>0<(c[9731]|0)>>>0)fa();else{l=a;m=b}}else{c[9727]=k|b;l=d;m=d+8|0}c[m>>2]=f;c[l+12>>2]=f;c[f+8>>2]=l;c[f+12>>2]=d}c[9729]=h;c[9732]=e;K=j;i=L;return K|0}l=c[9728]|0;if(l){a=(l&0-l)+-1|0;J=a>>>12&16;a=a>>>J;I=a>>>5&8;a=a>>>I;K=a>>>2&4;a=a>>>K;j=a>>>1&2;a=a>>>j;k=a>>>1&1;k=c[39212+((I|J|K|j|k)+(a>>>k)<<2)>>2]|0;a=k;j=k;k=(c[k+4>>2]&-8)-o|0;while(1){b=c[a+16>>2]|0;if(!b){b=c[a+20>>2]|0;if(!b)break}K=(c[b+4>>2]&-8)-o|0;J=K>>>0>>0;a=b;j=J?b:j;k=J?K:k}f=c[9731]|0;if(j>>>0>>0)fa();h=j+o|0;if(j>>>0>=h>>>0)fa();g=c[j+24>>2]|0;d=c[j+12>>2]|0;do if((d|0)==(j|0)){a=j+20|0;b=c[a>>2]|0;if(!b){a=j+16|0;b=c[a>>2]|0;if(!b){n=0;break}}while(1){d=b+20|0;e=c[d>>2]|0;if(e|0){b=e;a=d;continue}d=b+16|0;e=c[d>>2]|0;if(!e)break;else{b=e;a=d}}if(a>>>0>>0)fa();else{c[a>>2]=0;n=b;break}}else{e=c[j+8>>2]|0;if(e>>>0>>0)fa();b=e+12|0;if((c[b>>2]|0)!=(j|0))fa();a=d+8|0;if((c[a>>2]|0)==(j|0)){c[b>>2]=d;c[a>>2]=e;n=d;break}else fa()}while(0);do if(g|0){b=c[j+28>>2]|0;a=39212+(b<<2)|0;if((j|0)==(c[a>>2]|0)){c[a>>2]=n;if(!n){c[9728]=l&~(1<>>0<(c[9731]|0)>>>0)fa();b=g+16|0;if((c[b>>2]|0)==(j|0))c[b>>2]=n;else c[g+20>>2]=n;if(!n)break}a=c[9731]|0;if(n>>>0>>0)fa();c[n+24>>2]=g;b=c[j+16>>2]|0;do if(b|0)if(b>>>0>>0)fa();else{c[n+16>>2]=b;c[b+24>>2]=n;break}while(0);b=c[j+20>>2]|0;if(b|0)if(b>>>0<(c[9731]|0)>>>0)fa();else{c[n+20>>2]=b;c[b+24>>2]=n;break}}while(0);if(k>>>0<16){K=k+o|0;c[j+4>>2]=K|3;K=j+K+4|0;c[K>>2]=c[K>>2]|1}else{c[j+4>>2]=o|3;c[h+4>>2]=k|1;c[h+k>>2]=k;if(s|0){e=c[9732]|0;b=s>>>3;d=38948+(b<<1<<2)|0;b=1<>2]|0;if(a>>>0<(c[9731]|0)>>>0)fa();else{q=a;r=b}}else{c[9727]=t|b;q=d;r=d+8|0}c[r>>2]=e;c[q+12>>2]=e;c[e+8>>2]=q;c[e+12>>2]=d}c[9729]=k;c[9732]=h}K=j+8|0;i=L;return K|0}}}else if(a>>>0<=4294967231){a=a+11|0;o=a&-8;l=c[9728]|0;if(l){e=0-o|0;a=a>>>8;if(a)if(o>>>0>16777215)k=31;else{r=(a+1048320|0)>>>16&8;D=a<>>16&4;D=D<>>16&2;k=14-(q|r|k)+(D<>>15)|0;k=o>>>(k+7|0)&1|k<<1}else k=0;a=c[39212+(k<<2)>>2]|0;a:do if(!a){d=0;f=0;D=86}else{f=0;j=a;h=o<<((k|0)==31?0:25-(k>>>1)|0);d=0;while(1){a=(c[j+4>>2]&-8)-o|0;if(a>>>0>>0)if(!a){a=j;e=0;d=j;D=90;break a}else{f=j;e=a}a=c[j+20>>2]|0;j=c[j+16+(h>>>31<<2)>>2]|0;d=(a|0)==0|(a|0)==(j|0)?d:a;a=(j|0)==0;if(a){D=86;break}else h=h<<(a&1^1)}}while(0);if((D|0)==86){if((d|0)==0&(f|0)==0){a=2<>>12&16;r=r>>>m;k=r>>>5&8;r=r>>>k;n=r>>>2&4;r=r>>>n;q=r>>>1&2;r=r>>>q;d=r>>>1&1;d=c[39212+((k|m|n|q|d)+(r>>>d)<<2)>>2]|0}if(!d){k=f;j=e}else{a=f;D=90}}if((D|0)==90)while(1){D=0;r=(c[d+4>>2]&-8)-o|0;f=r>>>0>>0;e=f?r:e;a=f?d:a;f=c[d+16>>2]|0;if(f|0){d=f;D=90;continue}d=c[d+20>>2]|0;if(!d){k=a;j=e;break}else D=90}if((k|0)!=0?j>>>0<((c[9729]|0)-o|0)>>>0:0){f=c[9731]|0;if(k>>>0>>0)fa();h=k+o|0;if(k>>>0>=h>>>0)fa();g=c[k+24>>2]|0;d=c[k+12>>2]|0;do if((d|0)==(k|0)){a=k+20|0;b=c[a>>2]|0;if(!b){a=k+16|0;b=c[a>>2]|0;if(!b){s=0;break}}while(1){d=b+20|0;e=c[d>>2]|0;if(e|0){b=e;a=d;continue}d=b+16|0;e=c[d>>2]|0;if(!e)break;else{b=e;a=d}}if(a>>>0>>0)fa();else{c[a>>2]=0;s=b;break}}else{e=c[k+8>>2]|0;if(e>>>0>>0)fa();b=e+12|0;if((c[b>>2]|0)!=(k|0))fa();a=d+8|0;if((c[a>>2]|0)==(k|0)){c[b>>2]=d;c[a>>2]=e;s=d;break}else fa()}while(0);do if(g){b=c[k+28>>2]|0;a=39212+(b<<2)|0;if((k|0)==(c[a>>2]|0)){c[a>>2]=s;if(!s){t=l&~(1<>>0<(c[9731]|0)>>>0)fa();b=g+16|0;if((c[b>>2]|0)==(k|0))c[b>>2]=s;else c[g+20>>2]=s;if(!s){t=l;break}}a=c[9731]|0;if(s>>>0>>0)fa();c[s+24>>2]=g;b=c[k+16>>2]|0;do if(b|0)if(b>>>0>>0)fa();else{c[s+16>>2]=b;c[b+24>>2]=s;break}while(0);b=c[k+20>>2]|0;if(b)if(b>>>0<(c[9731]|0)>>>0)fa();else{c[s+20>>2]=b;c[b+24>>2]=s;t=l;break}else t=l}else t=l;while(0);do if(j>>>0>=16){c[k+4>>2]=o|3;c[h+4>>2]=j|1;c[h+j>>2]=j;b=j>>>3;if(j>>>0<256){d=38948+(b<<1<<2)|0;a=c[9727]|0;b=1<>2]|0;if(a>>>0<(c[9731]|0)>>>0)fa();else{B=a;C=b}}else{c[9727]=a|b;B=d;C=d+8|0}c[C>>2]=h;c[B+12>>2]=h;c[h+8>>2]=B;c[h+12>>2]=d;break}b=j>>>8;if(b)if(j>>>0>16777215)b=31;else{J=(b+1048320|0)>>>16&8;K=b<>>16&4;K=K<>>16&2;b=14-(I|J|b)+(K<>>15)|0;b=j>>>(b+7|0)&1|b<<1}else b=0;d=39212+(b<<2)|0;c[h+28>>2]=b;a=h+16|0;c[a+4>>2]=0;c[a>>2]=0;a=1<>2]=h;c[h+24>>2]=d;c[h+12>>2]=h;c[h+8>>2]=h;break}a=j<<((b|0)==31?0:25-(b>>>1)|0);e=c[d>>2]|0;while(1){if((c[e+4>>2]&-8|0)==(j|0)){D=148;break}d=e+16+(a>>>31<<2)|0;b=c[d>>2]|0;if(!b){D=145;break}else{a=a<<1;e=b}}if((D|0)==145)if(d>>>0<(c[9731]|0)>>>0)fa();else{c[d>>2]=h;c[h+24>>2]=e;c[h+12>>2]=h;c[h+8>>2]=h;break}else if((D|0)==148){b=e+8|0;a=c[b>>2]|0;K=c[9731]|0;if(a>>>0>=K>>>0&e>>>0>=K>>>0){c[a+12>>2]=h;c[b>>2]=h;c[h+8>>2]=a;c[h+12>>2]=e;c[h+24>>2]=0;break}else fa()}}else{K=j+o|0;c[k+4>>2]=K|3;K=k+K+4|0;c[K>>2]=c[K>>2]|1}while(0);K=k+8|0;i=L;return K|0}}}else o=-1;while(0);d=c[9729]|0;if(d>>>0>=o>>>0){b=d-o|0;a=c[9732]|0;if(b>>>0>15){K=a+o|0;c[9732]=K;c[9729]=b;c[K+4>>2]=b|1;c[K+b>>2]=b;c[a+4>>2]=o|3}else{c[9729]=0;c[9732]=0;c[a+4>>2]=d|3;K=a+d+4|0;c[K>>2]=c[K>>2]|1}K=a+8|0;i=L;return K|0}j=c[9730]|0;if(j>>>0>o>>>0){I=j-o|0;c[9730]=I;K=c[9733]|0;J=K+o|0;c[9733]=J;c[J+4>>2]=I|1;c[K+4>>2]=o|3;K=K+8|0;i=L;return K|0}if(!(c[9845]|0)){c[9847]=4096;c[9846]=4096;c[9848]=-1;c[9849]=-1;c[9850]=0;c[9838]=0;a=p&-16^1431655768;c[p>>2]=a;c[9845]=a;a=4096}else a=c[9847]|0;k=o+48|0;l=o+47|0;h=a+l|0;f=0-a|0;m=h&f;if(m>>>0<=o>>>0){K=0;i=L;return K|0}a=c[9837]|0;if(a|0?(B=c[9835]|0,C=B+m|0,C>>>0<=B>>>0|C>>>0>a>>>0):0){K=0;i=L;return K|0}b:do if(!(c[9838]&4)){d=c[9733]|0;c:do if(d){e=39356;while(1){a=c[e>>2]|0;if(a>>>0<=d>>>0?(u=e+4|0,(a+(c[u>>2]|0)|0)>>>0>d>>>0):0)break;a=c[e+8>>2]|0;if(!a){D=172;break c}else e=a}d=h-j&f;if(d>>>0<2147483647){a=oc(d|0)|0;if((a|0)==((c[e>>2]|0)+(c[u>>2]|0)|0)){if((a|0)!=(-1|0)){h=d;g=a;D=190;break b}}else{b=d;D=180}}}else D=172;while(0);do if(((D|0)==172?(g=oc(0)|0,(g|0)!=(-1|0)):0)?(b=g,v=c[9846]|0,w=v+-1|0,b=((w&b|0)==0?0:(w+b&0-v)-b|0)+m|0,v=c[9835]|0,w=b+v|0,b>>>0>o>>>0&b>>>0<2147483647):0){C=c[9837]|0;if(C|0?w>>>0<=v>>>0|w>>>0>C>>>0:0)break;a=oc(b|0)|0;if((a|0)==(g|0)){h=b;D=190;break b}else D=180}while(0);d:do if((D|0)==180){d=0-b|0;do if(k>>>0>b>>>0&(b>>>0<2147483647&(a|0)!=(-1|0))?(x=c[9847]|0,x=l-b+x&0-x,x>>>0<2147483647):0)if((oc(x|0)|0)==(-1|0)){oc(d|0)|0;break d}else{b=x+b|0;break}while(0);if((a|0)!=(-1|0)){h=b;g=a;D=190;break b}}while(0);c[9838]=c[9838]|4;D=187}else D=187;while(0);if((((D|0)==187?m>>>0<2147483647:0)?(A=oc(m|0)|0,y=oc(0)|0,A>>>0>>0&((A|0)!=(-1|0)&(y|0)!=(-1|0))):0)?(z=y-A|0,z>>>0>(o+40|0)>>>0):0){h=z;g=A;D=190}if((D|0)==190){b=(c[9835]|0)+h|0;c[9835]=b;if(b>>>0>(c[9836]|0)>>>0)c[9836]=b;l=c[9733]|0;do if(l){b=39356;while(1){a=c[b>>2]|0;d=b+4|0;e=c[d>>2]|0;if((g|0)==(a+e|0)){D=200;break}f=c[b+8>>2]|0;if(!f)break;else b=f}if(((D|0)==200?(c[b+12>>2]&8|0)==0:0)?l>>>0>>0&l>>>0>=a>>>0:0){c[d>>2]=e+h;K=l+8|0;K=(K&7|0)==0?0:0-K&7;J=l+K|0;K=h-K+(c[9730]|0)|0;c[9733]=J;c[9730]=K;c[J+4>>2]=K|1;c[J+K+4>>2]=40;c[9734]=c[9849];break}b=c[9731]|0;if(g>>>0>>0){c[9731]=g;j=g}else j=b;a=g+h|0;b=39356;while(1){if((c[b>>2]|0)==(a|0)){D=208;break}b=c[b+8>>2]|0;if(!b){a=39356;break}}if((D|0)==208)if(!(c[b+12>>2]&8)){c[b>>2]=g;n=b+4|0;c[n>>2]=(c[n>>2]|0)+h;n=g+8|0;n=g+((n&7|0)==0?0:0-n&7)|0;b=a+8|0;b=a+((b&7|0)==0?0:0-b&7)|0;m=n+o|0;k=b-n-o|0;c[n+4>>2]=o|3;do if((b|0)!=(l|0)){if((b|0)==(c[9732]|0)){K=(c[9729]|0)+k|0;c[9729]=K;c[9732]=m;c[m+4>>2]=K|1;c[m+K>>2]=K;break}a=c[b+4>>2]|0;if((a&3|0)==1){h=a&-8;f=a>>>3;e:do if(a>>>0>=256){g=c[b+24>>2]|0;e=c[b+12>>2]|0;do if((e|0)==(b|0)){e=b+16|0;d=e+4|0;a=c[d>>2]|0;if(!a){a=c[e>>2]|0;if(!a){I=0;break}else d=e}while(1){e=a+20|0;f=c[e>>2]|0;if(f|0){a=f;d=e;continue}e=a+16|0;f=c[e>>2]|0;if(!f)break;else{a=f;d=e}}if(d>>>0>>0)fa();else{c[d>>2]=0;I=a;break}}else{f=c[b+8>>2]|0;if(f>>>0>>0)fa();a=f+12|0;if((c[a>>2]|0)!=(b|0))fa();d=e+8|0;if((c[d>>2]|0)==(b|0)){c[a>>2]=e;c[d>>2]=f;I=e;break}else fa()}while(0);if(!g)break;a=c[b+28>>2]|0;d=39212+(a<<2)|0;do if((b|0)!=(c[d>>2]|0)){if(g>>>0<(c[9731]|0)>>>0)fa();a=g+16|0;if((c[a>>2]|0)==(b|0))c[a>>2]=I;else c[g+20>>2]=I;if(!I)break e}else{c[d>>2]=I;if(I|0)break;c[9728]=c[9728]&~(1<>>0>>0)fa();c[I+24>>2]=g;a=b+16|0;d=c[a>>2]|0;do if(d|0)if(d>>>0>>0)fa();else{c[I+16>>2]=d;c[d+24>>2]=I;break}while(0);a=c[a+4>>2]|0;if(!a)break;if(a>>>0<(c[9731]|0)>>>0)fa();else{c[I+20>>2]=a;c[a+24>>2]=I;break}}else{d=c[b+8>>2]|0;e=c[b+12>>2]|0;a=38948+(f<<1<<2)|0;do if((d|0)!=(a|0)){if(d>>>0>>0)fa();if((c[d+12>>2]|0)==(b|0))break;fa()}while(0);if((e|0)==(d|0)){c[9727]=c[9727]&~(1<>>0>>0)fa();a=e+8|0;if((c[a>>2]|0)==(b|0)){F=a;break}fa()}while(0);c[d+12>>2]=e;c[F>>2]=d}while(0);b=b+h|0;f=h+k|0}else f=k;b=b+4|0;c[b>>2]=c[b>>2]&-2;c[m+4>>2]=f|1;c[m+f>>2]=f;b=f>>>3;if(f>>>0<256){d=38948+(b<<1<<2)|0;a=c[9727]|0;b=1<>2]|0;if(a>>>0>=(c[9731]|0)>>>0){J=a;K=b;break}fa()}while(0);c[K>>2]=m;c[J+12>>2]=m;c[m+8>>2]=J;c[m+12>>2]=d;break}b=f>>>8;do if(!b)b=0;else{if(f>>>0>16777215){b=31;break}J=(b+1048320|0)>>>16&8;K=b<>>16&4;K=K<>>16&2;b=14-(I|J|b)+(K<>>15)|0;b=f>>>(b+7|0)&1|b<<1}while(0);e=39212+(b<<2)|0;c[m+28>>2]=b;a=m+16|0;c[a+4>>2]=0;c[a>>2]=0;a=c[9728]|0;d=1<>2]=m;c[m+24>>2]=e;c[m+12>>2]=m;c[m+8>>2]=m;break}a=f<<((b|0)==31?0:25-(b>>>1)|0);e=c[e>>2]|0;while(1){if((c[e+4>>2]&-8|0)==(f|0)){D=278;break}d=e+16+(a>>>31<<2)|0;b=c[d>>2]|0;if(!b){D=275;break}else{a=a<<1;e=b}}if((D|0)==275)if(d>>>0<(c[9731]|0)>>>0)fa();else{c[d>>2]=m;c[m+24>>2]=e;c[m+12>>2]=m;c[m+8>>2]=m;break}else if((D|0)==278){b=e+8|0;a=c[b>>2]|0;K=c[9731]|0;if(a>>>0>=K>>>0&e>>>0>=K>>>0){c[a+12>>2]=m;c[b>>2]=m;c[m+8>>2]=a;c[m+12>>2]=e;c[m+24>>2]=0;break}else fa()}}else{K=(c[9730]|0)+k|0;c[9730]=K;c[9733]=m;c[m+4>>2]=K|1}while(0);K=n+8|0;i=L;return K|0}else a=39356;while(1){b=c[a>>2]|0;if(b>>>0<=l>>>0?(E=b+(c[a+4>>2]|0)|0,E>>>0>l>>>0):0)break;a=c[a+8>>2]|0}f=E+-47|0;a=f+8|0;a=f+((a&7|0)==0?0:0-a&7)|0;f=l+16|0;a=a>>>0>>0?l:a;b=a+8|0;d=g+8|0;d=(d&7|0)==0?0:0-d&7;K=g+d|0;d=h+-40-d|0;c[9733]=K;c[9730]=d;c[K+4>>2]=d|1;c[K+d+4>>2]=40;c[9734]=c[9849];d=a+4|0;c[d>>2]=27;c[b>>2]=c[9839];c[b+4>>2]=c[9840];c[b+8>>2]=c[9841];c[b+12>>2]=c[9842];c[9839]=g;c[9840]=h;c[9842]=0;c[9841]=b;b=a+24|0;do{b=b+4|0;c[b>>2]=7}while((b+4|0)>>>0>>0);if((a|0)!=(l|0)){g=a-l|0;c[d>>2]=c[d>>2]&-2;c[l+4>>2]=g|1;c[a>>2]=g;b=g>>>3;if(g>>>0<256){d=38948+(b<<1<<2)|0;a=c[9727]|0;b=1<>2]|0;if(a>>>0<(c[9731]|0)>>>0)fa();else{G=a;H=b}}else{c[9727]=a|b;G=d;H=d+8|0}c[H>>2]=l;c[G+12>>2]=l;c[l+8>>2]=G;c[l+12>>2]=d;break}b=g>>>8;if(b)if(g>>>0>16777215)d=31;else{J=(b+1048320|0)>>>16&8;K=b<>>16&4;K=K<>>16&2;d=14-(I|J|d)+(K<>>15)|0;d=g>>>(d+7|0)&1|d<<1}else d=0;e=39212+(d<<2)|0;c[l+28>>2]=d;c[l+20>>2]=0;c[f>>2]=0;b=c[9728]|0;a=1<>2]=l;c[l+24>>2]=e;c[l+12>>2]=l;c[l+8>>2]=l;break}a=g<<((d|0)==31?0:25-(d>>>1)|0);e=c[e>>2]|0;while(1){if((c[e+4>>2]&-8|0)==(g|0)){D=304;break}d=e+16+(a>>>31<<2)|0;b=c[d>>2]|0;if(!b){D=301;break}else{a=a<<1;e=b}}if((D|0)==301)if(d>>>0<(c[9731]|0)>>>0)fa();else{c[d>>2]=l;c[l+24>>2]=e;c[l+12>>2]=l;c[l+8>>2]=l;break}else if((D|0)==304){b=e+8|0;a=c[b>>2]|0;K=c[9731]|0;if(a>>>0>=K>>>0&e>>>0>=K>>>0){c[a+12>>2]=l;c[b>>2]=l;c[l+8>>2]=a;c[l+12>>2]=e;c[l+24>>2]=0;break}else fa()}}}else{K=c[9731]|0;if((K|0)==0|g>>>0>>0)c[9731]=g;c[9839]=g;c[9840]=h;c[9842]=0;c[9736]=c[9845];c[9735]=-1;b=0;do{K=38948+(b<<1<<2)|0;c[K+12>>2]=K;c[K+8>>2]=K;b=b+1|0}while((b|0)!=32);K=g+8|0;K=(K&7|0)==0?0:0-K&7;J=g+K|0;K=h+-40-K|0;c[9733]=J;c[9730]=K;c[J+4>>2]=K|1;c[J+K+4>>2]=40;c[9734]=c[9849]}while(0);b=c[9730]|0;if(b>>>0>o>>>0){I=b-o|0;c[9730]=I;K=c[9733]|0;J=K+o|0;c[9733]=J;c[J+4>>2]=I|1;c[K+4>>2]=o|3;K=K+8|0;i=L;return K|0}}c[(Ob()|0)>>2]=12;K=0;i=L;return K|0}function fc(a){a=a|0;var b=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0;if(!a)return;d=a+-8|0;h=c[9731]|0;if(d>>>0>>0)fa();a=c[a+-4>>2]|0;b=a&3;if((b|0)==1)fa();e=a&-8;n=d+e|0;do if(!(a&1)){a=c[d>>2]|0;if(!b)return;k=d+(0-a)|0;j=a+e|0;if(k>>>0>>0)fa();if((k|0)==(c[9732]|0)){a=n+4|0;b=c[a>>2]|0;if((b&3|0)!=3){q=k;f=j;break}c[9729]=j;c[a>>2]=b&-2;c[k+4>>2]=j|1;c[k+j>>2]=j;return}e=a>>>3;if(a>>>0<256){b=c[k+8>>2]|0;d=c[k+12>>2]|0;a=38948+(e<<1<<2)|0;if((b|0)!=(a|0)){if(b>>>0>>0)fa();if((c[b+12>>2]|0)!=(k|0))fa()}if((d|0)==(b|0)){c[9727]=c[9727]&~(1<>>0>>0)fa();a=d+8|0;if((c[a>>2]|0)==(k|0))g=a;else fa()}else g=d+8|0;c[b+12>>2]=d;c[g>>2]=b;q=k;f=j;break}g=c[k+24>>2]|0;d=c[k+12>>2]|0;do if((d|0)==(k|0)){d=k+16|0;b=d+4|0;a=c[b>>2]|0;if(!a){a=c[d>>2]|0;if(!a){i=0;break}else b=d}while(1){d=a+20|0;e=c[d>>2]|0;if(e|0){a=e;b=d;continue}d=a+16|0;e=c[d>>2]|0;if(!e)break;else{a=e;b=d}}if(b>>>0>>0)fa();else{c[b>>2]=0;i=a;break}}else{e=c[k+8>>2]|0;if(e>>>0>>0)fa();a=e+12|0;if((c[a>>2]|0)!=(k|0))fa();b=d+8|0;if((c[b>>2]|0)==(k|0)){c[a>>2]=d;c[b>>2]=e;i=d;break}else fa()}while(0);if(g){a=c[k+28>>2]|0;b=39212+(a<<2)|0;if((k|0)==(c[b>>2]|0)){c[b>>2]=i;if(!i){c[9728]=c[9728]&~(1<>>0<(c[9731]|0)>>>0)fa();a=g+16|0;if((c[a>>2]|0)==(k|0))c[a>>2]=i;else c[g+20>>2]=i;if(!i){q=k;f=j;break}}d=c[9731]|0;if(i>>>0>>0)fa();c[i+24>>2]=g;a=k+16|0;b=c[a>>2]|0;do if(b|0)if(b>>>0>>0)fa();else{c[i+16>>2]=b;c[b+24>>2]=i;break}while(0);a=c[a+4>>2]|0;if(a)if(a>>>0<(c[9731]|0)>>>0)fa();else{c[i+20>>2]=a;c[a+24>>2]=i;q=k;f=j;break}else{q=k;f=j}}else{q=k;f=j}}else{q=d;f=e}while(0);if(q>>>0>=n>>>0)fa();a=n+4|0;b=c[a>>2]|0;if(!(b&1))fa();if(!(b&2)){if((n|0)==(c[9733]|0)){p=(c[9730]|0)+f|0;c[9730]=p;c[9733]=q;c[q+4>>2]=p|1;if((q|0)!=(c[9732]|0))return;c[9732]=0;c[9729]=0;return}if((n|0)==(c[9732]|0)){p=(c[9729]|0)+f|0;c[9729]=p;c[9732]=q;c[q+4>>2]=p|1;c[q+p>>2]=p;return}f=(b&-8)+f|0;e=b>>>3;do if(b>>>0>=256){g=c[n+24>>2]|0;a=c[n+12>>2]|0;do if((a|0)==(n|0)){d=n+16|0;b=d+4|0;a=c[b>>2]|0;if(!a){a=c[d>>2]|0;if(!a){m=0;break}else b=d}while(1){d=a+20|0;e=c[d>>2]|0;if(e|0){a=e;b=d;continue}d=a+16|0;e=c[d>>2]|0;if(!e)break;else{a=e;b=d}}if(b>>>0<(c[9731]|0)>>>0)fa();else{c[b>>2]=0;m=a;break}}else{b=c[n+8>>2]|0;if(b>>>0<(c[9731]|0)>>>0)fa();d=b+12|0;if((c[d>>2]|0)!=(n|0))fa();e=a+8|0;if((c[e>>2]|0)==(n|0)){c[d>>2]=a;c[e>>2]=b;m=a;break}else fa()}while(0);if(g|0){a=c[n+28>>2]|0;b=39212+(a<<2)|0;if((n|0)==(c[b>>2]|0)){c[b>>2]=m;if(!m){c[9728]=c[9728]&~(1<>>0<(c[9731]|0)>>>0)fa();a=g+16|0;if((c[a>>2]|0)==(n|0))c[a>>2]=m;else c[g+20>>2]=m;if(!m)break}d=c[9731]|0;if(m>>>0>>0)fa();c[m+24>>2]=g;a=n+16|0;b=c[a>>2]|0;do if(b|0)if(b>>>0>>0)fa();else{c[m+16>>2]=b;c[b+24>>2]=m;break}while(0);a=c[a+4>>2]|0;if(a|0)if(a>>>0<(c[9731]|0)>>>0)fa();else{c[m+20>>2]=a;c[a+24>>2]=m;break}}}else{b=c[n+8>>2]|0;d=c[n+12>>2]|0;a=38948+(e<<1<<2)|0;if((b|0)!=(a|0)){if(b>>>0<(c[9731]|0)>>>0)fa();if((c[b+12>>2]|0)!=(n|0))fa()}if((d|0)==(b|0)){c[9727]=c[9727]&~(1<>>0<(c[9731]|0)>>>0)fa();a=d+8|0;if((c[a>>2]|0)==(n|0))l=a;else fa()}else l=d+8|0;c[b+12>>2]=d;c[l>>2]=b}while(0);c[q+4>>2]=f|1;c[q+f>>2]=f;if((q|0)==(c[9732]|0)){c[9729]=f;return}}else{c[a>>2]=b&-2;c[q+4>>2]=f|1;c[q+f>>2]=f}a=f>>>3;if(f>>>0<256){d=38948+(a<<1<<2)|0;b=c[9727]|0;a=1<>2]|0;if(b>>>0<(c[9731]|0)>>>0)fa();else{o=b;p=a}}else{c[9727]=b|a;o=d;p=d+8|0}c[p>>2]=q;c[o+12>>2]=q;c[q+8>>2]=o;c[q+12>>2]=d;return}a=f>>>8;if(a)if(f>>>0>16777215)a=31;else{o=(a+1048320|0)>>>16&8;p=a<>>16&4;p=p<>>16&2;a=14-(n|o|a)+(p<>>15)|0;a=f>>>(a+7|0)&1|a<<1}else a=0;e=39212+(a<<2)|0;c[q+28>>2]=a;c[q+20>>2]=0;c[q+16>>2]=0;b=c[9728]|0;d=1<>>1)|0);e=c[e>>2]|0;while(1){if((c[e+4>>2]&-8|0)==(f|0)){a=130;break}d=e+16+(b>>>31<<2)|0;a=c[d>>2]|0;if(!a){a=127;break}else{b=b<<1;e=a}}if((a|0)==127)if(d>>>0<(c[9731]|0)>>>0)fa();else{c[d>>2]=q;c[q+24>>2]=e;c[q+12>>2]=q;c[q+8>>2]=q;break}else if((a|0)==130){a=e+8|0;b=c[a>>2]|0;p=c[9731]|0;if(b>>>0>=p>>>0&e>>>0>=p>>>0){c[b+12>>2]=q;c[a>>2]=q;c[q+8>>2]=b;c[q+12>>2]=e;c[q+24>>2]=0;break}else fa()}}else{c[9728]=b|d;c[e>>2]=q;c[q+24>>2]=e;c[q+12>>2]=q;c[q+8>>2]=q}while(0);q=(c[9735]|0)+-1|0;c[9735]=q;if(!q)a=39364;else return;while(1){a=c[a>>2]|0;if(!a)break;else a=a+8|0}c[9735]=-1;return}function gc(){}function hc(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;d=b-d-(c>>>0>a>>>0|0)>>>0;return (C=d,a-c>>>0|0)|0}function ic(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,i=0;f=b+e|0;if((e|0)>=20){d=d&255;h=b&3;i=d|d<<8|d<<16|d<<24;g=f&~3;if(h){h=b+4-h|0;while((b|0)<(h|0)){a[b>>0]=d;b=b+1|0}}while((b|0)<(g|0)){c[b>>2]=i;b=b+4|0}}while((b|0)<(f|0)){a[b>>0]=d;b=b+1|0}return b-e|0}function jc(a,b,c){a=a|0;b=b|0;c=c|0;if((c|0)<32){C=b>>>c;return a>>>c|(b&(1<>>c-32|0}function kc(a,b,c){a=a|0;b=b|0;c=c|0;if((c|0)<32){C=b<>>32-c;return a<>>16;a=(c>>>16)+(R(e,d)|0)|0;e=b>>>16;b=R(e,f)|0;return (C=(a>>>16)+(R(e,d)|0)+(((a&65535)+b|0)>>>16)|0,a+b<<16|c&65535|0)|0}function mc(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0,f=0;e=a;f=c;c=lc(e,f)|0;a=C;return (C=(R(b,f)|0)+(R(d,e)|0)+a|a&0,c|0|0)|0}function nc(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;c=a+c>>>0;return (C=b+d+(c>>>0>>0|0)>>>0,c|0)|0}function oc(a){a=a|0;var b=0,d=0;d=a+15&-16|0;b=c[k>>2]|0;a=b+d|0;if((d|0)>0&(a|0)<(b|0)|(a|0)<0){Z()|0;sa(12);return -1}c[k>>2]=a;if((a|0)>(Y()|0)?(X()|0)==0:0){sa(12);c[k>>2]=b;return -1}return b|0}function pc(a){a=a|0;return (a&255)<<24|(a>>8&255)<<16|(a>>16&255)<<8|a>>>24|0}function qc(b,d,e){b=b|0;d=d|0;e=e|0;var f=0;if((e|0)>=4096)return la(b|0,d|0,e|0)|0;f=b|0;if((b&3)==(d&3)){while(b&3){if(!e)return f|0;a[b>>0]=a[d>>0]|0;b=b+1|0;d=d+1|0;e=e-1|0}while((e|0)>=4){c[b>>2]=c[d>>2];b=b+4|0;d=d+4|0;e=e-4|0}}while((e|0)>0){a[b>>0]=a[d>>0]|0;b=b+1|0;d=d+1|0;e=e-1|0}return f|0}function rc(){return 0}function sc(a,b){a=a|0;b=b|0;return ua[a&1](b|0)|0}function tc(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;return va[a&7](b|0,c|0,d|0)|0}function uc(a,b){a=a|0;b=b|0;wa[a&3](b|0)}function vc(a){a=a|0;V(0);return 0}function wc(a,b,c){a=a|0;b=b|0;c=c|0;V(1);return 0}function xc(a){a=a|0;V(2)} + +// EMSCRIPTEN_END_FUNCS +var ua=[vc,Kb];var va=[wc,Tb,Mb,Rb,Lb,wc,wc,wc];var wa=[xc,Pb,Sb,xc];return{___muldsi3:lc,_sbrk:oc,_i64Subtract:hc,_free:fc,_ecdsa_read_pubkey:kb,_i64Add:nc,_pthread_self:rc,_memset:ic,_malloc:ec,_memcpy:qc,_llvm_bswap_i32:pc,___muldi3:mc,_bitshift64Lshr:jc,_fflush:Xb,_hdnode_public_ckd_address_optimized:tb,___errno_location:Ob,_bitshift64Shl:kc,runPostSets:gc,stackAlloc:xa,stackSave:ya,stackRestore:za,establishStackSpace:Aa,setThrew:Ba,setTempRet0:Ca,getTempRet0:Da,dynCall_ii:sc,dynCall_iiii:tc,dynCall_vi:uc}}) + + +// EMSCRIPTEN_END_ASM +(e.Ia,e.Ja,buffer),kc=e.___muldsi3=Z.___muldsi3,E=e._malloc=Z._malloc,db=e._i64Subtract=Z._i64Subtract,Ga=e._free=Z._free;e.runPostSets=Z.runPostSets; +var sc=e._ecdsa_read_pubkey=Z._ecdsa_read_pubkey,mc=e._i64Add=Z._i64Add,rc=e._pthread_self=Z._pthread_self,eb=e._memset=Z._memset,nc=e._sbrk=Z._sbrk,qc=e._memcpy=Z._memcpy;e.___errno_location=Z.___errno_location;var lc=e.___muldi3=Z.___muldi3,gb=e._bitshift64Lshr=Z._bitshift64Lshr;e._fflush=Z._fflush;var tc=e._hdnode_public_ckd_address_optimized=Z._hdnode_public_ckd_address_optimized,pc=e._llvm_bswap_i32=Z._llvm_bswap_i32,hb=e._bitshift64Shl=Z._bitshift64Shl;e.dynCall_ii=Z.dynCall_ii; +e.dynCall_iiii=Z.dynCall_iiii;e.dynCall_vi=Z.dynCall_vi;t.P=Z.stackAlloc;t.Q=Z.stackSave;t.I=Z.stackRestore;t.cd=Z.establishStackSpace;t.Wa=Z.setTempRet0;t.Na=Z.getTempRet0;function ga(a){this.name="ExitStatus";this.message="Program terminated with exit("+a+")";this.status=a}ga.prototype=Error();ga.prototype.constructor=ga;var uc=null,$a=function vc(){e.calledRun||wc();e.calledRun||($a=vc)}; +e.callMain=e.ad=function(a){function b(){for(var a=0;3>a;a++)d.push(0)}a=a||[];za||(za=!0,Qa(Sa));var c=a.length+1,d=[D(Xa(e.thisProgram),"i8",0)];b();for(var f=0;f Date: Thu, 13 Oct 2016 22:21:58 +0300 Subject: [PATCH 328/627] Add Curve25519 implementation Using https://github.com/agl/curve25519-donna repository source. --- Makefile | 5 +- curve25519-donna/curve25519-donna.c | 863 ++++++++++++++++++++++++++++ curve25519-donna/curve25519-donna.h | 11 + 3 files changed, 877 insertions(+), 2 deletions(-) create mode 100644 curve25519-donna/curve25519-donna.c create mode 100644 curve25519-donna/curve25519-donna.h diff --git a/Makefile b/Makefile index da15a751c..16e667a59 100644 --- a/Makefile +++ b/Makefile @@ -29,7 +29,7 @@ CFLAGS += -DED25519_CUSTOMRANDOM=1 CFLAGS += -DED25519_CUSTOMHASH=1 CFLAGS += -DED25519_NO_INLINE_ASM CFLAGS += -DED25519_FORCE_32BIT=1 -CFLAGS += -Ied25519-donna -I. +CFLAGS += -Ied25519-donna -Icurve25519-donna -I. CFLAGS += -DUSE_ETHEREUM=1 # disable certain optimizations and features when small footprint is required @@ -45,6 +45,7 @@ SRCS += sha2.c SRCS += sha3.c SRCS += aescrypt.c aeskey.c aestab.c aes_modes.c SRCS += ed25519-donna/ed25519.c +SRCS += curve25519-donna/curve25519-donna.c OBJS = $(SRCS:.c=.o) @@ -80,5 +81,5 @@ tools/bip39bruteforce: tools/bip39bruteforce.o $(OBJS) $(CC) tools/bip39bruteforce.o $(OBJS) -o tools/bip39bruteforce clean: - rm -f *.o ed25519-donna/*.o tests test_speed test-openssl libtrezor-crypto.so + rm -f *.o ed25519-donna/*.o curve25519-donna/*.o tests test_speed test-openssl libtrezor-crypto.so rm -f tools/*.o tools/xpubaddrgen tools/mktable tools/bip39bruteforce diff --git a/curve25519-donna/curve25519-donna.c b/curve25519-donna/curve25519-donna.c new file mode 100644 index 000000000..936aa890b --- /dev/null +++ b/curve25519-donna/curve25519-donna.c @@ -0,0 +1,863 @@ +/* Copyright 2008, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * curve25519-donna: Curve25519 elliptic curve, public key function + * + * http://code.google.com/p/curve25519-donna/ + * + * Adam Langley + * + * Derived from public domain C code by Daniel J. Bernstein + * + * More information about curve25519 can be found here + * http://cr.yp.to/ecdh.html + * + * djb's sample implementation of curve25519 is written in a special assembly + * language called qhasm and uses the floating point registers. + * + * This is, almost, a clean room reimplementation from the curve25519 paper. It + * uses many of the tricks described therein. Only the crecip function is taken + * from the sample implementation. */ + +#include + +#include "curve25519-donna.h" + +#ifdef _MSC_VER +#define inline __inline +#endif + +typedef int32_t s32; +typedef int64_t limb; + +/* Field element representation: + * + * Field elements are written as an array of signed, 64-bit limbs, least + * significant first. The value of the field element is: + * x[0] + 2^26·x[1] + x^51·x[2] + 2^102·x[3] + ... + * + * i.e. the limbs are 26, 25, 26, 25, ... bits wide. */ + +/* Sum two numbers: output += in */ +static void fsum(limb *output, const limb *in) { + unsigned i; + for (i = 0; i < 10; i += 2) { + output[0+i] = output[0+i] + in[0+i]; + output[1+i] = output[1+i] + in[1+i]; + } +} + +/* Find the difference of two numbers: output = in - output + * (note the order of the arguments!). */ +static void fdifference(limb *output, const limb *in) { + unsigned i; + for (i = 0; i < 10; ++i) { + output[i] = in[i] - output[i]; + } +} + +/* Multiply a number by a scalar: output = in * scalar */ +static void fscalar_product(limb *output, const limb *in, const limb scalar) { + unsigned i; + for (i = 0; i < 10; ++i) { + output[i] = in[i] * scalar; + } +} + +/* Multiply two numbers: output = in2 * in + * + * output must be distinct to both inputs. The inputs are reduced coefficient + * form, the output is not. + * + * output[x] <= 14 * the largest product of the input limbs. */ +static void fproduct(limb *output, const limb *in2, const limb *in) { + output[0] = ((limb) ((s32) in2[0])) * ((s32) in[0]); + output[1] = ((limb) ((s32) in2[0])) * ((s32) in[1]) + + ((limb) ((s32) in2[1])) * ((s32) in[0]); + output[2] = 2 * ((limb) ((s32) in2[1])) * ((s32) in[1]) + + ((limb) ((s32) in2[0])) * ((s32) in[2]) + + ((limb) ((s32) in2[2])) * ((s32) in[0]); + output[3] = ((limb) ((s32) in2[1])) * ((s32) in[2]) + + ((limb) ((s32) in2[2])) * ((s32) in[1]) + + ((limb) ((s32) in2[0])) * ((s32) in[3]) + + ((limb) ((s32) in2[3])) * ((s32) in[0]); + output[4] = ((limb) ((s32) in2[2])) * ((s32) in[2]) + + 2 * (((limb) ((s32) in2[1])) * ((s32) in[3]) + + ((limb) ((s32) in2[3])) * ((s32) in[1])) + + ((limb) ((s32) in2[0])) * ((s32) in[4]) + + ((limb) ((s32) in2[4])) * ((s32) in[0]); + output[5] = ((limb) ((s32) in2[2])) * ((s32) in[3]) + + ((limb) ((s32) in2[3])) * ((s32) in[2]) + + ((limb) ((s32) in2[1])) * ((s32) in[4]) + + ((limb) ((s32) in2[4])) * ((s32) in[1]) + + ((limb) ((s32) in2[0])) * ((s32) in[5]) + + ((limb) ((s32) in2[5])) * ((s32) in[0]); + output[6] = 2 * (((limb) ((s32) in2[3])) * ((s32) in[3]) + + ((limb) ((s32) in2[1])) * ((s32) in[5]) + + ((limb) ((s32) in2[5])) * ((s32) in[1])) + + ((limb) ((s32) in2[2])) * ((s32) in[4]) + + ((limb) ((s32) in2[4])) * ((s32) in[2]) + + ((limb) ((s32) in2[0])) * ((s32) in[6]) + + ((limb) ((s32) in2[6])) * ((s32) in[0]); + output[7] = ((limb) ((s32) in2[3])) * ((s32) in[4]) + + ((limb) ((s32) in2[4])) * ((s32) in[3]) + + ((limb) ((s32) in2[2])) * ((s32) in[5]) + + ((limb) ((s32) in2[5])) * ((s32) in[2]) + + ((limb) ((s32) in2[1])) * ((s32) in[6]) + + ((limb) ((s32) in2[6])) * ((s32) in[1]) + + ((limb) ((s32) in2[0])) * ((s32) in[7]) + + ((limb) ((s32) in2[7])) * ((s32) in[0]); + output[8] = ((limb) ((s32) in2[4])) * ((s32) in[4]) + + 2 * (((limb) ((s32) in2[3])) * ((s32) in[5]) + + ((limb) ((s32) in2[5])) * ((s32) in[3]) + + ((limb) ((s32) in2[1])) * ((s32) in[7]) + + ((limb) ((s32) in2[7])) * ((s32) in[1])) + + ((limb) ((s32) in2[2])) * ((s32) in[6]) + + ((limb) ((s32) in2[6])) * ((s32) in[2]) + + ((limb) ((s32) in2[0])) * ((s32) in[8]) + + ((limb) ((s32) in2[8])) * ((s32) in[0]); + output[9] = ((limb) ((s32) in2[4])) * ((s32) in[5]) + + ((limb) ((s32) in2[5])) * ((s32) in[4]) + + ((limb) ((s32) in2[3])) * ((s32) in[6]) + + ((limb) ((s32) in2[6])) * ((s32) in[3]) + + ((limb) ((s32) in2[2])) * ((s32) in[7]) + + ((limb) ((s32) in2[7])) * ((s32) in[2]) + + ((limb) ((s32) in2[1])) * ((s32) in[8]) + + ((limb) ((s32) in2[8])) * ((s32) in[1]) + + ((limb) ((s32) in2[0])) * ((s32) in[9]) + + ((limb) ((s32) in2[9])) * ((s32) in[0]); + output[10] = 2 * (((limb) ((s32) in2[5])) * ((s32) in[5]) + + ((limb) ((s32) in2[3])) * ((s32) in[7]) + + ((limb) ((s32) in2[7])) * ((s32) in[3]) + + ((limb) ((s32) in2[1])) * ((s32) in[9]) + + ((limb) ((s32) in2[9])) * ((s32) in[1])) + + ((limb) ((s32) in2[4])) * ((s32) in[6]) + + ((limb) ((s32) in2[6])) * ((s32) in[4]) + + ((limb) ((s32) in2[2])) * ((s32) in[8]) + + ((limb) ((s32) in2[8])) * ((s32) in[2]); + output[11] = ((limb) ((s32) in2[5])) * ((s32) in[6]) + + ((limb) ((s32) in2[6])) * ((s32) in[5]) + + ((limb) ((s32) in2[4])) * ((s32) in[7]) + + ((limb) ((s32) in2[7])) * ((s32) in[4]) + + ((limb) ((s32) in2[3])) * ((s32) in[8]) + + ((limb) ((s32) in2[8])) * ((s32) in[3]) + + ((limb) ((s32) in2[2])) * ((s32) in[9]) + + ((limb) ((s32) in2[9])) * ((s32) in[2]); + output[12] = ((limb) ((s32) in2[6])) * ((s32) in[6]) + + 2 * (((limb) ((s32) in2[5])) * ((s32) in[7]) + + ((limb) ((s32) in2[7])) * ((s32) in[5]) + + ((limb) ((s32) in2[3])) * ((s32) in[9]) + + ((limb) ((s32) in2[9])) * ((s32) in[3])) + + ((limb) ((s32) in2[4])) * ((s32) in[8]) + + ((limb) ((s32) in2[8])) * ((s32) in[4]); + output[13] = ((limb) ((s32) in2[6])) * ((s32) in[7]) + + ((limb) ((s32) in2[7])) * ((s32) in[6]) + + ((limb) ((s32) in2[5])) * ((s32) in[8]) + + ((limb) ((s32) in2[8])) * ((s32) in[5]) + + ((limb) ((s32) in2[4])) * ((s32) in[9]) + + ((limb) ((s32) in2[9])) * ((s32) in[4]); + output[14] = 2 * (((limb) ((s32) in2[7])) * ((s32) in[7]) + + ((limb) ((s32) in2[5])) * ((s32) in[9]) + + ((limb) ((s32) in2[9])) * ((s32) in[5])) + + ((limb) ((s32) in2[6])) * ((s32) in[8]) + + ((limb) ((s32) in2[8])) * ((s32) in[6]); + output[15] = ((limb) ((s32) in2[7])) * ((s32) in[8]) + + ((limb) ((s32) in2[8])) * ((s32) in[7]) + + ((limb) ((s32) in2[6])) * ((s32) in[9]) + + ((limb) ((s32) in2[9])) * ((s32) in[6]); + output[16] = ((limb) ((s32) in2[8])) * ((s32) in[8]) + + 2 * (((limb) ((s32) in2[7])) * ((s32) in[9]) + + ((limb) ((s32) in2[9])) * ((s32) in[7])); + output[17] = ((limb) ((s32) in2[8])) * ((s32) in[9]) + + ((limb) ((s32) in2[9])) * ((s32) in[8]); + output[18] = 2 * ((limb) ((s32) in2[9])) * ((s32) in[9]); +} + +/* Reduce a long form to a short form by taking the input mod 2^255 - 19. + * + * On entry: |output[i]| < 14*2^54 + * On exit: |output[0..8]| < 280*2^54 */ +static void freduce_degree(limb *output) { + /* Each of these shifts and adds ends up multiplying the value by 19. + * + * For output[0..8], the absolute entry value is < 14*2^54 and we add, at + * most, 19*14*2^54 thus, on exit, |output[0..8]| < 280*2^54. */ + output[8] += output[18] << 4; + output[8] += output[18] << 1; + output[8] += output[18]; + output[7] += output[17] << 4; + output[7] += output[17] << 1; + output[7] += output[17]; + output[6] += output[16] << 4; + output[6] += output[16] << 1; + output[6] += output[16]; + output[5] += output[15] << 4; + output[5] += output[15] << 1; + output[5] += output[15]; + output[4] += output[14] << 4; + output[4] += output[14] << 1; + output[4] += output[14]; + output[3] += output[13] << 4; + output[3] += output[13] << 1; + output[3] += output[13]; + output[2] += output[12] << 4; + output[2] += output[12] << 1; + output[2] += output[12]; + output[1] += output[11] << 4; + output[1] += output[11] << 1; + output[1] += output[11]; + output[0] += output[10] << 4; + output[0] += output[10] << 1; + output[0] += output[10]; +} + +#if (-1 & 3) != 3 +#error "This code only works on a two's complement system" +#endif + +/* return v / 2^26, using only shifts and adds. + * + * On entry: v can take any value. */ +static inline limb +div_by_2_26(const limb v) +{ + /* High word of v; no shift needed. */ + const uint32_t highword = (uint32_t) (((uint64_t) v) >> 32); + /* Set to all 1s if v was negative; else set to 0s. */ + const int32_t sign = ((int32_t) highword) >> 31; + /* Set to 0x3ffffff if v was negative; else set to 0. */ + const int32_t roundoff = ((uint32_t) sign) >> 6; + /* Should return v / (1<<26) */ + return (v + roundoff) >> 26; +} + +/* return v / (2^25), using only shifts and adds. + * + * On entry: v can take any value. */ +static inline limb +div_by_2_25(const limb v) +{ + /* High word of v; no shift needed*/ + const uint32_t highword = (uint32_t) (((uint64_t) v) >> 32); + /* Set to all 1s if v was negative; else set to 0s. */ + const int32_t sign = ((int32_t) highword) >> 31; + /* Set to 0x1ffffff if v was negative; else set to 0. */ + const int32_t roundoff = ((uint32_t) sign) >> 7; + /* Should return v / (1<<25) */ + return (v + roundoff) >> 25; +} + +/* Reduce all coefficients of the short form input so that |x| < 2^26. + * + * On entry: |output[i]| < 280*2^54 */ +static void freduce_coefficients(limb *output) { + unsigned i; + + output[10] = 0; + + for (i = 0; i < 10; i += 2) { + limb over = div_by_2_26(output[i]); + /* The entry condition (that |output[i]| < 280*2^54) means that over is, at + * most, 280*2^28 in the first iteration of this loop. This is added to the + * next limb and we can approximate the resulting bound of that limb by + * 281*2^54. */ + output[i] -= over << 26; + output[i+1] += over; + + /* For the first iteration, |output[i+1]| < 281*2^54, thus |over| < + * 281*2^29. When this is added to the next limb, the resulting bound can + * be approximated as 281*2^54. + * + * For subsequent iterations of the loop, 281*2^54 remains a conservative + * bound and no overflow occurs. */ + over = div_by_2_25(output[i+1]); + output[i+1] -= over << 25; + output[i+2] += over; + } + /* Now |output[10]| < 281*2^29 and all other coefficients are reduced. */ + output[0] += output[10] << 4; + output[0] += output[10] << 1; + output[0] += output[10]; + + output[10] = 0; + + /* Now output[1..9] are reduced, and |output[0]| < 2^26 + 19*281*2^29 + * So |over| will be no more than 2^16. */ + { + limb over = div_by_2_26(output[0]); + output[0] -= over << 26; + output[1] += over; + } + + /* Now output[0,2..9] are reduced, and |output[1]| < 2^25 + 2^16 < 2^26. The + * bound on |output[1]| is sufficient to meet our needs. */ +} + +/* A helpful wrapper around fproduct: output = in * in2. + * + * On entry: |in[i]| < 2^27 and |in2[i]| < 2^27. + * + * output must be distinct to both inputs. The output is reduced degree + * (indeed, one need only provide storage for 10 limbs) and |output[i]| < 2^26. */ +static void +fmul(limb *output, const limb *in, const limb *in2) { + limb t[19]; + fproduct(t, in, in2); + /* |t[i]| < 14*2^54 */ + freduce_degree(t); + freduce_coefficients(t); + /* |t[i]| < 2^26 */ + memcpy(output, t, sizeof(limb) * 10); +} + +/* Square a number: output = in**2 + * + * output must be distinct from the input. The inputs are reduced coefficient + * form, the output is not. + * + * output[x] <= 14 * the largest product of the input limbs. */ +static void fsquare_inner(limb *output, const limb *in) { + output[0] = ((limb) ((s32) in[0])) * ((s32) in[0]); + output[1] = 2 * ((limb) ((s32) in[0])) * ((s32) in[1]); + output[2] = 2 * (((limb) ((s32) in[1])) * ((s32) in[1]) + + ((limb) ((s32) in[0])) * ((s32) in[2])); + output[3] = 2 * (((limb) ((s32) in[1])) * ((s32) in[2]) + + ((limb) ((s32) in[0])) * ((s32) in[3])); + output[4] = ((limb) ((s32) in[2])) * ((s32) in[2]) + + 4 * ((limb) ((s32) in[1])) * ((s32) in[3]) + + 2 * ((limb) ((s32) in[0])) * ((s32) in[4]); + output[5] = 2 * (((limb) ((s32) in[2])) * ((s32) in[3]) + + ((limb) ((s32) in[1])) * ((s32) in[4]) + + ((limb) ((s32) in[0])) * ((s32) in[5])); + output[6] = 2 * (((limb) ((s32) in[3])) * ((s32) in[3]) + + ((limb) ((s32) in[2])) * ((s32) in[4]) + + ((limb) ((s32) in[0])) * ((s32) in[6]) + + 2 * ((limb) ((s32) in[1])) * ((s32) in[5])); + output[7] = 2 * (((limb) ((s32) in[3])) * ((s32) in[4]) + + ((limb) ((s32) in[2])) * ((s32) in[5]) + + ((limb) ((s32) in[1])) * ((s32) in[6]) + + ((limb) ((s32) in[0])) * ((s32) in[7])); + output[8] = ((limb) ((s32) in[4])) * ((s32) in[4]) + + 2 * (((limb) ((s32) in[2])) * ((s32) in[6]) + + ((limb) ((s32) in[0])) * ((s32) in[8]) + + 2 * (((limb) ((s32) in[1])) * ((s32) in[7]) + + ((limb) ((s32) in[3])) * ((s32) in[5]))); + output[9] = 2 * (((limb) ((s32) in[4])) * ((s32) in[5]) + + ((limb) ((s32) in[3])) * ((s32) in[6]) + + ((limb) ((s32) in[2])) * ((s32) in[7]) + + ((limb) ((s32) in[1])) * ((s32) in[8]) + + ((limb) ((s32) in[0])) * ((s32) in[9])); + output[10] = 2 * (((limb) ((s32) in[5])) * ((s32) in[5]) + + ((limb) ((s32) in[4])) * ((s32) in[6]) + + ((limb) ((s32) in[2])) * ((s32) in[8]) + + 2 * (((limb) ((s32) in[3])) * ((s32) in[7]) + + ((limb) ((s32) in[1])) * ((s32) in[9]))); + output[11] = 2 * (((limb) ((s32) in[5])) * ((s32) in[6]) + + ((limb) ((s32) in[4])) * ((s32) in[7]) + + ((limb) ((s32) in[3])) * ((s32) in[8]) + + ((limb) ((s32) in[2])) * ((s32) in[9])); + output[12] = ((limb) ((s32) in[6])) * ((s32) in[6]) + + 2 * (((limb) ((s32) in[4])) * ((s32) in[8]) + + 2 * (((limb) ((s32) in[5])) * ((s32) in[7]) + + ((limb) ((s32) in[3])) * ((s32) in[9]))); + output[13] = 2 * (((limb) ((s32) in[6])) * ((s32) in[7]) + + ((limb) ((s32) in[5])) * ((s32) in[8]) + + ((limb) ((s32) in[4])) * ((s32) in[9])); + output[14] = 2 * (((limb) ((s32) in[7])) * ((s32) in[7]) + + ((limb) ((s32) in[6])) * ((s32) in[8]) + + 2 * ((limb) ((s32) in[5])) * ((s32) in[9])); + output[15] = 2 * (((limb) ((s32) in[7])) * ((s32) in[8]) + + ((limb) ((s32) in[6])) * ((s32) in[9])); + output[16] = ((limb) ((s32) in[8])) * ((s32) in[8]) + + 4 * ((limb) ((s32) in[7])) * ((s32) in[9]); + output[17] = 2 * ((limb) ((s32) in[8])) * ((s32) in[9]); + output[18] = 2 * ((limb) ((s32) in[9])) * ((s32) in[9]); +} + +/* fsquare sets output = in^2. + * + * On entry: The |in| argument is in reduced coefficients form and |in[i]| < + * 2^27. + * + * On exit: The |output| argument is in reduced coefficients form (indeed, one + * need only provide storage for 10 limbs) and |out[i]| < 2^26. */ +static void +fsquare(limb *output, const limb *in) { + limb t[19]; + fsquare_inner(t, in); + /* |t[i]| < 14*2^54 because the largest product of two limbs will be < + * 2^(27+27) and fsquare_inner adds together, at most, 14 of those + * products. */ + freduce_degree(t); + freduce_coefficients(t); + /* |t[i]| < 2^26 */ + memcpy(output, t, sizeof(limb) * 10); +} + +/* Take a little-endian, 32-byte number and expand it into polynomial form */ +static void +fexpand(limb *output, const u8 *input) { +#define F(n,start,shift,mask) \ + output[n] = ((((limb) input[start + 0]) | \ + ((limb) input[start + 1]) << 8 | \ + ((limb) input[start + 2]) << 16 | \ + ((limb) input[start + 3]) << 24) >> shift) & mask; + F(0, 0, 0, 0x3ffffff); + F(1, 3, 2, 0x1ffffff); + F(2, 6, 3, 0x3ffffff); + F(3, 9, 5, 0x1ffffff); + F(4, 12, 6, 0x3ffffff); + F(5, 16, 0, 0x1ffffff); + F(6, 19, 1, 0x3ffffff); + F(7, 22, 3, 0x1ffffff); + F(8, 25, 4, 0x3ffffff); + F(9, 28, 6, 0x1ffffff); +#undef F +} + +#if (-32 >> 1) != -16 +#error "This code only works when >> does sign-extension on negative numbers" +#endif + +/* s32_eq returns 0xffffffff iff a == b and zero otherwise. */ +static s32 s32_eq(s32 a, s32 b) { + a = ~(a ^ b); + a &= a << 16; + a &= a << 8; + a &= a << 4; + a &= a << 2; + a &= a << 1; + return a >> 31; +} + +/* s32_gte returns 0xffffffff if a >= b and zero otherwise, where a and b are + * both non-negative. */ +static s32 s32_gte(s32 a, s32 b) { + a -= b; + /* a >= 0 iff a >= b. */ + return ~(a >> 31); +} + +/* Take a fully reduced polynomial form number and contract it into a + * little-endian, 32-byte array. + * + * On entry: |input_limbs[i]| < 2^26 */ +static void +fcontract(u8 *output, limb *input_limbs) { + int i; + int j; + s32 input[10]; + + /* |input_limbs[i]| < 2^26, so it's valid to convert to an s32. */ + for (i = 0; i < 10; i++) { + input[i] = input_limbs[i]; + } + + for (j = 0; j < 2; ++j) { + for (i = 0; i < 9; ++i) { + if ((i & 1) == 1) { + /* This calculation is a time-invariant way to make input[i] + * non-negative by borrowing from the next-larger limb. */ + const s32 mask = input[i] >> 31; + const s32 carry = -((input[i] & mask) >> 25); + input[i] = input[i] + (carry << 25); + input[i+1] = input[i+1] - carry; + } else { + const s32 mask = input[i] >> 31; + const s32 carry = -((input[i] & mask) >> 26); + input[i] = input[i] + (carry << 26); + input[i+1] = input[i+1] - carry; + } + } + + /* There's no greater limb for input[9] to borrow from, but we can multiply + * by 19 and borrow from input[0], which is valid mod 2^255-19. */ + { + const s32 mask = input[9] >> 31; + const s32 carry = -((input[9] & mask) >> 25); + input[9] = input[9] + (carry << 25); + input[0] = input[0] - (carry * 19); + } + + /* After the first iteration, input[1..9] are non-negative and fit within + * 25 or 26 bits, depending on position. However, input[0] may be + * negative. */ + } + + /* The first borrow-propagation pass above ended with every limb + except (possibly) input[0] non-negative. + + If input[0] was negative after the first pass, then it was because of a + carry from input[9]. On entry, input[9] < 2^26 so the carry was, at most, + one, since (2**26-1) >> 25 = 1. Thus input[0] >= -19. + + In the second pass, each limb is decreased by at most one. Thus the second + borrow-propagation pass could only have wrapped around to decrease + input[0] again if the first pass left input[0] negative *and* input[1] + through input[9] were all zero. In that case, input[1] is now 2^25 - 1, + and this last borrow-propagation step will leave input[1] non-negative. */ + { + const s32 mask = input[0] >> 31; + const s32 carry = -((input[0] & mask) >> 26); + input[0] = input[0] + (carry << 26); + input[1] = input[1] - carry; + } + + /* All input[i] are now non-negative. However, there might be values between + * 2^25 and 2^26 in a limb which is, nominally, 25 bits wide. */ + for (j = 0; j < 2; j++) { + for (i = 0; i < 9; i++) { + if ((i & 1) == 1) { + const s32 carry = input[i] >> 25; + input[i] &= 0x1ffffff; + input[i+1] += carry; + } else { + const s32 carry = input[i] >> 26; + input[i] &= 0x3ffffff; + input[i+1] += carry; + } + } + + { + const s32 carry = input[9] >> 25; + input[9] &= 0x1ffffff; + input[0] += 19*carry; + } + } + + /* If the first carry-chain pass, just above, ended up with a carry from + * input[9], and that caused input[0] to be out-of-bounds, then input[0] was + * < 2^26 + 2*19, because the carry was, at most, two. + * + * If the second pass carried from input[9] again then input[0] is < 2*19 and + * the input[9] -> input[0] carry didn't push input[0] out of bounds. */ + + /* It still remains the case that input might be between 2^255-19 and 2^255. + * In this case, input[1..9] must take their maximum value and input[0] must + * be >= (2^255-19) & 0x3ffffff, which is 0x3ffffed. */ + s32 mask = s32_gte(input[0], 0x3ffffed); + for (i = 1; i < 10; i++) { + if ((i & 1) == 1) { + mask &= s32_eq(input[i], 0x1ffffff); + } else { + mask &= s32_eq(input[i], 0x3ffffff); + } + } + + /* mask is either 0xffffffff (if input >= 2^255-19) and zero otherwise. Thus + * this conditionally subtracts 2^255-19. */ + input[0] -= mask & 0x3ffffed; + + for (i = 1; i < 10; i++) { + if ((i & 1) == 1) { + input[i] -= mask & 0x1ffffff; + } else { + input[i] -= mask & 0x3ffffff; + } + } + + input[1] <<= 2; + input[2] <<= 3; + input[3] <<= 5; + input[4] <<= 6; + input[6] <<= 1; + input[7] <<= 3; + input[8] <<= 4; + input[9] <<= 6; +#define F(i, s) \ + output[s+0] |= input[i] & 0xff; \ + output[s+1] = (input[i] >> 8) & 0xff; \ + output[s+2] = (input[i] >> 16) & 0xff; \ + output[s+3] = (input[i] >> 24) & 0xff; + output[0] = 0; + output[16] = 0; + F(0,0); + F(1,3); + F(2,6); + F(3,9); + F(4,12); + F(5,16); + F(6,19); + F(7,22); + F(8,25); + F(9,28); +#undef F +} + +/* Input: Q, Q', Q-Q' + * Output: 2Q, Q+Q' + * + * x2 z3: long form + * x3 z3: long form + * x z: short form, destroyed + * xprime zprime: short form, destroyed + * qmqp: short form, preserved + * + * On entry and exit, the absolute value of the limbs of all inputs and outputs + * are < 2^26. */ +static void fmonty(limb *x2, limb *z2, /* output 2Q */ + limb *x3, limb *z3, /* output Q + Q' */ + limb *x, limb *z, /* input Q */ + limb *xprime, limb *zprime, /* input Q' */ + const limb *qmqp /* input Q - Q' */) { + limb origx[10], origxprime[10], zzz[19], xx[19], zz[19], xxprime[19], + zzprime[19], zzzprime[19], xxxprime[19]; + + memcpy(origx, x, 10 * sizeof(limb)); + fsum(x, z); + /* |x[i]| < 2^27 */ + fdifference(z, origx); /* does x - z */ + /* |z[i]| < 2^27 */ + + memcpy(origxprime, xprime, sizeof(limb) * 10); + fsum(xprime, zprime); + /* |xprime[i]| < 2^27 */ + fdifference(zprime, origxprime); + /* |zprime[i]| < 2^27 */ + fproduct(xxprime, xprime, z); + /* |xxprime[i]| < 14*2^54: the largest product of two limbs will be < + * 2^(27+27) and fproduct adds together, at most, 14 of those products. + * (Approximating that to 2^58 doesn't work out.) */ + fproduct(zzprime, x, zprime); + /* |zzprime[i]| < 14*2^54 */ + freduce_degree(xxprime); + freduce_coefficients(xxprime); + /* |xxprime[i]| < 2^26 */ + freduce_degree(zzprime); + freduce_coefficients(zzprime); + /* |zzprime[i]| < 2^26 */ + memcpy(origxprime, xxprime, sizeof(limb) * 10); + fsum(xxprime, zzprime); + /* |xxprime[i]| < 2^27 */ + fdifference(zzprime, origxprime); + /* |zzprime[i]| < 2^27 */ + fsquare(xxxprime, xxprime); + /* |xxxprime[i]| < 2^26 */ + fsquare(zzzprime, zzprime); + /* |zzzprime[i]| < 2^26 */ + fproduct(zzprime, zzzprime, qmqp); + /* |zzprime[i]| < 14*2^52 */ + freduce_degree(zzprime); + freduce_coefficients(zzprime); + /* |zzprime[i]| < 2^26 */ + memcpy(x3, xxxprime, sizeof(limb) * 10); + memcpy(z3, zzprime, sizeof(limb) * 10); + + fsquare(xx, x); + /* |xx[i]| < 2^26 */ + fsquare(zz, z); + /* |zz[i]| < 2^26 */ + fproduct(x2, xx, zz); + /* |x2[i]| < 14*2^52 */ + freduce_degree(x2); + freduce_coefficients(x2); + /* |x2[i]| < 2^26 */ + fdifference(zz, xx); // does zz = xx - zz + /* |zz[i]| < 2^27 */ + memset(zzz + 10, 0, sizeof(limb) * 9); + fscalar_product(zzz, zz, 121665); + /* |zzz[i]| < 2^(27+17) */ + /* No need to call freduce_degree here: + fscalar_product doesn't increase the degree of its input. */ + freduce_coefficients(zzz); + /* |zzz[i]| < 2^26 */ + fsum(zzz, xx); + /* |zzz[i]| < 2^27 */ + fproduct(z2, zz, zzz); + /* |z2[i]| < 14*2^(26+27) */ + freduce_degree(z2); + freduce_coefficients(z2); + /* |z2|i| < 2^26 */ +} + +/* Conditionally swap two reduced-form limb arrays if 'iswap' is 1, but leave + * them unchanged if 'iswap' is 0. Runs in data-invariant time to avoid + * side-channel attacks. + * + * NOTE that this function requires that 'iswap' be 1 or 0; other values give + * wrong results. Also, the two limb arrays must be in reduced-coefficient, + * reduced-degree form: the values in a[10..19] or b[10..19] aren't swapped, + * and all all values in a[0..9],b[0..9] must have magnitude less than + * INT32_MAX. */ +static void +swap_conditional(limb a[19], limb b[19], limb iswap) { + unsigned i; + const s32 swap = (s32) -iswap; + + for (i = 0; i < 10; ++i) { + const s32 x = swap & ( ((s32)a[i]) ^ ((s32)b[i]) ); + a[i] = ((s32)a[i]) ^ x; + b[i] = ((s32)b[i]) ^ x; + } +} + +/* Calculates nQ where Q is the x-coordinate of a point on the curve + * + * resultx/resultz: the x coordinate of the resulting curve point (short form) + * n: a little endian, 32-byte number + * q: a point of the curve (short form) */ +static void +cmult(limb *resultx, limb *resultz, const u8 *n, const limb *q) { + limb a[19] = {0}, b[19] = {1}, c[19] = {1}, d[19] = {0}; + limb *nqpqx = a, *nqpqz = b, *nqx = c, *nqz = d, *t; + limb e[19] = {0}, f[19] = {1}, g[19] = {0}, h[19] = {1}; + limb *nqpqx2 = e, *nqpqz2 = f, *nqx2 = g, *nqz2 = h; + + unsigned i, j; + + memcpy(nqpqx, q, sizeof(limb) * 10); + + for (i = 0; i < 32; ++i) { + u8 byte = n[31 - i]; + for (j = 0; j < 8; ++j) { + const limb bit = byte >> 7; + + swap_conditional(nqx, nqpqx, bit); + swap_conditional(nqz, nqpqz, bit); + fmonty(nqx2, nqz2, + nqpqx2, nqpqz2, + nqx, nqz, + nqpqx, nqpqz, + q); + swap_conditional(nqx2, nqpqx2, bit); + swap_conditional(nqz2, nqpqz2, bit); + + t = nqx; + nqx = nqx2; + nqx2 = t; + t = nqz; + nqz = nqz2; + nqz2 = t; + t = nqpqx; + nqpqx = nqpqx2; + nqpqx2 = t; + t = nqpqz; + nqpqz = nqpqz2; + nqpqz2 = t; + + byte <<= 1; + } + } + + memcpy(resultx, nqx, sizeof(limb) * 10); + memcpy(resultz, nqz, sizeof(limb) * 10); +} + +// ----------------------------------------------------------------------------- +// Shamelessly copied from djb's code +// ----------------------------------------------------------------------------- +static void +crecip(limb *out, const limb *z) { + limb z2[10]; + limb z9[10]; + limb z11[10]; + limb z2_5_0[10]; + limb z2_10_0[10]; + limb z2_20_0[10]; + limb z2_50_0[10]; + limb z2_100_0[10]; + limb t0[10]; + limb t1[10]; + int i; + + /* 2 */ fsquare(z2,z); + /* 4 */ fsquare(t1,z2); + /* 8 */ fsquare(t0,t1); + /* 9 */ fmul(z9,t0,z); + /* 11 */ fmul(z11,z9,z2); + /* 22 */ fsquare(t0,z11); + /* 2^5 - 2^0 = 31 */ fmul(z2_5_0,t0,z9); + + /* 2^6 - 2^1 */ fsquare(t0,z2_5_0); + /* 2^7 - 2^2 */ fsquare(t1,t0); + /* 2^8 - 2^3 */ fsquare(t0,t1); + /* 2^9 - 2^4 */ fsquare(t1,t0); + /* 2^10 - 2^5 */ fsquare(t0,t1); + /* 2^10 - 2^0 */ fmul(z2_10_0,t0,z2_5_0); + + /* 2^11 - 2^1 */ fsquare(t0,z2_10_0); + /* 2^12 - 2^2 */ fsquare(t1,t0); + /* 2^20 - 2^10 */ for (i = 2;i < 10;i += 2) { fsquare(t0,t1); fsquare(t1,t0); } + /* 2^20 - 2^0 */ fmul(z2_20_0,t1,z2_10_0); + + /* 2^21 - 2^1 */ fsquare(t0,z2_20_0); + /* 2^22 - 2^2 */ fsquare(t1,t0); + /* 2^40 - 2^20 */ for (i = 2;i < 20;i += 2) { fsquare(t0,t1); fsquare(t1,t0); } + /* 2^40 - 2^0 */ fmul(t0,t1,z2_20_0); + + /* 2^41 - 2^1 */ fsquare(t1,t0); + /* 2^42 - 2^2 */ fsquare(t0,t1); + /* 2^50 - 2^10 */ for (i = 2;i < 10;i += 2) { fsquare(t1,t0); fsquare(t0,t1); } + /* 2^50 - 2^0 */ fmul(z2_50_0,t0,z2_10_0); + + /* 2^51 - 2^1 */ fsquare(t0,z2_50_0); + /* 2^52 - 2^2 */ fsquare(t1,t0); + /* 2^100 - 2^50 */ for (i = 2;i < 50;i += 2) { fsquare(t0,t1); fsquare(t1,t0); } + /* 2^100 - 2^0 */ fmul(z2_100_0,t1,z2_50_0); + + /* 2^101 - 2^1 */ fsquare(t1,z2_100_0); + /* 2^102 - 2^2 */ fsquare(t0,t1); + /* 2^200 - 2^100 */ for (i = 2;i < 100;i += 2) { fsquare(t1,t0); fsquare(t0,t1); } + /* 2^200 - 2^0 */ fmul(t1,t0,z2_100_0); + + /* 2^201 - 2^1 */ fsquare(t0,t1); + /* 2^202 - 2^2 */ fsquare(t1,t0); + /* 2^250 - 2^50 */ for (i = 2;i < 50;i += 2) { fsquare(t0,t1); fsquare(t1,t0); } + /* 2^250 - 2^0 */ fmul(t0,t1,z2_50_0); + + /* 2^251 - 2^1 */ fsquare(t1,t0); + /* 2^252 - 2^2 */ fsquare(t0,t1); + /* 2^253 - 2^3 */ fsquare(t1,t0); + /* 2^254 - 2^4 */ fsquare(t0,t1); + /* 2^255 - 2^5 */ fsquare(t1,t0); + /* 2^255 - 21 */ fmul(out,t1,z11); +} + +static const u8 curve25519_basepoint[32] = {9}; + +void curve25519_scalarmult(u8 *result, const u8 *secret, const u8 *basepoint) { + limb bp[10], x[10], z[11], zmone[10]; + uint8_t e[32]; + int i; + + for (i = 0; i < 32; ++i) e[i] = secret[i]; + e[0] &= 248; + e[31] &= 127; + e[31] |= 64; + + fexpand(bp, basepoint); + cmult(x, z, e, bp); + crecip(zmone, z); + fmul(z, x, zmone); + fcontract(result, z); +} + +void curve25519_publickey(u8 *public, const u8 *secret) { + curve25519_scalarmult(public, secret, curve25519_basepoint); +} diff --git a/curve25519-donna/curve25519-donna.h b/curve25519-donna/curve25519-donna.h new file mode 100644 index 000000000..2f6bb3d11 --- /dev/null +++ b/curve25519-donna/curve25519-donna.h @@ -0,0 +1,11 @@ +#ifndef CURVE25519_H +#define CURVE25519_H + +#include + +typedef uint8_t u8; + +void curve25519_scalarmult(u8 *result, const u8 *secret, const u8 *basepoint); +void curve25519_publickey(u8 *public, const u8 *secret); + +#endif // CURVE25519_H From f45bcc65f29986156568201217d06f6966a1b31d Mon Sep 17 00:00:00 2001 From: Jan Pochyla Date: Fri, 14 Oct 2016 14:33:49 +0200 Subject: [PATCH 329/627] bip32: deserialize the fingerprint --- bip32.c | 5 ++++- bip32.h | 2 +- tests.c | 48 ++++++++++++++++++++++----------------------- tools/xpubaddrgen.c | 2 +- 4 files changed, 30 insertions(+), 27 deletions(-) diff --git a/bip32.c b/bip32.c index f5b8b3331..5faa5a5c6 100644 --- a/bip32.c +++ b/bip32.c @@ -474,7 +474,7 @@ int hdnode_serialize_private(const HDNode *node, uint32_t fingerprint, char *str } // check for validity of curve point in case of public data not performed -int hdnode_deserialize(const char *str, HDNode *node) +int hdnode_deserialize(const char *str, HDNode *node, uint32_t *fingerprint) { uint8_t node_data[78]; memset(node, 0, sizeof(HDNode)); @@ -496,6 +496,9 @@ int hdnode_deserialize(const char *str, HDNode *node) return -3; // invalid version } node->depth = node_data[4]; + if (fingerprint) { + *fingerprint = read_be(node_data + 5); + } node->child_num = read_be(node_data + 9); memcpy(node->chain_code, node_data + 13, 32); return 0; diff --git a/bip32.h b/bip32.h index 24f674860..49de7e7d0 100644 --- a/bip32.h +++ b/bip32.h @@ -78,7 +78,7 @@ int hdnode_serialize_public(const HDNode *node, uint32_t fingerprint, char *str, int hdnode_serialize_private(const HDNode *node, uint32_t fingerprint, char *str, int strsize); -int hdnode_deserialize(const char *str, HDNode *node); +int hdnode_deserialize(const char *str, HDNode *node, uint32_t *fingerprint); // Private int hdnode_serialize(const HDNode *node, uint32_t fingerprint, uint32_t version, char use_public, char *str, int strsize); diff --git a/tests.c b/tests.c index 343d3fae1..40a3d6dd4 100644 --- a/tests.c +++ b/tests.c @@ -492,12 +492,12 @@ START_TEST(test_bip32_vector_1) ck_assert_mem_eq(node.public_key, fromhex("0339a36013301597daef41fbe593a02cc513d0b55527ec2df1050e2e8ff49c85c2"), 33); hdnode_serialize_private(&node, fingerprint, str, sizeof(str)); ck_assert_str_eq(str, "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi"); - r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, &node2, NULL); ck_assert_int_eq(r, 0); ck_assert_int_eq(r, 0); hdnode_fill_public_key(&node2); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); hdnode_serialize_public(&node, fingerprint, str, sizeof(str)); ck_assert_str_eq(str, "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8"); - r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, &node2, NULL); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); memset(&node3.private_key, 0, 32); ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); @@ -512,12 +512,12 @@ START_TEST(test_bip32_vector_1) ck_assert_mem_eq(node.public_key, fromhex("035a784662a4a20a65bf6aab9ae98a6c068a81c52e4b032c0fb5400c706cfccc56"), 33); hdnode_serialize_private(&node, fingerprint, str, sizeof(str)); ck_assert_str_eq(str, "xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7"); - r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, &node2, NULL); ck_assert_int_eq(r, 0); hdnode_fill_public_key(&node2); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); hdnode_serialize_public(&node, fingerprint, str, sizeof(str)); ck_assert_str_eq(str, "xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw"); - r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, &node2, NULL); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); memset(&node3.private_key, 0, 32); ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); @@ -532,12 +532,12 @@ START_TEST(test_bip32_vector_1) ck_assert_mem_eq(node.public_key, fromhex("03501e454bf00751f24b1b489aa925215d66af2234e3891c3b21a52bedb3cd711c"), 33); hdnode_serialize_private(&node, fingerprint, str, sizeof(str)); ck_assert_str_eq(str, "xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs"); - r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, &node2, NULL); ck_assert_int_eq(r, 0); hdnode_fill_public_key(&node2); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); hdnode_serialize_public(&node, fingerprint, str, sizeof(str)); ck_assert_str_eq(str, "xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFHKkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ"); - r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, &node2, NULL); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); memset(&node3.private_key, 0, 32); ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); @@ -552,12 +552,12 @@ START_TEST(test_bip32_vector_1) ck_assert_mem_eq(node.public_key, fromhex("0357bfe1e341d01c69fe5654309956cbea516822fba8a601743a012a7896ee8dc2"), 33); hdnode_serialize_private(&node, fingerprint, str, sizeof(str)); ck_assert_str_eq(str, "xprv9z4pot5VBttmtdRTWfWQmoH1taj2axGVzFqSb8C9xaxKymcFzXBDptWmT7FwuEzG3ryjH4ktypQSAewRiNMjANTtpgP4mLTj34bhnZX7UiM"); - r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, &node2, NULL); ck_assert_int_eq(r, 0); hdnode_fill_public_key(&node2); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); hdnode_serialize_public(&node, fingerprint, str, sizeof(str)); ck_assert_str_eq(str, "xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5"); - r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, &node2, NULL); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); memset(&node3.private_key, 0, 32); ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); @@ -572,12 +572,12 @@ START_TEST(test_bip32_vector_1) ck_assert_mem_eq(node.public_key, fromhex("02e8445082a72f29b75ca48748a914df60622a609cacfce8ed0e35804560741d29"), 33); hdnode_serialize_private(&node, fingerprint, str, sizeof(str)); ck_assert_str_eq(str, "xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334"); - r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, &node2, NULL); ck_assert_int_eq(r, 0); hdnode_fill_public_key(&node2); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); hdnode_serialize_public(&node, fingerprint, str, sizeof(str)); ck_assert_str_eq(str, "xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV"); - r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, &node2, NULL); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); memset(&node3.private_key, 0, 32); ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); @@ -592,12 +592,12 @@ START_TEST(test_bip32_vector_1) ck_assert_mem_eq(node.public_key, fromhex("022a471424da5e657499d1ff51cb43c47481a03b1e77f951fe64cec9f5a48f7011"), 33); hdnode_serialize_private(&node, fingerprint, str, sizeof(str)); ck_assert_str_eq(str, "xprvA41z7zogVVwxVSgdKUHDy1SKmdb533PjDz7J6N6mV6uS3ze1ai8FHa8kmHScGpWmj4WggLyQjgPie1rFSruoUihUZREPSL39UNdE3BBDu76"); - r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, &node2, NULL); ck_assert_int_eq(r, 0); hdnode_fill_public_key(&node2); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); hdnode_serialize_public(&node, fingerprint, str, sizeof(str)); ck_assert_str_eq(str, "xpub6H1LXWLaKsWFhvm6RVpEL9P4KfRZSW7abD2ttkWP3SSQvnyA8FSVqNTEcYFgJS2UaFcxupHiYkro49S8yGasTvXEYBVPamhGW6cFJodrTHy"); - r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, &node2, NULL); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); memset(&node3.private_key, 0, 32); ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); @@ -624,12 +624,12 @@ START_TEST(test_bip32_vector_2) ck_assert_mem_eq(node.public_key, fromhex("03cbcaa9c98c877a26977d00825c956a238e8dddfbd322cce4f74b0b5bd6ace4a7"), 33); hdnode_serialize_private(&node, fingerprint, str, sizeof(str)); ck_assert_str_eq(str, "xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U"); - r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, &node2, NULL); ck_assert_int_eq(r, 0); hdnode_fill_public_key(&node2); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); hdnode_serialize_public(&node, fingerprint, str, sizeof(str)); ck_assert_str_eq(str, "xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB"); - r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, &node2, NULL); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); memset(&node3.private_key, 0, 32); ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); @@ -645,12 +645,12 @@ START_TEST(test_bip32_vector_2) ck_assert_mem_eq(node.public_key, fromhex("02fc9e5af0ac8d9b3cecfe2a888e2117ba3d089d8585886c9c826b6b22a98d12ea"), 33); hdnode_serialize_private(&node, fingerprint, str, sizeof(str)); ck_assert_str_eq(str, "xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt"); - r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, &node2, NULL); ck_assert_int_eq(r, 0); hdnode_fill_public_key(&node2); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); hdnode_serialize_public(&node, fingerprint, str, sizeof(str)); ck_assert_str_eq(str, "xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH"); - r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, &node2, NULL); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); memset(&node3.private_key, 0, 32); ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); @@ -666,12 +666,12 @@ START_TEST(test_bip32_vector_2) ck_assert_mem_eq(node.public_key, fromhex("03c01e7425647bdefa82b12d9bad5e3e6865bee0502694b94ca58b666abc0a5c3b"), 33); hdnode_serialize_private(&node, fingerprint, str, sizeof(str)); ck_assert_str_eq(str, "xprv9wSp6B7kry3Vj9m1zSnLvN3xH8RdsPP1Mh7fAaR7aRLcQMKTR2vidYEeEg2mUCTAwCd6vnxVrcjfy2kRgVsFawNzmjuHc2YmYRmagcEPdU9"); - r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, &node2, NULL); ck_assert_int_eq(r, 0); hdnode_fill_public_key(&node2); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); hdnode_serialize_public(&node, fingerprint, str, sizeof(str)); ck_assert_str_eq(str, "xpub6ASAVgeehLbnwdqV6UKMHVzgqAG8Gr6riv3Fxxpj8ksbH9ebxaEyBLZ85ySDhKiLDBrQSARLq1uNRts8RuJiHjaDMBU4Zn9h8LZNnBC5y4a"); - r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, &node2, NULL); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); memset(&node3.private_key, 0, 32); ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); @@ -687,12 +687,12 @@ START_TEST(test_bip32_vector_2) ck_assert_mem_eq(node.public_key, fromhex("03a7d1d856deb74c508e05031f9895dab54626251b3806e16b4bd12e781a7df5b9"), 33); hdnode_serialize_private(&node, fingerprint, str, sizeof(str)); ck_assert_str_eq(str, "xprv9zFnWC6h2cLgpmSA46vutJzBcfJ8yaJGg8cX1e5StJh45BBciYTRXSd25UEPVuesF9yog62tGAQtHjXajPPdbRCHuWS6T8XA2ECKADdw4Ef"); - r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, &node2, NULL); ck_assert_int_eq(r, 0); hdnode_fill_public_key(&node2); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); hdnode_serialize_public(&node, fingerprint, str, sizeof(str)); ck_assert_str_eq(str, "xpub6DF8uhdarytz3FWdA8TvFSvvAh8dP3283MY7p2V4SeE2wyWmG5mg5EwVvmdMVCQcoNJxGoWaU9DCWh89LojfZ537wTfunKau47EL2dhHKon"); - r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, &node2, NULL); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); memset(&node3.private_key, 0, 32); ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); @@ -708,12 +708,12 @@ START_TEST(test_bip32_vector_2) ck_assert_mem_eq(node.public_key, fromhex("02d2b36900396c9282fa14628566582f206a5dd0bcc8d5e892611806cafb0301f0"), 33); hdnode_serialize_private(&node, fingerprint, str, sizeof(str)); ck_assert_str_eq(str, "xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc"); - r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, &node2, NULL); ck_assert_int_eq(r, 0); hdnode_fill_public_key(&node2); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); hdnode_serialize_public(&node, fingerprint, str, sizeof(str)); ck_assert_str_eq(str, "xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL"); - r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, &node2, NULL); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); memset(&node3.private_key, 0, 32); ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); @@ -729,12 +729,12 @@ START_TEST(test_bip32_vector_2) ck_assert_mem_eq(node.public_key, fromhex("024d902e1a2fc7a8755ab5b694c575fce742c48d9ff192e63df5193e4c7afe1f9c"), 33); hdnode_serialize_private(&node, fingerprint, str, sizeof(str)); ck_assert_str_eq(str, "xprvA2nrNbFZABcdryreWet9Ea4LvTJcGsqrMzxHx98MMrotbir7yrKCEXw7nadnHM8Dq38EGfSh6dqA9QWTyefMLEcBYJUuekgW4BYPJcr9E7j"); - r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, &node2, NULL); ck_assert_int_eq(r, 0); hdnode_fill_public_key(&node2); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); hdnode_serialize_public(&node, fingerprint, str, sizeof(str)); ck_assert_str_eq(str, "xpub6FnCn6nSzZAw5Tw7cgR9bi15UV96gLZhjDstkXXxvCLsUXBGXPdSnLFbdpq8p9HmGsApME5hQTZ3emM2rnY5agb9rXpVGyy3bdW6EEgAtqt"); - r = hdnode_deserialize(str, &node2); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, &node2, NULL); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); memset(&node3.private_key, 0, 32); ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); diff --git a/tools/xpubaddrgen.c b/tools/xpubaddrgen.c index 12b350d72..7d42af61a 100644 --- a/tools/xpubaddrgen.c +++ b/tools/xpubaddrgen.c @@ -8,7 +8,7 @@ void process_job(uint32_t jobid, const char *xpub, uint32_t change, uint32_t from, uint32_t to) { HDNode node, child; - if (change > 1 || to <= from || hdnode_deserialize(xpub, &node) != 0) { + if (change > 1 || to <= from || hdnode_deserialize(xpub, &node, NULL) != 0) { printf("%d error\n", jobid); return; } From 906c543ebc70759f98a47549dd238f78c119d988 Mon Sep 17 00:00:00 2001 From: Roman Zeyde Date: Thu, 13 Oct 2016 22:24:17 +0300 Subject: [PATCH 330/627] Implement ECDH with Curve25519 at BIP32 module --- bip32.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ bip32.h | 2 ++ curves.c | 1 + curves.h | 1 + 4 files changed, 55 insertions(+) diff --git a/bip32.c b/bip32.c index f5b8b3331..93455dc6c 100644 --- a/bip32.c +++ b/bip32.c @@ -37,6 +37,7 @@ #include "secp256k1.h" #include "nist256p1.h" #include "ed25519.h" +#include "curve25519-donna.h" #if USE_ETHEREUM #include "sha3.h" #endif @@ -47,6 +48,12 @@ const curve_info ed25519_info = { 0 }; +const curve_info curve25519_info = { + /* bip32_name */ + "curve25519 seed", + 0 +}; + int hdnode_from_xpub(uint32_t depth, uint32_t child_num, const uint8_t *chain_code, const uint8_t *public_key, const char* curve, HDNode *out) { const curve_info *info = get_curve_by_name(curve); @@ -393,6 +400,9 @@ void hdnode_fill_public_key(HDNode *node) if (node->curve == &ed25519_info) { node->public_key[0] = 1; ed25519_publickey(node->private_key, node->public_key + 1); + } else if (node->curve == &curve25519_info) { + node->public_key[0] = 1; + curve25519_publickey(node->public_key + 1, node->private_key); } else { ecdsa_get_public_key33(node->curve->params, node->private_key, node->public_key); } @@ -427,6 +437,8 @@ int hdnode_sign(HDNode *node, const uint8_t *msg, uint32_t msg_len, uint8_t *sig hdnode_fill_public_key(node); ed25519_sign(msg, msg_len, node->private_key, node->public_key + 1, sig); return 0; + } else if (node->curve == &curve25519_info) { + return 1; // signatures are not supported } else { return ecdsa_sign(node->curve->params, node->private_key, msg, msg_len, sig, pby, is_canonical); } @@ -438,11 +450,47 @@ int hdnode_sign_digest(HDNode *node, const uint8_t *digest, uint8_t *sig, uint8_ hdnode_fill_public_key(node); ed25519_sign(digest, 32, node->private_key, node->public_key + 1, sig); return 0; + } else if (node->curve == &curve25519_info) { + return 1; // signatures are not supported } else { return ecdsa_sign_digest(node->curve->params, node->private_key, digest, sig, pby, is_canonical); } } +int hdnode_get_shared_key(const HDNode *node, const uint8_t *peer_public_key, uint8_t *session_key, int *result_size) +{ + // Use elliptic curve Diffie-Helman to compute shared session key + if (node->curve == &ed25519_info) { + *result_size = 0; + return 1; // ECDH is not supported + } else if (node->curve == &curve25519_info) { + session_key[0] = 0x04; + if (peer_public_key[0] != 0x40) { + return 1; // Curve25519 public key should start with 0x40 byte. + } + curve25519_scalarmult(session_key + 1, node->private_key, peer_public_key + 1); + *result_size = 33; + return 0; + } else { + curve_point point; + const ecdsa_curve *curve = node->curve->params; + if (!ecdsa_read_pubkey(curve, peer_public_key, &point)) { + return 1; + } + bignum256 k; + bn_read_be(node->private_key, &k); + point_multiply(curve, &k, &point, &point); + MEMSET_BZERO(&k, sizeof(k)); + + session_key[0] = 0x04; + bn_write_be(&point.x, session_key + 1); + bn_write_be(&point.y, session_key + 33); + MEMSET_BZERO(&point, sizeof(point)); + *result_size = 65; + return 0; + } +} + int hdnode_serialize(const HDNode *node, uint32_t fingerprint, uint32_t version, char use_public, char *str, int strsize) { @@ -514,5 +562,8 @@ const curve_info *get_curve_by_name(const char *curve_name) { if (strcmp(curve_name, ED25519_NAME) == 0) { return &ed25519_info; } + if (strcmp(curve_name, CURVE25519_NAME) == 0) { + return &curve25519_info; + } return 0; } diff --git a/bip32.h b/bip32.h index 24f674860..e7226f02d 100644 --- a/bip32.h +++ b/bip32.h @@ -74,6 +74,8 @@ int hdnode_get_ethereum_pubkeyhash(const HDNode *node, uint8_t *pubkeyhash); int hdnode_sign(HDNode *node, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64])); int hdnode_sign_digest(HDNode *node, const uint8_t *digest, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64])); +int hdnode_get_shared_key(const HDNode *node, const uint8_t *peer_public_key, uint8_t *session_key, int *result_size); + int hdnode_serialize_public(const HDNode *node, uint32_t fingerprint, char *str, int strsize); int hdnode_serialize_private(const HDNode *node, uint32_t fingerprint, char *str, int strsize); diff --git a/curves.c b/curves.c index 86b671a2d..e2fa10239 100644 --- a/curves.c +++ b/curves.c @@ -23,3 +23,4 @@ const char SECP256K1_NAME[] = "secp256k1"; const char NIST256P1_NAME[] = "nist256p1"; const char ED25519_NAME[] = "ed25519"; +const char CURVE25519_NAME[] = "curve25519"; diff --git a/curves.h b/curves.h index be841b688..dc99bc66f 100644 --- a/curves.h +++ b/curves.h @@ -26,5 +26,6 @@ extern const char SECP256K1_NAME[]; extern const char NIST256P1_NAME[]; extern const char ED25519_NAME[]; +extern const char CURVE25519_NAME[]; #endif From 43f86e660d657f81b8d139aa7ee12b08e48a5c0e Mon Sep 17 00:00:00 2001 From: Roman Zeyde Date: Thu, 13 Oct 2016 22:24:47 +0300 Subject: [PATCH 331/627] Add Python tests for Curve25519 ECDH --- setup.py | 1 + test_curves.py | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/setup.py b/setup.py index a06f57cb1..ea76ea7ce 100755 --- a/setup.py +++ b/setup.py @@ -10,6 +10,7 @@ srcs = [ 'bignum', 'bip32', 'ecdsa', + 'curve25519', 'hmac', 'rand', 'ripemd160', diff --git a/test_curves.py b/test_curves.py index 0c47dfeec..fb89ec811 100755 --- a/test_curves.py +++ b/test_curves.py @@ -1,5 +1,6 @@ #!/usr/bin/python import ctypes as c +import curve25519 import random import ecdsa import hashlib @@ -399,3 +400,39 @@ def test_validate_pubkey(curve, r): def test_validate_pubkey_direct(point): assert lib.ecdsa_validate_pubkey(point.ptr, to_POINT(point.p)) + + +def test_curve25519(r): + sec1 = bytes(bytearray(r.randbytes(32))) + sec2 = bytes(bytearray(r.randbytes(32))) + pub1 = curve25519.Private(sec1).get_public() + pub2 = curve25519.Private(sec2).get_public() + + session1 = r.randbytes(32) + lib.curve25519_scalarmult(session1, sec2, pub1.public) + session2 = r.randbytes(32) + lib.curve25519_scalarmult(session2, sec1, pub2.public) + assert bytearray(session1) == bytearray(session2) + + shared1 = curve25519.Private(sec2).get_shared_key(pub1, hashfunc=lambda x: x) + shared2 = curve25519.Private(sec1).get_shared_key(pub2, hashfunc=lambda x: x) + assert shared1 == shared2 + assert bytearray(session1) == shared1 + assert bytearray(session2) == shared2 + + +def test_curve25519_pubkey(r): + sec = bytes(bytearray(r.randbytes(32))) + pub = curve25519.Private(sec).get_public() + res = r.randbytes(32) + lib.curve25519_publickey(res, sec) + assert bytearray(res) == pub.public + + +def test_curve25519_scalarmult_from_gpg(r): + sec = binascii.unhexlify('4a1e76f133afb29dbc7860bcbc16d0e829009cc15c2f81ed26de1179b1d9c938') + pub = binascii.unhexlify('5d6fc75c016e85b17f54e0128a216d5f9229f25bac1ec85cecab8daf48621b31') + res = r.randbytes(32) + lib.curve25519_scalarmult(res, sec[::-1], pub[::-1]) + expected = 'a93dbdb23e5c99da743e203bd391af79f2b83fb8d0fd6ec813371c71f08f2d4d' + assert binascii.hexlify(bytearray(res)) == expected From 0167d06378500392f3d7f656df53faecc81102e2 Mon Sep 17 00:00:00 2001 From: Roman Zeyde Date: Sat, 15 Oct 2016 15:26:51 +0300 Subject: [PATCH 332/627] Fix Travis build --- .travis.yml | 2 +- CMakeLists.txt | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index d270aea8b..9cfccfdf1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,7 @@ addons: - python-pip install: - - pip install --user pytest ecdsa + - pip install --user pytest ecdsa curve25519-donna script: - make diff --git a/CMakeLists.txt b/CMakeLists.txt index 7e25a4551..361dfaf2d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,6 +2,7 @@ cmake_minimum_required(VERSION 2.6) set(SOURCES address.c aescrypt.c aeskey.c aes_modes.c aestab.c base58.c bignum.c bip32.c bip39.c ecdsa.c hmac.c nist256p1.c pbkdf2.c rand.c ripemd160.c secp256k1.c sha2.c ed25519-donna/ed25519.c sha3.c) include_directories(ed25519-donna) +include_directories(curve25519-donna) # disable sequence point warnings where they are expected set_source_files_properties(aeskey.c PROPERTIES From 54cc18c4935a1566fd0407e74deaf4dc542a33df Mon Sep 17 00:00:00 2001 From: Fabian Schuh Date: Tue, 27 Sep 2016 22:48:36 +0200 Subject: [PATCH 333/627] Steem integration --- Makefile | 1 + base58.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ base58.h | 6 ++++++ options.h | 5 +++++ tests.c | 37 +++++++++++++++++++++++++++++++++++- 5 files changed, 104 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 16e667a59..c62447b17 100644 --- a/Makefile +++ b/Makefile @@ -31,6 +31,7 @@ CFLAGS += -DED25519_NO_INLINE_ASM CFLAGS += -DED25519_FORCE_32BIT=1 CFLAGS += -Ied25519-donna -Icurve25519-donna -I. CFLAGS += -DUSE_ETHEREUM=1 +CFLAGS += -DUSE_GRAPHENE=1 # disable certain optimizations and features when small footprint is required ifdef SMALL diff --git a/base58.c b/base58.c index 5355fcb1e..2c44d3985 100644 --- a/base58.c +++ b/base58.c @@ -27,6 +27,7 @@ #include "base58.h" #include "sha2.h" #include "macros.h" +#include "ripemd160.h" static const int8_t b58digits_map[] = { -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, @@ -217,3 +218,58 @@ int base58_decode_check(const char *str, uint8_t *data, int datalen) memcpy(data, nd, res - 4); return res - 4; } + +#if USE_GRAPHENE +int b58gphcheck(const void *bin, size_t binsz, const char *base58str) +{ + unsigned char buf[32]; + const uint8_t *binc = bin; + unsigned i; + if (binsz < 4) + return -4; + ripemd160(bin, binsz - 4, buf); // No double SHA256, but a single RIPEMD160 + if (memcmp(&binc[binsz - 4], buf, 4)) + return -1; + + // Check number of zeros is correct AFTER verifying checksum (to avoid possibility of accessing base58str beyond the end) + for (i = 0; binc[i] == '\0' && base58str[i] == '1'; ++i) + {} // Just finding the end of zeros, nothing to do in loop + if (binc[i] == '\0' || base58str[i] == '1') + return -3; + + return binc[0]; +} + +int base58gph_encode_check(const uint8_t *data, int datalen, char *str, int strsize) +{ + if (datalen > 128) { + return 0; + } + uint8_t buf[datalen + 32]; + uint8_t *hash = buf + datalen; + memcpy(buf, data, datalen); + ripemd160(data, datalen, hash); // No double SHA256, but a single RIPEMD160 + size_t res = strsize; + bool success = b58enc(str, &res, buf, datalen + 4); + MEMSET_BZERO(buf, sizeof(buf)); + return success ? res : 0; +} + +int base58gph_decode_check(const char *str, uint8_t *data, int datalen) +{ + if (datalen > 128) { + return 0; + } + uint8_t d[datalen + 4]; + size_t res = datalen + 4; + if (b58tobin(d, &res, str) != true) { + return 0; + } + uint8_t *nd = d + datalen + 4 - res; + if (b58gphcheck(nd, res, str) < 0) { + return 0; + } + memcpy(data, nd, res - 4); + return res - 4; +} +#endif diff --git a/base58.h b/base58.h index a53e4385b..094849bae 100644 --- a/base58.h +++ b/base58.h @@ -35,4 +35,10 @@ bool b58tobin(void *bin, size_t *binszp, const char *b58); int b58check(const void *bin, size_t binsz, const char *base58str); bool b58enc(char *b58, size_t *b58sz, const void *data, size_t binsz); +#if USE_GRAPHENE +int base58gph_encode_check(const uint8_t *data, int datalen, char *str, int strsize); +int base58gph_decode_check(const char *str, uint8_t *data, int datalen); +int b58gphcheck(const void *bin, size_t binsz, const char *base58str); +#endif + #endif diff --git a/options.h b/options.h index fabca9f9b..6b7de989b 100644 --- a/options.h +++ b/options.h @@ -61,6 +61,11 @@ #define USE_ETHEREUM 0 #endif +// support Graphene operations (STEEM, BitShares) +#ifndef USE_GRAPHENE +#define USE_GRAPHENE 0 +#endif + // support Keccak hashing #ifndef USE_KECCAK #define USE_KECCAK USE_ETHEREUM diff --git a/tests.c b/tests.c index 40a3d6dd4..3a492db10 100644 --- a/tests.c +++ b/tests.c @@ -442,6 +442,38 @@ START_TEST(test_base58) } END_TEST +// Graphene Base85CheckEncoding +START_TEST(test_base58gph) +{ + static const char *base58_vector[] = { + "02e649f63f8e8121345fd7f47d0d185a3ccaa843115cd2e9392dcd9b82263bc680", "6dumtt9swxCqwdPZBGXh9YmHoEjFFnNfwHaTqRbQTghGAY2gRz", + "021c7359cd885c0e319924d97e3980206ad64387aff54908241125b3a88b55ca16", "5725vivYpuFWbeyTifZ5KevnHyqXCi5hwHbNU9cYz1FHbFXCxX", + "02f561e0b57a552df3fa1df2d87a906b7a9fc33a83d5d15fa68a644ecb0806b49a", "6kZKHSuxqAwdCYsMvwTcipoTsNE2jmEUNBQufGYywpniBKXWZK", + "03e7595c3e6b58f907bee951dc29796f3757307e700ecf3d09307a0cc4a564eba3", "8b82mpnH8YX1E9RHnU2a2YgLTZ8ooevEGP9N15c1yFqhoBvJur", + 0, 0, + }; + const char **raw = base58_vector; + const char **str = base58_vector + 1; + uint8_t rawn[34]; + char strn[53]; + int r; + while (*raw && *str) { + int len = strlen(*raw) / 2; + + memcpy(rawn, fromhex(*raw), len); + r = base58gph_encode_check(rawn, len, strn, sizeof(strn)); + ck_assert_int_eq((size_t)r, strlen(*str) + 1); + ck_assert_str_eq(strn, *str); + + r = base58gph_decode_check(strn, rawn, len); + ck_assert_int_eq(r, len); + ck_assert_mem_eq(rawn, fromhex(*raw), len); + + raw += 2; str += 2; + } +} +END_TEST + START_TEST(test_bignum_divmod) { uint32_t r; @@ -2603,7 +2635,6 @@ START_TEST(test_ethereum_pubkeyhash) } END_TEST - // define test suite and cases Suite *test_suite(void) { @@ -2634,6 +2665,10 @@ Suite *test_suite(void) tcase_add_test(tc, test_base58); suite_add_tcase(s, tc); + tc = tcase_create("base58gph"); + tcase_add_test(tc, test_base58gph); + suite_add_tcase(s, tc); + tc = tcase_create("bignum_divmod"); tcase_add_test(tc, test_bignum_divmod); suite_add_tcase(s, tc); From ed755120af13a58ae339fc02c911573a71bee87d Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 16 Oct 2016 02:26:16 +0200 Subject: [PATCH 334/627] fix broken test_speed --- bip32.c | 6 ++---- ecdsa.h | 2 ++ test_speed.c | 43 +++++++++++++++++++++++-------------------- 3 files changed, 27 insertions(+), 24 deletions(-) diff --git a/bip32.c b/bip32.c index 820cc9136..a9fac779b 100644 --- a/bip32.c +++ b/bip32.c @@ -132,7 +132,7 @@ int hdnode_from_seed(const uint8_t *seed, int seed_len, const char* curve, HDNod } memcpy(out->private_key, I, 32); memcpy(out->chain_code, I + 32, 32); - + MEMSET_BZERO(out->public_key, sizeof(out->public_key)); MEMSET_BZERO(I, sizeof(I)); return 1; } @@ -215,7 +215,6 @@ int hdnode_public_ckd(HDNode *inout, uint32_t i) { uint8_t data[1 + 32 + 4]; uint8_t I[32 + 32]; - uint8_t fingerprint[32]; curve_point a, b; bignum256 c; @@ -265,7 +264,6 @@ int hdnode_public_ckd(HDNode *inout, uint32_t i) // Wipe all stack data. MEMSET_BZERO(data, sizeof(data)); MEMSET_BZERO(I, sizeof(I)); - MEMSET_BZERO(fingerprint, sizeof(fingerprint)); MEMSET_BZERO(&a, sizeof(a)); MEMSET_BZERO(&b, sizeof(b)); MEMSET_BZERO(&c, sizeof(c)); @@ -295,7 +293,7 @@ int hdnode_public_ckd_address_optimized(const curve_point *pub, const uint8_t *p failed = true; } else { scalar_multiply(&secp256k1, &c, &b); // b = c * G - point_add(&secp256k1, pub, &b); // b = a + b + point_add(&secp256k1, pub, &b); // b = a + b if (point_is_infinity(&b)) { failed = true; } diff --git a/ecdsa.h b/ecdsa.h index f74bf2efc..a2a4e29c2 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -50,6 +50,8 @@ typedef struct { #define MAX_ADDR_RAW_SIZE (4 + 20) #define MAX_WIF_RAW_SIZE (4 + 32 + 1) +#define MAX_ADDR_SIZE (40) +#define MAX_WIF_SIZE (58) // rfc6979 pseudo random number generator state typedef struct { diff --git a/test_speed.c b/test_speed.c index 23ce4dcc4..070561c91 100644 --- a/test_speed.c +++ b/test_speed.c @@ -9,7 +9,7 @@ #include "nist256p1.h" #include "ed25519.h" -uint8_t msg[32]; +static uint8_t msg[32]; void prepare_msg(void) { @@ -76,49 +76,52 @@ void test_verify_speed(void) { bench_ed25519(); } -HDNode root; +static HDNode root; void prepare_node(void) { hdnode_from_seed((uint8_t *)"NothingToSeeHere", 16, SECP256K1_NAME, &root); + hdnode_fill_public_key(&root); } -void bench_ckd_normal(void) { - char addr[40]; +void bench_ckd_normal(int iterations) { + char addr[MAX_ADDR_SIZE]; + HDNode node; clock_t t = clock(); - for (int i = 0; i < 1000; i++) { - HDNode node = root; + for (int i = 0; i < iterations; i++) { + memcpy(&node, &root, sizeof(HDNode)); hdnode_public_ckd(&node, i); - ecdsa_get_address(node.public_key, 0, addr, 40); - if (i == 0) { + hdnode_fill_public_key(&node); + ecdsa_get_address(node.public_key, 0, addr, sizeof(addr)); + if (i == 0 || i == iterations - 1) { printf("address = %s\n", addr); } } - printf("CKD normal speed: %0.2f iter/s\n", 1000.0f / ((float)(clock() - t) / CLOCKS_PER_SEC)); + printf("CKD normal speed: %0.2f iter/s\n", iterations / ((float)(clock() - t) / CLOCKS_PER_SEC)); } -void bench_ckd_optimized(void) { - char addr[40]; +void bench_ckd_optimized(int iterations) { + char addr[MAX_ADDR_SIZE]; curve_point pub; - ecdsa_read_pubkey(0, root.public_key, &pub); + ecdsa_read_pubkey(&secp256k1, root.public_key, &pub); clock_t t = clock(); - for (int i = 0; i < 1000; i++) { - hdnode_public_ckd_address_optimized(&pub, root.public_key, root.chain_code, i, 0, addr, 40); - if (i == 0) { + for (int i = 0; i < iterations; i++) { + hdnode_public_ckd_address_optimized(&pub, root.public_key, root.chain_code, i, 0, addr, sizeof(addr)); + if (i == 0 || i == iterations -1) { printf("address = %s\n", addr); } } - printf("CKD optim speed: %0.2f iter/s\n", 1000.0f / ((float)(clock() - t) / CLOCKS_PER_SEC)); + printf("CKD optim speed: %0.2f iter/s\n", iterations / ((float)(clock() - t) / CLOCKS_PER_SEC)); } -void test_ckd_speed(void) { +void test_ckd_speed(int iterations) { prepare_node(); - bench_ckd_normal(); - bench_ckd_optimized(); + bench_ckd_normal(iterations); + bench_ckd_optimized(iterations); } int main(void) { test_verify_speed(); - test_ckd_speed(); + test_ckd_speed(1000); return 0; } From e6574f8eea98efb13fec98cbfab30733cc107b10 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 19 Oct 2016 20:42:50 +0200 Subject: [PATCH 335/627] extract ck_assert_mem macros to separate file check_mem.h --- check_mem.h | 26 ++++++++++++++++++++++++++ tests.c | 26 +++----------------------- 2 files changed, 29 insertions(+), 23 deletions(-) create mode 100644 check_mem.h diff --git a/check_mem.h b/check_mem.h new file mode 100644 index 000000000..a66751e21 --- /dev/null +++ b/check_mem.h @@ -0,0 +1,26 @@ +#ifndef CHECK_MEM_H +#define CHECK_MEM_H + +#define _ck_assert_mem(X, Y, L, OP) do { \ + const char* _ck_x = (const char*)(void*)(X); \ + const char* _ck_y = (const char*)(void*)(Y); \ + size_t _ck_l = (L); \ + char _ck_x_str[129]; \ + char _ck_y_str[129]; \ + static char _ck_hexdigits[] = "0123456789abcdef"; \ + size_t _ck_i; \ + for (_ck_i = 0; _ck_i < ((_ck_l > 64) ? 64 : _ck_l); _ck_i++) { \ + _ck_x_str[_ck_i * 2 ] = _ck_hexdigits[(_ck_x[_ck_i] >> 4) & 0xF]; \ + _ck_y_str[_ck_i * 2 ] = _ck_hexdigits[(_ck_y[_ck_i] >> 4) & 0xF]; \ + _ck_x_str[_ck_i * 2 + 1] = _ck_hexdigits[_ck_x[_ck_i] & 0xF]; \ + _ck_y_str[_ck_i * 2 + 1] = _ck_hexdigits[_ck_y[_ck_i] & 0xF]; \ + } \ + _ck_x_str[_ck_i * 2] = 0; \ + _ck_y_str[_ck_i * 2] = 0; \ + ck_assert_msg(0 OP memcmp(_ck_y, _ck_x, _ck_l), \ + "Assertion '"#X#OP#Y"' failed: "#X"==\"%s\", "#Y"==\"%s\"", _ck_x_str, _ck_y_str); \ +} while (0) +#define ck_assert_mem_eq(X, Y, L) _ck_assert_mem(X, Y, L, ==) +#define ck_assert_mem_ne(X, Y, L) _ck_assert_mem(X, Y, L, !=) + +#endif diff --git a/tests.c b/tests.c index 3a492db10..632b36147 100644 --- a/tests.c +++ b/tests.c @@ -21,13 +21,15 @@ * OTHER DEALINGS IN THE SOFTWARE. */ -#include #include #include #include #include #include +#include +#include "check_mem.h" + #include "aes.h" #include "bignum.h" #include "base58.h" @@ -61,28 +63,6 @@ uint8_t *fromhex(const char *str) return buf; } -char *tohex(const uint8_t *bin, size_t l) -{ - char *buf = (char *)malloc(l * 2 + 1); - static char digits[] = "0123456789abcdef"; - for (size_t i = 0; i < l; i++) { - buf[i*2 ] = digits[(bin[i] >> 4) & 0xF]; - buf[i*2+1] = digits[bin[i] & 0xF]; - } - buf[l * 2] = 0; - return buf; -} - -#define _ck_assert_mem(X, Y, L, OP) do { \ - const void* _ck_x = (X); \ - const void* _ck_y = (Y); \ - size_t _ck_l = (L); \ - ck_assert_msg(0 OP memcmp(_ck_y, _ck_x, _ck_l), \ - "Assertion '"#X#OP#Y"' failed: "#X"==\"%s\", "#Y"==\"%s\"", tohex(_ck_x, _ck_l), tohex(_ck_y, _ck_l)); \ -} while (0) -#define ck_assert_mem_eq(X, Y, L) _ck_assert_mem(X, Y, L, ==) -#define ck_assert_mem_ne(X, Y, L) _ck_assert_mem(X, Y, L, !=) - START_TEST(test_bignum_read_be) { bignum256 a; From ca4057aca084f31e48d95961ea96b563c9484304 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 20 Oct 2016 12:04:05 +0200 Subject: [PATCH 336/627] tests: cleanup fromhex function --- tests.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/tests.c b/tests.c index 632b36147..8f39d4026 100644 --- a/tests.c +++ b/tests.c @@ -46,18 +46,19 @@ #include "ed25519.h" #include "script.h" -uint8_t *fromhex(const char *str) +#define FROMHEX_MAXLEN 256 + +const uint8_t *fromhex(const char *str) { - static uint8_t buf[256]; - uint8_t c; - for (size_t i = 0; i < strlen(str) / 2; i++) { - c = 0; - if (str[i*2] >= '0' && str[i*2] <= '9') c += (str[i*2] - '0') << 4; - if (str[i*2] >= 'a' && str[i*2] <= 'f') c += (10 + str[i*2] - 'a') << 4; - if (str[i*2] >= 'A' && str[i*2] <= 'F') c += (10 + str[i*2] - 'A') << 4; - if (str[i*2+1] >= '0' && str[i*2+1] <= '9') c += (str[i*2+1] - '0'); - if (str[i*2+1] >= 'a' && str[i*2+1] <= 'f') c += (10 + str[i*2+1] - 'a'); - if (str[i*2+1] >= 'A' && str[i*2+1] <= 'F') c += (10 + str[i*2+1] - 'A'); + static uint8_t buf[FROMHEX_MAXLEN]; + size_t len = strlen(str) / 2; + if (len > FROMHEX_MAXLEN) len = FROMHEX_MAXLEN; + for (size_t i = 0; i < len; i++) { + uint8_t c = 0; + if (str[i * 2] >= '0' && str[i*2] <= '9') c += (str[i * 2] - '0') << 4; + if ((str[i * 2] & ~0x20) >= 'A' && (str[i*2] & ~0x20) <= 'F') c += (10 + (str[i * 2] & ~0x20) - 'A') << 4; + if (str[i * 2 + 1] >= '0' && str[i * 2 + 1] <= '9') c += (str[i * 2 + 1] - '0'); + if ((str[i * 2 + 1] & ~0x20) >= 'A' && (str[i * 2 + 1] & ~0x20) <= 'F') c += (10 + (str[i * 2 + 1] & ~0x20) - 'A'); buf[i] = c; } return buf; From cf21bb2fbf4b0964ab23abf2fea5387c0401d10b Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 21 Oct 2016 18:19:01 +0200 Subject: [PATCH 337/627] refactor ECDH multiplication into ecdh_multiply function --- bip32.c | 13 +------------ ecdsa.c | 20 ++++++++++++++++++++ ecdsa.h | 1 + 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/bip32.c b/bip32.c index a9fac779b..b1fe8fc0a 100644 --- a/bip32.c +++ b/bip32.c @@ -470,20 +470,9 @@ int hdnode_get_shared_key(const HDNode *node, const uint8_t *peer_public_key, ui *result_size = 33; return 0; } else { - curve_point point; - const ecdsa_curve *curve = node->curve->params; - if (!ecdsa_read_pubkey(curve, peer_public_key, &point)) { + if (!ecdh_multiply(node->curve->params, node->private_key, peer_public_key, session_key)) { return 1; } - bignum256 k; - bn_read_be(node->private_key, &k); - point_multiply(curve, &k, &point, &point); - MEMSET_BZERO(&k, sizeof(k)); - - session_key[0] = 0x04; - bn_write_be(&point.x, session_key + 1); - bn_write_be(&point.y, session_key + 33); - MEMSET_BZERO(&point, sizeof(point)); *result_size = 65; return 0; } diff --git a/ecdsa.c b/ecdsa.c index fe73c4866..7e4d5b203 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -629,6 +629,26 @@ void scalar_multiply(const ecdsa_curve *curve, const bignum256 *k, curve_point * #endif +int ecdh_multiply(const ecdsa_curve *curve, const uint8_t *priv_key, const uint8_t *pub_key, uint8_t *session_key) +{ + curve_point point; + if (!ecdsa_read_pubkey(curve, pub_key, &point)) { + return 1; + } + + bignum256 k; + bn_read_be(priv_key, &k); + point_multiply(curve, &k, &point, &point); + MEMSET_BZERO(&k, sizeof(k)); + + session_key[0] = 0x04; + bn_write_be(&point.x, session_key + 1); + bn_write_be(&point.y, session_key + 33); + MEMSET_BZERO(&point, sizeof(point)); + + return 0; +} + // generate random K for signing void generate_k_random(bignum256 *k) { int i; diff --git a/ecdsa.h b/ecdsa.h index a2a4e29c2..7802d71df 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -67,6 +67,7 @@ int point_is_infinity(const curve_point *p); int point_is_equal(const curve_point *p, const curve_point *q); int point_is_negative_of(const curve_point *p, const curve_point *q); void scalar_multiply(const ecdsa_curve *curve, const bignum256 *k, curve_point *res); +int ecdh_multiply(const ecdsa_curve *curve, const uint8_t *priv_key, const uint8_t *pub_key, uint8_t *session_key); void uncompress_coords(const ecdsa_curve *curve, uint8_t odd, const bignum256 *x, bignum256 *y); int ecdsa_uncompress_pubkey(const ecdsa_curve *curve, const uint8_t *pub_key, uint8_t *uncompressed); From 228f9425d1b6f0050c2a1b29bf813d2077e1b19b Mon Sep 17 00:00:00 2001 From: Roman Zeyde Date: Sat, 22 Oct 2016 01:26:29 +0300 Subject: [PATCH 338/627] Fix small typo in return value checking (#75) --- bip32.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bip32.c b/bip32.c index b1fe8fc0a..a4d22e72b 100644 --- a/bip32.c +++ b/bip32.c @@ -470,7 +470,7 @@ int hdnode_get_shared_key(const HDNode *node, const uint8_t *peer_public_key, ui *result_size = 33; return 0; } else { - if (!ecdh_multiply(node->curve->params, node->private_key, peer_public_key, session_key)) { + if (ecdh_multiply(node->curve->params, node->private_key, peer_public_key, session_key) != 0) { return 1; } *result_size = 65; From 6d08eb99b8472a2896f73905c00a6405a258750c Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 22 Oct 2016 00:29:14 +0200 Subject: [PATCH 339/627] add ECDH to readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 26cada68f..ccfe4fc05 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,7 @@ These include: uses RFC6979 for deterministic signatures) - ECDSA public key derivation + Base58 address representation - Ed25519 signing/verifying +- ECDH using secp256k1, nist256p1 and Curve25519 - HMAC-SHA256 and HMAC-SHA512 - PBKDF2 - RIPEMD-160 From 420c71992a11972ea4ad6563011557bad6ae4464 Mon Sep 17 00:00:00 2001 From: Roman Zeyde Date: Mon, 24 Oct 2016 13:40:00 +0300 Subject: [PATCH 340/627] tests: add BIP32 ECDH (#76) * tests: add BIP32 ECDH * tests: BIP32 ECDH errors --- tests.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 73 insertions(+), 1 deletion(-) diff --git a/tests.c b/tests.c index 8f39d4026..757324b99 100644 --- a/tests.c +++ b/tests.c @@ -2510,6 +2510,72 @@ START_TEST(test_ed25519) { } END_TEST +static void test_bip32_ecdh_init_node(HDNode *node, const char *seed_str, const char *curve_name) { + hdnode_from_seed((const uint8_t *)seed_str, strlen(seed_str), curve_name, node); + hdnode_fill_public_key(node); + if (node->public_key[0] == 1) { + node->public_key[0] = 0x40; // Curve25519 public keys start with 0x40 byte + } +} + +static void test_bip32_ecdh(const char *curve_name, int expected_key_size, const uint8_t *expected_key) { + int res, key_size; + HDNode alice, bob; + uint8_t session_key1[expected_key_size], session_key2[expected_key_size]; + + test_bip32_ecdh_init_node(&alice, "Alice", curve_name); + test_bip32_ecdh_init_node(&bob, "Bob", curve_name); + + // Generate shared key from Alice's secret key and Bob's public key + res = hdnode_get_shared_key(&alice, bob.public_key, session_key1, &key_size); + ck_assert_int_eq(res, 0); + ck_assert_int_eq(key_size, expected_key_size); + ck_assert_mem_eq(session_key1, expected_key, key_size); + + // Generate shared key from Bob's secret key and Alice's public key + res = hdnode_get_shared_key(&bob, alice.public_key, session_key2, &key_size); + ck_assert_int_eq(res, 0); + ck_assert_int_eq(key_size, expected_key_size); + ck_assert_mem_eq(session_key2, expected_key, key_size); +} + +START_TEST(test_bip32_ecdh_nist256p1) { + test_bip32_ecdh( + NIST256P1_NAME, 65, + fromhex("044aa56f917323f071148cd29aa423f6bee96e7fe87f914d0b91a0f95388c6631646ea92e882773d7b0b1bec356b842c8559a1377673d3965fb931c8fe51e64873")); +} +END_TEST + +START_TEST(test_bip32_ecdh_curve25519) { + test_bip32_ecdh( + CURVE25519_NAME, 33, + fromhex("04f34e35516325bb0d4a58507096c444a05ba13524ccf66910f11ce96c62224169")); +} +END_TEST + +START_TEST(test_bip32_ecdh_errors) { + HDNode node; + const uint8_t peer_public_key[65] = {0}; // invalid public key + uint8_t session_key[65]; + int res, key_size = 0; + + test_bip32_ecdh_init_node(&node, "Seed", ED25519_NAME); + res = hdnode_get_shared_key(&node, peer_public_key, session_key, &key_size); + ck_assert_int_eq(res, 1); + ck_assert_int_eq(key_size, 0); + + test_bip32_ecdh_init_node(&node, "Seed", CURVE25519_NAME); + res = hdnode_get_shared_key(&node, peer_public_key, session_key, &key_size); + ck_assert_int_eq(res, 1); + ck_assert_int_eq(key_size, 0); + + test_bip32_ecdh_init_node(&node, "Seed", NIST256P1_NAME); + res = hdnode_get_shared_key(&node, peer_public_key, session_key, &key_size); + ck_assert_int_eq(res, 1); + ck_assert_int_eq(key_size, 0); +} +END_TEST + START_TEST(test_output_script) { static const char *vectors[] = { "76A914010966776006953D5567439E5E39F86A0D273BEE88AC", "16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM", @@ -2674,7 +2740,13 @@ Suite *test_suite(void) tcase_add_test(tc, test_bip32_ed25519_vector_1); tcase_add_test(tc, test_bip32_ed25519_vector_2); suite_add_tcase(s, tc); - + + tc = tcase_create("bip32-ecdh"); + tcase_add_test(tc, test_bip32_ecdh_nist256p1); + tcase_add_test(tc, test_bip32_ecdh_curve25519); + tcase_add_test(tc, test_bip32_ecdh_errors); + suite_add_tcase(s, tc); + tc = tcase_create("ecdsa"); tcase_add_test(tc, test_ecdsa_signature); suite_add_tcase(s, tc); From ce9022ad5df669de08ae69cf2772713041132952 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 24 Oct 2016 12:44:25 +0200 Subject: [PATCH 341/627] fix tests.c when USE_GRAPHENE=0 --- tests.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests.c b/tests.c index 757324b99..6b0394c67 100644 --- a/tests.c +++ b/tests.c @@ -423,6 +423,8 @@ START_TEST(test_base58) } END_TEST +#if USE_GRAPHENE + // Graphene Base85CheckEncoding START_TEST(test_base58gph) { @@ -455,6 +457,8 @@ START_TEST(test_base58gph) } END_TEST +#endif + START_TEST(test_bignum_divmod) { uint32_t r; @@ -2712,9 +2716,11 @@ Suite *test_suite(void) tcase_add_test(tc, test_base58); suite_add_tcase(s, tc); +#if USE_GRAPHENE tc = tcase_create("base58gph"); tcase_add_test(tc, test_base58gph); suite_add_tcase(s, tc); +#endif tc = tcase_create("bignum_divmod"); tcase_add_test(tc, test_bignum_divmod); From a8c7e5ef209350958113bdf02666569ef824c50c Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 24 Oct 2016 17:24:31 +0200 Subject: [PATCH 342/627] gui: fix build --- gui/gui.pro | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/gui/gui.pro b/gui/gui.pro index 2b89a71df..59ebd8ead 100644 --- a/gui/gui.pro +++ b/gui/gui.pro @@ -4,13 +4,32 @@ greaterThan(QT_MAJOR_VERSION, 4): QT += widgets TARGET = gui TEMPLATE = app -SOURCES += ../bip32.c ../bip39.c ../sha2.c ../pbkdf2.c ../hmac.c ../rand.c ../bignum.c ../ecdsa.c ../ripemd160.c ../base58.c ../secp256k1.c ../nist256p1.c ../curves.c ../ed25519-donna/ed25519.c mainwindow.cpp main.cpp +SOURCES += ../bip32.c +SOURCES += ../bip39.c +SOURCES += ../sha2.c +SOURCES += ../pbkdf2.c +SOURCES += ../hmac.c +SOURCES += ../rand.c +SOURCES += ../bignum.c +SOURCES += ../ecdsa.c +SOURCES += ../ripemd160.c +SOURCES += ../base58.c +SOURCES += ../secp256k1.c +SOURCES += ../nist256p1.c +SOURCES += ../curves.c +SOURCES += ../curve25519-donna/curve25519-donna.c +SOURCES += ../ed25519-donna/ed25519.c +SOURCES += mainwindow.cpp +SOURCES += main.cpp -HEADERS += mainwindow.h ../bip32.h ../bip39.h +HEADERS += mainwindow.h +HEADERS += ../bip32.h +HEADERS += ../bip39.h FORMS += mainwindow.ui INCLUDEPATH += .. +INCLUDEPATH += ../curve25519-donna INCLUDEPATH += ../ed25519-donna DEFINES += ED25519_CUSTOMRANDOM=1 From b61756806812b7661f859ff5a830ed26159735d3 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 24 Oct 2016 20:27:48 +0200 Subject: [PATCH 343/627] add curve25519 multiply to test_speed --- test_speed.c | 44 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 37 insertions(+), 7 deletions(-) diff --git a/test_speed.c b/test_speed.c index 070561c91..3a9b08b4b 100644 --- a/test_speed.c +++ b/test_speed.c @@ -8,6 +8,7 @@ #include "secp256k1.h" #include "nist256p1.h" #include "ed25519.h" +#include "curve25519-donna.h" static uint8_t msg[32]; @@ -18,7 +19,8 @@ void prepare_msg(void) } } -void bench_secp256k1(void) { +void bench_secp256k1(void) +{ uint8_t sig[64], pub[33], priv[32], pby; const ecdsa_curve *curve = &secp256k1; @@ -35,7 +37,8 @@ void bench_secp256k1(void) { printf("SECP256k1 verifying speed: %0.2f sig/s\n", 500.0f / ((float)(clock() - t) / CLOCKS_PER_SEC)); } -void bench_nist256p1(void) { +void bench_nist256p1(void) +{ uint8_t sig[64], pub[33], priv[32], pby; const ecdsa_curve *curve = &nist256p1; @@ -52,7 +55,8 @@ void bench_nist256p1(void) { printf("NIST256p1 verifying speed: %0.2f sig/s\n", 500.0f / ((float)(clock() - t) / CLOCKS_PER_SEC)); } -void bench_ed25519(void) { +void bench_ed25519(void) +{ ed25519_public_key pk; ed25519_secret_key sk; ed25519_signature sig; @@ -69,13 +73,35 @@ void bench_ed25519(void) { printf("Ed25519 verifying speed: %0.2f sig/s\n", 500.0f / ((float)(clock() - t) / CLOCKS_PER_SEC)); } -void test_verify_speed(void) { +void test_verify_speed(void) +{ prepare_msg(); bench_secp256k1(); bench_nist256p1(); bench_ed25519(); } +void bench_curve25519(void) +{ + uint8_t result[32]; + uint8_t secret[32]; + uint8_t basepoint[32]; + + memcpy(secret, "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", 32); + memcpy(basepoint, "\x96\x47\xda\xbe\x1e\xea\xaf\x25\x47\x1e\x68\x0b\x4d\x7c\x6f\xd1\x14\x38\x76\xbb\x77\x59\xd8\x3d\x0f\xf7\xa2\x49\x08\xfd\xda\xbc", 32); + + clock_t t = clock(); + for (int i = 0 ; i < 500; i++) { + curve25519_scalarmult(result, secret, basepoint); + } + printf("Curve25519 multiplying speed: %0.2f mul/s\n", 500.0f / ((float)(clock() - t) / CLOCKS_PER_SEC)); +} + +void test_multiply_speed(void) +{ + bench_curve25519(); +} + static HDNode root; void prepare_node(void) @@ -84,7 +110,8 @@ void prepare_node(void) hdnode_fill_public_key(&root); } -void bench_ckd_normal(int iterations) { +void bench_ckd_normal(int iterations) +{ char addr[MAX_ADDR_SIZE]; HDNode node; clock_t t = clock(); @@ -100,7 +127,8 @@ void bench_ckd_normal(int iterations) { printf("CKD normal speed: %0.2f iter/s\n", iterations / ((float)(clock() - t) / CLOCKS_PER_SEC)); } -void bench_ckd_optimized(int iterations) { +void bench_ckd_optimized(int iterations) +{ char addr[MAX_ADDR_SIZE]; curve_point pub; ecdsa_read_pubkey(&secp256k1, root.public_key, &pub); @@ -114,7 +142,8 @@ void bench_ckd_optimized(int iterations) { printf("CKD optim speed: %0.2f iter/s\n", iterations / ((float)(clock() - t) / CLOCKS_PER_SEC)); } -void test_ckd_speed(int iterations) { +void test_ckd_speed(int iterations) +{ prepare_node(); bench_ckd_normal(iterations); bench_ckd_optimized(iterations); @@ -122,6 +151,7 @@ void test_ckd_speed(int iterations) { int main(void) { test_verify_speed(); + test_multiply_speed(); test_ckd_speed(1000); return 0; } From bede439a623aadca83ecead86c35d12805dc1d02 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 24 Oct 2016 20:39:55 +0200 Subject: [PATCH 344/627] remove unused macros in test-openssl.c --- test-openssl.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/test-openssl.c b/test-openssl.c index 2af6286b7..9f3c2d2a5 100644 --- a/test-openssl.c +++ b/test-openssl.c @@ -31,12 +31,6 @@ #include "rand.h" #include "secp256k1.h" -#define CURVE (&secp256k1) -#define prime256k1 (secp256k1.prime) -#define G256k1 (secp256k1.G) -#define order256k1 (secp256k1.order) -#define secp256k1_cp (secp256k1.cp) - int main(int argc, char *argv[]) { uint8_t sig[64], pub_key33[33], pub_key65[65], priv_key[32], msg[256], buffer[1000], hash[32], *p; @@ -88,7 +82,7 @@ int main(int argc, char *argv[]) } // use our ECDSA signer to sign the message with the key - if (ecdsa_sign(CURVE, priv_key, msg, msg_len, sig, NULL, NULL) != 0) { + if (ecdsa_sign(&secp256k1, priv_key, msg, msg_len, sig, NULL, NULL) != 0) { printf("trezor-crypto signing failed\n"); break; } @@ -98,11 +92,11 @@ int main(int argc, char *argv[]) ecdsa_get_public_key65(&secp256k1, priv_key, pub_key65); // use our ECDSA verifier to verify the message signature - if (ecdsa_verify(CURVE, pub_key65, sig, msg, msg_len) != 0) { + if (ecdsa_verify(&secp256k1, pub_key65, sig, msg, msg_len) != 0) { printf("trezor-crypto verification failed (pub_key_len = 65)\n"); break; } - if (ecdsa_verify(CURVE, pub_key33, sig, msg, msg_len) != 0) { + if (ecdsa_verify(&secp256k1, pub_key33, sig, msg, msg_len) != 0) { printf("trezor-crypto verification failed (pub_key_len = 33)\n"); break; } From 0abc61f6722580ee779614ef5b31d17a29e4d841 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 24 Oct 2016 20:51:57 +0200 Subject: [PATCH 345/627] use curve25519-donna from floodyberry --- Makefile | 4 +- bip32.c | 6 +- curve25519-donna/README.md | 107 ++ curve25519-donna/curve25519-donna-32bit.h | 466 ++++++++ curve25519-donna/curve25519-donna-64bit.h | 345 ++++++ curve25519-donna/curve25519-donna-common.h | 43 + .../curve25519-donna-portable-identify.h | 103 ++ curve25519-donna/curve25519-donna-portable.h | 92 ++ .../curve25519-donna-scalarmult-base.h | 66 ++ .../curve25519-donna-scalarmult-sse2.h | 65 ++ curve25519-donna/curve25519-donna-sse2.h | 1009 +++++++++++++++++ curve25519-donna/curve25519-donna.c | 863 -------------- curve25519-donna/curve25519-donna.h | 35 +- curve25519-donna/curve25519.c | 27 + curve25519-donna/curve25519.h | 10 + test_speed.c | 4 +- 16 files changed, 2368 insertions(+), 877 deletions(-) create mode 100644 curve25519-donna/README.md create mode 100644 curve25519-donna/curve25519-donna-32bit.h create mode 100644 curve25519-donna/curve25519-donna-64bit.h create mode 100644 curve25519-donna/curve25519-donna-common.h create mode 100644 curve25519-donna/curve25519-donna-portable-identify.h create mode 100644 curve25519-donna/curve25519-donna-portable.h create mode 100644 curve25519-donna/curve25519-donna-scalarmult-base.h create mode 100644 curve25519-donna/curve25519-donna-scalarmult-sse2.h create mode 100644 curve25519-donna/curve25519-donna-sse2.h delete mode 100644 curve25519-donna/curve25519-donna.c create mode 100644 curve25519-donna/curve25519.c create mode 100644 curve25519-donna/curve25519.h diff --git a/Makefile b/Makefile index c62447b17..252a06f22 100644 --- a/Makefile +++ b/Makefile @@ -46,7 +46,7 @@ SRCS += sha2.c SRCS += sha3.c SRCS += aescrypt.c aeskey.c aestab.c aes_modes.c SRCS += ed25519-donna/ed25519.c -SRCS += curve25519-donna/curve25519-donna.c +SRCS += curve25519-donna/curve25519.c OBJS = $(SRCS:.c=.o) @@ -62,7 +62,7 @@ tests: tests.o $(OBJS) $(CC) tests.o $(OBJS) $(TESTLIBS) -o tests test_speed: test_speed.o $(OBJS) - $(CC) test_speed.o $(OBJS) $(TESTLIBS) -o test_speed + $(CC) test_speed.o $(OBJS) -o test_speed test-openssl: test-openssl.o $(OBJS) $(CC) test-openssl.o $(OBJS) $(TESTSSLLIBS) -o test-openssl diff --git a/bip32.c b/bip32.c index a4d22e72b..19d45402d 100644 --- a/bip32.c +++ b/bip32.c @@ -37,7 +37,7 @@ #include "secp256k1.h" #include "nist256p1.h" #include "ed25519.h" -#include "curve25519-donna.h" +#include "curve25519.h" #if USE_ETHEREUM #include "sha3.h" #endif @@ -400,7 +400,7 @@ void hdnode_fill_public_key(HDNode *node) ed25519_publickey(node->private_key, node->public_key + 1); } else if (node->curve == &curve25519_info) { node->public_key[0] = 1; - curve25519_publickey(node->public_key + 1, node->private_key); + curve25519_donna_basepoint(node->public_key + 1, node->private_key); } else { ecdsa_get_public_key33(node->curve->params, node->private_key, node->public_key); } @@ -466,7 +466,7 @@ int hdnode_get_shared_key(const HDNode *node, const uint8_t *peer_public_key, ui if (peer_public_key[0] != 0x40) { return 1; // Curve25519 public key should start with 0x40 byte. } - curve25519_scalarmult(session_key + 1, node->private_key, peer_public_key + 1); + curve25519_donna(session_key + 1, node->private_key, peer_public_key + 1); *result_size = 33; return 0; } else { diff --git a/curve25519-donna/README.md b/curve25519-donna/README.md new file mode 100644 index 000000000..4d7dfb7af --- /dev/null +++ b/curve25519-donna/README.md @@ -0,0 +1,107 @@ +[curve25519](http://cr.yp.to/ecdh.html) is an elliptic curve, developed by +[Dan Bernstein](http://cr.yp.to/djb.html), for fast +[Diffie-Hellman](http://en.wikipedia.org/wiki/Diffie-Hellman) key agreement. +DJB's [original implementation](http://cr.yp.to/ecdh.html) was written in a +language of his own devising called [qhasm](http://cr.yp.to/qhasm.html). +The original qhasm source isn't available, only the x86 32-bit assembly output. + +This project provides performant, portable 32-bit & 64-bit implementations. +All implementations are of course constant time in regard to secret data. + +#### Performance + +Compilers versions are gcc 4.6.3, icc 13.1.1, clang 3.4-1~exp1. + +Counts are in thousands of cycles. + +Note that SSE2 performance may be less impressive on AMD & older CPUs with slower SSE ops! + +##### E5200 @ 2.5ghz, march=core2 + + + + + + + + + +
Versiongcciccclang
64-bit SSE2 278k 265k 302k
64-bit 273k 271k 377k
32-bit SSE2 304k 289k 317k
32-bit 1417k 845k 981k
+ +##### E3-1270 @ 3.4ghz, march=corei7-avx + + + + + + + + + +
Versiongcciccclang
64-bit 201k 192k 233k
64-bit SSE2 201k 201k 261k
32-bit SSE2 238k 225k 250k
32-bit 1293k 822k 848k
+ +#### Compilation + +No configuration is needed. + +##### 32-bit + + gcc curve25519.c -m32 -O3 -c + +##### 64-bit + + gcc curve25519.c -m64 -O3 -c + +##### SSE2 + + gcc curve25519.c -m32 -O3 -c -DCURVE25519_SSE2 -msse2 + gcc curve25519.c -m64 -O3 -c -DCURVE25519_SSE2 + +clang, icc, and msvc are also supported + +##### Named Versions + +Define CURVE25519_SUFFIX to append a suffix to public functions, e.g. +`-DCURVE25519_SUFFIX=_sse2` to create curve25519_donna_sse2 and +curve25519_donna_basepoint_sse2. + +#### Usage + +To use the code, link against `curve25519.o` and: + + #include "curve25519.h" + +To generate a private/secret key, generate 32 cryptographically random bytes: + + curve25519_key sk; + randombytes(sk, sizeof(curve25519_key)); + +Manual clamping is not needed, and it is actually not possible to use unclamped +keys due to the code taking advantage of the clamped bits internally. + +To generate the public key from the private/secret key: + + curve25519_key pk; + curve25519_donna_basepoint(pk, sk); + +To generate a shared key with your private/secret key and someone elses public key: + + curve25519_key shared; + curve25519_donna(shared, mysk, yourpk); + +And hash `shared` with a cryptographic hash before using, or e.g. pass `shared` through +HSalsa20/HChacha as NaCl does. + +#### Testing + +Fuzzing against a reference implemenation is now available. See [fuzz/README](fuzz/README.md). + +Building `curve25519.c` and linking with `test.c` will run basic sanity tests and benchmark curve25519_donna. + +#### Papers + +[djb's curve25519 paper](http://cr.yp.to/ecdh/curve25519-20060209.pdf) + +#### License + +Public Domain, or MIT \ No newline at end of file diff --git a/curve25519-donna/curve25519-donna-32bit.h b/curve25519-donna/curve25519-donna-32bit.h new file mode 100644 index 000000000..5ef91a202 --- /dev/null +++ b/curve25519-donna/curve25519-donna-32bit.h @@ -0,0 +1,466 @@ +typedef uint32_t bignum25519[10]; + +static const uint32_t reduce_mask_26 = (1 << 26) - 1; +static const uint32_t reduce_mask_25 = (1 << 25) - 1; + +/* out = in */ +DONNA_INLINE static void +curve25519_copy(bignum25519 out, const bignum25519 in) { + out[0] = in[0]; + out[1] = in[1]; + out[2] = in[2]; + out[3] = in[3]; + out[4] = in[4]; + out[5] = in[5]; + out[6] = in[6]; + out[7] = in[7]; + out[8] = in[8]; + out[9] = in[9]; +} + +/* out = a + b */ +DONNA_INLINE static void +curve25519_add(bignum25519 out, const bignum25519 a, const bignum25519 b) { + out[0] = a[0] + b[0]; + out[1] = a[1] + b[1]; + out[2] = a[2] + b[2]; + out[3] = a[3] + b[3]; + out[4] = a[4] + b[4]; + out[5] = a[5] + b[5]; + out[6] = a[6] + b[6]; + out[7] = a[7] + b[7]; + out[8] = a[8] + b[8]; + out[9] = a[9] + b[9]; +} + +/* out = a - b */ +DONNA_INLINE static void +curve25519_sub(bignum25519 out, const bignum25519 a, const bignum25519 b) { + uint32_t c; + out[0] = 0x7ffffda + a[0] - b[0] ; c = (out[0] >> 26); out[0] &= reduce_mask_26; + out[1] = 0x3fffffe + a[1] - b[1] + c; c = (out[1] >> 25); out[1] &= reduce_mask_25; + out[2] = 0x7fffffe + a[2] - b[2] + c; c = (out[2] >> 26); out[2] &= reduce_mask_26; + out[3] = 0x3fffffe + a[3] - b[3] + c; c = (out[3] >> 25); out[3] &= reduce_mask_25; + out[4] = 0x7fffffe + a[4] - b[4] + c; c = (out[4] >> 26); out[4] &= reduce_mask_26; + out[5] = 0x3fffffe + a[5] - b[5] + c; c = (out[5] >> 25); out[5] &= reduce_mask_25; + out[6] = 0x7fffffe + a[6] - b[6] + c; c = (out[6] >> 26); out[6] &= reduce_mask_26; + out[7] = 0x3fffffe + a[7] - b[7] + c; c = (out[7] >> 25); out[7] &= reduce_mask_25; + out[8] = 0x7fffffe + a[8] - b[8] + c; c = (out[8] >> 26); out[8] &= reduce_mask_26; + out[9] = 0x3fffffe + a[9] - b[9] + c; c = (out[9] >> 25); out[9] &= reduce_mask_25; + out[0] += 19 * c; +} + +/* out = in * scalar */ +DONNA_INLINE static void +curve25519_scalar_product(bignum25519 out, const bignum25519 in, const uint32_t scalar) { + uint64_t a; + uint32_t c; + a = mul32x32_64(in[0], scalar); out[0] = (uint32_t)a & reduce_mask_26; c = (uint32_t)(a >> 26); + a = mul32x32_64(in[1], scalar) + c; out[1] = (uint32_t)a & reduce_mask_25; c = (uint32_t)(a >> 25); + a = mul32x32_64(in[2], scalar) + c; out[2] = (uint32_t)a & reduce_mask_26; c = (uint32_t)(a >> 26); + a = mul32x32_64(in[3], scalar) + c; out[3] = (uint32_t)a & reduce_mask_25; c = (uint32_t)(a >> 25); + a = mul32x32_64(in[4], scalar) + c; out[4] = (uint32_t)a & reduce_mask_26; c = (uint32_t)(a >> 26); + a = mul32x32_64(in[5], scalar) + c; out[5] = (uint32_t)a & reduce_mask_25; c = (uint32_t)(a >> 25); + a = mul32x32_64(in[6], scalar) + c; out[6] = (uint32_t)a & reduce_mask_26; c = (uint32_t)(a >> 26); + a = mul32x32_64(in[7], scalar) + c; out[7] = (uint32_t)a & reduce_mask_25; c = (uint32_t)(a >> 25); + a = mul32x32_64(in[8], scalar) + c; out[8] = (uint32_t)a & reduce_mask_26; c = (uint32_t)(a >> 26); + a = mul32x32_64(in[9], scalar) + c; out[9] = (uint32_t)a & reduce_mask_25; c = (uint32_t)(a >> 25); + out[0] += c * 19; +} + +/* out = a * b */ +DONNA_INLINE static void +curve25519_mul(bignum25519 out, const bignum25519 a, const bignum25519 b) { + uint32_t r0,r1,r2,r3,r4,r5,r6,r7,r8,r9; + uint32_t s0,s1,s2,s3,s4,s5,s6,s7,s8,s9; + uint64_t m0,m1,m2,m3,m4,m5,m6,m7,m8,m9,c; + uint32_t p; + + r0 = b[0]; + r1 = b[1]; + r2 = b[2]; + r3 = b[3]; + r4 = b[4]; + r5 = b[5]; + r6 = b[6]; + r7 = b[7]; + r8 = b[8]; + r9 = b[9]; + + s0 = a[0]; + s1 = a[1]; + s2 = a[2]; + s3 = a[3]; + s4 = a[4]; + s5 = a[5]; + s6 = a[6]; + s7 = a[7]; + s8 = a[8]; + s9 = a[9]; + + m1 = mul32x32_64(r0, s1) + mul32x32_64(r1, s0); + m3 = mul32x32_64(r0, s3) + mul32x32_64(r1, s2) + mul32x32_64(r2, s1) + mul32x32_64(r3, s0); + m5 = mul32x32_64(r0, s5) + mul32x32_64(r1, s4) + mul32x32_64(r2, s3) + mul32x32_64(r3, s2) + mul32x32_64(r4, s1) + mul32x32_64(r5, s0); + m7 = mul32x32_64(r0, s7) + mul32x32_64(r1, s6) + mul32x32_64(r2, s5) + mul32x32_64(r3, s4) + mul32x32_64(r4, s3) + mul32x32_64(r5, s2) + mul32x32_64(r6, s1) + mul32x32_64(r7, s0); + m9 = mul32x32_64(r0, s9) + mul32x32_64(r1, s8) + mul32x32_64(r2, s7) + mul32x32_64(r3, s6) + mul32x32_64(r4, s5) + mul32x32_64(r5, s4) + mul32x32_64(r6, s3) + mul32x32_64(r7, s2) + mul32x32_64(r8, s1) + mul32x32_64(r9, s0); + + r1 *= 2; + r3 *= 2; + r5 *= 2; + r7 *= 2; + + m0 = mul32x32_64(r0, s0); + m2 = mul32x32_64(r0, s2) + mul32x32_64(r1, s1) + mul32x32_64(r2, s0); + m4 = mul32x32_64(r0, s4) + mul32x32_64(r1, s3) + mul32x32_64(r2, s2) + mul32x32_64(r3, s1) + mul32x32_64(r4, s0); + m6 = mul32x32_64(r0, s6) + mul32x32_64(r1, s5) + mul32x32_64(r2, s4) + mul32x32_64(r3, s3) + mul32x32_64(r4, s2) + mul32x32_64(r5, s1) + mul32x32_64(r6, s0); + m8 = mul32x32_64(r0, s8) + mul32x32_64(r1, s7) + mul32x32_64(r2, s6) + mul32x32_64(r3, s5) + mul32x32_64(r4, s4) + mul32x32_64(r5, s3) + mul32x32_64(r6, s2) + mul32x32_64(r7, s1) + mul32x32_64(r8, s0); + + r1 *= 19; + r2 *= 19; + r3 = (r3 / 2) * 19; + r4 *= 19; + r5 = (r5 / 2) * 19; + r6 *= 19; + r7 = (r7 / 2) * 19; + r8 *= 19; + r9 *= 19; + + m1 += (mul32x32_64(r9, s2) + mul32x32_64(r8, s3) + mul32x32_64(r7, s4) + mul32x32_64(r6, s5) + mul32x32_64(r5, s6) + mul32x32_64(r4, s7) + mul32x32_64(r3, s8) + mul32x32_64(r2, s9)); + m3 += (mul32x32_64(r9, s4) + mul32x32_64(r8, s5) + mul32x32_64(r7, s6) + mul32x32_64(r6, s7) + mul32x32_64(r5, s8) + mul32x32_64(r4, s9)); + m5 += (mul32x32_64(r9, s6) + mul32x32_64(r8, s7) + mul32x32_64(r7, s8) + mul32x32_64(r6, s9)); + m7 += (mul32x32_64(r9, s8) + mul32x32_64(r8, s9)); + + r3 *= 2; + r5 *= 2; + r7 *= 2; + r9 *= 2; + + m0 += (mul32x32_64(r9, s1) + mul32x32_64(r8, s2) + mul32x32_64(r7, s3) + mul32x32_64(r6, s4) + mul32x32_64(r5, s5) + mul32x32_64(r4, s6) + mul32x32_64(r3, s7) + mul32x32_64(r2, s8) + mul32x32_64(r1, s9)); + m2 += (mul32x32_64(r9, s3) + mul32x32_64(r8, s4) + mul32x32_64(r7, s5) + mul32x32_64(r6, s6) + mul32x32_64(r5, s7) + mul32x32_64(r4, s8) + mul32x32_64(r3, s9)); + m4 += (mul32x32_64(r9, s5) + mul32x32_64(r8, s6) + mul32x32_64(r7, s7) + mul32x32_64(r6, s8) + mul32x32_64(r5, s9)); + m6 += (mul32x32_64(r9, s7) + mul32x32_64(r8, s8) + mul32x32_64(r7, s9)); + m8 += (mul32x32_64(r9, s9)); + + r0 = (uint32_t)m0 & reduce_mask_26; c = (m0 >> 26); + m1 += c; r1 = (uint32_t)m1 & reduce_mask_25; c = (m1 >> 25); + m2 += c; r2 = (uint32_t)m2 & reduce_mask_26; c = (m2 >> 26); + m3 += c; r3 = (uint32_t)m3 & reduce_mask_25; c = (m3 >> 25); + m4 += c; r4 = (uint32_t)m4 & reduce_mask_26; c = (m4 >> 26); + m5 += c; r5 = (uint32_t)m5 & reduce_mask_25; c = (m5 >> 25); + m6 += c; r6 = (uint32_t)m6 & reduce_mask_26; c = (m6 >> 26); + m7 += c; r7 = (uint32_t)m7 & reduce_mask_25; c = (m7 >> 25); + m8 += c; r8 = (uint32_t)m8 & reduce_mask_26; c = (m8 >> 26); + m9 += c; r9 = (uint32_t)m9 & reduce_mask_25; p = (uint32_t)(m9 >> 25); + m0 = r0 + mul32x32_64(p,19); r0 = (uint32_t)m0 & reduce_mask_26; p = (uint32_t)(m0 >> 26); + r1 += p; + + out[0] = r0; + out[1] = r1; + out[2] = r2; + out[3] = r3; + out[4] = r4; + out[5] = r5; + out[6] = r6; + out[7] = r7; + out[8] = r8; + out[9] = r9; +} + +/* out = in * in */ +DONNA_INLINE static void +curve25519_square(bignum25519 out, const bignum25519 in) { + uint32_t r0,r1,r2,r3,r4,r5,r6,r7,r8,r9; + uint32_t d6,d7,d8,d9; + uint64_t m0,m1,m2,m3,m4,m5,m6,m7,m8,m9,c; + uint32_t p; + + r0 = in[0]; + r1 = in[1]; + r2 = in[2]; + r3 = in[3]; + r4 = in[4]; + r5 = in[5]; + r6 = in[6]; + r7 = in[7]; + r8 = in[8]; + r9 = in[9]; + + + m0 = mul32x32_64(r0, r0); + r0 *= 2; + m1 = mul32x32_64(r0, r1); + m2 = mul32x32_64(r0, r2) + mul32x32_64(r1, r1 * 2); + r1 *= 2; + m3 = mul32x32_64(r0, r3) + mul32x32_64(r1, r2 ); + m4 = mul32x32_64(r0, r4) + mul32x32_64(r1, r3 * 2) + mul32x32_64(r2, r2); + r2 *= 2; + m5 = mul32x32_64(r0, r5) + mul32x32_64(r1, r4 ) + mul32x32_64(r2, r3); + m6 = mul32x32_64(r0, r6) + mul32x32_64(r1, r5 * 2) + mul32x32_64(r2, r4) + mul32x32_64(r3, r3 * 2); + r3 *= 2; + m7 = mul32x32_64(r0, r7) + mul32x32_64(r1, r6 ) + mul32x32_64(r2, r5) + mul32x32_64(r3, r4 ); + m8 = mul32x32_64(r0, r8) + mul32x32_64(r1, r7 * 2) + mul32x32_64(r2, r6) + mul32x32_64(r3, r5 * 2) + mul32x32_64(r4, r4 ); + m9 = mul32x32_64(r0, r9) + mul32x32_64(r1, r8 ) + mul32x32_64(r2, r7) + mul32x32_64(r3, r6 ) + mul32x32_64(r4, r5 * 2); + + d6 = r6 * 19; + d7 = r7 * 2 * 19; + d8 = r8 * 19; + d9 = r9 * 2 * 19; + + m0 += (mul32x32_64(d9, r1 ) + mul32x32_64(d8, r2 ) + mul32x32_64(d7, r3 ) + mul32x32_64(d6, r4 * 2) + mul32x32_64(r5, r5 * 2 * 19)); + m1 += (mul32x32_64(d9, r2 / 2) + mul32x32_64(d8, r3 ) + mul32x32_64(d7, r4 ) + mul32x32_64(d6, r5 * 2)); + m2 += (mul32x32_64(d9, r3 ) + mul32x32_64(d8, r4 * 2) + mul32x32_64(d7, r5 * 2) + mul32x32_64(d6, r6 )); + m3 += (mul32x32_64(d9, r4 ) + mul32x32_64(d8, r5 * 2) + mul32x32_64(d7, r6 )); + m4 += (mul32x32_64(d9, r5 * 2) + mul32x32_64(d8, r6 * 2) + mul32x32_64(d7, r7 )); + m5 += (mul32x32_64(d9, r6 ) + mul32x32_64(d8, r7 * 2)); + m6 += (mul32x32_64(d9, r7 * 2) + mul32x32_64(d8, r8 )); + m7 += (mul32x32_64(d9, r8 )); + m8 += (mul32x32_64(d9, r9 )); + + r0 = (uint32_t)m0 & reduce_mask_26; c = (m0 >> 26); + m1 += c; r1 = (uint32_t)m1 & reduce_mask_25; c = (m1 >> 25); + m2 += c; r2 = (uint32_t)m2 & reduce_mask_26; c = (m2 >> 26); + m3 += c; r3 = (uint32_t)m3 & reduce_mask_25; c = (m3 >> 25); + m4 += c; r4 = (uint32_t)m4 & reduce_mask_26; c = (m4 >> 26); + m5 += c; r5 = (uint32_t)m5 & reduce_mask_25; c = (m5 >> 25); + m6 += c; r6 = (uint32_t)m6 & reduce_mask_26; c = (m6 >> 26); + m7 += c; r7 = (uint32_t)m7 & reduce_mask_25; c = (m7 >> 25); + m8 += c; r8 = (uint32_t)m8 & reduce_mask_26; c = (m8 >> 26); + m9 += c; r9 = (uint32_t)m9 & reduce_mask_25; p = (uint32_t)(m9 >> 25); + m0 = r0 + mul32x32_64(p,19); r0 = (uint32_t)m0 & reduce_mask_26; p = (uint32_t)(m0 >> 26); + r1 += p; + + out[0] = r0; + out[1] = r1; + out[2] = r2; + out[3] = r3; + out[4] = r4; + out[5] = r5; + out[6] = r6; + out[7] = r7; + out[8] = r8; + out[9] = r9; +} + +/* out = in^(2 * count) */ +static void +curve25519_square_times(bignum25519 out, const bignum25519 in, int count) { + uint32_t r0,r1,r2,r3,r4,r5,r6,r7,r8,r9; + uint32_t d6,d7,d8,d9; + uint64_t m0,m1,m2,m3,m4,m5,m6,m7,m8,m9,c; + uint32_t p; + + r0 = in[0]; + r1 = in[1]; + r2 = in[2]; + r3 = in[3]; + r4 = in[4]; + r5 = in[5]; + r6 = in[6]; + r7 = in[7]; + r8 = in[8]; + r9 = in[9]; + + do { + m0 = mul32x32_64(r0, r0); + r0 *= 2; + m1 = mul32x32_64(r0, r1); + m2 = mul32x32_64(r0, r2) + mul32x32_64(r1, r1 * 2); + r1 *= 2; + m3 = mul32x32_64(r0, r3) + mul32x32_64(r1, r2 ); + m4 = mul32x32_64(r0, r4) + mul32x32_64(r1, r3 * 2) + mul32x32_64(r2, r2); + r2 *= 2; + m5 = mul32x32_64(r0, r5) + mul32x32_64(r1, r4 ) + mul32x32_64(r2, r3); + m6 = mul32x32_64(r0, r6) + mul32x32_64(r1, r5 * 2) + mul32x32_64(r2, r4) + mul32x32_64(r3, r3 * 2); + r3 *= 2; + m7 = mul32x32_64(r0, r7) + mul32x32_64(r1, r6 ) + mul32x32_64(r2, r5) + mul32x32_64(r3, r4 ); + m8 = mul32x32_64(r0, r8) + mul32x32_64(r1, r7 * 2) + mul32x32_64(r2, r6) + mul32x32_64(r3, r5 * 2) + mul32x32_64(r4, r4 ); + m9 = mul32x32_64(r0, r9) + mul32x32_64(r1, r8 ) + mul32x32_64(r2, r7) + mul32x32_64(r3, r6 ) + mul32x32_64(r4, r5 * 2); + + d6 = r6 * 19; + d7 = r7 * 2 * 19; + d8 = r8 * 19; + d9 = r9 * 2 * 19; + + m0 += (mul32x32_64(d9, r1 ) + mul32x32_64(d8, r2 ) + mul32x32_64(d7, r3 ) + mul32x32_64(d6, r4 * 2) + mul32x32_64(r5, r5 * 2 * 19)); + m1 += (mul32x32_64(d9, r2 / 2) + mul32x32_64(d8, r3 ) + mul32x32_64(d7, r4 ) + mul32x32_64(d6, r5 * 2)); + m2 += (mul32x32_64(d9, r3 ) + mul32x32_64(d8, r4 * 2) + mul32x32_64(d7, r5 * 2) + mul32x32_64(d6, r6 )); + m3 += (mul32x32_64(d9, r4 ) + mul32x32_64(d8, r5 * 2) + mul32x32_64(d7, r6 )); + m4 += (mul32x32_64(d9, r5 * 2) + mul32x32_64(d8, r6 * 2) + mul32x32_64(d7, r7 )); + m5 += (mul32x32_64(d9, r6 ) + mul32x32_64(d8, r7 * 2)); + m6 += (mul32x32_64(d9, r7 * 2) + mul32x32_64(d8, r8 )); + m7 += (mul32x32_64(d9, r8 )); + m8 += (mul32x32_64(d9, r9 )); + + r0 = (uint32_t)m0 & reduce_mask_26; c = (m0 >> 26); + m1 += c; r1 = (uint32_t)m1 & reduce_mask_25; c = (m1 >> 25); + m2 += c; r2 = (uint32_t)m2 & reduce_mask_26; c = (m2 >> 26); + m3 += c; r3 = (uint32_t)m3 & reduce_mask_25; c = (m3 >> 25); + m4 += c; r4 = (uint32_t)m4 & reduce_mask_26; c = (m4 >> 26); + m5 += c; r5 = (uint32_t)m5 & reduce_mask_25; c = (m5 >> 25); + m6 += c; r6 = (uint32_t)m6 & reduce_mask_26; c = (m6 >> 26); + m7 += c; r7 = (uint32_t)m7 & reduce_mask_25; c = (m7 >> 25); + m8 += c; r8 = (uint32_t)m8 & reduce_mask_26; c = (m8 >> 26); + m9 += c; r9 = (uint32_t)m9 & reduce_mask_25; p = (uint32_t)(m9 >> 25); + m0 = r0 + mul32x32_64(p,19); r0 = (uint32_t)m0 & reduce_mask_26; p = (uint32_t)(m0 >> 26); + r1 += p; + } while (--count); + + out[0] = r0; + out[1] = r1; + out[2] = r2; + out[3] = r3; + out[4] = r4; + out[5] = r5; + out[6] = r6; + out[7] = r7; + out[8] = r8; + out[9] = r9; +} + + +/* Take a little-endian, 32-byte number and expand it into polynomial form */ +static void +curve25519_expand(bignum25519 out, const unsigned char in[32]) { + static const union { uint8_t b[2]; uint16_t s; } endian_check = {{1,0}}; + uint32_t x0,x1,x2,x3,x4,x5,x6,x7; + + if (endian_check.s == 1) { + x0 = *(uint32_t *)(in + 0); + x1 = *(uint32_t *)(in + 4); + x2 = *(uint32_t *)(in + 8); + x3 = *(uint32_t *)(in + 12); + x4 = *(uint32_t *)(in + 16); + x5 = *(uint32_t *)(in + 20); + x6 = *(uint32_t *)(in + 24); + x7 = *(uint32_t *)(in + 28); + } else { + #define F(s) \ + ((((uint32_t)in[s + 0]) ) | \ + (((uint32_t)in[s + 1]) << 8) | \ + (((uint32_t)in[s + 2]) << 16) | \ + (((uint32_t)in[s + 3]) << 24)) + x0 = F(0); + x1 = F(4); + x2 = F(8); + x3 = F(12); + x4 = F(16); + x5 = F(20); + x6 = F(24); + x7 = F(28); + #undef F + } + + out[0] = ( x0 ) & reduce_mask_26; + out[1] = ((((uint64_t)x1 << 32) | x0) >> 26) & reduce_mask_25; + out[2] = ((((uint64_t)x2 << 32) | x1) >> 19) & reduce_mask_26; + out[3] = ((((uint64_t)x3 << 32) | x2) >> 13) & reduce_mask_25; + out[4] = (( x3) >> 6) & reduce_mask_26; + out[5] = ( x4 ) & reduce_mask_25; + out[6] = ((((uint64_t)x5 << 32) | x4) >> 25) & reduce_mask_26; + out[7] = ((((uint64_t)x6 << 32) | x5) >> 19) & reduce_mask_25; + out[8] = ((((uint64_t)x7 << 32) | x6) >> 12) & reduce_mask_26; + out[9] = (( x7) >> 6) & reduce_mask_25; /* ignore the top bit */ +} + +/* Take a fully reduced polynomial form number and contract it into a little-endian, 32-byte array */ +static void +curve25519_contract(unsigned char out[32], const bignum25519 in) { + bignum25519 f; + curve25519_copy(f, in); + + #define carry_pass() \ + f[1] += f[0] >> 26; f[0] &= reduce_mask_26; \ + f[2] += f[1] >> 25; f[1] &= reduce_mask_25; \ + f[3] += f[2] >> 26; f[2] &= reduce_mask_26; \ + f[4] += f[3] >> 25; f[3] &= reduce_mask_25; \ + f[5] += f[4] >> 26; f[4] &= reduce_mask_26; \ + f[6] += f[5] >> 25; f[5] &= reduce_mask_25; \ + f[7] += f[6] >> 26; f[6] &= reduce_mask_26; \ + f[8] += f[7] >> 25; f[7] &= reduce_mask_25; \ + f[9] += f[8] >> 26; f[8] &= reduce_mask_26; + + #define carry_pass_full() \ + carry_pass() \ + f[0] += 19 * (f[9] >> 25); f[9] &= reduce_mask_25; + + #define carry_pass_final() \ + carry_pass() \ + f[9] &= reduce_mask_25; + + carry_pass_full() + carry_pass_full() + + /* now t is between 0 and 2^255-1, properly carried. */ + /* case 1: between 0 and 2^255-20. case 2: between 2^255-19 and 2^255-1. */ + f[0] += 19; + carry_pass_full() + + /* now between 19 and 2^255-1 in both cases, and offset by 19. */ + f[0] += (1 << 26) - 19; + f[1] += (1 << 25) - 1; + f[2] += (1 << 26) - 1; + f[3] += (1 << 25) - 1; + f[4] += (1 << 26) - 1; + f[5] += (1 << 25) - 1; + f[6] += (1 << 26) - 1; + f[7] += (1 << 25) - 1; + f[8] += (1 << 26) - 1; + f[9] += (1 << 25) - 1; + + /* now between 2^255 and 2^256-20, and offset by 2^255. */ + carry_pass_final() + + #undef carry_pass + #undef carry_full + #undef carry_final + + f[1] <<= 2; + f[2] <<= 3; + f[3] <<= 5; + f[4] <<= 6; + f[6] <<= 1; + f[7] <<= 3; + f[8] <<= 4; + f[9] <<= 6; + + #define F(i, s) \ + out[s+0] |= (unsigned char )(f[i] & 0xff); \ + out[s+1] = (unsigned char )((f[i] >> 8) & 0xff); \ + out[s+2] = (unsigned char )((f[i] >> 16) & 0xff); \ + out[s+3] = (unsigned char )((f[i] >> 24) & 0xff); + + out[0] = 0; + out[16] = 0; + F(0,0); + F(1,3); + F(2,6); + F(3,9); + F(4,12); + F(5,16); + F(6,19); + F(7,22); + F(8,25); + F(9,28); + #undef F +} + +/* + * Swap the contents of [qx] and [qpx] iff @swap is non-zero + */ +DONNA_INLINE static void +curve25519_swap_conditional(bignum25519 x, bignum25519 qpx, uint32_t iswap) { + const uint32_t swap = (uint32_t)(-(int32_t)iswap); + uint32_t x0,x1,x2,x3,x4,x5,x6,x7,x8,x9; + + x0 = swap & (x[0] ^ qpx[0]); x[0] ^= x0; qpx[0] ^= x0; + x1 = swap & (x[1] ^ qpx[1]); x[1] ^= x1; qpx[1] ^= x1; + x2 = swap & (x[2] ^ qpx[2]); x[2] ^= x2; qpx[2] ^= x2; + x3 = swap & (x[3] ^ qpx[3]); x[3] ^= x3; qpx[3] ^= x3; + x4 = swap & (x[4] ^ qpx[4]); x[4] ^= x4; qpx[4] ^= x4; + x5 = swap & (x[5] ^ qpx[5]); x[5] ^= x5; qpx[5] ^= x5; + x6 = swap & (x[6] ^ qpx[6]); x[6] ^= x6; qpx[6] ^= x6; + x7 = swap & (x[7] ^ qpx[7]); x[7] ^= x7; qpx[7] ^= x7; + x8 = swap & (x[8] ^ qpx[8]); x[8] ^= x8; qpx[8] ^= x8; + x9 = swap & (x[9] ^ qpx[9]); x[9] ^= x9; qpx[9] ^= x9; +} + diff --git a/curve25519-donna/curve25519-donna-64bit.h b/curve25519-donna/curve25519-donna-64bit.h new file mode 100644 index 000000000..ec4df526b --- /dev/null +++ b/curve25519-donna/curve25519-donna-64bit.h @@ -0,0 +1,345 @@ +typedef uint64_t bignum25519[5]; + +static const uint64_t reduce_mask_51 = ((uint64_t)1 << 51) - 1; +static const uint64_t reduce_mask_52 = ((uint64_t)1 << 52) - 1; + +/* out = in */ +DONNA_INLINE static void +curve25519_copy(bignum25519 out, const bignum25519 in) { + out[0] = in[0]; + out[1] = in[1]; + out[2] = in[2]; + out[3] = in[3]; + out[4] = in[4]; +} + +/* out = a + b */ +DONNA_INLINE static void +curve25519_add(bignum25519 out, const bignum25519 a, const bignum25519 b) { + out[0] = a[0] + b[0]; + out[1] = a[1] + b[1]; + out[2] = a[2] + b[2]; + out[3] = a[3] + b[3]; + out[4] = a[4] + b[4]; +} + +static const uint64_t two54m152 = (((uint64_t)1) << 54) - 152; +static const uint64_t two54m8 = (((uint64_t)1) << 54) - 8; + +/* out = a - b */ +DONNA_INLINE static void +curve25519_sub(bignum25519 out, const bignum25519 a, const bignum25519 b) { + out[0] = a[0] + two54m152 - b[0]; + out[1] = a[1] + two54m8 - b[1]; + out[2] = a[2] + two54m8 - b[2]; + out[3] = a[3] + two54m8 - b[3]; + out[4] = a[4] + two54m8 - b[4]; +} + + +/* out = (in * scalar) */ +DONNA_INLINE static void +curve25519_scalar_product(bignum25519 out, const bignum25519 in, const uint64_t scalar) { + uint128_t a; + uint64_t c; + +#if defined(HAVE_NATIVE_UINT128) + a = ((uint128_t) in[0]) * scalar; out[0] = (uint64_t)a & reduce_mask_51; c = (uint64_t)(a >> 51); + a = ((uint128_t) in[1]) * scalar + c; out[1] = (uint64_t)a & reduce_mask_51; c = (uint64_t)(a >> 51); + a = ((uint128_t) in[2]) * scalar + c; out[2] = (uint64_t)a & reduce_mask_51; c = (uint64_t)(a >> 51); + a = ((uint128_t) in[3]) * scalar + c; out[3] = (uint64_t)a & reduce_mask_51; c = (uint64_t)(a >> 51); + a = ((uint128_t) in[4]) * scalar + c; out[4] = (uint64_t)a & reduce_mask_51; c = (uint64_t)(a >> 51); + out[0] += c * 19; +#else + mul64x64_128(a, in[0], scalar) out[0] = lo128(a) & reduce_mask_51; shr128(c, a, 51); + mul64x64_128(a, in[1], scalar) add128_64(a, c) out[1] = lo128(a) & reduce_mask_51; shr128(c, a, 51); + mul64x64_128(a, in[2], scalar) add128_64(a, c) out[2] = lo128(a) & reduce_mask_51; shr128(c, a, 51); + mul64x64_128(a, in[3], scalar) add128_64(a, c) out[3] = lo128(a) & reduce_mask_51; shr128(c, a, 51); + mul64x64_128(a, in[4], scalar) add128_64(a, c) out[4] = lo128(a) & reduce_mask_51; shr128(c, a, 51); + out[0] += c * 19; +#endif +} + +/* out = a * b */ +DONNA_INLINE static void +curve25519_mul(bignum25519 out, const bignum25519 a, const bignum25519 b) { +#if !defined(HAVE_NATIVE_UINT128) + uint128_t mul; +#endif + uint128_t t[5]; + uint64_t r0,r1,r2,r3,r4,s0,s1,s2,s3,s4,c; + + r0 = b[0]; + r1 = b[1]; + r2 = b[2]; + r3 = b[3]; + r4 = b[4]; + + s0 = a[0]; + s1 = a[1]; + s2 = a[2]; + s3 = a[3]; + s4 = a[4]; + +#if defined(HAVE_NATIVE_UINT128) + t[0] = ((uint128_t) r0) * s0; + t[1] = ((uint128_t) r0) * s1 + ((uint128_t) r1) * s0; + t[2] = ((uint128_t) r0) * s2 + ((uint128_t) r2) * s0 + ((uint128_t) r1) * s1; + t[3] = ((uint128_t) r0) * s3 + ((uint128_t) r3) * s0 + ((uint128_t) r1) * s2 + ((uint128_t) r2) * s1; + t[4] = ((uint128_t) r0) * s4 + ((uint128_t) r4) * s0 + ((uint128_t) r3) * s1 + ((uint128_t) r1) * s3 + ((uint128_t) r2) * s2; +#else + mul64x64_128(t[0], r0, s0) + mul64x64_128(t[1], r0, s1) mul64x64_128(mul, r1, s0) add128(t[1], mul) + mul64x64_128(t[2], r0, s2) mul64x64_128(mul, r2, s0) add128(t[2], mul) mul64x64_128(mul, r1, s1) add128(t[2], mul) + mul64x64_128(t[3], r0, s3) mul64x64_128(mul, r3, s0) add128(t[3], mul) mul64x64_128(mul, r1, s2) add128(t[3], mul) mul64x64_128(mul, r2, s1) add128(t[3], mul) + mul64x64_128(t[4], r0, s4) mul64x64_128(mul, r4, s0) add128(t[4], mul) mul64x64_128(mul, r3, s1) add128(t[4], mul) mul64x64_128(mul, r1, s3) add128(t[4], mul) mul64x64_128(mul, r2, s2) add128(t[4], mul) +#endif + + r1 *= 19; + r2 *= 19; + r3 *= 19; + r4 *= 19; + +#if defined(HAVE_NATIVE_UINT128) + t[0] += ((uint128_t) r4) * s1 + ((uint128_t) r1) * s4 + ((uint128_t) r2) * s3 + ((uint128_t) r3) * s2; + t[1] += ((uint128_t) r4) * s2 + ((uint128_t) r2) * s4 + ((uint128_t) r3) * s3; + t[2] += ((uint128_t) r4) * s3 + ((uint128_t) r3) * s4; + t[3] += ((uint128_t) r4) * s4; +#else + mul64x64_128(mul, r4, s1) add128(t[0], mul) mul64x64_128(mul, r1, s4) add128(t[0], mul) mul64x64_128(mul, r2, s3) add128(t[0], mul) mul64x64_128(mul, r3, s2) add128(t[0], mul) + mul64x64_128(mul, r4, s2) add128(t[1], mul) mul64x64_128(mul, r2, s4) add128(t[1], mul) mul64x64_128(mul, r3, s3) add128(t[1], mul) + mul64x64_128(mul, r4, s3) add128(t[2], mul) mul64x64_128(mul, r3, s4) add128(t[2], mul) + mul64x64_128(mul, r4, s4) add128(t[3], mul) +#endif + + r0 = lo128(t[0]) & reduce_mask_51; shr128(c, t[0], 51); + add128_64(t[1], c) r1 = lo128(t[1]) & reduce_mask_51; shr128(c, t[1], 51); + add128_64(t[2], c) r2 = lo128(t[2]) & reduce_mask_51; shr128(c, t[2], 51); + add128_64(t[3], c) r3 = lo128(t[3]) & reduce_mask_51; shr128(c, t[3], 51); + add128_64(t[4], c) r4 = lo128(t[4]) & reduce_mask_51; shr128(c, t[4], 51); + r0 += c * 19; c = r0 >> 51; r0 = r0 & reduce_mask_51; + r1 += c; + + out[0] = r0; + out[1] = r1; + out[2] = r2; + out[3] = r3; + out[4] = r4; +} + +/* out = in^(2 * count) */ +DONNA_INLINE static void +curve25519_square_times(bignum25519 out, const bignum25519 in, uint64_t count) { +#if !defined(HAVE_NATIVE_UINT128) + uint128_t mul; +#endif + uint128_t t[5]; + uint64_t r0,r1,r2,r3,r4,c; + uint64_t d0,d1,d2,d4,d419; + + r0 = in[0]; + r1 = in[1]; + r2 = in[2]; + r3 = in[3]; + r4 = in[4]; + + do { + d0 = r0 * 2; + d1 = r1 * 2; + d2 = r2 * 2 * 19; + d419 = r4 * 19; + d4 = d419 * 2; + +#if defined(HAVE_NATIVE_UINT128) + t[0] = ((uint128_t) r0) * r0 + ((uint128_t) d4) * r1 + (((uint128_t) d2) * (r3 )); + t[1] = ((uint128_t) d0) * r1 + ((uint128_t) d4) * r2 + (((uint128_t) r3) * (r3 * 19)); + t[2] = ((uint128_t) d0) * r2 + ((uint128_t) r1) * r1 + (((uint128_t) d4) * (r3 )); + t[3] = ((uint128_t) d0) * r3 + ((uint128_t) d1) * r2 + (((uint128_t) r4) * (d419 )); + t[4] = ((uint128_t) d0) * r4 + ((uint128_t) d1) * r3 + (((uint128_t) r2) * (r2 )); +#else + mul64x64_128(t[0], r0, r0) mul64x64_128(mul, d4, r1) add128(t[0], mul) mul64x64_128(mul, d2, r3) add128(t[0], mul) + mul64x64_128(t[1], d0, r1) mul64x64_128(mul, d4, r2) add128(t[1], mul) mul64x64_128(mul, r3, r3 * 19) add128(t[1], mul) + mul64x64_128(t[2], d0, r2) mul64x64_128(mul, r1, r1) add128(t[2], mul) mul64x64_128(mul, d4, r3) add128(t[2], mul) + mul64x64_128(t[3], d0, r3) mul64x64_128(mul, d1, r2) add128(t[3], mul) mul64x64_128(mul, r4, d419) add128(t[3], mul) + mul64x64_128(t[4], d0, r4) mul64x64_128(mul, d1, r3) add128(t[4], mul) mul64x64_128(mul, r2, r2) add128(t[4], mul) +#endif + + r0 = lo128(t[0]) & reduce_mask_51; shr128(c, t[0], 51); + add128_64(t[1], c) r1 = lo128(t[1]) & reduce_mask_51; shr128(c, t[1], 51); + add128_64(t[2], c) r2 = lo128(t[2]) & reduce_mask_51; shr128(c, t[2], 51); + add128_64(t[3], c) r3 = lo128(t[3]) & reduce_mask_51; shr128(c, t[3], 51); + add128_64(t[4], c) r4 = lo128(t[4]) & reduce_mask_51; shr128(c, t[4], 51); + r0 += c * 19; c = r0 >> 51; r0 = r0 & reduce_mask_51; + r1 += c; + } while(--count); + + out[0] = r0; + out[1] = r1; + out[2] = r2; + out[3] = r3; + out[4] = r4; +} + +DONNA_INLINE static void +curve25519_square(bignum25519 out, const bignum25519 in) { +#if !defined(HAVE_NATIVE_UINT128) + uint128_t mul; +#endif + uint128_t t[5]; + uint64_t r0,r1,r2,r3,r4,c; + uint64_t d0,d1,d2,d4,d419; + + r0 = in[0]; + r1 = in[1]; + r2 = in[2]; + r3 = in[3]; + r4 = in[4]; + + d0 = r0 * 2; + d1 = r1 * 2; + d2 = r2 * 2 * 19; + d419 = r4 * 19; + d4 = d419 * 2; + +#if defined(HAVE_NATIVE_UINT128) + t[0] = ((uint128_t) r0) * r0 + ((uint128_t) d4) * r1 + (((uint128_t) d2) * (r3 )); + t[1] = ((uint128_t) d0) * r1 + ((uint128_t) d4) * r2 + (((uint128_t) r3) * (r3 * 19)); + t[2] = ((uint128_t) d0) * r2 + ((uint128_t) r1) * r1 + (((uint128_t) d4) * (r3 )); + t[3] = ((uint128_t) d0) * r3 + ((uint128_t) d1) * r2 + (((uint128_t) r4) * (d419 )); + t[4] = ((uint128_t) d0) * r4 + ((uint128_t) d1) * r3 + (((uint128_t) r2) * (r2 )); +#else + mul64x64_128(t[0], r0, r0) mul64x64_128(mul, d4, r1) add128(t[0], mul) mul64x64_128(mul, d2, r3) add128(t[0], mul) + mul64x64_128(t[1], d0, r1) mul64x64_128(mul, d4, r2) add128(t[1], mul) mul64x64_128(mul, r3, r3 * 19) add128(t[1], mul) + mul64x64_128(t[2], d0, r2) mul64x64_128(mul, r1, r1) add128(t[2], mul) mul64x64_128(mul, d4, r3) add128(t[2], mul) + mul64x64_128(t[3], d0, r3) mul64x64_128(mul, d1, r2) add128(t[3], mul) mul64x64_128(mul, r4, d419) add128(t[3], mul) + mul64x64_128(t[4], d0, r4) mul64x64_128(mul, d1, r3) add128(t[4], mul) mul64x64_128(mul, r2, r2) add128(t[4], mul) +#endif + + r0 = lo128(t[0]) & reduce_mask_51; shr128(c, t[0], 51); + add128_64(t[1], c) r1 = lo128(t[1]) & reduce_mask_51; shr128(c, t[1], 51); + add128_64(t[2], c) r2 = lo128(t[2]) & reduce_mask_51; shr128(c, t[2], 51); + add128_64(t[3], c) r3 = lo128(t[3]) & reduce_mask_51; shr128(c, t[3], 51); + add128_64(t[4], c) r4 = lo128(t[4]) & reduce_mask_51; shr128(c, t[4], 51); + r0 += c * 19; c = r0 >> 51; r0 = r0 & reduce_mask_51; + r1 += c; + + out[0] = r0; + out[1] = r1; + out[2] = r2; + out[3] = r3; + out[4] = r4; +} + + +/* Take a little-endian, 32-byte number and expand it into polynomial form */ +DONNA_INLINE static void +curve25519_expand(bignum25519 out, const unsigned char *in) { + static const union { uint8_t b[2]; uint16_t s; } endian_check = {{1,0}}; + uint64_t x0,x1,x2,x3; + + if (endian_check.s == 1) { + x0 = *(uint64_t *)(in + 0); + x1 = *(uint64_t *)(in + 8); + x2 = *(uint64_t *)(in + 16); + x3 = *(uint64_t *)(in + 24); + } else { + #define F(s) \ + ((((uint64_t)in[s + 0]) ) | \ + (((uint64_t)in[s + 1]) << 8) | \ + (((uint64_t)in[s + 2]) << 16) | \ + (((uint64_t)in[s + 3]) << 24) | \ + (((uint64_t)in[s + 4]) << 32) | \ + (((uint64_t)in[s + 5]) << 40) | \ + (((uint64_t)in[s + 6]) << 48) | \ + (((uint64_t)in[s + 7]) << 56)) + + x0 = F(0); + x1 = F(8); + x2 = F(16); + x3 = F(24); + } + + out[0] = x0 & reduce_mask_51; x0 = (x0 >> 51) | (x1 << 13); + out[1] = x0 & reduce_mask_51; x1 = (x1 >> 38) | (x2 << 26); + out[2] = x1 & reduce_mask_51; x2 = (x2 >> 25) | (x3 << 39); + out[3] = x2 & reduce_mask_51; x3 = (x3 >> 12); + out[4] = x3 & reduce_mask_51; /* ignore the top bit */ +} + +/* Take a fully reduced polynomial form number and contract it into a + * little-endian, 32-byte array + */ +DONNA_INLINE static void +curve25519_contract(unsigned char *out, const bignum25519 input) { + uint64_t t[5]; + uint64_t f, i; + + t[0] = input[0]; + t[1] = input[1]; + t[2] = input[2]; + t[3] = input[3]; + t[4] = input[4]; + + #define curve25519_contract_carry() \ + t[1] += t[0] >> 51; t[0] &= reduce_mask_51; \ + t[2] += t[1] >> 51; t[1] &= reduce_mask_51; \ + t[3] += t[2] >> 51; t[2] &= reduce_mask_51; \ + t[4] += t[3] >> 51; t[3] &= reduce_mask_51; + + #define curve25519_contract_carry_full() curve25519_contract_carry() \ + t[0] += 19 * (t[4] >> 51); t[4] &= reduce_mask_51; + + #define curve25519_contract_carry_final() curve25519_contract_carry() \ + t[4] &= reduce_mask_51; + + curve25519_contract_carry_full() + curve25519_contract_carry_full() + + /* now t is between 0 and 2^255-1, properly carried. */ + /* case 1: between 0 and 2^255-20. case 2: between 2^255-19 and 2^255-1. */ + t[0] += 19; + curve25519_contract_carry_full() + + /* now between 19 and 2^255-1 in both cases, and offset by 19. */ + t[0] += 0x8000000000000 - 19; + t[1] += 0x8000000000000 - 1; + t[2] += 0x8000000000000 - 1; + t[3] += 0x8000000000000 - 1; + t[4] += 0x8000000000000 - 1; + + /* now between 2^255 and 2^256-20, and offset by 2^255. */ + curve25519_contract_carry_final() + + #define write51full(n,shift) \ + f = ((t[n] >> shift) | (t[n+1] << (51 - shift))); \ + for (i = 0; i < 8; i++, f >>= 8) *out++ = (unsigned char)f; + #define write51(n) write51full(n,13*n) + + write51(0) + write51(1) + write51(2) + write51(3) + + #undef curve25519_contract_carry + #undef curve25519_contract_carry_full + #undef curve25519_contract_carry_final + #undef write51full + #undef write51 +} + +/* + * Swap the contents of [qx] and [qpx] iff @swap is non-zero + */ +DONNA_INLINE static void +curve25519_swap_conditional(bignum25519 x, bignum25519 qpx, uint64_t iswap) { + const uint64_t swap = (uint64_t)(-(int64_t)iswap); + uint64_t x0,x1,x2,x3,x4; + + x0 = swap & (x[0] ^ qpx[0]); x[0] ^= x0; qpx[0] ^= x0; + x1 = swap & (x[1] ^ qpx[1]); x[1] ^= x1; qpx[1] ^= x1; + x2 = swap & (x[2] ^ qpx[2]); x[2] ^= x2; qpx[2] ^= x2; + x3 = swap & (x[3] ^ qpx[3]); x[3] ^= x3; qpx[3] ^= x3; + x4 = swap & (x[4] ^ qpx[4]); x[4] ^= x4; qpx[4] ^= x4; + +} + diff --git a/curve25519-donna/curve25519-donna-common.h b/curve25519-donna/curve25519-donna-common.h new file mode 100644 index 000000000..6b3ed2ad6 --- /dev/null +++ b/curve25519-donna/curve25519-donna-common.h @@ -0,0 +1,43 @@ +/* + * In: b = 2^5 - 2^0 + * Out: b = 2^250 - 2^0 + */ +static void +curve25519_pow_two5mtwo0_two250mtwo0(bignum25519 b) { + bignum25519 ALIGN(16) t0,c; + + /* 2^5 - 2^0 */ /* b */ + /* 2^10 - 2^5 */ curve25519_square_times(t0, b, 5); + /* 2^10 - 2^0 */ curve25519_mul(b, t0, b); + /* 2^20 - 2^10 */ curve25519_square_times(t0, b, 10); + /* 2^20 - 2^0 */ curve25519_mul(c, t0, b); + /* 2^40 - 2^20 */ curve25519_square_times(t0, c, 20); + /* 2^40 - 2^0 */ curve25519_mul(t0, t0, c); + /* 2^50 - 2^10 */ curve25519_square_times(t0, t0, 10); + /* 2^50 - 2^0 */ curve25519_mul(b, t0, b); + /* 2^100 - 2^50 */ curve25519_square_times(t0, b, 50); + /* 2^100 - 2^0 */ curve25519_mul(c, t0, b); + /* 2^200 - 2^100 */ curve25519_square_times(t0, c, 100); + /* 2^200 - 2^0 */ curve25519_mul(t0, t0, c); + /* 2^250 - 2^50 */ curve25519_square_times(t0, t0, 50); + /* 2^250 - 2^0 */ curve25519_mul(b, t0, b); +} + +/* + * z^(p - 2) = z(2^255 - 21) + */ +static void +curve25519_recip(bignum25519 out, const bignum25519 z) { + bignum25519 ALIGN(16) a,t0,b; + + /* 2 */ curve25519_square(a, z); /* a = 2 */ + /* 8 */ curve25519_square_times(t0, a, 2); + /* 9 */ curve25519_mul(b, t0, z); /* b = 9 */ + /* 11 */ curve25519_mul(a, b, a); /* a = 11 */ + /* 22 */ curve25519_square(t0, a); + /* 2^5 - 2^0 = 31 */ curve25519_mul(b, t0, b); + /* 2^250 - 2^0 */ curve25519_pow_two5mtwo0_two250mtwo0(b); + /* 2^255 - 2^5 */ curve25519_square_times(b, b, 5); + /* 2^255 - 21 */ curve25519_mul(out, b, a); +} + diff --git a/curve25519-donna/curve25519-donna-portable-identify.h b/curve25519-donna/curve25519-donna-portable-identify.h new file mode 100644 index 000000000..26a264cf9 --- /dev/null +++ b/curve25519-donna/curve25519-donna-portable-identify.h @@ -0,0 +1,103 @@ +/* os */ +#if defined(_WIN32) || defined(_WIN64) || defined(__TOS_WIN__) || defined(__WINDOWS__) + #define OS_WINDOWS +#elif defined(sun) || defined(__sun) || defined(__SVR4) || defined(__svr4__) + #define OS_SOLARIS +#else + #include /* need this to define BSD */ + #define OS_NIX + #if defined(__linux__) + #define OS_LINUX + #elif defined(BSD) + #define OS_BSD + #if defined(MACOS_X) || (defined(__APPLE__) & defined(__MACH__)) + #define OS_OSX + #elif defined(macintosh) || defined(Macintosh) + #define OS_MAC + #elif defined(__OpenBSD__) + #define OS_OPENBSD + #endif + #endif +#endif + + +/* compiler */ +#if defined(_MSC_VER) + #define COMPILER_MSVC +#endif +#if defined(__ICC) + #define COMPILER_INTEL +#endif +#if defined(__GNUC__) + #if (__GNUC__ >= 3) + #define COMPILER_GCC ((__GNUC__ * 10000) + (__GNUC_MINOR__ * 100) + (__GNUC_PATCHLEVEL__)) + #else + #define COMPILER_GCC ((__GNUC__ * 10000) + (__GNUC_MINOR__ * 100) ) + #endif +#endif +#if defined(__PATHCC__) + #define COMPILER_PATHCC +#endif +#if defined(__clang__) + #define COMPILER_CLANG ((__clang_major__ * 10000) + (__clang_minor__ * 100) + (__clang_patchlevel__)) +#endif + + + +/* cpu */ +#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__ ) || defined(_M_X64) + #define CPU_X86_64 +#elif defined(__i586__) || defined(__i686__) || (defined(_M_IX86) && (_M_IX86 >= 500)) + #define CPU_X86 500 +#elif defined(__i486__) || (defined(_M_IX86) && (_M_IX86 >= 400)) + #define CPU_X86 400 +#elif defined(__i386__) || (defined(_M_IX86) && (_M_IX86 >= 300)) || defined(__X86__) || defined(_X86_) || defined(__I86__) + #define CPU_X86 300 +#elif defined(__ia64__) || defined(_IA64) || defined(__IA64__) || defined(_M_IA64) || defined(__ia64) + #define CPU_IA64 +#endif + +#if defined(__sparc__) || defined(__sparc) || defined(__sparcv9) + #define CPU_SPARC + #if defined(__sparcv9) + #define CPU_SPARC64 + #endif +#endif + +#if defined(powerpc) || defined(__PPC__) || defined(__ppc__) || defined(_ARCH_PPC) || defined(__powerpc__) || defined(__powerpc) || defined(POWERPC) || defined(_M_PPC) + #define CPU_PPC + #if defined(_ARCH_PWR7) + #define CPU_POWER7 + #elif defined(__64BIT__) + #define CPU_PPC64 + #else + #define CPU_PPC32 + #endif +#endif + +#if defined(__hppa__) || defined(__hppa) + #define CPU_HPPA +#endif + +#if defined(__alpha__) || defined(__alpha) || defined(_M_ALPHA) + #define CPU_ALPHA +#endif + +/* 64 bit cpu */ +#if defined(CPU_X86_64) || defined(CPU_IA64) || defined(CPU_SPARC64) || defined(__64BIT__) || defined(__LP64__) || defined(_LP64) || (defined(_MIPS_SZLONG) && (_MIPS_SZLONG == 64)) + #define CPU_64BITS +#endif + +#if defined(COMPILER_MSVC) + typedef signed char int8_t; + typedef unsigned char uint8_t; + typedef signed short int16_t; + typedef unsigned short uint16_t; + typedef signed int int32_t; + typedef unsigned int uint32_t; + typedef signed __int64 int64_t; + typedef unsigned __int64 uint64_t; +#else + #include +#endif + diff --git a/curve25519-donna/curve25519-donna-portable.h b/curve25519-donna/curve25519-donna-portable.h new file mode 100644 index 000000000..71da697d5 --- /dev/null +++ b/curve25519-donna/curve25519-donna-portable.h @@ -0,0 +1,92 @@ +#include "curve25519-donna-portable-identify.h" + +#define mul32x32_64(a,b) (((uint64_t)(a))*(b)) + +/* platform */ +#if defined(COMPILER_MSVC) + #include + #if !defined(_DEBUG) + #undef mul32x32_64 + #define mul32x32_64(a,b) __emulu(a,b) + #endif + #undef inline + #define inline __forceinline + #define DONNA_INLINE __forceinline + #define DONNA_NOINLINE __declspec(noinline) + #define ALIGN(x) __declspec(align(x)) + #define ROTL32(a,b) _rotl(a,b) + #define ROTR32(a,b) _rotr(a,b) +#else + #include + #define DONNA_INLINE inline __attribute__((always_inline)) + #define DONNA_NOINLINE __attribute__((noinline)) + #define ALIGN(x) __attribute__((aligned(x))) + #define ROTL32(a,b) (((a) << (b)) | ((a) >> (32 - b))) + #define ROTR32(a,b) (((a) >> (b)) | ((a) << (32 - b))) +#endif + +/* uint128_t */ +#if defined(CPU_64BITS) && !defined(ED25519_FORCE_32BIT) + #if defined(COMPILER_CLANG) && (COMPILER_CLANG >= 30100) + #define HAVE_NATIVE_UINT128 + typedef unsigned __int128 uint128_t; + #elif defined(COMPILER_MSVC) + #define HAVE_UINT128 + typedef struct uint128_t { + uint64_t lo, hi; + } uint128_t; + #define mul64x64_128(out,a,b) out.lo = _umul128(a,b,&out.hi); + #define shr128_pair(out,hi,lo,shift) out = __shiftright128(lo, hi, shift); + #define shl128_pair(out,hi,lo,shift) out = __shiftleft128(lo, hi, shift); + #define shr128(out,in,shift) shr128_pair(out, in.hi, in.lo, shift) + #define shl128(out,in,shift) shl128_pair(out, in.hi, in.lo, shift) + #define add128(a,b) { uint64_t p = a.lo; a.lo += b.lo; a.hi += b.hi + (a.lo < p); } + #define add128_64(a,b) { uint64_t p = a.lo; a.lo += b; a.hi += (a.lo < p); } + #define lo128(a) (a.lo) + #define hi128(a) (a.hi) + #elif defined(COMPILER_GCC) && !defined(HAVE_NATIVE_UINT128) + #if defined(__SIZEOF_INT128__) + #define HAVE_NATIVE_UINT128 + typedef unsigned __int128 uint128_t; + #elif (COMPILER_GCC >= 40400) + #define HAVE_NATIVE_UINT128 + typedef unsigned uint128_t __attribute__((mode(TI))); + #elif defined(CPU_X86_64) + #define HAVE_UINT128 + typedef struct uint128_t { + uint64_t lo, hi; + } uint128_t; + #define mul64x64_128(out,a,b) __asm__ ("mulq %3" : "=a" (out.lo), "=d" (out.hi) : "a" (a), "rm" (b)); + #define shr128_pair(out,hi,lo,shift) __asm__ ("shrdq %2,%1,%0" : "+r" (lo) : "r" (hi), "J" (shift)); out = lo; + #define shl128_pair(out,hi,lo,shift) __asm__ ("shldq %2,%1,%0" : "+r" (hi) : "r" (lo), "J" (shift)); out = hi; + #define shr128(out,in,shift) shr128_pair(out,in.hi, in.lo, shift) + #define shl128(out,in,shift) shl128_pair(out,in.hi, in.lo, shift) + #define add128(a,b) __asm__ ("addq %4,%2; adcq %5,%3" : "=r" (a.hi), "=r" (a.lo) : "1" (a.lo), "0" (a.hi), "rm" (b.lo), "rm" (b.hi) : "cc"); + #define add128_64(a,b) __asm__ ("addq %4,%2; adcq $0,%3" : "=r" (a.hi), "=r" (a.lo) : "1" (a.lo), "0" (a.hi), "rm" (b) : "cc"); + #define lo128(a) (a.lo) + #define hi128(a) (a.hi) + #endif + #endif + + #if defined(HAVE_NATIVE_UINT128) + #define HAVE_UINT128 + #define mul64x64_128(out,a,b) out = (uint128_t)a * b; + #define shr128_pair(out,hi,lo,shift) out = (uint64_t)((((uint128_t)hi << 64) | lo) >> (shift)); + #define shl128_pair(out,hi,lo,shift) out = (uint64_t)(((((uint128_t)hi << 64) | lo) << (shift)) >> 64); + #define shr128(out,in,shift) out = (uint64_t)(in >> (shift)); + #define shl128(out,in,shift) out = (uint64_t)((in << shift) >> 64); + #define add128(a,b) a += b; + #define add128_64(a,b) a += (uint64_t)b; + #define lo128(a) ((uint64_t)a) + #define hi128(a) ((uint64_t)(a >> 64)) + #endif + + #if !defined(HAVE_UINT128) + #error Need a uint128_t implementation! + #endif +#endif + +#include +#include + + diff --git a/curve25519-donna/curve25519-donna-scalarmult-base.h b/curve25519-donna/curve25519-donna-scalarmult-base.h new file mode 100644 index 000000000..061759fa6 --- /dev/null +++ b/curve25519-donna/curve25519-donna-scalarmult-base.h @@ -0,0 +1,66 @@ +/* Calculates nQ where Q is the x-coordinate of a point on the curve + * + * mypublic: the packed little endian x coordinate of the resulting curve point + * n: a little endian, 32-byte number + * basepoint: a packed little endian point of the curve + */ + +static void +curve25519_scalarmult_donna(curve25519_key mypublic, const curve25519_key n, const curve25519_key basepoint) { + bignum25519 nqpqx = {1}, nqpqz = {0}, nqz = {1}, nqx; + bignum25519 q, qx, qpqx, qqx, zzz, zmone; + size_t bit, lastbit; + int32_t i; + + curve25519_expand(q, basepoint); + curve25519_copy(nqx, q); + + /* bit 255 is always 0, and bit 254 is always 1, so skip bit 255 and + start pre-swapped on bit 254 */ + lastbit = 1; + + /* we are doing bits 254..3 in the loop, but are swapping in bits 253..2 */ + for (i = 253; i >= 2; i--) { + curve25519_add(qx, nqx, nqz); + curve25519_sub(nqz, nqx, nqz); + curve25519_add(qpqx, nqpqx, nqpqz); + curve25519_sub(nqpqz, nqpqx, nqpqz); + curve25519_mul(nqpqx, qpqx, nqz); + curve25519_mul(nqpqz, qx, nqpqz); + curve25519_add(qqx, nqpqx, nqpqz); + curve25519_sub(nqpqz, nqpqx, nqpqz); + curve25519_square(nqpqz, nqpqz); + curve25519_square(nqpqx, qqx); + curve25519_mul(nqpqz, nqpqz, q); + curve25519_square(qx, qx); + curve25519_square(nqz, nqz); + curve25519_mul(nqx, qx, nqz); + curve25519_sub(nqz, qx, nqz); + curve25519_scalar_product(zzz, nqz, 121665); + curve25519_add(zzz, zzz, qx); + curve25519_mul(nqz, nqz, zzz); + + bit = (n[i/8] >> (i & 7)) & 1; + curve25519_swap_conditional(nqx, nqpqx, bit ^ lastbit); + curve25519_swap_conditional(nqz, nqpqz, bit ^ lastbit); + lastbit = bit; + } + + /* the final 3 bits are always zero, so we only need to double */ + for (i = 0; i < 3; i++) { + curve25519_add(qx, nqx, nqz); + curve25519_sub(nqz, nqx, nqz); + curve25519_square(qx, qx); + curve25519_square(nqz, nqz); + curve25519_mul(nqx, qx, nqz); + curve25519_sub(nqz, qx, nqz); + curve25519_scalar_product(zzz, nqz, 121665); + curve25519_add(zzz, zzz, qx); + curve25519_mul(nqz, nqz, zzz); + } + + curve25519_recip(zmone, nqz); + curve25519_mul(nqz, nqx, zmone); + curve25519_contract(mypublic, nqz); +} + diff --git a/curve25519-donna/curve25519-donna-scalarmult-sse2.h b/curve25519-donna/curve25519-donna-scalarmult-sse2.h new file mode 100644 index 000000000..e0ef14c11 --- /dev/null +++ b/curve25519-donna/curve25519-donna-scalarmult-sse2.h @@ -0,0 +1,65 @@ + +/* Calculates nQ where Q is the x-coordinate of a point on the curve + * + * mypublic: the packed little endian x coordinate of the resulting curve point + * n: a little endian, 32-byte number + * basepoint: a packed little endian point of the curve + */ +static void +curve25519_scalarmult_donna(curve25519_key mypublic, const curve25519_key n, const curve25519_key basepoint) { + bignum25519 ALIGN(16) nqx = {1}, nqpqz = {1}, nqz = {0}, nqpqx, zmone; + packed32bignum25519 qx, qz, pqz, pqx; + packed64bignum25519 nq, sq, sqscalar, prime, primex, primez, nqpq; + bignum25519mulprecomp preq; + size_t bit, lastbit, i; + + curve25519_expand(nqpqx, basepoint); + curve25519_mul_precompute(&preq, nqpqx); + + /* do bits 254..3 */ + for (i = 254, lastbit = 0; i >= 3; i--) { + bit = (n[i/8] >> (i & 7)) & 1; + curve25519_swap_conditional(nqx, nqpqx, bit ^ lastbit); + curve25519_swap_conditional(nqz, nqpqz, bit ^ lastbit); + lastbit = bit; + + curve25519_tangle32(qx, nqx, nqpqx); /* qx = [nqx,nqpqx] */ + curve25519_tangle32(qz, nqz, nqpqz); /* qz = [nqz,nqpqz] */ + + curve25519_add_packed32(pqx, qx, qz); /* pqx = [nqx+nqz,nqpqx+nqpqz] */ + curve25519_sub_packed32(pqz, qx, qz); /* pqz = [nqx-nqz,nqpqx-nqpqz] */ + + curve25519_make_nqpq(primex, primez, pqx, pqz); /* primex = [nqx+nqz,nqpqx+nqpqz], primez = [nqpqx-nqpqz,nqx-nqz] */ + curve25519_mul_packed64(prime, primex, primez); /* prime = [nqx+nqz,nqpqx+nqpqz] * [nqpqx-nqpqz,nqx-nqz] */ + curve25519_addsub_packed64(prime); /* prime = [prime.x+prime.z,prime.x-prime.z] */ + curve25519_square_packed64(nqpq, prime); /* nqpq = prime^2 */ + curve25519_untangle64(nqpqx, nqpqz, nqpq); + curve25519_mul_precomputed(nqpqz, nqpqz, &preq); /* nqpqz = nqpqz * q */ + + /* (((sq.x-sq.z)*121665)+sq.x) * (sq.x-sq.z) is equivalent to (sq.x*121666-sq.z*121665) * (sq.x-sq.z) */ + curve25519_make_nq(nq, pqx, pqz); /* nq = [nqx+nqz,nqx-nqz] */ + curve25519_square_packed64(sq, nq); /* sq = nq^2 */ + curve25519_121665_packed64(sqscalar, sq); /* sqscalar = sq * [121666,121665] */ + curve25519_final_nq(nq, sq, sqscalar); /* nq = [sq.x,sqscalar.x-sqscalar.z] * [sq.z,sq.x-sq.z] */ + curve25519_untangle64(nqx, nqz, nq); + }; + + /* it's possible to get rid of this swap with the swap in the above loop + at the bottom instead of the top, but compilers seem to optimize better this way */ + curve25519_swap_conditional(nqx, nqpqx, bit); + curve25519_swap_conditional(nqz, nqpqz, bit); + + /* do bits 2..0 */ + for (i = 0; i < 3; i++) { + curve25519_compute_nq(nq, nqx, nqz); + curve25519_square_packed64(sq, nq); /* sq = nq^2 */ + curve25519_121665_packed64(sqscalar, sq); /* sqscalar = sq * [121666,121665] */ + curve25519_final_nq(nq, sq, sqscalar); /* nq = [sq.x,sqscalar.x-sqscalar.z] * [sq.z,sq.x-sq.z] */ + curve25519_untangle64(nqx, nqz, nq); + } + + curve25519_recip(zmone, nqz); + curve25519_mul(nqz, nqx, zmone); + curve25519_contract(mypublic, nqz); +} + diff --git a/curve25519-donna/curve25519-donna-sse2.h b/curve25519-donna/curve25519-donna-sse2.h new file mode 100644 index 000000000..ff2416209 --- /dev/null +++ b/curve25519-donna/curve25519-donna-sse2.h @@ -0,0 +1,1009 @@ +#include +typedef __m128i xmmi; + +typedef union packedelem8_t { + unsigned char u[16]; + xmmi v; +} packedelem8; + +typedef union packedelem32_t { + uint32_t u[4]; + xmmi v; +} packedelem32; + +typedef union packedelem64_t { + uint64_t u[2]; + xmmi v; +} packedelem64; + +/* 10 elements + an extra 2 to fit in 3 xmm registers */ +typedef uint32_t bignum25519[10+2]; +typedef packedelem32 packed32bignum25519[5]; +typedef packedelem64 packed64bignum25519[10]; + +static const uint32_t reduce_mask_26 = (1 << 26) - 1; +static const uint32_t reduce_mask_25 = (1 << 25) - 1; + +static const packedelem32 sse2_bot32bitmask = {{0xffffffff, 0x00000000, 0xffffffff, 0x00000000}}; +static const packedelem32 sse2_top32bitmask = {{0x00000000, 0xffffffff, 0x00000000, 0xffffffff}}; +static const packedelem32 sse2_top64bitmask = {{0x00000000, 0x00000000, 0xffffffff, 0xffffffff}}; +static const packedelem32 sse2_bot64bitmask = {{0xffffffff, 0xffffffff, 0x00000000, 0x00000000}}; + +/* reduction masks */ +static const packedelem64 packedmask26 = {{0x03ffffff, 0x03ffffff}}; +static const packedelem64 packedmask25 = {{0x01ffffff, 0x01ffffff}}; +static const packedelem32 packedmask2625 = {{0x3ffffff,0,0x1ffffff,0}}; +static const packedelem32 packedmask26262626 = {{0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff}}; +static const packedelem32 packedmask25252525 = {{0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff}}; + +/* multipliers */ +static const packedelem64 packednineteen = {{19, 19}}; +static const packedelem64 packednineteenone = {{19, 1}}; +static const packedelem64 packedthirtyeight = {{38, 38}}; +static const packedelem64 packed3819 = {{19*2,19}}; +static const packedelem64 packed9638 = {{19*4,19*2}}; + +/* 121666,121665 */ +static const packedelem64 packed121666121665 = {{121666, 121665}}; + +/* 2*(2^255 - 19) = 0 mod p */ +static const packedelem32 packed2p0 = {{0x7ffffda,0x3fffffe,0x7fffffe,0x3fffffe}}; +static const packedelem32 packed2p1 = {{0x7fffffe,0x3fffffe,0x7fffffe,0x3fffffe}}; +static const packedelem32 packed2p2 = {{0x7fffffe,0x3fffffe,0x0000000,0x0000000}}; + +static const packedelem32 packed32zeromodp0 = {{0x7ffffda,0x7ffffda,0x3fffffe,0x3fffffe}}; +static const packedelem32 packed32zeromodp1 = {{0x7fffffe,0x7fffffe,0x3fffffe,0x3fffffe}}; + +/* Copy a bignum to another: out = in */ +DONNA_INLINE static void +curve25519_copy(bignum25519 out, const bignum25519 in) { + xmmi x0,x1,x2; + x0 = _mm_load_si128((xmmi*)in + 0); + x1 = _mm_load_si128((xmmi*)in + 1); + x2 = _mm_load_si128((xmmi*)in + 2); + _mm_store_si128((xmmi*)out + 0, x0); + _mm_store_si128((xmmi*)out + 1, x1); + _mm_store_si128((xmmi*)out + 2, x2); +} + +/* Take a little-endian, 32-byte number and expand it into polynomial form */ +DONNA_INLINE static void +curve25519_expand(bignum25519 out, const unsigned char in[32]) { + uint32_t x0,x1,x2,x3,x4,x5,x6,x7; + + x0 = *(uint32_t *)(in + 0); + x1 = *(uint32_t *)(in + 4); + x2 = *(uint32_t *)(in + 8); + x3 = *(uint32_t *)(in + 12); + x4 = *(uint32_t *)(in + 16); + x5 = *(uint32_t *)(in + 20); + x6 = *(uint32_t *)(in + 24); + x7 = *(uint32_t *)(in + 28); + + out[0] = ( x0 ) & reduce_mask_26; + out[1] = ((((uint64_t)x1 << 32) | x0) >> 26) & reduce_mask_25; + out[2] = ((((uint64_t)x2 << 32) | x1) >> 19) & reduce_mask_26; + out[3] = ((((uint64_t)x3 << 32) | x2) >> 13) & reduce_mask_25; + out[4] = (( x3) >> 6) & reduce_mask_26; + out[5] = ( x4 ) & reduce_mask_25; + out[6] = ((((uint64_t)x5 << 32) | x4) >> 25) & reduce_mask_26; + out[7] = ((((uint64_t)x6 << 32) | x5) >> 19) & reduce_mask_25; + out[8] = ((((uint64_t)x7 << 32) | x6) >> 12) & reduce_mask_26; + out[9] = (( x7) >> 6) & reduce_mask_25; /* ignore the top bit */ + + out[10] = 0; + out[11] = 0; +} + +/* Take a fully reduced polynomial form number and contract it into a + * little-endian, 32-byte array + */ +DONNA_INLINE static void +curve25519_contract(unsigned char out[32], const bignum25519 in) { + bignum25519 ALIGN(16) f; + + curve25519_copy(f, in); + + #define carry_pass() \ + f[1] += f[0] >> 26; f[0] &= reduce_mask_26; \ + f[2] += f[1] >> 25; f[1] &= reduce_mask_25; \ + f[3] += f[2] >> 26; f[2] &= reduce_mask_26; \ + f[4] += f[3] >> 25; f[3] &= reduce_mask_25; \ + f[5] += f[4] >> 26; f[4] &= reduce_mask_26; \ + f[6] += f[5] >> 25; f[5] &= reduce_mask_25; \ + f[7] += f[6] >> 26; f[6] &= reduce_mask_26; \ + f[8] += f[7] >> 25; f[7] &= reduce_mask_25; \ + f[9] += f[8] >> 26; f[8] &= reduce_mask_26; + + #define carry_pass_full() \ + carry_pass() \ + f[0] += 19 * (f[9] >> 25); f[9] &= reduce_mask_25; + + #define carry_pass_final() \ + carry_pass() \ + f[9] &= reduce_mask_25; + + carry_pass_full() + carry_pass_full() + + /* now t is between 0 and 2^255-1, properly carried. */ + /* case 1: between 0 and 2^255-20. case 2: between 2^255-19 and 2^255-1. */ + f[0] += 19; + carry_pass_full() + + /* now between 19 and 2^255-1 in both cases, and offset by 19. */ + f[0] += (1 << 26) - 19; + f[1] += (1 << 25) - 1; + f[2] += (1 << 26) - 1; + f[3] += (1 << 25) - 1; + f[4] += (1 << 26) - 1; + f[5] += (1 << 25) - 1; + f[6] += (1 << 26) - 1; + f[7] += (1 << 25) - 1; + f[8] += (1 << 26) - 1; + f[9] += (1 << 25) - 1; + + /* now between 2^255 and 2^256-20, and offset by 2^255. */ + carry_pass_final() + + #undef carry_pass + #undef carry_full + #undef carry_final + + *(uint32_t *)(out + 0) = ((f[0] ) | (f[1] << 26)); + *(uint32_t *)(out + 4) = ((f[1] >> 6) | (f[2] << 19)); + *(uint32_t *)(out + 8) = ((f[2] >> 13) | (f[3] << 13)); + *(uint32_t *)(out + 12) = ((f[3] >> 19) | (f[4] << 6)); + *(uint32_t *)(out + 16) = ((f[5] ) | (f[6] << 25)); + *(uint32_t *)(out + 20) = ((f[6] >> 7) | (f[7] << 19)); + *(uint32_t *)(out + 24) = ((f[7] >> 13) | (f[8] << 12)); + *(uint32_t *)(out + 28) = ((f[8] >> 20) | (f[9] << 6)); +} + +/* + * Maybe swap the contents of two felem arrays (@a and @b), each 5 elements + * long. Perform the swap iff @swap is non-zero. + */ +DONNA_INLINE static void +curve25519_swap_conditional(bignum25519 a, bignum25519 b, uint32_t iswap) { + const uint32_t swap = (uint32_t)(-(int32_t)iswap); + xmmi a0,a1,a2,b0,b1,b2,x0,x1,x2; + xmmi mask = _mm_cvtsi32_si128(swap); + mask = _mm_shuffle_epi32(mask, 0); + a0 = _mm_load_si128((xmmi *)a + 0); + a1 = _mm_load_si128((xmmi *)a + 1); + a2 = _mm_load_si128((xmmi *)a + 2); + b0 = _mm_load_si128((xmmi *)b + 0); + b1 = _mm_load_si128((xmmi *)b + 1); + b2 = _mm_load_si128((xmmi *)b + 2); + b0 = _mm_xor_si128(a0, b0); + b1 = _mm_xor_si128(a1, b1); + b2 = _mm_xor_si128(a2, b2); + x0 = _mm_and_si128(b0, mask); + x1 = _mm_and_si128(b1, mask); + x2 = _mm_and_si128(b2, mask); + x0 = _mm_xor_si128(x0, a0); + x1 = _mm_xor_si128(x1, a1); + x2 = _mm_xor_si128(x2, a2); + a0 = _mm_xor_si128(x0, b0); + a1 = _mm_xor_si128(x1, b1); + a2 = _mm_xor_si128(x2, b2); + _mm_store_si128((xmmi *)a + 0, x0); + _mm_store_si128((xmmi *)a + 1, x1); + _mm_store_si128((xmmi *)a + 2, x2); + _mm_store_si128((xmmi *)b + 0, a0); + _mm_store_si128((xmmi *)b + 1, a1); + _mm_store_si128((xmmi *)b + 2, a2); +} + +/* interleave two bignums */ +DONNA_INLINE static void +curve25519_tangle32(packedelem32 *out, const bignum25519 x, const bignum25519 z) { + xmmi x0,x1,x2,z0,z1,z2; + + x0 = _mm_load_si128((xmmi *)(x + 0)); + x1 = _mm_load_si128((xmmi *)(x + 4)); + x2 = _mm_load_si128((xmmi *)(x + 8)); + z0 = _mm_load_si128((xmmi *)(z + 0)); + z1 = _mm_load_si128((xmmi *)(z + 4)); + z2 = _mm_load_si128((xmmi *)(z + 8)); + + out[0].v = _mm_unpacklo_epi32(x0, z0); + out[1].v = _mm_unpackhi_epi32(x0, z0); + out[2].v = _mm_unpacklo_epi32(x1, z1); + out[3].v = _mm_unpackhi_epi32(x1, z1); + out[4].v = _mm_unpacklo_epi32(x2, z2); +} + +/* split a packed bignum in to it's two parts */ +DONNA_INLINE static void +curve25519_untangle64(bignum25519 x, bignum25519 z, const packedelem64 *in) { + _mm_store_si128((xmmi *)(x + 0), _mm_unpacklo_epi64(_mm_unpacklo_epi32(in[0].v, in[1].v), _mm_unpacklo_epi32(in[2].v, in[3].v))); + _mm_store_si128((xmmi *)(x + 4), _mm_unpacklo_epi64(_mm_unpacklo_epi32(in[4].v, in[5].v), _mm_unpacklo_epi32(in[6].v, in[7].v))); + _mm_store_si128((xmmi *)(x + 8), _mm_unpacklo_epi32(in[8].v, in[9].v) ); + _mm_store_si128((xmmi *)(z + 0), _mm_unpacklo_epi64(_mm_unpackhi_epi32(in[0].v, in[1].v), _mm_unpackhi_epi32(in[2].v, in[3].v))); + _mm_store_si128((xmmi *)(z + 4), _mm_unpacklo_epi64(_mm_unpackhi_epi32(in[4].v, in[5].v), _mm_unpackhi_epi32(in[6].v, in[7].v))); + _mm_store_si128((xmmi *)(z + 8), _mm_unpackhi_epi32(in[8].v, in[9].v) ); +} + +/* add two packed bignums */ +DONNA_INLINE static void +curve25519_add_packed32(packedelem32 *out, const packedelem32 *r, const packedelem32 *s) { + out[0].v = _mm_add_epi32(r[0].v, s[0].v); + out[1].v = _mm_add_epi32(r[1].v, s[1].v); + out[2].v = _mm_add_epi32(r[2].v, s[2].v); + out[3].v = _mm_add_epi32(r[3].v, s[3].v); + out[4].v = _mm_add_epi32(r[4].v, s[4].v); +} + +/* subtract two packed bignums */ +DONNA_INLINE static void +curve25519_sub_packed32(packedelem32 *out, const packedelem32 *r, const packedelem32 *s) { + xmmi r0,r1,r2,r3,r4; + xmmi s0,s1,s2,s3; + xmmi c1,c2; + + r0 = _mm_add_epi32(r[0].v, packed32zeromodp0.v); + r1 = _mm_add_epi32(r[1].v, packed32zeromodp1.v); + r2 = _mm_add_epi32(r[2].v, packed32zeromodp1.v); + r3 = _mm_add_epi32(r[3].v, packed32zeromodp1.v); + r4 = _mm_add_epi32(r[4].v, packed32zeromodp1.v); + r0 = _mm_sub_epi32(r0, s[0].v); /* 00 11 */ + r1 = _mm_sub_epi32(r1, s[1].v); /* 22 33 */ + r2 = _mm_sub_epi32(r2, s[2].v); /* 44 55 */ + r3 = _mm_sub_epi32(r3, s[3].v); /* 66 77 */ + r4 = _mm_sub_epi32(r4, s[4].v); /* 88 99 */ + + s0 = _mm_unpacklo_epi64(r0, r2); /* 00 44 */ + s1 = _mm_unpackhi_epi64(r0, r2); /* 11 55 */ + s2 = _mm_unpacklo_epi64(r1, r3); /* 22 66 */ + s3 = _mm_unpackhi_epi64(r1, r3); /* 33 77 */ + + c1 = _mm_srli_epi32(s0, 26); c2 = _mm_srli_epi32(s2, 26); s0 = _mm_and_si128(s0, packedmask26262626.v); s2 = _mm_and_si128(s2, packedmask26262626.v); s1 = _mm_add_epi32(s1, c1); s3 = _mm_add_epi32(s3, c2); + c1 = _mm_srli_epi32(s1, 25); c2 = _mm_srli_epi32(s3, 25); s1 = _mm_and_si128(s1, packedmask25252525.v); s3 = _mm_and_si128(s3, packedmask25252525.v); s2 = _mm_add_epi32(s2, c1); r4 = _mm_add_epi32(r4, _mm_srli_si128(c2, 8)); s0 = _mm_add_epi32(s0, _mm_slli_si128(c2, 8)); + + out[0].v = _mm_unpacklo_epi64(s0, s1); /* 00 11 */ + out[1].v = _mm_unpacklo_epi64(s2, s3); /* 22 33 */ + out[2].v = _mm_unpackhi_epi64(s0, s1); /* 44 55 */ + out[3].v = _mm_unpackhi_epi64(s2, s3); /* 66 77 */ + out[4].v = r4; /* 88 99 */ +} + +/* multiply two packed bignums */ +DONNA_INLINE static void +curve25519_mul_packed64(packedelem64 *out, const packedelem64 *r, const packedelem64 *s) { + xmmi r1,r2,r3,r4,r5,r6,r7,r8,r9; + xmmi r1_2,r3_2,r5_2,r7_2,r9_2; + xmmi c1,c2; + + out[0].v = _mm_mul_epu32(r[0].v, s[0].v); + out[1].v = _mm_add_epi64(_mm_mul_epu32(r[0].v, s[1].v), _mm_mul_epu32(r[1].v, s[0].v)); + r1_2 = _mm_slli_epi32(r[1].v, 1); + out[2].v = _mm_add_epi64(_mm_mul_epu32(r[0].v, s[2].v), _mm_add_epi64(_mm_mul_epu32(r1_2 , s[1].v), _mm_mul_epu32(r[2].v, s[0].v))); + out[3].v = _mm_add_epi64(_mm_mul_epu32(r[0].v, s[3].v), _mm_add_epi64(_mm_mul_epu32(r[1].v, s[2].v), _mm_add_epi64(_mm_mul_epu32(r[2].v, s[1].v), _mm_mul_epu32(r[3].v, s[0].v)))); + r3_2 = _mm_slli_epi32(r[3].v, 1); + out[4].v = _mm_add_epi64(_mm_mul_epu32(r[0].v, s[4].v), _mm_add_epi64(_mm_mul_epu32(r1_2 , s[3].v), _mm_add_epi64(_mm_mul_epu32(r[2].v, s[2].v), _mm_add_epi64(_mm_mul_epu32(r3_2 , s[1].v), _mm_mul_epu32(r[4].v, s[0].v))))); + out[5].v = _mm_add_epi64(_mm_mul_epu32(r[0].v, s[5].v), _mm_add_epi64(_mm_mul_epu32(r[1].v, s[4].v), _mm_add_epi64(_mm_mul_epu32(r[2].v, s[3].v), _mm_add_epi64(_mm_mul_epu32(r[3].v, s[2].v), _mm_add_epi64(_mm_mul_epu32(r[4].v, s[1].v), _mm_mul_epu32(r[5].v, s[0].v)))))); + r5_2 = _mm_slli_epi32(r[5].v, 1); + out[6].v = _mm_add_epi64(_mm_mul_epu32(r[0].v, s[6].v), _mm_add_epi64(_mm_mul_epu32(r1_2 , s[5].v), _mm_add_epi64(_mm_mul_epu32(r[2].v, s[4].v), _mm_add_epi64(_mm_mul_epu32(r3_2 , s[3].v), _mm_add_epi64(_mm_mul_epu32(r[4].v, s[2].v), _mm_add_epi64(_mm_mul_epu32(r5_2 , s[1].v), _mm_mul_epu32(r[6].v, s[0].v))))))); + out[7].v = _mm_add_epi64(_mm_mul_epu32(r[0].v, s[7].v), _mm_add_epi64(_mm_mul_epu32(r[1].v, s[6].v), _mm_add_epi64(_mm_mul_epu32(r[2].v, s[5].v), _mm_add_epi64(_mm_mul_epu32(r[3].v, s[4].v), _mm_add_epi64(_mm_mul_epu32(r[4].v, s[3].v), _mm_add_epi64(_mm_mul_epu32(r[5].v, s[2].v), _mm_add_epi64(_mm_mul_epu32(r[6].v, s[1].v), _mm_mul_epu32(r[7].v , s[0].v)))))))); + r7_2 = _mm_slli_epi32(r[7].v, 1); + out[8].v = _mm_add_epi64(_mm_mul_epu32(r[0].v, s[8].v), _mm_add_epi64(_mm_mul_epu32(r1_2 , s[7].v), _mm_add_epi64(_mm_mul_epu32(r[2].v, s[6].v), _mm_add_epi64(_mm_mul_epu32(r3_2 , s[5].v), _mm_add_epi64(_mm_mul_epu32(r[4].v, s[4].v), _mm_add_epi64(_mm_mul_epu32(r5_2 , s[3].v), _mm_add_epi64(_mm_mul_epu32(r[6].v, s[2].v), _mm_add_epi64(_mm_mul_epu32(r7_2 , s[1].v), _mm_mul_epu32(r[8].v, s[0].v))))))))); + out[9].v = _mm_add_epi64(_mm_mul_epu32(r[0].v, s[9].v), _mm_add_epi64(_mm_mul_epu32(r[1].v, s[8].v), _mm_add_epi64(_mm_mul_epu32(r[2].v, s[7].v), _mm_add_epi64(_mm_mul_epu32(r[3].v, s[6].v), _mm_add_epi64(_mm_mul_epu32(r[4].v, s[5].v), _mm_add_epi64(_mm_mul_epu32(r[5].v, s[4].v), _mm_add_epi64(_mm_mul_epu32(r[6].v, s[3].v), _mm_add_epi64(_mm_mul_epu32(r[7].v, s[2].v), _mm_add_epi64(_mm_mul_epu32(r[8].v, s[1].v), _mm_mul_epu32(r[9].v, s[0].v)))))))))); + + r1 = _mm_mul_epu32(r[1].v, packednineteen.v); + r2 = _mm_mul_epu32(r[2].v, packednineteen.v); + r1_2 = _mm_slli_epi32(r1, 1); + r3 = _mm_mul_epu32(r[3].v, packednineteen.v); + r4 = _mm_mul_epu32(r[4].v, packednineteen.v); + r3_2 = _mm_slli_epi32(r3, 1); + r5 = _mm_mul_epu32(r[5].v, packednineteen.v); + r6 = _mm_mul_epu32(r[6].v, packednineteen.v); + r5_2 = _mm_slli_epi32(r5, 1); + r7 = _mm_mul_epu32(r[7].v, packednineteen.v); + r8 = _mm_mul_epu32(r[8].v, packednineteen.v); + r7_2 = _mm_slli_epi32(r7, 1); + r9 = _mm_mul_epu32(r[9].v, packednineteen.v); + r9_2 = _mm_slli_epi32(r9, 1); + + out[0].v = _mm_add_epi64(out[0].v, _mm_add_epi64(_mm_mul_epu32(r9_2, s[1].v), _mm_add_epi64(_mm_mul_epu32(r8, s[2].v), _mm_add_epi64(_mm_mul_epu32(r7_2, s[3].v), _mm_add_epi64(_mm_mul_epu32(r6, s[4].v), _mm_add_epi64(_mm_mul_epu32(r5_2, s[5].v), _mm_add_epi64(_mm_mul_epu32(r4, s[6].v), _mm_add_epi64(_mm_mul_epu32(r3_2, s[7].v), _mm_add_epi64(_mm_mul_epu32(r2, s[8].v), _mm_mul_epu32(r1_2, s[9].v)))))))))); + out[1].v = _mm_add_epi64(out[1].v, _mm_add_epi64(_mm_mul_epu32(r9 , s[2].v), _mm_add_epi64(_mm_mul_epu32(r8, s[3].v), _mm_add_epi64(_mm_mul_epu32(r7 , s[4].v), _mm_add_epi64(_mm_mul_epu32(r6, s[5].v), _mm_add_epi64(_mm_mul_epu32(r5 , s[6].v), _mm_add_epi64(_mm_mul_epu32(r4, s[7].v), _mm_add_epi64(_mm_mul_epu32(r3 , s[8].v), _mm_mul_epu32(r2, s[9].v))))))))); + out[2].v = _mm_add_epi64(out[2].v, _mm_add_epi64(_mm_mul_epu32(r9_2, s[3].v), _mm_add_epi64(_mm_mul_epu32(r8, s[4].v), _mm_add_epi64(_mm_mul_epu32(r7_2, s[5].v), _mm_add_epi64(_mm_mul_epu32(r6, s[6].v), _mm_add_epi64(_mm_mul_epu32(r5_2, s[7].v), _mm_add_epi64(_mm_mul_epu32(r4, s[8].v), _mm_mul_epu32(r3_2, s[9].v)))))))); + out[3].v = _mm_add_epi64(out[3].v, _mm_add_epi64(_mm_mul_epu32(r9 , s[4].v), _mm_add_epi64(_mm_mul_epu32(r8, s[5].v), _mm_add_epi64(_mm_mul_epu32(r7 , s[6].v), _mm_add_epi64(_mm_mul_epu32(r6, s[7].v), _mm_add_epi64(_mm_mul_epu32(r5 , s[8].v), _mm_mul_epu32(r4, s[9].v))))))); + out[4].v = _mm_add_epi64(out[4].v, _mm_add_epi64(_mm_mul_epu32(r9_2, s[5].v), _mm_add_epi64(_mm_mul_epu32(r8, s[6].v), _mm_add_epi64(_mm_mul_epu32(r7_2, s[7].v), _mm_add_epi64(_mm_mul_epu32(r6, s[8].v), _mm_mul_epu32(r5_2, s[9].v)))))); + out[5].v = _mm_add_epi64(out[5].v, _mm_add_epi64(_mm_mul_epu32(r9 , s[6].v), _mm_add_epi64(_mm_mul_epu32(r8, s[7].v), _mm_add_epi64(_mm_mul_epu32(r7 , s[8].v), _mm_mul_epu32(r6, s[9].v))))); + out[6].v = _mm_add_epi64(out[6].v, _mm_add_epi64(_mm_mul_epu32(r9_2, s[7].v), _mm_add_epi64(_mm_mul_epu32(r8, s[8].v), _mm_mul_epu32(r7_2, s[9].v)))); + out[7].v = _mm_add_epi64(out[7].v, _mm_add_epi64(_mm_mul_epu32(r9 , s[8].v), _mm_mul_epu32(r8, s[9].v))); + out[8].v = _mm_add_epi64(out[8].v, _mm_mul_epu32(r9_2, s[9].v)); + + c1 = _mm_srli_epi64(out[0].v, 26); c2 = _mm_srli_epi64(out[4].v, 26); out[0].v = _mm_and_si128(out[0].v, packedmask26.v); out[4].v = _mm_and_si128(out[4].v, packedmask26.v); out[1].v = _mm_add_epi64(out[1].v, c1); out[5].v = _mm_add_epi64(out[5].v, c2); + c1 = _mm_srli_epi64(out[1].v, 25); c2 = _mm_srli_epi64(out[5].v, 25); out[1].v = _mm_and_si128(out[1].v, packedmask25.v); out[5].v = _mm_and_si128(out[5].v, packedmask25.v); out[2].v = _mm_add_epi64(out[2].v, c1); out[6].v = _mm_add_epi64(out[6].v, c2); + c1 = _mm_srli_epi64(out[2].v, 26); c2 = _mm_srli_epi64(out[6].v, 26); out[2].v = _mm_and_si128(out[2].v, packedmask26.v); out[6].v = _mm_and_si128(out[6].v, packedmask26.v); out[3].v = _mm_add_epi64(out[3].v, c1); out[7].v = _mm_add_epi64(out[7].v, c2); + c1 = _mm_srli_epi64(out[3].v, 25); c2 = _mm_srli_epi64(out[7].v, 25); out[3].v = _mm_and_si128(out[3].v, packedmask25.v); out[7].v = _mm_and_si128(out[7].v, packedmask25.v); out[4].v = _mm_add_epi64(out[4].v, c1); out[8].v = _mm_add_epi64(out[8].v, c2); + c2 = _mm_srli_epi64(out[8].v, 26); out[8].v = _mm_and_si128(out[8].v, packedmask26.v); out[9].v = _mm_add_epi64(out[9].v, c2); + c2 = _mm_srli_epi64(out[9].v, 25); out[9].v = _mm_and_si128(out[9].v, packedmask25.v); out[0].v = _mm_add_epi64(out[0].v, _mm_mul_epu32(c2, packednineteen.v)); + c1 = _mm_srli_epi64(out[0].v, 26); c2 = _mm_srli_epi64(out[4].v, 26); out[0].v = _mm_and_si128(out[0].v, packedmask26.v); out[4].v = _mm_and_si128(out[4].v, packedmask26.v); out[1].v = _mm_add_epi64(out[1].v, c1); out[5].v = _mm_add_epi64(out[5].v, c2); +} + +/* multiply a bignum */ +static void +curve25519_mul(bignum25519 out, const bignum25519 r, const bignum25519 s) { + xmmi m01,m23,m45,m67,m89; + xmmi m0123,m4567; + xmmi s0123,s4567; + xmmi s01,s23,s45,s67,s89; + xmmi s12,s34,s56,s78,s9; + xmmi r0,r2,r4,r6,r8; + xmmi r1,r3,r5,r7,r9; + xmmi r119,r219,r319,r419,r519,r619,r719,r819,r919; + xmmi c1,c2,c3; + + s0123 = _mm_load_si128((xmmi*)s + 0); + s01 = _mm_shuffle_epi32(s0123,_MM_SHUFFLE(3,1,2,0)); + s12 = _mm_shuffle_epi32(s0123, _MM_SHUFFLE(2,2,1,1)); + s23 = _mm_shuffle_epi32(s0123,_MM_SHUFFLE(3,3,2,2)); + s4567 = _mm_load_si128((xmmi*)s + 1); + s34 = _mm_unpacklo_epi64(_mm_srli_si128(s0123,12),s4567); + s45 = _mm_shuffle_epi32(s4567,_MM_SHUFFLE(3,1,2,0)); + s56 = _mm_shuffle_epi32(s4567, _MM_SHUFFLE(2,2,1,1)); + s67 = _mm_shuffle_epi32(s4567,_MM_SHUFFLE(3,3,2,2)); + s89 = _mm_load_si128((xmmi*)s + 2); + s78 = _mm_unpacklo_epi64(_mm_srli_si128(s4567,12),s89); + s89 = _mm_shuffle_epi32(s89,_MM_SHUFFLE(3,1,2,0)); + s9 = _mm_shuffle_epi32(s89, _MM_SHUFFLE(3,3,2,2)); + + r0 = _mm_load_si128((xmmi*)r + 0); + r1 = _mm_shuffle_epi32(r0, _MM_SHUFFLE(1,1,1,1)); + r1 = _mm_add_epi64(r1, _mm_and_si128(r1, sse2_top64bitmask.v)); + r2 = _mm_shuffle_epi32(r0, _MM_SHUFFLE(2,2,2,2)); + r3 = _mm_shuffle_epi32(r0, _MM_SHUFFLE(3,3,3,3)); + r3 = _mm_add_epi64(r3, _mm_and_si128(r3, sse2_top64bitmask.v)); + r0 = _mm_shuffle_epi32(r0, _MM_SHUFFLE(0,0,0,0)); + r4 = _mm_load_si128((xmmi*)r + 1); + r5 = _mm_shuffle_epi32(r4, _MM_SHUFFLE(1,1,1,1)); + r5 = _mm_add_epi64(r5, _mm_and_si128(r5, sse2_top64bitmask.v)); + r6 = _mm_shuffle_epi32(r4, _MM_SHUFFLE(2,2,2,2)); + r7 = _mm_shuffle_epi32(r4, _MM_SHUFFLE(3,3,3,3)); + r7 = _mm_add_epi64(r7, _mm_and_si128(r7, sse2_top64bitmask.v)); + r4 = _mm_shuffle_epi32(r4, _MM_SHUFFLE(0,0,0,0)); + r8 = _mm_load_si128((xmmi*)r + 2); + r9 = _mm_shuffle_epi32(r8, _MM_SHUFFLE(3,1,3,1)); + r9 = _mm_add_epi64(r9, _mm_and_si128(r9, sse2_top64bitmask.v)); + r8 = _mm_shuffle_epi32(r8, _MM_SHUFFLE(3,0,3,0)); + + m01 = _mm_mul_epu32(r1,s01); + m23 = _mm_mul_epu32(r1,s23); + m45 = _mm_mul_epu32(r1,s45); + m67 = _mm_mul_epu32(r1,s67); + m23 = _mm_add_epi64(m23,_mm_mul_epu32(r3,s01)); + m45 = _mm_add_epi64(m45,_mm_mul_epu32(r3,s23)); + m67 = _mm_add_epi64(m67,_mm_mul_epu32(r3,s45)); + m89 = _mm_mul_epu32(r1,s89); + m45 = _mm_add_epi64(m45,_mm_mul_epu32(r5,s01)); + m67 = _mm_add_epi64(m67,_mm_mul_epu32(r5,s23)); + m89 = _mm_add_epi64(m89,_mm_mul_epu32(r3,s67)); + m67 = _mm_add_epi64(m67,_mm_mul_epu32(r7,s01)); + m89 = _mm_add_epi64(m89,_mm_mul_epu32(r5,s45)); + m89 = _mm_add_epi64(m89,_mm_mul_epu32(r7,s23)); + m89 = _mm_add_epi64(m89,_mm_mul_epu32(r9,s01)); + + /* shift up */ + m89 = _mm_unpackhi_epi64(m67,_mm_slli_si128(m89,8)); + m67 = _mm_unpackhi_epi64(m45,_mm_slli_si128(m67,8)); + m45 = _mm_unpackhi_epi64(m23,_mm_slli_si128(m45,8)); + m23 = _mm_unpackhi_epi64(m01,_mm_slli_si128(m23,8)); + m01 = _mm_unpackhi_epi64(_mm_setzero_si128(),_mm_slli_si128(m01,8)); + + m01 = _mm_add_epi64(m01,_mm_mul_epu32(r0,s01)); + m23 = _mm_add_epi64(m23,_mm_mul_epu32(r0,s23)); + m45 = _mm_add_epi64(m45,_mm_mul_epu32(r0,s45)); + m67 = _mm_add_epi64(m67,_mm_mul_epu32(r0,s67)); + m23 = _mm_add_epi64(m23,_mm_mul_epu32(r2,s01)); + m45 = _mm_add_epi64(m45,_mm_mul_epu32(r2,s23)); + m67 = _mm_add_epi64(m67,_mm_mul_epu32(r4,s23)); + m89 = _mm_add_epi64(m89,_mm_mul_epu32(r0,s89)); + m45 = _mm_add_epi64(m45,_mm_mul_epu32(r4,s01)); + m67 = _mm_add_epi64(m67,_mm_mul_epu32(r2,s45)); + m89 = _mm_add_epi64(m89,_mm_mul_epu32(r2,s67)); + m67 = _mm_add_epi64(m67,_mm_mul_epu32(r6,s01)); + m89 = _mm_add_epi64(m89,_mm_mul_epu32(r4,s45)); + m89 = _mm_add_epi64(m89,_mm_mul_epu32(r6,s23)); + m89 = _mm_add_epi64(m89,_mm_mul_epu32(r8,s01)); + + r219 = _mm_mul_epu32(r2, packednineteen.v); + r419 = _mm_mul_epu32(r4, packednineteen.v); + r619 = _mm_mul_epu32(r6, packednineteen.v); + r819 = _mm_mul_epu32(r8, packednineteen.v); + r119 = _mm_shuffle_epi32(r1,_MM_SHUFFLE(0,0,2,2)); r119 = _mm_mul_epu32(r119, packednineteen.v); + r319 = _mm_shuffle_epi32(r3,_MM_SHUFFLE(0,0,2,2)); r319 = _mm_mul_epu32(r319, packednineteen.v); + r519 = _mm_shuffle_epi32(r5,_MM_SHUFFLE(0,0,2,2)); r519 = _mm_mul_epu32(r519, packednineteen.v); + r719 = _mm_shuffle_epi32(r7,_MM_SHUFFLE(0,0,2,2)); r719 = _mm_mul_epu32(r719, packednineteen.v); + r919 = _mm_shuffle_epi32(r9,_MM_SHUFFLE(0,0,2,2)); r919 = _mm_mul_epu32(r919, packednineteen.v); + + m01 = _mm_add_epi64(m01,_mm_mul_epu32(r919,s12)); + m23 = _mm_add_epi64(m23,_mm_mul_epu32(r919,s34)); + m45 = _mm_add_epi64(m45,_mm_mul_epu32(r919,s56)); + m67 = _mm_add_epi64(m67,_mm_mul_epu32(r919,s78)); + m01 = _mm_add_epi64(m01,_mm_mul_epu32(r719,s34)); + m23 = _mm_add_epi64(m23,_mm_mul_epu32(r719,s56)); + m45 = _mm_add_epi64(m45,_mm_mul_epu32(r719,s78)); + m67 = _mm_add_epi64(m67,_mm_mul_epu32(r719,s9)); + m01 = _mm_add_epi64(m01,_mm_mul_epu32(r519,s56)); + m23 = _mm_add_epi64(m23,_mm_mul_epu32(r519,s78)); + m45 = _mm_add_epi64(m45,_mm_mul_epu32(r519,s9)); + m67 = _mm_add_epi64(m67,_mm_mul_epu32(r819,s89)); + m01 = _mm_add_epi64(m01,_mm_mul_epu32(r319,s78)); + m23 = _mm_add_epi64(m23,_mm_mul_epu32(r319,s9)); + m45 = _mm_add_epi64(m45,_mm_mul_epu32(r619,s89)); + m89 = _mm_add_epi64(m89,_mm_mul_epu32(r919,s9)); + m01 = _mm_add_epi64(m01,_mm_mul_epu32(r819,s23)); + m23 = _mm_add_epi64(m23,_mm_mul_epu32(r819,s45)); + m45 = _mm_add_epi64(m45,_mm_mul_epu32(r819,s67)); + m01 = _mm_add_epi64(m01,_mm_mul_epu32(r619,s45)); + m23 = _mm_add_epi64(m23,_mm_mul_epu32(r619,s67)); + m01 = _mm_add_epi64(m01,_mm_mul_epu32(r419,s67)); + m23 = _mm_add_epi64(m23,_mm_mul_epu32(r419,s89)); + m01 = _mm_add_epi64(m01,_mm_mul_epu32(r219,s89)); + m01 = _mm_add_epi64(m01,_mm_mul_epu32(r119,s9)); + + r0 = _mm_unpacklo_epi64(m01, m45); + r1 = _mm_unpackhi_epi64(m01, m45); + r2 = _mm_unpacklo_epi64(m23, m67); + r3 = _mm_unpackhi_epi64(m23, m67); + r4 = _mm_unpacklo_epi64(m89, m89); + r5 = _mm_unpackhi_epi64(m89, m89); + + c1 = _mm_srli_epi64(r0, 26); c2 = _mm_srli_epi64(r2, 26); r0 = _mm_and_si128(r0, packedmask26.v); r2 = _mm_and_si128(r2, packedmask26.v); r1 = _mm_add_epi64(r1, c1); r3 = _mm_add_epi64(r3, c2); + c1 = _mm_srli_epi64(r1, 25); c2 = _mm_srli_epi64(r3, 25); r1 = _mm_and_si128(r1, packedmask25.v); r3 = _mm_and_si128(r3, packedmask25.v); r2 = _mm_add_epi64(r2, c1); r4 = _mm_add_epi64(r4, c2); c3 = _mm_slli_si128(c2, 8); + c1 = _mm_srli_epi64(r4, 26); r4 = _mm_and_si128(r4, packedmask26.v); r5 = _mm_add_epi64(r5, c1); + c1 = _mm_srli_epi64(r5, 25); r5 = _mm_and_si128(r5, packedmask25.v); r0 = _mm_add_epi64(r0, _mm_unpackhi_epi64(_mm_mul_epu32(c1, packednineteen.v), c3)); + c1 = _mm_srli_epi64(r0, 26); c2 = _mm_srli_epi64(r2, 26); r0 = _mm_and_si128(r0, packedmask26.v); r2 = _mm_and_si128(r2, packedmask26.v); r1 = _mm_add_epi64(r1, c1); r3 = _mm_add_epi64(r3, c2); + + m0123 = _mm_unpacklo_epi32(r0, r1); + m4567 = _mm_unpackhi_epi32(r0, r1); + m0123 = _mm_unpacklo_epi64(m0123, _mm_unpacklo_epi32(r2, r3)); + m4567 = _mm_unpacklo_epi64(m4567, _mm_unpackhi_epi32(r2, r3)); + m89 = _mm_unpackhi_epi32(r4, r5); + + _mm_store_si128((xmmi*)out + 0, m0123); + _mm_store_si128((xmmi*)out + 1, m4567); + _mm_store_si128((xmmi*)out + 2, m89); +} + +typedef struct bignum25519mulprecomp_t { + xmmi r0,r2,r4,r6,r8; + xmmi r1,r3,r5,r7,r9; + xmmi r119,r219,r319,r419,r519,r619,r719,r819,r919; +} bignum25519mulprecomp; + +/* precompute a constant to multiply by */ +DONNA_INLINE static void +curve25519_mul_precompute(bignum25519mulprecomp *pre, const bignum25519 r) { + pre->r0 = _mm_load_si128((xmmi*)r + 0); + pre->r1 = _mm_shuffle_epi32(pre->r0, _MM_SHUFFLE(1,1,1,1)); + pre->r1 = _mm_add_epi64(pre->r1, _mm_and_si128(pre->r1, sse2_top64bitmask.v)); + pre->r2 = _mm_shuffle_epi32(pre->r0, _MM_SHUFFLE(2,2,2,2)); + pre->r3 = _mm_shuffle_epi32(pre->r0, _MM_SHUFFLE(3,3,3,3)); + pre->r3 = _mm_add_epi64(pre->r3, _mm_and_si128(pre->r3, sse2_top64bitmask.v)); + pre->r0 = _mm_shuffle_epi32(pre->r0, _MM_SHUFFLE(0,0,0,0)); + pre->r4 = _mm_load_si128((xmmi*)r + 1); + pre->r5 = _mm_shuffle_epi32(pre->r4, _MM_SHUFFLE(1,1,1,1)); + pre->r5 = _mm_add_epi64(pre->r5, _mm_and_si128(pre->r5, sse2_top64bitmask.v)); + pre->r6 = _mm_shuffle_epi32(pre->r4, _MM_SHUFFLE(2,2,2,2)); + pre->r7 = _mm_shuffle_epi32(pre->r4, _MM_SHUFFLE(3,3,3,3)); + pre->r7 = _mm_add_epi64(pre->r7, _mm_and_si128(pre->r7, sse2_top64bitmask.v)); + pre->r4 = _mm_shuffle_epi32(pre->r4, _MM_SHUFFLE(0,0,0,0)); + pre->r8 = _mm_load_si128((xmmi*)r + 2); + pre->r9 = _mm_shuffle_epi32(pre->r8, _MM_SHUFFLE(3,1,3,1)); + pre->r9 = _mm_add_epi64(pre->r9, _mm_and_si128(pre->r9, sse2_top64bitmask.v)); + pre->r8 = _mm_shuffle_epi32(pre->r8, _MM_SHUFFLE(3,0,3,0)); + + pre->r219 = _mm_mul_epu32(pre->r2, packednineteen.v); + pre->r419 = _mm_mul_epu32(pre->r4, packednineteen.v); + pre->r619 = _mm_mul_epu32(pre->r6, packednineteen.v); + pre->r819 = _mm_mul_epu32(pre->r8, packednineteen.v); + pre->r119 = _mm_shuffle_epi32(pre->r1,_MM_SHUFFLE(0,0,2,2)); pre->r119 = _mm_mul_epu32(pre->r119, packednineteen.v); + pre->r319 = _mm_shuffle_epi32(pre->r3,_MM_SHUFFLE(0,0,2,2)); pre->r319 = _mm_mul_epu32(pre->r319, packednineteen.v); + pre->r519 = _mm_shuffle_epi32(pre->r5,_MM_SHUFFLE(0,0,2,2)); pre->r519 = _mm_mul_epu32(pre->r519, packednineteen.v); + pre->r719 = _mm_shuffle_epi32(pre->r7,_MM_SHUFFLE(0,0,2,2)); pre->r719 = _mm_mul_epu32(pre->r719, packednineteen.v); + pre->r919 = _mm_shuffle_epi32(pre->r9,_MM_SHUFFLE(0,0,2,2)); pre->r919 = _mm_mul_epu32(pre->r919, packednineteen.v); +} + + +/* multiply a bignum by a pre-computed constant */ +DONNA_INLINE static void +curve25519_mul_precomputed(bignum25519 out, const bignum25519 s, const bignum25519mulprecomp *r) { + xmmi m01,m23,m45,m67,m89; + xmmi m0123,m4567; + xmmi s0123,s4567; + xmmi s01,s23,s45,s67,s89; + xmmi s12,s34,s56,s78,s9; + xmmi r0,r1,r2,r3,r4,r5; + xmmi c1,c2,c3; + + s0123 = _mm_load_si128((xmmi*)s + 0); + s01 = _mm_shuffle_epi32(s0123,_MM_SHUFFLE(3,1,2,0)); + s12 = _mm_shuffle_epi32(s0123, _MM_SHUFFLE(2,2,1,1)); + s23 = _mm_shuffle_epi32(s0123,_MM_SHUFFLE(3,3,2,2)); + s4567 = _mm_load_si128((xmmi*)s + 1); + s34 = _mm_unpacklo_epi64(_mm_srli_si128(s0123,12),s4567); + s45 = _mm_shuffle_epi32(s4567,_MM_SHUFFLE(3,1,2,0)); + s56 = _mm_shuffle_epi32(s4567, _MM_SHUFFLE(2,2,1,1)); + s67 = _mm_shuffle_epi32(s4567,_MM_SHUFFLE(3,3,2,2)); + s89 = _mm_load_si128((xmmi*)s + 2); + s78 = _mm_unpacklo_epi64(_mm_srli_si128(s4567,12),s89); + s89 = _mm_shuffle_epi32(s89,_MM_SHUFFLE(3,1,2,0)); + s9 = _mm_shuffle_epi32(s89, _MM_SHUFFLE(3,3,2,2)); + + m01 = _mm_mul_epu32(r->r1,s01); + m23 = _mm_mul_epu32(r->r1,s23); + m45 = _mm_mul_epu32(r->r1,s45); + m67 = _mm_mul_epu32(r->r1,s67); + m23 = _mm_add_epi64(m23,_mm_mul_epu32(r->r3,s01)); + m45 = _mm_add_epi64(m45,_mm_mul_epu32(r->r3,s23)); + m67 = _mm_add_epi64(m67,_mm_mul_epu32(r->r3,s45)); + m89 = _mm_mul_epu32(r->r1,s89); + m45 = _mm_add_epi64(m45,_mm_mul_epu32(r->r5,s01)); + m67 = _mm_add_epi64(m67,_mm_mul_epu32(r->r5,s23)); + m89 = _mm_add_epi64(m89,_mm_mul_epu32(r->r3,s67)); + m67 = _mm_add_epi64(m67,_mm_mul_epu32(r->r7,s01)); + m89 = _mm_add_epi64(m89,_mm_mul_epu32(r->r5,s45)); + m89 = _mm_add_epi64(m89,_mm_mul_epu32(r->r7,s23)); + m89 = _mm_add_epi64(m89,_mm_mul_epu32(r->r9,s01)); + + /* shift up */ + m89 = _mm_unpackhi_epi64(m67,_mm_slli_si128(m89,8)); + m67 = _mm_unpackhi_epi64(m45,_mm_slli_si128(m67,8)); + m45 = _mm_unpackhi_epi64(m23,_mm_slli_si128(m45,8)); + m23 = _mm_unpackhi_epi64(m01,_mm_slli_si128(m23,8)); + m01 = _mm_unpackhi_epi64(_mm_setzero_si128(),_mm_slli_si128(m01,8)); + + m01 = _mm_add_epi64(m01,_mm_mul_epu32(r->r0,s01)); + m23 = _mm_add_epi64(m23,_mm_mul_epu32(r->r0,s23)); + m45 = _mm_add_epi64(m45,_mm_mul_epu32(r->r0,s45)); + m67 = _mm_add_epi64(m67,_mm_mul_epu32(r->r0,s67)); + m23 = _mm_add_epi64(m23,_mm_mul_epu32(r->r2,s01)); + m45 = _mm_add_epi64(m45,_mm_mul_epu32(r->r2,s23)); + m67 = _mm_add_epi64(m67,_mm_mul_epu32(r->r4,s23)); + m89 = _mm_add_epi64(m89,_mm_mul_epu32(r->r0,s89)); + m45 = _mm_add_epi64(m45,_mm_mul_epu32(r->r4,s01)); + m67 = _mm_add_epi64(m67,_mm_mul_epu32(r->r2,s45)); + m89 = _mm_add_epi64(m89,_mm_mul_epu32(r->r2,s67)); + m67 = _mm_add_epi64(m67,_mm_mul_epu32(r->r6,s01)); + m89 = _mm_add_epi64(m89,_mm_mul_epu32(r->r4,s45)); + m89 = _mm_add_epi64(m89,_mm_mul_epu32(r->r6,s23)); + m89 = _mm_add_epi64(m89,_mm_mul_epu32(r->r8,s01)); + m01 = _mm_add_epi64(m01,_mm_mul_epu32(r->r919,s12)); + m23 = _mm_add_epi64(m23,_mm_mul_epu32(r->r919,s34)); + m45 = _mm_add_epi64(m45,_mm_mul_epu32(r->r919,s56)); + m67 = _mm_add_epi64(m67,_mm_mul_epu32(r->r919,s78)); + m01 = _mm_add_epi64(m01,_mm_mul_epu32(r->r719,s34)); + m23 = _mm_add_epi64(m23,_mm_mul_epu32(r->r719,s56)); + m45 = _mm_add_epi64(m45,_mm_mul_epu32(r->r719,s78)); + m67 = _mm_add_epi64(m67,_mm_mul_epu32(r->r719,s9)); + m01 = _mm_add_epi64(m01,_mm_mul_epu32(r->r519,s56)); + m23 = _mm_add_epi64(m23,_mm_mul_epu32(r->r519,s78)); + m45 = _mm_add_epi64(m45,_mm_mul_epu32(r->r519,s9)); + m67 = _mm_add_epi64(m67,_mm_mul_epu32(r->r819,s89)); + m01 = _mm_add_epi64(m01,_mm_mul_epu32(r->r319,s78)); + m23 = _mm_add_epi64(m23,_mm_mul_epu32(r->r319,s9)); + m45 = _mm_add_epi64(m45,_mm_mul_epu32(r->r619,s89)); + m89 = _mm_add_epi64(m89,_mm_mul_epu32(r->r919,s9)); + m01 = _mm_add_epi64(m01,_mm_mul_epu32(r->r819,s23)); + m23 = _mm_add_epi64(m23,_mm_mul_epu32(r->r819,s45)); + m45 = _mm_add_epi64(m45,_mm_mul_epu32(r->r819,s67)); + m01 = _mm_add_epi64(m01,_mm_mul_epu32(r->r619,s45)); + m23 = _mm_add_epi64(m23,_mm_mul_epu32(r->r619,s67)); + m01 = _mm_add_epi64(m01,_mm_mul_epu32(r->r419,s67)); + m23 = _mm_add_epi64(m23,_mm_mul_epu32(r->r419,s89)); + m01 = _mm_add_epi64(m01,_mm_mul_epu32(r->r219,s89)); + m01 = _mm_add_epi64(m01,_mm_mul_epu32(r->r119,s9)); + + r0 = _mm_unpacklo_epi64(m01, m45); + r1 = _mm_unpackhi_epi64(m01, m45); + r2 = _mm_unpacklo_epi64(m23, m67); + r3 = _mm_unpackhi_epi64(m23, m67); + r4 = _mm_unpacklo_epi64(m89, m89); + r5 = _mm_unpackhi_epi64(m89, m89); + + c1 = _mm_srli_epi64(r0, 26); c2 = _mm_srli_epi64(r2, 26); r0 = _mm_and_si128(r0, packedmask26.v); r2 = _mm_and_si128(r2, packedmask26.v); r1 = _mm_add_epi64(r1, c1); r3 = _mm_add_epi64(r3, c2); + c1 = _mm_srli_epi64(r1, 25); c2 = _mm_srli_epi64(r3, 25); r1 = _mm_and_si128(r1, packedmask25.v); r3 = _mm_and_si128(r3, packedmask25.v); r2 = _mm_add_epi64(r2, c1); r4 = _mm_add_epi64(r4, c2); c3 = _mm_slli_si128(c2, 8); + c1 = _mm_srli_epi64(r4, 26); r4 = _mm_and_si128(r4, packedmask26.v); r5 = _mm_add_epi64(r5, c1); + c1 = _mm_srli_epi64(r5, 25); r5 = _mm_and_si128(r5, packedmask25.v); r0 = _mm_add_epi64(r0, _mm_unpackhi_epi64(_mm_mul_epu32(c1, packednineteen.v), c3)); + c1 = _mm_srli_epi64(r0, 26); c2 = _mm_srli_epi64(r2, 26); r0 = _mm_and_si128(r0, packedmask26.v); r2 = _mm_and_si128(r2, packedmask26.v); r1 = _mm_add_epi64(r1, c1); r3 = _mm_add_epi64(r3, c2); + + m0123 = _mm_unpacklo_epi32(r0, r1); + m4567 = _mm_unpackhi_epi32(r0, r1); + m0123 = _mm_unpacklo_epi64(m0123, _mm_unpacklo_epi32(r2, r3)); + m4567 = _mm_unpacklo_epi64(m4567, _mm_unpackhi_epi32(r2, r3)); + m89 = _mm_unpackhi_epi32(r4, r5); + + _mm_store_si128((xmmi*)out + 0, m0123); + _mm_store_si128((xmmi*)out + 1, m4567); + _mm_store_si128((xmmi*)out + 2, m89); +} + +/* square a bignum 'count' times */ +#define curve25519_square(r,x) curve25519_square_times(r,x,1) + +static void +curve25519_square_times(bignum25519 r, const bignum25519 in, int count) { + xmmi m01,m23,m45,m67,m89; + xmmi r0,r1,r2,r3,r4,r5,r6,r7,r8,r9; + xmmi r0a,r1a,r2a,r3a,r7a,r9a; + xmmi r0123,r4567; + xmmi r01,r23,r45,r67,r6x,r89,r8x; + xmmi r12,r34,r56,r78,r9x; + xmmi r5619; + xmmi c1,c2,c3; + + r0123 = _mm_load_si128((xmmi*)in + 0); + r01 = _mm_shuffle_epi32(r0123,_MM_SHUFFLE(3,1,2,0)); + r23 = _mm_shuffle_epi32(r0123,_MM_SHUFFLE(3,3,2,2)); + r4567 = _mm_load_si128((xmmi*)in + 1); + r45 = _mm_shuffle_epi32(r4567,_MM_SHUFFLE(3,1,2,0)); + r67 = _mm_shuffle_epi32(r4567,_MM_SHUFFLE(3,3,2,2)); + r89 = _mm_load_si128((xmmi*)in + 2); + r89 = _mm_shuffle_epi32(r89,_MM_SHUFFLE(3,1,2,0)); + + do { + r12 = _mm_unpackhi_epi64(r01, _mm_slli_si128(r23, 8)); + r0 = _mm_shuffle_epi32(r01, _MM_SHUFFLE(0,0,0,0)); + r0 = _mm_add_epi64(r0, _mm_and_si128(r0, sse2_top64bitmask.v)); + r0a = _mm_shuffle_epi32(r0,_MM_SHUFFLE(3,2,1,2)); + r1 = _mm_shuffle_epi32(r01, _MM_SHUFFLE(2,2,2,2)); + r2 = _mm_shuffle_epi32(r23, _MM_SHUFFLE(0,0,0,0)); + r2 = _mm_add_epi64(r2, _mm_and_si128(r2, sse2_top64bitmask.v)); + r2a = _mm_shuffle_epi32(r2,_MM_SHUFFLE(3,2,1,2)); + r3 = _mm_shuffle_epi32(r23, _MM_SHUFFLE(2,2,2,2)); + r34 = _mm_unpackhi_epi64(r23, _mm_slli_si128(r45, 8)); + r4 = _mm_shuffle_epi32(r45, _MM_SHUFFLE(0,0,0,0)); + r4 = _mm_add_epi64(r4, _mm_and_si128(r4, sse2_top64bitmask.v)); + r56 = _mm_unpackhi_epi64(r45, _mm_slli_si128(r67, 8)); + r5619 = _mm_mul_epu32(r56, packednineteen.v); + r5 = _mm_shuffle_epi32(r5619, _MM_SHUFFLE(1,1,1,0)); + r6 = _mm_shuffle_epi32(r5619, _MM_SHUFFLE(3,2,3,2)); + r78 = _mm_unpackhi_epi64(r67, _mm_slli_si128(r89, 8)); + r6x = _mm_unpacklo_epi64(r67, _mm_setzero_si128()); + r7 = _mm_shuffle_epi32(r67, _MM_SHUFFLE(2,2,2,2)); + r7 = _mm_mul_epu32(r7, packed3819.v); + r7a = _mm_shuffle_epi32(r7, _MM_SHUFFLE(3,3,3,2)); + r8x = _mm_unpacklo_epi64(r89, _mm_setzero_si128()); + r8 = _mm_shuffle_epi32(r89, _MM_SHUFFLE(0,0,0,0)); + r8 = _mm_mul_epu32(r8, packednineteen.v); + r9 = _mm_shuffle_epi32(r89, _MM_SHUFFLE(2,2,2,2)); + r9x = _mm_slli_epi32(_mm_shuffle_epi32(r89, _MM_SHUFFLE(3,3,3,2)), 1); + r9 = _mm_mul_epu32(r9, packed3819.v); + r9a = _mm_shuffle_epi32(r9, _MM_SHUFFLE(2,2,2,2)); + + m01 = _mm_mul_epu32(r01, r0); + m23 = _mm_mul_epu32(r23, r0a); + m45 = _mm_mul_epu32(r45, r0a); + m45 = _mm_add_epi64(m45, _mm_mul_epu32(r23, r2)); + r23 = _mm_slli_epi32(r23, 1); + m67 = _mm_mul_epu32(r67, r0a); + m67 = _mm_add_epi64(m67, _mm_mul_epu32(r45, r2a)); + m89 = _mm_mul_epu32(r89, r0a); + m89 = _mm_add_epi64(m89, _mm_mul_epu32(r67, r2a)); + r67 = _mm_slli_epi32(r67, 1); + m89 = _mm_add_epi64(m89, _mm_mul_epu32(r45, r4)); + r45 = _mm_slli_epi32(r45, 1); + + r1 = _mm_slli_epi32(r1, 1); + r3 = _mm_slli_epi32(r3, 1); + r1a = _mm_add_epi64(r1, _mm_and_si128(r1, sse2_bot64bitmask.v)); + r3a = _mm_add_epi64(r3, _mm_and_si128(r3, sse2_bot64bitmask.v)); + + m23 = _mm_add_epi64(m23, _mm_mul_epu32(r12, r1)); + m45 = _mm_add_epi64(m45, _mm_mul_epu32(r34, r1a)); + m67 = _mm_add_epi64(m67, _mm_mul_epu32(r56, r1a)); + m67 = _mm_add_epi64(m67, _mm_mul_epu32(r34, r3)); + r34 = _mm_slli_epi32(r34, 1); + m89 = _mm_add_epi64(m89, _mm_mul_epu32(r78, r1a)); + r78 = _mm_slli_epi32(r78, 1); + m89 = _mm_add_epi64(m89, _mm_mul_epu32(r56, r3a)); + r56 = _mm_slli_epi32(r56, 1); + + m01 = _mm_add_epi64(m01, _mm_mul_epu32(_mm_slli_epi32(r12, 1), r9)); + m01 = _mm_add_epi64(m01, _mm_mul_epu32(r34, r7)); + m23 = _mm_add_epi64(m23, _mm_mul_epu32(r34, r9)); + m01 = _mm_add_epi64(m01, _mm_mul_epu32(r56, r5)); + m23 = _mm_add_epi64(m23, _mm_mul_epu32(r56, r7)); + m45 = _mm_add_epi64(m45, _mm_mul_epu32(r56, r9)); + m01 = _mm_add_epi64(m01, _mm_mul_epu32(r23, r8)); + m01 = _mm_add_epi64(m01, _mm_mul_epu32(r45, r6)); + m23 = _mm_add_epi64(m23, _mm_mul_epu32(r45, r8)); + m23 = _mm_add_epi64(m23, _mm_mul_epu32(r6x, r6)); + m45 = _mm_add_epi64(m45, _mm_mul_epu32(r78, r7a)); + m67 = _mm_add_epi64(m67, _mm_mul_epu32(r78, r9)); + m45 = _mm_add_epi64(m45, _mm_mul_epu32(r67, r8)); + m67 = _mm_add_epi64(m67, _mm_mul_epu32(r8x, r8)); + m89 = _mm_add_epi64(m89, _mm_mul_epu32(r9x, r9a)); + + r0 = _mm_unpacklo_epi64(m01, m45); + r1 = _mm_unpackhi_epi64(m01, m45); + r2 = _mm_unpacklo_epi64(m23, m67); + r3 = _mm_unpackhi_epi64(m23, m67); + r4 = _mm_unpacklo_epi64(m89, m89); + r5 = _mm_unpackhi_epi64(m89, m89); + + c1 = _mm_srli_epi64(r0, 26); c2 = _mm_srli_epi64(r2, 26); r0 = _mm_and_si128(r0, packedmask26.v); r2 = _mm_and_si128(r2, packedmask26.v); r1 = _mm_add_epi64(r1, c1); r3 = _mm_add_epi64(r3, c2); + c1 = _mm_srli_epi64(r1, 25); c2 = _mm_srli_epi64(r3, 25); r1 = _mm_and_si128(r1, packedmask25.v); r3 = _mm_and_si128(r3, packedmask25.v); r2 = _mm_add_epi64(r2, c1); r4 = _mm_add_epi64(r4, c2); c3 = _mm_slli_si128(c2, 8); + c1 = _mm_srli_epi64(r4, 26); r4 = _mm_and_si128(r4, packedmask26.v); r5 = _mm_add_epi64(r5, c1); + c1 = _mm_srli_epi64(r5, 25); r5 = _mm_and_si128(r5, packedmask25.v); r0 = _mm_add_epi64(r0, _mm_unpackhi_epi64(_mm_mul_epu32(c1, packednineteen.v), c3)); + c1 = _mm_srli_epi64(r0, 26); c2 = _mm_srli_epi64(r2, 26); r0 = _mm_and_si128(r0, packedmask26.v); r2 = _mm_and_si128(r2, packedmask26.v); r1 = _mm_add_epi64(r1, c1); r3 = _mm_add_epi64(r3, c2); + + r01 = _mm_unpacklo_epi64(r0, r1); + r45 = _mm_unpackhi_epi64(r0, r1); + r23 = _mm_unpacklo_epi64(r2, r3); + r67 = _mm_unpackhi_epi64(r2, r3); + r89 = _mm_unpackhi_epi64(r4, r5); + } while (--count); + + r0123 = _mm_shuffle_epi32(r23, _MM_SHUFFLE(2,0,3,3)); + r4567 = _mm_shuffle_epi32(r67, _MM_SHUFFLE(2,0,3,3)); + r0123 = _mm_or_si128(r0123, _mm_shuffle_epi32(r01, _MM_SHUFFLE(3,3,2,0))); + r4567 = _mm_or_si128(r4567, _mm_shuffle_epi32(r45, _MM_SHUFFLE(3,3,2,0))); + r89 = _mm_shuffle_epi32(r89, _MM_SHUFFLE(3,3,2,0)); + + _mm_store_si128((xmmi*)r + 0, r0123); + _mm_store_si128((xmmi*)r + 1, r4567); + _mm_store_si128((xmmi*)r + 2, r89); +} + +/* square two packed bignums */ +DONNA_INLINE static void +curve25519_square_packed64(packedelem64 *out, const packedelem64 *r) { + xmmi r0,r1,r2,r3; + xmmi r1_2,r3_2,r4_2,r5_2,r6_2,r7_2; + xmmi d5,d6,d7,d8,d9; + xmmi c1,c2; + + r0 = r[0].v; + r1 = r[1].v; + r2 = r[2].v; + r3 = r[3].v; + + out[0].v = _mm_mul_epu32(r0, r0); + r0 = _mm_slli_epi32(r0, 1); + out[1].v = _mm_mul_epu32(r0, r1); + r1_2 = _mm_slli_epi32(r1, 1); + out[2].v = _mm_add_epi64(_mm_mul_epu32(r0, r2 ), _mm_mul_epu32(r1, r1_2)); + r1 = r1_2; + out[3].v = _mm_add_epi64(_mm_mul_epu32(r0, r3 ), _mm_mul_epu32(r1, r2 )); + r3_2 = _mm_slli_epi32(r3, 1); + out[4].v = _mm_add_epi64(_mm_mul_epu32(r0, r[4].v), _mm_add_epi64(_mm_mul_epu32(r1, r3_2 ), _mm_mul_epu32(r2, r2))); + r2 = _mm_slli_epi32(r2, 1); + out[5].v = _mm_add_epi64(_mm_mul_epu32(r0, r[5].v), _mm_add_epi64(_mm_mul_epu32(r1, r[4].v), _mm_mul_epu32(r2, r3))); + r5_2 = _mm_slli_epi32(r[5].v, 1); + out[6].v = _mm_add_epi64(_mm_mul_epu32(r0, r[6].v), _mm_add_epi64(_mm_mul_epu32(r1, r5_2 ), _mm_add_epi64(_mm_mul_epu32(r2, r[4].v), _mm_mul_epu32(r3, r3_2 )))); + r3 = r3_2; + out[7].v = _mm_add_epi64(_mm_mul_epu32(r0, r[7].v), _mm_add_epi64(_mm_mul_epu32(r1, r[6].v), _mm_add_epi64(_mm_mul_epu32(r2, r[5].v), _mm_mul_epu32(r3, r[4].v)))); + r7_2 = _mm_slli_epi32(r[7].v, 1); + out[8].v = _mm_add_epi64(_mm_mul_epu32(r0, r[8].v), _mm_add_epi64(_mm_mul_epu32(r1, r7_2 ), _mm_add_epi64(_mm_mul_epu32(r2, r[6].v), _mm_add_epi64(_mm_mul_epu32(r3, r5_2 ), _mm_mul_epu32(r[4].v, r[4].v))))); + out[9].v = _mm_add_epi64(_mm_mul_epu32(r0, r[9].v), _mm_add_epi64(_mm_mul_epu32(r1, r[8].v), _mm_add_epi64(_mm_mul_epu32(r2, r[7].v), _mm_add_epi64(_mm_mul_epu32(r3, r[6].v), _mm_mul_epu32(r[4].v, r5_2 ))))); + + d5 = _mm_mul_epu32(r[5].v, packedthirtyeight.v); + d6 = _mm_mul_epu32(r[6].v, packednineteen.v); + d7 = _mm_mul_epu32(r[7].v, packedthirtyeight.v); + d8 = _mm_mul_epu32(r[8].v, packednineteen.v); + d9 = _mm_mul_epu32(r[9].v, packedthirtyeight.v); + + r4_2 = _mm_slli_epi32(r[4].v, 1); + r6_2 = _mm_slli_epi32(r[6].v, 1); + out[0].v = _mm_add_epi64(out[0].v, _mm_add_epi64(_mm_mul_epu32(d9, r1 ), _mm_add_epi64(_mm_mul_epu32(d8, r2 ), _mm_add_epi64(_mm_mul_epu32(d7, r3 ), _mm_add_epi64(_mm_mul_epu32(d6, r4_2), _mm_mul_epu32(d5, r[5].v)))))); + out[1].v = _mm_add_epi64(out[1].v, _mm_add_epi64(_mm_mul_epu32(d9, _mm_srli_epi32(r2, 1)), _mm_add_epi64(_mm_mul_epu32(d8, r3 ), _mm_add_epi64(_mm_mul_epu32(d7, r[4].v), _mm_mul_epu32(d6, r5_2 ))))); + out[2].v = _mm_add_epi64(out[2].v, _mm_add_epi64(_mm_mul_epu32(d9, r3 ), _mm_add_epi64(_mm_mul_epu32(d8, r4_2), _mm_add_epi64(_mm_mul_epu32(d7, r5_2 ), _mm_mul_epu32(d6, r[6].v))))); + out[3].v = _mm_add_epi64(out[3].v, _mm_add_epi64(_mm_mul_epu32(d9, r[4].v ), _mm_add_epi64(_mm_mul_epu32(d8, r5_2), _mm_mul_epu32(d7, r[6].v)))); + out[4].v = _mm_add_epi64(out[4].v, _mm_add_epi64(_mm_mul_epu32(d9, r5_2 ), _mm_add_epi64(_mm_mul_epu32(d8, r6_2), _mm_mul_epu32(d7, r[7].v)))); + out[5].v = _mm_add_epi64(out[5].v, _mm_add_epi64(_mm_mul_epu32(d9, r[6].v ), _mm_mul_epu32(d8, r7_2 ))); + out[6].v = _mm_add_epi64(out[6].v, _mm_add_epi64(_mm_mul_epu32(d9, r7_2 ), _mm_mul_epu32(d8, r[8].v))); + out[7].v = _mm_add_epi64(out[7].v, _mm_mul_epu32(d9, r[8].v)); + out[8].v = _mm_add_epi64(out[8].v, _mm_mul_epu32(d9, r[9].v)); + + c1 = _mm_srli_epi64(out[0].v, 26); c2 = _mm_srli_epi64(out[4].v, 26); out[0].v = _mm_and_si128(out[0].v, packedmask26.v); out[4].v = _mm_and_si128(out[4].v, packedmask26.v); out[1].v = _mm_add_epi64(out[1].v, c1); out[5].v = _mm_add_epi64(out[5].v, c2); + c1 = _mm_srli_epi64(out[1].v, 25); c2 = _mm_srli_epi64(out[5].v, 25); out[1].v = _mm_and_si128(out[1].v, packedmask25.v); out[5].v = _mm_and_si128(out[5].v, packedmask25.v); out[2].v = _mm_add_epi64(out[2].v, c1); out[6].v = _mm_add_epi64(out[6].v, c2); + c1 = _mm_srli_epi64(out[2].v, 26); c2 = _mm_srli_epi64(out[6].v, 26); out[2].v = _mm_and_si128(out[2].v, packedmask26.v); out[6].v = _mm_and_si128(out[6].v, packedmask26.v); out[3].v = _mm_add_epi64(out[3].v, c1); out[7].v = _mm_add_epi64(out[7].v, c2); + c1 = _mm_srli_epi64(out[3].v, 25); c2 = _mm_srli_epi64(out[7].v, 25); out[3].v = _mm_and_si128(out[3].v, packedmask25.v); out[7].v = _mm_and_si128(out[7].v, packedmask25.v); out[4].v = _mm_add_epi64(out[4].v, c1); out[8].v = _mm_add_epi64(out[8].v, c2); + c2 = _mm_srli_epi64(out[8].v, 26); out[8].v = _mm_and_si128(out[8].v, packedmask26.v); out[9].v = _mm_add_epi64(out[9].v, c2); + c2 = _mm_srli_epi64(out[9].v, 25); out[9].v = _mm_and_si128(out[9].v, packedmask25.v); out[0].v = _mm_add_epi64(out[0].v, _mm_mul_epu32(c2, packednineteen.v)); + c1 = _mm_srli_epi64(out[0].v, 26); c2 = _mm_srli_epi64(out[4].v, 26); out[0].v = _mm_and_si128(out[0].v, packedmask26.v); out[4].v = _mm_and_si128(out[4].v, packedmask26.v); out[1].v = _mm_add_epi64(out[1].v, c1); out[5].v = _mm_add_epi64(out[5].v, c2); +} + +/* make [nqx+nqz,nqpqx+nqpqz], [nqpqx-nqpqz,nqx-nqz] from [nqx+nqz,nqpqx+nqpqz], [nqx-nqz,nqpqx-nqpqz] */ +DONNA_INLINE static void +curve25519_make_nqpq(packedelem64 *primex, packedelem64 *primez, const packedelem32 *pqx, const packedelem32 *pqz) { + primex[0].v = _mm_shuffle_epi32(pqx[0].v, _MM_SHUFFLE(1,1,0,0)); + primex[1].v = _mm_shuffle_epi32(pqx[0].v, _MM_SHUFFLE(3,3,2,2)); + primex[2].v = _mm_shuffle_epi32(pqx[1].v, _MM_SHUFFLE(1,1,0,0)); + primex[3].v = _mm_shuffle_epi32(pqx[1].v, _MM_SHUFFLE(3,3,2,2)); + primex[4].v = _mm_shuffle_epi32(pqx[2].v, _MM_SHUFFLE(1,1,0,0)); + primex[5].v = _mm_shuffle_epi32(pqx[2].v, _MM_SHUFFLE(3,3,2,2)); + primex[6].v = _mm_shuffle_epi32(pqx[3].v, _MM_SHUFFLE(1,1,0,0)); + primex[7].v = _mm_shuffle_epi32(pqx[3].v, _MM_SHUFFLE(3,3,2,2)); + primex[8].v = _mm_shuffle_epi32(pqx[4].v, _MM_SHUFFLE(1,1,0,0)); + primex[9].v = _mm_shuffle_epi32(pqx[4].v, _MM_SHUFFLE(3,3,2,2)); + primez[0].v = _mm_shuffle_epi32(pqz[0].v, _MM_SHUFFLE(0,0,1,1)); + primez[1].v = _mm_shuffle_epi32(pqz[0].v, _MM_SHUFFLE(2,2,3,3)); + primez[2].v = _mm_shuffle_epi32(pqz[1].v, _MM_SHUFFLE(0,0,1,1)); + primez[3].v = _mm_shuffle_epi32(pqz[1].v, _MM_SHUFFLE(2,2,3,3)); + primez[4].v = _mm_shuffle_epi32(pqz[2].v, _MM_SHUFFLE(0,0,1,1)); + primez[5].v = _mm_shuffle_epi32(pqz[2].v, _MM_SHUFFLE(2,2,3,3)); + primez[6].v = _mm_shuffle_epi32(pqz[3].v, _MM_SHUFFLE(0,0,1,1)); + primez[7].v = _mm_shuffle_epi32(pqz[3].v, _MM_SHUFFLE(2,2,3,3)); + primez[8].v = _mm_shuffle_epi32(pqz[4].v, _MM_SHUFFLE(0,0,1,1)); + primez[9].v = _mm_shuffle_epi32(pqz[4].v, _MM_SHUFFLE(2,2,3,3)); +} + +/* make [nqx+nqz,nqx-nqz] from [nqx+nqz,nqpqx+nqpqz], [nqx-nqz,nqpqx-nqpqz] */ +DONNA_INLINE static void +curve25519_make_nq(packedelem64 *nq, const packedelem32 *pqx, const packedelem32 *pqz) { + nq[0].v = _mm_unpacklo_epi64(pqx[0].v, pqz[0].v); + nq[1].v = _mm_unpackhi_epi64(pqx[0].v, pqz[0].v); + nq[2].v = _mm_unpacklo_epi64(pqx[1].v, pqz[1].v); + nq[3].v = _mm_unpackhi_epi64(pqx[1].v, pqz[1].v); + nq[4].v = _mm_unpacklo_epi64(pqx[2].v, pqz[2].v); + nq[5].v = _mm_unpackhi_epi64(pqx[2].v, pqz[2].v); + nq[6].v = _mm_unpacklo_epi64(pqx[3].v, pqz[3].v); + nq[7].v = _mm_unpackhi_epi64(pqx[3].v, pqz[3].v); + nq[8].v = _mm_unpacklo_epi64(pqx[4].v, pqz[4].v); + nq[9].v = _mm_unpackhi_epi64(pqx[4].v, pqz[4].v); +} + +/* compute [nqx+nqz,nqx-nqz] from nqx, nqz */ +DONNA_INLINE static void +curve25519_compute_nq(packedelem64 *nq, const bignum25519 nqx, const bignum25519 nqz) { + xmmi x0,x1,x2; + xmmi z0,z1,z2; + xmmi a0,a1,a2; + xmmi s0,s1,s2; + xmmi r0,r1; + xmmi c1,c2; + x0 = _mm_load_si128((xmmi*)nqx + 0); + x1 = _mm_load_si128((xmmi*)nqx + 1); + x2 = _mm_load_si128((xmmi*)nqx + 2); + z0 = _mm_load_si128((xmmi*)nqz + 0); + z1 = _mm_load_si128((xmmi*)nqz + 1); + z2 = _mm_load_si128((xmmi*)nqz + 2); + a0 = _mm_add_epi32(x0, z0); + a1 = _mm_add_epi32(x1, z1); + a2 = _mm_add_epi32(x2, z2); + s0 = _mm_add_epi32(x0, packed2p0.v); + s1 = _mm_add_epi32(x1, packed2p1.v); + s2 = _mm_add_epi32(x2, packed2p2.v); + s0 = _mm_sub_epi32(s0, z0); + s1 = _mm_sub_epi32(s1, z1); + s2 = _mm_sub_epi32(s2, z2); + r0 = _mm_and_si128(_mm_shuffle_epi32(s0, _MM_SHUFFLE(2,2,0,0)), sse2_bot32bitmask.v); + r1 = _mm_and_si128(_mm_shuffle_epi32(s0, _MM_SHUFFLE(3,3,1,1)), sse2_bot32bitmask.v); + c1 = _mm_srli_epi32(r0, 26); + c2 = _mm_srli_epi32(r1, 25); + r0 = _mm_and_si128(r0, packedmask26.v); + r1 = _mm_and_si128(r1, packedmask25.v); + r0 = _mm_add_epi32(r0, _mm_slli_si128(c2, 8)); + r1 = _mm_add_epi32(r1, c1); + s0 = _mm_unpacklo_epi64(_mm_unpacklo_epi32(r0, r1), _mm_unpackhi_epi32(r0, r1)); + s1 = _mm_add_epi32(s1, _mm_srli_si128(c2, 8)); + nq[0].v = _mm_unpacklo_epi64(a0, s0); + nq[2].v = _mm_unpackhi_epi64(a0, s0); + nq[4].v = _mm_unpacklo_epi64(a1, s1); + nq[6].v = _mm_unpackhi_epi64(a1, s1); + nq[8].v = _mm_unpacklo_epi64(a2, s2); + nq[1].v = _mm_shuffle_epi32(nq[0].v, _MM_SHUFFLE(3,3,1,1)); + nq[3].v = _mm_shuffle_epi32(nq[2].v, _MM_SHUFFLE(3,3,1,1)); + nq[5].v = _mm_shuffle_epi32(nq[4].v, _MM_SHUFFLE(3,3,1,1)); + nq[7].v = _mm_shuffle_epi32(nq[6].v, _MM_SHUFFLE(3,3,1,1)); + nq[9].v = _mm_shuffle_epi32(nq[8].v, _MM_SHUFFLE(3,3,1,1)); +} + + +/* compute [x+z,x-z] from [x,z] */ +DONNA_INLINE static void +curve25519_addsub_packed64(packedelem64 *r) { + packed32bignum25519 x,z,add,sub; + + x[0].v = _mm_unpacklo_epi64(r[0].v, r[1].v); + z[0].v = _mm_unpackhi_epi64(r[0].v, r[1].v); + x[1].v = _mm_unpacklo_epi64(r[2].v, r[3].v); + z[1].v = _mm_unpackhi_epi64(r[2].v, r[3].v); + x[2].v = _mm_unpacklo_epi64(r[4].v, r[5].v); + z[2].v = _mm_unpackhi_epi64(r[4].v, r[5].v); + x[3].v = _mm_unpacklo_epi64(r[6].v, r[7].v); + z[3].v = _mm_unpackhi_epi64(r[6].v, r[7].v); + x[4].v = _mm_unpacklo_epi64(r[8].v, r[9].v); + z[4].v = _mm_unpackhi_epi64(r[8].v, r[9].v); + + curve25519_add_packed32(add, x, z); + curve25519_sub_packed32(sub, x, z); + + r[0].v = _mm_unpacklo_epi64(add[0].v, sub[0].v); + r[1].v = _mm_unpackhi_epi64(add[0].v, sub[0].v); + r[2].v = _mm_unpacklo_epi64(add[1].v, sub[1].v); + r[3].v = _mm_unpackhi_epi64(add[1].v, sub[1].v); + r[4].v = _mm_unpacklo_epi64(add[2].v, sub[2].v); + r[5].v = _mm_unpackhi_epi64(add[2].v, sub[2].v); + r[6].v = _mm_unpacklo_epi64(add[3].v, sub[3].v); + r[7].v = _mm_unpackhi_epi64(add[3].v, sub[3].v); + r[8].v = _mm_unpacklo_epi64(add[4].v, sub[4].v); + r[9].v = _mm_unpackhi_epi64(add[4].v, sub[4].v); +} + +/* compute [x,z] * [121666,121665] */ +DONNA_INLINE static void +curve25519_121665_packed64(packedelem64 *out, const packedelem64 *in) { + xmmi c1,c2; + + out[0].v = _mm_mul_epu32(in[0].v, packed121666121665.v); + out[1].v = _mm_mul_epu32(in[1].v, packed121666121665.v); + out[2].v = _mm_mul_epu32(in[2].v, packed121666121665.v); + out[3].v = _mm_mul_epu32(in[3].v, packed121666121665.v); + out[4].v = _mm_mul_epu32(in[4].v, packed121666121665.v); + out[5].v = _mm_mul_epu32(in[5].v, packed121666121665.v); + out[6].v = _mm_mul_epu32(in[6].v, packed121666121665.v); + out[7].v = _mm_mul_epu32(in[7].v, packed121666121665.v); + out[8].v = _mm_mul_epu32(in[8].v, packed121666121665.v); + out[9].v = _mm_mul_epu32(in[9].v, packed121666121665.v); + + c1 = _mm_srli_epi64(out[0].v, 26); c2 = _mm_srli_epi64(out[4].v, 26); out[0].v = _mm_and_si128(out[0].v, packedmask26.v); out[4].v = _mm_and_si128(out[4].v, packedmask26.v); out[1].v = _mm_add_epi64(out[1].v, c1); out[5].v = _mm_add_epi64(out[5].v, c2); + c1 = _mm_srli_epi64(out[1].v, 25); c2 = _mm_srli_epi64(out[5].v, 25); out[1].v = _mm_and_si128(out[1].v, packedmask25.v); out[5].v = _mm_and_si128(out[5].v, packedmask25.v); out[2].v = _mm_add_epi64(out[2].v, c1); out[6].v = _mm_add_epi64(out[6].v, c2); + c1 = _mm_srli_epi64(out[2].v, 26); c2 = _mm_srli_epi64(out[6].v, 26); out[2].v = _mm_and_si128(out[2].v, packedmask26.v); out[6].v = _mm_and_si128(out[6].v, packedmask26.v); out[3].v = _mm_add_epi64(out[3].v, c1); out[7].v = _mm_add_epi64(out[7].v, c2); + c1 = _mm_srli_epi64(out[3].v, 25); c2 = _mm_srli_epi64(out[7].v, 25); out[3].v = _mm_and_si128(out[3].v, packedmask25.v); out[7].v = _mm_and_si128(out[7].v, packedmask25.v); out[4].v = _mm_add_epi64(out[4].v, c1); out[8].v = _mm_add_epi64(out[8].v, c2); + c2 = _mm_srli_epi64(out[8].v, 26); out[8].v = _mm_and_si128(out[8].v, packedmask26.v); out[9].v = _mm_add_epi64(out[9].v, c2); + c2 = _mm_srli_epi64(out[9].v, 25); out[9].v = _mm_and_si128(out[9].v, packedmask25.v); out[0].v = _mm_add_epi64(out[0].v, _mm_mul_epu32(c2, packednineteen.v)); + c1 = _mm_srli_epi64(out[0].v, 26); c2 = _mm_srli_epi64(out[4].v, 26); out[0].v = _mm_and_si128(out[0].v, packedmask26.v); out[4].v = _mm_and_si128(out[4].v, packedmask26.v); out[1].v = _mm_add_epi64(out[1].v, c1); out[5].v = _mm_add_epi64(out[5].v, c2); +} + +/* compute [sq.x,sqscalar.x-sqscalar.z] * [sq.z,sq.x-sq.z] */ +DONNA_INLINE static void +curve25519_final_nq(packedelem64 *nq, const packedelem64 *sq, const packedelem64 *sq121665) { + packed32bignum25519 x, z, sub; + packed64bignum25519 t, nqa, nqb; + + x[0].v = _mm_or_si128(_mm_unpacklo_epi64(sq[0].v, sq[1].v), _mm_slli_si128(_mm_unpacklo_epi64(sq121665[0].v, sq121665[1].v), 4)); + z[0].v = _mm_or_si128(_mm_unpackhi_epi64(sq[0].v, sq[1].v), _mm_slli_si128(_mm_unpackhi_epi64(sq121665[0].v, sq121665[1].v), 4)); + x[1].v = _mm_or_si128(_mm_unpacklo_epi64(sq[2].v, sq[3].v), _mm_slli_si128(_mm_unpacklo_epi64(sq121665[2].v, sq121665[3].v), 4)); + z[1].v = _mm_or_si128(_mm_unpackhi_epi64(sq[2].v, sq[3].v), _mm_slli_si128(_mm_unpackhi_epi64(sq121665[2].v, sq121665[3].v), 4)); + x[2].v = _mm_or_si128(_mm_unpacklo_epi64(sq[4].v, sq[5].v), _mm_slli_si128(_mm_unpacklo_epi64(sq121665[4].v, sq121665[5].v), 4)); + z[2].v = _mm_or_si128(_mm_unpackhi_epi64(sq[4].v, sq[5].v), _mm_slli_si128(_mm_unpackhi_epi64(sq121665[4].v, sq121665[5].v), 4)); + x[3].v = _mm_or_si128(_mm_unpacklo_epi64(sq[6].v, sq[7].v), _mm_slli_si128(_mm_unpacklo_epi64(sq121665[6].v, sq121665[7].v), 4)); + z[3].v = _mm_or_si128(_mm_unpackhi_epi64(sq[6].v, sq[7].v), _mm_slli_si128(_mm_unpackhi_epi64(sq121665[6].v, sq121665[7].v), 4)); + x[4].v = _mm_or_si128(_mm_unpacklo_epi64(sq[8].v, sq[9].v), _mm_slli_si128(_mm_unpacklo_epi64(sq121665[8].v, sq121665[9].v), 4)); + z[4].v = _mm_or_si128(_mm_unpackhi_epi64(sq[8].v, sq[9].v), _mm_slli_si128(_mm_unpackhi_epi64(sq121665[8].v, sq121665[9].v), 4)); + + curve25519_sub_packed32(sub, x, z); + + t[0].v = _mm_shuffle_epi32(sub[0].v, _MM_SHUFFLE(1,1,0,0)); + t[1].v = _mm_shuffle_epi32(sub[0].v, _MM_SHUFFLE(3,3,2,2)); + t[2].v = _mm_shuffle_epi32(sub[1].v, _MM_SHUFFLE(1,1,0,0)); + t[3].v = _mm_shuffle_epi32(sub[1].v, _MM_SHUFFLE(3,3,2,2)); + t[4].v = _mm_shuffle_epi32(sub[2].v, _MM_SHUFFLE(1,1,0,0)); + t[5].v = _mm_shuffle_epi32(sub[2].v, _MM_SHUFFLE(3,3,2,2)); + t[6].v = _mm_shuffle_epi32(sub[3].v, _MM_SHUFFLE(1,1,0,0)); + t[7].v = _mm_shuffle_epi32(sub[3].v, _MM_SHUFFLE(3,3,2,2)); + t[8].v = _mm_shuffle_epi32(sub[4].v, _MM_SHUFFLE(1,1,0,0)); + t[9].v = _mm_shuffle_epi32(sub[4].v, _MM_SHUFFLE(3,3,2,2)); + + nqa[0].v = _mm_unpacklo_epi64(sq[0].v, t[0].v); + nqb[0].v = _mm_unpackhi_epi64(sq[0].v, t[0].v); + nqa[1].v = _mm_unpacklo_epi64(sq[1].v, t[1].v); + nqb[1].v = _mm_unpackhi_epi64(sq[1].v, t[1].v); + nqa[2].v = _mm_unpacklo_epi64(sq[2].v, t[2].v); + nqb[2].v = _mm_unpackhi_epi64(sq[2].v, t[2].v); + nqa[3].v = _mm_unpacklo_epi64(sq[3].v, t[3].v); + nqb[3].v = _mm_unpackhi_epi64(sq[3].v, t[3].v); + nqa[4].v = _mm_unpacklo_epi64(sq[4].v, t[4].v); + nqb[4].v = _mm_unpackhi_epi64(sq[4].v, t[4].v); + nqa[5].v = _mm_unpacklo_epi64(sq[5].v, t[5].v); + nqb[5].v = _mm_unpackhi_epi64(sq[5].v, t[5].v); + nqa[6].v = _mm_unpacklo_epi64(sq[6].v, t[6].v); + nqb[6].v = _mm_unpackhi_epi64(sq[6].v, t[6].v); + nqa[7].v = _mm_unpacklo_epi64(sq[7].v, t[7].v); + nqb[7].v = _mm_unpackhi_epi64(sq[7].v, t[7].v); + nqa[8].v = _mm_unpacklo_epi64(sq[8].v, t[8].v); + nqb[8].v = _mm_unpackhi_epi64(sq[8].v, t[8].v); + nqa[9].v = _mm_unpacklo_epi64(sq[9].v, t[9].v); + nqb[9].v = _mm_unpackhi_epi64(sq[9].v, t[9].v); + + curve25519_mul_packed64(nq, nqa, nqb); +} + diff --git a/curve25519-donna/curve25519-donna.c b/curve25519-donna/curve25519-donna.c deleted file mode 100644 index 936aa890b..000000000 --- a/curve25519-donna/curve25519-donna.c +++ /dev/null @@ -1,863 +0,0 @@ -/* Copyright 2008, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * curve25519-donna: Curve25519 elliptic curve, public key function - * - * http://code.google.com/p/curve25519-donna/ - * - * Adam Langley - * - * Derived from public domain C code by Daniel J. Bernstein - * - * More information about curve25519 can be found here - * http://cr.yp.to/ecdh.html - * - * djb's sample implementation of curve25519 is written in a special assembly - * language called qhasm and uses the floating point registers. - * - * This is, almost, a clean room reimplementation from the curve25519 paper. It - * uses many of the tricks described therein. Only the crecip function is taken - * from the sample implementation. */ - -#include - -#include "curve25519-donna.h" - -#ifdef _MSC_VER -#define inline __inline -#endif - -typedef int32_t s32; -typedef int64_t limb; - -/* Field element representation: - * - * Field elements are written as an array of signed, 64-bit limbs, least - * significant first. The value of the field element is: - * x[0] + 2^26·x[1] + x^51·x[2] + 2^102·x[3] + ... - * - * i.e. the limbs are 26, 25, 26, 25, ... bits wide. */ - -/* Sum two numbers: output += in */ -static void fsum(limb *output, const limb *in) { - unsigned i; - for (i = 0; i < 10; i += 2) { - output[0+i] = output[0+i] + in[0+i]; - output[1+i] = output[1+i] + in[1+i]; - } -} - -/* Find the difference of two numbers: output = in - output - * (note the order of the arguments!). */ -static void fdifference(limb *output, const limb *in) { - unsigned i; - for (i = 0; i < 10; ++i) { - output[i] = in[i] - output[i]; - } -} - -/* Multiply a number by a scalar: output = in * scalar */ -static void fscalar_product(limb *output, const limb *in, const limb scalar) { - unsigned i; - for (i = 0; i < 10; ++i) { - output[i] = in[i] * scalar; - } -} - -/* Multiply two numbers: output = in2 * in - * - * output must be distinct to both inputs. The inputs are reduced coefficient - * form, the output is not. - * - * output[x] <= 14 * the largest product of the input limbs. */ -static void fproduct(limb *output, const limb *in2, const limb *in) { - output[0] = ((limb) ((s32) in2[0])) * ((s32) in[0]); - output[1] = ((limb) ((s32) in2[0])) * ((s32) in[1]) + - ((limb) ((s32) in2[1])) * ((s32) in[0]); - output[2] = 2 * ((limb) ((s32) in2[1])) * ((s32) in[1]) + - ((limb) ((s32) in2[0])) * ((s32) in[2]) + - ((limb) ((s32) in2[2])) * ((s32) in[0]); - output[3] = ((limb) ((s32) in2[1])) * ((s32) in[2]) + - ((limb) ((s32) in2[2])) * ((s32) in[1]) + - ((limb) ((s32) in2[0])) * ((s32) in[3]) + - ((limb) ((s32) in2[3])) * ((s32) in[0]); - output[4] = ((limb) ((s32) in2[2])) * ((s32) in[2]) + - 2 * (((limb) ((s32) in2[1])) * ((s32) in[3]) + - ((limb) ((s32) in2[3])) * ((s32) in[1])) + - ((limb) ((s32) in2[0])) * ((s32) in[4]) + - ((limb) ((s32) in2[4])) * ((s32) in[0]); - output[5] = ((limb) ((s32) in2[2])) * ((s32) in[3]) + - ((limb) ((s32) in2[3])) * ((s32) in[2]) + - ((limb) ((s32) in2[1])) * ((s32) in[4]) + - ((limb) ((s32) in2[4])) * ((s32) in[1]) + - ((limb) ((s32) in2[0])) * ((s32) in[5]) + - ((limb) ((s32) in2[5])) * ((s32) in[0]); - output[6] = 2 * (((limb) ((s32) in2[3])) * ((s32) in[3]) + - ((limb) ((s32) in2[1])) * ((s32) in[5]) + - ((limb) ((s32) in2[5])) * ((s32) in[1])) + - ((limb) ((s32) in2[2])) * ((s32) in[4]) + - ((limb) ((s32) in2[4])) * ((s32) in[2]) + - ((limb) ((s32) in2[0])) * ((s32) in[6]) + - ((limb) ((s32) in2[6])) * ((s32) in[0]); - output[7] = ((limb) ((s32) in2[3])) * ((s32) in[4]) + - ((limb) ((s32) in2[4])) * ((s32) in[3]) + - ((limb) ((s32) in2[2])) * ((s32) in[5]) + - ((limb) ((s32) in2[5])) * ((s32) in[2]) + - ((limb) ((s32) in2[1])) * ((s32) in[6]) + - ((limb) ((s32) in2[6])) * ((s32) in[1]) + - ((limb) ((s32) in2[0])) * ((s32) in[7]) + - ((limb) ((s32) in2[7])) * ((s32) in[0]); - output[8] = ((limb) ((s32) in2[4])) * ((s32) in[4]) + - 2 * (((limb) ((s32) in2[3])) * ((s32) in[5]) + - ((limb) ((s32) in2[5])) * ((s32) in[3]) + - ((limb) ((s32) in2[1])) * ((s32) in[7]) + - ((limb) ((s32) in2[7])) * ((s32) in[1])) + - ((limb) ((s32) in2[2])) * ((s32) in[6]) + - ((limb) ((s32) in2[6])) * ((s32) in[2]) + - ((limb) ((s32) in2[0])) * ((s32) in[8]) + - ((limb) ((s32) in2[8])) * ((s32) in[0]); - output[9] = ((limb) ((s32) in2[4])) * ((s32) in[5]) + - ((limb) ((s32) in2[5])) * ((s32) in[4]) + - ((limb) ((s32) in2[3])) * ((s32) in[6]) + - ((limb) ((s32) in2[6])) * ((s32) in[3]) + - ((limb) ((s32) in2[2])) * ((s32) in[7]) + - ((limb) ((s32) in2[7])) * ((s32) in[2]) + - ((limb) ((s32) in2[1])) * ((s32) in[8]) + - ((limb) ((s32) in2[8])) * ((s32) in[1]) + - ((limb) ((s32) in2[0])) * ((s32) in[9]) + - ((limb) ((s32) in2[9])) * ((s32) in[0]); - output[10] = 2 * (((limb) ((s32) in2[5])) * ((s32) in[5]) + - ((limb) ((s32) in2[3])) * ((s32) in[7]) + - ((limb) ((s32) in2[7])) * ((s32) in[3]) + - ((limb) ((s32) in2[1])) * ((s32) in[9]) + - ((limb) ((s32) in2[9])) * ((s32) in[1])) + - ((limb) ((s32) in2[4])) * ((s32) in[6]) + - ((limb) ((s32) in2[6])) * ((s32) in[4]) + - ((limb) ((s32) in2[2])) * ((s32) in[8]) + - ((limb) ((s32) in2[8])) * ((s32) in[2]); - output[11] = ((limb) ((s32) in2[5])) * ((s32) in[6]) + - ((limb) ((s32) in2[6])) * ((s32) in[5]) + - ((limb) ((s32) in2[4])) * ((s32) in[7]) + - ((limb) ((s32) in2[7])) * ((s32) in[4]) + - ((limb) ((s32) in2[3])) * ((s32) in[8]) + - ((limb) ((s32) in2[8])) * ((s32) in[3]) + - ((limb) ((s32) in2[2])) * ((s32) in[9]) + - ((limb) ((s32) in2[9])) * ((s32) in[2]); - output[12] = ((limb) ((s32) in2[6])) * ((s32) in[6]) + - 2 * (((limb) ((s32) in2[5])) * ((s32) in[7]) + - ((limb) ((s32) in2[7])) * ((s32) in[5]) + - ((limb) ((s32) in2[3])) * ((s32) in[9]) + - ((limb) ((s32) in2[9])) * ((s32) in[3])) + - ((limb) ((s32) in2[4])) * ((s32) in[8]) + - ((limb) ((s32) in2[8])) * ((s32) in[4]); - output[13] = ((limb) ((s32) in2[6])) * ((s32) in[7]) + - ((limb) ((s32) in2[7])) * ((s32) in[6]) + - ((limb) ((s32) in2[5])) * ((s32) in[8]) + - ((limb) ((s32) in2[8])) * ((s32) in[5]) + - ((limb) ((s32) in2[4])) * ((s32) in[9]) + - ((limb) ((s32) in2[9])) * ((s32) in[4]); - output[14] = 2 * (((limb) ((s32) in2[7])) * ((s32) in[7]) + - ((limb) ((s32) in2[5])) * ((s32) in[9]) + - ((limb) ((s32) in2[9])) * ((s32) in[5])) + - ((limb) ((s32) in2[6])) * ((s32) in[8]) + - ((limb) ((s32) in2[8])) * ((s32) in[6]); - output[15] = ((limb) ((s32) in2[7])) * ((s32) in[8]) + - ((limb) ((s32) in2[8])) * ((s32) in[7]) + - ((limb) ((s32) in2[6])) * ((s32) in[9]) + - ((limb) ((s32) in2[9])) * ((s32) in[6]); - output[16] = ((limb) ((s32) in2[8])) * ((s32) in[8]) + - 2 * (((limb) ((s32) in2[7])) * ((s32) in[9]) + - ((limb) ((s32) in2[9])) * ((s32) in[7])); - output[17] = ((limb) ((s32) in2[8])) * ((s32) in[9]) + - ((limb) ((s32) in2[9])) * ((s32) in[8]); - output[18] = 2 * ((limb) ((s32) in2[9])) * ((s32) in[9]); -} - -/* Reduce a long form to a short form by taking the input mod 2^255 - 19. - * - * On entry: |output[i]| < 14*2^54 - * On exit: |output[0..8]| < 280*2^54 */ -static void freduce_degree(limb *output) { - /* Each of these shifts and adds ends up multiplying the value by 19. - * - * For output[0..8], the absolute entry value is < 14*2^54 and we add, at - * most, 19*14*2^54 thus, on exit, |output[0..8]| < 280*2^54. */ - output[8] += output[18] << 4; - output[8] += output[18] << 1; - output[8] += output[18]; - output[7] += output[17] << 4; - output[7] += output[17] << 1; - output[7] += output[17]; - output[6] += output[16] << 4; - output[6] += output[16] << 1; - output[6] += output[16]; - output[5] += output[15] << 4; - output[5] += output[15] << 1; - output[5] += output[15]; - output[4] += output[14] << 4; - output[4] += output[14] << 1; - output[4] += output[14]; - output[3] += output[13] << 4; - output[3] += output[13] << 1; - output[3] += output[13]; - output[2] += output[12] << 4; - output[2] += output[12] << 1; - output[2] += output[12]; - output[1] += output[11] << 4; - output[1] += output[11] << 1; - output[1] += output[11]; - output[0] += output[10] << 4; - output[0] += output[10] << 1; - output[0] += output[10]; -} - -#if (-1 & 3) != 3 -#error "This code only works on a two's complement system" -#endif - -/* return v / 2^26, using only shifts and adds. - * - * On entry: v can take any value. */ -static inline limb -div_by_2_26(const limb v) -{ - /* High word of v; no shift needed. */ - const uint32_t highword = (uint32_t) (((uint64_t) v) >> 32); - /* Set to all 1s if v was negative; else set to 0s. */ - const int32_t sign = ((int32_t) highword) >> 31; - /* Set to 0x3ffffff if v was negative; else set to 0. */ - const int32_t roundoff = ((uint32_t) sign) >> 6; - /* Should return v / (1<<26) */ - return (v + roundoff) >> 26; -} - -/* return v / (2^25), using only shifts and adds. - * - * On entry: v can take any value. */ -static inline limb -div_by_2_25(const limb v) -{ - /* High word of v; no shift needed*/ - const uint32_t highword = (uint32_t) (((uint64_t) v) >> 32); - /* Set to all 1s if v was negative; else set to 0s. */ - const int32_t sign = ((int32_t) highword) >> 31; - /* Set to 0x1ffffff if v was negative; else set to 0. */ - const int32_t roundoff = ((uint32_t) sign) >> 7; - /* Should return v / (1<<25) */ - return (v + roundoff) >> 25; -} - -/* Reduce all coefficients of the short form input so that |x| < 2^26. - * - * On entry: |output[i]| < 280*2^54 */ -static void freduce_coefficients(limb *output) { - unsigned i; - - output[10] = 0; - - for (i = 0; i < 10; i += 2) { - limb over = div_by_2_26(output[i]); - /* The entry condition (that |output[i]| < 280*2^54) means that over is, at - * most, 280*2^28 in the first iteration of this loop. This is added to the - * next limb and we can approximate the resulting bound of that limb by - * 281*2^54. */ - output[i] -= over << 26; - output[i+1] += over; - - /* For the first iteration, |output[i+1]| < 281*2^54, thus |over| < - * 281*2^29. When this is added to the next limb, the resulting bound can - * be approximated as 281*2^54. - * - * For subsequent iterations of the loop, 281*2^54 remains a conservative - * bound and no overflow occurs. */ - over = div_by_2_25(output[i+1]); - output[i+1] -= over << 25; - output[i+2] += over; - } - /* Now |output[10]| < 281*2^29 and all other coefficients are reduced. */ - output[0] += output[10] << 4; - output[0] += output[10] << 1; - output[0] += output[10]; - - output[10] = 0; - - /* Now output[1..9] are reduced, and |output[0]| < 2^26 + 19*281*2^29 - * So |over| will be no more than 2^16. */ - { - limb over = div_by_2_26(output[0]); - output[0] -= over << 26; - output[1] += over; - } - - /* Now output[0,2..9] are reduced, and |output[1]| < 2^25 + 2^16 < 2^26. The - * bound on |output[1]| is sufficient to meet our needs. */ -} - -/* A helpful wrapper around fproduct: output = in * in2. - * - * On entry: |in[i]| < 2^27 and |in2[i]| < 2^27. - * - * output must be distinct to both inputs. The output is reduced degree - * (indeed, one need only provide storage for 10 limbs) and |output[i]| < 2^26. */ -static void -fmul(limb *output, const limb *in, const limb *in2) { - limb t[19]; - fproduct(t, in, in2); - /* |t[i]| < 14*2^54 */ - freduce_degree(t); - freduce_coefficients(t); - /* |t[i]| < 2^26 */ - memcpy(output, t, sizeof(limb) * 10); -} - -/* Square a number: output = in**2 - * - * output must be distinct from the input. The inputs are reduced coefficient - * form, the output is not. - * - * output[x] <= 14 * the largest product of the input limbs. */ -static void fsquare_inner(limb *output, const limb *in) { - output[0] = ((limb) ((s32) in[0])) * ((s32) in[0]); - output[1] = 2 * ((limb) ((s32) in[0])) * ((s32) in[1]); - output[2] = 2 * (((limb) ((s32) in[1])) * ((s32) in[1]) + - ((limb) ((s32) in[0])) * ((s32) in[2])); - output[3] = 2 * (((limb) ((s32) in[1])) * ((s32) in[2]) + - ((limb) ((s32) in[0])) * ((s32) in[3])); - output[4] = ((limb) ((s32) in[2])) * ((s32) in[2]) + - 4 * ((limb) ((s32) in[1])) * ((s32) in[3]) + - 2 * ((limb) ((s32) in[0])) * ((s32) in[4]); - output[5] = 2 * (((limb) ((s32) in[2])) * ((s32) in[3]) + - ((limb) ((s32) in[1])) * ((s32) in[4]) + - ((limb) ((s32) in[0])) * ((s32) in[5])); - output[6] = 2 * (((limb) ((s32) in[3])) * ((s32) in[3]) + - ((limb) ((s32) in[2])) * ((s32) in[4]) + - ((limb) ((s32) in[0])) * ((s32) in[6]) + - 2 * ((limb) ((s32) in[1])) * ((s32) in[5])); - output[7] = 2 * (((limb) ((s32) in[3])) * ((s32) in[4]) + - ((limb) ((s32) in[2])) * ((s32) in[5]) + - ((limb) ((s32) in[1])) * ((s32) in[6]) + - ((limb) ((s32) in[0])) * ((s32) in[7])); - output[8] = ((limb) ((s32) in[4])) * ((s32) in[4]) + - 2 * (((limb) ((s32) in[2])) * ((s32) in[6]) + - ((limb) ((s32) in[0])) * ((s32) in[8]) + - 2 * (((limb) ((s32) in[1])) * ((s32) in[7]) + - ((limb) ((s32) in[3])) * ((s32) in[5]))); - output[9] = 2 * (((limb) ((s32) in[4])) * ((s32) in[5]) + - ((limb) ((s32) in[3])) * ((s32) in[6]) + - ((limb) ((s32) in[2])) * ((s32) in[7]) + - ((limb) ((s32) in[1])) * ((s32) in[8]) + - ((limb) ((s32) in[0])) * ((s32) in[9])); - output[10] = 2 * (((limb) ((s32) in[5])) * ((s32) in[5]) + - ((limb) ((s32) in[4])) * ((s32) in[6]) + - ((limb) ((s32) in[2])) * ((s32) in[8]) + - 2 * (((limb) ((s32) in[3])) * ((s32) in[7]) + - ((limb) ((s32) in[1])) * ((s32) in[9]))); - output[11] = 2 * (((limb) ((s32) in[5])) * ((s32) in[6]) + - ((limb) ((s32) in[4])) * ((s32) in[7]) + - ((limb) ((s32) in[3])) * ((s32) in[8]) + - ((limb) ((s32) in[2])) * ((s32) in[9])); - output[12] = ((limb) ((s32) in[6])) * ((s32) in[6]) + - 2 * (((limb) ((s32) in[4])) * ((s32) in[8]) + - 2 * (((limb) ((s32) in[5])) * ((s32) in[7]) + - ((limb) ((s32) in[3])) * ((s32) in[9]))); - output[13] = 2 * (((limb) ((s32) in[6])) * ((s32) in[7]) + - ((limb) ((s32) in[5])) * ((s32) in[8]) + - ((limb) ((s32) in[4])) * ((s32) in[9])); - output[14] = 2 * (((limb) ((s32) in[7])) * ((s32) in[7]) + - ((limb) ((s32) in[6])) * ((s32) in[8]) + - 2 * ((limb) ((s32) in[5])) * ((s32) in[9])); - output[15] = 2 * (((limb) ((s32) in[7])) * ((s32) in[8]) + - ((limb) ((s32) in[6])) * ((s32) in[9])); - output[16] = ((limb) ((s32) in[8])) * ((s32) in[8]) + - 4 * ((limb) ((s32) in[7])) * ((s32) in[9]); - output[17] = 2 * ((limb) ((s32) in[8])) * ((s32) in[9]); - output[18] = 2 * ((limb) ((s32) in[9])) * ((s32) in[9]); -} - -/* fsquare sets output = in^2. - * - * On entry: The |in| argument is in reduced coefficients form and |in[i]| < - * 2^27. - * - * On exit: The |output| argument is in reduced coefficients form (indeed, one - * need only provide storage for 10 limbs) and |out[i]| < 2^26. */ -static void -fsquare(limb *output, const limb *in) { - limb t[19]; - fsquare_inner(t, in); - /* |t[i]| < 14*2^54 because the largest product of two limbs will be < - * 2^(27+27) and fsquare_inner adds together, at most, 14 of those - * products. */ - freduce_degree(t); - freduce_coefficients(t); - /* |t[i]| < 2^26 */ - memcpy(output, t, sizeof(limb) * 10); -} - -/* Take a little-endian, 32-byte number and expand it into polynomial form */ -static void -fexpand(limb *output, const u8 *input) { -#define F(n,start,shift,mask) \ - output[n] = ((((limb) input[start + 0]) | \ - ((limb) input[start + 1]) << 8 | \ - ((limb) input[start + 2]) << 16 | \ - ((limb) input[start + 3]) << 24) >> shift) & mask; - F(0, 0, 0, 0x3ffffff); - F(1, 3, 2, 0x1ffffff); - F(2, 6, 3, 0x3ffffff); - F(3, 9, 5, 0x1ffffff); - F(4, 12, 6, 0x3ffffff); - F(5, 16, 0, 0x1ffffff); - F(6, 19, 1, 0x3ffffff); - F(7, 22, 3, 0x1ffffff); - F(8, 25, 4, 0x3ffffff); - F(9, 28, 6, 0x1ffffff); -#undef F -} - -#if (-32 >> 1) != -16 -#error "This code only works when >> does sign-extension on negative numbers" -#endif - -/* s32_eq returns 0xffffffff iff a == b and zero otherwise. */ -static s32 s32_eq(s32 a, s32 b) { - a = ~(a ^ b); - a &= a << 16; - a &= a << 8; - a &= a << 4; - a &= a << 2; - a &= a << 1; - return a >> 31; -} - -/* s32_gte returns 0xffffffff if a >= b and zero otherwise, where a and b are - * both non-negative. */ -static s32 s32_gte(s32 a, s32 b) { - a -= b; - /* a >= 0 iff a >= b. */ - return ~(a >> 31); -} - -/* Take a fully reduced polynomial form number and contract it into a - * little-endian, 32-byte array. - * - * On entry: |input_limbs[i]| < 2^26 */ -static void -fcontract(u8 *output, limb *input_limbs) { - int i; - int j; - s32 input[10]; - - /* |input_limbs[i]| < 2^26, so it's valid to convert to an s32. */ - for (i = 0; i < 10; i++) { - input[i] = input_limbs[i]; - } - - for (j = 0; j < 2; ++j) { - for (i = 0; i < 9; ++i) { - if ((i & 1) == 1) { - /* This calculation is a time-invariant way to make input[i] - * non-negative by borrowing from the next-larger limb. */ - const s32 mask = input[i] >> 31; - const s32 carry = -((input[i] & mask) >> 25); - input[i] = input[i] + (carry << 25); - input[i+1] = input[i+1] - carry; - } else { - const s32 mask = input[i] >> 31; - const s32 carry = -((input[i] & mask) >> 26); - input[i] = input[i] + (carry << 26); - input[i+1] = input[i+1] - carry; - } - } - - /* There's no greater limb for input[9] to borrow from, but we can multiply - * by 19 and borrow from input[0], which is valid mod 2^255-19. */ - { - const s32 mask = input[9] >> 31; - const s32 carry = -((input[9] & mask) >> 25); - input[9] = input[9] + (carry << 25); - input[0] = input[0] - (carry * 19); - } - - /* After the first iteration, input[1..9] are non-negative and fit within - * 25 or 26 bits, depending on position. However, input[0] may be - * negative. */ - } - - /* The first borrow-propagation pass above ended with every limb - except (possibly) input[0] non-negative. - - If input[0] was negative after the first pass, then it was because of a - carry from input[9]. On entry, input[9] < 2^26 so the carry was, at most, - one, since (2**26-1) >> 25 = 1. Thus input[0] >= -19. - - In the second pass, each limb is decreased by at most one. Thus the second - borrow-propagation pass could only have wrapped around to decrease - input[0] again if the first pass left input[0] negative *and* input[1] - through input[9] were all zero. In that case, input[1] is now 2^25 - 1, - and this last borrow-propagation step will leave input[1] non-negative. */ - { - const s32 mask = input[0] >> 31; - const s32 carry = -((input[0] & mask) >> 26); - input[0] = input[0] + (carry << 26); - input[1] = input[1] - carry; - } - - /* All input[i] are now non-negative. However, there might be values between - * 2^25 and 2^26 in a limb which is, nominally, 25 bits wide. */ - for (j = 0; j < 2; j++) { - for (i = 0; i < 9; i++) { - if ((i & 1) == 1) { - const s32 carry = input[i] >> 25; - input[i] &= 0x1ffffff; - input[i+1] += carry; - } else { - const s32 carry = input[i] >> 26; - input[i] &= 0x3ffffff; - input[i+1] += carry; - } - } - - { - const s32 carry = input[9] >> 25; - input[9] &= 0x1ffffff; - input[0] += 19*carry; - } - } - - /* If the first carry-chain pass, just above, ended up with a carry from - * input[9], and that caused input[0] to be out-of-bounds, then input[0] was - * < 2^26 + 2*19, because the carry was, at most, two. - * - * If the second pass carried from input[9] again then input[0] is < 2*19 and - * the input[9] -> input[0] carry didn't push input[0] out of bounds. */ - - /* It still remains the case that input might be between 2^255-19 and 2^255. - * In this case, input[1..9] must take their maximum value and input[0] must - * be >= (2^255-19) & 0x3ffffff, which is 0x3ffffed. */ - s32 mask = s32_gte(input[0], 0x3ffffed); - for (i = 1; i < 10; i++) { - if ((i & 1) == 1) { - mask &= s32_eq(input[i], 0x1ffffff); - } else { - mask &= s32_eq(input[i], 0x3ffffff); - } - } - - /* mask is either 0xffffffff (if input >= 2^255-19) and zero otherwise. Thus - * this conditionally subtracts 2^255-19. */ - input[0] -= mask & 0x3ffffed; - - for (i = 1; i < 10; i++) { - if ((i & 1) == 1) { - input[i] -= mask & 0x1ffffff; - } else { - input[i] -= mask & 0x3ffffff; - } - } - - input[1] <<= 2; - input[2] <<= 3; - input[3] <<= 5; - input[4] <<= 6; - input[6] <<= 1; - input[7] <<= 3; - input[8] <<= 4; - input[9] <<= 6; -#define F(i, s) \ - output[s+0] |= input[i] & 0xff; \ - output[s+1] = (input[i] >> 8) & 0xff; \ - output[s+2] = (input[i] >> 16) & 0xff; \ - output[s+3] = (input[i] >> 24) & 0xff; - output[0] = 0; - output[16] = 0; - F(0,0); - F(1,3); - F(2,6); - F(3,9); - F(4,12); - F(5,16); - F(6,19); - F(7,22); - F(8,25); - F(9,28); -#undef F -} - -/* Input: Q, Q', Q-Q' - * Output: 2Q, Q+Q' - * - * x2 z3: long form - * x3 z3: long form - * x z: short form, destroyed - * xprime zprime: short form, destroyed - * qmqp: short form, preserved - * - * On entry and exit, the absolute value of the limbs of all inputs and outputs - * are < 2^26. */ -static void fmonty(limb *x2, limb *z2, /* output 2Q */ - limb *x3, limb *z3, /* output Q + Q' */ - limb *x, limb *z, /* input Q */ - limb *xprime, limb *zprime, /* input Q' */ - const limb *qmqp /* input Q - Q' */) { - limb origx[10], origxprime[10], zzz[19], xx[19], zz[19], xxprime[19], - zzprime[19], zzzprime[19], xxxprime[19]; - - memcpy(origx, x, 10 * sizeof(limb)); - fsum(x, z); - /* |x[i]| < 2^27 */ - fdifference(z, origx); /* does x - z */ - /* |z[i]| < 2^27 */ - - memcpy(origxprime, xprime, sizeof(limb) * 10); - fsum(xprime, zprime); - /* |xprime[i]| < 2^27 */ - fdifference(zprime, origxprime); - /* |zprime[i]| < 2^27 */ - fproduct(xxprime, xprime, z); - /* |xxprime[i]| < 14*2^54: the largest product of two limbs will be < - * 2^(27+27) and fproduct adds together, at most, 14 of those products. - * (Approximating that to 2^58 doesn't work out.) */ - fproduct(zzprime, x, zprime); - /* |zzprime[i]| < 14*2^54 */ - freduce_degree(xxprime); - freduce_coefficients(xxprime); - /* |xxprime[i]| < 2^26 */ - freduce_degree(zzprime); - freduce_coefficients(zzprime); - /* |zzprime[i]| < 2^26 */ - memcpy(origxprime, xxprime, sizeof(limb) * 10); - fsum(xxprime, zzprime); - /* |xxprime[i]| < 2^27 */ - fdifference(zzprime, origxprime); - /* |zzprime[i]| < 2^27 */ - fsquare(xxxprime, xxprime); - /* |xxxprime[i]| < 2^26 */ - fsquare(zzzprime, zzprime); - /* |zzzprime[i]| < 2^26 */ - fproduct(zzprime, zzzprime, qmqp); - /* |zzprime[i]| < 14*2^52 */ - freduce_degree(zzprime); - freduce_coefficients(zzprime); - /* |zzprime[i]| < 2^26 */ - memcpy(x3, xxxprime, sizeof(limb) * 10); - memcpy(z3, zzprime, sizeof(limb) * 10); - - fsquare(xx, x); - /* |xx[i]| < 2^26 */ - fsquare(zz, z); - /* |zz[i]| < 2^26 */ - fproduct(x2, xx, zz); - /* |x2[i]| < 14*2^52 */ - freduce_degree(x2); - freduce_coefficients(x2); - /* |x2[i]| < 2^26 */ - fdifference(zz, xx); // does zz = xx - zz - /* |zz[i]| < 2^27 */ - memset(zzz + 10, 0, sizeof(limb) * 9); - fscalar_product(zzz, zz, 121665); - /* |zzz[i]| < 2^(27+17) */ - /* No need to call freduce_degree here: - fscalar_product doesn't increase the degree of its input. */ - freduce_coefficients(zzz); - /* |zzz[i]| < 2^26 */ - fsum(zzz, xx); - /* |zzz[i]| < 2^27 */ - fproduct(z2, zz, zzz); - /* |z2[i]| < 14*2^(26+27) */ - freduce_degree(z2); - freduce_coefficients(z2); - /* |z2|i| < 2^26 */ -} - -/* Conditionally swap two reduced-form limb arrays if 'iswap' is 1, but leave - * them unchanged if 'iswap' is 0. Runs in data-invariant time to avoid - * side-channel attacks. - * - * NOTE that this function requires that 'iswap' be 1 or 0; other values give - * wrong results. Also, the two limb arrays must be in reduced-coefficient, - * reduced-degree form: the values in a[10..19] or b[10..19] aren't swapped, - * and all all values in a[0..9],b[0..9] must have magnitude less than - * INT32_MAX. */ -static void -swap_conditional(limb a[19], limb b[19], limb iswap) { - unsigned i; - const s32 swap = (s32) -iswap; - - for (i = 0; i < 10; ++i) { - const s32 x = swap & ( ((s32)a[i]) ^ ((s32)b[i]) ); - a[i] = ((s32)a[i]) ^ x; - b[i] = ((s32)b[i]) ^ x; - } -} - -/* Calculates nQ where Q is the x-coordinate of a point on the curve - * - * resultx/resultz: the x coordinate of the resulting curve point (short form) - * n: a little endian, 32-byte number - * q: a point of the curve (short form) */ -static void -cmult(limb *resultx, limb *resultz, const u8 *n, const limb *q) { - limb a[19] = {0}, b[19] = {1}, c[19] = {1}, d[19] = {0}; - limb *nqpqx = a, *nqpqz = b, *nqx = c, *nqz = d, *t; - limb e[19] = {0}, f[19] = {1}, g[19] = {0}, h[19] = {1}; - limb *nqpqx2 = e, *nqpqz2 = f, *nqx2 = g, *nqz2 = h; - - unsigned i, j; - - memcpy(nqpqx, q, sizeof(limb) * 10); - - for (i = 0; i < 32; ++i) { - u8 byte = n[31 - i]; - for (j = 0; j < 8; ++j) { - const limb bit = byte >> 7; - - swap_conditional(nqx, nqpqx, bit); - swap_conditional(nqz, nqpqz, bit); - fmonty(nqx2, nqz2, - nqpqx2, nqpqz2, - nqx, nqz, - nqpqx, nqpqz, - q); - swap_conditional(nqx2, nqpqx2, bit); - swap_conditional(nqz2, nqpqz2, bit); - - t = nqx; - nqx = nqx2; - nqx2 = t; - t = nqz; - nqz = nqz2; - nqz2 = t; - t = nqpqx; - nqpqx = nqpqx2; - nqpqx2 = t; - t = nqpqz; - nqpqz = nqpqz2; - nqpqz2 = t; - - byte <<= 1; - } - } - - memcpy(resultx, nqx, sizeof(limb) * 10); - memcpy(resultz, nqz, sizeof(limb) * 10); -} - -// ----------------------------------------------------------------------------- -// Shamelessly copied from djb's code -// ----------------------------------------------------------------------------- -static void -crecip(limb *out, const limb *z) { - limb z2[10]; - limb z9[10]; - limb z11[10]; - limb z2_5_0[10]; - limb z2_10_0[10]; - limb z2_20_0[10]; - limb z2_50_0[10]; - limb z2_100_0[10]; - limb t0[10]; - limb t1[10]; - int i; - - /* 2 */ fsquare(z2,z); - /* 4 */ fsquare(t1,z2); - /* 8 */ fsquare(t0,t1); - /* 9 */ fmul(z9,t0,z); - /* 11 */ fmul(z11,z9,z2); - /* 22 */ fsquare(t0,z11); - /* 2^5 - 2^0 = 31 */ fmul(z2_5_0,t0,z9); - - /* 2^6 - 2^1 */ fsquare(t0,z2_5_0); - /* 2^7 - 2^2 */ fsquare(t1,t0); - /* 2^8 - 2^3 */ fsquare(t0,t1); - /* 2^9 - 2^4 */ fsquare(t1,t0); - /* 2^10 - 2^5 */ fsquare(t0,t1); - /* 2^10 - 2^0 */ fmul(z2_10_0,t0,z2_5_0); - - /* 2^11 - 2^1 */ fsquare(t0,z2_10_0); - /* 2^12 - 2^2 */ fsquare(t1,t0); - /* 2^20 - 2^10 */ for (i = 2;i < 10;i += 2) { fsquare(t0,t1); fsquare(t1,t0); } - /* 2^20 - 2^0 */ fmul(z2_20_0,t1,z2_10_0); - - /* 2^21 - 2^1 */ fsquare(t0,z2_20_0); - /* 2^22 - 2^2 */ fsquare(t1,t0); - /* 2^40 - 2^20 */ for (i = 2;i < 20;i += 2) { fsquare(t0,t1); fsquare(t1,t0); } - /* 2^40 - 2^0 */ fmul(t0,t1,z2_20_0); - - /* 2^41 - 2^1 */ fsquare(t1,t0); - /* 2^42 - 2^2 */ fsquare(t0,t1); - /* 2^50 - 2^10 */ for (i = 2;i < 10;i += 2) { fsquare(t1,t0); fsquare(t0,t1); } - /* 2^50 - 2^0 */ fmul(z2_50_0,t0,z2_10_0); - - /* 2^51 - 2^1 */ fsquare(t0,z2_50_0); - /* 2^52 - 2^2 */ fsquare(t1,t0); - /* 2^100 - 2^50 */ for (i = 2;i < 50;i += 2) { fsquare(t0,t1); fsquare(t1,t0); } - /* 2^100 - 2^0 */ fmul(z2_100_0,t1,z2_50_0); - - /* 2^101 - 2^1 */ fsquare(t1,z2_100_0); - /* 2^102 - 2^2 */ fsquare(t0,t1); - /* 2^200 - 2^100 */ for (i = 2;i < 100;i += 2) { fsquare(t1,t0); fsquare(t0,t1); } - /* 2^200 - 2^0 */ fmul(t1,t0,z2_100_0); - - /* 2^201 - 2^1 */ fsquare(t0,t1); - /* 2^202 - 2^2 */ fsquare(t1,t0); - /* 2^250 - 2^50 */ for (i = 2;i < 50;i += 2) { fsquare(t0,t1); fsquare(t1,t0); } - /* 2^250 - 2^0 */ fmul(t0,t1,z2_50_0); - - /* 2^251 - 2^1 */ fsquare(t1,t0); - /* 2^252 - 2^2 */ fsquare(t0,t1); - /* 2^253 - 2^3 */ fsquare(t1,t0); - /* 2^254 - 2^4 */ fsquare(t0,t1); - /* 2^255 - 2^5 */ fsquare(t1,t0); - /* 2^255 - 21 */ fmul(out,t1,z11); -} - -static const u8 curve25519_basepoint[32] = {9}; - -void curve25519_scalarmult(u8 *result, const u8 *secret, const u8 *basepoint) { - limb bp[10], x[10], z[11], zmone[10]; - uint8_t e[32]; - int i; - - for (i = 0; i < 32; ++i) e[i] = secret[i]; - e[0] &= 248; - e[31] &= 127; - e[31] |= 64; - - fexpand(bp, basepoint); - cmult(x, z, e, bp); - crecip(zmone, z); - fmul(z, x, zmone); - fcontract(result, z); -} - -void curve25519_publickey(u8 *public, const u8 *secret) { - curve25519_scalarmult(public, secret, curve25519_basepoint); -} diff --git a/curve25519-donna/curve25519-donna.h b/curve25519-donna/curve25519-donna.h index 2f6bb3d11..e707e2293 100644 --- a/curve25519-donna/curve25519-donna.h +++ b/curve25519-donna/curve25519-donna.h @@ -1,11 +1,32 @@ -#ifndef CURVE25519_H -#define CURVE25519_H +#include "curve25519.h" +#include "curve25519-donna-portable.h" -#include +#if defined(CURVE25519_SSE2) +#else + #if defined(HAVE_UINT128) && !defined(CURVE25519_FORCE_32BIT) + #define CURVE25519_64BIT + #else + #define CURVE25519_32BIT + #endif +#endif -typedef uint8_t u8; +#if !defined(CURVE25519_NO_INLINE_ASM) +#endif -void curve25519_scalarmult(u8 *result, const u8 *secret, const u8 *basepoint); -void curve25519_publickey(u8 *public, const u8 *secret); -#endif // CURVE25519_H +#if defined(CURVE25519_SSE2) + #include "curve25519-donna-sse2.h" +#elif defined(CURVE25519_64BIT) + #include "curve25519-donna-64bit.h" +#else + #include "curve25519-donna-32bit.h" +#endif + +#include "curve25519-donna-common.h" + +#if defined(CURVE25519_SSE2) + #include "curve25519-donna-scalarmult-sse2.h" +#else + #include "curve25519-donna-scalarmult-base.h" +#endif + diff --git a/curve25519-donna/curve25519.c b/curve25519-donna/curve25519.c new file mode 100644 index 000000000..bfd2f58ec --- /dev/null +++ b/curve25519-donna/curve25519.c @@ -0,0 +1,27 @@ +#include "curve25519-donna.h" + +#if !defined(CURVE25519_SUFFIX) +#define CURVE25519_SUFFIX +#endif + +#define CURVE25519_FN3(fn,suffix) fn##suffix +#define CURVE25519_FN2(fn,suffix) CURVE25519_FN3(fn,suffix) +#define CURVE25519_FN(fn) CURVE25519_FN2(fn,CURVE25519_SUFFIX) + +void +CURVE25519_FN(curve25519_donna) (curve25519_key mypublic, const curve25519_key secret, const curve25519_key basepoint) { + curve25519_key e; + size_t i; + + for (i = 0;i < 32;++i) e[i] = secret[i]; + e[0] &= 0xf8; + e[31] &= 0x7f; + e[31] |= 0x40; + curve25519_scalarmult_donna(mypublic, e, basepoint); +} + +void +CURVE25519_FN(curve25519_donna_basepoint) (curve25519_key mypublic, const curve25519_key secret) { + static const curve25519_key basepoint = {9}; + CURVE25519_FN(curve25519_donna)(mypublic, secret, basepoint); +} diff --git a/curve25519-donna/curve25519.h b/curve25519-donna/curve25519.h new file mode 100644 index 000000000..51edd1e94 --- /dev/null +++ b/curve25519-donna/curve25519.h @@ -0,0 +1,10 @@ +#ifndef CURVE25519_H +#define CURVE25519_H + +typedef unsigned char curve25519_key[32]; + +void curve25519_donna(curve25519_key mypublic, const curve25519_key secret, const curve25519_key basepoint); +void curve25519_donna_basepoint(curve25519_key mypublic, const curve25519_key secret); + +#endif /* CURVE25519_H */ + diff --git a/test_speed.c b/test_speed.c index 3a9b08b4b..d9010bb90 100644 --- a/test_speed.c +++ b/test_speed.c @@ -8,7 +8,7 @@ #include "secp256k1.h" #include "nist256p1.h" #include "ed25519.h" -#include "curve25519-donna.h" +#include "curve25519.h" static uint8_t msg[32]; @@ -92,7 +92,7 @@ void bench_curve25519(void) clock_t t = clock(); for (int i = 0 ; i < 500; i++) { - curve25519_scalarmult(result, secret, basepoint); + curve25519_donna(result, secret, basepoint); } printf("Curve25519 multiplying speed: %0.2f mul/s\n", 500.0f / ((float)(clock() - t) / CLOCKS_PER_SEC)); } From fa8772dfee59f426fda238553f4613bcb7d30636 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 24 Oct 2016 20:54:29 +0200 Subject: [PATCH 346/627] include options.h to base58.h --- base58.h | 1 + 1 file changed, 1 insertion(+) diff --git a/base58.h b/base58.h index 094849bae..977d66733 100644 --- a/base58.h +++ b/base58.h @@ -26,6 +26,7 @@ #include #include +#include "options.h" int base58_encode_check(const uint8_t *data, int len, char *str, int strsize); int base58_decode_check(const char *str, uint8_t *data, int datalen); From 5ecb8574cc8d0a0adae10daacb269c3ab1bf5b12 Mon Sep 17 00:00:00 2001 From: Roman Zeyde Date: Mon, 24 Oct 2016 22:35:30 +0300 Subject: [PATCH 347/627] tests: fix curve25519 unittests (#78) --- test_curves.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test_curves.py b/test_curves.py index fb89ec811..669a425dd 100755 --- a/test_curves.py +++ b/test_curves.py @@ -409,9 +409,9 @@ def test_curve25519(r): pub2 = curve25519.Private(sec2).get_public() session1 = r.randbytes(32) - lib.curve25519_scalarmult(session1, sec2, pub1.public) + lib.curve25519_donna(session1, sec2, pub1.public) session2 = r.randbytes(32) - lib.curve25519_scalarmult(session2, sec1, pub2.public) + lib.curve25519_donna(session2, sec1, pub2.public) assert bytearray(session1) == bytearray(session2) shared1 = curve25519.Private(sec2).get_shared_key(pub1, hashfunc=lambda x: x) @@ -425,7 +425,7 @@ def test_curve25519_pubkey(r): sec = bytes(bytearray(r.randbytes(32))) pub = curve25519.Private(sec).get_public() res = r.randbytes(32) - lib.curve25519_publickey(res, sec) + lib.curve25519_donna_basepoint(res, sec) assert bytearray(res) == pub.public @@ -433,6 +433,6 @@ def test_curve25519_scalarmult_from_gpg(r): sec = binascii.unhexlify('4a1e76f133afb29dbc7860bcbc16d0e829009cc15c2f81ed26de1179b1d9c938') pub = binascii.unhexlify('5d6fc75c016e85b17f54e0128a216d5f9229f25bac1ec85cecab8daf48621b31') res = r.randbytes(32) - lib.curve25519_scalarmult(res, sec[::-1], pub[::-1]) + lib.curve25519_donna(res, sec[::-1], pub[::-1]) expected = 'a93dbdb23e5c99da743e203bd391af79f2b83fb8d0fd6ec813371c71f08f2d4d' assert binascii.hexlify(bytearray(res)) == expected From 1259c36f806c37d4ae3d0f6455394017c6c55e75 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 24 Oct 2016 21:43:33 +0200 Subject: [PATCH 348/627] change shebang for test_curves.py --- test_curves.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test_curves.py b/test_curves.py index 669a425dd..f5396fa37 100755 --- a/test_curves.py +++ b/test_curves.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/py.test import ctypes as c import curve25519 import random From 459f4a5e7aecd0a069d4ea4d6ea92a5611a17502 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 31 Oct 2016 17:26:24 +0100 Subject: [PATCH 349/627] add setbit, clearbit, testbit and xor to bignum --- bignum.c | 27 +++++++++++++++++++++++++++ bignum.h | 8 ++++++++ 2 files changed, 35 insertions(+) diff --git a/bignum.c b/bignum.c index eed53d22b..b2a20f974 100644 --- a/bignum.c +++ b/bignum.c @@ -296,6 +296,33 @@ void bn_rshift(bignum256 *a) a->val[8] >>= 1; } +// sets bit in bignum +void bn_setbit(bignum256 *a, uint8_t bit) +{ + a->val[bit / 30] |= (1 << (bit % 30)); +} + +// clears bit in bignum +void bn_clearbit(bignum256 *a, uint8_t bit) +{ + a->val[bit / 30] &= ~(1 << (bit % 30)); +} + +// tests bit in bignum +uint32_t bn_testbit(bignum256 *a, uint8_t bit) +{ + return a->val[bit / 30] & (1 << (bit % 30)); +} + +// a = b ^ c +void bn_xor(bignum256 *a, const bignum256 *b, const bignum256 *c) +{ + int i; + for (i = 0; i < 9; i++) { + a->val[i] = b->val[i] ^ c->val[i]; + } +} + // multiply x by 1/2 modulo prime. // it computes x = (x & 1) ? (x + prime) >> 1 : x >> 1. // assumes x is normalized. diff --git a/bignum.h b/bignum.h index 451e34489..83ae314ce 100644 --- a/bignum.h +++ b/bignum.h @@ -105,6 +105,14 @@ void bn_lshift(bignum256 *a); void bn_rshift(bignum256 *a); +void bn_setbit(bignum256 *a, uint8_t bit); + +void bn_clearbit(bignum256 *a, uint8_t bit); + +uint32_t bn_testbit(bignum256 *a, uint8_t bit); + +void bn_xor(bignum256 *a, const bignum256 *b, const bignum256 *c); + void bn_mult_half(bignum256 *x, const bignum256 *prime); void bn_mult_k(bignum256 *x, uint8_t k, const bignum256 *prime); From f4e4c2935602e8b57c4862b14a1c185f980dfe52 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 1 Nov 2016 16:22:20 +0100 Subject: [PATCH 350/627] add blake2s, add unittests for blake2s and sha3 --- Makefile | 1 + README.md | 1 + blake2s.c | 317 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ blake2s.h | 37 +++++++ sha3.c | 16 +++ sha3.h | 3 + tests.c | 77 ++++++++++++- 7 files changed, 448 insertions(+), 4 deletions(-) create mode 100644 blake2s.c create mode 100644 blake2s.h diff --git a/Makefile b/Makefile index 252a06f22..46dfeeb2c 100644 --- a/Makefile +++ b/Makefile @@ -47,6 +47,7 @@ SRCS += sha3.c SRCS += aescrypt.c aeskey.c aestab.c aes_modes.c SRCS += ed25519-donna/ed25519.c SRCS += curve25519-donna/curve25519.c +SRCS += blake2s.c OBJS = $(SRCS:.c=.o) diff --git a/README.md b/README.md index ccfe4fc05..3be6de73b 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ These include: - RIPEMD-160 - SHA256/SHA512 - SHA3/Keccak +- BLAKE2s - unit tests (using Check - check.sf.net; in tests.c) - tests against OpenSSL (in test-openssl.c) diff --git a/blake2s.c b/blake2s.c new file mode 100644 index 000000000..1f3b95193 --- /dev/null +++ b/blake2s.c @@ -0,0 +1,317 @@ +/* + BLAKE2 reference source code package - reference C implementations + + Copyright 2012, Samuel Neves . You may use this under the + terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at + your option. The terms of these licenses can be found at: + + - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0 + - OpenSSL license : https://www.openssl.org/source/license.html + - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0 + + More information about the BLAKE2 hash function can be found at + https://blake2.net. +*/ + +#include + +#include "macros.h" +#include "blake2s.h" + +typedef struct blake2s_param__ +{ + uint8_t digest_length; /* 1 */ + uint8_t key_length; /* 2 */ + uint8_t fanout; /* 3 */ + uint8_t depth; /* 4 */ + uint32_t leaf_length; /* 8 */ + uint32_t node_offset; /* 12 */ + uint16_t xof_length; /* 14 */ + uint8_t node_depth; /* 15 */ + uint8_t inner_length; /* 16 */ + /* uint8_t reserved[0]; */ + uint8_t salt[BLAKE2S_SALTBYTES]; /* 24 */ + uint8_t personal[BLAKE2S_PERSONALBYTES]; /* 32 */ +} __attribute__((packed)) blake2s_param; + +static const uint32_t blake2s_IV[8] = +{ + 0x6A09E667UL, 0xBB67AE85UL, 0x3C6EF372UL, 0xA54FF53AUL, + 0x510E527FUL, 0x9B05688CUL, 0x1F83D9ABUL, 0x5BE0CD19UL +}; + +static const uint8_t blake2s_sigma[10][16] = +{ + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } , + { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } , + { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } , + { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } , + { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } , + { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } , + { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } , + { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } , + { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } , + { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 } , +}; + +static inline uint32_t load32( const void *src ) +{ + uint32_t w; + memcpy(&w, src, sizeof w); + return w; +} + +static inline void store16( void *dst, uint16_t w ) +{ + memcpy(dst, &w, sizeof w); +} + +static inline void store32( void *dst, uint32_t w ) +{ + memcpy(dst, &w, sizeof w); +} + +static inline uint32_t rotr32( const uint32_t w, const unsigned c ) +{ + return ( w >> c ) | ( w << ( 32 - c ) ); +} + +static void blake2s_set_lastnode( blake2s_state *S ) +{ + S->f[1] = (uint32_t)-1; +} + +/* Some helper functions, not necessarily useful */ +static int blake2s_is_lastblock( const blake2s_state *S ) +{ + return S->f[0] != 0; +} + +static void blake2s_set_lastblock( blake2s_state *S ) +{ + if( S->last_node ) blake2s_set_lastnode( S ); + + S->f[0] = (uint32_t)-1; +} + +static void blake2s_increment_counter( blake2s_state *S, const uint32_t inc ) +{ + S->t[0] += inc; + S->t[1] += ( S->t[0] < inc ); +} + +static void blake2s_init0( blake2s_state *S ) +{ + size_t i; + memset( S, 0, sizeof( blake2s_state ) ); + + for( i = 0; i < 8; ++i ) S->h[i] = blake2s_IV[i]; +} + +/* init2 xors IV with input parameter block */ +int blake2s_init_param( blake2s_state *S, const blake2s_param *P ) +{ + const unsigned char *p = ( const unsigned char * )( P ); + size_t i; + + blake2s_init0( S ); + + /* IV XOR ParamBlock */ + for( i = 0; i < 8; ++i ) + S->h[i] ^= load32( &p[i * 4] ); + + S->outlen = P->digest_length; + return 0; +} + + +/* Sequential blake2s initialization */ +int blake2s_Init( blake2s_state *S, size_t outlen ) +{ + blake2s_param P[1]; + + /* Move interval verification here? */ + if ( ( !outlen ) || ( outlen > BLAKE2S_OUTBYTES ) ) return -1; + + P->digest_length = (uint8_t)outlen; + P->key_length = 0; + P->fanout = 1; + P->depth = 1; + store32( &P->leaf_length, 0 ); + store32( &P->node_offset, 0 ); + store16( &P->xof_length, 0 ); + P->node_depth = 0; + P->inner_length = 0; + /* memset(P->reserved, 0, sizeof(P->reserved) ); */ + memset( P->salt, 0, sizeof( P->salt ) ); + memset( P->personal, 0, sizeof( P->personal ) ); + return blake2s_init_param( S, P ); +} + +int blake2s_InitKey( blake2s_state *S, size_t outlen, const void *key, size_t keylen ) +{ + blake2s_param P[1]; + + if ( ( !outlen ) || ( outlen > BLAKE2S_OUTBYTES ) ) return -1; + + if ( !key || !keylen || keylen > BLAKE2S_KEYBYTES ) return -1; + + P->digest_length = (uint8_t)outlen; + P->key_length = (uint8_t)keylen; + P->fanout = 1; + P->depth = 1; + store32( &P->leaf_length, 0 ); + store32( &P->node_offset, 0 ); + store16( &P->xof_length, 0 ); + P->node_depth = 0; + P->inner_length = 0; + /* memset(P->reserved, 0, sizeof(P->reserved) ); */ + memset( P->salt, 0, sizeof( P->salt ) ); + memset( P->personal, 0, sizeof( P->personal ) ); + + if( blake2s_init_param( S, P ) < 0 ) return -1; + + { + uint8_t block[BLAKE2S_BLOCKBYTES]; + memset( block, 0, BLAKE2S_BLOCKBYTES ); + memcpy( block, key, keylen ); + blake2s_Update( S, block, BLAKE2S_BLOCKBYTES ); + MEMSET_BZERO( block, BLAKE2S_BLOCKBYTES ); /* Burn the key from stack */ + } + return 0; +} + +#define G(r,i,a,b,c,d) \ + do { \ + a = a + b + m[blake2s_sigma[r][2*i+0]]; \ + d = rotr32(d ^ a, 16); \ + c = c + d; \ + b = rotr32(b ^ c, 12); \ + a = a + b + m[blake2s_sigma[r][2*i+1]]; \ + d = rotr32(d ^ a, 8); \ + c = c + d; \ + b = rotr32(b ^ c, 7); \ + } while(0) + +#define ROUND(r) \ + do { \ + G(r,0,v[ 0],v[ 4],v[ 8],v[12]); \ + G(r,1,v[ 1],v[ 5],v[ 9],v[13]); \ + G(r,2,v[ 2],v[ 6],v[10],v[14]); \ + G(r,3,v[ 3],v[ 7],v[11],v[15]); \ + G(r,4,v[ 0],v[ 5],v[10],v[15]); \ + G(r,5,v[ 1],v[ 6],v[11],v[12]); \ + G(r,6,v[ 2],v[ 7],v[ 8],v[13]); \ + G(r,7,v[ 3],v[ 4],v[ 9],v[14]); \ + } while(0) + +static void blake2s_compress( blake2s_state *S, const uint8_t in[BLAKE2S_BLOCKBYTES] ) +{ + uint32_t m[16]; + uint32_t v[16]; + size_t i; + + for( i = 0; i < 16; ++i ) { + m[i] = load32( in + i * sizeof( m[i] ) ); + } + + for( i = 0; i < 8; ++i ) { + v[i] = S->h[i]; + } + + v[ 8] = blake2s_IV[0]; + v[ 9] = blake2s_IV[1]; + v[10] = blake2s_IV[2]; + v[11] = blake2s_IV[3]; + v[12] = S->t[0] ^ blake2s_IV[4]; + v[13] = S->t[1] ^ blake2s_IV[5]; + v[14] = S->f[0] ^ blake2s_IV[6]; + v[15] = S->f[1] ^ blake2s_IV[7]; + + ROUND( 0 ); + ROUND( 1 ); + ROUND( 2 ); + ROUND( 3 ); + ROUND( 4 ); + ROUND( 5 ); + ROUND( 6 ); + ROUND( 7 ); + ROUND( 8 ); + ROUND( 9 ); + + for( i = 0; i < 8; ++i ) { + S->h[i] = S->h[i] ^ v[i] ^ v[i + 8]; + } +} + +#undef G +#undef ROUND + +int blake2s_Update( blake2s_state *S, const void *pin, size_t inlen ) +{ + const unsigned char * in = (const unsigned char *)pin; + if( inlen > 0 ) + { + size_t left = S->buflen; + size_t fill = BLAKE2S_BLOCKBYTES - left; + if( inlen > fill ) + { + S->buflen = 0; + memcpy( S->buf + left, in, fill ); /* Fill buffer */ + blake2s_increment_counter( S, BLAKE2S_BLOCKBYTES ); + blake2s_compress( S, S->buf ); /* Compress */ + in += fill; inlen -= fill; + while(inlen > BLAKE2S_BLOCKBYTES) { + blake2s_increment_counter(S, BLAKE2S_BLOCKBYTES); + blake2s_compress( S, in ); + in += BLAKE2S_BLOCKBYTES; + inlen -= BLAKE2S_BLOCKBYTES; + } + } + memcpy( S->buf + S->buflen, in, inlen ); + S->buflen += inlen; + } + return 0; +} + +int blake2s_Final( blake2s_state *S, void *out, size_t outlen ) +{ + uint8_t buffer[BLAKE2S_OUTBYTES] = {0}; + size_t i; + + if( out == NULL || outlen < S->outlen ) + return -1; + + if( blake2s_is_lastblock( S ) ) + return -1; + + blake2s_increment_counter( S, ( uint32_t )S->buflen ); + blake2s_set_lastblock( S ); + memset( S->buf + S->buflen, 0, BLAKE2S_BLOCKBYTES - S->buflen ); /* Padding */ + blake2s_compress( S, S->buf ); + + for( i = 0; i < 8; ++i ) /* Output full hash to temp buffer */ + store32( buffer + sizeof( S->h[i] ) * i, S->h[i] ); + + memcpy( out, buffer, outlen ); + MEMSET_BZERO(buffer, sizeof(buffer)); + return 0; +} + +int blake2s(const uint8_t *msg, uint32_t msg_len, void *out, size_t outlen) +{ + BLAKE2S_CTX ctx; + if (0 != blake2s_Init(&ctx, outlen)) return -1; + if (0 != blake2s_Update(&ctx, msg, msg_len)) return -1; + if (0 != blake2s_Final(&ctx, out, outlen)) return -1; + return 0; +} + +int blake2s_Key(const uint8_t *msg, uint32_t msg_len, const void *key, size_t keylen, void *out, size_t outlen) +{ + BLAKE2S_CTX ctx; + if (0 != blake2s_InitKey(&ctx, outlen, key, keylen)) return -1; + if (0 != blake2s_Update(&ctx, msg, msg_len)) return -1; + if (0 != blake2s_Final(&ctx, out, outlen)) return -1; + return 0; +} diff --git a/blake2s.h b/blake2s.h new file mode 100644 index 000000000..24cedbe10 --- /dev/null +++ b/blake2s.h @@ -0,0 +1,37 @@ +#ifndef __BLAKE2S_H__ +#define __BLAKE2S_H__ + +#include +#include + +enum blake2s_constant +{ + BLAKE2S_BLOCKBYTES = 64, + BLAKE2S_OUTBYTES = 32, + BLAKE2S_KEYBYTES = 32, + BLAKE2S_SALTBYTES = 8, + BLAKE2S_PERSONALBYTES = 8 +}; + +typedef struct __blake2s_state +{ + uint32_t h[8]; + uint32_t t[2]; + uint32_t f[2]; + uint8_t buf[BLAKE2S_BLOCKBYTES]; + uint32_t buflen; + uint8_t outlen; + uint8_t last_node; +} blake2s_state; + +#define BLAKE2S_CTX blake2s_state + +int blake2s_Init(blake2s_state *S, size_t outlen); +int blake2s_InitKey(blake2s_state *S, size_t outlen, const void *key, size_t keylen); +int blake2s_Update(blake2s_state *S, const void *pin, size_t inlen); +int blake2s_Final(blake2s_state *S, void *out, size_t outlen); + +int blake2s(const uint8_t *msg, uint32_t msg_len, void *out, size_t outlen); +int blake2s_Key(const uint8_t *msg, uint32_t msg_len, const void *key, size_t keylen, void *out, size_t outlen); + +#endif diff --git a/sha3.c b/sha3.c index fc6d1c8bf..43fbc4509 100644 --- a/sha3.c +++ b/sha3.c @@ -359,3 +359,19 @@ void keccak_Final(SHA3_CTX *ctx, unsigned char* result) if (result) me64_to_le_str(result, ctx->hash, digest_length); } #endif /* USE_KECCAK */ + +void sha3_256(const unsigned char* data, size_t len, unsigned char* digest) +{ + SHA3_CTX ctx; + sha3_256_Init(&ctx); + sha3_Update(&ctx, data, len); + sha3_Final(&ctx, digest); +} + +void sha3_512(const unsigned char* data, size_t len, unsigned char* digest) +{ + SHA3_CTX ctx; + sha3_512_Init(&ctx); + sha3_Update(&ctx, data, len); + sha3_Final(&ctx, digest); +} diff --git a/sha3.h b/sha3.h index b605663ae..b78d9d84b 100644 --- a/sha3.h +++ b/sha3.h @@ -67,6 +67,9 @@ void sha3_Final(SHA3_CTX *ctx, unsigned char* result); void keccak_Final(SHA3_CTX *ctx, unsigned char* result); #endif +void sha3_256(const unsigned char* data, size_t len, unsigned char* digest); +void sha3_512(const unsigned char* data, size_t len, unsigned char* digest); + #ifdef __cplusplus } /* extern "C" */ #endif /* __cplusplus */ diff --git a/tests.c b/tests.c index 6b0394c67..23da04230 100644 --- a/tests.c +++ b/tests.c @@ -30,6 +30,8 @@ #include #include "check_mem.h" +#include "options.h" + #include "aes.h" #include "bignum.h" #include "base58.h" @@ -39,7 +41,8 @@ #include "pbkdf2.h" #include "rand.h" #include "sha2.h" -#include "options.h" +#include "sha3.h" +#include "blake2s.h" #include "curves.h" #include "secp256k1.h" #include "nist256p1.h" @@ -1774,6 +1777,66 @@ START_TEST(test_sha512) } END_TEST +// test vectors from http://www.di-mgt.com.au/sha_testvectors.html +START_TEST(test_sha3_256) +{ + uint8_t digest[sha3_256_hash_size]; + + sha3_256((uint8_t *)"", 0, digest); + ck_assert_mem_eq(digest, fromhex("a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a"), sha3_256_hash_size); + + sha3_256((uint8_t *)"abc", 3, digest); + ck_assert_mem_eq(digest, fromhex("3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532"), sha3_256_hash_size); + + sha3_256((uint8_t *)"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 56, digest); + ck_assert_mem_eq(digest, fromhex("41c0dba2a9d6240849100376a8235e2c82e1b9998a999e21db32dd97496d3376"), sha3_256_hash_size); + + sha3_256((uint8_t *)"abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", 112, digest); + ck_assert_mem_eq(digest, fromhex("916f6061fe879741ca6469b43971dfdb28b1a32dc36cb3254e812be27aad1d18"), sha3_256_hash_size); +} +END_TEST + +// test vectors from http://www.di-mgt.com.au/sha_testvectors.html +START_TEST(test_sha3_512) +{ + uint8_t digest[sha3_512_hash_size]; + + sha3_512((uint8_t *)"", 0, digest); + ck_assert_mem_eq(digest, fromhex("a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26"), sha3_512_hash_size); + + sha3_512((uint8_t *)"abc", 3, digest); + ck_assert_mem_eq(digest, fromhex("b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e10e116e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0"), sha3_512_hash_size); + + sha3_512((uint8_t *)"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 56, digest); + ck_assert_mem_eq(digest, fromhex("04a371e84ecfb5b8b77cb48610fca8182dd457ce6f326a0fd3d7ec2f1e91636dee691fbe0c985302ba1b0d8dc78c086346b533b49c030d99a27daf1139d6e75e"), sha3_512_hash_size); + + sha3_512((uint8_t *)"abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", 112, digest); + ck_assert_mem_eq(digest, fromhex("afebb2ef542e6579c50cad06d2e578f9f8dd6881d7dc824d26360feebf18a4fa73e3261122948efcfd492e74e82e2189ed0fb440d187f382270cb455f21dd185"), sha3_512_hash_size); +} +END_TEST + +// test vectors from https://raw.githubusercontent.com/BLAKE2/BLAKE2/master/testvectors/blake2s-kat.txt +START_TEST(test_blake2s) +{ + uint8_t key[BLAKE2S_KEYBYTES]; + memcpy(key, fromhex("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"), BLAKE2S_KEYBYTES); + + uint8_t digest[BLAKE2S_OUTBYTES]; + + blake2s_Key((uint8_t *)"", 0, key, BLAKE2S_KEYBYTES, digest, BLAKE2S_OUTBYTES); + ck_assert_mem_eq(digest, fromhex("48a8997da407876b3d79c0d92325ad3b89cbb754d86ab71aee047ad345fd2c49"), BLAKE2S_OUTBYTES); + + blake2s_Key(fromhex("000102"), 3, key, BLAKE2S_KEYBYTES, digest, BLAKE2S_OUTBYTES); + ck_assert_mem_eq(digest, fromhex("1d220dbe2ee134661fdf6d9e74b41704710556f2f6e5a091b227697445dbea6b"), BLAKE2S_OUTBYTES); + + blake2s_Key(fromhex("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637"), 56, key, BLAKE2S_KEYBYTES, digest, BLAKE2S_OUTBYTES); + ck_assert_mem_eq(digest, fromhex("2966b3cfae1e44ea996dc5d686cf25fa053fb6f67201b9e46eade85d0ad6b806"), BLAKE2S_OUTBYTES); + + blake2s_Key(fromhex("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f"), 112, key, BLAKE2S_KEYBYTES, digest, BLAKE2S_OUTBYTES); + ck_assert_mem_eq(digest, fromhex("90a83585717b75f0e9b725e055eeeeb9e7a028ea7e6cbc07b20917ec0363e38c"), BLAKE2S_OUTBYTES); +} +END_TEST + // test vectors from https://stackoverflow.com/questions/5130513/pbkdf2-hmac-sha2-test-vectors START_TEST(test_pbkdf2_hmac_sha256) { @@ -2786,12 +2849,18 @@ Suite *test_suite(void) tcase_add_test(tc, test_aes); suite_add_tcase(s, tc); - tc = tcase_create("sha256"); + tc = tcase_create("sha2"); tcase_add_test(tc, test_sha256); + tcase_add_test(tc, test_sha512); suite_add_tcase(s, tc); - tc = tcase_create("sha512"); - tcase_add_test(tc, test_sha512); + tc = tcase_create("sha3"); + tcase_add_test(tc, test_sha3_256); + tcase_add_test(tc, test_sha3_512); + suite_add_tcase(s, tc); + + tc = tcase_create("blake2s"); + tcase_add_test(tc, test_blake2s); suite_add_tcase(s, tc); tc = tcase_create("pbkdf2"); From a91e005633fa6950a95beae58f49561a29cc0053 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 1 Nov 2016 16:32:44 +0100 Subject: [PATCH 351/627] extract block size and digest size as macros in ripemd160 --- ripemd160.c | 16 ++++++++-------- ripemd160.h | 9 ++++++--- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/ripemd160.c b/ripemd160.c index ef9e76485..031f42202 100644 --- a/ripemd160.c +++ b/ripemd160.c @@ -70,7 +70,7 @@ void ripemd160_Init(RIPEMD160_CTX *ctx) /* * Process one block */ -void ripemd160_process( RIPEMD160_CTX *ctx, const uint8_t data[64] ) +void ripemd160_process( RIPEMD160_CTX *ctx, const uint8_t data[RIPEMD160_BLOCK_LENGTH] ) { uint32_t A, B, C, D, E, Ap, Bp, Cp, Dp, Ep, X[16]; @@ -260,7 +260,7 @@ void ripemd160_Update( RIPEMD160_CTX *ctx, const uint8_t *input, uint32_t ilen ) return; left = ctx->total[0] & 0x3F; - fill = 64 - left; + fill = RIPEMD160_BLOCK_LENGTH - left; ctx->total[0] += (uint32_t) ilen; ctx->total[0] &= 0xFFFFFFFF; @@ -277,11 +277,11 @@ void ripemd160_Update( RIPEMD160_CTX *ctx, const uint8_t *input, uint32_t ilen ) left = 0; } - while( ilen >= 64 ) + while( ilen >= RIPEMD160_BLOCK_LENGTH ) { ripemd160_process( ctx, input ); - input += 64; - ilen -= 64; + input += RIPEMD160_BLOCK_LENGTH; + ilen -= RIPEMD160_BLOCK_LENGTH; } if( ilen > 0 ) @@ -290,7 +290,7 @@ void ripemd160_Update( RIPEMD160_CTX *ctx, const uint8_t *input, uint32_t ilen ) } } -static const uint8_t ripemd160_padding[64] = +static const uint8_t ripemd160_padding[RIPEMD160_BLOCK_LENGTH] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -301,7 +301,7 @@ static const uint8_t ripemd160_padding[64] = /* * RIPEMD-160 final digest */ -void ripemd160_Final( RIPEMD160_CTX *ctx, uint8_t output[20] ) +void ripemd160_Final( RIPEMD160_CTX *ctx, uint8_t output[RIPEMD160_DIGEST_LENGTH] ) { uint32_t last, padn; uint32_t high, low; @@ -330,7 +330,7 @@ void ripemd160_Final( RIPEMD160_CTX *ctx, uint8_t output[20] ) /* * output = RIPEMD-160( input buffer ) */ -void ripemd160(const uint8_t *msg, uint32_t msg_len, uint8_t hash[20]) +void ripemd160(const uint8_t *msg, uint32_t msg_len, uint8_t hash[RIPEMD160_DIGEST_LENGTH]) { RIPEMD160_CTX ctx; ripemd160_Init( &ctx ); diff --git a/ripemd160.h b/ripemd160.h index 8b1454bed..a62de5cfc 100644 --- a/ripemd160.h +++ b/ripemd160.h @@ -3,15 +3,18 @@ #include +#define RIPEMD160_BLOCK_LENGTH 64 +#define RIPEMD160_DIGEST_LENGTH 20 + typedef struct _RIPEMD160_CTX { uint32_t total[2]; /*!< number of bytes processed */ uint32_t state[5]; /*!< intermediate digest state */ - uint8_t buffer[64]; /*!< data block being processed */ + uint8_t buffer[RIPEMD160_BLOCK_LENGTH]; /*!< data block being processed */ } RIPEMD160_CTX; void ripemd160_Init(RIPEMD160_CTX *ctx); void ripemd160_Update(RIPEMD160_CTX *ctx, const uint8_t *input, uint32_t ilen); -void ripemd160_Final(RIPEMD160_CTX *ctx, uint8_t output[20]); -void ripemd160(const uint8_t *msg, uint32_t msg_len, uint8_t hash[20]); +void ripemd160_Final(RIPEMD160_CTX *ctx, uint8_t output[RIPEMD160_DIGEST_LENGTH]); +void ripemd160(const uint8_t *msg, uint32_t msg_len, uint8_t hash[RIPEMD160_DIGEST_LENGTH]); #endif From 1b79c93bbcdc20ac89beece37380e6b24a23c4d4 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Thu, 29 Sep 2016 17:12:55 +0100 Subject: [PATCH 352/627] sha2: NIST FIPS 180-2 naming conventions --- sha2.c | 48 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 16 deletions(-) diff --git a/sha2.c b/sha2.c index 5831e3dd9..1af4413c9 100644 --- a/sha2.c +++ b/sha2.c @@ -114,33 +114,49 @@ typedef uint64_t sha2_word64; /* Exactly 8 bytes */ /* * Bit shifting and rotation (used by the six SHA-XYZ logical functions: * - * NOTE: The naming of R and S appears backwards here (R is a SHIFT and - * S is a ROTATION) because the SHA-256/384/512 description document - * (see http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf) uses this - * same "backwards" definition. + * NOTE: In the original SHA-256/384/512 document, the shift-right + * function was named R and the rotate-right function was called S. + * (See: http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf on the + * web.) + * + * The newer NIST FIPS 180-2 document uses a much clearer naming + * scheme, SHR for shift-right, ROTR for rotate-right, and ROTL for + * rotate-left. (See: + * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf + * on the web.) + * + * WARNING: These macros must be used cautiously, since they reference + * supplied parameters sometimes more than once, and thus could have + * unexpected side-effects if used without taking this into account. */ + /* Shift-right (used in SHA-256, SHA-384, and SHA-512): */ -#define R(b,x) ((x) >> (b)) +#define SHR(b,x) ((x) >> (b)) /* 32-bit Rotate-right (used in SHA-256): */ -#define S32(b,x) (((x) >> (b)) | ((x) << (32 - (b)))) +#define ROTR32(b,x) (((x) >> (b)) | ((x) << (32 - (b)))) /* 64-bit Rotate-right (used in SHA-384 and SHA-512): */ -#define S64(b,x) (((x) >> (b)) | ((x) << (64 - (b)))) +#define ROTR64(b,x) (((x) >> (b)) | ((x) << (64 - (b)))) +/* 32-bit Rotate-left (used in SHA-1): */ +#define ROTL32(b,x) (((x) << (b)) | ((x) >> (32 - (b)))) -/* Two of six logical functions used in SHA-256, SHA-384, and SHA-512: */ +/* Two of six logical functions used in SHA-1, SHA-256, SHA-384, and SHA-512: */ #define Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z))) #define Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) +/* Function used in SHA-1: */ +#define Parity(x,y,z) ((x) ^ (y) ^ (z)) + /* Four of six logical functions used in SHA-256: */ -#define Sigma0_256(x) (S32(2, (x)) ^ S32(13, (x)) ^ S32(22, (x))) -#define Sigma1_256(x) (S32(6, (x)) ^ S32(11, (x)) ^ S32(25, (x))) -#define sigma0_256(x) (S32(7, (x)) ^ S32(18, (x)) ^ R(3 , (x))) -#define sigma1_256(x) (S32(17, (x)) ^ S32(19, (x)) ^ R(10, (x))) +#define Sigma0_256(x) (ROTR32(2, (x)) ^ ROTR32(13, (x)) ^ ROTR32(22, (x))) +#define Sigma1_256(x) (ROTR32(6, (x)) ^ ROTR32(11, (x)) ^ ROTR32(25, (x))) +#define sigma0_256(x) (ROTR32(7, (x)) ^ ROTR32(18, (x)) ^ SHR(3 , (x))) +#define sigma1_256(x) (ROTR32(17, (x)) ^ ROTR32(19, (x)) ^ SHR(10, (x))) /* Four of six logical functions used in SHA-384 and SHA-512: */ -#define Sigma0_512(x) (S64(28, (x)) ^ S64(34, (x)) ^ S64(39, (x))) -#define Sigma1_512(x) (S64(14, (x)) ^ S64(18, (x)) ^ S64(41, (x))) -#define sigma0_512(x) (S64( 1, (x)) ^ S64( 8, (x)) ^ R( 7, (x))) -#define sigma1_512(x) (S64(19, (x)) ^ S64(61, (x)) ^ R( 6, (x))) +#define Sigma0_512(x) (ROTR64(28, (x)) ^ ROTR64(34, (x)) ^ ROTR64(39, (x))) +#define Sigma1_512(x) (ROTR64(14, (x)) ^ ROTR64(18, (x)) ^ ROTR64(41, (x))) +#define sigma0_512(x) (ROTR64( 1, (x)) ^ ROTR64( 8, (x)) ^ SHR( 7, (x))) +#define sigma1_512(x) (ROTR64(19, (x)) ^ ROTR64(61, (x)) ^ SHR( 6, (x))) /*** INTERNAL FUNCTION PROTOTYPES *************************************/ /* NOTE: These should not be accessed directly from outside this From 0acfb2cf285dad712d05867692863c6b4deab099 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Thu, 29 Sep 2016 17:13:25 +0100 Subject: [PATCH 353/627] tests: add SHA1 test --- tests.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/tests.c b/tests.c index 23da04230..0040705c2 100644 --- a/tests.c +++ b/tests.c @@ -1604,6 +1604,57 @@ END_TEST "\x6a\x0f\x85\xe6\xa9\x1d\x39\x6f\x5b\x5c\xbe\x57\x7f\x9b\x38\x80" \ "\x7c\x7d\x52\x3d\x6d\x79\x2f\x6e\xbc\x24\xa4\xec\xf2\xb3\xa4\x27" \ "\xcd\xbb\xfb" +#define length(x) (sizeof(x)-1) + +// test vectors from rfc-4634 +START_TEST(test_sha1) +{ + struct { + const char* test; + int length; + int repeatcount; + int extrabits; + int numberExtrabits; + const char* result; + } tests[] = { + /* 1 */ { TEST1, length(TEST1), 1, 0, 0, + "A9993E364706816ABA3E25717850C26C9CD0D89D" }, + /* 2 */ { TEST2_1, length(TEST2_1), 1, 0, 0, + "84983E441C3BD26EBAAE4AA1F95129E5E54670F1" }, + /* 3 */ { TEST3, length(TEST3), 1000000, 0, 0, + "34AA973CD4C4DAA4F61EEB2BDBAD27316534016F" }, + /* 4 */ { TEST4, length(TEST4), 10, 0, 0, + "DEA356A2CDDD90C7A7ECEDC5EBB563934F460452" }, + /* 5 */ { "", 0, 0, 0x98, 5, + "29826B003B906E660EFF4027CE98AF3531AC75BA" }, + /* 6 */ { "\x5e", 1, 1, 0, 0, + "5E6F80A34A9798CAFC6A5DB96CC57BA4C4DB59C2" }, + /* 7 */ { TEST7_1, length(TEST7_1), 1, 0x80, 3, + "6239781E03729919C01955B3FFA8ACB60B988340" }, + /* 8 */ { TEST8_1, length(TEST8_1), 1, 0, 0, + "82ABFF6605DBE1C17DEF12A394FA22A82B544A35" }, + /* 9 */ { TEST9_1, length(TEST9_1), 1, 0xE0, 3, + "8C5B2A5DDAE5A97FC7F9D85661C672ADBF7933D4" }, + /* 10 */ { TEST10_1, length(TEST10_1), 1, 0, 0, + "CB0082C8F197D260991BA6A460E76E202BAD27B3" } + }; + + for (int i = 0; i < 10; i++) { + SHA1_CTX ctx; + uint8_t digest[SHA1_DIGEST_LENGTH]; + sha1_Init(&ctx); + /* extra bits are not supported */ + if (tests[i].numberExtrabits) + continue; + for (int j = 0; j < tests[i].repeatcount; j++) { + sha1_Update(&ctx, (const uint8_t*) tests[i].test, tests[i].length); + } + sha1_Final(&ctx, digest); + ck_assert_mem_eq(digest, fromhex(tests[i].result), SHA1_DIGEST_LENGTH); + } +} +END_TEST + #define TEST7_256 \ "\xbe\x27\x46\xc6\xdb\x52\x76\x5f\xdb\x2f\x88\x70\x0f\x9a\x73" #define TEST8_256 \ @@ -1626,7 +1677,6 @@ END_TEST "\xa9\x7d\x13\x8f\x12\x92\x28\x96\x6f\x6c\x0a\xdc\x10\x6a\xad\x5a" \ "\x9f\xdd\x30\x82\x57\x69\xb2\xc6\x71\xaf\x67\x59\xdf\x28\xeb\x39" \ "\x3d\x54\xd6" -#define length(x) (sizeof(x)-1) // test vectors from rfc-4634 START_TEST(test_sha256) @@ -2850,6 +2900,7 @@ Suite *test_suite(void) suite_add_tcase(s, tc); tc = tcase_create("sha2"); + tcase_add_test(tc, test_sha1); tcase_add_test(tc, test_sha256); tcase_add_test(tc, test_sha512); suite_add_tcase(s, tc); From d812c7209f7100583dc011485f02c9660b8c1911 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Thu, 29 Sep 2016 17:13:39 +0100 Subject: [PATCH 354/627] sha2: import SHA1 implementation --- sha2.c | 418 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ sha2.h | 16 +++ 2 files changed, 434 insertions(+) diff --git a/sha2.c b/sha2.c index 1af4413c9..a556f8e05 100644 --- a/sha2.c +++ b/sha2.c @@ -92,6 +92,7 @@ typedef uint64_t sha2_word64; /* Exactly 8 bytes */ /*** SHA-256/384/512 Various Length Definitions ***********************/ /* NOTE: Most of these are in sha2.h */ +#define SHA1_SHORT_BLOCK_LENGTH (SHA1_BLOCK_LENGTH - 8) #define SHA256_SHORT_BLOCK_LENGTH (SHA256_BLOCK_LENGTH - 8) #define SHA512_SHORT_BLOCK_LENGTH (SHA512_BLOCK_LENGTH - 16) @@ -167,6 +168,22 @@ static void sha512_Last(SHA512_CTX*); /*** SHA-XYZ INITIAL HASH VALUES AND CONSTANTS ************************/ + +/* Hash constant words K for SHA-1: */ +#define K1_0_TO_19 0x5a827999UL +#define K1_20_TO_39 0x6ed9eba1UL +#define K1_40_TO_59 0x8f1bbcdcUL +#define K1_60_TO_79 0xca62c1d6UL + +/* Initial hash value H for SHA-1: */ +const sha2_word32 sha1_initial_hash_value[SHA1_DIGEST_LENGTH / sizeof(sha2_word32)] = { + 0x67452301UL, + 0xefcdab89UL, + 0x98badcfeUL, + 0x10325476UL, + 0xc3d2e1f0UL +}; + /* Hash constant words K for SHA-256: */ static const sha2_word32 K256[64] = { 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, @@ -262,6 +279,407 @@ const sha2_word64 sha512_initial_hash_value[8] = { static const char *sha2_hex_digits = "0123456789abcdef"; +/*** SHA-1: ***********************************************************/ +void sha1_Init(SHA1_CTX* context) { + MEMCPY_BCOPY(context->state, sha1_initial_hash_value, SHA1_DIGEST_LENGTH); + MEMSET_BZERO(context->buffer, SHA1_BLOCK_LENGTH); + context->bitcount = 0; +} + +#ifdef SHA2_UNROLL_TRANSFORM + +/* Unrolled SHA-1 round macros: */ + +#if BYTE_ORDER == LITTLE_ENDIAN + +#define ROUND1_0_TO_15(a,b,c,d,e) \ + REVERSE32(*data++, W1[j]); \ + (e) = ROTL32(5, (a)) + Ch((b), (c), (d)) + (e) + \ + K1_0_TO_19 + W1[j]; \ + (b) = ROTL32(30, (b)); \ + j++; + +#else /* BYTE_ORDER == LITTLE_ENDIAN */ + +#define ROUND1_0_TO_15(a,b,c,d,e) \ + (e) = ROTL32(5, (a)) + Ch((b), (c), (d)) + (e) + \ + K1_0_TO_19 + ( W1[j] = *data++ ); \ + (b) = ROTL32(30, (b)); \ + j++; + +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ + +#define ROUND1_16_TO_19(a,b,c,d,e) \ + T1 = W1[(j+13)&0x0f] ^ W1[(j+8)&0x0f] ^ W1[(j+2)&0x0f] ^ W1[j&0x0f]; \ + (e) = ROTL32(5, a) + Ch(b,c,d) + e + K1_0_TO_19 + ( W1[j&0x0f] = ROTL32(1, T1) ); \ + (b) = ROTL32(30, b); \ + j++; + +#define ROUND1_20_TO_39(a,b,c,d,e) \ + T1 = W1[(j+13)&0x0f] ^ W1[(j+8)&0x0f] ^ W1[(j+2)&0x0f] ^ W1[j&0x0f]; \ + (e) = ROTL32(5, a) + Parity(b,c,d) + e + K1_20_TO_39 + ( W1[j&0x0f] = ROTL32(1, T1) ); \ + (b) = ROTL32(30, b); \ + j++; + +#define ROUND1_40_TO_59(a,b,c,d,e) \ + T1 = W1[(j+13)&0x0f] ^ W1[(j+8)&0x0f] ^ W1[(j+2)&0x0f] ^ W1[j&0x0f]; \ + (e) = ROTL32(5, a) + Maj(b,c,d) + e + K1_40_TO_59 + ( W1[j&0x0f] = ROTL32(1, T1) ); \ + (b) = ROTL32(30, b); \ + j++; + +#define ROUND1_60_TO_79(a,b,c,d,e) \ + T1 = W1[(j+13)&0x0f] ^ W1[(j+8)&0x0f] ^ W1[(j+2)&0x0f] ^ W1[j&0x0f]; \ + (e) = ROTL32(5, a) + Parity(b,c,d) + e + K1_60_TO_79 + ( W1[j&0x0f] = ROTL32(1, T1) ); \ + (b) = ROTL32(30, b); \ + j++; + +void sha1_Transform(const sha2_word32* state_in, const sha2_word32* data, sha2_word32* state_out) { + sha2_word32 a, b, c, d, e; + sha2_word32 T1; + sha2_word32 W1[16]; + int j; + + /* Initialize registers with the prev. intermediate value */ + a = state_in[0]; + b = state_in[1]; + c = state_in[2]; + d = state_in[3]; + e = state_in[4]; + + j = 0; + + /* Rounds 0 to 15 unrolled: */ + ROUND1_0_TO_15(a,b,c,d,e); + ROUND1_0_TO_15(e,a,b,c,d); + ROUND1_0_TO_15(d,e,a,b,c); + ROUND1_0_TO_15(c,d,e,a,b); + ROUND1_0_TO_15(b,c,d,e,a); + ROUND1_0_TO_15(a,b,c,d,e); + ROUND1_0_TO_15(e,a,b,c,d); + ROUND1_0_TO_15(d,e,a,b,c); + ROUND1_0_TO_15(c,d,e,a,b); + ROUND1_0_TO_15(b,c,d,e,a); + ROUND1_0_TO_15(a,b,c,d,e); + ROUND1_0_TO_15(e,a,b,c,d); + ROUND1_0_TO_15(d,e,a,b,c); + ROUND1_0_TO_15(c,d,e,a,b); + ROUND1_0_TO_15(b,c,d,e,a); + ROUND1_0_TO_15(a,b,c,d,e); + + /* Rounds 16 to 19 unrolled: */ + ROUND1_16_TO_19(e,a,b,c,d); + ROUND1_16_TO_19(d,e,a,b,c); + ROUND1_16_TO_19(c,d,e,a,b); + ROUND1_16_TO_19(b,c,d,e,a); + + /* Rounds 20 to 39 unrolled: */ + ROUND1_20_TO_39(a,b,c,d,e); + ROUND1_20_TO_39(e,a,b,c,d); + ROUND1_20_TO_39(d,e,a,b,c); + ROUND1_20_TO_39(c,d,e,a,b); + ROUND1_20_TO_39(b,c,d,e,a); + ROUND1_20_TO_39(a,b,c,d,e); + ROUND1_20_TO_39(e,a,b,c,d); + ROUND1_20_TO_39(d,e,a,b,c); + ROUND1_20_TO_39(c,d,e,a,b); + ROUND1_20_TO_39(b,c,d,e,a); + ROUND1_20_TO_39(a,b,c,d,e); + ROUND1_20_TO_39(e,a,b,c,d); + ROUND1_20_TO_39(d,e,a,b,c); + ROUND1_20_TO_39(c,d,e,a,b); + ROUND1_20_TO_39(b,c,d,e,a); + ROUND1_20_TO_39(a,b,c,d,e); + ROUND1_20_TO_39(e,a,b,c,d); + ROUND1_20_TO_39(d,e,a,b,c); + ROUND1_20_TO_39(c,d,e,a,b); + ROUND1_20_TO_39(b,c,d,e,a); + + /* Rounds 40 to 59 unrolled: */ + ROUND1_40_TO_59(a,b,c,d,e); + ROUND1_40_TO_59(e,a,b,c,d); + ROUND1_40_TO_59(d,e,a,b,c); + ROUND1_40_TO_59(c,d,e,a,b); + ROUND1_40_TO_59(b,c,d,e,a); + ROUND1_40_TO_59(a,b,c,d,e); + ROUND1_40_TO_59(e,a,b,c,d); + ROUND1_40_TO_59(d,e,a,b,c); + ROUND1_40_TO_59(c,d,e,a,b); + ROUND1_40_TO_59(b,c,d,e,a); + ROUND1_40_TO_59(a,b,c,d,e); + ROUND1_40_TO_59(e,a,b,c,d); + ROUND1_40_TO_59(d,e,a,b,c); + ROUND1_40_TO_59(c,d,e,a,b); + ROUND1_40_TO_59(b,c,d,e,a); + ROUND1_40_TO_59(a,b,c,d,e); + ROUND1_40_TO_59(e,a,b,c,d); + ROUND1_40_TO_59(d,e,a,b,c); + ROUND1_40_TO_59(c,d,e,a,b); + ROUND1_40_TO_59(b,c,d,e,a); + + /* Rounds 60 to 79 unrolled: */ + ROUND1_60_TO_79(a,b,c,d,e); + ROUND1_60_TO_79(e,a,b,c,d); + ROUND1_60_TO_79(d,e,a,b,c); + ROUND1_60_TO_79(c,d,e,a,b); + ROUND1_60_TO_79(b,c,d,e,a); + ROUND1_60_TO_79(a,b,c,d,e); + ROUND1_60_TO_79(e,a,b,c,d); + ROUND1_60_TO_79(d,e,a,b,c); + ROUND1_60_TO_79(c,d,e,a,b); + ROUND1_60_TO_79(b,c,d,e,a); + ROUND1_60_TO_79(a,b,c,d,e); + ROUND1_60_TO_79(e,a,b,c,d); + ROUND1_60_TO_79(d,e,a,b,c); + ROUND1_60_TO_79(c,d,e,a,b); + ROUND1_60_TO_79(b,c,d,e,a); + ROUND1_60_TO_79(a,b,c,d,e); + ROUND1_60_TO_79(e,a,b,c,d); + ROUND1_60_TO_79(d,e,a,b,c); + ROUND1_60_TO_79(c,d,e,a,b); + ROUND1_60_TO_79(b,c,d,e,a); + + /* Compute the current intermediate hash value */ + state_out[0] = state_in[0] + a; + state_out[1] = state_in[1] + b; + state_out[2] = state_in[2] + c; + state_out[3] = state_in[3] + d; + state_out[4] = state_in[4] + e; + + /* Clean up */ + a = b = c = d = e = T1 = 0; +} + +#else /* SHA2_UNROLL_TRANSFORM */ + +void sha1_Transform(const sha2_word32* state_in, const sha2_word32* data, sha2_word32* state_out) { + sha2_word32 a, b, c, d, e; + sha2_word32 T1; + sha2_word32 W1[16]; + int j; + + /* Initialize registers with the prev. intermediate value */ + a = state_in[0]; + b = state_in[1]; + c = state_in[2]; + d = state_in[3]; + e = state_in[4]; + j = 0; + do { +#if BYTE_ORDER == LITTLE_ENDIAN + T1 = data[j]; + /* Copy data while converting to host byte order */ + REVERSE32(*data++, W1[j]); + T1 = ROTL32(5, a) + Ch(b, c, d) + e + K1_0_TO_19 + W1[j]; +#else /* BYTE_ORDER == LITTLE_ENDIAN */ + T1 = ROTL32(5, a) + Ch(b, c, d) + e + K1_0_TO_19 + (W1[j] = *data++); +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ + e = d; + d = c; + c = ROTL32(30, b); + b = a; + a = T1; + j++; + } while (j < 16); + + do { + T1 = W1[(j+13)&0x0f] ^ W1[(j+8)&0x0f] ^ W1[(j+2)&0x0f] ^ W1[j&0x0f]; + T1 = ROTL32(5, a) + Ch(b,c,d) + e + K1_0_TO_19 + (W1[j&0x0f] = ROTL32(1, T1)); + e = d; + d = c; + c = ROTL32(30, b); + b = a; + a = T1; + j++; + } while (j < 20); + + do { + T1 = W1[(j+13)&0x0f] ^ W1[(j+8)&0x0f] ^ W1[(j+2)&0x0f] ^ W1[j&0x0f]; + T1 = ROTL32(5, a) + Parity(b,c,d) + e + K1_20_TO_39 + (W1[j&0x0f] = ROTL32(1, T1)); + e = d; + d = c; + c = ROTL32(30, b); + b = a; + a = T1; + j++; + } while (j < 40); + + do { + T1 = W1[(j+13)&0x0f] ^ W1[(j+8)&0x0f] ^ W1[(j+2)&0x0f] ^ W1[j&0x0f]; + T1 = ROTL32(5, a) + Maj(b,c,d) + e + K1_40_TO_59 + (W1[j&0x0f] = ROTL32(1, T1)); + e = d; + d = c; + c = ROTL32(30, b); + b = a; + a = T1; + j++; + } while (j < 60); + + do { + T1 = W1[(j+13)&0x0f] ^ W1[(j+8)&0x0f] ^ W1[(j+2)&0x0f] ^ W1[j&0x0f]; + T1 = ROTL32(5, a) + Parity(b,c,d) + e + K1_60_TO_79 + (W1[j&0x0f] = ROTL32(1, T1)); + e = d; + d = c; + c = ROTL32(30, b); + b = a; + a = T1; + j++; + } while (j < 80); + + + /* Compute the current intermediate hash value */ + state_out[0] = state_in[0] + a; + state_out[1] = state_in[1] + b; + state_out[2] = state_in[2] + c; + state_out[3] = state_in[3] + d; + state_out[4] = state_in[4] + e; + + /* Clean up */ + a = b = c = d = e = T1 = 0; +} + +#endif /* SHA2_UNROLL_TRANSFORM */ + +void sha1_Update(SHA1_CTX* context, const sha2_byte *data, size_t len) { + unsigned int freespace, usedspace; + if (len == 0) { + /* Calling with no data is valid - we do nothing */ + return; + } + + usedspace = (context->bitcount >> 3) % SHA1_BLOCK_LENGTH; + if (usedspace > 0) { + /* Calculate how much free space is available in the buffer */ + freespace = SHA1_BLOCK_LENGTH - usedspace; + + if (len >= freespace) { + /* Fill the buffer completely and process it */ + MEMCPY_BCOPY(((uint8_t*)context->buffer) + usedspace, data, freespace); + context->bitcount += freespace << 3; + len -= freespace; + data += freespace; + sha1_Transform(context->state, context->buffer, context->state); + } else { + /* The buffer is not yet full */ + MEMCPY_BCOPY(((uint8_t*)context->buffer) + usedspace, data, len); + context->bitcount += len << 3; + /* Clean up: */ + usedspace = freespace = 0; + return; + } + } + while (len >= SHA1_BLOCK_LENGTH) { + /* Process as many complete blocks as we can */ + sha1_Transform(context->state, (sha2_word32*)data, context->state); + context->bitcount += SHA1_BLOCK_LENGTH << 3; + len -= SHA1_BLOCK_LENGTH; + data += SHA1_BLOCK_LENGTH; + } + if (len > 0) { + /* There's left-overs, so save 'em */ + MEMCPY_BCOPY(context->buffer, data, len); + context->bitcount += len << 3; + } + /* Clean up: */ + usedspace = freespace = 0; +} + +void sha1_Final(SHA1_CTX* context, sha2_byte digest[]) { + sha2_word32 *d = (sha2_word32*)digest; + unsigned int usedspace; + + if (digest == (sha2_byte*)0) { + /* + * No digest buffer, so we can do nothing + * except clean up and go home + */ + MEMSET_BZERO(context, sizeof(context)); + return; + } + + usedspace = (context->bitcount >> 3) % SHA1_BLOCK_LENGTH; + if (usedspace == 0) { + /* Set-up for the last transform: */ + MEMSET_BZERO(context->buffer, SHA1_SHORT_BLOCK_LENGTH); + + /* Begin padding with a 1 bit: */ + *context->buffer = 0x80; + } else { + /* Begin padding with a 1 bit: */ + ((uint8_t*)context->buffer)[usedspace++] = 0x80; + + if (usedspace <= 56) { + /* Set-up for the last transform: */ + MEMSET_BZERO(((uint8_t*)context->buffer) + usedspace, 56 - usedspace); + } else { + if (usedspace < 64) { + MEMSET_BZERO(((uint8_t*)context->buffer) + usedspace, 64 - usedspace); + } + /* Do second-to-last transform: */ + sha1_Transform(context->state, context->buffer, context->state); + + /* And set-up for the last transform: */ + MEMSET_BZERO(context->buffer, 56); + } + /* Clean up: */ + usedspace = 0; + } + /* Set the bit count: */ +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert FROM host byte order */ + REVERSE64(context->bitcount,context->bitcount); +#endif + context->buffer[SHA1_SHORT_BLOCK_LENGTH >> 2] = context->bitcount << 32; + context->buffer[SHA1_SHORT_BLOCK_LENGTH >> 2 | 1] = context->bitcount >> 32; + + /* Final transform: */ + sha1_Transform(context->state, context->buffer, context->state); + + /* Save the hash data for output: */ +#if BYTE_ORDER == LITTLE_ENDIAN + { + /* Convert TO host byte order */ + int j; + for (j = 0; j < (SHA1_DIGEST_LENGTH >> 2); j++) { + REVERSE32(context->state[j],context->state[j]); + *d++ = context->state[j]; + } + } +#else + MEMCPY_BCOPY(d, context->state, SHA1_DIGEST_LENGTH); +#endif + + /* Clean up: */ + MEMSET_BZERO(context, sizeof(context)); +} + +char *sha1_End(SHA1_CTX* context, char buffer[]) { + sha2_byte digest[SHA1_DIGEST_LENGTH], *d = digest; + int i; + + if (buffer != (char*)0) { + sha1_Final(context, digest); + + for (i = 0; i < SHA1_DIGEST_LENGTH; i++) { + *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; + *buffer++ = sha2_hex_digits[*d & 0x0f]; + d++; + } + *buffer = (char)0; + } else { + MEMSET_BZERO(context, sizeof(context)); + } + MEMSET_BZERO(digest, SHA1_DIGEST_LENGTH); + return buffer; +} + +char* sha1_Data(const sha2_byte* data, size_t len, char digest[SHA1_DIGEST_STRING_LENGTH]) { + SHA1_CTX context; + + sha1_Init(&context); + sha1_Update(&context, data, len); + return sha1_End(&context, digest); +} + /*** SHA-256: *********************************************************/ void sha256_Init(SHA256_CTX* context) { if (context == (SHA256_CTX*)0) { diff --git a/sha2.h b/sha2.h index 7c2a0bd30..7f519c50b 100644 --- a/sha2.h +++ b/sha2.h @@ -34,6 +34,9 @@ #include #include +#define SHA1_BLOCK_LENGTH 64 +#define SHA1_DIGEST_LENGTH 20 +#define SHA1_DIGEST_STRING_LENGTH (SHA1_DIGEST_LENGTH * 2 + 1) #define SHA256_BLOCK_LENGTH 64 #define SHA256_DIGEST_LENGTH 32 #define SHA256_DIGEST_STRING_LENGTH (SHA256_DIGEST_LENGTH * 2 + 1) @@ -41,6 +44,11 @@ #define SHA512_DIGEST_LENGTH 64 #define SHA512_DIGEST_STRING_LENGTH (SHA512_DIGEST_LENGTH * 2 + 1) +typedef struct _SHA1_CTX { + uint32_t state[5]; + uint64_t bitcount; + uint32_t buffer[SHA1_BLOCK_LENGTH/sizeof(uint32_t)]; +} SHA1_CTX; typedef struct _SHA256_CTX { uint32_t state[8]; uint64_t bitcount; @@ -81,6 +89,14 @@ typedef struct _SHA512_CTX { extern const uint32_t sha256_initial_hash_value[8]; extern const uint64_t sha512_initial_hash_value[8]; +void sha1_Transform(const uint32_t* state_in, const uint32_t* data, uint32_t* state_out); +void sha1_Init(SHA1_CTX *); +void sha1_Update(SHA1_CTX*, const uint8_t*, size_t); +void sha1_Final(SHA1_CTX*, uint8_t[SHA1_DIGEST_LENGTH]); +char* sha1_End(SHA1_CTX*, char[SHA1_DIGEST_STRING_LENGTH]); +void sha1_Raw(const uint8_t*, size_t, uint8_t[SHA1_DIGEST_LENGTH]); +char* sha1_Data(const uint8_t*, size_t, char[SHA1_DIGEST_STRING_LENGTH]); + void sha256_Transform(const uint32_t* state_in, const uint32_t* data, uint32_t* state_out); void sha256_Init(SHA256_CTX *); void sha256_Update(SHA256_CTX*, const uint8_t*, size_t); From 19efbeef8dbb1595a1a88850f7da3bc8c7fb335f Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Thu, 29 Sep 2016 17:48:02 +0100 Subject: [PATCH 355/627] sha2: add sha1_Raw --- sha2.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sha2.c b/sha2.c index a556f8e05..dedf5a465 100644 --- a/sha2.c +++ b/sha2.c @@ -672,6 +672,13 @@ char *sha1_End(SHA1_CTX* context, char buffer[]) { return buffer; } +void sha1_Raw(const sha2_byte* data, size_t len, uint8_t digest[SHA1_DIGEST_LENGTH]) { + SHA1_CTX context; + sha1_Init(&context); + sha1_Update(&context, data, len); + sha1_Final(&context, digest); +} + char* sha1_Data(const sha2_byte* data, size_t len, char digest[SHA1_DIGEST_STRING_LENGTH]) { SHA1_CTX context; From e855c605297a28d83c9973f6cedc669173faa05e Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Sat, 5 Nov 2016 21:21:48 +0100 Subject: [PATCH 356/627] Use bn_add instead of bn_addmod (#80) The bip32 private key derivation used bn_addmod to handle wrap around. This was never sufficient as bn_addmod uses only bn_fast_mod, so an additional bn_mod is necessary. The bn_fast_mod helped when bn_mod was not side-channel safe. Now that bn_mod uses constant time code, we can get rid of the unnecessary bn_fast_mod step and use bn_add instead of bn_addmod. --- bip32.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bip32.c b/bip32.c index 19d45402d..ad9ea46b7 100644 --- a/bip32.c +++ b/bip32.c @@ -178,7 +178,7 @@ int hdnode_private_ckd(HDNode *inout, uint32_t i) if (!bn_is_less(&b, &inout->curve->params->order)) { // >= order failed = true; } else { - bn_addmod(&b, &a, &inout->curve->params->order); + bn_add(&b, &a); bn_mod(&b, &inout->curve->params->order); if (bn_is_zero(&b)) { failed = true; From bb61fb75d8bcb4bd67a036f2e35755451b6cbe9b Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 5 Nov 2016 22:26:54 +0100 Subject: [PATCH 357/627] segwit address sizes --- ecdsa.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ecdsa.h b/ecdsa.h index 7802d71df..7683d4f54 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -48,9 +48,9 @@ typedef struct { } ecdsa_curve; -#define MAX_ADDR_RAW_SIZE (4 + 20) +#define MAX_ADDR_RAW_SIZE (4 + 40) #define MAX_WIF_RAW_SIZE (4 + 32 + 1) -#define MAX_ADDR_SIZE (40) +#define MAX_ADDR_SIZE (54) #define MAX_WIF_SIZE (58) // rfc6979 pseudo random number generator state From e68267e04bb3cfc8a694b5bc63bc343542c9e6ae Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 6 Nov 2016 15:16:09 +0100 Subject: [PATCH 358/627] undef ALIGN macro in curve25519 --- curve25519-donna/curve25519-donna-portable.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/curve25519-donna/curve25519-donna-portable.h b/curve25519-donna/curve25519-donna-portable.h index 71da697d5..0f428730e 100644 --- a/curve25519-donna/curve25519-donna-portable.h +++ b/curve25519-donna/curve25519-donna-portable.h @@ -13,6 +13,7 @@ #define inline __forceinline #define DONNA_INLINE __forceinline #define DONNA_NOINLINE __declspec(noinline) + #undef ALIGN #define ALIGN(x) __declspec(align(x)) #define ROTL32(a,b) _rotl(a,b) #define ROTR32(a,b) _rotr(a,b) @@ -20,6 +21,7 @@ #include #define DONNA_INLINE inline __attribute__((always_inline)) #define DONNA_NOINLINE __attribute__((noinline)) + #undef ALIGN #define ALIGN(x) __attribute__((aligned(x))) #define ROTL32(a,b) (((a) << (b)) | ((a) >> (32 - b))) #define ROTR32(a,b) (((a) >> (b)) | ((a) << (32 - b))) From 949220ac0b8cf8fe773555626c084116e1b5de2a Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Sun, 6 Nov 2016 15:19:14 +0100 Subject: [PATCH 359/627] Protect signing against side-channel attack (#81) Signing uses the bn_inverse function that is prone to side-channel attacks. We randomize its argument by multiplying it with a random non-zero number. At the end we multiply again by the same number to cancel it out. Changed get_k_random to take the prime range as a second argument and to return a non-zero number. This function was previously only used for (non-rfc6979) signing and is now used for side-channel protection. --- ecdsa.c | 53 +++++++++++++++++++++++++++++------------------------ ecdsa.h | 2 +- 2 files changed, 30 insertions(+), 25 deletions(-) diff --git a/ecdsa.c b/ecdsa.c index 7e4d5b203..2b0f00cbd 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -191,13 +191,21 @@ typedef struct jacobian_curve_point { bignum256 x, y, z; } jacobian_curve_point; +// generate random K for signing/side-channel noise +void generate_k_random(bignum256 *k, const bignum256 *prime) { + do { + int i; + for (i = 0; i < 8; i++) { + k->val[i] = random32() & 0x3FFFFFFF; + } + k->val[8] = random32() & 0xFFFF; + // check that k is in range and not zero. + } while (bn_is_zero(k) || !bn_is_less(k, prime)); +} + void curve_to_jacobian(const curve_point *p, jacobian_curve_point *jp, const bignum256 *prime) { - int i; // randomize z coordinate - for (i = 0; i < 8; i++) { - jp->z.val[i] = random32() & 0x3FFFFFFF; - } - jp->z.val[8] = (random32() & 0x7fff) + 1; + generate_k_random(&jp->z, prime); jp->x = jp->z; bn_multiply(&jp->z, &jp->x, prime); @@ -649,15 +657,6 @@ int ecdh_multiply(const ecdsa_curve *curve, const uint8_t *priv_key, const uint8 return 0; } -// generate random K for signing -void generate_k_random(bignum256 *k) { - int i; - for (i = 0; i < 8; i++) { - k->val[i] = random32() & 0x3FFFFFFF; - } - k->val[8] = random32() & 0xFFFF; -} - void init_k_rfc6979(const uint8_t *priv_key, const uint8_t *hash, rfc6979_state *state) { uint8_t bx[2*32]; uint8_t buf[32 + 1 + 2*32]; @@ -733,7 +732,7 @@ int ecdsa_sign_digest(const ecdsa_curve *curve, const uint8_t *priv_key, const u { int i; curve_point R; - bignum256 k, z; + bignum256 k, z, randk; bignum256 *s = &R.y; uint8_t by; // signature recovery byte @@ -749,14 +748,14 @@ int ecdsa_sign_digest(const ecdsa_curve *curve, const uint8_t *priv_key, const u #if USE_RFC6979 // generate K deterministically generate_k_rfc6979(&k, &rng); -#else - // generate random number k - generate_k_random(&k); -#endif // if k is too big or too small, we don't like it if (bn_is_zero(&k) || !bn_is_less(&k, &curve->order)) { continue; } +#else + // generate random number k + generate_k_random(&k, &curve->order); +#endif // compute k*G scalar_multiply(curve, &k, &R); @@ -771,11 +770,15 @@ int ecdsa_sign_digest(const ecdsa_curve *curve, const uint8_t *priv_key, const u continue; } - bn_inverse(&k, &curve->order); - bn_read_be(priv_key, s); - bn_multiply(&R.x, s, &curve->order); - bn_add(s, &z); - bn_multiply(&k, s, &curve->order); + // randomize operations to counter side-channel attacks + generate_k_random(&randk, &curve->order); + bn_multiply(&randk, &k, &curve->order); // k*rand + bn_inverse(&k, &curve->order); // (k*rand)^-1 + bn_read_be(priv_key, s); // priv + bn_multiply(&R.x, s, &curve->order); // R.x*priv + bn_add(s, &z); // R.x*priv + z + bn_multiply(&k, s, &curve->order); // (k*rand)^-1 (R.x*priv + z) + bn_multiply(&randk, s, &curve->order); // k^-1 (R.x*priv + z) bn_mod(s, &curve->order); // if s is zero, we retry if (bn_is_zero(s)) { @@ -801,6 +804,7 @@ int ecdsa_sign_digest(const ecdsa_curve *curve, const uint8_t *priv_key, const u } MEMSET_BZERO(&k, sizeof(k)); + MEMSET_BZERO(&randk, sizeof(randk)); #if USE_RFC6979 MEMSET_BZERO(&rng, sizeof(rng)); #endif @@ -810,6 +814,7 @@ int ecdsa_sign_digest(const ecdsa_curve *curve, const uint8_t *priv_key, const u // Too many retries without a valid signature // -> fail with an error MEMSET_BZERO(&k, sizeof(k)); + MEMSET_BZERO(&randk, sizeof(randk)); #if USE_RFC6979 MEMSET_BZERO(&rng, sizeof(rng)); #endif diff --git a/ecdsa.h b/ecdsa.h index 7683d4f54..163558a7d 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -93,6 +93,6 @@ int ecdsa_sig_to_der(const uint8_t *sig, uint8_t *der); // Private void init_k_rfc6979(const uint8_t *priv_key, const uint8_t *hash, rfc6979_state *rng); void generate_k_rfc6979(bignum256 *k, rfc6979_state *rng); -void generate_k_random(bignum256 *k); +void generate_k_random(bignum256 *k, const bignum256 *prime); #endif From 20bb7e9b5c932c6afe112630a615f5cc74c6c056 Mon Sep 17 00:00:00 2001 From: Jan Pochyla Date: Sun, 6 Nov 2016 15:53:04 +0100 Subject: [PATCH 360/627] sha1: fix context zeroing --- sha2.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sha2.c b/sha2.c index dedf5a465..f6ca3072c 100644 --- a/sha2.c +++ b/sha2.c @@ -592,7 +592,7 @@ void sha1_Final(SHA1_CTX* context, sha2_byte digest[]) { * No digest buffer, so we can do nothing * except clean up and go home */ - MEMSET_BZERO(context, sizeof(context)); + MEMSET_BZERO(context, sizeof(SHA1_CTX)); return; } @@ -649,7 +649,7 @@ void sha1_Final(SHA1_CTX* context, sha2_byte digest[]) { #endif /* Clean up: */ - MEMSET_BZERO(context, sizeof(context)); + MEMSET_BZERO(context, sizeof(SHA1_CTX)); } char *sha1_End(SHA1_CTX* context, char buffer[]) { @@ -666,7 +666,7 @@ char *sha1_End(SHA1_CTX* context, char buffer[]) { } *buffer = (char)0; } else { - MEMSET_BZERO(context, sizeof(context)); + MEMSET_BZERO(context, sizeof(SHA1_CTX)); } MEMSET_BZERO(digest, SHA1_DIGEST_LENGTH); return buffer; From 6aac03d2d853eadaf9e91452b15381594fcf09b1 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Wed, 16 Nov 2016 21:58:12 +0000 Subject: [PATCH 361/627] CMakeLists: Allow use as a library (#82) This allows TrezorCrypto to be linked with by other CMake projects --- .travis.yml | 4 ++++ CMakeLists.txt | 14 ++++++++------ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9cfccfdf1..b1eb22536 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,8 +3,12 @@ language: c addons: apt: + sources: + - george-edison55-precise-backports # CMake 3.x packages: - check + - cmake # Travis CI comes with CMake 2.8.7, we need CMake 2.8.11 + - cmake-data - libssl-dev - python-pip diff --git a/CMakeLists.txt b/CMakeLists.txt index 361dfaf2d..9d6aeb245 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,21 +1,23 @@ -cmake_minimum_required(VERSION 2.6) +cmake_minimum_required(VERSION 2.8) set(SOURCES address.c aescrypt.c aeskey.c aes_modes.c aestab.c base58.c bignum.c bip32.c bip39.c ecdsa.c hmac.c nist256p1.c pbkdf2.c rand.c ripemd160.c secp256k1.c sha2.c ed25519-donna/ed25519.c sha3.c) -include_directories(ed25519-donna) -include_directories(curve25519-donna) + +add_library(TrezorCrypto STATIC ${SOURCES}) + +target_include_directories(TrezorCrypto PUBLIC .) +target_include_directories(TrezorCrypto PUBLIC ed25519-donna) +target_include_directories(TrezorCrypto PUBLIC curve25519-donna) # disable sequence point warnings where they are expected set_source_files_properties(aeskey.c PROPERTIES COMPILE_FLAGS -Wno-sequence-point) -set(CMAKE_C_FLAGS "-std=c99") +target_compile_options(TrezorCrypto PRIVATE "-std=c99") if(MSVC) set_source_files_properties(${SOURCES} PROPERTIES LANGUAGE CXX) endif(MSVC) -add_library(TrezorCrypto STATIC ${SOURCES}) - # Build trezor-crypto tests (requires OpenSSL) if (TREZOR_CRYPTO_TESTS) add_executable(tests tests.c) From b55473a01ecfd095d1f4bd068c8d3385b993b986 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 12 Dec 2016 12:06:42 +0100 Subject: [PATCH 362/627] add fingerprint output parameter to hdnode_private_ckd_cached function --- bip32.c | 9 ++++++++- bip32.h | 2 +- tests.c | 8 ++++---- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/bip32.c b/bip32.c index ad9ea46b7..5135efdc7 100644 --- a/bip32.c +++ b/bip32.c @@ -323,12 +323,16 @@ static struct { HDNode node; } private_ckd_cache[BIP32_CACHE_SIZE]; -int hdnode_private_ckd_cached(HDNode *inout, const uint32_t *i, size_t i_count) +int hdnode_private_ckd_cached(HDNode *inout, const uint32_t *i, size_t i_count, uint32_t *fingerprint) { if (i_count == 0) { + // no way how to compute parent fingerprint return 1; } if (i_count == 1) { + if (fingerprint) { + *fingerprint = hdnode_fingerprint(inout); + } if (hdnode_private_ckd(inout, i[0]) == 0) return 0; return 1; } @@ -372,6 +376,9 @@ int hdnode_private_ckd_cached(HDNode *inout, const uint32_t *i, size_t i_count) private_ckd_cache_index = (private_ckd_cache_index + 1) % BIP32_CACHE_SIZE; } + if (fingerprint) { + *fingerprint = hdnode_fingerprint(inout); + } if (hdnode_private_ckd(inout, i[i_count - 1]) == 0) return 0; return 1; diff --git a/bip32.h b/bip32.h index 8ec1614b4..3a3adaa34 100644 --- a/bip32.h +++ b/bip32.h @@ -59,7 +59,7 @@ int hdnode_public_ckd_address_optimized(const curve_point *pub, const uint8_t *p #if USE_BIP32_CACHE -int hdnode_private_ckd_cached(HDNode *inout, const uint32_t *i, size_t i_count); +int hdnode_private_ckd_cached(HDNode *inout, const uint32_t *i, size_t i_count, uint32_t *fingerprint); #endif diff --git a/tests.c b/tests.c index 0040705c2..2c917dcdd 100644 --- a/tests.c +++ b/tests.c @@ -817,7 +817,7 @@ START_TEST(test_bip32_cache_1) for (i = 0; i < 8; i++) { r = hdnode_private_ckd(&node1, ii[i]); ck_assert_int_eq(r, 1); } - r = hdnode_private_ckd_cached(&node2, ii, 8); ck_assert_int_eq(r, 1); + r = hdnode_private_ckd_cached(&node2, ii, 8, NULL); ck_assert_int_eq(r, 1); ck_assert_mem_eq(&node1, &node2, sizeof(HDNode)); hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, SECP256K1_NAME, &node1); @@ -828,7 +828,7 @@ START_TEST(test_bip32_cache_1) for (i = 0; i < 8; i++) { r = hdnode_private_ckd(&node1, ii[i]); ck_assert_int_eq(r, 1); } - r = hdnode_private_ckd_cached(&node2, ii, 8); ck_assert_int_eq(r, 1); + r = hdnode_private_ckd_cached(&node2, ii, 8, NULL); ck_assert_int_eq(r, 1); ck_assert_mem_eq(&node1, &node2, sizeof(HDNode)); // test different root node @@ -838,7 +838,7 @@ START_TEST(test_bip32_cache_1) for (i = 0; i < 8; i++) { r = hdnode_private_ckd(&node1, ii[i]); ck_assert_int_eq(r, 1); } - r = hdnode_private_ckd_cached(&node2, ii, 8); ck_assert_int_eq(r, 1); + r = hdnode_private_ckd_cached(&node2, ii, 8, NULL); ck_assert_int_eq(r, 1); ck_assert_mem_eq(&node1, &node2, sizeof(HDNode)); } END_TEST @@ -860,7 +860,7 @@ START_TEST(test_bip32_cache_2) r = hdnode_private_ckd(&(nodea[j]), ii[i - 1]); ck_assert_int_eq(r, 1); } // cached - r = hdnode_private_ckd_cached(&(nodeb[j]), ii, j); ck_assert_int_eq(r, 1); + r = hdnode_private_ckd_cached(&(nodeb[j]), ii, j, NULL); ck_assert_int_eq(r, 1); } ck_assert_mem_eq(&(nodea[0]), &(nodeb[0]), sizeof(HDNode)); From 9443aefa9abb2b872127671e77a5e98bf4c6074f Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Wed, 4 Jan 2017 14:33:00 +0100 Subject: [PATCH 363/627] Multi-byte prefix cleanup use the functions from address.c in ecdsa.c to avoid duplicated code. --- ecdsa.c | 80 ++++++++++----------------------------------------------- 1 file changed, 14 insertions(+), 66 deletions(-) diff --git a/ecdsa.c b/ecdsa.c index 2b0f00cbd..310dad325 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -27,6 +27,7 @@ #include #include +#include "address.h" #include "bignum.h" #include "rand.h" #include "sha2.h" @@ -881,40 +882,17 @@ void ecdsa_get_pubkeyhash(const uint8_t *pub_key, uint8_t *pubkeyhash) void ecdsa_get_address_raw(const uint8_t *pub_key, uint32_t version, uint8_t *addr_raw) { - if (version <= 0xFF) { - addr_raw[0] = version; - ecdsa_get_pubkeyhash(pub_key, addr_raw + 1); - } else if (version <= 0xFFFF) { - addr_raw[0] = version >> 8; - addr_raw[1] = version & 0xFF; - ecdsa_get_pubkeyhash(pub_key, addr_raw + 2); - } else if (version <= 0xFFFFFF) { - addr_raw[0] = version >> 16; - addr_raw[1] = (version >> 8) & 0xFF; - addr_raw[2] = version & 0xFF; - ecdsa_get_pubkeyhash(pub_key, addr_raw + 3); - } else { - addr_raw[0] = version >> 24; - addr_raw[1] = (version >> 16) & 0xFF; - addr_raw[2] = (version >> 8) & 0xFF; - addr_raw[3] = version & 0xFF; - ecdsa_get_pubkeyhash(pub_key, addr_raw + 4); - } + size_t prefix_len = address_prefix_bytes_len(version); + address_write_prefix_bytes(version, addr_raw); + ecdsa_get_pubkeyhash(pub_key, addr_raw + prefix_len); } void ecdsa_get_address(const uint8_t *pub_key, uint32_t version, char *addr, int addrsize) { uint8_t raw[MAX_ADDR_RAW_SIZE]; + size_t prefix_len = address_prefix_bytes_len(version); ecdsa_get_address_raw(pub_key, version, raw); - if (version <= 0xFF) { - base58_encode_check(raw, 21, addr, addrsize); - } else if (version <= 0xFFFF) { - base58_encode_check(raw, 22, addr, addrsize); - } else if (version <= 0xFFFFFF) { - base58_encode_check(raw, 23, addr, addrsize); - } else { - base58_encode_check(raw, 24, addr, addrsize); - } + base58_encode_check(raw, 20 + prefix_len, addr, addrsize); // not as important to clear this one, but we might as well MEMSET_BZERO(raw, sizeof(raw)); } @@ -922,35 +900,11 @@ void ecdsa_get_address(const uint8_t *pub_key, uint32_t version, char *addr, int void ecdsa_get_wif(const uint8_t *priv_key, uint32_t version, char *wif, int wifsize) { uint8_t wif_raw[MAX_WIF_RAW_SIZE]; - - if (version <= 0xFF) { - wif_raw[0] = version; - memcpy(wif_raw + 1, priv_key, 32); - wif_raw[33] = 0x01; - base58_encode_check(wif_raw, 1 + 32 + 1, wif, wifsize); - } else if (version <= 0xFFFF) { - wif_raw[0] = version >> 8; - wif_raw[1] = version & 0xFF; - memcpy(wif_raw + 2, priv_key, 32); - wif_raw[34] = 0x01; - base58_encode_check(wif_raw, 2 + 32 + 1, wif, wifsize); - } else if (version <= 0xFFFFFF) { - wif_raw[0] = version >> 16; - wif_raw[1] = (version >> 8) & 0xFF; - wif_raw[2] = version & 0xFF; - memcpy(wif_raw + 3, priv_key, 32); - wif_raw[35] = 0x01; - base58_encode_check(wif_raw, 3 + 32 + 1, wif, wifsize); - } else { - wif_raw[0] = version >> 24; - wif_raw[1] = (version >> 16) & 0xFF; - wif_raw[2] = (version >> 8) & 0xFF; - wif_raw[3] = version & 0xFF; - memcpy(wif_raw + 4, priv_key, 32); - wif_raw[36] = 0x01; - base58_encode_check(wif_raw, 4 + 32 + 1, wif, wifsize); - } - + size_t prefix_len = address_prefix_bytes_len(version); + address_write_prefix_bytes(version, wif_raw); + memcpy(wif_raw + prefix_len, priv_key, 32); + wif_raw[prefix_len + 32] = 0x01; + base58_encode_check(wif_raw, prefix_len + 32 + 1, wif, wifsize); // private keys running around our stack can cause trouble MEMSET_BZERO(wif_raw, sizeof(wif_raw)); } @@ -958,15 +912,9 @@ void ecdsa_get_wif(const uint8_t *priv_key, uint32_t version, char *wif, int wif int ecdsa_address_decode(const char *addr, uint32_t version, uint8_t *out) { if (!addr) return 0; - if (version <= 0xFF) { - return base58_decode_check(addr, out, 21) == 21 && out[0] == (version & 0xFF); - } else if (version <= 0xFFFF) { - return base58_decode_check(addr, out, 22) == 22 && out[0] == ((version >> 8) & 0xFF) && out[1] == (version & 0xFF); - } else if (version <= 0xFFFFFF) { - return base58_decode_check(addr, out, 23) == 23 && out[0] == ((version >> 16) & 0xFF) && out[1] == ((version >> 8) & 0xFF) && out[2] == (version & 0xFF); - } else { - return base58_decode_check(addr, out, 24) == 24 && out[0] == (version >> 24) && out[1] == ((version >> 16) & 0xFF) && out[2] == ((version >> 8) & 0xFF) && out[3] == (version & 0xFF); - } + int prefix_len = address_prefix_bytes_len(version); + return base58_decode_check(addr, out, 20 + prefix_len) == 20 + prefix_len + && address_check_prefix(out, version); } void uncompress_coords(const ecdsa_curve *curve, uint8_t odd, const bignum256 *x, bignum256 *y) From 1fb56e34666833c6c61b864dac260c327230c961 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Wed, 4 Jan 2017 15:04:07 +0100 Subject: [PATCH 364/627] Test cases for multibyte address prefixes --- tests.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/tests.c b/tests.c index 2c917dcdd..fd1ef94cc 100644 --- a/tests.c +++ b/tests.c @@ -2799,6 +2799,65 @@ START_TEST(test_ethereum_pubkeyhash) } END_TEST +START_TEST(test_multibyte_address) +{ + uint8_t priv_key[32]; + char wif[57]; + uint8_t pub_key[33]; + char address[40]; + uint8_t decode[24]; + int res; + + memcpy(priv_key, fromhex("47f7616ea6f9b923076625b4488115de1ef1187f760e65f89eb6f4f7ff04b012"), 32); + ecdsa_get_wif(priv_key, 0, wif, sizeof(wif)); ck_assert_str_eq(wif, "13QtoXmbhELWcrwD9YA9KzvXy5rTaptiNuFR8L8ArpBNn4xmQj4N"); + ecdsa_get_wif(priv_key, 0x12, wif, sizeof(wif)); ck_assert_str_eq(wif, "3hrF6SFnqzpzABB36uGDf8dJSuUCcMmoJrTmCWMshRkBr2Vx86qJ"); + ecdsa_get_wif(priv_key, 0x1234, wif, sizeof(wif)); ck_assert_str_eq(wif, "CtPTF9awbVbfDWGepGdVhB3nBhr4HktUGya8nf8dLxgC8tbqBreB9"); + ecdsa_get_wif(priv_key, 0x123456, wif, sizeof(wif)); ck_assert_str_eq(wif, "uTrDevVQt5QZgoL3iJ1cPWHaCz7ZMBncM7QXZfCegtxiMHqBvWoYJa"); + ecdsa_get_wif(priv_key, 0x12345678, wif, sizeof(wif)); ck_assert_str_eq(wif, "4zZWMzv1SVbs95pmLXWrXJVp9ntPEam1mfwb6CXBLn9MpWNxLg9huYgv"); + ecdsa_get_wif(priv_key, 0xffffffff, wif, sizeof(wif)); ck_assert_str_eq(wif, "y9KVfV1RJXcTxpVjeuh6WYWh8tMwnAUeyUwDEiRviYdrJ61njTmnfUjE"); + + memcpy(pub_key, fromhex("0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71"), 33); + ecdsa_get_address(pub_key, 0, address, sizeof(address)); ck_assert_str_eq(address, "1C7zdTfnkzmr13HfA2vNm5SJYRK6nEKyq8"); + ecdsa_get_address(pub_key, 0x12, address, sizeof(address)); ck_assert_str_eq(address, "8SCrMR2yYF7ciqoDbav7VLLTsVx5dTVPPq"); + ecdsa_get_address(pub_key, 0x1234, address, sizeof(address)); ck_assert_str_eq(address, "ZLH8q1UgMPg8o2s1MD55YVMpPV7vqms9kiV"); + ecdsa_get_address(pub_key, 0x123456, address, sizeof(address)); ck_assert_str_eq(address, "3ThqvsQVFnbiF66NwHtfe2j6AKn75DpLKpQSq"); + ecdsa_get_address(pub_key, 0x12345678, address, sizeof(address)); ck_assert_str_eq(address, "BrsGxAHga3VbopvSnb3gmLvMBhJNCGuDxBZL44"); + ecdsa_get_address(pub_key, 0xffffffff, address, sizeof(address)); ck_assert_str_eq(address, "3diW7paWGJyZRLGqMJZ55DMfPExob8QxQHkrfYT"); + + + res = ecdsa_address_decode("1C7zdTfnkzmr13HfA2vNm5SJYRK6nEKyq8", 0, decode); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(decode, fromhex("0079fbfc3f34e7745860d76137da68f362380c606c"), 21); + res = ecdsa_address_decode("8SCrMR2yYF7ciqoDbav7VLLTsVx5dTVPPq", 0x12, decode); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(decode, fromhex("1279fbfc3f34e7745860d76137da68f362380c606c"), 21); + res = ecdsa_address_decode("ZLH8q1UgMPg8o2s1MD55YVMpPV7vqms9kiV", 0x1234, decode); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(decode, fromhex("123479fbfc3f34e7745860d76137da68f362380c606c"), 21); + res = ecdsa_address_decode("3ThqvsQVFnbiF66NwHtfe2j6AKn75DpLKpQSq", 0x123456, decode); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(decode, fromhex("12345679fbfc3f34e7745860d76137da68f362380c606c"), 21); + res = ecdsa_address_decode("BrsGxAHga3VbopvSnb3gmLvMBhJNCGuDxBZL44", 0x12345678, decode); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(decode, fromhex("1234567879fbfc3f34e7745860d76137da68f362380c606c"), 21); + res = ecdsa_address_decode("3diW7paWGJyZRLGqMJZ55DMfPExob8QxQHkrfYT", 0xffffffff, decode); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(decode, fromhex("ffffffff79fbfc3f34e7745860d76137da68f362380c606c"), 21); + + // wrong length + res = ecdsa_address_decode("BrsGxAHga3VbopvSnb3gmLvMBhJNCGuDxBZL44", 0x123456, decode); + ck_assert_int_eq(res, 0); + + // wrong address prefix + res = ecdsa_address_decode("BrsGxAHga3VbopvSnb3gmLvMBhJNCGuDxBZL44", 0x22345678, decode); + ck_assert_int_eq(res, 0); + + // wrong checksum + res = ecdsa_address_decode("BrsGxAHga3VbopvSnb3gmLvMBhJNCGuDxBZL45", 0x12345678, decode); + ck_assert_int_eq(res, 0); +} +END_TEST + // define test suite and cases Suite *test_suite(void) { @@ -2965,6 +3024,10 @@ Suite *test_suite(void) tcase_add_test(tc, test_ethereum_pubkeyhash); suite_add_tcase(s, tc); + tc = tcase_create("multibyte_addresse"); + tcase_add_test(tc, test_multibyte_address); + suite_add_tcase(s, tc); + return s; } From 3d364aac3618ca7cca1e7687a7a3d99f7981ccd6 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 11 Jan 2017 15:33:46 +0100 Subject: [PATCH 365/627] we don't use OPTIMIZED_IV anywhere anymore --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 46dfeeb2c..407373b42 100644 --- a/Makefile +++ b/Makefile @@ -35,7 +35,7 @@ CFLAGS += -DUSE_GRAPHENE=1 # disable certain optimizations and features when small footprint is required ifdef SMALL -CFLAGS += -DUSE_PRECOMPUTED_IV=0 -DUSE_PRECOMPUTED_CP=0 +CFLAGS += -DUSE_PRECOMPUTED_CP=0 endif SRCS = bignum.c ecdsa.c curves.c secp256k1.c nist256p1.c rand.c hmac.c bip32.c bip39.c pbkdf2.c base58.c From 9a2310fc53a4d03c19591cbb55d85436f7573971 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 28 Feb 2017 18:14:54 +0100 Subject: [PATCH 366/627] add Blake2b --- Makefile | 2 +- README.md | 2 +- blake2_common.h | 39 +++++++ blake2b.c | 303 ++++++++++++++++++++++++++++++++++++++++++++++++ blake2b.h | 37 ++++++ blake2s.c | 24 +--- tests.c | 26 ++++- 7 files changed, 407 insertions(+), 26 deletions(-) create mode 100644 blake2_common.h create mode 100644 blake2b.c create mode 100644 blake2b.h diff --git a/Makefile b/Makefile index 407373b42..7d0f8b5ff 100644 --- a/Makefile +++ b/Makefile @@ -47,7 +47,7 @@ SRCS += sha3.c SRCS += aescrypt.c aeskey.c aestab.c aes_modes.c SRCS += ed25519-donna/ed25519.c SRCS += curve25519-donna/curve25519.c -SRCS += blake2s.c +SRCS += blake2b.c blake2s.c OBJS = $(SRCS:.c=.o) diff --git a/README.md b/README.md index 3be6de73b..d37481e34 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ These include: - RIPEMD-160 - SHA256/SHA512 - SHA3/Keccak -- BLAKE2s +- BLAKE2s/Blake2b - unit tests (using Check - check.sf.net; in tests.c) - tests against OpenSSL (in test-openssl.c) diff --git a/blake2_common.h b/blake2_common.h new file mode 100644 index 000000000..40c6da3b5 --- /dev/null +++ b/blake2_common.h @@ -0,0 +1,39 @@ +static inline uint32_t load32( const void *src ) +{ + uint32_t w; + memcpy(&w, src, sizeof w); + return w; +} + +static inline uint64_t load64( const void *src ) +{ + uint64_t w; + memcpy(&w, src, sizeof w); + return w; +} + +static inline void store16( void *dst, uint16_t w ) +{ + memcpy(dst, &w, sizeof w); +} + +static inline void store32( void *dst, uint32_t w ) +{ + memcpy(dst, &w, sizeof w); +} + +static inline void store64( void *dst, uint64_t w ) +{ + memcpy(dst, &w, sizeof w); +} + +static inline uint32_t rotr32( const uint32_t w, const unsigned c ) +{ + return ( w >> c ) | ( w << ( 32 - c ) ); +} + +static inline uint64_t rotr64( const uint64_t w, const unsigned c ) +{ + return ( w >> c ) | ( w << ( 64 - c ) ); +} + diff --git a/blake2b.c b/blake2b.c new file mode 100644 index 000000000..93b4aba44 --- /dev/null +++ b/blake2b.c @@ -0,0 +1,303 @@ +/* + BLAKE2 reference source code package - reference C implementations + + Copyright 2012, Samuel Neves . You may use this under the + terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at + your option. The terms of these licenses can be found at: + + - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0 + - OpenSSL license : https://www.openssl.org/source/license.html + - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0 + + More information about the BLAKE2 hash function can be found at + https://blake2.net. +*/ + +#include + +#include "macros.h" +#include "blake2b.h" +#include "blake2_common.h" + +typedef struct blake2b_param__ +{ + uint8_t digest_length; /* 1 */ + uint8_t key_length; /* 2 */ + uint8_t fanout; /* 3 */ + uint8_t depth; /* 4 */ + uint32_t leaf_length; /* 8 */ + uint32_t node_offset; /* 12 */ + uint32_t xof_length; /* 16 */ + uint8_t node_depth; /* 17 */ + uint8_t inner_length; /* 18 */ + uint8_t reserved[14]; /* 32 */ + uint8_t salt[BLAKE2B_SALTBYTES]; /* 48 */ + uint8_t personal[BLAKE2B_PERSONALBYTES]; /* 64 */ +} __attribute__((packed)) blake2b_param; + +static const uint64_t blake2b_IV[8] = +{ + 0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, + 0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL, + 0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL, + 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL +}; + +static const uint8_t blake2b_sigma[12][16] = +{ + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } , + { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } , + { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } , + { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } , + { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } , + { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } , + { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } , + { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } , + { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } , + { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 } , + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } , + { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } +}; + + +static void blake2b_set_lastnode( blake2b_state *S ) +{ + S->f[1] = (uint64_t)-1; +} + +/* Some helper functions, not necessarily useful */ +static int blake2b_is_lastblock( const blake2b_state *S ) +{ + return S->f[0] != 0; +} + +static void blake2b_set_lastblock( blake2b_state *S ) +{ + if( S->last_node ) blake2b_set_lastnode( S ); + + S->f[0] = (uint64_t)-1; +} + +static void blake2b_increment_counter( blake2b_state *S, const uint64_t inc ) +{ + S->t[0] += inc; + S->t[1] += ( S->t[0] < inc ); +} + +static void blake2b_init0( blake2b_state *S ) +{ + size_t i; + memset( S, 0, sizeof( blake2b_state ) ); + + for( i = 0; i < 8; ++i ) S->h[i] = blake2b_IV[i]; +} + +/* init xors IV with input parameter block */ +int blake2b_init_param( blake2b_state *S, const blake2b_param *P ) +{ + const uint8_t *p = ( const uint8_t * )( P ); + size_t i; + + blake2b_init0( S ); + + /* IV XOR ParamBlock */ + for( i = 0; i < 8; ++i ) + S->h[i] ^= load64( p + sizeof( S->h[i] ) * i ); + + S->outlen = P->digest_length; + return 0; +} + + +/* Sequential blake2b initialization */ +int blake2b_Init( blake2b_state *S, size_t outlen ) +{ + blake2b_param P[1]; + + if ( ( !outlen ) || ( outlen > BLAKE2B_OUTBYTES ) ) return -1; + + P->digest_length = (uint8_t)outlen; + P->key_length = 0; + P->fanout = 1; + P->depth = 1; + store32( &P->leaf_length, 0 ); + store32( &P->node_offset, 0 ); + store32( &P->xof_length, 0 ); + P->node_depth = 0; + P->inner_length = 0; + memset( P->reserved, 0, sizeof( P->reserved ) ); + memset( P->salt, 0, sizeof( P->salt ) ); + memset( P->personal, 0, sizeof( P->personal ) ); + return blake2b_init_param( S, P ); +} + + +int blake2b_InitKey( blake2b_state *S, size_t outlen, const void *key, size_t keylen ) +{ + blake2b_param P[1]; + + if ( ( !outlen ) || ( outlen > BLAKE2B_OUTBYTES ) ) return -1; + + if ( !key || !keylen || keylen > BLAKE2B_KEYBYTES ) return -1; + + P->digest_length = (uint8_t)outlen; + P->key_length = (uint8_t)keylen; + P->fanout = 1; + P->depth = 1; + store32( &P->leaf_length, 0 ); + store32( &P->node_offset, 0 ); + store32( &P->xof_length, 0 ); + P->node_depth = 0; + P->inner_length = 0; + memset( P->reserved, 0, sizeof( P->reserved ) ); + memset( P->salt, 0, sizeof( P->salt ) ); + memset( P->personal, 0, sizeof( P->personal ) ); + + if( blake2b_init_param( S, P ) < 0 ) return -1; + + { + uint8_t block[BLAKE2B_BLOCKBYTES]; + memset( block, 0, BLAKE2B_BLOCKBYTES ); + memcpy( block, key, keylen ); + blake2b_Update( S, block, BLAKE2B_BLOCKBYTES ); + MEMSET_BZERO( block, BLAKE2B_BLOCKBYTES ); /* Burn the key from stack */ + } + return 0; +} + +#define G(r,i,a,b,c,d) \ + do { \ + a = a + b + m[blake2b_sigma[r][2*i+0]]; \ + d = rotr64(d ^ a, 32); \ + c = c + d; \ + b = rotr64(b ^ c, 24); \ + a = a + b + m[blake2b_sigma[r][2*i+1]]; \ + d = rotr64(d ^ a, 16); \ + c = c + d; \ + b = rotr64(b ^ c, 63); \ + } while(0) + +#define ROUND(r) \ + do { \ + G(r,0,v[ 0],v[ 4],v[ 8],v[12]); \ + G(r,1,v[ 1],v[ 5],v[ 9],v[13]); \ + G(r,2,v[ 2],v[ 6],v[10],v[14]); \ + G(r,3,v[ 3],v[ 7],v[11],v[15]); \ + G(r,4,v[ 0],v[ 5],v[10],v[15]); \ + G(r,5,v[ 1],v[ 6],v[11],v[12]); \ + G(r,6,v[ 2],v[ 7],v[ 8],v[13]); \ + G(r,7,v[ 3],v[ 4],v[ 9],v[14]); \ + } while(0) + +static void blake2b_compress( blake2b_state *S, const uint8_t block[BLAKE2B_BLOCKBYTES] ) +{ + uint64_t m[16]; + uint64_t v[16]; + size_t i; + + for( i = 0; i < 16; ++i ) { + m[i] = load64( block + i * sizeof( m[i] ) ); + } + + for( i = 0; i < 8; ++i ) { + v[i] = S->h[i]; + } + + v[ 8] = blake2b_IV[0]; + v[ 9] = blake2b_IV[1]; + v[10] = blake2b_IV[2]; + v[11] = blake2b_IV[3]; + v[12] = blake2b_IV[4] ^ S->t[0]; + v[13] = blake2b_IV[5] ^ S->t[1]; + v[14] = blake2b_IV[6] ^ S->f[0]; + v[15] = blake2b_IV[7] ^ S->f[1]; + + ROUND( 0 ); + ROUND( 1 ); + ROUND( 2 ); + ROUND( 3 ); + ROUND( 4 ); + ROUND( 5 ); + ROUND( 6 ); + ROUND( 7 ); + ROUND( 8 ); + ROUND( 9 ); + ROUND( 10 ); + ROUND( 11 ); + + for( i = 0; i < 8; ++i ) { + S->h[i] = S->h[i] ^ v[i] ^ v[i + 8]; + } +} + +#undef G +#undef ROUND + +int blake2b_Update( blake2b_state *S, const void *pin, size_t inlen ) +{ + const unsigned char * in = (const unsigned char *)pin; + if( inlen > 0 ) + { + size_t left = S->buflen; + size_t fill = BLAKE2B_BLOCKBYTES - left; + if( inlen > fill ) + { + S->buflen = 0; + memcpy( S->buf + left, in, fill ); /* Fill buffer */ + blake2b_increment_counter( S, BLAKE2B_BLOCKBYTES ); + blake2b_compress( S, S->buf ); /* Compress */ + in += fill; inlen -= fill; + while(inlen > BLAKE2B_BLOCKBYTES) { + blake2b_increment_counter(S, BLAKE2B_BLOCKBYTES); + blake2b_compress( S, in ); + in += BLAKE2B_BLOCKBYTES; + inlen -= BLAKE2B_BLOCKBYTES; + } + } + memcpy( S->buf + S->buflen, in, inlen ); + S->buflen += inlen; + } + return 0; +} + +int blake2b_Final( blake2b_state *S, void *out, size_t outlen ) +{ + uint8_t buffer[BLAKE2B_OUTBYTES] = {0}; + size_t i; + + if( out == NULL || outlen < S->outlen ) + return -1; + + if( blake2b_is_lastblock( S ) ) + return -1; + + blake2b_increment_counter( S, S->buflen ); + blake2b_set_lastblock( S ); + memset( S->buf + S->buflen, 0, BLAKE2B_BLOCKBYTES - S->buflen ); /* Padding */ + blake2b_compress( S, S->buf ); + + for( i = 0; i < 8; ++i ) /* Output full hash to temp buffer */ + store64( buffer + sizeof( S->h[i] ) * i, S->h[i] ); + + memcpy( out, buffer, S->outlen ); + MEMSET_BZERO(buffer, sizeof(buffer)); + return 0; +} + +int blake2b(const uint8_t *msg, uint32_t msg_len, void *out, size_t outlen) +{ + BLAKE2B_CTX ctx; + if (0 != blake2b_Init(&ctx, outlen)) return -1; + if (0 != blake2b_Update(&ctx, msg, msg_len)) return -1; + if (0 != blake2b_Final(&ctx, out, outlen)) return -1; + return 0; +} + +int blake2b_Key(const uint8_t *msg, uint32_t msg_len, const void *key, size_t keylen, void *out, size_t outlen) +{ + BLAKE2B_CTX ctx; + if (0 != blake2b_InitKey(&ctx, outlen, key, keylen)) return -1; + if (0 != blake2b_Update(&ctx, msg, msg_len)) return -1; + if (0 != blake2b_Final(&ctx, out, outlen)) return -1; + return 0; +} diff --git a/blake2b.h b/blake2b.h new file mode 100644 index 000000000..50a6df72e --- /dev/null +++ b/blake2b.h @@ -0,0 +1,37 @@ +#ifndef __BLAKE2B_H__ +#define __BLAKE2B_H__ + +#include +#include + +enum blake2b_constant +{ + BLAKE2B_BLOCKBYTES = 128, + BLAKE2B_OUTBYTES = 64, + BLAKE2B_KEYBYTES = 64, + BLAKE2B_SALTBYTES = 16, + BLAKE2B_PERSONALBYTES = 16 +}; + +typedef struct __blake2b_state +{ + uint64_t h[8]; + uint64_t t[2]; + uint64_t f[2]; + uint8_t buf[BLAKE2B_BLOCKBYTES]; + size_t buflen; + size_t outlen; + uint8_t last_node; +} blake2b_state; + +#define BLAKE2B_CTX blake2b_state + +int blake2b_Init(blake2b_state *S, size_t outlen); +int blake2b_InitKey(blake2b_state *S, size_t outlen, const void *key, size_t keylen); +int blake2b_Update(blake2b_state *S, const void *pin, size_t inlen); +int blake2b_Final(blake2b_state *S, void *out, size_t outlen); + +int blake2b(const uint8_t *msg, uint32_t msg_len, void *out, size_t outlen); +int blake2b_Key(const uint8_t *msg, uint32_t msg_len, const void *key, size_t keylen, void *out, size_t outlen); + +#endif diff --git a/blake2s.c b/blake2s.c index 1f3b95193..c1ad548e2 100644 --- a/blake2s.c +++ b/blake2s.c @@ -17,6 +17,7 @@ #include "macros.h" #include "blake2s.h" +#include "blake2_common.h" typedef struct blake2s_param__ { @@ -54,28 +55,6 @@ static const uint8_t blake2s_sigma[10][16] = { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 } , }; -static inline uint32_t load32( const void *src ) -{ - uint32_t w; - memcpy(&w, src, sizeof w); - return w; -} - -static inline void store16( void *dst, uint16_t w ) -{ - memcpy(dst, &w, sizeof w); -} - -static inline void store32( void *dst, uint32_t w ) -{ - memcpy(dst, &w, sizeof w); -} - -static inline uint32_t rotr32( const uint32_t w, const unsigned c ) -{ - return ( w >> c ) | ( w << ( 32 - c ) ); -} - static void blake2s_set_lastnode( blake2s_state *S ) { S->f[1] = (uint32_t)-1; @@ -130,7 +109,6 @@ int blake2s_Init( blake2s_state *S, size_t outlen ) { blake2s_param P[1]; - /* Move interval verification here? */ if ( ( !outlen ) || ( outlen > BLAKE2S_OUTBYTES ) ) return -1; P->digest_length = (uint8_t)outlen; diff --git a/tests.c b/tests.c index fd1ef94cc..5bac44d23 100644 --- a/tests.c +++ b/tests.c @@ -42,6 +42,7 @@ #include "rand.h" #include "sha2.h" #include "sha3.h" +#include "blake2b.h" #include "blake2s.h" #include "curves.h" #include "secp256k1.h" @@ -1865,6 +1866,28 @@ START_TEST(test_sha3_512) } END_TEST +// test vectors from https://raw.githubusercontent.com/BLAKE2/BLAKE2/master/testvectors/blake2b-kat.txt +START_TEST(test_blake2b) +{ + uint8_t key[BLAKE2B_KEYBYTES]; + memcpy(key, fromhex("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f"), BLAKE2B_KEYBYTES); + + uint8_t digest[BLAKE2B_OUTBYTES]; + + blake2b_Key((uint8_t *)"", 0, key, BLAKE2B_KEYBYTES, digest, BLAKE2B_OUTBYTES); + ck_assert_mem_eq(digest, fromhex("10ebb67700b1868efb4417987acf4690ae9d972fb7a590c2f02871799aaa4786b5e996e8f0f4eb981fc214b005f42d2ff4233499391653df7aefcbc13fc51568"), BLAKE2B_OUTBYTES); + + blake2b_Key(fromhex("000102"), 3, key, BLAKE2B_KEYBYTES, digest, BLAKE2B_OUTBYTES); + ck_assert_mem_eq(digest, fromhex("33d0825dddf7ada99b0e7e307104ad07ca9cfd9692214f1561356315e784f3e5a17e364ae9dbb14cb2036df932b77f4b292761365fb328de7afdc6d8998f5fc1"), BLAKE2B_OUTBYTES); + + blake2b_Key(fromhex("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637"), 56, key, BLAKE2B_KEYBYTES, digest, BLAKE2B_OUTBYTES); + ck_assert_mem_eq(digest, fromhex("f8f3726ac5a26cc80132493a6fedcb0e60760c09cfc84cad178175986819665e76842d7b9fedf76dddebf5d3f56faaad4477587af21606d396ae570d8e719af2"), BLAKE2B_OUTBYTES); + + blake2b_Key(fromhex("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f"), 112, key, BLAKE2B_KEYBYTES, digest, BLAKE2B_OUTBYTES); + ck_assert_mem_eq(digest, fromhex("227e3aed8d2cb10b918fcb04f9de3e6d0a57e08476d93759cd7b2ed54a1cbf0239c528fb04bbf288253e601d3bc38b21794afef90b17094a182cac557745e75f"), BLAKE2B_OUTBYTES); +} +END_TEST + // test vectors from https://raw.githubusercontent.com/BLAKE2/BLAKE2/master/testvectors/blake2s-kat.txt START_TEST(test_blake2s) { @@ -2969,7 +2992,8 @@ Suite *test_suite(void) tcase_add_test(tc, test_sha3_512); suite_add_tcase(s, tc); - tc = tcase_create("blake2s"); + tc = tcase_create("blake2"); + tcase_add_test(tc, test_blake2b); tcase_add_test(tc, test_blake2s); suite_add_tcase(s, tc); From 27807fd3672618f85452fd3c3e5ff3839f61c811 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 20 Mar 2017 19:19:24 +0100 Subject: [PATCH 367/627] blake: add compat macros --- blake2b.h | 2 ++ blake2s.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/blake2b.h b/blake2b.h index 50a6df72e..9f4e45b00 100644 --- a/blake2b.h +++ b/blake2b.h @@ -25,6 +25,8 @@ typedef struct __blake2b_state } blake2b_state; #define BLAKE2B_CTX blake2b_state +#define BLAKE2B_BLOCK_LENGTH BLAKE2B_BLOCKBYTES +#define BLAKE2B_DIGEST_LENGTH BLAKE2B_OUTBYTES int blake2b_Init(blake2b_state *S, size_t outlen); int blake2b_InitKey(blake2b_state *S, size_t outlen, const void *key, size_t keylen); diff --git a/blake2s.h b/blake2s.h index 24cedbe10..e26668b14 100644 --- a/blake2s.h +++ b/blake2s.h @@ -25,6 +25,8 @@ typedef struct __blake2s_state } blake2s_state; #define BLAKE2S_CTX blake2s_state +#define BLAKE2S_BLOCK_LENGTH BLAKE2S_BLOCKBYTES +#define BLAKE2S_DIGEST_LENGTH BLAKE2S_OUTBYTES int blake2s_Init(blake2s_state *S, size_t outlen); int blake2s_InitKey(blake2s_state *S, size_t outlen, const void *key, size_t keylen); From 87c920a7e747f7ed40b6ae841327868ab914435b Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 20 Mar 2017 20:20:14 +0100 Subject: [PATCH 368/627] use BLOCK_LENGTH and DIGEST_LENGTH across all hash functions --- blake2b.h | 1 + blake2s.h | 1 + sha3.h | 10 +++++++++ tests.c | 64 +++++++++++++++++++++++++++---------------------------- 4 files changed, 44 insertions(+), 32 deletions(-) diff --git a/blake2b.h b/blake2b.h index 9f4e45b00..772a5cfe4 100644 --- a/blake2b.h +++ b/blake2b.h @@ -27,6 +27,7 @@ typedef struct __blake2b_state #define BLAKE2B_CTX blake2b_state #define BLAKE2B_BLOCK_LENGTH BLAKE2B_BLOCKBYTES #define BLAKE2B_DIGEST_LENGTH BLAKE2B_OUTBYTES +#define BLAKE2B_KEY_LENGTH BLAKE2B_KEYBYTES int blake2b_Init(blake2b_state *S, size_t outlen); int blake2b_InitKey(blake2b_state *S, size_t outlen, const void *key, size_t keylen); diff --git a/blake2s.h b/blake2s.h index e26668b14..dd34bf194 100644 --- a/blake2s.h +++ b/blake2s.h @@ -27,6 +27,7 @@ typedef struct __blake2s_state #define BLAKE2S_CTX blake2s_state #define BLAKE2S_BLOCK_LENGTH BLAKE2S_BLOCKBYTES #define BLAKE2S_DIGEST_LENGTH BLAKE2S_OUTBYTES +#define BLAKE2S_KEY_LENGTH BLAKE2S_KEYBYTES int blake2s_Init(blake2s_state *S, size_t outlen); int blake2s_InitKey(blake2s_state *S, size_t outlen, const void *key, size_t keylen); diff --git a/sha3.h b/sha3.h index b78d9d84b..9d0d19b77 100644 --- a/sha3.h +++ b/sha3.h @@ -34,6 +34,16 @@ extern "C" { #define sha3_max_permutation_size 25 #define sha3_max_rate_in_qwords 24 +#define SHA3_224_BLOCK_LENGTH 144 +#define SHA3_256_BLOCK_LENGTH 136 +#define SHA3_384_BLOCK_LENGTH 104 +#define SHA3_512_BLOCK_LENGTH 72 + +#define SHA3_224_DIGEST_LENGTH sha3_224_hash_size +#define SHA3_256_DIGEST_LENGTH sha3_256_hash_size +#define SHA3_384_DIGEST_LENGTH sha3_384_hash_size +#define SHA3_512_DIGEST_LENGTH sha3_512_hash_size + /** * SHA3 Algorithm context. */ diff --git a/tests.c b/tests.c index 5bac44d23..97e0ec7ed 100644 --- a/tests.c +++ b/tests.c @@ -1831,82 +1831,82 @@ END_TEST // test vectors from http://www.di-mgt.com.au/sha_testvectors.html START_TEST(test_sha3_256) { - uint8_t digest[sha3_256_hash_size]; + uint8_t digest[SHA3_256_DIGEST_LENGTH]; sha3_256((uint8_t *)"", 0, digest); - ck_assert_mem_eq(digest, fromhex("a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a"), sha3_256_hash_size); + ck_assert_mem_eq(digest, fromhex("a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a"), SHA3_256_DIGEST_LENGTH); sha3_256((uint8_t *)"abc", 3, digest); - ck_assert_mem_eq(digest, fromhex("3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532"), sha3_256_hash_size); + ck_assert_mem_eq(digest, fromhex("3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532"), SHA3_256_DIGEST_LENGTH); sha3_256((uint8_t *)"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 56, digest); - ck_assert_mem_eq(digest, fromhex("41c0dba2a9d6240849100376a8235e2c82e1b9998a999e21db32dd97496d3376"), sha3_256_hash_size); + ck_assert_mem_eq(digest, fromhex("41c0dba2a9d6240849100376a8235e2c82e1b9998a999e21db32dd97496d3376"), SHA3_256_DIGEST_LENGTH); sha3_256((uint8_t *)"abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", 112, digest); - ck_assert_mem_eq(digest, fromhex("916f6061fe879741ca6469b43971dfdb28b1a32dc36cb3254e812be27aad1d18"), sha3_256_hash_size); + ck_assert_mem_eq(digest, fromhex("916f6061fe879741ca6469b43971dfdb28b1a32dc36cb3254e812be27aad1d18"), SHA3_256_DIGEST_LENGTH); } END_TEST // test vectors from http://www.di-mgt.com.au/sha_testvectors.html START_TEST(test_sha3_512) { - uint8_t digest[sha3_512_hash_size]; + uint8_t digest[SHA3_512_DIGEST_LENGTH]; sha3_512((uint8_t *)"", 0, digest); - ck_assert_mem_eq(digest, fromhex("a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26"), sha3_512_hash_size); + ck_assert_mem_eq(digest, fromhex("a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26"), SHA3_512_DIGEST_LENGTH); sha3_512((uint8_t *)"abc", 3, digest); - ck_assert_mem_eq(digest, fromhex("b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e10e116e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0"), sha3_512_hash_size); + ck_assert_mem_eq(digest, fromhex("b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e10e116e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0"), SHA3_512_DIGEST_LENGTH); sha3_512((uint8_t *)"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 56, digest); - ck_assert_mem_eq(digest, fromhex("04a371e84ecfb5b8b77cb48610fca8182dd457ce6f326a0fd3d7ec2f1e91636dee691fbe0c985302ba1b0d8dc78c086346b533b49c030d99a27daf1139d6e75e"), sha3_512_hash_size); + ck_assert_mem_eq(digest, fromhex("04a371e84ecfb5b8b77cb48610fca8182dd457ce6f326a0fd3d7ec2f1e91636dee691fbe0c985302ba1b0d8dc78c086346b533b49c030d99a27daf1139d6e75e"), SHA3_512_DIGEST_LENGTH); sha3_512((uint8_t *)"abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", 112, digest); - ck_assert_mem_eq(digest, fromhex("afebb2ef542e6579c50cad06d2e578f9f8dd6881d7dc824d26360feebf18a4fa73e3261122948efcfd492e74e82e2189ed0fb440d187f382270cb455f21dd185"), sha3_512_hash_size); + ck_assert_mem_eq(digest, fromhex("afebb2ef542e6579c50cad06d2e578f9f8dd6881d7dc824d26360feebf18a4fa73e3261122948efcfd492e74e82e2189ed0fb440d187f382270cb455f21dd185"), SHA3_512_DIGEST_LENGTH); } END_TEST // test vectors from https://raw.githubusercontent.com/BLAKE2/BLAKE2/master/testvectors/blake2b-kat.txt START_TEST(test_blake2b) { - uint8_t key[BLAKE2B_KEYBYTES]; - memcpy(key, fromhex("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f"), BLAKE2B_KEYBYTES); + uint8_t key[BLAKE2B_KEY_LENGTH]; + memcpy(key, fromhex("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f"), BLAKE2B_KEY_LENGTH); - uint8_t digest[BLAKE2B_OUTBYTES]; + uint8_t digest[BLAKE2B_DIGEST_LENGTH]; - blake2b_Key((uint8_t *)"", 0, key, BLAKE2B_KEYBYTES, digest, BLAKE2B_OUTBYTES); - ck_assert_mem_eq(digest, fromhex("10ebb67700b1868efb4417987acf4690ae9d972fb7a590c2f02871799aaa4786b5e996e8f0f4eb981fc214b005f42d2ff4233499391653df7aefcbc13fc51568"), BLAKE2B_OUTBYTES); + blake2b_Key((uint8_t *)"", 0, key, BLAKE2B_KEY_LENGTH, digest, BLAKE2B_DIGEST_LENGTH); + ck_assert_mem_eq(digest, fromhex("10ebb67700b1868efb4417987acf4690ae9d972fb7a590c2f02871799aaa4786b5e996e8f0f4eb981fc214b005f42d2ff4233499391653df7aefcbc13fc51568"), BLAKE2B_DIGEST_LENGTH); - blake2b_Key(fromhex("000102"), 3, key, BLAKE2B_KEYBYTES, digest, BLAKE2B_OUTBYTES); - ck_assert_mem_eq(digest, fromhex("33d0825dddf7ada99b0e7e307104ad07ca9cfd9692214f1561356315e784f3e5a17e364ae9dbb14cb2036df932b77f4b292761365fb328de7afdc6d8998f5fc1"), BLAKE2B_OUTBYTES); + blake2b_Key(fromhex("000102"), 3, key, BLAKE2B_KEY_LENGTH, digest, BLAKE2B_DIGEST_LENGTH); + ck_assert_mem_eq(digest, fromhex("33d0825dddf7ada99b0e7e307104ad07ca9cfd9692214f1561356315e784f3e5a17e364ae9dbb14cb2036df932b77f4b292761365fb328de7afdc6d8998f5fc1"), BLAKE2B_DIGEST_LENGTH); - blake2b_Key(fromhex("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637"), 56, key, BLAKE2B_KEYBYTES, digest, BLAKE2B_OUTBYTES); - ck_assert_mem_eq(digest, fromhex("f8f3726ac5a26cc80132493a6fedcb0e60760c09cfc84cad178175986819665e76842d7b9fedf76dddebf5d3f56faaad4477587af21606d396ae570d8e719af2"), BLAKE2B_OUTBYTES); + blake2b_Key(fromhex("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637"), 56, key, BLAKE2B_KEY_LENGTH, digest, BLAKE2B_DIGEST_LENGTH); + ck_assert_mem_eq(digest, fromhex("f8f3726ac5a26cc80132493a6fedcb0e60760c09cfc84cad178175986819665e76842d7b9fedf76dddebf5d3f56faaad4477587af21606d396ae570d8e719af2"), BLAKE2B_DIGEST_LENGTH); - blake2b_Key(fromhex("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f"), 112, key, BLAKE2B_KEYBYTES, digest, BLAKE2B_OUTBYTES); - ck_assert_mem_eq(digest, fromhex("227e3aed8d2cb10b918fcb04f9de3e6d0a57e08476d93759cd7b2ed54a1cbf0239c528fb04bbf288253e601d3bc38b21794afef90b17094a182cac557745e75f"), BLAKE2B_OUTBYTES); + blake2b_Key(fromhex("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f"), 112, key, BLAKE2B_KEY_LENGTH, digest, BLAKE2B_DIGEST_LENGTH); + ck_assert_mem_eq(digest, fromhex("227e3aed8d2cb10b918fcb04f9de3e6d0a57e08476d93759cd7b2ed54a1cbf0239c528fb04bbf288253e601d3bc38b21794afef90b17094a182cac557745e75f"), BLAKE2B_DIGEST_LENGTH); } END_TEST // test vectors from https://raw.githubusercontent.com/BLAKE2/BLAKE2/master/testvectors/blake2s-kat.txt START_TEST(test_blake2s) { - uint8_t key[BLAKE2S_KEYBYTES]; - memcpy(key, fromhex("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"), BLAKE2S_KEYBYTES); + uint8_t key[BLAKE2S_KEY_LENGTH]; + memcpy(key, fromhex("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"), BLAKE2S_KEY_LENGTH); - uint8_t digest[BLAKE2S_OUTBYTES]; + uint8_t digest[BLAKE2S_DIGEST_LENGTH]; - blake2s_Key((uint8_t *)"", 0, key, BLAKE2S_KEYBYTES, digest, BLAKE2S_OUTBYTES); - ck_assert_mem_eq(digest, fromhex("48a8997da407876b3d79c0d92325ad3b89cbb754d86ab71aee047ad345fd2c49"), BLAKE2S_OUTBYTES); + blake2s_Key((uint8_t *)"", 0, key, BLAKE2S_KEY_LENGTH, digest, BLAKE2S_DIGEST_LENGTH); + ck_assert_mem_eq(digest, fromhex("48a8997da407876b3d79c0d92325ad3b89cbb754d86ab71aee047ad345fd2c49"), BLAKE2S_DIGEST_LENGTH); - blake2s_Key(fromhex("000102"), 3, key, BLAKE2S_KEYBYTES, digest, BLAKE2S_OUTBYTES); - ck_assert_mem_eq(digest, fromhex("1d220dbe2ee134661fdf6d9e74b41704710556f2f6e5a091b227697445dbea6b"), BLAKE2S_OUTBYTES); + blake2s_Key(fromhex("000102"), 3, key, BLAKE2S_KEY_LENGTH, digest, BLAKE2S_DIGEST_LENGTH); + ck_assert_mem_eq(digest, fromhex("1d220dbe2ee134661fdf6d9e74b41704710556f2f6e5a091b227697445dbea6b"), BLAKE2S_DIGEST_LENGTH); - blake2s_Key(fromhex("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637"), 56, key, BLAKE2S_KEYBYTES, digest, BLAKE2S_OUTBYTES); - ck_assert_mem_eq(digest, fromhex("2966b3cfae1e44ea996dc5d686cf25fa053fb6f67201b9e46eade85d0ad6b806"), BLAKE2S_OUTBYTES); + blake2s_Key(fromhex("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637"), 56, key, BLAKE2S_KEY_LENGTH, digest, BLAKE2S_DIGEST_LENGTH); + ck_assert_mem_eq(digest, fromhex("2966b3cfae1e44ea996dc5d686cf25fa053fb6f67201b9e46eade85d0ad6b806"), BLAKE2S_DIGEST_LENGTH); - blake2s_Key(fromhex("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f"), 112, key, BLAKE2S_KEYBYTES, digest, BLAKE2S_OUTBYTES); - ck_assert_mem_eq(digest, fromhex("90a83585717b75f0e9b725e055eeeeb9e7a028ea7e6cbc07b20917ec0363e38c"), BLAKE2S_OUTBYTES); + blake2s_Key(fromhex("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f"), 112, key, BLAKE2S_KEY_LENGTH, digest, BLAKE2S_DIGEST_LENGTH); + ck_assert_mem_eq(digest, fromhex("90a83585717b75f0e9b725e055eeeeb9e7a028ea7e6cbc07b20917ec0363e38c"), BLAKE2S_DIGEST_LENGTH); } END_TEST From cb471ba2ec793c6c96d47ec1e121003d55b0823d Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 28 Mar 2017 18:01:42 +0200 Subject: [PATCH 369/627] upgrade ed25519 to forthy42 fork --- Makefile | 1 + ed25519-donna/curve25519-donna-32bit.h | 2 +- ed25519-donna/ed25519-donna-32bit-tables.h | 10 +- ed25519-donna/ed25519-donna-64bit-tables.h | 10 +- ed25519-donna/ed25519-donna-impl-base.h | 177 ++++++++++++++++-- ed25519-donna/ed25519-donna-impl-sse2.h | 153 +++++++++++++-- .../ed25519-donna-portable-identify.h | 3 + ed25519-donna/ed25519.c | 1 + ed25519-donna/modm-donna-32bit.h | 39 ++-- ed25519-donna/modm-donna-64bit.h | 39 ++-- 10 files changed, 346 insertions(+), 89 deletions(-) diff --git a/Makefile b/Makefile index 7d0f8b5ff..74e766803 100644 --- a/Makefile +++ b/Makefile @@ -21,6 +21,7 @@ CFLAGS += $(OPTFLAGS) \ -Winit-self \ -Wuninitialized \ -Wformat-security \ + -Wno-unused-function \ -Werror # disable sequence point warning because of AES code diff --git a/ed25519-donna/curve25519-donna-32bit.h b/ed25519-donna/curve25519-donna-32bit.h index b0861acf0..b8fa37d6e 100644 --- a/ed25519-donna/curve25519-donna-32bit.h +++ b/ed25519-donna/curve25519-donna-32bit.h @@ -403,8 +403,8 @@ static void curve25519_expand(bignum25519 out, const unsigned char in[32]) { static const union { uint8_t b[2]; uint16_t s; } endian_check = {{1,0}}; uint32_t x0,x1,x2,x3,x4,x5,x6,x7; - if (endian_check.s == 1) { + /* Take care, this only works when in is aligned */ x0 = *(uint32_t *)(in + 0); x1 = *(uint32_t *)(in + 4); x2 = *(uint32_t *)(in + 8); diff --git a/ed25519-donna/ed25519-donna-32bit-tables.h b/ed25519-donna/ed25519-donna-32bit-tables.h index c977c26eb..49022aee2 100644 --- a/ed25519-donna/ed25519-donna-32bit-tables.h +++ b/ed25519-donna/ed25519-donna-32bit-tables.h @@ -1,4 +1,4 @@ -static const ge25519 ALIGN(16) ge25519_basepoint = { +const ge25519 ALIGN(16) ge25519_basepoint = { {0x0325d51a,0x018b5823,0x00f6592a,0x0104a92d,0x01a4b31d,0x01d6dc5c,0x027118fe,0x007fd814,0x013cd6e5,0x0085a4db}, {0x02666658,0x01999999,0x00cccccc,0x01333333,0x01999999,0x00666666,0x03333333,0x00cccccc,0x02666666,0x01999999}, {0x00000001,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000}, @@ -9,11 +9,11 @@ static const ge25519 ALIGN(16) ge25519_basepoint = { d */ -static const bignum25519 ALIGN(16) ge25519_ecd = { +const bignum25519 ALIGN(16) ge25519_ecd = { 0x035978a3,0x00d37284,0x03156ebd,0x006a0a0e,0x0001c029,0x0179e898,0x03a03cbb,0x01ce7198,0x02e2b6ff,0x01480db3 }; -static const bignum25519 ALIGN(16) ge25519_ec2d = { +const bignum25519 ALIGN(16) ge25519_ec2d = { 0x02b2f159,0x01a6e509,0x022add7a,0x00d4141d,0x00038052,0x00f3d130,0x03407977,0x019ce331,0x01c56dff,0x00901b67 }; @@ -21,11 +21,11 @@ static const bignum25519 ALIGN(16) ge25519_ec2d = { sqrt(-1) */ -static const bignum25519 ALIGN(16) ge25519_sqrtneg1 = { +const bignum25519 ALIGN(16) ge25519_sqrtneg1 = { 0x020ea0b0,0x0186c9d2,0x008f189d,0x0035697f,0x00bd0c60,0x01fbd7a7,0x02804c9e,0x01e16569,0x0004fc1d,0x00ae0c92 }; -static const ge25519_niels ALIGN(16) ge25519_niels_sliding_multiples[32] = { +const ge25519_niels ALIGN(16) ge25519_niels_sliding_multiples[32] = { {{0x0340913e,0x000e4175,0x03d673a2,0x002e8a05,0x03f4e67c,0x008f8a09,0x00c21a34,0x004cf4b8,0x01298f81,0x0113f4be},{0x018c3b85,0x0124f1bd,0x01c325f7,0x0037dc60,0x033e4cb7,0x003d42c2,0x01a44c32,0x014ca4e1,0x03a33d4b,0x001f3e74},{0x037aaa68,0x00448161,0x0093d579,0x011e6556,0x009b67a0,0x0143598c,0x01bee5ee,0x00b50b43,0x0289f0c6,0x01bc45ed}}, {{0x00fcd265,0x0047fa29,0x034faacc,0x01ef2e0d,0x00ef4d4f,0x014bd6bd,0x00f98d10,0x014c5026,0x007555bd,0x00aae456},{0x00ee9730,0x016c2a13,0x017155e4,0x01874432,0x00096a10,0x01016732,0x01a8014f,0x011e9823,0x01b9a80f,0x01e85938},{0x01d0d889,0x01a4cfc3,0x034c4295,0x0110e1ae,0x0162508c,0x00f2db4c,0x0072a2c6,0x0098da2e,0x02f12b9b,0x0168a09a}}, {{0x0047d6ba,0x0060b0e9,0x0136eff2,0x008a5939,0x03540053,0x0064a087,0x02788e5c,0x00be7c67,0x033eb1b5,0x005529f9},{0x00a5bb33,0x00af1102,0x01a05442,0x001e3af7,0x02354123,0x00bfec44,0x01f5862d,0x00dd7ba3,0x03146e20,0x00a51733},{0x012a8285,0x00f6fc60,0x023f9797,0x003e85ee,0x009c3820,0x01bda72d,0x01b3858d,0x00d35683,0x0296b3bb,0x010eaaf9}}, diff --git a/ed25519-donna/ed25519-donna-64bit-tables.h b/ed25519-donna/ed25519-donna-64bit-tables.h index 4a6ff9eda..e5e449099 100644 --- a/ed25519-donna/ed25519-donna-64bit-tables.h +++ b/ed25519-donna/ed25519-donna-64bit-tables.h @@ -1,23 +1,23 @@ -static const ge25519 ge25519_basepoint = { +const ge25519 ge25519_basepoint = { {0x00062d608f25d51a,0x000412a4b4f6592a,0x00075b7171a4b31d,0x0001ff60527118fe,0x000216936d3cd6e5}, {0x0006666666666658,0x0004cccccccccccc,0x0001999999999999,0x0003333333333333,0x0006666666666666}, {0x0000000000000001,0x0000000000000000,0x0000000000000000,0x0000000000000000,0x0000000000000000}, {0x00068ab3a5b7dda3,0x00000eea2a5eadbb,0x0002af8df483c27e,0x000332b375274732,0x00067875f0fd78b7} }; -static const bignum25519 ge25519_ecd = { +const bignum25519 ge25519_ecd = { 0x00034dca135978a3,0x0001a8283b156ebd,0x0005e7a26001c029,0x000739c663a03cbb,0x00052036cee2b6ff }; -static const bignum25519 ge25519_ec2d = { +const bignum25519 ge25519_ec2d = { 0x00069b9426b2f159,0x00035050762add7a,0x0003cf44c0038052,0x0006738cc7407977,0x0002406d9dc56dff }; -static const bignum25519 ge25519_sqrtneg1 = { +const bignum25519 ge25519_sqrtneg1 = { 0x00061b274a0ea0b0,0x0000d5a5fc8f189d,0x0007ef5e9cbd0c60,0x00078595a6804c9e,0x0002b8324804fc1d }; -static const ge25519_niels ge25519_niels_sliding_multiples[32] = { +const ge25519_niels ge25519_niels_sliding_multiples[32] = { {{0x00003905d740913e,0x0000ba2817d673a2,0x00023e2827f4e67c,0x000133d2e0c21a34,0x00044fd2f9298f81},{0x000493c6f58c3b85,0x0000df7181c325f7,0x0000f50b0b3e4cb7,0x0005329385a44c32,0x00007cf9d3a33d4b},{0x00011205877aaa68,0x000479955893d579,0x00050d66309b67a0,0x0002d42d0dbee5ee,0x0006f117b689f0c6}}, {{0x00011fe8a4fcd265,0x0007bcb8374faacc,0x00052f5af4ef4d4f,0x0005314098f98d10,0x0002ab91587555bd},{0x0005b0a84cee9730,0x00061d10c97155e4,0x0004059cc8096a10,0x00047a608da8014f,0x0007a164e1b9a80f},{0x0006933f0dd0d889,0x00044386bb4c4295,0x0003cb6d3162508c,0x00026368b872a2c6,0x0005a2826af12b9b}}, {{0x000182c3a447d6ba,0x00022964e536eff2,0x000192821f540053,0x0002f9f19e788e5c,0x000154a7e73eb1b5},{0x0002bc4408a5bb33,0x000078ebdda05442,0x0002ffb112354123,0x000375ee8df5862d,0x0002945ccf146e20},{0x0003dbf1812a8285,0x0000fa17ba3f9797,0x0006f69cb49c3820,0x00034d5a0db3858d,0x00043aabe696b3bb}}, diff --git a/ed25519-donna/ed25519-donna-impl-base.h b/ed25519-donna/ed25519-donna-impl-base.h index 48913edcb..8cc85f216 100644 --- a/ed25519-donna/ed25519-donna-impl-base.h +++ b/ed25519-donna/ed25519-donna-impl-base.h @@ -176,7 +176,7 @@ ge25519_pnielsadd(ge25519_pniels *r, const ge25519 *p, const ge25519_pniels *q) pack & unpack */ -static void +STATIC void ge25519_pack(unsigned char r[32], const ge25519 *p) { bignum25519 tx, ty, zi; unsigned char parity[32]; @@ -188,8 +188,7 @@ ge25519_pack(unsigned char r[32], const ge25519 *p) { r[31] ^= ((parity[0] & 1) << 7); } -static int -ge25519_unpack_negative_vartime(ge25519 *r, const unsigned char p[32]) { +STATIC int ge25519_unpack_negative_vartime(ge25519 *r, const unsigned char p[32]) { static const unsigned char zero[32] = {0}; static const bignum25519 one = {1}; unsigned char parity = p[31] >> 7; @@ -243,14 +242,20 @@ ge25519_unpack_negative_vartime(ge25519 *r, const unsigned char p[32]) { scalarmults */ +DONNA_INLINE static void ge25519_set_neutral(ge25519 *r) +{ + memset(r, 0, sizeof(ge25519)); + r->y[0] = 1; + r->z[0] = 1; +} + #define S1_SWINDOWSIZE 5 #define S1_TABLE_SIZE (1<<(S1_SWINDOWSIZE-2)) #define S2_SWINDOWSIZE 7 #define S2_TABLE_SIZE (1<<(S2_SWINDOWSIZE-2)) -/* computes [s1]p1 + [s2]basepoint */ -static void -ge25519_double_scalarmult_vartime(ge25519 *r, const ge25519 *p1, const bignum256modm s1, const bignum256modm s2) { +/* computes [s1]p1 + [s2]base */ +STATIC void ge25519_double_scalarmult_vartime(ge25519 *r, const ge25519 *p1, const bignum256modm s1, const bignum256modm s2) { signed char slide1[256], slide2[256]; ge25519_pniels pre1[S1_TABLE_SIZE]; ge25519 d1; @@ -265,10 +270,7 @@ ge25519_double_scalarmult_vartime(ge25519 *r, const ge25519 *p1, const bignum256 for (i = 0; i < S1_TABLE_SIZE - 1; i++) ge25519_pnielsadd(&pre1[i+1], &d1, &pre1[i]); - /* set neutral */ - memset(r, 0, sizeof(ge25519)); - r->y[0] = 1; - r->z[0] = 1; + ge25519_set_neutral(r); i = 255; while ((i >= 0) && !(slide1[i] | slide2[i])) @@ -291,11 +293,156 @@ ge25519_double_scalarmult_vartime(ge25519 *r, const ge25519 *p1, const bignum256 } } +/* computes [s1]p1 */ +STATIC void ge25519_scalarmult_vartime(ge25519 *r, const ge25519 *p1, const bignum256modm s1) { + signed char slide1[256]; + ge25519_pniels pre1[S1_TABLE_SIZE]; + ge25519 d1; + ge25519_p1p1 t; + int32_t i; + + contract256_slidingwindow_modm(slide1, s1, S1_SWINDOWSIZE); + + ge25519_double(&d1, p1); + ge25519_full_to_pniels(pre1, p1); + for (i = 0; i < S1_TABLE_SIZE - 1; i++) + ge25519_pnielsadd(&pre1[i+1], &d1, &pre1[i]); + + /* set neutral */ + ge25519_set_neutral(r); + + i = 255; + while ((i >= 0) && !slide1[i]) + i--; + + for (; i >= 0; i--) { + ge25519_double_p1p1(&t, r); + + if (slide1[i]) { + ge25519_p1p1_to_full(r, &t); + ge25519_pnielsadd_p1p1(&t, r, &pre1[abs(slide1[i]) / 2], (unsigned char)slide1[i] >> 7); + } + + ge25519_p1p1_to_partial(r, &t); + } +} + +/* + * The following conditional move stuff uses conditional moves. + * I will check on which compilers this works, and provide suitable + * workarounds for those where it doesn't. + * + * This works on gcc 4.x and above with -O3. Don't use -O2, this will + * cause the code to not generate conditional moves. Don't use any -march= + * with less than i686 on x86 + */ +DONNA_INLINE static void ge25519_cmove_stride4(long * r, long * p, long * pos, long * n, int stride) { + long x0=r[0], x1=r[1], x2=r[2], x3=r[3], y0, y1, y2, y3; + for(; p= 0; i--) { + int k=abs(slide1[i]); + ge25519_double_partial(r, r); + ge25519_double_partial(r, r); + ge25519_double_partial(r, r); + ge25519_double_p1p1(&t, r); + ge25519_move_conditional_pniels_array(&pre, pre1, k, 9); + ge25519_p1p1_to_full(r, &t); + ge25519_pnielsadd_p1p1(&t, r, &pre, (unsigned char)slide1[i] >> 7); + ge25519_p1p1_to_partial(r, &t); + } +} #if !defined(HAVE_GE25519_SCALARMULT_BASE_CHOOSE_NIELS) -static uint32_t +DONNA_INLINE static uint32_t ge25519_windowb_equal(uint32_t b, uint32_t c) { return ((b ^ c) - 1) >> 31; } @@ -306,15 +453,13 @@ ge25519_scalarmult_base_choose_niels(ge25519_niels *t, const uint8_t table[256][ uint32_t sign = (uint32_t)((unsigned char)b >> 7); uint32_t mask = ~(sign - 1); uint32_t u = (b + mask) ^ mask; - uint32_t i; /* ysubx, xaddy, t2d in packed form. initialize to ysubx = 1, xaddy = 1, t2d = 0 */ uint8_t packed[96] = {0}; packed[0] = 1; packed[32] = 1; - for (i = 0; i < 8; i++) - curve25519_move_conditional_bytes(packed, table[(pos * 8) + i], ge25519_windowb_equal(u, i + 1)); + ge25519_move_conditional_niels_array((ge25519_niels *)packed, &table[pos*8], u-1, 8); /* expand in to t */ curve25519_expand(t->ysubx, packed + 0); @@ -362,3 +507,7 @@ ge25519_scalarmult_base_niels(ge25519 *r, const uint8_t basepoint_table[256][96] } } +STATIC void ge25519_scalarmult_base(ge25519 *r, const bignum256modm s) { + ge25519_scalarmult_base_niels(r, ge25519_niels_base_multiples, s); +} + diff --git a/ed25519-donna/ed25519-donna-impl-sse2.h b/ed25519-donna/ed25519-donna-impl-sse2.h index 5fe341638..67fd8f495 100644 --- a/ed25519-donna/ed25519-donna-impl-sse2.h +++ b/ed25519-donna/ed25519-donna-impl-sse2.h @@ -149,7 +149,7 @@ ge25519_double(ge25519 *r, const ge25519 *p) { ge25519_p1p1_to_full(r, &t); } -static void +STATIC void ge25519_add(ge25519 *r, const ge25519 *p, const ge25519 *q) { ge25519_p1p1 ALIGN(16) t; ge25519_add_p1p1(&t, p, q); @@ -205,7 +205,7 @@ ge25519_pnielsadd(ge25519_pniels *r, const ge25519 *p, const ge25519_pniels *q) pack & unpack */ -static void +STATIC void ge25519_pack(unsigned char r[32], const ge25519 *p) { bignum25519 ALIGN(16) tx, ty, zi; unsigned char parity[32]; @@ -218,7 +218,7 @@ ge25519_pack(unsigned char r[32], const ge25519 *p) { } -static int +STATIC int ge25519_unpack_negative_vartime(ge25519 *r, const unsigned char p[32]) { static const bignum25519 ALIGN(16) one = {1}; static const unsigned char zero[32] = {0}; @@ -275,12 +275,20 @@ ge25519_unpack_negative_vartime(ge25519 *r, const unsigned char p[32]) { scalarmults */ +DONNA_INLINE static void ge25519_set_neutral(ge25519 *r) +{ + memset(r, 0, sizeof(ge25519)); + r->y[0] = 1; + r->z[0] = 1; +} + #define S1_SWINDOWSIZE 5 #define S1_TABLE_SIZE (1<<(S1_SWINDOWSIZE-2)) #define S2_SWINDOWSIZE 7 #define S2_TABLE_SIZE (1<<(S2_SWINDOWSIZE-2)) -static void +/* computes [s1]p1 + [s2]base */ +STATIC void ge25519_double_scalarmult_vartime(ge25519 *r, const ge25519 *p1, const bignum256modm s1, const bignum256modm s2) { signed char slide1[256], slide2[256]; ge25519_pniels ALIGN(16) pre1[S1_TABLE_SIZE]; @@ -322,13 +330,131 @@ ge25519_double_scalarmult_vartime(ge25519 *r, const ge25519 *p1, const bignum256 } } -#if !defined(HAVE_GE25519_SCALARMULT_BASE_CHOOSE_NIELS) +#ifndef MM16 +# define MM16 __attribute__((aligned(16))) +#endif + +STATIC void +ge25519_scalarmult_vartime(ge25519 *r, const ge25519 *p1, const bignum256modm s1) { + signed char slide1[256]; + ge25519_pniels MM16 pre1[S1_TABLE_SIZE]; + ge25519 MM16 d1; + ge25519_p1p1 MM16 t; + int32_t i; + + contract256_slidingwindow_modm(slide1, s1, S1_SWINDOWSIZE); + + ge25519_double(&d1, p1); + ge25519_full_to_pniels(pre1, p1); + for (i = 0; i < S1_TABLE_SIZE - 1; i++) + ge25519_pnielsadd(&pre1[i+1], &d1, &pre1[i]); + + /* set neutral */ + memset(r, 0, sizeof(ge25519)); + r->y[0] = 1; + r->z[0] = 1; + + i = 255; + while ((i >= 0) && !slide1[i]) + i--; + + for (; i >= 0; i--) { + ge25519_double_p1p1(&t, r); + + if (slide1[i]) { + ge25519_p1p1_to_full(r, &t); + ge25519_pnielsadd_p1p1(&t, r, &pre1[abs(slide1[i]) / 2], (unsigned char)slide1[i] >> 7); + } + + ge25519_p1p1_to_partial(r, &t); + } +} -static uint32_t -ge25519_windowb_equal(uint32_t b, uint32_t c) { - return ((b ^ c) - 1) >> 31; +DONNA_INLINE static void ge25519_cmove_stride4(long * r, long * p, long * pos, long * n, int stride) { + int i; + long x0=p[0], x1=p[1], x2=p[2], x3=p[3], y0, y1, y2, y3; + for(p+=stride; p= 0; i--) { + int k=abs(slide1[i]); + ge25519_double_partial(r, r); + ge25519_double_partial(r, r); + ge25519_double_partial(r, r); + ge25519_double_p1p1(&t, r); + ge25519_move_conditional_pniels_array(&pre, pre1, k, 9); + ge25519_p1p1_to_full(r, &t); + ge25519_pnielsadd_p1p1(&t, r, &pre, (unsigned char)slide1[i] >> 7); + ge25519_p1p1_to_partial(r, &t); + } +} + +#if !defined(HAVE_GE25519_SCALARMULT_BASE_CHOOSE_NIELS) static void ge25519_scalarmult_base_choose_niels(ge25519_niels *t, const uint8_t table[256][96], uint32_t pos, signed char b) { bignum25519 ALIGN(16) neg; @@ -342,8 +468,7 @@ ge25519_scalarmult_base_choose_niels(ge25519_niels *t, const uint8_t table[256][ packed[0] = 1; packed[32] = 1; - for (i = 0; i < 8; i++) - curve25519_move_conditional_bytes(packed, table[(pos * 8) + i], ge25519_windowb_equal(u, i + 1)); + ge25519_move_conditional_niels_array(packed, &table[pos*8], u-1, 8); /* expand in to t */ curve25519_expand(t->ysubx, packed + 0); @@ -355,10 +480,9 @@ ge25519_scalarmult_base_choose_niels(ge25519_niels *t, const uint8_t table[256][ curve25519_neg(neg, t->t2d); curve25519_swap_conditional(t->t2d, neg, sign); } - #endif /* HAVE_GE25519_SCALARMULT_BASE_CHOOSE_NIELS */ -static void +STATIC void ge25519_scalarmult_base_niels(ge25519 *r, const uint8_t table[256][96], const bignum256modm s) { signed char b[64]; uint32_t i; @@ -388,3 +512,8 @@ ge25519_scalarmult_base_niels(ge25519 *r, const uint8_t table[256][96], const bi ge25519_nielsadd2(r, &t); } } + +STATIC void ge25519_scalarmult_base(ge25519 *r, const bignum256modm s) { + ge25519_scalarmult_base_niels(r, ge25519_niels_base_multiples, s); +} + diff --git a/ed25519-donna/ed25519-donna-portable-identify.h b/ed25519-donna/ed25519-donna-portable-identify.h index 26a264cf9..ee3a01cc4 100644 --- a/ed25519-donna/ed25519-donna-portable-identify.h +++ b/ed25519-donna/ed25519-donna-portable-identify.h @@ -49,6 +49,9 @@ #define CPU_X86_64 #elif defined(__i586__) || defined(__i686__) || (defined(_M_IX86) && (_M_IX86 >= 500)) #define CPU_X86 500 + #ifdef __SSE2__ + #define ED25519_SSE2 + #endif #elif defined(__i486__) || (defined(_M_IX86) && (_M_IX86 >= 400)) #define CPU_X86 400 #elif defined(__i386__) || (defined(_M_IX86) && (_M_IX86 >= 300)) || defined(__X86__) || defined(_X86_) || defined(__I86__) diff --git a/ed25519-donna/ed25519.c b/ed25519-donna/ed25519.c index 58a755b8d..b7c35847e 100644 --- a/ed25519-donna/ed25519.c +++ b/ed25519-donna/ed25519.c @@ -13,6 +13,7 @@ #define ED25519_FN3(fn,suffix) fn##suffix #define ED25519_FN2(fn,suffix) ED25519_FN3(fn,suffix) #define ED25519_FN(fn) ED25519_FN2(fn,ED25519_SUFFIX) +#define STATIC static #include "ed25519-donna.h" #include "ed25519.h" diff --git a/ed25519-donna/modm-donna-32bit.h b/ed25519-donna/modm-donna-32bit.h index dfd76be66..5b17b6a74 100644 --- a/ed25519-donna/modm-donna-32bit.h +++ b/ed25519-donna/modm-donna-32bit.h @@ -140,8 +140,7 @@ barrett_reduce256_modm(bignum256modm r, const bignum256modm q1, const bignum256m } /* addition modulo m */ -static void -add256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y) { +STATIC void add256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y) { bignum256modm_element_t c; c = x[0] + y[0]; r[0] = c & 0x3fffffff; c >>= 30; @@ -158,8 +157,7 @@ add256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y) { } /* multiplication modulo m */ -static void -mul256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y) { +STATIC void mul256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y) { bignum256modm r1, q1; uint64_t c; bignum256modm_element_t f; @@ -204,8 +202,7 @@ mul256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y) { barrett_reduce256_modm(r, q1, r1); } -static void -expand256_modm(bignum256modm out, const unsigned char *in, size_t len) { +STATIC void expand256_modm(bignum256modm out, const unsigned char *in, size_t len) { unsigned char work[64] = {0}; bignum256modm_element_t x[16]; bignum256modm q1; @@ -257,8 +254,7 @@ expand256_modm(bignum256modm out, const unsigned char *in, size_t len) { barrett_reduce256_modm(out, q1, out); } -static void -expand_raw256_modm(bignum256modm out, const unsigned char in[32]) { +STATIC void expand_raw256_modm(bignum256modm out, const unsigned char in[32]) { bignum256modm_element_t x[8]; x[0] = U8TO32_LE(in + 0); @@ -281,8 +277,7 @@ expand_raw256_modm(bignum256modm out, const unsigned char in[32]) { out[8] = ((x[ 7] >> 16) ) & 0x0000ffff; } -static void -contract256_modm(unsigned char out[32], const bignum256modm in) { +STATIC void contract256_modm(unsigned char out[32], const bignum256modm in) { U32TO8_LE(out + 0, (in[0] ) | (in[1] << 30)); U32TO8_LE(out + 4, (in[1] >> 2) | (in[2] << 28)); U32TO8_LE(out + 8, (in[2] >> 4) | (in[3] << 26)); @@ -295,8 +290,7 @@ contract256_modm(unsigned char out[32], const bignum256modm in) { -static void -contract256_window4_modm(signed char r[64], const bignum256modm in) { +STATIC void contract256_window4_modm(signed char r[64], const bignum256modm in) { char carry; signed char *quads = r; bignum256modm_element_t i, j, v; @@ -331,8 +325,7 @@ contract256_window4_modm(signed char r[64], const bignum256modm in) { r[63] += carry; } -static void -contract256_slidingwindow_modm(signed char r[256], const bignum256modm s, int windowsize) { +STATIC void contract256_slidingwindow_modm(signed char r[256], const bignum256modm s, int windowsize) { int i,j,k,b; int m = (1 << (windowsize - 1)) - 1, soplen = 256; signed char *bits = r; @@ -379,8 +372,7 @@ contract256_slidingwindow_modm(signed char r[256], const bignum256modm s, int wi */ /* out = a - b, a must be larger than b */ -static void -sub256_modm_batch(bignum256modm out, const bignum256modm a, const bignum256modm b, size_t limbsize) { +STATIC void sub256_modm_batch(bignum256modm out, const bignum256modm a, const bignum256modm b, size_t limbsize) { size_t i = 0; bignum256modm_element_t carry = 0; switch (limbsize) { @@ -399,8 +391,7 @@ sub256_modm_batch(bignum256modm out, const bignum256modm a, const bignum256modm /* is a < b */ -static int -lt256_modm_batch(const bignum256modm a, const bignum256modm b, size_t limbsize) { +STATIC int lt256_modm_batch(const bignum256modm a, const bignum256modm b, size_t limbsize) { switch (limbsize) { case 8: if (a[8] > b[8]) return 0; if (a[8] < b[8]) return 1; case 7: if (a[7] > b[7]) return 0; if (a[7] < b[7]) return 1; @@ -416,8 +407,7 @@ lt256_modm_batch(const bignum256modm a, const bignum256modm b, size_t limbsize) } /* is a <= b */ -static int -lte256_modm_batch(const bignum256modm a, const bignum256modm b, size_t limbsize) { +STATIC int lte256_modm_batch(const bignum256modm a, const bignum256modm b, size_t limbsize) { switch (limbsize) { case 8: if (a[8] > b[8]) return 0; if (a[8] < b[8]) return 1; case 7: if (a[7] > b[7]) return 0; if (a[7] < b[7]) return 1; @@ -434,8 +424,7 @@ lte256_modm_batch(const bignum256modm a, const bignum256modm b, size_t limbsize) /* is a == 0 */ -static int -iszero256_modm_batch(const bignum256modm a) { +STATIC int iszero256_modm_batch(const bignum256modm a) { size_t i; for (i = 0; i < 9; i++) if (a[i]) @@ -444,8 +433,7 @@ iszero256_modm_batch(const bignum256modm a) { } /* is a == 1 */ -static int -isone256_modm_batch(const bignum256modm a) { +STATIC int isone256_modm_batch(const bignum256modm a) { size_t i; if (a[0] != 1) return 0; @@ -456,8 +444,7 @@ isone256_modm_batch(const bignum256modm a) { } /* can a fit in to (at most) 128 bits */ -static int -isatmost128bits256_modm_batch(const bignum256modm a) { +STATIC int isatmost128bits256_modm_batch(const bignum256modm a) { uint32_t mask = ((a[8] ) | /* 16 */ (a[7] ) | /* 46 */ diff --git a/ed25519-donna/modm-donna-64bit.h b/ed25519-donna/modm-donna-64bit.h index a47a38a42..4197f3bf6 100644 --- a/ed25519-donna/modm-donna-64bit.h +++ b/ed25519-donna/modm-donna-64bit.h @@ -107,8 +107,7 @@ barrett_reduce256_modm(bignum256modm r, const bignum256modm q1, const bignum256m } -static void -add256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y) { +STATIC void add256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y) { bignum256modm_element_t c; c = x[0] + y[0]; r[0] = c & 0xffffffffffffff; c >>= 56; @@ -120,8 +119,7 @@ add256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y) { reduce256_modm(r); } -static void -mul256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y) { +STATIC void mul256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y) { bignum256modm q1, r1; uint128_t c, mul; bignum256modm_element_t f; @@ -149,8 +147,7 @@ mul256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y) { barrett_reduce256_modm(r, q1, r1); } -static void -expand256_modm(bignum256modm out, const unsigned char *in, size_t len) { +STATIC void expand256_modm(bignum256modm out, const unsigned char *in, size_t len) { unsigned char work[64] = {0}; bignum256modm_element_t x[16]; bignum256modm q1; @@ -186,8 +183,7 @@ expand256_modm(bignum256modm out, const unsigned char *in, size_t len) { barrett_reduce256_modm(out, q1, out); } -static void -expand_raw256_modm(bignum256modm out, const unsigned char in[32]) { +STATIC void expand_raw256_modm(bignum256modm out, const unsigned char in[32]) { bignum256modm_element_t x[4]; x[0] = U8TO64_LE(in + 0); @@ -202,16 +198,14 @@ expand_raw256_modm(bignum256modm out, const unsigned char in[32]) { out[4] = ((x[ 3] >> 32) ) & 0x000000ffffffff; } -static void -contract256_modm(unsigned char out[32], const bignum256modm in) { +STATIC void contract256_modm(unsigned char out[32], const bignum256modm in) { U64TO8_LE(out + 0, (in[0] ) | (in[1] << 56)); U64TO8_LE(out + 8, (in[1] >> 8) | (in[2] << 48)); U64TO8_LE(out + 16, (in[2] >> 16) | (in[3] << 40)); U64TO8_LE(out + 24, (in[3] >> 24) | (in[4] << 32)); } -static void -contract256_window4_modm(signed char r[64], const bignum256modm in) { +STATIC void contract256_window4_modm(signed char r[64], const bignum256modm in) { char carry; signed char *quads = r; bignum256modm_element_t i, j, v, m; @@ -237,8 +231,7 @@ contract256_window4_modm(signed char r[64], const bignum256modm in) { r[63] += carry; } -static void -contract256_slidingwindow_modm(signed char r[256], const bignum256modm s, int windowsize) { +STATIC void contract256_slidingwindow_modm(signed char r[256], const bignum256modm s, int windowsize) { int i,j,k,b; int m = (1 << (windowsize - 1)) - 1, soplen = 256; signed char *bits = r; @@ -284,8 +277,7 @@ contract256_slidingwindow_modm(signed char r[256], const bignum256modm s, int wi */ /* out = a - b, a must be larger than b */ -static void -sub256_modm_batch(bignum256modm out, const bignum256modm a, const bignum256modm b, size_t limbsize) { +STATIC void sub256_modm_batch(bignum256modm out, const bignum256modm a, const bignum256modm b, size_t limbsize) { size_t i = 0; bignum256modm_element_t carry = 0; switch (limbsize) { @@ -300,8 +292,7 @@ sub256_modm_batch(bignum256modm out, const bignum256modm a, const bignum256modm /* is a < b */ -static int -lt256_modm_batch(const bignum256modm a, const bignum256modm b, size_t limbsize) { +STATIC int lt256_modm_batch(const bignum256modm a, const bignum256modm b, size_t limbsize) { size_t i = 0; bignum256modm_element_t t, carry = 0; switch (limbsize) { @@ -315,8 +306,7 @@ lt256_modm_batch(const bignum256modm a, const bignum256modm b, size_t limbsize) } /* is a <= b */ -static int -lte256_modm_batch(const bignum256modm a, const bignum256modm b, size_t limbsize) { +STATIC int lte256_modm_batch(const bignum256modm a, const bignum256modm b, size_t limbsize) { size_t i = 0; bignum256modm_element_t t, carry = 0; switch (limbsize) { @@ -330,8 +320,7 @@ lte256_modm_batch(const bignum256modm a, const bignum256modm b, size_t limbsize) } /* is a == 0 */ -static int -iszero256_modm_batch(const bignum256modm a) { +STATIC int iszero256_modm_batch(const bignum256modm a) { size_t i; for (i = 0; i < 5; i++) if (a[i]) @@ -340,8 +329,7 @@ iszero256_modm_batch(const bignum256modm a) { } /* is a == 1 */ -static int -isone256_modm_batch(const bignum256modm a) { +STATIC int isone256_modm_batch(const bignum256modm a) { size_t i; for (i = 0; i < 5; i++) if (a[i] != ((i) ? 0 : 1)) @@ -350,8 +338,7 @@ isone256_modm_batch(const bignum256modm a) { } /* can a fit in to (at most) 128 bits */ -static int -isatmost128bits256_modm_batch(const bignum256modm a) { +STATIC int isatmost128bits256_modm_batch(const bignum256modm a) { uint64_t mask = ((a[4] ) | /* 32 */ (a[3] ) | /* 88 */ From 397a13f65404cec013e30de613692cd9cdcb576c Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 28 Mar 2017 18:32:58 +0200 Subject: [PATCH 370/627] simplify ed25519 code --- Makefile | 4 - ed25519-donna/curve25519-donna-64bit.h | 413 ------ ed25519-donna/curve25519-donna-sse2.h | 1112 ----------------- ed25519-donna/ed25519-donna-32bit-sse2.h | 513 -------- ed25519-donna/ed25519-donna-64bit-sse2.h | 436 ------- ed25519-donna/ed25519-donna-64bit-tables.h | 53 - ed25519-donna/ed25519-donna-64bit-x86-32bit.h | 435 ------- ed25519-donna/ed25519-donna-64bit-x86.h | 351 ------ ed25519-donna/ed25519-donna-batchverify.h | 275 ---- ed25519-donna/ed25519-donna-impl-sse2.h | 519 -------- .../ed25519-donna-portable-identify.h | 106 -- ed25519-donna/ed25519-donna-portable.h | 130 +- ed25519-donna/ed25519-donna.h | 63 +- ed25519-donna/ed25519-hash.h | 219 ---- ed25519-donna/ed25519-randombytes-custom.h | 12 - ed25519-donna/ed25519-randombytes.h | 91 -- ed25519-donna/ed25519.c | 5 +- ed25519-donna/ed25519.h | 2 - ed25519-donna/modm-donna-64bit.h | 348 ------ 19 files changed, 15 insertions(+), 5072 deletions(-) delete mode 100644 ed25519-donna/curve25519-donna-64bit.h delete mode 100644 ed25519-donna/curve25519-donna-sse2.h delete mode 100644 ed25519-donna/ed25519-donna-32bit-sse2.h delete mode 100644 ed25519-donna/ed25519-donna-64bit-sse2.h delete mode 100644 ed25519-donna/ed25519-donna-64bit-tables.h delete mode 100644 ed25519-donna/ed25519-donna-64bit-x86-32bit.h delete mode 100644 ed25519-donna/ed25519-donna-64bit-x86.h delete mode 100644 ed25519-donna/ed25519-donna-batchverify.h delete mode 100644 ed25519-donna/ed25519-donna-impl-sse2.h delete mode 100644 ed25519-donna/ed25519-donna-portable-identify.h delete mode 100644 ed25519-donna/ed25519-hash.h delete mode 100644 ed25519-donna/ed25519-randombytes-custom.h delete mode 100644 ed25519-donna/ed25519-randombytes.h delete mode 100644 ed25519-donna/modm-donna-64bit.h diff --git a/Makefile b/Makefile index 74e766803..65275c370 100644 --- a/Makefile +++ b/Makefile @@ -26,10 +26,6 @@ CFLAGS += $(OPTFLAGS) \ # disable sequence point warning because of AES code CFLAGS += -Wno-sequence-point -CFLAGS += -DED25519_CUSTOMRANDOM=1 -CFLAGS += -DED25519_CUSTOMHASH=1 -CFLAGS += -DED25519_NO_INLINE_ASM -CFLAGS += -DED25519_FORCE_32BIT=1 CFLAGS += -Ied25519-donna -Icurve25519-donna -I. CFLAGS += -DUSE_ETHEREUM=1 CFLAGS += -DUSE_GRAPHENE=1 diff --git a/ed25519-donna/curve25519-donna-64bit.h b/ed25519-donna/curve25519-donna-64bit.h deleted file mode 100644 index 2941d1bcd..000000000 --- a/ed25519-donna/curve25519-donna-64bit.h +++ /dev/null @@ -1,413 +0,0 @@ -/* - Public domain by Adam Langley & - Andrew M. - See: https://github.com/floodyberry/curve25519-donna - - 64bit integer curve25519 implementation -*/ - -typedef uint64_t bignum25519[5]; - -static const uint64_t reduce_mask_40 = ((uint64_t)1 << 40) - 1; -static const uint64_t reduce_mask_51 = ((uint64_t)1 << 51) - 1; -static const uint64_t reduce_mask_56 = ((uint64_t)1 << 56) - 1; - -/* out = in */ -DONNA_INLINE static void -curve25519_copy(bignum25519 out, const bignum25519 in) { - out[0] = in[0]; - out[1] = in[1]; - out[2] = in[2]; - out[3] = in[3]; - out[4] = in[4]; -} - -/* out = a + b */ -DONNA_INLINE static void -curve25519_add(bignum25519 out, const bignum25519 a, const bignum25519 b) { - out[0] = a[0] + b[0]; - out[1] = a[1] + b[1]; - out[2] = a[2] + b[2]; - out[3] = a[3] + b[3]; - out[4] = a[4] + b[4]; -} - -/* out = a + b, where a and/or b are the result of a basic op (add,sub) */ -DONNA_INLINE static void -curve25519_add_after_basic(bignum25519 out, const bignum25519 a, const bignum25519 b) { - out[0] = a[0] + b[0]; - out[1] = a[1] + b[1]; - out[2] = a[2] + b[2]; - out[3] = a[3] + b[3]; - out[4] = a[4] + b[4]; -} - -DONNA_INLINE static void -curve25519_add_reduce(bignum25519 out, const bignum25519 a, const bignum25519 b) { - uint64_t c; - out[0] = a[0] + b[0] ; c = (out[0] >> 51); out[0] &= reduce_mask_51; - out[1] = a[1] + b[1] + c; c = (out[1] >> 51); out[1] &= reduce_mask_51; - out[2] = a[2] + b[2] + c; c = (out[2] >> 51); out[2] &= reduce_mask_51; - out[3] = a[3] + b[3] + c; c = (out[3] >> 51); out[3] &= reduce_mask_51; - out[4] = a[4] + b[4] + c; c = (out[4] >> 51); out[4] &= reduce_mask_51; - out[0] += c * 19; -} - -/* multiples of p */ -static const uint64_t twoP0 = 0x0fffffffffffda; -static const uint64_t twoP1234 = 0x0ffffffffffffe; -static const uint64_t fourP0 = 0x1fffffffffffb4; -static const uint64_t fourP1234 = 0x1ffffffffffffc; - -/* out = a - b */ -DONNA_INLINE static void -curve25519_sub(bignum25519 out, const bignum25519 a, const bignum25519 b) { - out[0] = a[0] + twoP0 - b[0]; - out[1] = a[1] + twoP1234 - b[1]; - out[2] = a[2] + twoP1234 - b[2]; - out[3] = a[3] + twoP1234 - b[3]; - out[4] = a[4] + twoP1234 - b[4]; -} - -/* out = a - b, where a and/or b are the result of a basic op (add,sub) */ -DONNA_INLINE static void -curve25519_sub_after_basic(bignum25519 out, const bignum25519 a, const bignum25519 b) { - out[0] = a[0] + fourP0 - b[0]; - out[1] = a[1] + fourP1234 - b[1]; - out[2] = a[2] + fourP1234 - b[2]; - out[3] = a[3] + fourP1234 - b[3]; - out[4] = a[4] + fourP1234 - b[4]; -} - -DONNA_INLINE static void -curve25519_sub_reduce(bignum25519 out, const bignum25519 a, const bignum25519 b) { - uint64_t c; - out[0] = a[0] + fourP0 - b[0] ; c = (out[0] >> 51); out[0] &= reduce_mask_51; - out[1] = a[1] + fourP1234 - b[1] + c; c = (out[1] >> 51); out[1] &= reduce_mask_51; - out[2] = a[2] + fourP1234 - b[2] + c; c = (out[2] >> 51); out[2] &= reduce_mask_51; - out[3] = a[3] + fourP1234 - b[3] + c; c = (out[3] >> 51); out[3] &= reduce_mask_51; - out[4] = a[4] + fourP1234 - b[4] + c; c = (out[4] >> 51); out[4] &= reduce_mask_51; - out[0] += c * 19; -} - -/* out = -a */ -DONNA_INLINE static void -curve25519_neg(bignum25519 out, const bignum25519 a) { - uint64_t c; - out[0] = twoP0 - a[0] ; c = (out[0] >> 51); out[0] &= reduce_mask_51; - out[1] = twoP1234 - a[1] + c; c = (out[1] >> 51); out[1] &= reduce_mask_51; - out[2] = twoP1234 - a[2] + c; c = (out[2] >> 51); out[2] &= reduce_mask_51; - out[3] = twoP1234 - a[3] + c; c = (out[3] >> 51); out[3] &= reduce_mask_51; - out[4] = twoP1234 - a[4] + c; c = (out[4] >> 51); out[4] &= reduce_mask_51; - out[0] += c * 19; -} - -/* out = a * b */ -DONNA_INLINE static void -curve25519_mul(bignum25519 out, const bignum25519 in2, const bignum25519 in) { -#if !defined(HAVE_NATIVE_UINT128) - uint128_t mul; -#endif - uint128_t t[5]; - uint64_t r0,r1,r2,r3,r4,s0,s1,s2,s3,s4,c; - - r0 = in[0]; - r1 = in[1]; - r2 = in[2]; - r3 = in[3]; - r4 = in[4]; - - s0 = in2[0]; - s1 = in2[1]; - s2 = in2[2]; - s3 = in2[3]; - s4 = in2[4]; - -#if defined(HAVE_NATIVE_UINT128) - t[0] = ((uint128_t) r0) * s0; - t[1] = ((uint128_t) r0) * s1 + ((uint128_t) r1) * s0; - t[2] = ((uint128_t) r0) * s2 + ((uint128_t) r2) * s0 + ((uint128_t) r1) * s1; - t[3] = ((uint128_t) r0) * s3 + ((uint128_t) r3) * s0 + ((uint128_t) r1) * s2 + ((uint128_t) r2) * s1; - t[4] = ((uint128_t) r0) * s4 + ((uint128_t) r4) * s0 + ((uint128_t) r3) * s1 + ((uint128_t) r1) * s3 + ((uint128_t) r2) * s2; -#else - mul64x64_128(t[0], r0, s0) - mul64x64_128(t[1], r0, s1) mul64x64_128(mul, r1, s0) add128(t[1], mul) - mul64x64_128(t[2], r0, s2) mul64x64_128(mul, r2, s0) add128(t[2], mul) mul64x64_128(mul, r1, s1) add128(t[2], mul) - mul64x64_128(t[3], r0, s3) mul64x64_128(mul, r3, s0) add128(t[3], mul) mul64x64_128(mul, r1, s2) add128(t[3], mul) mul64x64_128(mul, r2, s1) add128(t[3], mul) - mul64x64_128(t[4], r0, s4) mul64x64_128(mul, r4, s0) add128(t[4], mul) mul64x64_128(mul, r3, s1) add128(t[4], mul) mul64x64_128(mul, r1, s3) add128(t[4], mul) mul64x64_128(mul, r2, s2) add128(t[4], mul) -#endif - - r1 *= 19; - r2 *= 19; - r3 *= 19; - r4 *= 19; - -#if defined(HAVE_NATIVE_UINT128) - t[0] += ((uint128_t) r4) * s1 + ((uint128_t) r1) * s4 + ((uint128_t) r2) * s3 + ((uint128_t) r3) * s2; - t[1] += ((uint128_t) r4) * s2 + ((uint128_t) r2) * s4 + ((uint128_t) r3) * s3; - t[2] += ((uint128_t) r4) * s3 + ((uint128_t) r3) * s4; - t[3] += ((uint128_t) r4) * s4; -#else - mul64x64_128(mul, r4, s1) add128(t[0], mul) mul64x64_128(mul, r1, s4) add128(t[0], mul) mul64x64_128(mul, r2, s3) add128(t[0], mul) mul64x64_128(mul, r3, s2) add128(t[0], mul) - mul64x64_128(mul, r4, s2) add128(t[1], mul) mul64x64_128(mul, r2, s4) add128(t[1], mul) mul64x64_128(mul, r3, s3) add128(t[1], mul) - mul64x64_128(mul, r4, s3) add128(t[2], mul) mul64x64_128(mul, r3, s4) add128(t[2], mul) - mul64x64_128(mul, r4, s4) add128(t[3], mul) -#endif - - - r0 = lo128(t[0]) & reduce_mask_51; shr128(c, t[0], 51); - add128_64(t[1], c) r1 = lo128(t[1]) & reduce_mask_51; shr128(c, t[1], 51); - add128_64(t[2], c) r2 = lo128(t[2]) & reduce_mask_51; shr128(c, t[2], 51); - add128_64(t[3], c) r3 = lo128(t[3]) & reduce_mask_51; shr128(c, t[3], 51); - add128_64(t[4], c) r4 = lo128(t[4]) & reduce_mask_51; shr128(c, t[4], 51); - r0 += c * 19; c = r0 >> 51; r0 = r0 & reduce_mask_51; - r1 += c; - - out[0] = r0; - out[1] = r1; - out[2] = r2; - out[3] = r3; - out[4] = r4; -} - -DONNA_NOINLINE static void -curve25519_mul_noinline(bignum25519 out, const bignum25519 in2, const bignum25519 in) { - curve25519_mul(out, in2, in); -} - -/* out = in^(2 * count) */ -DONNA_NOINLINE static void -curve25519_square_times(bignum25519 out, const bignum25519 in, uint64_t count) { -#if !defined(HAVE_NATIVE_UINT128) - uint128_t mul; -#endif - uint128_t t[5]; - uint64_t r0,r1,r2,r3,r4,c; - uint64_t d0,d1,d2,d4,d419; - - r0 = in[0]; - r1 = in[1]; - r2 = in[2]; - r3 = in[3]; - r4 = in[4]; - - do { - d0 = r0 * 2; - d1 = r1 * 2; - d2 = r2 * 2 * 19; - d419 = r4 * 19; - d4 = d419 * 2; - -#if defined(HAVE_NATIVE_UINT128) - t[0] = ((uint128_t) r0) * r0 + ((uint128_t) d4) * r1 + (((uint128_t) d2) * (r3 )); - t[1] = ((uint128_t) d0) * r1 + ((uint128_t) d4) * r2 + (((uint128_t) r3) * (r3 * 19)); - t[2] = ((uint128_t) d0) * r2 + ((uint128_t) r1) * r1 + (((uint128_t) d4) * (r3 )); - t[3] = ((uint128_t) d0) * r3 + ((uint128_t) d1) * r2 + (((uint128_t) r4) * (d419 )); - t[4] = ((uint128_t) d0) * r4 + ((uint128_t) d1) * r3 + (((uint128_t) r2) * (r2 )); -#else - mul64x64_128(t[0], r0, r0) mul64x64_128(mul, d4, r1) add128(t[0], mul) mul64x64_128(mul, d2, r3) add128(t[0], mul) - mul64x64_128(t[1], d0, r1) mul64x64_128(mul, d4, r2) add128(t[1], mul) mul64x64_128(mul, r3, r3 * 19) add128(t[1], mul) - mul64x64_128(t[2], d0, r2) mul64x64_128(mul, r1, r1) add128(t[2], mul) mul64x64_128(mul, d4, r3) add128(t[2], mul) - mul64x64_128(t[3], d0, r3) mul64x64_128(mul, d1, r2) add128(t[3], mul) mul64x64_128(mul, r4, d419) add128(t[3], mul) - mul64x64_128(t[4], d0, r4) mul64x64_128(mul, d1, r3) add128(t[4], mul) mul64x64_128(mul, r2, r2) add128(t[4], mul) -#endif - - r0 = lo128(t[0]) & reduce_mask_51; - r1 = lo128(t[1]) & reduce_mask_51; shl128(c, t[0], 13); r1 += c; - r2 = lo128(t[2]) & reduce_mask_51; shl128(c, t[1], 13); r2 += c; - r3 = lo128(t[3]) & reduce_mask_51; shl128(c, t[2], 13); r3 += c; - r4 = lo128(t[4]) & reduce_mask_51; shl128(c, t[3], 13); r4 += c; - shl128(c, t[4], 13); r0 += c * 19; - c = r0 >> 51; r0 &= reduce_mask_51; - r1 += c ; c = r1 >> 51; r1 &= reduce_mask_51; - r2 += c ; c = r2 >> 51; r2 &= reduce_mask_51; - r3 += c ; c = r3 >> 51; r3 &= reduce_mask_51; - r4 += c ; c = r4 >> 51; r4 &= reduce_mask_51; - r0 += c * 19; - } while(--count); - - out[0] = r0; - out[1] = r1; - out[2] = r2; - out[3] = r3; - out[4] = r4; -} - -DONNA_INLINE static void -curve25519_square(bignum25519 out, const bignum25519 in) { -#if !defined(HAVE_NATIVE_UINT128) - uint128_t mul; -#endif - uint128_t t[5]; - uint64_t r0,r1,r2,r3,r4,c; - uint64_t d0,d1,d2,d4,d419; - - r0 = in[0]; - r1 = in[1]; - r2 = in[2]; - r3 = in[3]; - r4 = in[4]; - - d0 = r0 * 2; - d1 = r1 * 2; - d2 = r2 * 2 * 19; - d419 = r4 * 19; - d4 = d419 * 2; - -#if defined(HAVE_NATIVE_UINT128) - t[0] = ((uint128_t) r0) * r0 + ((uint128_t) d4) * r1 + (((uint128_t) d2) * (r3 )); - t[1] = ((uint128_t) d0) * r1 + ((uint128_t) d4) * r2 + (((uint128_t) r3) * (r3 * 19)); - t[2] = ((uint128_t) d0) * r2 + ((uint128_t) r1) * r1 + (((uint128_t) d4) * (r3 )); - t[3] = ((uint128_t) d0) * r3 + ((uint128_t) d1) * r2 + (((uint128_t) r4) * (d419 )); - t[4] = ((uint128_t) d0) * r4 + ((uint128_t) d1) * r3 + (((uint128_t) r2) * (r2 )); -#else - mul64x64_128(t[0], r0, r0) mul64x64_128(mul, d4, r1) add128(t[0], mul) mul64x64_128(mul, d2, r3) add128(t[0], mul) - mul64x64_128(t[1], d0, r1) mul64x64_128(mul, d4, r2) add128(t[1], mul) mul64x64_128(mul, r3, r3 * 19) add128(t[1], mul) - mul64x64_128(t[2], d0, r2) mul64x64_128(mul, r1, r1) add128(t[2], mul) mul64x64_128(mul, d4, r3) add128(t[2], mul) - mul64x64_128(t[3], d0, r3) mul64x64_128(mul, d1, r2) add128(t[3], mul) mul64x64_128(mul, r4, d419) add128(t[3], mul) - mul64x64_128(t[4], d0, r4) mul64x64_128(mul, d1, r3) add128(t[4], mul) mul64x64_128(mul, r2, r2) add128(t[4], mul) -#endif - - r0 = lo128(t[0]) & reduce_mask_51; shr128(c, t[0], 51); - add128_64(t[1], c) r1 = lo128(t[1]) & reduce_mask_51; shr128(c, t[1], 51); - add128_64(t[2], c) r2 = lo128(t[2]) & reduce_mask_51; shr128(c, t[2], 51); - add128_64(t[3], c) r3 = lo128(t[3]) & reduce_mask_51; shr128(c, t[3], 51); - add128_64(t[4], c) r4 = lo128(t[4]) & reduce_mask_51; shr128(c, t[4], 51); - r0 += c * 19; c = r0 >> 51; r0 = r0 & reduce_mask_51; - r1 += c; - - out[0] = r0; - out[1] = r1; - out[2] = r2; - out[3] = r3; - out[4] = r4; -} - -/* Take a little-endian, 32-byte number and expand it into polynomial form */ -DONNA_INLINE static void -curve25519_expand(bignum25519 out, const unsigned char *in) { - static const union { uint8_t b[2]; uint16_t s; } endian_check = {{1,0}}; - uint64_t x0,x1,x2,x3; - - if (endian_check.s == 1) { - x0 = *(uint64_t *)(in + 0); - x1 = *(uint64_t *)(in + 8); - x2 = *(uint64_t *)(in + 16); - x3 = *(uint64_t *)(in + 24); - } else { - #define F(s) \ - ((((uint64_t)in[s + 0]) ) | \ - (((uint64_t)in[s + 1]) << 8) | \ - (((uint64_t)in[s + 2]) << 16) | \ - (((uint64_t)in[s + 3]) << 24) | \ - (((uint64_t)in[s + 4]) << 32) | \ - (((uint64_t)in[s + 5]) << 40) | \ - (((uint64_t)in[s + 6]) << 48) | \ - (((uint64_t)in[s + 7]) << 56)) - - x0 = F(0); - x1 = F(8); - x2 = F(16); - x3 = F(24); - } - - out[0] = x0 & reduce_mask_51; x0 = (x0 >> 51) | (x1 << 13); - out[1] = x0 & reduce_mask_51; x1 = (x1 >> 38) | (x2 << 26); - out[2] = x1 & reduce_mask_51; x2 = (x2 >> 25) | (x3 << 39); - out[3] = x2 & reduce_mask_51; x3 = (x3 >> 12); - out[4] = x3 & reduce_mask_51; -} - -/* Take a fully reduced polynomial form number and contract it into a - * little-endian, 32-byte array - */ -DONNA_INLINE static void -curve25519_contract(unsigned char *out, const bignum25519 input) { - uint64_t t[5]; - uint64_t f, i; - - t[0] = input[0]; - t[1] = input[1]; - t[2] = input[2]; - t[3] = input[3]; - t[4] = input[4]; - - #define curve25519_contract_carry() \ - t[1] += t[0] >> 51; t[0] &= reduce_mask_51; \ - t[2] += t[1] >> 51; t[1] &= reduce_mask_51; \ - t[3] += t[2] >> 51; t[2] &= reduce_mask_51; \ - t[4] += t[3] >> 51; t[3] &= reduce_mask_51; - - #define curve25519_contract_carry_full() curve25519_contract_carry() \ - t[0] += 19 * (t[4] >> 51); t[4] &= reduce_mask_51; - - #define curve25519_contract_carry_final() curve25519_contract_carry() \ - t[4] &= reduce_mask_51; - - curve25519_contract_carry_full() - curve25519_contract_carry_full() - - /* now t is between 0 and 2^255-1, properly carried. */ - /* case 1: between 0 and 2^255-20. case 2: between 2^255-19 and 2^255-1. */ - t[0] += 19; - curve25519_contract_carry_full() - - /* now between 19 and 2^255-1 in both cases, and offset by 19. */ - t[0] += (reduce_mask_51 + 1) - 19; - t[1] += (reduce_mask_51 + 1) - 1; - t[2] += (reduce_mask_51 + 1) - 1; - t[3] += (reduce_mask_51 + 1) - 1; - t[4] += (reduce_mask_51 + 1) - 1; - - /* now between 2^255 and 2^256-20, and offset by 2^255. */ - curve25519_contract_carry_final() - - #define write51full(n,shift) \ - f = ((t[n] >> shift) | (t[n+1] << (51 - shift))); \ - for (i = 0; i < 8; i++, f >>= 8) *out++ = (unsigned char)f; - #define write51(n) write51full(n,13*n) - write51(0) - write51(1) - write51(2) - write51(3) -} - -#if !defined(ED25519_GCC_64BIT_CHOOSE) - -/* out = (flag) ? in : out */ -DONNA_INLINE static void -curve25519_move_conditional_bytes(uint8_t out[96], const uint8_t in[96], uint64_t flag) { - const uint64_t nb = flag - 1, b = ~nb; - const uint64_t *inq = (const uint64_t *)in; - uint64_t *outq = (uint64_t *)out; - outq[0] = (outq[0] & nb) | (inq[0] & b); - outq[1] = (outq[1] & nb) | (inq[1] & b); - outq[2] = (outq[2] & nb) | (inq[2] & b); - outq[3] = (outq[3] & nb) | (inq[3] & b); - outq[4] = (outq[4] & nb) | (inq[4] & b); - outq[5] = (outq[5] & nb) | (inq[5] & b); - outq[6] = (outq[6] & nb) | (inq[6] & b); - outq[7] = (outq[7] & nb) | (inq[7] & b); - outq[8] = (outq[8] & nb) | (inq[8] & b); - outq[9] = (outq[9] & nb) | (inq[9] & b); - outq[10] = (outq[10] & nb) | (inq[10] & b); - outq[11] = (outq[11] & nb) | (inq[11] & b); -} - -/* if (iswap) swap(a, b) */ -DONNA_INLINE static void -curve25519_swap_conditional(bignum25519 a, bignum25519 b, uint64_t iswap) { - const uint64_t swap = (uint64_t)(-(int64_t)iswap); - uint64_t x0,x1,x2,x3,x4; - - x0 = swap & (a[0] ^ b[0]); a[0] ^= x0; b[0] ^= x0; - x1 = swap & (a[1] ^ b[1]); a[1] ^= x1; b[1] ^= x1; - x2 = swap & (a[2] ^ b[2]); a[2] ^= x2; b[2] ^= x2; - x3 = swap & (a[3] ^ b[3]); a[3] ^= x3; b[3] ^= x3; - x4 = swap & (a[4] ^ b[4]); a[4] ^= x4; b[4] ^= x4; -} - -#endif /* ED25519_GCC_64BIT_CHOOSE */ - -#define ED25519_64BIT_TABLES - diff --git a/ed25519-donna/curve25519-donna-sse2.h b/ed25519-donna/curve25519-donna-sse2.h deleted file mode 100644 index 1dbfd44d8..000000000 --- a/ed25519-donna/curve25519-donna-sse2.h +++ /dev/null @@ -1,1112 +0,0 @@ -/* - Public domain by Andrew M. - See: https://github.com/floodyberry/curve25519-donna - - SSE2 curve25519 implementation -*/ - -#include -typedef __m128i xmmi; - -typedef union packedelem8_t { - unsigned char u[16]; - xmmi v; -} packedelem8; - -typedef union packedelem32_t { - uint32_t u[4]; - xmmi v; -} packedelem32; - -typedef union packedelem64_t { - uint64_t u[2]; - xmmi v; -} packedelem64; - -/* 10 elements + an extra 2 to fit in 3 xmm registers */ -typedef uint32_t bignum25519[12]; -typedef packedelem32 packed32bignum25519[5]; -typedef packedelem64 packed64bignum25519[10]; - -static const packedelem32 bot32bitmask = {{0xffffffff, 0x00000000, 0xffffffff, 0x00000000}}; -static const packedelem32 top32bitmask = {{0x00000000, 0xffffffff, 0x00000000, 0xffffffff}}; -static const packedelem32 top64bitmask = {{0x00000000, 0x00000000, 0xffffffff, 0xffffffff}}; -static const packedelem32 bot64bitmask = {{0xffffffff, 0xffffffff, 0x00000000, 0x00000000}}; - -/* reduction masks */ -static const packedelem64 packedmask26 = {{0x03ffffff, 0x03ffffff}}; -static const packedelem64 packedmask25 = {{0x01ffffff, 0x01ffffff}}; -static const packedelem32 packedmask2625 = {{0x3ffffff,0,0x1ffffff,0}}; -static const packedelem32 packedmask26262626 = {{0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff}}; -static const packedelem32 packedmask25252525 = {{0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff}}; - -/* multipliers */ -static const packedelem64 packednineteen = {{19, 19}}; -static const packedelem64 packednineteenone = {{19, 1}}; -static const packedelem64 packedthirtyeight = {{38, 38}}; -static const packedelem64 packed3819 = {{19*2,19}}; -static const packedelem64 packed9638 = {{19*4,19*2}}; - -/* 121666,121665 */ -static const packedelem64 packed121666121665 = {{121666, 121665}}; - -/* 2*(2^255 - 19) = 0 mod p */ -static const packedelem32 packed2p0 = {{0x7ffffda,0x3fffffe,0x7fffffe,0x3fffffe}}; -static const packedelem32 packed2p1 = {{0x7fffffe,0x3fffffe,0x7fffffe,0x3fffffe}}; -static const packedelem32 packed2p2 = {{0x7fffffe,0x3fffffe,0x0000000,0x0000000}}; - -static const packedelem32 packed32packed2p0 = {{0x7ffffda,0x7ffffda,0x3fffffe,0x3fffffe}}; -static const packedelem32 packed32packed2p1 = {{0x7fffffe,0x7fffffe,0x3fffffe,0x3fffffe}}; - -/* 4*(2^255 - 19) = 0 mod p */ -static const packedelem32 packed4p0 = {{0xfffffb4,0x7fffffc,0xffffffc,0x7fffffc}}; -static const packedelem32 packed4p1 = {{0xffffffc,0x7fffffc,0xffffffc,0x7fffffc}}; -static const packedelem32 packed4p2 = {{0xffffffc,0x7fffffc,0x0000000,0x0000000}}; - -static const packedelem32 packed32packed4p0 = {{0xfffffb4,0xfffffb4,0x7fffffc,0x7fffffc}}; -static const packedelem32 packed32packed4p1 = {{0xffffffc,0xffffffc,0x7fffffc,0x7fffffc}}; - -/* out = in */ -DONNA_INLINE static void -curve25519_copy(bignum25519 out, const bignum25519 in) { - xmmi x0,x1,x2; - x0 = _mm_load_si128((xmmi*)in + 0); - x1 = _mm_load_si128((xmmi*)in + 1); - x2 = _mm_load_si128((xmmi*)in + 2); - _mm_store_si128((xmmi*)out + 0, x0); - _mm_store_si128((xmmi*)out + 1, x1); - _mm_store_si128((xmmi*)out + 2, x2); -} - -/* out = a + b */ -DONNA_INLINE static void -curve25519_add(bignum25519 out, const bignum25519 a, const bignum25519 b) { - xmmi a0,a1,a2,b0,b1,b2; - a0 = _mm_load_si128((xmmi*)a + 0); - a1 = _mm_load_si128((xmmi*)a + 1); - a2 = _mm_load_si128((xmmi*)a + 2); - b0 = _mm_load_si128((xmmi*)b + 0); - b1 = _mm_load_si128((xmmi*)b + 1); - b2 = _mm_load_si128((xmmi*)b + 2); - a0 = _mm_add_epi32(a0, b0); - a1 = _mm_add_epi32(a1, b1); - a2 = _mm_add_epi32(a2, b2); - _mm_store_si128((xmmi*)out + 0, a0); - _mm_store_si128((xmmi*)out + 1, a1); - _mm_store_si128((xmmi*)out + 2, a2); -} - -#define curve25519_add_after_basic curve25519_add_reduce -DONNA_INLINE static void -curve25519_add_reduce(bignum25519 out, const bignum25519 a, const bignum25519 b) { - xmmi a0,a1,a2,b0,b1,b2; - xmmi c1,c2,c3; - xmmi r0,r1,r2,r3,r4,r5; - - a0 = _mm_load_si128((xmmi*)a + 0); - a1 = _mm_load_si128((xmmi*)a + 1); - a2 = _mm_load_si128((xmmi*)a + 2); - b0 = _mm_load_si128((xmmi*)b + 0); - b1 = _mm_load_si128((xmmi*)b + 1); - b2 = _mm_load_si128((xmmi*)b + 2); - a0 = _mm_add_epi32(a0, b0); - a1 = _mm_add_epi32(a1, b1); - a2 = _mm_add_epi32(a2, b2); - - r0 = _mm_and_si128(_mm_unpacklo_epi64(a0, a1), bot32bitmask.v); - r1 = _mm_srli_epi64(_mm_unpacklo_epi64(a0, a1), 32); - r2 = _mm_and_si128(_mm_unpackhi_epi64(a0, a1), bot32bitmask.v); - r3 = _mm_srli_epi64(_mm_unpackhi_epi64(a0, a1), 32); - r4 = _mm_and_si128(_mm_unpacklo_epi64(_mm_setzero_si128(), a2), bot32bitmask.v); - r5 = _mm_srli_epi64(_mm_unpacklo_epi64(_mm_setzero_si128(), a2), 32); - - c1 = _mm_srli_epi64(r0, 26); c2 = _mm_srli_epi64(r2, 26); r0 = _mm_and_si128(r0, packedmask26.v); r2 = _mm_and_si128(r2, packedmask26.v); r1 = _mm_add_epi64(r1, c1); r3 = _mm_add_epi64(r3, c2); - c1 = _mm_srli_epi64(r1, 25); c2 = _mm_srli_epi64(r3, 25); r1 = _mm_and_si128(r1, packedmask25.v); r3 = _mm_and_si128(r3, packedmask25.v); r2 = _mm_add_epi64(r2, c1); r4 = _mm_add_epi64(r4, c2); c3 = _mm_slli_si128(c2, 8); - c1 = _mm_srli_epi64(r4, 26); r4 = _mm_and_si128(r4, packedmask26.v); r5 = _mm_add_epi64(r5, c1); - c1 = _mm_srli_epi64(r5, 25); r5 = _mm_and_si128(r5, packedmask25.v); r0 = _mm_add_epi64(r0, _mm_unpackhi_epi64(_mm_mul_epu32(c1, packednineteen.v), c3)); - c1 = _mm_srli_epi64(r0, 26); c2 = _mm_srli_epi64(r2, 26); r0 = _mm_and_si128(r0, packedmask26.v); r2 = _mm_and_si128(r2, packedmask26.v); r1 = _mm_add_epi64(r1, c1); r3 = _mm_add_epi64(r3, c2); - - _mm_store_si128((xmmi*)out + 0, _mm_unpacklo_epi64(_mm_unpacklo_epi32(r0, r1), _mm_unpacklo_epi32(r2, r3))); - _mm_store_si128((xmmi*)out + 1, _mm_unpacklo_epi64(_mm_unpackhi_epi32(r0, r1), _mm_unpackhi_epi32(r2, r3))); - _mm_store_si128((xmmi*)out + 2, _mm_unpackhi_epi32(r4, r5)); -} - -DONNA_INLINE static void -curve25519_sub(bignum25519 out, const bignum25519 a, const bignum25519 b) { - xmmi a0,a1,a2,b0,b1,b2; - xmmi c1,c2; - xmmi r0,r1; - - a0 = _mm_load_si128((xmmi*)a + 0); - a1 = _mm_load_si128((xmmi*)a + 1); - a2 = _mm_load_si128((xmmi*)a + 2); - a0 = _mm_add_epi32(a0, packed2p0.v); - a1 = _mm_add_epi32(a1, packed2p1.v); - a2 = _mm_add_epi32(a2, packed2p2.v); - b0 = _mm_load_si128((xmmi*)b + 0); - b1 = _mm_load_si128((xmmi*)b + 1); - b2 = _mm_load_si128((xmmi*)b + 2); - a0 = _mm_sub_epi32(a0, b0); - a1 = _mm_sub_epi32(a1, b1); - a2 = _mm_sub_epi32(a2, b2); - - r0 = _mm_and_si128(_mm_shuffle_epi32(a0, _MM_SHUFFLE(2,2,0,0)), bot32bitmask.v); - r1 = _mm_and_si128(_mm_shuffle_epi32(a0, _MM_SHUFFLE(3,3,1,1)), bot32bitmask.v); - - c1 = _mm_srli_epi32(r0, 26); - c2 = _mm_srli_epi32(r1, 25); - r0 = _mm_and_si128(r0, packedmask26.v); - r1 = _mm_and_si128(r1, packedmask25.v); - r0 = _mm_add_epi32(r0, _mm_slli_si128(c2, 8)); - r1 = _mm_add_epi32(r1, c1); - - a0 = _mm_unpacklo_epi64(_mm_unpacklo_epi32(r0, r1), _mm_unpackhi_epi32(r0, r1)); - a1 = _mm_add_epi32(a1, _mm_srli_si128(c2, 8)); - - _mm_store_si128((xmmi*)out + 0, a0); - _mm_store_si128((xmmi*)out + 1, a1); - _mm_store_si128((xmmi*)out + 2, a2); -} - -DONNA_INLINE static void -curve25519_sub_after_basic(bignum25519 out, const bignum25519 a, const bignum25519 b) { - xmmi a0,a1,a2,b0,b1,b2; - xmmi c1,c2,c3; - xmmi r0,r1,r2,r3,r4,r5; - - a0 = _mm_load_si128((xmmi*)a + 0); - a1 = _mm_load_si128((xmmi*)a + 1); - a2 = _mm_load_si128((xmmi*)a + 2); - a0 = _mm_add_epi32(a0, packed4p0.v); - a1 = _mm_add_epi32(a1, packed4p1.v); - a2 = _mm_add_epi32(a2, packed4p2.v); - b0 = _mm_load_si128((xmmi*)b + 0); - b1 = _mm_load_si128((xmmi*)b + 1); - b2 = _mm_load_si128((xmmi*)b + 2); - a0 = _mm_sub_epi32(a0, b0); - a1 = _mm_sub_epi32(a1, b1); - a2 = _mm_sub_epi32(a2, b2); - - r0 = _mm_and_si128(_mm_unpacklo_epi64(a0, a1), bot32bitmask.v); - r1 = _mm_srli_epi64(_mm_unpacklo_epi64(a0, a1), 32); - r2 = _mm_and_si128(_mm_unpackhi_epi64(a0, a1), bot32bitmask.v); - r3 = _mm_srli_epi64(_mm_unpackhi_epi64(a0, a1), 32); - r4 = _mm_and_si128(_mm_unpacklo_epi64(_mm_setzero_si128(), a2), bot32bitmask.v); - r5 = _mm_srli_epi64(_mm_unpacklo_epi64(_mm_setzero_si128(), a2), 32); - - c1 = _mm_srli_epi64(r0, 26); c2 = _mm_srli_epi64(r2, 26); r0 = _mm_and_si128(r0, packedmask26.v); r2 = _mm_and_si128(r2, packedmask26.v); r1 = _mm_add_epi64(r1, c1); r3 = _mm_add_epi64(r3, c2); - c1 = _mm_srli_epi64(r1, 25); c2 = _mm_srli_epi64(r3, 25); r1 = _mm_and_si128(r1, packedmask25.v); r3 = _mm_and_si128(r3, packedmask25.v); r2 = _mm_add_epi64(r2, c1); r4 = _mm_add_epi64(r4, c2); c3 = _mm_slli_si128(c2, 8); - c1 = _mm_srli_epi64(r4, 26); r4 = _mm_and_si128(r4, packedmask26.v); r5 = _mm_add_epi64(r5, c1); - c1 = _mm_srli_epi64(r5, 25); r5 = _mm_and_si128(r5, packedmask25.v); r0 = _mm_add_epi64(r0, _mm_unpackhi_epi64(_mm_mul_epu32(c1, packednineteen.v), c3)); - c1 = _mm_srli_epi64(r0, 26); c2 = _mm_srli_epi64(r2, 26); r0 = _mm_and_si128(r0, packedmask26.v); r2 = _mm_and_si128(r2, packedmask26.v); r1 = _mm_add_epi64(r1, c1); r3 = _mm_add_epi64(r3, c2); - - _mm_store_si128((xmmi*)out + 0, _mm_unpacklo_epi64(_mm_unpacklo_epi32(r0, r1), _mm_unpacklo_epi32(r2, r3))); - _mm_store_si128((xmmi*)out + 1, _mm_unpacklo_epi64(_mm_unpackhi_epi32(r0, r1), _mm_unpackhi_epi32(r2, r3))); - _mm_store_si128((xmmi*)out + 2, _mm_unpackhi_epi32(r4, r5)); -} - -DONNA_INLINE static void -curve25519_sub_reduce(bignum25519 out, const bignum25519 a, const bignum25519 b) { - xmmi a0,a1,a2,b0,b1,b2; - xmmi c1,c2,c3; - xmmi r0,r1,r2,r3,r4,r5; - - a0 = _mm_load_si128((xmmi*)a + 0); - a1 = _mm_load_si128((xmmi*)a + 1); - a2 = _mm_load_si128((xmmi*)a + 2); - a0 = _mm_add_epi32(a0, packed2p0.v); - a1 = _mm_add_epi32(a1, packed2p1.v); - a2 = _mm_add_epi32(a2, packed2p2.v); - b0 = _mm_load_si128((xmmi*)b + 0); - b1 = _mm_load_si128((xmmi*)b + 1); - b2 = _mm_load_si128((xmmi*)b + 2); - a0 = _mm_sub_epi32(a0, b0); - a1 = _mm_sub_epi32(a1, b1); - a2 = _mm_sub_epi32(a2, b2); - - r0 = _mm_and_si128(_mm_unpacklo_epi64(a0, a1), bot32bitmask.v); - r1 = _mm_srli_epi64(_mm_unpacklo_epi64(a0, a1), 32); - r2 = _mm_and_si128(_mm_unpackhi_epi64(a0, a1), bot32bitmask.v); - r3 = _mm_srli_epi64(_mm_unpackhi_epi64(a0, a1), 32); - r4 = _mm_and_si128(_mm_unpacklo_epi64(_mm_setzero_si128(), a2), bot32bitmask.v); - r5 = _mm_srli_epi64(_mm_unpacklo_epi64(_mm_setzero_si128(), a2), 32); - - c1 = _mm_srli_epi64(r0, 26); c2 = _mm_srli_epi64(r2, 26); r0 = _mm_and_si128(r0, packedmask26.v); r2 = _mm_and_si128(r2, packedmask26.v); r1 = _mm_add_epi64(r1, c1); r3 = _mm_add_epi64(r3, c2); - c1 = _mm_srli_epi64(r1, 25); c2 = _mm_srli_epi64(r3, 25); r1 = _mm_and_si128(r1, packedmask25.v); r3 = _mm_and_si128(r3, packedmask25.v); r2 = _mm_add_epi64(r2, c1); r4 = _mm_add_epi64(r4, c2); c3 = _mm_slli_si128(c2, 8); - c1 = _mm_srli_epi64(r4, 26); r4 = _mm_and_si128(r4, packedmask26.v); r5 = _mm_add_epi64(r5, c1); - c1 = _mm_srli_epi64(r5, 25); r5 = _mm_and_si128(r5, packedmask25.v); r0 = _mm_add_epi64(r0, _mm_unpackhi_epi64(_mm_mul_epu32(c1, packednineteen.v), c3)); - c1 = _mm_srli_epi64(r0, 26); c2 = _mm_srli_epi64(r2, 26); r0 = _mm_and_si128(r0, packedmask26.v); r2 = _mm_and_si128(r2, packedmask26.v); r1 = _mm_add_epi64(r1, c1); r3 = _mm_add_epi64(r3, c2); - - _mm_store_si128((xmmi*)out + 0, _mm_unpacklo_epi64(_mm_unpacklo_epi32(r0, r1), _mm_unpacklo_epi32(r2, r3))); - _mm_store_si128((xmmi*)out + 1, _mm_unpacklo_epi64(_mm_unpackhi_epi32(r0, r1), _mm_unpackhi_epi32(r2, r3))); - _mm_store_si128((xmmi*)out + 2, _mm_unpackhi_epi32(r4, r5)); -} - - -DONNA_INLINE static void -curve25519_neg(bignum25519 out, const bignum25519 b) { - xmmi a0,a1,a2,b0,b1,b2; - xmmi c1,c2,c3; - xmmi r0,r1,r2,r3,r4,r5; - - a0 = packed2p0.v; - a1 = packed2p1.v; - a2 = packed2p2.v; - b0 = _mm_load_si128((xmmi*)b + 0); - b1 = _mm_load_si128((xmmi*)b + 1); - b2 = _mm_load_si128((xmmi*)b + 2); - a0 = _mm_sub_epi32(a0, b0); - a1 = _mm_sub_epi32(a1, b1); - a2 = _mm_sub_epi32(a2, b2); - - r0 = _mm_and_si128(_mm_unpacklo_epi64(a0, a1), bot32bitmask.v); - r1 = _mm_srli_epi64(_mm_unpacklo_epi64(a0, a1), 32); - r2 = _mm_and_si128(_mm_unpackhi_epi64(a0, a1), bot32bitmask.v); - r3 = _mm_srli_epi64(_mm_unpackhi_epi64(a0, a1), 32); - r4 = _mm_and_si128(_mm_unpacklo_epi64(_mm_setzero_si128(), a2), bot32bitmask.v); - r5 = _mm_srli_epi64(_mm_unpacklo_epi64(_mm_setzero_si128(), a2), 32); - - c1 = _mm_srli_epi64(r0, 26); c2 = _mm_srli_epi64(r2, 26); r0 = _mm_and_si128(r0, packedmask26.v); r2 = _mm_and_si128(r2, packedmask26.v); r1 = _mm_add_epi64(r1, c1); r3 = _mm_add_epi64(r3, c2); - c1 = _mm_srli_epi64(r1, 25); c2 = _mm_srli_epi64(r3, 25); r1 = _mm_and_si128(r1, packedmask25.v); r3 = _mm_and_si128(r3, packedmask25.v); r2 = _mm_add_epi64(r2, c1); r4 = _mm_add_epi64(r4, c2); c3 = _mm_slli_si128(c2, 8); - c1 = _mm_srli_epi64(r4, 26); r4 = _mm_and_si128(r4, packedmask26.v); r5 = _mm_add_epi64(r5, c1); - c1 = _mm_srli_epi64(r5, 25); r5 = _mm_and_si128(r5, packedmask25.v); r0 = _mm_add_epi64(r0, _mm_unpackhi_epi64(_mm_mul_epu32(c1, packednineteen.v), c3)); - c1 = _mm_srli_epi64(r0, 26); c2 = _mm_srli_epi64(r2, 26); r0 = _mm_and_si128(r0, packedmask26.v); r2 = _mm_and_si128(r2, packedmask26.v); r1 = _mm_add_epi64(r1, c1); r3 = _mm_add_epi64(r3, c2); - - _mm_store_si128((xmmi*)out + 0, _mm_unpacklo_epi64(_mm_unpacklo_epi32(r0, r1), _mm_unpacklo_epi32(r2, r3))); - _mm_store_si128((xmmi*)out + 1, _mm_unpacklo_epi64(_mm_unpackhi_epi32(r0, r1), _mm_unpackhi_epi32(r2, r3))); - _mm_store_si128((xmmi*)out + 2, _mm_unpackhi_epi32(r4, r5)); -} - - -/* Multiply two numbers: out = in2 * in */ -static void -curve25519_mul(bignum25519 out, const bignum25519 r, const bignum25519 s) { - xmmi m01,m23,m45,m67,m89; - xmmi m0123,m4567; - xmmi s0123,s4567; - xmmi s01,s23,s45,s67,s89; - xmmi s12,s34,s56,s78,s9; - xmmi r0,r2,r4,r6,r8; - xmmi r1,r3,r5,r7,r9; - xmmi r119,r219,r319,r419,r519,r619,r719,r819,r919; - xmmi c1,c2,c3; - - s0123 = _mm_load_si128((xmmi*)s + 0); - s01 = _mm_shuffle_epi32(s0123,_MM_SHUFFLE(3,1,2,0)); - s12 = _mm_shuffle_epi32(s0123, _MM_SHUFFLE(2,2,1,1)); - s23 = _mm_shuffle_epi32(s0123,_MM_SHUFFLE(3,3,2,2)); - s4567 = _mm_load_si128((xmmi*)s + 1); - s34 = _mm_unpacklo_epi64(_mm_srli_si128(s0123,12),s4567); - s45 = _mm_shuffle_epi32(s4567,_MM_SHUFFLE(3,1,2,0)); - s56 = _mm_shuffle_epi32(s4567, _MM_SHUFFLE(2,2,1,1)); - s67 = _mm_shuffle_epi32(s4567,_MM_SHUFFLE(3,3,2,2)); - s89 = _mm_load_si128((xmmi*)s + 2); - s78 = _mm_unpacklo_epi64(_mm_srli_si128(s4567,12),s89); - s89 = _mm_shuffle_epi32(s89,_MM_SHUFFLE(3,1,2,0)); - s9 = _mm_shuffle_epi32(s89, _MM_SHUFFLE(3,3,2,2)); - - r0 = _mm_load_si128((xmmi*)r + 0); - r1 = _mm_shuffle_epi32(r0, _MM_SHUFFLE(1,1,1,1)); - r1 = _mm_add_epi64(r1, _mm_and_si128(r1, top64bitmask.v)); - r2 = _mm_shuffle_epi32(r0, _MM_SHUFFLE(2,2,2,2)); - r3 = _mm_shuffle_epi32(r0, _MM_SHUFFLE(3,3,3,3)); - r3 = _mm_add_epi64(r3, _mm_and_si128(r3, top64bitmask.v)); - r0 = _mm_shuffle_epi32(r0, _MM_SHUFFLE(0,0,0,0)); - r4 = _mm_load_si128((xmmi*)r + 1); - r5 = _mm_shuffle_epi32(r4, _MM_SHUFFLE(1,1,1,1)); - r5 = _mm_add_epi64(r5, _mm_and_si128(r5, top64bitmask.v)); - r6 = _mm_shuffle_epi32(r4, _MM_SHUFFLE(2,2,2,2)); - r7 = _mm_shuffle_epi32(r4, _MM_SHUFFLE(3,3,3,3)); - r7 = _mm_add_epi64(r7, _mm_and_si128(r7, top64bitmask.v)); - r4 = _mm_shuffle_epi32(r4, _MM_SHUFFLE(0,0,0,0)); - r8 = _mm_load_si128((xmmi*)r + 2); - r9 = _mm_shuffle_epi32(r8, _MM_SHUFFLE(3,1,3,1)); - r9 = _mm_add_epi64(r9, _mm_and_si128(r9, top64bitmask.v)); - r8 = _mm_shuffle_epi32(r8, _MM_SHUFFLE(3,0,3,0)); - - m01 = _mm_mul_epu32(r1,s01); - m23 = _mm_mul_epu32(r1,s23); - m45 = _mm_mul_epu32(r1,s45); - m67 = _mm_mul_epu32(r1,s67); - m23 = _mm_add_epi64(m23,_mm_mul_epu32(r3,s01)); - m45 = _mm_add_epi64(m45,_mm_mul_epu32(r3,s23)); - m67 = _mm_add_epi64(m67,_mm_mul_epu32(r3,s45)); - m89 = _mm_mul_epu32(r1,s89); - m45 = _mm_add_epi64(m45,_mm_mul_epu32(r5,s01)); - m67 = _mm_add_epi64(m67,_mm_mul_epu32(r5,s23)); - m89 = _mm_add_epi64(m89,_mm_mul_epu32(r3,s67)); - m67 = _mm_add_epi64(m67,_mm_mul_epu32(r7,s01)); - m89 = _mm_add_epi64(m89,_mm_mul_epu32(r5,s45)); - m89 = _mm_add_epi64(m89,_mm_mul_epu32(r7,s23)); - m89 = _mm_add_epi64(m89,_mm_mul_epu32(r9,s01)); - - /* shift up */ - m89 = _mm_unpackhi_epi64(m67,_mm_slli_si128(m89,8)); - m67 = _mm_unpackhi_epi64(m45,_mm_slli_si128(m67,8)); - m45 = _mm_unpackhi_epi64(m23,_mm_slli_si128(m45,8)); - m23 = _mm_unpackhi_epi64(m01,_mm_slli_si128(m23,8)); - m01 = _mm_unpackhi_epi64(_mm_setzero_si128(),_mm_slli_si128(m01,8)); - - m01 = _mm_add_epi64(m01,_mm_mul_epu32(r0,s01)); - m23 = _mm_add_epi64(m23,_mm_mul_epu32(r0,s23)); - m45 = _mm_add_epi64(m45,_mm_mul_epu32(r0,s45)); - m67 = _mm_add_epi64(m67,_mm_mul_epu32(r0,s67)); - m23 = _mm_add_epi64(m23,_mm_mul_epu32(r2,s01)); - m45 = _mm_add_epi64(m45,_mm_mul_epu32(r2,s23)); - m67 = _mm_add_epi64(m67,_mm_mul_epu32(r4,s23)); - m89 = _mm_add_epi64(m89,_mm_mul_epu32(r0,s89)); - m45 = _mm_add_epi64(m45,_mm_mul_epu32(r4,s01)); - m67 = _mm_add_epi64(m67,_mm_mul_epu32(r2,s45)); - m89 = _mm_add_epi64(m89,_mm_mul_epu32(r2,s67)); - m67 = _mm_add_epi64(m67,_mm_mul_epu32(r6,s01)); - m89 = _mm_add_epi64(m89,_mm_mul_epu32(r4,s45)); - m89 = _mm_add_epi64(m89,_mm_mul_epu32(r6,s23)); - m89 = _mm_add_epi64(m89,_mm_mul_epu32(r8,s01)); - - r219 = _mm_mul_epu32(r2, packednineteen.v); - r419 = _mm_mul_epu32(r4, packednineteen.v); - r619 = _mm_mul_epu32(r6, packednineteen.v); - r819 = _mm_mul_epu32(r8, packednineteen.v); - r119 = _mm_shuffle_epi32(r1,_MM_SHUFFLE(0,0,2,2)); r119 = _mm_mul_epu32(r119, packednineteen.v); - r319 = _mm_shuffle_epi32(r3,_MM_SHUFFLE(0,0,2,2)); r319 = _mm_mul_epu32(r319, packednineteen.v); - r519 = _mm_shuffle_epi32(r5,_MM_SHUFFLE(0,0,2,2)); r519 = _mm_mul_epu32(r519, packednineteen.v); - r719 = _mm_shuffle_epi32(r7,_MM_SHUFFLE(0,0,2,2)); r719 = _mm_mul_epu32(r719, packednineteen.v); - r919 = _mm_shuffle_epi32(r9,_MM_SHUFFLE(0,0,2,2)); r919 = _mm_mul_epu32(r919, packednineteen.v); - - m01 = _mm_add_epi64(m01,_mm_mul_epu32(r919,s12)); - m23 = _mm_add_epi64(m23,_mm_mul_epu32(r919,s34)); - m45 = _mm_add_epi64(m45,_mm_mul_epu32(r919,s56)); - m67 = _mm_add_epi64(m67,_mm_mul_epu32(r919,s78)); - m01 = _mm_add_epi64(m01,_mm_mul_epu32(r719,s34)); - m23 = _mm_add_epi64(m23,_mm_mul_epu32(r719,s56)); - m45 = _mm_add_epi64(m45,_mm_mul_epu32(r719,s78)); - m67 = _mm_add_epi64(m67,_mm_mul_epu32(r719,s9)); - m01 = _mm_add_epi64(m01,_mm_mul_epu32(r519,s56)); - m23 = _mm_add_epi64(m23,_mm_mul_epu32(r519,s78)); - m45 = _mm_add_epi64(m45,_mm_mul_epu32(r519,s9)); - m67 = _mm_add_epi64(m67,_mm_mul_epu32(r819,s89)); - m01 = _mm_add_epi64(m01,_mm_mul_epu32(r319,s78)); - m23 = _mm_add_epi64(m23,_mm_mul_epu32(r319,s9)); - m45 = _mm_add_epi64(m45,_mm_mul_epu32(r619,s89)); - m89 = _mm_add_epi64(m89,_mm_mul_epu32(r919,s9)); - m01 = _mm_add_epi64(m01,_mm_mul_epu32(r819,s23)); - m23 = _mm_add_epi64(m23,_mm_mul_epu32(r819,s45)); - m45 = _mm_add_epi64(m45,_mm_mul_epu32(r819,s67)); - m01 = _mm_add_epi64(m01,_mm_mul_epu32(r619,s45)); - m23 = _mm_add_epi64(m23,_mm_mul_epu32(r619,s67)); - m01 = _mm_add_epi64(m01,_mm_mul_epu32(r419,s67)); - m23 = _mm_add_epi64(m23,_mm_mul_epu32(r419,s89)); - m01 = _mm_add_epi64(m01,_mm_mul_epu32(r219,s89)); - m01 = _mm_add_epi64(m01,_mm_mul_epu32(r119,s9)); - - r0 = _mm_unpacklo_epi64(m01, m45); - r1 = _mm_unpackhi_epi64(m01, m45); - r2 = _mm_unpacklo_epi64(m23, m67); - r3 = _mm_unpackhi_epi64(m23, m67); - r4 = _mm_unpacklo_epi64(m89, m89); - r5 = _mm_unpackhi_epi64(m89, m89); - - c1 = _mm_srli_epi64(r0, 26); c2 = _mm_srli_epi64(r2, 26); r0 = _mm_and_si128(r0, packedmask26.v); r2 = _mm_and_si128(r2, packedmask26.v); r1 = _mm_add_epi64(r1, c1); r3 = _mm_add_epi64(r3, c2); - c1 = _mm_srli_epi64(r1, 25); c2 = _mm_srli_epi64(r3, 25); r1 = _mm_and_si128(r1, packedmask25.v); r3 = _mm_and_si128(r3, packedmask25.v); r2 = _mm_add_epi64(r2, c1); r4 = _mm_add_epi64(r4, c2); c3 = _mm_slli_si128(c2, 8); - c1 = _mm_srli_epi64(r4, 26); r4 = _mm_and_si128(r4, packedmask26.v); r5 = _mm_add_epi64(r5, c1); - c1 = _mm_srli_epi64(r5, 25); r5 = _mm_and_si128(r5, packedmask25.v); r0 = _mm_add_epi64(r0, _mm_unpackhi_epi64(_mm_mul_epu32(c1, packednineteen.v), c3)); - c1 = _mm_srli_epi64(r0, 26); c2 = _mm_srli_epi64(r2, 26); r0 = _mm_and_si128(r0, packedmask26.v); r2 = _mm_and_si128(r2, packedmask26.v); r1 = _mm_add_epi64(r1, c1); r3 = _mm_add_epi64(r3, c2); - - m0123 = _mm_unpacklo_epi32(r0, r1); - m4567 = _mm_unpackhi_epi32(r0, r1); - m0123 = _mm_unpacklo_epi64(m0123, _mm_unpacklo_epi32(r2, r3)); - m4567 = _mm_unpacklo_epi64(m4567, _mm_unpackhi_epi32(r2, r3)); - m89 = _mm_unpackhi_epi32(r4, r5); - - _mm_store_si128((xmmi*)out + 0, m0123); - _mm_store_si128((xmmi*)out + 1, m4567); - _mm_store_si128((xmmi*)out + 2, m89); -} - -DONNA_NOINLINE static void -curve25519_mul_noinline(bignum25519 out, const bignum25519 r, const bignum25519 s) { - curve25519_mul(out, r, s); -} - -#define curve25519_square(r, n) curve25519_square_times(r, n, 1) -static void -curve25519_square_times(bignum25519 r, const bignum25519 in, int count) { - xmmi m01,m23,m45,m67,m89; - xmmi r0,r1,r2,r3,r4,r5,r6,r7,r8,r9; - xmmi r0a,r1a,r2a,r3a,r7a,r9a; - xmmi r0123,r4567; - xmmi r01,r23,r45,r67,r6x,r89,r8x; - xmmi r12,r34,r56,r78,r9x; - xmmi r5619; - xmmi c1,c2,c3; - - r0123 = _mm_load_si128((xmmi*)in + 0); - r01 = _mm_shuffle_epi32(r0123,_MM_SHUFFLE(3,1,2,0)); - r23 = _mm_shuffle_epi32(r0123,_MM_SHUFFLE(3,3,2,2)); - r4567 = _mm_load_si128((xmmi*)in + 1); - r45 = _mm_shuffle_epi32(r4567,_MM_SHUFFLE(3,1,2,0)); - r67 = _mm_shuffle_epi32(r4567,_MM_SHUFFLE(3,3,2,2)); - r89 = _mm_load_si128((xmmi*)in + 2); - r89 = _mm_shuffle_epi32(r89,_MM_SHUFFLE(3,1,2,0)); - - do { - r12 = _mm_unpackhi_epi64(r01, _mm_slli_si128(r23, 8)); - r0 = _mm_shuffle_epi32(r01, _MM_SHUFFLE(0,0,0,0)); - r0 = _mm_add_epi64(r0, _mm_and_si128(r0, top64bitmask.v)); - r0a = _mm_shuffle_epi32(r0,_MM_SHUFFLE(3,2,1,2)); - r1 = _mm_shuffle_epi32(r01, _MM_SHUFFLE(2,2,2,2)); - r2 = _mm_shuffle_epi32(r23, _MM_SHUFFLE(0,0,0,0)); - r2 = _mm_add_epi64(r2, _mm_and_si128(r2, top64bitmask.v)); - r2a = _mm_shuffle_epi32(r2,_MM_SHUFFLE(3,2,1,2)); - r3 = _mm_shuffle_epi32(r23, _MM_SHUFFLE(2,2,2,2)); - r34 = _mm_unpackhi_epi64(r23, _mm_slli_si128(r45, 8)); - r4 = _mm_shuffle_epi32(r45, _MM_SHUFFLE(0,0,0,0)); - r4 = _mm_add_epi64(r4, _mm_and_si128(r4, top64bitmask.v)); - r56 = _mm_unpackhi_epi64(r45, _mm_slli_si128(r67, 8)); - r5619 = _mm_mul_epu32(r56, packednineteen.v); - r5 = _mm_shuffle_epi32(r5619, _MM_SHUFFLE(1,1,1,0)); - r6 = _mm_shuffle_epi32(r5619, _MM_SHUFFLE(3,2,3,2)); - r78 = _mm_unpackhi_epi64(r67, _mm_slli_si128(r89, 8)); - r6x = _mm_unpacklo_epi64(r67, _mm_setzero_si128()); - r7 = _mm_shuffle_epi32(r67, _MM_SHUFFLE(2,2,2,2)); - r7 = _mm_mul_epu32(r7, packed3819.v); - r7a = _mm_shuffle_epi32(r7, _MM_SHUFFLE(3,3,3,2)); - r8x = _mm_unpacklo_epi64(r89, _mm_setzero_si128()); - r8 = _mm_shuffle_epi32(r89, _MM_SHUFFLE(0,0,0,0)); - r8 = _mm_mul_epu32(r8, packednineteen.v); - r9 = _mm_shuffle_epi32(r89, _MM_SHUFFLE(2,2,2,2)); - r9x = _mm_slli_epi32(_mm_shuffle_epi32(r89, _MM_SHUFFLE(3,3,3,2)), 1); - r9 = _mm_mul_epu32(r9, packed3819.v); - r9a = _mm_shuffle_epi32(r9, _MM_SHUFFLE(2,2,2,2)); - - m01 = _mm_mul_epu32(r01, r0); - m23 = _mm_mul_epu32(r23, r0a); - m45 = _mm_mul_epu32(r45, r0a); - m45 = _mm_add_epi64(m45, _mm_mul_epu32(r23, r2)); - r23 = _mm_slli_epi32(r23, 1); - m67 = _mm_mul_epu32(r67, r0a); - m67 = _mm_add_epi64(m67, _mm_mul_epu32(r45, r2a)); - m89 = _mm_mul_epu32(r89, r0a); - m89 = _mm_add_epi64(m89, _mm_mul_epu32(r67, r2a)); - r67 = _mm_slli_epi32(r67, 1); - m89 = _mm_add_epi64(m89, _mm_mul_epu32(r45, r4)); - r45 = _mm_slli_epi32(r45, 1); - - r1 = _mm_slli_epi32(r1, 1); - r3 = _mm_slli_epi32(r3, 1); - r1a = _mm_add_epi64(r1, _mm_and_si128(r1, bot64bitmask.v)); - r3a = _mm_add_epi64(r3, _mm_and_si128(r3, bot64bitmask.v)); - - m23 = _mm_add_epi64(m23, _mm_mul_epu32(r12, r1)); - m45 = _mm_add_epi64(m45, _mm_mul_epu32(r34, r1a)); - m67 = _mm_add_epi64(m67, _mm_mul_epu32(r56, r1a)); - m67 = _mm_add_epi64(m67, _mm_mul_epu32(r34, r3)); - r34 = _mm_slli_epi32(r34, 1); - m89 = _mm_add_epi64(m89, _mm_mul_epu32(r78, r1a)); - r78 = _mm_slli_epi32(r78, 1); - m89 = _mm_add_epi64(m89, _mm_mul_epu32(r56, r3a)); - r56 = _mm_slli_epi32(r56, 1); - - m01 = _mm_add_epi64(m01, _mm_mul_epu32(_mm_slli_epi32(r12, 1), r9)); - m01 = _mm_add_epi64(m01, _mm_mul_epu32(r34, r7)); - m23 = _mm_add_epi64(m23, _mm_mul_epu32(r34, r9)); - m01 = _mm_add_epi64(m01, _mm_mul_epu32(r56, r5)); - m23 = _mm_add_epi64(m23, _mm_mul_epu32(r56, r7)); - m45 = _mm_add_epi64(m45, _mm_mul_epu32(r56, r9)); - m01 = _mm_add_epi64(m01, _mm_mul_epu32(r23, r8)); - m01 = _mm_add_epi64(m01, _mm_mul_epu32(r45, r6)); - m23 = _mm_add_epi64(m23, _mm_mul_epu32(r45, r8)); - m23 = _mm_add_epi64(m23, _mm_mul_epu32(r6x, r6)); - m45 = _mm_add_epi64(m45, _mm_mul_epu32(r78, r7a)); - m67 = _mm_add_epi64(m67, _mm_mul_epu32(r78, r9)); - m45 = _mm_add_epi64(m45, _mm_mul_epu32(r67, r8)); - m67 = _mm_add_epi64(m67, _mm_mul_epu32(r8x, r8)); - m89 = _mm_add_epi64(m89, _mm_mul_epu32(r9x, r9a)); - - r0 = _mm_unpacklo_epi64(m01, m45); - r1 = _mm_unpackhi_epi64(m01, m45); - r2 = _mm_unpacklo_epi64(m23, m67); - r3 = _mm_unpackhi_epi64(m23, m67); - r4 = _mm_unpacklo_epi64(m89, m89); - r5 = _mm_unpackhi_epi64(m89, m89); - - c1 = _mm_srli_epi64(r0, 26); c2 = _mm_srli_epi64(r2, 26); r0 = _mm_and_si128(r0, packedmask26.v); r2 = _mm_and_si128(r2, packedmask26.v); r1 = _mm_add_epi64(r1, c1); r3 = _mm_add_epi64(r3, c2); - c1 = _mm_srli_epi64(r1, 25); c2 = _mm_srli_epi64(r3, 25); r1 = _mm_and_si128(r1, packedmask25.v); r3 = _mm_and_si128(r3, packedmask25.v); r2 = _mm_add_epi64(r2, c1); r4 = _mm_add_epi64(r4, c2); c3 = _mm_slli_si128(c2, 8); - c1 = _mm_srli_epi64(r4, 26); r4 = _mm_and_si128(r4, packedmask26.v); r5 = _mm_add_epi64(r5, c1); - c1 = _mm_srli_epi64(r5, 25); r5 = _mm_and_si128(r5, packedmask25.v); r0 = _mm_add_epi64(r0, _mm_unpackhi_epi64(_mm_mul_epu32(c1, packednineteen.v), c3)); - c1 = _mm_srli_epi64(r0, 26); c2 = _mm_srli_epi64(r2, 26); r0 = _mm_and_si128(r0, packedmask26.v); r2 = _mm_and_si128(r2, packedmask26.v); r1 = _mm_add_epi64(r1, c1); r3 = _mm_add_epi64(r3, c2); - - r01 = _mm_unpacklo_epi64(r0, r1); - r45 = _mm_unpackhi_epi64(r0, r1); - r23 = _mm_unpacklo_epi64(r2, r3); - r67 = _mm_unpackhi_epi64(r2, r3); - r89 = _mm_unpackhi_epi64(r4, r5); - } while (--count); - - r0123 = _mm_shuffle_epi32(r23, _MM_SHUFFLE(2,0,3,3)); - r4567 = _mm_shuffle_epi32(r67, _MM_SHUFFLE(2,0,3,3)); - r0123 = _mm_or_si128(r0123, _mm_shuffle_epi32(r01, _MM_SHUFFLE(3,3,2,0))); - r4567 = _mm_or_si128(r4567, _mm_shuffle_epi32(r45, _MM_SHUFFLE(3,3,2,0))); - r89 = _mm_shuffle_epi32(r89, _MM_SHUFFLE(3,3,2,0)); - - _mm_store_si128((xmmi*)r + 0, r0123); - _mm_store_si128((xmmi*)r + 1, r4567); - _mm_store_si128((xmmi*)r + 2, r89); -} - -DONNA_INLINE static void -curve25519_tangle32(packedelem32 *out, const bignum25519 x, const bignum25519 z) { - xmmi x0,x1,x2,z0,z1,z2; - - x0 = _mm_load_si128((xmmi *)(x + 0)); - x1 = _mm_load_si128((xmmi *)(x + 4)); - x2 = _mm_load_si128((xmmi *)(x + 8)); - z0 = _mm_load_si128((xmmi *)(z + 0)); - z1 = _mm_load_si128((xmmi *)(z + 4)); - z2 = _mm_load_si128((xmmi *)(z + 8)); - - out[0].v = _mm_unpacklo_epi32(x0, z0); - out[1].v = _mm_unpackhi_epi32(x0, z0); - out[2].v = _mm_unpacklo_epi32(x1, z1); - out[3].v = _mm_unpackhi_epi32(x1, z1); - out[4].v = _mm_unpacklo_epi32(x2, z2); -} - -DONNA_INLINE static void -curve25519_untangle32(bignum25519 x, bignum25519 z, const packedelem32 *in) { - xmmi t0,t1,t2,t3,t4,zero; - - t0 = _mm_shuffle_epi32(in[0].v, _MM_SHUFFLE(3,1,2,0)); - t1 = _mm_shuffle_epi32(in[1].v, _MM_SHUFFLE(3,1,2,0)); - t2 = _mm_shuffle_epi32(in[2].v, _MM_SHUFFLE(3,1,2,0)); - t3 = _mm_shuffle_epi32(in[3].v, _MM_SHUFFLE(3,1,2,0)); - t4 = _mm_shuffle_epi32(in[4].v, _MM_SHUFFLE(3,1,2,0)); - zero = _mm_setzero_si128(); - _mm_store_si128((xmmi *)x + 0, _mm_unpacklo_epi64(t0, t1)); - _mm_store_si128((xmmi *)x + 1, _mm_unpacklo_epi64(t2, t3)); - _mm_store_si128((xmmi *)x + 2, _mm_unpacklo_epi64(t4, zero)); - _mm_store_si128((xmmi *)z + 0, _mm_unpackhi_epi64(t0, t1)); - _mm_store_si128((xmmi *)z + 1, _mm_unpackhi_epi64(t2, t3)); - _mm_store_si128((xmmi *)z + 2, _mm_unpackhi_epi64(t4, zero)); -} - -DONNA_INLINE static void -curve25519_add_reduce_packed32(packedelem32 *out, const packedelem32 *r, const packedelem32 *s) { - xmmi r0,r1,r2,r3,r4; - xmmi s0,s1,s2,s3,s4,s5; - xmmi c1,c2; - - r0 = _mm_add_epi32(r[0].v, s[0].v); - r1 = _mm_add_epi32(r[1].v, s[1].v); - r2 = _mm_add_epi32(r[2].v, s[2].v); - r3 = _mm_add_epi32(r[3].v, s[3].v); - r4 = _mm_add_epi32(r[4].v, s[4].v); - - s0 = _mm_unpacklo_epi64(r0, r2); /* 00 44 */ - s1 = _mm_unpackhi_epi64(r0, r2); /* 11 55 */ - s2 = _mm_unpacklo_epi64(r1, r3); /* 22 66 */ - s3 = _mm_unpackhi_epi64(r1, r3); /* 33 77 */ - s4 = _mm_unpacklo_epi64(_mm_setzero_si128(), r4); /* 00 88 */ - s5 = _mm_unpackhi_epi64(_mm_setzero_si128(), r4); /* 00 99 */ - - c1 = _mm_srli_epi32(s0, 26); c2 = _mm_srli_epi32(s2, 26); s0 = _mm_and_si128(s0, packedmask26262626.v); s2 = _mm_and_si128(s2, packedmask26262626.v); s1 = _mm_add_epi32(s1, c1); s3 = _mm_add_epi32(s3, c2); - c1 = _mm_srli_epi32(s1, 25); c2 = _mm_srli_epi32(s3, 25); s1 = _mm_and_si128(s1, packedmask25252525.v); s3 = _mm_and_si128(s3, packedmask25252525.v); s2 = _mm_add_epi32(s2, c1); s4 = _mm_add_epi32(s4, _mm_unpackhi_epi64(_mm_setzero_si128(), c2)); s0 = _mm_add_epi32(s0, _mm_unpacklo_epi64(_mm_setzero_si128(), c2)); - c1 = _mm_srli_epi32(s2, 26); c2 = _mm_srli_epi32(s4, 26); s2 = _mm_and_si128(s2, packedmask26262626.v); s4 = _mm_and_si128(s4, packedmask26262626.v); s3 = _mm_add_epi32(s3, c1); s5 = _mm_add_epi32(s5, c2); - c1 = _mm_srli_epi32(s3, 25); c2 = _mm_srli_epi32(s5, 25); s3 = _mm_and_si128(s3, packedmask25252525.v); s5 = _mm_and_si128(s5, packedmask25252525.v); s4 = _mm_add_epi32(s4, c1); s0 = _mm_add_epi32(s0, _mm_or_si128(_mm_slli_si128(c1, 8), _mm_srli_si128(_mm_add_epi32(_mm_add_epi32(_mm_slli_epi32(c2, 4), _mm_slli_epi32(c2, 1)), c2), 8))); - c1 = _mm_srli_epi32(s0, 26); c2 = _mm_srli_epi32(s2, 26); s0 = _mm_and_si128(s0, packedmask26262626.v); s2 = _mm_and_si128(s2, packedmask26262626.v); s1 = _mm_add_epi32(s1, c1); s3 = _mm_add_epi32(s3, c2); - - out[0].v = _mm_unpacklo_epi64(s0, s1); /* 00 11 */ - out[1].v = _mm_unpacklo_epi64(s2, s3); /* 22 33 */ - out[2].v = _mm_unpackhi_epi64(s0, s1); /* 44 55 */ - out[3].v = _mm_unpackhi_epi64(s2, s3); /* 66 77 */ - out[4].v = _mm_unpackhi_epi64(s4, s5); /* 88 99 */ -} - -DONNA_INLINE static void -curve25519_add_packed32(packedelem32 *out, const packedelem32 *r, const packedelem32 *s) { - out[0].v = _mm_add_epi32(r[0].v, s[0].v); - out[1].v = _mm_add_epi32(r[1].v, s[1].v); - out[2].v = _mm_add_epi32(r[2].v, s[2].v); - out[3].v = _mm_add_epi32(r[3].v, s[3].v); - out[4].v = _mm_add_epi32(r[4].v, s[4].v); -} - -DONNA_INLINE static void -curve25519_sub_packed32(packedelem32 *out, const packedelem32 *r, const packedelem32 *s) { - xmmi r0,r1,r2,r3,r4; - xmmi s0,s1,s2,s3; - xmmi c1,c2; - - r0 = _mm_add_epi32(r[0].v, packed32packed2p0.v); - r1 = _mm_add_epi32(r[1].v, packed32packed2p1.v); - r2 = _mm_add_epi32(r[2].v, packed32packed2p1.v); - r3 = _mm_add_epi32(r[3].v, packed32packed2p1.v); - r4 = _mm_add_epi32(r[4].v, packed32packed2p1.v); - r0 = _mm_sub_epi32(r0, s[0].v); /* 00 11 */ - r1 = _mm_sub_epi32(r1, s[1].v); /* 22 33 */ - r2 = _mm_sub_epi32(r2, s[2].v); /* 44 55 */ - r3 = _mm_sub_epi32(r3, s[3].v); /* 66 77 */ - r4 = _mm_sub_epi32(r4, s[4].v); /* 88 99 */ - - s0 = _mm_unpacklo_epi64(r0, r2); /* 00 44 */ - s1 = _mm_unpackhi_epi64(r0, r2); /* 11 55 */ - s2 = _mm_unpacklo_epi64(r1, r3); /* 22 66 */ - s3 = _mm_unpackhi_epi64(r1, r3); /* 33 77 */ - - c1 = _mm_srli_epi32(s0, 26); c2 = _mm_srli_epi32(s2, 26); s0 = _mm_and_si128(s0, packedmask26262626.v); s2 = _mm_and_si128(s2, packedmask26262626.v); s1 = _mm_add_epi32(s1, c1); s3 = _mm_add_epi32(s3, c2); - c1 = _mm_srli_epi32(s1, 25); c2 = _mm_srli_epi32(s3, 25); s1 = _mm_and_si128(s1, packedmask25252525.v); s3 = _mm_and_si128(s3, packedmask25252525.v); s2 = _mm_add_epi32(s2, c1); r4 = _mm_add_epi32(r4, _mm_srli_si128(c2, 8)); s0 = _mm_add_epi32(s0, _mm_slli_si128(c2, 8)); - - out[0].v = _mm_unpacklo_epi64(s0, s1); /* 00 11 */ - out[1].v = _mm_unpacklo_epi64(s2, s3); /* 22 33 */ - out[2].v = _mm_unpackhi_epi64(s0, s1); /* 44 55 */ - out[3].v = _mm_unpackhi_epi64(s2, s3); /* 66 77 */ - out[4].v = r4; -} - -DONNA_INLINE static void -curve25519_sub_after_basic_packed32(packedelem32 *out, const packedelem32 *r, const packedelem32 *s) { - xmmi r0,r1,r2,r3,r4; - xmmi s0,s1,s2,s3,s4,s5; - xmmi c1,c2; - - r0 = _mm_add_epi32(r[0].v, packed32packed4p0.v); - r1 = _mm_add_epi32(r[1].v, packed32packed4p1.v); - r2 = _mm_add_epi32(r[2].v, packed32packed4p1.v); - r3 = _mm_add_epi32(r[3].v, packed32packed4p1.v); - r4 = _mm_add_epi32(r[4].v, packed32packed4p1.v); - r0 = _mm_sub_epi32(r0, s[0].v); /* 00 11 */ - r1 = _mm_sub_epi32(r1, s[1].v); /* 22 33 */ - r2 = _mm_sub_epi32(r2, s[2].v); /* 44 55 */ - r3 = _mm_sub_epi32(r3, s[3].v); /* 66 77 */ - r4 = _mm_sub_epi32(r4, s[4].v); /* 88 99 */ - - s0 = _mm_unpacklo_epi64(r0, r2); /* 00 44 */ - s1 = _mm_unpackhi_epi64(r0, r2); /* 11 55 */ - s2 = _mm_unpacklo_epi64(r1, r3); /* 22 66 */ - s3 = _mm_unpackhi_epi64(r1, r3); /* 33 77 */ - s4 = _mm_unpacklo_epi64(_mm_setzero_si128(), r4); /* 00 88 */ - s5 = _mm_unpackhi_epi64(_mm_setzero_si128(), r4); /* 00 99 */ - - c1 = _mm_srli_epi32(s0, 26); c2 = _mm_srli_epi32(s2, 26); s0 = _mm_and_si128(s0, packedmask26262626.v); s2 = _mm_and_si128(s2, packedmask26262626.v); s1 = _mm_add_epi32(s1, c1); s3 = _mm_add_epi32(s3, c2); - c1 = _mm_srli_epi32(s1, 25); c2 = _mm_srli_epi32(s3, 25); s1 = _mm_and_si128(s1, packedmask25252525.v); s3 = _mm_and_si128(s3, packedmask25252525.v); s2 = _mm_add_epi32(s2, c1); s4 = _mm_add_epi32(s4, _mm_unpackhi_epi64(_mm_setzero_si128(), c2)); s0 = _mm_add_epi32(s0, _mm_unpacklo_epi64(_mm_setzero_si128(), c2)); - c1 = _mm_srli_epi32(s2, 26); c2 = _mm_srli_epi32(s4, 26); s2 = _mm_and_si128(s2, packedmask26262626.v); s4 = _mm_and_si128(s4, packedmask26262626.v); s3 = _mm_add_epi32(s3, c1); s5 = _mm_add_epi32(s5, c2); - c1 = _mm_srli_epi32(s3, 25); c2 = _mm_srli_epi32(s5, 25); s3 = _mm_and_si128(s3, packedmask25252525.v); s5 = _mm_and_si128(s5, packedmask25252525.v); s4 = _mm_add_epi32(s4, c1); s0 = _mm_add_epi32(s0, _mm_or_si128(_mm_slli_si128(c1, 8), _mm_srli_si128(_mm_add_epi32(_mm_add_epi32(_mm_slli_epi32(c2, 4), _mm_slli_epi32(c2, 1)), c2), 8))); - c1 = _mm_srli_epi32(s0, 26); c2 = _mm_srli_epi32(s2, 26); s0 = _mm_and_si128(s0, packedmask26262626.v); s2 = _mm_and_si128(s2, packedmask26262626.v); s1 = _mm_add_epi32(s1, c1); s3 = _mm_add_epi32(s3, c2); - - out[0].v = _mm_unpacklo_epi64(s0, s1); /* 00 11 */ - out[1].v = _mm_unpacklo_epi64(s2, s3); /* 22 33 */ - out[2].v = _mm_unpackhi_epi64(s0, s1); /* 44 55 */ - out[3].v = _mm_unpackhi_epi64(s2, s3); /* 66 77 */ - out[4].v = _mm_unpackhi_epi64(s4, s5); /* 88 99 */ -} - -DONNA_INLINE static void -curve25519_tangle64_from32(packedelem64 *a, packedelem64 *b, const packedelem32 *c, const packedelem32 *d) { - xmmi c0,c1,c2,c3,c4,c5,t; - xmmi d0,d1,d2,d3,d4,d5; - xmmi t0,t1,t2,t3,t4,zero; - - t0 = _mm_shuffle_epi32(c[0].v, _MM_SHUFFLE(3,1,2,0)); - t1 = _mm_shuffle_epi32(c[1].v, _MM_SHUFFLE(3,1,2,0)); - t2 = _mm_shuffle_epi32(d[0].v, _MM_SHUFFLE(3,1,2,0)); - t3 = _mm_shuffle_epi32(d[1].v, _MM_SHUFFLE(3,1,2,0)); - c0 = _mm_unpacklo_epi64(t0, t1); - c3 = _mm_unpackhi_epi64(t0, t1); - d0 = _mm_unpacklo_epi64(t2, t3); - d3 = _mm_unpackhi_epi64(t2, t3); - t = _mm_unpacklo_epi64(c0, d0); a[0].v = t; a[1].v = _mm_srli_epi64(t, 32); - t = _mm_unpackhi_epi64(c0, d0); a[2].v = t; a[3].v = _mm_srli_epi64(t, 32); - t = _mm_unpacklo_epi64(c3, d3); b[0].v = t; b[1].v = _mm_srli_epi64(t, 32); - t = _mm_unpackhi_epi64(c3, d3); b[2].v = t; b[3].v = _mm_srli_epi64(t, 32); - - t0 = _mm_shuffle_epi32(c[2].v, _MM_SHUFFLE(3,1,2,0)); - t1 = _mm_shuffle_epi32(c[3].v, _MM_SHUFFLE(3,1,2,0)); - t2 = _mm_shuffle_epi32(d[2].v, _MM_SHUFFLE(3,1,2,0)); - t3 = _mm_shuffle_epi32(d[3].v, _MM_SHUFFLE(3,1,2,0)); - c1 = _mm_unpacklo_epi64(t0, t1); - c4 = _mm_unpackhi_epi64(t0, t1); - d1 = _mm_unpacklo_epi64(t2, t3); - d4 = _mm_unpackhi_epi64(t2, t3); - t = _mm_unpacklo_epi64(c1, d1); a[4].v = t; a[5].v = _mm_srli_epi64(t, 32); - t = _mm_unpackhi_epi64(c1, d1); a[6].v = t; a[7].v = _mm_srli_epi64(t, 32); - t = _mm_unpacklo_epi64(c4, d4); b[4].v = t; b[5].v = _mm_srli_epi64(t, 32); - t = _mm_unpackhi_epi64(c4, d4); b[6].v = t; b[7].v = _mm_srli_epi64(t, 32); - - t4 = _mm_shuffle_epi32(c[4].v, _MM_SHUFFLE(3,1,2,0)); - zero = _mm_setzero_si128(); - c2 = _mm_unpacklo_epi64(t4, zero); - c5 = _mm_unpackhi_epi64(t4, zero); - t4 = _mm_shuffle_epi32(d[4].v, _MM_SHUFFLE(3,1,2,0)); - d2 = _mm_unpacklo_epi64(t4, zero); - d5 = _mm_unpackhi_epi64(t4, zero); - t = _mm_unpacklo_epi64(c2, d2); a[8].v = t; a[9].v = _mm_srli_epi64(t, 32); - t = _mm_unpacklo_epi64(c5, d5); b[8].v = t; b[9].v = _mm_srli_epi64(t, 32); -} - -DONNA_INLINE static void -curve25519_tangle64(packedelem64 *out, const bignum25519 x, const bignum25519 z) { - xmmi x0,x1,x2,z0,z1,z2,t; - - x0 = _mm_load_si128((xmmi *)x + 0); - x1 = _mm_load_si128((xmmi *)x + 1); - x2 = _mm_load_si128((xmmi *)x + 2); - z0 = _mm_load_si128((xmmi *)z + 0); - z1 = _mm_load_si128((xmmi *)z + 1); - z2 = _mm_load_si128((xmmi *)z + 2); - - t = _mm_unpacklo_epi64(x0, z0); out[0].v = t; out[1].v = _mm_srli_epi64(t, 32); - t = _mm_unpackhi_epi64(x0, z0); out[2].v = t; out[3].v = _mm_srli_epi64(t, 32); - t = _mm_unpacklo_epi64(x1, z1); out[4].v = t; out[5].v = _mm_srli_epi64(t, 32); - t = _mm_unpackhi_epi64(x1, z1); out[6].v = t; out[7].v = _mm_srli_epi64(t, 32); - t = _mm_unpacklo_epi64(x2, z2); out[8].v = t; out[9].v = _mm_srli_epi64(t, 32); -} - -DONNA_INLINE static void -curve25519_tangleone64(packedelem64 *out, const bignum25519 x) { - xmmi x0,x1,x2; - - x0 = _mm_load_si128((xmmi *)(x + 0)); - x1 = _mm_load_si128((xmmi *)(x + 4)); - x2 = _mm_load_si128((xmmi *)(x + 8)); - - out[0].v = _mm_shuffle_epi32(x0, _MM_SHUFFLE(0,0,0,0)); - out[1].v = _mm_shuffle_epi32(x0, _MM_SHUFFLE(1,1,1,1)); - out[2].v = _mm_shuffle_epi32(x0, _MM_SHUFFLE(2,2,2,2)); - out[3].v = _mm_shuffle_epi32(x0, _MM_SHUFFLE(3,3,3,3)); - out[4].v = _mm_shuffle_epi32(x1, _MM_SHUFFLE(0,0,0,0)); - out[5].v = _mm_shuffle_epi32(x1, _MM_SHUFFLE(1,1,1,1)); - out[6].v = _mm_shuffle_epi32(x1, _MM_SHUFFLE(2,2,2,2)); - out[7].v = _mm_shuffle_epi32(x1, _MM_SHUFFLE(3,3,3,3)); - out[8].v = _mm_shuffle_epi32(x2, _MM_SHUFFLE(0,0,0,0)); - out[9].v = _mm_shuffle_epi32(x2, _MM_SHUFFLE(1,1,1,1)); -} - -DONNA_INLINE static void -curve25519_swap64(packedelem64 *out) { - out[0].v = _mm_shuffle_epi32(out[0].v, _MM_SHUFFLE(1,0,3,2)); - out[1].v = _mm_shuffle_epi32(out[1].v, _MM_SHUFFLE(1,0,3,2)); - out[2].v = _mm_shuffle_epi32(out[2].v, _MM_SHUFFLE(1,0,3,2)); - out[3].v = _mm_shuffle_epi32(out[3].v, _MM_SHUFFLE(1,0,3,2)); - out[4].v = _mm_shuffle_epi32(out[4].v, _MM_SHUFFLE(1,0,3,2)); - out[5].v = _mm_shuffle_epi32(out[5].v, _MM_SHUFFLE(1,0,3,2)); - out[6].v = _mm_shuffle_epi32(out[6].v, _MM_SHUFFLE(1,0,3,2)); - out[7].v = _mm_shuffle_epi32(out[7].v, _MM_SHUFFLE(1,0,3,2)); - out[8].v = _mm_shuffle_epi32(out[8].v, _MM_SHUFFLE(1,0,3,2)); - out[9].v = _mm_shuffle_epi32(out[9].v, _MM_SHUFFLE(1,0,3,2)); -} - -DONNA_INLINE static void -curve25519_untangle64(bignum25519 x, bignum25519 z, const packedelem64 *in) { - _mm_store_si128((xmmi *)(x + 0), _mm_unpacklo_epi64(_mm_unpacklo_epi32(in[0].v, in[1].v), _mm_unpacklo_epi32(in[2].v, in[3].v))); - _mm_store_si128((xmmi *)(x + 4), _mm_unpacklo_epi64(_mm_unpacklo_epi32(in[4].v, in[5].v), _mm_unpacklo_epi32(in[6].v, in[7].v))); - _mm_store_si128((xmmi *)(x + 8), _mm_unpacklo_epi32(in[8].v, in[9].v) ); - _mm_store_si128((xmmi *)(z + 0), _mm_unpacklo_epi64(_mm_unpackhi_epi32(in[0].v, in[1].v), _mm_unpackhi_epi32(in[2].v, in[3].v))); - _mm_store_si128((xmmi *)(z + 4), _mm_unpacklo_epi64(_mm_unpackhi_epi32(in[4].v, in[5].v), _mm_unpackhi_epi32(in[6].v, in[7].v))); - _mm_store_si128((xmmi *)(z + 8), _mm_unpackhi_epi32(in[8].v, in[9].v) ); -} - -DONNA_INLINE static void -curve25519_mul_packed64(packedelem64 *out, const packedelem64 *r, const packedelem64 *s) { - xmmi r1,r2,r3,r4,r5,r6,r7,r8,r9; - xmmi r1_2,r3_2,r5_2,r7_2,r9_2; - xmmi c1,c2; - - out[0].v = _mm_mul_epu32(r[0].v, s[0].v); - out[1].v = _mm_add_epi64(_mm_mul_epu32(r[0].v, s[1].v), _mm_mul_epu32(r[1].v, s[0].v)); - r1_2 = _mm_slli_epi32(r[1].v, 1); - out[2].v = _mm_add_epi64(_mm_mul_epu32(r[0].v, s[2].v), _mm_add_epi64(_mm_mul_epu32(r1_2 , s[1].v), _mm_mul_epu32(r[2].v, s[0].v))); - out[3].v = _mm_add_epi64(_mm_mul_epu32(r[0].v, s[3].v), _mm_add_epi64(_mm_mul_epu32(r[1].v, s[2].v), _mm_add_epi64(_mm_mul_epu32(r[2].v, s[1].v), _mm_mul_epu32(r[3].v, s[0].v)))); - r3_2 = _mm_slli_epi32(r[3].v, 1); - out[4].v = _mm_add_epi64(_mm_mul_epu32(r[0].v, s[4].v), _mm_add_epi64(_mm_mul_epu32(r1_2 , s[3].v), _mm_add_epi64(_mm_mul_epu32(r[2].v, s[2].v), _mm_add_epi64(_mm_mul_epu32(r3_2 , s[1].v), _mm_mul_epu32(r[4].v, s[0].v))))); - out[5].v = _mm_add_epi64(_mm_mul_epu32(r[0].v, s[5].v), _mm_add_epi64(_mm_mul_epu32(r[1].v, s[4].v), _mm_add_epi64(_mm_mul_epu32(r[2].v, s[3].v), _mm_add_epi64(_mm_mul_epu32(r[3].v, s[2].v), _mm_add_epi64(_mm_mul_epu32(r[4].v, s[1].v), _mm_mul_epu32(r[5].v, s[0].v)))))); - r5_2 = _mm_slli_epi32(r[5].v, 1); - out[6].v = _mm_add_epi64(_mm_mul_epu32(r[0].v, s[6].v), _mm_add_epi64(_mm_mul_epu32(r1_2 , s[5].v), _mm_add_epi64(_mm_mul_epu32(r[2].v, s[4].v), _mm_add_epi64(_mm_mul_epu32(r3_2 , s[3].v), _mm_add_epi64(_mm_mul_epu32(r[4].v, s[2].v), _mm_add_epi64(_mm_mul_epu32(r5_2 , s[1].v), _mm_mul_epu32(r[6].v, s[0].v))))))); - out[7].v = _mm_add_epi64(_mm_mul_epu32(r[0].v, s[7].v), _mm_add_epi64(_mm_mul_epu32(r[1].v, s[6].v), _mm_add_epi64(_mm_mul_epu32(r[2].v, s[5].v), _mm_add_epi64(_mm_mul_epu32(r[3].v, s[4].v), _mm_add_epi64(_mm_mul_epu32(r[4].v, s[3].v), _mm_add_epi64(_mm_mul_epu32(r[5].v, s[2].v), _mm_add_epi64(_mm_mul_epu32(r[6].v, s[1].v), _mm_mul_epu32(r[7].v , s[0].v)))))))); - r7_2 = _mm_slli_epi32(r[7].v, 1); - out[8].v = _mm_add_epi64(_mm_mul_epu32(r[0].v, s[8].v), _mm_add_epi64(_mm_mul_epu32(r1_2 , s[7].v), _mm_add_epi64(_mm_mul_epu32(r[2].v, s[6].v), _mm_add_epi64(_mm_mul_epu32(r3_2 , s[5].v), _mm_add_epi64(_mm_mul_epu32(r[4].v, s[4].v), _mm_add_epi64(_mm_mul_epu32(r5_2 , s[3].v), _mm_add_epi64(_mm_mul_epu32(r[6].v, s[2].v), _mm_add_epi64(_mm_mul_epu32(r7_2 , s[1].v), _mm_mul_epu32(r[8].v, s[0].v))))))))); - out[9].v = _mm_add_epi64(_mm_mul_epu32(r[0].v, s[9].v), _mm_add_epi64(_mm_mul_epu32(r[1].v, s[8].v), _mm_add_epi64(_mm_mul_epu32(r[2].v, s[7].v), _mm_add_epi64(_mm_mul_epu32(r[3].v, s[6].v), _mm_add_epi64(_mm_mul_epu32(r[4].v, s[5].v), _mm_add_epi64(_mm_mul_epu32(r[5].v, s[4].v), _mm_add_epi64(_mm_mul_epu32(r[6].v, s[3].v), _mm_add_epi64(_mm_mul_epu32(r[7].v, s[2].v), _mm_add_epi64(_mm_mul_epu32(r[8].v, s[1].v), _mm_mul_epu32(r[9].v, s[0].v)))))))))); - - r1 = _mm_mul_epu32(r[1].v, packednineteen.v); - r2 = _mm_mul_epu32(r[2].v, packednineteen.v); - r1_2 = _mm_slli_epi32(r1, 1); - r3 = _mm_mul_epu32(r[3].v, packednineteen.v); - r4 = _mm_mul_epu32(r[4].v, packednineteen.v); - r3_2 = _mm_slli_epi32(r3, 1); - r5 = _mm_mul_epu32(r[5].v, packednineteen.v); - r6 = _mm_mul_epu32(r[6].v, packednineteen.v); - r5_2 = _mm_slli_epi32(r5, 1); - r7 = _mm_mul_epu32(r[7].v, packednineteen.v); - r8 = _mm_mul_epu32(r[8].v, packednineteen.v); - r7_2 = _mm_slli_epi32(r7, 1); - r9 = _mm_mul_epu32(r[9].v, packednineteen.v); - r9_2 = _mm_slli_epi32(r9, 1); - - out[0].v = _mm_add_epi64(out[0].v, _mm_add_epi64(_mm_mul_epu32(r9_2, s[1].v), _mm_add_epi64(_mm_mul_epu32(r8, s[2].v), _mm_add_epi64(_mm_mul_epu32(r7_2, s[3].v), _mm_add_epi64(_mm_mul_epu32(r6, s[4].v), _mm_add_epi64(_mm_mul_epu32(r5_2, s[5].v), _mm_add_epi64(_mm_mul_epu32(r4, s[6].v), _mm_add_epi64(_mm_mul_epu32(r3_2, s[7].v), _mm_add_epi64(_mm_mul_epu32(r2, s[8].v), _mm_mul_epu32(r1_2, s[9].v)))))))))); - out[1].v = _mm_add_epi64(out[1].v, _mm_add_epi64(_mm_mul_epu32(r9 , s[2].v), _mm_add_epi64(_mm_mul_epu32(r8, s[3].v), _mm_add_epi64(_mm_mul_epu32(r7 , s[4].v), _mm_add_epi64(_mm_mul_epu32(r6, s[5].v), _mm_add_epi64(_mm_mul_epu32(r5 , s[6].v), _mm_add_epi64(_mm_mul_epu32(r4, s[7].v), _mm_add_epi64(_mm_mul_epu32(r3 , s[8].v), _mm_mul_epu32(r2, s[9].v))))))))); - out[2].v = _mm_add_epi64(out[2].v, _mm_add_epi64(_mm_mul_epu32(r9_2, s[3].v), _mm_add_epi64(_mm_mul_epu32(r8, s[4].v), _mm_add_epi64(_mm_mul_epu32(r7_2, s[5].v), _mm_add_epi64(_mm_mul_epu32(r6, s[6].v), _mm_add_epi64(_mm_mul_epu32(r5_2, s[7].v), _mm_add_epi64(_mm_mul_epu32(r4, s[8].v), _mm_mul_epu32(r3_2, s[9].v)))))))); - out[3].v = _mm_add_epi64(out[3].v, _mm_add_epi64(_mm_mul_epu32(r9 , s[4].v), _mm_add_epi64(_mm_mul_epu32(r8, s[5].v), _mm_add_epi64(_mm_mul_epu32(r7 , s[6].v), _mm_add_epi64(_mm_mul_epu32(r6, s[7].v), _mm_add_epi64(_mm_mul_epu32(r5 , s[8].v), _mm_mul_epu32(r4, s[9].v))))))); - out[4].v = _mm_add_epi64(out[4].v, _mm_add_epi64(_mm_mul_epu32(r9_2, s[5].v), _mm_add_epi64(_mm_mul_epu32(r8, s[6].v), _mm_add_epi64(_mm_mul_epu32(r7_2, s[7].v), _mm_add_epi64(_mm_mul_epu32(r6, s[8].v), _mm_mul_epu32(r5_2, s[9].v)))))); - out[5].v = _mm_add_epi64(out[5].v, _mm_add_epi64(_mm_mul_epu32(r9 , s[6].v), _mm_add_epi64(_mm_mul_epu32(r8, s[7].v), _mm_add_epi64(_mm_mul_epu32(r7 , s[8].v), _mm_mul_epu32(r6, s[9].v))))); - out[6].v = _mm_add_epi64(out[6].v, _mm_add_epi64(_mm_mul_epu32(r9_2, s[7].v), _mm_add_epi64(_mm_mul_epu32(r8, s[8].v), _mm_mul_epu32(r7_2, s[9].v)))); - out[7].v = _mm_add_epi64(out[7].v, _mm_add_epi64(_mm_mul_epu32(r9 , s[8].v), _mm_mul_epu32(r8, s[9].v))); - out[8].v = _mm_add_epi64(out[8].v, _mm_mul_epu32(r9_2, s[9].v)); - - c1 = _mm_srli_epi64(out[0].v, 26); c2 = _mm_srli_epi64(out[4].v, 26); out[0].v = _mm_and_si128(out[0].v, packedmask26.v); out[4].v = _mm_and_si128(out[4].v, packedmask26.v); out[1].v = _mm_add_epi64(out[1].v, c1); out[5].v = _mm_add_epi64(out[5].v, c2); - c1 = _mm_srli_epi64(out[1].v, 25); c2 = _mm_srli_epi64(out[5].v, 25); out[1].v = _mm_and_si128(out[1].v, packedmask25.v); out[5].v = _mm_and_si128(out[5].v, packedmask25.v); out[2].v = _mm_add_epi64(out[2].v, c1); out[6].v = _mm_add_epi64(out[6].v, c2); - c1 = _mm_srli_epi64(out[2].v, 26); c2 = _mm_srli_epi64(out[6].v, 26); out[2].v = _mm_and_si128(out[2].v, packedmask26.v); out[6].v = _mm_and_si128(out[6].v, packedmask26.v); out[3].v = _mm_add_epi64(out[3].v, c1); out[7].v = _mm_add_epi64(out[7].v, c2); - c1 = _mm_srli_epi64(out[3].v, 25); c2 = _mm_srli_epi64(out[7].v, 25); out[3].v = _mm_and_si128(out[3].v, packedmask25.v); out[7].v = _mm_and_si128(out[7].v, packedmask25.v); out[4].v = _mm_add_epi64(out[4].v, c1); out[8].v = _mm_add_epi64(out[8].v, c2); - c2 = _mm_srli_epi64(out[8].v, 26); out[8].v = _mm_and_si128(out[8].v, packedmask26.v); out[9].v = _mm_add_epi64(out[9].v, c2); - c2 = _mm_srli_epi64(out[9].v, 25); out[9].v = _mm_and_si128(out[9].v, packedmask25.v); out[0].v = _mm_add_epi64(out[0].v, _mm_mul_epu32(c2, packednineteen.v)); - c1 = _mm_srli_epi64(out[0].v, 26); c2 = _mm_srli_epi64(out[4].v, 26); out[0].v = _mm_and_si128(out[0].v, packedmask26.v); out[4].v = _mm_and_si128(out[4].v, packedmask26.v); out[1].v = _mm_add_epi64(out[1].v, c1); out[5].v = _mm_add_epi64(out[5].v, c2); -} - -DONNA_INLINE static void -curve25519_square_packed64(packedelem64 *out, const packedelem64 *r) { - xmmi r0,r1,r2,r3; - xmmi r1_2,r3_2,r4_2,r5_2,r6_2,r7_2; - xmmi d5,d6,d7,d8,d9; - xmmi c1,c2; - - r0 = r[0].v; - r1 = r[1].v; - r2 = r[2].v; - r3 = r[3].v; - - out[0].v = _mm_mul_epu32(r0, r0); - r0 = _mm_slli_epi32(r0, 1); - out[1].v = _mm_mul_epu32(r0, r1); - r1_2 = _mm_slli_epi32(r1, 1); - out[2].v = _mm_add_epi64(_mm_mul_epu32(r0, r2 ), _mm_mul_epu32(r1, r1_2)); - r1 = r1_2; - out[3].v = _mm_add_epi64(_mm_mul_epu32(r0, r3 ), _mm_mul_epu32(r1, r2 )); - r3_2 = _mm_slli_epi32(r3, 1); - out[4].v = _mm_add_epi64(_mm_mul_epu32(r0, r[4].v), _mm_add_epi64(_mm_mul_epu32(r1, r3_2 ), _mm_mul_epu32(r2, r2))); - r2 = _mm_slli_epi32(r2, 1); - out[5].v = _mm_add_epi64(_mm_mul_epu32(r0, r[5].v), _mm_add_epi64(_mm_mul_epu32(r1, r[4].v), _mm_mul_epu32(r2, r3))); - r5_2 = _mm_slli_epi32(r[5].v, 1); - out[6].v = _mm_add_epi64(_mm_mul_epu32(r0, r[6].v), _mm_add_epi64(_mm_mul_epu32(r1, r5_2 ), _mm_add_epi64(_mm_mul_epu32(r2, r[4].v), _mm_mul_epu32(r3, r3_2 )))); - r3 = r3_2; - out[7].v = _mm_add_epi64(_mm_mul_epu32(r0, r[7].v), _mm_add_epi64(_mm_mul_epu32(r1, r[6].v), _mm_add_epi64(_mm_mul_epu32(r2, r[5].v), _mm_mul_epu32(r3, r[4].v)))); - r7_2 = _mm_slli_epi32(r[7].v, 1); - out[8].v = _mm_add_epi64(_mm_mul_epu32(r0, r[8].v), _mm_add_epi64(_mm_mul_epu32(r1, r7_2 ), _mm_add_epi64(_mm_mul_epu32(r2, r[6].v), _mm_add_epi64(_mm_mul_epu32(r3, r5_2 ), _mm_mul_epu32(r[4].v, r[4].v))))); - out[9].v = _mm_add_epi64(_mm_mul_epu32(r0, r[9].v), _mm_add_epi64(_mm_mul_epu32(r1, r[8].v), _mm_add_epi64(_mm_mul_epu32(r2, r[7].v), _mm_add_epi64(_mm_mul_epu32(r3, r[6].v), _mm_mul_epu32(r[4].v, r5_2 ))))); - - d5 = _mm_mul_epu32(r[5].v, packedthirtyeight.v); - d6 = _mm_mul_epu32(r[6].v, packednineteen.v); - d7 = _mm_mul_epu32(r[7].v, packedthirtyeight.v); - d8 = _mm_mul_epu32(r[8].v, packednineteen.v); - d9 = _mm_mul_epu32(r[9].v, packedthirtyeight.v); - - r4_2 = _mm_slli_epi32(r[4].v, 1); - r6_2 = _mm_slli_epi32(r[6].v, 1); - out[0].v = _mm_add_epi64(out[0].v, _mm_add_epi64(_mm_mul_epu32(d9, r1 ), _mm_add_epi64(_mm_mul_epu32(d8, r2 ), _mm_add_epi64(_mm_mul_epu32(d7, r3 ), _mm_add_epi64(_mm_mul_epu32(d6, r4_2), _mm_mul_epu32(d5, r[5].v)))))); - out[1].v = _mm_add_epi64(out[1].v, _mm_add_epi64(_mm_mul_epu32(d9, _mm_srli_epi32(r2, 1)), _mm_add_epi64(_mm_mul_epu32(d8, r3 ), _mm_add_epi64(_mm_mul_epu32(d7, r[4].v), _mm_mul_epu32(d6, r5_2 ))))); - out[2].v = _mm_add_epi64(out[2].v, _mm_add_epi64(_mm_mul_epu32(d9, r3 ), _mm_add_epi64(_mm_mul_epu32(d8, r4_2), _mm_add_epi64(_mm_mul_epu32(d7, r5_2 ), _mm_mul_epu32(d6, r[6].v))))); - out[3].v = _mm_add_epi64(out[3].v, _mm_add_epi64(_mm_mul_epu32(d9, r[4].v ), _mm_add_epi64(_mm_mul_epu32(d8, r5_2), _mm_mul_epu32(d7, r[6].v)))); - out[4].v = _mm_add_epi64(out[4].v, _mm_add_epi64(_mm_mul_epu32(d9, r5_2 ), _mm_add_epi64(_mm_mul_epu32(d8, r6_2), _mm_mul_epu32(d7, r[7].v)))); - out[5].v = _mm_add_epi64(out[5].v, _mm_add_epi64(_mm_mul_epu32(d9, r[6].v ), _mm_mul_epu32(d8, r7_2 ))); - out[6].v = _mm_add_epi64(out[6].v, _mm_add_epi64(_mm_mul_epu32(d9, r7_2 ), _mm_mul_epu32(d8, r[8].v))); - out[7].v = _mm_add_epi64(out[7].v, _mm_mul_epu32(d9, r[8].v)); - out[8].v = _mm_add_epi64(out[8].v, _mm_mul_epu32(d9, r[9].v)); - - c1 = _mm_srli_epi64(out[0].v, 26); c2 = _mm_srli_epi64(out[4].v, 26); out[0].v = _mm_and_si128(out[0].v, packedmask26.v); out[4].v = _mm_and_si128(out[4].v, packedmask26.v); out[1].v = _mm_add_epi64(out[1].v, c1); out[5].v = _mm_add_epi64(out[5].v, c2); - c1 = _mm_srli_epi64(out[1].v, 25); c2 = _mm_srli_epi64(out[5].v, 25); out[1].v = _mm_and_si128(out[1].v, packedmask25.v); out[5].v = _mm_and_si128(out[5].v, packedmask25.v); out[2].v = _mm_add_epi64(out[2].v, c1); out[6].v = _mm_add_epi64(out[6].v, c2); - c1 = _mm_srli_epi64(out[2].v, 26); c2 = _mm_srli_epi64(out[6].v, 26); out[2].v = _mm_and_si128(out[2].v, packedmask26.v); out[6].v = _mm_and_si128(out[6].v, packedmask26.v); out[3].v = _mm_add_epi64(out[3].v, c1); out[7].v = _mm_add_epi64(out[7].v, c2); - c1 = _mm_srli_epi64(out[3].v, 25); c2 = _mm_srli_epi64(out[7].v, 25); out[3].v = _mm_and_si128(out[3].v, packedmask25.v); out[7].v = _mm_and_si128(out[7].v, packedmask25.v); out[4].v = _mm_add_epi64(out[4].v, c1); out[8].v = _mm_add_epi64(out[8].v, c2); - c2 = _mm_srli_epi64(out[8].v, 26); out[8].v = _mm_and_si128(out[8].v, packedmask26.v); out[9].v = _mm_add_epi64(out[9].v, c2); - c2 = _mm_srli_epi64(out[9].v, 25); out[9].v = _mm_and_si128(out[9].v, packedmask25.v); out[0].v = _mm_add_epi64(out[0].v, _mm_mul_epu32(c2, packednineteen.v)); - c1 = _mm_srli_epi64(out[0].v, 26); c2 = _mm_srli_epi64(out[4].v, 26); out[0].v = _mm_and_si128(out[0].v, packedmask26.v); out[4].v = _mm_and_si128(out[4].v, packedmask26.v); out[1].v = _mm_add_epi64(out[1].v, c1); out[5].v = _mm_add_epi64(out[5].v, c2); -} - - -/* Take a little-endian, 32-byte number and expand it into polynomial form */ -static void -curve25519_expand(bignum25519 out, const unsigned char in[32]) { - uint32_t x0,x1,x2,x3,x4,x5,x6,x7; - - x0 = *(uint32_t *)(in + 0); - x1 = *(uint32_t *)(in + 4); - x2 = *(uint32_t *)(in + 8); - x3 = *(uint32_t *)(in + 12); - x4 = *(uint32_t *)(in + 16); - x5 = *(uint32_t *)(in + 20); - x6 = *(uint32_t *)(in + 24); - x7 = *(uint32_t *)(in + 28); - - out[0] = ( x0 ) & 0x3ffffff; - out[1] = ((((uint64_t)x1 << 32) | x0) >> 26) & 0x1ffffff; - out[2] = ((((uint64_t)x2 << 32) | x1) >> 19) & 0x3ffffff; - out[3] = ((((uint64_t)x3 << 32) | x2) >> 13) & 0x1ffffff; - out[4] = (( x3) >> 6) & 0x3ffffff; - out[5] = ( x4 ) & 0x1ffffff; - out[6] = ((((uint64_t)x5 << 32) | x4) >> 25) & 0x3ffffff; - out[7] = ((((uint64_t)x6 << 32) | x5) >> 19) & 0x1ffffff; - out[8] = ((((uint64_t)x7 << 32) | x6) >> 12) & 0x3ffffff; - out[9] = (( x7) >> 6) & 0x1ffffff; - out[10] = 0; - out[11] = 0; -} - -/* Take a fully reduced polynomial form number and contract it into a - * little-endian, 32-byte array - */ -static void -curve25519_contract(unsigned char out[32], const bignum25519 in) { - bignum25519 ALIGN(16) f; - curve25519_copy(f, in); - - #define carry_pass() \ - f[1] += f[0] >> 26; f[0] &= 0x3ffffff; \ - f[2] += f[1] >> 25; f[1] &= 0x1ffffff; \ - f[3] += f[2] >> 26; f[2] &= 0x3ffffff; \ - f[4] += f[3] >> 25; f[3] &= 0x1ffffff; \ - f[5] += f[4] >> 26; f[4] &= 0x3ffffff; \ - f[6] += f[5] >> 25; f[5] &= 0x1ffffff; \ - f[7] += f[6] >> 26; f[6] &= 0x3ffffff; \ - f[8] += f[7] >> 25; f[7] &= 0x1ffffff; \ - f[9] += f[8] >> 26; f[8] &= 0x3ffffff; - - #define carry_pass_full() \ - carry_pass() \ - f[0] += 19 * (f[9] >> 25); f[9] &= 0x1ffffff; - - #define carry_pass_final() \ - carry_pass() \ - f[9] &= 0x1ffffff; - - carry_pass_full() - carry_pass_full() - - /* now t is between 0 and 2^255-1, properly carried. */ - /* case 1: between 0 and 2^255-20. case 2: between 2^255-19 and 2^255-1. */ - f[0] += 19; - carry_pass_full() - - /* now between 19 and 2^255-1 in both cases, and offset by 19. */ - f[0] += (1 << 26) - 19; - f[1] += (1 << 25) - 1; - f[2] += (1 << 26) - 1; - f[3] += (1 << 25) - 1; - f[4] += (1 << 26) - 1; - f[5] += (1 << 25) - 1; - f[6] += (1 << 26) - 1; - f[7] += (1 << 25) - 1; - f[8] += (1 << 26) - 1; - f[9] += (1 << 25) - 1; - - /* now between 2^255 and 2^256-20, and offset by 2^255. */ - carry_pass_final() - - #undef carry_pass - #undef carry_full - #undef carry_final - - f[1] <<= 2; - f[2] <<= 3; - f[3] <<= 5; - f[4] <<= 6; - f[6] <<= 1; - f[7] <<= 3; - f[8] <<= 4; - f[9] <<= 6; - - #define F(i, s) \ - out[s+0] |= (unsigned char )(f[i] & 0xff); \ - out[s+1] = (unsigned char )((f[i] >> 8) & 0xff); \ - out[s+2] = (unsigned char )((f[i] >> 16) & 0xff); \ - out[s+3] = (unsigned char )((f[i] >> 24) & 0xff); - - out[0] = 0; - out[16] = 0; - F(0,0); - F(1,3); - F(2,6); - F(3,9); - F(4,12); - F(5,16); - F(6,19); - F(7,22); - F(8,25); - F(9,28); - #undef F -} - -/* if (iswap) swap(a, b) */ -DONNA_INLINE static void -curve25519_swap_conditional(bignum25519 a, bignum25519 b, uint32_t iswap) { - const uint32_t swap = (uint32_t)(-(int32_t)iswap); - xmmi a0,a1,a2,b0,b1,b2,x0,x1,x2; - xmmi mask = _mm_cvtsi32_si128(swap); - mask = _mm_shuffle_epi32(mask, 0); - a0 = _mm_load_si128((xmmi *)a + 0); - a1 = _mm_load_si128((xmmi *)a + 1); - b0 = _mm_load_si128((xmmi *)b + 0); - b1 = _mm_load_si128((xmmi *)b + 1); - b0 = _mm_xor_si128(a0, b0); - b1 = _mm_xor_si128(a1, b1); - x0 = _mm_and_si128(b0, mask); - x1 = _mm_and_si128(b1, mask); - x0 = _mm_xor_si128(x0, a0); - x1 = _mm_xor_si128(x1, a1); - a0 = _mm_xor_si128(x0, b0); - a1 = _mm_xor_si128(x1, b1); - _mm_store_si128((xmmi *)a + 0, x0); - _mm_store_si128((xmmi *)a + 1, x1); - _mm_store_si128((xmmi *)b + 0, a0); - _mm_store_si128((xmmi *)b + 1, a1); - - a2 = _mm_load_si128((xmmi *)a + 2); - b2 = _mm_load_si128((xmmi *)b + 2); - b2 = _mm_xor_si128(a2, b2); - x2 = _mm_and_si128(b2, mask); - x2 = _mm_xor_si128(x2, a2); - a2 = _mm_xor_si128(x2, b2); - _mm_store_si128((xmmi *)b + 2, a2); - _mm_store_si128((xmmi *)a + 2, x2); -} - -/* out = (flag) ? out : in */ -DONNA_INLINE static void -curve25519_move_conditional_bytes(uint8_t out[96], const uint8_t in[96], uint32_t flag) { - xmmi a0,a1,a2,a3,a4,a5,b0,b1,b2,b3,b4,b5; - const uint32_t nb = flag - 1; - xmmi masknb = _mm_shuffle_epi32(_mm_cvtsi32_si128(nb),0); - a0 = _mm_load_si128((xmmi *)in + 0); - a1 = _mm_load_si128((xmmi *)in + 1); - a2 = _mm_load_si128((xmmi *)in + 2); - b0 = _mm_load_si128((xmmi *)out + 0); - b1 = _mm_load_si128((xmmi *)out + 1); - b2 = _mm_load_si128((xmmi *)out + 2); - a0 = _mm_andnot_si128(masknb, a0); - a1 = _mm_andnot_si128(masknb, a1); - a2 = _mm_andnot_si128(masknb, a2); - b0 = _mm_and_si128(masknb, b0); - b1 = _mm_and_si128(masknb, b1); - b2 = _mm_and_si128(masknb, b2); - a0 = _mm_or_si128(a0, b0); - a1 = _mm_or_si128(a1, b1); - a2 = _mm_or_si128(a2, b2); - _mm_store_si128((xmmi*)out + 0, a0); - _mm_store_si128((xmmi*)out + 1, a1); - _mm_store_si128((xmmi*)out + 2, a2); - - a3 = _mm_load_si128((xmmi *)in + 3); - a4 = _mm_load_si128((xmmi *)in + 4); - a5 = _mm_load_si128((xmmi *)in + 5); - b3 = _mm_load_si128((xmmi *)out + 3); - b4 = _mm_load_si128((xmmi *)out + 4); - b5 = _mm_load_si128((xmmi *)out + 5); - a3 = _mm_andnot_si128(masknb, a3); - a4 = _mm_andnot_si128(masknb, a4); - a5 = _mm_andnot_si128(masknb, a5); - b3 = _mm_and_si128(masknb, b3); - b4 = _mm_and_si128(masknb, b4); - b5 = _mm_and_si128(masknb, b5); - a3 = _mm_or_si128(a3, b3); - a4 = _mm_or_si128(a4, b4); - a5 = _mm_or_si128(a5, b5); - _mm_store_si128((xmmi*)out + 3, a3); - _mm_store_si128((xmmi*)out + 4, a4); - _mm_store_si128((xmmi*)out + 5, a5); -} - diff --git a/ed25519-donna/ed25519-donna-32bit-sse2.h b/ed25519-donna/ed25519-donna-32bit-sse2.h deleted file mode 100644 index db04a13d3..000000000 --- a/ed25519-donna/ed25519-donna-32bit-sse2.h +++ /dev/null @@ -1,513 +0,0 @@ -#if defined(ED25519_GCC_32BIT_SSE_CHOOSE) - -#define HAVE_GE25519_SCALARMULT_BASE_CHOOSE_NIELS - -DONNA_NOINLINE static void -ge25519_scalarmult_base_choose_niels(ge25519_niels *t, const uint8_t table[256][96], uint32_t pos, signed char b) { - int32_t breg = (int32_t)b; - uint32_t sign = (uint32_t)breg >> 31; - uint32_t mask = ~(sign - 1); - uint32_t u = (breg + mask) ^ mask; - - __asm__ __volatile__ ( - /* ysubx+xaddy */ - "movl %0, %%eax ;\n" - "movd %%eax, %%xmm6 ;\n" - "pshufd $0x00, %%xmm6, %%xmm6 ;\n" - "pxor %%xmm0, %%xmm0 ;\n" - "pxor %%xmm1, %%xmm1 ;\n" - "pxor %%xmm2, %%xmm2 ;\n" - "pxor %%xmm3, %%xmm3 ;\n" - - /* 0 */ - "movl $0, %%eax ;\n" - "movd %%eax, %%xmm7 ;\n" - "pshufd $0x00, %%xmm7, %%xmm7 ;\n" - "pcmpeqd %%xmm6, %%xmm7 ;\n" - "movl $1, %%ecx ;\n" - "movd %%ecx, %%xmm4 ;\n" - "pxor %%xmm5, %%xmm5 ;\n" - "pand %%xmm7, %%xmm4 ;\n" - "pand %%xmm7, %%xmm5 ;\n" - "por %%xmm4, %%xmm0 ;\n" - "por %%xmm5, %%xmm1 ;\n" - "por %%xmm4, %%xmm2 ;\n" - "por %%xmm5, %%xmm3 ;\n" - - /* 1 */ - "movl $1, %%eax ;\n" - "movd %%eax, %%xmm7 ;\n" - "pshufd $0x00, %%xmm7, %%xmm7 ;\n" - "pcmpeqd %%xmm6, %%xmm7 ;\n" - "movdqa 0(%1), %%xmm4 ;\n" - "movdqa 16(%1), %%xmm5 ;\n" - "pand %%xmm7, %%xmm4 ;\n" - "pand %%xmm7, %%xmm5 ;\n" - "por %%xmm4, %%xmm0 ;\n" - "por %%xmm5, %%xmm1 ;\n" - "movdqa 32(%1), %%xmm4 ;\n" - "movdqa 48(%1), %%xmm5 ;\n" - "pand %%xmm7, %%xmm4 ;\n" - "pand %%xmm7, %%xmm5 ;\n" - "por %%xmm4, %%xmm2 ;\n" - "por %%xmm5, %%xmm3 ;\n" - - /* 2 */ - "movl $2, %%eax ;\n" - "movd %%eax, %%xmm7 ;\n" - "pshufd $0x00, %%xmm7, %%xmm7 ;\n" - "pcmpeqd %%xmm6, %%xmm7 ;\n" - "movdqa 96(%1), %%xmm4 ;\n" - "movdqa 112(%1), %%xmm5 ;\n" - "pand %%xmm7, %%xmm4 ;\n" - "pand %%xmm7, %%xmm5 ;\n" - "por %%xmm4, %%xmm0 ;\n" - "por %%xmm5, %%xmm1 ;\n" - "movdqa 128(%1), %%xmm4 ;\n" - "movdqa 144(%1), %%xmm5 ;\n" - "pand %%xmm7, %%xmm4 ;\n" - "pand %%xmm7, %%xmm5 ;\n" - "por %%xmm4, %%xmm2 ;\n" - "por %%xmm5, %%xmm3 ;\n" - - /* 3 */ - "movl $3, %%eax ;\n" - "movd %%eax, %%xmm7 ;\n" - "pshufd $0x00, %%xmm7, %%xmm7 ;\n" - "pcmpeqd %%xmm6, %%xmm7 ;\n" - "movdqa 192(%1), %%xmm4 ;\n" - "movdqa 208(%1), %%xmm5 ;\n" - "pand %%xmm7, %%xmm4 ;\n" - "pand %%xmm7, %%xmm5 ;\n" - "por %%xmm4, %%xmm0 ;\n" - "por %%xmm5, %%xmm1 ;\n" - "movdqa 224(%1), %%xmm4 ;\n" - "movdqa 240(%1), %%xmm5 ;\n" - "pand %%xmm7, %%xmm4 ;\n" - "pand %%xmm7, %%xmm5 ;\n" - "por %%xmm4, %%xmm2 ;\n" - "por %%xmm5, %%xmm3 ;\n" - - /* 4 */ - "movl $4, %%eax ;\n" - "movd %%eax, %%xmm7 ;\n" - "pshufd $0x00, %%xmm7, %%xmm7 ;\n" - "pcmpeqd %%xmm6, %%xmm7 ;\n" - "movdqa 288(%1), %%xmm4 ;\n" - "movdqa 304(%1), %%xmm5 ;\n" - "pand %%xmm7, %%xmm4 ;\n" - "pand %%xmm7, %%xmm5 ;\n" - "por %%xmm4, %%xmm0 ;\n" - "por %%xmm5, %%xmm1 ;\n" - "movdqa 320(%1), %%xmm4 ;\n" - "movdqa 336(%1), %%xmm5 ;\n" - "pand %%xmm7, %%xmm4 ;\n" - "pand %%xmm7, %%xmm5 ;\n" - "por %%xmm4, %%xmm2 ;\n" - "por %%xmm5, %%xmm3 ;\n" - - /* 5 */ - "movl $5, %%eax ;\n" - "movd %%eax, %%xmm7 ;\n" - "pshufd $0x00, %%xmm7, %%xmm7 ;\n" - "pcmpeqd %%xmm6, %%xmm7 ;\n" - "movdqa 384(%1), %%xmm4 ;\n" - "movdqa 400(%1), %%xmm5 ;\n" - "pand %%xmm7, %%xmm4 ;\n" - "pand %%xmm7, %%xmm5 ;\n" - "por %%xmm4, %%xmm0 ;\n" - "por %%xmm5, %%xmm1 ;\n" - "movdqa 416(%1), %%xmm4 ;\n" - "movdqa 432(%1), %%xmm5 ;\n" - "pand %%xmm7, %%xmm4 ;\n" - "pand %%xmm7, %%xmm5 ;\n" - "por %%xmm4, %%xmm2 ;\n" - "por %%xmm5, %%xmm3 ;\n" - - /* 6 */ - "movl $6, %%eax ;\n" - "movd %%eax, %%xmm7 ;\n" - "pshufd $0x00, %%xmm7, %%xmm7 ;\n" - "pcmpeqd %%xmm6, %%xmm7 ;\n" - "movdqa 480(%1), %%xmm4 ;\n" - "movdqa 496(%1), %%xmm5 ;\n" - "pand %%xmm7, %%xmm4 ;\n" - "pand %%xmm7, %%xmm5 ;\n" - "por %%xmm4, %%xmm0 ;\n" - "por %%xmm5, %%xmm1 ;\n" - "movdqa 512(%1), %%xmm4 ;\n" - "movdqa 528(%1), %%xmm5 ;\n" - "pand %%xmm7, %%xmm4 ;\n" - "pand %%xmm7, %%xmm5 ;\n" - "por %%xmm4, %%xmm2 ;\n" - "por %%xmm5, %%xmm3 ;\n" - - /* 7 */ - "movl $7, %%eax ;\n" - "movd %%eax, %%xmm7 ;\n" - "pshufd $0x00, %%xmm7, %%xmm7 ;\n" - "pcmpeqd %%xmm6, %%xmm7 ;\n" - "movdqa 576(%1), %%xmm4 ;\n" - "movdqa 592(%1), %%xmm5 ;\n" - "pand %%xmm7, %%xmm4 ;\n" - "pand %%xmm7, %%xmm5 ;\n" - "por %%xmm4, %%xmm0 ;\n" - "por %%xmm5, %%xmm1 ;\n" - "movdqa 608(%1), %%xmm4 ;\n" - "movdqa 624(%1), %%xmm5 ;\n" - "pand %%xmm7, %%xmm4 ;\n" - "pand %%xmm7, %%xmm5 ;\n" - "por %%xmm4, %%xmm2 ;\n" - "por %%xmm5, %%xmm3 ;\n" - - /* 8 */ - "movl $8, %%eax ;\n" - "movd %%eax, %%xmm7 ;\n" - "pshufd $0x00, %%xmm7, %%xmm7 ;\n" - "pcmpeqd %%xmm6, %%xmm7 ;\n" - "movdqa 672(%1), %%xmm4 ;\n" - "movdqa 688(%1), %%xmm5 ;\n" - "pand %%xmm7, %%xmm4 ;\n" - "pand %%xmm7, %%xmm5 ;\n" - "por %%xmm4, %%xmm0 ;\n" - "por %%xmm5, %%xmm1 ;\n" - "movdqa 704(%1), %%xmm4 ;\n" - "movdqa 720(%1), %%xmm5 ;\n" - "pand %%xmm7, %%xmm4 ;\n" - "pand %%xmm7, %%xmm5 ;\n" - "por %%xmm4, %%xmm2 ;\n" - "por %%xmm5, %%xmm3 ;\n" - - /* conditional swap based on sign */ - "movl %3, %%ecx ;\n" - "movl %2, %%eax ;\n" - "xorl $1, %%ecx ;\n" - "movd %%ecx, %%xmm6 ;\n" - "pxor %%xmm7, %%xmm7 ;\n" - "pshufd $0x00, %%xmm6, %%xmm6 ;\n" - "pxor %%xmm0, %%xmm2 ;\n" - "pxor %%xmm1, %%xmm3 ;\n" - "pcmpeqd %%xmm6, %%xmm7 ;\n" - "movdqa %%xmm2, %%xmm4 ;\n" - "movdqa %%xmm3, %%xmm5 ;\n" - "pand %%xmm7, %%xmm4 ;\n" - "pand %%xmm7, %%xmm5 ;\n" - "pxor %%xmm4, %%xmm0 ;\n" - "pxor %%xmm5, %%xmm1 ;\n" - "pxor %%xmm0, %%xmm2 ;\n" - "pxor %%xmm1, %%xmm3 ;\n" - - /* store ysubx */ - "movd %%xmm0, %%ecx ;\n" - "movl %%ecx, %%edx ;\n" - "pshufd $0x39, %%xmm0, %%xmm0 ;\n" - "andl $0x3ffffff, %%ecx ;\n" - "movl %%ecx, 0(%%eax) ;\n" - "movd %%xmm0, %%ecx ;\n" - "pshufd $0x39, %%xmm0, %%xmm0 ;\n" - "shrdl $26, %%ecx, %%edx ;\n" - "andl $0x1ffffff, %%edx ;\n" - "movl %%edx, 4(%%eax) ;\n" - "movd %%xmm0, %%edx ;\n" - "pshufd $0x39, %%xmm0, %%xmm0 ;\n" - "shrdl $19, %%edx, %%ecx ;\n" - "andl $0x3ffffff, %%ecx ;\n" - "movl %%ecx, 8(%%eax) ;\n" - "movd %%xmm0, %%ecx ;\n" - "shrdl $13, %%ecx, %%edx ;\n" - "andl $0x1ffffff, %%edx ;\n" - "movl %%edx, 12(%%eax) ;\n" - "movd %%xmm1, %%edx ;\n" - "pshufd $0x39, %%xmm1, %%xmm1 ;\n" - "shrl $6, %%ecx ;\n" - "andl $0x3ffffff, %%ecx ;\n" - "movl %%ecx, 16(%%eax) ;\n" - "movl %%edx, %%ecx ;\n" - "andl $0x1ffffff, %%edx ;\n" - "movl %%edx, 20(%%eax) ;\n" - "movd %%xmm1, %%edx ;\n" - "pshufd $0x39, %%xmm1, %%xmm1 ;\n" - "shrdl $25, %%edx, %%ecx ;\n" - "andl $0x3ffffff, %%ecx ;\n" - "movl %%ecx, 24(%%eax) ;\n" - "movd %%xmm1, %%ecx ;\n" - "pshufd $0x39, %%xmm1, %%xmm1 ;\n" - "shrdl $19, %%ecx, %%edx ;\n" - "andl $0x1ffffff, %%edx ;\n" - "movl %%edx, 28(%%eax) ;\n" - "movd %%xmm1, %%edx ;\n" - "shrdl $12, %%edx, %%ecx ;\n" - "andl $0x3ffffff, %%ecx ;\n" - "movl %%ecx, 32(%%eax) ;\n" - "shrl $6, %%edx ;\n" - "andl $0x1ffffff, %%edx ;\n" - "xorl %%ecx, %%ecx ;\n" - "movl %%edx, 36(%%eax) ;\n" - "movl %%ecx, 40(%%eax) ;\n" - "movl %%ecx, 44(%%eax) ;\n" - - /* store xaddy */ - "addl $48, %%eax ;\n" - "movdqa %%xmm2, %%xmm0 ;\n" - "movdqa %%xmm3, %%xmm1 ;\n" - "movd %%xmm0, %%ecx ;\n" - "movl %%ecx, %%edx ;\n" - "pshufd $0x39, %%xmm0, %%xmm0 ;\n" - "andl $0x3ffffff, %%ecx ;\n" - "movl %%ecx, 0(%%eax) ;\n" - "movd %%xmm0, %%ecx ;\n" - "pshufd $0x39, %%xmm0, %%xmm0 ;\n" - "shrdl $26, %%ecx, %%edx ;\n" - "andl $0x1ffffff, %%edx ;\n" - "movl %%edx, 4(%%eax) ;\n" - "movd %%xmm0, %%edx ;\n" - "pshufd $0x39, %%xmm0, %%xmm0 ;\n" - "shrdl $19, %%edx, %%ecx ;\n" - "andl $0x3ffffff, %%ecx ;\n" - "movl %%ecx, 8(%%eax) ;\n" - "movd %%xmm0, %%ecx ;\n" - "shrdl $13, %%ecx, %%edx ;\n" - "andl $0x1ffffff, %%edx ;\n" - "movl %%edx, 12(%%eax) ;\n" - "movd %%xmm1, %%edx ;\n" - "pshufd $0x39, %%xmm1, %%xmm1 ;\n" - "shrl $6, %%ecx ;\n" - "andl $0x3ffffff, %%ecx ;\n" - "movl %%ecx, 16(%%eax) ;\n" - "movl %%edx, %%ecx ;\n" - "andl $0x1ffffff, %%edx ;\n" - "movl %%edx, 20(%%eax) ;\n" - "movd %%xmm1, %%edx ;\n" - "pshufd $0x39, %%xmm1, %%xmm1 ;\n" - "shrdl $25, %%edx, %%ecx ;\n" - "andl $0x3ffffff, %%ecx ;\n" - "movl %%ecx, 24(%%eax) ;\n" - "movd %%xmm1, %%ecx ;\n" - "pshufd $0x39, %%xmm1, %%xmm1 ;\n" - "shrdl $19, %%ecx, %%edx ;\n" - "andl $0x1ffffff, %%edx ;\n" - "movl %%edx, 28(%%eax) ;\n" - "movd %%xmm1, %%edx ;\n" - "shrdl $12, %%edx, %%ecx ;\n" - "andl $0x3ffffff, %%ecx ;\n" - "movl %%ecx, 32(%%eax) ;\n" - "shrl $6, %%edx ;\n" - "andl $0x1ffffff, %%edx ;\n" - "xorl %%ecx, %%ecx ;\n" - "movl %%edx, 36(%%eax) ;\n" - "movl %%ecx, 40(%%eax) ;\n" - "movl %%ecx, 44(%%eax) ;\n" - - /* t2d */ - "movl %0, %%eax ;\n" - "movd %%eax, %%xmm6 ;\n" - "pshufd $0x00, %%xmm6, %%xmm6 ;\n" - "pxor %%xmm0, %%xmm0 ;\n" - "pxor %%xmm1, %%xmm1 ;\n" - - /* 0 */ - "movl $0, %%eax ;\n" - "movd %%eax, %%xmm7 ;\n" - "pshufd $0x00, %%xmm7, %%xmm7 ;\n" - "pcmpeqd %%xmm6, %%xmm7 ;\n" - "pxor %%xmm0, %%xmm0 ;\n" - "pxor %%xmm1, %%xmm1 ;\n" - - /* 1 */ - "movl $1, %%eax ;\n" - "movd %%eax, %%xmm7 ;\n" - "pshufd $0x00, %%xmm7, %%xmm7 ;\n" - "pcmpeqd %%xmm6, %%xmm7 ;\n" - "movdqa 64(%1), %%xmm3 ;\n" - "movdqa 80(%1), %%xmm4 ;\n" - "pand %%xmm7, %%xmm3 ;\n" - "pand %%xmm7, %%xmm4 ;\n" - "por %%xmm3, %%xmm0 ;\n" - "por %%xmm4, %%xmm1 ;\n" - - /* 2 */ - "movl $2, %%eax ;\n" - "movd %%eax, %%xmm7 ;\n" - "pshufd $0x00, %%xmm7, %%xmm7 ;\n" - "pcmpeqd %%xmm6, %%xmm7 ;\n" - "movdqa 160(%1), %%xmm3 ;\n" - "movdqa 176(%1), %%xmm4 ;\n" - "pand %%xmm7, %%xmm3 ;\n" - "pand %%xmm7, %%xmm4 ;\n" - "por %%xmm3, %%xmm0 ;\n" - "por %%xmm4, %%xmm1 ;\n" - - /* 3 */ - "movl $3, %%eax ;\n" - "movd %%eax, %%xmm7 ;\n" - "pshufd $0x00, %%xmm7, %%xmm7 ;\n" - "pcmpeqd %%xmm6, %%xmm7 ;\n" - "movdqa 256(%1), %%xmm3 ;\n" - "movdqa 272(%1), %%xmm4 ;\n" - "pand %%xmm7, %%xmm3 ;\n" - "pand %%xmm7, %%xmm4 ;\n" - "por %%xmm3, %%xmm0 ;\n" - "por %%xmm4, %%xmm1 ;\n" - - /* 4 */ - "movl $4, %%eax ;\n" - "movd %%eax, %%xmm7 ;\n" - "pshufd $0x00, %%xmm7, %%xmm7 ;\n" - "pcmpeqd %%xmm6, %%xmm7 ;\n" - "movdqa 352(%1), %%xmm3 ;\n" - "movdqa 368(%1), %%xmm4 ;\n" - "pand %%xmm7, %%xmm3 ;\n" - "pand %%xmm7, %%xmm4 ;\n" - "por %%xmm3, %%xmm0 ;\n" - "por %%xmm4, %%xmm1 ;\n" - - /* 5 */ - "movl $5, %%eax ;\n" - "movd %%eax, %%xmm7 ;\n" - "pshufd $0x00, %%xmm7, %%xmm7 ;\n" - "pcmpeqd %%xmm6, %%xmm7 ;\n" - "movdqa 448(%1), %%xmm3 ;\n" - "movdqa 464(%1), %%xmm4 ;\n" - "pand %%xmm7, %%xmm3 ;\n" - "pand %%xmm7, %%xmm4 ;\n" - "por %%xmm3, %%xmm0 ;\n" - "por %%xmm4, %%xmm1 ;\n" - - /* 6 */ - "movl $6, %%eax ;\n" - "movd %%eax, %%xmm7 ;\n" - "pshufd $0x00, %%xmm7, %%xmm7 ;\n" - "pcmpeqd %%xmm6, %%xmm7 ;\n" - "movdqa 544(%1), %%xmm3 ;\n" - "movdqa 560(%1), %%xmm4 ;\n" - "pand %%xmm7, %%xmm3 ;\n" - "pand %%xmm7, %%xmm4 ;\n" - "por %%xmm3, %%xmm0 ;\n" - "por %%xmm4, %%xmm1 ;\n" - - /* 7 */ - "movl $7, %%eax ;\n" - "movd %%eax, %%xmm7 ;\n" - "pshufd $0x00, %%xmm7, %%xmm7 ;\n" - "pcmpeqd %%xmm6, %%xmm7 ;\n" - "movdqa 640(%1), %%xmm3 ;\n" - "movdqa 656(%1), %%xmm4 ;\n" - "pand %%xmm7, %%xmm3 ;\n" - "pand %%xmm7, %%xmm4 ;\n" - "por %%xmm3, %%xmm0 ;\n" - "por %%xmm4, %%xmm1 ;\n" - - /* 8 */ - "movl $8, %%eax ;\n" - "movd %%eax, %%xmm7 ;\n" - "pshufd $0x00, %%xmm7, %%xmm7 ;\n" - "pcmpeqd %%xmm6, %%xmm7 ;\n" - "movdqa 736(%1), %%xmm3 ;\n" - "movdqa 752(%1), %%xmm4 ;\n" - "pand %%xmm7, %%xmm3 ;\n" - "pand %%xmm7, %%xmm4 ;\n" - "por %%xmm3, %%xmm0 ;\n" - "por %%xmm4, %%xmm1 ;\n" - - /* store t2d */ - "movl %2, %%eax ;\n" - "addl $96, %%eax ;\n" - "movd %%xmm0, %%ecx ;\n" - "movl %%ecx, %%edx ;\n" - "pshufd $0x39, %%xmm0, %%xmm0 ;\n" - "andl $0x3ffffff, %%ecx ;\n" - "movl %%ecx, 0(%%eax) ;\n" - "movd %%xmm0, %%ecx ;\n" - "pshufd $0x39, %%xmm0, %%xmm0 ;\n" - "shrdl $26, %%ecx, %%edx ;\n" - "andl $0x1ffffff, %%edx ;\n" - "movl %%edx, 4(%%eax) ;\n" - "movd %%xmm0, %%edx ;\n" - "pshufd $0x39, %%xmm0, %%xmm0 ;\n" - "shrdl $19, %%edx, %%ecx ;\n" - "andl $0x3ffffff, %%ecx ;\n" - "movl %%ecx, 8(%%eax) ;\n" - "movd %%xmm0, %%ecx ;\n" - "shrdl $13, %%ecx, %%edx ;\n" - "andl $0x1ffffff, %%edx ;\n" - "movl %%edx, 12(%%eax) ;\n" - "movd %%xmm1, %%edx ;\n" - "pshufd $0x39, %%xmm1, %%xmm1 ;\n" - "shrl $6, %%ecx ;\n" - "andl $0x3ffffff, %%ecx ;\n" - "movl %%ecx, 16(%%eax) ;\n" - "movl %%edx, %%ecx ;\n" - "andl $0x1ffffff, %%edx ;\n" - "movl %%edx, 20(%%eax) ;\n" - "movd %%xmm1, %%edx ;\n" - "pshufd $0x39, %%xmm1, %%xmm1 ;\n" - "shrdl $25, %%edx, %%ecx ;\n" - "andl $0x3ffffff, %%ecx ;\n" - "movl %%ecx, 24(%%eax) ;\n" - "movd %%xmm1, %%ecx ;\n" - "pshufd $0x39, %%xmm1, %%xmm1 ;\n" - "shrdl $19, %%ecx, %%edx ;\n" - "andl $0x1ffffff, %%edx ;\n" - "movl %%edx, 28(%%eax) ;\n" - "movd %%xmm1, %%edx ;\n" - "movd %%xmm1, %%edx ;\n" - "shrdl $12, %%edx, %%ecx ;\n" - "andl $0x3ffffff, %%ecx ;\n" - "movl %%ecx, 32(%%eax) ;\n" - "shrl $6, %%edx ;\n" - "andl $0x1ffffff, %%edx ;\n" - "xorl %%ecx, %%ecx ;\n" - "movl %%edx, 36(%%eax) ;\n" - "movl %%ecx, 40(%%eax) ;\n" - "movl %%ecx, 44(%%eax) ;\n" - "movdqa 0(%%eax), %%xmm0 ;\n" - "movdqa 16(%%eax), %%xmm1 ;\n" - "movdqa 32(%%eax), %%xmm2 ;\n" - - /* conditionally negate t2d */ - - /* set up 2p in to 3/4 */ - "movl $0x7ffffda, %%ecx ;\n" - "movl $0x3fffffe, %%edx ;\n" - "movd %%ecx, %%xmm3 ;\n" - "movd %%edx, %%xmm5 ;\n" - "movl $0x7fffffe, %%ecx ;\n" - "movd %%ecx, %%xmm4 ;\n" - "punpckldq %%xmm5, %%xmm3 ;\n" - "punpckldq %%xmm5, %%xmm4 ;\n" - "punpcklqdq %%xmm4, %%xmm3 ;\n" - "movdqa %%xmm4, %%xmm5 ;\n" - "punpcklqdq %%xmm4, %%xmm4 ;\n" - - /* subtract and conditionally move */ - "movl %3, %%ecx ;\n" - "sub $1, %%ecx ;\n" - "movd %%ecx, %%xmm6 ;\n" - "pshufd $0x00, %%xmm6, %%xmm6 ;\n" - "movdqa %%xmm6, %%xmm7 ;\n" - "psubd %%xmm0, %%xmm3 ;\n" - "psubd %%xmm1, %%xmm4 ;\n" - "psubd %%xmm2, %%xmm5 ;\n" - "pand %%xmm6, %%xmm0 ;\n" - "pand %%xmm6, %%xmm1 ;\n" - "pand %%xmm6, %%xmm2 ;\n" - "pandn %%xmm3, %%xmm6 ;\n" - "movdqa %%xmm7, %%xmm3 ;\n" - "pandn %%xmm4, %%xmm7 ;\n" - "pandn %%xmm5, %%xmm3 ;\n" - "por %%xmm6, %%xmm0 ;\n" - "por %%xmm7, %%xmm1 ;\n" - "por %%xmm3, %%xmm2 ;\n" - - /* store */ - "movdqa %%xmm0, 0(%%eax) ;\n" - "movdqa %%xmm1, 16(%%eax) ;\n" - "movdqa %%xmm2, 32(%%eax) ;\n" - : - : "m"(u), "r"(&table[pos * 8]), "m"(t), "m"(sign) /* %0 = u, %1 = table, %2 = t, %3 = sign */ - : "%eax", "%ecx", "%edx", "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "%xmm7", "cc", "memory" - ); -} - -#endif /* defined(ED25519_GCC_32BIT_SSE_CHOOSE) */ - diff --git a/ed25519-donna/ed25519-donna-64bit-sse2.h b/ed25519-donna/ed25519-donna-64bit-sse2.h deleted file mode 100644 index ca08651d6..000000000 --- a/ed25519-donna/ed25519-donna-64bit-sse2.h +++ /dev/null @@ -1,436 +0,0 @@ -#if defined(ED25519_GCC_64BIT_SSE_CHOOSE) - -#define HAVE_GE25519_SCALARMULT_BASE_CHOOSE_NIELS - -DONNA_NOINLINE static void -ge25519_scalarmult_base_choose_niels(ge25519_niels *t, const uint8_t table[256][96], uint32_t pos, signed char b) { - int64_t breg = (int64_t)b; - uint64_t sign = (uint64_t)breg >> 63; - uint64_t mask = ~(sign - 1); - uint64_t u = (breg + mask) ^ mask; - - __asm__ __volatile__ ( - /* ysubx+xaddy+t2d */ - "movq %0, %%rax ;\n" - "movd %%rax, %%xmm14 ;\n" - "pshufd $0x00, %%xmm14, %%xmm14 ;\n" - "pxor %%xmm0, %%xmm0 ;\n" - "pxor %%xmm1, %%xmm1 ;\n" - "pxor %%xmm2, %%xmm2 ;\n" - "pxor %%xmm3, %%xmm3 ;\n" - "pxor %%xmm4, %%xmm4 ;\n" - "pxor %%xmm5, %%xmm5 ;\n" - - /* 0 */ - "movq $0, %%rax ;\n" - "movd %%rax, %%xmm15 ;\n" - "pshufd $0x00, %%xmm15, %%xmm15 ;\n" - "pcmpeqd %%xmm14, %%xmm15 ;\n" - "movq $1, %%rax ;\n" - "movd %%rax, %%xmm6 ;\n" - "pxor %%xmm7, %%xmm7 ;\n" - "pand %%xmm15, %%xmm6 ;\n" - "pand %%xmm15, %%xmm7 ;\n" - "por %%xmm6, %%xmm0 ;\n" - "por %%xmm7, %%xmm1 ;\n" - "por %%xmm6, %%xmm2 ;\n" - "por %%xmm7, %%xmm3 ;\n" - - /* 1 */ - "movq $1, %%rax ;\n" - "movd %%rax, %%xmm15 ;\n" - "pshufd $0x00, %%xmm15, %%xmm15 ;\n" - "pcmpeqd %%xmm14, %%xmm15 ;\n" - "movdqa 0(%1), %%xmm6 ;\n" - "movdqa 16(%1), %%xmm7 ;\n" - "movdqa 32(%1), %%xmm8 ;\n" - "movdqa 48(%1), %%xmm9 ;\n" - "movdqa 64(%1), %%xmm10 ;\n" - "movdqa 80(%1), %%xmm11 ;\n" - "pand %%xmm15, %%xmm6 ;\n" - "pand %%xmm15, %%xmm7 ;\n" - "pand %%xmm15, %%xmm8 ;\n" - "pand %%xmm15, %%xmm9 ;\n" - "pand %%xmm15, %%xmm10 ;\n" - "pand %%xmm15, %%xmm11 ;\n" - "por %%xmm6, %%xmm0 ;\n" - "por %%xmm7, %%xmm1 ;\n" - "por %%xmm8, %%xmm2 ;\n" - "por %%xmm9, %%xmm3 ;\n" - "por %%xmm10, %%xmm4 ;\n" - "por %%xmm11, %%xmm5 ;\n" - - /* 2 */ - "movq $2, %%rax ;\n" - "movd %%rax, %%xmm15 ;\n" - "pshufd $0x00, %%xmm15, %%xmm15 ;\n" - "pcmpeqd %%xmm14, %%xmm15 ;\n" - "movdqa 96(%1), %%xmm6 ;\n" - "movdqa 112(%1), %%xmm7 ;\n" - "movdqa 128(%1), %%xmm8 ;\n" - "movdqa 144(%1), %%xmm9 ;\n" - "movdqa 160(%1), %%xmm10 ;\n" - "movdqa 176(%1), %%xmm11 ;\n" - "pand %%xmm15, %%xmm6 ;\n" - "pand %%xmm15, %%xmm7 ;\n" - "pand %%xmm15, %%xmm8 ;\n" - "pand %%xmm15, %%xmm9 ;\n" - "pand %%xmm15, %%xmm10 ;\n" - "pand %%xmm15, %%xmm11 ;\n" - "por %%xmm6, %%xmm0 ;\n" - "por %%xmm7, %%xmm1 ;\n" - "por %%xmm8, %%xmm2 ;\n" - "por %%xmm9, %%xmm3 ;\n" - "por %%xmm10, %%xmm4 ;\n" - "por %%xmm11, %%xmm5 ;\n" - - /* 3 */ - "movq $3, %%rax ;\n" - "movd %%rax, %%xmm15 ;\n" - "pshufd $0x00, %%xmm15, %%xmm15 ;\n" - "pcmpeqd %%xmm14, %%xmm15 ;\n" - "movdqa 192(%1), %%xmm6 ;\n" - "movdqa 208(%1), %%xmm7 ;\n" - "movdqa 224(%1), %%xmm8 ;\n" - "movdqa 240(%1), %%xmm9 ;\n" - "movdqa 256(%1), %%xmm10 ;\n" - "movdqa 272(%1), %%xmm11 ;\n" - "pand %%xmm15, %%xmm6 ;\n" - "pand %%xmm15, %%xmm7 ;\n" - "pand %%xmm15, %%xmm8 ;\n" - "pand %%xmm15, %%xmm9 ;\n" - "pand %%xmm15, %%xmm10 ;\n" - "pand %%xmm15, %%xmm11 ;\n" - "por %%xmm6, %%xmm0 ;\n" - "por %%xmm7, %%xmm1 ;\n" - "por %%xmm8, %%xmm2 ;\n" - "por %%xmm9, %%xmm3 ;\n" - "por %%xmm10, %%xmm4 ;\n" - "por %%xmm11, %%xmm5 ;\n" - - /* 4 */ - "movq $4, %%rax ;\n" - "movd %%rax, %%xmm15 ;\n" - "pshufd $0x00, %%xmm15, %%xmm15 ;\n" - "pcmpeqd %%xmm14, %%xmm15 ;\n" - "movdqa 288(%1), %%xmm6 ;\n" - "movdqa 304(%1), %%xmm7 ;\n" - "movdqa 320(%1), %%xmm8 ;\n" - "movdqa 336(%1), %%xmm9 ;\n" - "movdqa 352(%1), %%xmm10 ;\n" - "movdqa 368(%1), %%xmm11 ;\n" - "pand %%xmm15, %%xmm6 ;\n" - "pand %%xmm15, %%xmm7 ;\n" - "pand %%xmm15, %%xmm8 ;\n" - "pand %%xmm15, %%xmm9 ;\n" - "pand %%xmm15, %%xmm10 ;\n" - "pand %%xmm15, %%xmm11 ;\n" - "por %%xmm6, %%xmm0 ;\n" - "por %%xmm7, %%xmm1 ;\n" - "por %%xmm8, %%xmm2 ;\n" - "por %%xmm9, %%xmm3 ;\n" - "por %%xmm10, %%xmm4 ;\n" - "por %%xmm11, %%xmm5 ;\n" - - /* 5 */ - "movq $5, %%rax ;\n" - "movd %%rax, %%xmm15 ;\n" - "pshufd $0x00, %%xmm15, %%xmm15 ;\n" - "pcmpeqd %%xmm14, %%xmm15 ;\n" - "movdqa 384(%1), %%xmm6 ;\n" - "movdqa 400(%1), %%xmm7 ;\n" - "movdqa 416(%1), %%xmm8 ;\n" - "movdqa 432(%1), %%xmm9 ;\n" - "movdqa 448(%1), %%xmm10 ;\n" - "movdqa 464(%1), %%xmm11 ;\n" - "pand %%xmm15, %%xmm6 ;\n" - "pand %%xmm15, %%xmm7 ;\n" - "pand %%xmm15, %%xmm8 ;\n" - "pand %%xmm15, %%xmm9 ;\n" - "pand %%xmm15, %%xmm10 ;\n" - "pand %%xmm15, %%xmm11 ;\n" - "por %%xmm6, %%xmm0 ;\n" - "por %%xmm7, %%xmm1 ;\n" - "por %%xmm8, %%xmm2 ;\n" - "por %%xmm9, %%xmm3 ;\n" - "por %%xmm10, %%xmm4 ;\n" - "por %%xmm11, %%xmm5 ;\n" - - /* 6 */ - "movq $6, %%rax ;\n" - "movd %%rax, %%xmm15 ;\n" - "pshufd $0x00, %%xmm15, %%xmm15 ;\n" - "pcmpeqd %%xmm14, %%xmm15 ;\n" - "movdqa 480(%1), %%xmm6 ;\n" - "movdqa 496(%1), %%xmm7 ;\n" - "movdqa 512(%1), %%xmm8 ;\n" - "movdqa 528(%1), %%xmm9 ;\n" - "movdqa 544(%1), %%xmm10 ;\n" - "movdqa 560(%1), %%xmm11 ;\n" - "pand %%xmm15, %%xmm6 ;\n" - "pand %%xmm15, %%xmm7 ;\n" - "pand %%xmm15, %%xmm8 ;\n" - "pand %%xmm15, %%xmm9 ;\n" - "pand %%xmm15, %%xmm10 ;\n" - "pand %%xmm15, %%xmm11 ;\n" - "por %%xmm6, %%xmm0 ;\n" - "por %%xmm7, %%xmm1 ;\n" - "por %%xmm8, %%xmm2 ;\n" - "por %%xmm9, %%xmm3 ;\n" - "por %%xmm10, %%xmm4 ;\n" - "por %%xmm11, %%xmm5 ;\n" - - /* 7 */ - "movq $7, %%rax ;\n" - "movd %%rax, %%xmm15 ;\n" - "pshufd $0x00, %%xmm15, %%xmm15 ;\n" - "pcmpeqd %%xmm14, %%xmm15 ;\n" - "movdqa 576(%1), %%xmm6 ;\n" - "movdqa 592(%1), %%xmm7 ;\n" - "movdqa 608(%1), %%xmm8 ;\n" - "movdqa 624(%1), %%xmm9 ;\n" - "movdqa 640(%1), %%xmm10 ;\n" - "movdqa 656(%1), %%xmm11 ;\n" - "pand %%xmm15, %%xmm6 ;\n" - "pand %%xmm15, %%xmm7 ;\n" - "pand %%xmm15, %%xmm8 ;\n" - "pand %%xmm15, %%xmm9 ;\n" - "pand %%xmm15, %%xmm10 ;\n" - "pand %%xmm15, %%xmm11 ;\n" - "por %%xmm6, %%xmm0 ;\n" - "por %%xmm7, %%xmm1 ;\n" - "por %%xmm8, %%xmm2 ;\n" - "por %%xmm9, %%xmm3 ;\n" - "por %%xmm10, %%xmm4 ;\n" - "por %%xmm11, %%xmm5 ;\n" - - /* 8 */ - "movq $8, %%rax ;\n" - "movd %%rax, %%xmm15 ;\n" - "pshufd $0x00, %%xmm15, %%xmm15 ;\n" - "pcmpeqd %%xmm14, %%xmm15 ;\n" - "movdqa 672(%1), %%xmm6 ;\n" - "movdqa 688(%1), %%xmm7 ;\n" - "movdqa 704(%1), %%xmm8 ;\n" - "movdqa 720(%1), %%xmm9 ;\n" - "movdqa 736(%1), %%xmm10 ;\n" - "movdqa 752(%1), %%xmm11 ;\n" - "pand %%xmm15, %%xmm6 ;\n" - "pand %%xmm15, %%xmm7 ;\n" - "pand %%xmm15, %%xmm8 ;\n" - "pand %%xmm15, %%xmm9 ;\n" - "pand %%xmm15, %%xmm10 ;\n" - "pand %%xmm15, %%xmm11 ;\n" - "por %%xmm6, %%xmm0 ;\n" - "por %%xmm7, %%xmm1 ;\n" - "por %%xmm8, %%xmm2 ;\n" - "por %%xmm9, %%xmm3 ;\n" - "por %%xmm10, %%xmm4 ;\n" - "por %%xmm11, %%xmm5 ;\n" - - /* conditionally swap ysubx and xaddy */ - "movq %3, %%rax ;\n" - "xorq $1, %%rax ;\n" - "movd %%rax, %%xmm14 ;\n" - "pxor %%xmm15, %%xmm15 ;\n" - "pshufd $0x00, %%xmm14, %%xmm14 ;\n" - "pxor %%xmm0, %%xmm2 ;\n" - "pxor %%xmm1, %%xmm3 ;\n" - "pcmpeqd %%xmm14, %%xmm15 ;\n" - "movdqa %%xmm2, %%xmm6 ;\n" - "movdqa %%xmm3, %%xmm7 ;\n" - "pand %%xmm15, %%xmm6 ;\n" - "pand %%xmm15, %%xmm7 ;\n" - "pxor %%xmm6, %%xmm0 ;\n" - "pxor %%xmm7, %%xmm1 ;\n" - "pxor %%xmm0, %%xmm2 ;\n" - "pxor %%xmm1, %%xmm3 ;\n" - - /* store ysubx */ - "xorq %%rax, %%rax ;\n" - "movd %%xmm0, %%rcx ;\n" - "movd %%xmm0, %%r8 ;\n" - "movd %%xmm1, %%rsi ;\n" - "pshufd $0xee, %%xmm0, %%xmm0 ;\n" - "pshufd $0xee, %%xmm1, %%xmm1 ;\n" - "movd %%xmm0, %%rdx ;\n" - "movd %%xmm1, %%rdi ;\n" - "shrdq $51, %%rdx, %%r8 ;\n" - "shrdq $38, %%rsi, %%rdx ;\n" - "shrdq $25, %%rdi, %%rsi ;\n" - "shrq $12, %%rdi ;\n" - "movq %%rcx, %%r9 ;\n" - "movq %%r8, %%r10 ;\n" - "movq %%rdx, %%r11 ;\n" - "movq %%rsi, %%r12 ;\n" - "movq %%rdi, %%r13 ;\n" - "shrq $26, %%r9 ;\n" - "shrq $26, %%r10 ;\n" - "shrq $26, %%r11 ;\n" - "shrq $26, %%r12 ;\n" - "shrq $26, %%r13 ;\n" - "andl $0x3ffffff, %%ecx ;\n" - "andl $0x1ffffff, %%r9d ;\n" - "andl $0x3ffffff, %%r8d ;\n" - "andl $0x1ffffff, %%r10d ;\n" - "andl $0x3ffffff, %%edx ;\n" - "andl $0x1ffffff, %%r11d ;\n" - "andl $0x3ffffff, %%esi ;\n" - "andl $0x1ffffff, %%r12d ;\n" - "andl $0x3ffffff, %%edi ;\n" - "andl $0x1ffffff, %%r13d ;\n" - "movl %%ecx, 0(%2) ;\n" - "movl %%r9d, 4(%2) ;\n" - "movl %%r8d, 8(%2) ;\n" - "movl %%r10d, 12(%2) ;\n" - "movl %%edx, 16(%2) ;\n" - "movl %%r11d, 20(%2) ;\n" - "movl %%esi, 24(%2) ;\n" - "movl %%r12d, 28(%2) ;\n" - "movl %%edi, 32(%2) ;\n" - "movl %%r13d, 36(%2) ;\n" - "movq %%rax, 40(%2) ;\n" - - /* store xaddy */ - "movd %%xmm2, %%rcx ;\n" - "movd %%xmm2, %%r8 ;\n" - "movd %%xmm3, %%rsi ;\n" - "pshufd $0xee, %%xmm2, %%xmm2 ;\n" - "pshufd $0xee, %%xmm3, %%xmm3 ;\n" - "movd %%xmm2, %%rdx ;\n" - "movd %%xmm3, %%rdi ;\n" - "shrdq $51, %%rdx, %%r8 ;\n" - "shrdq $38, %%rsi, %%rdx ;\n" - "shrdq $25, %%rdi, %%rsi ;\n" - "shrq $12, %%rdi ;\n" - "movq %%rcx, %%r9 ;\n" - "movq %%r8, %%r10 ;\n" - "movq %%rdx, %%r11 ;\n" - "movq %%rsi, %%r12 ;\n" - "movq %%rdi, %%r13 ;\n" - "shrq $26, %%r9 ;\n" - "shrq $26, %%r10 ;\n" - "shrq $26, %%r11 ;\n" - "shrq $26, %%r12 ;\n" - "shrq $26, %%r13 ;\n" - "andl $0x3ffffff, %%ecx ;\n" - "andl $0x1ffffff, %%r9d ;\n" - "andl $0x3ffffff, %%r8d ;\n" - "andl $0x1ffffff, %%r10d ;\n" - "andl $0x3ffffff, %%edx ;\n" - "andl $0x1ffffff, %%r11d ;\n" - "andl $0x3ffffff, %%esi ;\n" - "andl $0x1ffffff, %%r12d ;\n" - "andl $0x3ffffff, %%edi ;\n" - "andl $0x1ffffff, %%r13d ;\n" - "movl %%ecx, 48(%2) ;\n" - "movl %%r9d, 52(%2) ;\n" - "movl %%r8d, 56(%2) ;\n" - "movl %%r10d, 60(%2) ;\n" - "movl %%edx, 64(%2) ;\n" - "movl %%r11d, 68(%2) ;\n" - "movl %%esi, 72(%2) ;\n" - "movl %%r12d, 76(%2) ;\n" - "movl %%edi, 80(%2) ;\n" - "movl %%r13d, 84(%2) ;\n" - "movq %%rax, 88(%2) ;\n" - - /* extract t2d */ - "xorq %%rax, %%rax ;\n" - "movd %%xmm4, %%rcx ;\n" - "movd %%xmm4, %%r8 ;\n" - "movd %%xmm5, %%rsi ;\n" - "pshufd $0xee, %%xmm4, %%xmm4 ;\n" - "pshufd $0xee, %%xmm5, %%xmm5 ;\n" - "movd %%xmm4, %%rdx ;\n" - "movd %%xmm5, %%rdi ;\n" - "shrdq $51, %%rdx, %%r8 ;\n" - "shrdq $38, %%rsi, %%rdx ;\n" - "shrdq $25, %%rdi, %%rsi ;\n" - "shrq $12, %%rdi ;\n" - "movq %%rcx, %%r9 ;\n" - "movq %%r8, %%r10 ;\n" - "movq %%rdx, %%r11 ;\n" - "movq %%rsi, %%r12 ;\n" - "movq %%rdi, %%r13 ;\n" - "shrq $26, %%r9 ;\n" - "shrq $26, %%r10 ;\n" - "shrq $26, %%r11 ;\n" - "shrq $26, %%r12 ;\n" - "shrq $26, %%r13 ;\n" - "andl $0x3ffffff, %%ecx ;\n" - "andl $0x1ffffff, %%r9d ;\n" - "andl $0x3ffffff, %%r8d ;\n" - "andl $0x1ffffff, %%r10d ;\n" - "andl $0x3ffffff, %%edx ;\n" - "andl $0x1ffffff, %%r11d ;\n" - "andl $0x3ffffff, %%esi ;\n" - "andl $0x1ffffff, %%r12d ;\n" - "andl $0x3ffffff, %%edi ;\n" - "andl $0x1ffffff, %%r13d ;\n" - "movd %%ecx, %%xmm0 ;\n" - "movd %%r9d, %%xmm4 ;\n" - "movd %%r8d, %%xmm8 ;\n" - "movd %%r10d, %%xmm3 ;\n" - "movd %%edx, %%xmm1 ;\n" - "movd %%r11d, %%xmm5 ;\n" - "movd %%esi, %%xmm6 ;\n" - "movd %%r12d, %%xmm7 ;\n" - "movd %%edi, %%xmm2 ;\n" - "movd %%r13d, %%xmm9 ;\n" - "punpckldq %%xmm4, %%xmm0 ;\n" - "punpckldq %%xmm3, %%xmm8 ;\n" - "punpckldq %%xmm5, %%xmm1 ;\n" - "punpckldq %%xmm7, %%xmm6 ;\n" - "punpckldq %%xmm9, %%xmm2 ;\n" - "punpcklqdq %%xmm8, %%xmm0 ;\n" - "punpcklqdq %%xmm6, %%xmm1 ;\n" - - /* set up 2p in to 3/4 */ - "movl $0x7ffffda, %%ecx ;\n" - "movl $0x3fffffe, %%edx ;\n" - "movl $0x7fffffe, %%eax ;\n" - "movd %%ecx, %%xmm3 ;\n" - "movd %%edx, %%xmm5 ;\n" - "movd %%eax, %%xmm4 ;\n" - "punpckldq %%xmm5, %%xmm3 ;\n" - "punpckldq %%xmm5, %%xmm4 ;\n" - "punpcklqdq %%xmm4, %%xmm3 ;\n" - "movdqa %%xmm4, %%xmm5 ;\n" - "punpcklqdq %%xmm4, %%xmm4 ;\n" - - /* subtract and conditionally move */ - "movl %3, %%ecx ;\n" - "sub $1, %%ecx ;\n" - "movd %%ecx, %%xmm6 ;\n" - "pshufd $0x00, %%xmm6, %%xmm6 ;\n" - "movdqa %%xmm6, %%xmm7 ;\n" - "psubd %%xmm0, %%xmm3 ;\n" - "psubd %%xmm1, %%xmm4 ;\n" - "psubd %%xmm2, %%xmm5 ;\n" - "pand %%xmm6, %%xmm0 ;\n" - "pand %%xmm6, %%xmm1 ;\n" - "pand %%xmm6, %%xmm2 ;\n" - "pandn %%xmm3, %%xmm6 ;\n" - "movdqa %%xmm7, %%xmm3 ;\n" - "pandn %%xmm4, %%xmm7 ;\n" - "pandn %%xmm5, %%xmm3 ;\n" - "por %%xmm6, %%xmm0 ;\n" - "por %%xmm7, %%xmm1 ;\n" - "por %%xmm3, %%xmm2 ;\n" - - /* store t2d */ - "movdqa %%xmm0, 96(%2) ;\n" - "movdqa %%xmm1, 112(%2) ;\n" - "movdqa %%xmm2, 128(%2) ;\n" - : - : "m"(u), "r"(&table[pos * 8]), "r"(t), "m"(sign) /* %0 = u, %1 = table, %2 = t, %3 = sign */ - : - "%rax", "%rcx", "%rdx", "%rdi", "%rsi", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", - "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "%xmm7", "%xmm8", "%xmm9", "%xmm10", "%xmm11", "%xmm14", "%xmm14", - "cc", "memory" - ); -} - -#endif /* defined(ED25519_GCC_64BIT_SSE_CHOOSE) */ - diff --git a/ed25519-donna/ed25519-donna-64bit-tables.h b/ed25519-donna/ed25519-donna-64bit-tables.h deleted file mode 100644 index e5e449099..000000000 --- a/ed25519-donna/ed25519-donna-64bit-tables.h +++ /dev/null @@ -1,53 +0,0 @@ -const ge25519 ge25519_basepoint = { - {0x00062d608f25d51a,0x000412a4b4f6592a,0x00075b7171a4b31d,0x0001ff60527118fe,0x000216936d3cd6e5}, - {0x0006666666666658,0x0004cccccccccccc,0x0001999999999999,0x0003333333333333,0x0006666666666666}, - {0x0000000000000001,0x0000000000000000,0x0000000000000000,0x0000000000000000,0x0000000000000000}, - {0x00068ab3a5b7dda3,0x00000eea2a5eadbb,0x0002af8df483c27e,0x000332b375274732,0x00067875f0fd78b7} -}; - -const bignum25519 ge25519_ecd = { - 0x00034dca135978a3,0x0001a8283b156ebd,0x0005e7a26001c029,0x000739c663a03cbb,0x00052036cee2b6ff -}; - -const bignum25519 ge25519_ec2d = { - 0x00069b9426b2f159,0x00035050762add7a,0x0003cf44c0038052,0x0006738cc7407977,0x0002406d9dc56dff -}; - -const bignum25519 ge25519_sqrtneg1 = { - 0x00061b274a0ea0b0,0x0000d5a5fc8f189d,0x0007ef5e9cbd0c60,0x00078595a6804c9e,0x0002b8324804fc1d -}; - -const ge25519_niels ge25519_niels_sliding_multiples[32] = { - {{0x00003905d740913e,0x0000ba2817d673a2,0x00023e2827f4e67c,0x000133d2e0c21a34,0x00044fd2f9298f81},{0x000493c6f58c3b85,0x0000df7181c325f7,0x0000f50b0b3e4cb7,0x0005329385a44c32,0x00007cf9d3a33d4b},{0x00011205877aaa68,0x000479955893d579,0x00050d66309b67a0,0x0002d42d0dbee5ee,0x0006f117b689f0c6}}, - {{0x00011fe8a4fcd265,0x0007bcb8374faacc,0x00052f5af4ef4d4f,0x0005314098f98d10,0x0002ab91587555bd},{0x0005b0a84cee9730,0x00061d10c97155e4,0x0004059cc8096a10,0x00047a608da8014f,0x0007a164e1b9a80f},{0x0006933f0dd0d889,0x00044386bb4c4295,0x0003cb6d3162508c,0x00026368b872a2c6,0x0005a2826af12b9b}}, - {{0x000182c3a447d6ba,0x00022964e536eff2,0x000192821f540053,0x0002f9f19e788e5c,0x000154a7e73eb1b5},{0x0002bc4408a5bb33,0x000078ebdda05442,0x0002ffb112354123,0x000375ee8df5862d,0x0002945ccf146e20},{0x0003dbf1812a8285,0x0000fa17ba3f9797,0x0006f69cb49c3820,0x00034d5a0db3858d,0x00043aabe696b3bb}}, - {{0x00072c9aaa3221b1,0x000267774474f74d,0x000064b0e9b28085,0x0003f04ef53b27c9,0x0001d6edd5d2e531},{0x00025cd0944ea3bf,0x00075673b81a4d63,0x000150b925d1c0d4,0x00013f38d9294114,0x000461bea69283c9},{0x00036dc801b8b3a2,0x0000e0a7d4935e30,0x0001deb7cecc0d7d,0x000053a94e20dd2c,0x0007a9fbb1c6a0f9}}, - {{0x0006217e039d8064,0x0006dea408337e6d,0x00057ac112628206,0x000647cb65e30473,0x00049c05a51fadc9},{0x0006678aa6a8632f,0x0005ea3788d8b365,0x00021bd6d6994279,0x0007ace75919e4e3,0x00034b9ed338add7},{0x0004e8bf9045af1b,0x000514e33a45e0d6,0x0007533c5b8bfe0f,0x000583557b7e14c9,0x00073c172021b008}}, - {{0x00075b0249864348,0x00052ee11070262b,0x000237ae54fb5acd,0x0003bfd1d03aaab5,0x00018ab598029d5c},{0x000700848a802ade,0x0001e04605c4e5f7,0x0005c0d01b9767fb,0x0007d7889f42388b,0x0004275aae2546d8},{0x00032cc5fd6089e9,0x000426505c949b05,0x00046a18880c7ad2,0x0004a4221888ccda,0x0003dc65522b53df}}, - {{0x0007013b327fbf93,0x0001336eeded6a0d,0x0002b565a2bbf3af,0x000253ce89591955,0x0000267882d17602},{0x0000c222a2007f6d,0x000356b79bdb77ee,0x00041ee81efe12ce,0x000120a9bd07097d,0x000234fd7eec346f},{0x0000a119732ea378,0x00063bf1ba8e2a6c,0x00069f94cc90df9a,0x000431d1779bfc48,0x000497ba6fdaa097}}, - {{0x0003cd86468ccf0b,0x00048553221ac081,0x0006c9464b4e0a6e,0x00075fba84180403,0x00043b5cd4218d05},{0x0006cc0313cfeaa0,0x0001a313848da499,0x0007cb534219230a,0x00039596dedefd60,0x00061e22917f12de},{0x0002762f9bd0b516,0x0001c6e7fbddcbb3,0x00075909c3ace2bd,0x00042101972d3ec9,0x000511d61210ae4d}}, - {{0x000386484420de87,0x0002d6b25db68102,0x000650b4962873c0,0x0004081cfd271394,0x00071a7fe6fe2482},{0x000676ef950e9d81,0x0001b81ae089f258,0x00063c4922951883,0x0002f1d54d9b3237,0x0006d325924ddb85},{0x000182b8a5c8c854,0x00073fcbe5406d8e,0x0005de3430cff451,0x000554b967ac8c41,0x0004746c4b6559ee}}, - {{0x000546c864741147,0x0003a1df99092690,0x0001ca8cc9f4d6bb,0x00036b7fc9cd3b03,0x000219663497db5e},{0x00077b3c6dc69a2b,0x0004edf13ec2fa6e,0x0004e85ad77beac8,0x0007dba2b28e7bda,0x0005c9a51de34fe9},{0x0000f1cf79f10e67,0x00043ccb0a2b7ea2,0x00005089dfff776a,0x0001dd84e1d38b88,0x0004804503c60822}}, - {{0x000021d23a36d175,0x0004fd3373c6476d,0x00020e291eeed02a,0x00062f2ecf2e7210,0x000771e098858de4},{0x00049ed02ca37fc7,0x000474c2b5957884,0x0005b8388e816683,0x0004b6c454b76be4,0x000553398a516506},{0x0002f5d278451edf,0x000730b133997342,0x0006965420eb6975,0x000308a3bfa516cf,0x0005a5ed1d68ff5a}}, - {{0x0005e0c558527359,0x0003395b73afd75c,0x000072afa4e4b970,0x00062214329e0f6d,0x000019b60135fefd},{0x0005122afe150e83,0x0004afc966bb0232,0x0001c478833c8268,0x00017839c3fc148f,0x00044acb897d8bf9},{0x000068145e134b83,0x0001e4860982c3cc,0x000068fb5f13d799,0x0007c9283744547e,0x000150c49fde6ad2}}, - {{0x0001863c9cdca868,0x0003770e295a1709,0x0000d85a3720fd13,0x0005e0ff1f71ab06,0x00078a6d7791e05f},{0x0003f29509471138,0x000729eeb4ca31cf,0x00069c22b575bfbc,0x0004910857bce212,0x0006b2b5a075bb99},{0x0007704b47a0b976,0x0002ae82e91aab17,0x00050bd6429806cd,0x00068055158fd8ea,0x000725c7ffc4ad55}}, - {{0x00002bf71cd098c0,0x00049dabcc6cd230,0x00040a6533f905b2,0x000573efac2eb8a4,0x0004cd54625f855f},{0x00026715d1cf99b2,0x0002205441a69c88,0x000448427dcd4b54,0x0001d191e88abdc5,0x000794cc9277cb1f},{0x0006c426c2ac5053,0x0005a65ece4b095e,0x0000c44086f26bb6,0x0007429568197885,0x0007008357b6fcc8}}, - {{0x00039fbb82584a34,0x00047a568f257a03,0x00014d88091ead91,0x0002145b18b1ce24,0x00013a92a3669d6d},{0x0000672738773f01,0x000752bf799f6171,0x0006b4a6dae33323,0x0007b54696ead1dc,0x00006ef7e9851ad0},{0x0003771cc0577de5,0x0003ca06bb8b9952,0x00000b81c5d50390,0x00043512340780ec,0x0003c296ddf8a2af}}, - {{0x00034d2ebb1f2541,0x0000e815b723ff9d,0x000286b416e25443,0x0000bdfe38d1bee8,0x0000a892c7007477},{0x000515f9d914a713,0x00073191ff2255d5,0x00054f5cc2a4bdef,0x0003dd57fc118bcf,0x0007a99d393490c7},{0x0002ed2436bda3e8,0x00002afd00f291ea,0x0000be7381dea321,0x0003e952d4b2b193,0x000286762d28302f}}, - {{0x00058e2bce2ef5bd,0x00068ce8f78c6f8a,0x0006ee26e39261b2,0x00033d0aa50bcf9d,0x0007686f2a3d6f17},{0x000036093ce35b25,0x0003b64d7552e9cf,0x00071ee0fe0b8460,0x00069d0660c969e5,0x00032f1da046a9d9},{0x000512a66d597c6a,0x0000609a70a57551,0x000026c08a3c464c,0x0004531fc8ee39e1,0x000561305f8a9ad2}}, - {{0x0002cc28e7b0c0d5,0x00077b60eb8a6ce4,0x0004042985c277a6,0x000636657b46d3eb,0x000030a1aef2c57c},{0x0004978dec92aed1,0x000069adae7ca201,0x00011ee923290f55,0x00069641898d916c,0x00000aaec53e35d4},{0x0001f773003ad2aa,0x000005642cc10f76,0x00003b48f82cfca6,0x0002403c10ee4329,0x00020be9c1c24065}}, - {{0x0000e44ae2025e60,0x0005f97b9727041c,0x0005683472c0ecec,0x000188882eb1ce7c,0x00069764c545067e},{0x000387d8249673a6,0x0005bea8dc927c2a,0x0005bd8ed5650ef0,0x0000ef0e3fcd40e1,0x000750ab3361f0ac},{0x00023283a2f81037,0x000477aff97e23d1,0x0000b8958dbcbb68,0x0000205b97e8add6,0x00054f96b3fb7075}}, - {{0x0005afc616b11ecd,0x00039f4aec8f22ef,0x0003b39e1625d92e,0x0005f85bd4508873,0x00078e6839fbe85d},{0x0005f20429669279,0x00008fafae4941f5,0x00015d83c4eb7688,0x0001cf379eca4146,0x0003d7fe9c52bb75},{0x00032df737b8856b,0x0000608342f14e06,0x0003967889d74175,0x0001211907fba550,0x00070f268f350088}}, - {{0x0004112070dcf355,0x0007dcff9c22e464,0x00054ada60e03325,0x00025cd98eef769a,0x000404e56c039b8c},{0x00064583b1805f47,0x00022c1baf832cd0,0x000132c01bd4d717,0x0004ecf4c3a75b8f,0x0007c0d345cfad88},{0x00071f4b8c78338a,0x00062cfc16bc2b23,0x00017cf51280d9aa,0x0003bbae5e20a95a,0x00020d754762aaec}}, - {{0x0004feb135b9f543,0x00063bd192ad93ae,0x00044e2ea612cdf7,0x000670f4991583ab,0x00038b8ada8790b4},{0x0007c36fc73bb758,0x0004a6c797734bd1,0x0000ef248ab3950e,0x00063154c9a53ec8,0x0002b8f1e46f3cee},{0x00004a9cdf51f95d,0x0005d963fbd596b8,0x00022d9b68ace54a,0x0004a98e8836c599,0x000049aeb32ceba1}}, - {{0x00067d3c63dcfe7e,0x000112f0adc81aee,0x00053df04c827165,0x0002fe5b33b430f0,0x00051c665e0c8d62},{0x00007d0b75fc7931,0x00016f4ce4ba754a,0x0005ace4c03fbe49,0x00027e0ec12a159c,0x000795ee17530f67},{0x00025b0a52ecbd81,0x0005dc0695fce4a9,0x0003b928c575047d,0x00023bf3512686e5,0x0006cd19bf49dc54}}, - {{0x0007619052179ca3,0x0000c16593f0afd0,0x000265c4795c7428,0x00031c40515d5442,0x0007520f3db40b2e},{0x0006612165afc386,0x0001171aa36203ff,0x0002642ea820a8aa,0x0001f3bb7b313f10,0x0005e01b3a7429e4},{0x00050be3d39357a1,0x0003ab33d294a7b6,0x0004c479ba59edb3,0x0004c30d184d326f,0x00071092c9ccef3c}}, - {{0x0000523f0364918c,0x000687f56d638a7b,0x00020796928ad013,0x0005d38405a54f33,0x0000ea15b03d0257},{0x0003d8ac74051dcf,0x00010ab6f543d0ad,0x0005d0f3ac0fda90,0x0005ef1d2573e5e4,0x0004173a5bb7137a},{0x00056e31f0f9218a,0x0005635f88e102f8,0x0002cbc5d969a5b8,0x000533fbc98b347a,0x0005fc565614a4e3}}, - {{0x0006570dc46d7ae5,0x00018a9f1b91e26d,0x000436b6183f42ab,0x000550acaa4f8198,0x00062711c414c454},{0x0002e1e67790988e,0x0001e38b9ae44912,0x000648fbb4075654,0x00028df1d840cd72,0x0003214c7409d466},{0x0001827406651770,0x0004d144f286c265,0x00017488f0ee9281,0x00019e6cdb5c760c,0x0005bea94073ecb8}}, - {{0x0005bf0912c89be4,0x00062fadcaf38c83,0x00025ec196b3ce2c,0x00077655ff4f017b,0x0003aacd5c148f61},{0x0000ce63f343d2f8,0x0001e0a87d1e368e,0x000045edbc019eea,0x0006979aed28d0d1,0x0004ad0785944f1b},{0x00063b34c3318301,0x0000e0e62d04d0b1,0x000676a233726701,0x00029e9a042d9769,0x0003aff0cb1d9028}}, - {{0x0005c7eb3a20405e,0x0005fdb5aad930f8,0x0004a757e63b8c47,0x00028e9492972456,0x000110e7e86f4cd2},{0x0006430bf4c53505,0x000264c3e4507244,0x00074c9f19a39270,0x00073f84f799bc47,0x0002ccf9f732bd99},{0x0000d89ed603f5e4,0x00051e1604018af8,0x0000b8eedc4a2218,0x00051ba98b9384d0,0x00005c557e0b9693}}, - {{0x0001ce311fc97e6f,0x0006023f3fb5db1f,0x0007b49775e8fc98,0x0003ad70adbf5045,0x0006e154c178fe98},{0x0006bbb089c20eb0,0x0006df41fb0b9eee,0x00051087ed87e16f,0x000102db5c9fa731,0x000289fef0841861},{0x00016336fed69abf,0x0004f066b929f9ec,0x0004e9ff9e6c5b93,0x00018c89bc4bb2ba,0x0006afbf642a95ca}}, - {{0x0000de0c62f5d2c1,0x00049601cf734fb5,0x0006b5c38263f0f6,0x0004623ef5b56d06,0x0000db4b851b9503},{0x00055070f913a8cc,0x000765619eac2bbc,0x0003ab5225f47459,0x00076ced14ab5b48,0x00012c093cedb801},{0x00047f9308b8190f,0x000414235c621f82,0x00031f5ff41a5a76,0x0006736773aab96d,0x00033aa8799c6635}}, - {{0x0007f51ebd085cf2,0x00012cfa67e3f5e1,0x0001800cf1e3d46a,0x00054337615ff0a8,0x000233c6f29e8e21},{0x0000f588fc156cb1,0x000363414da4f069,0x0007296ad9b68aea,0x0004d3711316ae43,0x000212cd0c1c8d58},{0x0004d5107f18c781,0x00064a4fd3a51a5e,0x0004f4cd0448bb37,0x000671d38543151e,0x0001db7778911914}}, - {{0x000352397c6bc26f,0x00018a7aa0227bbe,0x0005e68cc1ea5f8b,0x0006fe3e3a7a1d5f,0x00031ad97ad26e2a},{0x00014769dd701ab6,0x00028339f1b4b667,0x0004ab214b8ae37b,0x00025f0aefa0b0fe,0x0007ae2ca8a017d2},{0x000017ed0920b962,0x000187e33b53b6fd,0x00055829907a1463,0x000641f248e0a792,0x0001ed1fc53a6622}} -}; diff --git a/ed25519-donna/ed25519-donna-64bit-x86-32bit.h b/ed25519-donna/ed25519-donna-64bit-x86-32bit.h deleted file mode 100644 index 1ce109c5b..000000000 --- a/ed25519-donna/ed25519-donna-64bit-x86-32bit.h +++ /dev/null @@ -1,435 +0,0 @@ -#if defined(ED25519_GCC_64BIT_32BIT_CHOOSE) - -#define HAVE_GE25519_SCALARMULT_BASE_CHOOSE_NIELS - -DONNA_NOINLINE static void -ge25519_scalarmult_base_choose_niels(ge25519_niels *t, const uint8_t table[256][96], uint32_t pos, signed char b) { - int64_t breg = (int64_t)b; - uint64_t sign = (uint64_t)breg >> 63; - uint64_t mask = ~(sign - 1); - uint64_t u = (breg + mask) ^ mask; - - __asm__ __volatile__ ( - /* ysubx+xaddy+t2d */ - "movq %0, %%rax ;\n" - "movd %%rax, %%xmm14 ;\n" - "pshufd $0x00, %%xmm14, %%xmm14 ;\n" - "pxor %%xmm0, %%xmm0 ;\n" - "pxor %%xmm1, %%xmm1 ;\n" - "pxor %%xmm2, %%xmm2 ;\n" - "pxor %%xmm3, %%xmm3 ;\n" - "pxor %%xmm4, %%xmm4 ;\n" - "pxor %%xmm5, %%xmm5 ;\n" - - /* 0 */ - "movq $0, %%rax ;\n" - "movd %%rax, %%xmm15 ;\n" - "pshufd $0x00, %%xmm15, %%xmm15 ;\n" - "pcmpeqd %%xmm14, %%xmm15 ;\n" - "movq $1, %%rax ;\n" - "movd %%rax, %%xmm6 ;\n" - "pxor %%xmm7, %%xmm7 ;\n" - "pand %%xmm15, %%xmm6 ;\n" - "pand %%xmm15, %%xmm7 ;\n" - "por %%xmm6, %%xmm0 ;\n" - "por %%xmm7, %%xmm1 ;\n" - "por %%xmm6, %%xmm2 ;\n" - "por %%xmm7, %%xmm3 ;\n" - - /* 1 */ - "movq $1, %%rax ;\n" - "movd %%rax, %%xmm15 ;\n" - "pshufd $0x00, %%xmm15, %%xmm15 ;\n" - "pcmpeqd %%xmm14, %%xmm15 ;\n" - "movdqa 0(%1), %%xmm6 ;\n" - "movdqa 16(%1), %%xmm7 ;\n" - "movdqa 32(%1), %%xmm8 ;\n" - "movdqa 48(%1), %%xmm9 ;\n" - "movdqa 64(%1), %%xmm10 ;\n" - "movdqa 80(%1), %%xmm11 ;\n" - "pand %%xmm15, %%xmm6 ;\n" - "pand %%xmm15, %%xmm7 ;\n" - "pand %%xmm15, %%xmm8 ;\n" - "pand %%xmm15, %%xmm9 ;\n" - "pand %%xmm15, %%xmm10 ;\n" - "pand %%xmm15, %%xmm11 ;\n" - "por %%xmm6, %%xmm0 ;\n" - "por %%xmm7, %%xmm1 ;\n" - "por %%xmm8, %%xmm2 ;\n" - "por %%xmm9, %%xmm3 ;\n" - "por %%xmm10, %%xmm4 ;\n" - "por %%xmm11, %%xmm5 ;\n" - - /* 2 */ - "movq $2, %%rax ;\n" - "movd %%rax, %%xmm15 ;\n" - "pshufd $0x00, %%xmm15, %%xmm15 ;\n" - "pcmpeqd %%xmm14, %%xmm15 ;\n" - "movdqa 96(%1), %%xmm6 ;\n" - "movdqa 112(%1), %%xmm7 ;\n" - "movdqa 128(%1), %%xmm8 ;\n" - "movdqa 144(%1), %%xmm9 ;\n" - "movdqa 160(%1), %%xmm10 ;\n" - "movdqa 176(%1), %%xmm11 ;\n" - "pand %%xmm15, %%xmm6 ;\n" - "pand %%xmm15, %%xmm7 ;\n" - "pand %%xmm15, %%xmm8 ;\n" - "pand %%xmm15, %%xmm9 ;\n" - "pand %%xmm15, %%xmm10 ;\n" - "pand %%xmm15, %%xmm11 ;\n" - "por %%xmm6, %%xmm0 ;\n" - "por %%xmm7, %%xmm1 ;\n" - "por %%xmm8, %%xmm2 ;\n" - "por %%xmm9, %%xmm3 ;\n" - "por %%xmm10, %%xmm4 ;\n" - "por %%xmm11, %%xmm5 ;\n" - - /* 3 */ - "movq $3, %%rax ;\n" - "movd %%rax, %%xmm15 ;\n" - "pshufd $0x00, %%xmm15, %%xmm15 ;\n" - "pcmpeqd %%xmm14, %%xmm15 ;\n" - "movdqa 192(%1), %%xmm6 ;\n" - "movdqa 208(%1), %%xmm7 ;\n" - "movdqa 224(%1), %%xmm8 ;\n" - "movdqa 240(%1), %%xmm9 ;\n" - "movdqa 256(%1), %%xmm10 ;\n" - "movdqa 272(%1), %%xmm11 ;\n" - "pand %%xmm15, %%xmm6 ;\n" - "pand %%xmm15, %%xmm7 ;\n" - "pand %%xmm15, %%xmm8 ;\n" - "pand %%xmm15, %%xmm9 ;\n" - "pand %%xmm15, %%xmm10 ;\n" - "pand %%xmm15, %%xmm11 ;\n" - "por %%xmm6, %%xmm0 ;\n" - "por %%xmm7, %%xmm1 ;\n" - "por %%xmm8, %%xmm2 ;\n" - "por %%xmm9, %%xmm3 ;\n" - "por %%xmm10, %%xmm4 ;\n" - "por %%xmm11, %%xmm5 ;\n" - - /* 4 */ - "movq $4, %%rax ;\n" - "movd %%rax, %%xmm15 ;\n" - "pshufd $0x00, %%xmm15, %%xmm15 ;\n" - "pcmpeqd %%xmm14, %%xmm15 ;\n" - "movdqa 288(%1), %%xmm6 ;\n" - "movdqa 304(%1), %%xmm7 ;\n" - "movdqa 320(%1), %%xmm8 ;\n" - "movdqa 336(%1), %%xmm9 ;\n" - "movdqa 352(%1), %%xmm10 ;\n" - "movdqa 368(%1), %%xmm11 ;\n" - "pand %%xmm15, %%xmm6 ;\n" - "pand %%xmm15, %%xmm7 ;\n" - "pand %%xmm15, %%xmm8 ;\n" - "pand %%xmm15, %%xmm9 ;\n" - "pand %%xmm15, %%xmm10 ;\n" - "pand %%xmm15, %%xmm11 ;\n" - "por %%xmm6, %%xmm0 ;\n" - "por %%xmm7, %%xmm1 ;\n" - "por %%xmm8, %%xmm2 ;\n" - "por %%xmm9, %%xmm3 ;\n" - "por %%xmm10, %%xmm4 ;\n" - "por %%xmm11, %%xmm5 ;\n" - - /* 5 */ - "movq $5, %%rax ;\n" - "movd %%rax, %%xmm15 ;\n" - "pshufd $0x00, %%xmm15, %%xmm15 ;\n" - "pcmpeqd %%xmm14, %%xmm15 ;\n" - "movdqa 384(%1), %%xmm6 ;\n" - "movdqa 400(%1), %%xmm7 ;\n" - "movdqa 416(%1), %%xmm8 ;\n" - "movdqa 432(%1), %%xmm9 ;\n" - "movdqa 448(%1), %%xmm10 ;\n" - "movdqa 464(%1), %%xmm11 ;\n" - "pand %%xmm15, %%xmm6 ;\n" - "pand %%xmm15, %%xmm7 ;\n" - "pand %%xmm15, %%xmm8 ;\n" - "pand %%xmm15, %%xmm9 ;\n" - "pand %%xmm15, %%xmm10 ;\n" - "pand %%xmm15, %%xmm11 ;\n" - "por %%xmm6, %%xmm0 ;\n" - "por %%xmm7, %%xmm1 ;\n" - "por %%xmm8, %%xmm2 ;\n" - "por %%xmm9, %%xmm3 ;\n" - "por %%xmm10, %%xmm4 ;\n" - "por %%xmm11, %%xmm5 ;\n" - - /* 6 */ - "movq $6, %%rax ;\n" - "movd %%rax, %%xmm15 ;\n" - "pshufd $0x00, %%xmm15, %%xmm15 ;\n" - "pcmpeqd %%xmm14, %%xmm15 ;\n" - "movdqa 480(%1), %%xmm6 ;\n" - "movdqa 496(%1), %%xmm7 ;\n" - "movdqa 512(%1), %%xmm8 ;\n" - "movdqa 528(%1), %%xmm9 ;\n" - "movdqa 544(%1), %%xmm10 ;\n" - "movdqa 560(%1), %%xmm11 ;\n" - "pand %%xmm15, %%xmm6 ;\n" - "pand %%xmm15, %%xmm7 ;\n" - "pand %%xmm15, %%xmm8 ;\n" - "pand %%xmm15, %%xmm9 ;\n" - "pand %%xmm15, %%xmm10 ;\n" - "pand %%xmm15, %%xmm11 ;\n" - "por %%xmm6, %%xmm0 ;\n" - "por %%xmm7, %%xmm1 ;\n" - "por %%xmm8, %%xmm2 ;\n" - "por %%xmm9, %%xmm3 ;\n" - "por %%xmm10, %%xmm4 ;\n" - "por %%xmm11, %%xmm5 ;\n" - - /* 7 */ - "movq $7, %%rax ;\n" - "movd %%rax, %%xmm15 ;\n" - "pshufd $0x00, %%xmm15, %%xmm15 ;\n" - "pcmpeqd %%xmm14, %%xmm15 ;\n" - "movdqa 576(%1), %%xmm6 ;\n" - "movdqa 592(%1), %%xmm7 ;\n" - "movdqa 608(%1), %%xmm8 ;\n" - "movdqa 624(%1), %%xmm9 ;\n" - "movdqa 640(%1), %%xmm10 ;\n" - "movdqa 656(%1), %%xmm11 ;\n" - "pand %%xmm15, %%xmm6 ;\n" - "pand %%xmm15, %%xmm7 ;\n" - "pand %%xmm15, %%xmm8 ;\n" - "pand %%xmm15, %%xmm9 ;\n" - "pand %%xmm15, %%xmm10 ;\n" - "pand %%xmm15, %%xmm11 ;\n" - "por %%xmm6, %%xmm0 ;\n" - "por %%xmm7, %%xmm1 ;\n" - "por %%xmm8, %%xmm2 ;\n" - "por %%xmm9, %%xmm3 ;\n" - "por %%xmm10, %%xmm4 ;\n" - "por %%xmm11, %%xmm5 ;\n" - - /* 8 */ - "movq $8, %%rax ;\n" - "movd %%rax, %%xmm15 ;\n" - "pshufd $0x00, %%xmm15, %%xmm15 ;\n" - "pcmpeqd %%xmm14, %%xmm15 ;\n" - "movdqa 672(%1), %%xmm6 ;\n" - "movdqa 688(%1), %%xmm7 ;\n" - "movdqa 704(%1), %%xmm8 ;\n" - "movdqa 720(%1), %%xmm9 ;\n" - "movdqa 736(%1), %%xmm10 ;\n" - "movdqa 752(%1), %%xmm11 ;\n" - "pand %%xmm15, %%xmm6 ;\n" - "pand %%xmm15, %%xmm7 ;\n" - "pand %%xmm15, %%xmm8 ;\n" - "pand %%xmm15, %%xmm9 ;\n" - "pand %%xmm15, %%xmm10 ;\n" - "pand %%xmm15, %%xmm11 ;\n" - "por %%xmm6, %%xmm0 ;\n" - "por %%xmm7, %%xmm1 ;\n" - "por %%xmm8, %%xmm2 ;\n" - "por %%xmm9, %%xmm3 ;\n" - "por %%xmm10, %%xmm4 ;\n" - "por %%xmm11, %%xmm5 ;\n" - - /* conditionally swap ysubx and xaddy */ - "movq %3, %%rax ;\n" - "xorq $1, %%rax ;\n" - "movd %%rax, %%xmm14 ;\n" - "pxor %%xmm15, %%xmm15 ;\n" - "pshufd $0x00, %%xmm14, %%xmm14 ;\n" - "pxor %%xmm0, %%xmm2 ;\n" - "pxor %%xmm1, %%xmm3 ;\n" - "pcmpeqd %%xmm14, %%xmm15 ;\n" - "movdqa %%xmm2, %%xmm6 ;\n" - "movdqa %%xmm3, %%xmm7 ;\n" - "pand %%xmm15, %%xmm6 ;\n" - "pand %%xmm15, %%xmm7 ;\n" - "pxor %%xmm6, %%xmm0 ;\n" - "pxor %%xmm7, %%xmm1 ;\n" - "pxor %%xmm0, %%xmm2 ;\n" - "pxor %%xmm1, %%xmm3 ;\n" - - /* store ysubx */ - "xorq %%rax, %%rax ;\n" - "movd %%xmm0, %%rcx ;\n" - "movd %%xmm0, %%r8 ;\n" - "movd %%xmm1, %%rsi ;\n" - "pshufd $0xee, %%xmm0, %%xmm0 ;\n" - "pshufd $0xee, %%xmm1, %%xmm1 ;\n" - "movd %%xmm0, %%rdx ;\n" - "movd %%xmm1, %%rdi ;\n" - "shrdq $51, %%rdx, %%r8 ;\n" - "shrdq $38, %%rsi, %%rdx ;\n" - "shrdq $25, %%rdi, %%rsi ;\n" - "shrq $12, %%rdi ;\n" - "movq %%rcx, %%r9 ;\n" - "movq %%r8, %%r10 ;\n" - "movq %%rdx, %%r11 ;\n" - "movq %%rsi, %%r12 ;\n" - "movq %%rdi, %%r13 ;\n" - "shrq $26, %%r9 ;\n" - "shrq $26, %%r10 ;\n" - "shrq $26, %%r11 ;\n" - "shrq $26, %%r12 ;\n" - "shrq $26, %%r13 ;\n" - "andl $0x3ffffff, %%ecx ;\n" - "andl $0x1ffffff, %%r9d ;\n" - "andl $0x3ffffff, %%r8d ;\n" - "andl $0x1ffffff, %%r10d ;\n" - "andl $0x3ffffff, %%edx ;\n" - "andl $0x1ffffff, %%r11d ;\n" - "andl $0x3ffffff, %%esi ;\n" - "andl $0x1ffffff, %%r12d ;\n" - "andl $0x3ffffff, %%edi ;\n" - "andl $0x1ffffff, %%r13d ;\n" - "movl %%ecx, 0(%2) ;\n" - "movl %%r9d, 4(%2) ;\n" - "movl %%r8d, 8(%2) ;\n" - "movl %%r10d, 12(%2) ;\n" - "movl %%edx, 16(%2) ;\n" - "movl %%r11d, 20(%2) ;\n" - "movl %%esi, 24(%2) ;\n" - "movl %%r12d, 28(%2) ;\n" - "movl %%edi, 32(%2) ;\n" - "movl %%r13d, 36(%2) ;\n" - - /* store xaddy */ - "movd %%xmm2, %%rcx ;\n" - "movd %%xmm2, %%r8 ;\n" - "movd %%xmm3, %%rsi ;\n" - "pshufd $0xee, %%xmm2, %%xmm2 ;\n" - "pshufd $0xee, %%xmm3, %%xmm3 ;\n" - "movd %%xmm2, %%rdx ;\n" - "movd %%xmm3, %%rdi ;\n" - "shrdq $51, %%rdx, %%r8 ;\n" - "shrdq $38, %%rsi, %%rdx ;\n" - "shrdq $25, %%rdi, %%rsi ;\n" - "shrq $12, %%rdi ;\n" - "movq %%rcx, %%r9 ;\n" - "movq %%r8, %%r10 ;\n" - "movq %%rdx, %%r11 ;\n" - "movq %%rsi, %%r12 ;\n" - "movq %%rdi, %%r13 ;\n" - "shrq $26, %%r9 ;\n" - "shrq $26, %%r10 ;\n" - "shrq $26, %%r11 ;\n" - "shrq $26, %%r12 ;\n" - "shrq $26, %%r13 ;\n" - "andl $0x3ffffff, %%ecx ;\n" - "andl $0x1ffffff, %%r9d ;\n" - "andl $0x3ffffff, %%r8d ;\n" - "andl $0x1ffffff, %%r10d ;\n" - "andl $0x3ffffff, %%edx ;\n" - "andl $0x1ffffff, %%r11d ;\n" - "andl $0x3ffffff, %%esi ;\n" - "andl $0x1ffffff, %%r12d ;\n" - "andl $0x3ffffff, %%edi ;\n" - "andl $0x1ffffff, %%r13d ;\n" - "movl %%ecx, 40(%2) ;\n" - "movl %%r9d, 44(%2) ;\n" - "movl %%r8d, 48(%2) ;\n" - "movl %%r10d, 52(%2) ;\n" - "movl %%edx, 56(%2) ;\n" - "movl %%r11d, 60(%2) ;\n" - "movl %%esi, 64(%2) ;\n" - "movl %%r12d, 68(%2) ;\n" - "movl %%edi, 72(%2) ;\n" - "movl %%r13d, 76(%2) ;\n" - - /* extract t2d */ - "xorq %%rax, %%rax ;\n" - "movd %%xmm4, %%rcx ;\n" - "movd %%xmm4, %%r8 ;\n" - "movd %%xmm5, %%rsi ;\n" - "pshufd $0xee, %%xmm4, %%xmm4 ;\n" - "pshufd $0xee, %%xmm5, %%xmm5 ;\n" - "movd %%xmm4, %%rdx ;\n" - "movd %%xmm5, %%rdi ;\n" - "shrdq $51, %%rdx, %%r8 ;\n" - "shrdq $38, %%rsi, %%rdx ;\n" - "shrdq $25, %%rdi, %%rsi ;\n" - "shrq $12, %%rdi ;\n" - "movq %%rcx, %%r9 ;\n" - "movq %%r8, %%r10 ;\n" - "movq %%rdx, %%r11 ;\n" - "movq %%rsi, %%r12 ;\n" - "movq %%rdi, %%r13 ;\n" - "shrq $26, %%r9 ;\n" - "shrq $26, %%r10 ;\n" - "shrq $26, %%r11 ;\n" - "shrq $26, %%r12 ;\n" - "shrq $26, %%r13 ;\n" - "andl $0x3ffffff, %%ecx ;\n" - "andl $0x1ffffff, %%r9d ;\n" - "andl $0x3ffffff, %%r8d ;\n" - "andl $0x1ffffff, %%r10d ;\n" - "andl $0x3ffffff, %%edx ;\n" - "andl $0x1ffffff, %%r11d ;\n" - "andl $0x3ffffff, %%esi ;\n" - "andl $0x1ffffff, %%r12d ;\n" - "andl $0x3ffffff, %%edi ;\n" - "andl $0x1ffffff, %%r13d ;\n" - "movd %%ecx, %%xmm0 ;\n" - "movd %%r9d, %%xmm4 ;\n" - "movd %%r8d, %%xmm8 ;\n" - "movd %%r10d, %%xmm3 ;\n" - "movd %%edx, %%xmm1 ;\n" - "movd %%r11d, %%xmm5 ;\n" - "movd %%esi, %%xmm6 ;\n" - "movd %%r12d, %%xmm7 ;\n" - "movd %%edi, %%xmm2 ;\n" - "movd %%r13d, %%xmm9 ;\n" - "punpckldq %%xmm4, %%xmm0 ;\n" - "punpckldq %%xmm3, %%xmm8 ;\n" - "punpckldq %%xmm5, %%xmm1 ;\n" - "punpckldq %%xmm7, %%xmm6 ;\n" - "punpckldq %%xmm9, %%xmm2 ;\n" - "punpcklqdq %%xmm8, %%xmm0 ;\n" - "punpcklqdq %%xmm6, %%xmm1 ;\n" - - /* set up 2p in to 3/4 */ - "movl $0x7ffffda, %%ecx ;\n" - "movl $0x3fffffe, %%edx ;\n" - "movl $0x7fffffe, %%eax ;\n" - "movd %%ecx, %%xmm3 ;\n" - "movd %%edx, %%xmm5 ;\n" - "movd %%eax, %%xmm4 ;\n" - "punpckldq %%xmm5, %%xmm3 ;\n" - "punpckldq %%xmm5, %%xmm4 ;\n" - "punpcklqdq %%xmm4, %%xmm3 ;\n" - "movdqa %%xmm4, %%xmm5 ;\n" - "punpcklqdq %%xmm4, %%xmm4 ;\n" - - /* subtract and conditionally move */ - "movl %3, %%ecx ;\n" - "sub $1, %%ecx ;\n" - "movd %%ecx, %%xmm6 ;\n" - "pshufd $0x00, %%xmm6, %%xmm6 ;\n" - "movdqa %%xmm6, %%xmm7 ;\n" - "psubd %%xmm0, %%xmm3 ;\n" - "psubd %%xmm1, %%xmm4 ;\n" - "psubd %%xmm2, %%xmm5 ;\n" - "pand %%xmm6, %%xmm0 ;\n" - "pand %%xmm6, %%xmm1 ;\n" - "pand %%xmm6, %%xmm2 ;\n" - "pandn %%xmm3, %%xmm6 ;\n" - "movdqa %%xmm7, %%xmm3 ;\n" - "pandn %%xmm4, %%xmm7 ;\n" - "pandn %%xmm5, %%xmm3 ;\n" - "por %%xmm6, %%xmm0 ;\n" - "por %%xmm7, %%xmm1 ;\n" - "por %%xmm3, %%xmm2 ;\n" - - /* store t2d */ - "movdqa %%xmm0, 80(%2) ;\n" - "movdqa %%xmm1, 96(%2) ;\n" - "movd %%xmm2, %%rax ;\n" - "movq %%rax, 112(%2) ;\n" - : - : "m"(u), "r"(&table[pos * 8]), "r"(t), "m"(sign) /* %0 = u, %1 = table, %2 = t, %3 = sign */ - : - "%rax", "%rcx", "%rdx", "%rdi", "%rsi", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", - "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "%xmm7", "%xmm8", "%xmm9", "%xmm10", "%xmm11", "%xmm14", "%xmm14", - "cc", "memory" - ); -} - -#endif /* defined(ED25519_GCC_64BIT_32BIT_CHOOSE) */ - diff --git a/ed25519-donna/ed25519-donna-64bit-x86.h b/ed25519-donna/ed25519-donna-64bit-x86.h deleted file mode 100644 index 30bd47276..000000000 --- a/ed25519-donna/ed25519-donna-64bit-x86.h +++ /dev/null @@ -1,351 +0,0 @@ -#if defined(ED25519_GCC_64BIT_X86_CHOOSE) - -#define HAVE_GE25519_SCALARMULT_BASE_CHOOSE_NIELS - -DONNA_NOINLINE static void -ge25519_scalarmult_base_choose_niels(ge25519_niels *t, const uint8_t table[256][96], uint32_t pos, signed char b) { - int64_t breg = (int64_t)b; - uint64_t sign = (uint64_t)breg >> 63; - uint64_t mask = ~(sign - 1); - uint64_t u = (breg + mask) ^ mask; - - __asm__ __volatile__ ( - /* ysubx+xaddy+t2d */ - "movq %0, %%rax ;\n" - "movd %%rax, %%xmm14 ;\n" - "pshufd $0x00, %%xmm14, %%xmm14 ;\n" - "pxor %%xmm0, %%xmm0 ;\n" - "pxor %%xmm1, %%xmm1 ;\n" - "pxor %%xmm2, %%xmm2 ;\n" - "pxor %%xmm3, %%xmm3 ;\n" - "pxor %%xmm4, %%xmm4 ;\n" - "pxor %%xmm5, %%xmm5 ;\n" - - /* 0 */ - "movq $0, %%rax ;\n" - "movd %%rax, %%xmm15 ;\n" - "pshufd $0x00, %%xmm15, %%xmm15 ;\n" - "pcmpeqd %%xmm14, %%xmm15 ;\n" - "movq $1, %%rax ;\n" - "movd %%rax, %%xmm6 ;\n" - "pxor %%xmm7, %%xmm7 ;\n" - "pand %%xmm15, %%xmm6 ;\n" - "pand %%xmm15, %%xmm7 ;\n" - "por %%xmm6, %%xmm0 ;\n" - "por %%xmm7, %%xmm1 ;\n" - "por %%xmm6, %%xmm2 ;\n" - "por %%xmm7, %%xmm3 ;\n" - - /* 1 */ - "movq $1, %%rax ;\n" - "movd %%rax, %%xmm15 ;\n" - "pshufd $0x00, %%xmm15, %%xmm15 ;\n" - "pcmpeqd %%xmm14, %%xmm15 ;\n" - "movdqa 0(%1), %%xmm6 ;\n" - "movdqa 16(%1), %%xmm7 ;\n" - "movdqa 32(%1), %%xmm8 ;\n" - "movdqa 48(%1), %%xmm9 ;\n" - "movdqa 64(%1), %%xmm10 ;\n" - "movdqa 80(%1), %%xmm11 ;\n" - "pand %%xmm15, %%xmm6 ;\n" - "pand %%xmm15, %%xmm7 ;\n" - "pand %%xmm15, %%xmm8 ;\n" - "pand %%xmm15, %%xmm9 ;\n" - "pand %%xmm15, %%xmm10 ;\n" - "pand %%xmm15, %%xmm11 ;\n" - "por %%xmm6, %%xmm0 ;\n" - "por %%xmm7, %%xmm1 ;\n" - "por %%xmm8, %%xmm2 ;\n" - "por %%xmm9, %%xmm3 ;\n" - "por %%xmm10, %%xmm4 ;\n" - "por %%xmm11, %%xmm5 ;\n" - - /* 2 */ - "movq $2, %%rax ;\n" - "movd %%rax, %%xmm15 ;\n" - "pshufd $0x00, %%xmm15, %%xmm15 ;\n" - "pcmpeqd %%xmm14, %%xmm15 ;\n" - "movdqa 96(%1), %%xmm6 ;\n" - "movdqa 112(%1), %%xmm7 ;\n" - "movdqa 128(%1), %%xmm8 ;\n" - "movdqa 144(%1), %%xmm9 ;\n" - "movdqa 160(%1), %%xmm10 ;\n" - "movdqa 176(%1), %%xmm11 ;\n" - "pand %%xmm15, %%xmm6 ;\n" - "pand %%xmm15, %%xmm7 ;\n" - "pand %%xmm15, %%xmm8 ;\n" - "pand %%xmm15, %%xmm9 ;\n" - "pand %%xmm15, %%xmm10 ;\n" - "pand %%xmm15, %%xmm11 ;\n" - "por %%xmm6, %%xmm0 ;\n" - "por %%xmm7, %%xmm1 ;\n" - "por %%xmm8, %%xmm2 ;\n" - "por %%xmm9, %%xmm3 ;\n" - "por %%xmm10, %%xmm4 ;\n" - "por %%xmm11, %%xmm5 ;\n" - - /* 3 */ - "movq $3, %%rax ;\n" - "movd %%rax, %%xmm15 ;\n" - "pshufd $0x00, %%xmm15, %%xmm15 ;\n" - "pcmpeqd %%xmm14, %%xmm15 ;\n" - "movdqa 192(%1), %%xmm6 ;\n" - "movdqa 208(%1), %%xmm7 ;\n" - "movdqa 224(%1), %%xmm8 ;\n" - "movdqa 240(%1), %%xmm9 ;\n" - "movdqa 256(%1), %%xmm10 ;\n" - "movdqa 272(%1), %%xmm11 ;\n" - "pand %%xmm15, %%xmm6 ;\n" - "pand %%xmm15, %%xmm7 ;\n" - "pand %%xmm15, %%xmm8 ;\n" - "pand %%xmm15, %%xmm9 ;\n" - "pand %%xmm15, %%xmm10 ;\n" - "pand %%xmm15, %%xmm11 ;\n" - "por %%xmm6, %%xmm0 ;\n" - "por %%xmm7, %%xmm1 ;\n" - "por %%xmm8, %%xmm2 ;\n" - "por %%xmm9, %%xmm3 ;\n" - "por %%xmm10, %%xmm4 ;\n" - "por %%xmm11, %%xmm5 ;\n" - - /* 4 */ - "movq $4, %%rax ;\n" - "movd %%rax, %%xmm15 ;\n" - "pshufd $0x00, %%xmm15, %%xmm15 ;\n" - "pcmpeqd %%xmm14, %%xmm15 ;\n" - "movdqa 288(%1), %%xmm6 ;\n" - "movdqa 304(%1), %%xmm7 ;\n" - "movdqa 320(%1), %%xmm8 ;\n" - "movdqa 336(%1), %%xmm9 ;\n" - "movdqa 352(%1), %%xmm10 ;\n" - "movdqa 368(%1), %%xmm11 ;\n" - "pand %%xmm15, %%xmm6 ;\n" - "pand %%xmm15, %%xmm7 ;\n" - "pand %%xmm15, %%xmm8 ;\n" - "pand %%xmm15, %%xmm9 ;\n" - "pand %%xmm15, %%xmm10 ;\n" - "pand %%xmm15, %%xmm11 ;\n" - "por %%xmm6, %%xmm0 ;\n" - "por %%xmm7, %%xmm1 ;\n" - "por %%xmm8, %%xmm2 ;\n" - "por %%xmm9, %%xmm3 ;\n" - "por %%xmm10, %%xmm4 ;\n" - "por %%xmm11, %%xmm5 ;\n" - - /* 5 */ - "movq $5, %%rax ;\n" - "movd %%rax, %%xmm15 ;\n" - "pshufd $0x00, %%xmm15, %%xmm15 ;\n" - "pcmpeqd %%xmm14, %%xmm15 ;\n" - "movdqa 384(%1), %%xmm6 ;\n" - "movdqa 400(%1), %%xmm7 ;\n" - "movdqa 416(%1), %%xmm8 ;\n" - "movdqa 432(%1), %%xmm9 ;\n" - "movdqa 448(%1), %%xmm10 ;\n" - "movdqa 464(%1), %%xmm11 ;\n" - "pand %%xmm15, %%xmm6 ;\n" - "pand %%xmm15, %%xmm7 ;\n" - "pand %%xmm15, %%xmm8 ;\n" - "pand %%xmm15, %%xmm9 ;\n" - "pand %%xmm15, %%xmm10 ;\n" - "pand %%xmm15, %%xmm11 ;\n" - "por %%xmm6, %%xmm0 ;\n" - "por %%xmm7, %%xmm1 ;\n" - "por %%xmm8, %%xmm2 ;\n" - "por %%xmm9, %%xmm3 ;\n" - "por %%xmm10, %%xmm4 ;\n" - "por %%xmm11, %%xmm5 ;\n" - - /* 6 */ - "movq $6, %%rax ;\n" - "movd %%rax, %%xmm15 ;\n" - "pshufd $0x00, %%xmm15, %%xmm15 ;\n" - "pcmpeqd %%xmm14, %%xmm15 ;\n" - "movdqa 480(%1), %%xmm6 ;\n" - "movdqa 496(%1), %%xmm7 ;\n" - "movdqa 512(%1), %%xmm8 ;\n" - "movdqa 528(%1), %%xmm9 ;\n" - "movdqa 544(%1), %%xmm10 ;\n" - "movdqa 560(%1), %%xmm11 ;\n" - "pand %%xmm15, %%xmm6 ;\n" - "pand %%xmm15, %%xmm7 ;\n" - "pand %%xmm15, %%xmm8 ;\n" - "pand %%xmm15, %%xmm9 ;\n" - "pand %%xmm15, %%xmm10 ;\n" - "pand %%xmm15, %%xmm11 ;\n" - "por %%xmm6, %%xmm0 ;\n" - "por %%xmm7, %%xmm1 ;\n" - "por %%xmm8, %%xmm2 ;\n" - "por %%xmm9, %%xmm3 ;\n" - "por %%xmm10, %%xmm4 ;\n" - "por %%xmm11, %%xmm5 ;\n" - - /* 7 */ - "movq $7, %%rax ;\n" - "movd %%rax, %%xmm15 ;\n" - "pshufd $0x00, %%xmm15, %%xmm15 ;\n" - "pcmpeqd %%xmm14, %%xmm15 ;\n" - "movdqa 576(%1), %%xmm6 ;\n" - "movdqa 592(%1), %%xmm7 ;\n" - "movdqa 608(%1), %%xmm8 ;\n" - "movdqa 624(%1), %%xmm9 ;\n" - "movdqa 640(%1), %%xmm10 ;\n" - "movdqa 656(%1), %%xmm11 ;\n" - "pand %%xmm15, %%xmm6 ;\n" - "pand %%xmm15, %%xmm7 ;\n" - "pand %%xmm15, %%xmm8 ;\n" - "pand %%xmm15, %%xmm9 ;\n" - "pand %%xmm15, %%xmm10 ;\n" - "pand %%xmm15, %%xmm11 ;\n" - "por %%xmm6, %%xmm0 ;\n" - "por %%xmm7, %%xmm1 ;\n" - "por %%xmm8, %%xmm2 ;\n" - "por %%xmm9, %%xmm3 ;\n" - "por %%xmm10, %%xmm4 ;\n" - "por %%xmm11, %%xmm5 ;\n" - - /* 8 */ - "movq $8, %%rax ;\n" - "movd %%rax, %%xmm15 ;\n" - "pshufd $0x00, %%xmm15, %%xmm15 ;\n" - "pcmpeqd %%xmm14, %%xmm15 ;\n" - "movdqa 672(%1), %%xmm6 ;\n" - "movdqa 688(%1), %%xmm7 ;\n" - "movdqa 704(%1), %%xmm8 ;\n" - "movdqa 720(%1), %%xmm9 ;\n" - "movdqa 736(%1), %%xmm10 ;\n" - "movdqa 752(%1), %%xmm11 ;\n" - "pand %%xmm15, %%xmm6 ;\n" - "pand %%xmm15, %%xmm7 ;\n" - "pand %%xmm15, %%xmm8 ;\n" - "pand %%xmm15, %%xmm9 ;\n" - "pand %%xmm15, %%xmm10 ;\n" - "pand %%xmm15, %%xmm11 ;\n" - "por %%xmm6, %%xmm0 ;\n" - "por %%xmm7, %%xmm1 ;\n" - "por %%xmm8, %%xmm2 ;\n" - "por %%xmm9, %%xmm3 ;\n" - "por %%xmm10, %%xmm4 ;\n" - "por %%xmm11, %%xmm5 ;\n" - - /* conditionally swap ysubx and xaddy */ - "movq %3, %%rax ;\n" - "xorq $1, %%rax ;\n" - "movd %%rax, %%xmm14 ;\n" - "pxor %%xmm15, %%xmm15 ;\n" - "pshufd $0x00, %%xmm14, %%xmm14 ;\n" - "pxor %%xmm0, %%xmm2 ;\n" - "pxor %%xmm1, %%xmm3 ;\n" - "pcmpeqd %%xmm14, %%xmm15 ;\n" - "movdqa %%xmm2, %%xmm6 ;\n" - "movdqa %%xmm3, %%xmm7 ;\n" - "pand %%xmm15, %%xmm6 ;\n" - "pand %%xmm15, %%xmm7 ;\n" - "pxor %%xmm6, %%xmm0 ;\n" - "pxor %%xmm7, %%xmm1 ;\n" - "pxor %%xmm0, %%xmm2 ;\n" - "pxor %%xmm1, %%xmm3 ;\n" - - /* store ysubx */ - "movq $0x7ffffffffffff, %%rax ;\n" - "movd %%xmm0, %%rcx ;\n" - "movd %%xmm0, %%r8 ;\n" - "movd %%xmm1, %%rsi ;\n" - "pshufd $0xee, %%xmm0, %%xmm0 ;\n" - "pshufd $0xee, %%xmm1, %%xmm1 ;\n" - "movd %%xmm0, %%rdx ;\n" - "movd %%xmm1, %%rdi ;\n" - "shrdq $51, %%rdx, %%r8 ;\n" - "shrdq $38, %%rsi, %%rdx ;\n" - "shrdq $25, %%rdi, %%rsi ;\n" - "shrq $12, %%rdi ;\n" - "andq %%rax, %%rcx ;\n" - "andq %%rax, %%r8 ;\n" - "andq %%rax, %%rdx ;\n" - "andq %%rax, %%rsi ;\n" - "andq %%rax, %%rdi ;\n" - "movq %%rcx, 0(%2) ;\n" - "movq %%r8, 8(%2) ;\n" - "movq %%rdx, 16(%2) ;\n" - "movq %%rsi, 24(%2) ;\n" - "movq %%rdi, 32(%2) ;\n" - - /* store xaddy */ - "movq $0x7ffffffffffff, %%rax ;\n" - "movd %%xmm2, %%rcx ;\n" - "movd %%xmm2, %%r8 ;\n" - "movd %%xmm3, %%rsi ;\n" - "pshufd $0xee, %%xmm2, %%xmm2 ;\n" - "pshufd $0xee, %%xmm3, %%xmm3 ;\n" - "movd %%xmm2, %%rdx ;\n" - "movd %%xmm3, %%rdi ;\n" - "shrdq $51, %%rdx, %%r8 ;\n" - "shrdq $38, %%rsi, %%rdx ;\n" - "shrdq $25, %%rdi, %%rsi ;\n" - "shrq $12, %%rdi ;\n" - "andq %%rax, %%rcx ;\n" - "andq %%rax, %%r8 ;\n" - "andq %%rax, %%rdx ;\n" - "andq %%rax, %%rsi ;\n" - "andq %%rax, %%rdi ;\n" - "movq %%rcx, 40(%2) ;\n" - "movq %%r8, 48(%2) ;\n" - "movq %%rdx, 56(%2) ;\n" - "movq %%rsi, 64(%2) ;\n" - "movq %%rdi, 72(%2) ;\n" - - /* extract t2d */ - "movq $0x7ffffffffffff, %%rax ;\n" - "movd %%xmm4, %%rcx ;\n" - "movd %%xmm4, %%r8 ;\n" - "movd %%xmm5, %%rsi ;\n" - "pshufd $0xee, %%xmm4, %%xmm4 ;\n" - "pshufd $0xee, %%xmm5, %%xmm5 ;\n" - "movd %%xmm4, %%rdx ;\n" - "movd %%xmm5, %%rdi ;\n" - "shrdq $51, %%rdx, %%r8 ;\n" - "shrdq $38, %%rsi, %%rdx ;\n" - "shrdq $25, %%rdi, %%rsi ;\n" - "shrq $12, %%rdi ;\n" - "andq %%rax, %%rcx ;\n" - "andq %%rax, %%r8 ;\n" - "andq %%rax, %%rdx ;\n" - "andq %%rax, %%rsi ;\n" - "andq %%rax, %%rdi ;\n" - - /* conditionally negate t2d */ - "movq %3, %%rax ;\n" - "movq $0xfffffffffffda, %%r9 ;\n" - "movq $0xffffffffffffe, %%r10 ;\n" - "movq %%r10, %%r11 ;\n" - "movq %%r10, %%r12 ;\n" - "movq %%r10, %%r13 ;\n" - "subq %%rcx, %%r9 ;\n" - "subq %%r8, %%r10 ;\n" - "subq %%rdx, %%r11 ;\n" - "subq %%rsi, %%r12 ;\n" - "subq %%rdi, %%r13 ;\n" - "cmpq $1, %%rax ;\n" - "cmove %%r9, %%rcx ;\n" - "cmove %%r10, %%r8 ;\n" - "cmove %%r11, %%rdx ;\n" - "cmove %%r12, %%rsi ;\n" - "cmove %%r13, %%rdi ;\n" - - /* store t2d */ - "movq %%rcx, 80(%2) ;\n" - "movq %%r8, 88(%2) ;\n" - "movq %%rdx, 96(%2) ;\n" - "movq %%rsi, 104(%2) ;\n" - "movq %%rdi, 112(%2) ;\n" - : - : "m"(u), "r"(&table[pos * 8]), "r"(t), "m"(sign) /* %0 = u, %1 = table, %2 = t, %3 = sign */ - : - "%rax", "%rcx", "%rdx", "%rdi", "%rsi", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", - "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "%xmm7", "%xmm8", "%xmm9", "%xmm10", "%xmm11", "%xmm14", "%xmm14", - "cc", "memory" - ); -} - -#endif /* defined(ED25519_GCC_64BIT_X86_CHOOSE) */ - diff --git a/ed25519-donna/ed25519-donna-batchverify.h b/ed25519-donna/ed25519-donna-batchverify.h deleted file mode 100644 index 43c4923b3..000000000 --- a/ed25519-donna/ed25519-donna-batchverify.h +++ /dev/null @@ -1,275 +0,0 @@ -/* - Ed25519 batch verification -*/ - -#define max_batch_size 64 -#define heap_batch_size ((max_batch_size * 2) + 1) - -/* which limb is the 128th bit in? */ -static const size_t limb128bits = (128 + bignum256modm_bits_per_limb - 1) / bignum256modm_bits_per_limb; - -typedef size_t heap_index_t; - -typedef struct batch_heap_t { - unsigned char r[heap_batch_size][16]; /* 128 bit random values */ - ge25519 points[heap_batch_size]; - bignum256modm scalars[heap_batch_size]; - heap_index_t heap[heap_batch_size]; - size_t size; -} batch_heap; - -/* swap two values in the heap */ -static void -heap_swap(heap_index_t *heap, size_t a, size_t b) { - heap_index_t temp; - temp = heap[a]; - heap[a] = heap[b]; - heap[b] = temp; -} - -/* add the scalar at the end of the list to the heap */ -static void -heap_insert_next(batch_heap *heap) { - size_t node = heap->size, parent; - heap_index_t *pheap = heap->heap; - bignum256modm *scalars = heap->scalars; - - /* insert at the bottom */ - pheap[node] = (heap_index_t)node; - - /* sift node up to its sorted spot */ - parent = (node - 1) / 2; - while (node && lt256_modm_batch(scalars[pheap[parent]], scalars[pheap[node]], bignum256modm_limb_size - 1)) { - heap_swap(pheap, parent, node); - node = parent; - parent = (node - 1) / 2; - } - heap->size++; -} - -/* update the heap when the root element is updated */ -static void -heap_updated_root(batch_heap *heap, size_t limbsize) { - size_t node, parent, childr, childl; - heap_index_t *pheap = heap->heap; - bignum256modm *scalars = heap->scalars; - - /* sift root to the bottom */ - parent = 0; - node = 1; - childl = 1; - childr = 2; - while ((childr < heap->size)) { - node = lt256_modm_batch(scalars[pheap[childl]], scalars[pheap[childr]], limbsize) ? childr : childl; - heap_swap(pheap, parent, node); - parent = node; - childl = (parent * 2) + 1; - childr = childl + 1; - } - - /* sift root back up to its sorted spot */ - parent = (node - 1) / 2; - while (node && lte256_modm_batch(scalars[pheap[parent]], scalars[pheap[node]], limbsize)) { - heap_swap(pheap, parent, node); - node = parent; - parent = (node - 1) / 2; - } -} - -/* build the heap with count elements, count must be >= 3 */ -static void -heap_build(batch_heap *heap, size_t count) { - heap->heap[0] = 0; - heap->size = 0; - while (heap->size < count) - heap_insert_next(heap); -} - -/* extend the heap to contain new_count elements */ -static void -heap_extend(batch_heap *heap, size_t new_count) { - while (heap->size < new_count) - heap_insert_next(heap); -} - -/* get the top 2 elements of the heap */ -static void -heap_get_top2(batch_heap *heap, heap_index_t *max1, heap_index_t *max2, size_t limbsize) { - heap_index_t h0 = heap->heap[0], h1 = heap->heap[1], h2 = heap->heap[2]; - if (lt256_modm_batch(heap->scalars[h1], heap->scalars[h2], limbsize)) - h1 = h2; - *max1 = h0; - *max2 = h1; -} - -/* */ -static void -ge25519_multi_scalarmult_vartime_final(ge25519 *r, ge25519 *point, bignum256modm scalar) { - const bignum256modm_element_t topbit = ((bignum256modm_element_t)1 << (bignum256modm_bits_per_limb - 1)); - size_t limb = limb128bits; - bignum256modm_element_t flag; - - if (isone256_modm_batch(scalar)) { - /* this will happen most of the time after bos-carter */ - *r = *point; - return; - } else if (iszero256_modm_batch(scalar)) { - /* this will only happen if all scalars == 0 */ - memset(r, 0, sizeof(*r)); - r->y[0] = 1; - r->z[0] = 1; - return; - } - - *r = *point; - - /* find the limb where first bit is set */ - while (!scalar[limb]) - limb--; - - /* find the first bit */ - flag = topbit; - while ((scalar[limb] & flag) == 0) - flag >>= 1; - - /* exponentiate */ - for (;;) { - ge25519_double(r, r); - if (scalar[limb] & flag) - ge25519_add(r, r, point); - - flag >>= 1; - if (!flag) { - if (!limb--) - break; - flag = topbit; - } - } -} - -/* count must be >= 5 */ -static void -ge25519_multi_scalarmult_vartime(ge25519 *r, batch_heap *heap, size_t count) { - heap_index_t max1, max2; - - /* start with the full limb size */ - size_t limbsize = bignum256modm_limb_size - 1; - - /* whether the heap has been extended to include the 128 bit scalars */ - int extended = 0; - - /* grab an odd number of scalars to build the heap, unknown limb sizes */ - heap_build(heap, ((count + 1) / 2) | 1); - - for (;;) { - heap_get_top2(heap, &max1, &max2, limbsize); - - /* only one scalar remaining, we're done */ - if (iszero256_modm_batch(heap->scalars[max2])) - break; - - /* exhausted another limb? */ - if (!heap->scalars[max1][limbsize]) - limbsize -= 1; - - /* can we extend to the 128 bit scalars? */ - if (!extended && isatmost128bits256_modm_batch(heap->scalars[max1])) { - heap_extend(heap, count); - heap_get_top2(heap, &max1, &max2, limbsize); - extended = 1; - } - - sub256_modm_batch(heap->scalars[max1], heap->scalars[max1], heap->scalars[max2], limbsize); - ge25519_add(&heap->points[max2], &heap->points[max2], &heap->points[max1]); - heap_updated_root(heap, limbsize); - } - - ge25519_multi_scalarmult_vartime_final(r, &heap->points[max1], heap->scalars[max1]); -} - -/* not actually used for anything other than testing */ -unsigned char batch_point_buffer[3][32]; - -static int -ge25519_is_neutral_vartime(const ge25519 *p) { - static const unsigned char zero[32] = {0}; - unsigned char point_buffer[3][32]; - curve25519_contract(point_buffer[0], p->x); - curve25519_contract(point_buffer[1], p->y); - curve25519_contract(point_buffer[2], p->z); - memcpy(batch_point_buffer[1], point_buffer[1], 32); - return (memcmp(point_buffer[0], zero, 32) == 0) && (memcmp(point_buffer[1], point_buffer[2], 32) == 0); -} - -int -ED25519_FN(ed25519_sign_open_batch) (const unsigned char **m, size_t *mlen, const unsigned char **pk, const unsigned char **RS, size_t num, int *valid) { - batch_heap ALIGN(16) batch; - ge25519 ALIGN(16) p; - bignum256modm *r_scalars; - size_t i, batchsize; - unsigned char hram[64]; - int ret = 0; - - for (i = 0; i < num; i++) - valid[i] = 1; - - while (num > 3) { - batchsize = (num > max_batch_size) ? max_batch_size : num; - - /* generate r (scalars[batchsize+1]..scalars[2*batchsize] */ - ED25519_FN(ed25519_randombytes_unsafe) (batch.r, batchsize * 16); - r_scalars = &batch.scalars[batchsize + 1]; - for (i = 0; i < batchsize; i++) - expand256_modm(r_scalars[i], batch.r[i], 16); - - /* compute scalars[0] = ((r1s1 + r2s2 + ...)) */ - for (i = 0; i < batchsize; i++) { - expand256_modm(batch.scalars[i], RS[i] + 32, 32); - mul256_modm(batch.scalars[i], batch.scalars[i], r_scalars[i]); - } - for (i = 1; i < batchsize; i++) - add256_modm(batch.scalars[0], batch.scalars[0], batch.scalars[i]); - - /* compute scalars[1]..scalars[batchsize] as r[i]*H(R[i],A[i],m[i]) */ - for (i = 0; i < batchsize; i++) { - ed25519_hram(hram, RS[i], pk[i], m[i], mlen[i]); - expand256_modm(batch.scalars[i+1], hram, 64); - mul256_modm(batch.scalars[i+1], batch.scalars[i+1], r_scalars[i]); - } - - /* compute points */ - batch.points[0] = ge25519_basepoint; - for (i = 0; i < batchsize; i++) - if (!ge25519_unpack_negative_vartime(&batch.points[i+1], pk[i])) - goto fallback; - for (i = 0; i < batchsize; i++) - if (!ge25519_unpack_negative_vartime(&batch.points[batchsize+i+1], RS[i])) - goto fallback; - - ge25519_multi_scalarmult_vartime(&p, &batch, (batchsize * 2) + 1); - if (!ge25519_is_neutral_vartime(&p)) { - ret |= 2; - - fallback: - for (i = 0; i < batchsize; i++) { - valid[i] = ED25519_FN(ed25519_sign_open) (m[i], mlen[i], pk[i], RS[i]) ? 0 : 1; - ret |= (valid[i] ^ 1); - } - } - - m += batchsize; - mlen += batchsize; - pk += batchsize; - RS += batchsize; - num -= batchsize; - valid += batchsize; - } - - for (i = 0; i < num; i++) { - valid[i] = ED25519_FN(ed25519_sign_open) (m[i], mlen[i], pk[i], RS[i]) ? 0 : 1; - ret |= (valid[i] ^ 1); - } - - return ret; -} - diff --git a/ed25519-donna/ed25519-donna-impl-sse2.h b/ed25519-donna/ed25519-donna-impl-sse2.h deleted file mode 100644 index 67fd8f495..000000000 --- a/ed25519-donna/ed25519-donna-impl-sse2.h +++ /dev/null @@ -1,519 +0,0 @@ -/* - conversions -*/ - -static void -ge25519_p1p1_to_partial(ge25519 *r, const ge25519_p1p1 *p) { - packed64bignum25519 ALIGN(16) xz, tt, xzout; - curve25519_mul(r->y, p->y, p->z); - curve25519_tangle64(xz, p->x, p->z); - curve25519_tangleone64(tt, p->t); - curve25519_mul_packed64(xzout, xz, tt); - curve25519_untangle64(r->x, r->z, xzout); -} - -static void -ge25519_p1p1_to_full(ge25519 *r, const ge25519_p1p1 *p) { - packed64bignum25519 ALIGN(16) zy, xt, xx, zz, ty; - curve25519_tangle64(ty, p->t, p->y); - curve25519_tangleone64(xx, p->x); - curve25519_mul_packed64(xt, xx, ty); - curve25519_untangle64(r->x, r->t, xt); - curve25519_tangleone64(zz, p->z); - curve25519_mul_packed64(zy, zz, ty); - curve25519_untangle64(r->z, r->y, zy); -} - -static void -ge25519_full_to_pniels(ge25519_pniels *p, const ge25519 *r) { - curve25519_sub(p->ysubx, r->y, r->x); - curve25519_add(p->xaddy, r->x, r->y); - curve25519_copy(p->z, r->z); - curve25519_mul(p->t2d, r->t, ge25519_ec2d); -} - -/* - adding & doubling -*/ - -static void -ge25519_add_p1p1(ge25519_p1p1 *r, const ge25519 *p, const ge25519 *q) { - bignum25519 ALIGN(16) a,b,c,d; - packed32bignum25519 ALIGN(16) xx, yy, yypxx, yymxx, bd, ac, bdmac, bdpac; - packed64bignum25519 ALIGN(16) at, bu, atbu, ptz, qtz, cd; - - curve25519_tangle32(yy, p->y, q->y); - curve25519_tangle32(xx, p->x, q->x); - curve25519_add_packed32(yypxx, yy, xx); - curve25519_sub_packed32(yymxx, yy, xx); - curve25519_tangle64_from32(at, bu, yymxx, yypxx); - curve25519_mul_packed64(atbu, at, bu); - curve25519_untangle64(a, b, atbu); - curve25519_tangle64(ptz, p->t, p->z); - curve25519_tangle64(qtz, q->t, q->z); - curve25519_mul_packed64(cd, ptz, qtz); - curve25519_untangle64(c, d, cd); - curve25519_mul(c, c, ge25519_ec2d); - curve25519_add_reduce(d, d, d); - /* reduce, so no after_basic is needed later */ - curve25519_tangle32(bd, b, d); - curve25519_tangle32(ac, a, c); - curve25519_sub_packed32(bdmac, bd, ac); - curve25519_add_packed32(bdpac, bd, ac); - curve25519_untangle32(r->x, r->t, bdmac); - curve25519_untangle32(r->y, r->z, bdpac); -} - - -static void -ge25519_double_p1p1(ge25519_p1p1 *r, const ge25519 *p) { - bignum25519 ALIGN(16) a,b,c,x; - packed64bignum25519 ALIGN(16) xy, zx, ab, cx; - packed32bignum25519 ALIGN(16) xc, yz, xt, yc, ac, bc; - - curve25519_add(x, p->x, p->y); - curve25519_tangle64(xy, p->x, p->y); - curve25519_square_packed64(ab, xy); - curve25519_untangle64(a, b, ab); - curve25519_tangle64(zx, p->z, x); - curve25519_square_packed64(cx, zx); - curve25519_untangle64(c, x, cx); - curve25519_tangle32(bc, b, c); - curve25519_tangle32(ac, a, c); - curve25519_add_reduce_packed32(yc, bc, ac); - curve25519_untangle32(r->y, c, yc); - curve25519_sub(r->z, b, a); - curve25519_tangle32(yz, r->y, r->z); - curve25519_tangle32(xc, x, c); - curve25519_sub_after_basic_packed32(xt, xc, yz); - curve25519_untangle32(r->x, r->t, xt); -} - -static void -ge25519_nielsadd2_p1p1(ge25519_p1p1 *r, const ge25519 *p, const ge25519_niels *q, unsigned char signbit) { - const bignum25519 *qb = (const bignum25519 *)q; - bignum25519 *rb = (bignum25519 *)r; - bignum25519 ALIGN(16) a,b,c; - packed64bignum25519 ALIGN(16) ab, yx, aybx; - packed32bignum25519 ALIGN(16) bd, ac, bdac; - - curve25519_sub(a, p->y, p->x); - curve25519_add(b, p->y, p->x); - curve25519_tangle64(ab, a, b); - curve25519_tangle64(yx, qb[signbit], qb[signbit^1]); - curve25519_mul_packed64(aybx, ab, yx); - curve25519_untangle64(a, b, aybx); - curve25519_add(r->y, b, a); - curve25519_add_reduce(r->t, p->z, p->z); - curve25519_mul(c, p->t, q->t2d); - curve25519_copy(r->z, r->t); - curve25519_add(rb[2+signbit], rb[2+signbit], c); - curve25519_tangle32(bd, b, rb[2+(signbit^1)]); - curve25519_tangle32(ac, a, c); - curve25519_sub_packed32(bdac, bd, ac); - curve25519_untangle32(r->x, rb[2+(signbit^1)], bdac); -} - -static void -ge25519_pnielsadd_p1p1(ge25519_p1p1 *r, const ge25519 *p, const ge25519_pniels *q, unsigned char signbit) { - const bignum25519 *qb = (const bignum25519 *)q; - bignum25519 *rb = (bignum25519 *)r; - bignum25519 ALIGN(16) a,b,c; - packed64bignum25519 ALIGN(16) ab, yx, aybx, zt, zt2d, tc; - packed32bignum25519 ALIGN(16) bd, ac, bdac; - - curve25519_sub(a, p->y, p->x); - curve25519_add(b, p->y, p->x); - curve25519_tangle64(ab, a, b); - curve25519_tangle64(yx, qb[signbit], qb[signbit^1]); - curve25519_mul_packed64(aybx, ab, yx); - curve25519_untangle64(a, b, aybx); - curve25519_add(r->y, b, a); - curve25519_tangle64(zt, p->z, p->t); - curve25519_tangle64(zt2d, q->z, q->t2d); - curve25519_mul_packed64(tc, zt, zt2d); - curve25519_untangle64(r->t, c, tc); - curve25519_add_reduce(r->t, r->t, r->t); - curve25519_copy(r->z, r->t); - curve25519_add(rb[2+signbit], rb[2+signbit], c); - curve25519_tangle32(bd, b, rb[2+(signbit^1)]); - curve25519_tangle32(ac, a, c); - curve25519_sub_packed32(bdac, bd, ac); - curve25519_untangle32(r->x, rb[2+(signbit^1)], bdac); -} - -static void -ge25519_double(ge25519 *r, const ge25519 *p) { - ge25519_p1p1 ALIGN(16) t; - ge25519_double_p1p1(&t, p); - ge25519_p1p1_to_full(r, &t); -} - -STATIC void -ge25519_add(ge25519 *r, const ge25519 *p, const ge25519 *q) { - ge25519_p1p1 ALIGN(16) t; - ge25519_add_p1p1(&t, p, q); - ge25519_p1p1_to_full(r, &t); -} - -static void -ge25519_double_partial(ge25519 *r, const ge25519 *p) { - ge25519_p1p1 ALIGN(16) t; - ge25519_double_p1p1(&t, p); - ge25519_p1p1_to_partial(r, &t); -} - -static void -ge25519_nielsadd2(ge25519 *r, const ge25519_niels *q) { - packed64bignum25519 ALIGN(16) ab, yx, aybx, eg, ff, hh, xz, ty; - packed32bignum25519 ALIGN(16) bd, ac, bdac; - bignum25519 ALIGN(16) a,b,c,d,e,f,g,h; - - curve25519_sub(a, r->y, r->x); - curve25519_add(b, r->y, r->x); - curve25519_tangle64(ab, a, b); - curve25519_tangle64(yx, q->ysubx, q->xaddy); - curve25519_mul_packed64(aybx, ab, yx); - curve25519_untangle64(a, b, aybx); - curve25519_add(h, b, a); - curve25519_add_reduce(d, r->z, r->z); - curve25519_mul(c, r->t, q->t2d); - curve25519_add(g, d, c); /* d is reduced, so no need for after_basic */ - curve25519_tangle32(bd, b, d); - curve25519_tangle32(ac, a, c); - curve25519_sub_packed32(bdac, bd, ac); /* d is reduced, so no need for after_basic */ - curve25519_untangle32(e, f, bdac); - curve25519_tangle64(eg, e, g); - curve25519_tangleone64(ff, f); - curve25519_mul_packed64(xz, eg, ff); - curve25519_untangle64(r->x, r->z, xz); - curve25519_tangleone64(hh, h); - curve25519_mul_packed64(ty, eg, hh); - curve25519_untangle64(r->t, r->y, ty); -} - -static void -ge25519_pnielsadd(ge25519_pniels *r, const ge25519 *p, const ge25519_pniels *q) { - ge25519_p1p1 ALIGN(16) t; - ge25519 ALIGN(16) f; - ge25519_pnielsadd_p1p1(&t, p, q, 0); - ge25519_p1p1_to_full(&f, &t); - ge25519_full_to_pniels(r, &f); -} - -/* - pack & unpack -*/ - -STATIC void -ge25519_pack(unsigned char r[32], const ge25519 *p) { - bignum25519 ALIGN(16) tx, ty, zi; - unsigned char parity[32]; - curve25519_recip(zi, p->z); - curve25519_mul(tx, p->x, zi); - curve25519_mul(ty, p->y, zi); - curve25519_contract(r, ty); - curve25519_contract(parity, tx); - r[31] ^= ((parity[0] & 1) << 7); -} - - -STATIC int -ge25519_unpack_negative_vartime(ge25519 *r, const unsigned char p[32]) { - static const bignum25519 ALIGN(16) one = {1}; - static const unsigned char zero[32] = {0}; - unsigned char parity = p[31] >> 7; - unsigned char check[32]; - bignum25519 ALIGN(16) t, root, num, den, d3; - - curve25519_expand(r->y, p); - curve25519_copy(r->z, one); - curve25519_square_times(num, r->y, 1); /* x = y^2 */ - curve25519_mul(den, num, ge25519_ecd); /* den = dy^2 */ - curve25519_sub_reduce(num, num, r->z); /* x = y^2 - 1 */ - curve25519_add(den, den, r->z); /* den = dy^2 + 1 */ - - /* Computation of sqrt(num/den) */ - /* 1.: computation of num^((p-5)/8)*den^((7p-35)/8) = (num*den^7)^((p-5)/8) */ - curve25519_square_times(t, den, 1); - curve25519_mul(d3, t, den); - curve25519_square_times(r->x, d3, 1); - curve25519_mul(r->x, r->x, den); - curve25519_mul(r->x, r->x, num); - curve25519_pow_two252m3(r->x, r->x); - - /* 2. computation of r->x = t * num * den^3 */ - curve25519_mul(r->x, r->x, d3); - curve25519_mul(r->x, r->x, num); - - /* 3. Check if either of the roots works: */ - curve25519_square_times(t, r->x, 1); - curve25519_mul(t, t, den); - curve25519_copy(root, t); - curve25519_sub_reduce(root, root, num); - curve25519_contract(check, root); - if (!ed25519_verify(check, zero, 32)) { - curve25519_add_reduce(t, t, num); - curve25519_contract(check, t); - if (!ed25519_verify(check, zero, 32)) - return 0; - curve25519_mul(r->x, r->x, ge25519_sqrtneg1); - } - - curve25519_contract(check, r->x); - if ((check[0] & 1) == parity) { - curve25519_copy(t, r->x); - curve25519_neg(r->x, t); - } - curve25519_mul(r->t, r->x, r->y); - return 1; -} - - - -/* - scalarmults -*/ - -DONNA_INLINE static void ge25519_set_neutral(ge25519 *r) -{ - memset(r, 0, sizeof(ge25519)); - r->y[0] = 1; - r->z[0] = 1; -} - -#define S1_SWINDOWSIZE 5 -#define S1_TABLE_SIZE (1<<(S1_SWINDOWSIZE-2)) -#define S2_SWINDOWSIZE 7 -#define S2_TABLE_SIZE (1<<(S2_SWINDOWSIZE-2)) - -/* computes [s1]p1 + [s2]base */ -STATIC void -ge25519_double_scalarmult_vartime(ge25519 *r, const ge25519 *p1, const bignum256modm s1, const bignum256modm s2) { - signed char slide1[256], slide2[256]; - ge25519_pniels ALIGN(16) pre1[S1_TABLE_SIZE]; - ge25519 ALIGN(16) d1; - ge25519_p1p1 ALIGN(16) t; - int32_t i; - - contract256_slidingwindow_modm(slide1, s1, S1_SWINDOWSIZE); - contract256_slidingwindow_modm(slide2, s2, S2_SWINDOWSIZE); - - ge25519_double(&d1, p1); - ge25519_full_to_pniels(pre1, p1); - for (i = 0; i < S1_TABLE_SIZE - 1; i++) - ge25519_pnielsadd(&pre1[i+1], &d1, &pre1[i]); - - /* set neutral */ - memset(r, 0, sizeof(ge25519)); - r->y[0] = 1; - r->z[0] = 1; - - i = 255; - while ((i >= 0) && !(slide1[i] | slide2[i])) - i--; - - for (; i >= 0; i--) { - ge25519_double_p1p1(&t, r); - - if (slide1[i]) { - ge25519_p1p1_to_full(r, &t); - ge25519_pnielsadd_p1p1(&t, r, &pre1[abs(slide1[i]) / 2], (unsigned char)slide1[i] >> 7); - } - - if (slide2[i]) { - ge25519_p1p1_to_full(r, &t); - ge25519_nielsadd2_p1p1(&t, r, &ge25519_niels_sliding_multiples[abs(slide2[i]) / 2], (unsigned char)slide2[i] >> 7); - } - - ge25519_p1p1_to_partial(r, &t); - } -} - -#ifndef MM16 -# define MM16 __attribute__((aligned(16))) -#endif - -STATIC void -ge25519_scalarmult_vartime(ge25519 *r, const ge25519 *p1, const bignum256modm s1) { - signed char slide1[256]; - ge25519_pniels MM16 pre1[S1_TABLE_SIZE]; - ge25519 MM16 d1; - ge25519_p1p1 MM16 t; - int32_t i; - - contract256_slidingwindow_modm(slide1, s1, S1_SWINDOWSIZE); - - ge25519_double(&d1, p1); - ge25519_full_to_pniels(pre1, p1); - for (i = 0; i < S1_TABLE_SIZE - 1; i++) - ge25519_pnielsadd(&pre1[i+1], &d1, &pre1[i]); - - /* set neutral */ - memset(r, 0, sizeof(ge25519)); - r->y[0] = 1; - r->z[0] = 1; - - i = 255; - while ((i >= 0) && !slide1[i]) - i--; - - for (; i >= 0; i--) { - ge25519_double_p1p1(&t, r); - - if (slide1[i]) { - ge25519_p1p1_to_full(r, &t); - ge25519_pnielsadd_p1p1(&t, r, &pre1[abs(slide1[i]) / 2], (unsigned char)slide1[i] >> 7); - } - - ge25519_p1p1_to_partial(r, &t); - } -} - -DONNA_INLINE static void ge25519_cmove_stride4(long * r, long * p, long * pos, long * n, int stride) { - int i; - long x0=p[0], x1=p[1], x2=p[2], x3=p[3], y0, y1, y2, y3; - for(p+=stride; p= 0; i--) { - int k=abs(slide1[i]); - ge25519_double_partial(r, r); - ge25519_double_partial(r, r); - ge25519_double_partial(r, r); - ge25519_double_p1p1(&t, r); - ge25519_move_conditional_pniels_array(&pre, pre1, k, 9); - ge25519_p1p1_to_full(r, &t); - ge25519_pnielsadd_p1p1(&t, r, &pre, (unsigned char)slide1[i] >> 7); - ge25519_p1p1_to_partial(r, &t); - } -} - -#if !defined(HAVE_GE25519_SCALARMULT_BASE_CHOOSE_NIELS) -static void -ge25519_scalarmult_base_choose_niels(ge25519_niels *t, const uint8_t table[256][96], uint32_t pos, signed char b) { - bignum25519 ALIGN(16) neg; - uint32_t sign = (uint32_t)((unsigned char)b >> 7); - uint32_t mask = ~(sign - 1); - uint32_t u = (b + mask) ^ mask; - uint32_t i; - - /* ysubx, xaddy, t2d in packed form. initialize to ysubx = 1, xaddy = 1, t2d = 0 */ - uint8_t ALIGN(16) packed[96] = {0}; - packed[0] = 1; - packed[32] = 1; - - ge25519_move_conditional_niels_array(packed, &table[pos*8], u-1, 8); - - /* expand in to t */ - curve25519_expand(t->ysubx, packed + 0); - curve25519_expand(t->xaddy, packed + 32); - curve25519_expand(t->t2d , packed + 64); - - /* adjust for sign */ - curve25519_swap_conditional(t->ysubx, t->xaddy, sign); - curve25519_neg(neg, t->t2d); - curve25519_swap_conditional(t->t2d, neg, sign); -} -#endif /* HAVE_GE25519_SCALARMULT_BASE_CHOOSE_NIELS */ - -STATIC void -ge25519_scalarmult_base_niels(ge25519 *r, const uint8_t table[256][96], const bignum256modm s) { - signed char b[64]; - uint32_t i; - ge25519_niels ALIGN(16) t; - - contract256_window4_modm(b, s); - - ge25519_scalarmult_base_choose_niels(&t, table, 0, b[1]); - curve25519_sub_reduce(r->x, t.xaddy, t.ysubx); - curve25519_add_reduce(r->y, t.xaddy, t.ysubx); - memset(r->z, 0, sizeof(bignum25519)); - r->z[0] = 2; - curve25519_copy(r->t, t.t2d); - for (i = 3; i < 64; i += 2) { - ge25519_scalarmult_base_choose_niels(&t, table, i / 2, b[i]); - ge25519_nielsadd2(r, &t); - } - ge25519_double_partial(r, r); - ge25519_double_partial(r, r); - ge25519_double_partial(r, r); - ge25519_double(r, r); - ge25519_scalarmult_base_choose_niels(&t, table, 0, b[0]); - curve25519_mul(t.t2d, t.t2d, ge25519_ecd); - ge25519_nielsadd2(r, &t); - for(i = 2; i < 64; i += 2) { - ge25519_scalarmult_base_choose_niels(&t, table, i / 2, b[i]); - ge25519_nielsadd2(r, &t); - } -} - -STATIC void ge25519_scalarmult_base(ge25519 *r, const bignum256modm s) { - ge25519_scalarmult_base_niels(r, ge25519_niels_base_multiples, s); -} - diff --git a/ed25519-donna/ed25519-donna-portable-identify.h b/ed25519-donna/ed25519-donna-portable-identify.h deleted file mode 100644 index ee3a01cc4..000000000 --- a/ed25519-donna/ed25519-donna-portable-identify.h +++ /dev/null @@ -1,106 +0,0 @@ -/* os */ -#if defined(_WIN32) || defined(_WIN64) || defined(__TOS_WIN__) || defined(__WINDOWS__) - #define OS_WINDOWS -#elif defined(sun) || defined(__sun) || defined(__SVR4) || defined(__svr4__) - #define OS_SOLARIS -#else - #include /* need this to define BSD */ - #define OS_NIX - #if defined(__linux__) - #define OS_LINUX - #elif defined(BSD) - #define OS_BSD - #if defined(MACOS_X) || (defined(__APPLE__) & defined(__MACH__)) - #define OS_OSX - #elif defined(macintosh) || defined(Macintosh) - #define OS_MAC - #elif defined(__OpenBSD__) - #define OS_OPENBSD - #endif - #endif -#endif - - -/* compiler */ -#if defined(_MSC_VER) - #define COMPILER_MSVC -#endif -#if defined(__ICC) - #define COMPILER_INTEL -#endif -#if defined(__GNUC__) - #if (__GNUC__ >= 3) - #define COMPILER_GCC ((__GNUC__ * 10000) + (__GNUC_MINOR__ * 100) + (__GNUC_PATCHLEVEL__)) - #else - #define COMPILER_GCC ((__GNUC__ * 10000) + (__GNUC_MINOR__ * 100) ) - #endif -#endif -#if defined(__PATHCC__) - #define COMPILER_PATHCC -#endif -#if defined(__clang__) - #define COMPILER_CLANG ((__clang_major__ * 10000) + (__clang_minor__ * 100) + (__clang_patchlevel__)) -#endif - - - -/* cpu */ -#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__ ) || defined(_M_X64) - #define CPU_X86_64 -#elif defined(__i586__) || defined(__i686__) || (defined(_M_IX86) && (_M_IX86 >= 500)) - #define CPU_X86 500 - #ifdef __SSE2__ - #define ED25519_SSE2 - #endif -#elif defined(__i486__) || (defined(_M_IX86) && (_M_IX86 >= 400)) - #define CPU_X86 400 -#elif defined(__i386__) || (defined(_M_IX86) && (_M_IX86 >= 300)) || defined(__X86__) || defined(_X86_) || defined(__I86__) - #define CPU_X86 300 -#elif defined(__ia64__) || defined(_IA64) || defined(__IA64__) || defined(_M_IA64) || defined(__ia64) - #define CPU_IA64 -#endif - -#if defined(__sparc__) || defined(__sparc) || defined(__sparcv9) - #define CPU_SPARC - #if defined(__sparcv9) - #define CPU_SPARC64 - #endif -#endif - -#if defined(powerpc) || defined(__PPC__) || defined(__ppc__) || defined(_ARCH_PPC) || defined(__powerpc__) || defined(__powerpc) || defined(POWERPC) || defined(_M_PPC) - #define CPU_PPC - #if defined(_ARCH_PWR7) - #define CPU_POWER7 - #elif defined(__64BIT__) - #define CPU_PPC64 - #else - #define CPU_PPC32 - #endif -#endif - -#if defined(__hppa__) || defined(__hppa) - #define CPU_HPPA -#endif - -#if defined(__alpha__) || defined(__alpha) || defined(_M_ALPHA) - #define CPU_ALPHA -#endif - -/* 64 bit cpu */ -#if defined(CPU_X86_64) || defined(CPU_IA64) || defined(CPU_SPARC64) || defined(__64BIT__) || defined(__LP64__) || defined(_LP64) || (defined(_MIPS_SZLONG) && (_MIPS_SZLONG == 64)) - #define CPU_64BITS -#endif - -#if defined(COMPILER_MSVC) - typedef signed char int8_t; - typedef unsigned char uint8_t; - typedef signed short int16_t; - typedef unsigned short uint16_t; - typedef signed int int32_t; - typedef unsigned int uint32_t; - typedef signed __int64 int64_t; - typedef unsigned __int64 uint64_t; -#else - #include -#endif - diff --git a/ed25519-donna/ed25519-donna-portable.h b/ed25519-donna/ed25519-donna-portable.h index cc18822bb..bb8602869 100644 --- a/ed25519-donna/ed25519-donna-portable.h +++ b/ed25519-donna/ed25519-donna-portable.h @@ -1,137 +1,27 @@ -#include "ed25519-donna-portable-identify.h" - #define mul32x32_64(a,b) (((uint64_t)(a))*(b)) -/* platform */ -#if defined(COMPILER_MSVC) - #include - #if !defined(_DEBUG) - #undef mul32x32_64 - #define mul32x32_64(a,b) __emulu(a,b) - #endif - #undef inline - #define inline __forceinline - #define DONNA_INLINE __forceinline - #define DONNA_NOINLINE __declspec(noinline) - #undef ALIGN - #define ALIGN(x) __declspec(align(x)) - #define ROTL32(a,b) _rotl(a,b) - #define ROTR32(a,b) _rotr(a,b) -#else - #include - #define DONNA_INLINE inline __attribute__((always_inline)) - #define DONNA_NOINLINE __attribute__((noinline)) - #undef ALIGN - #define ALIGN(x) __attribute__((aligned(x))) - #define ROTL32(a,b) (((a) << (b)) | ((a) >> (32 - b))) - #define ROTR32(a,b) (((a) >> (b)) | ((a) << (32 - b))) -#endif - -/* uint128_t */ -#if defined(CPU_64BITS) && !defined(ED25519_FORCE_32BIT) - #if defined(COMPILER_CLANG) && (COMPILER_CLANG >= 30100) - #define HAVE_NATIVE_UINT128 - typedef unsigned __int128 uint128_t; - #elif defined(COMPILER_MSVC) - #define HAVE_UINT128 - typedef struct uint128_t { - uint64_t lo, hi; - } uint128_t; - #define mul64x64_128(out,a,b) out.lo = _umul128(a,b,&out.hi); - #define shr128_pair(out,hi,lo,shift) out = __shiftright128(lo, hi, shift); - #define shl128_pair(out,hi,lo,shift) out = __shiftleft128(lo, hi, shift); - #define shr128(out,in,shift) shr128_pair(out, in.hi, in.lo, shift) - #define shl128(out,in,shift) shl128_pair(out, in.hi, in.lo, shift) - #define add128(a,b) { uint64_t p = a.lo; a.lo += b.lo; a.hi += b.hi + (a.lo < p); } - #define add128_64(a,b) { uint64_t p = a.lo; a.lo += b; a.hi += (a.lo < p); } - #define lo128(a) (a.lo) - #define hi128(a) (a.hi) - #elif defined(COMPILER_GCC) && !defined(HAVE_NATIVE_UINT128) - #if defined(__SIZEOF_INT128__) - #define HAVE_NATIVE_UINT128 - typedef unsigned __int128 uint128_t; - #elif (COMPILER_GCC >= 40400) - #define HAVE_NATIVE_UINT128 - typedef unsigned uint128_t __attribute__((mode(TI))); - #elif defined(CPU_X86_64) - #define HAVE_UINT128 - typedef struct uint128_t { - uint64_t lo, hi; - } uint128_t; - #define mul64x64_128(out,a,b) __asm__ ("mulq %3" : "=a" (out.lo), "=d" (out.hi) : "a" (a), "rm" (b)); - #define shr128_pair(out,hi,lo,shift) __asm__ ("shrdq %2,%1,%0" : "+r" (lo) : "r" (hi), "J" (shift)); out = lo; - #define shl128_pair(out,hi,lo,shift) __asm__ ("shldq %2,%1,%0" : "+r" (hi) : "r" (lo), "J" (shift)); out = hi; - #define shr128(out,in,shift) shr128_pair(out,in.hi, in.lo, shift) - #define shl128(out,in,shift) shl128_pair(out,in.hi, in.lo, shift) - #define add128(a,b) __asm__ ("addq %4,%2; adcq %5,%3" : "=r" (a.hi), "=r" (a.lo) : "1" (a.lo), "0" (a.hi), "rm" (b.lo), "rm" (b.hi) : "cc"); - #define add128_64(a,b) __asm__ ("addq %4,%2; adcq $0,%3" : "=r" (a.hi), "=r" (a.lo) : "1" (a.lo), "0" (a.hi), "rm" (b) : "cc"); - #define lo128(a) (a.lo) - #define hi128(a) (a.hi) - #endif - #endif - - #if defined(HAVE_NATIVE_UINT128) - #define HAVE_UINT128 - #define mul64x64_128(out,a,b) out = (uint128_t)a * b; - #define shr128_pair(out,hi,lo,shift) out = (uint64_t)((((uint128_t)hi << 64) | lo) >> (shift)); - #define shl128_pair(out,hi,lo,shift) out = (uint64_t)(((((uint128_t)hi << 64) | lo) << (shift)) >> 64); - #define shr128(out,in,shift) out = (uint64_t)(in >> (shift)); - #define shl128(out,in,shift) out = (uint64_t)((in << shift) >> 64); - #define add128(a,b) a += b; - #define add128_64(a,b) a += (uint64_t)b; - #define lo128(a) ((uint64_t)a) - #define hi128(a) ((uint64_t)(a >> 64)) - #endif +#include +#include +#include - #if !defined(HAVE_UINT128) - #error Need a uint128_t implementation! - #endif -#endif +#define DONNA_INLINE inline __attribute__((always_inline)) +#define DONNA_NOINLINE __attribute__((noinline)) +#undef ALIGN +#define ALIGN(x) __attribute__((aligned(x))) +#define ROTL32(a,b) (((a) << (b)) | ((a) >> (32 - b))) +#define ROTR32(a,b) (((a) >> (b)) | ((a) << (32 - b))) -/* endian */ -#if !defined(ED25519_OPENSSLRNG) static inline void U32TO8_LE(unsigned char *p, const uint32_t v) { p[0] = (unsigned char)(v ); p[1] = (unsigned char)(v >> 8); p[2] = (unsigned char)(v >> 16); p[3] = (unsigned char)(v >> 24); } -#endif -#if !defined(HAVE_UINT128) static inline uint32_t U8TO32_LE(const unsigned char *p) { return - (((uint32_t)(p[0]) ) | + (((uint32_t)(p[0]) ) | ((uint32_t)(p[1]) << 8) | ((uint32_t)(p[2]) << 16) | ((uint32_t)(p[3]) << 24)); } -#else -static inline uint64_t U8TO64_LE(const unsigned char *p) { - return - (((uint64_t)(p[0]) ) | - ((uint64_t)(p[1]) << 8) | - ((uint64_t)(p[2]) << 16) | - ((uint64_t)(p[3]) << 24) | - ((uint64_t)(p[4]) << 32) | - ((uint64_t)(p[5]) << 40) | - ((uint64_t)(p[6]) << 48) | - ((uint64_t)(p[7]) << 56)); -} - -static inline void U64TO8_LE(unsigned char *p, const uint64_t v) { - p[0] = (unsigned char)(v ); - p[1] = (unsigned char)(v >> 8); - p[2] = (unsigned char)(v >> 16); - p[3] = (unsigned char)(v >> 24); - p[4] = (unsigned char)(v >> 32); - p[5] = (unsigned char)(v >> 40); - p[6] = (unsigned char)(v >> 48); - p[7] = (unsigned char)(v >> 56); -} -#endif - -#include -#include - - diff --git a/ed25519-donna/ed25519-donna.h b/ed25519-donna/ed25519-donna.h index de1120f46..de176abad 100644 --- a/ed25519-donna/ed25519-donna.h +++ b/ed25519-donna/ed25519-donna.h @@ -11,52 +11,11 @@ #include "ed25519-donna-portable.h" -#if defined(ED25519_SSE2) -#else - #if defined(HAVE_UINT128) && !defined(ED25519_FORCE_32BIT) - #define ED25519_64BIT - #else - #define ED25519_32BIT - #endif -#endif - -#if !defined(ED25519_NO_INLINE_ASM) - /* detect extra features first so un-needed functions can be disabled throughout */ - #if defined(ED25519_SSE2) - #if defined(COMPILER_GCC) && defined(CPU_X86) - #define ED25519_GCC_32BIT_SSE_CHOOSE - #elif defined(COMPILER_GCC) && defined(CPU_X86_64) - #define ED25519_GCC_64BIT_SSE_CHOOSE - #endif - #else - #if defined(CPU_X86_64) - #if defined(COMPILER_GCC) - #if defined(ED25519_64BIT) - #define ED25519_GCC_64BIT_X86_CHOOSE - #else - #define ED25519_GCC_64BIT_32BIT_CHOOSE - #endif - #endif - #endif - #endif -#endif - -#if defined(ED25519_SSE2) - #include "curve25519-donna-sse2.h" -#elif defined(ED25519_64BIT) - #include "curve25519-donna-64bit.h" -#else - #include "curve25519-donna-32bit.h" -#endif +#include "curve25519-donna-32bit.h" #include "curve25519-donna-helpers.h" -/* separate uint128 check for 64 bit sse2 */ -#if defined(HAVE_UINT128) && !defined(ED25519_FORCE_32BIT) - #include "modm-donna-64bit.h" -#else - #include "modm-donna-32bit.h" -#endif +#include "modm-donna-32bit.h" typedef unsigned char hash_512bits[64]; @@ -96,20 +55,6 @@ typedef struct ge25519_pniels_t { #include "ed25519-donna-basepoint-table.h" -#if defined(ED25519_64BIT) - #include "ed25519-donna-64bit-tables.h" - #include "ed25519-donna-64bit-x86.h" -#else - #include "ed25519-donna-32bit-tables.h" - #include "ed25519-donna-64bit-x86-32bit.h" -#endif - - -#if defined(ED25519_SSE2) - #include "ed25519-donna-32bit-sse2.h" - #include "ed25519-donna-64bit-sse2.h" - #include "ed25519-donna-impl-sse2.h" -#else - #include "ed25519-donna-impl-base.h" -#endif +#include "ed25519-donna-32bit-tables.h" +#include "ed25519-donna-impl-base.h" diff --git a/ed25519-donna/ed25519-hash.h b/ed25519-donna/ed25519-hash.h deleted file mode 100644 index 6ba8f5238..000000000 --- a/ed25519-donna/ed25519-hash.h +++ /dev/null @@ -1,219 +0,0 @@ -#if defined(ED25519_REFHASH) - -/* reference/slow SHA-512. really, do not use this */ - -#define HASH_BLOCK_SIZE 128 -#define HASH_DIGEST_SIZE 64 - -typedef struct sha512_state_t { - uint64_t H[8]; - uint64_t T[2]; - uint32_t leftover; - uint8_t buffer[HASH_BLOCK_SIZE]; -} sha512_state; - -typedef sha512_state ed25519_hash_context; - -static const uint64_t sha512_constants[80] = { - 0x428a2f98d728ae22ull, 0x7137449123ef65cdull, 0xb5c0fbcfec4d3b2full, 0xe9b5dba58189dbbcull, - 0x3956c25bf348b538ull, 0x59f111f1b605d019ull, 0x923f82a4af194f9bull, 0xab1c5ed5da6d8118ull, - 0xd807aa98a3030242ull, 0x12835b0145706fbeull, 0x243185be4ee4b28cull, 0x550c7dc3d5ffb4e2ull, - 0x72be5d74f27b896full, 0x80deb1fe3b1696b1ull, 0x9bdc06a725c71235ull, 0xc19bf174cf692694ull, - 0xe49b69c19ef14ad2ull, 0xefbe4786384f25e3ull, 0x0fc19dc68b8cd5b5ull, 0x240ca1cc77ac9c65ull, - 0x2de92c6f592b0275ull, 0x4a7484aa6ea6e483ull, 0x5cb0a9dcbd41fbd4ull, 0x76f988da831153b5ull, - 0x983e5152ee66dfabull, 0xa831c66d2db43210ull, 0xb00327c898fb213full, 0xbf597fc7beef0ee4ull, - 0xc6e00bf33da88fc2ull, 0xd5a79147930aa725ull, 0x06ca6351e003826full, 0x142929670a0e6e70ull, - 0x27b70a8546d22ffcull, 0x2e1b21385c26c926ull, 0x4d2c6dfc5ac42aedull, 0x53380d139d95b3dfull, - 0x650a73548baf63deull, 0x766a0abb3c77b2a8ull, 0x81c2c92e47edaee6ull, 0x92722c851482353bull, - 0xa2bfe8a14cf10364ull, 0xa81a664bbc423001ull, 0xc24b8b70d0f89791ull, 0xc76c51a30654be30ull, - 0xd192e819d6ef5218ull, 0xd69906245565a910ull, 0xf40e35855771202aull, 0x106aa07032bbd1b8ull, - 0x19a4c116b8d2d0c8ull, 0x1e376c085141ab53ull, 0x2748774cdf8eeb99ull, 0x34b0bcb5e19b48a8ull, - 0x391c0cb3c5c95a63ull, 0x4ed8aa4ae3418acbull, 0x5b9cca4f7763e373ull, 0x682e6ff3d6b2b8a3ull, - 0x748f82ee5defb2fcull, 0x78a5636f43172f60ull, 0x84c87814a1f0ab72ull, 0x8cc702081a6439ecull, - 0x90befffa23631e28ull, 0xa4506cebde82bde9ull, 0xbef9a3f7b2c67915ull, 0xc67178f2e372532bull, - 0xca273eceea26619cull, 0xd186b8c721c0c207ull, 0xeada7dd6cde0eb1eull, 0xf57d4f7fee6ed178ull, - 0x06f067aa72176fbaull, 0x0a637dc5a2c898a6ull, 0x113f9804bef90daeull, 0x1b710b35131c471bull, - 0x28db77f523047d84ull, 0x32caab7b40c72493ull, 0x3c9ebe0a15c9bebcull, 0x431d67c49c100d4cull, - 0x4cc5d4becb3e42b6ull, 0x597f299cfc657e2aull, 0x5fcb6fab3ad6faecull, 0x6c44198c4a475817ull -}; - -static uint64_t -sha512_ROTR64(uint64_t x, int k) { - return (x >> k) | (x << (64 - k)); -} - -static uint64_t -sha512_LOAD64_BE(const uint8_t *p) { - return - ((uint64_t)p[0] << 56) | - ((uint64_t)p[1] << 48) | - ((uint64_t)p[2] << 40) | - ((uint64_t)p[3] << 32) | - ((uint64_t)p[4] << 24) | - ((uint64_t)p[5] << 16) | - ((uint64_t)p[6] << 8) | - ((uint64_t)p[7] ); -} - -static void -sha512_STORE64_BE(uint8_t *p, uint64_t v) { - p[0] = (uint8_t)(v >> 56); - p[1] = (uint8_t)(v >> 48); - p[2] = (uint8_t)(v >> 40); - p[3] = (uint8_t)(v >> 32); - p[4] = (uint8_t)(v >> 24); - p[5] = (uint8_t)(v >> 16); - p[6] = (uint8_t)(v >> 8); - p[7] = (uint8_t)(v ); -} - -#define Ch(x,y,z) (z ^ (x & (y ^ z))) -#define Maj(x,y,z) (((x | y) & z) | (x & y)) -#define S0(x) (sha512_ROTR64(x, 28) ^ sha512_ROTR64(x, 34) ^ sha512_ROTR64(x, 39)) -#define S1(x) (sha512_ROTR64(x, 14) ^ sha512_ROTR64(x, 18) ^ sha512_ROTR64(x, 41)) -#define G0(x) (sha512_ROTR64(x, 1) ^ sha512_ROTR64(x, 8) ^ (x >> 7)) -#define G1(x) (sha512_ROTR64(x, 19) ^ sha512_ROTR64(x, 61) ^ (x >> 6)) -#define W0(in,i) (sha512_LOAD64_BE(&in[i * 8])) -#define W1(i) (G1(w[i - 2]) + w[i - 7] + G0(w[i - 15]) + w[i - 16]) -#define STEP(i) \ - t1 = S0(r[0]) + Maj(r[0], r[1], r[2]); \ - t0 = r[7] + S1(r[4]) + Ch(r[4], r[5], r[6]) + sha512_constants[i] + w[i]; \ - r[7] = r[6]; \ - r[6] = r[5]; \ - r[5] = r[4]; \ - r[4] = r[3] + t0; \ - r[3] = r[2]; \ - r[2] = r[1]; \ - r[1] = r[0]; \ - r[0] = t0 + t1; - -static void -sha512_blocks(sha512_state *S, const uint8_t *in, size_t blocks) { - uint64_t r[8], w[80], t0, t1; - size_t i; - - for (i = 0; i < 8; i++) r[i] = S->H[i]; - - while (blocks--) { - for (i = 0; i < 16; i++) { w[i] = W0(in, i); } - for (i = 16; i < 80; i++) { w[i] = W1(i); } - for (i = 0; i < 80; i++) { STEP(i); } - for (i = 0; i < 8; i++) { r[i] += S->H[i]; S->H[i] = r[i]; } - S->T[0] += HASH_BLOCK_SIZE * 8; - S->T[1] += (!S->T[0]) ? 1 : 0; - in += HASH_BLOCK_SIZE; - } -} - -static void -ed25519_hash_init(sha512_state *S) { - S->H[0] = 0x6a09e667f3bcc908ull; - S->H[1] = 0xbb67ae8584caa73bull; - S->H[2] = 0x3c6ef372fe94f82bull; - S->H[3] = 0xa54ff53a5f1d36f1ull; - S->H[4] = 0x510e527fade682d1ull; - S->H[5] = 0x9b05688c2b3e6c1full; - S->H[6] = 0x1f83d9abfb41bd6bull; - S->H[7] = 0x5be0cd19137e2179ull; - S->T[0] = 0; - S->T[1] = 0; - S->leftover = 0; -} - -static void -ed25519_hash_update(sha512_state *S, const uint8_t *in, size_t inlen) { - size_t blocks, want; - - /* handle the previous data */ - if (S->leftover) { - want = (HASH_BLOCK_SIZE - S->leftover); - want = (want < inlen) ? want : inlen; - memcpy(S->buffer + S->leftover, in, want); - S->leftover += (uint32_t)want; - if (S->leftover < HASH_BLOCK_SIZE) - return; - in += want; - inlen -= want; - sha512_blocks(S, S->buffer, 1); - } - - /* handle the current data */ - blocks = (inlen & ~(HASH_BLOCK_SIZE - 1)); - S->leftover = (uint32_t)(inlen - blocks); - if (blocks) { - sha512_blocks(S, in, blocks / HASH_BLOCK_SIZE); - in += blocks; - } - - /* handle leftover data */ - if (S->leftover) - memcpy(S->buffer, in, S->leftover); -} - -static void -ed25519_hash_final(sha512_state *S, uint8_t *hash) { - uint64_t t0 = S->T[0] + (S->leftover * 8), t1 = S->T[1]; - - S->buffer[S->leftover] = 0x80; - if (S->leftover <= 111) { - memset(S->buffer + S->leftover + 1, 0, 111 - S->leftover); - } else { - memset(S->buffer + S->leftover + 1, 0, 127 - S->leftover); - sha512_blocks(S, S->buffer, 1); - memset(S->buffer, 0, 112); - } - - sha512_STORE64_BE(S->buffer + 112, t1); - sha512_STORE64_BE(S->buffer + 120, t0); - sha512_blocks(S, S->buffer, 1); - - sha512_STORE64_BE(&hash[ 0], S->H[0]); - sha512_STORE64_BE(&hash[ 8], S->H[1]); - sha512_STORE64_BE(&hash[16], S->H[2]); - sha512_STORE64_BE(&hash[24], S->H[3]); - sha512_STORE64_BE(&hash[32], S->H[4]); - sha512_STORE64_BE(&hash[40], S->H[5]); - sha512_STORE64_BE(&hash[48], S->H[6]); - sha512_STORE64_BE(&hash[56], S->H[7]); -} - -static void -ed25519_hash(uint8_t *hash, const uint8_t *in, size_t inlen) { - ed25519_hash_context ctx; - ed25519_hash_init(&ctx); - ed25519_hash_update(&ctx, in, inlen); - ed25519_hash_final(&ctx, hash); -} - -#elif defined(ED25519_CUSTOMHASH) - -#include "ed25519-hash-custom.h" - -#else - -#include - -typedef SHA512_CTX ed25519_hash_context; - -static void -ed25519_hash_init(ed25519_hash_context *ctx) { - SHA512_Init(ctx); -} - -static void -ed25519_hash_update(ed25519_hash_context *ctx, const uint8_t *in, size_t inlen) { - SHA512_Update(ctx, in, inlen); -} - -static void -ed25519_hash_final(ed25519_hash_context *ctx, uint8_t *hash) { - SHA512_Final(hash, ctx); -} - -static void -ed25519_hash(uint8_t *hash, const uint8_t *in, size_t inlen) { - SHA512(in, inlen, hash); -} - -#endif - diff --git a/ed25519-donna/ed25519-randombytes-custom.h b/ed25519-donna/ed25519-randombytes-custom.h deleted file mode 100644 index 3515158b2..000000000 --- a/ed25519-donna/ed25519-randombytes-custom.h +++ /dev/null @@ -1,12 +0,0 @@ -/* - a custom randombytes must implement: - - void ED25519_FN(ed25519_randombytes_unsafe) (void *p, size_t len); - - ed25519_randombytes_unsafe is used by the batch verification function - to create random scalars -*/ - -#include "rand.h" - -#define ed25519_randombytes_unsafe(p, len) random_buffer((uint8_t *)(p), (len)) diff --git a/ed25519-donna/ed25519-randombytes.h b/ed25519-donna/ed25519-randombytes.h deleted file mode 100644 index 1dc629028..000000000 --- a/ed25519-donna/ed25519-randombytes.h +++ /dev/null @@ -1,91 +0,0 @@ -#if defined(ED25519_TEST) -/* - ISAAC+ "variant", the paper is not clear on operator precedence and other - things. This is the "first in, first out" option! - - Not threadsafe or securely initialized, only for deterministic testing -*/ -typedef struct isaacp_state_t { - uint32_t state[256]; - unsigned char buffer[1024]; - uint32_t a, b, c; - size_t left; -} isaacp_state; - -#define isaacp_step(offset, mix) \ - x = mm[i + offset]; \ - a = (a ^ (mix)) + (mm[(i + offset + 128) & 0xff]); \ - y = (a ^ b) + mm[(x >> 2) & 0xff]; \ - mm[i + offset] = y; \ - b = (x + a) ^ mm[(y >> 10) & 0xff]; \ - U32TO8_LE(out + (i + offset) * 4, b); - -static void -isaacp_mix(isaacp_state *st) { - uint32_t i, x, y; - uint32_t a = st->a, b = st->b, c = st->c; - uint32_t *mm = st->state; - unsigned char *out = st->buffer; - - c = c + 1; - b = b + c; - - for (i = 0; i < 256; i += 4) { - isaacp_step(0, ROTL32(a,13)) - isaacp_step(1, ROTR32(a, 6)) - isaacp_step(2, ROTL32(a, 2)) - isaacp_step(3, ROTR32(a,16)) - } - - st->a = a; - st->b = b; - st->c = c; - st->left = 1024; -} - -static void -isaacp_random(isaacp_state *st, void *p, size_t len) { - size_t use; - unsigned char *c = (unsigned char *)p; - while (len) { - use = (len > st->left) ? st->left : len; - memcpy(c, st->buffer + (sizeof(st->buffer) - st->left), use); - - st->left -= use; - c += use; - len -= use; - - if (!st->left) - isaacp_mix(st); - } -} - -void -ED25519_FN(ed25519_randombytes_unsafe) (void *p, size_t len) { - static int initialized = 0; - static isaacp_state rng; - - if (!initialized) { - memset(&rng, 0, sizeof(rng)); - isaacp_mix(&rng); - isaacp_mix(&rng); - initialized = 1; - } - - isaacp_random(&rng, p, len); -} -#elif defined(ED25519_CUSTOMRANDOM) - -#include "ed25519-randombytes-custom.h" - -#else - -#include - -void -ED25519_FN(ed25519_randombytes_unsafe) (void *p, size_t len) { - - RAND_bytes(p, (int) len); - -} -#endif diff --git a/ed25519-donna/ed25519.c b/ed25519-donna/ed25519.c index b7c35847e..9ed7c387f 100644 --- a/ed25519-donna/ed25519.c +++ b/ed25519-donna/ed25519.c @@ -17,8 +17,7 @@ #include "ed25519-donna.h" #include "ed25519.h" -#include "ed25519-randombytes.h" -#include "ed25519-hash.h" +#include "ed25519-hash-custom.h" /* Generates a (extsk[0..31]) and aExt (extsk[32..63]) @@ -116,8 +115,6 @@ ED25519_FN(ed25519_sign_open) (const unsigned char *m, size_t mlen, const ed2551 return ed25519_verify(RS, checkR, 32) ? 0 : -1; } -#include "ed25519-donna-batchverify.h" - /* Fast Curve25519 basepoint scalar multiplication */ diff --git a/ed25519-donna/ed25519.h b/ed25519-donna/ed25519.h index dc86675cd..94fb88314 100644 --- a/ed25519-donna/ed25519.h +++ b/ed25519-donna/ed25519.h @@ -19,8 +19,6 @@ void ed25519_sign(const unsigned char *m, size_t mlen, const ed25519_secret_key int ed25519_sign_open_batch(const unsigned char **m, size_t *mlen, const unsigned char **pk, const unsigned char **RS, size_t num, int *valid); -void ed25519_randombytes_unsafe(void *out, size_t count); - void curved25519_scalarmult_basepoint(curved25519_key pk, const curved25519_key e); #if defined(__cplusplus) diff --git a/ed25519-donna/modm-donna-64bit.h b/ed25519-donna/modm-donna-64bit.h deleted file mode 100644 index 4197f3bf6..000000000 --- a/ed25519-donna/modm-donna-64bit.h +++ /dev/null @@ -1,348 +0,0 @@ -/* - Public domain by Andrew M. -*/ - - -/* - Arithmetic modulo the group order n = 2^252 + 27742317777372353535851937790883648493 = 7237005577332262213973186563042994240857116359379907606001950938285454250989 - - k = 32 - b = 1 << 8 = 256 - m = 2^252 + 27742317777372353535851937790883648493 = 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed - mu = floor( b^(k*2) / m ) = 0xfffffffffffffffffffffffffffffffeb2106215d086329a7ed9ce5a30a2c131b -*/ - -#define bignum256modm_bits_per_limb 56 -#define bignum256modm_limb_size 5 - -typedef uint64_t bignum256modm_element_t; -typedef bignum256modm_element_t bignum256modm[5]; - -static const bignum256modm modm_m = { - 0x12631a5cf5d3ed, - 0xf9dea2f79cd658, - 0x000000000014de, - 0x00000000000000, - 0x00000010000000 -}; - -static const bignum256modm modm_mu = { - 0x9ce5a30a2c131b, - 0x215d086329a7ed, - 0xffffffffeb2106, - 0xffffffffffffff, - 0x00000fffffffff -}; - -static bignum256modm_element_t -lt_modm(bignum256modm_element_t a, bignum256modm_element_t b) { - return (a - b) >> 63; -} - -static void -reduce256_modm(bignum256modm r) { - bignum256modm t; - bignum256modm_element_t b = 0, pb, mask; - - /* t = r - m */ - pb = 0; - pb += modm_m[0]; b = lt_modm(r[0], pb); t[0] = (r[0] - pb + (b << 56)); pb = b; - pb += modm_m[1]; b = lt_modm(r[1], pb); t[1] = (r[1] - pb + (b << 56)); pb = b; - pb += modm_m[2]; b = lt_modm(r[2], pb); t[2] = (r[2] - pb + (b << 56)); pb = b; - pb += modm_m[3]; b = lt_modm(r[3], pb); t[3] = (r[3] - pb + (b << 56)); pb = b; - pb += modm_m[4]; b = lt_modm(r[4], pb); t[4] = (r[4] - pb + (b << 32)); - - /* keep r if r was smaller than m */ - mask = b - 1; - - r[0] ^= mask & (r[0] ^ t[0]); - r[1] ^= mask & (r[1] ^ t[1]); - r[2] ^= mask & (r[2] ^ t[2]); - r[3] ^= mask & (r[3] ^ t[3]); - r[4] ^= mask & (r[4] ^ t[4]); -} - -static void -barrett_reduce256_modm(bignum256modm r, const bignum256modm q1, const bignum256modm r1) { - bignum256modm q3, r2; - uint128_t c, mul; - bignum256modm_element_t f, b, pb; - - /* q1 = x >> 248 = 264 bits = 5 56 bit elements - q2 = mu * q1 - q3 = (q2 / 256(32+1)) = q2 / (2^8)^(32+1) = q2 >> 264 */ - mul64x64_128(c, modm_mu[0], q1[3]) mul64x64_128(mul, modm_mu[3], q1[0]) add128(c, mul) mul64x64_128(mul, modm_mu[1], q1[2]) add128(c, mul) mul64x64_128(mul, modm_mu[2], q1[1]) add128(c, mul) shr128(f, c, 56); - mul64x64_128(c, modm_mu[0], q1[4]) add128_64(c, f) mul64x64_128(mul, modm_mu[4], q1[0]) add128(c, mul) mul64x64_128(mul, modm_mu[3], q1[1]) add128(c, mul) mul64x64_128(mul, modm_mu[1], q1[3]) add128(c, mul) mul64x64_128(mul, modm_mu[2], q1[2]) add128(c, mul) - f = lo128(c); q3[0] = (f >> 40) & 0xffff; shr128(f, c, 56); - mul64x64_128(c, modm_mu[4], q1[1]) add128_64(c, f) mul64x64_128(mul, modm_mu[1], q1[4]) add128(c, mul) mul64x64_128(mul, modm_mu[2], q1[3]) add128(c, mul) mul64x64_128(mul, modm_mu[3], q1[2]) add128(c, mul) - f = lo128(c); q3[0] |= (f << 16) & 0xffffffffffffff; q3[1] = (f >> 40) & 0xffff; shr128(f, c, 56); - mul64x64_128(c, modm_mu[4], q1[2]) add128_64(c, f) mul64x64_128(mul, modm_mu[2], q1[4]) add128(c, mul) mul64x64_128(mul, modm_mu[3], q1[3]) add128(c, mul) - f = lo128(c); q3[1] |= (f << 16) & 0xffffffffffffff; q3[2] = (f >> 40) & 0xffff; shr128(f, c, 56); - mul64x64_128(c, modm_mu[4], q1[3]) add128_64(c, f) mul64x64_128(mul, modm_mu[3], q1[4]) add128(c, mul) - f = lo128(c); q3[2] |= (f << 16) & 0xffffffffffffff; q3[3] = (f >> 40) & 0xffff; shr128(f, c, 56); - mul64x64_128(c, modm_mu[4], q1[4]) add128_64(c, f) - f = lo128(c); q3[3] |= (f << 16) & 0xffffffffffffff; q3[4] = (f >> 40) & 0xffff; shr128(f, c, 56); - q3[4] |= (f << 16); - - mul64x64_128(c, modm_m[0], q3[0]) - r2[0] = lo128(c) & 0xffffffffffffff; shr128(f, c, 56); - mul64x64_128(c, modm_m[0], q3[1]) add128_64(c, f) mul64x64_128(mul, modm_m[1], q3[0]) add128(c, mul) - r2[1] = lo128(c) & 0xffffffffffffff; shr128(f, c, 56); - mul64x64_128(c, modm_m[0], q3[2]) add128_64(c, f) mul64x64_128(mul, modm_m[2], q3[0]) add128(c, mul) mul64x64_128(mul, modm_m[1], q3[1]) add128(c, mul) - r2[2] = lo128(c) & 0xffffffffffffff; shr128(f, c, 56); - mul64x64_128(c, modm_m[0], q3[3]) add128_64(c, f) mul64x64_128(mul, modm_m[3], q3[0]) add128(c, mul) mul64x64_128(mul, modm_m[1], q3[2]) add128(c, mul) mul64x64_128(mul, modm_m[2], q3[1]) add128(c, mul) - r2[3] = lo128(c) & 0xffffffffffffff; shr128(f, c, 56); - mul64x64_128(c, modm_m[0], q3[4]) add128_64(c, f) mul64x64_128(mul, modm_m[4], q3[0]) add128(c, mul) mul64x64_128(mul, modm_m[3], q3[1]) add128(c, mul) mul64x64_128(mul, modm_m[1], q3[3]) add128(c, mul) mul64x64_128(mul, modm_m[2], q3[2]) add128(c, mul) - r2[4] = lo128(c) & 0x0000ffffffffff; - - pb = 0; - pb += r2[0]; b = lt_modm(r1[0], pb); r[0] = (r1[0] - pb + (b << 56)); pb = b; - pb += r2[1]; b = lt_modm(r1[1], pb); r[1] = (r1[1] - pb + (b << 56)); pb = b; - pb += r2[2]; b = lt_modm(r1[2], pb); r[2] = (r1[2] - pb + (b << 56)); pb = b; - pb += r2[3]; b = lt_modm(r1[3], pb); r[3] = (r1[3] - pb + (b << 56)); pb = b; - pb += r2[4]; b = lt_modm(r1[4], pb); r[4] = (r1[4] - pb + (b << 40)); - - reduce256_modm(r); - reduce256_modm(r); -} - - -STATIC void add256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y) { - bignum256modm_element_t c; - - c = x[0] + y[0]; r[0] = c & 0xffffffffffffff; c >>= 56; - c += x[1] + y[1]; r[1] = c & 0xffffffffffffff; c >>= 56; - c += x[2] + y[2]; r[2] = c & 0xffffffffffffff; c >>= 56; - c += x[3] + y[3]; r[3] = c & 0xffffffffffffff; c >>= 56; - c += x[4] + y[4]; r[4] = c; - - reduce256_modm(r); -} - -STATIC void mul256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y) { - bignum256modm q1, r1; - uint128_t c, mul; - bignum256modm_element_t f; - - mul64x64_128(c, x[0], y[0]) - f = lo128(c); r1[0] = f & 0xffffffffffffff; shr128(f, c, 56); - mul64x64_128(c, x[0], y[1]) add128_64(c, f) mul64x64_128(mul, x[1], y[0]) add128(c, mul) - f = lo128(c); r1[1] = f & 0xffffffffffffff; shr128(f, c, 56); - mul64x64_128(c, x[0], y[2]) add128_64(c, f) mul64x64_128(mul, x[2], y[0]) add128(c, mul) mul64x64_128(mul, x[1], y[1]) add128(c, mul) - f = lo128(c); r1[2] = f & 0xffffffffffffff; shr128(f, c, 56); - mul64x64_128(c, x[0], y[3]) add128_64(c, f) mul64x64_128(mul, x[3], y[0]) add128(c, mul) mul64x64_128(mul, x[1], y[2]) add128(c, mul) mul64x64_128(mul, x[2], y[1]) add128(c, mul) - f = lo128(c); r1[3] = f & 0xffffffffffffff; shr128(f, c, 56); - mul64x64_128(c, x[0], y[4]) add128_64(c, f) mul64x64_128(mul, x[4], y[0]) add128(c, mul) mul64x64_128(mul, x[3], y[1]) add128(c, mul) mul64x64_128(mul, x[1], y[3]) add128(c, mul) mul64x64_128(mul, x[2], y[2]) add128(c, mul) - f = lo128(c); r1[4] = f & 0x0000ffffffffff; q1[0] = (f >> 24) & 0xffffffff; shr128(f, c, 56); - mul64x64_128(c, x[4], y[1]) add128_64(c, f) mul64x64_128(mul, x[1], y[4]) add128(c, mul) mul64x64_128(mul, x[2], y[3]) add128(c, mul) mul64x64_128(mul, x[3], y[2]) add128(c, mul) - f = lo128(c); q1[0] |= (f << 32) & 0xffffffffffffff; q1[1] = (f >> 24) & 0xffffffff; shr128(f, c, 56); - mul64x64_128(c, x[4], y[2]) add128_64(c, f) mul64x64_128(mul, x[2], y[4]) add128(c, mul) mul64x64_128(mul, x[3], y[3]) add128(c, mul) - f = lo128(c); q1[1] |= (f << 32) & 0xffffffffffffff; q1[2] = (f >> 24) & 0xffffffff; shr128(f, c, 56); - mul64x64_128(c, x[4], y[3]) add128_64(c, f) mul64x64_128(mul, x[3], y[4]) add128(c, mul) - f = lo128(c); q1[2] |= (f << 32) & 0xffffffffffffff; q1[3] = (f >> 24) & 0xffffffff; shr128(f, c, 56); - mul64x64_128(c, x[4], y[4]) add128_64(c, f) - f = lo128(c); q1[3] |= (f << 32) & 0xffffffffffffff; q1[4] = (f >> 24) & 0xffffffff; shr128(f, c, 56); - q1[4] |= (f << 32); - - barrett_reduce256_modm(r, q1, r1); -} - -STATIC void expand256_modm(bignum256modm out, const unsigned char *in, size_t len) { - unsigned char work[64] = {0}; - bignum256modm_element_t x[16]; - bignum256modm q1; - - memcpy(work, in, len); - x[0] = U8TO64_LE(work + 0); - x[1] = U8TO64_LE(work + 8); - x[2] = U8TO64_LE(work + 16); - x[3] = U8TO64_LE(work + 24); - x[4] = U8TO64_LE(work + 32); - x[5] = U8TO64_LE(work + 40); - x[6] = U8TO64_LE(work + 48); - x[7] = U8TO64_LE(work + 56); - - /* r1 = (x mod 256^(32+1)) = x mod (2^8)(31+1) = x & ((1 << 264) - 1) */ - out[0] = ( x[0]) & 0xffffffffffffff; - out[1] = ((x[ 0] >> 56) | (x[ 1] << 8)) & 0xffffffffffffff; - out[2] = ((x[ 1] >> 48) | (x[ 2] << 16)) & 0xffffffffffffff; - out[3] = ((x[ 2] >> 40) | (x[ 3] << 24)) & 0xffffffffffffff; - out[4] = ((x[ 3] >> 32) | (x[ 4] << 32)) & 0x0000ffffffffff; - - /* under 252 bits, no need to reduce */ - if (len < 32) - return; - - /* q1 = x >> 248 = 264 bits */ - q1[0] = ((x[ 3] >> 56) | (x[ 4] << 8)) & 0xffffffffffffff; - q1[1] = ((x[ 4] >> 48) | (x[ 5] << 16)) & 0xffffffffffffff; - q1[2] = ((x[ 5] >> 40) | (x[ 6] << 24)) & 0xffffffffffffff; - q1[3] = ((x[ 6] >> 32) | (x[ 7] << 32)) & 0xffffffffffffff; - q1[4] = ((x[ 7] >> 24) ); - - barrett_reduce256_modm(out, q1, out); -} - -STATIC void expand_raw256_modm(bignum256modm out, const unsigned char in[32]) { - bignum256modm_element_t x[4]; - - x[0] = U8TO64_LE(in + 0); - x[1] = U8TO64_LE(in + 8); - x[2] = U8TO64_LE(in + 16); - x[3] = U8TO64_LE(in + 24); - - out[0] = ( x[0]) & 0xffffffffffffff; - out[1] = ((x[ 0] >> 56) | (x[ 1] << 8)) & 0xffffffffffffff; - out[2] = ((x[ 1] >> 48) | (x[ 2] << 16)) & 0xffffffffffffff; - out[3] = ((x[ 2] >> 40) | (x[ 3] << 24)) & 0xffffffffffffff; - out[4] = ((x[ 3] >> 32) ) & 0x000000ffffffff; -} - -STATIC void contract256_modm(unsigned char out[32], const bignum256modm in) { - U64TO8_LE(out + 0, (in[0] ) | (in[1] << 56)); - U64TO8_LE(out + 8, (in[1] >> 8) | (in[2] << 48)); - U64TO8_LE(out + 16, (in[2] >> 16) | (in[3] << 40)); - U64TO8_LE(out + 24, (in[3] >> 24) | (in[4] << 32)); -} - -STATIC void contract256_window4_modm(signed char r[64], const bignum256modm in) { - char carry; - signed char *quads = r; - bignum256modm_element_t i, j, v, m; - - for (i = 0; i < 5; i++) { - v = in[i]; - m = (i == 4) ? 8 : 14; - for (j = 0; j < m; j++) { - *quads++ = (v & 15); - v >>= 4; - } - } - - /* making it signed */ - carry = 0; - for(i = 0; i < 63; i++) { - r[i] += carry; - r[i+1] += (r[i] >> 4); - r[i] &= 15; - carry = (r[i] >> 3); - r[i] -= (carry << 4); - } - r[63] += carry; -} - -STATIC void contract256_slidingwindow_modm(signed char r[256], const bignum256modm s, int windowsize) { - int i,j,k,b; - int m = (1 << (windowsize - 1)) - 1, soplen = 256; - signed char *bits = r; - bignum256modm_element_t v; - - /* first put the binary expansion into r */ - for (i = 0; i < 4; i++) { - v = s[i]; - for (j = 0; j < 56; j++, v >>= 1) - *bits++ = (v & 1); - } - v = s[4]; - for (j = 0; j < 32; j++, v >>= 1) - *bits++ = (v & 1); - - /* Making it sliding window */ - for (j = 0; j < soplen; j++) { - if (!r[j]) - continue; - - for (b = 1; (b < (soplen - j)) && (b <= 6); b++) { - if ((r[j] + (r[j + b] << b)) <= m) { - r[j] += r[j + b] << b; - r[j + b] = 0; - } else if ((r[j] - (r[j + b] << b)) >= -m) { - r[j] -= r[j + b] << b; - for (k = j + b; k < soplen; k++) { - if (!r[k]) { - r[k] = 1; - break; - } - r[k] = 0; - } - } else if (r[j + b]) { - break; - } - } - } -} - -/* - helpers for batch verifcation, are allowed to be vartime -*/ - -/* out = a - b, a must be larger than b */ -STATIC void sub256_modm_batch(bignum256modm out, const bignum256modm a, const bignum256modm b, size_t limbsize) { - size_t i = 0; - bignum256modm_element_t carry = 0; - switch (limbsize) { - case 4: out[i] = (a[i] - b[i]) ; carry = (out[i] >> 63); out[i] &= 0xffffffffffffff; i++; - case 3: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 63); out[i] &= 0xffffffffffffff; i++; - case 2: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 63); out[i] &= 0xffffffffffffff; i++; - case 1: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 63); out[i] &= 0xffffffffffffff; i++; - case 0: - default: out[i] = (a[i] - b[i]) - carry; - } -} - - -/* is a < b */ -STATIC int lt256_modm_batch(const bignum256modm a, const bignum256modm b, size_t limbsize) { - size_t i = 0; - bignum256modm_element_t t, carry = 0; - switch (limbsize) { - case 4: t = (a[i] - b[i]) ; carry = (t >> 63); i++; - case 3: t = (a[i] - b[i]) - carry; carry = (t >> 63); i++; - case 2: t = (a[i] - b[i]) - carry; carry = (t >> 63); i++; - case 1: t = (a[i] - b[i]) - carry; carry = (t >> 63); i++; - case 0: t = (a[i] - b[i]) - carry; carry = (t >> 63); - } - return (int)carry; -} - -/* is a <= b */ -STATIC int lte256_modm_batch(const bignum256modm a, const bignum256modm b, size_t limbsize) { - size_t i = 0; - bignum256modm_element_t t, carry = 0; - switch (limbsize) { - case 4: t = (b[i] - a[i]) ; carry = (t >> 63); i++; - case 3: t = (b[i] - a[i]) - carry; carry = (t >> 63); i++; - case 2: t = (b[i] - a[i]) - carry; carry = (t >> 63); i++; - case 1: t = (b[i] - a[i]) - carry; carry = (t >> 63); i++; - case 0: t = (b[i] - a[i]) - carry; carry = (t >> 63); - } - return (int)!carry; -} - -/* is a == 0 */ -STATIC int iszero256_modm_batch(const bignum256modm a) { - size_t i; - for (i = 0; i < 5; i++) - if (a[i]) - return 0; - return 1; -} - -/* is a == 1 */ -STATIC int isone256_modm_batch(const bignum256modm a) { - size_t i; - for (i = 0; i < 5; i++) - if (a[i] != ((i) ? 0 : 1)) - return 0; - return 1; -} - -/* can a fit in to (at most) 128 bits */ -STATIC int isatmost128bits256_modm_batch(const bignum256modm a) { - uint64_t mask = - ((a[4] ) | /* 32 */ - (a[3] ) | /* 88 */ - (a[2] & 0xffffffffff0000)); - - return (mask == 0); -} From 092d8e7bf1322a4c5e0224a620b2bc650fec3a05 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 28 Mar 2017 18:53:09 +0200 Subject: [PATCH 371/627] merge curve25519 into ed25519, code reuse --- Makefile | 7 +- curve25519-donna/README.md | 107 -- curve25519-donna/curve25519-donna-32bit.h | 466 -------- curve25519-donna/curve25519-donna-64bit.h | 345 ------ curve25519-donna/curve25519-donna-common.h | 43 - .../curve25519-donna-portable-identify.h | 103 -- curve25519-donna/curve25519-donna-portable.h | 94 -- .../curve25519-donna-scalarmult-sse2.h | 65 -- curve25519-donna/curve25519-donna-sse2.h | 1009 ----------------- curve25519-donna/curve25519-donna.h | 32 - ed25519-donna/curve25519-donna-32bit.h | 48 +- .../curve25519-donna-scalarmult-base.h | 0 ed25519-donna/curve25519-donna.h | 9 + .../curve25519.c | 0 .../curve25519.h | 0 15 files changed, 43 insertions(+), 2285 deletions(-) delete mode 100644 curve25519-donna/README.md delete mode 100644 curve25519-donna/curve25519-donna-32bit.h delete mode 100644 curve25519-donna/curve25519-donna-64bit.h delete mode 100644 curve25519-donna/curve25519-donna-common.h delete mode 100644 curve25519-donna/curve25519-donna-portable-identify.h delete mode 100644 curve25519-donna/curve25519-donna-portable.h delete mode 100644 curve25519-donna/curve25519-donna-scalarmult-sse2.h delete mode 100644 curve25519-donna/curve25519-donna-sse2.h delete mode 100644 curve25519-donna/curve25519-donna.h rename {curve25519-donna => ed25519-donna}/curve25519-donna-scalarmult-base.h (100%) create mode 100644 ed25519-donna/curve25519-donna.h rename {curve25519-donna => ed25519-donna}/curve25519.c (100%) rename {curve25519-donna => ed25519-donna}/curve25519.h (100%) diff --git a/Makefile b/Makefile index 65275c370..bcd923695 100644 --- a/Makefile +++ b/Makefile @@ -26,7 +26,7 @@ CFLAGS += $(OPTFLAGS) \ # disable sequence point warning because of AES code CFLAGS += -Wno-sequence-point -CFLAGS += -Ied25519-donna -Icurve25519-donna -I. +CFLAGS += -Ied25519-donna -I. CFLAGS += -DUSE_ETHEREUM=1 CFLAGS += -DUSE_GRAPHENE=1 @@ -42,8 +42,7 @@ SRCS += ripemd160.c SRCS += sha2.c SRCS += sha3.c SRCS += aescrypt.c aeskey.c aestab.c aes_modes.c -SRCS += ed25519-donna/ed25519.c -SRCS += curve25519-donna/curve25519.c +SRCS += ed25519-donna/ed25519.c ed25519-donna/curve25519.c SRCS += blake2b.c blake2s.c OBJS = $(SRCS:.c=.o) @@ -80,5 +79,5 @@ tools/bip39bruteforce: tools/bip39bruteforce.o $(OBJS) $(CC) tools/bip39bruteforce.o $(OBJS) -o tools/bip39bruteforce clean: - rm -f *.o ed25519-donna/*.o curve25519-donna/*.o tests test_speed test-openssl libtrezor-crypto.so + rm -f *.o ed25519-donna/*.o tests test_speed test-openssl libtrezor-crypto.so rm -f tools/*.o tools/xpubaddrgen tools/mktable tools/bip39bruteforce diff --git a/curve25519-donna/README.md b/curve25519-donna/README.md deleted file mode 100644 index 4d7dfb7af..000000000 --- a/curve25519-donna/README.md +++ /dev/null @@ -1,107 +0,0 @@ -[curve25519](http://cr.yp.to/ecdh.html) is an elliptic curve, developed by -[Dan Bernstein](http://cr.yp.to/djb.html), for fast -[Diffie-Hellman](http://en.wikipedia.org/wiki/Diffie-Hellman) key agreement. -DJB's [original implementation](http://cr.yp.to/ecdh.html) was written in a -language of his own devising called [qhasm](http://cr.yp.to/qhasm.html). -The original qhasm source isn't available, only the x86 32-bit assembly output. - -This project provides performant, portable 32-bit & 64-bit implementations. -All implementations are of course constant time in regard to secret data. - -#### Performance - -Compilers versions are gcc 4.6.3, icc 13.1.1, clang 3.4-1~exp1. - -Counts are in thousands of cycles. - -Note that SSE2 performance may be less impressive on AMD & older CPUs with slower SSE ops! - -##### E5200 @ 2.5ghz, march=core2 - - - - - - - - - -
Versiongcciccclang
64-bit SSE2 278k 265k 302k
64-bit 273k 271k 377k
32-bit SSE2 304k 289k 317k
32-bit 1417k 845k 981k
- -##### E3-1270 @ 3.4ghz, march=corei7-avx - - - - - - - - - -
Versiongcciccclang
64-bit 201k 192k 233k
64-bit SSE2 201k 201k 261k
32-bit SSE2 238k 225k 250k
32-bit 1293k 822k 848k
- -#### Compilation - -No configuration is needed. - -##### 32-bit - - gcc curve25519.c -m32 -O3 -c - -##### 64-bit - - gcc curve25519.c -m64 -O3 -c - -##### SSE2 - - gcc curve25519.c -m32 -O3 -c -DCURVE25519_SSE2 -msse2 - gcc curve25519.c -m64 -O3 -c -DCURVE25519_SSE2 - -clang, icc, and msvc are also supported - -##### Named Versions - -Define CURVE25519_SUFFIX to append a suffix to public functions, e.g. -`-DCURVE25519_SUFFIX=_sse2` to create curve25519_donna_sse2 and -curve25519_donna_basepoint_sse2. - -#### Usage - -To use the code, link against `curve25519.o` and: - - #include "curve25519.h" - -To generate a private/secret key, generate 32 cryptographically random bytes: - - curve25519_key sk; - randombytes(sk, sizeof(curve25519_key)); - -Manual clamping is not needed, and it is actually not possible to use unclamped -keys due to the code taking advantage of the clamped bits internally. - -To generate the public key from the private/secret key: - - curve25519_key pk; - curve25519_donna_basepoint(pk, sk); - -To generate a shared key with your private/secret key and someone elses public key: - - curve25519_key shared; - curve25519_donna(shared, mysk, yourpk); - -And hash `shared` with a cryptographic hash before using, or e.g. pass `shared` through -HSalsa20/HChacha as NaCl does. - -#### Testing - -Fuzzing against a reference implemenation is now available. See [fuzz/README](fuzz/README.md). - -Building `curve25519.c` and linking with `test.c` will run basic sanity tests and benchmark curve25519_donna. - -#### Papers - -[djb's curve25519 paper](http://cr.yp.to/ecdh/curve25519-20060209.pdf) - -#### License - -Public Domain, or MIT \ No newline at end of file diff --git a/curve25519-donna/curve25519-donna-32bit.h b/curve25519-donna/curve25519-donna-32bit.h deleted file mode 100644 index 5ef91a202..000000000 --- a/curve25519-donna/curve25519-donna-32bit.h +++ /dev/null @@ -1,466 +0,0 @@ -typedef uint32_t bignum25519[10]; - -static const uint32_t reduce_mask_26 = (1 << 26) - 1; -static const uint32_t reduce_mask_25 = (1 << 25) - 1; - -/* out = in */ -DONNA_INLINE static void -curve25519_copy(bignum25519 out, const bignum25519 in) { - out[0] = in[0]; - out[1] = in[1]; - out[2] = in[2]; - out[3] = in[3]; - out[4] = in[4]; - out[5] = in[5]; - out[6] = in[6]; - out[7] = in[7]; - out[8] = in[8]; - out[9] = in[9]; -} - -/* out = a + b */ -DONNA_INLINE static void -curve25519_add(bignum25519 out, const bignum25519 a, const bignum25519 b) { - out[0] = a[0] + b[0]; - out[1] = a[1] + b[1]; - out[2] = a[2] + b[2]; - out[3] = a[3] + b[3]; - out[4] = a[4] + b[4]; - out[5] = a[5] + b[5]; - out[6] = a[6] + b[6]; - out[7] = a[7] + b[7]; - out[8] = a[8] + b[8]; - out[9] = a[9] + b[9]; -} - -/* out = a - b */ -DONNA_INLINE static void -curve25519_sub(bignum25519 out, const bignum25519 a, const bignum25519 b) { - uint32_t c; - out[0] = 0x7ffffda + a[0] - b[0] ; c = (out[0] >> 26); out[0] &= reduce_mask_26; - out[1] = 0x3fffffe + a[1] - b[1] + c; c = (out[1] >> 25); out[1] &= reduce_mask_25; - out[2] = 0x7fffffe + a[2] - b[2] + c; c = (out[2] >> 26); out[2] &= reduce_mask_26; - out[3] = 0x3fffffe + a[3] - b[3] + c; c = (out[3] >> 25); out[3] &= reduce_mask_25; - out[4] = 0x7fffffe + a[4] - b[4] + c; c = (out[4] >> 26); out[4] &= reduce_mask_26; - out[5] = 0x3fffffe + a[5] - b[5] + c; c = (out[5] >> 25); out[5] &= reduce_mask_25; - out[6] = 0x7fffffe + a[6] - b[6] + c; c = (out[6] >> 26); out[6] &= reduce_mask_26; - out[7] = 0x3fffffe + a[7] - b[7] + c; c = (out[7] >> 25); out[7] &= reduce_mask_25; - out[8] = 0x7fffffe + a[8] - b[8] + c; c = (out[8] >> 26); out[8] &= reduce_mask_26; - out[9] = 0x3fffffe + a[9] - b[9] + c; c = (out[9] >> 25); out[9] &= reduce_mask_25; - out[0] += 19 * c; -} - -/* out = in * scalar */ -DONNA_INLINE static void -curve25519_scalar_product(bignum25519 out, const bignum25519 in, const uint32_t scalar) { - uint64_t a; - uint32_t c; - a = mul32x32_64(in[0], scalar); out[0] = (uint32_t)a & reduce_mask_26; c = (uint32_t)(a >> 26); - a = mul32x32_64(in[1], scalar) + c; out[1] = (uint32_t)a & reduce_mask_25; c = (uint32_t)(a >> 25); - a = mul32x32_64(in[2], scalar) + c; out[2] = (uint32_t)a & reduce_mask_26; c = (uint32_t)(a >> 26); - a = mul32x32_64(in[3], scalar) + c; out[3] = (uint32_t)a & reduce_mask_25; c = (uint32_t)(a >> 25); - a = mul32x32_64(in[4], scalar) + c; out[4] = (uint32_t)a & reduce_mask_26; c = (uint32_t)(a >> 26); - a = mul32x32_64(in[5], scalar) + c; out[5] = (uint32_t)a & reduce_mask_25; c = (uint32_t)(a >> 25); - a = mul32x32_64(in[6], scalar) + c; out[6] = (uint32_t)a & reduce_mask_26; c = (uint32_t)(a >> 26); - a = mul32x32_64(in[7], scalar) + c; out[7] = (uint32_t)a & reduce_mask_25; c = (uint32_t)(a >> 25); - a = mul32x32_64(in[8], scalar) + c; out[8] = (uint32_t)a & reduce_mask_26; c = (uint32_t)(a >> 26); - a = mul32x32_64(in[9], scalar) + c; out[9] = (uint32_t)a & reduce_mask_25; c = (uint32_t)(a >> 25); - out[0] += c * 19; -} - -/* out = a * b */ -DONNA_INLINE static void -curve25519_mul(bignum25519 out, const bignum25519 a, const bignum25519 b) { - uint32_t r0,r1,r2,r3,r4,r5,r6,r7,r8,r9; - uint32_t s0,s1,s2,s3,s4,s5,s6,s7,s8,s9; - uint64_t m0,m1,m2,m3,m4,m5,m6,m7,m8,m9,c; - uint32_t p; - - r0 = b[0]; - r1 = b[1]; - r2 = b[2]; - r3 = b[3]; - r4 = b[4]; - r5 = b[5]; - r6 = b[6]; - r7 = b[7]; - r8 = b[8]; - r9 = b[9]; - - s0 = a[0]; - s1 = a[1]; - s2 = a[2]; - s3 = a[3]; - s4 = a[4]; - s5 = a[5]; - s6 = a[6]; - s7 = a[7]; - s8 = a[8]; - s9 = a[9]; - - m1 = mul32x32_64(r0, s1) + mul32x32_64(r1, s0); - m3 = mul32x32_64(r0, s3) + mul32x32_64(r1, s2) + mul32x32_64(r2, s1) + mul32x32_64(r3, s0); - m5 = mul32x32_64(r0, s5) + mul32x32_64(r1, s4) + mul32x32_64(r2, s3) + mul32x32_64(r3, s2) + mul32x32_64(r4, s1) + mul32x32_64(r5, s0); - m7 = mul32x32_64(r0, s7) + mul32x32_64(r1, s6) + mul32x32_64(r2, s5) + mul32x32_64(r3, s4) + mul32x32_64(r4, s3) + mul32x32_64(r5, s2) + mul32x32_64(r6, s1) + mul32x32_64(r7, s0); - m9 = mul32x32_64(r0, s9) + mul32x32_64(r1, s8) + mul32x32_64(r2, s7) + mul32x32_64(r3, s6) + mul32x32_64(r4, s5) + mul32x32_64(r5, s4) + mul32x32_64(r6, s3) + mul32x32_64(r7, s2) + mul32x32_64(r8, s1) + mul32x32_64(r9, s0); - - r1 *= 2; - r3 *= 2; - r5 *= 2; - r7 *= 2; - - m0 = mul32x32_64(r0, s0); - m2 = mul32x32_64(r0, s2) + mul32x32_64(r1, s1) + mul32x32_64(r2, s0); - m4 = mul32x32_64(r0, s4) + mul32x32_64(r1, s3) + mul32x32_64(r2, s2) + mul32x32_64(r3, s1) + mul32x32_64(r4, s0); - m6 = mul32x32_64(r0, s6) + mul32x32_64(r1, s5) + mul32x32_64(r2, s4) + mul32x32_64(r3, s3) + mul32x32_64(r4, s2) + mul32x32_64(r5, s1) + mul32x32_64(r6, s0); - m8 = mul32x32_64(r0, s8) + mul32x32_64(r1, s7) + mul32x32_64(r2, s6) + mul32x32_64(r3, s5) + mul32x32_64(r4, s4) + mul32x32_64(r5, s3) + mul32x32_64(r6, s2) + mul32x32_64(r7, s1) + mul32x32_64(r8, s0); - - r1 *= 19; - r2 *= 19; - r3 = (r3 / 2) * 19; - r4 *= 19; - r5 = (r5 / 2) * 19; - r6 *= 19; - r7 = (r7 / 2) * 19; - r8 *= 19; - r9 *= 19; - - m1 += (mul32x32_64(r9, s2) + mul32x32_64(r8, s3) + mul32x32_64(r7, s4) + mul32x32_64(r6, s5) + mul32x32_64(r5, s6) + mul32x32_64(r4, s7) + mul32x32_64(r3, s8) + mul32x32_64(r2, s9)); - m3 += (mul32x32_64(r9, s4) + mul32x32_64(r8, s5) + mul32x32_64(r7, s6) + mul32x32_64(r6, s7) + mul32x32_64(r5, s8) + mul32x32_64(r4, s9)); - m5 += (mul32x32_64(r9, s6) + mul32x32_64(r8, s7) + mul32x32_64(r7, s8) + mul32x32_64(r6, s9)); - m7 += (mul32x32_64(r9, s8) + mul32x32_64(r8, s9)); - - r3 *= 2; - r5 *= 2; - r7 *= 2; - r9 *= 2; - - m0 += (mul32x32_64(r9, s1) + mul32x32_64(r8, s2) + mul32x32_64(r7, s3) + mul32x32_64(r6, s4) + mul32x32_64(r5, s5) + mul32x32_64(r4, s6) + mul32x32_64(r3, s7) + mul32x32_64(r2, s8) + mul32x32_64(r1, s9)); - m2 += (mul32x32_64(r9, s3) + mul32x32_64(r8, s4) + mul32x32_64(r7, s5) + mul32x32_64(r6, s6) + mul32x32_64(r5, s7) + mul32x32_64(r4, s8) + mul32x32_64(r3, s9)); - m4 += (mul32x32_64(r9, s5) + mul32x32_64(r8, s6) + mul32x32_64(r7, s7) + mul32x32_64(r6, s8) + mul32x32_64(r5, s9)); - m6 += (mul32x32_64(r9, s7) + mul32x32_64(r8, s8) + mul32x32_64(r7, s9)); - m8 += (mul32x32_64(r9, s9)); - - r0 = (uint32_t)m0 & reduce_mask_26; c = (m0 >> 26); - m1 += c; r1 = (uint32_t)m1 & reduce_mask_25; c = (m1 >> 25); - m2 += c; r2 = (uint32_t)m2 & reduce_mask_26; c = (m2 >> 26); - m3 += c; r3 = (uint32_t)m3 & reduce_mask_25; c = (m3 >> 25); - m4 += c; r4 = (uint32_t)m4 & reduce_mask_26; c = (m4 >> 26); - m5 += c; r5 = (uint32_t)m5 & reduce_mask_25; c = (m5 >> 25); - m6 += c; r6 = (uint32_t)m6 & reduce_mask_26; c = (m6 >> 26); - m7 += c; r7 = (uint32_t)m7 & reduce_mask_25; c = (m7 >> 25); - m8 += c; r8 = (uint32_t)m8 & reduce_mask_26; c = (m8 >> 26); - m9 += c; r9 = (uint32_t)m9 & reduce_mask_25; p = (uint32_t)(m9 >> 25); - m0 = r0 + mul32x32_64(p,19); r0 = (uint32_t)m0 & reduce_mask_26; p = (uint32_t)(m0 >> 26); - r1 += p; - - out[0] = r0; - out[1] = r1; - out[2] = r2; - out[3] = r3; - out[4] = r4; - out[5] = r5; - out[6] = r6; - out[7] = r7; - out[8] = r8; - out[9] = r9; -} - -/* out = in * in */ -DONNA_INLINE static void -curve25519_square(bignum25519 out, const bignum25519 in) { - uint32_t r0,r1,r2,r3,r4,r5,r6,r7,r8,r9; - uint32_t d6,d7,d8,d9; - uint64_t m0,m1,m2,m3,m4,m5,m6,m7,m8,m9,c; - uint32_t p; - - r0 = in[0]; - r1 = in[1]; - r2 = in[2]; - r3 = in[3]; - r4 = in[4]; - r5 = in[5]; - r6 = in[6]; - r7 = in[7]; - r8 = in[8]; - r9 = in[9]; - - - m0 = mul32x32_64(r0, r0); - r0 *= 2; - m1 = mul32x32_64(r0, r1); - m2 = mul32x32_64(r0, r2) + mul32x32_64(r1, r1 * 2); - r1 *= 2; - m3 = mul32x32_64(r0, r3) + mul32x32_64(r1, r2 ); - m4 = mul32x32_64(r0, r4) + mul32x32_64(r1, r3 * 2) + mul32x32_64(r2, r2); - r2 *= 2; - m5 = mul32x32_64(r0, r5) + mul32x32_64(r1, r4 ) + mul32x32_64(r2, r3); - m6 = mul32x32_64(r0, r6) + mul32x32_64(r1, r5 * 2) + mul32x32_64(r2, r4) + mul32x32_64(r3, r3 * 2); - r3 *= 2; - m7 = mul32x32_64(r0, r7) + mul32x32_64(r1, r6 ) + mul32x32_64(r2, r5) + mul32x32_64(r3, r4 ); - m8 = mul32x32_64(r0, r8) + mul32x32_64(r1, r7 * 2) + mul32x32_64(r2, r6) + mul32x32_64(r3, r5 * 2) + mul32x32_64(r4, r4 ); - m9 = mul32x32_64(r0, r9) + mul32x32_64(r1, r8 ) + mul32x32_64(r2, r7) + mul32x32_64(r3, r6 ) + mul32x32_64(r4, r5 * 2); - - d6 = r6 * 19; - d7 = r7 * 2 * 19; - d8 = r8 * 19; - d9 = r9 * 2 * 19; - - m0 += (mul32x32_64(d9, r1 ) + mul32x32_64(d8, r2 ) + mul32x32_64(d7, r3 ) + mul32x32_64(d6, r4 * 2) + mul32x32_64(r5, r5 * 2 * 19)); - m1 += (mul32x32_64(d9, r2 / 2) + mul32x32_64(d8, r3 ) + mul32x32_64(d7, r4 ) + mul32x32_64(d6, r5 * 2)); - m2 += (mul32x32_64(d9, r3 ) + mul32x32_64(d8, r4 * 2) + mul32x32_64(d7, r5 * 2) + mul32x32_64(d6, r6 )); - m3 += (mul32x32_64(d9, r4 ) + mul32x32_64(d8, r5 * 2) + mul32x32_64(d7, r6 )); - m4 += (mul32x32_64(d9, r5 * 2) + mul32x32_64(d8, r6 * 2) + mul32x32_64(d7, r7 )); - m5 += (mul32x32_64(d9, r6 ) + mul32x32_64(d8, r7 * 2)); - m6 += (mul32x32_64(d9, r7 * 2) + mul32x32_64(d8, r8 )); - m7 += (mul32x32_64(d9, r8 )); - m8 += (mul32x32_64(d9, r9 )); - - r0 = (uint32_t)m0 & reduce_mask_26; c = (m0 >> 26); - m1 += c; r1 = (uint32_t)m1 & reduce_mask_25; c = (m1 >> 25); - m2 += c; r2 = (uint32_t)m2 & reduce_mask_26; c = (m2 >> 26); - m3 += c; r3 = (uint32_t)m3 & reduce_mask_25; c = (m3 >> 25); - m4 += c; r4 = (uint32_t)m4 & reduce_mask_26; c = (m4 >> 26); - m5 += c; r5 = (uint32_t)m5 & reduce_mask_25; c = (m5 >> 25); - m6 += c; r6 = (uint32_t)m6 & reduce_mask_26; c = (m6 >> 26); - m7 += c; r7 = (uint32_t)m7 & reduce_mask_25; c = (m7 >> 25); - m8 += c; r8 = (uint32_t)m8 & reduce_mask_26; c = (m8 >> 26); - m9 += c; r9 = (uint32_t)m9 & reduce_mask_25; p = (uint32_t)(m9 >> 25); - m0 = r0 + mul32x32_64(p,19); r0 = (uint32_t)m0 & reduce_mask_26; p = (uint32_t)(m0 >> 26); - r1 += p; - - out[0] = r0; - out[1] = r1; - out[2] = r2; - out[3] = r3; - out[4] = r4; - out[5] = r5; - out[6] = r6; - out[7] = r7; - out[8] = r8; - out[9] = r9; -} - -/* out = in^(2 * count) */ -static void -curve25519_square_times(bignum25519 out, const bignum25519 in, int count) { - uint32_t r0,r1,r2,r3,r4,r5,r6,r7,r8,r9; - uint32_t d6,d7,d8,d9; - uint64_t m0,m1,m2,m3,m4,m5,m6,m7,m8,m9,c; - uint32_t p; - - r0 = in[0]; - r1 = in[1]; - r2 = in[2]; - r3 = in[3]; - r4 = in[4]; - r5 = in[5]; - r6 = in[6]; - r7 = in[7]; - r8 = in[8]; - r9 = in[9]; - - do { - m0 = mul32x32_64(r0, r0); - r0 *= 2; - m1 = mul32x32_64(r0, r1); - m2 = mul32x32_64(r0, r2) + mul32x32_64(r1, r1 * 2); - r1 *= 2; - m3 = mul32x32_64(r0, r3) + mul32x32_64(r1, r2 ); - m4 = mul32x32_64(r0, r4) + mul32x32_64(r1, r3 * 2) + mul32x32_64(r2, r2); - r2 *= 2; - m5 = mul32x32_64(r0, r5) + mul32x32_64(r1, r4 ) + mul32x32_64(r2, r3); - m6 = mul32x32_64(r0, r6) + mul32x32_64(r1, r5 * 2) + mul32x32_64(r2, r4) + mul32x32_64(r3, r3 * 2); - r3 *= 2; - m7 = mul32x32_64(r0, r7) + mul32x32_64(r1, r6 ) + mul32x32_64(r2, r5) + mul32x32_64(r3, r4 ); - m8 = mul32x32_64(r0, r8) + mul32x32_64(r1, r7 * 2) + mul32x32_64(r2, r6) + mul32x32_64(r3, r5 * 2) + mul32x32_64(r4, r4 ); - m9 = mul32x32_64(r0, r9) + mul32x32_64(r1, r8 ) + mul32x32_64(r2, r7) + mul32x32_64(r3, r6 ) + mul32x32_64(r4, r5 * 2); - - d6 = r6 * 19; - d7 = r7 * 2 * 19; - d8 = r8 * 19; - d9 = r9 * 2 * 19; - - m0 += (mul32x32_64(d9, r1 ) + mul32x32_64(d8, r2 ) + mul32x32_64(d7, r3 ) + mul32x32_64(d6, r4 * 2) + mul32x32_64(r5, r5 * 2 * 19)); - m1 += (mul32x32_64(d9, r2 / 2) + mul32x32_64(d8, r3 ) + mul32x32_64(d7, r4 ) + mul32x32_64(d6, r5 * 2)); - m2 += (mul32x32_64(d9, r3 ) + mul32x32_64(d8, r4 * 2) + mul32x32_64(d7, r5 * 2) + mul32x32_64(d6, r6 )); - m3 += (mul32x32_64(d9, r4 ) + mul32x32_64(d8, r5 * 2) + mul32x32_64(d7, r6 )); - m4 += (mul32x32_64(d9, r5 * 2) + mul32x32_64(d8, r6 * 2) + mul32x32_64(d7, r7 )); - m5 += (mul32x32_64(d9, r6 ) + mul32x32_64(d8, r7 * 2)); - m6 += (mul32x32_64(d9, r7 * 2) + mul32x32_64(d8, r8 )); - m7 += (mul32x32_64(d9, r8 )); - m8 += (mul32x32_64(d9, r9 )); - - r0 = (uint32_t)m0 & reduce_mask_26; c = (m0 >> 26); - m1 += c; r1 = (uint32_t)m1 & reduce_mask_25; c = (m1 >> 25); - m2 += c; r2 = (uint32_t)m2 & reduce_mask_26; c = (m2 >> 26); - m3 += c; r3 = (uint32_t)m3 & reduce_mask_25; c = (m3 >> 25); - m4 += c; r4 = (uint32_t)m4 & reduce_mask_26; c = (m4 >> 26); - m5 += c; r5 = (uint32_t)m5 & reduce_mask_25; c = (m5 >> 25); - m6 += c; r6 = (uint32_t)m6 & reduce_mask_26; c = (m6 >> 26); - m7 += c; r7 = (uint32_t)m7 & reduce_mask_25; c = (m7 >> 25); - m8 += c; r8 = (uint32_t)m8 & reduce_mask_26; c = (m8 >> 26); - m9 += c; r9 = (uint32_t)m9 & reduce_mask_25; p = (uint32_t)(m9 >> 25); - m0 = r0 + mul32x32_64(p,19); r0 = (uint32_t)m0 & reduce_mask_26; p = (uint32_t)(m0 >> 26); - r1 += p; - } while (--count); - - out[0] = r0; - out[1] = r1; - out[2] = r2; - out[3] = r3; - out[4] = r4; - out[5] = r5; - out[6] = r6; - out[7] = r7; - out[8] = r8; - out[9] = r9; -} - - -/* Take a little-endian, 32-byte number and expand it into polynomial form */ -static void -curve25519_expand(bignum25519 out, const unsigned char in[32]) { - static const union { uint8_t b[2]; uint16_t s; } endian_check = {{1,0}}; - uint32_t x0,x1,x2,x3,x4,x5,x6,x7; - - if (endian_check.s == 1) { - x0 = *(uint32_t *)(in + 0); - x1 = *(uint32_t *)(in + 4); - x2 = *(uint32_t *)(in + 8); - x3 = *(uint32_t *)(in + 12); - x4 = *(uint32_t *)(in + 16); - x5 = *(uint32_t *)(in + 20); - x6 = *(uint32_t *)(in + 24); - x7 = *(uint32_t *)(in + 28); - } else { - #define F(s) \ - ((((uint32_t)in[s + 0]) ) | \ - (((uint32_t)in[s + 1]) << 8) | \ - (((uint32_t)in[s + 2]) << 16) | \ - (((uint32_t)in[s + 3]) << 24)) - x0 = F(0); - x1 = F(4); - x2 = F(8); - x3 = F(12); - x4 = F(16); - x5 = F(20); - x6 = F(24); - x7 = F(28); - #undef F - } - - out[0] = ( x0 ) & reduce_mask_26; - out[1] = ((((uint64_t)x1 << 32) | x0) >> 26) & reduce_mask_25; - out[2] = ((((uint64_t)x2 << 32) | x1) >> 19) & reduce_mask_26; - out[3] = ((((uint64_t)x3 << 32) | x2) >> 13) & reduce_mask_25; - out[4] = (( x3) >> 6) & reduce_mask_26; - out[5] = ( x4 ) & reduce_mask_25; - out[6] = ((((uint64_t)x5 << 32) | x4) >> 25) & reduce_mask_26; - out[7] = ((((uint64_t)x6 << 32) | x5) >> 19) & reduce_mask_25; - out[8] = ((((uint64_t)x7 << 32) | x6) >> 12) & reduce_mask_26; - out[9] = (( x7) >> 6) & reduce_mask_25; /* ignore the top bit */ -} - -/* Take a fully reduced polynomial form number and contract it into a little-endian, 32-byte array */ -static void -curve25519_contract(unsigned char out[32], const bignum25519 in) { - bignum25519 f; - curve25519_copy(f, in); - - #define carry_pass() \ - f[1] += f[0] >> 26; f[0] &= reduce_mask_26; \ - f[2] += f[1] >> 25; f[1] &= reduce_mask_25; \ - f[3] += f[2] >> 26; f[2] &= reduce_mask_26; \ - f[4] += f[3] >> 25; f[3] &= reduce_mask_25; \ - f[5] += f[4] >> 26; f[4] &= reduce_mask_26; \ - f[6] += f[5] >> 25; f[5] &= reduce_mask_25; \ - f[7] += f[6] >> 26; f[6] &= reduce_mask_26; \ - f[8] += f[7] >> 25; f[7] &= reduce_mask_25; \ - f[9] += f[8] >> 26; f[8] &= reduce_mask_26; - - #define carry_pass_full() \ - carry_pass() \ - f[0] += 19 * (f[9] >> 25); f[9] &= reduce_mask_25; - - #define carry_pass_final() \ - carry_pass() \ - f[9] &= reduce_mask_25; - - carry_pass_full() - carry_pass_full() - - /* now t is between 0 and 2^255-1, properly carried. */ - /* case 1: between 0 and 2^255-20. case 2: between 2^255-19 and 2^255-1. */ - f[0] += 19; - carry_pass_full() - - /* now between 19 and 2^255-1 in both cases, and offset by 19. */ - f[0] += (1 << 26) - 19; - f[1] += (1 << 25) - 1; - f[2] += (1 << 26) - 1; - f[3] += (1 << 25) - 1; - f[4] += (1 << 26) - 1; - f[5] += (1 << 25) - 1; - f[6] += (1 << 26) - 1; - f[7] += (1 << 25) - 1; - f[8] += (1 << 26) - 1; - f[9] += (1 << 25) - 1; - - /* now between 2^255 and 2^256-20, and offset by 2^255. */ - carry_pass_final() - - #undef carry_pass - #undef carry_full - #undef carry_final - - f[1] <<= 2; - f[2] <<= 3; - f[3] <<= 5; - f[4] <<= 6; - f[6] <<= 1; - f[7] <<= 3; - f[8] <<= 4; - f[9] <<= 6; - - #define F(i, s) \ - out[s+0] |= (unsigned char )(f[i] & 0xff); \ - out[s+1] = (unsigned char )((f[i] >> 8) & 0xff); \ - out[s+2] = (unsigned char )((f[i] >> 16) & 0xff); \ - out[s+3] = (unsigned char )((f[i] >> 24) & 0xff); - - out[0] = 0; - out[16] = 0; - F(0,0); - F(1,3); - F(2,6); - F(3,9); - F(4,12); - F(5,16); - F(6,19); - F(7,22); - F(8,25); - F(9,28); - #undef F -} - -/* - * Swap the contents of [qx] and [qpx] iff @swap is non-zero - */ -DONNA_INLINE static void -curve25519_swap_conditional(bignum25519 x, bignum25519 qpx, uint32_t iswap) { - const uint32_t swap = (uint32_t)(-(int32_t)iswap); - uint32_t x0,x1,x2,x3,x4,x5,x6,x7,x8,x9; - - x0 = swap & (x[0] ^ qpx[0]); x[0] ^= x0; qpx[0] ^= x0; - x1 = swap & (x[1] ^ qpx[1]); x[1] ^= x1; qpx[1] ^= x1; - x2 = swap & (x[2] ^ qpx[2]); x[2] ^= x2; qpx[2] ^= x2; - x3 = swap & (x[3] ^ qpx[3]); x[3] ^= x3; qpx[3] ^= x3; - x4 = swap & (x[4] ^ qpx[4]); x[4] ^= x4; qpx[4] ^= x4; - x5 = swap & (x[5] ^ qpx[5]); x[5] ^= x5; qpx[5] ^= x5; - x6 = swap & (x[6] ^ qpx[6]); x[6] ^= x6; qpx[6] ^= x6; - x7 = swap & (x[7] ^ qpx[7]); x[7] ^= x7; qpx[7] ^= x7; - x8 = swap & (x[8] ^ qpx[8]); x[8] ^= x8; qpx[8] ^= x8; - x9 = swap & (x[9] ^ qpx[9]); x[9] ^= x9; qpx[9] ^= x9; -} - diff --git a/curve25519-donna/curve25519-donna-64bit.h b/curve25519-donna/curve25519-donna-64bit.h deleted file mode 100644 index ec4df526b..000000000 --- a/curve25519-donna/curve25519-donna-64bit.h +++ /dev/null @@ -1,345 +0,0 @@ -typedef uint64_t bignum25519[5]; - -static const uint64_t reduce_mask_51 = ((uint64_t)1 << 51) - 1; -static const uint64_t reduce_mask_52 = ((uint64_t)1 << 52) - 1; - -/* out = in */ -DONNA_INLINE static void -curve25519_copy(bignum25519 out, const bignum25519 in) { - out[0] = in[0]; - out[1] = in[1]; - out[2] = in[2]; - out[3] = in[3]; - out[4] = in[4]; -} - -/* out = a + b */ -DONNA_INLINE static void -curve25519_add(bignum25519 out, const bignum25519 a, const bignum25519 b) { - out[0] = a[0] + b[0]; - out[1] = a[1] + b[1]; - out[2] = a[2] + b[2]; - out[3] = a[3] + b[3]; - out[4] = a[4] + b[4]; -} - -static const uint64_t two54m152 = (((uint64_t)1) << 54) - 152; -static const uint64_t two54m8 = (((uint64_t)1) << 54) - 8; - -/* out = a - b */ -DONNA_INLINE static void -curve25519_sub(bignum25519 out, const bignum25519 a, const bignum25519 b) { - out[0] = a[0] + two54m152 - b[0]; - out[1] = a[1] + two54m8 - b[1]; - out[2] = a[2] + two54m8 - b[2]; - out[3] = a[3] + two54m8 - b[3]; - out[4] = a[4] + two54m8 - b[4]; -} - - -/* out = (in * scalar) */ -DONNA_INLINE static void -curve25519_scalar_product(bignum25519 out, const bignum25519 in, const uint64_t scalar) { - uint128_t a; - uint64_t c; - -#if defined(HAVE_NATIVE_UINT128) - a = ((uint128_t) in[0]) * scalar; out[0] = (uint64_t)a & reduce_mask_51; c = (uint64_t)(a >> 51); - a = ((uint128_t) in[1]) * scalar + c; out[1] = (uint64_t)a & reduce_mask_51; c = (uint64_t)(a >> 51); - a = ((uint128_t) in[2]) * scalar + c; out[2] = (uint64_t)a & reduce_mask_51; c = (uint64_t)(a >> 51); - a = ((uint128_t) in[3]) * scalar + c; out[3] = (uint64_t)a & reduce_mask_51; c = (uint64_t)(a >> 51); - a = ((uint128_t) in[4]) * scalar + c; out[4] = (uint64_t)a & reduce_mask_51; c = (uint64_t)(a >> 51); - out[0] += c * 19; -#else - mul64x64_128(a, in[0], scalar) out[0] = lo128(a) & reduce_mask_51; shr128(c, a, 51); - mul64x64_128(a, in[1], scalar) add128_64(a, c) out[1] = lo128(a) & reduce_mask_51; shr128(c, a, 51); - mul64x64_128(a, in[2], scalar) add128_64(a, c) out[2] = lo128(a) & reduce_mask_51; shr128(c, a, 51); - mul64x64_128(a, in[3], scalar) add128_64(a, c) out[3] = lo128(a) & reduce_mask_51; shr128(c, a, 51); - mul64x64_128(a, in[4], scalar) add128_64(a, c) out[4] = lo128(a) & reduce_mask_51; shr128(c, a, 51); - out[0] += c * 19; -#endif -} - -/* out = a * b */ -DONNA_INLINE static void -curve25519_mul(bignum25519 out, const bignum25519 a, const bignum25519 b) { -#if !defined(HAVE_NATIVE_UINT128) - uint128_t mul; -#endif - uint128_t t[5]; - uint64_t r0,r1,r2,r3,r4,s0,s1,s2,s3,s4,c; - - r0 = b[0]; - r1 = b[1]; - r2 = b[2]; - r3 = b[3]; - r4 = b[4]; - - s0 = a[0]; - s1 = a[1]; - s2 = a[2]; - s3 = a[3]; - s4 = a[4]; - -#if defined(HAVE_NATIVE_UINT128) - t[0] = ((uint128_t) r0) * s0; - t[1] = ((uint128_t) r0) * s1 + ((uint128_t) r1) * s0; - t[2] = ((uint128_t) r0) * s2 + ((uint128_t) r2) * s0 + ((uint128_t) r1) * s1; - t[3] = ((uint128_t) r0) * s3 + ((uint128_t) r3) * s0 + ((uint128_t) r1) * s2 + ((uint128_t) r2) * s1; - t[4] = ((uint128_t) r0) * s4 + ((uint128_t) r4) * s0 + ((uint128_t) r3) * s1 + ((uint128_t) r1) * s3 + ((uint128_t) r2) * s2; -#else - mul64x64_128(t[0], r0, s0) - mul64x64_128(t[1], r0, s1) mul64x64_128(mul, r1, s0) add128(t[1], mul) - mul64x64_128(t[2], r0, s2) mul64x64_128(mul, r2, s0) add128(t[2], mul) mul64x64_128(mul, r1, s1) add128(t[2], mul) - mul64x64_128(t[3], r0, s3) mul64x64_128(mul, r3, s0) add128(t[3], mul) mul64x64_128(mul, r1, s2) add128(t[3], mul) mul64x64_128(mul, r2, s1) add128(t[3], mul) - mul64x64_128(t[4], r0, s4) mul64x64_128(mul, r4, s0) add128(t[4], mul) mul64x64_128(mul, r3, s1) add128(t[4], mul) mul64x64_128(mul, r1, s3) add128(t[4], mul) mul64x64_128(mul, r2, s2) add128(t[4], mul) -#endif - - r1 *= 19; - r2 *= 19; - r3 *= 19; - r4 *= 19; - -#if defined(HAVE_NATIVE_UINT128) - t[0] += ((uint128_t) r4) * s1 + ((uint128_t) r1) * s4 + ((uint128_t) r2) * s3 + ((uint128_t) r3) * s2; - t[1] += ((uint128_t) r4) * s2 + ((uint128_t) r2) * s4 + ((uint128_t) r3) * s3; - t[2] += ((uint128_t) r4) * s3 + ((uint128_t) r3) * s4; - t[3] += ((uint128_t) r4) * s4; -#else - mul64x64_128(mul, r4, s1) add128(t[0], mul) mul64x64_128(mul, r1, s4) add128(t[0], mul) mul64x64_128(mul, r2, s3) add128(t[0], mul) mul64x64_128(mul, r3, s2) add128(t[0], mul) - mul64x64_128(mul, r4, s2) add128(t[1], mul) mul64x64_128(mul, r2, s4) add128(t[1], mul) mul64x64_128(mul, r3, s3) add128(t[1], mul) - mul64x64_128(mul, r4, s3) add128(t[2], mul) mul64x64_128(mul, r3, s4) add128(t[2], mul) - mul64x64_128(mul, r4, s4) add128(t[3], mul) -#endif - - r0 = lo128(t[0]) & reduce_mask_51; shr128(c, t[0], 51); - add128_64(t[1], c) r1 = lo128(t[1]) & reduce_mask_51; shr128(c, t[1], 51); - add128_64(t[2], c) r2 = lo128(t[2]) & reduce_mask_51; shr128(c, t[2], 51); - add128_64(t[3], c) r3 = lo128(t[3]) & reduce_mask_51; shr128(c, t[3], 51); - add128_64(t[4], c) r4 = lo128(t[4]) & reduce_mask_51; shr128(c, t[4], 51); - r0 += c * 19; c = r0 >> 51; r0 = r0 & reduce_mask_51; - r1 += c; - - out[0] = r0; - out[1] = r1; - out[2] = r2; - out[3] = r3; - out[4] = r4; -} - -/* out = in^(2 * count) */ -DONNA_INLINE static void -curve25519_square_times(bignum25519 out, const bignum25519 in, uint64_t count) { -#if !defined(HAVE_NATIVE_UINT128) - uint128_t mul; -#endif - uint128_t t[5]; - uint64_t r0,r1,r2,r3,r4,c; - uint64_t d0,d1,d2,d4,d419; - - r0 = in[0]; - r1 = in[1]; - r2 = in[2]; - r3 = in[3]; - r4 = in[4]; - - do { - d0 = r0 * 2; - d1 = r1 * 2; - d2 = r2 * 2 * 19; - d419 = r4 * 19; - d4 = d419 * 2; - -#if defined(HAVE_NATIVE_UINT128) - t[0] = ((uint128_t) r0) * r0 + ((uint128_t) d4) * r1 + (((uint128_t) d2) * (r3 )); - t[1] = ((uint128_t) d0) * r1 + ((uint128_t) d4) * r2 + (((uint128_t) r3) * (r3 * 19)); - t[2] = ((uint128_t) d0) * r2 + ((uint128_t) r1) * r1 + (((uint128_t) d4) * (r3 )); - t[3] = ((uint128_t) d0) * r3 + ((uint128_t) d1) * r2 + (((uint128_t) r4) * (d419 )); - t[4] = ((uint128_t) d0) * r4 + ((uint128_t) d1) * r3 + (((uint128_t) r2) * (r2 )); -#else - mul64x64_128(t[0], r0, r0) mul64x64_128(mul, d4, r1) add128(t[0], mul) mul64x64_128(mul, d2, r3) add128(t[0], mul) - mul64x64_128(t[1], d0, r1) mul64x64_128(mul, d4, r2) add128(t[1], mul) mul64x64_128(mul, r3, r3 * 19) add128(t[1], mul) - mul64x64_128(t[2], d0, r2) mul64x64_128(mul, r1, r1) add128(t[2], mul) mul64x64_128(mul, d4, r3) add128(t[2], mul) - mul64x64_128(t[3], d0, r3) mul64x64_128(mul, d1, r2) add128(t[3], mul) mul64x64_128(mul, r4, d419) add128(t[3], mul) - mul64x64_128(t[4], d0, r4) mul64x64_128(mul, d1, r3) add128(t[4], mul) mul64x64_128(mul, r2, r2) add128(t[4], mul) -#endif - - r0 = lo128(t[0]) & reduce_mask_51; shr128(c, t[0], 51); - add128_64(t[1], c) r1 = lo128(t[1]) & reduce_mask_51; shr128(c, t[1], 51); - add128_64(t[2], c) r2 = lo128(t[2]) & reduce_mask_51; shr128(c, t[2], 51); - add128_64(t[3], c) r3 = lo128(t[3]) & reduce_mask_51; shr128(c, t[3], 51); - add128_64(t[4], c) r4 = lo128(t[4]) & reduce_mask_51; shr128(c, t[4], 51); - r0 += c * 19; c = r0 >> 51; r0 = r0 & reduce_mask_51; - r1 += c; - } while(--count); - - out[0] = r0; - out[1] = r1; - out[2] = r2; - out[3] = r3; - out[4] = r4; -} - -DONNA_INLINE static void -curve25519_square(bignum25519 out, const bignum25519 in) { -#if !defined(HAVE_NATIVE_UINT128) - uint128_t mul; -#endif - uint128_t t[5]; - uint64_t r0,r1,r2,r3,r4,c; - uint64_t d0,d1,d2,d4,d419; - - r0 = in[0]; - r1 = in[1]; - r2 = in[2]; - r3 = in[3]; - r4 = in[4]; - - d0 = r0 * 2; - d1 = r1 * 2; - d2 = r2 * 2 * 19; - d419 = r4 * 19; - d4 = d419 * 2; - -#if defined(HAVE_NATIVE_UINT128) - t[0] = ((uint128_t) r0) * r0 + ((uint128_t) d4) * r1 + (((uint128_t) d2) * (r3 )); - t[1] = ((uint128_t) d0) * r1 + ((uint128_t) d4) * r2 + (((uint128_t) r3) * (r3 * 19)); - t[2] = ((uint128_t) d0) * r2 + ((uint128_t) r1) * r1 + (((uint128_t) d4) * (r3 )); - t[3] = ((uint128_t) d0) * r3 + ((uint128_t) d1) * r2 + (((uint128_t) r4) * (d419 )); - t[4] = ((uint128_t) d0) * r4 + ((uint128_t) d1) * r3 + (((uint128_t) r2) * (r2 )); -#else - mul64x64_128(t[0], r0, r0) mul64x64_128(mul, d4, r1) add128(t[0], mul) mul64x64_128(mul, d2, r3) add128(t[0], mul) - mul64x64_128(t[1], d0, r1) mul64x64_128(mul, d4, r2) add128(t[1], mul) mul64x64_128(mul, r3, r3 * 19) add128(t[1], mul) - mul64x64_128(t[2], d0, r2) mul64x64_128(mul, r1, r1) add128(t[2], mul) mul64x64_128(mul, d4, r3) add128(t[2], mul) - mul64x64_128(t[3], d0, r3) mul64x64_128(mul, d1, r2) add128(t[3], mul) mul64x64_128(mul, r4, d419) add128(t[3], mul) - mul64x64_128(t[4], d0, r4) mul64x64_128(mul, d1, r3) add128(t[4], mul) mul64x64_128(mul, r2, r2) add128(t[4], mul) -#endif - - r0 = lo128(t[0]) & reduce_mask_51; shr128(c, t[0], 51); - add128_64(t[1], c) r1 = lo128(t[1]) & reduce_mask_51; shr128(c, t[1], 51); - add128_64(t[2], c) r2 = lo128(t[2]) & reduce_mask_51; shr128(c, t[2], 51); - add128_64(t[3], c) r3 = lo128(t[3]) & reduce_mask_51; shr128(c, t[3], 51); - add128_64(t[4], c) r4 = lo128(t[4]) & reduce_mask_51; shr128(c, t[4], 51); - r0 += c * 19; c = r0 >> 51; r0 = r0 & reduce_mask_51; - r1 += c; - - out[0] = r0; - out[1] = r1; - out[2] = r2; - out[3] = r3; - out[4] = r4; -} - - -/* Take a little-endian, 32-byte number and expand it into polynomial form */ -DONNA_INLINE static void -curve25519_expand(bignum25519 out, const unsigned char *in) { - static const union { uint8_t b[2]; uint16_t s; } endian_check = {{1,0}}; - uint64_t x0,x1,x2,x3; - - if (endian_check.s == 1) { - x0 = *(uint64_t *)(in + 0); - x1 = *(uint64_t *)(in + 8); - x2 = *(uint64_t *)(in + 16); - x3 = *(uint64_t *)(in + 24); - } else { - #define F(s) \ - ((((uint64_t)in[s + 0]) ) | \ - (((uint64_t)in[s + 1]) << 8) | \ - (((uint64_t)in[s + 2]) << 16) | \ - (((uint64_t)in[s + 3]) << 24) | \ - (((uint64_t)in[s + 4]) << 32) | \ - (((uint64_t)in[s + 5]) << 40) | \ - (((uint64_t)in[s + 6]) << 48) | \ - (((uint64_t)in[s + 7]) << 56)) - - x0 = F(0); - x1 = F(8); - x2 = F(16); - x3 = F(24); - } - - out[0] = x0 & reduce_mask_51; x0 = (x0 >> 51) | (x1 << 13); - out[1] = x0 & reduce_mask_51; x1 = (x1 >> 38) | (x2 << 26); - out[2] = x1 & reduce_mask_51; x2 = (x2 >> 25) | (x3 << 39); - out[3] = x2 & reduce_mask_51; x3 = (x3 >> 12); - out[4] = x3 & reduce_mask_51; /* ignore the top bit */ -} - -/* Take a fully reduced polynomial form number and contract it into a - * little-endian, 32-byte array - */ -DONNA_INLINE static void -curve25519_contract(unsigned char *out, const bignum25519 input) { - uint64_t t[5]; - uint64_t f, i; - - t[0] = input[0]; - t[1] = input[1]; - t[2] = input[2]; - t[3] = input[3]; - t[4] = input[4]; - - #define curve25519_contract_carry() \ - t[1] += t[0] >> 51; t[0] &= reduce_mask_51; \ - t[2] += t[1] >> 51; t[1] &= reduce_mask_51; \ - t[3] += t[2] >> 51; t[2] &= reduce_mask_51; \ - t[4] += t[3] >> 51; t[3] &= reduce_mask_51; - - #define curve25519_contract_carry_full() curve25519_contract_carry() \ - t[0] += 19 * (t[4] >> 51); t[4] &= reduce_mask_51; - - #define curve25519_contract_carry_final() curve25519_contract_carry() \ - t[4] &= reduce_mask_51; - - curve25519_contract_carry_full() - curve25519_contract_carry_full() - - /* now t is between 0 and 2^255-1, properly carried. */ - /* case 1: between 0 and 2^255-20. case 2: between 2^255-19 and 2^255-1. */ - t[0] += 19; - curve25519_contract_carry_full() - - /* now between 19 and 2^255-1 in both cases, and offset by 19. */ - t[0] += 0x8000000000000 - 19; - t[1] += 0x8000000000000 - 1; - t[2] += 0x8000000000000 - 1; - t[3] += 0x8000000000000 - 1; - t[4] += 0x8000000000000 - 1; - - /* now between 2^255 and 2^256-20, and offset by 2^255. */ - curve25519_contract_carry_final() - - #define write51full(n,shift) \ - f = ((t[n] >> shift) | (t[n+1] << (51 - shift))); \ - for (i = 0; i < 8; i++, f >>= 8) *out++ = (unsigned char)f; - #define write51(n) write51full(n,13*n) - - write51(0) - write51(1) - write51(2) - write51(3) - - #undef curve25519_contract_carry - #undef curve25519_contract_carry_full - #undef curve25519_contract_carry_final - #undef write51full - #undef write51 -} - -/* - * Swap the contents of [qx] and [qpx] iff @swap is non-zero - */ -DONNA_INLINE static void -curve25519_swap_conditional(bignum25519 x, bignum25519 qpx, uint64_t iswap) { - const uint64_t swap = (uint64_t)(-(int64_t)iswap); - uint64_t x0,x1,x2,x3,x4; - - x0 = swap & (x[0] ^ qpx[0]); x[0] ^= x0; qpx[0] ^= x0; - x1 = swap & (x[1] ^ qpx[1]); x[1] ^= x1; qpx[1] ^= x1; - x2 = swap & (x[2] ^ qpx[2]); x[2] ^= x2; qpx[2] ^= x2; - x3 = swap & (x[3] ^ qpx[3]); x[3] ^= x3; qpx[3] ^= x3; - x4 = swap & (x[4] ^ qpx[4]); x[4] ^= x4; qpx[4] ^= x4; - -} - diff --git a/curve25519-donna/curve25519-donna-common.h b/curve25519-donna/curve25519-donna-common.h deleted file mode 100644 index 6b3ed2ad6..000000000 --- a/curve25519-donna/curve25519-donna-common.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * In: b = 2^5 - 2^0 - * Out: b = 2^250 - 2^0 - */ -static void -curve25519_pow_two5mtwo0_two250mtwo0(bignum25519 b) { - bignum25519 ALIGN(16) t0,c; - - /* 2^5 - 2^0 */ /* b */ - /* 2^10 - 2^5 */ curve25519_square_times(t0, b, 5); - /* 2^10 - 2^0 */ curve25519_mul(b, t0, b); - /* 2^20 - 2^10 */ curve25519_square_times(t0, b, 10); - /* 2^20 - 2^0 */ curve25519_mul(c, t0, b); - /* 2^40 - 2^20 */ curve25519_square_times(t0, c, 20); - /* 2^40 - 2^0 */ curve25519_mul(t0, t0, c); - /* 2^50 - 2^10 */ curve25519_square_times(t0, t0, 10); - /* 2^50 - 2^0 */ curve25519_mul(b, t0, b); - /* 2^100 - 2^50 */ curve25519_square_times(t0, b, 50); - /* 2^100 - 2^0 */ curve25519_mul(c, t0, b); - /* 2^200 - 2^100 */ curve25519_square_times(t0, c, 100); - /* 2^200 - 2^0 */ curve25519_mul(t0, t0, c); - /* 2^250 - 2^50 */ curve25519_square_times(t0, t0, 50); - /* 2^250 - 2^0 */ curve25519_mul(b, t0, b); -} - -/* - * z^(p - 2) = z(2^255 - 21) - */ -static void -curve25519_recip(bignum25519 out, const bignum25519 z) { - bignum25519 ALIGN(16) a,t0,b; - - /* 2 */ curve25519_square(a, z); /* a = 2 */ - /* 8 */ curve25519_square_times(t0, a, 2); - /* 9 */ curve25519_mul(b, t0, z); /* b = 9 */ - /* 11 */ curve25519_mul(a, b, a); /* a = 11 */ - /* 22 */ curve25519_square(t0, a); - /* 2^5 - 2^0 = 31 */ curve25519_mul(b, t0, b); - /* 2^250 - 2^0 */ curve25519_pow_two5mtwo0_two250mtwo0(b); - /* 2^255 - 2^5 */ curve25519_square_times(b, b, 5); - /* 2^255 - 21 */ curve25519_mul(out, b, a); -} - diff --git a/curve25519-donna/curve25519-donna-portable-identify.h b/curve25519-donna/curve25519-donna-portable-identify.h deleted file mode 100644 index 26a264cf9..000000000 --- a/curve25519-donna/curve25519-donna-portable-identify.h +++ /dev/null @@ -1,103 +0,0 @@ -/* os */ -#if defined(_WIN32) || defined(_WIN64) || defined(__TOS_WIN__) || defined(__WINDOWS__) - #define OS_WINDOWS -#elif defined(sun) || defined(__sun) || defined(__SVR4) || defined(__svr4__) - #define OS_SOLARIS -#else - #include /* need this to define BSD */ - #define OS_NIX - #if defined(__linux__) - #define OS_LINUX - #elif defined(BSD) - #define OS_BSD - #if defined(MACOS_X) || (defined(__APPLE__) & defined(__MACH__)) - #define OS_OSX - #elif defined(macintosh) || defined(Macintosh) - #define OS_MAC - #elif defined(__OpenBSD__) - #define OS_OPENBSD - #endif - #endif -#endif - - -/* compiler */ -#if defined(_MSC_VER) - #define COMPILER_MSVC -#endif -#if defined(__ICC) - #define COMPILER_INTEL -#endif -#if defined(__GNUC__) - #if (__GNUC__ >= 3) - #define COMPILER_GCC ((__GNUC__ * 10000) + (__GNUC_MINOR__ * 100) + (__GNUC_PATCHLEVEL__)) - #else - #define COMPILER_GCC ((__GNUC__ * 10000) + (__GNUC_MINOR__ * 100) ) - #endif -#endif -#if defined(__PATHCC__) - #define COMPILER_PATHCC -#endif -#if defined(__clang__) - #define COMPILER_CLANG ((__clang_major__ * 10000) + (__clang_minor__ * 100) + (__clang_patchlevel__)) -#endif - - - -/* cpu */ -#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__ ) || defined(_M_X64) - #define CPU_X86_64 -#elif defined(__i586__) || defined(__i686__) || (defined(_M_IX86) && (_M_IX86 >= 500)) - #define CPU_X86 500 -#elif defined(__i486__) || (defined(_M_IX86) && (_M_IX86 >= 400)) - #define CPU_X86 400 -#elif defined(__i386__) || (defined(_M_IX86) && (_M_IX86 >= 300)) || defined(__X86__) || defined(_X86_) || defined(__I86__) - #define CPU_X86 300 -#elif defined(__ia64__) || defined(_IA64) || defined(__IA64__) || defined(_M_IA64) || defined(__ia64) - #define CPU_IA64 -#endif - -#if defined(__sparc__) || defined(__sparc) || defined(__sparcv9) - #define CPU_SPARC - #if defined(__sparcv9) - #define CPU_SPARC64 - #endif -#endif - -#if defined(powerpc) || defined(__PPC__) || defined(__ppc__) || defined(_ARCH_PPC) || defined(__powerpc__) || defined(__powerpc) || defined(POWERPC) || defined(_M_PPC) - #define CPU_PPC - #if defined(_ARCH_PWR7) - #define CPU_POWER7 - #elif defined(__64BIT__) - #define CPU_PPC64 - #else - #define CPU_PPC32 - #endif -#endif - -#if defined(__hppa__) || defined(__hppa) - #define CPU_HPPA -#endif - -#if defined(__alpha__) || defined(__alpha) || defined(_M_ALPHA) - #define CPU_ALPHA -#endif - -/* 64 bit cpu */ -#if defined(CPU_X86_64) || defined(CPU_IA64) || defined(CPU_SPARC64) || defined(__64BIT__) || defined(__LP64__) || defined(_LP64) || (defined(_MIPS_SZLONG) && (_MIPS_SZLONG == 64)) - #define CPU_64BITS -#endif - -#if defined(COMPILER_MSVC) - typedef signed char int8_t; - typedef unsigned char uint8_t; - typedef signed short int16_t; - typedef unsigned short uint16_t; - typedef signed int int32_t; - typedef unsigned int uint32_t; - typedef signed __int64 int64_t; - typedef unsigned __int64 uint64_t; -#else - #include -#endif - diff --git a/curve25519-donna/curve25519-donna-portable.h b/curve25519-donna/curve25519-donna-portable.h deleted file mode 100644 index 0f428730e..000000000 --- a/curve25519-donna/curve25519-donna-portable.h +++ /dev/null @@ -1,94 +0,0 @@ -#include "curve25519-donna-portable-identify.h" - -#define mul32x32_64(a,b) (((uint64_t)(a))*(b)) - -/* platform */ -#if defined(COMPILER_MSVC) - #include - #if !defined(_DEBUG) - #undef mul32x32_64 - #define mul32x32_64(a,b) __emulu(a,b) - #endif - #undef inline - #define inline __forceinline - #define DONNA_INLINE __forceinline - #define DONNA_NOINLINE __declspec(noinline) - #undef ALIGN - #define ALIGN(x) __declspec(align(x)) - #define ROTL32(a,b) _rotl(a,b) - #define ROTR32(a,b) _rotr(a,b) -#else - #include - #define DONNA_INLINE inline __attribute__((always_inline)) - #define DONNA_NOINLINE __attribute__((noinline)) - #undef ALIGN - #define ALIGN(x) __attribute__((aligned(x))) - #define ROTL32(a,b) (((a) << (b)) | ((a) >> (32 - b))) - #define ROTR32(a,b) (((a) >> (b)) | ((a) << (32 - b))) -#endif - -/* uint128_t */ -#if defined(CPU_64BITS) && !defined(ED25519_FORCE_32BIT) - #if defined(COMPILER_CLANG) && (COMPILER_CLANG >= 30100) - #define HAVE_NATIVE_UINT128 - typedef unsigned __int128 uint128_t; - #elif defined(COMPILER_MSVC) - #define HAVE_UINT128 - typedef struct uint128_t { - uint64_t lo, hi; - } uint128_t; - #define mul64x64_128(out,a,b) out.lo = _umul128(a,b,&out.hi); - #define shr128_pair(out,hi,lo,shift) out = __shiftright128(lo, hi, shift); - #define shl128_pair(out,hi,lo,shift) out = __shiftleft128(lo, hi, shift); - #define shr128(out,in,shift) shr128_pair(out, in.hi, in.lo, shift) - #define shl128(out,in,shift) shl128_pair(out, in.hi, in.lo, shift) - #define add128(a,b) { uint64_t p = a.lo; a.lo += b.lo; a.hi += b.hi + (a.lo < p); } - #define add128_64(a,b) { uint64_t p = a.lo; a.lo += b; a.hi += (a.lo < p); } - #define lo128(a) (a.lo) - #define hi128(a) (a.hi) - #elif defined(COMPILER_GCC) && !defined(HAVE_NATIVE_UINT128) - #if defined(__SIZEOF_INT128__) - #define HAVE_NATIVE_UINT128 - typedef unsigned __int128 uint128_t; - #elif (COMPILER_GCC >= 40400) - #define HAVE_NATIVE_UINT128 - typedef unsigned uint128_t __attribute__((mode(TI))); - #elif defined(CPU_X86_64) - #define HAVE_UINT128 - typedef struct uint128_t { - uint64_t lo, hi; - } uint128_t; - #define mul64x64_128(out,a,b) __asm__ ("mulq %3" : "=a" (out.lo), "=d" (out.hi) : "a" (a), "rm" (b)); - #define shr128_pair(out,hi,lo,shift) __asm__ ("shrdq %2,%1,%0" : "+r" (lo) : "r" (hi), "J" (shift)); out = lo; - #define shl128_pair(out,hi,lo,shift) __asm__ ("shldq %2,%1,%0" : "+r" (hi) : "r" (lo), "J" (shift)); out = hi; - #define shr128(out,in,shift) shr128_pair(out,in.hi, in.lo, shift) - #define shl128(out,in,shift) shl128_pair(out,in.hi, in.lo, shift) - #define add128(a,b) __asm__ ("addq %4,%2; adcq %5,%3" : "=r" (a.hi), "=r" (a.lo) : "1" (a.lo), "0" (a.hi), "rm" (b.lo), "rm" (b.hi) : "cc"); - #define add128_64(a,b) __asm__ ("addq %4,%2; adcq $0,%3" : "=r" (a.hi), "=r" (a.lo) : "1" (a.lo), "0" (a.hi), "rm" (b) : "cc"); - #define lo128(a) (a.lo) - #define hi128(a) (a.hi) - #endif - #endif - - #if defined(HAVE_NATIVE_UINT128) - #define HAVE_UINT128 - #define mul64x64_128(out,a,b) out = (uint128_t)a * b; - #define shr128_pair(out,hi,lo,shift) out = (uint64_t)((((uint128_t)hi << 64) | lo) >> (shift)); - #define shl128_pair(out,hi,lo,shift) out = (uint64_t)(((((uint128_t)hi << 64) | lo) << (shift)) >> 64); - #define shr128(out,in,shift) out = (uint64_t)(in >> (shift)); - #define shl128(out,in,shift) out = (uint64_t)((in << shift) >> 64); - #define add128(a,b) a += b; - #define add128_64(a,b) a += (uint64_t)b; - #define lo128(a) ((uint64_t)a) - #define hi128(a) ((uint64_t)(a >> 64)) - #endif - - #if !defined(HAVE_UINT128) - #error Need a uint128_t implementation! - #endif -#endif - -#include -#include - - diff --git a/curve25519-donna/curve25519-donna-scalarmult-sse2.h b/curve25519-donna/curve25519-donna-scalarmult-sse2.h deleted file mode 100644 index e0ef14c11..000000000 --- a/curve25519-donna/curve25519-donna-scalarmult-sse2.h +++ /dev/null @@ -1,65 +0,0 @@ - -/* Calculates nQ where Q is the x-coordinate of a point on the curve - * - * mypublic: the packed little endian x coordinate of the resulting curve point - * n: a little endian, 32-byte number - * basepoint: a packed little endian point of the curve - */ -static void -curve25519_scalarmult_donna(curve25519_key mypublic, const curve25519_key n, const curve25519_key basepoint) { - bignum25519 ALIGN(16) nqx = {1}, nqpqz = {1}, nqz = {0}, nqpqx, zmone; - packed32bignum25519 qx, qz, pqz, pqx; - packed64bignum25519 nq, sq, sqscalar, prime, primex, primez, nqpq; - bignum25519mulprecomp preq; - size_t bit, lastbit, i; - - curve25519_expand(nqpqx, basepoint); - curve25519_mul_precompute(&preq, nqpqx); - - /* do bits 254..3 */ - for (i = 254, lastbit = 0; i >= 3; i--) { - bit = (n[i/8] >> (i & 7)) & 1; - curve25519_swap_conditional(nqx, nqpqx, bit ^ lastbit); - curve25519_swap_conditional(nqz, nqpqz, bit ^ lastbit); - lastbit = bit; - - curve25519_tangle32(qx, nqx, nqpqx); /* qx = [nqx,nqpqx] */ - curve25519_tangle32(qz, nqz, nqpqz); /* qz = [nqz,nqpqz] */ - - curve25519_add_packed32(pqx, qx, qz); /* pqx = [nqx+nqz,nqpqx+nqpqz] */ - curve25519_sub_packed32(pqz, qx, qz); /* pqz = [nqx-nqz,nqpqx-nqpqz] */ - - curve25519_make_nqpq(primex, primez, pqx, pqz); /* primex = [nqx+nqz,nqpqx+nqpqz], primez = [nqpqx-nqpqz,nqx-nqz] */ - curve25519_mul_packed64(prime, primex, primez); /* prime = [nqx+nqz,nqpqx+nqpqz] * [nqpqx-nqpqz,nqx-nqz] */ - curve25519_addsub_packed64(prime); /* prime = [prime.x+prime.z,prime.x-prime.z] */ - curve25519_square_packed64(nqpq, prime); /* nqpq = prime^2 */ - curve25519_untangle64(nqpqx, nqpqz, nqpq); - curve25519_mul_precomputed(nqpqz, nqpqz, &preq); /* nqpqz = nqpqz * q */ - - /* (((sq.x-sq.z)*121665)+sq.x) * (sq.x-sq.z) is equivalent to (sq.x*121666-sq.z*121665) * (sq.x-sq.z) */ - curve25519_make_nq(nq, pqx, pqz); /* nq = [nqx+nqz,nqx-nqz] */ - curve25519_square_packed64(sq, nq); /* sq = nq^2 */ - curve25519_121665_packed64(sqscalar, sq); /* sqscalar = sq * [121666,121665] */ - curve25519_final_nq(nq, sq, sqscalar); /* nq = [sq.x,sqscalar.x-sqscalar.z] * [sq.z,sq.x-sq.z] */ - curve25519_untangle64(nqx, nqz, nq); - }; - - /* it's possible to get rid of this swap with the swap in the above loop - at the bottom instead of the top, but compilers seem to optimize better this way */ - curve25519_swap_conditional(nqx, nqpqx, bit); - curve25519_swap_conditional(nqz, nqpqz, bit); - - /* do bits 2..0 */ - for (i = 0; i < 3; i++) { - curve25519_compute_nq(nq, nqx, nqz); - curve25519_square_packed64(sq, nq); /* sq = nq^2 */ - curve25519_121665_packed64(sqscalar, sq); /* sqscalar = sq * [121666,121665] */ - curve25519_final_nq(nq, sq, sqscalar); /* nq = [sq.x,sqscalar.x-sqscalar.z] * [sq.z,sq.x-sq.z] */ - curve25519_untangle64(nqx, nqz, nq); - } - - curve25519_recip(zmone, nqz); - curve25519_mul(nqz, nqx, zmone); - curve25519_contract(mypublic, nqz); -} - diff --git a/curve25519-donna/curve25519-donna-sse2.h b/curve25519-donna/curve25519-donna-sse2.h deleted file mode 100644 index ff2416209..000000000 --- a/curve25519-donna/curve25519-donna-sse2.h +++ /dev/null @@ -1,1009 +0,0 @@ -#include -typedef __m128i xmmi; - -typedef union packedelem8_t { - unsigned char u[16]; - xmmi v; -} packedelem8; - -typedef union packedelem32_t { - uint32_t u[4]; - xmmi v; -} packedelem32; - -typedef union packedelem64_t { - uint64_t u[2]; - xmmi v; -} packedelem64; - -/* 10 elements + an extra 2 to fit in 3 xmm registers */ -typedef uint32_t bignum25519[10+2]; -typedef packedelem32 packed32bignum25519[5]; -typedef packedelem64 packed64bignum25519[10]; - -static const uint32_t reduce_mask_26 = (1 << 26) - 1; -static const uint32_t reduce_mask_25 = (1 << 25) - 1; - -static const packedelem32 sse2_bot32bitmask = {{0xffffffff, 0x00000000, 0xffffffff, 0x00000000}}; -static const packedelem32 sse2_top32bitmask = {{0x00000000, 0xffffffff, 0x00000000, 0xffffffff}}; -static const packedelem32 sse2_top64bitmask = {{0x00000000, 0x00000000, 0xffffffff, 0xffffffff}}; -static const packedelem32 sse2_bot64bitmask = {{0xffffffff, 0xffffffff, 0x00000000, 0x00000000}}; - -/* reduction masks */ -static const packedelem64 packedmask26 = {{0x03ffffff, 0x03ffffff}}; -static const packedelem64 packedmask25 = {{0x01ffffff, 0x01ffffff}}; -static const packedelem32 packedmask2625 = {{0x3ffffff,0,0x1ffffff,0}}; -static const packedelem32 packedmask26262626 = {{0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff}}; -static const packedelem32 packedmask25252525 = {{0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff}}; - -/* multipliers */ -static const packedelem64 packednineteen = {{19, 19}}; -static const packedelem64 packednineteenone = {{19, 1}}; -static const packedelem64 packedthirtyeight = {{38, 38}}; -static const packedelem64 packed3819 = {{19*2,19}}; -static const packedelem64 packed9638 = {{19*4,19*2}}; - -/* 121666,121665 */ -static const packedelem64 packed121666121665 = {{121666, 121665}}; - -/* 2*(2^255 - 19) = 0 mod p */ -static const packedelem32 packed2p0 = {{0x7ffffda,0x3fffffe,0x7fffffe,0x3fffffe}}; -static const packedelem32 packed2p1 = {{0x7fffffe,0x3fffffe,0x7fffffe,0x3fffffe}}; -static const packedelem32 packed2p2 = {{0x7fffffe,0x3fffffe,0x0000000,0x0000000}}; - -static const packedelem32 packed32zeromodp0 = {{0x7ffffda,0x7ffffda,0x3fffffe,0x3fffffe}}; -static const packedelem32 packed32zeromodp1 = {{0x7fffffe,0x7fffffe,0x3fffffe,0x3fffffe}}; - -/* Copy a bignum to another: out = in */ -DONNA_INLINE static void -curve25519_copy(bignum25519 out, const bignum25519 in) { - xmmi x0,x1,x2; - x0 = _mm_load_si128((xmmi*)in + 0); - x1 = _mm_load_si128((xmmi*)in + 1); - x2 = _mm_load_si128((xmmi*)in + 2); - _mm_store_si128((xmmi*)out + 0, x0); - _mm_store_si128((xmmi*)out + 1, x1); - _mm_store_si128((xmmi*)out + 2, x2); -} - -/* Take a little-endian, 32-byte number and expand it into polynomial form */ -DONNA_INLINE static void -curve25519_expand(bignum25519 out, const unsigned char in[32]) { - uint32_t x0,x1,x2,x3,x4,x5,x6,x7; - - x0 = *(uint32_t *)(in + 0); - x1 = *(uint32_t *)(in + 4); - x2 = *(uint32_t *)(in + 8); - x3 = *(uint32_t *)(in + 12); - x4 = *(uint32_t *)(in + 16); - x5 = *(uint32_t *)(in + 20); - x6 = *(uint32_t *)(in + 24); - x7 = *(uint32_t *)(in + 28); - - out[0] = ( x0 ) & reduce_mask_26; - out[1] = ((((uint64_t)x1 << 32) | x0) >> 26) & reduce_mask_25; - out[2] = ((((uint64_t)x2 << 32) | x1) >> 19) & reduce_mask_26; - out[3] = ((((uint64_t)x3 << 32) | x2) >> 13) & reduce_mask_25; - out[4] = (( x3) >> 6) & reduce_mask_26; - out[5] = ( x4 ) & reduce_mask_25; - out[6] = ((((uint64_t)x5 << 32) | x4) >> 25) & reduce_mask_26; - out[7] = ((((uint64_t)x6 << 32) | x5) >> 19) & reduce_mask_25; - out[8] = ((((uint64_t)x7 << 32) | x6) >> 12) & reduce_mask_26; - out[9] = (( x7) >> 6) & reduce_mask_25; /* ignore the top bit */ - - out[10] = 0; - out[11] = 0; -} - -/* Take a fully reduced polynomial form number and contract it into a - * little-endian, 32-byte array - */ -DONNA_INLINE static void -curve25519_contract(unsigned char out[32], const bignum25519 in) { - bignum25519 ALIGN(16) f; - - curve25519_copy(f, in); - - #define carry_pass() \ - f[1] += f[0] >> 26; f[0] &= reduce_mask_26; \ - f[2] += f[1] >> 25; f[1] &= reduce_mask_25; \ - f[3] += f[2] >> 26; f[2] &= reduce_mask_26; \ - f[4] += f[3] >> 25; f[3] &= reduce_mask_25; \ - f[5] += f[4] >> 26; f[4] &= reduce_mask_26; \ - f[6] += f[5] >> 25; f[5] &= reduce_mask_25; \ - f[7] += f[6] >> 26; f[6] &= reduce_mask_26; \ - f[8] += f[7] >> 25; f[7] &= reduce_mask_25; \ - f[9] += f[8] >> 26; f[8] &= reduce_mask_26; - - #define carry_pass_full() \ - carry_pass() \ - f[0] += 19 * (f[9] >> 25); f[9] &= reduce_mask_25; - - #define carry_pass_final() \ - carry_pass() \ - f[9] &= reduce_mask_25; - - carry_pass_full() - carry_pass_full() - - /* now t is between 0 and 2^255-1, properly carried. */ - /* case 1: between 0 and 2^255-20. case 2: between 2^255-19 and 2^255-1. */ - f[0] += 19; - carry_pass_full() - - /* now between 19 and 2^255-1 in both cases, and offset by 19. */ - f[0] += (1 << 26) - 19; - f[1] += (1 << 25) - 1; - f[2] += (1 << 26) - 1; - f[3] += (1 << 25) - 1; - f[4] += (1 << 26) - 1; - f[5] += (1 << 25) - 1; - f[6] += (1 << 26) - 1; - f[7] += (1 << 25) - 1; - f[8] += (1 << 26) - 1; - f[9] += (1 << 25) - 1; - - /* now between 2^255 and 2^256-20, and offset by 2^255. */ - carry_pass_final() - - #undef carry_pass - #undef carry_full - #undef carry_final - - *(uint32_t *)(out + 0) = ((f[0] ) | (f[1] << 26)); - *(uint32_t *)(out + 4) = ((f[1] >> 6) | (f[2] << 19)); - *(uint32_t *)(out + 8) = ((f[2] >> 13) | (f[3] << 13)); - *(uint32_t *)(out + 12) = ((f[3] >> 19) | (f[4] << 6)); - *(uint32_t *)(out + 16) = ((f[5] ) | (f[6] << 25)); - *(uint32_t *)(out + 20) = ((f[6] >> 7) | (f[7] << 19)); - *(uint32_t *)(out + 24) = ((f[7] >> 13) | (f[8] << 12)); - *(uint32_t *)(out + 28) = ((f[8] >> 20) | (f[9] << 6)); -} - -/* - * Maybe swap the contents of two felem arrays (@a and @b), each 5 elements - * long. Perform the swap iff @swap is non-zero. - */ -DONNA_INLINE static void -curve25519_swap_conditional(bignum25519 a, bignum25519 b, uint32_t iswap) { - const uint32_t swap = (uint32_t)(-(int32_t)iswap); - xmmi a0,a1,a2,b0,b1,b2,x0,x1,x2; - xmmi mask = _mm_cvtsi32_si128(swap); - mask = _mm_shuffle_epi32(mask, 0); - a0 = _mm_load_si128((xmmi *)a + 0); - a1 = _mm_load_si128((xmmi *)a + 1); - a2 = _mm_load_si128((xmmi *)a + 2); - b0 = _mm_load_si128((xmmi *)b + 0); - b1 = _mm_load_si128((xmmi *)b + 1); - b2 = _mm_load_si128((xmmi *)b + 2); - b0 = _mm_xor_si128(a0, b0); - b1 = _mm_xor_si128(a1, b1); - b2 = _mm_xor_si128(a2, b2); - x0 = _mm_and_si128(b0, mask); - x1 = _mm_and_si128(b1, mask); - x2 = _mm_and_si128(b2, mask); - x0 = _mm_xor_si128(x0, a0); - x1 = _mm_xor_si128(x1, a1); - x2 = _mm_xor_si128(x2, a2); - a0 = _mm_xor_si128(x0, b0); - a1 = _mm_xor_si128(x1, b1); - a2 = _mm_xor_si128(x2, b2); - _mm_store_si128((xmmi *)a + 0, x0); - _mm_store_si128((xmmi *)a + 1, x1); - _mm_store_si128((xmmi *)a + 2, x2); - _mm_store_si128((xmmi *)b + 0, a0); - _mm_store_si128((xmmi *)b + 1, a1); - _mm_store_si128((xmmi *)b + 2, a2); -} - -/* interleave two bignums */ -DONNA_INLINE static void -curve25519_tangle32(packedelem32 *out, const bignum25519 x, const bignum25519 z) { - xmmi x0,x1,x2,z0,z1,z2; - - x0 = _mm_load_si128((xmmi *)(x + 0)); - x1 = _mm_load_si128((xmmi *)(x + 4)); - x2 = _mm_load_si128((xmmi *)(x + 8)); - z0 = _mm_load_si128((xmmi *)(z + 0)); - z1 = _mm_load_si128((xmmi *)(z + 4)); - z2 = _mm_load_si128((xmmi *)(z + 8)); - - out[0].v = _mm_unpacklo_epi32(x0, z0); - out[1].v = _mm_unpackhi_epi32(x0, z0); - out[2].v = _mm_unpacklo_epi32(x1, z1); - out[3].v = _mm_unpackhi_epi32(x1, z1); - out[4].v = _mm_unpacklo_epi32(x2, z2); -} - -/* split a packed bignum in to it's two parts */ -DONNA_INLINE static void -curve25519_untangle64(bignum25519 x, bignum25519 z, const packedelem64 *in) { - _mm_store_si128((xmmi *)(x + 0), _mm_unpacklo_epi64(_mm_unpacklo_epi32(in[0].v, in[1].v), _mm_unpacklo_epi32(in[2].v, in[3].v))); - _mm_store_si128((xmmi *)(x + 4), _mm_unpacklo_epi64(_mm_unpacklo_epi32(in[4].v, in[5].v), _mm_unpacklo_epi32(in[6].v, in[7].v))); - _mm_store_si128((xmmi *)(x + 8), _mm_unpacklo_epi32(in[8].v, in[9].v) ); - _mm_store_si128((xmmi *)(z + 0), _mm_unpacklo_epi64(_mm_unpackhi_epi32(in[0].v, in[1].v), _mm_unpackhi_epi32(in[2].v, in[3].v))); - _mm_store_si128((xmmi *)(z + 4), _mm_unpacklo_epi64(_mm_unpackhi_epi32(in[4].v, in[5].v), _mm_unpackhi_epi32(in[6].v, in[7].v))); - _mm_store_si128((xmmi *)(z + 8), _mm_unpackhi_epi32(in[8].v, in[9].v) ); -} - -/* add two packed bignums */ -DONNA_INLINE static void -curve25519_add_packed32(packedelem32 *out, const packedelem32 *r, const packedelem32 *s) { - out[0].v = _mm_add_epi32(r[0].v, s[0].v); - out[1].v = _mm_add_epi32(r[1].v, s[1].v); - out[2].v = _mm_add_epi32(r[2].v, s[2].v); - out[3].v = _mm_add_epi32(r[3].v, s[3].v); - out[4].v = _mm_add_epi32(r[4].v, s[4].v); -} - -/* subtract two packed bignums */ -DONNA_INLINE static void -curve25519_sub_packed32(packedelem32 *out, const packedelem32 *r, const packedelem32 *s) { - xmmi r0,r1,r2,r3,r4; - xmmi s0,s1,s2,s3; - xmmi c1,c2; - - r0 = _mm_add_epi32(r[0].v, packed32zeromodp0.v); - r1 = _mm_add_epi32(r[1].v, packed32zeromodp1.v); - r2 = _mm_add_epi32(r[2].v, packed32zeromodp1.v); - r3 = _mm_add_epi32(r[3].v, packed32zeromodp1.v); - r4 = _mm_add_epi32(r[4].v, packed32zeromodp1.v); - r0 = _mm_sub_epi32(r0, s[0].v); /* 00 11 */ - r1 = _mm_sub_epi32(r1, s[1].v); /* 22 33 */ - r2 = _mm_sub_epi32(r2, s[2].v); /* 44 55 */ - r3 = _mm_sub_epi32(r3, s[3].v); /* 66 77 */ - r4 = _mm_sub_epi32(r4, s[4].v); /* 88 99 */ - - s0 = _mm_unpacklo_epi64(r0, r2); /* 00 44 */ - s1 = _mm_unpackhi_epi64(r0, r2); /* 11 55 */ - s2 = _mm_unpacklo_epi64(r1, r3); /* 22 66 */ - s3 = _mm_unpackhi_epi64(r1, r3); /* 33 77 */ - - c1 = _mm_srli_epi32(s0, 26); c2 = _mm_srli_epi32(s2, 26); s0 = _mm_and_si128(s0, packedmask26262626.v); s2 = _mm_and_si128(s2, packedmask26262626.v); s1 = _mm_add_epi32(s1, c1); s3 = _mm_add_epi32(s3, c2); - c1 = _mm_srli_epi32(s1, 25); c2 = _mm_srli_epi32(s3, 25); s1 = _mm_and_si128(s1, packedmask25252525.v); s3 = _mm_and_si128(s3, packedmask25252525.v); s2 = _mm_add_epi32(s2, c1); r4 = _mm_add_epi32(r4, _mm_srli_si128(c2, 8)); s0 = _mm_add_epi32(s0, _mm_slli_si128(c2, 8)); - - out[0].v = _mm_unpacklo_epi64(s0, s1); /* 00 11 */ - out[1].v = _mm_unpacklo_epi64(s2, s3); /* 22 33 */ - out[2].v = _mm_unpackhi_epi64(s0, s1); /* 44 55 */ - out[3].v = _mm_unpackhi_epi64(s2, s3); /* 66 77 */ - out[4].v = r4; /* 88 99 */ -} - -/* multiply two packed bignums */ -DONNA_INLINE static void -curve25519_mul_packed64(packedelem64 *out, const packedelem64 *r, const packedelem64 *s) { - xmmi r1,r2,r3,r4,r5,r6,r7,r8,r9; - xmmi r1_2,r3_2,r5_2,r7_2,r9_2; - xmmi c1,c2; - - out[0].v = _mm_mul_epu32(r[0].v, s[0].v); - out[1].v = _mm_add_epi64(_mm_mul_epu32(r[0].v, s[1].v), _mm_mul_epu32(r[1].v, s[0].v)); - r1_2 = _mm_slli_epi32(r[1].v, 1); - out[2].v = _mm_add_epi64(_mm_mul_epu32(r[0].v, s[2].v), _mm_add_epi64(_mm_mul_epu32(r1_2 , s[1].v), _mm_mul_epu32(r[2].v, s[0].v))); - out[3].v = _mm_add_epi64(_mm_mul_epu32(r[0].v, s[3].v), _mm_add_epi64(_mm_mul_epu32(r[1].v, s[2].v), _mm_add_epi64(_mm_mul_epu32(r[2].v, s[1].v), _mm_mul_epu32(r[3].v, s[0].v)))); - r3_2 = _mm_slli_epi32(r[3].v, 1); - out[4].v = _mm_add_epi64(_mm_mul_epu32(r[0].v, s[4].v), _mm_add_epi64(_mm_mul_epu32(r1_2 , s[3].v), _mm_add_epi64(_mm_mul_epu32(r[2].v, s[2].v), _mm_add_epi64(_mm_mul_epu32(r3_2 , s[1].v), _mm_mul_epu32(r[4].v, s[0].v))))); - out[5].v = _mm_add_epi64(_mm_mul_epu32(r[0].v, s[5].v), _mm_add_epi64(_mm_mul_epu32(r[1].v, s[4].v), _mm_add_epi64(_mm_mul_epu32(r[2].v, s[3].v), _mm_add_epi64(_mm_mul_epu32(r[3].v, s[2].v), _mm_add_epi64(_mm_mul_epu32(r[4].v, s[1].v), _mm_mul_epu32(r[5].v, s[0].v)))))); - r5_2 = _mm_slli_epi32(r[5].v, 1); - out[6].v = _mm_add_epi64(_mm_mul_epu32(r[0].v, s[6].v), _mm_add_epi64(_mm_mul_epu32(r1_2 , s[5].v), _mm_add_epi64(_mm_mul_epu32(r[2].v, s[4].v), _mm_add_epi64(_mm_mul_epu32(r3_2 , s[3].v), _mm_add_epi64(_mm_mul_epu32(r[4].v, s[2].v), _mm_add_epi64(_mm_mul_epu32(r5_2 , s[1].v), _mm_mul_epu32(r[6].v, s[0].v))))))); - out[7].v = _mm_add_epi64(_mm_mul_epu32(r[0].v, s[7].v), _mm_add_epi64(_mm_mul_epu32(r[1].v, s[6].v), _mm_add_epi64(_mm_mul_epu32(r[2].v, s[5].v), _mm_add_epi64(_mm_mul_epu32(r[3].v, s[4].v), _mm_add_epi64(_mm_mul_epu32(r[4].v, s[3].v), _mm_add_epi64(_mm_mul_epu32(r[5].v, s[2].v), _mm_add_epi64(_mm_mul_epu32(r[6].v, s[1].v), _mm_mul_epu32(r[7].v , s[0].v)))))))); - r7_2 = _mm_slli_epi32(r[7].v, 1); - out[8].v = _mm_add_epi64(_mm_mul_epu32(r[0].v, s[8].v), _mm_add_epi64(_mm_mul_epu32(r1_2 , s[7].v), _mm_add_epi64(_mm_mul_epu32(r[2].v, s[6].v), _mm_add_epi64(_mm_mul_epu32(r3_2 , s[5].v), _mm_add_epi64(_mm_mul_epu32(r[4].v, s[4].v), _mm_add_epi64(_mm_mul_epu32(r5_2 , s[3].v), _mm_add_epi64(_mm_mul_epu32(r[6].v, s[2].v), _mm_add_epi64(_mm_mul_epu32(r7_2 , s[1].v), _mm_mul_epu32(r[8].v, s[0].v))))))))); - out[9].v = _mm_add_epi64(_mm_mul_epu32(r[0].v, s[9].v), _mm_add_epi64(_mm_mul_epu32(r[1].v, s[8].v), _mm_add_epi64(_mm_mul_epu32(r[2].v, s[7].v), _mm_add_epi64(_mm_mul_epu32(r[3].v, s[6].v), _mm_add_epi64(_mm_mul_epu32(r[4].v, s[5].v), _mm_add_epi64(_mm_mul_epu32(r[5].v, s[4].v), _mm_add_epi64(_mm_mul_epu32(r[6].v, s[3].v), _mm_add_epi64(_mm_mul_epu32(r[7].v, s[2].v), _mm_add_epi64(_mm_mul_epu32(r[8].v, s[1].v), _mm_mul_epu32(r[9].v, s[0].v)))))))))); - - r1 = _mm_mul_epu32(r[1].v, packednineteen.v); - r2 = _mm_mul_epu32(r[2].v, packednineteen.v); - r1_2 = _mm_slli_epi32(r1, 1); - r3 = _mm_mul_epu32(r[3].v, packednineteen.v); - r4 = _mm_mul_epu32(r[4].v, packednineteen.v); - r3_2 = _mm_slli_epi32(r3, 1); - r5 = _mm_mul_epu32(r[5].v, packednineteen.v); - r6 = _mm_mul_epu32(r[6].v, packednineteen.v); - r5_2 = _mm_slli_epi32(r5, 1); - r7 = _mm_mul_epu32(r[7].v, packednineteen.v); - r8 = _mm_mul_epu32(r[8].v, packednineteen.v); - r7_2 = _mm_slli_epi32(r7, 1); - r9 = _mm_mul_epu32(r[9].v, packednineteen.v); - r9_2 = _mm_slli_epi32(r9, 1); - - out[0].v = _mm_add_epi64(out[0].v, _mm_add_epi64(_mm_mul_epu32(r9_2, s[1].v), _mm_add_epi64(_mm_mul_epu32(r8, s[2].v), _mm_add_epi64(_mm_mul_epu32(r7_2, s[3].v), _mm_add_epi64(_mm_mul_epu32(r6, s[4].v), _mm_add_epi64(_mm_mul_epu32(r5_2, s[5].v), _mm_add_epi64(_mm_mul_epu32(r4, s[6].v), _mm_add_epi64(_mm_mul_epu32(r3_2, s[7].v), _mm_add_epi64(_mm_mul_epu32(r2, s[8].v), _mm_mul_epu32(r1_2, s[9].v)))))))))); - out[1].v = _mm_add_epi64(out[1].v, _mm_add_epi64(_mm_mul_epu32(r9 , s[2].v), _mm_add_epi64(_mm_mul_epu32(r8, s[3].v), _mm_add_epi64(_mm_mul_epu32(r7 , s[4].v), _mm_add_epi64(_mm_mul_epu32(r6, s[5].v), _mm_add_epi64(_mm_mul_epu32(r5 , s[6].v), _mm_add_epi64(_mm_mul_epu32(r4, s[7].v), _mm_add_epi64(_mm_mul_epu32(r3 , s[8].v), _mm_mul_epu32(r2, s[9].v))))))))); - out[2].v = _mm_add_epi64(out[2].v, _mm_add_epi64(_mm_mul_epu32(r9_2, s[3].v), _mm_add_epi64(_mm_mul_epu32(r8, s[4].v), _mm_add_epi64(_mm_mul_epu32(r7_2, s[5].v), _mm_add_epi64(_mm_mul_epu32(r6, s[6].v), _mm_add_epi64(_mm_mul_epu32(r5_2, s[7].v), _mm_add_epi64(_mm_mul_epu32(r4, s[8].v), _mm_mul_epu32(r3_2, s[9].v)))))))); - out[3].v = _mm_add_epi64(out[3].v, _mm_add_epi64(_mm_mul_epu32(r9 , s[4].v), _mm_add_epi64(_mm_mul_epu32(r8, s[5].v), _mm_add_epi64(_mm_mul_epu32(r7 , s[6].v), _mm_add_epi64(_mm_mul_epu32(r6, s[7].v), _mm_add_epi64(_mm_mul_epu32(r5 , s[8].v), _mm_mul_epu32(r4, s[9].v))))))); - out[4].v = _mm_add_epi64(out[4].v, _mm_add_epi64(_mm_mul_epu32(r9_2, s[5].v), _mm_add_epi64(_mm_mul_epu32(r8, s[6].v), _mm_add_epi64(_mm_mul_epu32(r7_2, s[7].v), _mm_add_epi64(_mm_mul_epu32(r6, s[8].v), _mm_mul_epu32(r5_2, s[9].v)))))); - out[5].v = _mm_add_epi64(out[5].v, _mm_add_epi64(_mm_mul_epu32(r9 , s[6].v), _mm_add_epi64(_mm_mul_epu32(r8, s[7].v), _mm_add_epi64(_mm_mul_epu32(r7 , s[8].v), _mm_mul_epu32(r6, s[9].v))))); - out[6].v = _mm_add_epi64(out[6].v, _mm_add_epi64(_mm_mul_epu32(r9_2, s[7].v), _mm_add_epi64(_mm_mul_epu32(r8, s[8].v), _mm_mul_epu32(r7_2, s[9].v)))); - out[7].v = _mm_add_epi64(out[7].v, _mm_add_epi64(_mm_mul_epu32(r9 , s[8].v), _mm_mul_epu32(r8, s[9].v))); - out[8].v = _mm_add_epi64(out[8].v, _mm_mul_epu32(r9_2, s[9].v)); - - c1 = _mm_srli_epi64(out[0].v, 26); c2 = _mm_srli_epi64(out[4].v, 26); out[0].v = _mm_and_si128(out[0].v, packedmask26.v); out[4].v = _mm_and_si128(out[4].v, packedmask26.v); out[1].v = _mm_add_epi64(out[1].v, c1); out[5].v = _mm_add_epi64(out[5].v, c2); - c1 = _mm_srli_epi64(out[1].v, 25); c2 = _mm_srli_epi64(out[5].v, 25); out[1].v = _mm_and_si128(out[1].v, packedmask25.v); out[5].v = _mm_and_si128(out[5].v, packedmask25.v); out[2].v = _mm_add_epi64(out[2].v, c1); out[6].v = _mm_add_epi64(out[6].v, c2); - c1 = _mm_srli_epi64(out[2].v, 26); c2 = _mm_srli_epi64(out[6].v, 26); out[2].v = _mm_and_si128(out[2].v, packedmask26.v); out[6].v = _mm_and_si128(out[6].v, packedmask26.v); out[3].v = _mm_add_epi64(out[3].v, c1); out[7].v = _mm_add_epi64(out[7].v, c2); - c1 = _mm_srli_epi64(out[3].v, 25); c2 = _mm_srli_epi64(out[7].v, 25); out[3].v = _mm_and_si128(out[3].v, packedmask25.v); out[7].v = _mm_and_si128(out[7].v, packedmask25.v); out[4].v = _mm_add_epi64(out[4].v, c1); out[8].v = _mm_add_epi64(out[8].v, c2); - c2 = _mm_srli_epi64(out[8].v, 26); out[8].v = _mm_and_si128(out[8].v, packedmask26.v); out[9].v = _mm_add_epi64(out[9].v, c2); - c2 = _mm_srli_epi64(out[9].v, 25); out[9].v = _mm_and_si128(out[9].v, packedmask25.v); out[0].v = _mm_add_epi64(out[0].v, _mm_mul_epu32(c2, packednineteen.v)); - c1 = _mm_srli_epi64(out[0].v, 26); c2 = _mm_srli_epi64(out[4].v, 26); out[0].v = _mm_and_si128(out[0].v, packedmask26.v); out[4].v = _mm_and_si128(out[4].v, packedmask26.v); out[1].v = _mm_add_epi64(out[1].v, c1); out[5].v = _mm_add_epi64(out[5].v, c2); -} - -/* multiply a bignum */ -static void -curve25519_mul(bignum25519 out, const bignum25519 r, const bignum25519 s) { - xmmi m01,m23,m45,m67,m89; - xmmi m0123,m4567; - xmmi s0123,s4567; - xmmi s01,s23,s45,s67,s89; - xmmi s12,s34,s56,s78,s9; - xmmi r0,r2,r4,r6,r8; - xmmi r1,r3,r5,r7,r9; - xmmi r119,r219,r319,r419,r519,r619,r719,r819,r919; - xmmi c1,c2,c3; - - s0123 = _mm_load_si128((xmmi*)s + 0); - s01 = _mm_shuffle_epi32(s0123,_MM_SHUFFLE(3,1,2,0)); - s12 = _mm_shuffle_epi32(s0123, _MM_SHUFFLE(2,2,1,1)); - s23 = _mm_shuffle_epi32(s0123,_MM_SHUFFLE(3,3,2,2)); - s4567 = _mm_load_si128((xmmi*)s + 1); - s34 = _mm_unpacklo_epi64(_mm_srli_si128(s0123,12),s4567); - s45 = _mm_shuffle_epi32(s4567,_MM_SHUFFLE(3,1,2,0)); - s56 = _mm_shuffle_epi32(s4567, _MM_SHUFFLE(2,2,1,1)); - s67 = _mm_shuffle_epi32(s4567,_MM_SHUFFLE(3,3,2,2)); - s89 = _mm_load_si128((xmmi*)s + 2); - s78 = _mm_unpacklo_epi64(_mm_srli_si128(s4567,12),s89); - s89 = _mm_shuffle_epi32(s89,_MM_SHUFFLE(3,1,2,0)); - s9 = _mm_shuffle_epi32(s89, _MM_SHUFFLE(3,3,2,2)); - - r0 = _mm_load_si128((xmmi*)r + 0); - r1 = _mm_shuffle_epi32(r0, _MM_SHUFFLE(1,1,1,1)); - r1 = _mm_add_epi64(r1, _mm_and_si128(r1, sse2_top64bitmask.v)); - r2 = _mm_shuffle_epi32(r0, _MM_SHUFFLE(2,2,2,2)); - r3 = _mm_shuffle_epi32(r0, _MM_SHUFFLE(3,3,3,3)); - r3 = _mm_add_epi64(r3, _mm_and_si128(r3, sse2_top64bitmask.v)); - r0 = _mm_shuffle_epi32(r0, _MM_SHUFFLE(0,0,0,0)); - r4 = _mm_load_si128((xmmi*)r + 1); - r5 = _mm_shuffle_epi32(r4, _MM_SHUFFLE(1,1,1,1)); - r5 = _mm_add_epi64(r5, _mm_and_si128(r5, sse2_top64bitmask.v)); - r6 = _mm_shuffle_epi32(r4, _MM_SHUFFLE(2,2,2,2)); - r7 = _mm_shuffle_epi32(r4, _MM_SHUFFLE(3,3,3,3)); - r7 = _mm_add_epi64(r7, _mm_and_si128(r7, sse2_top64bitmask.v)); - r4 = _mm_shuffle_epi32(r4, _MM_SHUFFLE(0,0,0,0)); - r8 = _mm_load_si128((xmmi*)r + 2); - r9 = _mm_shuffle_epi32(r8, _MM_SHUFFLE(3,1,3,1)); - r9 = _mm_add_epi64(r9, _mm_and_si128(r9, sse2_top64bitmask.v)); - r8 = _mm_shuffle_epi32(r8, _MM_SHUFFLE(3,0,3,0)); - - m01 = _mm_mul_epu32(r1,s01); - m23 = _mm_mul_epu32(r1,s23); - m45 = _mm_mul_epu32(r1,s45); - m67 = _mm_mul_epu32(r1,s67); - m23 = _mm_add_epi64(m23,_mm_mul_epu32(r3,s01)); - m45 = _mm_add_epi64(m45,_mm_mul_epu32(r3,s23)); - m67 = _mm_add_epi64(m67,_mm_mul_epu32(r3,s45)); - m89 = _mm_mul_epu32(r1,s89); - m45 = _mm_add_epi64(m45,_mm_mul_epu32(r5,s01)); - m67 = _mm_add_epi64(m67,_mm_mul_epu32(r5,s23)); - m89 = _mm_add_epi64(m89,_mm_mul_epu32(r3,s67)); - m67 = _mm_add_epi64(m67,_mm_mul_epu32(r7,s01)); - m89 = _mm_add_epi64(m89,_mm_mul_epu32(r5,s45)); - m89 = _mm_add_epi64(m89,_mm_mul_epu32(r7,s23)); - m89 = _mm_add_epi64(m89,_mm_mul_epu32(r9,s01)); - - /* shift up */ - m89 = _mm_unpackhi_epi64(m67,_mm_slli_si128(m89,8)); - m67 = _mm_unpackhi_epi64(m45,_mm_slli_si128(m67,8)); - m45 = _mm_unpackhi_epi64(m23,_mm_slli_si128(m45,8)); - m23 = _mm_unpackhi_epi64(m01,_mm_slli_si128(m23,8)); - m01 = _mm_unpackhi_epi64(_mm_setzero_si128(),_mm_slli_si128(m01,8)); - - m01 = _mm_add_epi64(m01,_mm_mul_epu32(r0,s01)); - m23 = _mm_add_epi64(m23,_mm_mul_epu32(r0,s23)); - m45 = _mm_add_epi64(m45,_mm_mul_epu32(r0,s45)); - m67 = _mm_add_epi64(m67,_mm_mul_epu32(r0,s67)); - m23 = _mm_add_epi64(m23,_mm_mul_epu32(r2,s01)); - m45 = _mm_add_epi64(m45,_mm_mul_epu32(r2,s23)); - m67 = _mm_add_epi64(m67,_mm_mul_epu32(r4,s23)); - m89 = _mm_add_epi64(m89,_mm_mul_epu32(r0,s89)); - m45 = _mm_add_epi64(m45,_mm_mul_epu32(r4,s01)); - m67 = _mm_add_epi64(m67,_mm_mul_epu32(r2,s45)); - m89 = _mm_add_epi64(m89,_mm_mul_epu32(r2,s67)); - m67 = _mm_add_epi64(m67,_mm_mul_epu32(r6,s01)); - m89 = _mm_add_epi64(m89,_mm_mul_epu32(r4,s45)); - m89 = _mm_add_epi64(m89,_mm_mul_epu32(r6,s23)); - m89 = _mm_add_epi64(m89,_mm_mul_epu32(r8,s01)); - - r219 = _mm_mul_epu32(r2, packednineteen.v); - r419 = _mm_mul_epu32(r4, packednineteen.v); - r619 = _mm_mul_epu32(r6, packednineteen.v); - r819 = _mm_mul_epu32(r8, packednineteen.v); - r119 = _mm_shuffle_epi32(r1,_MM_SHUFFLE(0,0,2,2)); r119 = _mm_mul_epu32(r119, packednineteen.v); - r319 = _mm_shuffle_epi32(r3,_MM_SHUFFLE(0,0,2,2)); r319 = _mm_mul_epu32(r319, packednineteen.v); - r519 = _mm_shuffle_epi32(r5,_MM_SHUFFLE(0,0,2,2)); r519 = _mm_mul_epu32(r519, packednineteen.v); - r719 = _mm_shuffle_epi32(r7,_MM_SHUFFLE(0,0,2,2)); r719 = _mm_mul_epu32(r719, packednineteen.v); - r919 = _mm_shuffle_epi32(r9,_MM_SHUFFLE(0,0,2,2)); r919 = _mm_mul_epu32(r919, packednineteen.v); - - m01 = _mm_add_epi64(m01,_mm_mul_epu32(r919,s12)); - m23 = _mm_add_epi64(m23,_mm_mul_epu32(r919,s34)); - m45 = _mm_add_epi64(m45,_mm_mul_epu32(r919,s56)); - m67 = _mm_add_epi64(m67,_mm_mul_epu32(r919,s78)); - m01 = _mm_add_epi64(m01,_mm_mul_epu32(r719,s34)); - m23 = _mm_add_epi64(m23,_mm_mul_epu32(r719,s56)); - m45 = _mm_add_epi64(m45,_mm_mul_epu32(r719,s78)); - m67 = _mm_add_epi64(m67,_mm_mul_epu32(r719,s9)); - m01 = _mm_add_epi64(m01,_mm_mul_epu32(r519,s56)); - m23 = _mm_add_epi64(m23,_mm_mul_epu32(r519,s78)); - m45 = _mm_add_epi64(m45,_mm_mul_epu32(r519,s9)); - m67 = _mm_add_epi64(m67,_mm_mul_epu32(r819,s89)); - m01 = _mm_add_epi64(m01,_mm_mul_epu32(r319,s78)); - m23 = _mm_add_epi64(m23,_mm_mul_epu32(r319,s9)); - m45 = _mm_add_epi64(m45,_mm_mul_epu32(r619,s89)); - m89 = _mm_add_epi64(m89,_mm_mul_epu32(r919,s9)); - m01 = _mm_add_epi64(m01,_mm_mul_epu32(r819,s23)); - m23 = _mm_add_epi64(m23,_mm_mul_epu32(r819,s45)); - m45 = _mm_add_epi64(m45,_mm_mul_epu32(r819,s67)); - m01 = _mm_add_epi64(m01,_mm_mul_epu32(r619,s45)); - m23 = _mm_add_epi64(m23,_mm_mul_epu32(r619,s67)); - m01 = _mm_add_epi64(m01,_mm_mul_epu32(r419,s67)); - m23 = _mm_add_epi64(m23,_mm_mul_epu32(r419,s89)); - m01 = _mm_add_epi64(m01,_mm_mul_epu32(r219,s89)); - m01 = _mm_add_epi64(m01,_mm_mul_epu32(r119,s9)); - - r0 = _mm_unpacklo_epi64(m01, m45); - r1 = _mm_unpackhi_epi64(m01, m45); - r2 = _mm_unpacklo_epi64(m23, m67); - r3 = _mm_unpackhi_epi64(m23, m67); - r4 = _mm_unpacklo_epi64(m89, m89); - r5 = _mm_unpackhi_epi64(m89, m89); - - c1 = _mm_srli_epi64(r0, 26); c2 = _mm_srli_epi64(r2, 26); r0 = _mm_and_si128(r0, packedmask26.v); r2 = _mm_and_si128(r2, packedmask26.v); r1 = _mm_add_epi64(r1, c1); r3 = _mm_add_epi64(r3, c2); - c1 = _mm_srli_epi64(r1, 25); c2 = _mm_srli_epi64(r3, 25); r1 = _mm_and_si128(r1, packedmask25.v); r3 = _mm_and_si128(r3, packedmask25.v); r2 = _mm_add_epi64(r2, c1); r4 = _mm_add_epi64(r4, c2); c3 = _mm_slli_si128(c2, 8); - c1 = _mm_srli_epi64(r4, 26); r4 = _mm_and_si128(r4, packedmask26.v); r5 = _mm_add_epi64(r5, c1); - c1 = _mm_srli_epi64(r5, 25); r5 = _mm_and_si128(r5, packedmask25.v); r0 = _mm_add_epi64(r0, _mm_unpackhi_epi64(_mm_mul_epu32(c1, packednineteen.v), c3)); - c1 = _mm_srli_epi64(r0, 26); c2 = _mm_srli_epi64(r2, 26); r0 = _mm_and_si128(r0, packedmask26.v); r2 = _mm_and_si128(r2, packedmask26.v); r1 = _mm_add_epi64(r1, c1); r3 = _mm_add_epi64(r3, c2); - - m0123 = _mm_unpacklo_epi32(r0, r1); - m4567 = _mm_unpackhi_epi32(r0, r1); - m0123 = _mm_unpacklo_epi64(m0123, _mm_unpacklo_epi32(r2, r3)); - m4567 = _mm_unpacklo_epi64(m4567, _mm_unpackhi_epi32(r2, r3)); - m89 = _mm_unpackhi_epi32(r4, r5); - - _mm_store_si128((xmmi*)out + 0, m0123); - _mm_store_si128((xmmi*)out + 1, m4567); - _mm_store_si128((xmmi*)out + 2, m89); -} - -typedef struct bignum25519mulprecomp_t { - xmmi r0,r2,r4,r6,r8; - xmmi r1,r3,r5,r7,r9; - xmmi r119,r219,r319,r419,r519,r619,r719,r819,r919; -} bignum25519mulprecomp; - -/* precompute a constant to multiply by */ -DONNA_INLINE static void -curve25519_mul_precompute(bignum25519mulprecomp *pre, const bignum25519 r) { - pre->r0 = _mm_load_si128((xmmi*)r + 0); - pre->r1 = _mm_shuffle_epi32(pre->r0, _MM_SHUFFLE(1,1,1,1)); - pre->r1 = _mm_add_epi64(pre->r1, _mm_and_si128(pre->r1, sse2_top64bitmask.v)); - pre->r2 = _mm_shuffle_epi32(pre->r0, _MM_SHUFFLE(2,2,2,2)); - pre->r3 = _mm_shuffle_epi32(pre->r0, _MM_SHUFFLE(3,3,3,3)); - pre->r3 = _mm_add_epi64(pre->r3, _mm_and_si128(pre->r3, sse2_top64bitmask.v)); - pre->r0 = _mm_shuffle_epi32(pre->r0, _MM_SHUFFLE(0,0,0,0)); - pre->r4 = _mm_load_si128((xmmi*)r + 1); - pre->r5 = _mm_shuffle_epi32(pre->r4, _MM_SHUFFLE(1,1,1,1)); - pre->r5 = _mm_add_epi64(pre->r5, _mm_and_si128(pre->r5, sse2_top64bitmask.v)); - pre->r6 = _mm_shuffle_epi32(pre->r4, _MM_SHUFFLE(2,2,2,2)); - pre->r7 = _mm_shuffle_epi32(pre->r4, _MM_SHUFFLE(3,3,3,3)); - pre->r7 = _mm_add_epi64(pre->r7, _mm_and_si128(pre->r7, sse2_top64bitmask.v)); - pre->r4 = _mm_shuffle_epi32(pre->r4, _MM_SHUFFLE(0,0,0,0)); - pre->r8 = _mm_load_si128((xmmi*)r + 2); - pre->r9 = _mm_shuffle_epi32(pre->r8, _MM_SHUFFLE(3,1,3,1)); - pre->r9 = _mm_add_epi64(pre->r9, _mm_and_si128(pre->r9, sse2_top64bitmask.v)); - pre->r8 = _mm_shuffle_epi32(pre->r8, _MM_SHUFFLE(3,0,3,0)); - - pre->r219 = _mm_mul_epu32(pre->r2, packednineteen.v); - pre->r419 = _mm_mul_epu32(pre->r4, packednineteen.v); - pre->r619 = _mm_mul_epu32(pre->r6, packednineteen.v); - pre->r819 = _mm_mul_epu32(pre->r8, packednineteen.v); - pre->r119 = _mm_shuffle_epi32(pre->r1,_MM_SHUFFLE(0,0,2,2)); pre->r119 = _mm_mul_epu32(pre->r119, packednineteen.v); - pre->r319 = _mm_shuffle_epi32(pre->r3,_MM_SHUFFLE(0,0,2,2)); pre->r319 = _mm_mul_epu32(pre->r319, packednineteen.v); - pre->r519 = _mm_shuffle_epi32(pre->r5,_MM_SHUFFLE(0,0,2,2)); pre->r519 = _mm_mul_epu32(pre->r519, packednineteen.v); - pre->r719 = _mm_shuffle_epi32(pre->r7,_MM_SHUFFLE(0,0,2,2)); pre->r719 = _mm_mul_epu32(pre->r719, packednineteen.v); - pre->r919 = _mm_shuffle_epi32(pre->r9,_MM_SHUFFLE(0,0,2,2)); pre->r919 = _mm_mul_epu32(pre->r919, packednineteen.v); -} - - -/* multiply a bignum by a pre-computed constant */ -DONNA_INLINE static void -curve25519_mul_precomputed(bignum25519 out, const bignum25519 s, const bignum25519mulprecomp *r) { - xmmi m01,m23,m45,m67,m89; - xmmi m0123,m4567; - xmmi s0123,s4567; - xmmi s01,s23,s45,s67,s89; - xmmi s12,s34,s56,s78,s9; - xmmi r0,r1,r2,r3,r4,r5; - xmmi c1,c2,c3; - - s0123 = _mm_load_si128((xmmi*)s + 0); - s01 = _mm_shuffle_epi32(s0123,_MM_SHUFFLE(3,1,2,0)); - s12 = _mm_shuffle_epi32(s0123, _MM_SHUFFLE(2,2,1,1)); - s23 = _mm_shuffle_epi32(s0123,_MM_SHUFFLE(3,3,2,2)); - s4567 = _mm_load_si128((xmmi*)s + 1); - s34 = _mm_unpacklo_epi64(_mm_srli_si128(s0123,12),s4567); - s45 = _mm_shuffle_epi32(s4567,_MM_SHUFFLE(3,1,2,0)); - s56 = _mm_shuffle_epi32(s4567, _MM_SHUFFLE(2,2,1,1)); - s67 = _mm_shuffle_epi32(s4567,_MM_SHUFFLE(3,3,2,2)); - s89 = _mm_load_si128((xmmi*)s + 2); - s78 = _mm_unpacklo_epi64(_mm_srli_si128(s4567,12),s89); - s89 = _mm_shuffle_epi32(s89,_MM_SHUFFLE(3,1,2,0)); - s9 = _mm_shuffle_epi32(s89, _MM_SHUFFLE(3,3,2,2)); - - m01 = _mm_mul_epu32(r->r1,s01); - m23 = _mm_mul_epu32(r->r1,s23); - m45 = _mm_mul_epu32(r->r1,s45); - m67 = _mm_mul_epu32(r->r1,s67); - m23 = _mm_add_epi64(m23,_mm_mul_epu32(r->r3,s01)); - m45 = _mm_add_epi64(m45,_mm_mul_epu32(r->r3,s23)); - m67 = _mm_add_epi64(m67,_mm_mul_epu32(r->r3,s45)); - m89 = _mm_mul_epu32(r->r1,s89); - m45 = _mm_add_epi64(m45,_mm_mul_epu32(r->r5,s01)); - m67 = _mm_add_epi64(m67,_mm_mul_epu32(r->r5,s23)); - m89 = _mm_add_epi64(m89,_mm_mul_epu32(r->r3,s67)); - m67 = _mm_add_epi64(m67,_mm_mul_epu32(r->r7,s01)); - m89 = _mm_add_epi64(m89,_mm_mul_epu32(r->r5,s45)); - m89 = _mm_add_epi64(m89,_mm_mul_epu32(r->r7,s23)); - m89 = _mm_add_epi64(m89,_mm_mul_epu32(r->r9,s01)); - - /* shift up */ - m89 = _mm_unpackhi_epi64(m67,_mm_slli_si128(m89,8)); - m67 = _mm_unpackhi_epi64(m45,_mm_slli_si128(m67,8)); - m45 = _mm_unpackhi_epi64(m23,_mm_slli_si128(m45,8)); - m23 = _mm_unpackhi_epi64(m01,_mm_slli_si128(m23,8)); - m01 = _mm_unpackhi_epi64(_mm_setzero_si128(),_mm_slli_si128(m01,8)); - - m01 = _mm_add_epi64(m01,_mm_mul_epu32(r->r0,s01)); - m23 = _mm_add_epi64(m23,_mm_mul_epu32(r->r0,s23)); - m45 = _mm_add_epi64(m45,_mm_mul_epu32(r->r0,s45)); - m67 = _mm_add_epi64(m67,_mm_mul_epu32(r->r0,s67)); - m23 = _mm_add_epi64(m23,_mm_mul_epu32(r->r2,s01)); - m45 = _mm_add_epi64(m45,_mm_mul_epu32(r->r2,s23)); - m67 = _mm_add_epi64(m67,_mm_mul_epu32(r->r4,s23)); - m89 = _mm_add_epi64(m89,_mm_mul_epu32(r->r0,s89)); - m45 = _mm_add_epi64(m45,_mm_mul_epu32(r->r4,s01)); - m67 = _mm_add_epi64(m67,_mm_mul_epu32(r->r2,s45)); - m89 = _mm_add_epi64(m89,_mm_mul_epu32(r->r2,s67)); - m67 = _mm_add_epi64(m67,_mm_mul_epu32(r->r6,s01)); - m89 = _mm_add_epi64(m89,_mm_mul_epu32(r->r4,s45)); - m89 = _mm_add_epi64(m89,_mm_mul_epu32(r->r6,s23)); - m89 = _mm_add_epi64(m89,_mm_mul_epu32(r->r8,s01)); - m01 = _mm_add_epi64(m01,_mm_mul_epu32(r->r919,s12)); - m23 = _mm_add_epi64(m23,_mm_mul_epu32(r->r919,s34)); - m45 = _mm_add_epi64(m45,_mm_mul_epu32(r->r919,s56)); - m67 = _mm_add_epi64(m67,_mm_mul_epu32(r->r919,s78)); - m01 = _mm_add_epi64(m01,_mm_mul_epu32(r->r719,s34)); - m23 = _mm_add_epi64(m23,_mm_mul_epu32(r->r719,s56)); - m45 = _mm_add_epi64(m45,_mm_mul_epu32(r->r719,s78)); - m67 = _mm_add_epi64(m67,_mm_mul_epu32(r->r719,s9)); - m01 = _mm_add_epi64(m01,_mm_mul_epu32(r->r519,s56)); - m23 = _mm_add_epi64(m23,_mm_mul_epu32(r->r519,s78)); - m45 = _mm_add_epi64(m45,_mm_mul_epu32(r->r519,s9)); - m67 = _mm_add_epi64(m67,_mm_mul_epu32(r->r819,s89)); - m01 = _mm_add_epi64(m01,_mm_mul_epu32(r->r319,s78)); - m23 = _mm_add_epi64(m23,_mm_mul_epu32(r->r319,s9)); - m45 = _mm_add_epi64(m45,_mm_mul_epu32(r->r619,s89)); - m89 = _mm_add_epi64(m89,_mm_mul_epu32(r->r919,s9)); - m01 = _mm_add_epi64(m01,_mm_mul_epu32(r->r819,s23)); - m23 = _mm_add_epi64(m23,_mm_mul_epu32(r->r819,s45)); - m45 = _mm_add_epi64(m45,_mm_mul_epu32(r->r819,s67)); - m01 = _mm_add_epi64(m01,_mm_mul_epu32(r->r619,s45)); - m23 = _mm_add_epi64(m23,_mm_mul_epu32(r->r619,s67)); - m01 = _mm_add_epi64(m01,_mm_mul_epu32(r->r419,s67)); - m23 = _mm_add_epi64(m23,_mm_mul_epu32(r->r419,s89)); - m01 = _mm_add_epi64(m01,_mm_mul_epu32(r->r219,s89)); - m01 = _mm_add_epi64(m01,_mm_mul_epu32(r->r119,s9)); - - r0 = _mm_unpacklo_epi64(m01, m45); - r1 = _mm_unpackhi_epi64(m01, m45); - r2 = _mm_unpacklo_epi64(m23, m67); - r3 = _mm_unpackhi_epi64(m23, m67); - r4 = _mm_unpacklo_epi64(m89, m89); - r5 = _mm_unpackhi_epi64(m89, m89); - - c1 = _mm_srli_epi64(r0, 26); c2 = _mm_srli_epi64(r2, 26); r0 = _mm_and_si128(r0, packedmask26.v); r2 = _mm_and_si128(r2, packedmask26.v); r1 = _mm_add_epi64(r1, c1); r3 = _mm_add_epi64(r3, c2); - c1 = _mm_srli_epi64(r1, 25); c2 = _mm_srli_epi64(r3, 25); r1 = _mm_and_si128(r1, packedmask25.v); r3 = _mm_and_si128(r3, packedmask25.v); r2 = _mm_add_epi64(r2, c1); r4 = _mm_add_epi64(r4, c2); c3 = _mm_slli_si128(c2, 8); - c1 = _mm_srli_epi64(r4, 26); r4 = _mm_and_si128(r4, packedmask26.v); r5 = _mm_add_epi64(r5, c1); - c1 = _mm_srli_epi64(r5, 25); r5 = _mm_and_si128(r5, packedmask25.v); r0 = _mm_add_epi64(r0, _mm_unpackhi_epi64(_mm_mul_epu32(c1, packednineteen.v), c3)); - c1 = _mm_srli_epi64(r0, 26); c2 = _mm_srli_epi64(r2, 26); r0 = _mm_and_si128(r0, packedmask26.v); r2 = _mm_and_si128(r2, packedmask26.v); r1 = _mm_add_epi64(r1, c1); r3 = _mm_add_epi64(r3, c2); - - m0123 = _mm_unpacklo_epi32(r0, r1); - m4567 = _mm_unpackhi_epi32(r0, r1); - m0123 = _mm_unpacklo_epi64(m0123, _mm_unpacklo_epi32(r2, r3)); - m4567 = _mm_unpacklo_epi64(m4567, _mm_unpackhi_epi32(r2, r3)); - m89 = _mm_unpackhi_epi32(r4, r5); - - _mm_store_si128((xmmi*)out + 0, m0123); - _mm_store_si128((xmmi*)out + 1, m4567); - _mm_store_si128((xmmi*)out + 2, m89); -} - -/* square a bignum 'count' times */ -#define curve25519_square(r,x) curve25519_square_times(r,x,1) - -static void -curve25519_square_times(bignum25519 r, const bignum25519 in, int count) { - xmmi m01,m23,m45,m67,m89; - xmmi r0,r1,r2,r3,r4,r5,r6,r7,r8,r9; - xmmi r0a,r1a,r2a,r3a,r7a,r9a; - xmmi r0123,r4567; - xmmi r01,r23,r45,r67,r6x,r89,r8x; - xmmi r12,r34,r56,r78,r9x; - xmmi r5619; - xmmi c1,c2,c3; - - r0123 = _mm_load_si128((xmmi*)in + 0); - r01 = _mm_shuffle_epi32(r0123,_MM_SHUFFLE(3,1,2,0)); - r23 = _mm_shuffle_epi32(r0123,_MM_SHUFFLE(3,3,2,2)); - r4567 = _mm_load_si128((xmmi*)in + 1); - r45 = _mm_shuffle_epi32(r4567,_MM_SHUFFLE(3,1,2,0)); - r67 = _mm_shuffle_epi32(r4567,_MM_SHUFFLE(3,3,2,2)); - r89 = _mm_load_si128((xmmi*)in + 2); - r89 = _mm_shuffle_epi32(r89,_MM_SHUFFLE(3,1,2,0)); - - do { - r12 = _mm_unpackhi_epi64(r01, _mm_slli_si128(r23, 8)); - r0 = _mm_shuffle_epi32(r01, _MM_SHUFFLE(0,0,0,0)); - r0 = _mm_add_epi64(r0, _mm_and_si128(r0, sse2_top64bitmask.v)); - r0a = _mm_shuffle_epi32(r0,_MM_SHUFFLE(3,2,1,2)); - r1 = _mm_shuffle_epi32(r01, _MM_SHUFFLE(2,2,2,2)); - r2 = _mm_shuffle_epi32(r23, _MM_SHUFFLE(0,0,0,0)); - r2 = _mm_add_epi64(r2, _mm_and_si128(r2, sse2_top64bitmask.v)); - r2a = _mm_shuffle_epi32(r2,_MM_SHUFFLE(3,2,1,2)); - r3 = _mm_shuffle_epi32(r23, _MM_SHUFFLE(2,2,2,2)); - r34 = _mm_unpackhi_epi64(r23, _mm_slli_si128(r45, 8)); - r4 = _mm_shuffle_epi32(r45, _MM_SHUFFLE(0,0,0,0)); - r4 = _mm_add_epi64(r4, _mm_and_si128(r4, sse2_top64bitmask.v)); - r56 = _mm_unpackhi_epi64(r45, _mm_slli_si128(r67, 8)); - r5619 = _mm_mul_epu32(r56, packednineteen.v); - r5 = _mm_shuffle_epi32(r5619, _MM_SHUFFLE(1,1,1,0)); - r6 = _mm_shuffle_epi32(r5619, _MM_SHUFFLE(3,2,3,2)); - r78 = _mm_unpackhi_epi64(r67, _mm_slli_si128(r89, 8)); - r6x = _mm_unpacklo_epi64(r67, _mm_setzero_si128()); - r7 = _mm_shuffle_epi32(r67, _MM_SHUFFLE(2,2,2,2)); - r7 = _mm_mul_epu32(r7, packed3819.v); - r7a = _mm_shuffle_epi32(r7, _MM_SHUFFLE(3,3,3,2)); - r8x = _mm_unpacklo_epi64(r89, _mm_setzero_si128()); - r8 = _mm_shuffle_epi32(r89, _MM_SHUFFLE(0,0,0,0)); - r8 = _mm_mul_epu32(r8, packednineteen.v); - r9 = _mm_shuffle_epi32(r89, _MM_SHUFFLE(2,2,2,2)); - r9x = _mm_slli_epi32(_mm_shuffle_epi32(r89, _MM_SHUFFLE(3,3,3,2)), 1); - r9 = _mm_mul_epu32(r9, packed3819.v); - r9a = _mm_shuffle_epi32(r9, _MM_SHUFFLE(2,2,2,2)); - - m01 = _mm_mul_epu32(r01, r0); - m23 = _mm_mul_epu32(r23, r0a); - m45 = _mm_mul_epu32(r45, r0a); - m45 = _mm_add_epi64(m45, _mm_mul_epu32(r23, r2)); - r23 = _mm_slli_epi32(r23, 1); - m67 = _mm_mul_epu32(r67, r0a); - m67 = _mm_add_epi64(m67, _mm_mul_epu32(r45, r2a)); - m89 = _mm_mul_epu32(r89, r0a); - m89 = _mm_add_epi64(m89, _mm_mul_epu32(r67, r2a)); - r67 = _mm_slli_epi32(r67, 1); - m89 = _mm_add_epi64(m89, _mm_mul_epu32(r45, r4)); - r45 = _mm_slli_epi32(r45, 1); - - r1 = _mm_slli_epi32(r1, 1); - r3 = _mm_slli_epi32(r3, 1); - r1a = _mm_add_epi64(r1, _mm_and_si128(r1, sse2_bot64bitmask.v)); - r3a = _mm_add_epi64(r3, _mm_and_si128(r3, sse2_bot64bitmask.v)); - - m23 = _mm_add_epi64(m23, _mm_mul_epu32(r12, r1)); - m45 = _mm_add_epi64(m45, _mm_mul_epu32(r34, r1a)); - m67 = _mm_add_epi64(m67, _mm_mul_epu32(r56, r1a)); - m67 = _mm_add_epi64(m67, _mm_mul_epu32(r34, r3)); - r34 = _mm_slli_epi32(r34, 1); - m89 = _mm_add_epi64(m89, _mm_mul_epu32(r78, r1a)); - r78 = _mm_slli_epi32(r78, 1); - m89 = _mm_add_epi64(m89, _mm_mul_epu32(r56, r3a)); - r56 = _mm_slli_epi32(r56, 1); - - m01 = _mm_add_epi64(m01, _mm_mul_epu32(_mm_slli_epi32(r12, 1), r9)); - m01 = _mm_add_epi64(m01, _mm_mul_epu32(r34, r7)); - m23 = _mm_add_epi64(m23, _mm_mul_epu32(r34, r9)); - m01 = _mm_add_epi64(m01, _mm_mul_epu32(r56, r5)); - m23 = _mm_add_epi64(m23, _mm_mul_epu32(r56, r7)); - m45 = _mm_add_epi64(m45, _mm_mul_epu32(r56, r9)); - m01 = _mm_add_epi64(m01, _mm_mul_epu32(r23, r8)); - m01 = _mm_add_epi64(m01, _mm_mul_epu32(r45, r6)); - m23 = _mm_add_epi64(m23, _mm_mul_epu32(r45, r8)); - m23 = _mm_add_epi64(m23, _mm_mul_epu32(r6x, r6)); - m45 = _mm_add_epi64(m45, _mm_mul_epu32(r78, r7a)); - m67 = _mm_add_epi64(m67, _mm_mul_epu32(r78, r9)); - m45 = _mm_add_epi64(m45, _mm_mul_epu32(r67, r8)); - m67 = _mm_add_epi64(m67, _mm_mul_epu32(r8x, r8)); - m89 = _mm_add_epi64(m89, _mm_mul_epu32(r9x, r9a)); - - r0 = _mm_unpacklo_epi64(m01, m45); - r1 = _mm_unpackhi_epi64(m01, m45); - r2 = _mm_unpacklo_epi64(m23, m67); - r3 = _mm_unpackhi_epi64(m23, m67); - r4 = _mm_unpacklo_epi64(m89, m89); - r5 = _mm_unpackhi_epi64(m89, m89); - - c1 = _mm_srli_epi64(r0, 26); c2 = _mm_srli_epi64(r2, 26); r0 = _mm_and_si128(r0, packedmask26.v); r2 = _mm_and_si128(r2, packedmask26.v); r1 = _mm_add_epi64(r1, c1); r3 = _mm_add_epi64(r3, c2); - c1 = _mm_srli_epi64(r1, 25); c2 = _mm_srli_epi64(r3, 25); r1 = _mm_and_si128(r1, packedmask25.v); r3 = _mm_and_si128(r3, packedmask25.v); r2 = _mm_add_epi64(r2, c1); r4 = _mm_add_epi64(r4, c2); c3 = _mm_slli_si128(c2, 8); - c1 = _mm_srli_epi64(r4, 26); r4 = _mm_and_si128(r4, packedmask26.v); r5 = _mm_add_epi64(r5, c1); - c1 = _mm_srli_epi64(r5, 25); r5 = _mm_and_si128(r5, packedmask25.v); r0 = _mm_add_epi64(r0, _mm_unpackhi_epi64(_mm_mul_epu32(c1, packednineteen.v), c3)); - c1 = _mm_srli_epi64(r0, 26); c2 = _mm_srli_epi64(r2, 26); r0 = _mm_and_si128(r0, packedmask26.v); r2 = _mm_and_si128(r2, packedmask26.v); r1 = _mm_add_epi64(r1, c1); r3 = _mm_add_epi64(r3, c2); - - r01 = _mm_unpacklo_epi64(r0, r1); - r45 = _mm_unpackhi_epi64(r0, r1); - r23 = _mm_unpacklo_epi64(r2, r3); - r67 = _mm_unpackhi_epi64(r2, r3); - r89 = _mm_unpackhi_epi64(r4, r5); - } while (--count); - - r0123 = _mm_shuffle_epi32(r23, _MM_SHUFFLE(2,0,3,3)); - r4567 = _mm_shuffle_epi32(r67, _MM_SHUFFLE(2,0,3,3)); - r0123 = _mm_or_si128(r0123, _mm_shuffle_epi32(r01, _MM_SHUFFLE(3,3,2,0))); - r4567 = _mm_or_si128(r4567, _mm_shuffle_epi32(r45, _MM_SHUFFLE(3,3,2,0))); - r89 = _mm_shuffle_epi32(r89, _MM_SHUFFLE(3,3,2,0)); - - _mm_store_si128((xmmi*)r + 0, r0123); - _mm_store_si128((xmmi*)r + 1, r4567); - _mm_store_si128((xmmi*)r + 2, r89); -} - -/* square two packed bignums */ -DONNA_INLINE static void -curve25519_square_packed64(packedelem64 *out, const packedelem64 *r) { - xmmi r0,r1,r2,r3; - xmmi r1_2,r3_2,r4_2,r5_2,r6_2,r7_2; - xmmi d5,d6,d7,d8,d9; - xmmi c1,c2; - - r0 = r[0].v; - r1 = r[1].v; - r2 = r[2].v; - r3 = r[3].v; - - out[0].v = _mm_mul_epu32(r0, r0); - r0 = _mm_slli_epi32(r0, 1); - out[1].v = _mm_mul_epu32(r0, r1); - r1_2 = _mm_slli_epi32(r1, 1); - out[2].v = _mm_add_epi64(_mm_mul_epu32(r0, r2 ), _mm_mul_epu32(r1, r1_2)); - r1 = r1_2; - out[3].v = _mm_add_epi64(_mm_mul_epu32(r0, r3 ), _mm_mul_epu32(r1, r2 )); - r3_2 = _mm_slli_epi32(r3, 1); - out[4].v = _mm_add_epi64(_mm_mul_epu32(r0, r[4].v), _mm_add_epi64(_mm_mul_epu32(r1, r3_2 ), _mm_mul_epu32(r2, r2))); - r2 = _mm_slli_epi32(r2, 1); - out[5].v = _mm_add_epi64(_mm_mul_epu32(r0, r[5].v), _mm_add_epi64(_mm_mul_epu32(r1, r[4].v), _mm_mul_epu32(r2, r3))); - r5_2 = _mm_slli_epi32(r[5].v, 1); - out[6].v = _mm_add_epi64(_mm_mul_epu32(r0, r[6].v), _mm_add_epi64(_mm_mul_epu32(r1, r5_2 ), _mm_add_epi64(_mm_mul_epu32(r2, r[4].v), _mm_mul_epu32(r3, r3_2 )))); - r3 = r3_2; - out[7].v = _mm_add_epi64(_mm_mul_epu32(r0, r[7].v), _mm_add_epi64(_mm_mul_epu32(r1, r[6].v), _mm_add_epi64(_mm_mul_epu32(r2, r[5].v), _mm_mul_epu32(r3, r[4].v)))); - r7_2 = _mm_slli_epi32(r[7].v, 1); - out[8].v = _mm_add_epi64(_mm_mul_epu32(r0, r[8].v), _mm_add_epi64(_mm_mul_epu32(r1, r7_2 ), _mm_add_epi64(_mm_mul_epu32(r2, r[6].v), _mm_add_epi64(_mm_mul_epu32(r3, r5_2 ), _mm_mul_epu32(r[4].v, r[4].v))))); - out[9].v = _mm_add_epi64(_mm_mul_epu32(r0, r[9].v), _mm_add_epi64(_mm_mul_epu32(r1, r[8].v), _mm_add_epi64(_mm_mul_epu32(r2, r[7].v), _mm_add_epi64(_mm_mul_epu32(r3, r[6].v), _mm_mul_epu32(r[4].v, r5_2 ))))); - - d5 = _mm_mul_epu32(r[5].v, packedthirtyeight.v); - d6 = _mm_mul_epu32(r[6].v, packednineteen.v); - d7 = _mm_mul_epu32(r[7].v, packedthirtyeight.v); - d8 = _mm_mul_epu32(r[8].v, packednineteen.v); - d9 = _mm_mul_epu32(r[9].v, packedthirtyeight.v); - - r4_2 = _mm_slli_epi32(r[4].v, 1); - r6_2 = _mm_slli_epi32(r[6].v, 1); - out[0].v = _mm_add_epi64(out[0].v, _mm_add_epi64(_mm_mul_epu32(d9, r1 ), _mm_add_epi64(_mm_mul_epu32(d8, r2 ), _mm_add_epi64(_mm_mul_epu32(d7, r3 ), _mm_add_epi64(_mm_mul_epu32(d6, r4_2), _mm_mul_epu32(d5, r[5].v)))))); - out[1].v = _mm_add_epi64(out[1].v, _mm_add_epi64(_mm_mul_epu32(d9, _mm_srli_epi32(r2, 1)), _mm_add_epi64(_mm_mul_epu32(d8, r3 ), _mm_add_epi64(_mm_mul_epu32(d7, r[4].v), _mm_mul_epu32(d6, r5_2 ))))); - out[2].v = _mm_add_epi64(out[2].v, _mm_add_epi64(_mm_mul_epu32(d9, r3 ), _mm_add_epi64(_mm_mul_epu32(d8, r4_2), _mm_add_epi64(_mm_mul_epu32(d7, r5_2 ), _mm_mul_epu32(d6, r[6].v))))); - out[3].v = _mm_add_epi64(out[3].v, _mm_add_epi64(_mm_mul_epu32(d9, r[4].v ), _mm_add_epi64(_mm_mul_epu32(d8, r5_2), _mm_mul_epu32(d7, r[6].v)))); - out[4].v = _mm_add_epi64(out[4].v, _mm_add_epi64(_mm_mul_epu32(d9, r5_2 ), _mm_add_epi64(_mm_mul_epu32(d8, r6_2), _mm_mul_epu32(d7, r[7].v)))); - out[5].v = _mm_add_epi64(out[5].v, _mm_add_epi64(_mm_mul_epu32(d9, r[6].v ), _mm_mul_epu32(d8, r7_2 ))); - out[6].v = _mm_add_epi64(out[6].v, _mm_add_epi64(_mm_mul_epu32(d9, r7_2 ), _mm_mul_epu32(d8, r[8].v))); - out[7].v = _mm_add_epi64(out[7].v, _mm_mul_epu32(d9, r[8].v)); - out[8].v = _mm_add_epi64(out[8].v, _mm_mul_epu32(d9, r[9].v)); - - c1 = _mm_srli_epi64(out[0].v, 26); c2 = _mm_srli_epi64(out[4].v, 26); out[0].v = _mm_and_si128(out[0].v, packedmask26.v); out[4].v = _mm_and_si128(out[4].v, packedmask26.v); out[1].v = _mm_add_epi64(out[1].v, c1); out[5].v = _mm_add_epi64(out[5].v, c2); - c1 = _mm_srli_epi64(out[1].v, 25); c2 = _mm_srli_epi64(out[5].v, 25); out[1].v = _mm_and_si128(out[1].v, packedmask25.v); out[5].v = _mm_and_si128(out[5].v, packedmask25.v); out[2].v = _mm_add_epi64(out[2].v, c1); out[6].v = _mm_add_epi64(out[6].v, c2); - c1 = _mm_srli_epi64(out[2].v, 26); c2 = _mm_srli_epi64(out[6].v, 26); out[2].v = _mm_and_si128(out[2].v, packedmask26.v); out[6].v = _mm_and_si128(out[6].v, packedmask26.v); out[3].v = _mm_add_epi64(out[3].v, c1); out[7].v = _mm_add_epi64(out[7].v, c2); - c1 = _mm_srli_epi64(out[3].v, 25); c2 = _mm_srli_epi64(out[7].v, 25); out[3].v = _mm_and_si128(out[3].v, packedmask25.v); out[7].v = _mm_and_si128(out[7].v, packedmask25.v); out[4].v = _mm_add_epi64(out[4].v, c1); out[8].v = _mm_add_epi64(out[8].v, c2); - c2 = _mm_srli_epi64(out[8].v, 26); out[8].v = _mm_and_si128(out[8].v, packedmask26.v); out[9].v = _mm_add_epi64(out[9].v, c2); - c2 = _mm_srli_epi64(out[9].v, 25); out[9].v = _mm_and_si128(out[9].v, packedmask25.v); out[0].v = _mm_add_epi64(out[0].v, _mm_mul_epu32(c2, packednineteen.v)); - c1 = _mm_srli_epi64(out[0].v, 26); c2 = _mm_srli_epi64(out[4].v, 26); out[0].v = _mm_and_si128(out[0].v, packedmask26.v); out[4].v = _mm_and_si128(out[4].v, packedmask26.v); out[1].v = _mm_add_epi64(out[1].v, c1); out[5].v = _mm_add_epi64(out[5].v, c2); -} - -/* make [nqx+nqz,nqpqx+nqpqz], [nqpqx-nqpqz,nqx-nqz] from [nqx+nqz,nqpqx+nqpqz], [nqx-nqz,nqpqx-nqpqz] */ -DONNA_INLINE static void -curve25519_make_nqpq(packedelem64 *primex, packedelem64 *primez, const packedelem32 *pqx, const packedelem32 *pqz) { - primex[0].v = _mm_shuffle_epi32(pqx[0].v, _MM_SHUFFLE(1,1,0,0)); - primex[1].v = _mm_shuffle_epi32(pqx[0].v, _MM_SHUFFLE(3,3,2,2)); - primex[2].v = _mm_shuffle_epi32(pqx[1].v, _MM_SHUFFLE(1,1,0,0)); - primex[3].v = _mm_shuffle_epi32(pqx[1].v, _MM_SHUFFLE(3,3,2,2)); - primex[4].v = _mm_shuffle_epi32(pqx[2].v, _MM_SHUFFLE(1,1,0,0)); - primex[5].v = _mm_shuffle_epi32(pqx[2].v, _MM_SHUFFLE(3,3,2,2)); - primex[6].v = _mm_shuffle_epi32(pqx[3].v, _MM_SHUFFLE(1,1,0,0)); - primex[7].v = _mm_shuffle_epi32(pqx[3].v, _MM_SHUFFLE(3,3,2,2)); - primex[8].v = _mm_shuffle_epi32(pqx[4].v, _MM_SHUFFLE(1,1,0,0)); - primex[9].v = _mm_shuffle_epi32(pqx[4].v, _MM_SHUFFLE(3,3,2,2)); - primez[0].v = _mm_shuffle_epi32(pqz[0].v, _MM_SHUFFLE(0,0,1,1)); - primez[1].v = _mm_shuffle_epi32(pqz[0].v, _MM_SHUFFLE(2,2,3,3)); - primez[2].v = _mm_shuffle_epi32(pqz[1].v, _MM_SHUFFLE(0,0,1,1)); - primez[3].v = _mm_shuffle_epi32(pqz[1].v, _MM_SHUFFLE(2,2,3,3)); - primez[4].v = _mm_shuffle_epi32(pqz[2].v, _MM_SHUFFLE(0,0,1,1)); - primez[5].v = _mm_shuffle_epi32(pqz[2].v, _MM_SHUFFLE(2,2,3,3)); - primez[6].v = _mm_shuffle_epi32(pqz[3].v, _MM_SHUFFLE(0,0,1,1)); - primez[7].v = _mm_shuffle_epi32(pqz[3].v, _MM_SHUFFLE(2,2,3,3)); - primez[8].v = _mm_shuffle_epi32(pqz[4].v, _MM_SHUFFLE(0,0,1,1)); - primez[9].v = _mm_shuffle_epi32(pqz[4].v, _MM_SHUFFLE(2,2,3,3)); -} - -/* make [nqx+nqz,nqx-nqz] from [nqx+nqz,nqpqx+nqpqz], [nqx-nqz,nqpqx-nqpqz] */ -DONNA_INLINE static void -curve25519_make_nq(packedelem64 *nq, const packedelem32 *pqx, const packedelem32 *pqz) { - nq[0].v = _mm_unpacklo_epi64(pqx[0].v, pqz[0].v); - nq[1].v = _mm_unpackhi_epi64(pqx[0].v, pqz[0].v); - nq[2].v = _mm_unpacklo_epi64(pqx[1].v, pqz[1].v); - nq[3].v = _mm_unpackhi_epi64(pqx[1].v, pqz[1].v); - nq[4].v = _mm_unpacklo_epi64(pqx[2].v, pqz[2].v); - nq[5].v = _mm_unpackhi_epi64(pqx[2].v, pqz[2].v); - nq[6].v = _mm_unpacklo_epi64(pqx[3].v, pqz[3].v); - nq[7].v = _mm_unpackhi_epi64(pqx[3].v, pqz[3].v); - nq[8].v = _mm_unpacklo_epi64(pqx[4].v, pqz[4].v); - nq[9].v = _mm_unpackhi_epi64(pqx[4].v, pqz[4].v); -} - -/* compute [nqx+nqz,nqx-nqz] from nqx, nqz */ -DONNA_INLINE static void -curve25519_compute_nq(packedelem64 *nq, const bignum25519 nqx, const bignum25519 nqz) { - xmmi x0,x1,x2; - xmmi z0,z1,z2; - xmmi a0,a1,a2; - xmmi s0,s1,s2; - xmmi r0,r1; - xmmi c1,c2; - x0 = _mm_load_si128((xmmi*)nqx + 0); - x1 = _mm_load_si128((xmmi*)nqx + 1); - x2 = _mm_load_si128((xmmi*)nqx + 2); - z0 = _mm_load_si128((xmmi*)nqz + 0); - z1 = _mm_load_si128((xmmi*)nqz + 1); - z2 = _mm_load_si128((xmmi*)nqz + 2); - a0 = _mm_add_epi32(x0, z0); - a1 = _mm_add_epi32(x1, z1); - a2 = _mm_add_epi32(x2, z2); - s0 = _mm_add_epi32(x0, packed2p0.v); - s1 = _mm_add_epi32(x1, packed2p1.v); - s2 = _mm_add_epi32(x2, packed2p2.v); - s0 = _mm_sub_epi32(s0, z0); - s1 = _mm_sub_epi32(s1, z1); - s2 = _mm_sub_epi32(s2, z2); - r0 = _mm_and_si128(_mm_shuffle_epi32(s0, _MM_SHUFFLE(2,2,0,0)), sse2_bot32bitmask.v); - r1 = _mm_and_si128(_mm_shuffle_epi32(s0, _MM_SHUFFLE(3,3,1,1)), sse2_bot32bitmask.v); - c1 = _mm_srli_epi32(r0, 26); - c2 = _mm_srli_epi32(r1, 25); - r0 = _mm_and_si128(r0, packedmask26.v); - r1 = _mm_and_si128(r1, packedmask25.v); - r0 = _mm_add_epi32(r0, _mm_slli_si128(c2, 8)); - r1 = _mm_add_epi32(r1, c1); - s0 = _mm_unpacklo_epi64(_mm_unpacklo_epi32(r0, r1), _mm_unpackhi_epi32(r0, r1)); - s1 = _mm_add_epi32(s1, _mm_srli_si128(c2, 8)); - nq[0].v = _mm_unpacklo_epi64(a0, s0); - nq[2].v = _mm_unpackhi_epi64(a0, s0); - nq[4].v = _mm_unpacklo_epi64(a1, s1); - nq[6].v = _mm_unpackhi_epi64(a1, s1); - nq[8].v = _mm_unpacklo_epi64(a2, s2); - nq[1].v = _mm_shuffle_epi32(nq[0].v, _MM_SHUFFLE(3,3,1,1)); - nq[3].v = _mm_shuffle_epi32(nq[2].v, _MM_SHUFFLE(3,3,1,1)); - nq[5].v = _mm_shuffle_epi32(nq[4].v, _MM_SHUFFLE(3,3,1,1)); - nq[7].v = _mm_shuffle_epi32(nq[6].v, _MM_SHUFFLE(3,3,1,1)); - nq[9].v = _mm_shuffle_epi32(nq[8].v, _MM_SHUFFLE(3,3,1,1)); -} - - -/* compute [x+z,x-z] from [x,z] */ -DONNA_INLINE static void -curve25519_addsub_packed64(packedelem64 *r) { - packed32bignum25519 x,z,add,sub; - - x[0].v = _mm_unpacklo_epi64(r[0].v, r[1].v); - z[0].v = _mm_unpackhi_epi64(r[0].v, r[1].v); - x[1].v = _mm_unpacklo_epi64(r[2].v, r[3].v); - z[1].v = _mm_unpackhi_epi64(r[2].v, r[3].v); - x[2].v = _mm_unpacklo_epi64(r[4].v, r[5].v); - z[2].v = _mm_unpackhi_epi64(r[4].v, r[5].v); - x[3].v = _mm_unpacklo_epi64(r[6].v, r[7].v); - z[3].v = _mm_unpackhi_epi64(r[6].v, r[7].v); - x[4].v = _mm_unpacklo_epi64(r[8].v, r[9].v); - z[4].v = _mm_unpackhi_epi64(r[8].v, r[9].v); - - curve25519_add_packed32(add, x, z); - curve25519_sub_packed32(sub, x, z); - - r[0].v = _mm_unpacklo_epi64(add[0].v, sub[0].v); - r[1].v = _mm_unpackhi_epi64(add[0].v, sub[0].v); - r[2].v = _mm_unpacklo_epi64(add[1].v, sub[1].v); - r[3].v = _mm_unpackhi_epi64(add[1].v, sub[1].v); - r[4].v = _mm_unpacklo_epi64(add[2].v, sub[2].v); - r[5].v = _mm_unpackhi_epi64(add[2].v, sub[2].v); - r[6].v = _mm_unpacklo_epi64(add[3].v, sub[3].v); - r[7].v = _mm_unpackhi_epi64(add[3].v, sub[3].v); - r[8].v = _mm_unpacklo_epi64(add[4].v, sub[4].v); - r[9].v = _mm_unpackhi_epi64(add[4].v, sub[4].v); -} - -/* compute [x,z] * [121666,121665] */ -DONNA_INLINE static void -curve25519_121665_packed64(packedelem64 *out, const packedelem64 *in) { - xmmi c1,c2; - - out[0].v = _mm_mul_epu32(in[0].v, packed121666121665.v); - out[1].v = _mm_mul_epu32(in[1].v, packed121666121665.v); - out[2].v = _mm_mul_epu32(in[2].v, packed121666121665.v); - out[3].v = _mm_mul_epu32(in[3].v, packed121666121665.v); - out[4].v = _mm_mul_epu32(in[4].v, packed121666121665.v); - out[5].v = _mm_mul_epu32(in[5].v, packed121666121665.v); - out[6].v = _mm_mul_epu32(in[6].v, packed121666121665.v); - out[7].v = _mm_mul_epu32(in[7].v, packed121666121665.v); - out[8].v = _mm_mul_epu32(in[8].v, packed121666121665.v); - out[9].v = _mm_mul_epu32(in[9].v, packed121666121665.v); - - c1 = _mm_srli_epi64(out[0].v, 26); c2 = _mm_srli_epi64(out[4].v, 26); out[0].v = _mm_and_si128(out[0].v, packedmask26.v); out[4].v = _mm_and_si128(out[4].v, packedmask26.v); out[1].v = _mm_add_epi64(out[1].v, c1); out[5].v = _mm_add_epi64(out[5].v, c2); - c1 = _mm_srli_epi64(out[1].v, 25); c2 = _mm_srli_epi64(out[5].v, 25); out[1].v = _mm_and_si128(out[1].v, packedmask25.v); out[5].v = _mm_and_si128(out[5].v, packedmask25.v); out[2].v = _mm_add_epi64(out[2].v, c1); out[6].v = _mm_add_epi64(out[6].v, c2); - c1 = _mm_srli_epi64(out[2].v, 26); c2 = _mm_srli_epi64(out[6].v, 26); out[2].v = _mm_and_si128(out[2].v, packedmask26.v); out[6].v = _mm_and_si128(out[6].v, packedmask26.v); out[3].v = _mm_add_epi64(out[3].v, c1); out[7].v = _mm_add_epi64(out[7].v, c2); - c1 = _mm_srli_epi64(out[3].v, 25); c2 = _mm_srli_epi64(out[7].v, 25); out[3].v = _mm_and_si128(out[3].v, packedmask25.v); out[7].v = _mm_and_si128(out[7].v, packedmask25.v); out[4].v = _mm_add_epi64(out[4].v, c1); out[8].v = _mm_add_epi64(out[8].v, c2); - c2 = _mm_srli_epi64(out[8].v, 26); out[8].v = _mm_and_si128(out[8].v, packedmask26.v); out[9].v = _mm_add_epi64(out[9].v, c2); - c2 = _mm_srli_epi64(out[9].v, 25); out[9].v = _mm_and_si128(out[9].v, packedmask25.v); out[0].v = _mm_add_epi64(out[0].v, _mm_mul_epu32(c2, packednineteen.v)); - c1 = _mm_srli_epi64(out[0].v, 26); c2 = _mm_srli_epi64(out[4].v, 26); out[0].v = _mm_and_si128(out[0].v, packedmask26.v); out[4].v = _mm_and_si128(out[4].v, packedmask26.v); out[1].v = _mm_add_epi64(out[1].v, c1); out[5].v = _mm_add_epi64(out[5].v, c2); -} - -/* compute [sq.x,sqscalar.x-sqscalar.z] * [sq.z,sq.x-sq.z] */ -DONNA_INLINE static void -curve25519_final_nq(packedelem64 *nq, const packedelem64 *sq, const packedelem64 *sq121665) { - packed32bignum25519 x, z, sub; - packed64bignum25519 t, nqa, nqb; - - x[0].v = _mm_or_si128(_mm_unpacklo_epi64(sq[0].v, sq[1].v), _mm_slli_si128(_mm_unpacklo_epi64(sq121665[0].v, sq121665[1].v), 4)); - z[0].v = _mm_or_si128(_mm_unpackhi_epi64(sq[0].v, sq[1].v), _mm_slli_si128(_mm_unpackhi_epi64(sq121665[0].v, sq121665[1].v), 4)); - x[1].v = _mm_or_si128(_mm_unpacklo_epi64(sq[2].v, sq[3].v), _mm_slli_si128(_mm_unpacklo_epi64(sq121665[2].v, sq121665[3].v), 4)); - z[1].v = _mm_or_si128(_mm_unpackhi_epi64(sq[2].v, sq[3].v), _mm_slli_si128(_mm_unpackhi_epi64(sq121665[2].v, sq121665[3].v), 4)); - x[2].v = _mm_or_si128(_mm_unpacklo_epi64(sq[4].v, sq[5].v), _mm_slli_si128(_mm_unpacklo_epi64(sq121665[4].v, sq121665[5].v), 4)); - z[2].v = _mm_or_si128(_mm_unpackhi_epi64(sq[4].v, sq[5].v), _mm_slli_si128(_mm_unpackhi_epi64(sq121665[4].v, sq121665[5].v), 4)); - x[3].v = _mm_or_si128(_mm_unpacklo_epi64(sq[6].v, sq[7].v), _mm_slli_si128(_mm_unpacklo_epi64(sq121665[6].v, sq121665[7].v), 4)); - z[3].v = _mm_or_si128(_mm_unpackhi_epi64(sq[6].v, sq[7].v), _mm_slli_si128(_mm_unpackhi_epi64(sq121665[6].v, sq121665[7].v), 4)); - x[4].v = _mm_or_si128(_mm_unpacklo_epi64(sq[8].v, sq[9].v), _mm_slli_si128(_mm_unpacklo_epi64(sq121665[8].v, sq121665[9].v), 4)); - z[4].v = _mm_or_si128(_mm_unpackhi_epi64(sq[8].v, sq[9].v), _mm_slli_si128(_mm_unpackhi_epi64(sq121665[8].v, sq121665[9].v), 4)); - - curve25519_sub_packed32(sub, x, z); - - t[0].v = _mm_shuffle_epi32(sub[0].v, _MM_SHUFFLE(1,1,0,0)); - t[1].v = _mm_shuffle_epi32(sub[0].v, _MM_SHUFFLE(3,3,2,2)); - t[2].v = _mm_shuffle_epi32(sub[1].v, _MM_SHUFFLE(1,1,0,0)); - t[3].v = _mm_shuffle_epi32(sub[1].v, _MM_SHUFFLE(3,3,2,2)); - t[4].v = _mm_shuffle_epi32(sub[2].v, _MM_SHUFFLE(1,1,0,0)); - t[5].v = _mm_shuffle_epi32(sub[2].v, _MM_SHUFFLE(3,3,2,2)); - t[6].v = _mm_shuffle_epi32(sub[3].v, _MM_SHUFFLE(1,1,0,0)); - t[7].v = _mm_shuffle_epi32(sub[3].v, _MM_SHUFFLE(3,3,2,2)); - t[8].v = _mm_shuffle_epi32(sub[4].v, _MM_SHUFFLE(1,1,0,0)); - t[9].v = _mm_shuffle_epi32(sub[4].v, _MM_SHUFFLE(3,3,2,2)); - - nqa[0].v = _mm_unpacklo_epi64(sq[0].v, t[0].v); - nqb[0].v = _mm_unpackhi_epi64(sq[0].v, t[0].v); - nqa[1].v = _mm_unpacklo_epi64(sq[1].v, t[1].v); - nqb[1].v = _mm_unpackhi_epi64(sq[1].v, t[1].v); - nqa[2].v = _mm_unpacklo_epi64(sq[2].v, t[2].v); - nqb[2].v = _mm_unpackhi_epi64(sq[2].v, t[2].v); - nqa[3].v = _mm_unpacklo_epi64(sq[3].v, t[3].v); - nqb[3].v = _mm_unpackhi_epi64(sq[3].v, t[3].v); - nqa[4].v = _mm_unpacklo_epi64(sq[4].v, t[4].v); - nqb[4].v = _mm_unpackhi_epi64(sq[4].v, t[4].v); - nqa[5].v = _mm_unpacklo_epi64(sq[5].v, t[5].v); - nqb[5].v = _mm_unpackhi_epi64(sq[5].v, t[5].v); - nqa[6].v = _mm_unpacklo_epi64(sq[6].v, t[6].v); - nqb[6].v = _mm_unpackhi_epi64(sq[6].v, t[6].v); - nqa[7].v = _mm_unpacklo_epi64(sq[7].v, t[7].v); - nqb[7].v = _mm_unpackhi_epi64(sq[7].v, t[7].v); - nqa[8].v = _mm_unpacklo_epi64(sq[8].v, t[8].v); - nqb[8].v = _mm_unpackhi_epi64(sq[8].v, t[8].v); - nqa[9].v = _mm_unpacklo_epi64(sq[9].v, t[9].v); - nqb[9].v = _mm_unpackhi_epi64(sq[9].v, t[9].v); - - curve25519_mul_packed64(nq, nqa, nqb); -} - diff --git a/curve25519-donna/curve25519-donna.h b/curve25519-donna/curve25519-donna.h deleted file mode 100644 index e707e2293..000000000 --- a/curve25519-donna/curve25519-donna.h +++ /dev/null @@ -1,32 +0,0 @@ -#include "curve25519.h" -#include "curve25519-donna-portable.h" - -#if defined(CURVE25519_SSE2) -#else - #if defined(HAVE_UINT128) && !defined(CURVE25519_FORCE_32BIT) - #define CURVE25519_64BIT - #else - #define CURVE25519_32BIT - #endif -#endif - -#if !defined(CURVE25519_NO_INLINE_ASM) -#endif - - -#if defined(CURVE25519_SSE2) - #include "curve25519-donna-sse2.h" -#elif defined(CURVE25519_64BIT) - #include "curve25519-donna-64bit.h" -#else - #include "curve25519-donna-32bit.h" -#endif - -#include "curve25519-donna-common.h" - -#if defined(CURVE25519_SSE2) - #include "curve25519-donna-scalarmult-sse2.h" -#else - #include "curve25519-donna-scalarmult-base.h" -#endif - diff --git a/ed25519-donna/curve25519-donna-32bit.h b/ed25519-donna/curve25519-donna-32bit.h index b8fa37d6e..16606fcfe 100644 --- a/ed25519-donna/curve25519-donna-32bit.h +++ b/ed25519-donna/curve25519-donna-32bit.h @@ -6,12 +6,10 @@ */ typedef uint32_t bignum25519[10]; -typedef uint32_t bignum25519align16[12]; static const uint32_t reduce_mask_25 = (1 << 25) - 1; static const uint32_t reduce_mask_26 = (1 << 26) - 1; - /* out = in */ DONNA_INLINE static void curve25519_copy(bignum25519 out, const bignum25519 in) { @@ -98,6 +96,24 @@ curve25519_sub(bignum25519 out, const bignum25519 a, const bignum25519 b) { out[9] = twoP13579 + a[9] - b[9] ; } +/* out = in * scalar */ +DONNA_INLINE static void +curve25519_scalar_product(bignum25519 out, const bignum25519 in, const uint32_t scalar) { + uint64_t a; + uint32_t c; + a = mul32x32_64(in[0], scalar); out[0] = (uint32_t)a & reduce_mask_26; c = (uint32_t)(a >> 26); + a = mul32x32_64(in[1], scalar) + c; out[1] = (uint32_t)a & reduce_mask_25; c = (uint32_t)(a >> 25); + a = mul32x32_64(in[2], scalar) + c; out[2] = (uint32_t)a & reduce_mask_26; c = (uint32_t)(a >> 26); + a = mul32x32_64(in[3], scalar) + c; out[3] = (uint32_t)a & reduce_mask_25; c = (uint32_t)(a >> 25); + a = mul32x32_64(in[4], scalar) + c; out[4] = (uint32_t)a & reduce_mask_26; c = (uint32_t)(a >> 26); + a = mul32x32_64(in[5], scalar) + c; out[5] = (uint32_t)a & reduce_mask_25; c = (uint32_t)(a >> 25); + a = mul32x32_64(in[6], scalar) + c; out[6] = (uint32_t)a & reduce_mask_26; c = (uint32_t)(a >> 26); + a = mul32x32_64(in[7], scalar) + c; out[7] = (uint32_t)a & reduce_mask_25; c = (uint32_t)(a >> 25); + a = mul32x32_64(in[8], scalar) + c; out[8] = (uint32_t)a & reduce_mask_26; c = (uint32_t)(a >> 26); + a = mul32x32_64(in[9], scalar) + c; out[9] = (uint32_t)a & reduce_mask_25; c = (uint32_t)(a >> 25); + out[0] += c * 19; +} + /* out = a - b, where a is the result of a basic op (add,sub) */ DONNA_INLINE static void curve25519_sub_after_basic(bignum25519 out, const bignum25519 a, const bignum25519 b) { @@ -150,7 +166,7 @@ curve25519_neg(bignum25519 out, const bignum25519 a) { /* out = a * b */ #define curve25519_mul_noinline curve25519_mul -static void +DONNA_INLINE static void curve25519_mul(bignum25519 out, const bignum25519 a, const bignum25519 b) { uint32_t r0,r1,r2,r3,r4,r5,r6,r7,r8,r9; uint32_t s0,s1,s2,s3,s4,s5,s6,s7,s8,s9; @@ -247,8 +263,8 @@ curve25519_mul(bignum25519 out, const bignum25519 a, const bignum25519 b) { out[9] = r9; } -/* out = in*in */ -static void +/* out = in * in */ +DONNA_INLINE static void curve25519_square(bignum25519 out, const bignum25519 in) { uint32_t r0,r1,r2,r3,r4,r5,r6,r7,r8,r9; uint32_t d6,d7,d8,d9; @@ -321,7 +337,6 @@ curve25519_square(bignum25519 out, const bignum25519 in) { out[9] = r9; } - /* out = in ^ (2 * count) */ static void curve25519_square_times(bignum25519 out, const bignum25519 in, int count) { @@ -430,16 +445,16 @@ curve25519_expand(bignum25519 out, const unsigned char in[32]) { #undef F } - out[0] = ( x0 ) & 0x3ffffff; - out[1] = ((((uint64_t)x1 << 32) | x0) >> 26) & 0x1ffffff; - out[2] = ((((uint64_t)x2 << 32) | x1) >> 19) & 0x3ffffff; - out[3] = ((((uint64_t)x3 << 32) | x2) >> 13) & 0x1ffffff; - out[4] = (( x3) >> 6) & 0x3ffffff; - out[5] = ( x4 ) & 0x1ffffff; - out[6] = ((((uint64_t)x5 << 32) | x4) >> 25) & 0x3ffffff; - out[7] = ((((uint64_t)x6 << 32) | x5) >> 19) & 0x1ffffff; - out[8] = ((((uint64_t)x7 << 32) | x6) >> 12) & 0x3ffffff; - out[9] = (( x7) >> 6) & 0x1ffffff; + out[0] = ( x0 ) & reduce_mask_26; + out[1] = ((((uint64_t)x1 << 32) | x0) >> 26) & reduce_mask_25; + out[2] = ((((uint64_t)x2 << 32) | x1) >> 19) & reduce_mask_26; + out[3] = ((((uint64_t)x3 << 32) | x2) >> 13) & reduce_mask_25; + out[4] = (( x3) >> 6) & reduce_mask_26; + out[5] = ( x4 ) & reduce_mask_25; + out[6] = ((((uint64_t)x5 << 32) | x4) >> 25) & reduce_mask_26; + out[7] = ((((uint64_t)x6 << 32) | x5) >> 19) & reduce_mask_25; + out[8] = ((((uint64_t)x7 << 32) | x6) >> 12) & reduce_mask_26; + out[9] = (( x7) >> 6) & reduce_mask_25; /* ignore the top bit */ } /* Take a fully reduced polynomial form number and contract it into a @@ -526,7 +541,6 @@ curve25519_contract(unsigned char out[32], const bignum25519 in) { #undef F } - /* out = (flag) ? in : out */ DONNA_INLINE static void curve25519_move_conditional_bytes(uint8_t out[96], const uint8_t in[96], uint32_t flag) { diff --git a/curve25519-donna/curve25519-donna-scalarmult-base.h b/ed25519-donna/curve25519-donna-scalarmult-base.h similarity index 100% rename from curve25519-donna/curve25519-donna-scalarmult-base.h rename to ed25519-donna/curve25519-donna-scalarmult-base.h diff --git a/ed25519-donna/curve25519-donna.h b/ed25519-donna/curve25519-donna.h new file mode 100644 index 000000000..feba4c6c8 --- /dev/null +++ b/ed25519-donna/curve25519-donna.h @@ -0,0 +1,9 @@ +#include "curve25519.h" + +#include "ed25519-donna-portable.h" + +#include "curve25519-donna-32bit.h" + +#include "curve25519-donna-helpers.h" + +#include "curve25519-donna-scalarmult-base.h" diff --git a/curve25519-donna/curve25519.c b/ed25519-donna/curve25519.c similarity index 100% rename from curve25519-donna/curve25519.c rename to ed25519-donna/curve25519.c diff --git a/curve25519-donna/curve25519.h b/ed25519-donna/curve25519.h similarity index 100% rename from curve25519-donna/curve25519.h rename to ed25519-donna/curve25519.h From 8cc6539d2d0683d7fa95a04fd718c3727e4acb5a Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 28 Mar 2017 19:18:57 +0200 Subject: [PATCH 372/627] remove unused functions --- Makefile | 1 - ed25519-donna/ed25519-donna-impl-base.h | 16 +++-- ed25519-donna/modm-donna-32bit.h | 89 ------------------------- 3 files changed, 10 insertions(+), 96 deletions(-) diff --git a/Makefile b/Makefile index bcd923695..6a1f11083 100644 --- a/Makefile +++ b/Makefile @@ -21,7 +21,6 @@ CFLAGS += $(OPTFLAGS) \ -Winit-self \ -Wuninitialized \ -Wformat-security \ - -Wno-unused-function \ -Werror # disable sequence point warning because of AES code diff --git a/ed25519-donna/ed25519-donna-impl-base.h b/ed25519-donna/ed25519-donna-impl-base.h index 8cc85f216..49936aa00 100644 --- a/ed25519-donna/ed25519-donna-impl-base.h +++ b/ed25519-donna/ed25519-donna-impl-base.h @@ -29,6 +29,7 @@ ge25519_full_to_pniels(ge25519_pniels *p, const ge25519 *r) { adding & doubling */ +#if 0 // UNUSED static void ge25519_add_p1p1(ge25519_p1p1 *r, const ge25519 *p, const ge25519 *q) { bignum25519 a,b,c,d,t,u; @@ -48,7 +49,7 @@ ge25519_add_p1p1(ge25519_p1p1 *r, const ge25519 *p, const ge25519 *q) { curve25519_add_after_basic(r->z, d, c); curve25519_sub_after_basic(r->t, d, c); } - +#endif static void ge25519_double_p1p1(ge25519_p1p1 *r, const ge25519 *p) { @@ -119,12 +120,14 @@ ge25519_double(ge25519 *r, const ge25519 *p) { ge25519_p1p1_to_full(r, &t); } +#if 0 // UNUSED static void ge25519_add(ge25519 *r, const ge25519 *p, const ge25519 *q) { ge25519_p1p1 t; ge25519_add_p1p1(&t, p, q); ge25519_p1p1_to_full(r, &t); } +#endif static void ge25519_nielsadd2(ge25519 *r, const ge25519_niels *q) { @@ -294,6 +297,7 @@ STATIC void ge25519_double_scalarmult_vartime(ge25519 *r, const ge25519 *p1, con } /* computes [s1]p1 */ +#if 0 // UNUSED STATIC void ge25519_scalarmult_vartime(ge25519 *r, const ge25519 *p1, const bignum256modm s1) { signed char slide1[256]; ge25519_pniels pre1[S1_TABLE_SIZE]; @@ -326,6 +330,7 @@ STATIC void ge25519_scalarmult_vartime(ge25519 *r, const ge25519 *p1, const bign ge25519_p1p1_to_partial(r, &t); } } +#endif /* * The following conditional move stuff uses conditional moves. @@ -376,6 +381,7 @@ DONNA_INLINE static void ge25519_cmove_stride4b(long * r, long * p, long * pos, } #define HAS_CMOVE_STRIDE4B +#if 0 // UNUSED STATIC void ge25519_move_conditional_pniels_array(ge25519_pniels * r, const ge25519_pniels * p, int pos, int n) { #ifdef HAS_CMOVE_STRIDE4B size_t i; @@ -393,6 +399,7 @@ STATIC void ge25519_move_conditional_pniels_array(ge25519_pniels * r, const ge25 } #endif } +#endif STATIC void ge25519_move_conditional_niels_array(ge25519_niels * r, const uint8_t p[8][96], int pos, int n) { size_t i; @@ -406,6 +413,7 @@ STATIC void ge25519_move_conditional_niels_array(ge25519_niels * r, const uint8_ } /* computes [s1]p1, constant time */ +#if 0 // UNUSED STATIC void ge25519_scalarmult(ge25519 *r, const ge25519 *p1, const bignum256modm s1) { signed char slide1[64]; ge25519_pniels pre1[9]; @@ -439,6 +447,7 @@ STATIC void ge25519_scalarmult(ge25519 *r, const ge25519 *p1, const bignum256mod ge25519_p1p1_to_partial(r, &t); } } +#endif #if !defined(HAVE_GE25519_SCALARMULT_BASE_CHOOSE_NIELS) @@ -506,8 +515,3 @@ ge25519_scalarmult_base_niels(ge25519 *r, const uint8_t basepoint_table[256][96] ge25519_nielsadd2(r, &t); } } - -STATIC void ge25519_scalarmult_base(ge25519 *r, const bignum256modm s) { - ge25519_scalarmult_base_niels(r, ge25519_niels_base_multiples, s); -} - diff --git a/ed25519-donna/modm-donna-32bit.h b/ed25519-donna/modm-donna-32bit.h index 5b17b6a74..1976bae37 100644 --- a/ed25519-donna/modm-donna-32bit.h +++ b/ed25519-donna/modm-donna-32bit.h @@ -365,92 +365,3 @@ STATIC void contract256_slidingwindow_modm(signed char r[256], const bignum256mo } } } - - -/* - helpers for batch verifcation, are allowed to be vartime -*/ - -/* out = a - b, a must be larger than b */ -STATIC void sub256_modm_batch(bignum256modm out, const bignum256modm a, const bignum256modm b, size_t limbsize) { - size_t i = 0; - bignum256modm_element_t carry = 0; - switch (limbsize) { - case 8: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 31); out[i] &= 0x3fffffff; i++; - case 7: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 31); out[i] &= 0x3fffffff; i++; - case 6: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 31); out[i] &= 0x3fffffff; i++; - case 5: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 31); out[i] &= 0x3fffffff; i++; - case 4: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 31); out[i] &= 0x3fffffff; i++; - case 3: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 31); out[i] &= 0x3fffffff; i++; - case 2: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 31); out[i] &= 0x3fffffff; i++; - case 1: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 31); out[i] &= 0x3fffffff; i++; - case 0: - default: out[i] = (a[i] - b[i]) - carry; - } -} - - -/* is a < b */ -STATIC int lt256_modm_batch(const bignum256modm a, const bignum256modm b, size_t limbsize) { - switch (limbsize) { - case 8: if (a[8] > b[8]) return 0; if (a[8] < b[8]) return 1; - case 7: if (a[7] > b[7]) return 0; if (a[7] < b[7]) return 1; - case 6: if (a[6] > b[6]) return 0; if (a[6] < b[6]) return 1; - case 5: if (a[5] > b[5]) return 0; if (a[5] < b[5]) return 1; - case 4: if (a[4] > b[4]) return 0; if (a[4] < b[4]) return 1; - case 3: if (a[3] > b[3]) return 0; if (a[3] < b[3]) return 1; - case 2: if (a[2] > b[2]) return 0; if (a[2] < b[2]) return 1; - case 1: if (a[1] > b[1]) return 0; if (a[1] < b[1]) return 1; - case 0: if (a[0] > b[0]) return 0; if (a[0] < b[0]) return 1; - } - return 0; -} - -/* is a <= b */ -STATIC int lte256_modm_batch(const bignum256modm a, const bignum256modm b, size_t limbsize) { - switch (limbsize) { - case 8: if (a[8] > b[8]) return 0; if (a[8] < b[8]) return 1; - case 7: if (a[7] > b[7]) return 0; if (a[7] < b[7]) return 1; - case 6: if (a[6] > b[6]) return 0; if (a[6] < b[6]) return 1; - case 5: if (a[5] > b[5]) return 0; if (a[5] < b[5]) return 1; - case 4: if (a[4] > b[4]) return 0; if (a[4] < b[4]) return 1; - case 3: if (a[3] > b[3]) return 0; if (a[3] < b[3]) return 1; - case 2: if (a[2] > b[2]) return 0; if (a[2] < b[2]) return 1; - case 1: if (a[1] > b[1]) return 0; if (a[1] < b[1]) return 1; - case 0: if (a[0] > b[0]) return 0; if (a[0] < b[0]) return 1; - } - return 1; -} - - -/* is a == 0 */ -STATIC int iszero256_modm_batch(const bignum256modm a) { - size_t i; - for (i = 0; i < 9; i++) - if (a[i]) - return 0; - return 1; -} - -/* is a == 1 */ -STATIC int isone256_modm_batch(const bignum256modm a) { - size_t i; - if (a[0] != 1) - return 0; - for (i = 1; i < 9; i++) - if (a[i]) - return 0; - return 1; -} - -/* can a fit in to (at most) 128 bits */ -STATIC int isatmost128bits256_modm_batch(const bignum256modm a) { - uint32_t mask = - ((a[8] ) | /* 16 */ - (a[7] ) | /* 46 */ - (a[6] ) | /* 76 */ - (a[5] ) | /* 106 */ - (a[4] & 0x3fffff00)); /* 128 */ - - return (mask == 0); -} From 4669c3db4c8af7997c9406dbc339692450928771 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 28 Mar 2017 19:48:36 +0200 Subject: [PATCH 373/627] more merging of curve25519 into ed25519 --- Makefile | 2 +- bip32.c | 1 - ed25519-donna/curve25519-donna.h | 9 ------ ed25519-donna/curve25519.c | 27 ------------------ ed25519-donna/curve25519.h | 10 ------- ed25519-donna/ed25519-donna-impl-base.h | 14 +++++----- ed25519-donna/ed25519.c | 37 +++++++++++++++---------- ed25519-donna/ed25519.h | 7 +++-- ed25519-donna/modm-donna-32bit.h | 14 +++++----- test_speed.c | 1 - 10 files changed, 43 insertions(+), 79 deletions(-) delete mode 100644 ed25519-donna/curve25519-donna.h delete mode 100644 ed25519-donna/curve25519.c delete mode 100644 ed25519-donna/curve25519.h diff --git a/Makefile b/Makefile index 6a1f11083..5e0609f73 100644 --- a/Makefile +++ b/Makefile @@ -41,7 +41,7 @@ SRCS += ripemd160.c SRCS += sha2.c SRCS += sha3.c SRCS += aescrypt.c aeskey.c aestab.c aes_modes.c -SRCS += ed25519-donna/ed25519.c ed25519-donna/curve25519.c +SRCS += ed25519-donna/ed25519.c SRCS += blake2b.c blake2s.c OBJS = $(SRCS:.c=.o) diff --git a/bip32.c b/bip32.c index 5135efdc7..11f3df75d 100644 --- a/bip32.c +++ b/bip32.c @@ -37,7 +37,6 @@ #include "secp256k1.h" #include "nist256p1.h" #include "ed25519.h" -#include "curve25519.h" #if USE_ETHEREUM #include "sha3.h" #endif diff --git a/ed25519-donna/curve25519-donna.h b/ed25519-donna/curve25519-donna.h deleted file mode 100644 index feba4c6c8..000000000 --- a/ed25519-donna/curve25519-donna.h +++ /dev/null @@ -1,9 +0,0 @@ -#include "curve25519.h" - -#include "ed25519-donna-portable.h" - -#include "curve25519-donna-32bit.h" - -#include "curve25519-donna-helpers.h" - -#include "curve25519-donna-scalarmult-base.h" diff --git a/ed25519-donna/curve25519.c b/ed25519-donna/curve25519.c deleted file mode 100644 index bfd2f58ec..000000000 --- a/ed25519-donna/curve25519.c +++ /dev/null @@ -1,27 +0,0 @@ -#include "curve25519-donna.h" - -#if !defined(CURVE25519_SUFFIX) -#define CURVE25519_SUFFIX -#endif - -#define CURVE25519_FN3(fn,suffix) fn##suffix -#define CURVE25519_FN2(fn,suffix) CURVE25519_FN3(fn,suffix) -#define CURVE25519_FN(fn) CURVE25519_FN2(fn,CURVE25519_SUFFIX) - -void -CURVE25519_FN(curve25519_donna) (curve25519_key mypublic, const curve25519_key secret, const curve25519_key basepoint) { - curve25519_key e; - size_t i; - - for (i = 0;i < 32;++i) e[i] = secret[i]; - e[0] &= 0xf8; - e[31] &= 0x7f; - e[31] |= 0x40; - curve25519_scalarmult_donna(mypublic, e, basepoint); -} - -void -CURVE25519_FN(curve25519_donna_basepoint) (curve25519_key mypublic, const curve25519_key secret) { - static const curve25519_key basepoint = {9}; - CURVE25519_FN(curve25519_donna)(mypublic, secret, basepoint); -} diff --git a/ed25519-donna/curve25519.h b/ed25519-donna/curve25519.h deleted file mode 100644 index 51edd1e94..000000000 --- a/ed25519-donna/curve25519.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef CURVE25519_H -#define CURVE25519_H - -typedef unsigned char curve25519_key[32]; - -void curve25519_donna(curve25519_key mypublic, const curve25519_key secret, const curve25519_key basepoint); -void curve25519_donna_basepoint(curve25519_key mypublic, const curve25519_key secret); - -#endif /* CURVE25519_H */ - diff --git a/ed25519-donna/ed25519-donna-impl-base.h b/ed25519-donna/ed25519-donna-impl-base.h index 49936aa00..e2e2db895 100644 --- a/ed25519-donna/ed25519-donna-impl-base.h +++ b/ed25519-donna/ed25519-donna-impl-base.h @@ -179,7 +179,7 @@ ge25519_pnielsadd(ge25519_pniels *r, const ge25519 *p, const ge25519_pniels *q) pack & unpack */ -STATIC void +static void ge25519_pack(unsigned char r[32], const ge25519 *p) { bignum25519 tx, ty, zi; unsigned char parity[32]; @@ -191,7 +191,7 @@ ge25519_pack(unsigned char r[32], const ge25519 *p) { r[31] ^= ((parity[0] & 1) << 7); } -STATIC int ge25519_unpack_negative_vartime(ge25519 *r, const unsigned char p[32]) { +static int ge25519_unpack_negative_vartime(ge25519 *r, const unsigned char p[32]) { static const unsigned char zero[32] = {0}; static const bignum25519 one = {1}; unsigned char parity = p[31] >> 7; @@ -258,7 +258,7 @@ DONNA_INLINE static void ge25519_set_neutral(ge25519 *r) #define S2_TABLE_SIZE (1<<(S2_SWINDOWSIZE-2)) /* computes [s1]p1 + [s2]base */ -STATIC void ge25519_double_scalarmult_vartime(ge25519 *r, const ge25519 *p1, const bignum256modm s1, const bignum256modm s2) { +static void ge25519_double_scalarmult_vartime(ge25519 *r, const ge25519 *p1, const bignum256modm s1, const bignum256modm s2) { signed char slide1[256], slide2[256]; ge25519_pniels pre1[S1_TABLE_SIZE]; ge25519 d1; @@ -298,7 +298,7 @@ STATIC void ge25519_double_scalarmult_vartime(ge25519 *r, const ge25519 *p1, con /* computes [s1]p1 */ #if 0 // UNUSED -STATIC void ge25519_scalarmult_vartime(ge25519 *r, const ge25519 *p1, const bignum256modm s1) { +static void ge25519_scalarmult_vartime(ge25519 *r, const ge25519 *p1, const bignum256modm s1) { signed char slide1[256]; ge25519_pniels pre1[S1_TABLE_SIZE]; ge25519 d1; @@ -382,7 +382,7 @@ DONNA_INLINE static void ge25519_cmove_stride4b(long * r, long * p, long * pos, #define HAS_CMOVE_STRIDE4B #if 0 // UNUSED -STATIC void ge25519_move_conditional_pniels_array(ge25519_pniels * r, const ge25519_pniels * p, int pos, int n) { +static void ge25519_move_conditional_pniels_array(ge25519_pniels * r, const ge25519_pniels * p, int pos, int n) { #ifdef HAS_CMOVE_STRIDE4B size_t i; for(i=0; i - #if defined(__cplusplus) extern "C" { #endif @@ -11,6 +9,8 @@ typedef unsigned char ed25519_signature[64]; typedef unsigned char ed25519_public_key[32]; typedef unsigned char ed25519_secret_key[32]; +typedef unsigned char curve25519_key[32]; + typedef unsigned char curved25519_key[32]; void ed25519_publickey(const ed25519_secret_key sk, ed25519_public_key pk); @@ -21,6 +21,9 @@ int ed25519_sign_open_batch(const unsigned char **m, size_t *mlen, const unsigne void curved25519_scalarmult_basepoint(curved25519_key pk, const curved25519_key e); +void curve25519_donna(curve25519_key mypublic, const curve25519_key secret, const curve25519_key basepoint); +void curve25519_donna_basepoint(curve25519_key mypublic, const curve25519_key secret); + #if defined(__cplusplus) } #endif diff --git a/ed25519-donna/modm-donna-32bit.h b/ed25519-donna/modm-donna-32bit.h index 1976bae37..16fba16d4 100644 --- a/ed25519-donna/modm-donna-32bit.h +++ b/ed25519-donna/modm-donna-32bit.h @@ -140,7 +140,7 @@ barrett_reduce256_modm(bignum256modm r, const bignum256modm q1, const bignum256m } /* addition modulo m */ -STATIC void add256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y) { +static void add256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y) { bignum256modm_element_t c; c = x[0] + y[0]; r[0] = c & 0x3fffffff; c >>= 30; @@ -157,7 +157,7 @@ STATIC void add256_modm(bignum256modm r, const bignum256modm x, const bignum256m } /* multiplication modulo m */ -STATIC void mul256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y) { +static void mul256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y) { bignum256modm r1, q1; uint64_t c; bignum256modm_element_t f; @@ -202,7 +202,7 @@ STATIC void mul256_modm(bignum256modm r, const bignum256modm x, const bignum256m barrett_reduce256_modm(r, q1, r1); } -STATIC void expand256_modm(bignum256modm out, const unsigned char *in, size_t len) { +static void expand256_modm(bignum256modm out, const unsigned char *in, size_t len) { unsigned char work[64] = {0}; bignum256modm_element_t x[16]; bignum256modm q1; @@ -254,7 +254,7 @@ STATIC void expand256_modm(bignum256modm out, const unsigned char *in, size_t le barrett_reduce256_modm(out, q1, out); } -STATIC void expand_raw256_modm(bignum256modm out, const unsigned char in[32]) { +static void expand_raw256_modm(bignum256modm out, const unsigned char in[32]) { bignum256modm_element_t x[8]; x[0] = U8TO32_LE(in + 0); @@ -277,7 +277,7 @@ STATIC void expand_raw256_modm(bignum256modm out, const unsigned char in[32]) { out[8] = ((x[ 7] >> 16) ) & 0x0000ffff; } -STATIC void contract256_modm(unsigned char out[32], const bignum256modm in) { +static void contract256_modm(unsigned char out[32], const bignum256modm in) { U32TO8_LE(out + 0, (in[0] ) | (in[1] << 30)); U32TO8_LE(out + 4, (in[1] >> 2) | (in[2] << 28)); U32TO8_LE(out + 8, (in[2] >> 4) | (in[3] << 26)); @@ -290,7 +290,7 @@ STATIC void contract256_modm(unsigned char out[32], const bignum256modm in) { -STATIC void contract256_window4_modm(signed char r[64], const bignum256modm in) { +static void contract256_window4_modm(signed char r[64], const bignum256modm in) { char carry; signed char *quads = r; bignum256modm_element_t i, j, v; @@ -325,7 +325,7 @@ STATIC void contract256_window4_modm(signed char r[64], const bignum256modm in) r[63] += carry; } -STATIC void contract256_slidingwindow_modm(signed char r[256], const bignum256modm s, int windowsize) { +static void contract256_slidingwindow_modm(signed char r[256], const bignum256modm s, int windowsize) { int i,j,k,b; int m = (1 << (windowsize - 1)) - 1, soplen = 256; signed char *bits = r; diff --git a/test_speed.c b/test_speed.c index d9010bb90..c6fa53174 100644 --- a/test_speed.c +++ b/test_speed.c @@ -8,7 +8,6 @@ #include "secp256k1.h" #include "nist256p1.h" #include "ed25519.h" -#include "curve25519.h" static uint8_t msg[32]; From b1bee409e72bf92283803ff53aef754040a54a2e Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 28 Mar 2017 20:26:43 +0200 Subject: [PATCH 374/627] ed22519: remove more unused stuff, don't inline --- ed25519-donna/curve25519-donna-32bit.h | 33 ----- ed25519-donna/ed25519-donna-impl-base.h | 154 ------------------------ ed25519-donna/ed25519-donna-portable.h | 3 +- 3 files changed, 1 insertion(+), 189 deletions(-) diff --git a/ed25519-donna/curve25519-donna-32bit.h b/ed25519-donna/curve25519-donna-32bit.h index 16606fcfe..6a4e9c3ab 100644 --- a/ed25519-donna/curve25519-donna-32bit.h +++ b/ed25519-donna/curve25519-donna-32bit.h @@ -541,39 +541,6 @@ curve25519_contract(unsigned char out[32], const bignum25519 in) { #undef F } -/* out = (flag) ? in : out */ -DONNA_INLINE static void -curve25519_move_conditional_bytes(uint8_t out[96], const uint8_t in[96], uint32_t flag) { - const uint32_t nb = flag - 1, b = ~nb; - const uint32_t *inl = (const uint32_t *)in; - uint32_t *outl = (uint32_t *)out; - outl[0] = (outl[0] & nb) | (inl[0] & b); - outl[1] = (outl[1] & nb) | (inl[1] & b); - outl[2] = (outl[2] & nb) | (inl[2] & b); - outl[3] = (outl[3] & nb) | (inl[3] & b); - outl[4] = (outl[4] & nb) | (inl[4] & b); - outl[5] = (outl[5] & nb) | (inl[5] & b); - outl[6] = (outl[6] & nb) | (inl[6] & b); - outl[7] = (outl[7] & nb) | (inl[7] & b); - outl[8] = (outl[8] & nb) | (inl[8] & b); - outl[9] = (outl[9] & nb) | (inl[9] & b); - outl[10] = (outl[10] & nb) | (inl[10] & b); - outl[11] = (outl[11] & nb) | (inl[11] & b); - outl[12] = (outl[12] & nb) | (inl[12] & b); - outl[13] = (outl[13] & nb) | (inl[13] & b); - outl[14] = (outl[14] & nb) | (inl[14] & b); - outl[15] = (outl[15] & nb) | (inl[15] & b); - outl[16] = (outl[16] & nb) | (inl[16] & b); - outl[17] = (outl[17] & nb) | (inl[17] & b); - outl[18] = (outl[18] & nb) | (inl[18] & b); - outl[19] = (outl[19] & nb) | (inl[19] & b); - outl[20] = (outl[20] & nb) | (inl[20] & b); - outl[21] = (outl[21] & nb) | (inl[21] & b); - outl[22] = (outl[22] & nb) | (inl[22] & b); - outl[23] = (outl[23] & nb) | (inl[23] & b); - -} - /* if (iswap) swap(a, b) */ DONNA_INLINE static void curve25519_swap_conditional(bignum25519 a, bignum25519 b, uint32_t iswap) { diff --git a/ed25519-donna/ed25519-donna-impl-base.h b/ed25519-donna/ed25519-donna-impl-base.h index e2e2db895..d5472795c 100644 --- a/ed25519-donna/ed25519-donna-impl-base.h +++ b/ed25519-donna/ed25519-donna-impl-base.h @@ -29,28 +29,6 @@ ge25519_full_to_pniels(ge25519_pniels *p, const ge25519 *r) { adding & doubling */ -#if 0 // UNUSED -static void -ge25519_add_p1p1(ge25519_p1p1 *r, const ge25519 *p, const ge25519 *q) { - bignum25519 a,b,c,d,t,u; - - curve25519_sub(a, p->y, p->x); - curve25519_add(b, p->y, p->x); - curve25519_sub(t, q->y, q->x); - curve25519_add(u, q->y, q->x); - curve25519_mul(a, a, t); - curve25519_mul(b, b, u); - curve25519_mul(c, p->t, q->t); - curve25519_mul(c, c, ge25519_ec2d); - curve25519_mul(d, p->z, q->z); - curve25519_add(d, d, d); - curve25519_sub(r->x, b, a); - curve25519_add(r->y, b, a); - curve25519_add_after_basic(r->z, d, c); - curve25519_sub_after_basic(r->t, d, c); -} -#endif - static void ge25519_double_p1p1(ge25519_p1p1 *r, const ge25519 *p) { bignum25519 a,b,c; @@ -120,15 +98,6 @@ ge25519_double(ge25519 *r, const ge25519 *p) { ge25519_p1p1_to_full(r, &t); } -#if 0 // UNUSED -static void -ge25519_add(ge25519 *r, const ge25519 *p, const ge25519 *q) { - ge25519_p1p1 t; - ge25519_add_p1p1(&t, p, q); - ge25519_p1p1_to_full(r, &t); -} -#endif - static void ge25519_nielsadd2(ge25519 *r, const ge25519_niels *q) { bignum25519 a,b,c,e,f,g,h; @@ -296,42 +265,6 @@ static void ge25519_double_scalarmult_vartime(ge25519 *r, const ge25519 *p1, con } } -/* computes [s1]p1 */ -#if 0 // UNUSED -static void ge25519_scalarmult_vartime(ge25519 *r, const ge25519 *p1, const bignum256modm s1) { - signed char slide1[256]; - ge25519_pniels pre1[S1_TABLE_SIZE]; - ge25519 d1; - ge25519_p1p1 t; - int32_t i; - - contract256_slidingwindow_modm(slide1, s1, S1_SWINDOWSIZE); - - ge25519_double(&d1, p1); - ge25519_full_to_pniels(pre1, p1); - for (i = 0; i < S1_TABLE_SIZE - 1; i++) - ge25519_pnielsadd(&pre1[i+1], &d1, &pre1[i]); - - /* set neutral */ - ge25519_set_neutral(r); - - i = 255; - while ((i >= 0) && !slide1[i]) - i--; - - for (; i >= 0; i--) { - ge25519_double_p1p1(&t, r); - - if (slide1[i]) { - ge25519_p1p1_to_full(r, &t); - ge25519_pnielsadd_p1p1(&t, r, &pre1[abs(slide1[i]) / 2], (unsigned char)slide1[i] >> 7); - } - - ge25519_p1p1_to_partial(r, &t); - } -} -#endif - /* * The following conditional move stuff uses conditional moves. * I will check on which compilers this works, and provide suitable @@ -361,46 +294,6 @@ DONNA_INLINE static void ge25519_cmove_stride4(long * r, long * p, long * pos, l } #define HAS_CMOVE_STRIDE4 -DONNA_INLINE static void ge25519_cmove_stride4b(long * r, long * p, long * pos, long * n, int stride) { - long x0=p[0], x1=p[1], x2=p[2], x3=p[3], y0, y1, y2, y3; - for(p+=stride; p= 0; i--) { - int k=abs(slide1[i]); - ge25519_double_partial(r, r); - ge25519_double_partial(r, r); - ge25519_double_partial(r, r); - ge25519_double_p1p1(&t, r); - ge25519_move_conditional_pniels_array(&pre, pre1, k, 9); - ge25519_p1p1_to_full(r, &t); - ge25519_pnielsadd_p1p1(&t, r, &pre, (unsigned char)slide1[i] >> 7); - ge25519_p1p1_to_partial(r, &t); - } -} -#endif - -#if !defined(HAVE_GE25519_SCALARMULT_BASE_CHOOSE_NIELS) - -DONNA_INLINE static uint32_t -ge25519_windowb_equal(uint32_t b, uint32_t c) { - return ((b ^ c) - 1) >> 31; -} - static void ge25519_scalarmult_base_choose_niels(ge25519_niels *t, const uint8_t table[256][96], uint32_t pos, signed char b) { bignum25519 neg; @@ -481,9 +330,6 @@ ge25519_scalarmult_base_choose_niels(ge25519_niels *t, const uint8_t table[256][ curve25519_swap_conditional(t->t2d, neg, sign); } -#endif /* HAVE_GE25519_SCALARMULT_BASE_CHOOSE_NIELS */ - - /* computes [s]basepoint */ static void ge25519_scalarmult_base_niels(ge25519 *r, const uint8_t basepoint_table[256][96], const bignum256modm s) { diff --git a/ed25519-donna/ed25519-donna-portable.h b/ed25519-donna/ed25519-donna-portable.h index bb8602869..2fa0ac56e 100644 --- a/ed25519-donna/ed25519-donna-portable.h +++ b/ed25519-donna/ed25519-donna-portable.h @@ -4,8 +4,7 @@ #include #include -#define DONNA_INLINE inline __attribute__((always_inline)) -#define DONNA_NOINLINE __attribute__((noinline)) +#define DONNA_INLINE #undef ALIGN #define ALIGN(x) __attribute__((aligned(x))) #define ROTL32(a,b) (((a) << (b)) | ((a) >> (32 - b))) From 1d232a6f86c97e603205dd539c933ee94aa8e857 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 28 Mar 2017 22:52:02 +0200 Subject: [PATCH 375/627] whitespace cleanup --- ed25519-donna/curve25519-donna-32bit.h | 2 +- ed25519-donna/curve25519-donna-scalarmult-base.h | 3 +-- ed25519-donna/ed25519-donna-32bit-tables.h | 10 +++++----- ed25519-donna/ed25519-donna-impl-base.h | 7 +++---- ed25519-donna/ed25519-donna.h | 2 -- ed25519-donna/ed25519.c | 4 ---- ed25519-donna/modm-donna-32bit.h | 4 +--- 7 files changed, 11 insertions(+), 21 deletions(-) diff --git a/ed25519-donna/curve25519-donna-32bit.h b/ed25519-donna/curve25519-donna-32bit.h index 6a4e9c3ab..d49e80ff0 100644 --- a/ed25519-donna/curve25519-donna-32bit.h +++ b/ed25519-donna/curve25519-donna-32bit.h @@ -40,7 +40,7 @@ curve25519_add(bignum25519 out, const bignum25519 a, const bignum25519 b) { out[9] = a[9] + b[9]; } -DONNA_INLINE static void +DONNA_INLINE static void curve25519_add_after_basic(bignum25519 out, const bignum25519 a, const bignum25519 b) { uint32_t c; out[0] = a[0] + b[0] ; c = (out[0] >> 26); out[0] &= reduce_mask_26; diff --git a/ed25519-donna/curve25519-donna-scalarmult-base.h b/ed25519-donna/curve25519-donna-scalarmult-base.h index 061759fa6..ff1010122 100644 --- a/ed25519-donna/curve25519-donna-scalarmult-base.h +++ b/ed25519-donna/curve25519-donna-scalarmult-base.h @@ -15,7 +15,7 @@ curve25519_scalarmult_donna(curve25519_key mypublic, const curve25519_key n, con curve25519_expand(q, basepoint); curve25519_copy(nqx, q); - /* bit 255 is always 0, and bit 254 is always 1, so skip bit 255 and + /* bit 255 is always 0, and bit 254 is always 1, so skip bit 255 and start pre-swapped on bit 254 */ lastbit = 1; @@ -63,4 +63,3 @@ curve25519_scalarmult_donna(curve25519_key mypublic, const curve25519_key n, con curve25519_mul(nqz, nqx, zmone); curve25519_contract(mypublic, nqz); } - diff --git a/ed25519-donna/ed25519-donna-32bit-tables.h b/ed25519-donna/ed25519-donna-32bit-tables.h index 49022aee2..c977c26eb 100644 --- a/ed25519-donna/ed25519-donna-32bit-tables.h +++ b/ed25519-donna/ed25519-donna-32bit-tables.h @@ -1,4 +1,4 @@ -const ge25519 ALIGN(16) ge25519_basepoint = { +static const ge25519 ALIGN(16) ge25519_basepoint = { {0x0325d51a,0x018b5823,0x00f6592a,0x0104a92d,0x01a4b31d,0x01d6dc5c,0x027118fe,0x007fd814,0x013cd6e5,0x0085a4db}, {0x02666658,0x01999999,0x00cccccc,0x01333333,0x01999999,0x00666666,0x03333333,0x00cccccc,0x02666666,0x01999999}, {0x00000001,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000}, @@ -9,11 +9,11 @@ const ge25519 ALIGN(16) ge25519_basepoint = { d */ -const bignum25519 ALIGN(16) ge25519_ecd = { +static const bignum25519 ALIGN(16) ge25519_ecd = { 0x035978a3,0x00d37284,0x03156ebd,0x006a0a0e,0x0001c029,0x0179e898,0x03a03cbb,0x01ce7198,0x02e2b6ff,0x01480db3 }; -const bignum25519 ALIGN(16) ge25519_ec2d = { +static const bignum25519 ALIGN(16) ge25519_ec2d = { 0x02b2f159,0x01a6e509,0x022add7a,0x00d4141d,0x00038052,0x00f3d130,0x03407977,0x019ce331,0x01c56dff,0x00901b67 }; @@ -21,11 +21,11 @@ const bignum25519 ALIGN(16) ge25519_ec2d = { sqrt(-1) */ -const bignum25519 ALIGN(16) ge25519_sqrtneg1 = { +static const bignum25519 ALIGN(16) ge25519_sqrtneg1 = { 0x020ea0b0,0x0186c9d2,0x008f189d,0x0035697f,0x00bd0c60,0x01fbd7a7,0x02804c9e,0x01e16569,0x0004fc1d,0x00ae0c92 }; -const ge25519_niels ALIGN(16) ge25519_niels_sliding_multiples[32] = { +static const ge25519_niels ALIGN(16) ge25519_niels_sliding_multiples[32] = { {{0x0340913e,0x000e4175,0x03d673a2,0x002e8a05,0x03f4e67c,0x008f8a09,0x00c21a34,0x004cf4b8,0x01298f81,0x0113f4be},{0x018c3b85,0x0124f1bd,0x01c325f7,0x0037dc60,0x033e4cb7,0x003d42c2,0x01a44c32,0x014ca4e1,0x03a33d4b,0x001f3e74},{0x037aaa68,0x00448161,0x0093d579,0x011e6556,0x009b67a0,0x0143598c,0x01bee5ee,0x00b50b43,0x0289f0c6,0x01bc45ed}}, {{0x00fcd265,0x0047fa29,0x034faacc,0x01ef2e0d,0x00ef4d4f,0x014bd6bd,0x00f98d10,0x014c5026,0x007555bd,0x00aae456},{0x00ee9730,0x016c2a13,0x017155e4,0x01874432,0x00096a10,0x01016732,0x01a8014f,0x011e9823,0x01b9a80f,0x01e85938},{0x01d0d889,0x01a4cfc3,0x034c4295,0x0110e1ae,0x0162508c,0x00f2db4c,0x0072a2c6,0x0098da2e,0x02f12b9b,0x0168a09a}}, {{0x0047d6ba,0x0060b0e9,0x0136eff2,0x008a5939,0x03540053,0x0064a087,0x02788e5c,0x00be7c67,0x033eb1b5,0x005529f9},{0x00a5bb33,0x00af1102,0x01a05442,0x001e3af7,0x02354123,0x00bfec44,0x01f5862d,0x00dd7ba3,0x03146e20,0x00a51733},{0x012a8285,0x00f6fc60,0x023f9797,0x003e85ee,0x009c3820,0x01bda72d,0x01b3858d,0x00d35683,0x0296b3bb,0x010eaaf9}}, diff --git a/ed25519-donna/ed25519-donna-impl-base.h b/ed25519-donna/ed25519-donna-impl-base.h index d5472795c..93257e224 100644 --- a/ed25519-donna/ed25519-donna-impl-base.h +++ b/ed25519-donna/ed25519-donna-impl-base.h @@ -6,15 +6,15 @@ DONNA_INLINE static void ge25519_p1p1_to_partial(ge25519 *r, const ge25519_p1p1 *p) { curve25519_mul(r->x, p->x, p->t); curve25519_mul(r->y, p->y, p->z); - curve25519_mul(r->z, p->z, p->t); + curve25519_mul(r->z, p->z, p->t); } DONNA_INLINE static void ge25519_p1p1_to_full(ge25519 *r, const ge25519_p1p1 *p) { curve25519_mul(r->x, p->x, p->t); curve25519_mul(r->y, p->y, p->z); - curve25519_mul(r->z, p->z, p->t); - curve25519_mul(r->t, p->x, p->y); + curve25519_mul(r->z, p->z, p->t); + curve25519_mul(r->t, p->x, p->y); } static void @@ -209,7 +209,6 @@ static int ge25519_unpack_negative_vartime(ge25519 *r, const unsigned char p[32] return 1; } - /* scalarmults */ diff --git a/ed25519-donna/ed25519-donna.h b/ed25519-donna/ed25519-donna.h index de176abad..f72cb7e66 100644 --- a/ed25519-donna/ed25519-donna.h +++ b/ed25519-donna/ed25519-donna.h @@ -8,7 +8,6 @@ Bo-Yin Yang */ - #include "ed25519-donna-portable.h" #include "curve25519-donna-32bit.h" @@ -30,7 +29,6 @@ ed25519_verify(const unsigned char *x, const unsigned char *y, size_t len) { return (int) (1 & ((differentbits - 1) >> 8)); } - /* * Arithmetic on the twisted Edwards curve -x^2 + y^2 = 1 + dx^2y^2 * with d = -(121665/121666) = 37095705934669439343138083508754565189542113879843219016388785533085940283555 diff --git a/ed25519-donna/ed25519.c b/ed25519-donna/ed25519.c index 6b13f6087..52a7f21fe 100644 --- a/ed25519-donna/ed25519.c +++ b/ed25519-donna/ed25519.c @@ -4,7 +4,6 @@ Ed25519 reference implementation using Ed25519-donna */ - #include "ed25519-donna.h" #include "ed25519.h" #include "ed25519-hash-custom.h" @@ -14,7 +13,6 @@ /* Generates a (extsk[0..31]) and aExt (extsk[32..63]) */ - DONNA_INLINE static void ed25519_extsk(hash_512bits extsk, const ed25519_secret_key sk) { ed25519_hash(extsk, sk, 32); @@ -46,7 +44,6 @@ ed25519_publickey(const ed25519_secret_key sk, ed25519_public_key pk) { ge25519_pack(pk, &A); } - void ed25519_sign(const unsigned char *m, size_t mlen, const ed25519_secret_key sk, const ed25519_public_key pk, ed25519_signature RS) { ed25519_hash_context ctx; @@ -110,7 +107,6 @@ ed25519_sign_open(const unsigned char *m, size_t mlen, const ed25519_public_key /* Fast Curve25519 basepoint scalar multiplication */ - void curved25519_scalarmult_basepoint(curved25519_key pk, const curved25519_key e) { curved25519_key ec; diff --git a/ed25519-donna/modm-donna-32bit.h b/ed25519-donna/modm-donna-32bit.h index 16fba16d4..ca691dec2 100644 --- a/ed25519-donna/modm-donna-32bit.h +++ b/ed25519-donna/modm-donna-32bit.h @@ -80,7 +80,7 @@ barrett_reduce256_modm(bignum256modm r, const bignum256modm q1, const bignum256m /* q1 = x >> 248 = 264 bits = 9 30 bit elements q2 = mu * q1 q3 = (q2 / 256(32+1)) = q2 / (2^8)^(32+1) = q2 >> 264 */ - c = mul32x32_64(modm_mu[0], q1[7]) + mul32x32_64(modm_mu[1], q1[6]) + mul32x32_64(modm_mu[2], q1[5]) + mul32x32_64(modm_mu[3], q1[4]) + mul32x32_64(modm_mu[4], q1[3]) + mul32x32_64(modm_mu[5], q1[2]) + mul32x32_64(modm_mu[6], q1[1]) + mul32x32_64(modm_mu[7], q1[0]); + c = mul32x32_64(modm_mu[0], q1[7]) + mul32x32_64(modm_mu[1], q1[6]) + mul32x32_64(modm_mu[2], q1[5]) + mul32x32_64(modm_mu[3], q1[4]) + mul32x32_64(modm_mu[4], q1[3]) + mul32x32_64(modm_mu[5], q1[2]) + mul32x32_64(modm_mu[6], q1[1]) + mul32x32_64(modm_mu[7], q1[0]); c >>= 30; c += mul32x32_64(modm_mu[0], q1[8]) + mul32x32_64(modm_mu[1], q1[7]) + mul32x32_64(modm_mu[2], q1[6]) + mul32x32_64(modm_mu[3], q1[5]) + mul32x32_64(modm_mu[4], q1[4]) + mul32x32_64(modm_mu[5], q1[3]) + mul32x32_64(modm_mu[6], q1[2]) + mul32x32_64(modm_mu[7], q1[1]) + mul32x32_64(modm_mu[8], q1[0]); f = (bignum256modm_element_t)c; q3[0] = (f >> 24) & 0x3f; c >>= 30; @@ -288,8 +288,6 @@ static void contract256_modm(unsigned char out[32], const bignum256modm in) { U32TO8_LE(out + 28, (in[7] >> 14) | (in[8] << 16)); } - - static void contract256_window4_modm(signed char r[64], const bignum256modm in) { char carry; signed char *quads = r; From fdf1b6dc6d2a8241854152e14cce907a1ce02d7b Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 28 Mar 2017 23:05:59 +0200 Subject: [PATCH 376/627] remove duplicite curve25519 scalarmult implementations --- bip32.c | 4 ++-- ed25519-donna/ed25519.c | 12 +++--------- ed25519-donna/ed25519.h | 10 ++-------- test_speed.c | 2 +- 4 files changed, 8 insertions(+), 20 deletions(-) diff --git a/bip32.c b/bip32.c index 11f3df75d..6effce145 100644 --- a/bip32.c +++ b/bip32.c @@ -406,7 +406,7 @@ void hdnode_fill_public_key(HDNode *node) ed25519_publickey(node->private_key, node->public_key + 1); } else if (node->curve == &curve25519_info) { node->public_key[0] = 1; - curve25519_donna_basepoint(node->public_key + 1, node->private_key); + curve25519_scalarmult_basepoint(node->public_key + 1, node->private_key); } else { ecdsa_get_public_key33(node->curve->params, node->private_key, node->public_key); } @@ -472,7 +472,7 @@ int hdnode_get_shared_key(const HDNode *node, const uint8_t *peer_public_key, ui if (peer_public_key[0] != 0x40) { return 1; // Curve25519 public key should start with 0x40 byte. } - curve25519_donna(session_key + 1, node->private_key, peer_public_key + 1); + curve25519_scalarmult(session_key + 1, node->private_key, peer_public_key + 1); *result_size = 33; return 0; } else { diff --git a/ed25519-donna/ed25519.c b/ed25519-donna/ed25519.c index 52a7f21fe..631d15f9d 100644 --- a/ed25519-donna/ed25519.c +++ b/ed25519-donna/ed25519.c @@ -108,8 +108,8 @@ ed25519_sign_open(const unsigned char *m, size_t mlen, const ed25519_public_key Fast Curve25519 basepoint scalar multiplication */ void -curved25519_scalarmult_basepoint(curved25519_key pk, const curved25519_key e) { - curved25519_key ec; +curve25519_scalarmult_basepoint(curve25519_key pk, const curve25519_key e) { + curve25519_key ec; bignum256modm s; bignum25519 ALIGN(16) yplusz, zminusy; ge25519 ALIGN(16) p; @@ -135,7 +135,7 @@ curved25519_scalarmult_basepoint(curved25519_key pk, const curved25519_key e) { } void -curve25519_donna(curve25519_key mypublic, const curve25519_key secret, const curve25519_key basepoint) { +curve25519_scalarmult(curve25519_key mypublic, const curve25519_key secret, const curve25519_key basepoint) { curve25519_key e; size_t i; @@ -145,9 +145,3 @@ curve25519_donna(curve25519_key mypublic, const curve25519_key secret, const cur e[31] |= 0x40; curve25519_scalarmult_donna(mypublic, e, basepoint); } - -void -curve25519_donna_basepoint(curve25519_key mypublic, const curve25519_key secret) { - static const curve25519_key basepoint = {9}; - curve25519_donna(mypublic, secret, basepoint); -} diff --git a/ed25519-donna/ed25519.h b/ed25519-donna/ed25519.h index 928e7cd06..96a2727b4 100644 --- a/ed25519-donna/ed25519.h +++ b/ed25519-donna/ed25519.h @@ -11,18 +11,12 @@ typedef unsigned char ed25519_secret_key[32]; typedef unsigned char curve25519_key[32]; -typedef unsigned char curved25519_key[32]; - void ed25519_publickey(const ed25519_secret_key sk, ed25519_public_key pk); int ed25519_sign_open(const unsigned char *m, size_t mlen, const ed25519_public_key pk, const ed25519_signature RS); void ed25519_sign(const unsigned char *m, size_t mlen, const ed25519_secret_key sk, const ed25519_public_key pk, ed25519_signature RS); -int ed25519_sign_open_batch(const unsigned char **m, size_t *mlen, const unsigned char **pk, const unsigned char **RS, size_t num, int *valid); - -void curved25519_scalarmult_basepoint(curved25519_key pk, const curved25519_key e); - -void curve25519_donna(curve25519_key mypublic, const curve25519_key secret, const curve25519_key basepoint); -void curve25519_donna_basepoint(curve25519_key mypublic, const curve25519_key secret); +void curve25519_scalarmult(curve25519_key mypublic, const curve25519_key secret, const curve25519_key basepoint); +void curve25519_scalarmult_basepoint(curve25519_key mypublic, const curve25519_key secret); #if defined(__cplusplus) } diff --git a/test_speed.c b/test_speed.c index c6fa53174..eaa808be6 100644 --- a/test_speed.c +++ b/test_speed.c @@ -91,7 +91,7 @@ void bench_curve25519(void) clock_t t = clock(); for (int i = 0 ; i < 500; i++) { - curve25519_donna(result, secret, basepoint); + curve25519_scalarmult(result, secret, basepoint); } printf("Curve25519 multiplying speed: %0.2f mul/s\n", 500.0f / ((float)(clock() - t) / CLOCKS_PER_SEC)); } From df2524e35bc7d10129b965be017277ce46d2cae0 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 28 Mar 2017 23:18:55 +0200 Subject: [PATCH 377/627] add changes to cmake/qmake builds --- CMakeLists.txt | 1 - gui/.gitignore | 3 +++ gui/gui.pro | 6 +----- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9d6aeb245..df68483c8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,6 @@ add_library(TrezorCrypto STATIC ${SOURCES}) target_include_directories(TrezorCrypto PUBLIC .) target_include_directories(TrezorCrypto PUBLIC ed25519-donna) -target_include_directories(TrezorCrypto PUBLIC curve25519-donna) # disable sequence point warnings where they are expected set_source_files_properties(aeskey.c PROPERTIES diff --git a/gui/.gitignore b/gui/.gitignore index f995622d5..b44cbb243 100644 --- a/gui/.gitignore +++ b/gui/.gitignore @@ -1 +1,4 @@ gui.pro.user +moc_mainwindow.cpp +ui_mainwindow.h +Makefile diff --git a/gui/gui.pro b/gui/gui.pro index 59ebd8ead..0197efe1e 100644 --- a/gui/gui.pro +++ b/gui/gui.pro @@ -4,6 +4,7 @@ greaterThan(QT_MAJOR_VERSION, 4): QT += widgets TARGET = gui TEMPLATE = app +SOURCES += ../address.c SOURCES += ../bip32.c SOURCES += ../bip39.c SOURCES += ../sha2.c @@ -17,7 +18,6 @@ SOURCES += ../base58.c SOURCES += ../secp256k1.c SOURCES += ../nist256p1.c SOURCES += ../curves.c -SOURCES += ../curve25519-donna/curve25519-donna.c SOURCES += ../ed25519-donna/ed25519.c SOURCES += mainwindow.cpp SOURCES += main.cpp @@ -29,8 +29,4 @@ HEADERS += ../bip39.h FORMS += mainwindow.ui INCLUDEPATH += .. -INCLUDEPATH += ../curve25519-donna INCLUDEPATH += ../ed25519-donna - -DEFINES += ED25519_CUSTOMRANDOM=1 -DEFINES += ED25519_CUSTOMHASH=1 From c200ce121ac268d7b201dddc89b42758ccfc40bf Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 29 Mar 2017 00:18:56 +0200 Subject: [PATCH 378/627] introduce ED25519_NO_PRECOMP flag to optimize ed25519 verify size --- ed25519-donna/ed25519-donna-impl-base.h | 26 ++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/ed25519-donna/ed25519-donna-impl-base.h b/ed25519-donna/ed25519-donna-impl-base.h index 93257e224..b12b012ca 100644 --- a/ed25519-donna/ed25519-donna-impl-base.h +++ b/ed25519-donna/ed25519-donna-impl-base.h @@ -45,6 +45,7 @@ ge25519_double_p1p1(ge25519_p1p1 *r, const ge25519 *p) { curve25519_sub_after_basic(r->t, c, r->z); } +#ifndef ED25519_NO_PRECOMP static void ge25519_nielsadd2_p1p1(ge25519_p1p1 *r, const ge25519 *p, const ge25519_niels *q, unsigned char signbit) { const bignum25519 *qb = (const bignum25519 *)q; @@ -63,6 +64,7 @@ ge25519_nielsadd2_p1p1(ge25519_p1p1 *r, const ge25519 *p, const ge25519_niels *q curve25519_add(rb[2+signbit], rb[2+signbit], c); /* z for +, t for - */ curve25519_sub(rb[2+(signbit^1)], rb[2+(signbit^1)], c); /* t for +, z for - */ } +#endif static void ge25519_pnielsadd_p1p1(ge25519_p1p1 *r, const ge25519 *p, const ge25519_pniels *q, unsigned char signbit) { @@ -222,24 +224,38 @@ DONNA_INLINE static void ge25519_set_neutral(ge25519 *r) #define S1_SWINDOWSIZE 5 #define S1_TABLE_SIZE (1<<(S1_SWINDOWSIZE-2)) +#ifdef ED25519_NO_PRECOMP +#define S2_SWINDOWSIZE 5 +#else #define S2_SWINDOWSIZE 7 +#endif #define S2_TABLE_SIZE (1<<(S2_SWINDOWSIZE-2)) /* computes [s1]p1 + [s2]base */ static void ge25519_double_scalarmult_vartime(ge25519 *r, const ge25519 *p1, const bignum256modm s1, const bignum256modm s2) { signed char slide1[256], slide2[256]; ge25519_pniels pre1[S1_TABLE_SIZE]; - ge25519 d1; +#ifdef ED25519_NO_PRECOMP + ge25519_pniels pre2[S2_TABLE_SIZE]; +#endif + ge25519 dp; ge25519_p1p1 t; int32_t i; contract256_slidingwindow_modm(slide1, s1, S1_SWINDOWSIZE); contract256_slidingwindow_modm(slide2, s2, S2_SWINDOWSIZE); - ge25519_double(&d1, p1); + ge25519_double(&dp, p1); ge25519_full_to_pniels(pre1, p1); for (i = 0; i < S1_TABLE_SIZE - 1; i++) - ge25519_pnielsadd(&pre1[i+1], &d1, &pre1[i]); + ge25519_pnielsadd(&pre1[i+1], &dp, &pre1[i]); + +#ifdef ED25519_NO_PRECOMP + ge25519_double(&dp, &ge25519_basepoint); + ge25519_full_to_pniels(pre2, &ge25519_basepoint); + for (i = 0; i < S2_TABLE_SIZE - 1; i++) + ge25519_pnielsadd(&pre2[i+1], &dp, &pre2[i]); +#endif ge25519_set_neutral(r); @@ -257,7 +273,11 @@ static void ge25519_double_scalarmult_vartime(ge25519 *r, const ge25519 *p1, con if (slide2[i]) { ge25519_p1p1_to_full(r, &t); +#ifdef ED25519_NO_PRECOMP + ge25519_pnielsadd_p1p1(&t, r, &pre2[abs(slide2[i]) / 2], (unsigned char)slide2[i] >> 7); +#else ge25519_nielsadd2_p1p1(&t, r, &ge25519_niels_sliding_multiples[abs(slide2[i]) / 2], (unsigned char)slide2[i] >> 7); +#endif } ge25519_p1p1_to_partial(r, &t); From 323d6b023a46715879d2bf06131f6ec4647ba7ab Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 30 Mar 2017 15:07:29 +0200 Subject: [PATCH 379/627] fix build --- test_curves.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test_curves.py b/test_curves.py index f5396fa37..1e0639647 100755 --- a/test_curves.py +++ b/test_curves.py @@ -409,9 +409,9 @@ def test_curve25519(r): pub2 = curve25519.Private(sec2).get_public() session1 = r.randbytes(32) - lib.curve25519_donna(session1, sec2, pub1.public) + lib.curve25519_scalarmult(session1, sec2, pub1.public) session2 = r.randbytes(32) - lib.curve25519_donna(session2, sec1, pub2.public) + lib.curve25519_scalarmult(session2, sec1, pub2.public) assert bytearray(session1) == bytearray(session2) shared1 = curve25519.Private(sec2).get_shared_key(pub1, hashfunc=lambda x: x) @@ -425,7 +425,7 @@ def test_curve25519_pubkey(r): sec = bytes(bytearray(r.randbytes(32))) pub = curve25519.Private(sec).get_public() res = r.randbytes(32) - lib.curve25519_donna_basepoint(res, sec) + lib.curve25519_scalarmult_basepoint(res, sec) assert bytearray(res) == pub.public @@ -433,6 +433,6 @@ def test_curve25519_scalarmult_from_gpg(r): sec = binascii.unhexlify('4a1e76f133afb29dbc7860bcbc16d0e829009cc15c2f81ed26de1179b1d9c938') pub = binascii.unhexlify('5d6fc75c016e85b17f54e0128a216d5f9229f25bac1ec85cecab8daf48621b31') res = r.randbytes(32) - lib.curve25519_donna(res, sec[::-1], pub[::-1]) + lib.curve25519_scalarmult(res, sec[::-1], pub[::-1]) expected = 'a93dbdb23e5c99da743e203bd391af79f2b83fb8d0fd6ec813371c71f08f2d4d' assert binascii.hexlify(bytearray(res)) == expected From aa16b53bbade13d3064cc42b210a7eef06009b7c Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Thu, 30 Mar 2017 17:38:49 +0200 Subject: [PATCH 380/627] Refactored duplicated code (#84) Changed signature of public_ckd_address_optimized to not include the compressed public_key (uncompressed is in pub). --- bip32.c | 103 +++++++++++++++++++-------------------------------- bip32.h | 4 +- test_speed.c | 3 +- 3 files changed, 43 insertions(+), 67 deletions(-) diff --git a/bip32.c b/bip32.c index 6effce145..f7b20ec1e 100644 --- a/bip32.c +++ b/bip32.c @@ -210,101 +210,74 @@ int hdnode_private_ckd(HDNode *inout, uint32_t i) return 1; } -int hdnode_public_ckd(HDNode *inout, uint32_t i) -{ +int hdnode_public_ckd_cp(const ecdsa_curve *curve, const curve_point *parent, const uint8_t *parent_chain_code, uint32_t i, curve_point *child, uint8_t *child_chain_code) { uint8_t data[1 + 32 + 4]; uint8_t I[32 + 32]; - curve_point a, b; bignum256 c; if (i & 0x80000000) { // private derivation return 0; - } else { // public derivation - if (!inout->curve->params) { - return 0; - } - memcpy(data, inout->public_key, 33); } - write_be(data + 33, i); - memset(inout->private_key, 0, 32); - if (!ecdsa_read_pubkey(inout->curve->params, inout->public_key, &a)) { - return 0; - } + data[0] = 0x02 | (parent->y.val[0] & 0x01); + bn_write_be(&parent->x, data + 1); + write_be(data + 33, i); while (true) { - bool failed = false; - hmac_sha512(inout->chain_code, 32, data, sizeof(data), I); + hmac_sha512(parent_chain_code, 32, data, sizeof(data), I); bn_read_be(I, &c); - if (!bn_is_less(&c, &inout->curve->params->order)) { // >= order - failed = true; - } else { - scalar_multiply(inout->curve->params, &c, &b); // b = c * G - point_add(inout->curve->params, &a, &b); // b = a + b - if (point_is_infinity(&b)) { - failed = true; + if (bn_is_less(&c, &curve->order)) { // < order + scalar_multiply(curve, &c, child); // b = c * G + point_add(curve, parent, child); // b = a + b + if (!point_is_infinity(child)) { + if (child_chain_code) { + memcpy(child_chain_code, I + 32, 32); + } + + // Wipe all stack data. + MEMSET_BZERO(data, sizeof(data)); + MEMSET_BZERO(I, sizeof(I)); + MEMSET_BZERO(&c, sizeof(c)); + return 1; } } - if (!failed) { - inout->public_key[0] = 0x02 | (b.y.val[0] & 0x01); - bn_write_be(&b.x, inout->public_key + 1); - break; - } - data[0] = 1; memcpy(data + 1, I + 32, 32); } +} +int hdnode_public_ckd(HDNode *inout, uint32_t i) +{ + curve_point parent, child; + + if (!ecdsa_read_pubkey(inout->curve->params, inout->public_key, &parent)) { + return 0; + } + if (!hdnode_public_ckd_cp(inout->curve->params, &parent, inout->chain_code, i, &child, inout->chain_code)) { + return 0; + } + memset(inout->private_key, 0, 32); inout->depth++; inout->child_num = i; - memcpy(inout->chain_code, I + 32, 32); + inout->public_key[0] = 0x02 | (child.y.val[0] & 0x01); + bn_write_be(&child.x, inout->public_key + 1); // Wipe all stack data. - MEMSET_BZERO(data, sizeof(data)); - MEMSET_BZERO(I, sizeof(I)); - MEMSET_BZERO(&a, sizeof(a)); - MEMSET_BZERO(&b, sizeof(b)); - MEMSET_BZERO(&c, sizeof(c)); + MEMSET_BZERO(&parent, sizeof(parent)); + MEMSET_BZERO(&child, sizeof(child)); return 1; } -int hdnode_public_ckd_address_optimized(const curve_point *pub, const uint8_t *public_key, const uint8_t *chain_code, uint32_t i, uint32_t version, char *addr, int addrsize) +int hdnode_public_ckd_address_optimized(const curve_point *pub, const uint8_t *chain_code, uint32_t i, uint32_t version, char *addr, int addrsize) { - uint8_t data[1 + 32 + 4]; - uint8_t I[32 + 32]; uint8_t child_pubkey[33]; curve_point b; - bignum256 c; - - if (i & 0x80000000) { // private derivation - return 0; - } - memcpy(data, public_key, 33); - write_be(data + 33, i); - while (true) { - bool failed = false; - hmac_sha512(chain_code, 32, data, sizeof(data), I); - bn_read_be(I, &c); - if (!bn_is_less(&c, &secp256k1.order)) { // >= order - failed = true; - } else { - scalar_multiply(&secp256k1, &c, &b); // b = c * G - point_add(&secp256k1, pub, &b); // b = a + b - if (point_is_infinity(&b)) { - failed = true; - } - } - if (!failed) { - child_pubkey[0] = 0x02 | (b.y.val[0] & 0x01); - bn_write_be(&b.x, child_pubkey + 1); - break; - } - data[0] = 1; - memcpy(data + 1, I + 32, 32); - } + hdnode_public_ckd_cp(&secp256k1, pub, chain_code, i, &b, NULL); + child_pubkey[0] = 0x02 | (b.y.val[0] & 0x01); + bn_write_be(&b.x, child_pubkey + 1); ecdsa_get_address(child_pubkey, version, addr, addrsize); return 1; } diff --git a/bip32.h b/bip32.h index 3a3adaa34..330294ace 100644 --- a/bip32.h +++ b/bip32.h @@ -53,9 +53,11 @@ int hdnode_from_seed(const uint8_t *seed, int seed_len, const char *curve, HDNod int hdnode_private_ckd(HDNode *inout, uint32_t i); +int hdnode_public_ckd_cp(const ecdsa_curve *curve, const curve_point *parent, const uint8_t *parent_chain_code, uint32_t i, curve_point *child, uint8_t *child_chain_code); + int hdnode_public_ckd(HDNode *inout, uint32_t i); -int hdnode_public_ckd_address_optimized(const curve_point *pub, const uint8_t *public_key, const uint8_t *chain_code, uint32_t i, uint32_t version, char *addr, int addrsize); +int hdnode_public_ckd_address_optimized(const curve_point *pub, const uint8_t *chain_code, uint32_t i, uint32_t version, char *addr, int addrsize); #if USE_BIP32_CACHE diff --git a/test_speed.c b/test_speed.c index eaa808be6..7e02d3488 100644 --- a/test_speed.c +++ b/test_speed.c @@ -5,6 +5,7 @@ #include #include "curves.h" #include "ecdsa.h" +#include "bip32.h" #include "secp256k1.h" #include "nist256p1.h" #include "ed25519.h" @@ -133,7 +134,7 @@ void bench_ckd_optimized(int iterations) ecdsa_read_pubkey(&secp256k1, root.public_key, &pub); clock_t t = clock(); for (int i = 0; i < iterations; i++) { - hdnode_public_ckd_address_optimized(&pub, root.public_key, root.chain_code, i, 0, addr, sizeof(addr)); + hdnode_public_ckd_address_optimized(&pub, root.chain_code, i, 0, addr, sizeof(addr)); if (i == 0 || i == iterations -1) { printf("address = %s\n", addr); } From 36f099fe62a121727723b88a3f361a21f1a16047 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 30 Mar 2017 17:53:09 +0200 Subject: [PATCH 381/627] update emscripten stuff --- emscripten/Makefile | 10 ++++++---- emscripten/post.js | 4 ++-- emscripten/trezor-crypto.js | 16 ++++++++-------- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/emscripten/Makefile b/emscripten/Makefile index ec3853f05..44666c57a 100644 --- a/emscripten/Makefile +++ b/emscripten/Makefile @@ -6,18 +6,20 @@ EMFLAGS = \ -s EXPORTED_FUNCTIONS='["_hdnode_public_ckd_address_optimized", "_ecdsa_read_pubkey"]' SRC = ../bignum.c ../ecdsa.c ../secp256k1.c ../hmac.c ../bip32.c \ - ../base58.c ../ripemd160.c ../sha2.c ../rand.c + ../base58.c ../ripemd160.c ../sha2.c ../rand.c ../address.c + +all: trezor-crypto.js test-browserify.js trezor-crypto.js: $(SRC) emcc $(EMFLAGS) -o $@ $^ -test-node: node_modules trezor-crypto.js test.js - node test.js - test-browserify.js: node_modules trezor-crypto.js test.js $(shell npm bin)/browserify test.js -o $@ --noparse=`pwd`/trezor-crypto.js @echo "open test.html in your favourite browser" +test-node: node_modules trezor-crypto.js test.js + node test.js + node_modules: npm install npm install browserify diff --git a/emscripten/post.js b/emscripten/post.js index 29942893a..e3a44bbca 100644 --- a/emscripten/post.js +++ b/emscripten/post.js @@ -24,7 +24,7 @@ var CHAINCODE_SIZE = 32; var _chaincode = _malloc(CHAINCODE_SIZE); // address string global -var ADDRESS_SIZE = 40; // maximum size +var ADDRESS_SIZE = 60; // maximum size var _address = _malloc(ADDRESS_SIZE); /* @@ -52,7 +52,7 @@ function serializeNode(node) { * @return {String} */ function deriveAddress(index, version) { - _hdnode_public_ckd_address_optimized(_pubpoint, _pubkey, _chaincode, index, version, _address, ADDRESS_SIZE); + _hdnode_public_ckd_address_optimized(_pubpoint, _chaincode, index, version, _address, ADDRESS_SIZE); return Pointer_stringify(_address); } diff --git a/emscripten/trezor-crypto.js b/emscripten/trezor-crypto.js index 02d4a769b..879b9a1a5 100644 --- a/emscripten/trezor-crypto.js +++ b/emscripten/trezor-crypto.js @@ -8,7 +8,7 @@ e.printErr||(e.printErr=e.print);e.arguments||(e.arguments=[]);e.thisProgram||(e var aa=void 0,t={Wa:function(a){tempRet0=a},Na:function(){return tempRet0},Q:function(){return p},I:function(a){p=a},va:function(a){switch(a){case "i1":case "i8":return 1;case "i16":return 2;case "i32":return 4;case "i64":return 8;case "float":return 4;case "double":return 8;default:return"*"===a[a.length-1]?t.V:"i"===a[0]?(a=parseInt(a.substr(1)),assert(0===a%8),a/8):0}},Ma:function(a){return Math.max(t.va(a),t.V)},Wc:16,rd:function(a,b){"double"===b||"i64"===b?a&7&&(assert(4===(a&7)),a+=4):assert(0=== (a&3));return a},ed:function(a,b,c){return c||"i64"!=a&&"double"!=a?a?Math.min(b||(a?t.Ma(a):0),t.V):Math.min(b,8):8},t:function(a,b,c){return c&&c.length?e["dynCall_"+a].apply(null,[b].concat(c)):e["dynCall_"+a].call(null,b)},N:[],Ha:function(a){for(var b=0;b>2];a=(b+a+15|0)&-16;w[x>>2]=a;if(a=a>=ha)ia(),a=!0;return a?(w[x>>2]=b,0):b},ma:function(a,b){return Math.ceil(a/(b?b:16))*(b?b:16)},qd:function(a,b,c){return c?+(a>>>0)+4294967296*+(b>>>0):+(a>>>0)+4294967296*+(b|0)},L:8,V:4,Xc:0};e.Runtime=t;t.addFunction=t.Ha;t.removeFunction=t.Sa;var ja=!1;function assert(a,b){a||z("Assertion failed: "+b)} +qa:function(a){var b=w[x>>2];a=(b+a+15|0)&-16;w[x>>2]=a;if(a=a>=ha)ia(),a=!0;return a?(w[x>>2]=b,0):b},ma:function(a,b){return Math.ceil(a/(b?b:16))*(b?b:16)},qd:function(a,b,c){return c?+(a>>>0)+4294967296*+(b>>>0):+(a>>>0)+4294967296*+(b|0)},L:8,V:4,Xc:0};e.Runtime=t;t.addFunction=t.Ha;t.removeFunction=t.Sa;var ja=0;function assert(a,b){a||z("Assertion failed: "+b)} function ka(a){var b=e["_"+a];if(!b)try{b=eval("_"+a)}catch(c){}assert(b,"Cannot call unknown function "+a+" (perhaps LLVM optimizations or closure removed it?)");return b}var la,ma; (function(){function a(a){a=a.toString().match(f).slice(1);return{arguments:a[0],body:a[1],returnValue:a[2]}}function b(){if(!g){g={};for(var b in c)c.hasOwnProperty(b)&&(g[b]=a(c[b]))}}var c={stackSave:function(){t.Q()},stackRestore:function(){t.I()},arrayToC:function(a){var b=t.P(a.length);na(a,b);return b},stringToC:function(a){var b=0;if(null!==a&&void 0!==a&&0!==a){var c=(a.length<<2)+1,b=t.P(c);oa(a,b,c)}return b}},d={string:c.stringToC,array:c.arrayToC};ma=function(a,b,c,f,g){a=ka(a);var y= [],H=0;if(f)for(var A=0;A>2]=a);return a} function kb(a,b){for(var c=0,d=a.length-1;0<=d;d--){var f=a[d];"."===f?a.splice(d,1):".."===f?(a.splice(d,1),c++):c&&(a.splice(d,1),c--)}if(b)for(;c--;c)a.unshift("..");return a}function lb(a){var b="/"===a.charAt(0),c="/"===a.substr(-1);(a=kb(a.split("/").filter(function(a){return!!a}),!b).join("/"))||b||(a=".");a&&c&&(a+="/");return(b?"/":"")+a} -function mb(a){var b=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/.exec(a).slice(1);a=b[0];b=b[1];if(!a&&!b)return".";b&&(b=b.substr(0,b.length-1));return a+b}function nb(a){if("/"===a)return"/";var b=a.lastIndexOf("/");return-1===b?a:a.substr(b+1)}function ob(){var a=Array.prototype.slice.call(arguments,0);return lb(a.join("/"))}function L(a,b){return lb(a+"/"+b)} +function mb(a){var b=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/.exec(a).slice(1);a=b[0];b=b[1];if(!a&&!b)return".";b&&(b=b.substr(0,b.length-1));return a+b}function nb(a){if("/"===a)return"/";var b=a.lastIndexOf("/");return-1===b?a:a.substr(b+1)}function pb(){var a=Array.prototype.slice.call(arguments,0);return lb(a.join("/"))}function L(a,b){return lb(a+"/"+b)} function qb(){for(var a="",b=!1,c=arguments.length-1;-1<=c&&!b;c--){b=0<=c?arguments[c]:"/";if("string"!==typeof b)throw new TypeError("Arguments to path.resolve must be strings");if(!b)return"";a=b+"/"+a;b="/"===b.charAt(0)}a=kb(a.split("/").filter(function(a){return!!a}),!b).join("/");return(b?"/":"")+a||"."}var rb=[];function sb(a,b){rb[a]={input:[],output:[],v:b};tb(a,ub)} var ub={open:function(a){var b=rb[a.c.rdev];if(!b)throw new M(K.U);a.tty=b;a.seekable=!1},close:function(a){a.tty.v.flush(a.tty)},flush:function(a){a.tty.v.flush(a.tty)},read:function(a,b,c,d){if(!a.tty||!a.tty.v.wa)throw new M(K.la);for(var f=0,g=0;ga.b.length&&(a.b=N.La(a),a.f=a.b.length);if(!a.b||a.b.subarray){var c=a.b?a.b.buffer.byteLength:0;c>=b||(b=Math.max(b,c*(1048576>c?2:1.125)|0),0!=c&&(b=Math.max(b,256)),c=a.b,a.b=new Uint8Array(b),0a.b.length&&(a.b=N.La(a),a.f=a.b.length);if(!a.b||a.b.subarray){var c=a.b?a.b.length:0;c>=b||(b=Math.max(b,c*(1048576>c?2:1.125)|0),0!=c&&(b=Math.max(b,256)),c=a.b,a.b=new Uint8Array(b),0b)a.b.length=b;else for(;a.b.length=a.c.f)return 0;a=Math.min(a.c.f-f,d);assert(0<=a);if(8b)throw new M(K.g);return b},na:function(a,b,c){N.ra(a.c,b+c);a.c.f=Math.max(a.c.f,b+c)},Aa:function(a, b,c,d,f,g,h){if(32768!==(a.c.mode&61440))throw new M(K.U);c=a.c.b;if(h&2||c.buffer!==b&&c.buffer!==b.buffer){if(0>1)}catch(c){if(!c.code)throw c;throw new M(K[c.code]);}return b.mode},j:function(a){for(var b=[];a.parent!==a;)b.push(a.name),a=a.parent;b.push(a.i.aa.root);b.reverse();return ob.apply(null,b)},sa:{0:"r",1:"r+",2:"r+",64:"r",65:"r+",66:"r+",129:"rx+",193:"rx+",514:"w+",577:"w", +"/",Q.ua(a.aa.root),0)},createNode:function(a,b,c){if(!P(c)&&32768!==(c&61440)&&40960!==(c&61440))throw new M(K.g);a=yb(a,b,c);a.d=Q.d;a.e=Q.e;return a},ua:function(a){var b;try{b=fs.lstatSync(a),Q.O&&(b.mode=b.mode|(b.mode&146)>>1)}catch(c){if(!c.code)throw c;throw new M(K[c.code]);}return b.mode},j:function(a){for(var b=[];a.parent!==a;)b.push(a.name),a=a.parent;b.push(a.i.aa.root);b.reverse();return pb.apply(null,b)},sa:{0:"r",1:"r+",2:"r+",64:"r",65:"r+",66:"r+",129:"rx+",193:"rx+",514:"w+",577:"w", 578:"w+",705:"wx",706:"wx+",1024:"a",1025:"a",1026:"a+",1089:"a",1090:"a+",1153:"ax",1154:"ax+",1217:"ax",1218:"ax+",4096:"rs",4098:"rs+"},Ka:function(a){a&=-2099201;a&=-32769;a&=-524289;if(a in Q.sa)return Q.sa[a];throw new M(K.g);},d:{l:function(a){a=Q.j(a);var b;try{b=fs.lstatSync(a)}catch(c){if(!c.code)throw c;throw new M(K[c.code]);}Q.O&&!b.q&&(b.q=4096);Q.O&&!b.blocks&&(b.blocks=(b.size+b.q-1)/b.q|0);return{dev:b.dev,ino:b.ino,mode:b.mode,nlink:b.nlink,uid:b.uid,gid:b.gid,rdev:b.rdev,size:b.size, atime:b.atime,mtime:b.mtime,ctime:b.ctime,q:b.q,blocks:b.blocks}},h:function(a,b){var c=Q.j(a);try{void 0!==b.mode&&(fs.chmodSync(c,b.mode),a.mode=b.mode),void 0!==b.size&&fs.truncateSync(c,b.size)}catch(d){if(!d.code)throw d;throw new M(K[d.code]);}},lookup:function(a,b){var c=L(Q.j(a),b),c=Q.ua(c);return Q.createNode(a,b,c)},F:function(a,b,c,d){a=Q.createNode(a,b,c,d);b=Q.j(a);try{P(a.mode)?fs.mkdirSync(b,a.mode):fs.writeFileSync(b,"",{mode:a.mode})}catch(f){if(!f.code)throw f;throw new M(K[f.code]); }return a},rename:function(a,b,c){a=Q.j(a);b=L(Q.j(b),c);try{fs.renameSync(a,b)}catch(d){if(!d.code)throw d;throw new M(K[d.code]);}},unlink:function(a,b){var c=L(Q.j(a),b);try{fs.unlinkSync(c)}catch(d){if(!d.code)throw d;throw new M(K[d.code]);}},rmdir:function(a,b){var c=L(Q.j(a),b);try{fs.rmdirSync(c)}catch(d){if(!d.code)throw d;throw new M(K[d.code]);}},readdir:function(a){a=Q.j(a);try{return fs.readdirSync(a)}catch(b){if(!b.code)throw b;throw new M(K[b.code]);}},symlink:function(a,b,c){a=L(Q.j(a), @@ -355,15 +355,15 @@ e.Ja={abort:z,assert:assert,enlargeMemory:function(){ia()},getTotalMemory:functi typeof ic&&f instanceof M||z(f),-f.n}},___syscall54:function(a,b){X=b;try{var c=jc(),d=Y();switch(d){case 21505:return c.tty?0:-K.C;case 21506:return c.tty?0:-K.C;case 21519:if(!c.tty)return-K.C;var f=Y();return w[f>>2]=0;case 21520:return c.tty?-K.g:-K.C;case 21531:f=Y();if(!c.e.Oa)throw new M(K.C);return c.e.Oa(c,d,f);default:z("bad ioctl syscall "+d)}}catch(g){return"undefined"!==typeof ic&&g instanceof M||z(g),-g.n}},___lock:function(){},_abort:function(){e.abort()},_pthread_cleanup_push:fb,___syscall6:function(a, b){X=b;try{var c=jc();$b(c);return 0}catch(d){return"undefined"!==typeof ic&&d instanceof M||z(d),-d.n}},_llvm_stacksave:oc,___syscall140:function(a,b){X=b;try{var c=jc(),d=Y(),f=Y(),g=Y(),h=Y();assert(0===d);ac(c,f,h);w[g>>2]=c.position;c.Z&&0===f&&0===h&&(c.Z=null);return 0}catch(n){return"undefined"!==typeof ic&&n instanceof M||z(n),-n.n}},___syscall5:function(a,b){X=b;try{var c=B(Y()),d=Y(),f=Y();return Yb(c,d,f).fd}catch(g){return"undefined"!==typeof ic&&g instanceof M||z(g),-g.n}},_emscripten_memcpy_big:function(a, b,c){F.set(F.subarray(b,b+c),a);return a},_llvm_bswap_i64:function(a,b){var c=pc(b)>>>0,d=pc(a)>>>0;return(Z.setTempRet0(d),c)|0},___unlock:function(){},_llvm_stackrestore:function(a){var b=oc.D[a];oc.D.splice(a,1);t.I(b)},___assert_fail:function(a,b,c,d){ja=!0;throw"Assertion failed: "+B(a)+", at: "+[b?B(b):"unknown filename",c,d?B(d):"unknown function"]+" at "+Ha();},___syscall145:function(a,b){X=b;try{var c=jc(),d=Y(),f;a:{for(var g=Y(),h=0,n=0;n>2],r,q=c,y=w[d+8*n>>2], -H=u,A=void 0,I=C;if(0>H||0>A)throw new M(K.g);if(1===(q.flags&2097155))throw new M(K.J);if(P(q.c.mode))throw new M(K.B);if(!q.e.read)throw new M(K.g);var O=!0;if("undefined"===typeof A)A=q.position,O=!1;else if(!q.seekable)throw new M(K.K);var pb=q.e.read(q,I,y,H,A);O||(q.position+=pb);r=pb;if(0>r){f=-1;break a}h+=r;if(rH||0>A)throw new M(K.g);if(1===(q.flags&2097155))throw new M(K.J);if(P(q.c.mode))throw new M(K.B);if(!q.e.read)throw new M(K.g);var O=!0;if("undefined"===typeof A)A=q.position,O=!1;else if(!q.seekable)throw new M(K.K);var ob=q.e.read(q,I,y,H,A);O||(q.position+=ob);r=ob;if(0>r){f=-1;break a}h+=r;if(r>2],w[d+(8*n+4)>>2],void 0);if(0>u){f=-1;break a}h+=u}f=h}return f}catch(r){return"undefined"!==typeof ic&&r instanceof M||z(r),-r.n}},___setErrNo:jb,STACKTOP:p,STACK_MAX:Ma,DYNAMICTOP_PTR:x,tempDoublePtr:cb,ABORT:ja};// EMSCRIPTEN_START_ASM var Z=(function(global,env,buffer) { "use asm";var a=new global.Int8Array(buffer);var b=new global.Int16Array(buffer);var c=new global.Int32Array(buffer);var d=new global.Uint8Array(buffer);var e=new global.Uint16Array(buffer);var f=new global.Uint32Array(buffer);var g=new global.Float32Array(buffer);var h=new global.Float64Array(buffer);var i=env.STACKTOP|0;var j=env.STACK_MAX|0;var k=env.DYNAMICTOP_PTR|0;var l=env.tempDoublePtr|0;var m=env.ABORT|0;var n=0;var o=0;var p=0;var q=0;var r=global.NaN,s=global.Infinity;var t=0,u=0,v=0,w=0,x=0.0,y=0,z=0,A=0,B=0.0;var C=0;var D=global.Math.floor;var E=global.Math.abs;var F=global.Math.sqrt;var G=global.Math.pow;var H=global.Math.cos;var I=global.Math.sin;var J=global.Math.tan;var K=global.Math.acos;var L=global.Math.asin;var M=global.Math.atan;var N=global.Math.atan2;var O=global.Math.exp;var P=global.Math.log;var Q=global.Math.ceil;var R=global.Math.imul;var S=global.Math.min;var T=global.Math.max;var U=global.Math.clz32;var V=env.abort;var W=env.assert;var X=env.enlargeMemory;var Y=env.getTotalMemory;var Z=env.abortOnCannotGrowMemory;var _=env.invoke_ii;var $=env.invoke_iiii;var aa=env.invoke_vi;var ba=env._pthread_cleanup_pop;var ca=env.___syscall221;var da=env.___syscall54;var ea=env.___lock;var fa=env._abort;var ga=env._pthread_cleanup_push;var ha=env.___syscall6;var ia=env._llvm_stacksave;var ja=env.___syscall140;var ka=env.___syscall5;var la=env._emscripten_memcpy_big;var ma=env._llvm_bswap_i64;var na=env.___unlock;var oa=env._llvm_stackrestore;var pa=env.___assert_fail;var qa=env.___syscall145;var ra=env.___syscall146;var sa=env.___setErrNo;var ta=0.0; // EMSCRIPTEN_START_FUNCS -function xa(a){a=a|0;var b=0;b=i;i=i+a|0;i=i+15&-16;return b|0}function ya(){return i|0}function za(a){a=a|0;i=a}function Aa(a,b){a=a|0;b=b|0;i=a;j=b}function Ba(a,b){a=a|0;b=b|0;if(!n){n=a;o=b}}function Ca(a){a=a|0;C=a}function Da(){return C|0}function Ea(b,c){b=b|0;c=c|0;a[b>>0]=c>>>24;a[b+1>>0]=c>>>16;a[b+2>>0]=c>>>8;a[b+3>>0]=c;return}function Fa(a,b){a=a|0;b=b|0;var e=0,f=0,g=0,h=0;e=0;f=0;do{h=a+(7-f<<2)|0;h=(d[h+1>>0]|0)<<16|(d[h>>0]|0)<<24|(d[h+2>>0]|0)<<8|(d[h+3>>0]|0);g=f<<1;c[b+(f<<2)>>2]=(h<>>(30-g|0);f=f+1|0}while((f|0)!=8);c[b+32>>2]=e;return}function Ga(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0;e=c[b+32>>2]<<16;f=0;while(1){g=c[b+(7-f<<2)>>2]|0;h=f<<1;i=g>>>(14-h|0)|e;e=d+(f<<2)|0;a[e>>0]=i>>>24;a[e+1>>0]=i>>>16;a[e+2>>0]=i>>>8;a[e+3>>0]=i;f=f+1|0;if((f|0)==8)break;else e=g<>2]=0;a=a+4|0}while((a|0)<(b|0));return}function Ia(a){a=a|0;return (c[a+32>>2]|(c[a+28>>2]|(c[a+24>>2]|(c[a+20>>2]|(c[a+16>>2]|(c[a+12>>2]|(c[a+8>>2]|(c[a+4>>2]|c[a>>2])))))))|0)==0|0}function Ja(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0;d=0;e=8;f=0;while(1){h=c[a+(e<<2)>>2]|0;g=c[b+(e<<2)>>2]|0;d=h>>>0>>0|d<<1;f=h>>>0>g>>>0|f<<1;if((e|0)<=0)break;else e=e+-1|0}return d>>>0>f>>>0|0}function Ka(a,b){a=a|0;b=b|0;var d=0,e=0;d=0;e=0;do{e=c[b+(d<<2)>>2]^c[a+(d<<2)>>2]|e;d=d+1|0}while((d|0)!=9);return (e|0)==0|0}function La(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0;g=0-b|0;h=b+-1|0;if((b|1|0)==1)f=0;else pa(38200,38223,270,38235);do{c[a+(f<<2)>>2]=c[e+(f<<2)>>2]&h|c[d+(f<<2)>>2]&g;f=f+1|0}while((f|0)!=9);return}function Ma(a){a=a|0;var b=0,d=0,e=0,f=0;b=8;d=c[a+32>>2]|0;do{e=b;b=b+-1|0;f=d;d=c[a+(b<<2)>>2]|0;c[a+(e<<2)>>2]=d>>>29&1|f<<1&1073741822}while((e|0)>1);c[a>>2]=c[a>>2]<<1&1073741822;return}function Na(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,i=0;d=c[a>>2]|0;f=0-(d&1)|0;d=((c[b>>2]&f)+d|0)>>>1;e=0;do{i=e;e=e+1|0;g=(c[b+(e<<2)>>2]&f)+(c[a+(e<<2)>>2]|0)|0;h=(g<<29&536870912)+d|0;c[a+(i<<2)>>2]=h&1073741823;d=(h>>>30)+(g>>>1)|0}while((e|0)!=8);c[a+32>>2]=d;return}function Oa(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0;e=b&255;b=0;do{f=a+(b<<2)|0;c[f>>2]=R(c[f>>2]|0,e)|0;b=b+1|0}while((b|0)!=9);Pa(a,d);return}function Pa(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0;g=(c[a+32>>2]|0)>>>16;i=c[a>>2]|0;h=mc(c[b>>2]|0,0,g|0,0)|0;d=C;e=hc(i|0,536870912,h|0,d|0)|0;f=C;d=hc(i|0,0,h|0,d|0)|0;c[a>>2]=d&1073741823;d=1;while(1){l=jc(e|0,f|0,30)|0;k=C;i=a+(d<<2)|0;j=c[i>>2]|0;f=mc(c[b+(d<<2)>>2]|0,0,g|0,0)|0;h=C;k=nc(l|0,k|0,-2147483648,536870911)|0;j=nc(k|0,C|0,j|0,0)|0;e=hc(j|0,C|0,f|0,h|0)|0;c[i>>2]=e&1073741823;d=d+1|0;if((d|0)==9)break;else f=C}return}function Qa(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0;h=i;i=i+48|0;g=h;d=0;e=8;f=0;while(1){k=c[a+(e<<2)>>2]|0;j=c[b+(e<<2)>>2]|0;d=k>>>0>>0|d<<1;f=k>>>0>j>>>0|f<<1;if((e|0)<=0)break;else e=e+-1|0}f=d>>>0>f>>>0;e=0;d=1;while(1){d=d+1073741823+(c[a+(e<<2)>>2]|0)-(c[b+(e<<2)>>2]|0)|0;c[g+(e<<2)>>2]=d&1073741823;e=e+1|0;if((e|0)==9)break;else d=d>>>30}La(a,f&1,a,g);i=h;return}function Ra(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0;f=0;e=1;while(1){e=e+1073741823+(c[a+(f<<2)>>2]|0)-(c[b+(f<<2)>>2]|0)|0;c[d+(f<<2)>>2]=e&1073741823;f=f+1|0;if((f|0)==9)break;else e=e>>>30}return}function Sa(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0,j=0;h=0;g=0;e=0;i=1;while(1){f=0;do{j=mc(c[b+(h-f<<2)>>2]|0,0,c[a+(f<<2)>>2]|0,0)|0;g=nc(j|0,C|0,g|0,e|0)|0;e=C;f=f+1|0}while((f|0)!=(i|0));c[d+(h<<2)>>2]=g&1073741823;g=jc(g|0,e|0,30)|0;e=C;h=h+1|0;if((h|0)==9){h=9;break}else i=i+1|0}while(1){f=h+-8|0;if((f|0)<9)do{j=mc(c[b+(h-f<<2)>>2]|0,0,c[a+(f<<2)>>2]|0,0)|0;g=nc(j|0,C|0,g|0,e|0)|0;e=C;f=f+1|0}while((f|0)!=9);c[d+(h<<2)>>2]=g&1073741823;g=jc(g|0,e|0,30)|0;h=h+1|0;if((h|0)==17)break;else e=C}c[d+68>>2]=g;return}function Ta(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0;l=a+(d+1<<2)|0;j=(c[l>>2]<<14)+((c[a+(d<<2)>>2]|0)>>>16)|0;k=d+-8|0;e=a+(k<<2)|0;f=c[e>>2]|0;g=mc(c[b>>2]|0,0,j|0,0)|0;h=C;if((j|0)<=-1)pa(38243,38223,390,38262);i=hc(f|0,536870912,g|0,h|0)|0;m=C;h=hc(f|0,0,g|0,h|0)|0;c[e>>2]=h&1073741823;h=jc(i|0,m|0,30)|0;m=C;i=a+(d+-7<<2)|0;f=nc(c[i>>2]|0,0,-2147483648,536870911)|0;e=1;g=C;d=m;do{m=mc(c[b+(e<<2)>>2]|0,0,j|0,0)|0;m=hc(f|0,g|0,m|0,C|0)|0;m=nc(m|0,C|0,h|0,d|0)|0;c[i>>2]=m&1073741823;e=e+1|0;h=jc(m|0,C|0,30)|0;d=C;i=a+(e+k<<2)|0;f=nc(c[i>>2]|0,0,-2147483648,536870911)|0;g=C}while((e|0)!=9);m=nc(f|0,g|0,h|0,d|0)|0;c[l>>2]=m&1073741823;return}function Ua(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0;e=16;while(1){Ta(b,d,e);if(c[b+(e+1<<2)>>2]|0){g=4;break}e=e+-1|0;if((e|0)<=7){f=0;break}}if((g|0)==4)pa(38286,38223,424,38302);do{c[a+(f<<2)>>2]=c[b+(f<<2)>>2];f=f+1|0}while((f|0)!=9);return}function Va(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0;g=i;i=i+80|0;e=g;f=e;h=f+72|0;do{c[f>>2]=0;f=f+4|0}while((f|0)<(h|0));Sa(a,b,e);Ua(b,e,d);i=g;return}function Wa(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0;n=i;i=i+144|0;k=n+72|0;l=n+36|0;m=n;c[l>>2]=1;h=l+4|0;c[h>>2]=0;c[h+4>>2]=0;c[h+8>>2]=0;c[h+12>>2]=0;c[h+16>>2]=0;c[h+20>>2]=0;c[h+24>>2]=0;c[h+28>>2]=0;h=m;d=b;j=h+36|0;do{c[h>>2]=c[d>>2];h=h+4|0;d=d+4|0}while((h|0)<(j|0));e=0;d=1;while(1){j=m+(e<<2)|0;d=(c[j>>2]|0)+d|0;c[j>>2]=d&1073741823;e=e+1|0;if((e|0)==9)break;else d=d>>>30}d=0;e=c[m>>2]|0;do{j=d;d=d+1|0;h=e;e=c[m+(d<<2)>>2]|0;c[m+(j<<2)>>2]=e<<29&536870912|h>>>1}while((d|0)!=8);e=m+32|0;c[e>>2]=(c[e>>2]|0)>>>1;d=0;f=c[m>>2]|0;do{j=d;d=d+1|0;h=f;f=c[m+(d<<2)>>2]|0;c[m+(j<<2)>>2]=f<<29&536870912|h>>>1}while((d|0)!=8);c[e>>2]=(c[e>>2]|0)>>>1;e=0;do{g=(e|0)==8;d=0;f=c[m+(e<<2)>>2]|0;do{if(g&(f|0)==0)break;if(f&1|0){h=k;j=h+72|0;do{c[h>>2]=0;h=h+4|0}while((h|0)<(j|0));Sa(a,l,k);Ua(l,k,b)}f=f>>>1;h=k;j=h+72|0;do{c[h>>2]=0;h=h+4|0}while((h|0)<(j|0));Sa(a,a,k);Ua(a,k,b);d=d+1|0}while(d>>>0<30);e=e+1|0}while((e|0)!=9);Qa(l,b);h=a;d=l;j=h+36|0;do{c[h>>2]=c[d>>2];h=h+4|0;d=d+4|0}while((h|0)<(j|0));i=n;return}function Xa(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0;v=i;i=i+112|0;d=v+72|0;u=v+32|0;t=v;Pa(a,b);Qa(a,b);e=c[b>>2]|0;f=0;while(1){r=f;f=f+1|0;g=c[b+(f<<2)>>2]|0;h=r<<1;p=g<<30-h|e;c[t+(r<<2)>>2]=p;c[d+(r<<2)>>2]=p;if((f|0)==8)break;else e=g>>>(h+2|0)}e=c[a>>2]|0;f=0;while(1){r=f;f=f+1|0;b=c[a+(f<<2)>>2]|0;g=r<<1;c[u+(r<<2)>>2]=b<<30-g|e;if((f|0)==8)break;else e=b>>>(g+2|0)}o=d+36|0;c[o>>2]=8;p=u+36|0;c[p>>2]=8;r=d+32|0;c[r>>2]=1;c[u+32>>2]=0;f=0;n=u;e=8;g=c[d>>2]|0;b=1;a:while(1){if(!(g&1)){q=7;break}if(!(b&1)){q=10;break}l=n+36|0;b=e;while(1){e=b+-1|0;if(c[n+(e<<2)>>2]|0)break;c[l>>2]=e;if((b|0)<1)break a;else b=e}e=c[n>>2]|0;if(!e){g=n+32|0;do{e=0;do{m=e;e=e+1|0;c[n+(m<<2)>>2]=c[n+(e<<2)>>2]}while((e|0)!=8);c[g>>2]=0;b=(c[l>>2]|0)+-1|0;c[l>>2]=b;f=f+32|0;e=c[n>>2]|0}while((e|0)==0)}k=0;while(1)if(!(e&1<0){e=e>>>k;if((b|0)>1){j=32-k|0;g=1;h=n;while(1){b=n+(g<<2)|0;c[h>>2]=c[b>>2]<>2]|0)>>>k;if((e|0)<(c[l>>2]|0)){g=e;e=h;h=b}else break}}else{g=0;h=e;b=n;e=1}c[b>>2]=h;if(!h)c[l>>2]=(c[l>>2]|0)+-1;else g=e;e=n+(g<<2)|0;b=c[e>>2]<>2]=(c[e>>2]|0)>>>h|b;b=c[e>>2]<>2]=b;m=k+f|0}else m=f;if(!(c[n>>2]&1)){q=32;break}if(c[n+32>>2]&1|0){q=34;break}f=c[o>>2]|0;e=f-(c[p>>2]|0)|0;if(!e){e=f;while(1){b=e+-1|0;if((e|0)<=0){q=38;break}e=c[d+(b<<2)>>2]|0;f=u+(b<<2)|0;if((e|0)==(c[f>>2]|0))e=b;else break}if((q|0)==38){q=0;if(!e){q=56;break}f=u+(b<<2)|0;e=c[d+(b<<2)>>2]|0}e=e>>>0>(c[f>>2]|0)>>>0?1:-1}n=(e|0)>0;l=n?u:d;n=n?d:u;k=l+36|0;h=c[k>>2]|0;if((h|0)>0){e=0;f=1;b=0;while(1){j=n+(e<<2)|0;w=c[j>>2]|0;g=c[l+(e<<2)>>2]|0;f=nc(f|0,b|0,-1,0)|0;f=nc(f|0,C|0,w|0,0)|0;g=hc(f|0,C|0,g|0,0)|0;f=C;c[j>>2]=g;e=e+1|0;if((e|0)<(h|0))b=0;else{b=e;g=0;break}}}else{b=0;f=1;g=0}j=n+36|0;e=c[j>>2]|0;if((b|0)<(e|0)){e=g;while(1){w=n+(b<<2)|0;g=c[w>>2]|0;e=nc(f|0,e|0,-1,0)|0;e=nc(e|0,C|0,g|0,0)|0;c[w>>2]=e;b=b+1|0;e=c[j>>2]|0;if((b|0)>=(e|0))break;else{f=C;e=0}}}if((e|0)>8){f=8;g=0;b=0}else{f=8;g=0;b=0;while(1){w=l+(f<<2)|0;j=c[n+(f<<2)>>2]|0;h=nc(c[w>>2]|0,0,g|0,b|0)|0;j=nc(h|0,C|0,j|0,0)|0;g=C;c[w>>2]=j;w=f;f=f+-1|0;if((w|0)<=(e|0))break;else b=0}h=c[k>>2]|0;b=0}if((f|0)>=(h|0))while(1){w=l+(f<<2)|0;j=nc(c[w>>2]|0,0,g|0,b|0)|0;c[w>>2]=j;if((f|0)>(c[k>>2]|0)){f=f+-1|0;g=C;b=0}else break}g=c[l>>2]|0;if(!(g&1)){q=51;break}b=c[l+32>>2]|0;if(!(b&1)){q=53;break}if(c[n>>2]&1|0){q=55;break}else f=m}if((q|0)==7)pa(38321,38223,619,38335);else if((q|0)==10)pa(38346,38223,620,38335);else if((q|0)==32)pa(38360,38223,672,38335);else if((q|0)==34)pa(38375,38223,673,38335);else if((q|0)==51)pa(38321,38223,730,38335);else if((q|0)==53)pa(38346,38223,731,38335);else if((q|0)==55)pa(38397,38223,732,38335);else if((q|0)==56){l=c[t>>2]|0;if(!(l&1))pa(38419,38223,759,38335);f=l+-1|0;e=l+-2|0;if(!f)k=e;else{do{f=R(f,f)|0;e=R(f+1|0,e)|0}while((f|0)!=0);k=e}b:do if((m|0)>31){j=d+4|0;e=m;while(1){w=c[r>>2]|0;b=R(w,k)|0;q=mc(l|0,0,b|0,0)|0;w=nc(q|0,C|0,w|0,0)|0;if(!((w|0)==0&0==0))break;f=0;g=C;h=0;while(1){w=f;f=f+1|0;o=c[d+(7-w<<2)>>2]|0;p=mc(c[t+(f<<2)>>2]|0,0,b|0,0)|0;q=C;o=nc(o|0,0,g|0,h|0)|0;q=nc(o|0,C|0,p|0,q|0)|0;g=C;c[d+(8-w<<2)>>2]=q;if((f|0)==7)break;else h=0}c[j>>2]=g;e=e+-32|0;if((e|0)<=31){s=e;break b}}pa(38429,38223,775,38335)}else s=m;while(0);if((s|0)>0){w=(1<>2]|0;h=(R(e,k)|0)&w;if((R(h,l)|0)+e&w|0)pa(38454,38223,794,38335);b=mc(h|0,0,l|0,0)|0;b=nc(b|0,C|0,e|0,0)|0;b=jc(b|0,C|0,s|0)|0;f=32-s|0;e=0;g=C;while(1){w=e;e=e+1|0;s=c[d+(7-w<<2)>>2]|0;r=mc(c[t+(e<<2)>>2]|0,0,h|0,0)|0;s=nc(r|0,C|0,s|0,0)|0;s=kc(s|0,C|0,f|0)|0;s=nc(s|0,C|0,b|0,g|0)|0;b=C;c[d+(8-w<<2)>>2]=s;if((e|0)==7)break;else g=0}c[d+4>>2]=b;e=0;f=0}else{e=0;f=0}do{s=c[d+(8-e<<2)>>2]|0;w=e<<1;c[a+(e<<2)>>2]=s<>>(30-w|0);e=e+1|0}while((e|0)!=8);c[a+32>>2]=f;c[t>>2]=0;c[t+4>>2]=0;c[t+8>>2]=0;c[t+12>>2]=0;c[t+16>>2]=0;c[t+20>>2]=0;c[t+24>>2]=0;c[t+28>>2]=0;e=d+40|0;do{c[d>>2]=0;d=d+4|0}while((d|0)<(e|0));d=u;e=d+40|0;do{c[d>>2]=0;d=d+4|0}while((d|0)<(e|0))}i=v;return}function Ya(a,b){a=a|0;b=b|0;var d=0,e=0,f=0;e=0;d=0;while(1){f=a+(e<<2)|0;d=(c[f>>2]|0)+d+(c[b+(e<<2)>>2]|0)|0;c[f>>2]=d&1073741823;e=e+1|0;if((e|0)==9)break;else d=d>>>30}return}function Za(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0;e=0;do{f=a+(e<<2)|0;c[f>>2]=(c[f>>2]|0)+(c[b+(e<<2)>>2]|0);e=e+1|0}while((e|0)!=9);Pa(a,d);return}function _a(a,b,d){a=a|0;b=b|0;d=d|0;var e=0;if((c[d>>2]|0)>>>0>>0)pa(38495,38223,856,38514);b=(c[a>>2]|0)-b|0;c[a>>2]=b;b=b+(c[d>>2]|0)|0;c[a>>2]=b&1073741823;e=1;do{b=(c[a+(e<<2)>>2]|0)+(b>>>30)+(c[d+(e<<2)>>2]|0)|0;c[a+(e<<2)>>2]=b&1073741823;e=e+1|0}while((e|0)!=9);return}function $a(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0;g=0;f=1;while(1){f=f+1073741823+(c[a+(g<<2)>>2]|0)+(c[e+(g<<2)>>2]<<1)-(c[b+(g<<2)>>2]|0)|0;c[d+(g<<2)>>2]=f&1073741823;g=g+1|0;if((g|0)==9)break;else f=f>>>30}return}function ab(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0;n=i;i=i+144|0;k=n+108|0;e=n+72|0;l=n+36|0;m=n;do if(!(bb(b)|0)){if(bb(d)|0){e=d;f=b;g=e+72|0;do{c[e>>2]=c[f>>2];e=e+4|0;f=f+4|0}while((e|0)<(g|0));break}if(cb(b,d)|0){db(a,d);break}if(!(eb(b,d)|0)){$a(d,b,e,a);Xa(e,a);h=d+36|0;j=b+36|0;$a(h,j,k,a);Va(e,k,a);e=l;f=k;g=e+36|0;do{c[e>>2]=c[f>>2];e=e+4|0;f=f+4|0}while((e|0)<(g|0));Va(l,l,a);e=m;f=b;g=e+36|0;do{c[e>>2]=c[f>>2];e=e+4|0;f=f+4|0}while((e|0)<(g|0));Za(m,d,a);$a(l,m,l,a);Pa(l,a);Qa(l,a);$a(b,l,m,a);Va(k,m,a);$a(m,j,m,a);Pa(m,a);Qa(m,a);e=d;f=l;g=e+36|0;do{c[e>>2]=c[f>>2];e=e+4|0;f=f+4|0}while((e|0)<(g|0));e=h;f=m;g=e+36|0;do{c[e>>2]=c[f>>2];e=e+4|0;f=f+4|0}while((e|0)<(g|0));break}else{Ha(d);Ha(d+36|0);break}}while(0);i=n;return}function bb(a){a=a|0;if(!(Ia(a)|0))a=0;else a=(Ia(a+36|0)|0)!=0;return a&1|0}function cb(a,b){a=a|0;b=b|0;if(!(Ka(a,b)|0))a=0;else a=(Ka(a+36|0,b+36|0)|0)!=0;return a&1|0}function db(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0,l=0;j=i;i=i+112|0;d=j+72|0;e=j+36|0;f=j;do if(!(bb(b)|0)){g=b+36|0;if(!(Ia(g)|0)){h=d;k=g;l=h+36|0;do{c[h>>2]=c[k>>2];h=h+4|0;k=k+4|0}while((h|0)<(l|0));Oa(d,2,a);Xa(d,a);h=e;k=b;l=h+36|0;do{c[h>>2]=c[k>>2];h=h+4|0;k=k+4|0}while((h|0)<(l|0));Va(e,e,a);Oa(e,3,a);_a(e,0-(c[a+180>>2]|0)|0,a);Va(e,d,a);h=e;k=d;l=h+36|0;do{c[h>>2]=c[k>>2];h=h+4|0;k=k+4|0}while((h|0)<(l|0));Va(e,e,a);h=f;k=b;l=h+36|0;do{c[h>>2]=c[k>>2];h=h+4|0;k=k+4|0}while((h|0)<(l|0));Ma(f);$a(e,f,e,a);Pa(e,a);Qa(e,a);$a(b,e,f,a);Va(d,f,a);$a(f,g,f,a);Pa(f,a);Qa(f,a);h=b;k=e;l=h+36|0;do{c[h>>2]=c[k>>2];h=h+4|0;k=k+4|0}while((h|0)<(l|0));h=g;k=f;l=h+36|0;do{c[h>>2]=c[k>>2];h=h+4|0;k=k+4|0}while((h|0)<(l|0));break}else{Ha(b);Ha(g);break}}while(0);i=j;return}function eb(a,b){a=a|0;b=b|0;var c=0;if((Ka(a,b)|0)!=0?(c=a+36|0,(Ia(c)|0)==0):0)a=(Ka(c,b+36|0)|0)==0&1;else a=0;return a|0}function fb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0,j=0;g=b+32|0;if((c[g>>2]|0)>>>0>=131072)pa(38522,38542,179,38553);h=a&1073741823;f=~a;a=c[b>>2]|0;e=(c[d>>2]<<1)+1073741824-a|0;c[b>>2]=h&e|a&f;a=0;do{a=a+1|0;i=b+(a<<2)|0;j=c[i>>2]|0;e=(e>>>30)+1073741823+(c[d+(a<<2)>>2]<<1)-j|0;c[i>>2]=h&e|j&f}while((a|0)!=8);if((c[g>>2]|0)>>>0<131072)return;else pa(38522,38542,187,38553)}function gb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0;e=0;f=Jb()|0;do{c[b+72+(e<<2)>>2]=f&1073741823;e=e+1|0;f=Jb()|0}while((e|0)!=8);i=b+72|0;c[b+104>>2]=(f&32767)+1;f=b;g=i;h=f+36|0;do{c[f>>2]=c[g>>2];f=f+4|0;g=g+4|0}while((f|0)<(h|0));Va(i,b,d);e=b+36|0;f=e;g=b;h=f+36|0;do{c[f>>2]=c[g>>2];f=f+4|0;g=g+4|0}while((f|0)<(h|0));Va(i,e,d);Va(a,b,d);Va(a+36|0,e,d);return}function hb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0;e=b+36|0;f=e;g=a+72|0;h=f+36|0;do{c[f>>2]=c[g>>2];f=f+4|0;g=g+4|0}while((f|0)<(h|0));Xa(e,d);f=b;g=e;h=f+36|0;do{c[f>>2]=c[g>>2];f=f+4|0;g=g+4|0}while((f|0)<(h|0));Va(b,b,d);Va(b,e,d);Va(a,b,d);Va(a+36|0,e,d);Qa(b,d);Qa(e,d);return}function ib(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0;s=i;i=i+288|0;k=s+252|0;l=s+216|0;m=s+180|0;n=s+144|0;o=s+108|0;p=s+72|0;q=s+36|0;g=s;e=c[d+180>>2]|0;if((e+3|0)>>>0>=4)pa(38572,38542,238,38590);h=b+72|0;r=p;t=h;u=r+36|0;do{c[r>>2]=c[t>>2];r=r+4|0;t=t+4|0}while((r|0)<(u|0));Va(p,p,d);r=q;t=h;u=r+36|0;do{c[r>>2]=c[t>>2];r=r+4|0;t=t+4|0}while((r|0)<(u|0));Va(p,q,d);j=(e|0)!=0;if(j){e=0-e|0;r=g;t=p;u=r+36|0;do{c[r>>2]=c[t>>2];r=r+4|0;t=t+4|0}while((r|0)<(u|0));Va(g,g,d);Oa(g,e&255,d)}Va(a,p,d);r=l;t=p;u=r+36|0;do{c[r>>2]=c[t>>2];r=r+4|0;t=t+4|0}while((r|0)<(u|0));$a(l,b,l,d);Pa(l,d);Ya(p,b);f=Ka(l,d)|0;Va(a+36|0,q,d);e=b+36|0;$a(q,e,k,d);Ya(q,e);r=m;t=b;u=r+36|0;do{c[r>>2]=c[t>>2];r=r+4|0;t=t+4|0}while((r|0)<(u|0));Va(m,m,d);Oa(m,3,d);if(j)$a(m,g,m,d);La(k,f,m,k);La(l,f,q,l);r=o;t=l;u=r+36|0;do{c[r>>2]=c[t>>2];r=r+4|0;t=t+4|0}while((r|0)<(u|0));Va(o,o,d);r=n;t=l;u=r+36|0;do{c[r>>2]=c[t>>2];r=r+4|0;t=t+4|0}while((r|0)<(u|0));Va(o,n,d);Va(p,o,d);Va(q,n,d);Va(l,h,d);r=b;t=k;u=r+36|0;do{c[r>>2]=c[t>>2];r=r+4|0;t=t+4|0}while((r|0)<(u|0));Va(b,b,d);$a(b,o,b,d);Pa(b,d);$a(o,b,e,d);$a(e,b,e,d);Va(k,e,d);$a(e,n,e,d);Na(e,d);Pa(e,d);i=s;return}function jb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0;n=i;i=i+144|0;l=n+108|0;m=n;if(!(Ja(b,a+108|0)|0))pa(38609,38542,543,38658);j=c[b>>2]|0;g=(j&1)+-1|0;f=1;e=0;h=j;do{k=f+1073741823+h-(c[a+108+(e<<2)>>2]&g)|0;c[l+(e<<2)>>2]=k&1073741823;f=k>>>30;e=e+1|0;h=c[b+(e<<2)>>2]|0;j=h|j}while((e|0)!=8);k=l+32|0;c[k>>2]=f+65535+h-(c[a+140>>2]&g);e=c[l>>2]|0;if(!(e&1))pa(38638,38542,566,38658);if(!j){Ha(d);Ha(d+36|0)}else{gb(a+220+((((e>>>4&1)+15^e)>>>1&7)*72|0)|0,m,a);h=m+36|0;g=1;do{f=0;e=e>>>4;b=l;do{f=f+1|0;j=b;b=l+(f<<2)|0;c[j>>2]=c[b>>2]<<26&1006632960|e;e=(c[b>>2]|0)>>>4}while((f|0)!=8);c[k>>2]=e;e=c[l>>2]|0;b=e>>>4&1;j=b+15^e;fb((j&1)+-1|0,h,a);ib(a+220+(g*576|0)+((j>>>1&7)*72|0)|0,m,a);g=g+1|0}while((g|0)!=64);fb(b+-1|0,h,a);hb(m,d,a)}i=n;return}function kb(b,c,d){b=b|0;c=c|0;d=d|0;b=(b|0)==0?712:b;switch(a[c>>0]|0){case 4:{Fa(c+1|0,d);Fa(c+33|0,d+36|0);b=lb(b,d)|0;break}case 3:case 2:{Fa(c+1|0,d);mb(b,a[c>>0]|0,d,d+36|0);b=lb(b,d)|0;break}default:b=0}return b|0}function lb(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0;k=i;i=i+80|0;d=k+36|0;e=k;if(((bb(b)|0)==0?(Ja(b,a)|0)!=0:0)?(f=b+36|0,(Ja(f,a)|0)!=0):0){g=d;h=f;j=g+36|0;do{c[g>>2]=c[h>>2];g=g+4|0;h=h+4|0}while((g|0)<(j|0));g=e;h=b;j=g+36|0;do{c[g>>2]=c[h>>2];g=g+4|0;h=h+4|0}while((g|0)<(j|0));Va(f,d,a);Qa(d,a);Va(b,e,a);_a(e,0-(c[a+180>>2]|0)|0,a);Va(b,e,a);Za(e,a+184|0,a);Qa(e,a);a=(Ka(e,d)|0)!=0&1}else a=0;i=k;return a|0}function mb(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0;f=e;g=d;h=f+36|0;do{c[f>>2]=c[g>>2];f=f+4|0;g=g+4|0}while((f|0)<(h|0));Va(d,e,a);_a(e,0-(c[a+180>>2]|0)|0,a);Va(d,e,a);Ya(e,a+184|0);Wa(e,a);if((c[e>>2]^b&255)&1|0)Ra(a,e,e);return}function nb(b,c){b=b|0;c=c|0;var d=0,e=0;e=i;i=i+32|0;d=e;switch(a[b>>0]|0){case 4:{Db(b,65,d);break}case 0:{Db(b,1,d);break}default:Db(b,33,d)}zb(d,32,c);i=e;return}function ob(b,c,d){b=b|0;c=c|0;d=d|0;do if(c>>>0>=256){if(c>>>0<65536){a[d>>0]=c>>>8;a[d+1>>0]=c;nb(b,d+2|0);break}if(c>>>0<16777216){a[d>>0]=c>>>16;a[d+1>>0]=c>>>8;a[d+2>>0]=c;nb(b,d+3|0);break}else{a[d>>0]=c>>>24;a[d+1>>0]=c>>>16;a[d+2>>0]=c>>>8;a[d+3>>0]=c;nb(b,d+4|0);break}}else{a[d>>0]=c;nb(b,d+1|0)}while(0);return}function pb(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0,f=0;f=i;i=i+32|0;e=f;ob(a,b,e);do if(b>>>0>=256){if(b>>>0<65536){vb(e,22,c,d)|0;break}if(b>>>0<16777216){vb(e,23,c,d)|0;break}else{vb(e,24,c,d)|0;break}}else vb(e,21,c,d)|0;while(0);i=f;return}function qb(b,c,e){b=b|0;c=c|0;e=e|0;var f=0,g=0,h=0,j=0;j=i;i=i+128|0;h=j;f=h;g=f+128|0;do{a[f>>0]=0;f=f+1|0}while((f|0)<(g|0));if(e>>>0>128){Ib(c,e,h);c=0}else{qc(h|0,c|0,e|0)|0;c=0}do{g=h+c|0;f=d[g>>0]|0;a[b+c>>0]=f^92;a[g>>0]=f^54;c=c+1|0}while((c|0)!=128);b=b+128|0;Eb(b);Gb(b,h,128);i=j;return}function rb(a,b){a=a|0;b=b|0;var c=0,d=0,e=0;c=i;i=i+64|0;e=c;d=a+128|0;Hb(d,e);Eb(d);Gb(d,a,128);Gb(d,e,64);Hb(d,b);ic(a|0,0,336)|0;i=c;return}function sb(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;var f=0,g=0;f=i;i=i+336|0;g=f;qb(g,a,b);Gb(g+128|0,c,d);rb(g,e);i=f;return}function tb(b,d,e,f,g,h,j){b=b|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;j=j|0;var k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0;s=i;i=i+256|0;o=s+216|0;p=s+152|0;q=s+112|0;m=s+40|0;n=s;if((f|0)<0)d=0;else{r=o;l=r+33|0;do{a[r>>0]=a[d>>0]|0;r=r+1|0;d=d+1|0}while((r|0)<(l|0));Ea(o+33|0,f);f=o+1|0;k=p+32|0;while(1){sb(e,32,o,37,p);Fa(p,n);if(Ja(n,820)|0?(jb(712,n,m),ab(712,b,m),(bb(m)|0)==0):0)break;a[o>>0]=1;r=f;d=k;l=r+32|0;do{a[r>>0]=a[d>>0]|0;r=r+1|0;d=d+1|0}while((r|0)<(l|0))}a[q>>0]=c[m+36>>2]&1|2;Ga(m,q+1|0);pb(q,g,h,j);d=1}i=s;return d|0}function ub(b,e,f,g){b=b|0;e=e|0;f=f|0;g=g|0;var h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0;q=i;a:do if((g|0)>0){h=0;do{if(a[f+h>>0]|0)break a;h=h+1|0}while((h|0)<(g|0))}else h=0;while(0);o=(((g-h|0)*138|0)>>>0)/100|0;n=o+1|0;p=i;i=i+((1*n|0)+15&-16)|0;ic(p|0,0,n|0)|0;if((h|0)<(g|0)){j=o;m=h;do{k=a[f+m>>0]|0;if((o|0)>(j|0)|k<<24>>24!=0){k=k&255;l=o;while(1){r=p+l|0;k=(d[r>>0]<<8)+k|0;a[r>>0]=(k|0)%58|0;l=l+-1|0;if((l|0)>(j|0)|(k+57|0)>>>0>114)k=(k|0)/58|0;else{j=l;break}}}else j=o;m=m+1|0}while((m|0)!=(g|0));j=0}else j=0;while(1){if(a[p+j>>0]|0)break;k=j+1|0;if((j|0)<(o|0))j=k;else{j=k;break}}k=n+h-j|0;if((c[e>>2]|0)>>>0>k>>>0){if(!h)h=0;else ic(b|0,49,h|0)|0;if((j|0)<=(o|0))while(1){a[b+h>>0]=a[38674+(d[p+j>>0]|0)>>0]|0;h=h+1|0;if((j|0)<(o|0))j=j+1|0;else break}a[b+h>>0]=0;j=1}else{j=0;h=k}c[e>>2]=h+1;i=q;return j|0}function vb(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,j=0,k=0,l=0;g=i;i=i+16|0;f=g;if((b|0)>128)a=0;else{j=b+32|0;h=ia()|0;k=i;i=i+((1*j|0)+15&-16)|0;l=k+b|0;qc(k|0,a|0,b|0)|0;Db(a,b,l);Db(l,32,l);c[f>>2]=e;a=ub(d,f,k,b+4|0)|0;ic(k|0,0,j|0)|0;a=a?c[f>>2]|0:0;oa(h|0)}i=g;return a|0}function wb(a,b){a=a|0;b=b|0;var e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0;s=(d[b+1>>0]|0)<<8|(d[b>>0]|0)|(d[b+2>>0]|0)<<16|(d[b+3>>0]|0)<<24;D=(d[b+5>>0]|0)<<8|(d[b+4>>0]|0)|(d[b+6>>0]|0)<<16|(d[b+7>>0]|0)<<24;v=(d[b+9>>0]|0)<<8|(d[b+8>>0]|0)|(d[b+10>>0]|0)<<16|(d[b+11>>0]|0)<<24;f=(d[b+13>>0]|0)<<8|(d[b+12>>0]|0)|(d[b+14>>0]|0)<<16|(d[b+15>>0]|0)<<24;x=(d[b+17>>0]|0)<<8|(d[b+16>>0]|0)|(d[b+18>>0]|0)<<16|(d[b+19>>0]|0)<<24;t=(d[b+21>>0]|0)<<8|(d[b+20>>0]|0)|(d[b+22>>0]|0)<<16|(d[b+23>>0]|0)<<24;y=(d[b+25>>0]|0)<<8|(d[b+24>>0]|0)|(d[b+26>>0]|0)<<16|(d[b+27>>0]|0)<<24;z=(d[b+29>>0]|0)<<8|(d[b+28>>0]|0)|(d[b+30>>0]|0)<<16|(d[b+31>>0]|0)<<24;B=(d[b+33>>0]|0)<<8|(d[b+32>>0]|0)|(d[b+34>>0]|0)<<16|(d[b+35>>0]|0)<<24;i=(d[b+37>>0]|0)<<8|(d[b+36>>0]|0)|(d[b+38>>0]|0)<<16|(d[b+39>>0]|0)<<24;F=(d[b+41>>0]|0)<<8|(d[b+40>>0]|0)|(d[b+42>>0]|0)<<16|(d[b+43>>0]|0)<<24;l=(d[b+45>>0]|0)<<8|(d[b+44>>0]|0)|(d[b+46>>0]|0)<<16|(d[b+47>>0]|0)<<24;H=(d[b+49>>0]|0)<<8|(d[b+48>>0]|0)|(d[b+50>>0]|0)<<16|(d[b+51>>0]|0)<<24;u=(d[b+53>>0]|0)<<8|(d[b+52>>0]|0)|(d[b+54>>0]|0)<<16|(d[b+55>>0]|0)<<24;m=(d[b+57>>0]|0)<<8|(d[b+56>>0]|0)|(d[b+58>>0]|0)<<16|(d[b+59>>0]|0)<<24;w=(d[b+61>>0]|0)<<8|(d[b+60>>0]|0)|(d[b+62>>0]|0)<<16|(d[b+63>>0]|0)<<24;b=a+8|0;A=c[b>>2]|0;p=a+12|0;e=c[p>>2]|0;n=a+16|0;r=c[n>>2]|0;k=a+20|0;I=c[k>>2]|0;g=a+24|0;E=c[g>>2]|0;j=A+s+(r^e^I)|0;j=(j<<11|j>>>21)+E|0;C=r<<10|r>>>22;A=t+1352829926+A+((r|~I)^e)|0;A=(A<<8|A>>>24)+E|0;o=E+D+(C^e^j)|0;o=(o<<14|o>>>18)+I|0;G=e<<10|e>>>22;E=m+1352829926+E+(A^(e|~C))|0;E=(E<<9|E>>>23)+I|0;J=I+v+(j^G^o)|0;J=(J<<15|J>>>17)+C|0;j=j<<10|j>>>22;I=z+1352829926+I+(E^(A|~G))|0;I=(I<<9|I>>>23)+C|0;A=A<<10|A>>>22;a=C+f+(o^j^J)|0;a=(a<<12|a>>>20)+G|0;o=o<<10|o>>>22;C=s+1352829926+C+(I^(E|~A))|0;C=(C<<11|C>>>21)+G|0;E=E<<10|E>>>22;h=G+x+(J^o^a)|0;h=(h<<5|h>>>27)+j|0;J=J<<10|J>>>22;G=i+1352829926+G+(C^(I|~E))|0;G=(G<<13|G>>>19)+A|0;I=I<<10|I>>>22;j=j+t+(a^J^h)|0;j=(j<<8|j>>>24)+o|0;a=a<<10|a>>>22;A=v+1352829926+A+(G^(C|~I))|0;A=(A<<15|A>>>17)+E|0;C=C<<10|C>>>22;o=o+y+(h^a^j)|0;o=(o<<7|o>>>25)+J|0;h=h<<10|h>>>22;E=l+1352829926+E+(A^(G|~C))|0;E=(E<<15|E>>>17)+I|0;G=G<<10|G>>>22;J=J+z+(j^h^o)|0;J=(J<<9|J>>>23)+a|0;j=j<<10|j>>>22;I=x+1352829926+I+(E^(A|~G))|0;I=(I<<5|I>>>27)+C|0;A=A<<10|A>>>22;a=a+B+(o^j^J)|0;a=(a<<11|a>>>21)+h|0;o=o<<10|o>>>22;C=u+1352829926+C+(I^(E|~A))|0;C=(C<<7|C>>>25)+G|0;E=E<<10|E>>>22;h=h+i+(J^o^a)|0;h=(h<<13|h>>>19)+j|0;J=J<<10|J>>>22;G=y+1352829926+G+(C^(I|~E))|0;G=(G<<7|G>>>25)+A|0;I=I<<10|I>>>22;j=j+F+(a^J^h)|0;j=(j<<14|j>>>18)+o|0;a=a<<10|a>>>22;A=w+1352829926+A+(G^(C|~I))|0;A=(A<<8|A>>>24)+E|0;C=C<<10|C>>>22;o=o+l+(h^a^j)|0;o=(o<<15|o>>>17)+J|0;h=h<<10|h>>>22;E=B+1352829926+E+(A^(G|~C))|0;E=(E<<11|E>>>21)+I|0;G=G<<10|G>>>22;J=J+H+(j^h^o)|0;J=(J<<6|J>>>26)+a|0;j=j<<10|j>>>22;I=D+1352829926+I+(E^(A|~G))|0;I=(I<<14|I>>>18)+C|0;A=A<<10|A>>>22;a=a+u+(o^j^J)|0;a=(a<<7|a>>>25)+h|0;o=o<<10|o>>>22;C=F+1352829926+C+(I^(E|~A))|0;C=(C<<14|C>>>18)+G|0;E=E<<10|E>>>22;h=h+m+(J^o^a)|0;h=(h<<9|h>>>23)+j|0;J=J<<10|J>>>22;G=f+1352829926+G+(C^(I|~E))|0;G=(G<<12|G>>>20)+A|0;I=I<<10|I>>>22;j=j+w+(a^J^h)|0;j=(j<<8|j>>>24)+o|0;a=a<<10|a>>>22;A=H+1352829926+A+(G^(C|~I))|0;A=(A<<6|A>>>26)+E|0;C=C<<10|C>>>22;o=z+1518500249+o+(j&h|a&~j)|0;o=(o<<7|o>>>25)+J|0;h=h<<10|h>>>22;E=y+1548603684+E+(A&C|G&~C)|0;E=(E<<9|E>>>23)+I|0;G=G<<10|G>>>22;J=x+1518500249+J+(o&j|h&~o)|0;J=(J<<6|J>>>26)+a|0;j=j<<10|j>>>22;I=l+1548603684+I+(E&G|A&~G)|0;I=(I<<13|I>>>19)+C|0;A=A<<10|A>>>22;a=u+1518500249+a+(J&o|j&~J)|0;a=(a<<8|a>>>24)+h|0;o=o<<10|o>>>22;C=f+1548603684+C+(I&A|E&~A)|0;C=(C<<15|C>>>17)+G|0;E=E<<10|E>>>22;h=D+1518500249+h+(a&J|o&~a)|0;h=(h<<13|h>>>19)+j|0;J=J<<10|J>>>22;G=z+1548603684+G+(C&E|I&~E)|0;G=(G<<7|G>>>25)+A|0;I=I<<10|I>>>22;j=F+1518500249+j+(h&a|J&~h)|0;j=(j<<11|j>>>21)+o|0;a=a<<10|a>>>22;A=s+1548603684+A+(G&I|C&~I)|0;A=(A<<12|A>>>20)+E|0;C=C<<10|C>>>22;o=y+1518500249+o+(j&h|a&~j)|0;o=(o<<9|o>>>23)+J|0;h=h<<10|h>>>22;E=u+1548603684+E+(A&C|G&~C)|0;E=(E<<8|E>>>24)+I|0;G=G<<10|G>>>22;J=w+1518500249+J+(o&j|h&~o)|0;J=(J<<7|J>>>25)+a|0;j=j<<10|j>>>22;I=t+1548603684+I+(E&G|A&~G)|0;I=(I<<9|I>>>23)+C|0;A=A<<10|A>>>22;a=f+1518500249+a+(J&o|j&~J)|0;a=(a<<15|a>>>17)+h|0;o=o<<10|o>>>22;C=F+1548603684+C+(I&A|E&~A)|0;C=(C<<11|C>>>21)+G|0;E=E<<10|E>>>22;h=H+1518500249+h+(a&J|o&~a)|0;h=(h<<7|h>>>25)+j|0;J=J<<10|J>>>22;G=m+1548603684+G+(C&E|I&~E)|0;G=(G<<7|G>>>25)+A|0;I=I<<10|I>>>22;j=s+1518500249+j+(h&a|J&~h)|0;j=(j<<12|j>>>20)+o|0;a=a<<10|a>>>22;A=w+1548603684+A+(G&I|C&~I)|0;A=(A<<7|A>>>25)+E|0;C=C<<10|C>>>22;o=i+1518500249+o+(j&h|a&~j)|0;o=(o<<15|o>>>17)+J|0;h=h<<10|h>>>22;E=B+1548603684+E+(A&C|G&~C)|0;E=(E<<12|E>>>20)+I|0;G=G<<10|G>>>22;J=t+1518500249+J+(o&j|h&~o)|0;J=(J<<9|J>>>23)+a|0;j=j<<10|j>>>22;I=H+1548603684+I+(E&G|A&~G)|0;I=(I<<7|I>>>25)+C|0;A=A<<10|A>>>22;a=v+1518500249+a+(J&o|j&~J)|0;a=(a<<11|a>>>21)+h|0;o=o<<10|o>>>22;C=x+1548603684+C+(I&A|E&~A)|0;C=(C<<6|C>>>26)+G|0;E=E<<10|E>>>22;h=m+1518500249+h+(a&J|o&~a)|0;h=(h<<7|h>>>25)+j|0;J=J<<10|J>>>22;G=i+1548603684+G+(C&E|I&~E)|0;G=(G<<15|G>>>17)+A|0;I=I<<10|I>>>22;j=l+1518500249+j+(h&a|J&~h)|0;j=(j<<13|j>>>19)+o|0;a=a<<10|a>>>22;A=D+1548603684+A+(G&I|C&~I)|0;A=(A<<13|A>>>19)+E|0;C=C<<10|C>>>22;q=~j;o=B+1518500249+o+(j&h|a&q)|0;o=(o<<12|o>>>20)+J|0;h=h<<10|h>>>22;E=v+1548603684+E+(A&C|G&~C)|0;E=(E<<11|E>>>21)+I|0;G=G<<10|G>>>22;q=f+1859775393+J+((o|q)^h)|0;q=(q<<11|q>>>21)+a|0;j=j<<10|j>>>22;I=w+1836072691+I+((E|~A)^G)|0;I=(I<<9|I>>>23)+C|0;A=A<<10|A>>>22;a=F+1859775393+a+((q|~o)^j)|0;a=(a<<13|a>>>19)+h|0;o=o<<10|o>>>22;C=t+1836072691+C+((I|~E)^A)|0;C=(C<<7|C>>>25)+G|0;E=E<<10|E>>>22;h=m+1859775393+h+((a|~q)^o)|0;h=(h<<6|h>>>26)+j|0;q=q<<10|q>>>22;G=D+1836072691+G+((C|~I)^E)|0;G=(G<<15|G>>>17)+A|0;I=I<<10|I>>>22;j=x+1859775393+j+((h|~a)^q)|0;j=(j<<7|j>>>25)+o|0;a=a<<10|a>>>22;A=f+1836072691+A+((G|~C)^I)|0;A=(A<<11|A>>>21)+E|0;C=C<<10|C>>>22;o=i+1859775393+o+((j|~h)^a)|0;o=(o<<14|o>>>18)+q|0;h=h<<10|h>>>22;E=z+1836072691+E+((A|~G)^C)|0;E=(E<<8|E>>>24)+I|0;G=G<<10|G>>>22;q=w+1859775393+q+((o|~j)^h)|0;q=(q<<9|q>>>23)+a|0;j=j<<10|j>>>22;I=m+1836072691+I+((E|~A)^G)|0;I=(I<<6|I>>>26)+C|0;A=A<<10|A>>>22;a=B+1859775393+a+((q|~o)^j)|0;a=(a<<13|a>>>19)+h|0;o=o<<10|o>>>22;C=y+1836072691+C+((I|~E)^A)|0;C=(C<<6|C>>>26)+G|0;E=E<<10|E>>>22;h=D+1859775393+h+((a|~q)^o)|0;h=(h<<15|h>>>17)+j|0;q=q<<10|q>>>22;G=i+1836072691+G+((C|~I)^E)|0;G=(G<<14|G>>>18)+A|0;I=I<<10|I>>>22;j=v+1859775393+j+((h|~a)^q)|0;j=(j<<14|j>>>18)+o|0;a=a<<10|a>>>22;A=l+1836072691+A+((G|~C)^I)|0;A=(A<<12|A>>>20)+E|0;C=C<<10|C>>>22;o=z+1859775393+o+((j|~h)^a)|0;o=(o<<8|o>>>24)+q|0;h=h<<10|h>>>22;E=B+1836072691+E+((A|~G)^C)|0;E=(E<<13|E>>>19)+I|0;G=G<<10|G>>>22;q=s+1859775393+q+((o|~j)^h)|0;q=(q<<13|q>>>19)+a|0;j=j<<10|j>>>22;I=H+1836072691+I+((E|~A)^G)|0;I=(I<<5|I>>>27)+C|0;A=A<<10|A>>>22;a=y+1859775393+a+((q|~o)^j)|0;a=(a<<6|a>>>26)+h|0;o=o<<10|o>>>22;C=v+1836072691+C+((I|~E)^A)|0;C=(C<<14|C>>>18)+G|0;E=E<<10|E>>>22;h=u+1859775393+h+((a|~q)^o)|0;h=(h<<5|h>>>27)+j|0;q=q<<10|q>>>22;G=F+1836072691+G+((C|~I)^E)|0;G=(G<<13|G>>>19)+A|0;I=I<<10|I>>>22;j=l+1859775393+j+((h|~a)^q)|0;j=(j<<12|j>>>20)+o|0;a=a<<10|a>>>22;A=s+1836072691+A+((G|~C)^I)|0;A=(A<<13|A>>>19)+E|0;C=C<<10|C>>>22;o=t+1859775393+o+((j|~h)^a)|0;o=(o<<7|o>>>25)+q|0;h=h<<10|h>>>22;E=x+1836072691+E+((A|~G)^C)|0;E=(E<<7|E>>>25)+I|0;G=G<<10|G>>>22;q=H+1859775393+q+((o|~j)^h)|0;q=(q<<5|q>>>27)+a|0;j=j<<10|j>>>22;I=u+1836072691+I+((E|~A)^G)|0;I=(I<<5|I>>>27)+C|0;A=A<<10|A>>>22;a=D+-1894007588+a+(q&j|o&~j)|0;a=(a<<11|a>>>21)+h|0;o=o<<10|o>>>22;C=B+2053994217+C+(I&E|A&~I)|0;C=(C<<15|C>>>17)+G|0;E=E<<10|E>>>22;h=i+-1894007588+h+(a&o|q&~o)|0;h=(h<<12|h>>>20)+j|0;q=q<<10|q>>>22;G=y+2053994217+G+(C&I|E&~C)|0;G=(G<<5|G>>>27)+A|0;I=I<<10|I>>>22;j=l+-1894007588+j+(h&q|a&~q)|0;j=(j<<14|j>>>18)+o|0;a=a<<10|a>>>22;A=x+2053994217+A+(G&C|I&~G)|0;A=(A<<8|A>>>24)+E|0;C=C<<10|C>>>22;o=F+-1894007588+o+(j&a|h&~a)|0;o=(o<<15|o>>>17)+q|0;h=h<<10|h>>>22;E=D+2053994217+E+(A&G|C&~A)|0;E=(E<<11|E>>>21)+I|0;G=G<<10|G>>>22;q=s+-1894007588+q+(o&h|j&~h)|0;q=(q<<14|q>>>18)+a|0;j=j<<10|j>>>22;I=f+2053994217+I+(E&A|G&~E)|0;I=(I<<14|I>>>18)+C|0;A=A<<10|A>>>22;a=B+-1894007588+a+(q&j|o&~j)|0;a=(a<<15|a>>>17)+h|0;o=o<<10|o>>>22;C=l+2053994217+C+(I&E|A&~I)|0;C=(C<<14|C>>>18)+G|0;E=E<<10|E>>>22;h=H+-1894007588+h+(a&o|q&~o)|0;h=(h<<9|h>>>23)+j|0;q=q<<10|q>>>22;G=w+2053994217+G+(C&I|E&~C)|0;G=(G<<6|G>>>26)+A|0;I=I<<10|I>>>22;j=x+-1894007588+j+(h&q|a&~q)|0;j=(j<<8|j>>>24)+o|0;a=a<<10|a>>>22;A=s+2053994217+A+(G&C|I&~G)|0;A=(A<<14|A>>>18)+E|0;C=C<<10|C>>>22;o=u+-1894007588+o+(j&a|h&~a)|0;o=(o<<9|o>>>23)+q|0;h=h<<10|h>>>22;E=t+2053994217+E+(A&G|C&~A)|0;E=(E<<6|E>>>26)+I|0;G=G<<10|G>>>22;q=f+-1894007588+q+(o&h|j&~h)|0;q=(q<<14|q>>>18)+a|0;j=j<<10|j>>>22;I=H+2053994217+I+(E&A|G&~E)|0;I=(I<<9|I>>>23)+C|0;A=A<<10|A>>>22;a=z+-1894007588+a+(q&j|o&~j)|0;a=(a<<5|a>>>27)+h|0;o=o<<10|o>>>22;C=v+2053994217+C+(I&E|A&~I)|0;C=(C<<12|C>>>20)+G|0;E=E<<10|E>>>22;h=w+-1894007588+h+(a&o|q&~o)|0;h=(h<<6|h>>>26)+j|0;q=q<<10|q>>>22;G=u+2053994217+G+(C&I|E&~C)|0;G=(G<<9|G>>>23)+A|0;I=I<<10|I>>>22;j=m+-1894007588+j+(h&q|a&~q)|0;j=(j<<8|j>>>24)+o|0;a=a<<10|a>>>22;A=i+2053994217+A+(G&C|I&~G)|0;A=(A<<12|A>>>20)+E|0;C=C<<10|C>>>22;o=t+-1894007588+o+(j&a|h&~a)|0;o=(o<<6|o>>>26)+q|0;h=h<<10|h>>>22;E=z+2053994217+E+(A&G|C&~A)|0;E=(E<<5|E>>>27)+I|0;G=G<<10|G>>>22;q=y+-1894007588+q+(o&h|j&~h)|0;q=(q<<5|q>>>27)+a|0;j=j<<10|j>>>22;I=F+2053994217+I+(E&A|G&~E)|0;I=(I<<15|I>>>17)+C|0;A=A<<10|A>>>22;a=v+-1894007588+a+(q&j|o&~j)|0;a=(a<<12|a>>>20)+h|0;o=o<<10|o>>>22;C=m+2053994217+C+(I&E|A&~I)|0;C=(C<<8|C>>>24)+G|0;E=E<<10|E>>>22;h=x+-1454113458+h+(a^(q|~o))|0;h=(h<<9|h>>>23)+j|0;q=q<<10|q>>>22;G=G+H+(I^E^C)|0;G=(G<<8|G>>>24)+A|0;I=I<<10|I>>>22;j=s+-1454113458+j+(h^(a|~q))|0;j=(j<<15|j>>>17)+o|0;a=a<<10|a>>>22;A=A+w+(C^I^G)|0;A=(A<<5|A>>>27)+E|0;C=C<<10|C>>>22;o=t+-1454113458+o+(j^(h|~a))|0;o=(o<<5|o>>>27)+q|0;h=h<<10|h>>>22;E=E+F+(G^C^A)|0;E=(E<<12|E>>>20)+I|0;G=G<<10|G>>>22;q=i+-1454113458+q+(o^(j|~h))|0;q=(q<<11|q>>>21)+a|0;j=j<<10|j>>>22;x=I+x+(A^G^E)|0;x=(x<<9|x>>>23)+C|0;A=A<<10|A>>>22;a=z+-1454113458+a+(q^(o|~j))|0;a=(a<<6|a>>>26)+h|0;o=o<<10|o>>>22;C=C+D+(E^A^x)|0;C=(C<<12|C>>>20)+G|0;E=E<<10|E>>>22;h=H+-1454113458+h+(a^(q|~o))|0;h=(h<<8|h>>>24)+j|0;q=q<<10|q>>>22;t=G+t+(x^E^C)|0;t=(t<<5|t>>>27)+A|0;x=x<<10|x>>>22;j=v+-1454113458+j+(h^(a|~q))|0;j=(j<<13|j>>>19)+o|0;a=a<<10|a>>>22;A=A+B+(C^x^t)|0;A=(A<<14|A>>>18)+E|0;C=C<<10|C>>>22;o=F+-1454113458+o+(j^(h|~a))|0;o=(o<<12|o>>>20)+q|0;h=h<<10|h>>>22;z=E+z+(t^C^A)|0;z=(z<<6|z>>>26)+x|0;t=t<<10|t>>>22;q=m+-1454113458+q+(o^(j|~h))|0;q=(q<<5|q>>>27)+a|0;j=j<<10|j>>>22;x=x+y+(A^t^z)|0;x=(x<<8|x>>>24)+C|0;A=A<<10|A>>>22;a=D+-1454113458+a+(q^(o|~j))|0;a=(a<<12|a>>>20)+h|0;o=o<<10|o>>>22;v=C+v+(z^A^x)|0;v=(v<<13|v>>>19)+t|0;z=z<<10|z>>>22;h=f+-1454113458+h+(a^(q|~o))|0;h=(h<<13|h>>>19)+j|0;q=q<<10|q>>>22;t=t+u+(x^z^v)|0;t=(t<<6|t>>>26)+A|0;x=x<<10|x>>>22;j=B+-1454113458+j+(h^(a|~q))|0;j=(j<<14|j>>>18)+o|0;a=a<<10|a>>>22;m=A+m+(v^x^t)|0;m=(m<<5|m>>>27)+z|0;v=v<<10|v>>>22;o=l+-1454113458+o+(j^(h|~a))|0;o=(o<<11|o>>>21)+q|0;h=h<<10|h>>>22;s=z+s+(t^v^m)|0;s=(s<<15|s>>>17)+x|0;t=t<<10|t>>>22;q=y+-1454113458+q+(o^(j|~h))|0;q=(q<<8|q>>>24)+a|0;j=j<<10|j>>>22;f=x+f+(m^t^s)|0;f=(f<<13|f>>>19)+v|0;m=m<<10|m>>>22;a=w+-1454113458+a+(q^(o|~j))|0;a=(a<<5|a>>>27)+h|0;o=o<<10|o>>>22;i=v+i+(s^m^f)|0;i=(i<<11|i>>>21)+t|0;s=s<<10|s>>>22;h=u+-1454113458+h+(a^(q|~o))|0;l=t+l+(f^s^i)|0;c[p>>2]=s+r+(q<<10|q>>>22);c[n>>2]=m+(c[k>>2]|0)+o;c[k>>2]=j+(c[g>>2]|0)+m+(l<<11|l>>>21);c[g>>2]=j+(c[b>>2]|0)+i+(h<<6|h>>>26);c[b>>2]=(f<<10|f>>>22)+e+a;return}function xb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0;if(d|0){h=c[a>>2]|0;e=h&63;f=64-e|0;h=h+d|0;c[a>>2]=h;if(h>>>0>>0){h=a+4|0;c[h>>2]=(c[h>>2]|0)+1}if(!((e|0)==0|f>>>0>d>>>0)){qc(a+28+e|0,b|0,f|0)|0;wb(a,a+28|0);e=0;b=b+f|0;d=d-f|0}if(d>>>0>63){g=d+-64|0;h=g&-64;f=b+(h+64)|0;while(1){wb(a,b);d=d+-64|0;if(d>>>0<=63)break;else b=b+64|0}b=f;d=g-h|0}if(d|0)qc(a+28+e|0,b|0,d|0)|0}return}function yb(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0;e=i;i=i+16|0;f=e;g=c[b>>2]|0;h=c[b+4>>2]|0;a[f>>0]=g<<3;a[f+1>>0]=g>>>5;a[f+2>>0]=g>>>13;a[f+3>>0]=g>>>21;a[f+4>>0]=h<<3|g>>>29;a[f+5>>0]=h>>>5;a[f+6>>0]=h>>>13;a[f+7>>0]=h>>>21;g=g&63;xb(b,38733,(g>>>0<56?56:120)-g|0);xb(b,f,8);f=b+8|0;a[d>>0]=c[f>>2];a[d+1>>0]=(c[f>>2]|0)>>>8;a[d+2>>0]=(c[f>>2]|0)>>>16;a[d+3>>0]=(c[f>>2]|0)>>>24;f=b+12|0;a[d+4>>0]=c[f>>2];a[d+5>>0]=(c[f>>2]|0)>>>8;a[d+6>>0]=(c[f>>2]|0)>>>16;a[d+7>>0]=(c[f>>2]|0)>>>24;f=b+16|0;a[d+8>>0]=c[f>>2];a[d+9>>0]=(c[f>>2]|0)>>>8;a[d+10>>0]=(c[f>>2]|0)>>>16;a[d+11>>0]=(c[f>>2]|0)>>>24;f=b+20|0;a[d+12>>0]=c[f>>2];a[d+13>>0]=(c[f>>2]|0)>>>8;a[d+14>>0]=(c[f>>2]|0)>>>16;a[d+15>>0]=(c[f>>2]|0)>>>24;b=b+24|0;a[d+16>>0]=c[b>>2];a[d+17>>0]=(c[b>>2]|0)>>>8;a[d+18>>0]=(c[b>>2]|0)>>>16;a[d+19>>0]=(c[b>>2]|0)>>>24;i=e;return}function zb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0;h=i;i=i+96|0;e=h;f=e+8|0;g=e;j=g+92|0;do{c[g>>2]=0;g=g+4|0}while((g|0)<(j|0));c[f>>2]=1732584193;c[e+12>>2]=-271733879;c[e+16>>2]=-1732584194;c[e+20>>2]=271733878;c[e+24>>2]=-1009589776;xb(e,a,b);yb(e,d);i=h;return}function Ab(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0;y=i;i=i+64|0;t=y;u=c[a>>2]|0;v=a+4|0;w=a+8|0;x=a+12|0;q=a+16|0;r=a+20|0;s=a+24|0;p=a+28|0;g=0;o=u;a=c[p>>2]|0;h=c[s>>2]|0;j=c[r>>2]|0;k=c[q>>2]|0;e=c[x>>2]|0;l=c[w>>2]|0;f=c[v>>2]|0;while(1){n=((k>>>6|k<<26)^(k>>>11|k<<21)^(k>>>25|k<<7))+a+(h&~k^j&k)+(c[37828+(g<<2)>>2]|0)|0;a=c[b>>2]|0;c[t+(g<<2)>>2]=a;a=n+a|0;e=a+e|0;a=((o>>>2|o<<30)^(o>>>13|o<<19)^(o>>>22|o<<10))+(o&(l^f)^l&f)+a|0;g=g+1|0;if((g|0)==16){n=16;m=a;g=e;a=l;e=o;break}else{C=o;B=f;A=l;z=k;m=j;n=h;b=b+4|0;o=a;k=e;f=C;l=B;e=A;j=z;h=m;a=n}}while(1){A=n;n=n+1|0;z=c[t+((n&15)<<2)>>2]|0;b=c[t+((A+14&15)<<2)>>2]|0;C=((g>>>6|g<<26)^(g>>>11|g<<21)^(g>>>25|g<<7))+h+(j&~g^k&g)+(c[37828+(A<<2)>>2]|0)|0;B=t+((A&15)<<2)|0;b=((z>>>18|z<<14)^z>>>3^(z>>>7|z<<25))+(c[t+((A+9&15)<<2)>>2]|0)+(c[B>>2]|0)+((b>>>19|b<<13)^b>>>10^(b>>>17|b<<15))|0;c[B>>2]=b;b=C+b|0;a=b+a|0;b=((m>>>2|m<<30)^(m>>>13|m<<19)^(m>>>22|m<<10))+(m&(f^e)^f&e)+b|0;if((n|0)==64)break;else{o=m;z=e;A=f;B=g;C=k;h=j;m=b;g=a;e=o;f=z;a=A;k=B;j=C}}c[d>>2]=u+b;c[d+4>>2]=(c[v>>2]|0)+m;c[d+8>>2]=(c[w>>2]|0)+e;c[d+12>>2]=(c[x>>2]|0)+f;c[d+16>>2]=(c[q>>2]|0)+a;c[d+20>>2]=(c[r>>2]|0)+g;c[d+24>>2]=(c[s>>2]|0)+k;c[d+28>>2]=(c[p>>2]|0)+j;i=y;return}function Bb(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0;do if(e|0){n=b+32|0;g=n;h=c[g>>2]|0;g=c[g+4>>2]|0;f=jc(h|0,g|0,3)|0;f=f&63;if(f){i=64-f|0;j=b+40|0;f=j+f|0;if(i>>>0>e>>>0){qc(f|0,d|0,e|0)|0;b=nc(h|0,g|0,e<<3|0,0)|0;c[n>>2]=b;c[n+4>>2]=C;break}qc(f|0,d|0,i|0)|0;m=nc(h|0,g|0,i<<3|0,0)|0;f=n;c[f>>2]=m;c[f+4>>2]=C;e=e-i|0;f=0;do{m=b+40+(f<<2)|0;c[m>>2]=pc(c[m>>2]|0)|0;f=f+1|0}while((f|0)!=16);Ab(b,j,b);d=d+i|0}if(e>>>0>63){j=b+40|0;l=e+-64|0;m=l&-64;k=m+64|0;i=d;while(1){f=j;g=i;h=f+64|0;do{a[f>>0]=a[g>>0]|0;f=f+1|0;g=g+1|0}while((f|0)<(h|0));f=0;do{h=b+40+(f<<2)|0;c[h>>2]=pc(c[h>>2]|0)|0;f=f+1|0}while((f|0)!=16);Ab(b,j,b);g=n;g=nc(c[g>>2]|0,c[g+4>>2]|0,512,0)|0;h=n;c[h>>2]=g;c[h+4>>2]=C;e=e+-64|0;if(e>>>0<=63)break;else i=i+64|0}d=d+k|0;e=l-m|0}if(e|0){qc(b+40|0,d|0,e|0)|0;b=n;b=nc(c[b>>2]|0,c[b+4>>2]|0,e<<3|0,0)|0;c[n>>2]=b;c[n+4>>2]=C}}while(0);return}function Cb(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0;if(d){h=b+32|0;f=h;f=jc(c[f>>2]|0,c[f+4>>2]|0,3)|0;f=f&63;e=f+1|0;g=b+40|0;a[g+f>>0]=-128;if(e>>>0>56){ic(g+e|0,0,f^63|0)|0;e=0;do{f=b+40+(e<<2)|0;c[f>>2]=pc(c[f>>2]|0)|0;e=e+1|0}while((e|0)!=16);Ab(b,g,b);e=0}ic(g+e|0,0,56-e|0)|0;e=0;do{f=b+40+(e<<2)|0;c[f>>2]=pc(c[f>>2]|0)|0;e=e+1|0}while((e|0)!=14);e=c[h>>2]|0;c[b+96>>2]=c[h+4>>2];c[b+100>>2]=e;Ab(b,g,b);e=0;do{h=b+(e<<2)|0;c[h>>2]=pc(c[h>>2]|0)|0;e=e+1|0}while((e|0)!=8);e=d;f=b;g=e+32|0;do{a[e>>0]=a[f>>0]|0;e=e+1|0;f=f+1|0}while((e|0)<(g|0))}e=b;g=e+104|0;do{c[e>>2]=0;e=e+4|0}while((e|0)<(g|0));return}function Db(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0;g=i;i=i+112|0;e=g;c[e>>2]=c[9449];c[e+4>>2]=c[9450];c[e+8>>2]=c[9451];c[e+12>>2]=c[9452];c[e+16>>2]=c[9453];c[e+20>>2]=c[9454];c[e+24>>2]=c[9455];c[e+28>>2]=c[9456];f=e+32|0;h=f+72|0;do{c[f>>2]=0;f=f+4|0}while((f|0)<(h|0));Bb(e,a,b);Cb(e,d);i=g;return}function Eb(a){a=a|0;var b=0,d=0,e=0;if(a|0){b=a;d=8;e=b+64|0;do{c[b>>2]=c[d>>2];b=b+4|0;d=d+4|0}while((b|0)<(e|0));ic(a+64|0,0,144)|0}return}function Fb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0,X=0,Y=0,Z=0,_=0;L=i;i=i+128|0;F=L;K=a;J=c[K>>2]|0;K=c[K+4>>2]|0;B=a+8|0;w=B;D=a+16|0;e=D;E=a+24|0;f=E;G=a+32|0;p=G;H=a+40|0;q=H;I=a+48|0;m=I;A=a+56|0;h=A;j=0;l=J;u=K;t=c[w>>2]|0;z=c[e>>2]|0;w=c[w+4>>2]|0;a=c[e+4>>2]|0;e=c[f>>2]|0;f=c[f+4>>2]|0;o=c[p>>2]|0;p=c[p+4>>2]|0;g=c[h>>2]|0;h=c[h+4>>2]|0;r=c[q>>2]|0;q=c[q+4>>2]|0;k=c[m>>2]|0;m=c[m+4>>2]|0;while(1){v=jc(o|0,p|0,14)|0;N=C;x=kc(o|0,p|0,50)|0;N=N|C;y=jc(o|0,p|0,18)|0;O=C;M=kc(o|0,p|0,46)|0;O=N^(O|C);N=jc(o|0,p|0,41)|0;n=C;s=kc(o|0,p|0,23)|0;n=nc((v|x)^(y|M)^(N|s)|0,O^(n|C)|0,g|0,h|0)|0;n=nc(n|0,C|0,k&~o^r&o|0,m&~p^q&p|0)|0;O=72+(j<<3)|0;O=nc(n|0,C|0,c[O>>2]|0,c[O+4>>2]|0)|0;n=b;g=c[n>>2]|0;n=c[n+4>>2]|0;s=F+(j<<3)|0;c[s>>2]=g;c[s+4>>2]=n;n=nc(O|0,C|0,g|0,n|0)|0;g=C;O=jc(l|0,u|0,28)|0;s=C;N=kc(l|0,u|0,36)|0;s=s|C;M=jc(l|0,u|0,34)|0;y=C;h=kc(l|0,u|0,30)|0;y=s^(y|C);s=jc(l|0,u|0,39)|0;x=C;v=kc(l|0,u|0,25)|0;x=nc((O|N)^(M|h)^(s|v)|0,y^(x|C)|0,l&(z^t)^z&t|0,u&(a^w)^a&w|0)|0;y=C;e=nc(n|0,g|0,e|0,f|0)|0;f=C;g=nc(x|0,y|0,n|0,g|0)|0;n=C;j=j+1|0;if((j|0)==16){y=16;x=e;v=f;s=p;p=g;j=t;h=u;g=w;b=z;break}else{x=p;y=o;h=m;M=k;N=u;O=l;b=b+8|0;l=g;u=n;o=e;p=f;m=q;k=r;q=x;r=y;g=M;f=a;e=z;a=w;w=N;z=t;t=O}}while(1){t=y;y=y+1|0;T=F+((y&15)<<3)|0;W=c[T>>2]|0;T=c[T+4>>2]|0;S=jc(W|0,T|0,1)|0;Q=C;R=kc(W|0,T|0,63)|0;Q=Q|C;V=jc(W|0,T|0,8)|0;O=C;U=kc(W|0,T|0,56)|0;O=O|C;T=jc(W|0,T|0,7)|0;Q=O^C^Q;O=F+((t+14&15)<<3)|0;W=c[O>>2]|0;O=c[O+4>>2]|0;u=jc(W|0,O|0,19)|0;e=C;f=kc(W|0,O|0,45)|0;e=e|C;N=jc(W|0,O|0,61)|0;_=C;w=kc(W|0,O|0,3)|0;_=_|C;O=jc(W|0,O|0,6)|0;e=_^C^e;_=jc(x|0,v|0,14)|0;W=C;Z=kc(x|0,v|0,50)|0;W=W|C;Y=jc(x|0,v|0,18)|0;P=C;X=kc(x|0,v|0,46)|0;P=W^(P|C);W=jc(x|0,v|0,41)|0;z=C;M=kc(x|0,v|0,23)|0;m=nc((_|Z)^(Y|X)^(W|M)|0,P^(z|C)|0,k|0,m|0)|0;m=nc(m|0,C|0,r&~x^o&x|0,q&~v^s&v|0)|0;z=72+(t<<3)|0;z=nc(m|0,C|0,c[z>>2]|0,c[z+4>>2]|0)|0;m=C;P=F+((t+9&15)<<3)|0;t=F+((t&15)<<3)|0;M=t;k=c[M>>2]|0;M=c[M+4>>2]|0;P=nc((V|U)^T^(S|R)|0,Q|0,c[P>>2]|0,c[P+4>>2]|0)|0;M=nc(P|0,C|0,k|0,M|0)|0;e=nc(M|0,C|0,(N|w)^O^(u|f)|0,e|0)|0;f=C;c[t>>2]=e;c[t+4>>2]=f;f=nc(z|0,m|0,e|0,f|0)|0;e=C;m=jc(p|0,n|0,28)|0;z=C;t=kc(p|0,n|0,36)|0;z=z|C;u=jc(p|0,n|0,34)|0;O=C;w=kc(p|0,n|0,30)|0;O=z^(O|C);z=jc(p|0,n|0,39)|0;N=C;M=kc(p|0,n|0,25)|0;N=nc((m|t)^(u|w)^(z|M)|0,O^(N|C)|0,p&(j^l)^j&l|0,n&(g^h)^g&h|0)|0;O=C;a=nc(f|0,e|0,b|0,a|0)|0;b=C;e=nc(N|0,O|0,f|0,e|0)|0;f=C;if((y|0)==80)break;else{X=n;Y=p;Z=v;_=x;m=q;k=r;x=a;v=b;p=e;n=f;a=g;b=j;g=h;h=X;j=l;l=Y;q=s;r=o;s=Z;o=_}}_=nc(J|0,K|0,e|0,f|0)|0;Z=d;c[Z>>2]=_;c[Z+4>>2]=C;Z=B;Z=nc(c[Z>>2]|0,c[Z+4>>2]|0,p|0,n|0)|0;_=d+8|0;c[_>>2]=Z;c[_+4>>2]=C;_=D;_=nc(c[_>>2]|0,c[_+4>>2]|0,l|0,h|0)|0;Z=d+16|0;c[Z>>2]=_;c[Z+4>>2]=C;Z=E;Z=nc(c[Z>>2]|0,c[Z+4>>2]|0,j|0,g|0)|0;_=d+24|0;c[_>>2]=Z;c[_+4>>2]=C;_=G;_=nc(c[_>>2]|0,c[_+4>>2]|0,a|0,b|0)|0;Z=d+32|0;c[Z>>2]=_;c[Z+4>>2]=C;Z=H;Z=nc(c[Z>>2]|0,c[Z+4>>2]|0,x|0,v|0)|0;_=d+40|0;c[_>>2]=Z;c[_+4>>2]=C;_=I;_=nc(c[_>>2]|0,c[_+4>>2]|0,o|0,s|0)|0;Z=d+48|0;c[Z>>2]=_;c[Z+4>>2]=C;Z=A;Z=nc(c[Z>>2]|0,c[Z+4>>2]|0,r|0,q|0)|0;_=d+56|0;c[_>>2]=Z;c[_+4>>2]=C;i=L;return}function Gb(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0;do if(e|0){o=b+64|0;g=o;h=c[g>>2]|0;g=c[g+4>>2]|0;f=jc(h|0,g|0,3)|0;f=f&127;if(f){i=128-f|0;j=b+80|0;f=j+f|0;if(i>>>0>e>>>0){qc(f|0,d|0,e|0)|0;n=e<<3;m=nc(h|0,g|0,n|0,0)|0;l=C;c[o>>2]=m;c[o+4>>2]=l;if(!(l>>>0<0|(l|0)==0&m>>>0>>0))break;o=b+72|0;b=o;b=nc(c[b>>2]|0,c[b+4>>2]|0,1,0)|0;c[o>>2]=b;c[o+4>>2]=C;break}qc(f|0,d|0,i|0)|0;n=i<<3;m=nc(h|0,g|0,n|0,0)|0;l=C;k=o;c[k>>2]=m;c[k+4>>2]=l;if(l>>>0<0|(l|0)==0&m>>>0>>0){n=b+72|0;m=n;m=nc(c[m>>2]|0,c[m+4>>2]|0,1,0)|0;c[n>>2]=m;c[n+4>>2]=C}e=e-i|0;f=0;do{n=b+80+(f<<3)|0;m=n;m=ma(c[m>>2]|0,c[m+4>>2]|0)|0;c[n>>2]=m;c[n+4>>2]=C;f=f+1|0}while((f|0)!=16);Fb(b,j,b);d=d+i|0}if(e>>>0>127){j=b+80|0;k=b+72|0;m=e+-128|0;n=m&-128;l=n+128|0;i=d;while(1){f=j;g=i;h=f+128|0;do{a[f>>0]=a[g>>0]|0;f=f+1|0;g=g+1|0}while((f|0)<(h|0));f=0;do{h=b+80+(f<<3)|0;g=h;g=ma(c[g>>2]|0,c[g+4>>2]|0)|0;c[h>>2]=g;c[h+4>>2]=C;f=f+1|0}while((f|0)!=16);Fb(b,j,b);g=o;h=c[g>>2]|0;g=c[g+4>>2]|0;p=nc(h|0,g|0,1024,0)|0;f=o;c[f>>2]=p;c[f+4>>2]=C;if(g>>>0>4294967295|(g|0)==-1&h>>>0>4294966271){h=k;h=nc(c[h>>2]|0,c[h+4>>2]|0,1,0)|0;p=k;c[p>>2]=h;c[p+4>>2]=C}e=e+-128|0;if(e>>>0<=127)break;else i=i+128|0}d=d+l|0;e=m-n|0}if(e|0?(qc(b+80|0,d|0,e|0)|0,p=e<<3,n=o,n=nc(c[n>>2]|0,c[n+4>>2]|0,p|0,0)|0,m=C,o,c[o>>2]=n,c[o+4>>2]=m,m>>>0<0|(m|0)==0&n>>>0

>>0):0){p=b+72|0;o=p;o=nc(c[o>>2]|0,c[o+4>>2]|0,1,0)|0;c[p>>2]=o;c[p+4>>2]=C}}while(0);return}function Hb(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0;if(d){h=b+64|0;f=h;f=jc(c[f>>2]|0,c[f+4>>2]|0,3)|0;f=f&127;e=f+1|0;g=b+80|0;a[g+f>>0]=-128;if(e>>>0>112){ic(g+e|0,0,f^127|0)|0;e=0;do{f=b+80+(e<<3)|0;i=f;i=ma(c[i>>2]|0,c[i+4>>2]|0)|0;c[f>>2]=i;c[f+4>>2]=C;e=e+1|0}while((e|0)!=16);Fb(b,g,b);e=0}ic(g+e|0,0,112-e|0)|0;e=0;do{i=b+80+(e<<3)|0;f=i;f=ma(c[f>>2]|0,c[f+4>>2]|0)|0;c[i>>2]=f;c[i+4>>2]=C;e=e+1|0}while((e|0)!=14);f=b+72|0;e=c[f+4>>2]|0;i=b+192|0;c[i>>2]=c[f>>2];c[i+4>>2]=e;i=c[h+4>>2]|0;e=b+200|0;c[e>>2]=c[h>>2];c[e+4>>2]=i;Fb(b,g,b);e=0;do{i=b+(e<<3)|0;h=i;h=ma(c[h>>2]|0,c[h+4>>2]|0)|0;c[i>>2]=h;c[i+4>>2]=C;e=e+1|0}while((e|0)!=8);e=d;f=b;g=e+64|0;do{a[e>>0]=a[f>>0]|0;e=e+1|0;f=f+1|0}while((e|0)<(g|0))}ic(b|0,0,208)|0;return}function Ib(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0;g=i;i=i+208|0;e=g;f=e;h=8;j=f+64|0;do{c[f>>2]=c[h>>2];f=f+4|0;h=h+4|0}while((f|0)<(j|0));ic(e+64|0,0,144)|0;Gb(e,a,b);Hb(e,d);i=g;return}function Jb(){var a=0,b=0,d=0;d=i;i=i+16|0;b=d;a=c[9714]|0;if(!a){a=bc(38797,38810)|0;c[9714]=a}if((dc(b,1,4,a)|0)==4){i=d;return c[b>>2]|0}else pa(38812,38828,60,38838);return 0}function Kb(a){a=a|0;var b=0,d=0;b=i;i=i+16|0;d=b;c[d>>2]=c[a+60>>2];a=Nb(ha(6,d|0)|0)|0;i=b;return a|0}function Lb(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0;m=i;i=i+48|0;h=m+16|0;g=m;f=m+32|0;c[f>>2]=d;j=f+4|0;l=b+48|0;n=c[l>>2]|0;c[j>>2]=e-((n|0)!=0&1);k=b+44|0;c[f+8>>2]=c[k>>2];c[f+12>>2]=n;if(!(c[9715]|0)){c[h>>2]=c[b+60>>2];c[h+4>>2]=f;c[h+8>>2]=2;f=Nb(qa(145,h|0)|0)|0}else{ga(1,b|0);c[g>>2]=c[b+60>>2];c[g+4>>2]=f;c[g+8>>2]=2;f=Nb(qa(145,g|0)|0)|0;ba(0)}if((f|0)>=1){j=c[j>>2]|0;if(f>>>0>j>>>0){g=c[k>>2]|0;h=b+4|0;c[h>>2]=g;c[b+8>>2]=g+(f-j);if(!(c[l>>2]|0))f=e;else{c[h>>2]=g+1;a[d+(e+-1)>>0]=a[g>>0]|0;f=e}}}else{c[b>>2]=c[b>>2]|f&48^16;c[b+8>>2]=0;c[b+4>>2]=0}i=m;return f|0}function Mb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0;f=i;i=i+32|0;g=f;e=f+20|0;c[g>>2]=c[a+60>>2];c[g+4>>2]=0;c[g+8>>2]=b;c[g+12>>2]=e;c[g+16>>2]=d;if((Nb(ja(140,g|0)|0)|0)<0){c[e>>2]=-1;a=-1}else a=c[e>>2]|0;i=f;return a|0}function Nb(a){a=a|0;if(a>>>0>4294963200){c[(Ob()|0)>>2]=0-a;a=-1}return a|0}function Ob(){var a=0;if(!(c[9715]|0))a=38904;else a=c[(rc()|0)+64>>2]|0;return a|0}function Pb(a){a=a|0;if(!(c[a+68>>2]|0))Qb(a);return}function Qb(a){a=a|0;return}function Rb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0;q=i;i=i+48|0;n=q+16|0;m=q;j=q+32|0;o=a+28|0;h=c[o>>2]|0;c[j>>2]=h;p=a+20|0;h=(c[p>>2]|0)-h|0;c[j+4>>2]=h;c[j+8>>2]=b;c[j+12>>2]=d;k=a+60|0;l=a+44|0;g=2;b=h+d|0;while(1){if(!(c[9715]|0)){c[n>>2]=c[k>>2];c[n+4>>2]=j;c[n+8>>2]=g;f=Nb(ra(146,n|0)|0)|0}else{ga(2,a|0);c[m>>2]=c[k>>2];c[m+4>>2]=j;c[m+8>>2]=g;f=Nb(ra(146,m|0)|0)|0;ba(0)}if((b|0)==(f|0)){b=6;break}if((f|0)<0){b=8;break}b=b-f|0;e=c[j+4>>2]|0;if(f>>>0<=e>>>0)if((g|0)==2){c[o>>2]=(c[o>>2]|0)+f;g=2;h=j}else h=j;else{h=c[l>>2]|0;c[o>>2]=h;c[p>>2]=h;f=f-e|0;g=g+-1|0;h=j+8|0;e=c[j+12>>2]|0}c[h>>2]=(c[h>>2]|0)+f;c[h+4>>2]=e-f;j=h}if((b|0)==6){n=c[l>>2]|0;c[a+16>>2]=n+(c[a+48>>2]|0);a=n;c[o>>2]=a;c[p>>2]=a}else if((b|0)==8){c[a+16>>2]=0;c[o>>2]=0;c[p>>2]=0;c[a>>2]=c[a>>2]|32;if((g|0)==2)d=0;else d=d-(c[j+4>>2]|0)|0}i=q;return d|0}function Sb(a){a=a|0;if(!(c[a+68>>2]|0))Qb(a);return}function Tb(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0;g=i;i=i+80|0;f=g;c[b+36>>2]=3;if((c[b>>2]&64|0)==0?(c[f>>2]=c[b+60>>2],c[f+4>>2]=21505,c[f+8>>2]=g+12,da(54,f|0)|0):0)a[b+75>>0]=-1;f=Rb(b,d,e)|0;i=g;return f|0}function Ub(b){b=b|0;var d=0,e=0,f=0;f=b;a:do if(!(f&3))e=4;else{d=f;while(1){if(!(a[b>>0]|0)){b=d;break a}b=b+1|0;d=b;if(!(d&3)){e=4;break}}}while(0);if((e|0)==4){while(1){d=c[b>>2]|0;if(!((d&-2139062144^-2139062144)&d+-16843009))b=b+4|0;else break}if((d&255)<<24>>24)do b=b+1|0;while((a[b>>0]|0)!=0)}return b-f|0}function Vb(a){a=a|0;return 0}function Wb(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,i=0;h=d&255;f=(e|0)!=0;a:do if(f&(b&3|0)!=0){g=d&255;while(1){if((a[b>>0]|0)==g<<24>>24){i=6;break a}b=b+1|0;e=e+-1|0;f=(e|0)!=0;if(!(f&(b&3|0)!=0)){i=5;break}}}else i=5;while(0);if((i|0)==5)if(f)i=6;else e=0;b:do if((i|0)==6){g=d&255;if((a[b>>0]|0)!=g<<24>>24){f=R(h,16843009)|0;c:do if(e>>>0>3)while(1){h=c[b>>2]^f;if((h&-2139062144^-2139062144)&h+-16843009|0)break;b=b+4|0;e=e+-4|0;if(e>>>0<=3){i=11;break c}}else i=11;while(0);if((i|0)==11)if(!e){e=0;break}while(1){if((a[b>>0]|0)==g<<24>>24)break b;b=b+1|0;e=e+-1|0;if(!e){e=0;break}}}}while(0);return (e|0?b:0)|0}function Xb(a){a=a|0;var b=0,d=0;do if(a){if((c[a+76>>2]|0)<=-1){b=Yb(a)|0;break}d=(Vb(a)|0)==0;b=Yb(a)|0;if(!d)Qb(a)}else{if(!(c[9549]|0))b=0;else b=Xb(c[9549]|0)|0;ea(38888);a=c[9721]|0;if(a)do{if((c[a+76>>2]|0)>-1)d=Vb(a)|0;else d=0;if((c[a+20>>2]|0)>>>0>(c[a+28>>2]|0)>>>0)b=Yb(a)|0|b;if(d|0)Qb(a);a=c[a+56>>2]|0}while((a|0)!=0);na(38888)}while(0);return b|0}function Yb(a){a=a|0;var b=0,d=0,e=0,f=0,g=0,h=0;b=a+20|0;h=a+28|0;if((c[b>>2]|0)>>>0>(c[h>>2]|0)>>>0?(va[c[a+36>>2]&7](a,0,0)|0,(c[b>>2]|0)==0):0)a=-1;else{d=a+4|0;e=c[d>>2]|0;f=a+8|0;g=c[f>>2]|0;if(e>>>0>>0)va[c[a+40>>2]&7](a,e-g|0,1)|0;c[a+16>>2]=0;c[h>>2]=0;c[b>>2]=0;c[f>>2]=0;c[d>>2]=0;a=0}return a|0}function Zb(b){b=b|0;var d=0,e=0;d=b+74|0;e=a[d>>0]|0;a[d>>0]=e+255|e;d=b+20|0;e=b+44|0;if((c[d>>2]|0)>>>0>(c[e>>2]|0)>>>0)va[c[b+36>>2]&7](b,0,0)|0;c[b+16>>2]=0;c[b+28>>2]=0;c[d>>2]=0;d=c[b>>2]|0;if(d&20)if(!(d&4))d=-1;else{c[b>>2]=d|32;d=-1}else{d=c[e>>2]|0;c[b+8>>2]=d;c[b+4>>2]=d;d=0}return d|0}function _b(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0;o=i;i=i+112|0;n=o+40|0;l=o+24|0;k=o+16|0;g=o;m=o+52|0;f=a[d>>0]|0;if(Wb(38847,f<<24>>24,4)|0){e=ec(1144)|0;if(!e)e=0;else{h=e;j=h+112|0;do{c[h>>2]=0;h=h+4|0}while((h|0)<(j|0));if(!($b(d,43)|0))c[e>>2]=f<<24>>24==114?8:4;if($b(d,101)|0){c[g>>2]=b;c[g+4>>2]=2;c[g+8>>2]=1;ca(221,g|0)|0;f=a[d>>0]|0}if(f<<24>>24==97){c[k>>2]=b;c[k+4>>2]=3;f=ca(221,k|0)|0;if(!(f&1024)){c[l>>2]=b;c[l+4>>2]=4;c[l+8>>2]=f|1024;ca(221,l|0)|0}d=c[e>>2]|128;c[e>>2]=d}else d=c[e>>2]|0;c[e+60>>2]=b;c[e+44>>2]=e+120;c[e+48>>2]=1024;f=e+75|0;a[f>>0]=-1;if((d&8|0)==0?(c[n>>2]=b,c[n+4>>2]=21505,c[n+8>>2]=m,(da(54,n|0)|0)==0):0)a[f>>0]=10;c[e+32>>2]=4;c[e+36>>2]=3;c[e+40>>2]=2;c[e+12>>2]=1;if(!(c[9716]|0))c[e+76>>2]=-1;ea(38888);f=c[9721]|0;c[e+56>>2]=f;if(f|0)c[f+52>>2]=e;c[9721]=e;na(38888)}}else{c[(Ob()|0)>>2]=22;e=0}i=o;return e|0}function $b(b,c){b=b|0;c=c|0;b=ac(b,c)|0;return ((a[b>>0]|0)==(c&255)<<24>>24?b:0)|0}function ac(b,d){b=b|0;d=d|0;var e=0,f=0,g=0;f=d&255;a:do if(!f)b=b+(Ub(b)|0)|0;else{if(b&3){e=d&255;do{g=a[b>>0]|0;if(g<<24>>24==0?1:g<<24>>24==e<<24>>24)break a;b=b+1|0}while((b&3|0)!=0)}f=R(f,16843009)|0;e=c[b>>2]|0;b:do if(!((e&-2139062144^-2139062144)&e+-16843009))do{g=e^f;if((g&-2139062144^-2139062144)&g+-16843009|0)break b;b=b+4|0;e=c[b>>2]|0}while(!((e&-2139062144^-2139062144)&e+-16843009|0));while(0);e=d&255;while(1){g=a[b>>0]|0;if(g<<24>>24==0?1:g<<24>>24==e<<24>>24)break;else b=b+1|0}}while(0);return b|0}function bc(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0;g=i;i=i+32|0;f=g+16|0;e=g;if(Wb(38847,a[d>>0]|0,4)|0){h=cc(d)|0|32768;c[e>>2]=b;c[e+4>>2]=h;c[e+8>>2]=438;e=Nb(ka(5,e|0)|0)|0;if((e|0)>=0){b=_b(e,d)|0;if(!b){c[f>>2]=e;ha(6,f|0)|0;b=0}}else b=0}else{c[(Ob()|0)>>2]=22;b=0}i=g;return b|0}function cc(b){b=b|0;var c=0,d=0,e=0;d=($b(b,43)|0)==0;c=a[b>>0]|0;d=d?c<<24>>24!=114&1:2;e=($b(b,120)|0)==0;d=e?d:d|128;b=($b(b,101)|0)==0;b=b?d:d|524288;b=c<<24>>24==114?b:b|64;b=c<<24>>24==119?b|512:b;return (c<<24>>24==97?b|1024:b)|0}function dc(b,d,e,f){b=b|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,i=0,j=0,k=0,l=0;k=R(e,d)|0;if((c[f+76>>2]|0)>-1)j=Vb(f)|0;else j=0;g=f+74|0;i=a[g>>0]|0;a[g>>0]=i+255|i;g=f+4|0;i=c[g>>2]|0;h=(c[f+8>>2]|0)-i|0;if((h|0)>0){h=h>>>0>>0?h:k;qc(b|0,i|0,h|0)|0;c[g>>2]=i+h;g=k-h|0;b=b+h|0}else g=k;a:do if(!g)l=13;else{i=f+32|0;while(1){if(Zb(f)|0)break;h=va[c[i>>2]&7](f,b,g)|0;if((h+1|0)>>>0<2)break;g=g-h|0;if(!g){l=13;break a}else b=b+h|0}if(j|0)Qb(f);e=((k-g|0)>>>0)/(d>>>0)|0}while(0);if((l|0)==13)if(j)Qb(f);return e|0}function ec(a){a=a|0;var b=0,d=0,e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0;L=i;i=i+16|0;p=L;do if(a>>>0<245){o=a>>>0<11?16:a+11&-8;a=o>>>3;t=c[9727]|0;d=t>>>a;if(d&3|0){a=(d&1^1)+a|0;d=38948+(a<<1<<2)|0;e=d+8|0;f=c[e>>2]|0;g=f+8|0;h=c[g>>2]|0;do if((d|0)!=(h|0)){if(h>>>0<(c[9731]|0)>>>0)fa();b=h+12|0;if((c[b>>2]|0)==(f|0)){c[b>>2]=d;c[e>>2]=h;break}else fa()}else c[9727]=t&~(1<>2]=K|3;K=f+K+4|0;c[K>>2]=c[K>>2]|1;K=g;i=L;return K|0}s=c[9729]|0;if(o>>>0>s>>>0){if(d|0){j=2<>>12&16;a=a>>>j;e=a>>>5&8;a=a>>>e;g=a>>>2&4;a=a>>>g;d=a>>>1&2;a=a>>>d;b=a>>>1&1;b=(e|j|g|d|b)+(a>>>b)|0;a=38948+(b<<1<<2)|0;d=a+8|0;g=c[d>>2]|0;j=g+8|0;e=c[j>>2]|0;do if((a|0)!=(e|0)){if(e>>>0<(c[9731]|0)>>>0)fa();f=e+12|0;if((c[f>>2]|0)==(g|0)){c[f>>2]=a;c[d>>2]=e;k=t;break}else fa()}else{k=t&~(1<>2]=o|3;e=g+o|0;c[e+4>>2]=h|1;c[e+h>>2]=h;if(s|0){f=c[9732]|0;b=s>>>3;d=38948+(b<<1<<2)|0;b=1<>2]|0;if(a>>>0<(c[9731]|0)>>>0)fa();else{l=a;m=b}}else{c[9727]=k|b;l=d;m=d+8|0}c[m>>2]=f;c[l+12>>2]=f;c[f+8>>2]=l;c[f+12>>2]=d}c[9729]=h;c[9732]=e;K=j;i=L;return K|0}l=c[9728]|0;if(l){a=(l&0-l)+-1|0;J=a>>>12&16;a=a>>>J;I=a>>>5&8;a=a>>>I;K=a>>>2&4;a=a>>>K;j=a>>>1&2;a=a>>>j;k=a>>>1&1;k=c[39212+((I|J|K|j|k)+(a>>>k)<<2)>>2]|0;a=k;j=k;k=(c[k+4>>2]&-8)-o|0;while(1){b=c[a+16>>2]|0;if(!b){b=c[a+20>>2]|0;if(!b)break}K=(c[b+4>>2]&-8)-o|0;J=K>>>0>>0;a=b;j=J?b:j;k=J?K:k}f=c[9731]|0;if(j>>>0>>0)fa();h=j+o|0;if(j>>>0>=h>>>0)fa();g=c[j+24>>2]|0;d=c[j+12>>2]|0;do if((d|0)==(j|0)){a=j+20|0;b=c[a>>2]|0;if(!b){a=j+16|0;b=c[a>>2]|0;if(!b){n=0;break}}while(1){d=b+20|0;e=c[d>>2]|0;if(e|0){b=e;a=d;continue}d=b+16|0;e=c[d>>2]|0;if(!e)break;else{b=e;a=d}}if(a>>>0>>0)fa();else{c[a>>2]=0;n=b;break}}else{e=c[j+8>>2]|0;if(e>>>0>>0)fa();b=e+12|0;if((c[b>>2]|0)!=(j|0))fa();a=d+8|0;if((c[a>>2]|0)==(j|0)){c[b>>2]=d;c[a>>2]=e;n=d;break}else fa()}while(0);do if(g|0){b=c[j+28>>2]|0;a=39212+(b<<2)|0;if((j|0)==(c[a>>2]|0)){c[a>>2]=n;if(!n){c[9728]=l&~(1<>>0<(c[9731]|0)>>>0)fa();b=g+16|0;if((c[b>>2]|0)==(j|0))c[b>>2]=n;else c[g+20>>2]=n;if(!n)break}a=c[9731]|0;if(n>>>0>>0)fa();c[n+24>>2]=g;b=c[j+16>>2]|0;do if(b|0)if(b>>>0>>0)fa();else{c[n+16>>2]=b;c[b+24>>2]=n;break}while(0);b=c[j+20>>2]|0;if(b|0)if(b>>>0<(c[9731]|0)>>>0)fa();else{c[n+20>>2]=b;c[b+24>>2]=n;break}}while(0);if(k>>>0<16){K=k+o|0;c[j+4>>2]=K|3;K=j+K+4|0;c[K>>2]=c[K>>2]|1}else{c[j+4>>2]=o|3;c[h+4>>2]=k|1;c[h+k>>2]=k;if(s|0){e=c[9732]|0;b=s>>>3;d=38948+(b<<1<<2)|0;b=1<>2]|0;if(a>>>0<(c[9731]|0)>>>0)fa();else{q=a;r=b}}else{c[9727]=t|b;q=d;r=d+8|0}c[r>>2]=e;c[q+12>>2]=e;c[e+8>>2]=q;c[e+12>>2]=d}c[9729]=k;c[9732]=h}K=j+8|0;i=L;return K|0}}}else if(a>>>0<=4294967231){a=a+11|0;o=a&-8;l=c[9728]|0;if(l){e=0-o|0;a=a>>>8;if(a)if(o>>>0>16777215)k=31;else{r=(a+1048320|0)>>>16&8;D=a<>>16&4;D=D<>>16&2;k=14-(q|r|k)+(D<>>15)|0;k=o>>>(k+7|0)&1|k<<1}else k=0;a=c[39212+(k<<2)>>2]|0;a:do if(!a){d=0;f=0;D=86}else{f=0;j=a;h=o<<((k|0)==31?0:25-(k>>>1)|0);d=0;while(1){a=(c[j+4>>2]&-8)-o|0;if(a>>>0>>0)if(!a){a=j;e=0;d=j;D=90;break a}else{f=j;e=a}a=c[j+20>>2]|0;j=c[j+16+(h>>>31<<2)>>2]|0;d=(a|0)==0|(a|0)==(j|0)?d:a;a=(j|0)==0;if(a){D=86;break}else h=h<<(a&1^1)}}while(0);if((D|0)==86){if((d|0)==0&(f|0)==0){a=2<>>12&16;r=r>>>m;k=r>>>5&8;r=r>>>k;n=r>>>2&4;r=r>>>n;q=r>>>1&2;r=r>>>q;d=r>>>1&1;d=c[39212+((k|m|n|q|d)+(r>>>d)<<2)>>2]|0}if(!d){k=f;j=e}else{a=f;D=90}}if((D|0)==90)while(1){D=0;r=(c[d+4>>2]&-8)-o|0;f=r>>>0>>0;e=f?r:e;a=f?d:a;f=c[d+16>>2]|0;if(f|0){d=f;D=90;continue}d=c[d+20>>2]|0;if(!d){k=a;j=e;break}else D=90}if((k|0)!=0?j>>>0<((c[9729]|0)-o|0)>>>0:0){f=c[9731]|0;if(k>>>0>>0)fa();h=k+o|0;if(k>>>0>=h>>>0)fa();g=c[k+24>>2]|0;d=c[k+12>>2]|0;do if((d|0)==(k|0)){a=k+20|0;b=c[a>>2]|0;if(!b){a=k+16|0;b=c[a>>2]|0;if(!b){s=0;break}}while(1){d=b+20|0;e=c[d>>2]|0;if(e|0){b=e;a=d;continue}d=b+16|0;e=c[d>>2]|0;if(!e)break;else{b=e;a=d}}if(a>>>0>>0)fa();else{c[a>>2]=0;s=b;break}}else{e=c[k+8>>2]|0;if(e>>>0>>0)fa();b=e+12|0;if((c[b>>2]|0)!=(k|0))fa();a=d+8|0;if((c[a>>2]|0)==(k|0)){c[b>>2]=d;c[a>>2]=e;s=d;break}else fa()}while(0);do if(g){b=c[k+28>>2]|0;a=39212+(b<<2)|0;if((k|0)==(c[a>>2]|0)){c[a>>2]=s;if(!s){t=l&~(1<>>0<(c[9731]|0)>>>0)fa();b=g+16|0;if((c[b>>2]|0)==(k|0))c[b>>2]=s;else c[g+20>>2]=s;if(!s){t=l;break}}a=c[9731]|0;if(s>>>0>>0)fa();c[s+24>>2]=g;b=c[k+16>>2]|0;do if(b|0)if(b>>>0>>0)fa();else{c[s+16>>2]=b;c[b+24>>2]=s;break}while(0);b=c[k+20>>2]|0;if(b)if(b>>>0<(c[9731]|0)>>>0)fa();else{c[s+20>>2]=b;c[b+24>>2]=s;t=l;break}else t=l}else t=l;while(0);do if(j>>>0>=16){c[k+4>>2]=o|3;c[h+4>>2]=j|1;c[h+j>>2]=j;b=j>>>3;if(j>>>0<256){d=38948+(b<<1<<2)|0;a=c[9727]|0;b=1<>2]|0;if(a>>>0<(c[9731]|0)>>>0)fa();else{B=a;C=b}}else{c[9727]=a|b;B=d;C=d+8|0}c[C>>2]=h;c[B+12>>2]=h;c[h+8>>2]=B;c[h+12>>2]=d;break}b=j>>>8;if(b)if(j>>>0>16777215)b=31;else{J=(b+1048320|0)>>>16&8;K=b<>>16&4;K=K<>>16&2;b=14-(I|J|b)+(K<>>15)|0;b=j>>>(b+7|0)&1|b<<1}else b=0;d=39212+(b<<2)|0;c[h+28>>2]=b;a=h+16|0;c[a+4>>2]=0;c[a>>2]=0;a=1<>2]=h;c[h+24>>2]=d;c[h+12>>2]=h;c[h+8>>2]=h;break}a=j<<((b|0)==31?0:25-(b>>>1)|0);e=c[d>>2]|0;while(1){if((c[e+4>>2]&-8|0)==(j|0)){D=148;break}d=e+16+(a>>>31<<2)|0;b=c[d>>2]|0;if(!b){D=145;break}else{a=a<<1;e=b}}if((D|0)==145)if(d>>>0<(c[9731]|0)>>>0)fa();else{c[d>>2]=h;c[h+24>>2]=e;c[h+12>>2]=h;c[h+8>>2]=h;break}else if((D|0)==148){b=e+8|0;a=c[b>>2]|0;K=c[9731]|0;if(a>>>0>=K>>>0&e>>>0>=K>>>0){c[a+12>>2]=h;c[b>>2]=h;c[h+8>>2]=a;c[h+12>>2]=e;c[h+24>>2]=0;break}else fa()}}else{K=j+o|0;c[k+4>>2]=K|3;K=k+K+4|0;c[K>>2]=c[K>>2]|1}while(0);K=k+8|0;i=L;return K|0}}}else o=-1;while(0);d=c[9729]|0;if(d>>>0>=o>>>0){b=d-o|0;a=c[9732]|0;if(b>>>0>15){K=a+o|0;c[9732]=K;c[9729]=b;c[K+4>>2]=b|1;c[K+b>>2]=b;c[a+4>>2]=o|3}else{c[9729]=0;c[9732]=0;c[a+4>>2]=d|3;K=a+d+4|0;c[K>>2]=c[K>>2]|1}K=a+8|0;i=L;return K|0}j=c[9730]|0;if(j>>>0>o>>>0){I=j-o|0;c[9730]=I;K=c[9733]|0;J=K+o|0;c[9733]=J;c[J+4>>2]=I|1;c[K+4>>2]=o|3;K=K+8|0;i=L;return K|0}if(!(c[9845]|0)){c[9847]=4096;c[9846]=4096;c[9848]=-1;c[9849]=-1;c[9850]=0;c[9838]=0;a=p&-16^1431655768;c[p>>2]=a;c[9845]=a;a=4096}else a=c[9847]|0;k=o+48|0;l=o+47|0;h=a+l|0;f=0-a|0;m=h&f;if(m>>>0<=o>>>0){K=0;i=L;return K|0}a=c[9837]|0;if(a|0?(B=c[9835]|0,C=B+m|0,C>>>0<=B>>>0|C>>>0>a>>>0):0){K=0;i=L;return K|0}b:do if(!(c[9838]&4)){d=c[9733]|0;c:do if(d){e=39356;while(1){a=c[e>>2]|0;if(a>>>0<=d>>>0?(u=e+4|0,(a+(c[u>>2]|0)|0)>>>0>d>>>0):0)break;a=c[e+8>>2]|0;if(!a){D=172;break c}else e=a}d=h-j&f;if(d>>>0<2147483647){a=oc(d|0)|0;if((a|0)==((c[e>>2]|0)+(c[u>>2]|0)|0)){if((a|0)!=(-1|0)){h=d;g=a;D=190;break b}}else{b=d;D=180}}}else D=172;while(0);do if(((D|0)==172?(g=oc(0)|0,(g|0)!=(-1|0)):0)?(b=g,v=c[9846]|0,w=v+-1|0,b=((w&b|0)==0?0:(w+b&0-v)-b|0)+m|0,v=c[9835]|0,w=b+v|0,b>>>0>o>>>0&b>>>0<2147483647):0){C=c[9837]|0;if(C|0?w>>>0<=v>>>0|w>>>0>C>>>0:0)break;a=oc(b|0)|0;if((a|0)==(g|0)){h=b;D=190;break b}else D=180}while(0);d:do if((D|0)==180){d=0-b|0;do if(k>>>0>b>>>0&(b>>>0<2147483647&(a|0)!=(-1|0))?(x=c[9847]|0,x=l-b+x&0-x,x>>>0<2147483647):0)if((oc(x|0)|0)==(-1|0)){oc(d|0)|0;break d}else{b=x+b|0;break}while(0);if((a|0)!=(-1|0)){h=b;g=a;D=190;break b}}while(0);c[9838]=c[9838]|4;D=187}else D=187;while(0);if((((D|0)==187?m>>>0<2147483647:0)?(A=oc(m|0)|0,y=oc(0)|0,A>>>0>>0&((A|0)!=(-1|0)&(y|0)!=(-1|0))):0)?(z=y-A|0,z>>>0>(o+40|0)>>>0):0){h=z;g=A;D=190}if((D|0)==190){b=(c[9835]|0)+h|0;c[9835]=b;if(b>>>0>(c[9836]|0)>>>0)c[9836]=b;l=c[9733]|0;do if(l){b=39356;while(1){a=c[b>>2]|0;d=b+4|0;e=c[d>>2]|0;if((g|0)==(a+e|0)){D=200;break}f=c[b+8>>2]|0;if(!f)break;else b=f}if(((D|0)==200?(c[b+12>>2]&8|0)==0:0)?l>>>0>>0&l>>>0>=a>>>0:0){c[d>>2]=e+h;K=l+8|0;K=(K&7|0)==0?0:0-K&7;J=l+K|0;K=h-K+(c[9730]|0)|0;c[9733]=J;c[9730]=K;c[J+4>>2]=K|1;c[J+K+4>>2]=40;c[9734]=c[9849];break}b=c[9731]|0;if(g>>>0>>0){c[9731]=g;j=g}else j=b;a=g+h|0;b=39356;while(1){if((c[b>>2]|0)==(a|0)){D=208;break}b=c[b+8>>2]|0;if(!b){a=39356;break}}if((D|0)==208)if(!(c[b+12>>2]&8)){c[b>>2]=g;n=b+4|0;c[n>>2]=(c[n>>2]|0)+h;n=g+8|0;n=g+((n&7|0)==0?0:0-n&7)|0;b=a+8|0;b=a+((b&7|0)==0?0:0-b&7)|0;m=n+o|0;k=b-n-o|0;c[n+4>>2]=o|3;do if((b|0)!=(l|0)){if((b|0)==(c[9732]|0)){K=(c[9729]|0)+k|0;c[9729]=K;c[9732]=m;c[m+4>>2]=K|1;c[m+K>>2]=K;break}a=c[b+4>>2]|0;if((a&3|0)==1){h=a&-8;f=a>>>3;e:do if(a>>>0>=256){g=c[b+24>>2]|0;e=c[b+12>>2]|0;do if((e|0)==(b|0)){e=b+16|0;d=e+4|0;a=c[d>>2]|0;if(!a){a=c[e>>2]|0;if(!a){I=0;break}else d=e}while(1){e=a+20|0;f=c[e>>2]|0;if(f|0){a=f;d=e;continue}e=a+16|0;f=c[e>>2]|0;if(!f)break;else{a=f;d=e}}if(d>>>0>>0)fa();else{c[d>>2]=0;I=a;break}}else{f=c[b+8>>2]|0;if(f>>>0>>0)fa();a=f+12|0;if((c[a>>2]|0)!=(b|0))fa();d=e+8|0;if((c[d>>2]|0)==(b|0)){c[a>>2]=e;c[d>>2]=f;I=e;break}else fa()}while(0);if(!g)break;a=c[b+28>>2]|0;d=39212+(a<<2)|0;do if((b|0)!=(c[d>>2]|0)){if(g>>>0<(c[9731]|0)>>>0)fa();a=g+16|0;if((c[a>>2]|0)==(b|0))c[a>>2]=I;else c[g+20>>2]=I;if(!I)break e}else{c[d>>2]=I;if(I|0)break;c[9728]=c[9728]&~(1<>>0>>0)fa();c[I+24>>2]=g;a=b+16|0;d=c[a>>2]|0;do if(d|0)if(d>>>0>>0)fa();else{c[I+16>>2]=d;c[d+24>>2]=I;break}while(0);a=c[a+4>>2]|0;if(!a)break;if(a>>>0<(c[9731]|0)>>>0)fa();else{c[I+20>>2]=a;c[a+24>>2]=I;break}}else{d=c[b+8>>2]|0;e=c[b+12>>2]|0;a=38948+(f<<1<<2)|0;do if((d|0)!=(a|0)){if(d>>>0>>0)fa();if((c[d+12>>2]|0)==(b|0))break;fa()}while(0);if((e|0)==(d|0)){c[9727]=c[9727]&~(1<>>0>>0)fa();a=e+8|0;if((c[a>>2]|0)==(b|0)){F=a;break}fa()}while(0);c[d+12>>2]=e;c[F>>2]=d}while(0);b=b+h|0;f=h+k|0}else f=k;b=b+4|0;c[b>>2]=c[b>>2]&-2;c[m+4>>2]=f|1;c[m+f>>2]=f;b=f>>>3;if(f>>>0<256){d=38948+(b<<1<<2)|0;a=c[9727]|0;b=1<>2]|0;if(a>>>0>=(c[9731]|0)>>>0){J=a;K=b;break}fa()}while(0);c[K>>2]=m;c[J+12>>2]=m;c[m+8>>2]=J;c[m+12>>2]=d;break}b=f>>>8;do if(!b)b=0;else{if(f>>>0>16777215){b=31;break}J=(b+1048320|0)>>>16&8;K=b<>>16&4;K=K<>>16&2;b=14-(I|J|b)+(K<>>15)|0;b=f>>>(b+7|0)&1|b<<1}while(0);e=39212+(b<<2)|0;c[m+28>>2]=b;a=m+16|0;c[a+4>>2]=0;c[a>>2]=0;a=c[9728]|0;d=1<>2]=m;c[m+24>>2]=e;c[m+12>>2]=m;c[m+8>>2]=m;break}a=f<<((b|0)==31?0:25-(b>>>1)|0);e=c[e>>2]|0;while(1){if((c[e+4>>2]&-8|0)==(f|0)){D=278;break}d=e+16+(a>>>31<<2)|0;b=c[d>>2]|0;if(!b){D=275;break}else{a=a<<1;e=b}}if((D|0)==275)if(d>>>0<(c[9731]|0)>>>0)fa();else{c[d>>2]=m;c[m+24>>2]=e;c[m+12>>2]=m;c[m+8>>2]=m;break}else if((D|0)==278){b=e+8|0;a=c[b>>2]|0;K=c[9731]|0;if(a>>>0>=K>>>0&e>>>0>=K>>>0){c[a+12>>2]=m;c[b>>2]=m;c[m+8>>2]=a;c[m+12>>2]=e;c[m+24>>2]=0;break}else fa()}}else{K=(c[9730]|0)+k|0;c[9730]=K;c[9733]=m;c[m+4>>2]=K|1}while(0);K=n+8|0;i=L;return K|0}else a=39356;while(1){b=c[a>>2]|0;if(b>>>0<=l>>>0?(E=b+(c[a+4>>2]|0)|0,E>>>0>l>>>0):0)break;a=c[a+8>>2]|0}f=E+-47|0;a=f+8|0;a=f+((a&7|0)==0?0:0-a&7)|0;f=l+16|0;a=a>>>0>>0?l:a;b=a+8|0;d=g+8|0;d=(d&7|0)==0?0:0-d&7;K=g+d|0;d=h+-40-d|0;c[9733]=K;c[9730]=d;c[K+4>>2]=d|1;c[K+d+4>>2]=40;c[9734]=c[9849];d=a+4|0;c[d>>2]=27;c[b>>2]=c[9839];c[b+4>>2]=c[9840];c[b+8>>2]=c[9841];c[b+12>>2]=c[9842];c[9839]=g;c[9840]=h;c[9842]=0;c[9841]=b;b=a+24|0;do{b=b+4|0;c[b>>2]=7}while((b+4|0)>>>0>>0);if((a|0)!=(l|0)){g=a-l|0;c[d>>2]=c[d>>2]&-2;c[l+4>>2]=g|1;c[a>>2]=g;b=g>>>3;if(g>>>0<256){d=38948+(b<<1<<2)|0;a=c[9727]|0;b=1<>2]|0;if(a>>>0<(c[9731]|0)>>>0)fa();else{G=a;H=b}}else{c[9727]=a|b;G=d;H=d+8|0}c[H>>2]=l;c[G+12>>2]=l;c[l+8>>2]=G;c[l+12>>2]=d;break}b=g>>>8;if(b)if(g>>>0>16777215)d=31;else{J=(b+1048320|0)>>>16&8;K=b<>>16&4;K=K<>>16&2;d=14-(I|J|d)+(K<>>15)|0;d=g>>>(d+7|0)&1|d<<1}else d=0;e=39212+(d<<2)|0;c[l+28>>2]=d;c[l+20>>2]=0;c[f>>2]=0;b=c[9728]|0;a=1<>2]=l;c[l+24>>2]=e;c[l+12>>2]=l;c[l+8>>2]=l;break}a=g<<((d|0)==31?0:25-(d>>>1)|0);e=c[e>>2]|0;while(1){if((c[e+4>>2]&-8|0)==(g|0)){D=304;break}d=e+16+(a>>>31<<2)|0;b=c[d>>2]|0;if(!b){D=301;break}else{a=a<<1;e=b}}if((D|0)==301)if(d>>>0<(c[9731]|0)>>>0)fa();else{c[d>>2]=l;c[l+24>>2]=e;c[l+12>>2]=l;c[l+8>>2]=l;break}else if((D|0)==304){b=e+8|0;a=c[b>>2]|0;K=c[9731]|0;if(a>>>0>=K>>>0&e>>>0>=K>>>0){c[a+12>>2]=l;c[b>>2]=l;c[l+8>>2]=a;c[l+12>>2]=e;c[l+24>>2]=0;break}else fa()}}}else{K=c[9731]|0;if((K|0)==0|g>>>0>>0)c[9731]=g;c[9839]=g;c[9840]=h;c[9842]=0;c[9736]=c[9845];c[9735]=-1;b=0;do{K=38948+(b<<1<<2)|0;c[K+12>>2]=K;c[K+8>>2]=K;b=b+1|0}while((b|0)!=32);K=g+8|0;K=(K&7|0)==0?0:0-K&7;J=g+K|0;K=h+-40-K|0;c[9733]=J;c[9730]=K;c[J+4>>2]=K|1;c[J+K+4>>2]=40;c[9734]=c[9849]}while(0);b=c[9730]|0;if(b>>>0>o>>>0){I=b-o|0;c[9730]=I;K=c[9733]|0;J=K+o|0;c[9733]=J;c[J+4>>2]=I|1;c[K+4>>2]=o|3;K=K+8|0;i=L;return K|0}}c[(Ob()|0)>>2]=12;K=0;i=L;return K|0}function fc(a){a=a|0;var b=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0;if(!a)return;d=a+-8|0;h=c[9731]|0;if(d>>>0>>0)fa();a=c[a+-4>>2]|0;b=a&3;if((b|0)==1)fa();e=a&-8;n=d+e|0;do if(!(a&1)){a=c[d>>2]|0;if(!b)return;k=d+(0-a)|0;j=a+e|0;if(k>>>0>>0)fa();if((k|0)==(c[9732]|0)){a=n+4|0;b=c[a>>2]|0;if((b&3|0)!=3){q=k;f=j;break}c[9729]=j;c[a>>2]=b&-2;c[k+4>>2]=j|1;c[k+j>>2]=j;return}e=a>>>3;if(a>>>0<256){b=c[k+8>>2]|0;d=c[k+12>>2]|0;a=38948+(e<<1<<2)|0;if((b|0)!=(a|0)){if(b>>>0>>0)fa();if((c[b+12>>2]|0)!=(k|0))fa()}if((d|0)==(b|0)){c[9727]=c[9727]&~(1<>>0>>0)fa();a=d+8|0;if((c[a>>2]|0)==(k|0))g=a;else fa()}else g=d+8|0;c[b+12>>2]=d;c[g>>2]=b;q=k;f=j;break}g=c[k+24>>2]|0;d=c[k+12>>2]|0;do if((d|0)==(k|0)){d=k+16|0;b=d+4|0;a=c[b>>2]|0;if(!a){a=c[d>>2]|0;if(!a){i=0;break}else b=d}while(1){d=a+20|0;e=c[d>>2]|0;if(e|0){a=e;b=d;continue}d=a+16|0;e=c[d>>2]|0;if(!e)break;else{a=e;b=d}}if(b>>>0>>0)fa();else{c[b>>2]=0;i=a;break}}else{e=c[k+8>>2]|0;if(e>>>0>>0)fa();a=e+12|0;if((c[a>>2]|0)!=(k|0))fa();b=d+8|0;if((c[b>>2]|0)==(k|0)){c[a>>2]=d;c[b>>2]=e;i=d;break}else fa()}while(0);if(g){a=c[k+28>>2]|0;b=39212+(a<<2)|0;if((k|0)==(c[b>>2]|0)){c[b>>2]=i;if(!i){c[9728]=c[9728]&~(1<>>0<(c[9731]|0)>>>0)fa();a=g+16|0;if((c[a>>2]|0)==(k|0))c[a>>2]=i;else c[g+20>>2]=i;if(!i){q=k;f=j;break}}d=c[9731]|0;if(i>>>0>>0)fa();c[i+24>>2]=g;a=k+16|0;b=c[a>>2]|0;do if(b|0)if(b>>>0>>0)fa();else{c[i+16>>2]=b;c[b+24>>2]=i;break}while(0);a=c[a+4>>2]|0;if(a)if(a>>>0<(c[9731]|0)>>>0)fa();else{c[i+20>>2]=a;c[a+24>>2]=i;q=k;f=j;break}else{q=k;f=j}}else{q=k;f=j}}else{q=d;f=e}while(0);if(q>>>0>=n>>>0)fa();a=n+4|0;b=c[a>>2]|0;if(!(b&1))fa();if(!(b&2)){if((n|0)==(c[9733]|0)){p=(c[9730]|0)+f|0;c[9730]=p;c[9733]=q;c[q+4>>2]=p|1;if((q|0)!=(c[9732]|0))return;c[9732]=0;c[9729]=0;return}if((n|0)==(c[9732]|0)){p=(c[9729]|0)+f|0;c[9729]=p;c[9732]=q;c[q+4>>2]=p|1;c[q+p>>2]=p;return}f=(b&-8)+f|0;e=b>>>3;do if(b>>>0>=256){g=c[n+24>>2]|0;a=c[n+12>>2]|0;do if((a|0)==(n|0)){d=n+16|0;b=d+4|0;a=c[b>>2]|0;if(!a){a=c[d>>2]|0;if(!a){m=0;break}else b=d}while(1){d=a+20|0;e=c[d>>2]|0;if(e|0){a=e;b=d;continue}d=a+16|0;e=c[d>>2]|0;if(!e)break;else{a=e;b=d}}if(b>>>0<(c[9731]|0)>>>0)fa();else{c[b>>2]=0;m=a;break}}else{b=c[n+8>>2]|0;if(b>>>0<(c[9731]|0)>>>0)fa();d=b+12|0;if((c[d>>2]|0)!=(n|0))fa();e=a+8|0;if((c[e>>2]|0)==(n|0)){c[d>>2]=a;c[e>>2]=b;m=a;break}else fa()}while(0);if(g|0){a=c[n+28>>2]|0;b=39212+(a<<2)|0;if((n|0)==(c[b>>2]|0)){c[b>>2]=m;if(!m){c[9728]=c[9728]&~(1<>>0<(c[9731]|0)>>>0)fa();a=g+16|0;if((c[a>>2]|0)==(n|0))c[a>>2]=m;else c[g+20>>2]=m;if(!m)break}d=c[9731]|0;if(m>>>0>>0)fa();c[m+24>>2]=g;a=n+16|0;b=c[a>>2]|0;do if(b|0)if(b>>>0>>0)fa();else{c[m+16>>2]=b;c[b+24>>2]=m;break}while(0);a=c[a+4>>2]|0;if(a|0)if(a>>>0<(c[9731]|0)>>>0)fa();else{c[m+20>>2]=a;c[a+24>>2]=m;break}}}else{b=c[n+8>>2]|0;d=c[n+12>>2]|0;a=38948+(e<<1<<2)|0;if((b|0)!=(a|0)){if(b>>>0<(c[9731]|0)>>>0)fa();if((c[b+12>>2]|0)!=(n|0))fa()}if((d|0)==(b|0)){c[9727]=c[9727]&~(1<>>0<(c[9731]|0)>>>0)fa();a=d+8|0;if((c[a>>2]|0)==(n|0))l=a;else fa()}else l=d+8|0;c[b+12>>2]=d;c[l>>2]=b}while(0);c[q+4>>2]=f|1;c[q+f>>2]=f;if((q|0)==(c[9732]|0)){c[9729]=f;return}}else{c[a>>2]=b&-2;c[q+4>>2]=f|1;c[q+f>>2]=f}a=f>>>3;if(f>>>0<256){d=38948+(a<<1<<2)|0;b=c[9727]|0;a=1<>2]|0;if(b>>>0<(c[9731]|0)>>>0)fa();else{o=b;p=a}}else{c[9727]=b|a;o=d;p=d+8|0}c[p>>2]=q;c[o+12>>2]=q;c[q+8>>2]=o;c[q+12>>2]=d;return}a=f>>>8;if(a)if(f>>>0>16777215)a=31;else{o=(a+1048320|0)>>>16&8;p=a<>>16&4;p=p<>>16&2;a=14-(n|o|a)+(p<>>15)|0;a=f>>>(a+7|0)&1|a<<1}else a=0;e=39212+(a<<2)|0;c[q+28>>2]=a;c[q+20>>2]=0;c[q+16>>2]=0;b=c[9728]|0;d=1<>>1)|0);e=c[e>>2]|0;while(1){if((c[e+4>>2]&-8|0)==(f|0)){a=130;break}d=e+16+(b>>>31<<2)|0;a=c[d>>2]|0;if(!a){a=127;break}else{b=b<<1;e=a}}if((a|0)==127)if(d>>>0<(c[9731]|0)>>>0)fa();else{c[d>>2]=q;c[q+24>>2]=e;c[q+12>>2]=q;c[q+8>>2]=q;break}else if((a|0)==130){a=e+8|0;b=c[a>>2]|0;p=c[9731]|0;if(b>>>0>=p>>>0&e>>>0>=p>>>0){c[b+12>>2]=q;c[a>>2]=q;c[q+8>>2]=b;c[q+12>>2]=e;c[q+24>>2]=0;break}else fa()}}else{c[9728]=b|d;c[e>>2]=q;c[q+24>>2]=e;c[q+12>>2]=q;c[q+8>>2]=q}while(0);q=(c[9735]|0)+-1|0;c[9735]=q;if(!q)a=39364;else return;while(1){a=c[a>>2]|0;if(!a)break;else a=a+8|0}c[9735]=-1;return}function gc(){}function hc(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;d=b-d-(c>>>0>a>>>0|0)>>>0;return (C=d,a-c>>>0|0)|0}function ic(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,i=0;f=b+e|0;if((e|0)>=20){d=d&255;h=b&3;i=d|d<<8|d<<16|d<<24;g=f&~3;if(h){h=b+4-h|0;while((b|0)<(h|0)){a[b>>0]=d;b=b+1|0}}while((b|0)<(g|0)){c[b>>2]=i;b=b+4|0}}while((b|0)<(f|0)){a[b>>0]=d;b=b+1|0}return b-e|0}function jc(a,b,c){a=a|0;b=b|0;c=c|0;if((c|0)<32){C=b>>>c;return a>>>c|(b&(1<>>c-32|0}function kc(a,b,c){a=a|0;b=b|0;c=c|0;if((c|0)<32){C=b<>>32-c;return a<>>16;a=(c>>>16)+(R(e,d)|0)|0;e=b>>>16;b=R(e,f)|0;return (C=(a>>>16)+(R(e,d)|0)+(((a&65535)+b|0)>>>16)|0,a+b<<16|c&65535|0)|0}function mc(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0,f=0;e=a;f=c;c=lc(e,f)|0;a=C;return (C=(R(b,f)|0)+(R(d,e)|0)+a|a&0,c|0|0)|0}function nc(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;c=a+c>>>0;return (C=b+d+(c>>>0>>0|0)>>>0,c|0)|0}function oc(a){a=a|0;var b=0,d=0;d=a+15&-16|0;b=c[k>>2]|0;a=b+d|0;if((d|0)>0&(a|0)<(b|0)|(a|0)<0){Z()|0;sa(12);return -1}c[k>>2]=a;if((a|0)>(Y()|0)?(X()|0)==0:0){sa(12);c[k>>2]=b;return -1}return b|0}function pc(a){a=a|0;return (a&255)<<24|(a>>8&255)<<16|(a>>16&255)<<8|a>>>24|0}function qc(b,d,e){b=b|0;d=d|0;e=e|0;var f=0;if((e|0)>=4096)return la(b|0,d|0,e|0)|0;f=b|0;if((b&3)==(d&3)){while(b&3){if(!e)return f|0;a[b>>0]=a[d>>0]|0;b=b+1|0;d=d+1|0;e=e-1|0}while((e|0)>=4){c[b>>2]=c[d>>2];b=b+4|0;d=d+4|0;e=e-4|0}}while((e|0)>0){a[b>>0]=a[d>>0]|0;b=b+1|0;d=d+1|0;e=e-1|0}return f|0}function rc(){return 0}function sc(a,b){a=a|0;b=b|0;return ua[a&1](b|0)|0}function tc(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;return va[a&7](b|0,c|0,d|0)|0}function uc(a,b){a=a|0;b=b|0;wa[a&3](b|0)}function vc(a){a=a|0;V(0);return 0}function wc(a,b,c){a=a|0;b=b|0;c=c|0;V(1);return 0}function xc(a){a=a|0;V(2)} +function xa(a){a=a|0;var b=0;b=i;i=i+a|0;i=i+15&-16;return b|0}function ya(){return i|0}function za(a){a=a|0;i=a}function Aa(a,b){a=a|0;b=b|0;i=a;j=b}function Ba(a,b){a=a|0;b=b|0;if(!n){n=a;o=b}}function Ca(a){a=a|0;C=a}function Da(){return C|0}function Ea(b,c){b=b|0;c=c|0;a[b>>0]=c>>>24;a[b+1>>0]=c>>>16;a[b+2>>0]=c>>>8;a[b+3>>0]=c;return}function Fa(a,b){a=a|0;b=b|0;var e=0,f=0,g=0,h=0;e=0;f=0;do{h=a+(7-f<<2)|0;h=(d[h+1>>0]|0)<<16|(d[h>>0]|0)<<24|(d[h+2>>0]|0)<<8|(d[h+3>>0]|0);g=f<<1;c[b+(f<<2)>>2]=(h<>>(30-g|0);f=f+1|0}while((f|0)!=8);c[b+32>>2]=e;return}function Ga(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0;e=c[b+32>>2]<<16;f=0;while(1){g=c[b+(7-f<<2)>>2]|0;h=f<<1;i=g>>>(14-h|0)|e;e=d+(f<<2)|0;a[e>>0]=i>>>24;a[e+1>>0]=i>>>16;a[e+2>>0]=i>>>8;a[e+3>>0]=i;f=f+1|0;if((f|0)==8)break;else e=g<>2]=0;a=a+4|0}while((a|0)<(b|0));return}function Ia(a){a=a|0;return (c[a+32>>2]|(c[a+28>>2]|(c[a+24>>2]|(c[a+20>>2]|(c[a+16>>2]|(c[a+12>>2]|(c[a+8>>2]|(c[a+4>>2]|c[a>>2])))))))|0)==0|0}function Ja(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0;d=0;e=8;f=0;while(1){h=c[a+(e<<2)>>2]|0;g=c[b+(e<<2)>>2]|0;d=h>>>0>>0|d<<1;f=h>>>0>g>>>0|f<<1;if((e|0)<=0)break;else e=e+-1|0}return d>>>0>f>>>0|0}function Ka(a,b){a=a|0;b=b|0;var d=0,e=0;d=0;e=0;do{e=c[b+(d<<2)>>2]^c[a+(d<<2)>>2]|e;d=d+1|0}while((d|0)!=9);return (e|0)==0|0}function La(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0;g=0-b|0;h=b+-1|0;if((b|1|0)==1)f=0;else pa(38200,38223,270,38235);do{c[a+(f<<2)>>2]=c[e+(f<<2)>>2]&h|c[d+(f<<2)>>2]&g;f=f+1|0}while((f|0)!=9);return}function Ma(a){a=a|0;var b=0,d=0,e=0,f=0;b=8;d=c[a+32>>2]|0;do{e=b;b=b+-1|0;f=d;d=c[a+(b<<2)>>2]|0;c[a+(e<<2)>>2]=d>>>29&1|f<<1&1073741822}while((e|0)>1);c[a>>2]=c[a>>2]<<1&1073741822;return}function Na(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,i=0;d=c[a>>2]|0;f=0-(d&1)|0;d=((c[b>>2]&f)+d|0)>>>1;e=0;do{i=e;e=e+1|0;g=(c[b+(e<<2)>>2]&f)+(c[a+(e<<2)>>2]|0)|0;h=(g<<29&536870912)+d|0;c[a+(i<<2)>>2]=h&1073741823;d=(h>>>30)+(g>>>1)|0}while((e|0)!=8);c[a+32>>2]=d;return}function Oa(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0;e=b&255;b=0;do{f=a+(b<<2)|0;c[f>>2]=R(c[f>>2]|0,e)|0;b=b+1|0}while((b|0)!=9);Pa(a,d);return}function Pa(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0;g=(c[a+32>>2]|0)>>>16;i=c[a>>2]|0;h=pc(c[b>>2]|0,0,g|0,0)|0;d=C;e=kc(i|0,536870912,h|0,d|0)|0;f=C;d=kc(i|0,0,h|0,d|0)|0;c[a>>2]=d&1073741823;d=1;while(1){l=mc(e|0,f|0,30)|0;k=C;i=a+(d<<2)|0;j=c[i>>2]|0;f=pc(c[b+(d<<2)>>2]|0,0,g|0,0)|0;h=C;k=qc(l|0,k|0,-2147483648,536870911)|0;j=qc(k|0,C|0,j|0,0)|0;e=kc(j|0,C|0,f|0,h|0)|0;c[i>>2]=e&1073741823;d=d+1|0;if((d|0)==9)break;else f=C}return}function Qa(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0;h=i;i=i+48|0;g=h;d=0;e=8;f=0;while(1){k=c[a+(e<<2)>>2]|0;j=c[b+(e<<2)>>2]|0;d=k>>>0>>0|d<<1;f=k>>>0>j>>>0|f<<1;if((e|0)<=0)break;else e=e+-1|0}f=d>>>0>f>>>0;e=0;d=1;while(1){d=d+1073741823+(c[a+(e<<2)>>2]|0)-(c[b+(e<<2)>>2]|0)|0;c[g+(e<<2)>>2]=d&1073741823;e=e+1|0;if((e|0)==9)break;else d=d>>>30}La(a,f&1,a,g);i=h;return}function Ra(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0;f=0;e=1;while(1){e=e+1073741823+(c[a+(f<<2)>>2]|0)-(c[b+(f<<2)>>2]|0)|0;c[d+(f<<2)>>2]=e&1073741823;f=f+1|0;if((f|0)==9)break;else e=e>>>30}return}function Sa(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0,j=0;h=0;g=0;e=0;i=1;while(1){f=0;do{j=pc(c[b+(h-f<<2)>>2]|0,0,c[a+(f<<2)>>2]|0,0)|0;g=qc(j|0,C|0,g|0,e|0)|0;e=C;f=f+1|0}while((f|0)!=(i|0));c[d+(h<<2)>>2]=g&1073741823;g=mc(g|0,e|0,30)|0;e=C;h=h+1|0;if((h|0)==9){h=9;break}else i=i+1|0}while(1){f=h+-8|0;if((f|0)<9)do{j=pc(c[b+(h-f<<2)>>2]|0,0,c[a+(f<<2)>>2]|0,0)|0;g=qc(j|0,C|0,g|0,e|0)|0;e=C;f=f+1|0}while((f|0)!=9);c[d+(h<<2)>>2]=g&1073741823;g=mc(g|0,e|0,30)|0;h=h+1|0;if((h|0)==17)break;else e=C}c[d+68>>2]=g;return}function Ta(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0;l=a+(d+1<<2)|0;j=(c[l>>2]<<14)+((c[a+(d<<2)>>2]|0)>>>16)|0;k=d+-8|0;e=a+(k<<2)|0;f=c[e>>2]|0;g=pc(c[b>>2]|0,0,j|0,0)|0;h=C;if((j|0)<=-1)pa(38243,38223,417,38262);i=kc(f|0,536870912,g|0,h|0)|0;m=C;h=kc(f|0,0,g|0,h|0)|0;c[e>>2]=h&1073741823;h=mc(i|0,m|0,30)|0;m=C;i=a+(d+-7<<2)|0;f=qc(c[i>>2]|0,0,-2147483648,536870911)|0;e=1;g=C;d=m;do{m=pc(c[b+(e<<2)>>2]|0,0,j|0,0)|0;m=kc(f|0,g|0,m|0,C|0)|0;m=qc(m|0,C|0,h|0,d|0)|0;c[i>>2]=m&1073741823;e=e+1|0;h=mc(m|0,C|0,30)|0;d=C;i=a+(e+k<<2)|0;f=qc(c[i>>2]|0,0,-2147483648,536870911)|0;g=C}while((e|0)!=9);m=qc(f|0,g|0,h|0,d|0)|0;c[l>>2]=m&1073741823;return}function Ua(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0;e=16;while(1){Ta(b,d,e);if(c[b+(e+1<<2)>>2]|0){g=4;break}e=e+-1|0;if((e|0)<=7){f=0;break}}if((g|0)==4)pa(38286,38223,451,38302);do{c[a+(f<<2)>>2]=c[b+(f<<2)>>2];f=f+1|0}while((f|0)!=9);return}function Va(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0;g=i;i=i+80|0;e=g;f=e;h=f+72|0;do{c[f>>2]=0;f=f+4|0}while((f|0)<(h|0));Sa(a,b,e);Ua(b,e,d);i=g;return}function Wa(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0;n=i;i=i+144|0;k=n+72|0;l=n+36|0;m=n;c[l>>2]=1;h=l+4|0;c[h>>2]=0;c[h+4>>2]=0;c[h+8>>2]=0;c[h+12>>2]=0;c[h+16>>2]=0;c[h+20>>2]=0;c[h+24>>2]=0;c[h+28>>2]=0;h=m;d=b;j=h+36|0;do{c[h>>2]=c[d>>2];h=h+4|0;d=d+4|0}while((h|0)<(j|0));e=0;d=1;while(1){j=m+(e<<2)|0;d=(c[j>>2]|0)+d|0;c[j>>2]=d&1073741823;e=e+1|0;if((e|0)==9)break;else d=d>>>30}d=0;e=c[m>>2]|0;do{j=d;d=d+1|0;h=e;e=c[m+(d<<2)>>2]|0;c[m+(j<<2)>>2]=e<<29&536870912|h>>>1}while((d|0)!=8);e=m+32|0;c[e>>2]=(c[e>>2]|0)>>>1;d=0;f=c[m>>2]|0;do{j=d;d=d+1|0;h=f;f=c[m+(d<<2)>>2]|0;c[m+(j<<2)>>2]=f<<29&536870912|h>>>1}while((d|0)!=8);c[e>>2]=(c[e>>2]|0)>>>1;e=0;do{g=(e|0)==8;d=0;f=c[m+(e<<2)>>2]|0;do{if(g&(f|0)==0)break;if(f&1|0){h=k;j=h+72|0;do{c[h>>2]=0;h=h+4|0}while((h|0)<(j|0));Sa(a,l,k);Ua(l,k,b)}f=f>>>1;h=k;j=h+72|0;do{c[h>>2]=0;h=h+4|0}while((h|0)<(j|0));Sa(a,a,k);Ua(a,k,b);d=d+1|0}while(d>>>0<30);e=e+1|0}while((e|0)!=9);Qa(l,b);h=a;d=l;j=h+36|0;do{c[h>>2]=c[d>>2];h=h+4|0;d=d+4|0}while((h|0)<(j|0));i=n;return}function Xa(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0;v=i;i=i+112|0;d=v+72|0;u=v+32|0;t=v;Pa(a,b);Qa(a,b);e=c[b>>2]|0;f=0;while(1){r=f;f=f+1|0;g=c[b+(f<<2)>>2]|0;h=r<<1;p=g<<30-h|e;c[t+(r<<2)>>2]=p;c[d+(r<<2)>>2]=p;if((f|0)==8)break;else e=g>>>(h+2|0)}e=c[a>>2]|0;f=0;while(1){r=f;f=f+1|0;b=c[a+(f<<2)>>2]|0;g=r<<1;c[u+(r<<2)>>2]=b<<30-g|e;if((f|0)==8)break;else e=b>>>(g+2|0)}o=d+36|0;c[o>>2]=8;p=u+36|0;c[p>>2]=8;r=d+32|0;c[r>>2]=1;c[u+32>>2]=0;f=0;n=u;e=8;g=c[d>>2]|0;b=1;a:while(1){if(!(g&1)){q=7;break}if(!(b&1)){q=10;break}l=n+36|0;b=e;while(1){e=b+-1|0;if(c[n+(e<<2)>>2]|0)break;c[l>>2]=e;if((b|0)<1)break a;else b=e}e=c[n>>2]|0;if(!e){g=n+32|0;do{e=0;do{m=e;e=e+1|0;c[n+(m<<2)>>2]=c[n+(e<<2)>>2]}while((e|0)!=8);c[g>>2]=0;b=(c[l>>2]|0)+-1|0;c[l>>2]=b;f=f+32|0;e=c[n>>2]|0}while((e|0)==0)}k=0;while(1)if(!(e&1<0){e=e>>>k;if((b|0)>1){j=32-k|0;g=1;h=n;while(1){b=n+(g<<2)|0;c[h>>2]=c[b>>2]<>2]|0)>>>k;if((e|0)<(c[l>>2]|0)){g=e;e=h;h=b}else break}}else{g=0;h=e;b=n;e=1}c[b>>2]=h;if(!h)c[l>>2]=(c[l>>2]|0)+-1;else g=e;e=n+(g<<2)|0;b=c[e>>2]<>2]=(c[e>>2]|0)>>>h|b;b=c[e>>2]<>2]=b;m=k+f|0}else m=f;if(!(c[n>>2]&1)){q=32;break}if(c[n+32>>2]&1|0){q=34;break}f=c[o>>2]|0;e=f-(c[p>>2]|0)|0;if(!e){e=f;while(1){b=e+-1|0;if((e|0)<=0){q=38;break}e=c[d+(b<<2)>>2]|0;f=u+(b<<2)|0;if((e|0)==(c[f>>2]|0))e=b;else break}if((q|0)==38){q=0;if(!e){q=56;break}f=u+(b<<2)|0;e=c[d+(b<<2)>>2]|0}e=e>>>0>(c[f>>2]|0)>>>0?1:-1}n=(e|0)>0;l=n?u:d;n=n?d:u;k=l+36|0;h=c[k>>2]|0;if((h|0)>0){e=0;f=1;b=0;while(1){j=n+(e<<2)|0;w=c[j>>2]|0;g=c[l+(e<<2)>>2]|0;f=qc(f|0,b|0,-1,0)|0;f=qc(f|0,C|0,w|0,0)|0;g=kc(f|0,C|0,g|0,0)|0;f=C;c[j>>2]=g;e=e+1|0;if((e|0)<(h|0))b=0;else{b=e;g=0;break}}}else{b=0;f=1;g=0}j=n+36|0;e=c[j>>2]|0;if((b|0)<(e|0)){e=g;while(1){w=n+(b<<2)|0;g=c[w>>2]|0;e=qc(f|0,e|0,-1,0)|0;e=qc(e|0,C|0,g|0,0)|0;c[w>>2]=e;b=b+1|0;e=c[j>>2]|0;if((b|0)>=(e|0))break;else{f=C;e=0}}}if((e|0)>8){f=8;g=0;b=0}else{f=8;g=0;b=0;while(1){w=l+(f<<2)|0;j=c[n+(f<<2)>>2]|0;h=qc(c[w>>2]|0,0,g|0,b|0)|0;j=qc(h|0,C|0,j|0,0)|0;g=C;c[w>>2]=j;w=f;f=f+-1|0;if((w|0)<=(e|0))break;else b=0}h=c[k>>2]|0;b=0}if((f|0)>=(h|0))while(1){w=l+(f<<2)|0;j=qc(c[w>>2]|0,0,g|0,b|0)|0;c[w>>2]=j;if((f|0)>(c[k>>2]|0)){f=f+-1|0;g=C;b=0}else break}g=c[l>>2]|0;if(!(g&1)){q=51;break}b=c[l+32>>2]|0;if(!(b&1)){q=53;break}if(c[n>>2]&1|0){q=55;break}else f=m}if((q|0)==7)pa(38321,38223,646,38335);else if((q|0)==10)pa(38346,38223,647,38335);else if((q|0)==32)pa(38360,38223,699,38335);else if((q|0)==34)pa(38375,38223,700,38335);else if((q|0)==51)pa(38321,38223,757,38335);else if((q|0)==53)pa(38346,38223,758,38335);else if((q|0)==55)pa(38397,38223,759,38335);else if((q|0)==56){l=c[t>>2]|0;if(!(l&1))pa(38419,38223,786,38335);f=l+-1|0;e=l+-2|0;if(!f)k=e;else{do{f=R(f,f)|0;e=R(f+1|0,e)|0}while((f|0)!=0);k=e}b:do if((m|0)>31){j=d+4|0;e=m;while(1){w=c[r>>2]|0;b=R(w,k)|0;q=pc(l|0,0,b|0,0)|0;w=qc(q|0,C|0,w|0,0)|0;if(!((w|0)==0&0==0))break;f=0;g=C;h=0;while(1){w=f;f=f+1|0;o=c[d+(7-w<<2)>>2]|0;p=pc(c[t+(f<<2)>>2]|0,0,b|0,0)|0;q=C;o=qc(o|0,0,g|0,h|0)|0;q=qc(o|0,C|0,p|0,q|0)|0;g=C;c[d+(8-w<<2)>>2]=q;if((f|0)==7)break;else h=0}c[j>>2]=g;e=e+-32|0;if((e|0)<=31){s=e;break b}}pa(38429,38223,802,38335)}else s=m;while(0);if((s|0)>0){w=(1<>2]|0;h=(R(e,k)|0)&w;if((R(h,l)|0)+e&w|0)pa(38454,38223,821,38335);b=pc(h|0,0,l|0,0)|0;b=qc(b|0,C|0,e|0,0)|0;b=mc(b|0,C|0,s|0)|0;f=32-s|0;e=0;g=C;while(1){w=e;e=e+1|0;s=c[d+(7-w<<2)>>2]|0;r=pc(c[t+(e<<2)>>2]|0,0,h|0,0)|0;s=qc(r|0,C|0,s|0,0)|0;s=nc(s|0,C|0,f|0)|0;s=qc(s|0,C|0,b|0,g|0)|0;b=C;c[d+(8-w<<2)>>2]=s;if((e|0)==7)break;else g=0}c[d+4>>2]=b;e=0;f=0}else{e=0;f=0}do{s=c[d+(8-e<<2)>>2]|0;w=e<<1;c[a+(e<<2)>>2]=s<>>(30-w|0);e=e+1|0}while((e|0)!=8);c[a+32>>2]=f;c[t>>2]=0;c[t+4>>2]=0;c[t+8>>2]=0;c[t+12>>2]=0;c[t+16>>2]=0;c[t+20>>2]=0;c[t+24>>2]=0;c[t+28>>2]=0;e=d+40|0;do{c[d>>2]=0;d=d+4|0}while((d|0)<(e|0));d=u;e=d+40|0;do{c[d>>2]=0;d=d+4|0}while((d|0)<(e|0))}i=v;return}function Ya(a,b){a=a|0;b=b|0;var d=0,e=0,f=0;e=0;d=0;while(1){f=a+(e<<2)|0;d=(c[f>>2]|0)+d+(c[b+(e<<2)>>2]|0)|0;c[f>>2]=d&1073741823;e=e+1|0;if((e|0)==9)break;else d=d>>>30}return}function Za(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0;e=0;do{f=a+(e<<2)|0;c[f>>2]=(c[f>>2]|0)+(c[b+(e<<2)>>2]|0);e=e+1|0}while((e|0)!=9);Pa(a,d);return}function _a(a,b,d){a=a|0;b=b|0;d=d|0;var e=0;if((c[d>>2]|0)>>>0>>0)pa(38495,38223,883,38514);b=(c[a>>2]|0)-b|0;c[a>>2]=b;b=b+(c[d>>2]|0)|0;c[a>>2]=b&1073741823;e=1;do{b=(c[a+(e<<2)>>2]|0)+(b>>>30)+(c[d+(e<<2)>>2]|0)|0;c[a+(e<<2)>>2]=b&1073741823;e=e+1|0}while((e|0)!=9);return}function $a(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0;g=0;f=1;while(1){f=f+1073741823+(c[a+(g<<2)>>2]|0)+(c[e+(g<<2)>>2]<<1)-(c[b+(g<<2)>>2]|0)|0;c[d+(g<<2)>>2]=f&1073741823;g=g+1|0;if((g|0)==9)break;else f=f>>>30}return}function ab(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0;n=i;i=i+144|0;k=n+108|0;e=n+72|0;l=n+36|0;m=n;do if(!(bb(b)|0)){if(bb(d)|0){e=d;f=b;g=e+72|0;do{c[e>>2]=c[f>>2];e=e+4|0;f=f+4|0}while((e|0)<(g|0));break}if(cb(b,d)|0){db(a,d);break}if(!(eb(b,d)|0)){$a(d,b,e,a);Xa(e,a);h=d+36|0;j=b+36|0;$a(h,j,k,a);Va(e,k,a);e=l;f=k;g=e+36|0;do{c[e>>2]=c[f>>2];e=e+4|0;f=f+4|0}while((e|0)<(g|0));Va(l,l,a);e=m;f=b;g=e+36|0;do{c[e>>2]=c[f>>2];e=e+4|0;f=f+4|0}while((e|0)<(g|0));Za(m,d,a);$a(l,m,l,a);Pa(l,a);Qa(l,a);$a(b,l,m,a);Va(k,m,a);$a(m,j,m,a);Pa(m,a);Qa(m,a);e=d;f=l;g=e+36|0;do{c[e>>2]=c[f>>2];e=e+4|0;f=f+4|0}while((e|0)<(g|0));e=h;f=m;g=e+36|0;do{c[e>>2]=c[f>>2];e=e+4|0;f=f+4|0}while((e|0)<(g|0));break}else{Ha(d);Ha(d+36|0);break}}while(0);i=n;return}function bb(a){a=a|0;if(!(Ia(a)|0))a=0;else a=(Ia(a+36|0)|0)!=0;return a&1|0}function cb(a,b){a=a|0;b=b|0;if(!(Ka(a,b)|0))a=0;else a=(Ka(a+36|0,b+36|0)|0)!=0;return a&1|0}function db(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0,l=0;j=i;i=i+112|0;d=j+72|0;e=j+36|0;f=j;do if(!(bb(b)|0)){g=b+36|0;if(!(Ia(g)|0)){h=d;k=g;l=h+36|0;do{c[h>>2]=c[k>>2];h=h+4|0;k=k+4|0}while((h|0)<(l|0));Oa(d,2,a);Xa(d,a);h=e;k=b;l=h+36|0;do{c[h>>2]=c[k>>2];h=h+4|0;k=k+4|0}while((h|0)<(l|0));Va(e,e,a);Oa(e,3,a);_a(e,0-(c[a+180>>2]|0)|0,a);Va(e,d,a);h=e;k=d;l=h+36|0;do{c[h>>2]=c[k>>2];h=h+4|0;k=k+4|0}while((h|0)<(l|0));Va(e,e,a);h=f;k=b;l=h+36|0;do{c[h>>2]=c[k>>2];h=h+4|0;k=k+4|0}while((h|0)<(l|0));Ma(f);$a(e,f,e,a);Pa(e,a);Qa(e,a);$a(b,e,f,a);Va(d,f,a);$a(f,g,f,a);Pa(f,a);Qa(f,a);h=b;k=e;l=h+36|0;do{c[h>>2]=c[k>>2];h=h+4|0;k=k+4|0}while((h|0)<(l|0));h=g;k=f;l=h+36|0;do{c[h>>2]=c[k>>2];h=h+4|0;k=k+4|0}while((h|0)<(l|0));break}else{Ha(b);Ha(g);break}}while(0);i=j;return}function eb(a,b){a=a|0;b=b|0;var c=0;if((Ka(a,b)|0)!=0?(c=a+36|0,(Ia(c)|0)==0):0)a=(Ka(c,b+36|0)|0)==0&1;else a=0;return a|0}function fb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0,j=0;g=b+32|0;if((c[g>>2]|0)>>>0>=131072)pa(38522,38542,180,38553);h=a&1073741823;f=~a;a=c[b>>2]|0;e=(c[d>>2]<<1)+1073741824-a|0;c[b>>2]=h&e|a&f;a=0;do{a=a+1|0;i=b+(a<<2)|0;j=c[i>>2]|0;e=(e>>>30)+1073741823+(c[d+(a<<2)>>2]<<1)-j|0;c[i>>2]=h&e|j&f}while((a|0)!=8);if((c[g>>2]|0)>>>0<131072)return;else pa(38522,38542,188,38553)}function gb(a,b){a=a|0;b=b|0;var d=0,e=0,f=0;e=a+32|0;while(1){d=0;f=Kb()|0;do{c[a+(d<<2)>>2]=f&1073741823;d=d+1|0;f=Kb()|0}while((d|0)!=8);c[e>>2]=f&65535;if(Ia(a)|0)continue;if(Ja(a,b)|0)break}return}function hb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0;e=b+72|0;gb(e,d);g=b;h=e;i=g+36|0;do{c[g>>2]=c[h>>2];g=g+4|0;h=h+4|0}while((g|0)<(i|0));Va(e,b,d);f=b+36|0;g=f;h=b;i=g+36|0;do{c[g>>2]=c[h>>2];g=g+4|0;h=h+4|0}while((g|0)<(i|0));Va(e,f,d);Va(a,b,d);Va(a+36|0,f,d);return}function ib(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0;e=b+36|0;f=e;g=a+72|0;h=f+36|0;do{c[f>>2]=c[g>>2];f=f+4|0;g=g+4|0}while((f|0)<(h|0));Xa(e,d);f=b;g=e;h=f+36|0;do{c[f>>2]=c[g>>2];f=f+4|0;g=g+4|0}while((f|0)<(h|0));Va(b,b,d);Va(b,e,d);Va(a,b,d);Va(a+36|0,e,d);Qa(b,d);Qa(e,d);return}function jb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0;s=i;i=i+288|0;k=s+252|0;l=s+216|0;m=s+180|0;n=s+144|0;o=s+108|0;p=s+72|0;q=s+36|0;g=s;e=c[d+180>>2]|0;if((e+3|0)>>>0>=4)pa(38572,38542,247,38590);h=b+72|0;r=p;t=h;u=r+36|0;do{c[r>>2]=c[t>>2];r=r+4|0;t=t+4|0}while((r|0)<(u|0));Va(p,p,d);r=q;t=h;u=r+36|0;do{c[r>>2]=c[t>>2];r=r+4|0;t=t+4|0}while((r|0)<(u|0));Va(p,q,d);j=(e|0)!=0;if(j){e=0-e|0;r=g;t=p;u=r+36|0;do{c[r>>2]=c[t>>2];r=r+4|0;t=t+4|0}while((r|0)<(u|0));Va(g,g,d);Oa(g,e&255,d)}Va(a,p,d);r=l;t=p;u=r+36|0;do{c[r>>2]=c[t>>2];r=r+4|0;t=t+4|0}while((r|0)<(u|0));$a(l,b,l,d);Pa(l,d);Ya(p,b);f=Ka(l,d)|0;Va(a+36|0,q,d);e=b+36|0;$a(q,e,k,d);Ya(q,e);r=m;t=b;u=r+36|0;do{c[r>>2]=c[t>>2];r=r+4|0;t=t+4|0}while((r|0)<(u|0));Va(m,m,d);Oa(m,3,d);if(j)$a(m,g,m,d);La(k,f,m,k);La(l,f,q,l);r=o;t=l;u=r+36|0;do{c[r>>2]=c[t>>2];r=r+4|0;t=t+4|0}while((r|0)<(u|0));Va(o,o,d);r=n;t=l;u=r+36|0;do{c[r>>2]=c[t>>2];r=r+4|0;t=t+4|0}while((r|0)<(u|0));Va(o,n,d);Va(p,o,d);Va(q,n,d);Va(l,h,d);r=b;t=k;u=r+36|0;do{c[r>>2]=c[t>>2];r=r+4|0;t=t+4|0}while((r|0)<(u|0));Va(b,b,d);$a(b,o,b,d);Pa(b,d);$a(o,b,e,d);$a(e,b,e,d);Va(k,e,d);$a(e,n,e,d);Na(e,d);Pa(e,d);i=s;return}function kb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0;n=i;i=i+144|0;l=n+108|0;m=n;if(!(Ja(b,a+108|0)|0))pa(38609,38542,552,38658);j=c[b>>2]|0;g=(j&1)+-1|0;f=1;e=0;h=j;do{k=f+1073741823+h-(c[a+108+(e<<2)>>2]&g)|0;c[l+(e<<2)>>2]=k&1073741823;f=k>>>30;e=e+1|0;h=c[b+(e<<2)>>2]|0;j=h|j}while((e|0)!=8);k=l+32|0;c[k>>2]=f+65535+h-(c[a+140>>2]&g);e=c[l>>2]|0;if(!(e&1))pa(38638,38542,575,38658);if(!j){Ha(d);Ha(d+36|0)}else{hb(a+220+((((e>>>4&1)+15^e)>>>1&7)*72|0)|0,m,a);h=m+36|0;g=1;do{f=0;e=e>>>4;b=l;do{f=f+1|0;j=b;b=l+(f<<2)|0;c[j>>2]=c[b>>2]<<26&1006632960|e;e=(c[b>>2]|0)>>>4}while((f|0)!=8);c[k>>2]=e;e=c[l>>2]|0;b=e>>>4&1;j=b+15^e;fb((j&1)+-1|0,h,a);jb(a+220+(g*576|0)+((j>>>1&7)*72|0)|0,m,a);g=g+1|0}while((g|0)!=64);fb(b+-1|0,h,a);ib(m,d,a)}i=n;return}function lb(b,c,d){b=b|0;c=c|0;d=d|0;b=(b|0)==0?712:b;switch(a[c>>0]|0){case 4:{Fa(c+1|0,d);Fa(c+33|0,d+36|0);b=mb(b,d)|0;break}case 3:case 2:{Fa(c+1|0,d);nb(b,a[c>>0]|0,d,d+36|0);b=mb(b,d)|0;break}default:b=0}return b|0}function mb(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0;k=i;i=i+80|0;d=k+36|0;e=k;if(((bb(b)|0)==0?(Ja(b,a)|0)!=0:0)?(f=b+36|0,(Ja(f,a)|0)!=0):0){g=d;h=f;j=g+36|0;do{c[g>>2]=c[h>>2];g=g+4|0;h=h+4|0}while((g|0)<(j|0));g=e;h=b;j=g+36|0;do{c[g>>2]=c[h>>2];g=g+4|0;h=h+4|0}while((g|0)<(j|0));Va(f,d,a);Qa(d,a);Va(b,e,a);_a(e,0-(c[a+180>>2]|0)|0,a);Va(b,e,a);Za(e,a+184|0,a);Qa(e,a);a=(Ka(e,d)|0)!=0&1}else a=0;i=k;return a|0}function nb(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0;f=e;g=d;h=f+36|0;do{c[f>>2]=c[g>>2];f=f+4|0;g=g+4|0}while((f|0)<(h|0));Va(d,e,a);_a(e,0-(c[a+180>>2]|0)|0,a);Va(d,e,a);Ya(e,a+184|0);Wa(e,a);if((c[e>>2]^b&255)&1|0)Ra(a,e,e);return}function ob(b,c){b=b|0;c=c|0;var d=0,e=0;e=i;i=i+32|0;d=e;switch(a[b>>0]|0){case 4:{Eb(b,65,d);break}case 0:{Eb(b,1,d);break}default:Eb(b,33,d)}Ab(d,32,c);i=e;return}function pb(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0,f=0,g=0,h=0;e=i;i=i+48|0;g=e;f=Lb(b)|0;h=Lb(b)|0;Mb(b,g);ob(a,g+h|0);wb(g,f+20|0,c,d)|0;i=e;return}function qb(b,c,e){b=b|0;c=c|0;e=e|0;var f=0,g=0,h=0,j=0;j=i;i=i+128|0;h=j;f=h;g=f+128|0;do{a[f>>0]=0;f=f+1|0}while((f|0)<(g|0));if(e>>>0>128){Jb(c,e,h);c=0}else{tc(h|0,c|0,e|0)|0;c=0}do{g=h+c|0;f=d[g>>0]|0;a[b+c>>0]=f^92;a[g>>0]=f^54;c=c+1|0}while((c|0)!=128);b=b+128|0;Fb(b);Hb(b,h,128);i=j;return}function rb(a,b){a=a|0;b=b|0;var c=0,d=0,e=0;c=i;i=i+64|0;e=c;d=a+128|0;Ib(d,e);Fb(d);Hb(d,a,128);Hb(d,e,64);Ib(d,b);lc(a|0,0,336)|0;i=c;return}function sb(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;var f=0,g=0;f=i;i=i+336|0;g=f;qb(g,a,b);Hb(g+128|0,c,d);rb(g,e);i=f;return}function tb(b,d,e,f,g,h){b=b|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;var j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0;r=i;i=i+144|0;o=r+104|0;p=r+40|0;q=r;if((f|0)<0)f=0;else{a[o>>0]=c[d+36>>2]&1|2;n=o+1|0;Ga(d,n);Ea(o+33|0,f);f=b+108|0;j=p+32|0;while(1){sb(e,32,o,37,p);Fa(p,q);if(Ja(q,f)|0?(kb(b,q,g),ab(b,d,g),(bb(g)|0)==0):0)break;a[o>>0]=1;k=n;l=j;m=k+32|0;do{a[k>>0]=a[l>>0]|0;k=k+1|0;l=l+1|0}while((k|0)<(m|0))}if(h|0){k=h;l=j;m=k+32|0;do{a[k>>0]=a[l>>0]|0;k=k+1|0;l=l+1|0}while((k|0)<(m|0))}k=o;m=k+37|0;do{a[k>>0]=0;k=k+1|0}while((k|0)<(m|0));k=p;m=k+64|0;do{a[k>>0]=0;k=k+1|0}while((k|0)<(m|0));k=q;m=k+36|0;do{c[k>>2]=0;k=k+4|0}while((k|0)<(m|0));f=1}i=r;return f|0}function ub(b,d,e,f,g,h){b=b|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;var j=0,k=0,l=0;j=i;i=i+112|0;k=j+72|0;l=j;tb(712,b,d,e,l,0)|0;a[k>>0]=c[l+36>>2]&1|2;Ga(l,k+1|0);pb(k,f,g,h);i=j;return 1}function vb(b,e,f,g){b=b|0;e=e|0;f=f|0;g=g|0;var h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0;q=i;a:do if((g|0)>0){h=0;do{if(a[f+h>>0]|0)break a;h=h+1|0}while((h|0)<(g|0))}else h=0;while(0);o=(((g-h|0)*138|0)>>>0)/100|0;n=o+1|0;p=i;i=i+((1*n|0)+15&-16)|0;lc(p|0,0,n|0)|0;if((h|0)<(g|0)){j=o;m=h;do{k=a[f+m>>0]|0;if((o|0)>(j|0)|k<<24>>24!=0){k=k&255;l=o;while(1){r=p+l|0;k=(d[r>>0]<<8)+k|0;a[r>>0]=(k|0)%58|0;l=l+-1|0;if((l|0)>(j|0)|(k+57|0)>>>0>114)k=(k|0)/58|0;else{j=l;break}}}else j=o;m=m+1|0}while((m|0)!=(g|0));j=0}else j=0;while(1){if(a[p+j>>0]|0)break;k=j+1|0;if((j|0)<(o|0))j=k;else{j=k;break}}k=n+h-j|0;if((c[e>>2]|0)>>>0>k>>>0){if(!h)h=0;else lc(b|0,49,h|0)|0;if((j|0)<=(o|0))while(1){a[b+h>>0]=a[38674+(d[p+j>>0]|0)>>0]|0;h=h+1|0;if((j|0)<(o|0))j=j+1|0;else break}a[b+h>>0]=0;j=1}else{j=0;h=k}c[e>>2]=h+1;i=q;return j|0}function wb(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,j=0,k=0,l=0;g=i;i=i+16|0;f=g;if((b|0)>128)a=0;else{j=b+32|0;h=ia()|0;k=i;i=i+((1*j|0)+15&-16)|0;l=k+b|0;tc(k|0,a|0,b|0)|0;Eb(a,b,l);Eb(l,32,l);c[f>>2]=e;a=vb(d,f,k,b+4|0)|0;lc(k|0,0,j|0)|0;a=a?c[f>>2]|0:0;oa(h|0)}i=g;return a|0}function xb(a,b){a=a|0;b=b|0;var e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0;s=(d[b+1>>0]|0)<<8|(d[b>>0]|0)|(d[b+2>>0]|0)<<16|(d[b+3>>0]|0)<<24;D=(d[b+5>>0]|0)<<8|(d[b+4>>0]|0)|(d[b+6>>0]|0)<<16|(d[b+7>>0]|0)<<24;v=(d[b+9>>0]|0)<<8|(d[b+8>>0]|0)|(d[b+10>>0]|0)<<16|(d[b+11>>0]|0)<<24;f=(d[b+13>>0]|0)<<8|(d[b+12>>0]|0)|(d[b+14>>0]|0)<<16|(d[b+15>>0]|0)<<24;x=(d[b+17>>0]|0)<<8|(d[b+16>>0]|0)|(d[b+18>>0]|0)<<16|(d[b+19>>0]|0)<<24;t=(d[b+21>>0]|0)<<8|(d[b+20>>0]|0)|(d[b+22>>0]|0)<<16|(d[b+23>>0]|0)<<24;y=(d[b+25>>0]|0)<<8|(d[b+24>>0]|0)|(d[b+26>>0]|0)<<16|(d[b+27>>0]|0)<<24;z=(d[b+29>>0]|0)<<8|(d[b+28>>0]|0)|(d[b+30>>0]|0)<<16|(d[b+31>>0]|0)<<24;B=(d[b+33>>0]|0)<<8|(d[b+32>>0]|0)|(d[b+34>>0]|0)<<16|(d[b+35>>0]|0)<<24;i=(d[b+37>>0]|0)<<8|(d[b+36>>0]|0)|(d[b+38>>0]|0)<<16|(d[b+39>>0]|0)<<24;F=(d[b+41>>0]|0)<<8|(d[b+40>>0]|0)|(d[b+42>>0]|0)<<16|(d[b+43>>0]|0)<<24;l=(d[b+45>>0]|0)<<8|(d[b+44>>0]|0)|(d[b+46>>0]|0)<<16|(d[b+47>>0]|0)<<24;H=(d[b+49>>0]|0)<<8|(d[b+48>>0]|0)|(d[b+50>>0]|0)<<16|(d[b+51>>0]|0)<<24;u=(d[b+53>>0]|0)<<8|(d[b+52>>0]|0)|(d[b+54>>0]|0)<<16|(d[b+55>>0]|0)<<24;m=(d[b+57>>0]|0)<<8|(d[b+56>>0]|0)|(d[b+58>>0]|0)<<16|(d[b+59>>0]|0)<<24;w=(d[b+61>>0]|0)<<8|(d[b+60>>0]|0)|(d[b+62>>0]|0)<<16|(d[b+63>>0]|0)<<24;b=a+8|0;A=c[b>>2]|0;p=a+12|0;e=c[p>>2]|0;n=a+16|0;r=c[n>>2]|0;k=a+20|0;I=c[k>>2]|0;g=a+24|0;E=c[g>>2]|0;j=A+s+(r^e^I)|0;j=(j<<11|j>>>21)+E|0;C=r<<10|r>>>22;A=t+1352829926+A+((r|~I)^e)|0;A=(A<<8|A>>>24)+E|0;o=E+D+(C^e^j)|0;o=(o<<14|o>>>18)+I|0;G=e<<10|e>>>22;E=m+1352829926+E+(A^(e|~C))|0;E=(E<<9|E>>>23)+I|0;J=I+v+(j^G^o)|0;J=(J<<15|J>>>17)+C|0;j=j<<10|j>>>22;I=z+1352829926+I+(E^(A|~G))|0;I=(I<<9|I>>>23)+C|0;A=A<<10|A>>>22;a=C+f+(o^j^J)|0;a=(a<<12|a>>>20)+G|0;o=o<<10|o>>>22;C=s+1352829926+C+(I^(E|~A))|0;C=(C<<11|C>>>21)+G|0;E=E<<10|E>>>22;h=G+x+(J^o^a)|0;h=(h<<5|h>>>27)+j|0;J=J<<10|J>>>22;G=i+1352829926+G+(C^(I|~E))|0;G=(G<<13|G>>>19)+A|0;I=I<<10|I>>>22;j=j+t+(a^J^h)|0;j=(j<<8|j>>>24)+o|0;a=a<<10|a>>>22;A=v+1352829926+A+(G^(C|~I))|0;A=(A<<15|A>>>17)+E|0;C=C<<10|C>>>22;o=o+y+(h^a^j)|0;o=(o<<7|o>>>25)+J|0;h=h<<10|h>>>22;E=l+1352829926+E+(A^(G|~C))|0;E=(E<<15|E>>>17)+I|0;G=G<<10|G>>>22;J=J+z+(j^h^o)|0;J=(J<<9|J>>>23)+a|0;j=j<<10|j>>>22;I=x+1352829926+I+(E^(A|~G))|0;I=(I<<5|I>>>27)+C|0;A=A<<10|A>>>22;a=a+B+(o^j^J)|0;a=(a<<11|a>>>21)+h|0;o=o<<10|o>>>22;C=u+1352829926+C+(I^(E|~A))|0;C=(C<<7|C>>>25)+G|0;E=E<<10|E>>>22;h=h+i+(J^o^a)|0;h=(h<<13|h>>>19)+j|0;J=J<<10|J>>>22;G=y+1352829926+G+(C^(I|~E))|0;G=(G<<7|G>>>25)+A|0;I=I<<10|I>>>22;j=j+F+(a^J^h)|0;j=(j<<14|j>>>18)+o|0;a=a<<10|a>>>22;A=w+1352829926+A+(G^(C|~I))|0;A=(A<<8|A>>>24)+E|0;C=C<<10|C>>>22;o=o+l+(h^a^j)|0;o=(o<<15|o>>>17)+J|0;h=h<<10|h>>>22;E=B+1352829926+E+(A^(G|~C))|0;E=(E<<11|E>>>21)+I|0;G=G<<10|G>>>22;J=J+H+(j^h^o)|0;J=(J<<6|J>>>26)+a|0;j=j<<10|j>>>22;I=D+1352829926+I+(E^(A|~G))|0;I=(I<<14|I>>>18)+C|0;A=A<<10|A>>>22;a=a+u+(o^j^J)|0;a=(a<<7|a>>>25)+h|0;o=o<<10|o>>>22;C=F+1352829926+C+(I^(E|~A))|0;C=(C<<14|C>>>18)+G|0;E=E<<10|E>>>22;h=h+m+(J^o^a)|0;h=(h<<9|h>>>23)+j|0;J=J<<10|J>>>22;G=f+1352829926+G+(C^(I|~E))|0;G=(G<<12|G>>>20)+A|0;I=I<<10|I>>>22;j=j+w+(a^J^h)|0;j=(j<<8|j>>>24)+o|0;a=a<<10|a>>>22;A=H+1352829926+A+(G^(C|~I))|0;A=(A<<6|A>>>26)+E|0;C=C<<10|C>>>22;o=z+1518500249+o+(j&h|a&~j)|0;o=(o<<7|o>>>25)+J|0;h=h<<10|h>>>22;E=y+1548603684+E+(A&C|G&~C)|0;E=(E<<9|E>>>23)+I|0;G=G<<10|G>>>22;J=x+1518500249+J+(o&j|h&~o)|0;J=(J<<6|J>>>26)+a|0;j=j<<10|j>>>22;I=l+1548603684+I+(E&G|A&~G)|0;I=(I<<13|I>>>19)+C|0;A=A<<10|A>>>22;a=u+1518500249+a+(J&o|j&~J)|0;a=(a<<8|a>>>24)+h|0;o=o<<10|o>>>22;C=f+1548603684+C+(I&A|E&~A)|0;C=(C<<15|C>>>17)+G|0;E=E<<10|E>>>22;h=D+1518500249+h+(a&J|o&~a)|0;h=(h<<13|h>>>19)+j|0;J=J<<10|J>>>22;G=z+1548603684+G+(C&E|I&~E)|0;G=(G<<7|G>>>25)+A|0;I=I<<10|I>>>22;j=F+1518500249+j+(h&a|J&~h)|0;j=(j<<11|j>>>21)+o|0;a=a<<10|a>>>22;A=s+1548603684+A+(G&I|C&~I)|0;A=(A<<12|A>>>20)+E|0;C=C<<10|C>>>22;o=y+1518500249+o+(j&h|a&~j)|0;o=(o<<9|o>>>23)+J|0;h=h<<10|h>>>22;E=u+1548603684+E+(A&C|G&~C)|0;E=(E<<8|E>>>24)+I|0;G=G<<10|G>>>22;J=w+1518500249+J+(o&j|h&~o)|0;J=(J<<7|J>>>25)+a|0;j=j<<10|j>>>22;I=t+1548603684+I+(E&G|A&~G)|0;I=(I<<9|I>>>23)+C|0;A=A<<10|A>>>22;a=f+1518500249+a+(J&o|j&~J)|0;a=(a<<15|a>>>17)+h|0;o=o<<10|o>>>22;C=F+1548603684+C+(I&A|E&~A)|0;C=(C<<11|C>>>21)+G|0;E=E<<10|E>>>22;h=H+1518500249+h+(a&J|o&~a)|0;h=(h<<7|h>>>25)+j|0;J=J<<10|J>>>22;G=m+1548603684+G+(C&E|I&~E)|0;G=(G<<7|G>>>25)+A|0;I=I<<10|I>>>22;j=s+1518500249+j+(h&a|J&~h)|0;j=(j<<12|j>>>20)+o|0;a=a<<10|a>>>22;A=w+1548603684+A+(G&I|C&~I)|0;A=(A<<7|A>>>25)+E|0;C=C<<10|C>>>22;o=i+1518500249+o+(j&h|a&~j)|0;o=(o<<15|o>>>17)+J|0;h=h<<10|h>>>22;E=B+1548603684+E+(A&C|G&~C)|0;E=(E<<12|E>>>20)+I|0;G=G<<10|G>>>22;J=t+1518500249+J+(o&j|h&~o)|0;J=(J<<9|J>>>23)+a|0;j=j<<10|j>>>22;I=H+1548603684+I+(E&G|A&~G)|0;I=(I<<7|I>>>25)+C|0;A=A<<10|A>>>22;a=v+1518500249+a+(J&o|j&~J)|0;a=(a<<11|a>>>21)+h|0;o=o<<10|o>>>22;C=x+1548603684+C+(I&A|E&~A)|0;C=(C<<6|C>>>26)+G|0;E=E<<10|E>>>22;h=m+1518500249+h+(a&J|o&~a)|0;h=(h<<7|h>>>25)+j|0;J=J<<10|J>>>22;G=i+1548603684+G+(C&E|I&~E)|0;G=(G<<15|G>>>17)+A|0;I=I<<10|I>>>22;j=l+1518500249+j+(h&a|J&~h)|0;j=(j<<13|j>>>19)+o|0;a=a<<10|a>>>22;A=D+1548603684+A+(G&I|C&~I)|0;A=(A<<13|A>>>19)+E|0;C=C<<10|C>>>22;q=~j;o=B+1518500249+o+(j&h|a&q)|0;o=(o<<12|o>>>20)+J|0;h=h<<10|h>>>22;E=v+1548603684+E+(A&C|G&~C)|0;E=(E<<11|E>>>21)+I|0;G=G<<10|G>>>22;q=f+1859775393+J+((o|q)^h)|0;q=(q<<11|q>>>21)+a|0;j=j<<10|j>>>22;I=w+1836072691+I+((E|~A)^G)|0;I=(I<<9|I>>>23)+C|0;A=A<<10|A>>>22;a=F+1859775393+a+((q|~o)^j)|0;a=(a<<13|a>>>19)+h|0;o=o<<10|o>>>22;C=t+1836072691+C+((I|~E)^A)|0;C=(C<<7|C>>>25)+G|0;E=E<<10|E>>>22;h=m+1859775393+h+((a|~q)^o)|0;h=(h<<6|h>>>26)+j|0;q=q<<10|q>>>22;G=D+1836072691+G+((C|~I)^E)|0;G=(G<<15|G>>>17)+A|0;I=I<<10|I>>>22;j=x+1859775393+j+((h|~a)^q)|0;j=(j<<7|j>>>25)+o|0;a=a<<10|a>>>22;A=f+1836072691+A+((G|~C)^I)|0;A=(A<<11|A>>>21)+E|0;C=C<<10|C>>>22;o=i+1859775393+o+((j|~h)^a)|0;o=(o<<14|o>>>18)+q|0;h=h<<10|h>>>22;E=z+1836072691+E+((A|~G)^C)|0;E=(E<<8|E>>>24)+I|0;G=G<<10|G>>>22;q=w+1859775393+q+((o|~j)^h)|0;q=(q<<9|q>>>23)+a|0;j=j<<10|j>>>22;I=m+1836072691+I+((E|~A)^G)|0;I=(I<<6|I>>>26)+C|0;A=A<<10|A>>>22;a=B+1859775393+a+((q|~o)^j)|0;a=(a<<13|a>>>19)+h|0;o=o<<10|o>>>22;C=y+1836072691+C+((I|~E)^A)|0;C=(C<<6|C>>>26)+G|0;E=E<<10|E>>>22;h=D+1859775393+h+((a|~q)^o)|0;h=(h<<15|h>>>17)+j|0;q=q<<10|q>>>22;G=i+1836072691+G+((C|~I)^E)|0;G=(G<<14|G>>>18)+A|0;I=I<<10|I>>>22;j=v+1859775393+j+((h|~a)^q)|0;j=(j<<14|j>>>18)+o|0;a=a<<10|a>>>22;A=l+1836072691+A+((G|~C)^I)|0;A=(A<<12|A>>>20)+E|0;C=C<<10|C>>>22;o=z+1859775393+o+((j|~h)^a)|0;o=(o<<8|o>>>24)+q|0;h=h<<10|h>>>22;E=B+1836072691+E+((A|~G)^C)|0;E=(E<<13|E>>>19)+I|0;G=G<<10|G>>>22;q=s+1859775393+q+((o|~j)^h)|0;q=(q<<13|q>>>19)+a|0;j=j<<10|j>>>22;I=H+1836072691+I+((E|~A)^G)|0;I=(I<<5|I>>>27)+C|0;A=A<<10|A>>>22;a=y+1859775393+a+((q|~o)^j)|0;a=(a<<6|a>>>26)+h|0;o=o<<10|o>>>22;C=v+1836072691+C+((I|~E)^A)|0;C=(C<<14|C>>>18)+G|0;E=E<<10|E>>>22;h=u+1859775393+h+((a|~q)^o)|0;h=(h<<5|h>>>27)+j|0;q=q<<10|q>>>22;G=F+1836072691+G+((C|~I)^E)|0;G=(G<<13|G>>>19)+A|0;I=I<<10|I>>>22;j=l+1859775393+j+((h|~a)^q)|0;j=(j<<12|j>>>20)+o|0;a=a<<10|a>>>22;A=s+1836072691+A+((G|~C)^I)|0;A=(A<<13|A>>>19)+E|0;C=C<<10|C>>>22;o=t+1859775393+o+((j|~h)^a)|0;o=(o<<7|o>>>25)+q|0;h=h<<10|h>>>22;E=x+1836072691+E+((A|~G)^C)|0;E=(E<<7|E>>>25)+I|0;G=G<<10|G>>>22;q=H+1859775393+q+((o|~j)^h)|0;q=(q<<5|q>>>27)+a|0;j=j<<10|j>>>22;I=u+1836072691+I+((E|~A)^G)|0;I=(I<<5|I>>>27)+C|0;A=A<<10|A>>>22;a=D+-1894007588+a+(q&j|o&~j)|0;a=(a<<11|a>>>21)+h|0;o=o<<10|o>>>22;C=B+2053994217+C+(I&E|A&~I)|0;C=(C<<15|C>>>17)+G|0;E=E<<10|E>>>22;h=i+-1894007588+h+(a&o|q&~o)|0;h=(h<<12|h>>>20)+j|0;q=q<<10|q>>>22;G=y+2053994217+G+(C&I|E&~C)|0;G=(G<<5|G>>>27)+A|0;I=I<<10|I>>>22;j=l+-1894007588+j+(h&q|a&~q)|0;j=(j<<14|j>>>18)+o|0;a=a<<10|a>>>22;A=x+2053994217+A+(G&C|I&~G)|0;A=(A<<8|A>>>24)+E|0;C=C<<10|C>>>22;o=F+-1894007588+o+(j&a|h&~a)|0;o=(o<<15|o>>>17)+q|0;h=h<<10|h>>>22;E=D+2053994217+E+(A&G|C&~A)|0;E=(E<<11|E>>>21)+I|0;G=G<<10|G>>>22;q=s+-1894007588+q+(o&h|j&~h)|0;q=(q<<14|q>>>18)+a|0;j=j<<10|j>>>22;I=f+2053994217+I+(E&A|G&~E)|0;I=(I<<14|I>>>18)+C|0;A=A<<10|A>>>22;a=B+-1894007588+a+(q&j|o&~j)|0;a=(a<<15|a>>>17)+h|0;o=o<<10|o>>>22;C=l+2053994217+C+(I&E|A&~I)|0;C=(C<<14|C>>>18)+G|0;E=E<<10|E>>>22;h=H+-1894007588+h+(a&o|q&~o)|0;h=(h<<9|h>>>23)+j|0;q=q<<10|q>>>22;G=w+2053994217+G+(C&I|E&~C)|0;G=(G<<6|G>>>26)+A|0;I=I<<10|I>>>22;j=x+-1894007588+j+(h&q|a&~q)|0;j=(j<<8|j>>>24)+o|0;a=a<<10|a>>>22;A=s+2053994217+A+(G&C|I&~G)|0;A=(A<<14|A>>>18)+E|0;C=C<<10|C>>>22;o=u+-1894007588+o+(j&a|h&~a)|0;o=(o<<9|o>>>23)+q|0;h=h<<10|h>>>22;E=t+2053994217+E+(A&G|C&~A)|0;E=(E<<6|E>>>26)+I|0;G=G<<10|G>>>22;q=f+-1894007588+q+(o&h|j&~h)|0;q=(q<<14|q>>>18)+a|0;j=j<<10|j>>>22;I=H+2053994217+I+(E&A|G&~E)|0;I=(I<<9|I>>>23)+C|0;A=A<<10|A>>>22;a=z+-1894007588+a+(q&j|o&~j)|0;a=(a<<5|a>>>27)+h|0;o=o<<10|o>>>22;C=v+2053994217+C+(I&E|A&~I)|0;C=(C<<12|C>>>20)+G|0;E=E<<10|E>>>22;h=w+-1894007588+h+(a&o|q&~o)|0;h=(h<<6|h>>>26)+j|0;q=q<<10|q>>>22;G=u+2053994217+G+(C&I|E&~C)|0;G=(G<<9|G>>>23)+A|0;I=I<<10|I>>>22;j=m+-1894007588+j+(h&q|a&~q)|0;j=(j<<8|j>>>24)+o|0;a=a<<10|a>>>22;A=i+2053994217+A+(G&C|I&~G)|0;A=(A<<12|A>>>20)+E|0;C=C<<10|C>>>22;o=t+-1894007588+o+(j&a|h&~a)|0;o=(o<<6|o>>>26)+q|0;h=h<<10|h>>>22;E=z+2053994217+E+(A&G|C&~A)|0;E=(E<<5|E>>>27)+I|0;G=G<<10|G>>>22;q=y+-1894007588+q+(o&h|j&~h)|0;q=(q<<5|q>>>27)+a|0;j=j<<10|j>>>22;I=F+2053994217+I+(E&A|G&~E)|0;I=(I<<15|I>>>17)+C|0;A=A<<10|A>>>22;a=v+-1894007588+a+(q&j|o&~j)|0;a=(a<<12|a>>>20)+h|0;o=o<<10|o>>>22;C=m+2053994217+C+(I&E|A&~I)|0;C=(C<<8|C>>>24)+G|0;E=E<<10|E>>>22;h=x+-1454113458+h+(a^(q|~o))|0;h=(h<<9|h>>>23)+j|0;q=q<<10|q>>>22;G=G+H+(I^E^C)|0;G=(G<<8|G>>>24)+A|0;I=I<<10|I>>>22;j=s+-1454113458+j+(h^(a|~q))|0;j=(j<<15|j>>>17)+o|0;a=a<<10|a>>>22;A=A+w+(C^I^G)|0;A=(A<<5|A>>>27)+E|0;C=C<<10|C>>>22;o=t+-1454113458+o+(j^(h|~a))|0;o=(o<<5|o>>>27)+q|0;h=h<<10|h>>>22;E=E+F+(G^C^A)|0;E=(E<<12|E>>>20)+I|0;G=G<<10|G>>>22;q=i+-1454113458+q+(o^(j|~h))|0;q=(q<<11|q>>>21)+a|0;j=j<<10|j>>>22;x=I+x+(A^G^E)|0;x=(x<<9|x>>>23)+C|0;A=A<<10|A>>>22;a=z+-1454113458+a+(q^(o|~j))|0;a=(a<<6|a>>>26)+h|0;o=o<<10|o>>>22;C=C+D+(E^A^x)|0;C=(C<<12|C>>>20)+G|0;E=E<<10|E>>>22;h=H+-1454113458+h+(a^(q|~o))|0;h=(h<<8|h>>>24)+j|0;q=q<<10|q>>>22;t=G+t+(x^E^C)|0;t=(t<<5|t>>>27)+A|0;x=x<<10|x>>>22;j=v+-1454113458+j+(h^(a|~q))|0;j=(j<<13|j>>>19)+o|0;a=a<<10|a>>>22;A=A+B+(C^x^t)|0;A=(A<<14|A>>>18)+E|0;C=C<<10|C>>>22;o=F+-1454113458+o+(j^(h|~a))|0;o=(o<<12|o>>>20)+q|0;h=h<<10|h>>>22;z=E+z+(t^C^A)|0;z=(z<<6|z>>>26)+x|0;t=t<<10|t>>>22;q=m+-1454113458+q+(o^(j|~h))|0;q=(q<<5|q>>>27)+a|0;j=j<<10|j>>>22;x=x+y+(A^t^z)|0;x=(x<<8|x>>>24)+C|0;A=A<<10|A>>>22;a=D+-1454113458+a+(q^(o|~j))|0;a=(a<<12|a>>>20)+h|0;o=o<<10|o>>>22;v=C+v+(z^A^x)|0;v=(v<<13|v>>>19)+t|0;z=z<<10|z>>>22;h=f+-1454113458+h+(a^(q|~o))|0;h=(h<<13|h>>>19)+j|0;q=q<<10|q>>>22;t=t+u+(x^z^v)|0;t=(t<<6|t>>>26)+A|0;x=x<<10|x>>>22;j=B+-1454113458+j+(h^(a|~q))|0;j=(j<<14|j>>>18)+o|0;a=a<<10|a>>>22;m=A+m+(v^x^t)|0;m=(m<<5|m>>>27)+z|0;v=v<<10|v>>>22;o=l+-1454113458+o+(j^(h|~a))|0;o=(o<<11|o>>>21)+q|0;h=h<<10|h>>>22;s=z+s+(t^v^m)|0;s=(s<<15|s>>>17)+x|0;t=t<<10|t>>>22;q=y+-1454113458+q+(o^(j|~h))|0;q=(q<<8|q>>>24)+a|0;j=j<<10|j>>>22;f=x+f+(m^t^s)|0;f=(f<<13|f>>>19)+v|0;m=m<<10|m>>>22;a=w+-1454113458+a+(q^(o|~j))|0;a=(a<<5|a>>>27)+h|0;o=o<<10|o>>>22;i=v+i+(s^m^f)|0;i=(i<<11|i>>>21)+t|0;s=s<<10|s>>>22;h=u+-1454113458+h+(a^(q|~o))|0;l=t+l+(f^s^i)|0;c[p>>2]=s+r+(q<<10|q>>>22);c[n>>2]=m+(c[k>>2]|0)+o;c[k>>2]=j+(c[g>>2]|0)+m+(l<<11|l>>>21);c[g>>2]=j+(c[b>>2]|0)+i+(h<<6|h>>>26);c[b>>2]=(f<<10|f>>>22)+e+a;return}function yb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0;if(d|0){h=c[a>>2]|0;e=h&63;f=64-e|0;h=h+d|0;c[a>>2]=h;if(h>>>0>>0){h=a+4|0;c[h>>2]=(c[h>>2]|0)+1}if(!((e|0)==0|f>>>0>d>>>0)){tc(a+28+e|0,b|0,f|0)|0;xb(a,a+28|0);e=0;b=b+f|0;d=d-f|0}if(d>>>0>63){g=d+-64|0;h=g&-64;f=b+(h+64)|0;while(1){xb(a,b);d=d+-64|0;if(d>>>0<=63)break;else b=b+64|0}b=f;d=g-h|0}if(d|0)tc(a+28+e|0,b|0,d|0)|0}return}function zb(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0;e=i;i=i+16|0;f=e;g=c[b>>2]|0;h=c[b+4>>2]|0;a[f>>0]=g<<3;a[f+1>>0]=g>>>5;a[f+2>>0]=g>>>13;a[f+3>>0]=g>>>21;a[f+4>>0]=h<<3|g>>>29;a[f+5>>0]=h>>>5;a[f+6>>0]=h>>>13;a[f+7>>0]=h>>>21;g=g&63;yb(b,38733,(g>>>0<56?56:120)-g|0);yb(b,f,8);f=b+8|0;a[d>>0]=c[f>>2];a[d+1>>0]=(c[f>>2]|0)>>>8;a[d+2>>0]=(c[f>>2]|0)>>>16;a[d+3>>0]=(c[f>>2]|0)>>>24;f=b+12|0;a[d+4>>0]=c[f>>2];a[d+5>>0]=(c[f>>2]|0)>>>8;a[d+6>>0]=(c[f>>2]|0)>>>16;a[d+7>>0]=(c[f>>2]|0)>>>24;f=b+16|0;a[d+8>>0]=c[f>>2];a[d+9>>0]=(c[f>>2]|0)>>>8;a[d+10>>0]=(c[f>>2]|0)>>>16;a[d+11>>0]=(c[f>>2]|0)>>>24;f=b+20|0;a[d+12>>0]=c[f>>2];a[d+13>>0]=(c[f>>2]|0)>>>8;a[d+14>>0]=(c[f>>2]|0)>>>16;a[d+15>>0]=(c[f>>2]|0)>>>24;b=b+24|0;a[d+16>>0]=c[b>>2];a[d+17>>0]=(c[b>>2]|0)>>>8;a[d+18>>0]=(c[b>>2]|0)>>>16;a[d+19>>0]=(c[b>>2]|0)>>>24;i=e;return}function Ab(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0;h=i;i=i+96|0;e=h;f=e+8|0;g=e;j=g+92|0;do{c[g>>2]=0;g=g+4|0}while((g|0)<(j|0));c[f>>2]=1732584193;c[e+12>>2]=-271733879;c[e+16>>2]=-1732584194;c[e+20>>2]=271733878;c[e+24>>2]=-1009589776;yb(e,a,b);zb(e,d);i=h;return}function Bb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0;y=i;i=i+64|0;t=y;u=c[a>>2]|0;v=a+4|0;w=a+8|0;x=a+12|0;q=a+16|0;r=a+20|0;s=a+24|0;p=a+28|0;g=0;o=u;a=c[p>>2]|0;h=c[s>>2]|0;j=c[r>>2]|0;k=c[q>>2]|0;e=c[x>>2]|0;l=c[w>>2]|0;f=c[v>>2]|0;while(1){n=((k>>>6|k<<26)^(k>>>11|k<<21)^(k>>>25|k<<7))+a+(h&~k^j&k)+(c[37828+(g<<2)>>2]|0)|0;a=c[b>>2]|0;c[t+(g<<2)>>2]=a;a=n+a|0;e=a+e|0;a=((o>>>2|o<<30)^(o>>>13|o<<19)^(o>>>22|o<<10))+(o&(l^f)^l&f)+a|0;g=g+1|0;if((g|0)==16){n=16;m=a;g=e;a=l;e=o;break}else{C=o;B=f;A=l;z=k;m=j;n=h;b=b+4|0;o=a;k=e;f=C;l=B;e=A;j=z;h=m;a=n}}while(1){A=n;n=n+1|0;z=c[t+((n&15)<<2)>>2]|0;b=c[t+((A+14&15)<<2)>>2]|0;C=((g>>>6|g<<26)^(g>>>11|g<<21)^(g>>>25|g<<7))+h+(j&~g^k&g)+(c[37828+(A<<2)>>2]|0)|0;B=t+((A&15)<<2)|0;b=((z>>>18|z<<14)^z>>>3^(z>>>7|z<<25))+(c[t+((A+9&15)<<2)>>2]|0)+(c[B>>2]|0)+((b>>>19|b<<13)^b>>>10^(b>>>17|b<<15))|0;c[B>>2]=b;b=C+b|0;a=b+a|0;b=((m>>>2|m<<30)^(m>>>13|m<<19)^(m>>>22|m<<10))+(m&(f^e)^f&e)+b|0;if((n|0)==64)break;else{o=m;z=e;A=f;B=g;C=k;h=j;m=b;g=a;e=o;f=z;a=A;k=B;j=C}}c[d>>2]=u+b;c[d+4>>2]=(c[v>>2]|0)+m;c[d+8>>2]=(c[w>>2]|0)+e;c[d+12>>2]=(c[x>>2]|0)+f;c[d+16>>2]=(c[q>>2]|0)+a;c[d+20>>2]=(c[r>>2]|0)+g;c[d+24>>2]=(c[s>>2]|0)+k;c[d+28>>2]=(c[p>>2]|0)+j;i=y;return}function Cb(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0;do if(e|0){n=b+32|0;g=n;h=c[g>>2]|0;g=c[g+4>>2]|0;f=mc(h|0,g|0,3)|0;f=f&63;if(f){i=64-f|0;j=b+40|0;f=j+f|0;if(i>>>0>e>>>0){tc(f|0,d|0,e|0)|0;b=qc(h|0,g|0,e<<3|0,0)|0;c[n>>2]=b;c[n+4>>2]=C;break}tc(f|0,d|0,i|0)|0;m=qc(h|0,g|0,i<<3|0,0)|0;f=n;c[f>>2]=m;c[f+4>>2]=C;e=e-i|0;f=0;do{m=b+40+(f<<2)|0;c[m>>2]=sc(c[m>>2]|0)|0;f=f+1|0}while((f|0)!=16);Bb(b,j,b);d=d+i|0}if(e>>>0>63){j=b+40|0;l=e+-64|0;m=l&-64;k=m+64|0;i=d;while(1){f=j;g=i;h=f+64|0;do{a[f>>0]=a[g>>0]|0;f=f+1|0;g=g+1|0}while((f|0)<(h|0));f=0;do{h=b+40+(f<<2)|0;c[h>>2]=sc(c[h>>2]|0)|0;f=f+1|0}while((f|0)!=16);Bb(b,j,b);g=n;g=qc(c[g>>2]|0,c[g+4>>2]|0,512,0)|0;h=n;c[h>>2]=g;c[h+4>>2]=C;e=e+-64|0;if(e>>>0<=63)break;else i=i+64|0}d=d+k|0;e=l-m|0}if(e|0){tc(b+40|0,d|0,e|0)|0;b=n;b=qc(c[b>>2]|0,c[b+4>>2]|0,e<<3|0,0)|0;c[n>>2]=b;c[n+4>>2]=C}}while(0);return}function Db(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0;if(d){h=b+32|0;f=h;f=mc(c[f>>2]|0,c[f+4>>2]|0,3)|0;f=f&63;e=f+1|0;g=b+40|0;a[g+f>>0]=-128;if(e>>>0>56){lc(g+e|0,0,f^63|0)|0;e=0;do{f=b+40+(e<<2)|0;c[f>>2]=sc(c[f>>2]|0)|0;e=e+1|0}while((e|0)!=16);Bb(b,g,b);e=0}lc(g+e|0,0,56-e|0)|0;e=0;do{f=b+40+(e<<2)|0;c[f>>2]=sc(c[f>>2]|0)|0;e=e+1|0}while((e|0)!=14);e=c[h>>2]|0;c[b+96>>2]=c[h+4>>2];c[b+100>>2]=e;Bb(b,g,b);e=0;do{h=b+(e<<2)|0;c[h>>2]=sc(c[h>>2]|0)|0;e=e+1|0}while((e|0)!=8);e=d;f=b;g=e+32|0;do{a[e>>0]=a[f>>0]|0;e=e+1|0;f=f+1|0}while((e|0)<(g|0))}e=b;g=e+104|0;do{c[e>>2]=0;e=e+4|0}while((e|0)<(g|0));return}function Eb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0;g=i;i=i+112|0;e=g;c[e>>2]=c[9449];c[e+4>>2]=c[9450];c[e+8>>2]=c[9451];c[e+12>>2]=c[9452];c[e+16>>2]=c[9453];c[e+20>>2]=c[9454];c[e+24>>2]=c[9455];c[e+28>>2]=c[9456];f=e+32|0;h=f+72|0;do{c[f>>2]=0;f=f+4|0}while((f|0)<(h|0));Cb(e,a,b);Db(e,d);i=g;return}function Fb(a){a=a|0;var b=0,d=0,e=0;if(a|0){b=a;d=8;e=b+64|0;do{c[b>>2]=c[d>>2];b=b+4|0;d=d+4|0}while((b|0)<(e|0));lc(a+64|0,0,144)|0}return}function Gb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0,X=0,Y=0,Z=0,_=0;L=i;i=i+128|0;F=L;K=a;J=c[K>>2]|0;K=c[K+4>>2]|0;B=a+8|0;w=B;D=a+16|0;e=D;E=a+24|0;f=E;G=a+32|0;p=G;H=a+40|0;q=H;I=a+48|0;m=I;A=a+56|0;h=A;j=0;l=J;u=K;t=c[w>>2]|0;z=c[e>>2]|0;w=c[w+4>>2]|0;a=c[e+4>>2]|0;e=c[f>>2]|0;f=c[f+4>>2]|0;o=c[p>>2]|0;p=c[p+4>>2]|0;g=c[h>>2]|0;h=c[h+4>>2]|0;r=c[q>>2]|0;q=c[q+4>>2]|0;k=c[m>>2]|0;m=c[m+4>>2]|0;while(1){v=mc(o|0,p|0,14)|0;N=C;x=nc(o|0,p|0,50)|0;N=N|C;y=mc(o|0,p|0,18)|0;O=C;M=nc(o|0,p|0,46)|0;O=N^(O|C);N=mc(o|0,p|0,41)|0;n=C;s=nc(o|0,p|0,23)|0;n=qc((v|x)^(y|M)^(N|s)|0,O^(n|C)|0,g|0,h|0)|0;n=qc(n|0,C|0,k&~o^r&o|0,m&~p^q&p|0)|0;O=72+(j<<3)|0;O=qc(n|0,C|0,c[O>>2]|0,c[O+4>>2]|0)|0;n=b;g=c[n>>2]|0;n=c[n+4>>2]|0;s=F+(j<<3)|0;c[s>>2]=g;c[s+4>>2]=n;n=qc(O|0,C|0,g|0,n|0)|0;g=C;O=mc(l|0,u|0,28)|0;s=C;N=nc(l|0,u|0,36)|0;s=s|C;M=mc(l|0,u|0,34)|0;y=C;h=nc(l|0,u|0,30)|0;y=s^(y|C);s=mc(l|0,u|0,39)|0;x=C;v=nc(l|0,u|0,25)|0;x=qc((O|N)^(M|h)^(s|v)|0,y^(x|C)|0,l&(z^t)^z&t|0,u&(a^w)^a&w|0)|0;y=C;e=qc(n|0,g|0,e|0,f|0)|0;f=C;g=qc(x|0,y|0,n|0,g|0)|0;n=C;j=j+1|0;if((j|0)==16){y=16;x=e;v=f;s=p;p=g;j=t;h=u;g=w;b=z;break}else{x=p;y=o;h=m;M=k;N=u;O=l;b=b+8|0;l=g;u=n;o=e;p=f;m=q;k=r;q=x;r=y;g=M;f=a;e=z;a=w;w=N;z=t;t=O}}while(1){t=y;y=y+1|0;T=F+((y&15)<<3)|0;W=c[T>>2]|0;T=c[T+4>>2]|0;S=mc(W|0,T|0,1)|0;Q=C;R=nc(W|0,T|0,63)|0;Q=Q|C;V=mc(W|0,T|0,8)|0;O=C;U=nc(W|0,T|0,56)|0;O=O|C;T=mc(W|0,T|0,7)|0;Q=O^C^Q;O=F+((t+14&15)<<3)|0;W=c[O>>2]|0;O=c[O+4>>2]|0;u=mc(W|0,O|0,19)|0;e=C;f=nc(W|0,O|0,45)|0;e=e|C;N=mc(W|0,O|0,61)|0;_=C;w=nc(W|0,O|0,3)|0;_=_|C;O=mc(W|0,O|0,6)|0;e=_^C^e;_=mc(x|0,v|0,14)|0;W=C;Z=nc(x|0,v|0,50)|0;W=W|C;Y=mc(x|0,v|0,18)|0;P=C;X=nc(x|0,v|0,46)|0;P=W^(P|C);W=mc(x|0,v|0,41)|0;z=C;M=nc(x|0,v|0,23)|0;m=qc((_|Z)^(Y|X)^(W|M)|0,P^(z|C)|0,k|0,m|0)|0;m=qc(m|0,C|0,r&~x^o&x|0,q&~v^s&v|0)|0;z=72+(t<<3)|0;z=qc(m|0,C|0,c[z>>2]|0,c[z+4>>2]|0)|0;m=C;P=F+((t+9&15)<<3)|0;t=F+((t&15)<<3)|0;M=t;k=c[M>>2]|0;M=c[M+4>>2]|0;P=qc((V|U)^T^(S|R)|0,Q|0,c[P>>2]|0,c[P+4>>2]|0)|0;M=qc(P|0,C|0,k|0,M|0)|0;e=qc(M|0,C|0,(N|w)^O^(u|f)|0,e|0)|0;f=C;c[t>>2]=e;c[t+4>>2]=f;f=qc(z|0,m|0,e|0,f|0)|0;e=C;m=mc(p|0,n|0,28)|0;z=C;t=nc(p|0,n|0,36)|0;z=z|C;u=mc(p|0,n|0,34)|0;O=C;w=nc(p|0,n|0,30)|0;O=z^(O|C);z=mc(p|0,n|0,39)|0;N=C;M=nc(p|0,n|0,25)|0;N=qc((m|t)^(u|w)^(z|M)|0,O^(N|C)|0,p&(j^l)^j&l|0,n&(g^h)^g&h|0)|0;O=C;a=qc(f|0,e|0,b|0,a|0)|0;b=C;e=qc(N|0,O|0,f|0,e|0)|0;f=C;if((y|0)==80)break;else{X=n;Y=p;Z=v;_=x;m=q;k=r;x=a;v=b;p=e;n=f;a=g;b=j;g=h;h=X;j=l;l=Y;q=s;r=o;s=Z;o=_}}_=qc(J|0,K|0,e|0,f|0)|0;Z=d;c[Z>>2]=_;c[Z+4>>2]=C;Z=B;Z=qc(c[Z>>2]|0,c[Z+4>>2]|0,p|0,n|0)|0;_=d+8|0;c[_>>2]=Z;c[_+4>>2]=C;_=D;_=qc(c[_>>2]|0,c[_+4>>2]|0,l|0,h|0)|0;Z=d+16|0;c[Z>>2]=_;c[Z+4>>2]=C;Z=E;Z=qc(c[Z>>2]|0,c[Z+4>>2]|0,j|0,g|0)|0;_=d+24|0;c[_>>2]=Z;c[_+4>>2]=C;_=G;_=qc(c[_>>2]|0,c[_+4>>2]|0,a|0,b|0)|0;Z=d+32|0;c[Z>>2]=_;c[Z+4>>2]=C;Z=H;Z=qc(c[Z>>2]|0,c[Z+4>>2]|0,x|0,v|0)|0;_=d+40|0;c[_>>2]=Z;c[_+4>>2]=C;_=I;_=qc(c[_>>2]|0,c[_+4>>2]|0,o|0,s|0)|0;Z=d+48|0;c[Z>>2]=_;c[Z+4>>2]=C;Z=A;Z=qc(c[Z>>2]|0,c[Z+4>>2]|0,r|0,q|0)|0;_=d+56|0;c[_>>2]=Z;c[_+4>>2]=C;i=L;return}function Hb(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0;do if(e|0){o=b+64|0;g=o;h=c[g>>2]|0;g=c[g+4>>2]|0;f=mc(h|0,g|0,3)|0;f=f&127;if(f){i=128-f|0;j=b+80|0;f=j+f|0;if(i>>>0>e>>>0){tc(f|0,d|0,e|0)|0;n=e<<3;m=qc(h|0,g|0,n|0,0)|0;l=C;c[o>>2]=m;c[o+4>>2]=l;if(!(l>>>0<0|(l|0)==0&m>>>0>>0))break;o=b+72|0;b=o;b=qc(c[b>>2]|0,c[b+4>>2]|0,1,0)|0;c[o>>2]=b;c[o+4>>2]=C;break}tc(f|0,d|0,i|0)|0;n=i<<3;m=qc(h|0,g|0,n|0,0)|0;l=C;k=o;c[k>>2]=m;c[k+4>>2]=l;if(l>>>0<0|(l|0)==0&m>>>0>>0){n=b+72|0;m=n;m=qc(c[m>>2]|0,c[m+4>>2]|0,1,0)|0;c[n>>2]=m;c[n+4>>2]=C}e=e-i|0;f=0;do{n=b+80+(f<<3)|0;m=n;m=ma(c[m>>2]|0,c[m+4>>2]|0)|0;c[n>>2]=m;c[n+4>>2]=C;f=f+1|0}while((f|0)!=16);Gb(b,j,b);d=d+i|0}if(e>>>0>127){j=b+80|0;k=b+72|0;m=e+-128|0;n=m&-128;l=n+128|0;i=d;while(1){f=j;g=i;h=f+128|0;do{a[f>>0]=a[g>>0]|0;f=f+1|0;g=g+1|0}while((f|0)<(h|0));f=0;do{h=b+80+(f<<3)|0;g=h;g=ma(c[g>>2]|0,c[g+4>>2]|0)|0;c[h>>2]=g;c[h+4>>2]=C;f=f+1|0}while((f|0)!=16);Gb(b,j,b);g=o;h=c[g>>2]|0;g=c[g+4>>2]|0;p=qc(h|0,g|0,1024,0)|0;f=o;c[f>>2]=p;c[f+4>>2]=C;if(g>>>0>4294967295|(g|0)==-1&h>>>0>4294966271){h=k;h=qc(c[h>>2]|0,c[h+4>>2]|0,1,0)|0;p=k;c[p>>2]=h;c[p+4>>2]=C}e=e+-128|0;if(e>>>0<=127)break;else i=i+128|0}d=d+l|0;e=m-n|0}if(e|0?(tc(b+80|0,d|0,e|0)|0,p=e<<3,n=o,n=qc(c[n>>2]|0,c[n+4>>2]|0,p|0,0)|0,m=C,o,c[o>>2]=n,c[o+4>>2]=m,m>>>0<0|(m|0)==0&n>>>0

>>0):0){p=b+72|0;o=p;o=qc(c[o>>2]|0,c[o+4>>2]|0,1,0)|0;c[p>>2]=o;c[p+4>>2]=C}}while(0);return}function Ib(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0;if(d){h=b+64|0;f=h;f=mc(c[f>>2]|0,c[f+4>>2]|0,3)|0;f=f&127;e=f+1|0;g=b+80|0;a[g+f>>0]=-128;if(e>>>0>112){lc(g+e|0,0,f^127|0)|0;e=0;do{f=b+80+(e<<3)|0;i=f;i=ma(c[i>>2]|0,c[i+4>>2]|0)|0;c[f>>2]=i;c[f+4>>2]=C;e=e+1|0}while((e|0)!=16);Gb(b,g,b);e=0}lc(g+e|0,0,112-e|0)|0;e=0;do{i=b+80+(e<<3)|0;f=i;f=ma(c[f>>2]|0,c[f+4>>2]|0)|0;c[i>>2]=f;c[i+4>>2]=C;e=e+1|0}while((e|0)!=14);f=b+72|0;e=c[f+4>>2]|0;i=b+192|0;c[i>>2]=c[f>>2];c[i+4>>2]=e;i=c[h+4>>2]|0;e=b+200|0;c[e>>2]=c[h>>2];c[e+4>>2]=i;Gb(b,g,b);e=0;do{i=b+(e<<3)|0;h=i;h=ma(c[h>>2]|0,c[h+4>>2]|0)|0;c[i>>2]=h;c[i+4>>2]=C;e=e+1|0}while((e|0)!=8);e=d;f=b;g=e+64|0;do{a[e>>0]=a[f>>0]|0;e=e+1|0;f=f+1|0}while((e|0)<(g|0))}lc(b|0,0,208)|0;return}function Jb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0;g=i;i=i+208|0;e=g;f=e;h=8;j=f+64|0;do{c[f>>2]=c[h>>2];f=f+4|0;h=h+4|0}while((f|0)<(j|0));lc(e+64|0,0,144)|0;Hb(e,a,b);Ib(e,d);i=g;return}function Kb(){var a=0,b=0,d=0;d=i;i=i+16|0;b=d;a=c[9714]|0;if(!a){a=bc(38797,38810)|0;c[9714]=a}if((gc(b,1,4,a)|0)==4){i=d;return c[b>>2]|0}else pa(38812,38828,60,38838);return 0}function Lb(a){a=a|0;if(a>>>0>=256)if(a>>>0<65536)a=2;else a=a>>>0<16777216?3:4;else a=1;return a|0}function Mb(b,c){b=b|0;c=c|0;var d=0;if(b>>>0<=16777215)if(b>>>0<=65535){if(b>>>0>255)d=6}else d=4;else{a[c>>0]=b>>>24;c=c+1|0;d=4}if((d|0)==4){a[c>>0]=b>>>16;c=c+1|0;d=6}if((d|0)==6){a[c>>0]=b>>>8;c=c+1|0}a[c>>0]=b;return}function Nb(a){a=a|0;var b=0,d=0;b=i;i=i+16|0;d=b;c[d>>2]=c[a+60>>2];a=Qb(ha(6,d|0)|0)|0;i=b;return a|0}function Ob(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0;m=i;i=i+48|0;h=m+16|0;g=m;f=m+32|0;c[f>>2]=d;j=f+4|0;l=b+48|0;n=c[l>>2]|0;c[j>>2]=e-((n|0)!=0&1);k=b+44|0;c[f+8>>2]=c[k>>2];c[f+12>>2]=n;if(!(c[9715]|0)){c[h>>2]=c[b+60>>2];c[h+4>>2]=f;c[h+8>>2]=2;f=Qb(qa(145,h|0)|0)|0}else{ga(1,b|0);c[g>>2]=c[b+60>>2];c[g+4>>2]=f;c[g+8>>2]=2;f=Qb(qa(145,g|0)|0)|0;ba(0)}if((f|0)>=1){j=c[j>>2]|0;if(f>>>0>j>>>0){g=c[k>>2]|0;h=b+4|0;c[h>>2]=g;c[b+8>>2]=g+(f-j);if(!(c[l>>2]|0))f=e;else{c[h>>2]=g+1;a[d+(e+-1)>>0]=a[g>>0]|0;f=e}}}else{c[b>>2]=c[b>>2]|f&48^16;c[b+8>>2]=0;c[b+4>>2]=0}i=m;return f|0}function Pb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0;f=i;i=i+32|0;g=f;e=f+20|0;c[g>>2]=c[a+60>>2];c[g+4>>2]=0;c[g+8>>2]=b;c[g+12>>2]=e;c[g+16>>2]=d;if((Qb(ja(140,g|0)|0)|0)<0){c[e>>2]=-1;a=-1}else a=c[e>>2]|0;i=f;return a|0}function Qb(a){a=a|0;if(a>>>0>4294963200){c[(Rb()|0)>>2]=0-a;a=-1}return a|0}function Rb(){var a=0;if(!(c[9715]|0))a=38904;else a=c[(uc()|0)+64>>2]|0;return a|0}function Sb(a){a=a|0;if(!(c[a+68>>2]|0))Tb(a);return}function Tb(a){a=a|0;return}function Ub(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0;q=i;i=i+48|0;n=q+16|0;m=q;j=q+32|0;o=a+28|0;h=c[o>>2]|0;c[j>>2]=h;p=a+20|0;h=(c[p>>2]|0)-h|0;c[j+4>>2]=h;c[j+8>>2]=b;c[j+12>>2]=d;k=a+60|0;l=a+44|0;g=2;b=h+d|0;while(1){if(!(c[9715]|0)){c[n>>2]=c[k>>2];c[n+4>>2]=j;c[n+8>>2]=g;f=Qb(ra(146,n|0)|0)|0}else{ga(2,a|0);c[m>>2]=c[k>>2];c[m+4>>2]=j;c[m+8>>2]=g;f=Qb(ra(146,m|0)|0)|0;ba(0)}if((b|0)==(f|0)){b=6;break}if((f|0)<0){b=8;break}b=b-f|0;e=c[j+4>>2]|0;if(f>>>0<=e>>>0)if((g|0)==2){c[o>>2]=(c[o>>2]|0)+f;g=2;h=j}else h=j;else{h=c[l>>2]|0;c[o>>2]=h;c[p>>2]=h;f=f-e|0;g=g+-1|0;h=j+8|0;e=c[j+12>>2]|0}c[h>>2]=(c[h>>2]|0)+f;c[h+4>>2]=e-f;j=h}if((b|0)==6){n=c[l>>2]|0;c[a+16>>2]=n+(c[a+48>>2]|0);a=n;c[o>>2]=a;c[p>>2]=a}else if((b|0)==8){c[a+16>>2]=0;c[o>>2]=0;c[p>>2]=0;c[a>>2]=c[a>>2]|32;if((g|0)==2)d=0;else d=d-(c[j+4>>2]|0)|0}i=q;return d|0}function Vb(a){a=a|0;if(!(c[a+68>>2]|0))Tb(a);return}function Wb(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0;g=i;i=i+80|0;f=g;c[b+36>>2]=3;if((c[b>>2]&64|0)==0?(c[f>>2]=c[b+60>>2],c[f+4>>2]=21505,c[f+8>>2]=g+12,da(54,f|0)|0):0)a[b+75>>0]=-1;f=Ub(b,d,e)|0;i=g;return f|0}function Xb(b){b=b|0;var d=0,e=0;d=b+74|0;e=a[d>>0]|0;a[d>>0]=e+255|e;d=b+20|0;e=b+44|0;if((c[d>>2]|0)>>>0>(c[e>>2]|0)>>>0)va[c[b+36>>2]&7](b,0,0)|0;c[b+16>>2]=0;c[b+28>>2]=0;c[d>>2]=0;d=c[b>>2]|0;if(d&20)if(!(d&4))d=-1;else{c[b>>2]=d|32;d=-1}else{d=c[e>>2]|0;c[b+8>>2]=d;c[b+4>>2]=d;d=0}return d|0}function Yb(a){a=a|0;return 0}function Zb(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,i=0;h=d&255;f=(e|0)!=0;a:do if(f&(b&3|0)!=0){g=d&255;while(1){if((a[b>>0]|0)==g<<24>>24){i=6;break a}b=b+1|0;e=e+-1|0;f=(e|0)!=0;if(!(f&(b&3|0)!=0)){i=5;break}}}else i=5;while(0);if((i|0)==5)if(f)i=6;else e=0;b:do if((i|0)==6){g=d&255;if((a[b>>0]|0)!=g<<24>>24){f=R(h,16843009)|0;c:do if(e>>>0>3)while(1){h=c[b>>2]^f;if((h&-2139062144^-2139062144)&h+-16843009|0)break;b=b+4|0;e=e+-4|0;if(e>>>0<=3){i=11;break c}}else i=11;while(0);if((i|0)==11)if(!e){e=0;break}while(1){if((a[b>>0]|0)==g<<24>>24)break b;b=b+1|0;e=e+-1|0;if(!e){e=0;break}}}}while(0);return (e|0?b:0)|0}function _b(b){b=b|0;var d=0,e=0,f=0;f=b;a:do if(!(f&3))e=4;else{d=f;while(1){if(!(a[b>>0]|0)){b=d;break a}b=b+1|0;d=b;if(!(d&3)){e=4;break}}}while(0);if((e|0)==4){while(1){d=c[b>>2]|0;if(!((d&-2139062144^-2139062144)&d+-16843009))b=b+4|0;else break}if((d&255)<<24>>24)do b=b+1|0;while((a[b>>0]|0)!=0)}return b-f|0}function $b(b,c){b=b|0;c=c|0;b=ac(b,c)|0;return ((a[b>>0]|0)==(c&255)<<24>>24?b:0)|0}function ac(b,d){b=b|0;d=d|0;var e=0,f=0,g=0;f=d&255;a:do if(!f)b=b+(_b(b)|0)|0;else{if(b&3){e=d&255;do{g=a[b>>0]|0;if(g<<24>>24==0?1:g<<24>>24==e<<24>>24)break a;b=b+1|0}while((b&3|0)!=0)}f=R(f,16843009)|0;e=c[b>>2]|0;b:do if(!((e&-2139062144^-2139062144)&e+-16843009))do{g=e^f;if((g&-2139062144^-2139062144)&g+-16843009|0)break b;b=b+4|0;e=c[b>>2]|0}while(!((e&-2139062144^-2139062144)&e+-16843009|0));while(0);e=d&255;while(1){g=a[b>>0]|0;if(g<<24>>24==0?1:g<<24>>24==e<<24>>24)break;else b=b+1|0}}while(0);return b|0}function bc(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0;g=i;i=i+32|0;f=g+16|0;e=g;if(Zb(38847,a[d>>0]|0,4)|0){h=cc(d)|0|32768;c[e>>2]=b;c[e+4>>2]=h;c[e+8>>2]=438;e=Qb(ka(5,e|0)|0)|0;if((e|0)>=0){b=dc(e,d)|0;if(!b){c[f>>2]=e;ha(6,f|0)|0;b=0}}else b=0}else{c[(Rb()|0)>>2]=22;b=0}i=g;return b|0}function cc(b){b=b|0;var c=0,d=0,e=0;d=($b(b,43)|0)==0;c=a[b>>0]|0;d=d?c<<24>>24!=114&1:2;e=($b(b,120)|0)==0;d=e?d:d|128;b=($b(b,101)|0)==0;b=b?d:d|524288;b=c<<24>>24==114?b:b|64;b=c<<24>>24==119?b|512:b;return (c<<24>>24==97?b|1024:b)|0}function dc(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0;o=i;i=i+112|0;n=o+40|0;l=o+24|0;k=o+16|0;g=o;m=o+52|0;f=a[d>>0]|0;if(Zb(38847,f<<24>>24,4)|0){e=hc(1144)|0;if(!e)e=0;else{h=e;j=h+112|0;do{c[h>>2]=0;h=h+4|0}while((h|0)<(j|0));if(!($b(d,43)|0))c[e>>2]=f<<24>>24==114?8:4;if($b(d,101)|0){c[g>>2]=b;c[g+4>>2]=2;c[g+8>>2]=1;ca(221,g|0)|0;f=a[d>>0]|0}if(f<<24>>24==97){c[k>>2]=b;c[k+4>>2]=3;f=ca(221,k|0)|0;if(!(f&1024)){c[l>>2]=b;c[l+4>>2]=4;c[l+8>>2]=f|1024;ca(221,l|0)|0}d=c[e>>2]|128;c[e>>2]=d}else d=c[e>>2]|0;c[e+60>>2]=b;c[e+44>>2]=e+120;c[e+48>>2]=1024;f=e+75|0;a[f>>0]=-1;if((d&8|0)==0?(c[n>>2]=b,c[n+4>>2]=21505,c[n+8>>2]=m,(da(54,n|0)|0)==0):0)a[f>>0]=10;c[e+32>>2]=4;c[e+36>>2]=3;c[e+40>>2]=2;c[e+12>>2]=1;if(!(c[9716]|0))c[e+76>>2]=-1;ea(38888);f=c[9721]|0;c[e+56>>2]=f;if(f|0)c[f+52>>2]=e;c[9721]=e;na(38888)}}else{c[(Rb()|0)>>2]=22;e=0}i=o;return e|0}function ec(a){a=a|0;var b=0,d=0;do if(a){if((c[a+76>>2]|0)<=-1){b=fc(a)|0;break}d=(Yb(a)|0)==0;b=fc(a)|0;if(!d)Tb(a)}else{if(!(c[9549]|0))b=0;else b=ec(c[9549]|0)|0;ea(38888);a=c[9721]|0;if(a)do{if((c[a+76>>2]|0)>-1)d=Yb(a)|0;else d=0;if((c[a+20>>2]|0)>>>0>(c[a+28>>2]|0)>>>0)b=fc(a)|0|b;if(d|0)Tb(a);a=c[a+56>>2]|0}while((a|0)!=0);na(38888)}while(0);return b|0}function fc(a){a=a|0;var b=0,d=0,e=0,f=0,g=0,h=0;b=a+20|0;h=a+28|0;if((c[b>>2]|0)>>>0>(c[h>>2]|0)>>>0?(va[c[a+36>>2]&7](a,0,0)|0,(c[b>>2]|0)==0):0)a=-1;else{d=a+4|0;e=c[d>>2]|0;f=a+8|0;g=c[f>>2]|0;if(e>>>0>>0)va[c[a+40>>2]&7](a,e-g|0,1)|0;c[a+16>>2]=0;c[h>>2]=0;c[b>>2]=0;c[f>>2]=0;c[d>>2]=0;a=0}return a|0}function gc(b,d,e,f){b=b|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,i=0,j=0,k=0,l=0;k=R(e,d)|0;if((c[f+76>>2]|0)>-1)j=Yb(f)|0;else j=0;g=f+74|0;i=a[g>>0]|0;a[g>>0]=i+255|i;g=f+4|0;i=c[g>>2]|0;h=(c[f+8>>2]|0)-i|0;if((h|0)>0){h=h>>>0>>0?h:k;tc(b|0,i|0,h|0)|0;c[g>>2]=i+h;g=k-h|0;b=b+h|0}else g=k;a:do if(!g)l=13;else{i=f+32|0;while(1){if(Xb(f)|0)break;h=va[c[i>>2]&7](f,b,g)|0;if((h+1|0)>>>0<2)break;g=g-h|0;if(!g){l=13;break a}else b=b+h|0}if(j|0)Tb(f);e=((k-g|0)>>>0)/(d>>>0)|0}while(0);if((l|0)==13)if(j)Tb(f);return e|0}function hc(a){a=a|0;var b=0,d=0,e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0;L=i;i=i+16|0;p=L;do if(a>>>0<245){o=a>>>0<11?16:a+11&-8;a=o>>>3;t=c[9727]|0;d=t>>>a;if(d&3|0){a=(d&1^1)+a|0;d=38948+(a<<1<<2)|0;e=d+8|0;f=c[e>>2]|0;g=f+8|0;h=c[g>>2]|0;do if((d|0)!=(h|0)){if(h>>>0<(c[9731]|0)>>>0)fa();b=h+12|0;if((c[b>>2]|0)==(f|0)){c[b>>2]=d;c[e>>2]=h;break}else fa()}else c[9727]=t&~(1<>2]=K|3;K=f+K+4|0;c[K>>2]=c[K>>2]|1;K=g;i=L;return K|0}s=c[9729]|0;if(o>>>0>s>>>0){if(d|0){j=2<>>12&16;a=a>>>j;e=a>>>5&8;a=a>>>e;g=a>>>2&4;a=a>>>g;d=a>>>1&2;a=a>>>d;b=a>>>1&1;b=(e|j|g|d|b)+(a>>>b)|0;a=38948+(b<<1<<2)|0;d=a+8|0;g=c[d>>2]|0;j=g+8|0;e=c[j>>2]|0;do if((a|0)!=(e|0)){if(e>>>0<(c[9731]|0)>>>0)fa();f=e+12|0;if((c[f>>2]|0)==(g|0)){c[f>>2]=a;c[d>>2]=e;k=t;break}else fa()}else{k=t&~(1<>2]=o|3;e=g+o|0;c[e+4>>2]=h|1;c[e+h>>2]=h;if(s|0){f=c[9732]|0;b=s>>>3;d=38948+(b<<1<<2)|0;b=1<>2]|0;if(a>>>0<(c[9731]|0)>>>0)fa();else{l=a;m=b}}else{c[9727]=k|b;l=d;m=d+8|0}c[m>>2]=f;c[l+12>>2]=f;c[f+8>>2]=l;c[f+12>>2]=d}c[9729]=h;c[9732]=e;K=j;i=L;return K|0}l=c[9728]|0;if(l){a=(l&0-l)+-1|0;J=a>>>12&16;a=a>>>J;I=a>>>5&8;a=a>>>I;K=a>>>2&4;a=a>>>K;j=a>>>1&2;a=a>>>j;k=a>>>1&1;k=c[39212+((I|J|K|j|k)+(a>>>k)<<2)>>2]|0;a=k;j=k;k=(c[k+4>>2]&-8)-o|0;while(1){b=c[a+16>>2]|0;if(!b){b=c[a+20>>2]|0;if(!b)break}K=(c[b+4>>2]&-8)-o|0;J=K>>>0>>0;a=b;j=J?b:j;k=J?K:k}f=c[9731]|0;if(j>>>0>>0)fa();h=j+o|0;if(j>>>0>=h>>>0)fa();g=c[j+24>>2]|0;d=c[j+12>>2]|0;do if((d|0)==(j|0)){a=j+20|0;b=c[a>>2]|0;if(!b){a=j+16|0;b=c[a>>2]|0;if(!b){n=0;break}}while(1){d=b+20|0;e=c[d>>2]|0;if(e|0){b=e;a=d;continue}d=b+16|0;e=c[d>>2]|0;if(!e)break;else{b=e;a=d}}if(a>>>0>>0)fa();else{c[a>>2]=0;n=b;break}}else{e=c[j+8>>2]|0;if(e>>>0>>0)fa();b=e+12|0;if((c[b>>2]|0)!=(j|0))fa();a=d+8|0;if((c[a>>2]|0)==(j|0)){c[b>>2]=d;c[a>>2]=e;n=d;break}else fa()}while(0);do if(g|0){b=c[j+28>>2]|0;a=39212+(b<<2)|0;if((j|0)==(c[a>>2]|0)){c[a>>2]=n;if(!n){c[9728]=l&~(1<>>0<(c[9731]|0)>>>0)fa();b=g+16|0;if((c[b>>2]|0)==(j|0))c[b>>2]=n;else c[g+20>>2]=n;if(!n)break}a=c[9731]|0;if(n>>>0>>0)fa();c[n+24>>2]=g;b=c[j+16>>2]|0;do if(b|0)if(b>>>0>>0)fa();else{c[n+16>>2]=b;c[b+24>>2]=n;break}while(0);b=c[j+20>>2]|0;if(b|0)if(b>>>0<(c[9731]|0)>>>0)fa();else{c[n+20>>2]=b;c[b+24>>2]=n;break}}while(0);if(k>>>0<16){K=k+o|0;c[j+4>>2]=K|3;K=j+K+4|0;c[K>>2]=c[K>>2]|1}else{c[j+4>>2]=o|3;c[h+4>>2]=k|1;c[h+k>>2]=k;if(s|0){e=c[9732]|0;b=s>>>3;d=38948+(b<<1<<2)|0;b=1<>2]|0;if(a>>>0<(c[9731]|0)>>>0)fa();else{q=a;r=b}}else{c[9727]=t|b;q=d;r=d+8|0}c[r>>2]=e;c[q+12>>2]=e;c[e+8>>2]=q;c[e+12>>2]=d}c[9729]=k;c[9732]=h}K=j+8|0;i=L;return K|0}}}else if(a>>>0<=4294967231){a=a+11|0;o=a&-8;l=c[9728]|0;if(l){e=0-o|0;a=a>>>8;if(a)if(o>>>0>16777215)k=31;else{r=(a+1048320|0)>>>16&8;D=a<>>16&4;D=D<>>16&2;k=14-(q|r|k)+(D<>>15)|0;k=o>>>(k+7|0)&1|k<<1}else k=0;a=c[39212+(k<<2)>>2]|0;a:do if(!a){d=0;f=0;D=86}else{f=0;j=a;h=o<<((k|0)==31?0:25-(k>>>1)|0);d=0;while(1){a=(c[j+4>>2]&-8)-o|0;if(a>>>0>>0)if(!a){a=j;e=0;d=j;D=90;break a}else{f=j;e=a}a=c[j+20>>2]|0;j=c[j+16+(h>>>31<<2)>>2]|0;d=(a|0)==0|(a|0)==(j|0)?d:a;a=(j|0)==0;if(a){D=86;break}else h=h<<(a&1^1)}}while(0);if((D|0)==86){if((d|0)==0&(f|0)==0){a=2<>>12&16;r=r>>>m;k=r>>>5&8;r=r>>>k;n=r>>>2&4;r=r>>>n;q=r>>>1&2;r=r>>>q;d=r>>>1&1;d=c[39212+((k|m|n|q|d)+(r>>>d)<<2)>>2]|0}if(!d){k=f;j=e}else{a=f;D=90}}if((D|0)==90)while(1){D=0;r=(c[d+4>>2]&-8)-o|0;f=r>>>0>>0;e=f?r:e;a=f?d:a;f=c[d+16>>2]|0;if(f|0){d=f;D=90;continue}d=c[d+20>>2]|0;if(!d){k=a;j=e;break}else D=90}if((k|0)!=0?j>>>0<((c[9729]|0)-o|0)>>>0:0){f=c[9731]|0;if(k>>>0>>0)fa();h=k+o|0;if(k>>>0>=h>>>0)fa();g=c[k+24>>2]|0;d=c[k+12>>2]|0;do if((d|0)==(k|0)){a=k+20|0;b=c[a>>2]|0;if(!b){a=k+16|0;b=c[a>>2]|0;if(!b){s=0;break}}while(1){d=b+20|0;e=c[d>>2]|0;if(e|0){b=e;a=d;continue}d=b+16|0;e=c[d>>2]|0;if(!e)break;else{b=e;a=d}}if(a>>>0>>0)fa();else{c[a>>2]=0;s=b;break}}else{e=c[k+8>>2]|0;if(e>>>0>>0)fa();b=e+12|0;if((c[b>>2]|0)!=(k|0))fa();a=d+8|0;if((c[a>>2]|0)==(k|0)){c[b>>2]=d;c[a>>2]=e;s=d;break}else fa()}while(0);do if(g){b=c[k+28>>2]|0;a=39212+(b<<2)|0;if((k|0)==(c[a>>2]|0)){c[a>>2]=s;if(!s){t=l&~(1<>>0<(c[9731]|0)>>>0)fa();b=g+16|0;if((c[b>>2]|0)==(k|0))c[b>>2]=s;else c[g+20>>2]=s;if(!s){t=l;break}}a=c[9731]|0;if(s>>>0>>0)fa();c[s+24>>2]=g;b=c[k+16>>2]|0;do if(b|0)if(b>>>0>>0)fa();else{c[s+16>>2]=b;c[b+24>>2]=s;break}while(0);b=c[k+20>>2]|0;if(b)if(b>>>0<(c[9731]|0)>>>0)fa();else{c[s+20>>2]=b;c[b+24>>2]=s;t=l;break}else t=l}else t=l;while(0);do if(j>>>0>=16){c[k+4>>2]=o|3;c[h+4>>2]=j|1;c[h+j>>2]=j;b=j>>>3;if(j>>>0<256){d=38948+(b<<1<<2)|0;a=c[9727]|0;b=1<>2]|0;if(a>>>0<(c[9731]|0)>>>0)fa();else{B=a;C=b}}else{c[9727]=a|b;B=d;C=d+8|0}c[C>>2]=h;c[B+12>>2]=h;c[h+8>>2]=B;c[h+12>>2]=d;break}b=j>>>8;if(b)if(j>>>0>16777215)b=31;else{J=(b+1048320|0)>>>16&8;K=b<>>16&4;K=K<>>16&2;b=14-(I|J|b)+(K<>>15)|0;b=j>>>(b+7|0)&1|b<<1}else b=0;d=39212+(b<<2)|0;c[h+28>>2]=b;a=h+16|0;c[a+4>>2]=0;c[a>>2]=0;a=1<>2]=h;c[h+24>>2]=d;c[h+12>>2]=h;c[h+8>>2]=h;break}a=j<<((b|0)==31?0:25-(b>>>1)|0);e=c[d>>2]|0;while(1){if((c[e+4>>2]&-8|0)==(j|0)){D=148;break}d=e+16+(a>>>31<<2)|0;b=c[d>>2]|0;if(!b){D=145;break}else{a=a<<1;e=b}}if((D|0)==145)if(d>>>0<(c[9731]|0)>>>0)fa();else{c[d>>2]=h;c[h+24>>2]=e;c[h+12>>2]=h;c[h+8>>2]=h;break}else if((D|0)==148){b=e+8|0;a=c[b>>2]|0;K=c[9731]|0;if(a>>>0>=K>>>0&e>>>0>=K>>>0){c[a+12>>2]=h;c[b>>2]=h;c[h+8>>2]=a;c[h+12>>2]=e;c[h+24>>2]=0;break}else fa()}}else{K=j+o|0;c[k+4>>2]=K|3;K=k+K+4|0;c[K>>2]=c[K>>2]|1}while(0);K=k+8|0;i=L;return K|0}}}else o=-1;while(0);d=c[9729]|0;if(d>>>0>=o>>>0){b=d-o|0;a=c[9732]|0;if(b>>>0>15){K=a+o|0;c[9732]=K;c[9729]=b;c[K+4>>2]=b|1;c[K+b>>2]=b;c[a+4>>2]=o|3}else{c[9729]=0;c[9732]=0;c[a+4>>2]=d|3;K=a+d+4|0;c[K>>2]=c[K>>2]|1}K=a+8|0;i=L;return K|0}j=c[9730]|0;if(j>>>0>o>>>0){I=j-o|0;c[9730]=I;K=c[9733]|0;J=K+o|0;c[9733]=J;c[J+4>>2]=I|1;c[K+4>>2]=o|3;K=K+8|0;i=L;return K|0}if(!(c[9845]|0)){c[9847]=4096;c[9846]=4096;c[9848]=-1;c[9849]=-1;c[9850]=0;c[9838]=0;a=p&-16^1431655768;c[p>>2]=a;c[9845]=a;a=4096}else a=c[9847]|0;k=o+48|0;l=o+47|0;h=a+l|0;f=0-a|0;m=h&f;if(m>>>0<=o>>>0){K=0;i=L;return K|0}a=c[9837]|0;if(a|0?(B=c[9835]|0,C=B+m|0,C>>>0<=B>>>0|C>>>0>a>>>0):0){K=0;i=L;return K|0}b:do if(!(c[9838]&4)){d=c[9733]|0;c:do if(d){e=39356;while(1){a=c[e>>2]|0;if(a>>>0<=d>>>0?(u=e+4|0,(a+(c[u>>2]|0)|0)>>>0>d>>>0):0)break;a=c[e+8>>2]|0;if(!a){D=172;break c}else e=a}d=h-j&f;if(d>>>0<2147483647){a=rc(d|0)|0;if((a|0)==((c[e>>2]|0)+(c[u>>2]|0)|0)){if((a|0)!=(-1|0)){h=d;g=a;D=190;break b}}else{b=d;D=180}}}else D=172;while(0);do if(((D|0)==172?(g=rc(0)|0,(g|0)!=(-1|0)):0)?(b=g,v=c[9846]|0,w=v+-1|0,b=((w&b|0)==0?0:(w+b&0-v)-b|0)+m|0,v=c[9835]|0,w=b+v|0,b>>>0>o>>>0&b>>>0<2147483647):0){C=c[9837]|0;if(C|0?w>>>0<=v>>>0|w>>>0>C>>>0:0)break;a=rc(b|0)|0;if((a|0)==(g|0)){h=b;D=190;break b}else D=180}while(0);d:do if((D|0)==180){d=0-b|0;do if(k>>>0>b>>>0&(b>>>0<2147483647&(a|0)!=(-1|0))?(x=c[9847]|0,x=l-b+x&0-x,x>>>0<2147483647):0)if((rc(x|0)|0)==(-1|0)){rc(d|0)|0;break d}else{b=x+b|0;break}while(0);if((a|0)!=(-1|0)){h=b;g=a;D=190;break b}}while(0);c[9838]=c[9838]|4;D=187}else D=187;while(0);if((((D|0)==187?m>>>0<2147483647:0)?(A=rc(m|0)|0,y=rc(0)|0,A>>>0>>0&((A|0)!=(-1|0)&(y|0)!=(-1|0))):0)?(z=y-A|0,z>>>0>(o+40|0)>>>0):0){h=z;g=A;D=190}if((D|0)==190){b=(c[9835]|0)+h|0;c[9835]=b;if(b>>>0>(c[9836]|0)>>>0)c[9836]=b;l=c[9733]|0;do if(l){b=39356;while(1){a=c[b>>2]|0;d=b+4|0;e=c[d>>2]|0;if((g|0)==(a+e|0)){D=200;break}f=c[b+8>>2]|0;if(!f)break;else b=f}if(((D|0)==200?(c[b+12>>2]&8|0)==0:0)?l>>>0>>0&l>>>0>=a>>>0:0){c[d>>2]=e+h;K=l+8|0;K=(K&7|0)==0?0:0-K&7;J=l+K|0;K=h-K+(c[9730]|0)|0;c[9733]=J;c[9730]=K;c[J+4>>2]=K|1;c[J+K+4>>2]=40;c[9734]=c[9849];break}b=c[9731]|0;if(g>>>0>>0){c[9731]=g;j=g}else j=b;a=g+h|0;b=39356;while(1){if((c[b>>2]|0)==(a|0)){D=208;break}b=c[b+8>>2]|0;if(!b){a=39356;break}}if((D|0)==208)if(!(c[b+12>>2]&8)){c[b>>2]=g;n=b+4|0;c[n>>2]=(c[n>>2]|0)+h;n=g+8|0;n=g+((n&7|0)==0?0:0-n&7)|0;b=a+8|0;b=a+((b&7|0)==0?0:0-b&7)|0;m=n+o|0;k=b-n-o|0;c[n+4>>2]=o|3;do if((b|0)!=(l|0)){if((b|0)==(c[9732]|0)){K=(c[9729]|0)+k|0;c[9729]=K;c[9732]=m;c[m+4>>2]=K|1;c[m+K>>2]=K;break}a=c[b+4>>2]|0;if((a&3|0)==1){h=a&-8;f=a>>>3;e:do if(a>>>0>=256){g=c[b+24>>2]|0;e=c[b+12>>2]|0;do if((e|0)==(b|0)){e=b+16|0;d=e+4|0;a=c[d>>2]|0;if(!a){a=c[e>>2]|0;if(!a){I=0;break}else d=e}while(1){e=a+20|0;f=c[e>>2]|0;if(f|0){a=f;d=e;continue}e=a+16|0;f=c[e>>2]|0;if(!f)break;else{a=f;d=e}}if(d>>>0>>0)fa();else{c[d>>2]=0;I=a;break}}else{f=c[b+8>>2]|0;if(f>>>0>>0)fa();a=f+12|0;if((c[a>>2]|0)!=(b|0))fa();d=e+8|0;if((c[d>>2]|0)==(b|0)){c[a>>2]=e;c[d>>2]=f;I=e;break}else fa()}while(0);if(!g)break;a=c[b+28>>2]|0;d=39212+(a<<2)|0;do if((b|0)!=(c[d>>2]|0)){if(g>>>0<(c[9731]|0)>>>0)fa();a=g+16|0;if((c[a>>2]|0)==(b|0))c[a>>2]=I;else c[g+20>>2]=I;if(!I)break e}else{c[d>>2]=I;if(I|0)break;c[9728]=c[9728]&~(1<>>0>>0)fa();c[I+24>>2]=g;a=b+16|0;d=c[a>>2]|0;do if(d|0)if(d>>>0>>0)fa();else{c[I+16>>2]=d;c[d+24>>2]=I;break}while(0);a=c[a+4>>2]|0;if(!a)break;if(a>>>0<(c[9731]|0)>>>0)fa();else{c[I+20>>2]=a;c[a+24>>2]=I;break}}else{d=c[b+8>>2]|0;e=c[b+12>>2]|0;a=38948+(f<<1<<2)|0;do if((d|0)!=(a|0)){if(d>>>0>>0)fa();if((c[d+12>>2]|0)==(b|0))break;fa()}while(0);if((e|0)==(d|0)){c[9727]=c[9727]&~(1<>>0>>0)fa();a=e+8|0;if((c[a>>2]|0)==(b|0)){F=a;break}fa()}while(0);c[d+12>>2]=e;c[F>>2]=d}while(0);b=b+h|0;f=h+k|0}else f=k;b=b+4|0;c[b>>2]=c[b>>2]&-2;c[m+4>>2]=f|1;c[m+f>>2]=f;b=f>>>3;if(f>>>0<256){d=38948+(b<<1<<2)|0;a=c[9727]|0;b=1<>2]|0;if(a>>>0>=(c[9731]|0)>>>0){J=a;K=b;break}fa()}while(0);c[K>>2]=m;c[J+12>>2]=m;c[m+8>>2]=J;c[m+12>>2]=d;break}b=f>>>8;do if(!b)b=0;else{if(f>>>0>16777215){b=31;break}J=(b+1048320|0)>>>16&8;K=b<>>16&4;K=K<>>16&2;b=14-(I|J|b)+(K<>>15)|0;b=f>>>(b+7|0)&1|b<<1}while(0);e=39212+(b<<2)|0;c[m+28>>2]=b;a=m+16|0;c[a+4>>2]=0;c[a>>2]=0;a=c[9728]|0;d=1<>2]=m;c[m+24>>2]=e;c[m+12>>2]=m;c[m+8>>2]=m;break}a=f<<((b|0)==31?0:25-(b>>>1)|0);e=c[e>>2]|0;while(1){if((c[e+4>>2]&-8|0)==(f|0)){D=278;break}d=e+16+(a>>>31<<2)|0;b=c[d>>2]|0;if(!b){D=275;break}else{a=a<<1;e=b}}if((D|0)==275)if(d>>>0<(c[9731]|0)>>>0)fa();else{c[d>>2]=m;c[m+24>>2]=e;c[m+12>>2]=m;c[m+8>>2]=m;break}else if((D|0)==278){b=e+8|0;a=c[b>>2]|0;K=c[9731]|0;if(a>>>0>=K>>>0&e>>>0>=K>>>0){c[a+12>>2]=m;c[b>>2]=m;c[m+8>>2]=a;c[m+12>>2]=e;c[m+24>>2]=0;break}else fa()}}else{K=(c[9730]|0)+k|0;c[9730]=K;c[9733]=m;c[m+4>>2]=K|1}while(0);K=n+8|0;i=L;return K|0}else a=39356;while(1){b=c[a>>2]|0;if(b>>>0<=l>>>0?(E=b+(c[a+4>>2]|0)|0,E>>>0>l>>>0):0)break;a=c[a+8>>2]|0}f=E+-47|0;a=f+8|0;a=f+((a&7|0)==0?0:0-a&7)|0;f=l+16|0;a=a>>>0>>0?l:a;b=a+8|0;d=g+8|0;d=(d&7|0)==0?0:0-d&7;K=g+d|0;d=h+-40-d|0;c[9733]=K;c[9730]=d;c[K+4>>2]=d|1;c[K+d+4>>2]=40;c[9734]=c[9849];d=a+4|0;c[d>>2]=27;c[b>>2]=c[9839];c[b+4>>2]=c[9840];c[b+8>>2]=c[9841];c[b+12>>2]=c[9842];c[9839]=g;c[9840]=h;c[9842]=0;c[9841]=b;b=a+24|0;do{b=b+4|0;c[b>>2]=7}while((b+4|0)>>>0>>0);if((a|0)!=(l|0)){g=a-l|0;c[d>>2]=c[d>>2]&-2;c[l+4>>2]=g|1;c[a>>2]=g;b=g>>>3;if(g>>>0<256){d=38948+(b<<1<<2)|0;a=c[9727]|0;b=1<>2]|0;if(a>>>0<(c[9731]|0)>>>0)fa();else{G=a;H=b}}else{c[9727]=a|b;G=d;H=d+8|0}c[H>>2]=l;c[G+12>>2]=l;c[l+8>>2]=G;c[l+12>>2]=d;break}b=g>>>8;if(b)if(g>>>0>16777215)d=31;else{J=(b+1048320|0)>>>16&8;K=b<>>16&4;K=K<>>16&2;d=14-(I|J|d)+(K<>>15)|0;d=g>>>(d+7|0)&1|d<<1}else d=0;e=39212+(d<<2)|0;c[l+28>>2]=d;c[l+20>>2]=0;c[f>>2]=0;b=c[9728]|0;a=1<>2]=l;c[l+24>>2]=e;c[l+12>>2]=l;c[l+8>>2]=l;break}a=g<<((d|0)==31?0:25-(d>>>1)|0);e=c[e>>2]|0;while(1){if((c[e+4>>2]&-8|0)==(g|0)){D=304;break}d=e+16+(a>>>31<<2)|0;b=c[d>>2]|0;if(!b){D=301;break}else{a=a<<1;e=b}}if((D|0)==301)if(d>>>0<(c[9731]|0)>>>0)fa();else{c[d>>2]=l;c[l+24>>2]=e;c[l+12>>2]=l;c[l+8>>2]=l;break}else if((D|0)==304){b=e+8|0;a=c[b>>2]|0;K=c[9731]|0;if(a>>>0>=K>>>0&e>>>0>=K>>>0){c[a+12>>2]=l;c[b>>2]=l;c[l+8>>2]=a;c[l+12>>2]=e;c[l+24>>2]=0;break}else fa()}}}else{K=c[9731]|0;if((K|0)==0|g>>>0>>0)c[9731]=g;c[9839]=g;c[9840]=h;c[9842]=0;c[9736]=c[9845];c[9735]=-1;b=0;do{K=38948+(b<<1<<2)|0;c[K+12>>2]=K;c[K+8>>2]=K;b=b+1|0}while((b|0)!=32);K=g+8|0;K=(K&7|0)==0?0:0-K&7;J=g+K|0;K=h+-40-K|0;c[9733]=J;c[9730]=K;c[J+4>>2]=K|1;c[J+K+4>>2]=40;c[9734]=c[9849]}while(0);b=c[9730]|0;if(b>>>0>o>>>0){I=b-o|0;c[9730]=I;K=c[9733]|0;J=K+o|0;c[9733]=J;c[J+4>>2]=I|1;c[K+4>>2]=o|3;K=K+8|0;i=L;return K|0}}c[(Rb()|0)>>2]=12;K=0;i=L;return K|0}function ic(a){a=a|0;var b=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0;if(!a)return;d=a+-8|0;h=c[9731]|0;if(d>>>0>>0)fa();a=c[a+-4>>2]|0;b=a&3;if((b|0)==1)fa();e=a&-8;n=d+e|0;do if(!(a&1)){a=c[d>>2]|0;if(!b)return;k=d+(0-a)|0;j=a+e|0;if(k>>>0>>0)fa();if((k|0)==(c[9732]|0)){a=n+4|0;b=c[a>>2]|0;if((b&3|0)!=3){q=k;f=j;break}c[9729]=j;c[a>>2]=b&-2;c[k+4>>2]=j|1;c[k+j>>2]=j;return}e=a>>>3;if(a>>>0<256){b=c[k+8>>2]|0;d=c[k+12>>2]|0;a=38948+(e<<1<<2)|0;if((b|0)!=(a|0)){if(b>>>0>>0)fa();if((c[b+12>>2]|0)!=(k|0))fa()}if((d|0)==(b|0)){c[9727]=c[9727]&~(1<>>0>>0)fa();a=d+8|0;if((c[a>>2]|0)==(k|0))g=a;else fa()}else g=d+8|0;c[b+12>>2]=d;c[g>>2]=b;q=k;f=j;break}g=c[k+24>>2]|0;d=c[k+12>>2]|0;do if((d|0)==(k|0)){d=k+16|0;b=d+4|0;a=c[b>>2]|0;if(!a){a=c[d>>2]|0;if(!a){i=0;break}else b=d}while(1){d=a+20|0;e=c[d>>2]|0;if(e|0){a=e;b=d;continue}d=a+16|0;e=c[d>>2]|0;if(!e)break;else{a=e;b=d}}if(b>>>0>>0)fa();else{c[b>>2]=0;i=a;break}}else{e=c[k+8>>2]|0;if(e>>>0>>0)fa();a=e+12|0;if((c[a>>2]|0)!=(k|0))fa();b=d+8|0;if((c[b>>2]|0)==(k|0)){c[a>>2]=d;c[b>>2]=e;i=d;break}else fa()}while(0);if(g){a=c[k+28>>2]|0;b=39212+(a<<2)|0;if((k|0)==(c[b>>2]|0)){c[b>>2]=i;if(!i){c[9728]=c[9728]&~(1<>>0<(c[9731]|0)>>>0)fa();a=g+16|0;if((c[a>>2]|0)==(k|0))c[a>>2]=i;else c[g+20>>2]=i;if(!i){q=k;f=j;break}}d=c[9731]|0;if(i>>>0>>0)fa();c[i+24>>2]=g;a=k+16|0;b=c[a>>2]|0;do if(b|0)if(b>>>0>>0)fa();else{c[i+16>>2]=b;c[b+24>>2]=i;break}while(0);a=c[a+4>>2]|0;if(a)if(a>>>0<(c[9731]|0)>>>0)fa();else{c[i+20>>2]=a;c[a+24>>2]=i;q=k;f=j;break}else{q=k;f=j}}else{q=k;f=j}}else{q=d;f=e}while(0);if(q>>>0>=n>>>0)fa();a=n+4|0;b=c[a>>2]|0;if(!(b&1))fa();if(!(b&2)){if((n|0)==(c[9733]|0)){p=(c[9730]|0)+f|0;c[9730]=p;c[9733]=q;c[q+4>>2]=p|1;if((q|0)!=(c[9732]|0))return;c[9732]=0;c[9729]=0;return}if((n|0)==(c[9732]|0)){p=(c[9729]|0)+f|0;c[9729]=p;c[9732]=q;c[q+4>>2]=p|1;c[q+p>>2]=p;return}f=(b&-8)+f|0;e=b>>>3;do if(b>>>0>=256){g=c[n+24>>2]|0;a=c[n+12>>2]|0;do if((a|0)==(n|0)){d=n+16|0;b=d+4|0;a=c[b>>2]|0;if(!a){a=c[d>>2]|0;if(!a){m=0;break}else b=d}while(1){d=a+20|0;e=c[d>>2]|0;if(e|0){a=e;b=d;continue}d=a+16|0;e=c[d>>2]|0;if(!e)break;else{a=e;b=d}}if(b>>>0<(c[9731]|0)>>>0)fa();else{c[b>>2]=0;m=a;break}}else{b=c[n+8>>2]|0;if(b>>>0<(c[9731]|0)>>>0)fa();d=b+12|0;if((c[d>>2]|0)!=(n|0))fa();e=a+8|0;if((c[e>>2]|0)==(n|0)){c[d>>2]=a;c[e>>2]=b;m=a;break}else fa()}while(0);if(g|0){a=c[n+28>>2]|0;b=39212+(a<<2)|0;if((n|0)==(c[b>>2]|0)){c[b>>2]=m;if(!m){c[9728]=c[9728]&~(1<>>0<(c[9731]|0)>>>0)fa();a=g+16|0;if((c[a>>2]|0)==(n|0))c[a>>2]=m;else c[g+20>>2]=m;if(!m)break}d=c[9731]|0;if(m>>>0>>0)fa();c[m+24>>2]=g;a=n+16|0;b=c[a>>2]|0;do if(b|0)if(b>>>0>>0)fa();else{c[m+16>>2]=b;c[b+24>>2]=m;break}while(0);a=c[a+4>>2]|0;if(a|0)if(a>>>0<(c[9731]|0)>>>0)fa();else{c[m+20>>2]=a;c[a+24>>2]=m;break}}}else{b=c[n+8>>2]|0;d=c[n+12>>2]|0;a=38948+(e<<1<<2)|0;if((b|0)!=(a|0)){if(b>>>0<(c[9731]|0)>>>0)fa();if((c[b+12>>2]|0)!=(n|0))fa()}if((d|0)==(b|0)){c[9727]=c[9727]&~(1<>>0<(c[9731]|0)>>>0)fa();a=d+8|0;if((c[a>>2]|0)==(n|0))l=a;else fa()}else l=d+8|0;c[b+12>>2]=d;c[l>>2]=b}while(0);c[q+4>>2]=f|1;c[q+f>>2]=f;if((q|0)==(c[9732]|0)){c[9729]=f;return}}else{c[a>>2]=b&-2;c[q+4>>2]=f|1;c[q+f>>2]=f}a=f>>>3;if(f>>>0<256){d=38948+(a<<1<<2)|0;b=c[9727]|0;a=1<>2]|0;if(b>>>0<(c[9731]|0)>>>0)fa();else{o=b;p=a}}else{c[9727]=b|a;o=d;p=d+8|0}c[p>>2]=q;c[o+12>>2]=q;c[q+8>>2]=o;c[q+12>>2]=d;return}a=f>>>8;if(a)if(f>>>0>16777215)a=31;else{o=(a+1048320|0)>>>16&8;p=a<>>16&4;p=p<>>16&2;a=14-(n|o|a)+(p<>>15)|0;a=f>>>(a+7|0)&1|a<<1}else a=0;e=39212+(a<<2)|0;c[q+28>>2]=a;c[q+20>>2]=0;c[q+16>>2]=0;b=c[9728]|0;d=1<>>1)|0);e=c[e>>2]|0;while(1){if((c[e+4>>2]&-8|0)==(f|0)){a=130;break}d=e+16+(b>>>31<<2)|0;a=c[d>>2]|0;if(!a){a=127;break}else{b=b<<1;e=a}}if((a|0)==127)if(d>>>0<(c[9731]|0)>>>0)fa();else{c[d>>2]=q;c[q+24>>2]=e;c[q+12>>2]=q;c[q+8>>2]=q;break}else if((a|0)==130){a=e+8|0;b=c[a>>2]|0;p=c[9731]|0;if(b>>>0>=p>>>0&e>>>0>=p>>>0){c[b+12>>2]=q;c[a>>2]=q;c[q+8>>2]=b;c[q+12>>2]=e;c[q+24>>2]=0;break}else fa()}}else{c[9728]=b|d;c[e>>2]=q;c[q+24>>2]=e;c[q+12>>2]=q;c[q+8>>2]=q}while(0);q=(c[9735]|0)+-1|0;c[9735]=q;if(!q)a=39364;else return;while(1){a=c[a>>2]|0;if(!a)break;else a=a+8|0}c[9735]=-1;return}function jc(){}function kc(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;d=b-d-(c>>>0>a>>>0|0)>>>0;return (C=d,a-c>>>0|0)|0}function lc(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,i=0;f=b+e|0;if((e|0)>=20){d=d&255;h=b&3;i=d|d<<8|d<<16|d<<24;g=f&~3;if(h){h=b+4-h|0;while((b|0)<(h|0)){a[b>>0]=d;b=b+1|0}}while((b|0)<(g|0)){c[b>>2]=i;b=b+4|0}}while((b|0)<(f|0)){a[b>>0]=d;b=b+1|0}return b-e|0}function mc(a,b,c){a=a|0;b=b|0;c=c|0;if((c|0)<32){C=b>>>c;return a>>>c|(b&(1<>>c-32|0}function nc(a,b,c){a=a|0;b=b|0;c=c|0;if((c|0)<32){C=b<>>32-c;return a<>>16;a=(c>>>16)+(R(e,d)|0)|0;e=b>>>16;b=R(e,f)|0;return (C=(a>>>16)+(R(e,d)|0)+(((a&65535)+b|0)>>>16)|0,a+b<<16|c&65535|0)|0}function pc(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0,f=0;e=a;f=c;c=oc(e,f)|0;a=C;return (C=(R(b,f)|0)+(R(d,e)|0)+a|a&0,c|0|0)|0}function qc(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;c=a+c>>>0;return (C=b+d+(c>>>0>>0|0)>>>0,c|0)|0}function rc(a){a=a|0;var b=0,d=0;d=a+15&-16|0;b=c[k>>2]|0;a=b+d|0;if((d|0)>0&(a|0)<(b|0)|(a|0)<0){Z()|0;sa(12);return -1}c[k>>2]=a;if((a|0)>(Y()|0)?(X()|0)==0:0){sa(12);c[k>>2]=b;return -1}return b|0}function sc(a){a=a|0;return (a&255)<<24|(a>>8&255)<<16|(a>>16&255)<<8|a>>>24|0}function tc(b,d,e){b=b|0;d=d|0;e=e|0;var f=0;if((e|0)>=4096)return la(b|0,d|0,e|0)|0;f=b|0;if((b&3)==(d&3)){while(b&3){if(!e)return f|0;a[b>>0]=a[d>>0]|0;b=b+1|0;d=d+1|0;e=e-1|0}while((e|0)>=4){c[b>>2]=c[d>>2];b=b+4|0;d=d+4|0;e=e-4|0}}while((e|0)>0){a[b>>0]=a[d>>0]|0;b=b+1|0;d=d+1|0;e=e-1|0}return f|0}function uc(){return 0}function vc(a,b){a=a|0;b=b|0;return ua[a&1](b|0)|0}function wc(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;return va[a&7](b|0,c|0,d|0)|0}function xc(a,b){a=a|0;b=b|0;wa[a&3](b|0)}function yc(a){a=a|0;V(0);return 0}function zc(a,b,c){a=a|0;b=b|0;c=c|0;V(1);return 0}function Ac(a){a=a|0;V(2)} // EMSCRIPTEN_END_FUNCS -var ua=[vc,Kb];var va=[wc,Tb,Mb,Rb,Lb,wc,wc,wc];var wa=[xc,Pb,Sb,xc];return{___muldsi3:lc,_sbrk:oc,_i64Subtract:hc,_free:fc,_ecdsa_read_pubkey:kb,_i64Add:nc,_pthread_self:rc,_memset:ic,_malloc:ec,_memcpy:qc,_llvm_bswap_i32:pc,___muldi3:mc,_bitshift64Lshr:jc,_fflush:Xb,_hdnode_public_ckd_address_optimized:tb,___errno_location:Ob,_bitshift64Shl:kc,runPostSets:gc,stackAlloc:xa,stackSave:ya,stackRestore:za,establishStackSpace:Aa,setThrew:Ba,setTempRet0:Ca,getTempRet0:Da,dynCall_ii:sc,dynCall_iiii:tc,dynCall_vi:uc}}) +var ua=[yc,Nb];var va=[zc,Wb,Pb,Ub,Ob,zc,zc,zc];var wa=[Ac,Sb,Vb,Ac];return{___muldsi3:oc,_sbrk:rc,_i64Subtract:kc,_free:ic,_ecdsa_read_pubkey:lb,_i64Add:qc,_pthread_self:uc,_memset:lc,_malloc:hc,_memcpy:tc,_llvm_bswap_i32:sc,___muldi3:pc,_bitshift64Lshr:mc,_fflush:ec,_hdnode_public_ckd_address_optimized:ub,___errno_location:Rb,_bitshift64Shl:nc,runPostSets:jc,stackAlloc:xa,stackSave:ya,stackRestore:za,establishStackSpace:Aa,setThrew:Ba,setTempRet0:Ca,getTempRet0:Da,dynCall_ii:vc,dynCall_iiii:wc,dynCall_vi:xc}}) // EMSCRIPTEN_END_ASM @@ -374,6 +374,6 @@ e.callMain=e.ad=function(a){function b(){for(var a=0;3>a;a++)d.push(0)}a=a||[];z function wc(a){function b(){if(!e.calledRun&&(e.calledRun=!0,!ja)){za||(za=!0,Qa(Sa));Qa(Ta);if(e.onRuntimeInitialized)e.onRuntimeInitialized();e._main&&yc&&e.callMain(a);if(e.postRun)for("function"==typeof e.postRun&&(e.postRun=[e.postRun]);e.postRun.length;)Wa(e.postRun.shift());Qa(Ua)}}a=a||e.arguments;null===uc&&(uc=Date.now());if(!(0 Date: Fri, 31 Mar 2017 01:36:29 +0200 Subject: [PATCH 382/627] fix typo in readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d37481e34..74dacc587 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ These include: - RIPEMD-160 - SHA256/SHA512 - SHA3/Keccak -- BLAKE2s/Blake2b +- BLAKE2s/BLAKE2b - unit tests (using Check - check.sf.net; in tests.c) - tests against OpenSSL (in test-openssl.c) From a46c3729690ca7cb23f1cee09f53411728130fbd Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 2 Apr 2017 00:01:07 +0200 Subject: [PATCH 383/627] build: use trusty in travis --- .travis.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index b1eb22536..2aeda0978 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,13 +1,12 @@ sudo: false +dist: trusty language: c addons: apt: - sources: - - george-edison55-precise-backports # CMake 3.x packages: - check - - cmake # Travis CI comes with CMake 2.8.7, we need CMake 2.8.11 + - cmake - cmake-data - libssl-dev - python-pip From 12af9b262be8e4ee6f94922b1fcbe10b0630bb9f Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 2 Apr 2017 01:07:00 +0200 Subject: [PATCH 384/627] build: switch to gcc-5 (in travis) --- .travis.yml | 4 ++++ Makefile | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2aeda0978..f819bc954 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,10 @@ language: c addons: apt: + sources: + - ubuntu-toolchain-r-test packages: + - gcc-5 - check - cmake - cmake-data @@ -15,6 +18,7 @@ install: - pip install --user pytest ecdsa curve25519-donna script: + - export CC='gcc-5' - make - ./tests - ./test-openssl 1000 diff --git a/Makefile b/Makefile index 5e0609f73..1e78ffe97 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ -CC = gcc +CC ?= gcc -OPTFLAGS = -O3 -g +OPTFLAGS ?= -O3 -g CFLAGS += $(OPTFLAGS) \ -std=gnu99 \ From d3d88591d0b5245343d09ec46afa75d65e5d1c2c Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Sun, 2 Apr 2017 00:08:04 +0200 Subject: [PATCH 385/627] Added co-signing for ed25519. --- ecdsa.c | 21 ++++++++---- ecdsa.h | 3 +- ed25519-donna/ed25519.c | 71 ++++++++++++++++++++++++++++++++++++++++- ed25519-donna/ed25519.h | 5 +++ tests.c | 56 +++++++++++++++++++++++++++++++- 5 files changed, 147 insertions(+), 9 deletions(-) diff --git a/ecdsa.c b/ecdsa.c index 310dad325..81dc2a82f 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -658,7 +658,7 @@ int ecdh_multiply(const ecdsa_curve *curve, const uint8_t *priv_key, const uint8 return 0; } -void init_k_rfc6979(const uint8_t *priv_key, const uint8_t *hash, rfc6979_state *state) { +void init_rfc6979(const uint8_t *priv_key, const uint8_t *hash, rfc6979_state *state) { uint8_t bx[2*32]; uint8_t buf[32 + 1 + 2*32]; @@ -684,18 +684,27 @@ void init_k_rfc6979(const uint8_t *priv_key, const uint8_t *hash, rfc6979_state MEMSET_BZERO(buf, sizeof(buf)); } -// generate K in a deterministic way, according to RFC6979 -// http://tools.ietf.org/html/rfc6979 -void generate_k_rfc6979(bignum256 *k, rfc6979_state *state) +// generate next number from deterministic random number generator +void generate_rfc6979(uint8_t rand[32], rfc6979_state *state) { uint8_t buf[32 + 1]; hmac_sha256(state->k, sizeof(state->k), state->v, sizeof(state->v), state->v); - bn_read_be(state->v, k); memcpy(buf, state->v, sizeof(state->v)); buf[sizeof(state->v)] = 0x00; hmac_sha256(state->k, sizeof(state->k), buf, sizeof(state->v) + 1, state->k); hmac_sha256(state->k, sizeof(state->k), state->v, sizeof(state->v), state->v); + memcpy(rand, buf, 32); + MEMSET_BZERO(buf, sizeof(buf)); +} + +// generate K in a deterministic way, according to RFC6979 +// http://tools.ietf.org/html/rfc6979 +void generate_k_rfc6979(bignum256 *k, rfc6979_state *state) +{ + uint8_t buf[32]; + generate_rfc6979(buf, state); + bn_read_be(buf, k); MEMSET_BZERO(buf, sizeof(buf)); } @@ -739,7 +748,7 @@ int ecdsa_sign_digest(const ecdsa_curve *curve, const uint8_t *priv_key, const u #if USE_RFC6979 rfc6979_state rng; - init_k_rfc6979(priv_key, digest, &rng); + init_rfc6979(priv_key, digest, &rng); #endif bn_read_be(digest, &z); diff --git a/ecdsa.h b/ecdsa.h index 163558a7d..596ec1ec6 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -91,7 +91,8 @@ int ecdsa_verify_digest_recover(const ecdsa_curve *curve, uint8_t *pub_key, cons int ecdsa_sig_to_der(const uint8_t *sig, uint8_t *der); // Private -void init_k_rfc6979(const uint8_t *priv_key, const uint8_t *hash, rfc6979_state *rng); +void init_rfc6979(const uint8_t *priv_key, const uint8_t *hash, rfc6979_state *rng); +void generate_rfc6979(uint8_t rand[32], rfc6979_state *rng); void generate_k_rfc6979(bignum256 *k, rfc6979_state *rng); void generate_k_random(bignum256 *k, const bignum256 *prime); diff --git a/ed25519-donna/ed25519.c b/ed25519-donna/ed25519.c index 631d15f9d..9a91896b2 100644 --- a/ed25519-donna/ed25519.c +++ b/ed25519-donna/ed25519.c @@ -44,6 +44,75 @@ ed25519_publickey(const ed25519_secret_key sk, ed25519_public_key pk) { ge25519_pack(pk, &A); } +int +ed25519_cosi_combine_publickeys(ed25519_public_key res, const ed25519_public_key *pks, size_t n) { + size_t i = 0; + ge25519 P; + ge25519_pniels sump; + ge25519_p1p1 sump1; + + if (n == 1) { + memcpy(res, pks, sizeof(ed25519_public_key)); + return 0; + } + if (!ge25519_unpack_negative_vartime(&P, pks[i++])) + return -1; + ge25519_full_to_pniels(&sump, &P); + while (i < n-1) { + if (!ge25519_unpack_negative_vartime(&P, pks[i++])) + return -1; + ge25519_pnielsadd(&sump, &P, &sump); + } + if (!ge25519_unpack_negative_vartime(&P, pks[i++])) + return -1; + ge25519_pnielsadd_p1p1(&sump1, &P, &sump, 0); + ge25519_p1p1_to_partial(&P, &sump1); + curve25519_neg(P.x, P.x); + ge25519_pack(res, &P); + return 0; +} + +void +ed25519_cosi_combine_signatures(ed25519_signature res, const ed25519_public_key R, const ed25519_cosi_signature *sigs, size_t n) { + bignum256modm s, t; + size_t i; + + i = 0; + expand256_modm(s, sigs[i++], 32); + while (i < n) { + expand256_modm(t, sigs[i++], 32); + add256_modm(s, s, t); + } + memcpy(res, R, 32); + contract256_modm(res + 32, s); +} + +void +ed25519_cosi_sign(const unsigned char *m, size_t mlen, const ed25519_secret_key sk, const ed25519_secret_key nonce, const ed25519_public_key R, const ed25519_public_key pk, ed25519_cosi_signature sig) { + bignum256modm r, S, a; + hash_512bits extsk, extnonce, hram; + + ed25519_extsk(extsk, sk); + ed25519_extsk(extnonce, nonce); + + /* r = nonce */ + expand256_modm(r, extnonce, 32); + + /* S = H(R,A,m).. */ + ed25519_hram(hram, R, pk, m, mlen); + expand256_modm(S, hram, 64); + + /* S = H(R,A,m)a */ + expand256_modm(a, extsk, 32); + mul256_modm(S, S, a); + + /* S = (r + H(R,A,m)a) */ + add256_modm(S, S, r); + + /* S = (r + H(R,A,m)a) mod L */ + contract256_modm(sig, S); +} + void ed25519_sign(const unsigned char *m, size_t mlen, const ed25519_secret_key sk, const ed25519_public_key pk, ed25519_signature RS) { ed25519_hash_context ctx; @@ -75,7 +144,7 @@ ed25519_sign(const unsigned char *m, size_t mlen, const ed25519_secret_key sk, c /* S = (r + H(R,A,m)a) */ add256_modm(S, S, r); - /* S = (r + H(R,A,m)a) mod L */ + /* S = (r + H(R,A,m)a) mod L */ contract256_modm(RS + 32, S); } diff --git a/ed25519-donna/ed25519.h b/ed25519-donna/ed25519.h index 96a2727b4..2fa64e402 100644 --- a/ed25519-donna/ed25519.h +++ b/ed25519-donna/ed25519.h @@ -5,6 +5,7 @@ extern "C" { #endif +typedef unsigned char ed25519_cosi_signature[32]; typedef unsigned char ed25519_signature[64]; typedef unsigned char ed25519_public_key[32]; typedef unsigned char ed25519_secret_key[32]; @@ -12,6 +13,10 @@ typedef unsigned char ed25519_secret_key[32]; typedef unsigned char curve25519_key[32]; void ed25519_publickey(const ed25519_secret_key sk, ed25519_public_key pk); + +int ed25519_cosi_combine_publickeys(ed25519_public_key res, const ed25519_public_key *pks, size_t n); +void ed25519_cosi_combine_signatures(ed25519_signature res, const ed25519_public_key R, const ed25519_cosi_signature *sigs, size_t n); +void ed25519_cosi_sign(const unsigned char *m, size_t mlen, const ed25519_secret_key key, const ed25519_secret_key nonce, const ed25519_public_key R, const ed25519_public_key pk, ed25519_cosi_signature sig); int ed25519_sign_open(const unsigned char *m, size_t mlen, const ed25519_public_key pk, const ed25519_signature RS); void ed25519_sign(const unsigned char *m, size_t mlen, const ed25519_secret_key sk, const ed25519_public_key pk, ed25519_signature RS); diff --git a/tests.c b/tests.c index 97e0ec7ed..a9c37ab01 100644 --- a/tests.c +++ b/tests.c @@ -1287,7 +1287,7 @@ END_TEST #define test_deterministic(KEY, MSG, K) do { \ sha256_Raw((uint8_t *)MSG, strlen(MSG), buf); \ - init_k_rfc6979(fromhex(KEY), buf, &rng); \ + init_rfc6979(fromhex(KEY), buf, &rng); \ generate_k_rfc6979(&k, &rng); \ bn_write_be(&k, buf); \ ck_assert_mem_eq(buf, fromhex(K), 32); \ @@ -2650,6 +2650,56 @@ START_TEST(test_ed25519) { } END_TEST +START_TEST(test_ed25519_cosi) { + int MAXN=10; + ed25519_secret_key keys[MAXN]; + ed25519_public_key pubkeys[MAXN]; + ed25519_secret_key nonces[MAXN]; + ed25519_public_key Rs[MAXN]; + ed25519_cosi_signature sigs[MAXN]; + unsigned char msg[32]; + rfc6979_state rng; + int res; + + init_rfc6979(fromhex("26c76712d89d906e6672dafa614c42e5cb1caac8c6568e4d2493087db51f0d36"), + fromhex("26659c1cf7321c178c07437150639ff0c5b7679c7ea195253ed9abda2e081a37"), &rng); + + for (int N = 1; N < 11; N++) { + ed25519_public_key pk; + ed25519_public_key R; + ed25519_signature sig; + /* phase 0: create priv/pubkeys and combine pubkeys */ + for (int j = 0; j < N; j++) { + generate_rfc6979(keys[j], &rng); + ed25519_publickey(keys[j], pubkeys[j]); + } + res = ed25519_cosi_combine_publickeys(pk, pubkeys, N); + ck_assert_int_eq(res, 0); + + generate_rfc6979(msg, &rng); + + /* phase 1: create nonces, commitments (R values) and combine commitments */ + for (int j = 0; j < N; j++) { + generate_rfc6979(nonces[j], &rng); + ed25519_publickey(nonces[j], Rs[j]); + } + res = ed25519_cosi_combine_publickeys(R, Rs, N); + ck_assert_int_eq(res, 0); + + /* phase 2: sign and combine signatures */ + for (int j = 0; j < N; j++) { + ed25519_cosi_sign(msg, sizeof(msg), keys[j], nonces[j], R, pk, sigs[j]); + } + + ed25519_cosi_combine_signatures(sig, R, sigs, N); + + /* check signature */ + res = ed25519_sign_open(msg, sizeof(msg), pk, sig); + ck_assert_int_eq(res, 0); + } +} +END_TEST + static void test_bip32_ecdh_init_node(HDNode *node, const char *seed_str, const char *curve_name) { hdnode_from_seed((const uint8_t *)seed_str, strlen(seed_str), curve_name, node); hdnode_fill_public_key(node); @@ -3040,6 +3090,10 @@ Suite *test_suite(void) tcase_add_test(tc, test_ed25519); suite_add_tcase(s, tc); + tc = tcase_create("ed25519_cosi"); + tcase_add_test(tc, test_ed25519_cosi); + suite_add_tcase(s, tc); + tc = tcase_create("script"); tcase_add_test(tc, test_output_script); suite_add_tcase(s, tc); From b666039f669299618d6f162d95d2bee49114fb13 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 2 Apr 2017 01:28:18 +0200 Subject: [PATCH 386/627] ed25519_cosi: small changes to code style --- ed25519-donna/ed25519.c | 14 ++++++++------ tests.c | 4 ++-- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/ed25519-donna/ed25519.c b/ed25519-donna/ed25519.c index 9a91896b2..4182a3253 100644 --- a/ed25519-donna/ed25519.c +++ b/ed25519-donna/ed25519.c @@ -55,16 +55,19 @@ ed25519_cosi_combine_publickeys(ed25519_public_key res, const ed25519_public_key memcpy(res, pks, sizeof(ed25519_public_key)); return 0; } - if (!ge25519_unpack_negative_vartime(&P, pks[i++])) + if (!ge25519_unpack_negative_vartime(&P, pks[i++])) { return -1; + } ge25519_full_to_pniels(&sump, &P); - while (i < n-1) { - if (!ge25519_unpack_negative_vartime(&P, pks[i++])) + while (i < n - 1) { + if (!ge25519_unpack_negative_vartime(&P, pks[i++])) { return -1; + } ge25519_pnielsadd(&sump, &P, &sump); } - if (!ge25519_unpack_negative_vartime(&P, pks[i++])) + if (!ge25519_unpack_negative_vartime(&P, pks[i++])) { return -1; + } ge25519_pnielsadd_p1p1(&sump1, &P, &sump, 0); ge25519_p1p1_to_partial(&P, &sump1); curve25519_neg(P.x, P.x); @@ -75,9 +78,8 @@ ed25519_cosi_combine_publickeys(ed25519_public_key res, const ed25519_public_key void ed25519_cosi_combine_signatures(ed25519_signature res, const ed25519_public_key R, const ed25519_cosi_signature *sigs, size_t n) { bignum256modm s, t; - size_t i; + size_t i = 0; - i = 0; expand256_modm(s, sigs[i++], 32); while (i < n) { expand256_modm(t, sigs[i++], 32); diff --git a/tests.c b/tests.c index a9c37ab01..88be17f88 100644 --- a/tests.c +++ b/tests.c @@ -2651,13 +2651,13 @@ START_TEST(test_ed25519) { END_TEST START_TEST(test_ed25519_cosi) { - int MAXN=10; + const int MAXN = 10; ed25519_secret_key keys[MAXN]; ed25519_public_key pubkeys[MAXN]; ed25519_secret_key nonces[MAXN]; ed25519_public_key Rs[MAXN]; ed25519_cosi_signature sigs[MAXN]; - unsigned char msg[32]; + uint8_t msg[32]; rfc6979_state rng; int res; From 900f4b0756a57706ebffbe77b96d941a9b2ee981 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 2 Apr 2017 02:51:09 +0200 Subject: [PATCH 387/627] build: don't use const for ed25519/cosi if gcc<5 --- ed25519-donna/ed25519.c | 4 ++-- ed25519-donna/ed25519.h | 16 ++++++++++++---- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/ed25519-donna/ed25519.c b/ed25519-donna/ed25519.c index 4182a3253..7a117aef1 100644 --- a/ed25519-donna/ed25519.c +++ b/ed25519-donna/ed25519.c @@ -45,7 +45,7 @@ ed25519_publickey(const ed25519_secret_key sk, ed25519_public_key pk) { } int -ed25519_cosi_combine_publickeys(ed25519_public_key res, const ed25519_public_key *pks, size_t n) { +ed25519_cosi_combine_publickeys(ed25519_public_key res, CONST ed25519_public_key *pks, size_t n) { size_t i = 0; ge25519 P; ge25519_pniels sump; @@ -76,7 +76,7 @@ ed25519_cosi_combine_publickeys(ed25519_public_key res, const ed25519_public_key } void -ed25519_cosi_combine_signatures(ed25519_signature res, const ed25519_public_key R, const ed25519_cosi_signature *sigs, size_t n) { +ed25519_cosi_combine_signatures(ed25519_signature res, const ed25519_public_key R, CONST ed25519_cosi_signature *sigs, size_t n) { bignum256modm s, t; size_t i = 0; diff --git a/ed25519-donna/ed25519.h b/ed25519-donna/ed25519.h index 2fa64e402..dd76be42e 100644 --- a/ed25519-donna/ed25519.h +++ b/ed25519-donna/ed25519.h @@ -5,24 +5,32 @@ extern "C" { #endif -typedef unsigned char ed25519_cosi_signature[32]; typedef unsigned char ed25519_signature[64]; typedef unsigned char ed25519_public_key[32]; typedef unsigned char ed25519_secret_key[32]; typedef unsigned char curve25519_key[32]; +typedef unsigned char ed25519_cosi_signature[32]; + void ed25519_publickey(const ed25519_secret_key sk, ed25519_public_key pk); -int ed25519_cosi_combine_publickeys(ed25519_public_key res, const ed25519_public_key *pks, size_t n); -void ed25519_cosi_combine_signatures(ed25519_signature res, const ed25519_public_key R, const ed25519_cosi_signature *sigs, size_t n); -void ed25519_cosi_sign(const unsigned char *m, size_t mlen, const ed25519_secret_key key, const ed25519_secret_key nonce, const ed25519_public_key R, const ed25519_public_key pk, ed25519_cosi_signature sig); int ed25519_sign_open(const unsigned char *m, size_t mlen, const ed25519_public_key pk, const ed25519_signature RS); void ed25519_sign(const unsigned char *m, size_t mlen, const ed25519_secret_key sk, const ed25519_public_key pk, ed25519_signature RS); void curve25519_scalarmult(curve25519_key mypublic, const curve25519_key secret, const curve25519_key basepoint); void curve25519_scalarmult_basepoint(curve25519_key mypublic, const curve25519_key secret); +#if __GNUC__ > 4 +#define CONST const +#else +#define CONST +#endif + +int ed25519_cosi_combine_publickeys(ed25519_public_key res, CONST ed25519_public_key *pks, size_t n); +void ed25519_cosi_combine_signatures(ed25519_signature res, const ed25519_public_key R, CONST ed25519_cosi_signature *sigs, size_t n); +void ed25519_cosi_sign(const unsigned char *m, size_t mlen, const ed25519_secret_key key, const ed25519_secret_key nonce, const ed25519_public_key R, const ed25519_public_key pk, ed25519_cosi_signature sig); + #if defined(__cplusplus) } #endif From a8aacac6bec8bcfd194dedfd13a47471bbae6491 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 2 Apr 2017 02:52:50 +0200 Subject: [PATCH 388/627] ecdsa: rand -> rnd --- ecdsa.c | 4 ++-- ecdsa.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ecdsa.c b/ecdsa.c index 81dc2a82f..344ba836d 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -685,7 +685,7 @@ void init_rfc6979(const uint8_t *priv_key, const uint8_t *hash, rfc6979_state *s } // generate next number from deterministic random number generator -void generate_rfc6979(uint8_t rand[32], rfc6979_state *state) +void generate_rfc6979(uint8_t rnd[32], rfc6979_state *state) { uint8_t buf[32 + 1]; @@ -694,7 +694,7 @@ void generate_rfc6979(uint8_t rand[32], rfc6979_state *state) buf[sizeof(state->v)] = 0x00; hmac_sha256(state->k, sizeof(state->k), buf, sizeof(state->v) + 1, state->k); hmac_sha256(state->k, sizeof(state->k), state->v, sizeof(state->v), state->v); - memcpy(rand, buf, 32); + memcpy(rnd, buf, 32); MEMSET_BZERO(buf, sizeof(buf)); } diff --git a/ecdsa.h b/ecdsa.h index 596ec1ec6..570bfd22e 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -92,7 +92,7 @@ int ecdsa_sig_to_der(const uint8_t *sig, uint8_t *der); // Private void init_rfc6979(const uint8_t *priv_key, const uint8_t *hash, rfc6979_state *rng); -void generate_rfc6979(uint8_t rand[32], rfc6979_state *rng); +void generate_rfc6979(uint8_t rnd[32], rfc6979_state *rng); void generate_k_rfc6979(bignum256 *k, rfc6979_state *rng); void generate_k_random(bignum256 *k, const bignum256 *prime); From 3d04064384b3f4e8331bdcfc96d2c7e5fc04a269 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 2 Apr 2017 02:54:46 +0200 Subject: [PATCH 389/627] don't skip const if not using gcc --- ed25519-donna/ed25519.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ed25519-donna/ed25519.h b/ed25519-donna/ed25519.h index dd76be42e..af5cbb277 100644 --- a/ed25519-donna/ed25519.h +++ b/ed25519-donna/ed25519.h @@ -21,7 +21,7 @@ void ed25519_sign(const unsigned char *m, size_t mlen, const ed25519_secret_key void curve25519_scalarmult(curve25519_key mypublic, const curve25519_key secret, const curve25519_key basepoint); void curve25519_scalarmult_basepoint(curve25519_key mypublic, const curve25519_key secret); -#if __GNUC__ > 4 +#if !defined(__GNUC__) || __GNUC__ > 4 #define CONST const #else #define CONST From a820a5601b84089639349cf2ccd13c0734075005 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 3 Apr 2017 20:58:53 +0200 Subject: [PATCH 390/627] split rfc6979 from ecdsa into separate module --- ecdsa.c | 3 ++- ecdsa.h | 11 -------- rfc6979.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ rfc6979.h | 40 +++++++++++++++++++++++++++++ tests.c | 1 + 5 files changed, 120 insertions(+), 12 deletions(-) create mode 100644 rfc6979.c create mode 100644 rfc6979.h diff --git a/ecdsa.c b/ecdsa.c index 344ba836d..016f52bda 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -37,6 +37,7 @@ #include "base58.h" #include "macros.h" #include "secp256k1.h" +#include "rfc6979.h" // Set cp2 = cp1 void point_copy(const curve_point *cp1, curve_point *cp2) @@ -193,7 +194,7 @@ typedef struct jacobian_curve_point { } jacobian_curve_point; // generate random K for signing/side-channel noise -void generate_k_random(bignum256 *k, const bignum256 *prime) { +static void generate_k_random(bignum256 *k, const bignum256 *prime) { do { int i; for (i = 0; i < 8; i++) { diff --git a/ecdsa.h b/ecdsa.h index 570bfd22e..32388191a 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -53,11 +53,6 @@ typedef struct { #define MAX_ADDR_SIZE (54) #define MAX_WIF_SIZE (58) -// rfc6979 pseudo random number generator state -typedef struct { - uint8_t v[32], k[32]; -} rfc6979_state; - void point_copy(const curve_point *cp1, curve_point *cp2); void point_add(const ecdsa_curve *curve, const curve_point *cp1, curve_point *cp2); void point_double(const ecdsa_curve *curve, curve_point *cp); @@ -90,10 +85,4 @@ int ecdsa_verify_digest(const ecdsa_curve *curve, const uint8_t *pub_key, const int ecdsa_verify_digest_recover(const ecdsa_curve *curve, uint8_t *pub_key, const uint8_t *sig, const uint8_t *digest, int recid); int ecdsa_sig_to_der(const uint8_t *sig, uint8_t *der); -// Private -void init_rfc6979(const uint8_t *priv_key, const uint8_t *hash, rfc6979_state *rng); -void generate_rfc6979(uint8_t rnd[32], rfc6979_state *rng); -void generate_k_rfc6979(bignum256 *k, rfc6979_state *rng); -void generate_k_random(bignum256 *k, const bignum256 *prime); - #endif diff --git a/rfc6979.c b/rfc6979.c new file mode 100644 index 000000000..c6e50a484 --- /dev/null +++ b/rfc6979.c @@ -0,0 +1,77 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * Copyright (c) 2015 Jochen Hoenicke + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include "rfc6979.h" +#include "hmac.h" + +void init_rfc6979(const uint8_t *priv_key, const uint8_t *hash, rfc6979_state *state) { + uint8_t bx[2*32]; + uint8_t buf[32 + 1 + 2*32]; + + memcpy(bx, priv_key, 32); + memcpy(bx+32, hash, 32); + + memset(state->v, 1, sizeof(state->v)); + memset(state->k, 0, sizeof(state->k)); + + memcpy(buf, state->v, sizeof(state->v)); + buf[sizeof(state->v)] = 0x00; + memcpy(buf + sizeof(state->v) + 1, bx, 64); + hmac_sha256(state->k, sizeof(state->k), buf, sizeof(buf), state->k); + hmac_sha256(state->k, sizeof(state->k), state->v, sizeof(state->v), state->v); + + memcpy(buf, state->v, sizeof(state->v)); + buf[sizeof(state->v)] = 0x01; + memcpy(buf + sizeof(state->v) + 1, bx, 64); + hmac_sha256(state->k, sizeof(state->k), buf, sizeof(buf), state->k); + hmac_sha256(state->k, sizeof(state->k), state->v, sizeof(state->v), state->v); + + MEMSET_BZERO(bx, sizeof(bx)); + MEMSET_BZERO(buf, sizeof(buf)); +} + +// generate next number from deterministic random number generator +void generate_rfc6979(uint8_t rnd[32], rfc6979_state *state) +{ + uint8_t buf[32 + 1]; + + hmac_sha256(state->k, sizeof(state->k), state->v, sizeof(state->v), state->v); + memcpy(buf, state->v, sizeof(state->v)); + buf[sizeof(state->v)] = 0x00; + hmac_sha256(state->k, sizeof(state->k), buf, sizeof(state->v) + 1, state->k); + hmac_sha256(state->k, sizeof(state->k), state->v, sizeof(state->v), state->v); + memcpy(rnd, buf, 32); + MEMSET_BZERO(buf, sizeof(buf)); +} + +// generate K in a deterministic way, according to RFC6979 +// http://tools.ietf.org/html/rfc6979 +void generate_k_rfc6979(bignum256 *k, rfc6979_state *state) +{ + uint8_t buf[32]; + generate_rfc6979(buf, state); + bn_read_be(buf, k); + MEMSET_BZERO(buf, sizeof(buf)); +} diff --git a/rfc6979.h b/rfc6979.h new file mode 100644 index 000000000..e541d6ade --- /dev/null +++ b/rfc6979.h @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * Copyright (c) 2015-2017 Jochen Hoenicke + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __RFC6979_H__ +#define __RFC6979_H__ + +#include +#include "bignum.h" + +// rfc6979 pseudo random number generator state +typedef struct { + uint8_t v[32], k[32]; +} rfc6979_state; + +void init_rfc6979(const uint8_t *priv_key, const uint8_t *hash, rfc6979_state *rng); +void generate_rfc6979(uint8_t rnd[32], rfc6979_state *rng); +void generate_k_rfc6979(bignum256 *k, rfc6979_state *rng); + +#endif diff --git a/tests.c b/tests.c index 88be17f88..d2870362d 100644 --- a/tests.c +++ b/tests.c @@ -49,6 +49,7 @@ #include "nist256p1.h" #include "ed25519.h" #include "script.h" +#include "rfc6979.h" #define FROMHEX_MAXLEN 256 From e15a7bc986667902bf31f2f2cc623e540168f7f0 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 3 Apr 2017 21:19:19 +0200 Subject: [PATCH 391/627] add extra test for rfc6979 from the paper --- tests.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests.c b/tests.c index d2870362d..f11aed206 100644 --- a/tests.c +++ b/tests.c @@ -1286,7 +1286,7 @@ START_TEST(test_ecdsa_signature) } END_TEST -#define test_deterministic(KEY, MSG, K) do { \ +#define test_deterministic(KEY, MSG, K) do { \ sha256_Raw((uint8_t *)MSG, strlen(MSG), buf); \ init_rfc6979(fromhex(KEY), buf, &rng); \ generate_k_rfc6979(&k, &rng); \ @@ -1300,6 +1300,7 @@ START_TEST(test_rfc6979) uint8_t buf[32]; rfc6979_state rng; + test_deterministic("c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721", "sample", "a6e3c57dd01abe90086538398355dd4c3b17aa873382b0f24d6129493d8aad60"); test_deterministic("cca9fbcc1b41e5a95d369eaa6ddcff73b61a4efaa279cfc6567e8daa39cbaf50", "sample", "2df40ca70e639d89528a6b670d9d48d9165fdc0febc0974056bdce192b8e16a3"); test_deterministic("0000000000000000000000000000000000000000000000000000000000000001", "Satoshi Nakamoto", "8f8a276c19f4149656b280621e358cce24f5f52542772691ee69063b74f15d15"); test_deterministic("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", "Satoshi Nakamoto", "33a19b60e25fb6f4435af53a3d42d493644827367e6453928554f43e49aa6f90"); From 81c61ba5a41a9156a8951686d5ff64d0000ec943 Mon Sep 17 00:00:00 2001 From: Karel Bilek Date: Fri, 31 Mar 2017 01:35:00 +0200 Subject: [PATCH 392/627] Adding emscripten tests --- .travis.yml | 7 +- emscripten/.gitignore | 1 + emscripten/Makefile | 20 +- emscripten/{test.html => benchmark.html} | 2 +- emscripten/{test.js => benchmark.js} | 0 emscripten/test-addresses.txt | 1000 ++++++++++++++++++++++ emscripten/test-correctness.js | 30 + 7 files changed, 1051 insertions(+), 9 deletions(-) rename emscripten/{test.html => benchmark.html} (57%) rename emscripten/{test.js => benchmark.js} (100%) create mode 100644 emscripten/test-addresses.txt create mode 100644 emscripten/test-correctness.js diff --git a/.travis.yml b/.travis.yml index f819bc954..1b66fc956 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,10 @@ -sudo: false +sudo: required dist: trusty language: c +services: + - docker + addons: apt: sources: @@ -13,6 +16,7 @@ addons: - cmake-data - libssl-dev - python-pip + - nodejs install: - pip install --user pytest ecdsa curve25519-donna @@ -26,3 +30,4 @@ script: - mkdir _build && cd _build - cmake .. - make + - cd .. && cd emscripten && rm trezor-crypto.js && make docker-build && make test-correctness diff --git a/emscripten/.gitignore b/emscripten/.gitignore index 9bb5de5d2..9947cd122 100644 --- a/emscripten/.gitignore +++ b/emscripten/.gitignore @@ -1,2 +1,3 @@ node_modules/ +benchmark-browserify.js test-browserify.js diff --git a/emscripten/Makefile b/emscripten/Makefile index 44666c57a..6bcc01ee2 100644 --- a/emscripten/Makefile +++ b/emscripten/Makefile @@ -8,24 +8,30 @@ EMFLAGS = \ SRC = ../bignum.c ../ecdsa.c ../secp256k1.c ../hmac.c ../bip32.c \ ../base58.c ../ripemd160.c ../sha2.c ../rand.c ../address.c -all: trezor-crypto.js test-browserify.js +all: trezor-crypto.js benchmark-browserify.js trezor-crypto.js: $(SRC) emcc $(EMFLAGS) -o $@ $^ -test-browserify.js: node_modules trezor-crypto.js test.js - $(shell npm bin)/browserify test.js -o $@ --noparse=`pwd`/trezor-crypto.js - @echo "open test.html in your favourite browser" +benchmark-browserify.js: node_modules trezor-crypto.js benchmark.js + $(shell npm bin)/browserify benchmark.js -o $@ --noparse=`pwd`/trezor-crypto.js + @echo "open benchmark.html in your favourite browser" -test-node: node_modules trezor-crypto.js test.js - node test.js +benchmark-node: node_modules trezor-crypto.js benchmark.js + node benchmark.js node_modules: npm install npm install browserify clean: - rm -f trezor-crypto.js test-browserify.js + rm -f trezor-crypto.js benchmark-browserify.js docker: docker run --rm -i -v $(shell pwd)/..:/src -t apiaryio/emcc /bin/bash + +docker-build: + docker run --rm -v $(shell pwd)/..:/src apiaryio/emcc /bin/bash -c 'cd emscripten && make' + +test-correctness: node_modules + node test-correctness.js diff --git a/emscripten/test.html b/emscripten/benchmark.html similarity index 57% rename from emscripten/test.html rename to emscripten/benchmark.html index 9c764a230..be2acc00e 100644 --- a/emscripten/test.html +++ b/emscripten/benchmark.html @@ -3,6 +3,6 @@ - + diff --git a/emscripten/test.js b/emscripten/benchmark.js similarity index 100% rename from emscripten/test.js rename to emscripten/benchmark.js diff --git a/emscripten/test-addresses.txt b/emscripten/test-addresses.txt new file mode 100644 index 000000000..1eedfe677 --- /dev/null +++ b/emscripten/test-addresses.txt @@ -0,0 +1,1000 @@ +1JAd7XCBzGudGpJQSDSfpmJhiygtLQWaGL +1GWFxtwWmNVqotUPXLcKVL2mUKpshuJYo +1Eni8JFS4yA2wJkicc3yx3QzCNzopLybCM +124dT55Jqpj9AKTyJnTX6G8RkUs7ReTzun +15T9DSqc6wjkPxcr2MNVSzF9JAePdvS3n1 +1GA9u9TfCG7SWmKCveBumdA1TZpfom6ZdJ +1PogPE3bXc84abzEuM2rJEZf2vCbCEZzXz +176U2WABbj4h5PCrxE963wmxzXd2Mw6bP4 +1HRZDR7CmLnq59w6mtzNa7SHtVWPSxdgKA +1MPdvYLzcekvEzAB7DmiHa1oU8Foh4KUw8 +1JL3nCw76rhwK6EguU6uhe7GCa7Mq88kXg +1DXKPgQU6ACQiww48chz7iPJhoV5L5bjRC +1Fwv7wsw5qa6tN44Soad8fC9CBwpVPgqCM +16BuufZRpRJYbiExJDgwW9orTBb2SbyqkL +18QJ4b6gpAhuGu21BDAmhTd6Pjvfa5bPD6 +16aucVQ7w1hfyXY4LLbP47a4ooeCy9ukeW +13kAzknifqXPEZu8zDgxiYdEUtfA1JXmAx +1AeFfrrseG6BRZ9v2xL5hyQCvzs4pdEG9B +12i8L9kzLejeJA1ncvkagQ3hbzdpr9pAQN +1JnEtPqqx1B7GpHVHGRtziZ4pEwzHms7qZ +1KGGARUSGAgo1EThKwC6adccWXVg5NHYiv +1t99qaUE2BwFmWD5NM3Vfmm2WSkrtoyeZ +182gbbXmn8A69BBxdsMeMXfsKKk1hnRKar +17t48iTUrYMWRATbASddjA1zQxAiWhLq3t +12YeNKUAsx2fygpL9Z9LM2e5aDo4AWnRmH +1D8APpheG1ZHaQShcxCWh5kacPGh22rK3x +19jH6toVaYxsYWNTETrAdBv9JZqnegPmNw +13ERsUEhyagQhyht45zYkxmW6z1PSBwkbN +1BDB7VTH31N9cyN2uReuB6ayp66x7o5heE +1JwNJJKam5Y8pmmqfYGUJGJaUrvoEJCYTr +1FDjtziBqui5yJAwwfUEuu5ZqNm8heJ2fm +1LvcPy9SQ76jz2QWEcnMA478UC2UjAj3cc +12ppxDpGQDjW68Mcw62FpDWJH8CTiCw9JQ +1L7k8mh72oeRitY9PAfb1kJHHeoaKkDqvj +1Em928XFeNgGHu9bkevvtLicJzTkWtpS67 +142epfDnLURiJhbzrasx41TEcbzdNbbscC +1629DnNSKLxBn5CMaEraTuRucpXPJknzpM +17J4t26g2ManWQFhRWgBGt2DV5cACW3KUp +1DNppZ4ocTDkmdoUo4DBZr1iBAxdyygo1H +1DaJFoJJ8388vYWKmtkeJrEHYL8rzq3zcX +19c7WFB79FcZ2nmG4zMPkkJ27iUw8BsU1P +1Lwf2wMRt9Nx6xWwSKnsdK9ajCKHU646HQ +1MCng5rjimjAL5TZgM9qFLhzST7Zog5qn9 +1BCzxbp2krVfrGjrB4fziUNpDTqyMwMgcf +123b86CERqz6xdyw52jDgLBTuNC94odtah +12EMUkatbvPBw37bYamrTZa3nfp2m3hks3 +197zzWaARhRg2vwxsVpcHA6LTLjiKdtJxU +15PZA4wvEcw8Tfvaxg7ULf3jeud72kwtdy +1DGqgeNkcopfNeC3Vhur4UPicDoWWu3nNW +1CkRASjrSdN1M8rHaLUXPUkM9j1VNtZURT +1MJmJo4cNrQqjtWfC79jGzLpNSukzeFA4K +1C4ZNh68ethCKQy74B58FCShiuDrqLpfHB +1ExY9wSMj67qEF4wCLwgwgqxTbNyeWMzZs +1GyQ8WgfYZ3VjgNXUQNhcjtPjSXwhmG8b2 +128pzPoxQAWKtVPm4ymAqt7vADVbxckWHS +14nw9rFTWGUncHZjSqpPSJQaptWW7iRRB8 +15FmDszjbUEcAB6i3abWkrApa7bRXXWnir +1svSxTo76gw1W6X7SbDNtEWAr3YR6vAjw +1HDEwxpJwE9vuKBz8oi4vYzayRi6CHFs7T +19HctfTN93QVUmMKwzhACwNWdAsLX7NPv2 +1QHkRxwudvtknK4fs2KQRnHYzLzVSti6oi +1GzpH1Gn969noj7ph1oav7YdbKLLdJsYAX +13XYPXRdd7nevx15PHLKD1Cg4HRjAWnvMc +15zwUVQQrmWS4VXy88wmk4jgqbyApTkNWQ +18852P4BcrXL9kTyr24DQyGKzsXNZgBxjB +1ECZAWouiDHDSKX9HcCTHyqJJJ2kfLzRgt +1EDHvjhsgkxECEVGwzD3A5kZMdXsWcEicR +1PkR3KKzg8xXeTVdqxjHERQEukugN2Y5Ah +1NKi3aKBmSThXmTAtpSwQuwGoJvMGsXE5i +1KxXpLUSxoEcMrXgDqVwtrmZTepStwD6dr +17podqn8DHbUaYTiCk7nUxjCfkPxT7zu8m +1HE9zd4tkHgpdNVuBQBx8JgKiwrc5ZTrVy +1FVcvYGmWj7kQaVYfqQi3nBeNsRGJRdYNg +1CLsrKSrB1MuVgtMMfXKW2gPfTS4JruUfi +1JwrgCwzAJGxDug3KpZUjYY6QHUYqhDgyX +1GvLHzNjyWFotyiVeDq2vxDYCefmSAuvg1 +1NFGiwpsMau4pMV9ZkN83ouVKVH1NDV9se +16vzqohcc3J9x8vcKZi5oGLr7GTzQT4j7k +1MxKoRGvRweETXeNFXR4r5bygJ5e8MCDxS +1GtambqQjBg6xwzWQo6pjPsBkt4bfw8Fgw +1DSqp45me3MDCjstcHHPXYXVNymnY1edW5 +15osmj5VdVcCp7NTgGLr2r86Akz4N4gycg +16yBPz5o2pFNCyTf1sZuFMBKLNAbs54jqU +16Gq1Zv9utMWaDeLD5naPSftqg6M6KXdZV +17XCuuQowAS7gSKXrChxN3UPDSefG2Rx5Y +12U2zAA6j6e28VPGmkjTTExzVudn8PZpsL +14kLA5PaT2jrAgYHSRWmS8AYh2CdCzfknB +14dXQGMby9q3TBAYFurAThvHBK29vr2ymg +1Q98pM4MRc2mM3FSAAvFb937T2jJJDSjqP +1CYpXNYUrEENG8xAegd2ewdzQafqKNpSxt +1MWgXUw3cEbdBbVVYxSGJTrrQUEDmNpy1T +19YdoJbRaFHXW7bbyGX62bE8QG2a9LKGfu +18ee1MfCNAy1SmnpuWV2MFhaSRuh1PYg9i +1FHo7TG4XUw1QnpB6cHkYYp9tGyYzuQ4nc +1JCrRW8JSHnGn5mRVivb7t6np9QGnT8fzF +1JpXDB4qT8vcy5YnTGa2ujoZXQEhf3RNfd +1NgAZySoicM1FBLKy2bTyUAXbdemkjZkvp +1KZM4FRnLoTGEdVBsrBeh6AwKXVkdMVZHx +15mQ7JpfgkHQhS1HMyakTvSp6wZobZdrbA +1CNNL5m291HKymC8QdPUYsoesGtYGBHPRi +15FNuRGSzyRdmzaPrWfB4NAVn1iesq8xgg +1KHDeB2e8vFw7q6xAtnWedoVfGpVZwGaee +1FNoTGfHrSXsvByAwdLKYZ7iv8h56jKd9c +19XgwbbLXsEfKAAUJfxZ2QLidfsvzMXTtA +1PCQh7vqFNSfiTWiMn9z2m5KUc9sNCuGmf +1MDQ93z3q74gHEWZEt37dz5g7ygsos7bMa +18x6Dgrve9qL8XWDcYWQwEEq39FxHDBCBx +185VkAbKaNJHzdqksh6YFZSJa3we6BmsSa +1J1K3HEDWgJwjvu5PqMeJDgKUzsy75BFyy +1FkYsK5shgqDTN59qvLEDhZakhCZjDzkPW +1Jw7W6qFvmfPCp96ryWQRov1wfB9dAYkjh +1B1LxiJyawNr5GhHS1t4X87EN1gFQEvgrv +1Dwfc4BXDxDzVKkcJsMozEQ3SXnFFWoQNo +16TRWVbM6fiDdB2QSkjTASJ39LHJxyD2ed +17dAeedrU5tUUKM18cWrcamkQ6QjC1FeS2 +1MeJ4nGCTqQmkNpi1SzayJsotWPQLqeMTJ +17Uwzeue5iowEf5ETrMWJuCKVA8LnpwuZV +16nqjHukctc2KU4JN5tggCW3V5eGicqxAs +151JSRC9KCtgu7DWwKRaY6KGJMzsgg6Usu +1HRGAdFqa9YtB7uRKjq1dEcMDwpSHxjh68 +1Kvr7DfpiT8cKD6BEQr7HRTGqobnSjpQ2L +1DQaYQaYGZykvTbq8KL8qynf78nDb1Ygbw +1QJd1HH4fh8XwrvDKCLbdV2U5JGRiJBE2w +1JpRWAgAGjx3iH6F2RXNpNfietpaAgkTXT +18o1SWjFmtUYfbAPaek9DK1eFSPfBzDTmU +13AYKKg5Se1pjd9xckKWeuF7sDUr5BRtEv +12KJKJG3ZPmHr1mrJb3wy7dh3TCR9E4Nuq +19KpDnF5abLmVT5uSS7g3Xoozh3GD4mCaC +1D6ikYhzpGVRNqiV8vB1PyY1DNtZLdbJ4T +1Enj8YzCghHTQbJCAwnALcVJ8BNjqBPjvZ +1A21fw2Pjb8yK9D6NDqArVWzMP45SBg3e9 +1BRKGYPZQKMLwdS4HFi3177KPkqULUeyg5 +17iYezXCKaPLKCmsQEKDzfGkjX7Si24dFy +133ENJEmCrzr1ipM5xyWdkdFhXYF3USi8e +1PFYCH2XMPWtLeFVEKdkyeie8bJwNduC5e +15yecmvNS4PXtKk8s7aJ9QJZWoeZdHiVNK +17ebiTYPEq6wtAJnYf4UVKexqkUiuAR6au +1HgmBLSCpL7rDSvBj1cwoM3nPRV9fPUumc +1Me64du1HYr5qva6ao5XDQ4CQyt1TCeiUb +1M5jcoAGzZM8dKcgEGgMyxbWDePhEcCY75 +1H5xzBjdM342AHEyGXFZ1VfnyjqNks5vqi +1LhESpq12LThMDA7n6e9d1XPrG7arAJc3x +1MFhkR4cphKja9k6PQ5mUWeGFxopdPhmg4 +14cJiWw64jqEv1Usim8RR5apxJoRRqKgpw +1Le5h3weGsMHnnBATecmpDdbGVKC7MMjnJ +18Fk4GsjFhQSXdpNZCbqSFwGu9W69p2hWj +14qQSeaYcVAFBprTnNZheSN3Af7iPygkD6 +1DJBpSoX6pz7tiEWoZAXHxWDAtQKek3KYD +18W8Mu9E623T9Y4sYuiGAUKRbCzjNc8F3d +172fcW9FcrJWPgKcwWeGydRGt7d8H9up7e +1Po3tjftRxwCWQ5gszdCDteXLZC4DwmdZr +1FXcbrqSPfbD9114NNNcA9nxKWd3RL7QZ9 +1PadkVqEAFyaB1yu4hQZjWCsDRkZQK1x9U +1CZs9cQbHMz89b4XFfsACtMjMbFNA3c19S +143pyba6dVGqqnocefycWKza1Jd3fFuXuX +1LoqPvf2o49V2Z3NxNzyURqKPvRaSLDzti +1EfTCSdjamhz7zPgtsGyvFC471wNKwd65p +1NFbF2UwqqmZdchv63JQaEcZFfTQ6ihtk +16C31YsZddzRumn3mdomebxBHX1meyY21J +1F9qWj4VVVTxqHSTmgNWXhzqyHiHjQrHkL +1P6XqDnLiAbAyJuYoZ4uYgNgsoqgjveaPz +13CU9THbfTVbcnQiTHdJSz5nTAQgtdiBqA +1GWBf7n5UBvdbf25xxSJPnsCTve5VqHGt5 +15scurPVnxksv8iv5FifSBpaV1unW14MFw +12Dsp1x5WTykQRHzma1zjkk36Q4gd6y8cz +12NH8ZY1fK8KFUdjwJUDktaSJNaNxChGmU +1EM9yr5Cugub7ZchD1VB1EEctUanP4CtDJ +17AG39yw13U7JeBxKrrFPnZe4RjBFbzkxv +1GeTZXbUqNThapHNFVR3Sp2LtSGsJRrAgf +1pqdwRHGinZ1fStFkrncWW7uuUjcFbG1E +13Fkc8uv8jtDH4gbGfqHxLPk1TsQtbheXT +1PtsmYHkMH8pnQNQBhSDHMSHXEr91GS1J6 +14eJ2Ak1dkKDXMrZmLTbKBT4iB19MD3724 +1Gm6yZChBQ9rtfnfSM7tMGmdENLHffuwQi +1EuLrMA2L8Lqpbc68hCv5g5vf4uviPwRpD +1DLw76eY8mXCcuHp2HtvUJMkLuhK73XZ13 +1LjBaMwSaiiEB4CbYC2mX2XLo2cdhAw23y +147TXhQvYy6D3vmFRbvzhoRkxTyS9m2oTG +1szJzr7Xj68tHn3eXvEWna8JG88cYMnbw +1QK97d1PUCMGhoYCxdxQDf84mGLm5eV36F +1DknC87FoKB1FcC4NwHFvR1wWp6sHbMeEg +143Ez5s8TvuRuLBEhco8QiLKKPHL2Y7TiS +1Lwe52M9thScXbABWUS6fwnkxfpxW5VEwK +1Csv6v2Ci6pJQNSsxSvGPXmi6iVE6qt3Cq +162ciBsHHKtxCHmF5DTatdkgkoGStR8ciS +1eYcCWe5345KRBj3XDVpdAbxwsehbXxzx +1AvZLrGmLxNPF73brmw8HBK9fHMGMat6cm +1MZXbmTNfujQqh13e6yy7xNGeyrN5t2moP +17EA4eRLCg7gAUTc8sQxM8GibEeUVHh7aW +1GRidtL5bXrkTujj1cJDqGTKC1WASx3DG2 +1Krvw7QMugnTdz7sT3S3J7TEKJDCKw8Qu8 +1QFy5YTpY2yA8tafPeLYgikVHgcDK7WGiP +12YsnFrCKr6k1AjoWw99E4JETheA8xXU9w +1PcphLWi9SM4nBpP8xYraTKGFekyKpXBNE +16TDsoS3vCR8Jw55qk1nafCyVtzgWiHWhP +14ToKnMWoyqYQPSMyxvNZxnwtzn5hue1r2 +1PL7uWP5Hca5Y1sVPo7JQvWEV47S9LfrzJ +1NKmgGLHTMthWHvZnzLX9NiACsmqZ9BYgU +17uUAEyVNJMXdijy5cUV4TMXiSui8PAd4c +15RHeA889tj1Ciy6e9SPWne4cSmyBfTrTu +17VxWEoQmueMqkT5Ppe84ybTvD76QUdnKt +1AWEphUDwLMX4ZSyRucRhpGHwkAAmCW8Sh +13vPJyag3Rz9uiDmCHDAkgb8QnvhSqSF16 +123khoFbmNuPQ38VhLH4BE9eRnKj55pjxo +19GQbL8R9ViGbrbBNdUja32Mz7o5Dq3cwg +1MhYUBVkjAWqX9VgRYPz4eB6tCQ9AnSRRt +1Nvuku2aPT4ULUghxc255gjScVwXKgag4r +14AyPSjduDdB57z8fsmGH72SfdYQ2cRLQY +1NGWJPiadqZx24XREtnbMRTb3wkT5BEj97 +12pfMNqmVXvTmiXsgH1ocDdZw5wCQFtk1z +13FxB6FL2ntg8Boq5HNo5vyDdhyyvRXS9s +14MqRDz4Ayoi5KnVjUiLTBKBa7FaF22pVU +1CuFwfY7bzhz9PjY2W3G5TB5R7DtueFLPW +1CCQHAnCvUPi4Ku4A9FGfXYP3KJVdXMgo9 +1KWQGJwsPGLUApnX42YbPgKph6YoTYgQCa +1WM9zuf26p24igG5tioeVK8Kja1o5ZFX7 +1F8EumfRo1QTe92SNyN2Q7bKcjExUg8BQM +1J1tMDS6bzx3bYEZNb3B2ecL5cGYJhmd24 +1C36qVENEb9ZVcitgMPwg6uTHUrMRKRdn4 +1NY2TfycdMsEgJjo98CXZVpsU9cJsqw8QN +17VNU8SuNSxQVQr8V7Nah6wQvNcKNLQ8kg +1NRd3CiwZh8sbvi1LuXuizekJroAuZ9q1j +1BhbzGi5psoGb1sdzP7WXC8U1SpEK9zowQ +1JNJ8YcCZYDCbmqFZRVmHufVxhKJfLfgi3 +13x85eWzXMKhxMVTb3AxuPQYva3LTUEfDu +13WmPh98GHGPkJ59Uzzhj1sadFEkAtqSnq +1GbNNSciicEfRH92SkU3BU8CvqDRs9fwBU +1Gu3HkKhwr7NhxtD1B2d8k5kfng4dhQdQP +1768HUKpnU7xuSWjbmv4ewhYPDCyJ9F2jZ +1Mk3JZfbfv3hdWhiXSH6WPmx73k6jmWyvN +18SKCrUJaTBE47EzPycyqpBpPW7CGgoWE2 +14WyZtQudnuJ71S9qvBFubY9uaB5pD7Ro8 +19Y1Ne9sWwwRcie4VtX6pjrdsA5z8Lpdxp +15i4uQJt4g1PnamZadRGXT7UoZB9Y6jj5J +1FZri6Q8amwt2C6C3jNHFEgmUXj29Z4Wo4 +1EoSy286Jp6S771R4K6HbZAB34z49wBqBS +15E65uLQs2yBDhjLKqxDBQFdCJZuHRNEiT +1LVPHMqJQKwNj2hMat2F9BUSADsfNqhcgN +12mvuWpRM2mnptD2N9Nnvkyh4MMm31SAQp +16DQEUtqgxFJ2284edUHnHTMQFqf7LDzhW +14pzog455vVZCUZWKNvB7JqMkAimi2c4Ne +172LSqVDdmStc5vrUQcsprQ8qCFcRZQtMK +19z9nwJvYtyrhEMhK8EmJ2iCzzv7yHUd8i +1NpDgPWooxGngu67zFCBX8DuF6pmxSfVFL +1EezQbR25rDMmUjLeHn6GSALJLY4rvQw8A +1E24awmY9C21UGrfG1xpnFsXKHMtMbHvjB +1Bak9A2zkAefgcUZn3gH2rCEA1A7Fu5bMQ +1KaEBFt6TTuSnfXWJwkK8aVVgs13HVnHoJ +1BqQ12PxtxWXDAiX16G6roe87FAdepPT1b +1HaXfPfCX51Gpe9apxDmh9tAyZnGANrWsX +1JyHmDVLuKxbLF8ppuxG7waYcpSVbeqKZ7 +1LsGSZunm5MSWxa5GJhmQd3NhdaFe29zve +14omipNZTVxhJNEm6z5SSrPLmTjHF8Ht4L +18jz2t8515EKar1TFjLZc71Sn4wfvwV6N4 +1Fum9NC14WPo6H67h8BCuT4uUjPUp7wXUE +17Bt5d4dCCUUwqV2V3jWjKK8p7YzzTb81x +1KMA5RsNypFvCvWWDf9R8ZdYBkj12QQypC +14gn1J64bRjUr1CZTQdB4H3d9pMFSBBpBJ +14raFodBoiYZ4NYy1Wgojenux8cHm89qc3 +16BwA6DUvmX95ijNGRzTdzCJBNTtYYbhPL +1MyV5zGX3aQGKetNpcTMDYQEsHycE3wtMt +1FcTbtKkpnMNLhmG8f8aj4ZXJV8sQcEJXD +1Hgb7B3r5gtZomuGDZu9k67GsnTWbyfHZ +1F41MihRcNpFgzMAjw5Skbby7x3hBxVLiZ +13WEj1sqk1DvL9veqUY7Vtm7mvpz6mAzai +1LhvajVGEtqiUhSMzuWRMbFEbWVkrLJfuW +1HeC5VdNutkex5aJ2ue7gYvJFJPivp8Ac1 +113bpVpHGuxLZSFQttrpeWLz2uEWkQSbgE +1QBHgLtYbEqgrEXRNyBt76jZmX6KygcZVL +12rtcU6RKg8G1RoS4SfBLpsdigPHQY8UDi +1EZEDCqmW4hWPjFdV6HamFmCAhikBHw5By +13YvjWnmzdWJ5bUWoM7y96NmbV1nd7GbG3 +1F455s8HobaaL96YboaJDZbLT3ZowcwPpC +1Jf6L7GxJRjHCZL2T9swq6o6tivCLp9oxd +14N5VJJoGFvoLjLyLwCuuLDiyY6vD5j3GK +1NZN8E2fxWLpKPMNm5ecWwPkHmvr9nSpaL +1EiYBo2qExLERy21Ur5BypWn7EJZ5DiXbX +1AiyrxizJvgaupAE8Q1FpL9yfKZUCXmEbp +1EC9SktW9Y4kS4iW48idshNg9eNeBdY5Xi +1DR7fFFhHe4CutgPyXvo4EX9PvaJXAncoA +1J4nHTHgsV38VEZfb1gknamTpPAFMCqrnJ +17L467eezUxfvABRJnXWYxoUEU7BjbovfT +1Jw5FrKhi2aWbbF4h3QRWLog5AjsJYGswv +16gYznc3m1smWgiGAm2paGRNiLdqLh5HGx +1MBVsecwAsJ7giFTjaYx9aKswxgDpouoV1 +1HLBRpfuYJppgUY4kF1Pn7UN5agqK4X8T2 +1P2GApSG26JF3hpkzwUNsfVtJEDL5jw5Dh +1JPeEXdtwZKD3WhJV3Vc7ApFoK3RfZurXc +12q3TYGqboZfqC8DG85t4YJNZm1RVTCsoh +1wP8MbtqyvH29ZrAePKUACiLPMUmqf9pz +1Jc5q4FJNAsXyQux7n15LwwraZRUBhM1f3 +1SReqT2WfY1Wjv7urpa16FoubpYvEW71K +16a49zHXVSA4yuDxNFLhQnV4EzUXG3vx3r +1HLkBtvkCfi8a6VMxMy9DHjPm5ZU7GxEYA +14r6iGFRaMShhvWgFB5HQmbkY8TkFLrSAS +1FmeswGFnH8bCoqEAgpbBUnEaAfM8R4y8C +14oiyRSNMYipMoLfyVDKPPTzkoNYWzuAy3 +19pUMjoJEvBJYL4aUHTnbQoBMnhUPSrYxL +1Hs2dbDPrD2iEUnM9gaUiY819BHFActRPW +1J3Nj1FzViBE6SJYY6HEUfoyDrtCzPR9Fo +185vYvzQZVP6cEXoH3DKiBpJnSeQCW4acG +1QCJEDYWF8MVArSc12zVroeH8ENB6dD46 +1J1CeoLLVtAG4HfycqAPiMQJoAbz7WcT9h +1N5CpbQmNxowUUBJ8EBJZzGFE7wQjtU9r6 +1MHm3SYvqGq2gSjgFJPxWFaeL35rZ22uF6 +1BQmi9pSFvgtrMnbQ2CkSyDfwdqtmKB7Qe +1APsNapXbU1kMT2d9z9MujRTHEnSZnBDcQ +19RPixj4DKZHzcH4Fm9iTDMiJAAqnCKaiN +1BB6uMHPkeYzqBfHiVJgqHnLyNycykitHp +16wUAGjrTBbEKQQ8zpCFQbEoJpQ3xC1MGp +1FtfE8MhewzcEMPgi8y4jz56UenAt1Ryfn +1PspUiJiL4mt8WXcZBKzakGaur5WaoaHsq +17uSkpk1KaPyZLnSMzPV3T8nhAAuEHeohu +1MK5z4NA4z2yU3U8wZPyMzBTBut48hvyZR +1QCL7RT9iUidn9feZzqejc7Npifs6HxrSQ +1Ls4VxG13sQ6x4h75m1K751Lg4BtmWYQvF +18zB3r75LkedVqnwHfFii8mmM1xMNuZVG3 +1L3zwavUgzVD6KKYZM2zQHiKHA6L3wKjb9 +1HggzjQE3iMiM3bmFzKcoSdFoE4Sqh1bhL +167w8pyvfzDCb51UdCx8k2dPvsHPTQn64N +18QdCXXHNiXiLiHtM6o1UjMEtr6R4V4ay +14eUiYsXut98Wh4ZRGqZSG5S9zR7dDT515 +1L8LLHpuRmGUMEm5BeR55QrZfjfWPhKgmG +16NUWB9djkNMveERnJr2RkMDaQXV4XN8A9 +1PWHQdhnXTUVCzctoGcNajVp1x4LCqyaeM +18zGQeRT2pSQhamCW63iVt3H18HiqmcjFQ +1KJwR31A1wpHVbkDwtZ72taWiXK87Qg9P3 +1DgZzkrLAkBHJhp1Ecrhi1xLdypMGvYcJS +1AmVZJ1NxuCWB9sP5Jk1Y3rHFdKXMmoro9 +1EHbCbMVSjm3cz6FF8AxHb13uJ9hHowJ95 +17uKzSy47giFbfvLU9ZVLN4amJo8zuPPai +1GECLG1R8s5E5gK5Lh3f1rC8HaWF7vCyTJ +13fEfSJbiz8dAu3AHJ9Fi8eA1sa4j8v3tY +176qdApJYubiKzrV25buV4ekCEqES7V1MG +1KAKNrmTziboYs2RukVQBPxaa671Z2bqhL +1H6dijst3RVrkaphQfFoLa7HbBHbv6EFKm +1J4kJXvcKKLfTG86EFN97ZEyqhMJ7bxqDt +16Aw3gisPBLBDSYEeyv9n7NDGCGXZBVhmx +1ExVE3n9uapCDfL83R98LCRg8oE8bXDyrZ +1Q9jbsnYQfyeVqkDKUTfNMnX425Z4mVzWd +1Q33DnQwjFrw7qvPvELP4wSeCFA5ioD6Qt +19KmcWE8n9DT7BdC6rUXC7ujQQemVtxQrY +1DjogejLS1wprPVmuLu5bfgbmxdBsBmvz2 +1357na7rCWaaFTeDpcxcYcmogvvBvMyv6b +1FPEzEy8S65PJCFJm4zu1yLbhfKiczifx3 +18AaCF5k7ZDmeQeCEF9q528tV6FjCDBNiD +19e56sugyYfVfk9vBoq5W2UK862oxckqV3 +13phgTbhWAzihnBpzHpdpqTGA5vaYa1NZb +1CiQ5DV5gzpZ3kbwrQLXGwGcPzVdpLYU6d +1LgjPYCB6Gav4aoHc8KcHc9TuZGvbYRSuU +1CQxNksBaM2dhKA2jTC7m5wrozFX4GEJoG +16SrkHfSGxTEoSvEMeB2Nn5xEEMgidooA2 +1Bb2DGtsPJWKoz9wcWS7hj6jRavrwhYHZL +19KLGvvCWMVp7uBB4wc54sYrcFn1C9fd2Y +175EjDvAXZoaCWyoK2PqtejMkRqL3WuYmD +1KvU3HQDYbNdkhHierPg2ymfw5dnUW148j +1DJnfviC2VSNq7HMegGkrjZ6QFZ3arAjbg +19VMoPJu3zVz9hRqAMNRuobp9HUd5M7kz5 +17qGhq5VLPGvBtxnr2HrruUWuSXFHRZxB2 +1MjUJPmJ39KE3fUjLoAZAxHSxe8aAzaWLq +1PP3N5URVGvPNaLkNp3PtuWS7BZnJ1qm98 +14WSNr58LkbCefw57dgzexL5rsKyymJC9H +1NyanGJ3CQHhTDPttmZFhkRrx1sEL5yCY7 +17Qo2yRpM5wAs7rfWQMCfq4ACcZrqM7yWg +1JXujWJhxEWeh1p3TU8K37f8JSvTAuiJSf +1J5PT6UfimMExeWf43PCtKK9HXKdBjZJGp +16P4N3opsox3Xw7nR1m2ivq5GNXdetWGw1 +1FyFBAnK2DWuGLc8h65n2Mxc3mJHu417wS +1E5pE9FN3aAcX7iSThhr6qfwo1YDDZ1VL3 +1LHU2gw3HUr62f3DEuhiteJy4T3mcvnHc6 +12mWJRnRSjjbe8oJPja1eYLDP2bAhCeWDu +1NQPoc6oWLiR7xEYHmhYide7gxeEfzaenD +13icTzLY9bNFW719MaFZsCTYwJzDLXvxEX +1JZxsbLWCrpjB4XmjyMoCrwTSb49EDyNia +1JSxinLEudB16dwvLR5Y7D9FcDDDnZLAGy +1J2YsKvVLFjn3LuyyYFXSvQXvpF13KiA1L +14nNW6xRPA4sR36YkWmSZAQacrSHxXby2u +1CrZ9EW4tzfJbL5iCwWBEbHPgHuU3B5LyY +1CXy3bDMNFwC5uCatwAzKEJDny8wckufyv +1Ac4b3RwiFvZHyDf1tRvvW7DV8TPHfnZxA +1PWngUDo6obeQetiR35ge3wAgKLKCpUv19 +1L71VMQx9q1A2LvAmYy1WDNh3uNBeqbkJn +1DygLoLsnZiMX2dtocDL7WLyA5cuoNJvVr +18agJ2i62noucHgFPZ1LME2DhBsKi84hSM +18mt9cTUe5dtDXVna2oJA6Sd67KtEmzmP +16DP1gh4hwbe6bw2vWGiHcJ4FqewX6tvtp +1LyjRgCoesgLyiPPqS4Ug1kLasxWDLEzp4 +19MfUc2pQnBeMbck1UQvDVcnxtPhYgGKb5 +12Ldg4X3sHfJSsNyhJyZ1SCJbTPazWbEhX +17MG6FkzukW9YCJTt3xjAhfMR8W3T9YkUy +1cGUtp1i4mQKTBPH2FQNDG7VWdQdZa9sB +1ChkyuNr9kBgFytaUQUkbK9JqdFqa7ZLAe +14efmp2YXeHuAsM9cojrwXPudQEYeNLNqg +17BEDgKbkQ2rmnEpx9sNM9YgmN3ikX7DNj +1NAJgVasWRkqNiWd3ZTXnKxeg9T6XGp4VL +1Eo5itCHtH5uQ6G9y9HzPANPVZuDCyJe9r +1331NFh7WdsC6zGvUxRC3bAVhEmraKhnNb +15Yh3QugDuqW2wh8iKxmBpUiJe9Qq2MNtP +1KTWfL4Y381dcKgbHLbLpX43JmLrACkg2N +1AGmFTg4wZDTDKNY1bYZn23DfLFuk6jjZw +1LVbQM8YoUj1B22iWxnpbcpJ24ZmBmHe6W +12CJJnvnNBNXLnWSxHX1X7T48myrShUHeS +1PgDeXTfYrThPXFRjVpULyuTD8b6got3JL +1Cp1NijoMUDpVN8wKdScGAyooHNCh15Chi +1Mafdt4VesjWHrpQeAB5xK7WswjX4DAFdk +16wMFY1x4vAh1u2TxkArBBgUzw8JSC25N6 +1CpoEYtCRbcVXX53x5TrqgREM58cXsyWkh +179rcziZeN8e7GPq9aBGUQ8MqDqAPavBHM +1EDM3dbK6JhQTRVYgGgcSWopSzuhUeM7YV +1CEF4TBf7SxHbjwawCMY4CWs9rV7YWCbiW +1PH6ScAyuHhGL8gw8gpmiPxYv27cREt5Rn +1BGyw5bfaPxuCFdWCt2G7Qzm7sDgfyE11V +1M4bPEYTaoBgMKV5NAybaEKaKRmqDfGk6e +1D5PYsmytcoaLE9e3DuUEEJDuJkbq2HruE +13L7fAWbL5zKMoHo5TsrhAi3eDvMB89HM7 +1B9qAyr3t3TGK3Y9y7SNBV3nfV4F4Hc6f9 +1KiEgW3t63YJxKcAFKUyjXq4MoD3xibFx +19CYyDiRktmCNfqxLAM3BZ5ZkLs4yHQRTk +1KMF1AW36gtg5aHiqiU3gX76g8b4kRKY5x +124sJU69RiFyuMQgcyk1i4LNT5NGoh2DTx +19c6YezE6zAejRZihtyEo2k8VzPQdyVRjY +1CPAMekJDdGZ3cxTGXTGeaEx9sYzCafvo5 +1F5wcFT1BrEdVEsFZEG2sthtzBkA4SzgZh +157GAgu9PZBDrUtjZchFfhAkfHNtjRSHWw +1ApNnRgA4QEdkVt7cWRmyyoutXJttcxUTk +17p9wtTQ27ACRKZscoCJ1g5sPz3GSLHhwj +1Jyz43BPBvFhc2hjsDZ2FnRRB5ToewZUm9 +18VtcrbaCguG3Vf2atuhago3oJaS4P6Cyr +1At2wZsF2QTHPKExNQ7iqZXGktVAu2SrP3 +1LCsYznxNKU8Q92Z3i9sgoZ8sS7gVZhmay +1MUSVtcGCmgUoVGhtdBPy6N73hM3igiFWf +14oaWAKGpYt4y8rsLRFfKjyp28r4owe1Z3 +1NHqErQzhFKN325JQbpJmGEHBXx6XfkMXF +13KyQ8GBnv5MvrWQUnZGipdBoH3SYbdaeD +133CJc7tuAJZWf5YTp2jb2AE5gTbftiCU3 +1N6jFHqPVSaNf1sNi8UeksB3dTfQckmmzv +15MQP8gt59hF4QANXGg8BnR9LTrsutxyeX +14Z21k1iQZ98p8yqXVgeinFhe8kSxCFws1 +13MYaz3QgxZbkaeBdZD6j8DFxMfKm1WXif +14zdL3Y7C9DoAzzvGYXEMvLMmt9yGgBbJw +123Q7nM1RUA7A4Q1SYAi9UJif1xBmwKwpn +1FZaMJeHzNU8x7fdn4pvoGMcXT2cq2jk3w +1H5UyTYgaWqTFCDh2FNn8RbsLoJM2qUc8N +1CuP14feeBzqe3dXTMKfNvupcxCPqFXjyk +16TeMhDN9dWktAvhR4wMLE5wcSX1R3kjSh +1pxM7v4RbKJ1D2ULPFbyvPhcu8Eh6cc3k +142TjaqP5w4QAiy6noPf6FYXUQcZQF3dMd +1DJaSBmF7QtwqDE73kToPv3GgJ91zDiFKC +1BKbVw4RnY8spYGeqWznELdVx5W5JE9b2p +19yRef8pGNPPF1k5MaDe7sZYR7PvppHtr5 +1oY4nvsZHua8tU8z5itzy2ifEzHvUkW64 +19K8B4vRkkYNUedrR4tPfCCrsgCofg6Dbx +1LRUN7jGnLQjqNZwpmQEgeAsrZwF8kATjr +13fLhrDtUUpmvtWJCW3HqdgqQWgxxbjDx7 +18M6G7kWqvccbNv9pgha5cJWx7jTYHzCs3 +12jE1a8iLrJywUqKgjv5iXB4VHhMgcSrfR +1A9FTXrbnXVcmABs4FAXY3dSUJD8uMn3Vh +1g7rvTMSVJT1YvrMcG2K3X6phKDdF3Uj7 +1DPPW3uMSvGmfdsBKDsBWSRqN67KrH7Tqp +15DHowJw2QrNwAMYGYGwHTJnKEqtViTz2P +1NHRCUBFCJebw4dNtTxUSwQcTeqN91faY5 +18i9oQ5qsCMguvx7vit324jb1DYfv4LioG +1PFoLqViRoBnPX3mH4HmnyAt2WnEiNjUZy +1Nan2VcgCrAUWfYYSVGCcxW41jAW3FsqRu +1FJNu323WEJb34XAZZe3ZM438rAzgAjDPn +1DMKTFEXjWW7T9UXaocLTzsaUBrVhASA9a +1EPfdcTBxkmSJEGanp1UwjQYyTYkVXCgA1 +12oEfUSaVWnxnkJiXCrW6HURcta1BnypB4 +1Mf9xoyZKbviKphrqqEy3G2NbSqTguPpEF +1Mrwawi7FBAZTBHbv5yh8mBkQuBhKXeVHt +1FFrRqhYRBmsT8Ap5kZSU9A64L729ueb4a +1MqJbeZzQL5K1Smei2LasyJQD9vqJm19aw +13MaFBjJXQXnX1uEidoPVbyCRZCJeAFuse +15DFYzgK17dBqULd9eB3BESpfAsEW7Pn2y +1FzJj1sSqyLY2jb5NFNhUzj4LvBAncfLgR +1NiejRjyPgfZavoj1JF8ehcC98nc9j3SnM +1KBhjjx3QZHJo13qFQLvEHBca9bULXKwGd +1Bvm5TduWUBC9Qh3Jcmz6cbHDgyNrjtnQj +1MUDAcBKpuaikALCWA9iNMa1UkfVw8zvS6 +1NpD58HbyYdox8ZGQnmeDssikuXaB8y9uy +16Lbh8PUPLqxmxdoqHwvghzwMeM47dVYwj +16iRqJ7oGQHg1qGnwGUsFgY5YpACbPSyz4 +14hcCw853aT5sX9LSinWp6Pm6ZYKHjwFTd +1Pp3fNYBCeCeRVYENNFHcJKXRMiXL2r46i +1DFLy6ideYcY9c7oAuRWqon4zRRRF25wPm +1Nm9hSmeQt21JBRWdbBQxTrtWx36uhgJ2A +18w8HmmDmG8EjCHAnbqqSdH8qMujxasrJr +1LekUNmqGv9Wj9U2eaAoUexT6B8ZagxAgK +15ZWkQkggCkGTBn7txN9kw38sWnkqvr1Nh +1HxGBp6HKVDKVtcCxSQihL2HA56aoZeSeU +1D2i6PDgZbydZFdq3dqurNP3ARpNsmn63X +1KqNCyBNsUtSLsjxdr9ojv9zsTEYWpvRij +18DQDw8BEHSwspgat6QfS5AnVw8cYewrgX +1CfpbTgiiMaxf86ThNd5anHTU8WJYqQ2Ka +1ESQj15zJCwP5X9WEiTAMoEsT94DpeoEdE +1M5vZ8tEAKGGetuGGwtsmJ42xCa52uA5Gt +1LgZZq3xyVGeQueir8uhV1QDEvknBpMHWM +1HGym6kcCtSK9RrxsNdm9wK164UJ6epkwW +1BCxK2xfzdNGHL9bGNkYCiBXhuCtZootza +1FnaDddenyU7VHFfDCHYkahYZTWo5EN7tw +19Dbd9tNGufL6wZQZmXEiEDPjpHtarbPLJ +1EDKYRrSqMXymHQVE57A5GG844Sjc5Ppyu +1BsnhKSe5vrgF4Bp2fKf9ENU7S1P8m3PYA +18VijMP8xt5ZgFHPoZ5DV92phpUY6r8ay4 +14S8NNBX43kxa7svpXDonkEhJCiCXLbtze +1JXQE3R8waXpzjSNwcExKtCwYjDABC8XBR +19Ub8TUHno87dRdAFevruhemWwdgasPFgN +1KThqVosXuN36fo9t6rKVngLuw3bdRycEo +17hYxEs5uSMpE2NYAsZCbsfWDzqwCuM9jb +1Nmogks8wun71ZicJ4CsjB4Ln8V4UGBiZ9 +1EedR6M7wTBzip7wJMiNZYQddS3SYkRvSj +1L4hAGgD9AeCKAkPAQqdqXLemh5sb9nqRA +1XHjpfaJwXjKKEPRh4v5dJrz9xApAbB7y +1DvcaPZeusfoBJnvVrnQxyyThCGueCSVWB +1Gi1X9GTRdQngz8GawfKv33qvSswJqg6Rk +1B3BScPDZh5KoBSZASJTjLvHcHaK43cuKm +1L4MAP5mkT3YJZLjGUp41iMkbeRcKGnJD8 +1LFCHFsPYq8zBdiJdEuxjQTw6te8AnDpA5 +12VdpsxBxR18asGy253Q7oh7H9Pj3cs99p +1BTx7zEGYNUENbC9mDsJDADcd8ko8XXHE +12uRenUezcXbxThE437Uj1J9kAoU3hgZuJ +19YpA5Mgo15SRJHzDUrxpoRLKQPtqVzMyD +12UC4gfk7BYZvfaDhMfVTdvZGARXYvKgbZ +1Fkx39uwVyD5Nm5cj4hVeyUAuBeEKqPoyC +17PKMqSju6K7rSfGPnWStKM1ifN3VCirco +157x55P3FXPjEaBBfMBLq3qxfYT4WvpPLr +19xg38W1zbUhdqzV59Br7wauCejFzf5HCD +121UVcayVstKTBRe7nKTJapaC9FjCEXXtb +1KP1P41V1Zw15xWPaxSk6a1CZVBL8m3wHv +13AfkGKDV8HzYWTJ7NbUCzi1uNcxuqNHsP +1BL7xKMsbAab3wYjS18N1gwnu5FNMktzrG +1QBKmZTboNi7oSzhK3GvDNj9e6CZEpRzPR +15BCqkuh6hbRTZPTxbuMaTCLbV6pkjSY1s +1Pj1M9AzxmMZyrRCqQ5bipR1McVk4JhN3 +1JJqbTnnoTLEW4SQ1AseisYHkSYLySwugv +1JoJLyzX9rcYUribBghnboQKXXa8hhSaFq +1NvpoLBWe6aK9QJhrG8we246nEZPhyyyrL +13Wou4Lkwin9Sx8aUzu8KQvjACstrnDwoi +1GtXWjsEs2pHSv5LKskaKSaqMGDwLcZCG4 +12LY5xNwqMKk9RFR1JaZx2yserxdfNZKq8 +1maGz7VXtu4jXvdZ7av4BVdERgaUjr8cU +1DYAieq5RwJ5fZrcwmcd8EVT7DDzGrchQb +13LgcneUXMZrkJ3jys1BwowFgiHKM6ABTW +1C6agqxwWbYzJ7PwCvezUNAcQLcDFijLo6 +1CnsZz1SJ43dTNXAkXYoocZrqUMEyVM2qK +18zkTbRxhjEcVehKD5mfjJC1joHfT1bKDK +12ghKyC6ciMHL69Tt8pTUXwCZwnh56ZBbS +1Dntvs3X3LWjvYQjjjh5yWNdyEtRi8qinL +13Jbmbzuzb9vo7LzPGDqwNAukCj1KWMpyi +1J7uJNL2RQBK27mxMLQTNa2Bt6DKwVLbQK +17u8enU8KDwBk3YTtGCLwTaEGzsTBhTfcq +1P53yDVajWv6WGAPoyq1Aqd2fFT7PxgNqx +1P7VTJXxBoriGSTZ59EFoiBnBH9TqGpNAN +1FWcn1WG3r5kmKE36ZiLcPbeUZ5cHa2Edc +1Dyg8y3d33Sid7KVTNQT3ps7APhZkSVGEY +1Q2GuYmdvXGDmYttJ9siWppxogTm6upfGb +1N1MYUgQopbhB5Wwv4VTwsVBs2gTuVSxhn +16QxnVQq8djwd2o6JDk7yZ4sLTxEzWA44V +1JjcYHEwBcrZomQMvMD2NhNLgscYVqdZXv +1EPonShHiY94Q5VnUVn5wQbh7fscMJFAYy +1Ls97dYNsPuZoz9GcKcaWdEt9T5DaXnt9w +1KN2PVxho2NJf4U5QF68YqCVgqyHiXpwE1 +1JvXNL4TLT3h2oJ7Bk4D1Ve7dr9dvyTmJy +1HCQdsySupLiiHEg3mHxxoMNEifY2yLXzj +1D9GVTXvFx9LyFAHdVEKszzDKur9ieT815 +19EWBDB7A7EbzGD316p8VXWKPUtqNuZT8h +1F2noyvpxcXLUibx5SSe4r9Hzv5Vr1e8h9 +1FUXrdupyqLidwXhJ1w87FSkvTYvu4pM9Z +1DBBqUiUA6ivMxBdHVU1QDFyuz9ZpF43fo +1GDxRgtH1xwr2vR9dR2Ajn473Da2hwUQty +1GgqTYwgR5uvrSF1p9rovaHtZ8npsEZ9pR +12mnEtjBW8ejJkbsSn1CvxoudPEc8WmUyH +16BY5adyQHhK5qRZ5deRa97wq8w94g2BAt +1CeyovcmTPJJrLGfP11GJvLTGHorqC7r8j +1MbBbvMhZxC7mEzbcyBv5EBLHEwYKrt88i +16Vxoe9dUSuJFfFE1jf2k6Mt7hbUgodwMZ +1C8Da5t5bXXqZqibfSuSJKU9FVxpTGB4sJ +1JmDo9xrAucUVaaEbRm5QT3zhF4D9BFTKk +1MXPaoSGJJiQ6d2an9hgmJtgx4DqP9t5GJ +1Be62oGb2W8REFJZgYymhQXZgYwsxRuhrk +1FwdXwF9URb14ua5J7oovHNwnnSdmvPGMY +1L4owQCG1WkLpQr7JPPzErtAsWeh743Ncx +1AfFZ65gCUnWKxyM3jxmHg5yR4CmtxgELk +1FRWyxunrG5mmgpDGijg8cns5BR1vWXZpa +1JcwP5q4db5C6U15pgSdn4aDVdGAVaaf9f +1PFWYpZjpTLMKtLYvD4uzd9kvVNgmhyPK1 +1BdK2SjWn2agAS1EiZyrwuwuFvDKDtSakD +1GxygBzaTc2E7s67hr7A7r4fSf3nuk9JzC +1AqkhxSSJ9GnHrkw552LUxx3YxV9Z8SF7J +1CuM3NQNHwUH2H9KzYWwtC8wDaujdwaw3K +1M5pgNxUa5x47opLvXPaoiRiEKqcNetuC5 +1Lhpf1kYQqq6NFuw9bGJkpRSi8CZ3p57WP +1GTRFadrMLzidHZwkZ8UUNkRkMtZZ39EMw +12PwFRYeXRHpSbxSb6ejA9pDTb1Byny2o2 +1BbEoHXudHGYYqgC5CfFMFEHEiWg7yQ1dZ +12Ba6fYvDagbRVPsZj29kA28REUJg8H5vK +1Ba7HwRDkj1EmbzSgr3NSzuotpo9jAbP5m +1Fji7gkypgoQagpSYCkA8wCDZywAN1Sjae +15pRf652Pq8PidQwHWCsMgnspz59HDyDDc +1QGrCSRkDeyhH9JGWczsvrzJR1pBnkeHcH +1KzZVFxQuR8q32zkBQGVz2pFnj5XeNox8G +17kTVMEbxwmnqaWxpchS8ADzBXPY5jTYv4 +1KB88hNBc6rZLgcSS6Q4EdXmwT7JXNri9d +1JCJdSWwUj2zPWvt5LBvU31QW8PubfMPo8 +1W3auEGNAW5ZH7rnrAqFisXZJ8mwcbnZk +15tmPXNJoi7sKwPZqqyTngRbmLrkXhYpEM +1FYhRVDw9aU4w8gy3xfbRjSq1Jwbpvv6L1 +19HBsgXt7CJq5NWUF1qKu7U48G839zrKEL +1CxpHE1s8bAZC9bcf5BAN3cf4fDB7VPwbn +1Ngt7QTNf8Nh6Wbs5bsJARsc1gc8QGLo2y +183XPvV3X9zr8foytYY2GrK98GXTCbaVwk +1LxRJcSq1AgLdU89M6eEw6gmRaUASMwAAY +12aN6WBMFTVwZFC4oh1F1kv55xXMjJibtq +1FDSusCaNeL2zsd6WFA6dzBbdRrB29G1oG +1PnXh6hQ2tLnGi9Vbn83AGHcJ9S3cXYdpq +16tC34AEmGTNvo4i4sEU2EK6f5pQzT5yBu +12Gsy2Y4kyPG2ChNN4X6ehLbaeNZbSet6f +1BkurcHX64fPiBvZCwjfhkh8jVioVgsDi1 +1JwVkBb26YAXeFgXCpuxqRhY1BJF4zzQBu +1MpzyMHmFnsvdV8pE5zxBSQCEu9WvTcXQd +15rPnh9iv7FVAok3NahBF1isDvB9EdL3Hi +1HGPWaNFDcPLafKX842Casur8wzrmDxizU +19meijgj9PBP1koG6HBj2htGYrvKWsJvbL +16KWc7rEHLgA5chEExbc1Kk4dRxFLkuZNE +16TWjy74kT1P8h4WhzENWmy5ptqevbFeg7 +13mfXGDLde5G48Bpcvjeg1FwngHvmJzG4M +14MMPDNEKf63x1jD6QMhEVWp31UMqxc4d8 +1P4PX1Em2kPSYRx63zGXMnwZr1Z8EL5Ysj +1NkAJ212cWHMw2J9eKZ7Fn6BMsGeWJVq1A +1CC8mkSYRZioaZyFHpzw5Denz1vvxptQt4 +17GuxbmFeHbCtokzHaMk4HVKrVqG3SoDEs +12ZhDPXbtBWhJ3XkzKrSYz2qX2V6ZovFPS +18uFzNWpX4JzNpH64sHR6LaYbwH2YoZwro +1BT4XCW1RnpNTvYiyZ2CNRWiWgJ6Y5EBhb +1Sfn81VkbSMRuBUEegcXMssVo7nMhkmA7 +16g4GBPCtwSLfY8ZgQtmubW2CDqDTwLGWK +19z1Zp4ZPoYYtVKpFSeqqnLgrvdbVxiT13 +1Jw85H83jK5E4mTs5NEADfRRhYwnMuMf39 +1L4n5E7Wk73HvXtVmvDQRk4YLumK8nmGyq +14LEaYTsLa1zW92Q1mhyGMKo4MYFXD1bFW +17pyeiqs4MpxMJf3kZo4TCqu7X4APfk4nk +1PQQdkjcuofM2MGG8mW6ZRtYV3TjMREyUi +1Ca2ABaAjPkq4iHSGcUXcLhfPHgmUkggdW +1Fva4EjBL8hZbyXsxJqzZVtUwbjcBCkZdi +12CEH2QGVokx6WzSejfSmsQpn5GiEKKzCC +1F3wRs3QK7QJV6BwNSi4Auzpbawu58EgDP +161TWgAiajs1Ajt4njnQ5V8tbzb8b7ctd7 +123rZzwq2g54gQxdB58F2V5sZrXF69rnpq +1QFKyqfRQDcVMmzjL94WSmcKga36tDtf8N +12G9XDq6vgHbjz9LB2rKdf8Ja4W7VrGDpK +1Nv6bZU2YUVzgghAB1D528iFWJSBEAo5rT +12PyTTWxpgbS2k89sbBEoe8Pkw2KEwSo8H +15M96MNjweMBFiRJinXebKZujUJRqSbRpB +12pEdkhzM3cabhcifYpiQf72cn8vbknUH3 +1J532afVpajKbKVBb2hDJMTMurAVMh3W93 +1ATUyFyy1bYR8JWxjsJT6MHzNRZnpKM54J +17tP8Pzw9ctNo1oBLZmAQhPiktyVgp4GCC +16qL8pBSnxRGBHJ2vuhBZ1Lac4B9yuvFw5 +14s8an3A9rLQKtvo4FFz9W8KfKrxATgMBj +1EPC3UuCgfh27Xnb3BBCUqEcEyd5wgcENw +16s6aXouevxC2ZKpMrqYAg8shLJqBbyfav +1PQZadtPvsaEdAL6Ka56XkRpHWE8FXKjAe +13bKUc577F2cNUJWzQrwMZePVoKw28FzWf +1M97b8578wpUjRZqz269wStxFcUeNTDfpP +1DomxGXifhHSCNnhdk1YogitgS1U915G13 +1K1ecSVvcwtf8KJgwsgHm8eD1SDQDtJnq2 +1N3CkpP9VipPXwaLLPoQLv4ARELjjKK2Hj +1ELNDsiHCbAqkmtmMwuJuAQdZu4Z8onyG4 +1GrfEePJibYRbwW7P2rCGHwt1D6aZHU2Kf +1LZsgsokm538VKMqVCpuB4Z62or3tGf82A +15tA7N4PEmNAEbKteAXrXd9HoHeXQM4fDL +1Ma5cTmtdT5jDttyZBaoKStty6X8QCAfey +1DNgt7FuJwP739mNCmT44a6nJj8kad5pov +1BGsEC6DvHTAtGWqpmVzMyxspLq3yd4tFn +14j7CbUpxUd4oZNbanMdUMYpmBMy9ghSyu +1HJX84Hg7T5aboShS74iePPgq8nef4jcfc +161mruucsu3Vz5Vm95KYuNCKvvtJNHtw6X +1CcFZ5MPkrQCH2PYtKaLWYSxShoUkR3w4U +1Mbrdb4r4wPGrwyVdaGHmUZ7mqNjqjxwdg +1stSRKjCTi8zmRb8dDAbJ4LD8ckvdhkPH +16Nvzv29k1dS1Lq6fZJrRjWLbPvvpHL9Ay +13Lyj6Nrtro9eBrD8fzhmLn9MbUMZvGsDc +18ahcGJf3sjPEUAzoozVk32gpCky53BnSa +14zt5Qci9QrujuikyhtmeLxgzhSwWr8TVQ +13hw2JDbns44UXU6g3V3JgBgM1rYW9kjzx +1MgQHxNDtGmKXsuemVnVi2rBirkdZqNcok +1NyBLmpdSM8K6NBDKcAivkeb5H3eXLRd8d +1CbUTBdUhSSTVktqY67DCRdVZQD5aiMVYu +128cLWQUEWAczYNM6NbPLWJpXFwwGC16gh +1JubNugn6Gv6cezCLPFk9eE95crRPK4vx +1Ho38tw9Ht9JXZdNQATBHGbMmoGSjBh6EB +169rp6jUEXmeFXVXafivbMDkF657iP5UJU +1Di9eWYzXTrr5QXXemtMsefKvFGUscPL41 +14Dikv7GbD1kaiHEg1pVfHeRtJBnrck3Wa +12ctEtrVvfv143tXXPvgLLsSkea6uktEMg +1NE2RUC8dqy9wJRTZWPT1oCEVUiTHNZCzU +1A7xCwGMWd4n1rg3UULdjgBRsH757K1yne +1F69Hf2je5Ym7UAcDMrKNuj43cWFY7YUfE +1Gi56oTV4cxE7JGbY2H5Ur698X7yr6fHub +121qDS7q3bd4ijsQ2SVjBQpttCbF7Y4bhf +17qicUDCffa6SydpQBU2eXaiNxT1FDjoE1 +171qJwzK6HGsWhWAkKgDrgmZAMYKnmwVTM +1GpfJBYTuGA4tQ6MPCnn5iHtaQkV9kghtk +115SuvxbtDFYxdaXjagKzoH1rtxu5JEnN9 +15bRACbGw67rqub4EpTHY8pEaiucFonwiv +1ELab4Mzmq6PyVGkQAzCuVyUnBwUg7PB1L +15Bepn3x6k6Xsd5pHktV2feKPyHj4gNacy +17qDWJFiFTm3EbFTUdsMcQvK78SrKuyPGb +1QL7VCKKg3zLPsCsmvjnh5xJVGMvGcGHXh +1Jn13tZ8PgFB3j9YdASrfUMb5Kf5hTWBDE +1LoeXtNGzeiLxm9vjteSrL7VF5rRAJeF4W +1ChEg3RM4FytXBx4qEouavH4Hp4Q6xASLw +1Duc7ur9aGY5pQgr2qgDSFVAaFC4Ecnm2R +1A7SxJyUhb931oto4252vSBKcMmkmuzm6Q +12YhgyqoHWGxgn6hkmH4GK4NR71d1Hn12h +1JwCwji1cCzvbsTaTZfXiaE2pZ7QFPnw6r +1PmWfx8rnEvRXDCpfD1XuexidsTDbp3zB9 +134Fe7kr9YfADccusHNuoqxW7eC1JZA42N +1yzaZVYQJ9zK16NbNgsvgTXXezNymRSxT +1LHXyTyv7mQLsm8SHAK2NveiQHctQh4jmP +14WX1ke8Rg5jJXdeWGHCu3KRWWHySD5SFS +1944Nz2NKxVVbT33qHWSuCF1D7Nm9YaPJq +18Nv5McKPtxa2hW4anrC4vrdiVFKgQy1Mv +1BWjsxSwsWLhJ83BeLy4EUeKaLQ5L7sVcr +1Q6jTD2vsQS35Lc4NNZZGaGE2vmFKvRcym +1WHuXoWD1ssLohhbbJ7Px3FZKrMeQEiPd +1Nf3niELqXgr7wV7GP4McnmDKEPCdSDwZk +1M3iMmG4dg5TaSSPKRCa33qAkQbbVF6TsU +1D86wUKtrDZqDng8XMUDbGB2GADSiPSr8m +1NnyH38jZYtgS6nS6h2DzN5frYEE5MAhv2 +1FPYRNGbVCJfuuor8vpbHWK6kobb9uSAYg +12Hhn5bHJZakvrzhZTvz3CKakjtswNQA53 +1CfoM6krsutGb2fv1eGTDughpbbZj8jWqe +16hvfcdrbzfkQ1Quq7DUzGKRhh9aBFxY3a +18d9KHYdmRC5MBPYUz1DQYyGpwRQZiba7F +1EWLPVjPQb3KZKRFN6eRQZoMnHGQg6gVaF +14TV8AzqUtNk1wpfzDRu22JcxbnrnJGJto +1KEy39wWtHMpkuGDxUCPUdDzXzAjoJLWqq +1QFRpqnWVzjwNGss9KZFgPET4s6qvUGKim +18Ar4Hh7UW6eda5azZw4Grw1z2HNryfAH9 +1AGyB1SPEBEPsSojEY7Hn6mHQ83ygobHAx +1A8hL5cfLS4nSUsZuBWVd3pE4W9WL6svhd +1Eccf1QptyweS5F5uetCdUdrShw69YAwVv +13eEKC14KmBSvrLvReWY8dX9RP8fj57XLu +1P5cCMgdafN332hQrdrkMJNa58uJW6YZdW +1KXyHA8rptd1EHqwfXhdguD5URfbWhF8rs +1FYrVf9baGCd5Qzb5WFUiDnXB39giJS1jb +174F7mX51zxrLPomZ6aCFG6rkrxkyhxdVi +13meLuLfv3XjDZEnqpxo8Gkqhk9uCF4XdU +14YUnP286RiPdoPwz9j56jnh4AjV5PujUt +169eBP2sK11SDUhYtfa1mkkNTbNK9efrAY +13z5TAcFQpHsidDSkaH28SUpWihLGmqvhv +1Ez6b5s9GssnbZfv5LyFECL1YMuTtZbapz +15veVD8ap2DCHZRP5j3oLywHzrg36XU1og +1PZsZy1a3bYT6nXy9rjjbEwmJj6VyvFAVZ +1Gz9K7ESGbkecMgVD5LARQsSdT6ucYX7nP +1guKbhM9jkna2iC8Lkukd1RS9qdBkann8 +1KJnpk7jNBAjym4JNi6ZgvEp9hkzvpzjmt +1CZsrCecWm4xX8EVUVvH1eydf51ofRFryi +1Q5eRt7cKiskF5CWsp27NXUJ1YEWqS5zzU +1JNG1Fy5683eWpmrFC1pYS42o4C8xCZ8rV +12r9M2iQykc2ZV1HuY8Ctzw1nCeow4VyXE +1FCx8yZ1YZrZcdYGUSoJ2iErYF32diGHs +18hU7su1sVV1tVmnhCg48posui3NcAWbSB +126nmdK7wUtkqB8FwWsL1TCP16w8n67mK1 +1BQ5ytDuwn3FUVfQV2QWb2DkxCwacukN6r +1Bbs5VzZhRCcHCxPeAHbry8krpGTz2GKs1 +16PRjyaU9PmW1PiaCQpcKw5kj8P6TYjieA +1GhqrCY947CSna9tR54RNrmrbFaCrF8B6r +1J9onNVCFkxGFiJiqEq53fvgSr6nhyhwg3 +17W9GaL4SxbZkwvt6JAzS8fMhg2s2Q6dqf +1GoBDhZB9qkLsfeS9Kg32cMkhRKe7KDrz4 +18qcSgnPKoRnfNiXgqgyKrajvqhWNa5iWx +1BFjRsnkCQqGtrWFyuQPdADbrjqzCftrFE +1ERgCYPA1CHy2ct4KFt5sVPMfCXwsFiGLa +1AAeAHWvoEAhi9cNNqhiyAMLfoVeFakHp7 +1HuLju8YEpuZeg13DhYJ23VmJzTHmVoHCv +1K4hg6YPFyvNUdBvuPDbNp9T6nimxPNV9R +1z3bJ9dt52ZreMQyagxP2u1Bne8ZWMAKw +1GgKap16LHq1CmcF2PDFZn1BtZEj58qv1w +144KAyK3Ree9iokmmfLt13f1LG5qpTAq1k +1MYw9umdJR5hXW59Jq38D1hBSvjhwMnpB3 +1BZ7vudWc9dcsda8v4kyiu8RE5ucE5VgRx +13sRoVLrAYT8stuHU86phkDzqadNGiY1fz +19jxrMqg8rrfn47AV1gfkWGV9TwiiMSf2a +1LzScjNDp6CqQZ25BBrcoE6jGCy9aewDTk +13wYtnCn5empGK4xnMU1KgSRVfU2EGwxmW +1KwTYWcDakrLqcTJWJ8wbeNk7vqUAxVxJs +1MS72nweK5AWpL48f3hRGpfGEkJEZHDne5 +1Eq9V7XjSquDZtjSL7JnJt4vYHmYMv5mqE +19R5hRTuvrDoFq1zR69EGmUVC8U1VnrXRC +1P9XGm3eNKRn7UMR539B7juwjJ2H9hNKPY +1Ly3qa7TWJZehX4bYE1RgSeSzuXyfZcgun +1JwN1NqLW3k2iRPeNdKHNzjhuqJvyEqVDe +1ERa6ugnqHBkXHbtQ6EvEsSvowfDcomE98 +1BjJoYXuvPbnU9hRNnMAEcAkGmB2aTs5et +16C6E9HaVyNYibqkApAXE8VZrWBCKBQbTB +17uW3Kh8oeQ1CgMypN5qMh9kxEFn4qBEAR +13GDjLhJJbyY2t8n8WsQjdKWkZmMW37thY +15pVTFwmaMG9jFLJWAud63zDbggBrJukfB +1GRt8T5ha4HGfLQB3V5tnqQgeVVSYdpnTS +1JdXMrpGun1bev4V1iLxp4RVRH1UF9dxJ5 +1FtzsfZEA1RqwHgcnrz96pGMrEzLekvHR9 +18Mwe1zAt4Dbiiss2CGb97TUQg2KBQkXxn +1MTmTKpYizsJ6gccpAVg9TbAXxs4ND2kVE +1CNRMist9CPpnaoh5FAhco6vSXseMENVb +1CW47r67y4TR6dEAZs1cqBAUSZ4Ldw1wim +1EgNJuCafoPSH5aBHHTDLaugYpm9bR6QVQ +17Abhj8nstPsKuWENaSobPU9xiw37cJgog +1AocKgw2zVg9NLB5pJh3AuuTxyXwBQXc71 +17WRB4zQbW3hbxXikMAafC5qJEirDFaABa +12jUpb2vhUXoAriJMk9Fz2pgQC9R3H4LQL +1JKxyU6jge9untdfgdtNDQeJiWnSMbZKex +1P81YjstjA5hPBUhPPztQM1u71XEVEDpSq +1DmKVfEM1LU1XjSwX2DaEoQj3ZuHwZZdHc +1QA8SQVUoJVQ5yJ1mp24gbkSm8F3BUzxiU +13CbZurSuYbFaGetH5jA4dPL15v1k4PJrN +1AA8ac2PrNFRohGHdketnpbpycsdFFyCAd +1KwNYn9d4jH4z8oapUdukzVWgNzk1eJ2CR +12wgS36rJgQbbnk68iVf8ZLwarJqxyXukh +1MShxJ1sR9rCr3KQjwteWfBzv6CkhUr72B +1JMrptPJHHKEkBHw7qeWU1N5AUyHnP9UXg +129bo4zyTtKJ8woeaomhXd5Cp8gN4N6thd +1DCmdE34feS9gV8GPsduSc3PVkk4x77W2e +1GnLBed9Q8MGXBHMbsGS9ymFcnMuJYNBnB +1Gto9rpiZjSeXaizuDC4k9Utg6x2gM1iDC +17zxioxEY4iV3mNxaTHNYf7rYAX6rP1CQj +14noVN5N6cThyVstG4dQrnJDKfKBPeEsaJ +18d7Yy9Gqh4eqztqPGyQY6srwb1Khg7FpL +18MyUVw4dYHctGpGSHsL8e49BaGG4e8VWG +1NU3brSXbLrbaEwPxRnn1iLBEse1meyAqZ +16Wzeuf3uMCbsSkUs9M8379stWgfsDQVYp +14PZHKvkbCe3eTs4hh6DentJ7daAeJqRvJ +17p1c9n5LwfFN63jo52o9M6ksF89D2eKcb +16JJBxZjBhsQSgBBmk4Sqi1qNatTaNr1aJ +1HrtgMo5U56e6FjyrvwD8cXQG4GNZPh9dc +18iaeqibVM9ADW6KZhWB5Mtdahg7cWAEsG +13VLWHaT4PZATVLHDgusfCqZE3nQhHVHzw +1B12VaLiNiUun76siMhceHMVTtqqmYxQVv +1NFBDR1sWrtccGuN59p93jdVJCX13Sdutg +1MuhB3dYNpon8SSsKE5tWufhTABDL3C71k +16ccFT1T4Bi2Dk7bEJQnfENZ2migRVySov +1LeDkYg2dM62CekiTPLkc2GyMtYfZrk53a +1AgooJ5VHef9Fov72nVELJjw296Jqu9KGB +13qfqzn7BRYbDcvQZykFK4KECtwsec8ua6 +13H14qvWuEowbMorCxcp2fd9ZMoMP2EFLK +14braWHtQLu5PbfkFdFfr6uYtMf1HKtEWe +1FPP65HVquMMVwCikFzmoESug4U57Q5gCw +1JDFurxtFSLMgmxqhkzNwwyE1vhXERxwA4 +1ECNjCbe6JxYbT5YPnv7nLydb8L2bEWxYM +1HLk1Epe4RkYYZpwjGr8SjqHpXCQdqmZjC +1PNTowBBi11L79WUMHkntaQNCKioziePXk +1KPY7HDfyJPY3vAGUsCvYiAucYQEVmcWSy +1BjunRMBoJDmPzRGZKkZA2utGds3qJHZcz +17euyCxnv4Qzt2PY6rHXVKGLaV7rV2iwvK +1NXhZHh2pyv7C8Qq535ZxZMCnharYH4anJ +1Pdanw4DjJj1ngkjAbhog6GEUpo3acs4MQ +1GEh2hLNS9F9ugmHnUCdK8sVXZU4qZoNv2 +123pFsKpHr4pmPbkmQdXNZekVJgUaekWFM +1DFL3GWwCPeMVsWD3LHvQD35Zh1xsskZgL +12TCu21psbZYkjLQB1maCnHee5w4dSD1im +18Nn7TEVF5cUXbsvk8RFs4z4bnqb343Efu +18GpJRE9i62rqoeu1wqtiZod3PQvibFcPC +1FAzZVw2DR7xrXD3n9dPL6FwANk2CXcfAt +1CEcvfMksUT53HzukxqSw8grwDfQ2XNrcg +15LFwQ73t2kqSQVCvnDyMNXi7PQjts6uuz +1Crznw7d7vGWzFUy6KHUjkQBXwBg5X3A1B +15eE5AYa7iJbC6LGjhYQCvEtALygWUvtwp +1FY9wdre1ZTPnjbHKppkr44YGjtmToFrcE +1AdNX1upvcVtxWtMDFmU1rDd778GJRELvC +1F3CqtgRhYrK2wU9BKsnxEfHriKuS9hKiq +1B2AyBwUjYePAjTyttaWPDD9YFRyYaUe4s +1DKwZ4kfYgrDwFMEY4cC8QA2wJVNxFdb14 +13EWVm2apmf7kMH3fqcWMSHrdXquApsiQM +13dVFhaSweTjgGxKuMepw9omSN2qvbd25n +19MrMniUU2ph7PhNgrC8MAdhbfximnSP6g +1DLSoZ13K9hAPDQuV1rxdtUY6ZUwJXPSPa +13QZjLTU7s1yd559g5LhPb422qYNDqnEP5 +1GWdPe4tCEELZ7ft28PRCfM4tsXmG7T1eu +1DCqUSKZbbUxFfeYxia4zYAU86GuCKmEK3 +1CLqpEe3STBaYzBqRfRNR82F3ALFM1NvzG +1uEhcGHzPzCnepjLeYy5ZPdXeJgY1bd2C +1KVPoi5y2tT1R9sx5vSuZedytMrCCY7i25 +138gZhxd8rC6re7TTJz7usPQ96ytdLzqZS +14k2FkZ3L87BqJLYMPpmY4HeCp4Kzds11Q +14gnAGERQxBuvEbYpshzWMLP4mQPSTrtTP +1t3MKUBZkWkQpwTQQcmi8CSjXbM24VxyV +1PecGwu4MPMrYsSzU4DneAJpUSndjkn5Z3 +1LNXA7LvCW9z6hcGgWuoAC5tevZd4PL6Fz +1LMffBBHx2AnkQb9nSAthXx53JWsz4KcDk +1Bjp8DqPZmD3Vtmhgu6S6PiMPPAVXhomui +18aYc5f1F2N4Nrrrdn4awkv4YohzDLfEsq +19t9aLTJ81zHRkpWVVMeuVZQKxnbUAyNds +1F6YbhzHZz38FCCKVP9FzuQ2FejHUBEGdU +1CMKLBBxdM753sVTHcs4k8QDJEj2UFkFHz +182Yew3p6ER1gozm5GfV2NLuUAq4Tz7FVD +141dw7uv5bZMofNyBTWr22jiepzE4wDPoR +19FbHXCuwwaTkY7DMYJDPUF13JvBJ4hFL9 +18tdsBX5bzXmUAmH7NvtYUbFdLMXkZmC2q +19P16aLMxu2TRzNf8QwM6zKKuQErf1xvVX +16qWsW7v2W8ndYfpzqrypXBHwRx62nnfxr +18dAa6HbFBfeVHvbZqp1nGqrgMgXNXYYTX +193HRnBH1yhzqWS3aYCevCcBvwVBThW3tn +1DHPfdFeK6J6TP2xGWqm4LLnxnrLQkYYy2 +1Jz4hi81rWfEL6LtAibMUPahGXpLauCEha +1FfqPG5jYucHjr8wnUpACCtVP8oqvmu7Wa +1DEqz2GJGJWkgQG1qu6LW4CwAQWTFS8ysd +17GnmpcUXgDK1nbqT9Re1EfPSRTQUCrs21 +14hnSKT6VWvfzmj4ZZpufVZc9vdFMBKuW7 +1Es53mVX3uotPXE8G7adadwRg1vYYA83g2 +1J3WTv4rdxmcZYVA1AbEEM2GhEibefs6BE +1Pu14kxht1pRS61TWcv5PgnaXEVTEp35KN +1NCTXvNTkC9fjeozNWMt35D8d9GYwW6JbP +1GmLNxzRzKWMzmF6riFW4bg3cLTiE5typb +1Nw2KSvRf9kaYtbEXi5EKcDnimHxWQZ9Q2 +13SXiugGftnPrdKz684uL2Ekqhqw2Fv9Kv +17QBA9Q7GuyStmDhunP1YcgvrervmE6iXT +12hQHYjg7wBkbz21h3qYvnD9KJ4cD4vCTS +1ENU2ku5T2cYcQA8Yk9e6Xt3DCxw1v1Nsk +1Kbw17PYLn8saf2hR89MGE4oCVBmLjvyvW +1LJYt1eB8pKx17cnKZcsorybymYimtzBbF +1J4wW3XhcmApaoMRyvMYFpa5JnjJRx7bLP +1PCs1y1FDAWF2nZvN3c4RifoGSNQ5YyEPu +17rNtHdh95Py3p5auCJobyyurmXMnAaFnP +14s1FQGm6ofntneRbqLjGcgdhGNheKFxsT +16xQXZLXSwwXeLRqzxuS7tWMogcitCQ52W +1GUiX4fkKxeDeJSQwFkEfMw3aCssseB2ML +17y8z1foSQNeeHjRCNDGHLzdnsiehvCYwU +1E4hAQm7JyAZzc9jNAWDryt7cmryjTbmjK +1BaP7yS7XUhcqDrtS63hLmfL1Pe7ybQvHP +1D6gzPa1MeR6qEUsmVvamfPnwVrKvBajtA +1HD8eDq2vXbxkTKPBvJXSXiZSzkDJPgxar +12YTp7UMmqDV6bvnKGwymwfZHjEdP7QWf9 +19HtigGnFEnCsMmdjTNMzeMH2wgbe42hxj +15VRxDX7JBtAfpj21FfceVzacAzPmTWEvz +1A5v7Y5Z8oaHJ9yaf6joeJ2CqhpTh9a1Ak +1ELhikDJuKYCf5RK6aDhzzxhv1Eta7kue4 +1G5ZPFfZCAR3heRaJWAJYibsCfci6jiKba +17GfJpBHWs4utJe1ujEvRKvnWG6jsSVh3E +1354kRp6T7R6bDtpPbtoFqKDJxotj7CEEg +1JMHLF9wAgDtqQtrj3YFnCWwHQC4tMz9y6 +14VCTwvvLgdxnDL6wXu8L4Wq77hWJ9Lyn9 +1GkHA3pnXNQ175o8pM3WVtYhh74xVfis4m +1BVyvfRCnior2DwMTvWdVwXz4wRM4eV1dB +1P6icJU7GYqyYeoSbFGc6WtUgH4uBvrVYQ +1CCqFNK6kZpQv2b2sUkEMYNPoA1LDaKY7X +1EWCf8dzNUR1ijK4M3E57edsKnq9wLwZfB +1PPSADWFNyBCyf2UUQjrkuiUNvngNJzgJf +1FT8V4VjhqH5vDrcwCt9w7PBWCFVLLDD2g +1FGF1zvUQKGBCwNSHcMBKooXsp6TBh5vgk +12CxJdthb9tGwXW5MEXtNGb4d6wr6j3P4w +16jKhyEJBg8JTEjcFDFsuDUmXPeHeZkEKS +1AB27w6paxP3StYVmhq1UeZT1dATfHehQS +1Ni6S1oznLGgC75UsUua6bbpm1QwkZUFmh +1JQWj7ePXAcG7sjZLh97yNcqDntxgnV1N2 +1CscrUuWuY7ncNeoUjK49AG6euqhjr5rX2 +1AmsTXfeWsYYwZrESYE8RGGz6D5vXLLmeS +1LxG4zyrAj2FX7N8zNn6bWeoYMMKUFzboe +1BMNhNBQcu9MjEJGjDHgaQPLocYMYXpQbK +1Fo4kadtPAx1RbGqHnRV4XmnkkHBi6qJKd +1Q2wkHZHbkLAtg5xJaxJvAk2fipyzX5FBq +1BJk713mMSJU5WLxuEPciJbCTvGHdWD8qF +19BZDfpRm5Ancno74LoXMoeNV8ZvdFuscq +1P6brD5MFNdyaFrhrqadzPTkQQuh9hXiup +16XUgYDkigfJMSad7kR6WhttggPb4JwEDB +1rrTPHxQ9dniQBJLt5MognwPaf7ic4U3G +1BnaRsV15Up3Y6R9MeWGUMEVXFnWTfFf1X +16YxjrDt7ghVTnkrjkQ46ZsjoyRtj7Dtro +1EhgTgpWm5ymsQjHpr48TokZtKxKXHea38 +1BJjnxETzi3Z2H85uB7Cvne1jMf3pZEpxi +1DeGJMb5zQc5njgUkyJfsUsUJYSdhtkTTf +1KEmDwFpqbmYzgxUquqHoeh8x4tVijiW4r +1LZn2MCdiBVphPK7AVhMfZirZ53Mm9ghVc +1HLTBG6BzHSf7RyS2FThczyfTFHFm37kjK +12EtQx1eSQkkGAVqTs3JhQDVS1QGN8ws1N +1BbwDE6tg6ZFLyZ83Sbpsw4LspXGNTpjEE +1N6mqfcFgTSTTGEivq3Q1HgbUWbASpXAnr +1FFQBVy4hK28aGHkZTwBo99NvZhx7piSUD +1FynKcDzYdLrauEKNJtXvzE8hRDD3AurVn +1Le1vYGtvaAQzUYfJNBedMxbnPYjFpsKg6 +13e92EKCZxkUzqTB2e3UpbTHkKYyBnEH8v +15iTHzMDiCn1DHBk1huiEBp5MRyntKcEq6 +1P9JWUnNkMaM3C29nSoUSVrQy61CxLkJbt +1Kfgjy9mv7dCBzsjoNQg5mxQcaf7PqZvtr +16UswN5LByGZe52tWSEVY5wk7eW9EHUgvA +1AD14hXsoG8HFq73iGNgEYTwP75vCpE99m +1Bd4BT7D1UBGYo26uw9jQuEVnCrTVxzY2d +16VQeGPpVVVTckTjhGJCBvUgjpTZj8TiFy +19XLyVF1Ckab2QxKpyDhUGctiLeRshmZi3 +16DAZRSAdB9sTaQfbGwcbFQWS3u6hY9EYA +14STs7QHk9f1KDpCyhfA461SwtxpREqANH +15RbwBrbNuyVZWawYcBwBPqjqfRJnK29Nz +141125cLgVp67d59Vheesz5CNrTJpoN1xX +17jzG7B6pfetSZfFFYkT2QpLf7hBq4Gkza +1MZzDJyH1ytzJPqwozCurGTXGz8bXv92qF +1Cz5tzo9pJjYQHAHrfzygh46zbYooMZ4A9 +1KwFtBnB7u9FYxk7hjuG5P9pcmA3iafSMe +14vZWsBkcQCsfwkKvGYQCDNu49BfTqZv4g +1HDk2av5JFrbQfhCspAu2Lz2JL7XKHoSpJ +1EueUe5M8bbhRSPvqmmLFGtQHatxD4eQ6z diff --git a/emscripten/test-correctness.js b/emscripten/test-correctness.js new file mode 100644 index 000000000..623e53b2b --- /dev/null +++ b/emscripten/test-correctness.js @@ -0,0 +1,30 @@ +var crypto = require('./trezor-crypto'); +var bitcoin = require('bitcoinjs-lib'); + +var XPUB = + 'xpub6BiVtCpG9fQPxnPmHXG8PhtzQdWC2Su4qWu6XW9tpWFYhxydCLJGrWBJZ5H6qTAHdPQ7pQhtpjiYZVZARo14qHiay2fvrX996oEP42u8wZy'; +var node = bitcoin.HDNode.fromBase58(XPUB).derive(0); + +var nodeStruct = { + depth: node.depth, + child_num: node.index, + fingerprint: node.parentFingerprint, + chain_code: node.chainCode, + public_key: node.keyPair.getPublicKeyBuffer() +}; + +var addresses = crypto.deriveAddressRange(nodeStruct, 0, 999, 0); + +var fs = require('fs'); +var loaded = fs.readFileSync('test-addresses.txt').toString().split("\n"); + +for (var i = 0; i < 1000; i++) { + if (loaded[i] !== addresses[i]) { + console.log("bad address", i); + process.exit(1) + } +} + +console.log("Testing address ended correctly"); +process.exit(0) + From 08545a15e7e4083f05d4da5bdf5c04e70d7c2858 Mon Sep 17 00:00:00 2001 From: Karel Bilek Date: Fri, 31 Mar 2017 03:38:28 +0200 Subject: [PATCH 393/627] Experiment - generating segwit addresses --- bip32.c | 26 +++++++++++++++++++++++--- bip32.h | 3 ++- emscripten/post.js | 8 ++++---- emscripten/test-correctness.js | 5 ++++- emscripten/trezor-crypto.js | 4 ++-- 5 files changed, 35 insertions(+), 11 deletions(-) diff --git a/bip32.c b/bip32.c index f7b20ec1e..b639af600 100644 --- a/bip32.c +++ b/bip32.c @@ -25,6 +25,7 @@ #include #include +#include "address.h" #include "bignum.h" #include "hmac.h" #include "ecdsa.h" @@ -270,7 +271,7 @@ int hdnode_public_ckd(HDNode *inout, uint32_t i) return 1; } -int hdnode_public_ckd_address_optimized(const curve_point *pub, const uint8_t *chain_code, uint32_t i, uint32_t version, char *addr, int addrsize) +int hdnode_public_ckd_address_optimized(const curve_point *pub, const uint8_t *chain_code, uint32_t i, uint32_t version, char *addr, int addrsize, bool segwit) { uint8_t child_pubkey[33]; curve_point b; @@ -278,8 +279,27 @@ int hdnode_public_ckd_address_optimized(const curve_point *pub, const uint8_t *c hdnode_public_ckd_cp(&secp256k1, pub, chain_code, i, &b, NULL); child_pubkey[0] = 0x02 | (b.y.val[0] & 0x01); bn_write_be(&b.x, child_pubkey + 1); - ecdsa_get_address(child_pubkey, version, addr, addrsize); - return 1; + + if (!segwit) { + ecdsa_get_address(child_pubkey, version, addr, addrsize); + return 1; + } else { + uint8_t raw[32]; + size_t prelen = address_prefix_bytes_len(version); + uint8_t digest[MAX_ADDR_RAW_SIZE]; + + raw[0] = 0; // version byte + raw[1] = 20; // push 20 bytes + ecdsa_get_pubkeyhash(child_pubkey, raw + 2); + sha256_Raw(raw, 22, digest); + address_write_prefix_bytes(version, raw); + ripemd160(digest, 32, raw + prelen); + + if (!base58_encode_check(raw, prelen + 20, addr, MAX_ADDR_SIZE)) { + return 0; + } + return 1; + } } #if USE_BIP32_CACHE diff --git a/bip32.h b/bip32.h index 330294ace..2bdeef721 100644 --- a/bip32.h +++ b/bip32.h @@ -26,6 +26,7 @@ #include #include +#include #include "ecdsa.h" #include "options.h" @@ -57,7 +58,7 @@ int hdnode_public_ckd_cp(const ecdsa_curve *curve, const curve_point *parent, co int hdnode_public_ckd(HDNode *inout, uint32_t i); -int hdnode_public_ckd_address_optimized(const curve_point *pub, const uint8_t *chain_code, uint32_t i, uint32_t version, char *addr, int addrsize); +int hdnode_public_ckd_address_optimized(const curve_point *pub, const uint8_t *chain_code, uint32_t i, uint32_t version, char *addr, int addrsize, bool segwit); #if USE_BIP32_CACHE diff --git a/emscripten/post.js b/emscripten/post.js index e3a44bbca..d10dc3bfa 100644 --- a/emscripten/post.js +++ b/emscripten/post.js @@ -51,8 +51,8 @@ function serializeNode(node) { * @param {Number} version address version byte * @return {String} */ -function deriveAddress(index, version) { - _hdnode_public_ckd_address_optimized(_pubpoint, _chaincode, index, version, _address, ADDRESS_SIZE); +function deriveAddress(index, version, segwit) { + _hdnode_public_ckd_address_optimized(_pubpoint, _chaincode, index, version, _address, ADDRESS_SIZE, segwit); return Pointer_stringify(_address); } @@ -63,12 +63,12 @@ function deriveAddress(index, version) { * @param {Number} version address version byte * @return {Array} */ -function deriveAddressRange(node, firstIndex, lastIndex, version) { +function deriveAddressRange(node, firstIndex, lastIndex, version, segwit) { var addresses = []; serializeNode(node); var i; for (i = firstIndex; i <= lastIndex; i++) { - addresses.push(deriveAddress(i, version)); + addresses.push(deriveAddress(i, version, segwit)); } return addresses; } diff --git a/emscripten/test-correctness.js b/emscripten/test-correctness.js index 623e53b2b..0640adcb0 100644 --- a/emscripten/test-correctness.js +++ b/emscripten/test-correctness.js @@ -13,7 +13,10 @@ var nodeStruct = { public_key: node.keyPair.getPublicKeyBuffer() }; -var addresses = crypto.deriveAddressRange(nodeStruct, 0, 999, 0); +var addresses = crypto.deriveAddressRange(nodeStruct, 0, 999, 0, false); + +// for segwit: +// var addresses = crypto.deriveAddressRange(nodeStruct, 0, 999, 5, true); var fs = require('fs'); var loaded = fs.readFileSync('test-addresses.txt').toString().split("\n"); diff --git a/emscripten/trezor-crypto.js b/emscripten/trezor-crypto.js index 879b9a1a5..c625161f4 100644 --- a/emscripten/trezor-crypto.js +++ b/emscripten/trezor-crypto.js @@ -360,7 +360,7 @@ bc(c,C,w[d+8*n>>2],w[d+(8*n+4)>>2],void 0);if(0>u){f=-1;break a}h+=u}f=h}return var Z=(function(global,env,buffer) { "use asm";var a=new global.Int8Array(buffer);var b=new global.Int16Array(buffer);var c=new global.Int32Array(buffer);var d=new global.Uint8Array(buffer);var e=new global.Uint16Array(buffer);var f=new global.Uint32Array(buffer);var g=new global.Float32Array(buffer);var h=new global.Float64Array(buffer);var i=env.STACKTOP|0;var j=env.STACK_MAX|0;var k=env.DYNAMICTOP_PTR|0;var l=env.tempDoublePtr|0;var m=env.ABORT|0;var n=0;var o=0;var p=0;var q=0;var r=global.NaN,s=global.Infinity;var t=0,u=0,v=0,w=0,x=0.0,y=0,z=0,A=0,B=0.0;var C=0;var D=global.Math.floor;var E=global.Math.abs;var F=global.Math.sqrt;var G=global.Math.pow;var H=global.Math.cos;var I=global.Math.sin;var J=global.Math.tan;var K=global.Math.acos;var L=global.Math.asin;var M=global.Math.atan;var N=global.Math.atan2;var O=global.Math.exp;var P=global.Math.log;var Q=global.Math.ceil;var R=global.Math.imul;var S=global.Math.min;var T=global.Math.max;var U=global.Math.clz32;var V=env.abort;var W=env.assert;var X=env.enlargeMemory;var Y=env.getTotalMemory;var Z=env.abortOnCannotGrowMemory;var _=env.invoke_ii;var $=env.invoke_iiii;var aa=env.invoke_vi;var ba=env._pthread_cleanup_pop;var ca=env.___syscall221;var da=env.___syscall54;var ea=env.___lock;var fa=env._abort;var ga=env._pthread_cleanup_push;var ha=env.___syscall6;var ia=env._llvm_stacksave;var ja=env.___syscall140;var ka=env.___syscall5;var la=env._emscripten_memcpy_big;var ma=env._llvm_bswap_i64;var na=env.___unlock;var oa=env._llvm_stackrestore;var pa=env.___assert_fail;var qa=env.___syscall145;var ra=env.___syscall146;var sa=env.___setErrNo;var ta=0.0; // EMSCRIPTEN_START_FUNCS -function xa(a){a=a|0;var b=0;b=i;i=i+a|0;i=i+15&-16;return b|0}function ya(){return i|0}function za(a){a=a|0;i=a}function Aa(a,b){a=a|0;b=b|0;i=a;j=b}function Ba(a,b){a=a|0;b=b|0;if(!n){n=a;o=b}}function Ca(a){a=a|0;C=a}function Da(){return C|0}function Ea(b,c){b=b|0;c=c|0;a[b>>0]=c>>>24;a[b+1>>0]=c>>>16;a[b+2>>0]=c>>>8;a[b+3>>0]=c;return}function Fa(a,b){a=a|0;b=b|0;var e=0,f=0,g=0,h=0;e=0;f=0;do{h=a+(7-f<<2)|0;h=(d[h+1>>0]|0)<<16|(d[h>>0]|0)<<24|(d[h+2>>0]|0)<<8|(d[h+3>>0]|0);g=f<<1;c[b+(f<<2)>>2]=(h<>>(30-g|0);f=f+1|0}while((f|0)!=8);c[b+32>>2]=e;return}function Ga(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0;e=c[b+32>>2]<<16;f=0;while(1){g=c[b+(7-f<<2)>>2]|0;h=f<<1;i=g>>>(14-h|0)|e;e=d+(f<<2)|0;a[e>>0]=i>>>24;a[e+1>>0]=i>>>16;a[e+2>>0]=i>>>8;a[e+3>>0]=i;f=f+1|0;if((f|0)==8)break;else e=g<>2]=0;a=a+4|0}while((a|0)<(b|0));return}function Ia(a){a=a|0;return (c[a+32>>2]|(c[a+28>>2]|(c[a+24>>2]|(c[a+20>>2]|(c[a+16>>2]|(c[a+12>>2]|(c[a+8>>2]|(c[a+4>>2]|c[a>>2])))))))|0)==0|0}function Ja(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0;d=0;e=8;f=0;while(1){h=c[a+(e<<2)>>2]|0;g=c[b+(e<<2)>>2]|0;d=h>>>0>>0|d<<1;f=h>>>0>g>>>0|f<<1;if((e|0)<=0)break;else e=e+-1|0}return d>>>0>f>>>0|0}function Ka(a,b){a=a|0;b=b|0;var d=0,e=0;d=0;e=0;do{e=c[b+(d<<2)>>2]^c[a+(d<<2)>>2]|e;d=d+1|0}while((d|0)!=9);return (e|0)==0|0}function La(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0;g=0-b|0;h=b+-1|0;if((b|1|0)==1)f=0;else pa(38200,38223,270,38235);do{c[a+(f<<2)>>2]=c[e+(f<<2)>>2]&h|c[d+(f<<2)>>2]&g;f=f+1|0}while((f|0)!=9);return}function Ma(a){a=a|0;var b=0,d=0,e=0,f=0;b=8;d=c[a+32>>2]|0;do{e=b;b=b+-1|0;f=d;d=c[a+(b<<2)>>2]|0;c[a+(e<<2)>>2]=d>>>29&1|f<<1&1073741822}while((e|0)>1);c[a>>2]=c[a>>2]<<1&1073741822;return}function Na(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,i=0;d=c[a>>2]|0;f=0-(d&1)|0;d=((c[b>>2]&f)+d|0)>>>1;e=0;do{i=e;e=e+1|0;g=(c[b+(e<<2)>>2]&f)+(c[a+(e<<2)>>2]|0)|0;h=(g<<29&536870912)+d|0;c[a+(i<<2)>>2]=h&1073741823;d=(h>>>30)+(g>>>1)|0}while((e|0)!=8);c[a+32>>2]=d;return}function Oa(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0;e=b&255;b=0;do{f=a+(b<<2)|0;c[f>>2]=R(c[f>>2]|0,e)|0;b=b+1|0}while((b|0)!=9);Pa(a,d);return}function Pa(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0;g=(c[a+32>>2]|0)>>>16;i=c[a>>2]|0;h=pc(c[b>>2]|0,0,g|0,0)|0;d=C;e=kc(i|0,536870912,h|0,d|0)|0;f=C;d=kc(i|0,0,h|0,d|0)|0;c[a>>2]=d&1073741823;d=1;while(1){l=mc(e|0,f|0,30)|0;k=C;i=a+(d<<2)|0;j=c[i>>2]|0;f=pc(c[b+(d<<2)>>2]|0,0,g|0,0)|0;h=C;k=qc(l|0,k|0,-2147483648,536870911)|0;j=qc(k|0,C|0,j|0,0)|0;e=kc(j|0,C|0,f|0,h|0)|0;c[i>>2]=e&1073741823;d=d+1|0;if((d|0)==9)break;else f=C}return}function Qa(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0;h=i;i=i+48|0;g=h;d=0;e=8;f=0;while(1){k=c[a+(e<<2)>>2]|0;j=c[b+(e<<2)>>2]|0;d=k>>>0>>0|d<<1;f=k>>>0>j>>>0|f<<1;if((e|0)<=0)break;else e=e+-1|0}f=d>>>0>f>>>0;e=0;d=1;while(1){d=d+1073741823+(c[a+(e<<2)>>2]|0)-(c[b+(e<<2)>>2]|0)|0;c[g+(e<<2)>>2]=d&1073741823;e=e+1|0;if((e|0)==9)break;else d=d>>>30}La(a,f&1,a,g);i=h;return}function Ra(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0;f=0;e=1;while(1){e=e+1073741823+(c[a+(f<<2)>>2]|0)-(c[b+(f<<2)>>2]|0)|0;c[d+(f<<2)>>2]=e&1073741823;f=f+1|0;if((f|0)==9)break;else e=e>>>30}return}function Sa(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0,j=0;h=0;g=0;e=0;i=1;while(1){f=0;do{j=pc(c[b+(h-f<<2)>>2]|0,0,c[a+(f<<2)>>2]|0,0)|0;g=qc(j|0,C|0,g|0,e|0)|0;e=C;f=f+1|0}while((f|0)!=(i|0));c[d+(h<<2)>>2]=g&1073741823;g=mc(g|0,e|0,30)|0;e=C;h=h+1|0;if((h|0)==9){h=9;break}else i=i+1|0}while(1){f=h+-8|0;if((f|0)<9)do{j=pc(c[b+(h-f<<2)>>2]|0,0,c[a+(f<<2)>>2]|0,0)|0;g=qc(j|0,C|0,g|0,e|0)|0;e=C;f=f+1|0}while((f|0)!=9);c[d+(h<<2)>>2]=g&1073741823;g=mc(g|0,e|0,30)|0;h=h+1|0;if((h|0)==17)break;else e=C}c[d+68>>2]=g;return}function Ta(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0;l=a+(d+1<<2)|0;j=(c[l>>2]<<14)+((c[a+(d<<2)>>2]|0)>>>16)|0;k=d+-8|0;e=a+(k<<2)|0;f=c[e>>2]|0;g=pc(c[b>>2]|0,0,j|0,0)|0;h=C;if((j|0)<=-1)pa(38243,38223,417,38262);i=kc(f|0,536870912,g|0,h|0)|0;m=C;h=kc(f|0,0,g|0,h|0)|0;c[e>>2]=h&1073741823;h=mc(i|0,m|0,30)|0;m=C;i=a+(d+-7<<2)|0;f=qc(c[i>>2]|0,0,-2147483648,536870911)|0;e=1;g=C;d=m;do{m=pc(c[b+(e<<2)>>2]|0,0,j|0,0)|0;m=kc(f|0,g|0,m|0,C|0)|0;m=qc(m|0,C|0,h|0,d|0)|0;c[i>>2]=m&1073741823;e=e+1|0;h=mc(m|0,C|0,30)|0;d=C;i=a+(e+k<<2)|0;f=qc(c[i>>2]|0,0,-2147483648,536870911)|0;g=C}while((e|0)!=9);m=qc(f|0,g|0,h|0,d|0)|0;c[l>>2]=m&1073741823;return}function Ua(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0;e=16;while(1){Ta(b,d,e);if(c[b+(e+1<<2)>>2]|0){g=4;break}e=e+-1|0;if((e|0)<=7){f=0;break}}if((g|0)==4)pa(38286,38223,451,38302);do{c[a+(f<<2)>>2]=c[b+(f<<2)>>2];f=f+1|0}while((f|0)!=9);return}function Va(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0;g=i;i=i+80|0;e=g;f=e;h=f+72|0;do{c[f>>2]=0;f=f+4|0}while((f|0)<(h|0));Sa(a,b,e);Ua(b,e,d);i=g;return}function Wa(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0;n=i;i=i+144|0;k=n+72|0;l=n+36|0;m=n;c[l>>2]=1;h=l+4|0;c[h>>2]=0;c[h+4>>2]=0;c[h+8>>2]=0;c[h+12>>2]=0;c[h+16>>2]=0;c[h+20>>2]=0;c[h+24>>2]=0;c[h+28>>2]=0;h=m;d=b;j=h+36|0;do{c[h>>2]=c[d>>2];h=h+4|0;d=d+4|0}while((h|0)<(j|0));e=0;d=1;while(1){j=m+(e<<2)|0;d=(c[j>>2]|0)+d|0;c[j>>2]=d&1073741823;e=e+1|0;if((e|0)==9)break;else d=d>>>30}d=0;e=c[m>>2]|0;do{j=d;d=d+1|0;h=e;e=c[m+(d<<2)>>2]|0;c[m+(j<<2)>>2]=e<<29&536870912|h>>>1}while((d|0)!=8);e=m+32|0;c[e>>2]=(c[e>>2]|0)>>>1;d=0;f=c[m>>2]|0;do{j=d;d=d+1|0;h=f;f=c[m+(d<<2)>>2]|0;c[m+(j<<2)>>2]=f<<29&536870912|h>>>1}while((d|0)!=8);c[e>>2]=(c[e>>2]|0)>>>1;e=0;do{g=(e|0)==8;d=0;f=c[m+(e<<2)>>2]|0;do{if(g&(f|0)==0)break;if(f&1|0){h=k;j=h+72|0;do{c[h>>2]=0;h=h+4|0}while((h|0)<(j|0));Sa(a,l,k);Ua(l,k,b)}f=f>>>1;h=k;j=h+72|0;do{c[h>>2]=0;h=h+4|0}while((h|0)<(j|0));Sa(a,a,k);Ua(a,k,b);d=d+1|0}while(d>>>0<30);e=e+1|0}while((e|0)!=9);Qa(l,b);h=a;d=l;j=h+36|0;do{c[h>>2]=c[d>>2];h=h+4|0;d=d+4|0}while((h|0)<(j|0));i=n;return}function Xa(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0;v=i;i=i+112|0;d=v+72|0;u=v+32|0;t=v;Pa(a,b);Qa(a,b);e=c[b>>2]|0;f=0;while(1){r=f;f=f+1|0;g=c[b+(f<<2)>>2]|0;h=r<<1;p=g<<30-h|e;c[t+(r<<2)>>2]=p;c[d+(r<<2)>>2]=p;if((f|0)==8)break;else e=g>>>(h+2|0)}e=c[a>>2]|0;f=0;while(1){r=f;f=f+1|0;b=c[a+(f<<2)>>2]|0;g=r<<1;c[u+(r<<2)>>2]=b<<30-g|e;if((f|0)==8)break;else e=b>>>(g+2|0)}o=d+36|0;c[o>>2]=8;p=u+36|0;c[p>>2]=8;r=d+32|0;c[r>>2]=1;c[u+32>>2]=0;f=0;n=u;e=8;g=c[d>>2]|0;b=1;a:while(1){if(!(g&1)){q=7;break}if(!(b&1)){q=10;break}l=n+36|0;b=e;while(1){e=b+-1|0;if(c[n+(e<<2)>>2]|0)break;c[l>>2]=e;if((b|0)<1)break a;else b=e}e=c[n>>2]|0;if(!e){g=n+32|0;do{e=0;do{m=e;e=e+1|0;c[n+(m<<2)>>2]=c[n+(e<<2)>>2]}while((e|0)!=8);c[g>>2]=0;b=(c[l>>2]|0)+-1|0;c[l>>2]=b;f=f+32|0;e=c[n>>2]|0}while((e|0)==0)}k=0;while(1)if(!(e&1<0){e=e>>>k;if((b|0)>1){j=32-k|0;g=1;h=n;while(1){b=n+(g<<2)|0;c[h>>2]=c[b>>2]<>2]|0)>>>k;if((e|0)<(c[l>>2]|0)){g=e;e=h;h=b}else break}}else{g=0;h=e;b=n;e=1}c[b>>2]=h;if(!h)c[l>>2]=(c[l>>2]|0)+-1;else g=e;e=n+(g<<2)|0;b=c[e>>2]<>2]=(c[e>>2]|0)>>>h|b;b=c[e>>2]<>2]=b;m=k+f|0}else m=f;if(!(c[n>>2]&1)){q=32;break}if(c[n+32>>2]&1|0){q=34;break}f=c[o>>2]|0;e=f-(c[p>>2]|0)|0;if(!e){e=f;while(1){b=e+-1|0;if((e|0)<=0){q=38;break}e=c[d+(b<<2)>>2]|0;f=u+(b<<2)|0;if((e|0)==(c[f>>2]|0))e=b;else break}if((q|0)==38){q=0;if(!e){q=56;break}f=u+(b<<2)|0;e=c[d+(b<<2)>>2]|0}e=e>>>0>(c[f>>2]|0)>>>0?1:-1}n=(e|0)>0;l=n?u:d;n=n?d:u;k=l+36|0;h=c[k>>2]|0;if((h|0)>0){e=0;f=1;b=0;while(1){j=n+(e<<2)|0;w=c[j>>2]|0;g=c[l+(e<<2)>>2]|0;f=qc(f|0,b|0,-1,0)|0;f=qc(f|0,C|0,w|0,0)|0;g=kc(f|0,C|0,g|0,0)|0;f=C;c[j>>2]=g;e=e+1|0;if((e|0)<(h|0))b=0;else{b=e;g=0;break}}}else{b=0;f=1;g=0}j=n+36|0;e=c[j>>2]|0;if((b|0)<(e|0)){e=g;while(1){w=n+(b<<2)|0;g=c[w>>2]|0;e=qc(f|0,e|0,-1,0)|0;e=qc(e|0,C|0,g|0,0)|0;c[w>>2]=e;b=b+1|0;e=c[j>>2]|0;if((b|0)>=(e|0))break;else{f=C;e=0}}}if((e|0)>8){f=8;g=0;b=0}else{f=8;g=0;b=0;while(1){w=l+(f<<2)|0;j=c[n+(f<<2)>>2]|0;h=qc(c[w>>2]|0,0,g|0,b|0)|0;j=qc(h|0,C|0,j|0,0)|0;g=C;c[w>>2]=j;w=f;f=f+-1|0;if((w|0)<=(e|0))break;else b=0}h=c[k>>2]|0;b=0}if((f|0)>=(h|0))while(1){w=l+(f<<2)|0;j=qc(c[w>>2]|0,0,g|0,b|0)|0;c[w>>2]=j;if((f|0)>(c[k>>2]|0)){f=f+-1|0;g=C;b=0}else break}g=c[l>>2]|0;if(!(g&1)){q=51;break}b=c[l+32>>2]|0;if(!(b&1)){q=53;break}if(c[n>>2]&1|0){q=55;break}else f=m}if((q|0)==7)pa(38321,38223,646,38335);else if((q|0)==10)pa(38346,38223,647,38335);else if((q|0)==32)pa(38360,38223,699,38335);else if((q|0)==34)pa(38375,38223,700,38335);else if((q|0)==51)pa(38321,38223,757,38335);else if((q|0)==53)pa(38346,38223,758,38335);else if((q|0)==55)pa(38397,38223,759,38335);else if((q|0)==56){l=c[t>>2]|0;if(!(l&1))pa(38419,38223,786,38335);f=l+-1|0;e=l+-2|0;if(!f)k=e;else{do{f=R(f,f)|0;e=R(f+1|0,e)|0}while((f|0)!=0);k=e}b:do if((m|0)>31){j=d+4|0;e=m;while(1){w=c[r>>2]|0;b=R(w,k)|0;q=pc(l|0,0,b|0,0)|0;w=qc(q|0,C|0,w|0,0)|0;if(!((w|0)==0&0==0))break;f=0;g=C;h=0;while(1){w=f;f=f+1|0;o=c[d+(7-w<<2)>>2]|0;p=pc(c[t+(f<<2)>>2]|0,0,b|0,0)|0;q=C;o=qc(o|0,0,g|0,h|0)|0;q=qc(o|0,C|0,p|0,q|0)|0;g=C;c[d+(8-w<<2)>>2]=q;if((f|0)==7)break;else h=0}c[j>>2]=g;e=e+-32|0;if((e|0)<=31){s=e;break b}}pa(38429,38223,802,38335)}else s=m;while(0);if((s|0)>0){w=(1<>2]|0;h=(R(e,k)|0)&w;if((R(h,l)|0)+e&w|0)pa(38454,38223,821,38335);b=pc(h|0,0,l|0,0)|0;b=qc(b|0,C|0,e|0,0)|0;b=mc(b|0,C|0,s|0)|0;f=32-s|0;e=0;g=C;while(1){w=e;e=e+1|0;s=c[d+(7-w<<2)>>2]|0;r=pc(c[t+(e<<2)>>2]|0,0,h|0,0)|0;s=qc(r|0,C|0,s|0,0)|0;s=nc(s|0,C|0,f|0)|0;s=qc(s|0,C|0,b|0,g|0)|0;b=C;c[d+(8-w<<2)>>2]=s;if((e|0)==7)break;else g=0}c[d+4>>2]=b;e=0;f=0}else{e=0;f=0}do{s=c[d+(8-e<<2)>>2]|0;w=e<<1;c[a+(e<<2)>>2]=s<>>(30-w|0);e=e+1|0}while((e|0)!=8);c[a+32>>2]=f;c[t>>2]=0;c[t+4>>2]=0;c[t+8>>2]=0;c[t+12>>2]=0;c[t+16>>2]=0;c[t+20>>2]=0;c[t+24>>2]=0;c[t+28>>2]=0;e=d+40|0;do{c[d>>2]=0;d=d+4|0}while((d|0)<(e|0));d=u;e=d+40|0;do{c[d>>2]=0;d=d+4|0}while((d|0)<(e|0))}i=v;return}function Ya(a,b){a=a|0;b=b|0;var d=0,e=0,f=0;e=0;d=0;while(1){f=a+(e<<2)|0;d=(c[f>>2]|0)+d+(c[b+(e<<2)>>2]|0)|0;c[f>>2]=d&1073741823;e=e+1|0;if((e|0)==9)break;else d=d>>>30}return}function Za(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0;e=0;do{f=a+(e<<2)|0;c[f>>2]=(c[f>>2]|0)+(c[b+(e<<2)>>2]|0);e=e+1|0}while((e|0)!=9);Pa(a,d);return}function _a(a,b,d){a=a|0;b=b|0;d=d|0;var e=0;if((c[d>>2]|0)>>>0>>0)pa(38495,38223,883,38514);b=(c[a>>2]|0)-b|0;c[a>>2]=b;b=b+(c[d>>2]|0)|0;c[a>>2]=b&1073741823;e=1;do{b=(c[a+(e<<2)>>2]|0)+(b>>>30)+(c[d+(e<<2)>>2]|0)|0;c[a+(e<<2)>>2]=b&1073741823;e=e+1|0}while((e|0)!=9);return}function $a(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0;g=0;f=1;while(1){f=f+1073741823+(c[a+(g<<2)>>2]|0)+(c[e+(g<<2)>>2]<<1)-(c[b+(g<<2)>>2]|0)|0;c[d+(g<<2)>>2]=f&1073741823;g=g+1|0;if((g|0)==9)break;else f=f>>>30}return}function ab(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0;n=i;i=i+144|0;k=n+108|0;e=n+72|0;l=n+36|0;m=n;do if(!(bb(b)|0)){if(bb(d)|0){e=d;f=b;g=e+72|0;do{c[e>>2]=c[f>>2];e=e+4|0;f=f+4|0}while((e|0)<(g|0));break}if(cb(b,d)|0){db(a,d);break}if(!(eb(b,d)|0)){$a(d,b,e,a);Xa(e,a);h=d+36|0;j=b+36|0;$a(h,j,k,a);Va(e,k,a);e=l;f=k;g=e+36|0;do{c[e>>2]=c[f>>2];e=e+4|0;f=f+4|0}while((e|0)<(g|0));Va(l,l,a);e=m;f=b;g=e+36|0;do{c[e>>2]=c[f>>2];e=e+4|0;f=f+4|0}while((e|0)<(g|0));Za(m,d,a);$a(l,m,l,a);Pa(l,a);Qa(l,a);$a(b,l,m,a);Va(k,m,a);$a(m,j,m,a);Pa(m,a);Qa(m,a);e=d;f=l;g=e+36|0;do{c[e>>2]=c[f>>2];e=e+4|0;f=f+4|0}while((e|0)<(g|0));e=h;f=m;g=e+36|0;do{c[e>>2]=c[f>>2];e=e+4|0;f=f+4|0}while((e|0)<(g|0));break}else{Ha(d);Ha(d+36|0);break}}while(0);i=n;return}function bb(a){a=a|0;if(!(Ia(a)|0))a=0;else a=(Ia(a+36|0)|0)!=0;return a&1|0}function cb(a,b){a=a|0;b=b|0;if(!(Ka(a,b)|0))a=0;else a=(Ka(a+36|0,b+36|0)|0)!=0;return a&1|0}function db(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0,l=0;j=i;i=i+112|0;d=j+72|0;e=j+36|0;f=j;do if(!(bb(b)|0)){g=b+36|0;if(!(Ia(g)|0)){h=d;k=g;l=h+36|0;do{c[h>>2]=c[k>>2];h=h+4|0;k=k+4|0}while((h|0)<(l|0));Oa(d,2,a);Xa(d,a);h=e;k=b;l=h+36|0;do{c[h>>2]=c[k>>2];h=h+4|0;k=k+4|0}while((h|0)<(l|0));Va(e,e,a);Oa(e,3,a);_a(e,0-(c[a+180>>2]|0)|0,a);Va(e,d,a);h=e;k=d;l=h+36|0;do{c[h>>2]=c[k>>2];h=h+4|0;k=k+4|0}while((h|0)<(l|0));Va(e,e,a);h=f;k=b;l=h+36|0;do{c[h>>2]=c[k>>2];h=h+4|0;k=k+4|0}while((h|0)<(l|0));Ma(f);$a(e,f,e,a);Pa(e,a);Qa(e,a);$a(b,e,f,a);Va(d,f,a);$a(f,g,f,a);Pa(f,a);Qa(f,a);h=b;k=e;l=h+36|0;do{c[h>>2]=c[k>>2];h=h+4|0;k=k+4|0}while((h|0)<(l|0));h=g;k=f;l=h+36|0;do{c[h>>2]=c[k>>2];h=h+4|0;k=k+4|0}while((h|0)<(l|0));break}else{Ha(b);Ha(g);break}}while(0);i=j;return}function eb(a,b){a=a|0;b=b|0;var c=0;if((Ka(a,b)|0)!=0?(c=a+36|0,(Ia(c)|0)==0):0)a=(Ka(c,b+36|0)|0)==0&1;else a=0;return a|0}function fb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0,j=0;g=b+32|0;if((c[g>>2]|0)>>>0>=131072)pa(38522,38542,180,38553);h=a&1073741823;f=~a;a=c[b>>2]|0;e=(c[d>>2]<<1)+1073741824-a|0;c[b>>2]=h&e|a&f;a=0;do{a=a+1|0;i=b+(a<<2)|0;j=c[i>>2]|0;e=(e>>>30)+1073741823+(c[d+(a<<2)>>2]<<1)-j|0;c[i>>2]=h&e|j&f}while((a|0)!=8);if((c[g>>2]|0)>>>0<131072)return;else pa(38522,38542,188,38553)}function gb(a,b){a=a|0;b=b|0;var d=0,e=0,f=0;e=a+32|0;while(1){d=0;f=Kb()|0;do{c[a+(d<<2)>>2]=f&1073741823;d=d+1|0;f=Kb()|0}while((d|0)!=8);c[e>>2]=f&65535;if(Ia(a)|0)continue;if(Ja(a,b)|0)break}return}function hb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0;e=b+72|0;gb(e,d);g=b;h=e;i=g+36|0;do{c[g>>2]=c[h>>2];g=g+4|0;h=h+4|0}while((g|0)<(i|0));Va(e,b,d);f=b+36|0;g=f;h=b;i=g+36|0;do{c[g>>2]=c[h>>2];g=g+4|0;h=h+4|0}while((g|0)<(i|0));Va(e,f,d);Va(a,b,d);Va(a+36|0,f,d);return}function ib(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0;e=b+36|0;f=e;g=a+72|0;h=f+36|0;do{c[f>>2]=c[g>>2];f=f+4|0;g=g+4|0}while((f|0)<(h|0));Xa(e,d);f=b;g=e;h=f+36|0;do{c[f>>2]=c[g>>2];f=f+4|0;g=g+4|0}while((f|0)<(h|0));Va(b,b,d);Va(b,e,d);Va(a,b,d);Va(a+36|0,e,d);Qa(b,d);Qa(e,d);return}function jb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0;s=i;i=i+288|0;k=s+252|0;l=s+216|0;m=s+180|0;n=s+144|0;o=s+108|0;p=s+72|0;q=s+36|0;g=s;e=c[d+180>>2]|0;if((e+3|0)>>>0>=4)pa(38572,38542,247,38590);h=b+72|0;r=p;t=h;u=r+36|0;do{c[r>>2]=c[t>>2];r=r+4|0;t=t+4|0}while((r|0)<(u|0));Va(p,p,d);r=q;t=h;u=r+36|0;do{c[r>>2]=c[t>>2];r=r+4|0;t=t+4|0}while((r|0)<(u|0));Va(p,q,d);j=(e|0)!=0;if(j){e=0-e|0;r=g;t=p;u=r+36|0;do{c[r>>2]=c[t>>2];r=r+4|0;t=t+4|0}while((r|0)<(u|0));Va(g,g,d);Oa(g,e&255,d)}Va(a,p,d);r=l;t=p;u=r+36|0;do{c[r>>2]=c[t>>2];r=r+4|0;t=t+4|0}while((r|0)<(u|0));$a(l,b,l,d);Pa(l,d);Ya(p,b);f=Ka(l,d)|0;Va(a+36|0,q,d);e=b+36|0;$a(q,e,k,d);Ya(q,e);r=m;t=b;u=r+36|0;do{c[r>>2]=c[t>>2];r=r+4|0;t=t+4|0}while((r|0)<(u|0));Va(m,m,d);Oa(m,3,d);if(j)$a(m,g,m,d);La(k,f,m,k);La(l,f,q,l);r=o;t=l;u=r+36|0;do{c[r>>2]=c[t>>2];r=r+4|0;t=t+4|0}while((r|0)<(u|0));Va(o,o,d);r=n;t=l;u=r+36|0;do{c[r>>2]=c[t>>2];r=r+4|0;t=t+4|0}while((r|0)<(u|0));Va(o,n,d);Va(p,o,d);Va(q,n,d);Va(l,h,d);r=b;t=k;u=r+36|0;do{c[r>>2]=c[t>>2];r=r+4|0;t=t+4|0}while((r|0)<(u|0));Va(b,b,d);$a(b,o,b,d);Pa(b,d);$a(o,b,e,d);$a(e,b,e,d);Va(k,e,d);$a(e,n,e,d);Na(e,d);Pa(e,d);i=s;return}function kb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0;n=i;i=i+144|0;l=n+108|0;m=n;if(!(Ja(b,a+108|0)|0))pa(38609,38542,552,38658);j=c[b>>2]|0;g=(j&1)+-1|0;f=1;e=0;h=j;do{k=f+1073741823+h-(c[a+108+(e<<2)>>2]&g)|0;c[l+(e<<2)>>2]=k&1073741823;f=k>>>30;e=e+1|0;h=c[b+(e<<2)>>2]|0;j=h|j}while((e|0)!=8);k=l+32|0;c[k>>2]=f+65535+h-(c[a+140>>2]&g);e=c[l>>2]|0;if(!(e&1))pa(38638,38542,575,38658);if(!j){Ha(d);Ha(d+36|0)}else{hb(a+220+((((e>>>4&1)+15^e)>>>1&7)*72|0)|0,m,a);h=m+36|0;g=1;do{f=0;e=e>>>4;b=l;do{f=f+1|0;j=b;b=l+(f<<2)|0;c[j>>2]=c[b>>2]<<26&1006632960|e;e=(c[b>>2]|0)>>>4}while((f|0)!=8);c[k>>2]=e;e=c[l>>2]|0;b=e>>>4&1;j=b+15^e;fb((j&1)+-1|0,h,a);jb(a+220+(g*576|0)+((j>>>1&7)*72|0)|0,m,a);g=g+1|0}while((g|0)!=64);fb(b+-1|0,h,a);ib(m,d,a)}i=n;return}function lb(b,c,d){b=b|0;c=c|0;d=d|0;b=(b|0)==0?712:b;switch(a[c>>0]|0){case 4:{Fa(c+1|0,d);Fa(c+33|0,d+36|0);b=mb(b,d)|0;break}case 3:case 2:{Fa(c+1|0,d);nb(b,a[c>>0]|0,d,d+36|0);b=mb(b,d)|0;break}default:b=0}return b|0}function mb(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0;k=i;i=i+80|0;d=k+36|0;e=k;if(((bb(b)|0)==0?(Ja(b,a)|0)!=0:0)?(f=b+36|0,(Ja(f,a)|0)!=0):0){g=d;h=f;j=g+36|0;do{c[g>>2]=c[h>>2];g=g+4|0;h=h+4|0}while((g|0)<(j|0));g=e;h=b;j=g+36|0;do{c[g>>2]=c[h>>2];g=g+4|0;h=h+4|0}while((g|0)<(j|0));Va(f,d,a);Qa(d,a);Va(b,e,a);_a(e,0-(c[a+180>>2]|0)|0,a);Va(b,e,a);Za(e,a+184|0,a);Qa(e,a);a=(Ka(e,d)|0)!=0&1}else a=0;i=k;return a|0}function nb(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0;f=e;g=d;h=f+36|0;do{c[f>>2]=c[g>>2];f=f+4|0;g=g+4|0}while((f|0)<(h|0));Va(d,e,a);_a(e,0-(c[a+180>>2]|0)|0,a);Va(d,e,a);Ya(e,a+184|0);Wa(e,a);if((c[e>>2]^b&255)&1|0)Ra(a,e,e);return}function ob(b,c){b=b|0;c=c|0;var d=0,e=0;e=i;i=i+32|0;d=e;switch(a[b>>0]|0){case 4:{Eb(b,65,d);break}case 0:{Eb(b,1,d);break}default:Eb(b,33,d)}Ab(d,32,c);i=e;return}function pb(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0,f=0,g=0,h=0;e=i;i=i+48|0;g=e;f=Lb(b)|0;h=Lb(b)|0;Mb(b,g);ob(a,g+h|0);wb(g,f+20|0,c,d)|0;i=e;return}function qb(b,c,e){b=b|0;c=c|0;e=e|0;var f=0,g=0,h=0,j=0;j=i;i=i+128|0;h=j;f=h;g=f+128|0;do{a[f>>0]=0;f=f+1|0}while((f|0)<(g|0));if(e>>>0>128){Jb(c,e,h);c=0}else{tc(h|0,c|0,e|0)|0;c=0}do{g=h+c|0;f=d[g>>0]|0;a[b+c>>0]=f^92;a[g>>0]=f^54;c=c+1|0}while((c|0)!=128);b=b+128|0;Fb(b);Hb(b,h,128);i=j;return}function rb(a,b){a=a|0;b=b|0;var c=0,d=0,e=0;c=i;i=i+64|0;e=c;d=a+128|0;Ib(d,e);Fb(d);Hb(d,a,128);Hb(d,e,64);Ib(d,b);lc(a|0,0,336)|0;i=c;return}function sb(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;var f=0,g=0;f=i;i=i+336|0;g=f;qb(g,a,b);Hb(g+128|0,c,d);rb(g,e);i=f;return}function tb(b,d,e,f,g,h){b=b|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;var j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0;r=i;i=i+144|0;o=r+104|0;p=r+40|0;q=r;if((f|0)<0)f=0;else{a[o>>0]=c[d+36>>2]&1|2;n=o+1|0;Ga(d,n);Ea(o+33|0,f);f=b+108|0;j=p+32|0;while(1){sb(e,32,o,37,p);Fa(p,q);if(Ja(q,f)|0?(kb(b,q,g),ab(b,d,g),(bb(g)|0)==0):0)break;a[o>>0]=1;k=n;l=j;m=k+32|0;do{a[k>>0]=a[l>>0]|0;k=k+1|0;l=l+1|0}while((k|0)<(m|0))}if(h|0){k=h;l=j;m=k+32|0;do{a[k>>0]=a[l>>0]|0;k=k+1|0;l=l+1|0}while((k|0)<(m|0))}k=o;m=k+37|0;do{a[k>>0]=0;k=k+1|0}while((k|0)<(m|0));k=p;m=k+64|0;do{a[k>>0]=0;k=k+1|0}while((k|0)<(m|0));k=q;m=k+36|0;do{c[k>>2]=0;k=k+4|0}while((k|0)<(m|0));f=1}i=r;return f|0}function ub(b,d,e,f,g,h){b=b|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;var j=0,k=0,l=0;j=i;i=i+112|0;k=j+72|0;l=j;tb(712,b,d,e,l,0)|0;a[k>>0]=c[l+36>>2]&1|2;Ga(l,k+1|0);pb(k,f,g,h);i=j;return 1}function vb(b,e,f,g){b=b|0;e=e|0;f=f|0;g=g|0;var h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0;q=i;a:do if((g|0)>0){h=0;do{if(a[f+h>>0]|0)break a;h=h+1|0}while((h|0)<(g|0))}else h=0;while(0);o=(((g-h|0)*138|0)>>>0)/100|0;n=o+1|0;p=i;i=i+((1*n|0)+15&-16)|0;lc(p|0,0,n|0)|0;if((h|0)<(g|0)){j=o;m=h;do{k=a[f+m>>0]|0;if((o|0)>(j|0)|k<<24>>24!=0){k=k&255;l=o;while(1){r=p+l|0;k=(d[r>>0]<<8)+k|0;a[r>>0]=(k|0)%58|0;l=l+-1|0;if((l|0)>(j|0)|(k+57|0)>>>0>114)k=(k|0)/58|0;else{j=l;break}}}else j=o;m=m+1|0}while((m|0)!=(g|0));j=0}else j=0;while(1){if(a[p+j>>0]|0)break;k=j+1|0;if((j|0)<(o|0))j=k;else{j=k;break}}k=n+h-j|0;if((c[e>>2]|0)>>>0>k>>>0){if(!h)h=0;else lc(b|0,49,h|0)|0;if((j|0)<=(o|0))while(1){a[b+h>>0]=a[38674+(d[p+j>>0]|0)>>0]|0;h=h+1|0;if((j|0)<(o|0))j=j+1|0;else break}a[b+h>>0]=0;j=1}else{j=0;h=k}c[e>>2]=h+1;i=q;return j|0}function wb(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,j=0,k=0,l=0;g=i;i=i+16|0;f=g;if((b|0)>128)a=0;else{j=b+32|0;h=ia()|0;k=i;i=i+((1*j|0)+15&-16)|0;l=k+b|0;tc(k|0,a|0,b|0)|0;Eb(a,b,l);Eb(l,32,l);c[f>>2]=e;a=vb(d,f,k,b+4|0)|0;lc(k|0,0,j|0)|0;a=a?c[f>>2]|0:0;oa(h|0)}i=g;return a|0}function xb(a,b){a=a|0;b=b|0;var e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0;s=(d[b+1>>0]|0)<<8|(d[b>>0]|0)|(d[b+2>>0]|0)<<16|(d[b+3>>0]|0)<<24;D=(d[b+5>>0]|0)<<8|(d[b+4>>0]|0)|(d[b+6>>0]|0)<<16|(d[b+7>>0]|0)<<24;v=(d[b+9>>0]|0)<<8|(d[b+8>>0]|0)|(d[b+10>>0]|0)<<16|(d[b+11>>0]|0)<<24;f=(d[b+13>>0]|0)<<8|(d[b+12>>0]|0)|(d[b+14>>0]|0)<<16|(d[b+15>>0]|0)<<24;x=(d[b+17>>0]|0)<<8|(d[b+16>>0]|0)|(d[b+18>>0]|0)<<16|(d[b+19>>0]|0)<<24;t=(d[b+21>>0]|0)<<8|(d[b+20>>0]|0)|(d[b+22>>0]|0)<<16|(d[b+23>>0]|0)<<24;y=(d[b+25>>0]|0)<<8|(d[b+24>>0]|0)|(d[b+26>>0]|0)<<16|(d[b+27>>0]|0)<<24;z=(d[b+29>>0]|0)<<8|(d[b+28>>0]|0)|(d[b+30>>0]|0)<<16|(d[b+31>>0]|0)<<24;B=(d[b+33>>0]|0)<<8|(d[b+32>>0]|0)|(d[b+34>>0]|0)<<16|(d[b+35>>0]|0)<<24;i=(d[b+37>>0]|0)<<8|(d[b+36>>0]|0)|(d[b+38>>0]|0)<<16|(d[b+39>>0]|0)<<24;F=(d[b+41>>0]|0)<<8|(d[b+40>>0]|0)|(d[b+42>>0]|0)<<16|(d[b+43>>0]|0)<<24;l=(d[b+45>>0]|0)<<8|(d[b+44>>0]|0)|(d[b+46>>0]|0)<<16|(d[b+47>>0]|0)<<24;H=(d[b+49>>0]|0)<<8|(d[b+48>>0]|0)|(d[b+50>>0]|0)<<16|(d[b+51>>0]|0)<<24;u=(d[b+53>>0]|0)<<8|(d[b+52>>0]|0)|(d[b+54>>0]|0)<<16|(d[b+55>>0]|0)<<24;m=(d[b+57>>0]|0)<<8|(d[b+56>>0]|0)|(d[b+58>>0]|0)<<16|(d[b+59>>0]|0)<<24;w=(d[b+61>>0]|0)<<8|(d[b+60>>0]|0)|(d[b+62>>0]|0)<<16|(d[b+63>>0]|0)<<24;b=a+8|0;A=c[b>>2]|0;p=a+12|0;e=c[p>>2]|0;n=a+16|0;r=c[n>>2]|0;k=a+20|0;I=c[k>>2]|0;g=a+24|0;E=c[g>>2]|0;j=A+s+(r^e^I)|0;j=(j<<11|j>>>21)+E|0;C=r<<10|r>>>22;A=t+1352829926+A+((r|~I)^e)|0;A=(A<<8|A>>>24)+E|0;o=E+D+(C^e^j)|0;o=(o<<14|o>>>18)+I|0;G=e<<10|e>>>22;E=m+1352829926+E+(A^(e|~C))|0;E=(E<<9|E>>>23)+I|0;J=I+v+(j^G^o)|0;J=(J<<15|J>>>17)+C|0;j=j<<10|j>>>22;I=z+1352829926+I+(E^(A|~G))|0;I=(I<<9|I>>>23)+C|0;A=A<<10|A>>>22;a=C+f+(o^j^J)|0;a=(a<<12|a>>>20)+G|0;o=o<<10|o>>>22;C=s+1352829926+C+(I^(E|~A))|0;C=(C<<11|C>>>21)+G|0;E=E<<10|E>>>22;h=G+x+(J^o^a)|0;h=(h<<5|h>>>27)+j|0;J=J<<10|J>>>22;G=i+1352829926+G+(C^(I|~E))|0;G=(G<<13|G>>>19)+A|0;I=I<<10|I>>>22;j=j+t+(a^J^h)|0;j=(j<<8|j>>>24)+o|0;a=a<<10|a>>>22;A=v+1352829926+A+(G^(C|~I))|0;A=(A<<15|A>>>17)+E|0;C=C<<10|C>>>22;o=o+y+(h^a^j)|0;o=(o<<7|o>>>25)+J|0;h=h<<10|h>>>22;E=l+1352829926+E+(A^(G|~C))|0;E=(E<<15|E>>>17)+I|0;G=G<<10|G>>>22;J=J+z+(j^h^o)|0;J=(J<<9|J>>>23)+a|0;j=j<<10|j>>>22;I=x+1352829926+I+(E^(A|~G))|0;I=(I<<5|I>>>27)+C|0;A=A<<10|A>>>22;a=a+B+(o^j^J)|0;a=(a<<11|a>>>21)+h|0;o=o<<10|o>>>22;C=u+1352829926+C+(I^(E|~A))|0;C=(C<<7|C>>>25)+G|0;E=E<<10|E>>>22;h=h+i+(J^o^a)|0;h=(h<<13|h>>>19)+j|0;J=J<<10|J>>>22;G=y+1352829926+G+(C^(I|~E))|0;G=(G<<7|G>>>25)+A|0;I=I<<10|I>>>22;j=j+F+(a^J^h)|0;j=(j<<14|j>>>18)+o|0;a=a<<10|a>>>22;A=w+1352829926+A+(G^(C|~I))|0;A=(A<<8|A>>>24)+E|0;C=C<<10|C>>>22;o=o+l+(h^a^j)|0;o=(o<<15|o>>>17)+J|0;h=h<<10|h>>>22;E=B+1352829926+E+(A^(G|~C))|0;E=(E<<11|E>>>21)+I|0;G=G<<10|G>>>22;J=J+H+(j^h^o)|0;J=(J<<6|J>>>26)+a|0;j=j<<10|j>>>22;I=D+1352829926+I+(E^(A|~G))|0;I=(I<<14|I>>>18)+C|0;A=A<<10|A>>>22;a=a+u+(o^j^J)|0;a=(a<<7|a>>>25)+h|0;o=o<<10|o>>>22;C=F+1352829926+C+(I^(E|~A))|0;C=(C<<14|C>>>18)+G|0;E=E<<10|E>>>22;h=h+m+(J^o^a)|0;h=(h<<9|h>>>23)+j|0;J=J<<10|J>>>22;G=f+1352829926+G+(C^(I|~E))|0;G=(G<<12|G>>>20)+A|0;I=I<<10|I>>>22;j=j+w+(a^J^h)|0;j=(j<<8|j>>>24)+o|0;a=a<<10|a>>>22;A=H+1352829926+A+(G^(C|~I))|0;A=(A<<6|A>>>26)+E|0;C=C<<10|C>>>22;o=z+1518500249+o+(j&h|a&~j)|0;o=(o<<7|o>>>25)+J|0;h=h<<10|h>>>22;E=y+1548603684+E+(A&C|G&~C)|0;E=(E<<9|E>>>23)+I|0;G=G<<10|G>>>22;J=x+1518500249+J+(o&j|h&~o)|0;J=(J<<6|J>>>26)+a|0;j=j<<10|j>>>22;I=l+1548603684+I+(E&G|A&~G)|0;I=(I<<13|I>>>19)+C|0;A=A<<10|A>>>22;a=u+1518500249+a+(J&o|j&~J)|0;a=(a<<8|a>>>24)+h|0;o=o<<10|o>>>22;C=f+1548603684+C+(I&A|E&~A)|0;C=(C<<15|C>>>17)+G|0;E=E<<10|E>>>22;h=D+1518500249+h+(a&J|o&~a)|0;h=(h<<13|h>>>19)+j|0;J=J<<10|J>>>22;G=z+1548603684+G+(C&E|I&~E)|0;G=(G<<7|G>>>25)+A|0;I=I<<10|I>>>22;j=F+1518500249+j+(h&a|J&~h)|0;j=(j<<11|j>>>21)+o|0;a=a<<10|a>>>22;A=s+1548603684+A+(G&I|C&~I)|0;A=(A<<12|A>>>20)+E|0;C=C<<10|C>>>22;o=y+1518500249+o+(j&h|a&~j)|0;o=(o<<9|o>>>23)+J|0;h=h<<10|h>>>22;E=u+1548603684+E+(A&C|G&~C)|0;E=(E<<8|E>>>24)+I|0;G=G<<10|G>>>22;J=w+1518500249+J+(o&j|h&~o)|0;J=(J<<7|J>>>25)+a|0;j=j<<10|j>>>22;I=t+1548603684+I+(E&G|A&~G)|0;I=(I<<9|I>>>23)+C|0;A=A<<10|A>>>22;a=f+1518500249+a+(J&o|j&~J)|0;a=(a<<15|a>>>17)+h|0;o=o<<10|o>>>22;C=F+1548603684+C+(I&A|E&~A)|0;C=(C<<11|C>>>21)+G|0;E=E<<10|E>>>22;h=H+1518500249+h+(a&J|o&~a)|0;h=(h<<7|h>>>25)+j|0;J=J<<10|J>>>22;G=m+1548603684+G+(C&E|I&~E)|0;G=(G<<7|G>>>25)+A|0;I=I<<10|I>>>22;j=s+1518500249+j+(h&a|J&~h)|0;j=(j<<12|j>>>20)+o|0;a=a<<10|a>>>22;A=w+1548603684+A+(G&I|C&~I)|0;A=(A<<7|A>>>25)+E|0;C=C<<10|C>>>22;o=i+1518500249+o+(j&h|a&~j)|0;o=(o<<15|o>>>17)+J|0;h=h<<10|h>>>22;E=B+1548603684+E+(A&C|G&~C)|0;E=(E<<12|E>>>20)+I|0;G=G<<10|G>>>22;J=t+1518500249+J+(o&j|h&~o)|0;J=(J<<9|J>>>23)+a|0;j=j<<10|j>>>22;I=H+1548603684+I+(E&G|A&~G)|0;I=(I<<7|I>>>25)+C|0;A=A<<10|A>>>22;a=v+1518500249+a+(J&o|j&~J)|0;a=(a<<11|a>>>21)+h|0;o=o<<10|o>>>22;C=x+1548603684+C+(I&A|E&~A)|0;C=(C<<6|C>>>26)+G|0;E=E<<10|E>>>22;h=m+1518500249+h+(a&J|o&~a)|0;h=(h<<7|h>>>25)+j|0;J=J<<10|J>>>22;G=i+1548603684+G+(C&E|I&~E)|0;G=(G<<15|G>>>17)+A|0;I=I<<10|I>>>22;j=l+1518500249+j+(h&a|J&~h)|0;j=(j<<13|j>>>19)+o|0;a=a<<10|a>>>22;A=D+1548603684+A+(G&I|C&~I)|0;A=(A<<13|A>>>19)+E|0;C=C<<10|C>>>22;q=~j;o=B+1518500249+o+(j&h|a&q)|0;o=(o<<12|o>>>20)+J|0;h=h<<10|h>>>22;E=v+1548603684+E+(A&C|G&~C)|0;E=(E<<11|E>>>21)+I|0;G=G<<10|G>>>22;q=f+1859775393+J+((o|q)^h)|0;q=(q<<11|q>>>21)+a|0;j=j<<10|j>>>22;I=w+1836072691+I+((E|~A)^G)|0;I=(I<<9|I>>>23)+C|0;A=A<<10|A>>>22;a=F+1859775393+a+((q|~o)^j)|0;a=(a<<13|a>>>19)+h|0;o=o<<10|o>>>22;C=t+1836072691+C+((I|~E)^A)|0;C=(C<<7|C>>>25)+G|0;E=E<<10|E>>>22;h=m+1859775393+h+((a|~q)^o)|0;h=(h<<6|h>>>26)+j|0;q=q<<10|q>>>22;G=D+1836072691+G+((C|~I)^E)|0;G=(G<<15|G>>>17)+A|0;I=I<<10|I>>>22;j=x+1859775393+j+((h|~a)^q)|0;j=(j<<7|j>>>25)+o|0;a=a<<10|a>>>22;A=f+1836072691+A+((G|~C)^I)|0;A=(A<<11|A>>>21)+E|0;C=C<<10|C>>>22;o=i+1859775393+o+((j|~h)^a)|0;o=(o<<14|o>>>18)+q|0;h=h<<10|h>>>22;E=z+1836072691+E+((A|~G)^C)|0;E=(E<<8|E>>>24)+I|0;G=G<<10|G>>>22;q=w+1859775393+q+((o|~j)^h)|0;q=(q<<9|q>>>23)+a|0;j=j<<10|j>>>22;I=m+1836072691+I+((E|~A)^G)|0;I=(I<<6|I>>>26)+C|0;A=A<<10|A>>>22;a=B+1859775393+a+((q|~o)^j)|0;a=(a<<13|a>>>19)+h|0;o=o<<10|o>>>22;C=y+1836072691+C+((I|~E)^A)|0;C=(C<<6|C>>>26)+G|0;E=E<<10|E>>>22;h=D+1859775393+h+((a|~q)^o)|0;h=(h<<15|h>>>17)+j|0;q=q<<10|q>>>22;G=i+1836072691+G+((C|~I)^E)|0;G=(G<<14|G>>>18)+A|0;I=I<<10|I>>>22;j=v+1859775393+j+((h|~a)^q)|0;j=(j<<14|j>>>18)+o|0;a=a<<10|a>>>22;A=l+1836072691+A+((G|~C)^I)|0;A=(A<<12|A>>>20)+E|0;C=C<<10|C>>>22;o=z+1859775393+o+((j|~h)^a)|0;o=(o<<8|o>>>24)+q|0;h=h<<10|h>>>22;E=B+1836072691+E+((A|~G)^C)|0;E=(E<<13|E>>>19)+I|0;G=G<<10|G>>>22;q=s+1859775393+q+((o|~j)^h)|0;q=(q<<13|q>>>19)+a|0;j=j<<10|j>>>22;I=H+1836072691+I+((E|~A)^G)|0;I=(I<<5|I>>>27)+C|0;A=A<<10|A>>>22;a=y+1859775393+a+((q|~o)^j)|0;a=(a<<6|a>>>26)+h|0;o=o<<10|o>>>22;C=v+1836072691+C+((I|~E)^A)|0;C=(C<<14|C>>>18)+G|0;E=E<<10|E>>>22;h=u+1859775393+h+((a|~q)^o)|0;h=(h<<5|h>>>27)+j|0;q=q<<10|q>>>22;G=F+1836072691+G+((C|~I)^E)|0;G=(G<<13|G>>>19)+A|0;I=I<<10|I>>>22;j=l+1859775393+j+((h|~a)^q)|0;j=(j<<12|j>>>20)+o|0;a=a<<10|a>>>22;A=s+1836072691+A+((G|~C)^I)|0;A=(A<<13|A>>>19)+E|0;C=C<<10|C>>>22;o=t+1859775393+o+((j|~h)^a)|0;o=(o<<7|o>>>25)+q|0;h=h<<10|h>>>22;E=x+1836072691+E+((A|~G)^C)|0;E=(E<<7|E>>>25)+I|0;G=G<<10|G>>>22;q=H+1859775393+q+((o|~j)^h)|0;q=(q<<5|q>>>27)+a|0;j=j<<10|j>>>22;I=u+1836072691+I+((E|~A)^G)|0;I=(I<<5|I>>>27)+C|0;A=A<<10|A>>>22;a=D+-1894007588+a+(q&j|o&~j)|0;a=(a<<11|a>>>21)+h|0;o=o<<10|o>>>22;C=B+2053994217+C+(I&E|A&~I)|0;C=(C<<15|C>>>17)+G|0;E=E<<10|E>>>22;h=i+-1894007588+h+(a&o|q&~o)|0;h=(h<<12|h>>>20)+j|0;q=q<<10|q>>>22;G=y+2053994217+G+(C&I|E&~C)|0;G=(G<<5|G>>>27)+A|0;I=I<<10|I>>>22;j=l+-1894007588+j+(h&q|a&~q)|0;j=(j<<14|j>>>18)+o|0;a=a<<10|a>>>22;A=x+2053994217+A+(G&C|I&~G)|0;A=(A<<8|A>>>24)+E|0;C=C<<10|C>>>22;o=F+-1894007588+o+(j&a|h&~a)|0;o=(o<<15|o>>>17)+q|0;h=h<<10|h>>>22;E=D+2053994217+E+(A&G|C&~A)|0;E=(E<<11|E>>>21)+I|0;G=G<<10|G>>>22;q=s+-1894007588+q+(o&h|j&~h)|0;q=(q<<14|q>>>18)+a|0;j=j<<10|j>>>22;I=f+2053994217+I+(E&A|G&~E)|0;I=(I<<14|I>>>18)+C|0;A=A<<10|A>>>22;a=B+-1894007588+a+(q&j|o&~j)|0;a=(a<<15|a>>>17)+h|0;o=o<<10|o>>>22;C=l+2053994217+C+(I&E|A&~I)|0;C=(C<<14|C>>>18)+G|0;E=E<<10|E>>>22;h=H+-1894007588+h+(a&o|q&~o)|0;h=(h<<9|h>>>23)+j|0;q=q<<10|q>>>22;G=w+2053994217+G+(C&I|E&~C)|0;G=(G<<6|G>>>26)+A|0;I=I<<10|I>>>22;j=x+-1894007588+j+(h&q|a&~q)|0;j=(j<<8|j>>>24)+o|0;a=a<<10|a>>>22;A=s+2053994217+A+(G&C|I&~G)|0;A=(A<<14|A>>>18)+E|0;C=C<<10|C>>>22;o=u+-1894007588+o+(j&a|h&~a)|0;o=(o<<9|o>>>23)+q|0;h=h<<10|h>>>22;E=t+2053994217+E+(A&G|C&~A)|0;E=(E<<6|E>>>26)+I|0;G=G<<10|G>>>22;q=f+-1894007588+q+(o&h|j&~h)|0;q=(q<<14|q>>>18)+a|0;j=j<<10|j>>>22;I=H+2053994217+I+(E&A|G&~E)|0;I=(I<<9|I>>>23)+C|0;A=A<<10|A>>>22;a=z+-1894007588+a+(q&j|o&~j)|0;a=(a<<5|a>>>27)+h|0;o=o<<10|o>>>22;C=v+2053994217+C+(I&E|A&~I)|0;C=(C<<12|C>>>20)+G|0;E=E<<10|E>>>22;h=w+-1894007588+h+(a&o|q&~o)|0;h=(h<<6|h>>>26)+j|0;q=q<<10|q>>>22;G=u+2053994217+G+(C&I|E&~C)|0;G=(G<<9|G>>>23)+A|0;I=I<<10|I>>>22;j=m+-1894007588+j+(h&q|a&~q)|0;j=(j<<8|j>>>24)+o|0;a=a<<10|a>>>22;A=i+2053994217+A+(G&C|I&~G)|0;A=(A<<12|A>>>20)+E|0;C=C<<10|C>>>22;o=t+-1894007588+o+(j&a|h&~a)|0;o=(o<<6|o>>>26)+q|0;h=h<<10|h>>>22;E=z+2053994217+E+(A&G|C&~A)|0;E=(E<<5|E>>>27)+I|0;G=G<<10|G>>>22;q=y+-1894007588+q+(o&h|j&~h)|0;q=(q<<5|q>>>27)+a|0;j=j<<10|j>>>22;I=F+2053994217+I+(E&A|G&~E)|0;I=(I<<15|I>>>17)+C|0;A=A<<10|A>>>22;a=v+-1894007588+a+(q&j|o&~j)|0;a=(a<<12|a>>>20)+h|0;o=o<<10|o>>>22;C=m+2053994217+C+(I&E|A&~I)|0;C=(C<<8|C>>>24)+G|0;E=E<<10|E>>>22;h=x+-1454113458+h+(a^(q|~o))|0;h=(h<<9|h>>>23)+j|0;q=q<<10|q>>>22;G=G+H+(I^E^C)|0;G=(G<<8|G>>>24)+A|0;I=I<<10|I>>>22;j=s+-1454113458+j+(h^(a|~q))|0;j=(j<<15|j>>>17)+o|0;a=a<<10|a>>>22;A=A+w+(C^I^G)|0;A=(A<<5|A>>>27)+E|0;C=C<<10|C>>>22;o=t+-1454113458+o+(j^(h|~a))|0;o=(o<<5|o>>>27)+q|0;h=h<<10|h>>>22;E=E+F+(G^C^A)|0;E=(E<<12|E>>>20)+I|0;G=G<<10|G>>>22;q=i+-1454113458+q+(o^(j|~h))|0;q=(q<<11|q>>>21)+a|0;j=j<<10|j>>>22;x=I+x+(A^G^E)|0;x=(x<<9|x>>>23)+C|0;A=A<<10|A>>>22;a=z+-1454113458+a+(q^(o|~j))|0;a=(a<<6|a>>>26)+h|0;o=o<<10|o>>>22;C=C+D+(E^A^x)|0;C=(C<<12|C>>>20)+G|0;E=E<<10|E>>>22;h=H+-1454113458+h+(a^(q|~o))|0;h=(h<<8|h>>>24)+j|0;q=q<<10|q>>>22;t=G+t+(x^E^C)|0;t=(t<<5|t>>>27)+A|0;x=x<<10|x>>>22;j=v+-1454113458+j+(h^(a|~q))|0;j=(j<<13|j>>>19)+o|0;a=a<<10|a>>>22;A=A+B+(C^x^t)|0;A=(A<<14|A>>>18)+E|0;C=C<<10|C>>>22;o=F+-1454113458+o+(j^(h|~a))|0;o=(o<<12|o>>>20)+q|0;h=h<<10|h>>>22;z=E+z+(t^C^A)|0;z=(z<<6|z>>>26)+x|0;t=t<<10|t>>>22;q=m+-1454113458+q+(o^(j|~h))|0;q=(q<<5|q>>>27)+a|0;j=j<<10|j>>>22;x=x+y+(A^t^z)|0;x=(x<<8|x>>>24)+C|0;A=A<<10|A>>>22;a=D+-1454113458+a+(q^(o|~j))|0;a=(a<<12|a>>>20)+h|0;o=o<<10|o>>>22;v=C+v+(z^A^x)|0;v=(v<<13|v>>>19)+t|0;z=z<<10|z>>>22;h=f+-1454113458+h+(a^(q|~o))|0;h=(h<<13|h>>>19)+j|0;q=q<<10|q>>>22;t=t+u+(x^z^v)|0;t=(t<<6|t>>>26)+A|0;x=x<<10|x>>>22;j=B+-1454113458+j+(h^(a|~q))|0;j=(j<<14|j>>>18)+o|0;a=a<<10|a>>>22;m=A+m+(v^x^t)|0;m=(m<<5|m>>>27)+z|0;v=v<<10|v>>>22;o=l+-1454113458+o+(j^(h|~a))|0;o=(o<<11|o>>>21)+q|0;h=h<<10|h>>>22;s=z+s+(t^v^m)|0;s=(s<<15|s>>>17)+x|0;t=t<<10|t>>>22;q=y+-1454113458+q+(o^(j|~h))|0;q=(q<<8|q>>>24)+a|0;j=j<<10|j>>>22;f=x+f+(m^t^s)|0;f=(f<<13|f>>>19)+v|0;m=m<<10|m>>>22;a=w+-1454113458+a+(q^(o|~j))|0;a=(a<<5|a>>>27)+h|0;o=o<<10|o>>>22;i=v+i+(s^m^f)|0;i=(i<<11|i>>>21)+t|0;s=s<<10|s>>>22;h=u+-1454113458+h+(a^(q|~o))|0;l=t+l+(f^s^i)|0;c[p>>2]=s+r+(q<<10|q>>>22);c[n>>2]=m+(c[k>>2]|0)+o;c[k>>2]=j+(c[g>>2]|0)+m+(l<<11|l>>>21);c[g>>2]=j+(c[b>>2]|0)+i+(h<<6|h>>>26);c[b>>2]=(f<<10|f>>>22)+e+a;return}function yb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0;if(d|0){h=c[a>>2]|0;e=h&63;f=64-e|0;h=h+d|0;c[a>>2]=h;if(h>>>0>>0){h=a+4|0;c[h>>2]=(c[h>>2]|0)+1}if(!((e|0)==0|f>>>0>d>>>0)){tc(a+28+e|0,b|0,f|0)|0;xb(a,a+28|0);e=0;b=b+f|0;d=d-f|0}if(d>>>0>63){g=d+-64|0;h=g&-64;f=b+(h+64)|0;while(1){xb(a,b);d=d+-64|0;if(d>>>0<=63)break;else b=b+64|0}b=f;d=g-h|0}if(d|0)tc(a+28+e|0,b|0,d|0)|0}return}function zb(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0;e=i;i=i+16|0;f=e;g=c[b>>2]|0;h=c[b+4>>2]|0;a[f>>0]=g<<3;a[f+1>>0]=g>>>5;a[f+2>>0]=g>>>13;a[f+3>>0]=g>>>21;a[f+4>>0]=h<<3|g>>>29;a[f+5>>0]=h>>>5;a[f+6>>0]=h>>>13;a[f+7>>0]=h>>>21;g=g&63;yb(b,38733,(g>>>0<56?56:120)-g|0);yb(b,f,8);f=b+8|0;a[d>>0]=c[f>>2];a[d+1>>0]=(c[f>>2]|0)>>>8;a[d+2>>0]=(c[f>>2]|0)>>>16;a[d+3>>0]=(c[f>>2]|0)>>>24;f=b+12|0;a[d+4>>0]=c[f>>2];a[d+5>>0]=(c[f>>2]|0)>>>8;a[d+6>>0]=(c[f>>2]|0)>>>16;a[d+7>>0]=(c[f>>2]|0)>>>24;f=b+16|0;a[d+8>>0]=c[f>>2];a[d+9>>0]=(c[f>>2]|0)>>>8;a[d+10>>0]=(c[f>>2]|0)>>>16;a[d+11>>0]=(c[f>>2]|0)>>>24;f=b+20|0;a[d+12>>0]=c[f>>2];a[d+13>>0]=(c[f>>2]|0)>>>8;a[d+14>>0]=(c[f>>2]|0)>>>16;a[d+15>>0]=(c[f>>2]|0)>>>24;b=b+24|0;a[d+16>>0]=c[b>>2];a[d+17>>0]=(c[b>>2]|0)>>>8;a[d+18>>0]=(c[b>>2]|0)>>>16;a[d+19>>0]=(c[b>>2]|0)>>>24;i=e;return}function Ab(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0;h=i;i=i+96|0;e=h;f=e+8|0;g=e;j=g+92|0;do{c[g>>2]=0;g=g+4|0}while((g|0)<(j|0));c[f>>2]=1732584193;c[e+12>>2]=-271733879;c[e+16>>2]=-1732584194;c[e+20>>2]=271733878;c[e+24>>2]=-1009589776;yb(e,a,b);zb(e,d);i=h;return}function Bb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0;y=i;i=i+64|0;t=y;u=c[a>>2]|0;v=a+4|0;w=a+8|0;x=a+12|0;q=a+16|0;r=a+20|0;s=a+24|0;p=a+28|0;g=0;o=u;a=c[p>>2]|0;h=c[s>>2]|0;j=c[r>>2]|0;k=c[q>>2]|0;e=c[x>>2]|0;l=c[w>>2]|0;f=c[v>>2]|0;while(1){n=((k>>>6|k<<26)^(k>>>11|k<<21)^(k>>>25|k<<7))+a+(h&~k^j&k)+(c[37828+(g<<2)>>2]|0)|0;a=c[b>>2]|0;c[t+(g<<2)>>2]=a;a=n+a|0;e=a+e|0;a=((o>>>2|o<<30)^(o>>>13|o<<19)^(o>>>22|o<<10))+(o&(l^f)^l&f)+a|0;g=g+1|0;if((g|0)==16){n=16;m=a;g=e;a=l;e=o;break}else{C=o;B=f;A=l;z=k;m=j;n=h;b=b+4|0;o=a;k=e;f=C;l=B;e=A;j=z;h=m;a=n}}while(1){A=n;n=n+1|0;z=c[t+((n&15)<<2)>>2]|0;b=c[t+((A+14&15)<<2)>>2]|0;C=((g>>>6|g<<26)^(g>>>11|g<<21)^(g>>>25|g<<7))+h+(j&~g^k&g)+(c[37828+(A<<2)>>2]|0)|0;B=t+((A&15)<<2)|0;b=((z>>>18|z<<14)^z>>>3^(z>>>7|z<<25))+(c[t+((A+9&15)<<2)>>2]|0)+(c[B>>2]|0)+((b>>>19|b<<13)^b>>>10^(b>>>17|b<<15))|0;c[B>>2]=b;b=C+b|0;a=b+a|0;b=((m>>>2|m<<30)^(m>>>13|m<<19)^(m>>>22|m<<10))+(m&(f^e)^f&e)+b|0;if((n|0)==64)break;else{o=m;z=e;A=f;B=g;C=k;h=j;m=b;g=a;e=o;f=z;a=A;k=B;j=C}}c[d>>2]=u+b;c[d+4>>2]=(c[v>>2]|0)+m;c[d+8>>2]=(c[w>>2]|0)+e;c[d+12>>2]=(c[x>>2]|0)+f;c[d+16>>2]=(c[q>>2]|0)+a;c[d+20>>2]=(c[r>>2]|0)+g;c[d+24>>2]=(c[s>>2]|0)+k;c[d+28>>2]=(c[p>>2]|0)+j;i=y;return}function Cb(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0;do if(e|0){n=b+32|0;g=n;h=c[g>>2]|0;g=c[g+4>>2]|0;f=mc(h|0,g|0,3)|0;f=f&63;if(f){i=64-f|0;j=b+40|0;f=j+f|0;if(i>>>0>e>>>0){tc(f|0,d|0,e|0)|0;b=qc(h|0,g|0,e<<3|0,0)|0;c[n>>2]=b;c[n+4>>2]=C;break}tc(f|0,d|0,i|0)|0;m=qc(h|0,g|0,i<<3|0,0)|0;f=n;c[f>>2]=m;c[f+4>>2]=C;e=e-i|0;f=0;do{m=b+40+(f<<2)|0;c[m>>2]=sc(c[m>>2]|0)|0;f=f+1|0}while((f|0)!=16);Bb(b,j,b);d=d+i|0}if(e>>>0>63){j=b+40|0;l=e+-64|0;m=l&-64;k=m+64|0;i=d;while(1){f=j;g=i;h=f+64|0;do{a[f>>0]=a[g>>0]|0;f=f+1|0;g=g+1|0}while((f|0)<(h|0));f=0;do{h=b+40+(f<<2)|0;c[h>>2]=sc(c[h>>2]|0)|0;f=f+1|0}while((f|0)!=16);Bb(b,j,b);g=n;g=qc(c[g>>2]|0,c[g+4>>2]|0,512,0)|0;h=n;c[h>>2]=g;c[h+4>>2]=C;e=e+-64|0;if(e>>>0<=63)break;else i=i+64|0}d=d+k|0;e=l-m|0}if(e|0){tc(b+40|0,d|0,e|0)|0;b=n;b=qc(c[b>>2]|0,c[b+4>>2]|0,e<<3|0,0)|0;c[n>>2]=b;c[n+4>>2]=C}}while(0);return}function Db(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0;if(d){h=b+32|0;f=h;f=mc(c[f>>2]|0,c[f+4>>2]|0,3)|0;f=f&63;e=f+1|0;g=b+40|0;a[g+f>>0]=-128;if(e>>>0>56){lc(g+e|0,0,f^63|0)|0;e=0;do{f=b+40+(e<<2)|0;c[f>>2]=sc(c[f>>2]|0)|0;e=e+1|0}while((e|0)!=16);Bb(b,g,b);e=0}lc(g+e|0,0,56-e|0)|0;e=0;do{f=b+40+(e<<2)|0;c[f>>2]=sc(c[f>>2]|0)|0;e=e+1|0}while((e|0)!=14);e=c[h>>2]|0;c[b+96>>2]=c[h+4>>2];c[b+100>>2]=e;Bb(b,g,b);e=0;do{h=b+(e<<2)|0;c[h>>2]=sc(c[h>>2]|0)|0;e=e+1|0}while((e|0)!=8);e=d;f=b;g=e+32|0;do{a[e>>0]=a[f>>0]|0;e=e+1|0;f=f+1|0}while((e|0)<(g|0))}e=b;g=e+104|0;do{c[e>>2]=0;e=e+4|0}while((e|0)<(g|0));return}function Eb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0;g=i;i=i+112|0;e=g;c[e>>2]=c[9449];c[e+4>>2]=c[9450];c[e+8>>2]=c[9451];c[e+12>>2]=c[9452];c[e+16>>2]=c[9453];c[e+20>>2]=c[9454];c[e+24>>2]=c[9455];c[e+28>>2]=c[9456];f=e+32|0;h=f+72|0;do{c[f>>2]=0;f=f+4|0}while((f|0)<(h|0));Cb(e,a,b);Db(e,d);i=g;return}function Fb(a){a=a|0;var b=0,d=0,e=0;if(a|0){b=a;d=8;e=b+64|0;do{c[b>>2]=c[d>>2];b=b+4|0;d=d+4|0}while((b|0)<(e|0));lc(a+64|0,0,144)|0}return}function Gb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0,X=0,Y=0,Z=0,_=0;L=i;i=i+128|0;F=L;K=a;J=c[K>>2]|0;K=c[K+4>>2]|0;B=a+8|0;w=B;D=a+16|0;e=D;E=a+24|0;f=E;G=a+32|0;p=G;H=a+40|0;q=H;I=a+48|0;m=I;A=a+56|0;h=A;j=0;l=J;u=K;t=c[w>>2]|0;z=c[e>>2]|0;w=c[w+4>>2]|0;a=c[e+4>>2]|0;e=c[f>>2]|0;f=c[f+4>>2]|0;o=c[p>>2]|0;p=c[p+4>>2]|0;g=c[h>>2]|0;h=c[h+4>>2]|0;r=c[q>>2]|0;q=c[q+4>>2]|0;k=c[m>>2]|0;m=c[m+4>>2]|0;while(1){v=mc(o|0,p|0,14)|0;N=C;x=nc(o|0,p|0,50)|0;N=N|C;y=mc(o|0,p|0,18)|0;O=C;M=nc(o|0,p|0,46)|0;O=N^(O|C);N=mc(o|0,p|0,41)|0;n=C;s=nc(o|0,p|0,23)|0;n=qc((v|x)^(y|M)^(N|s)|0,O^(n|C)|0,g|0,h|0)|0;n=qc(n|0,C|0,k&~o^r&o|0,m&~p^q&p|0)|0;O=72+(j<<3)|0;O=qc(n|0,C|0,c[O>>2]|0,c[O+4>>2]|0)|0;n=b;g=c[n>>2]|0;n=c[n+4>>2]|0;s=F+(j<<3)|0;c[s>>2]=g;c[s+4>>2]=n;n=qc(O|0,C|0,g|0,n|0)|0;g=C;O=mc(l|0,u|0,28)|0;s=C;N=nc(l|0,u|0,36)|0;s=s|C;M=mc(l|0,u|0,34)|0;y=C;h=nc(l|0,u|0,30)|0;y=s^(y|C);s=mc(l|0,u|0,39)|0;x=C;v=nc(l|0,u|0,25)|0;x=qc((O|N)^(M|h)^(s|v)|0,y^(x|C)|0,l&(z^t)^z&t|0,u&(a^w)^a&w|0)|0;y=C;e=qc(n|0,g|0,e|0,f|0)|0;f=C;g=qc(x|0,y|0,n|0,g|0)|0;n=C;j=j+1|0;if((j|0)==16){y=16;x=e;v=f;s=p;p=g;j=t;h=u;g=w;b=z;break}else{x=p;y=o;h=m;M=k;N=u;O=l;b=b+8|0;l=g;u=n;o=e;p=f;m=q;k=r;q=x;r=y;g=M;f=a;e=z;a=w;w=N;z=t;t=O}}while(1){t=y;y=y+1|0;T=F+((y&15)<<3)|0;W=c[T>>2]|0;T=c[T+4>>2]|0;S=mc(W|0,T|0,1)|0;Q=C;R=nc(W|0,T|0,63)|0;Q=Q|C;V=mc(W|0,T|0,8)|0;O=C;U=nc(W|0,T|0,56)|0;O=O|C;T=mc(W|0,T|0,7)|0;Q=O^C^Q;O=F+((t+14&15)<<3)|0;W=c[O>>2]|0;O=c[O+4>>2]|0;u=mc(W|0,O|0,19)|0;e=C;f=nc(W|0,O|0,45)|0;e=e|C;N=mc(W|0,O|0,61)|0;_=C;w=nc(W|0,O|0,3)|0;_=_|C;O=mc(W|0,O|0,6)|0;e=_^C^e;_=mc(x|0,v|0,14)|0;W=C;Z=nc(x|0,v|0,50)|0;W=W|C;Y=mc(x|0,v|0,18)|0;P=C;X=nc(x|0,v|0,46)|0;P=W^(P|C);W=mc(x|0,v|0,41)|0;z=C;M=nc(x|0,v|0,23)|0;m=qc((_|Z)^(Y|X)^(W|M)|0,P^(z|C)|0,k|0,m|0)|0;m=qc(m|0,C|0,r&~x^o&x|0,q&~v^s&v|0)|0;z=72+(t<<3)|0;z=qc(m|0,C|0,c[z>>2]|0,c[z+4>>2]|0)|0;m=C;P=F+((t+9&15)<<3)|0;t=F+((t&15)<<3)|0;M=t;k=c[M>>2]|0;M=c[M+4>>2]|0;P=qc((V|U)^T^(S|R)|0,Q|0,c[P>>2]|0,c[P+4>>2]|0)|0;M=qc(P|0,C|0,k|0,M|0)|0;e=qc(M|0,C|0,(N|w)^O^(u|f)|0,e|0)|0;f=C;c[t>>2]=e;c[t+4>>2]=f;f=qc(z|0,m|0,e|0,f|0)|0;e=C;m=mc(p|0,n|0,28)|0;z=C;t=nc(p|0,n|0,36)|0;z=z|C;u=mc(p|0,n|0,34)|0;O=C;w=nc(p|0,n|0,30)|0;O=z^(O|C);z=mc(p|0,n|0,39)|0;N=C;M=nc(p|0,n|0,25)|0;N=qc((m|t)^(u|w)^(z|M)|0,O^(N|C)|0,p&(j^l)^j&l|0,n&(g^h)^g&h|0)|0;O=C;a=qc(f|0,e|0,b|0,a|0)|0;b=C;e=qc(N|0,O|0,f|0,e|0)|0;f=C;if((y|0)==80)break;else{X=n;Y=p;Z=v;_=x;m=q;k=r;x=a;v=b;p=e;n=f;a=g;b=j;g=h;h=X;j=l;l=Y;q=s;r=o;s=Z;o=_}}_=qc(J|0,K|0,e|0,f|0)|0;Z=d;c[Z>>2]=_;c[Z+4>>2]=C;Z=B;Z=qc(c[Z>>2]|0,c[Z+4>>2]|0,p|0,n|0)|0;_=d+8|0;c[_>>2]=Z;c[_+4>>2]=C;_=D;_=qc(c[_>>2]|0,c[_+4>>2]|0,l|0,h|0)|0;Z=d+16|0;c[Z>>2]=_;c[Z+4>>2]=C;Z=E;Z=qc(c[Z>>2]|0,c[Z+4>>2]|0,j|0,g|0)|0;_=d+24|0;c[_>>2]=Z;c[_+4>>2]=C;_=G;_=qc(c[_>>2]|0,c[_+4>>2]|0,a|0,b|0)|0;Z=d+32|0;c[Z>>2]=_;c[Z+4>>2]=C;Z=H;Z=qc(c[Z>>2]|0,c[Z+4>>2]|0,x|0,v|0)|0;_=d+40|0;c[_>>2]=Z;c[_+4>>2]=C;_=I;_=qc(c[_>>2]|0,c[_+4>>2]|0,o|0,s|0)|0;Z=d+48|0;c[Z>>2]=_;c[Z+4>>2]=C;Z=A;Z=qc(c[Z>>2]|0,c[Z+4>>2]|0,r|0,q|0)|0;_=d+56|0;c[_>>2]=Z;c[_+4>>2]=C;i=L;return}function Hb(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0;do if(e|0){o=b+64|0;g=o;h=c[g>>2]|0;g=c[g+4>>2]|0;f=mc(h|0,g|0,3)|0;f=f&127;if(f){i=128-f|0;j=b+80|0;f=j+f|0;if(i>>>0>e>>>0){tc(f|0,d|0,e|0)|0;n=e<<3;m=qc(h|0,g|0,n|0,0)|0;l=C;c[o>>2]=m;c[o+4>>2]=l;if(!(l>>>0<0|(l|0)==0&m>>>0>>0))break;o=b+72|0;b=o;b=qc(c[b>>2]|0,c[b+4>>2]|0,1,0)|0;c[o>>2]=b;c[o+4>>2]=C;break}tc(f|0,d|0,i|0)|0;n=i<<3;m=qc(h|0,g|0,n|0,0)|0;l=C;k=o;c[k>>2]=m;c[k+4>>2]=l;if(l>>>0<0|(l|0)==0&m>>>0>>0){n=b+72|0;m=n;m=qc(c[m>>2]|0,c[m+4>>2]|0,1,0)|0;c[n>>2]=m;c[n+4>>2]=C}e=e-i|0;f=0;do{n=b+80+(f<<3)|0;m=n;m=ma(c[m>>2]|0,c[m+4>>2]|0)|0;c[n>>2]=m;c[n+4>>2]=C;f=f+1|0}while((f|0)!=16);Gb(b,j,b);d=d+i|0}if(e>>>0>127){j=b+80|0;k=b+72|0;m=e+-128|0;n=m&-128;l=n+128|0;i=d;while(1){f=j;g=i;h=f+128|0;do{a[f>>0]=a[g>>0]|0;f=f+1|0;g=g+1|0}while((f|0)<(h|0));f=0;do{h=b+80+(f<<3)|0;g=h;g=ma(c[g>>2]|0,c[g+4>>2]|0)|0;c[h>>2]=g;c[h+4>>2]=C;f=f+1|0}while((f|0)!=16);Gb(b,j,b);g=o;h=c[g>>2]|0;g=c[g+4>>2]|0;p=qc(h|0,g|0,1024,0)|0;f=o;c[f>>2]=p;c[f+4>>2]=C;if(g>>>0>4294967295|(g|0)==-1&h>>>0>4294966271){h=k;h=qc(c[h>>2]|0,c[h+4>>2]|0,1,0)|0;p=k;c[p>>2]=h;c[p+4>>2]=C}e=e+-128|0;if(e>>>0<=127)break;else i=i+128|0}d=d+l|0;e=m-n|0}if(e|0?(tc(b+80|0,d|0,e|0)|0,p=e<<3,n=o,n=qc(c[n>>2]|0,c[n+4>>2]|0,p|0,0)|0,m=C,o,c[o>>2]=n,c[o+4>>2]=m,m>>>0<0|(m|0)==0&n>>>0

>>0):0){p=b+72|0;o=p;o=qc(c[o>>2]|0,c[o+4>>2]|0,1,0)|0;c[p>>2]=o;c[p+4>>2]=C}}while(0);return}function Ib(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0;if(d){h=b+64|0;f=h;f=mc(c[f>>2]|0,c[f+4>>2]|0,3)|0;f=f&127;e=f+1|0;g=b+80|0;a[g+f>>0]=-128;if(e>>>0>112){lc(g+e|0,0,f^127|0)|0;e=0;do{f=b+80+(e<<3)|0;i=f;i=ma(c[i>>2]|0,c[i+4>>2]|0)|0;c[f>>2]=i;c[f+4>>2]=C;e=e+1|0}while((e|0)!=16);Gb(b,g,b);e=0}lc(g+e|0,0,112-e|0)|0;e=0;do{i=b+80+(e<<3)|0;f=i;f=ma(c[f>>2]|0,c[f+4>>2]|0)|0;c[i>>2]=f;c[i+4>>2]=C;e=e+1|0}while((e|0)!=14);f=b+72|0;e=c[f+4>>2]|0;i=b+192|0;c[i>>2]=c[f>>2];c[i+4>>2]=e;i=c[h+4>>2]|0;e=b+200|0;c[e>>2]=c[h>>2];c[e+4>>2]=i;Gb(b,g,b);e=0;do{i=b+(e<<3)|0;h=i;h=ma(c[h>>2]|0,c[h+4>>2]|0)|0;c[i>>2]=h;c[i+4>>2]=C;e=e+1|0}while((e|0)!=8);e=d;f=b;g=e+64|0;do{a[e>>0]=a[f>>0]|0;e=e+1|0;f=f+1|0}while((e|0)<(g|0))}lc(b|0,0,208)|0;return}function Jb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0;g=i;i=i+208|0;e=g;f=e;h=8;j=f+64|0;do{c[f>>2]=c[h>>2];f=f+4|0;h=h+4|0}while((f|0)<(j|0));lc(e+64|0,0,144)|0;Hb(e,a,b);Ib(e,d);i=g;return}function Kb(){var a=0,b=0,d=0;d=i;i=i+16|0;b=d;a=c[9714]|0;if(!a){a=bc(38797,38810)|0;c[9714]=a}if((gc(b,1,4,a)|0)==4){i=d;return c[b>>2]|0}else pa(38812,38828,60,38838);return 0}function Lb(a){a=a|0;if(a>>>0>=256)if(a>>>0<65536)a=2;else a=a>>>0<16777216?3:4;else a=1;return a|0}function Mb(b,c){b=b|0;c=c|0;var d=0;if(b>>>0<=16777215)if(b>>>0<=65535){if(b>>>0>255)d=6}else d=4;else{a[c>>0]=b>>>24;c=c+1|0;d=4}if((d|0)==4){a[c>>0]=b>>>16;c=c+1|0;d=6}if((d|0)==6){a[c>>0]=b>>>8;c=c+1|0}a[c>>0]=b;return}function Nb(a){a=a|0;var b=0,d=0;b=i;i=i+16|0;d=b;c[d>>2]=c[a+60>>2];a=Qb(ha(6,d|0)|0)|0;i=b;return a|0}function Ob(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0;m=i;i=i+48|0;h=m+16|0;g=m;f=m+32|0;c[f>>2]=d;j=f+4|0;l=b+48|0;n=c[l>>2]|0;c[j>>2]=e-((n|0)!=0&1);k=b+44|0;c[f+8>>2]=c[k>>2];c[f+12>>2]=n;if(!(c[9715]|0)){c[h>>2]=c[b+60>>2];c[h+4>>2]=f;c[h+8>>2]=2;f=Qb(qa(145,h|0)|0)|0}else{ga(1,b|0);c[g>>2]=c[b+60>>2];c[g+4>>2]=f;c[g+8>>2]=2;f=Qb(qa(145,g|0)|0)|0;ba(0)}if((f|0)>=1){j=c[j>>2]|0;if(f>>>0>j>>>0){g=c[k>>2]|0;h=b+4|0;c[h>>2]=g;c[b+8>>2]=g+(f-j);if(!(c[l>>2]|0))f=e;else{c[h>>2]=g+1;a[d+(e+-1)>>0]=a[g>>0]|0;f=e}}}else{c[b>>2]=c[b>>2]|f&48^16;c[b+8>>2]=0;c[b+4>>2]=0}i=m;return f|0}function Pb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0;f=i;i=i+32|0;g=f;e=f+20|0;c[g>>2]=c[a+60>>2];c[g+4>>2]=0;c[g+8>>2]=b;c[g+12>>2]=e;c[g+16>>2]=d;if((Qb(ja(140,g|0)|0)|0)<0){c[e>>2]=-1;a=-1}else a=c[e>>2]|0;i=f;return a|0}function Qb(a){a=a|0;if(a>>>0>4294963200){c[(Rb()|0)>>2]=0-a;a=-1}return a|0}function Rb(){var a=0;if(!(c[9715]|0))a=38904;else a=c[(uc()|0)+64>>2]|0;return a|0}function Sb(a){a=a|0;if(!(c[a+68>>2]|0))Tb(a);return}function Tb(a){a=a|0;return}function Ub(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0;q=i;i=i+48|0;n=q+16|0;m=q;j=q+32|0;o=a+28|0;h=c[o>>2]|0;c[j>>2]=h;p=a+20|0;h=(c[p>>2]|0)-h|0;c[j+4>>2]=h;c[j+8>>2]=b;c[j+12>>2]=d;k=a+60|0;l=a+44|0;g=2;b=h+d|0;while(1){if(!(c[9715]|0)){c[n>>2]=c[k>>2];c[n+4>>2]=j;c[n+8>>2]=g;f=Qb(ra(146,n|0)|0)|0}else{ga(2,a|0);c[m>>2]=c[k>>2];c[m+4>>2]=j;c[m+8>>2]=g;f=Qb(ra(146,m|0)|0)|0;ba(0)}if((b|0)==(f|0)){b=6;break}if((f|0)<0){b=8;break}b=b-f|0;e=c[j+4>>2]|0;if(f>>>0<=e>>>0)if((g|0)==2){c[o>>2]=(c[o>>2]|0)+f;g=2;h=j}else h=j;else{h=c[l>>2]|0;c[o>>2]=h;c[p>>2]=h;f=f-e|0;g=g+-1|0;h=j+8|0;e=c[j+12>>2]|0}c[h>>2]=(c[h>>2]|0)+f;c[h+4>>2]=e-f;j=h}if((b|0)==6){n=c[l>>2]|0;c[a+16>>2]=n+(c[a+48>>2]|0);a=n;c[o>>2]=a;c[p>>2]=a}else if((b|0)==8){c[a+16>>2]=0;c[o>>2]=0;c[p>>2]=0;c[a>>2]=c[a>>2]|32;if((g|0)==2)d=0;else d=d-(c[j+4>>2]|0)|0}i=q;return d|0}function Vb(a){a=a|0;if(!(c[a+68>>2]|0))Tb(a);return}function Wb(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0;g=i;i=i+80|0;f=g;c[b+36>>2]=3;if((c[b>>2]&64|0)==0?(c[f>>2]=c[b+60>>2],c[f+4>>2]=21505,c[f+8>>2]=g+12,da(54,f|0)|0):0)a[b+75>>0]=-1;f=Ub(b,d,e)|0;i=g;return f|0}function Xb(b){b=b|0;var d=0,e=0;d=b+74|0;e=a[d>>0]|0;a[d>>0]=e+255|e;d=b+20|0;e=b+44|0;if((c[d>>2]|0)>>>0>(c[e>>2]|0)>>>0)va[c[b+36>>2]&7](b,0,0)|0;c[b+16>>2]=0;c[b+28>>2]=0;c[d>>2]=0;d=c[b>>2]|0;if(d&20)if(!(d&4))d=-1;else{c[b>>2]=d|32;d=-1}else{d=c[e>>2]|0;c[b+8>>2]=d;c[b+4>>2]=d;d=0}return d|0}function Yb(a){a=a|0;return 0}function Zb(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,i=0;h=d&255;f=(e|0)!=0;a:do if(f&(b&3|0)!=0){g=d&255;while(1){if((a[b>>0]|0)==g<<24>>24){i=6;break a}b=b+1|0;e=e+-1|0;f=(e|0)!=0;if(!(f&(b&3|0)!=0)){i=5;break}}}else i=5;while(0);if((i|0)==5)if(f)i=6;else e=0;b:do if((i|0)==6){g=d&255;if((a[b>>0]|0)!=g<<24>>24){f=R(h,16843009)|0;c:do if(e>>>0>3)while(1){h=c[b>>2]^f;if((h&-2139062144^-2139062144)&h+-16843009|0)break;b=b+4|0;e=e+-4|0;if(e>>>0<=3){i=11;break c}}else i=11;while(0);if((i|0)==11)if(!e){e=0;break}while(1){if((a[b>>0]|0)==g<<24>>24)break b;b=b+1|0;e=e+-1|0;if(!e){e=0;break}}}}while(0);return (e|0?b:0)|0}function _b(b){b=b|0;var d=0,e=0,f=0;f=b;a:do if(!(f&3))e=4;else{d=f;while(1){if(!(a[b>>0]|0)){b=d;break a}b=b+1|0;d=b;if(!(d&3)){e=4;break}}}while(0);if((e|0)==4){while(1){d=c[b>>2]|0;if(!((d&-2139062144^-2139062144)&d+-16843009))b=b+4|0;else break}if((d&255)<<24>>24)do b=b+1|0;while((a[b>>0]|0)!=0)}return b-f|0}function $b(b,c){b=b|0;c=c|0;b=ac(b,c)|0;return ((a[b>>0]|0)==(c&255)<<24>>24?b:0)|0}function ac(b,d){b=b|0;d=d|0;var e=0,f=0,g=0;f=d&255;a:do if(!f)b=b+(_b(b)|0)|0;else{if(b&3){e=d&255;do{g=a[b>>0]|0;if(g<<24>>24==0?1:g<<24>>24==e<<24>>24)break a;b=b+1|0}while((b&3|0)!=0)}f=R(f,16843009)|0;e=c[b>>2]|0;b:do if(!((e&-2139062144^-2139062144)&e+-16843009))do{g=e^f;if((g&-2139062144^-2139062144)&g+-16843009|0)break b;b=b+4|0;e=c[b>>2]|0}while(!((e&-2139062144^-2139062144)&e+-16843009|0));while(0);e=d&255;while(1){g=a[b>>0]|0;if(g<<24>>24==0?1:g<<24>>24==e<<24>>24)break;else b=b+1|0}}while(0);return b|0}function bc(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0;g=i;i=i+32|0;f=g+16|0;e=g;if(Zb(38847,a[d>>0]|0,4)|0){h=cc(d)|0|32768;c[e>>2]=b;c[e+4>>2]=h;c[e+8>>2]=438;e=Qb(ka(5,e|0)|0)|0;if((e|0)>=0){b=dc(e,d)|0;if(!b){c[f>>2]=e;ha(6,f|0)|0;b=0}}else b=0}else{c[(Rb()|0)>>2]=22;b=0}i=g;return b|0}function cc(b){b=b|0;var c=0,d=0,e=0;d=($b(b,43)|0)==0;c=a[b>>0]|0;d=d?c<<24>>24!=114&1:2;e=($b(b,120)|0)==0;d=e?d:d|128;b=($b(b,101)|0)==0;b=b?d:d|524288;b=c<<24>>24==114?b:b|64;b=c<<24>>24==119?b|512:b;return (c<<24>>24==97?b|1024:b)|0}function dc(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0;o=i;i=i+112|0;n=o+40|0;l=o+24|0;k=o+16|0;g=o;m=o+52|0;f=a[d>>0]|0;if(Zb(38847,f<<24>>24,4)|0){e=hc(1144)|0;if(!e)e=0;else{h=e;j=h+112|0;do{c[h>>2]=0;h=h+4|0}while((h|0)<(j|0));if(!($b(d,43)|0))c[e>>2]=f<<24>>24==114?8:4;if($b(d,101)|0){c[g>>2]=b;c[g+4>>2]=2;c[g+8>>2]=1;ca(221,g|0)|0;f=a[d>>0]|0}if(f<<24>>24==97){c[k>>2]=b;c[k+4>>2]=3;f=ca(221,k|0)|0;if(!(f&1024)){c[l>>2]=b;c[l+4>>2]=4;c[l+8>>2]=f|1024;ca(221,l|0)|0}d=c[e>>2]|128;c[e>>2]=d}else d=c[e>>2]|0;c[e+60>>2]=b;c[e+44>>2]=e+120;c[e+48>>2]=1024;f=e+75|0;a[f>>0]=-1;if((d&8|0)==0?(c[n>>2]=b,c[n+4>>2]=21505,c[n+8>>2]=m,(da(54,n|0)|0)==0):0)a[f>>0]=10;c[e+32>>2]=4;c[e+36>>2]=3;c[e+40>>2]=2;c[e+12>>2]=1;if(!(c[9716]|0))c[e+76>>2]=-1;ea(38888);f=c[9721]|0;c[e+56>>2]=f;if(f|0)c[f+52>>2]=e;c[9721]=e;na(38888)}}else{c[(Rb()|0)>>2]=22;e=0}i=o;return e|0}function ec(a){a=a|0;var b=0,d=0;do if(a){if((c[a+76>>2]|0)<=-1){b=fc(a)|0;break}d=(Yb(a)|0)==0;b=fc(a)|0;if(!d)Tb(a)}else{if(!(c[9549]|0))b=0;else b=ec(c[9549]|0)|0;ea(38888);a=c[9721]|0;if(a)do{if((c[a+76>>2]|0)>-1)d=Yb(a)|0;else d=0;if((c[a+20>>2]|0)>>>0>(c[a+28>>2]|0)>>>0)b=fc(a)|0|b;if(d|0)Tb(a);a=c[a+56>>2]|0}while((a|0)!=0);na(38888)}while(0);return b|0}function fc(a){a=a|0;var b=0,d=0,e=0,f=0,g=0,h=0;b=a+20|0;h=a+28|0;if((c[b>>2]|0)>>>0>(c[h>>2]|0)>>>0?(va[c[a+36>>2]&7](a,0,0)|0,(c[b>>2]|0)==0):0)a=-1;else{d=a+4|0;e=c[d>>2]|0;f=a+8|0;g=c[f>>2]|0;if(e>>>0>>0)va[c[a+40>>2]&7](a,e-g|0,1)|0;c[a+16>>2]=0;c[h>>2]=0;c[b>>2]=0;c[f>>2]=0;c[d>>2]=0;a=0}return a|0}function gc(b,d,e,f){b=b|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,i=0,j=0,k=0,l=0;k=R(e,d)|0;if((c[f+76>>2]|0)>-1)j=Yb(f)|0;else j=0;g=f+74|0;i=a[g>>0]|0;a[g>>0]=i+255|i;g=f+4|0;i=c[g>>2]|0;h=(c[f+8>>2]|0)-i|0;if((h|0)>0){h=h>>>0>>0?h:k;tc(b|0,i|0,h|0)|0;c[g>>2]=i+h;g=k-h|0;b=b+h|0}else g=k;a:do if(!g)l=13;else{i=f+32|0;while(1){if(Xb(f)|0)break;h=va[c[i>>2]&7](f,b,g)|0;if((h+1|0)>>>0<2)break;g=g-h|0;if(!g){l=13;break a}else b=b+h|0}if(j|0)Tb(f);e=((k-g|0)>>>0)/(d>>>0)|0}while(0);if((l|0)==13)if(j)Tb(f);return e|0}function hc(a){a=a|0;var b=0,d=0,e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0;L=i;i=i+16|0;p=L;do if(a>>>0<245){o=a>>>0<11?16:a+11&-8;a=o>>>3;t=c[9727]|0;d=t>>>a;if(d&3|0){a=(d&1^1)+a|0;d=38948+(a<<1<<2)|0;e=d+8|0;f=c[e>>2]|0;g=f+8|0;h=c[g>>2]|0;do if((d|0)!=(h|0)){if(h>>>0<(c[9731]|0)>>>0)fa();b=h+12|0;if((c[b>>2]|0)==(f|0)){c[b>>2]=d;c[e>>2]=h;break}else fa()}else c[9727]=t&~(1<>2]=K|3;K=f+K+4|0;c[K>>2]=c[K>>2]|1;K=g;i=L;return K|0}s=c[9729]|0;if(o>>>0>s>>>0){if(d|0){j=2<>>12&16;a=a>>>j;e=a>>>5&8;a=a>>>e;g=a>>>2&4;a=a>>>g;d=a>>>1&2;a=a>>>d;b=a>>>1&1;b=(e|j|g|d|b)+(a>>>b)|0;a=38948+(b<<1<<2)|0;d=a+8|0;g=c[d>>2]|0;j=g+8|0;e=c[j>>2]|0;do if((a|0)!=(e|0)){if(e>>>0<(c[9731]|0)>>>0)fa();f=e+12|0;if((c[f>>2]|0)==(g|0)){c[f>>2]=a;c[d>>2]=e;k=t;break}else fa()}else{k=t&~(1<>2]=o|3;e=g+o|0;c[e+4>>2]=h|1;c[e+h>>2]=h;if(s|0){f=c[9732]|0;b=s>>>3;d=38948+(b<<1<<2)|0;b=1<>2]|0;if(a>>>0<(c[9731]|0)>>>0)fa();else{l=a;m=b}}else{c[9727]=k|b;l=d;m=d+8|0}c[m>>2]=f;c[l+12>>2]=f;c[f+8>>2]=l;c[f+12>>2]=d}c[9729]=h;c[9732]=e;K=j;i=L;return K|0}l=c[9728]|0;if(l){a=(l&0-l)+-1|0;J=a>>>12&16;a=a>>>J;I=a>>>5&8;a=a>>>I;K=a>>>2&4;a=a>>>K;j=a>>>1&2;a=a>>>j;k=a>>>1&1;k=c[39212+((I|J|K|j|k)+(a>>>k)<<2)>>2]|0;a=k;j=k;k=(c[k+4>>2]&-8)-o|0;while(1){b=c[a+16>>2]|0;if(!b){b=c[a+20>>2]|0;if(!b)break}K=(c[b+4>>2]&-8)-o|0;J=K>>>0>>0;a=b;j=J?b:j;k=J?K:k}f=c[9731]|0;if(j>>>0>>0)fa();h=j+o|0;if(j>>>0>=h>>>0)fa();g=c[j+24>>2]|0;d=c[j+12>>2]|0;do if((d|0)==(j|0)){a=j+20|0;b=c[a>>2]|0;if(!b){a=j+16|0;b=c[a>>2]|0;if(!b){n=0;break}}while(1){d=b+20|0;e=c[d>>2]|0;if(e|0){b=e;a=d;continue}d=b+16|0;e=c[d>>2]|0;if(!e)break;else{b=e;a=d}}if(a>>>0>>0)fa();else{c[a>>2]=0;n=b;break}}else{e=c[j+8>>2]|0;if(e>>>0>>0)fa();b=e+12|0;if((c[b>>2]|0)!=(j|0))fa();a=d+8|0;if((c[a>>2]|0)==(j|0)){c[b>>2]=d;c[a>>2]=e;n=d;break}else fa()}while(0);do if(g|0){b=c[j+28>>2]|0;a=39212+(b<<2)|0;if((j|0)==(c[a>>2]|0)){c[a>>2]=n;if(!n){c[9728]=l&~(1<>>0<(c[9731]|0)>>>0)fa();b=g+16|0;if((c[b>>2]|0)==(j|0))c[b>>2]=n;else c[g+20>>2]=n;if(!n)break}a=c[9731]|0;if(n>>>0>>0)fa();c[n+24>>2]=g;b=c[j+16>>2]|0;do if(b|0)if(b>>>0>>0)fa();else{c[n+16>>2]=b;c[b+24>>2]=n;break}while(0);b=c[j+20>>2]|0;if(b|0)if(b>>>0<(c[9731]|0)>>>0)fa();else{c[n+20>>2]=b;c[b+24>>2]=n;break}}while(0);if(k>>>0<16){K=k+o|0;c[j+4>>2]=K|3;K=j+K+4|0;c[K>>2]=c[K>>2]|1}else{c[j+4>>2]=o|3;c[h+4>>2]=k|1;c[h+k>>2]=k;if(s|0){e=c[9732]|0;b=s>>>3;d=38948+(b<<1<<2)|0;b=1<>2]|0;if(a>>>0<(c[9731]|0)>>>0)fa();else{q=a;r=b}}else{c[9727]=t|b;q=d;r=d+8|0}c[r>>2]=e;c[q+12>>2]=e;c[e+8>>2]=q;c[e+12>>2]=d}c[9729]=k;c[9732]=h}K=j+8|0;i=L;return K|0}}}else if(a>>>0<=4294967231){a=a+11|0;o=a&-8;l=c[9728]|0;if(l){e=0-o|0;a=a>>>8;if(a)if(o>>>0>16777215)k=31;else{r=(a+1048320|0)>>>16&8;D=a<>>16&4;D=D<>>16&2;k=14-(q|r|k)+(D<>>15)|0;k=o>>>(k+7|0)&1|k<<1}else k=0;a=c[39212+(k<<2)>>2]|0;a:do if(!a){d=0;f=0;D=86}else{f=0;j=a;h=o<<((k|0)==31?0:25-(k>>>1)|0);d=0;while(1){a=(c[j+4>>2]&-8)-o|0;if(a>>>0>>0)if(!a){a=j;e=0;d=j;D=90;break a}else{f=j;e=a}a=c[j+20>>2]|0;j=c[j+16+(h>>>31<<2)>>2]|0;d=(a|0)==0|(a|0)==(j|0)?d:a;a=(j|0)==0;if(a){D=86;break}else h=h<<(a&1^1)}}while(0);if((D|0)==86){if((d|0)==0&(f|0)==0){a=2<>>12&16;r=r>>>m;k=r>>>5&8;r=r>>>k;n=r>>>2&4;r=r>>>n;q=r>>>1&2;r=r>>>q;d=r>>>1&1;d=c[39212+((k|m|n|q|d)+(r>>>d)<<2)>>2]|0}if(!d){k=f;j=e}else{a=f;D=90}}if((D|0)==90)while(1){D=0;r=(c[d+4>>2]&-8)-o|0;f=r>>>0>>0;e=f?r:e;a=f?d:a;f=c[d+16>>2]|0;if(f|0){d=f;D=90;continue}d=c[d+20>>2]|0;if(!d){k=a;j=e;break}else D=90}if((k|0)!=0?j>>>0<((c[9729]|0)-o|0)>>>0:0){f=c[9731]|0;if(k>>>0>>0)fa();h=k+o|0;if(k>>>0>=h>>>0)fa();g=c[k+24>>2]|0;d=c[k+12>>2]|0;do if((d|0)==(k|0)){a=k+20|0;b=c[a>>2]|0;if(!b){a=k+16|0;b=c[a>>2]|0;if(!b){s=0;break}}while(1){d=b+20|0;e=c[d>>2]|0;if(e|0){b=e;a=d;continue}d=b+16|0;e=c[d>>2]|0;if(!e)break;else{b=e;a=d}}if(a>>>0>>0)fa();else{c[a>>2]=0;s=b;break}}else{e=c[k+8>>2]|0;if(e>>>0>>0)fa();b=e+12|0;if((c[b>>2]|0)!=(k|0))fa();a=d+8|0;if((c[a>>2]|0)==(k|0)){c[b>>2]=d;c[a>>2]=e;s=d;break}else fa()}while(0);do if(g){b=c[k+28>>2]|0;a=39212+(b<<2)|0;if((k|0)==(c[a>>2]|0)){c[a>>2]=s;if(!s){t=l&~(1<>>0<(c[9731]|0)>>>0)fa();b=g+16|0;if((c[b>>2]|0)==(k|0))c[b>>2]=s;else c[g+20>>2]=s;if(!s){t=l;break}}a=c[9731]|0;if(s>>>0>>0)fa();c[s+24>>2]=g;b=c[k+16>>2]|0;do if(b|0)if(b>>>0>>0)fa();else{c[s+16>>2]=b;c[b+24>>2]=s;break}while(0);b=c[k+20>>2]|0;if(b)if(b>>>0<(c[9731]|0)>>>0)fa();else{c[s+20>>2]=b;c[b+24>>2]=s;t=l;break}else t=l}else t=l;while(0);do if(j>>>0>=16){c[k+4>>2]=o|3;c[h+4>>2]=j|1;c[h+j>>2]=j;b=j>>>3;if(j>>>0<256){d=38948+(b<<1<<2)|0;a=c[9727]|0;b=1<>2]|0;if(a>>>0<(c[9731]|0)>>>0)fa();else{B=a;C=b}}else{c[9727]=a|b;B=d;C=d+8|0}c[C>>2]=h;c[B+12>>2]=h;c[h+8>>2]=B;c[h+12>>2]=d;break}b=j>>>8;if(b)if(j>>>0>16777215)b=31;else{J=(b+1048320|0)>>>16&8;K=b<>>16&4;K=K<>>16&2;b=14-(I|J|b)+(K<>>15)|0;b=j>>>(b+7|0)&1|b<<1}else b=0;d=39212+(b<<2)|0;c[h+28>>2]=b;a=h+16|0;c[a+4>>2]=0;c[a>>2]=0;a=1<>2]=h;c[h+24>>2]=d;c[h+12>>2]=h;c[h+8>>2]=h;break}a=j<<((b|0)==31?0:25-(b>>>1)|0);e=c[d>>2]|0;while(1){if((c[e+4>>2]&-8|0)==(j|0)){D=148;break}d=e+16+(a>>>31<<2)|0;b=c[d>>2]|0;if(!b){D=145;break}else{a=a<<1;e=b}}if((D|0)==145)if(d>>>0<(c[9731]|0)>>>0)fa();else{c[d>>2]=h;c[h+24>>2]=e;c[h+12>>2]=h;c[h+8>>2]=h;break}else if((D|0)==148){b=e+8|0;a=c[b>>2]|0;K=c[9731]|0;if(a>>>0>=K>>>0&e>>>0>=K>>>0){c[a+12>>2]=h;c[b>>2]=h;c[h+8>>2]=a;c[h+12>>2]=e;c[h+24>>2]=0;break}else fa()}}else{K=j+o|0;c[k+4>>2]=K|3;K=k+K+4|0;c[K>>2]=c[K>>2]|1}while(0);K=k+8|0;i=L;return K|0}}}else o=-1;while(0);d=c[9729]|0;if(d>>>0>=o>>>0){b=d-o|0;a=c[9732]|0;if(b>>>0>15){K=a+o|0;c[9732]=K;c[9729]=b;c[K+4>>2]=b|1;c[K+b>>2]=b;c[a+4>>2]=o|3}else{c[9729]=0;c[9732]=0;c[a+4>>2]=d|3;K=a+d+4|0;c[K>>2]=c[K>>2]|1}K=a+8|0;i=L;return K|0}j=c[9730]|0;if(j>>>0>o>>>0){I=j-o|0;c[9730]=I;K=c[9733]|0;J=K+o|0;c[9733]=J;c[J+4>>2]=I|1;c[K+4>>2]=o|3;K=K+8|0;i=L;return K|0}if(!(c[9845]|0)){c[9847]=4096;c[9846]=4096;c[9848]=-1;c[9849]=-1;c[9850]=0;c[9838]=0;a=p&-16^1431655768;c[p>>2]=a;c[9845]=a;a=4096}else a=c[9847]|0;k=o+48|0;l=o+47|0;h=a+l|0;f=0-a|0;m=h&f;if(m>>>0<=o>>>0){K=0;i=L;return K|0}a=c[9837]|0;if(a|0?(B=c[9835]|0,C=B+m|0,C>>>0<=B>>>0|C>>>0>a>>>0):0){K=0;i=L;return K|0}b:do if(!(c[9838]&4)){d=c[9733]|0;c:do if(d){e=39356;while(1){a=c[e>>2]|0;if(a>>>0<=d>>>0?(u=e+4|0,(a+(c[u>>2]|0)|0)>>>0>d>>>0):0)break;a=c[e+8>>2]|0;if(!a){D=172;break c}else e=a}d=h-j&f;if(d>>>0<2147483647){a=rc(d|0)|0;if((a|0)==((c[e>>2]|0)+(c[u>>2]|0)|0)){if((a|0)!=(-1|0)){h=d;g=a;D=190;break b}}else{b=d;D=180}}}else D=172;while(0);do if(((D|0)==172?(g=rc(0)|0,(g|0)!=(-1|0)):0)?(b=g,v=c[9846]|0,w=v+-1|0,b=((w&b|0)==0?0:(w+b&0-v)-b|0)+m|0,v=c[9835]|0,w=b+v|0,b>>>0>o>>>0&b>>>0<2147483647):0){C=c[9837]|0;if(C|0?w>>>0<=v>>>0|w>>>0>C>>>0:0)break;a=rc(b|0)|0;if((a|0)==(g|0)){h=b;D=190;break b}else D=180}while(0);d:do if((D|0)==180){d=0-b|0;do if(k>>>0>b>>>0&(b>>>0<2147483647&(a|0)!=(-1|0))?(x=c[9847]|0,x=l-b+x&0-x,x>>>0<2147483647):0)if((rc(x|0)|0)==(-1|0)){rc(d|0)|0;break d}else{b=x+b|0;break}while(0);if((a|0)!=(-1|0)){h=b;g=a;D=190;break b}}while(0);c[9838]=c[9838]|4;D=187}else D=187;while(0);if((((D|0)==187?m>>>0<2147483647:0)?(A=rc(m|0)|0,y=rc(0)|0,A>>>0>>0&((A|0)!=(-1|0)&(y|0)!=(-1|0))):0)?(z=y-A|0,z>>>0>(o+40|0)>>>0):0){h=z;g=A;D=190}if((D|0)==190){b=(c[9835]|0)+h|0;c[9835]=b;if(b>>>0>(c[9836]|0)>>>0)c[9836]=b;l=c[9733]|0;do if(l){b=39356;while(1){a=c[b>>2]|0;d=b+4|0;e=c[d>>2]|0;if((g|0)==(a+e|0)){D=200;break}f=c[b+8>>2]|0;if(!f)break;else b=f}if(((D|0)==200?(c[b+12>>2]&8|0)==0:0)?l>>>0>>0&l>>>0>=a>>>0:0){c[d>>2]=e+h;K=l+8|0;K=(K&7|0)==0?0:0-K&7;J=l+K|0;K=h-K+(c[9730]|0)|0;c[9733]=J;c[9730]=K;c[J+4>>2]=K|1;c[J+K+4>>2]=40;c[9734]=c[9849];break}b=c[9731]|0;if(g>>>0>>0){c[9731]=g;j=g}else j=b;a=g+h|0;b=39356;while(1){if((c[b>>2]|0)==(a|0)){D=208;break}b=c[b+8>>2]|0;if(!b){a=39356;break}}if((D|0)==208)if(!(c[b+12>>2]&8)){c[b>>2]=g;n=b+4|0;c[n>>2]=(c[n>>2]|0)+h;n=g+8|0;n=g+((n&7|0)==0?0:0-n&7)|0;b=a+8|0;b=a+((b&7|0)==0?0:0-b&7)|0;m=n+o|0;k=b-n-o|0;c[n+4>>2]=o|3;do if((b|0)!=(l|0)){if((b|0)==(c[9732]|0)){K=(c[9729]|0)+k|0;c[9729]=K;c[9732]=m;c[m+4>>2]=K|1;c[m+K>>2]=K;break}a=c[b+4>>2]|0;if((a&3|0)==1){h=a&-8;f=a>>>3;e:do if(a>>>0>=256){g=c[b+24>>2]|0;e=c[b+12>>2]|0;do if((e|0)==(b|0)){e=b+16|0;d=e+4|0;a=c[d>>2]|0;if(!a){a=c[e>>2]|0;if(!a){I=0;break}else d=e}while(1){e=a+20|0;f=c[e>>2]|0;if(f|0){a=f;d=e;continue}e=a+16|0;f=c[e>>2]|0;if(!f)break;else{a=f;d=e}}if(d>>>0>>0)fa();else{c[d>>2]=0;I=a;break}}else{f=c[b+8>>2]|0;if(f>>>0>>0)fa();a=f+12|0;if((c[a>>2]|0)!=(b|0))fa();d=e+8|0;if((c[d>>2]|0)==(b|0)){c[a>>2]=e;c[d>>2]=f;I=e;break}else fa()}while(0);if(!g)break;a=c[b+28>>2]|0;d=39212+(a<<2)|0;do if((b|0)!=(c[d>>2]|0)){if(g>>>0<(c[9731]|0)>>>0)fa();a=g+16|0;if((c[a>>2]|0)==(b|0))c[a>>2]=I;else c[g+20>>2]=I;if(!I)break e}else{c[d>>2]=I;if(I|0)break;c[9728]=c[9728]&~(1<>>0>>0)fa();c[I+24>>2]=g;a=b+16|0;d=c[a>>2]|0;do if(d|0)if(d>>>0>>0)fa();else{c[I+16>>2]=d;c[d+24>>2]=I;break}while(0);a=c[a+4>>2]|0;if(!a)break;if(a>>>0<(c[9731]|0)>>>0)fa();else{c[I+20>>2]=a;c[a+24>>2]=I;break}}else{d=c[b+8>>2]|0;e=c[b+12>>2]|0;a=38948+(f<<1<<2)|0;do if((d|0)!=(a|0)){if(d>>>0>>0)fa();if((c[d+12>>2]|0)==(b|0))break;fa()}while(0);if((e|0)==(d|0)){c[9727]=c[9727]&~(1<>>0>>0)fa();a=e+8|0;if((c[a>>2]|0)==(b|0)){F=a;break}fa()}while(0);c[d+12>>2]=e;c[F>>2]=d}while(0);b=b+h|0;f=h+k|0}else f=k;b=b+4|0;c[b>>2]=c[b>>2]&-2;c[m+4>>2]=f|1;c[m+f>>2]=f;b=f>>>3;if(f>>>0<256){d=38948+(b<<1<<2)|0;a=c[9727]|0;b=1<>2]|0;if(a>>>0>=(c[9731]|0)>>>0){J=a;K=b;break}fa()}while(0);c[K>>2]=m;c[J+12>>2]=m;c[m+8>>2]=J;c[m+12>>2]=d;break}b=f>>>8;do if(!b)b=0;else{if(f>>>0>16777215){b=31;break}J=(b+1048320|0)>>>16&8;K=b<>>16&4;K=K<>>16&2;b=14-(I|J|b)+(K<>>15)|0;b=f>>>(b+7|0)&1|b<<1}while(0);e=39212+(b<<2)|0;c[m+28>>2]=b;a=m+16|0;c[a+4>>2]=0;c[a>>2]=0;a=c[9728]|0;d=1<>2]=m;c[m+24>>2]=e;c[m+12>>2]=m;c[m+8>>2]=m;break}a=f<<((b|0)==31?0:25-(b>>>1)|0);e=c[e>>2]|0;while(1){if((c[e+4>>2]&-8|0)==(f|0)){D=278;break}d=e+16+(a>>>31<<2)|0;b=c[d>>2]|0;if(!b){D=275;break}else{a=a<<1;e=b}}if((D|0)==275)if(d>>>0<(c[9731]|0)>>>0)fa();else{c[d>>2]=m;c[m+24>>2]=e;c[m+12>>2]=m;c[m+8>>2]=m;break}else if((D|0)==278){b=e+8|0;a=c[b>>2]|0;K=c[9731]|0;if(a>>>0>=K>>>0&e>>>0>=K>>>0){c[a+12>>2]=m;c[b>>2]=m;c[m+8>>2]=a;c[m+12>>2]=e;c[m+24>>2]=0;break}else fa()}}else{K=(c[9730]|0)+k|0;c[9730]=K;c[9733]=m;c[m+4>>2]=K|1}while(0);K=n+8|0;i=L;return K|0}else a=39356;while(1){b=c[a>>2]|0;if(b>>>0<=l>>>0?(E=b+(c[a+4>>2]|0)|0,E>>>0>l>>>0):0)break;a=c[a+8>>2]|0}f=E+-47|0;a=f+8|0;a=f+((a&7|0)==0?0:0-a&7)|0;f=l+16|0;a=a>>>0>>0?l:a;b=a+8|0;d=g+8|0;d=(d&7|0)==0?0:0-d&7;K=g+d|0;d=h+-40-d|0;c[9733]=K;c[9730]=d;c[K+4>>2]=d|1;c[K+d+4>>2]=40;c[9734]=c[9849];d=a+4|0;c[d>>2]=27;c[b>>2]=c[9839];c[b+4>>2]=c[9840];c[b+8>>2]=c[9841];c[b+12>>2]=c[9842];c[9839]=g;c[9840]=h;c[9842]=0;c[9841]=b;b=a+24|0;do{b=b+4|0;c[b>>2]=7}while((b+4|0)>>>0>>0);if((a|0)!=(l|0)){g=a-l|0;c[d>>2]=c[d>>2]&-2;c[l+4>>2]=g|1;c[a>>2]=g;b=g>>>3;if(g>>>0<256){d=38948+(b<<1<<2)|0;a=c[9727]|0;b=1<>2]|0;if(a>>>0<(c[9731]|0)>>>0)fa();else{G=a;H=b}}else{c[9727]=a|b;G=d;H=d+8|0}c[H>>2]=l;c[G+12>>2]=l;c[l+8>>2]=G;c[l+12>>2]=d;break}b=g>>>8;if(b)if(g>>>0>16777215)d=31;else{J=(b+1048320|0)>>>16&8;K=b<>>16&4;K=K<>>16&2;d=14-(I|J|d)+(K<>>15)|0;d=g>>>(d+7|0)&1|d<<1}else d=0;e=39212+(d<<2)|0;c[l+28>>2]=d;c[l+20>>2]=0;c[f>>2]=0;b=c[9728]|0;a=1<>2]=l;c[l+24>>2]=e;c[l+12>>2]=l;c[l+8>>2]=l;break}a=g<<((d|0)==31?0:25-(d>>>1)|0);e=c[e>>2]|0;while(1){if((c[e+4>>2]&-8|0)==(g|0)){D=304;break}d=e+16+(a>>>31<<2)|0;b=c[d>>2]|0;if(!b){D=301;break}else{a=a<<1;e=b}}if((D|0)==301)if(d>>>0<(c[9731]|0)>>>0)fa();else{c[d>>2]=l;c[l+24>>2]=e;c[l+12>>2]=l;c[l+8>>2]=l;break}else if((D|0)==304){b=e+8|0;a=c[b>>2]|0;K=c[9731]|0;if(a>>>0>=K>>>0&e>>>0>=K>>>0){c[a+12>>2]=l;c[b>>2]=l;c[l+8>>2]=a;c[l+12>>2]=e;c[l+24>>2]=0;break}else fa()}}}else{K=c[9731]|0;if((K|0)==0|g>>>0>>0)c[9731]=g;c[9839]=g;c[9840]=h;c[9842]=0;c[9736]=c[9845];c[9735]=-1;b=0;do{K=38948+(b<<1<<2)|0;c[K+12>>2]=K;c[K+8>>2]=K;b=b+1|0}while((b|0)!=32);K=g+8|0;K=(K&7|0)==0?0:0-K&7;J=g+K|0;K=h+-40-K|0;c[9733]=J;c[9730]=K;c[J+4>>2]=K|1;c[J+K+4>>2]=40;c[9734]=c[9849]}while(0);b=c[9730]|0;if(b>>>0>o>>>0){I=b-o|0;c[9730]=I;K=c[9733]|0;J=K+o|0;c[9733]=J;c[J+4>>2]=I|1;c[K+4>>2]=o|3;K=K+8|0;i=L;return K|0}}c[(Rb()|0)>>2]=12;K=0;i=L;return K|0}function ic(a){a=a|0;var b=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0;if(!a)return;d=a+-8|0;h=c[9731]|0;if(d>>>0>>0)fa();a=c[a+-4>>2]|0;b=a&3;if((b|0)==1)fa();e=a&-8;n=d+e|0;do if(!(a&1)){a=c[d>>2]|0;if(!b)return;k=d+(0-a)|0;j=a+e|0;if(k>>>0>>0)fa();if((k|0)==(c[9732]|0)){a=n+4|0;b=c[a>>2]|0;if((b&3|0)!=3){q=k;f=j;break}c[9729]=j;c[a>>2]=b&-2;c[k+4>>2]=j|1;c[k+j>>2]=j;return}e=a>>>3;if(a>>>0<256){b=c[k+8>>2]|0;d=c[k+12>>2]|0;a=38948+(e<<1<<2)|0;if((b|0)!=(a|0)){if(b>>>0>>0)fa();if((c[b+12>>2]|0)!=(k|0))fa()}if((d|0)==(b|0)){c[9727]=c[9727]&~(1<>>0>>0)fa();a=d+8|0;if((c[a>>2]|0)==(k|0))g=a;else fa()}else g=d+8|0;c[b+12>>2]=d;c[g>>2]=b;q=k;f=j;break}g=c[k+24>>2]|0;d=c[k+12>>2]|0;do if((d|0)==(k|0)){d=k+16|0;b=d+4|0;a=c[b>>2]|0;if(!a){a=c[d>>2]|0;if(!a){i=0;break}else b=d}while(1){d=a+20|0;e=c[d>>2]|0;if(e|0){a=e;b=d;continue}d=a+16|0;e=c[d>>2]|0;if(!e)break;else{a=e;b=d}}if(b>>>0>>0)fa();else{c[b>>2]=0;i=a;break}}else{e=c[k+8>>2]|0;if(e>>>0>>0)fa();a=e+12|0;if((c[a>>2]|0)!=(k|0))fa();b=d+8|0;if((c[b>>2]|0)==(k|0)){c[a>>2]=d;c[b>>2]=e;i=d;break}else fa()}while(0);if(g){a=c[k+28>>2]|0;b=39212+(a<<2)|0;if((k|0)==(c[b>>2]|0)){c[b>>2]=i;if(!i){c[9728]=c[9728]&~(1<>>0<(c[9731]|0)>>>0)fa();a=g+16|0;if((c[a>>2]|0)==(k|0))c[a>>2]=i;else c[g+20>>2]=i;if(!i){q=k;f=j;break}}d=c[9731]|0;if(i>>>0>>0)fa();c[i+24>>2]=g;a=k+16|0;b=c[a>>2]|0;do if(b|0)if(b>>>0>>0)fa();else{c[i+16>>2]=b;c[b+24>>2]=i;break}while(0);a=c[a+4>>2]|0;if(a)if(a>>>0<(c[9731]|0)>>>0)fa();else{c[i+20>>2]=a;c[a+24>>2]=i;q=k;f=j;break}else{q=k;f=j}}else{q=k;f=j}}else{q=d;f=e}while(0);if(q>>>0>=n>>>0)fa();a=n+4|0;b=c[a>>2]|0;if(!(b&1))fa();if(!(b&2)){if((n|0)==(c[9733]|0)){p=(c[9730]|0)+f|0;c[9730]=p;c[9733]=q;c[q+4>>2]=p|1;if((q|0)!=(c[9732]|0))return;c[9732]=0;c[9729]=0;return}if((n|0)==(c[9732]|0)){p=(c[9729]|0)+f|0;c[9729]=p;c[9732]=q;c[q+4>>2]=p|1;c[q+p>>2]=p;return}f=(b&-8)+f|0;e=b>>>3;do if(b>>>0>=256){g=c[n+24>>2]|0;a=c[n+12>>2]|0;do if((a|0)==(n|0)){d=n+16|0;b=d+4|0;a=c[b>>2]|0;if(!a){a=c[d>>2]|0;if(!a){m=0;break}else b=d}while(1){d=a+20|0;e=c[d>>2]|0;if(e|0){a=e;b=d;continue}d=a+16|0;e=c[d>>2]|0;if(!e)break;else{a=e;b=d}}if(b>>>0<(c[9731]|0)>>>0)fa();else{c[b>>2]=0;m=a;break}}else{b=c[n+8>>2]|0;if(b>>>0<(c[9731]|0)>>>0)fa();d=b+12|0;if((c[d>>2]|0)!=(n|0))fa();e=a+8|0;if((c[e>>2]|0)==(n|0)){c[d>>2]=a;c[e>>2]=b;m=a;break}else fa()}while(0);if(g|0){a=c[n+28>>2]|0;b=39212+(a<<2)|0;if((n|0)==(c[b>>2]|0)){c[b>>2]=m;if(!m){c[9728]=c[9728]&~(1<>>0<(c[9731]|0)>>>0)fa();a=g+16|0;if((c[a>>2]|0)==(n|0))c[a>>2]=m;else c[g+20>>2]=m;if(!m)break}d=c[9731]|0;if(m>>>0>>0)fa();c[m+24>>2]=g;a=n+16|0;b=c[a>>2]|0;do if(b|0)if(b>>>0>>0)fa();else{c[m+16>>2]=b;c[b+24>>2]=m;break}while(0);a=c[a+4>>2]|0;if(a|0)if(a>>>0<(c[9731]|0)>>>0)fa();else{c[m+20>>2]=a;c[a+24>>2]=m;break}}}else{b=c[n+8>>2]|0;d=c[n+12>>2]|0;a=38948+(e<<1<<2)|0;if((b|0)!=(a|0)){if(b>>>0<(c[9731]|0)>>>0)fa();if((c[b+12>>2]|0)!=(n|0))fa()}if((d|0)==(b|0)){c[9727]=c[9727]&~(1<>>0<(c[9731]|0)>>>0)fa();a=d+8|0;if((c[a>>2]|0)==(n|0))l=a;else fa()}else l=d+8|0;c[b+12>>2]=d;c[l>>2]=b}while(0);c[q+4>>2]=f|1;c[q+f>>2]=f;if((q|0)==(c[9732]|0)){c[9729]=f;return}}else{c[a>>2]=b&-2;c[q+4>>2]=f|1;c[q+f>>2]=f}a=f>>>3;if(f>>>0<256){d=38948+(a<<1<<2)|0;b=c[9727]|0;a=1<>2]|0;if(b>>>0<(c[9731]|0)>>>0)fa();else{o=b;p=a}}else{c[9727]=b|a;o=d;p=d+8|0}c[p>>2]=q;c[o+12>>2]=q;c[q+8>>2]=o;c[q+12>>2]=d;return}a=f>>>8;if(a)if(f>>>0>16777215)a=31;else{o=(a+1048320|0)>>>16&8;p=a<>>16&4;p=p<>>16&2;a=14-(n|o|a)+(p<>>15)|0;a=f>>>(a+7|0)&1|a<<1}else a=0;e=39212+(a<<2)|0;c[q+28>>2]=a;c[q+20>>2]=0;c[q+16>>2]=0;b=c[9728]|0;d=1<>>1)|0);e=c[e>>2]|0;while(1){if((c[e+4>>2]&-8|0)==(f|0)){a=130;break}d=e+16+(b>>>31<<2)|0;a=c[d>>2]|0;if(!a){a=127;break}else{b=b<<1;e=a}}if((a|0)==127)if(d>>>0<(c[9731]|0)>>>0)fa();else{c[d>>2]=q;c[q+24>>2]=e;c[q+12>>2]=q;c[q+8>>2]=q;break}else if((a|0)==130){a=e+8|0;b=c[a>>2]|0;p=c[9731]|0;if(b>>>0>=p>>>0&e>>>0>=p>>>0){c[b+12>>2]=q;c[a>>2]=q;c[q+8>>2]=b;c[q+12>>2]=e;c[q+24>>2]=0;break}else fa()}}else{c[9728]=b|d;c[e>>2]=q;c[q+24>>2]=e;c[q+12>>2]=q;c[q+8>>2]=q}while(0);q=(c[9735]|0)+-1|0;c[9735]=q;if(!q)a=39364;else return;while(1){a=c[a>>2]|0;if(!a)break;else a=a+8|0}c[9735]=-1;return}function jc(){}function kc(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;d=b-d-(c>>>0>a>>>0|0)>>>0;return (C=d,a-c>>>0|0)|0}function lc(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,i=0;f=b+e|0;if((e|0)>=20){d=d&255;h=b&3;i=d|d<<8|d<<16|d<<24;g=f&~3;if(h){h=b+4-h|0;while((b|0)<(h|0)){a[b>>0]=d;b=b+1|0}}while((b|0)<(g|0)){c[b>>2]=i;b=b+4|0}}while((b|0)<(f|0)){a[b>>0]=d;b=b+1|0}return b-e|0}function mc(a,b,c){a=a|0;b=b|0;c=c|0;if((c|0)<32){C=b>>>c;return a>>>c|(b&(1<>>c-32|0}function nc(a,b,c){a=a|0;b=b|0;c=c|0;if((c|0)<32){C=b<>>32-c;return a<>>16;a=(c>>>16)+(R(e,d)|0)|0;e=b>>>16;b=R(e,f)|0;return (C=(a>>>16)+(R(e,d)|0)+(((a&65535)+b|0)>>>16)|0,a+b<<16|c&65535|0)|0}function pc(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0,f=0;e=a;f=c;c=oc(e,f)|0;a=C;return (C=(R(b,f)|0)+(R(d,e)|0)+a|a&0,c|0|0)|0}function qc(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;c=a+c>>>0;return (C=b+d+(c>>>0>>0|0)>>>0,c|0)|0}function rc(a){a=a|0;var b=0,d=0;d=a+15&-16|0;b=c[k>>2]|0;a=b+d|0;if((d|0)>0&(a|0)<(b|0)|(a|0)<0){Z()|0;sa(12);return -1}c[k>>2]=a;if((a|0)>(Y()|0)?(X()|0)==0:0){sa(12);c[k>>2]=b;return -1}return b|0}function sc(a){a=a|0;return (a&255)<<24|(a>>8&255)<<16|(a>>16&255)<<8|a>>>24|0}function tc(b,d,e){b=b|0;d=d|0;e=e|0;var f=0;if((e|0)>=4096)return la(b|0,d|0,e|0)|0;f=b|0;if((b&3)==(d&3)){while(b&3){if(!e)return f|0;a[b>>0]=a[d>>0]|0;b=b+1|0;d=d+1|0;e=e-1|0}while((e|0)>=4){c[b>>2]=c[d>>2];b=b+4|0;d=d+4|0;e=e-4|0}}while((e|0)>0){a[b>>0]=a[d>>0]|0;b=b+1|0;d=d+1|0;e=e-1|0}return f|0}function uc(){return 0}function vc(a,b){a=a|0;b=b|0;return ua[a&1](b|0)|0}function wc(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;return va[a&7](b|0,c|0,d|0)|0}function xc(a,b){a=a|0;b=b|0;wa[a&3](b|0)}function yc(a){a=a|0;V(0);return 0}function zc(a,b,c){a=a|0;b=b|0;c=c|0;V(1);return 0}function Ac(a){a=a|0;V(2)} +function xa(a){a=a|0;var b=0;b=i;i=i+a|0;i=i+15&-16;return b|0}function ya(){return i|0}function za(a){a=a|0;i=a}function Aa(a,b){a=a|0;b=b|0;i=a;j=b}function Ba(a,b){a=a|0;b=b|0;if(!n){n=a;o=b}}function Ca(a){a=a|0;C=a}function Da(){return C|0}function Ea(b,c){b=b|0;c=c|0;a[b>>0]=c>>>24;a[b+1>>0]=c>>>16;a[b+2>>0]=c>>>8;a[b+3>>0]=c;return}function Fa(a,b){a=a|0;b=b|0;var e=0,f=0,g=0,h=0;e=0;f=0;do{h=a+(7-f<<2)|0;h=(d[h+1>>0]|0)<<16|(d[h>>0]|0)<<24|(d[h+2>>0]|0)<<8|(d[h+3>>0]|0);g=f<<1;c[b+(f<<2)>>2]=(h<>>(30-g|0);f=f+1|0}while((f|0)!=8);c[b+32>>2]=e;return}function Ga(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0;e=c[b+32>>2]<<16;f=0;while(1){g=c[b+(7-f<<2)>>2]|0;h=f<<1;i=g>>>(14-h|0)|e;e=d+(f<<2)|0;a[e>>0]=i>>>24;a[e+1>>0]=i>>>16;a[e+2>>0]=i>>>8;a[e+3>>0]=i;f=f+1|0;if((f|0)==8)break;else e=g<>2]=0;a=a+4|0}while((a|0)<(b|0));return}function Ia(a){a=a|0;return (c[a+32>>2]|(c[a+28>>2]|(c[a+24>>2]|(c[a+20>>2]|(c[a+16>>2]|(c[a+12>>2]|(c[a+8>>2]|(c[a+4>>2]|c[a>>2])))))))|0)==0|0}function Ja(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0;d=0;e=8;f=0;while(1){h=c[a+(e<<2)>>2]|0;g=c[b+(e<<2)>>2]|0;d=h>>>0>>0|d<<1;f=h>>>0>g>>>0|f<<1;if((e|0)<=0)break;else e=e+-1|0}return d>>>0>f>>>0|0}function Ka(a,b){a=a|0;b=b|0;var d=0,e=0;d=0;e=0;do{e=c[b+(d<<2)>>2]^c[a+(d<<2)>>2]|e;d=d+1|0}while((d|0)!=9);return (e|0)==0|0}function La(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0;g=0-b|0;h=b+-1|0;if((b|1|0)==1)f=0;else pa(38200,38223,270,38235);do{c[a+(f<<2)>>2]=c[e+(f<<2)>>2]&h|c[d+(f<<2)>>2]&g;f=f+1|0}while((f|0)!=9);return}function Ma(a){a=a|0;var b=0,d=0,e=0,f=0;b=8;d=c[a+32>>2]|0;do{e=b;b=b+-1|0;f=d;d=c[a+(b<<2)>>2]|0;c[a+(e<<2)>>2]=d>>>29&1|f<<1&1073741822}while((e|0)>1);c[a>>2]=c[a>>2]<<1&1073741822;return}function Na(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,i=0;d=c[a>>2]|0;f=0-(d&1)|0;d=((c[b>>2]&f)+d|0)>>>1;e=0;do{i=e;e=e+1|0;g=(c[b+(e<<2)>>2]&f)+(c[a+(e<<2)>>2]|0)|0;h=(g<<29&536870912)+d|0;c[a+(i<<2)>>2]=h&1073741823;d=(h>>>30)+(g>>>1)|0}while((e|0)!=8);c[a+32>>2]=d;return}function Oa(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0;e=b&255;b=0;do{f=a+(b<<2)|0;c[f>>2]=R(c[f>>2]|0,e)|0;b=b+1|0}while((b|0)!=9);Pa(a,d);return}function Pa(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0;g=(c[a+32>>2]|0)>>>16;i=c[a>>2]|0;h=pc(c[b>>2]|0,0,g|0,0)|0;d=C;e=kc(i|0,536870912,h|0,d|0)|0;f=C;d=kc(i|0,0,h|0,d|0)|0;c[a>>2]=d&1073741823;d=1;while(1){l=mc(e|0,f|0,30)|0;k=C;i=a+(d<<2)|0;j=c[i>>2]|0;f=pc(c[b+(d<<2)>>2]|0,0,g|0,0)|0;h=C;k=qc(l|0,k|0,-2147483648,536870911)|0;j=qc(k|0,C|0,j|0,0)|0;e=kc(j|0,C|0,f|0,h|0)|0;c[i>>2]=e&1073741823;d=d+1|0;if((d|0)==9)break;else f=C}return}function Qa(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0;h=i;i=i+48|0;g=h;d=0;e=8;f=0;while(1){k=c[a+(e<<2)>>2]|0;j=c[b+(e<<2)>>2]|0;d=k>>>0>>0|d<<1;f=k>>>0>j>>>0|f<<1;if((e|0)<=0)break;else e=e+-1|0}f=d>>>0>f>>>0;e=0;d=1;while(1){d=d+1073741823+(c[a+(e<<2)>>2]|0)-(c[b+(e<<2)>>2]|0)|0;c[g+(e<<2)>>2]=d&1073741823;e=e+1|0;if((e|0)==9)break;else d=d>>>30}La(a,f&1,a,g);i=h;return}function Ra(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0;f=0;e=1;while(1){e=e+1073741823+(c[a+(f<<2)>>2]|0)-(c[b+(f<<2)>>2]|0)|0;c[d+(f<<2)>>2]=e&1073741823;f=f+1|0;if((f|0)==9)break;else e=e>>>30}return}function Sa(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0,j=0;h=0;g=0;e=0;i=1;while(1){f=0;do{j=pc(c[b+(h-f<<2)>>2]|0,0,c[a+(f<<2)>>2]|0,0)|0;g=qc(j|0,C|0,g|0,e|0)|0;e=C;f=f+1|0}while((f|0)!=(i|0));c[d+(h<<2)>>2]=g&1073741823;g=mc(g|0,e|0,30)|0;e=C;h=h+1|0;if((h|0)==9){h=9;break}else i=i+1|0}while(1){f=h+-8|0;if((f|0)<9)do{j=pc(c[b+(h-f<<2)>>2]|0,0,c[a+(f<<2)>>2]|0,0)|0;g=qc(j|0,C|0,g|0,e|0)|0;e=C;f=f+1|0}while((f|0)!=9);c[d+(h<<2)>>2]=g&1073741823;g=mc(g|0,e|0,30)|0;h=h+1|0;if((h|0)==17)break;else e=C}c[d+68>>2]=g;return}function Ta(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0;l=a+(d+1<<2)|0;j=(c[l>>2]<<14)+((c[a+(d<<2)>>2]|0)>>>16)|0;k=d+-8|0;e=a+(k<<2)|0;f=c[e>>2]|0;g=pc(c[b>>2]|0,0,j|0,0)|0;h=C;if((j|0)<=-1)pa(38243,38223,417,38262);i=kc(f|0,536870912,g|0,h|0)|0;m=C;h=kc(f|0,0,g|0,h|0)|0;c[e>>2]=h&1073741823;h=mc(i|0,m|0,30)|0;m=C;i=a+(d+-7<<2)|0;f=qc(c[i>>2]|0,0,-2147483648,536870911)|0;e=1;g=C;d=m;do{m=pc(c[b+(e<<2)>>2]|0,0,j|0,0)|0;m=kc(f|0,g|0,m|0,C|0)|0;m=qc(m|0,C|0,h|0,d|0)|0;c[i>>2]=m&1073741823;e=e+1|0;h=mc(m|0,C|0,30)|0;d=C;i=a+(e+k<<2)|0;f=qc(c[i>>2]|0,0,-2147483648,536870911)|0;g=C}while((e|0)!=9);m=qc(f|0,g|0,h|0,d|0)|0;c[l>>2]=m&1073741823;return}function Ua(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0;e=16;while(1){Ta(b,d,e);if(c[b+(e+1<<2)>>2]|0){g=4;break}e=e+-1|0;if((e|0)<=7){f=0;break}}if((g|0)==4)pa(38286,38223,451,38302);do{c[a+(f<<2)>>2]=c[b+(f<<2)>>2];f=f+1|0}while((f|0)!=9);return}function Va(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0;g=i;i=i+80|0;e=g;f=e;h=f+72|0;do{c[f>>2]=0;f=f+4|0}while((f|0)<(h|0));Sa(a,b,e);Ua(b,e,d);i=g;return}function Wa(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0;n=i;i=i+144|0;k=n+72|0;l=n+36|0;m=n;c[l>>2]=1;h=l+4|0;c[h>>2]=0;c[h+4>>2]=0;c[h+8>>2]=0;c[h+12>>2]=0;c[h+16>>2]=0;c[h+20>>2]=0;c[h+24>>2]=0;c[h+28>>2]=0;h=m;d=b;j=h+36|0;do{c[h>>2]=c[d>>2];h=h+4|0;d=d+4|0}while((h|0)<(j|0));e=0;d=1;while(1){j=m+(e<<2)|0;d=(c[j>>2]|0)+d|0;c[j>>2]=d&1073741823;e=e+1|0;if((e|0)==9)break;else d=d>>>30}d=0;e=c[m>>2]|0;do{j=d;d=d+1|0;h=e;e=c[m+(d<<2)>>2]|0;c[m+(j<<2)>>2]=e<<29&536870912|h>>>1}while((d|0)!=8);e=m+32|0;c[e>>2]=(c[e>>2]|0)>>>1;d=0;f=c[m>>2]|0;do{j=d;d=d+1|0;h=f;f=c[m+(d<<2)>>2]|0;c[m+(j<<2)>>2]=f<<29&536870912|h>>>1}while((d|0)!=8);c[e>>2]=(c[e>>2]|0)>>>1;e=0;do{g=(e|0)==8;d=0;f=c[m+(e<<2)>>2]|0;do{if(g&(f|0)==0)break;if(f&1|0){h=k;j=h+72|0;do{c[h>>2]=0;h=h+4|0}while((h|0)<(j|0));Sa(a,l,k);Ua(l,k,b)}f=f>>>1;h=k;j=h+72|0;do{c[h>>2]=0;h=h+4|0}while((h|0)<(j|0));Sa(a,a,k);Ua(a,k,b);d=d+1|0}while(d>>>0<30);e=e+1|0}while((e|0)!=9);Qa(l,b);h=a;d=l;j=h+36|0;do{c[h>>2]=c[d>>2];h=h+4|0;d=d+4|0}while((h|0)<(j|0));i=n;return}function Xa(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0;v=i;i=i+112|0;d=v+72|0;u=v+32|0;t=v;Pa(a,b);Qa(a,b);e=c[b>>2]|0;f=0;while(1){r=f;f=f+1|0;g=c[b+(f<<2)>>2]|0;h=r<<1;p=g<<30-h|e;c[t+(r<<2)>>2]=p;c[d+(r<<2)>>2]=p;if((f|0)==8)break;else e=g>>>(h+2|0)}e=c[a>>2]|0;f=0;while(1){r=f;f=f+1|0;b=c[a+(f<<2)>>2]|0;g=r<<1;c[u+(r<<2)>>2]=b<<30-g|e;if((f|0)==8)break;else e=b>>>(g+2|0)}o=d+36|0;c[o>>2]=8;p=u+36|0;c[p>>2]=8;r=d+32|0;c[r>>2]=1;c[u+32>>2]=0;f=0;n=u;e=8;g=c[d>>2]|0;b=1;a:while(1){if(!(g&1)){q=7;break}if(!(b&1)){q=10;break}l=n+36|0;b=e;while(1){e=b+-1|0;if(c[n+(e<<2)>>2]|0)break;c[l>>2]=e;if((b|0)<1)break a;else b=e}e=c[n>>2]|0;if(!e){g=n+32|0;do{e=0;do{m=e;e=e+1|0;c[n+(m<<2)>>2]=c[n+(e<<2)>>2]}while((e|0)!=8);c[g>>2]=0;b=(c[l>>2]|0)+-1|0;c[l>>2]=b;f=f+32|0;e=c[n>>2]|0}while((e|0)==0)}k=0;while(1)if(!(e&1<0){e=e>>>k;if((b|0)>1){j=32-k|0;g=1;h=n;while(1){b=n+(g<<2)|0;c[h>>2]=c[b>>2]<>2]|0)>>>k;if((e|0)<(c[l>>2]|0)){g=e;e=h;h=b}else break}}else{g=0;h=e;b=n;e=1}c[b>>2]=h;if(!h)c[l>>2]=(c[l>>2]|0)+-1;else g=e;e=n+(g<<2)|0;b=c[e>>2]<>2]=(c[e>>2]|0)>>>h|b;b=c[e>>2]<>2]=b;m=k+f|0}else m=f;if(!(c[n>>2]&1)){q=32;break}if(c[n+32>>2]&1|0){q=34;break}f=c[o>>2]|0;e=f-(c[p>>2]|0)|0;if(!e){e=f;while(1){b=e+-1|0;if((e|0)<=0){q=38;break}e=c[d+(b<<2)>>2]|0;f=u+(b<<2)|0;if((e|0)==(c[f>>2]|0))e=b;else break}if((q|0)==38){q=0;if(!e){q=56;break}f=u+(b<<2)|0;e=c[d+(b<<2)>>2]|0}e=e>>>0>(c[f>>2]|0)>>>0?1:-1}n=(e|0)>0;l=n?u:d;n=n?d:u;k=l+36|0;h=c[k>>2]|0;if((h|0)>0){e=0;f=1;b=0;while(1){j=n+(e<<2)|0;w=c[j>>2]|0;g=c[l+(e<<2)>>2]|0;f=qc(f|0,b|0,-1,0)|0;f=qc(f|0,C|0,w|0,0)|0;g=kc(f|0,C|0,g|0,0)|0;f=C;c[j>>2]=g;e=e+1|0;if((e|0)<(h|0))b=0;else{b=e;g=0;break}}}else{b=0;f=1;g=0}j=n+36|0;e=c[j>>2]|0;if((b|0)<(e|0)){e=g;while(1){w=n+(b<<2)|0;g=c[w>>2]|0;e=qc(f|0,e|0,-1,0)|0;e=qc(e|0,C|0,g|0,0)|0;c[w>>2]=e;b=b+1|0;e=c[j>>2]|0;if((b|0)>=(e|0))break;else{f=C;e=0}}}if((e|0)>8){f=8;g=0;b=0}else{f=8;g=0;b=0;while(1){w=l+(f<<2)|0;j=c[n+(f<<2)>>2]|0;h=qc(c[w>>2]|0,0,g|0,b|0)|0;j=qc(h|0,C|0,j|0,0)|0;g=C;c[w>>2]=j;w=f;f=f+-1|0;if((w|0)<=(e|0))break;else b=0}h=c[k>>2]|0;b=0}if((f|0)>=(h|0))while(1){w=l+(f<<2)|0;j=qc(c[w>>2]|0,0,g|0,b|0)|0;c[w>>2]=j;if((f|0)>(c[k>>2]|0)){f=f+-1|0;g=C;b=0}else break}g=c[l>>2]|0;if(!(g&1)){q=51;break}b=c[l+32>>2]|0;if(!(b&1)){q=53;break}if(c[n>>2]&1|0){q=55;break}else f=m}if((q|0)==7)pa(38321,38223,646,38335);else if((q|0)==10)pa(38346,38223,647,38335);else if((q|0)==32)pa(38360,38223,699,38335);else if((q|0)==34)pa(38375,38223,700,38335);else if((q|0)==51)pa(38321,38223,757,38335);else if((q|0)==53)pa(38346,38223,758,38335);else if((q|0)==55)pa(38397,38223,759,38335);else if((q|0)==56){l=c[t>>2]|0;if(!(l&1))pa(38419,38223,786,38335);f=l+-1|0;e=l+-2|0;if(!f)k=e;else{do{f=R(f,f)|0;e=R(f+1|0,e)|0}while((f|0)!=0);k=e}b:do if((m|0)>31){j=d+4|0;e=m;while(1){w=c[r>>2]|0;b=R(w,k)|0;q=pc(l|0,0,b|0,0)|0;w=qc(q|0,C|0,w|0,0)|0;if(!((w|0)==0&0==0))break;f=0;g=C;h=0;while(1){w=f;f=f+1|0;o=c[d+(7-w<<2)>>2]|0;p=pc(c[t+(f<<2)>>2]|0,0,b|0,0)|0;q=C;o=qc(o|0,0,g|0,h|0)|0;q=qc(o|0,C|0,p|0,q|0)|0;g=C;c[d+(8-w<<2)>>2]=q;if((f|0)==7)break;else h=0}c[j>>2]=g;e=e+-32|0;if((e|0)<=31){s=e;break b}}pa(38429,38223,802,38335)}else s=m;while(0);if((s|0)>0){w=(1<>2]|0;h=(R(e,k)|0)&w;if((R(h,l)|0)+e&w|0)pa(38454,38223,821,38335);b=pc(h|0,0,l|0,0)|0;b=qc(b|0,C|0,e|0,0)|0;b=mc(b|0,C|0,s|0)|0;f=32-s|0;e=0;g=C;while(1){w=e;e=e+1|0;s=c[d+(7-w<<2)>>2]|0;r=pc(c[t+(e<<2)>>2]|0,0,h|0,0)|0;s=qc(r|0,C|0,s|0,0)|0;s=nc(s|0,C|0,f|0)|0;s=qc(s|0,C|0,b|0,g|0)|0;b=C;c[d+(8-w<<2)>>2]=s;if((e|0)==7)break;else g=0}c[d+4>>2]=b;e=0;f=0}else{e=0;f=0}do{s=c[d+(8-e<<2)>>2]|0;w=e<<1;c[a+(e<<2)>>2]=s<>>(30-w|0);e=e+1|0}while((e|0)!=8);c[a+32>>2]=f;c[t>>2]=0;c[t+4>>2]=0;c[t+8>>2]=0;c[t+12>>2]=0;c[t+16>>2]=0;c[t+20>>2]=0;c[t+24>>2]=0;c[t+28>>2]=0;e=d+40|0;do{c[d>>2]=0;d=d+4|0}while((d|0)<(e|0));d=u;e=d+40|0;do{c[d>>2]=0;d=d+4|0}while((d|0)<(e|0))}i=v;return}function Ya(a,b){a=a|0;b=b|0;var d=0,e=0,f=0;e=0;d=0;while(1){f=a+(e<<2)|0;d=(c[f>>2]|0)+d+(c[b+(e<<2)>>2]|0)|0;c[f>>2]=d&1073741823;e=e+1|0;if((e|0)==9)break;else d=d>>>30}return}function Za(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0;e=0;do{f=a+(e<<2)|0;c[f>>2]=(c[f>>2]|0)+(c[b+(e<<2)>>2]|0);e=e+1|0}while((e|0)!=9);Pa(a,d);return}function _a(a,b,d){a=a|0;b=b|0;d=d|0;var e=0;if((c[d>>2]|0)>>>0>>0)pa(38495,38223,883,38514);b=(c[a>>2]|0)-b|0;c[a>>2]=b;b=b+(c[d>>2]|0)|0;c[a>>2]=b&1073741823;e=1;do{b=(c[a+(e<<2)>>2]|0)+(b>>>30)+(c[d+(e<<2)>>2]|0)|0;c[a+(e<<2)>>2]=b&1073741823;e=e+1|0}while((e|0)!=9);return}function $a(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0;g=0;f=1;while(1){f=f+1073741823+(c[a+(g<<2)>>2]|0)+(c[e+(g<<2)>>2]<<1)-(c[b+(g<<2)>>2]|0)|0;c[d+(g<<2)>>2]=f&1073741823;g=g+1|0;if((g|0)==9)break;else f=f>>>30}return}function ab(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0;n=i;i=i+144|0;k=n+108|0;e=n+72|0;l=n+36|0;m=n;do if(!(bb(b)|0)){if(bb(d)|0){e=d;f=b;g=e+72|0;do{c[e>>2]=c[f>>2];e=e+4|0;f=f+4|0}while((e|0)<(g|0));break}if(cb(b,d)|0){db(a,d);break}if(!(eb(b,d)|0)){$a(d,b,e,a);Xa(e,a);h=d+36|0;j=b+36|0;$a(h,j,k,a);Va(e,k,a);e=l;f=k;g=e+36|0;do{c[e>>2]=c[f>>2];e=e+4|0;f=f+4|0}while((e|0)<(g|0));Va(l,l,a);e=m;f=b;g=e+36|0;do{c[e>>2]=c[f>>2];e=e+4|0;f=f+4|0}while((e|0)<(g|0));Za(m,d,a);$a(l,m,l,a);Pa(l,a);Qa(l,a);$a(b,l,m,a);Va(k,m,a);$a(m,j,m,a);Pa(m,a);Qa(m,a);e=d;f=l;g=e+36|0;do{c[e>>2]=c[f>>2];e=e+4|0;f=f+4|0}while((e|0)<(g|0));e=h;f=m;g=e+36|0;do{c[e>>2]=c[f>>2];e=e+4|0;f=f+4|0}while((e|0)<(g|0));break}else{Ha(d);Ha(d+36|0);break}}while(0);i=n;return}function bb(a){a=a|0;if(!(Ia(a)|0))a=0;else a=(Ia(a+36|0)|0)!=0;return a&1|0}function cb(a,b){a=a|0;b=b|0;if(!(Ka(a,b)|0))a=0;else a=(Ka(a+36|0,b+36|0)|0)!=0;return a&1|0}function db(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0,l=0;j=i;i=i+112|0;d=j+72|0;e=j+36|0;f=j;do if(!(bb(b)|0)){g=b+36|0;if(!(Ia(g)|0)){h=d;k=g;l=h+36|0;do{c[h>>2]=c[k>>2];h=h+4|0;k=k+4|0}while((h|0)<(l|0));Oa(d,2,a);Xa(d,a);h=e;k=b;l=h+36|0;do{c[h>>2]=c[k>>2];h=h+4|0;k=k+4|0}while((h|0)<(l|0));Va(e,e,a);Oa(e,3,a);_a(e,0-(c[a+180>>2]|0)|0,a);Va(e,d,a);h=e;k=d;l=h+36|0;do{c[h>>2]=c[k>>2];h=h+4|0;k=k+4|0}while((h|0)<(l|0));Va(e,e,a);h=f;k=b;l=h+36|0;do{c[h>>2]=c[k>>2];h=h+4|0;k=k+4|0}while((h|0)<(l|0));Ma(f);$a(e,f,e,a);Pa(e,a);Qa(e,a);$a(b,e,f,a);Va(d,f,a);$a(f,g,f,a);Pa(f,a);Qa(f,a);h=b;k=e;l=h+36|0;do{c[h>>2]=c[k>>2];h=h+4|0;k=k+4|0}while((h|0)<(l|0));h=g;k=f;l=h+36|0;do{c[h>>2]=c[k>>2];h=h+4|0;k=k+4|0}while((h|0)<(l|0));break}else{Ha(b);Ha(g);break}}while(0);i=j;return}function eb(a,b){a=a|0;b=b|0;var c=0;if((Ka(a,b)|0)!=0?(c=a+36|0,(Ia(c)|0)==0):0)a=(Ka(c,b+36|0)|0)==0&1;else a=0;return a|0}function fb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0,j=0;g=b+32|0;if((c[g>>2]|0)>>>0>=131072)pa(38522,38542,180,38553);h=a&1073741823;f=~a;a=c[b>>2]|0;e=(c[d>>2]<<1)+1073741824-a|0;c[b>>2]=h&e|a&f;a=0;do{a=a+1|0;i=b+(a<<2)|0;j=c[i>>2]|0;e=(e>>>30)+1073741823+(c[d+(a<<2)>>2]<<1)-j|0;c[i>>2]=h&e|j&f}while((a|0)!=8);if((c[g>>2]|0)>>>0<131072)return;else pa(38522,38542,188,38553)}function gb(a,b){a=a|0;b=b|0;var d=0,e=0,f=0;e=a+32|0;while(1){d=0;f=Kb()|0;do{c[a+(d<<2)>>2]=f&1073741823;d=d+1|0;f=Kb()|0}while((d|0)!=8);c[e>>2]=f&65535;if(Ia(a)|0)continue;if(Ja(a,b)|0)break}return}function hb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0;e=b+72|0;gb(e,d);g=b;h=e;i=g+36|0;do{c[g>>2]=c[h>>2];g=g+4|0;h=h+4|0}while((g|0)<(i|0));Va(e,b,d);f=b+36|0;g=f;h=b;i=g+36|0;do{c[g>>2]=c[h>>2];g=g+4|0;h=h+4|0}while((g|0)<(i|0));Va(e,f,d);Va(a,b,d);Va(a+36|0,f,d);return}function ib(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0;e=b+36|0;f=e;g=a+72|0;h=f+36|0;do{c[f>>2]=c[g>>2];f=f+4|0;g=g+4|0}while((f|0)<(h|0));Xa(e,d);f=b;g=e;h=f+36|0;do{c[f>>2]=c[g>>2];f=f+4|0;g=g+4|0}while((f|0)<(h|0));Va(b,b,d);Va(b,e,d);Va(a,b,d);Va(a+36|0,e,d);Qa(b,d);Qa(e,d);return}function jb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0;s=i;i=i+288|0;k=s+252|0;l=s+216|0;m=s+180|0;n=s+144|0;o=s+108|0;p=s+72|0;q=s+36|0;g=s;e=c[d+180>>2]|0;if((e+3|0)>>>0>=4)pa(38572,38542,247,38590);h=b+72|0;r=p;t=h;u=r+36|0;do{c[r>>2]=c[t>>2];r=r+4|0;t=t+4|0}while((r|0)<(u|0));Va(p,p,d);r=q;t=h;u=r+36|0;do{c[r>>2]=c[t>>2];r=r+4|0;t=t+4|0}while((r|0)<(u|0));Va(p,q,d);j=(e|0)!=0;if(j){e=0-e|0;r=g;t=p;u=r+36|0;do{c[r>>2]=c[t>>2];r=r+4|0;t=t+4|0}while((r|0)<(u|0));Va(g,g,d);Oa(g,e&255,d)}Va(a,p,d);r=l;t=p;u=r+36|0;do{c[r>>2]=c[t>>2];r=r+4|0;t=t+4|0}while((r|0)<(u|0));$a(l,b,l,d);Pa(l,d);Ya(p,b);f=Ka(l,d)|0;Va(a+36|0,q,d);e=b+36|0;$a(q,e,k,d);Ya(q,e);r=m;t=b;u=r+36|0;do{c[r>>2]=c[t>>2];r=r+4|0;t=t+4|0}while((r|0)<(u|0));Va(m,m,d);Oa(m,3,d);if(j)$a(m,g,m,d);La(k,f,m,k);La(l,f,q,l);r=o;t=l;u=r+36|0;do{c[r>>2]=c[t>>2];r=r+4|0;t=t+4|0}while((r|0)<(u|0));Va(o,o,d);r=n;t=l;u=r+36|0;do{c[r>>2]=c[t>>2];r=r+4|0;t=t+4|0}while((r|0)<(u|0));Va(o,n,d);Va(p,o,d);Va(q,n,d);Va(l,h,d);r=b;t=k;u=r+36|0;do{c[r>>2]=c[t>>2];r=r+4|0;t=t+4|0}while((r|0)<(u|0));Va(b,b,d);$a(b,o,b,d);Pa(b,d);$a(o,b,e,d);$a(e,b,e,d);Va(k,e,d);$a(e,n,e,d);Na(e,d);Pa(e,d);i=s;return}function kb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0;n=i;i=i+144|0;l=n+108|0;m=n;if(!(Ja(b,a+108|0)|0))pa(38609,38542,552,38658);j=c[b>>2]|0;g=(j&1)+-1|0;f=1;e=0;h=j;do{k=f+1073741823+h-(c[a+108+(e<<2)>>2]&g)|0;c[l+(e<<2)>>2]=k&1073741823;f=k>>>30;e=e+1|0;h=c[b+(e<<2)>>2]|0;j=h|j}while((e|0)!=8);k=l+32|0;c[k>>2]=f+65535+h-(c[a+140>>2]&g);e=c[l>>2]|0;if(!(e&1))pa(38638,38542,575,38658);if(!j){Ha(d);Ha(d+36|0)}else{hb(a+220+((((e>>>4&1)+15^e)>>>1&7)*72|0)|0,m,a);h=m+36|0;g=1;do{f=0;e=e>>>4;b=l;do{f=f+1|0;j=b;b=l+(f<<2)|0;c[j>>2]=c[b>>2]<<26&1006632960|e;e=(c[b>>2]|0)>>>4}while((f|0)!=8);c[k>>2]=e;e=c[l>>2]|0;b=e>>>4&1;j=b+15^e;fb((j&1)+-1|0,h,a);jb(a+220+(g*576|0)+((j>>>1&7)*72|0)|0,m,a);g=g+1|0}while((g|0)!=64);fb(b+-1|0,h,a);ib(m,d,a)}i=n;return}function lb(b,c,d){b=b|0;c=c|0;d=d|0;b=(b|0)==0?712:b;switch(a[c>>0]|0){case 4:{Fa(c+1|0,d);Fa(c+33|0,d+36|0);b=mb(b,d)|0;break}case 3:case 2:{Fa(c+1|0,d);nb(b,a[c>>0]|0,d,d+36|0);b=mb(b,d)|0;break}default:b=0}return b|0}function mb(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0;k=i;i=i+80|0;d=k+36|0;e=k;if(((bb(b)|0)==0?(Ja(b,a)|0)!=0:0)?(f=b+36|0,(Ja(f,a)|0)!=0):0){g=d;h=f;j=g+36|0;do{c[g>>2]=c[h>>2];g=g+4|0;h=h+4|0}while((g|0)<(j|0));g=e;h=b;j=g+36|0;do{c[g>>2]=c[h>>2];g=g+4|0;h=h+4|0}while((g|0)<(j|0));Va(f,d,a);Qa(d,a);Va(b,e,a);_a(e,0-(c[a+180>>2]|0)|0,a);Va(b,e,a);Za(e,a+184|0,a);Qa(e,a);a=(Ka(e,d)|0)!=0&1}else a=0;i=k;return a|0}function nb(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0;f=e;g=d;h=f+36|0;do{c[f>>2]=c[g>>2];f=f+4|0;g=g+4|0}while((f|0)<(h|0));Va(d,e,a);_a(e,0-(c[a+180>>2]|0)|0,a);Va(d,e,a);Ya(e,a+184|0);Wa(e,a);if((c[e>>2]^b&255)&1|0)Ra(a,e,e);return}function ob(b,c){b=b|0;c=c|0;var d=0,e=0;e=i;i=i+32|0;d=e;switch(a[b>>0]|0){case 4:{Eb(b,65,d);break}case 0:{Eb(b,1,d);break}default:Eb(b,33,d)}Ab(d,32,c);i=e;return}function pb(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0,f=0,g=0,h=0;e=i;i=i+48|0;g=e;f=Lb(b)|0;h=Lb(b)|0;Mb(b,g);ob(a,g+h|0);wb(g,f+20|0,c,d)|0;i=e;return}function qb(b,c,e){b=b|0;c=c|0;e=e|0;var f=0,g=0,h=0,j=0;j=i;i=i+128|0;h=j;f=h;g=f+128|0;do{a[f>>0]=0;f=f+1|0}while((f|0)<(g|0));if(e>>>0>128){Jb(c,e,h);c=0}else{tc(h|0,c|0,e|0)|0;c=0}do{g=h+c|0;f=d[g>>0]|0;a[b+c>>0]=f^92;a[g>>0]=f^54;c=c+1|0}while((c|0)!=128);b=b+128|0;Fb(b);Hb(b,h,128);i=j;return}function rb(a,b){a=a|0;b=b|0;var c=0,d=0,e=0;c=i;i=i+64|0;e=c;d=a+128|0;Ib(d,e);Fb(d);Hb(d,a,128);Hb(d,e,64);Ib(d,b);lc(a|0,0,336)|0;i=c;return}function sb(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;var f=0,g=0;f=i;i=i+336|0;g=f;qb(g,a,b);Hb(g+128|0,c,d);rb(g,e);i=f;return}function tb(b,d,e,f,g,h){b=b|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;var j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0;r=i;i=i+144|0;o=r+104|0;p=r+40|0;q=r;if((f|0)<0)f=0;else{a[o>>0]=c[d+36>>2]&1|2;n=o+1|0;Ga(d,n);Ea(o+33|0,f);f=b+108|0;j=p+32|0;while(1){sb(e,32,o,37,p);Fa(p,q);if(Ja(q,f)|0?(kb(b,q,g),ab(b,d,g),(bb(g)|0)==0):0)break;a[o>>0]=1;k=n;l=j;m=k+32|0;do{a[k>>0]=a[l>>0]|0;k=k+1|0;l=l+1|0}while((k|0)<(m|0))}if(h|0){k=h;l=j;m=k+32|0;do{a[k>>0]=a[l>>0]|0;k=k+1|0;l=l+1|0}while((k|0)<(m|0))}k=o;m=k+37|0;do{a[k>>0]=0;k=k+1|0}while((k|0)<(m|0));k=p;m=k+64|0;do{a[k>>0]=0;k=k+1|0}while((k|0)<(m|0));k=q;m=k+36|0;do{c[k>>2]=0;k=k+4|0}while((k|0)<(m|0));f=1}i=r;return f|0}function ub(b,d,e,f,g,h,j){b=b|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;j=j|0;var k=0,l=0,m=0,n=0,o=0;n=i;i=i+192|0;l=n+152|0;o=n;m=n+120|0;k=n+72|0;tb(712,b,d,e,o,0)|0;a[l>>0]=c[o+36>>2]&1|2;Ga(o,l+1|0);if(j){b=Lb(f)|0;a[m>>0]=0;a[m+1>>0]=20;ob(l,m+2|0);Eb(m,22,k);Mb(f,m);Ab(k,32,m+b|0);b=(wb(m,b+20|0,g,54)|0)!=0&1}else{pb(l,f,g,h);b=1}i=n;return b|0}function vb(b,e,f,g){b=b|0;e=e|0;f=f|0;g=g|0;var h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0;q=i;a:do if((g|0)>0){h=0;do{if(a[f+h>>0]|0)break a;h=h+1|0}while((h|0)<(g|0))}else h=0;while(0);o=(((g-h|0)*138|0)>>>0)/100|0;n=o+1|0;p=i;i=i+((1*n|0)+15&-16)|0;lc(p|0,0,n|0)|0;if((h|0)<(g|0)){j=o;m=h;do{k=a[f+m>>0]|0;if((o|0)>(j|0)|k<<24>>24!=0){k=k&255;l=o;while(1){r=p+l|0;k=(d[r>>0]<<8)+k|0;a[r>>0]=(k|0)%58|0;l=l+-1|0;if((l|0)>(j|0)|(k+57|0)>>>0>114)k=(k|0)/58|0;else{j=l;break}}}else j=o;m=m+1|0}while((m|0)!=(g|0));j=0}else j=0;while(1){if(a[p+j>>0]|0)break;k=j+1|0;if((j|0)<(o|0))j=k;else{j=k;break}}k=n+h-j|0;if((c[e>>2]|0)>>>0>k>>>0){if(!h)h=0;else lc(b|0,49,h|0)|0;if((j|0)<=(o|0))while(1){a[b+h>>0]=a[38674+(d[p+j>>0]|0)>>0]|0;h=h+1|0;if((j|0)<(o|0))j=j+1|0;else break}a[b+h>>0]=0;j=1}else{j=0;h=k}c[e>>2]=h+1;i=q;return j|0}function wb(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,j=0,k=0,l=0;g=i;i=i+16|0;f=g;if((b|0)>128)a=0;else{j=b+32|0;h=ia()|0;k=i;i=i+((1*j|0)+15&-16)|0;l=k+b|0;tc(k|0,a|0,b|0)|0;Eb(a,b,l);Eb(l,32,l);c[f>>2]=e;a=vb(d,f,k,b+4|0)|0;lc(k|0,0,j|0)|0;a=a?c[f>>2]|0:0;oa(h|0)}i=g;return a|0}function xb(a,b){a=a|0;b=b|0;var e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0;s=(d[b+1>>0]|0)<<8|(d[b>>0]|0)|(d[b+2>>0]|0)<<16|(d[b+3>>0]|0)<<24;D=(d[b+5>>0]|0)<<8|(d[b+4>>0]|0)|(d[b+6>>0]|0)<<16|(d[b+7>>0]|0)<<24;v=(d[b+9>>0]|0)<<8|(d[b+8>>0]|0)|(d[b+10>>0]|0)<<16|(d[b+11>>0]|0)<<24;f=(d[b+13>>0]|0)<<8|(d[b+12>>0]|0)|(d[b+14>>0]|0)<<16|(d[b+15>>0]|0)<<24;x=(d[b+17>>0]|0)<<8|(d[b+16>>0]|0)|(d[b+18>>0]|0)<<16|(d[b+19>>0]|0)<<24;t=(d[b+21>>0]|0)<<8|(d[b+20>>0]|0)|(d[b+22>>0]|0)<<16|(d[b+23>>0]|0)<<24;y=(d[b+25>>0]|0)<<8|(d[b+24>>0]|0)|(d[b+26>>0]|0)<<16|(d[b+27>>0]|0)<<24;z=(d[b+29>>0]|0)<<8|(d[b+28>>0]|0)|(d[b+30>>0]|0)<<16|(d[b+31>>0]|0)<<24;B=(d[b+33>>0]|0)<<8|(d[b+32>>0]|0)|(d[b+34>>0]|0)<<16|(d[b+35>>0]|0)<<24;i=(d[b+37>>0]|0)<<8|(d[b+36>>0]|0)|(d[b+38>>0]|0)<<16|(d[b+39>>0]|0)<<24;F=(d[b+41>>0]|0)<<8|(d[b+40>>0]|0)|(d[b+42>>0]|0)<<16|(d[b+43>>0]|0)<<24;l=(d[b+45>>0]|0)<<8|(d[b+44>>0]|0)|(d[b+46>>0]|0)<<16|(d[b+47>>0]|0)<<24;H=(d[b+49>>0]|0)<<8|(d[b+48>>0]|0)|(d[b+50>>0]|0)<<16|(d[b+51>>0]|0)<<24;u=(d[b+53>>0]|0)<<8|(d[b+52>>0]|0)|(d[b+54>>0]|0)<<16|(d[b+55>>0]|0)<<24;m=(d[b+57>>0]|0)<<8|(d[b+56>>0]|0)|(d[b+58>>0]|0)<<16|(d[b+59>>0]|0)<<24;w=(d[b+61>>0]|0)<<8|(d[b+60>>0]|0)|(d[b+62>>0]|0)<<16|(d[b+63>>0]|0)<<24;b=a+8|0;A=c[b>>2]|0;p=a+12|0;e=c[p>>2]|0;n=a+16|0;r=c[n>>2]|0;k=a+20|0;I=c[k>>2]|0;g=a+24|0;E=c[g>>2]|0;j=A+s+(r^e^I)|0;j=(j<<11|j>>>21)+E|0;C=r<<10|r>>>22;A=t+1352829926+A+((r|~I)^e)|0;A=(A<<8|A>>>24)+E|0;o=E+D+(C^e^j)|0;o=(o<<14|o>>>18)+I|0;G=e<<10|e>>>22;E=m+1352829926+E+(A^(e|~C))|0;E=(E<<9|E>>>23)+I|0;J=I+v+(j^G^o)|0;J=(J<<15|J>>>17)+C|0;j=j<<10|j>>>22;I=z+1352829926+I+(E^(A|~G))|0;I=(I<<9|I>>>23)+C|0;A=A<<10|A>>>22;a=C+f+(o^j^J)|0;a=(a<<12|a>>>20)+G|0;o=o<<10|o>>>22;C=s+1352829926+C+(I^(E|~A))|0;C=(C<<11|C>>>21)+G|0;E=E<<10|E>>>22;h=G+x+(J^o^a)|0;h=(h<<5|h>>>27)+j|0;J=J<<10|J>>>22;G=i+1352829926+G+(C^(I|~E))|0;G=(G<<13|G>>>19)+A|0;I=I<<10|I>>>22;j=j+t+(a^J^h)|0;j=(j<<8|j>>>24)+o|0;a=a<<10|a>>>22;A=v+1352829926+A+(G^(C|~I))|0;A=(A<<15|A>>>17)+E|0;C=C<<10|C>>>22;o=o+y+(h^a^j)|0;o=(o<<7|o>>>25)+J|0;h=h<<10|h>>>22;E=l+1352829926+E+(A^(G|~C))|0;E=(E<<15|E>>>17)+I|0;G=G<<10|G>>>22;J=J+z+(j^h^o)|0;J=(J<<9|J>>>23)+a|0;j=j<<10|j>>>22;I=x+1352829926+I+(E^(A|~G))|0;I=(I<<5|I>>>27)+C|0;A=A<<10|A>>>22;a=a+B+(o^j^J)|0;a=(a<<11|a>>>21)+h|0;o=o<<10|o>>>22;C=u+1352829926+C+(I^(E|~A))|0;C=(C<<7|C>>>25)+G|0;E=E<<10|E>>>22;h=h+i+(J^o^a)|0;h=(h<<13|h>>>19)+j|0;J=J<<10|J>>>22;G=y+1352829926+G+(C^(I|~E))|0;G=(G<<7|G>>>25)+A|0;I=I<<10|I>>>22;j=j+F+(a^J^h)|0;j=(j<<14|j>>>18)+o|0;a=a<<10|a>>>22;A=w+1352829926+A+(G^(C|~I))|0;A=(A<<8|A>>>24)+E|0;C=C<<10|C>>>22;o=o+l+(h^a^j)|0;o=(o<<15|o>>>17)+J|0;h=h<<10|h>>>22;E=B+1352829926+E+(A^(G|~C))|0;E=(E<<11|E>>>21)+I|0;G=G<<10|G>>>22;J=J+H+(j^h^o)|0;J=(J<<6|J>>>26)+a|0;j=j<<10|j>>>22;I=D+1352829926+I+(E^(A|~G))|0;I=(I<<14|I>>>18)+C|0;A=A<<10|A>>>22;a=a+u+(o^j^J)|0;a=(a<<7|a>>>25)+h|0;o=o<<10|o>>>22;C=F+1352829926+C+(I^(E|~A))|0;C=(C<<14|C>>>18)+G|0;E=E<<10|E>>>22;h=h+m+(J^o^a)|0;h=(h<<9|h>>>23)+j|0;J=J<<10|J>>>22;G=f+1352829926+G+(C^(I|~E))|0;G=(G<<12|G>>>20)+A|0;I=I<<10|I>>>22;j=j+w+(a^J^h)|0;j=(j<<8|j>>>24)+o|0;a=a<<10|a>>>22;A=H+1352829926+A+(G^(C|~I))|0;A=(A<<6|A>>>26)+E|0;C=C<<10|C>>>22;o=z+1518500249+o+(j&h|a&~j)|0;o=(o<<7|o>>>25)+J|0;h=h<<10|h>>>22;E=y+1548603684+E+(A&C|G&~C)|0;E=(E<<9|E>>>23)+I|0;G=G<<10|G>>>22;J=x+1518500249+J+(o&j|h&~o)|0;J=(J<<6|J>>>26)+a|0;j=j<<10|j>>>22;I=l+1548603684+I+(E&G|A&~G)|0;I=(I<<13|I>>>19)+C|0;A=A<<10|A>>>22;a=u+1518500249+a+(J&o|j&~J)|0;a=(a<<8|a>>>24)+h|0;o=o<<10|o>>>22;C=f+1548603684+C+(I&A|E&~A)|0;C=(C<<15|C>>>17)+G|0;E=E<<10|E>>>22;h=D+1518500249+h+(a&J|o&~a)|0;h=(h<<13|h>>>19)+j|0;J=J<<10|J>>>22;G=z+1548603684+G+(C&E|I&~E)|0;G=(G<<7|G>>>25)+A|0;I=I<<10|I>>>22;j=F+1518500249+j+(h&a|J&~h)|0;j=(j<<11|j>>>21)+o|0;a=a<<10|a>>>22;A=s+1548603684+A+(G&I|C&~I)|0;A=(A<<12|A>>>20)+E|0;C=C<<10|C>>>22;o=y+1518500249+o+(j&h|a&~j)|0;o=(o<<9|o>>>23)+J|0;h=h<<10|h>>>22;E=u+1548603684+E+(A&C|G&~C)|0;E=(E<<8|E>>>24)+I|0;G=G<<10|G>>>22;J=w+1518500249+J+(o&j|h&~o)|0;J=(J<<7|J>>>25)+a|0;j=j<<10|j>>>22;I=t+1548603684+I+(E&G|A&~G)|0;I=(I<<9|I>>>23)+C|0;A=A<<10|A>>>22;a=f+1518500249+a+(J&o|j&~J)|0;a=(a<<15|a>>>17)+h|0;o=o<<10|o>>>22;C=F+1548603684+C+(I&A|E&~A)|0;C=(C<<11|C>>>21)+G|0;E=E<<10|E>>>22;h=H+1518500249+h+(a&J|o&~a)|0;h=(h<<7|h>>>25)+j|0;J=J<<10|J>>>22;G=m+1548603684+G+(C&E|I&~E)|0;G=(G<<7|G>>>25)+A|0;I=I<<10|I>>>22;j=s+1518500249+j+(h&a|J&~h)|0;j=(j<<12|j>>>20)+o|0;a=a<<10|a>>>22;A=w+1548603684+A+(G&I|C&~I)|0;A=(A<<7|A>>>25)+E|0;C=C<<10|C>>>22;o=i+1518500249+o+(j&h|a&~j)|0;o=(o<<15|o>>>17)+J|0;h=h<<10|h>>>22;E=B+1548603684+E+(A&C|G&~C)|0;E=(E<<12|E>>>20)+I|0;G=G<<10|G>>>22;J=t+1518500249+J+(o&j|h&~o)|0;J=(J<<9|J>>>23)+a|0;j=j<<10|j>>>22;I=H+1548603684+I+(E&G|A&~G)|0;I=(I<<7|I>>>25)+C|0;A=A<<10|A>>>22;a=v+1518500249+a+(J&o|j&~J)|0;a=(a<<11|a>>>21)+h|0;o=o<<10|o>>>22;C=x+1548603684+C+(I&A|E&~A)|0;C=(C<<6|C>>>26)+G|0;E=E<<10|E>>>22;h=m+1518500249+h+(a&J|o&~a)|0;h=(h<<7|h>>>25)+j|0;J=J<<10|J>>>22;G=i+1548603684+G+(C&E|I&~E)|0;G=(G<<15|G>>>17)+A|0;I=I<<10|I>>>22;j=l+1518500249+j+(h&a|J&~h)|0;j=(j<<13|j>>>19)+o|0;a=a<<10|a>>>22;A=D+1548603684+A+(G&I|C&~I)|0;A=(A<<13|A>>>19)+E|0;C=C<<10|C>>>22;q=~j;o=B+1518500249+o+(j&h|a&q)|0;o=(o<<12|o>>>20)+J|0;h=h<<10|h>>>22;E=v+1548603684+E+(A&C|G&~C)|0;E=(E<<11|E>>>21)+I|0;G=G<<10|G>>>22;q=f+1859775393+J+((o|q)^h)|0;q=(q<<11|q>>>21)+a|0;j=j<<10|j>>>22;I=w+1836072691+I+((E|~A)^G)|0;I=(I<<9|I>>>23)+C|0;A=A<<10|A>>>22;a=F+1859775393+a+((q|~o)^j)|0;a=(a<<13|a>>>19)+h|0;o=o<<10|o>>>22;C=t+1836072691+C+((I|~E)^A)|0;C=(C<<7|C>>>25)+G|0;E=E<<10|E>>>22;h=m+1859775393+h+((a|~q)^o)|0;h=(h<<6|h>>>26)+j|0;q=q<<10|q>>>22;G=D+1836072691+G+((C|~I)^E)|0;G=(G<<15|G>>>17)+A|0;I=I<<10|I>>>22;j=x+1859775393+j+((h|~a)^q)|0;j=(j<<7|j>>>25)+o|0;a=a<<10|a>>>22;A=f+1836072691+A+((G|~C)^I)|0;A=(A<<11|A>>>21)+E|0;C=C<<10|C>>>22;o=i+1859775393+o+((j|~h)^a)|0;o=(o<<14|o>>>18)+q|0;h=h<<10|h>>>22;E=z+1836072691+E+((A|~G)^C)|0;E=(E<<8|E>>>24)+I|0;G=G<<10|G>>>22;q=w+1859775393+q+((o|~j)^h)|0;q=(q<<9|q>>>23)+a|0;j=j<<10|j>>>22;I=m+1836072691+I+((E|~A)^G)|0;I=(I<<6|I>>>26)+C|0;A=A<<10|A>>>22;a=B+1859775393+a+((q|~o)^j)|0;a=(a<<13|a>>>19)+h|0;o=o<<10|o>>>22;C=y+1836072691+C+((I|~E)^A)|0;C=(C<<6|C>>>26)+G|0;E=E<<10|E>>>22;h=D+1859775393+h+((a|~q)^o)|0;h=(h<<15|h>>>17)+j|0;q=q<<10|q>>>22;G=i+1836072691+G+((C|~I)^E)|0;G=(G<<14|G>>>18)+A|0;I=I<<10|I>>>22;j=v+1859775393+j+((h|~a)^q)|0;j=(j<<14|j>>>18)+o|0;a=a<<10|a>>>22;A=l+1836072691+A+((G|~C)^I)|0;A=(A<<12|A>>>20)+E|0;C=C<<10|C>>>22;o=z+1859775393+o+((j|~h)^a)|0;o=(o<<8|o>>>24)+q|0;h=h<<10|h>>>22;E=B+1836072691+E+((A|~G)^C)|0;E=(E<<13|E>>>19)+I|0;G=G<<10|G>>>22;q=s+1859775393+q+((o|~j)^h)|0;q=(q<<13|q>>>19)+a|0;j=j<<10|j>>>22;I=H+1836072691+I+((E|~A)^G)|0;I=(I<<5|I>>>27)+C|0;A=A<<10|A>>>22;a=y+1859775393+a+((q|~o)^j)|0;a=(a<<6|a>>>26)+h|0;o=o<<10|o>>>22;C=v+1836072691+C+((I|~E)^A)|0;C=(C<<14|C>>>18)+G|0;E=E<<10|E>>>22;h=u+1859775393+h+((a|~q)^o)|0;h=(h<<5|h>>>27)+j|0;q=q<<10|q>>>22;G=F+1836072691+G+((C|~I)^E)|0;G=(G<<13|G>>>19)+A|0;I=I<<10|I>>>22;j=l+1859775393+j+((h|~a)^q)|0;j=(j<<12|j>>>20)+o|0;a=a<<10|a>>>22;A=s+1836072691+A+((G|~C)^I)|0;A=(A<<13|A>>>19)+E|0;C=C<<10|C>>>22;o=t+1859775393+o+((j|~h)^a)|0;o=(o<<7|o>>>25)+q|0;h=h<<10|h>>>22;E=x+1836072691+E+((A|~G)^C)|0;E=(E<<7|E>>>25)+I|0;G=G<<10|G>>>22;q=H+1859775393+q+((o|~j)^h)|0;q=(q<<5|q>>>27)+a|0;j=j<<10|j>>>22;I=u+1836072691+I+((E|~A)^G)|0;I=(I<<5|I>>>27)+C|0;A=A<<10|A>>>22;a=D+-1894007588+a+(q&j|o&~j)|0;a=(a<<11|a>>>21)+h|0;o=o<<10|o>>>22;C=B+2053994217+C+(I&E|A&~I)|0;C=(C<<15|C>>>17)+G|0;E=E<<10|E>>>22;h=i+-1894007588+h+(a&o|q&~o)|0;h=(h<<12|h>>>20)+j|0;q=q<<10|q>>>22;G=y+2053994217+G+(C&I|E&~C)|0;G=(G<<5|G>>>27)+A|0;I=I<<10|I>>>22;j=l+-1894007588+j+(h&q|a&~q)|0;j=(j<<14|j>>>18)+o|0;a=a<<10|a>>>22;A=x+2053994217+A+(G&C|I&~G)|0;A=(A<<8|A>>>24)+E|0;C=C<<10|C>>>22;o=F+-1894007588+o+(j&a|h&~a)|0;o=(o<<15|o>>>17)+q|0;h=h<<10|h>>>22;E=D+2053994217+E+(A&G|C&~A)|0;E=(E<<11|E>>>21)+I|0;G=G<<10|G>>>22;q=s+-1894007588+q+(o&h|j&~h)|0;q=(q<<14|q>>>18)+a|0;j=j<<10|j>>>22;I=f+2053994217+I+(E&A|G&~E)|0;I=(I<<14|I>>>18)+C|0;A=A<<10|A>>>22;a=B+-1894007588+a+(q&j|o&~j)|0;a=(a<<15|a>>>17)+h|0;o=o<<10|o>>>22;C=l+2053994217+C+(I&E|A&~I)|0;C=(C<<14|C>>>18)+G|0;E=E<<10|E>>>22;h=H+-1894007588+h+(a&o|q&~o)|0;h=(h<<9|h>>>23)+j|0;q=q<<10|q>>>22;G=w+2053994217+G+(C&I|E&~C)|0;G=(G<<6|G>>>26)+A|0;I=I<<10|I>>>22;j=x+-1894007588+j+(h&q|a&~q)|0;j=(j<<8|j>>>24)+o|0;a=a<<10|a>>>22;A=s+2053994217+A+(G&C|I&~G)|0;A=(A<<14|A>>>18)+E|0;C=C<<10|C>>>22;o=u+-1894007588+o+(j&a|h&~a)|0;o=(o<<9|o>>>23)+q|0;h=h<<10|h>>>22;E=t+2053994217+E+(A&G|C&~A)|0;E=(E<<6|E>>>26)+I|0;G=G<<10|G>>>22;q=f+-1894007588+q+(o&h|j&~h)|0;q=(q<<14|q>>>18)+a|0;j=j<<10|j>>>22;I=H+2053994217+I+(E&A|G&~E)|0;I=(I<<9|I>>>23)+C|0;A=A<<10|A>>>22;a=z+-1894007588+a+(q&j|o&~j)|0;a=(a<<5|a>>>27)+h|0;o=o<<10|o>>>22;C=v+2053994217+C+(I&E|A&~I)|0;C=(C<<12|C>>>20)+G|0;E=E<<10|E>>>22;h=w+-1894007588+h+(a&o|q&~o)|0;h=(h<<6|h>>>26)+j|0;q=q<<10|q>>>22;G=u+2053994217+G+(C&I|E&~C)|0;G=(G<<9|G>>>23)+A|0;I=I<<10|I>>>22;j=m+-1894007588+j+(h&q|a&~q)|0;j=(j<<8|j>>>24)+o|0;a=a<<10|a>>>22;A=i+2053994217+A+(G&C|I&~G)|0;A=(A<<12|A>>>20)+E|0;C=C<<10|C>>>22;o=t+-1894007588+o+(j&a|h&~a)|0;o=(o<<6|o>>>26)+q|0;h=h<<10|h>>>22;E=z+2053994217+E+(A&G|C&~A)|0;E=(E<<5|E>>>27)+I|0;G=G<<10|G>>>22;q=y+-1894007588+q+(o&h|j&~h)|0;q=(q<<5|q>>>27)+a|0;j=j<<10|j>>>22;I=F+2053994217+I+(E&A|G&~E)|0;I=(I<<15|I>>>17)+C|0;A=A<<10|A>>>22;a=v+-1894007588+a+(q&j|o&~j)|0;a=(a<<12|a>>>20)+h|0;o=o<<10|o>>>22;C=m+2053994217+C+(I&E|A&~I)|0;C=(C<<8|C>>>24)+G|0;E=E<<10|E>>>22;h=x+-1454113458+h+(a^(q|~o))|0;h=(h<<9|h>>>23)+j|0;q=q<<10|q>>>22;G=G+H+(I^E^C)|0;G=(G<<8|G>>>24)+A|0;I=I<<10|I>>>22;j=s+-1454113458+j+(h^(a|~q))|0;j=(j<<15|j>>>17)+o|0;a=a<<10|a>>>22;A=A+w+(C^I^G)|0;A=(A<<5|A>>>27)+E|0;C=C<<10|C>>>22;o=t+-1454113458+o+(j^(h|~a))|0;o=(o<<5|o>>>27)+q|0;h=h<<10|h>>>22;E=E+F+(G^C^A)|0;E=(E<<12|E>>>20)+I|0;G=G<<10|G>>>22;q=i+-1454113458+q+(o^(j|~h))|0;q=(q<<11|q>>>21)+a|0;j=j<<10|j>>>22;x=I+x+(A^G^E)|0;x=(x<<9|x>>>23)+C|0;A=A<<10|A>>>22;a=z+-1454113458+a+(q^(o|~j))|0;a=(a<<6|a>>>26)+h|0;o=o<<10|o>>>22;C=C+D+(E^A^x)|0;C=(C<<12|C>>>20)+G|0;E=E<<10|E>>>22;h=H+-1454113458+h+(a^(q|~o))|0;h=(h<<8|h>>>24)+j|0;q=q<<10|q>>>22;t=G+t+(x^E^C)|0;t=(t<<5|t>>>27)+A|0;x=x<<10|x>>>22;j=v+-1454113458+j+(h^(a|~q))|0;j=(j<<13|j>>>19)+o|0;a=a<<10|a>>>22;A=A+B+(C^x^t)|0;A=(A<<14|A>>>18)+E|0;C=C<<10|C>>>22;o=F+-1454113458+o+(j^(h|~a))|0;o=(o<<12|o>>>20)+q|0;h=h<<10|h>>>22;z=E+z+(t^C^A)|0;z=(z<<6|z>>>26)+x|0;t=t<<10|t>>>22;q=m+-1454113458+q+(o^(j|~h))|0;q=(q<<5|q>>>27)+a|0;j=j<<10|j>>>22;x=x+y+(A^t^z)|0;x=(x<<8|x>>>24)+C|0;A=A<<10|A>>>22;a=D+-1454113458+a+(q^(o|~j))|0;a=(a<<12|a>>>20)+h|0;o=o<<10|o>>>22;v=C+v+(z^A^x)|0;v=(v<<13|v>>>19)+t|0;z=z<<10|z>>>22;h=f+-1454113458+h+(a^(q|~o))|0;h=(h<<13|h>>>19)+j|0;q=q<<10|q>>>22;t=t+u+(x^z^v)|0;t=(t<<6|t>>>26)+A|0;x=x<<10|x>>>22;j=B+-1454113458+j+(h^(a|~q))|0;j=(j<<14|j>>>18)+o|0;a=a<<10|a>>>22;m=A+m+(v^x^t)|0;m=(m<<5|m>>>27)+z|0;v=v<<10|v>>>22;o=l+-1454113458+o+(j^(h|~a))|0;o=(o<<11|o>>>21)+q|0;h=h<<10|h>>>22;s=z+s+(t^v^m)|0;s=(s<<15|s>>>17)+x|0;t=t<<10|t>>>22;q=y+-1454113458+q+(o^(j|~h))|0;q=(q<<8|q>>>24)+a|0;j=j<<10|j>>>22;f=x+f+(m^t^s)|0;f=(f<<13|f>>>19)+v|0;m=m<<10|m>>>22;a=w+-1454113458+a+(q^(o|~j))|0;a=(a<<5|a>>>27)+h|0;o=o<<10|o>>>22;i=v+i+(s^m^f)|0;i=(i<<11|i>>>21)+t|0;s=s<<10|s>>>22;h=u+-1454113458+h+(a^(q|~o))|0;l=t+l+(f^s^i)|0;c[p>>2]=s+r+(q<<10|q>>>22);c[n>>2]=m+(c[k>>2]|0)+o;c[k>>2]=j+(c[g>>2]|0)+m+(l<<11|l>>>21);c[g>>2]=j+(c[b>>2]|0)+i+(h<<6|h>>>26);c[b>>2]=(f<<10|f>>>22)+e+a;return}function yb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0;if(d|0){h=c[a>>2]|0;e=h&63;f=64-e|0;h=h+d|0;c[a>>2]=h;if(h>>>0>>0){h=a+4|0;c[h>>2]=(c[h>>2]|0)+1}if(!((e|0)==0|f>>>0>d>>>0)){tc(a+28+e|0,b|0,f|0)|0;xb(a,a+28|0);e=0;b=b+f|0;d=d-f|0}if(d>>>0>63){g=d+-64|0;h=g&-64;f=b+(h+64)|0;while(1){xb(a,b);d=d+-64|0;if(d>>>0<=63)break;else b=b+64|0}b=f;d=g-h|0}if(d|0)tc(a+28+e|0,b|0,d|0)|0}return}function zb(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0;e=i;i=i+16|0;f=e;g=c[b>>2]|0;h=c[b+4>>2]|0;a[f>>0]=g<<3;a[f+1>>0]=g>>>5;a[f+2>>0]=g>>>13;a[f+3>>0]=g>>>21;a[f+4>>0]=h<<3|g>>>29;a[f+5>>0]=h>>>5;a[f+6>>0]=h>>>13;a[f+7>>0]=h>>>21;g=g&63;yb(b,38733,(g>>>0<56?56:120)-g|0);yb(b,f,8);f=b+8|0;a[d>>0]=c[f>>2];a[d+1>>0]=(c[f>>2]|0)>>>8;a[d+2>>0]=(c[f>>2]|0)>>>16;a[d+3>>0]=(c[f>>2]|0)>>>24;f=b+12|0;a[d+4>>0]=c[f>>2];a[d+5>>0]=(c[f>>2]|0)>>>8;a[d+6>>0]=(c[f>>2]|0)>>>16;a[d+7>>0]=(c[f>>2]|0)>>>24;f=b+16|0;a[d+8>>0]=c[f>>2];a[d+9>>0]=(c[f>>2]|0)>>>8;a[d+10>>0]=(c[f>>2]|0)>>>16;a[d+11>>0]=(c[f>>2]|0)>>>24;f=b+20|0;a[d+12>>0]=c[f>>2];a[d+13>>0]=(c[f>>2]|0)>>>8;a[d+14>>0]=(c[f>>2]|0)>>>16;a[d+15>>0]=(c[f>>2]|0)>>>24;b=b+24|0;a[d+16>>0]=c[b>>2];a[d+17>>0]=(c[b>>2]|0)>>>8;a[d+18>>0]=(c[b>>2]|0)>>>16;a[d+19>>0]=(c[b>>2]|0)>>>24;i=e;return}function Ab(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0;h=i;i=i+96|0;e=h;f=e+8|0;g=e;j=g+92|0;do{c[g>>2]=0;g=g+4|0}while((g|0)<(j|0));c[f>>2]=1732584193;c[e+12>>2]=-271733879;c[e+16>>2]=-1732584194;c[e+20>>2]=271733878;c[e+24>>2]=-1009589776;yb(e,a,b);zb(e,d);i=h;return}function Bb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0;y=i;i=i+64|0;t=y;u=c[a>>2]|0;v=a+4|0;w=a+8|0;x=a+12|0;q=a+16|0;r=a+20|0;s=a+24|0;p=a+28|0;g=0;o=u;a=c[p>>2]|0;h=c[s>>2]|0;j=c[r>>2]|0;k=c[q>>2]|0;e=c[x>>2]|0;l=c[w>>2]|0;f=c[v>>2]|0;while(1){n=((k>>>6|k<<26)^(k>>>11|k<<21)^(k>>>25|k<<7))+a+(h&~k^j&k)+(c[37828+(g<<2)>>2]|0)|0;a=c[b>>2]|0;c[t+(g<<2)>>2]=a;a=n+a|0;e=a+e|0;a=((o>>>2|o<<30)^(o>>>13|o<<19)^(o>>>22|o<<10))+(o&(l^f)^l&f)+a|0;g=g+1|0;if((g|0)==16){n=16;m=a;g=e;a=l;e=o;break}else{C=o;B=f;A=l;z=k;m=j;n=h;b=b+4|0;o=a;k=e;f=C;l=B;e=A;j=z;h=m;a=n}}while(1){A=n;n=n+1|0;z=c[t+((n&15)<<2)>>2]|0;b=c[t+((A+14&15)<<2)>>2]|0;C=((g>>>6|g<<26)^(g>>>11|g<<21)^(g>>>25|g<<7))+h+(j&~g^k&g)+(c[37828+(A<<2)>>2]|0)|0;B=t+((A&15)<<2)|0;b=((z>>>18|z<<14)^z>>>3^(z>>>7|z<<25))+(c[t+((A+9&15)<<2)>>2]|0)+(c[B>>2]|0)+((b>>>19|b<<13)^b>>>10^(b>>>17|b<<15))|0;c[B>>2]=b;b=C+b|0;a=b+a|0;b=((m>>>2|m<<30)^(m>>>13|m<<19)^(m>>>22|m<<10))+(m&(f^e)^f&e)+b|0;if((n|0)==64)break;else{o=m;z=e;A=f;B=g;C=k;h=j;m=b;g=a;e=o;f=z;a=A;k=B;j=C}}c[d>>2]=u+b;c[d+4>>2]=(c[v>>2]|0)+m;c[d+8>>2]=(c[w>>2]|0)+e;c[d+12>>2]=(c[x>>2]|0)+f;c[d+16>>2]=(c[q>>2]|0)+a;c[d+20>>2]=(c[r>>2]|0)+g;c[d+24>>2]=(c[s>>2]|0)+k;c[d+28>>2]=(c[p>>2]|0)+j;i=y;return}function Cb(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0;do if(e|0){n=b+32|0;g=n;h=c[g>>2]|0;g=c[g+4>>2]|0;f=mc(h|0,g|0,3)|0;f=f&63;if(f){i=64-f|0;j=b+40|0;f=j+f|0;if(i>>>0>e>>>0){tc(f|0,d|0,e|0)|0;b=qc(h|0,g|0,e<<3|0,0)|0;c[n>>2]=b;c[n+4>>2]=C;break}tc(f|0,d|0,i|0)|0;m=qc(h|0,g|0,i<<3|0,0)|0;f=n;c[f>>2]=m;c[f+4>>2]=C;e=e-i|0;f=0;do{m=b+40+(f<<2)|0;c[m>>2]=sc(c[m>>2]|0)|0;f=f+1|0}while((f|0)!=16);Bb(b,j,b);d=d+i|0}if(e>>>0>63){j=b+40|0;l=e+-64|0;m=l&-64;k=m+64|0;i=d;while(1){f=j;g=i;h=f+64|0;do{a[f>>0]=a[g>>0]|0;f=f+1|0;g=g+1|0}while((f|0)<(h|0));f=0;do{h=b+40+(f<<2)|0;c[h>>2]=sc(c[h>>2]|0)|0;f=f+1|0}while((f|0)!=16);Bb(b,j,b);g=n;g=qc(c[g>>2]|0,c[g+4>>2]|0,512,0)|0;h=n;c[h>>2]=g;c[h+4>>2]=C;e=e+-64|0;if(e>>>0<=63)break;else i=i+64|0}d=d+k|0;e=l-m|0}if(e|0){tc(b+40|0,d|0,e|0)|0;b=n;b=qc(c[b>>2]|0,c[b+4>>2]|0,e<<3|0,0)|0;c[n>>2]=b;c[n+4>>2]=C}}while(0);return}function Db(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0;if(d){h=b+32|0;f=h;f=mc(c[f>>2]|0,c[f+4>>2]|0,3)|0;f=f&63;e=f+1|0;g=b+40|0;a[g+f>>0]=-128;if(e>>>0>56){lc(g+e|0,0,f^63|0)|0;e=0;do{f=b+40+(e<<2)|0;c[f>>2]=sc(c[f>>2]|0)|0;e=e+1|0}while((e|0)!=16);Bb(b,g,b);e=0}lc(g+e|0,0,56-e|0)|0;e=0;do{f=b+40+(e<<2)|0;c[f>>2]=sc(c[f>>2]|0)|0;e=e+1|0}while((e|0)!=14);e=c[h>>2]|0;c[b+96>>2]=c[h+4>>2];c[b+100>>2]=e;Bb(b,g,b);e=0;do{h=b+(e<<2)|0;c[h>>2]=sc(c[h>>2]|0)|0;e=e+1|0}while((e|0)!=8);e=d;f=b;g=e+32|0;do{a[e>>0]=a[f>>0]|0;e=e+1|0;f=f+1|0}while((e|0)<(g|0))}e=b;g=e+104|0;do{c[e>>2]=0;e=e+4|0}while((e|0)<(g|0));return}function Eb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0;g=i;i=i+112|0;e=g;c[e>>2]=c[9449];c[e+4>>2]=c[9450];c[e+8>>2]=c[9451];c[e+12>>2]=c[9452];c[e+16>>2]=c[9453];c[e+20>>2]=c[9454];c[e+24>>2]=c[9455];c[e+28>>2]=c[9456];f=e+32|0;h=f+72|0;do{c[f>>2]=0;f=f+4|0}while((f|0)<(h|0));Cb(e,a,b);Db(e,d);i=g;return}function Fb(a){a=a|0;var b=0,d=0,e=0;if(a|0){b=a;d=8;e=b+64|0;do{c[b>>2]=c[d>>2];b=b+4|0;d=d+4|0}while((b|0)<(e|0));lc(a+64|0,0,144)|0}return}function Gb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0,X=0,Y=0,Z=0,_=0;L=i;i=i+128|0;F=L;K=a;J=c[K>>2]|0;K=c[K+4>>2]|0;B=a+8|0;w=B;D=a+16|0;e=D;E=a+24|0;f=E;G=a+32|0;p=G;H=a+40|0;q=H;I=a+48|0;m=I;A=a+56|0;h=A;j=0;l=J;u=K;t=c[w>>2]|0;z=c[e>>2]|0;w=c[w+4>>2]|0;a=c[e+4>>2]|0;e=c[f>>2]|0;f=c[f+4>>2]|0;o=c[p>>2]|0;p=c[p+4>>2]|0;g=c[h>>2]|0;h=c[h+4>>2]|0;r=c[q>>2]|0;q=c[q+4>>2]|0;k=c[m>>2]|0;m=c[m+4>>2]|0;while(1){v=mc(o|0,p|0,14)|0;N=C;x=nc(o|0,p|0,50)|0;N=N|C;y=mc(o|0,p|0,18)|0;O=C;M=nc(o|0,p|0,46)|0;O=N^(O|C);N=mc(o|0,p|0,41)|0;n=C;s=nc(o|0,p|0,23)|0;n=qc((v|x)^(y|M)^(N|s)|0,O^(n|C)|0,g|0,h|0)|0;n=qc(n|0,C|0,k&~o^r&o|0,m&~p^q&p|0)|0;O=72+(j<<3)|0;O=qc(n|0,C|0,c[O>>2]|0,c[O+4>>2]|0)|0;n=b;g=c[n>>2]|0;n=c[n+4>>2]|0;s=F+(j<<3)|0;c[s>>2]=g;c[s+4>>2]=n;n=qc(O|0,C|0,g|0,n|0)|0;g=C;O=mc(l|0,u|0,28)|0;s=C;N=nc(l|0,u|0,36)|0;s=s|C;M=mc(l|0,u|0,34)|0;y=C;h=nc(l|0,u|0,30)|0;y=s^(y|C);s=mc(l|0,u|0,39)|0;x=C;v=nc(l|0,u|0,25)|0;x=qc((O|N)^(M|h)^(s|v)|0,y^(x|C)|0,l&(z^t)^z&t|0,u&(a^w)^a&w|0)|0;y=C;e=qc(n|0,g|0,e|0,f|0)|0;f=C;g=qc(x|0,y|0,n|0,g|0)|0;n=C;j=j+1|0;if((j|0)==16){y=16;x=e;v=f;s=p;p=g;j=t;h=u;g=w;b=z;break}else{x=p;y=o;h=m;M=k;N=u;O=l;b=b+8|0;l=g;u=n;o=e;p=f;m=q;k=r;q=x;r=y;g=M;f=a;e=z;a=w;w=N;z=t;t=O}}while(1){t=y;y=y+1|0;T=F+((y&15)<<3)|0;W=c[T>>2]|0;T=c[T+4>>2]|0;S=mc(W|0,T|0,1)|0;Q=C;R=nc(W|0,T|0,63)|0;Q=Q|C;V=mc(W|0,T|0,8)|0;O=C;U=nc(W|0,T|0,56)|0;O=O|C;T=mc(W|0,T|0,7)|0;Q=O^C^Q;O=F+((t+14&15)<<3)|0;W=c[O>>2]|0;O=c[O+4>>2]|0;u=mc(W|0,O|0,19)|0;e=C;f=nc(W|0,O|0,45)|0;e=e|C;N=mc(W|0,O|0,61)|0;_=C;w=nc(W|0,O|0,3)|0;_=_|C;O=mc(W|0,O|0,6)|0;e=_^C^e;_=mc(x|0,v|0,14)|0;W=C;Z=nc(x|0,v|0,50)|0;W=W|C;Y=mc(x|0,v|0,18)|0;P=C;X=nc(x|0,v|0,46)|0;P=W^(P|C);W=mc(x|0,v|0,41)|0;z=C;M=nc(x|0,v|0,23)|0;m=qc((_|Z)^(Y|X)^(W|M)|0,P^(z|C)|0,k|0,m|0)|0;m=qc(m|0,C|0,r&~x^o&x|0,q&~v^s&v|0)|0;z=72+(t<<3)|0;z=qc(m|0,C|0,c[z>>2]|0,c[z+4>>2]|0)|0;m=C;P=F+((t+9&15)<<3)|0;t=F+((t&15)<<3)|0;M=t;k=c[M>>2]|0;M=c[M+4>>2]|0;P=qc((V|U)^T^(S|R)|0,Q|0,c[P>>2]|0,c[P+4>>2]|0)|0;M=qc(P|0,C|0,k|0,M|0)|0;e=qc(M|0,C|0,(N|w)^O^(u|f)|0,e|0)|0;f=C;c[t>>2]=e;c[t+4>>2]=f;f=qc(z|0,m|0,e|0,f|0)|0;e=C;m=mc(p|0,n|0,28)|0;z=C;t=nc(p|0,n|0,36)|0;z=z|C;u=mc(p|0,n|0,34)|0;O=C;w=nc(p|0,n|0,30)|0;O=z^(O|C);z=mc(p|0,n|0,39)|0;N=C;M=nc(p|0,n|0,25)|0;N=qc((m|t)^(u|w)^(z|M)|0,O^(N|C)|0,p&(j^l)^j&l|0,n&(g^h)^g&h|0)|0;O=C;a=qc(f|0,e|0,b|0,a|0)|0;b=C;e=qc(N|0,O|0,f|0,e|0)|0;f=C;if((y|0)==80)break;else{X=n;Y=p;Z=v;_=x;m=q;k=r;x=a;v=b;p=e;n=f;a=g;b=j;g=h;h=X;j=l;l=Y;q=s;r=o;s=Z;o=_}}_=qc(J|0,K|0,e|0,f|0)|0;Z=d;c[Z>>2]=_;c[Z+4>>2]=C;Z=B;Z=qc(c[Z>>2]|0,c[Z+4>>2]|0,p|0,n|0)|0;_=d+8|0;c[_>>2]=Z;c[_+4>>2]=C;_=D;_=qc(c[_>>2]|0,c[_+4>>2]|0,l|0,h|0)|0;Z=d+16|0;c[Z>>2]=_;c[Z+4>>2]=C;Z=E;Z=qc(c[Z>>2]|0,c[Z+4>>2]|0,j|0,g|0)|0;_=d+24|0;c[_>>2]=Z;c[_+4>>2]=C;_=G;_=qc(c[_>>2]|0,c[_+4>>2]|0,a|0,b|0)|0;Z=d+32|0;c[Z>>2]=_;c[Z+4>>2]=C;Z=H;Z=qc(c[Z>>2]|0,c[Z+4>>2]|0,x|0,v|0)|0;_=d+40|0;c[_>>2]=Z;c[_+4>>2]=C;_=I;_=qc(c[_>>2]|0,c[_+4>>2]|0,o|0,s|0)|0;Z=d+48|0;c[Z>>2]=_;c[Z+4>>2]=C;Z=A;Z=qc(c[Z>>2]|0,c[Z+4>>2]|0,r|0,q|0)|0;_=d+56|0;c[_>>2]=Z;c[_+4>>2]=C;i=L;return}function Hb(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0;do if(e|0){o=b+64|0;g=o;h=c[g>>2]|0;g=c[g+4>>2]|0;f=mc(h|0,g|0,3)|0;f=f&127;if(f){i=128-f|0;j=b+80|0;f=j+f|0;if(i>>>0>e>>>0){tc(f|0,d|0,e|0)|0;n=e<<3;m=qc(h|0,g|0,n|0,0)|0;l=C;c[o>>2]=m;c[o+4>>2]=l;if(!(l>>>0<0|(l|0)==0&m>>>0>>0))break;o=b+72|0;b=o;b=qc(c[b>>2]|0,c[b+4>>2]|0,1,0)|0;c[o>>2]=b;c[o+4>>2]=C;break}tc(f|0,d|0,i|0)|0;n=i<<3;m=qc(h|0,g|0,n|0,0)|0;l=C;k=o;c[k>>2]=m;c[k+4>>2]=l;if(l>>>0<0|(l|0)==0&m>>>0>>0){n=b+72|0;m=n;m=qc(c[m>>2]|0,c[m+4>>2]|0,1,0)|0;c[n>>2]=m;c[n+4>>2]=C}e=e-i|0;f=0;do{n=b+80+(f<<3)|0;m=n;m=ma(c[m>>2]|0,c[m+4>>2]|0)|0;c[n>>2]=m;c[n+4>>2]=C;f=f+1|0}while((f|0)!=16);Gb(b,j,b);d=d+i|0}if(e>>>0>127){j=b+80|0;k=b+72|0;m=e+-128|0;n=m&-128;l=n+128|0;i=d;while(1){f=j;g=i;h=f+128|0;do{a[f>>0]=a[g>>0]|0;f=f+1|0;g=g+1|0}while((f|0)<(h|0));f=0;do{h=b+80+(f<<3)|0;g=h;g=ma(c[g>>2]|0,c[g+4>>2]|0)|0;c[h>>2]=g;c[h+4>>2]=C;f=f+1|0}while((f|0)!=16);Gb(b,j,b);g=o;h=c[g>>2]|0;g=c[g+4>>2]|0;p=qc(h|0,g|0,1024,0)|0;f=o;c[f>>2]=p;c[f+4>>2]=C;if(g>>>0>4294967295|(g|0)==-1&h>>>0>4294966271){h=k;h=qc(c[h>>2]|0,c[h+4>>2]|0,1,0)|0;p=k;c[p>>2]=h;c[p+4>>2]=C}e=e+-128|0;if(e>>>0<=127)break;else i=i+128|0}d=d+l|0;e=m-n|0}if(e|0?(tc(b+80|0,d|0,e|0)|0,p=e<<3,n=o,n=qc(c[n>>2]|0,c[n+4>>2]|0,p|0,0)|0,m=C,o,c[o>>2]=n,c[o+4>>2]=m,m>>>0<0|(m|0)==0&n>>>0

>>0):0){p=b+72|0;o=p;o=qc(c[o>>2]|0,c[o+4>>2]|0,1,0)|0;c[p>>2]=o;c[p+4>>2]=C}}while(0);return}function Ib(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0;if(d){h=b+64|0;f=h;f=mc(c[f>>2]|0,c[f+4>>2]|0,3)|0;f=f&127;e=f+1|0;g=b+80|0;a[g+f>>0]=-128;if(e>>>0>112){lc(g+e|0,0,f^127|0)|0;e=0;do{f=b+80+(e<<3)|0;i=f;i=ma(c[i>>2]|0,c[i+4>>2]|0)|0;c[f>>2]=i;c[f+4>>2]=C;e=e+1|0}while((e|0)!=16);Gb(b,g,b);e=0}lc(g+e|0,0,112-e|0)|0;e=0;do{i=b+80+(e<<3)|0;f=i;f=ma(c[f>>2]|0,c[f+4>>2]|0)|0;c[i>>2]=f;c[i+4>>2]=C;e=e+1|0}while((e|0)!=14);f=b+72|0;e=c[f+4>>2]|0;i=b+192|0;c[i>>2]=c[f>>2];c[i+4>>2]=e;i=c[h+4>>2]|0;e=b+200|0;c[e>>2]=c[h>>2];c[e+4>>2]=i;Gb(b,g,b);e=0;do{i=b+(e<<3)|0;h=i;h=ma(c[h>>2]|0,c[h+4>>2]|0)|0;c[i>>2]=h;c[i+4>>2]=C;e=e+1|0}while((e|0)!=8);e=d;f=b;g=e+64|0;do{a[e>>0]=a[f>>0]|0;e=e+1|0;f=f+1|0}while((e|0)<(g|0))}lc(b|0,0,208)|0;return}function Jb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0;g=i;i=i+208|0;e=g;f=e;h=8;j=f+64|0;do{c[f>>2]=c[h>>2];f=f+4|0;h=h+4|0}while((f|0)<(j|0));lc(e+64|0,0,144)|0;Hb(e,a,b);Ib(e,d);i=g;return}function Kb(){var a=0,b=0,d=0;d=i;i=i+16|0;b=d;a=c[9714]|0;if(!a){a=bc(38797,38810)|0;c[9714]=a}if((gc(b,1,4,a)|0)==4){i=d;return c[b>>2]|0}else pa(38812,38828,60,38838);return 0}function Lb(a){a=a|0;if(a>>>0>=256)if(a>>>0<65536)a=2;else a=a>>>0<16777216?3:4;else a=1;return a|0}function Mb(b,c){b=b|0;c=c|0;var d=0;if(b>>>0<=16777215)if(b>>>0<=65535){if(b>>>0>255)d=6}else d=4;else{a[c>>0]=b>>>24;c=c+1|0;d=4}if((d|0)==4){a[c>>0]=b>>>16;c=c+1|0;d=6}if((d|0)==6){a[c>>0]=b>>>8;c=c+1|0}a[c>>0]=b;return}function Nb(a){a=a|0;var b=0,d=0;b=i;i=i+16|0;d=b;c[d>>2]=c[a+60>>2];a=Qb(ha(6,d|0)|0)|0;i=b;return a|0}function Ob(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0;m=i;i=i+48|0;h=m+16|0;g=m;f=m+32|0;c[f>>2]=d;j=f+4|0;l=b+48|0;n=c[l>>2]|0;c[j>>2]=e-((n|0)!=0&1);k=b+44|0;c[f+8>>2]=c[k>>2];c[f+12>>2]=n;if(!(c[9715]|0)){c[h>>2]=c[b+60>>2];c[h+4>>2]=f;c[h+8>>2]=2;f=Qb(qa(145,h|0)|0)|0}else{ga(1,b|0);c[g>>2]=c[b+60>>2];c[g+4>>2]=f;c[g+8>>2]=2;f=Qb(qa(145,g|0)|0)|0;ba(0)}if((f|0)>=1){j=c[j>>2]|0;if(f>>>0>j>>>0){g=c[k>>2]|0;h=b+4|0;c[h>>2]=g;c[b+8>>2]=g+(f-j);if(!(c[l>>2]|0))f=e;else{c[h>>2]=g+1;a[d+(e+-1)>>0]=a[g>>0]|0;f=e}}}else{c[b>>2]=c[b>>2]|f&48^16;c[b+8>>2]=0;c[b+4>>2]=0}i=m;return f|0}function Pb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0;f=i;i=i+32|0;g=f;e=f+20|0;c[g>>2]=c[a+60>>2];c[g+4>>2]=0;c[g+8>>2]=b;c[g+12>>2]=e;c[g+16>>2]=d;if((Qb(ja(140,g|0)|0)|0)<0){c[e>>2]=-1;a=-1}else a=c[e>>2]|0;i=f;return a|0}function Qb(a){a=a|0;if(a>>>0>4294963200){c[(Rb()|0)>>2]=0-a;a=-1}return a|0}function Rb(){var a=0;if(!(c[9715]|0))a=38904;else a=c[(uc()|0)+64>>2]|0;return a|0}function Sb(a){a=a|0;if(!(c[a+68>>2]|0))Tb(a);return}function Tb(a){a=a|0;return}function Ub(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0;q=i;i=i+48|0;n=q+16|0;m=q;j=q+32|0;o=a+28|0;h=c[o>>2]|0;c[j>>2]=h;p=a+20|0;h=(c[p>>2]|0)-h|0;c[j+4>>2]=h;c[j+8>>2]=b;c[j+12>>2]=d;k=a+60|0;l=a+44|0;g=2;b=h+d|0;while(1){if(!(c[9715]|0)){c[n>>2]=c[k>>2];c[n+4>>2]=j;c[n+8>>2]=g;f=Qb(ra(146,n|0)|0)|0}else{ga(2,a|0);c[m>>2]=c[k>>2];c[m+4>>2]=j;c[m+8>>2]=g;f=Qb(ra(146,m|0)|0)|0;ba(0)}if((b|0)==(f|0)){b=6;break}if((f|0)<0){b=8;break}b=b-f|0;e=c[j+4>>2]|0;if(f>>>0<=e>>>0)if((g|0)==2){c[o>>2]=(c[o>>2]|0)+f;g=2;h=j}else h=j;else{h=c[l>>2]|0;c[o>>2]=h;c[p>>2]=h;f=f-e|0;g=g+-1|0;h=j+8|0;e=c[j+12>>2]|0}c[h>>2]=(c[h>>2]|0)+f;c[h+4>>2]=e-f;j=h}if((b|0)==6){n=c[l>>2]|0;c[a+16>>2]=n+(c[a+48>>2]|0);a=n;c[o>>2]=a;c[p>>2]=a}else if((b|0)==8){c[a+16>>2]=0;c[o>>2]=0;c[p>>2]=0;c[a>>2]=c[a>>2]|32;if((g|0)==2)d=0;else d=d-(c[j+4>>2]|0)|0}i=q;return d|0}function Vb(a){a=a|0;if(!(c[a+68>>2]|0))Tb(a);return}function Wb(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0;g=i;i=i+80|0;f=g;c[b+36>>2]=3;if((c[b>>2]&64|0)==0?(c[f>>2]=c[b+60>>2],c[f+4>>2]=21505,c[f+8>>2]=g+12,da(54,f|0)|0):0)a[b+75>>0]=-1;f=Ub(b,d,e)|0;i=g;return f|0}function Xb(b){b=b|0;var d=0,e=0;d=b+74|0;e=a[d>>0]|0;a[d>>0]=e+255|e;d=b+20|0;e=b+44|0;if((c[d>>2]|0)>>>0>(c[e>>2]|0)>>>0)va[c[b+36>>2]&7](b,0,0)|0;c[b+16>>2]=0;c[b+28>>2]=0;c[d>>2]=0;d=c[b>>2]|0;if(d&20)if(!(d&4))d=-1;else{c[b>>2]=d|32;d=-1}else{d=c[e>>2]|0;c[b+8>>2]=d;c[b+4>>2]=d;d=0}return d|0}function Yb(a){a=a|0;return 0}function Zb(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,i=0;h=d&255;f=(e|0)!=0;a:do if(f&(b&3|0)!=0){g=d&255;while(1){if((a[b>>0]|0)==g<<24>>24){i=6;break a}b=b+1|0;e=e+-1|0;f=(e|0)!=0;if(!(f&(b&3|0)!=0)){i=5;break}}}else i=5;while(0);if((i|0)==5)if(f)i=6;else e=0;b:do if((i|0)==6){g=d&255;if((a[b>>0]|0)!=g<<24>>24){f=R(h,16843009)|0;c:do if(e>>>0>3)while(1){h=c[b>>2]^f;if((h&-2139062144^-2139062144)&h+-16843009|0)break;b=b+4|0;e=e+-4|0;if(e>>>0<=3){i=11;break c}}else i=11;while(0);if((i|0)==11)if(!e){e=0;break}while(1){if((a[b>>0]|0)==g<<24>>24)break b;b=b+1|0;e=e+-1|0;if(!e){e=0;break}}}}while(0);return (e|0?b:0)|0}function _b(b){b=b|0;var d=0,e=0,f=0;f=b;a:do if(!(f&3))e=4;else{d=f;while(1){if(!(a[b>>0]|0)){b=d;break a}b=b+1|0;d=b;if(!(d&3)){e=4;break}}}while(0);if((e|0)==4){while(1){d=c[b>>2]|0;if(!((d&-2139062144^-2139062144)&d+-16843009))b=b+4|0;else break}if((d&255)<<24>>24)do b=b+1|0;while((a[b>>0]|0)!=0)}return b-f|0}function $b(b,c){b=b|0;c=c|0;b=ac(b,c)|0;return ((a[b>>0]|0)==(c&255)<<24>>24?b:0)|0}function ac(b,d){b=b|0;d=d|0;var e=0,f=0,g=0;f=d&255;a:do if(!f)b=b+(_b(b)|0)|0;else{if(b&3){e=d&255;do{g=a[b>>0]|0;if(g<<24>>24==0?1:g<<24>>24==e<<24>>24)break a;b=b+1|0}while((b&3|0)!=0)}f=R(f,16843009)|0;e=c[b>>2]|0;b:do if(!((e&-2139062144^-2139062144)&e+-16843009))do{g=e^f;if((g&-2139062144^-2139062144)&g+-16843009|0)break b;b=b+4|0;e=c[b>>2]|0}while(!((e&-2139062144^-2139062144)&e+-16843009|0));while(0);e=d&255;while(1){g=a[b>>0]|0;if(g<<24>>24==0?1:g<<24>>24==e<<24>>24)break;else b=b+1|0}}while(0);return b|0}function bc(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0;g=i;i=i+32|0;f=g+16|0;e=g;if(Zb(38847,a[d>>0]|0,4)|0){h=cc(d)|0|32768;c[e>>2]=b;c[e+4>>2]=h;c[e+8>>2]=438;e=Qb(ka(5,e|0)|0)|0;if((e|0)>=0){b=dc(e,d)|0;if(!b){c[f>>2]=e;ha(6,f|0)|0;b=0}}else b=0}else{c[(Rb()|0)>>2]=22;b=0}i=g;return b|0}function cc(b){b=b|0;var c=0,d=0,e=0;d=($b(b,43)|0)==0;c=a[b>>0]|0;d=d?c<<24>>24!=114&1:2;e=($b(b,120)|0)==0;d=e?d:d|128;b=($b(b,101)|0)==0;b=b?d:d|524288;b=c<<24>>24==114?b:b|64;b=c<<24>>24==119?b|512:b;return (c<<24>>24==97?b|1024:b)|0}function dc(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0;o=i;i=i+112|0;n=o+40|0;l=o+24|0;k=o+16|0;g=o;m=o+52|0;f=a[d>>0]|0;if(Zb(38847,f<<24>>24,4)|0){e=hc(1144)|0;if(!e)e=0;else{h=e;j=h+112|0;do{c[h>>2]=0;h=h+4|0}while((h|0)<(j|0));if(!($b(d,43)|0))c[e>>2]=f<<24>>24==114?8:4;if($b(d,101)|0){c[g>>2]=b;c[g+4>>2]=2;c[g+8>>2]=1;ca(221,g|0)|0;f=a[d>>0]|0}if(f<<24>>24==97){c[k>>2]=b;c[k+4>>2]=3;f=ca(221,k|0)|0;if(!(f&1024)){c[l>>2]=b;c[l+4>>2]=4;c[l+8>>2]=f|1024;ca(221,l|0)|0}d=c[e>>2]|128;c[e>>2]=d}else d=c[e>>2]|0;c[e+60>>2]=b;c[e+44>>2]=e+120;c[e+48>>2]=1024;f=e+75|0;a[f>>0]=-1;if((d&8|0)==0?(c[n>>2]=b,c[n+4>>2]=21505,c[n+8>>2]=m,(da(54,n|0)|0)==0):0)a[f>>0]=10;c[e+32>>2]=4;c[e+36>>2]=3;c[e+40>>2]=2;c[e+12>>2]=1;if(!(c[9716]|0))c[e+76>>2]=-1;ea(38888);f=c[9721]|0;c[e+56>>2]=f;if(f|0)c[f+52>>2]=e;c[9721]=e;na(38888)}}else{c[(Rb()|0)>>2]=22;e=0}i=o;return e|0}function ec(a){a=a|0;var b=0,d=0;do if(a){if((c[a+76>>2]|0)<=-1){b=fc(a)|0;break}d=(Yb(a)|0)==0;b=fc(a)|0;if(!d)Tb(a)}else{if(!(c[9549]|0))b=0;else b=ec(c[9549]|0)|0;ea(38888);a=c[9721]|0;if(a)do{if((c[a+76>>2]|0)>-1)d=Yb(a)|0;else d=0;if((c[a+20>>2]|0)>>>0>(c[a+28>>2]|0)>>>0)b=fc(a)|0|b;if(d|0)Tb(a);a=c[a+56>>2]|0}while((a|0)!=0);na(38888)}while(0);return b|0}function fc(a){a=a|0;var b=0,d=0,e=0,f=0,g=0,h=0;b=a+20|0;h=a+28|0;if((c[b>>2]|0)>>>0>(c[h>>2]|0)>>>0?(va[c[a+36>>2]&7](a,0,0)|0,(c[b>>2]|0)==0):0)a=-1;else{d=a+4|0;e=c[d>>2]|0;f=a+8|0;g=c[f>>2]|0;if(e>>>0>>0)va[c[a+40>>2]&7](a,e-g|0,1)|0;c[a+16>>2]=0;c[h>>2]=0;c[b>>2]=0;c[f>>2]=0;c[d>>2]=0;a=0}return a|0}function gc(b,d,e,f){b=b|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,i=0,j=0,k=0,l=0;k=R(e,d)|0;if((c[f+76>>2]|0)>-1)j=Yb(f)|0;else j=0;g=f+74|0;i=a[g>>0]|0;a[g>>0]=i+255|i;g=f+4|0;i=c[g>>2]|0;h=(c[f+8>>2]|0)-i|0;if((h|0)>0){h=h>>>0>>0?h:k;tc(b|0,i|0,h|0)|0;c[g>>2]=i+h;g=k-h|0;b=b+h|0}else g=k;a:do if(!g)l=13;else{i=f+32|0;while(1){if(Xb(f)|0)break;h=va[c[i>>2]&7](f,b,g)|0;if((h+1|0)>>>0<2)break;g=g-h|0;if(!g){l=13;break a}else b=b+h|0}if(j|0)Tb(f);e=((k-g|0)>>>0)/(d>>>0)|0}while(0);if((l|0)==13)if(j)Tb(f);return e|0}function hc(a){a=a|0;var b=0,d=0,e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0;L=i;i=i+16|0;p=L;do if(a>>>0<245){o=a>>>0<11?16:a+11&-8;a=o>>>3;t=c[9727]|0;d=t>>>a;if(d&3|0){a=(d&1^1)+a|0;d=38948+(a<<1<<2)|0;e=d+8|0;f=c[e>>2]|0;g=f+8|0;h=c[g>>2]|0;do if((d|0)!=(h|0)){if(h>>>0<(c[9731]|0)>>>0)fa();b=h+12|0;if((c[b>>2]|0)==(f|0)){c[b>>2]=d;c[e>>2]=h;break}else fa()}else c[9727]=t&~(1<>2]=K|3;K=f+K+4|0;c[K>>2]=c[K>>2]|1;K=g;i=L;return K|0}s=c[9729]|0;if(o>>>0>s>>>0){if(d|0){j=2<>>12&16;a=a>>>j;e=a>>>5&8;a=a>>>e;g=a>>>2&4;a=a>>>g;d=a>>>1&2;a=a>>>d;b=a>>>1&1;b=(e|j|g|d|b)+(a>>>b)|0;a=38948+(b<<1<<2)|0;d=a+8|0;g=c[d>>2]|0;j=g+8|0;e=c[j>>2]|0;do if((a|0)!=(e|0)){if(e>>>0<(c[9731]|0)>>>0)fa();f=e+12|0;if((c[f>>2]|0)==(g|0)){c[f>>2]=a;c[d>>2]=e;k=t;break}else fa()}else{k=t&~(1<>2]=o|3;e=g+o|0;c[e+4>>2]=h|1;c[e+h>>2]=h;if(s|0){f=c[9732]|0;b=s>>>3;d=38948+(b<<1<<2)|0;b=1<>2]|0;if(a>>>0<(c[9731]|0)>>>0)fa();else{l=a;m=b}}else{c[9727]=k|b;l=d;m=d+8|0}c[m>>2]=f;c[l+12>>2]=f;c[f+8>>2]=l;c[f+12>>2]=d}c[9729]=h;c[9732]=e;K=j;i=L;return K|0}l=c[9728]|0;if(l){a=(l&0-l)+-1|0;J=a>>>12&16;a=a>>>J;I=a>>>5&8;a=a>>>I;K=a>>>2&4;a=a>>>K;j=a>>>1&2;a=a>>>j;k=a>>>1&1;k=c[39212+((I|J|K|j|k)+(a>>>k)<<2)>>2]|0;a=k;j=k;k=(c[k+4>>2]&-8)-o|0;while(1){b=c[a+16>>2]|0;if(!b){b=c[a+20>>2]|0;if(!b)break}K=(c[b+4>>2]&-8)-o|0;J=K>>>0>>0;a=b;j=J?b:j;k=J?K:k}f=c[9731]|0;if(j>>>0>>0)fa();h=j+o|0;if(j>>>0>=h>>>0)fa();g=c[j+24>>2]|0;d=c[j+12>>2]|0;do if((d|0)==(j|0)){a=j+20|0;b=c[a>>2]|0;if(!b){a=j+16|0;b=c[a>>2]|0;if(!b){n=0;break}}while(1){d=b+20|0;e=c[d>>2]|0;if(e|0){b=e;a=d;continue}d=b+16|0;e=c[d>>2]|0;if(!e)break;else{b=e;a=d}}if(a>>>0>>0)fa();else{c[a>>2]=0;n=b;break}}else{e=c[j+8>>2]|0;if(e>>>0>>0)fa();b=e+12|0;if((c[b>>2]|0)!=(j|0))fa();a=d+8|0;if((c[a>>2]|0)==(j|0)){c[b>>2]=d;c[a>>2]=e;n=d;break}else fa()}while(0);do if(g|0){b=c[j+28>>2]|0;a=39212+(b<<2)|0;if((j|0)==(c[a>>2]|0)){c[a>>2]=n;if(!n){c[9728]=l&~(1<>>0<(c[9731]|0)>>>0)fa();b=g+16|0;if((c[b>>2]|0)==(j|0))c[b>>2]=n;else c[g+20>>2]=n;if(!n)break}a=c[9731]|0;if(n>>>0>>0)fa();c[n+24>>2]=g;b=c[j+16>>2]|0;do if(b|0)if(b>>>0>>0)fa();else{c[n+16>>2]=b;c[b+24>>2]=n;break}while(0);b=c[j+20>>2]|0;if(b|0)if(b>>>0<(c[9731]|0)>>>0)fa();else{c[n+20>>2]=b;c[b+24>>2]=n;break}}while(0);if(k>>>0<16){K=k+o|0;c[j+4>>2]=K|3;K=j+K+4|0;c[K>>2]=c[K>>2]|1}else{c[j+4>>2]=o|3;c[h+4>>2]=k|1;c[h+k>>2]=k;if(s|0){e=c[9732]|0;b=s>>>3;d=38948+(b<<1<<2)|0;b=1<>2]|0;if(a>>>0<(c[9731]|0)>>>0)fa();else{q=a;r=b}}else{c[9727]=t|b;q=d;r=d+8|0}c[r>>2]=e;c[q+12>>2]=e;c[e+8>>2]=q;c[e+12>>2]=d}c[9729]=k;c[9732]=h}K=j+8|0;i=L;return K|0}}}else if(a>>>0<=4294967231){a=a+11|0;o=a&-8;l=c[9728]|0;if(l){e=0-o|0;a=a>>>8;if(a)if(o>>>0>16777215)k=31;else{r=(a+1048320|0)>>>16&8;D=a<>>16&4;D=D<>>16&2;k=14-(q|r|k)+(D<>>15)|0;k=o>>>(k+7|0)&1|k<<1}else k=0;a=c[39212+(k<<2)>>2]|0;a:do if(!a){d=0;f=0;D=86}else{f=0;j=a;h=o<<((k|0)==31?0:25-(k>>>1)|0);d=0;while(1){a=(c[j+4>>2]&-8)-o|0;if(a>>>0>>0)if(!a){a=j;e=0;d=j;D=90;break a}else{f=j;e=a}a=c[j+20>>2]|0;j=c[j+16+(h>>>31<<2)>>2]|0;d=(a|0)==0|(a|0)==(j|0)?d:a;a=(j|0)==0;if(a){D=86;break}else h=h<<(a&1^1)}}while(0);if((D|0)==86){if((d|0)==0&(f|0)==0){a=2<>>12&16;r=r>>>m;k=r>>>5&8;r=r>>>k;n=r>>>2&4;r=r>>>n;q=r>>>1&2;r=r>>>q;d=r>>>1&1;d=c[39212+((k|m|n|q|d)+(r>>>d)<<2)>>2]|0}if(!d){k=f;j=e}else{a=f;D=90}}if((D|0)==90)while(1){D=0;r=(c[d+4>>2]&-8)-o|0;f=r>>>0>>0;e=f?r:e;a=f?d:a;f=c[d+16>>2]|0;if(f|0){d=f;D=90;continue}d=c[d+20>>2]|0;if(!d){k=a;j=e;break}else D=90}if((k|0)!=0?j>>>0<((c[9729]|0)-o|0)>>>0:0){f=c[9731]|0;if(k>>>0>>0)fa();h=k+o|0;if(k>>>0>=h>>>0)fa();g=c[k+24>>2]|0;d=c[k+12>>2]|0;do if((d|0)==(k|0)){a=k+20|0;b=c[a>>2]|0;if(!b){a=k+16|0;b=c[a>>2]|0;if(!b){s=0;break}}while(1){d=b+20|0;e=c[d>>2]|0;if(e|0){b=e;a=d;continue}d=b+16|0;e=c[d>>2]|0;if(!e)break;else{b=e;a=d}}if(a>>>0>>0)fa();else{c[a>>2]=0;s=b;break}}else{e=c[k+8>>2]|0;if(e>>>0>>0)fa();b=e+12|0;if((c[b>>2]|0)!=(k|0))fa();a=d+8|0;if((c[a>>2]|0)==(k|0)){c[b>>2]=d;c[a>>2]=e;s=d;break}else fa()}while(0);do if(g){b=c[k+28>>2]|0;a=39212+(b<<2)|0;if((k|0)==(c[a>>2]|0)){c[a>>2]=s;if(!s){t=l&~(1<>>0<(c[9731]|0)>>>0)fa();b=g+16|0;if((c[b>>2]|0)==(k|0))c[b>>2]=s;else c[g+20>>2]=s;if(!s){t=l;break}}a=c[9731]|0;if(s>>>0>>0)fa();c[s+24>>2]=g;b=c[k+16>>2]|0;do if(b|0)if(b>>>0>>0)fa();else{c[s+16>>2]=b;c[b+24>>2]=s;break}while(0);b=c[k+20>>2]|0;if(b)if(b>>>0<(c[9731]|0)>>>0)fa();else{c[s+20>>2]=b;c[b+24>>2]=s;t=l;break}else t=l}else t=l;while(0);do if(j>>>0>=16){c[k+4>>2]=o|3;c[h+4>>2]=j|1;c[h+j>>2]=j;b=j>>>3;if(j>>>0<256){d=38948+(b<<1<<2)|0;a=c[9727]|0;b=1<>2]|0;if(a>>>0<(c[9731]|0)>>>0)fa();else{B=a;C=b}}else{c[9727]=a|b;B=d;C=d+8|0}c[C>>2]=h;c[B+12>>2]=h;c[h+8>>2]=B;c[h+12>>2]=d;break}b=j>>>8;if(b)if(j>>>0>16777215)b=31;else{J=(b+1048320|0)>>>16&8;K=b<>>16&4;K=K<>>16&2;b=14-(I|J|b)+(K<>>15)|0;b=j>>>(b+7|0)&1|b<<1}else b=0;d=39212+(b<<2)|0;c[h+28>>2]=b;a=h+16|0;c[a+4>>2]=0;c[a>>2]=0;a=1<>2]=h;c[h+24>>2]=d;c[h+12>>2]=h;c[h+8>>2]=h;break}a=j<<((b|0)==31?0:25-(b>>>1)|0);e=c[d>>2]|0;while(1){if((c[e+4>>2]&-8|0)==(j|0)){D=148;break}d=e+16+(a>>>31<<2)|0;b=c[d>>2]|0;if(!b){D=145;break}else{a=a<<1;e=b}}if((D|0)==145)if(d>>>0<(c[9731]|0)>>>0)fa();else{c[d>>2]=h;c[h+24>>2]=e;c[h+12>>2]=h;c[h+8>>2]=h;break}else if((D|0)==148){b=e+8|0;a=c[b>>2]|0;K=c[9731]|0;if(a>>>0>=K>>>0&e>>>0>=K>>>0){c[a+12>>2]=h;c[b>>2]=h;c[h+8>>2]=a;c[h+12>>2]=e;c[h+24>>2]=0;break}else fa()}}else{K=j+o|0;c[k+4>>2]=K|3;K=k+K+4|0;c[K>>2]=c[K>>2]|1}while(0);K=k+8|0;i=L;return K|0}}}else o=-1;while(0);d=c[9729]|0;if(d>>>0>=o>>>0){b=d-o|0;a=c[9732]|0;if(b>>>0>15){K=a+o|0;c[9732]=K;c[9729]=b;c[K+4>>2]=b|1;c[K+b>>2]=b;c[a+4>>2]=o|3}else{c[9729]=0;c[9732]=0;c[a+4>>2]=d|3;K=a+d+4|0;c[K>>2]=c[K>>2]|1}K=a+8|0;i=L;return K|0}j=c[9730]|0;if(j>>>0>o>>>0){I=j-o|0;c[9730]=I;K=c[9733]|0;J=K+o|0;c[9733]=J;c[J+4>>2]=I|1;c[K+4>>2]=o|3;K=K+8|0;i=L;return K|0}if(!(c[9845]|0)){c[9847]=4096;c[9846]=4096;c[9848]=-1;c[9849]=-1;c[9850]=0;c[9838]=0;a=p&-16^1431655768;c[p>>2]=a;c[9845]=a;a=4096}else a=c[9847]|0;k=o+48|0;l=o+47|0;h=a+l|0;f=0-a|0;m=h&f;if(m>>>0<=o>>>0){K=0;i=L;return K|0}a=c[9837]|0;if(a|0?(B=c[9835]|0,C=B+m|0,C>>>0<=B>>>0|C>>>0>a>>>0):0){K=0;i=L;return K|0}b:do if(!(c[9838]&4)){d=c[9733]|0;c:do if(d){e=39356;while(1){a=c[e>>2]|0;if(a>>>0<=d>>>0?(u=e+4|0,(a+(c[u>>2]|0)|0)>>>0>d>>>0):0)break;a=c[e+8>>2]|0;if(!a){D=172;break c}else e=a}d=h-j&f;if(d>>>0<2147483647){a=rc(d|0)|0;if((a|0)==((c[e>>2]|0)+(c[u>>2]|0)|0)){if((a|0)!=(-1|0)){h=d;g=a;D=190;break b}}else{b=d;D=180}}}else D=172;while(0);do if(((D|0)==172?(g=rc(0)|0,(g|0)!=(-1|0)):0)?(b=g,v=c[9846]|0,w=v+-1|0,b=((w&b|0)==0?0:(w+b&0-v)-b|0)+m|0,v=c[9835]|0,w=b+v|0,b>>>0>o>>>0&b>>>0<2147483647):0){C=c[9837]|0;if(C|0?w>>>0<=v>>>0|w>>>0>C>>>0:0)break;a=rc(b|0)|0;if((a|0)==(g|0)){h=b;D=190;break b}else D=180}while(0);d:do if((D|0)==180){d=0-b|0;do if(k>>>0>b>>>0&(b>>>0<2147483647&(a|0)!=(-1|0))?(x=c[9847]|0,x=l-b+x&0-x,x>>>0<2147483647):0)if((rc(x|0)|0)==(-1|0)){rc(d|0)|0;break d}else{b=x+b|0;break}while(0);if((a|0)!=(-1|0)){h=b;g=a;D=190;break b}}while(0);c[9838]=c[9838]|4;D=187}else D=187;while(0);if((((D|0)==187?m>>>0<2147483647:0)?(A=rc(m|0)|0,y=rc(0)|0,A>>>0>>0&((A|0)!=(-1|0)&(y|0)!=(-1|0))):0)?(z=y-A|0,z>>>0>(o+40|0)>>>0):0){h=z;g=A;D=190}if((D|0)==190){b=(c[9835]|0)+h|0;c[9835]=b;if(b>>>0>(c[9836]|0)>>>0)c[9836]=b;l=c[9733]|0;do if(l){b=39356;while(1){a=c[b>>2]|0;d=b+4|0;e=c[d>>2]|0;if((g|0)==(a+e|0)){D=200;break}f=c[b+8>>2]|0;if(!f)break;else b=f}if(((D|0)==200?(c[b+12>>2]&8|0)==0:0)?l>>>0>>0&l>>>0>=a>>>0:0){c[d>>2]=e+h;K=l+8|0;K=(K&7|0)==0?0:0-K&7;J=l+K|0;K=h-K+(c[9730]|0)|0;c[9733]=J;c[9730]=K;c[J+4>>2]=K|1;c[J+K+4>>2]=40;c[9734]=c[9849];break}b=c[9731]|0;if(g>>>0>>0){c[9731]=g;j=g}else j=b;a=g+h|0;b=39356;while(1){if((c[b>>2]|0)==(a|0)){D=208;break}b=c[b+8>>2]|0;if(!b){a=39356;break}}if((D|0)==208)if(!(c[b+12>>2]&8)){c[b>>2]=g;n=b+4|0;c[n>>2]=(c[n>>2]|0)+h;n=g+8|0;n=g+((n&7|0)==0?0:0-n&7)|0;b=a+8|0;b=a+((b&7|0)==0?0:0-b&7)|0;m=n+o|0;k=b-n-o|0;c[n+4>>2]=o|3;do if((b|0)!=(l|0)){if((b|0)==(c[9732]|0)){K=(c[9729]|0)+k|0;c[9729]=K;c[9732]=m;c[m+4>>2]=K|1;c[m+K>>2]=K;break}a=c[b+4>>2]|0;if((a&3|0)==1){h=a&-8;f=a>>>3;e:do if(a>>>0>=256){g=c[b+24>>2]|0;e=c[b+12>>2]|0;do if((e|0)==(b|0)){e=b+16|0;d=e+4|0;a=c[d>>2]|0;if(!a){a=c[e>>2]|0;if(!a){I=0;break}else d=e}while(1){e=a+20|0;f=c[e>>2]|0;if(f|0){a=f;d=e;continue}e=a+16|0;f=c[e>>2]|0;if(!f)break;else{a=f;d=e}}if(d>>>0>>0)fa();else{c[d>>2]=0;I=a;break}}else{f=c[b+8>>2]|0;if(f>>>0>>0)fa();a=f+12|0;if((c[a>>2]|0)!=(b|0))fa();d=e+8|0;if((c[d>>2]|0)==(b|0)){c[a>>2]=e;c[d>>2]=f;I=e;break}else fa()}while(0);if(!g)break;a=c[b+28>>2]|0;d=39212+(a<<2)|0;do if((b|0)!=(c[d>>2]|0)){if(g>>>0<(c[9731]|0)>>>0)fa();a=g+16|0;if((c[a>>2]|0)==(b|0))c[a>>2]=I;else c[g+20>>2]=I;if(!I)break e}else{c[d>>2]=I;if(I|0)break;c[9728]=c[9728]&~(1<>>0>>0)fa();c[I+24>>2]=g;a=b+16|0;d=c[a>>2]|0;do if(d|0)if(d>>>0>>0)fa();else{c[I+16>>2]=d;c[d+24>>2]=I;break}while(0);a=c[a+4>>2]|0;if(!a)break;if(a>>>0<(c[9731]|0)>>>0)fa();else{c[I+20>>2]=a;c[a+24>>2]=I;break}}else{d=c[b+8>>2]|0;e=c[b+12>>2]|0;a=38948+(f<<1<<2)|0;do if((d|0)!=(a|0)){if(d>>>0>>0)fa();if((c[d+12>>2]|0)==(b|0))break;fa()}while(0);if((e|0)==(d|0)){c[9727]=c[9727]&~(1<>>0>>0)fa();a=e+8|0;if((c[a>>2]|0)==(b|0)){F=a;break}fa()}while(0);c[d+12>>2]=e;c[F>>2]=d}while(0);b=b+h|0;f=h+k|0}else f=k;b=b+4|0;c[b>>2]=c[b>>2]&-2;c[m+4>>2]=f|1;c[m+f>>2]=f;b=f>>>3;if(f>>>0<256){d=38948+(b<<1<<2)|0;a=c[9727]|0;b=1<>2]|0;if(a>>>0>=(c[9731]|0)>>>0){J=a;K=b;break}fa()}while(0);c[K>>2]=m;c[J+12>>2]=m;c[m+8>>2]=J;c[m+12>>2]=d;break}b=f>>>8;do if(!b)b=0;else{if(f>>>0>16777215){b=31;break}J=(b+1048320|0)>>>16&8;K=b<>>16&4;K=K<>>16&2;b=14-(I|J|b)+(K<>>15)|0;b=f>>>(b+7|0)&1|b<<1}while(0);e=39212+(b<<2)|0;c[m+28>>2]=b;a=m+16|0;c[a+4>>2]=0;c[a>>2]=0;a=c[9728]|0;d=1<>2]=m;c[m+24>>2]=e;c[m+12>>2]=m;c[m+8>>2]=m;break}a=f<<((b|0)==31?0:25-(b>>>1)|0);e=c[e>>2]|0;while(1){if((c[e+4>>2]&-8|0)==(f|0)){D=278;break}d=e+16+(a>>>31<<2)|0;b=c[d>>2]|0;if(!b){D=275;break}else{a=a<<1;e=b}}if((D|0)==275)if(d>>>0<(c[9731]|0)>>>0)fa();else{c[d>>2]=m;c[m+24>>2]=e;c[m+12>>2]=m;c[m+8>>2]=m;break}else if((D|0)==278){b=e+8|0;a=c[b>>2]|0;K=c[9731]|0;if(a>>>0>=K>>>0&e>>>0>=K>>>0){c[a+12>>2]=m;c[b>>2]=m;c[m+8>>2]=a;c[m+12>>2]=e;c[m+24>>2]=0;break}else fa()}}else{K=(c[9730]|0)+k|0;c[9730]=K;c[9733]=m;c[m+4>>2]=K|1}while(0);K=n+8|0;i=L;return K|0}else a=39356;while(1){b=c[a>>2]|0;if(b>>>0<=l>>>0?(E=b+(c[a+4>>2]|0)|0,E>>>0>l>>>0):0)break;a=c[a+8>>2]|0}f=E+-47|0;a=f+8|0;a=f+((a&7|0)==0?0:0-a&7)|0;f=l+16|0;a=a>>>0>>0?l:a;b=a+8|0;d=g+8|0;d=(d&7|0)==0?0:0-d&7;K=g+d|0;d=h+-40-d|0;c[9733]=K;c[9730]=d;c[K+4>>2]=d|1;c[K+d+4>>2]=40;c[9734]=c[9849];d=a+4|0;c[d>>2]=27;c[b>>2]=c[9839];c[b+4>>2]=c[9840];c[b+8>>2]=c[9841];c[b+12>>2]=c[9842];c[9839]=g;c[9840]=h;c[9842]=0;c[9841]=b;b=a+24|0;do{b=b+4|0;c[b>>2]=7}while((b+4|0)>>>0>>0);if((a|0)!=(l|0)){g=a-l|0;c[d>>2]=c[d>>2]&-2;c[l+4>>2]=g|1;c[a>>2]=g;b=g>>>3;if(g>>>0<256){d=38948+(b<<1<<2)|0;a=c[9727]|0;b=1<>2]|0;if(a>>>0<(c[9731]|0)>>>0)fa();else{G=a;H=b}}else{c[9727]=a|b;G=d;H=d+8|0}c[H>>2]=l;c[G+12>>2]=l;c[l+8>>2]=G;c[l+12>>2]=d;break}b=g>>>8;if(b)if(g>>>0>16777215)d=31;else{J=(b+1048320|0)>>>16&8;K=b<>>16&4;K=K<>>16&2;d=14-(I|J|d)+(K<>>15)|0;d=g>>>(d+7|0)&1|d<<1}else d=0;e=39212+(d<<2)|0;c[l+28>>2]=d;c[l+20>>2]=0;c[f>>2]=0;b=c[9728]|0;a=1<>2]=l;c[l+24>>2]=e;c[l+12>>2]=l;c[l+8>>2]=l;break}a=g<<((d|0)==31?0:25-(d>>>1)|0);e=c[e>>2]|0;while(1){if((c[e+4>>2]&-8|0)==(g|0)){D=304;break}d=e+16+(a>>>31<<2)|0;b=c[d>>2]|0;if(!b){D=301;break}else{a=a<<1;e=b}}if((D|0)==301)if(d>>>0<(c[9731]|0)>>>0)fa();else{c[d>>2]=l;c[l+24>>2]=e;c[l+12>>2]=l;c[l+8>>2]=l;break}else if((D|0)==304){b=e+8|0;a=c[b>>2]|0;K=c[9731]|0;if(a>>>0>=K>>>0&e>>>0>=K>>>0){c[a+12>>2]=l;c[b>>2]=l;c[l+8>>2]=a;c[l+12>>2]=e;c[l+24>>2]=0;break}else fa()}}}else{K=c[9731]|0;if((K|0)==0|g>>>0>>0)c[9731]=g;c[9839]=g;c[9840]=h;c[9842]=0;c[9736]=c[9845];c[9735]=-1;b=0;do{K=38948+(b<<1<<2)|0;c[K+12>>2]=K;c[K+8>>2]=K;b=b+1|0}while((b|0)!=32);K=g+8|0;K=(K&7|0)==0?0:0-K&7;J=g+K|0;K=h+-40-K|0;c[9733]=J;c[9730]=K;c[J+4>>2]=K|1;c[J+K+4>>2]=40;c[9734]=c[9849]}while(0);b=c[9730]|0;if(b>>>0>o>>>0){I=b-o|0;c[9730]=I;K=c[9733]|0;J=K+o|0;c[9733]=J;c[J+4>>2]=I|1;c[K+4>>2]=o|3;K=K+8|0;i=L;return K|0}}c[(Rb()|0)>>2]=12;K=0;i=L;return K|0}function ic(a){a=a|0;var b=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0;if(!a)return;d=a+-8|0;h=c[9731]|0;if(d>>>0>>0)fa();a=c[a+-4>>2]|0;b=a&3;if((b|0)==1)fa();e=a&-8;n=d+e|0;do if(!(a&1)){a=c[d>>2]|0;if(!b)return;k=d+(0-a)|0;j=a+e|0;if(k>>>0>>0)fa();if((k|0)==(c[9732]|0)){a=n+4|0;b=c[a>>2]|0;if((b&3|0)!=3){q=k;f=j;break}c[9729]=j;c[a>>2]=b&-2;c[k+4>>2]=j|1;c[k+j>>2]=j;return}e=a>>>3;if(a>>>0<256){b=c[k+8>>2]|0;d=c[k+12>>2]|0;a=38948+(e<<1<<2)|0;if((b|0)!=(a|0)){if(b>>>0>>0)fa();if((c[b+12>>2]|0)!=(k|0))fa()}if((d|0)==(b|0)){c[9727]=c[9727]&~(1<>>0>>0)fa();a=d+8|0;if((c[a>>2]|0)==(k|0))g=a;else fa()}else g=d+8|0;c[b+12>>2]=d;c[g>>2]=b;q=k;f=j;break}g=c[k+24>>2]|0;d=c[k+12>>2]|0;do if((d|0)==(k|0)){d=k+16|0;b=d+4|0;a=c[b>>2]|0;if(!a){a=c[d>>2]|0;if(!a){i=0;break}else b=d}while(1){d=a+20|0;e=c[d>>2]|0;if(e|0){a=e;b=d;continue}d=a+16|0;e=c[d>>2]|0;if(!e)break;else{a=e;b=d}}if(b>>>0>>0)fa();else{c[b>>2]=0;i=a;break}}else{e=c[k+8>>2]|0;if(e>>>0>>0)fa();a=e+12|0;if((c[a>>2]|0)!=(k|0))fa();b=d+8|0;if((c[b>>2]|0)==(k|0)){c[a>>2]=d;c[b>>2]=e;i=d;break}else fa()}while(0);if(g){a=c[k+28>>2]|0;b=39212+(a<<2)|0;if((k|0)==(c[b>>2]|0)){c[b>>2]=i;if(!i){c[9728]=c[9728]&~(1<>>0<(c[9731]|0)>>>0)fa();a=g+16|0;if((c[a>>2]|0)==(k|0))c[a>>2]=i;else c[g+20>>2]=i;if(!i){q=k;f=j;break}}d=c[9731]|0;if(i>>>0>>0)fa();c[i+24>>2]=g;a=k+16|0;b=c[a>>2]|0;do if(b|0)if(b>>>0>>0)fa();else{c[i+16>>2]=b;c[b+24>>2]=i;break}while(0);a=c[a+4>>2]|0;if(a)if(a>>>0<(c[9731]|0)>>>0)fa();else{c[i+20>>2]=a;c[a+24>>2]=i;q=k;f=j;break}else{q=k;f=j}}else{q=k;f=j}}else{q=d;f=e}while(0);if(q>>>0>=n>>>0)fa();a=n+4|0;b=c[a>>2]|0;if(!(b&1))fa();if(!(b&2)){if((n|0)==(c[9733]|0)){p=(c[9730]|0)+f|0;c[9730]=p;c[9733]=q;c[q+4>>2]=p|1;if((q|0)!=(c[9732]|0))return;c[9732]=0;c[9729]=0;return}if((n|0)==(c[9732]|0)){p=(c[9729]|0)+f|0;c[9729]=p;c[9732]=q;c[q+4>>2]=p|1;c[q+p>>2]=p;return}f=(b&-8)+f|0;e=b>>>3;do if(b>>>0>=256){g=c[n+24>>2]|0;a=c[n+12>>2]|0;do if((a|0)==(n|0)){d=n+16|0;b=d+4|0;a=c[b>>2]|0;if(!a){a=c[d>>2]|0;if(!a){m=0;break}else b=d}while(1){d=a+20|0;e=c[d>>2]|0;if(e|0){a=e;b=d;continue}d=a+16|0;e=c[d>>2]|0;if(!e)break;else{a=e;b=d}}if(b>>>0<(c[9731]|0)>>>0)fa();else{c[b>>2]=0;m=a;break}}else{b=c[n+8>>2]|0;if(b>>>0<(c[9731]|0)>>>0)fa();d=b+12|0;if((c[d>>2]|0)!=(n|0))fa();e=a+8|0;if((c[e>>2]|0)==(n|0)){c[d>>2]=a;c[e>>2]=b;m=a;break}else fa()}while(0);if(g|0){a=c[n+28>>2]|0;b=39212+(a<<2)|0;if((n|0)==(c[b>>2]|0)){c[b>>2]=m;if(!m){c[9728]=c[9728]&~(1<>>0<(c[9731]|0)>>>0)fa();a=g+16|0;if((c[a>>2]|0)==(n|0))c[a>>2]=m;else c[g+20>>2]=m;if(!m)break}d=c[9731]|0;if(m>>>0>>0)fa();c[m+24>>2]=g;a=n+16|0;b=c[a>>2]|0;do if(b|0)if(b>>>0>>0)fa();else{c[m+16>>2]=b;c[b+24>>2]=m;break}while(0);a=c[a+4>>2]|0;if(a|0)if(a>>>0<(c[9731]|0)>>>0)fa();else{c[m+20>>2]=a;c[a+24>>2]=m;break}}}else{b=c[n+8>>2]|0;d=c[n+12>>2]|0;a=38948+(e<<1<<2)|0;if((b|0)!=(a|0)){if(b>>>0<(c[9731]|0)>>>0)fa();if((c[b+12>>2]|0)!=(n|0))fa()}if((d|0)==(b|0)){c[9727]=c[9727]&~(1<>>0<(c[9731]|0)>>>0)fa();a=d+8|0;if((c[a>>2]|0)==(n|0))l=a;else fa()}else l=d+8|0;c[b+12>>2]=d;c[l>>2]=b}while(0);c[q+4>>2]=f|1;c[q+f>>2]=f;if((q|0)==(c[9732]|0)){c[9729]=f;return}}else{c[a>>2]=b&-2;c[q+4>>2]=f|1;c[q+f>>2]=f}a=f>>>3;if(f>>>0<256){d=38948+(a<<1<<2)|0;b=c[9727]|0;a=1<>2]|0;if(b>>>0<(c[9731]|0)>>>0)fa();else{o=b;p=a}}else{c[9727]=b|a;o=d;p=d+8|0}c[p>>2]=q;c[o+12>>2]=q;c[q+8>>2]=o;c[q+12>>2]=d;return}a=f>>>8;if(a)if(f>>>0>16777215)a=31;else{o=(a+1048320|0)>>>16&8;p=a<>>16&4;p=p<>>16&2;a=14-(n|o|a)+(p<>>15)|0;a=f>>>(a+7|0)&1|a<<1}else a=0;e=39212+(a<<2)|0;c[q+28>>2]=a;c[q+20>>2]=0;c[q+16>>2]=0;b=c[9728]|0;d=1<>>1)|0);e=c[e>>2]|0;while(1){if((c[e+4>>2]&-8|0)==(f|0)){a=130;break}d=e+16+(b>>>31<<2)|0;a=c[d>>2]|0;if(!a){a=127;break}else{b=b<<1;e=a}}if((a|0)==127)if(d>>>0<(c[9731]|0)>>>0)fa();else{c[d>>2]=q;c[q+24>>2]=e;c[q+12>>2]=q;c[q+8>>2]=q;break}else if((a|0)==130){a=e+8|0;b=c[a>>2]|0;p=c[9731]|0;if(b>>>0>=p>>>0&e>>>0>=p>>>0){c[b+12>>2]=q;c[a>>2]=q;c[q+8>>2]=b;c[q+12>>2]=e;c[q+24>>2]=0;break}else fa()}}else{c[9728]=b|d;c[e>>2]=q;c[q+24>>2]=e;c[q+12>>2]=q;c[q+8>>2]=q}while(0);q=(c[9735]|0)+-1|0;c[9735]=q;if(!q)a=39364;else return;while(1){a=c[a>>2]|0;if(!a)break;else a=a+8|0}c[9735]=-1;return}function jc(){}function kc(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;d=b-d-(c>>>0>a>>>0|0)>>>0;return (C=d,a-c>>>0|0)|0}function lc(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,i=0;f=b+e|0;if((e|0)>=20){d=d&255;h=b&3;i=d|d<<8|d<<16|d<<24;g=f&~3;if(h){h=b+4-h|0;while((b|0)<(h|0)){a[b>>0]=d;b=b+1|0}}while((b|0)<(g|0)){c[b>>2]=i;b=b+4|0}}while((b|0)<(f|0)){a[b>>0]=d;b=b+1|0}return b-e|0}function mc(a,b,c){a=a|0;b=b|0;c=c|0;if((c|0)<32){C=b>>>c;return a>>>c|(b&(1<>>c-32|0}function nc(a,b,c){a=a|0;b=b|0;c=c|0;if((c|0)<32){C=b<>>32-c;return a<>>16;a=(c>>>16)+(R(e,d)|0)|0;e=b>>>16;b=R(e,f)|0;return (C=(a>>>16)+(R(e,d)|0)+(((a&65535)+b|0)>>>16)|0,a+b<<16|c&65535|0)|0}function pc(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0,f=0;e=a;f=c;c=oc(e,f)|0;a=C;return (C=(R(b,f)|0)+(R(d,e)|0)+a|a&0,c|0|0)|0}function qc(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;c=a+c>>>0;return (C=b+d+(c>>>0>>0|0)>>>0,c|0)|0}function rc(a){a=a|0;var b=0,d=0;d=a+15&-16|0;b=c[k>>2]|0;a=b+d|0;if((d|0)>0&(a|0)<(b|0)|(a|0)<0){Z()|0;sa(12);return -1}c[k>>2]=a;if((a|0)>(Y()|0)?(X()|0)==0:0){sa(12);c[k>>2]=b;return -1}return b|0}function sc(a){a=a|0;return (a&255)<<24|(a>>8&255)<<16|(a>>16&255)<<8|a>>>24|0}function tc(b,d,e){b=b|0;d=d|0;e=e|0;var f=0;if((e|0)>=4096)return la(b|0,d|0,e|0)|0;f=b|0;if((b&3)==(d&3)){while(b&3){if(!e)return f|0;a[b>>0]=a[d>>0]|0;b=b+1|0;d=d+1|0;e=e-1|0}while((e|0)>=4){c[b>>2]=c[d>>2];b=b+4|0;d=d+4|0;e=e-4|0}}while((e|0)>0){a[b>>0]=a[d>>0]|0;b=b+1|0;d=d+1|0;e=e-1|0}return f|0}function uc(){return 0}function vc(a,b){a=a|0;b=b|0;return ua[a&1](b|0)|0}function wc(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;return va[a&7](b|0,c|0,d|0)|0}function xc(a,b){a=a|0;b=b|0;wa[a&3](b|0)}function yc(a){a=a|0;V(0);return 0}function zc(a,b,c){a=a|0;b=b|0;c=c|0;V(1);return 0}function Ac(a){a=a|0;V(2)} // EMSCRIPTEN_END_FUNCS var ua=[yc,Nb];var va=[zc,Wb,Pb,Ub,Ob,zc,zc,zc];var wa=[Ac,Sb,Vb,Ac];return{___muldsi3:oc,_sbrk:rc,_i64Subtract:kc,_free:ic,_ecdsa_read_pubkey:lb,_i64Add:qc,_pthread_self:uc,_memset:lc,_malloc:hc,_memcpy:tc,_llvm_bswap_i32:sc,___muldi3:pc,_bitshift64Lshr:mc,_fflush:ec,_hdnode_public_ckd_address_optimized:ub,___errno_location:Rb,_bitshift64Shl:nc,runPostSets:jc,stackAlloc:xa,stackSave:ya,stackRestore:za,establishStackSpace:Aa,setThrew:Ba,setTempRet0:Ca,getTempRet0:Da,dynCall_ii:vc,dynCall_iiii:wc,dynCall_vi:xc}}) @@ -374,6 +374,6 @@ e.callMain=e.ad=function(a){function b(){for(var a=0;3>a;a++)d.push(0)}a=a||[];z function wc(a){function b(){if(!e.calledRun&&(e.calledRun=!0,!ja)){za||(za=!0,Qa(Sa));Qa(Ta);if(e.onRuntimeInitialized)e.onRuntimeInitialized();e._main&&yc&&e.callMain(a);if(e.postRun)for("function"==typeof e.postRun&&(e.postRun=[e.postRun]);e.postRun.length;)Wa(e.postRun.shift());Qa(Ua)}}a=a||e.arguments;null===uc&&(uc=Date.now());if(!(0 Date: Fri, 31 Mar 2017 18:26:34 +0200 Subject: [PATCH 394/627] Fixing C test of optimized bip32 --- test_speed.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test_speed.c b/test_speed.c index 7e02d3488..4b0d1707c 100644 --- a/test_speed.c +++ b/test_speed.c @@ -134,7 +134,7 @@ void bench_ckd_optimized(int iterations) ecdsa_read_pubkey(&secp256k1, root.public_key, &pub); clock_t t = clock(); for (int i = 0; i < iterations; i++) { - hdnode_public_ckd_address_optimized(&pub, root.chain_code, i, 0, addr, sizeof(addr)); + hdnode_public_ckd_address_optimized(&pub, root.chain_code, i, 0, addr, sizeof(addr), false); if (i == 0 || i == iterations -1) { printf("address = %s\n", addr); } From 0094706e0e6594bf991a9bcaec33bccc4189ca18 Mon Sep 17 00:00:00 2001 From: Karel Bilek Date: Fri, 31 Mar 2017 22:19:37 +0200 Subject: [PATCH 395/627] Adding segwit test vector --- emscripten/Makefile | 2 +- emscripten/test-addresses-segwit-p2sh.txt | 1001 ++++++++++++++++++++ emscripten/test-correctness-segwit-p2sh.js | 30 + emscripten/test-correctness.js | 3 - 4 files changed, 1032 insertions(+), 4 deletions(-) create mode 100644 emscripten/test-addresses-segwit-p2sh.txt create mode 100644 emscripten/test-correctness-segwit-p2sh.js diff --git a/emscripten/Makefile b/emscripten/Makefile index 6bcc01ee2..11c07169f 100644 --- a/emscripten/Makefile +++ b/emscripten/Makefile @@ -34,4 +34,4 @@ docker-build: docker run --rm -v $(shell pwd)/..:/src apiaryio/emcc /bin/bash -c 'cd emscripten && make' test-correctness: node_modules - node test-correctness.js + node test-correctness.js test-correctness-segwit-p2sh.js diff --git a/emscripten/test-addresses-segwit-p2sh.txt b/emscripten/test-addresses-segwit-p2sh.txt new file mode 100644 index 000000000..8b06787d8 --- /dev/null +++ b/emscripten/test-addresses-segwit-p2sh.txt @@ -0,0 +1,1001 @@ +3L6TyTisPBmrDAj6RoKmDzNnj4eQi54gD2 +3GMMgFUQiYTYQhuHQuZfQoXPvW3GPqfGmD +3BKbtvJtLSjnSoGUYTeQ17tMKTuyqbUV7P +3Dyf1D6pVR6ZAQYN1th6ehgS1uqgGk1TGh +33wLRyxHFtrXLF7Aun38Dctw5QyiBdruK2 +32pKKUD5TKyqb4kzPorJnY8XhiLaHBKni1 +3NCRi181wMB1v9gPyms9WDruKemBfrE9rQ +32d6ze9Be4J45ERomziXxGWXxLobAAQq85 +3FNTNKoAcXDUTUSNAtVTcvAehwQLyJSmP9 +3L55P4LZsyKYUw5Aqy6DPky6ySw3g34TQS +3QUYdkHXqUh596y3nSrqd1Wo9hvXDHC391 +3LSrVvK9jQTemnSyj9sqzD7wFTHwD8zqM7 +3NVbd95gArUqSZ6yJWpc2S558xsfXvgu8y +39RWZUTeiNuNb5GjhcrU636FKB6DF1EMpn +37uK6ozVfE5G35oUmu3Y9z3Y1veV6KrQgZ +32Px86LYPEPTQBCSY3oqw7nsJjgaFZeu8w +3Nr9468Yg3SR1uvT91eVVcK5HDBsvBV1WA +3GmgGz1EDuEegTFX8ZvRY3D9Hn5YdAHVHw +3C9pLLkD9GWaeoe5Wk1Fzh8heCtvWiMu9y +3JVy2YsVyGHiyV4Mpd72VfRgjMEc5sh4xB +3BEK3pjowHUJyBLoJUGmEiMdbS5f3Uc8kz +3MY7p5Cwv2ZXnjaqsinoS38nw64DzF6KsL +3JNH6miNDAtjaEGTUpUj2N49hpCdZDR9tD +37oPVPaHVDzCRvhjGJCbbFoY2zir7Zwa7s +3PRc5bYn5cJXbCtTkE4CqXTsydLLJ8r2kz +3Ls1ZtNeUm2EhZguHg5gHM16MCmkaHHvYv +35cQ6AS5BFPnvJzMdKUgvn12okTFW4xiUk +36ZokNVM61qVXwJ2kPjheD5NXv8R1m4kNx +35qSDRkPGrsZakQjfWCsVu4XXQVXfpE4VH +3MeTLGKR7ZGAiDNKhuLkeL485iubhUPuun +34g5cGJi4KvDRSXUHkvoHQ814JnUtkKEJR +392DKjhHFBCF5VV37wbqUWJKeyrPUwJ99w +3KeSMat1jJD9hTUzz2y1dzUHmNM3h8ASwR +3No5TYGwyihJeYASUR8R7tfrGfcR34iLpw +3QnNX54yJ1dMfGEjPj78M6VdfBgd2AA8H4 +3EcbwVoWKVsktWeEwefDbe416xk7kdExdP +36b2VYEoCPKxPq8e8cpP43SNffj3uvjbY5 +39BtjJpWxEFrYcxqnbv45UHaCvNMa8QjMB +36CWUsqi89VQYX25aLkoTjnvLkMVETVBUg +3FYQ9DUaKU3bfuibADb8VK7gv8YC4etnJC +3HDPiUsdCJqeKxMefN9Qgir7T82ttUGHj3 +34PxdeMc3GPB21aSHWdUskRuiKb7EUisJh +3LnStYPBS1mAhN67UtSahS6LGHsiVmApkP +3P4jqTxnq85Ln9TJ5458EiNX6uowZeftmQ +3LtexPXYoYW6QYdEk8UKfyXHpfsL3dkzhW +3NcBeiCaCTFnGUuR1DFWqHnrh1yHcW7vs6 +34DbTn7C2EpCT9PGwAZ34nEQqm417rdjs9 +36iyb6aG34fqRQY5nckjKQBP1ie2HrCf8b +3BZrb86oAVd6PxA6eUjNjFnftFvoWNS1jc +3KE6HXaLGA8AGhmt6qBVCUySPshPfAzSvL +36xBToEgeMRt7rNxMHRBZMsJ4mdiZR2KPq +39dj1YhQrrTrXr4EKxAPMk1MptPHnAEjtP +3GYBScjaBYkitkiir988cAoYy2ywun4DJ2 +32sPwqW7TebhLdK2PZVD5rUsAmGuNtPPyu +3GcTnN9CqwPmmumyz2Gpjad2vRXTTVTvZC +3DEAk9KGrgvj2gHQ1hyfCXus9hZr9K8Beh +3DDEgt7quAq7XqoG6PjVXi1eeAea4rfWck +3AAVuCwY14GhZxneLdnyyHVnbxrnybvfLG +38dN4pKoM5xj7Ng3x77MQjTzFu5pGfao1k +3BpgvVhxeLPXaSky6XKbRGhqy8qqStdPaa +3Lv3RTGKZTm2G3Ffmi5STD4bSs21ZZGCgb +3H3VjuiyT2yZeb5kCfHvbpsojuxWGFahVq +3G41qJZTA41WTCf72U1uCkv7NYV3kTw8De +3DqVnsZhebv3TzRHxuBH3yMB9e57AKdk6N +36TdEmtdTNwyVF1LcCQBWb3fUzcaYefjUF +3KEY3rtdNVKVAY1VaWQxKTFqzviELndU9L +3JduTJqDLS6HeASbKgd8BJ2n6T7FDoKUKh +3PfsZaRzm13wddt74z4XB4UqftAhkUGhxq +34ZmW5gD8s9s3gzBHLjz9hTDajwyVYbMXC +32MG7JkvmLtr8tJfck4VopRb2L3GJFFqQW +3Dr8FASDUmvL6zR1X4SmpFCQFCMDyVYmgs +37yxSBtTyDDadVDp5m7yXRWteLEWMFfJ2E +3PoBGg2EN2n7egvoheJVEdbidA95YREtBd +3BXjcAzmWFBJ3vmzMs9bj6N6UszV4PCBG5 +3Jhttc2iRyT8ZLZk9px4VXuCze3RaW2Esy +3EVtXiRUhSLtRtKGgiAr6w81SEihf79rAB +3HyKdhyaDQXmrkXwPgiQupwy7VJEG76EAA +32RTpbK5pBLc2nJshZRQRHxTJ3fCSYKhHy +3HEqaNBsNHNS4a2UhnsJeGuYkzPa4dEiFx +34CW8uoLtrphrcpyUFvZHFbdLTk7LdrA3a +3Ep4h4GCgRam5VYnQVFR3zKkoA5C7rY1Yg +3JcVQHPjeF55U4CqG8VwczN5yh71jtBwoE +35LLdriZnzD2kkwTNdn67uusqSRMQVGBW6 +3Dzf6T3d7TdzrvungAmyrecLQACETAd26E +37D3oRNsL4AQ7xMg1V2DGANoc91nmt6ncn +3GsQ4ybMZZB95b4KvhgoVd7wCfP15A3C4C +3MsFkAVEx8qdEDjbhBgCkxvHPYNZdsvEMv +34AEwPwjHnfho9sxabzoYYGgw4pRh7Nnx2 +3EMQZP2AyrYfgB1WbZBaRVAPQZcStDKp2P +3Cy3X7Bc3ETRZNitRU9CBEFduAnyhrK3Wt +3PvsU51ccgJTqxVWyi7U3xK2PdRKKtkcik +3PoP4fcaESzfPEYbdseAFSeV7us4k9fvtR +3CYTYw1g4KqmkRL6bxjRkVuJG3c5PhzGQa +3KEwXq9tAeX1JdNqKpqfDZYvie4GHJV3P7 +32RyQNez8F74xZzyFgLutEVYpJhgRGYpzM +3HxxnrxsVqi5xxzM4hK6A3eg8PKRNjBwZz +38LULYeGHYnZUnm7qqB97TEBMXhVmZsRUE +3KmBxRUkDupzQsX4hRqzx9GMzcQ65gDQXp +38CmCv5ZtCWS89EqKKBPe3Q3EpGLNVXL3Q +39fkbE1D4sfc2hG385gHnMzyuU8qFZDUDr +394WfmmiuKJhZvPmTTPh6cJGUDxzKgq8eG +35ZRKaEDJ87cFsBUYPxSicNEqi1RUZNoTW +3H3X8fQ5pwLaxmnA24sKH1XUupnrnKL7is +3FGkrSSjyhYKJ5mqU8mRrEhMNQtTXL8m3N +3CEsMxjUG8vBFs1aURjgX3V2oCqNNGbp7i +3EDV71yq84X6q2uSYYYBtrbzao4yyYRBp9 +3AALBMc96FApvdHVaMk5q85bT3i424aWBk +3Ef3XwwckWbqSpj51PtrmcAFkvg4pQgGKV +39kF6UbxnZaRhURAKpwjZpCce9o6qeZZrv +3CNdahrrayWEDVYsYzz2eK65cdvSHcVPgh +3BbXJHBsFDXVmYMBgdEfi5FGpbiDHWXf7e +3D2vB7NXrXpiPJm3Lxf8GaefiqBo4hgJeB +3D8VCaGovUuMmgaJsYjkNzmsiCxPB29HA5 +39C59wJZqumNrXtXaJ6SAsS5NZcNXpfWd3 +3MCYPB8SsyEyDhweEww3NPN71VJzBwJNBd +3Qar97RYd2AbJupsktRqEo4U3HDfu7PhCg +3Jg9qAWv8bVQy1qaxHgPzf6RnQEaovGP4D +3MToyVfVTtz8m5BSoTmoYP3o6zwvkwiHza +381fixojPQmwJ52FWdbMezL67xcct1kkJ8 +38q1znmvmhydbszNgH4Nsuu1xyFvomjyeb +3G73GQG4AMVt1UwWD8nRJthxYVbjrJAL2v +391G3wDCXNRTmEn5SeuMonwhiNteewjuWP +37WUSLfbPXCBWfbGcCvYhvPrGLMsA6p1wc +3BEZDvhBXjvugNeD1ZTBnSUwNP5jXWPHX2 +3LG4poMSHpFfQNR5CNnuARQ4Z1rWBes486 +35mZSVZz3FcAdkaJApupNmsFRuExxc9a6W +3Q78psT2LSEUziG4TyezZzT9eJaVJrxvSM +3B6J1ssSk7nj4tRdHYAS5Rk4FAfQug1KAd +3Hf1int17fDuLFeSQK7Qt3eajPfrqtt9cB +34mHkCSxAjRDuzxPnzRM7DsiJTWLqgmRG1 +3PToajRg8PMJicBoFhetftxNg68jXzyFdd +3ENbeAhd15EdFqrnYr9HWcAM59kUKAEVH1 +3BJTCd6aA5qqhBASquA7WDFnWu5MfvSMZe +3D2KVUuewqVeNd48mJJv57AbXavPoyVDSt +33kgX4pUwisdZr63y4yg5dkeWtyNm19Tce +39ApLYH7yPPeQWnHmNpwhjnx5rwuygQjeW +3MxRzPcqSKW5hq9XeNtXR5eghzwJS8Sn42 +3Jay1T9dHjEvxhFWu9bx5RWqfxvPVCaLjS +3JwA6tEjLpwCQYD7kfEJJTriUssyqNhyJp +3E7K9gCGA52KEHbc9WJjrKrVkkugtJsWt9 +34Nw8rKMyKjD738oFzdF6c6piU9KvAiXPF +3PWYXFEeh3VXiQQQWS9RyP8mqxV73AiMKD +3B2xXCtWpKbAzPiBUifUDyV5rfX5RwvUCA +32r8NwCVFzwSSNUEbE8AG4UPYEaNtvJAVB +3Lo4bJdFBi3N2Bu5UBRpmq4oMgq54iKzaS +33aGcY5baLuYzZbmPpELJBhBQkfmEb9uhZ +3EKcxDj6a24zL5ER6zgTzm4kbjfzsPAhFD +38Ua4cxZimk3kF9kjYutgHbTF68v2u5ZZU +3GGqTUnmPs2TLkyC3P9qvcAaj4fE2TGaar +3Nsrx1kSbYa5g2QptUuTeaoHx4JpgqJP5U +35e9AtgykmE8FcnKxXu9e79yAoVLkDThH5 +35iQrqAJEQxTRRMv5CbBUTdqmhxH74KD7H +3BoAvoQb5rb2xnwJzT8bExWKzngjjDhQRQ +3FYUxi6d8d4gpbZfcdTGUZtiSVNfMVTwjd +3KQHuRJjep5h7NGvhvWABH7wAwXzAjd9LH +37yHo2YfZ94kVGBBgvpF8C54GtB9zcChdw +3BFejSxEJynev1VxEfFxrYXRDMiVu5V3ga +3KEQ8fgBbp9EYjKDDPpVKQqc1PYnrCxsSK +36s4vvQNHrwuj1FS8h8nDGz9Af3irU9K4J +38HgcZAs9Hzhzx9NU8UVnbTqiuVyqwEEpv +3Mtby8dhy1j99FPKczS3418NiKR3GN8TTp +3APwYdK4bdeuFbpVKhuHuqUiR8FKGrcf1B +39wbDWDDJj65mMGichyCtaWxS3NZ53XkCz +3Ng36zB3As9GEjLYXNaY2QujrL714xRz9T +3FB3hLqHA6wQy6dEjgNVmsp8araWnTmhBj +3Gi1gpsX8ADmfd7jZP2Cw7KB6ECPUzNHqW +3EQavtEiEZNBXXKzPNQRNBLvpYWafJsKx1 +3DHDH9AQ2zRWbzSchbsKdHWFvBeMtyE9xt +38Awq1VkndCAe1GGYisgbz2tahacXcbMii +3LJgE5CukXNkey2bXzUuvLmD8RwoSiQWb4 +31tVLdmfSHx7NCmX6wWTnaRh38EMMszaqr +3LvMR7ajcLno5Mos6aYTMPHyRL1WEyTPQd +3QjNACh1jimgM2Suk1J39orYFzSRukdCir +3DtToHiK6LuCLwXsrFn86YJbZTrbBGTxgt +39FM8S2DHoT7c8y4ZDkvSuMbVX1QfajkXB +3KAoG8pg6WtXXLkireP6oEhA1DPHiLpcqb +36eESGCgXivSuXT5tXKVxtpVegmsYBVvqV +3LZWwbcUC8itYrUERdSbGCz5BJCR8dZkMm +3HwYZFj8h4h5oSvC3FTraTdByqaxdX4zQK +3PW9gZPuvNpGUCqKeXdPLCcLg2tgF89Dw1 +3FBrWKVpsj6gMnVZxuk9dR5pB59AKJNUyt +34CGcF9Z423ZtpTMnrudcp3nwx21SxDomd +3JaGfRyJkUcyETYmVsmm9EqyPk7kAntHRD +3B9KKoBXJBLnUpNhmPz8HGCCZA42fofeyA +3HKnua8DtGDXXN5gRG3qcLSMwAbqBpJzoG +3EVvcXvC1tVhBLamCeqtw3NtWkEdZSfSeh +36Qd5m1kTRKyBvakGgpPn9mbYr2PokaKsH +3ANZVa73V8tvfKCna3Gi7pvyGcqeMn1aDM +31js7uf83h2U9wuziYNXW2Ky5wGXmJW28G +3DfRd2bXxT8TYCyShwPUs8fB2vB4VCdQaU +3Gcob9CoJUknXp4Gd9xHrEGLrEPBbThgTj +3H6BjYJGKZjvaZyH4Nib7ASo87x2aw9jRm +3LnfxKWRD6FR2K12HfRqwuoJUFtZuJbDwH +3FySJ94MJLB9KPoQedbGT95DTaVVcBXXHv +3AsuiWeDknv6oE5ameVxYxN37VRYNXqQpy +34GJ6JRvr59iYDdn4LSvfhNs7drEjvNivZ +3JWLaXiUZJQALwPjXM1Q7zMUigkevwqGCr +31kd4USisJARZbUJVeiQwT8vJPruCet2AQ +3Av8DdCNJN8fy3ZV5kv424Rsdr5nPSv2wd +3NgsLbMUDsCk6x33vTcRWuuz71SXX59UDf +39scmZ4WSYyvXcK9evZKw8q2WxRfGngDS6 +3Cthen1QN4jaSLbmJGu7NpaZZ4tHZFvuuU +3B6JqdUQ4qdSokxs6WK8myfqeXxZfjG1mr +3PnCVj6SCRKvWXthmQDhKGTcgPip8CigLx +3DDXfQMfZ5D9KRTXsGLy3rRoDS2qzCLVWa +3HhSxMLaPcSARmWbq6iJGua58q1QxPnuyH +3Q9anVecF51TnKpHpJRFmQC7CsJV7Wsbjp +395itDqVRWgLZiLYaV4iWTi88SD81wMRrN +34m6dNeV8Y1ekCLTCxa8fLPPFPJpCLDFTT +334CRfuhkRmsTAYqm9kEcCsRq2drt63GGh +38Zo2Sg1NgWgD3bdPuqS8ZNXhRQRUdUwTo +3Fb2eKvyCixRop6UNqi7j3YSKZVTBW4Q9q +3M3qP8ED67yCRKyegpUMpP6aSwEa7F7dqv +35S13HitowwoMFvVgQQAGBr54qQGmnJo6e +3JHoB2dDPxcU1vLtbcxxvxnaWUxX2rtD3j +38mxcJkYHmrz39aXUAdwkiY56UnSKsHcvi +3LXfABPvn7tdp3dWs8KndRTWVvAhd71xHe +3AAkwi9ysQUf31fQzmToEemmhZ5wD9f8P7 +3QVas1yE3KEo4qmmiqR9iAb33vC4wJtoei +3N3wfptzCnEKGNPshQQxM87qPCT7oPqAAe +3BGoxh6QobBzGsEcuqWEernPkLfEEAnveP +37ckjTdwRDTvaKb4dp3GEhQLEftN2bAgo4 +3MHitmAa8WvUKRiJZeBPCrKGBkQctn71CZ +3BNpK5Jxyx4tt6ZNxXq3weha1cyqAjLNKv +34g5efpp89DbcizSWbwnuMVNzK2NrjgmAN +3HLexR3V5yHfZTnugRAoAV46cwMDSdv8TA +3QhJRdaATGP2w9HcvwVqxoS54dytbojvXA +39PMxps7ZLfegv7pd3gS14DS4x4y3HTZS5 +3DQiceqDi47oNkZtDX3x5nfVTdgZpXtv35 +3NcEAAt47ZoooSdHyniJ44ncCpxhps4pE8 +3GMkfeLcnxGw7xmDrUwxSFXqz7yCAbatuS +3BPsFcRYhfrLPVXW8eLgtUcZ6MMLzMhui7 +34SSzaXNNxHk3FFmKSip1geB1MWUX9qW1K +37x3QMz5MPWoQvAeQGKz5fv2ZRBsa7xQMw +3GpYKMvD8WnszHmyGujyv6vj13oenKUknP +3Hh2JxSH7Qatje7ev9k9qKCuEnwrWP6i7i +3G1PVGeiLxXDef31eo9Mtb9PJdrY1qi4T9 +3MVvq3MNQteKod56oVNxYSnnVvzn7qFyQ2 +35mSKfaHBDhsd9ECPGvJTYjeVS5FJFbWc9 +3MrWBCQ4HDfCjniobUMvuZhrABxAhd2vgh +3BPTMUCkfzfFYo2xRDTj4DfbsBiiUmCGVU +3HTX5DL4AX2zpQNrnEGG75pLhPzJuQoZVS +3Jr3MvNuq1MvtdLkYhdNCrmtWUxXXpknxT +3PbU4r1azQoKs2eFL1jQzL76u8u3rmtLAN +3MM4X2dGkEMHeKZYJSmf1cqAH5ci6rNgKj +3QqpkHXKGkcmHJ1Hb3GmbdYhwFLqjF152M +355m2CJuTiTpM8FpcjG4ag7VcJoWH7MVgy +3C28kVoK5mimgV7t39EGbBCRg9hfdzCR2c +3Jbok7ncfp5vfh4yx9Btap8gbheeNrwwy8 +38EygWfJheecCKfKissVeXAJJFSMvnXTSx +33gDy43DtzPZDntwUTBm54mVCs6bZJwVUc +37Er8AmgGgymzvyhFZrFnYae1Ujjyx16yK +36V9U3Uhbv7TBwzEvDBWoXNvJfGqH3K7HA +35sKhEvTxDrpWaAtVKr9WZg7iMNK68bKjR +39JyYcV7ni2YEEjmb1RJJgi6m5zc86uaoi +3ErCHnzHtM4aJEJNgQCCXSAeiqy2ATsfRv +3BXaXWMweNeZa4qDTU7e7YbjFL6LUAqBqh +3PXuVnzee5aT1BEPyzNQHC1oejmjVsXb9Z +3N9UNh1WnsTjMRMRRghyDGi5sYUgfGabyu +3QDRoSqGJCNai9BszsT1H6ohQS8P5xXzQM +3MH4a5oZTmqgix3GkdKTB4MLLfCqXjrFx8 +3M6q6tB3byGjHb1DaMJWnMaGkvLxGUNvuC +3Gb2HAkNDedBneFAx6NHRkreJVyqatciaz +3GwRuLwbNi387Q724zyurWacgvodJYqeaG +3G2HLzgggdCbjT4R7LCQB6VC2epCdkruUc +34oo6hWHJuM2oUALJnyVfoH96Ry6nVevSr +3BUzzsTvrmXj53s3jdMTefQ8UHTvmSrrQ9 +3CE656Fob3tEGRb6yvW1Ei1FKWFUjYb7xs +3PSckpv9Khn5a2JsBa3gE3tX4W2bmqLUHY +3CpLrJmVqmvu4g4npQeTjae8Mhx38d7TEf +32E5cLsJrJhoked2ZP6n7WzNvcCfWjXq4b +3H4tYTKw1Vk3bcAn7ropZLMzvuLPcLbNX3 +3DkRczeJT2abDWY3Jz5L8u6rkUqMDsLWCH +3CouBpbYoAHXfNWWWT1nrv6ovMWA5f2K3z +3CPG67PZGoiWR7m3S345XnwphNn9PSWKkk +37bAg19dst1JsdVbpvbcXoWG2Ept1JQQ2X +31xwFJoBGnWbqtxd2XK887uCW7DcC21q1N +3G9tCzxHFmzYmcu1ZTPsEqFtuzWSajTzM8 +3MdTw93dyG5pjnaKh9kRUsnLZGBMCyhe3H +3JYHRJDFVrWXuWmuJURRwogPkxSmYgQ3bK +32jxYHDj4JV6Q7CYzyeVfHakeg3zJXnHMT +3Kx7oP5MMKxQ39XUa2UsgvPmvx8vLGca57 +3N41fo3Rmk1ayYyXT1wXxFq2oFAEbk1MDg +39XA63rsXkpLKAGuGd2kDqVccaC3j5Uq4u +3M9bpEng5CLNvMkx48CkRjvhPeiLRJ7gHS +3FyYYSSpnXjgajuVjS13oWnGbNbAj4B4Rs +37q8tuMcq6H9UWtxe3iBeaWdiAwxNzRufw +3Ci9S6NfyYPoq9db9vS2rVvRdGy1CvG4XK +33eJznYW7soHwpPgfSwWw6o1ZH2jkGdzgt +3EoACBva5Wt6ViyF4APQRn1mTTor2WqxNm +3KGZppQhzndnW14CPrek2gqseNDcFH9AoF +3JncQ5wy9iR2ZVg1faHcmnruK4asiEsKzs +3AyQmownVfTHLs687vgPWtC77Vv7T5q1Jh +3R2ardYGFhwKEEi9VBAwe5B2LbkT2nXggG +3JruDbZnJWUcF7wvue7naRNAV1Kn8x4KPo +3F9ZGgm6T9AUQpJbrpUaUUA4UjCXMxLSF3 +362AucPPeMUe9o8BTkRVxTEHy6hHWKucdG +35QtHk6eZAaQEir8PSq8ZRk1xPBWLdgpdH +326TKYh8dpRw6Jb76iryX1n1vU1nG5Umxb +375X2J6QfXjNH3ZCAEuucTopqWXqpjcbJZ +3KJogBBb35iK5barU5MTuJJ4giJGNJ8s5b +35qqxXGYdWBGi86vUUjNxE7p2iQJ7eq4bU +3Quz5WYEAQiayi1EAPLVvsvmrgUe4gLcTf +3FidZfuw8DcSGnWq6R3P6VJPd1thju7p6b +3F45YuvEodf7aq7BDFBLYufxMekjS5txka +3HhPjspM7HybkQJL4ej8cADCFvgkgL1XGL +3BCCvN97bGezVa54REBJnMCk8E2VU8cDdN +34SxNu7b65VPK8EfLehoSMGVZf5xzmUPMi +361ePvZFy9USCFJDBWUwXzZMcbcEJDmKca +3BFtrWf5gH6eZtUJzNZJvLS2TveNoP5h3T +39kkXMUQrhS3XivCMLCFf896ujj3YbxWMg +3QNHp8AQRwRojWYDPpgnrgZsqXcQhBt6vQ +3CmTuso1QS1KQdPCKasccJvyF8qe4gy8ht +35SVXZmzriTe8RHAGC97KXSRDgcYUeZ5Qu +38HnbftkWAjDuGWxtkw9qjkdjSv82Ezymb +31mUJDPhKJr7rcL1eG35wkRMn3npm82Q4k +3QBKmLVVt6MWd2N1emrUzFpDk9dKym2ptD +34y7NbJYxHfTkaxGX8WFFHjGUXjWSW2NWA +3NQbLLb5cEBVubVsp9oRkzWFQEU4wiD6Jx +33whNENQeuEH9WDNYRUofUPYVPy3Q2TxXS +391ZdeW4YymhKAT6kzBKDY3JuzNzevZV4L +3MNExBQiLDSRYfjQ3Qx9ndrJgTBoqD9rnM +3G13D1t2dwAi1A4kYHsyK4h6W852qCPZM7 +3N1rX7mrLM5tvdapevSJgocjZKEJagThQU +3NFEe52aNsH3eobeH5Wf59RPEK5p5gWDGB +31iK7aLeMWssxo2TxUFFrff2q1VYAEx6Mp +35Z5JDC3hbvyaQNB1XCUyLBbYiK1oe1UKG +35mfUkdtQuJziATLBquipxYoW2oSQdnynz +3HXxHQZbAj3iKr8DoojawxY8mVSK5fFCt9 +3GMLeVDxsvn6WCrDkFRFCMqEZd5QA13SEc +3B9gFuGrnujb5cQRPXJJEBaKgangfuEjCw +3Q3KsiQ949JFC1oqbVV6qqp6avdbRD6KFc +3L7bBGUoVQZddCPpotujudGS82bSdFG6G1 +31rwfH9MrvowcSRzVT52o7gzHrzdzJUp7Y +3Ht7nGkERcU8kMxScKF6fm8c5F3e7PsgsE +3NViHVXE3nxfjtbPkHkSSiCFcscC6XLnmS +3Cv7GtuL9wX4JEnf8Q1WGYDaQpBNicXBvm +35ix858Ju1CNppRtBneMNAfxG2rACwRAQd +3F6Sg4e3smKmT9pDCUXEK1pMKAzBna8xLm +3LDVkthExgq9cweTv25vDReMiuYFfUgEvB +32zGVSJMzaFWW6b7mJqKFsh3Jj2jd9GiK5 +3PigVb8hCrtepwnQMiE3x73vfcjqiTAbke +3GDZ5NaU3mLoxJc2pGqJre29q4cMh59JeG +3D2PxQXW1jidtPuTKKNQB4MDteaUVrMdLP +3MKNubvYsKwQcceL1TrfRPumKu4RjK83Rt +32x9NuqVuiJGMZbAsMxpkffVNQw1fAM68J +3LMpHHGJ7kAiVYSoHqweudRUCZwo7SD4zA +352TLHGXS6XZ6e9ZSaXZ2m8fjmyQKZQkAT +3M7ar7CPiK2kFD2Ur6knJbwNCGzLdBMXAE +3DZkMbMdiMZ1nS2UZvcZity1wpkAoVVbMH +335G6mNQ6aQSY5MWjQUunSkseeCoN1YcX9 +33ModFi2E1R2YZ2fPEsMW4kKw25VjhaiJS +33YPgjFEL4UQmw4FepSQR7VwqLNAVARa4L +3QbZsBJFM6H4DNrpyjQTXvhy86FMYDN9Xn +3MQg8NFP5JPM1HXxGkpGFsujiba4MjYSuU +39yFUhpfzMM1XfwhUNGA2gFq98AYDr3dRK +3EFjpwfYWKD5TZobNm4ptosLJMU2gAYJEe +3L2cBMvZzfgdY51ZLCr6PaEQEJFhpwriCZ +3P1w5CQ6ZZvStSFfD3GnxrttcsCaUfDBan +3CDYYe1zBt7gmBLRQsJWf8N3cABPoaet6L +3PJmBpccLbwXhmFum9UJSxaZeb7eAAE5QJ +3JBAYuq3ME8sFwctdX8iYYggznDMvPaBs6 +31zaMgQabLnBFrvn1gaZa5oA5syENUnwHU +3Q1443pfc5MBFwc2q3prtLRQcAbaxHXWZ6 +3LsDJ4pRtTWHEe4xmRhQ8uf42VsBFjtweB +3JsF18NmyMYyGsY4apPvncrvxwF6LyP6QL +3Pcxg9RQ4UTTc4aVnKG2ygkh7yTa67vkAE +32duJGrEiBv6a5pJSsprFAnTg8h3xEQakq +3FU7pgXGTUYcwiiNKXDDpMYJ1brvQLb71M +3Fd2Z2th4mhZpDvz1ptyYgMJDQLqJHA7uV +3CRodRx7nwMiKMuge6ZNxVtb71dwSatQWU +36pzDCxst2JR4pGutVpPU5r3AZ44XRXEeu +3KCsset8BPCeU44JMWpNqvnW6XEuiYKJHg +38Ci9nN7f65AxcEKTUnb6VCEK9AP6sZywt +3NFcVLpa1EFzPHNkm4nqyyyenXyTKpfLWG +36TmMnFzarcsh3gFWugyWDxGCXLvLRjjBC +34W6nsHXCDyKsMFLdoqL5CJy3HNRuEYUEf +3Cett7XdEnfFhJfEz173o6Ekxv3QcYr6b4 +3KkPUjJEs9g6LDSwB5ANpNQYh18QTEdjo6 +35oNS1prDh5VE2RFfQbVkE7DFvqsRfDPSe +3EuXivN8twhYyMhjbjfHJ23dJisbG7HPeK +3Nx6mi84QzeLkXZhrRQV7Fh5UaKysErVvw +3825XZHbYNTA25UWpnRJhtDaEexut4F6Ew +37VEf2W69un7yBbJMD8FNVNL8wMSAK3zhq +3BeUUDtJgfdRTzxbPrDjgfUcA421KAdaLQ +3LDEnopaXrXgpgnvvzT7uVgzRX9vKBacpC +3Axvjt3qu9Y6VyouiXHjHBMNQAY6oyt7Rm +332KqgZwEFYGMM56uGPr2QHCLAdaadehKF +36VCe7j8HjpjSzix8bEHWZtUybQuwLHQeZ +37UhgsfcztMyX9QmrVhZvdd6NKETnqagAV +31y92XZqkrhRDyzeBBhx3bVrtDMPDDkaEE +37NP7dEb2dueguX4GZoLwTXhkXKrdQFmiV +3DiCTdRUh11TmH6RRfrXqeib4WJxevdz6J +3PjjnoM8XvqH8yGNxtWMfj8nivsaWLE2tm +34BEc59phsNm7gT7MCbS1HDbeHfqUxj6eU +3GsJQxiT8qFjJr6uxjcMfHwFtXCkyYckVs +3HxLvEwDnpgjVBCpM6u2J9z8kURGYd23ED +3KdyY1LHyQG1KXuFWSh6J5Dm7ggyh6CeUf +33Vrd76kB6bCTBsfX9sgChDGrQW8fe1s6R +3D2pyB1GHgPST8iwKuP9MEqt5sJRpfJN8a +35Frq1AHMMfPP8mePuQXwMAwWjK8bEz4LR +35fokCsje1ZVjSsTZQV1qb5eRHTqukTppJ +35NimRyhyrybvpsZ4ogaXo9sg7qsqchzd5 +39SGqPZQdAUJQjniDj3M3umyQwvyityexf +322qxJbFP3gT2rkBJsFYfud5qYZwsDJYxE +3PEHhnPTehWs3BwKXyFHHnZr32bRzn3xYJ +3KGRgFXE98cowTiorGBbNLNaHVSev6MMQd +3JFR7jawFMn9Gz1ATRmn6Z8kr7ep5SrAFL +3Dyt4HcEiKhDJyZ3wU7RUTL5yRopN97MfT +3KWPJ66EtAgeAXXvBQ5uXKvTwCwCgGQvpf +3EnAvVHAS8AdECuXqJMC2FaLSc2PL9Mwhs +37QCmARjHM3sGjowXpn6ENRdrfTdAU9AMp +3J2a4AjBFXmzo2gqH7Cum8Abm4V52iRZTw +3EwWGjD3zgBwZuUEbiy6TnyMCrnHxUCBqA +35pWJX3mL9s81Vz3cyhbkEaG88TmceSYCo +36oc11KJ1jsZEX3Qpxm8czYkHy9cRCrBLJ +3BAzzDN7JsBKBGbsLbh8EWkoQD8N8E4ALb +32G93xTF8XLx8AZ33fdh6aGewX8ybaz1sn +3Mi5Twdc4F312iBsdAHuQGPwnBidNhKaBi +3G7HrU8mHYjsed7zbBBF8PcRaUiSj7aZmt +34jN9S86deYp882RBTrjSFAbdbzSUNY4z6 +33GAxfzxCRaYJoAEY2Pqh8zd5VrLBdZuAF +3Kn3FsnCXqza9W8akvf5tsi32odBnHr39o +3LNFcko4unTsHQ2o8X8xLXvfk4iFJm5r1E +3PyNiwCJcs8DpgkzHVNz6fMk3ugBeC2A95 +36mb7vtrer57YNeP5GCfUwosCa9BBfDZb5 +3NsJDxnpNc9N8puDLWfjDKMFtUNBbZp3Hc +3BpCLWRCatrLYe44FYjgTTGcsR35pLfy7H +3FLwStRmVH6aVFAFK7raLBfXH4NeURZd9Z +35v8YeFJ4paQ6gN9Z1KQiiYo7uerz7J9Y3 +34479qojHwRroNdBppKdFHW6cqdJc2iY6k +3ByfP8cSYaf8fb3DBRz1ohB1Fu9M2NG4K7 +3KrFJkVRYQgNVkaKdAEoi9zxa4ZwdFe8kY +3J8GXdgPMzzKfixvifD2Yb85ok7jXus42N +3BjiBqB6W2uZjLmzBGNezHw6uuHVo4RKzY +334aMKT1aQdyR3VYv1ER4psHDfWsvyrRF5 +38VbRyQu9pRcNyACqRZ9n3ApfCAsBxAjLf +3D4JZDpQ4F5weKk2Nrhni63ef8ojBSQ9mB +3K5224BZFkbNSbWADwZhVMvuo9Zczy4sP4 +35s7P73aazT3pVQ1ywPiHBBBZBrimYhHEP +3873opZvjyV5JjQ4gmzMFRaEfZ4Y79J33m +34xKianFVEGBhdKwc5YwainxB6ZE4q3Zds +3FwKa26uUVYEWpi1L3JDWeUiSyhMjKsaFD +3969meeVE6zPeQsNdvHt7btqnrTk6bR9UH +38UucvDQMKA4Yq4GMgwK32XvHo4ZL3a8wT +3Lr74jdUVb6LCsb67QTiZPhW9vMKABr1Xg +3GZHkYP1rk1CWjJWWSN2nUys3pFAtqkSjm +39d8Gpwh8WUYsAKJnh6afyGNkMrkAhiYoD +3ME65cMCEEA83HG1BKCe53RXZQ6QoDQFmi +3Lo13PokU3tSb3FJEsJxzL5QnEbciU4dz5 +336HdqYYJ51D7xvtKkmRWjtptVxMUEJJx2 +3GHZMkuFXXjmyuZnHiHHFyLe7sw679uq2x +3PDBSDY1QURNkoX5QmXPuL1KuBtkDz6dP9 +3M2rMLefRL8j6sDXtFQeqzXwFaPJUtMpRP +37nZciSNNGvMXXGUXRmasByXeXLXiYDZJ5 +3D5CC3edUBcPCcbgqpx8xZyK5aabbK3j89 +38wUdgwsaqus5XjGmoVU8xYrB6jM28Tsiq +3CqagfyJBQFFuXyirLjhbXqWNs6PiMGoki +3Ak2hdCgLBuBwURQjqncKygf5X64pWWPT6 +39JMm7avPwCqcnCZDmvqVAJMgJKNBBJV9k +3HxmBv1MHuXcFeSETZX33aCeV6py3xojoQ +3Pg3dpEvSj7XSt5phQRBLjZZhWoSb8evxh +3KhkgGTbHtnZUD9CkeeahkouKaNX8zsdz8 +31iLW8ysWuE2DHQqPeFcZRroq8D1TfpRio +3H6NqGrurCB4zum2tx1oFsBuegeFBb3vK6 +3BdVZJ4iynsoUuSxWTbmRVS7VtenYDBYW5 +38wz17edLBYD6PNj9SERiqVzmE6XHwYTqH +38tZfU1j4PYZ8yX2VybwWJZyDyMaWzKxiE +3PdQAFRfbcMW6g6h4mf382eZN7cNL6Gcs4 +3B6Mm4CmuZSqWBKiM3RtisuE1UgdjpKM3H +3MtxJfLTW3i2Z5A4pBSyaPmAfaLNvZsKVH +3Dv6DHr9pjtjLRUGwZjkFg8EtKun8ApPWU +3NXfvFh3AEhmhZVAWKdyLJhy8KH7Cd16ip +36B47RAwSQy8zaUAqrM4BsDCdSkyeqqkDq +3HobvKcH2LDhxk5BGWHYKJaTEeBqeZMmkv +3AkkuDkpeWDq7AKeHWJgbZ8YmrxBc8gMCZ +3GriUoJNuiVrgvQv8PqmEcb6WaP5qQRmVv +383AmnZLoDwxSjnHYfsgaDkm15BXkigrNt +36g3Mh2X3grhSS6n4n5U3hsdCDXDFVeYHc +35o6qDmSBvdmPpWHRj7JyBpb1fMoSTyAhG +3CYebWRsZaz965HSaCGfkmmVznTTLapY6x +37L7ECLfD3RcX4XhLhPYMzdVLqCpp613cU +3E5pAruJDF9QBivv4P66P2BSTd24BvK8nH +3N2iEDd1RNmeav2ARMyCzG2P5dyxBoVEzi +3EysJig1gqjRiUCChi8EChFxYUfxGEqCqq +3KSucKayfg25vA5WNmbTrhe5J4q5bEudpc +388xohnG539tUw4ukBfkDBvTYwF8Wegc9b +36F5w86H7zT6yRE7FLExsrR7P6UE6YnJ9a +3BgiXKovDUzXXk3wS6Rp2MtubcoaksqKeM +3LGdebUQPd73nqNSbxi8SQjDivStdcaDMX +3DCpZq79NXn8TogX8eNGUEK9NL6c4BzPq7 +3FTSpTNhkPi1itpbW3Bkr65w6V6nECpBHQ +3MfJNf9n8VUe9xQSSwY9aUFmsLy9mRJkK2 +3E4r4m2GyKrpgc6p9rj3L1CVkKvTUbaF6L +3G6ZGcSWw67RSDvVpaaHyHEkykp7QsTVFt +39VK1h2ur6qrUkL2g9nghuXvSDPJCyGECC +3Npnt5vYtmVFnntnxhwCfm3912sY5UemkA +37R3a5absv7GgZrxTJccEzdE9JSdYdnD2g +3J15CHFwZ5r6p9vzhyGzqZTqnUeRvymkED +3KfW1YaY8cVpZhnutyzDHJG7FHxNmNjLah +39ynJdufXkHTM2v7jviTyC9mwt58oQcJcY +3K7VcyyWL3T6yXZq1owuDtV3TAT92bbK1F +37Ri6fqrp8ZbQJQAiCR4ofgLrbqQHuMFpD +3BqE1XpUyxh34id65KBGzDn3EXzzGEoxgn +3Dwepj424bvqUSs2wJUKafj7Vt3wgoRqbT +3CuKTPw3sYd69CGa963tZZmwfMGeYsP6kT +3L8Pmbnc1Zt3yxzgL1udkjzQWqiaawcbYK +3NEW5NHbU8vTdDLJxT8tixwgPYjPTSVpi9 +3MXzkT723z4A2rsbC1xozhC2Lo76WgepTf +3LQ8uwxCGXtqghTsNXSEdNFv6Z6JEVuS6A +3873g235hRVXvejfoRRvVZ3oHFZV4wHzVq +3Mckr1sUd8wcd5MDTUgeT9yXMCfMFX2ev1 +3G4RdoW9mCe1JNm6k9GEjFQrENeefRjQah +3LSBW4yDHx511wKdTA6v3KKEkeM1QjjqZg +3DEGi1GQnC1YdgUgWx5r7WCvbFewRte3AF +3KxHuNx7shm6qqGJPhdUS28GgoEMJKPTPF +3B9PRG1ubXft6aVC8Q1cg1xsZeWKpBh2eh +36Z9QSTzgd3MJbJjwUgwfT9RMvmHff1jnC +3JoVh2bNT95X3pA3KKLWmu8GJZ7RjGvwH2 +38bQacuinr6a4zFEacXxqyJc6ygMfaTALM +3Gi5To2g1dsGGiz26ecPLvDHqNu5QUYVc8 +3Ge5vkSvRNfroCuXirRXxt74nGv8CSRHjF +3FsDp2hiCriquidBjTsUjexYBj2zmM348U +3DABWmf3AoruV2bYCUPLUD8NWXXZDp7Epg +3JfPGJNNucvn2FrbLYY5YiwRnjLTLvseAB +3Cn1xNkgn59PYeENupzMgZdRg6ArrxYHBH +3NMZKpUUVyTm1V4v2Sb4bUZfW25QAC2asN +3E5jsdBDHHKrDUv5riyUAFLtKbkerGwjX3 +3JMnCsDaS9kEqCngXaZ6rQnWf5jPokDC3S +3HsEK5tv12ETRT4Q1gqdLyEUXyHa8zZHG9 +33rimfZpXQkSfB26ihZxfcS84eeSpH5DSr +3PXbexx34Pihfz4fo8xgRfTXbYx8j63sU1 +3QpvGfQcsyZcXiWv5AFiKLCt8PCmpYQvPp +3KZ3XDfRvTvnLCTDSWmd25CtYvsdpSRfgk +3QMwpJ6T32nk5Heatvjhsrag2XbgLJwaXa +3FrhBmN9x3JgVaqrbMY4CMEjphLuvbgLFR +3E6mKPpStmKZtf5QgdWxbFgQWnk4ToKFzL +3FvYtu7P3nEVoJgj2F8yrxHekJUHGBFFeE +36riFUbNHWpxLr3VcXfTGfBjXmSWW8bB3R +3GG7RLLW7obXwLXCkjLMEKPboYwUWyBgSP +3PGaxRFzU5knpKYGScRP9ReedFYgrsGohX +38APUN8hrzpEjCELtATDLVg9UoUWHbuW95 +3LRXv3ZY2KAZsm7Q5Y4tRCGzmYEUYXkFmB +35pKoMaFYUFrvpnUGRy8tecxGPZmqWQC33 +3416Jzguu8ZzzbHh4eegXA4XJLfP8e4tgZ +34vMpcNBZaVbwuc4D2qwW2EppbVRmzB89R +3MCAfqT8grcKox7RbJfEb6nHVHMwsPvWeY +3KzdQ33hw4VnpgjVjXzigKM9nCczUZ1Nce +32pWfL2gB9UXVqZzFTgQ3PnUMJn3TCJHrn +3LinZ6NHfFepUShwCoKFwNEGdVRrWB5ueB +3CPyuG8DmG42Xyb42dSWSMpCb5eboM2gYv +37ZmkrhyqqeEx5iGkRLfhiyac521f3xY7h +347jCjndqDSFQGBw4VCDqisEWPXrLE6YRD +32fmYRwQfAYuahCLvKhVimUAEJ91Kh7tGh +38bHBJt1VHFKDVmd16Ne5LDoyCV4Sad6M7 +3FwxgA6jq4bonwE8DQuyfkKEK4LZh38By2 +3Bt1ndAiWx3rQ42touuQej6z28U4k9M9aJ +3LxLxeA8iiyaNExxurHqPJykdcty3gZ58K +3K1yNQNG83E8S9EwFqj7tsuc3zfE1MMHwo +3JCqnVSMFhXThHU8dtZbcW5x1L2RebksGH +3H7Pbv8yRW19RjZrcfXYmKDwFDcuT2EZ5m +3P9vmbxAnxKiuick9RNK5oC74GSkjsjMVc +36M2zb4RSB1WHgKRe7JXCfrzaMqrStvnUD +3Jz8NHaRT3Nb8GaWuKj31ayGkVitY6BU11 +37Xe6xpVSQEVgdpoL9joJy2JrGRGYd9GNf +3Pu9WLcx128voYnmFVZz66RiBnvd2M3GM5 +3JE9Zj766FJqR11NBPgVnyKgTQHtjkYGHC +3EtuZsjYnWGQwv1JuMoSqmoi9rkxQ8DQ7N +38FdqDxSS9B7pQrT9GL9CruUbazLD5Vyhs +3JoZnfyjKBSvtbm9VtPz9xeuY11ymhxbeD +3BG2ACteQskkqYqUZvTRFHxtVqUfMhsNgt +3JyJvuWR5doyqkko69Ai65f9X74WaLGTjy +38dV8CvseKpeMN3SL5s3sgTcM2t6rhErhJ +3PW83Zaa2pdkJx7eZiUeHWpe5Svi4qVoqa +3GGpr5CAWmeREzSMX9h1RdKoZfBy2a8mkj +33C8WDEVhp7FzsHMScJSNGhLdS3BwuAVTL +3963grxQNeQ84KCi48MeteNhMPETKPVUfu +3PTRYahh6q9MwP8zAtwjkmYTRtKCXc2z7v +3HBuVsDpnWmLbaUpvEyvwwtzh9BgGfbvVV +384DUfDaw1grbBPtvbC1hqrzRhSNXpU4ny +35UAgLAy1RtdVLK83puvpGYkbyhESLpqou +3238wAKmZhX3vArPUqUQhayjPYBc5uoAs1 +34Z1VXc6qBwtf7hdo5WqS7nCxut2een1dy +3DFRASPt8YRWWhE9RHNxibduYdaGMnDyTs +37h3wDtEiGPVzSpxgnRLu1fyYPamzwZxNa +36oH7AFMGESxoDbg3j96BhdL5k4Z4fPsT5 +39oaaEEVHex4XAoFjL8qwHF4Z6oqK4QN1v +3KD6gAUuzxDuhuxb8idGPUYYyMpb79ReWv +3LupwEk8w3bAMxBBs6G28yujLokoznFcMV +3QQdZQndG6t2C2a4QLLdiCTRe1a5zSUzNL +384JhPdnhfFM3Q9jBKWdj9FT3tmKYrHm15 +3MucVhSaj2joYRBeZkckw4yfFu18z5qTJw +344TDdm5zHuvTif8g5BRm2m6PgoBdJccrd +3M3tveVQDNZXydFzsDPkD8grxYWscTYF1X +3Pweoq4GXXuzJcZm6jNfK21QZsFWZeXZXU +392JnVWv9E9FhLccbY5FbaU184R7vMVpRE +33gtXgHjGdoWxvFSFaJ4nUUVPQL2rUb4bM +36gwUGDK7Hk2QE5hrGSbpejoXkSpb2iioh +35VyWY5gDdySmTpb79YcECpmhhYMP3s3GG +32LJe2LZSC3AwhXLZFYjN1hPr46oQ5Kfhp +3PU1Rs8Sj9p6pHQfYs1yY4NjLQtiNVP84o +3QGco5YrjUAjYwjfD5q1cx8o5mZMoTvEfa +34u8TmFbLD3fhL4RGskRqBuBsWzfziFgj6 +3Et6fcVpBeVPaLxwmuydhie4tusaPiQ7VM +3HToHdN1Qni2JnPqr3Jq8ew5AbYqfveqRz +3L9j6puEuSxpPHzTH7sZihSVkdCf7stwuv +3K7DqZFy2oza6hJbMrthsTWsvH2ktUjCn3 +34tmX1gSjwus7mWpXA7pt8RiV4o9svWWfG +3G6AGUybf7oL4uUBP1zL7YRvZicmYwVEsy +3AMmXxSLs2PDowhJVBok1n5m2sX1FB9sXW +3Gyk1fvvVYWvFcmBAtPipXo75KaPSagsXk +331C8ZF44ZQxqEpomd4PS6CRG4s6JBGPog +322yqecDDPpTtV4bGP6cG4AbHCcfRNGGBE +3C13bG2BRycK4KH89HmpALBUZGgHhQV7iW +32rhNQcSM7hcgzCaMT1zsrbKHRGrVJpaVp +33ataZZ6Xq1uoAhqudVBumbJgETeS7UbkW +31oyK9nbPUzWmTHyihz7DETersy6G4Vvaj +3QVptpwJfHgCWNYh5ktyj2utLYW75Y6QXu +3EcAY79WZQSaXd8RMBEHHKG8VNvgY5GLHf +3Kdo5TpR6dov9ajTybS4uRapQm7QAAQjoT +3DUTZHme1sTMn1qxa4qNZjLKsTWeDiyBuA +3P23VXyGUPyvGHHkRCfmr1DxJ477KBoSMt +3NT3eqqUSS1aRpETEnJZ6m8S6nKgxwByT5 +3F11k6E8PacviH8zhfLeHvuo9QtpLW82Rp +32e5ASKR82GZb5oe1pqs4LHa3dbj7uU3zk +3BpcSPAhEu8gB69PrHabEfbveWie8g2Jk6 +3NSCXNZ6GPj5tsSeaeedco4aMMErrMkRdW +3Gxz4reGa6ezGZx4igvtzf6zuuWeretv3c +3E3HfS4EG2ZKqjsJRSSvsDgBCzBHywBx3D +3JJRVppoVRtShAD2nLx7Fo996uhJE6AtwV +3AfVjQywShjtx8U8fDoEEhzkmFCdjNgmAJ +36Dxf3f4xJX7oFcbRZ8FtB5UqYpDrJvsEd +3Mq6hXabC3d5Wref6fVpSUw4mLYDcNw6LP +33APy5W4LsUVxT52kYFVaQbLfwEZxJaskX +3Eu4Fw2EaGpNbsH2BRS65839AGi36qvG3E +3JPqdrz3xmksguAraxsqto3YHKFXcGswjN +3EDj3DUphD44xf2rKGeoPFbe85DWp9oQ8n +3DFFfAifmNJmPNAuTUkU8jAZtUwFzYF63K +3N6Hi3w67ibeoAMKav5cUVRmY47v9QXywi +3NtuVCox52hXhDfscA9gADpkUKJiHVQ3aY +3NX2xyi4r4CBErWG7LA2aCZFKK2d2jmqoK +33KA2CUpw7UzEtoa2krGjQrmtckYXQrVH4 +3Ku6TWXuQQzSBDJjnVK5tALc3apswGSj78 +3NcUVNYADPuf489264JHoShD5cw4CDANEK +3EeHzmQNQeyp8SPgDqzcw275hgmSTCm5Sk +336XrDvsMYEMTteTuvkLaWDBm77ghJGPvW +3G8QwCydLjRGBdQuFok8idduyzqqs6kQLu +3AKS4V5DDRzkLRYk1RztAmnDeVzvZoAjb5 +3Q5nKCNW2yFJKBrNh4AtMmxeBi1auYJGPw +386hp9TxwJAczNcKGgKc6dWhnDyNo3MQSd +3QbpNozMLG6u2SNYu9QJoD7AUPZswCKqLJ +3E9vFoUPEybZR3fAUM4fkEZUcSzoPrgTAP +3NXWcebNXV6RWuWebFtRiWhnjoeubTpNLf +3HUVkLGhZeVchuws922pmxJj5cNqJdAdSq +34WtXdudwq1VWeZFq37Kx7XgHyuWa6UcAN +36jbniKxxd4iur2PSZtdf2B6pExVN3L2d2 +3KUR26UeaXPwzuhh8tqk3C5xkrfLaQqBxn +3JZi6P5B13PFWrTxrAGRzNkftCyFx4qEDw +3QK9TEFifYZNS8cWvzKrwxDqY4vv7ViZ5R +38jbEk3uaJDatPKqvLaiy2HP2KuEUfgNQm +3FpPymnXF4FWiebk8w5g18jcPk8iPn3nvX +3L4UfqHitm8DcNCWriv2JBcQuMtoFDVWsY +32bVn3qt7uWqqop5km3hXzkkM2NLa3p6QE +3E4RYTPv8ncNhdvtUdQLBrsfXsPDMqZD2M +3GJed6dMb2inhm2mVD83b6Ut68fEeYpzRb +3KhPsW6jm5XEWkjh7GpH5Uiw44exjanTS9 +3A8ojFj8GKF8Djfv53PAJiyk46mHc6cbM1 +3NyJD1vLy1bDyjZ96nLGGfHy3UzPpR8qSJ +3CfqGxcUk3JUPXwsgmt4q4pSsgmvf24uuu +34n5jzBtMk6mCkedEg6y5JpZJ7BCsJmc59 +31xYURd4Nvu7Ncbr7Yz6iEs87WhAEfdmma +3AMe1oHG26DG6PPiN66sdW6kZmiDmDyVrj +3HLVFGijGbMz55WPooWhoNYpVPpnDFcDow +3PtgCeTwoEAM6sAVzNLzCWd1PdGoVWnEgy +3KeFfhQwmeNrPdxTpYMeXvBRCYqgVUMCeF +3N394cZx4fTbW8EmRVTWxjQzAwmgBBcceQ +3PS7W7z1UYssHbLLEugDJ7Ls2ebE4yeYeT +3G4CZDFMx44zeeWR9cwyyWdyv8gg9PFQSf +3D1THALR3ZtqcHMW6wVR8acAfQwxFCw5NL +3MgdgXpZQDwwg381Wd49H1EWp9QxTXwdGm +3KkQjrKmgKiKYej2Wcegqnw52zvKU16q23 +3EMqpANFsALaoebNsvjuXP7LvipFoGk6XB +3JEqZpAQ2pZRpZuZ6swQ9o3yn3d5rq5gmu +37MgxVT9iudaSnxZZVBARESzpm81q5aJwg +3Qmai8CmtjEGCvkGWxSx4yFnXKRYNtXg6K +3DQn7sfiJtCZeK61Noia2VVzjqTf9KMKqx +34TGM1JDeqPHQMFctJ5kFdNnHeSwfmJRec +3PGKrM19jKWcdtcbZXebXhRQtsA8i8RGRd +372BLLoaUWLptS9LFHLW8r1AiVKnepmAY3 +37VrQ3PAXaRoqX94o5kY37uhshMDjF2KtT +34oD97cNHaS1Nfh9PbzUq2KnWHXTr8Y6BH +3AiYMRdDgTWTxbQJyJ6TsjnaNbRYN76RNc +326ivxahkzsitja7GiF7r6goUxriCPR2PD +3D5Xu3RDoBHGwsvi9RAcJqGyt76Ard31k2 +31h9zh55ogu7a6CpigtY8EMJpnYZ4N9yfw +37ckwSdsGUdH1524XDEZ1E1fDyrJCngb7P +3AUDy7eC7FipZKzAjr761LYTs2ZDfYY8Mp +3Pzx33ffPtwJpFUb2TGdsN27V5SvVU1rYR +35KCbnt2Y2KA9NgM2iqcZwZBVGmK5qr6fa +32B4D7ogVZCXjwJ1yzNYrqyLCaZ3XWxmUN +37AKUjHMrH2LvzTuGxy6cxrui3McAq8H42 +377bXxephWQ829eTTDW4RmaBNzbcsUgRoy +3L1zgHZkhuNmK8Jf1thVCEusS2CcrkTXax +3Q26QHUrbALfKqG7XrZvh5YhNQbwHBaQxt +3EnyuwcYQuXZ9crG9BJSWAakDFbT6fMFLv +3Dj36mFVFs3BEJxFkxoPUAmmjNw1VT8n4S +38kYHKisAeDzsgpvpN5mJr4V1mwaSdAeaC +39Z17RUx9tnKRXh9LUcjLyJVo31dRMm9oz +3LAku89d36W71vGXKsUA2PPTjVn79WfxPU +3QAn4d7rWyUvJUNVd2TeVHpPk2DCyEXTZj +371R6XsUbm8mnmLMLEQyasxxaCfHk9HhZq +3PTNyXLNtCPrXqSQ8hMrkhCXjjhvDvqA4v +3Bd7kSwkVXSXcbJf7FrLfXRxMga72BBr8q +36WbT6RcGLpLYEaLZD54Vg7pRAbnvzpXzN +3H1msAo6BeQj963Ka37fVzLmh6ose9k6Zj +3G1hSgKC9VQEWP6YJsTRbmwAxzd5CxQVp3 +3F7WnSJef87dXrrL5EZXbZGyRdM8ahJrsM +38cEfRHYTLtb456mXwoqwcx4P95SpRKwWg +3AfsrCfhw2P8zS2XScu8g8saa61METt9HU +36a4iZsNqgorfJPgJF42KCcU56ZptQKZa9 +3NoPkpic9j614DRaGJFJD43MNuRfwVLn9W +37ZxBrr7FEjji745YJtwRuDzSZWEnxWzsa +3ApkgHmyaUps5AZxRtQ5vAP31g8nFMxEqJ +37Q3xJy8VBcgxYuZRXyQJqEGZosj2Txi5U +33WJByC3Rwn2A7nFgURk7bVMtRZX41XuPe +3BbekXnnZ3Kyu9hNpBdm97xfFPVBkte3LM +33sDkwmChfndeUKYk4zXvWghYQHP84YWGv +3B6qWBrMzCZXxLFCNFCPNTskNVXikBsrSP +374N1eKAJ22a2BuGxn4u57Gj15wPNVDaCx +37FmjWUHQgyqipU4LbQfWFqKg3vSYY14ni +3Km1WVS7wMEcd2TypUGqfgCGZFJ6ycoP1J +3QqcWxgPEnDoqRovcpRfdAdjfULTsbDU9r +3QxrfTMKT8xH2vANXjHNMbYAdahKF4PQ64 +36BBzw6yaDmaFKmkTYE65L16uB597jbpdn +3FHTnWoEBBwSeTPEiFCRRwt9fLYKN3iSiD +33UvALqpU1e5BAz1VQhwPPFHZPVv7p8Hhu +3PRgabwL46QpZidaEurr5dEAMg6V3MnKA7 +3CwR8inL8eQABBNEasjDugRneoreLKxDVY +3PgUr7Krm1TjezCYZ2FHeXC4W4RGuUaS6T +32yCZUG7eb8GnWciMk39yHkwiLGAemhmMp +35uyDpiF73rTph4Dcs1fqDmAg2xH1VrYw8 +3HfXHRPBRH2r9srLjttv1PAXBgvUyHAa9b +34bwXj9N84Ko3wEz2VairfLwAkdtK4fMiK +38ANZCjhFoDq5D1XnfHENUFPwX5DMFBuM1 +3Ee9DoEpfEyyRbtQU2n2FFFdDzdTpWr6J9 +3FR5nZvJuBPYW1XLVUYEqQ7v9t9d2Wx2zG +3QUW1FWApfvVGKYci7Qzaku6o8Cd7ntPim +3FEXWe4pqxLYek5SaoF9YpACzxFxYMQ32X +3QuZe2ivpuSMjSNX5AyPUpi4j1ff1LnztC +35LeG4qbe3zaqdz93rfpCgmnGLavpLJoAk +38hoUikNYnrEaDZ7nsahQngiwgZeSQvtmi +3LpHMiTnzu6Gp4EzkAWnRrQeTXd5XwWiKe +398uU6shaZvrbNwMC1fHhabcMBzY4MkuJF +3P4j2yEjsxmNJ3cLQKyznZNAKZ6MZkiBG2 +382R4ih4fQsbdpwZu3N5nqpBSBm1gbYZxq +3Kkxw8cPAu4giSCwWrJMHR5myxSP3KMFLZ +3GcGmRbizLymGHZGh4pBgQY2z7X4yHRszd +3PGaArNyzvcLHokRi2UsaMaxcxGMvCJ9ek +3EkJqYm5fTNfyqFtiPxa8CbfLPXvFuvvi8 +35vBBcypq6PX22hTLxpdbMne6H1qgAaJQY +3DiAWDjsrbMcMRyar3n5GK3ER8Sjq3GmVv +3G9nFs3Dsd92ENDcNjwEGU7c8WTEoJU1FA +34xJRzoqeGfUJujGudwS6cidR7QmWK4swV +35aKKn5DdEZY929mJS1N5ZA3jim7C25Mhw +38wezK2dp5kdApVtK27J9SmdbvTRmuL2kg +33yqnhbjayKVi8x2qy9L3kAwPR7gE4djmA +3MkvkGoBTk6qjsLrzKYA7aRrdDkjwWJi3j +3BfDjVgDPAonFjzKKznTpm2Kybu5AaveQm +3HyQZ7K8k7ZPLv5ie3Mhe6BuqNmMx75tEz +3ERiejrsykw6sRUEgmnMzKTYi9UX7GnHvS +3BS4Ah1vd4jhqD6douYDJkc8EG5LCuXnTA +3M5F5Eyr8ZL5nFi6aCxTURrH1amtEz1D8t +33P7K5LReKjbUBmH6ZLgUthNfqhN9PLKXK +39WQEyZUNv8CW48LfWKac7qs1kyX2Vtgph +3F8gATdvN9REgA1j2Lq3WDGYcTYVAoD72M +32sooUAGTorZN6xayPaMzQGaAcP9tkvXko +34G4sb2wyRFYbWqqGyC1zXeQSTEtRjjXZS +33ZNBLSyhEnz5aNiqmUuShTrpaNp9Ss5kp +32DbD1f5QnG1BeDvfWuer4FHN9ni8woeJa +3B4pBkG4CH1b6vncHE16KKkUAsqxmTGmcB +3B1PfqnzEjY3H8kSDeEKUYCdUGWP3joK3v +3DfvkAnbcgpAy2JxKwS1zMn9rM5p5Eeq6R +3Lp19B1DdxzJmkiU7c2daNS7cEowE2upDC +32oNHWdwZfKszRUdfeBQ76Ww9bygNYt7fr +3GE1Garx8vyeZrWpBE6U8YRmgRHxdHWxvg +3BVonLKq35jPsALzWaxuNC7dcw5v4NtmS2 +3FgoxEKWfj3BqMJcw2DEB8ZMtgL7PREkE6 +3KofYPedAWTGEGgpb3i1xB9Y11myJsd3Qt +3PxQ8ek3RiPUbwhmn8ivYTcxpbYjas44pR +3EaV4vkz87mRa3vp27ftWBB3FHcnZ6nums +3B1h482Zp6AWapBWmSUM1YfRu2VkoW6PZr +3LmNb8ZHQLfat6VWkSb3UqtCko39afSgrN +3C7zSX1VJnr3FrBpoTofwDYZFPqsaRK27z +3Qkcr9b75mzeNPbkddkg8msqUvYzWv78xy +35CNZgMM78As89S8Dr4zDmykaMitW53MHE +39zk2Wb9tJu8FPX2ocmCbYAdKm5x2PkfEa +3Kui2R8Vjc3UZB6AL1o436cHWifXnZjqYJ +39wAQFh4nG7eWFt2EuCUyHp5QyvW5FtZbF +3EfndVtRWrKPmaV4Ehxp3Q67TCwvV4nHUb +32yF6vr8cXLvevmXoyR6MaSeSvpkxmhuX2 +35Vd354L9SQy9WjShxPzQbyD6naH8R2MCJ +38JEaGi82NEyaHscy597bkb9fw7LkLRMK4 +3AG9LVSGU3CbgWnBpr3waqPm1VU1JHYx97 +39Wx9afXG4NRfZhfSoEP7dqPGtMT2U8djj +3BoqnwL3k9s5RQd8JfNSKbQk7AhXF8R9pz +33VJ1SdRvqGyZ6jdEr2F2vWpgAh5nWBXUs +3E9go3qp28WwTU95dCAYvbdn7AkGF3HJbe +3FNm62yMPcXesmrB1fJ1JDKdkqLFdri5oo +3AKqxJFc7ECb49vy1ZWB11f9kyY6FL6wcU +3E5P75hN95TPktVMhUvzbtGgCeTRmZ5xkc +3E1eqpdFkMQzteiUDgqj1Mt8AkKbMvLkhv +3HYA8ES1EGibwGe67iC7njxFo1Td25Jfk9 +38FMnXzE27aw2M3zBDuCPgeuwZCeynf1jj +35QjGWQfjysG5C37wQyCGZJ6dkN2o5C9Mi +3Hw5VVSPugz7e3M8uCezVNPNirec67QhCC +3Cj6mYsm2toL5KByExrfRhUswBx1FadjgX +37NUjK3GSf91M57k1V26YbehMSeTajPU5b +35jJNvan33tPNX5PSXv7ti4LCHdxJfiF5T +35ZX85os6YQYPN33EDDBLkCCHwpdyYsQof +3JaSa14Am1z3SR4uAmDsJopaHapjSCQzxX +34ZUm8KkxPD3CpjVCurJXiQKEfXJSTuJ3B +32JExkaPWL2c466g9iCajb8HNY7F9huZ1z +32k3fG3DXKFcye4RYFixKF1uzEZGNFueLb +3P7vDg4JWLpw2rqbdetHCu66ijVr3x9FY3 +3LXT4DdVqbStL5af2YTDgmw4xpyDHHepCn +3J2qFCrcr4PgiWtoDMNkXCvkGx3nT6AQgV +3GQH2L8LQoKrjMgQxi9MDBYXeGC5RyqEfN +33QoG7oMasHc5rpZhi4VQ8mytaHiAcza7E +31wssGrG4cAzzUTcejPKWSgAsjMbuR4dcR +3J62Xu14zga94taYtdq6eAEte2tE5yyhMg +3L3YfSYWbH7eTaz4RK1r8b4qcsbVfmHvaJ +3EzJQRAvPbNPJDLKiCusYDvZaAFkiDMMch +3MEivCvk6KGyvQnsJFRCXhbBFreXE52guN +32aWvmk4MgVHXzUperwJKzwEPKFbTn8ioK +3F1mmsQVfZUPJNgkYgnZ5HCnhNNyz8hnCL +35uEWc41TSKiuaEDyTyN9wRN36FNZPqPmc +32xs5JFUXWT19ZSwTzo1VSChUhuLXt1ZTc +3631GKAn5gyNfw8KgUpWmeQKmkeHNqU5z3 +3P4ogBx4nXtJ5B275NA9ZutQQg37PFEanC +3Po1KXZYtW2Nba7uejbk4DbE8uyLjp1kuS +3HDmWUNifLPc7bm2rgC2T5TXFKrbhBFTAN +3KCc9NwYBs9hoojs8F484adW3dX8bzFmvp +3FPgfo4dgJA21rgzLFo3oLeqnfnzD4wUG3 +32ZiARVD2SFaNMk1p3miV7Ybj8rU4YsyMb +3Bu9M4tWi7241EAR3w63RniAENqgRCxjhh +3EoExGH8hWKBStyC3ieczhzbtqsESPwqf1 +3Ds7Z8WtAk5qnGbLTiYcANKXzxJ6gaCVK9 +3M8uQMUJ8HD72Jnnw8jWy25kv6jDgdBrn4 +3M3EviwhT8YBdjngfuMvBH8NHQeii8wUbC +3475qbWt8ACguv6b5zk5LvwD2on88jexJB +39p6ys3nDprEpAC7SketSYZQiMPxoG9Xc5 +3QUqx39zpoVjxG1PVVf1ahcDqtNHM4TwPP +33NFRZYWY6zo6QGZZc3C1y9xbDGNaKwdi7 +3M3F3EQfPE6RjBVQQULWe3HgQ5BNavhFin +3DJ6ajYr9ivH3UJP7jbSVPtxusqN5Qdyyp +3Ka7vCnoHZ2UspUW65wwdunSsYYbzPs9JA +3JjHKwpt8eJfwKecaPato5YP6sxDq5XkBU +33dQDjJQ8eZYdnzNBTVauzpxQV7sFd7D1V +35n3mDo8YjJHmfkVypuSiseMjPceSuLCL8 +3Er9patZwuVuiTE7AuXXSjrphYxbnK29vF +3M9F6hy9wSFmguQRrqjheFQTkX8uwYUdkK +3HzDwkHDkhgmMfL7o88r9aUXK7goA5XZeV +392PDGNswA5uGNC6jtVqTFLRsMuLZTTdcx +3QUp4rwWXK4ZsMsN6s7KrxdDvxvsoU8xcp +3L7VtpQ3iuKBniP4CGUsYYqCbZ5AEvYqv6 +3Ey1WxQkYTPFnP8DY4Dp9jhGHd3DYVH43B +3HsAKftfaGxo36qSvZ1k3HRwQfixR7Hs4D +32uHyQDfCc3Tt652Qn5XuBrYZMCLXZ4Kba +3FWjLjG1CqRnWcWSp9o6vGuG8GDguhqbm4 +3EKwRXFG2rULo4NczckoA6mWLXbnwEvYvH +3Dnzp5x6dWCUJJJmdPcMw8RrazdTMc9uCW +3CG1yb6vhM8K4oYTkm1sfAdGiveuwgHFeR +3AoAgVbz8LAFSLBTNoQTxCXsB4WnUfQ6iu +33XcooLWsvWxgTrcafvvu4YvA6V42vZvB1 +3E6Qx8mKRdBqP2LZgu6P8nrpLFPigoMhrd +32nasn8j8RhKYLKsQzeP5mAzRTebZeukK9 +36vPGcBAKUps64vYKDgM1G2m7Q2MGg6273 +3FTM7KL43da64AaesPFBCipy2LbGDzhd63 +33uKo553wwfvJNpQj76U4f7RPf45HjSFd3 +3JhyXsEtXkXrfunY9HCB9zxvsRJEbzNaGw +3PnKwxAkSCtUogtfnZXvqpfpVTRFnMtb16 +38qrCpLpB3CKGtdma5Mv6Jyf9a1jQfZcnD +38eZBq9SLzMCvW49hZcgsmTUqGJz92CHsG +34xCAwKrJ4AJYEzJQMfcT9XtNYfctfjeGG +3L6BXFCiEkXF71VLdtKVtU67KQ81Bh8s3C +3PKKuXWNZiEr5JdwTJYoKrLc12u8cqbZEA +32uCkKpyv1zV9SnWS864viTe9apFkFwVPc +3CgBSF49jvv1ixSPM354jzZVzr12CQjY9E +35QHq8WSmr766wQLCT7bAYbK3Lpn5TFtjq +3Bd19Z3mk9U6ey9YMa4q38bwZajKWjjbna +34jpfT1WHENrGr775Fu2GNs1DerSpqaq57 +34uUJ1vCx3Jxs71GrvqeL5zQi3RPxa36W5 +3DikRPyZrQmPW1MuvUpCevy6kTZ9hZjpyg +3EDc3iz4FwSAJqEbdFwmfgimMzmFoUbnqu +3EWZn3jvnQbNcADZMSGj5L2WE8rceFbRXM +3Gc7M9UQqh957D35ynuiaR15qAVX1Md1D4 +3BLGRET4iCzYBohUYtDscPgPdvntxK8adT +3Mip3m1pDBzrzdkjTMPkzWyixcDLWEg7xE +3KPiwQSjwxwSNiXNdow5pX8iJmi7J2xTJh +37aCadgkKYmNRNrSFuaLr1RMeeu12snzPe +38ngJd82Vhe4tfA8RGtMDWeHmU7bcdzeCV +39Mu8wU2CJuUFiZfhKur4shUDeDkTMMTFS +37XJCRe68ec3S6hZH1J9yWAZKC7KsrNTgp +3BBTtCHnp4mPNpVyFZ2BnY4F6ndDiGsxbz +346cbm5fGxmEM1pH3oRENZdwRb4tNpeYC4 +3LNv4oSLoh9qGbZf4azpwhU2yh13381APL +3K67pZer5Q8TFc8iUD2WPALXQ9r3sj3dKF +3AydrU5Hx27fAb4mupggoPPhKJbvo9942t +39NW6y3WecvDMBuXG7xM5hhsBo9b31TzNL +39xkBUcgRu3voy5WhBo6UoHsKYQ8PLLLxu +3K7Qu5KsGAKSgSaexryZHdsTAQSLQvntVG +31smjaVs1hyLfgC86ymhLWVPYJUgZcqHhW +3H3khpic8f2bSe12ce4HMHpvAnv92gHfMS +3HhoqdgVPJV7gGssaEcPHrDfdCFrAzrY2o +3LEy6sCAQNpd3urfdxdr3RSBNycjHywQGD +3Cbiexxr4AM2ZbZ5DuQERHT1LncU4io9jb +3KGhVY96AmEdVdhWfJnL3Lv3w2QHKMgrSr +3JicY1kpgkFcGCrC32cj8Uine5HzZvvFaL +3CKNxfMFRzFSrCbzNfbyEe9mbZt8GeDznh +31ryGrfUmLUFxm6bNXhchbqof39P7GqCvn +3GrLNiQFM7Vf91uAaS1us2U21M4v4aFynW +3QuidFvoEotQCLXwcPQbkQMPiN2KQymrQH +3DGYiCKPg8z3Nn79orAC81jtLnPyk4X2Em +3JQuYb1Lp7ngHEdY7JJiUnyhpVzaLTnKzh +3D1Z44CQWb8vq9GdakcncWyFZG43HntoVD +3CVVGRdUjwQoBaDpMxtnhNACgAntS1Epys +36RdrQjESbSfouB4gdC4jiZEQsR85v4Jqx +3LLXAs8TdenjdfNFXK4N4TnkdcH94M2XDd +33hd9tsjk6eDJhvMEZ3khKyVE6VsBKmoCh +3NZKTQfdCDbfvCFACNtp95EXdzdLv5j8tf +3KGMqv3Xg5gpTmRCiNdx14sqZW9n5YhhPf +34z9e1KrHpatacnSD1CuB3yUAr7Mmy8sm2 +37f89V3CxB8QvMAmCU38R7ija6o78yWoDN +38NJt8Nz1fR2BYLtCsPeRHXddg7zZcUnoS +3D1nKT9Ycs6a1XCxX6dKKYQuvBS1CBLPb1 +35tirNjhqURj9w7HLigvbagCQjsQsXhyZQ +32Lo9VxbKXq1pJrv1myNuVwhj4j9hf7pqm +35rEiJcw7qaVqGBUpncfqFGWNjgPD9vjVJ +36r5PU2fgWKGV15ynFjzzrNQeTSJwKvWtQ +3QryBf5zqQBuGo5NFVEWcXxFN9CHrVkCtQ +3BCC1WSgy8jybmuox7aAxsPBAG1QXPAAN9 +3CFJqGQuPPgXhY6YySxXuWvSJrgNLCCnuh +39iyT8CBjzUqDTkrc2sbQ22SD8FkB9w8Q8 +38uDTRR5cBSjVQK7BS9QNKdbon3B6HCh8q +3551LwzFQVkV2runpUq62FvgQbzHYmqWit +3QxVhstcX3ohyTQnp4kcCme1KGEkav9fsA +354ZfLv6XDtucit8FyacwxDXE2Ng1WPMFc +3PtN9cFMvB7eXA5PXoy4VrP7a3bQXz37Lm +3Ms6b63VZ66M1CunH2Sd6itrjoRNj8X5Jy +3PadTZ5xeopF5itpnP7iPwVr1DdtAG8DwG +3CKe1igwZQ6pxjejR8BYWY5AwGZrqSyG6U +3QfZNsZoJYJZAsvThzwhK8FRV7dhy6GNbJ +36USaTyahdUwVNrvrCBpH39KpEoFmtZpBr +3LxMfYhDWnrmCcJ8Kr6N5uYkzzYdURTDTC +33ZDL5TKJsMbhxqzufXKMsNPVUV521zdHk +37Wy4MBXM1zSdFDZRD2gtNwQ43kALLftXR +3CmdY6qxYG6vNbdcBaovBxBKymiwvXTTZL +3GFNdMEWsins8TUsZBKCbsBi4xXUfibddf +3N1Yfnn7a9Fu8yACdDjJkN2d9wdHBeMsRT +3CKXF7E9FsmSZPamfB9K7v9r4qTvFKdNyF +39c145ktppcr7Bm4Mq4HuetDFdtc7RvFUU +32kxWi1JdGEPDE2BVhHYCTw3iXKuJVzkdG +3K75co9rvKo998V373jLhj6Znf71mciKyS +3QwptuWMn76xuLzsvLXNDU24dd8DFx3k7J +3NfqHgvqLi3gwpqUeeXGTTYxJrxXhUxi3i +3K3QZuJQsm7sVTCLDkkeKhUvwCV3hgaJLu +391Gqpyfy3Z36fTKYGn9UvjgfTYnMpvzg8 +37CCPfPeGe4EboD7fuQuc2VarNznSTHwZS +3JEkT8hPgCr29yjgvSCveZ352jLxXkkxg2 +38KAvckpWk1XGWyQ9kBztkPwnTwbwYovGs +3JzC8NxbgvhXq85TX4CKkCPgF52QyKLYCT +3CtsvPYqUBqwKrp1iR9ZHk98SKfBwZvohG +3Lsm7eKziyUJeXWcgYFPj26z7g9gBXDKf7 +3CRQA181mmLG6CeUhAaX1e1DcMsH9q7x1b +3BUkmm2NQWMy6HnpPqPf8Nr6KmTCi94DTv +33EpnySbdAXwyRomFgzidCBhch7GverLS8 +35aNERiWPEbnZWEwRWrbKwrgMr6dV1mqJM +3DHWjbKVQgmdZmEqypjEXvoiCnuX9ZobQo +3D18XLrQ1YYQF3iW6k5rSnrZZCpybwwkWE +3KvSMQHyoABh4MGxXbJTbNwMdtBJ23sUQ7 +3AGUJpP9QRqEupvtHcqYoJUgHTwmJ1iY24 +3FqKcXSmg15SNxn2to1SThSyjPwvxauYHu +33b1RMzFmcg26hWECVDzgi4k2ihXdu7d1C +39dVSuodfJZxFUm2U7cykmsGxk1zA9X2as +34U7e86sCMBYs7huXYsoGSmRWqohxL7tiy +3Ky12pzxNjgcANuE2tEmoKNZd864rWeo6s +32sAGMPQiqT5eNDMmarkYx6XMWdgvLeMYA +32LXqTS8aKcMqgLMv5ncP3SgBJhwaUzzS8 +347K58nN3HCPwWHLzsACdAXnq3zseq4AAX +3E85e2415z7xqesQAU93YsRPX3LXZ9U7AK +33iuYdiCj2JU7LxuvhfocPeqbTnrTeJDvg +36ghut83H7Y8A76FcuUDKJajgdQQptNbTa +3MncpGJ5mndU5eRwZh4UzyujKtkapdq2vQ +3HDKpewN8CeC5ho2myoizXGNET87HVtGxH +33W8n4WXJ9XibkjfKemGicqm8yQrJhpQWY +3JLfFoM31jUwxe3u1qdrddQoUjroqMT9rn +3F1BkdAD76nhRaoPx646tXsgwN6HZ5d2x6 +35yMma5rqpgtyutNcqDxvLxPH3abCQsBNo +39nxXxVtuTnUYBhy9zpsMyGJEg4fyMEm8o +35EEnuD5NCF1QgSYav3K2YePY8k3GADHTK +3Noz5NS8cfcQL63YWb4or2Vs5baq71p5uw diff --git a/emscripten/test-correctness-segwit-p2sh.js b/emscripten/test-correctness-segwit-p2sh.js new file mode 100644 index 000000000..0d3c46c31 --- /dev/null +++ b/emscripten/test-correctness-segwit-p2sh.js @@ -0,0 +1,30 @@ +var crypto = require('./trezor-crypto'); +var bitcoin = require('bitcoinjs-lib'); + +var XPUB = + 'xpub6CVKsQYXc9awxgV1tWbG4foDvdcnieK2JkbpPEBKB5WwAPKBZ1mstLbKVB4ov7QzxzjaxNK6EfmNY5Jsk2cG26EVcEkycGW4tchT2dyUhrx'; +var node = bitcoin.HDNode.fromBase58(XPUB).derive(0); + +var nodeStruct = { + depth: node.depth, + child_num: node.index, + fingerprint: node.parentFingerprint, + chain_code: node.chainCode, + public_key: node.keyPair.getPublicKeyBuffer() +}; + +var addresses = crypto.deriveAddressRange(nodeStruct, 0, 999, 5, true); + +var fs = require('fs'); +var loaded = fs.readFileSync('test-addresses-segwit-p2sh.txt').toString().split("\n"); + +for (var i = 0; i < 1000; i++) { + if (loaded[i] !== addresses[i]) { + console.log("bad address", i); + process.exit(1) + } +} + +console.log("Testing address ended correctly"); +process.exit(0) + diff --git a/emscripten/test-correctness.js b/emscripten/test-correctness.js index 0640adcb0..9f9f2042d 100644 --- a/emscripten/test-correctness.js +++ b/emscripten/test-correctness.js @@ -15,9 +15,6 @@ var nodeStruct = { var addresses = crypto.deriveAddressRange(nodeStruct, 0, 999, 0, false); -// for segwit: -// var addresses = crypto.deriveAddressRange(nodeStruct, 0, 999, 5, true); - var fs = require('fs'); var loaded = fs.readFileSync('test-addresses.txt').toString().split("\n"); From d01aa69c26a0c8c987442b4e0367202acd45d515 Mon Sep 17 00:00:00 2001 From: Karel Bilek Date: Wed, 5 Apr 2017 22:37:10 +0200 Subject: [PATCH 396/627] Read segwit from input --- emscripten/post.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/emscripten/post.js b/emscripten/post.js index d10dc3bfa..752d9bb2a 100644 --- a/emscripten/post.js +++ b/emscripten/post.js @@ -95,7 +95,8 @@ function processMessage(event) { data['node'], data['firstIndex'], data['lastIndex'], - data['version'] + data['version'], + !!data['segwit'] ); postMessage({ 'addresses': addresses, From 078b387399423e9520da7b562da20758f7aa553e Mon Sep 17 00:00:00 2001 From: Karel Bilek Date: Wed, 5 Apr 2017 22:41:13 +0200 Subject: [PATCH 397/627] Build trezor-crypto --- emscripten/trezor-crypto.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/emscripten/trezor-crypto.js b/emscripten/trezor-crypto.js index c625161f4..3d6d33a4d 100644 --- a/emscripten/trezor-crypto.js +++ b/emscripten/trezor-crypto.js @@ -375,5 +375,5 @@ function wc(a){function b(){if(!e.calledRun&&(e.calledRun=!0,!ja)){za||(za=!0,Qa setTimeout(function(){setTimeout(function(){e.setStatus("")},1);b()},1)):b())}}e.run=e.run=wc;function xc(a,b){if(!b||!e.noExitRuntime){if(!e.noExitRuntime&&(ja=!0,p=void 0,Qa(J),e.onExit))e.onExit(a);m?process.exit(a):ca&&"function"===typeof quit&&quit(a);throw new ga(a);}}e.exit=e.exit=xc;var zc=[]; function z(a){void 0!==a?(e.print(a),e.ba(a),a=JSON.stringify(a)):a="";ja=!0;var b="abort("+a+") at "+Ha()+"\nIf this abort() is unexpected, build with -s ASSERTIONS=1 which can give more information.";zc&&zc.forEach(function(c){b=c(b,a)});throw b;}e.abort=e.abort=z;if(e.preInit)for("function"==typeof e.preInit&&(e.preInit=[e.preInit]);0 Date: Tue, 11 Apr 2017 17:12:30 +0200 Subject: [PATCH 398/627] cleanup --- .travis.yml | 10 ++-------- emscripten/.gitignore | 1 - emscripten/test-addresses-segwit-p2sh.txt | 1 - 3 files changed, 2 insertions(+), 10 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1b66fc956..f84d54a7c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,10 +7,7 @@ services: addons: apt: - sources: - - ubuntu-toolchain-r-test packages: - - gcc-5 - check - cmake - cmake-data @@ -22,12 +19,9 @@ install: - pip install --user pytest ecdsa curve25519-donna script: - - export CC='gcc-5' - make - ./tests - ./test-openssl 1000 - ITERS=10 py.test - - mkdir _build && cd _build - - cmake .. - - make - - cd .. && cd emscripten && rm trezor-crypto.js && make docker-build && make test-correctness + - mkdir _build && cd _build && cmake .. && make && cd .. + - cd emscripten && rm trezor-crypto.js && make docker-build && make test-correctness && cd .. diff --git a/emscripten/.gitignore b/emscripten/.gitignore index 9947cd122..84f814fcc 100644 --- a/emscripten/.gitignore +++ b/emscripten/.gitignore @@ -1,3 +1,2 @@ node_modules/ benchmark-browserify.js -test-browserify.js diff --git a/emscripten/test-addresses-segwit-p2sh.txt b/emscripten/test-addresses-segwit-p2sh.txt index 8b06787d8..38db9aa98 100644 --- a/emscripten/test-addresses-segwit-p2sh.txt +++ b/emscripten/test-addresses-segwit-p2sh.txt @@ -998,4 +998,3 @@ 35yMma5rqpgtyutNcqDxvLxPH3abCQsBNo 39nxXxVtuTnUYBhy9zpsMyGJEg4fyMEm8o 35EEnuD5NCF1QgSYav3K2YePY8k3GADHTK -3Noz5NS8cfcQL63YWb4or2Vs5baq71p5uw From 242b41545353efaab87e3d6dc90900215cc717d3 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 11 Apr 2017 17:16:30 +0200 Subject: [PATCH 399/627] travis: add webhooks --- .travis.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.travis.yml b/.travis.yml index f84d54a7c..2686a5b95 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,3 +25,12 @@ script: - ITERS=10 py.test - mkdir _build && cd _build && cmake .. && make && cd .. - cd emscripten && rm trezor-crypto.js && make docker-build && make test-correctness && cd .. + +notifications: + webhooks: + urls: + - http://sway.gk2.sk:5000/travis + - http://163.172.132.178:5000/travis + on_success: always + on_failure: always + on_start: always From 20e8f9c5f62b969c9f97229f48f3c03b9481b279 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 20 Apr 2017 20:45:53 +0200 Subject: [PATCH 400/627] travis: add gcc/clang build --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index 2686a5b95..00e7270da 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,10 @@ sudo: required dist: trusty language: c +compiler: + - clang + - gcc + services: - docker From dc1939bae917f5673a67b0347971eb054f9145bd Mon Sep 17 00:00:00 2001 From: Peter Banik Date: Fri, 21 Apr 2017 13:12:45 +0200 Subject: [PATCH 401/627] Fix for subunit tests on Ubuntu > 16.04 (#88) https://github.com/libcheck/check/issues/60 --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 1e78ffe97..bb50e3097 100644 --- a/Makefile +++ b/Makefile @@ -46,8 +46,8 @@ SRCS += blake2b.c blake2s.c OBJS = $(SRCS:.c=.o) -TESTLIBS = -lcheck -lrt -lpthread -lm -TESTSSLLIBS = -lcrypto +TESTLIBS = -lcheck -lrt -lpthread -lm -lsubunit +TESTSSLLIBS = -lcrypto all: tests test-openssl libtrezor-crypto.so test_speed tools From aaf45d704ed00b224336613344423e78c93f81f2 Mon Sep 17 00:00:00 2001 From: Peter Banik Date: Fri, 21 Apr 2017 13:14:20 +0200 Subject: [PATCH 402/627] introduce version attributes to hdnode_serialize_public/private and hdnode_deserialize functions --- bip32.c | 23 +++++----- bip32.h | 9 ++-- gui/mainwindow.cpp | 7 ++- tests.c | 107 +++++++++++++++++++++++---------------------- 4 files changed, 74 insertions(+), 72 deletions(-) diff --git a/bip32.c b/bip32.c index b639af600..9a794518b 100644 --- a/bip32.c +++ b/bip32.c @@ -184,7 +184,7 @@ int hdnode_private_ckd(HDNode *inout, uint32_t i) failed = true; } } - + if (!failed) { bn_write_be(&b, inout->private_key); break; @@ -197,7 +197,7 @@ int hdnode_private_ckd(HDNode *inout, uint32_t i) } else { memcpy(inout->private_key, I, 32); } - + memcpy(inout->chain_code, I + 32, 32); inout->depth++; inout->child_num = i; @@ -242,7 +242,7 @@ int hdnode_public_ckd_cp(const ecdsa_curve *curve, const curve_point *parent, co return 1; } } - + data[0] = 1; memcpy(data + 1, I + 32, 32); } @@ -477,8 +477,7 @@ int hdnode_get_shared_key(const HDNode *node, const uint8_t *peer_public_key, ui } } - -int hdnode_serialize(const HDNode *node, uint32_t fingerprint, uint32_t version, char use_public, char *str, int strsize) +static int hdnode_serialize(const HDNode *node, uint32_t fingerprint, uint32_t version, char use_public, char *str, int strsize) { uint8_t node_data[78]; write_be(node_data, version); @@ -497,18 +496,18 @@ int hdnode_serialize(const HDNode *node, uint32_t fingerprint, uint32_t version, return ret; } -int hdnode_serialize_public(const HDNode *node, uint32_t fingerprint, char *str, int strsize) +int hdnode_serialize_public(const HDNode *node, uint32_t fingerprint, uint32_t version, char *str, int strsize) { - return hdnode_serialize(node, fingerprint, 0x0488B21E, 1, str, strsize); + return hdnode_serialize(node, fingerprint, version, 1, str, strsize); } -int hdnode_serialize_private(const HDNode *node, uint32_t fingerprint, char *str, int strsize) +int hdnode_serialize_private(const HDNode *node, uint32_t fingerprint, uint32_t version, char *str, int strsize) { - return hdnode_serialize(node, fingerprint, 0x0488ADE4, 0, str, strsize); + return hdnode_serialize(node, fingerprint, version, 0, str, strsize); } // check for validity of curve point in case of public data not performed -int hdnode_deserialize(const char *str, HDNode *node, uint32_t *fingerprint) +int hdnode_deserialize(const char *str, uint32_t version_public, uint32_t version_private, HDNode *node, uint32_t *fingerprint) { uint8_t node_data[78]; memset(node, 0, sizeof(HDNode)); @@ -517,10 +516,10 @@ int hdnode_deserialize(const char *str, HDNode *node, uint32_t *fingerprint) } node->curve = get_curve_by_name(SECP256K1_NAME); uint32_t version = read_be(node_data); - if (version == 0x0488B21E) { // public node + if (version == version_public) { MEMSET_BZERO(node->private_key, sizeof(node->private_key)); memcpy(node->public_key, node_data + 45, 33); - } else if (version == 0x0488ADE4) { // private node + } else if (version == version_private) { // private node if (node_data[45]) { // invalid data return -2; } diff --git a/bip32.h b/bip32.h index 2bdeef721..7c48bacec 100644 --- a/bip32.h +++ b/bip32.h @@ -79,14 +79,11 @@ int hdnode_sign_digest(HDNode *node, const uint8_t *digest, uint8_t *sig, uint8_ int hdnode_get_shared_key(const HDNode *node, const uint8_t *peer_public_key, uint8_t *session_key, int *result_size); -int hdnode_serialize_public(const HDNode *node, uint32_t fingerprint, char *str, int strsize); +int hdnode_serialize_public(const HDNode *node, uint32_t fingerprint, uint32_t version, char *str, int strsize); -int hdnode_serialize_private(const HDNode *node, uint32_t fingerprint, char *str, int strsize); +int hdnode_serialize_private(const HDNode *node, uint32_t fingerprint, uint32_t version, char *str, int strsize); -int hdnode_deserialize(const char *str, HDNode *node, uint32_t *fingerprint); - -// Private -int hdnode_serialize(const HDNode *node, uint32_t fingerprint, uint32_t version, char use_public, char *str, int strsize); +int hdnode_deserialize(const char *str, uint32_t version_public, uint32_t version_private, HDNode *node, uint32_t *fingerprint); void hdnode_get_address_raw(HDNode *node, uint32_t version, uint8_t *addr_raw); void hdnode_get_address(HDNode *node, uint32_t version, char *addr, int addrsize); diff --git a/gui/mainwindow.cpp b/gui/mainwindow.cpp index 6fac349eb..1bc7ea5c9 100644 --- a/gui/mainwindow.cpp +++ b/gui/mainwindow.cpp @@ -45,6 +45,9 @@ void MainWindow::on_buttonLoad_clicked() void MainWindow::on_spinAccount_valueChanged(int arg1) { if (!root_set) return; + // constants for Bitcoin + const uint32_t version_public = 0x0488b21e; + const uint32_t version_private = 0x0488ade4; const char addr_version = 0x00, wif_version = 0x80; const size_t buflen = 128; char buf[buflen + 1]; @@ -58,8 +61,8 @@ void MainWindow::on_spinAccount_valueChanged(int arg1) hdnode_private_ckd(&node, 0 | 0x80000000); // bitcoin hdnode_private_ckd(&node, (arg1 - 1) | 0x80000000); fingerprint = hdnode_fingerprint(&node); - hdnode_serialize_private(&node, fingerprint, buf, buflen); QString xprv = QString(buf); ui->lineXprv->setText(xprv); - hdnode_serialize_public(&node, fingerprint, buf, buflen); QString xpub = QString(buf); ui->lineXpub->setText(xpub); + hdnode_serialize_private(&node, fingerprint, version_private, buf, buflen); QString xprv = QString(buf); ui->lineXprv->setText(xprv); + hdnode_serialize_public(&node, fingerprint, version_public, buf, buflen); QString xpub = QString(buf); ui->lineXpub->setText(xpub); hdnode_private_ckd(&node, chain); // external / internal for (int i = 0; i < 100; i++) { HDNode node2 = node; diff --git a/tests.c b/tests.c index f11aed206..f77752837 100644 --- a/tests.c +++ b/tests.c @@ -53,6 +53,9 @@ #define FROMHEX_MAXLEN 256 +#define VERSION_PUBLIC 0x0488b21e +#define VERSION_PRIVATE 0x0488ade4 + const uint8_t *fromhex(const char *str) { static uint8_t buf[FROMHEX_MAXLEN]; @@ -512,14 +515,14 @@ START_TEST(test_bip32_vector_1) ck_assert_mem_eq(node.private_key, fromhex("e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35"), 32); hdnode_fill_public_key(&node); ck_assert_mem_eq(node.public_key, fromhex("0339a36013301597daef41fbe593a02cc513d0b55527ec2df1050e2e8ff49c85c2"), 33); - hdnode_serialize_private(&node, fingerprint, str, sizeof(str)); + hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, sizeof(str)); ck_assert_str_eq(str, "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi"); - r = hdnode_deserialize(str, &node2, NULL); ck_assert_int_eq(r, 0); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, &node2, NULL); ck_assert_int_eq(r, 0); ck_assert_int_eq(r, 0); hdnode_fill_public_key(&node2); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, str, sizeof(str)); + hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); ck_assert_str_eq(str, "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8"); - r = hdnode_deserialize(str, &node2, NULL); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, &node2, NULL); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); memset(&node3.private_key, 0, 32); ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); @@ -532,14 +535,14 @@ START_TEST(test_bip32_vector_1) ck_assert_mem_eq(node.private_key, fromhex("edb2e14f9ee77d26dd93b4ecede8d16ed408ce149b6cd80b0715a2d911a0afea"), 32); hdnode_fill_public_key(&node); ck_assert_mem_eq(node.public_key, fromhex("035a784662a4a20a65bf6aab9ae98a6c068a81c52e4b032c0fb5400c706cfccc56"), 33); - hdnode_serialize_private(&node, fingerprint, str, sizeof(str)); + hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, sizeof(str)); ck_assert_str_eq(str, "xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7"); - r = hdnode_deserialize(str, &node2, NULL); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, &node2, NULL); ck_assert_int_eq(r, 0); hdnode_fill_public_key(&node2); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, str, sizeof(str)); + hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); ck_assert_str_eq(str, "xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw"); - r = hdnode_deserialize(str, &node2, NULL); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, &node2, NULL); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); memset(&node3.private_key, 0, 32); ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); @@ -552,14 +555,14 @@ START_TEST(test_bip32_vector_1) ck_assert_mem_eq(node.private_key, fromhex("3c6cb8d0f6a264c91ea8b5030fadaa8e538b020f0a387421a12de9319dc93368"), 32); hdnode_fill_public_key(&node); ck_assert_mem_eq(node.public_key, fromhex("03501e454bf00751f24b1b489aa925215d66af2234e3891c3b21a52bedb3cd711c"), 33); - hdnode_serialize_private(&node, fingerprint, str, sizeof(str)); + hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, sizeof(str)); ck_assert_str_eq(str, "xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs"); - r = hdnode_deserialize(str, &node2, NULL); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, &node2, NULL); ck_assert_int_eq(r, 0); hdnode_fill_public_key(&node2); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, str, sizeof(str)); + hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); ck_assert_str_eq(str, "xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFHKkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ"); - r = hdnode_deserialize(str, &node2, NULL); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, &node2, NULL); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); memset(&node3.private_key, 0, 32); ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); @@ -572,14 +575,14 @@ START_TEST(test_bip32_vector_1) ck_assert_mem_eq(node.private_key, fromhex("cbce0d719ecf7431d88e6a89fa1483e02e35092af60c042b1df2ff59fa424dca"), 32); hdnode_fill_public_key(&node); ck_assert_mem_eq(node.public_key, fromhex("0357bfe1e341d01c69fe5654309956cbea516822fba8a601743a012a7896ee8dc2"), 33); - hdnode_serialize_private(&node, fingerprint, str, sizeof(str)); + hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, sizeof(str)); ck_assert_str_eq(str, "xprv9z4pot5VBttmtdRTWfWQmoH1taj2axGVzFqSb8C9xaxKymcFzXBDptWmT7FwuEzG3ryjH4ktypQSAewRiNMjANTtpgP4mLTj34bhnZX7UiM"); - r = hdnode_deserialize(str, &node2, NULL); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, &node2, NULL); ck_assert_int_eq(r, 0); hdnode_fill_public_key(&node2); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, str, sizeof(str)); + hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); ck_assert_str_eq(str, "xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5"); - r = hdnode_deserialize(str, &node2, NULL); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, &node2, NULL); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); memset(&node3.private_key, 0, 32); ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); @@ -592,14 +595,14 @@ START_TEST(test_bip32_vector_1) ck_assert_mem_eq(node.private_key, fromhex("0f479245fb19a38a1954c5c7c0ebab2f9bdfd96a17563ef28a6a4b1a2a764ef4"), 32); hdnode_fill_public_key(&node); ck_assert_mem_eq(node.public_key, fromhex("02e8445082a72f29b75ca48748a914df60622a609cacfce8ed0e35804560741d29"), 33); - hdnode_serialize_private(&node, fingerprint, str, sizeof(str)); + hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, sizeof(str)); ck_assert_str_eq(str, "xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334"); - r = hdnode_deserialize(str, &node2, NULL); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, &node2, NULL); ck_assert_int_eq(r, 0); hdnode_fill_public_key(&node2); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, str, sizeof(str)); + hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); ck_assert_str_eq(str, "xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV"); - r = hdnode_deserialize(str, &node2, NULL); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, &node2, NULL); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); memset(&node3.private_key, 0, 32); ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); @@ -612,14 +615,14 @@ START_TEST(test_bip32_vector_1) ck_assert_mem_eq(node.private_key, fromhex("471b76e389e528d6de6d816857e012c5455051cad6660850e58372a6c3e6e7c8"), 32); hdnode_fill_public_key(&node); ck_assert_mem_eq(node.public_key, fromhex("022a471424da5e657499d1ff51cb43c47481a03b1e77f951fe64cec9f5a48f7011"), 33); - hdnode_serialize_private(&node, fingerprint, str, sizeof(str)); + hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, sizeof(str)); ck_assert_str_eq(str, "xprvA41z7zogVVwxVSgdKUHDy1SKmdb533PjDz7J6N6mV6uS3ze1ai8FHa8kmHScGpWmj4WggLyQjgPie1rFSruoUihUZREPSL39UNdE3BBDu76"); - r = hdnode_deserialize(str, &node2, NULL); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, &node2, NULL); ck_assert_int_eq(r, 0); hdnode_fill_public_key(&node2); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, str, sizeof(str)); + hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); ck_assert_str_eq(str, "xpub6H1LXWLaKsWFhvm6RVpEL9P4KfRZSW7abD2ttkWP3SSQvnyA8FSVqNTEcYFgJS2UaFcxupHiYkro49S8yGasTvXEYBVPamhGW6cFJodrTHy"); - r = hdnode_deserialize(str, &node2, NULL); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, &node2, NULL); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); memset(&node3.private_key, 0, 32); ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); @@ -644,14 +647,14 @@ START_TEST(test_bip32_vector_2) ck_assert_mem_eq(node.private_key, fromhex("4b03d6fc340455b363f51020ad3ecca4f0850280cf436c70c727923f6db46c3e"), 32); hdnode_fill_public_key(&node); ck_assert_mem_eq(node.public_key, fromhex("03cbcaa9c98c877a26977d00825c956a238e8dddfbd322cce4f74b0b5bd6ace4a7"), 33); - hdnode_serialize_private(&node, fingerprint, str, sizeof(str)); + hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, sizeof(str)); ck_assert_str_eq(str, "xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U"); - r = hdnode_deserialize(str, &node2, NULL); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, &node2, NULL); ck_assert_int_eq(r, 0); hdnode_fill_public_key(&node2); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, str, sizeof(str)); + hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); ck_assert_str_eq(str, "xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB"); - r = hdnode_deserialize(str, &node2, NULL); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, &node2, NULL); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); memset(&node3.private_key, 0, 32); ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); @@ -665,14 +668,14 @@ START_TEST(test_bip32_vector_2) ck_assert_mem_eq(node.private_key, fromhex("abe74a98f6c7eabee0428f53798f0ab8aa1bd37873999041703c742f15ac7e1e"), 32); hdnode_fill_public_key(&node); ck_assert_mem_eq(node.public_key, fromhex("02fc9e5af0ac8d9b3cecfe2a888e2117ba3d089d8585886c9c826b6b22a98d12ea"), 33); - hdnode_serialize_private(&node, fingerprint, str, sizeof(str)); + hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, sizeof(str)); ck_assert_str_eq(str, "xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt"); - r = hdnode_deserialize(str, &node2, NULL); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, &node2, NULL); ck_assert_int_eq(r, 0); hdnode_fill_public_key(&node2); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, str, sizeof(str)); + hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); ck_assert_str_eq(str, "xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH"); - r = hdnode_deserialize(str, &node2, NULL); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, &node2, NULL); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); memset(&node3.private_key, 0, 32); ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); @@ -686,14 +689,14 @@ START_TEST(test_bip32_vector_2) ck_assert_mem_eq(node.private_key, fromhex("877c779ad9687164e9c2f4f0f4ff0340814392330693ce95a58fe18fd52e6e93"), 32); hdnode_fill_public_key(&node); ck_assert_mem_eq(node.public_key, fromhex("03c01e7425647bdefa82b12d9bad5e3e6865bee0502694b94ca58b666abc0a5c3b"), 33); - hdnode_serialize_private(&node, fingerprint, str, sizeof(str)); + hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, sizeof(str)); ck_assert_str_eq(str, "xprv9wSp6B7kry3Vj9m1zSnLvN3xH8RdsPP1Mh7fAaR7aRLcQMKTR2vidYEeEg2mUCTAwCd6vnxVrcjfy2kRgVsFawNzmjuHc2YmYRmagcEPdU9"); - r = hdnode_deserialize(str, &node2, NULL); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, &node2, NULL); ck_assert_int_eq(r, 0); hdnode_fill_public_key(&node2); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, str, sizeof(str)); + hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); ck_assert_str_eq(str, "xpub6ASAVgeehLbnwdqV6UKMHVzgqAG8Gr6riv3Fxxpj8ksbH9ebxaEyBLZ85ySDhKiLDBrQSARLq1uNRts8RuJiHjaDMBU4Zn9h8LZNnBC5y4a"); - r = hdnode_deserialize(str, &node2, NULL); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, &node2, NULL); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); memset(&node3.private_key, 0, 32); ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); @@ -707,14 +710,14 @@ START_TEST(test_bip32_vector_2) ck_assert_mem_eq(node.private_key, fromhex("704addf544a06e5ee4bea37098463c23613da32020d604506da8c0518e1da4b7"), 32); hdnode_fill_public_key(&node); ck_assert_mem_eq(node.public_key, fromhex("03a7d1d856deb74c508e05031f9895dab54626251b3806e16b4bd12e781a7df5b9"), 33); - hdnode_serialize_private(&node, fingerprint, str, sizeof(str)); + hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, sizeof(str)); ck_assert_str_eq(str, "xprv9zFnWC6h2cLgpmSA46vutJzBcfJ8yaJGg8cX1e5StJh45BBciYTRXSd25UEPVuesF9yog62tGAQtHjXajPPdbRCHuWS6T8XA2ECKADdw4Ef"); - r = hdnode_deserialize(str, &node2, NULL); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, &node2, NULL); ck_assert_int_eq(r, 0); hdnode_fill_public_key(&node2); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, str, sizeof(str)); + hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); ck_assert_str_eq(str, "xpub6DF8uhdarytz3FWdA8TvFSvvAh8dP3283MY7p2V4SeE2wyWmG5mg5EwVvmdMVCQcoNJxGoWaU9DCWh89LojfZ537wTfunKau47EL2dhHKon"); - r = hdnode_deserialize(str, &node2, NULL); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, &node2, NULL); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); memset(&node3.private_key, 0, 32); ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); @@ -728,14 +731,14 @@ START_TEST(test_bip32_vector_2) ck_assert_mem_eq(node.private_key, fromhex("f1c7c871a54a804afe328b4c83a1c33b8e5ff48f5087273f04efa83b247d6a2d"), 32); hdnode_fill_public_key(&node); ck_assert_mem_eq(node.public_key, fromhex("02d2b36900396c9282fa14628566582f206a5dd0bcc8d5e892611806cafb0301f0"), 33); - hdnode_serialize_private(&node, fingerprint, str, sizeof(str)); + hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, sizeof(str)); ck_assert_str_eq(str, "xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc"); - r = hdnode_deserialize(str, &node2, NULL); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, &node2, NULL); ck_assert_int_eq(r, 0); hdnode_fill_public_key(&node2); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, str, sizeof(str)); + hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); ck_assert_str_eq(str, "xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL"); - r = hdnode_deserialize(str, &node2, NULL); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, &node2, NULL); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); memset(&node3.private_key, 0, 32); ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); @@ -749,14 +752,14 @@ START_TEST(test_bip32_vector_2) ck_assert_mem_eq(node.private_key, fromhex("bb7d39bdb83ecf58f2fd82b6d918341cbef428661ef01ab97c28a4842125ac23"), 32); hdnode_fill_public_key(&node); ck_assert_mem_eq(node.public_key, fromhex("024d902e1a2fc7a8755ab5b694c575fce742c48d9ff192e63df5193e4c7afe1f9c"), 33); - hdnode_serialize_private(&node, fingerprint, str, sizeof(str)); + hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, sizeof(str)); ck_assert_str_eq(str, "xprvA2nrNbFZABcdryreWet9Ea4LvTJcGsqrMzxHx98MMrotbir7yrKCEXw7nadnHM8Dq38EGfSh6dqA9QWTyefMLEcBYJUuekgW4BYPJcr9E7j"); - r = hdnode_deserialize(str, &node2, NULL); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, &node2, NULL); ck_assert_int_eq(r, 0); hdnode_fill_public_key(&node2); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, str, sizeof(str)); + hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); ck_assert_str_eq(str, "xpub6FnCn6nSzZAw5Tw7cgR9bi15UV96gLZhjDstkXXxvCLsUXBGXPdSnLFbdpq8p9HmGsApME5hQTZ3emM2rnY5agb9rXpVGyy3bdW6EEgAtqt"); - r = hdnode_deserialize(str, &node2, NULL); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, &node2, NULL); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); memset(&node3.private_key, 0, 32); ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); @@ -1083,7 +1086,7 @@ START_TEST(test_bip32_nist_repeat) // init m hdnode_from_seed(fromhex("000102030405060708090a0b0c0d0e0f"), 16, NIST256P1_NAME, &node); - // [Chain m/28578'] + // [Chain m/28578'] fingerprint = hdnode_fingerprint(&node); r = hdnode_private_ckd_prime(&node, 28578); ck_assert_int_eq(r, 1); @@ -1245,7 +1248,7 @@ START_TEST(test_ecdsa_signature) res = ecdsa_verify_digest_recover(curve, pubkey, fromhex("00000000000000000000000000000000000000000000000000000000000000020123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), digest, 3); ck_assert_int_eq(res, 0); ck_assert_mem_eq(pubkey, fromhex("0490d2bd2e9a564d6e1d8324fc6ad00aa4ae597684ecf4abea58bdfe7287ea4fa72968c2e5b0b40999ede3d7898d94e82c3f8dc4536a567a4bd45998c826a4c4b2"), 65); - + memcpy(digest, fromhex("0000000000000000000000000000000000000000000000000000000000000000"), 32); // r = 7: No point P with P.x = 7, but P.x = (order + 7) exists res = ecdsa_verify_digest_recover(curve, pubkey, fromhex("00000000000000000000000000000000000000000000000000000000000000070123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), digest, 2); @@ -1265,7 +1268,7 @@ START_TEST(test_ecdsa_signature) res = ecdsa_verify_digest_recover(curve, pubkey, fromhex("00000000000000000000000000000000000000000000000000000000000000010123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), digest, 1); ck_assert_int_eq(res, 0); ck_assert_mem_eq(pubkey, fromhex("049e609c3950e70d6f3e3f3c81a473b1d5ca72739d51debdd80230ae80cab05134a94285375c834a417e8115c546c41da83a263087b79ef1cae25c7b3c738daa2b"), 65); - + // r = 0 is always invalid res = ecdsa_verify_digest_recover(curve, pubkey, fromhex("00000000000000000000000000000000000000000000000000000000000000010123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), digest, 2); ck_assert_int_eq(res, 1); @@ -2922,7 +2925,7 @@ START_TEST(test_multibyte_address) // wrong length res = ecdsa_address_decode("BrsGxAHga3VbopvSnb3gmLvMBhJNCGuDxBZL44", 0x123456, decode); ck_assert_int_eq(res, 0); - + // wrong address prefix res = ecdsa_address_decode("BrsGxAHga3VbopvSnb3gmLvMBhJNCGuDxBZL44", 0x22345678, decode); ck_assert_int_eq(res, 0); From cfde8ec2339bf62803db42e07324599457468079 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 21 Apr 2017 13:44:10 +0200 Subject: [PATCH 403/627] use pkg-config for build of tests --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index bb50e3097..0201336bc 100644 --- a/Makefile +++ b/Makefile @@ -46,8 +46,8 @@ SRCS += blake2b.c blake2s.c OBJS = $(SRCS:.c=.o) -TESTLIBS = -lcheck -lrt -lpthread -lm -lsubunit -TESTSSLLIBS = -lcrypto +TESTLIBS = $(shell pkg-config --libs check) -lrt -lpthread -lm +TESTSSLLIBS = -lcrypto all: tests test-openssl libtrezor-crypto.so test_speed tools From fa82ba6d3f4ca9bbfee0c3dd7f8da22a8bfc6f11 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 21 Apr 2017 13:53:10 +0200 Subject: [PATCH 404/627] fix xpubaddrgen --- tools/xpubaddrgen.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/xpubaddrgen.c b/tools/xpubaddrgen.c index 7d42af61a..b1bc5a5e4 100644 --- a/tools/xpubaddrgen.c +++ b/tools/xpubaddrgen.c @@ -5,10 +5,13 @@ #include "bip32.h" #include "ecdsa.h" +#define VERSION_PUBLIC 0x0488b21e +#define VERSION_PRIVATE 0x0488ade4 + void process_job(uint32_t jobid, const char *xpub, uint32_t change, uint32_t from, uint32_t to) { HDNode node, child; - if (change > 1 || to <= from || hdnode_deserialize(xpub, &node, NULL) != 0) { + if (change > 1 || to <= from || hdnode_deserialize(xpub, VERSION_PUBLIC, VERSION_PRIVATE, &node, NULL) != 0) { printf("%d error\n", jobid); return; } From 8b47323c05960b4c623ddc1275daa0b8d6f7202c Mon Sep 17 00:00:00 2001 From: Karel Bilek Date: Thu, 4 May 2017 02:34:41 +0200 Subject: [PATCH 405/627] Changing `this` to `self` in emscripten post --- emscripten/post.js | 4 ++-- emscripten/trezor-crypto.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/emscripten/post.js b/emscripten/post.js index 752d9bb2a..ce2dfb7b0 100644 --- a/emscripten/post.js +++ b/emscripten/post.js @@ -98,7 +98,7 @@ function processMessage(event) { data['version'], !!data['segwit'] ); - postMessage({ + self.postMessage({ 'addresses': addresses, 'firstIndex': data['firstIndex'], 'lastIndex': data['lastIndex'] @@ -111,5 +111,5 @@ function processMessage(event) { } if (ENVIRONMENT_IS_WORKER) { - this['onmessage'] = processMessage; + self.onmessage = processMessage; } diff --git a/emscripten/trezor-crypto.js b/emscripten/trezor-crypto.js index 3d6d33a4d..b56b4b49f 100644 --- a/emscripten/trezor-crypto.js +++ b/emscripten/trezor-crypto.js @@ -360,7 +360,7 @@ bc(c,C,w[d+8*n>>2],w[d+(8*n+4)>>2],void 0);if(0>u){f=-1;break a}h+=u}f=h}return var Z=(function(global,env,buffer) { "use asm";var a=new global.Int8Array(buffer);var b=new global.Int16Array(buffer);var c=new global.Int32Array(buffer);var d=new global.Uint8Array(buffer);var e=new global.Uint16Array(buffer);var f=new global.Uint32Array(buffer);var g=new global.Float32Array(buffer);var h=new global.Float64Array(buffer);var i=env.STACKTOP|0;var j=env.STACK_MAX|0;var k=env.DYNAMICTOP_PTR|0;var l=env.tempDoublePtr|0;var m=env.ABORT|0;var n=0;var o=0;var p=0;var q=0;var r=global.NaN,s=global.Infinity;var t=0,u=0,v=0,w=0,x=0.0,y=0,z=0,A=0,B=0.0;var C=0;var D=global.Math.floor;var E=global.Math.abs;var F=global.Math.sqrt;var G=global.Math.pow;var H=global.Math.cos;var I=global.Math.sin;var J=global.Math.tan;var K=global.Math.acos;var L=global.Math.asin;var M=global.Math.atan;var N=global.Math.atan2;var O=global.Math.exp;var P=global.Math.log;var Q=global.Math.ceil;var R=global.Math.imul;var S=global.Math.min;var T=global.Math.max;var U=global.Math.clz32;var V=env.abort;var W=env.assert;var X=env.enlargeMemory;var Y=env.getTotalMemory;var Z=env.abortOnCannotGrowMemory;var _=env.invoke_ii;var $=env.invoke_iiii;var aa=env.invoke_vi;var ba=env._pthread_cleanup_pop;var ca=env.___syscall221;var da=env.___syscall54;var ea=env.___lock;var fa=env._abort;var ga=env._pthread_cleanup_push;var ha=env.___syscall6;var ia=env._llvm_stacksave;var ja=env.___syscall140;var ka=env.___syscall5;var la=env._emscripten_memcpy_big;var ma=env._llvm_bswap_i64;var na=env.___unlock;var oa=env._llvm_stackrestore;var pa=env.___assert_fail;var qa=env.___syscall145;var ra=env.___syscall146;var sa=env.___setErrNo;var ta=0.0; // EMSCRIPTEN_START_FUNCS -function xa(a){a=a|0;var b=0;b=i;i=i+a|0;i=i+15&-16;return b|0}function ya(){return i|0}function za(a){a=a|0;i=a}function Aa(a,b){a=a|0;b=b|0;i=a;j=b}function Ba(a,b){a=a|0;b=b|0;if(!n){n=a;o=b}}function Ca(a){a=a|0;C=a}function Da(){return C|0}function Ea(b,c){b=b|0;c=c|0;a[b>>0]=c>>>24;a[b+1>>0]=c>>>16;a[b+2>>0]=c>>>8;a[b+3>>0]=c;return}function Fa(a,b){a=a|0;b=b|0;var e=0,f=0,g=0,h=0;e=0;f=0;do{h=a+(7-f<<2)|0;h=(d[h+1>>0]|0)<<16|(d[h>>0]|0)<<24|(d[h+2>>0]|0)<<8|(d[h+3>>0]|0);g=f<<1;c[b+(f<<2)>>2]=(h<>>(30-g|0);f=f+1|0}while((f|0)!=8);c[b+32>>2]=e;return}function Ga(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0;e=c[b+32>>2]<<16;f=0;while(1){g=c[b+(7-f<<2)>>2]|0;h=f<<1;i=g>>>(14-h|0)|e;e=d+(f<<2)|0;a[e>>0]=i>>>24;a[e+1>>0]=i>>>16;a[e+2>>0]=i>>>8;a[e+3>>0]=i;f=f+1|0;if((f|0)==8)break;else e=g<>2]=0;a=a+4|0}while((a|0)<(b|0));return}function Ia(a){a=a|0;return (c[a+32>>2]|(c[a+28>>2]|(c[a+24>>2]|(c[a+20>>2]|(c[a+16>>2]|(c[a+12>>2]|(c[a+8>>2]|(c[a+4>>2]|c[a>>2])))))))|0)==0|0}function Ja(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0;d=0;e=8;f=0;while(1){h=c[a+(e<<2)>>2]|0;g=c[b+(e<<2)>>2]|0;d=h>>>0>>0|d<<1;f=h>>>0>g>>>0|f<<1;if((e|0)<=0)break;else e=e+-1|0}return d>>>0>f>>>0|0}function Ka(a,b){a=a|0;b=b|0;var d=0,e=0;d=0;e=0;do{e=c[b+(d<<2)>>2]^c[a+(d<<2)>>2]|e;d=d+1|0}while((d|0)!=9);return (e|0)==0|0}function La(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0;g=0-b|0;h=b+-1|0;if((b|1|0)==1)f=0;else pa(38200,38223,270,38235);do{c[a+(f<<2)>>2]=c[e+(f<<2)>>2]&h|c[d+(f<<2)>>2]&g;f=f+1|0}while((f|0)!=9);return}function Ma(a){a=a|0;var b=0,d=0,e=0,f=0;b=8;d=c[a+32>>2]|0;do{e=b;b=b+-1|0;f=d;d=c[a+(b<<2)>>2]|0;c[a+(e<<2)>>2]=d>>>29&1|f<<1&1073741822}while((e|0)>1);c[a>>2]=c[a>>2]<<1&1073741822;return}function Na(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,i=0;d=c[a>>2]|0;f=0-(d&1)|0;d=((c[b>>2]&f)+d|0)>>>1;e=0;do{i=e;e=e+1|0;g=(c[b+(e<<2)>>2]&f)+(c[a+(e<<2)>>2]|0)|0;h=(g<<29&536870912)+d|0;c[a+(i<<2)>>2]=h&1073741823;d=(h>>>30)+(g>>>1)|0}while((e|0)!=8);c[a+32>>2]=d;return}function Oa(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0;e=b&255;b=0;do{f=a+(b<<2)|0;c[f>>2]=R(c[f>>2]|0,e)|0;b=b+1|0}while((b|0)!=9);Pa(a,d);return}function Pa(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0;g=(c[a+32>>2]|0)>>>16;i=c[a>>2]|0;h=pc(c[b>>2]|0,0,g|0,0)|0;d=C;e=kc(i|0,536870912,h|0,d|0)|0;f=C;d=kc(i|0,0,h|0,d|0)|0;c[a>>2]=d&1073741823;d=1;while(1){l=mc(e|0,f|0,30)|0;k=C;i=a+(d<<2)|0;j=c[i>>2]|0;f=pc(c[b+(d<<2)>>2]|0,0,g|0,0)|0;h=C;k=qc(l|0,k|0,-2147483648,536870911)|0;j=qc(k|0,C|0,j|0,0)|0;e=kc(j|0,C|0,f|0,h|0)|0;c[i>>2]=e&1073741823;d=d+1|0;if((d|0)==9)break;else f=C}return}function Qa(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0;h=i;i=i+48|0;g=h;d=0;e=8;f=0;while(1){k=c[a+(e<<2)>>2]|0;j=c[b+(e<<2)>>2]|0;d=k>>>0>>0|d<<1;f=k>>>0>j>>>0|f<<1;if((e|0)<=0)break;else e=e+-1|0}f=d>>>0>f>>>0;e=0;d=1;while(1){d=d+1073741823+(c[a+(e<<2)>>2]|0)-(c[b+(e<<2)>>2]|0)|0;c[g+(e<<2)>>2]=d&1073741823;e=e+1|0;if((e|0)==9)break;else d=d>>>30}La(a,f&1,a,g);i=h;return}function Ra(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0;f=0;e=1;while(1){e=e+1073741823+(c[a+(f<<2)>>2]|0)-(c[b+(f<<2)>>2]|0)|0;c[d+(f<<2)>>2]=e&1073741823;f=f+1|0;if((f|0)==9)break;else e=e>>>30}return}function Sa(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0,j=0;h=0;g=0;e=0;i=1;while(1){f=0;do{j=pc(c[b+(h-f<<2)>>2]|0,0,c[a+(f<<2)>>2]|0,0)|0;g=qc(j|0,C|0,g|0,e|0)|0;e=C;f=f+1|0}while((f|0)!=(i|0));c[d+(h<<2)>>2]=g&1073741823;g=mc(g|0,e|0,30)|0;e=C;h=h+1|0;if((h|0)==9){h=9;break}else i=i+1|0}while(1){f=h+-8|0;if((f|0)<9)do{j=pc(c[b+(h-f<<2)>>2]|0,0,c[a+(f<<2)>>2]|0,0)|0;g=qc(j|0,C|0,g|0,e|0)|0;e=C;f=f+1|0}while((f|0)!=9);c[d+(h<<2)>>2]=g&1073741823;g=mc(g|0,e|0,30)|0;h=h+1|0;if((h|0)==17)break;else e=C}c[d+68>>2]=g;return}function Ta(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0;l=a+(d+1<<2)|0;j=(c[l>>2]<<14)+((c[a+(d<<2)>>2]|0)>>>16)|0;k=d+-8|0;e=a+(k<<2)|0;f=c[e>>2]|0;g=pc(c[b>>2]|0,0,j|0,0)|0;h=C;if((j|0)<=-1)pa(38243,38223,417,38262);i=kc(f|0,536870912,g|0,h|0)|0;m=C;h=kc(f|0,0,g|0,h|0)|0;c[e>>2]=h&1073741823;h=mc(i|0,m|0,30)|0;m=C;i=a+(d+-7<<2)|0;f=qc(c[i>>2]|0,0,-2147483648,536870911)|0;e=1;g=C;d=m;do{m=pc(c[b+(e<<2)>>2]|0,0,j|0,0)|0;m=kc(f|0,g|0,m|0,C|0)|0;m=qc(m|0,C|0,h|0,d|0)|0;c[i>>2]=m&1073741823;e=e+1|0;h=mc(m|0,C|0,30)|0;d=C;i=a+(e+k<<2)|0;f=qc(c[i>>2]|0,0,-2147483648,536870911)|0;g=C}while((e|0)!=9);m=qc(f|0,g|0,h|0,d|0)|0;c[l>>2]=m&1073741823;return}function Ua(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0;e=16;while(1){Ta(b,d,e);if(c[b+(e+1<<2)>>2]|0){g=4;break}e=e+-1|0;if((e|0)<=7){f=0;break}}if((g|0)==4)pa(38286,38223,451,38302);do{c[a+(f<<2)>>2]=c[b+(f<<2)>>2];f=f+1|0}while((f|0)!=9);return}function Va(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0;g=i;i=i+80|0;e=g;f=e;h=f+72|0;do{c[f>>2]=0;f=f+4|0}while((f|0)<(h|0));Sa(a,b,e);Ua(b,e,d);i=g;return}function Wa(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0;n=i;i=i+144|0;k=n+72|0;l=n+36|0;m=n;c[l>>2]=1;h=l+4|0;c[h>>2]=0;c[h+4>>2]=0;c[h+8>>2]=0;c[h+12>>2]=0;c[h+16>>2]=0;c[h+20>>2]=0;c[h+24>>2]=0;c[h+28>>2]=0;h=m;d=b;j=h+36|0;do{c[h>>2]=c[d>>2];h=h+4|0;d=d+4|0}while((h|0)<(j|0));e=0;d=1;while(1){j=m+(e<<2)|0;d=(c[j>>2]|0)+d|0;c[j>>2]=d&1073741823;e=e+1|0;if((e|0)==9)break;else d=d>>>30}d=0;e=c[m>>2]|0;do{j=d;d=d+1|0;h=e;e=c[m+(d<<2)>>2]|0;c[m+(j<<2)>>2]=e<<29&536870912|h>>>1}while((d|0)!=8);e=m+32|0;c[e>>2]=(c[e>>2]|0)>>>1;d=0;f=c[m>>2]|0;do{j=d;d=d+1|0;h=f;f=c[m+(d<<2)>>2]|0;c[m+(j<<2)>>2]=f<<29&536870912|h>>>1}while((d|0)!=8);c[e>>2]=(c[e>>2]|0)>>>1;e=0;do{g=(e|0)==8;d=0;f=c[m+(e<<2)>>2]|0;do{if(g&(f|0)==0)break;if(f&1|0){h=k;j=h+72|0;do{c[h>>2]=0;h=h+4|0}while((h|0)<(j|0));Sa(a,l,k);Ua(l,k,b)}f=f>>>1;h=k;j=h+72|0;do{c[h>>2]=0;h=h+4|0}while((h|0)<(j|0));Sa(a,a,k);Ua(a,k,b);d=d+1|0}while(d>>>0<30);e=e+1|0}while((e|0)!=9);Qa(l,b);h=a;d=l;j=h+36|0;do{c[h>>2]=c[d>>2];h=h+4|0;d=d+4|0}while((h|0)<(j|0));i=n;return}function Xa(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0;v=i;i=i+112|0;d=v+72|0;u=v+32|0;t=v;Pa(a,b);Qa(a,b);e=c[b>>2]|0;f=0;while(1){r=f;f=f+1|0;g=c[b+(f<<2)>>2]|0;h=r<<1;p=g<<30-h|e;c[t+(r<<2)>>2]=p;c[d+(r<<2)>>2]=p;if((f|0)==8)break;else e=g>>>(h+2|0)}e=c[a>>2]|0;f=0;while(1){r=f;f=f+1|0;b=c[a+(f<<2)>>2]|0;g=r<<1;c[u+(r<<2)>>2]=b<<30-g|e;if((f|0)==8)break;else e=b>>>(g+2|0)}o=d+36|0;c[o>>2]=8;p=u+36|0;c[p>>2]=8;r=d+32|0;c[r>>2]=1;c[u+32>>2]=0;f=0;n=u;e=8;g=c[d>>2]|0;b=1;a:while(1){if(!(g&1)){q=7;break}if(!(b&1)){q=10;break}l=n+36|0;b=e;while(1){e=b+-1|0;if(c[n+(e<<2)>>2]|0)break;c[l>>2]=e;if((b|0)<1)break a;else b=e}e=c[n>>2]|0;if(!e){g=n+32|0;do{e=0;do{m=e;e=e+1|0;c[n+(m<<2)>>2]=c[n+(e<<2)>>2]}while((e|0)!=8);c[g>>2]=0;b=(c[l>>2]|0)+-1|0;c[l>>2]=b;f=f+32|0;e=c[n>>2]|0}while((e|0)==0)}k=0;while(1)if(!(e&1<0){e=e>>>k;if((b|0)>1){j=32-k|0;g=1;h=n;while(1){b=n+(g<<2)|0;c[h>>2]=c[b>>2]<>2]|0)>>>k;if((e|0)<(c[l>>2]|0)){g=e;e=h;h=b}else break}}else{g=0;h=e;b=n;e=1}c[b>>2]=h;if(!h)c[l>>2]=(c[l>>2]|0)+-1;else g=e;e=n+(g<<2)|0;b=c[e>>2]<>2]=(c[e>>2]|0)>>>h|b;b=c[e>>2]<>2]=b;m=k+f|0}else m=f;if(!(c[n>>2]&1)){q=32;break}if(c[n+32>>2]&1|0){q=34;break}f=c[o>>2]|0;e=f-(c[p>>2]|0)|0;if(!e){e=f;while(1){b=e+-1|0;if((e|0)<=0){q=38;break}e=c[d+(b<<2)>>2]|0;f=u+(b<<2)|0;if((e|0)==(c[f>>2]|0))e=b;else break}if((q|0)==38){q=0;if(!e){q=56;break}f=u+(b<<2)|0;e=c[d+(b<<2)>>2]|0}e=e>>>0>(c[f>>2]|0)>>>0?1:-1}n=(e|0)>0;l=n?u:d;n=n?d:u;k=l+36|0;h=c[k>>2]|0;if((h|0)>0){e=0;f=1;b=0;while(1){j=n+(e<<2)|0;w=c[j>>2]|0;g=c[l+(e<<2)>>2]|0;f=qc(f|0,b|0,-1,0)|0;f=qc(f|0,C|0,w|0,0)|0;g=kc(f|0,C|0,g|0,0)|0;f=C;c[j>>2]=g;e=e+1|0;if((e|0)<(h|0))b=0;else{b=e;g=0;break}}}else{b=0;f=1;g=0}j=n+36|0;e=c[j>>2]|0;if((b|0)<(e|0)){e=g;while(1){w=n+(b<<2)|0;g=c[w>>2]|0;e=qc(f|0,e|0,-1,0)|0;e=qc(e|0,C|0,g|0,0)|0;c[w>>2]=e;b=b+1|0;e=c[j>>2]|0;if((b|0)>=(e|0))break;else{f=C;e=0}}}if((e|0)>8){f=8;g=0;b=0}else{f=8;g=0;b=0;while(1){w=l+(f<<2)|0;j=c[n+(f<<2)>>2]|0;h=qc(c[w>>2]|0,0,g|0,b|0)|0;j=qc(h|0,C|0,j|0,0)|0;g=C;c[w>>2]=j;w=f;f=f+-1|0;if((w|0)<=(e|0))break;else b=0}h=c[k>>2]|0;b=0}if((f|0)>=(h|0))while(1){w=l+(f<<2)|0;j=qc(c[w>>2]|0,0,g|0,b|0)|0;c[w>>2]=j;if((f|0)>(c[k>>2]|0)){f=f+-1|0;g=C;b=0}else break}g=c[l>>2]|0;if(!(g&1)){q=51;break}b=c[l+32>>2]|0;if(!(b&1)){q=53;break}if(c[n>>2]&1|0){q=55;break}else f=m}if((q|0)==7)pa(38321,38223,646,38335);else if((q|0)==10)pa(38346,38223,647,38335);else if((q|0)==32)pa(38360,38223,699,38335);else if((q|0)==34)pa(38375,38223,700,38335);else if((q|0)==51)pa(38321,38223,757,38335);else if((q|0)==53)pa(38346,38223,758,38335);else if((q|0)==55)pa(38397,38223,759,38335);else if((q|0)==56){l=c[t>>2]|0;if(!(l&1))pa(38419,38223,786,38335);f=l+-1|0;e=l+-2|0;if(!f)k=e;else{do{f=R(f,f)|0;e=R(f+1|0,e)|0}while((f|0)!=0);k=e}b:do if((m|0)>31){j=d+4|0;e=m;while(1){w=c[r>>2]|0;b=R(w,k)|0;q=pc(l|0,0,b|0,0)|0;w=qc(q|0,C|0,w|0,0)|0;if(!((w|0)==0&0==0))break;f=0;g=C;h=0;while(1){w=f;f=f+1|0;o=c[d+(7-w<<2)>>2]|0;p=pc(c[t+(f<<2)>>2]|0,0,b|0,0)|0;q=C;o=qc(o|0,0,g|0,h|0)|0;q=qc(o|0,C|0,p|0,q|0)|0;g=C;c[d+(8-w<<2)>>2]=q;if((f|0)==7)break;else h=0}c[j>>2]=g;e=e+-32|0;if((e|0)<=31){s=e;break b}}pa(38429,38223,802,38335)}else s=m;while(0);if((s|0)>0){w=(1<>2]|0;h=(R(e,k)|0)&w;if((R(h,l)|0)+e&w|0)pa(38454,38223,821,38335);b=pc(h|0,0,l|0,0)|0;b=qc(b|0,C|0,e|0,0)|0;b=mc(b|0,C|0,s|0)|0;f=32-s|0;e=0;g=C;while(1){w=e;e=e+1|0;s=c[d+(7-w<<2)>>2]|0;r=pc(c[t+(e<<2)>>2]|0,0,h|0,0)|0;s=qc(r|0,C|0,s|0,0)|0;s=nc(s|0,C|0,f|0)|0;s=qc(s|0,C|0,b|0,g|0)|0;b=C;c[d+(8-w<<2)>>2]=s;if((e|0)==7)break;else g=0}c[d+4>>2]=b;e=0;f=0}else{e=0;f=0}do{s=c[d+(8-e<<2)>>2]|0;w=e<<1;c[a+(e<<2)>>2]=s<>>(30-w|0);e=e+1|0}while((e|0)!=8);c[a+32>>2]=f;c[t>>2]=0;c[t+4>>2]=0;c[t+8>>2]=0;c[t+12>>2]=0;c[t+16>>2]=0;c[t+20>>2]=0;c[t+24>>2]=0;c[t+28>>2]=0;e=d+40|0;do{c[d>>2]=0;d=d+4|0}while((d|0)<(e|0));d=u;e=d+40|0;do{c[d>>2]=0;d=d+4|0}while((d|0)<(e|0))}i=v;return}function Ya(a,b){a=a|0;b=b|0;var d=0,e=0,f=0;e=0;d=0;while(1){f=a+(e<<2)|0;d=(c[f>>2]|0)+d+(c[b+(e<<2)>>2]|0)|0;c[f>>2]=d&1073741823;e=e+1|0;if((e|0)==9)break;else d=d>>>30}return}function Za(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0;e=0;do{f=a+(e<<2)|0;c[f>>2]=(c[f>>2]|0)+(c[b+(e<<2)>>2]|0);e=e+1|0}while((e|0)!=9);Pa(a,d);return}function _a(a,b,d){a=a|0;b=b|0;d=d|0;var e=0;if((c[d>>2]|0)>>>0>>0)pa(38495,38223,883,38514);b=(c[a>>2]|0)-b|0;c[a>>2]=b;b=b+(c[d>>2]|0)|0;c[a>>2]=b&1073741823;e=1;do{b=(c[a+(e<<2)>>2]|0)+(b>>>30)+(c[d+(e<<2)>>2]|0)|0;c[a+(e<<2)>>2]=b&1073741823;e=e+1|0}while((e|0)!=9);return}function $a(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0;g=0;f=1;while(1){f=f+1073741823+(c[a+(g<<2)>>2]|0)+(c[e+(g<<2)>>2]<<1)-(c[b+(g<<2)>>2]|0)|0;c[d+(g<<2)>>2]=f&1073741823;g=g+1|0;if((g|0)==9)break;else f=f>>>30}return}function ab(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0;n=i;i=i+144|0;k=n+108|0;e=n+72|0;l=n+36|0;m=n;do if(!(bb(b)|0)){if(bb(d)|0){e=d;f=b;g=e+72|0;do{c[e>>2]=c[f>>2];e=e+4|0;f=f+4|0}while((e|0)<(g|0));break}if(cb(b,d)|0){db(a,d);break}if(!(eb(b,d)|0)){$a(d,b,e,a);Xa(e,a);h=d+36|0;j=b+36|0;$a(h,j,k,a);Va(e,k,a);e=l;f=k;g=e+36|0;do{c[e>>2]=c[f>>2];e=e+4|0;f=f+4|0}while((e|0)<(g|0));Va(l,l,a);e=m;f=b;g=e+36|0;do{c[e>>2]=c[f>>2];e=e+4|0;f=f+4|0}while((e|0)<(g|0));Za(m,d,a);$a(l,m,l,a);Pa(l,a);Qa(l,a);$a(b,l,m,a);Va(k,m,a);$a(m,j,m,a);Pa(m,a);Qa(m,a);e=d;f=l;g=e+36|0;do{c[e>>2]=c[f>>2];e=e+4|0;f=f+4|0}while((e|0)<(g|0));e=h;f=m;g=e+36|0;do{c[e>>2]=c[f>>2];e=e+4|0;f=f+4|0}while((e|0)<(g|0));break}else{Ha(d);Ha(d+36|0);break}}while(0);i=n;return}function bb(a){a=a|0;if(!(Ia(a)|0))a=0;else a=(Ia(a+36|0)|0)!=0;return a&1|0}function cb(a,b){a=a|0;b=b|0;if(!(Ka(a,b)|0))a=0;else a=(Ka(a+36|0,b+36|0)|0)!=0;return a&1|0}function db(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0,l=0;j=i;i=i+112|0;d=j+72|0;e=j+36|0;f=j;do if(!(bb(b)|0)){g=b+36|0;if(!(Ia(g)|0)){h=d;k=g;l=h+36|0;do{c[h>>2]=c[k>>2];h=h+4|0;k=k+4|0}while((h|0)<(l|0));Oa(d,2,a);Xa(d,a);h=e;k=b;l=h+36|0;do{c[h>>2]=c[k>>2];h=h+4|0;k=k+4|0}while((h|0)<(l|0));Va(e,e,a);Oa(e,3,a);_a(e,0-(c[a+180>>2]|0)|0,a);Va(e,d,a);h=e;k=d;l=h+36|0;do{c[h>>2]=c[k>>2];h=h+4|0;k=k+4|0}while((h|0)<(l|0));Va(e,e,a);h=f;k=b;l=h+36|0;do{c[h>>2]=c[k>>2];h=h+4|0;k=k+4|0}while((h|0)<(l|0));Ma(f);$a(e,f,e,a);Pa(e,a);Qa(e,a);$a(b,e,f,a);Va(d,f,a);$a(f,g,f,a);Pa(f,a);Qa(f,a);h=b;k=e;l=h+36|0;do{c[h>>2]=c[k>>2];h=h+4|0;k=k+4|0}while((h|0)<(l|0));h=g;k=f;l=h+36|0;do{c[h>>2]=c[k>>2];h=h+4|0;k=k+4|0}while((h|0)<(l|0));break}else{Ha(b);Ha(g);break}}while(0);i=j;return}function eb(a,b){a=a|0;b=b|0;var c=0;if((Ka(a,b)|0)!=0?(c=a+36|0,(Ia(c)|0)==0):0)a=(Ka(c,b+36|0)|0)==0&1;else a=0;return a|0}function fb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0,j=0;g=b+32|0;if((c[g>>2]|0)>>>0>=131072)pa(38522,38542,180,38553);h=a&1073741823;f=~a;a=c[b>>2]|0;e=(c[d>>2]<<1)+1073741824-a|0;c[b>>2]=h&e|a&f;a=0;do{a=a+1|0;i=b+(a<<2)|0;j=c[i>>2]|0;e=(e>>>30)+1073741823+(c[d+(a<<2)>>2]<<1)-j|0;c[i>>2]=h&e|j&f}while((a|0)!=8);if((c[g>>2]|0)>>>0<131072)return;else pa(38522,38542,188,38553)}function gb(a,b){a=a|0;b=b|0;var d=0,e=0,f=0;e=a+32|0;while(1){d=0;f=Kb()|0;do{c[a+(d<<2)>>2]=f&1073741823;d=d+1|0;f=Kb()|0}while((d|0)!=8);c[e>>2]=f&65535;if(Ia(a)|0)continue;if(Ja(a,b)|0)break}return}function hb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0;e=b+72|0;gb(e,d);g=b;h=e;i=g+36|0;do{c[g>>2]=c[h>>2];g=g+4|0;h=h+4|0}while((g|0)<(i|0));Va(e,b,d);f=b+36|0;g=f;h=b;i=g+36|0;do{c[g>>2]=c[h>>2];g=g+4|0;h=h+4|0}while((g|0)<(i|0));Va(e,f,d);Va(a,b,d);Va(a+36|0,f,d);return}function ib(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0;e=b+36|0;f=e;g=a+72|0;h=f+36|0;do{c[f>>2]=c[g>>2];f=f+4|0;g=g+4|0}while((f|0)<(h|0));Xa(e,d);f=b;g=e;h=f+36|0;do{c[f>>2]=c[g>>2];f=f+4|0;g=g+4|0}while((f|0)<(h|0));Va(b,b,d);Va(b,e,d);Va(a,b,d);Va(a+36|0,e,d);Qa(b,d);Qa(e,d);return}function jb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0;s=i;i=i+288|0;k=s+252|0;l=s+216|0;m=s+180|0;n=s+144|0;o=s+108|0;p=s+72|0;q=s+36|0;g=s;e=c[d+180>>2]|0;if((e+3|0)>>>0>=4)pa(38572,38542,247,38590);h=b+72|0;r=p;t=h;u=r+36|0;do{c[r>>2]=c[t>>2];r=r+4|0;t=t+4|0}while((r|0)<(u|0));Va(p,p,d);r=q;t=h;u=r+36|0;do{c[r>>2]=c[t>>2];r=r+4|0;t=t+4|0}while((r|0)<(u|0));Va(p,q,d);j=(e|0)!=0;if(j){e=0-e|0;r=g;t=p;u=r+36|0;do{c[r>>2]=c[t>>2];r=r+4|0;t=t+4|0}while((r|0)<(u|0));Va(g,g,d);Oa(g,e&255,d)}Va(a,p,d);r=l;t=p;u=r+36|0;do{c[r>>2]=c[t>>2];r=r+4|0;t=t+4|0}while((r|0)<(u|0));$a(l,b,l,d);Pa(l,d);Ya(p,b);f=Ka(l,d)|0;Va(a+36|0,q,d);e=b+36|0;$a(q,e,k,d);Ya(q,e);r=m;t=b;u=r+36|0;do{c[r>>2]=c[t>>2];r=r+4|0;t=t+4|0}while((r|0)<(u|0));Va(m,m,d);Oa(m,3,d);if(j)$a(m,g,m,d);La(k,f,m,k);La(l,f,q,l);r=o;t=l;u=r+36|0;do{c[r>>2]=c[t>>2];r=r+4|0;t=t+4|0}while((r|0)<(u|0));Va(o,o,d);r=n;t=l;u=r+36|0;do{c[r>>2]=c[t>>2];r=r+4|0;t=t+4|0}while((r|0)<(u|0));Va(o,n,d);Va(p,o,d);Va(q,n,d);Va(l,h,d);r=b;t=k;u=r+36|0;do{c[r>>2]=c[t>>2];r=r+4|0;t=t+4|0}while((r|0)<(u|0));Va(b,b,d);$a(b,o,b,d);Pa(b,d);$a(o,b,e,d);$a(e,b,e,d);Va(k,e,d);$a(e,n,e,d);Na(e,d);Pa(e,d);i=s;return}function kb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0;n=i;i=i+144|0;l=n+108|0;m=n;if(!(Ja(b,a+108|0)|0))pa(38609,38542,552,38658);j=c[b>>2]|0;g=(j&1)+-1|0;f=1;e=0;h=j;do{k=f+1073741823+h-(c[a+108+(e<<2)>>2]&g)|0;c[l+(e<<2)>>2]=k&1073741823;f=k>>>30;e=e+1|0;h=c[b+(e<<2)>>2]|0;j=h|j}while((e|0)!=8);k=l+32|0;c[k>>2]=f+65535+h-(c[a+140>>2]&g);e=c[l>>2]|0;if(!(e&1))pa(38638,38542,575,38658);if(!j){Ha(d);Ha(d+36|0)}else{hb(a+220+((((e>>>4&1)+15^e)>>>1&7)*72|0)|0,m,a);h=m+36|0;g=1;do{f=0;e=e>>>4;b=l;do{f=f+1|0;j=b;b=l+(f<<2)|0;c[j>>2]=c[b>>2]<<26&1006632960|e;e=(c[b>>2]|0)>>>4}while((f|0)!=8);c[k>>2]=e;e=c[l>>2]|0;b=e>>>4&1;j=b+15^e;fb((j&1)+-1|0,h,a);jb(a+220+(g*576|0)+((j>>>1&7)*72|0)|0,m,a);g=g+1|0}while((g|0)!=64);fb(b+-1|0,h,a);ib(m,d,a)}i=n;return}function lb(b,c,d){b=b|0;c=c|0;d=d|0;b=(b|0)==0?712:b;switch(a[c>>0]|0){case 4:{Fa(c+1|0,d);Fa(c+33|0,d+36|0);b=mb(b,d)|0;break}case 3:case 2:{Fa(c+1|0,d);nb(b,a[c>>0]|0,d,d+36|0);b=mb(b,d)|0;break}default:b=0}return b|0}function mb(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0;k=i;i=i+80|0;d=k+36|0;e=k;if(((bb(b)|0)==0?(Ja(b,a)|0)!=0:0)?(f=b+36|0,(Ja(f,a)|0)!=0):0){g=d;h=f;j=g+36|0;do{c[g>>2]=c[h>>2];g=g+4|0;h=h+4|0}while((g|0)<(j|0));g=e;h=b;j=g+36|0;do{c[g>>2]=c[h>>2];g=g+4|0;h=h+4|0}while((g|0)<(j|0));Va(f,d,a);Qa(d,a);Va(b,e,a);_a(e,0-(c[a+180>>2]|0)|0,a);Va(b,e,a);Za(e,a+184|0,a);Qa(e,a);a=(Ka(e,d)|0)!=0&1}else a=0;i=k;return a|0}function nb(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0;f=e;g=d;h=f+36|0;do{c[f>>2]=c[g>>2];f=f+4|0;g=g+4|0}while((f|0)<(h|0));Va(d,e,a);_a(e,0-(c[a+180>>2]|0)|0,a);Va(d,e,a);Ya(e,a+184|0);Wa(e,a);if((c[e>>2]^b&255)&1|0)Ra(a,e,e);return}function ob(b,c){b=b|0;c=c|0;var d=0,e=0;e=i;i=i+32|0;d=e;switch(a[b>>0]|0){case 4:{Eb(b,65,d);break}case 0:{Eb(b,1,d);break}default:Eb(b,33,d)}Ab(d,32,c);i=e;return}function pb(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0,f=0,g=0,h=0;e=i;i=i+48|0;g=e;f=Lb(b)|0;h=Lb(b)|0;Mb(b,g);ob(a,g+h|0);wb(g,f+20|0,c,d)|0;i=e;return}function qb(b,c,e){b=b|0;c=c|0;e=e|0;var f=0,g=0,h=0,j=0;j=i;i=i+128|0;h=j;f=h;g=f+128|0;do{a[f>>0]=0;f=f+1|0}while((f|0)<(g|0));if(e>>>0>128){Jb(c,e,h);c=0}else{tc(h|0,c|0,e|0)|0;c=0}do{g=h+c|0;f=d[g>>0]|0;a[b+c>>0]=f^92;a[g>>0]=f^54;c=c+1|0}while((c|0)!=128);b=b+128|0;Fb(b);Hb(b,h,128);i=j;return}function rb(a,b){a=a|0;b=b|0;var c=0,d=0,e=0;c=i;i=i+64|0;e=c;d=a+128|0;Ib(d,e);Fb(d);Hb(d,a,128);Hb(d,e,64);Ib(d,b);lc(a|0,0,336)|0;i=c;return}function sb(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;var f=0,g=0;f=i;i=i+336|0;g=f;qb(g,a,b);Hb(g+128|0,c,d);rb(g,e);i=f;return}function tb(b,d,e,f,g,h){b=b|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;var j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0;r=i;i=i+144|0;o=r+104|0;p=r+40|0;q=r;if((f|0)<0)f=0;else{a[o>>0]=c[d+36>>2]&1|2;n=o+1|0;Ga(d,n);Ea(o+33|0,f);f=b+108|0;j=p+32|0;while(1){sb(e,32,o,37,p);Fa(p,q);if(Ja(q,f)|0?(kb(b,q,g),ab(b,d,g),(bb(g)|0)==0):0)break;a[o>>0]=1;k=n;l=j;m=k+32|0;do{a[k>>0]=a[l>>0]|0;k=k+1|0;l=l+1|0}while((k|0)<(m|0))}if(h|0){k=h;l=j;m=k+32|0;do{a[k>>0]=a[l>>0]|0;k=k+1|0;l=l+1|0}while((k|0)<(m|0))}k=o;m=k+37|0;do{a[k>>0]=0;k=k+1|0}while((k|0)<(m|0));k=p;m=k+64|0;do{a[k>>0]=0;k=k+1|0}while((k|0)<(m|0));k=q;m=k+36|0;do{c[k>>2]=0;k=k+4|0}while((k|0)<(m|0));f=1}i=r;return f|0}function ub(b,d,e,f,g,h,j){b=b|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;j=j|0;var k=0,l=0,m=0,n=0,o=0;n=i;i=i+192|0;l=n+152|0;o=n;m=n+120|0;k=n+72|0;tb(712,b,d,e,o,0)|0;a[l>>0]=c[o+36>>2]&1|2;Ga(o,l+1|0);if(j){b=Lb(f)|0;a[m>>0]=0;a[m+1>>0]=20;ob(l,m+2|0);Eb(m,22,k);Mb(f,m);Ab(k,32,m+b|0);b=(wb(m,b+20|0,g,54)|0)!=0&1}else{pb(l,f,g,h);b=1}i=n;return b|0}function vb(b,e,f,g){b=b|0;e=e|0;f=f|0;g=g|0;var h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0;q=i;a:do if((g|0)>0){h=0;do{if(a[f+h>>0]|0)break a;h=h+1|0}while((h|0)<(g|0))}else h=0;while(0);o=(((g-h|0)*138|0)>>>0)/100|0;n=o+1|0;p=i;i=i+((1*n|0)+15&-16)|0;lc(p|0,0,n|0)|0;if((h|0)<(g|0)){j=o;m=h;do{k=a[f+m>>0]|0;if((o|0)>(j|0)|k<<24>>24!=0){k=k&255;l=o;while(1){r=p+l|0;k=(d[r>>0]<<8)+k|0;a[r>>0]=(k|0)%58|0;l=l+-1|0;if((l|0)>(j|0)|(k+57|0)>>>0>114)k=(k|0)/58|0;else{j=l;break}}}else j=o;m=m+1|0}while((m|0)!=(g|0));j=0}else j=0;while(1){if(a[p+j>>0]|0)break;k=j+1|0;if((j|0)<(o|0))j=k;else{j=k;break}}k=n+h-j|0;if((c[e>>2]|0)>>>0>k>>>0){if(!h)h=0;else lc(b|0,49,h|0)|0;if((j|0)<=(o|0))while(1){a[b+h>>0]=a[38674+(d[p+j>>0]|0)>>0]|0;h=h+1|0;if((j|0)<(o|0))j=j+1|0;else break}a[b+h>>0]=0;j=1}else{j=0;h=k}c[e>>2]=h+1;i=q;return j|0}function wb(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,j=0,k=0,l=0;g=i;i=i+16|0;f=g;if((b|0)>128)a=0;else{j=b+32|0;h=ia()|0;k=i;i=i+((1*j|0)+15&-16)|0;l=k+b|0;tc(k|0,a|0,b|0)|0;Eb(a,b,l);Eb(l,32,l);c[f>>2]=e;a=vb(d,f,k,b+4|0)|0;lc(k|0,0,j|0)|0;a=a?c[f>>2]|0:0;oa(h|0)}i=g;return a|0}function xb(a,b){a=a|0;b=b|0;var e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0;s=(d[b+1>>0]|0)<<8|(d[b>>0]|0)|(d[b+2>>0]|0)<<16|(d[b+3>>0]|0)<<24;D=(d[b+5>>0]|0)<<8|(d[b+4>>0]|0)|(d[b+6>>0]|0)<<16|(d[b+7>>0]|0)<<24;v=(d[b+9>>0]|0)<<8|(d[b+8>>0]|0)|(d[b+10>>0]|0)<<16|(d[b+11>>0]|0)<<24;f=(d[b+13>>0]|0)<<8|(d[b+12>>0]|0)|(d[b+14>>0]|0)<<16|(d[b+15>>0]|0)<<24;x=(d[b+17>>0]|0)<<8|(d[b+16>>0]|0)|(d[b+18>>0]|0)<<16|(d[b+19>>0]|0)<<24;t=(d[b+21>>0]|0)<<8|(d[b+20>>0]|0)|(d[b+22>>0]|0)<<16|(d[b+23>>0]|0)<<24;y=(d[b+25>>0]|0)<<8|(d[b+24>>0]|0)|(d[b+26>>0]|0)<<16|(d[b+27>>0]|0)<<24;z=(d[b+29>>0]|0)<<8|(d[b+28>>0]|0)|(d[b+30>>0]|0)<<16|(d[b+31>>0]|0)<<24;B=(d[b+33>>0]|0)<<8|(d[b+32>>0]|0)|(d[b+34>>0]|0)<<16|(d[b+35>>0]|0)<<24;i=(d[b+37>>0]|0)<<8|(d[b+36>>0]|0)|(d[b+38>>0]|0)<<16|(d[b+39>>0]|0)<<24;F=(d[b+41>>0]|0)<<8|(d[b+40>>0]|0)|(d[b+42>>0]|0)<<16|(d[b+43>>0]|0)<<24;l=(d[b+45>>0]|0)<<8|(d[b+44>>0]|0)|(d[b+46>>0]|0)<<16|(d[b+47>>0]|0)<<24;H=(d[b+49>>0]|0)<<8|(d[b+48>>0]|0)|(d[b+50>>0]|0)<<16|(d[b+51>>0]|0)<<24;u=(d[b+53>>0]|0)<<8|(d[b+52>>0]|0)|(d[b+54>>0]|0)<<16|(d[b+55>>0]|0)<<24;m=(d[b+57>>0]|0)<<8|(d[b+56>>0]|0)|(d[b+58>>0]|0)<<16|(d[b+59>>0]|0)<<24;w=(d[b+61>>0]|0)<<8|(d[b+60>>0]|0)|(d[b+62>>0]|0)<<16|(d[b+63>>0]|0)<<24;b=a+8|0;A=c[b>>2]|0;p=a+12|0;e=c[p>>2]|0;n=a+16|0;r=c[n>>2]|0;k=a+20|0;I=c[k>>2]|0;g=a+24|0;E=c[g>>2]|0;j=A+s+(r^e^I)|0;j=(j<<11|j>>>21)+E|0;C=r<<10|r>>>22;A=t+1352829926+A+((r|~I)^e)|0;A=(A<<8|A>>>24)+E|0;o=E+D+(C^e^j)|0;o=(o<<14|o>>>18)+I|0;G=e<<10|e>>>22;E=m+1352829926+E+(A^(e|~C))|0;E=(E<<9|E>>>23)+I|0;J=I+v+(j^G^o)|0;J=(J<<15|J>>>17)+C|0;j=j<<10|j>>>22;I=z+1352829926+I+(E^(A|~G))|0;I=(I<<9|I>>>23)+C|0;A=A<<10|A>>>22;a=C+f+(o^j^J)|0;a=(a<<12|a>>>20)+G|0;o=o<<10|o>>>22;C=s+1352829926+C+(I^(E|~A))|0;C=(C<<11|C>>>21)+G|0;E=E<<10|E>>>22;h=G+x+(J^o^a)|0;h=(h<<5|h>>>27)+j|0;J=J<<10|J>>>22;G=i+1352829926+G+(C^(I|~E))|0;G=(G<<13|G>>>19)+A|0;I=I<<10|I>>>22;j=j+t+(a^J^h)|0;j=(j<<8|j>>>24)+o|0;a=a<<10|a>>>22;A=v+1352829926+A+(G^(C|~I))|0;A=(A<<15|A>>>17)+E|0;C=C<<10|C>>>22;o=o+y+(h^a^j)|0;o=(o<<7|o>>>25)+J|0;h=h<<10|h>>>22;E=l+1352829926+E+(A^(G|~C))|0;E=(E<<15|E>>>17)+I|0;G=G<<10|G>>>22;J=J+z+(j^h^o)|0;J=(J<<9|J>>>23)+a|0;j=j<<10|j>>>22;I=x+1352829926+I+(E^(A|~G))|0;I=(I<<5|I>>>27)+C|0;A=A<<10|A>>>22;a=a+B+(o^j^J)|0;a=(a<<11|a>>>21)+h|0;o=o<<10|o>>>22;C=u+1352829926+C+(I^(E|~A))|0;C=(C<<7|C>>>25)+G|0;E=E<<10|E>>>22;h=h+i+(J^o^a)|0;h=(h<<13|h>>>19)+j|0;J=J<<10|J>>>22;G=y+1352829926+G+(C^(I|~E))|0;G=(G<<7|G>>>25)+A|0;I=I<<10|I>>>22;j=j+F+(a^J^h)|0;j=(j<<14|j>>>18)+o|0;a=a<<10|a>>>22;A=w+1352829926+A+(G^(C|~I))|0;A=(A<<8|A>>>24)+E|0;C=C<<10|C>>>22;o=o+l+(h^a^j)|0;o=(o<<15|o>>>17)+J|0;h=h<<10|h>>>22;E=B+1352829926+E+(A^(G|~C))|0;E=(E<<11|E>>>21)+I|0;G=G<<10|G>>>22;J=J+H+(j^h^o)|0;J=(J<<6|J>>>26)+a|0;j=j<<10|j>>>22;I=D+1352829926+I+(E^(A|~G))|0;I=(I<<14|I>>>18)+C|0;A=A<<10|A>>>22;a=a+u+(o^j^J)|0;a=(a<<7|a>>>25)+h|0;o=o<<10|o>>>22;C=F+1352829926+C+(I^(E|~A))|0;C=(C<<14|C>>>18)+G|0;E=E<<10|E>>>22;h=h+m+(J^o^a)|0;h=(h<<9|h>>>23)+j|0;J=J<<10|J>>>22;G=f+1352829926+G+(C^(I|~E))|0;G=(G<<12|G>>>20)+A|0;I=I<<10|I>>>22;j=j+w+(a^J^h)|0;j=(j<<8|j>>>24)+o|0;a=a<<10|a>>>22;A=H+1352829926+A+(G^(C|~I))|0;A=(A<<6|A>>>26)+E|0;C=C<<10|C>>>22;o=z+1518500249+o+(j&h|a&~j)|0;o=(o<<7|o>>>25)+J|0;h=h<<10|h>>>22;E=y+1548603684+E+(A&C|G&~C)|0;E=(E<<9|E>>>23)+I|0;G=G<<10|G>>>22;J=x+1518500249+J+(o&j|h&~o)|0;J=(J<<6|J>>>26)+a|0;j=j<<10|j>>>22;I=l+1548603684+I+(E&G|A&~G)|0;I=(I<<13|I>>>19)+C|0;A=A<<10|A>>>22;a=u+1518500249+a+(J&o|j&~J)|0;a=(a<<8|a>>>24)+h|0;o=o<<10|o>>>22;C=f+1548603684+C+(I&A|E&~A)|0;C=(C<<15|C>>>17)+G|0;E=E<<10|E>>>22;h=D+1518500249+h+(a&J|o&~a)|0;h=(h<<13|h>>>19)+j|0;J=J<<10|J>>>22;G=z+1548603684+G+(C&E|I&~E)|0;G=(G<<7|G>>>25)+A|0;I=I<<10|I>>>22;j=F+1518500249+j+(h&a|J&~h)|0;j=(j<<11|j>>>21)+o|0;a=a<<10|a>>>22;A=s+1548603684+A+(G&I|C&~I)|0;A=(A<<12|A>>>20)+E|0;C=C<<10|C>>>22;o=y+1518500249+o+(j&h|a&~j)|0;o=(o<<9|o>>>23)+J|0;h=h<<10|h>>>22;E=u+1548603684+E+(A&C|G&~C)|0;E=(E<<8|E>>>24)+I|0;G=G<<10|G>>>22;J=w+1518500249+J+(o&j|h&~o)|0;J=(J<<7|J>>>25)+a|0;j=j<<10|j>>>22;I=t+1548603684+I+(E&G|A&~G)|0;I=(I<<9|I>>>23)+C|0;A=A<<10|A>>>22;a=f+1518500249+a+(J&o|j&~J)|0;a=(a<<15|a>>>17)+h|0;o=o<<10|o>>>22;C=F+1548603684+C+(I&A|E&~A)|0;C=(C<<11|C>>>21)+G|0;E=E<<10|E>>>22;h=H+1518500249+h+(a&J|o&~a)|0;h=(h<<7|h>>>25)+j|0;J=J<<10|J>>>22;G=m+1548603684+G+(C&E|I&~E)|0;G=(G<<7|G>>>25)+A|0;I=I<<10|I>>>22;j=s+1518500249+j+(h&a|J&~h)|0;j=(j<<12|j>>>20)+o|0;a=a<<10|a>>>22;A=w+1548603684+A+(G&I|C&~I)|0;A=(A<<7|A>>>25)+E|0;C=C<<10|C>>>22;o=i+1518500249+o+(j&h|a&~j)|0;o=(o<<15|o>>>17)+J|0;h=h<<10|h>>>22;E=B+1548603684+E+(A&C|G&~C)|0;E=(E<<12|E>>>20)+I|0;G=G<<10|G>>>22;J=t+1518500249+J+(o&j|h&~o)|0;J=(J<<9|J>>>23)+a|0;j=j<<10|j>>>22;I=H+1548603684+I+(E&G|A&~G)|0;I=(I<<7|I>>>25)+C|0;A=A<<10|A>>>22;a=v+1518500249+a+(J&o|j&~J)|0;a=(a<<11|a>>>21)+h|0;o=o<<10|o>>>22;C=x+1548603684+C+(I&A|E&~A)|0;C=(C<<6|C>>>26)+G|0;E=E<<10|E>>>22;h=m+1518500249+h+(a&J|o&~a)|0;h=(h<<7|h>>>25)+j|0;J=J<<10|J>>>22;G=i+1548603684+G+(C&E|I&~E)|0;G=(G<<15|G>>>17)+A|0;I=I<<10|I>>>22;j=l+1518500249+j+(h&a|J&~h)|0;j=(j<<13|j>>>19)+o|0;a=a<<10|a>>>22;A=D+1548603684+A+(G&I|C&~I)|0;A=(A<<13|A>>>19)+E|0;C=C<<10|C>>>22;q=~j;o=B+1518500249+o+(j&h|a&q)|0;o=(o<<12|o>>>20)+J|0;h=h<<10|h>>>22;E=v+1548603684+E+(A&C|G&~C)|0;E=(E<<11|E>>>21)+I|0;G=G<<10|G>>>22;q=f+1859775393+J+((o|q)^h)|0;q=(q<<11|q>>>21)+a|0;j=j<<10|j>>>22;I=w+1836072691+I+((E|~A)^G)|0;I=(I<<9|I>>>23)+C|0;A=A<<10|A>>>22;a=F+1859775393+a+((q|~o)^j)|0;a=(a<<13|a>>>19)+h|0;o=o<<10|o>>>22;C=t+1836072691+C+((I|~E)^A)|0;C=(C<<7|C>>>25)+G|0;E=E<<10|E>>>22;h=m+1859775393+h+((a|~q)^o)|0;h=(h<<6|h>>>26)+j|0;q=q<<10|q>>>22;G=D+1836072691+G+((C|~I)^E)|0;G=(G<<15|G>>>17)+A|0;I=I<<10|I>>>22;j=x+1859775393+j+((h|~a)^q)|0;j=(j<<7|j>>>25)+o|0;a=a<<10|a>>>22;A=f+1836072691+A+((G|~C)^I)|0;A=(A<<11|A>>>21)+E|0;C=C<<10|C>>>22;o=i+1859775393+o+((j|~h)^a)|0;o=(o<<14|o>>>18)+q|0;h=h<<10|h>>>22;E=z+1836072691+E+((A|~G)^C)|0;E=(E<<8|E>>>24)+I|0;G=G<<10|G>>>22;q=w+1859775393+q+((o|~j)^h)|0;q=(q<<9|q>>>23)+a|0;j=j<<10|j>>>22;I=m+1836072691+I+((E|~A)^G)|0;I=(I<<6|I>>>26)+C|0;A=A<<10|A>>>22;a=B+1859775393+a+((q|~o)^j)|0;a=(a<<13|a>>>19)+h|0;o=o<<10|o>>>22;C=y+1836072691+C+((I|~E)^A)|0;C=(C<<6|C>>>26)+G|0;E=E<<10|E>>>22;h=D+1859775393+h+((a|~q)^o)|0;h=(h<<15|h>>>17)+j|0;q=q<<10|q>>>22;G=i+1836072691+G+((C|~I)^E)|0;G=(G<<14|G>>>18)+A|0;I=I<<10|I>>>22;j=v+1859775393+j+((h|~a)^q)|0;j=(j<<14|j>>>18)+o|0;a=a<<10|a>>>22;A=l+1836072691+A+((G|~C)^I)|0;A=(A<<12|A>>>20)+E|0;C=C<<10|C>>>22;o=z+1859775393+o+((j|~h)^a)|0;o=(o<<8|o>>>24)+q|0;h=h<<10|h>>>22;E=B+1836072691+E+((A|~G)^C)|0;E=(E<<13|E>>>19)+I|0;G=G<<10|G>>>22;q=s+1859775393+q+((o|~j)^h)|0;q=(q<<13|q>>>19)+a|0;j=j<<10|j>>>22;I=H+1836072691+I+((E|~A)^G)|0;I=(I<<5|I>>>27)+C|0;A=A<<10|A>>>22;a=y+1859775393+a+((q|~o)^j)|0;a=(a<<6|a>>>26)+h|0;o=o<<10|o>>>22;C=v+1836072691+C+((I|~E)^A)|0;C=(C<<14|C>>>18)+G|0;E=E<<10|E>>>22;h=u+1859775393+h+((a|~q)^o)|0;h=(h<<5|h>>>27)+j|0;q=q<<10|q>>>22;G=F+1836072691+G+((C|~I)^E)|0;G=(G<<13|G>>>19)+A|0;I=I<<10|I>>>22;j=l+1859775393+j+((h|~a)^q)|0;j=(j<<12|j>>>20)+o|0;a=a<<10|a>>>22;A=s+1836072691+A+((G|~C)^I)|0;A=(A<<13|A>>>19)+E|0;C=C<<10|C>>>22;o=t+1859775393+o+((j|~h)^a)|0;o=(o<<7|o>>>25)+q|0;h=h<<10|h>>>22;E=x+1836072691+E+((A|~G)^C)|0;E=(E<<7|E>>>25)+I|0;G=G<<10|G>>>22;q=H+1859775393+q+((o|~j)^h)|0;q=(q<<5|q>>>27)+a|0;j=j<<10|j>>>22;I=u+1836072691+I+((E|~A)^G)|0;I=(I<<5|I>>>27)+C|0;A=A<<10|A>>>22;a=D+-1894007588+a+(q&j|o&~j)|0;a=(a<<11|a>>>21)+h|0;o=o<<10|o>>>22;C=B+2053994217+C+(I&E|A&~I)|0;C=(C<<15|C>>>17)+G|0;E=E<<10|E>>>22;h=i+-1894007588+h+(a&o|q&~o)|0;h=(h<<12|h>>>20)+j|0;q=q<<10|q>>>22;G=y+2053994217+G+(C&I|E&~C)|0;G=(G<<5|G>>>27)+A|0;I=I<<10|I>>>22;j=l+-1894007588+j+(h&q|a&~q)|0;j=(j<<14|j>>>18)+o|0;a=a<<10|a>>>22;A=x+2053994217+A+(G&C|I&~G)|0;A=(A<<8|A>>>24)+E|0;C=C<<10|C>>>22;o=F+-1894007588+o+(j&a|h&~a)|0;o=(o<<15|o>>>17)+q|0;h=h<<10|h>>>22;E=D+2053994217+E+(A&G|C&~A)|0;E=(E<<11|E>>>21)+I|0;G=G<<10|G>>>22;q=s+-1894007588+q+(o&h|j&~h)|0;q=(q<<14|q>>>18)+a|0;j=j<<10|j>>>22;I=f+2053994217+I+(E&A|G&~E)|0;I=(I<<14|I>>>18)+C|0;A=A<<10|A>>>22;a=B+-1894007588+a+(q&j|o&~j)|0;a=(a<<15|a>>>17)+h|0;o=o<<10|o>>>22;C=l+2053994217+C+(I&E|A&~I)|0;C=(C<<14|C>>>18)+G|0;E=E<<10|E>>>22;h=H+-1894007588+h+(a&o|q&~o)|0;h=(h<<9|h>>>23)+j|0;q=q<<10|q>>>22;G=w+2053994217+G+(C&I|E&~C)|0;G=(G<<6|G>>>26)+A|0;I=I<<10|I>>>22;j=x+-1894007588+j+(h&q|a&~q)|0;j=(j<<8|j>>>24)+o|0;a=a<<10|a>>>22;A=s+2053994217+A+(G&C|I&~G)|0;A=(A<<14|A>>>18)+E|0;C=C<<10|C>>>22;o=u+-1894007588+o+(j&a|h&~a)|0;o=(o<<9|o>>>23)+q|0;h=h<<10|h>>>22;E=t+2053994217+E+(A&G|C&~A)|0;E=(E<<6|E>>>26)+I|0;G=G<<10|G>>>22;q=f+-1894007588+q+(o&h|j&~h)|0;q=(q<<14|q>>>18)+a|0;j=j<<10|j>>>22;I=H+2053994217+I+(E&A|G&~E)|0;I=(I<<9|I>>>23)+C|0;A=A<<10|A>>>22;a=z+-1894007588+a+(q&j|o&~j)|0;a=(a<<5|a>>>27)+h|0;o=o<<10|o>>>22;C=v+2053994217+C+(I&E|A&~I)|0;C=(C<<12|C>>>20)+G|0;E=E<<10|E>>>22;h=w+-1894007588+h+(a&o|q&~o)|0;h=(h<<6|h>>>26)+j|0;q=q<<10|q>>>22;G=u+2053994217+G+(C&I|E&~C)|0;G=(G<<9|G>>>23)+A|0;I=I<<10|I>>>22;j=m+-1894007588+j+(h&q|a&~q)|0;j=(j<<8|j>>>24)+o|0;a=a<<10|a>>>22;A=i+2053994217+A+(G&C|I&~G)|0;A=(A<<12|A>>>20)+E|0;C=C<<10|C>>>22;o=t+-1894007588+o+(j&a|h&~a)|0;o=(o<<6|o>>>26)+q|0;h=h<<10|h>>>22;E=z+2053994217+E+(A&G|C&~A)|0;E=(E<<5|E>>>27)+I|0;G=G<<10|G>>>22;q=y+-1894007588+q+(o&h|j&~h)|0;q=(q<<5|q>>>27)+a|0;j=j<<10|j>>>22;I=F+2053994217+I+(E&A|G&~E)|0;I=(I<<15|I>>>17)+C|0;A=A<<10|A>>>22;a=v+-1894007588+a+(q&j|o&~j)|0;a=(a<<12|a>>>20)+h|0;o=o<<10|o>>>22;C=m+2053994217+C+(I&E|A&~I)|0;C=(C<<8|C>>>24)+G|0;E=E<<10|E>>>22;h=x+-1454113458+h+(a^(q|~o))|0;h=(h<<9|h>>>23)+j|0;q=q<<10|q>>>22;G=G+H+(I^E^C)|0;G=(G<<8|G>>>24)+A|0;I=I<<10|I>>>22;j=s+-1454113458+j+(h^(a|~q))|0;j=(j<<15|j>>>17)+o|0;a=a<<10|a>>>22;A=A+w+(C^I^G)|0;A=(A<<5|A>>>27)+E|0;C=C<<10|C>>>22;o=t+-1454113458+o+(j^(h|~a))|0;o=(o<<5|o>>>27)+q|0;h=h<<10|h>>>22;E=E+F+(G^C^A)|0;E=(E<<12|E>>>20)+I|0;G=G<<10|G>>>22;q=i+-1454113458+q+(o^(j|~h))|0;q=(q<<11|q>>>21)+a|0;j=j<<10|j>>>22;x=I+x+(A^G^E)|0;x=(x<<9|x>>>23)+C|0;A=A<<10|A>>>22;a=z+-1454113458+a+(q^(o|~j))|0;a=(a<<6|a>>>26)+h|0;o=o<<10|o>>>22;C=C+D+(E^A^x)|0;C=(C<<12|C>>>20)+G|0;E=E<<10|E>>>22;h=H+-1454113458+h+(a^(q|~o))|0;h=(h<<8|h>>>24)+j|0;q=q<<10|q>>>22;t=G+t+(x^E^C)|0;t=(t<<5|t>>>27)+A|0;x=x<<10|x>>>22;j=v+-1454113458+j+(h^(a|~q))|0;j=(j<<13|j>>>19)+o|0;a=a<<10|a>>>22;A=A+B+(C^x^t)|0;A=(A<<14|A>>>18)+E|0;C=C<<10|C>>>22;o=F+-1454113458+o+(j^(h|~a))|0;o=(o<<12|o>>>20)+q|0;h=h<<10|h>>>22;z=E+z+(t^C^A)|0;z=(z<<6|z>>>26)+x|0;t=t<<10|t>>>22;q=m+-1454113458+q+(o^(j|~h))|0;q=(q<<5|q>>>27)+a|0;j=j<<10|j>>>22;x=x+y+(A^t^z)|0;x=(x<<8|x>>>24)+C|0;A=A<<10|A>>>22;a=D+-1454113458+a+(q^(o|~j))|0;a=(a<<12|a>>>20)+h|0;o=o<<10|o>>>22;v=C+v+(z^A^x)|0;v=(v<<13|v>>>19)+t|0;z=z<<10|z>>>22;h=f+-1454113458+h+(a^(q|~o))|0;h=(h<<13|h>>>19)+j|0;q=q<<10|q>>>22;t=t+u+(x^z^v)|0;t=(t<<6|t>>>26)+A|0;x=x<<10|x>>>22;j=B+-1454113458+j+(h^(a|~q))|0;j=(j<<14|j>>>18)+o|0;a=a<<10|a>>>22;m=A+m+(v^x^t)|0;m=(m<<5|m>>>27)+z|0;v=v<<10|v>>>22;o=l+-1454113458+o+(j^(h|~a))|0;o=(o<<11|o>>>21)+q|0;h=h<<10|h>>>22;s=z+s+(t^v^m)|0;s=(s<<15|s>>>17)+x|0;t=t<<10|t>>>22;q=y+-1454113458+q+(o^(j|~h))|0;q=(q<<8|q>>>24)+a|0;j=j<<10|j>>>22;f=x+f+(m^t^s)|0;f=(f<<13|f>>>19)+v|0;m=m<<10|m>>>22;a=w+-1454113458+a+(q^(o|~j))|0;a=(a<<5|a>>>27)+h|0;o=o<<10|o>>>22;i=v+i+(s^m^f)|0;i=(i<<11|i>>>21)+t|0;s=s<<10|s>>>22;h=u+-1454113458+h+(a^(q|~o))|0;l=t+l+(f^s^i)|0;c[p>>2]=s+r+(q<<10|q>>>22);c[n>>2]=m+(c[k>>2]|0)+o;c[k>>2]=j+(c[g>>2]|0)+m+(l<<11|l>>>21);c[g>>2]=j+(c[b>>2]|0)+i+(h<<6|h>>>26);c[b>>2]=(f<<10|f>>>22)+e+a;return}function yb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0;if(d|0){h=c[a>>2]|0;e=h&63;f=64-e|0;h=h+d|0;c[a>>2]=h;if(h>>>0>>0){h=a+4|0;c[h>>2]=(c[h>>2]|0)+1}if(!((e|0)==0|f>>>0>d>>>0)){tc(a+28+e|0,b|0,f|0)|0;xb(a,a+28|0);e=0;b=b+f|0;d=d-f|0}if(d>>>0>63){g=d+-64|0;h=g&-64;f=b+(h+64)|0;while(1){xb(a,b);d=d+-64|0;if(d>>>0<=63)break;else b=b+64|0}b=f;d=g-h|0}if(d|0)tc(a+28+e|0,b|0,d|0)|0}return}function zb(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0;e=i;i=i+16|0;f=e;g=c[b>>2]|0;h=c[b+4>>2]|0;a[f>>0]=g<<3;a[f+1>>0]=g>>>5;a[f+2>>0]=g>>>13;a[f+3>>0]=g>>>21;a[f+4>>0]=h<<3|g>>>29;a[f+5>>0]=h>>>5;a[f+6>>0]=h>>>13;a[f+7>>0]=h>>>21;g=g&63;yb(b,38733,(g>>>0<56?56:120)-g|0);yb(b,f,8);f=b+8|0;a[d>>0]=c[f>>2];a[d+1>>0]=(c[f>>2]|0)>>>8;a[d+2>>0]=(c[f>>2]|0)>>>16;a[d+3>>0]=(c[f>>2]|0)>>>24;f=b+12|0;a[d+4>>0]=c[f>>2];a[d+5>>0]=(c[f>>2]|0)>>>8;a[d+6>>0]=(c[f>>2]|0)>>>16;a[d+7>>0]=(c[f>>2]|0)>>>24;f=b+16|0;a[d+8>>0]=c[f>>2];a[d+9>>0]=(c[f>>2]|0)>>>8;a[d+10>>0]=(c[f>>2]|0)>>>16;a[d+11>>0]=(c[f>>2]|0)>>>24;f=b+20|0;a[d+12>>0]=c[f>>2];a[d+13>>0]=(c[f>>2]|0)>>>8;a[d+14>>0]=(c[f>>2]|0)>>>16;a[d+15>>0]=(c[f>>2]|0)>>>24;b=b+24|0;a[d+16>>0]=c[b>>2];a[d+17>>0]=(c[b>>2]|0)>>>8;a[d+18>>0]=(c[b>>2]|0)>>>16;a[d+19>>0]=(c[b>>2]|0)>>>24;i=e;return}function Ab(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0;h=i;i=i+96|0;e=h;f=e+8|0;g=e;j=g+92|0;do{c[g>>2]=0;g=g+4|0}while((g|0)<(j|0));c[f>>2]=1732584193;c[e+12>>2]=-271733879;c[e+16>>2]=-1732584194;c[e+20>>2]=271733878;c[e+24>>2]=-1009589776;yb(e,a,b);zb(e,d);i=h;return}function Bb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0;y=i;i=i+64|0;t=y;u=c[a>>2]|0;v=a+4|0;w=a+8|0;x=a+12|0;q=a+16|0;r=a+20|0;s=a+24|0;p=a+28|0;g=0;o=u;a=c[p>>2]|0;h=c[s>>2]|0;j=c[r>>2]|0;k=c[q>>2]|0;e=c[x>>2]|0;l=c[w>>2]|0;f=c[v>>2]|0;while(1){n=((k>>>6|k<<26)^(k>>>11|k<<21)^(k>>>25|k<<7))+a+(h&~k^j&k)+(c[37828+(g<<2)>>2]|0)|0;a=c[b>>2]|0;c[t+(g<<2)>>2]=a;a=n+a|0;e=a+e|0;a=((o>>>2|o<<30)^(o>>>13|o<<19)^(o>>>22|o<<10))+(o&(l^f)^l&f)+a|0;g=g+1|0;if((g|0)==16){n=16;m=a;g=e;a=l;e=o;break}else{C=o;B=f;A=l;z=k;m=j;n=h;b=b+4|0;o=a;k=e;f=C;l=B;e=A;j=z;h=m;a=n}}while(1){A=n;n=n+1|0;z=c[t+((n&15)<<2)>>2]|0;b=c[t+((A+14&15)<<2)>>2]|0;C=((g>>>6|g<<26)^(g>>>11|g<<21)^(g>>>25|g<<7))+h+(j&~g^k&g)+(c[37828+(A<<2)>>2]|0)|0;B=t+((A&15)<<2)|0;b=((z>>>18|z<<14)^z>>>3^(z>>>7|z<<25))+(c[t+((A+9&15)<<2)>>2]|0)+(c[B>>2]|0)+((b>>>19|b<<13)^b>>>10^(b>>>17|b<<15))|0;c[B>>2]=b;b=C+b|0;a=b+a|0;b=((m>>>2|m<<30)^(m>>>13|m<<19)^(m>>>22|m<<10))+(m&(f^e)^f&e)+b|0;if((n|0)==64)break;else{o=m;z=e;A=f;B=g;C=k;h=j;m=b;g=a;e=o;f=z;a=A;k=B;j=C}}c[d>>2]=u+b;c[d+4>>2]=(c[v>>2]|0)+m;c[d+8>>2]=(c[w>>2]|0)+e;c[d+12>>2]=(c[x>>2]|0)+f;c[d+16>>2]=(c[q>>2]|0)+a;c[d+20>>2]=(c[r>>2]|0)+g;c[d+24>>2]=(c[s>>2]|0)+k;c[d+28>>2]=(c[p>>2]|0)+j;i=y;return}function Cb(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0;do if(e|0){n=b+32|0;g=n;h=c[g>>2]|0;g=c[g+4>>2]|0;f=mc(h|0,g|0,3)|0;f=f&63;if(f){i=64-f|0;j=b+40|0;f=j+f|0;if(i>>>0>e>>>0){tc(f|0,d|0,e|0)|0;b=qc(h|0,g|0,e<<3|0,0)|0;c[n>>2]=b;c[n+4>>2]=C;break}tc(f|0,d|0,i|0)|0;m=qc(h|0,g|0,i<<3|0,0)|0;f=n;c[f>>2]=m;c[f+4>>2]=C;e=e-i|0;f=0;do{m=b+40+(f<<2)|0;c[m>>2]=sc(c[m>>2]|0)|0;f=f+1|0}while((f|0)!=16);Bb(b,j,b);d=d+i|0}if(e>>>0>63){j=b+40|0;l=e+-64|0;m=l&-64;k=m+64|0;i=d;while(1){f=j;g=i;h=f+64|0;do{a[f>>0]=a[g>>0]|0;f=f+1|0;g=g+1|0}while((f|0)<(h|0));f=0;do{h=b+40+(f<<2)|0;c[h>>2]=sc(c[h>>2]|0)|0;f=f+1|0}while((f|0)!=16);Bb(b,j,b);g=n;g=qc(c[g>>2]|0,c[g+4>>2]|0,512,0)|0;h=n;c[h>>2]=g;c[h+4>>2]=C;e=e+-64|0;if(e>>>0<=63)break;else i=i+64|0}d=d+k|0;e=l-m|0}if(e|0){tc(b+40|0,d|0,e|0)|0;b=n;b=qc(c[b>>2]|0,c[b+4>>2]|0,e<<3|0,0)|0;c[n>>2]=b;c[n+4>>2]=C}}while(0);return}function Db(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0;if(d){h=b+32|0;f=h;f=mc(c[f>>2]|0,c[f+4>>2]|0,3)|0;f=f&63;e=f+1|0;g=b+40|0;a[g+f>>0]=-128;if(e>>>0>56){lc(g+e|0,0,f^63|0)|0;e=0;do{f=b+40+(e<<2)|0;c[f>>2]=sc(c[f>>2]|0)|0;e=e+1|0}while((e|0)!=16);Bb(b,g,b);e=0}lc(g+e|0,0,56-e|0)|0;e=0;do{f=b+40+(e<<2)|0;c[f>>2]=sc(c[f>>2]|0)|0;e=e+1|0}while((e|0)!=14);e=c[h>>2]|0;c[b+96>>2]=c[h+4>>2];c[b+100>>2]=e;Bb(b,g,b);e=0;do{h=b+(e<<2)|0;c[h>>2]=sc(c[h>>2]|0)|0;e=e+1|0}while((e|0)!=8);e=d;f=b;g=e+32|0;do{a[e>>0]=a[f>>0]|0;e=e+1|0;f=f+1|0}while((e|0)<(g|0))}e=b;g=e+104|0;do{c[e>>2]=0;e=e+4|0}while((e|0)<(g|0));return}function Eb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0;g=i;i=i+112|0;e=g;c[e>>2]=c[9449];c[e+4>>2]=c[9450];c[e+8>>2]=c[9451];c[e+12>>2]=c[9452];c[e+16>>2]=c[9453];c[e+20>>2]=c[9454];c[e+24>>2]=c[9455];c[e+28>>2]=c[9456];f=e+32|0;h=f+72|0;do{c[f>>2]=0;f=f+4|0}while((f|0)<(h|0));Cb(e,a,b);Db(e,d);i=g;return}function Fb(a){a=a|0;var b=0,d=0,e=0;if(a|0){b=a;d=8;e=b+64|0;do{c[b>>2]=c[d>>2];b=b+4|0;d=d+4|0}while((b|0)<(e|0));lc(a+64|0,0,144)|0}return}function Gb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0,X=0,Y=0,Z=0,_=0;L=i;i=i+128|0;F=L;K=a;J=c[K>>2]|0;K=c[K+4>>2]|0;B=a+8|0;w=B;D=a+16|0;e=D;E=a+24|0;f=E;G=a+32|0;p=G;H=a+40|0;q=H;I=a+48|0;m=I;A=a+56|0;h=A;j=0;l=J;u=K;t=c[w>>2]|0;z=c[e>>2]|0;w=c[w+4>>2]|0;a=c[e+4>>2]|0;e=c[f>>2]|0;f=c[f+4>>2]|0;o=c[p>>2]|0;p=c[p+4>>2]|0;g=c[h>>2]|0;h=c[h+4>>2]|0;r=c[q>>2]|0;q=c[q+4>>2]|0;k=c[m>>2]|0;m=c[m+4>>2]|0;while(1){v=mc(o|0,p|0,14)|0;N=C;x=nc(o|0,p|0,50)|0;N=N|C;y=mc(o|0,p|0,18)|0;O=C;M=nc(o|0,p|0,46)|0;O=N^(O|C);N=mc(o|0,p|0,41)|0;n=C;s=nc(o|0,p|0,23)|0;n=qc((v|x)^(y|M)^(N|s)|0,O^(n|C)|0,g|0,h|0)|0;n=qc(n|0,C|0,k&~o^r&o|0,m&~p^q&p|0)|0;O=72+(j<<3)|0;O=qc(n|0,C|0,c[O>>2]|0,c[O+4>>2]|0)|0;n=b;g=c[n>>2]|0;n=c[n+4>>2]|0;s=F+(j<<3)|0;c[s>>2]=g;c[s+4>>2]=n;n=qc(O|0,C|0,g|0,n|0)|0;g=C;O=mc(l|0,u|0,28)|0;s=C;N=nc(l|0,u|0,36)|0;s=s|C;M=mc(l|0,u|0,34)|0;y=C;h=nc(l|0,u|0,30)|0;y=s^(y|C);s=mc(l|0,u|0,39)|0;x=C;v=nc(l|0,u|0,25)|0;x=qc((O|N)^(M|h)^(s|v)|0,y^(x|C)|0,l&(z^t)^z&t|0,u&(a^w)^a&w|0)|0;y=C;e=qc(n|0,g|0,e|0,f|0)|0;f=C;g=qc(x|0,y|0,n|0,g|0)|0;n=C;j=j+1|0;if((j|0)==16){y=16;x=e;v=f;s=p;p=g;j=t;h=u;g=w;b=z;break}else{x=p;y=o;h=m;M=k;N=u;O=l;b=b+8|0;l=g;u=n;o=e;p=f;m=q;k=r;q=x;r=y;g=M;f=a;e=z;a=w;w=N;z=t;t=O}}while(1){t=y;y=y+1|0;T=F+((y&15)<<3)|0;W=c[T>>2]|0;T=c[T+4>>2]|0;S=mc(W|0,T|0,1)|0;Q=C;R=nc(W|0,T|0,63)|0;Q=Q|C;V=mc(W|0,T|0,8)|0;O=C;U=nc(W|0,T|0,56)|0;O=O|C;T=mc(W|0,T|0,7)|0;Q=O^C^Q;O=F+((t+14&15)<<3)|0;W=c[O>>2]|0;O=c[O+4>>2]|0;u=mc(W|0,O|0,19)|0;e=C;f=nc(W|0,O|0,45)|0;e=e|C;N=mc(W|0,O|0,61)|0;_=C;w=nc(W|0,O|0,3)|0;_=_|C;O=mc(W|0,O|0,6)|0;e=_^C^e;_=mc(x|0,v|0,14)|0;W=C;Z=nc(x|0,v|0,50)|0;W=W|C;Y=mc(x|0,v|0,18)|0;P=C;X=nc(x|0,v|0,46)|0;P=W^(P|C);W=mc(x|0,v|0,41)|0;z=C;M=nc(x|0,v|0,23)|0;m=qc((_|Z)^(Y|X)^(W|M)|0,P^(z|C)|0,k|0,m|0)|0;m=qc(m|0,C|0,r&~x^o&x|0,q&~v^s&v|0)|0;z=72+(t<<3)|0;z=qc(m|0,C|0,c[z>>2]|0,c[z+4>>2]|0)|0;m=C;P=F+((t+9&15)<<3)|0;t=F+((t&15)<<3)|0;M=t;k=c[M>>2]|0;M=c[M+4>>2]|0;P=qc((V|U)^T^(S|R)|0,Q|0,c[P>>2]|0,c[P+4>>2]|0)|0;M=qc(P|0,C|0,k|0,M|0)|0;e=qc(M|0,C|0,(N|w)^O^(u|f)|0,e|0)|0;f=C;c[t>>2]=e;c[t+4>>2]=f;f=qc(z|0,m|0,e|0,f|0)|0;e=C;m=mc(p|0,n|0,28)|0;z=C;t=nc(p|0,n|0,36)|0;z=z|C;u=mc(p|0,n|0,34)|0;O=C;w=nc(p|0,n|0,30)|0;O=z^(O|C);z=mc(p|0,n|0,39)|0;N=C;M=nc(p|0,n|0,25)|0;N=qc((m|t)^(u|w)^(z|M)|0,O^(N|C)|0,p&(j^l)^j&l|0,n&(g^h)^g&h|0)|0;O=C;a=qc(f|0,e|0,b|0,a|0)|0;b=C;e=qc(N|0,O|0,f|0,e|0)|0;f=C;if((y|0)==80)break;else{X=n;Y=p;Z=v;_=x;m=q;k=r;x=a;v=b;p=e;n=f;a=g;b=j;g=h;h=X;j=l;l=Y;q=s;r=o;s=Z;o=_}}_=qc(J|0,K|0,e|0,f|0)|0;Z=d;c[Z>>2]=_;c[Z+4>>2]=C;Z=B;Z=qc(c[Z>>2]|0,c[Z+4>>2]|0,p|0,n|0)|0;_=d+8|0;c[_>>2]=Z;c[_+4>>2]=C;_=D;_=qc(c[_>>2]|0,c[_+4>>2]|0,l|0,h|0)|0;Z=d+16|0;c[Z>>2]=_;c[Z+4>>2]=C;Z=E;Z=qc(c[Z>>2]|0,c[Z+4>>2]|0,j|0,g|0)|0;_=d+24|0;c[_>>2]=Z;c[_+4>>2]=C;_=G;_=qc(c[_>>2]|0,c[_+4>>2]|0,a|0,b|0)|0;Z=d+32|0;c[Z>>2]=_;c[Z+4>>2]=C;Z=H;Z=qc(c[Z>>2]|0,c[Z+4>>2]|0,x|0,v|0)|0;_=d+40|0;c[_>>2]=Z;c[_+4>>2]=C;_=I;_=qc(c[_>>2]|0,c[_+4>>2]|0,o|0,s|0)|0;Z=d+48|0;c[Z>>2]=_;c[Z+4>>2]=C;Z=A;Z=qc(c[Z>>2]|0,c[Z+4>>2]|0,r|0,q|0)|0;_=d+56|0;c[_>>2]=Z;c[_+4>>2]=C;i=L;return}function Hb(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0;do if(e|0){o=b+64|0;g=o;h=c[g>>2]|0;g=c[g+4>>2]|0;f=mc(h|0,g|0,3)|0;f=f&127;if(f){i=128-f|0;j=b+80|0;f=j+f|0;if(i>>>0>e>>>0){tc(f|0,d|0,e|0)|0;n=e<<3;m=qc(h|0,g|0,n|0,0)|0;l=C;c[o>>2]=m;c[o+4>>2]=l;if(!(l>>>0<0|(l|0)==0&m>>>0>>0))break;o=b+72|0;b=o;b=qc(c[b>>2]|0,c[b+4>>2]|0,1,0)|0;c[o>>2]=b;c[o+4>>2]=C;break}tc(f|0,d|0,i|0)|0;n=i<<3;m=qc(h|0,g|0,n|0,0)|0;l=C;k=o;c[k>>2]=m;c[k+4>>2]=l;if(l>>>0<0|(l|0)==0&m>>>0>>0){n=b+72|0;m=n;m=qc(c[m>>2]|0,c[m+4>>2]|0,1,0)|0;c[n>>2]=m;c[n+4>>2]=C}e=e-i|0;f=0;do{n=b+80+(f<<3)|0;m=n;m=ma(c[m>>2]|0,c[m+4>>2]|0)|0;c[n>>2]=m;c[n+4>>2]=C;f=f+1|0}while((f|0)!=16);Gb(b,j,b);d=d+i|0}if(e>>>0>127){j=b+80|0;k=b+72|0;m=e+-128|0;n=m&-128;l=n+128|0;i=d;while(1){f=j;g=i;h=f+128|0;do{a[f>>0]=a[g>>0]|0;f=f+1|0;g=g+1|0}while((f|0)<(h|0));f=0;do{h=b+80+(f<<3)|0;g=h;g=ma(c[g>>2]|0,c[g+4>>2]|0)|0;c[h>>2]=g;c[h+4>>2]=C;f=f+1|0}while((f|0)!=16);Gb(b,j,b);g=o;h=c[g>>2]|0;g=c[g+4>>2]|0;p=qc(h|0,g|0,1024,0)|0;f=o;c[f>>2]=p;c[f+4>>2]=C;if(g>>>0>4294967295|(g|0)==-1&h>>>0>4294966271){h=k;h=qc(c[h>>2]|0,c[h+4>>2]|0,1,0)|0;p=k;c[p>>2]=h;c[p+4>>2]=C}e=e+-128|0;if(e>>>0<=127)break;else i=i+128|0}d=d+l|0;e=m-n|0}if(e|0?(tc(b+80|0,d|0,e|0)|0,p=e<<3,n=o,n=qc(c[n>>2]|0,c[n+4>>2]|0,p|0,0)|0,m=C,o,c[o>>2]=n,c[o+4>>2]=m,m>>>0<0|(m|0)==0&n>>>0

>>0):0){p=b+72|0;o=p;o=qc(c[o>>2]|0,c[o+4>>2]|0,1,0)|0;c[p>>2]=o;c[p+4>>2]=C}}while(0);return}function Ib(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0;if(d){h=b+64|0;f=h;f=mc(c[f>>2]|0,c[f+4>>2]|0,3)|0;f=f&127;e=f+1|0;g=b+80|0;a[g+f>>0]=-128;if(e>>>0>112){lc(g+e|0,0,f^127|0)|0;e=0;do{f=b+80+(e<<3)|0;i=f;i=ma(c[i>>2]|0,c[i+4>>2]|0)|0;c[f>>2]=i;c[f+4>>2]=C;e=e+1|0}while((e|0)!=16);Gb(b,g,b);e=0}lc(g+e|0,0,112-e|0)|0;e=0;do{i=b+80+(e<<3)|0;f=i;f=ma(c[f>>2]|0,c[f+4>>2]|0)|0;c[i>>2]=f;c[i+4>>2]=C;e=e+1|0}while((e|0)!=14);f=b+72|0;e=c[f+4>>2]|0;i=b+192|0;c[i>>2]=c[f>>2];c[i+4>>2]=e;i=c[h+4>>2]|0;e=b+200|0;c[e>>2]=c[h>>2];c[e+4>>2]=i;Gb(b,g,b);e=0;do{i=b+(e<<3)|0;h=i;h=ma(c[h>>2]|0,c[h+4>>2]|0)|0;c[i>>2]=h;c[i+4>>2]=C;e=e+1|0}while((e|0)!=8);e=d;f=b;g=e+64|0;do{a[e>>0]=a[f>>0]|0;e=e+1|0;f=f+1|0}while((e|0)<(g|0))}lc(b|0,0,208)|0;return}function Jb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0;g=i;i=i+208|0;e=g;f=e;h=8;j=f+64|0;do{c[f>>2]=c[h>>2];f=f+4|0;h=h+4|0}while((f|0)<(j|0));lc(e+64|0,0,144)|0;Hb(e,a,b);Ib(e,d);i=g;return}function Kb(){var a=0,b=0,d=0;d=i;i=i+16|0;b=d;a=c[9714]|0;if(!a){a=bc(38797,38810)|0;c[9714]=a}if((gc(b,1,4,a)|0)==4){i=d;return c[b>>2]|0}else pa(38812,38828,60,38838);return 0}function Lb(a){a=a|0;if(a>>>0>=256)if(a>>>0<65536)a=2;else a=a>>>0<16777216?3:4;else a=1;return a|0}function Mb(b,c){b=b|0;c=c|0;var d=0;if(b>>>0<=16777215)if(b>>>0<=65535){if(b>>>0>255)d=6}else d=4;else{a[c>>0]=b>>>24;c=c+1|0;d=4}if((d|0)==4){a[c>>0]=b>>>16;c=c+1|0;d=6}if((d|0)==6){a[c>>0]=b>>>8;c=c+1|0}a[c>>0]=b;return}function Nb(a){a=a|0;var b=0,d=0;b=i;i=i+16|0;d=b;c[d>>2]=c[a+60>>2];a=Qb(ha(6,d|0)|0)|0;i=b;return a|0}function Ob(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0;m=i;i=i+48|0;h=m+16|0;g=m;f=m+32|0;c[f>>2]=d;j=f+4|0;l=b+48|0;n=c[l>>2]|0;c[j>>2]=e-((n|0)!=0&1);k=b+44|0;c[f+8>>2]=c[k>>2];c[f+12>>2]=n;if(!(c[9715]|0)){c[h>>2]=c[b+60>>2];c[h+4>>2]=f;c[h+8>>2]=2;f=Qb(qa(145,h|0)|0)|0}else{ga(1,b|0);c[g>>2]=c[b+60>>2];c[g+4>>2]=f;c[g+8>>2]=2;f=Qb(qa(145,g|0)|0)|0;ba(0)}if((f|0)>=1){j=c[j>>2]|0;if(f>>>0>j>>>0){g=c[k>>2]|0;h=b+4|0;c[h>>2]=g;c[b+8>>2]=g+(f-j);if(!(c[l>>2]|0))f=e;else{c[h>>2]=g+1;a[d+(e+-1)>>0]=a[g>>0]|0;f=e}}}else{c[b>>2]=c[b>>2]|f&48^16;c[b+8>>2]=0;c[b+4>>2]=0}i=m;return f|0}function Pb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0;f=i;i=i+32|0;g=f;e=f+20|0;c[g>>2]=c[a+60>>2];c[g+4>>2]=0;c[g+8>>2]=b;c[g+12>>2]=e;c[g+16>>2]=d;if((Qb(ja(140,g|0)|0)|0)<0){c[e>>2]=-1;a=-1}else a=c[e>>2]|0;i=f;return a|0}function Qb(a){a=a|0;if(a>>>0>4294963200){c[(Rb()|0)>>2]=0-a;a=-1}return a|0}function Rb(){var a=0;if(!(c[9715]|0))a=38904;else a=c[(uc()|0)+64>>2]|0;return a|0}function Sb(a){a=a|0;if(!(c[a+68>>2]|0))Tb(a);return}function Tb(a){a=a|0;return}function Ub(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0;q=i;i=i+48|0;n=q+16|0;m=q;j=q+32|0;o=a+28|0;h=c[o>>2]|0;c[j>>2]=h;p=a+20|0;h=(c[p>>2]|0)-h|0;c[j+4>>2]=h;c[j+8>>2]=b;c[j+12>>2]=d;k=a+60|0;l=a+44|0;g=2;b=h+d|0;while(1){if(!(c[9715]|0)){c[n>>2]=c[k>>2];c[n+4>>2]=j;c[n+8>>2]=g;f=Qb(ra(146,n|0)|0)|0}else{ga(2,a|0);c[m>>2]=c[k>>2];c[m+4>>2]=j;c[m+8>>2]=g;f=Qb(ra(146,m|0)|0)|0;ba(0)}if((b|0)==(f|0)){b=6;break}if((f|0)<0){b=8;break}b=b-f|0;e=c[j+4>>2]|0;if(f>>>0<=e>>>0)if((g|0)==2){c[o>>2]=(c[o>>2]|0)+f;g=2;h=j}else h=j;else{h=c[l>>2]|0;c[o>>2]=h;c[p>>2]=h;f=f-e|0;g=g+-1|0;h=j+8|0;e=c[j+12>>2]|0}c[h>>2]=(c[h>>2]|0)+f;c[h+4>>2]=e-f;j=h}if((b|0)==6){n=c[l>>2]|0;c[a+16>>2]=n+(c[a+48>>2]|0);a=n;c[o>>2]=a;c[p>>2]=a}else if((b|0)==8){c[a+16>>2]=0;c[o>>2]=0;c[p>>2]=0;c[a>>2]=c[a>>2]|32;if((g|0)==2)d=0;else d=d-(c[j+4>>2]|0)|0}i=q;return d|0}function Vb(a){a=a|0;if(!(c[a+68>>2]|0))Tb(a);return}function Wb(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0;g=i;i=i+80|0;f=g;c[b+36>>2]=3;if((c[b>>2]&64|0)==0?(c[f>>2]=c[b+60>>2],c[f+4>>2]=21505,c[f+8>>2]=g+12,da(54,f|0)|0):0)a[b+75>>0]=-1;f=Ub(b,d,e)|0;i=g;return f|0}function Xb(b){b=b|0;var d=0,e=0;d=b+74|0;e=a[d>>0]|0;a[d>>0]=e+255|e;d=b+20|0;e=b+44|0;if((c[d>>2]|0)>>>0>(c[e>>2]|0)>>>0)va[c[b+36>>2]&7](b,0,0)|0;c[b+16>>2]=0;c[b+28>>2]=0;c[d>>2]=0;d=c[b>>2]|0;if(d&20)if(!(d&4))d=-1;else{c[b>>2]=d|32;d=-1}else{d=c[e>>2]|0;c[b+8>>2]=d;c[b+4>>2]=d;d=0}return d|0}function Yb(a){a=a|0;return 0}function Zb(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,i=0;h=d&255;f=(e|0)!=0;a:do if(f&(b&3|0)!=0){g=d&255;while(1){if((a[b>>0]|0)==g<<24>>24){i=6;break a}b=b+1|0;e=e+-1|0;f=(e|0)!=0;if(!(f&(b&3|0)!=0)){i=5;break}}}else i=5;while(0);if((i|0)==5)if(f)i=6;else e=0;b:do if((i|0)==6){g=d&255;if((a[b>>0]|0)!=g<<24>>24){f=R(h,16843009)|0;c:do if(e>>>0>3)while(1){h=c[b>>2]^f;if((h&-2139062144^-2139062144)&h+-16843009|0)break;b=b+4|0;e=e+-4|0;if(e>>>0<=3){i=11;break c}}else i=11;while(0);if((i|0)==11)if(!e){e=0;break}while(1){if((a[b>>0]|0)==g<<24>>24)break b;b=b+1|0;e=e+-1|0;if(!e){e=0;break}}}}while(0);return (e|0?b:0)|0}function _b(b){b=b|0;var d=0,e=0,f=0;f=b;a:do if(!(f&3))e=4;else{d=f;while(1){if(!(a[b>>0]|0)){b=d;break a}b=b+1|0;d=b;if(!(d&3)){e=4;break}}}while(0);if((e|0)==4){while(1){d=c[b>>2]|0;if(!((d&-2139062144^-2139062144)&d+-16843009))b=b+4|0;else break}if((d&255)<<24>>24)do b=b+1|0;while((a[b>>0]|0)!=0)}return b-f|0}function $b(b,c){b=b|0;c=c|0;b=ac(b,c)|0;return ((a[b>>0]|0)==(c&255)<<24>>24?b:0)|0}function ac(b,d){b=b|0;d=d|0;var e=0,f=0,g=0;f=d&255;a:do if(!f)b=b+(_b(b)|0)|0;else{if(b&3){e=d&255;do{g=a[b>>0]|0;if(g<<24>>24==0?1:g<<24>>24==e<<24>>24)break a;b=b+1|0}while((b&3|0)!=0)}f=R(f,16843009)|0;e=c[b>>2]|0;b:do if(!((e&-2139062144^-2139062144)&e+-16843009))do{g=e^f;if((g&-2139062144^-2139062144)&g+-16843009|0)break b;b=b+4|0;e=c[b>>2]|0}while(!((e&-2139062144^-2139062144)&e+-16843009|0));while(0);e=d&255;while(1){g=a[b>>0]|0;if(g<<24>>24==0?1:g<<24>>24==e<<24>>24)break;else b=b+1|0}}while(0);return b|0}function bc(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0;g=i;i=i+32|0;f=g+16|0;e=g;if(Zb(38847,a[d>>0]|0,4)|0){h=cc(d)|0|32768;c[e>>2]=b;c[e+4>>2]=h;c[e+8>>2]=438;e=Qb(ka(5,e|0)|0)|0;if((e|0)>=0){b=dc(e,d)|0;if(!b){c[f>>2]=e;ha(6,f|0)|0;b=0}}else b=0}else{c[(Rb()|0)>>2]=22;b=0}i=g;return b|0}function cc(b){b=b|0;var c=0,d=0,e=0;d=($b(b,43)|0)==0;c=a[b>>0]|0;d=d?c<<24>>24!=114&1:2;e=($b(b,120)|0)==0;d=e?d:d|128;b=($b(b,101)|0)==0;b=b?d:d|524288;b=c<<24>>24==114?b:b|64;b=c<<24>>24==119?b|512:b;return (c<<24>>24==97?b|1024:b)|0}function dc(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0;o=i;i=i+112|0;n=o+40|0;l=o+24|0;k=o+16|0;g=o;m=o+52|0;f=a[d>>0]|0;if(Zb(38847,f<<24>>24,4)|0){e=hc(1144)|0;if(!e)e=0;else{h=e;j=h+112|0;do{c[h>>2]=0;h=h+4|0}while((h|0)<(j|0));if(!($b(d,43)|0))c[e>>2]=f<<24>>24==114?8:4;if($b(d,101)|0){c[g>>2]=b;c[g+4>>2]=2;c[g+8>>2]=1;ca(221,g|0)|0;f=a[d>>0]|0}if(f<<24>>24==97){c[k>>2]=b;c[k+4>>2]=3;f=ca(221,k|0)|0;if(!(f&1024)){c[l>>2]=b;c[l+4>>2]=4;c[l+8>>2]=f|1024;ca(221,l|0)|0}d=c[e>>2]|128;c[e>>2]=d}else d=c[e>>2]|0;c[e+60>>2]=b;c[e+44>>2]=e+120;c[e+48>>2]=1024;f=e+75|0;a[f>>0]=-1;if((d&8|0)==0?(c[n>>2]=b,c[n+4>>2]=21505,c[n+8>>2]=m,(da(54,n|0)|0)==0):0)a[f>>0]=10;c[e+32>>2]=4;c[e+36>>2]=3;c[e+40>>2]=2;c[e+12>>2]=1;if(!(c[9716]|0))c[e+76>>2]=-1;ea(38888);f=c[9721]|0;c[e+56>>2]=f;if(f|0)c[f+52>>2]=e;c[9721]=e;na(38888)}}else{c[(Rb()|0)>>2]=22;e=0}i=o;return e|0}function ec(a){a=a|0;var b=0,d=0;do if(a){if((c[a+76>>2]|0)<=-1){b=fc(a)|0;break}d=(Yb(a)|0)==0;b=fc(a)|0;if(!d)Tb(a)}else{if(!(c[9549]|0))b=0;else b=ec(c[9549]|0)|0;ea(38888);a=c[9721]|0;if(a)do{if((c[a+76>>2]|0)>-1)d=Yb(a)|0;else d=0;if((c[a+20>>2]|0)>>>0>(c[a+28>>2]|0)>>>0)b=fc(a)|0|b;if(d|0)Tb(a);a=c[a+56>>2]|0}while((a|0)!=0);na(38888)}while(0);return b|0}function fc(a){a=a|0;var b=0,d=0,e=0,f=0,g=0,h=0;b=a+20|0;h=a+28|0;if((c[b>>2]|0)>>>0>(c[h>>2]|0)>>>0?(va[c[a+36>>2]&7](a,0,0)|0,(c[b>>2]|0)==0):0)a=-1;else{d=a+4|0;e=c[d>>2]|0;f=a+8|0;g=c[f>>2]|0;if(e>>>0>>0)va[c[a+40>>2]&7](a,e-g|0,1)|0;c[a+16>>2]=0;c[h>>2]=0;c[b>>2]=0;c[f>>2]=0;c[d>>2]=0;a=0}return a|0}function gc(b,d,e,f){b=b|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,i=0,j=0,k=0,l=0;k=R(e,d)|0;if((c[f+76>>2]|0)>-1)j=Yb(f)|0;else j=0;g=f+74|0;i=a[g>>0]|0;a[g>>0]=i+255|i;g=f+4|0;i=c[g>>2]|0;h=(c[f+8>>2]|0)-i|0;if((h|0)>0){h=h>>>0>>0?h:k;tc(b|0,i|0,h|0)|0;c[g>>2]=i+h;g=k-h|0;b=b+h|0}else g=k;a:do if(!g)l=13;else{i=f+32|0;while(1){if(Xb(f)|0)break;h=va[c[i>>2]&7](f,b,g)|0;if((h+1|0)>>>0<2)break;g=g-h|0;if(!g){l=13;break a}else b=b+h|0}if(j|0)Tb(f);e=((k-g|0)>>>0)/(d>>>0)|0}while(0);if((l|0)==13)if(j)Tb(f);return e|0}function hc(a){a=a|0;var b=0,d=0,e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0;L=i;i=i+16|0;p=L;do if(a>>>0<245){o=a>>>0<11?16:a+11&-8;a=o>>>3;t=c[9727]|0;d=t>>>a;if(d&3|0){a=(d&1^1)+a|0;d=38948+(a<<1<<2)|0;e=d+8|0;f=c[e>>2]|0;g=f+8|0;h=c[g>>2]|0;do if((d|0)!=(h|0)){if(h>>>0<(c[9731]|0)>>>0)fa();b=h+12|0;if((c[b>>2]|0)==(f|0)){c[b>>2]=d;c[e>>2]=h;break}else fa()}else c[9727]=t&~(1<>2]=K|3;K=f+K+4|0;c[K>>2]=c[K>>2]|1;K=g;i=L;return K|0}s=c[9729]|0;if(o>>>0>s>>>0){if(d|0){j=2<>>12&16;a=a>>>j;e=a>>>5&8;a=a>>>e;g=a>>>2&4;a=a>>>g;d=a>>>1&2;a=a>>>d;b=a>>>1&1;b=(e|j|g|d|b)+(a>>>b)|0;a=38948+(b<<1<<2)|0;d=a+8|0;g=c[d>>2]|0;j=g+8|0;e=c[j>>2]|0;do if((a|0)!=(e|0)){if(e>>>0<(c[9731]|0)>>>0)fa();f=e+12|0;if((c[f>>2]|0)==(g|0)){c[f>>2]=a;c[d>>2]=e;k=t;break}else fa()}else{k=t&~(1<>2]=o|3;e=g+o|0;c[e+4>>2]=h|1;c[e+h>>2]=h;if(s|0){f=c[9732]|0;b=s>>>3;d=38948+(b<<1<<2)|0;b=1<>2]|0;if(a>>>0<(c[9731]|0)>>>0)fa();else{l=a;m=b}}else{c[9727]=k|b;l=d;m=d+8|0}c[m>>2]=f;c[l+12>>2]=f;c[f+8>>2]=l;c[f+12>>2]=d}c[9729]=h;c[9732]=e;K=j;i=L;return K|0}l=c[9728]|0;if(l){a=(l&0-l)+-1|0;J=a>>>12&16;a=a>>>J;I=a>>>5&8;a=a>>>I;K=a>>>2&4;a=a>>>K;j=a>>>1&2;a=a>>>j;k=a>>>1&1;k=c[39212+((I|J|K|j|k)+(a>>>k)<<2)>>2]|0;a=k;j=k;k=(c[k+4>>2]&-8)-o|0;while(1){b=c[a+16>>2]|0;if(!b){b=c[a+20>>2]|0;if(!b)break}K=(c[b+4>>2]&-8)-o|0;J=K>>>0>>0;a=b;j=J?b:j;k=J?K:k}f=c[9731]|0;if(j>>>0>>0)fa();h=j+o|0;if(j>>>0>=h>>>0)fa();g=c[j+24>>2]|0;d=c[j+12>>2]|0;do if((d|0)==(j|0)){a=j+20|0;b=c[a>>2]|0;if(!b){a=j+16|0;b=c[a>>2]|0;if(!b){n=0;break}}while(1){d=b+20|0;e=c[d>>2]|0;if(e|0){b=e;a=d;continue}d=b+16|0;e=c[d>>2]|0;if(!e)break;else{b=e;a=d}}if(a>>>0>>0)fa();else{c[a>>2]=0;n=b;break}}else{e=c[j+8>>2]|0;if(e>>>0>>0)fa();b=e+12|0;if((c[b>>2]|0)!=(j|0))fa();a=d+8|0;if((c[a>>2]|0)==(j|0)){c[b>>2]=d;c[a>>2]=e;n=d;break}else fa()}while(0);do if(g|0){b=c[j+28>>2]|0;a=39212+(b<<2)|0;if((j|0)==(c[a>>2]|0)){c[a>>2]=n;if(!n){c[9728]=l&~(1<>>0<(c[9731]|0)>>>0)fa();b=g+16|0;if((c[b>>2]|0)==(j|0))c[b>>2]=n;else c[g+20>>2]=n;if(!n)break}a=c[9731]|0;if(n>>>0>>0)fa();c[n+24>>2]=g;b=c[j+16>>2]|0;do if(b|0)if(b>>>0>>0)fa();else{c[n+16>>2]=b;c[b+24>>2]=n;break}while(0);b=c[j+20>>2]|0;if(b|0)if(b>>>0<(c[9731]|0)>>>0)fa();else{c[n+20>>2]=b;c[b+24>>2]=n;break}}while(0);if(k>>>0<16){K=k+o|0;c[j+4>>2]=K|3;K=j+K+4|0;c[K>>2]=c[K>>2]|1}else{c[j+4>>2]=o|3;c[h+4>>2]=k|1;c[h+k>>2]=k;if(s|0){e=c[9732]|0;b=s>>>3;d=38948+(b<<1<<2)|0;b=1<>2]|0;if(a>>>0<(c[9731]|0)>>>0)fa();else{q=a;r=b}}else{c[9727]=t|b;q=d;r=d+8|0}c[r>>2]=e;c[q+12>>2]=e;c[e+8>>2]=q;c[e+12>>2]=d}c[9729]=k;c[9732]=h}K=j+8|0;i=L;return K|0}}}else if(a>>>0<=4294967231){a=a+11|0;o=a&-8;l=c[9728]|0;if(l){e=0-o|0;a=a>>>8;if(a)if(o>>>0>16777215)k=31;else{r=(a+1048320|0)>>>16&8;D=a<>>16&4;D=D<>>16&2;k=14-(q|r|k)+(D<>>15)|0;k=o>>>(k+7|0)&1|k<<1}else k=0;a=c[39212+(k<<2)>>2]|0;a:do if(!a){d=0;f=0;D=86}else{f=0;j=a;h=o<<((k|0)==31?0:25-(k>>>1)|0);d=0;while(1){a=(c[j+4>>2]&-8)-o|0;if(a>>>0>>0)if(!a){a=j;e=0;d=j;D=90;break a}else{f=j;e=a}a=c[j+20>>2]|0;j=c[j+16+(h>>>31<<2)>>2]|0;d=(a|0)==0|(a|0)==(j|0)?d:a;a=(j|0)==0;if(a){D=86;break}else h=h<<(a&1^1)}}while(0);if((D|0)==86){if((d|0)==0&(f|0)==0){a=2<>>12&16;r=r>>>m;k=r>>>5&8;r=r>>>k;n=r>>>2&4;r=r>>>n;q=r>>>1&2;r=r>>>q;d=r>>>1&1;d=c[39212+((k|m|n|q|d)+(r>>>d)<<2)>>2]|0}if(!d){k=f;j=e}else{a=f;D=90}}if((D|0)==90)while(1){D=0;r=(c[d+4>>2]&-8)-o|0;f=r>>>0>>0;e=f?r:e;a=f?d:a;f=c[d+16>>2]|0;if(f|0){d=f;D=90;continue}d=c[d+20>>2]|0;if(!d){k=a;j=e;break}else D=90}if((k|0)!=0?j>>>0<((c[9729]|0)-o|0)>>>0:0){f=c[9731]|0;if(k>>>0>>0)fa();h=k+o|0;if(k>>>0>=h>>>0)fa();g=c[k+24>>2]|0;d=c[k+12>>2]|0;do if((d|0)==(k|0)){a=k+20|0;b=c[a>>2]|0;if(!b){a=k+16|0;b=c[a>>2]|0;if(!b){s=0;break}}while(1){d=b+20|0;e=c[d>>2]|0;if(e|0){b=e;a=d;continue}d=b+16|0;e=c[d>>2]|0;if(!e)break;else{b=e;a=d}}if(a>>>0>>0)fa();else{c[a>>2]=0;s=b;break}}else{e=c[k+8>>2]|0;if(e>>>0>>0)fa();b=e+12|0;if((c[b>>2]|0)!=(k|0))fa();a=d+8|0;if((c[a>>2]|0)==(k|0)){c[b>>2]=d;c[a>>2]=e;s=d;break}else fa()}while(0);do if(g){b=c[k+28>>2]|0;a=39212+(b<<2)|0;if((k|0)==(c[a>>2]|0)){c[a>>2]=s;if(!s){t=l&~(1<>>0<(c[9731]|0)>>>0)fa();b=g+16|0;if((c[b>>2]|0)==(k|0))c[b>>2]=s;else c[g+20>>2]=s;if(!s){t=l;break}}a=c[9731]|0;if(s>>>0>>0)fa();c[s+24>>2]=g;b=c[k+16>>2]|0;do if(b|0)if(b>>>0>>0)fa();else{c[s+16>>2]=b;c[b+24>>2]=s;break}while(0);b=c[k+20>>2]|0;if(b)if(b>>>0<(c[9731]|0)>>>0)fa();else{c[s+20>>2]=b;c[b+24>>2]=s;t=l;break}else t=l}else t=l;while(0);do if(j>>>0>=16){c[k+4>>2]=o|3;c[h+4>>2]=j|1;c[h+j>>2]=j;b=j>>>3;if(j>>>0<256){d=38948+(b<<1<<2)|0;a=c[9727]|0;b=1<>2]|0;if(a>>>0<(c[9731]|0)>>>0)fa();else{B=a;C=b}}else{c[9727]=a|b;B=d;C=d+8|0}c[C>>2]=h;c[B+12>>2]=h;c[h+8>>2]=B;c[h+12>>2]=d;break}b=j>>>8;if(b)if(j>>>0>16777215)b=31;else{J=(b+1048320|0)>>>16&8;K=b<>>16&4;K=K<>>16&2;b=14-(I|J|b)+(K<>>15)|0;b=j>>>(b+7|0)&1|b<<1}else b=0;d=39212+(b<<2)|0;c[h+28>>2]=b;a=h+16|0;c[a+4>>2]=0;c[a>>2]=0;a=1<>2]=h;c[h+24>>2]=d;c[h+12>>2]=h;c[h+8>>2]=h;break}a=j<<((b|0)==31?0:25-(b>>>1)|0);e=c[d>>2]|0;while(1){if((c[e+4>>2]&-8|0)==(j|0)){D=148;break}d=e+16+(a>>>31<<2)|0;b=c[d>>2]|0;if(!b){D=145;break}else{a=a<<1;e=b}}if((D|0)==145)if(d>>>0<(c[9731]|0)>>>0)fa();else{c[d>>2]=h;c[h+24>>2]=e;c[h+12>>2]=h;c[h+8>>2]=h;break}else if((D|0)==148){b=e+8|0;a=c[b>>2]|0;K=c[9731]|0;if(a>>>0>=K>>>0&e>>>0>=K>>>0){c[a+12>>2]=h;c[b>>2]=h;c[h+8>>2]=a;c[h+12>>2]=e;c[h+24>>2]=0;break}else fa()}}else{K=j+o|0;c[k+4>>2]=K|3;K=k+K+4|0;c[K>>2]=c[K>>2]|1}while(0);K=k+8|0;i=L;return K|0}}}else o=-1;while(0);d=c[9729]|0;if(d>>>0>=o>>>0){b=d-o|0;a=c[9732]|0;if(b>>>0>15){K=a+o|0;c[9732]=K;c[9729]=b;c[K+4>>2]=b|1;c[K+b>>2]=b;c[a+4>>2]=o|3}else{c[9729]=0;c[9732]=0;c[a+4>>2]=d|3;K=a+d+4|0;c[K>>2]=c[K>>2]|1}K=a+8|0;i=L;return K|0}j=c[9730]|0;if(j>>>0>o>>>0){I=j-o|0;c[9730]=I;K=c[9733]|0;J=K+o|0;c[9733]=J;c[J+4>>2]=I|1;c[K+4>>2]=o|3;K=K+8|0;i=L;return K|0}if(!(c[9845]|0)){c[9847]=4096;c[9846]=4096;c[9848]=-1;c[9849]=-1;c[9850]=0;c[9838]=0;a=p&-16^1431655768;c[p>>2]=a;c[9845]=a;a=4096}else a=c[9847]|0;k=o+48|0;l=o+47|0;h=a+l|0;f=0-a|0;m=h&f;if(m>>>0<=o>>>0){K=0;i=L;return K|0}a=c[9837]|0;if(a|0?(B=c[9835]|0,C=B+m|0,C>>>0<=B>>>0|C>>>0>a>>>0):0){K=0;i=L;return K|0}b:do if(!(c[9838]&4)){d=c[9733]|0;c:do if(d){e=39356;while(1){a=c[e>>2]|0;if(a>>>0<=d>>>0?(u=e+4|0,(a+(c[u>>2]|0)|0)>>>0>d>>>0):0)break;a=c[e+8>>2]|0;if(!a){D=172;break c}else e=a}d=h-j&f;if(d>>>0<2147483647){a=rc(d|0)|0;if((a|0)==((c[e>>2]|0)+(c[u>>2]|0)|0)){if((a|0)!=(-1|0)){h=d;g=a;D=190;break b}}else{b=d;D=180}}}else D=172;while(0);do if(((D|0)==172?(g=rc(0)|0,(g|0)!=(-1|0)):0)?(b=g,v=c[9846]|0,w=v+-1|0,b=((w&b|0)==0?0:(w+b&0-v)-b|0)+m|0,v=c[9835]|0,w=b+v|0,b>>>0>o>>>0&b>>>0<2147483647):0){C=c[9837]|0;if(C|0?w>>>0<=v>>>0|w>>>0>C>>>0:0)break;a=rc(b|0)|0;if((a|0)==(g|0)){h=b;D=190;break b}else D=180}while(0);d:do if((D|0)==180){d=0-b|0;do if(k>>>0>b>>>0&(b>>>0<2147483647&(a|0)!=(-1|0))?(x=c[9847]|0,x=l-b+x&0-x,x>>>0<2147483647):0)if((rc(x|0)|0)==(-1|0)){rc(d|0)|0;break d}else{b=x+b|0;break}while(0);if((a|0)!=(-1|0)){h=b;g=a;D=190;break b}}while(0);c[9838]=c[9838]|4;D=187}else D=187;while(0);if((((D|0)==187?m>>>0<2147483647:0)?(A=rc(m|0)|0,y=rc(0)|0,A>>>0>>0&((A|0)!=(-1|0)&(y|0)!=(-1|0))):0)?(z=y-A|0,z>>>0>(o+40|0)>>>0):0){h=z;g=A;D=190}if((D|0)==190){b=(c[9835]|0)+h|0;c[9835]=b;if(b>>>0>(c[9836]|0)>>>0)c[9836]=b;l=c[9733]|0;do if(l){b=39356;while(1){a=c[b>>2]|0;d=b+4|0;e=c[d>>2]|0;if((g|0)==(a+e|0)){D=200;break}f=c[b+8>>2]|0;if(!f)break;else b=f}if(((D|0)==200?(c[b+12>>2]&8|0)==0:0)?l>>>0>>0&l>>>0>=a>>>0:0){c[d>>2]=e+h;K=l+8|0;K=(K&7|0)==0?0:0-K&7;J=l+K|0;K=h-K+(c[9730]|0)|0;c[9733]=J;c[9730]=K;c[J+4>>2]=K|1;c[J+K+4>>2]=40;c[9734]=c[9849];break}b=c[9731]|0;if(g>>>0>>0){c[9731]=g;j=g}else j=b;a=g+h|0;b=39356;while(1){if((c[b>>2]|0)==(a|0)){D=208;break}b=c[b+8>>2]|0;if(!b){a=39356;break}}if((D|0)==208)if(!(c[b+12>>2]&8)){c[b>>2]=g;n=b+4|0;c[n>>2]=(c[n>>2]|0)+h;n=g+8|0;n=g+((n&7|0)==0?0:0-n&7)|0;b=a+8|0;b=a+((b&7|0)==0?0:0-b&7)|0;m=n+o|0;k=b-n-o|0;c[n+4>>2]=o|3;do if((b|0)!=(l|0)){if((b|0)==(c[9732]|0)){K=(c[9729]|0)+k|0;c[9729]=K;c[9732]=m;c[m+4>>2]=K|1;c[m+K>>2]=K;break}a=c[b+4>>2]|0;if((a&3|0)==1){h=a&-8;f=a>>>3;e:do if(a>>>0>=256){g=c[b+24>>2]|0;e=c[b+12>>2]|0;do if((e|0)==(b|0)){e=b+16|0;d=e+4|0;a=c[d>>2]|0;if(!a){a=c[e>>2]|0;if(!a){I=0;break}else d=e}while(1){e=a+20|0;f=c[e>>2]|0;if(f|0){a=f;d=e;continue}e=a+16|0;f=c[e>>2]|0;if(!f)break;else{a=f;d=e}}if(d>>>0>>0)fa();else{c[d>>2]=0;I=a;break}}else{f=c[b+8>>2]|0;if(f>>>0>>0)fa();a=f+12|0;if((c[a>>2]|0)!=(b|0))fa();d=e+8|0;if((c[d>>2]|0)==(b|0)){c[a>>2]=e;c[d>>2]=f;I=e;break}else fa()}while(0);if(!g)break;a=c[b+28>>2]|0;d=39212+(a<<2)|0;do if((b|0)!=(c[d>>2]|0)){if(g>>>0<(c[9731]|0)>>>0)fa();a=g+16|0;if((c[a>>2]|0)==(b|0))c[a>>2]=I;else c[g+20>>2]=I;if(!I)break e}else{c[d>>2]=I;if(I|0)break;c[9728]=c[9728]&~(1<>>0>>0)fa();c[I+24>>2]=g;a=b+16|0;d=c[a>>2]|0;do if(d|0)if(d>>>0>>0)fa();else{c[I+16>>2]=d;c[d+24>>2]=I;break}while(0);a=c[a+4>>2]|0;if(!a)break;if(a>>>0<(c[9731]|0)>>>0)fa();else{c[I+20>>2]=a;c[a+24>>2]=I;break}}else{d=c[b+8>>2]|0;e=c[b+12>>2]|0;a=38948+(f<<1<<2)|0;do if((d|0)!=(a|0)){if(d>>>0>>0)fa();if((c[d+12>>2]|0)==(b|0))break;fa()}while(0);if((e|0)==(d|0)){c[9727]=c[9727]&~(1<>>0>>0)fa();a=e+8|0;if((c[a>>2]|0)==(b|0)){F=a;break}fa()}while(0);c[d+12>>2]=e;c[F>>2]=d}while(0);b=b+h|0;f=h+k|0}else f=k;b=b+4|0;c[b>>2]=c[b>>2]&-2;c[m+4>>2]=f|1;c[m+f>>2]=f;b=f>>>3;if(f>>>0<256){d=38948+(b<<1<<2)|0;a=c[9727]|0;b=1<>2]|0;if(a>>>0>=(c[9731]|0)>>>0){J=a;K=b;break}fa()}while(0);c[K>>2]=m;c[J+12>>2]=m;c[m+8>>2]=J;c[m+12>>2]=d;break}b=f>>>8;do if(!b)b=0;else{if(f>>>0>16777215){b=31;break}J=(b+1048320|0)>>>16&8;K=b<>>16&4;K=K<>>16&2;b=14-(I|J|b)+(K<>>15)|0;b=f>>>(b+7|0)&1|b<<1}while(0);e=39212+(b<<2)|0;c[m+28>>2]=b;a=m+16|0;c[a+4>>2]=0;c[a>>2]=0;a=c[9728]|0;d=1<>2]=m;c[m+24>>2]=e;c[m+12>>2]=m;c[m+8>>2]=m;break}a=f<<((b|0)==31?0:25-(b>>>1)|0);e=c[e>>2]|0;while(1){if((c[e+4>>2]&-8|0)==(f|0)){D=278;break}d=e+16+(a>>>31<<2)|0;b=c[d>>2]|0;if(!b){D=275;break}else{a=a<<1;e=b}}if((D|0)==275)if(d>>>0<(c[9731]|0)>>>0)fa();else{c[d>>2]=m;c[m+24>>2]=e;c[m+12>>2]=m;c[m+8>>2]=m;break}else if((D|0)==278){b=e+8|0;a=c[b>>2]|0;K=c[9731]|0;if(a>>>0>=K>>>0&e>>>0>=K>>>0){c[a+12>>2]=m;c[b>>2]=m;c[m+8>>2]=a;c[m+12>>2]=e;c[m+24>>2]=0;break}else fa()}}else{K=(c[9730]|0)+k|0;c[9730]=K;c[9733]=m;c[m+4>>2]=K|1}while(0);K=n+8|0;i=L;return K|0}else a=39356;while(1){b=c[a>>2]|0;if(b>>>0<=l>>>0?(E=b+(c[a+4>>2]|0)|0,E>>>0>l>>>0):0)break;a=c[a+8>>2]|0}f=E+-47|0;a=f+8|0;a=f+((a&7|0)==0?0:0-a&7)|0;f=l+16|0;a=a>>>0>>0?l:a;b=a+8|0;d=g+8|0;d=(d&7|0)==0?0:0-d&7;K=g+d|0;d=h+-40-d|0;c[9733]=K;c[9730]=d;c[K+4>>2]=d|1;c[K+d+4>>2]=40;c[9734]=c[9849];d=a+4|0;c[d>>2]=27;c[b>>2]=c[9839];c[b+4>>2]=c[9840];c[b+8>>2]=c[9841];c[b+12>>2]=c[9842];c[9839]=g;c[9840]=h;c[9842]=0;c[9841]=b;b=a+24|0;do{b=b+4|0;c[b>>2]=7}while((b+4|0)>>>0>>0);if((a|0)!=(l|0)){g=a-l|0;c[d>>2]=c[d>>2]&-2;c[l+4>>2]=g|1;c[a>>2]=g;b=g>>>3;if(g>>>0<256){d=38948+(b<<1<<2)|0;a=c[9727]|0;b=1<>2]|0;if(a>>>0<(c[9731]|0)>>>0)fa();else{G=a;H=b}}else{c[9727]=a|b;G=d;H=d+8|0}c[H>>2]=l;c[G+12>>2]=l;c[l+8>>2]=G;c[l+12>>2]=d;break}b=g>>>8;if(b)if(g>>>0>16777215)d=31;else{J=(b+1048320|0)>>>16&8;K=b<>>16&4;K=K<>>16&2;d=14-(I|J|d)+(K<>>15)|0;d=g>>>(d+7|0)&1|d<<1}else d=0;e=39212+(d<<2)|0;c[l+28>>2]=d;c[l+20>>2]=0;c[f>>2]=0;b=c[9728]|0;a=1<>2]=l;c[l+24>>2]=e;c[l+12>>2]=l;c[l+8>>2]=l;break}a=g<<((d|0)==31?0:25-(d>>>1)|0);e=c[e>>2]|0;while(1){if((c[e+4>>2]&-8|0)==(g|0)){D=304;break}d=e+16+(a>>>31<<2)|0;b=c[d>>2]|0;if(!b){D=301;break}else{a=a<<1;e=b}}if((D|0)==301)if(d>>>0<(c[9731]|0)>>>0)fa();else{c[d>>2]=l;c[l+24>>2]=e;c[l+12>>2]=l;c[l+8>>2]=l;break}else if((D|0)==304){b=e+8|0;a=c[b>>2]|0;K=c[9731]|0;if(a>>>0>=K>>>0&e>>>0>=K>>>0){c[a+12>>2]=l;c[b>>2]=l;c[l+8>>2]=a;c[l+12>>2]=e;c[l+24>>2]=0;break}else fa()}}}else{K=c[9731]|0;if((K|0)==0|g>>>0>>0)c[9731]=g;c[9839]=g;c[9840]=h;c[9842]=0;c[9736]=c[9845];c[9735]=-1;b=0;do{K=38948+(b<<1<<2)|0;c[K+12>>2]=K;c[K+8>>2]=K;b=b+1|0}while((b|0)!=32);K=g+8|0;K=(K&7|0)==0?0:0-K&7;J=g+K|0;K=h+-40-K|0;c[9733]=J;c[9730]=K;c[J+4>>2]=K|1;c[J+K+4>>2]=40;c[9734]=c[9849]}while(0);b=c[9730]|0;if(b>>>0>o>>>0){I=b-o|0;c[9730]=I;K=c[9733]|0;J=K+o|0;c[9733]=J;c[J+4>>2]=I|1;c[K+4>>2]=o|3;K=K+8|0;i=L;return K|0}}c[(Rb()|0)>>2]=12;K=0;i=L;return K|0}function ic(a){a=a|0;var b=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0;if(!a)return;d=a+-8|0;h=c[9731]|0;if(d>>>0>>0)fa();a=c[a+-4>>2]|0;b=a&3;if((b|0)==1)fa();e=a&-8;n=d+e|0;do if(!(a&1)){a=c[d>>2]|0;if(!b)return;k=d+(0-a)|0;j=a+e|0;if(k>>>0>>0)fa();if((k|0)==(c[9732]|0)){a=n+4|0;b=c[a>>2]|0;if((b&3|0)!=3){q=k;f=j;break}c[9729]=j;c[a>>2]=b&-2;c[k+4>>2]=j|1;c[k+j>>2]=j;return}e=a>>>3;if(a>>>0<256){b=c[k+8>>2]|0;d=c[k+12>>2]|0;a=38948+(e<<1<<2)|0;if((b|0)!=(a|0)){if(b>>>0>>0)fa();if((c[b+12>>2]|0)!=(k|0))fa()}if((d|0)==(b|0)){c[9727]=c[9727]&~(1<>>0>>0)fa();a=d+8|0;if((c[a>>2]|0)==(k|0))g=a;else fa()}else g=d+8|0;c[b+12>>2]=d;c[g>>2]=b;q=k;f=j;break}g=c[k+24>>2]|0;d=c[k+12>>2]|0;do if((d|0)==(k|0)){d=k+16|0;b=d+4|0;a=c[b>>2]|0;if(!a){a=c[d>>2]|0;if(!a){i=0;break}else b=d}while(1){d=a+20|0;e=c[d>>2]|0;if(e|0){a=e;b=d;continue}d=a+16|0;e=c[d>>2]|0;if(!e)break;else{a=e;b=d}}if(b>>>0>>0)fa();else{c[b>>2]=0;i=a;break}}else{e=c[k+8>>2]|0;if(e>>>0>>0)fa();a=e+12|0;if((c[a>>2]|0)!=(k|0))fa();b=d+8|0;if((c[b>>2]|0)==(k|0)){c[a>>2]=d;c[b>>2]=e;i=d;break}else fa()}while(0);if(g){a=c[k+28>>2]|0;b=39212+(a<<2)|0;if((k|0)==(c[b>>2]|0)){c[b>>2]=i;if(!i){c[9728]=c[9728]&~(1<>>0<(c[9731]|0)>>>0)fa();a=g+16|0;if((c[a>>2]|0)==(k|0))c[a>>2]=i;else c[g+20>>2]=i;if(!i){q=k;f=j;break}}d=c[9731]|0;if(i>>>0>>0)fa();c[i+24>>2]=g;a=k+16|0;b=c[a>>2]|0;do if(b|0)if(b>>>0>>0)fa();else{c[i+16>>2]=b;c[b+24>>2]=i;break}while(0);a=c[a+4>>2]|0;if(a)if(a>>>0<(c[9731]|0)>>>0)fa();else{c[i+20>>2]=a;c[a+24>>2]=i;q=k;f=j;break}else{q=k;f=j}}else{q=k;f=j}}else{q=d;f=e}while(0);if(q>>>0>=n>>>0)fa();a=n+4|0;b=c[a>>2]|0;if(!(b&1))fa();if(!(b&2)){if((n|0)==(c[9733]|0)){p=(c[9730]|0)+f|0;c[9730]=p;c[9733]=q;c[q+4>>2]=p|1;if((q|0)!=(c[9732]|0))return;c[9732]=0;c[9729]=0;return}if((n|0)==(c[9732]|0)){p=(c[9729]|0)+f|0;c[9729]=p;c[9732]=q;c[q+4>>2]=p|1;c[q+p>>2]=p;return}f=(b&-8)+f|0;e=b>>>3;do if(b>>>0>=256){g=c[n+24>>2]|0;a=c[n+12>>2]|0;do if((a|0)==(n|0)){d=n+16|0;b=d+4|0;a=c[b>>2]|0;if(!a){a=c[d>>2]|0;if(!a){m=0;break}else b=d}while(1){d=a+20|0;e=c[d>>2]|0;if(e|0){a=e;b=d;continue}d=a+16|0;e=c[d>>2]|0;if(!e)break;else{a=e;b=d}}if(b>>>0<(c[9731]|0)>>>0)fa();else{c[b>>2]=0;m=a;break}}else{b=c[n+8>>2]|0;if(b>>>0<(c[9731]|0)>>>0)fa();d=b+12|0;if((c[d>>2]|0)!=(n|0))fa();e=a+8|0;if((c[e>>2]|0)==(n|0)){c[d>>2]=a;c[e>>2]=b;m=a;break}else fa()}while(0);if(g|0){a=c[n+28>>2]|0;b=39212+(a<<2)|0;if((n|0)==(c[b>>2]|0)){c[b>>2]=m;if(!m){c[9728]=c[9728]&~(1<>>0<(c[9731]|0)>>>0)fa();a=g+16|0;if((c[a>>2]|0)==(n|0))c[a>>2]=m;else c[g+20>>2]=m;if(!m)break}d=c[9731]|0;if(m>>>0>>0)fa();c[m+24>>2]=g;a=n+16|0;b=c[a>>2]|0;do if(b|0)if(b>>>0>>0)fa();else{c[m+16>>2]=b;c[b+24>>2]=m;break}while(0);a=c[a+4>>2]|0;if(a|0)if(a>>>0<(c[9731]|0)>>>0)fa();else{c[m+20>>2]=a;c[a+24>>2]=m;break}}}else{b=c[n+8>>2]|0;d=c[n+12>>2]|0;a=38948+(e<<1<<2)|0;if((b|0)!=(a|0)){if(b>>>0<(c[9731]|0)>>>0)fa();if((c[b+12>>2]|0)!=(n|0))fa()}if((d|0)==(b|0)){c[9727]=c[9727]&~(1<>>0<(c[9731]|0)>>>0)fa();a=d+8|0;if((c[a>>2]|0)==(n|0))l=a;else fa()}else l=d+8|0;c[b+12>>2]=d;c[l>>2]=b}while(0);c[q+4>>2]=f|1;c[q+f>>2]=f;if((q|0)==(c[9732]|0)){c[9729]=f;return}}else{c[a>>2]=b&-2;c[q+4>>2]=f|1;c[q+f>>2]=f}a=f>>>3;if(f>>>0<256){d=38948+(a<<1<<2)|0;b=c[9727]|0;a=1<>2]|0;if(b>>>0<(c[9731]|0)>>>0)fa();else{o=b;p=a}}else{c[9727]=b|a;o=d;p=d+8|0}c[p>>2]=q;c[o+12>>2]=q;c[q+8>>2]=o;c[q+12>>2]=d;return}a=f>>>8;if(a)if(f>>>0>16777215)a=31;else{o=(a+1048320|0)>>>16&8;p=a<>>16&4;p=p<>>16&2;a=14-(n|o|a)+(p<>>15)|0;a=f>>>(a+7|0)&1|a<<1}else a=0;e=39212+(a<<2)|0;c[q+28>>2]=a;c[q+20>>2]=0;c[q+16>>2]=0;b=c[9728]|0;d=1<>>1)|0);e=c[e>>2]|0;while(1){if((c[e+4>>2]&-8|0)==(f|0)){a=130;break}d=e+16+(b>>>31<<2)|0;a=c[d>>2]|0;if(!a){a=127;break}else{b=b<<1;e=a}}if((a|0)==127)if(d>>>0<(c[9731]|0)>>>0)fa();else{c[d>>2]=q;c[q+24>>2]=e;c[q+12>>2]=q;c[q+8>>2]=q;break}else if((a|0)==130){a=e+8|0;b=c[a>>2]|0;p=c[9731]|0;if(b>>>0>=p>>>0&e>>>0>=p>>>0){c[b+12>>2]=q;c[a>>2]=q;c[q+8>>2]=b;c[q+12>>2]=e;c[q+24>>2]=0;break}else fa()}}else{c[9728]=b|d;c[e>>2]=q;c[q+24>>2]=e;c[q+12>>2]=q;c[q+8>>2]=q}while(0);q=(c[9735]|0)+-1|0;c[9735]=q;if(!q)a=39364;else return;while(1){a=c[a>>2]|0;if(!a)break;else a=a+8|0}c[9735]=-1;return}function jc(){}function kc(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;d=b-d-(c>>>0>a>>>0|0)>>>0;return (C=d,a-c>>>0|0)|0}function lc(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,i=0;f=b+e|0;if((e|0)>=20){d=d&255;h=b&3;i=d|d<<8|d<<16|d<<24;g=f&~3;if(h){h=b+4-h|0;while((b|0)<(h|0)){a[b>>0]=d;b=b+1|0}}while((b|0)<(g|0)){c[b>>2]=i;b=b+4|0}}while((b|0)<(f|0)){a[b>>0]=d;b=b+1|0}return b-e|0}function mc(a,b,c){a=a|0;b=b|0;c=c|0;if((c|0)<32){C=b>>>c;return a>>>c|(b&(1<>>c-32|0}function nc(a,b,c){a=a|0;b=b|0;c=c|0;if((c|0)<32){C=b<>>32-c;return a<>>16;a=(c>>>16)+(R(e,d)|0)|0;e=b>>>16;b=R(e,f)|0;return (C=(a>>>16)+(R(e,d)|0)+(((a&65535)+b|0)>>>16)|0,a+b<<16|c&65535|0)|0}function pc(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0,f=0;e=a;f=c;c=oc(e,f)|0;a=C;return (C=(R(b,f)|0)+(R(d,e)|0)+a|a&0,c|0|0)|0}function qc(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;c=a+c>>>0;return (C=b+d+(c>>>0>>0|0)>>>0,c|0)|0}function rc(a){a=a|0;var b=0,d=0;d=a+15&-16|0;b=c[k>>2]|0;a=b+d|0;if((d|0)>0&(a|0)<(b|0)|(a|0)<0){Z()|0;sa(12);return -1}c[k>>2]=a;if((a|0)>(Y()|0)?(X()|0)==0:0){sa(12);c[k>>2]=b;return -1}return b|0}function sc(a){a=a|0;return (a&255)<<24|(a>>8&255)<<16|(a>>16&255)<<8|a>>>24|0}function tc(b,d,e){b=b|0;d=d|0;e=e|0;var f=0;if((e|0)>=4096)return la(b|0,d|0,e|0)|0;f=b|0;if((b&3)==(d&3)){while(b&3){if(!e)return f|0;a[b>>0]=a[d>>0]|0;b=b+1|0;d=d+1|0;e=e-1|0}while((e|0)>=4){c[b>>2]=c[d>>2];b=b+4|0;d=d+4|0;e=e-4|0}}while((e|0)>0){a[b>>0]=a[d>>0]|0;b=b+1|0;d=d+1|0;e=e-1|0}return f|0}function uc(){return 0}function vc(a,b){a=a|0;b=b|0;return ua[a&1](b|0)|0}function wc(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;return va[a&7](b|0,c|0,d|0)|0}function xc(a,b){a=a|0;b=b|0;wa[a&3](b|0)}function yc(a){a=a|0;V(0);return 0}function zc(a,b,c){a=a|0;b=b|0;c=c|0;V(1);return 0}function Ac(a){a=a|0;V(2)} +function xa(a){a=a|0;var b=0;b=i;i=i+a|0;i=i+15&-16;return b|0}function ya(){return i|0}function za(a){a=a|0;i=a}function Aa(a,b){a=a|0;b=b|0;i=a;j=b}function Ba(a,b){a=a|0;b=b|0;if(!n){n=a;o=b}}function Ca(a){a=a|0;C=a}function Da(){return C|0}function Ea(b,c){b=b|0;c=c|0;a[b>>0]=c>>>24;a[b+1>>0]=c>>>16;a[b+2>>0]=c>>>8;a[b+3>>0]=c;return}function Fa(a,b){a=a|0;b=b|0;var e=0,f=0,g=0,h=0;e=0;f=0;do{h=a+(7-f<<2)|0;h=(d[h+1>>0]|0)<<16|(d[h>>0]|0)<<24|(d[h+2>>0]|0)<<8|(d[h+3>>0]|0);g=f<<1;c[b+(f<<2)>>2]=(h<>>(30-g|0);f=f+1|0}while((f|0)!=8);c[b+32>>2]=e;return}function Ga(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0;e=c[b+32>>2]<<16;f=0;while(1){g=c[b+(7-f<<2)>>2]|0;h=f<<1;i=g>>>(14-h|0)|e;e=d+(f<<2)|0;a[e>>0]=i>>>24;a[e+1>>0]=i>>>16;a[e+2>>0]=i>>>8;a[e+3>>0]=i;f=f+1|0;if((f|0)==8)break;else e=g<>2]=0;a=a+4|0}while((a|0)<(b|0));return}function Ia(a){a=a|0;return (c[a+32>>2]|(c[a+28>>2]|(c[a+24>>2]|(c[a+20>>2]|(c[a+16>>2]|(c[a+12>>2]|(c[a+8>>2]|(c[a+4>>2]|c[a>>2])))))))|0)==0|0}function Ja(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0;d=0;e=8;f=0;while(1){h=c[a+(e<<2)>>2]|0;g=c[b+(e<<2)>>2]|0;d=h>>>0>>0|d<<1;f=h>>>0>g>>>0|f<<1;if((e|0)<=0)break;else e=e+-1|0}return d>>>0>f>>>0|0}function Ka(a,b){a=a|0;b=b|0;var d=0,e=0;d=0;e=0;do{e=c[b+(d<<2)>>2]^c[a+(d<<2)>>2]|e;d=d+1|0}while((d|0)!=9);return (e|0)==0|0}function La(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0;g=0-b|0;h=b+-1|0;if((b|1|0)==1)f=0;else pa(38200,38223,270,38235);do{c[a+(f<<2)>>2]=c[e+(f<<2)>>2]&h|c[d+(f<<2)>>2]&g;f=f+1|0}while((f|0)!=9);return}function Ma(a){a=a|0;var b=0,d=0,e=0,f=0;b=8;d=c[a+32>>2]|0;do{e=b;b=b+-1|0;f=d;d=c[a+(b<<2)>>2]|0;c[a+(e<<2)>>2]=d>>>29&1|f<<1&1073741822}while((e|0)>1);c[a>>2]=c[a>>2]<<1&1073741822;return}function Na(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,i=0;d=c[a>>2]|0;f=0-(d&1)|0;d=((c[b>>2]&f)+d|0)>>>1;e=0;do{i=e;e=e+1|0;g=(c[b+(e<<2)>>2]&f)+(c[a+(e<<2)>>2]|0)|0;h=(g<<29&536870912)+d|0;c[a+(i<<2)>>2]=h&1073741823;d=(h>>>30)+(g>>>1)|0}while((e|0)!=8);c[a+32>>2]=d;return}function Oa(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0;e=b&255;b=0;do{f=a+(b<<2)|0;c[f>>2]=R(c[f>>2]|0,e)|0;b=b+1|0}while((b|0)!=9);Pa(a,d);return}function Pa(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0;g=(c[a+32>>2]|0)>>>16;i=c[a>>2]|0;h=pc(c[b>>2]|0,0,g|0,0)|0;d=C;e=kc(i|0,536870912,h|0,d|0)|0;f=C;d=kc(i|0,0,h|0,d|0)|0;c[a>>2]=d&1073741823;d=1;while(1){l=mc(e|0,f|0,30)|0;k=C;i=a+(d<<2)|0;j=c[i>>2]|0;f=pc(c[b+(d<<2)>>2]|0,0,g|0,0)|0;h=C;k=qc(l|0,k|0,-2147483648,536870911)|0;j=qc(k|0,C|0,j|0,0)|0;e=kc(j|0,C|0,f|0,h|0)|0;c[i>>2]=e&1073741823;d=d+1|0;if((d|0)==9)break;else f=C}return}function Qa(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0;h=i;i=i+48|0;g=h;d=0;e=8;f=0;while(1){k=c[a+(e<<2)>>2]|0;j=c[b+(e<<2)>>2]|0;d=k>>>0>>0|d<<1;f=k>>>0>j>>>0|f<<1;if((e|0)<=0)break;else e=e+-1|0}f=d>>>0>f>>>0;e=0;d=1;while(1){d=d+1073741823+(c[a+(e<<2)>>2]|0)-(c[b+(e<<2)>>2]|0)|0;c[g+(e<<2)>>2]=d&1073741823;e=e+1|0;if((e|0)==9)break;else d=d>>>30}La(a,f&1,a,g);i=h;return}function Ra(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0;f=0;e=1;while(1){e=e+1073741823+(c[a+(f<<2)>>2]|0)-(c[b+(f<<2)>>2]|0)|0;c[d+(f<<2)>>2]=e&1073741823;f=f+1|0;if((f|0)==9)break;else e=e>>>30}return}function Sa(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0,j=0;h=0;g=0;e=0;i=1;while(1){f=0;do{j=pc(c[b+(h-f<<2)>>2]|0,0,c[a+(f<<2)>>2]|0,0)|0;g=qc(j|0,C|0,g|0,e|0)|0;e=C;f=f+1|0}while((f|0)!=(i|0));c[d+(h<<2)>>2]=g&1073741823;g=mc(g|0,e|0,30)|0;e=C;h=h+1|0;if((h|0)==9){h=9;break}else i=i+1|0}while(1){f=h+-8|0;if((f|0)<9)do{j=pc(c[b+(h-f<<2)>>2]|0,0,c[a+(f<<2)>>2]|0,0)|0;g=qc(j|0,C|0,g|0,e|0)|0;e=C;f=f+1|0}while((f|0)!=9);c[d+(h<<2)>>2]=g&1073741823;g=mc(g|0,e|0,30)|0;h=h+1|0;if((h|0)==17)break;else e=C}c[d+68>>2]=g;return}function Ta(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0;l=a+(d+1<<2)|0;j=(c[l>>2]<<14)+((c[a+(d<<2)>>2]|0)>>>16)|0;k=d+-8|0;e=a+(k<<2)|0;f=c[e>>2]|0;g=pc(c[b>>2]|0,0,j|0,0)|0;h=C;if((j|0)<=-1)pa(38243,38223,417,38262);i=kc(f|0,536870912,g|0,h|0)|0;m=C;h=kc(f|0,0,g|0,h|0)|0;c[e>>2]=h&1073741823;h=mc(i|0,m|0,30)|0;m=C;i=a+(d+-7<<2)|0;f=qc(c[i>>2]|0,0,-2147483648,536870911)|0;e=1;g=C;d=m;do{m=pc(c[b+(e<<2)>>2]|0,0,j|0,0)|0;m=kc(f|0,g|0,m|0,C|0)|0;m=qc(m|0,C|0,h|0,d|0)|0;c[i>>2]=m&1073741823;e=e+1|0;h=mc(m|0,C|0,30)|0;d=C;i=a+(e+k<<2)|0;f=qc(c[i>>2]|0,0,-2147483648,536870911)|0;g=C}while((e|0)!=9);m=qc(f|0,g|0,h|0,d|0)|0;c[l>>2]=m&1073741823;return}function Ua(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0;e=16;while(1){Ta(b,d,e);if(c[b+(e+1<<2)>>2]|0){g=4;break}e=e+-1|0;if((e|0)<=7){f=0;break}}if((g|0)==4)pa(38286,38223,451,38302);do{c[a+(f<<2)>>2]=c[b+(f<<2)>>2];f=f+1|0}while((f|0)!=9);return}function Va(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0;g=i;i=i+80|0;e=g;f=e;h=f+72|0;do{c[f>>2]=0;f=f+4|0}while((f|0)<(h|0));Sa(a,b,e);Ua(b,e,d);i=g;return}function Wa(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0;n=i;i=i+144|0;k=n+72|0;l=n+36|0;m=n;c[l>>2]=1;h=l+4|0;c[h>>2]=0;c[h+4>>2]=0;c[h+8>>2]=0;c[h+12>>2]=0;c[h+16>>2]=0;c[h+20>>2]=0;c[h+24>>2]=0;c[h+28>>2]=0;h=m;d=b;j=h+36|0;do{c[h>>2]=c[d>>2];h=h+4|0;d=d+4|0}while((h|0)<(j|0));e=0;d=1;while(1){j=m+(e<<2)|0;d=(c[j>>2]|0)+d|0;c[j>>2]=d&1073741823;e=e+1|0;if((e|0)==9)break;else d=d>>>30}d=0;e=c[m>>2]|0;do{j=d;d=d+1|0;h=e;e=c[m+(d<<2)>>2]|0;c[m+(j<<2)>>2]=e<<29&536870912|h>>>1}while((d|0)!=8);e=m+32|0;c[e>>2]=(c[e>>2]|0)>>>1;d=0;f=c[m>>2]|0;do{j=d;d=d+1|0;h=f;f=c[m+(d<<2)>>2]|0;c[m+(j<<2)>>2]=f<<29&536870912|h>>>1}while((d|0)!=8);c[e>>2]=(c[e>>2]|0)>>>1;e=0;do{g=(e|0)==8;d=0;f=c[m+(e<<2)>>2]|0;do{if(g&(f|0)==0)break;if(f&1|0){h=k;j=h+72|0;do{c[h>>2]=0;h=h+4|0}while((h|0)<(j|0));Sa(a,l,k);Ua(l,k,b)}f=f>>>1;h=k;j=h+72|0;do{c[h>>2]=0;h=h+4|0}while((h|0)<(j|0));Sa(a,a,k);Ua(a,k,b);d=d+1|0}while(d>>>0<30);e=e+1|0}while((e|0)!=9);Qa(l,b);h=a;d=l;j=h+36|0;do{c[h>>2]=c[d>>2];h=h+4|0;d=d+4|0}while((h|0)<(j|0));i=n;return}function Xa(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0;v=i;i=i+112|0;d=v+72|0;u=v+32|0;t=v;Pa(a,b);Qa(a,b);e=c[b>>2]|0;f=0;while(1){r=f;f=f+1|0;g=c[b+(f<<2)>>2]|0;h=r<<1;p=g<<30-h|e;c[t+(r<<2)>>2]=p;c[d+(r<<2)>>2]=p;if((f|0)==8)break;else e=g>>>(h+2|0)}e=c[a>>2]|0;f=0;while(1){r=f;f=f+1|0;b=c[a+(f<<2)>>2]|0;g=r<<1;c[u+(r<<2)>>2]=b<<30-g|e;if((f|0)==8)break;else e=b>>>(g+2|0)}o=d+36|0;c[o>>2]=8;p=u+36|0;c[p>>2]=8;r=d+32|0;c[r>>2]=1;c[u+32>>2]=0;f=0;n=u;e=8;g=c[d>>2]|0;b=1;a:while(1){if(!(g&1)){q=7;break}if(!(b&1)){q=10;break}l=n+36|0;b=e;while(1){e=b+-1|0;if(c[n+(e<<2)>>2]|0)break;c[l>>2]=e;if((b|0)<1)break a;else b=e}e=c[n>>2]|0;if(!e){g=n+32|0;do{e=0;do{m=e;e=e+1|0;c[n+(m<<2)>>2]=c[n+(e<<2)>>2]}while((e|0)!=8);c[g>>2]=0;b=(c[l>>2]|0)+-1|0;c[l>>2]=b;f=f+32|0;e=c[n>>2]|0}while((e|0)==0)}k=0;while(1)if(!(e&1<0){e=e>>>k;if((b|0)>1){j=32-k|0;g=1;h=n;while(1){b=n+(g<<2)|0;c[h>>2]=c[b>>2]<>2]|0)>>>k;if((e|0)<(c[l>>2]|0)){g=e;e=h;h=b}else break}}else{g=0;h=e;b=n;e=1}c[b>>2]=h;if(!h)c[l>>2]=(c[l>>2]|0)+-1;else g=e;e=n+(g<<2)|0;b=c[e>>2]<>2]=(c[e>>2]|0)>>>h|b;b=c[e>>2]<>2]=b;m=k+f|0}else m=f;if(!(c[n>>2]&1)){q=32;break}if(c[n+32>>2]&1|0){q=34;break}f=c[o>>2]|0;e=f-(c[p>>2]|0)|0;if(!e){e=f;while(1){b=e+-1|0;if((e|0)<=0){q=38;break}e=c[d+(b<<2)>>2]|0;f=u+(b<<2)|0;if((e|0)==(c[f>>2]|0))e=b;else break}if((q|0)==38){q=0;if(!e){q=56;break}f=u+(b<<2)|0;e=c[d+(b<<2)>>2]|0}e=e>>>0>(c[f>>2]|0)>>>0?1:-1}n=(e|0)>0;l=n?u:d;n=n?d:u;k=l+36|0;h=c[k>>2]|0;if((h|0)>0){e=0;f=1;b=0;while(1){j=n+(e<<2)|0;w=c[j>>2]|0;g=c[l+(e<<2)>>2]|0;f=qc(f|0,b|0,-1,0)|0;f=qc(f|0,C|0,w|0,0)|0;g=kc(f|0,C|0,g|0,0)|0;f=C;c[j>>2]=g;e=e+1|0;if((e|0)<(h|0))b=0;else{b=e;g=0;break}}}else{b=0;f=1;g=0}j=n+36|0;e=c[j>>2]|0;if((b|0)<(e|0)){e=g;while(1){w=n+(b<<2)|0;g=c[w>>2]|0;e=qc(f|0,e|0,-1,0)|0;e=qc(e|0,C|0,g|0,0)|0;c[w>>2]=e;b=b+1|0;e=c[j>>2]|0;if((b|0)>=(e|0))break;else{f=C;e=0}}}if((e|0)>8){f=8;g=0;b=0}else{f=8;g=0;b=0;while(1){w=l+(f<<2)|0;j=c[n+(f<<2)>>2]|0;h=qc(c[w>>2]|0,0,g|0,b|0)|0;j=qc(h|0,C|0,j|0,0)|0;g=C;c[w>>2]=j;w=f;f=f+-1|0;if((w|0)<=(e|0))break;else b=0}h=c[k>>2]|0;b=0}if((f|0)>=(h|0))while(1){w=l+(f<<2)|0;j=qc(c[w>>2]|0,0,g|0,b|0)|0;c[w>>2]=j;if((f|0)>(c[k>>2]|0)){f=f+-1|0;g=C;b=0}else break}g=c[l>>2]|0;if(!(g&1)){q=51;break}b=c[l+32>>2]|0;if(!(b&1)){q=53;break}if(c[n>>2]&1|0){q=55;break}else f=m}if((q|0)==7)pa(38321,38223,646,38335);else if((q|0)==10)pa(38346,38223,647,38335);else if((q|0)==32)pa(38360,38223,699,38335);else if((q|0)==34)pa(38375,38223,700,38335);else if((q|0)==51)pa(38321,38223,757,38335);else if((q|0)==53)pa(38346,38223,758,38335);else if((q|0)==55)pa(38397,38223,759,38335);else if((q|0)==56){l=c[t>>2]|0;if(!(l&1))pa(38419,38223,786,38335);f=l+-1|0;e=l+-2|0;if(!f)k=e;else{do{f=R(f,f)|0;e=R(f+1|0,e)|0}while((f|0)!=0);k=e}b:do if((m|0)>31){j=d+4|0;e=m;while(1){w=c[r>>2]|0;b=R(w,k)|0;q=pc(l|0,0,b|0,0)|0;w=qc(q|0,C|0,w|0,0)|0;if(!((w|0)==0&0==0))break;f=0;g=C;h=0;while(1){w=f;f=f+1|0;o=c[d+(7-w<<2)>>2]|0;p=pc(c[t+(f<<2)>>2]|0,0,b|0,0)|0;q=C;o=qc(o|0,0,g|0,h|0)|0;q=qc(o|0,C|0,p|0,q|0)|0;g=C;c[d+(8-w<<2)>>2]=q;if((f|0)==7)break;else h=0}c[j>>2]=g;e=e+-32|0;if((e|0)<=31){s=e;break b}}pa(38429,38223,802,38335)}else s=m;while(0);if((s|0)>0){w=(1<>2]|0;h=(R(e,k)|0)&w;if((R(h,l)|0)+e&w|0)pa(38454,38223,821,38335);b=pc(h|0,0,l|0,0)|0;b=qc(b|0,C|0,e|0,0)|0;b=mc(b|0,C|0,s|0)|0;f=32-s|0;e=0;g=C;while(1){w=e;e=e+1|0;s=c[d+(7-w<<2)>>2]|0;r=pc(c[t+(e<<2)>>2]|0,0,h|0,0)|0;s=qc(r|0,C|0,s|0,0)|0;s=nc(s|0,C|0,f|0)|0;s=qc(s|0,C|0,b|0,g|0)|0;b=C;c[d+(8-w<<2)>>2]=s;if((e|0)==7)break;else g=0}c[d+4>>2]=b;e=0;f=0}else{e=0;f=0}do{s=c[d+(8-e<<2)>>2]|0;w=e<<1;c[a+(e<<2)>>2]=s<>>(30-w|0);e=e+1|0}while((e|0)!=8);c[a+32>>2]=f;c[t>>2]=0;c[t+4>>2]=0;c[t+8>>2]=0;c[t+12>>2]=0;c[t+16>>2]=0;c[t+20>>2]=0;c[t+24>>2]=0;c[t+28>>2]=0;e=d+40|0;do{c[d>>2]=0;d=d+4|0}while((d|0)<(e|0));d=u;e=d+40|0;do{c[d>>2]=0;d=d+4|0}while((d|0)<(e|0))}i=v;return}function Ya(a,b){a=a|0;b=b|0;var d=0,e=0,f=0;e=0;d=0;while(1){f=a+(e<<2)|0;d=(c[f>>2]|0)+d+(c[b+(e<<2)>>2]|0)|0;c[f>>2]=d&1073741823;e=e+1|0;if((e|0)==9)break;else d=d>>>30}return}function Za(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0;e=0;do{f=a+(e<<2)|0;c[f>>2]=(c[f>>2]|0)+(c[b+(e<<2)>>2]|0);e=e+1|0}while((e|0)!=9);Pa(a,d);return}function _a(a,b,d){a=a|0;b=b|0;d=d|0;var e=0;if((c[d>>2]|0)>>>0>>0)pa(38495,38223,883,38514);b=(c[a>>2]|0)-b|0;c[a>>2]=b;b=b+(c[d>>2]|0)|0;c[a>>2]=b&1073741823;e=1;do{b=(c[a+(e<<2)>>2]|0)+(b>>>30)+(c[d+(e<<2)>>2]|0)|0;c[a+(e<<2)>>2]=b&1073741823;e=e+1|0}while((e|0)!=9);return}function $a(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0;g=0;f=1;while(1){f=f+1073741823+(c[a+(g<<2)>>2]|0)+(c[e+(g<<2)>>2]<<1)-(c[b+(g<<2)>>2]|0)|0;c[d+(g<<2)>>2]=f&1073741823;g=g+1|0;if((g|0)==9)break;else f=f>>>30}return}function ab(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0;n=i;i=i+144|0;k=n+108|0;e=n+72|0;l=n+36|0;m=n;do if(!(bb(b)|0)){if(bb(d)|0){e=d;f=b;g=e+72|0;do{c[e>>2]=c[f>>2];e=e+4|0;f=f+4|0}while((e|0)<(g|0));break}if(cb(b,d)|0){db(a,d);break}if(!(eb(b,d)|0)){$a(d,b,e,a);Xa(e,a);h=d+36|0;j=b+36|0;$a(h,j,k,a);Va(e,k,a);e=l;f=k;g=e+36|0;do{c[e>>2]=c[f>>2];e=e+4|0;f=f+4|0}while((e|0)<(g|0));Va(l,l,a);e=m;f=b;g=e+36|0;do{c[e>>2]=c[f>>2];e=e+4|0;f=f+4|0}while((e|0)<(g|0));Za(m,d,a);$a(l,m,l,a);Pa(l,a);Qa(l,a);$a(b,l,m,a);Va(k,m,a);$a(m,j,m,a);Pa(m,a);Qa(m,a);e=d;f=l;g=e+36|0;do{c[e>>2]=c[f>>2];e=e+4|0;f=f+4|0}while((e|0)<(g|0));e=h;f=m;g=e+36|0;do{c[e>>2]=c[f>>2];e=e+4|0;f=f+4|0}while((e|0)<(g|0));break}else{Ha(d);Ha(d+36|0);break}}while(0);i=n;return}function bb(a){a=a|0;if(!(Ia(a)|0))a=0;else a=(Ia(a+36|0)|0)!=0;return a&1|0}function cb(a,b){a=a|0;b=b|0;if(!(Ka(a,b)|0))a=0;else a=(Ka(a+36|0,b+36|0)|0)!=0;return a&1|0}function db(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0,l=0;j=i;i=i+112|0;d=j+72|0;e=j+36|0;f=j;do if(!(bb(b)|0)){g=b+36|0;if(!(Ia(g)|0)){h=d;k=g;l=h+36|0;do{c[h>>2]=c[k>>2];h=h+4|0;k=k+4|0}while((h|0)<(l|0));Oa(d,2,a);Xa(d,a);h=e;k=b;l=h+36|0;do{c[h>>2]=c[k>>2];h=h+4|0;k=k+4|0}while((h|0)<(l|0));Va(e,e,a);Oa(e,3,a);_a(e,0-(c[a+180>>2]|0)|0,a);Va(e,d,a);h=e;k=d;l=h+36|0;do{c[h>>2]=c[k>>2];h=h+4|0;k=k+4|0}while((h|0)<(l|0));Va(e,e,a);h=f;k=b;l=h+36|0;do{c[h>>2]=c[k>>2];h=h+4|0;k=k+4|0}while((h|0)<(l|0));Ma(f);$a(e,f,e,a);Pa(e,a);Qa(e,a);$a(b,e,f,a);Va(d,f,a);$a(f,g,f,a);Pa(f,a);Qa(f,a);h=b;k=e;l=h+36|0;do{c[h>>2]=c[k>>2];h=h+4|0;k=k+4|0}while((h|0)<(l|0));h=g;k=f;l=h+36|0;do{c[h>>2]=c[k>>2];h=h+4|0;k=k+4|0}while((h|0)<(l|0));break}else{Ha(b);Ha(g);break}}while(0);i=j;return}function eb(a,b){a=a|0;b=b|0;var c=0;if((Ka(a,b)|0)!=0?(c=a+36|0,(Ia(c)|0)==0):0)a=(Ka(c,b+36|0)|0)==0&1;else a=0;return a|0}function fb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0,j=0;g=b+32|0;if((c[g>>2]|0)>>>0>=131072)pa(38522,38542,181,38553);h=a&1073741823;f=~a;a=c[b>>2]|0;e=(c[d>>2]<<1)+1073741824-a|0;c[b>>2]=h&e|a&f;a=0;do{a=a+1|0;i=b+(a<<2)|0;j=c[i>>2]|0;e=(e>>>30)+1073741823+(c[d+(a<<2)>>2]<<1)-j|0;c[i>>2]=h&e|j&f}while((a|0)!=8);if((c[g>>2]|0)>>>0<131072)return;else pa(38522,38542,189,38553)}function gb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0;e=b+72|0;hb(e,d);g=b;h=e;i=g+36|0;do{c[g>>2]=c[h>>2];g=g+4|0;h=h+4|0}while((g|0)<(i|0));Va(e,b,d);f=b+36|0;g=f;h=b;i=g+36|0;do{c[g>>2]=c[h>>2];g=g+4|0;h=h+4|0}while((g|0)<(i|0));Va(e,f,d);Va(a,b,d);Va(a+36|0,f,d);return}function hb(a,b){a=a|0;b=b|0;var d=0,e=0,f=0;e=a+32|0;while(1){d=0;f=Kb()|0;do{c[a+(d<<2)>>2]=f&1073741823;d=d+1|0;f=Kb()|0}while((d|0)!=8);c[e>>2]=f&65535;if(Ia(a)|0)continue;if(Ja(a,b)|0)break}return}function ib(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0;e=b+36|0;f=e;g=a+72|0;h=f+36|0;do{c[f>>2]=c[g>>2];f=f+4|0;g=g+4|0}while((f|0)<(h|0));Xa(e,d);f=b;g=e;h=f+36|0;do{c[f>>2]=c[g>>2];f=f+4|0;g=g+4|0}while((f|0)<(h|0));Va(b,b,d);Va(b,e,d);Va(a,b,d);Va(a+36|0,e,d);Qa(b,d);Qa(e,d);return}function jb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0;s=i;i=i+288|0;k=s+252|0;l=s+216|0;m=s+180|0;n=s+144|0;o=s+108|0;p=s+72|0;q=s+36|0;g=s;e=c[d+180>>2]|0;if((e+3|0)>>>0>=4)pa(38572,38542,248,38590);h=b+72|0;r=p;t=h;u=r+36|0;do{c[r>>2]=c[t>>2];r=r+4|0;t=t+4|0}while((r|0)<(u|0));Va(p,p,d);r=q;t=h;u=r+36|0;do{c[r>>2]=c[t>>2];r=r+4|0;t=t+4|0}while((r|0)<(u|0));Va(p,q,d);j=(e|0)!=0;if(j){e=0-e|0;r=g;t=p;u=r+36|0;do{c[r>>2]=c[t>>2];r=r+4|0;t=t+4|0}while((r|0)<(u|0));Va(g,g,d);Oa(g,e&255,d)}Va(a,p,d);r=l;t=p;u=r+36|0;do{c[r>>2]=c[t>>2];r=r+4|0;t=t+4|0}while((r|0)<(u|0));$a(l,b,l,d);Pa(l,d);Ya(p,b);f=Ka(l,d)|0;Va(a+36|0,q,d);e=b+36|0;$a(q,e,k,d);Ya(q,e);r=m;t=b;u=r+36|0;do{c[r>>2]=c[t>>2];r=r+4|0;t=t+4|0}while((r|0)<(u|0));Va(m,m,d);Oa(m,3,d);if(j)$a(m,g,m,d);La(k,f,m,k);La(l,f,q,l);r=o;t=l;u=r+36|0;do{c[r>>2]=c[t>>2];r=r+4|0;t=t+4|0}while((r|0)<(u|0));Va(o,o,d);r=n;t=l;u=r+36|0;do{c[r>>2]=c[t>>2];r=r+4|0;t=t+4|0}while((r|0)<(u|0));Va(o,n,d);Va(p,o,d);Va(q,n,d);Va(l,h,d);r=b;t=k;u=r+36|0;do{c[r>>2]=c[t>>2];r=r+4|0;t=t+4|0}while((r|0)<(u|0));Va(b,b,d);$a(b,o,b,d);Pa(b,d);$a(o,b,e,d);$a(e,b,e,d);Va(k,e,d);$a(e,n,e,d);Na(e,d);Pa(e,d);i=s;return}function kb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0;n=i;i=i+144|0;l=n+108|0;m=n;if(!(Ja(b,a+108|0)|0))pa(38609,38542,553,38658);j=c[b>>2]|0;g=(j&1)+-1|0;f=1;e=0;h=j;do{k=f+1073741823+h-(c[a+108+(e<<2)>>2]&g)|0;c[l+(e<<2)>>2]=k&1073741823;f=k>>>30;e=e+1|0;h=c[b+(e<<2)>>2]|0;j=h|j}while((e|0)!=8);k=l+32|0;c[k>>2]=f+65535+h-(c[a+140>>2]&g);e=c[l>>2]|0;if(!(e&1))pa(38638,38542,576,38658);if(!j){Ha(d);Ha(d+36|0)}else{gb(a+220+((((e>>>4&1)+15^e)>>>1&7)*72|0)|0,m,a);h=m+36|0;g=1;do{f=0;e=e>>>4;b=l;do{f=f+1|0;j=b;b=l+(f<<2)|0;c[j>>2]=c[b>>2]<<26&1006632960|e;e=(c[b>>2]|0)>>>4}while((f|0)!=8);c[k>>2]=e;e=c[l>>2]|0;b=e>>>4&1;j=b+15^e;fb((j&1)+-1|0,h,a);jb(a+220+(g*576|0)+((j>>>1&7)*72|0)|0,m,a);g=g+1|0}while((g|0)!=64);fb(b+-1|0,h,a);ib(m,d,a)}i=n;return}function lb(b,c,d){b=b|0;c=c|0;d=d|0;b=(b|0)==0?712:b;switch(a[c>>0]|0){case 4:{Fa(c+1|0,d);Fa(c+33|0,d+36|0);b=mb(b,d)|0;break}case 3:case 2:{Fa(c+1|0,d);nb(b,a[c>>0]|0,d,d+36|0);b=mb(b,d)|0;break}default:b=0}return b|0}function mb(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0;k=i;i=i+80|0;d=k+36|0;e=k;if(((bb(b)|0)==0?(Ja(b,a)|0)!=0:0)?(f=b+36|0,(Ja(f,a)|0)!=0):0){g=d;h=f;j=g+36|0;do{c[g>>2]=c[h>>2];g=g+4|0;h=h+4|0}while((g|0)<(j|0));g=e;h=b;j=g+36|0;do{c[g>>2]=c[h>>2];g=g+4|0;h=h+4|0}while((g|0)<(j|0));Va(f,d,a);Qa(d,a);Va(b,e,a);_a(e,0-(c[a+180>>2]|0)|0,a);Va(b,e,a);Za(e,a+184|0,a);Qa(e,a);a=(Ka(e,d)|0)!=0&1}else a=0;i=k;return a|0}function nb(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0;f=e;g=d;h=f+36|0;do{c[f>>2]=c[g>>2];f=f+4|0;g=g+4|0}while((f|0)<(h|0));Va(d,e,a);_a(e,0-(c[a+180>>2]|0)|0,a);Va(d,e,a);Ya(e,a+184|0);Wa(e,a);if((c[e>>2]^b&255)&1|0)Ra(a,e,e);return}function ob(b,c){b=b|0;c=c|0;var d=0,e=0;e=i;i=i+32|0;d=e;switch(a[b>>0]|0){case 4:{Eb(b,65,d);break}case 0:{Eb(b,1,d);break}default:Eb(b,33,d)}Ab(d,32,c);i=e;return}function pb(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0,f=0,g=0,h=0;e=i;i=i+48|0;g=e;f=Lb(b)|0;h=Lb(b)|0;Mb(b,g);ob(a,g+h|0);wb(g,f+20|0,c,d)|0;i=e;return}function qb(b,c,e){b=b|0;c=c|0;e=e|0;var f=0,g=0,h=0,j=0;j=i;i=i+128|0;h=j;f=h;g=f+128|0;do{a[f>>0]=0;f=f+1|0}while((f|0)<(g|0));if(e>>>0>128){Jb(c,e,h);c=0}else{tc(h|0,c|0,e|0)|0;c=0}do{g=h+c|0;f=d[g>>0]|0;a[b+c>>0]=f^92;a[g>>0]=f^54;c=c+1|0}while((c|0)!=128);b=b+128|0;Fb(b);Hb(b,h,128);i=j;return}function rb(a,b){a=a|0;b=b|0;var c=0,d=0,e=0;c=i;i=i+64|0;e=c;d=a+128|0;Ib(d,e);Fb(d);Hb(d,a,128);Hb(d,e,64);Ib(d,b);lc(a|0,0,336)|0;i=c;return}function sb(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;var f=0,g=0;f=i;i=i+336|0;g=f;qb(g,a,b);Hb(g+128|0,c,d);rb(g,e);i=f;return}function tb(b,d,e,f,g,h){b=b|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;var j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0;r=i;i=i+144|0;o=r+104|0;p=r+40|0;q=r;if((f|0)<0)f=0;else{a[o>>0]=c[d+36>>2]&1|2;n=o+1|0;Ga(d,n);Ea(o+33|0,f);f=b+108|0;j=p+32|0;while(1){sb(e,32,o,37,p);Fa(p,q);if(Ja(q,f)|0?(kb(b,q,g),ab(b,d,g),(bb(g)|0)==0):0)break;a[o>>0]=1;k=n;l=j;m=k+32|0;do{a[k>>0]=a[l>>0]|0;k=k+1|0;l=l+1|0}while((k|0)<(m|0))}if(h|0){k=h;l=j;m=k+32|0;do{a[k>>0]=a[l>>0]|0;k=k+1|0;l=l+1|0}while((k|0)<(m|0))}k=o;m=k+37|0;do{a[k>>0]=0;k=k+1|0}while((k|0)<(m|0));k=p;m=k+64|0;do{a[k>>0]=0;k=k+1|0}while((k|0)<(m|0));k=q;m=k+36|0;do{c[k>>2]=0;k=k+4|0}while((k|0)<(m|0));f=1}i=r;return f|0}function ub(b,d,e,f,g,h,j){b=b|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;j=j|0;var k=0,l=0,m=0,n=0,o=0;n=i;i=i+192|0;l=n+152|0;o=n;m=n+120|0;k=n+72|0;tb(712,b,d,e,o,0)|0;a[l>>0]=c[o+36>>2]&1|2;Ga(o,l+1|0);if(j){b=Lb(f)|0;a[m>>0]=0;a[m+1>>0]=20;ob(l,m+2|0);Eb(m,22,k);Mb(f,m);Ab(k,32,m+b|0);b=(wb(m,b+20|0,g,54)|0)!=0&1}else{pb(l,f,g,h);b=1}i=n;return b|0}function vb(b,e,f,g){b=b|0;e=e|0;f=f|0;g=g|0;var h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0;q=i;a:do if((g|0)>0){h=0;do{if(a[f+h>>0]|0)break a;h=h+1|0}while((h|0)<(g|0))}else h=0;while(0);o=(((g-h|0)*138|0)>>>0)/100|0;n=o+1|0;p=i;i=i+((1*n|0)+15&-16)|0;lc(p|0,0,n|0)|0;if((h|0)<(g|0)){j=o;m=h;do{k=a[f+m>>0]|0;if((o|0)>(j|0)|k<<24>>24!=0){k=k&255;l=o;while(1){r=p+l|0;k=(d[r>>0]<<8)+k|0;a[r>>0]=(k|0)%58|0;l=l+-1|0;if((l|0)>(j|0)|(k+57|0)>>>0>114)k=(k|0)/58|0;else{j=l;break}}}else j=o;m=m+1|0}while((m|0)!=(g|0));j=0}else j=0;while(1){if(a[p+j>>0]|0)break;k=j+1|0;if((j|0)<(o|0))j=k;else{j=k;break}}k=n+h-j|0;if((c[e>>2]|0)>>>0>k>>>0){if(!h)h=0;else lc(b|0,49,h|0)|0;if((j|0)<=(o|0))while(1){a[b+h>>0]=a[38674+(d[p+j>>0]|0)>>0]|0;h=h+1|0;if((j|0)<(o|0))j=j+1|0;else break}a[b+h>>0]=0;j=1}else{j=0;h=k}c[e>>2]=h+1;i=q;return j|0}function wb(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,j=0,k=0,l=0;g=i;i=i+16|0;f=g;if((b|0)>128)a=0;else{j=b+32|0;h=ia()|0;k=i;i=i+((1*j|0)+15&-16)|0;l=k+b|0;tc(k|0,a|0,b|0)|0;Eb(a,b,l);Eb(l,32,l);c[f>>2]=e;a=vb(d,f,k,b+4|0)|0;lc(k|0,0,j|0)|0;a=a?c[f>>2]|0:0;oa(h|0)}i=g;return a|0}function xb(a,b){a=a|0;b=b|0;var e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0;s=(d[b+1>>0]|0)<<8|(d[b>>0]|0)|(d[b+2>>0]|0)<<16|(d[b+3>>0]|0)<<24;D=(d[b+5>>0]|0)<<8|(d[b+4>>0]|0)|(d[b+6>>0]|0)<<16|(d[b+7>>0]|0)<<24;v=(d[b+9>>0]|0)<<8|(d[b+8>>0]|0)|(d[b+10>>0]|0)<<16|(d[b+11>>0]|0)<<24;f=(d[b+13>>0]|0)<<8|(d[b+12>>0]|0)|(d[b+14>>0]|0)<<16|(d[b+15>>0]|0)<<24;x=(d[b+17>>0]|0)<<8|(d[b+16>>0]|0)|(d[b+18>>0]|0)<<16|(d[b+19>>0]|0)<<24;t=(d[b+21>>0]|0)<<8|(d[b+20>>0]|0)|(d[b+22>>0]|0)<<16|(d[b+23>>0]|0)<<24;y=(d[b+25>>0]|0)<<8|(d[b+24>>0]|0)|(d[b+26>>0]|0)<<16|(d[b+27>>0]|0)<<24;z=(d[b+29>>0]|0)<<8|(d[b+28>>0]|0)|(d[b+30>>0]|0)<<16|(d[b+31>>0]|0)<<24;B=(d[b+33>>0]|0)<<8|(d[b+32>>0]|0)|(d[b+34>>0]|0)<<16|(d[b+35>>0]|0)<<24;i=(d[b+37>>0]|0)<<8|(d[b+36>>0]|0)|(d[b+38>>0]|0)<<16|(d[b+39>>0]|0)<<24;F=(d[b+41>>0]|0)<<8|(d[b+40>>0]|0)|(d[b+42>>0]|0)<<16|(d[b+43>>0]|0)<<24;l=(d[b+45>>0]|0)<<8|(d[b+44>>0]|0)|(d[b+46>>0]|0)<<16|(d[b+47>>0]|0)<<24;H=(d[b+49>>0]|0)<<8|(d[b+48>>0]|0)|(d[b+50>>0]|0)<<16|(d[b+51>>0]|0)<<24;u=(d[b+53>>0]|0)<<8|(d[b+52>>0]|0)|(d[b+54>>0]|0)<<16|(d[b+55>>0]|0)<<24;m=(d[b+57>>0]|0)<<8|(d[b+56>>0]|0)|(d[b+58>>0]|0)<<16|(d[b+59>>0]|0)<<24;w=(d[b+61>>0]|0)<<8|(d[b+60>>0]|0)|(d[b+62>>0]|0)<<16|(d[b+63>>0]|0)<<24;b=a+8|0;A=c[b>>2]|0;p=a+12|0;e=c[p>>2]|0;n=a+16|0;r=c[n>>2]|0;k=a+20|0;I=c[k>>2]|0;g=a+24|0;E=c[g>>2]|0;j=A+s+(r^e^I)|0;j=(j<<11|j>>>21)+E|0;C=r<<10|r>>>22;A=t+1352829926+A+((r|~I)^e)|0;A=(A<<8|A>>>24)+E|0;o=E+D+(C^e^j)|0;o=(o<<14|o>>>18)+I|0;G=e<<10|e>>>22;E=m+1352829926+E+(A^(e|~C))|0;E=(E<<9|E>>>23)+I|0;J=I+v+(j^G^o)|0;J=(J<<15|J>>>17)+C|0;j=j<<10|j>>>22;I=z+1352829926+I+(E^(A|~G))|0;I=(I<<9|I>>>23)+C|0;A=A<<10|A>>>22;a=C+f+(o^j^J)|0;a=(a<<12|a>>>20)+G|0;o=o<<10|o>>>22;C=s+1352829926+C+(I^(E|~A))|0;C=(C<<11|C>>>21)+G|0;E=E<<10|E>>>22;h=G+x+(J^o^a)|0;h=(h<<5|h>>>27)+j|0;J=J<<10|J>>>22;G=i+1352829926+G+(C^(I|~E))|0;G=(G<<13|G>>>19)+A|0;I=I<<10|I>>>22;j=j+t+(a^J^h)|0;j=(j<<8|j>>>24)+o|0;a=a<<10|a>>>22;A=v+1352829926+A+(G^(C|~I))|0;A=(A<<15|A>>>17)+E|0;C=C<<10|C>>>22;o=o+y+(h^a^j)|0;o=(o<<7|o>>>25)+J|0;h=h<<10|h>>>22;E=l+1352829926+E+(A^(G|~C))|0;E=(E<<15|E>>>17)+I|0;G=G<<10|G>>>22;J=J+z+(j^h^o)|0;J=(J<<9|J>>>23)+a|0;j=j<<10|j>>>22;I=x+1352829926+I+(E^(A|~G))|0;I=(I<<5|I>>>27)+C|0;A=A<<10|A>>>22;a=a+B+(o^j^J)|0;a=(a<<11|a>>>21)+h|0;o=o<<10|o>>>22;C=u+1352829926+C+(I^(E|~A))|0;C=(C<<7|C>>>25)+G|0;E=E<<10|E>>>22;h=h+i+(J^o^a)|0;h=(h<<13|h>>>19)+j|0;J=J<<10|J>>>22;G=y+1352829926+G+(C^(I|~E))|0;G=(G<<7|G>>>25)+A|0;I=I<<10|I>>>22;j=j+F+(a^J^h)|0;j=(j<<14|j>>>18)+o|0;a=a<<10|a>>>22;A=w+1352829926+A+(G^(C|~I))|0;A=(A<<8|A>>>24)+E|0;C=C<<10|C>>>22;o=o+l+(h^a^j)|0;o=(o<<15|o>>>17)+J|0;h=h<<10|h>>>22;E=B+1352829926+E+(A^(G|~C))|0;E=(E<<11|E>>>21)+I|0;G=G<<10|G>>>22;J=J+H+(j^h^o)|0;J=(J<<6|J>>>26)+a|0;j=j<<10|j>>>22;I=D+1352829926+I+(E^(A|~G))|0;I=(I<<14|I>>>18)+C|0;A=A<<10|A>>>22;a=a+u+(o^j^J)|0;a=(a<<7|a>>>25)+h|0;o=o<<10|o>>>22;C=F+1352829926+C+(I^(E|~A))|0;C=(C<<14|C>>>18)+G|0;E=E<<10|E>>>22;h=h+m+(J^o^a)|0;h=(h<<9|h>>>23)+j|0;J=J<<10|J>>>22;G=f+1352829926+G+(C^(I|~E))|0;G=(G<<12|G>>>20)+A|0;I=I<<10|I>>>22;j=j+w+(a^J^h)|0;j=(j<<8|j>>>24)+o|0;a=a<<10|a>>>22;A=H+1352829926+A+(G^(C|~I))|0;A=(A<<6|A>>>26)+E|0;C=C<<10|C>>>22;o=z+1518500249+o+(j&h|a&~j)|0;o=(o<<7|o>>>25)+J|0;h=h<<10|h>>>22;E=y+1548603684+E+(A&C|G&~C)|0;E=(E<<9|E>>>23)+I|0;G=G<<10|G>>>22;J=x+1518500249+J+(o&j|h&~o)|0;J=(J<<6|J>>>26)+a|0;j=j<<10|j>>>22;I=l+1548603684+I+(E&G|A&~G)|0;I=(I<<13|I>>>19)+C|0;A=A<<10|A>>>22;a=u+1518500249+a+(J&o|j&~J)|0;a=(a<<8|a>>>24)+h|0;o=o<<10|o>>>22;C=f+1548603684+C+(I&A|E&~A)|0;C=(C<<15|C>>>17)+G|0;E=E<<10|E>>>22;h=D+1518500249+h+(a&J|o&~a)|0;h=(h<<13|h>>>19)+j|0;J=J<<10|J>>>22;G=z+1548603684+G+(C&E|I&~E)|0;G=(G<<7|G>>>25)+A|0;I=I<<10|I>>>22;j=F+1518500249+j+(h&a|J&~h)|0;j=(j<<11|j>>>21)+o|0;a=a<<10|a>>>22;A=s+1548603684+A+(G&I|C&~I)|0;A=(A<<12|A>>>20)+E|0;C=C<<10|C>>>22;o=y+1518500249+o+(j&h|a&~j)|0;o=(o<<9|o>>>23)+J|0;h=h<<10|h>>>22;E=u+1548603684+E+(A&C|G&~C)|0;E=(E<<8|E>>>24)+I|0;G=G<<10|G>>>22;J=w+1518500249+J+(o&j|h&~o)|0;J=(J<<7|J>>>25)+a|0;j=j<<10|j>>>22;I=t+1548603684+I+(E&G|A&~G)|0;I=(I<<9|I>>>23)+C|0;A=A<<10|A>>>22;a=f+1518500249+a+(J&o|j&~J)|0;a=(a<<15|a>>>17)+h|0;o=o<<10|o>>>22;C=F+1548603684+C+(I&A|E&~A)|0;C=(C<<11|C>>>21)+G|0;E=E<<10|E>>>22;h=H+1518500249+h+(a&J|o&~a)|0;h=(h<<7|h>>>25)+j|0;J=J<<10|J>>>22;G=m+1548603684+G+(C&E|I&~E)|0;G=(G<<7|G>>>25)+A|0;I=I<<10|I>>>22;j=s+1518500249+j+(h&a|J&~h)|0;j=(j<<12|j>>>20)+o|0;a=a<<10|a>>>22;A=w+1548603684+A+(G&I|C&~I)|0;A=(A<<7|A>>>25)+E|0;C=C<<10|C>>>22;o=i+1518500249+o+(j&h|a&~j)|0;o=(o<<15|o>>>17)+J|0;h=h<<10|h>>>22;E=B+1548603684+E+(A&C|G&~C)|0;E=(E<<12|E>>>20)+I|0;G=G<<10|G>>>22;J=t+1518500249+J+(o&j|h&~o)|0;J=(J<<9|J>>>23)+a|0;j=j<<10|j>>>22;I=H+1548603684+I+(E&G|A&~G)|0;I=(I<<7|I>>>25)+C|0;A=A<<10|A>>>22;a=v+1518500249+a+(J&o|j&~J)|0;a=(a<<11|a>>>21)+h|0;o=o<<10|o>>>22;C=x+1548603684+C+(I&A|E&~A)|0;C=(C<<6|C>>>26)+G|0;E=E<<10|E>>>22;h=m+1518500249+h+(a&J|o&~a)|0;h=(h<<7|h>>>25)+j|0;J=J<<10|J>>>22;G=i+1548603684+G+(C&E|I&~E)|0;G=(G<<15|G>>>17)+A|0;I=I<<10|I>>>22;j=l+1518500249+j+(h&a|J&~h)|0;j=(j<<13|j>>>19)+o|0;a=a<<10|a>>>22;A=D+1548603684+A+(G&I|C&~I)|0;A=(A<<13|A>>>19)+E|0;C=C<<10|C>>>22;q=~j;o=B+1518500249+o+(j&h|a&q)|0;o=(o<<12|o>>>20)+J|0;h=h<<10|h>>>22;E=v+1548603684+E+(A&C|G&~C)|0;E=(E<<11|E>>>21)+I|0;G=G<<10|G>>>22;q=f+1859775393+J+((o|q)^h)|0;q=(q<<11|q>>>21)+a|0;j=j<<10|j>>>22;I=w+1836072691+I+((E|~A)^G)|0;I=(I<<9|I>>>23)+C|0;A=A<<10|A>>>22;a=F+1859775393+a+((q|~o)^j)|0;a=(a<<13|a>>>19)+h|0;o=o<<10|o>>>22;C=t+1836072691+C+((I|~E)^A)|0;C=(C<<7|C>>>25)+G|0;E=E<<10|E>>>22;h=m+1859775393+h+((a|~q)^o)|0;h=(h<<6|h>>>26)+j|0;q=q<<10|q>>>22;G=D+1836072691+G+((C|~I)^E)|0;G=(G<<15|G>>>17)+A|0;I=I<<10|I>>>22;j=x+1859775393+j+((h|~a)^q)|0;j=(j<<7|j>>>25)+o|0;a=a<<10|a>>>22;A=f+1836072691+A+((G|~C)^I)|0;A=(A<<11|A>>>21)+E|0;C=C<<10|C>>>22;o=i+1859775393+o+((j|~h)^a)|0;o=(o<<14|o>>>18)+q|0;h=h<<10|h>>>22;E=z+1836072691+E+((A|~G)^C)|0;E=(E<<8|E>>>24)+I|0;G=G<<10|G>>>22;q=w+1859775393+q+((o|~j)^h)|0;q=(q<<9|q>>>23)+a|0;j=j<<10|j>>>22;I=m+1836072691+I+((E|~A)^G)|0;I=(I<<6|I>>>26)+C|0;A=A<<10|A>>>22;a=B+1859775393+a+((q|~o)^j)|0;a=(a<<13|a>>>19)+h|0;o=o<<10|o>>>22;C=y+1836072691+C+((I|~E)^A)|0;C=(C<<6|C>>>26)+G|0;E=E<<10|E>>>22;h=D+1859775393+h+((a|~q)^o)|0;h=(h<<15|h>>>17)+j|0;q=q<<10|q>>>22;G=i+1836072691+G+((C|~I)^E)|0;G=(G<<14|G>>>18)+A|0;I=I<<10|I>>>22;j=v+1859775393+j+((h|~a)^q)|0;j=(j<<14|j>>>18)+o|0;a=a<<10|a>>>22;A=l+1836072691+A+((G|~C)^I)|0;A=(A<<12|A>>>20)+E|0;C=C<<10|C>>>22;o=z+1859775393+o+((j|~h)^a)|0;o=(o<<8|o>>>24)+q|0;h=h<<10|h>>>22;E=B+1836072691+E+((A|~G)^C)|0;E=(E<<13|E>>>19)+I|0;G=G<<10|G>>>22;q=s+1859775393+q+((o|~j)^h)|0;q=(q<<13|q>>>19)+a|0;j=j<<10|j>>>22;I=H+1836072691+I+((E|~A)^G)|0;I=(I<<5|I>>>27)+C|0;A=A<<10|A>>>22;a=y+1859775393+a+((q|~o)^j)|0;a=(a<<6|a>>>26)+h|0;o=o<<10|o>>>22;C=v+1836072691+C+((I|~E)^A)|0;C=(C<<14|C>>>18)+G|0;E=E<<10|E>>>22;h=u+1859775393+h+((a|~q)^o)|0;h=(h<<5|h>>>27)+j|0;q=q<<10|q>>>22;G=F+1836072691+G+((C|~I)^E)|0;G=(G<<13|G>>>19)+A|0;I=I<<10|I>>>22;j=l+1859775393+j+((h|~a)^q)|0;j=(j<<12|j>>>20)+o|0;a=a<<10|a>>>22;A=s+1836072691+A+((G|~C)^I)|0;A=(A<<13|A>>>19)+E|0;C=C<<10|C>>>22;o=t+1859775393+o+((j|~h)^a)|0;o=(o<<7|o>>>25)+q|0;h=h<<10|h>>>22;E=x+1836072691+E+((A|~G)^C)|0;E=(E<<7|E>>>25)+I|0;G=G<<10|G>>>22;q=H+1859775393+q+((o|~j)^h)|0;q=(q<<5|q>>>27)+a|0;j=j<<10|j>>>22;I=u+1836072691+I+((E|~A)^G)|0;I=(I<<5|I>>>27)+C|0;A=A<<10|A>>>22;a=D+-1894007588+a+(q&j|o&~j)|0;a=(a<<11|a>>>21)+h|0;o=o<<10|o>>>22;C=B+2053994217+C+(I&E|A&~I)|0;C=(C<<15|C>>>17)+G|0;E=E<<10|E>>>22;h=i+-1894007588+h+(a&o|q&~o)|0;h=(h<<12|h>>>20)+j|0;q=q<<10|q>>>22;G=y+2053994217+G+(C&I|E&~C)|0;G=(G<<5|G>>>27)+A|0;I=I<<10|I>>>22;j=l+-1894007588+j+(h&q|a&~q)|0;j=(j<<14|j>>>18)+o|0;a=a<<10|a>>>22;A=x+2053994217+A+(G&C|I&~G)|0;A=(A<<8|A>>>24)+E|0;C=C<<10|C>>>22;o=F+-1894007588+o+(j&a|h&~a)|0;o=(o<<15|o>>>17)+q|0;h=h<<10|h>>>22;E=D+2053994217+E+(A&G|C&~A)|0;E=(E<<11|E>>>21)+I|0;G=G<<10|G>>>22;q=s+-1894007588+q+(o&h|j&~h)|0;q=(q<<14|q>>>18)+a|0;j=j<<10|j>>>22;I=f+2053994217+I+(E&A|G&~E)|0;I=(I<<14|I>>>18)+C|0;A=A<<10|A>>>22;a=B+-1894007588+a+(q&j|o&~j)|0;a=(a<<15|a>>>17)+h|0;o=o<<10|o>>>22;C=l+2053994217+C+(I&E|A&~I)|0;C=(C<<14|C>>>18)+G|0;E=E<<10|E>>>22;h=H+-1894007588+h+(a&o|q&~o)|0;h=(h<<9|h>>>23)+j|0;q=q<<10|q>>>22;G=w+2053994217+G+(C&I|E&~C)|0;G=(G<<6|G>>>26)+A|0;I=I<<10|I>>>22;j=x+-1894007588+j+(h&q|a&~q)|0;j=(j<<8|j>>>24)+o|0;a=a<<10|a>>>22;A=s+2053994217+A+(G&C|I&~G)|0;A=(A<<14|A>>>18)+E|0;C=C<<10|C>>>22;o=u+-1894007588+o+(j&a|h&~a)|0;o=(o<<9|o>>>23)+q|0;h=h<<10|h>>>22;E=t+2053994217+E+(A&G|C&~A)|0;E=(E<<6|E>>>26)+I|0;G=G<<10|G>>>22;q=f+-1894007588+q+(o&h|j&~h)|0;q=(q<<14|q>>>18)+a|0;j=j<<10|j>>>22;I=H+2053994217+I+(E&A|G&~E)|0;I=(I<<9|I>>>23)+C|0;A=A<<10|A>>>22;a=z+-1894007588+a+(q&j|o&~j)|0;a=(a<<5|a>>>27)+h|0;o=o<<10|o>>>22;C=v+2053994217+C+(I&E|A&~I)|0;C=(C<<12|C>>>20)+G|0;E=E<<10|E>>>22;h=w+-1894007588+h+(a&o|q&~o)|0;h=(h<<6|h>>>26)+j|0;q=q<<10|q>>>22;G=u+2053994217+G+(C&I|E&~C)|0;G=(G<<9|G>>>23)+A|0;I=I<<10|I>>>22;j=m+-1894007588+j+(h&q|a&~q)|0;j=(j<<8|j>>>24)+o|0;a=a<<10|a>>>22;A=i+2053994217+A+(G&C|I&~G)|0;A=(A<<12|A>>>20)+E|0;C=C<<10|C>>>22;o=t+-1894007588+o+(j&a|h&~a)|0;o=(o<<6|o>>>26)+q|0;h=h<<10|h>>>22;E=z+2053994217+E+(A&G|C&~A)|0;E=(E<<5|E>>>27)+I|0;G=G<<10|G>>>22;q=y+-1894007588+q+(o&h|j&~h)|0;q=(q<<5|q>>>27)+a|0;j=j<<10|j>>>22;I=F+2053994217+I+(E&A|G&~E)|0;I=(I<<15|I>>>17)+C|0;A=A<<10|A>>>22;a=v+-1894007588+a+(q&j|o&~j)|0;a=(a<<12|a>>>20)+h|0;o=o<<10|o>>>22;C=m+2053994217+C+(I&E|A&~I)|0;C=(C<<8|C>>>24)+G|0;E=E<<10|E>>>22;h=x+-1454113458+h+(a^(q|~o))|0;h=(h<<9|h>>>23)+j|0;q=q<<10|q>>>22;G=G+H+(I^E^C)|0;G=(G<<8|G>>>24)+A|0;I=I<<10|I>>>22;j=s+-1454113458+j+(h^(a|~q))|0;j=(j<<15|j>>>17)+o|0;a=a<<10|a>>>22;A=A+w+(C^I^G)|0;A=(A<<5|A>>>27)+E|0;C=C<<10|C>>>22;o=t+-1454113458+o+(j^(h|~a))|0;o=(o<<5|o>>>27)+q|0;h=h<<10|h>>>22;E=E+F+(G^C^A)|0;E=(E<<12|E>>>20)+I|0;G=G<<10|G>>>22;q=i+-1454113458+q+(o^(j|~h))|0;q=(q<<11|q>>>21)+a|0;j=j<<10|j>>>22;x=I+x+(A^G^E)|0;x=(x<<9|x>>>23)+C|0;A=A<<10|A>>>22;a=z+-1454113458+a+(q^(o|~j))|0;a=(a<<6|a>>>26)+h|0;o=o<<10|o>>>22;C=C+D+(E^A^x)|0;C=(C<<12|C>>>20)+G|0;E=E<<10|E>>>22;h=H+-1454113458+h+(a^(q|~o))|0;h=(h<<8|h>>>24)+j|0;q=q<<10|q>>>22;t=G+t+(x^E^C)|0;t=(t<<5|t>>>27)+A|0;x=x<<10|x>>>22;j=v+-1454113458+j+(h^(a|~q))|0;j=(j<<13|j>>>19)+o|0;a=a<<10|a>>>22;A=A+B+(C^x^t)|0;A=(A<<14|A>>>18)+E|0;C=C<<10|C>>>22;o=F+-1454113458+o+(j^(h|~a))|0;o=(o<<12|o>>>20)+q|0;h=h<<10|h>>>22;z=E+z+(t^C^A)|0;z=(z<<6|z>>>26)+x|0;t=t<<10|t>>>22;q=m+-1454113458+q+(o^(j|~h))|0;q=(q<<5|q>>>27)+a|0;j=j<<10|j>>>22;x=x+y+(A^t^z)|0;x=(x<<8|x>>>24)+C|0;A=A<<10|A>>>22;a=D+-1454113458+a+(q^(o|~j))|0;a=(a<<12|a>>>20)+h|0;o=o<<10|o>>>22;v=C+v+(z^A^x)|0;v=(v<<13|v>>>19)+t|0;z=z<<10|z>>>22;h=f+-1454113458+h+(a^(q|~o))|0;h=(h<<13|h>>>19)+j|0;q=q<<10|q>>>22;t=t+u+(x^z^v)|0;t=(t<<6|t>>>26)+A|0;x=x<<10|x>>>22;j=B+-1454113458+j+(h^(a|~q))|0;j=(j<<14|j>>>18)+o|0;a=a<<10|a>>>22;m=A+m+(v^x^t)|0;m=(m<<5|m>>>27)+z|0;v=v<<10|v>>>22;o=l+-1454113458+o+(j^(h|~a))|0;o=(o<<11|o>>>21)+q|0;h=h<<10|h>>>22;s=z+s+(t^v^m)|0;s=(s<<15|s>>>17)+x|0;t=t<<10|t>>>22;q=y+-1454113458+q+(o^(j|~h))|0;q=(q<<8|q>>>24)+a|0;j=j<<10|j>>>22;f=x+f+(m^t^s)|0;f=(f<<13|f>>>19)+v|0;m=m<<10|m>>>22;a=w+-1454113458+a+(q^(o|~j))|0;a=(a<<5|a>>>27)+h|0;o=o<<10|o>>>22;i=v+i+(s^m^f)|0;i=(i<<11|i>>>21)+t|0;s=s<<10|s>>>22;h=u+-1454113458+h+(a^(q|~o))|0;l=t+l+(f^s^i)|0;c[p>>2]=s+r+(q<<10|q>>>22);c[n>>2]=m+(c[k>>2]|0)+o;c[k>>2]=j+(c[g>>2]|0)+m+(l<<11|l>>>21);c[g>>2]=j+(c[b>>2]|0)+i+(h<<6|h>>>26);c[b>>2]=(f<<10|f>>>22)+e+a;return}function yb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0;if(d|0){h=c[a>>2]|0;e=h&63;f=64-e|0;h=h+d|0;c[a>>2]=h;if(h>>>0>>0){h=a+4|0;c[h>>2]=(c[h>>2]|0)+1}if(!((e|0)==0|f>>>0>d>>>0)){tc(a+28+e|0,b|0,f|0)|0;xb(a,a+28|0);e=0;b=b+f|0;d=d-f|0}if(d>>>0>63){g=d+-64|0;h=g&-64;f=b+(h+64)|0;while(1){xb(a,b);d=d+-64|0;if(d>>>0<=63)break;else b=b+64|0}b=f;d=g-h|0}if(d|0)tc(a+28+e|0,b|0,d|0)|0}return}function zb(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0;e=i;i=i+16|0;f=e;g=c[b>>2]|0;h=c[b+4>>2]|0;a[f>>0]=g<<3;a[f+1>>0]=g>>>5;a[f+2>>0]=g>>>13;a[f+3>>0]=g>>>21;a[f+4>>0]=h<<3|g>>>29;a[f+5>>0]=h>>>5;a[f+6>>0]=h>>>13;a[f+7>>0]=h>>>21;g=g&63;yb(b,38733,(g>>>0<56?56:120)-g|0);yb(b,f,8);f=b+8|0;a[d>>0]=c[f>>2];a[d+1>>0]=(c[f>>2]|0)>>>8;a[d+2>>0]=(c[f>>2]|0)>>>16;a[d+3>>0]=(c[f>>2]|0)>>>24;f=b+12|0;a[d+4>>0]=c[f>>2];a[d+5>>0]=(c[f>>2]|0)>>>8;a[d+6>>0]=(c[f>>2]|0)>>>16;a[d+7>>0]=(c[f>>2]|0)>>>24;f=b+16|0;a[d+8>>0]=c[f>>2];a[d+9>>0]=(c[f>>2]|0)>>>8;a[d+10>>0]=(c[f>>2]|0)>>>16;a[d+11>>0]=(c[f>>2]|0)>>>24;f=b+20|0;a[d+12>>0]=c[f>>2];a[d+13>>0]=(c[f>>2]|0)>>>8;a[d+14>>0]=(c[f>>2]|0)>>>16;a[d+15>>0]=(c[f>>2]|0)>>>24;b=b+24|0;a[d+16>>0]=c[b>>2];a[d+17>>0]=(c[b>>2]|0)>>>8;a[d+18>>0]=(c[b>>2]|0)>>>16;a[d+19>>0]=(c[b>>2]|0)>>>24;i=e;return}function Ab(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0;h=i;i=i+96|0;e=h;f=e+8|0;g=e;j=g+92|0;do{c[g>>2]=0;g=g+4|0}while((g|0)<(j|0));c[f>>2]=1732584193;c[e+12>>2]=-271733879;c[e+16>>2]=-1732584194;c[e+20>>2]=271733878;c[e+24>>2]=-1009589776;yb(e,a,b);zb(e,d);i=h;return}function Bb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0;y=i;i=i+64|0;t=y;u=c[a>>2]|0;v=a+4|0;w=a+8|0;x=a+12|0;q=a+16|0;r=a+20|0;s=a+24|0;p=a+28|0;g=0;o=u;a=c[p>>2]|0;h=c[s>>2]|0;j=c[r>>2]|0;k=c[q>>2]|0;e=c[x>>2]|0;l=c[w>>2]|0;f=c[v>>2]|0;while(1){n=((k>>>6|k<<26)^(k>>>11|k<<21)^(k>>>25|k<<7))+a+(h&~k^j&k)+(c[37828+(g<<2)>>2]|0)|0;a=c[b>>2]|0;c[t+(g<<2)>>2]=a;a=n+a|0;e=a+e|0;a=((o>>>2|o<<30)^(o>>>13|o<<19)^(o>>>22|o<<10))+(o&(l^f)^l&f)+a|0;g=g+1|0;if((g|0)==16){n=16;m=a;g=e;a=l;e=o;break}else{C=o;B=f;A=l;z=k;m=j;n=h;b=b+4|0;o=a;k=e;f=C;l=B;e=A;j=z;h=m;a=n}}while(1){A=n;n=n+1|0;z=c[t+((n&15)<<2)>>2]|0;b=c[t+((A+14&15)<<2)>>2]|0;C=((g>>>6|g<<26)^(g>>>11|g<<21)^(g>>>25|g<<7))+h+(j&~g^k&g)+(c[37828+(A<<2)>>2]|0)|0;B=t+((A&15)<<2)|0;b=((z>>>18|z<<14)^z>>>3^(z>>>7|z<<25))+(c[t+((A+9&15)<<2)>>2]|0)+(c[B>>2]|0)+((b>>>19|b<<13)^b>>>10^(b>>>17|b<<15))|0;c[B>>2]=b;b=C+b|0;a=b+a|0;b=((m>>>2|m<<30)^(m>>>13|m<<19)^(m>>>22|m<<10))+(m&(f^e)^f&e)+b|0;if((n|0)==64)break;else{o=m;z=e;A=f;B=g;C=k;h=j;m=b;g=a;e=o;f=z;a=A;k=B;j=C}}c[d>>2]=u+b;c[d+4>>2]=(c[v>>2]|0)+m;c[d+8>>2]=(c[w>>2]|0)+e;c[d+12>>2]=(c[x>>2]|0)+f;c[d+16>>2]=(c[q>>2]|0)+a;c[d+20>>2]=(c[r>>2]|0)+g;c[d+24>>2]=(c[s>>2]|0)+k;c[d+28>>2]=(c[p>>2]|0)+j;i=y;return}function Cb(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0;do if(e|0){n=b+32|0;g=n;h=c[g>>2]|0;g=c[g+4>>2]|0;f=mc(h|0,g|0,3)|0;f=f&63;if(f){i=64-f|0;j=b+40|0;f=j+f|0;if(i>>>0>e>>>0){tc(f|0,d|0,e|0)|0;b=qc(h|0,g|0,e<<3|0,0)|0;c[n>>2]=b;c[n+4>>2]=C;break}tc(f|0,d|0,i|0)|0;m=qc(h|0,g|0,i<<3|0,0)|0;f=n;c[f>>2]=m;c[f+4>>2]=C;e=e-i|0;f=0;do{m=b+40+(f<<2)|0;c[m>>2]=sc(c[m>>2]|0)|0;f=f+1|0}while((f|0)!=16);Bb(b,j,b);d=d+i|0}if(e>>>0>63){j=b+40|0;l=e+-64|0;m=l&-64;k=m+64|0;i=d;while(1){f=j;g=i;h=f+64|0;do{a[f>>0]=a[g>>0]|0;f=f+1|0;g=g+1|0}while((f|0)<(h|0));f=0;do{h=b+40+(f<<2)|0;c[h>>2]=sc(c[h>>2]|0)|0;f=f+1|0}while((f|0)!=16);Bb(b,j,b);g=n;g=qc(c[g>>2]|0,c[g+4>>2]|0,512,0)|0;h=n;c[h>>2]=g;c[h+4>>2]=C;e=e+-64|0;if(e>>>0<=63)break;else i=i+64|0}d=d+k|0;e=l-m|0}if(e|0){tc(b+40|0,d|0,e|0)|0;b=n;b=qc(c[b>>2]|0,c[b+4>>2]|0,e<<3|0,0)|0;c[n>>2]=b;c[n+4>>2]=C}}while(0);return}function Db(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0;if(d){h=b+32|0;f=h;f=mc(c[f>>2]|0,c[f+4>>2]|0,3)|0;f=f&63;e=f+1|0;g=b+40|0;a[g+f>>0]=-128;if(e>>>0>56){lc(g+e|0,0,f^63|0)|0;e=0;do{f=b+40+(e<<2)|0;c[f>>2]=sc(c[f>>2]|0)|0;e=e+1|0}while((e|0)!=16);Bb(b,g,b);e=0}lc(g+e|0,0,56-e|0)|0;e=0;do{f=b+40+(e<<2)|0;c[f>>2]=sc(c[f>>2]|0)|0;e=e+1|0}while((e|0)!=14);e=c[h>>2]|0;c[b+96>>2]=c[h+4>>2];c[b+100>>2]=e;Bb(b,g,b);e=0;do{h=b+(e<<2)|0;c[h>>2]=sc(c[h>>2]|0)|0;e=e+1|0}while((e|0)!=8);e=d;f=b;g=e+32|0;do{a[e>>0]=a[f>>0]|0;e=e+1|0;f=f+1|0}while((e|0)<(g|0))}e=b;g=e+104|0;do{c[e>>2]=0;e=e+4|0}while((e|0)<(g|0));return}function Eb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0;g=i;i=i+112|0;e=g;c[e>>2]=c[9449];c[e+4>>2]=c[9450];c[e+8>>2]=c[9451];c[e+12>>2]=c[9452];c[e+16>>2]=c[9453];c[e+20>>2]=c[9454];c[e+24>>2]=c[9455];c[e+28>>2]=c[9456];f=e+32|0;h=f+72|0;do{c[f>>2]=0;f=f+4|0}while((f|0)<(h|0));Cb(e,a,b);Db(e,d);i=g;return}function Fb(a){a=a|0;var b=0,d=0,e=0;if(a|0){b=a;d=8;e=b+64|0;do{c[b>>2]=c[d>>2];b=b+4|0;d=d+4|0}while((b|0)<(e|0));lc(a+64|0,0,144)|0}return}function Gb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0,X=0,Y=0,Z=0,_=0;L=i;i=i+128|0;F=L;K=a;J=c[K>>2]|0;K=c[K+4>>2]|0;B=a+8|0;w=B;D=a+16|0;e=D;E=a+24|0;f=E;G=a+32|0;p=G;H=a+40|0;q=H;I=a+48|0;m=I;A=a+56|0;h=A;j=0;l=J;u=K;t=c[w>>2]|0;z=c[e>>2]|0;w=c[w+4>>2]|0;a=c[e+4>>2]|0;e=c[f>>2]|0;f=c[f+4>>2]|0;o=c[p>>2]|0;p=c[p+4>>2]|0;g=c[h>>2]|0;h=c[h+4>>2]|0;r=c[q>>2]|0;q=c[q+4>>2]|0;k=c[m>>2]|0;m=c[m+4>>2]|0;while(1){v=mc(o|0,p|0,14)|0;N=C;x=nc(o|0,p|0,50)|0;N=N|C;y=mc(o|0,p|0,18)|0;O=C;M=nc(o|0,p|0,46)|0;O=N^(O|C);N=mc(o|0,p|0,41)|0;n=C;s=nc(o|0,p|0,23)|0;n=qc((v|x)^(y|M)^(N|s)|0,O^(n|C)|0,g|0,h|0)|0;n=qc(n|0,C|0,k&~o^r&o|0,m&~p^q&p|0)|0;O=72+(j<<3)|0;O=qc(n|0,C|0,c[O>>2]|0,c[O+4>>2]|0)|0;n=b;g=c[n>>2]|0;n=c[n+4>>2]|0;s=F+(j<<3)|0;c[s>>2]=g;c[s+4>>2]=n;n=qc(O|0,C|0,g|0,n|0)|0;g=C;O=mc(l|0,u|0,28)|0;s=C;N=nc(l|0,u|0,36)|0;s=s|C;M=mc(l|0,u|0,34)|0;y=C;h=nc(l|0,u|0,30)|0;y=s^(y|C);s=mc(l|0,u|0,39)|0;x=C;v=nc(l|0,u|0,25)|0;x=qc((O|N)^(M|h)^(s|v)|0,y^(x|C)|0,l&(z^t)^z&t|0,u&(a^w)^a&w|0)|0;y=C;e=qc(n|0,g|0,e|0,f|0)|0;f=C;g=qc(x|0,y|0,n|0,g|0)|0;n=C;j=j+1|0;if((j|0)==16){y=16;x=e;v=f;s=p;p=g;j=t;h=u;g=w;b=z;break}else{x=p;y=o;h=m;M=k;N=u;O=l;b=b+8|0;l=g;u=n;o=e;p=f;m=q;k=r;q=x;r=y;g=M;f=a;e=z;a=w;w=N;z=t;t=O}}while(1){t=y;y=y+1|0;T=F+((y&15)<<3)|0;W=c[T>>2]|0;T=c[T+4>>2]|0;S=mc(W|0,T|0,1)|0;Q=C;R=nc(W|0,T|0,63)|0;Q=Q|C;V=mc(W|0,T|0,8)|0;O=C;U=nc(W|0,T|0,56)|0;O=O|C;T=mc(W|0,T|0,7)|0;Q=O^C^Q;O=F+((t+14&15)<<3)|0;W=c[O>>2]|0;O=c[O+4>>2]|0;u=mc(W|0,O|0,19)|0;e=C;f=nc(W|0,O|0,45)|0;e=e|C;N=mc(W|0,O|0,61)|0;_=C;w=nc(W|0,O|0,3)|0;_=_|C;O=mc(W|0,O|0,6)|0;e=_^C^e;_=mc(x|0,v|0,14)|0;W=C;Z=nc(x|0,v|0,50)|0;W=W|C;Y=mc(x|0,v|0,18)|0;P=C;X=nc(x|0,v|0,46)|0;P=W^(P|C);W=mc(x|0,v|0,41)|0;z=C;M=nc(x|0,v|0,23)|0;m=qc((_|Z)^(Y|X)^(W|M)|0,P^(z|C)|0,k|0,m|0)|0;m=qc(m|0,C|0,r&~x^o&x|0,q&~v^s&v|0)|0;z=72+(t<<3)|0;z=qc(m|0,C|0,c[z>>2]|0,c[z+4>>2]|0)|0;m=C;P=F+((t+9&15)<<3)|0;t=F+((t&15)<<3)|0;M=t;k=c[M>>2]|0;M=c[M+4>>2]|0;P=qc((V|U)^T^(S|R)|0,Q|0,c[P>>2]|0,c[P+4>>2]|0)|0;M=qc(P|0,C|0,k|0,M|0)|0;e=qc(M|0,C|0,(N|w)^O^(u|f)|0,e|0)|0;f=C;c[t>>2]=e;c[t+4>>2]=f;f=qc(z|0,m|0,e|0,f|0)|0;e=C;m=mc(p|0,n|0,28)|0;z=C;t=nc(p|0,n|0,36)|0;z=z|C;u=mc(p|0,n|0,34)|0;O=C;w=nc(p|0,n|0,30)|0;O=z^(O|C);z=mc(p|0,n|0,39)|0;N=C;M=nc(p|0,n|0,25)|0;N=qc((m|t)^(u|w)^(z|M)|0,O^(N|C)|0,p&(j^l)^j&l|0,n&(g^h)^g&h|0)|0;O=C;a=qc(f|0,e|0,b|0,a|0)|0;b=C;e=qc(N|0,O|0,f|0,e|0)|0;f=C;if((y|0)==80)break;else{X=n;Y=p;Z=v;_=x;m=q;k=r;x=a;v=b;p=e;n=f;a=g;b=j;g=h;h=X;j=l;l=Y;q=s;r=o;s=Z;o=_}}_=qc(J|0,K|0,e|0,f|0)|0;Z=d;c[Z>>2]=_;c[Z+4>>2]=C;Z=B;Z=qc(c[Z>>2]|0,c[Z+4>>2]|0,p|0,n|0)|0;_=d+8|0;c[_>>2]=Z;c[_+4>>2]=C;_=D;_=qc(c[_>>2]|0,c[_+4>>2]|0,l|0,h|0)|0;Z=d+16|0;c[Z>>2]=_;c[Z+4>>2]=C;Z=E;Z=qc(c[Z>>2]|0,c[Z+4>>2]|0,j|0,g|0)|0;_=d+24|0;c[_>>2]=Z;c[_+4>>2]=C;_=G;_=qc(c[_>>2]|0,c[_+4>>2]|0,a|0,b|0)|0;Z=d+32|0;c[Z>>2]=_;c[Z+4>>2]=C;Z=H;Z=qc(c[Z>>2]|0,c[Z+4>>2]|0,x|0,v|0)|0;_=d+40|0;c[_>>2]=Z;c[_+4>>2]=C;_=I;_=qc(c[_>>2]|0,c[_+4>>2]|0,o|0,s|0)|0;Z=d+48|0;c[Z>>2]=_;c[Z+4>>2]=C;Z=A;Z=qc(c[Z>>2]|0,c[Z+4>>2]|0,r|0,q|0)|0;_=d+56|0;c[_>>2]=Z;c[_+4>>2]=C;i=L;return}function Hb(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0;do if(e|0){o=b+64|0;g=o;h=c[g>>2]|0;g=c[g+4>>2]|0;f=mc(h|0,g|0,3)|0;f=f&127;if(f){i=128-f|0;j=b+80|0;f=j+f|0;if(i>>>0>e>>>0){tc(f|0,d|0,e|0)|0;n=e<<3;m=qc(h|0,g|0,n|0,0)|0;l=C;c[o>>2]=m;c[o+4>>2]=l;if(!(l>>>0<0|(l|0)==0&m>>>0>>0))break;o=b+72|0;b=o;b=qc(c[b>>2]|0,c[b+4>>2]|0,1,0)|0;c[o>>2]=b;c[o+4>>2]=C;break}tc(f|0,d|0,i|0)|0;n=i<<3;m=qc(h|0,g|0,n|0,0)|0;l=C;k=o;c[k>>2]=m;c[k+4>>2]=l;if(l>>>0<0|(l|0)==0&m>>>0>>0){n=b+72|0;m=n;m=qc(c[m>>2]|0,c[m+4>>2]|0,1,0)|0;c[n>>2]=m;c[n+4>>2]=C}e=e-i|0;f=0;do{n=b+80+(f<<3)|0;m=n;m=ma(c[m>>2]|0,c[m+4>>2]|0)|0;c[n>>2]=m;c[n+4>>2]=C;f=f+1|0}while((f|0)!=16);Gb(b,j,b);d=d+i|0}if(e>>>0>127){j=b+80|0;k=b+72|0;m=e+-128|0;n=m&-128;l=n+128|0;i=d;while(1){f=j;g=i;h=f+128|0;do{a[f>>0]=a[g>>0]|0;f=f+1|0;g=g+1|0}while((f|0)<(h|0));f=0;do{h=b+80+(f<<3)|0;g=h;g=ma(c[g>>2]|0,c[g+4>>2]|0)|0;c[h>>2]=g;c[h+4>>2]=C;f=f+1|0}while((f|0)!=16);Gb(b,j,b);g=o;h=c[g>>2]|0;g=c[g+4>>2]|0;p=qc(h|0,g|0,1024,0)|0;f=o;c[f>>2]=p;c[f+4>>2]=C;if(g>>>0>4294967295|(g|0)==-1&h>>>0>4294966271){h=k;h=qc(c[h>>2]|0,c[h+4>>2]|0,1,0)|0;p=k;c[p>>2]=h;c[p+4>>2]=C}e=e+-128|0;if(e>>>0<=127)break;else i=i+128|0}d=d+l|0;e=m-n|0}if(e|0?(tc(b+80|0,d|0,e|0)|0,p=e<<3,n=o,n=qc(c[n>>2]|0,c[n+4>>2]|0,p|0,0)|0,m=C,o,c[o>>2]=n,c[o+4>>2]=m,m>>>0<0|(m|0)==0&n>>>0

>>0):0){p=b+72|0;o=p;o=qc(c[o>>2]|0,c[o+4>>2]|0,1,0)|0;c[p>>2]=o;c[p+4>>2]=C}}while(0);return}function Ib(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0;if(d){h=b+64|0;f=h;f=mc(c[f>>2]|0,c[f+4>>2]|0,3)|0;f=f&127;e=f+1|0;g=b+80|0;a[g+f>>0]=-128;if(e>>>0>112){lc(g+e|0,0,f^127|0)|0;e=0;do{f=b+80+(e<<3)|0;i=f;i=ma(c[i>>2]|0,c[i+4>>2]|0)|0;c[f>>2]=i;c[f+4>>2]=C;e=e+1|0}while((e|0)!=16);Gb(b,g,b);e=0}lc(g+e|0,0,112-e|0)|0;e=0;do{i=b+80+(e<<3)|0;f=i;f=ma(c[f>>2]|0,c[f+4>>2]|0)|0;c[i>>2]=f;c[i+4>>2]=C;e=e+1|0}while((e|0)!=14);f=b+72|0;e=c[f+4>>2]|0;i=b+192|0;c[i>>2]=c[f>>2];c[i+4>>2]=e;i=c[h+4>>2]|0;e=b+200|0;c[e>>2]=c[h>>2];c[e+4>>2]=i;Gb(b,g,b);e=0;do{i=b+(e<<3)|0;h=i;h=ma(c[h>>2]|0,c[h+4>>2]|0)|0;c[i>>2]=h;c[i+4>>2]=C;e=e+1|0}while((e|0)!=8);e=d;f=b;g=e+64|0;do{a[e>>0]=a[f>>0]|0;e=e+1|0;f=f+1|0}while((e|0)<(g|0))}lc(b|0,0,208)|0;return}function Jb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0;g=i;i=i+208|0;e=g;f=e;h=8;j=f+64|0;do{c[f>>2]=c[h>>2];f=f+4|0;h=h+4|0}while((f|0)<(j|0));lc(e+64|0,0,144)|0;Hb(e,a,b);Ib(e,d);i=g;return}function Kb(){var a=0,b=0,d=0;d=i;i=i+16|0;b=d;a=c[9714]|0;if(!a){a=bc(38797,38810)|0;c[9714]=a}if((gc(b,1,4,a)|0)==4){i=d;return c[b>>2]|0}else pa(38812,38828,60,38838);return 0}function Lb(a){a=a|0;if(a>>>0>=256)if(a>>>0<65536)a=2;else a=a>>>0<16777216?3:4;else a=1;return a|0}function Mb(b,c){b=b|0;c=c|0;var d=0;if(b>>>0<=16777215)if(b>>>0<=65535){if(b>>>0>255)d=6}else d=4;else{a[c>>0]=b>>>24;c=c+1|0;d=4}if((d|0)==4){a[c>>0]=b>>>16;c=c+1|0;d=6}if((d|0)==6){a[c>>0]=b>>>8;c=c+1|0}a[c>>0]=b;return}function Nb(a){a=a|0;var b=0,d=0;b=i;i=i+16|0;d=b;c[d>>2]=c[a+60>>2];a=Qb(ha(6,d|0)|0)|0;i=b;return a|0}function Ob(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0;m=i;i=i+48|0;h=m+16|0;g=m;f=m+32|0;c[f>>2]=d;j=f+4|0;l=b+48|0;n=c[l>>2]|0;c[j>>2]=e-((n|0)!=0&1);k=b+44|0;c[f+8>>2]=c[k>>2];c[f+12>>2]=n;if(!(c[9715]|0)){c[h>>2]=c[b+60>>2];c[h+4>>2]=f;c[h+8>>2]=2;f=Qb(qa(145,h|0)|0)|0}else{ga(1,b|0);c[g>>2]=c[b+60>>2];c[g+4>>2]=f;c[g+8>>2]=2;f=Qb(qa(145,g|0)|0)|0;ba(0)}if((f|0)>=1){j=c[j>>2]|0;if(f>>>0>j>>>0){g=c[k>>2]|0;h=b+4|0;c[h>>2]=g;c[b+8>>2]=g+(f-j);if(!(c[l>>2]|0))f=e;else{c[h>>2]=g+1;a[d+(e+-1)>>0]=a[g>>0]|0;f=e}}}else{c[b>>2]=c[b>>2]|f&48^16;c[b+8>>2]=0;c[b+4>>2]=0}i=m;return f|0}function Pb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0;f=i;i=i+32|0;g=f;e=f+20|0;c[g>>2]=c[a+60>>2];c[g+4>>2]=0;c[g+8>>2]=b;c[g+12>>2]=e;c[g+16>>2]=d;if((Qb(ja(140,g|0)|0)|0)<0){c[e>>2]=-1;a=-1}else a=c[e>>2]|0;i=f;return a|0}function Qb(a){a=a|0;if(a>>>0>4294963200){c[(Rb()|0)>>2]=0-a;a=-1}return a|0}function Rb(){var a=0;if(!(c[9715]|0))a=38904;else a=c[(uc()|0)+64>>2]|0;return a|0}function Sb(a){a=a|0;if(!(c[a+68>>2]|0))Tb(a);return}function Tb(a){a=a|0;return}function Ub(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0;q=i;i=i+48|0;n=q+16|0;m=q;j=q+32|0;o=a+28|0;h=c[o>>2]|0;c[j>>2]=h;p=a+20|0;h=(c[p>>2]|0)-h|0;c[j+4>>2]=h;c[j+8>>2]=b;c[j+12>>2]=d;k=a+60|0;l=a+44|0;g=2;b=h+d|0;while(1){if(!(c[9715]|0)){c[n>>2]=c[k>>2];c[n+4>>2]=j;c[n+8>>2]=g;f=Qb(ra(146,n|0)|0)|0}else{ga(2,a|0);c[m>>2]=c[k>>2];c[m+4>>2]=j;c[m+8>>2]=g;f=Qb(ra(146,m|0)|0)|0;ba(0)}if((b|0)==(f|0)){b=6;break}if((f|0)<0){b=8;break}b=b-f|0;e=c[j+4>>2]|0;if(f>>>0<=e>>>0)if((g|0)==2){c[o>>2]=(c[o>>2]|0)+f;g=2;h=j}else h=j;else{h=c[l>>2]|0;c[o>>2]=h;c[p>>2]=h;f=f-e|0;g=g+-1|0;h=j+8|0;e=c[j+12>>2]|0}c[h>>2]=(c[h>>2]|0)+f;c[h+4>>2]=e-f;j=h}if((b|0)==6){n=c[l>>2]|0;c[a+16>>2]=n+(c[a+48>>2]|0);a=n;c[o>>2]=a;c[p>>2]=a}else if((b|0)==8){c[a+16>>2]=0;c[o>>2]=0;c[p>>2]=0;c[a>>2]=c[a>>2]|32;if((g|0)==2)d=0;else d=d-(c[j+4>>2]|0)|0}i=q;return d|0}function Vb(a){a=a|0;if(!(c[a+68>>2]|0))Tb(a);return}function Wb(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0;g=i;i=i+80|0;f=g;c[b+36>>2]=3;if((c[b>>2]&64|0)==0?(c[f>>2]=c[b+60>>2],c[f+4>>2]=21505,c[f+8>>2]=g+12,da(54,f|0)|0):0)a[b+75>>0]=-1;f=Ub(b,d,e)|0;i=g;return f|0}function Xb(b){b=b|0;var d=0,e=0;d=b+74|0;e=a[d>>0]|0;a[d>>0]=e+255|e;d=b+20|0;e=b+44|0;if((c[d>>2]|0)>>>0>(c[e>>2]|0)>>>0)va[c[b+36>>2]&7](b,0,0)|0;c[b+16>>2]=0;c[b+28>>2]=0;c[d>>2]=0;d=c[b>>2]|0;if(d&20)if(!(d&4))d=-1;else{c[b>>2]=d|32;d=-1}else{d=c[e>>2]|0;c[b+8>>2]=d;c[b+4>>2]=d;d=0}return d|0}function Yb(a){a=a|0;return 0}function Zb(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,i=0;h=d&255;f=(e|0)!=0;a:do if(f&(b&3|0)!=0){g=d&255;while(1){if((a[b>>0]|0)==g<<24>>24){i=6;break a}b=b+1|0;e=e+-1|0;f=(e|0)!=0;if(!(f&(b&3|0)!=0)){i=5;break}}}else i=5;while(0);if((i|0)==5)if(f)i=6;else e=0;b:do if((i|0)==6){g=d&255;if((a[b>>0]|0)!=g<<24>>24){f=R(h,16843009)|0;c:do if(e>>>0>3)while(1){h=c[b>>2]^f;if((h&-2139062144^-2139062144)&h+-16843009|0)break;b=b+4|0;e=e+-4|0;if(e>>>0<=3){i=11;break c}}else i=11;while(0);if((i|0)==11)if(!e){e=0;break}while(1){if((a[b>>0]|0)==g<<24>>24)break b;b=b+1|0;e=e+-1|0;if(!e){e=0;break}}}}while(0);return (e|0?b:0)|0}function _b(b){b=b|0;var d=0,e=0,f=0;f=b;a:do if(!(f&3))e=4;else{d=f;while(1){if(!(a[b>>0]|0)){b=d;break a}b=b+1|0;d=b;if(!(d&3)){e=4;break}}}while(0);if((e|0)==4){while(1){d=c[b>>2]|0;if(!((d&-2139062144^-2139062144)&d+-16843009))b=b+4|0;else break}if((d&255)<<24>>24)do b=b+1|0;while((a[b>>0]|0)!=0)}return b-f|0}function $b(b,c){b=b|0;c=c|0;b=ac(b,c)|0;return ((a[b>>0]|0)==(c&255)<<24>>24?b:0)|0}function ac(b,d){b=b|0;d=d|0;var e=0,f=0,g=0;f=d&255;a:do if(!f)b=b+(_b(b)|0)|0;else{if(b&3){e=d&255;do{g=a[b>>0]|0;if(g<<24>>24==0?1:g<<24>>24==e<<24>>24)break a;b=b+1|0}while((b&3|0)!=0)}f=R(f,16843009)|0;e=c[b>>2]|0;b:do if(!((e&-2139062144^-2139062144)&e+-16843009))do{g=e^f;if((g&-2139062144^-2139062144)&g+-16843009|0)break b;b=b+4|0;e=c[b>>2]|0}while(!((e&-2139062144^-2139062144)&e+-16843009|0));while(0);e=d&255;while(1){g=a[b>>0]|0;if(g<<24>>24==0?1:g<<24>>24==e<<24>>24)break;else b=b+1|0}}while(0);return b|0}function bc(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0;g=i;i=i+32|0;f=g+16|0;e=g;if(Zb(38847,a[d>>0]|0,4)|0){h=cc(d)|0|32768;c[e>>2]=b;c[e+4>>2]=h;c[e+8>>2]=438;e=Qb(ka(5,e|0)|0)|0;if((e|0)>=0){b=dc(e,d)|0;if(!b){c[f>>2]=e;ha(6,f|0)|0;b=0}}else b=0}else{c[(Rb()|0)>>2]=22;b=0}i=g;return b|0}function cc(b){b=b|0;var c=0,d=0,e=0;d=($b(b,43)|0)==0;c=a[b>>0]|0;d=d?c<<24>>24!=114&1:2;e=($b(b,120)|0)==0;d=e?d:d|128;b=($b(b,101)|0)==0;b=b?d:d|524288;b=c<<24>>24==114?b:b|64;b=c<<24>>24==119?b|512:b;return (c<<24>>24==97?b|1024:b)|0}function dc(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0;o=i;i=i+112|0;n=o+40|0;l=o+24|0;k=o+16|0;g=o;m=o+52|0;f=a[d>>0]|0;if(Zb(38847,f<<24>>24,4)|0){e=hc(1144)|0;if(!e)e=0;else{h=e;j=h+112|0;do{c[h>>2]=0;h=h+4|0}while((h|0)<(j|0));if(!($b(d,43)|0))c[e>>2]=f<<24>>24==114?8:4;if($b(d,101)|0){c[g>>2]=b;c[g+4>>2]=2;c[g+8>>2]=1;ca(221,g|0)|0;f=a[d>>0]|0}if(f<<24>>24==97){c[k>>2]=b;c[k+4>>2]=3;f=ca(221,k|0)|0;if(!(f&1024)){c[l>>2]=b;c[l+4>>2]=4;c[l+8>>2]=f|1024;ca(221,l|0)|0}d=c[e>>2]|128;c[e>>2]=d}else d=c[e>>2]|0;c[e+60>>2]=b;c[e+44>>2]=e+120;c[e+48>>2]=1024;f=e+75|0;a[f>>0]=-1;if((d&8|0)==0?(c[n>>2]=b,c[n+4>>2]=21505,c[n+8>>2]=m,(da(54,n|0)|0)==0):0)a[f>>0]=10;c[e+32>>2]=4;c[e+36>>2]=3;c[e+40>>2]=2;c[e+12>>2]=1;if(!(c[9716]|0))c[e+76>>2]=-1;ea(38888);f=c[9721]|0;c[e+56>>2]=f;if(f|0)c[f+52>>2]=e;c[9721]=e;na(38888)}}else{c[(Rb()|0)>>2]=22;e=0}i=o;return e|0}function ec(a){a=a|0;var b=0,d=0;do if(a){if((c[a+76>>2]|0)<=-1){b=fc(a)|0;break}d=(Yb(a)|0)==0;b=fc(a)|0;if(!d)Tb(a)}else{if(!(c[9549]|0))b=0;else b=ec(c[9549]|0)|0;ea(38888);a=c[9721]|0;if(a)do{if((c[a+76>>2]|0)>-1)d=Yb(a)|0;else d=0;if((c[a+20>>2]|0)>>>0>(c[a+28>>2]|0)>>>0)b=fc(a)|0|b;if(d|0)Tb(a);a=c[a+56>>2]|0}while((a|0)!=0);na(38888)}while(0);return b|0}function fc(a){a=a|0;var b=0,d=0,e=0,f=0,g=0,h=0;b=a+20|0;h=a+28|0;if((c[b>>2]|0)>>>0>(c[h>>2]|0)>>>0?(va[c[a+36>>2]&7](a,0,0)|0,(c[b>>2]|0)==0):0)a=-1;else{d=a+4|0;e=c[d>>2]|0;f=a+8|0;g=c[f>>2]|0;if(e>>>0>>0)va[c[a+40>>2]&7](a,e-g|0,1)|0;c[a+16>>2]=0;c[h>>2]=0;c[b>>2]=0;c[f>>2]=0;c[d>>2]=0;a=0}return a|0}function gc(b,d,e,f){b=b|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,i=0,j=0,k=0,l=0;k=R(e,d)|0;if((c[f+76>>2]|0)>-1)j=Yb(f)|0;else j=0;g=f+74|0;i=a[g>>0]|0;a[g>>0]=i+255|i;g=f+4|0;i=c[g>>2]|0;h=(c[f+8>>2]|0)-i|0;if((h|0)>0){h=h>>>0>>0?h:k;tc(b|0,i|0,h|0)|0;c[g>>2]=i+h;g=k-h|0;b=b+h|0}else g=k;a:do if(!g)l=13;else{i=f+32|0;while(1){if(Xb(f)|0)break;h=va[c[i>>2]&7](f,b,g)|0;if((h+1|0)>>>0<2)break;g=g-h|0;if(!g){l=13;break a}else b=b+h|0}if(j|0)Tb(f);e=((k-g|0)>>>0)/(d>>>0)|0}while(0);if((l|0)==13)if(j)Tb(f);return e|0}function hc(a){a=a|0;var b=0,d=0,e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0;L=i;i=i+16|0;p=L;do if(a>>>0<245){o=a>>>0<11?16:a+11&-8;a=o>>>3;t=c[9727]|0;d=t>>>a;if(d&3|0){a=(d&1^1)+a|0;d=38948+(a<<1<<2)|0;e=d+8|0;f=c[e>>2]|0;g=f+8|0;h=c[g>>2]|0;do if((d|0)!=(h|0)){if(h>>>0<(c[9731]|0)>>>0)fa();b=h+12|0;if((c[b>>2]|0)==(f|0)){c[b>>2]=d;c[e>>2]=h;break}else fa()}else c[9727]=t&~(1<>2]=K|3;K=f+K+4|0;c[K>>2]=c[K>>2]|1;K=g;i=L;return K|0}s=c[9729]|0;if(o>>>0>s>>>0){if(d|0){j=2<>>12&16;a=a>>>j;e=a>>>5&8;a=a>>>e;g=a>>>2&4;a=a>>>g;d=a>>>1&2;a=a>>>d;b=a>>>1&1;b=(e|j|g|d|b)+(a>>>b)|0;a=38948+(b<<1<<2)|0;d=a+8|0;g=c[d>>2]|0;j=g+8|0;e=c[j>>2]|0;do if((a|0)!=(e|0)){if(e>>>0<(c[9731]|0)>>>0)fa();f=e+12|0;if((c[f>>2]|0)==(g|0)){c[f>>2]=a;c[d>>2]=e;k=t;break}else fa()}else{k=t&~(1<>2]=o|3;e=g+o|0;c[e+4>>2]=h|1;c[e+h>>2]=h;if(s|0){f=c[9732]|0;b=s>>>3;d=38948+(b<<1<<2)|0;b=1<>2]|0;if(a>>>0<(c[9731]|0)>>>0)fa();else{l=a;m=b}}else{c[9727]=k|b;l=d;m=d+8|0}c[m>>2]=f;c[l+12>>2]=f;c[f+8>>2]=l;c[f+12>>2]=d}c[9729]=h;c[9732]=e;K=j;i=L;return K|0}l=c[9728]|0;if(l){a=(l&0-l)+-1|0;J=a>>>12&16;a=a>>>J;I=a>>>5&8;a=a>>>I;K=a>>>2&4;a=a>>>K;j=a>>>1&2;a=a>>>j;k=a>>>1&1;k=c[39212+((I|J|K|j|k)+(a>>>k)<<2)>>2]|0;a=k;j=k;k=(c[k+4>>2]&-8)-o|0;while(1){b=c[a+16>>2]|0;if(!b){b=c[a+20>>2]|0;if(!b)break}K=(c[b+4>>2]&-8)-o|0;J=K>>>0>>0;a=b;j=J?b:j;k=J?K:k}f=c[9731]|0;if(j>>>0>>0)fa();h=j+o|0;if(j>>>0>=h>>>0)fa();g=c[j+24>>2]|0;d=c[j+12>>2]|0;do if((d|0)==(j|0)){a=j+20|0;b=c[a>>2]|0;if(!b){a=j+16|0;b=c[a>>2]|0;if(!b){n=0;break}}while(1){d=b+20|0;e=c[d>>2]|0;if(e|0){b=e;a=d;continue}d=b+16|0;e=c[d>>2]|0;if(!e)break;else{b=e;a=d}}if(a>>>0>>0)fa();else{c[a>>2]=0;n=b;break}}else{e=c[j+8>>2]|0;if(e>>>0>>0)fa();b=e+12|0;if((c[b>>2]|0)!=(j|0))fa();a=d+8|0;if((c[a>>2]|0)==(j|0)){c[b>>2]=d;c[a>>2]=e;n=d;break}else fa()}while(0);do if(g|0){b=c[j+28>>2]|0;a=39212+(b<<2)|0;if((j|0)==(c[a>>2]|0)){c[a>>2]=n;if(!n){c[9728]=l&~(1<>>0<(c[9731]|0)>>>0)fa();b=g+16|0;if((c[b>>2]|0)==(j|0))c[b>>2]=n;else c[g+20>>2]=n;if(!n)break}a=c[9731]|0;if(n>>>0>>0)fa();c[n+24>>2]=g;b=c[j+16>>2]|0;do if(b|0)if(b>>>0>>0)fa();else{c[n+16>>2]=b;c[b+24>>2]=n;break}while(0);b=c[j+20>>2]|0;if(b|0)if(b>>>0<(c[9731]|0)>>>0)fa();else{c[n+20>>2]=b;c[b+24>>2]=n;break}}while(0);if(k>>>0<16){K=k+o|0;c[j+4>>2]=K|3;K=j+K+4|0;c[K>>2]=c[K>>2]|1}else{c[j+4>>2]=o|3;c[h+4>>2]=k|1;c[h+k>>2]=k;if(s|0){e=c[9732]|0;b=s>>>3;d=38948+(b<<1<<2)|0;b=1<>2]|0;if(a>>>0<(c[9731]|0)>>>0)fa();else{q=a;r=b}}else{c[9727]=t|b;q=d;r=d+8|0}c[r>>2]=e;c[q+12>>2]=e;c[e+8>>2]=q;c[e+12>>2]=d}c[9729]=k;c[9732]=h}K=j+8|0;i=L;return K|0}}}else if(a>>>0<=4294967231){a=a+11|0;o=a&-8;l=c[9728]|0;if(l){e=0-o|0;a=a>>>8;if(a)if(o>>>0>16777215)k=31;else{r=(a+1048320|0)>>>16&8;D=a<>>16&4;D=D<>>16&2;k=14-(q|r|k)+(D<>>15)|0;k=o>>>(k+7|0)&1|k<<1}else k=0;a=c[39212+(k<<2)>>2]|0;a:do if(!a){d=0;f=0;D=86}else{f=0;j=a;h=o<<((k|0)==31?0:25-(k>>>1)|0);d=0;while(1){a=(c[j+4>>2]&-8)-o|0;if(a>>>0>>0)if(!a){a=j;e=0;d=j;D=90;break a}else{f=j;e=a}a=c[j+20>>2]|0;j=c[j+16+(h>>>31<<2)>>2]|0;d=(a|0)==0|(a|0)==(j|0)?d:a;a=(j|0)==0;if(a){D=86;break}else h=h<<(a&1^1)}}while(0);if((D|0)==86){if((d|0)==0&(f|0)==0){a=2<>>12&16;r=r>>>m;k=r>>>5&8;r=r>>>k;n=r>>>2&4;r=r>>>n;q=r>>>1&2;r=r>>>q;d=r>>>1&1;d=c[39212+((k|m|n|q|d)+(r>>>d)<<2)>>2]|0}if(!d){k=f;j=e}else{a=f;D=90}}if((D|0)==90)while(1){D=0;r=(c[d+4>>2]&-8)-o|0;f=r>>>0>>0;e=f?r:e;a=f?d:a;f=c[d+16>>2]|0;if(f|0){d=f;D=90;continue}d=c[d+20>>2]|0;if(!d){k=a;j=e;break}else D=90}if((k|0)!=0?j>>>0<((c[9729]|0)-o|0)>>>0:0){f=c[9731]|0;if(k>>>0>>0)fa();h=k+o|0;if(k>>>0>=h>>>0)fa();g=c[k+24>>2]|0;d=c[k+12>>2]|0;do if((d|0)==(k|0)){a=k+20|0;b=c[a>>2]|0;if(!b){a=k+16|0;b=c[a>>2]|0;if(!b){s=0;break}}while(1){d=b+20|0;e=c[d>>2]|0;if(e|0){b=e;a=d;continue}d=b+16|0;e=c[d>>2]|0;if(!e)break;else{b=e;a=d}}if(a>>>0>>0)fa();else{c[a>>2]=0;s=b;break}}else{e=c[k+8>>2]|0;if(e>>>0>>0)fa();b=e+12|0;if((c[b>>2]|0)!=(k|0))fa();a=d+8|0;if((c[a>>2]|0)==(k|0)){c[b>>2]=d;c[a>>2]=e;s=d;break}else fa()}while(0);do if(g){b=c[k+28>>2]|0;a=39212+(b<<2)|0;if((k|0)==(c[a>>2]|0)){c[a>>2]=s;if(!s){t=l&~(1<>>0<(c[9731]|0)>>>0)fa();b=g+16|0;if((c[b>>2]|0)==(k|0))c[b>>2]=s;else c[g+20>>2]=s;if(!s){t=l;break}}a=c[9731]|0;if(s>>>0>>0)fa();c[s+24>>2]=g;b=c[k+16>>2]|0;do if(b|0)if(b>>>0>>0)fa();else{c[s+16>>2]=b;c[b+24>>2]=s;break}while(0);b=c[k+20>>2]|0;if(b)if(b>>>0<(c[9731]|0)>>>0)fa();else{c[s+20>>2]=b;c[b+24>>2]=s;t=l;break}else t=l}else t=l;while(0);do if(j>>>0>=16){c[k+4>>2]=o|3;c[h+4>>2]=j|1;c[h+j>>2]=j;b=j>>>3;if(j>>>0<256){d=38948+(b<<1<<2)|0;a=c[9727]|0;b=1<>2]|0;if(a>>>0<(c[9731]|0)>>>0)fa();else{B=a;C=b}}else{c[9727]=a|b;B=d;C=d+8|0}c[C>>2]=h;c[B+12>>2]=h;c[h+8>>2]=B;c[h+12>>2]=d;break}b=j>>>8;if(b)if(j>>>0>16777215)b=31;else{J=(b+1048320|0)>>>16&8;K=b<>>16&4;K=K<>>16&2;b=14-(I|J|b)+(K<>>15)|0;b=j>>>(b+7|0)&1|b<<1}else b=0;d=39212+(b<<2)|0;c[h+28>>2]=b;a=h+16|0;c[a+4>>2]=0;c[a>>2]=0;a=1<>2]=h;c[h+24>>2]=d;c[h+12>>2]=h;c[h+8>>2]=h;break}a=j<<((b|0)==31?0:25-(b>>>1)|0);e=c[d>>2]|0;while(1){if((c[e+4>>2]&-8|0)==(j|0)){D=148;break}d=e+16+(a>>>31<<2)|0;b=c[d>>2]|0;if(!b){D=145;break}else{a=a<<1;e=b}}if((D|0)==145)if(d>>>0<(c[9731]|0)>>>0)fa();else{c[d>>2]=h;c[h+24>>2]=e;c[h+12>>2]=h;c[h+8>>2]=h;break}else if((D|0)==148){b=e+8|0;a=c[b>>2]|0;K=c[9731]|0;if(a>>>0>=K>>>0&e>>>0>=K>>>0){c[a+12>>2]=h;c[b>>2]=h;c[h+8>>2]=a;c[h+12>>2]=e;c[h+24>>2]=0;break}else fa()}}else{K=j+o|0;c[k+4>>2]=K|3;K=k+K+4|0;c[K>>2]=c[K>>2]|1}while(0);K=k+8|0;i=L;return K|0}}}else o=-1;while(0);d=c[9729]|0;if(d>>>0>=o>>>0){b=d-o|0;a=c[9732]|0;if(b>>>0>15){K=a+o|0;c[9732]=K;c[9729]=b;c[K+4>>2]=b|1;c[K+b>>2]=b;c[a+4>>2]=o|3}else{c[9729]=0;c[9732]=0;c[a+4>>2]=d|3;K=a+d+4|0;c[K>>2]=c[K>>2]|1}K=a+8|0;i=L;return K|0}j=c[9730]|0;if(j>>>0>o>>>0){I=j-o|0;c[9730]=I;K=c[9733]|0;J=K+o|0;c[9733]=J;c[J+4>>2]=I|1;c[K+4>>2]=o|3;K=K+8|0;i=L;return K|0}if(!(c[9845]|0)){c[9847]=4096;c[9846]=4096;c[9848]=-1;c[9849]=-1;c[9850]=0;c[9838]=0;a=p&-16^1431655768;c[p>>2]=a;c[9845]=a;a=4096}else a=c[9847]|0;k=o+48|0;l=o+47|0;h=a+l|0;f=0-a|0;m=h&f;if(m>>>0<=o>>>0){K=0;i=L;return K|0}a=c[9837]|0;if(a|0?(B=c[9835]|0,C=B+m|0,C>>>0<=B>>>0|C>>>0>a>>>0):0){K=0;i=L;return K|0}b:do if(!(c[9838]&4)){d=c[9733]|0;c:do if(d){e=39356;while(1){a=c[e>>2]|0;if(a>>>0<=d>>>0?(u=e+4|0,(a+(c[u>>2]|0)|0)>>>0>d>>>0):0)break;a=c[e+8>>2]|0;if(!a){D=172;break c}else e=a}d=h-j&f;if(d>>>0<2147483647){a=rc(d|0)|0;if((a|0)==((c[e>>2]|0)+(c[u>>2]|0)|0)){if((a|0)!=(-1|0)){h=d;g=a;D=190;break b}}else{b=d;D=180}}}else D=172;while(0);do if(((D|0)==172?(g=rc(0)|0,(g|0)!=(-1|0)):0)?(b=g,v=c[9846]|0,w=v+-1|0,b=((w&b|0)==0?0:(w+b&0-v)-b|0)+m|0,v=c[9835]|0,w=b+v|0,b>>>0>o>>>0&b>>>0<2147483647):0){C=c[9837]|0;if(C|0?w>>>0<=v>>>0|w>>>0>C>>>0:0)break;a=rc(b|0)|0;if((a|0)==(g|0)){h=b;D=190;break b}else D=180}while(0);d:do if((D|0)==180){d=0-b|0;do if(k>>>0>b>>>0&(b>>>0<2147483647&(a|0)!=(-1|0))?(x=c[9847]|0,x=l-b+x&0-x,x>>>0<2147483647):0)if((rc(x|0)|0)==(-1|0)){rc(d|0)|0;break d}else{b=x+b|0;break}while(0);if((a|0)!=(-1|0)){h=b;g=a;D=190;break b}}while(0);c[9838]=c[9838]|4;D=187}else D=187;while(0);if((((D|0)==187?m>>>0<2147483647:0)?(A=rc(m|0)|0,y=rc(0)|0,A>>>0>>0&((A|0)!=(-1|0)&(y|0)!=(-1|0))):0)?(z=y-A|0,z>>>0>(o+40|0)>>>0):0){h=z;g=A;D=190}if((D|0)==190){b=(c[9835]|0)+h|0;c[9835]=b;if(b>>>0>(c[9836]|0)>>>0)c[9836]=b;l=c[9733]|0;do if(l){b=39356;while(1){a=c[b>>2]|0;d=b+4|0;e=c[d>>2]|0;if((g|0)==(a+e|0)){D=200;break}f=c[b+8>>2]|0;if(!f)break;else b=f}if(((D|0)==200?(c[b+12>>2]&8|0)==0:0)?l>>>0>>0&l>>>0>=a>>>0:0){c[d>>2]=e+h;K=l+8|0;K=(K&7|0)==0?0:0-K&7;J=l+K|0;K=h-K+(c[9730]|0)|0;c[9733]=J;c[9730]=K;c[J+4>>2]=K|1;c[J+K+4>>2]=40;c[9734]=c[9849];break}b=c[9731]|0;if(g>>>0>>0){c[9731]=g;j=g}else j=b;a=g+h|0;b=39356;while(1){if((c[b>>2]|0)==(a|0)){D=208;break}b=c[b+8>>2]|0;if(!b){a=39356;break}}if((D|0)==208)if(!(c[b+12>>2]&8)){c[b>>2]=g;n=b+4|0;c[n>>2]=(c[n>>2]|0)+h;n=g+8|0;n=g+((n&7|0)==0?0:0-n&7)|0;b=a+8|0;b=a+((b&7|0)==0?0:0-b&7)|0;m=n+o|0;k=b-n-o|0;c[n+4>>2]=o|3;do if((b|0)!=(l|0)){if((b|0)==(c[9732]|0)){K=(c[9729]|0)+k|0;c[9729]=K;c[9732]=m;c[m+4>>2]=K|1;c[m+K>>2]=K;break}a=c[b+4>>2]|0;if((a&3|0)==1){h=a&-8;f=a>>>3;e:do if(a>>>0>=256){g=c[b+24>>2]|0;e=c[b+12>>2]|0;do if((e|0)==(b|0)){e=b+16|0;d=e+4|0;a=c[d>>2]|0;if(!a){a=c[e>>2]|0;if(!a){I=0;break}else d=e}while(1){e=a+20|0;f=c[e>>2]|0;if(f|0){a=f;d=e;continue}e=a+16|0;f=c[e>>2]|0;if(!f)break;else{a=f;d=e}}if(d>>>0>>0)fa();else{c[d>>2]=0;I=a;break}}else{f=c[b+8>>2]|0;if(f>>>0>>0)fa();a=f+12|0;if((c[a>>2]|0)!=(b|0))fa();d=e+8|0;if((c[d>>2]|0)==(b|0)){c[a>>2]=e;c[d>>2]=f;I=e;break}else fa()}while(0);if(!g)break;a=c[b+28>>2]|0;d=39212+(a<<2)|0;do if((b|0)!=(c[d>>2]|0)){if(g>>>0<(c[9731]|0)>>>0)fa();a=g+16|0;if((c[a>>2]|0)==(b|0))c[a>>2]=I;else c[g+20>>2]=I;if(!I)break e}else{c[d>>2]=I;if(I|0)break;c[9728]=c[9728]&~(1<>>0>>0)fa();c[I+24>>2]=g;a=b+16|0;d=c[a>>2]|0;do if(d|0)if(d>>>0>>0)fa();else{c[I+16>>2]=d;c[d+24>>2]=I;break}while(0);a=c[a+4>>2]|0;if(!a)break;if(a>>>0<(c[9731]|0)>>>0)fa();else{c[I+20>>2]=a;c[a+24>>2]=I;break}}else{d=c[b+8>>2]|0;e=c[b+12>>2]|0;a=38948+(f<<1<<2)|0;do if((d|0)!=(a|0)){if(d>>>0>>0)fa();if((c[d+12>>2]|0)==(b|0))break;fa()}while(0);if((e|0)==(d|0)){c[9727]=c[9727]&~(1<>>0>>0)fa();a=e+8|0;if((c[a>>2]|0)==(b|0)){F=a;break}fa()}while(0);c[d+12>>2]=e;c[F>>2]=d}while(0);b=b+h|0;f=h+k|0}else f=k;b=b+4|0;c[b>>2]=c[b>>2]&-2;c[m+4>>2]=f|1;c[m+f>>2]=f;b=f>>>3;if(f>>>0<256){d=38948+(b<<1<<2)|0;a=c[9727]|0;b=1<>2]|0;if(a>>>0>=(c[9731]|0)>>>0){J=a;K=b;break}fa()}while(0);c[K>>2]=m;c[J+12>>2]=m;c[m+8>>2]=J;c[m+12>>2]=d;break}b=f>>>8;do if(!b)b=0;else{if(f>>>0>16777215){b=31;break}J=(b+1048320|0)>>>16&8;K=b<>>16&4;K=K<>>16&2;b=14-(I|J|b)+(K<>>15)|0;b=f>>>(b+7|0)&1|b<<1}while(0);e=39212+(b<<2)|0;c[m+28>>2]=b;a=m+16|0;c[a+4>>2]=0;c[a>>2]=0;a=c[9728]|0;d=1<>2]=m;c[m+24>>2]=e;c[m+12>>2]=m;c[m+8>>2]=m;break}a=f<<((b|0)==31?0:25-(b>>>1)|0);e=c[e>>2]|0;while(1){if((c[e+4>>2]&-8|0)==(f|0)){D=278;break}d=e+16+(a>>>31<<2)|0;b=c[d>>2]|0;if(!b){D=275;break}else{a=a<<1;e=b}}if((D|0)==275)if(d>>>0<(c[9731]|0)>>>0)fa();else{c[d>>2]=m;c[m+24>>2]=e;c[m+12>>2]=m;c[m+8>>2]=m;break}else if((D|0)==278){b=e+8|0;a=c[b>>2]|0;K=c[9731]|0;if(a>>>0>=K>>>0&e>>>0>=K>>>0){c[a+12>>2]=m;c[b>>2]=m;c[m+8>>2]=a;c[m+12>>2]=e;c[m+24>>2]=0;break}else fa()}}else{K=(c[9730]|0)+k|0;c[9730]=K;c[9733]=m;c[m+4>>2]=K|1}while(0);K=n+8|0;i=L;return K|0}else a=39356;while(1){b=c[a>>2]|0;if(b>>>0<=l>>>0?(E=b+(c[a+4>>2]|0)|0,E>>>0>l>>>0):0)break;a=c[a+8>>2]|0}f=E+-47|0;a=f+8|0;a=f+((a&7|0)==0?0:0-a&7)|0;f=l+16|0;a=a>>>0>>0?l:a;b=a+8|0;d=g+8|0;d=(d&7|0)==0?0:0-d&7;K=g+d|0;d=h+-40-d|0;c[9733]=K;c[9730]=d;c[K+4>>2]=d|1;c[K+d+4>>2]=40;c[9734]=c[9849];d=a+4|0;c[d>>2]=27;c[b>>2]=c[9839];c[b+4>>2]=c[9840];c[b+8>>2]=c[9841];c[b+12>>2]=c[9842];c[9839]=g;c[9840]=h;c[9842]=0;c[9841]=b;b=a+24|0;do{b=b+4|0;c[b>>2]=7}while((b+4|0)>>>0>>0);if((a|0)!=(l|0)){g=a-l|0;c[d>>2]=c[d>>2]&-2;c[l+4>>2]=g|1;c[a>>2]=g;b=g>>>3;if(g>>>0<256){d=38948+(b<<1<<2)|0;a=c[9727]|0;b=1<>2]|0;if(a>>>0<(c[9731]|0)>>>0)fa();else{G=a;H=b}}else{c[9727]=a|b;G=d;H=d+8|0}c[H>>2]=l;c[G+12>>2]=l;c[l+8>>2]=G;c[l+12>>2]=d;break}b=g>>>8;if(b)if(g>>>0>16777215)d=31;else{J=(b+1048320|0)>>>16&8;K=b<>>16&4;K=K<>>16&2;d=14-(I|J|d)+(K<>>15)|0;d=g>>>(d+7|0)&1|d<<1}else d=0;e=39212+(d<<2)|0;c[l+28>>2]=d;c[l+20>>2]=0;c[f>>2]=0;b=c[9728]|0;a=1<>2]=l;c[l+24>>2]=e;c[l+12>>2]=l;c[l+8>>2]=l;break}a=g<<((d|0)==31?0:25-(d>>>1)|0);e=c[e>>2]|0;while(1){if((c[e+4>>2]&-8|0)==(g|0)){D=304;break}d=e+16+(a>>>31<<2)|0;b=c[d>>2]|0;if(!b){D=301;break}else{a=a<<1;e=b}}if((D|0)==301)if(d>>>0<(c[9731]|0)>>>0)fa();else{c[d>>2]=l;c[l+24>>2]=e;c[l+12>>2]=l;c[l+8>>2]=l;break}else if((D|0)==304){b=e+8|0;a=c[b>>2]|0;K=c[9731]|0;if(a>>>0>=K>>>0&e>>>0>=K>>>0){c[a+12>>2]=l;c[b>>2]=l;c[l+8>>2]=a;c[l+12>>2]=e;c[l+24>>2]=0;break}else fa()}}}else{K=c[9731]|0;if((K|0)==0|g>>>0>>0)c[9731]=g;c[9839]=g;c[9840]=h;c[9842]=0;c[9736]=c[9845];c[9735]=-1;b=0;do{K=38948+(b<<1<<2)|0;c[K+12>>2]=K;c[K+8>>2]=K;b=b+1|0}while((b|0)!=32);K=g+8|0;K=(K&7|0)==0?0:0-K&7;J=g+K|0;K=h+-40-K|0;c[9733]=J;c[9730]=K;c[J+4>>2]=K|1;c[J+K+4>>2]=40;c[9734]=c[9849]}while(0);b=c[9730]|0;if(b>>>0>o>>>0){I=b-o|0;c[9730]=I;K=c[9733]|0;J=K+o|0;c[9733]=J;c[J+4>>2]=I|1;c[K+4>>2]=o|3;K=K+8|0;i=L;return K|0}}c[(Rb()|0)>>2]=12;K=0;i=L;return K|0}function ic(a){a=a|0;var b=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0;if(!a)return;d=a+-8|0;h=c[9731]|0;if(d>>>0>>0)fa();a=c[a+-4>>2]|0;b=a&3;if((b|0)==1)fa();e=a&-8;n=d+e|0;do if(!(a&1)){a=c[d>>2]|0;if(!b)return;k=d+(0-a)|0;j=a+e|0;if(k>>>0>>0)fa();if((k|0)==(c[9732]|0)){a=n+4|0;b=c[a>>2]|0;if((b&3|0)!=3){q=k;f=j;break}c[9729]=j;c[a>>2]=b&-2;c[k+4>>2]=j|1;c[k+j>>2]=j;return}e=a>>>3;if(a>>>0<256){b=c[k+8>>2]|0;d=c[k+12>>2]|0;a=38948+(e<<1<<2)|0;if((b|0)!=(a|0)){if(b>>>0>>0)fa();if((c[b+12>>2]|0)!=(k|0))fa()}if((d|0)==(b|0)){c[9727]=c[9727]&~(1<>>0>>0)fa();a=d+8|0;if((c[a>>2]|0)==(k|0))g=a;else fa()}else g=d+8|0;c[b+12>>2]=d;c[g>>2]=b;q=k;f=j;break}g=c[k+24>>2]|0;d=c[k+12>>2]|0;do if((d|0)==(k|0)){d=k+16|0;b=d+4|0;a=c[b>>2]|0;if(!a){a=c[d>>2]|0;if(!a){i=0;break}else b=d}while(1){d=a+20|0;e=c[d>>2]|0;if(e|0){a=e;b=d;continue}d=a+16|0;e=c[d>>2]|0;if(!e)break;else{a=e;b=d}}if(b>>>0>>0)fa();else{c[b>>2]=0;i=a;break}}else{e=c[k+8>>2]|0;if(e>>>0>>0)fa();a=e+12|0;if((c[a>>2]|0)!=(k|0))fa();b=d+8|0;if((c[b>>2]|0)==(k|0)){c[a>>2]=d;c[b>>2]=e;i=d;break}else fa()}while(0);if(g){a=c[k+28>>2]|0;b=39212+(a<<2)|0;if((k|0)==(c[b>>2]|0)){c[b>>2]=i;if(!i){c[9728]=c[9728]&~(1<>>0<(c[9731]|0)>>>0)fa();a=g+16|0;if((c[a>>2]|0)==(k|0))c[a>>2]=i;else c[g+20>>2]=i;if(!i){q=k;f=j;break}}d=c[9731]|0;if(i>>>0>>0)fa();c[i+24>>2]=g;a=k+16|0;b=c[a>>2]|0;do if(b|0)if(b>>>0>>0)fa();else{c[i+16>>2]=b;c[b+24>>2]=i;break}while(0);a=c[a+4>>2]|0;if(a)if(a>>>0<(c[9731]|0)>>>0)fa();else{c[i+20>>2]=a;c[a+24>>2]=i;q=k;f=j;break}else{q=k;f=j}}else{q=k;f=j}}else{q=d;f=e}while(0);if(q>>>0>=n>>>0)fa();a=n+4|0;b=c[a>>2]|0;if(!(b&1))fa();if(!(b&2)){if((n|0)==(c[9733]|0)){p=(c[9730]|0)+f|0;c[9730]=p;c[9733]=q;c[q+4>>2]=p|1;if((q|0)!=(c[9732]|0))return;c[9732]=0;c[9729]=0;return}if((n|0)==(c[9732]|0)){p=(c[9729]|0)+f|0;c[9729]=p;c[9732]=q;c[q+4>>2]=p|1;c[q+p>>2]=p;return}f=(b&-8)+f|0;e=b>>>3;do if(b>>>0>=256){g=c[n+24>>2]|0;a=c[n+12>>2]|0;do if((a|0)==(n|0)){d=n+16|0;b=d+4|0;a=c[b>>2]|0;if(!a){a=c[d>>2]|0;if(!a){m=0;break}else b=d}while(1){d=a+20|0;e=c[d>>2]|0;if(e|0){a=e;b=d;continue}d=a+16|0;e=c[d>>2]|0;if(!e)break;else{a=e;b=d}}if(b>>>0<(c[9731]|0)>>>0)fa();else{c[b>>2]=0;m=a;break}}else{b=c[n+8>>2]|0;if(b>>>0<(c[9731]|0)>>>0)fa();d=b+12|0;if((c[d>>2]|0)!=(n|0))fa();e=a+8|0;if((c[e>>2]|0)==(n|0)){c[d>>2]=a;c[e>>2]=b;m=a;break}else fa()}while(0);if(g|0){a=c[n+28>>2]|0;b=39212+(a<<2)|0;if((n|0)==(c[b>>2]|0)){c[b>>2]=m;if(!m){c[9728]=c[9728]&~(1<>>0<(c[9731]|0)>>>0)fa();a=g+16|0;if((c[a>>2]|0)==(n|0))c[a>>2]=m;else c[g+20>>2]=m;if(!m)break}d=c[9731]|0;if(m>>>0>>0)fa();c[m+24>>2]=g;a=n+16|0;b=c[a>>2]|0;do if(b|0)if(b>>>0>>0)fa();else{c[m+16>>2]=b;c[b+24>>2]=m;break}while(0);a=c[a+4>>2]|0;if(a|0)if(a>>>0<(c[9731]|0)>>>0)fa();else{c[m+20>>2]=a;c[a+24>>2]=m;break}}}else{b=c[n+8>>2]|0;d=c[n+12>>2]|0;a=38948+(e<<1<<2)|0;if((b|0)!=(a|0)){if(b>>>0<(c[9731]|0)>>>0)fa();if((c[b+12>>2]|0)!=(n|0))fa()}if((d|0)==(b|0)){c[9727]=c[9727]&~(1<>>0<(c[9731]|0)>>>0)fa();a=d+8|0;if((c[a>>2]|0)==(n|0))l=a;else fa()}else l=d+8|0;c[b+12>>2]=d;c[l>>2]=b}while(0);c[q+4>>2]=f|1;c[q+f>>2]=f;if((q|0)==(c[9732]|0)){c[9729]=f;return}}else{c[a>>2]=b&-2;c[q+4>>2]=f|1;c[q+f>>2]=f}a=f>>>3;if(f>>>0<256){d=38948+(a<<1<<2)|0;b=c[9727]|0;a=1<>2]|0;if(b>>>0<(c[9731]|0)>>>0)fa();else{o=b;p=a}}else{c[9727]=b|a;o=d;p=d+8|0}c[p>>2]=q;c[o+12>>2]=q;c[q+8>>2]=o;c[q+12>>2]=d;return}a=f>>>8;if(a)if(f>>>0>16777215)a=31;else{o=(a+1048320|0)>>>16&8;p=a<>>16&4;p=p<>>16&2;a=14-(n|o|a)+(p<>>15)|0;a=f>>>(a+7|0)&1|a<<1}else a=0;e=39212+(a<<2)|0;c[q+28>>2]=a;c[q+20>>2]=0;c[q+16>>2]=0;b=c[9728]|0;d=1<>>1)|0);e=c[e>>2]|0;while(1){if((c[e+4>>2]&-8|0)==(f|0)){a=130;break}d=e+16+(b>>>31<<2)|0;a=c[d>>2]|0;if(!a){a=127;break}else{b=b<<1;e=a}}if((a|0)==127)if(d>>>0<(c[9731]|0)>>>0)fa();else{c[d>>2]=q;c[q+24>>2]=e;c[q+12>>2]=q;c[q+8>>2]=q;break}else if((a|0)==130){a=e+8|0;b=c[a>>2]|0;p=c[9731]|0;if(b>>>0>=p>>>0&e>>>0>=p>>>0){c[b+12>>2]=q;c[a>>2]=q;c[q+8>>2]=b;c[q+12>>2]=e;c[q+24>>2]=0;break}else fa()}}else{c[9728]=b|d;c[e>>2]=q;c[q+24>>2]=e;c[q+12>>2]=q;c[q+8>>2]=q}while(0);q=(c[9735]|0)+-1|0;c[9735]=q;if(!q)a=39364;else return;while(1){a=c[a>>2]|0;if(!a)break;else a=a+8|0}c[9735]=-1;return}function jc(){}function kc(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;d=b-d-(c>>>0>a>>>0|0)>>>0;return (C=d,a-c>>>0|0)|0}function lc(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,i=0;f=b+e|0;if((e|0)>=20){d=d&255;h=b&3;i=d|d<<8|d<<16|d<<24;g=f&~3;if(h){h=b+4-h|0;while((b|0)<(h|0)){a[b>>0]=d;b=b+1|0}}while((b|0)<(g|0)){c[b>>2]=i;b=b+4|0}}while((b|0)<(f|0)){a[b>>0]=d;b=b+1|0}return b-e|0}function mc(a,b,c){a=a|0;b=b|0;c=c|0;if((c|0)<32){C=b>>>c;return a>>>c|(b&(1<>>c-32|0}function nc(a,b,c){a=a|0;b=b|0;c=c|0;if((c|0)<32){C=b<>>32-c;return a<>>16;a=(c>>>16)+(R(e,d)|0)|0;e=b>>>16;b=R(e,f)|0;return (C=(a>>>16)+(R(e,d)|0)+(((a&65535)+b|0)>>>16)|0,a+b<<16|c&65535|0)|0}function pc(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0,f=0;e=a;f=c;c=oc(e,f)|0;a=C;return (C=(R(b,f)|0)+(R(d,e)|0)+a|a&0,c|0|0)|0}function qc(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;c=a+c>>>0;return (C=b+d+(c>>>0>>0|0)>>>0,c|0)|0}function rc(a){a=a|0;var b=0,d=0;d=a+15&-16|0;b=c[k>>2]|0;a=b+d|0;if((d|0)>0&(a|0)<(b|0)|(a|0)<0){Z()|0;sa(12);return -1}c[k>>2]=a;if((a|0)>(Y()|0)?(X()|0)==0:0){sa(12);c[k>>2]=b;return -1}return b|0}function sc(a){a=a|0;return (a&255)<<24|(a>>8&255)<<16|(a>>16&255)<<8|a>>>24|0}function tc(b,d,e){b=b|0;d=d|0;e=e|0;var f=0;if((e|0)>=4096)return la(b|0,d|0,e|0)|0;f=b|0;if((b&3)==(d&3)){while(b&3){if(!e)return f|0;a[b>>0]=a[d>>0]|0;b=b+1|0;d=d+1|0;e=e-1|0}while((e|0)>=4){c[b>>2]=c[d>>2];b=b+4|0;d=d+4|0;e=e-4|0}}while((e|0)>0){a[b>>0]=a[d>>0]|0;b=b+1|0;d=d+1|0;e=e-1|0}return f|0}function uc(){return 0}function vc(a,b){a=a|0;b=b|0;return ua[a&1](b|0)|0}function wc(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;return va[a&7](b|0,c|0,d|0)|0}function xc(a,b){a=a|0;b=b|0;wa[a&3](b|0)}function yc(a){a=a|0;V(0);return 0}function zc(a,b,c){a=a|0;b=b|0;c=c|0;V(1);return 0}function Ac(a){a=a|0;V(2)} // EMSCRIPTEN_END_FUNCS var ua=[yc,Nb];var va=[zc,Wb,Pb,Ub,Ob,zc,zc,zc];var wa=[Ac,Sb,Vb,Ac];return{___muldsi3:oc,_sbrk:rc,_i64Subtract:kc,_free:ic,_ecdsa_read_pubkey:lb,_i64Add:qc,_pthread_self:uc,_memset:lc,_malloc:hc,_memcpy:tc,_llvm_bswap_i32:sc,___muldi3:pc,_bitshift64Lshr:mc,_fflush:ec,_hdnode_public_ckd_address_optimized:ub,___errno_location:Rb,_bitshift64Shl:nc,runPostSets:jc,stackAlloc:xa,stackSave:ya,stackRestore:za,establishStackSpace:Aa,setThrew:Ba,setTempRet0:Ca,getTempRet0:Da,dynCall_ii:vc,dynCall_iiii:wc,dynCall_vi:xc}}) @@ -375,5 +375,5 @@ function wc(a){function b(){if(!e.calledRun&&(e.calledRun=!0,!ja)){za||(za=!0,Qa setTimeout(function(){setTimeout(function(){e.setStatus("")},1);b()},1)):b())}}e.run=e.run=wc;function xc(a,b){if(!b||!e.noExitRuntime){if(!e.noExitRuntime&&(ja=!0,p=void 0,Qa(J),e.onExit))e.onExit(a);m?process.exit(a):ca&&"function"===typeof quit&&quit(a);throw new ga(a);}}e.exit=e.exit=xc;var zc=[]; function z(a){void 0!==a?(e.print(a),e.ba(a),a=JSON.stringify(a)):a="";ja=!0;var b="abort("+a+") at "+Ha()+"\nIf this abort() is unexpected, build with -s ASSERTIONS=1 which can give more information.";zc&&zc.forEach(function(c){b=c(b,a)});throw b;}e.abort=e.abort=z;if(e.preInit)for("function"==typeof e.preInit&&(e.preInit=[e.preInit]);0 Date: Thu, 4 May 2017 03:02:51 +0200 Subject: [PATCH 406/627] Moving emscripten into a separate job --- .travis.yml | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 00e7270da..0b07782ad 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,4 @@ -sudo: required +sudo: false dist: trusty language: c @@ -6,9 +6,6 @@ compiler: - clang - gcc -services: - - docker - addons: apt: packages: @@ -17,7 +14,6 @@ addons: - cmake-data - libssl-dev - python-pip - - nodejs install: - pip install --user pytest ecdsa curve25519-donna @@ -28,7 +24,21 @@ script: - ./test-openssl 1000 - ITERS=10 py.test - mkdir _build && cd _build && cmake .. && make && cd .. - - cd emscripten && rm trezor-crypto.js && make docker-build && make test-correctness && cd .. + +matrix: + include: + - env: BUILD=emscripten + script: + - cd emscripten && rm trezor-crypto.js && make docker-build && make test-correctness && cd .. + services: + - docker + sudo: required + install: true + compiler: true + addons: + apt: + packages: + - nodejs notifications: webhooks: From 671dad42df99bd777e3c6143ab9c0f0797adc512 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 8 May 2017 14:57:55 +0200 Subject: [PATCH 407/627] whitespace in bip32.[ch], formatting in readme --- README.md | 3 ++- bip32.c | 2 -- bip32.h | 2 -- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 74dacc587..53a994255 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,8 @@ These include: - BIP39 Mnemonic code - ECDSA signing/verifying (supports secp256k1 and nist256p1 curves, uses RFC6979 for deterministic signatures) -- ECDSA public key derivation + Base58 address representation +- ECDSA public key derivation +- Base58 address representation - Ed25519 signing/verifying - ECDH using secp256k1, nist256p1 and Curve25519 - HMAC-SHA256 and HMAC-SHA512 diff --git a/bip32.c b/bip32.c index 9a794518b..7810f4c43 100644 --- a/bip32.c +++ b/bip32.c @@ -303,7 +303,6 @@ int hdnode_public_ckd_address_optimized(const curve_point *pub, const uint8_t *c } #if USE_BIP32_CACHE - static bool private_ckd_cache_root_set = false; static HDNode private_ckd_cache_root; static int private_ckd_cache_index = 0; @@ -375,7 +374,6 @@ int hdnode_private_ckd_cached(HDNode *inout, const uint32_t *i, size_t i_count, return 1; } - #endif void hdnode_get_address_raw(HDNode *node, uint32_t version, uint8_t *addr_raw) diff --git a/bip32.h b/bip32.h index 7c48bacec..7004c534a 100644 --- a/bip32.h +++ b/bip32.h @@ -61,9 +61,7 @@ int hdnode_public_ckd(HDNode *inout, uint32_t i); int hdnode_public_ckd_address_optimized(const curve_point *pub, const uint8_t *chain_code, uint32_t i, uint32_t version, char *addr, int addrsize, bool segwit); #if USE_BIP32_CACHE - int hdnode_private_ckd_cached(HDNode *inout, const uint32_t *i, size_t i_count, uint32_t *fingerprint); - #endif uint32_t hdnode_fingerprint(HDNode *node); From ca3423efc3db1621a9b5523d83f8251377ce4c7b Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 8 May 2017 16:46:53 +0200 Subject: [PATCH 408/627] move aes stuff to aes/ subdirectory --- Makefile | 6 +++--- aes.h => aes/aes.h | 0 aes_modes.c => aes/aes_modes.c | 0 aescrypt.c => aes/aescrypt.c | 0 aeskey.c => aes/aeskey.c | 0 aesopt.h => aes/aesopt.h | 0 aestab.c => aes/aestab.c | 0 aestab.h => aes/aestab.h | 0 8 files changed, 3 insertions(+), 3 deletions(-) rename aes.h => aes/aes.h (100%) rename aes_modes.c => aes/aes_modes.c (100%) rename aescrypt.c => aes/aescrypt.c (100%) rename aeskey.c => aes/aeskey.c (100%) rename aesopt.h => aes/aesopt.h (100%) rename aestab.c => aes/aestab.c (100%) rename aestab.h => aes/aestab.h (100%) diff --git a/Makefile b/Makefile index 0201336bc..e2c5e4163 100644 --- a/Makefile +++ b/Makefile @@ -25,7 +25,7 @@ CFLAGS += $(OPTFLAGS) \ # disable sequence point warning because of AES code CFLAGS += -Wno-sequence-point -CFLAGS += -Ied25519-donna -I. +CFLAGS += -I. -Iaes -Ied25519-donna CFLAGS += -DUSE_ETHEREUM=1 CFLAGS += -DUSE_GRAPHENE=1 @@ -40,7 +40,7 @@ SRCS += script.c SRCS += ripemd160.c SRCS += sha2.c SRCS += sha3.c -SRCS += aescrypt.c aeskey.c aestab.c aes_modes.c +SRCS += aes/aescrypt.c aes/aeskey.c aes/aestab.c aes/aes_modes.c SRCS += ed25519-donna/ed25519.c SRCS += blake2b.c blake2s.c @@ -78,5 +78,5 @@ tools/bip39bruteforce: tools/bip39bruteforce.o $(OBJS) $(CC) tools/bip39bruteforce.o $(OBJS) -o tools/bip39bruteforce clean: - rm -f *.o ed25519-donna/*.o tests test_speed test-openssl libtrezor-crypto.so + rm -f *.o aes/*.o ed25519-donna/*.o tests test_speed test-openssl libtrezor-crypto.so rm -f tools/*.o tools/xpubaddrgen tools/mktable tools/bip39bruteforce diff --git a/aes.h b/aes/aes.h similarity index 100% rename from aes.h rename to aes/aes.h diff --git a/aes_modes.c b/aes/aes_modes.c similarity index 100% rename from aes_modes.c rename to aes/aes_modes.c diff --git a/aescrypt.c b/aes/aescrypt.c similarity index 100% rename from aescrypt.c rename to aes/aescrypt.c diff --git a/aeskey.c b/aes/aeskey.c similarity index 100% rename from aeskey.c rename to aes/aeskey.c diff --git a/aesopt.h b/aes/aesopt.h similarity index 100% rename from aesopt.h rename to aes/aesopt.h diff --git a/aestab.c b/aes/aestab.c similarity index 100% rename from aestab.c rename to aes/aestab.c diff --git a/aestab.h b/aes/aestab.h similarity index 100% rename from aestab.h rename to aes/aestab.h From 2ae032adbbb5fd45895e54eb6d47849d77e62d2b Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 8 May 2017 17:08:48 +0200 Subject: [PATCH 409/627] update AES code from Github --- aes/aes.h | 42 ++++++----- aes/aes_modes.c | 12 +-- aes/aesopt.h | 47 +++++++----- aes/aestab.c | 49 ++++++++++--- aes/aestab.h | 6 +- aes/brg_types.h | 191 ++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 292 insertions(+), 55 deletions(-) create mode 100644 aes/brg_types.h diff --git a/aes/aes.h b/aes/aes.h index 524f4c0f5..8cc0526ae 100644 --- a/aes/aes.h +++ b/aes/aes.h @@ -25,17 +25,15 @@ Issue Date: 20/12/2007 #define _AES_H #include -#include + +/* This include is used to find 8 & 32 bit unsigned integer types */ +#include "brg_types.h" #if defined(__cplusplus) extern "C" { #endif -#define ALIGN_OFFSET(x,n) (((intptr_t)(x)) & ((n) - 1)) -#define ALIGN_FLOOR(x,n) ((uint8_t*)(x) - ( ((intptr_t)(x)) & ((n) - 1))) -#define ALIGN_CEIL(x,n) ((uint8_t*)(x) + (-((intptr_t)(x)) & ((n) - 1))) - // #define AES_128 /* if a fast 128 bit key scheduler is needed */ // #define AES_192 /* if a fast 192 bit key scheduler is needed */ #define AES_256 /* if a fast 256 bit key scheduler is needed */ @@ -62,7 +60,7 @@ extern "C" #define KS_LENGTH 44 #endif -#define AES_RETURN int +#define AES_RETURN INT_RETURN /* the character array 'inf' in the following structures is used */ /* to hold AES context information. This AES code uses cx->inf.b[0] */ @@ -74,22 +72,32 @@ typedef union uint8_t b[4]; } aes_inf; -#ifdef _WIN64 -__declspec(align(16)) -#endif -typedef struct +#ifdef _MSC_VER +# pragma warning( disable : 4324 ) +#endif + +#if defined(_MSC_VER) && defined(_WIN64) +#define ALIGNED_(x) __declspec(align(x)) +#elif defined(__GNUC__) && defined(__x86_64__) +#define ALIGNED_(x) __attribute__ ((aligned(x))) +#else +#define ALIGNED_(x) +#endif + +typedef struct ALIGNED_(16) { uint32_t ks[KS_LENGTH]; aes_inf inf; } aes_encrypt_ctx; -#ifdef _WIN64 -__declspec(align(16)) -#endif -typedef struct +typedef struct ALIGNED_(16) { uint32_t ks[KS_LENGTH]; aes_inf inf; } aes_decrypt_ctx; +#ifdef _MSC_VER +# pragma warning( default : 4324 ) +#endif + /* This routine must be called before first use if non-static */ /* tables are being used */ @@ -151,9 +159,9 @@ AES_RETURN aes_decrypt(const unsigned char *in, unsigned char *out, const aes_de /* each individual call within a series of incremental calls must */ /* process only full blocks (i.e. len must be a multiple of 16) but */ /* the CFB, OFB and CTR mode calls can handle multiple incremental */ -/* calls of any length. Each mode is reset when a new AES key is */ -/* set but ECB and CBC operations can be reset without setting a */ -/* new key by setting a new IV value. To reset CFB, OFB and CTR */ +/* calls of any length. Each mode is reset when a new AES key is */ +/* set but ECB needs no reset and CBC can be reset without setting */ +/* a new key by setting a new IV value. To reset CFB, OFB and CTR */ /* without setting the key, aes_mode_reset() must be called and the */ /* IV must be set. NOTE: All these calls update the IV on exit so */ /* this has to be reset if a new operation with the same IV as the */ diff --git a/aes/aes_modes.c b/aes/aes_modes.c index 2a432c804..744395e0e 100644 --- a/aes/aes_modes.c +++ b/aes/aes_modes.c @@ -943,12 +943,12 @@ AES_RETURN aes_ctr_crypt(const unsigned char *ibuf, unsigned char *obuf, void aes_ctr_cbuf_inc(unsigned char *cbuf) { - int i = 15; - while (i >= 0) { - cbuf[i]++; - if (cbuf[i]) return; // if there was no overflow - i--; - } + int i = AES_BLOCK_SIZE - 1; + while (i >= 0) { + cbuf[i]++; + if (cbuf[i]) return; // if there was no overflow + i--; + } } #if defined(__cplusplus) diff --git a/aes/aesopt.h b/aes/aesopt.h index ee96215b2..a1ef045df 100644 --- a/aes/aesopt.h +++ b/aes/aesopt.h @@ -87,7 +87,11 @@ Issue Date: 20/12/2007 #if !defined( _AESOPT_H ) #define _AESOPT_H +#if defined( __cplusplus ) +#include "aescpp.h" +#else #include "aes.h" +#endif /* PLATFORM SPECIFIC INCLUDES */ @@ -162,30 +166,31 @@ Issue Date: 20/12/2007 /* 2. Intel AES AND VIA ACE SUPPORT */ #if defined( __GNUC__ ) && defined( __i386__ ) \ - || defined(_WIN32) && defined(_M_IX86) \ - && !(defined(_WIN64) || defined(_WIN32_WCE) || defined(_MSC_VER) && (_MSC_VER <= 800)) + || defined( _WIN32 ) && defined( _M_IX86 ) && !(defined( _WIN64 ) \ + || defined( _WIN32_WCE ) || defined( _MSC_VER ) && ( _MSC_VER <= 800 )) # define VIA_ACE_POSSIBLE #endif -/* Define this option if support for the Intel AESNI is required (not - currently available with GCC). If AESNI is known to be present, then - defining ASSUME_INTEL_AES_VIA_PRESENT will replace the ordinary - encryption/decryption. If USE_INTEL_AES_IF_PRESENT is defined then - AESNI will be used if it is detected (both present and enabled). +#if (defined( _WIN64 ) && defined( _MSC_VER )) \ + || (defined( __GNUC__ ) && defined( __x86_64__ )) \ + && !(defined( INTEL_AES_POSSIBLE )) +# define INTEL_AES_POSSIBLE +#endif + +/* Define this option if support for the Intel AESNI is required + If USE_INTEL_AES_IF_PRESENT is defined then AESNI will be used + if it is detected (both present and enabled). AESNI uses a decryption key schedule with the first decryption round key at the high end of the key scedule with the following round keys at lower positions in memory. So AES_REV_DKS must NOT be defined when AESNI will be used. ALthough it is unlikely that assembler code will be used with an AESNI build, if it is then - AES_REV_DKS must NOT be defined when such assembler files are + AES_REV_DKS must NOT be defined when the assembler files are built */ -#if 0 && defined( _WIN64 ) && defined( _MSC_VER ) -# define INTEL_AES_POSSIBLE -#endif -#if defined( INTEL_AES_POSSIBLE ) && !defined( USE_INTEL_AES_IF_PRESENT ) +#if 0 && defined( INTEL_AES_POSSIBLE ) && !defined( USE_INTEL_AES_IF_PRESENT ) # define USE_INTEL_AES_IF_PRESENT #endif @@ -243,8 +248,14 @@ Issue Date: 20/12/2007 # define ASM_AMD64_C #endif +#if defined( __i386 ) || defined( _M_IX86 ) +# define A32_ +#elif defined( __x86_64__ ) || defined( _M_X64 ) +# define A64_ +#endif + #if (defined ( ASM_X86_V1C ) || defined( ASM_X86_V2 ) || defined( ASM_X86_V2C )) \ - && !defined( _M_IX86 ) || defined( ASM_AMD64_C ) && !defined( _M_X64 ) + && !defined( A32_ ) || defined( ASM_AMD64_C ) && !defined( A64_ ) # error Assembler code is only available for x86 and AMD64 systems #endif @@ -306,7 +317,7 @@ Issue Date: 20/12/2007 /* 6. FAST FINITE FIELD OPERATIONS If this section is included, tables are used to provide faster finite - field arithmetic (this has no effect if FIXED_TABLES is defined). + field arithmetic (this has no effect if STATIC_TABLES is defined). */ #if 1 # define FF_TABLES @@ -330,12 +341,12 @@ Issue Date: 20/12/2007 must be called to compute them before the code is first used. */ #if 1 && !(defined( _MSC_VER ) && ( _MSC_VER <= 800 )) -# define FIXED_TABLES +# define STATIC_TABLES #endif /* 9. MASKING OR CASTING FROM LONGER VALUES TO BYTES - In some systems it is better to mask longer values to extract bytes + In some systems it is better to mask longer values to extract bytes rather than using a cast. This option allows this choice. */ #if 0 @@ -676,7 +687,7 @@ Issue Date: 20/12/2007 #if !(defined( REDUCE_CODE_SIZE ) && (defined( ASM_X86_V2 ) || defined( ASM_X86_V2C ))) # if ((FUNCS_IN_C & ENC_KEYING_IN_C) || (FUNCS_IN_C & DEC_KEYING_IN_C)) # if KEY_SCHED == ONE_TABLE -# if !defined( FL1_SET ) && !defined( FL4_SET ) +# if !defined( FL1_SET ) && !defined( FL4_SET ) # define LS1_SET # endif # elif KEY_SCHED == FOUR_TABLES @@ -725,7 +736,7 @@ Issue Date: 20/12/2007 /* perform forward and inverse column mix operation on four bytes in long word x in */ /* parallel. NOTE: x must be a simple variable, NOT an expression in these macros. */ -#if !(defined( REDUCE_CODE_SIZE ) && (defined( ASM_X86_V2 ) || defined( ASM_X86_V2C ))) +#if !(defined( REDUCE_CODE_SIZE ) && (defined( ASM_X86_V2 ) || defined( ASM_X86_V2C ))) #if defined( FM4_SET ) /* not currently used */ # define fwd_mcol(x) four_tables(x,t_use(f,m),vf1,rf1,0) diff --git a/aes/aestab.c b/aes/aestab.c index 8fd11f94a..3d48edf3e 100644 --- a/aes/aestab.c +++ b/aes/aestab.c @@ -23,7 +23,7 @@ Issue Date: 20/12/2007 #include "aes.h" #include "aesopt.h" -#if defined(FIXED_TABLES) +#if defined(STATIC_TABLES) #define sb_data(w) {\ w(0x63), w(0x7c), w(0x77), w(0x7b), w(0xf2), w(0x6b), w(0x6f), w(0xc5),\ @@ -150,7 +150,7 @@ Issue Date: 20/12/2007 #endif -#if defined(FIXED_TABLES) || !defined(FF_TABLES) +#if defined(STATIC_TABLES) || !defined(FF_TABLES) #define f2(x) ((x<<1) ^ (((x>>7) & 1) * WPOLY)) #define f4(x) ((x<<2) ^ (((x>>6) & 1) * WPOLY) ^ (((x>>6) & 2) * WPOLY)) @@ -180,7 +180,7 @@ extern "C" { #endif -#if defined(FIXED_TABLES) +#if defined(STATIC_TABLES) /* implemented in case of wrong call for fixed tables */ @@ -195,7 +195,7 @@ AES_RETURN aes_init(void) #define gf_inv(x) ((x) ? pow[ 255 - log[x]] : 0) -#else +#else /* It will generally be sensible to use tables to compute finite field multiplies and inverses but where memory is scarse this @@ -221,7 +221,7 @@ static uint8_t hibit(const uint32_t x) static uint8_t gf_inv(const uint8_t x) { uint8_t p1 = x, p2 = BPOLY, n1 = hibit(x), n2 = 0x80, v1 = 1, v2 = 0; - if(x < 2) + if(x < 2) return x; for( ; ; ) @@ -229,20 +229,20 @@ static uint8_t gf_inv(const uint8_t x) if(n1) while(n2 >= n1) /* divide polynomial p2 by p1 */ { - n2 /= n1; /* shift smaller polynomial left */ + n2 /= n1; /* shift smaller polynomial left */ p2 ^= (p1 * n2) & 0xff; /* and remove from larger one */ - v2 ^= v1 * n2; /* shift accumulated value and */ + v2 ^= v1 * n2; /* shift accumulated value and */ n2 = hibit(p2); /* add into result */ } else return v1; - if(n2) /* repeat with values swapped */ + if(n2) /* repeat with values swapped */ while(n1 >= n2) { - n1 /= n2; - p1 ^= p2 * n1; - v1 ^= v2 * n1; + n1 /= n2; + p1 ^= p2 * n1; + v1 ^= v2 * n1; n1 = hibit(p1); } else @@ -383,6 +383,33 @@ AES_RETURN aes_init(void) return EXIT_SUCCESS; } +/* + Automatic code initialisation (suggested by by Henrik S. Gaßmann) + based on code provided by Joe Lowe and placed in the public domain at: + http://stackoverflow.com/questions/1113409/attribute-constructor-equivalent-in-vc +*/ + +#ifdef _MSC_VER + +#pragma section(".CRT$XCU", read) + +__declspec(allocate(".CRT$XCU")) void (__cdecl *aes_startup)(void) = aes_init; + +#elif defined(__GNUC__) + +static void aes_startup(void) __attribute__((constructor)); + +static void aes_startup(void) +{ + aes_init(); +} + +#else + +#pragma message( "dynamic tables must be initialised manually on your system" ) + +#endif + #endif #if defined(__cplusplus) diff --git a/aes/aestab.h b/aes/aestab.h index 46719d330..8fe32d180 100644 --- a/aes/aestab.h +++ b/aes/aestab.h @@ -29,7 +29,7 @@ Issue Date: 20/12/2007 that control the calls to aes_init() and the aes_init() routine itself will have to be changed for a specific implementation. If global variables are available it will generally be preferable to use them with the precomputed - FIXED_TABLES option that uses static global tables. + STATIC_TABLES option that uses static global tables. The following defines can be used to control the way the tables are defined, initialised and used in embedded environments that @@ -69,7 +69,7 @@ extern "C" { #define t_set(m,n) t_##m##n #define t_use(m,n) t_##m##n -#if defined(FIXED_TABLES) +#if defined(STATIC_TABLES) # if !defined( __GNUC__ ) && (defined( __MSDOS__ ) || defined( __WIN16__ )) /* make tables far data to avoid using too much DGROUP space (PG) */ # define CONST const far @@ -98,7 +98,7 @@ extern "C" { # define XP_DIR #endif -#if defined(DO_TABLES) && defined(FIXED_TABLES) +#if defined(DO_TABLES) && defined(STATIC_TABLES) #define d_1(t,n,b,e) EXTERN ALIGN CONST XP_DIR t n[256] = b(e) #define d_4(t,n,b,e,f,g,h) EXTERN ALIGN CONST XP_DIR t n[4][256] = { b(e), b(f), b(g), b(h) } EXTERN ALIGN CONST uint32_t t_dec(r,c)[RC_LENGTH] = rc_data(w0); diff --git a/aes/brg_types.h b/aes/brg_types.h new file mode 100644 index 000000000..307319bf6 --- /dev/null +++ b/aes/brg_types.h @@ -0,0 +1,191 @@ +/* +--------------------------------------------------------------------------- +Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved. + +The redistribution and use of this software (with or without changes) +is allowed without the payment of fees or royalties provided that: + + source code distributions include the above copyright notice, this + list of conditions and the following disclaimer; + + binary distributions include the above copyright notice, this list + of conditions and the following disclaimer in their documentation. + +This software is provided 'as is' with no explicit or implied warranties +in respect of its operation, including, but not limited to, correctness +and fitness for purpose. +--------------------------------------------------------------------------- +Issue Date: 20/12/2007 + + The unsigned integer types defined here are of the form uint_t where + is the length of the type; for example, the unsigned 32-bit type is + 'uint32_t'. These are NOT the same as the 'C99 integer types' that are + defined in the inttypes.h and stdint.h headers since attempts to use these + types have shown that support for them is still highly variable. However, + since the latter are of the form uint_t, a regular expression search + and replace (in VC++ search on 'uint_{:z}t' and replace with 'uint\1_t') + can be used to convert the types used here to the C99 standard types. +*/ + +#ifndef _BRG_TYPES_H +#define _BRG_TYPES_H + +#if defined(__cplusplus) +extern "C" { +#endif + +#include +#include + +#if defined( _MSC_VER ) && ( _MSC_VER >= 1300 ) +# include +# define ptrint_t intptr_t +#elif defined( __ECOS__ ) +# define intptr_t unsigned int +# define ptrint_t intptr_t +#elif defined( __GNUC__ ) && ( __GNUC__ >= 3 ) +# define ptrint_t intptr_t +#else +# define ptrint_t int +#endif + +#ifndef BRG_UI32 +# define BRG_UI32 +# if UINT_MAX == 4294967295u +# define li_32(h) 0x##h##u +# elif ULONG_MAX == 4294967295u +# define li_32(h) 0x##h##ul +# elif defined( _CRAY ) +# error This code needs 32-bit data types, which Cray machines do not provide +# else +# error Please define uint32_t as a 32-bit unsigned integer type in brg_types.h +# endif +#endif + +#ifndef BRG_UI64 +# if defined( __BORLANDC__ ) && !defined( __MSDOS__ ) +# define BRG_UI64 +# define li_64(h) 0x##h##ui64 +# elif defined( _MSC_VER ) && ( _MSC_VER < 1300 ) /* 1300 == VC++ 7.0 */ +# define BRG_UI64 +# define li_64(h) 0x##h##ui64 +# elif defined( __sun ) && defined( ULONG_MAX ) && ULONG_MAX == 0xfffffffful +# define BRG_UI64 +# define li_64(h) 0x##h##ull +# elif defined( __MVS__ ) +# define BRG_UI64 +# define li_64(h) 0x##h##ull +# elif defined( UINT_MAX ) && UINT_MAX > 4294967295u +# if UINT_MAX == 18446744073709551615u +# define BRG_UI64 +# define li_64(h) 0x##h##u +# endif +# elif defined( ULONG_MAX ) && ULONG_MAX > 4294967295u +# if ULONG_MAX == 18446744073709551615ul +# define BRG_UI64 +# define li_64(h) 0x##h##ul +# endif +# elif defined( ULLONG_MAX ) && ULLONG_MAX > 4294967295u +# if ULLONG_MAX == 18446744073709551615ull +# define BRG_UI64 +# define li_64(h) 0x##h##ull +# endif +# elif defined( ULONG_LONG_MAX ) && ULONG_LONG_MAX > 4294967295u +# if ULONG_LONG_MAX == 18446744073709551615ull +# define BRG_UI64 +# define li_64(h) 0x##h##ull +# endif +# endif +#endif + +#if !defined( BRG_UI64 ) +# if defined( NEED_UINT_64T ) +# error Please define uint64_t as an unsigned 64 bit type in brg_types.h +# endif +#endif + +#ifndef RETURN_VALUES +# define RETURN_VALUES +# if defined( DLL_EXPORT ) +# if defined( _MSC_VER ) || defined ( __INTEL_COMPILER ) +# define VOID_RETURN __declspec( dllexport ) void __stdcall +# define INT_RETURN __declspec( dllexport ) int __stdcall +# elif defined( __GNUC__ ) +# define VOID_RETURN __declspec( __dllexport__ ) void +# define INT_RETURN __declspec( __dllexport__ ) int +# else +# error Use of the DLL is only available on the Microsoft, Intel and GCC compilers +# endif +# elif defined( DLL_IMPORT ) +# if defined( _MSC_VER ) || defined ( __INTEL_COMPILER ) +# define VOID_RETURN __declspec( dllimport ) void __stdcall +# define INT_RETURN __declspec( dllimport ) int __stdcall +# elif defined( __GNUC__ ) +# define VOID_RETURN __declspec( __dllimport__ ) void +# define INT_RETURN __declspec( __dllimport__ ) int +# else +# error Use of the DLL is only available on the Microsoft, Intel and GCC compilers +# endif +# elif defined( __WATCOMC__ ) +# define VOID_RETURN void __cdecl +# define INT_RETURN int __cdecl +# else +# define VOID_RETURN void +# define INT_RETURN int +# endif +#endif + +/* These defines are used to detect and set the memory alignment of pointers. + Note that offsets are in bytes. + + ALIGN_OFFSET(x,n) return the positive or zero offset of + the memory addressed by the pointer 'x' + from an address that is aligned on an + 'n' byte boundary ('n' is a power of 2) + + ALIGN_FLOOR(x,n) return a pointer that points to memory + that is aligned on an 'n' byte boundary + and is not higher than the memory address + pointed to by 'x' ('n' is a power of 2) + + ALIGN_CEIL(x,n) return a pointer that points to memory + that is aligned on an 'n' byte boundary + and is not lower than the memory address + pointed to by 'x' ('n' is a power of 2) +*/ + +#define ALIGN_OFFSET(x,n) (((ptrint_t)(x)) & ((n) - 1)) +#define ALIGN_FLOOR(x,n) ((uint8_t*)(x) - ( ((ptrint_t)(x)) & ((n) - 1))) +#define ALIGN_CEIL(x,n) ((uint8_t*)(x) + (-((ptrint_t)(x)) & ((n) - 1))) + +/* These defines are used to declare buffers in a way that allows + faster operations on longer variables to be used. In all these + defines 'size' must be a power of 2 and >= 8. NOTE that the + buffer size is in bytes but the type length is in bits + + UNIT_TYPEDEF(x,size) declares a variable 'x' of length + 'size' bits + + BUFR_TYPEDEF(x,size,bsize) declares a buffer 'x' of length 'bsize' + bytes defined as an array of variables + each of 'size' bits (bsize must be a + multiple of size / 8) + + UNIT_CAST(x,size) casts a variable to a type of + length 'size' bits + + UPTR_CAST(x,size) casts a pointer to a pointer to a + varaiable of length 'size' bits +*/ + +#define UI_TYPE(size) uint##size##_t +#define UNIT_TYPEDEF(x,size) typedef UI_TYPE(size) x +#define BUFR_TYPEDEF(x,size,bsize) typedef UI_TYPE(size) x[bsize / (size >> 3)] +#define UNIT_CAST(x,size) ((UI_TYPE(size) )(x)) +#define UPTR_CAST(x,size) ((UI_TYPE(size)*)(x)) + +#if defined(__cplusplus) +} +#endif + +#endif From ea227fd805fb97aa2fa76a89bfd05d44012d153f Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 8 May 2017 17:15:54 +0200 Subject: [PATCH 410/627] update readme for sources --- README.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 53a994255..fcfd50be4 100644 --- a/README.md +++ b/README.md @@ -18,10 +18,22 @@ These include: - HMAC-SHA256 and HMAC-SHA512 - PBKDF2 - RIPEMD-160 -- SHA256/SHA512 +- SHA1 +- SHA2-256/SHA2-512 - SHA3/Keccak - BLAKE2s/BLAKE2b - unit tests (using Check - check.sf.net; in tests.c) - tests against OpenSSL (in test-openssl.c) Distibuted under MIT License. + +## Some parts of the library come from external sources: + +- AES: https://github.com/BrianGladman/aes +- Base58: https://github.com/luke-jr/libbase58 +- BLAKE2s/BLAKE2b: https://github.com/BLAKE2/BLAKE2 +- RIPEMD-160: https://github.com/ARMmbed/mbedtls +- SHA1/SHA2: http://www.aarongifford.com/computers/sha.html +- SHA3: https://github.com/rhash/RHash +- Curve25519: https://github.com/agl/curve25519-donna +- Ed25519: https://github.com/floodyberry/ed25519-donna From f6195d8aecc39dcbf366ef9e04ef5ff0233aeefb Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 8 May 2017 17:53:48 +0200 Subject: [PATCH 411/627] update CMakeLists.txt as well --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index df68483c8..21c0839cc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 2.8) -set(SOURCES address.c aescrypt.c aeskey.c aes_modes.c aestab.c base58.c bignum.c bip32.c bip39.c ecdsa.c hmac.c nist256p1.c pbkdf2.c rand.c ripemd160.c secp256k1.c sha2.c ed25519-donna/ed25519.c sha3.c) +set(SOURCES address.c aes/aescrypt.c aes/aeskey.c aes/aes_modes.c aes/aestab.c base58.c bignum.c bip32.c bip39.c ecdsa.c hmac.c nist256p1.c pbkdf2.c rand.c ripemd160.c secp256k1.c sha2.c ed25519-donna/ed25519.c sha3.c) add_library(TrezorCrypto STATIC ${SOURCES}) From d6d7919c87b57b6cab83a84635f4a84de1437992 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 11 May 2017 13:27:34 +0200 Subject: [PATCH 412/627] add chacha20poly1305 --- Makefile | 9 +- README.md | 3 + chacha20poly1305/chacha20poly1305.c | 59 +++++ chacha20poly1305/chacha20poly1305.h | 18 ++ chacha20poly1305/chacha_merged.c | 244 +++++++++++++++++++++ chacha20poly1305/ecrypt-config.h | 316 +++++++++++++++++++++++++++ chacha20poly1305/ecrypt-machine.h | 49 +++++ chacha20poly1305/ecrypt-portable.h | 310 ++++++++++++++++++++++++++ chacha20poly1305/ecrypt-sync.h | 281 ++++++++++++++++++++++++ chacha20poly1305/poly1305-donna-32.h | 219 +++++++++++++++++++ chacha20poly1305/poly1305-donna.c | 201 +++++++++++++++++ chacha20poly1305/poly1305-donna.h | 20 ++ chacha20poly1305/rfc7539.c | 43 ++++ chacha20poly1305/rfc7539.h | 10 + 14 files changed, 1780 insertions(+), 2 deletions(-) create mode 100644 chacha20poly1305/chacha20poly1305.c create mode 100644 chacha20poly1305/chacha20poly1305.h create mode 100644 chacha20poly1305/chacha_merged.c create mode 100644 chacha20poly1305/ecrypt-config.h create mode 100644 chacha20poly1305/ecrypt-machine.h create mode 100644 chacha20poly1305/ecrypt-portable.h create mode 100644 chacha20poly1305/ecrypt-sync.h create mode 100644 chacha20poly1305/poly1305-donna-32.h create mode 100644 chacha20poly1305/poly1305-donna.c create mode 100644 chacha20poly1305/poly1305-donna.h create mode 100644 chacha20poly1305/rfc7539.c create mode 100644 chacha20poly1305/rfc7539.h diff --git a/Makefile b/Makefile index e2c5e4163..15247cf1f 100644 --- a/Makefile +++ b/Makefile @@ -25,7 +25,10 @@ CFLAGS += $(OPTFLAGS) \ # disable sequence point warning because of AES code CFLAGS += -Wno-sequence-point -CFLAGS += -I. -Iaes -Ied25519-donna +CFLAGS += -I. +CFLAGS += -Iaes +CFLAGS += -Ichacha20poly1305 +CFLAGS += -Ied25519-donna CFLAGS += -DUSE_ETHEREUM=1 CFLAGS += -DUSE_GRAPHENE=1 @@ -43,6 +46,7 @@ SRCS += sha3.c SRCS += aes/aescrypt.c aes/aeskey.c aes/aestab.c aes/aes_modes.c SRCS += ed25519-donna/ed25519.c SRCS += blake2b.c blake2s.c +SRCS += chacha20poly1305/chacha20poly1305.c chacha20poly1305/chacha_merged.c chacha20poly1305/poly1305-donna.c chacha20poly1305/rfc7539.c OBJS = $(SRCS:.c=.o) @@ -78,5 +82,6 @@ tools/bip39bruteforce: tools/bip39bruteforce.o $(OBJS) $(CC) tools/bip39bruteforce.o $(OBJS) -o tools/bip39bruteforce clean: - rm -f *.o aes/*.o ed25519-donna/*.o tests test_speed test-openssl libtrezor-crypto.so + rm -f *.o aes/*.o chacha20poly1305/*.o ed25519-donna/*.o + rm -f tests test_speed test-openssl libtrezor-crypto.so rm -f tools/*.o tools/xpubaddrgen tools/mktable tools/bip39bruteforce diff --git a/README.md b/README.md index fcfd50be4..d3001a4d9 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ These include: - SHA2-256/SHA2-512 - SHA3/Keccak - BLAKE2s/BLAKE2b +- Chacha20-Poly1305 - unit tests (using Check - check.sf.net; in tests.c) - tests against OpenSSL (in test-openssl.c) @@ -37,3 +38,5 @@ Distibuted under MIT License. - SHA3: https://github.com/rhash/RHash - Curve25519: https://github.com/agl/curve25519-donna - Ed25519: https://github.com/floodyberry/ed25519-donna +- Chacha20: https://github.com/wg/c20p1305 +- Poly1305: https://github.com/floodyberry/poly1305-donna diff --git a/chacha20poly1305/chacha20poly1305.c b/chacha20poly1305/chacha20poly1305.c new file mode 100644 index 000000000..70662a03d --- /dev/null +++ b/chacha20poly1305/chacha20poly1305.c @@ -0,0 +1,59 @@ +// Implementations of the XChaCha20 + Poly1305 and ChaCha20 + Poly1305 +// AEAD constructions with a goal of simplicity and correctness rather +// than performance. + +#include "chacha20poly1305.h" + +void hchacha20(ECRYPT_ctx *x,u8 *c); + +// Initialize the XChaCha20 + Poly1305 context for encryption or decryption +// using a 32 byte key and 24 byte nonce. The key and the first 16 bytes of +// the nonce are used as input to HChaCha20 to derive the Chacha20 key. +void xchacha20poly1305_init(chacha20poly1305_ctx *ctx, uint8_t key[32], uint8_t nonce[24]) { + unsigned char subkey[32] = {0}; + unsigned char block0[64] = {0}; + ECRYPT_ctx tmp; + + // Generate the Chacha20 key by applying HChaCha20 to the + // original key and the first 16 bytes of the nonce. + ECRYPT_keysetup(&tmp, key, 256, 16); + tmp.input[12] = U8TO32_LITTLE(nonce + 0); + tmp.input[13] = U8TO32_LITTLE(nonce + 4); + tmp.input[14] = U8TO32_LITTLE(nonce + 8); + tmp.input[15] = U8TO32_LITTLE(nonce + 12); + hchacha20(&tmp, subkey); + + // Initialize Chacha20 with the newly generated key and + // the last 8 bytes of the nonce. + ECRYPT_keysetup(&ctx->chacha20, subkey, 256, 16); + ECRYPT_ivsetup(&ctx->chacha20, nonce+16); + + // Encrypt 64 bytes of zeros and use the first 32 bytes + // as the Poly1305 key. + ECRYPT_encrypt_bytes(&ctx->chacha20, block0, block0, 64); + poly1305_init(&ctx->poly1305, block0); +} + +// Encrypt n bytes of plaintext where n must be evenly divisible by the +// Chacha20 blocksize of 64, except for the final n bytes of plaintext. +void chacha20poly1305_encrypt(chacha20poly1305_ctx *ctx, uint8_t *in, uint8_t *out, size_t n) { + ECRYPT_encrypt_bytes(&ctx->chacha20, in, out, n); + poly1305_update(&ctx->poly1305, out, n); +} + +// Decrypt n bytes of ciphertext where n must be evenly divisible by the +// Chacha20 blocksize of 64, except for the final n bytes of ciphertext. +void chacha20poly1305_decrypt(chacha20poly1305_ctx *ctx, uint8_t *in, uint8_t *out, size_t n) { + poly1305_update(&ctx->poly1305, in, n); + ECRYPT_encrypt_bytes(&ctx->chacha20, in, out, n); +} + +// Include authenticated data in the Poly1305 MAC. +void chacha20poly1305_auth(chacha20poly1305_ctx *ctx, uint8_t *in, size_t n) { + poly1305_update(&ctx->poly1305, in, n); +} + +// Compute NaCl secretbox-style Poly1305 MAC. +void chacha20poly1305_finish(chacha20poly1305_ctx *ctx, uint8_t mac[16]) { + poly1305_finish(&ctx->poly1305, mac); +} diff --git a/chacha20poly1305/chacha20poly1305.h b/chacha20poly1305/chacha20poly1305.h new file mode 100644 index 000000000..785b81c73 --- /dev/null +++ b/chacha20poly1305/chacha20poly1305.h @@ -0,0 +1,18 @@ +#ifndef CHACHA20POLY1305_H +#define CHACHA20POLY1305_H + +#include "ecrypt-sync.h" +#include "poly1305-donna.h" + +typedef struct { + ECRYPT_ctx chacha20; + poly1305_context poly1305; +} chacha20poly1305_ctx; + +void xchacha20poly1305_init(chacha20poly1305_ctx *ctx, uint8_t key[32], uint8_t nonce[24]); +void chacha20poly1305_encrypt(chacha20poly1305_ctx *ctx, uint8_t *in, uint8_t *out, size_t n); +void chacha20poly1305_decrypt(chacha20poly1305_ctx *ctx, uint8_t *in, uint8_t *out, size_t n); +void chacha20poly1305_auth(chacha20poly1305_ctx *ctx, uint8_t *in, size_t n); +void chacha20poly1305_finish(chacha20poly1305_ctx *ctx, uint8_t mac[16]); + +#endif // CHACHA20POLY1305_H diff --git a/chacha20poly1305/chacha_merged.c b/chacha20poly1305/chacha_merged.c new file mode 100644 index 000000000..22d09e149 --- /dev/null +++ b/chacha20poly1305/chacha_merged.c @@ -0,0 +1,244 @@ +/* +chacha-merged.c version 20080118 +D. J. Bernstein +Public domain. +*/ + +#include "ecrypt-sync.h" + +#define ROTATE(v,c) (ROTL32(v,c)) +#define XOR(v,w) ((v) ^ (w)) +#define PLUS(v,w) (U32V((v) + (w))) +#define PLUSONE(v) (PLUS((v),1)) + +#define QUARTERROUND(a,b,c,d) \ + a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \ + c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \ + a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \ + c = PLUS(c,d); b = ROTATE(XOR(b,c), 7); + +void ECRYPT_init(void) +{ + return; +} + +static const char sigma[16] = "expand 32-byte k"; +static const char tau[16] = "expand 16-byte k"; + +void ECRYPT_keysetup(ECRYPT_ctx *x,const u8 *k,u32 kbits,u32 ivbits) +{ + const char *constants; + + x->input[4] = U8TO32_LITTLE(k + 0); + x->input[5] = U8TO32_LITTLE(k + 4); + x->input[6] = U8TO32_LITTLE(k + 8); + x->input[7] = U8TO32_LITTLE(k + 12); + if (kbits == 256) { /* recommended */ + k += 16; + constants = sigma; + } else { /* kbits == 128 */ + constants = tau; + } + x->input[8] = U8TO32_LITTLE(k + 0); + x->input[9] = U8TO32_LITTLE(k + 4); + x->input[10] = U8TO32_LITTLE(k + 8); + x->input[11] = U8TO32_LITTLE(k + 12); + x->input[0] = U8TO32_LITTLE(constants + 0); + x->input[1] = U8TO32_LITTLE(constants + 4); + x->input[2] = U8TO32_LITTLE(constants + 8); + x->input[3] = U8TO32_LITTLE(constants + 12); +} + +void ECRYPT_ivsetup(ECRYPT_ctx *x,const u8 *iv) +{ + x->input[12] = 0; + x->input[13] = 0; + x->input[14] = U8TO32_LITTLE(iv + 0); + x->input[15] = U8TO32_LITTLE(iv + 4); +} + +void ECRYPT_encrypt_bytes(ECRYPT_ctx *x,const u8 *m,u8 *c,u32 bytes) +{ + u32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; + u32 j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15; + u8 *ctarget; + u8 tmp[64]; + int i; + + if (!bytes) return; + + j0 = x->input[0]; + j1 = x->input[1]; + j2 = x->input[2]; + j3 = x->input[3]; + j4 = x->input[4]; + j5 = x->input[5]; + j6 = x->input[6]; + j7 = x->input[7]; + j8 = x->input[8]; + j9 = x->input[9]; + j10 = x->input[10]; + j11 = x->input[11]; + j12 = x->input[12]; + j13 = x->input[13]; + j14 = x->input[14]; + j15 = x->input[15]; + + for (;;) { + if (bytes < 64) { + for (i = 0;i < bytes;++i) tmp[i] = m[i]; + m = tmp; + ctarget = c; + c = tmp; + } + x0 = j0; + x1 = j1; + x2 = j2; + x3 = j3; + x4 = j4; + x5 = j5; + x6 = j6; + x7 = j7; + x8 = j8; + x9 = j9; + x10 = j10; + x11 = j11; + x12 = j12; + x13 = j13; + x14 = j14; + x15 = j15; + for (i = 20;i > 0;i -= 2) { + QUARTERROUND( x0, x4, x8,x12) + QUARTERROUND( x1, x5, x9,x13) + QUARTERROUND( x2, x6,x10,x14) + QUARTERROUND( x3, x7,x11,x15) + QUARTERROUND( x0, x5,x10,x15) + QUARTERROUND( x1, x6,x11,x12) + QUARTERROUND( x2, x7, x8,x13) + QUARTERROUND( x3, x4, x9,x14) + } + x0 = PLUS(x0,j0); + x1 = PLUS(x1,j1); + x2 = PLUS(x2,j2); + x3 = PLUS(x3,j3); + x4 = PLUS(x4,j4); + x5 = PLUS(x5,j5); + x6 = PLUS(x6,j6); + x7 = PLUS(x7,j7); + x8 = PLUS(x8,j8); + x9 = PLUS(x9,j9); + x10 = PLUS(x10,j10); + x11 = PLUS(x11,j11); + x12 = PLUS(x12,j12); + x13 = PLUS(x13,j13); + x14 = PLUS(x14,j14); + x15 = PLUS(x15,j15); + + x0 = XOR(x0,U8TO32_LITTLE(m + 0)); + x1 = XOR(x1,U8TO32_LITTLE(m + 4)); + x2 = XOR(x2,U8TO32_LITTLE(m + 8)); + x3 = XOR(x3,U8TO32_LITTLE(m + 12)); + x4 = XOR(x4,U8TO32_LITTLE(m + 16)); + x5 = XOR(x5,U8TO32_LITTLE(m + 20)); + x6 = XOR(x6,U8TO32_LITTLE(m + 24)); + x7 = XOR(x7,U8TO32_LITTLE(m + 28)); + x8 = XOR(x8,U8TO32_LITTLE(m + 32)); + x9 = XOR(x9,U8TO32_LITTLE(m + 36)); + x10 = XOR(x10,U8TO32_LITTLE(m + 40)); + x11 = XOR(x11,U8TO32_LITTLE(m + 44)); + x12 = XOR(x12,U8TO32_LITTLE(m + 48)); + x13 = XOR(x13,U8TO32_LITTLE(m + 52)); + x14 = XOR(x14,U8TO32_LITTLE(m + 56)); + x15 = XOR(x15,U8TO32_LITTLE(m + 60)); + + j12 = PLUSONE(j12); + if (!j12) { + j13 = PLUSONE(j13); + /* stopping at 2^70 bytes per nonce is user's responsibility */ + } + + U32TO8_LITTLE(c + 0,x0); + U32TO8_LITTLE(c + 4,x1); + U32TO8_LITTLE(c + 8,x2); + U32TO8_LITTLE(c + 12,x3); + U32TO8_LITTLE(c + 16,x4); + U32TO8_LITTLE(c + 20,x5); + U32TO8_LITTLE(c + 24,x6); + U32TO8_LITTLE(c + 28,x7); + U32TO8_LITTLE(c + 32,x8); + U32TO8_LITTLE(c + 36,x9); + U32TO8_LITTLE(c + 40,x10); + U32TO8_LITTLE(c + 44,x11); + U32TO8_LITTLE(c + 48,x12); + U32TO8_LITTLE(c + 52,x13); + U32TO8_LITTLE(c + 56,x14); + U32TO8_LITTLE(c + 60,x15); + + if (bytes <= 64) { + if (bytes < 64) { + for (i = 0;i < bytes;++i) ctarget[i] = c[i]; + } + x->input[12] = j12; + x->input[13] = j13; + return; + } + bytes -= 64; + c += 64; + m += 64; + } +} + +void ECRYPT_decrypt_bytes(ECRYPT_ctx *x,const u8 *c,u8 *m,u32 bytes) +{ + ECRYPT_encrypt_bytes(x,c,m,bytes); +} + +void ECRYPT_keystream_bytes(ECRYPT_ctx *x,u8 *stream,u32 bytes) +{ + u32 i; + for (i = 0;i < bytes;++i) stream[i] = 0; + ECRYPT_encrypt_bytes(x,stream,stream,bytes); +} + +void hchacha20(ECRYPT_ctx *x,u8 *c) +{ + u32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; + int i; + + x0 = x->input[0]; + x1 = x->input[1]; + x2 = x->input[2]; + x3 = x->input[3]; + x4 = x->input[4]; + x5 = x->input[5]; + x6 = x->input[6]; + x7 = x->input[7]; + x8 = x->input[8]; + x9 = x->input[9]; + x10 = x->input[10]; + x11 = x->input[11]; + x12 = x->input[12]; + x13 = x->input[13]; + x14 = x->input[14]; + x15 = x->input[15]; + + for (i = 20;i > 0;i -= 2) { + QUARTERROUND( x0, x4, x8,x12) + QUARTERROUND( x1, x5, x9,x13) + QUARTERROUND( x2, x6,x10,x14) + QUARTERROUND( x3, x7,x11,x15) + QUARTERROUND( x0, x5,x10,x15) + QUARTERROUND( x1, x6,x11,x12) + QUARTERROUND( x2, x7, x8,x13) + QUARTERROUND( x3, x4, x9,x14) + } + + U32TO8_LITTLE(c + 0,x0); + U32TO8_LITTLE(c + 4,x1); + U32TO8_LITTLE(c + 8,x2); + U32TO8_LITTLE(c + 12,x3); + U32TO8_LITTLE(c + 16,x12); + U32TO8_LITTLE(c + 20,x13); + U32TO8_LITTLE(c + 24,x14); + U32TO8_LITTLE(c + 28,x15); +} diff --git a/chacha20poly1305/ecrypt-config.h b/chacha20poly1305/ecrypt-config.h new file mode 100644 index 000000000..5c0d3810a --- /dev/null +++ b/chacha20poly1305/ecrypt-config.h @@ -0,0 +1,316 @@ +/* ecrypt-config.h */ + +/* *** Normally, it should not be necessary to edit this file. *** */ + +#ifndef ECRYPT_CONFIG +#define ECRYPT_CONFIG + +/* ------------------------------------------------------------------------- */ + +/* Guess the endianness of the target architecture. */ + +/* + * The LITTLE endian machines: + */ +#if defined(__ultrix) /* Older MIPS */ +#define ECRYPT_LITTLE_ENDIAN +#elif defined(__alpha) /* Alpha */ +#define ECRYPT_LITTLE_ENDIAN +#elif defined(i386) /* x86 (gcc) */ +#define ECRYPT_LITTLE_ENDIAN +#elif defined(__i386) /* x86 (gcc) */ +#define ECRYPT_LITTLE_ENDIAN +#elif defined(__x86_64) /* x86_64 (gcc) */ +#define ECRYPT_LITTLE_ENDIAN +#elif defined(_M_IX86) /* x86 (MSC, Borland) */ +#define ECRYPT_LITTLE_ENDIAN +#elif defined(_MSC_VER) /* x86 (surely MSC) */ +#define ECRYPT_LITTLE_ENDIAN +#elif defined(__INTEL_COMPILER) /* x86 (surely Intel compiler icl.exe) */ +#define ECRYPT_LITTLE_ENDIAN + +/* + * The BIG endian machines: + */ +#elif defined(__sparc) /* Newer Sparc's */ +#define ECRYPT_BIG_ENDIAN +#elif defined(__powerpc__) /* PowerPC */ +#define ECRYPT_BIG_ENDIAN +#elif defined(__ppc__) /* PowerPC */ +#define ECRYPT_BIG_ENDIAN +#elif defined(__hppa) /* HP-PA */ +#define ECRYPT_BIG_ENDIAN + +/* + * Finally machines with UNKNOWN endianness: + */ +#elif defined (_AIX) /* RS6000 */ +#define ECRYPT_UNKNOWN +#elif defined(__aux) /* 68K */ +#define ECRYPT_UNKNOWN +#elif defined(__dgux) /* 88K (but P6 in latest boxes) */ +#define ECRYPT_UNKNOWN +#elif defined(__sgi) /* Newer MIPS */ +#define ECRYPT_UNKNOWN +#else /* Any other processor */ +#define ECRYPT_UNKNOWN +#endif + +/* ------------------------------------------------------------------------- */ + +/* + * Find minimal-width types to store 8-bit, 16-bit, 32-bit, and 64-bit + * integers. + * + * Note: to enable 64-bit types on 32-bit compilers, it might be + * necessary to switch from ISO C90 mode to ISO C99 mode (e.g., gcc + * -std=c99), or to allow compiler-specific extensions. + */ + +#include + +/* --- check char --- */ + +#if (UCHAR_MAX / 0xFU > 0xFU) +#ifndef I8T +#define I8T char +#define U8C(v) (v##U) + +#if (UCHAR_MAX == 0xFFU) +#define ECRYPT_I8T_IS_BYTE +#endif + +#endif + +#if (UCHAR_MAX / 0xFFU > 0xFFU) +#ifndef I16T +#define I16T char +#define U16C(v) (v##U) +#endif + +#if (UCHAR_MAX / 0xFFFFU > 0xFFFFU) +#ifndef I32T +#define I32T char +#define U32C(v) (v##U) +#endif + +#if (UCHAR_MAX / 0xFFFFFFFFU > 0xFFFFFFFFU) +#ifndef I64T +#define I64T char +#define U64C(v) (v##U) +#define ECRYPT_NATIVE64 +#endif + +#endif +#endif +#endif +#endif + +/* --- check short --- */ + +#if (USHRT_MAX / 0xFU > 0xFU) +#ifndef I8T +#define I8T short +#define U8C(v) (v##U) + +#if (USHRT_MAX == 0xFFU) +#define ECRYPT_I8T_IS_BYTE +#endif + +#endif + +#if (USHRT_MAX / 0xFFU > 0xFFU) +#ifndef I16T +#define I16T short +#define U16C(v) (v##U) +#endif + +#if (USHRT_MAX / 0xFFFFU > 0xFFFFU) +#ifndef I32T +#define I32T short +#define U32C(v) (v##U) +#endif + +#if (USHRT_MAX / 0xFFFFFFFFU > 0xFFFFFFFFU) +#ifndef I64T +#define I64T short +#define U64C(v) (v##U) +#define ECRYPT_NATIVE64 +#endif + +#endif +#endif +#endif +#endif + +/* --- check int --- */ + +#if (UINT_MAX / 0xFU > 0xFU) +#ifndef I8T +#define I8T int +#define U8C(v) (v##U) + +#if (ULONG_MAX == 0xFFU) +#define ECRYPT_I8T_IS_BYTE +#endif + +#endif + +#if (UINT_MAX / 0xFFU > 0xFFU) +#ifndef I16T +#define I16T int +#define U16C(v) (v##U) +#endif + +#if (UINT_MAX / 0xFFFFU > 0xFFFFU) +#ifndef I32T +#define I32T int +#define U32C(v) (v##U) +#endif + +#if (UINT_MAX / 0xFFFFFFFFU > 0xFFFFFFFFU) +#ifndef I64T +#define I64T int +#define U64C(v) (v##U) +#define ECRYPT_NATIVE64 +#endif + +#endif +#endif +#endif +#endif + +/* --- check long --- */ + +#if (ULONG_MAX / 0xFUL > 0xFUL) +#ifndef I8T +#define I8T long +#define U8C(v) (v##UL) + +#if (ULONG_MAX == 0xFFUL) +#define ECRYPT_I8T_IS_BYTE +#endif + +#endif + +#if (ULONG_MAX / 0xFFUL > 0xFFUL) +#ifndef I16T +#define I16T long +#define U16C(v) (v##UL) +#endif + +#if (ULONG_MAX / 0xFFFFUL > 0xFFFFUL) +#ifndef I32T +#define I32T long +#define U32C(v) (v##UL) +#endif + +#if (ULONG_MAX / 0xFFFFFFFFUL > 0xFFFFFFFFUL) +#ifndef I64T +#define I64T long +#define U64C(v) (v##UL) +#define ECRYPT_NATIVE64 +#endif + +#endif +#endif +#endif +#endif + +/* --- check long long --- */ + +#ifdef ULLONG_MAX + +#if (ULLONG_MAX / 0xFULL > 0xFULL) +#ifndef I8T +#define I8T long long +#define U8C(v) (v##ULL) + +#if (ULLONG_MAX == 0xFFULL) +#define ECRYPT_I8T_IS_BYTE +#endif + +#endif + +#if (ULLONG_MAX / 0xFFULL > 0xFFULL) +#ifndef I16T +#define I16T long long +#define U16C(v) (v##ULL) +#endif + +#if (ULLONG_MAX / 0xFFFFULL > 0xFFFFULL) +#ifndef I32T +#define I32T long long +#define U32C(v) (v##ULL) +#endif + +#if (ULLONG_MAX / 0xFFFFFFFFULL > 0xFFFFFFFFULL) +#ifndef I64T +#define I64T long long +#define U64C(v) (v##ULL) +#endif + +#endif +#endif +#endif +#endif + +#endif + +/* --- check __int64 --- */ + +#if !defined(__STDC__) && defined(_UI64_MAX) + +#ifndef I64T +#define I64T __int64 +#define U64C(v) (v##ui64) +#endif + +#endif + +/* --- if platform doesn't announce anything, use most common choices --- */ + +#ifndef I8T +#define I8T char +#define U8C(v) (v##U) +#endif +#ifndef I16T +#define I16T short +#define U16C(v) (v##U) +#endif +#ifndef I32T +#define I32T int +#define U32C(v) (v##U) +#endif +#ifndef I64T +#define I64T long long +#define U64C(v) (v##ULL) +#endif + +/* ------------------------------------------------------------------------- */ + +/* find the largest type on this platform (used for alignment) */ + +#if defined(__SSE__) || (defined(_MSC_VER) && (_MSC_VER >= 1300)) + +#include +#define MAXT __m128 + +#elif defined(__MMX__) + +#include +#define MAXT __m64 + +#elif defined(__ALTIVEC__) + +#define MAXT __vector int + +#else + +#define MAXT long + +#endif + +/* ------------------------------------------------------------------------- */ + +#endif diff --git a/chacha20poly1305/ecrypt-machine.h b/chacha20poly1305/ecrypt-machine.h new file mode 100644 index 000000000..d006bedec --- /dev/null +++ b/chacha20poly1305/ecrypt-machine.h @@ -0,0 +1,49 @@ +/* ecrypt-machine.h */ + +/* + * This file is included by 'ecrypt-portable.h'. It allows to override + * the default macros for specific platforms. Please carefully check + * the machine code generated by your compiler (with optimisations + * turned on) before deciding to edit this file. + */ + +/* ------------------------------------------------------------------------- */ + +#if (defined(ECRYPT_DEFAULT_ROT) && !defined(ECRYPT_MACHINE_ROT)) + +#define ECRYPT_MACHINE_ROT + +#if (defined(WIN32) && defined(_MSC_VER)) + +#undef ROTL32 +#undef ROTR32 +#undef ROTL64 +#undef ROTR64 + +#include + +#pragma intrinsic(_lrotl) /* compile rotations "inline" */ +#pragma intrinsic(_lrotr) + +#define ROTL32(v, n) _lrotl(v, n) +#define ROTR32(v, n) _lrotr(v, n) +#define ROTL64(v, n) _rotl64(v, n) +#define ROTR64(v, n) _rotr64(v, n) + +#endif + +#endif + +/* ------------------------------------------------------------------------- */ + +#if (defined(ECRYPT_DEFAULT_SWAP) && !defined(ECRYPT_MACHINE_SWAP)) + +#define ECRYPT_MACHINE_SWAP + +/* + * If you want to overwrite the default swap macros, put it here. And so on. + */ + +#endif + +/* ------------------------------------------------------------------------- */ diff --git a/chacha20poly1305/ecrypt-portable.h b/chacha20poly1305/ecrypt-portable.h new file mode 100644 index 000000000..438a464a7 --- /dev/null +++ b/chacha20poly1305/ecrypt-portable.h @@ -0,0 +1,310 @@ +/* ecrypt-portable.h */ + +/* + * WARNING: the conversions defined below are implemented as macros, + * and should be used carefully. They should NOT be used with + * parameters which perform some action. E.g., the following two lines + * are not equivalent: + * + * 1) ++x; y = ROTL32(x, n); + * 2) y = ROTL32(++x, n); + */ + +/* + * *** Please do not edit this file. *** + * + * The default macros can be overridden for specific architectures by + * editing 'ecrypt-machine.h'. + */ + +#ifndef ECRYPT_PORTABLE +#define ECRYPT_PORTABLE + +#include "ecrypt-config.h" + +/* ------------------------------------------------------------------------- */ + +/* + * The following types are defined (if available): + * + * u8: unsigned integer type, at least 8 bits + * u16: unsigned integer type, at least 16 bits + * u32: unsigned integer type, at least 32 bits + * u64: unsigned integer type, at least 64 bits + * + * s8, s16, s32, s64 -> signed counterparts of u8, u16, u32, u64 + * + * The selection of minimum-width integer types is taken care of by + * 'ecrypt-config.h'. Note: to enable 64-bit types on 32-bit + * compilers, it might be necessary to switch from ISO C90 mode to ISO + * C99 mode (e.g., gcc -std=c99). + */ + +#ifdef I8T +typedef signed I8T s8; +typedef unsigned I8T u8; +#endif + +#ifdef I16T +typedef signed I16T s16; +typedef unsigned I16T u16; +#endif + +#ifdef I32T +typedef signed I32T s32; +typedef unsigned I32T u32; +#endif + +#ifdef I64T +typedef signed I64T s64; +typedef unsigned I64T u64; +#endif + +/* + * The following macros are used to obtain exact-width results. + */ + +#define U8V(v) ((u8)(v) & U8C(0xFF)) +#define U16V(v) ((u16)(v) & U16C(0xFFFF)) +#define U32V(v) ((u32)(v) & U32C(0xFFFFFFFF)) +#define U64V(v) ((u64)(v) & U64C(0xFFFFFFFFFFFFFFFF)) + +/* ------------------------------------------------------------------------- */ + +/* + * The following macros return words with their bits rotated over n + * positions to the left/right. + */ + +#define ECRYPT_DEFAULT_ROT + +#define ROTL8(v, n) \ + (U8V((v) << (n)) | ((v) >> (8 - (n)))) + +#define ROTL16(v, n) \ + (U16V((v) << (n)) | ((v) >> (16 - (n)))) + +#define ROTL32(v, n) \ + (U32V((v) << (n)) | ((v) >> (32 - (n)))) + +#define ROTL64(v, n) \ + (U64V((v) << (n)) | ((v) >> (64 - (n)))) + +#define ROTR8(v, n) ROTL8(v, 8 - (n)) +#define ROTR16(v, n) ROTL16(v, 16 - (n)) +#define ROTR32(v, n) ROTL32(v, 32 - (n)) +#define ROTR64(v, n) ROTL64(v, 64 - (n)) + +#include "ecrypt-machine.h" + +/* ------------------------------------------------------------------------- */ + +/* + * The following macros return a word with bytes in reverse order. + */ + +#define ECRYPT_DEFAULT_SWAP + +#define SWAP16(v) \ + ROTL16(v, 8) + +#define SWAP32(v) \ + ((ROTL32(v, 8) & U32C(0x00FF00FF)) | \ + (ROTL32(v, 24) & U32C(0xFF00FF00))) + +#ifdef ECRYPT_NATIVE64 +#define SWAP64(v) \ + ((ROTL64(v, 8) & U64C(0x000000FF000000FF)) | \ + (ROTL64(v, 24) & U64C(0x0000FF000000FF00)) | \ + (ROTL64(v, 40) & U64C(0x00FF000000FF0000)) | \ + (ROTL64(v, 56) & U64C(0xFF000000FF000000))) +#else +#define SWAP64(v) \ + (((u64)SWAP32(U32V(v)) << 32) | (u64)SWAP32(U32V(v >> 32))) +#endif + +#include "ecrypt-machine.h" + +#define ECRYPT_DEFAULT_WTOW + +#ifdef ECRYPT_LITTLE_ENDIAN +#define U16TO16_LITTLE(v) (v) +#define U32TO32_LITTLE(v) (v) +#define U64TO64_LITTLE(v) (v) + +#define U16TO16_BIG(v) SWAP16(v) +#define U32TO32_BIG(v) SWAP32(v) +#define U64TO64_BIG(v) SWAP64(v) +#endif + +#ifdef ECRYPT_BIG_ENDIAN +#define U16TO16_LITTLE(v) SWAP16(v) +#define U32TO32_LITTLE(v) SWAP32(v) +#define U64TO64_LITTLE(v) SWAP64(v) + +#define U16TO16_BIG(v) (v) +#define U32TO32_BIG(v) (v) +#define U64TO64_BIG(v) (v) +#endif + +#include "ecrypt-machine.h" + +/* + * The following macros load words from an array of bytes with + * different types of endianness, and vice versa. + */ + +#define ECRYPT_DEFAULT_BTOW + +#if (!defined(ECRYPT_UNKNOWN) && defined(ECRYPT_I8T_IS_BYTE)) + +#define U8TO16_LITTLE(p) U16TO16_LITTLE(((u16*)(p))[0]) +#define U8TO32_LITTLE(p) U32TO32_LITTLE(((u32*)(p))[0]) +#define U8TO64_LITTLE(p) U64TO64_LITTLE(((u64*)(p))[0]) + +#define U8TO16_BIG(p) U16TO16_BIG(((u16*)(p))[0]) +#define U8TO32_BIG(p) U32TO32_BIG(((u32*)(p))[0]) +#define U8TO64_BIG(p) U64TO64_BIG(((u64*)(p))[0]) + +#define U16TO8_LITTLE(p, v) (((u16*)(p))[0] = U16TO16_LITTLE(v)) +#define U32TO8_LITTLE(p, v) (((u32*)(p))[0] = U32TO32_LITTLE(v)) +#define U64TO8_LITTLE(p, v) (((u64*)(p))[0] = U64TO64_LITTLE(v)) + +#define U16TO8_BIG(p, v) (((u16*)(p))[0] = U16TO16_BIG(v)) +#define U32TO8_BIG(p, v) (((u32*)(p))[0] = U32TO32_BIG(v)) +#define U64TO8_BIG(p, v) (((u64*)(p))[0] = U64TO64_BIG(v)) + +#else + +#define U8TO16_LITTLE(p) \ + (((u16)((p)[0]) ) | \ + ((u16)((p)[1]) << 8)) + +#define U8TO32_LITTLE(p) \ + (((u32)((p)[0]) ) | \ + ((u32)((p)[1]) << 8) | \ + ((u32)((p)[2]) << 16) | \ + ((u32)((p)[3]) << 24)) + +#ifdef ECRYPT_NATIVE64 +#define U8TO64_LITTLE(p) \ + (((u64)((p)[0]) ) | \ + ((u64)((p)[1]) << 8) | \ + ((u64)((p)[2]) << 16) | \ + ((u64)((p)[3]) << 24) | \ + ((u64)((p)[4]) << 32) | \ + ((u64)((p)[5]) << 40) | \ + ((u64)((p)[6]) << 48) | \ + ((u64)((p)[7]) << 56)) +#else +#define U8TO64_LITTLE(p) \ + ((u64)U8TO32_LITTLE(p) | ((u64)U8TO32_LITTLE((p) + 4) << 32)) +#endif + +#define U8TO16_BIG(p) \ + (((u16)((p)[0]) << 8) | \ + ((u16)((p)[1]) )) + +#define U8TO32_BIG(p) \ + (((u32)((p)[0]) << 24) | \ + ((u32)((p)[1]) << 16) | \ + ((u32)((p)[2]) << 8) | \ + ((u32)((p)[3]) )) + +#ifdef ECRYPT_NATIVE64 +#define U8TO64_BIG(p) \ + (((u64)((p)[0]) << 56) | \ + ((u64)((p)[1]) << 48) | \ + ((u64)((p)[2]) << 40) | \ + ((u64)((p)[3]) << 32) | \ + ((u64)((p)[4]) << 24) | \ + ((u64)((p)[5]) << 16) | \ + ((u64)((p)[6]) << 8) | \ + ((u64)((p)[7]) )) +#else +#define U8TO64_BIG(p) \ + (((u64)U8TO32_BIG(p) << 32) | (u64)U8TO32_BIG((p) + 4)) +#endif + +#define U16TO8_LITTLE(p, v) \ + do { \ + (p)[0] = U8V((v) ); \ + (p)[1] = U8V((v) >> 8); \ + } while (0) + +#define U32TO8_LITTLE(p, v) \ + do { \ + (p)[0] = U8V((v) ); \ + (p)[1] = U8V((v) >> 8); \ + (p)[2] = U8V((v) >> 16); \ + (p)[3] = U8V((v) >> 24); \ + } while (0) + +#ifdef ECRYPT_NATIVE64 +#define U64TO8_LITTLE(p, v) \ + do { \ + (p)[0] = U8V((v) ); \ + (p)[1] = U8V((v) >> 8); \ + (p)[2] = U8V((v) >> 16); \ + (p)[3] = U8V((v) >> 24); \ + (p)[4] = U8V((v) >> 32); \ + (p)[5] = U8V((v) >> 40); \ + (p)[6] = U8V((v) >> 48); \ + (p)[7] = U8V((v) >> 56); \ + } while (0) +#else +#define U64TO8_LITTLE(p, v) \ + do { \ + U32TO8_LITTLE((p), U32V((v) )); \ + U32TO8_LITTLE((p) + 4, U32V((v) >> 32)); \ + } while (0) +#endif + +#define U16TO8_BIG(p, v) \ + do { \ + (p)[0] = U8V((v) ); \ + (p)[1] = U8V((v) >> 8); \ + } while (0) + +#define U32TO8_BIG(p, v) \ + do { \ + (p)[0] = U8V((v) >> 24); \ + (p)[1] = U8V((v) >> 16); \ + (p)[2] = U8V((v) >> 8); \ + (p)[3] = U8V((v) ); \ + } while (0) + +#ifdef ECRYPT_NATIVE64 +#define U64TO8_BIG(p, v) \ + do { \ + (p)[0] = U8V((v) >> 56); \ + (p)[1] = U8V((v) >> 48); \ + (p)[2] = U8V((v) >> 40); \ + (p)[3] = U8V((v) >> 32); \ + (p)[4] = U8V((v) >> 24); \ + (p)[5] = U8V((v) >> 16); \ + (p)[6] = U8V((v) >> 8); \ + (p)[7] = U8V((v) ); \ + } while (0) +#else +#define U64TO8_BIG(p, v) \ + do { \ + U32TO8_BIG((p), U32V((v) >> 32)); \ + U32TO8_BIG((p) + 4, U32V((v) )); \ + } while (0) +#endif + +#endif + +#include "ecrypt-machine.h" + +/* ------------------------------------------------------------------------- */ + +#define AT_LEAST_ONE(n) (((n) < 1) ? 1 : (n)) + +#define ALIGN(t, v, n) \ + union { t b[n]; MAXT l[AT_LEAST_ONE(n * sizeof(t) / sizeof(MAXT))]; } v + +/* ------------------------------------------------------------------------- */ + +#endif diff --git a/chacha20poly1305/ecrypt-sync.h b/chacha20poly1305/ecrypt-sync.h new file mode 100644 index 000000000..0923d38a4 --- /dev/null +++ b/chacha20poly1305/ecrypt-sync.h @@ -0,0 +1,281 @@ +#define ECRYPT_VARIANT 1 +#define ECRYPT_API +/* ecrypt-sync.h */ + +/* + * Header file for synchronous stream ciphers without authentication + * mechanism. + * + * *** Please only edit parts marked with "[edit]". *** + */ + +#ifndef ECRYPT_SYNC +#define ECRYPT_SYNC + +#include "ecrypt-portable.h" + +/* ------------------------------------------------------------------------- */ + +/* Cipher parameters */ + +/* + * The name of your cipher. + */ +#define ECRYPT_NAME "ChaCha20" +#define ECRYPT_PROFILE "_____" + +/* + * Specify which key and IV sizes are supported by your cipher. A user + * should be able to enumerate the supported sizes by running the + * following code: + * + * for (i = 0; ECRYPT_KEYSIZE(i) <= ECRYPT_MAXKEYSIZE; ++i) + * { + * keysize = ECRYPT_KEYSIZE(i); + * + * ... + * } + * + * All sizes are in bits. + */ + +#define ECRYPT_MAXKEYSIZE 256 /* [edit] */ +#define ECRYPT_KEYSIZE(i) (128 + (i)*128) /* [edit] */ + +#define ECRYPT_MAXIVSIZE 64 /* [edit] */ +#define ECRYPT_IVSIZE(i) (64 + (i)*64) /* [edit] */ + +/* ------------------------------------------------------------------------- */ + +/* Data structures */ + +/* + * ECRYPT_ctx is the structure containing the representation of the + * internal state of your cipher. + */ + +typedef struct +{ + u32 input[16]; /* could be compressed */ + /* + * [edit] + * + * Put here all state variable needed during the encryption process. + */ +} ECRYPT_ctx; + +/* ------------------------------------------------------------------------- */ + +/* Mandatory functions */ + +/* + * Key and message independent initialization. This function will be + * called once when the program starts (e.g., to build expanded S-box + * tables). + */ +void ECRYPT_init(); + +/* + * Key setup. It is the user's responsibility to select the values of + * keysize and ivsize from the set of supported values specified + * above. + */ +void ECRYPT_keysetup( + ECRYPT_ctx* ctx, + const u8* key, + u32 keysize, /* Key size in bits. */ + u32 ivsize); /* IV size in bits. */ + +/* + * IV setup. After having called ECRYPT_keysetup(), the user is + * allowed to call ECRYPT_ivsetup() different times in order to + * encrypt/decrypt different messages with the same key but different + * IV's. + */ +void ECRYPT_ivsetup( + ECRYPT_ctx* ctx, + const u8* iv); + +/* + * Encryption/decryption of arbitrary length messages. + * + * For efficiency reasons, the API provides two types of + * encrypt/decrypt functions. The ECRYPT_encrypt_bytes() function + * (declared here) encrypts byte strings of arbitrary length, while + * the ECRYPT_encrypt_blocks() function (defined later) only accepts + * lengths which are multiples of ECRYPT_BLOCKLENGTH. + * + * The user is allowed to make multiple calls to + * ECRYPT_encrypt_blocks() to incrementally encrypt a long message, + * but he is NOT allowed to make additional encryption calls once he + * has called ECRYPT_encrypt_bytes() (unless he starts a new message + * of course). For example, this sequence of calls is acceptable: + * + * ECRYPT_keysetup(); + * + * ECRYPT_ivsetup(); + * ECRYPT_encrypt_blocks(); + * ECRYPT_encrypt_blocks(); + * ECRYPT_encrypt_bytes(); + * + * ECRYPT_ivsetup(); + * ECRYPT_encrypt_blocks(); + * ECRYPT_encrypt_blocks(); + * + * ECRYPT_ivsetup(); + * ECRYPT_encrypt_bytes(); + * + * The following sequence is not: + * + * ECRYPT_keysetup(); + * ECRYPT_ivsetup(); + * ECRYPT_encrypt_blocks(); + * ECRYPT_encrypt_bytes(); + * ECRYPT_encrypt_blocks(); + */ + +void ECRYPT_encrypt_bytes( + ECRYPT_ctx* ctx, + const u8* plaintext, + u8* ciphertext, + u32 msglen); /* Message length in bytes. */ + +void ECRYPT_decrypt_bytes( + ECRYPT_ctx* ctx, + const u8* ciphertext, + u8* plaintext, + u32 msglen); /* Message length in bytes. */ + +/* ------------------------------------------------------------------------- */ + +/* Optional features */ + +/* + * For testing purposes it can sometimes be useful to have a function + * which immediately generates keystream without having to provide it + * with a zero plaintext. If your cipher cannot provide this function + * (e.g., because it is not strictly a synchronous cipher), please + * reset the ECRYPT_GENERATES_KEYSTREAM flag. + */ + +#define ECRYPT_GENERATES_KEYSTREAM +#ifdef ECRYPT_GENERATES_KEYSTREAM + +void ECRYPT_keystream_bytes( + ECRYPT_ctx* ctx, + u8* keystream, + u32 length); /* Length of keystream in bytes. */ + +#endif + +/* ------------------------------------------------------------------------- */ + +/* Optional optimizations */ + +/* + * By default, the functions in this section are implemented using + * calls to functions declared above. However, you might want to + * implement them differently for performance reasons. + */ + +/* + * All-in-one encryption/decryption of (short) packets. + * + * The default definitions of these functions can be found in + * "ecrypt-sync.c". If you want to implement them differently, please + * undef the ECRYPT_USES_DEFAULT_ALL_IN_ONE flag. + */ +#define ECRYPT_USES_DEFAULT_ALL_IN_ONE /* [edit] */ + +void ECRYPT_encrypt_packet( + ECRYPT_ctx* ctx, + const u8* iv, + const u8* plaintext, + u8* ciphertext, + u32 msglen); + +void ECRYPT_decrypt_packet( + ECRYPT_ctx* ctx, + const u8* iv, + const u8* ciphertext, + u8* plaintext, + u32 msglen); + +/* + * Encryption/decryption of blocks. + * + * By default, these functions are defined as macros. If you want to + * provide a different implementation, please undef the + * ECRYPT_USES_DEFAULT_BLOCK_MACROS flag and implement the functions + * declared below. + */ + +#define ECRYPT_BLOCKLENGTH 64 /* [edit] */ + +#define ECRYPT_USES_DEFAULT_BLOCK_MACROS /* [edit] */ +#ifdef ECRYPT_USES_DEFAULT_BLOCK_MACROS + +#define ECRYPT_encrypt_blocks(ctx, plaintext, ciphertext, blocks) \ + ECRYPT_encrypt_bytes(ctx, plaintext, ciphertext, \ + (blocks) * ECRYPT_BLOCKLENGTH) + +#define ECRYPT_decrypt_blocks(ctx, ciphertext, plaintext, blocks) \ + ECRYPT_decrypt_bytes(ctx, ciphertext, plaintext, \ + (blocks) * ECRYPT_BLOCKLENGTH) + +#ifdef ECRYPT_GENERATES_KEYSTREAM + +#define ECRYPT_keystream_blocks(ctx, keystream, blocks) \ + ECRYPT_keystream_bytes(ctx, keystream, \ + (blocks) * ECRYPT_BLOCKLENGTH) + +#endif + +#else + +void ECRYPT_encrypt_blocks( + ECRYPT_ctx* ctx, + const u8* plaintext, + u8* ciphertext, + u32 blocks); /* Message length in blocks. */ + +void ECRYPT_decrypt_blocks( + ECRYPT_ctx* ctx, + const u8* ciphertext, + u8* plaintext, + u32 blocks); /* Message length in blocks. */ + +#ifdef ECRYPT_GENERATES_KEYSTREAM + +void ECRYPT_keystream_blocks( + ECRYPT_ctx* ctx, + const u8* keystream, + u32 blocks); /* Keystream length in blocks. */ + +#endif + +#endif + +/* + * If your cipher can be implemented in different ways, you can use + * the ECRYPT_VARIANT parameter to allow the user to choose between + * them at compile time (e.g., gcc -DECRYPT_VARIANT=3 ...). Please + * only use this possibility if you really think it could make a + * significant difference and keep the number of variants + * (ECRYPT_MAXVARIANT) as small as possible (definitely not more than + * 10). Note also that all variants should have exactly the same + * external interface (i.e., the same ECRYPT_BLOCKLENGTH, etc.). + */ +#define ECRYPT_MAXVARIANT 1 /* [edit] */ + +#ifndef ECRYPT_VARIANT +#define ECRYPT_VARIANT 1 +#endif + +#if (ECRYPT_VARIANT > ECRYPT_MAXVARIANT) +#error this variant does not exist +#endif + +/* ------------------------------------------------------------------------- */ + +#endif diff --git a/chacha20poly1305/poly1305-donna-32.h b/chacha20poly1305/poly1305-donna-32.h new file mode 100644 index 000000000..6a570f06e --- /dev/null +++ b/chacha20poly1305/poly1305-donna-32.h @@ -0,0 +1,219 @@ +/* + poly1305 implementation using 32 bit * 32 bit = 64 bit multiplication and 64 bit addition +*/ + +#if defined(_MSC_VER) + #define POLY1305_NOINLINE __declspec(noinline) +#elif defined(__GNUC__) + #define POLY1305_NOINLINE __attribute__((noinline)) +#else + #define POLY1305_NOINLINE +#endif + +#define poly1305_block_size 16 + +/* 17 + sizeof(size_t) + 14*sizeof(unsigned long) */ +typedef struct poly1305_state_internal_t { + unsigned long r[5]; + unsigned long h[5]; + unsigned long pad[4]; + size_t leftover; + unsigned char buffer[poly1305_block_size]; + unsigned char final; +} poly1305_state_internal_t; + +/* interpret four 8 bit unsigned integers as a 32 bit unsigned integer in little endian */ +static unsigned long +U8TO32(const unsigned char *p) { + return + (((unsigned long)(p[0] & 0xff) ) | + ((unsigned long)(p[1] & 0xff) << 8) | + ((unsigned long)(p[2] & 0xff) << 16) | + ((unsigned long)(p[3] & 0xff) << 24)); +} + +/* store a 32 bit unsigned integer as four 8 bit unsigned integers in little endian */ +static void +U32TO8(unsigned char *p, unsigned long v) { + p[0] = (v ) & 0xff; + p[1] = (v >> 8) & 0xff; + p[2] = (v >> 16) & 0xff; + p[3] = (v >> 24) & 0xff; +} + +void +poly1305_init(poly1305_context *ctx, const unsigned char key[32]) { + poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx; + + /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */ + st->r[0] = (U8TO32(&key[ 0]) ) & 0x3ffffff; + st->r[1] = (U8TO32(&key[ 3]) >> 2) & 0x3ffff03; + st->r[2] = (U8TO32(&key[ 6]) >> 4) & 0x3ffc0ff; + st->r[3] = (U8TO32(&key[ 9]) >> 6) & 0x3f03fff; + st->r[4] = (U8TO32(&key[12]) >> 8) & 0x00fffff; + + /* h = 0 */ + st->h[0] = 0; + st->h[1] = 0; + st->h[2] = 0; + st->h[3] = 0; + st->h[4] = 0; + + /* save pad for later */ + st->pad[0] = U8TO32(&key[16]); + st->pad[1] = U8TO32(&key[20]); + st->pad[2] = U8TO32(&key[24]); + st->pad[3] = U8TO32(&key[28]); + + st->leftover = 0; + st->final = 0; +} + +static void +poly1305_blocks(poly1305_state_internal_t *st, const unsigned char *m, size_t bytes) { + const unsigned long hibit = (st->final) ? 0 : (1UL << 24); /* 1 << 128 */ + unsigned long r0,r1,r2,r3,r4; + unsigned long s1,s2,s3,s4; + unsigned long h0,h1,h2,h3,h4; + unsigned long long d0,d1,d2,d3,d4; + unsigned long c; + + r0 = st->r[0]; + r1 = st->r[1]; + r2 = st->r[2]; + r3 = st->r[3]; + r4 = st->r[4]; + + s1 = r1 * 5; + s2 = r2 * 5; + s3 = r3 * 5; + s4 = r4 * 5; + + h0 = st->h[0]; + h1 = st->h[1]; + h2 = st->h[2]; + h3 = st->h[3]; + h4 = st->h[4]; + + while (bytes >= poly1305_block_size) { + /* h += m[i] */ + h0 += (U8TO32(m+ 0) ) & 0x3ffffff; + h1 += (U8TO32(m+ 3) >> 2) & 0x3ffffff; + h2 += (U8TO32(m+ 6) >> 4) & 0x3ffffff; + h3 += (U8TO32(m+ 9) >> 6) & 0x3ffffff; + h4 += (U8TO32(m+12) >> 8) | hibit; + + /* h *= r */ + d0 = ((unsigned long long)h0 * r0) + ((unsigned long long)h1 * s4) + ((unsigned long long)h2 * s3) + ((unsigned long long)h3 * s2) + ((unsigned long long)h4 * s1); + d1 = ((unsigned long long)h0 * r1) + ((unsigned long long)h1 * r0) + ((unsigned long long)h2 * s4) + ((unsigned long long)h3 * s3) + ((unsigned long long)h4 * s2); + d2 = ((unsigned long long)h0 * r2) + ((unsigned long long)h1 * r1) + ((unsigned long long)h2 * r0) + ((unsigned long long)h3 * s4) + ((unsigned long long)h4 * s3); + d3 = ((unsigned long long)h0 * r3) + ((unsigned long long)h1 * r2) + ((unsigned long long)h2 * r1) + ((unsigned long long)h3 * r0) + ((unsigned long long)h4 * s4); + d4 = ((unsigned long long)h0 * r4) + ((unsigned long long)h1 * r3) + ((unsigned long long)h2 * r2) + ((unsigned long long)h3 * r1) + ((unsigned long long)h4 * r0); + + /* (partial) h %= p */ + c = (unsigned long)(d0 >> 26); h0 = (unsigned long)d0 & 0x3ffffff; + d1 += c; c = (unsigned long)(d1 >> 26); h1 = (unsigned long)d1 & 0x3ffffff; + d2 += c; c = (unsigned long)(d2 >> 26); h2 = (unsigned long)d2 & 0x3ffffff; + d3 += c; c = (unsigned long)(d3 >> 26); h3 = (unsigned long)d3 & 0x3ffffff; + d4 += c; c = (unsigned long)(d4 >> 26); h4 = (unsigned long)d4 & 0x3ffffff; + h0 += c * 5; c = (h0 >> 26); h0 = h0 & 0x3ffffff; + h1 += c; + + m += poly1305_block_size; + bytes -= poly1305_block_size; + } + + st->h[0] = h0; + st->h[1] = h1; + st->h[2] = h2; + st->h[3] = h3; + st->h[4] = h4; +} + +POLY1305_NOINLINE void +poly1305_finish(poly1305_context *ctx, unsigned char mac[16]) { + poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx; + unsigned long h0,h1,h2,h3,h4,c; + unsigned long g0,g1,g2,g3,g4; + unsigned long long f; + unsigned long mask; + + /* process the remaining block */ + if (st->leftover) { + size_t i = st->leftover; + st->buffer[i++] = 1; + for (; i < poly1305_block_size; i++) + st->buffer[i] = 0; + st->final = 1; + poly1305_blocks(st, st->buffer, poly1305_block_size); + } + + /* fully carry h */ + h0 = st->h[0]; + h1 = st->h[1]; + h2 = st->h[2]; + h3 = st->h[3]; + h4 = st->h[4]; + + c = h1 >> 26; h1 = h1 & 0x3ffffff; + h2 += c; c = h2 >> 26; h2 = h2 & 0x3ffffff; + h3 += c; c = h3 >> 26; h3 = h3 & 0x3ffffff; + h4 += c; c = h4 >> 26; h4 = h4 & 0x3ffffff; + h0 += c * 5; c = h0 >> 26; h0 = h0 & 0x3ffffff; + h1 += c; + + /* compute h + -p */ + g0 = h0 + 5; c = g0 >> 26; g0 &= 0x3ffffff; + g1 = h1 + c; c = g1 >> 26; g1 &= 0x3ffffff; + g2 = h2 + c; c = g2 >> 26; g2 &= 0x3ffffff; + g3 = h3 + c; c = g3 >> 26; g3 &= 0x3ffffff; + g4 = h4 + c - (1UL << 26); + + /* select h if h < p, or h + -p if h >= p */ + mask = (g4 >> ((sizeof(unsigned long) * 8) - 1)) - 1; + g0 &= mask; + g1 &= mask; + g2 &= mask; + g3 &= mask; + g4 &= mask; + mask = ~mask; + h0 = (h0 & mask) | g0; + h1 = (h1 & mask) | g1; + h2 = (h2 & mask) | g2; + h3 = (h3 & mask) | g3; + h4 = (h4 & mask) | g4; + + /* h = h % (2^128) */ + h0 = ((h0 ) | (h1 << 26)) & 0xffffffff; + h1 = ((h1 >> 6) | (h2 << 20)) & 0xffffffff; + h2 = ((h2 >> 12) | (h3 << 14)) & 0xffffffff; + h3 = ((h3 >> 18) | (h4 << 8)) & 0xffffffff; + + /* mac = (h + pad) % (2^128) */ + f = (unsigned long long)h0 + st->pad[0] ; h0 = (unsigned long)f; + f = (unsigned long long)h1 + st->pad[1] + (f >> 32); h1 = (unsigned long)f; + f = (unsigned long long)h2 + st->pad[2] + (f >> 32); h2 = (unsigned long)f; + f = (unsigned long long)h3 + st->pad[3] + (f >> 32); h3 = (unsigned long)f; + + U32TO8(mac + 0, h0); + U32TO8(mac + 4, h1); + U32TO8(mac + 8, h2); + U32TO8(mac + 12, h3); + + /* zero out the state */ + st->h[0] = 0; + st->h[1] = 0; + st->h[2] = 0; + st->h[3] = 0; + st->h[4] = 0; + st->r[0] = 0; + st->r[1] = 0; + st->r[2] = 0; + st->r[3] = 0; + st->r[4] = 0; + st->pad[0] = 0; + st->pad[1] = 0; + st->pad[2] = 0; + st->pad[3] = 0; +} + diff --git a/chacha20poly1305/poly1305-donna.c b/chacha20poly1305/poly1305-donna.c new file mode 100644 index 000000000..c1e3c74b5 --- /dev/null +++ b/chacha20poly1305/poly1305-donna.c @@ -0,0 +1,201 @@ +#include "poly1305-donna.h" + +#if defined(POLY1305_8BIT) +#include "poly1305-donna-8.h" +#elif defined(POLY1305_16BIT) +#include "poly1305-donna-16.h" +#elif defined(POLY1305_32BIT) +#include "poly1305-donna-32.h" +#elif defined(POLY1305_64BIT) +#include "poly1305-donna-64.h" +#else + +/* auto detect between 32bit / 64bit */ +#define HAS_SIZEOF_INT128_64BIT (defined(__SIZEOF_INT128__) && defined(__LP64__)) +#define HAS_MSVC_64BIT (defined(_MSC_VER) && defined(_M_X64)) +#define HAS_GCC_4_4_64BIT (defined(__GNUC__) && defined(__LP64__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)))) + +#if (HAS_SIZEOF_INT128_64BIT || HAS_MSVC_64BIT || HAS_GCC_4_4_64BIT) +#include "poly1305-donna-64.h" +#else +#include "poly1305-donna-32.h" +#endif + +#endif + +void +poly1305_update(poly1305_context *ctx, const unsigned char *m, size_t bytes) { + poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx; + size_t i; + + /* handle leftover */ + if (st->leftover) { + size_t want = (poly1305_block_size - st->leftover); + if (want > bytes) + want = bytes; + for (i = 0; i < want; i++) + st->buffer[st->leftover + i] = m[i]; + bytes -= want; + m += want; + st->leftover += want; + if (st->leftover < poly1305_block_size) + return; + poly1305_blocks(st, st->buffer, poly1305_block_size); + st->leftover = 0; + } + + /* process full blocks */ + if (bytes >= poly1305_block_size) { + size_t want = (bytes & ~(poly1305_block_size - 1)); + poly1305_blocks(st, m, want); + m += want; + bytes -= want; + } + + /* store leftover */ + if (bytes) { + for (i = 0; i < bytes; i++) + st->buffer[st->leftover + i] = m[i]; + st->leftover += bytes; + } +} + +void +poly1305_auth(unsigned char mac[16], const unsigned char *m, size_t bytes, const unsigned char key[32]) { + poly1305_context ctx; + poly1305_init(&ctx, key); + poly1305_update(&ctx, m, bytes); + poly1305_finish(&ctx, mac); +} + +int +poly1305_verify(const unsigned char mac1[16], const unsigned char mac2[16]) { + size_t i; + unsigned int dif = 0; + for (i = 0; i < 16; i++) + dif |= (mac1[i] ^ mac2[i]); + dif = (dif - 1) >> ((sizeof(unsigned int) * 8) - 1); + return (dif & 1); +} + + +/* test a few basic operations */ +int +poly1305_power_on_self_test(void) { + /* example from nacl */ + static const unsigned char nacl_key[32] = { + 0xee,0xa6,0xa7,0x25,0x1c,0x1e,0x72,0x91, + 0x6d,0x11,0xc2,0xcb,0x21,0x4d,0x3c,0x25, + 0x25,0x39,0x12,0x1d,0x8e,0x23,0x4e,0x65, + 0x2d,0x65,0x1f,0xa4,0xc8,0xcf,0xf8,0x80, + }; + + static const unsigned char nacl_msg[131] = { + 0x8e,0x99,0x3b,0x9f,0x48,0x68,0x12,0x73, + 0xc2,0x96,0x50,0xba,0x32,0xfc,0x76,0xce, + 0x48,0x33,0x2e,0xa7,0x16,0x4d,0x96,0xa4, + 0x47,0x6f,0xb8,0xc5,0x31,0xa1,0x18,0x6a, + 0xc0,0xdf,0xc1,0x7c,0x98,0xdc,0xe8,0x7b, + 0x4d,0xa7,0xf0,0x11,0xec,0x48,0xc9,0x72, + 0x71,0xd2,0xc2,0x0f,0x9b,0x92,0x8f,0xe2, + 0x27,0x0d,0x6f,0xb8,0x63,0xd5,0x17,0x38, + 0xb4,0x8e,0xee,0xe3,0x14,0xa7,0xcc,0x8a, + 0xb9,0x32,0x16,0x45,0x48,0xe5,0x26,0xae, + 0x90,0x22,0x43,0x68,0x51,0x7a,0xcf,0xea, + 0xbd,0x6b,0xb3,0x73,0x2b,0xc0,0xe9,0xda, + 0x99,0x83,0x2b,0x61,0xca,0x01,0xb6,0xde, + 0x56,0x24,0x4a,0x9e,0x88,0xd5,0xf9,0xb3, + 0x79,0x73,0xf6,0x22,0xa4,0x3d,0x14,0xa6, + 0x59,0x9b,0x1f,0x65,0x4c,0xb4,0x5a,0x74, + 0xe3,0x55,0xa5 + }; + + static const unsigned char nacl_mac[16] = { + 0xf3,0xff,0xc7,0x70,0x3f,0x94,0x00,0xe5, + 0x2a,0x7d,0xfb,0x4b,0x3d,0x33,0x05,0xd9 + }; + + /* generates a final value of (2^130 - 2) == 3 */ + static const unsigned char wrap_key[32] = { + 0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + }; + + static const unsigned char wrap_msg[16] = { + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff + }; + + static const unsigned char wrap_mac[16] = { + 0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + }; + + /* + mac of the macs of messages of length 0 to 256, where the key and messages + have all their values set to the length + */ + static const unsigned char total_key[32] = { + 0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0xff,0xfe,0xfd,0xfc,0xfb,0xfa,0xf9, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff + }; + + static const unsigned char total_mac[16] = { + 0x64,0xaf,0xe2,0xe8,0xd6,0xad,0x7b,0xbd, + 0xd2,0x87,0xf9,0x7c,0x44,0x62,0x3d,0x39 + }; + + poly1305_context ctx; + poly1305_context total_ctx; + unsigned char all_key[32]; + unsigned char all_msg[256]; + unsigned char mac[16]; + size_t i, j; + int result = 1; + + for (i = 0; i < sizeof(mac); i++) + mac[i] = 0; + poly1305_auth(mac, nacl_msg, sizeof(nacl_msg), nacl_key); + result &= poly1305_verify(nacl_mac, mac); + + for (i = 0; i < sizeof(mac); i++) + mac[i] = 0; + poly1305_init(&ctx, nacl_key); + poly1305_update(&ctx, nacl_msg + 0, 32); + poly1305_update(&ctx, nacl_msg + 32, 64); + poly1305_update(&ctx, nacl_msg + 96, 16); + poly1305_update(&ctx, nacl_msg + 112, 8); + poly1305_update(&ctx, nacl_msg + 120, 4); + poly1305_update(&ctx, nacl_msg + 124, 2); + poly1305_update(&ctx, nacl_msg + 126, 1); + poly1305_update(&ctx, nacl_msg + 127, 1); + poly1305_update(&ctx, nacl_msg + 128, 1); + poly1305_update(&ctx, nacl_msg + 129, 1); + poly1305_update(&ctx, nacl_msg + 130, 1); + poly1305_finish(&ctx, mac); + result &= poly1305_verify(nacl_mac, mac); + + for (i = 0; i < sizeof(mac); i++) + mac[i] = 0; + poly1305_auth(mac, wrap_msg, sizeof(wrap_msg), wrap_key); + result &= poly1305_verify(wrap_mac, mac); + + poly1305_init(&total_ctx, total_key); + for (i = 0; i < 256; i++) { + /* set key and message to 'i,i,i..' */ + for (j = 0; j < sizeof(all_key); j++) + all_key[j] = i; + for (j = 0; j < i; j++) + all_msg[j] = i; + poly1305_auth(mac, all_msg, i, all_key); + poly1305_update(&total_ctx, mac, 16); + } + poly1305_finish(&total_ctx, mac); + result &= poly1305_verify(total_mac, mac); + + return result; +} diff --git a/chacha20poly1305/poly1305-donna.h b/chacha20poly1305/poly1305-donna.h new file mode 100644 index 000000000..94e23533f --- /dev/null +++ b/chacha20poly1305/poly1305-donna.h @@ -0,0 +1,20 @@ +#ifndef POLY1305_DONNA_H +#define POLY1305_DONNA_H + +#include + +typedef struct poly1305_context { + size_t aligner; + unsigned char opaque[136]; +} poly1305_context; + +void poly1305_init(poly1305_context *ctx, const unsigned char key[32]); +void poly1305_update(poly1305_context *ctx, const unsigned char *m, size_t bytes); +void poly1305_finish(poly1305_context *ctx, unsigned char mac[16]); +void poly1305_auth(unsigned char mac[16], const unsigned char *m, size_t bytes, const unsigned char key[32]); + +int poly1305_verify(const unsigned char mac1[16], const unsigned char mac2[16]); +int poly1305_power_on_self_test(void); + +#endif /* POLY1305_DONNA_H */ + diff --git a/chacha20poly1305/rfc7539.c b/chacha20poly1305/rfc7539.c new file mode 100644 index 000000000..8cb26d6f0 --- /dev/null +++ b/chacha20poly1305/rfc7539.c @@ -0,0 +1,43 @@ +// Implementation of the ChaCha20 + Poly1305 AEAD construction +// as described in RFC 7539. + +#include "rfc7539.h" + +// Initialize the ChaCha20 + Poly1305 context for encryption or decryption +// using a 32 byte key and 12 byte nonce as in the RFC 7539 style. +void rfc7539_init(chacha20poly1305_ctx *ctx, uint8_t key[32], uint8_t nonce[12]) { + unsigned char block0[64] = {0}; + + ECRYPT_keysetup(&ctx->chacha20, key, 256, 16); + ctx->chacha20.input[13] = U8TO32_LITTLE(nonce + 0); + ctx->chacha20.input[14] = U8TO32_LITTLE(nonce + 4); + ctx->chacha20.input[15] = U8TO32_LITTLE(nonce + 8); + + // Encrypt 64 bytes of zeros and use the first 32 bytes + // as the Poly1305 key. + ECRYPT_encrypt_bytes(&ctx->chacha20, block0, block0, 64); + poly1305_init(&ctx->poly1305, block0); +} + +// Include authenticated data in the Poly1305 MAC using the RFC 7539 +// style with 16 byte padding. This must only be called once and prior +// to encryption or decryption. +void rfc7539_auth(chacha20poly1305_ctx *ctx, uint8_t *in, size_t n) { + uint8_t padding[16] = {0}; + poly1305_update(&ctx->poly1305, in, n); + poly1305_update(&ctx->poly1305, padding, 16 - n%16); +} + +// Compute RFC 7539-style Poly1305 MAC. +void rfc7539_finish(chacha20poly1305_ctx *ctx, int64_t alen, int64_t plen, uint8_t mac[16]) { + uint8_t padding[16] = {0}; + uint8_t lengths[16] = {0}; + + U64TO8_LITTLE(lengths + 0, alen); + U64TO8_LITTLE(lengths + 8, plen); + + poly1305_update(&ctx->poly1305, padding, 16 - plen%16); + poly1305_update(&ctx->poly1305, lengths, 16); + + poly1305_finish(&ctx->poly1305, mac); +} diff --git a/chacha20poly1305/rfc7539.h b/chacha20poly1305/rfc7539.h new file mode 100644 index 000000000..2bd4990b6 --- /dev/null +++ b/chacha20poly1305/rfc7539.h @@ -0,0 +1,10 @@ +#ifndef RFC7539_H +#define RFC7539_H + +#include "chacha20poly1305.h" + +void rfc7539_init(chacha20poly1305_ctx *ctx, uint8_t key[32], uint8_t nonce[12]); +void rfc7539_auth(chacha20poly1305_ctx *ctx, uint8_t *in, size_t n); +void rfc7539_finish(chacha20poly1305_ctx *ctx, int64_t alen, int64_t plen, uint8_t mac[16]); + +#endif // RFC7539_H From 1ae459912f11f715ce16c3750cd44aed8f87890f Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 11 May 2017 13:27:59 +0200 Subject: [PATCH 413/627] fix chacha20poly1305 issues --- chacha20poly1305/chacha20poly1305.h | 1 + chacha20poly1305/chacha_merged.c | 7 ++++--- chacha20poly1305/ecrypt-sync.h | 2 +- chacha20poly1305/poly1305-donna.c | 22 ---------------------- chacha20poly1305/rfc7539.c | 5 +++-- 5 files changed, 9 insertions(+), 28 deletions(-) diff --git a/chacha20poly1305/chacha20poly1305.h b/chacha20poly1305/chacha20poly1305.h index 785b81c73..d02ea0c60 100644 --- a/chacha20poly1305/chacha20poly1305.h +++ b/chacha20poly1305/chacha20poly1305.h @@ -1,6 +1,7 @@ #ifndef CHACHA20POLY1305_H #define CHACHA20POLY1305_H +#include #include "ecrypt-sync.h" #include "poly1305-donna.h" diff --git a/chacha20poly1305/chacha_merged.c b/chacha20poly1305/chacha_merged.c index 22d09e149..f2845846c 100644 --- a/chacha20poly1305/chacha_merged.c +++ b/chacha20poly1305/chacha_merged.c @@ -27,6 +27,7 @@ static const char tau[16] = "expand 16-byte k"; void ECRYPT_keysetup(ECRYPT_ctx *x,const u8 *k,u32 kbits,u32 ivbits) { + (void)ivbits; const char *constants; x->input[4] = U8TO32_LITTLE(k + 0); @@ -61,7 +62,7 @@ void ECRYPT_encrypt_bytes(ECRYPT_ctx *x,const u8 *m,u8 *c,u32 bytes) { u32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; u32 j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15; - u8 *ctarget; + u8 *ctarget = 0; u8 tmp[64]; int i; @@ -86,7 +87,7 @@ void ECRYPT_encrypt_bytes(ECRYPT_ctx *x,const u8 *m,u8 *c,u32 bytes) for (;;) { if (bytes < 64) { - for (i = 0;i < bytes;++i) tmp[i] = m[i]; + for (i = 0;i < (int)bytes;++i) tmp[i] = m[i]; m = tmp; ctarget = c; c = tmp; @@ -176,7 +177,7 @@ void ECRYPT_encrypt_bytes(ECRYPT_ctx *x,const u8 *m,u8 *c,u32 bytes) if (bytes <= 64) { if (bytes < 64) { - for (i = 0;i < bytes;++i) ctarget[i] = c[i]; + for (i = 0;i < (int)bytes;++i) ctarget[i] = c[i]; } x->input[12] = j12; x->input[13] = j13; diff --git a/chacha20poly1305/ecrypt-sync.h b/chacha20poly1305/ecrypt-sync.h index 0923d38a4..5f363d4c8 100644 --- a/chacha20poly1305/ecrypt-sync.h +++ b/chacha20poly1305/ecrypt-sync.h @@ -73,7 +73,7 @@ typedef struct * called once when the program starts (e.g., to build expanded S-box * tables). */ -void ECRYPT_init(); +void ECRYPT_init(void); /* * Key setup. It is the user's responsibility to select the values of diff --git a/chacha20poly1305/poly1305-donna.c b/chacha20poly1305/poly1305-donna.c index c1e3c74b5..f8964e010 100644 --- a/chacha20poly1305/poly1305-donna.c +++ b/chacha20poly1305/poly1305-donna.c @@ -1,27 +1,5 @@ #include "poly1305-donna.h" - -#if defined(POLY1305_8BIT) -#include "poly1305-donna-8.h" -#elif defined(POLY1305_16BIT) -#include "poly1305-donna-16.h" -#elif defined(POLY1305_32BIT) -#include "poly1305-donna-32.h" -#elif defined(POLY1305_64BIT) -#include "poly1305-donna-64.h" -#else - -/* auto detect between 32bit / 64bit */ -#define HAS_SIZEOF_INT128_64BIT (defined(__SIZEOF_INT128__) && defined(__LP64__)) -#define HAS_MSVC_64BIT (defined(_MSC_VER) && defined(_M_X64)) -#define HAS_GCC_4_4_64BIT (defined(__GNUC__) && defined(__LP64__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)))) - -#if (HAS_SIZEOF_INT128_64BIT || HAS_MSVC_64BIT || HAS_GCC_4_4_64BIT) -#include "poly1305-donna-64.h" -#else #include "poly1305-donna-32.h" -#endif - -#endif void poly1305_update(poly1305_context *ctx, const unsigned char *m, size_t bytes) { diff --git a/chacha20poly1305/rfc7539.c b/chacha20poly1305/rfc7539.c index 8cb26d6f0..585a695d9 100644 --- a/chacha20poly1305/rfc7539.c +++ b/chacha20poly1305/rfc7539.c @@ -1,6 +1,7 @@ // Implementation of the ChaCha20 + Poly1305 AEAD construction // as described in RFC 7539. +#include #include "rfc7539.h" // Initialize the ChaCha20 + Poly1305 context for encryption or decryption @@ -33,8 +34,8 @@ void rfc7539_finish(chacha20poly1305_ctx *ctx, int64_t alen, int64_t plen, uint8 uint8_t padding[16] = {0}; uint8_t lengths[16] = {0}; - U64TO8_LITTLE(lengths + 0, alen); - U64TO8_LITTLE(lengths + 8, plen); + memcpy(lengths, &alen, sizeof(int64_t)); + memcpy(lengths + 8, &plen, sizeof(int64_t)); poly1305_update(&ctx->poly1305, padding, 16 - plen%16); poly1305_update(&ctx->poly1305, lengths, 16); From af01ef71fc51b57e2de9436c65a235ea94b33df2 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 17 May 2017 17:49:35 +0200 Subject: [PATCH 414/627] bignum: add bn_format --- Makefile | 2 +- bignum.c | 52 +++++++++++++++++++++ bignum.h | 2 + tests.c | 135 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 189 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 15247cf1f..ea978be05 100644 --- a/Makefile +++ b/Makefile @@ -53,7 +53,7 @@ OBJS = $(SRCS:.c=.o) TESTLIBS = $(shell pkg-config --libs check) -lrt -lpthread -lm TESTSSLLIBS = -lcrypto -all: tests test-openssl libtrezor-crypto.so test_speed tools +all: tests test-openssl test_speed tools libtrezor-crypto.so %.o: %.c %.h options.h $(CC) $(CFLAGS) -o $@ -c $< diff --git a/bignum.c b/bignum.c index b2a20f974..c06bd53da 100644 --- a/bignum.c +++ b/bignum.c @@ -960,6 +960,58 @@ void bn_divmod1000(bignum256 *a, uint32_t *r) *r = rem; } +// 2^256 has 78 digits in decimal (+ 1 for decimal point, + 1 for leading zero, + 1 for trailing zero) +#define DIGITLEN (78 + 1 + 1 + 1) + +int bn_format(const bignum256 *amnt, const char *prefix, const char *suffix, int decimals, char *out, int outlen) +{ + // convert bignum to characters + bignum256 val; + memcpy(&val, amnt, sizeof(bignum256)); + char digits[DIGITLEN]; + memset(digits, '0', DIGITLEN); + int pos = 1; // keep one trailing zero + for (int i = 0; i < 78 / 3; i++) { + uint32_t limb; + bn_divmod1000(&val, &limb); + if (pos == decimals + 1) { digits[DIGITLEN - 1 - pos] = '.'; pos++; } + digits[DIGITLEN - 1 - pos] = '0' + (limb % 10); pos++; + if (pos == decimals + 1) { digits[DIGITLEN - 1 - pos] = '.'; pos++; } + digits[DIGITLEN - 1 - pos] = '0' + ((limb / 10) % 10); pos++; + if (pos == decimals + 1) { digits[DIGITLEN - 1 - pos] = '.'; pos++; } + digits[DIGITLEN - 1 - pos] = '0' + ((limb / 100) % 10); pos++; + } + + // drop leading zeroes + int digitstart = 0; + while (digitstart < DIGITLEN - 1 && digits[digitstart] == '0' && digits[digitstart + 1] >= '0' && digits[digitstart + 1] <= '9') { + digitstart++; + } + + // drop trailing zeroes + int digitend = DIGITLEN - 1; + while (digitend > 0 && digits[digitend] == '0' && digits[digitend - 1] >= '0' && digits[digitend - 1] <= '9') { + digitend--; + } + + int digitslen = digitend - digitstart + 1; + int prefixlen = prefix != NULL ? strlen(prefix) : 0; + int suffixlen = suffix != NULL ? strlen(suffix) : 0; + + // output buffer is too small + if (prefixlen + digitslen + suffixlen + 1 > outlen) { + return 0; + } + + // copy result to output buffer + memcpy(out, prefix, prefixlen); + memcpy(out + prefixlen, digits + digitstart, digitslen); + memcpy(out + prefixlen + digitslen, suffix, suffixlen); + out[prefixlen + digitslen + suffixlen] = 0; + + return prefixlen + digitslen + suffixlen; +} + #if USE_BN_PRINT void bn_print(const bignum256 *a) { diff --git a/bignum.h b/bignum.h index 83ae314ce..8e23ab976 100644 --- a/bignum.h +++ b/bignum.h @@ -145,6 +145,8 @@ void bn_divmod58(bignum256 *a, uint32_t *r); void bn_divmod1000(bignum256 *a, uint32_t *r); +int bn_format(const bignum256 *amnt, const char *prefix, const char *suffix, int decimals, char *out, int outlen); + #if USE_BN_PRINT void bn_print(const bignum256 *a); void bn_print_raw(const bignum256 *a); diff --git a/tests.c b/tests.c index f77752837..4c9c6be21 100644 --- a/tests.c +++ b/tests.c @@ -353,6 +353,138 @@ START_TEST(test_bignum_is_less) } END_TEST +START_TEST(test_bignum_format) { + bignum256 a; + char buf[128]; + int r; + + bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000000"), &a); + r = bn_format(&a, NULL, NULL, 0, buf, sizeof(buf)); + ck_assert_int_eq(r, 3); + ck_assert_str_eq(buf, "0.0"); + + bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000000"), &a); + r = bn_format(&a, "", "", 0, buf, sizeof(buf)); + ck_assert_int_eq(r, 3); + ck_assert_str_eq(buf, "0.0"); + + bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000000"), &a); + r = bn_format(&a, NULL, "SFFX", 0, buf, sizeof(buf)); + ck_assert_int_eq(r, 3 + 4); + ck_assert_str_eq(buf, "0.0SFFX"); + + bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000000"), &a); + r = bn_format(&a, "PRFX", NULL, 0, buf, sizeof(buf)); + ck_assert_int_eq(r, 4 + 3); + ck_assert_str_eq(buf, "PRFX0.0"); + + bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000000"), &a); + r = bn_format(&a, "PRFX", "SFFX", 0, buf, sizeof(buf)); + ck_assert_int_eq(r, 4 + 3 + 4); + ck_assert_str_eq(buf, "PRFX0.0SFFX"); + + bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000000"), &a); + r = bn_format(&a, NULL, NULL, 18, buf, sizeof(buf)); + ck_assert_int_eq(r, 3); + ck_assert_str_eq(buf, "0.0"); + + bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000001"), &a); + r = bn_format(&a, NULL, NULL, 0, buf, sizeof(buf)); + ck_assert_int_eq(r, 3); + ck_assert_str_eq(buf, "1.0"); + + bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000002"), &a); + r = bn_format(&a, NULL, NULL, 0, buf, sizeof(buf)); + ck_assert_int_eq(r, 3); + ck_assert_str_eq(buf, "2.0"); + + bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000005"), &a); + r = bn_format(&a, NULL, NULL, 0, buf, sizeof(buf)); + ck_assert_int_eq(r, 3); + ck_assert_str_eq(buf, "5.0"); + + bn_read_be(fromhex("000000000000000000000000000000000000000000000000000000000000000a"), &a); + r = bn_format(&a, NULL, NULL, 0, buf, sizeof(buf)); + ck_assert_int_eq(r, 4); + ck_assert_str_eq(buf, "10.0"); + + bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000014"), &a); + r = bn_format(&a, NULL, NULL, 0, buf, sizeof(buf)); + ck_assert_int_eq(r, 4); + ck_assert_str_eq(buf, "20.0"); + + bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000032"), &a); + r = bn_format(&a, NULL, NULL, 0, buf, sizeof(buf)); + ck_assert_int_eq(r, 4); + ck_assert_str_eq(buf, "50.0"); + + bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000064"), &a); + r = bn_format(&a, NULL, NULL, 0, buf, sizeof(buf)); + ck_assert_int_eq(r, 5); + ck_assert_str_eq(buf, "100.0"); + + bn_read_be(fromhex("00000000000000000000000000000000000000000000000000000000000000c8"), &a); + r = bn_format(&a, NULL, NULL, 0, buf, sizeof(buf)); + ck_assert_int_eq(r, 5); + ck_assert_str_eq(buf, "200.0"); + + bn_read_be(fromhex("00000000000000000000000000000000000000000000000000000000000001f4"), &a); + r = bn_format(&a, NULL, NULL, 0, buf, sizeof(buf)); + ck_assert_int_eq(r, 5); + ck_assert_str_eq(buf, "500.0"); + + bn_read_be(fromhex("00000000000000000000000000000000000000000000000000000000000003e8"), &a); + r = bn_format(&a, NULL, NULL, 0, buf, sizeof(buf)); + ck_assert_int_eq(r, 6); + ck_assert_str_eq(buf, "1000.0"); + + bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000989680"), &a); + r = bn_format(&a, NULL, NULL, 7, buf, sizeof(buf)); + ck_assert_int_eq(r, 3); + ck_assert_str_eq(buf, "1.0"); + + bn_read_be(fromhex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), &a); + r = bn_format(&a, NULL, NULL, 0, buf, sizeof(buf)); + ck_assert_int_eq(r, 80); + ck_assert_str_eq(buf, "115792089237316195423570985008687907853269984665640564039457584007913129639935.0"); + + bn_read_be(fromhex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), &a); + r = bn_format(&a, NULL, NULL, 1, buf, sizeof(buf)); + ck_assert_int_eq(r, 79); + ck_assert_str_eq(buf, "11579208923731619542357098500868790785326998466564056403945758400791312963993.5"); + + bn_read_be(fromhex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), &a); + r = bn_format(&a, NULL, NULL, 2, buf, sizeof(buf)); + ck_assert_int_eq(r, 79); + ck_assert_str_eq(buf, "1157920892373161954235709850086879078532699846656405640394575840079131296399.35"); + + bn_read_be(fromhex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), &a); + r = bn_format(&a, NULL, NULL, 8, buf, sizeof(buf)); + ck_assert_int_eq(r, 79); + ck_assert_str_eq(buf, "1157920892373161954235709850086879078532699846656405640394575840079131.29639935"); + + bn_read_be(fromhex("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffe3bbb00"), &a); + r = bn_format(&a, NULL, NULL, 8, buf, sizeof(buf)); + ck_assert_int_eq(r, 72); + ck_assert_str_eq(buf, "1157920892373161954235709850086879078532699846656405640394575840079131.0"); + + bn_read_be(fromhex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), &a); + r = bn_format(&a, NULL, NULL, 18, buf, sizeof(buf)); + ck_assert_int_eq(r, 79); + ck_assert_str_eq(buf, "115792089237316195423570985008687907853269984665640564039457.584007913129639935"); + + bn_read_be(fromhex("fffffffffffffffffffffffffffffffffffffffffffffffff7e52fe5afe40000"), &a); + r = bn_format(&a, NULL, NULL, 18, buf, sizeof(buf)); + ck_assert_int_eq(r, 62); + ck_assert_str_eq(buf, "115792089237316195423570985008687907853269984665640564039457.0"); + + bn_read_be(fromhex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), &a); + r = bn_format(&a, "quite a long prefix", "even longer suffix", 60, buf, sizeof(buf)); + ck_assert_int_eq(r, 116); + ck_assert_str_eq(buf, "quite a long prefix115792089237316195.423570985008687907853269984665640564039457584007913129639935even longer suffix"); +} +END_TEST + // from https://github.com/bitcoin/bitcoin/blob/master/src/test/data/base58_keys_valid.json START_TEST(test_base58) { @@ -2960,6 +3092,7 @@ Suite *test_suite(void) tcase_add_test(tc, test_bignum_is_odd); tcase_add_test(tc, test_bignum_bitcount); tcase_add_test(tc, test_bignum_is_less); + tcase_add_test(tc, test_bignum_format); suite_add_tcase(s, tc); tc = tcase_create("base58"); @@ -3107,7 +3240,7 @@ Suite *test_suite(void) tcase_add_test(tc, test_ethereum_pubkeyhash); suite_add_tcase(s, tc); - tc = tcase_create("multibyte_addresse"); + tc = tcase_create("multibyte_address"); tcase_add_test(tc, test_multibyte_address); suite_add_tcase(s, tc); From f029bd876ec5fce6ab65eedc8b3b2d3059ba1391 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sat, 3 Jun 2017 14:08:04 +0100 Subject: [PATCH 415/627] check_mem: Fix Check 0.11 --- check_mem.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/check_mem.h b/check_mem.h index a66751e21..be8a43cd6 100644 --- a/check_mem.h +++ b/check_mem.h @@ -1,6 +1,8 @@ #ifndef CHECK_MEM_H #define CHECK_MEM_H +#if CHECK_MAJOR_VERSION == 0 && CHECK_MINOR_VERSION < 11 + #define _ck_assert_mem(X, Y, L, OP) do { \ const char* _ck_x = (const char*)(void*)(X); \ const char* _ck_y = (const char*)(void*)(Y); \ @@ -24,3 +26,5 @@ #define ck_assert_mem_ne(X, Y, L) _ck_assert_mem(X, Y, L, !=) #endif + +#endif From 7f07896c9b58a76c67f1f57846b680b65fffc75a Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sat, 3 Jun 2017 14:13:29 +0100 Subject: [PATCH 416/627] tests: Add {UN,}MARK_SECRET_DATA macros --- tests.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests.c b/tests.c index 4c9c6be21..40a6657c4 100644 --- a/tests.c +++ b/tests.c @@ -30,6 +30,9 @@ #include #include "check_mem.h" +#include +#include + #include "options.h" #include "aes.h" @@ -51,6 +54,16 @@ #include "script.h" #include "rfc6979.h" +/* + * This is a clever trick to make Valgrind's Memcheck verify code + * is constant-time with respect to secret data. + */ + +/* Call after secret data is written, before first use */ +#define MARK_SECRET_DATA(addr, len) VALGRIND_MAKE_MEM_UNDEFINED(addr, len) +/* Call before secret data is freed */ +#define UNMARK_SECRET_DATA(addr, len) VALGRIND_MAKE_MEM_DEFINED (addr, len) + #define FROMHEX_MAXLEN 256 #define VERSION_PUBLIC 0x0488b21e From d5b148ad5f2313dc308a0ccd3f131cb2b42a92a4 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sat, 3 Jun 2017 15:34:56 +0100 Subject: [PATCH 417/627] travis.yml: Add Valgrind --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 0b07782ad..4d9dcdf61 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,6 +14,7 @@ addons: - cmake-data - libssl-dev - python-pip + - valgrind install: - pip install --user pytest ecdsa curve25519-donna @@ -21,6 +22,7 @@ install: script: - make - ./tests + - CK_TIMEOUT_MULTIPLIER=20 valgrind -q --error-exitcode=1 ./tests - ./test-openssl 1000 - ITERS=10 py.test - mkdir _build && cd _build && cmake .. && make && cd .. From 50301f22ec3979a0ccf27b95a4b78730151d2fe9 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sat, 3 Jun 2017 15:47:06 +0100 Subject: [PATCH 418/627] tests: Skip speed tests when running on Valgrind --- tests.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tests.c b/tests.c index 40a6657c4..2d9bbbcc8 100644 --- a/tests.c +++ b/tests.c @@ -3157,10 +3157,12 @@ Suite *test_suite(void) tcase_add_test(tc, test_rfc6979); suite_add_tcase(s, tc); - tc = tcase_create("speed"); - tcase_add_test(tc, test_sign_speed); - tcase_add_test(tc, test_verify_speed); - suite_add_tcase(s, tc); + if (!RUNNING_ON_VALGRIND) { + tc = tcase_create("speed"); + tcase_add_test(tc, test_sign_speed); + tcase_add_test(tc, test_verify_speed); + suite_add_tcase(s, tc); + } tc = tcase_create("address"); tcase_add_test(tc, test_address); From 27c7474856b2d6aa3a9afca02f1391c68d3cd8a9 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sat, 3 Jun 2017 15:53:09 +0100 Subject: [PATCH 419/627] tests: Split curve tests into individual tests --- tests.c | 51 ++++++++++++++++++++------------------------------- 1 file changed, 20 insertions(+), 31 deletions(-) diff --git a/tests.c b/tests.c index 2d9bbbcc8..c0d5d5451 100644 --- a/tests.c +++ b/tests.c @@ -2594,11 +2594,8 @@ static void test_codepoints_curve(const ecdsa_curve *curve) { } } -START_TEST(test_codepoints) { - test_codepoints_curve(&secp256k1); - test_codepoints_curve(&nist256p1); -} -END_TEST +START_TEST(test_codepoints_secp256k1) { test_codepoints_curve(&secp256k1); } END_TEST +START_TEST(test_codepoints_nist256p1) { test_codepoints_curve(&nist256p1); } END_TEST static void test_mult_border_cases_curve(const ecdsa_curve *curve) { bignum256 a; @@ -2645,11 +2642,8 @@ static void test_mult_border_cases_curve(const ecdsa_curve *curve) { ck_assert_mem_eq(&p, &expected, sizeof(curve_point)); } -START_TEST(test_mult_border_cases) { - test_mult_border_cases_curve(&secp256k1); - test_mult_border_cases_curve(&nist256p1); -} -END_TEST +START_TEST(test_mult_border_cases_secp256k1) { test_mult_border_cases_curve(&secp256k1); } END_TEST +START_TEST(test_mult_border_cases_nist256p1) { test_mult_border_cases_curve(&nist256p1); } END_TEST static void test_scalar_mult_curve(const ecdsa_curve *curve) { int i; @@ -2674,11 +2668,8 @@ static void test_scalar_mult_curve(const ecdsa_curve *curve) { } } -START_TEST(test_scalar_mult) { - test_scalar_mult_curve(&secp256k1); - test_scalar_mult_curve(&nist256p1); -} -END_TEST +START_TEST(test_scalar_mult_secp256k1) { test_scalar_mult_curve(&secp256k1); } END_TEST +START_TEST(test_scalar_mult_nist256p1) { test_scalar_mult_curve(&nist256p1); } END_TEST static void test_point_mult_curve(const ecdsa_curve *curve) { int i; @@ -2705,11 +2696,8 @@ static void test_point_mult_curve(const ecdsa_curve *curve) { } } -START_TEST(test_point_mult) { - test_point_mult_curve(&secp256k1); - test_point_mult_curve(&nist256p1); -} -END_TEST +START_TEST(test_point_mult_secp256k1) { test_point_mult_curve(&secp256k1); } END_TEST +START_TEST(test_point_mult_nist256p1) { test_point_mult_curve(&nist256p1); } END_TEST static void test_scalar_point_mult_curve(const ecdsa_curve *curve) { int i; @@ -2743,11 +2731,8 @@ static void test_scalar_point_mult_curve(const ecdsa_curve *curve) { } } -START_TEST(test_scalar_point_mult) { - test_scalar_point_mult_curve(&secp256k1); - test_scalar_point_mult_curve(&nist256p1); -} -END_TEST +START_TEST(test_scalar_point_mult_secp256k1) { test_scalar_point_mult_curve(&secp256k1); } END_TEST +START_TEST(test_scalar_point_mult_nist256p1) { test_scalar_point_mult_curve(&nist256p1); } END_TEST START_TEST(test_ed25519) { // test vectors from https://github.com/torproject/tor/blob/master/src/test/ed25519_vectors.inc @@ -3219,24 +3204,28 @@ Suite *test_suite(void) suite_add_tcase(s, tc); tc = tcase_create("codepoints"); - tcase_add_test(tc, test_codepoints); - tcase_set_timeout(tc, 8); + tcase_add_test(tc, test_codepoints_secp256k1); + tcase_add_test(tc, test_codepoints_nist256p1); suite_add_tcase(s, tc); tc = tcase_create("mult_border_cases"); - tcase_add_test(tc, test_mult_border_cases); + tcase_add_test(tc, test_mult_border_cases_secp256k1); + tcase_add_test(tc, test_mult_border_cases_nist256p1); suite_add_tcase(s, tc); tc = tcase_create("scalar_mult"); - tcase_add_test(tc, test_scalar_mult); + tcase_add_test(tc, test_scalar_mult_secp256k1); + tcase_add_test(tc, test_scalar_mult_nist256p1); suite_add_tcase(s, tc); tc = tcase_create("point_mult"); - tcase_add_test(tc, test_point_mult); + tcase_add_test(tc, test_point_mult_secp256k1); + tcase_add_test(tc, test_point_mult_nist256p1); suite_add_tcase(s, tc); tc = tcase_create("scalar_point_mult"); - tcase_add_test(tc, test_scalar_point_mult); + tcase_add_test(tc, test_scalar_point_mult_secp256k1); + tcase_add_test(tc, test_scalar_point_mult_nist256p1); suite_add_tcase(s, tc); tc = tcase_create("ed25519"); From edb31b89a8f1c0cefd04e0bd6422564b21f118fe Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 3 Jun 2017 23:43:58 +0200 Subject: [PATCH 420/627] remove test_{sign,verify}_speed from tests.c, rename tests to test_check.c, rework test_speed --- .gitignore | 4 +- .travis.yml | 6 +- CMakeLists.txt | 12 +-- Makefile | 12 +-- README.md | 4 +- tests.c => test_check.c | 146 +++++---------------------- test-openssl.c => test_openssl.c | 0 test_speed.c | 163 +++++++++++++++++++++---------- 8 files changed, 156 insertions(+), 191 deletions(-) rename tests.c => test_check.c (97%) rename test-openssl.c => test_openssl.c (100%) diff --git a/.gitignore b/.gitignore index 5b2841e7f..683ecbe3e 100644 --- a/.gitignore +++ b/.gitignore @@ -2,9 +2,9 @@ *.d *.exe *~ -test-openssl +test_openssl test_speed -tests +test_check *.os *.so *.pyc diff --git a/.travis.yml b/.travis.yml index 4d9dcdf61..8a5c3ef25 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,9 +21,9 @@ install: script: - make - - ./tests - - CK_TIMEOUT_MULTIPLIER=20 valgrind -q --error-exitcode=1 ./tests - - ./test-openssl 1000 + - ./test_check + - CK_TIMEOUT_MULTIPLIER=20 valgrind -q --error-exitcode=1 ./test_check + - ./test_openssl 1000 - ITERS=10 py.test - mkdir _build && cd _build && cmake .. && make && cd .. diff --git a/CMakeLists.txt b/CMakeLists.txt index 21c0839cc..37e076366 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,11 +19,11 @@ endif(MSVC) # Build trezor-crypto tests (requires OpenSSL) if (TREZOR_CRYPTO_TESTS) - add_executable(tests tests.c) - target_link_libraries(tests TrezorCrypto check rt pthread m crypto) - add_test(NAME trezor-crypto COMMAND tests) + add_executable(test_check test_check.c) + target_link_libraries(test_check TrezorCrypto check rt pthread m crypto) + add_test(NAME trezor-crypto COMMAND test_check) - add_executable(test-openssl test-openssl.c) - target_link_libraries(test-openssl TrezorCrypto check rt pthread m crypto) - add_test(NAME trezor-crypto-openssl COMMAND test-openssl 100) + add_executable(test_openssl test_openssl.c) + target_link_libraries(test_openssl TrezorCrypto check rt pthread m crypto) + add_test(NAME trezor-crypto-openssl COMMAND test_openssl 100) endif() diff --git a/Makefile b/Makefile index ea978be05..e4fb98a98 100644 --- a/Makefile +++ b/Makefile @@ -53,19 +53,19 @@ OBJS = $(SRCS:.c=.o) TESTLIBS = $(shell pkg-config --libs check) -lrt -lpthread -lm TESTSSLLIBS = -lcrypto -all: tests test-openssl test_speed tools libtrezor-crypto.so +all: test_check test_openssl test_speed tools libtrezor-crypto.so %.o: %.c %.h options.h $(CC) $(CFLAGS) -o $@ -c $< -tests: tests.o $(OBJS) - $(CC) tests.o $(OBJS) $(TESTLIBS) -o tests +test_check: test_check.o $(OBJS) + $(CC) test_check.o $(OBJS) $(TESTLIBS) -o test_check test_speed: test_speed.o $(OBJS) $(CC) test_speed.o $(OBJS) -o test_speed -test-openssl: test-openssl.o $(OBJS) - $(CC) test-openssl.o $(OBJS) $(TESTSSLLIBS) -o test-openssl +test_openssl: test_openssl.o $(OBJS) + $(CC) test_openssl.o $(OBJS) $(TESTSSLLIBS) -o test_openssl libtrezor-crypto.so: $(SRCS) $(CC) $(CFLAGS) -fPIC -shared $(SRCS) -o libtrezor-crypto.so @@ -83,5 +83,5 @@ tools/bip39bruteforce: tools/bip39bruteforce.o $(OBJS) clean: rm -f *.o aes/*.o chacha20poly1305/*.o ed25519-donna/*.o - rm -f tests test_speed test-openssl libtrezor-crypto.so + rm -f test_check test_speed test_openssl libtrezor-crypto.so rm -f tools/*.o tools/xpubaddrgen tools/mktable tools/bip39bruteforce diff --git a/README.md b/README.md index d3001a4d9..e2bf3ef49 100644 --- a/README.md +++ b/README.md @@ -23,8 +23,8 @@ These include: - SHA3/Keccak - BLAKE2s/BLAKE2b - Chacha20-Poly1305 -- unit tests (using Check - check.sf.net; in tests.c) -- tests against OpenSSL (in test-openssl.c) +- unit tests (using Check - check.sf.net; in test_check.c) +- tests against OpenSSL (in test_openssl.c) Distibuted under MIT License. diff --git a/tests.c b/test_check.c similarity index 97% rename from tests.c rename to test_check.c index c0d5d5451..ab345e5e0 100644 --- a/tests.c +++ b/test_check.c @@ -953,6 +953,32 @@ START_TEST(test_bip32_compare) } END_TEST +START_TEST(test_bip32_optimized) +{ + HDNode root; + hdnode_from_seed((uint8_t *)"NothingToSeeHere", 16, SECP256K1_NAME, &root); + hdnode_fill_public_key(&root); + + curve_point pub; + ecdsa_read_pubkey(&secp256k1, root.public_key, &pub); + + HDNode node; + char addr1[MAX_ADDR_SIZE], addr2[MAX_ADDR_SIZE]; + + for (int i = 0; i < 40; i++) { + // unoptimized + memcpy(&node, &root, sizeof(HDNode)); + hdnode_public_ckd(&node, i); + hdnode_fill_public_key(&node); + ecdsa_get_address(node.public_key, 0, addr1, sizeof(addr1)); + // optimized + hdnode_public_ckd_address_optimized(&pub, root.chain_code, i, 0, addr2, sizeof(addr2), false); + // check + ck_assert_str_eq(addr1, addr2); + } +} +END_TEST + START_TEST(test_bip32_cache_1) { HDNode node1, node2; @@ -1458,118 +1484,6 @@ START_TEST(test_rfc6979) } END_TEST -START_TEST(test_sign_speed) -{ - uint8_t sig[64], priv_key[32], msg[256]; - size_t i; - int res; - - for (i = 0; i < sizeof(msg); i++) { - msg[i] = i * 1103515245; - } - - const ecdsa_curve *curve = &secp256k1; - clock_t t = clock(); - - memcpy(priv_key, fromhex("c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd5"), 32); - for (i = 0 ; i < 250; i++) { - res = ecdsa_sign(curve, priv_key, msg, sizeof(msg), sig, NULL, NULL); - ck_assert_int_eq(res, 0); - } - - memcpy(priv_key, fromhex("509a0382ff5da48e402967a671bdcde70046d07f0df52cff12e8e3883b426a0a"), 32); - for (i = 0 ; i < 250; i++) { - res = ecdsa_sign(curve, priv_key, msg, sizeof(msg), sig, NULL, NULL); - ck_assert_int_eq(res, 0); - } - - printf("SECP256k1 signing speed: %0.2f sig/s\n", 500.0f / ((float)(clock() - t) / CLOCKS_PER_SEC)); - - curve = &nist256p1; - t = clock(); - - memcpy(priv_key, fromhex("c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd5"), 32); - for (i = 0 ; i < 250; i++) { - res = ecdsa_sign(curve, priv_key, msg, sizeof(msg), sig, NULL, NULL); - ck_assert_int_eq(res, 0); - } - - memcpy(priv_key, fromhex("509a0382ff5da48e402967a671bdcde70046d07f0df52cff12e8e3883b426a0a"), 32); - for (i = 0 ; i < 250; i++) { - res = ecdsa_sign(curve, priv_key, msg, sizeof(msg), sig, NULL, NULL); - ck_assert_int_eq(res, 0); - } - - printf("NIST256p1 signing speed: %0.2f sig/s\n", 500.0f / ((float)(clock() - t) / CLOCKS_PER_SEC)); -} -END_TEST - -START_TEST(test_verify_speed) -{ - uint8_t sig[64], pub_key33[33], pub_key65[65], msg[256]; - size_t i; - int res; - - for (i = 0; i < sizeof(msg); i++) { - msg[i] = i * 1103515245; - } - - const ecdsa_curve *curve = &secp256k1; - clock_t t = clock(); - - memcpy(sig, fromhex("88dc0db6bc5efa762e75fbcc802af69b9f1fcdbdffce748d403f687f855556e610ee8035414099ac7d89cff88a3fa246d332dfa3c78d82c801394112dda039c2"), 64); - memcpy(pub_key33, fromhex("024054fd18aeb277aeedea01d3f3986ff4e5be18092a04339dcf4e524e2c0a0974"), 33); - memcpy(pub_key65, fromhex("044054fd18aeb277aeedea01d3f3986ff4e5be18092a04339dcf4e524e2c0a09746c7083ed2097011b1223a17a644e81f59aa3de22dac119fd980b36a8ff29a244"), 65); - - for (i = 0 ; i < 25; i++) { - res = ecdsa_verify(curve, pub_key65, sig, msg, sizeof(msg)); - ck_assert_int_eq(res, 0); - res = ecdsa_verify(curve, pub_key33, sig, msg, sizeof(msg)); - ck_assert_int_eq(res, 0); - } - - memcpy(sig, fromhex("067040a2adb3d9deefeef95dae86f69671968a0b90ee72c2eab54369612fd524eb6756c5a1bb662f1175a5fa888763cddc3a07b8a045ef6ab358d8d5d1a9a745"), 64); - memcpy(pub_key33, fromhex("03ff45a5561a76be930358457d113f25fac790794ec70317eff3b97d7080d45719"), 33); - memcpy(pub_key65, fromhex("04ff45a5561a76be930358457d113f25fac790794ec70317eff3b97d7080d457196235193a15778062ddaa44aef7e6901b781763e52147f2504e268b2d572bf197"), 65); - - for (i = 0 ; i < 25; i++) { - res = ecdsa_verify(curve, pub_key65, sig, msg, sizeof(msg)); - ck_assert_int_eq(res, 0); - res = ecdsa_verify(curve, pub_key33, sig, msg, sizeof(msg)); - ck_assert_int_eq(res, 0); - } - - printf("SECP256k1 verifying speed: %0.2f sig/s\n", 100.0f / ((float)(clock() - t) / CLOCKS_PER_SEC)); - - curve = &nist256p1; - t = clock(); - - memcpy(sig, fromhex("7ed26b02c7e9664baaaa1e6ab64b3350c65ff685a7502863f357029c21c92a0dd7f2ae56d229262a8c7e97a0bfe1e7f9fd80c29df97355afa52ca07b507cecb9"), 64); - memcpy(pub_key33, fromhex("035662d692de519699000c7f5f04b2714e6a7f358c567fbcc001107ab86e4a7dea"), 33); - memcpy(pub_key65, fromhex("045662d692de519699000c7f5f04b2714e6a7f358c567fbcc001107ab86e4a7dea40523030e793724473d3cd60e436cbfc0a6e4ac5a5d0b340c5d637c6c870c00f"), 65); - - for (i = 0 ; i < 25; i++) { - res = ecdsa_verify(curve, pub_key65, sig, msg, sizeof(msg)); - //ck_assert_int_eq(res, 0); - res = ecdsa_verify(curve, pub_key33, sig, msg, sizeof(msg)); - //ck_assert_int_eq(res, 0); - } - - memcpy(sig, fromhex("6e13956f4227e66264dfcd92cf40b3b253622e96b1e1030392c0b06d9570f725dd1542164a481c0342ceb0b575f3516df536b7b90da57c381dfbd1aac6138c0b"), 64); - memcpy(pub_key33, fromhex("034b17f6b5c42b1be32c09f49056ee793e67f3ff42058123ce72fffc61d7236bc2"), 33); - memcpy(pub_key65, fromhex("044b17f6b5c42b1be32c09f49056ee793e67f3ff42058123ce72fffc61d7236bc29b6c29cbbbb2681d2b2e9c699cde8e591650d02bf4bb577ec53fd229442882e5"), 65); - - for (i = 0 ; i < 25; i++) { - res = ecdsa_verify(curve, pub_key65, sig, msg, sizeof(msg)); - //ck_assert_int_eq(res, 0); - res = ecdsa_verify(curve, pub_key33, sig, msg, sizeof(msg)); - //ck_assert_int_eq(res, 0); - } - - printf("NIST256p1 verifying speed: %0.2f sig/s\n", 100.0f / ((float)(clock() - t) / CLOCKS_PER_SEC)); -} -END_TEST - // test vectors from http://www.inconteam.com/software-development/41-encryption/55-aes-test-vectors START_TEST(test_aes) { @@ -3111,6 +3025,7 @@ Suite *test_suite(void) tcase_add_test(tc, test_bip32_vector_1); tcase_add_test(tc, test_bip32_vector_2); tcase_add_test(tc, test_bip32_compare); + tcase_add_test(tc, test_bip32_optimized); tcase_add_test(tc, test_bip32_cache_1); tcase_add_test(tc, test_bip32_cache_2); suite_add_tcase(s, tc); @@ -3142,13 +3057,6 @@ Suite *test_suite(void) tcase_add_test(tc, test_rfc6979); suite_add_tcase(s, tc); - if (!RUNNING_ON_VALGRIND) { - tc = tcase_create("speed"); - tcase_add_test(tc, test_sign_speed); - tcase_add_test(tc, test_verify_speed); - suite_add_tcase(s, tc); - } - tc = tcase_create("address"); tcase_add_test(tc, test_address); suite_add_tcase(s, tc); diff --git a/test-openssl.c b/test_openssl.c similarity index 100% rename from test-openssl.c rename to test_openssl.c diff --git a/test_speed.c b/test_speed.c index 4b0d1707c..24b97f2f5 100644 --- a/test_speed.c +++ b/test_speed.c @@ -10,7 +10,7 @@ #include "nist256p1.h" #include "ed25519.h" -static uint8_t msg[32]; +static uint8_t msg[256]; void prepare_msg(void) { @@ -19,7 +19,47 @@ void prepare_msg(void) } } -void bench_secp256k1(void) +void bench_sign_secp256k1(int iterations) +{ + uint8_t sig[64], priv[32], pby; + + const ecdsa_curve *curve = &secp256k1; + + memcpy(priv, "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", 32); + + for (int i = 0 ; i < iterations; i++) { + ecdsa_sign(curve, priv, msg, sizeof(msg), sig, &pby, NULL); + } +} + +void bench_sign_nist256p1(int iterations) +{ + uint8_t sig[64], priv[32], pby; + + const ecdsa_curve *curve = &nist256p1; + + memcpy(priv, "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", 32); + + for (int i = 0 ; i < iterations; i++) { + ecdsa_sign(curve, priv, msg, sizeof(msg), sig, &pby, NULL); + } +} + +void bench_sign_ed25519(int iterations) +{ + ed25519_public_key pk; + ed25519_secret_key sk; + ed25519_signature sig; + + memcpy(pk, "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", 32); + ed25519_publickey(sk, pk); + + for (int i = 0 ; i < iterations; i++) { + ed25519_sign(msg, sizeof(msg), sk, pk, sig); + } +} + +void bench_verify_secp256k1_33(int iterations) { uint8_t sig[64], pub[33], priv[32], pby; @@ -29,15 +69,27 @@ void bench_secp256k1(void) ecdsa_get_public_key33(curve, priv, pub); ecdsa_sign(curve, priv, msg, sizeof(msg), sig, &pby, NULL); - clock_t t = clock(); - for (int i = 0 ; i < 500; i++) { - int res = ecdsa_verify(curve, pub, sig, msg, sizeof(msg)); - assert(res == 0); + for (int i = 0 ; i < iterations; i++) { + ecdsa_verify(curve, pub, sig, msg, sizeof(msg)); } - printf("SECP256k1 verifying speed: %0.2f sig/s\n", 500.0f / ((float)(clock() - t) / CLOCKS_PER_SEC)); } -void bench_nist256p1(void) +void bench_verify_secp256k1_65(int iterations) +{ + uint8_t sig[64], pub[65], priv[32], pby; + + const ecdsa_curve *curve = &secp256k1; + + memcpy(priv, "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", 32); + ecdsa_get_public_key65(curve, priv, pub); + ecdsa_sign(curve, priv, msg, sizeof(msg), sig, &pby, NULL); + + for (int i = 0 ; i < iterations; i++) { + ecdsa_verify(curve, pub, sig, msg, sizeof(msg)); + } +} + +void bench_verify_nist256p1_33(int iterations) { uint8_t sig[64], pub[33], priv[32], pby; @@ -47,15 +99,27 @@ void bench_nist256p1(void) ecdsa_get_public_key33(curve, priv, pub); ecdsa_sign(curve, priv, msg, sizeof(msg), sig, &pby, NULL); - clock_t t = clock(); - for (int i = 0 ; i < 500; i++) { - int res = ecdsa_verify(curve, pub, sig, msg, sizeof(msg)); - assert(res == 0); + for (int i = 0 ; i < iterations; i++) { + ecdsa_verify(curve, pub, sig, msg, sizeof(msg)); } - printf("NIST256p1 verifying speed: %0.2f sig/s\n", 500.0f / ((float)(clock() - t) / CLOCKS_PER_SEC)); } -void bench_ed25519(void) +void bench_verify_nist256p1_65(int iterations) +{ + uint8_t sig[64], pub[65], priv[32], pby; + + const ecdsa_curve *curve = &nist256p1; + + memcpy(priv, "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", 32); + ecdsa_get_public_key65(curve, priv, pub); + ecdsa_sign(curve, priv, msg, sizeof(msg), sig, &pby, NULL); + + for (int i = 0 ; i < iterations; i++) { + ecdsa_verify(curve, pub, sig, msg, sizeof(msg)); + } +} + +void bench_verify_ed25519(int iterations) { ed25519_public_key pk; ed25519_secret_key sk; @@ -65,23 +129,12 @@ void bench_ed25519(void) ed25519_publickey(sk, pk); ed25519_sign(msg, sizeof(msg), sk, pk, sig); - clock_t t = clock(); - for (int i = 0 ; i < 500; i++) { - int res = ed25519_sign_open(msg, sizeof(msg), pk, sig); - assert(res == 0); + for (int i = 0 ; i < iterations; i++) { + ed25519_sign_open(msg, sizeof(msg), pk, sig); } - printf("Ed25519 verifying speed: %0.2f sig/s\n", 500.0f / ((float)(clock() - t) / CLOCKS_PER_SEC)); } -void test_verify_speed(void) -{ - prepare_msg(); - bench_secp256k1(); - bench_nist256p1(); - bench_ed25519(); -} - -void bench_curve25519(void) +void bench_multiply_curve25519(int iterations) { uint8_t result[32]; uint8_t secret[32]; @@ -90,16 +143,9 @@ void bench_curve25519(void) memcpy(secret, "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", 32); memcpy(basepoint, "\x96\x47\xda\xbe\x1e\xea\xaf\x25\x47\x1e\x68\x0b\x4d\x7c\x6f\xd1\x14\x38\x76\xbb\x77\x59\xd8\x3d\x0f\xf7\xa2\x49\x08\xfd\xda\xbc", 32); - clock_t t = clock(); - for (int i = 0 ; i < 500; i++) { + for (int i = 0 ; i < iterations; i++) { curve25519_scalarmult(result, secret, basepoint); } - printf("Curve25519 multiplying speed: %0.2f mul/s\n", 500.0f / ((float)(clock() - t) / CLOCKS_PER_SEC)); -} - -void test_multiply_speed(void) -{ - bench_curve25519(); } static HDNode root; @@ -114,17 +160,12 @@ void bench_ckd_normal(int iterations) { char addr[MAX_ADDR_SIZE]; HDNode node; - clock_t t = clock(); for (int i = 0; i < iterations; i++) { memcpy(&node, &root, sizeof(HDNode)); hdnode_public_ckd(&node, i); hdnode_fill_public_key(&node); ecdsa_get_address(node.public_key, 0, addr, sizeof(addr)); - if (i == 0 || i == iterations - 1) { - printf("address = %s\n", addr); - } } - printf("CKD normal speed: %0.2f iter/s\n", iterations / ((float)(clock() - t) / CLOCKS_PER_SEC)); } void bench_ckd_optimized(int iterations) @@ -132,26 +173,42 @@ void bench_ckd_optimized(int iterations) char addr[MAX_ADDR_SIZE]; curve_point pub; ecdsa_read_pubkey(&secp256k1, root.public_key, &pub); - clock_t t = clock(); for (int i = 0; i < iterations; i++) { hdnode_public_ckd_address_optimized(&pub, root.chain_code, i, 0, addr, sizeof(addr), false); - if (i == 0 || i == iterations -1) { - printf("address = %s\n", addr); - } } - printf("CKD optim speed: %0.2f iter/s\n", iterations / ((float)(clock() - t) / CLOCKS_PER_SEC)); } -void test_ckd_speed(int iterations) +void bench(void (*func)(int), const char *name, int iterations) { - prepare_node(); - bench_ckd_normal(iterations); - bench_ckd_optimized(iterations); + clock_t t = clock(); + func(iterations); + float speed = iterations / ((float)(clock() - t) / CLOCKS_PER_SEC); + printf("%25s: %8.2f ops/s\n", name, speed); } +#define BENCH(FUNC, ITER) bench(FUNC, #FUNC, ITER) + int main(void) { - test_verify_speed(); - test_multiply_speed(); - test_ckd_speed(1000); + + prepare_msg(); + + BENCH(bench_sign_secp256k1, 500); + BENCH(bench_verify_secp256k1_33, 500); + BENCH(bench_verify_secp256k1_65, 500); + + BENCH(bench_sign_nist256p1, 500); + BENCH(bench_verify_nist256p1_33, 500); + BENCH(bench_verify_nist256p1_65, 500); + + BENCH(bench_sign_ed25519, 4000); + BENCH(bench_verify_ed25519, 4000); + + BENCH(bench_multiply_curve25519, 4000); + + prepare_node(); + + BENCH(bench_ckd_normal, 1000); + BENCH(bench_ckd_optimized, 1000); + return 0; } From 9da2e2440a1d8aacdeadae8df80105635f1d521e Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sat, 3 Jun 2017 16:07:30 +0100 Subject: [PATCH 421/627] test_check: Add MARK_SECRET_DATA to test_ed25519{,_cosi} --- test_check.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test_check.c b/test_check.c index ab345e5e0..9aae97050 100644 --- a/test_check.c +++ b/test_check.c @@ -2688,13 +2688,21 @@ START_TEST(test_ed25519) { ed25519_signature sig; while (*ssk && *spk && *ssig) { memcpy(sk, fromhex(*ssk), 32); + MARK_SECRET_DATA(sk, sizeof(sk)); + ed25519_publickey(sk, pk); + UNMARK_SECRET_DATA(pk, sizeof(pk)); ck_assert_mem_eq(pk, fromhex(*spk), 32); + ed25519_sign(pk, 32, sk, pk, sig); + UNMARK_SECRET_DATA(sig, sizeof(sig)); ck_assert_mem_eq(sig, fromhex(*ssig), 64); + ssk += 3; spk += 3; ssig += 3; + + UNMARK_SECRET_DATA(sk, sizeof(sk)); } } END_TEST @@ -2735,10 +2743,13 @@ START_TEST(test_ed25519_cosi) { res = ed25519_cosi_combine_publickeys(R, Rs, N); ck_assert_int_eq(res, 0); + MARK_SECRET_DATA(keys, sizeof(keys)); /* phase 2: sign and combine signatures */ for (int j = 0; j < N; j++) { ed25519_cosi_sign(msg, sizeof(msg), keys[j], nonces[j], R, pk, sigs[j]); } + UNMARK_SECRET_DATA(keys, sizeof(keys)); + UNMARK_SECRET_DATA(sigs, sizeof(sigs)); ed25519_cosi_combine_signatures(sig, R, sigs, N); From 5f7d34a506763b205bdbc8ae374ecdc546f69356 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sun, 4 Jun 2017 12:47:26 +0100 Subject: [PATCH 422/627] test_check: Document UNMARK_SECRET_DATA further --- test_check.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test_check.c b/test_check.c index 9aae97050..c996360a2 100644 --- a/test_check.c +++ b/test_check.c @@ -61,7 +61,7 @@ /* Call after secret data is written, before first use */ #define MARK_SECRET_DATA(addr, len) VALGRIND_MAKE_MEM_UNDEFINED(addr, len) -/* Call before secret data is freed */ +/* Call before secret data is freed or to mark non-secret data (public keys or signatures) */ #define UNMARK_SECRET_DATA(addr, len) VALGRIND_MAKE_MEM_DEFINED (addr, len) #define FROMHEX_MAXLEN 256 From 3d6c726bc4e7728deb1a68e2f51e1f23ba4fcff8 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sun, 4 Jun 2017 13:01:26 +0100 Subject: [PATCH 423/627] test_check: Move UNMARK_SECRET_DATA in test_ed25519_cosi --- test_check.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test_check.c b/test_check.c index c996360a2..3cc675c4d 100644 --- a/test_check.c +++ b/test_check.c @@ -2748,7 +2748,6 @@ START_TEST(test_ed25519_cosi) { for (int j = 0; j < N; j++) { ed25519_cosi_sign(msg, sizeof(msg), keys[j], nonces[j], R, pk, sigs[j]); } - UNMARK_SECRET_DATA(keys, sizeof(keys)); UNMARK_SECRET_DATA(sigs, sizeof(sigs)); ed25519_cosi_combine_signatures(sig, R, sigs, N); @@ -2756,6 +2755,8 @@ START_TEST(test_ed25519_cosi) { /* check signature */ res = ed25519_sign_open(msg, sizeof(msg), pk, sig); ck_assert_int_eq(res, 0); + + UNMARK_SECRET_DATA(keys, sizeof(keys)); } } END_TEST From afdcb37f826807120cc4cba0d60ab2304f0340dc Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Thu, 25 May 2017 19:16:14 +0100 Subject: [PATCH 424/627] base32: Initial commit --- base32.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ base32.h | 28 ++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 base32.c create mode 100644 base32.h diff --git a/base32.c b/base32.c new file mode 100644 index 000000000..7f834983d --- /dev/null +++ b/base32.c @@ -0,0 +1,54 @@ +/** + * Copyright (c) 2017 Saleem Rashid + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, E1PRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "base32.h" + +static inline void base32_5to8(const uint8_t *in, uint8_t length, uint8_t *out); + +void base32_5to8(const uint8_t *in, uint8_t length, uint8_t *out) { + if (length >= 1) { + out[0] = (in[0] >> 3); + out[1] = (in[0] & 7) << 2; + } + + if (length >= 2) { + out[1] |= (in[1] >> 6); + out[2] = (in[1] >> 1) & 31; + out[3] = (in[1] & 1) << 4; + } + + if (length >= 3) { + out[3] |= (in[2] >> 4); + out[4] = (in[2] & 15) << 1; + } + + if (length >= 4) { + out[4] |= (in[3] >> 7); + out[5] = (in[3] >> 2) & 31; + out[6] = (in[3] & 3) << 3; + } + + if (length >= 5) { + out[6] |= (in[4] >> 5); + out[7] = (in[4] & 31); + } +} diff --git a/base32.h b/base32.h new file mode 100644 index 000000000..48c340c23 --- /dev/null +++ b/base32.h @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2017 Saleem Rashid + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __BASE32_H__ +#define __BASE32_H__ + +#include + +#endif From 6b7553e2f2e07f6c05f096458c87dbb85925ef01 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Thu, 25 May 2017 20:21:53 +0100 Subject: [PATCH 425/627] base32: Add base32_encode_unsafe --- base32.c | 12 ++++++++++++ base32.h | 3 +++ 2 files changed, 15 insertions(+) diff --git a/base32.c b/base32.c index 7f834983d..0f9f90f3c 100644 --- a/base32.c +++ b/base32.c @@ -24,6 +24,18 @@ static inline void base32_5to8(const uint8_t *in, uint8_t length, uint8_t *out); +void base32_encode_unsafe(const uint8_t *in, size_t inlen, uint8_t *out) { + uint8_t remainder = inlen % 5; + size_t limit = inlen - remainder; + + size_t i, j; + for (i = 0, j = 0; i < limit; i += 5, j += 8) { + base32_5to8(&in[i], 5, &out[j]); + } + + if (remainder) base32_5to8(&in[i], remainder, &out[j]); +} + void base32_5to8(const uint8_t *in, uint8_t length, uint8_t *out) { if (length >= 1) { out[0] = (in[0] >> 3); diff --git a/base32.h b/base32.h index 48c340c23..e0b49375c 100644 --- a/base32.h +++ b/base32.h @@ -23,6 +23,9 @@ #ifndef __BASE32_H__ #define __BASE32_H__ +#include #include +void base32_encode_unsafe(const uint8_t *in, size_t inlen, uint8_t *out); + #endif From b258e7f924ddada495619d9b00c2513f1944e268 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Thu, 25 May 2017 20:50:13 +0100 Subject: [PATCH 426/627] base32: Add base32_encode & base32_encoded_length --- base32.c | 35 +++++++++++++++++++++++++++++++++++ base32.h | 6 ++++++ 2 files changed, 41 insertions(+) diff --git a/base32.c b/base32.c index 0f9f90f3c..c058fdb6b 100644 --- a/base32.c +++ b/base32.c @@ -22,7 +22,28 @@ #include "base32.h" +const char *BASE32_ALPHABET_RFC4648 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ23456789"; + static inline void base32_5to8(const uint8_t *in, uint8_t length, uint8_t *out); +static inline char base32_encode_character(uint8_t base32, const char *alphabet); + +bool base32_encode(const uint8_t *in, size_t inlen, char *out, size_t outlen, const char *alphabet) { + size_t length = base32_encoded_length(inlen); + if (outlen <= length) { + return false; + } + + base32_encode_unsafe(in, inlen, (uint8_t *) out); + + for (size_t i = 0; i < length; i++) { + if (!(out[i] = base32_encode_character(out[i], alphabet))) { + return false; + } + } + + out[length] = '\0'; + return true; +} void base32_encode_unsafe(const uint8_t *in, size_t inlen, uint8_t *out) { uint8_t remainder = inlen % 5; @@ -36,6 +57,12 @@ void base32_encode_unsafe(const uint8_t *in, size_t inlen, uint8_t *out) { if (remainder) base32_5to8(&in[i], remainder, &out[j]); } +size_t base32_encoded_length(size_t inlen) { + uint8_t remainder = inlen % 5; + + return (inlen / 5) * 8 + (remainder * 8 + 4) / 5; +} + void base32_5to8(const uint8_t *in, uint8_t length, uint8_t *out) { if (length >= 1) { out[0] = (in[0] >> 3); @@ -64,3 +91,11 @@ void base32_5to8(const uint8_t *in, uint8_t length, uint8_t *out) { out[7] = (in[4] & 31); } } + +char base32_encode_character(uint8_t base32, const char *alphabet) { + if (base32 >> 5) { + return '\0'; + } + + return alphabet[base32]; +} diff --git a/base32.h b/base32.h index e0b49375c..d2d7df41d 100644 --- a/base32.h +++ b/base32.h @@ -23,9 +23,15 @@ #ifndef __BASE32_H__ #define __BASE32_H__ +#include #include #include +extern const char *BASE32_ALPHABET_RFC4648; + +bool base32_encode(const uint8_t *in, size_t inlen, char *out, size_t outlen, const char *alphabet); void base32_encode_unsafe(const uint8_t *in, size_t inlen, uint8_t *out); +size_t base32_encoded_length(size_t inlen); + #endif From 5ae3f572554ee275065c7e2a65ac9fe6e3b68e0e Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Thu, 25 May 2017 20:50:53 +0100 Subject: [PATCH 427/627] base32: Add to Makefile & CMakeLists.txt --- CMakeLists.txt | 2 +- Makefile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 37e076366..1d2d3830c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 2.8) -set(SOURCES address.c aes/aescrypt.c aes/aeskey.c aes/aes_modes.c aes/aestab.c base58.c bignum.c bip32.c bip39.c ecdsa.c hmac.c nist256p1.c pbkdf2.c rand.c ripemd160.c secp256k1.c sha2.c ed25519-donna/ed25519.c sha3.c) +set(SOURCES address.c aes/aescrypt.c aes/aeskey.c aes/aes_modes.c aes/aestab.c base32.c base58.c bignum.c bip32.c bip39.c ecdsa.c hmac.c nist256p1.c pbkdf2.c rand.c ripemd160.c secp256k1.c sha2.c ed25519-donna/ed25519.c sha3.c) add_library(TrezorCrypto STATIC ${SOURCES}) diff --git a/Makefile b/Makefile index e4fb98a98..9cbf9f93a 100644 --- a/Makefile +++ b/Makefile @@ -37,7 +37,7 @@ ifdef SMALL CFLAGS += -DUSE_PRECOMPUTED_CP=0 endif -SRCS = bignum.c ecdsa.c curves.c secp256k1.c nist256p1.c rand.c hmac.c bip32.c bip39.c pbkdf2.c base58.c +SRCS = bignum.c ecdsa.c curves.c secp256k1.c nist256p1.c rand.c hmac.c bip32.c bip39.c pbkdf2.c base58.c base32.c SRCS += address.c SRCS += script.c SRCS += ripemd160.c From 1df57c3de277ec683015eeea02f26455bfd5dc64 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Fri, 26 May 2017 17:35:28 +0100 Subject: [PATCH 428/627] tests: Add test_base32_rfc4648 --- test_check.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/test_check.c b/test_check.c index 3cc675c4d..e814da204 100644 --- a/test_check.c +++ b/test_check.c @@ -37,6 +37,7 @@ #include "aes.h" #include "bignum.h" +#include "base32.h" #include "base58.h" #include "bip32.h" #include "bip39.h" @@ -498,6 +499,38 @@ START_TEST(test_bignum_format) { } END_TEST +// https://tools.ietf.org/html/rfc4648#section-10 +START_TEST(test_base32_rfc4648) +{ + static const struct { + const char *input; + const char *output; + } tests[] = { + { "", "" }, + { "f", "MY" }, + { "fo", "MZXQ" }, + { "foo", "MZXW6" }, + { "foob", "MZXW6YQ" }, + { "fooba", "MZXW6YTB" }, + { "foobar", "MZXW6YTBOI" }, + }; + + char buffer[64]; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + const char *input = tests[i].input; + const char *output = tests[i].output; + + size_t inlen = strlen(input); + size_t outlen = base32_encoded_length(inlen); + ck_assert_int_eq(outlen, strlen(output)); + + base32_encode((uint8_t *) input, inlen, buffer, sizeof(buffer), BASE32_ALPHABET_RFC4648); + ck_assert_str_eq(buffer, output); + } +} +END_TEST + // from https://github.com/bitcoin/bitcoin/blob/master/src/test/data/base58_keys_valid.json START_TEST(test_base58) { @@ -3019,6 +3052,10 @@ Suite *test_suite(void) tcase_add_test(tc, test_bignum_format); suite_add_tcase(s, tc); + tc = tcase_create("base32"); + tcase_add_test(tc, test_base32_rfc4648); + suite_add_tcase(s, tc); + tc = tcase_create("base58"); tcase_add_test(tc, test_base58); suite_add_tcase(s, tc); From b26a44a20540be2aaac53552410f64a45bd43722 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Fri, 26 May 2017 17:47:56 +0100 Subject: [PATCH 429/627] base32: Optimize base32_encode_character --- base32.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/base32.c b/base32.c index c058fdb6b..8604b0585 100644 --- a/base32.c +++ b/base32.c @@ -25,7 +25,7 @@ const char *BASE32_ALPHABET_RFC4648 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ23456789"; static inline void base32_5to8(const uint8_t *in, uint8_t length, uint8_t *out); -static inline char base32_encode_character(uint8_t base32, const char *alphabet); +static inline int base32_encode_character(uint8_t decoded, const char *alphabet); bool base32_encode(const uint8_t *in, size_t inlen, char *out, size_t outlen, const char *alphabet) { size_t length = base32_encoded_length(inlen); @@ -36,7 +36,7 @@ bool base32_encode(const uint8_t *in, size_t inlen, char *out, size_t outlen, co base32_encode_unsafe(in, inlen, (uint8_t *) out); for (size_t i = 0; i < length; i++) { - if (!(out[i] = base32_encode_character(out[i], alphabet))) { + if ((out[i] = base32_encode_character(out[i], alphabet)) == -1) { return false; } } @@ -92,10 +92,18 @@ void base32_5to8(const uint8_t *in, uint8_t length, uint8_t *out) { } } -char base32_encode_character(uint8_t base32, const char *alphabet) { - if (base32 >> 5) { - return '\0'; +int base32_encode_character(uint8_t decoded, const char *alphabet) { + if (decoded >> 5) { + return -1; } - return alphabet[base32]; + if (alphabet == BASE32_ALPHABET_RFC4648) { + if (decoded < 26) { + return 'A' + decoded; + } else { + return '2' - 26 + decoded; + } + } + + return alphabet[decoded]; } From c4db240e702ce722357b810916b9db71b402ad24 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Fri, 26 May 2017 18:48:32 +0100 Subject: [PATCH 430/627] base32: Add base32_decoded_length --- base32.c | 6 ++++++ base32.h | 1 + test_check.c | 16 +++++++++------- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/base32.c b/base32.c index 8604b0585..4ae018ce5 100644 --- a/base32.c +++ b/base32.c @@ -63,6 +63,12 @@ size_t base32_encoded_length(size_t inlen) { return (inlen / 5) * 8 + (remainder * 8 + 4) / 5; } +size_t base32_decoded_length(size_t inlen) { + uint8_t remainder = inlen % 8; + + return (inlen / 8) * 5 + (remainder * 5) / 8; +} + void base32_5to8(const uint8_t *in, uint8_t length, uint8_t *out) { if (length >= 1) { out[0] = (in[0] >> 3); diff --git a/base32.h b/base32.h index d2d7df41d..edef9806b 100644 --- a/base32.h +++ b/base32.h @@ -33,5 +33,6 @@ bool base32_encode(const uint8_t *in, size_t inlen, char *out, size_t outlen, co void base32_encode_unsafe(const uint8_t *in, size_t inlen, uint8_t *out); size_t base32_encoded_length(size_t inlen); +size_t base32_decoded_length(size_t inlen); #endif diff --git a/test_check.c b/test_check.c index e814da204..54037b615 100644 --- a/test_check.c +++ b/test_check.c @@ -518,15 +518,17 @@ START_TEST(test_base32_rfc4648) char buffer[64]; for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - const char *input = tests[i].input; - const char *output = tests[i].output; + const char *in = tests[i].input; + const char *out = tests[i].output; - size_t inlen = strlen(input); - size_t outlen = base32_encoded_length(inlen); - ck_assert_int_eq(outlen, strlen(output)); + size_t inlen = strlen(in); + size_t outlen = strlen(out); - base32_encode((uint8_t *) input, inlen, buffer, sizeof(buffer), BASE32_ALPHABET_RFC4648); - ck_assert_str_eq(buffer, output); + ck_assert_int_eq(outlen, base32_encoded_length(inlen)); + ck_assert_int_eq(inlen, base32_decoded_length(outlen)); + + base32_encode((uint8_t *) in, inlen, buffer, sizeof(buffer), BASE32_ALPHABET_RFC4648); + ck_assert_str_eq(buffer, out); } } END_TEST From 0912c4d215b69b20365219cd825c50c5b46382a2 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Fri, 26 May 2017 19:58:40 +0100 Subject: [PATCH 431/627] base32: Add base32_decode family of functions --- base32.c | 114 +++++++++++++++++++++++++++++++++++++++++++++++++++ base32.h | 3 ++ test_check.c | 8 +++- 3 files changed, 124 insertions(+), 1 deletion(-) diff --git a/base32.c b/base32.c index 4ae018ce5..1da7e6332 100644 --- a/base32.c +++ b/base32.c @@ -22,10 +22,16 @@ #include "base32.h" +#include + const char *BASE32_ALPHABET_RFC4648 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ23456789"; static inline void base32_5to8(const uint8_t *in, uint8_t length, uint8_t *out); +static inline bool base32_8to5(const uint8_t *in, uint8_t length, uint8_t *out, const char *alphabet); +static inline void base32_8to5_raw(const uint8_t *in, uint8_t length, uint8_t *out); + static inline int base32_encode_character(uint8_t decoded, const char *alphabet); +static inline int base32_decode_character(char encoded, const char *alphabet); bool base32_encode(const uint8_t *in, size_t inlen, char *out, size_t outlen, const char *alphabet) { size_t length = base32_encoded_length(inlen); @@ -45,6 +51,19 @@ bool base32_encode(const uint8_t *in, size_t inlen, char *out, size_t outlen, co return true; } +uint8_t *base32_decode(const char *in, size_t inlen, uint8_t *out, size_t outlen, const char *alphabet) { + size_t length = base32_decoded_length(inlen); + if (outlen < length) { + return NULL; + } + + if (!base32_decode_unsafe((uint8_t *) in, inlen, (uint8_t *) out, alphabet)) { + return NULL; + } + + return &out[length]; +} + void base32_encode_unsafe(const uint8_t *in, size_t inlen, uint8_t *out) { uint8_t remainder = inlen % 5; size_t limit = inlen - remainder; @@ -57,6 +76,24 @@ void base32_encode_unsafe(const uint8_t *in, size_t inlen, uint8_t *out) { if (remainder) base32_5to8(&in[i], remainder, &out[j]); } +bool base32_decode_unsafe(const uint8_t *in, size_t inlen, uint8_t *out, const char *alphabet) { + uint8_t remainder = inlen % 8; + size_t limit = inlen - remainder; + + size_t i, j; + for (i = 0, j = 0; i < limit; i += 8, j += 5) { + if (!base32_8to5(&in[i], 8, &out[j], alphabet)) { + return false; + } + } + + if (remainder && !base32_8to5(&in[i], remainder, &out[j], alphabet)) { + return false; + } + + return true; +} + size_t base32_encoded_length(size_t inlen) { uint8_t remainder = inlen % 5; @@ -98,6 +135,61 @@ void base32_5to8(const uint8_t *in, uint8_t length, uint8_t *out) { } } +bool base32_8to5(const uint8_t *in, uint8_t length, uint8_t *out, const char *alphabet) { + if (length == 1 || length == 3 || length == 6 || length > 8) { + return false; + } + + if (alphabet) { + uint8_t decoded[length]; + + for (size_t i = 0; i < length; i++) { + int ret = base32_decode_character(in[i], alphabet); + + if (ret == -1) { + return false; + } else { + decoded[i] = ret; + } + } + + base32_8to5_raw(decoded, length, out); + } else { + base32_8to5_raw(in, length, out); + } + + return true; +} + +void base32_8to5_raw(const uint8_t *in, uint8_t length, uint8_t *out) { + if (length >= 2) { + out[0] = (in[0] << 3); + out[0] |= (in[1] >> 2); + } + + if (length >= 4) { + out[1] = (in[1] & 3) << 6; + out[1] |= (in[2] << 1); + out[1] |= (in[3] >> 4); + } + + if (length >= 5) { + out[2] = (in[3] & 15) << 4; + out[2] |= (in[4] >> 1); + } + + if (length >= 7) { + out[3] = (in[4] & 1) << 7; + out[3] |= (in[5] << 2); + out[3] |= (in[6] >> 3); + } + + if (length >= 8) { + out[4] = (in[6] & 7) << 5; + out[4] |= (in[7] & 31); + } +} + int base32_encode_character(uint8_t decoded, const char *alphabet) { if (decoded >> 5) { return -1; @@ -113,3 +205,25 @@ int base32_encode_character(uint8_t decoded, const char *alphabet) { return alphabet[decoded]; } + +int base32_decode_character(char encoded, const char *alphabet) { + if (alphabet == BASE32_ALPHABET_RFC4648) { + if (encoded >= 'A' && encoded <= 'Z') { + return encoded - 'A'; + } else if (encoded >= 'a' && encoded <= 'z') { + return encoded - 'a'; + } else if (encoded >= '2' && encoded <= '7') { + return encoded - '2' + 26; + } else { + return -1; + } + } + + const char *occurrence = strchr(alphabet, encoded); + + if (occurrence) { + return occurrence - alphabet; + } else { + return -1; + } +} diff --git a/base32.h b/base32.h index edef9806b..a4dcbc8da 100644 --- a/base32.h +++ b/base32.h @@ -32,6 +32,9 @@ extern const char *BASE32_ALPHABET_RFC4648; bool base32_encode(const uint8_t *in, size_t inlen, char *out, size_t outlen, const char *alphabet); void base32_encode_unsafe(const uint8_t *in, size_t inlen, uint8_t *out); +uint8_t *base32_decode(const char *in, size_t inlen, uint8_t *out, size_t outlen, const char *alphabet); +bool base32_decode_unsafe(const uint8_t *in, size_t inlen, uint8_t *out, const char *alphabet); + size_t base32_encoded_length(size_t inlen); size_t base32_decoded_length(size_t inlen); diff --git a/test_check.c b/test_check.c index 54037b615..4659460fa 100644 --- a/test_check.c +++ b/test_check.c @@ -527,8 +527,14 @@ START_TEST(test_base32_rfc4648) ck_assert_int_eq(outlen, base32_encoded_length(inlen)); ck_assert_int_eq(inlen, base32_decoded_length(outlen)); - base32_encode((uint8_t *) in, inlen, buffer, sizeof(buffer), BASE32_ALPHABET_RFC4648); + ck_assert(base32_encode((uint8_t *) in, inlen, buffer, sizeof(buffer), BASE32_ALPHABET_RFC4648)); ck_assert_str_eq(buffer, out); + + char *ret = (char *) base32_decode(out, outlen, (uint8_t *) buffer, sizeof(buffer), BASE32_ALPHABET_RFC4648); + ck_assert(ret); + + *ret = '\0'; + ck_assert_str_eq(buffer, in); } } END_TEST From 0afb53fba29aceabf4f8aa395ebf4861dfc16f3c Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sat, 27 May 2017 10:15:12 +0100 Subject: [PATCH 432/627] base32: Return char* from base32_encode --- base32.c | 8 ++++---- base32.h | 2 +- test_check.c | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/base32.c b/base32.c index 1da7e6332..42675e5b5 100644 --- a/base32.c +++ b/base32.c @@ -33,22 +33,22 @@ static inline void base32_8to5_raw(const uint8_t *in, uint8_t length, uint8_t *o static inline int base32_encode_character(uint8_t decoded, const char *alphabet); static inline int base32_decode_character(char encoded, const char *alphabet); -bool base32_encode(const uint8_t *in, size_t inlen, char *out, size_t outlen, const char *alphabet) { +char *base32_encode(const uint8_t *in, size_t inlen, char *out, size_t outlen, const char *alphabet) { size_t length = base32_encoded_length(inlen); if (outlen <= length) { - return false; + return NULL; } base32_encode_unsafe(in, inlen, (uint8_t *) out); for (size_t i = 0; i < length; i++) { if ((out[i] = base32_encode_character(out[i], alphabet)) == -1) { - return false; + return NULL; } } out[length] = '\0'; - return true; + return &out[length]; } uint8_t *base32_decode(const char *in, size_t inlen, uint8_t *out, size_t outlen, const char *alphabet) { diff --git a/base32.h b/base32.h index a4dcbc8da..250997967 100644 --- a/base32.h +++ b/base32.h @@ -29,7 +29,7 @@ extern const char *BASE32_ALPHABET_RFC4648; -bool base32_encode(const uint8_t *in, size_t inlen, char *out, size_t outlen, const char *alphabet); +char *base32_encode(const uint8_t *in, size_t inlen, char *out, size_t outlen, const char *alphabet); void base32_encode_unsafe(const uint8_t *in, size_t inlen, uint8_t *out); uint8_t *base32_decode(const char *in, size_t inlen, uint8_t *out, size_t outlen, const char *alphabet); diff --git a/test_check.c b/test_check.c index 4659460fa..78b97cd81 100644 --- a/test_check.c +++ b/test_check.c @@ -527,11 +527,11 @@ START_TEST(test_base32_rfc4648) ck_assert_int_eq(outlen, base32_encoded_length(inlen)); ck_assert_int_eq(inlen, base32_decoded_length(outlen)); - ck_assert(base32_encode((uint8_t *) in, inlen, buffer, sizeof(buffer), BASE32_ALPHABET_RFC4648)); + ck_assert(base32_encode((uint8_t *) in, inlen, buffer, sizeof(buffer), BASE32_ALPHABET_RFC4648) != NULL); ck_assert_str_eq(buffer, out); char *ret = (char *) base32_decode(out, outlen, (uint8_t *) buffer, sizeof(buffer), BASE32_ALPHABET_RFC4648); - ck_assert(ret); + ck_assert(ret != NULL); *ret = '\0'; ck_assert_str_eq(buffer, in); From 2edd17ab54a63ea6d624f9d7162be1507968bd8e Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Mon, 29 May 2017 09:49:38 +0100 Subject: [PATCH 433/627] base32: Handle when char is unsigned --- base32.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/base32.c b/base32.c index 42675e5b5..06760ccae 100644 --- a/base32.c +++ b/base32.c @@ -42,8 +42,12 @@ char *base32_encode(const uint8_t *in, size_t inlen, char *out, size_t outlen, c base32_encode_unsafe(in, inlen, (uint8_t *) out); for (size_t i = 0; i < length; i++) { - if ((out[i] = base32_encode_character(out[i], alphabet)) == -1) { - return NULL; + int ret = base32_encode_character(out[i], alphabet); + + if (ret == -1) { + return false; + } else { + out[i] = ret; } } From 406c926caa28898ae2647da6959f32b0506db5e8 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 5 Jun 2017 12:33:42 +0200 Subject: [PATCH 434/627] add base32 to readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index e2bf3ef49..f4afd0c66 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ These include: - ECDSA signing/verifying (supports secp256k1 and nist256p1 curves, uses RFC6979 for deterministic signatures) - ECDSA public key derivation +- Base32 (RFC4648) - Base58 address representation - Ed25519 signing/verifying - ECDH using secp256k1, nist256p1 and Curve25519 From 36e8ef48f1ee3299826e0949783ee91d785c5f63 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Tue, 16 May 2017 19:19:58 +0100 Subject: [PATCH 435/627] ed25519-donna: Add ED25519_SUFFIX --- ed25519-donna/curve25519-donna-32bit.h | 6 +- ed25519-donna/ed25519-donna-portable.h | 6 ++ ed25519-donna/ed25519.c | 117 ++++++++++++++----------- ed25519-donna/modm-donna-32bit.h | 5 +- 4 files changed, 80 insertions(+), 54 deletions(-) diff --git a/ed25519-donna/curve25519-donna-32bit.h b/ed25519-donna/curve25519-donna-32bit.h index d49e80ff0..07882043f 100644 --- a/ed25519-donna/curve25519-donna-32bit.h +++ b/ed25519-donna/curve25519-donna-32bit.h @@ -96,9 +96,11 @@ curve25519_sub(bignum25519 out, const bignum25519 a, const bignum25519 b) { out[9] = twoP13579 + a[9] - b[9] ; } +DONNA_INLINE DONNA_UNUSED static void +curve25519_scalar_product(bignum25519 out, const bignum25519 in, const uint32_t scalar); + /* out = in * scalar */ -DONNA_INLINE static void -curve25519_scalar_product(bignum25519 out, const bignum25519 in, const uint32_t scalar) { +void curve25519_scalar_product(bignum25519 out, const bignum25519 in, const uint32_t scalar) { uint64_t a; uint32_t c; a = mul32x32_64(in[0], scalar); out[0] = (uint32_t)a & reduce_mask_26; c = (uint32_t)(a >> 26); diff --git a/ed25519-donna/ed25519-donna-portable.h b/ed25519-donna/ed25519-donna-portable.h index 2fa0ac56e..70c950488 100644 --- a/ed25519-donna/ed25519-donna-portable.h +++ b/ed25519-donna/ed25519-donna-portable.h @@ -4,6 +4,12 @@ #include #include +#ifdef __GNUC__ +#define DONNA_UNUSED __attribute__((unused)) +#else +#define DONNA_UNUSED +#endif + #define DONNA_INLINE #undef ALIGN #define ALIGN(x) __attribute__((aligned(x))) diff --git a/ed25519-donna/ed25519.c b/ed25519-donna/ed25519.c index 7a117aef1..b54d505db 100644 --- a/ed25519-donna/ed25519.c +++ b/ed25519-donna/ed25519.c @@ -4,11 +4,20 @@ Ed25519 reference implementation using Ed25519-donna */ + +/* define ED25519_SUFFIX to have it appended to the end of each public function */ +#ifdef ED25519_SUFFIX +#define ED25519_FN3(fn,suffix) fn##suffix +#define ED25519_FN2(fn,suffix) ED25519_FN3(fn,suffix) +#define ED25519_FN(fn) ED25519_FN2(fn,ED25519_SUFFIX) +#else +#define ED25519_FN(fn) fn +#endif + #include "ed25519-donna.h" #include "ed25519.h" -#include "ed25519-hash-custom.h" -#include "curve25519-donna-scalarmult-base.h" +#include "ed25519-hash-custom.h" /* Generates a (extsk[0..31]) and aExt (extsk[32..63]) @@ -32,7 +41,7 @@ ed25519_hram(hash_512bits hram, const ed25519_signature RS, const ed25519_public } void -ed25519_publickey(const ed25519_secret_key sk, ed25519_public_key pk) { +ED25519_FN(ed25519_publickey) (const ed25519_secret_key sk, ed25519_public_key pk) { bignum256modm a; ge25519 ALIGN(16) A; hash_512bits extsk; @@ -44,53 +53,8 @@ ed25519_publickey(const ed25519_secret_key sk, ed25519_public_key pk) { ge25519_pack(pk, &A); } -int -ed25519_cosi_combine_publickeys(ed25519_public_key res, CONST ed25519_public_key *pks, size_t n) { - size_t i = 0; - ge25519 P; - ge25519_pniels sump; - ge25519_p1p1 sump1; - - if (n == 1) { - memcpy(res, pks, sizeof(ed25519_public_key)); - return 0; - } - if (!ge25519_unpack_negative_vartime(&P, pks[i++])) { - return -1; - } - ge25519_full_to_pniels(&sump, &P); - while (i < n - 1) { - if (!ge25519_unpack_negative_vartime(&P, pks[i++])) { - return -1; - } - ge25519_pnielsadd(&sump, &P, &sump); - } - if (!ge25519_unpack_negative_vartime(&P, pks[i++])) { - return -1; - } - ge25519_pnielsadd_p1p1(&sump1, &P, &sump, 0); - ge25519_p1p1_to_partial(&P, &sump1); - curve25519_neg(P.x, P.x); - ge25519_pack(res, &P); - return 0; -} - -void -ed25519_cosi_combine_signatures(ed25519_signature res, const ed25519_public_key R, CONST ed25519_cosi_signature *sigs, size_t n) { - bignum256modm s, t; - size_t i = 0; - - expand256_modm(s, sigs[i++], 32); - while (i < n) { - expand256_modm(t, sigs[i++], 32); - add256_modm(s, s, t); - } - memcpy(res, R, 32); - contract256_modm(res + 32, s); -} - void -ed25519_cosi_sign(const unsigned char *m, size_t mlen, const ed25519_secret_key sk, const ed25519_secret_key nonce, const ed25519_public_key R, const ed25519_public_key pk, ed25519_cosi_signature sig) { +ED25519_FN(ed25519_cosi_sign) (const unsigned char *m, size_t mlen, const ed25519_secret_key sk, const ed25519_secret_key nonce, const ed25519_public_key R, const ed25519_public_key pk, ed25519_cosi_signature sig) { bignum256modm r, S, a; hash_512bits extsk, extnonce, hram; @@ -116,7 +80,7 @@ ed25519_cosi_sign(const unsigned char *m, size_t mlen, const ed25519_secret_key } void -ed25519_sign(const unsigned char *m, size_t mlen, const ed25519_secret_key sk, const ed25519_public_key pk, ed25519_signature RS) { +ED25519_FN(ed25519_sign) (const unsigned char *m, size_t mlen, const ed25519_secret_key sk, const ed25519_public_key pk, ed25519_signature RS) { ed25519_hash_context ctx; bignum256modm r, S, a; ge25519 ALIGN(16) R; @@ -151,7 +115,7 @@ ed25519_sign(const unsigned char *m, size_t mlen, const ed25519_secret_key sk, c } int -ed25519_sign_open(const unsigned char *m, size_t mlen, const ed25519_public_key pk, const ed25519_signature RS) { +ED25519_FN(ed25519_sign_open) (const unsigned char *m, size_t mlen, const ed25519_public_key pk, const ed25519_signature RS) { ge25519 ALIGN(16) R, A; hash_512bits hash; bignum256modm hram, S; @@ -175,6 +139,55 @@ ed25519_sign_open(const unsigned char *m, size_t mlen, const ed25519_public_key return ed25519_verify(RS, checkR, 32) ? 0 : -1; } +#ifndef ED25519_SUFFIX + +#include "curve25519-donna-scalarmult-base.h" + +int +ed25519_cosi_combine_publickeys(ed25519_public_key res, CONST ed25519_public_key *pks, size_t n) { + size_t i = 0; + ge25519 P; + ge25519_pniels sump; + ge25519_p1p1 sump1; + + if (n == 1) { + memcpy(res, pks, sizeof(ed25519_public_key)); + return 0; + } + if (!ge25519_unpack_negative_vartime(&P, pks[i++])) { + return -1; + } + ge25519_full_to_pniels(&sump, &P); + while (i < n - 1) { + if (!ge25519_unpack_negative_vartime(&P, pks[i++])) { + return -1; + } + ge25519_pnielsadd(&sump, &P, &sump); + } + if (!ge25519_unpack_negative_vartime(&P, pks[i++])) { + return -1; + } + ge25519_pnielsadd_p1p1(&sump1, &P, &sump, 0); + ge25519_p1p1_to_partial(&P, &sump1); + curve25519_neg(P.x, P.x); + ge25519_pack(res, &P); + return 0; +} + +void +ed25519_cosi_combine_signatures(ed25519_signature res, const ed25519_public_key R, CONST ed25519_cosi_signature *sigs, size_t n) { + bignum256modm s, t; + size_t i = 0; + + expand256_modm(s, sigs[i++], 32); + while (i < n) { + expand256_modm(t, sigs[i++], 32); + add256_modm(s, s, t); + } + memcpy(res, R, 32); + contract256_modm(res + 32, s); +} + /* Fast Curve25519 basepoint scalar multiplication */ @@ -216,3 +229,5 @@ curve25519_scalarmult(curve25519_key mypublic, const curve25519_key secret, cons e[31] |= 0x40; curve25519_scalarmult_donna(mypublic, e, basepoint); } + +#endif // ED25519_SUFFIX diff --git a/ed25519-donna/modm-donna-32bit.h b/ed25519-donna/modm-donna-32bit.h index ca691dec2..74501f7f3 100644 --- a/ed25519-donna/modm-donna-32bit.h +++ b/ed25519-donna/modm-donna-32bit.h @@ -254,7 +254,10 @@ static void expand256_modm(bignum256modm out, const unsigned char *in, size_t le barrett_reduce256_modm(out, q1, out); } -static void expand_raw256_modm(bignum256modm out, const unsigned char in[32]) { +DONNA_UNUSED static void +expand_raw256_modm(bignum256modm out, const unsigned char in[32]); + +void expand_raw256_modm(bignum256modm out, const unsigned char in[32]) { bignum256modm_element_t x[8]; x[0] = U8TO32_LE(in + 0); From e808d405a1f5b308dd3abd306e9ee34f6a82693e Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Tue, 16 May 2017 19:22:24 +0100 Subject: [PATCH 436/627] ed25519-donna: Add ed25519-sha3 --- CMakeLists.txt | 2 +- Makefile | 2 +- ed25519-donna/ed25519-hash-custom-sha3.h | 23 +++++++++++++++++++++++ ed25519-donna/ed25519-hash-custom.h | 5 +++++ ed25519-donna/ed25519-sha3.c | 8 ++++++++ ed25519-donna/ed25519-sha3.h | 19 +++++++++++++++++++ 6 files changed, 57 insertions(+), 2 deletions(-) create mode 100644 ed25519-donna/ed25519-hash-custom-sha3.h create mode 100644 ed25519-donna/ed25519-sha3.c create mode 100644 ed25519-donna/ed25519-sha3.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 1d2d3830c..fd5978767 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 2.8) -set(SOURCES address.c aes/aescrypt.c aes/aeskey.c aes/aes_modes.c aes/aestab.c base32.c base58.c bignum.c bip32.c bip39.c ecdsa.c hmac.c nist256p1.c pbkdf2.c rand.c ripemd160.c secp256k1.c sha2.c ed25519-donna/ed25519.c sha3.c) +set(SOURCES address.c aes/aescrypt.c aes/aeskey.c aes/aes_modes.c aes/aestab.c base32.c base58.c bignum.c bip32.c bip39.c ecdsa.c hmac.c nist256p1.c pbkdf2.c rand.c ripemd160.c secp256k1.c sha2.c ed25519-donna/ed25519.c sha3.c ed25519-donna/ed25519-sha3.c) add_library(TrezorCrypto STATIC ${SOURCES}) diff --git a/Makefile b/Makefile index 9cbf9f93a..2afcee75d 100644 --- a/Makefile +++ b/Makefile @@ -44,7 +44,7 @@ SRCS += ripemd160.c SRCS += sha2.c SRCS += sha3.c SRCS += aes/aescrypt.c aes/aeskey.c aes/aestab.c aes/aes_modes.c -SRCS += ed25519-donna/ed25519.c +SRCS += ed25519-donna/ed25519.c ed25519-donna/ed25519-sha3.c SRCS += blake2b.c blake2s.c SRCS += chacha20poly1305/chacha20poly1305.c chacha20poly1305/chacha_merged.c chacha20poly1305/poly1305-donna.c chacha20poly1305/rfc7539.c diff --git a/ed25519-donna/ed25519-hash-custom-sha3.h b/ed25519-donna/ed25519-hash-custom-sha3.h new file mode 100644 index 000000000..6d0bd8f23 --- /dev/null +++ b/ed25519-donna/ed25519-hash-custom-sha3.h @@ -0,0 +1,23 @@ +/* + a custom hash must have a 512bit digest and implement: + + struct ed25519_hash_context; + + void ed25519_hash_init(ed25519_hash_context *ctx); + void ed25519_hash_update(ed25519_hash_context *ctx, const uint8_t *in, size_t inlen); + void ed25519_hash_final(ed25519_hash_context *ctx, uint8_t *hash); + void ed25519_hash(uint8_t *hash, const uint8_t *in, size_t inlen); +*/ + +#ifndef ED25519_HASH_CUSTOM +#define ED25519_HASH_CUSTOM + +#include "sha3.h" + +#define ed25519_hash_context SHA3_CTX +#define ed25519_hash_init(ctx) sha3_512_Init(ctx) +#define ed25519_hash_update(ctx, in, inlen) sha3_Update((ctx), (in), (inlen)) +#define ed25519_hash_final(ctx, hash) sha3_Final((ctx), (hash)) +#define ed25519_hash(hash, in, inlen) sha3_512((in), (inlen), (hash)) + +#endif // ED25519_HASH_CUSTOM diff --git a/ed25519-donna/ed25519-hash-custom.h b/ed25519-donna/ed25519-hash-custom.h index 67e00e295..5d8236ee0 100644 --- a/ed25519-donna/ed25519-hash-custom.h +++ b/ed25519-donna/ed25519-hash-custom.h @@ -9,6 +9,9 @@ void ed25519_hash(uint8_t *hash, const uint8_t *in, size_t inlen); */ +#ifndef ED25519_HASH_CUSTOM +#define ED25519_HASH_CUSTOM + #include "sha2.h" #define ed25519_hash_context SHA512_CTX @@ -16,3 +19,5 @@ #define ed25519_hash_update(ctx, in, inlen) sha512_Update((ctx), (in), (inlen)) #define ed25519_hash_final(ctx, hash) sha512_Final((ctx), (hash)) #define ed25519_hash(hash, in, inlen) sha512_Raw((in), (inlen), (hash)) + +#endif // ED25519_HASH_CUSTOM diff --git a/ed25519-donna/ed25519-sha3.c b/ed25519-donna/ed25519-sha3.c new file mode 100644 index 000000000..6a7687d0d --- /dev/null +++ b/ed25519-donna/ed25519-sha3.c @@ -0,0 +1,8 @@ +#include + +#include "ed25519-sha3.h" +#include "ed25519-hash-custom-sha3.h" + +#define ED25519_SUFFIX _sha3 + +#include "ed25519.c" diff --git a/ed25519-donna/ed25519-sha3.h b/ed25519-donna/ed25519-sha3.h new file mode 100644 index 000000000..0779c5559 --- /dev/null +++ b/ed25519-donna/ed25519-sha3.h @@ -0,0 +1,19 @@ +#ifndef ED25519_SHA3_H +#define ED25519_SHA3_H + +#include "ed25519.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +void ed25519_publickey_sha3(const ed25519_secret_key sk, ed25519_public_key pk); + +int ed25519_sign_open_sha3(const unsigned char *m, size_t mlen, const ed25519_public_key pk, const ed25519_signature RS); +void ed25519_sign_sha3(const unsigned char *m, size_t mlen, const ed25519_secret_key sk, const ed25519_public_key pk, ed25519_signature RS); + +#if defined(__cplusplus) +} +#endif + +#endif // ED25519_SHA3_H From a7947fec9ba72d19703f9ae5e6e26513797ff36c Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Tue, 16 May 2017 19:26:35 +0100 Subject: [PATCH 437/627] ed25519-donna: Add ed25519-keccak --- CMakeLists.txt | 2 +- Makefile | 2 +- ed25519-donna/ed25519-hash-custom-keccak.h | 23 ++++++++++++++++++++++ ed25519-donna/ed25519-keccak.c | 8 ++++++++ ed25519-donna/ed25519-keccak.h | 19 ++++++++++++++++++ options.h | 2 +- sha3.c | 8 ++++++++ sha3.h | 1 + 8 files changed, 62 insertions(+), 3 deletions(-) create mode 100644 ed25519-donna/ed25519-hash-custom-keccak.h create mode 100644 ed25519-donna/ed25519-keccak.c create mode 100644 ed25519-donna/ed25519-keccak.h diff --git a/CMakeLists.txt b/CMakeLists.txt index fd5978767..816e0255e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 2.8) -set(SOURCES address.c aes/aescrypt.c aes/aeskey.c aes/aes_modes.c aes/aestab.c base32.c base58.c bignum.c bip32.c bip39.c ecdsa.c hmac.c nist256p1.c pbkdf2.c rand.c ripemd160.c secp256k1.c sha2.c ed25519-donna/ed25519.c sha3.c ed25519-donna/ed25519-sha3.c) +set(SOURCES address.c aes/aescrypt.c aes/aeskey.c aes/aes_modes.c aes/aestab.c base32.c base58.c bignum.c bip32.c bip39.c ecdsa.c hmac.c nist256p1.c pbkdf2.c rand.c ripemd160.c secp256k1.c sha2.c sha3.c ed25519-donna/ed25519.c ed25519-donna/ed25519-sha3.c ed25519-donna/ed25519-keccak.c) add_library(TrezorCrypto STATIC ${SOURCES}) diff --git a/Makefile b/Makefile index 2afcee75d..a69a2904b 100644 --- a/Makefile +++ b/Makefile @@ -44,7 +44,7 @@ SRCS += ripemd160.c SRCS += sha2.c SRCS += sha3.c SRCS += aes/aescrypt.c aes/aeskey.c aes/aestab.c aes/aes_modes.c -SRCS += ed25519-donna/ed25519.c ed25519-donna/ed25519-sha3.c +SRCS += ed25519-donna/ed25519.c ed25519-donna/ed25519-sha3.c ed25519-donna/ed25519-keccak.c SRCS += blake2b.c blake2s.c SRCS += chacha20poly1305/chacha20poly1305.c chacha20poly1305/chacha_merged.c chacha20poly1305/poly1305-donna.c chacha20poly1305/rfc7539.c diff --git a/ed25519-donna/ed25519-hash-custom-keccak.h b/ed25519-donna/ed25519-hash-custom-keccak.h new file mode 100644 index 000000000..4cfe148e5 --- /dev/null +++ b/ed25519-donna/ed25519-hash-custom-keccak.h @@ -0,0 +1,23 @@ +/* + a custom hash must have a 512bit digest and implement: + + struct ed25519_hash_context; + + void ed25519_hash_init(ed25519_hash_context *ctx); + void ed25519_hash_update(ed25519_hash_context *ctx, const uint8_t *in, size_t inlen); + void ed25519_hash_final(ed25519_hash_context *ctx, uint8_t *hash); + void ed25519_hash(uint8_t *hash, const uint8_t *in, size_t inlen); +*/ + +#ifndef ED25519_HASH_CUSTOM +#define ED25519_HASH_CUSTOM + +#include "sha3.h" + +#define ed25519_hash_context SHA3_CTX +#define ed25519_hash_init(ctx) keccak_512_Init(ctx) +#define ed25519_hash_update(ctx, in, inlen) keccak_Update((ctx), (in), (inlen)) +#define ed25519_hash_final(ctx, hash) keccak_Final((ctx), (hash)) +#define ed25519_hash(hash, in, inlen) keccak_512((in), (inlen), (hash)) + +#endif // ED25519_HASH_CUSTOM diff --git a/ed25519-donna/ed25519-keccak.c b/ed25519-donna/ed25519-keccak.c new file mode 100644 index 000000000..b109360a7 --- /dev/null +++ b/ed25519-donna/ed25519-keccak.c @@ -0,0 +1,8 @@ +#include + +#include "ed25519-keccak.h" +#include "ed25519-hash-custom-keccak.h" + +#define ED25519_SUFFIX _keccak + +#include "ed25519.c" diff --git a/ed25519-donna/ed25519-keccak.h b/ed25519-donna/ed25519-keccak.h new file mode 100644 index 000000000..e122a9fda --- /dev/null +++ b/ed25519-donna/ed25519-keccak.h @@ -0,0 +1,19 @@ +#ifndef ED25519_KECCAK_H +#define ED25519_KECCAK_H + +#include "ed25519.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +void ed25519_publickey_keccak(const ed25519_secret_key sk, ed25519_public_key pk); + +int ed25519_sign_open_keccak(const unsigned char *m, size_t mlen, const ed25519_public_key pk, const ed25519_signature RS); +void ed25519_sign_keccak(const unsigned char *m, size_t mlen, const ed25519_secret_key sk, const ed25519_public_key pk, ed25519_signature RS); + +#if defined(__cplusplus) +} +#endif + +#endif // ED25519_KECCAK_H diff --git a/options.h b/options.h index 6b7de989b..a8a1f499d 100644 --- a/options.h +++ b/options.h @@ -68,7 +68,7 @@ // support Keccak hashing #ifndef USE_KECCAK -#define USE_KECCAK USE_ETHEREUM +#define USE_KECCAK 1 #endif #endif diff --git a/sha3.c b/sha3.c index 43fbc4509..8e1a7f4a1 100644 --- a/sha3.c +++ b/sha3.c @@ -358,6 +358,14 @@ void keccak_Final(SHA3_CTX *ctx, unsigned char* result) assert(block_size > digest_length); if (result) me64_to_le_str(result, ctx->hash, digest_length); } + +void keccak_512(const unsigned char* data, size_t len, unsigned char* digest) +{ + SHA3_CTX ctx; + keccak_512_Init(&ctx); + keccak_Update(&ctx, data, len); + keccak_Final(&ctx, digest); +} #endif /* USE_KECCAK */ void sha3_256(const unsigned char* data, size_t len, unsigned char* digest) diff --git a/sha3.h b/sha3.h index 9d0d19b77..24547a210 100644 --- a/sha3.h +++ b/sha3.h @@ -75,6 +75,7 @@ void sha3_Final(SHA3_CTX *ctx, unsigned char* result); #define keccak_512_Init sha3_512_Init #define keccak_Update sha3_Update void keccak_Final(SHA3_CTX *ctx, unsigned char* result); +void keccak_512(const unsigned char* data, size_t len, unsigned char* digest); #endif void sha3_256(const unsigned char* data, size_t len, unsigned char* digest); From 4cb090169c31c21df63aad960993f224645203cc Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Fri, 19 May 2017 18:20:55 +0100 Subject: [PATCH 438/627] curves: Add ed25519-sha3 & ed25519-keccak --- bip32.c | 22 ++++++++++++++++++++++ curves.c | 6 ++++++ curves.h | 6 ++++++ 3 files changed, 34 insertions(+) diff --git a/bip32.c b/bip32.c index 7810f4c43..8076d2c0b 100644 --- a/bip32.c +++ b/bip32.c @@ -48,6 +48,20 @@ const curve_info ed25519_info = { 0 }; +const curve_info ed25519_sha3_info = { + /* bip32_name */ + "ed25519-sha3 seed", + 0 +}; + +#if USE_KECCAK +const curve_info ed25519_keccak_info = { + /* bip32_name */ + "ed25519-keccak seed", + 0 +}; +#endif + const curve_info curve25519_info = { /* bip32_name */ "curve25519 seed", @@ -548,6 +562,14 @@ const curve_info *get_curve_by_name(const char *curve_name) { if (strcmp(curve_name, ED25519_NAME) == 0) { return &ed25519_info; } + if (strcmp(curve_name, ED25519_SHA3_NAME) == 0) { + return &ed25519_sha3_info; + } +#if USE_KECCAK + if (strcmp(curve_name, ED25519_KECCAK_NAME) == 0) { + return &ed25519_keccak_info; + } +#endif if (strcmp(curve_name, CURVE25519_NAME) == 0) { return &curve25519_info; } diff --git a/curves.c b/curves.c index e2fa10239..42863cdb0 100644 --- a/curves.c +++ b/curves.c @@ -20,7 +20,13 @@ * OTHER DEALINGS IN THE SOFTWARE. */ +#include "curves.h" + const char SECP256K1_NAME[] = "secp256k1"; const char NIST256P1_NAME[] = "nist256p1"; const char ED25519_NAME[] = "ed25519"; +const char ED25519_SHA3_NAME[] = "ed25519-sha3"; +#if USE_KECCAK +const char ED25519_KECCAK_NAME[] = "ed25519-keccak"; +#endif const char CURVE25519_NAME[] = "curve25519"; diff --git a/curves.h b/curves.h index dc99bc66f..cd95e0848 100644 --- a/curves.h +++ b/curves.h @@ -23,9 +23,15 @@ #ifndef __CURVES_H__ #define __CURVES_H__ +#include "options.h" + extern const char SECP256K1_NAME[]; extern const char NIST256P1_NAME[]; extern const char ED25519_NAME[]; +extern const char ED25519_SHA3_NAME[]; +#if USE_KECCAK +extern const char ED25519_KECCAK_NAME[]; +#endif extern const char CURVE25519_NAME[]; #endif From accae3e7d159b8318f6d81d52668356e9578d437 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Fri, 19 May 2017 18:33:21 +0100 Subject: [PATCH 439/627] bip32: Add ed25519-sha3 & ed25519-keccak --- bip32.c | 69 +++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 42 insertions(+), 27 deletions(-) diff --git a/bip32.c b/bip32.c index 8076d2c0b..49bc25db9 100644 --- a/bip32.c +++ b/bip32.c @@ -31,6 +31,7 @@ #include "ecdsa.h" #include "bip32.h" #include "sha2.h" +#include "sha3.h" #include "ripemd160.h" #include "base58.h" #include "macros.h" @@ -38,8 +39,9 @@ #include "secp256k1.h" #include "nist256p1.h" #include "ed25519.h" -#if USE_ETHEREUM -#include "sha3.h" +#include "ed25519-sha3.h" +#if USE_KECCAK +#include "ed25519-keccak.h" #endif const curve_info ed25519_info = { @@ -406,14 +408,21 @@ void hdnode_fill_public_key(HDNode *node) { if (node->public_key[0] != 0) return; - if (node->curve == &ed25519_info) { - node->public_key[0] = 1; - ed25519_publickey(node->private_key, node->public_key + 1); - } else if (node->curve == &curve25519_info) { - node->public_key[0] = 1; - curve25519_scalarmult_basepoint(node->public_key + 1, node->private_key); - } else { + if (node->curve->params) { ecdsa_get_public_key33(node->curve->params, node->private_key, node->public_key); + } else { + node->public_key[0] = 1; + if (node->curve == &ed25519_info) { + ed25519_publickey(node->private_key, node->public_key + 1); + } else if (node->curve == &ed25519_sha3_info) { + ed25519_publickey_sha3(node->private_key, node->public_key + 1); +#if USE_KECCAK + } else if (node->curve == &ed25519_keccak_info) { + ed25519_publickey_keccak(node->private_key, node->public_key + 1); +#endif + } else if (node->curve == &curve25519_info) { + curve25519_scalarmult_basepoint(node->public_key + 1, node->private_key); + } } } @@ -442,36 +451,45 @@ int hdnode_get_ethereum_pubkeyhash(const HDNode *node, uint8_t *pubkeyhash) // msg_len is the message length int hdnode_sign(HDNode *node, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64])) { - if (node->curve == &ed25519_info) { - hdnode_fill_public_key(node); - ed25519_sign(msg, msg_len, node->private_key, node->public_key + 1, sig); - return 0; + if (node->curve->params) { + return ecdsa_sign(node->curve->params, node->private_key, msg, msg_len, sig, pby, is_canonical); } else if (node->curve == &curve25519_info) { return 1; // signatures are not supported } else { - return ecdsa_sign(node->curve->params, node->private_key, msg, msg_len, sig, pby, is_canonical); + hdnode_fill_public_key(node); + if (node->curve == &ed25519_info) { + ed25519_sign(msg, msg_len, node->private_key, node->public_key + 1, sig); + } else if (node->curve == &ed25519_sha3_info) { + ed25519_sign_sha3(msg, msg_len, node->private_key, node->public_key + 1, sig); +#if USE_KECCAK + } else if (node->curve == &ed25519_keccak_info) { + ed25519_sign_keccak(msg, msg_len, node->private_key, node->public_key + 1, sig); +#endif + } + return 0; } } int hdnode_sign_digest(HDNode *node, const uint8_t *digest, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64])) { - if (node->curve == &ed25519_info) { - hdnode_fill_public_key(node); - ed25519_sign(digest, 32, node->private_key, node->public_key + 1, sig); - return 0; + if (node->curve->params) { + return ecdsa_sign_digest(node->curve->params, node->private_key, digest, sig, pby, is_canonical); } else if (node->curve == &curve25519_info) { return 1; // signatures are not supported } else { - return ecdsa_sign_digest(node->curve->params, node->private_key, digest, sig, pby, is_canonical); + return hdnode_sign(node, digest, 32, sig, pby, is_canonical); } } int hdnode_get_shared_key(const HDNode *node, const uint8_t *peer_public_key, uint8_t *session_key, int *result_size) { // Use elliptic curve Diffie-Helman to compute shared session key - if (node->curve == &ed25519_info) { - *result_size = 0; - return 1; // ECDH is not supported + if (node->curve->params) { + if (ecdh_multiply(node->curve->params, node->private_key, peer_public_key, session_key) != 0) { + return 1; + } + *result_size = 65; + return 0; } else if (node->curve == &curve25519_info) { session_key[0] = 0x04; if (peer_public_key[0] != 0x40) { @@ -481,11 +499,8 @@ int hdnode_get_shared_key(const HDNode *node, const uint8_t *peer_public_key, ui *result_size = 33; return 0; } else { - if (ecdh_multiply(node->curve->params, node->private_key, peer_public_key, session_key) != 0) { - return 1; - } - *result_size = 65; - return 0; + *result_size = 0; + return 1; // ECDH is not supported } } From 7fb886440e7b2765f3ad5d2a8bb42ad2a923cef9 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sun, 21 May 2017 20:52:05 +0100 Subject: [PATCH 440/627] nem_test_vectors: Initial commit --- tools/nem_test_vectors.erb | 18 ++++++ tools/nem_test_vectors.rb | 120 +++++++++++++++++++++++++++++++++++++ 2 files changed, 138 insertions(+) create mode 100644 tools/nem_test_vectors.erb create mode 100755 tools/nem_test_vectors.rb diff --git a/tools/nem_test_vectors.erb b/tools/nem_test_vectors.erb new file mode 100644 index 000000000..0e7ed946e --- /dev/null +++ b/tools/nem_test_vectors.erb @@ -0,0 +1,18 @@ +// test vectors from <%= source_url %> +START_TEST(<%= test_name %>) +{ + static const struct { +<% fields.each do |(name, type)| -%> + <%= if type.nil? then 'const char *' else "#{type} " end %><%= name %>; +<% end -%> + } tests[] = { +<% data.each do |values| -%> + { <% values.each do |value| %><%= value %>, <% end %>}, +<% end -%> + }; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + // TODO: Implement test + } +} +END_TEST diff --git a/tools/nem_test_vectors.rb b/tools/nem_test_vectors.rb new file mode 100755 index 000000000..46586f84e --- /dev/null +++ b/tools/nem_test_vectors.rb @@ -0,0 +1,120 @@ +#!/usr/bin/env ruby +require 'highline' +require 'open-uri' + +TEMPLATE_NAME = (Pathname.new(__FILE__).sub_ext '.erb').to_s.freeze + +@terminal = HighLine.new($stdin, $stderr) + +def github_files + require 'octokit' + + @github_files ||= Octokit.contents('NemProject/nem-test-vectors') + .select do |file| + file.name.end_with? '.dat' + end +end + +def choose_data_file + @terminal.choose do |menu| + github_files.each do |file| + menu.choice(file.name) { file.download_url } + end + + menu.prompt = 'Which file? ' + + menu.index = :none + menu.select_by = :name + end +end + +def load_header(line) + line = line.dup + abort 'Header is not a comment' unless line.slice!(0) == '#' + + line.split(':').each(&:strip!) +end + +def parse_field_answer(answer) + if answer.empty? + nil + elsif /^(?:(?\w+) )?(?\w+)$/ =~ answer + [identifier, type] + else + raise NotValidQuestionError + end +end + +def ask_fields(header) + header.map do |name| + @terminal.ask "Field for `#{name}'? " do |question| + question.answer_type = lambda(&method(:parse_field_answer)) + end + end +end + +def load_data_line(line) + abort 'Line does not begin with colon' unless line.slice!(0) == ':' + + values = line.split(':').each(&:strip!) + values.pop if values.last.empty? + + values +end + +def load_data(file, count) + file.each_line.lazy.reject { |line| line.start_with? '#' } + .take(count) + .map(&method(:load_data_line)) + .to_a +end + +def remove_skipped_fields(fields, data) + data.each do |values| + abort 'Line does not match header' unless values.size == fields.size + + values.reject!.each_with_index { |_, index| fields[index].nil? } + end + + fields.compact! +end + +def format_data_fields(fields, data) + data.each do |values| + fields.each_with_index do |(_, type), index| + values[index] = values[index].dump if type.nil? + end + end +end + +def template(source_url, fields, data) + test_name = @terminal.ask('Name for test? ') do |question| + question.validate = /./ + end + + erb = ERB.new(File.read(TEMPLATE_NAME), nil, '-') + erb.filename = TEMPLATE_NAME + + erb.result(binding) +end + +download_url = choose_data_file + +source_code = open download_url do |file| + line = file.readline + + header = load_header(line) + @terminal.say line + + count = @terminal.ask('How many vectors to import? ', Integer) + + fields = ask_fields(header) + data = load_data(file, count) + + remove_skipped_fields(fields, data) + format_data_fields(fields, data) + + template(download_url, fields, data) +end + +puts source_code From dc397ff0ed4014baecef85b40d82828e117819ca Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Mon, 22 May 2017 18:31:53 +0100 Subject: [PATCH 441/627] tests: Import NEM test vectors for keccak_256 --- sha3.c | 8 ++++++++ sha3.h | 1 + test_check.c | 42 +++++++++++++++++++++++++++++++++++++++++- 3 files changed, 50 insertions(+), 1 deletion(-) diff --git a/sha3.c b/sha3.c index 8e1a7f4a1..a3496e20f 100644 --- a/sha3.c +++ b/sha3.c @@ -359,6 +359,14 @@ void keccak_Final(SHA3_CTX *ctx, unsigned char* result) if (result) me64_to_le_str(result, ctx->hash, digest_length); } +void keccak_256(const unsigned char* data, size_t len, unsigned char* digest) +{ + SHA3_CTX ctx; + keccak_256_Init(&ctx); + keccak_Update(&ctx, data, len); + keccak_Final(&ctx, digest); +} + void keccak_512(const unsigned char* data, size_t len, unsigned char* digest) { SHA3_CTX ctx; diff --git a/sha3.h b/sha3.h index 24547a210..367369d4d 100644 --- a/sha3.h +++ b/sha3.h @@ -75,6 +75,7 @@ void sha3_Final(SHA3_CTX *ctx, unsigned char* result); #define keccak_512_Init sha3_512_Init #define keccak_Update sha3_Update void keccak_Final(SHA3_CTX *ctx, unsigned char* result); +void keccak_256(const unsigned char* data, size_t len, unsigned char* digest); void keccak_512(const unsigned char* data, size_t len, unsigned char* digest); #endif diff --git a/test_check.c b/test_check.c index 78b97cd81..23a812a3f 100644 --- a/test_check.c +++ b/test_check.c @@ -65,7 +65,7 @@ /* Call before secret data is freed or to mark non-secret data (public keys or signatures) */ #define UNMARK_SECRET_DATA(addr, len) VALGRIND_MAKE_MEM_DEFINED (addr, len) -#define FROMHEX_MAXLEN 256 +#define FROMHEX_MAXLEN 512 #define VERSION_PUBLIC 0x0488b21e #define VERSION_PRIVATE 0x0488ade4 @@ -1971,6 +1971,45 @@ START_TEST(test_sha3_512) } END_TEST +// test vectors from https://raw.githubusercontent.com/NemProject/nem-test-vectors/master/0.test-sha3-256.dat +START_TEST(test_keccak_256) +{ + static const struct { + const char *hash; + size_t length; + const char *data; + } tests[] = { + { "4e9e79ab7434f6c7401fb3305d55052ee829b9e46d5d05d43b59fefb32e9a619", 293, "a6151d4904e18ec288243028ceda30556e6c42096af7150d6a7232ca5dba52bd2192e23daa5fa2bea3d4bd95efa2389cd193fcd3376e70a5c097b32c1c62c80af9d710211545f7cdddf63747420281d64529477c61e721273cfd78f8890abb4070e97baa52ac8ff61c26d195fc54c077def7a3f6f79b36e046c1a83ce9674ba1983ec2fb58947de616dd797d6499b0385d5e8a213db9ad5078a8e0c940ff0cb6bf92357ea5609f778c3d1fb1e7e36c35db873361e2be5c125ea7148eff4a035b0cce880a41190b2e22924ad9d1b82433d9c023924f2311315f07b88bfd42850047bf3be785c4ce11c09d7e02065d30f6324365f93c5e7e423a07d754eb314b5fe9db4614275be4be26af017abdc9c338d01368226fe9af1fb1f815e7317bdbb30a0f36dc69", }, + { "c1268babc42d00c3463dc388222100f7e525a74a64665c39f112f788ddb5da42", 376, "9db801077952c2324e0044a4994edfb09b3edfcf669bfdd029f4bf42d5b0eab3056b0bf82708ca7bfadba43c9de806b10a19d0f00c2351ef1086b6b108f306e035c6b61b2e70fd7087ba848601c8a3f626a66666423717ef305a1068bfa3a1f7ffc1e5a78cb6182ffc8a577ca2a821630bf900d0fbba848bdf94b77c5946771b6c3f8c02269bc772ca56098f724536d96be68c284ee1d81697989d40029b8ea63ac1fd85f8b3cae8b194f6834ff65a5858f9498ddbb467995eb2d49cdfc6c05d92038c6e9aaeee85f8222b3784165f12a2c3df4c7a142e26dddfd831d07e22dfecc0eded48a69c8a9e1b97f1a4e0efcd4edd310de0edf82af38a6e4d5ab2a19da586e61210d4f75e7a07e2201f9c8154ca52a414a70d2eb2ac1c5b9a2900b4d871f62fa56f70d03b3dd3704bd644808c45a13231918ea884645b8ec054e8bab2935a66811fe590ddc119ae901dfeb54fc2a87c1e0a236778baab2fa8843709c6676d3c1888ba19d75ec52d73a7d035c143179b93823726b7", }, + { "e83b50e8c83cb676a7dd64c055f53e5110d5a4c62245ceb8f683fd87b2b3ec77", 166, "c070a957550b7b34113ee6543a1918d96d241f27123425db7f7b9004e047ffbe05612e7fa8c54b23c83ea427e625e97b7a28b09a70bf6d91e478eeed01d7907931c29ea86e70f2cdcfb243ccf7f24a1619abf4b5b9e6f75cbf63fc02baf4a820a9790a6b053e50fd94e0ed57037cfc2bab4d95472b97d3c25f434f1cc0b1ede5ba7f15907a42a223933e5e2dfcb518c3531975268c326d60fa911fbb7997eee3ba87656c4fe7", }, + { "8ebd2c9d4ff00e285a9b6b140bfc3cef672016f0098100e1f6f250220af7ce1a", 224, "b502fbdce4045e49e147eff5463d4b3f37f43461518868368e2c78008c84c2db79d12b58107034f67e7d0abfee67add0342dd23dce623f26b9156def87b1d7ac15a6e07301f832610fe869ada13a2b0e3d60aa6bb81bc04487e2e800f5106b0402ee0331df745e021b5ea5e32faf1c7fc1322041d221a54191c0af19948b5f34411937182e30d5cd39b5a6c959d77d92d21bb1de51f1b3411cb6eec00600429916227fb62d2c88e69576f4ac8e5efcde8efa512cc80ce7fb0dfaa6c74d26e898cefe9d4f7dce232a69f2a6a9477aa08366efcdfca117c89cb79eba15a23755e0", }, + { "db3961fdddd0c314289efed5d57363459a6700a7bd015e7a03d3e1d03f046401", 262, "22e203a98ba2c43d8bc3658f0a48a35766df356d6a5e98b0c7222d16d85a00b317207d4aef3fc7cabb67b9d8f5838de0b733e1fd59c31f0667e53286972d7090421ad90d54db2ea40047d0d1700c86f53dbf48da532396307e68edad877dcae481848801b0a5db44dbdba6fc7c63b5cd15281d57ca9e6be96f530b209b59d6127ad2bd8750f3f80798f62521f0d5b42633c2f5a9aaefbed38779b7aded2338d66850b0bb0e33c48e040c99f2dcee7a7ebb3d7416e1c5bf038c19d09682dab67c96dbbfad472e45980aa27d1b301b15f7de4d4f549bad2501931c9d4f1a3b1692dcb4b1b834ddd4a636126702307ddaeec61841693b21887d56e76cc2069dafb557fd6682160f", }, + { "25dd3acacd6bf688c0eace8d33eb7cc550271969142deb769a05b4012f7bb722", 122, "99e7f6e0ed46ec866c43a1ab494998d47e9309a79fde2a629eb63bb2160a5ffd0f2206de9c32dd20e9b23e57ab7422cf82971cc2873ec0e173fe93281c7b33e1c76ac79223a6f435f230bdd30260c00d00986c72a399d3ba70f6e783d834bbf8a6127844def559b8b6db742b2cfd715f7ff29e7b42bf7d567beb", }, + { "00d747c9045c093484290afc161437f11c2ddf5f8a9fc2acae9c7ef5fcf511e5", 440, "50c392f97f8788377f0ab2e2aab196cb017ad157c6f9d022673d39072cc198b06622a5cbd269d1516089fa59e28c3373a92bd54b2ebf1a79811c7e40fdd7bce200e80983fda6e77fc44c44c1b5f87e01cef2f41e1141103f73364e9c2f25a4597e6517ef31b316300b770c69595e0fa6d011df1566a8676a88c7698562273bbfa217cc69d4b5c89a8907b902f7dc14481fefc7da4a810c15a60f5641aae854d2f8cc50cbc393015560f01c94e0d0c075dbcb150ad6eba29dc747919edcaf0231dba3eb3f2b1a87e136a1f0fd4b3d8ee61bad2729e9526a32884f7bcfa41e361add1b4c51dc81463528372b4ec321244de0c541ba00df22b8773cdf4cf898510c867829fa6b4ff11f9627338b9686d905cb7bcdf085080ab842146e0035c808be58cce97827d8926a98bd1ff7c529be3bc14f68c91b2ca4d2f6fc748f56bcf14853b7f8b9aa6d388f0fd82f53fdc4bacf9d9ba10a165f404cf427e199f51bf6773b7c82531e17933f6d8b8d9181e22f8921a2dbb20fc7c8023a87e716e245017c399d0942934f5e085219b3f8d26a196bf8b239438b8e561c28a61ff08872ecb052c5fcb19e2fdbc09565924a50ebee1461c4b414219d4257", }, + { "dadcde7c3603ef419d319ba3d50cf00ad57f3e81566fd11b9b6f461cbb9dcb0f", 338, "18e1df97abccc91e07dc7b7ffab5ee8919d5610721453176aa2089fb96d9a477e1476f507fa1129f04304e960e8017ff41246cacc0153055fc4b1dc6168a74067ebb077cb5aa80a9df6e8b5b821e906531159668c4c164b9e511d8724aedbe17c1f41da8809417d3c30b79ea5a2e3c961f6bac5436d9af6be24a36eebcb17863fed82c0eb8962339eb612d58659dddd2ea06a120b3a2d8a17050be2de367db25a5bef4290c209bdb4c16c4df5a1fe1ead635169a1c35f0a56bc07bcf6ef0e4c2d8573ed7a3b58030fa268c1a5974b097288f01f34d5a1087946410688016882c6c7621aad680d9a25c7a3e5dbcbb07ffdb7243b91031c08a121b40785e96b7ee46770c760f84aca8f36b7c7da64d25c8f73b4d88ff3acb7eeefc0b75144dffea66d2d1f6b42b905b61929ab3f38538393ba5ca9d3c62c61f46fa63789cac14e4e1d8722bf03cceef6e3de91f783b0072616c", }, + { "d184e84a2507fc0f187b640dd5b849a366c0383d9cbdbc6fa30904f054111255", 141, "13b8df9c1bcfddd0aa39b3055f52e2bc36562b6677535994b173f07041d141699db42589d6091ef0e71b645b41ab57577f58c98da966562d24823158f8e1d43b54edea4e61dd66fe8c59ad8405f5a0d9a3eb509a77ae3d8ae4adf926fd3d8d31c3dcccfc140814541010937024cc554e1daaee1b333a66316e7fbebb07ac8dfb134a918b9090b14168012c4824", }, + { "20c19635364a00b151d0168fe5ae03bac6dd7d06030475b40d2e8c577a192f53", 84, "e1e96da4b7d8dcc2b316006503a990ea26a5b200cb7a7edfc14f5ce827f06d8d232ec95b1acdc1422ffc16da11d258f0c7b378f026d64c74b2fb41df8bfd3cd30066caecdc6f76c8163de9309d9fd0cf33d54a29", }, + { "86cc2c428d469e43fb4ee8d38dffbf5128d20d1659dbc45edf4a855399ca730e", 319, "30391840ad14e66c53e1a5aaa03989ff059940b60c44c3b21295a93d023f2e6c7cdcf60208b7d87a7605fb5cee94630d94cad90bc6955328357fa37fea47c09f9cee759c31537187321c7d572e3554eeb90f441a9494575454dfbf8cfd86128da15de9418821ca158856eb84ff6a29a2c8380711e9e6d4955388374fcd3c1ca45b49e0679fc7157f96bc6e4f86ce20a89c12d4449b1ca7056e0b7296fc646f68f6ddbfa6a48e384d63ab68bc75fd69a2add59b8e41c4a0f753935df9a703d7df82a430798b0a67710a78061485a9d15de16f154582082459b4462485ce8a82d35ac6b9498ae40df3a23d5f00e0e86661cb02c52f677fd374c32969ec63028b5dd2c1d4bce67a6d9f79ba5e7eeb5a2763dc9fe2a05aa2ebaad36aaec2541e343a677fb4e6b6a180eff33c93744a4624f6a79f054c6c9e9c5b6928dbe7ba5fca", }, + { "e80eee72a76e6957f7cb7f68c41b92f0ad9aac6e58aa8fc272c1e7364af11c70", 108, "3c210ed15889ae938781d2cebd49d4a8007f163ffba1f7669bccdccf6ad5a1418299d5f4348f5cd03b0ba9e6999ab154e46836c3546feb395d17bcc60f23d7ba0e8efe6aa616c00b6bf552fe1cb5e28e3e7bc39dfc20c63ae3901035e91ddd110e43fe59ed744beeedb6bc1e", }, + { "f971bbae97dd8a034835269fb246867de358a889de6de13672e771d6fb4c89b7", 468, "64e9a3a99c021df8bea59368cfe1cd3b0a4aca33ffcd5cf6028d9307c0b904b8037d056a3c12803f196f74c4d360a3132452d365922b1157e5b0d76f91fb94bebfdcb4d50fa23ed5be3d3c5712219e8666debc8abcd5e6c69a542761a6cbbd1b3c0f0524875204b64d2788465f90cb19b6f6da9f8bec6d6e684196e713549ec83e47cbaeff77838ac4936b312562e2de17c970449d49d214ec2597c6d4f642e6c94a613a0c53285abccd7794a3d72241808594fb4e6e4d5d2c310ef1cdcbfd34805ca2408f554797a6cfd49d0f25ed8927f206acb127e6436e1234902489ec2e7f3058e26c0eba80341bc7ad0da8b8bd80bd1b43c9099269e3f8b68445c69b79d8cf5693d4a0d47a44f9e9114dbb33992d2ea9d3b5b86e4ea57a44a638848de4ac365bb6bb7855305ade62b07ebf0954d70b7c2fb5e6fcc154c7a36fb1756df5f20a84d35696627ebf22d44f40f805c0878ad110bc17dcd66821084ca87902e05bc0afa61161086956b85a6ea900d35c7784d4c361a43fe294e267d5762408be58962cdb4f45a9c0efd7d2335916df3acb98ccfbcf5ee39530540e5f3d3c5f3326a9a536d7bfa37aae2b143e2499b81bf0670e3a418c26c7dc82b293d9bd182dd6435670514237df88d8286e19ce93e0a0db2790", }, + { "b97fd51f4e4eaa40c7a2853010fc46be5be2f43b9520ea0c533b68f728c978a2", 214, "ced3a43193caceb269d2517f4ecb892bb7d57d7201869e28e669b0b17d1c44d286e02734e2210ea9009565832975cc6303b9b6008fe1165b99ae5f1b29962ef042ebad8b676d7433ed2fe0d0d6f4f32b2cb4c519da61552328c2caea799bb2fd907308173a1cd2b798fb0df7d2eaf2ff0be733af74f42889e211843fc80b09952ae7eb246725b91d31c1f7a5503fdf3bc9c269c76519cf2dc3225e862436b587bb74adbad88c773056cfea3bddb1f6533c01125eeae0986e5c817359912c9d0472bf8320b824ee097f82a8e05b9f53a5be7d153225de", }, + { "f0fecf766e4f7522568b3be71843cce3e5fcb10ea96b1a236c8c0a71c9ad55c9", 159, "8aca4de41275f5c4102f66266d70cff1a2d56f58df8d12061c64cb6cd8f616a5bf19c2bb3c91585c695326f561a2d0eb4eef2e202d82dcc9089e4bee82b62a199a11963cd08987d3abd5914def2cdd3c1e4748d46b654f338e3959121e869c18d5327e88090d0ba0ac6762a2b14514cc505af7499f1a22f421dbe978494f9ffe1e88f1c59228f21da5bc9fcc911d022300a443bca17258bdd6cfbbf52fde61", }, + { "5c4f16043c0084bf98499fc7dc4d674ce9c730b7135210acdbf5e41d3dcf317b", 87, "01bbc193d0ee2396a7d8267ad63f18149667b31d8f7f48c8bb0c634755febc9ef1a79e93c475f6cd137ee37d4dc243ea2fdcdc0d098844af2208337b7bbf6930e39e74e23952ac1a19b4d38b83810a10c3b069e4fafb06", }, + { "14b61fc981f7d9449b7b6a2d57eb48cc8f7896f4dced2005291b2a2f38cb4a63", 358, "cbc1709a531438d5ead32cea20a9e4ddc0101ec555ab42b2e378145013cc05a97b9e2c43c89bfa63ae5e9e9ce1fc022035c6b68f0a906ee1f53396d9dbe41cb2bc4bfeb144b005b0f40e0fec872d9c4aca9929ba3cbacd84c58ab43c26f10d345a24692bbd55a76506876768e8e32a461bf160cee953da88920d36ad4aff6eea7126aa6f44a7a6fce770ce43f0f90a20590bdaad3ffcda30ca8e3700f832c62caa5df030c16bcf74aff492466f781eb69863a80663535fc154abd7cfdd02eef1019221cf608b9780f807e507fbbf559b1dfe4e971b4d08fe45263a3c697ba90f9f71bec97e12438b4b12f6a84ab66872b888097089d76c9c2502d9ed2eece6bef8eee1d439782e218f5cc75d38f9886012cdcb4bbe6caf812e97c5a336bcceae38b1109e3243a291ce23d097aaee7d9a711de6886749a7a6d15d7e7cbc4a51b1b4da9fcf139e4a6fd7dc0bc017db624b17fc9b8f847592ed42467c25ad9fe96acbf20c0ffd18", }, + { "47ec7f3a362becbb110867995a0f066a66152603c4d433f11bf51870c67e2864", 354, "0636983353c9ea3f75256ed00b70e8b7cfc6f4e4c0ba3aa9a8da59b6e6ad9dfb5bc2c49f48cc0b4237f87dedf34b888e54ecebf1d435bcd4aab72eb4ce39e5262fb68c6f86423dac123bf59e903989eda7df4a982822d0831521403cedcfe9a5bbea648bb2e7ef8cd81442ea5abe468b3ee8b06376ef8099447255c2fdc1b73af37fe0e0b852ffbc9339868db756680db99e6e9837dbd28c39a69f229044ad7ec772524a6e01f679d25fdc2e736a2418e5dfd7c2ab1348d0f821b777c975244c6cfc2fca5c36ccae7cf1d07b190a9d17a088a1276bd096250b92f53b29b6ef88ef69d744b56fb2ec5078cc0b68a9106943ef242b466097b9e29df11eb5cb0c06c29d7917410ba1097215d6aa4dafd90adff0c3e7221b9e8832613bd9aca8bcc6b2aa7b43acedcbc11aee1b5ba56f77a210be7cf3485ee813e1126c3eeccd8419bbf22c412cad32cc0fc7a73aca4e379651caac3d13d6cf5ca05508fd2d96f3ad94e7", }, + { "73778e7f1943646a89d3c78909e0afbe584071ba5230546a39cd73e44e36d78a", 91, "6217504a26b3395855eab6ddeb79f2e3490d74b80eff343721150ee0c1c02b07186743589f93c22a03dc5ed29fb5bf592de0a089763e83e5b95f9dd524d66c8da3e04c1814e65e68b2810c1b517648aabc266ad62896c51864a7f4", }, + { "35ef6868e750cf0c1d5285992c231d93ec644670fb79cf85324067a9f77fde78", 185, "0118b7fb15f927a977e0b330b4fa351aeeec299d6ba090eb16e5114fc4a6749e5915434a123c112697390c96ea2c26dc613eb5c75f5ecfb6c419317426367e34da0ddc6d7b7612cefa70a22fea0025f5186593b22449dab71f90a49f7de7352e54e0c0bd8837e661ca2127c3313a7268cafdd5ccfbf3bdd7c974b0e7551a2d96766579ef8d2e1f376af74cd1ab62162fc2dc61a8b7ed4163c1caccf20ed73e284da2ed257ec974eee96b502acb2c60a04886465e44debb0317", }, + }; + + uint8_t hash[SHA3_256_DIGEST_LENGTH]; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + keccak_256(fromhex(tests[i].data), tests[i].length, hash); + ck_assert_mem_eq(hash, fromhex(tests[i].hash), SHA3_256_DIGEST_LENGTH); + } +} +END_TEST + // test vectors from https://raw.githubusercontent.com/BLAKE2/BLAKE2/master/testvectors/blake2b-kat.txt START_TEST(test_blake2b) { @@ -3143,6 +3182,7 @@ Suite *test_suite(void) tc = tcase_create("sha3"); tcase_add_test(tc, test_sha3_256); tcase_add_test(tc, test_sha3_512); + tcase_add_test(tc, test_keccak_256); suite_add_tcase(s, tc); tc = tcase_create("blake2"); From ce25dcc9fcb61771892e73e889c2956f40d4bb10 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Mon, 22 May 2017 18:48:05 +0100 Subject: [PATCH 442/627] tests: Import NEM test vectors for ed25519_keccak --- test_check.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/test_check.c b/test_check.c index 23a812a3f..80fb1ed35 100644 --- a/test_check.c +++ b/test_check.c @@ -52,6 +52,7 @@ #include "secp256k1.h" #include "nist256p1.h" #include "ed25519.h" +#include "ed25519-keccak.h" #include "script.h" #include "rfc6979.h" @@ -2787,6 +2788,58 @@ START_TEST(test_ed25519) { } END_TEST +// test vectors from https://raw.githubusercontent.com/NemProject/nem-test-vectors/master/2.test-sign.dat +START_TEST(test_ed25519_keccak) +{ + static const struct { + const char *private_key; + const char *public_key; + const char *signature; + size_t length; + const char *data; + } tests[] = { + { "abf4cf55a2b3f742d7543d9cc17f50447b969e6e06f5ea9195d428ab12b7318d", "8a558c728c21c126181e5e654b404a45b4f0137ce88177435a69978cc6bec1f4", "d9cec0cc0e3465fab229f8e1d6db68ab9cc99a18cb0435f70deb6100948576cd5c0aa1feb550bdd8693ef81eb10a556a622db1f9301986827b96716a7134230c", 41, "8ce03cd60514233b86789729102ea09e867fc6d964dea8c2018ef7d0a2e0e24bf7e348e917116690b9", }, + { "6aa6dad25d3acb3385d5643293133936cdddd7f7e11818771db1ff2f9d3f9215", "bbc8cbb43dda3ecf70a555981a351a064493f09658fffe884c6fab2a69c845c6", "98bca58b075d1748f1c3a7ae18f9341bc18e90d1beb8499e8a654c65d8a0b4fbd2e084661088d1e5069187a2811996ae31f59463668ef0f8cb0ac46a726e7902", 49, "e4a92208a6fc52282b620699191ee6fb9cf04daf48b48fd542c5e43daa9897763a199aaa4b6f10546109f47ac3564fade0", }, + { "8e32bc030a4c53de782ec75ba7d5e25e64a2a072a56e5170b77a4924ef3c32a9", "72d0e65f1ede79c4af0ba7ec14204e10f0f7ea09f2bc43259cd60ea8c3a087e2", "ef257d6e73706bb04878875c58aa385385bf439f7040ea8297f7798a0ea30c1c5eff5ddc05443f801849c68e98111ae65d088e726d1d9b7eeca2eb93b677860c", 40, "13ed795344c4448a3b256f23665336645a853c5c44dbff6db1b9224b5303b6447fbf8240a2249c55", }, + { "c83ce30fcb5b81a51ba58ff827ccbc0142d61c13e2ed39e78e876605da16d8d7", "3ec8923f9ea5ea14f8aaa7e7c2784653ed8c7de44e352ef9fc1dee81fc3fa1a3", "0c684e71b35fed4d92b222fc60561db34e0d8afe44bdd958aaf4ee965911bef5991236f3e1bced59fc44030693bcac37f34d29e5ae946669dc326e706e81b804", 49, "a2704638434e9f7340f22d08019c4c8e3dbee0df8dd4454a1d70844de11694f4c8ca67fdcb08fed0cec9abb2112b5e5f89", }, + { "2da2a0aae0f37235957b51d15843edde348a559692d8fa87b94848459899fc27", "d73d0b14a9754eec825fcb25ef1cfa9ae3b1370074eda53fc64c22334a26c254", "6f17f7b21ef9d6907a7ab104559f77d5a2532b557d95edffd6d88c073d87ac00fc838fc0d05282a0280368092a4bd67e95c20f3e14580be28d8b351968c65e03", 40, "d2488e854dbcdfdb2c9d16c8c0b2fdbc0abb6bac991bfe2b14d359a6bc99d66c00fd60d731ae06d0", }, + { "0c066261fb1b18ebf2a9bcdeda81eb47d5a3745438b3d0b9d19b75885ad0a154", "2e5773f0e725024bc0359ce93a44e15d6507e7b160b6c592200385fee4a269cf", "13b5d2dd1b04f62cc2ec1544fed256423684f2dbca4538ceddda1d15c59dc7196c87840ea303ea30f4f6914a6ec9167841980c1d717f47fd641225068de88507", 41, "f15cb706e29fcfbcb324e38cbac62bb355deddb845c142e970f0c029ea4d05e59fd6adf85573cf1775", }, + { "ef3d8e22a592f04c3a31aa736e10901757a821d053f1a49a525b4ec91eacdee3", "72a2b4910a502b30e13a96aba643c59c79328c1ba1462be6f254e817ef157fee", "95f2437a0210d2d2f125a3c377ed666c0d596cd104185e70204924a182a11a6eb3bdba4395bbfc3f4e827d38805752657ee52d1ce0f17e70f59bfd4999282509", 50, "6c3e4387345740b8d62cf0c9dec48f98c292539431b2b54020d8072d9cb55f0197f7d99ff066afcf9e41ea8b7aea78eb082d", }, + { "f7fb79743e9ba957d2a4f1bd95ceb1299552abecaf758bf840d2dc2c09f3e3cb", "8b7d7531280f76a8abac8293d87508e3953894087112ae01b6ad32485d4e9b67", "c868ecf31cee783fe8799ac7e6a662431c822967351d8b79687f4ddf608f79a080c4ff9eed4fdee8c99fe1be905f734cae2a172f1cfdb00771625c0695a5260e", 42, "55d8e60c307ee533b1af9ff677a2de40a6eace722bcc9eb5d79907b420e533bc06db674dafbd9f43d672", }, + { "8cc9a2469a77fad18b44b871b2b6932cd354641d2d1e84403f746c4fff829791", "aed5da202d4983dac560faf6704dc76ac111616318570e244043e82ed1bbcd2b", "aee9616db4135150818eaffa3e4503c2d7e9e834847a4c7d0a8856e952761d361a657104d36950c9b75770ded00d56a96e06f383fa2406bc935dcf51f272300e", 42, "d9b8be2f71b83261304e333d6e35563dc3c36c2eb5a23e1461b6e95aa7c6f381f9c3bd39deaa1b6df2f9", }, + { "a247abbef0c1affbf021d1aff128888550532fc0edd77bc39f6ef5312317ec47", "98ededbad1e5ad7a0d5a0cf4fcd7a794eb5c6900a65e7e921884a636f19b131d", "f8cc02933851432f0c5df0b70f2067f740ccb72de7d6fa1e9a9b0d6de1402b9c6c525fd848e45aaaac1423b52880ec3474a2f64b38db6fc8e008d95a310e6e0c", 47, "4a5f07eb713932532fc3132c96efdc45862fe7a954c1d2ae4640afdf4728fb58c65e8a4ebfe0d53d5797d5146442b9", }, + { "163d69079ddad1f16695c47d81c3b72f869b2fdd50e6e47113db6c85051a6ede", "93fe602642ee5773f4aaf6a3bc21e98e354035225353f419e78e43c3ec36c88a", "da747fa2cb47aae1effc1e4cfde0e39fa79937948592a712a7665bf948b8311e7f3f80f966301679520d5c2afa3eadd60e061f0d264887500d8d03a17e10fd02", 41, "65fe5c1a0214a59644892e5ac4216f09fbb4e191b89bfb63d6540177d25ef9e3714850b8453bd6b2b6", }, + { "7b061bf90eb760971b9ec66a96fd6609635ca4b531f33e3c126b9ae6fdb3d491", "cb392ebb6912df4111efeeb1278160daf9da396e9291b83979a5ac479f7276d2", "f6eebe86f7ea672e0707ee518e1798d6fbd118c11b2aa30be07d10e3882e3721f2030f9f044b77c3a7a9a2f1feba7e7ce75d1f7f3807a96a764fded35d341d02", 45, "a17f5ce39b9ba7b7cf1147e515d6aa84b22fd0e2d8323a91367198fc6c3aff04ebb21fc2bdbe7bc0364e8040a9", }, + { "c9f8ccbf761cec00ab236c52651e76b5f46d90f8936d44d40561ed5c277104de", "a3192641e343b669ffd43677c2e5cd4efaed174e876141f1d773bd6cfe30d875", "d44f884ec9eae2e99e74194b5acc769b7aa369aaad359e92ba6ff0fe629af2a9a7156c19b720e7de8c7f03c039563f160948073cab6f99b26a56a8bb1023ba08", 47, "3d7e33b0ecead8269966e9dcd192b73eb8a12573fc8a5fdfbe5753541026ef2e49f5280cba9bc2515a049b3a1c1b49", }, + { "ebfa409ac6f987df476858dd35310879bf564eeb62984a52115d2e6c24590124", "7bb1601fe7215f3f4da9c8ab5e804dc58f57ba41b03223f57ec80d9c9a2dd0e1", "f3e7c1abfcc9f35556cb1e4c5a2b34445177ac188312d9148f1d1d8467ea8411fa3cda031d023034e45bbe407ef7d1b937bfb098266138857d35cb4efe407306", 52, "0c37564f718eda683aa6f3e9ab2487620b1a8b5c8f20adb3b2d7550af0d635371e531f27cebe76a2abcc96de0875bdae987a45ac", }, + { "f993f61902b7da332f2bb001baa7accaf764d824eb0cd073315f7ec43158b8fb", "55fc8e0da1b454cab6ddefb235311db2b01504bf9ac3f71c7e3f3d0d1f09f80b", "178bd147673c0ca330e45da63cbd1f1811906bd5284bb44e4bb00f7d7163d1f396975610b6f71c1ae4686466fad4c5e7bb9685099e21ca4f1a45bb3fcf56ae0c", 42, "b7dd613bc9c364d9eeb9a52636d72bc881dfc81a836b6537bbb928bff5b73831358947ea9edea1570550", }, + { "05188c09c31b4bb63f0d49b47ccc1654c2aba907b8c6c0a82ee403e950169167", "e096d808dfabe8e44eb74950199dadcd586f9de6b141a0ce85ab94b3d97866eb", "669491c8eb7cedbbc0252f3eafb048b39a2a37f60ac87837777c72c879ac8b726c39e10060750c2f539102999b71889746111bc5f71ec8c158cc81cf566aef03", 44, "bb8e22469d1c7f1d5418563e8781f69eccb56678bd36d8919f358c2778562ff6b50de916c12d44f1a778a7f3", }, + { "eabe57e1a916ebbffa4ba7abc7f23e83d4deb1338816cc1784d7495d92e98d0b", "3aad275642f48a46ed1032f3de9f4053e0fd35cf217e065d2e4579c3683932f7", "b2e9dac2c83942ca374f29c8eff5a30c377c3db3c1c645e593e524d17484e7705b11f79573e2d63495fc3ce3bf216a209f0cb7bea477ae0f8bd297f193af8805", 44, "3f2c2d6682ee597f2a92d7e560ac53d5623550311a4939d68adfb904045ed8d215a9fdb757a2368ea4d89f5f", }, + { "fef7b893b4b517fab68ca12d36b603bc00826bf3c9b31a05149642ae10bb3f55", "b3fb891868708dfa5da5b9b5234058767ab42c117f12c3228c02a1976d1c0f83", "6243e289314b7c7587802909a9be6173a916b36f9de1e164954dfe5d1ebd57c869a79552d770e13b51855502be6b15e7be42a3675298a81284df58e609b06503", 47, "38c69f884045cdbeebe4478fdbd1ccc6cf00a08d8a3120c74e7167d3a2e26a67a043b8e5bd198f7b0ce0358cef7cf9", }, + { "16228bec9b724300a37e88e535fc1c58548d34d7148b57c226f2b3af974c1822", "3c92423a8360c9a5d9a093730d72831bec4601dcadfe84de19fc8c8f91fc3d4b", "6aebfa9a4294ec888d54bcb517fcb6821e4c16d2708a2afe701f431a28149ff4f139f9d16a52a63f1f91baf4c8dea37710c73f25c263a8035a39cc118ad0280f", 44, "a3d7b122cd4431b396b20d8cc46cc73ed4a5253a44a76fc83db62cdc845a2bf7081d069a857955a161cccf84", }, + { "2dc3f5f0a0bc32c6632534e1e8f27e59cbe0bf7617d31aff98098e974c828be7", "b998a416edc28ded988dcacb1caf2bd96c87354b0d1eeccb6980e54a3104f21f", "76a2ddfc4bea48c47e0c82bcbfee28a37c61ec626af39a468e643e0ef9f6533056a5a0b44e64d614ba3c641a40e5b003a99463445ae2c3c8e1e9882092d74b07", 42, "bdae276d738b9758ea3d322b54fd12fe82b767e8d817d8ef3d41f78705748e28d15e9c506962a1b85901", }, + }; + + ed25519_secret_key private_key; + ed25519_public_key public_key; + ed25519_signature signature; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + // For some reason, NEM stores private keys in big endian + const uint8_t *reversed_key = fromhex(tests[i].private_key); + for (size_t j = 0; j < 32; j++) { + private_key[j] = reversed_key[32 - j - 1]; + } + + ed25519_publickey_keccak(private_key, public_key); + ck_assert_mem_eq(public_key, fromhex(tests[i].public_key), 32); + + ed25519_sign_keccak(fromhex(tests[i].data), tests[i].length, private_key, public_key, signature); + ck_assert_mem_eq(signature, fromhex(tests[i].signature), 64); + } +} +END_TEST + START_TEST(test_ed25519_cosi) { const int MAXN = 10; ed25519_secret_key keys[MAXN]; @@ -3237,6 +3290,10 @@ Suite *test_suite(void) tcase_add_test(tc, test_ed25519); suite_add_tcase(s, tc); + tc = tcase_create("ed25519_keccak"); + tcase_add_test(tc, test_ed25519_keccak); + suite_add_tcase(s, tc); + tc = tcase_create("ed25519_cosi"); tcase_add_test(tc, test_ed25519_cosi); suite_add_tcase(s, tc); From d1f97d07f88bd382db0f9fb6af529d8115e75830 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Mon, 22 May 2017 20:10:07 +0100 Subject: [PATCH 443/627] nem_test_vectors: Handle empty header column --- tools/nem_test_vectors.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/nem_test_vectors.rb b/tools/nem_test_vectors.rb index 46586f84e..8d43239cd 100755 --- a/tools/nem_test_vectors.rb +++ b/tools/nem_test_vectors.rb @@ -32,7 +32,10 @@ def load_header(line) line = line.dup abort 'Header is not a comment' unless line.slice!(0) == '#' - line.split(':').each(&:strip!) + header = line.split(':').each(&:strip!) + header.shift if header.first.empty? + + header end def parse_field_answer(answer) From d4b5e64ba2ff4426c4c2d3effb5335f71bf67aef Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sun, 4 Jun 2017 12:46:29 +0100 Subject: [PATCH 444/627] test_check: Add MARK_SECRET_DATA to test_ed25519_keccak --- test_check.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test_check.c b/test_check.c index 80fb1ed35..364643eba 100644 --- a/test_check.c +++ b/test_check.c @@ -2830,12 +2830,17 @@ START_TEST(test_ed25519_keccak) for (size_t j = 0; j < 32; j++) { private_key[j] = reversed_key[32 - j - 1]; } + MARK_SECRET_DATA(private_key, sizeof(private_key)); ed25519_publickey_keccak(private_key, public_key); + UNMARK_SECRET_DATA(public_key, sizeof(public_key)); ck_assert_mem_eq(public_key, fromhex(tests[i].public_key), 32); ed25519_sign_keccak(fromhex(tests[i].data), tests[i].length, private_key, public_key, signature); + UNMARK_SECRET_DATA(signature, sizeof(signature)); ck_assert_mem_eq(signature, fromhex(tests[i].signature), 64); + + UNMARK_SECRET_DATA(private_key, sizeof(private_key)); } } END_TEST From 4e3ae3d69b3b9cf1b702e0da435fef91304f544f Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 5 Jun 2017 17:02:21 +0200 Subject: [PATCH 445/627] test_openssl: test for NIST curve too --- test_openssl.c | 81 ++++++++++++++++++++++++++++---------------------- 1 file changed, 46 insertions(+), 35 deletions(-) diff --git a/test_openssl.c b/test_openssl.c index 9f3c2d2a5..f1446ad3c 100644 --- a/test_openssl.c +++ b/test_openssl.c @@ -29,32 +29,25 @@ #include "ecdsa.h" #include "rand.h" + +#include "nist256p1.h" #include "secp256k1.h" -int main(int argc, char *argv[]) +void openssl_check(unsigned int iterations, int nid, const ecdsa_curve *curve) { uint8_t sig[64], pub_key33[33], pub_key65[65], priv_key[32], msg[256], buffer[1000], hash[32], *p; - uint32_t i, j, msg_len; SHA256_CTX sha256; EC_GROUP *ecgroup; - int cnt = 0; - ecgroup = EC_GROUP_new_by_curve_name(NID_secp256k1); + ecgroup = EC_GROUP_new_by_curve_name(nid); + + for (unsigned int iter = 0; iter < iterations; iter++) { - unsigned long max_iterations = -1; - if (argc == 2) { - sscanf(argv[1], "%lu", &max_iterations); - } else if (argc > 2) { - puts("Zero or one command-line arguments only, exiting...."); - } - unsigned long iterations = 0; - while (argc == 1 || iterations < max_iterations) { // random message len between 1 and 256 - msg_len = (random32() & 0xFF) + 1; + int msg_len = (random32() & 0xFF) + 1; // create random message - for (i = 0; i < msg_len; i++) { - msg[i] = random32() & 0xFF; - } + random_buffer(msg, msg_len); + // new ECDSA key EC_KEY *eckey = EC_KEY_new(); EC_KEY_set_group(eckey, ecgroup); @@ -66,39 +59,39 @@ int main(int argc, char *argv[]) i2d_ECPrivateKey(eckey, &p); // size of the key is in buffer[8] and the key begins right after that - i = buffer[8]; + int s = buffer[8]; // extract key data - if (i > 32) { - for (j = 0; j < 32; j++) { - priv_key[j] = buffer[j + i - 23]; + if (s > 32) { + for (int j = 0; j < 32; j++) { + priv_key[j] = buffer[j + s - 23]; } } else { - for (j = 0; j < 32 - i; j++) { + for (int j = 0; j < 32 - s; j++) { priv_key[j] = 0; } - for (j = 0; j < i; j++) { - priv_key[j + 32 - i] = buffer[j + 9]; + for (int j = 0; j < s; j++) { + priv_key[j + 32 - s] = buffer[j + 9]; } } // use our ECDSA signer to sign the message with the key - if (ecdsa_sign(&secp256k1, priv_key, msg, msg_len, sig, NULL, NULL) != 0) { + if (ecdsa_sign(curve, priv_key, msg, msg_len, sig, NULL, NULL) != 0) { printf("trezor-crypto signing failed\n"); - break; + return; } // generate public key from private key - ecdsa_get_public_key33(&secp256k1, priv_key, pub_key33); - ecdsa_get_public_key65(&secp256k1, priv_key, pub_key65); + ecdsa_get_public_key33(curve, priv_key, pub_key33); + ecdsa_get_public_key65(curve, priv_key, pub_key65); // use our ECDSA verifier to verify the message signature - if (ecdsa_verify(&secp256k1, pub_key65, sig, msg, msg_len) != 0) { + if (ecdsa_verify(curve, pub_key65, sig, msg, msg_len) != 0) { printf("trezor-crypto verification failed (pub_key_len = 65)\n"); - break; + return; } - if (ecdsa_verify(&secp256k1, pub_key33, sig, msg, msg_len) != 0) { + if (ecdsa_verify(curve, pub_key33, sig, msg, msg_len) != 0) { printf("trezor-crypto verification failed (pub_key_len = 33)\n"); - break; + return; } // copy signature to the OpenSSL struct @@ -114,14 +107,32 @@ int main(int argc, char *argv[]) // verify all went well, i.e. we can decrypt our signature with OpenSSL if (ECDSA_do_verify(hash, 32, signature, eckey) != 1) { printf("OpenSSL verification failed\n"); - break; + return; } + ECDSA_SIG_free(signature); EC_KEY_free(eckey); - cnt++; - if ((cnt % 100) == 0) printf("Passed ... %d\n", cnt); - ++iterations; + if (((iter + 1) % 100) == 0) printf("Passed ... %d\n", iter + 1); } EC_GROUP_free(ecgroup); + printf("All OK\n"); +} + +int main(int argc, char *argv[]) +{ + if (argc != 2) { + printf("Usage: test_openssl iterations\n"); + return 1; + } + + unsigned int iterations; + sscanf(argv[1], "%u", &iterations); + + printf("Testing secp256k1:\n"); + openssl_check(iterations, NID_secp256k1, &secp256k1); + + printf("Testing nist256p1:\n"); + openssl_check(iterations, NID_X9_62_prime256v1, &nist256p1); + return 0; } From e92f5ad90753fe48045bfcfd729633bf0f49ca26 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 5 Jun 2017 17:04:11 +0200 Subject: [PATCH 446/627] add more info to readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f4afd0c66..92e766985 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ These include: - ECDSA public key derivation - Base32 (RFC4648) - Base58 address representation -- Ed25519 signing/verifying +- Ed25519 signing/verifying (also SHA3 and Keccak variants) - ECDH using secp256k1, nist256p1 and Curve25519 - HMAC-SHA256 and HMAC-SHA512 - PBKDF2 From a07a89a421e1caaeb8b7be0108a20826024cc0fd Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Mon, 5 Jun 2017 18:14:43 +0100 Subject: [PATCH 447/627] GCC 7.1.1 -Wimplicit-fallthrough comments Use //-fallthrough rather than __attribute__((fallthrough)) --- aes/aescrypt.c | 6 ++++++ base58.c | 3 +++ 2 files changed, 9 insertions(+) diff --git a/aes/aescrypt.c b/aes/aescrypt.c index 83c77f0b6..8c7c7f24c 100644 --- a/aes/aescrypt.c +++ b/aes/aescrypt.c @@ -115,10 +115,12 @@ AES_RETURN aes_xi(encrypt)(const unsigned char *in, unsigned char *out, const ae round(fwd_rnd, b1, b0, kp + 1 * N_COLS); round(fwd_rnd, b0, b1, kp + 2 * N_COLS); kp += 2 * N_COLS; + //-fallthrough case 12 * 16: round(fwd_rnd, b1, b0, kp + 1 * N_COLS); round(fwd_rnd, b0, b1, kp + 2 * N_COLS); kp += 2 * N_COLS; + //-fallthrough case 10 * 16: round(fwd_rnd, b1, b0, kp + 1 * N_COLS); round(fwd_rnd, b0, b1, kp + 2 * N_COLS); @@ -130,6 +132,7 @@ AES_RETURN aes_xi(encrypt)(const unsigned char *in, unsigned char *out, const ae round(fwd_rnd, b0, b1, kp + 8 * N_COLS); round(fwd_rnd, b1, b0, kp + 9 * N_COLS); round(fwd_lrnd, b0, b1, kp +10 * N_COLS); + //-fallthrough } #else @@ -247,9 +250,11 @@ AES_RETURN aes_xi(decrypt)(const unsigned char *in, unsigned char *out, const ae case 14 * 16: round(inv_rnd, b1, b0, rnd_key(-13)); round(inv_rnd, b0, b1, rnd_key(-12)); + //-fallthrough case 12 * 16: round(inv_rnd, b1, b0, rnd_key(-11)); round(inv_rnd, b0, b1, rnd_key(-10)); + //-fallthrough case 10 * 16: round(inv_rnd, b1, b0, rnd_key(-9)); round(inv_rnd, b0, b1, rnd_key(-8)); @@ -261,6 +266,7 @@ AES_RETURN aes_xi(decrypt)(const unsigned char *in, unsigned char *out, const ae round(inv_rnd, b0, b1, rnd_key(-2)); round(inv_rnd, b1, b0, rnd_key(-1)); round(inv_lrnd, b0, b1, rnd_key( 0)); + //-fallthrough } #else diff --git a/base58.c b/base58.c index 2c44d3985..0c26943ca 100644 --- a/base58.c +++ b/base58.c @@ -90,11 +90,14 @@ bool b58tobin(void *bin, size_t *binszp, const char *b58) switch (bytesleft) { case 3: *(binu++) = (outi[0] & 0xff0000) >> 16; + //-fallthrough case 2: *(binu++) = (outi[0] & 0xff00) >> 8; + //-fallthrough case 1: *(binu++) = (outi[0] & 0xff); ++j; + //-fallthrough default: break; } From 3806c6fcd38face9464b74ee2a1b0ce9efd64170 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Mon, 5 Jun 2017 18:17:16 +0100 Subject: [PATCH 448/627] test_check: Add Base32 lowercase RFC4648 tests --- test_check.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/test_check.c b/test_check.c index 364643eba..aaecb11f9 100644 --- a/test_check.c +++ b/test_check.c @@ -504,23 +504,25 @@ END_TEST START_TEST(test_base32_rfc4648) { static const struct { - const char *input; - const char *output; + const char *decoded; + const char *encoded; + const char *encoded_lowercase; } tests[] = { - { "", "" }, - { "f", "MY" }, - { "fo", "MZXQ" }, - { "foo", "MZXW6" }, - { "foob", "MZXW6YQ" }, - { "fooba", "MZXW6YTB" }, - { "foobar", "MZXW6YTBOI" }, + { "", "", ""}, + { "f", "MY", "my" }, + { "fo", "MZXQ", "mzxq" }, + { "foo", "MZXW6", "mzxw6" }, + { "foob", "MZXW6YQ", "mzxw6yq" }, + { "fooba", "MZXW6YTB", "mzxw6ytb" }, + { "foobar", "MZXW6YTBOI", "mzxw6ytboi" }, }; char buffer[64]; for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - const char *in = tests[i].input; - const char *out = tests[i].output; + const char *in = tests[i].decoded; + const char *out = tests[i].encoded; + const char *out_lowercase = tests[i].encoded_lowercase; size_t inlen = strlen(in); size_t outlen = strlen(out); @@ -533,7 +535,11 @@ START_TEST(test_base32_rfc4648) char *ret = (char *) base32_decode(out, outlen, (uint8_t *) buffer, sizeof(buffer), BASE32_ALPHABET_RFC4648); ck_assert(ret != NULL); + *ret = '\0'; + ck_assert_str_eq(buffer, in); + ret = (char *) base32_decode(out_lowercase, outlen, (uint8_t *) buffer, sizeof(buffer), BASE32_ALPHABET_RFC4648); + ck_assert(ret != NULL); *ret = '\0'; ck_assert_str_eq(buffer, in); } From ba206056e73cb1972b7ecb6ad7939254cb51074f Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Mon, 5 Jun 2017 19:17:30 +0100 Subject: [PATCH 449/627] README: Add Base32 custom alphabet support --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 92e766985..556356029 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ These include: - ECDSA signing/verifying (supports secp256k1 and nist256p1 curves, uses RFC6979 for deterministic signatures) - ECDSA public key derivation -- Base32 (RFC4648) +- Base32 (RFC4648 and custom alphabets) - Base58 address representation - Ed25519 signing/verifying (also SHA3 and Keccak variants) - ECDH using secp256k1, nist256p1 and Curve25519 From 4ad30592af54197f66446a3ed7f56ec26be6d87c Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 12 Jun 2017 14:40:57 +0200 Subject: [PATCH 450/627] update travis notification url --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8a5c3ef25..e7d3020ab 100644 --- a/.travis.yml +++ b/.travis.yml @@ -45,8 +45,7 @@ matrix: notifications: webhooks: urls: - - http://sway.gk2.sk:5000/travis - - http://163.172.132.178:5000/travis + - http://ci-bot.satoshilabs.com:5000/travis on_success: always on_failure: always on_start: always From 533193562601780c8705ecb80c908916bb80b427 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sat, 24 Jun 2017 17:42:10 +0100 Subject: [PATCH 451/627] ed25519-donna: Remove duplicate basepoint tables --- CMakeLists.txt | 2 +- Makefile | 2 +- ed25519-donna/ed25519-donna-basepoint-table.c | 262 ++++++++++++++++++ ed25519-donna/ed25519-donna-basepoint-table.h | 259 +---------------- 4 files changed, 265 insertions(+), 260 deletions(-) create mode 100644 ed25519-donna/ed25519-donna-basepoint-table.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 816e0255e..6133c903a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 2.8) -set(SOURCES address.c aes/aescrypt.c aes/aeskey.c aes/aes_modes.c aes/aestab.c base32.c base58.c bignum.c bip32.c bip39.c ecdsa.c hmac.c nist256p1.c pbkdf2.c rand.c ripemd160.c secp256k1.c sha2.c sha3.c ed25519-donna/ed25519.c ed25519-donna/ed25519-sha3.c ed25519-donna/ed25519-keccak.c) +set(SOURCES address.c aes/aescrypt.c aes/aeskey.c aes/aes_modes.c aes/aestab.c base32.c base58.c bignum.c bip32.c bip39.c ecdsa.c hmac.c nist256p1.c pbkdf2.c rand.c ripemd160.c secp256k1.c sha2.c sha3.c ed25519-donna/ed25519.c ed25519-donna/ed25519-donna-basepoint-table.c ed25519-donna/ed25519-sha3.c ed25519-donna/ed25519-keccak.c) add_library(TrezorCrypto STATIC ${SOURCES}) diff --git a/Makefile b/Makefile index a69a2904b..f2598d737 100644 --- a/Makefile +++ b/Makefile @@ -44,7 +44,7 @@ SRCS += ripemd160.c SRCS += sha2.c SRCS += sha3.c SRCS += aes/aescrypt.c aes/aeskey.c aes/aestab.c aes/aes_modes.c -SRCS += ed25519-donna/ed25519.c ed25519-donna/ed25519-sha3.c ed25519-donna/ed25519-keccak.c +SRCS += ed25519-donna/ed25519.c ed25519-donna/ed25519-donna-basepoint-table.c ed25519-donna/ed25519-sha3.c ed25519-donna/ed25519-keccak.c SRCS += blake2b.c blake2s.c SRCS += chacha20poly1305/chacha20poly1305.c chacha20poly1305/chacha_merged.c chacha20poly1305/poly1305-donna.c chacha20poly1305/rfc7539.c diff --git a/ed25519-donna/ed25519-donna-basepoint-table.c b/ed25519-donna/ed25519-donna-basepoint-table.c new file mode 100644 index 000000000..7a05f8935 --- /dev/null +++ b/ed25519-donna/ed25519-donna-basepoint-table.c @@ -0,0 +1,262 @@ +#include "ed25519-donna-portable.h" +#include "ed25519-donna-basepoint-table.h" + +/* multiples of the base point in packed {ysubx, xaddy, t2d} form */ +const uint8_t ALIGN(16) ge25519_niels_base_multiples[256][96] = { + {0x3e,0x91,0x40,0xd7,0x05,0x39,0x10,0x9d,0xb3,0xbe,0x40,0xd1,0x05,0x9f,0x39,0xfd,0x09,0x8a,0x8f,0x68,0x34,0x84,0xc1,0xa5,0x67,0x12,0xf8,0x98,0x92,0x2f,0xfd,0x44,0x85,0x3b,0x8c,0xf5,0xc6,0x93,0xbc,0x2f,0x19,0x0e,0x8c,0xfb,0xc6,0x2d,0x93,0xcf,0xc2,0x42,0x3d,0x64,0x98,0x48,0x0b,0x27,0x65,0xba,0xd4,0x33,0x3a,0x9d,0xcf,0x07,0x59,0xbb,0x6f,0x4b,0x67,0x15,0xbd,0xdb,0xea,0xa5,0xa2,0xee,0x00,0x3f,0xe1,0x41,0xfa,0xc6,0x57,0xc9,0x1c,0x9d,0xd4,0xcd,0xca,0xec,0x16,0xaf,0x1f,0xbe,0x0e,0x4f}, + {0xa8,0xd5,0xb4,0x42,0x60,0xa5,0x99,0x8a,0xf6,0xac,0x60,0x4e,0x0c,0x81,0x2b,0x8f,0xaa,0x37,0x6e,0xb1,0x6b,0x23,0x9e,0xe0,0x55,0x25,0xc9,0x69,0xa6,0x95,0xb5,0x6b,0xd7,0x71,0x3c,0x93,0xfc,0xe7,0x24,0x92,0xb5,0xf5,0x0f,0x7a,0x96,0x9d,0x46,0x9f,0x02,0x07,0xd6,0xe1,0x65,0x9a,0xa6,0x5a,0x2e,0x2e,0x7d,0xa8,0x3f,0x06,0x0c,0x59,0x02,0x68,0xd3,0xda,0xaa,0x7e,0x34,0x6e,0x05,0x48,0xee,0x83,0x93,0x59,0xf3,0xba,0x26,0x68,0x07,0xe6,0x10,0xbe,0xca,0x3b,0xb8,0xd1,0x5e,0x16,0x0a,0x4f,0x31,0x49}, + {0x65,0xd2,0xfc,0xa4,0xe8,0x1f,0x61,0x56,0x7d,0xba,0xc1,0xe5,0xfd,0x53,0xd3,0x3b,0xbd,0xd6,0x4b,0x21,0x1a,0xf3,0x31,0x81,0x62,0xda,0x5b,0x55,0x87,0x15,0xb9,0x2a,0x30,0x97,0xee,0x4c,0xa8,0xb0,0x25,0xaf,0x8a,0x4b,0x86,0xe8,0x30,0x84,0x5a,0x02,0x32,0x67,0x01,0x9f,0x02,0x50,0x1b,0xc1,0xf4,0xf8,0x80,0x9a,0x1b,0x4e,0x16,0x7a,0x34,0x48,0x67,0xf1,0xf4,0x11,0xf2,0x9b,0x95,0xf8,0x2d,0xf6,0x17,0x6b,0x4e,0xb8,0x4e,0x2a,0x72,0x5b,0x07,0x6f,0xde,0xd7,0x21,0x2a,0xbb,0x63,0xb9,0x04,0x9a,0x54}, + {0xbf,0x18,0x68,0x05,0x0a,0x05,0xfe,0x95,0xa9,0xfa,0x60,0x56,0x71,0x89,0x7e,0x32,0x73,0x50,0xa0,0x06,0xcd,0xe3,0xe8,0xc3,0x9a,0xa4,0x45,0x74,0x4c,0x3f,0x93,0x27,0x9f,0x09,0xfc,0x8e,0xb9,0x51,0x73,0x28,0x38,0x25,0xfd,0x7d,0xf4,0xc6,0x65,0x67,0x65,0x92,0x0a,0xfb,0x3d,0x8d,0x34,0xca,0x27,0x87,0xe5,0x21,0x03,0x91,0x0e,0x68,0xb0,0x26,0x14,0xe5,0xec,0x45,0x1e,0xbf,0x94,0x0f,0xba,0x6d,0x3d,0xc6,0x2b,0xe3,0xc0,0x52,0xf8,0x8c,0xd5,0x74,0x29,0xe4,0x18,0x4c,0xe6,0xb0,0xb1,0x79,0xf0,0x44}, + {0xba,0xd6,0x47,0xa4,0xc3,0x82,0x91,0x7f,0xb7,0x29,0x27,0x4b,0xd1,0x14,0x00,0xd5,0x87,0xa0,0x64,0xb8,0x1c,0xf1,0x3c,0xe3,0xf3,0x55,0x1b,0xeb,0x73,0x7e,0x4a,0x15,0x33,0xbb,0xa5,0x08,0x44,0xbc,0x12,0xa2,0x02,0xed,0x5e,0xc7,0xc3,0x48,0x50,0x8d,0x44,0xec,0xbf,0x5a,0x0c,0xeb,0x1b,0xdd,0xeb,0x06,0xe2,0x46,0xf1,0xcc,0x45,0x29,0xb3,0x03,0xd0,0xe7,0x79,0xa1,0x32,0xc8,0x7e,0x4d,0x12,0x00,0x0a,0x9d,0x72,0x5f,0xf3,0x8f,0x6d,0x0e,0xa1,0xd4,0xc1,0x62,0x98,0x7a,0xb2,0x38,0x59,0xac,0xb8,0x68}, + {0xa4,0x8c,0x7d,0x7b,0xb6,0x06,0x98,0x49,0x39,0x27,0xd2,0x27,0x84,0xe2,0x5b,0x57,0xb9,0x53,0x45,0x20,0xe7,0x5c,0x08,0xbb,0x84,0x78,0x41,0xae,0x41,0x4c,0xb6,0x38,0x31,0x71,0x15,0x77,0xeb,0xee,0x0c,0x3a,0x88,0xaf,0xc8,0x00,0x89,0x15,0x27,0x9b,0x36,0xa7,0x59,0xda,0x68,0xb6,0x65,0x80,0xbd,0x38,0xcc,0xa2,0xb6,0x7b,0xe5,0x51,0xa4,0xe3,0x9d,0x68,0x91,0xad,0x9d,0x8f,0x37,0x91,0xfb,0xf8,0x28,0x24,0x5f,0x17,0x88,0xb9,0xcf,0x9f,0x32,0xb5,0x0a,0x05,0x9f,0xc0,0x54,0x13,0xa2,0xdf,0x65,0x78}, + {0xb1,0x21,0x32,0xaa,0x9a,0x2c,0x6f,0xba,0xa7,0x23,0xba,0x3b,0x53,0x21,0xa0,0x6c,0x3a,0x2c,0x19,0x92,0x4f,0x76,0xea,0x9d,0xe0,0x17,0x53,0x2e,0x5d,0xdd,0x6e,0x1d,0xbf,0xa3,0x4e,0x94,0xd0,0x5c,0x1a,0x6b,0xd2,0xc0,0x9d,0xb3,0x3a,0x35,0x70,0x74,0x49,0x2e,0x54,0x28,0x82,0x52,0xb2,0x71,0x7e,0x92,0x3c,0x28,0x69,0xea,0x1b,0x46,0x36,0xda,0x0f,0xab,0xac,0x8a,0x7a,0x21,0xc8,0x49,0x35,0x3d,0x54,0xc6,0x28,0xa5,0x68,0x75,0xab,0x13,0x8b,0x5b,0xd0,0x37,0x37,0xbc,0x2c,0x3a,0x62,0xef,0x3c,0x23}, + {0xd9,0x34,0x92,0xf3,0xed,0x5d,0xa7,0xe2,0xf9,0x58,0xb5,0xe1,0x80,0x76,0x3d,0x96,0xfb,0x23,0x3c,0x6e,0xac,0x41,0x27,0x2c,0xc3,0x01,0x0e,0x32,0xa1,0x24,0x90,0x3a,0x8f,0x3e,0xdd,0x04,0x66,0x59,0xb7,0x59,0x2c,0x70,0x88,0xe2,0x77,0x03,0xb3,0x6c,0x23,0xc3,0xd9,0x5e,0x66,0x9c,0x33,0xb1,0x2f,0xe5,0xbc,0x61,0x60,0xe7,0x15,0x09,0x7e,0xa3,0x34,0xa8,0x35,0xe8,0x7d,0xdf,0xea,0x57,0x98,0x68,0xda,0x9c,0xe1,0x8b,0x26,0xb3,0x67,0x71,0x36,0x85,0x11,0x2c,0xc2,0xd5,0xef,0xdb,0xd9,0xb3,0x9e,0x58}, + {0x5e,0x51,0xaa,0x49,0x54,0x63,0x5b,0xed,0x3a,0x82,0xc6,0x0b,0x9f,0xc4,0x65,0xa8,0xc4,0xd1,0x42,0x5b,0xe9,0x1f,0x0c,0x85,0xb9,0x15,0xd3,0x03,0x6f,0x6d,0xd7,0x30,0x1d,0x9c,0x2f,0x63,0x0e,0xdd,0xcc,0x2e,0x15,0x31,0x89,0x76,0x96,0xb6,0xd0,0x51,0x58,0x7a,0x63,0xa8,0x6b,0xb7,0xdf,0x52,0x39,0xef,0x0e,0xa0,0x49,0x7d,0xd3,0x6d,0xc7,0xe4,0x06,0x21,0x17,0x44,0x44,0x6c,0x69,0x7f,0x8d,0x92,0x80,0xd6,0x53,0xfb,0x26,0x3f,0x4d,0x69,0xa4,0x9e,0x73,0xb4,0xb0,0x4b,0x86,0x2e,0x11,0x97,0xc6,0x10}, + {0xde,0x5f,0xbe,0x7d,0x27,0xc4,0x93,0x64,0xa2,0x7e,0xad,0x19,0xad,0x4f,0x5d,0x26,0x90,0x45,0x30,0x46,0xc8,0xdf,0x00,0x0e,0x09,0xfe,0x66,0xed,0xab,0x1c,0xe6,0x25,0x05,0xc8,0x58,0x83,0xa0,0x2a,0xa6,0x0c,0x47,0x42,0x20,0x7a,0xe3,0x4a,0x3d,0x6a,0xdc,0xed,0x11,0x3b,0xa6,0xd3,0x64,0x74,0xef,0x06,0x08,0x55,0xaf,0x9b,0xbf,0x03,0x04,0x66,0x58,0xcc,0x28,0xe1,0x13,0x3f,0x7e,0x74,0x59,0xb4,0xec,0x73,0x58,0x6f,0xf5,0x68,0x12,0xcc,0xed,0x3d,0xb6,0xa0,0x2c,0xe2,0x86,0x45,0x63,0x78,0x6d,0x56}, + {0x34,0x08,0xc1,0x9c,0x9f,0xa4,0x37,0x16,0x51,0xc4,0x9b,0xa8,0xd5,0x56,0x8e,0xbc,0xdb,0xd2,0x7f,0x7f,0x0f,0xec,0xb5,0x1c,0xd9,0x35,0xcc,0x5e,0xca,0x5b,0x97,0x33,0xd0,0x2f,0x5a,0xc6,0x85,0x42,0x05,0xa1,0xc3,0x67,0x16,0xf3,0x2a,0x11,0x64,0x6c,0x58,0xee,0x1a,0x73,0x40,0xe2,0x0a,0x68,0x2a,0xb2,0x93,0x47,0xf3,0xa5,0xfb,0x14,0xd4,0xf7,0x85,0x69,0x16,0x46,0xd7,0x3c,0x57,0x00,0xc8,0xc9,0x84,0x5e,0x3e,0x59,0x1e,0x13,0x61,0x7b,0xb6,0xf2,0xc3,0x2f,0x6c,0x52,0xfc,0x83,0xea,0x9c,0x82,0x14}, + {0xc2,0x95,0xdd,0x97,0x84,0x7b,0x43,0xff,0xa7,0xb5,0x4e,0xaa,0x30,0x4e,0x74,0x6c,0x8b,0xe8,0x85,0x3c,0x61,0x5d,0x0c,0x9e,0x73,0x81,0x75,0x5f,0x1e,0xc7,0xd9,0x2f,0xb8,0xec,0x71,0x4e,0x2f,0x0b,0xe7,0x21,0xe3,0x77,0xa4,0x40,0xb9,0xdd,0x56,0xe6,0x80,0x4f,0x1d,0xce,0xce,0x56,0x65,0xbf,0x7e,0x7b,0x5d,0x53,0xc4,0x3b,0xfc,0x05,0xdd,0xde,0xaf,0x52,0xae,0xb3,0xb8,0x24,0xcf,0x30,0x3b,0xed,0x8c,0x63,0x95,0x34,0x95,0x81,0xbe,0xa9,0x83,0xbc,0xa4,0x33,0x04,0x1f,0x65,0x5c,0x47,0x67,0x37,0x37}, + {0xd9,0xad,0xd1,0x40,0xfd,0x99,0xba,0x2f,0x27,0xd0,0xf4,0x96,0x6f,0x16,0x07,0xb3,0xae,0x3b,0xf0,0x15,0x52,0xf0,0x63,0x43,0x99,0xf9,0x18,0x3b,0x6c,0xa5,0xbe,0x1f,0x90,0x65,0x24,0x14,0xcb,0x95,0x40,0x63,0x35,0x55,0xc1,0x16,0x40,0x14,0x12,0xef,0x60,0xbc,0x10,0x89,0x0c,0x14,0x38,0x9e,0x8c,0x7c,0x90,0x30,0x57,0x90,0xf5,0x6b,0x8a,0x5b,0x41,0xe1,0xf1,0x78,0xa7,0x0f,0x7e,0xa7,0xc3,0xba,0xf7,0x9f,0x40,0x06,0x50,0x9a,0xa2,0x9a,0xb8,0xd7,0x52,0x6f,0x56,0x5a,0x63,0x7a,0xf6,0x1c,0x52,0x02}, + {0x94,0x52,0x9d,0x0a,0x0b,0xee,0x3f,0x51,0x66,0x5a,0xdf,0x0f,0x5c,0xe7,0x98,0x8f,0xce,0x07,0xe1,0xbf,0x88,0x86,0x61,0xd4,0xed,0x2c,0x38,0x71,0x7e,0x0a,0xa0,0x3f,0xe4,0x5e,0x2f,0x77,0x20,0x67,0x14,0xb1,0xce,0x9a,0x07,0x96,0xb1,0x94,0xf8,0xe8,0x4a,0x82,0xac,0x00,0x4d,0x22,0xf8,0x4a,0xc4,0x6c,0xcd,0xf7,0xd9,0x53,0x17,0x00,0x34,0xdb,0x3d,0x96,0x2d,0x23,0x69,0x3c,0x58,0x38,0x97,0xb4,0xda,0x87,0xde,0x1d,0x85,0xf2,0x91,0xa0,0xf9,0xd1,0xd7,0xaa,0xb6,0xed,0x48,0xa0,0x2f,0xfe,0xb5,0x12}, + {0x4d,0xe3,0xfc,0x96,0xc4,0xfb,0xf0,0x71,0xed,0x5b,0xf3,0xad,0x6b,0x82,0xb9,0x73,0x61,0xc5,0x28,0xff,0x61,0x72,0x04,0xd2,0x6f,0x20,0xb1,0x6f,0xf9,0x76,0x9b,0x74,0x92,0x1e,0x6f,0xad,0x26,0x7c,0x2b,0xdf,0x13,0x89,0x4b,0x50,0x23,0xd3,0x66,0x4b,0xc3,0x8b,0x1c,0x75,0xc0,0x9d,0x40,0x8c,0xb8,0xc7,0x96,0x07,0xc2,0x93,0x7e,0x6f,0x05,0xae,0xa6,0xae,0x04,0xf6,0x5a,0x1f,0x99,0x9c,0xe4,0xbe,0xf1,0x51,0x23,0xc1,0x66,0x6b,0xff,0xee,0xb5,0x08,0xa8,0x61,0x51,0x21,0xe0,0x01,0x0f,0xc1,0xce,0x0f}, + {0x44,0x1e,0xfe,0x49,0xa6,0x58,0x4d,0x64,0x7e,0x77,0xad,0x31,0xa2,0xae,0xfc,0x21,0xd2,0xd0,0x7f,0x88,0x5a,0x1c,0x44,0x02,0xf3,0x11,0xc5,0x83,0x71,0xaa,0x01,0x49,0x45,0x4e,0x24,0xc4,0x9d,0xd2,0xf2,0x3d,0x0a,0xde,0xd8,0x93,0x74,0x0e,0x02,0x2b,0x4d,0x21,0x0c,0x82,0x7e,0x06,0xc8,0x6c,0x0a,0xb9,0xea,0x6f,0x16,0x79,0x37,0x41,0xf0,0xf8,0x1a,0x8c,0x54,0xb7,0xb1,0x08,0xb4,0x99,0x62,0x24,0x7c,0x7a,0x0f,0xce,0x39,0xd9,0x06,0x1e,0xf9,0xb0,0x60,0xf7,0x13,0x12,0x6d,0x72,0x7b,0x88,0xbb,0x41}, + {0xbe,0x46,0x43,0x74,0x44,0x7d,0xe8,0x40,0x25,0x2b,0xb5,0x15,0xd4,0xda,0x48,0x1d,0x3e,0x60,0x3b,0xa1,0x18,0x8a,0x3a,0x7c,0xf7,0xbd,0xcd,0x2f,0xc1,0x28,0xb7,0x4e,0xae,0x91,0x66,0x7c,0x59,0x4c,0x23,0x7e,0xc8,0xb4,0x85,0x0a,0x3d,0x9d,0x88,0x64,0xe7,0xfa,0x4a,0x35,0x0c,0xc9,0xe2,0xda,0x1d,0x9e,0x6a,0x0c,0x07,0x1e,0x87,0x0a,0x89,0x89,0xbc,0x4b,0x99,0xb5,0x01,0x33,0x60,0x42,0xdd,0x5b,0x3a,0xae,0x6b,0x73,0x3c,0x9e,0xd5,0x19,0xe2,0xad,0x61,0x0d,0x64,0xd4,0x85,0x26,0x0f,0x30,0xe7,0x3e}, + {0xb7,0xd6,0x7d,0x9e,0xe4,0x55,0xd2,0xf5,0xac,0x1e,0x0b,0x61,0x5c,0x11,0x16,0x80,0xca,0x87,0xe1,0x92,0x5d,0x97,0x99,0x3c,0xc2,0x25,0x91,0x97,0x62,0x57,0x81,0x13,0x18,0x75,0x1e,0x84,0x47,0x79,0xfa,0x43,0xd7,0x46,0x9c,0x63,0x59,0xfa,0xc6,0xe5,0x74,0x2b,0x05,0xe3,0x1d,0x5e,0x06,0xa1,0x30,0x90,0xb8,0xcf,0xa2,0xc6,0x47,0x7d,0xe0,0xd6,0xf0,0x8e,0x14,0xd0,0xda,0x3f,0x3c,0x6f,0x54,0x91,0x9a,0x74,0x3e,0x9d,0x57,0x81,0xbb,0x26,0x10,0x62,0xec,0x71,0x80,0xec,0xc9,0x34,0x8d,0xf5,0x8c,0x14}, + {0x27,0xf0,0x34,0x79,0xf6,0x92,0xa4,0x46,0xa9,0x0a,0x84,0xf6,0xbe,0x84,0x99,0x46,0x54,0x18,0x61,0x89,0x2a,0xbc,0xa1,0x5c,0xd4,0xbb,0x5d,0xbd,0x1e,0xfa,0xf2,0x3f,0x6d,0x75,0xe4,0x9a,0x7d,0x2f,0x57,0xe2,0x7f,0x48,0xf3,0x88,0xbb,0x45,0xc3,0x56,0x8d,0xa8,0x60,0x69,0x6d,0x0b,0xd1,0x9f,0xb9,0xa1,0xae,0x4e,0xad,0xeb,0x8f,0x27,0x66,0x39,0x93,0x8c,0x1f,0x68,0xaa,0xb1,0x98,0x0c,0x29,0x20,0x9c,0x94,0x21,0x8c,0x52,0x3c,0x9d,0x21,0x91,0x52,0x11,0x39,0x7b,0x67,0x9c,0xfe,0x02,0xdd,0x04,0x41}, + {0x2a,0x42,0x24,0x11,0x5e,0xbf,0xb2,0x72,0xb5,0x3a,0xa3,0x98,0x33,0x0c,0xfa,0xa1,0x66,0xb6,0x52,0xfa,0x01,0x61,0xcb,0x94,0xd5,0x53,0xaf,0xaf,0x00,0x3b,0x86,0x2c,0xb8,0x6a,0x09,0xdb,0x06,0x4e,0x21,0x81,0x35,0x4f,0xe4,0x0c,0xc9,0xb6,0xa8,0x21,0xf5,0x2a,0x9e,0x40,0x2a,0xc1,0x24,0x65,0x81,0xa4,0xfc,0x8e,0xa4,0xb5,0x65,0x01,0x76,0x6a,0x84,0xa0,0x74,0xa4,0x90,0xf1,0xc0,0x7c,0x2f,0xcd,0x84,0xf9,0xef,0x12,0x8f,0x2b,0xaa,0x58,0x06,0x29,0x5e,0x69,0xb8,0xc8,0xfe,0xbf,0xd9,0x67,0x1b,0x59}, + {0xfa,0x9b,0xb4,0x80,0x1c,0x0d,0x2f,0x31,0x8a,0xec,0xf3,0xab,0x5e,0x51,0x79,0x59,0x88,0x1c,0xf0,0x9e,0xc0,0x33,0x70,0x72,0xcb,0x7b,0x8f,0xca,0xc7,0x2e,0xe0,0x3d,0x5d,0xb5,0x18,0x9f,0x71,0xb3,0xb9,0x99,0x1e,0x64,0x8c,0xa1,0xfa,0xe5,0x65,0xe4,0xed,0x05,0x9f,0xc2,0x36,0x11,0x08,0x61,0x8b,0x12,0x30,0x70,0x86,0x4f,0x9b,0x48,0xef,0x92,0xeb,0x3a,0x2d,0x10,0x32,0xd2,0x61,0xa8,0x16,0x61,0xb4,0x53,0x62,0xe1,0x24,0xaa,0x0b,0x19,0xe7,0xab,0x7e,0x3d,0xbf,0xbe,0x6c,0x49,0xba,0xfb,0xf5,0x49}, + {0xd4,0xcf,0x5b,0x8a,0x10,0x9a,0x94,0x30,0xeb,0x73,0x64,0xbc,0x70,0xdd,0x40,0xdc,0x1c,0x0d,0x7c,0x30,0xc1,0x94,0xc2,0x92,0x74,0x6e,0xfa,0xcb,0x6d,0xa8,0x04,0x56,0x2e,0x57,0x9c,0x1e,0x8c,0x62,0x5d,0x15,0x41,0x47,0x88,0xc5,0xac,0x86,0x4d,0x8a,0xeb,0x63,0x57,0x51,0xf6,0x52,0xa3,0x91,0x5b,0x51,0x67,0x88,0xc2,0xa6,0xa1,0x06,0xb6,0x64,0x17,0x7c,0xd4,0xd1,0x88,0x72,0x51,0x8b,0x41,0xe0,0x40,0x11,0x54,0x72,0xd1,0xf6,0xac,0x18,0x60,0x1a,0x03,0x9f,0xc6,0x42,0x27,0xfe,0x89,0x9e,0x98,0x20}, + {0x7f,0xcc,0x2d,0x3a,0xfd,0x77,0x97,0x49,0x92,0xd8,0x4f,0xa5,0x2c,0x7c,0x85,0x32,0xa0,0xe3,0x07,0xd2,0x64,0xd8,0x79,0xa2,0x29,0x7e,0xa6,0x0c,0x1d,0xed,0x03,0x04,0x2e,0xec,0xea,0x85,0x8b,0x27,0x74,0x16,0xdf,0x2b,0xcb,0x7a,0x07,0xdc,0x21,0x56,0x5a,0xf4,0xcb,0x61,0x16,0x4c,0x0a,0x64,0xd3,0x95,0x05,0xf7,0x50,0x99,0x0b,0x73,0x52,0xc5,0x4e,0x87,0x35,0x2d,0x4b,0xc9,0x8d,0x6f,0x24,0x98,0xcf,0xc8,0xe6,0xc5,0xce,0x35,0xc0,0x16,0xfa,0x46,0xcb,0xf7,0xcc,0x3d,0x30,0x08,0x43,0x45,0xd7,0x5b}, + {0xc2,0x4c,0xb2,0x28,0x95,0xd1,0x9a,0x7f,0x81,0xc1,0x35,0x63,0x65,0x54,0x6b,0x7f,0x36,0x72,0xc0,0x4f,0x6e,0xb6,0xb8,0x66,0x83,0xad,0x80,0x73,0x00,0x78,0x3a,0x13,0x2a,0x79,0xe7,0x15,0x21,0x93,0xc4,0x85,0xc9,0xdd,0xcd,0xbd,0xa2,0x89,0x4c,0xc6,0x62,0xd7,0xa3,0xad,0xa8,0x3d,0x1e,0x9d,0x2c,0xf8,0x67,0x30,0x12,0xdb,0xb7,0x5b,0xbe,0x62,0xca,0xc6,0x67,0xf4,0x61,0x09,0xee,0x52,0x19,0x21,0xd6,0x21,0xec,0x04,0x70,0x47,0xd5,0x9b,0x77,0x60,0x23,0x18,0xd2,0xe0,0xf0,0x58,0x6d,0xca,0x0d,0x74}, + {0x4e,0xce,0xcf,0x52,0x07,0xee,0x48,0xdf,0xb7,0x08,0xec,0x06,0xf3,0xfa,0xff,0xc3,0xc4,0x59,0x54,0xb9,0x2a,0x0b,0x71,0x05,0x8d,0xa3,0x3e,0x96,0xfa,0x25,0x1d,0x16,0x3c,0x43,0x78,0x04,0x57,0x8c,0x1a,0x23,0x9d,0x43,0x81,0xc2,0x0e,0x27,0xb5,0xb7,0x9f,0x07,0xd9,0xe3,0xea,0x99,0xaa,0xdb,0xd9,0x03,0x2b,0x6c,0x25,0xf5,0x03,0x2c,0x7d,0xa4,0x53,0x7b,0x75,0x18,0x0f,0x79,0x79,0x58,0x0c,0xcf,0x30,0x01,0x7b,0x30,0xf9,0xf7,0x7e,0x25,0x77,0x3d,0x90,0x31,0xaf,0xbb,0x96,0xbd,0xbd,0x68,0x94,0x69}, + {0xcf,0xfe,0xda,0xf4,0x46,0x2f,0x1f,0xbd,0xf7,0xd6,0x7f,0xa4,0x14,0x01,0xef,0x7c,0x7f,0xb3,0x47,0x4a,0xda,0xfd,0x1f,0xd3,0x85,0x57,0x90,0x73,0xa4,0x19,0x52,0x52,0x48,0x19,0xa9,0x6a,0xe6,0x3d,0xdd,0xd8,0xcc,0xd2,0xc0,0x2f,0xc2,0x64,0x50,0x48,0x2f,0xea,0xfd,0x34,0x66,0x24,0x48,0x9b,0x3a,0x2e,0x4a,0x6c,0x4e,0x1c,0x3e,0x29,0xe1,0x12,0x51,0x92,0x4b,0x13,0x6e,0x37,0xa0,0x5d,0xa1,0xdc,0xb5,0x78,0x37,0x70,0x11,0x31,0x1c,0x46,0xaf,0x89,0x45,0xb0,0x23,0x28,0x03,0x7f,0x44,0x5c,0x60,0x5b}, + {0x89,0x7c,0xc4,0x20,0x59,0x80,0x65,0xb9,0xcc,0x8f,0x3b,0x92,0x0c,0x10,0xf0,0xe7,0x77,0xef,0xe2,0x02,0x65,0x25,0x01,0x00,0xee,0xb3,0xae,0xa8,0xce,0x6d,0xa7,0x24,0x4c,0xf0,0xe7,0xf0,0xc6,0xfe,0xe9,0x3b,0x62,0x49,0xe3,0x75,0x9e,0x57,0x6a,0x86,0x1a,0xe6,0x1d,0x1e,0x16,0xef,0x42,0x55,0xd5,0xbd,0x5a,0xcc,0xf4,0xfe,0x12,0x2f,0x40,0xc7,0xc0,0xdf,0xb2,0x22,0x45,0x0a,0x07,0xa4,0xc9,0x40,0x7f,0x6e,0xd0,0x10,0x68,0xf6,0xcf,0x78,0x41,0x14,0xcf,0xc6,0x90,0x37,0xa4,0x18,0x25,0x7b,0x60,0x5e}, + {0x18,0x18,0xdf,0x6c,0x8f,0x1d,0xb3,0x58,0xa2,0x58,0x62,0xc3,0x4f,0xa7,0xcf,0x35,0x6e,0x1d,0xe6,0x66,0x4f,0xff,0xb3,0xe1,0xf7,0xd5,0xcd,0x6c,0xab,0xac,0x67,0x50,0x14,0xcf,0x96,0xa5,0x1c,0x43,0x2c,0xa0,0x00,0xe4,0xd3,0xae,0x40,0x2d,0xc4,0xe3,0xdb,0x26,0x0f,0x2e,0x80,0x26,0x45,0xd2,0x68,0x70,0x45,0x9e,0x13,0x33,0x1f,0x20,0x51,0x9d,0x03,0x08,0x6b,0x7f,0x52,0xfd,0x06,0x00,0x7c,0x01,0x64,0x49,0xb1,0x18,0xa8,0xa4,0x25,0x2e,0xb0,0x0e,0x22,0xd5,0x75,0x03,0x46,0x62,0x88,0xba,0x7c,0x39}, + {0xb2,0x59,0x59,0xf0,0x93,0x30,0xc1,0x30,0x76,0x79,0xa9,0xe9,0x8d,0xa1,0x3a,0xe2,0x26,0x5e,0x1d,0x72,0x91,0xd4,0x2f,0x22,0x3a,0x6c,0x6e,0x76,0x20,0xd3,0x39,0x23,0xe7,0x79,0x13,0xc8,0xfb,0xc3,0x15,0x78,0xf1,0x2a,0xe1,0xdd,0x20,0x94,0x61,0xa6,0xd5,0xfd,0xa8,0x85,0xf8,0xc0,0xa9,0xff,0x52,0xc2,0xe1,0xc1,0x22,0x40,0x1b,0x77,0xa7,0x2f,0x3a,0x51,0x86,0xd9,0x7d,0xd8,0x08,0xcf,0xd4,0xf9,0x71,0x9b,0xac,0xf5,0xb3,0x83,0xa2,0x1e,0x1b,0xc3,0x6b,0xd0,0x76,0x1a,0x97,0x19,0x92,0x18,0x1a,0x33}, + {0xc6,0x80,0x4f,0xfb,0x45,0x6f,0x16,0xf5,0xcf,0x75,0xc7,0x61,0xde,0xc7,0x36,0x9c,0x1c,0xd9,0x41,0x90,0x1b,0xe8,0xd4,0xe3,0x21,0xfe,0xbd,0x83,0x6b,0x7c,0x16,0x31,0xaf,0x72,0x75,0x9d,0x3a,0x2f,0x51,0x26,0x9e,0x4a,0x07,0x68,0x88,0xe2,0xcb,0x5b,0xc4,0xf7,0x80,0x11,0xc1,0xc1,0xed,0x84,0x7b,0xa6,0x49,0xf6,0x9f,0x61,0xc9,0x1a,0x68,0x10,0x4b,0x52,0x42,0x38,0x2b,0xf2,0x87,0xe9,0x9c,0xee,0x3b,0x34,0x68,0x50,0xc8,0x50,0x62,0x4a,0x84,0x71,0x9d,0xfc,0x11,0xb1,0x08,0x1f,0x34,0x36,0x24,0x61}, + {0x8d,0x89,0x4e,0x87,0xdb,0x41,0x9d,0xd9,0x20,0xdc,0x07,0x6c,0xf1,0xa5,0xfe,0x09,0xbc,0x9b,0x0f,0xd0,0x67,0x2c,0x3d,0x79,0x40,0xff,0x5e,0x9e,0x30,0xe2,0xeb,0x46,0x38,0x26,0x2d,0x1a,0xe3,0x49,0x63,0x8b,0x35,0xfd,0xd3,0x9b,0x00,0xb7,0xdf,0x9d,0xa4,0x6b,0xa0,0xa3,0xb8,0xf1,0x8b,0x7f,0x45,0x04,0xd9,0x78,0x31,0xaa,0x22,0x15,0x38,0x49,0x61,0x69,0x53,0x2f,0x38,0x2c,0x10,0x6d,0x2d,0xb7,0x9a,0x40,0xfe,0xda,0x27,0xf2,0x46,0xb6,0x91,0x33,0xc8,0xe8,0x6c,0x30,0x24,0x05,0xf5,0x70,0xfe,0x45}, + {0x8c,0x0b,0x0c,0x96,0xa6,0x75,0x48,0xda,0x20,0x2f,0x0e,0xef,0x76,0xd0,0x68,0x5b,0xd4,0x8f,0x0b,0x3d,0xcf,0x51,0xfb,0x07,0xd4,0x92,0xe3,0xa0,0x23,0x16,0x8d,0x42,0x91,0x14,0x95,0xc8,0x20,0x49,0xf2,0x62,0xa2,0x0c,0x63,0x3f,0xc8,0x07,0xf0,0x05,0xb8,0xd4,0xc9,0xf5,0xd2,0x45,0xbb,0x6f,0x45,0x22,0x7a,0xb5,0x6d,0x9f,0x61,0x16,0xfd,0x08,0xa3,0x01,0x44,0x4a,0x4f,0x08,0xac,0xca,0xa5,0x76,0xc3,0x19,0x22,0xa8,0x7d,0xbc,0xd1,0x43,0x46,0xde,0xb8,0xde,0xc6,0x38,0xbd,0x60,0x2d,0x59,0x81,0x1d}, + {0x5f,0xac,0x0d,0xa6,0x56,0x87,0x36,0x61,0x57,0xdc,0xab,0xeb,0x6a,0x2f,0xe0,0x17,0x7d,0x0f,0xce,0x4c,0x2d,0x3f,0x19,0x7f,0xf0,0xdc,0xec,0x89,0x77,0x4a,0x23,0x20,0xe8,0xc5,0x85,0x7b,0x9f,0xb6,0x65,0x87,0xb2,0xba,0x68,0xd1,0x8b,0x67,0xf0,0x6f,0x9b,0x0f,0x33,0x1d,0x7c,0xe7,0x70,0x3a,0x7c,0x8e,0xaf,0xb0,0x51,0x6d,0x5f,0x3a,0x52,0xb2,0x78,0x71,0xb6,0x0d,0xd2,0x76,0x60,0xd1,0x1e,0xd5,0xf9,0x34,0x1c,0x07,0x70,0x11,0xe4,0xb3,0x20,0x4a,0x2a,0xf6,0x66,0xe3,0xff,0x3c,0x35,0x82,0xd6,0x7c}, + {0xb6,0xfa,0x87,0xd8,0x5b,0xa4,0xe1,0x0b,0x6e,0x3b,0x40,0xba,0x32,0x6a,0x84,0x2a,0x00,0x60,0x6e,0xe9,0x12,0x10,0x92,0xd9,0x43,0x09,0xdc,0x3b,0x86,0xc8,0x38,0x28,0xf3,0xf4,0xac,0x68,0x60,0xcd,0x65,0xa6,0xd3,0xe3,0xd7,0x3c,0x18,0x2d,0xd9,0x42,0xd9,0x25,0x60,0x33,0x9d,0x38,0x59,0x57,0xff,0xd8,0x2c,0x2b,0x3b,0x25,0xf0,0x3e,0x30,0x50,0x46,0x4a,0xcf,0xb0,0x6b,0xd1,0xab,0x77,0xc5,0x15,0x41,0x6b,0x49,0xfa,0x9d,0x41,0xab,0xf4,0x8a,0xae,0xcf,0x82,0x12,0x28,0xa8,0x06,0xa6,0xb8,0xdc,0x21}, + {0xc8,0x9f,0x9d,0x8c,0x46,0x04,0x60,0x5c,0xcb,0xa3,0x2a,0xd4,0x6e,0x09,0x40,0x25,0x9c,0x2f,0xee,0x12,0x4c,0x4d,0x5b,0x12,0xab,0x1d,0xa3,0x94,0x81,0xd0,0xc3,0x0b,0xba,0x31,0x77,0xbe,0xfa,0x00,0x8d,0x9a,0x89,0x18,0x9e,0x62,0x7e,0x60,0x03,0x82,0x7f,0xd9,0xf3,0x43,0x37,0x02,0xcc,0xb2,0x8b,0x67,0x6f,0x6c,0xbf,0x0d,0x84,0x5d,0x8b,0xe1,0x9f,0x30,0x0d,0x38,0x6e,0x70,0xc7,0x65,0xe1,0xb9,0xa6,0x2d,0xb0,0x6e,0xab,0x20,0xae,0x7d,0x99,0xba,0xbb,0x57,0xdd,0x96,0xc1,0x2a,0x23,0x76,0x42,0x3a}, + {0xfa,0x84,0x70,0x8a,0x2c,0x43,0x42,0x4b,0x45,0xe5,0xb9,0xdf,0xe3,0x19,0x8a,0x89,0x5d,0xe4,0x58,0x9c,0x21,0x00,0x9f,0xbe,0xd1,0xeb,0x6d,0xa1,0xce,0x77,0xf1,0x1f,0xcb,0x7e,0x44,0xdb,0x72,0xc1,0xf8,0x3b,0xbd,0x2d,0x28,0xc6,0x1f,0xc4,0xcf,0x5f,0xfe,0x15,0xaa,0x75,0xc0,0xff,0xac,0x80,0xf9,0xa9,0xe1,0x24,0xe8,0xc9,0x70,0x07,0xfd,0xb5,0xb5,0x45,0x9a,0xd9,0x61,0xcf,0x24,0x79,0x3a,0x1b,0xe9,0x84,0x09,0x86,0x89,0x3e,0x3e,0x30,0x19,0x09,0x30,0xe7,0x1e,0x0b,0x50,0x41,0xfd,0x64,0xf2,0x39}, + {0x9c,0xe2,0xe7,0xdb,0x17,0x34,0xad,0xa7,0x9c,0x13,0x9c,0x2b,0x6a,0x37,0x94,0xbd,0xa9,0x7b,0x59,0x93,0x8e,0x1b,0xe9,0xa0,0x40,0x98,0x88,0x68,0x34,0xd7,0x12,0x17,0xe1,0x7b,0x09,0xfe,0xab,0x4a,0x9b,0xd1,0x29,0x19,0xe0,0xdf,0xe1,0xfc,0x6d,0xa4,0xff,0xf1,0xa6,0x2c,0x94,0x08,0xc9,0xc3,0x4e,0xf1,0x35,0x2c,0x27,0x21,0xc6,0x65,0xdd,0x93,0x31,0xce,0xf8,0x89,0x2b,0xe7,0xbb,0xc0,0x25,0xa1,0x56,0x33,0x10,0x4d,0x83,0xfe,0x1c,0x2e,0x3d,0xa9,0x19,0x04,0x72,0xe2,0x9c,0xb1,0x0a,0x80,0xf9,0x22}, + {0xcb,0xf8,0x9e,0x3e,0x8a,0x36,0x5a,0x60,0x15,0x47,0x50,0xa5,0x22,0xc0,0xe9,0xe3,0x8f,0x24,0x24,0x5f,0xb0,0x48,0x3d,0x55,0xe5,0x26,0x76,0x64,0xcd,0x16,0xf4,0x13,0xac,0xfd,0x6e,0x9a,0xdd,0x9f,0x02,0x42,0x41,0x49,0xa5,0x34,0xbe,0xce,0x12,0xb9,0x7b,0xf3,0xbd,0x87,0xb9,0x64,0x0f,0x64,0xb4,0xca,0x98,0x85,0xd3,0xa4,0x71,0x41,0x8c,0x4c,0xc9,0x99,0xaa,0x58,0x27,0xfa,0x07,0xb8,0x00,0xb0,0x6f,0x6f,0x00,0x23,0x92,0x53,0xda,0xad,0xdd,0x91,0xd2,0xfb,0xab,0xd1,0x4b,0x57,0xfa,0x14,0x82,0x50}, + {0x4b,0xfe,0xd6,0x3e,0x15,0x69,0x02,0xc2,0xc4,0x77,0x1d,0x51,0x39,0x67,0x5a,0xa6,0x94,0xaf,0x14,0x2c,0x46,0x26,0xde,0xcb,0x4b,0xa7,0xab,0x6f,0xec,0x60,0xf9,0x22,0xd6,0x03,0xd0,0x53,0xbb,0x15,0x1a,0x46,0x65,0xc9,0xf3,0xbc,0x88,0x28,0x10,0xb2,0x5a,0x3a,0x68,0x6c,0x75,0x76,0xc5,0x27,0x47,0xb4,0x6c,0xc8,0xa4,0x58,0x77,0x3a,0x76,0x50,0xae,0x93,0xf6,0x11,0x81,0x54,0xa6,0x54,0xfd,0x1d,0xdf,0x21,0xae,0x1d,0x65,0x5e,0x11,0xf3,0x90,0x8c,0x24,0x12,0x94,0xf4,0xe7,0x8d,0x5f,0xd1,0x9f,0x5d}, + {0x7f,0x72,0x63,0x6d,0xd3,0x08,0x14,0x03,0x33,0xb5,0xc7,0xd7,0xef,0x9a,0x37,0x6a,0x4b,0xe2,0xae,0xcc,0xc5,0x8f,0xe1,0xa9,0xd3,0xbe,0x8f,0x4f,0x91,0x35,0x2f,0x33,0x1e,0x52,0xd7,0xee,0x2a,0x4d,0x24,0x3f,0x15,0x96,0x2e,0x43,0x28,0x90,0x3a,0x8e,0xd4,0x16,0x9c,0x2e,0x77,0xba,0x64,0xe1,0xd8,0x98,0xeb,0x47,0xfa,0x87,0xc1,0x3b,0x0c,0xc2,0x86,0xea,0x15,0x01,0x47,0x6d,0x25,0xd1,0x46,0x6c,0xcb,0xb7,0x8a,0x99,0x88,0x01,0x66,0x3a,0xb5,0x32,0x78,0xd7,0x03,0xba,0x6f,0x90,0xce,0x81,0x0d,0x45}, + {0x75,0x52,0x20,0xa6,0xa1,0xb6,0x7b,0x6e,0x83,0x8e,0x3c,0x41,0xd7,0x21,0x4f,0xaa,0xb2,0x5c,0x8f,0xe8,0x55,0xd1,0x56,0x6f,0xe1,0x5b,0x34,0xa6,0x4b,0x5d,0xe2,0x2d,0x3f,0x74,0xae,0x1c,0x96,0xd8,0x74,0xd0,0xed,0x63,0x1c,0xee,0xf5,0x18,0x6d,0xf8,0x29,0xed,0xf4,0xe7,0x5b,0xc5,0xbd,0x97,0x08,0xb1,0x3a,0x66,0x79,0xd2,0xba,0x4c,0xcd,0x1f,0xd7,0xa0,0x24,0x90,0xd1,0x80,0xf8,0x8a,0x28,0xfb,0x0a,0xc2,0x25,0xc5,0x19,0x64,0x3a,0x5f,0x4b,0x97,0xa3,0xb1,0x33,0x72,0x00,0xe2,0xef,0xbc,0x7f,0x7d}, + {0x01,0x28,0x6b,0x26,0x6a,0x1e,0xef,0xfa,0x16,0x9f,0x73,0xd5,0xc4,0x68,0x6c,0x86,0x2c,0x76,0x03,0x1b,0xbc,0x2f,0x8a,0xf6,0x8d,0x5a,0xb7,0x87,0x5e,0x43,0x75,0x59,0x94,0x90,0xc2,0xf3,0xc5,0x5d,0x7c,0xcd,0xab,0x05,0x91,0x2a,0x9a,0xa2,0x81,0xc7,0x58,0x30,0x1c,0x42,0x36,0x1d,0xc6,0x80,0xd7,0xd4,0xd8,0xdc,0x96,0xd1,0x9c,0x4f,0x68,0x37,0x7b,0x6a,0xd8,0x97,0x92,0x19,0x63,0x7a,0xd1,0x1a,0x24,0x58,0xd0,0xd0,0x17,0x0c,0x1c,0x5c,0xad,0x9c,0x02,0xba,0x07,0x03,0x7a,0x38,0x84,0xd0,0xcd,0x7c}, + {0x17,0x04,0x26,0x6d,0x2c,0x42,0xa6,0xdc,0xbd,0x40,0x82,0x94,0x50,0x3d,0x15,0xae,0x77,0xc6,0x68,0xfb,0xb4,0xc1,0xc0,0xa9,0x53,0xcf,0xd0,0x61,0xed,0xd0,0x8b,0x42,0x93,0xcc,0x60,0x67,0x18,0x84,0x0c,0x9b,0x99,0x2a,0xb3,0x1a,0x7a,0x00,0xae,0xcd,0x18,0xda,0x0b,0x62,0x86,0xec,0x8d,0xa8,0x44,0xca,0x90,0x81,0x84,0xca,0x93,0x35,0xa7,0x9a,0x84,0x5e,0x9a,0x18,0x13,0x92,0xcd,0xfa,0xd8,0x65,0x35,0xc3,0xd8,0xd4,0xd1,0xbb,0xfd,0x53,0x5b,0x54,0x52,0x8c,0xe6,0x63,0x2d,0xda,0x08,0x83,0x39,0x27}, + {0x13,0xd4,0x5e,0x43,0x28,0x8d,0xc3,0x42,0xc9,0xcc,0x78,0x32,0x60,0xf3,0x50,0xbd,0xef,0x03,0xda,0x79,0x1a,0xab,0x07,0xbb,0x55,0x33,0x8c,0xbe,0xae,0x97,0x95,0x26,0x53,0x24,0x70,0x0a,0x4c,0x0e,0xa1,0xb9,0xde,0x1b,0x7d,0xd5,0x66,0x58,0xa2,0x0f,0xf7,0xda,0x27,0xcd,0xb5,0xd9,0xb9,0xff,0xfd,0x33,0x2c,0x49,0x45,0x29,0x2c,0x57,0xbe,0x30,0xcd,0xd6,0x45,0xc7,0x7f,0xc7,0xfb,0xae,0xba,0xe3,0xd3,0xe8,0xdf,0xe4,0x0c,0xda,0x5d,0xaa,0x30,0x88,0x2c,0xa2,0x80,0xca,0x5b,0xc0,0x98,0x54,0x98,0x7f}, + {0x17,0xe1,0x0b,0x9f,0x88,0xce,0x49,0x38,0x88,0xa2,0x54,0x7b,0x1b,0xad,0x05,0x80,0x1c,0x92,0xfc,0x23,0x9f,0xc3,0xa3,0x3d,0x04,0xf3,0x31,0x0a,0x47,0xec,0xc2,0x76,0x63,0x63,0xbf,0x0f,0x52,0x15,0x56,0xd3,0xa6,0xfb,0x4d,0xcf,0x45,0x5a,0x04,0x08,0xc2,0xa0,0x3f,0x87,0xbc,0x4f,0xc2,0xee,0xe7,0x12,0x9b,0xd6,0x3c,0x65,0xf2,0x30,0x85,0x0c,0xc1,0xaa,0x38,0xc9,0x08,0x8a,0xcb,0x6b,0x27,0xdb,0x60,0x9b,0x17,0x46,0x70,0xac,0x6f,0x0e,0x1e,0xc0,0x20,0xa9,0xda,0x73,0x64,0x59,0xf1,0x73,0x12,0x2f}, + {0x11,0x1e,0xe0,0x8a,0x7c,0xfc,0x39,0x47,0x9f,0xab,0x6a,0x4a,0x90,0x74,0x52,0xfd,0x2e,0x8f,0x72,0x87,0x82,0x8a,0xd9,0x41,0xf2,0x69,0x5b,0xd8,0x2a,0x57,0x9e,0x5d,0xc0,0x0b,0xa7,0x55,0xd7,0x8b,0x48,0x30,0xe7,0x42,0xd4,0xf1,0xa4,0xb5,0xd6,0x06,0x62,0x61,0x59,0xbc,0x9e,0xa6,0xd1,0xea,0x84,0xf7,0xc5,0xed,0x97,0x19,0xac,0x38,0x3b,0xb1,0x51,0xa7,0x17,0xb5,0x66,0x06,0x8c,0x85,0x9b,0x7e,0x86,0x06,0x7d,0x74,0x49,0xde,0x4d,0x45,0x11,0xc0,0xac,0xac,0x9c,0xe6,0xe9,0xbf,0x9c,0xcd,0xdf,0x22}, + {0xd9,0x0c,0x0d,0xc3,0xe0,0xd2,0xdb,0x8d,0x33,0x43,0xbb,0xac,0x5f,0x66,0x8e,0xad,0x1f,0x96,0x2a,0x32,0x8c,0x25,0x6b,0x8f,0xc7,0xc1,0x48,0x54,0xc0,0x16,0x29,0x6b,0xa1,0xe0,0x3b,0x10,0xb4,0x59,0xec,0x56,0x69,0xf9,0x59,0xd2,0xec,0xba,0xe3,0x2e,0x32,0xcd,0xf5,0x13,0x94,0xb2,0x7c,0x79,0x72,0xe4,0xcd,0x24,0x78,0x87,0xe9,0x0f,0x3b,0x91,0xba,0x0a,0xd1,0x34,0xdb,0x7e,0x0e,0xac,0x6d,0x2e,0x82,0xcd,0xa3,0x4e,0x15,0xf8,0x78,0x65,0xff,0x3d,0x08,0x66,0x17,0x0a,0xf0,0x7f,0x30,0x3f,0x30,0x4c}, + {0x85,0x8c,0xb2,0x17,0xd6,0x3b,0x0a,0xd3,0xea,0x3b,0x77,0x39,0xb7,0x77,0xd3,0xc5,0xbf,0x5c,0x6a,0x1e,0x8c,0xe7,0xc6,0xc6,0xc4,0xb7,0x2a,0x8b,0xf7,0xb8,0x61,0x0d,0x00,0x45,0xd9,0x0d,0x58,0x03,0xfc,0x29,0x93,0xec,0xbb,0x6f,0xa4,0x7a,0xd2,0xec,0xf8,0xa7,0xe2,0xc2,0x5f,0x15,0x0a,0x13,0xd5,0xa1,0x06,0xb7,0x1a,0x15,0x6b,0x41,0xb0,0x36,0xc1,0xe9,0xef,0xd7,0xa8,0x56,0x20,0x4b,0xe4,0x58,0xcd,0xe5,0x07,0xbd,0xab,0xe0,0x57,0x1b,0xda,0x2f,0xe6,0xaf,0xd2,0xe8,0x77,0x42,0xf7,0x2a,0x1a,0x19}, + {0x31,0x14,0x3c,0xc5,0x4b,0xf7,0x16,0xce,0xde,0xed,0x72,0x20,0xce,0x25,0x97,0x2b,0xe7,0x3e,0xb2,0xb5,0x6f,0xc3,0xb9,0xb8,0x08,0xc9,0x5c,0x0b,0x45,0x0e,0x2e,0x7e,0xfb,0x0e,0x46,0x4f,0x43,0x2b,0xe6,0x9f,0xd6,0x07,0x36,0xa6,0xd4,0x03,0xd3,0xde,0x24,0xda,0xa0,0xb7,0x0e,0x21,0x52,0xf0,0x93,0x5b,0x54,0x00,0xbe,0x7d,0x7e,0x23,0x30,0xb4,0x01,0x67,0xed,0x75,0x35,0x01,0x10,0xfd,0x0b,0x9f,0xe6,0x94,0x10,0x23,0x22,0x7f,0xe4,0x83,0x15,0x0f,0x32,0x75,0xe3,0x55,0x11,0xb1,0x99,0xa6,0xaf,0x71}, + {0x1d,0xb6,0x53,0x39,0x9b,0x6f,0xce,0x65,0xe6,0x41,0xa1,0xaf,0xea,0x39,0x58,0xc6,0xfe,0x59,0xf7,0xa9,0xfd,0x5f,0x43,0x0f,0x8e,0xc2,0xb1,0xc2,0xe9,0x42,0x11,0x02,0xd6,0x50,0x3b,0x47,0x1c,0x3c,0x42,0xea,0x10,0xef,0x38,0x3b,0x1f,0x7a,0xe8,0x51,0x95,0xbe,0xc9,0xb2,0x5f,0xbf,0x84,0x9b,0x1c,0x9a,0xf8,0x78,0xbc,0x1f,0x73,0x00,0x80,0x18,0xf8,0x48,0x18,0xc7,0x30,0xe4,0x19,0xc1,0xce,0x5e,0x22,0x0c,0x96,0xbf,0xe3,0x15,0xba,0x6b,0x83,0xe0,0xda,0xb6,0x08,0x58,0xe1,0x47,0x33,0x6f,0x4d,0x4c}, + {0xc9,0x1f,0x7d,0xc1,0xcf,0xec,0xf7,0x18,0x14,0x3c,0x40,0x51,0xa6,0xf5,0x75,0x6c,0xdf,0x0c,0xee,0xf7,0x2b,0x71,0xde,0xdb,0x22,0x7a,0xe4,0xa7,0xaa,0xdd,0x3f,0x19,0x70,0x19,0x8f,0x98,0xfc,0xdd,0x0c,0x2f,0x1b,0xf5,0xb9,0xb0,0x27,0x62,0x91,0x6b,0xbe,0x76,0x91,0x77,0xc4,0xb6,0xc7,0x6e,0xa8,0x9f,0x8f,0xa8,0x00,0x95,0xbf,0x38,0x6f,0x87,0xe8,0x37,0x3c,0xc9,0xd2,0x1f,0x2c,0x46,0xd1,0x18,0x5a,0x1e,0xf6,0xa2,0x76,0x12,0x24,0x39,0x82,0xf5,0x80,0x50,0x69,0x49,0x0d,0xbf,0x9e,0xb9,0x6f,0x6a}, + {0xeb,0x55,0x08,0x56,0xbb,0xc1,0x46,0x6a,0x9d,0xf0,0x93,0xf8,0x38,0xbb,0x16,0x24,0xc1,0xac,0x71,0x8f,0x37,0x11,0x1d,0xd7,0xea,0x96,0x18,0xa3,0x14,0x69,0xf7,0x75,0xc6,0x23,0xe4,0xb6,0xb5,0x22,0xb1,0xee,0x8e,0xff,0x86,0xf2,0x10,0x70,0x9d,0x93,0x8c,0x5d,0xcf,0x1d,0x83,0x2a,0xa9,0x90,0x10,0xeb,0xc5,0x42,0x9f,0xda,0x6f,0x13,0xd1,0xbd,0x05,0xa3,0xb1,0xdf,0x4c,0xf9,0x08,0x2c,0xf8,0x9f,0x9d,0x4b,0x36,0x0f,0x8a,0x58,0xbb,0xc3,0xa5,0xd8,0x87,0x2a,0xba,0xdc,0xe8,0x0b,0x51,0x83,0x21,0x02}, + {0x14,0x2d,0xad,0x5e,0x38,0x66,0xf7,0x4a,0x30,0x58,0x7c,0xca,0x80,0xd8,0x8e,0xa0,0x3d,0x1e,0x21,0x10,0xe6,0xa6,0x13,0x0d,0x03,0x6c,0x80,0x7b,0xe1,0x1c,0x07,0x6a,0x7f,0x7a,0x30,0x43,0x01,0x71,0x5a,0x9d,0x5f,0xa4,0x7d,0xc4,0x9e,0xde,0x63,0xb0,0xd3,0x7a,0x92,0xbe,0x52,0xfe,0xbb,0x22,0x6c,0x42,0x40,0xfd,0x41,0xc4,0x87,0x13,0xf8,0x8a,0x97,0x87,0xd1,0xc3,0xd3,0xb5,0x13,0x44,0x0e,0x7f,0x3d,0x5a,0x2b,0x72,0xa0,0x7c,0x47,0xbb,0x48,0x48,0x7b,0x0d,0x92,0xdc,0x1e,0xaf,0x6a,0xb2,0x71,0x31}, + {0xa8,0x4c,0x56,0x97,0x90,0x31,0x2f,0xa9,0x19,0xe1,0x75,0x22,0x4c,0xb8,0x7b,0xff,0x50,0x51,0x87,0xa4,0x37,0xfe,0x55,0x4f,0x5a,0x83,0xf0,0x3c,0x87,0xd4,0x1f,0x22,0xd1,0x47,0x8a,0xb2,0xd8,0xb7,0x0d,0xa6,0xf1,0xa4,0x70,0x17,0xd6,0x14,0xbf,0xa6,0x58,0xbd,0xdd,0x53,0x93,0xf8,0xa1,0xd4,0xe9,0x43,0x42,0x34,0x63,0x4a,0x51,0x6c,0x41,0x63,0x15,0x3a,0x4f,0x20,0x22,0x23,0x2d,0x03,0x0a,0xba,0xe9,0xe0,0x73,0xfb,0x0e,0x03,0x0f,0x41,0x4c,0xdd,0xe0,0xfc,0xaa,0x4a,0x92,0xfb,0x96,0xa5,0xda,0x48}, + {0xc7,0x9c,0xa5,0x5c,0x66,0x8e,0xca,0x6e,0xa0,0xac,0x38,0x2e,0x4b,0x25,0x47,0xa8,0xce,0x17,0x1e,0xd2,0x08,0xc7,0xaf,0x31,0xf7,0x4a,0xd8,0xca,0xfc,0xd6,0x6d,0x67,0x93,0x97,0x4c,0xc8,0x5d,0x1d,0xf6,0x14,0x06,0x82,0x41,0xef,0xe3,0xf9,0x41,0x99,0xac,0x77,0x62,0x34,0x8f,0xb8,0xf5,0xcd,0xa9,0x79,0x8a,0x0e,0xfa,0x37,0xc8,0x58,0x58,0x90,0xfc,0x96,0x85,0x68,0xf9,0x0c,0x1b,0xa0,0x56,0x7b,0xf3,0xbb,0xdc,0x1d,0x6a,0xd6,0x35,0x49,0x7d,0xe7,0xc2,0xdc,0x0a,0x7f,0xa5,0xc6,0xf2,0x73,0x4f,0x1c}, + {0xbb,0xa0,0x5f,0x30,0xbd,0x4f,0x7a,0x0e,0xad,0x63,0xc6,0x54,0xe0,0x4c,0x9d,0x82,0x48,0x38,0xe3,0x2f,0x83,0xc3,0x21,0xf4,0x42,0x4c,0xf6,0x1b,0x0d,0xc8,0x5a,0x79,0x84,0x34,0x7c,0xfc,0x6e,0x70,0x6e,0xb3,0x61,0xcf,0xc1,0xc3,0xb4,0xc9,0xdf,0x73,0xe5,0xc7,0x1c,0x78,0xc9,0x79,0x1d,0xeb,0x5c,0x67,0xaf,0x7d,0xdb,0x9a,0x45,0x70,0xb3,0x2b,0xb4,0x91,0x49,0xdb,0x91,0x1b,0xca,0xdc,0x02,0x4b,0x23,0x96,0x26,0x57,0xdc,0x78,0x8c,0x1f,0xe5,0x9e,0xdf,0x9f,0xd3,0x1f,0xe2,0x8c,0x84,0x62,0xe1,0x5f}, + {0x1a,0x96,0x94,0xe1,0x4f,0x21,0x59,0x4e,0x4f,0xcd,0x71,0x0d,0xc7,0x7d,0xbe,0x49,0x2d,0xf2,0x50,0x3b,0xd2,0xcf,0x00,0x93,0x32,0x72,0x91,0xfc,0x46,0xd4,0x89,0x47,0x08,0xb2,0x7c,0x5d,0x2d,0x85,0x79,0x28,0xe7,0xf2,0x7d,0x68,0x70,0xdd,0xde,0xb8,0x91,0x78,0x68,0x21,0xab,0xff,0x0b,0xdc,0x35,0xaa,0x7d,0x67,0x43,0xc0,0x44,0x2b,0x8e,0xb7,0x4e,0x07,0xab,0x87,0x1c,0x1a,0x67,0xf4,0xda,0x99,0x8e,0xd1,0xc6,0xfa,0x67,0x90,0x4f,0x48,0xcd,0xbb,0xac,0x3e,0xe4,0xa4,0xb9,0x2b,0xef,0x2e,0xc5,0x60}, + {0xf1,0x8b,0xfd,0x3b,0xbc,0x89,0x5d,0x0b,0x1a,0x55,0xf3,0xc9,0x37,0x92,0x6b,0xb0,0xf5,0x28,0x30,0xd5,0xb0,0x16,0x4c,0x0e,0xab,0xca,0xcf,0x2c,0x31,0x9c,0xbc,0x10,0x11,0x6d,0xae,0x7c,0xc2,0xc5,0x2b,0x70,0xab,0x8c,0xa4,0x54,0x9b,0x69,0xc7,0x44,0xb2,0x2e,0x49,0xba,0x56,0x40,0xbc,0xef,0x6d,0x67,0xb6,0xd9,0x48,0x72,0xd7,0x70,0x5b,0xa0,0xc2,0x3e,0x4b,0xe8,0x8a,0xaa,0xe0,0x81,0x17,0xed,0xf4,0x9e,0x69,0x98,0xd1,0x85,0x8e,0x70,0xe4,0x13,0x45,0x79,0x13,0xf4,0x76,0xa9,0xd3,0x5b,0x75,0x63}, + {0x53,0x08,0xd1,0x2a,0x3e,0xa0,0x5f,0xb5,0x69,0x35,0xe6,0x9e,0x90,0x75,0x6f,0x35,0x90,0xb8,0x69,0xbe,0xfd,0xf1,0xf9,0x9f,0x84,0x6f,0xc1,0x8b,0xc4,0xc1,0x8c,0x0d,0xb7,0xac,0xf1,0x97,0x18,0x10,0xc7,0x3d,0xd8,0xbb,0x65,0xc1,0x5e,0x7d,0xda,0x5d,0x0f,0x02,0xa1,0x0f,0x9c,0x5b,0x8e,0x50,0x56,0x2a,0xc5,0x37,0x17,0x75,0x63,0x27,0xa9,0x19,0xb4,0x6e,0xd3,0x02,0x94,0x02,0xa5,0x60,0xb4,0x77,0x7e,0x4e,0xb4,0xf0,0x56,0x49,0x3c,0xd4,0x30,0x62,0xa8,0xcf,0xe7,0x66,0xd1,0x7a,0x8a,0xdd,0xc2,0x70}, + {0x0e,0xec,0x6f,0x9f,0x50,0x94,0x61,0x65,0x8d,0x51,0xc6,0x46,0xa9,0x7e,0x2e,0xee,0x5c,0x9b,0xe0,0x67,0xf3,0xc1,0x33,0x97,0x95,0x84,0x94,0x63,0x63,0xac,0x0f,0x2e,0x13,0x7e,0xed,0xb8,0x7d,0x96,0xd4,0x91,0x7a,0x81,0x76,0xd7,0x0a,0x2f,0x25,0x74,0x64,0x25,0x85,0x0d,0xe0,0x82,0x09,0xe4,0xe5,0x3c,0xa5,0x16,0x38,0x61,0xb8,0x32,0x64,0xcd,0x48,0xe4,0xbe,0xf7,0xe7,0x79,0xd0,0x86,0x78,0x08,0x67,0x3a,0xc8,0x6a,0x2e,0xdb,0xe4,0xa0,0xd9,0xd4,0x9f,0xf8,0x41,0x4f,0x5a,0x73,0x5c,0x21,0x79,0x41}, + {0x2a,0xed,0xdc,0xd7,0xe7,0x94,0x70,0x8c,0x70,0x9c,0xd3,0x47,0xc3,0x8a,0xfb,0x97,0x02,0xd9,0x06,0xa9,0x33,0xe0,0x3b,0xe1,0x76,0x9d,0xd9,0x0c,0xa3,0x44,0x03,0x70,0x34,0xcd,0x6b,0x28,0xb9,0x33,0xae,0xe4,0xdc,0xd6,0x9d,0x55,0xb6,0x7e,0xef,0xb7,0x1f,0x8e,0xd3,0xb3,0x1f,0x14,0x8b,0x27,0x86,0xc2,0x41,0x22,0x66,0x85,0xfa,0x31,0xf4,0x22,0x36,0x2e,0x42,0x6c,0x82,0xaf,0x2d,0x50,0x33,0x98,0x87,0x29,0x20,0xc1,0x23,0x91,0x38,0x2b,0xe1,0xb7,0xc1,0x9b,0x89,0x24,0x95,0xa9,0x12,0x23,0xbb,0x24}, + {0xc3,0x67,0xde,0x32,0x17,0xed,0xa8,0xb1,0x48,0x49,0x1b,0x46,0x18,0x94,0xb4,0x3c,0xd2,0xbc,0xcf,0x76,0x43,0x43,0xbd,0x8e,0x08,0x80,0x18,0x1e,0x87,0x3e,0xee,0x0f,0x6b,0x5c,0xf8,0xf5,0x2a,0x0c,0xf8,0x41,0x94,0x67,0xfa,0x04,0xc3,0x84,0x72,0x68,0xad,0x1b,0xba,0xa3,0x99,0xdf,0x45,0x89,0x16,0x5d,0xeb,0xff,0xf9,0x2a,0x1d,0x0d,0xdf,0x1e,0x62,0x32,0xa1,0x8a,0xda,0xa9,0x79,0x65,0x22,0x59,0xa1,0x22,0xb8,0x30,0x93,0xc1,0x9a,0xa7,0x7b,0x19,0x04,0x40,0x76,0x1d,0x53,0x18,0x97,0xd7,0xac,0x16}, + {0x3d,0x1d,0x9b,0x2d,0xaf,0x72,0xdf,0x72,0x5a,0x24,0x32,0xa4,0x36,0x2a,0x46,0x63,0x37,0x96,0xb3,0x16,0x79,0xa0,0xce,0x3e,0x09,0x23,0x30,0xb9,0xf6,0x0e,0x3e,0x12,0xad,0xb6,0x87,0x78,0xc5,0xc6,0x59,0xc9,0xba,0xfe,0x90,0x5f,0xad,0x9e,0xe1,0x94,0x04,0xf5,0x42,0xa3,0x62,0x4e,0xe2,0x16,0x00,0x17,0x16,0x18,0x4b,0xd3,0x4e,0x16,0x9a,0xe6,0x2f,0x19,0x4c,0xd9,0x7e,0x48,0x13,0x15,0x91,0x3a,0xea,0x2c,0xae,0x61,0x27,0xde,0xa4,0xb9,0xd3,0xf6,0x7b,0x87,0xeb,0xf3,0x73,0x10,0xc6,0x0f,0xda,0x78}, + {0x6a,0xc6,0x2b,0xe5,0x28,0x5d,0xf1,0x5b,0x8e,0x1a,0xf0,0x70,0x18,0xe3,0x47,0x2c,0xdd,0x8b,0xc2,0x06,0xbc,0xaf,0x19,0x24,0x3a,0x17,0x6b,0x25,0xeb,0xde,0x25,0x2d,0x94,0x3a,0x0c,0x68,0xf1,0x80,0x9f,0xa2,0xe6,0xe7,0xe9,0x1a,0x15,0x7e,0xf7,0x71,0x73,0x79,0x01,0x48,0x58,0xf1,0x00,0x11,0xdd,0x8d,0xb3,0x16,0xb3,0xa4,0x4a,0x05,0xb8,0x7c,0x26,0x19,0x8d,0x46,0xc8,0xdf,0xaf,0x4d,0xe5,0x66,0x9c,0x78,0x28,0x0b,0x17,0xec,0x6e,0x66,0x2a,0x1d,0xeb,0x2a,0x60,0xa7,0x7d,0xab,0xa6,0x10,0x46,0x13}, + {0xfe,0xb0,0xf6,0x8d,0xc7,0x8e,0x13,0x51,0x1b,0xf5,0x75,0xe5,0x89,0xda,0x97,0x53,0xb9,0xf1,0x7a,0x71,0x1d,0x7a,0x20,0x09,0x50,0xd6,0x20,0x2b,0xba,0xfd,0x02,0x21,0x15,0xf5,0xd1,0x77,0xe7,0x65,0x2a,0xcd,0xf1,0x60,0xaa,0x8f,0x87,0x91,0x89,0x54,0xe5,0x06,0xbc,0xda,0xbc,0x3b,0xb7,0xb1,0xfb,0xc9,0x7c,0xa9,0xcb,0x78,0x48,0x65,0xa1,0xe6,0x5c,0x05,0x05,0xe4,0x9e,0x96,0x29,0xad,0x51,0x12,0x68,0xa7,0xbc,0x36,0x15,0xa4,0x7d,0xaa,0x17,0xf5,0x1a,0x3a,0xba,0xb2,0xec,0x29,0xdb,0x25,0xd7,0x0a}, + {0x57,0x24,0x4e,0x83,0xb1,0x67,0x42,0xdc,0xc5,0x1b,0xce,0x70,0xb5,0x44,0x75,0xb6,0xd7,0x5e,0xd1,0xf7,0x0b,0x7a,0xf0,0x1a,0x50,0x36,0xa0,0x71,0xfb,0xcf,0xef,0x4a,0x85,0x6f,0x05,0x9b,0x0c,0xbc,0xc7,0xfe,0xd7,0xff,0xf5,0xe7,0x68,0x52,0x7d,0x53,0xfa,0xae,0x12,0x43,0x62,0xc6,0xaf,0x77,0xd9,0x9f,0x39,0x02,0x53,0x5f,0x67,0x4f,0x1e,0x17,0x15,0x04,0x36,0x36,0x2d,0xc3,0x3b,0x48,0x98,0x89,0x11,0xef,0x2b,0xcd,0x10,0x51,0x94,0xd0,0xad,0x6e,0x0a,0x87,0x61,0x65,0xa8,0xa2,0x72,0xbb,0xcc,0x0b}, + {0xc8,0xa9,0xb1,0xea,0x2f,0x96,0x5e,0x18,0xcd,0x7d,0x14,0x65,0x35,0xe6,0xe7,0x86,0xf2,0x6d,0x5b,0xbb,0x31,0xe0,0x92,0xb0,0x3e,0xb7,0xd6,0x59,0xab,0xf0,0x24,0x40,0x96,0x12,0xfe,0x50,0x4c,0x5e,0x6d,0x18,0x7e,0x9f,0xe8,0xfe,0x82,0x7b,0x39,0xe0,0xb0,0x31,0x70,0x50,0xc5,0xf6,0xc7,0x3b,0xc2,0x37,0x8f,0x10,0x69,0xfd,0x78,0x66,0xc2,0x63,0x68,0x63,0x31,0xfa,0x86,0x15,0xf2,0x33,0x2d,0x57,0x48,0x8c,0xf6,0x07,0xfc,0xae,0x9e,0x78,0x9f,0xcc,0x73,0x4f,0x01,0x47,0xad,0x8e,0x10,0xe2,0x42,0x2d}, + {0x9b,0xd2,0xdf,0x94,0x15,0x13,0xf5,0x97,0x6a,0x4c,0x3f,0x31,0x5d,0x98,0x55,0x61,0x10,0x50,0x45,0x08,0x07,0x3f,0xa1,0xeb,0x22,0xd3,0xd2,0xb8,0x08,0x26,0x6b,0x67,0x93,0x75,0x53,0x0f,0x0d,0x7b,0x71,0x21,0x4c,0x06,0x1e,0x13,0x0b,0x69,0x4e,0x91,0x9f,0xe0,0x2a,0x75,0xae,0x87,0xb6,0x1b,0x6e,0x3c,0x42,0x9b,0xa7,0xf3,0x0b,0x42,0x47,0x2b,0x5b,0x1c,0x65,0xba,0x38,0x81,0x80,0x1b,0x1b,0x31,0xec,0xb6,0x71,0x86,0xb0,0x35,0x31,0xbc,0xb1,0x0c,0xff,0x7b,0xe0,0xf1,0x0c,0x9c,0xfa,0x2f,0x5d,0x74}, + {0xbd,0xc8,0xc9,0x2b,0x1e,0x5a,0x52,0xbf,0x81,0x9d,0x47,0x26,0x08,0x26,0x5b,0xea,0xdb,0x55,0x01,0xdf,0x0e,0xc7,0x11,0xd5,0xd0,0xf5,0x0c,0x96,0xeb,0x3c,0xe2,0x1a,0x6a,0x4e,0xd3,0x21,0x57,0xdf,0x36,0x60,0xd0,0xb3,0x7b,0x99,0x27,0x88,0xdb,0xb1,0xfa,0x6a,0x75,0xc8,0xc3,0x09,0xc2,0xd3,0x39,0xc8,0x1d,0x4c,0xe5,0x5b,0xe1,0x06,0x4a,0x99,0x32,0x19,0x87,0x5d,0x72,0x5b,0xb0,0xda,0xb1,0xce,0xb5,0x1c,0x35,0x32,0x05,0xca,0xb7,0xda,0x49,0x15,0xc4,0x7d,0xf7,0xc1,0x8e,0x27,0x61,0xd8,0xde,0x58}, + {0x5c,0xc5,0x66,0xf2,0x93,0x37,0x17,0xd8,0x49,0x4e,0x45,0xcc,0xc5,0x76,0xc9,0xc8,0xa8,0xc3,0x26,0xbc,0xf8,0x82,0xe3,0x5c,0xf9,0xf6,0x85,0x54,0xe8,0x9d,0xf3,0x2f,0xa8,0xc9,0xc2,0xb6,0xa8,0x5b,0xfb,0x2d,0x8c,0x59,0x2c,0xf5,0x8e,0xef,0xee,0x48,0x73,0x15,0x2d,0xf1,0x07,0x91,0x80,0x33,0xd8,0x5b,0x1d,0x53,0x6b,0x69,0xba,0x08,0x7a,0xc5,0xef,0xc3,0xee,0x3e,0xed,0x77,0x11,0x48,0xff,0xd4,0x17,0x55,0xe0,0x04,0xcb,0x71,0xa6,0xf1,0x3f,0x7a,0x3d,0xea,0x54,0xfe,0x7c,0x94,0xb4,0x33,0x06,0x12}, + {0x42,0x00,0x61,0x91,0x78,0x98,0x94,0x0b,0xe8,0xfa,0xeb,0xec,0x3c,0xb1,0xe7,0x4e,0xc0,0xa4,0xf0,0x94,0x95,0x73,0xbe,0x70,0x85,0x91,0xd5,0xb4,0x99,0x0a,0xd3,0x35,0x0a,0x10,0x12,0x49,0x47,0x31,0xbd,0x82,0x06,0xbe,0x6f,0x7e,0x6d,0x7b,0x23,0xde,0xc6,0x79,0xea,0x11,0x19,0x76,0x1e,0xe1,0xde,0x3b,0x39,0xcb,0xe3,0x3b,0x43,0x07,0xf4,0x97,0xe9,0x5c,0xc0,0x44,0x79,0xff,0xa3,0x51,0x5c,0xb0,0xe4,0x3d,0x5d,0x57,0x7c,0x84,0x76,0x5a,0xfd,0x81,0x33,0x58,0x9f,0xda,0xf6,0x7a,0xde,0x3e,0x87,0x2d}, + {0x09,0x34,0x37,0x43,0x64,0x31,0x7a,0x15,0xd9,0x81,0xaa,0xf4,0xee,0xb7,0xb8,0xfa,0x06,0x48,0xa6,0xf5,0xe6,0xfe,0x93,0xb0,0xb6,0xa7,0x7f,0x70,0x54,0x36,0x77,0x2e,0x81,0xf9,0x5d,0x4e,0xe1,0x02,0x62,0xaa,0xf5,0xe1,0x15,0x50,0x17,0x59,0x0d,0xa2,0x6c,0x1d,0xe2,0xba,0xd3,0x75,0xa2,0x18,0x53,0x02,0x60,0x01,0x8a,0x61,0x43,0x05,0xc1,0x23,0x4c,0x97,0xf4,0xbd,0xea,0x0d,0x93,0x46,0xce,0x9d,0x25,0x0a,0x6f,0xaa,0x2c,0xba,0x9a,0xa2,0xb8,0x2c,0x20,0x04,0x0d,0x96,0x07,0x2d,0x36,0x43,0x14,0x4b}, + {0x7a,0x1f,0x6e,0xb6,0xc7,0xb7,0xc4,0xcc,0x7e,0x2f,0x0c,0xf5,0x25,0x7e,0x15,0x44,0x1c,0xaf,0x3e,0x71,0xfc,0x6d,0xf0,0x3e,0xf7,0x63,0xda,0x52,0x67,0x44,0x2f,0x58,0xcb,0x9c,0x52,0x1c,0xe9,0x54,0x7c,0x96,0xfb,0x35,0xc6,0x64,0x92,0x26,0xf6,0x30,0x65,0x19,0x12,0x78,0xf4,0xaf,0x47,0x27,0x5c,0x6f,0xf6,0xea,0x18,0x84,0x03,0x17,0xe4,0x4c,0x32,0x20,0xd3,0x7b,0x31,0xc6,0xc4,0x8b,0x48,0xa4,0xe8,0x42,0x10,0xa8,0x64,0x13,0x5a,0x4e,0x8b,0xf1,0x1e,0xb2,0xc9,0x8d,0xa2,0xcd,0x4b,0x1c,0x2a,0x0c}, + {0x47,0x04,0x1f,0x6f,0xd0,0xc7,0x4d,0xd2,0x59,0xc0,0x87,0xdb,0x3e,0x9e,0x26,0xb2,0x8f,0xd2,0xb2,0xfb,0x72,0x02,0x5b,0xd1,0x77,0x48,0xf6,0xc6,0xd1,0x8b,0x55,0x7c,0x45,0x69,0xbd,0x69,0x48,0x81,0xc4,0xed,0x22,0x8d,0x1c,0xbe,0x7d,0x90,0x6d,0x0d,0xab,0xc5,0x5c,0xd5,0x12,0xd2,0x3b,0xc6,0x83,0xdc,0x14,0xa3,0x30,0x9b,0x6a,0x5a,0x3d,0x46,0x96,0xd3,0x24,0x15,0xec,0xd0,0xf0,0x24,0x5a,0xc3,0x8a,0x62,0xbb,0x12,0xa4,0x5f,0xbc,0x1c,0x79,0x3a,0x0c,0xa5,0xc3,0xaf,0xfb,0x0a,0xca,0xa5,0x04,0x04}, + {0xd6,0x43,0xa7,0x0a,0x07,0x40,0x1f,0x8c,0xe8,0x5e,0x26,0x5b,0xcb,0xd0,0xba,0xcc,0xde,0xd2,0x8f,0x66,0x6b,0x04,0x4b,0x57,0x33,0x96,0xdd,0xca,0xfd,0x5b,0x39,0x46,0xd1,0x6f,0x41,0x2a,0x1b,0x9e,0xbc,0x62,0x8b,0x59,0x50,0xe3,0x28,0xf7,0xc6,0xb5,0x67,0x69,0x5d,0x3d,0xd8,0x3f,0x34,0x04,0x98,0xee,0xf8,0xe7,0x16,0x75,0x52,0x39,0x9c,0x9a,0x5d,0x1a,0x2d,0xdb,0x7f,0x11,0x2a,0x5c,0x00,0xd1,0xbc,0x45,0x77,0x9c,0xea,0x6f,0xd5,0x54,0xf1,0xbe,0xd4,0xef,0x16,0xd0,0x22,0xe8,0x29,0x9a,0x57,0x76}, + {0x17,0x2a,0xc0,0x49,0x7e,0x8e,0xb6,0x45,0x7f,0xa3,0xa9,0xbc,0xa2,0x51,0xcd,0x23,0x1b,0x4c,0x22,0xec,0x11,0x5f,0xd6,0x3e,0xb1,0xbd,0x05,0x9e,0xdc,0x84,0xa3,0x43,0xf2,0x34,0xb4,0x52,0x13,0xb5,0x3c,0x33,0xe1,0x80,0xde,0x93,0x49,0x28,0x32,0xd8,0xce,0x35,0x0d,0x75,0x87,0x28,0x51,0xb5,0xc1,0x77,0x27,0x2a,0xbb,0x14,0xc5,0x02,0x45,0xb6,0xf1,0x8b,0xda,0xd5,0x4b,0x68,0x53,0x4b,0xb5,0xf6,0x7e,0xd3,0x8b,0xfb,0x53,0xd2,0xb0,0xa9,0xd7,0x16,0x39,0x31,0x59,0x80,0x54,0x61,0x09,0x92,0x60,0x11}, + {0xaa,0xcf,0xda,0x29,0x69,0x16,0x4d,0xb4,0x8f,0x59,0x13,0x84,0x4c,0x9f,0x52,0xda,0x59,0x55,0x3d,0x45,0xca,0x63,0xef,0xe9,0x0b,0x8e,0x69,0xc5,0x5b,0x12,0x1e,0x35,0xcd,0x4d,0x9b,0x36,0x16,0x56,0x38,0x7a,0x63,0x35,0x5c,0x65,0xa7,0x2c,0xc0,0x75,0x21,0x80,0xf1,0xd4,0xf9,0x1b,0xc2,0x7d,0x42,0xe0,0xe6,0x91,0x74,0x7d,0x63,0x2f,0xbe,0x7b,0xf6,0x1a,0x46,0x9b,0xb4,0xd4,0x61,0x89,0xab,0xc8,0x7a,0x03,0x03,0xd6,0xfb,0x99,0xa6,0xf9,0x9f,0xe1,0xde,0x71,0x9a,0x2a,0xce,0xe7,0x06,0x2d,0x18,0x7f}, + {0xec,0x68,0x01,0xab,0x64,0x8e,0x7c,0x7a,0x43,0xc5,0xed,0x15,0x55,0x4a,0x5a,0xcb,0xda,0x0e,0xcd,0x47,0xd3,0x19,0x55,0x09,0xb0,0x93,0x3e,0x34,0x8c,0xac,0xd4,0x67,0x22,0x75,0x21,0x8e,0x72,0x4b,0x45,0x09,0xd8,0xb8,0x84,0xd4,0xf4,0xe8,0x58,0xaa,0x3c,0x90,0x46,0x7f,0x4d,0x25,0x58,0xd3,0x17,0x52,0x1c,0x24,0x43,0xc0,0xac,0x44,0x77,0x57,0x7a,0x4f,0xbb,0x6b,0x7d,0x1c,0xe1,0x13,0x83,0x91,0xd4,0xfe,0x35,0x8b,0x84,0x46,0x6b,0xc9,0xc6,0xa1,0xdc,0x4a,0xbd,0x71,0xad,0x12,0x83,0x1c,0x6d,0x55}, + {0x82,0x39,0x8d,0x0c,0xe3,0x40,0xef,0x17,0x34,0xfa,0xa3,0x15,0x3e,0x07,0xf7,0x31,0x6e,0x64,0x73,0x07,0xcb,0xf3,0x21,0x4f,0xff,0x4e,0x82,0x1d,0x6d,0x6c,0x6c,0x74,0x21,0xe8,0x1b,0xb1,0x56,0x67,0xf0,0x81,0xdd,0xf3,0xa3,0x10,0x23,0xf8,0xaf,0x0f,0x5d,0x46,0x99,0x6a,0x55,0xd0,0xb2,0xf8,0x05,0x7f,0x8c,0xcc,0x38,0xbe,0x7a,0x09,0xa4,0x2d,0xa5,0x7e,0x87,0xc9,0x49,0x0c,0x43,0x1d,0xdc,0x9b,0x55,0x69,0x43,0x4c,0xd2,0xeb,0xcc,0xf7,0x09,0x38,0x2c,0x02,0xbd,0x84,0xee,0x4b,0xa3,0x14,0x7e,0x57}, + {0x0a,0x3b,0xa7,0x61,0xac,0x68,0xe2,0xf0,0xf5,0xa5,0x91,0x37,0x10,0xfa,0xfa,0xf2,0xe9,0x00,0x6d,0x6b,0x82,0x3e,0xe1,0xc1,0x42,0x8f,0xd7,0x6f,0xe9,0x7e,0xfa,0x60,0x2b,0xd7,0x4d,0xbd,0xbe,0xce,0xfe,0x94,0x11,0x22,0x0f,0x06,0xda,0x4f,0x6a,0xf4,0xff,0xd1,0xc8,0xc0,0x77,0x59,0x4a,0x12,0x95,0x92,0x00,0xfb,0xb8,0x04,0x53,0x70,0xc6,0x6e,0x29,0x4d,0x35,0x1d,0x3d,0xb6,0xd8,0x31,0xad,0x5f,0x3e,0x05,0xc3,0xf3,0xec,0x42,0xbd,0xb4,0x8c,0x95,0x0b,0x67,0xfd,0x53,0x63,0xa1,0x0c,0x8e,0x39,0x21}, + {0xf3,0x33,0x2b,0x38,0x8a,0x05,0xf5,0x89,0xb4,0xc0,0x48,0xad,0x0b,0xba,0xe2,0x5a,0x6e,0xb3,0x3d,0xa5,0x03,0xb5,0x93,0x8f,0xe6,0x32,0xa2,0x95,0x9d,0xed,0xa3,0x5a,0x01,0x56,0xb7,0xb4,0xf9,0xaa,0x98,0x27,0x72,0xad,0x8d,0x5c,0x13,0x72,0xac,0x5e,0x23,0xa0,0xb7,0x61,0x61,0xaa,0xce,0xd2,0x4e,0x7d,0x8f,0xe9,0x84,0xb2,0xbf,0x1b,0x61,0x65,0xd9,0xc7,0xe9,0x77,0x67,0x65,0x36,0x80,0xc7,0x72,0x54,0x12,0x2b,0xcb,0xee,0x6e,0x50,0xd9,0x99,0x32,0x05,0x65,0xcc,0x57,0x89,0x5e,0x4e,0xe1,0x07,0x4a}, + {0x99,0xf9,0x0d,0x98,0xcb,0x12,0xe4,0x4e,0x71,0xc7,0x6e,0x3c,0x6f,0xd7,0x15,0xa3,0xfd,0x77,0x5c,0x92,0xde,0xed,0xa5,0xbb,0x02,0x34,0x31,0x1d,0x39,0xac,0x0b,0x3f,0x9b,0xa4,0x77,0xc4,0xcd,0x58,0x0b,0x24,0x17,0xf0,0x47,0x64,0xde,0xda,0x38,0xfd,0xad,0x6a,0xc8,0xa7,0x32,0x8d,0x92,0x19,0x81,0xa0,0xaf,0x84,0xed,0x7a,0xaf,0x50,0xe5,0x5b,0xf6,0x15,0x01,0xde,0x4f,0x6e,0xb2,0x09,0x61,0x21,0x21,0x26,0x98,0x29,0xd9,0xd6,0xad,0x0b,0x81,0x05,0x02,0x78,0x06,0xd0,0xeb,0xba,0x16,0xa3,0x21,0x19}, + {0xfc,0x70,0xb8,0xdf,0x7e,0x2f,0x42,0x89,0xbd,0xb3,0x76,0x4f,0xeb,0x6b,0x29,0x2c,0xf7,0x4d,0xc2,0x36,0xd4,0xf1,0x38,0x07,0xb0,0xae,0x73,0xe2,0x41,0xdf,0x58,0x64,0x8b,0xc1,0xf3,0xd9,0x9a,0xad,0x5a,0xd7,0x9c,0xc1,0xb1,0x60,0xef,0x0e,0x6a,0x56,0xd9,0x0e,0x5c,0x25,0xac,0x0b,0x9a,0x3e,0xf5,0xc7,0x62,0xa0,0xec,0x9d,0x04,0x7b,0x83,0x44,0x44,0x35,0x7a,0xe3,0xcb,0xdc,0x93,0xbe,0xed,0x0f,0x33,0x79,0x88,0x75,0x87,0xdd,0xc5,0x12,0xc3,0x04,0x60,0x78,0x64,0x0e,0x95,0xc2,0xcb,0xdc,0x93,0x60}, + {0x6d,0x70,0xe0,0x85,0x85,0x9a,0xf3,0x1f,0x33,0x39,0xe7,0xb3,0xd8,0xa5,0xd0,0x36,0x3b,0x45,0x8f,0x71,0xe1,0xf2,0xb9,0x43,0x7c,0xa9,0x27,0x48,0x08,0xea,0xd1,0x57,0x4b,0x03,0x84,0x60,0xbe,0xee,0xde,0x6b,0x54,0xb8,0x0f,0x78,0xb6,0xc2,0x99,0x31,0x95,0x06,0x2d,0xb6,0xab,0x76,0x33,0x97,0x90,0x7d,0x64,0x8b,0xc9,0x80,0x31,0x6e,0x71,0xb0,0x28,0xa1,0xe7,0xb6,0x7a,0xee,0xaa,0x8b,0xa8,0x93,0x6d,0x59,0xc1,0xa4,0x30,0x61,0x21,0xb2,0x82,0xde,0xb4,0xf7,0x18,0xbd,0x97,0xdd,0x9d,0x99,0x3e,0x36}, + {0xc4,0x1f,0xee,0x35,0xc1,0x43,0xa8,0x96,0xcf,0xc8,0xe4,0x08,0x55,0xb3,0x6e,0x97,0x30,0xd3,0x8c,0xb5,0x01,0x68,0x2f,0xb4,0x2b,0x05,0x3a,0x69,0x78,0x9b,0xee,0x48,0xc6,0xae,0x4b,0xe2,0xdc,0x48,0x18,0x2f,0x60,0xaf,0xbc,0xba,0x55,0x72,0x9b,0x76,0x31,0xe9,0xef,0x3c,0x6e,0x3c,0xcb,0x90,0x55,0xb3,0xf9,0xc6,0x9b,0x97,0x1f,0x23,0xc6,0xf3,0x2a,0xcc,0x4b,0xde,0x31,0x5c,0x1f,0x8d,0x20,0xfe,0x30,0xb0,0x4b,0xb0,0x66,0xb4,0x4f,0xc1,0x09,0x70,0x8d,0xb7,0x13,0x24,0x79,0x08,0x9b,0xfa,0x9b,0x07}, + {0xf4,0x0d,0x30,0xda,0x51,0x3a,0x90,0xe3,0xb0,0x5a,0xa9,0x3d,0x23,0x64,0x39,0x84,0x80,0x64,0x35,0x0b,0x2d,0xf1,0x3c,0xed,0x94,0x71,0x81,0x84,0xf6,0x77,0x8c,0x03,0x45,0x42,0xd5,0xa2,0x80,0xed,0xc9,0xf3,0x52,0x39,0xf6,0x77,0x78,0x8b,0xa0,0x0a,0x75,0x54,0x08,0xd1,0x63,0xac,0x6d,0xd7,0x6b,0x63,0x70,0x94,0x15,0xfb,0xf4,0x1e,0xec,0x7b,0x16,0x5b,0xe6,0x5e,0x4e,0x85,0xc2,0xcd,0xd0,0x96,0x42,0x0a,0x59,0x59,0x99,0x21,0x10,0x98,0x34,0xdf,0xb2,0x72,0x56,0xff,0x0b,0x4a,0x2a,0xe9,0x5e,0x57}, + {0xcf,0x2f,0x18,0x8a,0x90,0x80,0xc0,0xd4,0xbd,0x9d,0x48,0x99,0xc2,0x70,0xe1,0x30,0xde,0x33,0xf7,0x52,0x57,0xbd,0xba,0x05,0x00,0xfd,0xd3,0x2c,0x11,0xe7,0xd4,0x43,0x01,0xd8,0xa4,0x0a,0x45,0xbc,0x46,0x5d,0xd8,0xb9,0x33,0xa5,0x27,0x12,0xaf,0xc3,0xc2,0x06,0x89,0x2b,0x26,0x3b,0x9e,0x38,0x1b,0x58,0x2f,0x38,0x7e,0x1e,0x0a,0x20,0xc5,0x3a,0xf9,0xea,0x67,0xb9,0x8d,0x51,0xc0,0x52,0x66,0x05,0x9b,0x98,0xbc,0x71,0xf5,0x97,0x71,0x56,0xd9,0x85,0x2b,0xfe,0x38,0x4e,0x1e,0x65,0x52,0xca,0x0e,0x05}, + {0x9c,0x0c,0x3f,0x45,0xde,0x1a,0x43,0xc3,0x9b,0x3b,0x70,0xff,0x5e,0x04,0xf5,0xe9,0x3d,0x7b,0x84,0xed,0xc9,0x7a,0xd9,0xfc,0xc6,0xf4,0x58,0x1c,0xc2,0xe6,0x0e,0x4b,0xea,0x68,0xe6,0x60,0x76,0x39,0xac,0x97,0x97,0xb4,0x3a,0x15,0xfe,0xbb,0x19,0x9b,0x9f,0xa7,0xec,0x34,0xb5,0x79,0xb1,0x4c,0x57,0xae,0x31,0xa1,0x9f,0xc0,0x51,0x61,0x96,0x5d,0xf0,0xfd,0x0d,0x5c,0xf5,0x3a,0x7a,0xee,0xb4,0x2a,0xe0,0x2e,0x26,0xdd,0x09,0x17,0x17,0x12,0x87,0xbb,0xb2,0x11,0x0b,0x03,0x0f,0x80,0xfa,0x24,0xef,0x1f}, + {0x96,0x31,0xa7,0x1a,0xfb,0x53,0xd6,0x37,0x18,0x64,0xd7,0x3f,0x30,0x95,0x94,0x0f,0xb2,0x17,0x3a,0xfb,0x09,0x0b,0x20,0xad,0x3e,0x61,0xc8,0x2f,0x29,0x49,0x4d,0x54,0x86,0x6b,0x97,0x30,0xf5,0xaf,0xd2,0x22,0x04,0x46,0xd2,0xc2,0x06,0xb8,0x90,0x8d,0xe5,0xba,0xe5,0x4d,0x6c,0x89,0xa1,0xdc,0x17,0x0c,0x34,0xc8,0xe6,0x5f,0x00,0x28,0x88,0x86,0x52,0x34,0x9f,0xba,0xef,0x6a,0xa1,0x7d,0x10,0x25,0x94,0xff,0x1b,0x5c,0x36,0x4b,0xd9,0x66,0xcd,0xbb,0x5b,0xf7,0xfa,0x6d,0x31,0x0f,0x93,0x72,0xe4,0x72}, + {0x4f,0x08,0x81,0x97,0x8c,0x20,0x95,0x26,0xe1,0x0e,0x45,0x23,0x0b,0x2a,0x50,0xb1,0x02,0xde,0xef,0x03,0xa6,0xae,0x9d,0xfd,0x4c,0xa3,0x33,0x27,0x8c,0x2e,0x9d,0x5a,0x27,0x76,0x2a,0xd3,0x35,0xf6,0xf3,0x07,0xf0,0x66,0x65,0x5f,0x86,0x4d,0xaa,0x7a,0x50,0x44,0xd0,0x28,0x97,0xe7,0x85,0x3c,0x38,0x64,0xe0,0x0f,0x00,0x7f,0xee,0x1f,0xe5,0xf7,0xdb,0x03,0xda,0x05,0x53,0x76,0xbd,0xcd,0x34,0x14,0x49,0xf2,0xda,0xa4,0xec,0x88,0x4a,0xd2,0xcd,0xd5,0x4a,0x7b,0x43,0x05,0x04,0xee,0x51,0x40,0xf9,0x00}, + {0xb2,0x30,0xd3,0xc3,0x23,0x6b,0x35,0x8d,0x06,0x1b,0x47,0xb0,0x9b,0x8b,0x1c,0xf2,0x3c,0xb8,0x42,0x6e,0x6c,0x31,0x6c,0xb3,0x0d,0xb1,0xea,0x8b,0x7e,0x9c,0xd7,0x07,0x53,0x97,0xaf,0x07,0xbb,0x93,0xef,0xd7,0xa7,0x66,0xb7,0x3d,0xcf,0xd0,0x3e,0x58,0xc5,0x1e,0x0b,0x6e,0xbf,0x98,0x69,0xce,0x52,0x04,0xd4,0x5d,0xd2,0xff,0xb7,0x47,0x12,0xdd,0x08,0xbc,0x9c,0xfb,0xfb,0x87,0x9b,0xc2,0xee,0xe1,0x3a,0x6b,0x06,0x8a,0xbf,0xc1,0x1f,0xdb,0x2b,0x24,0x57,0x0d,0xb6,0x4b,0xa6,0x5e,0xa3,0x20,0x35,0x1c}, + {0x4a,0xa3,0xcb,0xbc,0xa6,0x53,0xd2,0x80,0x9b,0x21,0x38,0x38,0xa1,0xc3,0x61,0x3e,0x96,0xe3,0x82,0x98,0x01,0xb6,0xc3,0x90,0x6f,0xe6,0x0e,0x5d,0x77,0x05,0x3d,0x1c,0x59,0xc0,0x6b,0x21,0x40,0x6f,0xa8,0xcd,0x7e,0xd8,0xbc,0x12,0x1d,0x23,0xbb,0x1f,0x90,0x09,0xc7,0x17,0x9e,0x6a,0x95,0xb4,0x55,0x2e,0xd1,0x66,0x3b,0x0c,0x75,0x38,0x1a,0xe5,0x22,0x94,0x40,0xf1,0x2e,0x69,0x71,0xf6,0x5d,0x2b,0x3c,0xc7,0xc0,0xcb,0x29,0xe0,0x4c,0x74,0xe7,0x4f,0x01,0x21,0x7c,0x48,0x30,0xd3,0xc7,0xe2,0x21,0x06}, + {0x8d,0x83,0x59,0x82,0xcc,0x60,0x98,0xaf,0xdc,0x9a,0x9f,0xc6,0xc1,0x48,0xea,0x90,0x30,0x1e,0x58,0x65,0x37,0x48,0x26,0x65,0xbc,0xa5,0xd3,0x7b,0x09,0xd6,0x07,0x00,0xf3,0xf0,0xdb,0xb0,0x96,0x17,0xae,0xb7,0x96,0xe1,0x7c,0xe1,0xb9,0xaf,0xdf,0x54,0xb4,0xa3,0xaa,0xe9,0x71,0x30,0x92,0x25,0x9d,0x2e,0x00,0xa1,0x9c,0x58,0x8e,0x5d,0x4b,0xa9,0x42,0x08,0x95,0x1d,0xbf,0xc0,0x3e,0x2e,0x8f,0x58,0x63,0xc3,0xd3,0xb2,0xef,0xe2,0x51,0xbb,0x38,0x14,0x96,0x0a,0x86,0xbf,0x1c,0x3c,0x78,0xd7,0x83,0x15}, + {0xe1,0x7a,0xa2,0x5d,0xef,0xa2,0xee,0xec,0x74,0x01,0x67,0x55,0x14,0x3a,0x7c,0x59,0x7a,0x16,0x09,0x66,0x12,0x2a,0xa6,0xc9,0x70,0x8f,0xed,0x81,0x2e,0x5f,0x2a,0x25,0xc7,0x28,0x9d,0xcc,0x04,0x47,0x03,0x90,0x8f,0xc5,0x2c,0xf7,0x9e,0x67,0x1b,0x1d,0x26,0x87,0x5b,0xbe,0x5f,0x2b,0xe1,0x16,0x0a,0x58,0xc5,0x83,0x4e,0x06,0x58,0x49,0x0d,0xe8,0x66,0x50,0x26,0x94,0x28,0x0d,0x6b,0x8c,0x7c,0x30,0x85,0xf7,0xc3,0xfc,0xfd,0x12,0x11,0x0c,0x78,0xda,0x53,0x1b,0x88,0xb3,0x43,0xd8,0x0b,0x17,0x9c,0x07}, + {0xff,0x6f,0xfa,0x64,0xe4,0xec,0x06,0x05,0x23,0xe5,0x05,0x62,0x1e,0x43,0xe3,0xbe,0x42,0xea,0xb8,0x51,0x24,0x42,0x79,0x35,0x00,0xfb,0xc9,0x4a,0xe3,0x05,0xec,0x6d,0x56,0xd0,0xd5,0xc0,0x50,0xcd,0xd6,0xcd,0x3b,0x57,0x03,0xbb,0x6d,0x68,0xf7,0x9a,0x48,0xef,0xc3,0xf3,0x3f,0x72,0xa6,0x3c,0xcc,0x8a,0x7b,0x31,0xd7,0xc0,0x68,0x67,0xb3,0xc1,0x55,0xf1,0xe5,0x25,0xb6,0x94,0x91,0x7b,0x7b,0x99,0xa7,0xf3,0x7b,0x41,0x00,0x26,0x6b,0x6d,0xdc,0xbd,0x2c,0xc2,0xf4,0x52,0xcd,0xdd,0x14,0x5e,0x44,0x51}, + {0x51,0x49,0x14,0x3b,0x4b,0x2b,0x50,0x57,0xb3,0xbc,0x4b,0x44,0x6b,0xff,0x67,0x8e,0xdb,0x85,0x63,0x16,0x27,0x69,0xbd,0xb8,0xc8,0x95,0x92,0xe3,0x31,0x6f,0x18,0x13,0x55,0xa4,0xbe,0x2b,0xab,0x47,0x31,0x89,0x29,0x91,0x07,0x92,0x4f,0xa2,0x53,0x8c,0xa7,0xf7,0x30,0xbe,0x48,0xf9,0x49,0x4b,0x3d,0xd4,0x4f,0x6e,0x08,0x90,0xe9,0x12,0x2e,0xbb,0xdf,0x7f,0xb3,0x96,0x0c,0xf1,0xf9,0xea,0x1c,0x12,0x5e,0x93,0x9a,0x9f,0x3f,0x98,0x5b,0x3a,0xc4,0x36,0x11,0xdf,0xaf,0x99,0x3e,0x5d,0xf0,0xe3,0xb2,0x77}, + {0xde,0xc4,0x2e,0x9c,0xc5,0xa9,0x6f,0x29,0xcb,0xf3,0x84,0x4f,0xbf,0x61,0x8b,0xbc,0x08,0xf9,0xa8,0x17,0xd9,0x06,0x77,0x1c,0x5d,0x25,0xd3,0x7a,0xfc,0x95,0xb7,0x63,0xa4,0xb0,0xdd,0x12,0x9c,0x63,0x98,0xd5,0x6b,0x86,0x24,0xc0,0x30,0x9f,0xd1,0xa5,0x60,0xe4,0xfc,0x58,0x03,0x2f,0x7c,0xd1,0x8a,0x5e,0x09,0x2e,0x15,0x95,0xa1,0x07,0xc8,0x5f,0x9e,0x38,0x02,0x8f,0x36,0xa8,0x3b,0xe4,0x8d,0xcf,0x02,0x3b,0x43,0x90,0x43,0x26,0x41,0xc5,0x5d,0xfd,0xa1,0xaf,0x37,0x01,0x2f,0x03,0x3d,0xe8,0x8f,0x3e}, + {0x94,0xa2,0x70,0x05,0xb9,0x15,0x8b,0x2f,0x49,0x45,0x08,0x67,0x70,0x42,0xf2,0x94,0x84,0xfd,0xbb,0x61,0xe1,0x5a,0x1c,0xde,0x07,0x40,0xac,0x7f,0x79,0x3b,0xba,0x75,0x3c,0xd1,0xef,0xe8,0x8d,0x4c,0x70,0x08,0x31,0x37,0xe0,0x33,0x8e,0x1a,0xc5,0xdf,0xe3,0xcd,0x60,0x12,0xa5,0x5d,0x9d,0xa5,0x86,0x8c,0x25,0xa6,0x99,0x08,0xd6,0x22,0x96,0xd1,0xcd,0x70,0xc0,0xdb,0x39,0x62,0x9a,0x8a,0x7d,0x6c,0x8b,0x8a,0xfe,0x60,0x60,0x12,0x40,0xeb,0xbc,0x47,0x88,0xb3,0x5e,0x9e,0x77,0x87,0x7b,0xd0,0x04,0x09}, + {0x9c,0x91,0xba,0xdd,0xd4,0x1f,0xce,0xb4,0xaa,0x8d,0x4c,0xc7,0x3e,0xdb,0x31,0xcf,0x51,0xcc,0x86,0xad,0x63,0xcc,0x63,0x2c,0x07,0xde,0x1d,0xbc,0x3f,0x14,0xe2,0x43,0xb9,0x40,0xf9,0x48,0x66,0x2d,0x32,0xf4,0x39,0x0c,0x2d,0xbd,0x0c,0x2f,0x95,0x06,0x31,0xf9,0x81,0xa0,0xad,0x97,0x76,0x16,0x6c,0x2a,0xf7,0xba,0xce,0xaa,0x40,0x62,0xa0,0x95,0xa2,0x5b,0x9c,0x74,0x34,0xf8,0x5a,0xd2,0x37,0xca,0x5b,0x7c,0x94,0xd6,0x6a,0x31,0xc9,0xe7,0xa7,0x3b,0xf1,0x66,0xac,0x0c,0xb4,0x8d,0x23,0xaf,0xbd,0x56}, + {0xeb,0x33,0x35,0xf5,0xe3,0xb9,0x2a,0x36,0x40,0x3d,0xb9,0x6e,0xd5,0x68,0x85,0x33,0x72,0x55,0x5a,0x1d,0x52,0x14,0x0e,0x9e,0x18,0x13,0x74,0x83,0x6d,0xa8,0x24,0x1d,0xb2,0x3b,0x9d,0xc1,0x6c,0xd3,0x10,0x13,0xb9,0x86,0x23,0x62,0xb7,0x6b,0x2a,0x06,0x5c,0x4f,0xa1,0xd7,0x91,0x85,0x9b,0x7c,0x54,0x57,0x1e,0x7e,0x50,0x31,0xaa,0x03,0x1f,0xce,0xd4,0xff,0x48,0x76,0xec,0xf4,0x1c,0x8c,0xac,0x54,0xf0,0xea,0x45,0xe0,0x7c,0x35,0x09,0x1d,0x82,0x25,0xd2,0x88,0x59,0x48,0xeb,0x9a,0xdc,0x61,0xb2,0x43}, + {0xbb,0x79,0xbb,0x88,0x19,0x1e,0x5b,0xe5,0x9d,0x35,0x7a,0xc1,0x7d,0xd0,0x9e,0xa0,0x33,0xea,0x3d,0x60,0xe2,0x2e,0x2c,0xb0,0xc2,0x6b,0x27,0x5b,0xcf,0x55,0x60,0x32,0x64,0x13,0x95,0x6c,0x8b,0x3d,0x51,0x19,0x7b,0xf4,0x0b,0x00,0x26,0x71,0xfe,0x94,0x67,0x95,0x4f,0xd5,0xdd,0x10,0x8d,0x02,0x64,0x09,0x94,0x42,0xe2,0xd5,0xb4,0x02,0xf2,0x8d,0xd1,0x28,0xcb,0x55,0xa1,0xb4,0x08,0xe5,0x6c,0x18,0x46,0x46,0xcc,0xea,0x89,0x43,0x82,0x6c,0x93,0xf4,0x9c,0xc4,0x10,0x34,0x5d,0xae,0x09,0xc8,0xa6,0x27}, + {0x88,0xb1,0x0d,0x1f,0xcd,0xeb,0xa6,0x8b,0xe8,0x5b,0x5a,0x67,0x3a,0xd7,0xd3,0x37,0x5a,0x58,0xf5,0x15,0xa3,0xdf,0x2e,0xf2,0x7e,0xa1,0x60,0xff,0x74,0x71,0xb6,0x2c,0x54,0x69,0x3d,0xc4,0x0a,0x27,0x2c,0xcd,0xb2,0xca,0x66,0x6a,0x57,0x3e,0x4a,0xdd,0x6c,0x03,0xd7,0x69,0x24,0x59,0xfa,0x79,0x99,0x25,0x8c,0x3d,0x60,0x03,0x15,0x22,0xd0,0xe1,0x0b,0x39,0xf9,0xcd,0xee,0x59,0xf1,0xe3,0x8c,0x72,0x44,0x20,0x42,0xa9,0xf4,0xf0,0x94,0x7a,0x66,0x1c,0x89,0x82,0x36,0xf4,0x90,0x38,0xb7,0xf4,0x1d,0x7b}, + {0x24,0xa2,0xb2,0xb3,0xe0,0xf2,0x92,0xe4,0x60,0x11,0x55,0x2b,0x06,0x9e,0x6c,0x7c,0x0e,0x7b,0x7f,0x0d,0xe2,0x8f,0xeb,0x15,0x92,0x59,0xfc,0x58,0x26,0xef,0xfc,0x61,0x8c,0xf5,0xf8,0x07,0x18,0x22,0x2e,0x5f,0xd4,0x09,0x94,0xd4,0x9f,0x5c,0x55,0xe3,0x30,0xa6,0xb6,0x1f,0x8d,0xa8,0xaa,0xb2,0x3d,0xe0,0x52,0xd3,0x45,0x82,0x69,0x68,0x7a,0x18,0x18,0x2a,0x85,0x5d,0xb1,0xdb,0xd7,0xac,0xdd,0x86,0xd3,0xaa,0xe4,0xf3,0x82,0xc4,0xf6,0x0f,0x81,0xe2,0xba,0x44,0xcf,0x01,0xaf,0x3d,0x47,0x4c,0xcf,0x46}, + {0xf9,0xe5,0xc4,0x9e,0xed,0x25,0x65,0x42,0x03,0x33,0x90,0x16,0x01,0xda,0x5e,0x0e,0xdc,0xca,0xe5,0xcb,0xf2,0xa7,0xb1,0x72,0x40,0x5f,0xeb,0x14,0xcd,0x7b,0x38,0x29,0x40,0x81,0x49,0xf1,0xa7,0x6e,0x3c,0x21,0x54,0x48,0x2b,0x39,0xf8,0x7e,0x1e,0x7c,0xba,0xce,0x29,0x56,0x8c,0xc3,0x88,0x24,0xbb,0xc5,0x8c,0x0d,0xe5,0xaa,0x65,0x10,0x57,0x0d,0x20,0xdf,0x25,0x45,0x2c,0x1c,0x4a,0x67,0xca,0xbf,0xd6,0x2d,0x3b,0x5c,0x30,0x40,0x83,0xe1,0xb1,0xe7,0x07,0x0a,0x16,0xe7,0x1c,0x4f,0xe6,0x98,0xa1,0x69}, + {0xbc,0x78,0x1a,0xd9,0xe0,0xb2,0x62,0x90,0x67,0x96,0x50,0xc8,0x9c,0x88,0xc9,0x47,0xb8,0x70,0x50,0x40,0x66,0x4a,0xf5,0x9d,0xbf,0xa1,0x93,0x24,0xa9,0xe6,0x69,0x73,0xed,0xca,0xc5,0xdc,0x34,0x44,0x01,0xe1,0x33,0xfb,0x84,0x3c,0x96,0x5d,0xed,0x47,0xe7,0xa0,0x86,0xed,0x76,0x95,0x01,0x70,0xe4,0xf9,0x67,0xd2,0x7b,0x69,0xb2,0x25,0x64,0x68,0x98,0x13,0xfb,0x3f,0x67,0x9d,0xb8,0xc7,0x5d,0x41,0xd9,0xfb,0xa5,0x3c,0x5e,0x3b,0x27,0xdf,0x3b,0xcc,0x4e,0xe0,0xd2,0x4c,0x4e,0xb5,0x3d,0x68,0x20,0x14}, + {0x97,0xd1,0x9d,0x24,0x1e,0xbd,0x78,0xb4,0x02,0xc1,0x58,0x5e,0x00,0x35,0x0c,0x62,0x5c,0xac,0xba,0xcc,0x2f,0xd3,0x02,0xfb,0x2d,0xa7,0x08,0xf5,0xeb,0x3b,0xb6,0x60,0xd0,0x5a,0xcc,0xc1,0x6f,0xbb,0xee,0x34,0x8b,0xac,0x46,0x96,0xe9,0x0c,0x1b,0x6a,0x53,0xde,0x6b,0xa6,0x49,0xda,0xb0,0xd3,0xc1,0x81,0xd0,0x61,0x41,0x3b,0xe8,0x31,0x4f,0x2b,0x06,0x9e,0x12,0xc7,0xe8,0x97,0xd8,0x0a,0x32,0x29,0x4f,0x8f,0xe4,0x49,0x3f,0x68,0x18,0x6f,0x4b,0xe1,0xec,0x5b,0x17,0x03,0x55,0x2d,0xb6,0x1e,0xcf,0x55}, + {0x58,0x3d,0xc2,0x65,0x10,0x10,0x79,0x58,0x9c,0x81,0x94,0x50,0x6d,0x08,0x9d,0x8b,0xa7,0x5f,0xc5,0x12,0xa9,0x2f,0x40,0xe2,0xd4,0x91,0x08,0x57,0x64,0x65,0x9a,0x66,0x52,0x8c,0xf5,0x7d,0xe3,0xb5,0x76,0x30,0x36,0xcc,0x99,0xe7,0xdd,0xb9,0x3a,0xd7,0x20,0xee,0x13,0x49,0xe3,0x1c,0x83,0xbd,0x33,0x01,0xba,0x62,0xaa,0xfb,0x56,0x1a,0xec,0xc9,0x9d,0x5c,0x50,0x6b,0x3e,0x94,0x1a,0x37,0x7c,0xa7,0xbb,0x57,0x25,0x30,0x51,0x76,0x34,0x41,0x56,0xae,0x73,0x98,0x5c,0x8a,0xc5,0x99,0x67,0x83,0xc4,0x13}, + {0xb9,0xe1,0xb3,0x5a,0x46,0x5d,0x3a,0x42,0x61,0x3f,0xf1,0xc7,0x87,0xc1,0x13,0xfc,0xb6,0xb9,0xb5,0xec,0x64,0x36,0xf8,0x19,0x07,0xb6,0x37,0xa6,0x93,0x0c,0xf8,0x66,0x80,0xd0,0x8b,0x5d,0x6a,0xfb,0xdc,0xc4,0x42,0x48,0x1a,0x57,0xec,0xc4,0xeb,0xde,0x65,0x53,0xe5,0xb8,0x83,0xe8,0xb2,0xd4,0x27,0xb8,0xe5,0xc8,0x7d,0xc8,0xbd,0x50,0x11,0xe1,0xdf,0x6e,0x83,0x37,0x6d,0x60,0xd9,0xab,0x11,0xf0,0x15,0x3e,0x35,0x32,0x96,0x3b,0xb7,0x25,0xc3,0x3a,0xb0,0x64,0xae,0xd5,0x5f,0x72,0x44,0x64,0xd5,0x1d}, + {0x7d,0x12,0x62,0x33,0xf8,0x7f,0xa4,0x8f,0x15,0x7c,0xcd,0x71,0xc4,0x6a,0x9f,0xbc,0x8b,0x0c,0x22,0x49,0x43,0x45,0x71,0x6e,0x2e,0x73,0x9f,0x21,0x12,0x59,0x64,0x0e,0x9a,0xc8,0xba,0x08,0x00,0xe6,0x97,0xc2,0xe0,0xc3,0xe1,0xea,0x11,0xea,0x4c,0x7d,0x7c,0x97,0xe7,0x9f,0xe1,0x8b,0xe3,0xf3,0xcd,0x05,0xa3,0x63,0x0f,0x45,0x3a,0x3a,0x27,0x46,0x39,0xd8,0x31,0x2f,0x8f,0x07,0x10,0xa5,0x94,0xde,0x83,0x31,0x9d,0x38,0x80,0x6f,0x99,0x17,0x6d,0x6c,0xe3,0xd1,0x7b,0xa8,0xa9,0x93,0x93,0x8d,0x8c,0x31}, + {0x19,0xfe,0xff,0x2a,0x03,0x5d,0x74,0xf2,0x66,0xdb,0x24,0x7f,0x49,0x3c,0x9f,0x0c,0xef,0x98,0x85,0xba,0xe3,0xd3,0x98,0xbc,0x14,0x53,0x1d,0x9a,0x67,0x7c,0x4c,0x22,0x98,0xd3,0x1d,0xab,0x29,0x9e,0x66,0x5d,0x3b,0x9e,0x2d,0x34,0x58,0x16,0x92,0xfc,0xcd,0x73,0x59,0xf3,0xfd,0x1d,0x85,0x55,0xf6,0x0a,0x95,0x25,0xc3,0x41,0x9a,0x50,0xe9,0x25,0xf9,0xa6,0xdc,0x6e,0xc0,0xbd,0x33,0x1f,0x1b,0x64,0xf4,0xf3,0x3e,0x79,0x89,0x3e,0x83,0x9d,0x80,0x12,0xec,0x82,0x89,0x13,0xa1,0x28,0x23,0xf0,0xbf,0x05}, + {0x0b,0xe0,0xca,0x23,0x70,0x13,0x32,0x36,0x59,0xcf,0xac,0xd1,0x0a,0xcf,0x4a,0x54,0x88,0x1c,0x1a,0xd2,0x49,0x10,0x74,0x96,0xa7,0x44,0x2a,0xfa,0xc3,0x8c,0x0b,0x78,0xe4,0x12,0xc5,0x0d,0xdd,0xa0,0x81,0x68,0xfe,0xfa,0xa5,0x44,0xc8,0x0d,0xe7,0x4f,0x40,0x52,0x4a,0x8f,0x6b,0x8e,0x74,0x1f,0xea,0xa3,0x01,0xee,0xcd,0x77,0x62,0x57,0x5f,0x30,0x4f,0x23,0xbc,0x8a,0xf3,0x1e,0x08,0xde,0x05,0x14,0xbd,0x7f,0x57,0x9a,0x0d,0x2a,0xe6,0x34,0x14,0xa5,0x82,0x5e,0xa1,0xb7,0x71,0x62,0x72,0x18,0xf4,0x5f}, + {0x9d,0xdb,0x89,0x17,0x0c,0x08,0x8e,0x39,0xf5,0x78,0xe7,0xf3,0x25,0x20,0x60,0xa7,0x5d,0x03,0xbd,0x06,0x4c,0x89,0x98,0xfa,0xbe,0x66,0xa9,0x25,0xdc,0x03,0x6a,0x10,0x40,0x95,0xb6,0x13,0xe8,0x47,0xdb,0xe5,0xe1,0x10,0x26,0x43,0x3b,0x2a,0x5d,0xf3,0x76,0x12,0x78,0x38,0xe9,0x26,0x1f,0xac,0x69,0xcb,0xa0,0xa0,0x8c,0xdb,0xd4,0x29,0xd0,0x53,0x33,0x33,0xaf,0x0a,0xad,0xd9,0xe5,0x09,0xd3,0xac,0xa5,0x9d,0x66,0x38,0xf0,0xf7,0x88,0xc8,0x8a,0x65,0x57,0x3c,0xfa,0xbe,0x2c,0x05,0x51,0x8a,0xb3,0x4a}, + {0x93,0xd5,0x68,0x67,0x25,0x2b,0x7c,0xda,0x13,0xca,0x22,0x44,0x57,0xc0,0xc1,0x98,0x1d,0xce,0x0a,0xca,0xd5,0x0b,0xa8,0xf1,0x90,0xa6,0x88,0xc0,0xad,0xd1,0xcd,0x29,0x9c,0xc0,0xdd,0x5f,0xef,0xd1,0xcf,0xd6,0xce,0x5d,0x57,0xf7,0xfd,0x3e,0x2b,0xe8,0xc2,0x34,0x16,0x20,0x5d,0x6b,0xd5,0x25,0x9b,0x2b,0xed,0x04,0xbb,0xc6,0x41,0x30,0x48,0xe1,0x56,0xd9,0xf9,0xf2,0xf2,0x0f,0x2e,0x6b,0x35,0x9f,0x75,0x97,0xe7,0xad,0x5c,0x02,0x6c,0x5f,0xbb,0x98,0x46,0x1a,0x7b,0x9a,0x04,0x14,0x68,0xbd,0x4b,0x10}, + {0x67,0xed,0xf1,0x68,0x31,0xfd,0xf0,0x51,0xc2,0x3b,0x6f,0xd8,0xcd,0x1d,0x81,0x2c,0xde,0xf2,0xd2,0x04,0x43,0x5c,0xdc,0x44,0x49,0x71,0x2a,0x09,0x57,0xcc,0xe8,0x5b,0x63,0xf1,0x7f,0xd6,0x5f,0x9a,0x5d,0xa9,0x81,0x56,0xc7,0x4c,0x9d,0xe6,0x2b,0xe9,0x57,0xf2,0x20,0xde,0x4c,0x02,0xf8,0xb7,0xf5,0x2d,0x07,0xfb,0x20,0x2a,0x4f,0x20,0x79,0xb0,0xeb,0x30,0x3d,0x3b,0x14,0xc8,0x30,0x2e,0x65,0xbd,0x5a,0x15,0x89,0x75,0x31,0x5c,0x6d,0x8f,0x31,0x3c,0x3c,0x65,0x1f,0x16,0x79,0xc2,0x17,0xfb,0x70,0x25}, + {0x75,0x15,0xb6,0x2c,0x7f,0x36,0xfa,0x3e,0x6c,0x02,0xd6,0x1c,0x76,0x6f,0xf9,0xf5,0x62,0x25,0xb5,0x65,0x2a,0x14,0xc7,0xe8,0xcd,0x0a,0x03,0x53,0xea,0x65,0xcb,0x3d,0x5a,0x24,0xb8,0x0b,0x55,0xa9,0x2e,0x19,0xd1,0x50,0x90,0x8f,0xa8,0xfb,0xe6,0xc8,0x35,0xc9,0xa4,0x88,0x2d,0xea,0x86,0x79,0x68,0x86,0x01,0xde,0x91,0x5f,0x1c,0x24,0xaa,0x6c,0xde,0x40,0x29,0x17,0xd8,0x28,0x3a,0x73,0xd9,0x22,0xf0,0x2c,0xbf,0x8f,0xd1,0x01,0x5b,0x23,0xdd,0xfc,0xd7,0x16,0xe5,0xf0,0xcd,0x5f,0xdd,0x0e,0x42,0x08}, + {0x4a,0xfa,0x62,0x83,0xab,0x20,0xff,0xcd,0x6e,0x3e,0x1a,0xe2,0xd4,0x18,0xe1,0x57,0x2b,0xe6,0x39,0xfc,0x17,0x96,0x17,0xe3,0xfd,0x69,0x17,0xbc,0xef,0x53,0x9a,0x0d,0xce,0x10,0xf4,0x04,0x4e,0xc3,0x58,0x03,0x85,0x06,0x6e,0x27,0x5a,0x5b,0x13,0xb6,0x21,0x15,0xb9,0xeb,0xc7,0x70,0x96,0x5d,0x9c,0x88,0xdb,0x21,0xf3,0x54,0xd6,0x04,0xd5,0xb5,0xbd,0xdd,0x16,0xc1,0x7d,0x5e,0x2d,0xdd,0xa5,0x8d,0xb6,0xde,0x54,0x29,0x92,0xa2,0x34,0x33,0x17,0x08,0xb6,0x1c,0xd7,0x1a,0x99,0x18,0x26,0x4f,0x7a,0x4a}, + {0x95,0x5f,0xb1,0x5f,0x02,0x18,0xa7,0xf4,0x8f,0x1b,0x5c,0x6b,0x34,0x5f,0xf6,0x3d,0x12,0x11,0xe0,0x00,0x85,0xf0,0xfc,0xcd,0x48,0x18,0xd3,0xdd,0x4c,0x0c,0xb5,0x11,0x4b,0x2a,0x37,0xaf,0x91,0xb2,0xc3,0x24,0xf2,0x47,0x81,0x71,0x70,0x82,0xda,0x93,0xf2,0x9e,0x89,0x86,0x64,0x85,0x84,0xdd,0x33,0xee,0xe0,0x23,0x42,0x31,0x96,0x4a,0xd6,0xff,0xa4,0x08,0x44,0x27,0xe8,0xa6,0xd9,0x76,0x15,0x9c,0x7e,0x17,0x8e,0x73,0xf2,0xb3,0x02,0x3d,0xb6,0x48,0x33,0x77,0x51,0xcc,0x6b,0xce,0x4d,0xce,0x4b,0x4f}, + {0x84,0x25,0x24,0xe2,0x5a,0xce,0x1f,0xa7,0x9e,0x8a,0xf5,0x92,0x56,0x72,0xea,0x26,0xf4,0x3c,0xea,0x1c,0xd7,0x09,0x1a,0xd2,0xe6,0x01,0x1c,0xb7,0x14,0xdd,0xfc,0x73,0x6f,0x0b,0x9d,0xc4,0x6e,0x61,0xe2,0x30,0x17,0x23,0xec,0xca,0x8f,0x71,0x56,0xe4,0xa6,0x4f,0x6b,0xf2,0x9b,0x40,0xeb,0x48,0x37,0x5f,0x59,0x61,0xe5,0xce,0x42,0x30,0x41,0xac,0x9b,0x44,0x79,0x70,0x7e,0x42,0x0a,0x31,0xe2,0xbc,0x6d,0xe3,0x5a,0x85,0x7c,0x1a,0x84,0x5f,0x21,0x76,0xae,0x4c,0xd6,0xe1,0x9c,0x9a,0x0c,0x74,0x9e,0x38}, + {0xce,0xb9,0xdc,0x34,0xae,0xb3,0xfc,0x64,0xad,0xd0,0x48,0xe3,0x23,0x03,0x50,0x97,0x1b,0x38,0xc6,0x62,0x7d,0xf0,0xb3,0x45,0x88,0x67,0x5a,0x46,0x79,0x53,0x54,0x61,0x28,0xac,0x0e,0x57,0xf6,0x78,0xbd,0xc9,0xe1,0x9c,0x91,0x27,0x32,0x0b,0x5b,0xe5,0xed,0x91,0x9b,0xa1,0xab,0x3e,0xfc,0x65,0x90,0x36,0x26,0xd6,0xe5,0x25,0xc4,0x25,0x6e,0xde,0xd7,0xf1,0xa6,0x06,0x3e,0x3f,0x08,0x23,0x06,0x8e,0x27,0x76,0xf9,0x3e,0x77,0x6c,0x8a,0x4e,0x26,0xf6,0x14,0x8c,0x59,0x47,0x48,0x15,0x89,0xa0,0x39,0x65}, + {0x73,0xf7,0xd2,0xc3,0x74,0x1f,0xd2,0xe9,0x45,0x68,0xc4,0x25,0x41,0x54,0x50,0xc1,0x33,0x9e,0xb9,0xf9,0xe8,0x5c,0x4e,0x62,0x6c,0x18,0xcd,0xc5,0xaa,0xe4,0xc5,0x11,0x19,0x4a,0xbb,0x14,0xd4,0xdb,0xc4,0xdd,0x8e,0x4f,0x42,0x98,0x3c,0xbc,0xb2,0x19,0x69,0x71,0xca,0x36,0xd7,0x9f,0xa8,0x48,0x90,0xbd,0x19,0xf0,0x0e,0x32,0x65,0x0f,0xc6,0xe0,0xfd,0xca,0xb1,0xd1,0x86,0xd4,0x81,0x51,0x3b,0x16,0xe3,0xe6,0x3f,0x4f,0x9a,0x93,0xf2,0xfa,0x0d,0xaf,0xa8,0x59,0x2a,0x07,0x33,0xec,0xbd,0xc7,0xab,0x4c}, + {0x2e,0x0a,0x9c,0x08,0x24,0x96,0x9e,0x23,0x38,0x47,0xfe,0x3a,0xc0,0xc4,0x48,0xc7,0x2a,0xa1,0x4f,0x76,0x2a,0xed,0xdb,0x17,0x82,0x85,0x1c,0x32,0xf0,0x93,0x9b,0x63,0x89,0xd2,0x78,0x3f,0x8f,0x78,0x8f,0xc0,0x9f,0x4d,0x40,0xa1,0x2c,0xa7,0x30,0xfe,0x9d,0xcc,0x65,0xcf,0xfc,0x8b,0x77,0xf2,0x21,0x20,0xcb,0x5a,0x16,0x98,0xe4,0x7e,0xc3,0xa1,0x11,0x91,0xe3,0x08,0xd5,0x7b,0x89,0x74,0x90,0x80,0xd4,0x90,0x2b,0x2b,0x19,0xfd,0x72,0xae,0xc2,0xae,0xd2,0xe7,0xa6,0x02,0xb6,0x85,0x3c,0x49,0xdf,0x0e}, + {0x68,0x5a,0x9b,0x59,0x58,0x81,0xcc,0xae,0x0e,0xe2,0xad,0xeb,0x0f,0x4f,0x57,0xea,0x07,0x7f,0xb6,0x22,0x74,0x1d,0xe4,0x4f,0xb4,0x4f,0x9d,0x01,0xe3,0x92,0x3b,0x40,0x13,0x41,0x76,0x84,0xd2,0xc4,0x67,0x67,0x35,0xf8,0xf5,0xf7,0x3f,0x40,0x90,0xa0,0xde,0xbe,0xe6,0xca,0xfa,0xcf,0x8f,0x1c,0x69,0xa3,0xdf,0xd1,0x54,0x0c,0xc0,0x04,0xf8,0x5c,0x46,0x8b,0x81,0x2f,0xc2,0x4d,0xf8,0xef,0x80,0x14,0x5a,0xf3,0xa0,0x71,0x57,0xd6,0xc7,0x04,0xad,0xbf,0xe8,0xae,0xf4,0x76,0x61,0xb2,0x2a,0xb1,0x5b,0x35}, + {0xf4,0xbb,0x93,0x74,0xcc,0x64,0x1e,0xa7,0xc3,0xb0,0xa3,0xec,0xd9,0x84,0xbd,0xe5,0x85,0xe7,0x05,0xfa,0x0c,0xc5,0x6b,0x0a,0x12,0xc3,0x2e,0x18,0x32,0x81,0x9b,0x0f,0x18,0x73,0x8c,0x5a,0xc7,0xda,0x01,0xa3,0x11,0xaa,0xce,0xb3,0x9d,0x03,0x90,0xed,0x2d,0x3f,0xae,0x3b,0xbf,0x7c,0x07,0x6f,0x8e,0xad,0x52,0xe0,0xf8,0xea,0x18,0x75,0x32,0x6c,0x7f,0x1b,0xc4,0x59,0x88,0xa4,0x98,0x32,0x38,0xf4,0xbc,0x60,0x2d,0x0f,0xd9,0xd1,0xb1,0xc9,0x29,0xa9,0x15,0x18,0xc4,0x55,0x17,0xbb,0x1b,0x87,0xc3,0x47}, + {0x48,0x4f,0xec,0x71,0x97,0x53,0x44,0x51,0x6e,0x5d,0x8c,0xc9,0x7d,0xb1,0x05,0xf8,0x6b,0xc6,0xc3,0x47,0x1a,0xc1,0x62,0xf7,0xdc,0x99,0x46,0x76,0x85,0x9b,0xb8,0x00,0xb0,0x66,0x50,0xc8,0x50,0x5d,0xe6,0xfb,0xb0,0x99,0xa2,0xb3,0xb0,0xc4,0xec,0x62,0xe0,0xe8,0x1a,0x44,0xea,0x54,0x37,0xe5,0x5f,0x8d,0xd4,0xe8,0x2c,0xa0,0xfe,0x08,0xd0,0xea,0xde,0x68,0x76,0xdd,0x4d,0x82,0x23,0x5d,0x68,0x4b,0x20,0x45,0x64,0xc8,0x65,0xd6,0x89,0x5d,0xcd,0xcf,0x14,0xb5,0x37,0xd5,0x75,0x4f,0xa7,0x29,0x38,0x47}, + {0x18,0xc4,0x79,0x46,0x75,0xda,0xd2,0x82,0xf0,0x8d,0x61,0xb2,0xd8,0xd7,0x3b,0xe6,0x0a,0xeb,0x47,0xac,0x24,0xef,0x5e,0x35,0xb4,0xc6,0x33,0x48,0x4c,0x68,0x78,0x20,0xc9,0x02,0x39,0xad,0x3a,0x53,0xd9,0x23,0x8f,0x58,0x03,0xef,0xce,0xdd,0xc2,0x64,0xb4,0x2f,0xe1,0xcf,0x90,0x73,0x25,0x15,0x90,0xd3,0xe4,0x44,0x4d,0x8b,0x66,0x6c,0x0c,0x82,0x78,0x7a,0x21,0xcf,0x48,0x3b,0x97,0x3e,0x27,0x81,0xb2,0x0a,0x6a,0xf7,0x7b,0xed,0x8e,0x8c,0xa7,0x65,0x6c,0xa9,0x3f,0x43,0x8a,0x4f,0x05,0xa6,0x11,0x74}, + {0x6d,0xc8,0x9d,0xb9,0x32,0x9d,0x65,0x4d,0x15,0xf1,0x3a,0x60,0x75,0xdc,0x4c,0x04,0x88,0xe4,0xc2,0xdc,0x2c,0x71,0x4c,0xb3,0xff,0x34,0x81,0xfb,0x74,0x65,0x13,0x7c,0xb4,0x75,0xb1,0x18,0x3d,0xe5,0x9a,0x57,0x02,0xa1,0x92,0xf3,0x59,0x31,0x71,0x68,0xf5,0x35,0xef,0x1e,0xba,0xec,0x55,0x84,0x8f,0x39,0x8c,0x45,0x72,0xa8,0xc9,0x1e,0x9b,0x50,0xa2,0x00,0xd4,0xa4,0xe6,0xb8,0xb4,0x82,0xc8,0x0b,0x02,0xd7,0x81,0x9b,0x61,0x75,0x95,0xf1,0x9b,0xcc,0xe7,0x57,0x60,0x64,0xcd,0xc7,0xa5,0x88,0xdd,0x3a}, + {0xf2,0xdc,0x35,0xb6,0x70,0x57,0x89,0xab,0xbc,0x1f,0x6c,0xf6,0x6c,0xef,0xdf,0x02,0x87,0xd1,0xb6,0xbe,0x68,0x02,0x53,0x85,0x74,0x9e,0x87,0xcc,0xfc,0x29,0x99,0x24,0x46,0x30,0x39,0x59,0xd4,0x98,0xc2,0x85,0xec,0x59,0xf6,0x5f,0x98,0x35,0x7e,0x8f,0x3a,0x6e,0xf6,0xf2,0x2a,0xa2,0x2c,0x1d,0x20,0xa7,0x06,0xa4,0x31,0x11,0xba,0x61,0x29,0x90,0x95,0x16,0xf1,0xa0,0xd0,0xa3,0x89,0xbd,0x7e,0xba,0x6c,0x6b,0x3b,0x02,0x07,0x33,0x78,0x26,0x3e,0x5a,0xf1,0x7b,0xe7,0xec,0xd8,0xbb,0x0c,0x31,0x20,0x56}, + {0x43,0xd6,0x34,0x49,0x43,0x93,0x89,0x52,0xf5,0x22,0x12,0xa5,0x06,0xf8,0xdb,0xb9,0x22,0x1c,0xf4,0xc3,0x8f,0x87,0x6d,0x8f,0x30,0x97,0x9d,0x4d,0x2a,0x6a,0x67,0x37,0xd6,0x85,0xe2,0x77,0xf4,0xb5,0x46,0x66,0x93,0x61,0x8f,0x6c,0x67,0xff,0xe8,0x40,0xdd,0x94,0xb5,0xab,0x11,0x73,0xec,0xa6,0x4d,0xec,0x8c,0x65,0xf3,0x46,0xc8,0x7e,0xc7,0x2e,0xa2,0x1d,0x3f,0x8f,0x5e,0x9b,0x13,0xcd,0x01,0x6c,0x77,0x1d,0x0f,0x13,0xb8,0x9f,0x98,0xa2,0xcf,0x8f,0x4c,0x21,0xd5,0x9d,0x9b,0x39,0x23,0xf7,0xaa,0x6d}, + {0x47,0xbe,0x3d,0xeb,0x62,0x75,0x3a,0x5f,0xb8,0xa0,0xbd,0x8e,0x54,0x38,0xea,0xf7,0x99,0x72,0x74,0x45,0x31,0xe5,0xc3,0x00,0x51,0xd5,0x27,0x16,0xe7,0xe9,0x04,0x13,0xa2,0x8e,0xad,0xac,0xbf,0x04,0x3b,0x58,0x84,0xe8,0x8b,0x14,0xe8,0x43,0xb7,0x29,0xdb,0xc5,0x10,0x08,0x3b,0x58,0x1e,0x2b,0xaa,0xbb,0xb3,0x8e,0xe5,0x49,0x54,0x2b,0xfe,0x9c,0xdc,0x6a,0xd2,0x14,0x98,0x78,0x0b,0xdd,0x48,0x8b,0x3f,0xab,0x1b,0x3c,0x0a,0xc6,0x79,0xf9,0xff,0xe1,0x0f,0xda,0x93,0xd6,0x2d,0x7c,0x2d,0xde,0x68,0x44}, + {0x9e,0x46,0x19,0x94,0x5e,0x35,0xbb,0x51,0x54,0xc7,0xdd,0x23,0x4c,0xdc,0xe6,0x33,0x62,0x99,0x7f,0x44,0xd6,0xb6,0xa5,0x93,0x63,0xbd,0x44,0xfb,0x6f,0x7c,0xce,0x6c,0xce,0x07,0x63,0xf8,0xc6,0xd8,0x9a,0x4b,0x28,0x0c,0x5d,0x43,0x31,0x35,0x11,0x21,0x2c,0x77,0x7a,0x65,0xc5,0x66,0xa8,0xd4,0x52,0x73,0x24,0x63,0x7e,0x42,0xa6,0x5d,0xca,0x22,0xac,0xde,0x88,0xc6,0x94,0x1a,0xf8,0x1f,0xae,0xbb,0xf7,0x6e,0x06,0xb9,0x0f,0x58,0x59,0x8d,0x38,0x8c,0xad,0x88,0xa8,0x2c,0x9f,0xe7,0xbf,0x9a,0xf2,0x58}, + {0x68,0x3e,0xe7,0x8d,0xab,0xcf,0x0e,0xe9,0xa5,0x76,0x7e,0x37,0x9f,0x6f,0x03,0x54,0x82,0x59,0x01,0xbe,0x0b,0x5b,0x49,0xf0,0x36,0x1e,0xf4,0xa7,0xc4,0x29,0x76,0x57,0xf6,0xcd,0x0e,0x71,0xbf,0x64,0x5a,0x4b,0x3c,0x29,0x2c,0x46,0x38,0xe5,0x4c,0xb1,0xb9,0x3a,0x0b,0xd5,0x56,0xd0,0x43,0x36,0x70,0x48,0x5b,0x18,0x24,0x37,0xf9,0x6a,0x88,0xa8,0xc6,0x09,0x45,0x02,0x20,0x32,0x73,0x89,0x55,0x4b,0x13,0x36,0xe0,0xd2,0x9f,0x28,0x33,0x3c,0x23,0x36,0xe2,0x83,0x8f,0xc1,0xae,0x0c,0xbb,0x25,0x1f,0x70}, + {0xed,0x6c,0x61,0xe4,0xf8,0xb0,0xa8,0xc3,0x7d,0xa8,0x25,0x9e,0x0e,0x66,0x00,0xf7,0x9c,0xa5,0xbc,0xf4,0x1f,0x06,0xe3,0x61,0xe9,0x0b,0xc4,0xbd,0xbf,0x92,0x0c,0x2e,0x13,0xc1,0xbe,0x7c,0xd9,0xf6,0x18,0x9d,0xe4,0xdb,0xbf,0x74,0xe6,0x06,0x4a,0x84,0xd6,0x60,0x4e,0xac,0x22,0xb5,0xf5,0x20,0x51,0x5e,0x95,0x50,0xc0,0x5b,0x0a,0x72,0x35,0x5a,0x80,0x9b,0x43,0x09,0x3f,0x0c,0xfc,0xab,0x42,0x62,0x37,0x8b,0x4e,0xe8,0x46,0x93,0x22,0x5c,0xf3,0x17,0x14,0x69,0xec,0xf0,0x4e,0x14,0xbb,0x9c,0x9b,0x0e}, + {0xad,0x20,0x57,0xfb,0x8f,0xd4,0xba,0xfb,0x0e,0x0d,0xf9,0xdb,0x6b,0x91,0x81,0xee,0xbf,0x43,0x55,0x63,0x52,0x31,0x81,0xd4,0xd8,0x7b,0x33,0x3f,0xeb,0x04,0x11,0x22,0xee,0xbe,0xb1,0x5d,0xd5,0x9b,0xee,0x8d,0xb9,0x3f,0x72,0x0a,0x37,0xab,0xc3,0xc9,0x91,0xd7,0x68,0x1c,0xbf,0xf1,0xa8,0x44,0xde,0x3c,0xfd,0x1c,0x19,0x44,0x6d,0x36,0x14,0x8c,0xbc,0xf2,0x43,0x17,0x3c,0x9e,0x3b,0x6c,0x85,0xb5,0xfc,0x26,0xda,0x2e,0x97,0xfb,0xa7,0x68,0x0e,0x2f,0xb8,0xcc,0x44,0x32,0x59,0xbc,0xe6,0xa4,0x67,0x41}, + {0x00,0x27,0xf6,0x76,0x28,0x9d,0x3b,0x64,0xeb,0x68,0x76,0x0e,0x40,0x9d,0x1d,0x5d,0x84,0x06,0xfc,0x21,0x03,0x43,0x4b,0x1b,0x6a,0x24,0x55,0x22,0x7e,0xbb,0x38,0x79,0xee,0x8f,0xce,0xf8,0x65,0x26,0xbe,0xc2,0x2c,0xd6,0x80,0xe8,0x14,0xff,0x67,0xe9,0xee,0x4e,0x36,0x2f,0x7e,0x6e,0x2e,0xf1,0xf6,0xd2,0x7e,0xcb,0x70,0x33,0xb3,0x34,0xcc,0xd6,0x81,0x86,0xee,0x91,0xc5,0xcd,0x53,0xa7,0x85,0xed,0x9c,0x10,0x02,0xce,0x83,0x88,0x80,0x58,0xc1,0x85,0x74,0xed,0xe4,0x65,0xfe,0x2d,0x6e,0xfc,0x76,0x11}, + {0x9b,0x61,0x9c,0x5b,0xd0,0x6c,0xaf,0xb4,0x80,0x84,0xa5,0xb2,0xf4,0xc9,0xdf,0x2d,0xc4,0x4d,0xe9,0xeb,0x02,0xa5,0x4f,0x3d,0x34,0x5f,0x7d,0x67,0x4c,0x3a,0xfc,0x08,0xb8,0x0e,0x77,0x49,0x89,0xe2,0x90,0xdb,0xa3,0x40,0xf4,0xac,0x2a,0xcc,0xfb,0x98,0x9b,0x87,0xd7,0xde,0xfe,0x4f,0x35,0x21,0xb6,0x06,0x69,0xf2,0x54,0x3e,0x6a,0x1f,0xea,0x34,0x07,0xd3,0x99,0xc1,0xa4,0x60,0xd6,0x5c,0x16,0x31,0xb6,0x85,0xc0,0x40,0x95,0x82,0x59,0xf7,0x23,0x3e,0x33,0xe2,0xd1,0x00,0xb9,0x16,0x01,0xad,0x2f,0x4f}, + {0x54,0x4e,0xae,0x94,0x41,0xb2,0xbe,0x44,0x6c,0xef,0x57,0x18,0x51,0x1c,0x54,0x5f,0x98,0x04,0x8d,0x36,0x2d,0x6b,0x1e,0xa6,0xab,0xf7,0x2e,0x97,0xa4,0x84,0x54,0x44,0x38,0xb6,0x3b,0xb7,0x1d,0xd9,0x2c,0x96,0x08,0x9c,0x12,0xfc,0xaa,0x77,0x05,0xe6,0x89,0x16,0xb6,0xf3,0x39,0x9b,0x61,0x6f,0x81,0xee,0x44,0x29,0x5f,0x99,0x51,0x34,0x7c,0x7d,0xea,0x9f,0xd0,0xfc,0x52,0x91,0xf6,0x5c,0x93,0xb0,0x94,0x6c,0x81,0x4a,0x40,0x5c,0x28,0x47,0xaa,0x9a,0x8e,0x25,0xb7,0x93,0x28,0x04,0xa6,0x9c,0xb8,0x10}, + {0x9c,0x28,0x18,0x97,0x49,0x47,0x59,0x3d,0x26,0x3f,0x53,0x24,0xc5,0xf8,0xeb,0x12,0x15,0xef,0xc3,0x14,0xcb,0xbf,0x62,0x02,0x8e,0x51,0xb7,0x77,0xd5,0x78,0xb8,0x20,0x6e,0xf0,0x45,0x5a,0xbe,0x41,0x39,0x75,0x65,0x5f,0x9c,0x6d,0xed,0xae,0x7c,0xd0,0xb6,0x51,0xff,0x72,0x9c,0x6b,0x77,0x11,0xa9,0x4d,0x0d,0xef,0xd9,0xd1,0xd2,0x17,0x6a,0x3e,0x3f,0x07,0x18,0xaf,0xf2,0x27,0x69,0x10,0x52,0xd7,0x19,0xe5,0x3f,0xfd,0x22,0x00,0xa6,0x3c,0x2c,0xb7,0xe3,0x22,0xa7,0xc6,0x65,0xcc,0x63,0x4f,0x21,0x72}, + {0x93,0xa6,0x07,0x53,0x40,0x7f,0xe3,0xb4,0x95,0x67,0x33,0x2f,0xd7,0x14,0xa7,0xab,0x99,0x10,0x76,0x73,0xa7,0xd0,0xfb,0xd6,0xc9,0xcb,0x71,0x81,0xc5,0x48,0xdf,0x5f,0xc9,0x29,0x3b,0xf4,0xb9,0xb7,0x9d,0x1d,0x75,0x8f,0x51,0x4f,0x4a,0x82,0x05,0xd6,0xc4,0x9d,0x2f,0x31,0xbd,0x72,0xc0,0xf2,0xb0,0x45,0x15,0x5a,0x85,0xac,0x24,0x1f,0xaa,0x05,0x95,0x8e,0x32,0x08,0xd6,0x24,0xee,0x20,0x14,0x0c,0xd1,0xc1,0x48,0x47,0xa2,0x25,0xfb,0x06,0x5c,0xe4,0xff,0xc7,0xe6,0x95,0xe3,0x2a,0x9e,0x73,0xba,0x00}, + {0xd6,0x90,0x87,0x5c,0xde,0x98,0x2e,0x59,0xdf,0xa2,0xc2,0x45,0xd3,0xb7,0xbf,0xe5,0x22,0x99,0xb4,0xf9,0x60,0x3b,0x5a,0x11,0xf3,0x78,0xad,0x67,0x3e,0x3a,0x28,0x03,0x26,0xbb,0x88,0xea,0xf5,0x26,0x44,0xae,0xfb,0x3b,0x97,0x84,0xd9,0x79,0x06,0x36,0x50,0x4e,0x69,0x26,0x0c,0x03,0x9f,0x5c,0x26,0xd2,0x18,0xd5,0xe7,0x7d,0x29,0x72,0x39,0xb9,0x0c,0xbe,0xc7,0x1d,0x24,0x48,0x80,0x30,0x63,0x8b,0x4d,0x9b,0xf1,0x32,0x08,0x93,0x28,0x02,0x0d,0xc9,0xdf,0xd3,0x45,0x19,0x27,0x46,0x68,0x29,0xe1,0x05}, + {0x5a,0x49,0x9c,0x2d,0xb3,0xee,0x82,0xba,0x7c,0xb9,0x2b,0xf1,0xfc,0xc8,0xef,0xce,0xe0,0xd1,0xb5,0x93,0xae,0xab,0x2d,0xb0,0x9b,0x8d,0x69,0x13,0x9c,0x0c,0xc0,0x39,0x50,0x45,0x2c,0x24,0xc8,0xbb,0xbf,0xad,0xd9,0x81,0x30,0xd0,0xec,0x0c,0xc8,0xbc,0x92,0xdf,0xc8,0xf5,0xa6,0x66,0x35,0x84,0x4c,0xce,0x58,0x82,0xd3,0x25,0xcf,0x78,0x68,0x9d,0x48,0x31,0x8e,0x6b,0xae,0x15,0x87,0xf0,0x2b,0x9c,0xab,0x1c,0x85,0xaa,0x05,0xfa,0x4e,0xf0,0x97,0x5a,0xa7,0xc9,0x32,0xf8,0x3f,0x6b,0x07,0x52,0x6b,0x00}, + {0x1c,0x78,0x95,0x9d,0xe1,0xcf,0xe0,0x29,0xe2,0x10,0x63,0x96,0x18,0xdf,0x81,0xb6,0x39,0x6b,0x51,0x70,0xd3,0x39,0xdf,0x57,0x22,0x61,0xc7,0x3b,0x44,0xe3,0x57,0x4d,0x2d,0x08,0xce,0xb9,0x16,0x7e,0xcb,0xf5,0x29,0xbc,0x7a,0x41,0x4c,0xf1,0x07,0x34,0xab,0xa7,0xf4,0x2b,0xce,0x6b,0xb3,0xd4,0xce,0x75,0x9f,0x1a,0x56,0xe9,0xe2,0x7d,0xcb,0x5e,0xa5,0xb6,0xf4,0xd4,0x70,0xde,0x99,0xdb,0x85,0x5d,0x7f,0x52,0x01,0x48,0x81,0x9a,0xee,0xd3,0x40,0xc4,0xc9,0xdb,0xed,0x29,0x60,0x1a,0xaf,0x90,0x2a,0x6b}, + {0x97,0x1e,0xe6,0x9a,0xfc,0xf4,0x23,0x69,0xd1,0x5f,0x3f,0xe0,0x1d,0x28,0x35,0x57,0x2d,0xd1,0xed,0xe6,0x43,0xae,0x64,0xa7,0x4a,0x3e,0x2d,0xd1,0xe9,0xf4,0xd8,0x5f,0x0a,0xd8,0xb2,0x5b,0x24,0xf3,0xeb,0x77,0x9b,0x07,0xb9,0x2f,0x47,0x1b,0x30,0xd8,0x33,0x73,0xee,0x4c,0xf2,0xe6,0x47,0xc6,0x09,0x21,0x6c,0x27,0xc8,0x12,0x58,0x46,0xd9,0x62,0x10,0x2a,0xb2,0xbe,0x43,0x4d,0x16,0xdc,0x31,0x38,0x75,0xfb,0x65,0x70,0xd7,0x68,0x29,0xde,0x7b,0x4a,0x0d,0x18,0x90,0x67,0xb1,0x1c,0x2b,0x2c,0xb3,0x05}, + {0xfd,0xa8,0x4d,0xd2,0xcc,0x5e,0xc0,0xc8,0x83,0xef,0xdf,0x05,0xac,0x1a,0xcf,0xa1,0x61,0xcd,0xf9,0x7d,0xf2,0xef,0xbe,0xdb,0x99,0x1e,0x47,0x7b,0xa3,0x56,0x55,0x3b,0x95,0x81,0xd5,0x7a,0x2c,0xa4,0xfc,0xf7,0xcc,0xf3,0x33,0x43,0x6e,0x28,0x14,0x32,0x9d,0x97,0x0b,0x34,0x0d,0x9d,0xc2,0xb6,0xe1,0x07,0x73,0x56,0x48,0x1a,0x77,0x31,0x82,0xd4,0x4d,0xe1,0x24,0xc5,0xb0,0x32,0xb6,0xa4,0x2b,0x1a,0x54,0x51,0xb3,0xed,0xf3,0x5a,0x2b,0x28,0x48,0x60,0xd1,0xa3,0xeb,0x36,0x73,0x7a,0xd2,0x79,0xc0,0x4f}, + {0x7f,0x2f,0xbf,0x89,0xb0,0x38,0xc9,0x51,0xa7,0xe9,0xdf,0x02,0x65,0xbd,0x97,0x24,0x53,0xe4,0x80,0x78,0x9c,0xc0,0xff,0xff,0x92,0x8e,0xf9,0xca,0xce,0x67,0x45,0x12,0x0d,0xc5,0x86,0x0c,0x44,0x8b,0x34,0xdc,0x51,0xe6,0x94,0xcc,0xc9,0xcb,0x37,0x13,0xb9,0x3c,0x3e,0x64,0x4d,0xf7,0x22,0x64,0x08,0xcd,0xe3,0xba,0xc2,0x70,0x11,0x24,0xb4,0x73,0xc4,0x0a,0x86,0xab,0xf9,0x3f,0x35,0xe4,0x13,0x01,0xee,0x1d,0x91,0xf0,0xaf,0xc4,0xc6,0xeb,0x60,0x50,0xe7,0x4a,0x0d,0x00,0x87,0x6c,0x96,0x12,0x86,0x3f}, + {0xde,0x0d,0x2a,0x78,0xc9,0x0c,0x9a,0x55,0x85,0x83,0x71,0xea,0xb2,0xcd,0x1d,0x55,0x8c,0x23,0xef,0x31,0x5b,0x86,0x62,0x7f,0x3d,0x61,0x73,0x79,0x76,0xa7,0x4a,0x50,0x13,0x8d,0x04,0x36,0xfa,0xfc,0x18,0x9c,0xdd,0x9d,0x89,0x73,0xb3,0x9d,0x15,0x29,0xaa,0xd0,0x92,0x9f,0x0b,0x35,0x9f,0xdc,0xd4,0x19,0x8a,0x87,0xee,0x7e,0xf5,0x26,0xb1,0xef,0x87,0x56,0xd5,0x2c,0xab,0x0c,0x7b,0xf1,0x7a,0x24,0x62,0xd1,0x80,0x51,0x67,0x24,0x5a,0x4f,0x34,0x5a,0xc1,0x85,0x69,0x30,0xba,0x9d,0x3d,0x94,0x41,0x40}, + {0x96,0xcc,0xeb,0x43,0xba,0xee,0xc0,0xc3,0xaf,0x9c,0xea,0x26,0x9c,0x9c,0x74,0x8d,0xc6,0xcc,0x77,0x1c,0xee,0x95,0xfa,0xd9,0x0f,0x34,0x84,0x76,0xd9,0xa1,0x20,0x14,0xdd,0xaa,0x6c,0xa2,0x43,0x77,0x21,0x4b,0xce,0xb7,0x8a,0x64,0x24,0xb4,0xa6,0x47,0xe3,0xc9,0xfb,0x03,0x7a,0x4f,0x1d,0xcb,0x19,0xd0,0x00,0x98,0x42,0x31,0xd9,0x12,0x4f,0x59,0x37,0xd3,0x99,0x77,0xc6,0x00,0x7b,0xa4,0x3a,0xb2,0x40,0x51,0x3c,0x5e,0x95,0xf3,0x5f,0xe3,0x54,0x28,0x18,0x44,0x12,0xa0,0x59,0x43,0x31,0x92,0x4f,0x1b}, + {0x51,0x09,0x15,0x89,0x9d,0x10,0x5c,0x3e,0x6a,0x69,0xe9,0x2d,0x91,0xfa,0xce,0x39,0x20,0x30,0x5f,0x97,0x3f,0xe4,0xea,0x20,0xae,0x2d,0x13,0x7f,0x2a,0x57,0x9b,0x23,0xb1,0x66,0x98,0xa4,0x30,0x30,0xcf,0x33,0x59,0x48,0x5f,0x21,0xd2,0x73,0x1f,0x25,0xf6,0xf4,0xde,0x51,0x40,0xaa,0x82,0xab,0xf6,0x23,0x9a,0x6f,0xd5,0x91,0xf1,0x5f,0x68,0x90,0x2d,0xac,0x33,0xd4,0x9e,0x81,0x23,0x85,0xc9,0x5f,0x79,0xab,0x83,0x28,0x3d,0xeb,0x93,0x55,0x80,0x72,0x45,0xef,0xcb,0x36,0x8f,0x75,0x6a,0x52,0x0c,0x02}, + {0xbc,0xdb,0xd8,0x9e,0xf8,0x34,0x98,0x77,0x6c,0xa4,0x7c,0xdc,0xf9,0xaa,0xf2,0xc8,0x74,0xb0,0xe1,0xa3,0xdc,0x4c,0x52,0xa9,0x77,0x38,0x31,0x15,0x46,0xcc,0xaa,0x02,0x89,0xcc,0x42,0xf0,0x59,0xef,0x31,0xe9,0xb6,0x4b,0x12,0x8e,0x9d,0x9c,0x58,0x2c,0x97,0x59,0xc7,0xae,0x8a,0xe1,0xc8,0xad,0x0c,0xc5,0x02,0x56,0x0a,0xfe,0x2c,0x45,0xdf,0x77,0x78,0x64,0xa0,0xf7,0xa0,0x86,0x9f,0x7c,0x60,0x0e,0x27,0x64,0xc4,0xbb,0xc9,0x11,0xfb,0xf1,0x25,0xea,0x17,0xab,0x7b,0x87,0x4b,0x30,0x7b,0x7d,0xfb,0x4c}, + {0xfe,0x75,0x9b,0xb8,0x6c,0x3d,0xb4,0x72,0x80,0xdc,0x6a,0x9c,0xd9,0x94,0xc6,0x54,0x9f,0x4c,0xe3,0x3e,0x37,0xaa,0xc3,0xb8,0x64,0x53,0x07,0x39,0x2b,0x62,0xb4,0x14,0x12,0xef,0x89,0x97,0xc2,0x99,0x86,0xe2,0x0d,0x19,0x57,0xdf,0x71,0xcd,0x6e,0x2b,0xd0,0x70,0xc9,0xec,0x57,0xc8,0x43,0xc3,0xc5,0x3a,0x4d,0x43,0xbc,0x4c,0x1d,0x5b,0x26,0x9f,0x0a,0xcc,0x15,0x26,0xfb,0xb6,0xe5,0xcc,0x8d,0xb8,0x2b,0x0e,0x4f,0x3a,0x05,0xa7,0x69,0x33,0x8b,0x49,0x01,0x13,0xd1,0x2d,0x59,0x58,0x12,0xf7,0x98,0x2f}, + {0x56,0x9e,0x0f,0xb5,0x4c,0xa7,0x94,0x0c,0x20,0x13,0x8e,0x8e,0xa9,0xf4,0x1f,0x5b,0x67,0x0f,0x30,0x82,0x21,0xcc,0x2a,0x9a,0xf9,0xaa,0x06,0xd8,0x49,0xe2,0x6a,0x3a,0x01,0xa7,0x54,0x4f,0x44,0xae,0x12,0x2e,0xde,0xd7,0xcb,0xa9,0xf0,0x3e,0xfe,0xfc,0xe0,0x5d,0x83,0x75,0x0d,0x89,0xbf,0xce,0x54,0x45,0x61,0xe7,0xe9,0x62,0x80,0x1d,0x5a,0x7c,0x90,0xa9,0x85,0xda,0x7a,0x65,0x62,0x0f,0xb9,0x91,0xb5,0xa8,0x0e,0x1a,0xe9,0xb4,0x34,0xdf,0xfb,0x1d,0x0e,0x8d,0xf3,0x5f,0xf2,0xae,0xe8,0x8c,0x8b,0x29}, + {0xb2,0x0c,0xf7,0xef,0x53,0x79,0x92,0x2a,0x76,0x70,0x15,0x79,0x2a,0xc9,0x89,0x4b,0x6a,0xcf,0xa7,0x30,0x7a,0x45,0x18,0x94,0x85,0xe4,0x5c,0x4d,0x40,0xa8,0xb8,0x34,0xde,0x65,0x21,0x0a,0xea,0x72,0x7a,0x83,0xf6,0x79,0xcf,0x0b,0xb4,0x07,0xab,0x3f,0x70,0xae,0x38,0x77,0xc7,0x36,0x16,0x52,0xdc,0xd7,0xa7,0x03,0x18,0x27,0xa6,0x6b,0x35,0x33,0x69,0x83,0xb5,0xec,0x6e,0xc2,0xfd,0xfe,0xb5,0x63,0xdf,0x13,0xa8,0xd5,0x73,0x25,0xb2,0xa4,0x9a,0xaa,0x93,0xa2,0x6a,0x1c,0x5e,0x46,0xdd,0x2b,0xd6,0x71}, + {0x80,0xdf,0x78,0xd3,0x28,0xcc,0x33,0x65,0xb4,0xa4,0x0f,0x0a,0x79,0x43,0xdb,0xf6,0x5a,0xda,0x01,0xf7,0xf9,0x5f,0x64,0xe3,0xa4,0x2b,0x17,0xf3,0x17,0xf3,0xd5,0x74,0xf5,0x5e,0xf7,0xb1,0xda,0xb5,0x2d,0xcd,0xf5,0x65,0xb0,0x16,0xcf,0x95,0x7f,0xd7,0x85,0xf0,0x49,0x3f,0xea,0x1f,0x57,0x14,0x3d,0x2b,0x2b,0x26,0x21,0x36,0x33,0x1c,0x81,0xca,0xd9,0x67,0x54,0xe5,0x6f,0xa8,0x37,0x8c,0x29,0x2b,0x75,0x7c,0x8b,0x39,0x3b,0x62,0xac,0xe3,0x92,0x08,0x6d,0xda,0x8c,0xd9,0xe9,0x47,0x45,0xcc,0xeb,0x4a}, + {0xc9,0x01,0x6d,0x27,0x1b,0x07,0xf0,0x12,0x70,0x8c,0xc4,0x86,0xc5,0xba,0xb8,0xe7,0xa9,0xfb,0xd6,0x71,0x9b,0x12,0x08,0x53,0x92,0xb7,0x3d,0x5a,0xf9,0xfb,0x88,0x5d,0x10,0xb6,0x54,0x73,0x9e,0x8d,0x40,0x0b,0x6e,0x5b,0xa8,0x5b,0x53,0x32,0x6b,0x80,0x07,0xa2,0x58,0x4a,0x03,0x3a,0xe6,0xdb,0x2c,0xdf,0xa1,0xc9,0xdd,0xd9,0x3b,0x17,0xdf,0x72,0x58,0xfe,0x1e,0x0f,0x50,0x2b,0xc1,0x18,0x39,0xd4,0x2e,0x58,0xd6,0x58,0xe0,0x3a,0x67,0xc9,0x8e,0x27,0xed,0xe6,0x19,0xa3,0x9e,0xb1,0x13,0xcd,0xe1,0x06}, + {0x23,0x6f,0x16,0x6f,0x51,0xad,0xd0,0x40,0xbe,0x6a,0xab,0x1f,0x93,0x32,0x8e,0x11,0x8e,0x08,0x4d,0xa0,0x14,0x5e,0xe3,0x3f,0x66,0x62,0xe1,0x26,0x35,0x60,0x80,0x30,0x53,0x03,0x5b,0x9e,0x62,0xaf,0x2b,0x47,0x47,0x04,0x8d,0x27,0x90,0x0b,0xaa,0x3b,0x27,0xbf,0x43,0x96,0x46,0x5f,0x78,0x0c,0x13,0x7b,0x83,0x8d,0x1a,0x6a,0x3a,0x7f,0x0b,0x80,0x3d,0x5d,0x39,0x44,0xe6,0xf7,0xf6,0xed,0x01,0xc9,0x55,0xd5,0xa8,0x95,0x39,0x63,0x2c,0x59,0x30,0x78,0xcd,0x68,0x7e,0x30,0x51,0x2e,0xed,0xfd,0xd0,0x30}, + {0xb3,0x33,0x12,0xf2,0x1a,0x4d,0x59,0xe0,0x9c,0x4d,0xcc,0xf0,0x8e,0xe7,0xdb,0x1b,0x77,0x9a,0x49,0x8f,0x7f,0x18,0x65,0x69,0x68,0x98,0x09,0x2c,0x20,0x14,0x92,0x0a,0x50,0x47,0xb8,0x68,0x1e,0x97,0xb4,0x9c,0xcf,0xbb,0x64,0x66,0x29,0x72,0x95,0xa0,0x2b,0x41,0xfa,0x72,0x26,0xe7,0x8d,0x5c,0xd9,0x89,0xc5,0x51,0x43,0x08,0x15,0x46,0x2e,0xa0,0xb9,0xae,0xc0,0x19,0x90,0xbc,0xae,0x4c,0x03,0x16,0x0d,0x11,0xc7,0x55,0xec,0x32,0x99,0x65,0x01,0xf5,0x6d,0x0e,0xfe,0x5d,0xca,0x95,0x28,0x0d,0xca,0x3b}, + {0xa4,0x62,0x5d,0x3c,0xbc,0x31,0xf0,0x40,0x60,0x7a,0xf0,0xcf,0x3e,0x8b,0xfc,0x19,0x45,0xb5,0x0f,0x13,0xa2,0x3d,0x18,0x98,0xcd,0x13,0x8f,0xae,0xdd,0xde,0x31,0x56,0xbf,0x01,0xcc,0x9e,0xb6,0x8e,0x68,0x9c,0x6f,0x89,0x44,0xa6,0xad,0x83,0xbc,0xf0,0xe2,0x9f,0x7a,0x5f,0x5f,0x95,0x2d,0xca,0x41,0x82,0xf2,0x8d,0x03,0xb4,0xa8,0x4e,0x02,0xd2,0xca,0xf1,0x0a,0x46,0xed,0x2a,0x83,0xee,0x8c,0xa4,0x05,0x53,0x30,0x46,0x5f,0x1a,0xf1,0x49,0x45,0x77,0x21,0x91,0x63,0xa4,0x2c,0x54,0x30,0x09,0xce,0x24}, + {0x06,0xc1,0x06,0xfd,0xf5,0x90,0xe8,0x1f,0xf2,0x10,0x88,0x5d,0x35,0x68,0xc4,0xb5,0x3e,0xaf,0x8c,0x6e,0xfe,0x08,0x78,0x82,0x4b,0xd7,0x06,0x8a,0xc2,0xe3,0xd4,0x41,0x85,0x0b,0xf3,0xfd,0x55,0xa1,0xcf,0x3f,0xa4,0x2e,0x37,0x36,0x8e,0x16,0xf7,0xd2,0x44,0xf8,0x92,0x64,0xde,0x64,0xe0,0xb2,0x80,0x42,0x4f,0x32,0xa7,0x28,0x99,0x54,0x2e,0x1a,0xee,0x63,0xa7,0x32,0x6e,0xf2,0xea,0xfd,0x5f,0xd2,0xb7,0xe4,0x91,0xae,0x69,0x4d,0x7f,0xd1,0x3b,0xd3,0x3b,0xbc,0x6a,0xff,0xdc,0xc0,0xde,0x66,0x1b,0x49}, + {0xa7,0x32,0xea,0xc7,0x3d,0xb1,0xf5,0x98,0x98,0xdb,0x16,0x7e,0xcc,0xf8,0xd5,0xe3,0x47,0xd9,0xf8,0xcb,0x52,0xbf,0x0a,0xac,0xac,0xe4,0x5e,0xc8,0xd0,0x38,0xf3,0x08,0xa1,0x64,0xda,0xd0,0x8e,0x4a,0xf0,0x75,0x4b,0x28,0xe2,0x67,0xaf,0x2c,0x22,0xed,0xa4,0x7b,0x7b,0x1f,0x79,0xa3,0x34,0x82,0x67,0x8b,0x01,0xb7,0xb0,0xb8,0xf6,0x4c,0xbd,0x73,0x1a,0x99,0x21,0xa8,0x83,0xc3,0x7a,0x0c,0x32,0xdf,0x01,0xbc,0x27,0xab,0x63,0x70,0x77,0x84,0x1b,0x33,0x3d,0xc1,0x99,0x8a,0x07,0xeb,0x82,0x4a,0x0d,0x53}, + {0x25,0x48,0xf9,0xe1,0x30,0x36,0x4c,0x00,0x5a,0x53,0xab,0x8c,0x26,0x78,0x2d,0x7e,0x8b,0xff,0x84,0xcc,0x23,0x23,0x48,0xc7,0xb9,0x70,0x17,0x10,0x3f,0x75,0xea,0x65,0x9e,0xbf,0x9a,0x6c,0x45,0x73,0x69,0x6d,0x80,0xa8,0x00,0x49,0xfc,0xb2,0x7f,0x25,0x50,0xb8,0xcf,0xc8,0x12,0xf4,0xac,0x2b,0x5b,0xbd,0xbf,0x0c,0xe0,0xe7,0xb3,0x0d,0x63,0x63,0x09,0xe2,0x3e,0xfc,0x66,0x3d,0x6b,0xcb,0xb5,0x61,0x7f,0x2c,0xd6,0x81,0x1a,0x3b,0x44,0x13,0x42,0x04,0xbe,0x0f,0xdb,0xa1,0xe1,0x21,0x19,0xec,0xa4,0x02}, + {0xa2,0xb8,0x24,0x3b,0x9a,0x25,0xe6,0x5c,0xb8,0xa0,0xaf,0x45,0xcc,0x7a,0x57,0xb8,0x37,0x70,0xa0,0x8b,0xe8,0xe6,0xcb,0xcc,0xbf,0x09,0x78,0x12,0x51,0x3c,0x14,0x3d,0x5f,0x79,0xcf,0xf1,0x62,0x61,0xc8,0xf5,0xf2,0x57,0xee,0x26,0x19,0x86,0x8c,0x11,0x78,0x35,0x06,0x1c,0x85,0x24,0x21,0x17,0xcf,0x7f,0x06,0xec,0x5d,0x2b,0xd1,0x36,0x57,0x45,0x15,0x79,0x91,0x27,0x6d,0x12,0x0a,0x3a,0x78,0xfc,0x5c,0x8f,0xe4,0xd5,0xac,0x9b,0x17,0xdf,0xe8,0xb6,0xbd,0x36,0x59,0x28,0xa8,0x5b,0x88,0x17,0xf5,0x2e}, + {0xdc,0xae,0x58,0x8c,0x4e,0x97,0x37,0x46,0xa4,0x41,0xf0,0xab,0xfb,0x22,0xef,0xb9,0x8a,0x71,0x80,0xe9,0x56,0xd9,0x85,0xe1,0xa6,0xa8,0x43,0xb1,0xfa,0x78,0x1b,0x2f,0x51,0x2f,0x5b,0x30,0xfb,0xbf,0xee,0x96,0xb8,0x96,0x95,0x88,0xad,0x38,0xf9,0xd3,0x25,0xdd,0xd5,0x46,0xc7,0x2d,0xf5,0xf0,0x95,0x00,0x3a,0xbb,0x90,0x82,0x96,0x57,0x01,0xe1,0x20,0x0a,0x43,0xb8,0x1a,0xf7,0x47,0xec,0xf0,0x24,0x8d,0x65,0x93,0xf3,0xd1,0xee,0xe2,0x6e,0xa8,0x09,0x75,0xcf,0xe1,0xa3,0x2a,0xdc,0x35,0x3e,0xc4,0x7d}, + {0xc3,0xd9,0x7d,0x88,0x65,0x66,0x96,0x85,0x55,0x53,0xb0,0x4b,0x31,0x9b,0x0f,0xc9,0xb1,0x79,0x20,0xef,0xf8,0x8d,0xe0,0xc6,0x2f,0xc1,0x8c,0x75,0x16,0x20,0xf7,0x7e,0x18,0x97,0x3e,0x27,0x5c,0x2a,0x78,0x5a,0x94,0xfd,0x4e,0x5e,0x99,0xc6,0x76,0x35,0x3e,0x7d,0x23,0x1f,0x05,0xd8,0x2e,0x0f,0x99,0x0a,0xd5,0x82,0x1d,0xb8,0x4f,0x04,0xd9,0xe3,0x07,0xa9,0xc5,0x18,0xdf,0xc1,0x59,0x63,0x4c,0xce,0x1d,0x37,0xb3,0x57,0x49,0xbb,0x01,0xb2,0x34,0x45,0x70,0xca,0x2e,0xdd,0x30,0x9c,0x3f,0x82,0x79,0x7f}, + {0xe8,0x13,0xb5,0xa3,0x39,0xd2,0x34,0x83,0xd8,0xa8,0x1f,0xb9,0xd4,0x70,0x36,0xc1,0x33,0xbd,0x90,0xf5,0x36,0x41,0xb5,0x12,0xb4,0xd9,0x84,0xd7,0x73,0x03,0x4e,0x0a,0xba,0x87,0xf5,0x68,0xf0,0x1f,0x9c,0x6a,0xde,0xc8,0x50,0x00,0x4e,0x89,0x27,0x08,0xe7,0x5b,0xed,0x7d,0x55,0x99,0xbf,0x3c,0xf0,0xd6,0x06,0x1c,0x43,0xb0,0xa9,0x64,0x19,0x29,0x7d,0x5b,0xa1,0xd6,0xb3,0x2e,0x35,0x82,0x3a,0xd5,0xa0,0xf6,0xb4,0xb0,0x47,0x5d,0xa4,0x89,0x43,0xce,0x56,0x71,0x6c,0x34,0x18,0xce,0x0a,0x7d,0x1a,0x07}, + {0x0b,0xba,0x87,0xc8,0xaa,0x2d,0x07,0xd3,0xee,0x62,0xa5,0xbf,0x05,0x29,0x26,0x01,0x8b,0x76,0xef,0xc0,0x02,0x30,0x54,0xcf,0x9c,0x7e,0xea,0x46,0x71,0xcc,0x3b,0x2c,0x31,0x44,0xe1,0x20,0x52,0x35,0x0c,0xcc,0x41,0x51,0xb1,0x09,0x07,0x95,0x65,0x0d,0x36,0x5f,0x9d,0x20,0x1b,0x62,0xf5,0x9a,0xd3,0x55,0x77,0x61,0xf7,0xbc,0x69,0x7c,0x5f,0x29,0xe8,0x04,0xeb,0xd7,0xf0,0x07,0x7d,0xf3,0x50,0x2f,0x25,0x18,0xdb,0x10,0xd7,0x98,0x17,0x17,0xa3,0xa9,0x51,0xe9,0x1d,0xa5,0xac,0x22,0x73,0x9a,0x5a,0x6f}, + {0xc5,0xc6,0x41,0x2f,0x0c,0x00,0xa1,0x8b,0x9b,0xfb,0xfe,0x0c,0xc1,0x79,0x9f,0xc4,0x9f,0x1c,0xc5,0x3c,0x70,0x47,0xfa,0x4e,0xca,0xaf,0x47,0xe1,0xa2,0x21,0x4e,0x49,0xbe,0x44,0xd9,0xa3,0xeb,0xd4,0x29,0xe7,0x9e,0xaf,0x78,0x80,0x40,0x09,0x9e,0x8d,0x03,0x9c,0x86,0x47,0x7a,0x56,0x25,0x45,0x24,0x3b,0x8d,0xee,0x80,0x96,0xab,0x02,0x9a,0x0d,0xe5,0xdd,0x85,0x8a,0xa4,0xef,0x49,0xa2,0xb9,0x0f,0x4e,0x22,0x9a,0x21,0xd9,0xf6,0x1e,0xd9,0x1d,0x1f,0x09,0xfa,0x34,0xbb,0x46,0xea,0xcb,0x76,0x5d,0x6b}, + {0x94,0xd9,0x0c,0xec,0x6c,0x55,0x57,0x88,0xba,0x1d,0xd0,0x5c,0x6f,0xdc,0x72,0x64,0x77,0xb4,0x42,0x8f,0x14,0x69,0x01,0xaf,0x54,0x73,0x27,0x85,0xf6,0x33,0xe3,0x0a,0x22,0x25,0x78,0x1e,0x17,0x41,0xf9,0xe0,0xd3,0x36,0x69,0x03,0x74,0xae,0xe6,0xf1,0x46,0xc7,0xfc,0xd0,0xa2,0x3e,0x8b,0x40,0x3e,0x31,0xdd,0x03,0x9c,0x86,0xfb,0x16,0x62,0x09,0xb6,0x33,0x97,0x19,0x8e,0x28,0x33,0xe1,0xab,0xd8,0xb4,0x72,0xfc,0x24,0x3e,0xd0,0x91,0x09,0xed,0xf7,0x11,0x48,0x75,0xd0,0x70,0x8f,0x8b,0xe3,0x81,0x3f}, + {0xfe,0xaf,0xd9,0x7e,0xcc,0x0f,0x91,0x7f,0x4b,0x87,0x65,0x24,0xa1,0xb8,0x5c,0x54,0x04,0x47,0x0c,0x4b,0xd2,0x7e,0x39,0xa8,0x93,0x09,0xf5,0x04,0xc1,0x0f,0x51,0x50,0x24,0xc8,0x17,0x5f,0x35,0x7f,0xdb,0x0a,0xa4,0x99,0x42,0xd7,0xc3,0x23,0xb9,0x74,0xf7,0xea,0xf8,0xcb,0x8b,0x3e,0x7c,0xd5,0x3d,0xdc,0xde,0x4c,0xd3,0xe2,0xd3,0x0a,0x9d,0x24,0x6e,0x33,0xc5,0x0f,0x0c,0x6f,0xd9,0xcf,0x31,0xc3,0x19,0xde,0x5e,0x74,0x1c,0xfe,0xee,0x09,0x00,0xfd,0xd6,0xf2,0xbe,0x1e,0xfa,0xf0,0x8b,0x15,0x7c,0x12}, + {0xa2,0x79,0x98,0x2e,0x42,0x7c,0x19,0xf6,0x47,0x36,0xca,0x52,0xd4,0xdd,0x4a,0xa4,0xcb,0xac,0x4e,0x4b,0xc1,0x3f,0x41,0x9b,0x68,0x4f,0xef,0x07,0x7d,0xf8,0x4e,0x35,0x74,0xb9,0x51,0xae,0xc4,0x8f,0xa2,0xde,0x96,0xfe,0x4d,0x74,0xd3,0x73,0x99,0x1d,0xa8,0x48,0x38,0x87,0x0b,0x68,0x40,0x62,0x95,0xdf,0x67,0xd1,0x79,0x24,0xd8,0x4e,0x75,0xd9,0xc5,0x60,0x22,0xb5,0xe3,0xfe,0xb8,0xb0,0x41,0xeb,0xfc,0x2e,0x35,0x50,0x3c,0x65,0xf6,0xa9,0x30,0xac,0x08,0x88,0x6d,0x23,0x39,0x05,0xd2,0x92,0x2d,0x30}, + {0x3d,0x28,0xa4,0xbc,0xa2,0xc1,0x13,0x78,0xd9,0x3d,0x86,0xa1,0x91,0xf0,0x62,0xed,0x86,0xfa,0x68,0xc2,0xb8,0xbc,0xc7,0xae,0x4c,0xae,0x1c,0x6f,0xb7,0xd3,0xe5,0x10,0x77,0xf1,0xe0,0xe4,0xb6,0x6f,0xbc,0x2d,0x93,0x6a,0xbd,0xa4,0x29,0xbf,0xe1,0x04,0xe8,0xf6,0x7a,0x78,0xd4,0x66,0x19,0x5e,0x60,0xd0,0x26,0xb4,0x5e,0x5f,0xdc,0x0e,0x67,0x8e,0xda,0x53,0xd6,0xbf,0x53,0x54,0x41,0xf6,0xa9,0x24,0xec,0x1e,0xdc,0xe9,0x23,0x8a,0x57,0x03,0x3b,0x26,0x87,0xbf,0x72,0xba,0x1c,0x36,0x51,0x6c,0xb4,0x45}, + {0xa1,0x7f,0x4f,0x31,0xbf,0x2a,0x40,0xa9,0x50,0xf4,0x8c,0x8e,0xdc,0xf1,0x57,0xe2,0x84,0xbe,0xa8,0x23,0x4b,0xd5,0xbb,0x1d,0x3b,0x71,0xcb,0x6d,0xa3,0xbf,0x77,0x21,0xe4,0xe3,0x7f,0x8a,0xdd,0x4d,0x9d,0xce,0x30,0x0e,0x62,0x76,0x56,0x64,0x13,0xab,0x58,0x99,0x0e,0xb3,0x7b,0x4f,0x59,0x4b,0xdf,0x29,0x12,0x32,0xef,0x0a,0x1c,0x5c,0x8f,0xdb,0x79,0xfa,0xbc,0x1b,0x08,0x37,0xb3,0x59,0x5f,0xc2,0x1e,0x81,0x48,0x60,0x87,0x24,0x83,0x9c,0x65,0x76,0x7a,0x08,0xbb,0xb5,0x8a,0x7d,0x38,0x19,0xe6,0x4a}, + {0x2e,0xa3,0x44,0x53,0xaa,0xf6,0xdb,0x8d,0x78,0x40,0x1b,0xb4,0xb4,0xea,0x88,0x7d,0x60,0x0d,0x13,0x4a,0x97,0xeb,0xb0,0x5e,0x03,0x3e,0xbf,0x17,0x1b,0xd9,0x00,0x1a,0x83,0xfb,0x5b,0x98,0x44,0x7e,0x11,0x61,0x36,0x31,0x96,0x71,0x2a,0x46,0xe0,0xfc,0x4b,0x90,0x25,0xd4,0x48,0x34,0xac,0x83,0x64,0x3d,0xa4,0x5b,0xbe,0x5a,0x68,0x75,0xb2,0xf2,0x61,0xeb,0x33,0x09,0x96,0x6e,0x52,0x49,0xff,0xc9,0xa8,0x0f,0x3d,0x54,0x69,0x65,0xf6,0x7a,0x10,0x75,0x72,0xdf,0xaa,0xe6,0xb0,0x23,0xb6,0x29,0x55,0x13}, + {0x18,0xd5,0xd1,0xad,0xd7,0xdb,0xf0,0x18,0x11,0x1f,0xc1,0xcf,0x88,0x78,0x9f,0x97,0x9b,0x75,0x14,0x71,0xf0,0xe1,0x32,0x87,0x01,0x3a,0xca,0x65,0x1a,0xb8,0xb5,0x79,0xfe,0x83,0x2e,0xe2,0xbc,0x16,0xc7,0xf5,0xc1,0x85,0x09,0xe8,0x19,0xeb,0x2b,0xb4,0xae,0x4a,0x25,0x14,0x37,0xa6,0x9d,0xec,0x13,0xa6,0x90,0x15,0x05,0xea,0x72,0x59,0x11,0x78,0x8f,0xdc,0x20,0xac,0xd4,0x0f,0xa8,0x4f,0x4d,0xac,0x94,0xd2,0x9a,0x9a,0x34,0x04,0x36,0xb3,0x64,0x2d,0x1b,0xc0,0xdb,0x3b,0x5f,0x90,0x95,0x9c,0x7e,0x4f}, + {0x2e,0x30,0x81,0x57,0xbc,0x4b,0x67,0x62,0x0f,0xdc,0xad,0x89,0x39,0x0f,0x52,0xd8,0xc6,0xd9,0xfb,0x53,0xae,0x99,0x29,0x8c,0x4c,0x8e,0x63,0x2e,0xd9,0x3a,0x99,0x31,0xfe,0x99,0x52,0x35,0x3d,0x44,0xc8,0x71,0xd7,0xea,0xeb,0xdb,0x1c,0x3b,0xcd,0x8b,0x66,0x94,0xa4,0xf1,0x9e,0x49,0x92,0x80,0xc8,0xad,0x44,0xa1,0xc4,0xee,0x42,0x19,0x92,0x49,0x23,0xae,0x19,0x53,0xac,0x7d,0x92,0x3e,0xea,0x0c,0x91,0x3d,0x1b,0x2c,0x22,0x11,0x3c,0x25,0x94,0xe4,0x3c,0x55,0x75,0xca,0xf9,0x4e,0x31,0x65,0x0a,0x2a}, + {0xc2,0x27,0xf9,0xf7,0x7f,0x93,0xb7,0x2d,0x35,0xa6,0xd0,0x17,0x06,0x1f,0x74,0xdb,0x76,0xaf,0x55,0x11,0xa2,0xf3,0x82,0x59,0xed,0x2d,0x7c,0x64,0x18,0xe2,0xf6,0x4c,0x3a,0x79,0x1c,0x3c,0xcd,0x1a,0x36,0xcf,0x3b,0xbc,0x35,0x5a,0xac,0xbc,0x9e,0x2f,0xab,0xa6,0xcd,0xa8,0xe9,0x60,0xe8,0x60,0x13,0x1a,0xea,0x6d,0x9b,0xc3,0x5d,0x05,0xb6,0x5b,0x8d,0xc2,0x7c,0x22,0x19,0xb1,0xab,0xff,0x4d,0x77,0xbc,0x4e,0xe2,0x07,0x89,0x2c,0xa3,0xe4,0xce,0x78,0x3c,0xa8,0xb6,0x24,0xaa,0x10,0x77,0x30,0x1a,0x12}, + {0x97,0x4a,0x03,0x9f,0x5e,0x5d,0xdb,0xe4,0x2d,0xbc,0x34,0x30,0x09,0xfc,0x53,0xe1,0xb1,0xd3,0x51,0x95,0x91,0x46,0x05,0x46,0x2d,0xe5,0x40,0x7a,0x6c,0xc7,0x3f,0x33,0xc9,0x83,0x74,0xc7,0x3e,0x71,0x59,0xd6,0xaf,0x96,0x2b,0xb8,0x77,0xe0,0xbf,0x88,0xd3,0xbc,0x97,0x10,0x23,0x28,0x9e,0x28,0x9b,0x3a,0xed,0x6c,0x4a,0xb9,0x7b,0x52,0x2e,0x48,0x5b,0x99,0x2a,0x99,0x3d,0x56,0x01,0x38,0x38,0x6e,0x7c,0xd0,0x05,0x34,0xe5,0xd8,0x64,0x2f,0xde,0x35,0x50,0x48,0xf7,0xa9,0xa7,0x20,0x9b,0x06,0x89,0x6b}, + {0x0d,0x22,0x70,0x62,0x41,0xa0,0x2a,0x81,0x4e,0x5b,0x24,0xf9,0xfa,0x89,0x5a,0x99,0x05,0xef,0x72,0x50,0xce,0xc4,0xad,0xff,0x73,0xeb,0x73,0xaa,0x03,0x21,0xbc,0x23,0x77,0xdb,0xc7,0xb5,0x8c,0xfa,0x82,0x40,0x55,0xc1,0x34,0xc7,0xf8,0x86,0x86,0x06,0x7e,0xa5,0xe7,0xf6,0xd9,0xc8,0xe6,0x29,0xcf,0x9b,0x63,0xa7,0x08,0xd3,0x73,0x04,0x05,0x9e,0x58,0x03,0x26,0x79,0xee,0xca,0x92,0xc4,0xdc,0x46,0x12,0x42,0x4b,0x2b,0x4f,0xa9,0x01,0xe6,0x74,0xef,0xa1,0x02,0x1a,0x34,0x04,0xde,0xbf,0x73,0x2f,0x10}, + {0xc6,0x45,0x57,0x7f,0xab,0xb9,0x18,0xeb,0x90,0xc6,0x87,0x57,0xee,0x8a,0x3a,0x02,0xa9,0xaf,0xf7,0x2d,0xda,0x12,0x27,0xb7,0x3d,0x01,0x5c,0xea,0x25,0x7d,0x59,0x36,0x9a,0x1c,0x51,0xb5,0xe0,0xda,0xb4,0xa2,0x06,0xff,0xff,0x2b,0x29,0x60,0xc8,0x7a,0x34,0x42,0x50,0xf5,0x5d,0x37,0x1f,0x98,0x2d,0xa1,0x4e,0xda,0x25,0xd7,0x6b,0x3f,0xac,0x58,0x60,0x10,0x7b,0x8d,0x4d,0x73,0x5f,0x90,0xc6,0x6f,0x9e,0x57,0x40,0xd9,0x2d,0x93,0x02,0x92,0xf9,0xf8,0x66,0x64,0xd0,0xd6,0x60,0xda,0x19,0xcc,0x7e,0x7b}, + {0x0d,0x69,0x5c,0x69,0x3c,0x37,0xc2,0x78,0x6e,0x90,0x42,0x06,0x66,0x2e,0x25,0xdd,0xd2,0x2b,0xe1,0x4a,0x44,0x44,0x1d,0x95,0x56,0x39,0x74,0x01,0x76,0xad,0x35,0x42,0x9b,0xfa,0x7c,0xa7,0x51,0x4a,0xae,0x6d,0x50,0x86,0xa3,0xe7,0x54,0x36,0x26,0x82,0xdb,0x82,0x2d,0x8f,0xcd,0xff,0xbb,0x09,0xba,0xca,0xf5,0x1b,0x66,0xdc,0xbe,0x03,0xf5,0x75,0x89,0x07,0x0d,0xcb,0x58,0x62,0x98,0xf2,0x89,0x91,0x54,0x42,0x29,0x49,0xe4,0x6e,0xe3,0xe2,0x23,0xb4,0xca,0xa0,0xa1,0x66,0xf0,0xcd,0xb0,0xe2,0x7c,0x0e}, + {0xa3,0x85,0x8c,0xc4,0x3a,0x64,0x94,0xc4,0xad,0x39,0x61,0x3c,0xf4,0x1d,0x36,0xfd,0x48,0x4d,0xe9,0x3a,0xdd,0x17,0xdb,0x09,0x4a,0x67,0xb4,0x8f,0x5d,0x0a,0x6e,0x66,0xf9,0x70,0x4b,0xd9,0xdf,0xfe,0xa6,0xfe,0x2d,0xba,0xfc,0xc1,0x51,0xc0,0x30,0xf1,0x89,0xab,0x2f,0x7f,0x7e,0xd4,0x82,0x48,0xb5,0xee,0xec,0x8a,0x13,0x56,0x52,0x61,0x0d,0xcb,0x70,0x48,0x4e,0xf6,0xbb,0x2a,0x6b,0x8b,0x45,0xaa,0xf0,0xbc,0x65,0xcd,0x5d,0x98,0xe8,0x75,0xba,0x4e,0xbe,0x9a,0xe4,0xde,0x14,0xd5,0x10,0xc8,0x0b,0x7f}, + {0x6f,0x13,0xf4,0x26,0xa4,0x6b,0x00,0xb9,0x35,0x30,0xe0,0x57,0x9e,0x36,0x67,0x8d,0x28,0x3c,0x46,0x4f,0xd9,0xdf,0xc8,0xcb,0xf5,0xdb,0xee,0xf8,0xbc,0x8d,0x1f,0x0d,0xa0,0x13,0x72,0x73,0xad,0x9d,0xac,0x83,0x98,0x2e,0xf7,0x2e,0xba,0xf8,0xf6,0x9f,0x57,0x69,0xec,0x43,0xdd,0x2e,0x1e,0x31,0x75,0xab,0xc5,0xde,0x7d,0x90,0x3a,0x1d,0xdc,0x81,0xd0,0x3e,0x31,0x93,0x16,0xba,0x80,0x34,0x1b,0x85,0xad,0x9f,0x32,0x29,0xcb,0x21,0x03,0x03,0x3c,0x01,0x28,0x01,0xe3,0xfd,0x1b,0xa3,0x44,0x1b,0x01,0x00}, + {0x0c,0x6c,0xc6,0x3f,0x6c,0xa0,0xdf,0x3f,0xd2,0x0d,0xd6,0x4d,0x8e,0xe3,0x40,0x5d,0x71,0x4d,0x8e,0x26,0x38,0x8b,0xe3,0x7a,0xe1,0x57,0x83,0x6e,0x91,0x8d,0xc4,0x3a,0x5c,0xa7,0x0a,0x6a,0x69,0x1f,0x56,0x16,0x6a,0xbd,0x52,0x58,0x5c,0x72,0xbf,0xc1,0xad,0x66,0x79,0x9a,0x7f,0xdd,0xa8,0x11,0x26,0x10,0x85,0xd2,0xa2,0x88,0xd9,0x63,0x2e,0x23,0xbd,0xaf,0x53,0x07,0x12,0x00,0x83,0xf6,0xd8,0xfd,0xb8,0xce,0x2b,0xe9,0x91,0x2b,0xe7,0x84,0xb3,0x69,0x16,0xf8,0x66,0xa0,0x68,0x23,0x2b,0xd5,0xfa,0x33}, + {0x16,0x1e,0xe4,0xc5,0xc6,0x49,0x06,0x54,0x35,0x77,0x3f,0x33,0x30,0x64,0xf8,0x0a,0x46,0xe7,0x05,0xf3,0xd2,0xfc,0xac,0xb2,0xa7,0xdc,0x56,0xa2,0x29,0xf4,0xc0,0x16,0xe8,0xcf,0x22,0xc4,0xd0,0xc8,0x2c,0x8d,0xcb,0x3a,0xa1,0x05,0x7b,0x4f,0x2b,0x07,0x6f,0xa5,0xf6,0xec,0xe6,0xb6,0xfe,0xa3,0xe2,0x71,0x0a,0xb9,0xcc,0x55,0xc3,0x3c,0x31,0x91,0x3e,0x90,0x43,0x94,0xb6,0xe9,0xce,0x37,0x56,0x7a,0xcb,0x94,0xa4,0xb8,0x44,0x92,0xba,0xba,0xa4,0xd1,0x7c,0xc8,0x68,0x75,0xae,0x6b,0x42,0xaf,0x1e,0x63}, + {0x9f,0xfe,0x66,0xda,0x10,0x04,0xe9,0xb3,0xa6,0xe5,0x16,0x6c,0x52,0x4b,0xdd,0x85,0x83,0xbf,0xf9,0x1e,0x61,0x97,0x3d,0xbc,0xb5,0x19,0xa9,0x1e,0x8b,0x64,0x99,0x55,0xe8,0x0d,0x70,0xa3,0xb9,0x75,0xd9,0x47,0x52,0x05,0xf8,0xe2,0xfb,0xc5,0x80,0x72,0xe1,0x5d,0xe4,0x32,0x27,0x8f,0x65,0x53,0xb5,0x80,0x5f,0x66,0x7f,0x2c,0x1f,0x43,0x19,0x7b,0x8f,0x85,0x44,0x63,0x02,0xd6,0x4a,0x51,0xea,0xa1,0x2f,0x35,0xab,0x14,0xd7,0xa9,0x90,0x20,0x1a,0x44,0x00,0x89,0x26,0x3b,0x25,0x91,0x5f,0x71,0x04,0x7b}, + {0x43,0xae,0xf6,0xac,0x28,0xbd,0xed,0x83,0xb4,0x7a,0x5c,0x7d,0x8b,0x7c,0x35,0x86,0x44,0x2c,0xeb,0xb7,0x69,0x47,0x40,0xc0,0x3f,0x58,0xf6,0xc2,0xf5,0x7b,0xb3,0x59,0xc6,0xba,0xe6,0xc4,0x80,0xc2,0x76,0xb3,0x0b,0x9b,0x1d,0x6d,0xdd,0xd3,0x0e,0x97,0x44,0xf9,0x0b,0x45,0x58,0x95,0x9a,0xb0,0x23,0xe2,0xcd,0x57,0xfa,0xac,0xd0,0x48,0x71,0xe6,0xab,0x7d,0xe4,0x26,0x0f,0xb6,0x37,0x3a,0x2f,0x62,0x97,0xa1,0xd1,0xf1,0x94,0x03,0x96,0xe9,0x7e,0xce,0x08,0x42,0xdb,0x3b,0x6d,0x33,0x91,0x41,0x23,0x16}, + {0xf6,0x7f,0x26,0xf6,0xde,0x99,0xe4,0xb9,0x43,0x08,0x2c,0x74,0x7b,0xca,0x72,0x77,0xb1,0xf2,0xa4,0xe9,0x3f,0x15,0xa0,0x23,0x06,0x50,0xd0,0xd5,0xec,0xdf,0xdf,0x2c,0x40,0x86,0xf3,0x1f,0xd6,0x9c,0x49,0xdd,0xa0,0x25,0x36,0x06,0xc3,0x9b,0xcd,0x29,0xc3,0x3d,0xd7,0x3d,0x02,0xd8,0xe2,0x51,0x31,0x92,0x3b,0x20,0x7a,0x70,0x25,0x4a,0x6a,0xed,0xf6,0x53,0x8a,0x66,0xb7,0x2a,0xa1,0x70,0xd1,0x1d,0x58,0x42,0x42,0x30,0x61,0x01,0xe2,0x3a,0x4c,0x14,0x00,0x40,0xfc,0x49,0x8e,0x24,0x6d,0x89,0x21,0x57}, + {0xae,0x1b,0x18,0xfd,0x17,0x55,0x6e,0x0b,0xb4,0x63,0xb9,0x2b,0x9f,0x62,0x22,0x90,0x25,0x46,0x06,0x32,0xe9,0xbc,0x09,0x55,0xda,0x13,0x3c,0xf6,0x74,0xdd,0x8e,0x57,0x4e,0xda,0xd0,0xa1,0x91,0x50,0x5d,0x28,0x08,0x3e,0xfe,0xb5,0xa7,0x6f,0xaa,0x4b,0xb3,0x93,0x93,0xe1,0x7c,0x17,0xe5,0x63,0xfd,0x30,0xb0,0xc4,0xaf,0x35,0xc9,0x03,0x3d,0x0c,0x2b,0x49,0xc6,0x76,0x72,0x99,0xfc,0x05,0xe2,0xdf,0xc4,0xc2,0xcc,0x47,0x3c,0x3a,0x62,0xdd,0x84,0x9b,0xd2,0xdc,0xa2,0xc7,0x88,0x02,0x59,0xab,0xc2,0x3e}, + {0xb9,0x7b,0xd8,0xe4,0x7b,0xd2,0xa0,0xa1,0xed,0x1a,0x39,0x61,0xeb,0x4d,0x8b,0xa9,0x83,0x9b,0xcb,0x73,0xd0,0xdd,0xa0,0x99,0xce,0xca,0x0f,0x20,0x5a,0xc2,0xd5,0x2d,0xcb,0xd1,0x32,0xae,0x09,0x3a,0x21,0xa7,0xd5,0xc2,0xf5,0x40,0xdf,0x87,0x2b,0x0f,0x29,0xab,0x1e,0xe8,0xc6,0xa4,0xae,0x0b,0x5e,0xac,0xdb,0x6a,0x6c,0xf6,0x1b,0x0e,0x7e,0x88,0x2c,0x79,0xe9,0xd5,0xab,0xe2,0x5d,0x6d,0x92,0xcb,0x18,0x00,0x02,0x1a,0x1e,0x5f,0xae,0xba,0xcd,0x69,0xba,0xbf,0x5f,0x8f,0xe8,0x5a,0xb3,0x48,0x05,0x73}, + {0xee,0xb8,0xa8,0xcb,0xa3,0x51,0x35,0xc4,0x16,0x5f,0x11,0xb2,0x1d,0x6f,0xa2,0x65,0x50,0x38,0x8c,0xab,0x52,0x4f,0x0f,0x76,0xca,0xb8,0x1d,0x41,0x3b,0x44,0x43,0x30,0x34,0xe3,0xd6,0xa1,0x4b,0x09,0x5b,0x80,0x19,0x3f,0x35,0x09,0x77,0xf1,0x3e,0xbf,0x2b,0x70,0x22,0x06,0xcb,0x06,0x3f,0x42,0xdd,0x45,0x78,0xd8,0x77,0x22,0x5a,0x58,0x62,0x89,0xd4,0x33,0x82,0x5f,0x8a,0xa1,0x7f,0x25,0x78,0xec,0xb5,0xc4,0x98,0x66,0xff,0x41,0x3e,0x37,0xa5,0x6f,0x8e,0xa7,0x1f,0x98,0xef,0x50,0x89,0x27,0x56,0x76}, + {0xc0,0xc8,0x1f,0xd5,0x59,0xcf,0xc3,0x38,0xf2,0xb6,0x06,0x05,0xfd,0xd2,0xed,0x9b,0x8f,0x0e,0x57,0xab,0x9f,0x10,0xbf,0x26,0xa6,0x46,0xb8,0xc1,0xa8,0x60,0x41,0x3f,0x9d,0xcf,0x86,0xea,0xa3,0x73,0x70,0xe1,0xdc,0x5f,0x15,0x07,0xb7,0xfb,0x8c,0x3a,0x8e,0x8a,0x83,0x31,0xfc,0xe7,0x53,0x48,0x16,0xf6,0x13,0xb6,0x84,0xf4,0xbb,0x28,0x7c,0x6c,0x13,0x6f,0x5c,0x2f,0x61,0xf2,0xbe,0x11,0xdd,0xf6,0x07,0xd1,0xea,0xaf,0x33,0x6f,0xde,0x13,0xd2,0x9a,0x7e,0x52,0x5d,0xf7,0x88,0x81,0x35,0xcb,0x79,0x1e}, + {0xf1,0xe3,0xf7,0xee,0xc3,0x36,0x34,0x01,0xf8,0x10,0x9e,0xfe,0x7f,0x6a,0x8b,0x82,0xfc,0xde,0xf9,0xbc,0xe5,0x08,0xf9,0x7f,0x31,0x38,0x3b,0x3a,0x1b,0x95,0xd7,0x65,0x81,0x81,0xe0,0xf5,0xd8,0x53,0xe9,0x77,0xd9,0xde,0x9d,0x29,0x44,0x0c,0xa5,0x84,0xe5,0x25,0x45,0x86,0x0c,0x2d,0x6c,0xdc,0xf4,0xf2,0xd1,0x39,0x2d,0xb5,0x8a,0x47,0x59,0xd1,0x52,0x92,0xd3,0xa4,0xa6,0x66,0x07,0xc8,0x1a,0x87,0xbc,0xe1,0xdd,0xe5,0x6f,0xc9,0xc1,0xa6,0x40,0x6b,0x2c,0xb8,0x14,0x22,0x21,0x1a,0x41,0x7a,0xd8,0x16}, + {0x15,0x62,0x06,0x42,0x5a,0x7e,0xbd,0xb3,0xc1,0x24,0x5a,0x0c,0xcd,0xe3,0x9b,0x87,0xb7,0x94,0xf9,0xd6,0xb1,0x5d,0xc0,0x57,0xa6,0x8c,0xf3,0x65,0x81,0x7c,0xf8,0x28,0x83,0x05,0x4e,0xd5,0xe2,0xd5,0xa4,0xfb,0xfa,0x99,0xbd,0x2e,0xd7,0xaf,0x1f,0xe2,0x8f,0x77,0xe9,0x6e,0x73,0xc2,0x7a,0x49,0xde,0x6d,0x5a,0x7a,0x57,0x0b,0x99,0x1f,0xd6,0xf7,0xe8,0x1b,0xad,0x4e,0x34,0xa3,0x8f,0x79,0xea,0xac,0xeb,0x50,0x1e,0x7d,0x52,0xe0,0x0d,0x52,0x9e,0x56,0xc6,0x77,0x3e,0x6d,0x4d,0x53,0xe1,0x2f,0x88,0x45}, + {0xd6,0x83,0x79,0x75,0x5d,0x34,0x69,0x66,0xa6,0x11,0xaa,0x17,0x11,0xed,0xb6,0x62,0x8f,0x12,0x5e,0x98,0x57,0x18,0xdd,0x7d,0xdd,0xf6,0x26,0xf6,0xb8,0xe5,0x8f,0x68,0xe4,0x6f,0x3c,0x94,0x29,0x99,0xac,0xd8,0xa2,0x92,0x83,0xa3,0x61,0xf1,0xf9,0xb5,0xf3,0x9a,0xc8,0xbe,0x13,0xdb,0x99,0x26,0x74,0xf0,0x05,0xe4,0x3c,0x84,0xcf,0x7d,0xc0,0x32,0x47,0x4a,0x48,0xd6,0x90,0x6c,0x99,0x32,0x56,0xca,0xfd,0x43,0x21,0xd5,0xe1,0xc6,0x5d,0x91,0xc3,0x28,0xbe,0xb3,0x1b,0x19,0x27,0x73,0x7e,0x68,0x39,0x67}, + {0xa6,0x75,0x56,0x38,0x14,0x20,0x78,0xef,0xe8,0xa9,0xfd,0xaa,0x30,0x9f,0x64,0xa2,0xcb,0xa8,0xdf,0x5c,0x50,0xeb,0xd1,0x4c,0xb3,0xc0,0x4d,0x1d,0xba,0x5a,0x11,0x46,0xc0,0x1a,0x0c,0xc8,0x9d,0xcc,0x6d,0xa6,0x36,0xa4,0x38,0x1b,0xf4,0x5c,0xa0,0x97,0xc6,0xd7,0xdb,0x95,0xbe,0xf3,0xeb,0xa7,0xab,0x7d,0x7e,0x8d,0xf6,0xb8,0xa0,0x7d,0x76,0xda,0xb5,0xc3,0x53,0x19,0x0f,0xd4,0x9b,0x9e,0x11,0x21,0x73,0x6f,0xac,0x1d,0x60,0x59,0xb2,0xfe,0x21,0x60,0xcc,0x03,0x4b,0x4b,0x67,0x83,0x7e,0x88,0x5f,0x5a}, + {0x11,0x3d,0xa1,0x70,0xcf,0x01,0x63,0x8f,0xc4,0xd0,0x0d,0x35,0x15,0xb8,0xce,0xcf,0x7e,0xa4,0xbc,0xa4,0xd4,0x97,0x02,0xf7,0x34,0x14,0x4d,0xe4,0x56,0xb6,0x69,0x36,0xb9,0x43,0xa6,0xa0,0xd3,0x28,0x96,0x9e,0x64,0x20,0xc3,0xe6,0x00,0xcb,0xc3,0xb5,0x32,0xec,0x2d,0x7c,0x89,0x02,0x53,0x9b,0x0c,0xc7,0xd1,0xd5,0xe2,0x7a,0xe3,0x43,0x33,0xe1,0xa6,0xed,0x06,0x3f,0x7e,0x38,0xc0,0x3a,0xa1,0x99,0x51,0x1d,0x30,0x67,0x11,0x38,0x26,0x36,0xf8,0xd8,0x5a,0xbd,0xbe,0xe9,0xd5,0x4f,0xcd,0xe6,0x21,0x6a}, + {0x5f,0xe6,0x46,0x30,0x0a,0x17,0xc6,0xf1,0x24,0x35,0xd2,0x00,0x2a,0x2a,0x71,0x58,0x55,0xb7,0x82,0x8c,0x3c,0xbd,0xdb,0x69,0x57,0xff,0x95,0xa1,0xf1,0xf9,0x6b,0x58,0xe3,0xb2,0x99,0x66,0x12,0x29,0x41,0xef,0x01,0x13,0x8d,0x70,0x47,0x08,0xd3,0x71,0xbd,0xb0,0x82,0x11,0xd0,0x32,0x54,0x32,0x36,0x8b,0x1e,0x00,0x07,0x1b,0x37,0x45,0x0b,0x79,0xf8,0x5e,0x8d,0x08,0xdb,0xa6,0xe5,0x37,0x09,0x61,0xdc,0xf0,0x78,0x52,0xb8,0x6e,0xa1,0x61,0xd2,0x49,0x03,0xac,0x79,0x21,0xe5,0x90,0x37,0xb0,0xaf,0x0e}, + {0x2f,0x04,0x48,0x37,0xc1,0x55,0x05,0x96,0x11,0xaa,0x0b,0x82,0xe6,0x41,0x9a,0x21,0x0c,0x6d,0x48,0x73,0x38,0xf7,0x81,0x1c,0x61,0xc6,0x02,0x5a,0x67,0xcc,0x9a,0x30,0x1d,0xae,0x75,0x0f,0x5e,0x80,0x40,0x51,0x30,0xcc,0x62,0x26,0xe3,0xfb,0x02,0xec,0x6d,0x39,0x92,0xea,0x1e,0xdf,0xeb,0x2c,0xb3,0x5b,0x43,0xc5,0x44,0x33,0xae,0x44,0xee,0x43,0xa5,0xbb,0xb9,0x89,0xf2,0x9c,0x42,0x71,0xc9,0x5a,0x9d,0x0e,0x76,0xf3,0xaa,0x60,0x93,0x4f,0xc6,0xe5,0x82,0x1d,0x8f,0x67,0x94,0x7f,0x1b,0x22,0xd5,0x62}, + {0x6d,0x93,0xd0,0x18,0x9c,0x29,0x4c,0x52,0x0c,0x1a,0x0c,0x8a,0x6c,0xb5,0x6b,0xc8,0x31,0x86,0x4a,0xdb,0x2e,0x05,0x75,0xa3,0x62,0x45,0x75,0xbc,0xe4,0xfd,0x0e,0x5c,0x3c,0x7a,0xf7,0x3a,0x26,0xd4,0x85,0x75,0x4d,0x14,0xe9,0xfe,0x11,0x7b,0xae,0xdf,0x3d,0x19,0xf7,0x59,0x80,0x70,0x06,0xa5,0x37,0x20,0x92,0x83,0x53,0x9a,0xf2,0x14,0xf5,0xd7,0xb2,0x25,0xdc,0x7e,0x71,0xdf,0x40,0x30,0xb5,0x99,0xdb,0x70,0xf9,0x21,0x62,0x4c,0xed,0xc3,0xb7,0x34,0x92,0xda,0x3e,0x09,0xee,0x7b,0x5c,0x36,0x72,0x5e}, + {0x7f,0x21,0x71,0x45,0x07,0xfc,0x5b,0x57,0x5b,0xd9,0x94,0x06,0x5d,0x67,0x79,0x37,0x33,0x1e,0x19,0xf4,0xbb,0x37,0x0a,0x9a,0xbc,0xea,0xb4,0x47,0x4c,0x10,0xf1,0x77,0x3e,0xb3,0x08,0x2f,0x06,0x39,0x93,0x7d,0xbe,0x32,0x9f,0xdf,0xe5,0x59,0x96,0x5b,0xfd,0xbd,0x9e,0x1f,0xad,0x3d,0xff,0xac,0xb7,0x49,0x73,0xcb,0x55,0x05,0xb2,0x70,0x4c,0x2c,0x11,0x55,0xc5,0x13,0x51,0xbe,0xcd,0x1f,0x88,0x9a,0x3a,0x42,0x88,0x66,0x47,0x3b,0x50,0x5e,0x85,0x77,0x66,0x44,0x4a,0x40,0x06,0x4a,0x8f,0x39,0x34,0x0e}, + {0xe8,0xbd,0xce,0x3e,0xd9,0x22,0x7d,0xb6,0x07,0x2f,0x82,0x27,0x41,0xe8,0xb3,0x09,0x8d,0x6d,0x5b,0xb0,0x1f,0xa6,0x3f,0x74,0x72,0x23,0x36,0x8a,0x36,0x05,0x54,0x5e,0x28,0x19,0x4b,0x3e,0x09,0x0b,0x93,0x18,0x40,0xf6,0xf3,0x73,0x0e,0xe1,0xe3,0x7d,0x6f,0x5d,0x39,0x73,0xda,0x17,0x32,0xf4,0x3e,0x9c,0x37,0xca,0xd6,0xde,0x8a,0x6f,0x9a,0xb2,0xb7,0xfd,0x3d,0x12,0x40,0xe3,0x91,0xb2,0x1a,0xa2,0xe1,0x97,0x7b,0x48,0x9e,0x94,0xe6,0xfd,0x02,0x7d,0x96,0xf9,0x97,0xde,0xd3,0xc8,0x2e,0xe7,0x0d,0x78}, + {0xbc,0xe7,0x9a,0x08,0x45,0x85,0xe2,0x0a,0x06,0x4d,0x7f,0x1c,0xcf,0xde,0x8d,0x38,0xb8,0x11,0x48,0x0a,0x51,0x15,0xac,0x38,0xe4,0x8c,0x92,0x71,0xf6,0x8b,0xb2,0x0e,0x72,0x27,0xf4,0x00,0xf3,0xea,0x1f,0x67,0xaa,0x41,0x8c,0x2a,0x2a,0xeb,0x72,0x8f,0x92,0x32,0x37,0x97,0xd7,0x7f,0xa1,0x29,0xa6,0x87,0xb5,0x32,0xad,0xc6,0xef,0x1d,0xa7,0x95,0x51,0xef,0x1a,0xbe,0x5b,0xaf,0xed,0x15,0x7b,0x91,0x77,0x12,0x8c,0x14,0x2e,0xda,0xe5,0x7a,0xfb,0xf7,0x91,0x29,0x67,0x28,0xdd,0xf8,0x1b,0x20,0x7d,0x46}, + {0xad,0x4f,0xef,0x74,0x9a,0x91,0xfe,0x95,0xa2,0x08,0xa3,0xf6,0xec,0x7b,0x82,0x3a,0x01,0x7b,0xa4,0x09,0xd3,0x01,0x4e,0x96,0x97,0xc7,0xa3,0x5b,0x4f,0x3c,0xc4,0x71,0xa9,0xe7,0x7a,0x56,0xbd,0xf4,0x1e,0xbc,0xbd,0x98,0x44,0xd6,0xb2,0x4c,0x62,0x3f,0xc8,0x4e,0x1f,0x2c,0xd2,0x64,0x10,0xe4,0x01,0x40,0x38,0xba,0xa5,0xc5,0xf9,0x2e,0xcd,0x74,0x9e,0xfa,0xf6,0x6d,0xfd,0xb6,0x7a,0x26,0xaf,0xe4,0xbc,0x78,0x82,0xf1,0x0e,0x99,0xef,0xf1,0xd0,0xb3,0x55,0x82,0x93,0xf2,0xc5,0x90,0xa3,0x8c,0x75,0x5a}, + {0x95,0x24,0x46,0xd9,0x10,0x27,0xb7,0xa2,0x03,0x50,0x7d,0xd5,0xd2,0xc6,0xa8,0x3a,0xca,0x87,0xb4,0xa0,0xbf,0x00,0xd4,0xe3,0xec,0x72,0xeb,0xb3,0x44,0xe2,0xba,0x2d,0x94,0xdc,0x61,0x1d,0x8b,0x91,0xe0,0x8c,0x66,0x30,0x81,0x9a,0x46,0x36,0xed,0x8d,0xd3,0xaa,0xe8,0xaf,0x29,0xa8,0xe6,0xd4,0x3f,0xd4,0x39,0xf6,0x27,0x80,0x73,0x0a,0xcc,0xe1,0xff,0x57,0x2f,0x4a,0x0f,0x98,0x43,0x98,0x83,0xe1,0x0d,0x0d,0x67,0x00,0xfd,0x15,0xfb,0x49,0x4a,0x3f,0x5c,0x10,0x9c,0xa6,0x26,0x51,0x63,0xca,0x98,0x26}, + {0x78,0xba,0xb0,0x32,0x88,0x31,0x65,0xe7,0x8b,0xff,0x5c,0x92,0xf7,0x31,0x18,0x38,0xcc,0x1f,0x29,0xa0,0x91,0x1b,0xa8,0x08,0x07,0xeb,0xca,0x49,0xcc,0x3d,0xb4,0x1f,0x0e,0xd9,0x3d,0x5e,0x2f,0x70,0x3d,0x2e,0x86,0x53,0xd2,0xe4,0x18,0x09,0x3f,0x9e,0x6a,0xa9,0x4d,0x02,0xf6,0x3e,0x77,0x5e,0x32,0x33,0xfa,0x4a,0x0c,0x4b,0x00,0x3c,0x2b,0xb8,0xf4,0x06,0xac,0x46,0xa9,0x9a,0xf3,0xc4,0x06,0xa8,0xa5,0x84,0xa2,0x1c,0x87,0x47,0xcd,0xc6,0x5f,0x26,0xd3,0x3e,0x17,0xd2,0x1f,0xcd,0x01,0xfd,0x43,0x6b}, + {0x44,0xc5,0x97,0x46,0x4b,0x5d,0xa7,0xc7,0xbf,0xff,0x0f,0xdf,0x48,0xf8,0xfd,0x15,0x5a,0x78,0x46,0xaa,0xeb,0xb9,0x68,0x28,0x14,0xf7,0x52,0x5b,0x10,0xd7,0x68,0x5a,0xf3,0x0e,0x76,0x3e,0x58,0x42,0xc7,0xb5,0x90,0xb9,0x0a,0xee,0xb9,0x52,0xdc,0x75,0x3f,0x92,0x2b,0x07,0xc2,0x27,0x14,0xbf,0xf0,0xd9,0xf0,0x6f,0x2d,0x0b,0x42,0x73,0x06,0x1e,0x85,0x9e,0xcb,0xf6,0x2c,0xaf,0xc4,0x38,0x22,0xc6,0x13,0x39,0x59,0x8f,0x73,0xf3,0xfb,0x99,0x96,0xb8,0x8a,0xda,0x9e,0xbc,0x34,0xea,0x2f,0x63,0xb5,0x3d}, + {0xd8,0xd9,0x5d,0xf7,0x2b,0xee,0x6e,0xf4,0xa5,0x59,0x67,0x39,0xf6,0xb1,0x17,0x0d,0x73,0x72,0x9e,0x49,0x31,0xd1,0xf2,0x1b,0x13,0x5f,0xd7,0x49,0xdf,0x1a,0x32,0x04,0xd5,0x25,0x98,0x82,0xb1,0x90,0x49,0x2e,0x91,0x89,0x9a,0x3e,0x87,0xeb,0xea,0xed,0xf8,0x4a,0x70,0x4c,0x39,0x3d,0xf0,0xee,0x0e,0x2b,0xdf,0x95,0xa4,0x7e,0x19,0x59,0xae,0x5a,0xe5,0xe4,0x19,0x60,0xe1,0x04,0xe9,0x92,0x2f,0x7e,0x7a,0x43,0x7b,0xe7,0xa4,0x9a,0x15,0x6f,0xc1,0x2d,0xce,0xc7,0xc0,0x0c,0xd7,0xf4,0xc1,0xfd,0xea,0x45}, + {0x2b,0xd7,0x45,0x80,0x85,0x01,0x84,0x69,0x51,0x06,0x2f,0xcf,0xa2,0xfa,0x22,0x4c,0xc6,0x2d,0x22,0x6b,0x65,0x36,0x1a,0x94,0xde,0xda,0x62,0x03,0xc8,0xeb,0x5e,0x5a,0xed,0xb1,0xcc,0xcf,0x24,0x46,0x0e,0xb6,0x95,0x03,0x5c,0xbd,0x92,0xc2,0xdb,0x59,0xc9,0x81,0x04,0xdc,0x1d,0x9d,0xa0,0x31,0x40,0xd9,0x56,0x5d,0xea,0xce,0x73,0x3f,0xc6,0x8d,0x4e,0x0a,0xd1,0xbf,0xa7,0xb7,0x39,0xb3,0xc9,0x44,0x7e,0x00,0x57,0xbe,0xfa,0xae,0x57,0x15,0x7f,0x20,0xc1,0x60,0xdb,0x18,0x62,0x26,0x91,0x88,0x05,0x26}, + {0x04,0xff,0x60,0x83,0xa6,0x04,0xf7,0x59,0xf4,0xe6,0x61,0x76,0xde,0x3f,0xd9,0xc3,0x51,0x35,0x87,0x12,0x73,0x2a,0x1b,0x83,0x57,0x5d,0x61,0x4e,0x2e,0x0c,0xad,0x54,0x42,0xe5,0x76,0xc6,0x3c,0x8e,0x81,0x4c,0xad,0xcc,0xce,0x03,0x93,0x2c,0x42,0x5e,0x08,0x9f,0x12,0xb4,0xca,0xcc,0x07,0xec,0xb8,0x43,0x44,0xb2,0x10,0xfa,0xed,0x0d,0x2a,0x52,0x2b,0xb8,0xd5,0x67,0x3b,0xee,0xeb,0xc1,0xa5,0x9f,0x46,0x63,0xf1,0x36,0xd3,0x9f,0xc1,0x6e,0xf2,0xd2,0xb4,0xa5,0x08,0x94,0x7a,0xa7,0xba,0xb2,0xec,0x62}, + {0x3d,0x2b,0x15,0x61,0x52,0x79,0xed,0xe5,0xd1,0xd7,0xdd,0x0e,0x7d,0x35,0x62,0x49,0x71,0x4c,0x6b,0xb9,0xd0,0xc8,0x82,0x74,0xbe,0xd8,0x66,0xa9,0x19,0xf9,0x59,0x2e,0x74,0x28,0xb6,0xaf,0x36,0x28,0x07,0x92,0xa5,0x04,0xe1,0x79,0x85,0x5e,0xcd,0x5f,0x4a,0xa1,0x30,0xc6,0xad,0x01,0xad,0x5a,0x98,0x3f,0x66,0x75,0x50,0x3d,0x91,0x61,0xda,0x31,0x32,0x1a,0x36,0x2d,0xc6,0x0d,0x70,0x02,0x20,0x94,0x32,0x58,0x47,0xfa,0xce,0x94,0x95,0x3f,0x51,0x01,0xd8,0x02,0x5c,0x5d,0xc0,0x31,0xa1,0xc2,0xdb,0x3d}, + {0x4b,0xc5,0x5e,0xce,0xf9,0x0f,0xdc,0x9a,0x0d,0x13,0x2f,0x8c,0x6b,0x2a,0x9c,0x03,0x15,0x95,0xf8,0xf0,0xc7,0x07,0x80,0x02,0x6b,0xb3,0x04,0xac,0x14,0x83,0x96,0x78,0x14,0xbb,0x96,0x27,0xa2,0x57,0xaa,0xf3,0x21,0xda,0x07,0x9b,0xb7,0xba,0x3a,0x88,0x1c,0x39,0xa0,0x31,0x18,0xe2,0x4b,0xe5,0xf9,0x05,0x32,0xd8,0x38,0xfb,0xe7,0x5e,0x8e,0x6a,0x44,0x41,0xcb,0xfd,0x8d,0x53,0xf9,0x37,0x49,0x43,0xa9,0xfd,0xac,0xa5,0x78,0x8c,0x3c,0x26,0x8d,0x90,0xaf,0x46,0x09,0x0d,0xca,0x9b,0x3c,0x63,0xd0,0x61}, + {0x66,0x25,0xdb,0xff,0x35,0x49,0x74,0x63,0xbb,0x68,0x0b,0x78,0x89,0x6b,0xbd,0xc5,0x03,0xec,0x3e,0x55,0x80,0x32,0x1b,0x6f,0xf5,0xd7,0xae,0x47,0xd8,0x5f,0x96,0x6e,0xdf,0x73,0xfc,0xf8,0xbc,0x28,0xa3,0xad,0xfc,0x37,0xf0,0xa6,0x5d,0x69,0x84,0xee,0x09,0xa9,0xc2,0x38,0xdb,0xb4,0x7f,0x63,0xdc,0x7b,0x06,0xf8,0x2d,0xac,0x23,0x5b,0x7b,0x52,0x80,0xee,0x53,0xb9,0xd2,0x9a,0x8d,0x6d,0xde,0xfa,0xaa,0x19,0x8f,0xe8,0xcf,0x82,0x0e,0x15,0x04,0x17,0x71,0x0e,0xdc,0xde,0x95,0xdd,0xb9,0xbb,0xb9,0x79}, + {0xc2,0x26,0x31,0x6a,0x40,0x55,0xb3,0xeb,0x93,0xc3,0xc8,0x68,0xa8,0x83,0x63,0xd2,0x82,0x7a,0xb9,0xe5,0x29,0x64,0x0c,0x6c,0x47,0x21,0xfd,0xc9,0x58,0xf1,0x65,0x50,0x74,0x73,0x9f,0x8e,0xae,0x7d,0x99,0xd1,0x16,0x08,0xbb,0xcf,0xf8,0xa2,0x32,0xa0,0x0a,0x5f,0x44,0x6d,0x12,0xba,0x6c,0xcd,0x34,0xb8,0xcc,0x0a,0x46,0x11,0xa8,0x1b,0x54,0x99,0x42,0x0c,0xfb,0x69,0x81,0x70,0x67,0xcf,0x6e,0xd7,0xac,0x00,0x46,0xe1,0xba,0x45,0xe6,0x70,0x8a,0xb9,0xaa,0x2e,0xf2,0xfa,0xa4,0x58,0x9e,0xf3,0x81,0x39}, + {0x93,0x0a,0x23,0x59,0x75,0x8a,0xfb,0x18,0x5d,0xf4,0xe6,0x60,0x69,0x8f,0x16,0x1d,0xb5,0x3c,0xa9,0x14,0x45,0xa9,0x85,0x3a,0xfd,0xd0,0xac,0x05,0x37,0x08,0xdc,0x38,0xde,0x6f,0xe6,0x6d,0xa5,0xdf,0x45,0xc8,0x3a,0x48,0x40,0x2c,0x00,0xa5,0x52,0xe1,0x32,0xf6,0xb4,0xc7,0x63,0xe1,0xd2,0xe9,0x65,0x1b,0xbc,0xdc,0x2e,0x45,0xf4,0x30,0x40,0x97,0x75,0xc5,0x82,0x27,0x6d,0x85,0xcc,0xbe,0x9c,0xf9,0x69,0x45,0x13,0xfa,0x71,0x4e,0xea,0xc0,0x73,0xfc,0x44,0x88,0x69,0x24,0x3f,0x59,0x1a,0x9a,0x2d,0x63}, + {0xa6,0xcb,0x07,0xb8,0x15,0x6b,0xbb,0xf6,0xd7,0xf0,0x54,0xbc,0xdf,0xc7,0x23,0x18,0x0b,0x67,0x29,0x6e,0x03,0x97,0x1d,0xbb,0x57,0x4a,0xed,0x47,0x88,0xf4,0x24,0x0b,0xa7,0x84,0x0c,0xed,0x11,0xfd,0x09,0xbf,0x3a,0x69,0x9f,0x0d,0x81,0x71,0xf0,0x63,0x79,0x87,0xcf,0x57,0x2d,0x8c,0x90,0x21,0xa2,0x4b,0xf6,0x8a,0xf2,0x7d,0x5a,0x3a,0xc7,0xea,0x1b,0x51,0xbe,0xd4,0xda,0xdc,0xf2,0xcc,0x26,0xed,0x75,0x80,0x53,0xa4,0x65,0x9a,0x5f,0x00,0x9f,0xff,0x9c,0xe1,0x63,0x1f,0x48,0x75,0x44,0xf7,0xfc,0x34}, + {0xca,0x67,0x97,0x78,0x4c,0xe0,0x97,0xc1,0x7d,0x46,0xd9,0x38,0xcb,0x4d,0x71,0xb8,0xa8,0x5f,0xf9,0x83,0x82,0x88,0xde,0x55,0xf7,0x63,0xfa,0x4d,0x16,0xdc,0x3b,0x3d,0x98,0xaa,0xcf,0x78,0xab,0x1d,0xbb,0xa5,0xf2,0x72,0x0b,0x19,0x67,0xa2,0xed,0x5c,0x8e,0x60,0x92,0x0a,0x11,0xc9,0x09,0x93,0xb0,0x74,0xb3,0x2f,0x04,0xa3,0x19,0x01,0x7d,0x17,0xc2,0xe8,0x9c,0xd8,0xa2,0x67,0xc1,0xd0,0x95,0x68,0xf6,0xa5,0x9d,0x66,0xb0,0xa2,0x82,0xb2,0xe5,0x98,0x65,0xf5,0x73,0x0a,0xe2,0xed,0xf1,0x88,0xc0,0x56}, + {0x17,0x6e,0xa8,0x10,0x11,0x3d,0x6d,0x33,0xfa,0xb2,0x75,0x0b,0x32,0x88,0xf3,0xd7,0x88,0x29,0x07,0x25,0x76,0x33,0x15,0xf9,0x87,0x8b,0x10,0x99,0x6b,0x4c,0x67,0x09,0x02,0x8f,0xf3,0x24,0xac,0x5f,0x1b,0x58,0xbd,0x0c,0xe3,0xba,0xfe,0xe9,0x0b,0xa9,0xf0,0x92,0xcf,0x8a,0x02,0x69,0x21,0x9a,0x8f,0x03,0x59,0x83,0xa4,0x7e,0x8b,0x03,0xf8,0x6f,0x31,0x99,0x21,0xf8,0x4e,0x9f,0x4f,0x8d,0xa7,0xea,0x82,0xd2,0x49,0x2f,0x74,0x31,0xef,0x5a,0xab,0xa5,0x71,0x09,0x65,0xeb,0x69,0x59,0x02,0x31,0x5e,0x6e}, + {0xfb,0x93,0xe5,0x87,0xf5,0x62,0x6c,0xb1,0x71,0x3e,0x5d,0xca,0xde,0xed,0x99,0x49,0x6d,0x3e,0xcc,0x14,0xe0,0xc1,0x91,0xb4,0xa8,0xdb,0xa8,0x89,0x47,0x11,0xf5,0x08,0x22,0x62,0x06,0x63,0x0e,0xfb,0x04,0x33,0x3f,0xba,0xac,0x87,0x89,0x06,0x35,0xfb,0xa3,0x61,0x10,0x8c,0x77,0x24,0x19,0xbd,0x20,0x86,0x83,0xd1,0x43,0xad,0x58,0x30,0xd0,0x63,0x76,0xe5,0xfd,0x0f,0x3c,0x32,0x10,0xa6,0x2e,0xa2,0x38,0xdf,0xc3,0x05,0x9a,0x4f,0x99,0xac,0xbd,0x8a,0xc7,0xbd,0x99,0xdc,0xe3,0xef,0xa4,0x9f,0x54,0x26}, + {0xd6,0xf9,0x6b,0x1e,0x46,0x5a,0x1d,0x74,0x81,0xa5,0x77,0x77,0xfc,0xb3,0x05,0x23,0xd9,0xd3,0x74,0x64,0xa2,0x74,0x55,0xd4,0xff,0xe0,0x01,0x64,0xdc,0xe1,0x26,0x19,0x6e,0x66,0x3f,0xaf,0x49,0x85,0x46,0xdb,0xa5,0x0e,0x4a,0xf1,0x04,0xcf,0x7f,0xd7,0x47,0x0c,0xba,0xa4,0xf7,0x3f,0xf2,0x3d,0x85,0x3c,0xce,0x32,0xe1,0xdf,0x10,0x3a,0xa0,0xce,0x17,0xea,0x8a,0x4e,0x7f,0xe0,0xfd,0xc1,0x1f,0x3a,0x46,0x15,0xd5,0x2f,0xf1,0xc0,0xf2,0x31,0xfd,0x22,0x53,0x17,0x15,0x5d,0x1e,0x86,0x1d,0xd0,0xa1,0x1f}, + {0x32,0x98,0x59,0x7d,0x94,0x55,0x80,0xcc,0x20,0x55,0xf1,0x37,0xda,0x56,0x46,0x1e,0x20,0x93,0x05,0x4e,0x74,0xf7,0xf6,0x99,0x33,0xcf,0x75,0x6a,0xbc,0x63,0x35,0x77,0xab,0x94,0xdf,0xd1,0x00,0xac,0xdc,0x38,0xe9,0x0d,0x08,0xd1,0xdd,0x2b,0x71,0x2e,0x62,0xe2,0xd5,0xfd,0x3e,0xe9,0x13,0x7f,0xe5,0x01,0x9a,0xee,0x18,0xed,0xfc,0x73,0xb3,0x9c,0x13,0x63,0x08,0xe9,0xb1,0x06,0xcd,0x3e,0xa0,0xc5,0x67,0xda,0x93,0xa4,0x32,0x89,0x63,0xad,0xc8,0xce,0x77,0x8d,0x44,0x4f,0x86,0x1b,0x70,0x6b,0x42,0x1f}, + {0x01,0x1c,0x91,0x41,0x4c,0x26,0xc9,0xef,0x25,0x2c,0xa2,0x17,0xb8,0xb7,0xa3,0xf1,0x47,0x14,0x0f,0xf3,0x6b,0xda,0x75,0x58,0x90,0xb0,0x31,0x1d,0x27,0xf5,0x1a,0x4e,0x52,0x25,0xa1,0x91,0xc8,0x35,0x7e,0xf1,0x76,0x9c,0x5e,0x57,0x53,0x81,0x6b,0xb7,0x3e,0x72,0x9b,0x0d,0x6f,0x40,0x83,0xfa,0x38,0xe4,0xa7,0x3f,0x1b,0xbb,0x76,0x0b,0x9b,0x93,0x92,0x7f,0xf9,0xc1,0xb8,0x08,0x6e,0xab,0x44,0xd4,0xcb,0x71,0x67,0xbe,0x17,0x80,0xbb,0x99,0x63,0x64,0xe5,0x22,0x55,0xa9,0x72,0xb7,0x1e,0xd6,0x6d,0x7b}, + {0x92,0x3d,0xf3,0x50,0xe8,0xc1,0xad,0xb7,0xcf,0xd5,0x8c,0x60,0x4f,0xfa,0x98,0x79,0xdb,0x5b,0xfc,0x8d,0xbd,0x2d,0x96,0xad,0x4f,0x2f,0x1d,0xaf,0xce,0x9b,0x3e,0x70,0xc7,0xd2,0x01,0xab,0xf9,0xab,0x30,0x57,0x18,0x3b,0x14,0x40,0xdc,0x76,0xfb,0x16,0x81,0xb2,0xcb,0xa0,0x65,0xbe,0x6c,0x86,0xfe,0x6a,0xff,0x9b,0x65,0x9b,0xfa,0x53,0x55,0x54,0x88,0x94,0xe9,0xc8,0x14,0x6c,0xe5,0xd4,0xae,0x65,0x66,0x5d,0x3a,0x84,0xf1,0x5a,0xd6,0xbc,0x3e,0xb7,0x1b,0x18,0x50,0x1f,0xc6,0xc4,0xe5,0x93,0x8d,0x39}, + {0xf3,0x48,0xe2,0x33,0x67,0xd1,0x4b,0x1c,0x5f,0x0a,0xbf,0x15,0x87,0x12,0x9e,0xbd,0x76,0x03,0x0b,0xa1,0xf0,0x8c,0x3f,0xd4,0x13,0x1b,0x19,0xdf,0x5d,0x9b,0xb0,0x53,0xf2,0xe3,0xe7,0xd2,0x60,0x7c,0x87,0xc3,0xb1,0x8b,0x82,0x30,0xa0,0xaa,0x34,0x3b,0x38,0xf1,0x9e,0x73,0xe7,0x26,0x3e,0x28,0x77,0x05,0xc3,0x02,0x90,0x9c,0x9c,0x69,0xcc,0xf1,0x46,0x59,0x23,0xa7,0x06,0xf3,0x7d,0xd9,0xe5,0xcc,0xb5,0x18,0x17,0x92,0x75,0xe9,0xb4,0x81,0x47,0xd2,0xcd,0x28,0x07,0xd9,0xcd,0x6f,0x0c,0xf3,0xca,0x51}, + {0x0a,0xe0,0x74,0x76,0x42,0xa7,0x0b,0xa6,0xf3,0x7b,0x7a,0xa1,0x70,0x85,0x0e,0x63,0xcc,0x24,0x33,0xcf,0x3d,0x56,0x58,0x37,0xaa,0xfd,0x83,0x23,0x29,0xaa,0x04,0x55,0xc7,0x54,0xac,0x18,0x9a,0xf9,0x7a,0x73,0x0f,0xb3,0x1c,0xc5,0xdc,0x78,0x33,0x90,0xc7,0x0c,0xe1,0x4c,0x33,0xbc,0x89,0x2b,0x9a,0xe9,0xf8,0x89,0xc1,0x29,0xae,0x12,0xcf,0x01,0x0d,0x1f,0xcb,0xc0,0x9e,0xa9,0xae,0xf7,0x34,0x3a,0xcc,0xef,0xd1,0x0d,0x22,0x4e,0x9c,0xd0,0x21,0x75,0xca,0x55,0xea,0xa5,0xeb,0x58,0xe9,0x4f,0xd1,0x5f}, + {0x2c,0xab,0x45,0x28,0xdf,0x2d,0xdc,0xb5,0x93,0xe9,0x7f,0x0a,0xb1,0x91,0x94,0x06,0x46,0xe3,0x02,0x40,0xd6,0xf3,0xaa,0x4d,0xd1,0x74,0x64,0x58,0x6e,0xf2,0x3f,0x09,0x8e,0xcb,0x93,0xbf,0x5e,0xfe,0x42,0x3c,0x5f,0x56,0xd4,0x36,0x51,0xa8,0xdf,0xbe,0xe8,0x20,0x42,0x88,0x9e,0x85,0xf0,0xe0,0x28,0xd1,0x25,0x07,0x96,0x3f,0xd7,0x7d,0x29,0x98,0x05,0x68,0xfe,0x24,0x0d,0xb1,0xe5,0x23,0xaf,0xdb,0x72,0x06,0x73,0x75,0x29,0xac,0x57,0xb4,0x3a,0x25,0x67,0x13,0xa4,0x70,0xb4,0x86,0xbc,0xbc,0x59,0x2f}, + {0x5f,0x13,0x17,0x99,0x42,0x7d,0x84,0x83,0xd7,0x03,0x7d,0x56,0x1f,0x91,0x1b,0xad,0xd1,0xaa,0x77,0xbe,0xd9,0x48,0x77,0x7e,0x4a,0xaf,0x51,0x2e,0x2e,0xb4,0x58,0x54,0x01,0xc3,0x91,0xb6,0x60,0xd5,0x41,0x70,0x1e,0xe7,0xd7,0xad,0x3f,0x1b,0x20,0x85,0x85,0x55,0x33,0x11,0x63,0xe1,0xc2,0x16,0xb1,0x28,0x08,0x01,0x3d,0x5e,0xa5,0x2a,0x4f,0x44,0x07,0x0c,0xe6,0x92,0x51,0xed,0x10,0x1d,0x42,0x74,0x2d,0x4e,0xc5,0x42,0x64,0xc8,0xb5,0xfd,0x82,0x4c,0x2b,0x35,0x64,0x86,0x76,0x8a,0x4a,0x00,0xe9,0x13}, + {0xdb,0xce,0x2f,0x83,0x45,0x88,0x9d,0x73,0x63,0xf8,0x6b,0xae,0xc9,0xd6,0x38,0xfa,0xf7,0xfe,0x4f,0xb7,0xca,0x0d,0xbc,0x32,0x5e,0xe4,0xbc,0x14,0x88,0x7e,0x93,0x73,0x7f,0x87,0x3b,0x19,0xc9,0x00,0x2e,0xbb,0x6b,0x50,0xdc,0xe0,0x90,0xa8,0xe3,0xec,0x9f,0x64,0xde,0x36,0xc0,0xb7,0xf3,0xec,0x1a,0x9e,0xde,0x98,0x08,0x04,0x46,0x5f,0x8d,0xf4,0x7b,0x29,0x16,0x71,0x03,0xb9,0x34,0x68,0xf0,0xd4,0x22,0x3b,0xd1,0xa9,0xc6,0xbd,0x96,0x46,0x57,0x15,0x97,0xe1,0x35,0xe8,0xd5,0x91,0xe8,0xa4,0xf8,0x2c}, + {0x67,0x0f,0x11,0x07,0x87,0xfd,0x93,0x6d,0x49,0xb5,0x38,0x7c,0xd3,0x09,0x4c,0xdd,0x86,0x6a,0x73,0xc2,0x4c,0x6a,0xb1,0x7c,0x09,0x2a,0x25,0x58,0x6e,0xbd,0x49,0x20,0xa2,0x6b,0xd0,0x17,0x7e,0x48,0xb5,0x2c,0x6b,0x19,0x50,0x39,0x1c,0x38,0xd2,0x24,0x30,0x8a,0x97,0x85,0x81,0x9c,0x65,0xd7,0xf6,0xa4,0xd6,0x91,0x28,0x7f,0x6f,0x7a,0x49,0xef,0x9a,0x6a,0x8d,0xfd,0x09,0x7d,0x0b,0xb9,0x3d,0x5b,0xbe,0x60,0xee,0xf0,0xd4,0xbf,0x9e,0x51,0x2c,0xb5,0x21,0x4c,0x1d,0x94,0x45,0xc5,0xdf,0xaa,0x11,0x60}, + {0x3c,0xf8,0x95,0xcf,0x6d,0x92,0x67,0x5f,0x71,0x90,0x28,0x71,0x61,0x85,0x7e,0x7c,0x5b,0x7a,0x8f,0x99,0xf3,0xe7,0xa1,0xd6,0xe0,0xf9,0x62,0x0b,0x1b,0xcc,0xc5,0x6f,0x90,0xf8,0xcb,0x02,0xc8,0xd0,0xde,0x63,0xaa,0x6a,0xff,0x0d,0xca,0x98,0xd0,0xfb,0x99,0xed,0xb6,0xb9,0xfd,0x0a,0x4d,0x62,0x1e,0x0b,0x34,0x79,0xb7,0x18,0xce,0x69,0xcb,0x79,0x98,0xb2,0x28,0x55,0xef,0xd1,0x92,0x90,0x7e,0xd4,0x3c,0xae,0x1a,0xdd,0x52,0x23,0x9f,0x18,0x42,0x04,0x7e,0x12,0xf1,0x01,0x71,0xe5,0x3a,0x6b,0x59,0x15}, + {0xa2,0x79,0x91,0x3f,0xd2,0x39,0x27,0x46,0xcf,0xdd,0xd6,0x97,0x31,0x12,0x83,0xff,0x8a,0x14,0xf2,0x53,0xb5,0xde,0x07,0x13,0xda,0x4d,0x5f,0x7b,0x68,0x37,0x22,0x0d,0xca,0x24,0x51,0x7e,0x16,0x31,0xff,0x09,0xdf,0x45,0xc7,0xd9,0x8b,0x15,0xe4,0x0b,0xe5,0x56,0xf5,0x7e,0x22,0x7d,0x2b,0x29,0x38,0xd1,0xb6,0xaf,0x41,0xe2,0xa4,0x3a,0xf5,0x05,0x33,0x2a,0xbf,0x38,0xc1,0x2c,0xc3,0x26,0xe9,0xa2,0x8f,0x3f,0x58,0x48,0xeb,0xd2,0x49,0x55,0xa2,0xb1,0x3a,0x08,0x6c,0xa3,0x87,0x46,0x6e,0xaa,0xfc,0x32}, + {0xf5,0x9a,0x7d,0xc5,0x8d,0x6e,0xc5,0x7b,0xf2,0xbd,0xf0,0x9d,0xed,0xd2,0x0b,0x3e,0xa3,0xe4,0xef,0x22,0xde,0x14,0xc0,0xaa,0x5c,0x6a,0xbd,0xfe,0xce,0xe9,0x27,0x46,0xdf,0xcc,0x87,0x27,0x73,0xa4,0x07,0x32,0xf8,0xe3,0x13,0xf2,0x08,0x19,0xe3,0x17,0x4e,0x96,0x0d,0xf6,0xd7,0xec,0xb2,0xd5,0xe9,0x0b,0x60,0xc2,0x36,0x63,0x6f,0x74,0x1c,0x97,0x6c,0xab,0x45,0xf3,0x4a,0x3f,0x1f,0x73,0x43,0x99,0x72,0xeb,0x88,0xe2,0x6d,0x18,0x44,0x03,0x8a,0x6a,0x59,0x33,0x93,0x62,0xd6,0x7e,0x00,0x17,0x49,0x7b}, + {0x64,0xb0,0x84,0xab,0x5c,0xfb,0x85,0x2d,0x14,0xbc,0xf3,0x89,0xd2,0x10,0x78,0x49,0x0c,0xce,0x15,0x7b,0x44,0xdc,0x6a,0x47,0x7b,0xfd,0x44,0xf8,0x76,0xa3,0x2b,0x12,0xdd,0xa2,0x53,0xdd,0x28,0x1b,0x34,0x54,0x3f,0xfc,0x42,0xdf,0x5b,0x90,0x17,0xaa,0xf4,0xf8,0xd2,0x4d,0xd9,0x92,0xf5,0x0f,0x7d,0xd3,0x8c,0xe0,0x0f,0x62,0x03,0x1d,0x54,0xe5,0xb4,0xa2,0xcd,0x32,0x02,0xc2,0x7f,0x18,0x5d,0x11,0x42,0xfd,0xd0,0x9e,0xd9,0x79,0xd4,0x7d,0xbe,0xb4,0xab,0x2e,0x4c,0xec,0x68,0x2b,0xf5,0x0b,0xc7,0x02}, + {0xbb,0x2f,0x0b,0x5d,0x4b,0xec,0x87,0xa2,0xca,0x82,0x48,0x07,0x90,0x57,0x5c,0x41,0x5c,0x81,0xd0,0xc1,0x1e,0xa6,0x44,0xe0,0xe0,0xf5,0x9e,0x40,0x0a,0x4f,0x33,0x26,0xe1,0x72,0x8d,0x45,0xbf,0x32,0xe5,0xac,0xb5,0x3c,0xb7,0x7c,0xe0,0x68,0xe7,0x5b,0xe7,0xbd,0x8b,0xee,0x94,0x7d,0xcf,0x56,0x03,0x3a,0xb4,0xfe,0xe3,0x97,0x06,0x6b,0xc0,0xa3,0x62,0xdf,0x4a,0xf0,0xc8,0xb6,0x5d,0xa4,0x6d,0x07,0xef,0x00,0xf0,0x3e,0xa9,0xd2,0xf0,0x49,0x58,0xb9,0x9c,0x9c,0xae,0x2f,0x1b,0x44,0x43,0x7f,0xc3,0x1c}, + {0x4f,0x32,0xc7,0x5c,0x5a,0x56,0x8f,0x50,0x22,0xa9,0x06,0xe5,0xc0,0xc4,0x61,0xd0,0x19,0xac,0x45,0x5c,0xdb,0xab,0x18,0xfb,0x4a,0x31,0x80,0x03,0xc1,0x09,0x68,0x6c,0xb9,0xae,0xce,0xc9,0xf1,0x56,0x66,0xd7,0x6a,0x65,0xe5,0x18,0xf8,0x15,0x5b,0x1c,0x34,0x23,0x4c,0x84,0x32,0x28,0xe7,0x26,0x38,0x68,0x19,0x2f,0x77,0x6f,0x34,0x3a,0xc8,0x6a,0xda,0xe2,0x12,0x51,0xd5,0xd2,0xed,0x51,0xe8,0xb1,0x31,0x03,0xbd,0xe9,0x62,0x72,0xc6,0x8e,0xdd,0x46,0x07,0x96,0xd0,0xc5,0xf7,0x6e,0x9f,0x1b,0x91,0x05}, + {0xbb,0x0e,0xdf,0xf5,0x83,0x99,0x33,0xc1,0xac,0x4c,0x2c,0x51,0x8f,0x75,0xf3,0xc0,0xe1,0x98,0xb3,0x0b,0x0a,0x13,0xf1,0x2c,0x62,0x0c,0x27,0xaa,0xf9,0xec,0x3c,0x6b,0xef,0xea,0x2e,0x51,0xf3,0xac,0x49,0x53,0x49,0xcb,0xc1,0x1c,0xd3,0x41,0xc1,0x20,0x8d,0x68,0x9a,0xa9,0x07,0x0c,0x18,0x24,0x17,0x2d,0x4b,0xc6,0xd1,0xf9,0x5e,0x55,0x08,0xbd,0x73,0x3b,0xba,0x70,0xa7,0x36,0x0c,0xbf,0xaf,0xa3,0x08,0xef,0x4a,0x62,0xf2,0x46,0x09,0xb4,0x98,0xff,0x37,0x57,0x9d,0x74,0x81,0x33,0xe1,0x4d,0x5f,0x67}, + {0xfc,0x82,0x17,0x6b,0x03,0x52,0x2c,0x0e,0xb4,0x83,0xad,0x6c,0x81,0x6c,0x81,0x64,0x3e,0x07,0x64,0x69,0xd9,0xbd,0xdc,0xd0,0x20,0xc5,0x64,0x01,0xf7,0x9d,0xd9,0x13,0x1d,0xb3,0xda,0x3b,0xd9,0xf6,0x2f,0xa1,0xfe,0x2d,0x65,0x9d,0x0f,0xd8,0x25,0x07,0x87,0x94,0xbe,0x9a,0xf3,0x4f,0x9c,0x01,0x43,0x3c,0xcd,0x82,0xb8,0x50,0xf4,0x60,0xca,0xc0,0xe5,0x21,0xc3,0x5e,0x4b,0x01,0xa2,0xbf,0x19,0xd7,0xc9,0x69,0xcb,0x4f,0xa0,0x23,0x00,0x75,0x18,0x1c,0x5f,0x4e,0x80,0xac,0xed,0x55,0x9e,0xde,0x06,0x1c}, + {0xe2,0xc4,0x3e,0xa3,0xd6,0x7a,0x0f,0x99,0x8e,0xe0,0x2e,0xbe,0x38,0xf9,0x08,0x66,0x15,0x45,0x28,0x63,0xc5,0x43,0xa1,0x9c,0x0d,0xb6,0x2d,0xec,0x1f,0x8a,0xf3,0x4c,0xaa,0x69,0x6d,0xff,0x40,0x2b,0xd5,0xff,0xbb,0x49,0x40,0xdc,0x18,0x0b,0x53,0x34,0x97,0x98,0x4d,0xa3,0x2f,0x5c,0x4a,0x5e,0x2d,0xba,0x32,0x7d,0x8e,0x6f,0x09,0x78,0xe7,0x5c,0xfa,0x0d,0x65,0xaa,0xaa,0xa0,0x8c,0x47,0xb5,0x48,0x2a,0x9e,0xc4,0xf9,0x5b,0x72,0x03,0x70,0x7d,0xcc,0x09,0x4f,0xbe,0x1a,0x09,0x26,0x3a,0xad,0x3c,0x37}, + {0x7c,0xf5,0xc9,0x82,0x4d,0x63,0x94,0xb2,0x36,0x45,0x93,0x24,0xe1,0xfd,0xcb,0x1f,0x5a,0xdb,0x8c,0x41,0xb3,0x4d,0x9c,0x9e,0xfc,0x19,0x44,0x45,0xd9,0xf3,0x40,0x00,0xad,0xbb,0xdd,0x89,0xfb,0xa8,0xbe,0xf1,0xcb,0xae,0xae,0x61,0xbc,0x2c,0xcb,0x3b,0x9d,0x8d,0x9b,0x1f,0xbb,0xa7,0x58,0x8f,0x86,0xa6,0x12,0x51,0xda,0x7e,0x54,0x21,0xd3,0x86,0x59,0xfd,0x39,0xe9,0xfd,0xde,0x0c,0x38,0x0a,0x51,0x89,0x2c,0x27,0xf4,0xb9,0x19,0x31,0xbb,0x07,0xa4,0x2b,0xb7,0xf4,0x4d,0x25,0x4a,0x33,0x0a,0x55,0x63}, + {0x37,0xcf,0x69,0xb5,0xed,0xd6,0x07,0x65,0xe1,0x2e,0xa5,0x0c,0xb0,0x29,0x84,0x17,0x5d,0xd6,0x6b,0xeb,0x90,0x00,0x7c,0xea,0x51,0x8f,0xf7,0xda,0xc7,0x62,0xea,0x3e,0x49,0x7b,0x54,0x72,0x45,0x58,0xba,0x9b,0xe0,0x08,0xc4,0xe2,0xfa,0xc6,0x05,0xf3,0x8d,0xf1,0x34,0xc7,0x69,0xfa,0xe8,0x60,0x7a,0x76,0x7d,0xaa,0xaf,0x2b,0xa9,0x39,0x4e,0x27,0x93,0xe6,0x13,0xc7,0x24,0x9d,0x75,0xd3,0xdb,0x68,0x77,0x85,0x63,0x5f,0x9a,0xb3,0x8a,0xeb,0x60,0x55,0x52,0x70,0xcd,0xc4,0xc9,0x65,0x06,0x6a,0x43,0x68}, + {0x27,0x3f,0x2f,0x20,0xe8,0x35,0x02,0xbc,0xb0,0x75,0xf9,0x64,0xe2,0x00,0x5c,0xc7,0x16,0x24,0x8c,0xa3,0xd5,0xe9,0xa4,0x91,0xf9,0x89,0xb7,0x8a,0xf6,0xe7,0xb6,0x17,0x7c,0x10,0x20,0xe8,0x17,0xd3,0x56,0x1e,0x65,0xe9,0x0a,0x84,0x44,0x68,0x26,0xc5,0x7a,0xfc,0x0f,0x32,0xc6,0xa1,0xe0,0xc1,0x72,0x14,0x61,0x91,0x9c,0x66,0x73,0x53,0x57,0x52,0x0e,0x9a,0xab,0x14,0x28,0x5d,0xfc,0xb3,0xca,0xc9,0x84,0x20,0x8f,0x90,0xca,0x1e,0x2d,0x5b,0x88,0xf5,0xca,0xaf,0x11,0x7d,0xf8,0x78,0xa6,0xb5,0xb4,0x1c}, + {0x6c,0xfc,0x4a,0x39,0x6b,0xc0,0x64,0xb6,0xb1,0x5f,0xda,0x98,0x24,0xde,0x88,0x0c,0x34,0xd8,0xca,0x4b,0x16,0x03,0x8d,0x4f,0xa2,0x34,0x74,0xde,0x78,0xca,0x0b,0x33,0xe7,0x07,0xa0,0xa2,0x62,0xaa,0x74,0x6b,0xb1,0xc7,0x71,0xf0,0xb0,0xe0,0x11,0xf3,0x23,0xe2,0x0b,0x00,0x38,0xe4,0x07,0x57,0xac,0x6e,0xef,0x82,0x2d,0xfd,0xc0,0x2d,0x4e,0x74,0x19,0x11,0x84,0xff,0x2e,0x98,0x24,0x47,0x07,0x2b,0x96,0x5e,0x69,0xf9,0xfb,0x53,0xc9,0xbf,0x4f,0xc1,0x8a,0xc5,0xf5,0x1c,0x9f,0x36,0x1b,0xbe,0x31,0x3c}, + {0xee,0x8a,0x94,0x08,0x4d,0x86,0xf4,0xb0,0x6f,0x1c,0xba,0x91,0xee,0x19,0xdc,0x07,0x58,0xa1,0xac,0xa6,0xae,0xcd,0x75,0x79,0xbb,0xd4,0x62,0x42,0x13,0x61,0x0b,0x33,0x72,0x42,0xcb,0xf9,0x93,0xbc,0x68,0xc1,0x98,0xdb,0xce,0xc7,0x1f,0x71,0xb8,0xae,0x7a,0x8d,0xac,0x34,0xaa,0x52,0x0e,0x7f,0xbb,0x55,0x7d,0x7e,0x09,0xc1,0xce,0x41,0x8a,0x80,0x6d,0xa2,0xd7,0x19,0x96,0xf7,0x6d,0x15,0x9e,0x1d,0x9e,0xd4,0x1f,0xbb,0x27,0xdf,0xa1,0xdb,0x6c,0xc3,0xd7,0x73,0x7d,0x77,0x28,0x1f,0xd9,0x4c,0xb4,0x26}, + {0x75,0x74,0x38,0x8f,0x47,0x48,0xf0,0x51,0x3c,0xcb,0xbe,0x9c,0xf4,0xbc,0x5d,0xb2,0x55,0x20,0x9f,0xd9,0x44,0x12,0xab,0x9a,0xd6,0xa5,0x10,0x1c,0x6c,0x9e,0x70,0x2c,0x83,0x03,0x73,0x62,0x93,0xf2,0xb7,0xe1,0x2c,0x8a,0xca,0xeb,0xff,0x79,0x52,0x4b,0x14,0x13,0xd4,0xbf,0x8a,0x77,0xfc,0xda,0x0f,0x61,0x72,0x9c,0x14,0x10,0xeb,0x7d,0x7a,0xee,0x66,0x87,0x6a,0xaf,0x62,0xcb,0x0e,0xcd,0x53,0x55,0x04,0xec,0xcb,0x66,0xb5,0xe4,0x0b,0x0f,0x38,0x01,0x80,0x58,0xea,0xe2,0x2c,0xf6,0x9f,0x8e,0xe6,0x08}, + {0xad,0x30,0xc1,0x4b,0x0a,0x50,0xad,0x34,0x9c,0xd4,0x0b,0x3d,0x49,0xdb,0x38,0x8d,0xbe,0x89,0x0a,0x50,0x98,0x3d,0x5c,0xa2,0x09,0x3b,0xba,0xee,0x87,0x3f,0x1f,0x2f,0xf9,0xf2,0xb8,0x0a,0xd5,0x09,0x2d,0x2f,0xdf,0x23,0x59,0xc5,0x8d,0x21,0xb9,0xac,0xb9,0x6c,0x76,0x73,0x26,0x34,0x8f,0x4a,0xf5,0x19,0xf7,0x38,0xd7,0x3b,0xb1,0x4c,0x4a,0xb6,0x15,0xe5,0x75,0x8c,0x84,0xf7,0x38,0x90,0x4a,0xdb,0xba,0x01,0x95,0xa5,0x50,0x1b,0x75,0x3f,0x3f,0x31,0x0d,0xc2,0xe8,0x2e,0xae,0xc0,0x53,0xe3,0xa1,0x19}, + {0xc3,0x05,0xfa,0xba,0x60,0x75,0x1c,0x7d,0x61,0x5e,0xe5,0xc6,0xa0,0xa0,0xe1,0xb3,0x73,0x64,0xd6,0xc0,0x18,0x97,0x52,0xe3,0x86,0x34,0x0c,0xc2,0x11,0x6b,0x54,0x41,0xbd,0xbd,0x96,0xd5,0xcd,0x72,0x21,0xb4,0x40,0xfc,0xee,0x98,0x43,0x45,0xe0,0x93,0xb5,0x09,0x41,0xb4,0x47,0x53,0xb1,0x9f,0x34,0xae,0x66,0x02,0x99,0xd3,0x6b,0x73,0xb4,0xb3,0x34,0x93,0x50,0x2d,0x53,0x85,0x73,0x65,0x81,0x60,0x4b,0x11,0xfd,0x46,0x75,0x83,0x5c,0x42,0x30,0x5f,0x5f,0xcc,0x5c,0xab,0x7f,0xb8,0xa2,0x95,0x22,0x41}, + {0xe9,0xd6,0x7e,0xf5,0x88,0x9b,0xc9,0x19,0x25,0xc8,0xf8,0x6d,0x26,0xcb,0x93,0x53,0x73,0xd2,0x0a,0xb3,0x13,0x32,0xee,0x5c,0x34,0x2e,0x2d,0xb5,0xeb,0x53,0xe1,0x14,0xc6,0xea,0x93,0xe2,0x61,0x52,0x65,0x2e,0xdb,0xac,0x33,0x21,0x03,0x92,0x5a,0x84,0x6b,0x99,0x00,0x79,0xcb,0x75,0x09,0x46,0x80,0xdd,0x5a,0x19,0x8d,0xbb,0x60,0x07,0x8a,0x81,0xe6,0xcd,0x17,0x1a,0x3e,0x41,0x84,0xa0,0x69,0xed,0xa9,0x6d,0x15,0x57,0xb1,0xcc,0xca,0x46,0x8f,0x26,0xbf,0x2c,0xf2,0xc5,0x3a,0xc3,0x9b,0xbe,0x34,0x6b}, + {0xb2,0xc0,0x78,0x3a,0x64,0x2f,0xdf,0xf3,0x7c,0x02,0x2e,0xf2,0x1e,0x97,0x3e,0x4c,0xa3,0xb5,0xc1,0x49,0x5e,0x1c,0x7d,0xec,0x2d,0xdd,0x22,0x09,0x8f,0xc1,0x12,0x20,0xd3,0xf2,0x71,0x65,0x65,0x69,0xfc,0x11,0x7a,0x73,0x0e,0x53,0x45,0xe8,0xc9,0xc6,0x35,0x50,0xfe,0xd4,0xa2,0xe7,0x3a,0xe3,0x0b,0xd3,0x6d,0x2e,0xb6,0xc7,0xb9,0x01,0x29,0x9d,0xc8,0x5a,0xe5,0x55,0x0b,0x88,0x63,0xa7,0xa0,0x45,0x1f,0x24,0x83,0x14,0x1f,0x6c,0xe7,0xc2,0xdf,0xef,0x36,0x3d,0xe8,0xad,0x4b,0x4e,0x78,0x5b,0xaf,0x08}, + {0x33,0x25,0x1f,0x88,0xdc,0x99,0x34,0x28,0xb6,0x23,0x93,0x77,0xda,0x25,0x05,0x9d,0xf4,0x41,0x34,0x67,0xfb,0xdd,0x7a,0x89,0x8d,0x16,0x3a,0x16,0x71,0x9d,0xb7,0x32,0x4b,0x2c,0xcc,0x89,0xd2,0x14,0x73,0xe2,0x8d,0x17,0x87,0xa2,0x11,0xbd,0xe4,0x4b,0xce,0x64,0x33,0xfa,0xd6,0x28,0xd5,0x18,0x6e,0x82,0xd9,0xaf,0xd5,0xc1,0x23,0x64,0x6a,0xb3,0xfc,0xed,0xd9,0xf8,0x85,0xcc,0xf9,0xe5,0x46,0x37,0x8f,0xc2,0xbc,0x22,0xcd,0xd3,0xe5,0xf9,0x38,0xe3,0x9d,0xe4,0xcc,0x2d,0x3e,0xc1,0xfb,0x5e,0x0a,0x48}, + {0x71,0x20,0x62,0x01,0x0b,0xe7,0x51,0x0b,0xc5,0xaf,0x1d,0x8b,0xcf,0x05,0xb5,0x06,0xcd,0xab,0x5a,0xef,0x61,0xb0,0x6b,0x2c,0x31,0xbf,0xb7,0x0c,0x60,0x27,0xaa,0x47,0x1f,0x22,0xce,0x42,0xe4,0x4c,0x61,0xb6,0x28,0x39,0x05,0x4c,0xcc,0x9d,0x19,0x6e,0x03,0xbe,0x1c,0xdc,0xa4,0xb4,0x3f,0x66,0x06,0x8e,0x1c,0x69,0x47,0x1d,0xb3,0x24,0xc3,0xf8,0x15,0xc0,0xed,0x1e,0x54,0x2a,0x7c,0x3f,0x69,0x7c,0x7e,0xfe,0xa4,0x11,0xd6,0x78,0xa2,0x4e,0x13,0x66,0xaf,0xf0,0x94,0xa0,0xdd,0x14,0x5d,0x58,0x5b,0x54}, + {0x0f,0x3a,0xd4,0xa0,0x5e,0x27,0xbf,0x67,0xbe,0xee,0x9b,0x08,0x34,0x8e,0xe6,0xad,0x2e,0xe7,0x79,0xd4,0x4c,0x13,0x89,0x42,0x54,0x54,0xba,0x32,0xc3,0xf9,0x62,0x0f,0xe1,0x21,0xb3,0xe3,0xd0,0xe4,0x04,0x62,0x95,0x1e,0xff,0x28,0x7a,0x63,0xaa,0x3b,0x9e,0xbd,0x99,0x5b,0xfd,0xcf,0x0c,0x0b,0x71,0xd0,0xc8,0x64,0x3e,0xdc,0x22,0x4d,0x39,0x5f,0x3b,0xd6,0x89,0x65,0xb4,0xfc,0x61,0xcf,0xcb,0x57,0x3f,0x6a,0xae,0x5c,0x05,0xfa,0x3a,0x95,0xd2,0xc2,0xba,0xfe,0x36,0x14,0x37,0x36,0x1a,0xa0,0x0f,0x1c}, + {0xff,0x3d,0x94,0x22,0xb6,0x04,0xc6,0xd2,0xa0,0xb3,0xcf,0x44,0xce,0xbe,0x8c,0xbc,0x78,0x86,0x80,0x97,0xf3,0x4f,0x25,0x5d,0xbf,0xa6,0x1c,0x3b,0x4f,0x61,0xa3,0x0f,0x50,0x6a,0x93,0x8c,0x0e,0x2b,0x08,0x69,0xb6,0xc5,0xda,0xc1,0x35,0xa0,0xc9,0xf9,0x34,0xb6,0xdf,0xc4,0x54,0x3e,0xb7,0x6f,0x40,0xc1,0x2b,0x1d,0x9b,0x41,0x05,0x40,0xf0,0x82,0xbe,0xb9,0xbd,0xfe,0x03,0xa0,0x90,0xac,0x44,0x3a,0xaf,0xc1,0x89,0x20,0x8e,0xfa,0x54,0x19,0x91,0x9f,0x49,0xf8,0x42,0xab,0x40,0xef,0x8a,0x21,0xba,0x1f}, + {0x3e,0xf5,0xc8,0xfa,0x48,0x94,0x54,0xab,0x41,0x37,0xa6,0x7b,0x9a,0xe8,0xf6,0x81,0x01,0x5e,0x2b,0x6c,0x7d,0x6c,0xfd,0x74,0x42,0x6e,0xc8,0xa8,0xca,0x3a,0x2e,0x39,0x94,0x01,0x7b,0x3e,0x04,0x57,0x3e,0x4f,0x7f,0xaf,0xda,0x08,0xee,0x3e,0x1d,0xa8,0xf1,0xde,0xdc,0x99,0xab,0xc6,0x39,0xc8,0xd5,0x61,0x77,0xff,0x13,0x5d,0x53,0x6c,0xaf,0x35,0x8a,0x3e,0xe9,0x34,0xbd,0x4c,0x16,0xe8,0x87,0x58,0x44,0x81,0x07,0x2e,0xab,0xb0,0x9a,0xf2,0x76,0x9c,0x31,0x19,0x3b,0xc1,0x0a,0xd5,0xe4,0x7f,0xe1,0x25}, + {0x76,0xf6,0x04,0x1e,0xd7,0x9b,0x28,0x0a,0x95,0x0f,0x42,0xd6,0x52,0x1c,0x8e,0x20,0xab,0x1f,0x69,0x34,0xb0,0xd8,0x86,0x51,0x51,0xb3,0x9f,0x2a,0x44,0x51,0x57,0x25,0xa7,0x21,0xf1,0x76,0xf5,0x7f,0x5f,0x91,0xe3,0x87,0xcd,0x2f,0x27,0x32,0x4a,0xc3,0x26,0xe5,0x1b,0x4d,0xde,0x2f,0xba,0xcc,0x9b,0x89,0x69,0x89,0x8f,0x82,0xba,0x6b,0x01,0x39,0xfe,0x90,0x66,0xbc,0xd1,0xe2,0xd5,0x7a,0x99,0xa0,0x18,0x4a,0xb5,0x4c,0xd4,0x60,0x84,0xaf,0x14,0x69,0x1d,0x97,0xe4,0x7b,0x6b,0x7f,0x4f,0x50,0x9d,0x55}, + {0xd5,0x54,0xeb,0xb3,0x78,0x83,0x73,0xa7,0x7c,0x3c,0x55,0xa5,0x66,0xd3,0x69,0x1d,0xba,0x00,0x28,0xf9,0x62,0xcf,0x26,0x0a,0x17,0x32,0x7e,0x80,0xd5,0x12,0xab,0x01,0xfd,0x66,0xd2,0xf6,0xe7,0x91,0x48,0x9c,0x1b,0x78,0x07,0x03,0x9b,0xa1,0x44,0x07,0x3b,0xe2,0x61,0x60,0x1d,0x8f,0x38,0x88,0x0e,0xd5,0x4b,0x35,0xa3,0xa6,0x3e,0x12,0x96,0x2d,0xe3,0x41,0x90,0x18,0x8d,0x11,0x48,0x58,0x31,0xd8,0xc2,0xe3,0xed,0xb9,0xd9,0x45,0x32,0xd8,0x71,0x42,0xab,0x1e,0x54,0xa1,0x18,0xc9,0xe2,0x61,0x39,0x4a}, + {0xa0,0xbb,0xe6,0xf8,0xe0,0x3b,0xdc,0x71,0x0a,0xe3,0xff,0x7e,0x34,0xf8,0xce,0xd6,0x6a,0x47,0x3a,0xe1,0x5f,0x42,0x92,0xa9,0x63,0xb7,0x1d,0xfb,0xe3,0xbc,0xd6,0x2c,0x1e,0x3f,0x23,0xf3,0x44,0xd6,0x27,0x03,0x16,0xf0,0xfc,0x34,0x0e,0x26,0x9a,0x49,0x79,0xb9,0xda,0xf2,0x16,0xa7,0xb5,0x83,0x1f,0x11,0xd4,0x9b,0xad,0xee,0xac,0x68,0x10,0xc2,0xd7,0xf3,0x0e,0xc9,0xb4,0x38,0x0c,0x04,0xad,0xb7,0x24,0x6e,0x8e,0x30,0x23,0x3e,0xe7,0xb7,0xf1,0xd9,0x60,0x38,0x97,0xf5,0x08,0xb5,0xd5,0x60,0x57,0x59}, + {0x97,0x63,0xaa,0x04,0xe1,0xbf,0x29,0x61,0xcb,0xfc,0xa7,0xa4,0x08,0x00,0x96,0x8f,0x58,0x94,0x90,0x7d,0x89,0xc0,0x8b,0x3f,0xa9,0x91,0xb2,0xdc,0x3e,0xa4,0x9f,0x70,0x90,0x27,0x02,0xfd,0xeb,0xcb,0x2a,0x88,0x60,0x57,0x11,0xc4,0x05,0x33,0xaf,0x89,0xf4,0x73,0x34,0x7d,0xe3,0x92,0xf4,0x65,0x2b,0x5a,0x51,0x54,0xdf,0xc5,0xb2,0x2c,0xca,0x2a,0xfd,0x63,0x8c,0x5d,0x0a,0xeb,0xff,0x4e,0x69,0x2e,0x66,0xc1,0x2b,0xd2,0x3a,0xb0,0xcb,0xf8,0x6e,0xf3,0x23,0x27,0x1f,0x13,0xc8,0xf0,0xec,0x29,0xf0,0x70}, + {0x33,0x3e,0xed,0x2e,0xb3,0x07,0x13,0x46,0xe7,0x81,0x55,0xa4,0x33,0x2f,0x04,0xae,0x66,0x03,0x5f,0x19,0xd3,0x49,0x44,0xc9,0x58,0x48,0x31,0x6c,0x8a,0x5d,0x7d,0x0b,0xb9,0xb0,0x10,0x5e,0xaa,0xaf,0x6a,0x2a,0xa9,0x1a,0x04,0xef,0x70,0xa3,0xf0,0x78,0x1f,0xd6,0x3a,0xaa,0x77,0xfb,0x3e,0x77,0xe1,0xd9,0x4b,0xa7,0xa2,0xa5,0xec,0x44,0x43,0xd5,0x95,0x7b,0x32,0x48,0xd4,0x25,0x1d,0x0f,0x34,0xa3,0x00,0x83,0xd3,0x70,0x2b,0xc5,0xe1,0x60,0x1c,0x53,0x1c,0xde,0xe4,0xe9,0x7d,0x2c,0x51,0x24,0x22,0x27}, + {0x2e,0x34,0xc5,0x49,0xaf,0x92,0xbc,0x1a,0xd0,0xfa,0xe6,0xb2,0x11,0xd8,0xee,0xff,0x29,0x4e,0xc8,0xfc,0x8d,0x8c,0xa2,0xef,0x43,0xc5,0x4c,0xa4,0x18,0xdf,0xb5,0x11,0xfc,0x75,0xa9,0x42,0x8a,0xbb,0x7b,0xbf,0x58,0xa3,0xad,0x96,0x77,0x39,0x5c,0x8c,0x48,0xaa,0xed,0xcd,0x6f,0xc7,0x7f,0xe2,0xa6,0x20,0xbc,0xf6,0xd7,0x5f,0x73,0x19,0x66,0x42,0xc8,0x42,0xd0,0x90,0xab,0xe3,0x7e,0x54,0x19,0x7f,0x0f,0x8e,0x84,0xeb,0xb9,0x97,0xa4,0x65,0xd0,0xa1,0x03,0x25,0x5f,0x89,0xdf,0x91,0x11,0x91,0xef,0x0f} +}; diff --git a/ed25519-donna/ed25519-donna-basepoint-table.h b/ed25519-donna/ed25519-donna-basepoint-table.h index 41dcd526a..9c0cdfc0c 100644 --- a/ed25519-donna/ed25519-donna-basepoint-table.h +++ b/ed25519-donna/ed25519-donna-basepoint-table.h @@ -1,259 +1,2 @@ /* multiples of the base point in packed {ysubx, xaddy, t2d} form */ -static const uint8_t ALIGN(16) ge25519_niels_base_multiples[256][96] = { - {0x3e,0x91,0x40,0xd7,0x05,0x39,0x10,0x9d,0xb3,0xbe,0x40,0xd1,0x05,0x9f,0x39,0xfd,0x09,0x8a,0x8f,0x68,0x34,0x84,0xc1,0xa5,0x67,0x12,0xf8,0x98,0x92,0x2f,0xfd,0x44,0x85,0x3b,0x8c,0xf5,0xc6,0x93,0xbc,0x2f,0x19,0x0e,0x8c,0xfb,0xc6,0x2d,0x93,0xcf,0xc2,0x42,0x3d,0x64,0x98,0x48,0x0b,0x27,0x65,0xba,0xd4,0x33,0x3a,0x9d,0xcf,0x07,0x59,0xbb,0x6f,0x4b,0x67,0x15,0xbd,0xdb,0xea,0xa5,0xa2,0xee,0x00,0x3f,0xe1,0x41,0xfa,0xc6,0x57,0xc9,0x1c,0x9d,0xd4,0xcd,0xca,0xec,0x16,0xaf,0x1f,0xbe,0x0e,0x4f}, - {0xa8,0xd5,0xb4,0x42,0x60,0xa5,0x99,0x8a,0xf6,0xac,0x60,0x4e,0x0c,0x81,0x2b,0x8f,0xaa,0x37,0x6e,0xb1,0x6b,0x23,0x9e,0xe0,0x55,0x25,0xc9,0x69,0xa6,0x95,0xb5,0x6b,0xd7,0x71,0x3c,0x93,0xfc,0xe7,0x24,0x92,0xb5,0xf5,0x0f,0x7a,0x96,0x9d,0x46,0x9f,0x02,0x07,0xd6,0xe1,0x65,0x9a,0xa6,0x5a,0x2e,0x2e,0x7d,0xa8,0x3f,0x06,0x0c,0x59,0x02,0x68,0xd3,0xda,0xaa,0x7e,0x34,0x6e,0x05,0x48,0xee,0x83,0x93,0x59,0xf3,0xba,0x26,0x68,0x07,0xe6,0x10,0xbe,0xca,0x3b,0xb8,0xd1,0x5e,0x16,0x0a,0x4f,0x31,0x49}, - {0x65,0xd2,0xfc,0xa4,0xe8,0x1f,0x61,0x56,0x7d,0xba,0xc1,0xe5,0xfd,0x53,0xd3,0x3b,0xbd,0xd6,0x4b,0x21,0x1a,0xf3,0x31,0x81,0x62,0xda,0x5b,0x55,0x87,0x15,0xb9,0x2a,0x30,0x97,0xee,0x4c,0xa8,0xb0,0x25,0xaf,0x8a,0x4b,0x86,0xe8,0x30,0x84,0x5a,0x02,0x32,0x67,0x01,0x9f,0x02,0x50,0x1b,0xc1,0xf4,0xf8,0x80,0x9a,0x1b,0x4e,0x16,0x7a,0x34,0x48,0x67,0xf1,0xf4,0x11,0xf2,0x9b,0x95,0xf8,0x2d,0xf6,0x17,0x6b,0x4e,0xb8,0x4e,0x2a,0x72,0x5b,0x07,0x6f,0xde,0xd7,0x21,0x2a,0xbb,0x63,0xb9,0x04,0x9a,0x54}, - {0xbf,0x18,0x68,0x05,0x0a,0x05,0xfe,0x95,0xa9,0xfa,0x60,0x56,0x71,0x89,0x7e,0x32,0x73,0x50,0xa0,0x06,0xcd,0xe3,0xe8,0xc3,0x9a,0xa4,0x45,0x74,0x4c,0x3f,0x93,0x27,0x9f,0x09,0xfc,0x8e,0xb9,0x51,0x73,0x28,0x38,0x25,0xfd,0x7d,0xf4,0xc6,0x65,0x67,0x65,0x92,0x0a,0xfb,0x3d,0x8d,0x34,0xca,0x27,0x87,0xe5,0x21,0x03,0x91,0x0e,0x68,0xb0,0x26,0x14,0xe5,0xec,0x45,0x1e,0xbf,0x94,0x0f,0xba,0x6d,0x3d,0xc6,0x2b,0xe3,0xc0,0x52,0xf8,0x8c,0xd5,0x74,0x29,0xe4,0x18,0x4c,0xe6,0xb0,0xb1,0x79,0xf0,0x44}, - {0xba,0xd6,0x47,0xa4,0xc3,0x82,0x91,0x7f,0xb7,0x29,0x27,0x4b,0xd1,0x14,0x00,0xd5,0x87,0xa0,0x64,0xb8,0x1c,0xf1,0x3c,0xe3,0xf3,0x55,0x1b,0xeb,0x73,0x7e,0x4a,0x15,0x33,0xbb,0xa5,0x08,0x44,0xbc,0x12,0xa2,0x02,0xed,0x5e,0xc7,0xc3,0x48,0x50,0x8d,0x44,0xec,0xbf,0x5a,0x0c,0xeb,0x1b,0xdd,0xeb,0x06,0xe2,0x46,0xf1,0xcc,0x45,0x29,0xb3,0x03,0xd0,0xe7,0x79,0xa1,0x32,0xc8,0x7e,0x4d,0x12,0x00,0x0a,0x9d,0x72,0x5f,0xf3,0x8f,0x6d,0x0e,0xa1,0xd4,0xc1,0x62,0x98,0x7a,0xb2,0x38,0x59,0xac,0xb8,0x68}, - {0xa4,0x8c,0x7d,0x7b,0xb6,0x06,0x98,0x49,0x39,0x27,0xd2,0x27,0x84,0xe2,0x5b,0x57,0xb9,0x53,0x45,0x20,0xe7,0x5c,0x08,0xbb,0x84,0x78,0x41,0xae,0x41,0x4c,0xb6,0x38,0x31,0x71,0x15,0x77,0xeb,0xee,0x0c,0x3a,0x88,0xaf,0xc8,0x00,0x89,0x15,0x27,0x9b,0x36,0xa7,0x59,0xda,0x68,0xb6,0x65,0x80,0xbd,0x38,0xcc,0xa2,0xb6,0x7b,0xe5,0x51,0xa4,0xe3,0x9d,0x68,0x91,0xad,0x9d,0x8f,0x37,0x91,0xfb,0xf8,0x28,0x24,0x5f,0x17,0x88,0xb9,0xcf,0x9f,0x32,0xb5,0x0a,0x05,0x9f,0xc0,0x54,0x13,0xa2,0xdf,0x65,0x78}, - {0xb1,0x21,0x32,0xaa,0x9a,0x2c,0x6f,0xba,0xa7,0x23,0xba,0x3b,0x53,0x21,0xa0,0x6c,0x3a,0x2c,0x19,0x92,0x4f,0x76,0xea,0x9d,0xe0,0x17,0x53,0x2e,0x5d,0xdd,0x6e,0x1d,0xbf,0xa3,0x4e,0x94,0xd0,0x5c,0x1a,0x6b,0xd2,0xc0,0x9d,0xb3,0x3a,0x35,0x70,0x74,0x49,0x2e,0x54,0x28,0x82,0x52,0xb2,0x71,0x7e,0x92,0x3c,0x28,0x69,0xea,0x1b,0x46,0x36,0xda,0x0f,0xab,0xac,0x8a,0x7a,0x21,0xc8,0x49,0x35,0x3d,0x54,0xc6,0x28,0xa5,0x68,0x75,0xab,0x13,0x8b,0x5b,0xd0,0x37,0x37,0xbc,0x2c,0x3a,0x62,0xef,0x3c,0x23}, - {0xd9,0x34,0x92,0xf3,0xed,0x5d,0xa7,0xe2,0xf9,0x58,0xb5,0xe1,0x80,0x76,0x3d,0x96,0xfb,0x23,0x3c,0x6e,0xac,0x41,0x27,0x2c,0xc3,0x01,0x0e,0x32,0xa1,0x24,0x90,0x3a,0x8f,0x3e,0xdd,0x04,0x66,0x59,0xb7,0x59,0x2c,0x70,0x88,0xe2,0x77,0x03,0xb3,0x6c,0x23,0xc3,0xd9,0x5e,0x66,0x9c,0x33,0xb1,0x2f,0xe5,0xbc,0x61,0x60,0xe7,0x15,0x09,0x7e,0xa3,0x34,0xa8,0x35,0xe8,0x7d,0xdf,0xea,0x57,0x98,0x68,0xda,0x9c,0xe1,0x8b,0x26,0xb3,0x67,0x71,0x36,0x85,0x11,0x2c,0xc2,0xd5,0xef,0xdb,0xd9,0xb3,0x9e,0x58}, - {0x5e,0x51,0xaa,0x49,0x54,0x63,0x5b,0xed,0x3a,0x82,0xc6,0x0b,0x9f,0xc4,0x65,0xa8,0xc4,0xd1,0x42,0x5b,0xe9,0x1f,0x0c,0x85,0xb9,0x15,0xd3,0x03,0x6f,0x6d,0xd7,0x30,0x1d,0x9c,0x2f,0x63,0x0e,0xdd,0xcc,0x2e,0x15,0x31,0x89,0x76,0x96,0xb6,0xd0,0x51,0x58,0x7a,0x63,0xa8,0x6b,0xb7,0xdf,0x52,0x39,0xef,0x0e,0xa0,0x49,0x7d,0xd3,0x6d,0xc7,0xe4,0x06,0x21,0x17,0x44,0x44,0x6c,0x69,0x7f,0x8d,0x92,0x80,0xd6,0x53,0xfb,0x26,0x3f,0x4d,0x69,0xa4,0x9e,0x73,0xb4,0xb0,0x4b,0x86,0x2e,0x11,0x97,0xc6,0x10}, - {0xde,0x5f,0xbe,0x7d,0x27,0xc4,0x93,0x64,0xa2,0x7e,0xad,0x19,0xad,0x4f,0x5d,0x26,0x90,0x45,0x30,0x46,0xc8,0xdf,0x00,0x0e,0x09,0xfe,0x66,0xed,0xab,0x1c,0xe6,0x25,0x05,0xc8,0x58,0x83,0xa0,0x2a,0xa6,0x0c,0x47,0x42,0x20,0x7a,0xe3,0x4a,0x3d,0x6a,0xdc,0xed,0x11,0x3b,0xa6,0xd3,0x64,0x74,0xef,0x06,0x08,0x55,0xaf,0x9b,0xbf,0x03,0x04,0x66,0x58,0xcc,0x28,0xe1,0x13,0x3f,0x7e,0x74,0x59,0xb4,0xec,0x73,0x58,0x6f,0xf5,0x68,0x12,0xcc,0xed,0x3d,0xb6,0xa0,0x2c,0xe2,0x86,0x45,0x63,0x78,0x6d,0x56}, - {0x34,0x08,0xc1,0x9c,0x9f,0xa4,0x37,0x16,0x51,0xc4,0x9b,0xa8,0xd5,0x56,0x8e,0xbc,0xdb,0xd2,0x7f,0x7f,0x0f,0xec,0xb5,0x1c,0xd9,0x35,0xcc,0x5e,0xca,0x5b,0x97,0x33,0xd0,0x2f,0x5a,0xc6,0x85,0x42,0x05,0xa1,0xc3,0x67,0x16,0xf3,0x2a,0x11,0x64,0x6c,0x58,0xee,0x1a,0x73,0x40,0xe2,0x0a,0x68,0x2a,0xb2,0x93,0x47,0xf3,0xa5,0xfb,0x14,0xd4,0xf7,0x85,0x69,0x16,0x46,0xd7,0x3c,0x57,0x00,0xc8,0xc9,0x84,0x5e,0x3e,0x59,0x1e,0x13,0x61,0x7b,0xb6,0xf2,0xc3,0x2f,0x6c,0x52,0xfc,0x83,0xea,0x9c,0x82,0x14}, - {0xc2,0x95,0xdd,0x97,0x84,0x7b,0x43,0xff,0xa7,0xb5,0x4e,0xaa,0x30,0x4e,0x74,0x6c,0x8b,0xe8,0x85,0x3c,0x61,0x5d,0x0c,0x9e,0x73,0x81,0x75,0x5f,0x1e,0xc7,0xd9,0x2f,0xb8,0xec,0x71,0x4e,0x2f,0x0b,0xe7,0x21,0xe3,0x77,0xa4,0x40,0xb9,0xdd,0x56,0xe6,0x80,0x4f,0x1d,0xce,0xce,0x56,0x65,0xbf,0x7e,0x7b,0x5d,0x53,0xc4,0x3b,0xfc,0x05,0xdd,0xde,0xaf,0x52,0xae,0xb3,0xb8,0x24,0xcf,0x30,0x3b,0xed,0x8c,0x63,0x95,0x34,0x95,0x81,0xbe,0xa9,0x83,0xbc,0xa4,0x33,0x04,0x1f,0x65,0x5c,0x47,0x67,0x37,0x37}, - {0xd9,0xad,0xd1,0x40,0xfd,0x99,0xba,0x2f,0x27,0xd0,0xf4,0x96,0x6f,0x16,0x07,0xb3,0xae,0x3b,0xf0,0x15,0x52,0xf0,0x63,0x43,0x99,0xf9,0x18,0x3b,0x6c,0xa5,0xbe,0x1f,0x90,0x65,0x24,0x14,0xcb,0x95,0x40,0x63,0x35,0x55,0xc1,0x16,0x40,0x14,0x12,0xef,0x60,0xbc,0x10,0x89,0x0c,0x14,0x38,0x9e,0x8c,0x7c,0x90,0x30,0x57,0x90,0xf5,0x6b,0x8a,0x5b,0x41,0xe1,0xf1,0x78,0xa7,0x0f,0x7e,0xa7,0xc3,0xba,0xf7,0x9f,0x40,0x06,0x50,0x9a,0xa2,0x9a,0xb8,0xd7,0x52,0x6f,0x56,0x5a,0x63,0x7a,0xf6,0x1c,0x52,0x02}, - {0x94,0x52,0x9d,0x0a,0x0b,0xee,0x3f,0x51,0x66,0x5a,0xdf,0x0f,0x5c,0xe7,0x98,0x8f,0xce,0x07,0xe1,0xbf,0x88,0x86,0x61,0xd4,0xed,0x2c,0x38,0x71,0x7e,0x0a,0xa0,0x3f,0xe4,0x5e,0x2f,0x77,0x20,0x67,0x14,0xb1,0xce,0x9a,0x07,0x96,0xb1,0x94,0xf8,0xe8,0x4a,0x82,0xac,0x00,0x4d,0x22,0xf8,0x4a,0xc4,0x6c,0xcd,0xf7,0xd9,0x53,0x17,0x00,0x34,0xdb,0x3d,0x96,0x2d,0x23,0x69,0x3c,0x58,0x38,0x97,0xb4,0xda,0x87,0xde,0x1d,0x85,0xf2,0x91,0xa0,0xf9,0xd1,0xd7,0xaa,0xb6,0xed,0x48,0xa0,0x2f,0xfe,0xb5,0x12}, - {0x4d,0xe3,0xfc,0x96,0xc4,0xfb,0xf0,0x71,0xed,0x5b,0xf3,0xad,0x6b,0x82,0xb9,0x73,0x61,0xc5,0x28,0xff,0x61,0x72,0x04,0xd2,0x6f,0x20,0xb1,0x6f,0xf9,0x76,0x9b,0x74,0x92,0x1e,0x6f,0xad,0x26,0x7c,0x2b,0xdf,0x13,0x89,0x4b,0x50,0x23,0xd3,0x66,0x4b,0xc3,0x8b,0x1c,0x75,0xc0,0x9d,0x40,0x8c,0xb8,0xc7,0x96,0x07,0xc2,0x93,0x7e,0x6f,0x05,0xae,0xa6,0xae,0x04,0xf6,0x5a,0x1f,0x99,0x9c,0xe4,0xbe,0xf1,0x51,0x23,0xc1,0x66,0x6b,0xff,0xee,0xb5,0x08,0xa8,0x61,0x51,0x21,0xe0,0x01,0x0f,0xc1,0xce,0x0f}, - {0x44,0x1e,0xfe,0x49,0xa6,0x58,0x4d,0x64,0x7e,0x77,0xad,0x31,0xa2,0xae,0xfc,0x21,0xd2,0xd0,0x7f,0x88,0x5a,0x1c,0x44,0x02,0xf3,0x11,0xc5,0x83,0x71,0xaa,0x01,0x49,0x45,0x4e,0x24,0xc4,0x9d,0xd2,0xf2,0x3d,0x0a,0xde,0xd8,0x93,0x74,0x0e,0x02,0x2b,0x4d,0x21,0x0c,0x82,0x7e,0x06,0xc8,0x6c,0x0a,0xb9,0xea,0x6f,0x16,0x79,0x37,0x41,0xf0,0xf8,0x1a,0x8c,0x54,0xb7,0xb1,0x08,0xb4,0x99,0x62,0x24,0x7c,0x7a,0x0f,0xce,0x39,0xd9,0x06,0x1e,0xf9,0xb0,0x60,0xf7,0x13,0x12,0x6d,0x72,0x7b,0x88,0xbb,0x41}, - {0xbe,0x46,0x43,0x74,0x44,0x7d,0xe8,0x40,0x25,0x2b,0xb5,0x15,0xd4,0xda,0x48,0x1d,0x3e,0x60,0x3b,0xa1,0x18,0x8a,0x3a,0x7c,0xf7,0xbd,0xcd,0x2f,0xc1,0x28,0xb7,0x4e,0xae,0x91,0x66,0x7c,0x59,0x4c,0x23,0x7e,0xc8,0xb4,0x85,0x0a,0x3d,0x9d,0x88,0x64,0xe7,0xfa,0x4a,0x35,0x0c,0xc9,0xe2,0xda,0x1d,0x9e,0x6a,0x0c,0x07,0x1e,0x87,0x0a,0x89,0x89,0xbc,0x4b,0x99,0xb5,0x01,0x33,0x60,0x42,0xdd,0x5b,0x3a,0xae,0x6b,0x73,0x3c,0x9e,0xd5,0x19,0xe2,0xad,0x61,0x0d,0x64,0xd4,0x85,0x26,0x0f,0x30,0xe7,0x3e}, - {0xb7,0xd6,0x7d,0x9e,0xe4,0x55,0xd2,0xf5,0xac,0x1e,0x0b,0x61,0x5c,0x11,0x16,0x80,0xca,0x87,0xe1,0x92,0x5d,0x97,0x99,0x3c,0xc2,0x25,0x91,0x97,0x62,0x57,0x81,0x13,0x18,0x75,0x1e,0x84,0x47,0x79,0xfa,0x43,0xd7,0x46,0x9c,0x63,0x59,0xfa,0xc6,0xe5,0x74,0x2b,0x05,0xe3,0x1d,0x5e,0x06,0xa1,0x30,0x90,0xb8,0xcf,0xa2,0xc6,0x47,0x7d,0xe0,0xd6,0xf0,0x8e,0x14,0xd0,0xda,0x3f,0x3c,0x6f,0x54,0x91,0x9a,0x74,0x3e,0x9d,0x57,0x81,0xbb,0x26,0x10,0x62,0xec,0x71,0x80,0xec,0xc9,0x34,0x8d,0xf5,0x8c,0x14}, - {0x27,0xf0,0x34,0x79,0xf6,0x92,0xa4,0x46,0xa9,0x0a,0x84,0xf6,0xbe,0x84,0x99,0x46,0x54,0x18,0x61,0x89,0x2a,0xbc,0xa1,0x5c,0xd4,0xbb,0x5d,0xbd,0x1e,0xfa,0xf2,0x3f,0x6d,0x75,0xe4,0x9a,0x7d,0x2f,0x57,0xe2,0x7f,0x48,0xf3,0x88,0xbb,0x45,0xc3,0x56,0x8d,0xa8,0x60,0x69,0x6d,0x0b,0xd1,0x9f,0xb9,0xa1,0xae,0x4e,0xad,0xeb,0x8f,0x27,0x66,0x39,0x93,0x8c,0x1f,0x68,0xaa,0xb1,0x98,0x0c,0x29,0x20,0x9c,0x94,0x21,0x8c,0x52,0x3c,0x9d,0x21,0x91,0x52,0x11,0x39,0x7b,0x67,0x9c,0xfe,0x02,0xdd,0x04,0x41}, - {0x2a,0x42,0x24,0x11,0x5e,0xbf,0xb2,0x72,0xb5,0x3a,0xa3,0x98,0x33,0x0c,0xfa,0xa1,0x66,0xb6,0x52,0xfa,0x01,0x61,0xcb,0x94,0xd5,0x53,0xaf,0xaf,0x00,0x3b,0x86,0x2c,0xb8,0x6a,0x09,0xdb,0x06,0x4e,0x21,0x81,0x35,0x4f,0xe4,0x0c,0xc9,0xb6,0xa8,0x21,0xf5,0x2a,0x9e,0x40,0x2a,0xc1,0x24,0x65,0x81,0xa4,0xfc,0x8e,0xa4,0xb5,0x65,0x01,0x76,0x6a,0x84,0xa0,0x74,0xa4,0x90,0xf1,0xc0,0x7c,0x2f,0xcd,0x84,0xf9,0xef,0x12,0x8f,0x2b,0xaa,0x58,0x06,0x29,0x5e,0x69,0xb8,0xc8,0xfe,0xbf,0xd9,0x67,0x1b,0x59}, - {0xfa,0x9b,0xb4,0x80,0x1c,0x0d,0x2f,0x31,0x8a,0xec,0xf3,0xab,0x5e,0x51,0x79,0x59,0x88,0x1c,0xf0,0x9e,0xc0,0x33,0x70,0x72,0xcb,0x7b,0x8f,0xca,0xc7,0x2e,0xe0,0x3d,0x5d,0xb5,0x18,0x9f,0x71,0xb3,0xb9,0x99,0x1e,0x64,0x8c,0xa1,0xfa,0xe5,0x65,0xe4,0xed,0x05,0x9f,0xc2,0x36,0x11,0x08,0x61,0x8b,0x12,0x30,0x70,0x86,0x4f,0x9b,0x48,0xef,0x92,0xeb,0x3a,0x2d,0x10,0x32,0xd2,0x61,0xa8,0x16,0x61,0xb4,0x53,0x62,0xe1,0x24,0xaa,0x0b,0x19,0xe7,0xab,0x7e,0x3d,0xbf,0xbe,0x6c,0x49,0xba,0xfb,0xf5,0x49}, - {0xd4,0xcf,0x5b,0x8a,0x10,0x9a,0x94,0x30,0xeb,0x73,0x64,0xbc,0x70,0xdd,0x40,0xdc,0x1c,0x0d,0x7c,0x30,0xc1,0x94,0xc2,0x92,0x74,0x6e,0xfa,0xcb,0x6d,0xa8,0x04,0x56,0x2e,0x57,0x9c,0x1e,0x8c,0x62,0x5d,0x15,0x41,0x47,0x88,0xc5,0xac,0x86,0x4d,0x8a,0xeb,0x63,0x57,0x51,0xf6,0x52,0xa3,0x91,0x5b,0x51,0x67,0x88,0xc2,0xa6,0xa1,0x06,0xb6,0x64,0x17,0x7c,0xd4,0xd1,0x88,0x72,0x51,0x8b,0x41,0xe0,0x40,0x11,0x54,0x72,0xd1,0xf6,0xac,0x18,0x60,0x1a,0x03,0x9f,0xc6,0x42,0x27,0xfe,0x89,0x9e,0x98,0x20}, - {0x7f,0xcc,0x2d,0x3a,0xfd,0x77,0x97,0x49,0x92,0xd8,0x4f,0xa5,0x2c,0x7c,0x85,0x32,0xa0,0xe3,0x07,0xd2,0x64,0xd8,0x79,0xa2,0x29,0x7e,0xa6,0x0c,0x1d,0xed,0x03,0x04,0x2e,0xec,0xea,0x85,0x8b,0x27,0x74,0x16,0xdf,0x2b,0xcb,0x7a,0x07,0xdc,0x21,0x56,0x5a,0xf4,0xcb,0x61,0x16,0x4c,0x0a,0x64,0xd3,0x95,0x05,0xf7,0x50,0x99,0x0b,0x73,0x52,0xc5,0x4e,0x87,0x35,0x2d,0x4b,0xc9,0x8d,0x6f,0x24,0x98,0xcf,0xc8,0xe6,0xc5,0xce,0x35,0xc0,0x16,0xfa,0x46,0xcb,0xf7,0xcc,0x3d,0x30,0x08,0x43,0x45,0xd7,0x5b}, - {0xc2,0x4c,0xb2,0x28,0x95,0xd1,0x9a,0x7f,0x81,0xc1,0x35,0x63,0x65,0x54,0x6b,0x7f,0x36,0x72,0xc0,0x4f,0x6e,0xb6,0xb8,0x66,0x83,0xad,0x80,0x73,0x00,0x78,0x3a,0x13,0x2a,0x79,0xe7,0x15,0x21,0x93,0xc4,0x85,0xc9,0xdd,0xcd,0xbd,0xa2,0x89,0x4c,0xc6,0x62,0xd7,0xa3,0xad,0xa8,0x3d,0x1e,0x9d,0x2c,0xf8,0x67,0x30,0x12,0xdb,0xb7,0x5b,0xbe,0x62,0xca,0xc6,0x67,0xf4,0x61,0x09,0xee,0x52,0x19,0x21,0xd6,0x21,0xec,0x04,0x70,0x47,0xd5,0x9b,0x77,0x60,0x23,0x18,0xd2,0xe0,0xf0,0x58,0x6d,0xca,0x0d,0x74}, - {0x4e,0xce,0xcf,0x52,0x07,0xee,0x48,0xdf,0xb7,0x08,0xec,0x06,0xf3,0xfa,0xff,0xc3,0xc4,0x59,0x54,0xb9,0x2a,0x0b,0x71,0x05,0x8d,0xa3,0x3e,0x96,0xfa,0x25,0x1d,0x16,0x3c,0x43,0x78,0x04,0x57,0x8c,0x1a,0x23,0x9d,0x43,0x81,0xc2,0x0e,0x27,0xb5,0xb7,0x9f,0x07,0xd9,0xe3,0xea,0x99,0xaa,0xdb,0xd9,0x03,0x2b,0x6c,0x25,0xf5,0x03,0x2c,0x7d,0xa4,0x53,0x7b,0x75,0x18,0x0f,0x79,0x79,0x58,0x0c,0xcf,0x30,0x01,0x7b,0x30,0xf9,0xf7,0x7e,0x25,0x77,0x3d,0x90,0x31,0xaf,0xbb,0x96,0xbd,0xbd,0x68,0x94,0x69}, - {0xcf,0xfe,0xda,0xf4,0x46,0x2f,0x1f,0xbd,0xf7,0xd6,0x7f,0xa4,0x14,0x01,0xef,0x7c,0x7f,0xb3,0x47,0x4a,0xda,0xfd,0x1f,0xd3,0x85,0x57,0x90,0x73,0xa4,0x19,0x52,0x52,0x48,0x19,0xa9,0x6a,0xe6,0x3d,0xdd,0xd8,0xcc,0xd2,0xc0,0x2f,0xc2,0x64,0x50,0x48,0x2f,0xea,0xfd,0x34,0x66,0x24,0x48,0x9b,0x3a,0x2e,0x4a,0x6c,0x4e,0x1c,0x3e,0x29,0xe1,0x12,0x51,0x92,0x4b,0x13,0x6e,0x37,0xa0,0x5d,0xa1,0xdc,0xb5,0x78,0x37,0x70,0x11,0x31,0x1c,0x46,0xaf,0x89,0x45,0xb0,0x23,0x28,0x03,0x7f,0x44,0x5c,0x60,0x5b}, - {0x89,0x7c,0xc4,0x20,0x59,0x80,0x65,0xb9,0xcc,0x8f,0x3b,0x92,0x0c,0x10,0xf0,0xe7,0x77,0xef,0xe2,0x02,0x65,0x25,0x01,0x00,0xee,0xb3,0xae,0xa8,0xce,0x6d,0xa7,0x24,0x4c,0xf0,0xe7,0xf0,0xc6,0xfe,0xe9,0x3b,0x62,0x49,0xe3,0x75,0x9e,0x57,0x6a,0x86,0x1a,0xe6,0x1d,0x1e,0x16,0xef,0x42,0x55,0xd5,0xbd,0x5a,0xcc,0xf4,0xfe,0x12,0x2f,0x40,0xc7,0xc0,0xdf,0xb2,0x22,0x45,0x0a,0x07,0xa4,0xc9,0x40,0x7f,0x6e,0xd0,0x10,0x68,0xf6,0xcf,0x78,0x41,0x14,0xcf,0xc6,0x90,0x37,0xa4,0x18,0x25,0x7b,0x60,0x5e}, - {0x18,0x18,0xdf,0x6c,0x8f,0x1d,0xb3,0x58,0xa2,0x58,0x62,0xc3,0x4f,0xa7,0xcf,0x35,0x6e,0x1d,0xe6,0x66,0x4f,0xff,0xb3,0xe1,0xf7,0xd5,0xcd,0x6c,0xab,0xac,0x67,0x50,0x14,0xcf,0x96,0xa5,0x1c,0x43,0x2c,0xa0,0x00,0xe4,0xd3,0xae,0x40,0x2d,0xc4,0xe3,0xdb,0x26,0x0f,0x2e,0x80,0x26,0x45,0xd2,0x68,0x70,0x45,0x9e,0x13,0x33,0x1f,0x20,0x51,0x9d,0x03,0x08,0x6b,0x7f,0x52,0xfd,0x06,0x00,0x7c,0x01,0x64,0x49,0xb1,0x18,0xa8,0xa4,0x25,0x2e,0xb0,0x0e,0x22,0xd5,0x75,0x03,0x46,0x62,0x88,0xba,0x7c,0x39}, - {0xb2,0x59,0x59,0xf0,0x93,0x30,0xc1,0x30,0x76,0x79,0xa9,0xe9,0x8d,0xa1,0x3a,0xe2,0x26,0x5e,0x1d,0x72,0x91,0xd4,0x2f,0x22,0x3a,0x6c,0x6e,0x76,0x20,0xd3,0x39,0x23,0xe7,0x79,0x13,0xc8,0xfb,0xc3,0x15,0x78,0xf1,0x2a,0xe1,0xdd,0x20,0x94,0x61,0xa6,0xd5,0xfd,0xa8,0x85,0xf8,0xc0,0xa9,0xff,0x52,0xc2,0xe1,0xc1,0x22,0x40,0x1b,0x77,0xa7,0x2f,0x3a,0x51,0x86,0xd9,0x7d,0xd8,0x08,0xcf,0xd4,0xf9,0x71,0x9b,0xac,0xf5,0xb3,0x83,0xa2,0x1e,0x1b,0xc3,0x6b,0xd0,0x76,0x1a,0x97,0x19,0x92,0x18,0x1a,0x33}, - {0xc6,0x80,0x4f,0xfb,0x45,0x6f,0x16,0xf5,0xcf,0x75,0xc7,0x61,0xde,0xc7,0x36,0x9c,0x1c,0xd9,0x41,0x90,0x1b,0xe8,0xd4,0xe3,0x21,0xfe,0xbd,0x83,0x6b,0x7c,0x16,0x31,0xaf,0x72,0x75,0x9d,0x3a,0x2f,0x51,0x26,0x9e,0x4a,0x07,0x68,0x88,0xe2,0xcb,0x5b,0xc4,0xf7,0x80,0x11,0xc1,0xc1,0xed,0x84,0x7b,0xa6,0x49,0xf6,0x9f,0x61,0xc9,0x1a,0x68,0x10,0x4b,0x52,0x42,0x38,0x2b,0xf2,0x87,0xe9,0x9c,0xee,0x3b,0x34,0x68,0x50,0xc8,0x50,0x62,0x4a,0x84,0x71,0x9d,0xfc,0x11,0xb1,0x08,0x1f,0x34,0x36,0x24,0x61}, - {0x8d,0x89,0x4e,0x87,0xdb,0x41,0x9d,0xd9,0x20,0xdc,0x07,0x6c,0xf1,0xa5,0xfe,0x09,0xbc,0x9b,0x0f,0xd0,0x67,0x2c,0x3d,0x79,0x40,0xff,0x5e,0x9e,0x30,0xe2,0xeb,0x46,0x38,0x26,0x2d,0x1a,0xe3,0x49,0x63,0x8b,0x35,0xfd,0xd3,0x9b,0x00,0xb7,0xdf,0x9d,0xa4,0x6b,0xa0,0xa3,0xb8,0xf1,0x8b,0x7f,0x45,0x04,0xd9,0x78,0x31,0xaa,0x22,0x15,0x38,0x49,0x61,0x69,0x53,0x2f,0x38,0x2c,0x10,0x6d,0x2d,0xb7,0x9a,0x40,0xfe,0xda,0x27,0xf2,0x46,0xb6,0x91,0x33,0xc8,0xe8,0x6c,0x30,0x24,0x05,0xf5,0x70,0xfe,0x45}, - {0x8c,0x0b,0x0c,0x96,0xa6,0x75,0x48,0xda,0x20,0x2f,0x0e,0xef,0x76,0xd0,0x68,0x5b,0xd4,0x8f,0x0b,0x3d,0xcf,0x51,0xfb,0x07,0xd4,0x92,0xe3,0xa0,0x23,0x16,0x8d,0x42,0x91,0x14,0x95,0xc8,0x20,0x49,0xf2,0x62,0xa2,0x0c,0x63,0x3f,0xc8,0x07,0xf0,0x05,0xb8,0xd4,0xc9,0xf5,0xd2,0x45,0xbb,0x6f,0x45,0x22,0x7a,0xb5,0x6d,0x9f,0x61,0x16,0xfd,0x08,0xa3,0x01,0x44,0x4a,0x4f,0x08,0xac,0xca,0xa5,0x76,0xc3,0x19,0x22,0xa8,0x7d,0xbc,0xd1,0x43,0x46,0xde,0xb8,0xde,0xc6,0x38,0xbd,0x60,0x2d,0x59,0x81,0x1d}, - {0x5f,0xac,0x0d,0xa6,0x56,0x87,0x36,0x61,0x57,0xdc,0xab,0xeb,0x6a,0x2f,0xe0,0x17,0x7d,0x0f,0xce,0x4c,0x2d,0x3f,0x19,0x7f,0xf0,0xdc,0xec,0x89,0x77,0x4a,0x23,0x20,0xe8,0xc5,0x85,0x7b,0x9f,0xb6,0x65,0x87,0xb2,0xba,0x68,0xd1,0x8b,0x67,0xf0,0x6f,0x9b,0x0f,0x33,0x1d,0x7c,0xe7,0x70,0x3a,0x7c,0x8e,0xaf,0xb0,0x51,0x6d,0x5f,0x3a,0x52,0xb2,0x78,0x71,0xb6,0x0d,0xd2,0x76,0x60,0xd1,0x1e,0xd5,0xf9,0x34,0x1c,0x07,0x70,0x11,0xe4,0xb3,0x20,0x4a,0x2a,0xf6,0x66,0xe3,0xff,0x3c,0x35,0x82,0xd6,0x7c}, - {0xb6,0xfa,0x87,0xd8,0x5b,0xa4,0xe1,0x0b,0x6e,0x3b,0x40,0xba,0x32,0x6a,0x84,0x2a,0x00,0x60,0x6e,0xe9,0x12,0x10,0x92,0xd9,0x43,0x09,0xdc,0x3b,0x86,0xc8,0x38,0x28,0xf3,0xf4,0xac,0x68,0x60,0xcd,0x65,0xa6,0xd3,0xe3,0xd7,0x3c,0x18,0x2d,0xd9,0x42,0xd9,0x25,0x60,0x33,0x9d,0x38,0x59,0x57,0xff,0xd8,0x2c,0x2b,0x3b,0x25,0xf0,0x3e,0x30,0x50,0x46,0x4a,0xcf,0xb0,0x6b,0xd1,0xab,0x77,0xc5,0x15,0x41,0x6b,0x49,0xfa,0x9d,0x41,0xab,0xf4,0x8a,0xae,0xcf,0x82,0x12,0x28,0xa8,0x06,0xa6,0xb8,0xdc,0x21}, - {0xc8,0x9f,0x9d,0x8c,0x46,0x04,0x60,0x5c,0xcb,0xa3,0x2a,0xd4,0x6e,0x09,0x40,0x25,0x9c,0x2f,0xee,0x12,0x4c,0x4d,0x5b,0x12,0xab,0x1d,0xa3,0x94,0x81,0xd0,0xc3,0x0b,0xba,0x31,0x77,0xbe,0xfa,0x00,0x8d,0x9a,0x89,0x18,0x9e,0x62,0x7e,0x60,0x03,0x82,0x7f,0xd9,0xf3,0x43,0x37,0x02,0xcc,0xb2,0x8b,0x67,0x6f,0x6c,0xbf,0x0d,0x84,0x5d,0x8b,0xe1,0x9f,0x30,0x0d,0x38,0x6e,0x70,0xc7,0x65,0xe1,0xb9,0xa6,0x2d,0xb0,0x6e,0xab,0x20,0xae,0x7d,0x99,0xba,0xbb,0x57,0xdd,0x96,0xc1,0x2a,0x23,0x76,0x42,0x3a}, - {0xfa,0x84,0x70,0x8a,0x2c,0x43,0x42,0x4b,0x45,0xe5,0xb9,0xdf,0xe3,0x19,0x8a,0x89,0x5d,0xe4,0x58,0x9c,0x21,0x00,0x9f,0xbe,0xd1,0xeb,0x6d,0xa1,0xce,0x77,0xf1,0x1f,0xcb,0x7e,0x44,0xdb,0x72,0xc1,0xf8,0x3b,0xbd,0x2d,0x28,0xc6,0x1f,0xc4,0xcf,0x5f,0xfe,0x15,0xaa,0x75,0xc0,0xff,0xac,0x80,0xf9,0xa9,0xe1,0x24,0xe8,0xc9,0x70,0x07,0xfd,0xb5,0xb5,0x45,0x9a,0xd9,0x61,0xcf,0x24,0x79,0x3a,0x1b,0xe9,0x84,0x09,0x86,0x89,0x3e,0x3e,0x30,0x19,0x09,0x30,0xe7,0x1e,0x0b,0x50,0x41,0xfd,0x64,0xf2,0x39}, - {0x9c,0xe2,0xe7,0xdb,0x17,0x34,0xad,0xa7,0x9c,0x13,0x9c,0x2b,0x6a,0x37,0x94,0xbd,0xa9,0x7b,0x59,0x93,0x8e,0x1b,0xe9,0xa0,0x40,0x98,0x88,0x68,0x34,0xd7,0x12,0x17,0xe1,0x7b,0x09,0xfe,0xab,0x4a,0x9b,0xd1,0x29,0x19,0xe0,0xdf,0xe1,0xfc,0x6d,0xa4,0xff,0xf1,0xa6,0x2c,0x94,0x08,0xc9,0xc3,0x4e,0xf1,0x35,0x2c,0x27,0x21,0xc6,0x65,0xdd,0x93,0x31,0xce,0xf8,0x89,0x2b,0xe7,0xbb,0xc0,0x25,0xa1,0x56,0x33,0x10,0x4d,0x83,0xfe,0x1c,0x2e,0x3d,0xa9,0x19,0x04,0x72,0xe2,0x9c,0xb1,0x0a,0x80,0xf9,0x22}, - {0xcb,0xf8,0x9e,0x3e,0x8a,0x36,0x5a,0x60,0x15,0x47,0x50,0xa5,0x22,0xc0,0xe9,0xe3,0x8f,0x24,0x24,0x5f,0xb0,0x48,0x3d,0x55,0xe5,0x26,0x76,0x64,0xcd,0x16,0xf4,0x13,0xac,0xfd,0x6e,0x9a,0xdd,0x9f,0x02,0x42,0x41,0x49,0xa5,0x34,0xbe,0xce,0x12,0xb9,0x7b,0xf3,0xbd,0x87,0xb9,0x64,0x0f,0x64,0xb4,0xca,0x98,0x85,0xd3,0xa4,0x71,0x41,0x8c,0x4c,0xc9,0x99,0xaa,0x58,0x27,0xfa,0x07,0xb8,0x00,0xb0,0x6f,0x6f,0x00,0x23,0x92,0x53,0xda,0xad,0xdd,0x91,0xd2,0xfb,0xab,0xd1,0x4b,0x57,0xfa,0x14,0x82,0x50}, - {0x4b,0xfe,0xd6,0x3e,0x15,0x69,0x02,0xc2,0xc4,0x77,0x1d,0x51,0x39,0x67,0x5a,0xa6,0x94,0xaf,0x14,0x2c,0x46,0x26,0xde,0xcb,0x4b,0xa7,0xab,0x6f,0xec,0x60,0xf9,0x22,0xd6,0x03,0xd0,0x53,0xbb,0x15,0x1a,0x46,0x65,0xc9,0xf3,0xbc,0x88,0x28,0x10,0xb2,0x5a,0x3a,0x68,0x6c,0x75,0x76,0xc5,0x27,0x47,0xb4,0x6c,0xc8,0xa4,0x58,0x77,0x3a,0x76,0x50,0xae,0x93,0xf6,0x11,0x81,0x54,0xa6,0x54,0xfd,0x1d,0xdf,0x21,0xae,0x1d,0x65,0x5e,0x11,0xf3,0x90,0x8c,0x24,0x12,0x94,0xf4,0xe7,0x8d,0x5f,0xd1,0x9f,0x5d}, - {0x7f,0x72,0x63,0x6d,0xd3,0x08,0x14,0x03,0x33,0xb5,0xc7,0xd7,0xef,0x9a,0x37,0x6a,0x4b,0xe2,0xae,0xcc,0xc5,0x8f,0xe1,0xa9,0xd3,0xbe,0x8f,0x4f,0x91,0x35,0x2f,0x33,0x1e,0x52,0xd7,0xee,0x2a,0x4d,0x24,0x3f,0x15,0x96,0x2e,0x43,0x28,0x90,0x3a,0x8e,0xd4,0x16,0x9c,0x2e,0x77,0xba,0x64,0xe1,0xd8,0x98,0xeb,0x47,0xfa,0x87,0xc1,0x3b,0x0c,0xc2,0x86,0xea,0x15,0x01,0x47,0x6d,0x25,0xd1,0x46,0x6c,0xcb,0xb7,0x8a,0x99,0x88,0x01,0x66,0x3a,0xb5,0x32,0x78,0xd7,0x03,0xba,0x6f,0x90,0xce,0x81,0x0d,0x45}, - {0x75,0x52,0x20,0xa6,0xa1,0xb6,0x7b,0x6e,0x83,0x8e,0x3c,0x41,0xd7,0x21,0x4f,0xaa,0xb2,0x5c,0x8f,0xe8,0x55,0xd1,0x56,0x6f,0xe1,0x5b,0x34,0xa6,0x4b,0x5d,0xe2,0x2d,0x3f,0x74,0xae,0x1c,0x96,0xd8,0x74,0xd0,0xed,0x63,0x1c,0xee,0xf5,0x18,0x6d,0xf8,0x29,0xed,0xf4,0xe7,0x5b,0xc5,0xbd,0x97,0x08,0xb1,0x3a,0x66,0x79,0xd2,0xba,0x4c,0xcd,0x1f,0xd7,0xa0,0x24,0x90,0xd1,0x80,0xf8,0x8a,0x28,0xfb,0x0a,0xc2,0x25,0xc5,0x19,0x64,0x3a,0x5f,0x4b,0x97,0xa3,0xb1,0x33,0x72,0x00,0xe2,0xef,0xbc,0x7f,0x7d}, - {0x01,0x28,0x6b,0x26,0x6a,0x1e,0xef,0xfa,0x16,0x9f,0x73,0xd5,0xc4,0x68,0x6c,0x86,0x2c,0x76,0x03,0x1b,0xbc,0x2f,0x8a,0xf6,0x8d,0x5a,0xb7,0x87,0x5e,0x43,0x75,0x59,0x94,0x90,0xc2,0xf3,0xc5,0x5d,0x7c,0xcd,0xab,0x05,0x91,0x2a,0x9a,0xa2,0x81,0xc7,0x58,0x30,0x1c,0x42,0x36,0x1d,0xc6,0x80,0xd7,0xd4,0xd8,0xdc,0x96,0xd1,0x9c,0x4f,0x68,0x37,0x7b,0x6a,0xd8,0x97,0x92,0x19,0x63,0x7a,0xd1,0x1a,0x24,0x58,0xd0,0xd0,0x17,0x0c,0x1c,0x5c,0xad,0x9c,0x02,0xba,0x07,0x03,0x7a,0x38,0x84,0xd0,0xcd,0x7c}, - {0x17,0x04,0x26,0x6d,0x2c,0x42,0xa6,0xdc,0xbd,0x40,0x82,0x94,0x50,0x3d,0x15,0xae,0x77,0xc6,0x68,0xfb,0xb4,0xc1,0xc0,0xa9,0x53,0xcf,0xd0,0x61,0xed,0xd0,0x8b,0x42,0x93,0xcc,0x60,0x67,0x18,0x84,0x0c,0x9b,0x99,0x2a,0xb3,0x1a,0x7a,0x00,0xae,0xcd,0x18,0xda,0x0b,0x62,0x86,0xec,0x8d,0xa8,0x44,0xca,0x90,0x81,0x84,0xca,0x93,0x35,0xa7,0x9a,0x84,0x5e,0x9a,0x18,0x13,0x92,0xcd,0xfa,0xd8,0x65,0x35,0xc3,0xd8,0xd4,0xd1,0xbb,0xfd,0x53,0x5b,0x54,0x52,0x8c,0xe6,0x63,0x2d,0xda,0x08,0x83,0x39,0x27}, - {0x13,0xd4,0x5e,0x43,0x28,0x8d,0xc3,0x42,0xc9,0xcc,0x78,0x32,0x60,0xf3,0x50,0xbd,0xef,0x03,0xda,0x79,0x1a,0xab,0x07,0xbb,0x55,0x33,0x8c,0xbe,0xae,0x97,0x95,0x26,0x53,0x24,0x70,0x0a,0x4c,0x0e,0xa1,0xb9,0xde,0x1b,0x7d,0xd5,0x66,0x58,0xa2,0x0f,0xf7,0xda,0x27,0xcd,0xb5,0xd9,0xb9,0xff,0xfd,0x33,0x2c,0x49,0x45,0x29,0x2c,0x57,0xbe,0x30,0xcd,0xd6,0x45,0xc7,0x7f,0xc7,0xfb,0xae,0xba,0xe3,0xd3,0xe8,0xdf,0xe4,0x0c,0xda,0x5d,0xaa,0x30,0x88,0x2c,0xa2,0x80,0xca,0x5b,0xc0,0x98,0x54,0x98,0x7f}, - {0x17,0xe1,0x0b,0x9f,0x88,0xce,0x49,0x38,0x88,0xa2,0x54,0x7b,0x1b,0xad,0x05,0x80,0x1c,0x92,0xfc,0x23,0x9f,0xc3,0xa3,0x3d,0x04,0xf3,0x31,0x0a,0x47,0xec,0xc2,0x76,0x63,0x63,0xbf,0x0f,0x52,0x15,0x56,0xd3,0xa6,0xfb,0x4d,0xcf,0x45,0x5a,0x04,0x08,0xc2,0xa0,0x3f,0x87,0xbc,0x4f,0xc2,0xee,0xe7,0x12,0x9b,0xd6,0x3c,0x65,0xf2,0x30,0x85,0x0c,0xc1,0xaa,0x38,0xc9,0x08,0x8a,0xcb,0x6b,0x27,0xdb,0x60,0x9b,0x17,0x46,0x70,0xac,0x6f,0x0e,0x1e,0xc0,0x20,0xa9,0xda,0x73,0x64,0x59,0xf1,0x73,0x12,0x2f}, - {0x11,0x1e,0xe0,0x8a,0x7c,0xfc,0x39,0x47,0x9f,0xab,0x6a,0x4a,0x90,0x74,0x52,0xfd,0x2e,0x8f,0x72,0x87,0x82,0x8a,0xd9,0x41,0xf2,0x69,0x5b,0xd8,0x2a,0x57,0x9e,0x5d,0xc0,0x0b,0xa7,0x55,0xd7,0x8b,0x48,0x30,0xe7,0x42,0xd4,0xf1,0xa4,0xb5,0xd6,0x06,0x62,0x61,0x59,0xbc,0x9e,0xa6,0xd1,0xea,0x84,0xf7,0xc5,0xed,0x97,0x19,0xac,0x38,0x3b,0xb1,0x51,0xa7,0x17,0xb5,0x66,0x06,0x8c,0x85,0x9b,0x7e,0x86,0x06,0x7d,0x74,0x49,0xde,0x4d,0x45,0x11,0xc0,0xac,0xac,0x9c,0xe6,0xe9,0xbf,0x9c,0xcd,0xdf,0x22}, - {0xd9,0x0c,0x0d,0xc3,0xe0,0xd2,0xdb,0x8d,0x33,0x43,0xbb,0xac,0x5f,0x66,0x8e,0xad,0x1f,0x96,0x2a,0x32,0x8c,0x25,0x6b,0x8f,0xc7,0xc1,0x48,0x54,0xc0,0x16,0x29,0x6b,0xa1,0xe0,0x3b,0x10,0xb4,0x59,0xec,0x56,0x69,0xf9,0x59,0xd2,0xec,0xba,0xe3,0x2e,0x32,0xcd,0xf5,0x13,0x94,0xb2,0x7c,0x79,0x72,0xe4,0xcd,0x24,0x78,0x87,0xe9,0x0f,0x3b,0x91,0xba,0x0a,0xd1,0x34,0xdb,0x7e,0x0e,0xac,0x6d,0x2e,0x82,0xcd,0xa3,0x4e,0x15,0xf8,0x78,0x65,0xff,0x3d,0x08,0x66,0x17,0x0a,0xf0,0x7f,0x30,0x3f,0x30,0x4c}, - {0x85,0x8c,0xb2,0x17,0xd6,0x3b,0x0a,0xd3,0xea,0x3b,0x77,0x39,0xb7,0x77,0xd3,0xc5,0xbf,0x5c,0x6a,0x1e,0x8c,0xe7,0xc6,0xc6,0xc4,0xb7,0x2a,0x8b,0xf7,0xb8,0x61,0x0d,0x00,0x45,0xd9,0x0d,0x58,0x03,0xfc,0x29,0x93,0xec,0xbb,0x6f,0xa4,0x7a,0xd2,0xec,0xf8,0xa7,0xe2,0xc2,0x5f,0x15,0x0a,0x13,0xd5,0xa1,0x06,0xb7,0x1a,0x15,0x6b,0x41,0xb0,0x36,0xc1,0xe9,0xef,0xd7,0xa8,0x56,0x20,0x4b,0xe4,0x58,0xcd,0xe5,0x07,0xbd,0xab,0xe0,0x57,0x1b,0xda,0x2f,0xe6,0xaf,0xd2,0xe8,0x77,0x42,0xf7,0x2a,0x1a,0x19}, - {0x31,0x14,0x3c,0xc5,0x4b,0xf7,0x16,0xce,0xde,0xed,0x72,0x20,0xce,0x25,0x97,0x2b,0xe7,0x3e,0xb2,0xb5,0x6f,0xc3,0xb9,0xb8,0x08,0xc9,0x5c,0x0b,0x45,0x0e,0x2e,0x7e,0xfb,0x0e,0x46,0x4f,0x43,0x2b,0xe6,0x9f,0xd6,0x07,0x36,0xa6,0xd4,0x03,0xd3,0xde,0x24,0xda,0xa0,0xb7,0x0e,0x21,0x52,0xf0,0x93,0x5b,0x54,0x00,0xbe,0x7d,0x7e,0x23,0x30,0xb4,0x01,0x67,0xed,0x75,0x35,0x01,0x10,0xfd,0x0b,0x9f,0xe6,0x94,0x10,0x23,0x22,0x7f,0xe4,0x83,0x15,0x0f,0x32,0x75,0xe3,0x55,0x11,0xb1,0x99,0xa6,0xaf,0x71}, - {0x1d,0xb6,0x53,0x39,0x9b,0x6f,0xce,0x65,0xe6,0x41,0xa1,0xaf,0xea,0x39,0x58,0xc6,0xfe,0x59,0xf7,0xa9,0xfd,0x5f,0x43,0x0f,0x8e,0xc2,0xb1,0xc2,0xe9,0x42,0x11,0x02,0xd6,0x50,0x3b,0x47,0x1c,0x3c,0x42,0xea,0x10,0xef,0x38,0x3b,0x1f,0x7a,0xe8,0x51,0x95,0xbe,0xc9,0xb2,0x5f,0xbf,0x84,0x9b,0x1c,0x9a,0xf8,0x78,0xbc,0x1f,0x73,0x00,0x80,0x18,0xf8,0x48,0x18,0xc7,0x30,0xe4,0x19,0xc1,0xce,0x5e,0x22,0x0c,0x96,0xbf,0xe3,0x15,0xba,0x6b,0x83,0xe0,0xda,0xb6,0x08,0x58,0xe1,0x47,0x33,0x6f,0x4d,0x4c}, - {0xc9,0x1f,0x7d,0xc1,0xcf,0xec,0xf7,0x18,0x14,0x3c,0x40,0x51,0xa6,0xf5,0x75,0x6c,0xdf,0x0c,0xee,0xf7,0x2b,0x71,0xde,0xdb,0x22,0x7a,0xe4,0xa7,0xaa,0xdd,0x3f,0x19,0x70,0x19,0x8f,0x98,0xfc,0xdd,0x0c,0x2f,0x1b,0xf5,0xb9,0xb0,0x27,0x62,0x91,0x6b,0xbe,0x76,0x91,0x77,0xc4,0xb6,0xc7,0x6e,0xa8,0x9f,0x8f,0xa8,0x00,0x95,0xbf,0x38,0x6f,0x87,0xe8,0x37,0x3c,0xc9,0xd2,0x1f,0x2c,0x46,0xd1,0x18,0x5a,0x1e,0xf6,0xa2,0x76,0x12,0x24,0x39,0x82,0xf5,0x80,0x50,0x69,0x49,0x0d,0xbf,0x9e,0xb9,0x6f,0x6a}, - {0xeb,0x55,0x08,0x56,0xbb,0xc1,0x46,0x6a,0x9d,0xf0,0x93,0xf8,0x38,0xbb,0x16,0x24,0xc1,0xac,0x71,0x8f,0x37,0x11,0x1d,0xd7,0xea,0x96,0x18,0xa3,0x14,0x69,0xf7,0x75,0xc6,0x23,0xe4,0xb6,0xb5,0x22,0xb1,0xee,0x8e,0xff,0x86,0xf2,0x10,0x70,0x9d,0x93,0x8c,0x5d,0xcf,0x1d,0x83,0x2a,0xa9,0x90,0x10,0xeb,0xc5,0x42,0x9f,0xda,0x6f,0x13,0xd1,0xbd,0x05,0xa3,0xb1,0xdf,0x4c,0xf9,0x08,0x2c,0xf8,0x9f,0x9d,0x4b,0x36,0x0f,0x8a,0x58,0xbb,0xc3,0xa5,0xd8,0x87,0x2a,0xba,0xdc,0xe8,0x0b,0x51,0x83,0x21,0x02}, - {0x14,0x2d,0xad,0x5e,0x38,0x66,0xf7,0x4a,0x30,0x58,0x7c,0xca,0x80,0xd8,0x8e,0xa0,0x3d,0x1e,0x21,0x10,0xe6,0xa6,0x13,0x0d,0x03,0x6c,0x80,0x7b,0xe1,0x1c,0x07,0x6a,0x7f,0x7a,0x30,0x43,0x01,0x71,0x5a,0x9d,0x5f,0xa4,0x7d,0xc4,0x9e,0xde,0x63,0xb0,0xd3,0x7a,0x92,0xbe,0x52,0xfe,0xbb,0x22,0x6c,0x42,0x40,0xfd,0x41,0xc4,0x87,0x13,0xf8,0x8a,0x97,0x87,0xd1,0xc3,0xd3,0xb5,0x13,0x44,0x0e,0x7f,0x3d,0x5a,0x2b,0x72,0xa0,0x7c,0x47,0xbb,0x48,0x48,0x7b,0x0d,0x92,0xdc,0x1e,0xaf,0x6a,0xb2,0x71,0x31}, - {0xa8,0x4c,0x56,0x97,0x90,0x31,0x2f,0xa9,0x19,0xe1,0x75,0x22,0x4c,0xb8,0x7b,0xff,0x50,0x51,0x87,0xa4,0x37,0xfe,0x55,0x4f,0x5a,0x83,0xf0,0x3c,0x87,0xd4,0x1f,0x22,0xd1,0x47,0x8a,0xb2,0xd8,0xb7,0x0d,0xa6,0xf1,0xa4,0x70,0x17,0xd6,0x14,0xbf,0xa6,0x58,0xbd,0xdd,0x53,0x93,0xf8,0xa1,0xd4,0xe9,0x43,0x42,0x34,0x63,0x4a,0x51,0x6c,0x41,0x63,0x15,0x3a,0x4f,0x20,0x22,0x23,0x2d,0x03,0x0a,0xba,0xe9,0xe0,0x73,0xfb,0x0e,0x03,0x0f,0x41,0x4c,0xdd,0xe0,0xfc,0xaa,0x4a,0x92,0xfb,0x96,0xa5,0xda,0x48}, - {0xc7,0x9c,0xa5,0x5c,0x66,0x8e,0xca,0x6e,0xa0,0xac,0x38,0x2e,0x4b,0x25,0x47,0xa8,0xce,0x17,0x1e,0xd2,0x08,0xc7,0xaf,0x31,0xf7,0x4a,0xd8,0xca,0xfc,0xd6,0x6d,0x67,0x93,0x97,0x4c,0xc8,0x5d,0x1d,0xf6,0x14,0x06,0x82,0x41,0xef,0xe3,0xf9,0x41,0x99,0xac,0x77,0x62,0x34,0x8f,0xb8,0xf5,0xcd,0xa9,0x79,0x8a,0x0e,0xfa,0x37,0xc8,0x58,0x58,0x90,0xfc,0x96,0x85,0x68,0xf9,0x0c,0x1b,0xa0,0x56,0x7b,0xf3,0xbb,0xdc,0x1d,0x6a,0xd6,0x35,0x49,0x7d,0xe7,0xc2,0xdc,0x0a,0x7f,0xa5,0xc6,0xf2,0x73,0x4f,0x1c}, - {0xbb,0xa0,0x5f,0x30,0xbd,0x4f,0x7a,0x0e,0xad,0x63,0xc6,0x54,0xe0,0x4c,0x9d,0x82,0x48,0x38,0xe3,0x2f,0x83,0xc3,0x21,0xf4,0x42,0x4c,0xf6,0x1b,0x0d,0xc8,0x5a,0x79,0x84,0x34,0x7c,0xfc,0x6e,0x70,0x6e,0xb3,0x61,0xcf,0xc1,0xc3,0xb4,0xc9,0xdf,0x73,0xe5,0xc7,0x1c,0x78,0xc9,0x79,0x1d,0xeb,0x5c,0x67,0xaf,0x7d,0xdb,0x9a,0x45,0x70,0xb3,0x2b,0xb4,0x91,0x49,0xdb,0x91,0x1b,0xca,0xdc,0x02,0x4b,0x23,0x96,0x26,0x57,0xdc,0x78,0x8c,0x1f,0xe5,0x9e,0xdf,0x9f,0xd3,0x1f,0xe2,0x8c,0x84,0x62,0xe1,0x5f}, - {0x1a,0x96,0x94,0xe1,0x4f,0x21,0x59,0x4e,0x4f,0xcd,0x71,0x0d,0xc7,0x7d,0xbe,0x49,0x2d,0xf2,0x50,0x3b,0xd2,0xcf,0x00,0x93,0x32,0x72,0x91,0xfc,0x46,0xd4,0x89,0x47,0x08,0xb2,0x7c,0x5d,0x2d,0x85,0x79,0x28,0xe7,0xf2,0x7d,0x68,0x70,0xdd,0xde,0xb8,0x91,0x78,0x68,0x21,0xab,0xff,0x0b,0xdc,0x35,0xaa,0x7d,0x67,0x43,0xc0,0x44,0x2b,0x8e,0xb7,0x4e,0x07,0xab,0x87,0x1c,0x1a,0x67,0xf4,0xda,0x99,0x8e,0xd1,0xc6,0xfa,0x67,0x90,0x4f,0x48,0xcd,0xbb,0xac,0x3e,0xe4,0xa4,0xb9,0x2b,0xef,0x2e,0xc5,0x60}, - {0xf1,0x8b,0xfd,0x3b,0xbc,0x89,0x5d,0x0b,0x1a,0x55,0xf3,0xc9,0x37,0x92,0x6b,0xb0,0xf5,0x28,0x30,0xd5,0xb0,0x16,0x4c,0x0e,0xab,0xca,0xcf,0x2c,0x31,0x9c,0xbc,0x10,0x11,0x6d,0xae,0x7c,0xc2,0xc5,0x2b,0x70,0xab,0x8c,0xa4,0x54,0x9b,0x69,0xc7,0x44,0xb2,0x2e,0x49,0xba,0x56,0x40,0xbc,0xef,0x6d,0x67,0xb6,0xd9,0x48,0x72,0xd7,0x70,0x5b,0xa0,0xc2,0x3e,0x4b,0xe8,0x8a,0xaa,0xe0,0x81,0x17,0xed,0xf4,0x9e,0x69,0x98,0xd1,0x85,0x8e,0x70,0xe4,0x13,0x45,0x79,0x13,0xf4,0x76,0xa9,0xd3,0x5b,0x75,0x63}, - {0x53,0x08,0xd1,0x2a,0x3e,0xa0,0x5f,0xb5,0x69,0x35,0xe6,0x9e,0x90,0x75,0x6f,0x35,0x90,0xb8,0x69,0xbe,0xfd,0xf1,0xf9,0x9f,0x84,0x6f,0xc1,0x8b,0xc4,0xc1,0x8c,0x0d,0xb7,0xac,0xf1,0x97,0x18,0x10,0xc7,0x3d,0xd8,0xbb,0x65,0xc1,0x5e,0x7d,0xda,0x5d,0x0f,0x02,0xa1,0x0f,0x9c,0x5b,0x8e,0x50,0x56,0x2a,0xc5,0x37,0x17,0x75,0x63,0x27,0xa9,0x19,0xb4,0x6e,0xd3,0x02,0x94,0x02,0xa5,0x60,0xb4,0x77,0x7e,0x4e,0xb4,0xf0,0x56,0x49,0x3c,0xd4,0x30,0x62,0xa8,0xcf,0xe7,0x66,0xd1,0x7a,0x8a,0xdd,0xc2,0x70}, - {0x0e,0xec,0x6f,0x9f,0x50,0x94,0x61,0x65,0x8d,0x51,0xc6,0x46,0xa9,0x7e,0x2e,0xee,0x5c,0x9b,0xe0,0x67,0xf3,0xc1,0x33,0x97,0x95,0x84,0x94,0x63,0x63,0xac,0x0f,0x2e,0x13,0x7e,0xed,0xb8,0x7d,0x96,0xd4,0x91,0x7a,0x81,0x76,0xd7,0x0a,0x2f,0x25,0x74,0x64,0x25,0x85,0x0d,0xe0,0x82,0x09,0xe4,0xe5,0x3c,0xa5,0x16,0x38,0x61,0xb8,0x32,0x64,0xcd,0x48,0xe4,0xbe,0xf7,0xe7,0x79,0xd0,0x86,0x78,0x08,0x67,0x3a,0xc8,0x6a,0x2e,0xdb,0xe4,0xa0,0xd9,0xd4,0x9f,0xf8,0x41,0x4f,0x5a,0x73,0x5c,0x21,0x79,0x41}, - {0x2a,0xed,0xdc,0xd7,0xe7,0x94,0x70,0x8c,0x70,0x9c,0xd3,0x47,0xc3,0x8a,0xfb,0x97,0x02,0xd9,0x06,0xa9,0x33,0xe0,0x3b,0xe1,0x76,0x9d,0xd9,0x0c,0xa3,0x44,0x03,0x70,0x34,0xcd,0x6b,0x28,0xb9,0x33,0xae,0xe4,0xdc,0xd6,0x9d,0x55,0xb6,0x7e,0xef,0xb7,0x1f,0x8e,0xd3,0xb3,0x1f,0x14,0x8b,0x27,0x86,0xc2,0x41,0x22,0x66,0x85,0xfa,0x31,0xf4,0x22,0x36,0x2e,0x42,0x6c,0x82,0xaf,0x2d,0x50,0x33,0x98,0x87,0x29,0x20,0xc1,0x23,0x91,0x38,0x2b,0xe1,0xb7,0xc1,0x9b,0x89,0x24,0x95,0xa9,0x12,0x23,0xbb,0x24}, - {0xc3,0x67,0xde,0x32,0x17,0xed,0xa8,0xb1,0x48,0x49,0x1b,0x46,0x18,0x94,0xb4,0x3c,0xd2,0xbc,0xcf,0x76,0x43,0x43,0xbd,0x8e,0x08,0x80,0x18,0x1e,0x87,0x3e,0xee,0x0f,0x6b,0x5c,0xf8,0xf5,0x2a,0x0c,0xf8,0x41,0x94,0x67,0xfa,0x04,0xc3,0x84,0x72,0x68,0xad,0x1b,0xba,0xa3,0x99,0xdf,0x45,0x89,0x16,0x5d,0xeb,0xff,0xf9,0x2a,0x1d,0x0d,0xdf,0x1e,0x62,0x32,0xa1,0x8a,0xda,0xa9,0x79,0x65,0x22,0x59,0xa1,0x22,0xb8,0x30,0x93,0xc1,0x9a,0xa7,0x7b,0x19,0x04,0x40,0x76,0x1d,0x53,0x18,0x97,0xd7,0xac,0x16}, - {0x3d,0x1d,0x9b,0x2d,0xaf,0x72,0xdf,0x72,0x5a,0x24,0x32,0xa4,0x36,0x2a,0x46,0x63,0x37,0x96,0xb3,0x16,0x79,0xa0,0xce,0x3e,0x09,0x23,0x30,0xb9,0xf6,0x0e,0x3e,0x12,0xad,0xb6,0x87,0x78,0xc5,0xc6,0x59,0xc9,0xba,0xfe,0x90,0x5f,0xad,0x9e,0xe1,0x94,0x04,0xf5,0x42,0xa3,0x62,0x4e,0xe2,0x16,0x00,0x17,0x16,0x18,0x4b,0xd3,0x4e,0x16,0x9a,0xe6,0x2f,0x19,0x4c,0xd9,0x7e,0x48,0x13,0x15,0x91,0x3a,0xea,0x2c,0xae,0x61,0x27,0xde,0xa4,0xb9,0xd3,0xf6,0x7b,0x87,0xeb,0xf3,0x73,0x10,0xc6,0x0f,0xda,0x78}, - {0x6a,0xc6,0x2b,0xe5,0x28,0x5d,0xf1,0x5b,0x8e,0x1a,0xf0,0x70,0x18,0xe3,0x47,0x2c,0xdd,0x8b,0xc2,0x06,0xbc,0xaf,0x19,0x24,0x3a,0x17,0x6b,0x25,0xeb,0xde,0x25,0x2d,0x94,0x3a,0x0c,0x68,0xf1,0x80,0x9f,0xa2,0xe6,0xe7,0xe9,0x1a,0x15,0x7e,0xf7,0x71,0x73,0x79,0x01,0x48,0x58,0xf1,0x00,0x11,0xdd,0x8d,0xb3,0x16,0xb3,0xa4,0x4a,0x05,0xb8,0x7c,0x26,0x19,0x8d,0x46,0xc8,0xdf,0xaf,0x4d,0xe5,0x66,0x9c,0x78,0x28,0x0b,0x17,0xec,0x6e,0x66,0x2a,0x1d,0xeb,0x2a,0x60,0xa7,0x7d,0xab,0xa6,0x10,0x46,0x13}, - {0xfe,0xb0,0xf6,0x8d,0xc7,0x8e,0x13,0x51,0x1b,0xf5,0x75,0xe5,0x89,0xda,0x97,0x53,0xb9,0xf1,0x7a,0x71,0x1d,0x7a,0x20,0x09,0x50,0xd6,0x20,0x2b,0xba,0xfd,0x02,0x21,0x15,0xf5,0xd1,0x77,0xe7,0x65,0x2a,0xcd,0xf1,0x60,0xaa,0x8f,0x87,0x91,0x89,0x54,0xe5,0x06,0xbc,0xda,0xbc,0x3b,0xb7,0xb1,0xfb,0xc9,0x7c,0xa9,0xcb,0x78,0x48,0x65,0xa1,0xe6,0x5c,0x05,0x05,0xe4,0x9e,0x96,0x29,0xad,0x51,0x12,0x68,0xa7,0xbc,0x36,0x15,0xa4,0x7d,0xaa,0x17,0xf5,0x1a,0x3a,0xba,0xb2,0xec,0x29,0xdb,0x25,0xd7,0x0a}, - {0x57,0x24,0x4e,0x83,0xb1,0x67,0x42,0xdc,0xc5,0x1b,0xce,0x70,0xb5,0x44,0x75,0xb6,0xd7,0x5e,0xd1,0xf7,0x0b,0x7a,0xf0,0x1a,0x50,0x36,0xa0,0x71,0xfb,0xcf,0xef,0x4a,0x85,0x6f,0x05,0x9b,0x0c,0xbc,0xc7,0xfe,0xd7,0xff,0xf5,0xe7,0x68,0x52,0x7d,0x53,0xfa,0xae,0x12,0x43,0x62,0xc6,0xaf,0x77,0xd9,0x9f,0x39,0x02,0x53,0x5f,0x67,0x4f,0x1e,0x17,0x15,0x04,0x36,0x36,0x2d,0xc3,0x3b,0x48,0x98,0x89,0x11,0xef,0x2b,0xcd,0x10,0x51,0x94,0xd0,0xad,0x6e,0x0a,0x87,0x61,0x65,0xa8,0xa2,0x72,0xbb,0xcc,0x0b}, - {0xc8,0xa9,0xb1,0xea,0x2f,0x96,0x5e,0x18,0xcd,0x7d,0x14,0x65,0x35,0xe6,0xe7,0x86,0xf2,0x6d,0x5b,0xbb,0x31,0xe0,0x92,0xb0,0x3e,0xb7,0xd6,0x59,0xab,0xf0,0x24,0x40,0x96,0x12,0xfe,0x50,0x4c,0x5e,0x6d,0x18,0x7e,0x9f,0xe8,0xfe,0x82,0x7b,0x39,0xe0,0xb0,0x31,0x70,0x50,0xc5,0xf6,0xc7,0x3b,0xc2,0x37,0x8f,0x10,0x69,0xfd,0x78,0x66,0xc2,0x63,0x68,0x63,0x31,0xfa,0x86,0x15,0xf2,0x33,0x2d,0x57,0x48,0x8c,0xf6,0x07,0xfc,0xae,0x9e,0x78,0x9f,0xcc,0x73,0x4f,0x01,0x47,0xad,0x8e,0x10,0xe2,0x42,0x2d}, - {0x9b,0xd2,0xdf,0x94,0x15,0x13,0xf5,0x97,0x6a,0x4c,0x3f,0x31,0x5d,0x98,0x55,0x61,0x10,0x50,0x45,0x08,0x07,0x3f,0xa1,0xeb,0x22,0xd3,0xd2,0xb8,0x08,0x26,0x6b,0x67,0x93,0x75,0x53,0x0f,0x0d,0x7b,0x71,0x21,0x4c,0x06,0x1e,0x13,0x0b,0x69,0x4e,0x91,0x9f,0xe0,0x2a,0x75,0xae,0x87,0xb6,0x1b,0x6e,0x3c,0x42,0x9b,0xa7,0xf3,0x0b,0x42,0x47,0x2b,0x5b,0x1c,0x65,0xba,0x38,0x81,0x80,0x1b,0x1b,0x31,0xec,0xb6,0x71,0x86,0xb0,0x35,0x31,0xbc,0xb1,0x0c,0xff,0x7b,0xe0,0xf1,0x0c,0x9c,0xfa,0x2f,0x5d,0x74}, - {0xbd,0xc8,0xc9,0x2b,0x1e,0x5a,0x52,0xbf,0x81,0x9d,0x47,0x26,0x08,0x26,0x5b,0xea,0xdb,0x55,0x01,0xdf,0x0e,0xc7,0x11,0xd5,0xd0,0xf5,0x0c,0x96,0xeb,0x3c,0xe2,0x1a,0x6a,0x4e,0xd3,0x21,0x57,0xdf,0x36,0x60,0xd0,0xb3,0x7b,0x99,0x27,0x88,0xdb,0xb1,0xfa,0x6a,0x75,0xc8,0xc3,0x09,0xc2,0xd3,0x39,0xc8,0x1d,0x4c,0xe5,0x5b,0xe1,0x06,0x4a,0x99,0x32,0x19,0x87,0x5d,0x72,0x5b,0xb0,0xda,0xb1,0xce,0xb5,0x1c,0x35,0x32,0x05,0xca,0xb7,0xda,0x49,0x15,0xc4,0x7d,0xf7,0xc1,0x8e,0x27,0x61,0xd8,0xde,0x58}, - {0x5c,0xc5,0x66,0xf2,0x93,0x37,0x17,0xd8,0x49,0x4e,0x45,0xcc,0xc5,0x76,0xc9,0xc8,0xa8,0xc3,0x26,0xbc,0xf8,0x82,0xe3,0x5c,0xf9,0xf6,0x85,0x54,0xe8,0x9d,0xf3,0x2f,0xa8,0xc9,0xc2,0xb6,0xa8,0x5b,0xfb,0x2d,0x8c,0x59,0x2c,0xf5,0x8e,0xef,0xee,0x48,0x73,0x15,0x2d,0xf1,0x07,0x91,0x80,0x33,0xd8,0x5b,0x1d,0x53,0x6b,0x69,0xba,0x08,0x7a,0xc5,0xef,0xc3,0xee,0x3e,0xed,0x77,0x11,0x48,0xff,0xd4,0x17,0x55,0xe0,0x04,0xcb,0x71,0xa6,0xf1,0x3f,0x7a,0x3d,0xea,0x54,0xfe,0x7c,0x94,0xb4,0x33,0x06,0x12}, - {0x42,0x00,0x61,0x91,0x78,0x98,0x94,0x0b,0xe8,0xfa,0xeb,0xec,0x3c,0xb1,0xe7,0x4e,0xc0,0xa4,0xf0,0x94,0x95,0x73,0xbe,0x70,0x85,0x91,0xd5,0xb4,0x99,0x0a,0xd3,0x35,0x0a,0x10,0x12,0x49,0x47,0x31,0xbd,0x82,0x06,0xbe,0x6f,0x7e,0x6d,0x7b,0x23,0xde,0xc6,0x79,0xea,0x11,0x19,0x76,0x1e,0xe1,0xde,0x3b,0x39,0xcb,0xe3,0x3b,0x43,0x07,0xf4,0x97,0xe9,0x5c,0xc0,0x44,0x79,0xff,0xa3,0x51,0x5c,0xb0,0xe4,0x3d,0x5d,0x57,0x7c,0x84,0x76,0x5a,0xfd,0x81,0x33,0x58,0x9f,0xda,0xf6,0x7a,0xde,0x3e,0x87,0x2d}, - {0x09,0x34,0x37,0x43,0x64,0x31,0x7a,0x15,0xd9,0x81,0xaa,0xf4,0xee,0xb7,0xb8,0xfa,0x06,0x48,0xa6,0xf5,0xe6,0xfe,0x93,0xb0,0xb6,0xa7,0x7f,0x70,0x54,0x36,0x77,0x2e,0x81,0xf9,0x5d,0x4e,0xe1,0x02,0x62,0xaa,0xf5,0xe1,0x15,0x50,0x17,0x59,0x0d,0xa2,0x6c,0x1d,0xe2,0xba,0xd3,0x75,0xa2,0x18,0x53,0x02,0x60,0x01,0x8a,0x61,0x43,0x05,0xc1,0x23,0x4c,0x97,0xf4,0xbd,0xea,0x0d,0x93,0x46,0xce,0x9d,0x25,0x0a,0x6f,0xaa,0x2c,0xba,0x9a,0xa2,0xb8,0x2c,0x20,0x04,0x0d,0x96,0x07,0x2d,0x36,0x43,0x14,0x4b}, - {0x7a,0x1f,0x6e,0xb6,0xc7,0xb7,0xc4,0xcc,0x7e,0x2f,0x0c,0xf5,0x25,0x7e,0x15,0x44,0x1c,0xaf,0x3e,0x71,0xfc,0x6d,0xf0,0x3e,0xf7,0x63,0xda,0x52,0x67,0x44,0x2f,0x58,0xcb,0x9c,0x52,0x1c,0xe9,0x54,0x7c,0x96,0xfb,0x35,0xc6,0x64,0x92,0x26,0xf6,0x30,0x65,0x19,0x12,0x78,0xf4,0xaf,0x47,0x27,0x5c,0x6f,0xf6,0xea,0x18,0x84,0x03,0x17,0xe4,0x4c,0x32,0x20,0xd3,0x7b,0x31,0xc6,0xc4,0x8b,0x48,0xa4,0xe8,0x42,0x10,0xa8,0x64,0x13,0x5a,0x4e,0x8b,0xf1,0x1e,0xb2,0xc9,0x8d,0xa2,0xcd,0x4b,0x1c,0x2a,0x0c}, - {0x47,0x04,0x1f,0x6f,0xd0,0xc7,0x4d,0xd2,0x59,0xc0,0x87,0xdb,0x3e,0x9e,0x26,0xb2,0x8f,0xd2,0xb2,0xfb,0x72,0x02,0x5b,0xd1,0x77,0x48,0xf6,0xc6,0xd1,0x8b,0x55,0x7c,0x45,0x69,0xbd,0x69,0x48,0x81,0xc4,0xed,0x22,0x8d,0x1c,0xbe,0x7d,0x90,0x6d,0x0d,0xab,0xc5,0x5c,0xd5,0x12,0xd2,0x3b,0xc6,0x83,0xdc,0x14,0xa3,0x30,0x9b,0x6a,0x5a,0x3d,0x46,0x96,0xd3,0x24,0x15,0xec,0xd0,0xf0,0x24,0x5a,0xc3,0x8a,0x62,0xbb,0x12,0xa4,0x5f,0xbc,0x1c,0x79,0x3a,0x0c,0xa5,0xc3,0xaf,0xfb,0x0a,0xca,0xa5,0x04,0x04}, - {0xd6,0x43,0xa7,0x0a,0x07,0x40,0x1f,0x8c,0xe8,0x5e,0x26,0x5b,0xcb,0xd0,0xba,0xcc,0xde,0xd2,0x8f,0x66,0x6b,0x04,0x4b,0x57,0x33,0x96,0xdd,0xca,0xfd,0x5b,0x39,0x46,0xd1,0x6f,0x41,0x2a,0x1b,0x9e,0xbc,0x62,0x8b,0x59,0x50,0xe3,0x28,0xf7,0xc6,0xb5,0x67,0x69,0x5d,0x3d,0xd8,0x3f,0x34,0x04,0x98,0xee,0xf8,0xe7,0x16,0x75,0x52,0x39,0x9c,0x9a,0x5d,0x1a,0x2d,0xdb,0x7f,0x11,0x2a,0x5c,0x00,0xd1,0xbc,0x45,0x77,0x9c,0xea,0x6f,0xd5,0x54,0xf1,0xbe,0xd4,0xef,0x16,0xd0,0x22,0xe8,0x29,0x9a,0x57,0x76}, - {0x17,0x2a,0xc0,0x49,0x7e,0x8e,0xb6,0x45,0x7f,0xa3,0xa9,0xbc,0xa2,0x51,0xcd,0x23,0x1b,0x4c,0x22,0xec,0x11,0x5f,0xd6,0x3e,0xb1,0xbd,0x05,0x9e,0xdc,0x84,0xa3,0x43,0xf2,0x34,0xb4,0x52,0x13,0xb5,0x3c,0x33,0xe1,0x80,0xde,0x93,0x49,0x28,0x32,0xd8,0xce,0x35,0x0d,0x75,0x87,0x28,0x51,0xb5,0xc1,0x77,0x27,0x2a,0xbb,0x14,0xc5,0x02,0x45,0xb6,0xf1,0x8b,0xda,0xd5,0x4b,0x68,0x53,0x4b,0xb5,0xf6,0x7e,0xd3,0x8b,0xfb,0x53,0xd2,0xb0,0xa9,0xd7,0x16,0x39,0x31,0x59,0x80,0x54,0x61,0x09,0x92,0x60,0x11}, - {0xaa,0xcf,0xda,0x29,0x69,0x16,0x4d,0xb4,0x8f,0x59,0x13,0x84,0x4c,0x9f,0x52,0xda,0x59,0x55,0x3d,0x45,0xca,0x63,0xef,0xe9,0x0b,0x8e,0x69,0xc5,0x5b,0x12,0x1e,0x35,0xcd,0x4d,0x9b,0x36,0x16,0x56,0x38,0x7a,0x63,0x35,0x5c,0x65,0xa7,0x2c,0xc0,0x75,0x21,0x80,0xf1,0xd4,0xf9,0x1b,0xc2,0x7d,0x42,0xe0,0xe6,0x91,0x74,0x7d,0x63,0x2f,0xbe,0x7b,0xf6,0x1a,0x46,0x9b,0xb4,0xd4,0x61,0x89,0xab,0xc8,0x7a,0x03,0x03,0xd6,0xfb,0x99,0xa6,0xf9,0x9f,0xe1,0xde,0x71,0x9a,0x2a,0xce,0xe7,0x06,0x2d,0x18,0x7f}, - {0xec,0x68,0x01,0xab,0x64,0x8e,0x7c,0x7a,0x43,0xc5,0xed,0x15,0x55,0x4a,0x5a,0xcb,0xda,0x0e,0xcd,0x47,0xd3,0x19,0x55,0x09,0xb0,0x93,0x3e,0x34,0x8c,0xac,0xd4,0x67,0x22,0x75,0x21,0x8e,0x72,0x4b,0x45,0x09,0xd8,0xb8,0x84,0xd4,0xf4,0xe8,0x58,0xaa,0x3c,0x90,0x46,0x7f,0x4d,0x25,0x58,0xd3,0x17,0x52,0x1c,0x24,0x43,0xc0,0xac,0x44,0x77,0x57,0x7a,0x4f,0xbb,0x6b,0x7d,0x1c,0xe1,0x13,0x83,0x91,0xd4,0xfe,0x35,0x8b,0x84,0x46,0x6b,0xc9,0xc6,0xa1,0xdc,0x4a,0xbd,0x71,0xad,0x12,0x83,0x1c,0x6d,0x55}, - {0x82,0x39,0x8d,0x0c,0xe3,0x40,0xef,0x17,0x34,0xfa,0xa3,0x15,0x3e,0x07,0xf7,0x31,0x6e,0x64,0x73,0x07,0xcb,0xf3,0x21,0x4f,0xff,0x4e,0x82,0x1d,0x6d,0x6c,0x6c,0x74,0x21,0xe8,0x1b,0xb1,0x56,0x67,0xf0,0x81,0xdd,0xf3,0xa3,0x10,0x23,0xf8,0xaf,0x0f,0x5d,0x46,0x99,0x6a,0x55,0xd0,0xb2,0xf8,0x05,0x7f,0x8c,0xcc,0x38,0xbe,0x7a,0x09,0xa4,0x2d,0xa5,0x7e,0x87,0xc9,0x49,0x0c,0x43,0x1d,0xdc,0x9b,0x55,0x69,0x43,0x4c,0xd2,0xeb,0xcc,0xf7,0x09,0x38,0x2c,0x02,0xbd,0x84,0xee,0x4b,0xa3,0x14,0x7e,0x57}, - {0x0a,0x3b,0xa7,0x61,0xac,0x68,0xe2,0xf0,0xf5,0xa5,0x91,0x37,0x10,0xfa,0xfa,0xf2,0xe9,0x00,0x6d,0x6b,0x82,0x3e,0xe1,0xc1,0x42,0x8f,0xd7,0x6f,0xe9,0x7e,0xfa,0x60,0x2b,0xd7,0x4d,0xbd,0xbe,0xce,0xfe,0x94,0x11,0x22,0x0f,0x06,0xda,0x4f,0x6a,0xf4,0xff,0xd1,0xc8,0xc0,0x77,0x59,0x4a,0x12,0x95,0x92,0x00,0xfb,0xb8,0x04,0x53,0x70,0xc6,0x6e,0x29,0x4d,0x35,0x1d,0x3d,0xb6,0xd8,0x31,0xad,0x5f,0x3e,0x05,0xc3,0xf3,0xec,0x42,0xbd,0xb4,0x8c,0x95,0x0b,0x67,0xfd,0x53,0x63,0xa1,0x0c,0x8e,0x39,0x21}, - {0xf3,0x33,0x2b,0x38,0x8a,0x05,0xf5,0x89,0xb4,0xc0,0x48,0xad,0x0b,0xba,0xe2,0x5a,0x6e,0xb3,0x3d,0xa5,0x03,0xb5,0x93,0x8f,0xe6,0x32,0xa2,0x95,0x9d,0xed,0xa3,0x5a,0x01,0x56,0xb7,0xb4,0xf9,0xaa,0x98,0x27,0x72,0xad,0x8d,0x5c,0x13,0x72,0xac,0x5e,0x23,0xa0,0xb7,0x61,0x61,0xaa,0xce,0xd2,0x4e,0x7d,0x8f,0xe9,0x84,0xb2,0xbf,0x1b,0x61,0x65,0xd9,0xc7,0xe9,0x77,0x67,0x65,0x36,0x80,0xc7,0x72,0x54,0x12,0x2b,0xcb,0xee,0x6e,0x50,0xd9,0x99,0x32,0x05,0x65,0xcc,0x57,0x89,0x5e,0x4e,0xe1,0x07,0x4a}, - {0x99,0xf9,0x0d,0x98,0xcb,0x12,0xe4,0x4e,0x71,0xc7,0x6e,0x3c,0x6f,0xd7,0x15,0xa3,0xfd,0x77,0x5c,0x92,0xde,0xed,0xa5,0xbb,0x02,0x34,0x31,0x1d,0x39,0xac,0x0b,0x3f,0x9b,0xa4,0x77,0xc4,0xcd,0x58,0x0b,0x24,0x17,0xf0,0x47,0x64,0xde,0xda,0x38,0xfd,0xad,0x6a,0xc8,0xa7,0x32,0x8d,0x92,0x19,0x81,0xa0,0xaf,0x84,0xed,0x7a,0xaf,0x50,0xe5,0x5b,0xf6,0x15,0x01,0xde,0x4f,0x6e,0xb2,0x09,0x61,0x21,0x21,0x26,0x98,0x29,0xd9,0xd6,0xad,0x0b,0x81,0x05,0x02,0x78,0x06,0xd0,0xeb,0xba,0x16,0xa3,0x21,0x19}, - {0xfc,0x70,0xb8,0xdf,0x7e,0x2f,0x42,0x89,0xbd,0xb3,0x76,0x4f,0xeb,0x6b,0x29,0x2c,0xf7,0x4d,0xc2,0x36,0xd4,0xf1,0x38,0x07,0xb0,0xae,0x73,0xe2,0x41,0xdf,0x58,0x64,0x8b,0xc1,0xf3,0xd9,0x9a,0xad,0x5a,0xd7,0x9c,0xc1,0xb1,0x60,0xef,0x0e,0x6a,0x56,0xd9,0x0e,0x5c,0x25,0xac,0x0b,0x9a,0x3e,0xf5,0xc7,0x62,0xa0,0xec,0x9d,0x04,0x7b,0x83,0x44,0x44,0x35,0x7a,0xe3,0xcb,0xdc,0x93,0xbe,0xed,0x0f,0x33,0x79,0x88,0x75,0x87,0xdd,0xc5,0x12,0xc3,0x04,0x60,0x78,0x64,0x0e,0x95,0xc2,0xcb,0xdc,0x93,0x60}, - {0x6d,0x70,0xe0,0x85,0x85,0x9a,0xf3,0x1f,0x33,0x39,0xe7,0xb3,0xd8,0xa5,0xd0,0x36,0x3b,0x45,0x8f,0x71,0xe1,0xf2,0xb9,0x43,0x7c,0xa9,0x27,0x48,0x08,0xea,0xd1,0x57,0x4b,0x03,0x84,0x60,0xbe,0xee,0xde,0x6b,0x54,0xb8,0x0f,0x78,0xb6,0xc2,0x99,0x31,0x95,0x06,0x2d,0xb6,0xab,0x76,0x33,0x97,0x90,0x7d,0x64,0x8b,0xc9,0x80,0x31,0x6e,0x71,0xb0,0x28,0xa1,0xe7,0xb6,0x7a,0xee,0xaa,0x8b,0xa8,0x93,0x6d,0x59,0xc1,0xa4,0x30,0x61,0x21,0xb2,0x82,0xde,0xb4,0xf7,0x18,0xbd,0x97,0xdd,0x9d,0x99,0x3e,0x36}, - {0xc4,0x1f,0xee,0x35,0xc1,0x43,0xa8,0x96,0xcf,0xc8,0xe4,0x08,0x55,0xb3,0x6e,0x97,0x30,0xd3,0x8c,0xb5,0x01,0x68,0x2f,0xb4,0x2b,0x05,0x3a,0x69,0x78,0x9b,0xee,0x48,0xc6,0xae,0x4b,0xe2,0xdc,0x48,0x18,0x2f,0x60,0xaf,0xbc,0xba,0x55,0x72,0x9b,0x76,0x31,0xe9,0xef,0x3c,0x6e,0x3c,0xcb,0x90,0x55,0xb3,0xf9,0xc6,0x9b,0x97,0x1f,0x23,0xc6,0xf3,0x2a,0xcc,0x4b,0xde,0x31,0x5c,0x1f,0x8d,0x20,0xfe,0x30,0xb0,0x4b,0xb0,0x66,0xb4,0x4f,0xc1,0x09,0x70,0x8d,0xb7,0x13,0x24,0x79,0x08,0x9b,0xfa,0x9b,0x07}, - {0xf4,0x0d,0x30,0xda,0x51,0x3a,0x90,0xe3,0xb0,0x5a,0xa9,0x3d,0x23,0x64,0x39,0x84,0x80,0x64,0x35,0x0b,0x2d,0xf1,0x3c,0xed,0x94,0x71,0x81,0x84,0xf6,0x77,0x8c,0x03,0x45,0x42,0xd5,0xa2,0x80,0xed,0xc9,0xf3,0x52,0x39,0xf6,0x77,0x78,0x8b,0xa0,0x0a,0x75,0x54,0x08,0xd1,0x63,0xac,0x6d,0xd7,0x6b,0x63,0x70,0x94,0x15,0xfb,0xf4,0x1e,0xec,0x7b,0x16,0x5b,0xe6,0x5e,0x4e,0x85,0xc2,0xcd,0xd0,0x96,0x42,0x0a,0x59,0x59,0x99,0x21,0x10,0x98,0x34,0xdf,0xb2,0x72,0x56,0xff,0x0b,0x4a,0x2a,0xe9,0x5e,0x57}, - {0xcf,0x2f,0x18,0x8a,0x90,0x80,0xc0,0xd4,0xbd,0x9d,0x48,0x99,0xc2,0x70,0xe1,0x30,0xde,0x33,0xf7,0x52,0x57,0xbd,0xba,0x05,0x00,0xfd,0xd3,0x2c,0x11,0xe7,0xd4,0x43,0x01,0xd8,0xa4,0x0a,0x45,0xbc,0x46,0x5d,0xd8,0xb9,0x33,0xa5,0x27,0x12,0xaf,0xc3,0xc2,0x06,0x89,0x2b,0x26,0x3b,0x9e,0x38,0x1b,0x58,0x2f,0x38,0x7e,0x1e,0x0a,0x20,0xc5,0x3a,0xf9,0xea,0x67,0xb9,0x8d,0x51,0xc0,0x52,0x66,0x05,0x9b,0x98,0xbc,0x71,0xf5,0x97,0x71,0x56,0xd9,0x85,0x2b,0xfe,0x38,0x4e,0x1e,0x65,0x52,0xca,0x0e,0x05}, - {0x9c,0x0c,0x3f,0x45,0xde,0x1a,0x43,0xc3,0x9b,0x3b,0x70,0xff,0x5e,0x04,0xf5,0xe9,0x3d,0x7b,0x84,0xed,0xc9,0x7a,0xd9,0xfc,0xc6,0xf4,0x58,0x1c,0xc2,0xe6,0x0e,0x4b,0xea,0x68,0xe6,0x60,0x76,0x39,0xac,0x97,0x97,0xb4,0x3a,0x15,0xfe,0xbb,0x19,0x9b,0x9f,0xa7,0xec,0x34,0xb5,0x79,0xb1,0x4c,0x57,0xae,0x31,0xa1,0x9f,0xc0,0x51,0x61,0x96,0x5d,0xf0,0xfd,0x0d,0x5c,0xf5,0x3a,0x7a,0xee,0xb4,0x2a,0xe0,0x2e,0x26,0xdd,0x09,0x17,0x17,0x12,0x87,0xbb,0xb2,0x11,0x0b,0x03,0x0f,0x80,0xfa,0x24,0xef,0x1f}, - {0x96,0x31,0xa7,0x1a,0xfb,0x53,0xd6,0x37,0x18,0x64,0xd7,0x3f,0x30,0x95,0x94,0x0f,0xb2,0x17,0x3a,0xfb,0x09,0x0b,0x20,0xad,0x3e,0x61,0xc8,0x2f,0x29,0x49,0x4d,0x54,0x86,0x6b,0x97,0x30,0xf5,0xaf,0xd2,0x22,0x04,0x46,0xd2,0xc2,0x06,0xb8,0x90,0x8d,0xe5,0xba,0xe5,0x4d,0x6c,0x89,0xa1,0xdc,0x17,0x0c,0x34,0xc8,0xe6,0x5f,0x00,0x28,0x88,0x86,0x52,0x34,0x9f,0xba,0xef,0x6a,0xa1,0x7d,0x10,0x25,0x94,0xff,0x1b,0x5c,0x36,0x4b,0xd9,0x66,0xcd,0xbb,0x5b,0xf7,0xfa,0x6d,0x31,0x0f,0x93,0x72,0xe4,0x72}, - {0x4f,0x08,0x81,0x97,0x8c,0x20,0x95,0x26,0xe1,0x0e,0x45,0x23,0x0b,0x2a,0x50,0xb1,0x02,0xde,0xef,0x03,0xa6,0xae,0x9d,0xfd,0x4c,0xa3,0x33,0x27,0x8c,0x2e,0x9d,0x5a,0x27,0x76,0x2a,0xd3,0x35,0xf6,0xf3,0x07,0xf0,0x66,0x65,0x5f,0x86,0x4d,0xaa,0x7a,0x50,0x44,0xd0,0x28,0x97,0xe7,0x85,0x3c,0x38,0x64,0xe0,0x0f,0x00,0x7f,0xee,0x1f,0xe5,0xf7,0xdb,0x03,0xda,0x05,0x53,0x76,0xbd,0xcd,0x34,0x14,0x49,0xf2,0xda,0xa4,0xec,0x88,0x4a,0xd2,0xcd,0xd5,0x4a,0x7b,0x43,0x05,0x04,0xee,0x51,0x40,0xf9,0x00}, - {0xb2,0x30,0xd3,0xc3,0x23,0x6b,0x35,0x8d,0x06,0x1b,0x47,0xb0,0x9b,0x8b,0x1c,0xf2,0x3c,0xb8,0x42,0x6e,0x6c,0x31,0x6c,0xb3,0x0d,0xb1,0xea,0x8b,0x7e,0x9c,0xd7,0x07,0x53,0x97,0xaf,0x07,0xbb,0x93,0xef,0xd7,0xa7,0x66,0xb7,0x3d,0xcf,0xd0,0x3e,0x58,0xc5,0x1e,0x0b,0x6e,0xbf,0x98,0x69,0xce,0x52,0x04,0xd4,0x5d,0xd2,0xff,0xb7,0x47,0x12,0xdd,0x08,0xbc,0x9c,0xfb,0xfb,0x87,0x9b,0xc2,0xee,0xe1,0x3a,0x6b,0x06,0x8a,0xbf,0xc1,0x1f,0xdb,0x2b,0x24,0x57,0x0d,0xb6,0x4b,0xa6,0x5e,0xa3,0x20,0x35,0x1c}, - {0x4a,0xa3,0xcb,0xbc,0xa6,0x53,0xd2,0x80,0x9b,0x21,0x38,0x38,0xa1,0xc3,0x61,0x3e,0x96,0xe3,0x82,0x98,0x01,0xb6,0xc3,0x90,0x6f,0xe6,0x0e,0x5d,0x77,0x05,0x3d,0x1c,0x59,0xc0,0x6b,0x21,0x40,0x6f,0xa8,0xcd,0x7e,0xd8,0xbc,0x12,0x1d,0x23,0xbb,0x1f,0x90,0x09,0xc7,0x17,0x9e,0x6a,0x95,0xb4,0x55,0x2e,0xd1,0x66,0x3b,0x0c,0x75,0x38,0x1a,0xe5,0x22,0x94,0x40,0xf1,0x2e,0x69,0x71,0xf6,0x5d,0x2b,0x3c,0xc7,0xc0,0xcb,0x29,0xe0,0x4c,0x74,0xe7,0x4f,0x01,0x21,0x7c,0x48,0x30,0xd3,0xc7,0xe2,0x21,0x06}, - {0x8d,0x83,0x59,0x82,0xcc,0x60,0x98,0xaf,0xdc,0x9a,0x9f,0xc6,0xc1,0x48,0xea,0x90,0x30,0x1e,0x58,0x65,0x37,0x48,0x26,0x65,0xbc,0xa5,0xd3,0x7b,0x09,0xd6,0x07,0x00,0xf3,0xf0,0xdb,0xb0,0x96,0x17,0xae,0xb7,0x96,0xe1,0x7c,0xe1,0xb9,0xaf,0xdf,0x54,0xb4,0xa3,0xaa,0xe9,0x71,0x30,0x92,0x25,0x9d,0x2e,0x00,0xa1,0x9c,0x58,0x8e,0x5d,0x4b,0xa9,0x42,0x08,0x95,0x1d,0xbf,0xc0,0x3e,0x2e,0x8f,0x58,0x63,0xc3,0xd3,0xb2,0xef,0xe2,0x51,0xbb,0x38,0x14,0x96,0x0a,0x86,0xbf,0x1c,0x3c,0x78,0xd7,0x83,0x15}, - {0xe1,0x7a,0xa2,0x5d,0xef,0xa2,0xee,0xec,0x74,0x01,0x67,0x55,0x14,0x3a,0x7c,0x59,0x7a,0x16,0x09,0x66,0x12,0x2a,0xa6,0xc9,0x70,0x8f,0xed,0x81,0x2e,0x5f,0x2a,0x25,0xc7,0x28,0x9d,0xcc,0x04,0x47,0x03,0x90,0x8f,0xc5,0x2c,0xf7,0x9e,0x67,0x1b,0x1d,0x26,0x87,0x5b,0xbe,0x5f,0x2b,0xe1,0x16,0x0a,0x58,0xc5,0x83,0x4e,0x06,0x58,0x49,0x0d,0xe8,0x66,0x50,0x26,0x94,0x28,0x0d,0x6b,0x8c,0x7c,0x30,0x85,0xf7,0xc3,0xfc,0xfd,0x12,0x11,0x0c,0x78,0xda,0x53,0x1b,0x88,0xb3,0x43,0xd8,0x0b,0x17,0x9c,0x07}, - {0xff,0x6f,0xfa,0x64,0xe4,0xec,0x06,0x05,0x23,0xe5,0x05,0x62,0x1e,0x43,0xe3,0xbe,0x42,0xea,0xb8,0x51,0x24,0x42,0x79,0x35,0x00,0xfb,0xc9,0x4a,0xe3,0x05,0xec,0x6d,0x56,0xd0,0xd5,0xc0,0x50,0xcd,0xd6,0xcd,0x3b,0x57,0x03,0xbb,0x6d,0x68,0xf7,0x9a,0x48,0xef,0xc3,0xf3,0x3f,0x72,0xa6,0x3c,0xcc,0x8a,0x7b,0x31,0xd7,0xc0,0x68,0x67,0xb3,0xc1,0x55,0xf1,0xe5,0x25,0xb6,0x94,0x91,0x7b,0x7b,0x99,0xa7,0xf3,0x7b,0x41,0x00,0x26,0x6b,0x6d,0xdc,0xbd,0x2c,0xc2,0xf4,0x52,0xcd,0xdd,0x14,0x5e,0x44,0x51}, - {0x51,0x49,0x14,0x3b,0x4b,0x2b,0x50,0x57,0xb3,0xbc,0x4b,0x44,0x6b,0xff,0x67,0x8e,0xdb,0x85,0x63,0x16,0x27,0x69,0xbd,0xb8,0xc8,0x95,0x92,0xe3,0x31,0x6f,0x18,0x13,0x55,0xa4,0xbe,0x2b,0xab,0x47,0x31,0x89,0x29,0x91,0x07,0x92,0x4f,0xa2,0x53,0x8c,0xa7,0xf7,0x30,0xbe,0x48,0xf9,0x49,0x4b,0x3d,0xd4,0x4f,0x6e,0x08,0x90,0xe9,0x12,0x2e,0xbb,0xdf,0x7f,0xb3,0x96,0x0c,0xf1,0xf9,0xea,0x1c,0x12,0x5e,0x93,0x9a,0x9f,0x3f,0x98,0x5b,0x3a,0xc4,0x36,0x11,0xdf,0xaf,0x99,0x3e,0x5d,0xf0,0xe3,0xb2,0x77}, - {0xde,0xc4,0x2e,0x9c,0xc5,0xa9,0x6f,0x29,0xcb,0xf3,0x84,0x4f,0xbf,0x61,0x8b,0xbc,0x08,0xf9,0xa8,0x17,0xd9,0x06,0x77,0x1c,0x5d,0x25,0xd3,0x7a,0xfc,0x95,0xb7,0x63,0xa4,0xb0,0xdd,0x12,0x9c,0x63,0x98,0xd5,0x6b,0x86,0x24,0xc0,0x30,0x9f,0xd1,0xa5,0x60,0xe4,0xfc,0x58,0x03,0x2f,0x7c,0xd1,0x8a,0x5e,0x09,0x2e,0x15,0x95,0xa1,0x07,0xc8,0x5f,0x9e,0x38,0x02,0x8f,0x36,0xa8,0x3b,0xe4,0x8d,0xcf,0x02,0x3b,0x43,0x90,0x43,0x26,0x41,0xc5,0x5d,0xfd,0xa1,0xaf,0x37,0x01,0x2f,0x03,0x3d,0xe8,0x8f,0x3e}, - {0x94,0xa2,0x70,0x05,0xb9,0x15,0x8b,0x2f,0x49,0x45,0x08,0x67,0x70,0x42,0xf2,0x94,0x84,0xfd,0xbb,0x61,0xe1,0x5a,0x1c,0xde,0x07,0x40,0xac,0x7f,0x79,0x3b,0xba,0x75,0x3c,0xd1,0xef,0xe8,0x8d,0x4c,0x70,0x08,0x31,0x37,0xe0,0x33,0x8e,0x1a,0xc5,0xdf,0xe3,0xcd,0x60,0x12,0xa5,0x5d,0x9d,0xa5,0x86,0x8c,0x25,0xa6,0x99,0x08,0xd6,0x22,0x96,0xd1,0xcd,0x70,0xc0,0xdb,0x39,0x62,0x9a,0x8a,0x7d,0x6c,0x8b,0x8a,0xfe,0x60,0x60,0x12,0x40,0xeb,0xbc,0x47,0x88,0xb3,0x5e,0x9e,0x77,0x87,0x7b,0xd0,0x04,0x09}, - {0x9c,0x91,0xba,0xdd,0xd4,0x1f,0xce,0xb4,0xaa,0x8d,0x4c,0xc7,0x3e,0xdb,0x31,0xcf,0x51,0xcc,0x86,0xad,0x63,0xcc,0x63,0x2c,0x07,0xde,0x1d,0xbc,0x3f,0x14,0xe2,0x43,0xb9,0x40,0xf9,0x48,0x66,0x2d,0x32,0xf4,0x39,0x0c,0x2d,0xbd,0x0c,0x2f,0x95,0x06,0x31,0xf9,0x81,0xa0,0xad,0x97,0x76,0x16,0x6c,0x2a,0xf7,0xba,0xce,0xaa,0x40,0x62,0xa0,0x95,0xa2,0x5b,0x9c,0x74,0x34,0xf8,0x5a,0xd2,0x37,0xca,0x5b,0x7c,0x94,0xd6,0x6a,0x31,0xc9,0xe7,0xa7,0x3b,0xf1,0x66,0xac,0x0c,0xb4,0x8d,0x23,0xaf,0xbd,0x56}, - {0xeb,0x33,0x35,0xf5,0xe3,0xb9,0x2a,0x36,0x40,0x3d,0xb9,0x6e,0xd5,0x68,0x85,0x33,0x72,0x55,0x5a,0x1d,0x52,0x14,0x0e,0x9e,0x18,0x13,0x74,0x83,0x6d,0xa8,0x24,0x1d,0xb2,0x3b,0x9d,0xc1,0x6c,0xd3,0x10,0x13,0xb9,0x86,0x23,0x62,0xb7,0x6b,0x2a,0x06,0x5c,0x4f,0xa1,0xd7,0x91,0x85,0x9b,0x7c,0x54,0x57,0x1e,0x7e,0x50,0x31,0xaa,0x03,0x1f,0xce,0xd4,0xff,0x48,0x76,0xec,0xf4,0x1c,0x8c,0xac,0x54,0xf0,0xea,0x45,0xe0,0x7c,0x35,0x09,0x1d,0x82,0x25,0xd2,0x88,0x59,0x48,0xeb,0x9a,0xdc,0x61,0xb2,0x43}, - {0xbb,0x79,0xbb,0x88,0x19,0x1e,0x5b,0xe5,0x9d,0x35,0x7a,0xc1,0x7d,0xd0,0x9e,0xa0,0x33,0xea,0x3d,0x60,0xe2,0x2e,0x2c,0xb0,0xc2,0x6b,0x27,0x5b,0xcf,0x55,0x60,0x32,0x64,0x13,0x95,0x6c,0x8b,0x3d,0x51,0x19,0x7b,0xf4,0x0b,0x00,0x26,0x71,0xfe,0x94,0x67,0x95,0x4f,0xd5,0xdd,0x10,0x8d,0x02,0x64,0x09,0x94,0x42,0xe2,0xd5,0xb4,0x02,0xf2,0x8d,0xd1,0x28,0xcb,0x55,0xa1,0xb4,0x08,0xe5,0x6c,0x18,0x46,0x46,0xcc,0xea,0x89,0x43,0x82,0x6c,0x93,0xf4,0x9c,0xc4,0x10,0x34,0x5d,0xae,0x09,0xc8,0xa6,0x27}, - {0x88,0xb1,0x0d,0x1f,0xcd,0xeb,0xa6,0x8b,0xe8,0x5b,0x5a,0x67,0x3a,0xd7,0xd3,0x37,0x5a,0x58,0xf5,0x15,0xa3,0xdf,0x2e,0xf2,0x7e,0xa1,0x60,0xff,0x74,0x71,0xb6,0x2c,0x54,0x69,0x3d,0xc4,0x0a,0x27,0x2c,0xcd,0xb2,0xca,0x66,0x6a,0x57,0x3e,0x4a,0xdd,0x6c,0x03,0xd7,0x69,0x24,0x59,0xfa,0x79,0x99,0x25,0x8c,0x3d,0x60,0x03,0x15,0x22,0xd0,0xe1,0x0b,0x39,0xf9,0xcd,0xee,0x59,0xf1,0xe3,0x8c,0x72,0x44,0x20,0x42,0xa9,0xf4,0xf0,0x94,0x7a,0x66,0x1c,0x89,0x82,0x36,0xf4,0x90,0x38,0xb7,0xf4,0x1d,0x7b}, - {0x24,0xa2,0xb2,0xb3,0xe0,0xf2,0x92,0xe4,0x60,0x11,0x55,0x2b,0x06,0x9e,0x6c,0x7c,0x0e,0x7b,0x7f,0x0d,0xe2,0x8f,0xeb,0x15,0x92,0x59,0xfc,0x58,0x26,0xef,0xfc,0x61,0x8c,0xf5,0xf8,0x07,0x18,0x22,0x2e,0x5f,0xd4,0x09,0x94,0xd4,0x9f,0x5c,0x55,0xe3,0x30,0xa6,0xb6,0x1f,0x8d,0xa8,0xaa,0xb2,0x3d,0xe0,0x52,0xd3,0x45,0x82,0x69,0x68,0x7a,0x18,0x18,0x2a,0x85,0x5d,0xb1,0xdb,0xd7,0xac,0xdd,0x86,0xd3,0xaa,0xe4,0xf3,0x82,0xc4,0xf6,0x0f,0x81,0xe2,0xba,0x44,0xcf,0x01,0xaf,0x3d,0x47,0x4c,0xcf,0x46}, - {0xf9,0xe5,0xc4,0x9e,0xed,0x25,0x65,0x42,0x03,0x33,0x90,0x16,0x01,0xda,0x5e,0x0e,0xdc,0xca,0xe5,0xcb,0xf2,0xa7,0xb1,0x72,0x40,0x5f,0xeb,0x14,0xcd,0x7b,0x38,0x29,0x40,0x81,0x49,0xf1,0xa7,0x6e,0x3c,0x21,0x54,0x48,0x2b,0x39,0xf8,0x7e,0x1e,0x7c,0xba,0xce,0x29,0x56,0x8c,0xc3,0x88,0x24,0xbb,0xc5,0x8c,0x0d,0xe5,0xaa,0x65,0x10,0x57,0x0d,0x20,0xdf,0x25,0x45,0x2c,0x1c,0x4a,0x67,0xca,0xbf,0xd6,0x2d,0x3b,0x5c,0x30,0x40,0x83,0xe1,0xb1,0xe7,0x07,0x0a,0x16,0xe7,0x1c,0x4f,0xe6,0x98,0xa1,0x69}, - {0xbc,0x78,0x1a,0xd9,0xe0,0xb2,0x62,0x90,0x67,0x96,0x50,0xc8,0x9c,0x88,0xc9,0x47,0xb8,0x70,0x50,0x40,0x66,0x4a,0xf5,0x9d,0xbf,0xa1,0x93,0x24,0xa9,0xe6,0x69,0x73,0xed,0xca,0xc5,0xdc,0x34,0x44,0x01,0xe1,0x33,0xfb,0x84,0x3c,0x96,0x5d,0xed,0x47,0xe7,0xa0,0x86,0xed,0x76,0x95,0x01,0x70,0xe4,0xf9,0x67,0xd2,0x7b,0x69,0xb2,0x25,0x64,0x68,0x98,0x13,0xfb,0x3f,0x67,0x9d,0xb8,0xc7,0x5d,0x41,0xd9,0xfb,0xa5,0x3c,0x5e,0x3b,0x27,0xdf,0x3b,0xcc,0x4e,0xe0,0xd2,0x4c,0x4e,0xb5,0x3d,0x68,0x20,0x14}, - {0x97,0xd1,0x9d,0x24,0x1e,0xbd,0x78,0xb4,0x02,0xc1,0x58,0x5e,0x00,0x35,0x0c,0x62,0x5c,0xac,0xba,0xcc,0x2f,0xd3,0x02,0xfb,0x2d,0xa7,0x08,0xf5,0xeb,0x3b,0xb6,0x60,0xd0,0x5a,0xcc,0xc1,0x6f,0xbb,0xee,0x34,0x8b,0xac,0x46,0x96,0xe9,0x0c,0x1b,0x6a,0x53,0xde,0x6b,0xa6,0x49,0xda,0xb0,0xd3,0xc1,0x81,0xd0,0x61,0x41,0x3b,0xe8,0x31,0x4f,0x2b,0x06,0x9e,0x12,0xc7,0xe8,0x97,0xd8,0x0a,0x32,0x29,0x4f,0x8f,0xe4,0x49,0x3f,0x68,0x18,0x6f,0x4b,0xe1,0xec,0x5b,0x17,0x03,0x55,0x2d,0xb6,0x1e,0xcf,0x55}, - {0x58,0x3d,0xc2,0x65,0x10,0x10,0x79,0x58,0x9c,0x81,0x94,0x50,0x6d,0x08,0x9d,0x8b,0xa7,0x5f,0xc5,0x12,0xa9,0x2f,0x40,0xe2,0xd4,0x91,0x08,0x57,0x64,0x65,0x9a,0x66,0x52,0x8c,0xf5,0x7d,0xe3,0xb5,0x76,0x30,0x36,0xcc,0x99,0xe7,0xdd,0xb9,0x3a,0xd7,0x20,0xee,0x13,0x49,0xe3,0x1c,0x83,0xbd,0x33,0x01,0xba,0x62,0xaa,0xfb,0x56,0x1a,0xec,0xc9,0x9d,0x5c,0x50,0x6b,0x3e,0x94,0x1a,0x37,0x7c,0xa7,0xbb,0x57,0x25,0x30,0x51,0x76,0x34,0x41,0x56,0xae,0x73,0x98,0x5c,0x8a,0xc5,0x99,0x67,0x83,0xc4,0x13}, - {0xb9,0xe1,0xb3,0x5a,0x46,0x5d,0x3a,0x42,0x61,0x3f,0xf1,0xc7,0x87,0xc1,0x13,0xfc,0xb6,0xb9,0xb5,0xec,0x64,0x36,0xf8,0x19,0x07,0xb6,0x37,0xa6,0x93,0x0c,0xf8,0x66,0x80,0xd0,0x8b,0x5d,0x6a,0xfb,0xdc,0xc4,0x42,0x48,0x1a,0x57,0xec,0xc4,0xeb,0xde,0x65,0x53,0xe5,0xb8,0x83,0xe8,0xb2,0xd4,0x27,0xb8,0xe5,0xc8,0x7d,0xc8,0xbd,0x50,0x11,0xe1,0xdf,0x6e,0x83,0x37,0x6d,0x60,0xd9,0xab,0x11,0xf0,0x15,0x3e,0x35,0x32,0x96,0x3b,0xb7,0x25,0xc3,0x3a,0xb0,0x64,0xae,0xd5,0x5f,0x72,0x44,0x64,0xd5,0x1d}, - {0x7d,0x12,0x62,0x33,0xf8,0x7f,0xa4,0x8f,0x15,0x7c,0xcd,0x71,0xc4,0x6a,0x9f,0xbc,0x8b,0x0c,0x22,0x49,0x43,0x45,0x71,0x6e,0x2e,0x73,0x9f,0x21,0x12,0x59,0x64,0x0e,0x9a,0xc8,0xba,0x08,0x00,0xe6,0x97,0xc2,0xe0,0xc3,0xe1,0xea,0x11,0xea,0x4c,0x7d,0x7c,0x97,0xe7,0x9f,0xe1,0x8b,0xe3,0xf3,0xcd,0x05,0xa3,0x63,0x0f,0x45,0x3a,0x3a,0x27,0x46,0x39,0xd8,0x31,0x2f,0x8f,0x07,0x10,0xa5,0x94,0xde,0x83,0x31,0x9d,0x38,0x80,0x6f,0x99,0x17,0x6d,0x6c,0xe3,0xd1,0x7b,0xa8,0xa9,0x93,0x93,0x8d,0x8c,0x31}, - {0x19,0xfe,0xff,0x2a,0x03,0x5d,0x74,0xf2,0x66,0xdb,0x24,0x7f,0x49,0x3c,0x9f,0x0c,0xef,0x98,0x85,0xba,0xe3,0xd3,0x98,0xbc,0x14,0x53,0x1d,0x9a,0x67,0x7c,0x4c,0x22,0x98,0xd3,0x1d,0xab,0x29,0x9e,0x66,0x5d,0x3b,0x9e,0x2d,0x34,0x58,0x16,0x92,0xfc,0xcd,0x73,0x59,0xf3,0xfd,0x1d,0x85,0x55,0xf6,0x0a,0x95,0x25,0xc3,0x41,0x9a,0x50,0xe9,0x25,0xf9,0xa6,0xdc,0x6e,0xc0,0xbd,0x33,0x1f,0x1b,0x64,0xf4,0xf3,0x3e,0x79,0x89,0x3e,0x83,0x9d,0x80,0x12,0xec,0x82,0x89,0x13,0xa1,0x28,0x23,0xf0,0xbf,0x05}, - {0x0b,0xe0,0xca,0x23,0x70,0x13,0x32,0x36,0x59,0xcf,0xac,0xd1,0x0a,0xcf,0x4a,0x54,0x88,0x1c,0x1a,0xd2,0x49,0x10,0x74,0x96,0xa7,0x44,0x2a,0xfa,0xc3,0x8c,0x0b,0x78,0xe4,0x12,0xc5,0x0d,0xdd,0xa0,0x81,0x68,0xfe,0xfa,0xa5,0x44,0xc8,0x0d,0xe7,0x4f,0x40,0x52,0x4a,0x8f,0x6b,0x8e,0x74,0x1f,0xea,0xa3,0x01,0xee,0xcd,0x77,0x62,0x57,0x5f,0x30,0x4f,0x23,0xbc,0x8a,0xf3,0x1e,0x08,0xde,0x05,0x14,0xbd,0x7f,0x57,0x9a,0x0d,0x2a,0xe6,0x34,0x14,0xa5,0x82,0x5e,0xa1,0xb7,0x71,0x62,0x72,0x18,0xf4,0x5f}, - {0x9d,0xdb,0x89,0x17,0x0c,0x08,0x8e,0x39,0xf5,0x78,0xe7,0xf3,0x25,0x20,0x60,0xa7,0x5d,0x03,0xbd,0x06,0x4c,0x89,0x98,0xfa,0xbe,0x66,0xa9,0x25,0xdc,0x03,0x6a,0x10,0x40,0x95,0xb6,0x13,0xe8,0x47,0xdb,0xe5,0xe1,0x10,0x26,0x43,0x3b,0x2a,0x5d,0xf3,0x76,0x12,0x78,0x38,0xe9,0x26,0x1f,0xac,0x69,0xcb,0xa0,0xa0,0x8c,0xdb,0xd4,0x29,0xd0,0x53,0x33,0x33,0xaf,0x0a,0xad,0xd9,0xe5,0x09,0xd3,0xac,0xa5,0x9d,0x66,0x38,0xf0,0xf7,0x88,0xc8,0x8a,0x65,0x57,0x3c,0xfa,0xbe,0x2c,0x05,0x51,0x8a,0xb3,0x4a}, - {0x93,0xd5,0x68,0x67,0x25,0x2b,0x7c,0xda,0x13,0xca,0x22,0x44,0x57,0xc0,0xc1,0x98,0x1d,0xce,0x0a,0xca,0xd5,0x0b,0xa8,0xf1,0x90,0xa6,0x88,0xc0,0xad,0xd1,0xcd,0x29,0x9c,0xc0,0xdd,0x5f,0xef,0xd1,0xcf,0xd6,0xce,0x5d,0x57,0xf7,0xfd,0x3e,0x2b,0xe8,0xc2,0x34,0x16,0x20,0x5d,0x6b,0xd5,0x25,0x9b,0x2b,0xed,0x04,0xbb,0xc6,0x41,0x30,0x48,0xe1,0x56,0xd9,0xf9,0xf2,0xf2,0x0f,0x2e,0x6b,0x35,0x9f,0x75,0x97,0xe7,0xad,0x5c,0x02,0x6c,0x5f,0xbb,0x98,0x46,0x1a,0x7b,0x9a,0x04,0x14,0x68,0xbd,0x4b,0x10}, - {0x67,0xed,0xf1,0x68,0x31,0xfd,0xf0,0x51,0xc2,0x3b,0x6f,0xd8,0xcd,0x1d,0x81,0x2c,0xde,0xf2,0xd2,0x04,0x43,0x5c,0xdc,0x44,0x49,0x71,0x2a,0x09,0x57,0xcc,0xe8,0x5b,0x63,0xf1,0x7f,0xd6,0x5f,0x9a,0x5d,0xa9,0x81,0x56,0xc7,0x4c,0x9d,0xe6,0x2b,0xe9,0x57,0xf2,0x20,0xde,0x4c,0x02,0xf8,0xb7,0xf5,0x2d,0x07,0xfb,0x20,0x2a,0x4f,0x20,0x79,0xb0,0xeb,0x30,0x3d,0x3b,0x14,0xc8,0x30,0x2e,0x65,0xbd,0x5a,0x15,0x89,0x75,0x31,0x5c,0x6d,0x8f,0x31,0x3c,0x3c,0x65,0x1f,0x16,0x79,0xc2,0x17,0xfb,0x70,0x25}, - {0x75,0x15,0xb6,0x2c,0x7f,0x36,0xfa,0x3e,0x6c,0x02,0xd6,0x1c,0x76,0x6f,0xf9,0xf5,0x62,0x25,0xb5,0x65,0x2a,0x14,0xc7,0xe8,0xcd,0x0a,0x03,0x53,0xea,0x65,0xcb,0x3d,0x5a,0x24,0xb8,0x0b,0x55,0xa9,0x2e,0x19,0xd1,0x50,0x90,0x8f,0xa8,0xfb,0xe6,0xc8,0x35,0xc9,0xa4,0x88,0x2d,0xea,0x86,0x79,0x68,0x86,0x01,0xde,0x91,0x5f,0x1c,0x24,0xaa,0x6c,0xde,0x40,0x29,0x17,0xd8,0x28,0x3a,0x73,0xd9,0x22,0xf0,0x2c,0xbf,0x8f,0xd1,0x01,0x5b,0x23,0xdd,0xfc,0xd7,0x16,0xe5,0xf0,0xcd,0x5f,0xdd,0x0e,0x42,0x08}, - {0x4a,0xfa,0x62,0x83,0xab,0x20,0xff,0xcd,0x6e,0x3e,0x1a,0xe2,0xd4,0x18,0xe1,0x57,0x2b,0xe6,0x39,0xfc,0x17,0x96,0x17,0xe3,0xfd,0x69,0x17,0xbc,0xef,0x53,0x9a,0x0d,0xce,0x10,0xf4,0x04,0x4e,0xc3,0x58,0x03,0x85,0x06,0x6e,0x27,0x5a,0x5b,0x13,0xb6,0x21,0x15,0xb9,0xeb,0xc7,0x70,0x96,0x5d,0x9c,0x88,0xdb,0x21,0xf3,0x54,0xd6,0x04,0xd5,0xb5,0xbd,0xdd,0x16,0xc1,0x7d,0x5e,0x2d,0xdd,0xa5,0x8d,0xb6,0xde,0x54,0x29,0x92,0xa2,0x34,0x33,0x17,0x08,0xb6,0x1c,0xd7,0x1a,0x99,0x18,0x26,0x4f,0x7a,0x4a}, - {0x95,0x5f,0xb1,0x5f,0x02,0x18,0xa7,0xf4,0x8f,0x1b,0x5c,0x6b,0x34,0x5f,0xf6,0x3d,0x12,0x11,0xe0,0x00,0x85,0xf0,0xfc,0xcd,0x48,0x18,0xd3,0xdd,0x4c,0x0c,0xb5,0x11,0x4b,0x2a,0x37,0xaf,0x91,0xb2,0xc3,0x24,0xf2,0x47,0x81,0x71,0x70,0x82,0xda,0x93,0xf2,0x9e,0x89,0x86,0x64,0x85,0x84,0xdd,0x33,0xee,0xe0,0x23,0x42,0x31,0x96,0x4a,0xd6,0xff,0xa4,0x08,0x44,0x27,0xe8,0xa6,0xd9,0x76,0x15,0x9c,0x7e,0x17,0x8e,0x73,0xf2,0xb3,0x02,0x3d,0xb6,0x48,0x33,0x77,0x51,0xcc,0x6b,0xce,0x4d,0xce,0x4b,0x4f}, - {0x84,0x25,0x24,0xe2,0x5a,0xce,0x1f,0xa7,0x9e,0x8a,0xf5,0x92,0x56,0x72,0xea,0x26,0xf4,0x3c,0xea,0x1c,0xd7,0x09,0x1a,0xd2,0xe6,0x01,0x1c,0xb7,0x14,0xdd,0xfc,0x73,0x6f,0x0b,0x9d,0xc4,0x6e,0x61,0xe2,0x30,0x17,0x23,0xec,0xca,0x8f,0x71,0x56,0xe4,0xa6,0x4f,0x6b,0xf2,0x9b,0x40,0xeb,0x48,0x37,0x5f,0x59,0x61,0xe5,0xce,0x42,0x30,0x41,0xac,0x9b,0x44,0x79,0x70,0x7e,0x42,0x0a,0x31,0xe2,0xbc,0x6d,0xe3,0x5a,0x85,0x7c,0x1a,0x84,0x5f,0x21,0x76,0xae,0x4c,0xd6,0xe1,0x9c,0x9a,0x0c,0x74,0x9e,0x38}, - {0xce,0xb9,0xdc,0x34,0xae,0xb3,0xfc,0x64,0xad,0xd0,0x48,0xe3,0x23,0x03,0x50,0x97,0x1b,0x38,0xc6,0x62,0x7d,0xf0,0xb3,0x45,0x88,0x67,0x5a,0x46,0x79,0x53,0x54,0x61,0x28,0xac,0x0e,0x57,0xf6,0x78,0xbd,0xc9,0xe1,0x9c,0x91,0x27,0x32,0x0b,0x5b,0xe5,0xed,0x91,0x9b,0xa1,0xab,0x3e,0xfc,0x65,0x90,0x36,0x26,0xd6,0xe5,0x25,0xc4,0x25,0x6e,0xde,0xd7,0xf1,0xa6,0x06,0x3e,0x3f,0x08,0x23,0x06,0x8e,0x27,0x76,0xf9,0x3e,0x77,0x6c,0x8a,0x4e,0x26,0xf6,0x14,0x8c,0x59,0x47,0x48,0x15,0x89,0xa0,0x39,0x65}, - {0x73,0xf7,0xd2,0xc3,0x74,0x1f,0xd2,0xe9,0x45,0x68,0xc4,0x25,0x41,0x54,0x50,0xc1,0x33,0x9e,0xb9,0xf9,0xe8,0x5c,0x4e,0x62,0x6c,0x18,0xcd,0xc5,0xaa,0xe4,0xc5,0x11,0x19,0x4a,0xbb,0x14,0xd4,0xdb,0xc4,0xdd,0x8e,0x4f,0x42,0x98,0x3c,0xbc,0xb2,0x19,0x69,0x71,0xca,0x36,0xd7,0x9f,0xa8,0x48,0x90,0xbd,0x19,0xf0,0x0e,0x32,0x65,0x0f,0xc6,0xe0,0xfd,0xca,0xb1,0xd1,0x86,0xd4,0x81,0x51,0x3b,0x16,0xe3,0xe6,0x3f,0x4f,0x9a,0x93,0xf2,0xfa,0x0d,0xaf,0xa8,0x59,0x2a,0x07,0x33,0xec,0xbd,0xc7,0xab,0x4c}, - {0x2e,0x0a,0x9c,0x08,0x24,0x96,0x9e,0x23,0x38,0x47,0xfe,0x3a,0xc0,0xc4,0x48,0xc7,0x2a,0xa1,0x4f,0x76,0x2a,0xed,0xdb,0x17,0x82,0x85,0x1c,0x32,0xf0,0x93,0x9b,0x63,0x89,0xd2,0x78,0x3f,0x8f,0x78,0x8f,0xc0,0x9f,0x4d,0x40,0xa1,0x2c,0xa7,0x30,0xfe,0x9d,0xcc,0x65,0xcf,0xfc,0x8b,0x77,0xf2,0x21,0x20,0xcb,0x5a,0x16,0x98,0xe4,0x7e,0xc3,0xa1,0x11,0x91,0xe3,0x08,0xd5,0x7b,0x89,0x74,0x90,0x80,0xd4,0x90,0x2b,0x2b,0x19,0xfd,0x72,0xae,0xc2,0xae,0xd2,0xe7,0xa6,0x02,0xb6,0x85,0x3c,0x49,0xdf,0x0e}, - {0x68,0x5a,0x9b,0x59,0x58,0x81,0xcc,0xae,0x0e,0xe2,0xad,0xeb,0x0f,0x4f,0x57,0xea,0x07,0x7f,0xb6,0x22,0x74,0x1d,0xe4,0x4f,0xb4,0x4f,0x9d,0x01,0xe3,0x92,0x3b,0x40,0x13,0x41,0x76,0x84,0xd2,0xc4,0x67,0x67,0x35,0xf8,0xf5,0xf7,0x3f,0x40,0x90,0xa0,0xde,0xbe,0xe6,0xca,0xfa,0xcf,0x8f,0x1c,0x69,0xa3,0xdf,0xd1,0x54,0x0c,0xc0,0x04,0xf8,0x5c,0x46,0x8b,0x81,0x2f,0xc2,0x4d,0xf8,0xef,0x80,0x14,0x5a,0xf3,0xa0,0x71,0x57,0xd6,0xc7,0x04,0xad,0xbf,0xe8,0xae,0xf4,0x76,0x61,0xb2,0x2a,0xb1,0x5b,0x35}, - {0xf4,0xbb,0x93,0x74,0xcc,0x64,0x1e,0xa7,0xc3,0xb0,0xa3,0xec,0xd9,0x84,0xbd,0xe5,0x85,0xe7,0x05,0xfa,0x0c,0xc5,0x6b,0x0a,0x12,0xc3,0x2e,0x18,0x32,0x81,0x9b,0x0f,0x18,0x73,0x8c,0x5a,0xc7,0xda,0x01,0xa3,0x11,0xaa,0xce,0xb3,0x9d,0x03,0x90,0xed,0x2d,0x3f,0xae,0x3b,0xbf,0x7c,0x07,0x6f,0x8e,0xad,0x52,0xe0,0xf8,0xea,0x18,0x75,0x32,0x6c,0x7f,0x1b,0xc4,0x59,0x88,0xa4,0x98,0x32,0x38,0xf4,0xbc,0x60,0x2d,0x0f,0xd9,0xd1,0xb1,0xc9,0x29,0xa9,0x15,0x18,0xc4,0x55,0x17,0xbb,0x1b,0x87,0xc3,0x47}, - {0x48,0x4f,0xec,0x71,0x97,0x53,0x44,0x51,0x6e,0x5d,0x8c,0xc9,0x7d,0xb1,0x05,0xf8,0x6b,0xc6,0xc3,0x47,0x1a,0xc1,0x62,0xf7,0xdc,0x99,0x46,0x76,0x85,0x9b,0xb8,0x00,0xb0,0x66,0x50,0xc8,0x50,0x5d,0xe6,0xfb,0xb0,0x99,0xa2,0xb3,0xb0,0xc4,0xec,0x62,0xe0,0xe8,0x1a,0x44,0xea,0x54,0x37,0xe5,0x5f,0x8d,0xd4,0xe8,0x2c,0xa0,0xfe,0x08,0xd0,0xea,0xde,0x68,0x76,0xdd,0x4d,0x82,0x23,0x5d,0x68,0x4b,0x20,0x45,0x64,0xc8,0x65,0xd6,0x89,0x5d,0xcd,0xcf,0x14,0xb5,0x37,0xd5,0x75,0x4f,0xa7,0x29,0x38,0x47}, - {0x18,0xc4,0x79,0x46,0x75,0xda,0xd2,0x82,0xf0,0x8d,0x61,0xb2,0xd8,0xd7,0x3b,0xe6,0x0a,0xeb,0x47,0xac,0x24,0xef,0x5e,0x35,0xb4,0xc6,0x33,0x48,0x4c,0x68,0x78,0x20,0xc9,0x02,0x39,0xad,0x3a,0x53,0xd9,0x23,0x8f,0x58,0x03,0xef,0xce,0xdd,0xc2,0x64,0xb4,0x2f,0xe1,0xcf,0x90,0x73,0x25,0x15,0x90,0xd3,0xe4,0x44,0x4d,0x8b,0x66,0x6c,0x0c,0x82,0x78,0x7a,0x21,0xcf,0x48,0x3b,0x97,0x3e,0x27,0x81,0xb2,0x0a,0x6a,0xf7,0x7b,0xed,0x8e,0x8c,0xa7,0x65,0x6c,0xa9,0x3f,0x43,0x8a,0x4f,0x05,0xa6,0x11,0x74}, - {0x6d,0xc8,0x9d,0xb9,0x32,0x9d,0x65,0x4d,0x15,0xf1,0x3a,0x60,0x75,0xdc,0x4c,0x04,0x88,0xe4,0xc2,0xdc,0x2c,0x71,0x4c,0xb3,0xff,0x34,0x81,0xfb,0x74,0x65,0x13,0x7c,0xb4,0x75,0xb1,0x18,0x3d,0xe5,0x9a,0x57,0x02,0xa1,0x92,0xf3,0x59,0x31,0x71,0x68,0xf5,0x35,0xef,0x1e,0xba,0xec,0x55,0x84,0x8f,0x39,0x8c,0x45,0x72,0xa8,0xc9,0x1e,0x9b,0x50,0xa2,0x00,0xd4,0xa4,0xe6,0xb8,0xb4,0x82,0xc8,0x0b,0x02,0xd7,0x81,0x9b,0x61,0x75,0x95,0xf1,0x9b,0xcc,0xe7,0x57,0x60,0x64,0xcd,0xc7,0xa5,0x88,0xdd,0x3a}, - {0xf2,0xdc,0x35,0xb6,0x70,0x57,0x89,0xab,0xbc,0x1f,0x6c,0xf6,0x6c,0xef,0xdf,0x02,0x87,0xd1,0xb6,0xbe,0x68,0x02,0x53,0x85,0x74,0x9e,0x87,0xcc,0xfc,0x29,0x99,0x24,0x46,0x30,0x39,0x59,0xd4,0x98,0xc2,0x85,0xec,0x59,0xf6,0x5f,0x98,0x35,0x7e,0x8f,0x3a,0x6e,0xf6,0xf2,0x2a,0xa2,0x2c,0x1d,0x20,0xa7,0x06,0xa4,0x31,0x11,0xba,0x61,0x29,0x90,0x95,0x16,0xf1,0xa0,0xd0,0xa3,0x89,0xbd,0x7e,0xba,0x6c,0x6b,0x3b,0x02,0x07,0x33,0x78,0x26,0x3e,0x5a,0xf1,0x7b,0xe7,0xec,0xd8,0xbb,0x0c,0x31,0x20,0x56}, - {0x43,0xd6,0x34,0x49,0x43,0x93,0x89,0x52,0xf5,0x22,0x12,0xa5,0x06,0xf8,0xdb,0xb9,0x22,0x1c,0xf4,0xc3,0x8f,0x87,0x6d,0x8f,0x30,0x97,0x9d,0x4d,0x2a,0x6a,0x67,0x37,0xd6,0x85,0xe2,0x77,0xf4,0xb5,0x46,0x66,0x93,0x61,0x8f,0x6c,0x67,0xff,0xe8,0x40,0xdd,0x94,0xb5,0xab,0x11,0x73,0xec,0xa6,0x4d,0xec,0x8c,0x65,0xf3,0x46,0xc8,0x7e,0xc7,0x2e,0xa2,0x1d,0x3f,0x8f,0x5e,0x9b,0x13,0xcd,0x01,0x6c,0x77,0x1d,0x0f,0x13,0xb8,0x9f,0x98,0xa2,0xcf,0x8f,0x4c,0x21,0xd5,0x9d,0x9b,0x39,0x23,0xf7,0xaa,0x6d}, - {0x47,0xbe,0x3d,0xeb,0x62,0x75,0x3a,0x5f,0xb8,0xa0,0xbd,0x8e,0x54,0x38,0xea,0xf7,0x99,0x72,0x74,0x45,0x31,0xe5,0xc3,0x00,0x51,0xd5,0x27,0x16,0xe7,0xe9,0x04,0x13,0xa2,0x8e,0xad,0xac,0xbf,0x04,0x3b,0x58,0x84,0xe8,0x8b,0x14,0xe8,0x43,0xb7,0x29,0xdb,0xc5,0x10,0x08,0x3b,0x58,0x1e,0x2b,0xaa,0xbb,0xb3,0x8e,0xe5,0x49,0x54,0x2b,0xfe,0x9c,0xdc,0x6a,0xd2,0x14,0x98,0x78,0x0b,0xdd,0x48,0x8b,0x3f,0xab,0x1b,0x3c,0x0a,0xc6,0x79,0xf9,0xff,0xe1,0x0f,0xda,0x93,0xd6,0x2d,0x7c,0x2d,0xde,0x68,0x44}, - {0x9e,0x46,0x19,0x94,0x5e,0x35,0xbb,0x51,0x54,0xc7,0xdd,0x23,0x4c,0xdc,0xe6,0x33,0x62,0x99,0x7f,0x44,0xd6,0xb6,0xa5,0x93,0x63,0xbd,0x44,0xfb,0x6f,0x7c,0xce,0x6c,0xce,0x07,0x63,0xf8,0xc6,0xd8,0x9a,0x4b,0x28,0x0c,0x5d,0x43,0x31,0x35,0x11,0x21,0x2c,0x77,0x7a,0x65,0xc5,0x66,0xa8,0xd4,0x52,0x73,0x24,0x63,0x7e,0x42,0xa6,0x5d,0xca,0x22,0xac,0xde,0x88,0xc6,0x94,0x1a,0xf8,0x1f,0xae,0xbb,0xf7,0x6e,0x06,0xb9,0x0f,0x58,0x59,0x8d,0x38,0x8c,0xad,0x88,0xa8,0x2c,0x9f,0xe7,0xbf,0x9a,0xf2,0x58}, - {0x68,0x3e,0xe7,0x8d,0xab,0xcf,0x0e,0xe9,0xa5,0x76,0x7e,0x37,0x9f,0x6f,0x03,0x54,0x82,0x59,0x01,0xbe,0x0b,0x5b,0x49,0xf0,0x36,0x1e,0xf4,0xa7,0xc4,0x29,0x76,0x57,0xf6,0xcd,0x0e,0x71,0xbf,0x64,0x5a,0x4b,0x3c,0x29,0x2c,0x46,0x38,0xe5,0x4c,0xb1,0xb9,0x3a,0x0b,0xd5,0x56,0xd0,0x43,0x36,0x70,0x48,0x5b,0x18,0x24,0x37,0xf9,0x6a,0x88,0xa8,0xc6,0x09,0x45,0x02,0x20,0x32,0x73,0x89,0x55,0x4b,0x13,0x36,0xe0,0xd2,0x9f,0x28,0x33,0x3c,0x23,0x36,0xe2,0x83,0x8f,0xc1,0xae,0x0c,0xbb,0x25,0x1f,0x70}, - {0xed,0x6c,0x61,0xe4,0xf8,0xb0,0xa8,0xc3,0x7d,0xa8,0x25,0x9e,0x0e,0x66,0x00,0xf7,0x9c,0xa5,0xbc,0xf4,0x1f,0x06,0xe3,0x61,0xe9,0x0b,0xc4,0xbd,0xbf,0x92,0x0c,0x2e,0x13,0xc1,0xbe,0x7c,0xd9,0xf6,0x18,0x9d,0xe4,0xdb,0xbf,0x74,0xe6,0x06,0x4a,0x84,0xd6,0x60,0x4e,0xac,0x22,0xb5,0xf5,0x20,0x51,0x5e,0x95,0x50,0xc0,0x5b,0x0a,0x72,0x35,0x5a,0x80,0x9b,0x43,0x09,0x3f,0x0c,0xfc,0xab,0x42,0x62,0x37,0x8b,0x4e,0xe8,0x46,0x93,0x22,0x5c,0xf3,0x17,0x14,0x69,0xec,0xf0,0x4e,0x14,0xbb,0x9c,0x9b,0x0e}, - {0xad,0x20,0x57,0xfb,0x8f,0xd4,0xba,0xfb,0x0e,0x0d,0xf9,0xdb,0x6b,0x91,0x81,0xee,0xbf,0x43,0x55,0x63,0x52,0x31,0x81,0xd4,0xd8,0x7b,0x33,0x3f,0xeb,0x04,0x11,0x22,0xee,0xbe,0xb1,0x5d,0xd5,0x9b,0xee,0x8d,0xb9,0x3f,0x72,0x0a,0x37,0xab,0xc3,0xc9,0x91,0xd7,0x68,0x1c,0xbf,0xf1,0xa8,0x44,0xde,0x3c,0xfd,0x1c,0x19,0x44,0x6d,0x36,0x14,0x8c,0xbc,0xf2,0x43,0x17,0x3c,0x9e,0x3b,0x6c,0x85,0xb5,0xfc,0x26,0xda,0x2e,0x97,0xfb,0xa7,0x68,0x0e,0x2f,0xb8,0xcc,0x44,0x32,0x59,0xbc,0xe6,0xa4,0x67,0x41}, - {0x00,0x27,0xf6,0x76,0x28,0x9d,0x3b,0x64,0xeb,0x68,0x76,0x0e,0x40,0x9d,0x1d,0x5d,0x84,0x06,0xfc,0x21,0x03,0x43,0x4b,0x1b,0x6a,0x24,0x55,0x22,0x7e,0xbb,0x38,0x79,0xee,0x8f,0xce,0xf8,0x65,0x26,0xbe,0xc2,0x2c,0xd6,0x80,0xe8,0x14,0xff,0x67,0xe9,0xee,0x4e,0x36,0x2f,0x7e,0x6e,0x2e,0xf1,0xf6,0xd2,0x7e,0xcb,0x70,0x33,0xb3,0x34,0xcc,0xd6,0x81,0x86,0xee,0x91,0xc5,0xcd,0x53,0xa7,0x85,0xed,0x9c,0x10,0x02,0xce,0x83,0x88,0x80,0x58,0xc1,0x85,0x74,0xed,0xe4,0x65,0xfe,0x2d,0x6e,0xfc,0x76,0x11}, - {0x9b,0x61,0x9c,0x5b,0xd0,0x6c,0xaf,0xb4,0x80,0x84,0xa5,0xb2,0xf4,0xc9,0xdf,0x2d,0xc4,0x4d,0xe9,0xeb,0x02,0xa5,0x4f,0x3d,0x34,0x5f,0x7d,0x67,0x4c,0x3a,0xfc,0x08,0xb8,0x0e,0x77,0x49,0x89,0xe2,0x90,0xdb,0xa3,0x40,0xf4,0xac,0x2a,0xcc,0xfb,0x98,0x9b,0x87,0xd7,0xde,0xfe,0x4f,0x35,0x21,0xb6,0x06,0x69,0xf2,0x54,0x3e,0x6a,0x1f,0xea,0x34,0x07,0xd3,0x99,0xc1,0xa4,0x60,0xd6,0x5c,0x16,0x31,0xb6,0x85,0xc0,0x40,0x95,0x82,0x59,0xf7,0x23,0x3e,0x33,0xe2,0xd1,0x00,0xb9,0x16,0x01,0xad,0x2f,0x4f}, - {0x54,0x4e,0xae,0x94,0x41,0xb2,0xbe,0x44,0x6c,0xef,0x57,0x18,0x51,0x1c,0x54,0x5f,0x98,0x04,0x8d,0x36,0x2d,0x6b,0x1e,0xa6,0xab,0xf7,0x2e,0x97,0xa4,0x84,0x54,0x44,0x38,0xb6,0x3b,0xb7,0x1d,0xd9,0x2c,0x96,0x08,0x9c,0x12,0xfc,0xaa,0x77,0x05,0xe6,0x89,0x16,0xb6,0xf3,0x39,0x9b,0x61,0x6f,0x81,0xee,0x44,0x29,0x5f,0x99,0x51,0x34,0x7c,0x7d,0xea,0x9f,0xd0,0xfc,0x52,0x91,0xf6,0x5c,0x93,0xb0,0x94,0x6c,0x81,0x4a,0x40,0x5c,0x28,0x47,0xaa,0x9a,0x8e,0x25,0xb7,0x93,0x28,0x04,0xa6,0x9c,0xb8,0x10}, - {0x9c,0x28,0x18,0x97,0x49,0x47,0x59,0x3d,0x26,0x3f,0x53,0x24,0xc5,0xf8,0xeb,0x12,0x15,0xef,0xc3,0x14,0xcb,0xbf,0x62,0x02,0x8e,0x51,0xb7,0x77,0xd5,0x78,0xb8,0x20,0x6e,0xf0,0x45,0x5a,0xbe,0x41,0x39,0x75,0x65,0x5f,0x9c,0x6d,0xed,0xae,0x7c,0xd0,0xb6,0x51,0xff,0x72,0x9c,0x6b,0x77,0x11,0xa9,0x4d,0x0d,0xef,0xd9,0xd1,0xd2,0x17,0x6a,0x3e,0x3f,0x07,0x18,0xaf,0xf2,0x27,0x69,0x10,0x52,0xd7,0x19,0xe5,0x3f,0xfd,0x22,0x00,0xa6,0x3c,0x2c,0xb7,0xe3,0x22,0xa7,0xc6,0x65,0xcc,0x63,0x4f,0x21,0x72}, - {0x93,0xa6,0x07,0x53,0x40,0x7f,0xe3,0xb4,0x95,0x67,0x33,0x2f,0xd7,0x14,0xa7,0xab,0x99,0x10,0x76,0x73,0xa7,0xd0,0xfb,0xd6,0xc9,0xcb,0x71,0x81,0xc5,0x48,0xdf,0x5f,0xc9,0x29,0x3b,0xf4,0xb9,0xb7,0x9d,0x1d,0x75,0x8f,0x51,0x4f,0x4a,0x82,0x05,0xd6,0xc4,0x9d,0x2f,0x31,0xbd,0x72,0xc0,0xf2,0xb0,0x45,0x15,0x5a,0x85,0xac,0x24,0x1f,0xaa,0x05,0x95,0x8e,0x32,0x08,0xd6,0x24,0xee,0x20,0x14,0x0c,0xd1,0xc1,0x48,0x47,0xa2,0x25,0xfb,0x06,0x5c,0xe4,0xff,0xc7,0xe6,0x95,0xe3,0x2a,0x9e,0x73,0xba,0x00}, - {0xd6,0x90,0x87,0x5c,0xde,0x98,0x2e,0x59,0xdf,0xa2,0xc2,0x45,0xd3,0xb7,0xbf,0xe5,0x22,0x99,0xb4,0xf9,0x60,0x3b,0x5a,0x11,0xf3,0x78,0xad,0x67,0x3e,0x3a,0x28,0x03,0x26,0xbb,0x88,0xea,0xf5,0x26,0x44,0xae,0xfb,0x3b,0x97,0x84,0xd9,0x79,0x06,0x36,0x50,0x4e,0x69,0x26,0x0c,0x03,0x9f,0x5c,0x26,0xd2,0x18,0xd5,0xe7,0x7d,0x29,0x72,0x39,0xb9,0x0c,0xbe,0xc7,0x1d,0x24,0x48,0x80,0x30,0x63,0x8b,0x4d,0x9b,0xf1,0x32,0x08,0x93,0x28,0x02,0x0d,0xc9,0xdf,0xd3,0x45,0x19,0x27,0x46,0x68,0x29,0xe1,0x05}, - {0x5a,0x49,0x9c,0x2d,0xb3,0xee,0x82,0xba,0x7c,0xb9,0x2b,0xf1,0xfc,0xc8,0xef,0xce,0xe0,0xd1,0xb5,0x93,0xae,0xab,0x2d,0xb0,0x9b,0x8d,0x69,0x13,0x9c,0x0c,0xc0,0x39,0x50,0x45,0x2c,0x24,0xc8,0xbb,0xbf,0xad,0xd9,0x81,0x30,0xd0,0xec,0x0c,0xc8,0xbc,0x92,0xdf,0xc8,0xf5,0xa6,0x66,0x35,0x84,0x4c,0xce,0x58,0x82,0xd3,0x25,0xcf,0x78,0x68,0x9d,0x48,0x31,0x8e,0x6b,0xae,0x15,0x87,0xf0,0x2b,0x9c,0xab,0x1c,0x85,0xaa,0x05,0xfa,0x4e,0xf0,0x97,0x5a,0xa7,0xc9,0x32,0xf8,0x3f,0x6b,0x07,0x52,0x6b,0x00}, - {0x1c,0x78,0x95,0x9d,0xe1,0xcf,0xe0,0x29,0xe2,0x10,0x63,0x96,0x18,0xdf,0x81,0xb6,0x39,0x6b,0x51,0x70,0xd3,0x39,0xdf,0x57,0x22,0x61,0xc7,0x3b,0x44,0xe3,0x57,0x4d,0x2d,0x08,0xce,0xb9,0x16,0x7e,0xcb,0xf5,0x29,0xbc,0x7a,0x41,0x4c,0xf1,0x07,0x34,0xab,0xa7,0xf4,0x2b,0xce,0x6b,0xb3,0xd4,0xce,0x75,0x9f,0x1a,0x56,0xe9,0xe2,0x7d,0xcb,0x5e,0xa5,0xb6,0xf4,0xd4,0x70,0xde,0x99,0xdb,0x85,0x5d,0x7f,0x52,0x01,0x48,0x81,0x9a,0xee,0xd3,0x40,0xc4,0xc9,0xdb,0xed,0x29,0x60,0x1a,0xaf,0x90,0x2a,0x6b}, - {0x97,0x1e,0xe6,0x9a,0xfc,0xf4,0x23,0x69,0xd1,0x5f,0x3f,0xe0,0x1d,0x28,0x35,0x57,0x2d,0xd1,0xed,0xe6,0x43,0xae,0x64,0xa7,0x4a,0x3e,0x2d,0xd1,0xe9,0xf4,0xd8,0x5f,0x0a,0xd8,0xb2,0x5b,0x24,0xf3,0xeb,0x77,0x9b,0x07,0xb9,0x2f,0x47,0x1b,0x30,0xd8,0x33,0x73,0xee,0x4c,0xf2,0xe6,0x47,0xc6,0x09,0x21,0x6c,0x27,0xc8,0x12,0x58,0x46,0xd9,0x62,0x10,0x2a,0xb2,0xbe,0x43,0x4d,0x16,0xdc,0x31,0x38,0x75,0xfb,0x65,0x70,0xd7,0x68,0x29,0xde,0x7b,0x4a,0x0d,0x18,0x90,0x67,0xb1,0x1c,0x2b,0x2c,0xb3,0x05}, - {0xfd,0xa8,0x4d,0xd2,0xcc,0x5e,0xc0,0xc8,0x83,0xef,0xdf,0x05,0xac,0x1a,0xcf,0xa1,0x61,0xcd,0xf9,0x7d,0xf2,0xef,0xbe,0xdb,0x99,0x1e,0x47,0x7b,0xa3,0x56,0x55,0x3b,0x95,0x81,0xd5,0x7a,0x2c,0xa4,0xfc,0xf7,0xcc,0xf3,0x33,0x43,0x6e,0x28,0x14,0x32,0x9d,0x97,0x0b,0x34,0x0d,0x9d,0xc2,0xb6,0xe1,0x07,0x73,0x56,0x48,0x1a,0x77,0x31,0x82,0xd4,0x4d,0xe1,0x24,0xc5,0xb0,0x32,0xb6,0xa4,0x2b,0x1a,0x54,0x51,0xb3,0xed,0xf3,0x5a,0x2b,0x28,0x48,0x60,0xd1,0xa3,0xeb,0x36,0x73,0x7a,0xd2,0x79,0xc0,0x4f}, - {0x7f,0x2f,0xbf,0x89,0xb0,0x38,0xc9,0x51,0xa7,0xe9,0xdf,0x02,0x65,0xbd,0x97,0x24,0x53,0xe4,0x80,0x78,0x9c,0xc0,0xff,0xff,0x92,0x8e,0xf9,0xca,0xce,0x67,0x45,0x12,0x0d,0xc5,0x86,0x0c,0x44,0x8b,0x34,0xdc,0x51,0xe6,0x94,0xcc,0xc9,0xcb,0x37,0x13,0xb9,0x3c,0x3e,0x64,0x4d,0xf7,0x22,0x64,0x08,0xcd,0xe3,0xba,0xc2,0x70,0x11,0x24,0xb4,0x73,0xc4,0x0a,0x86,0xab,0xf9,0x3f,0x35,0xe4,0x13,0x01,0xee,0x1d,0x91,0xf0,0xaf,0xc4,0xc6,0xeb,0x60,0x50,0xe7,0x4a,0x0d,0x00,0x87,0x6c,0x96,0x12,0x86,0x3f}, - {0xde,0x0d,0x2a,0x78,0xc9,0x0c,0x9a,0x55,0x85,0x83,0x71,0xea,0xb2,0xcd,0x1d,0x55,0x8c,0x23,0xef,0x31,0x5b,0x86,0x62,0x7f,0x3d,0x61,0x73,0x79,0x76,0xa7,0x4a,0x50,0x13,0x8d,0x04,0x36,0xfa,0xfc,0x18,0x9c,0xdd,0x9d,0x89,0x73,0xb3,0x9d,0x15,0x29,0xaa,0xd0,0x92,0x9f,0x0b,0x35,0x9f,0xdc,0xd4,0x19,0x8a,0x87,0xee,0x7e,0xf5,0x26,0xb1,0xef,0x87,0x56,0xd5,0x2c,0xab,0x0c,0x7b,0xf1,0x7a,0x24,0x62,0xd1,0x80,0x51,0x67,0x24,0x5a,0x4f,0x34,0x5a,0xc1,0x85,0x69,0x30,0xba,0x9d,0x3d,0x94,0x41,0x40}, - {0x96,0xcc,0xeb,0x43,0xba,0xee,0xc0,0xc3,0xaf,0x9c,0xea,0x26,0x9c,0x9c,0x74,0x8d,0xc6,0xcc,0x77,0x1c,0xee,0x95,0xfa,0xd9,0x0f,0x34,0x84,0x76,0xd9,0xa1,0x20,0x14,0xdd,0xaa,0x6c,0xa2,0x43,0x77,0x21,0x4b,0xce,0xb7,0x8a,0x64,0x24,0xb4,0xa6,0x47,0xe3,0xc9,0xfb,0x03,0x7a,0x4f,0x1d,0xcb,0x19,0xd0,0x00,0x98,0x42,0x31,0xd9,0x12,0x4f,0x59,0x37,0xd3,0x99,0x77,0xc6,0x00,0x7b,0xa4,0x3a,0xb2,0x40,0x51,0x3c,0x5e,0x95,0xf3,0x5f,0xe3,0x54,0x28,0x18,0x44,0x12,0xa0,0x59,0x43,0x31,0x92,0x4f,0x1b}, - {0x51,0x09,0x15,0x89,0x9d,0x10,0x5c,0x3e,0x6a,0x69,0xe9,0x2d,0x91,0xfa,0xce,0x39,0x20,0x30,0x5f,0x97,0x3f,0xe4,0xea,0x20,0xae,0x2d,0x13,0x7f,0x2a,0x57,0x9b,0x23,0xb1,0x66,0x98,0xa4,0x30,0x30,0xcf,0x33,0x59,0x48,0x5f,0x21,0xd2,0x73,0x1f,0x25,0xf6,0xf4,0xde,0x51,0x40,0xaa,0x82,0xab,0xf6,0x23,0x9a,0x6f,0xd5,0x91,0xf1,0x5f,0x68,0x90,0x2d,0xac,0x33,0xd4,0x9e,0x81,0x23,0x85,0xc9,0x5f,0x79,0xab,0x83,0x28,0x3d,0xeb,0x93,0x55,0x80,0x72,0x45,0xef,0xcb,0x36,0x8f,0x75,0x6a,0x52,0x0c,0x02}, - {0xbc,0xdb,0xd8,0x9e,0xf8,0x34,0x98,0x77,0x6c,0xa4,0x7c,0xdc,0xf9,0xaa,0xf2,0xc8,0x74,0xb0,0xe1,0xa3,0xdc,0x4c,0x52,0xa9,0x77,0x38,0x31,0x15,0x46,0xcc,0xaa,0x02,0x89,0xcc,0x42,0xf0,0x59,0xef,0x31,0xe9,0xb6,0x4b,0x12,0x8e,0x9d,0x9c,0x58,0x2c,0x97,0x59,0xc7,0xae,0x8a,0xe1,0xc8,0xad,0x0c,0xc5,0x02,0x56,0x0a,0xfe,0x2c,0x45,0xdf,0x77,0x78,0x64,0xa0,0xf7,0xa0,0x86,0x9f,0x7c,0x60,0x0e,0x27,0x64,0xc4,0xbb,0xc9,0x11,0xfb,0xf1,0x25,0xea,0x17,0xab,0x7b,0x87,0x4b,0x30,0x7b,0x7d,0xfb,0x4c}, - {0xfe,0x75,0x9b,0xb8,0x6c,0x3d,0xb4,0x72,0x80,0xdc,0x6a,0x9c,0xd9,0x94,0xc6,0x54,0x9f,0x4c,0xe3,0x3e,0x37,0xaa,0xc3,0xb8,0x64,0x53,0x07,0x39,0x2b,0x62,0xb4,0x14,0x12,0xef,0x89,0x97,0xc2,0x99,0x86,0xe2,0x0d,0x19,0x57,0xdf,0x71,0xcd,0x6e,0x2b,0xd0,0x70,0xc9,0xec,0x57,0xc8,0x43,0xc3,0xc5,0x3a,0x4d,0x43,0xbc,0x4c,0x1d,0x5b,0x26,0x9f,0x0a,0xcc,0x15,0x26,0xfb,0xb6,0xe5,0xcc,0x8d,0xb8,0x2b,0x0e,0x4f,0x3a,0x05,0xa7,0x69,0x33,0x8b,0x49,0x01,0x13,0xd1,0x2d,0x59,0x58,0x12,0xf7,0x98,0x2f}, - {0x56,0x9e,0x0f,0xb5,0x4c,0xa7,0x94,0x0c,0x20,0x13,0x8e,0x8e,0xa9,0xf4,0x1f,0x5b,0x67,0x0f,0x30,0x82,0x21,0xcc,0x2a,0x9a,0xf9,0xaa,0x06,0xd8,0x49,0xe2,0x6a,0x3a,0x01,0xa7,0x54,0x4f,0x44,0xae,0x12,0x2e,0xde,0xd7,0xcb,0xa9,0xf0,0x3e,0xfe,0xfc,0xe0,0x5d,0x83,0x75,0x0d,0x89,0xbf,0xce,0x54,0x45,0x61,0xe7,0xe9,0x62,0x80,0x1d,0x5a,0x7c,0x90,0xa9,0x85,0xda,0x7a,0x65,0x62,0x0f,0xb9,0x91,0xb5,0xa8,0x0e,0x1a,0xe9,0xb4,0x34,0xdf,0xfb,0x1d,0x0e,0x8d,0xf3,0x5f,0xf2,0xae,0xe8,0x8c,0x8b,0x29}, - {0xb2,0x0c,0xf7,0xef,0x53,0x79,0x92,0x2a,0x76,0x70,0x15,0x79,0x2a,0xc9,0x89,0x4b,0x6a,0xcf,0xa7,0x30,0x7a,0x45,0x18,0x94,0x85,0xe4,0x5c,0x4d,0x40,0xa8,0xb8,0x34,0xde,0x65,0x21,0x0a,0xea,0x72,0x7a,0x83,0xf6,0x79,0xcf,0x0b,0xb4,0x07,0xab,0x3f,0x70,0xae,0x38,0x77,0xc7,0x36,0x16,0x52,0xdc,0xd7,0xa7,0x03,0x18,0x27,0xa6,0x6b,0x35,0x33,0x69,0x83,0xb5,0xec,0x6e,0xc2,0xfd,0xfe,0xb5,0x63,0xdf,0x13,0xa8,0xd5,0x73,0x25,0xb2,0xa4,0x9a,0xaa,0x93,0xa2,0x6a,0x1c,0x5e,0x46,0xdd,0x2b,0xd6,0x71}, - {0x80,0xdf,0x78,0xd3,0x28,0xcc,0x33,0x65,0xb4,0xa4,0x0f,0x0a,0x79,0x43,0xdb,0xf6,0x5a,0xda,0x01,0xf7,0xf9,0x5f,0x64,0xe3,0xa4,0x2b,0x17,0xf3,0x17,0xf3,0xd5,0x74,0xf5,0x5e,0xf7,0xb1,0xda,0xb5,0x2d,0xcd,0xf5,0x65,0xb0,0x16,0xcf,0x95,0x7f,0xd7,0x85,0xf0,0x49,0x3f,0xea,0x1f,0x57,0x14,0x3d,0x2b,0x2b,0x26,0x21,0x36,0x33,0x1c,0x81,0xca,0xd9,0x67,0x54,0xe5,0x6f,0xa8,0x37,0x8c,0x29,0x2b,0x75,0x7c,0x8b,0x39,0x3b,0x62,0xac,0xe3,0x92,0x08,0x6d,0xda,0x8c,0xd9,0xe9,0x47,0x45,0xcc,0xeb,0x4a}, - {0xc9,0x01,0x6d,0x27,0x1b,0x07,0xf0,0x12,0x70,0x8c,0xc4,0x86,0xc5,0xba,0xb8,0xe7,0xa9,0xfb,0xd6,0x71,0x9b,0x12,0x08,0x53,0x92,0xb7,0x3d,0x5a,0xf9,0xfb,0x88,0x5d,0x10,0xb6,0x54,0x73,0x9e,0x8d,0x40,0x0b,0x6e,0x5b,0xa8,0x5b,0x53,0x32,0x6b,0x80,0x07,0xa2,0x58,0x4a,0x03,0x3a,0xe6,0xdb,0x2c,0xdf,0xa1,0xc9,0xdd,0xd9,0x3b,0x17,0xdf,0x72,0x58,0xfe,0x1e,0x0f,0x50,0x2b,0xc1,0x18,0x39,0xd4,0x2e,0x58,0xd6,0x58,0xe0,0x3a,0x67,0xc9,0x8e,0x27,0xed,0xe6,0x19,0xa3,0x9e,0xb1,0x13,0xcd,0xe1,0x06}, - {0x23,0x6f,0x16,0x6f,0x51,0xad,0xd0,0x40,0xbe,0x6a,0xab,0x1f,0x93,0x32,0x8e,0x11,0x8e,0x08,0x4d,0xa0,0x14,0x5e,0xe3,0x3f,0x66,0x62,0xe1,0x26,0x35,0x60,0x80,0x30,0x53,0x03,0x5b,0x9e,0x62,0xaf,0x2b,0x47,0x47,0x04,0x8d,0x27,0x90,0x0b,0xaa,0x3b,0x27,0xbf,0x43,0x96,0x46,0x5f,0x78,0x0c,0x13,0x7b,0x83,0x8d,0x1a,0x6a,0x3a,0x7f,0x0b,0x80,0x3d,0x5d,0x39,0x44,0xe6,0xf7,0xf6,0xed,0x01,0xc9,0x55,0xd5,0xa8,0x95,0x39,0x63,0x2c,0x59,0x30,0x78,0xcd,0x68,0x7e,0x30,0x51,0x2e,0xed,0xfd,0xd0,0x30}, - {0xb3,0x33,0x12,0xf2,0x1a,0x4d,0x59,0xe0,0x9c,0x4d,0xcc,0xf0,0x8e,0xe7,0xdb,0x1b,0x77,0x9a,0x49,0x8f,0x7f,0x18,0x65,0x69,0x68,0x98,0x09,0x2c,0x20,0x14,0x92,0x0a,0x50,0x47,0xb8,0x68,0x1e,0x97,0xb4,0x9c,0xcf,0xbb,0x64,0x66,0x29,0x72,0x95,0xa0,0x2b,0x41,0xfa,0x72,0x26,0xe7,0x8d,0x5c,0xd9,0x89,0xc5,0x51,0x43,0x08,0x15,0x46,0x2e,0xa0,0xb9,0xae,0xc0,0x19,0x90,0xbc,0xae,0x4c,0x03,0x16,0x0d,0x11,0xc7,0x55,0xec,0x32,0x99,0x65,0x01,0xf5,0x6d,0x0e,0xfe,0x5d,0xca,0x95,0x28,0x0d,0xca,0x3b}, - {0xa4,0x62,0x5d,0x3c,0xbc,0x31,0xf0,0x40,0x60,0x7a,0xf0,0xcf,0x3e,0x8b,0xfc,0x19,0x45,0xb5,0x0f,0x13,0xa2,0x3d,0x18,0x98,0xcd,0x13,0x8f,0xae,0xdd,0xde,0x31,0x56,0xbf,0x01,0xcc,0x9e,0xb6,0x8e,0x68,0x9c,0x6f,0x89,0x44,0xa6,0xad,0x83,0xbc,0xf0,0xe2,0x9f,0x7a,0x5f,0x5f,0x95,0x2d,0xca,0x41,0x82,0xf2,0x8d,0x03,0xb4,0xa8,0x4e,0x02,0xd2,0xca,0xf1,0x0a,0x46,0xed,0x2a,0x83,0xee,0x8c,0xa4,0x05,0x53,0x30,0x46,0x5f,0x1a,0xf1,0x49,0x45,0x77,0x21,0x91,0x63,0xa4,0x2c,0x54,0x30,0x09,0xce,0x24}, - {0x06,0xc1,0x06,0xfd,0xf5,0x90,0xe8,0x1f,0xf2,0x10,0x88,0x5d,0x35,0x68,0xc4,0xb5,0x3e,0xaf,0x8c,0x6e,0xfe,0x08,0x78,0x82,0x4b,0xd7,0x06,0x8a,0xc2,0xe3,0xd4,0x41,0x85,0x0b,0xf3,0xfd,0x55,0xa1,0xcf,0x3f,0xa4,0x2e,0x37,0x36,0x8e,0x16,0xf7,0xd2,0x44,0xf8,0x92,0x64,0xde,0x64,0xe0,0xb2,0x80,0x42,0x4f,0x32,0xa7,0x28,0x99,0x54,0x2e,0x1a,0xee,0x63,0xa7,0x32,0x6e,0xf2,0xea,0xfd,0x5f,0xd2,0xb7,0xe4,0x91,0xae,0x69,0x4d,0x7f,0xd1,0x3b,0xd3,0x3b,0xbc,0x6a,0xff,0xdc,0xc0,0xde,0x66,0x1b,0x49}, - {0xa7,0x32,0xea,0xc7,0x3d,0xb1,0xf5,0x98,0x98,0xdb,0x16,0x7e,0xcc,0xf8,0xd5,0xe3,0x47,0xd9,0xf8,0xcb,0x52,0xbf,0x0a,0xac,0xac,0xe4,0x5e,0xc8,0xd0,0x38,0xf3,0x08,0xa1,0x64,0xda,0xd0,0x8e,0x4a,0xf0,0x75,0x4b,0x28,0xe2,0x67,0xaf,0x2c,0x22,0xed,0xa4,0x7b,0x7b,0x1f,0x79,0xa3,0x34,0x82,0x67,0x8b,0x01,0xb7,0xb0,0xb8,0xf6,0x4c,0xbd,0x73,0x1a,0x99,0x21,0xa8,0x83,0xc3,0x7a,0x0c,0x32,0xdf,0x01,0xbc,0x27,0xab,0x63,0x70,0x77,0x84,0x1b,0x33,0x3d,0xc1,0x99,0x8a,0x07,0xeb,0x82,0x4a,0x0d,0x53}, - {0x25,0x48,0xf9,0xe1,0x30,0x36,0x4c,0x00,0x5a,0x53,0xab,0x8c,0x26,0x78,0x2d,0x7e,0x8b,0xff,0x84,0xcc,0x23,0x23,0x48,0xc7,0xb9,0x70,0x17,0x10,0x3f,0x75,0xea,0x65,0x9e,0xbf,0x9a,0x6c,0x45,0x73,0x69,0x6d,0x80,0xa8,0x00,0x49,0xfc,0xb2,0x7f,0x25,0x50,0xb8,0xcf,0xc8,0x12,0xf4,0xac,0x2b,0x5b,0xbd,0xbf,0x0c,0xe0,0xe7,0xb3,0x0d,0x63,0x63,0x09,0xe2,0x3e,0xfc,0x66,0x3d,0x6b,0xcb,0xb5,0x61,0x7f,0x2c,0xd6,0x81,0x1a,0x3b,0x44,0x13,0x42,0x04,0xbe,0x0f,0xdb,0xa1,0xe1,0x21,0x19,0xec,0xa4,0x02}, - {0xa2,0xb8,0x24,0x3b,0x9a,0x25,0xe6,0x5c,0xb8,0xa0,0xaf,0x45,0xcc,0x7a,0x57,0xb8,0x37,0x70,0xa0,0x8b,0xe8,0xe6,0xcb,0xcc,0xbf,0x09,0x78,0x12,0x51,0x3c,0x14,0x3d,0x5f,0x79,0xcf,0xf1,0x62,0x61,0xc8,0xf5,0xf2,0x57,0xee,0x26,0x19,0x86,0x8c,0x11,0x78,0x35,0x06,0x1c,0x85,0x24,0x21,0x17,0xcf,0x7f,0x06,0xec,0x5d,0x2b,0xd1,0x36,0x57,0x45,0x15,0x79,0x91,0x27,0x6d,0x12,0x0a,0x3a,0x78,0xfc,0x5c,0x8f,0xe4,0xd5,0xac,0x9b,0x17,0xdf,0xe8,0xb6,0xbd,0x36,0x59,0x28,0xa8,0x5b,0x88,0x17,0xf5,0x2e}, - {0xdc,0xae,0x58,0x8c,0x4e,0x97,0x37,0x46,0xa4,0x41,0xf0,0xab,0xfb,0x22,0xef,0xb9,0x8a,0x71,0x80,0xe9,0x56,0xd9,0x85,0xe1,0xa6,0xa8,0x43,0xb1,0xfa,0x78,0x1b,0x2f,0x51,0x2f,0x5b,0x30,0xfb,0xbf,0xee,0x96,0xb8,0x96,0x95,0x88,0xad,0x38,0xf9,0xd3,0x25,0xdd,0xd5,0x46,0xc7,0x2d,0xf5,0xf0,0x95,0x00,0x3a,0xbb,0x90,0x82,0x96,0x57,0x01,0xe1,0x20,0x0a,0x43,0xb8,0x1a,0xf7,0x47,0xec,0xf0,0x24,0x8d,0x65,0x93,0xf3,0xd1,0xee,0xe2,0x6e,0xa8,0x09,0x75,0xcf,0xe1,0xa3,0x2a,0xdc,0x35,0x3e,0xc4,0x7d}, - {0xc3,0xd9,0x7d,0x88,0x65,0x66,0x96,0x85,0x55,0x53,0xb0,0x4b,0x31,0x9b,0x0f,0xc9,0xb1,0x79,0x20,0xef,0xf8,0x8d,0xe0,0xc6,0x2f,0xc1,0x8c,0x75,0x16,0x20,0xf7,0x7e,0x18,0x97,0x3e,0x27,0x5c,0x2a,0x78,0x5a,0x94,0xfd,0x4e,0x5e,0x99,0xc6,0x76,0x35,0x3e,0x7d,0x23,0x1f,0x05,0xd8,0x2e,0x0f,0x99,0x0a,0xd5,0x82,0x1d,0xb8,0x4f,0x04,0xd9,0xe3,0x07,0xa9,0xc5,0x18,0xdf,0xc1,0x59,0x63,0x4c,0xce,0x1d,0x37,0xb3,0x57,0x49,0xbb,0x01,0xb2,0x34,0x45,0x70,0xca,0x2e,0xdd,0x30,0x9c,0x3f,0x82,0x79,0x7f}, - {0xe8,0x13,0xb5,0xa3,0x39,0xd2,0x34,0x83,0xd8,0xa8,0x1f,0xb9,0xd4,0x70,0x36,0xc1,0x33,0xbd,0x90,0xf5,0x36,0x41,0xb5,0x12,0xb4,0xd9,0x84,0xd7,0x73,0x03,0x4e,0x0a,0xba,0x87,0xf5,0x68,0xf0,0x1f,0x9c,0x6a,0xde,0xc8,0x50,0x00,0x4e,0x89,0x27,0x08,0xe7,0x5b,0xed,0x7d,0x55,0x99,0xbf,0x3c,0xf0,0xd6,0x06,0x1c,0x43,0xb0,0xa9,0x64,0x19,0x29,0x7d,0x5b,0xa1,0xd6,0xb3,0x2e,0x35,0x82,0x3a,0xd5,0xa0,0xf6,0xb4,0xb0,0x47,0x5d,0xa4,0x89,0x43,0xce,0x56,0x71,0x6c,0x34,0x18,0xce,0x0a,0x7d,0x1a,0x07}, - {0x0b,0xba,0x87,0xc8,0xaa,0x2d,0x07,0xd3,0xee,0x62,0xa5,0xbf,0x05,0x29,0x26,0x01,0x8b,0x76,0xef,0xc0,0x02,0x30,0x54,0xcf,0x9c,0x7e,0xea,0x46,0x71,0xcc,0x3b,0x2c,0x31,0x44,0xe1,0x20,0x52,0x35,0x0c,0xcc,0x41,0x51,0xb1,0x09,0x07,0x95,0x65,0x0d,0x36,0x5f,0x9d,0x20,0x1b,0x62,0xf5,0x9a,0xd3,0x55,0x77,0x61,0xf7,0xbc,0x69,0x7c,0x5f,0x29,0xe8,0x04,0xeb,0xd7,0xf0,0x07,0x7d,0xf3,0x50,0x2f,0x25,0x18,0xdb,0x10,0xd7,0x98,0x17,0x17,0xa3,0xa9,0x51,0xe9,0x1d,0xa5,0xac,0x22,0x73,0x9a,0x5a,0x6f}, - {0xc5,0xc6,0x41,0x2f,0x0c,0x00,0xa1,0x8b,0x9b,0xfb,0xfe,0x0c,0xc1,0x79,0x9f,0xc4,0x9f,0x1c,0xc5,0x3c,0x70,0x47,0xfa,0x4e,0xca,0xaf,0x47,0xe1,0xa2,0x21,0x4e,0x49,0xbe,0x44,0xd9,0xa3,0xeb,0xd4,0x29,0xe7,0x9e,0xaf,0x78,0x80,0x40,0x09,0x9e,0x8d,0x03,0x9c,0x86,0x47,0x7a,0x56,0x25,0x45,0x24,0x3b,0x8d,0xee,0x80,0x96,0xab,0x02,0x9a,0x0d,0xe5,0xdd,0x85,0x8a,0xa4,0xef,0x49,0xa2,0xb9,0x0f,0x4e,0x22,0x9a,0x21,0xd9,0xf6,0x1e,0xd9,0x1d,0x1f,0x09,0xfa,0x34,0xbb,0x46,0xea,0xcb,0x76,0x5d,0x6b}, - {0x94,0xd9,0x0c,0xec,0x6c,0x55,0x57,0x88,0xba,0x1d,0xd0,0x5c,0x6f,0xdc,0x72,0x64,0x77,0xb4,0x42,0x8f,0x14,0x69,0x01,0xaf,0x54,0x73,0x27,0x85,0xf6,0x33,0xe3,0x0a,0x22,0x25,0x78,0x1e,0x17,0x41,0xf9,0xe0,0xd3,0x36,0x69,0x03,0x74,0xae,0xe6,0xf1,0x46,0xc7,0xfc,0xd0,0xa2,0x3e,0x8b,0x40,0x3e,0x31,0xdd,0x03,0x9c,0x86,0xfb,0x16,0x62,0x09,0xb6,0x33,0x97,0x19,0x8e,0x28,0x33,0xe1,0xab,0xd8,0xb4,0x72,0xfc,0x24,0x3e,0xd0,0x91,0x09,0xed,0xf7,0x11,0x48,0x75,0xd0,0x70,0x8f,0x8b,0xe3,0x81,0x3f}, - {0xfe,0xaf,0xd9,0x7e,0xcc,0x0f,0x91,0x7f,0x4b,0x87,0x65,0x24,0xa1,0xb8,0x5c,0x54,0x04,0x47,0x0c,0x4b,0xd2,0x7e,0x39,0xa8,0x93,0x09,0xf5,0x04,0xc1,0x0f,0x51,0x50,0x24,0xc8,0x17,0x5f,0x35,0x7f,0xdb,0x0a,0xa4,0x99,0x42,0xd7,0xc3,0x23,0xb9,0x74,0xf7,0xea,0xf8,0xcb,0x8b,0x3e,0x7c,0xd5,0x3d,0xdc,0xde,0x4c,0xd3,0xe2,0xd3,0x0a,0x9d,0x24,0x6e,0x33,0xc5,0x0f,0x0c,0x6f,0xd9,0xcf,0x31,0xc3,0x19,0xde,0x5e,0x74,0x1c,0xfe,0xee,0x09,0x00,0xfd,0xd6,0xf2,0xbe,0x1e,0xfa,0xf0,0x8b,0x15,0x7c,0x12}, - {0xa2,0x79,0x98,0x2e,0x42,0x7c,0x19,0xf6,0x47,0x36,0xca,0x52,0xd4,0xdd,0x4a,0xa4,0xcb,0xac,0x4e,0x4b,0xc1,0x3f,0x41,0x9b,0x68,0x4f,0xef,0x07,0x7d,0xf8,0x4e,0x35,0x74,0xb9,0x51,0xae,0xc4,0x8f,0xa2,0xde,0x96,0xfe,0x4d,0x74,0xd3,0x73,0x99,0x1d,0xa8,0x48,0x38,0x87,0x0b,0x68,0x40,0x62,0x95,0xdf,0x67,0xd1,0x79,0x24,0xd8,0x4e,0x75,0xd9,0xc5,0x60,0x22,0xb5,0xe3,0xfe,0xb8,0xb0,0x41,0xeb,0xfc,0x2e,0x35,0x50,0x3c,0x65,0xf6,0xa9,0x30,0xac,0x08,0x88,0x6d,0x23,0x39,0x05,0xd2,0x92,0x2d,0x30}, - {0x3d,0x28,0xa4,0xbc,0xa2,0xc1,0x13,0x78,0xd9,0x3d,0x86,0xa1,0x91,0xf0,0x62,0xed,0x86,0xfa,0x68,0xc2,0xb8,0xbc,0xc7,0xae,0x4c,0xae,0x1c,0x6f,0xb7,0xd3,0xe5,0x10,0x77,0xf1,0xe0,0xe4,0xb6,0x6f,0xbc,0x2d,0x93,0x6a,0xbd,0xa4,0x29,0xbf,0xe1,0x04,0xe8,0xf6,0x7a,0x78,0xd4,0x66,0x19,0x5e,0x60,0xd0,0x26,0xb4,0x5e,0x5f,0xdc,0x0e,0x67,0x8e,0xda,0x53,0xd6,0xbf,0x53,0x54,0x41,0xf6,0xa9,0x24,0xec,0x1e,0xdc,0xe9,0x23,0x8a,0x57,0x03,0x3b,0x26,0x87,0xbf,0x72,0xba,0x1c,0x36,0x51,0x6c,0xb4,0x45}, - {0xa1,0x7f,0x4f,0x31,0xbf,0x2a,0x40,0xa9,0x50,0xf4,0x8c,0x8e,0xdc,0xf1,0x57,0xe2,0x84,0xbe,0xa8,0x23,0x4b,0xd5,0xbb,0x1d,0x3b,0x71,0xcb,0x6d,0xa3,0xbf,0x77,0x21,0xe4,0xe3,0x7f,0x8a,0xdd,0x4d,0x9d,0xce,0x30,0x0e,0x62,0x76,0x56,0x64,0x13,0xab,0x58,0x99,0x0e,0xb3,0x7b,0x4f,0x59,0x4b,0xdf,0x29,0x12,0x32,0xef,0x0a,0x1c,0x5c,0x8f,0xdb,0x79,0xfa,0xbc,0x1b,0x08,0x37,0xb3,0x59,0x5f,0xc2,0x1e,0x81,0x48,0x60,0x87,0x24,0x83,0x9c,0x65,0x76,0x7a,0x08,0xbb,0xb5,0x8a,0x7d,0x38,0x19,0xe6,0x4a}, - {0x2e,0xa3,0x44,0x53,0xaa,0xf6,0xdb,0x8d,0x78,0x40,0x1b,0xb4,0xb4,0xea,0x88,0x7d,0x60,0x0d,0x13,0x4a,0x97,0xeb,0xb0,0x5e,0x03,0x3e,0xbf,0x17,0x1b,0xd9,0x00,0x1a,0x83,0xfb,0x5b,0x98,0x44,0x7e,0x11,0x61,0x36,0x31,0x96,0x71,0x2a,0x46,0xe0,0xfc,0x4b,0x90,0x25,0xd4,0x48,0x34,0xac,0x83,0x64,0x3d,0xa4,0x5b,0xbe,0x5a,0x68,0x75,0xb2,0xf2,0x61,0xeb,0x33,0x09,0x96,0x6e,0x52,0x49,0xff,0xc9,0xa8,0x0f,0x3d,0x54,0x69,0x65,0xf6,0x7a,0x10,0x75,0x72,0xdf,0xaa,0xe6,0xb0,0x23,0xb6,0x29,0x55,0x13}, - {0x18,0xd5,0xd1,0xad,0xd7,0xdb,0xf0,0x18,0x11,0x1f,0xc1,0xcf,0x88,0x78,0x9f,0x97,0x9b,0x75,0x14,0x71,0xf0,0xe1,0x32,0x87,0x01,0x3a,0xca,0x65,0x1a,0xb8,0xb5,0x79,0xfe,0x83,0x2e,0xe2,0xbc,0x16,0xc7,0xf5,0xc1,0x85,0x09,0xe8,0x19,0xeb,0x2b,0xb4,0xae,0x4a,0x25,0x14,0x37,0xa6,0x9d,0xec,0x13,0xa6,0x90,0x15,0x05,0xea,0x72,0x59,0x11,0x78,0x8f,0xdc,0x20,0xac,0xd4,0x0f,0xa8,0x4f,0x4d,0xac,0x94,0xd2,0x9a,0x9a,0x34,0x04,0x36,0xb3,0x64,0x2d,0x1b,0xc0,0xdb,0x3b,0x5f,0x90,0x95,0x9c,0x7e,0x4f}, - {0x2e,0x30,0x81,0x57,0xbc,0x4b,0x67,0x62,0x0f,0xdc,0xad,0x89,0x39,0x0f,0x52,0xd8,0xc6,0xd9,0xfb,0x53,0xae,0x99,0x29,0x8c,0x4c,0x8e,0x63,0x2e,0xd9,0x3a,0x99,0x31,0xfe,0x99,0x52,0x35,0x3d,0x44,0xc8,0x71,0xd7,0xea,0xeb,0xdb,0x1c,0x3b,0xcd,0x8b,0x66,0x94,0xa4,0xf1,0x9e,0x49,0x92,0x80,0xc8,0xad,0x44,0xa1,0xc4,0xee,0x42,0x19,0x92,0x49,0x23,0xae,0x19,0x53,0xac,0x7d,0x92,0x3e,0xea,0x0c,0x91,0x3d,0x1b,0x2c,0x22,0x11,0x3c,0x25,0x94,0xe4,0x3c,0x55,0x75,0xca,0xf9,0x4e,0x31,0x65,0x0a,0x2a}, - {0xc2,0x27,0xf9,0xf7,0x7f,0x93,0xb7,0x2d,0x35,0xa6,0xd0,0x17,0x06,0x1f,0x74,0xdb,0x76,0xaf,0x55,0x11,0xa2,0xf3,0x82,0x59,0xed,0x2d,0x7c,0x64,0x18,0xe2,0xf6,0x4c,0x3a,0x79,0x1c,0x3c,0xcd,0x1a,0x36,0xcf,0x3b,0xbc,0x35,0x5a,0xac,0xbc,0x9e,0x2f,0xab,0xa6,0xcd,0xa8,0xe9,0x60,0xe8,0x60,0x13,0x1a,0xea,0x6d,0x9b,0xc3,0x5d,0x05,0xb6,0x5b,0x8d,0xc2,0x7c,0x22,0x19,0xb1,0xab,0xff,0x4d,0x77,0xbc,0x4e,0xe2,0x07,0x89,0x2c,0xa3,0xe4,0xce,0x78,0x3c,0xa8,0xb6,0x24,0xaa,0x10,0x77,0x30,0x1a,0x12}, - {0x97,0x4a,0x03,0x9f,0x5e,0x5d,0xdb,0xe4,0x2d,0xbc,0x34,0x30,0x09,0xfc,0x53,0xe1,0xb1,0xd3,0x51,0x95,0x91,0x46,0x05,0x46,0x2d,0xe5,0x40,0x7a,0x6c,0xc7,0x3f,0x33,0xc9,0x83,0x74,0xc7,0x3e,0x71,0x59,0xd6,0xaf,0x96,0x2b,0xb8,0x77,0xe0,0xbf,0x88,0xd3,0xbc,0x97,0x10,0x23,0x28,0x9e,0x28,0x9b,0x3a,0xed,0x6c,0x4a,0xb9,0x7b,0x52,0x2e,0x48,0x5b,0x99,0x2a,0x99,0x3d,0x56,0x01,0x38,0x38,0x6e,0x7c,0xd0,0x05,0x34,0xe5,0xd8,0x64,0x2f,0xde,0x35,0x50,0x48,0xf7,0xa9,0xa7,0x20,0x9b,0x06,0x89,0x6b}, - {0x0d,0x22,0x70,0x62,0x41,0xa0,0x2a,0x81,0x4e,0x5b,0x24,0xf9,0xfa,0x89,0x5a,0x99,0x05,0xef,0x72,0x50,0xce,0xc4,0xad,0xff,0x73,0xeb,0x73,0xaa,0x03,0x21,0xbc,0x23,0x77,0xdb,0xc7,0xb5,0x8c,0xfa,0x82,0x40,0x55,0xc1,0x34,0xc7,0xf8,0x86,0x86,0x06,0x7e,0xa5,0xe7,0xf6,0xd9,0xc8,0xe6,0x29,0xcf,0x9b,0x63,0xa7,0x08,0xd3,0x73,0x04,0x05,0x9e,0x58,0x03,0x26,0x79,0xee,0xca,0x92,0xc4,0xdc,0x46,0x12,0x42,0x4b,0x2b,0x4f,0xa9,0x01,0xe6,0x74,0xef,0xa1,0x02,0x1a,0x34,0x04,0xde,0xbf,0x73,0x2f,0x10}, - {0xc6,0x45,0x57,0x7f,0xab,0xb9,0x18,0xeb,0x90,0xc6,0x87,0x57,0xee,0x8a,0x3a,0x02,0xa9,0xaf,0xf7,0x2d,0xda,0x12,0x27,0xb7,0x3d,0x01,0x5c,0xea,0x25,0x7d,0x59,0x36,0x9a,0x1c,0x51,0xb5,0xe0,0xda,0xb4,0xa2,0x06,0xff,0xff,0x2b,0x29,0x60,0xc8,0x7a,0x34,0x42,0x50,0xf5,0x5d,0x37,0x1f,0x98,0x2d,0xa1,0x4e,0xda,0x25,0xd7,0x6b,0x3f,0xac,0x58,0x60,0x10,0x7b,0x8d,0x4d,0x73,0x5f,0x90,0xc6,0x6f,0x9e,0x57,0x40,0xd9,0x2d,0x93,0x02,0x92,0xf9,0xf8,0x66,0x64,0xd0,0xd6,0x60,0xda,0x19,0xcc,0x7e,0x7b}, - {0x0d,0x69,0x5c,0x69,0x3c,0x37,0xc2,0x78,0x6e,0x90,0x42,0x06,0x66,0x2e,0x25,0xdd,0xd2,0x2b,0xe1,0x4a,0x44,0x44,0x1d,0x95,0x56,0x39,0x74,0x01,0x76,0xad,0x35,0x42,0x9b,0xfa,0x7c,0xa7,0x51,0x4a,0xae,0x6d,0x50,0x86,0xa3,0xe7,0x54,0x36,0x26,0x82,0xdb,0x82,0x2d,0x8f,0xcd,0xff,0xbb,0x09,0xba,0xca,0xf5,0x1b,0x66,0xdc,0xbe,0x03,0xf5,0x75,0x89,0x07,0x0d,0xcb,0x58,0x62,0x98,0xf2,0x89,0x91,0x54,0x42,0x29,0x49,0xe4,0x6e,0xe3,0xe2,0x23,0xb4,0xca,0xa0,0xa1,0x66,0xf0,0xcd,0xb0,0xe2,0x7c,0x0e}, - {0xa3,0x85,0x8c,0xc4,0x3a,0x64,0x94,0xc4,0xad,0x39,0x61,0x3c,0xf4,0x1d,0x36,0xfd,0x48,0x4d,0xe9,0x3a,0xdd,0x17,0xdb,0x09,0x4a,0x67,0xb4,0x8f,0x5d,0x0a,0x6e,0x66,0xf9,0x70,0x4b,0xd9,0xdf,0xfe,0xa6,0xfe,0x2d,0xba,0xfc,0xc1,0x51,0xc0,0x30,0xf1,0x89,0xab,0x2f,0x7f,0x7e,0xd4,0x82,0x48,0xb5,0xee,0xec,0x8a,0x13,0x56,0x52,0x61,0x0d,0xcb,0x70,0x48,0x4e,0xf6,0xbb,0x2a,0x6b,0x8b,0x45,0xaa,0xf0,0xbc,0x65,0xcd,0x5d,0x98,0xe8,0x75,0xba,0x4e,0xbe,0x9a,0xe4,0xde,0x14,0xd5,0x10,0xc8,0x0b,0x7f}, - {0x6f,0x13,0xf4,0x26,0xa4,0x6b,0x00,0xb9,0x35,0x30,0xe0,0x57,0x9e,0x36,0x67,0x8d,0x28,0x3c,0x46,0x4f,0xd9,0xdf,0xc8,0xcb,0xf5,0xdb,0xee,0xf8,0xbc,0x8d,0x1f,0x0d,0xa0,0x13,0x72,0x73,0xad,0x9d,0xac,0x83,0x98,0x2e,0xf7,0x2e,0xba,0xf8,0xf6,0x9f,0x57,0x69,0xec,0x43,0xdd,0x2e,0x1e,0x31,0x75,0xab,0xc5,0xde,0x7d,0x90,0x3a,0x1d,0xdc,0x81,0xd0,0x3e,0x31,0x93,0x16,0xba,0x80,0x34,0x1b,0x85,0xad,0x9f,0x32,0x29,0xcb,0x21,0x03,0x03,0x3c,0x01,0x28,0x01,0xe3,0xfd,0x1b,0xa3,0x44,0x1b,0x01,0x00}, - {0x0c,0x6c,0xc6,0x3f,0x6c,0xa0,0xdf,0x3f,0xd2,0x0d,0xd6,0x4d,0x8e,0xe3,0x40,0x5d,0x71,0x4d,0x8e,0x26,0x38,0x8b,0xe3,0x7a,0xe1,0x57,0x83,0x6e,0x91,0x8d,0xc4,0x3a,0x5c,0xa7,0x0a,0x6a,0x69,0x1f,0x56,0x16,0x6a,0xbd,0x52,0x58,0x5c,0x72,0xbf,0xc1,0xad,0x66,0x79,0x9a,0x7f,0xdd,0xa8,0x11,0x26,0x10,0x85,0xd2,0xa2,0x88,0xd9,0x63,0x2e,0x23,0xbd,0xaf,0x53,0x07,0x12,0x00,0x83,0xf6,0xd8,0xfd,0xb8,0xce,0x2b,0xe9,0x91,0x2b,0xe7,0x84,0xb3,0x69,0x16,0xf8,0x66,0xa0,0x68,0x23,0x2b,0xd5,0xfa,0x33}, - {0x16,0x1e,0xe4,0xc5,0xc6,0x49,0x06,0x54,0x35,0x77,0x3f,0x33,0x30,0x64,0xf8,0x0a,0x46,0xe7,0x05,0xf3,0xd2,0xfc,0xac,0xb2,0xa7,0xdc,0x56,0xa2,0x29,0xf4,0xc0,0x16,0xe8,0xcf,0x22,0xc4,0xd0,0xc8,0x2c,0x8d,0xcb,0x3a,0xa1,0x05,0x7b,0x4f,0x2b,0x07,0x6f,0xa5,0xf6,0xec,0xe6,0xb6,0xfe,0xa3,0xe2,0x71,0x0a,0xb9,0xcc,0x55,0xc3,0x3c,0x31,0x91,0x3e,0x90,0x43,0x94,0xb6,0xe9,0xce,0x37,0x56,0x7a,0xcb,0x94,0xa4,0xb8,0x44,0x92,0xba,0xba,0xa4,0xd1,0x7c,0xc8,0x68,0x75,0xae,0x6b,0x42,0xaf,0x1e,0x63}, - {0x9f,0xfe,0x66,0xda,0x10,0x04,0xe9,0xb3,0xa6,0xe5,0x16,0x6c,0x52,0x4b,0xdd,0x85,0x83,0xbf,0xf9,0x1e,0x61,0x97,0x3d,0xbc,0xb5,0x19,0xa9,0x1e,0x8b,0x64,0x99,0x55,0xe8,0x0d,0x70,0xa3,0xb9,0x75,0xd9,0x47,0x52,0x05,0xf8,0xe2,0xfb,0xc5,0x80,0x72,0xe1,0x5d,0xe4,0x32,0x27,0x8f,0x65,0x53,0xb5,0x80,0x5f,0x66,0x7f,0x2c,0x1f,0x43,0x19,0x7b,0x8f,0x85,0x44,0x63,0x02,0xd6,0x4a,0x51,0xea,0xa1,0x2f,0x35,0xab,0x14,0xd7,0xa9,0x90,0x20,0x1a,0x44,0x00,0x89,0x26,0x3b,0x25,0x91,0x5f,0x71,0x04,0x7b}, - {0x43,0xae,0xf6,0xac,0x28,0xbd,0xed,0x83,0xb4,0x7a,0x5c,0x7d,0x8b,0x7c,0x35,0x86,0x44,0x2c,0xeb,0xb7,0x69,0x47,0x40,0xc0,0x3f,0x58,0xf6,0xc2,0xf5,0x7b,0xb3,0x59,0xc6,0xba,0xe6,0xc4,0x80,0xc2,0x76,0xb3,0x0b,0x9b,0x1d,0x6d,0xdd,0xd3,0x0e,0x97,0x44,0xf9,0x0b,0x45,0x58,0x95,0x9a,0xb0,0x23,0xe2,0xcd,0x57,0xfa,0xac,0xd0,0x48,0x71,0xe6,0xab,0x7d,0xe4,0x26,0x0f,0xb6,0x37,0x3a,0x2f,0x62,0x97,0xa1,0xd1,0xf1,0x94,0x03,0x96,0xe9,0x7e,0xce,0x08,0x42,0xdb,0x3b,0x6d,0x33,0x91,0x41,0x23,0x16}, - {0xf6,0x7f,0x26,0xf6,0xde,0x99,0xe4,0xb9,0x43,0x08,0x2c,0x74,0x7b,0xca,0x72,0x77,0xb1,0xf2,0xa4,0xe9,0x3f,0x15,0xa0,0x23,0x06,0x50,0xd0,0xd5,0xec,0xdf,0xdf,0x2c,0x40,0x86,0xf3,0x1f,0xd6,0x9c,0x49,0xdd,0xa0,0x25,0x36,0x06,0xc3,0x9b,0xcd,0x29,0xc3,0x3d,0xd7,0x3d,0x02,0xd8,0xe2,0x51,0x31,0x92,0x3b,0x20,0x7a,0x70,0x25,0x4a,0x6a,0xed,0xf6,0x53,0x8a,0x66,0xb7,0x2a,0xa1,0x70,0xd1,0x1d,0x58,0x42,0x42,0x30,0x61,0x01,0xe2,0x3a,0x4c,0x14,0x00,0x40,0xfc,0x49,0x8e,0x24,0x6d,0x89,0x21,0x57}, - {0xae,0x1b,0x18,0xfd,0x17,0x55,0x6e,0x0b,0xb4,0x63,0xb9,0x2b,0x9f,0x62,0x22,0x90,0x25,0x46,0x06,0x32,0xe9,0xbc,0x09,0x55,0xda,0x13,0x3c,0xf6,0x74,0xdd,0x8e,0x57,0x4e,0xda,0xd0,0xa1,0x91,0x50,0x5d,0x28,0x08,0x3e,0xfe,0xb5,0xa7,0x6f,0xaa,0x4b,0xb3,0x93,0x93,0xe1,0x7c,0x17,0xe5,0x63,0xfd,0x30,0xb0,0xc4,0xaf,0x35,0xc9,0x03,0x3d,0x0c,0x2b,0x49,0xc6,0x76,0x72,0x99,0xfc,0x05,0xe2,0xdf,0xc4,0xc2,0xcc,0x47,0x3c,0x3a,0x62,0xdd,0x84,0x9b,0xd2,0xdc,0xa2,0xc7,0x88,0x02,0x59,0xab,0xc2,0x3e}, - {0xb9,0x7b,0xd8,0xe4,0x7b,0xd2,0xa0,0xa1,0xed,0x1a,0x39,0x61,0xeb,0x4d,0x8b,0xa9,0x83,0x9b,0xcb,0x73,0xd0,0xdd,0xa0,0x99,0xce,0xca,0x0f,0x20,0x5a,0xc2,0xd5,0x2d,0xcb,0xd1,0x32,0xae,0x09,0x3a,0x21,0xa7,0xd5,0xc2,0xf5,0x40,0xdf,0x87,0x2b,0x0f,0x29,0xab,0x1e,0xe8,0xc6,0xa4,0xae,0x0b,0x5e,0xac,0xdb,0x6a,0x6c,0xf6,0x1b,0x0e,0x7e,0x88,0x2c,0x79,0xe9,0xd5,0xab,0xe2,0x5d,0x6d,0x92,0xcb,0x18,0x00,0x02,0x1a,0x1e,0x5f,0xae,0xba,0xcd,0x69,0xba,0xbf,0x5f,0x8f,0xe8,0x5a,0xb3,0x48,0x05,0x73}, - {0xee,0xb8,0xa8,0xcb,0xa3,0x51,0x35,0xc4,0x16,0x5f,0x11,0xb2,0x1d,0x6f,0xa2,0x65,0x50,0x38,0x8c,0xab,0x52,0x4f,0x0f,0x76,0xca,0xb8,0x1d,0x41,0x3b,0x44,0x43,0x30,0x34,0xe3,0xd6,0xa1,0x4b,0x09,0x5b,0x80,0x19,0x3f,0x35,0x09,0x77,0xf1,0x3e,0xbf,0x2b,0x70,0x22,0x06,0xcb,0x06,0x3f,0x42,0xdd,0x45,0x78,0xd8,0x77,0x22,0x5a,0x58,0x62,0x89,0xd4,0x33,0x82,0x5f,0x8a,0xa1,0x7f,0x25,0x78,0xec,0xb5,0xc4,0x98,0x66,0xff,0x41,0x3e,0x37,0xa5,0x6f,0x8e,0xa7,0x1f,0x98,0xef,0x50,0x89,0x27,0x56,0x76}, - {0xc0,0xc8,0x1f,0xd5,0x59,0xcf,0xc3,0x38,0xf2,0xb6,0x06,0x05,0xfd,0xd2,0xed,0x9b,0x8f,0x0e,0x57,0xab,0x9f,0x10,0xbf,0x26,0xa6,0x46,0xb8,0xc1,0xa8,0x60,0x41,0x3f,0x9d,0xcf,0x86,0xea,0xa3,0x73,0x70,0xe1,0xdc,0x5f,0x15,0x07,0xb7,0xfb,0x8c,0x3a,0x8e,0x8a,0x83,0x31,0xfc,0xe7,0x53,0x48,0x16,0xf6,0x13,0xb6,0x84,0xf4,0xbb,0x28,0x7c,0x6c,0x13,0x6f,0x5c,0x2f,0x61,0xf2,0xbe,0x11,0xdd,0xf6,0x07,0xd1,0xea,0xaf,0x33,0x6f,0xde,0x13,0xd2,0x9a,0x7e,0x52,0x5d,0xf7,0x88,0x81,0x35,0xcb,0x79,0x1e}, - {0xf1,0xe3,0xf7,0xee,0xc3,0x36,0x34,0x01,0xf8,0x10,0x9e,0xfe,0x7f,0x6a,0x8b,0x82,0xfc,0xde,0xf9,0xbc,0xe5,0x08,0xf9,0x7f,0x31,0x38,0x3b,0x3a,0x1b,0x95,0xd7,0x65,0x81,0x81,0xe0,0xf5,0xd8,0x53,0xe9,0x77,0xd9,0xde,0x9d,0x29,0x44,0x0c,0xa5,0x84,0xe5,0x25,0x45,0x86,0x0c,0x2d,0x6c,0xdc,0xf4,0xf2,0xd1,0x39,0x2d,0xb5,0x8a,0x47,0x59,0xd1,0x52,0x92,0xd3,0xa4,0xa6,0x66,0x07,0xc8,0x1a,0x87,0xbc,0xe1,0xdd,0xe5,0x6f,0xc9,0xc1,0xa6,0x40,0x6b,0x2c,0xb8,0x14,0x22,0x21,0x1a,0x41,0x7a,0xd8,0x16}, - {0x15,0x62,0x06,0x42,0x5a,0x7e,0xbd,0xb3,0xc1,0x24,0x5a,0x0c,0xcd,0xe3,0x9b,0x87,0xb7,0x94,0xf9,0xd6,0xb1,0x5d,0xc0,0x57,0xa6,0x8c,0xf3,0x65,0x81,0x7c,0xf8,0x28,0x83,0x05,0x4e,0xd5,0xe2,0xd5,0xa4,0xfb,0xfa,0x99,0xbd,0x2e,0xd7,0xaf,0x1f,0xe2,0x8f,0x77,0xe9,0x6e,0x73,0xc2,0x7a,0x49,0xde,0x6d,0x5a,0x7a,0x57,0x0b,0x99,0x1f,0xd6,0xf7,0xe8,0x1b,0xad,0x4e,0x34,0xa3,0x8f,0x79,0xea,0xac,0xeb,0x50,0x1e,0x7d,0x52,0xe0,0x0d,0x52,0x9e,0x56,0xc6,0x77,0x3e,0x6d,0x4d,0x53,0xe1,0x2f,0x88,0x45}, - {0xd6,0x83,0x79,0x75,0x5d,0x34,0x69,0x66,0xa6,0x11,0xaa,0x17,0x11,0xed,0xb6,0x62,0x8f,0x12,0x5e,0x98,0x57,0x18,0xdd,0x7d,0xdd,0xf6,0x26,0xf6,0xb8,0xe5,0x8f,0x68,0xe4,0x6f,0x3c,0x94,0x29,0x99,0xac,0xd8,0xa2,0x92,0x83,0xa3,0x61,0xf1,0xf9,0xb5,0xf3,0x9a,0xc8,0xbe,0x13,0xdb,0x99,0x26,0x74,0xf0,0x05,0xe4,0x3c,0x84,0xcf,0x7d,0xc0,0x32,0x47,0x4a,0x48,0xd6,0x90,0x6c,0x99,0x32,0x56,0xca,0xfd,0x43,0x21,0xd5,0xe1,0xc6,0x5d,0x91,0xc3,0x28,0xbe,0xb3,0x1b,0x19,0x27,0x73,0x7e,0x68,0x39,0x67}, - {0xa6,0x75,0x56,0x38,0x14,0x20,0x78,0xef,0xe8,0xa9,0xfd,0xaa,0x30,0x9f,0x64,0xa2,0xcb,0xa8,0xdf,0x5c,0x50,0xeb,0xd1,0x4c,0xb3,0xc0,0x4d,0x1d,0xba,0x5a,0x11,0x46,0xc0,0x1a,0x0c,0xc8,0x9d,0xcc,0x6d,0xa6,0x36,0xa4,0x38,0x1b,0xf4,0x5c,0xa0,0x97,0xc6,0xd7,0xdb,0x95,0xbe,0xf3,0xeb,0xa7,0xab,0x7d,0x7e,0x8d,0xf6,0xb8,0xa0,0x7d,0x76,0xda,0xb5,0xc3,0x53,0x19,0x0f,0xd4,0x9b,0x9e,0x11,0x21,0x73,0x6f,0xac,0x1d,0x60,0x59,0xb2,0xfe,0x21,0x60,0xcc,0x03,0x4b,0x4b,0x67,0x83,0x7e,0x88,0x5f,0x5a}, - {0x11,0x3d,0xa1,0x70,0xcf,0x01,0x63,0x8f,0xc4,0xd0,0x0d,0x35,0x15,0xb8,0xce,0xcf,0x7e,0xa4,0xbc,0xa4,0xd4,0x97,0x02,0xf7,0x34,0x14,0x4d,0xe4,0x56,0xb6,0x69,0x36,0xb9,0x43,0xa6,0xa0,0xd3,0x28,0x96,0x9e,0x64,0x20,0xc3,0xe6,0x00,0xcb,0xc3,0xb5,0x32,0xec,0x2d,0x7c,0x89,0x02,0x53,0x9b,0x0c,0xc7,0xd1,0xd5,0xe2,0x7a,0xe3,0x43,0x33,0xe1,0xa6,0xed,0x06,0x3f,0x7e,0x38,0xc0,0x3a,0xa1,0x99,0x51,0x1d,0x30,0x67,0x11,0x38,0x26,0x36,0xf8,0xd8,0x5a,0xbd,0xbe,0xe9,0xd5,0x4f,0xcd,0xe6,0x21,0x6a}, - {0x5f,0xe6,0x46,0x30,0x0a,0x17,0xc6,0xf1,0x24,0x35,0xd2,0x00,0x2a,0x2a,0x71,0x58,0x55,0xb7,0x82,0x8c,0x3c,0xbd,0xdb,0x69,0x57,0xff,0x95,0xa1,0xf1,0xf9,0x6b,0x58,0xe3,0xb2,0x99,0x66,0x12,0x29,0x41,0xef,0x01,0x13,0x8d,0x70,0x47,0x08,0xd3,0x71,0xbd,0xb0,0x82,0x11,0xd0,0x32,0x54,0x32,0x36,0x8b,0x1e,0x00,0x07,0x1b,0x37,0x45,0x0b,0x79,0xf8,0x5e,0x8d,0x08,0xdb,0xa6,0xe5,0x37,0x09,0x61,0xdc,0xf0,0x78,0x52,0xb8,0x6e,0xa1,0x61,0xd2,0x49,0x03,0xac,0x79,0x21,0xe5,0x90,0x37,0xb0,0xaf,0x0e}, - {0x2f,0x04,0x48,0x37,0xc1,0x55,0x05,0x96,0x11,0xaa,0x0b,0x82,0xe6,0x41,0x9a,0x21,0x0c,0x6d,0x48,0x73,0x38,0xf7,0x81,0x1c,0x61,0xc6,0x02,0x5a,0x67,0xcc,0x9a,0x30,0x1d,0xae,0x75,0x0f,0x5e,0x80,0x40,0x51,0x30,0xcc,0x62,0x26,0xe3,0xfb,0x02,0xec,0x6d,0x39,0x92,0xea,0x1e,0xdf,0xeb,0x2c,0xb3,0x5b,0x43,0xc5,0x44,0x33,0xae,0x44,0xee,0x43,0xa5,0xbb,0xb9,0x89,0xf2,0x9c,0x42,0x71,0xc9,0x5a,0x9d,0x0e,0x76,0xf3,0xaa,0x60,0x93,0x4f,0xc6,0xe5,0x82,0x1d,0x8f,0x67,0x94,0x7f,0x1b,0x22,0xd5,0x62}, - {0x6d,0x93,0xd0,0x18,0x9c,0x29,0x4c,0x52,0x0c,0x1a,0x0c,0x8a,0x6c,0xb5,0x6b,0xc8,0x31,0x86,0x4a,0xdb,0x2e,0x05,0x75,0xa3,0x62,0x45,0x75,0xbc,0xe4,0xfd,0x0e,0x5c,0x3c,0x7a,0xf7,0x3a,0x26,0xd4,0x85,0x75,0x4d,0x14,0xe9,0xfe,0x11,0x7b,0xae,0xdf,0x3d,0x19,0xf7,0x59,0x80,0x70,0x06,0xa5,0x37,0x20,0x92,0x83,0x53,0x9a,0xf2,0x14,0xf5,0xd7,0xb2,0x25,0xdc,0x7e,0x71,0xdf,0x40,0x30,0xb5,0x99,0xdb,0x70,0xf9,0x21,0x62,0x4c,0xed,0xc3,0xb7,0x34,0x92,0xda,0x3e,0x09,0xee,0x7b,0x5c,0x36,0x72,0x5e}, - {0x7f,0x21,0x71,0x45,0x07,0xfc,0x5b,0x57,0x5b,0xd9,0x94,0x06,0x5d,0x67,0x79,0x37,0x33,0x1e,0x19,0xf4,0xbb,0x37,0x0a,0x9a,0xbc,0xea,0xb4,0x47,0x4c,0x10,0xf1,0x77,0x3e,0xb3,0x08,0x2f,0x06,0x39,0x93,0x7d,0xbe,0x32,0x9f,0xdf,0xe5,0x59,0x96,0x5b,0xfd,0xbd,0x9e,0x1f,0xad,0x3d,0xff,0xac,0xb7,0x49,0x73,0xcb,0x55,0x05,0xb2,0x70,0x4c,0x2c,0x11,0x55,0xc5,0x13,0x51,0xbe,0xcd,0x1f,0x88,0x9a,0x3a,0x42,0x88,0x66,0x47,0x3b,0x50,0x5e,0x85,0x77,0x66,0x44,0x4a,0x40,0x06,0x4a,0x8f,0x39,0x34,0x0e}, - {0xe8,0xbd,0xce,0x3e,0xd9,0x22,0x7d,0xb6,0x07,0x2f,0x82,0x27,0x41,0xe8,0xb3,0x09,0x8d,0x6d,0x5b,0xb0,0x1f,0xa6,0x3f,0x74,0x72,0x23,0x36,0x8a,0x36,0x05,0x54,0x5e,0x28,0x19,0x4b,0x3e,0x09,0x0b,0x93,0x18,0x40,0xf6,0xf3,0x73,0x0e,0xe1,0xe3,0x7d,0x6f,0x5d,0x39,0x73,0xda,0x17,0x32,0xf4,0x3e,0x9c,0x37,0xca,0xd6,0xde,0x8a,0x6f,0x9a,0xb2,0xb7,0xfd,0x3d,0x12,0x40,0xe3,0x91,0xb2,0x1a,0xa2,0xe1,0x97,0x7b,0x48,0x9e,0x94,0xe6,0xfd,0x02,0x7d,0x96,0xf9,0x97,0xde,0xd3,0xc8,0x2e,0xe7,0x0d,0x78}, - {0xbc,0xe7,0x9a,0x08,0x45,0x85,0xe2,0x0a,0x06,0x4d,0x7f,0x1c,0xcf,0xde,0x8d,0x38,0xb8,0x11,0x48,0x0a,0x51,0x15,0xac,0x38,0xe4,0x8c,0x92,0x71,0xf6,0x8b,0xb2,0x0e,0x72,0x27,0xf4,0x00,0xf3,0xea,0x1f,0x67,0xaa,0x41,0x8c,0x2a,0x2a,0xeb,0x72,0x8f,0x92,0x32,0x37,0x97,0xd7,0x7f,0xa1,0x29,0xa6,0x87,0xb5,0x32,0xad,0xc6,0xef,0x1d,0xa7,0x95,0x51,0xef,0x1a,0xbe,0x5b,0xaf,0xed,0x15,0x7b,0x91,0x77,0x12,0x8c,0x14,0x2e,0xda,0xe5,0x7a,0xfb,0xf7,0x91,0x29,0x67,0x28,0xdd,0xf8,0x1b,0x20,0x7d,0x46}, - {0xad,0x4f,0xef,0x74,0x9a,0x91,0xfe,0x95,0xa2,0x08,0xa3,0xf6,0xec,0x7b,0x82,0x3a,0x01,0x7b,0xa4,0x09,0xd3,0x01,0x4e,0x96,0x97,0xc7,0xa3,0x5b,0x4f,0x3c,0xc4,0x71,0xa9,0xe7,0x7a,0x56,0xbd,0xf4,0x1e,0xbc,0xbd,0x98,0x44,0xd6,0xb2,0x4c,0x62,0x3f,0xc8,0x4e,0x1f,0x2c,0xd2,0x64,0x10,0xe4,0x01,0x40,0x38,0xba,0xa5,0xc5,0xf9,0x2e,0xcd,0x74,0x9e,0xfa,0xf6,0x6d,0xfd,0xb6,0x7a,0x26,0xaf,0xe4,0xbc,0x78,0x82,0xf1,0x0e,0x99,0xef,0xf1,0xd0,0xb3,0x55,0x82,0x93,0xf2,0xc5,0x90,0xa3,0x8c,0x75,0x5a}, - {0x95,0x24,0x46,0xd9,0x10,0x27,0xb7,0xa2,0x03,0x50,0x7d,0xd5,0xd2,0xc6,0xa8,0x3a,0xca,0x87,0xb4,0xa0,0xbf,0x00,0xd4,0xe3,0xec,0x72,0xeb,0xb3,0x44,0xe2,0xba,0x2d,0x94,0xdc,0x61,0x1d,0x8b,0x91,0xe0,0x8c,0x66,0x30,0x81,0x9a,0x46,0x36,0xed,0x8d,0xd3,0xaa,0xe8,0xaf,0x29,0xa8,0xe6,0xd4,0x3f,0xd4,0x39,0xf6,0x27,0x80,0x73,0x0a,0xcc,0xe1,0xff,0x57,0x2f,0x4a,0x0f,0x98,0x43,0x98,0x83,0xe1,0x0d,0x0d,0x67,0x00,0xfd,0x15,0xfb,0x49,0x4a,0x3f,0x5c,0x10,0x9c,0xa6,0x26,0x51,0x63,0xca,0x98,0x26}, - {0x78,0xba,0xb0,0x32,0x88,0x31,0x65,0xe7,0x8b,0xff,0x5c,0x92,0xf7,0x31,0x18,0x38,0xcc,0x1f,0x29,0xa0,0x91,0x1b,0xa8,0x08,0x07,0xeb,0xca,0x49,0xcc,0x3d,0xb4,0x1f,0x0e,0xd9,0x3d,0x5e,0x2f,0x70,0x3d,0x2e,0x86,0x53,0xd2,0xe4,0x18,0x09,0x3f,0x9e,0x6a,0xa9,0x4d,0x02,0xf6,0x3e,0x77,0x5e,0x32,0x33,0xfa,0x4a,0x0c,0x4b,0x00,0x3c,0x2b,0xb8,0xf4,0x06,0xac,0x46,0xa9,0x9a,0xf3,0xc4,0x06,0xa8,0xa5,0x84,0xa2,0x1c,0x87,0x47,0xcd,0xc6,0x5f,0x26,0xd3,0x3e,0x17,0xd2,0x1f,0xcd,0x01,0xfd,0x43,0x6b}, - {0x44,0xc5,0x97,0x46,0x4b,0x5d,0xa7,0xc7,0xbf,0xff,0x0f,0xdf,0x48,0xf8,0xfd,0x15,0x5a,0x78,0x46,0xaa,0xeb,0xb9,0x68,0x28,0x14,0xf7,0x52,0x5b,0x10,0xd7,0x68,0x5a,0xf3,0x0e,0x76,0x3e,0x58,0x42,0xc7,0xb5,0x90,0xb9,0x0a,0xee,0xb9,0x52,0xdc,0x75,0x3f,0x92,0x2b,0x07,0xc2,0x27,0x14,0xbf,0xf0,0xd9,0xf0,0x6f,0x2d,0x0b,0x42,0x73,0x06,0x1e,0x85,0x9e,0xcb,0xf6,0x2c,0xaf,0xc4,0x38,0x22,0xc6,0x13,0x39,0x59,0x8f,0x73,0xf3,0xfb,0x99,0x96,0xb8,0x8a,0xda,0x9e,0xbc,0x34,0xea,0x2f,0x63,0xb5,0x3d}, - {0xd8,0xd9,0x5d,0xf7,0x2b,0xee,0x6e,0xf4,0xa5,0x59,0x67,0x39,0xf6,0xb1,0x17,0x0d,0x73,0x72,0x9e,0x49,0x31,0xd1,0xf2,0x1b,0x13,0x5f,0xd7,0x49,0xdf,0x1a,0x32,0x04,0xd5,0x25,0x98,0x82,0xb1,0x90,0x49,0x2e,0x91,0x89,0x9a,0x3e,0x87,0xeb,0xea,0xed,0xf8,0x4a,0x70,0x4c,0x39,0x3d,0xf0,0xee,0x0e,0x2b,0xdf,0x95,0xa4,0x7e,0x19,0x59,0xae,0x5a,0xe5,0xe4,0x19,0x60,0xe1,0x04,0xe9,0x92,0x2f,0x7e,0x7a,0x43,0x7b,0xe7,0xa4,0x9a,0x15,0x6f,0xc1,0x2d,0xce,0xc7,0xc0,0x0c,0xd7,0xf4,0xc1,0xfd,0xea,0x45}, - {0x2b,0xd7,0x45,0x80,0x85,0x01,0x84,0x69,0x51,0x06,0x2f,0xcf,0xa2,0xfa,0x22,0x4c,0xc6,0x2d,0x22,0x6b,0x65,0x36,0x1a,0x94,0xde,0xda,0x62,0x03,0xc8,0xeb,0x5e,0x5a,0xed,0xb1,0xcc,0xcf,0x24,0x46,0x0e,0xb6,0x95,0x03,0x5c,0xbd,0x92,0xc2,0xdb,0x59,0xc9,0x81,0x04,0xdc,0x1d,0x9d,0xa0,0x31,0x40,0xd9,0x56,0x5d,0xea,0xce,0x73,0x3f,0xc6,0x8d,0x4e,0x0a,0xd1,0xbf,0xa7,0xb7,0x39,0xb3,0xc9,0x44,0x7e,0x00,0x57,0xbe,0xfa,0xae,0x57,0x15,0x7f,0x20,0xc1,0x60,0xdb,0x18,0x62,0x26,0x91,0x88,0x05,0x26}, - {0x04,0xff,0x60,0x83,0xa6,0x04,0xf7,0x59,0xf4,0xe6,0x61,0x76,0xde,0x3f,0xd9,0xc3,0x51,0x35,0x87,0x12,0x73,0x2a,0x1b,0x83,0x57,0x5d,0x61,0x4e,0x2e,0x0c,0xad,0x54,0x42,0xe5,0x76,0xc6,0x3c,0x8e,0x81,0x4c,0xad,0xcc,0xce,0x03,0x93,0x2c,0x42,0x5e,0x08,0x9f,0x12,0xb4,0xca,0xcc,0x07,0xec,0xb8,0x43,0x44,0xb2,0x10,0xfa,0xed,0x0d,0x2a,0x52,0x2b,0xb8,0xd5,0x67,0x3b,0xee,0xeb,0xc1,0xa5,0x9f,0x46,0x63,0xf1,0x36,0xd3,0x9f,0xc1,0x6e,0xf2,0xd2,0xb4,0xa5,0x08,0x94,0x7a,0xa7,0xba,0xb2,0xec,0x62}, - {0x3d,0x2b,0x15,0x61,0x52,0x79,0xed,0xe5,0xd1,0xd7,0xdd,0x0e,0x7d,0x35,0x62,0x49,0x71,0x4c,0x6b,0xb9,0xd0,0xc8,0x82,0x74,0xbe,0xd8,0x66,0xa9,0x19,0xf9,0x59,0x2e,0x74,0x28,0xb6,0xaf,0x36,0x28,0x07,0x92,0xa5,0x04,0xe1,0x79,0x85,0x5e,0xcd,0x5f,0x4a,0xa1,0x30,0xc6,0xad,0x01,0xad,0x5a,0x98,0x3f,0x66,0x75,0x50,0x3d,0x91,0x61,0xda,0x31,0x32,0x1a,0x36,0x2d,0xc6,0x0d,0x70,0x02,0x20,0x94,0x32,0x58,0x47,0xfa,0xce,0x94,0x95,0x3f,0x51,0x01,0xd8,0x02,0x5c,0x5d,0xc0,0x31,0xa1,0xc2,0xdb,0x3d}, - {0x4b,0xc5,0x5e,0xce,0xf9,0x0f,0xdc,0x9a,0x0d,0x13,0x2f,0x8c,0x6b,0x2a,0x9c,0x03,0x15,0x95,0xf8,0xf0,0xc7,0x07,0x80,0x02,0x6b,0xb3,0x04,0xac,0x14,0x83,0x96,0x78,0x14,0xbb,0x96,0x27,0xa2,0x57,0xaa,0xf3,0x21,0xda,0x07,0x9b,0xb7,0xba,0x3a,0x88,0x1c,0x39,0xa0,0x31,0x18,0xe2,0x4b,0xe5,0xf9,0x05,0x32,0xd8,0x38,0xfb,0xe7,0x5e,0x8e,0x6a,0x44,0x41,0xcb,0xfd,0x8d,0x53,0xf9,0x37,0x49,0x43,0xa9,0xfd,0xac,0xa5,0x78,0x8c,0x3c,0x26,0x8d,0x90,0xaf,0x46,0x09,0x0d,0xca,0x9b,0x3c,0x63,0xd0,0x61}, - {0x66,0x25,0xdb,0xff,0x35,0x49,0x74,0x63,0xbb,0x68,0x0b,0x78,0x89,0x6b,0xbd,0xc5,0x03,0xec,0x3e,0x55,0x80,0x32,0x1b,0x6f,0xf5,0xd7,0xae,0x47,0xd8,0x5f,0x96,0x6e,0xdf,0x73,0xfc,0xf8,0xbc,0x28,0xa3,0xad,0xfc,0x37,0xf0,0xa6,0x5d,0x69,0x84,0xee,0x09,0xa9,0xc2,0x38,0xdb,0xb4,0x7f,0x63,0xdc,0x7b,0x06,0xf8,0x2d,0xac,0x23,0x5b,0x7b,0x52,0x80,0xee,0x53,0xb9,0xd2,0x9a,0x8d,0x6d,0xde,0xfa,0xaa,0x19,0x8f,0xe8,0xcf,0x82,0x0e,0x15,0x04,0x17,0x71,0x0e,0xdc,0xde,0x95,0xdd,0xb9,0xbb,0xb9,0x79}, - {0xc2,0x26,0x31,0x6a,0x40,0x55,0xb3,0xeb,0x93,0xc3,0xc8,0x68,0xa8,0x83,0x63,0xd2,0x82,0x7a,0xb9,0xe5,0x29,0x64,0x0c,0x6c,0x47,0x21,0xfd,0xc9,0x58,0xf1,0x65,0x50,0x74,0x73,0x9f,0x8e,0xae,0x7d,0x99,0xd1,0x16,0x08,0xbb,0xcf,0xf8,0xa2,0x32,0xa0,0x0a,0x5f,0x44,0x6d,0x12,0xba,0x6c,0xcd,0x34,0xb8,0xcc,0x0a,0x46,0x11,0xa8,0x1b,0x54,0x99,0x42,0x0c,0xfb,0x69,0x81,0x70,0x67,0xcf,0x6e,0xd7,0xac,0x00,0x46,0xe1,0xba,0x45,0xe6,0x70,0x8a,0xb9,0xaa,0x2e,0xf2,0xfa,0xa4,0x58,0x9e,0xf3,0x81,0x39}, - {0x93,0x0a,0x23,0x59,0x75,0x8a,0xfb,0x18,0x5d,0xf4,0xe6,0x60,0x69,0x8f,0x16,0x1d,0xb5,0x3c,0xa9,0x14,0x45,0xa9,0x85,0x3a,0xfd,0xd0,0xac,0x05,0x37,0x08,0xdc,0x38,0xde,0x6f,0xe6,0x6d,0xa5,0xdf,0x45,0xc8,0x3a,0x48,0x40,0x2c,0x00,0xa5,0x52,0xe1,0x32,0xf6,0xb4,0xc7,0x63,0xe1,0xd2,0xe9,0x65,0x1b,0xbc,0xdc,0x2e,0x45,0xf4,0x30,0x40,0x97,0x75,0xc5,0x82,0x27,0x6d,0x85,0xcc,0xbe,0x9c,0xf9,0x69,0x45,0x13,0xfa,0x71,0x4e,0xea,0xc0,0x73,0xfc,0x44,0x88,0x69,0x24,0x3f,0x59,0x1a,0x9a,0x2d,0x63}, - {0xa6,0xcb,0x07,0xb8,0x15,0x6b,0xbb,0xf6,0xd7,0xf0,0x54,0xbc,0xdf,0xc7,0x23,0x18,0x0b,0x67,0x29,0x6e,0x03,0x97,0x1d,0xbb,0x57,0x4a,0xed,0x47,0x88,0xf4,0x24,0x0b,0xa7,0x84,0x0c,0xed,0x11,0xfd,0x09,0xbf,0x3a,0x69,0x9f,0x0d,0x81,0x71,0xf0,0x63,0x79,0x87,0xcf,0x57,0x2d,0x8c,0x90,0x21,0xa2,0x4b,0xf6,0x8a,0xf2,0x7d,0x5a,0x3a,0xc7,0xea,0x1b,0x51,0xbe,0xd4,0xda,0xdc,0xf2,0xcc,0x26,0xed,0x75,0x80,0x53,0xa4,0x65,0x9a,0x5f,0x00,0x9f,0xff,0x9c,0xe1,0x63,0x1f,0x48,0x75,0x44,0xf7,0xfc,0x34}, - {0xca,0x67,0x97,0x78,0x4c,0xe0,0x97,0xc1,0x7d,0x46,0xd9,0x38,0xcb,0x4d,0x71,0xb8,0xa8,0x5f,0xf9,0x83,0x82,0x88,0xde,0x55,0xf7,0x63,0xfa,0x4d,0x16,0xdc,0x3b,0x3d,0x98,0xaa,0xcf,0x78,0xab,0x1d,0xbb,0xa5,0xf2,0x72,0x0b,0x19,0x67,0xa2,0xed,0x5c,0x8e,0x60,0x92,0x0a,0x11,0xc9,0x09,0x93,0xb0,0x74,0xb3,0x2f,0x04,0xa3,0x19,0x01,0x7d,0x17,0xc2,0xe8,0x9c,0xd8,0xa2,0x67,0xc1,0xd0,0x95,0x68,0xf6,0xa5,0x9d,0x66,0xb0,0xa2,0x82,0xb2,0xe5,0x98,0x65,0xf5,0x73,0x0a,0xe2,0xed,0xf1,0x88,0xc0,0x56}, - {0x17,0x6e,0xa8,0x10,0x11,0x3d,0x6d,0x33,0xfa,0xb2,0x75,0x0b,0x32,0x88,0xf3,0xd7,0x88,0x29,0x07,0x25,0x76,0x33,0x15,0xf9,0x87,0x8b,0x10,0x99,0x6b,0x4c,0x67,0x09,0x02,0x8f,0xf3,0x24,0xac,0x5f,0x1b,0x58,0xbd,0x0c,0xe3,0xba,0xfe,0xe9,0x0b,0xa9,0xf0,0x92,0xcf,0x8a,0x02,0x69,0x21,0x9a,0x8f,0x03,0x59,0x83,0xa4,0x7e,0x8b,0x03,0xf8,0x6f,0x31,0x99,0x21,0xf8,0x4e,0x9f,0x4f,0x8d,0xa7,0xea,0x82,0xd2,0x49,0x2f,0x74,0x31,0xef,0x5a,0xab,0xa5,0x71,0x09,0x65,0xeb,0x69,0x59,0x02,0x31,0x5e,0x6e}, - {0xfb,0x93,0xe5,0x87,0xf5,0x62,0x6c,0xb1,0x71,0x3e,0x5d,0xca,0xde,0xed,0x99,0x49,0x6d,0x3e,0xcc,0x14,0xe0,0xc1,0x91,0xb4,0xa8,0xdb,0xa8,0x89,0x47,0x11,0xf5,0x08,0x22,0x62,0x06,0x63,0x0e,0xfb,0x04,0x33,0x3f,0xba,0xac,0x87,0x89,0x06,0x35,0xfb,0xa3,0x61,0x10,0x8c,0x77,0x24,0x19,0xbd,0x20,0x86,0x83,0xd1,0x43,0xad,0x58,0x30,0xd0,0x63,0x76,0xe5,0xfd,0x0f,0x3c,0x32,0x10,0xa6,0x2e,0xa2,0x38,0xdf,0xc3,0x05,0x9a,0x4f,0x99,0xac,0xbd,0x8a,0xc7,0xbd,0x99,0xdc,0xe3,0xef,0xa4,0x9f,0x54,0x26}, - {0xd6,0xf9,0x6b,0x1e,0x46,0x5a,0x1d,0x74,0x81,0xa5,0x77,0x77,0xfc,0xb3,0x05,0x23,0xd9,0xd3,0x74,0x64,0xa2,0x74,0x55,0xd4,0xff,0xe0,0x01,0x64,0xdc,0xe1,0x26,0x19,0x6e,0x66,0x3f,0xaf,0x49,0x85,0x46,0xdb,0xa5,0x0e,0x4a,0xf1,0x04,0xcf,0x7f,0xd7,0x47,0x0c,0xba,0xa4,0xf7,0x3f,0xf2,0x3d,0x85,0x3c,0xce,0x32,0xe1,0xdf,0x10,0x3a,0xa0,0xce,0x17,0xea,0x8a,0x4e,0x7f,0xe0,0xfd,0xc1,0x1f,0x3a,0x46,0x15,0xd5,0x2f,0xf1,0xc0,0xf2,0x31,0xfd,0x22,0x53,0x17,0x15,0x5d,0x1e,0x86,0x1d,0xd0,0xa1,0x1f}, - {0x32,0x98,0x59,0x7d,0x94,0x55,0x80,0xcc,0x20,0x55,0xf1,0x37,0xda,0x56,0x46,0x1e,0x20,0x93,0x05,0x4e,0x74,0xf7,0xf6,0x99,0x33,0xcf,0x75,0x6a,0xbc,0x63,0x35,0x77,0xab,0x94,0xdf,0xd1,0x00,0xac,0xdc,0x38,0xe9,0x0d,0x08,0xd1,0xdd,0x2b,0x71,0x2e,0x62,0xe2,0xd5,0xfd,0x3e,0xe9,0x13,0x7f,0xe5,0x01,0x9a,0xee,0x18,0xed,0xfc,0x73,0xb3,0x9c,0x13,0x63,0x08,0xe9,0xb1,0x06,0xcd,0x3e,0xa0,0xc5,0x67,0xda,0x93,0xa4,0x32,0x89,0x63,0xad,0xc8,0xce,0x77,0x8d,0x44,0x4f,0x86,0x1b,0x70,0x6b,0x42,0x1f}, - {0x01,0x1c,0x91,0x41,0x4c,0x26,0xc9,0xef,0x25,0x2c,0xa2,0x17,0xb8,0xb7,0xa3,0xf1,0x47,0x14,0x0f,0xf3,0x6b,0xda,0x75,0x58,0x90,0xb0,0x31,0x1d,0x27,0xf5,0x1a,0x4e,0x52,0x25,0xa1,0x91,0xc8,0x35,0x7e,0xf1,0x76,0x9c,0x5e,0x57,0x53,0x81,0x6b,0xb7,0x3e,0x72,0x9b,0x0d,0x6f,0x40,0x83,0xfa,0x38,0xe4,0xa7,0x3f,0x1b,0xbb,0x76,0x0b,0x9b,0x93,0x92,0x7f,0xf9,0xc1,0xb8,0x08,0x6e,0xab,0x44,0xd4,0xcb,0x71,0x67,0xbe,0x17,0x80,0xbb,0x99,0x63,0x64,0xe5,0x22,0x55,0xa9,0x72,0xb7,0x1e,0xd6,0x6d,0x7b}, - {0x92,0x3d,0xf3,0x50,0xe8,0xc1,0xad,0xb7,0xcf,0xd5,0x8c,0x60,0x4f,0xfa,0x98,0x79,0xdb,0x5b,0xfc,0x8d,0xbd,0x2d,0x96,0xad,0x4f,0x2f,0x1d,0xaf,0xce,0x9b,0x3e,0x70,0xc7,0xd2,0x01,0xab,0xf9,0xab,0x30,0x57,0x18,0x3b,0x14,0x40,0xdc,0x76,0xfb,0x16,0x81,0xb2,0xcb,0xa0,0x65,0xbe,0x6c,0x86,0xfe,0x6a,0xff,0x9b,0x65,0x9b,0xfa,0x53,0x55,0x54,0x88,0x94,0xe9,0xc8,0x14,0x6c,0xe5,0xd4,0xae,0x65,0x66,0x5d,0x3a,0x84,0xf1,0x5a,0xd6,0xbc,0x3e,0xb7,0x1b,0x18,0x50,0x1f,0xc6,0xc4,0xe5,0x93,0x8d,0x39}, - {0xf3,0x48,0xe2,0x33,0x67,0xd1,0x4b,0x1c,0x5f,0x0a,0xbf,0x15,0x87,0x12,0x9e,0xbd,0x76,0x03,0x0b,0xa1,0xf0,0x8c,0x3f,0xd4,0x13,0x1b,0x19,0xdf,0x5d,0x9b,0xb0,0x53,0xf2,0xe3,0xe7,0xd2,0x60,0x7c,0x87,0xc3,0xb1,0x8b,0x82,0x30,0xa0,0xaa,0x34,0x3b,0x38,0xf1,0x9e,0x73,0xe7,0x26,0x3e,0x28,0x77,0x05,0xc3,0x02,0x90,0x9c,0x9c,0x69,0xcc,0xf1,0x46,0x59,0x23,0xa7,0x06,0xf3,0x7d,0xd9,0xe5,0xcc,0xb5,0x18,0x17,0x92,0x75,0xe9,0xb4,0x81,0x47,0xd2,0xcd,0x28,0x07,0xd9,0xcd,0x6f,0x0c,0xf3,0xca,0x51}, - {0x0a,0xe0,0x74,0x76,0x42,0xa7,0x0b,0xa6,0xf3,0x7b,0x7a,0xa1,0x70,0x85,0x0e,0x63,0xcc,0x24,0x33,0xcf,0x3d,0x56,0x58,0x37,0xaa,0xfd,0x83,0x23,0x29,0xaa,0x04,0x55,0xc7,0x54,0xac,0x18,0x9a,0xf9,0x7a,0x73,0x0f,0xb3,0x1c,0xc5,0xdc,0x78,0x33,0x90,0xc7,0x0c,0xe1,0x4c,0x33,0xbc,0x89,0x2b,0x9a,0xe9,0xf8,0x89,0xc1,0x29,0xae,0x12,0xcf,0x01,0x0d,0x1f,0xcb,0xc0,0x9e,0xa9,0xae,0xf7,0x34,0x3a,0xcc,0xef,0xd1,0x0d,0x22,0x4e,0x9c,0xd0,0x21,0x75,0xca,0x55,0xea,0xa5,0xeb,0x58,0xe9,0x4f,0xd1,0x5f}, - {0x2c,0xab,0x45,0x28,0xdf,0x2d,0xdc,0xb5,0x93,0xe9,0x7f,0x0a,0xb1,0x91,0x94,0x06,0x46,0xe3,0x02,0x40,0xd6,0xf3,0xaa,0x4d,0xd1,0x74,0x64,0x58,0x6e,0xf2,0x3f,0x09,0x8e,0xcb,0x93,0xbf,0x5e,0xfe,0x42,0x3c,0x5f,0x56,0xd4,0x36,0x51,0xa8,0xdf,0xbe,0xe8,0x20,0x42,0x88,0x9e,0x85,0xf0,0xe0,0x28,0xd1,0x25,0x07,0x96,0x3f,0xd7,0x7d,0x29,0x98,0x05,0x68,0xfe,0x24,0x0d,0xb1,0xe5,0x23,0xaf,0xdb,0x72,0x06,0x73,0x75,0x29,0xac,0x57,0xb4,0x3a,0x25,0x67,0x13,0xa4,0x70,0xb4,0x86,0xbc,0xbc,0x59,0x2f}, - {0x5f,0x13,0x17,0x99,0x42,0x7d,0x84,0x83,0xd7,0x03,0x7d,0x56,0x1f,0x91,0x1b,0xad,0xd1,0xaa,0x77,0xbe,0xd9,0x48,0x77,0x7e,0x4a,0xaf,0x51,0x2e,0x2e,0xb4,0x58,0x54,0x01,0xc3,0x91,0xb6,0x60,0xd5,0x41,0x70,0x1e,0xe7,0xd7,0xad,0x3f,0x1b,0x20,0x85,0x85,0x55,0x33,0x11,0x63,0xe1,0xc2,0x16,0xb1,0x28,0x08,0x01,0x3d,0x5e,0xa5,0x2a,0x4f,0x44,0x07,0x0c,0xe6,0x92,0x51,0xed,0x10,0x1d,0x42,0x74,0x2d,0x4e,0xc5,0x42,0x64,0xc8,0xb5,0xfd,0x82,0x4c,0x2b,0x35,0x64,0x86,0x76,0x8a,0x4a,0x00,0xe9,0x13}, - {0xdb,0xce,0x2f,0x83,0x45,0x88,0x9d,0x73,0x63,0xf8,0x6b,0xae,0xc9,0xd6,0x38,0xfa,0xf7,0xfe,0x4f,0xb7,0xca,0x0d,0xbc,0x32,0x5e,0xe4,0xbc,0x14,0x88,0x7e,0x93,0x73,0x7f,0x87,0x3b,0x19,0xc9,0x00,0x2e,0xbb,0x6b,0x50,0xdc,0xe0,0x90,0xa8,0xe3,0xec,0x9f,0x64,0xde,0x36,0xc0,0xb7,0xf3,0xec,0x1a,0x9e,0xde,0x98,0x08,0x04,0x46,0x5f,0x8d,0xf4,0x7b,0x29,0x16,0x71,0x03,0xb9,0x34,0x68,0xf0,0xd4,0x22,0x3b,0xd1,0xa9,0xc6,0xbd,0x96,0x46,0x57,0x15,0x97,0xe1,0x35,0xe8,0xd5,0x91,0xe8,0xa4,0xf8,0x2c}, - {0x67,0x0f,0x11,0x07,0x87,0xfd,0x93,0x6d,0x49,0xb5,0x38,0x7c,0xd3,0x09,0x4c,0xdd,0x86,0x6a,0x73,0xc2,0x4c,0x6a,0xb1,0x7c,0x09,0x2a,0x25,0x58,0x6e,0xbd,0x49,0x20,0xa2,0x6b,0xd0,0x17,0x7e,0x48,0xb5,0x2c,0x6b,0x19,0x50,0x39,0x1c,0x38,0xd2,0x24,0x30,0x8a,0x97,0x85,0x81,0x9c,0x65,0xd7,0xf6,0xa4,0xd6,0x91,0x28,0x7f,0x6f,0x7a,0x49,0xef,0x9a,0x6a,0x8d,0xfd,0x09,0x7d,0x0b,0xb9,0x3d,0x5b,0xbe,0x60,0xee,0xf0,0xd4,0xbf,0x9e,0x51,0x2c,0xb5,0x21,0x4c,0x1d,0x94,0x45,0xc5,0xdf,0xaa,0x11,0x60}, - {0x3c,0xf8,0x95,0xcf,0x6d,0x92,0x67,0x5f,0x71,0x90,0x28,0x71,0x61,0x85,0x7e,0x7c,0x5b,0x7a,0x8f,0x99,0xf3,0xe7,0xa1,0xd6,0xe0,0xf9,0x62,0x0b,0x1b,0xcc,0xc5,0x6f,0x90,0xf8,0xcb,0x02,0xc8,0xd0,0xde,0x63,0xaa,0x6a,0xff,0x0d,0xca,0x98,0xd0,0xfb,0x99,0xed,0xb6,0xb9,0xfd,0x0a,0x4d,0x62,0x1e,0x0b,0x34,0x79,0xb7,0x18,0xce,0x69,0xcb,0x79,0x98,0xb2,0x28,0x55,0xef,0xd1,0x92,0x90,0x7e,0xd4,0x3c,0xae,0x1a,0xdd,0x52,0x23,0x9f,0x18,0x42,0x04,0x7e,0x12,0xf1,0x01,0x71,0xe5,0x3a,0x6b,0x59,0x15}, - {0xa2,0x79,0x91,0x3f,0xd2,0x39,0x27,0x46,0xcf,0xdd,0xd6,0x97,0x31,0x12,0x83,0xff,0x8a,0x14,0xf2,0x53,0xb5,0xde,0x07,0x13,0xda,0x4d,0x5f,0x7b,0x68,0x37,0x22,0x0d,0xca,0x24,0x51,0x7e,0x16,0x31,0xff,0x09,0xdf,0x45,0xc7,0xd9,0x8b,0x15,0xe4,0x0b,0xe5,0x56,0xf5,0x7e,0x22,0x7d,0x2b,0x29,0x38,0xd1,0xb6,0xaf,0x41,0xe2,0xa4,0x3a,0xf5,0x05,0x33,0x2a,0xbf,0x38,0xc1,0x2c,0xc3,0x26,0xe9,0xa2,0x8f,0x3f,0x58,0x48,0xeb,0xd2,0x49,0x55,0xa2,0xb1,0x3a,0x08,0x6c,0xa3,0x87,0x46,0x6e,0xaa,0xfc,0x32}, - {0xf5,0x9a,0x7d,0xc5,0x8d,0x6e,0xc5,0x7b,0xf2,0xbd,0xf0,0x9d,0xed,0xd2,0x0b,0x3e,0xa3,0xe4,0xef,0x22,0xde,0x14,0xc0,0xaa,0x5c,0x6a,0xbd,0xfe,0xce,0xe9,0x27,0x46,0xdf,0xcc,0x87,0x27,0x73,0xa4,0x07,0x32,0xf8,0xe3,0x13,0xf2,0x08,0x19,0xe3,0x17,0x4e,0x96,0x0d,0xf6,0xd7,0xec,0xb2,0xd5,0xe9,0x0b,0x60,0xc2,0x36,0x63,0x6f,0x74,0x1c,0x97,0x6c,0xab,0x45,0xf3,0x4a,0x3f,0x1f,0x73,0x43,0x99,0x72,0xeb,0x88,0xe2,0x6d,0x18,0x44,0x03,0x8a,0x6a,0x59,0x33,0x93,0x62,0xd6,0x7e,0x00,0x17,0x49,0x7b}, - {0x64,0xb0,0x84,0xab,0x5c,0xfb,0x85,0x2d,0x14,0xbc,0xf3,0x89,0xd2,0x10,0x78,0x49,0x0c,0xce,0x15,0x7b,0x44,0xdc,0x6a,0x47,0x7b,0xfd,0x44,0xf8,0x76,0xa3,0x2b,0x12,0xdd,0xa2,0x53,0xdd,0x28,0x1b,0x34,0x54,0x3f,0xfc,0x42,0xdf,0x5b,0x90,0x17,0xaa,0xf4,0xf8,0xd2,0x4d,0xd9,0x92,0xf5,0x0f,0x7d,0xd3,0x8c,0xe0,0x0f,0x62,0x03,0x1d,0x54,0xe5,0xb4,0xa2,0xcd,0x32,0x02,0xc2,0x7f,0x18,0x5d,0x11,0x42,0xfd,0xd0,0x9e,0xd9,0x79,0xd4,0x7d,0xbe,0xb4,0xab,0x2e,0x4c,0xec,0x68,0x2b,0xf5,0x0b,0xc7,0x02}, - {0xbb,0x2f,0x0b,0x5d,0x4b,0xec,0x87,0xa2,0xca,0x82,0x48,0x07,0x90,0x57,0x5c,0x41,0x5c,0x81,0xd0,0xc1,0x1e,0xa6,0x44,0xe0,0xe0,0xf5,0x9e,0x40,0x0a,0x4f,0x33,0x26,0xe1,0x72,0x8d,0x45,0xbf,0x32,0xe5,0xac,0xb5,0x3c,0xb7,0x7c,0xe0,0x68,0xe7,0x5b,0xe7,0xbd,0x8b,0xee,0x94,0x7d,0xcf,0x56,0x03,0x3a,0xb4,0xfe,0xe3,0x97,0x06,0x6b,0xc0,0xa3,0x62,0xdf,0x4a,0xf0,0xc8,0xb6,0x5d,0xa4,0x6d,0x07,0xef,0x00,0xf0,0x3e,0xa9,0xd2,0xf0,0x49,0x58,0xb9,0x9c,0x9c,0xae,0x2f,0x1b,0x44,0x43,0x7f,0xc3,0x1c}, - {0x4f,0x32,0xc7,0x5c,0x5a,0x56,0x8f,0x50,0x22,0xa9,0x06,0xe5,0xc0,0xc4,0x61,0xd0,0x19,0xac,0x45,0x5c,0xdb,0xab,0x18,0xfb,0x4a,0x31,0x80,0x03,0xc1,0x09,0x68,0x6c,0xb9,0xae,0xce,0xc9,0xf1,0x56,0x66,0xd7,0x6a,0x65,0xe5,0x18,0xf8,0x15,0x5b,0x1c,0x34,0x23,0x4c,0x84,0x32,0x28,0xe7,0x26,0x38,0x68,0x19,0x2f,0x77,0x6f,0x34,0x3a,0xc8,0x6a,0xda,0xe2,0x12,0x51,0xd5,0xd2,0xed,0x51,0xe8,0xb1,0x31,0x03,0xbd,0xe9,0x62,0x72,0xc6,0x8e,0xdd,0x46,0x07,0x96,0xd0,0xc5,0xf7,0x6e,0x9f,0x1b,0x91,0x05}, - {0xbb,0x0e,0xdf,0xf5,0x83,0x99,0x33,0xc1,0xac,0x4c,0x2c,0x51,0x8f,0x75,0xf3,0xc0,0xe1,0x98,0xb3,0x0b,0x0a,0x13,0xf1,0x2c,0x62,0x0c,0x27,0xaa,0xf9,0xec,0x3c,0x6b,0xef,0xea,0x2e,0x51,0xf3,0xac,0x49,0x53,0x49,0xcb,0xc1,0x1c,0xd3,0x41,0xc1,0x20,0x8d,0x68,0x9a,0xa9,0x07,0x0c,0x18,0x24,0x17,0x2d,0x4b,0xc6,0xd1,0xf9,0x5e,0x55,0x08,0xbd,0x73,0x3b,0xba,0x70,0xa7,0x36,0x0c,0xbf,0xaf,0xa3,0x08,0xef,0x4a,0x62,0xf2,0x46,0x09,0xb4,0x98,0xff,0x37,0x57,0x9d,0x74,0x81,0x33,0xe1,0x4d,0x5f,0x67}, - {0xfc,0x82,0x17,0x6b,0x03,0x52,0x2c,0x0e,0xb4,0x83,0xad,0x6c,0x81,0x6c,0x81,0x64,0x3e,0x07,0x64,0x69,0xd9,0xbd,0xdc,0xd0,0x20,0xc5,0x64,0x01,0xf7,0x9d,0xd9,0x13,0x1d,0xb3,0xda,0x3b,0xd9,0xf6,0x2f,0xa1,0xfe,0x2d,0x65,0x9d,0x0f,0xd8,0x25,0x07,0x87,0x94,0xbe,0x9a,0xf3,0x4f,0x9c,0x01,0x43,0x3c,0xcd,0x82,0xb8,0x50,0xf4,0x60,0xca,0xc0,0xe5,0x21,0xc3,0x5e,0x4b,0x01,0xa2,0xbf,0x19,0xd7,0xc9,0x69,0xcb,0x4f,0xa0,0x23,0x00,0x75,0x18,0x1c,0x5f,0x4e,0x80,0xac,0xed,0x55,0x9e,0xde,0x06,0x1c}, - {0xe2,0xc4,0x3e,0xa3,0xd6,0x7a,0x0f,0x99,0x8e,0xe0,0x2e,0xbe,0x38,0xf9,0x08,0x66,0x15,0x45,0x28,0x63,0xc5,0x43,0xa1,0x9c,0x0d,0xb6,0x2d,0xec,0x1f,0x8a,0xf3,0x4c,0xaa,0x69,0x6d,0xff,0x40,0x2b,0xd5,0xff,0xbb,0x49,0x40,0xdc,0x18,0x0b,0x53,0x34,0x97,0x98,0x4d,0xa3,0x2f,0x5c,0x4a,0x5e,0x2d,0xba,0x32,0x7d,0x8e,0x6f,0x09,0x78,0xe7,0x5c,0xfa,0x0d,0x65,0xaa,0xaa,0xa0,0x8c,0x47,0xb5,0x48,0x2a,0x9e,0xc4,0xf9,0x5b,0x72,0x03,0x70,0x7d,0xcc,0x09,0x4f,0xbe,0x1a,0x09,0x26,0x3a,0xad,0x3c,0x37}, - {0x7c,0xf5,0xc9,0x82,0x4d,0x63,0x94,0xb2,0x36,0x45,0x93,0x24,0xe1,0xfd,0xcb,0x1f,0x5a,0xdb,0x8c,0x41,0xb3,0x4d,0x9c,0x9e,0xfc,0x19,0x44,0x45,0xd9,0xf3,0x40,0x00,0xad,0xbb,0xdd,0x89,0xfb,0xa8,0xbe,0xf1,0xcb,0xae,0xae,0x61,0xbc,0x2c,0xcb,0x3b,0x9d,0x8d,0x9b,0x1f,0xbb,0xa7,0x58,0x8f,0x86,0xa6,0x12,0x51,0xda,0x7e,0x54,0x21,0xd3,0x86,0x59,0xfd,0x39,0xe9,0xfd,0xde,0x0c,0x38,0x0a,0x51,0x89,0x2c,0x27,0xf4,0xb9,0x19,0x31,0xbb,0x07,0xa4,0x2b,0xb7,0xf4,0x4d,0x25,0x4a,0x33,0x0a,0x55,0x63}, - {0x37,0xcf,0x69,0xb5,0xed,0xd6,0x07,0x65,0xe1,0x2e,0xa5,0x0c,0xb0,0x29,0x84,0x17,0x5d,0xd6,0x6b,0xeb,0x90,0x00,0x7c,0xea,0x51,0x8f,0xf7,0xda,0xc7,0x62,0xea,0x3e,0x49,0x7b,0x54,0x72,0x45,0x58,0xba,0x9b,0xe0,0x08,0xc4,0xe2,0xfa,0xc6,0x05,0xf3,0x8d,0xf1,0x34,0xc7,0x69,0xfa,0xe8,0x60,0x7a,0x76,0x7d,0xaa,0xaf,0x2b,0xa9,0x39,0x4e,0x27,0x93,0xe6,0x13,0xc7,0x24,0x9d,0x75,0xd3,0xdb,0x68,0x77,0x85,0x63,0x5f,0x9a,0xb3,0x8a,0xeb,0x60,0x55,0x52,0x70,0xcd,0xc4,0xc9,0x65,0x06,0x6a,0x43,0x68}, - {0x27,0x3f,0x2f,0x20,0xe8,0x35,0x02,0xbc,0xb0,0x75,0xf9,0x64,0xe2,0x00,0x5c,0xc7,0x16,0x24,0x8c,0xa3,0xd5,0xe9,0xa4,0x91,0xf9,0x89,0xb7,0x8a,0xf6,0xe7,0xb6,0x17,0x7c,0x10,0x20,0xe8,0x17,0xd3,0x56,0x1e,0x65,0xe9,0x0a,0x84,0x44,0x68,0x26,0xc5,0x7a,0xfc,0x0f,0x32,0xc6,0xa1,0xe0,0xc1,0x72,0x14,0x61,0x91,0x9c,0x66,0x73,0x53,0x57,0x52,0x0e,0x9a,0xab,0x14,0x28,0x5d,0xfc,0xb3,0xca,0xc9,0x84,0x20,0x8f,0x90,0xca,0x1e,0x2d,0x5b,0x88,0xf5,0xca,0xaf,0x11,0x7d,0xf8,0x78,0xa6,0xb5,0xb4,0x1c}, - {0x6c,0xfc,0x4a,0x39,0x6b,0xc0,0x64,0xb6,0xb1,0x5f,0xda,0x98,0x24,0xde,0x88,0x0c,0x34,0xd8,0xca,0x4b,0x16,0x03,0x8d,0x4f,0xa2,0x34,0x74,0xde,0x78,0xca,0x0b,0x33,0xe7,0x07,0xa0,0xa2,0x62,0xaa,0x74,0x6b,0xb1,0xc7,0x71,0xf0,0xb0,0xe0,0x11,0xf3,0x23,0xe2,0x0b,0x00,0x38,0xe4,0x07,0x57,0xac,0x6e,0xef,0x82,0x2d,0xfd,0xc0,0x2d,0x4e,0x74,0x19,0x11,0x84,0xff,0x2e,0x98,0x24,0x47,0x07,0x2b,0x96,0x5e,0x69,0xf9,0xfb,0x53,0xc9,0xbf,0x4f,0xc1,0x8a,0xc5,0xf5,0x1c,0x9f,0x36,0x1b,0xbe,0x31,0x3c}, - {0xee,0x8a,0x94,0x08,0x4d,0x86,0xf4,0xb0,0x6f,0x1c,0xba,0x91,0xee,0x19,0xdc,0x07,0x58,0xa1,0xac,0xa6,0xae,0xcd,0x75,0x79,0xbb,0xd4,0x62,0x42,0x13,0x61,0x0b,0x33,0x72,0x42,0xcb,0xf9,0x93,0xbc,0x68,0xc1,0x98,0xdb,0xce,0xc7,0x1f,0x71,0xb8,0xae,0x7a,0x8d,0xac,0x34,0xaa,0x52,0x0e,0x7f,0xbb,0x55,0x7d,0x7e,0x09,0xc1,0xce,0x41,0x8a,0x80,0x6d,0xa2,0xd7,0x19,0x96,0xf7,0x6d,0x15,0x9e,0x1d,0x9e,0xd4,0x1f,0xbb,0x27,0xdf,0xa1,0xdb,0x6c,0xc3,0xd7,0x73,0x7d,0x77,0x28,0x1f,0xd9,0x4c,0xb4,0x26}, - {0x75,0x74,0x38,0x8f,0x47,0x48,0xf0,0x51,0x3c,0xcb,0xbe,0x9c,0xf4,0xbc,0x5d,0xb2,0x55,0x20,0x9f,0xd9,0x44,0x12,0xab,0x9a,0xd6,0xa5,0x10,0x1c,0x6c,0x9e,0x70,0x2c,0x83,0x03,0x73,0x62,0x93,0xf2,0xb7,0xe1,0x2c,0x8a,0xca,0xeb,0xff,0x79,0x52,0x4b,0x14,0x13,0xd4,0xbf,0x8a,0x77,0xfc,0xda,0x0f,0x61,0x72,0x9c,0x14,0x10,0xeb,0x7d,0x7a,0xee,0x66,0x87,0x6a,0xaf,0x62,0xcb,0x0e,0xcd,0x53,0x55,0x04,0xec,0xcb,0x66,0xb5,0xe4,0x0b,0x0f,0x38,0x01,0x80,0x58,0xea,0xe2,0x2c,0xf6,0x9f,0x8e,0xe6,0x08}, - {0xad,0x30,0xc1,0x4b,0x0a,0x50,0xad,0x34,0x9c,0xd4,0x0b,0x3d,0x49,0xdb,0x38,0x8d,0xbe,0x89,0x0a,0x50,0x98,0x3d,0x5c,0xa2,0x09,0x3b,0xba,0xee,0x87,0x3f,0x1f,0x2f,0xf9,0xf2,0xb8,0x0a,0xd5,0x09,0x2d,0x2f,0xdf,0x23,0x59,0xc5,0x8d,0x21,0xb9,0xac,0xb9,0x6c,0x76,0x73,0x26,0x34,0x8f,0x4a,0xf5,0x19,0xf7,0x38,0xd7,0x3b,0xb1,0x4c,0x4a,0xb6,0x15,0xe5,0x75,0x8c,0x84,0xf7,0x38,0x90,0x4a,0xdb,0xba,0x01,0x95,0xa5,0x50,0x1b,0x75,0x3f,0x3f,0x31,0x0d,0xc2,0xe8,0x2e,0xae,0xc0,0x53,0xe3,0xa1,0x19}, - {0xc3,0x05,0xfa,0xba,0x60,0x75,0x1c,0x7d,0x61,0x5e,0xe5,0xc6,0xa0,0xa0,0xe1,0xb3,0x73,0x64,0xd6,0xc0,0x18,0x97,0x52,0xe3,0x86,0x34,0x0c,0xc2,0x11,0x6b,0x54,0x41,0xbd,0xbd,0x96,0xd5,0xcd,0x72,0x21,0xb4,0x40,0xfc,0xee,0x98,0x43,0x45,0xe0,0x93,0xb5,0x09,0x41,0xb4,0x47,0x53,0xb1,0x9f,0x34,0xae,0x66,0x02,0x99,0xd3,0x6b,0x73,0xb4,0xb3,0x34,0x93,0x50,0x2d,0x53,0x85,0x73,0x65,0x81,0x60,0x4b,0x11,0xfd,0x46,0x75,0x83,0x5c,0x42,0x30,0x5f,0x5f,0xcc,0x5c,0xab,0x7f,0xb8,0xa2,0x95,0x22,0x41}, - {0xe9,0xd6,0x7e,0xf5,0x88,0x9b,0xc9,0x19,0x25,0xc8,0xf8,0x6d,0x26,0xcb,0x93,0x53,0x73,0xd2,0x0a,0xb3,0x13,0x32,0xee,0x5c,0x34,0x2e,0x2d,0xb5,0xeb,0x53,0xe1,0x14,0xc6,0xea,0x93,0xe2,0x61,0x52,0x65,0x2e,0xdb,0xac,0x33,0x21,0x03,0x92,0x5a,0x84,0x6b,0x99,0x00,0x79,0xcb,0x75,0x09,0x46,0x80,0xdd,0x5a,0x19,0x8d,0xbb,0x60,0x07,0x8a,0x81,0xe6,0xcd,0x17,0x1a,0x3e,0x41,0x84,0xa0,0x69,0xed,0xa9,0x6d,0x15,0x57,0xb1,0xcc,0xca,0x46,0x8f,0x26,0xbf,0x2c,0xf2,0xc5,0x3a,0xc3,0x9b,0xbe,0x34,0x6b}, - {0xb2,0xc0,0x78,0x3a,0x64,0x2f,0xdf,0xf3,0x7c,0x02,0x2e,0xf2,0x1e,0x97,0x3e,0x4c,0xa3,0xb5,0xc1,0x49,0x5e,0x1c,0x7d,0xec,0x2d,0xdd,0x22,0x09,0x8f,0xc1,0x12,0x20,0xd3,0xf2,0x71,0x65,0x65,0x69,0xfc,0x11,0x7a,0x73,0x0e,0x53,0x45,0xe8,0xc9,0xc6,0x35,0x50,0xfe,0xd4,0xa2,0xe7,0x3a,0xe3,0x0b,0xd3,0x6d,0x2e,0xb6,0xc7,0xb9,0x01,0x29,0x9d,0xc8,0x5a,0xe5,0x55,0x0b,0x88,0x63,0xa7,0xa0,0x45,0x1f,0x24,0x83,0x14,0x1f,0x6c,0xe7,0xc2,0xdf,0xef,0x36,0x3d,0xe8,0xad,0x4b,0x4e,0x78,0x5b,0xaf,0x08}, - {0x33,0x25,0x1f,0x88,0xdc,0x99,0x34,0x28,0xb6,0x23,0x93,0x77,0xda,0x25,0x05,0x9d,0xf4,0x41,0x34,0x67,0xfb,0xdd,0x7a,0x89,0x8d,0x16,0x3a,0x16,0x71,0x9d,0xb7,0x32,0x4b,0x2c,0xcc,0x89,0xd2,0x14,0x73,0xe2,0x8d,0x17,0x87,0xa2,0x11,0xbd,0xe4,0x4b,0xce,0x64,0x33,0xfa,0xd6,0x28,0xd5,0x18,0x6e,0x82,0xd9,0xaf,0xd5,0xc1,0x23,0x64,0x6a,0xb3,0xfc,0xed,0xd9,0xf8,0x85,0xcc,0xf9,0xe5,0x46,0x37,0x8f,0xc2,0xbc,0x22,0xcd,0xd3,0xe5,0xf9,0x38,0xe3,0x9d,0xe4,0xcc,0x2d,0x3e,0xc1,0xfb,0x5e,0x0a,0x48}, - {0x71,0x20,0x62,0x01,0x0b,0xe7,0x51,0x0b,0xc5,0xaf,0x1d,0x8b,0xcf,0x05,0xb5,0x06,0xcd,0xab,0x5a,0xef,0x61,0xb0,0x6b,0x2c,0x31,0xbf,0xb7,0x0c,0x60,0x27,0xaa,0x47,0x1f,0x22,0xce,0x42,0xe4,0x4c,0x61,0xb6,0x28,0x39,0x05,0x4c,0xcc,0x9d,0x19,0x6e,0x03,0xbe,0x1c,0xdc,0xa4,0xb4,0x3f,0x66,0x06,0x8e,0x1c,0x69,0x47,0x1d,0xb3,0x24,0xc3,0xf8,0x15,0xc0,0xed,0x1e,0x54,0x2a,0x7c,0x3f,0x69,0x7c,0x7e,0xfe,0xa4,0x11,0xd6,0x78,0xa2,0x4e,0x13,0x66,0xaf,0xf0,0x94,0xa0,0xdd,0x14,0x5d,0x58,0x5b,0x54}, - {0x0f,0x3a,0xd4,0xa0,0x5e,0x27,0xbf,0x67,0xbe,0xee,0x9b,0x08,0x34,0x8e,0xe6,0xad,0x2e,0xe7,0x79,0xd4,0x4c,0x13,0x89,0x42,0x54,0x54,0xba,0x32,0xc3,0xf9,0x62,0x0f,0xe1,0x21,0xb3,0xe3,0xd0,0xe4,0x04,0x62,0x95,0x1e,0xff,0x28,0x7a,0x63,0xaa,0x3b,0x9e,0xbd,0x99,0x5b,0xfd,0xcf,0x0c,0x0b,0x71,0xd0,0xc8,0x64,0x3e,0xdc,0x22,0x4d,0x39,0x5f,0x3b,0xd6,0x89,0x65,0xb4,0xfc,0x61,0xcf,0xcb,0x57,0x3f,0x6a,0xae,0x5c,0x05,0xfa,0x3a,0x95,0xd2,0xc2,0xba,0xfe,0x36,0x14,0x37,0x36,0x1a,0xa0,0x0f,0x1c}, - {0xff,0x3d,0x94,0x22,0xb6,0x04,0xc6,0xd2,0xa0,0xb3,0xcf,0x44,0xce,0xbe,0x8c,0xbc,0x78,0x86,0x80,0x97,0xf3,0x4f,0x25,0x5d,0xbf,0xa6,0x1c,0x3b,0x4f,0x61,0xa3,0x0f,0x50,0x6a,0x93,0x8c,0x0e,0x2b,0x08,0x69,0xb6,0xc5,0xda,0xc1,0x35,0xa0,0xc9,0xf9,0x34,0xb6,0xdf,0xc4,0x54,0x3e,0xb7,0x6f,0x40,0xc1,0x2b,0x1d,0x9b,0x41,0x05,0x40,0xf0,0x82,0xbe,0xb9,0xbd,0xfe,0x03,0xa0,0x90,0xac,0x44,0x3a,0xaf,0xc1,0x89,0x20,0x8e,0xfa,0x54,0x19,0x91,0x9f,0x49,0xf8,0x42,0xab,0x40,0xef,0x8a,0x21,0xba,0x1f}, - {0x3e,0xf5,0xc8,0xfa,0x48,0x94,0x54,0xab,0x41,0x37,0xa6,0x7b,0x9a,0xe8,0xf6,0x81,0x01,0x5e,0x2b,0x6c,0x7d,0x6c,0xfd,0x74,0x42,0x6e,0xc8,0xa8,0xca,0x3a,0x2e,0x39,0x94,0x01,0x7b,0x3e,0x04,0x57,0x3e,0x4f,0x7f,0xaf,0xda,0x08,0xee,0x3e,0x1d,0xa8,0xf1,0xde,0xdc,0x99,0xab,0xc6,0x39,0xc8,0xd5,0x61,0x77,0xff,0x13,0x5d,0x53,0x6c,0xaf,0x35,0x8a,0x3e,0xe9,0x34,0xbd,0x4c,0x16,0xe8,0x87,0x58,0x44,0x81,0x07,0x2e,0xab,0xb0,0x9a,0xf2,0x76,0x9c,0x31,0x19,0x3b,0xc1,0x0a,0xd5,0xe4,0x7f,0xe1,0x25}, - {0x76,0xf6,0x04,0x1e,0xd7,0x9b,0x28,0x0a,0x95,0x0f,0x42,0xd6,0x52,0x1c,0x8e,0x20,0xab,0x1f,0x69,0x34,0xb0,0xd8,0x86,0x51,0x51,0xb3,0x9f,0x2a,0x44,0x51,0x57,0x25,0xa7,0x21,0xf1,0x76,0xf5,0x7f,0x5f,0x91,0xe3,0x87,0xcd,0x2f,0x27,0x32,0x4a,0xc3,0x26,0xe5,0x1b,0x4d,0xde,0x2f,0xba,0xcc,0x9b,0x89,0x69,0x89,0x8f,0x82,0xba,0x6b,0x01,0x39,0xfe,0x90,0x66,0xbc,0xd1,0xe2,0xd5,0x7a,0x99,0xa0,0x18,0x4a,0xb5,0x4c,0xd4,0x60,0x84,0xaf,0x14,0x69,0x1d,0x97,0xe4,0x7b,0x6b,0x7f,0x4f,0x50,0x9d,0x55}, - {0xd5,0x54,0xeb,0xb3,0x78,0x83,0x73,0xa7,0x7c,0x3c,0x55,0xa5,0x66,0xd3,0x69,0x1d,0xba,0x00,0x28,0xf9,0x62,0xcf,0x26,0x0a,0x17,0x32,0x7e,0x80,0xd5,0x12,0xab,0x01,0xfd,0x66,0xd2,0xf6,0xe7,0x91,0x48,0x9c,0x1b,0x78,0x07,0x03,0x9b,0xa1,0x44,0x07,0x3b,0xe2,0x61,0x60,0x1d,0x8f,0x38,0x88,0x0e,0xd5,0x4b,0x35,0xa3,0xa6,0x3e,0x12,0x96,0x2d,0xe3,0x41,0x90,0x18,0x8d,0x11,0x48,0x58,0x31,0xd8,0xc2,0xe3,0xed,0xb9,0xd9,0x45,0x32,0xd8,0x71,0x42,0xab,0x1e,0x54,0xa1,0x18,0xc9,0xe2,0x61,0x39,0x4a}, - {0xa0,0xbb,0xe6,0xf8,0xe0,0x3b,0xdc,0x71,0x0a,0xe3,0xff,0x7e,0x34,0xf8,0xce,0xd6,0x6a,0x47,0x3a,0xe1,0x5f,0x42,0x92,0xa9,0x63,0xb7,0x1d,0xfb,0xe3,0xbc,0xd6,0x2c,0x1e,0x3f,0x23,0xf3,0x44,0xd6,0x27,0x03,0x16,0xf0,0xfc,0x34,0x0e,0x26,0x9a,0x49,0x79,0xb9,0xda,0xf2,0x16,0xa7,0xb5,0x83,0x1f,0x11,0xd4,0x9b,0xad,0xee,0xac,0x68,0x10,0xc2,0xd7,0xf3,0x0e,0xc9,0xb4,0x38,0x0c,0x04,0xad,0xb7,0x24,0x6e,0x8e,0x30,0x23,0x3e,0xe7,0xb7,0xf1,0xd9,0x60,0x38,0x97,0xf5,0x08,0xb5,0xd5,0x60,0x57,0x59}, - {0x97,0x63,0xaa,0x04,0xe1,0xbf,0x29,0x61,0xcb,0xfc,0xa7,0xa4,0x08,0x00,0x96,0x8f,0x58,0x94,0x90,0x7d,0x89,0xc0,0x8b,0x3f,0xa9,0x91,0xb2,0xdc,0x3e,0xa4,0x9f,0x70,0x90,0x27,0x02,0xfd,0xeb,0xcb,0x2a,0x88,0x60,0x57,0x11,0xc4,0x05,0x33,0xaf,0x89,0xf4,0x73,0x34,0x7d,0xe3,0x92,0xf4,0x65,0x2b,0x5a,0x51,0x54,0xdf,0xc5,0xb2,0x2c,0xca,0x2a,0xfd,0x63,0x8c,0x5d,0x0a,0xeb,0xff,0x4e,0x69,0x2e,0x66,0xc1,0x2b,0xd2,0x3a,0xb0,0xcb,0xf8,0x6e,0xf3,0x23,0x27,0x1f,0x13,0xc8,0xf0,0xec,0x29,0xf0,0x70}, - {0x33,0x3e,0xed,0x2e,0xb3,0x07,0x13,0x46,0xe7,0x81,0x55,0xa4,0x33,0x2f,0x04,0xae,0x66,0x03,0x5f,0x19,0xd3,0x49,0x44,0xc9,0x58,0x48,0x31,0x6c,0x8a,0x5d,0x7d,0x0b,0xb9,0xb0,0x10,0x5e,0xaa,0xaf,0x6a,0x2a,0xa9,0x1a,0x04,0xef,0x70,0xa3,0xf0,0x78,0x1f,0xd6,0x3a,0xaa,0x77,0xfb,0x3e,0x77,0xe1,0xd9,0x4b,0xa7,0xa2,0xa5,0xec,0x44,0x43,0xd5,0x95,0x7b,0x32,0x48,0xd4,0x25,0x1d,0x0f,0x34,0xa3,0x00,0x83,0xd3,0x70,0x2b,0xc5,0xe1,0x60,0x1c,0x53,0x1c,0xde,0xe4,0xe9,0x7d,0x2c,0x51,0x24,0x22,0x27}, - {0x2e,0x34,0xc5,0x49,0xaf,0x92,0xbc,0x1a,0xd0,0xfa,0xe6,0xb2,0x11,0xd8,0xee,0xff,0x29,0x4e,0xc8,0xfc,0x8d,0x8c,0xa2,0xef,0x43,0xc5,0x4c,0xa4,0x18,0xdf,0xb5,0x11,0xfc,0x75,0xa9,0x42,0x8a,0xbb,0x7b,0xbf,0x58,0xa3,0xad,0x96,0x77,0x39,0x5c,0x8c,0x48,0xaa,0xed,0xcd,0x6f,0xc7,0x7f,0xe2,0xa6,0x20,0xbc,0xf6,0xd7,0x5f,0x73,0x19,0x66,0x42,0xc8,0x42,0xd0,0x90,0xab,0xe3,0x7e,0x54,0x19,0x7f,0x0f,0x8e,0x84,0xeb,0xb9,0x97,0xa4,0x65,0xd0,0xa1,0x03,0x25,0x5f,0x89,0xdf,0x91,0x11,0x91,0xef,0x0f} -}; +extern const uint8_t ALIGN(16) ge25519_niels_base_multiples[256][96]; From ce81cc61df8fcb1e59abf9f302153428c0df0184 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 11 Jul 2017 19:10:08 +0200 Subject: [PATCH 452/627] add ethereum_address_checksum --- address.c | 16 ++++++++++++++++ address.h | 3 +++ test_check.c | 24 ++++++++++++++++++++++++ 3 files changed, 43 insertions(+) diff --git a/address.c b/address.c index 2fb8b32dd..5882e5c3e 100644 --- a/address.c +++ b/address.c @@ -52,3 +52,19 @@ bool address_check_prefix(const uint8_t *addr, uint32_t address_type) } return address_type == ((uint32_t)(addr[0] << 24) | (uint32_t)(addr[1] << 16) | (uint32_t)(addr[2] << 8) | (uint32_t)(addr[3])); } + +#if USE_ETHEREUM +#include "sha3.h" + +void ethereum_address_checksum(const uint8_t *addr, char *address) +{ + const char *hexU = "0123456789ABCDEF", *hexL = "0123456789abcdef"; + uint8_t hash[32]; + keccak_256(addr, 20, hash); + for (int i = 0; i < 40; i++) { + const char *t = (hash[i / 8] & (1 << (7 - i % 8))) ? hexU : hexL; + address[i] = (i % 2 == 0) ? t[(addr[i / 2] >> 4) & 0xF] : t[addr[i / 2] & 0xF]; + } + address[40] = 0; +} +#endif diff --git a/address.h b/address.h index bd96d61f5..62ce887f0 100644 --- a/address.h +++ b/address.h @@ -31,5 +31,8 @@ size_t address_prefix_bytes_len(uint32_t address_type); void address_write_prefix_bytes(uint32_t address_type, uint8_t *out); bool address_check_prefix(const uint8_t *addr, uint32_t address_type); +#if USE_ETHEREUM +void ethereum_address_checksum(const uint8_t *addr, char *address); +#endif #endif diff --git a/test_check.c b/test_check.c index aaecb11f9..6f43c49f9 100644 --- a/test_check.c +++ b/test_check.c @@ -55,6 +55,7 @@ #include "ed25519-keccak.h" #include "script.h" #include "rfc6979.h" +#include "address.h" /* * This is a clever trick to make Valgrind's Memcheck verify code @@ -3077,6 +3078,25 @@ START_TEST(test_ethereum_pubkeyhash) } END_TEST +START_TEST(test_ethereum_address) +{ + uint8_t addr[20]; + char address[41]; + + memcpy(addr, fromhex("cd2a3d9f938e13cd947ec05abc7fe734df8dd826"), 20); + ethereum_address_checksum(addr, address); + ck_assert_str_eq(address, "Cd2a3d9f938e13Cd947eC05ABC7fe734df8DD826"); + + memcpy(addr, fromhex("9ca0e998df92c5351cecbbb6dba82ac2266f7e0c"), 20); + ethereum_address_checksum(addr, address); + ck_assert_str_eq(address, "9Ca0e998dF92c5351cEcbBb6Dba82Ac2266f7e0C"); + + memcpy(addr, fromhex("cb16d0e54450cdd2368476e762b09d147972b637"), 20); + ethereum_address_checksum(addr, address); + ck_assert_str_eq(address, "cB16D0E54450Cdd2368476E762B09D147972b637"); +} +END_TEST + START_TEST(test_multibyte_address) { uint8_t priv_key[32]; @@ -3225,6 +3245,10 @@ Suite *test_suite(void) tcase_add_test(tc, test_address_decode); suite_add_tcase(s, tc); + tc = tcase_create("ethereum_address"); + tcase_add_test(tc, test_ethereum_address); + suite_add_tcase(s, tc); + tc = tcase_create("wif"); tcase_add_test(tc, test_wif); suite_add_tcase(s, tc); From f49fe75e15eafaa69ab687857c4ffd0c9410a0e1 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 11 Jul 2017 21:17:22 +0200 Subject: [PATCH 453/627] fix ethereum_address_checksum implementation --- address.c | 20 ++++++++++++++------ test_check.c | 35 +++++++++++++++++++++++------------ 2 files changed, 37 insertions(+), 18 deletions(-) diff --git a/address.c b/address.c index 5882e5c3e..1e5587611 100644 --- a/address.c +++ b/address.c @@ -58,13 +58,21 @@ bool address_check_prefix(const uint8_t *addr, uint32_t address_type) void ethereum_address_checksum(const uint8_t *addr, char *address) { - const char *hexU = "0123456789ABCDEF", *hexL = "0123456789abcdef"; - uint8_t hash[32]; - keccak_256(addr, 20, hash); - for (int i = 0; i < 40; i++) { - const char *t = (hash[i / 8] & (1 << (7 - i % 8))) ? hexU : hexL; - address[i] = (i % 2 == 0) ? t[(addr[i / 2] >> 4) & 0xF] : t[addr[i / 2] & 0xF]; + const char *hex = "0123456789abcdef"; + for (int i = 0; i < 20; i++) { + address[i * 2] = hex[(addr[i] >> 4) & 0xF]; + address[i * 2 + 1] = hex[addr[i] & 0xF]; } address[40] = 0; + uint8_t hash[32]; + keccak_256((const uint8_t *)address, 40, hash); + for (int i = 0; i < 20; i++) { + if (hash[i] & 0x80 && address[i * 2 ] >= 'a' && address[i * 2 ] <= 'f') { + address[i * 2] -= 0x20; + } + if (hash[i] & 0x08 && address[i * 2 + 1] >= 'a' && address[i * 2 + 1] <= 'f') { + address[i * 2 + 1] -= 0x20; + } + } } #endif diff --git a/test_check.c b/test_check.c index 6f43c49f9..c9674bf68 100644 --- a/test_check.c +++ b/test_check.c @@ -3080,20 +3080,31 @@ END_TEST START_TEST(test_ethereum_address) { + static const char *vectors[] = { + "52908400098527886E0F7030069857D2E4169EE7", + "8617E340B3D01FA5F11F306F4090FD50E238070D", + "de709f2102306220921060314715629080e2fb77", + "27b1fdb04752bbc536007a920d24acb045561c26", + "5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed", + "fB6916095ca1df60bB79Ce92cE3Ea74c37c5d359", + "dbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB", + "D1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb", + "5A4EAB120fB44eb6684E5e32785702FF45ea344D", + "5be4BDC48CeF65dbCbCaD5218B1A7D37F58A0741", + "a7dD84573f5ffF821baf2205745f768F8edCDD58", + "027a49d11d118c0060746F1990273FcB8c2fC196", + "CD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826", + 0 + }; uint8_t addr[20]; char address[41]; - - memcpy(addr, fromhex("cd2a3d9f938e13cd947ec05abc7fe734df8dd826"), 20); - ethereum_address_checksum(addr, address); - ck_assert_str_eq(address, "Cd2a3d9f938e13Cd947eC05ABC7fe734df8DD826"); - - memcpy(addr, fromhex("9ca0e998df92c5351cecbbb6dba82ac2266f7e0c"), 20); - ethereum_address_checksum(addr, address); - ck_assert_str_eq(address, "9Ca0e998dF92c5351cEcbBb6Dba82Ac2266f7e0C"); - - memcpy(addr, fromhex("cb16d0e54450cdd2368476e762b09d147972b637"), 20); - ethereum_address_checksum(addr, address); - ck_assert_str_eq(address, "cB16D0E54450Cdd2368476E762B09D147972b637"); + const char **vec = vectors; + while (*vec) { + memcpy(addr, fromhex(*vec), 20); + ethereum_address_checksum(addr, address); + ck_assert_str_eq(address, *vec); + vec++; + } } END_TEST From cfe8f39cd436bf98e864775a9131e81e554e7bf1 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 11 Jul 2017 21:34:47 +0200 Subject: [PATCH 454/627] include options.h in address.h --- address.h | 1 + 1 file changed, 1 insertion(+) diff --git a/address.h b/address.h index 62ce887f0..307cf8dc8 100644 --- a/address.h +++ b/address.h @@ -27,6 +27,7 @@ #include #include #include +#include "options.h" size_t address_prefix_bytes_len(uint32_t address_type); void address_write_prefix_bytes(uint32_t address_type, uint8_t *out); From c95034206388ddf7cbac9e182e0f9c1eb86ab65f Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 24 Jul 2017 22:57:20 +0200 Subject: [PATCH 455/627] refactor hdnode_public_ckd_address_optimized --- bip32.c | 28 ++++++++-------------------- bip32.h | 2 +- ecdsa.c | 17 +++++++++++++++++ ecdsa.h | 1 + test_check.c | 2 +- 5 files changed, 28 insertions(+), 22 deletions(-) diff --git a/bip32.c b/bip32.c index 49bc25db9..cfa05ed61 100644 --- a/bip32.c +++ b/bip32.c @@ -287,7 +287,7 @@ int hdnode_public_ckd(HDNode *inout, uint32_t i) return 1; } -int hdnode_public_ckd_address_optimized(const curve_point *pub, const uint8_t *chain_code, uint32_t i, uint32_t version, char *addr, int addrsize, bool segwit) +void hdnode_public_ckd_address_optimized(const curve_point *pub, const uint8_t *chain_code, uint32_t i, uint32_t version, char *addr, int addrsize, int addrformat) { uint8_t child_pubkey[33]; curve_point b; @@ -296,25 +296,13 @@ int hdnode_public_ckd_address_optimized(const curve_point *pub, const uint8_t *c child_pubkey[0] = 0x02 | (b.y.val[0] & 0x01); bn_write_be(&b.x, child_pubkey + 1); - if (!segwit) { - ecdsa_get_address(child_pubkey, version, addr, addrsize); - return 1; - } else { - uint8_t raw[32]; - size_t prelen = address_prefix_bytes_len(version); - uint8_t digest[MAX_ADDR_RAW_SIZE]; - - raw[0] = 0; // version byte - raw[1] = 20; // push 20 bytes - ecdsa_get_pubkeyhash(child_pubkey, raw + 2); - sha256_Raw(raw, 22, digest); - address_write_prefix_bytes(version, raw); - ripemd160(digest, 32, raw + prelen); - - if (!base58_encode_check(raw, prelen + 20, addr, MAX_ADDR_SIZE)) { - return 0; - } - return 1; + switch (addrformat) { + case 1: // Segwit-in-P2SH + ecdsa_get_address_segwit(child_pubkey, version, addr, addrsize); + break; + default: // normal address + ecdsa_get_address(child_pubkey, version, addr, addrsize); + break; } } diff --git a/bip32.h b/bip32.h index 7004c534a..71d9b8ed7 100644 --- a/bip32.h +++ b/bip32.h @@ -58,7 +58,7 @@ int hdnode_public_ckd_cp(const ecdsa_curve *curve, const curve_point *parent, co int hdnode_public_ckd(HDNode *inout, uint32_t i); -int hdnode_public_ckd_address_optimized(const curve_point *pub, const uint8_t *chain_code, uint32_t i, uint32_t version, char *addr, int addrsize, bool segwit); +void hdnode_public_ckd_address_optimized(const curve_point *pub, const uint8_t *chain_code, uint32_t i, uint32_t version, char *addr, int addrsize, int addrformat); #if USE_BIP32_CACHE int hdnode_private_ckd_cached(HDNode *inout, const uint32_t *i, size_t i_count, uint32_t *fingerprint); diff --git a/ecdsa.c b/ecdsa.c index 016f52bda..995afc5e7 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -907,6 +907,23 @@ void ecdsa_get_address(const uint8_t *pub_key, uint32_t version, char *addr, int MEMSET_BZERO(raw, sizeof(raw)); } +void ecdsa_get_address_segwit(const uint8_t *pub_key, uint32_t version, char *addr, int addrsize) +{ + uint8_t raw[MAX_ADDR_RAW_SIZE]; + size_t prefix_len = address_prefix_bytes_len(version); + uint8_t digest[32]; + raw[0] = 0; // version byte + raw[1] = 20; // push 20 bytes + ecdsa_get_pubkeyhash(pub_key, raw + 2); + sha256_Raw(raw, 22, digest); + address_write_prefix_bytes(version, raw); + ripemd160(digest, 32, raw + prefix_len); + base58_encode_check(raw, prefix_len + 20, addr, addrsize); + // not as important to clear these, but we might as well + MEMSET_BZERO(raw, sizeof(raw)); + MEMSET_BZERO(digest, sizeof(digest)); +} + void ecdsa_get_wif(const uint8_t *priv_key, uint32_t version, char *wif, int wifsize) { uint8_t wif_raw[MAX_WIF_RAW_SIZE]; diff --git a/ecdsa.h b/ecdsa.h index 32388191a..bd55451f0 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -74,6 +74,7 @@ void ecdsa_get_public_key65(const ecdsa_curve *curve, const uint8_t *priv_key, u void ecdsa_get_pubkeyhash(const uint8_t *pub_key, uint8_t *pubkeyhash); void ecdsa_get_address_raw(const uint8_t *pub_key, uint32_t version, uint8_t *addr_raw); void ecdsa_get_address(const uint8_t *pub_key, uint32_t version, char *addr, int addrsize); +void ecdsa_get_address_segwit(const uint8_t *pub_key, uint32_t version, char *addr, int addrsize); void ecdsa_get_wif(const uint8_t *priv_key, uint32_t version, char *wif, int wifsize); int ecdsa_address_decode(const char *addr, uint32_t version, uint8_t *out); diff --git a/test_check.c b/test_check.c index c9674bf68..bd2e2d82c 100644 --- a/test_check.c +++ b/test_check.c @@ -1021,7 +1021,7 @@ START_TEST(test_bip32_optimized) hdnode_fill_public_key(&node); ecdsa_get_address(node.public_key, 0, addr1, sizeof(addr1)); // optimized - hdnode_public_ckd_address_optimized(&pub, root.chain_code, i, 0, addr2, sizeof(addr2), false); + hdnode_public_ckd_address_optimized(&pub, root.chain_code, i, 0, addr2, sizeof(addr2), 0); // check ck_assert_str_eq(addr1, addr2); } From 8d0852403c012879bd4f7c616adea26ac5924b24 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 24 Jul 2017 23:43:30 +0200 Subject: [PATCH 456/627] move emscripten build to separate repository (hd-wallet/fastxpub) --- .travis.yml | 15 - emscripten/.gitignore | 2 - emscripten/Makefile | 37 - emscripten/benchmark.html | 8 - emscripten/benchmark.js | 98 -- emscripten/package.json | 8 - emscripten/post.js | 115 --- emscripten/pre.js | 9 - emscripten/test-addresses-segwit-p2sh.txt | 1000 -------------------- emscripten/test-addresses.txt | 1000 -------------------- emscripten/test-correctness-segwit-p2sh.js | 30 - emscripten/test-correctness.js | 30 - emscripten/trezor-crypto.js | 379 -------- 13 files changed, 2731 deletions(-) delete mode 100644 emscripten/.gitignore delete mode 100644 emscripten/Makefile delete mode 100644 emscripten/benchmark.html delete mode 100644 emscripten/benchmark.js delete mode 100644 emscripten/package.json delete mode 100644 emscripten/post.js delete mode 100644 emscripten/pre.js delete mode 100644 emscripten/test-addresses-segwit-p2sh.txt delete mode 100644 emscripten/test-addresses.txt delete mode 100644 emscripten/test-correctness-segwit-p2sh.js delete mode 100644 emscripten/test-correctness.js delete mode 100644 emscripten/trezor-crypto.js diff --git a/.travis.yml b/.travis.yml index e7d3020ab..2ebf2ea7d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,21 +27,6 @@ script: - ITERS=10 py.test - mkdir _build && cd _build && cmake .. && make && cd .. -matrix: - include: - - env: BUILD=emscripten - script: - - cd emscripten && rm trezor-crypto.js && make docker-build && make test-correctness && cd .. - services: - - docker - sudo: required - install: true - compiler: true - addons: - apt: - packages: - - nodejs - notifications: webhooks: urls: diff --git a/emscripten/.gitignore b/emscripten/.gitignore deleted file mode 100644 index 84f814fcc..000000000 --- a/emscripten/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -node_modules/ -benchmark-browserify.js diff --git a/emscripten/Makefile b/emscripten/Makefile deleted file mode 100644 index 11c07169f..000000000 --- a/emscripten/Makefile +++ /dev/null @@ -1,37 +0,0 @@ -EMFLAGS = \ - -Os --closure 1 \ - --memory-init-file 0 \ - --pre-js pre.js --post-js post.js \ - -I ../ed25519-donna \ - -s EXPORTED_FUNCTIONS='["_hdnode_public_ckd_address_optimized", "_ecdsa_read_pubkey"]' - -SRC = ../bignum.c ../ecdsa.c ../secp256k1.c ../hmac.c ../bip32.c \ - ../base58.c ../ripemd160.c ../sha2.c ../rand.c ../address.c - -all: trezor-crypto.js benchmark-browserify.js - -trezor-crypto.js: $(SRC) - emcc $(EMFLAGS) -o $@ $^ - -benchmark-browserify.js: node_modules trezor-crypto.js benchmark.js - $(shell npm bin)/browserify benchmark.js -o $@ --noparse=`pwd`/trezor-crypto.js - @echo "open benchmark.html in your favourite browser" - -benchmark-node: node_modules trezor-crypto.js benchmark.js - node benchmark.js - -node_modules: - npm install - npm install browserify - -clean: - rm -f trezor-crypto.js benchmark-browserify.js - -docker: - docker run --rm -i -v $(shell pwd)/..:/src -t apiaryio/emcc /bin/bash - -docker-build: - docker run --rm -v $(shell pwd)/..:/src apiaryio/emcc /bin/bash -c 'cd emscripten && make' - -test-correctness: node_modules - node test-correctness.js test-correctness-segwit-p2sh.js diff --git a/emscripten/benchmark.html b/emscripten/benchmark.html deleted file mode 100644 index be2acc00e..000000000 --- a/emscripten/benchmark.html +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/emscripten/benchmark.js b/emscripten/benchmark.js deleted file mode 100644 index ed7ed8cfc..000000000 --- a/emscripten/benchmark.js +++ /dev/null @@ -1,98 +0,0 @@ -var crypto = require('./trezor-crypto'); -var bitcoin = require('bitcoinjs-lib'); - -var XPUB = - 'xpub6AHA9hZDN11k2ijHMeS5QqHx2KP9aMBRhTDqANMnwVtdyw2TDYRm' + - 'F8PjpvwUFcL1Et8Hj59S3gTSMcUQ5gAqTz3Wd8EsMTmF3DChhqPQBnU'; -var node = bitcoin.HDNode.fromBase58(XPUB).derive(0); - -var nodeStruct = { - depth: node.depth, - child_num: node.index, - fingerprint: node.parentFingerprint, - chain_code: node.chainCode, - public_key: node.keyPair.getPublicKeyBuffer() -}; - -var suite; -var worker; - -if (typeof Worker !== 'undefined') { - console.log('enabling web worker benchmark'); - worker = new Worker('./trezor-crypto.js'); - worker.onerror = function (error) { - console.error('worker:', error); - }; - suite = [ - // benchBitcoinJS, - // benchBrowserify, - benchWorker - ]; -} else { - suite = [ - benchBitcoinJS, - benchBrowserify - ]; -} - -benchmark(suite, 1000, 1000); - -function benchmark(suite, delay, ops) { - (function cycle(i) { - setTimeout(function () { - var benchmark = suite[i]; - runBenchmark(benchmark, ops, function (runtime) { - printResult(benchmark, ops, runtime); - cycle(i+1 < suite.length ? i+1 : 0); - }); - }, delay); - }(0)); -} - -function benchBitcoinJS(ops, fn) { - var i; - for (i = 0; i < ops; i++) { - node.derive(i).getAddress(); - } - fn(); -} - -function benchBrowserify(ops, fn) { - var i; - crypto.serializeNode(nodeStruct); - for (i = 0; i < ops; i++) { - crypto.deriveAddress(i, 0); - } - fn(); -} - -function benchWorker(ops, fn) { - worker.onmessage = function (event) { - fn(); - }; - worker.postMessage({ - type: 'deriveAddressRange', - node: nodeStruct, - from: 0, - to: ops - 1, - version: 0 - }); -} - -function runBenchmark(benchmark, ops, fn) { - var start = new Date(); - benchmark(ops, function () { - var end = new Date(); - fn(end - start); - }); -} - -function printResult(benchmark, ops, runtime) { - var opssec = (ops / runtime) * 1000; - console.log( - benchmark.name, - 'ops #', ops, - 'runtime', runtime / 1000, - 'sec, ops/sec', opssec - ); -} diff --git a/emscripten/package.json b/emscripten/package.json deleted file mode 100644 index 16ad3c5ce..000000000 --- a/emscripten/package.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "name": "trezor-crypto-test", - "version": "1.0.0", - "description": "", - "dependencies": { - "bitcoinjs-lib": "^2.1.1" - } -} diff --git a/emscripten/post.js b/emscripten/post.js deleted file mode 100644 index ce2dfb7b0..000000000 --- a/emscripten/post.js +++ /dev/null @@ -1,115 +0,0 @@ -/* - typedef struct { - uint32_t depth; - uint32_t fingerprint; - uint32_t child_num; - uint8_t chain_code[32]; - uint8_t private_key[32]; - uint8_t public_key[33]; - } HDNode; - */ - -var HEAPU8 = Module['HEAPU8']; -var _malloc = Module['_malloc']; -var _hdnode_public_ckd_address_optimized = Module['_hdnode_public_ckd_address_optimized']; -var _ecdsa_read_pubkey = Module['_ecdsa_read_pubkey']; -var Pointer_stringify = Module['Pointer_stringify']; - -// HDNode structs global -var PUBPOINT_SIZE = 2 * 9 * 4; // (2 * bignum256 (= 9 * uint32_t)) -var _pubpoint = _malloc(PUBPOINT_SIZE); -var PUBKEY_SIZE = 33; -var _pubkey = _malloc(PUBKEY_SIZE); -var CHAINCODE_SIZE = 32; -var _chaincode = _malloc(CHAINCODE_SIZE); - -// address string global -var ADDRESS_SIZE = 60; // maximum size -var _address = _malloc(ADDRESS_SIZE); - -/* - * public library interface - */ - -/** - * @param {HDNode} node HDNode struct, see the definition above - */ -function serializeNode(node) { - var u8_pubkey = new Uint8Array(33); - u8_pubkey.set(node['public_key'], 0); - HEAPU8.set(u8_pubkey, _pubkey); - - var u8_chaincode = new Uint8Array(32); - u8_chaincode.set(node['chain_code'], 0); - HEAPU8.set(u8_chaincode, _chaincode); - - _ecdsa_read_pubkey(0, _pubkey, _pubpoint); -} - -/** - * @param {Number} index BIP32 index of the address - * @param {Number} version address version byte - * @return {String} - */ -function deriveAddress(index, version, segwit) { - _hdnode_public_ckd_address_optimized(_pubpoint, _chaincode, index, version, _address, ADDRESS_SIZE, segwit); - return Pointer_stringify(_address); -} - -/** - * @param {HDNode} node HDNode struct, see the definition above - * @param {Number} firstIndex index of the first address - * @param {Number} lastIndex index of the last address - * @param {Number} version address version byte - * @return {Array} - */ -function deriveAddressRange(node, firstIndex, lastIndex, version, segwit) { - var addresses = []; - serializeNode(node); - var i; - for (i = firstIndex; i <= lastIndex; i++) { - addresses.push(deriveAddress(i, version, segwit)); - } - return addresses; -} - -if (typeof module !== 'undefined') { - module['exports'] = { - 'serializeNode': serializeNode, - 'deriveAddress': deriveAddress, - 'deriveAddressRange': deriveAddressRange - }; -} - -/* - * Web worker processing - */ - -function processMessage(event) { - var data = event['data']; - var type = data['type']; - - switch (type) { - case 'deriveAddressRange': - var addresses = deriveAddressRange( - data['node'], - data['firstIndex'], - data['lastIndex'], - data['version'], - !!data['segwit'] - ); - self.postMessage({ - 'addresses': addresses, - 'firstIndex': data['firstIndex'], - 'lastIndex': data['lastIndex'] - }); - break; - - default: - throw new Error('Unknown message type: ' + type); - } -} - -if (ENVIRONMENT_IS_WORKER) { - self.onmessage = processMessage; -} diff --git a/emscripten/pre.js b/emscripten/pre.js deleted file mode 100644 index f1b364afc..000000000 --- a/emscripten/pre.js +++ /dev/null @@ -1,9 +0,0 @@ -// stub importScripts for the faulty detection of web worker env -if (typeof importScripts === 'undefined' - && typeof WorkerGlobalScope !== 'undefined' - && this instanceof WorkerGlobalScope - ) { - this.importScripts = function () { - throw new Error('importScripts is a stub'); - }; - } diff --git a/emscripten/test-addresses-segwit-p2sh.txt b/emscripten/test-addresses-segwit-p2sh.txt deleted file mode 100644 index 38db9aa98..000000000 --- a/emscripten/test-addresses-segwit-p2sh.txt +++ /dev/null @@ -1,1000 +0,0 @@ -3L6TyTisPBmrDAj6RoKmDzNnj4eQi54gD2 -3GMMgFUQiYTYQhuHQuZfQoXPvW3GPqfGmD -3BKbtvJtLSjnSoGUYTeQ17tMKTuyqbUV7P -3Dyf1D6pVR6ZAQYN1th6ehgS1uqgGk1TGh -33wLRyxHFtrXLF7Aun38Dctw5QyiBdruK2 -32pKKUD5TKyqb4kzPorJnY8XhiLaHBKni1 -3NCRi181wMB1v9gPyms9WDruKemBfrE9rQ -32d6ze9Be4J45ERomziXxGWXxLobAAQq85 -3FNTNKoAcXDUTUSNAtVTcvAehwQLyJSmP9 -3L55P4LZsyKYUw5Aqy6DPky6ySw3g34TQS -3QUYdkHXqUh596y3nSrqd1Wo9hvXDHC391 -3LSrVvK9jQTemnSyj9sqzD7wFTHwD8zqM7 -3NVbd95gArUqSZ6yJWpc2S558xsfXvgu8y -39RWZUTeiNuNb5GjhcrU636FKB6DF1EMpn -37uK6ozVfE5G35oUmu3Y9z3Y1veV6KrQgZ -32Px86LYPEPTQBCSY3oqw7nsJjgaFZeu8w -3Nr9468Yg3SR1uvT91eVVcK5HDBsvBV1WA -3GmgGz1EDuEegTFX8ZvRY3D9Hn5YdAHVHw -3C9pLLkD9GWaeoe5Wk1Fzh8heCtvWiMu9y -3JVy2YsVyGHiyV4Mpd72VfRgjMEc5sh4xB -3BEK3pjowHUJyBLoJUGmEiMdbS5f3Uc8kz -3MY7p5Cwv2ZXnjaqsinoS38nw64DzF6KsL -3JNH6miNDAtjaEGTUpUj2N49hpCdZDR9tD -37oPVPaHVDzCRvhjGJCbbFoY2zir7Zwa7s -3PRc5bYn5cJXbCtTkE4CqXTsydLLJ8r2kz -3Ls1ZtNeUm2EhZguHg5gHM16MCmkaHHvYv -35cQ6AS5BFPnvJzMdKUgvn12okTFW4xiUk -36ZokNVM61qVXwJ2kPjheD5NXv8R1m4kNx -35qSDRkPGrsZakQjfWCsVu4XXQVXfpE4VH -3MeTLGKR7ZGAiDNKhuLkeL485iubhUPuun -34g5cGJi4KvDRSXUHkvoHQ814JnUtkKEJR -392DKjhHFBCF5VV37wbqUWJKeyrPUwJ99w -3KeSMat1jJD9hTUzz2y1dzUHmNM3h8ASwR -3No5TYGwyihJeYASUR8R7tfrGfcR34iLpw -3QnNX54yJ1dMfGEjPj78M6VdfBgd2AA8H4 -3EcbwVoWKVsktWeEwefDbe416xk7kdExdP -36b2VYEoCPKxPq8e8cpP43SNffj3uvjbY5 -39BtjJpWxEFrYcxqnbv45UHaCvNMa8QjMB -36CWUsqi89VQYX25aLkoTjnvLkMVETVBUg -3FYQ9DUaKU3bfuibADb8VK7gv8YC4etnJC -3HDPiUsdCJqeKxMefN9Qgir7T82ttUGHj3 -34PxdeMc3GPB21aSHWdUskRuiKb7EUisJh -3LnStYPBS1mAhN67UtSahS6LGHsiVmApkP -3P4jqTxnq85Ln9TJ5458EiNX6uowZeftmQ -3LtexPXYoYW6QYdEk8UKfyXHpfsL3dkzhW -3NcBeiCaCTFnGUuR1DFWqHnrh1yHcW7vs6 -34DbTn7C2EpCT9PGwAZ34nEQqm417rdjs9 -36iyb6aG34fqRQY5nckjKQBP1ie2HrCf8b -3BZrb86oAVd6PxA6eUjNjFnftFvoWNS1jc -3KE6HXaLGA8AGhmt6qBVCUySPshPfAzSvL -36xBToEgeMRt7rNxMHRBZMsJ4mdiZR2KPq -39dj1YhQrrTrXr4EKxAPMk1MptPHnAEjtP -3GYBScjaBYkitkiir988cAoYy2ywun4DJ2 -32sPwqW7TebhLdK2PZVD5rUsAmGuNtPPyu -3GcTnN9CqwPmmumyz2Gpjad2vRXTTVTvZC -3DEAk9KGrgvj2gHQ1hyfCXus9hZr9K8Beh -3DDEgt7quAq7XqoG6PjVXi1eeAea4rfWck -3AAVuCwY14GhZxneLdnyyHVnbxrnybvfLG -38dN4pKoM5xj7Ng3x77MQjTzFu5pGfao1k -3BpgvVhxeLPXaSky6XKbRGhqy8qqStdPaa -3Lv3RTGKZTm2G3Ffmi5STD4bSs21ZZGCgb -3H3VjuiyT2yZeb5kCfHvbpsojuxWGFahVq -3G41qJZTA41WTCf72U1uCkv7NYV3kTw8De -3DqVnsZhebv3TzRHxuBH3yMB9e57AKdk6N -36TdEmtdTNwyVF1LcCQBWb3fUzcaYefjUF -3KEY3rtdNVKVAY1VaWQxKTFqzviELndU9L -3JduTJqDLS6HeASbKgd8BJ2n6T7FDoKUKh -3PfsZaRzm13wddt74z4XB4UqftAhkUGhxq -34ZmW5gD8s9s3gzBHLjz9hTDajwyVYbMXC -32MG7JkvmLtr8tJfck4VopRb2L3GJFFqQW -3Dr8FASDUmvL6zR1X4SmpFCQFCMDyVYmgs -37yxSBtTyDDadVDp5m7yXRWteLEWMFfJ2E -3PoBGg2EN2n7egvoheJVEdbidA95YREtBd -3BXjcAzmWFBJ3vmzMs9bj6N6UszV4PCBG5 -3Jhttc2iRyT8ZLZk9px4VXuCze3RaW2Esy -3EVtXiRUhSLtRtKGgiAr6w81SEihf79rAB -3HyKdhyaDQXmrkXwPgiQupwy7VJEG76EAA -32RTpbK5pBLc2nJshZRQRHxTJ3fCSYKhHy -3HEqaNBsNHNS4a2UhnsJeGuYkzPa4dEiFx -34CW8uoLtrphrcpyUFvZHFbdLTk7LdrA3a -3Ep4h4GCgRam5VYnQVFR3zKkoA5C7rY1Yg -3JcVQHPjeF55U4CqG8VwczN5yh71jtBwoE -35LLdriZnzD2kkwTNdn67uusqSRMQVGBW6 -3Dzf6T3d7TdzrvungAmyrecLQACETAd26E -37D3oRNsL4AQ7xMg1V2DGANoc91nmt6ncn -3GsQ4ybMZZB95b4KvhgoVd7wCfP15A3C4C -3MsFkAVEx8qdEDjbhBgCkxvHPYNZdsvEMv -34AEwPwjHnfho9sxabzoYYGgw4pRh7Nnx2 -3EMQZP2AyrYfgB1WbZBaRVAPQZcStDKp2P -3Cy3X7Bc3ETRZNitRU9CBEFduAnyhrK3Wt -3PvsU51ccgJTqxVWyi7U3xK2PdRKKtkcik -3PoP4fcaESzfPEYbdseAFSeV7us4k9fvtR -3CYTYw1g4KqmkRL6bxjRkVuJG3c5PhzGQa -3KEwXq9tAeX1JdNqKpqfDZYvie4GHJV3P7 -32RyQNez8F74xZzyFgLutEVYpJhgRGYpzM -3HxxnrxsVqi5xxzM4hK6A3eg8PKRNjBwZz -38LULYeGHYnZUnm7qqB97TEBMXhVmZsRUE -3KmBxRUkDupzQsX4hRqzx9GMzcQ65gDQXp -38CmCv5ZtCWS89EqKKBPe3Q3EpGLNVXL3Q -39fkbE1D4sfc2hG385gHnMzyuU8qFZDUDr -394WfmmiuKJhZvPmTTPh6cJGUDxzKgq8eG -35ZRKaEDJ87cFsBUYPxSicNEqi1RUZNoTW -3H3X8fQ5pwLaxmnA24sKH1XUupnrnKL7is -3FGkrSSjyhYKJ5mqU8mRrEhMNQtTXL8m3N -3CEsMxjUG8vBFs1aURjgX3V2oCqNNGbp7i -3EDV71yq84X6q2uSYYYBtrbzao4yyYRBp9 -3AALBMc96FApvdHVaMk5q85bT3i424aWBk -3Ef3XwwckWbqSpj51PtrmcAFkvg4pQgGKV -39kF6UbxnZaRhURAKpwjZpCce9o6qeZZrv -3CNdahrrayWEDVYsYzz2eK65cdvSHcVPgh -3BbXJHBsFDXVmYMBgdEfi5FGpbiDHWXf7e -3D2vB7NXrXpiPJm3Lxf8GaefiqBo4hgJeB -3D8VCaGovUuMmgaJsYjkNzmsiCxPB29HA5 -39C59wJZqumNrXtXaJ6SAsS5NZcNXpfWd3 -3MCYPB8SsyEyDhweEww3NPN71VJzBwJNBd -3Qar97RYd2AbJupsktRqEo4U3HDfu7PhCg -3Jg9qAWv8bVQy1qaxHgPzf6RnQEaovGP4D -3MToyVfVTtz8m5BSoTmoYP3o6zwvkwiHza -381fixojPQmwJ52FWdbMezL67xcct1kkJ8 -38q1znmvmhydbszNgH4Nsuu1xyFvomjyeb -3G73GQG4AMVt1UwWD8nRJthxYVbjrJAL2v -391G3wDCXNRTmEn5SeuMonwhiNteewjuWP -37WUSLfbPXCBWfbGcCvYhvPrGLMsA6p1wc -3BEZDvhBXjvugNeD1ZTBnSUwNP5jXWPHX2 -3LG4poMSHpFfQNR5CNnuARQ4Z1rWBes486 -35mZSVZz3FcAdkaJApupNmsFRuExxc9a6W -3Q78psT2LSEUziG4TyezZzT9eJaVJrxvSM -3B6J1ssSk7nj4tRdHYAS5Rk4FAfQug1KAd -3Hf1int17fDuLFeSQK7Qt3eajPfrqtt9cB -34mHkCSxAjRDuzxPnzRM7DsiJTWLqgmRG1 -3PToajRg8PMJicBoFhetftxNg68jXzyFdd -3ENbeAhd15EdFqrnYr9HWcAM59kUKAEVH1 -3BJTCd6aA5qqhBASquA7WDFnWu5MfvSMZe -3D2KVUuewqVeNd48mJJv57AbXavPoyVDSt -33kgX4pUwisdZr63y4yg5dkeWtyNm19Tce -39ApLYH7yPPeQWnHmNpwhjnx5rwuygQjeW -3MxRzPcqSKW5hq9XeNtXR5eghzwJS8Sn42 -3Jay1T9dHjEvxhFWu9bx5RWqfxvPVCaLjS -3JwA6tEjLpwCQYD7kfEJJTriUssyqNhyJp -3E7K9gCGA52KEHbc9WJjrKrVkkugtJsWt9 -34Nw8rKMyKjD738oFzdF6c6piU9KvAiXPF -3PWYXFEeh3VXiQQQWS9RyP8mqxV73AiMKD -3B2xXCtWpKbAzPiBUifUDyV5rfX5RwvUCA -32r8NwCVFzwSSNUEbE8AG4UPYEaNtvJAVB -3Lo4bJdFBi3N2Bu5UBRpmq4oMgq54iKzaS -33aGcY5baLuYzZbmPpELJBhBQkfmEb9uhZ -3EKcxDj6a24zL5ER6zgTzm4kbjfzsPAhFD -38Ua4cxZimk3kF9kjYutgHbTF68v2u5ZZU -3GGqTUnmPs2TLkyC3P9qvcAaj4fE2TGaar -3Nsrx1kSbYa5g2QptUuTeaoHx4JpgqJP5U -35e9AtgykmE8FcnKxXu9e79yAoVLkDThH5 -35iQrqAJEQxTRRMv5CbBUTdqmhxH74KD7H -3BoAvoQb5rb2xnwJzT8bExWKzngjjDhQRQ -3FYUxi6d8d4gpbZfcdTGUZtiSVNfMVTwjd -3KQHuRJjep5h7NGvhvWABH7wAwXzAjd9LH -37yHo2YfZ94kVGBBgvpF8C54GtB9zcChdw -3BFejSxEJynev1VxEfFxrYXRDMiVu5V3ga -3KEQ8fgBbp9EYjKDDPpVKQqc1PYnrCxsSK -36s4vvQNHrwuj1FS8h8nDGz9Af3irU9K4J -38HgcZAs9Hzhzx9NU8UVnbTqiuVyqwEEpv -3Mtby8dhy1j99FPKczS3418NiKR3GN8TTp -3APwYdK4bdeuFbpVKhuHuqUiR8FKGrcf1B -39wbDWDDJj65mMGichyCtaWxS3NZ53XkCz -3Ng36zB3As9GEjLYXNaY2QujrL714xRz9T -3FB3hLqHA6wQy6dEjgNVmsp8araWnTmhBj -3Gi1gpsX8ADmfd7jZP2Cw7KB6ECPUzNHqW -3EQavtEiEZNBXXKzPNQRNBLvpYWafJsKx1 -3DHDH9AQ2zRWbzSchbsKdHWFvBeMtyE9xt -38Awq1VkndCAe1GGYisgbz2tahacXcbMii -3LJgE5CukXNkey2bXzUuvLmD8RwoSiQWb4 -31tVLdmfSHx7NCmX6wWTnaRh38EMMszaqr -3LvMR7ajcLno5Mos6aYTMPHyRL1WEyTPQd -3QjNACh1jimgM2Suk1J39orYFzSRukdCir -3DtToHiK6LuCLwXsrFn86YJbZTrbBGTxgt -39FM8S2DHoT7c8y4ZDkvSuMbVX1QfajkXB -3KAoG8pg6WtXXLkireP6oEhA1DPHiLpcqb -36eESGCgXivSuXT5tXKVxtpVegmsYBVvqV -3LZWwbcUC8itYrUERdSbGCz5BJCR8dZkMm -3HwYZFj8h4h5oSvC3FTraTdByqaxdX4zQK -3PW9gZPuvNpGUCqKeXdPLCcLg2tgF89Dw1 -3FBrWKVpsj6gMnVZxuk9dR5pB59AKJNUyt -34CGcF9Z423ZtpTMnrudcp3nwx21SxDomd -3JaGfRyJkUcyETYmVsmm9EqyPk7kAntHRD -3B9KKoBXJBLnUpNhmPz8HGCCZA42fofeyA -3HKnua8DtGDXXN5gRG3qcLSMwAbqBpJzoG -3EVvcXvC1tVhBLamCeqtw3NtWkEdZSfSeh -36Qd5m1kTRKyBvakGgpPn9mbYr2PokaKsH -3ANZVa73V8tvfKCna3Gi7pvyGcqeMn1aDM -31js7uf83h2U9wuziYNXW2Ky5wGXmJW28G -3DfRd2bXxT8TYCyShwPUs8fB2vB4VCdQaU -3Gcob9CoJUknXp4Gd9xHrEGLrEPBbThgTj -3H6BjYJGKZjvaZyH4Nib7ASo87x2aw9jRm -3LnfxKWRD6FR2K12HfRqwuoJUFtZuJbDwH -3FySJ94MJLB9KPoQedbGT95DTaVVcBXXHv -3AsuiWeDknv6oE5ameVxYxN37VRYNXqQpy -34GJ6JRvr59iYDdn4LSvfhNs7drEjvNivZ -3JWLaXiUZJQALwPjXM1Q7zMUigkevwqGCr -31kd4USisJARZbUJVeiQwT8vJPruCet2AQ -3Av8DdCNJN8fy3ZV5kv424Rsdr5nPSv2wd -3NgsLbMUDsCk6x33vTcRWuuz71SXX59UDf -39scmZ4WSYyvXcK9evZKw8q2WxRfGngDS6 -3Cthen1QN4jaSLbmJGu7NpaZZ4tHZFvuuU -3B6JqdUQ4qdSokxs6WK8myfqeXxZfjG1mr -3PnCVj6SCRKvWXthmQDhKGTcgPip8CigLx -3DDXfQMfZ5D9KRTXsGLy3rRoDS2qzCLVWa -3HhSxMLaPcSARmWbq6iJGua58q1QxPnuyH -3Q9anVecF51TnKpHpJRFmQC7CsJV7Wsbjp -395itDqVRWgLZiLYaV4iWTi88SD81wMRrN -34m6dNeV8Y1ekCLTCxa8fLPPFPJpCLDFTT -334CRfuhkRmsTAYqm9kEcCsRq2drt63GGh -38Zo2Sg1NgWgD3bdPuqS8ZNXhRQRUdUwTo -3Fb2eKvyCixRop6UNqi7j3YSKZVTBW4Q9q -3M3qP8ED67yCRKyegpUMpP6aSwEa7F7dqv -35S13HitowwoMFvVgQQAGBr54qQGmnJo6e -3JHoB2dDPxcU1vLtbcxxvxnaWUxX2rtD3j -38mxcJkYHmrz39aXUAdwkiY56UnSKsHcvi -3LXfABPvn7tdp3dWs8KndRTWVvAhd71xHe -3AAkwi9ysQUf31fQzmToEemmhZ5wD9f8P7 -3QVas1yE3KEo4qmmiqR9iAb33vC4wJtoei -3N3wfptzCnEKGNPshQQxM87qPCT7oPqAAe -3BGoxh6QobBzGsEcuqWEernPkLfEEAnveP -37ckjTdwRDTvaKb4dp3GEhQLEftN2bAgo4 -3MHitmAa8WvUKRiJZeBPCrKGBkQctn71CZ -3BNpK5Jxyx4tt6ZNxXq3weha1cyqAjLNKv -34g5efpp89DbcizSWbwnuMVNzK2NrjgmAN -3HLexR3V5yHfZTnugRAoAV46cwMDSdv8TA -3QhJRdaATGP2w9HcvwVqxoS54dytbojvXA -39PMxps7ZLfegv7pd3gS14DS4x4y3HTZS5 -3DQiceqDi47oNkZtDX3x5nfVTdgZpXtv35 -3NcEAAt47ZoooSdHyniJ44ncCpxhps4pE8 -3GMkfeLcnxGw7xmDrUwxSFXqz7yCAbatuS -3BPsFcRYhfrLPVXW8eLgtUcZ6MMLzMhui7 -34SSzaXNNxHk3FFmKSip1geB1MWUX9qW1K -37x3QMz5MPWoQvAeQGKz5fv2ZRBsa7xQMw -3GpYKMvD8WnszHmyGujyv6vj13oenKUknP -3Hh2JxSH7Qatje7ev9k9qKCuEnwrWP6i7i -3G1PVGeiLxXDef31eo9Mtb9PJdrY1qi4T9 -3MVvq3MNQteKod56oVNxYSnnVvzn7qFyQ2 -35mSKfaHBDhsd9ECPGvJTYjeVS5FJFbWc9 -3MrWBCQ4HDfCjniobUMvuZhrABxAhd2vgh -3BPTMUCkfzfFYo2xRDTj4DfbsBiiUmCGVU -3HTX5DL4AX2zpQNrnEGG75pLhPzJuQoZVS -3Jr3MvNuq1MvtdLkYhdNCrmtWUxXXpknxT -3PbU4r1azQoKs2eFL1jQzL76u8u3rmtLAN -3MM4X2dGkEMHeKZYJSmf1cqAH5ci6rNgKj -3QqpkHXKGkcmHJ1Hb3GmbdYhwFLqjF152M -355m2CJuTiTpM8FpcjG4ag7VcJoWH7MVgy -3C28kVoK5mimgV7t39EGbBCRg9hfdzCR2c -3Jbok7ncfp5vfh4yx9Btap8gbheeNrwwy8 -38EygWfJheecCKfKissVeXAJJFSMvnXTSx -33gDy43DtzPZDntwUTBm54mVCs6bZJwVUc -37Er8AmgGgymzvyhFZrFnYae1Ujjyx16yK -36V9U3Uhbv7TBwzEvDBWoXNvJfGqH3K7HA -35sKhEvTxDrpWaAtVKr9WZg7iMNK68bKjR -39JyYcV7ni2YEEjmb1RJJgi6m5zc86uaoi -3ErCHnzHtM4aJEJNgQCCXSAeiqy2ATsfRv -3BXaXWMweNeZa4qDTU7e7YbjFL6LUAqBqh -3PXuVnzee5aT1BEPyzNQHC1oejmjVsXb9Z -3N9UNh1WnsTjMRMRRghyDGi5sYUgfGabyu -3QDRoSqGJCNai9BszsT1H6ohQS8P5xXzQM -3MH4a5oZTmqgix3GkdKTB4MLLfCqXjrFx8 -3M6q6tB3byGjHb1DaMJWnMaGkvLxGUNvuC -3Gb2HAkNDedBneFAx6NHRkreJVyqatciaz -3GwRuLwbNi387Q724zyurWacgvodJYqeaG -3G2HLzgggdCbjT4R7LCQB6VC2epCdkruUc -34oo6hWHJuM2oUALJnyVfoH96Ry6nVevSr -3BUzzsTvrmXj53s3jdMTefQ8UHTvmSrrQ9 -3CE656Fob3tEGRb6yvW1Ei1FKWFUjYb7xs -3PSckpv9Khn5a2JsBa3gE3tX4W2bmqLUHY -3CpLrJmVqmvu4g4npQeTjae8Mhx38d7TEf -32E5cLsJrJhoked2ZP6n7WzNvcCfWjXq4b -3H4tYTKw1Vk3bcAn7ropZLMzvuLPcLbNX3 -3DkRczeJT2abDWY3Jz5L8u6rkUqMDsLWCH -3CouBpbYoAHXfNWWWT1nrv6ovMWA5f2K3z -3CPG67PZGoiWR7m3S345XnwphNn9PSWKkk -37bAg19dst1JsdVbpvbcXoWG2Ept1JQQ2X -31xwFJoBGnWbqtxd2XK887uCW7DcC21q1N -3G9tCzxHFmzYmcu1ZTPsEqFtuzWSajTzM8 -3MdTw93dyG5pjnaKh9kRUsnLZGBMCyhe3H -3JYHRJDFVrWXuWmuJURRwogPkxSmYgQ3bK -32jxYHDj4JV6Q7CYzyeVfHakeg3zJXnHMT -3Kx7oP5MMKxQ39XUa2UsgvPmvx8vLGca57 -3N41fo3Rmk1ayYyXT1wXxFq2oFAEbk1MDg -39XA63rsXkpLKAGuGd2kDqVccaC3j5Uq4u -3M9bpEng5CLNvMkx48CkRjvhPeiLRJ7gHS -3FyYYSSpnXjgajuVjS13oWnGbNbAj4B4Rs -37q8tuMcq6H9UWtxe3iBeaWdiAwxNzRufw -3Ci9S6NfyYPoq9db9vS2rVvRdGy1CvG4XK -33eJznYW7soHwpPgfSwWw6o1ZH2jkGdzgt -3EoACBva5Wt6ViyF4APQRn1mTTor2WqxNm -3KGZppQhzndnW14CPrek2gqseNDcFH9AoF -3JncQ5wy9iR2ZVg1faHcmnruK4asiEsKzs -3AyQmownVfTHLs687vgPWtC77Vv7T5q1Jh -3R2ardYGFhwKEEi9VBAwe5B2LbkT2nXggG -3JruDbZnJWUcF7wvue7naRNAV1Kn8x4KPo -3F9ZGgm6T9AUQpJbrpUaUUA4UjCXMxLSF3 -362AucPPeMUe9o8BTkRVxTEHy6hHWKucdG -35QtHk6eZAaQEir8PSq8ZRk1xPBWLdgpdH -326TKYh8dpRw6Jb76iryX1n1vU1nG5Umxb -375X2J6QfXjNH3ZCAEuucTopqWXqpjcbJZ -3KJogBBb35iK5barU5MTuJJ4giJGNJ8s5b -35qqxXGYdWBGi86vUUjNxE7p2iQJ7eq4bU -3Quz5WYEAQiayi1EAPLVvsvmrgUe4gLcTf -3FidZfuw8DcSGnWq6R3P6VJPd1thju7p6b -3F45YuvEodf7aq7BDFBLYufxMekjS5txka -3HhPjspM7HybkQJL4ej8cADCFvgkgL1XGL -3BCCvN97bGezVa54REBJnMCk8E2VU8cDdN -34SxNu7b65VPK8EfLehoSMGVZf5xzmUPMi -361ePvZFy9USCFJDBWUwXzZMcbcEJDmKca -3BFtrWf5gH6eZtUJzNZJvLS2TveNoP5h3T -39kkXMUQrhS3XivCMLCFf896ujj3YbxWMg -3QNHp8AQRwRojWYDPpgnrgZsqXcQhBt6vQ -3CmTuso1QS1KQdPCKasccJvyF8qe4gy8ht -35SVXZmzriTe8RHAGC97KXSRDgcYUeZ5Qu -38HnbftkWAjDuGWxtkw9qjkdjSv82Ezymb -31mUJDPhKJr7rcL1eG35wkRMn3npm82Q4k -3QBKmLVVt6MWd2N1emrUzFpDk9dKym2ptD -34y7NbJYxHfTkaxGX8WFFHjGUXjWSW2NWA -3NQbLLb5cEBVubVsp9oRkzWFQEU4wiD6Jx -33whNENQeuEH9WDNYRUofUPYVPy3Q2TxXS -391ZdeW4YymhKAT6kzBKDY3JuzNzevZV4L -3MNExBQiLDSRYfjQ3Qx9ndrJgTBoqD9rnM -3G13D1t2dwAi1A4kYHsyK4h6W852qCPZM7 -3N1rX7mrLM5tvdapevSJgocjZKEJagThQU -3NFEe52aNsH3eobeH5Wf59RPEK5p5gWDGB -31iK7aLeMWssxo2TxUFFrff2q1VYAEx6Mp -35Z5JDC3hbvyaQNB1XCUyLBbYiK1oe1UKG -35mfUkdtQuJziATLBquipxYoW2oSQdnynz -3HXxHQZbAj3iKr8DoojawxY8mVSK5fFCt9 -3GMLeVDxsvn6WCrDkFRFCMqEZd5QA13SEc -3B9gFuGrnujb5cQRPXJJEBaKgangfuEjCw -3Q3KsiQ949JFC1oqbVV6qqp6avdbRD6KFc -3L7bBGUoVQZddCPpotujudGS82bSdFG6G1 -31rwfH9MrvowcSRzVT52o7gzHrzdzJUp7Y -3Ht7nGkERcU8kMxScKF6fm8c5F3e7PsgsE -3NViHVXE3nxfjtbPkHkSSiCFcscC6XLnmS -3Cv7GtuL9wX4JEnf8Q1WGYDaQpBNicXBvm -35ix858Ju1CNppRtBneMNAfxG2rACwRAQd -3F6Sg4e3smKmT9pDCUXEK1pMKAzBna8xLm -3LDVkthExgq9cweTv25vDReMiuYFfUgEvB -32zGVSJMzaFWW6b7mJqKFsh3Jj2jd9GiK5 -3PigVb8hCrtepwnQMiE3x73vfcjqiTAbke -3GDZ5NaU3mLoxJc2pGqJre29q4cMh59JeG -3D2PxQXW1jidtPuTKKNQB4MDteaUVrMdLP -3MKNubvYsKwQcceL1TrfRPumKu4RjK83Rt -32x9NuqVuiJGMZbAsMxpkffVNQw1fAM68J -3LMpHHGJ7kAiVYSoHqweudRUCZwo7SD4zA -352TLHGXS6XZ6e9ZSaXZ2m8fjmyQKZQkAT -3M7ar7CPiK2kFD2Ur6knJbwNCGzLdBMXAE -3DZkMbMdiMZ1nS2UZvcZity1wpkAoVVbMH -335G6mNQ6aQSY5MWjQUunSkseeCoN1YcX9 -33ModFi2E1R2YZ2fPEsMW4kKw25VjhaiJS -33YPgjFEL4UQmw4FepSQR7VwqLNAVARa4L -3QbZsBJFM6H4DNrpyjQTXvhy86FMYDN9Xn -3MQg8NFP5JPM1HXxGkpGFsujiba4MjYSuU -39yFUhpfzMM1XfwhUNGA2gFq98AYDr3dRK -3EFjpwfYWKD5TZobNm4ptosLJMU2gAYJEe -3L2cBMvZzfgdY51ZLCr6PaEQEJFhpwriCZ -3P1w5CQ6ZZvStSFfD3GnxrttcsCaUfDBan -3CDYYe1zBt7gmBLRQsJWf8N3cABPoaet6L -3PJmBpccLbwXhmFum9UJSxaZeb7eAAE5QJ -3JBAYuq3ME8sFwctdX8iYYggznDMvPaBs6 -31zaMgQabLnBFrvn1gaZa5oA5syENUnwHU -3Q1443pfc5MBFwc2q3prtLRQcAbaxHXWZ6 -3LsDJ4pRtTWHEe4xmRhQ8uf42VsBFjtweB -3JsF18NmyMYyGsY4apPvncrvxwF6LyP6QL -3Pcxg9RQ4UTTc4aVnKG2ygkh7yTa67vkAE -32duJGrEiBv6a5pJSsprFAnTg8h3xEQakq -3FU7pgXGTUYcwiiNKXDDpMYJ1brvQLb71M -3Fd2Z2th4mhZpDvz1ptyYgMJDQLqJHA7uV -3CRodRx7nwMiKMuge6ZNxVtb71dwSatQWU -36pzDCxst2JR4pGutVpPU5r3AZ44XRXEeu -3KCsset8BPCeU44JMWpNqvnW6XEuiYKJHg -38Ci9nN7f65AxcEKTUnb6VCEK9AP6sZywt -3NFcVLpa1EFzPHNkm4nqyyyenXyTKpfLWG -36TmMnFzarcsh3gFWugyWDxGCXLvLRjjBC -34W6nsHXCDyKsMFLdoqL5CJy3HNRuEYUEf -3Cett7XdEnfFhJfEz173o6Ekxv3QcYr6b4 -3KkPUjJEs9g6LDSwB5ANpNQYh18QTEdjo6 -35oNS1prDh5VE2RFfQbVkE7DFvqsRfDPSe -3EuXivN8twhYyMhjbjfHJ23dJisbG7HPeK -3Nx6mi84QzeLkXZhrRQV7Fh5UaKysErVvw -3825XZHbYNTA25UWpnRJhtDaEexut4F6Ew -37VEf2W69un7yBbJMD8FNVNL8wMSAK3zhq -3BeUUDtJgfdRTzxbPrDjgfUcA421KAdaLQ -3LDEnopaXrXgpgnvvzT7uVgzRX9vKBacpC -3Axvjt3qu9Y6VyouiXHjHBMNQAY6oyt7Rm -332KqgZwEFYGMM56uGPr2QHCLAdaadehKF -36VCe7j8HjpjSzix8bEHWZtUybQuwLHQeZ -37UhgsfcztMyX9QmrVhZvdd6NKETnqagAV -31y92XZqkrhRDyzeBBhx3bVrtDMPDDkaEE -37NP7dEb2dueguX4GZoLwTXhkXKrdQFmiV -3DiCTdRUh11TmH6RRfrXqeib4WJxevdz6J -3PjjnoM8XvqH8yGNxtWMfj8nivsaWLE2tm -34BEc59phsNm7gT7MCbS1HDbeHfqUxj6eU -3GsJQxiT8qFjJr6uxjcMfHwFtXCkyYckVs -3HxLvEwDnpgjVBCpM6u2J9z8kURGYd23ED -3KdyY1LHyQG1KXuFWSh6J5Dm7ggyh6CeUf -33Vrd76kB6bCTBsfX9sgChDGrQW8fe1s6R -3D2pyB1GHgPST8iwKuP9MEqt5sJRpfJN8a -35Frq1AHMMfPP8mePuQXwMAwWjK8bEz4LR -35fokCsje1ZVjSsTZQV1qb5eRHTqukTppJ -35NimRyhyrybvpsZ4ogaXo9sg7qsqchzd5 -39SGqPZQdAUJQjniDj3M3umyQwvyityexf -322qxJbFP3gT2rkBJsFYfud5qYZwsDJYxE -3PEHhnPTehWs3BwKXyFHHnZr32bRzn3xYJ -3KGRgFXE98cowTiorGBbNLNaHVSev6MMQd -3JFR7jawFMn9Gz1ATRmn6Z8kr7ep5SrAFL -3Dyt4HcEiKhDJyZ3wU7RUTL5yRopN97MfT -3KWPJ66EtAgeAXXvBQ5uXKvTwCwCgGQvpf -3EnAvVHAS8AdECuXqJMC2FaLSc2PL9Mwhs -37QCmARjHM3sGjowXpn6ENRdrfTdAU9AMp -3J2a4AjBFXmzo2gqH7Cum8Abm4V52iRZTw -3EwWGjD3zgBwZuUEbiy6TnyMCrnHxUCBqA -35pWJX3mL9s81Vz3cyhbkEaG88TmceSYCo -36oc11KJ1jsZEX3Qpxm8czYkHy9cRCrBLJ -3BAzzDN7JsBKBGbsLbh8EWkoQD8N8E4ALb -32G93xTF8XLx8AZ33fdh6aGewX8ybaz1sn -3Mi5Twdc4F312iBsdAHuQGPwnBidNhKaBi -3G7HrU8mHYjsed7zbBBF8PcRaUiSj7aZmt -34jN9S86deYp882RBTrjSFAbdbzSUNY4z6 -33GAxfzxCRaYJoAEY2Pqh8zd5VrLBdZuAF -3Kn3FsnCXqza9W8akvf5tsi32odBnHr39o -3LNFcko4unTsHQ2o8X8xLXvfk4iFJm5r1E -3PyNiwCJcs8DpgkzHVNz6fMk3ugBeC2A95 -36mb7vtrer57YNeP5GCfUwosCa9BBfDZb5 -3NsJDxnpNc9N8puDLWfjDKMFtUNBbZp3Hc -3BpCLWRCatrLYe44FYjgTTGcsR35pLfy7H -3FLwStRmVH6aVFAFK7raLBfXH4NeURZd9Z -35v8YeFJ4paQ6gN9Z1KQiiYo7uerz7J9Y3 -34479qojHwRroNdBppKdFHW6cqdJc2iY6k -3ByfP8cSYaf8fb3DBRz1ohB1Fu9M2NG4K7 -3KrFJkVRYQgNVkaKdAEoi9zxa4ZwdFe8kY -3J8GXdgPMzzKfixvifD2Yb85ok7jXus42N -3BjiBqB6W2uZjLmzBGNezHw6uuHVo4RKzY -334aMKT1aQdyR3VYv1ER4psHDfWsvyrRF5 -38VbRyQu9pRcNyACqRZ9n3ApfCAsBxAjLf -3D4JZDpQ4F5weKk2Nrhni63ef8ojBSQ9mB -3K5224BZFkbNSbWADwZhVMvuo9Zczy4sP4 -35s7P73aazT3pVQ1ywPiHBBBZBrimYhHEP -3873opZvjyV5JjQ4gmzMFRaEfZ4Y79J33m -34xKianFVEGBhdKwc5YwainxB6ZE4q3Zds -3FwKa26uUVYEWpi1L3JDWeUiSyhMjKsaFD -3969meeVE6zPeQsNdvHt7btqnrTk6bR9UH -38UucvDQMKA4Yq4GMgwK32XvHo4ZL3a8wT -3Lr74jdUVb6LCsb67QTiZPhW9vMKABr1Xg -3GZHkYP1rk1CWjJWWSN2nUys3pFAtqkSjm -39d8Gpwh8WUYsAKJnh6afyGNkMrkAhiYoD -3ME65cMCEEA83HG1BKCe53RXZQ6QoDQFmi -3Lo13PokU3tSb3FJEsJxzL5QnEbciU4dz5 -336HdqYYJ51D7xvtKkmRWjtptVxMUEJJx2 -3GHZMkuFXXjmyuZnHiHHFyLe7sw679uq2x -3PDBSDY1QURNkoX5QmXPuL1KuBtkDz6dP9 -3M2rMLefRL8j6sDXtFQeqzXwFaPJUtMpRP -37nZciSNNGvMXXGUXRmasByXeXLXiYDZJ5 -3D5CC3edUBcPCcbgqpx8xZyK5aabbK3j89 -38wUdgwsaqus5XjGmoVU8xYrB6jM28Tsiq -3CqagfyJBQFFuXyirLjhbXqWNs6PiMGoki -3Ak2hdCgLBuBwURQjqncKygf5X64pWWPT6 -39JMm7avPwCqcnCZDmvqVAJMgJKNBBJV9k -3HxmBv1MHuXcFeSETZX33aCeV6py3xojoQ -3Pg3dpEvSj7XSt5phQRBLjZZhWoSb8evxh -3KhkgGTbHtnZUD9CkeeahkouKaNX8zsdz8 -31iLW8ysWuE2DHQqPeFcZRroq8D1TfpRio -3H6NqGrurCB4zum2tx1oFsBuegeFBb3vK6 -3BdVZJ4iynsoUuSxWTbmRVS7VtenYDBYW5 -38wz17edLBYD6PNj9SERiqVzmE6XHwYTqH -38tZfU1j4PYZ8yX2VybwWJZyDyMaWzKxiE -3PdQAFRfbcMW6g6h4mf382eZN7cNL6Gcs4 -3B6Mm4CmuZSqWBKiM3RtisuE1UgdjpKM3H -3MtxJfLTW3i2Z5A4pBSyaPmAfaLNvZsKVH -3Dv6DHr9pjtjLRUGwZjkFg8EtKun8ApPWU -3NXfvFh3AEhmhZVAWKdyLJhy8KH7Cd16ip -36B47RAwSQy8zaUAqrM4BsDCdSkyeqqkDq -3HobvKcH2LDhxk5BGWHYKJaTEeBqeZMmkv -3AkkuDkpeWDq7AKeHWJgbZ8YmrxBc8gMCZ -3GriUoJNuiVrgvQv8PqmEcb6WaP5qQRmVv -383AmnZLoDwxSjnHYfsgaDkm15BXkigrNt -36g3Mh2X3grhSS6n4n5U3hsdCDXDFVeYHc -35o6qDmSBvdmPpWHRj7JyBpb1fMoSTyAhG -3CYebWRsZaz965HSaCGfkmmVznTTLapY6x -37L7ECLfD3RcX4XhLhPYMzdVLqCpp613cU -3E5pAruJDF9QBivv4P66P2BSTd24BvK8nH -3N2iEDd1RNmeav2ARMyCzG2P5dyxBoVEzi -3EysJig1gqjRiUCChi8EChFxYUfxGEqCqq -3KSucKayfg25vA5WNmbTrhe5J4q5bEudpc -388xohnG539tUw4ukBfkDBvTYwF8Wegc9b -36F5w86H7zT6yRE7FLExsrR7P6UE6YnJ9a -3BgiXKovDUzXXk3wS6Rp2MtubcoaksqKeM -3LGdebUQPd73nqNSbxi8SQjDivStdcaDMX -3DCpZq79NXn8TogX8eNGUEK9NL6c4BzPq7 -3FTSpTNhkPi1itpbW3Bkr65w6V6nECpBHQ -3MfJNf9n8VUe9xQSSwY9aUFmsLy9mRJkK2 -3E4r4m2GyKrpgc6p9rj3L1CVkKvTUbaF6L -3G6ZGcSWw67RSDvVpaaHyHEkykp7QsTVFt -39VK1h2ur6qrUkL2g9nghuXvSDPJCyGECC -3Npnt5vYtmVFnntnxhwCfm3912sY5UemkA -37R3a5absv7GgZrxTJccEzdE9JSdYdnD2g -3J15CHFwZ5r6p9vzhyGzqZTqnUeRvymkED -3KfW1YaY8cVpZhnutyzDHJG7FHxNmNjLah -39ynJdufXkHTM2v7jviTyC9mwt58oQcJcY -3K7VcyyWL3T6yXZq1owuDtV3TAT92bbK1F -37Ri6fqrp8ZbQJQAiCR4ofgLrbqQHuMFpD -3BqE1XpUyxh34id65KBGzDn3EXzzGEoxgn -3Dwepj424bvqUSs2wJUKafj7Vt3wgoRqbT -3CuKTPw3sYd69CGa963tZZmwfMGeYsP6kT -3L8Pmbnc1Zt3yxzgL1udkjzQWqiaawcbYK -3NEW5NHbU8vTdDLJxT8tixwgPYjPTSVpi9 -3MXzkT723z4A2rsbC1xozhC2Lo76WgepTf -3LQ8uwxCGXtqghTsNXSEdNFv6Z6JEVuS6A -3873g235hRVXvejfoRRvVZ3oHFZV4wHzVq -3Mckr1sUd8wcd5MDTUgeT9yXMCfMFX2ev1 -3G4RdoW9mCe1JNm6k9GEjFQrENeefRjQah -3LSBW4yDHx511wKdTA6v3KKEkeM1QjjqZg -3DEGi1GQnC1YdgUgWx5r7WCvbFewRte3AF -3KxHuNx7shm6qqGJPhdUS28GgoEMJKPTPF -3B9PRG1ubXft6aVC8Q1cg1xsZeWKpBh2eh -36Z9QSTzgd3MJbJjwUgwfT9RMvmHff1jnC -3JoVh2bNT95X3pA3KKLWmu8GJZ7RjGvwH2 -38bQacuinr6a4zFEacXxqyJc6ygMfaTALM -3Gi5To2g1dsGGiz26ecPLvDHqNu5QUYVc8 -3Ge5vkSvRNfroCuXirRXxt74nGv8CSRHjF -3FsDp2hiCriquidBjTsUjexYBj2zmM348U -3DABWmf3AoruV2bYCUPLUD8NWXXZDp7Epg -3JfPGJNNucvn2FrbLYY5YiwRnjLTLvseAB -3Cn1xNkgn59PYeENupzMgZdRg6ArrxYHBH -3NMZKpUUVyTm1V4v2Sb4bUZfW25QAC2asN -3E5jsdBDHHKrDUv5riyUAFLtKbkerGwjX3 -3JMnCsDaS9kEqCngXaZ6rQnWf5jPokDC3S -3HsEK5tv12ETRT4Q1gqdLyEUXyHa8zZHG9 -33rimfZpXQkSfB26ihZxfcS84eeSpH5DSr -3PXbexx34Pihfz4fo8xgRfTXbYx8j63sU1 -3QpvGfQcsyZcXiWv5AFiKLCt8PCmpYQvPp -3KZ3XDfRvTvnLCTDSWmd25CtYvsdpSRfgk -3QMwpJ6T32nk5Heatvjhsrag2XbgLJwaXa -3FrhBmN9x3JgVaqrbMY4CMEjphLuvbgLFR -3E6mKPpStmKZtf5QgdWxbFgQWnk4ToKFzL -3FvYtu7P3nEVoJgj2F8yrxHekJUHGBFFeE -36riFUbNHWpxLr3VcXfTGfBjXmSWW8bB3R -3GG7RLLW7obXwLXCkjLMEKPboYwUWyBgSP -3PGaxRFzU5knpKYGScRP9ReedFYgrsGohX -38APUN8hrzpEjCELtATDLVg9UoUWHbuW95 -3LRXv3ZY2KAZsm7Q5Y4tRCGzmYEUYXkFmB -35pKoMaFYUFrvpnUGRy8tecxGPZmqWQC33 -3416Jzguu8ZzzbHh4eegXA4XJLfP8e4tgZ -34vMpcNBZaVbwuc4D2qwW2EppbVRmzB89R -3MCAfqT8grcKox7RbJfEb6nHVHMwsPvWeY -3KzdQ33hw4VnpgjVjXzigKM9nCczUZ1Nce -32pWfL2gB9UXVqZzFTgQ3PnUMJn3TCJHrn -3LinZ6NHfFepUShwCoKFwNEGdVRrWB5ueB -3CPyuG8DmG42Xyb42dSWSMpCb5eboM2gYv -37ZmkrhyqqeEx5iGkRLfhiyac521f3xY7h -347jCjndqDSFQGBw4VCDqisEWPXrLE6YRD -32fmYRwQfAYuahCLvKhVimUAEJ91Kh7tGh -38bHBJt1VHFKDVmd16Ne5LDoyCV4Sad6M7 -3FwxgA6jq4bonwE8DQuyfkKEK4LZh38By2 -3Bt1ndAiWx3rQ42touuQej6z28U4k9M9aJ -3LxLxeA8iiyaNExxurHqPJykdcty3gZ58K -3K1yNQNG83E8S9EwFqj7tsuc3zfE1MMHwo -3JCqnVSMFhXThHU8dtZbcW5x1L2RebksGH -3H7Pbv8yRW19RjZrcfXYmKDwFDcuT2EZ5m -3P9vmbxAnxKiuick9RNK5oC74GSkjsjMVc -36M2zb4RSB1WHgKRe7JXCfrzaMqrStvnUD -3Jz8NHaRT3Nb8GaWuKj31ayGkVitY6BU11 -37Xe6xpVSQEVgdpoL9joJy2JrGRGYd9GNf -3Pu9WLcx128voYnmFVZz66RiBnvd2M3GM5 -3JE9Zj766FJqR11NBPgVnyKgTQHtjkYGHC -3EtuZsjYnWGQwv1JuMoSqmoi9rkxQ8DQ7N -38FdqDxSS9B7pQrT9GL9CruUbazLD5Vyhs -3JoZnfyjKBSvtbm9VtPz9xeuY11ymhxbeD -3BG2ACteQskkqYqUZvTRFHxtVqUfMhsNgt -3JyJvuWR5doyqkko69Ai65f9X74WaLGTjy -38dV8CvseKpeMN3SL5s3sgTcM2t6rhErhJ -3PW83Zaa2pdkJx7eZiUeHWpe5Svi4qVoqa -3GGpr5CAWmeREzSMX9h1RdKoZfBy2a8mkj -33C8WDEVhp7FzsHMScJSNGhLdS3BwuAVTL -3963grxQNeQ84KCi48MeteNhMPETKPVUfu -3PTRYahh6q9MwP8zAtwjkmYTRtKCXc2z7v -3HBuVsDpnWmLbaUpvEyvwwtzh9BgGfbvVV -384DUfDaw1grbBPtvbC1hqrzRhSNXpU4ny -35UAgLAy1RtdVLK83puvpGYkbyhESLpqou -3238wAKmZhX3vArPUqUQhayjPYBc5uoAs1 -34Z1VXc6qBwtf7hdo5WqS7nCxut2een1dy -3DFRASPt8YRWWhE9RHNxibduYdaGMnDyTs -37h3wDtEiGPVzSpxgnRLu1fyYPamzwZxNa -36oH7AFMGESxoDbg3j96BhdL5k4Z4fPsT5 -39oaaEEVHex4XAoFjL8qwHF4Z6oqK4QN1v -3KD6gAUuzxDuhuxb8idGPUYYyMpb79ReWv -3LupwEk8w3bAMxBBs6G28yujLokoznFcMV -3QQdZQndG6t2C2a4QLLdiCTRe1a5zSUzNL -384JhPdnhfFM3Q9jBKWdj9FT3tmKYrHm15 -3MucVhSaj2joYRBeZkckw4yfFu18z5qTJw -344TDdm5zHuvTif8g5BRm2m6PgoBdJccrd -3M3tveVQDNZXydFzsDPkD8grxYWscTYF1X -3Pweoq4GXXuzJcZm6jNfK21QZsFWZeXZXU -392JnVWv9E9FhLccbY5FbaU184R7vMVpRE -33gtXgHjGdoWxvFSFaJ4nUUVPQL2rUb4bM -36gwUGDK7Hk2QE5hrGSbpejoXkSpb2iioh -35VyWY5gDdySmTpb79YcECpmhhYMP3s3GG -32LJe2LZSC3AwhXLZFYjN1hPr46oQ5Kfhp -3PU1Rs8Sj9p6pHQfYs1yY4NjLQtiNVP84o -3QGco5YrjUAjYwjfD5q1cx8o5mZMoTvEfa -34u8TmFbLD3fhL4RGskRqBuBsWzfziFgj6 -3Et6fcVpBeVPaLxwmuydhie4tusaPiQ7VM -3HToHdN1Qni2JnPqr3Jq8ew5AbYqfveqRz -3L9j6puEuSxpPHzTH7sZihSVkdCf7stwuv -3K7DqZFy2oza6hJbMrthsTWsvH2ktUjCn3 -34tmX1gSjwus7mWpXA7pt8RiV4o9svWWfG -3G6AGUybf7oL4uUBP1zL7YRvZicmYwVEsy -3AMmXxSLs2PDowhJVBok1n5m2sX1FB9sXW -3Gyk1fvvVYWvFcmBAtPipXo75KaPSagsXk -331C8ZF44ZQxqEpomd4PS6CRG4s6JBGPog -322yqecDDPpTtV4bGP6cG4AbHCcfRNGGBE -3C13bG2BRycK4KH89HmpALBUZGgHhQV7iW -32rhNQcSM7hcgzCaMT1zsrbKHRGrVJpaVp -33ataZZ6Xq1uoAhqudVBumbJgETeS7UbkW -31oyK9nbPUzWmTHyihz7DETersy6G4Vvaj -3QVptpwJfHgCWNYh5ktyj2utLYW75Y6QXu -3EcAY79WZQSaXd8RMBEHHKG8VNvgY5GLHf -3Kdo5TpR6dov9ajTybS4uRapQm7QAAQjoT -3DUTZHme1sTMn1qxa4qNZjLKsTWeDiyBuA -3P23VXyGUPyvGHHkRCfmr1DxJ477KBoSMt -3NT3eqqUSS1aRpETEnJZ6m8S6nKgxwByT5 -3F11k6E8PacviH8zhfLeHvuo9QtpLW82Rp -32e5ASKR82GZb5oe1pqs4LHa3dbj7uU3zk -3BpcSPAhEu8gB69PrHabEfbveWie8g2Jk6 -3NSCXNZ6GPj5tsSeaeedco4aMMErrMkRdW -3Gxz4reGa6ezGZx4igvtzf6zuuWeretv3c -3E3HfS4EG2ZKqjsJRSSvsDgBCzBHywBx3D -3JJRVppoVRtShAD2nLx7Fo996uhJE6AtwV -3AfVjQywShjtx8U8fDoEEhzkmFCdjNgmAJ -36Dxf3f4xJX7oFcbRZ8FtB5UqYpDrJvsEd -3Mq6hXabC3d5Wref6fVpSUw4mLYDcNw6LP -33APy5W4LsUVxT52kYFVaQbLfwEZxJaskX -3Eu4Fw2EaGpNbsH2BRS65839AGi36qvG3E -3JPqdrz3xmksguAraxsqto3YHKFXcGswjN -3EDj3DUphD44xf2rKGeoPFbe85DWp9oQ8n -3DFFfAifmNJmPNAuTUkU8jAZtUwFzYF63K -3N6Hi3w67ibeoAMKav5cUVRmY47v9QXywi -3NtuVCox52hXhDfscA9gADpkUKJiHVQ3aY -3NX2xyi4r4CBErWG7LA2aCZFKK2d2jmqoK -33KA2CUpw7UzEtoa2krGjQrmtckYXQrVH4 -3Ku6TWXuQQzSBDJjnVK5tALc3apswGSj78 -3NcUVNYADPuf489264JHoShD5cw4CDANEK -3EeHzmQNQeyp8SPgDqzcw275hgmSTCm5Sk -336XrDvsMYEMTteTuvkLaWDBm77ghJGPvW -3G8QwCydLjRGBdQuFok8idduyzqqs6kQLu -3AKS4V5DDRzkLRYk1RztAmnDeVzvZoAjb5 -3Q5nKCNW2yFJKBrNh4AtMmxeBi1auYJGPw -386hp9TxwJAczNcKGgKc6dWhnDyNo3MQSd -3QbpNozMLG6u2SNYu9QJoD7AUPZswCKqLJ -3E9vFoUPEybZR3fAUM4fkEZUcSzoPrgTAP -3NXWcebNXV6RWuWebFtRiWhnjoeubTpNLf -3HUVkLGhZeVchuws922pmxJj5cNqJdAdSq -34WtXdudwq1VWeZFq37Kx7XgHyuWa6UcAN -36jbniKxxd4iur2PSZtdf2B6pExVN3L2d2 -3KUR26UeaXPwzuhh8tqk3C5xkrfLaQqBxn -3JZi6P5B13PFWrTxrAGRzNkftCyFx4qEDw -3QK9TEFifYZNS8cWvzKrwxDqY4vv7ViZ5R -38jbEk3uaJDatPKqvLaiy2HP2KuEUfgNQm -3FpPymnXF4FWiebk8w5g18jcPk8iPn3nvX -3L4UfqHitm8DcNCWriv2JBcQuMtoFDVWsY -32bVn3qt7uWqqop5km3hXzkkM2NLa3p6QE -3E4RYTPv8ncNhdvtUdQLBrsfXsPDMqZD2M -3GJed6dMb2inhm2mVD83b6Ut68fEeYpzRb -3KhPsW6jm5XEWkjh7GpH5Uiw44exjanTS9 -3A8ojFj8GKF8Djfv53PAJiyk46mHc6cbM1 -3NyJD1vLy1bDyjZ96nLGGfHy3UzPpR8qSJ -3CfqGxcUk3JUPXwsgmt4q4pSsgmvf24uuu -34n5jzBtMk6mCkedEg6y5JpZJ7BCsJmc59 -31xYURd4Nvu7Ncbr7Yz6iEs87WhAEfdmma -3AMe1oHG26DG6PPiN66sdW6kZmiDmDyVrj -3HLVFGijGbMz55WPooWhoNYpVPpnDFcDow -3PtgCeTwoEAM6sAVzNLzCWd1PdGoVWnEgy -3KeFfhQwmeNrPdxTpYMeXvBRCYqgVUMCeF -3N394cZx4fTbW8EmRVTWxjQzAwmgBBcceQ -3PS7W7z1UYssHbLLEugDJ7Ls2ebE4yeYeT -3G4CZDFMx44zeeWR9cwyyWdyv8gg9PFQSf -3D1THALR3ZtqcHMW6wVR8acAfQwxFCw5NL -3MgdgXpZQDwwg381Wd49H1EWp9QxTXwdGm -3KkQjrKmgKiKYej2Wcegqnw52zvKU16q23 -3EMqpANFsALaoebNsvjuXP7LvipFoGk6XB -3JEqZpAQ2pZRpZuZ6swQ9o3yn3d5rq5gmu -37MgxVT9iudaSnxZZVBARESzpm81q5aJwg -3Qmai8CmtjEGCvkGWxSx4yFnXKRYNtXg6K -3DQn7sfiJtCZeK61Noia2VVzjqTf9KMKqx -34TGM1JDeqPHQMFctJ5kFdNnHeSwfmJRec -3PGKrM19jKWcdtcbZXebXhRQtsA8i8RGRd -372BLLoaUWLptS9LFHLW8r1AiVKnepmAY3 -37VrQ3PAXaRoqX94o5kY37uhshMDjF2KtT -34oD97cNHaS1Nfh9PbzUq2KnWHXTr8Y6BH -3AiYMRdDgTWTxbQJyJ6TsjnaNbRYN76RNc -326ivxahkzsitja7GiF7r6goUxriCPR2PD -3D5Xu3RDoBHGwsvi9RAcJqGyt76Ard31k2 -31h9zh55ogu7a6CpigtY8EMJpnYZ4N9yfw -37ckwSdsGUdH1524XDEZ1E1fDyrJCngb7P -3AUDy7eC7FipZKzAjr761LYTs2ZDfYY8Mp -3Pzx33ffPtwJpFUb2TGdsN27V5SvVU1rYR -35KCbnt2Y2KA9NgM2iqcZwZBVGmK5qr6fa -32B4D7ogVZCXjwJ1yzNYrqyLCaZ3XWxmUN -37AKUjHMrH2LvzTuGxy6cxrui3McAq8H42 -377bXxephWQ829eTTDW4RmaBNzbcsUgRoy -3L1zgHZkhuNmK8Jf1thVCEusS2CcrkTXax -3Q26QHUrbALfKqG7XrZvh5YhNQbwHBaQxt -3EnyuwcYQuXZ9crG9BJSWAakDFbT6fMFLv -3Dj36mFVFs3BEJxFkxoPUAmmjNw1VT8n4S -38kYHKisAeDzsgpvpN5mJr4V1mwaSdAeaC -39Z17RUx9tnKRXh9LUcjLyJVo31dRMm9oz -3LAku89d36W71vGXKsUA2PPTjVn79WfxPU -3QAn4d7rWyUvJUNVd2TeVHpPk2DCyEXTZj -371R6XsUbm8mnmLMLEQyasxxaCfHk9HhZq -3PTNyXLNtCPrXqSQ8hMrkhCXjjhvDvqA4v -3Bd7kSwkVXSXcbJf7FrLfXRxMga72BBr8q -36WbT6RcGLpLYEaLZD54Vg7pRAbnvzpXzN -3H1msAo6BeQj963Ka37fVzLmh6ose9k6Zj -3G1hSgKC9VQEWP6YJsTRbmwAxzd5CxQVp3 -3F7WnSJef87dXrrL5EZXbZGyRdM8ahJrsM -38cEfRHYTLtb456mXwoqwcx4P95SpRKwWg -3AfsrCfhw2P8zS2XScu8g8saa61METt9HU -36a4iZsNqgorfJPgJF42KCcU56ZptQKZa9 -3NoPkpic9j614DRaGJFJD43MNuRfwVLn9W -37ZxBrr7FEjji745YJtwRuDzSZWEnxWzsa -3ApkgHmyaUps5AZxRtQ5vAP31g8nFMxEqJ -37Q3xJy8VBcgxYuZRXyQJqEGZosj2Txi5U -33WJByC3Rwn2A7nFgURk7bVMtRZX41XuPe -3BbekXnnZ3Kyu9hNpBdm97xfFPVBkte3LM -33sDkwmChfndeUKYk4zXvWghYQHP84YWGv -3B6qWBrMzCZXxLFCNFCPNTskNVXikBsrSP -374N1eKAJ22a2BuGxn4u57Gj15wPNVDaCx -37FmjWUHQgyqipU4LbQfWFqKg3vSYY14ni -3Km1WVS7wMEcd2TypUGqfgCGZFJ6ycoP1J -3QqcWxgPEnDoqRovcpRfdAdjfULTsbDU9r -3QxrfTMKT8xH2vANXjHNMbYAdahKF4PQ64 -36BBzw6yaDmaFKmkTYE65L16uB597jbpdn -3FHTnWoEBBwSeTPEiFCRRwt9fLYKN3iSiD -33UvALqpU1e5BAz1VQhwPPFHZPVv7p8Hhu -3PRgabwL46QpZidaEurr5dEAMg6V3MnKA7 -3CwR8inL8eQABBNEasjDugRneoreLKxDVY -3PgUr7Krm1TjezCYZ2FHeXC4W4RGuUaS6T -32yCZUG7eb8GnWciMk39yHkwiLGAemhmMp -35uyDpiF73rTph4Dcs1fqDmAg2xH1VrYw8 -3HfXHRPBRH2r9srLjttv1PAXBgvUyHAa9b -34bwXj9N84Ko3wEz2VairfLwAkdtK4fMiK -38ANZCjhFoDq5D1XnfHENUFPwX5DMFBuM1 -3Ee9DoEpfEyyRbtQU2n2FFFdDzdTpWr6J9 -3FR5nZvJuBPYW1XLVUYEqQ7v9t9d2Wx2zG -3QUW1FWApfvVGKYci7Qzaku6o8Cd7ntPim -3FEXWe4pqxLYek5SaoF9YpACzxFxYMQ32X -3QuZe2ivpuSMjSNX5AyPUpi4j1ff1LnztC -35LeG4qbe3zaqdz93rfpCgmnGLavpLJoAk -38hoUikNYnrEaDZ7nsahQngiwgZeSQvtmi -3LpHMiTnzu6Gp4EzkAWnRrQeTXd5XwWiKe -398uU6shaZvrbNwMC1fHhabcMBzY4MkuJF -3P4j2yEjsxmNJ3cLQKyznZNAKZ6MZkiBG2 -382R4ih4fQsbdpwZu3N5nqpBSBm1gbYZxq -3Kkxw8cPAu4giSCwWrJMHR5myxSP3KMFLZ -3GcGmRbizLymGHZGh4pBgQY2z7X4yHRszd -3PGaArNyzvcLHokRi2UsaMaxcxGMvCJ9ek -3EkJqYm5fTNfyqFtiPxa8CbfLPXvFuvvi8 -35vBBcypq6PX22hTLxpdbMne6H1qgAaJQY -3DiAWDjsrbMcMRyar3n5GK3ER8Sjq3GmVv -3G9nFs3Dsd92ENDcNjwEGU7c8WTEoJU1FA -34xJRzoqeGfUJujGudwS6cidR7QmWK4swV -35aKKn5DdEZY929mJS1N5ZA3jim7C25Mhw -38wezK2dp5kdApVtK27J9SmdbvTRmuL2kg -33yqnhbjayKVi8x2qy9L3kAwPR7gE4djmA -3MkvkGoBTk6qjsLrzKYA7aRrdDkjwWJi3j -3BfDjVgDPAonFjzKKznTpm2Kybu5AaveQm -3HyQZ7K8k7ZPLv5ie3Mhe6BuqNmMx75tEz -3ERiejrsykw6sRUEgmnMzKTYi9UX7GnHvS -3BS4Ah1vd4jhqD6douYDJkc8EG5LCuXnTA -3M5F5Eyr8ZL5nFi6aCxTURrH1amtEz1D8t -33P7K5LReKjbUBmH6ZLgUthNfqhN9PLKXK -39WQEyZUNv8CW48LfWKac7qs1kyX2Vtgph -3F8gATdvN9REgA1j2Lq3WDGYcTYVAoD72M -32sooUAGTorZN6xayPaMzQGaAcP9tkvXko -34G4sb2wyRFYbWqqGyC1zXeQSTEtRjjXZS -33ZNBLSyhEnz5aNiqmUuShTrpaNp9Ss5kp -32DbD1f5QnG1BeDvfWuer4FHN9ni8woeJa -3B4pBkG4CH1b6vncHE16KKkUAsqxmTGmcB -3B1PfqnzEjY3H8kSDeEKUYCdUGWP3joK3v -3DfvkAnbcgpAy2JxKwS1zMn9rM5p5Eeq6R -3Lp19B1DdxzJmkiU7c2daNS7cEowE2upDC -32oNHWdwZfKszRUdfeBQ76Ww9bygNYt7fr -3GE1Garx8vyeZrWpBE6U8YRmgRHxdHWxvg -3BVonLKq35jPsALzWaxuNC7dcw5v4NtmS2 -3FgoxEKWfj3BqMJcw2DEB8ZMtgL7PREkE6 -3KofYPedAWTGEGgpb3i1xB9Y11myJsd3Qt -3PxQ8ek3RiPUbwhmn8ivYTcxpbYjas44pR -3EaV4vkz87mRa3vp27ftWBB3FHcnZ6nums -3B1h482Zp6AWapBWmSUM1YfRu2VkoW6PZr -3LmNb8ZHQLfat6VWkSb3UqtCko39afSgrN -3C7zSX1VJnr3FrBpoTofwDYZFPqsaRK27z -3Qkcr9b75mzeNPbkddkg8msqUvYzWv78xy -35CNZgMM78As89S8Dr4zDmykaMitW53MHE -39zk2Wb9tJu8FPX2ocmCbYAdKm5x2PkfEa -3Kui2R8Vjc3UZB6AL1o436cHWifXnZjqYJ -39wAQFh4nG7eWFt2EuCUyHp5QyvW5FtZbF -3EfndVtRWrKPmaV4Ehxp3Q67TCwvV4nHUb -32yF6vr8cXLvevmXoyR6MaSeSvpkxmhuX2 -35Vd354L9SQy9WjShxPzQbyD6naH8R2MCJ -38JEaGi82NEyaHscy597bkb9fw7LkLRMK4 -3AG9LVSGU3CbgWnBpr3waqPm1VU1JHYx97 -39Wx9afXG4NRfZhfSoEP7dqPGtMT2U8djj -3BoqnwL3k9s5RQd8JfNSKbQk7AhXF8R9pz -33VJ1SdRvqGyZ6jdEr2F2vWpgAh5nWBXUs -3E9go3qp28WwTU95dCAYvbdn7AkGF3HJbe -3FNm62yMPcXesmrB1fJ1JDKdkqLFdri5oo -3AKqxJFc7ECb49vy1ZWB11f9kyY6FL6wcU -3E5P75hN95TPktVMhUvzbtGgCeTRmZ5xkc -3E1eqpdFkMQzteiUDgqj1Mt8AkKbMvLkhv -3HYA8ES1EGibwGe67iC7njxFo1Td25Jfk9 -38FMnXzE27aw2M3zBDuCPgeuwZCeynf1jj -35QjGWQfjysG5C37wQyCGZJ6dkN2o5C9Mi -3Hw5VVSPugz7e3M8uCezVNPNirec67QhCC -3Cj6mYsm2toL5KByExrfRhUswBx1FadjgX -37NUjK3GSf91M57k1V26YbehMSeTajPU5b -35jJNvan33tPNX5PSXv7ti4LCHdxJfiF5T -35ZX85os6YQYPN33EDDBLkCCHwpdyYsQof -3JaSa14Am1z3SR4uAmDsJopaHapjSCQzxX -34ZUm8KkxPD3CpjVCurJXiQKEfXJSTuJ3B -32JExkaPWL2c466g9iCajb8HNY7F9huZ1z -32k3fG3DXKFcye4RYFixKF1uzEZGNFueLb -3P7vDg4JWLpw2rqbdetHCu66ijVr3x9FY3 -3LXT4DdVqbStL5af2YTDgmw4xpyDHHepCn -3J2qFCrcr4PgiWtoDMNkXCvkGx3nT6AQgV -3GQH2L8LQoKrjMgQxi9MDBYXeGC5RyqEfN -33QoG7oMasHc5rpZhi4VQ8mytaHiAcza7E -31wssGrG4cAzzUTcejPKWSgAsjMbuR4dcR -3J62Xu14zga94taYtdq6eAEte2tE5yyhMg -3L3YfSYWbH7eTaz4RK1r8b4qcsbVfmHvaJ -3EzJQRAvPbNPJDLKiCusYDvZaAFkiDMMch -3MEivCvk6KGyvQnsJFRCXhbBFreXE52guN -32aWvmk4MgVHXzUperwJKzwEPKFbTn8ioK -3F1mmsQVfZUPJNgkYgnZ5HCnhNNyz8hnCL -35uEWc41TSKiuaEDyTyN9wRN36FNZPqPmc -32xs5JFUXWT19ZSwTzo1VSChUhuLXt1ZTc -3631GKAn5gyNfw8KgUpWmeQKmkeHNqU5z3 -3P4ogBx4nXtJ5B275NA9ZutQQg37PFEanC -3Po1KXZYtW2Nba7uejbk4DbE8uyLjp1kuS -3HDmWUNifLPc7bm2rgC2T5TXFKrbhBFTAN -3KCc9NwYBs9hoojs8F484adW3dX8bzFmvp -3FPgfo4dgJA21rgzLFo3oLeqnfnzD4wUG3 -32ZiARVD2SFaNMk1p3miV7Ybj8rU4YsyMb -3Bu9M4tWi7241EAR3w63RniAENqgRCxjhh -3EoExGH8hWKBStyC3ieczhzbtqsESPwqf1 -3Ds7Z8WtAk5qnGbLTiYcANKXzxJ6gaCVK9 -3M8uQMUJ8HD72Jnnw8jWy25kv6jDgdBrn4 -3M3EviwhT8YBdjngfuMvBH8NHQeii8wUbC -3475qbWt8ACguv6b5zk5LvwD2on88jexJB -39p6ys3nDprEpAC7SketSYZQiMPxoG9Xc5 -3QUqx39zpoVjxG1PVVf1ahcDqtNHM4TwPP -33NFRZYWY6zo6QGZZc3C1y9xbDGNaKwdi7 -3M3F3EQfPE6RjBVQQULWe3HgQ5BNavhFin -3DJ6ajYr9ivH3UJP7jbSVPtxusqN5Qdyyp -3Ka7vCnoHZ2UspUW65wwdunSsYYbzPs9JA -3JjHKwpt8eJfwKecaPato5YP6sxDq5XkBU -33dQDjJQ8eZYdnzNBTVauzpxQV7sFd7D1V -35n3mDo8YjJHmfkVypuSiseMjPceSuLCL8 -3Er9patZwuVuiTE7AuXXSjrphYxbnK29vF -3M9F6hy9wSFmguQRrqjheFQTkX8uwYUdkK -3HzDwkHDkhgmMfL7o88r9aUXK7goA5XZeV -392PDGNswA5uGNC6jtVqTFLRsMuLZTTdcx -3QUp4rwWXK4ZsMsN6s7KrxdDvxvsoU8xcp -3L7VtpQ3iuKBniP4CGUsYYqCbZ5AEvYqv6 -3Ey1WxQkYTPFnP8DY4Dp9jhGHd3DYVH43B -3HsAKftfaGxo36qSvZ1k3HRwQfixR7Hs4D -32uHyQDfCc3Tt652Qn5XuBrYZMCLXZ4Kba -3FWjLjG1CqRnWcWSp9o6vGuG8GDguhqbm4 -3EKwRXFG2rULo4NczckoA6mWLXbnwEvYvH -3Dnzp5x6dWCUJJJmdPcMw8RrazdTMc9uCW -3CG1yb6vhM8K4oYTkm1sfAdGiveuwgHFeR -3AoAgVbz8LAFSLBTNoQTxCXsB4WnUfQ6iu -33XcooLWsvWxgTrcafvvu4YvA6V42vZvB1 -3E6Qx8mKRdBqP2LZgu6P8nrpLFPigoMhrd -32nasn8j8RhKYLKsQzeP5mAzRTebZeukK9 -36vPGcBAKUps64vYKDgM1G2m7Q2MGg6273 -3FTM7KL43da64AaesPFBCipy2LbGDzhd63 -33uKo553wwfvJNpQj76U4f7RPf45HjSFd3 -3JhyXsEtXkXrfunY9HCB9zxvsRJEbzNaGw -3PnKwxAkSCtUogtfnZXvqpfpVTRFnMtb16 -38qrCpLpB3CKGtdma5Mv6Jyf9a1jQfZcnD -38eZBq9SLzMCvW49hZcgsmTUqGJz92CHsG -34xCAwKrJ4AJYEzJQMfcT9XtNYfctfjeGG -3L6BXFCiEkXF71VLdtKVtU67KQ81Bh8s3C -3PKKuXWNZiEr5JdwTJYoKrLc12u8cqbZEA -32uCkKpyv1zV9SnWS864viTe9apFkFwVPc -3CgBSF49jvv1ixSPM354jzZVzr12CQjY9E -35QHq8WSmr766wQLCT7bAYbK3Lpn5TFtjq -3Bd19Z3mk9U6ey9YMa4q38bwZajKWjjbna -34jpfT1WHENrGr775Fu2GNs1DerSpqaq57 -34uUJ1vCx3Jxs71GrvqeL5zQi3RPxa36W5 -3DikRPyZrQmPW1MuvUpCevy6kTZ9hZjpyg -3EDc3iz4FwSAJqEbdFwmfgimMzmFoUbnqu -3EWZn3jvnQbNcADZMSGj5L2WE8rceFbRXM -3Gc7M9UQqh957D35ynuiaR15qAVX1Md1D4 -3BLGRET4iCzYBohUYtDscPgPdvntxK8adT -3Mip3m1pDBzrzdkjTMPkzWyixcDLWEg7xE -3KPiwQSjwxwSNiXNdow5pX8iJmi7J2xTJh -37aCadgkKYmNRNrSFuaLr1RMeeu12snzPe -38ngJd82Vhe4tfA8RGtMDWeHmU7bcdzeCV -39Mu8wU2CJuUFiZfhKur4shUDeDkTMMTFS -37XJCRe68ec3S6hZH1J9yWAZKC7KsrNTgp -3BBTtCHnp4mPNpVyFZ2BnY4F6ndDiGsxbz -346cbm5fGxmEM1pH3oRENZdwRb4tNpeYC4 -3LNv4oSLoh9qGbZf4azpwhU2yh13381APL -3K67pZer5Q8TFc8iUD2WPALXQ9r3sj3dKF -3AydrU5Hx27fAb4mupggoPPhKJbvo9942t -39NW6y3WecvDMBuXG7xM5hhsBo9b31TzNL -39xkBUcgRu3voy5WhBo6UoHsKYQ8PLLLxu -3K7Qu5KsGAKSgSaexryZHdsTAQSLQvntVG -31smjaVs1hyLfgC86ymhLWVPYJUgZcqHhW -3H3khpic8f2bSe12ce4HMHpvAnv92gHfMS -3HhoqdgVPJV7gGssaEcPHrDfdCFrAzrY2o -3LEy6sCAQNpd3urfdxdr3RSBNycjHywQGD -3Cbiexxr4AM2ZbZ5DuQERHT1LncU4io9jb -3KGhVY96AmEdVdhWfJnL3Lv3w2QHKMgrSr -3JicY1kpgkFcGCrC32cj8Uine5HzZvvFaL -3CKNxfMFRzFSrCbzNfbyEe9mbZt8GeDznh -31ryGrfUmLUFxm6bNXhchbqof39P7GqCvn -3GrLNiQFM7Vf91uAaS1us2U21M4v4aFynW -3QuidFvoEotQCLXwcPQbkQMPiN2KQymrQH -3DGYiCKPg8z3Nn79orAC81jtLnPyk4X2Em -3JQuYb1Lp7ngHEdY7JJiUnyhpVzaLTnKzh -3D1Z44CQWb8vq9GdakcncWyFZG43HntoVD -3CVVGRdUjwQoBaDpMxtnhNACgAntS1Epys -36RdrQjESbSfouB4gdC4jiZEQsR85v4Jqx -3LLXAs8TdenjdfNFXK4N4TnkdcH94M2XDd -33hd9tsjk6eDJhvMEZ3khKyVE6VsBKmoCh -3NZKTQfdCDbfvCFACNtp95EXdzdLv5j8tf -3KGMqv3Xg5gpTmRCiNdx14sqZW9n5YhhPf -34z9e1KrHpatacnSD1CuB3yUAr7Mmy8sm2 -37f89V3CxB8QvMAmCU38R7ija6o78yWoDN -38NJt8Nz1fR2BYLtCsPeRHXddg7zZcUnoS -3D1nKT9Ycs6a1XCxX6dKKYQuvBS1CBLPb1 -35tirNjhqURj9w7HLigvbagCQjsQsXhyZQ -32Lo9VxbKXq1pJrv1myNuVwhj4j9hf7pqm -35rEiJcw7qaVqGBUpncfqFGWNjgPD9vjVJ -36r5PU2fgWKGV15ynFjzzrNQeTSJwKvWtQ -3QryBf5zqQBuGo5NFVEWcXxFN9CHrVkCtQ -3BCC1WSgy8jybmuox7aAxsPBAG1QXPAAN9 -3CFJqGQuPPgXhY6YySxXuWvSJrgNLCCnuh -39iyT8CBjzUqDTkrc2sbQ22SD8FkB9w8Q8 -38uDTRR5cBSjVQK7BS9QNKdbon3B6HCh8q -3551LwzFQVkV2runpUq62FvgQbzHYmqWit -3QxVhstcX3ohyTQnp4kcCme1KGEkav9fsA -354ZfLv6XDtucit8FyacwxDXE2Ng1WPMFc -3PtN9cFMvB7eXA5PXoy4VrP7a3bQXz37Lm -3Ms6b63VZ66M1CunH2Sd6itrjoRNj8X5Jy -3PadTZ5xeopF5itpnP7iPwVr1DdtAG8DwG -3CKe1igwZQ6pxjejR8BYWY5AwGZrqSyG6U -3QfZNsZoJYJZAsvThzwhK8FRV7dhy6GNbJ -36USaTyahdUwVNrvrCBpH39KpEoFmtZpBr -3LxMfYhDWnrmCcJ8Kr6N5uYkzzYdURTDTC -33ZDL5TKJsMbhxqzufXKMsNPVUV521zdHk -37Wy4MBXM1zSdFDZRD2gtNwQ43kALLftXR -3CmdY6qxYG6vNbdcBaovBxBKymiwvXTTZL -3GFNdMEWsins8TUsZBKCbsBi4xXUfibddf -3N1Yfnn7a9Fu8yACdDjJkN2d9wdHBeMsRT -3CKXF7E9FsmSZPamfB9K7v9r4qTvFKdNyF -39c145ktppcr7Bm4Mq4HuetDFdtc7RvFUU -32kxWi1JdGEPDE2BVhHYCTw3iXKuJVzkdG -3K75co9rvKo998V373jLhj6Znf71mciKyS -3QwptuWMn76xuLzsvLXNDU24dd8DFx3k7J -3NfqHgvqLi3gwpqUeeXGTTYxJrxXhUxi3i -3K3QZuJQsm7sVTCLDkkeKhUvwCV3hgaJLu -391Gqpyfy3Z36fTKYGn9UvjgfTYnMpvzg8 -37CCPfPeGe4EboD7fuQuc2VarNznSTHwZS -3JEkT8hPgCr29yjgvSCveZ352jLxXkkxg2 -38KAvckpWk1XGWyQ9kBztkPwnTwbwYovGs -3JzC8NxbgvhXq85TX4CKkCPgF52QyKLYCT -3CtsvPYqUBqwKrp1iR9ZHk98SKfBwZvohG -3Lsm7eKziyUJeXWcgYFPj26z7g9gBXDKf7 -3CRQA181mmLG6CeUhAaX1e1DcMsH9q7x1b -3BUkmm2NQWMy6HnpPqPf8Nr6KmTCi94DTv -33EpnySbdAXwyRomFgzidCBhch7GverLS8 -35aNERiWPEbnZWEwRWrbKwrgMr6dV1mqJM -3DHWjbKVQgmdZmEqypjEXvoiCnuX9ZobQo -3D18XLrQ1YYQF3iW6k5rSnrZZCpybwwkWE -3KvSMQHyoABh4MGxXbJTbNwMdtBJ23sUQ7 -3AGUJpP9QRqEupvtHcqYoJUgHTwmJ1iY24 -3FqKcXSmg15SNxn2to1SThSyjPwvxauYHu -33b1RMzFmcg26hWECVDzgi4k2ihXdu7d1C -39dVSuodfJZxFUm2U7cykmsGxk1zA9X2as -34U7e86sCMBYs7huXYsoGSmRWqohxL7tiy -3Ky12pzxNjgcANuE2tEmoKNZd864rWeo6s -32sAGMPQiqT5eNDMmarkYx6XMWdgvLeMYA -32LXqTS8aKcMqgLMv5ncP3SgBJhwaUzzS8 -347K58nN3HCPwWHLzsACdAXnq3zseq4AAX -3E85e2415z7xqesQAU93YsRPX3LXZ9U7AK -33iuYdiCj2JU7LxuvhfocPeqbTnrTeJDvg -36ghut83H7Y8A76FcuUDKJajgdQQptNbTa -3MncpGJ5mndU5eRwZh4UzyujKtkapdq2vQ -3HDKpewN8CeC5ho2myoizXGNET87HVtGxH -33W8n4WXJ9XibkjfKemGicqm8yQrJhpQWY -3JLfFoM31jUwxe3u1qdrddQoUjroqMT9rn -3F1BkdAD76nhRaoPx646tXsgwN6HZ5d2x6 -35yMma5rqpgtyutNcqDxvLxPH3abCQsBNo -39nxXxVtuTnUYBhy9zpsMyGJEg4fyMEm8o -35EEnuD5NCF1QgSYav3K2YePY8k3GADHTK diff --git a/emscripten/test-addresses.txt b/emscripten/test-addresses.txt deleted file mode 100644 index 1eedfe677..000000000 --- a/emscripten/test-addresses.txt +++ /dev/null @@ -1,1000 +0,0 @@ -1JAd7XCBzGudGpJQSDSfpmJhiygtLQWaGL -1GWFxtwWmNVqotUPXLcKVL2mUKpshuJYo -1Eni8JFS4yA2wJkicc3yx3QzCNzopLybCM -124dT55Jqpj9AKTyJnTX6G8RkUs7ReTzun -15T9DSqc6wjkPxcr2MNVSzF9JAePdvS3n1 -1GA9u9TfCG7SWmKCveBumdA1TZpfom6ZdJ -1PogPE3bXc84abzEuM2rJEZf2vCbCEZzXz -176U2WABbj4h5PCrxE963wmxzXd2Mw6bP4 -1HRZDR7CmLnq59w6mtzNa7SHtVWPSxdgKA -1MPdvYLzcekvEzAB7DmiHa1oU8Foh4KUw8 -1JL3nCw76rhwK6EguU6uhe7GCa7Mq88kXg -1DXKPgQU6ACQiww48chz7iPJhoV5L5bjRC -1Fwv7wsw5qa6tN44Soad8fC9CBwpVPgqCM -16BuufZRpRJYbiExJDgwW9orTBb2SbyqkL -18QJ4b6gpAhuGu21BDAmhTd6Pjvfa5bPD6 -16aucVQ7w1hfyXY4LLbP47a4ooeCy9ukeW -13kAzknifqXPEZu8zDgxiYdEUtfA1JXmAx -1AeFfrrseG6BRZ9v2xL5hyQCvzs4pdEG9B -12i8L9kzLejeJA1ncvkagQ3hbzdpr9pAQN -1JnEtPqqx1B7GpHVHGRtziZ4pEwzHms7qZ -1KGGARUSGAgo1EThKwC6adccWXVg5NHYiv -1t99qaUE2BwFmWD5NM3Vfmm2WSkrtoyeZ -182gbbXmn8A69BBxdsMeMXfsKKk1hnRKar -17t48iTUrYMWRATbASddjA1zQxAiWhLq3t -12YeNKUAsx2fygpL9Z9LM2e5aDo4AWnRmH -1D8APpheG1ZHaQShcxCWh5kacPGh22rK3x -19jH6toVaYxsYWNTETrAdBv9JZqnegPmNw -13ERsUEhyagQhyht45zYkxmW6z1PSBwkbN -1BDB7VTH31N9cyN2uReuB6ayp66x7o5heE -1JwNJJKam5Y8pmmqfYGUJGJaUrvoEJCYTr -1FDjtziBqui5yJAwwfUEuu5ZqNm8heJ2fm -1LvcPy9SQ76jz2QWEcnMA478UC2UjAj3cc -12ppxDpGQDjW68Mcw62FpDWJH8CTiCw9JQ -1L7k8mh72oeRitY9PAfb1kJHHeoaKkDqvj -1Em928XFeNgGHu9bkevvtLicJzTkWtpS67 -142epfDnLURiJhbzrasx41TEcbzdNbbscC -1629DnNSKLxBn5CMaEraTuRucpXPJknzpM -17J4t26g2ManWQFhRWgBGt2DV5cACW3KUp -1DNppZ4ocTDkmdoUo4DBZr1iBAxdyygo1H -1DaJFoJJ8388vYWKmtkeJrEHYL8rzq3zcX -19c7WFB79FcZ2nmG4zMPkkJ27iUw8BsU1P -1Lwf2wMRt9Nx6xWwSKnsdK9ajCKHU646HQ -1MCng5rjimjAL5TZgM9qFLhzST7Zog5qn9 -1BCzxbp2krVfrGjrB4fziUNpDTqyMwMgcf -123b86CERqz6xdyw52jDgLBTuNC94odtah -12EMUkatbvPBw37bYamrTZa3nfp2m3hks3 -197zzWaARhRg2vwxsVpcHA6LTLjiKdtJxU -15PZA4wvEcw8Tfvaxg7ULf3jeud72kwtdy -1DGqgeNkcopfNeC3Vhur4UPicDoWWu3nNW -1CkRASjrSdN1M8rHaLUXPUkM9j1VNtZURT -1MJmJo4cNrQqjtWfC79jGzLpNSukzeFA4K -1C4ZNh68ethCKQy74B58FCShiuDrqLpfHB -1ExY9wSMj67qEF4wCLwgwgqxTbNyeWMzZs -1GyQ8WgfYZ3VjgNXUQNhcjtPjSXwhmG8b2 -128pzPoxQAWKtVPm4ymAqt7vADVbxckWHS -14nw9rFTWGUncHZjSqpPSJQaptWW7iRRB8 -15FmDszjbUEcAB6i3abWkrApa7bRXXWnir -1svSxTo76gw1W6X7SbDNtEWAr3YR6vAjw -1HDEwxpJwE9vuKBz8oi4vYzayRi6CHFs7T -19HctfTN93QVUmMKwzhACwNWdAsLX7NPv2 -1QHkRxwudvtknK4fs2KQRnHYzLzVSti6oi -1GzpH1Gn969noj7ph1oav7YdbKLLdJsYAX -13XYPXRdd7nevx15PHLKD1Cg4HRjAWnvMc -15zwUVQQrmWS4VXy88wmk4jgqbyApTkNWQ -18852P4BcrXL9kTyr24DQyGKzsXNZgBxjB -1ECZAWouiDHDSKX9HcCTHyqJJJ2kfLzRgt -1EDHvjhsgkxECEVGwzD3A5kZMdXsWcEicR -1PkR3KKzg8xXeTVdqxjHERQEukugN2Y5Ah -1NKi3aKBmSThXmTAtpSwQuwGoJvMGsXE5i -1KxXpLUSxoEcMrXgDqVwtrmZTepStwD6dr -17podqn8DHbUaYTiCk7nUxjCfkPxT7zu8m -1HE9zd4tkHgpdNVuBQBx8JgKiwrc5ZTrVy -1FVcvYGmWj7kQaVYfqQi3nBeNsRGJRdYNg -1CLsrKSrB1MuVgtMMfXKW2gPfTS4JruUfi -1JwrgCwzAJGxDug3KpZUjYY6QHUYqhDgyX -1GvLHzNjyWFotyiVeDq2vxDYCefmSAuvg1 -1NFGiwpsMau4pMV9ZkN83ouVKVH1NDV9se -16vzqohcc3J9x8vcKZi5oGLr7GTzQT4j7k -1MxKoRGvRweETXeNFXR4r5bygJ5e8MCDxS -1GtambqQjBg6xwzWQo6pjPsBkt4bfw8Fgw -1DSqp45me3MDCjstcHHPXYXVNymnY1edW5 -15osmj5VdVcCp7NTgGLr2r86Akz4N4gycg -16yBPz5o2pFNCyTf1sZuFMBKLNAbs54jqU -16Gq1Zv9utMWaDeLD5naPSftqg6M6KXdZV -17XCuuQowAS7gSKXrChxN3UPDSefG2Rx5Y -12U2zAA6j6e28VPGmkjTTExzVudn8PZpsL -14kLA5PaT2jrAgYHSRWmS8AYh2CdCzfknB -14dXQGMby9q3TBAYFurAThvHBK29vr2ymg -1Q98pM4MRc2mM3FSAAvFb937T2jJJDSjqP -1CYpXNYUrEENG8xAegd2ewdzQafqKNpSxt -1MWgXUw3cEbdBbVVYxSGJTrrQUEDmNpy1T -19YdoJbRaFHXW7bbyGX62bE8QG2a9LKGfu -18ee1MfCNAy1SmnpuWV2MFhaSRuh1PYg9i -1FHo7TG4XUw1QnpB6cHkYYp9tGyYzuQ4nc -1JCrRW8JSHnGn5mRVivb7t6np9QGnT8fzF -1JpXDB4qT8vcy5YnTGa2ujoZXQEhf3RNfd -1NgAZySoicM1FBLKy2bTyUAXbdemkjZkvp -1KZM4FRnLoTGEdVBsrBeh6AwKXVkdMVZHx -15mQ7JpfgkHQhS1HMyakTvSp6wZobZdrbA -1CNNL5m291HKymC8QdPUYsoesGtYGBHPRi -15FNuRGSzyRdmzaPrWfB4NAVn1iesq8xgg -1KHDeB2e8vFw7q6xAtnWedoVfGpVZwGaee -1FNoTGfHrSXsvByAwdLKYZ7iv8h56jKd9c -19XgwbbLXsEfKAAUJfxZ2QLidfsvzMXTtA -1PCQh7vqFNSfiTWiMn9z2m5KUc9sNCuGmf -1MDQ93z3q74gHEWZEt37dz5g7ygsos7bMa -18x6Dgrve9qL8XWDcYWQwEEq39FxHDBCBx -185VkAbKaNJHzdqksh6YFZSJa3we6BmsSa -1J1K3HEDWgJwjvu5PqMeJDgKUzsy75BFyy -1FkYsK5shgqDTN59qvLEDhZakhCZjDzkPW -1Jw7W6qFvmfPCp96ryWQRov1wfB9dAYkjh -1B1LxiJyawNr5GhHS1t4X87EN1gFQEvgrv -1Dwfc4BXDxDzVKkcJsMozEQ3SXnFFWoQNo -16TRWVbM6fiDdB2QSkjTASJ39LHJxyD2ed -17dAeedrU5tUUKM18cWrcamkQ6QjC1FeS2 -1MeJ4nGCTqQmkNpi1SzayJsotWPQLqeMTJ -17Uwzeue5iowEf5ETrMWJuCKVA8LnpwuZV -16nqjHukctc2KU4JN5tggCW3V5eGicqxAs -151JSRC9KCtgu7DWwKRaY6KGJMzsgg6Usu -1HRGAdFqa9YtB7uRKjq1dEcMDwpSHxjh68 -1Kvr7DfpiT8cKD6BEQr7HRTGqobnSjpQ2L -1DQaYQaYGZykvTbq8KL8qynf78nDb1Ygbw -1QJd1HH4fh8XwrvDKCLbdV2U5JGRiJBE2w -1JpRWAgAGjx3iH6F2RXNpNfietpaAgkTXT -18o1SWjFmtUYfbAPaek9DK1eFSPfBzDTmU -13AYKKg5Se1pjd9xckKWeuF7sDUr5BRtEv -12KJKJG3ZPmHr1mrJb3wy7dh3TCR9E4Nuq -19KpDnF5abLmVT5uSS7g3Xoozh3GD4mCaC -1D6ikYhzpGVRNqiV8vB1PyY1DNtZLdbJ4T -1Enj8YzCghHTQbJCAwnALcVJ8BNjqBPjvZ -1A21fw2Pjb8yK9D6NDqArVWzMP45SBg3e9 -1BRKGYPZQKMLwdS4HFi3177KPkqULUeyg5 -17iYezXCKaPLKCmsQEKDzfGkjX7Si24dFy -133ENJEmCrzr1ipM5xyWdkdFhXYF3USi8e -1PFYCH2XMPWtLeFVEKdkyeie8bJwNduC5e -15yecmvNS4PXtKk8s7aJ9QJZWoeZdHiVNK -17ebiTYPEq6wtAJnYf4UVKexqkUiuAR6au -1HgmBLSCpL7rDSvBj1cwoM3nPRV9fPUumc -1Me64du1HYr5qva6ao5XDQ4CQyt1TCeiUb -1M5jcoAGzZM8dKcgEGgMyxbWDePhEcCY75 -1H5xzBjdM342AHEyGXFZ1VfnyjqNks5vqi -1LhESpq12LThMDA7n6e9d1XPrG7arAJc3x -1MFhkR4cphKja9k6PQ5mUWeGFxopdPhmg4 -14cJiWw64jqEv1Usim8RR5apxJoRRqKgpw -1Le5h3weGsMHnnBATecmpDdbGVKC7MMjnJ -18Fk4GsjFhQSXdpNZCbqSFwGu9W69p2hWj -14qQSeaYcVAFBprTnNZheSN3Af7iPygkD6 -1DJBpSoX6pz7tiEWoZAXHxWDAtQKek3KYD -18W8Mu9E623T9Y4sYuiGAUKRbCzjNc8F3d -172fcW9FcrJWPgKcwWeGydRGt7d8H9up7e -1Po3tjftRxwCWQ5gszdCDteXLZC4DwmdZr -1FXcbrqSPfbD9114NNNcA9nxKWd3RL7QZ9 -1PadkVqEAFyaB1yu4hQZjWCsDRkZQK1x9U -1CZs9cQbHMz89b4XFfsACtMjMbFNA3c19S -143pyba6dVGqqnocefycWKza1Jd3fFuXuX -1LoqPvf2o49V2Z3NxNzyURqKPvRaSLDzti -1EfTCSdjamhz7zPgtsGyvFC471wNKwd65p -1NFbF2UwqqmZdchv63JQaEcZFfTQ6ihtk -16C31YsZddzRumn3mdomebxBHX1meyY21J -1F9qWj4VVVTxqHSTmgNWXhzqyHiHjQrHkL -1P6XqDnLiAbAyJuYoZ4uYgNgsoqgjveaPz -13CU9THbfTVbcnQiTHdJSz5nTAQgtdiBqA -1GWBf7n5UBvdbf25xxSJPnsCTve5VqHGt5 -15scurPVnxksv8iv5FifSBpaV1unW14MFw -12Dsp1x5WTykQRHzma1zjkk36Q4gd6y8cz -12NH8ZY1fK8KFUdjwJUDktaSJNaNxChGmU -1EM9yr5Cugub7ZchD1VB1EEctUanP4CtDJ -17AG39yw13U7JeBxKrrFPnZe4RjBFbzkxv -1GeTZXbUqNThapHNFVR3Sp2LtSGsJRrAgf -1pqdwRHGinZ1fStFkrncWW7uuUjcFbG1E -13Fkc8uv8jtDH4gbGfqHxLPk1TsQtbheXT -1PtsmYHkMH8pnQNQBhSDHMSHXEr91GS1J6 -14eJ2Ak1dkKDXMrZmLTbKBT4iB19MD3724 -1Gm6yZChBQ9rtfnfSM7tMGmdENLHffuwQi -1EuLrMA2L8Lqpbc68hCv5g5vf4uviPwRpD -1DLw76eY8mXCcuHp2HtvUJMkLuhK73XZ13 -1LjBaMwSaiiEB4CbYC2mX2XLo2cdhAw23y -147TXhQvYy6D3vmFRbvzhoRkxTyS9m2oTG -1szJzr7Xj68tHn3eXvEWna8JG88cYMnbw -1QK97d1PUCMGhoYCxdxQDf84mGLm5eV36F -1DknC87FoKB1FcC4NwHFvR1wWp6sHbMeEg -143Ez5s8TvuRuLBEhco8QiLKKPHL2Y7TiS -1Lwe52M9thScXbABWUS6fwnkxfpxW5VEwK -1Csv6v2Ci6pJQNSsxSvGPXmi6iVE6qt3Cq -162ciBsHHKtxCHmF5DTatdkgkoGStR8ciS -1eYcCWe5345KRBj3XDVpdAbxwsehbXxzx -1AvZLrGmLxNPF73brmw8HBK9fHMGMat6cm -1MZXbmTNfujQqh13e6yy7xNGeyrN5t2moP -17EA4eRLCg7gAUTc8sQxM8GibEeUVHh7aW -1GRidtL5bXrkTujj1cJDqGTKC1WASx3DG2 -1Krvw7QMugnTdz7sT3S3J7TEKJDCKw8Qu8 -1QFy5YTpY2yA8tafPeLYgikVHgcDK7WGiP -12YsnFrCKr6k1AjoWw99E4JETheA8xXU9w -1PcphLWi9SM4nBpP8xYraTKGFekyKpXBNE -16TDsoS3vCR8Jw55qk1nafCyVtzgWiHWhP -14ToKnMWoyqYQPSMyxvNZxnwtzn5hue1r2 -1PL7uWP5Hca5Y1sVPo7JQvWEV47S9LfrzJ -1NKmgGLHTMthWHvZnzLX9NiACsmqZ9BYgU -17uUAEyVNJMXdijy5cUV4TMXiSui8PAd4c -15RHeA889tj1Ciy6e9SPWne4cSmyBfTrTu -17VxWEoQmueMqkT5Ppe84ybTvD76QUdnKt -1AWEphUDwLMX4ZSyRucRhpGHwkAAmCW8Sh -13vPJyag3Rz9uiDmCHDAkgb8QnvhSqSF16 -123khoFbmNuPQ38VhLH4BE9eRnKj55pjxo -19GQbL8R9ViGbrbBNdUja32Mz7o5Dq3cwg -1MhYUBVkjAWqX9VgRYPz4eB6tCQ9AnSRRt -1Nvuku2aPT4ULUghxc255gjScVwXKgag4r -14AyPSjduDdB57z8fsmGH72SfdYQ2cRLQY -1NGWJPiadqZx24XREtnbMRTb3wkT5BEj97 -12pfMNqmVXvTmiXsgH1ocDdZw5wCQFtk1z -13FxB6FL2ntg8Boq5HNo5vyDdhyyvRXS9s -14MqRDz4Ayoi5KnVjUiLTBKBa7FaF22pVU -1CuFwfY7bzhz9PjY2W3G5TB5R7DtueFLPW -1CCQHAnCvUPi4Ku4A9FGfXYP3KJVdXMgo9 -1KWQGJwsPGLUApnX42YbPgKph6YoTYgQCa -1WM9zuf26p24igG5tioeVK8Kja1o5ZFX7 -1F8EumfRo1QTe92SNyN2Q7bKcjExUg8BQM -1J1tMDS6bzx3bYEZNb3B2ecL5cGYJhmd24 -1C36qVENEb9ZVcitgMPwg6uTHUrMRKRdn4 -1NY2TfycdMsEgJjo98CXZVpsU9cJsqw8QN -17VNU8SuNSxQVQr8V7Nah6wQvNcKNLQ8kg -1NRd3CiwZh8sbvi1LuXuizekJroAuZ9q1j -1BhbzGi5psoGb1sdzP7WXC8U1SpEK9zowQ -1JNJ8YcCZYDCbmqFZRVmHufVxhKJfLfgi3 -13x85eWzXMKhxMVTb3AxuPQYva3LTUEfDu -13WmPh98GHGPkJ59Uzzhj1sadFEkAtqSnq -1GbNNSciicEfRH92SkU3BU8CvqDRs9fwBU -1Gu3HkKhwr7NhxtD1B2d8k5kfng4dhQdQP -1768HUKpnU7xuSWjbmv4ewhYPDCyJ9F2jZ -1Mk3JZfbfv3hdWhiXSH6WPmx73k6jmWyvN -18SKCrUJaTBE47EzPycyqpBpPW7CGgoWE2 -14WyZtQudnuJ71S9qvBFubY9uaB5pD7Ro8 -19Y1Ne9sWwwRcie4VtX6pjrdsA5z8Lpdxp -15i4uQJt4g1PnamZadRGXT7UoZB9Y6jj5J -1FZri6Q8amwt2C6C3jNHFEgmUXj29Z4Wo4 -1EoSy286Jp6S771R4K6HbZAB34z49wBqBS -15E65uLQs2yBDhjLKqxDBQFdCJZuHRNEiT -1LVPHMqJQKwNj2hMat2F9BUSADsfNqhcgN -12mvuWpRM2mnptD2N9Nnvkyh4MMm31SAQp -16DQEUtqgxFJ2284edUHnHTMQFqf7LDzhW -14pzog455vVZCUZWKNvB7JqMkAimi2c4Ne -172LSqVDdmStc5vrUQcsprQ8qCFcRZQtMK -19z9nwJvYtyrhEMhK8EmJ2iCzzv7yHUd8i -1NpDgPWooxGngu67zFCBX8DuF6pmxSfVFL -1EezQbR25rDMmUjLeHn6GSALJLY4rvQw8A -1E24awmY9C21UGrfG1xpnFsXKHMtMbHvjB -1Bak9A2zkAefgcUZn3gH2rCEA1A7Fu5bMQ -1KaEBFt6TTuSnfXWJwkK8aVVgs13HVnHoJ -1BqQ12PxtxWXDAiX16G6roe87FAdepPT1b -1HaXfPfCX51Gpe9apxDmh9tAyZnGANrWsX -1JyHmDVLuKxbLF8ppuxG7waYcpSVbeqKZ7 -1LsGSZunm5MSWxa5GJhmQd3NhdaFe29zve -14omipNZTVxhJNEm6z5SSrPLmTjHF8Ht4L -18jz2t8515EKar1TFjLZc71Sn4wfvwV6N4 -1Fum9NC14WPo6H67h8BCuT4uUjPUp7wXUE -17Bt5d4dCCUUwqV2V3jWjKK8p7YzzTb81x -1KMA5RsNypFvCvWWDf9R8ZdYBkj12QQypC -14gn1J64bRjUr1CZTQdB4H3d9pMFSBBpBJ -14raFodBoiYZ4NYy1Wgojenux8cHm89qc3 -16BwA6DUvmX95ijNGRzTdzCJBNTtYYbhPL -1MyV5zGX3aQGKetNpcTMDYQEsHycE3wtMt -1FcTbtKkpnMNLhmG8f8aj4ZXJV8sQcEJXD -1Hgb7B3r5gtZomuGDZu9k67GsnTWbyfHZ -1F41MihRcNpFgzMAjw5Skbby7x3hBxVLiZ -13WEj1sqk1DvL9veqUY7Vtm7mvpz6mAzai -1LhvajVGEtqiUhSMzuWRMbFEbWVkrLJfuW -1HeC5VdNutkex5aJ2ue7gYvJFJPivp8Ac1 -113bpVpHGuxLZSFQttrpeWLz2uEWkQSbgE -1QBHgLtYbEqgrEXRNyBt76jZmX6KygcZVL -12rtcU6RKg8G1RoS4SfBLpsdigPHQY8UDi -1EZEDCqmW4hWPjFdV6HamFmCAhikBHw5By -13YvjWnmzdWJ5bUWoM7y96NmbV1nd7GbG3 -1F455s8HobaaL96YboaJDZbLT3ZowcwPpC -1Jf6L7GxJRjHCZL2T9swq6o6tivCLp9oxd -14N5VJJoGFvoLjLyLwCuuLDiyY6vD5j3GK -1NZN8E2fxWLpKPMNm5ecWwPkHmvr9nSpaL -1EiYBo2qExLERy21Ur5BypWn7EJZ5DiXbX -1AiyrxizJvgaupAE8Q1FpL9yfKZUCXmEbp -1EC9SktW9Y4kS4iW48idshNg9eNeBdY5Xi -1DR7fFFhHe4CutgPyXvo4EX9PvaJXAncoA -1J4nHTHgsV38VEZfb1gknamTpPAFMCqrnJ -17L467eezUxfvABRJnXWYxoUEU7BjbovfT -1Jw5FrKhi2aWbbF4h3QRWLog5AjsJYGswv -16gYznc3m1smWgiGAm2paGRNiLdqLh5HGx -1MBVsecwAsJ7giFTjaYx9aKswxgDpouoV1 -1HLBRpfuYJppgUY4kF1Pn7UN5agqK4X8T2 -1P2GApSG26JF3hpkzwUNsfVtJEDL5jw5Dh -1JPeEXdtwZKD3WhJV3Vc7ApFoK3RfZurXc -12q3TYGqboZfqC8DG85t4YJNZm1RVTCsoh -1wP8MbtqyvH29ZrAePKUACiLPMUmqf9pz -1Jc5q4FJNAsXyQux7n15LwwraZRUBhM1f3 -1SReqT2WfY1Wjv7urpa16FoubpYvEW71K -16a49zHXVSA4yuDxNFLhQnV4EzUXG3vx3r -1HLkBtvkCfi8a6VMxMy9DHjPm5ZU7GxEYA -14r6iGFRaMShhvWgFB5HQmbkY8TkFLrSAS -1FmeswGFnH8bCoqEAgpbBUnEaAfM8R4y8C -14oiyRSNMYipMoLfyVDKPPTzkoNYWzuAy3 -19pUMjoJEvBJYL4aUHTnbQoBMnhUPSrYxL -1Hs2dbDPrD2iEUnM9gaUiY819BHFActRPW -1J3Nj1FzViBE6SJYY6HEUfoyDrtCzPR9Fo -185vYvzQZVP6cEXoH3DKiBpJnSeQCW4acG -1QCJEDYWF8MVArSc12zVroeH8ENB6dD46 -1J1CeoLLVtAG4HfycqAPiMQJoAbz7WcT9h -1N5CpbQmNxowUUBJ8EBJZzGFE7wQjtU9r6 -1MHm3SYvqGq2gSjgFJPxWFaeL35rZ22uF6 -1BQmi9pSFvgtrMnbQ2CkSyDfwdqtmKB7Qe -1APsNapXbU1kMT2d9z9MujRTHEnSZnBDcQ -19RPixj4DKZHzcH4Fm9iTDMiJAAqnCKaiN -1BB6uMHPkeYzqBfHiVJgqHnLyNycykitHp -16wUAGjrTBbEKQQ8zpCFQbEoJpQ3xC1MGp -1FtfE8MhewzcEMPgi8y4jz56UenAt1Ryfn -1PspUiJiL4mt8WXcZBKzakGaur5WaoaHsq -17uSkpk1KaPyZLnSMzPV3T8nhAAuEHeohu -1MK5z4NA4z2yU3U8wZPyMzBTBut48hvyZR -1QCL7RT9iUidn9feZzqejc7Npifs6HxrSQ -1Ls4VxG13sQ6x4h75m1K751Lg4BtmWYQvF -18zB3r75LkedVqnwHfFii8mmM1xMNuZVG3 -1L3zwavUgzVD6KKYZM2zQHiKHA6L3wKjb9 -1HggzjQE3iMiM3bmFzKcoSdFoE4Sqh1bhL -167w8pyvfzDCb51UdCx8k2dPvsHPTQn64N -18QdCXXHNiXiLiHtM6o1UjMEtr6R4V4ay -14eUiYsXut98Wh4ZRGqZSG5S9zR7dDT515 -1L8LLHpuRmGUMEm5BeR55QrZfjfWPhKgmG -16NUWB9djkNMveERnJr2RkMDaQXV4XN8A9 -1PWHQdhnXTUVCzctoGcNajVp1x4LCqyaeM -18zGQeRT2pSQhamCW63iVt3H18HiqmcjFQ -1KJwR31A1wpHVbkDwtZ72taWiXK87Qg9P3 -1DgZzkrLAkBHJhp1Ecrhi1xLdypMGvYcJS -1AmVZJ1NxuCWB9sP5Jk1Y3rHFdKXMmoro9 -1EHbCbMVSjm3cz6FF8AxHb13uJ9hHowJ95 -17uKzSy47giFbfvLU9ZVLN4amJo8zuPPai -1GECLG1R8s5E5gK5Lh3f1rC8HaWF7vCyTJ -13fEfSJbiz8dAu3AHJ9Fi8eA1sa4j8v3tY -176qdApJYubiKzrV25buV4ekCEqES7V1MG -1KAKNrmTziboYs2RukVQBPxaa671Z2bqhL -1H6dijst3RVrkaphQfFoLa7HbBHbv6EFKm -1J4kJXvcKKLfTG86EFN97ZEyqhMJ7bxqDt -16Aw3gisPBLBDSYEeyv9n7NDGCGXZBVhmx -1ExVE3n9uapCDfL83R98LCRg8oE8bXDyrZ -1Q9jbsnYQfyeVqkDKUTfNMnX425Z4mVzWd -1Q33DnQwjFrw7qvPvELP4wSeCFA5ioD6Qt -19KmcWE8n9DT7BdC6rUXC7ujQQemVtxQrY -1DjogejLS1wprPVmuLu5bfgbmxdBsBmvz2 -1357na7rCWaaFTeDpcxcYcmogvvBvMyv6b -1FPEzEy8S65PJCFJm4zu1yLbhfKiczifx3 -18AaCF5k7ZDmeQeCEF9q528tV6FjCDBNiD -19e56sugyYfVfk9vBoq5W2UK862oxckqV3 -13phgTbhWAzihnBpzHpdpqTGA5vaYa1NZb -1CiQ5DV5gzpZ3kbwrQLXGwGcPzVdpLYU6d -1LgjPYCB6Gav4aoHc8KcHc9TuZGvbYRSuU -1CQxNksBaM2dhKA2jTC7m5wrozFX4GEJoG -16SrkHfSGxTEoSvEMeB2Nn5xEEMgidooA2 -1Bb2DGtsPJWKoz9wcWS7hj6jRavrwhYHZL -19KLGvvCWMVp7uBB4wc54sYrcFn1C9fd2Y -175EjDvAXZoaCWyoK2PqtejMkRqL3WuYmD -1KvU3HQDYbNdkhHierPg2ymfw5dnUW148j -1DJnfviC2VSNq7HMegGkrjZ6QFZ3arAjbg -19VMoPJu3zVz9hRqAMNRuobp9HUd5M7kz5 -17qGhq5VLPGvBtxnr2HrruUWuSXFHRZxB2 -1MjUJPmJ39KE3fUjLoAZAxHSxe8aAzaWLq -1PP3N5URVGvPNaLkNp3PtuWS7BZnJ1qm98 -14WSNr58LkbCefw57dgzexL5rsKyymJC9H -1NyanGJ3CQHhTDPttmZFhkRrx1sEL5yCY7 -17Qo2yRpM5wAs7rfWQMCfq4ACcZrqM7yWg -1JXujWJhxEWeh1p3TU8K37f8JSvTAuiJSf -1J5PT6UfimMExeWf43PCtKK9HXKdBjZJGp -16P4N3opsox3Xw7nR1m2ivq5GNXdetWGw1 -1FyFBAnK2DWuGLc8h65n2Mxc3mJHu417wS -1E5pE9FN3aAcX7iSThhr6qfwo1YDDZ1VL3 -1LHU2gw3HUr62f3DEuhiteJy4T3mcvnHc6 -12mWJRnRSjjbe8oJPja1eYLDP2bAhCeWDu -1NQPoc6oWLiR7xEYHmhYide7gxeEfzaenD -13icTzLY9bNFW719MaFZsCTYwJzDLXvxEX -1JZxsbLWCrpjB4XmjyMoCrwTSb49EDyNia -1JSxinLEudB16dwvLR5Y7D9FcDDDnZLAGy -1J2YsKvVLFjn3LuyyYFXSvQXvpF13KiA1L -14nNW6xRPA4sR36YkWmSZAQacrSHxXby2u -1CrZ9EW4tzfJbL5iCwWBEbHPgHuU3B5LyY -1CXy3bDMNFwC5uCatwAzKEJDny8wckufyv -1Ac4b3RwiFvZHyDf1tRvvW7DV8TPHfnZxA -1PWngUDo6obeQetiR35ge3wAgKLKCpUv19 -1L71VMQx9q1A2LvAmYy1WDNh3uNBeqbkJn -1DygLoLsnZiMX2dtocDL7WLyA5cuoNJvVr -18agJ2i62noucHgFPZ1LME2DhBsKi84hSM -18mt9cTUe5dtDXVna2oJA6Sd67KtEmzmP -16DP1gh4hwbe6bw2vWGiHcJ4FqewX6tvtp -1LyjRgCoesgLyiPPqS4Ug1kLasxWDLEzp4 -19MfUc2pQnBeMbck1UQvDVcnxtPhYgGKb5 -12Ldg4X3sHfJSsNyhJyZ1SCJbTPazWbEhX -17MG6FkzukW9YCJTt3xjAhfMR8W3T9YkUy -1cGUtp1i4mQKTBPH2FQNDG7VWdQdZa9sB -1ChkyuNr9kBgFytaUQUkbK9JqdFqa7ZLAe -14efmp2YXeHuAsM9cojrwXPudQEYeNLNqg -17BEDgKbkQ2rmnEpx9sNM9YgmN3ikX7DNj -1NAJgVasWRkqNiWd3ZTXnKxeg9T6XGp4VL -1Eo5itCHtH5uQ6G9y9HzPANPVZuDCyJe9r -1331NFh7WdsC6zGvUxRC3bAVhEmraKhnNb -15Yh3QugDuqW2wh8iKxmBpUiJe9Qq2MNtP -1KTWfL4Y381dcKgbHLbLpX43JmLrACkg2N -1AGmFTg4wZDTDKNY1bYZn23DfLFuk6jjZw -1LVbQM8YoUj1B22iWxnpbcpJ24ZmBmHe6W -12CJJnvnNBNXLnWSxHX1X7T48myrShUHeS -1PgDeXTfYrThPXFRjVpULyuTD8b6got3JL -1Cp1NijoMUDpVN8wKdScGAyooHNCh15Chi -1Mafdt4VesjWHrpQeAB5xK7WswjX4DAFdk -16wMFY1x4vAh1u2TxkArBBgUzw8JSC25N6 -1CpoEYtCRbcVXX53x5TrqgREM58cXsyWkh -179rcziZeN8e7GPq9aBGUQ8MqDqAPavBHM -1EDM3dbK6JhQTRVYgGgcSWopSzuhUeM7YV -1CEF4TBf7SxHbjwawCMY4CWs9rV7YWCbiW -1PH6ScAyuHhGL8gw8gpmiPxYv27cREt5Rn -1BGyw5bfaPxuCFdWCt2G7Qzm7sDgfyE11V -1M4bPEYTaoBgMKV5NAybaEKaKRmqDfGk6e -1D5PYsmytcoaLE9e3DuUEEJDuJkbq2HruE -13L7fAWbL5zKMoHo5TsrhAi3eDvMB89HM7 -1B9qAyr3t3TGK3Y9y7SNBV3nfV4F4Hc6f9 -1KiEgW3t63YJxKcAFKUyjXq4MoD3xibFx -19CYyDiRktmCNfqxLAM3BZ5ZkLs4yHQRTk -1KMF1AW36gtg5aHiqiU3gX76g8b4kRKY5x -124sJU69RiFyuMQgcyk1i4LNT5NGoh2DTx -19c6YezE6zAejRZihtyEo2k8VzPQdyVRjY -1CPAMekJDdGZ3cxTGXTGeaEx9sYzCafvo5 -1F5wcFT1BrEdVEsFZEG2sthtzBkA4SzgZh -157GAgu9PZBDrUtjZchFfhAkfHNtjRSHWw -1ApNnRgA4QEdkVt7cWRmyyoutXJttcxUTk -17p9wtTQ27ACRKZscoCJ1g5sPz3GSLHhwj -1Jyz43BPBvFhc2hjsDZ2FnRRB5ToewZUm9 -18VtcrbaCguG3Vf2atuhago3oJaS4P6Cyr -1At2wZsF2QTHPKExNQ7iqZXGktVAu2SrP3 -1LCsYznxNKU8Q92Z3i9sgoZ8sS7gVZhmay -1MUSVtcGCmgUoVGhtdBPy6N73hM3igiFWf -14oaWAKGpYt4y8rsLRFfKjyp28r4owe1Z3 -1NHqErQzhFKN325JQbpJmGEHBXx6XfkMXF -13KyQ8GBnv5MvrWQUnZGipdBoH3SYbdaeD -133CJc7tuAJZWf5YTp2jb2AE5gTbftiCU3 -1N6jFHqPVSaNf1sNi8UeksB3dTfQckmmzv -15MQP8gt59hF4QANXGg8BnR9LTrsutxyeX -14Z21k1iQZ98p8yqXVgeinFhe8kSxCFws1 -13MYaz3QgxZbkaeBdZD6j8DFxMfKm1WXif -14zdL3Y7C9DoAzzvGYXEMvLMmt9yGgBbJw -123Q7nM1RUA7A4Q1SYAi9UJif1xBmwKwpn -1FZaMJeHzNU8x7fdn4pvoGMcXT2cq2jk3w -1H5UyTYgaWqTFCDh2FNn8RbsLoJM2qUc8N -1CuP14feeBzqe3dXTMKfNvupcxCPqFXjyk -16TeMhDN9dWktAvhR4wMLE5wcSX1R3kjSh -1pxM7v4RbKJ1D2ULPFbyvPhcu8Eh6cc3k -142TjaqP5w4QAiy6noPf6FYXUQcZQF3dMd -1DJaSBmF7QtwqDE73kToPv3GgJ91zDiFKC -1BKbVw4RnY8spYGeqWznELdVx5W5JE9b2p -19yRef8pGNPPF1k5MaDe7sZYR7PvppHtr5 -1oY4nvsZHua8tU8z5itzy2ifEzHvUkW64 -19K8B4vRkkYNUedrR4tPfCCrsgCofg6Dbx -1LRUN7jGnLQjqNZwpmQEgeAsrZwF8kATjr -13fLhrDtUUpmvtWJCW3HqdgqQWgxxbjDx7 -18M6G7kWqvccbNv9pgha5cJWx7jTYHzCs3 -12jE1a8iLrJywUqKgjv5iXB4VHhMgcSrfR -1A9FTXrbnXVcmABs4FAXY3dSUJD8uMn3Vh -1g7rvTMSVJT1YvrMcG2K3X6phKDdF3Uj7 -1DPPW3uMSvGmfdsBKDsBWSRqN67KrH7Tqp -15DHowJw2QrNwAMYGYGwHTJnKEqtViTz2P -1NHRCUBFCJebw4dNtTxUSwQcTeqN91faY5 -18i9oQ5qsCMguvx7vit324jb1DYfv4LioG -1PFoLqViRoBnPX3mH4HmnyAt2WnEiNjUZy -1Nan2VcgCrAUWfYYSVGCcxW41jAW3FsqRu -1FJNu323WEJb34XAZZe3ZM438rAzgAjDPn -1DMKTFEXjWW7T9UXaocLTzsaUBrVhASA9a -1EPfdcTBxkmSJEGanp1UwjQYyTYkVXCgA1 -12oEfUSaVWnxnkJiXCrW6HURcta1BnypB4 -1Mf9xoyZKbviKphrqqEy3G2NbSqTguPpEF -1Mrwawi7FBAZTBHbv5yh8mBkQuBhKXeVHt -1FFrRqhYRBmsT8Ap5kZSU9A64L729ueb4a -1MqJbeZzQL5K1Smei2LasyJQD9vqJm19aw -13MaFBjJXQXnX1uEidoPVbyCRZCJeAFuse -15DFYzgK17dBqULd9eB3BESpfAsEW7Pn2y -1FzJj1sSqyLY2jb5NFNhUzj4LvBAncfLgR -1NiejRjyPgfZavoj1JF8ehcC98nc9j3SnM -1KBhjjx3QZHJo13qFQLvEHBca9bULXKwGd -1Bvm5TduWUBC9Qh3Jcmz6cbHDgyNrjtnQj -1MUDAcBKpuaikALCWA9iNMa1UkfVw8zvS6 -1NpD58HbyYdox8ZGQnmeDssikuXaB8y9uy -16Lbh8PUPLqxmxdoqHwvghzwMeM47dVYwj -16iRqJ7oGQHg1qGnwGUsFgY5YpACbPSyz4 -14hcCw853aT5sX9LSinWp6Pm6ZYKHjwFTd -1Pp3fNYBCeCeRVYENNFHcJKXRMiXL2r46i -1DFLy6ideYcY9c7oAuRWqon4zRRRF25wPm -1Nm9hSmeQt21JBRWdbBQxTrtWx36uhgJ2A -18w8HmmDmG8EjCHAnbqqSdH8qMujxasrJr -1LekUNmqGv9Wj9U2eaAoUexT6B8ZagxAgK -15ZWkQkggCkGTBn7txN9kw38sWnkqvr1Nh -1HxGBp6HKVDKVtcCxSQihL2HA56aoZeSeU -1D2i6PDgZbydZFdq3dqurNP3ARpNsmn63X -1KqNCyBNsUtSLsjxdr9ojv9zsTEYWpvRij -18DQDw8BEHSwspgat6QfS5AnVw8cYewrgX -1CfpbTgiiMaxf86ThNd5anHTU8WJYqQ2Ka -1ESQj15zJCwP5X9WEiTAMoEsT94DpeoEdE -1M5vZ8tEAKGGetuGGwtsmJ42xCa52uA5Gt -1LgZZq3xyVGeQueir8uhV1QDEvknBpMHWM -1HGym6kcCtSK9RrxsNdm9wK164UJ6epkwW -1BCxK2xfzdNGHL9bGNkYCiBXhuCtZootza -1FnaDddenyU7VHFfDCHYkahYZTWo5EN7tw -19Dbd9tNGufL6wZQZmXEiEDPjpHtarbPLJ -1EDKYRrSqMXymHQVE57A5GG844Sjc5Ppyu -1BsnhKSe5vrgF4Bp2fKf9ENU7S1P8m3PYA -18VijMP8xt5ZgFHPoZ5DV92phpUY6r8ay4 -14S8NNBX43kxa7svpXDonkEhJCiCXLbtze -1JXQE3R8waXpzjSNwcExKtCwYjDABC8XBR -19Ub8TUHno87dRdAFevruhemWwdgasPFgN -1KThqVosXuN36fo9t6rKVngLuw3bdRycEo -17hYxEs5uSMpE2NYAsZCbsfWDzqwCuM9jb -1Nmogks8wun71ZicJ4CsjB4Ln8V4UGBiZ9 -1EedR6M7wTBzip7wJMiNZYQddS3SYkRvSj -1L4hAGgD9AeCKAkPAQqdqXLemh5sb9nqRA -1XHjpfaJwXjKKEPRh4v5dJrz9xApAbB7y -1DvcaPZeusfoBJnvVrnQxyyThCGueCSVWB -1Gi1X9GTRdQngz8GawfKv33qvSswJqg6Rk -1B3BScPDZh5KoBSZASJTjLvHcHaK43cuKm -1L4MAP5mkT3YJZLjGUp41iMkbeRcKGnJD8 -1LFCHFsPYq8zBdiJdEuxjQTw6te8AnDpA5 -12VdpsxBxR18asGy253Q7oh7H9Pj3cs99p -1BTx7zEGYNUENbC9mDsJDADcd8ko8XXHE -12uRenUezcXbxThE437Uj1J9kAoU3hgZuJ -19YpA5Mgo15SRJHzDUrxpoRLKQPtqVzMyD -12UC4gfk7BYZvfaDhMfVTdvZGARXYvKgbZ -1Fkx39uwVyD5Nm5cj4hVeyUAuBeEKqPoyC -17PKMqSju6K7rSfGPnWStKM1ifN3VCirco -157x55P3FXPjEaBBfMBLq3qxfYT4WvpPLr -19xg38W1zbUhdqzV59Br7wauCejFzf5HCD -121UVcayVstKTBRe7nKTJapaC9FjCEXXtb -1KP1P41V1Zw15xWPaxSk6a1CZVBL8m3wHv -13AfkGKDV8HzYWTJ7NbUCzi1uNcxuqNHsP -1BL7xKMsbAab3wYjS18N1gwnu5FNMktzrG -1QBKmZTboNi7oSzhK3GvDNj9e6CZEpRzPR -15BCqkuh6hbRTZPTxbuMaTCLbV6pkjSY1s -1Pj1M9AzxmMZyrRCqQ5bipR1McVk4JhN3 -1JJqbTnnoTLEW4SQ1AseisYHkSYLySwugv -1JoJLyzX9rcYUribBghnboQKXXa8hhSaFq -1NvpoLBWe6aK9QJhrG8we246nEZPhyyyrL -13Wou4Lkwin9Sx8aUzu8KQvjACstrnDwoi -1GtXWjsEs2pHSv5LKskaKSaqMGDwLcZCG4 -12LY5xNwqMKk9RFR1JaZx2yserxdfNZKq8 -1maGz7VXtu4jXvdZ7av4BVdERgaUjr8cU -1DYAieq5RwJ5fZrcwmcd8EVT7DDzGrchQb -13LgcneUXMZrkJ3jys1BwowFgiHKM6ABTW -1C6agqxwWbYzJ7PwCvezUNAcQLcDFijLo6 -1CnsZz1SJ43dTNXAkXYoocZrqUMEyVM2qK -18zkTbRxhjEcVehKD5mfjJC1joHfT1bKDK -12ghKyC6ciMHL69Tt8pTUXwCZwnh56ZBbS -1Dntvs3X3LWjvYQjjjh5yWNdyEtRi8qinL -13Jbmbzuzb9vo7LzPGDqwNAukCj1KWMpyi -1J7uJNL2RQBK27mxMLQTNa2Bt6DKwVLbQK -17u8enU8KDwBk3YTtGCLwTaEGzsTBhTfcq -1P53yDVajWv6WGAPoyq1Aqd2fFT7PxgNqx -1P7VTJXxBoriGSTZ59EFoiBnBH9TqGpNAN -1FWcn1WG3r5kmKE36ZiLcPbeUZ5cHa2Edc -1Dyg8y3d33Sid7KVTNQT3ps7APhZkSVGEY -1Q2GuYmdvXGDmYttJ9siWppxogTm6upfGb -1N1MYUgQopbhB5Wwv4VTwsVBs2gTuVSxhn -16QxnVQq8djwd2o6JDk7yZ4sLTxEzWA44V -1JjcYHEwBcrZomQMvMD2NhNLgscYVqdZXv -1EPonShHiY94Q5VnUVn5wQbh7fscMJFAYy -1Ls97dYNsPuZoz9GcKcaWdEt9T5DaXnt9w -1KN2PVxho2NJf4U5QF68YqCVgqyHiXpwE1 -1JvXNL4TLT3h2oJ7Bk4D1Ve7dr9dvyTmJy -1HCQdsySupLiiHEg3mHxxoMNEifY2yLXzj -1D9GVTXvFx9LyFAHdVEKszzDKur9ieT815 -19EWBDB7A7EbzGD316p8VXWKPUtqNuZT8h -1F2noyvpxcXLUibx5SSe4r9Hzv5Vr1e8h9 -1FUXrdupyqLidwXhJ1w87FSkvTYvu4pM9Z -1DBBqUiUA6ivMxBdHVU1QDFyuz9ZpF43fo -1GDxRgtH1xwr2vR9dR2Ajn473Da2hwUQty -1GgqTYwgR5uvrSF1p9rovaHtZ8npsEZ9pR -12mnEtjBW8ejJkbsSn1CvxoudPEc8WmUyH -16BY5adyQHhK5qRZ5deRa97wq8w94g2BAt -1CeyovcmTPJJrLGfP11GJvLTGHorqC7r8j -1MbBbvMhZxC7mEzbcyBv5EBLHEwYKrt88i -16Vxoe9dUSuJFfFE1jf2k6Mt7hbUgodwMZ -1C8Da5t5bXXqZqibfSuSJKU9FVxpTGB4sJ -1JmDo9xrAucUVaaEbRm5QT3zhF4D9BFTKk -1MXPaoSGJJiQ6d2an9hgmJtgx4DqP9t5GJ -1Be62oGb2W8REFJZgYymhQXZgYwsxRuhrk -1FwdXwF9URb14ua5J7oovHNwnnSdmvPGMY -1L4owQCG1WkLpQr7JPPzErtAsWeh743Ncx -1AfFZ65gCUnWKxyM3jxmHg5yR4CmtxgELk -1FRWyxunrG5mmgpDGijg8cns5BR1vWXZpa -1JcwP5q4db5C6U15pgSdn4aDVdGAVaaf9f -1PFWYpZjpTLMKtLYvD4uzd9kvVNgmhyPK1 -1BdK2SjWn2agAS1EiZyrwuwuFvDKDtSakD -1GxygBzaTc2E7s67hr7A7r4fSf3nuk9JzC -1AqkhxSSJ9GnHrkw552LUxx3YxV9Z8SF7J -1CuM3NQNHwUH2H9KzYWwtC8wDaujdwaw3K -1M5pgNxUa5x47opLvXPaoiRiEKqcNetuC5 -1Lhpf1kYQqq6NFuw9bGJkpRSi8CZ3p57WP -1GTRFadrMLzidHZwkZ8UUNkRkMtZZ39EMw -12PwFRYeXRHpSbxSb6ejA9pDTb1Byny2o2 -1BbEoHXudHGYYqgC5CfFMFEHEiWg7yQ1dZ -12Ba6fYvDagbRVPsZj29kA28REUJg8H5vK -1Ba7HwRDkj1EmbzSgr3NSzuotpo9jAbP5m -1Fji7gkypgoQagpSYCkA8wCDZywAN1Sjae -15pRf652Pq8PidQwHWCsMgnspz59HDyDDc -1QGrCSRkDeyhH9JGWczsvrzJR1pBnkeHcH -1KzZVFxQuR8q32zkBQGVz2pFnj5XeNox8G -17kTVMEbxwmnqaWxpchS8ADzBXPY5jTYv4 -1KB88hNBc6rZLgcSS6Q4EdXmwT7JXNri9d -1JCJdSWwUj2zPWvt5LBvU31QW8PubfMPo8 -1W3auEGNAW5ZH7rnrAqFisXZJ8mwcbnZk -15tmPXNJoi7sKwPZqqyTngRbmLrkXhYpEM -1FYhRVDw9aU4w8gy3xfbRjSq1Jwbpvv6L1 -19HBsgXt7CJq5NWUF1qKu7U48G839zrKEL -1CxpHE1s8bAZC9bcf5BAN3cf4fDB7VPwbn -1Ngt7QTNf8Nh6Wbs5bsJARsc1gc8QGLo2y -183XPvV3X9zr8foytYY2GrK98GXTCbaVwk -1LxRJcSq1AgLdU89M6eEw6gmRaUASMwAAY -12aN6WBMFTVwZFC4oh1F1kv55xXMjJibtq -1FDSusCaNeL2zsd6WFA6dzBbdRrB29G1oG -1PnXh6hQ2tLnGi9Vbn83AGHcJ9S3cXYdpq -16tC34AEmGTNvo4i4sEU2EK6f5pQzT5yBu -12Gsy2Y4kyPG2ChNN4X6ehLbaeNZbSet6f -1BkurcHX64fPiBvZCwjfhkh8jVioVgsDi1 -1JwVkBb26YAXeFgXCpuxqRhY1BJF4zzQBu -1MpzyMHmFnsvdV8pE5zxBSQCEu9WvTcXQd -15rPnh9iv7FVAok3NahBF1isDvB9EdL3Hi -1HGPWaNFDcPLafKX842Casur8wzrmDxizU -19meijgj9PBP1koG6HBj2htGYrvKWsJvbL -16KWc7rEHLgA5chEExbc1Kk4dRxFLkuZNE -16TWjy74kT1P8h4WhzENWmy5ptqevbFeg7 -13mfXGDLde5G48Bpcvjeg1FwngHvmJzG4M -14MMPDNEKf63x1jD6QMhEVWp31UMqxc4d8 -1P4PX1Em2kPSYRx63zGXMnwZr1Z8EL5Ysj -1NkAJ212cWHMw2J9eKZ7Fn6BMsGeWJVq1A -1CC8mkSYRZioaZyFHpzw5Denz1vvxptQt4 -17GuxbmFeHbCtokzHaMk4HVKrVqG3SoDEs -12ZhDPXbtBWhJ3XkzKrSYz2qX2V6ZovFPS -18uFzNWpX4JzNpH64sHR6LaYbwH2YoZwro -1BT4XCW1RnpNTvYiyZ2CNRWiWgJ6Y5EBhb -1Sfn81VkbSMRuBUEegcXMssVo7nMhkmA7 -16g4GBPCtwSLfY8ZgQtmubW2CDqDTwLGWK -19z1Zp4ZPoYYtVKpFSeqqnLgrvdbVxiT13 -1Jw85H83jK5E4mTs5NEADfRRhYwnMuMf39 -1L4n5E7Wk73HvXtVmvDQRk4YLumK8nmGyq -14LEaYTsLa1zW92Q1mhyGMKo4MYFXD1bFW -17pyeiqs4MpxMJf3kZo4TCqu7X4APfk4nk -1PQQdkjcuofM2MGG8mW6ZRtYV3TjMREyUi -1Ca2ABaAjPkq4iHSGcUXcLhfPHgmUkggdW -1Fva4EjBL8hZbyXsxJqzZVtUwbjcBCkZdi -12CEH2QGVokx6WzSejfSmsQpn5GiEKKzCC -1F3wRs3QK7QJV6BwNSi4Auzpbawu58EgDP -161TWgAiajs1Ajt4njnQ5V8tbzb8b7ctd7 -123rZzwq2g54gQxdB58F2V5sZrXF69rnpq -1QFKyqfRQDcVMmzjL94WSmcKga36tDtf8N -12G9XDq6vgHbjz9LB2rKdf8Ja4W7VrGDpK -1Nv6bZU2YUVzgghAB1D528iFWJSBEAo5rT -12PyTTWxpgbS2k89sbBEoe8Pkw2KEwSo8H -15M96MNjweMBFiRJinXebKZujUJRqSbRpB -12pEdkhzM3cabhcifYpiQf72cn8vbknUH3 -1J532afVpajKbKVBb2hDJMTMurAVMh3W93 -1ATUyFyy1bYR8JWxjsJT6MHzNRZnpKM54J -17tP8Pzw9ctNo1oBLZmAQhPiktyVgp4GCC -16qL8pBSnxRGBHJ2vuhBZ1Lac4B9yuvFw5 -14s8an3A9rLQKtvo4FFz9W8KfKrxATgMBj -1EPC3UuCgfh27Xnb3BBCUqEcEyd5wgcENw -16s6aXouevxC2ZKpMrqYAg8shLJqBbyfav -1PQZadtPvsaEdAL6Ka56XkRpHWE8FXKjAe -13bKUc577F2cNUJWzQrwMZePVoKw28FzWf -1M97b8578wpUjRZqz269wStxFcUeNTDfpP -1DomxGXifhHSCNnhdk1YogitgS1U915G13 -1K1ecSVvcwtf8KJgwsgHm8eD1SDQDtJnq2 -1N3CkpP9VipPXwaLLPoQLv4ARELjjKK2Hj -1ELNDsiHCbAqkmtmMwuJuAQdZu4Z8onyG4 -1GrfEePJibYRbwW7P2rCGHwt1D6aZHU2Kf -1LZsgsokm538VKMqVCpuB4Z62or3tGf82A -15tA7N4PEmNAEbKteAXrXd9HoHeXQM4fDL -1Ma5cTmtdT5jDttyZBaoKStty6X8QCAfey -1DNgt7FuJwP739mNCmT44a6nJj8kad5pov -1BGsEC6DvHTAtGWqpmVzMyxspLq3yd4tFn -14j7CbUpxUd4oZNbanMdUMYpmBMy9ghSyu -1HJX84Hg7T5aboShS74iePPgq8nef4jcfc -161mruucsu3Vz5Vm95KYuNCKvvtJNHtw6X -1CcFZ5MPkrQCH2PYtKaLWYSxShoUkR3w4U -1Mbrdb4r4wPGrwyVdaGHmUZ7mqNjqjxwdg -1stSRKjCTi8zmRb8dDAbJ4LD8ckvdhkPH -16Nvzv29k1dS1Lq6fZJrRjWLbPvvpHL9Ay -13Lyj6Nrtro9eBrD8fzhmLn9MbUMZvGsDc -18ahcGJf3sjPEUAzoozVk32gpCky53BnSa -14zt5Qci9QrujuikyhtmeLxgzhSwWr8TVQ -13hw2JDbns44UXU6g3V3JgBgM1rYW9kjzx -1MgQHxNDtGmKXsuemVnVi2rBirkdZqNcok -1NyBLmpdSM8K6NBDKcAivkeb5H3eXLRd8d -1CbUTBdUhSSTVktqY67DCRdVZQD5aiMVYu -128cLWQUEWAczYNM6NbPLWJpXFwwGC16gh -1JubNugn6Gv6cezCLPFk9eE95crRPK4vx -1Ho38tw9Ht9JXZdNQATBHGbMmoGSjBh6EB -169rp6jUEXmeFXVXafivbMDkF657iP5UJU -1Di9eWYzXTrr5QXXemtMsefKvFGUscPL41 -14Dikv7GbD1kaiHEg1pVfHeRtJBnrck3Wa -12ctEtrVvfv143tXXPvgLLsSkea6uktEMg -1NE2RUC8dqy9wJRTZWPT1oCEVUiTHNZCzU -1A7xCwGMWd4n1rg3UULdjgBRsH757K1yne -1F69Hf2je5Ym7UAcDMrKNuj43cWFY7YUfE -1Gi56oTV4cxE7JGbY2H5Ur698X7yr6fHub -121qDS7q3bd4ijsQ2SVjBQpttCbF7Y4bhf -17qicUDCffa6SydpQBU2eXaiNxT1FDjoE1 -171qJwzK6HGsWhWAkKgDrgmZAMYKnmwVTM -1GpfJBYTuGA4tQ6MPCnn5iHtaQkV9kghtk -115SuvxbtDFYxdaXjagKzoH1rtxu5JEnN9 -15bRACbGw67rqub4EpTHY8pEaiucFonwiv -1ELab4Mzmq6PyVGkQAzCuVyUnBwUg7PB1L -15Bepn3x6k6Xsd5pHktV2feKPyHj4gNacy -17qDWJFiFTm3EbFTUdsMcQvK78SrKuyPGb -1QL7VCKKg3zLPsCsmvjnh5xJVGMvGcGHXh -1Jn13tZ8PgFB3j9YdASrfUMb5Kf5hTWBDE -1LoeXtNGzeiLxm9vjteSrL7VF5rRAJeF4W -1ChEg3RM4FytXBx4qEouavH4Hp4Q6xASLw -1Duc7ur9aGY5pQgr2qgDSFVAaFC4Ecnm2R -1A7SxJyUhb931oto4252vSBKcMmkmuzm6Q -12YhgyqoHWGxgn6hkmH4GK4NR71d1Hn12h -1JwCwji1cCzvbsTaTZfXiaE2pZ7QFPnw6r -1PmWfx8rnEvRXDCpfD1XuexidsTDbp3zB9 -134Fe7kr9YfADccusHNuoqxW7eC1JZA42N -1yzaZVYQJ9zK16NbNgsvgTXXezNymRSxT -1LHXyTyv7mQLsm8SHAK2NveiQHctQh4jmP -14WX1ke8Rg5jJXdeWGHCu3KRWWHySD5SFS -1944Nz2NKxVVbT33qHWSuCF1D7Nm9YaPJq -18Nv5McKPtxa2hW4anrC4vrdiVFKgQy1Mv -1BWjsxSwsWLhJ83BeLy4EUeKaLQ5L7sVcr -1Q6jTD2vsQS35Lc4NNZZGaGE2vmFKvRcym -1WHuXoWD1ssLohhbbJ7Px3FZKrMeQEiPd -1Nf3niELqXgr7wV7GP4McnmDKEPCdSDwZk -1M3iMmG4dg5TaSSPKRCa33qAkQbbVF6TsU -1D86wUKtrDZqDng8XMUDbGB2GADSiPSr8m -1NnyH38jZYtgS6nS6h2DzN5frYEE5MAhv2 -1FPYRNGbVCJfuuor8vpbHWK6kobb9uSAYg -12Hhn5bHJZakvrzhZTvz3CKakjtswNQA53 -1CfoM6krsutGb2fv1eGTDughpbbZj8jWqe -16hvfcdrbzfkQ1Quq7DUzGKRhh9aBFxY3a -18d9KHYdmRC5MBPYUz1DQYyGpwRQZiba7F -1EWLPVjPQb3KZKRFN6eRQZoMnHGQg6gVaF -14TV8AzqUtNk1wpfzDRu22JcxbnrnJGJto -1KEy39wWtHMpkuGDxUCPUdDzXzAjoJLWqq -1QFRpqnWVzjwNGss9KZFgPET4s6qvUGKim -18Ar4Hh7UW6eda5azZw4Grw1z2HNryfAH9 -1AGyB1SPEBEPsSojEY7Hn6mHQ83ygobHAx -1A8hL5cfLS4nSUsZuBWVd3pE4W9WL6svhd -1Eccf1QptyweS5F5uetCdUdrShw69YAwVv -13eEKC14KmBSvrLvReWY8dX9RP8fj57XLu -1P5cCMgdafN332hQrdrkMJNa58uJW6YZdW -1KXyHA8rptd1EHqwfXhdguD5URfbWhF8rs -1FYrVf9baGCd5Qzb5WFUiDnXB39giJS1jb -174F7mX51zxrLPomZ6aCFG6rkrxkyhxdVi -13meLuLfv3XjDZEnqpxo8Gkqhk9uCF4XdU -14YUnP286RiPdoPwz9j56jnh4AjV5PujUt -169eBP2sK11SDUhYtfa1mkkNTbNK9efrAY -13z5TAcFQpHsidDSkaH28SUpWihLGmqvhv -1Ez6b5s9GssnbZfv5LyFECL1YMuTtZbapz -15veVD8ap2DCHZRP5j3oLywHzrg36XU1og -1PZsZy1a3bYT6nXy9rjjbEwmJj6VyvFAVZ -1Gz9K7ESGbkecMgVD5LARQsSdT6ucYX7nP -1guKbhM9jkna2iC8Lkukd1RS9qdBkann8 -1KJnpk7jNBAjym4JNi6ZgvEp9hkzvpzjmt -1CZsrCecWm4xX8EVUVvH1eydf51ofRFryi -1Q5eRt7cKiskF5CWsp27NXUJ1YEWqS5zzU -1JNG1Fy5683eWpmrFC1pYS42o4C8xCZ8rV -12r9M2iQykc2ZV1HuY8Ctzw1nCeow4VyXE -1FCx8yZ1YZrZcdYGUSoJ2iErYF32diGHs -18hU7su1sVV1tVmnhCg48posui3NcAWbSB -126nmdK7wUtkqB8FwWsL1TCP16w8n67mK1 -1BQ5ytDuwn3FUVfQV2QWb2DkxCwacukN6r -1Bbs5VzZhRCcHCxPeAHbry8krpGTz2GKs1 -16PRjyaU9PmW1PiaCQpcKw5kj8P6TYjieA -1GhqrCY947CSna9tR54RNrmrbFaCrF8B6r -1J9onNVCFkxGFiJiqEq53fvgSr6nhyhwg3 -17W9GaL4SxbZkwvt6JAzS8fMhg2s2Q6dqf -1GoBDhZB9qkLsfeS9Kg32cMkhRKe7KDrz4 -18qcSgnPKoRnfNiXgqgyKrajvqhWNa5iWx -1BFjRsnkCQqGtrWFyuQPdADbrjqzCftrFE -1ERgCYPA1CHy2ct4KFt5sVPMfCXwsFiGLa -1AAeAHWvoEAhi9cNNqhiyAMLfoVeFakHp7 -1HuLju8YEpuZeg13DhYJ23VmJzTHmVoHCv -1K4hg6YPFyvNUdBvuPDbNp9T6nimxPNV9R -1z3bJ9dt52ZreMQyagxP2u1Bne8ZWMAKw -1GgKap16LHq1CmcF2PDFZn1BtZEj58qv1w -144KAyK3Ree9iokmmfLt13f1LG5qpTAq1k -1MYw9umdJR5hXW59Jq38D1hBSvjhwMnpB3 -1BZ7vudWc9dcsda8v4kyiu8RE5ucE5VgRx -13sRoVLrAYT8stuHU86phkDzqadNGiY1fz -19jxrMqg8rrfn47AV1gfkWGV9TwiiMSf2a -1LzScjNDp6CqQZ25BBrcoE6jGCy9aewDTk -13wYtnCn5empGK4xnMU1KgSRVfU2EGwxmW -1KwTYWcDakrLqcTJWJ8wbeNk7vqUAxVxJs -1MS72nweK5AWpL48f3hRGpfGEkJEZHDne5 -1Eq9V7XjSquDZtjSL7JnJt4vYHmYMv5mqE -19R5hRTuvrDoFq1zR69EGmUVC8U1VnrXRC -1P9XGm3eNKRn7UMR539B7juwjJ2H9hNKPY -1Ly3qa7TWJZehX4bYE1RgSeSzuXyfZcgun -1JwN1NqLW3k2iRPeNdKHNzjhuqJvyEqVDe -1ERa6ugnqHBkXHbtQ6EvEsSvowfDcomE98 -1BjJoYXuvPbnU9hRNnMAEcAkGmB2aTs5et -16C6E9HaVyNYibqkApAXE8VZrWBCKBQbTB -17uW3Kh8oeQ1CgMypN5qMh9kxEFn4qBEAR -13GDjLhJJbyY2t8n8WsQjdKWkZmMW37thY -15pVTFwmaMG9jFLJWAud63zDbggBrJukfB -1GRt8T5ha4HGfLQB3V5tnqQgeVVSYdpnTS -1JdXMrpGun1bev4V1iLxp4RVRH1UF9dxJ5 -1FtzsfZEA1RqwHgcnrz96pGMrEzLekvHR9 -18Mwe1zAt4Dbiiss2CGb97TUQg2KBQkXxn -1MTmTKpYizsJ6gccpAVg9TbAXxs4ND2kVE -1CNRMist9CPpnaoh5FAhco6vSXseMENVb -1CW47r67y4TR6dEAZs1cqBAUSZ4Ldw1wim -1EgNJuCafoPSH5aBHHTDLaugYpm9bR6QVQ -17Abhj8nstPsKuWENaSobPU9xiw37cJgog -1AocKgw2zVg9NLB5pJh3AuuTxyXwBQXc71 -17WRB4zQbW3hbxXikMAafC5qJEirDFaABa -12jUpb2vhUXoAriJMk9Fz2pgQC9R3H4LQL -1JKxyU6jge9untdfgdtNDQeJiWnSMbZKex -1P81YjstjA5hPBUhPPztQM1u71XEVEDpSq -1DmKVfEM1LU1XjSwX2DaEoQj3ZuHwZZdHc -1QA8SQVUoJVQ5yJ1mp24gbkSm8F3BUzxiU -13CbZurSuYbFaGetH5jA4dPL15v1k4PJrN -1AA8ac2PrNFRohGHdketnpbpycsdFFyCAd -1KwNYn9d4jH4z8oapUdukzVWgNzk1eJ2CR -12wgS36rJgQbbnk68iVf8ZLwarJqxyXukh -1MShxJ1sR9rCr3KQjwteWfBzv6CkhUr72B -1JMrptPJHHKEkBHw7qeWU1N5AUyHnP9UXg -129bo4zyTtKJ8woeaomhXd5Cp8gN4N6thd -1DCmdE34feS9gV8GPsduSc3PVkk4x77W2e -1GnLBed9Q8MGXBHMbsGS9ymFcnMuJYNBnB -1Gto9rpiZjSeXaizuDC4k9Utg6x2gM1iDC -17zxioxEY4iV3mNxaTHNYf7rYAX6rP1CQj -14noVN5N6cThyVstG4dQrnJDKfKBPeEsaJ -18d7Yy9Gqh4eqztqPGyQY6srwb1Khg7FpL -18MyUVw4dYHctGpGSHsL8e49BaGG4e8VWG -1NU3brSXbLrbaEwPxRnn1iLBEse1meyAqZ -16Wzeuf3uMCbsSkUs9M8379stWgfsDQVYp -14PZHKvkbCe3eTs4hh6DentJ7daAeJqRvJ -17p1c9n5LwfFN63jo52o9M6ksF89D2eKcb -16JJBxZjBhsQSgBBmk4Sqi1qNatTaNr1aJ -1HrtgMo5U56e6FjyrvwD8cXQG4GNZPh9dc -18iaeqibVM9ADW6KZhWB5Mtdahg7cWAEsG -13VLWHaT4PZATVLHDgusfCqZE3nQhHVHzw -1B12VaLiNiUun76siMhceHMVTtqqmYxQVv -1NFBDR1sWrtccGuN59p93jdVJCX13Sdutg -1MuhB3dYNpon8SSsKE5tWufhTABDL3C71k -16ccFT1T4Bi2Dk7bEJQnfENZ2migRVySov -1LeDkYg2dM62CekiTPLkc2GyMtYfZrk53a -1AgooJ5VHef9Fov72nVELJjw296Jqu9KGB -13qfqzn7BRYbDcvQZykFK4KECtwsec8ua6 -13H14qvWuEowbMorCxcp2fd9ZMoMP2EFLK -14braWHtQLu5PbfkFdFfr6uYtMf1HKtEWe -1FPP65HVquMMVwCikFzmoESug4U57Q5gCw -1JDFurxtFSLMgmxqhkzNwwyE1vhXERxwA4 -1ECNjCbe6JxYbT5YPnv7nLydb8L2bEWxYM -1HLk1Epe4RkYYZpwjGr8SjqHpXCQdqmZjC -1PNTowBBi11L79WUMHkntaQNCKioziePXk -1KPY7HDfyJPY3vAGUsCvYiAucYQEVmcWSy -1BjunRMBoJDmPzRGZKkZA2utGds3qJHZcz -17euyCxnv4Qzt2PY6rHXVKGLaV7rV2iwvK -1NXhZHh2pyv7C8Qq535ZxZMCnharYH4anJ -1Pdanw4DjJj1ngkjAbhog6GEUpo3acs4MQ -1GEh2hLNS9F9ugmHnUCdK8sVXZU4qZoNv2 -123pFsKpHr4pmPbkmQdXNZekVJgUaekWFM -1DFL3GWwCPeMVsWD3LHvQD35Zh1xsskZgL -12TCu21psbZYkjLQB1maCnHee5w4dSD1im -18Nn7TEVF5cUXbsvk8RFs4z4bnqb343Efu -18GpJRE9i62rqoeu1wqtiZod3PQvibFcPC -1FAzZVw2DR7xrXD3n9dPL6FwANk2CXcfAt -1CEcvfMksUT53HzukxqSw8grwDfQ2XNrcg -15LFwQ73t2kqSQVCvnDyMNXi7PQjts6uuz -1Crznw7d7vGWzFUy6KHUjkQBXwBg5X3A1B -15eE5AYa7iJbC6LGjhYQCvEtALygWUvtwp -1FY9wdre1ZTPnjbHKppkr44YGjtmToFrcE -1AdNX1upvcVtxWtMDFmU1rDd778GJRELvC -1F3CqtgRhYrK2wU9BKsnxEfHriKuS9hKiq -1B2AyBwUjYePAjTyttaWPDD9YFRyYaUe4s -1DKwZ4kfYgrDwFMEY4cC8QA2wJVNxFdb14 -13EWVm2apmf7kMH3fqcWMSHrdXquApsiQM -13dVFhaSweTjgGxKuMepw9omSN2qvbd25n -19MrMniUU2ph7PhNgrC8MAdhbfximnSP6g -1DLSoZ13K9hAPDQuV1rxdtUY6ZUwJXPSPa -13QZjLTU7s1yd559g5LhPb422qYNDqnEP5 -1GWdPe4tCEELZ7ft28PRCfM4tsXmG7T1eu -1DCqUSKZbbUxFfeYxia4zYAU86GuCKmEK3 -1CLqpEe3STBaYzBqRfRNR82F3ALFM1NvzG -1uEhcGHzPzCnepjLeYy5ZPdXeJgY1bd2C -1KVPoi5y2tT1R9sx5vSuZedytMrCCY7i25 -138gZhxd8rC6re7TTJz7usPQ96ytdLzqZS -14k2FkZ3L87BqJLYMPpmY4HeCp4Kzds11Q -14gnAGERQxBuvEbYpshzWMLP4mQPSTrtTP -1t3MKUBZkWkQpwTQQcmi8CSjXbM24VxyV -1PecGwu4MPMrYsSzU4DneAJpUSndjkn5Z3 -1LNXA7LvCW9z6hcGgWuoAC5tevZd4PL6Fz -1LMffBBHx2AnkQb9nSAthXx53JWsz4KcDk -1Bjp8DqPZmD3Vtmhgu6S6PiMPPAVXhomui -18aYc5f1F2N4Nrrrdn4awkv4YohzDLfEsq -19t9aLTJ81zHRkpWVVMeuVZQKxnbUAyNds -1F6YbhzHZz38FCCKVP9FzuQ2FejHUBEGdU -1CMKLBBxdM753sVTHcs4k8QDJEj2UFkFHz -182Yew3p6ER1gozm5GfV2NLuUAq4Tz7FVD -141dw7uv5bZMofNyBTWr22jiepzE4wDPoR -19FbHXCuwwaTkY7DMYJDPUF13JvBJ4hFL9 -18tdsBX5bzXmUAmH7NvtYUbFdLMXkZmC2q -19P16aLMxu2TRzNf8QwM6zKKuQErf1xvVX -16qWsW7v2W8ndYfpzqrypXBHwRx62nnfxr -18dAa6HbFBfeVHvbZqp1nGqrgMgXNXYYTX -193HRnBH1yhzqWS3aYCevCcBvwVBThW3tn -1DHPfdFeK6J6TP2xGWqm4LLnxnrLQkYYy2 -1Jz4hi81rWfEL6LtAibMUPahGXpLauCEha -1FfqPG5jYucHjr8wnUpACCtVP8oqvmu7Wa -1DEqz2GJGJWkgQG1qu6LW4CwAQWTFS8ysd -17GnmpcUXgDK1nbqT9Re1EfPSRTQUCrs21 -14hnSKT6VWvfzmj4ZZpufVZc9vdFMBKuW7 -1Es53mVX3uotPXE8G7adadwRg1vYYA83g2 -1J3WTv4rdxmcZYVA1AbEEM2GhEibefs6BE -1Pu14kxht1pRS61TWcv5PgnaXEVTEp35KN -1NCTXvNTkC9fjeozNWMt35D8d9GYwW6JbP -1GmLNxzRzKWMzmF6riFW4bg3cLTiE5typb -1Nw2KSvRf9kaYtbEXi5EKcDnimHxWQZ9Q2 -13SXiugGftnPrdKz684uL2Ekqhqw2Fv9Kv -17QBA9Q7GuyStmDhunP1YcgvrervmE6iXT -12hQHYjg7wBkbz21h3qYvnD9KJ4cD4vCTS -1ENU2ku5T2cYcQA8Yk9e6Xt3DCxw1v1Nsk -1Kbw17PYLn8saf2hR89MGE4oCVBmLjvyvW -1LJYt1eB8pKx17cnKZcsorybymYimtzBbF -1J4wW3XhcmApaoMRyvMYFpa5JnjJRx7bLP -1PCs1y1FDAWF2nZvN3c4RifoGSNQ5YyEPu -17rNtHdh95Py3p5auCJobyyurmXMnAaFnP -14s1FQGm6ofntneRbqLjGcgdhGNheKFxsT -16xQXZLXSwwXeLRqzxuS7tWMogcitCQ52W -1GUiX4fkKxeDeJSQwFkEfMw3aCssseB2ML -17y8z1foSQNeeHjRCNDGHLzdnsiehvCYwU -1E4hAQm7JyAZzc9jNAWDryt7cmryjTbmjK -1BaP7yS7XUhcqDrtS63hLmfL1Pe7ybQvHP -1D6gzPa1MeR6qEUsmVvamfPnwVrKvBajtA -1HD8eDq2vXbxkTKPBvJXSXiZSzkDJPgxar -12YTp7UMmqDV6bvnKGwymwfZHjEdP7QWf9 -19HtigGnFEnCsMmdjTNMzeMH2wgbe42hxj -15VRxDX7JBtAfpj21FfceVzacAzPmTWEvz -1A5v7Y5Z8oaHJ9yaf6joeJ2CqhpTh9a1Ak -1ELhikDJuKYCf5RK6aDhzzxhv1Eta7kue4 -1G5ZPFfZCAR3heRaJWAJYibsCfci6jiKba -17GfJpBHWs4utJe1ujEvRKvnWG6jsSVh3E -1354kRp6T7R6bDtpPbtoFqKDJxotj7CEEg -1JMHLF9wAgDtqQtrj3YFnCWwHQC4tMz9y6 -14VCTwvvLgdxnDL6wXu8L4Wq77hWJ9Lyn9 -1GkHA3pnXNQ175o8pM3WVtYhh74xVfis4m -1BVyvfRCnior2DwMTvWdVwXz4wRM4eV1dB -1P6icJU7GYqyYeoSbFGc6WtUgH4uBvrVYQ -1CCqFNK6kZpQv2b2sUkEMYNPoA1LDaKY7X -1EWCf8dzNUR1ijK4M3E57edsKnq9wLwZfB -1PPSADWFNyBCyf2UUQjrkuiUNvngNJzgJf -1FT8V4VjhqH5vDrcwCt9w7PBWCFVLLDD2g -1FGF1zvUQKGBCwNSHcMBKooXsp6TBh5vgk -12CxJdthb9tGwXW5MEXtNGb4d6wr6j3P4w -16jKhyEJBg8JTEjcFDFsuDUmXPeHeZkEKS -1AB27w6paxP3StYVmhq1UeZT1dATfHehQS -1Ni6S1oznLGgC75UsUua6bbpm1QwkZUFmh -1JQWj7ePXAcG7sjZLh97yNcqDntxgnV1N2 -1CscrUuWuY7ncNeoUjK49AG6euqhjr5rX2 -1AmsTXfeWsYYwZrESYE8RGGz6D5vXLLmeS -1LxG4zyrAj2FX7N8zNn6bWeoYMMKUFzboe -1BMNhNBQcu9MjEJGjDHgaQPLocYMYXpQbK -1Fo4kadtPAx1RbGqHnRV4XmnkkHBi6qJKd -1Q2wkHZHbkLAtg5xJaxJvAk2fipyzX5FBq -1BJk713mMSJU5WLxuEPciJbCTvGHdWD8qF -19BZDfpRm5Ancno74LoXMoeNV8ZvdFuscq -1P6brD5MFNdyaFrhrqadzPTkQQuh9hXiup -16XUgYDkigfJMSad7kR6WhttggPb4JwEDB -1rrTPHxQ9dniQBJLt5MognwPaf7ic4U3G -1BnaRsV15Up3Y6R9MeWGUMEVXFnWTfFf1X -16YxjrDt7ghVTnkrjkQ46ZsjoyRtj7Dtro -1EhgTgpWm5ymsQjHpr48TokZtKxKXHea38 -1BJjnxETzi3Z2H85uB7Cvne1jMf3pZEpxi -1DeGJMb5zQc5njgUkyJfsUsUJYSdhtkTTf -1KEmDwFpqbmYzgxUquqHoeh8x4tVijiW4r -1LZn2MCdiBVphPK7AVhMfZirZ53Mm9ghVc -1HLTBG6BzHSf7RyS2FThczyfTFHFm37kjK -12EtQx1eSQkkGAVqTs3JhQDVS1QGN8ws1N -1BbwDE6tg6ZFLyZ83Sbpsw4LspXGNTpjEE -1N6mqfcFgTSTTGEivq3Q1HgbUWbASpXAnr -1FFQBVy4hK28aGHkZTwBo99NvZhx7piSUD -1FynKcDzYdLrauEKNJtXvzE8hRDD3AurVn -1Le1vYGtvaAQzUYfJNBedMxbnPYjFpsKg6 -13e92EKCZxkUzqTB2e3UpbTHkKYyBnEH8v -15iTHzMDiCn1DHBk1huiEBp5MRyntKcEq6 -1P9JWUnNkMaM3C29nSoUSVrQy61CxLkJbt -1Kfgjy9mv7dCBzsjoNQg5mxQcaf7PqZvtr -16UswN5LByGZe52tWSEVY5wk7eW9EHUgvA -1AD14hXsoG8HFq73iGNgEYTwP75vCpE99m -1Bd4BT7D1UBGYo26uw9jQuEVnCrTVxzY2d -16VQeGPpVVVTckTjhGJCBvUgjpTZj8TiFy -19XLyVF1Ckab2QxKpyDhUGctiLeRshmZi3 -16DAZRSAdB9sTaQfbGwcbFQWS3u6hY9EYA -14STs7QHk9f1KDpCyhfA461SwtxpREqANH -15RbwBrbNuyVZWawYcBwBPqjqfRJnK29Nz -141125cLgVp67d59Vheesz5CNrTJpoN1xX -17jzG7B6pfetSZfFFYkT2QpLf7hBq4Gkza -1MZzDJyH1ytzJPqwozCurGTXGz8bXv92qF -1Cz5tzo9pJjYQHAHrfzygh46zbYooMZ4A9 -1KwFtBnB7u9FYxk7hjuG5P9pcmA3iafSMe -14vZWsBkcQCsfwkKvGYQCDNu49BfTqZv4g -1HDk2av5JFrbQfhCspAu2Lz2JL7XKHoSpJ -1EueUe5M8bbhRSPvqmmLFGtQHatxD4eQ6z diff --git a/emscripten/test-correctness-segwit-p2sh.js b/emscripten/test-correctness-segwit-p2sh.js deleted file mode 100644 index 0d3c46c31..000000000 --- a/emscripten/test-correctness-segwit-p2sh.js +++ /dev/null @@ -1,30 +0,0 @@ -var crypto = require('./trezor-crypto'); -var bitcoin = require('bitcoinjs-lib'); - -var XPUB = - 'xpub6CVKsQYXc9awxgV1tWbG4foDvdcnieK2JkbpPEBKB5WwAPKBZ1mstLbKVB4ov7QzxzjaxNK6EfmNY5Jsk2cG26EVcEkycGW4tchT2dyUhrx'; -var node = bitcoin.HDNode.fromBase58(XPUB).derive(0); - -var nodeStruct = { - depth: node.depth, - child_num: node.index, - fingerprint: node.parentFingerprint, - chain_code: node.chainCode, - public_key: node.keyPair.getPublicKeyBuffer() -}; - -var addresses = crypto.deriveAddressRange(nodeStruct, 0, 999, 5, true); - -var fs = require('fs'); -var loaded = fs.readFileSync('test-addresses-segwit-p2sh.txt').toString().split("\n"); - -for (var i = 0; i < 1000; i++) { - if (loaded[i] !== addresses[i]) { - console.log("bad address", i); - process.exit(1) - } -} - -console.log("Testing address ended correctly"); -process.exit(0) - diff --git a/emscripten/test-correctness.js b/emscripten/test-correctness.js deleted file mode 100644 index 9f9f2042d..000000000 --- a/emscripten/test-correctness.js +++ /dev/null @@ -1,30 +0,0 @@ -var crypto = require('./trezor-crypto'); -var bitcoin = require('bitcoinjs-lib'); - -var XPUB = - 'xpub6BiVtCpG9fQPxnPmHXG8PhtzQdWC2Su4qWu6XW9tpWFYhxydCLJGrWBJZ5H6qTAHdPQ7pQhtpjiYZVZARo14qHiay2fvrX996oEP42u8wZy'; -var node = bitcoin.HDNode.fromBase58(XPUB).derive(0); - -var nodeStruct = { - depth: node.depth, - child_num: node.index, - fingerprint: node.parentFingerprint, - chain_code: node.chainCode, - public_key: node.keyPair.getPublicKeyBuffer() -}; - -var addresses = crypto.deriveAddressRange(nodeStruct, 0, 999, 0, false); - -var fs = require('fs'); -var loaded = fs.readFileSync('test-addresses.txt').toString().split("\n"); - -for (var i = 0; i < 1000; i++) { - if (loaded[i] !== addresses[i]) { - console.log("bad address", i); - process.exit(1) - } -} - -console.log("Testing address ended correctly"); -process.exit(0) - diff --git a/emscripten/trezor-crypto.js b/emscripten/trezor-crypto.js deleted file mode 100644 index b56b4b49f..000000000 --- a/emscripten/trezor-crypto.js +++ /dev/null @@ -1,379 +0,0 @@ -"undefined"===typeof importScripts&&"undefined"!==typeof WorkerGlobalScope&&this instanceof WorkerGlobalScope&&(this.importScripts=function(){throw Error("importScripts is a stub");});var e;e||(e=eval("(function() { try { return Module || {} } catch(e) { return {} } })()"));var aa={},k;for(k in e)e.hasOwnProperty(k)&&(aa[k]=e[k]);var ba=!1,l=!1,m=!1,ca=!1; -if(e.ENVIRONMENT)if("WEB"===e.ENVIRONMENT)ba=!0;else if("WORKER"===e.ENVIRONMENT)l=!0;else if("NODE"===e.ENVIRONMENT)m=!0;else if("SHELL"===e.ENVIRONMENT)ca=!0;else throw Error("The provided Module['ENVIRONMENT'] value is not valid. It must be one of: WEB|WORKER|NODE|SHELL.");else ba="object"===typeof window,l="function"===typeof importScripts,m="object"===typeof process&&"function"===typeof require&&!ba&&!l,ca=!ba&&!m&&!l; -if(m){e.print||(e.print=console.log);e.printErr||(e.printErr=console.warn);var da,ea;e.read=function(a,b){da||(da=require("fs"));ea||(ea=require("path"));a=ea.normalize(a);var c=da.readFileSync(a);return b?c:c.toString()};e.readBinary=function(a){a=e.read(a,!0);a.buffer||(a=new Uint8Array(a));assert(a.buffer);return a};e.load=function(a){fa(read(a))};e.thisProgram||(e.thisProgram=1 0) var gc = undefined");else if(ba||l)e.read=function(a){var b=new XMLHttpRequest;b.open("GET",a,!1);b.send(null);return b.responseText},e.readAsync=function(a,b,c){var d=new XMLHttpRequest;d.open("GET",a,!0);d.responseType="arraybuffer";d.onload=function(){200==d.status||0==d.status&&d.response?b(d.response):c()};d.onerror=c;d.send(null)},"undefined"!= -typeof arguments&&(e.arguments=arguments),"undefined"!==typeof console?(e.print||(e.print=function(a){console.log(a)}),e.printErr||(e.printErr=function(a){console.warn(a)})):e.print||(e.print=function(){}),l&&(e.load=importScripts),"undefined"===typeof e.setWindowTitle&&(e.setWindowTitle=function(a){document.title=a});else throw"Unknown runtime environment. Where are we?";function fa(a){eval.call(null,a)}!e.load&&e.read&&(e.load=function(a){fa(e.read(a))});e.print||(e.print=function(){}); -e.printErr||(e.printErr=e.print);e.arguments||(e.arguments=[]);e.thisProgram||(e.thisProgram="./this.program");e.print=e.print;e.ba=e.printErr;e.preRun=[];e.postRun=[];for(k in aa)aa.hasOwnProperty(k)&&(e[k]=aa[k]); -var aa=void 0,t={Wa:function(a){tempRet0=a},Na:function(){return tempRet0},Q:function(){return p},I:function(a){p=a},va:function(a){switch(a){case "i1":case "i8":return 1;case "i16":return 2;case "i32":return 4;case "i64":return 8;case "float":return 4;case "double":return 8;default:return"*"===a[a.length-1]?t.V:"i"===a[0]?(a=parseInt(a.substr(1)),assert(0===a%8),a/8):0}},Ma:function(a){return Math.max(t.va(a),t.V)},Wc:16,rd:function(a,b){"double"===b||"i64"===b?a&7&&(assert(4===(a&7)),a+=4):assert(0=== -(a&3));return a},ed:function(a,b,c){return c||"i64"!=a&&"double"!=a?a?Math.min(b||(a?t.Ma(a):0),t.V):Math.min(b,8):8},t:function(a,b,c){return c&&c.length?e["dynCall_"+a].apply(null,[b].concat(c)):e["dynCall_"+a].call(null,b)},N:[],Ha:function(a){for(var b=0;b>2];a=(b+a+15|0)&-16;w[x>>2]=a;if(a=a>=ha)ia(),a=!0;return a?(w[x>>2]=b,0):b},ma:function(a,b){return Math.ceil(a/(b?b:16))*(b?b:16)},qd:function(a,b,c){return c?+(a>>>0)+4294967296*+(b>>>0):+(a>>>0)+4294967296*+(b|0)},L:8,V:4,Xc:0};e.Runtime=t;t.addFunction=t.Ha;t.removeFunction=t.Sa;var ja=0;function assert(a,b){a||z("Assertion failed: "+b)} -function ka(a){var b=e["_"+a];if(!b)try{b=eval("_"+a)}catch(c){}assert(b,"Cannot call unknown function "+a+" (perhaps LLVM optimizations or closure removed it?)");return b}var la,ma; -(function(){function a(a){a=a.toString().match(f).slice(1);return{arguments:a[0],body:a[1],returnValue:a[2]}}function b(){if(!g){g={};for(var b in c)c.hasOwnProperty(b)&&(g[b]=a(c[b]))}}var c={stackSave:function(){t.Q()},stackRestore:function(){t.I()},arrayToC:function(a){var b=t.P(a.length);na(a,b);return b},stringToC:function(a){var b=0;if(null!==a&&void 0!==a&&0!==a){var c=(a.length<<2)+1,b=t.P(c);oa(a,b,c)}return b}},d={string:c.stringToC,array:c.arrayToC};ma=function(a,b,c,f,g){a=ka(a);var y= -[],H=0;if(f)for(var A=0;A>0]=b;break;case "i8":C[a>>0]=b;break;case "i16":qa[a>>1]=b;break;case "i32":w[a>>2]=b;break;case "i64":tempI64=[b>>>0,(tempDouble=b,1<=+ra(tempDouble)?0>>0:~~+ua((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)];w[a>>2]=tempI64[0];w[a+4>>2]=tempI64[1];break;case "float":va[a>>2]=b;break;case "double":wa[a>>3]=b;break;default:z("invalid type for setValue: "+ -c)}}e.setValue=pa;function xa(a,b){b=b||"i8";"*"===b.charAt(b.length-1)&&(b="i32");switch(b){case "i1":return C[a>>0];case "i8":return C[a>>0];case "i16":return qa[a>>1];case "i32":return w[a>>2];case "i64":return w[a>>2];case "float":return va[a>>2];case "double":return wa[a>>3];default:z("invalid type for setValue: "+b)}return null}e.getValue=xa;e.ALLOC_NORMAL=0;e.ALLOC_STACK=1;e.ALLOC_STATIC=2;e.ALLOC_DYNAMIC=3;e.ALLOC_NONE=4; -function D(a,b,c,d){var f,g;"number"===typeof a?(f=!0,g=a):(f=!1,g=a.length);var h="string"===typeof b?b:null;c=4==c?d:["function"===typeof E?E:t.ga,t.P,t.ga,t.qa][void 0===c?2:c](Math.max(g,h?1:b.length));if(f){d=c;assert(0==(c&3));for(a=c+(g&-4);d>2]=0;for(a=c+g;d>0]=0;return c}if("i8"===h)return a.subarray||a.slice?F.set(a,c):F.set(new Uint8Array(a),c),c;d=0;for(var n,u;d>0];c|=d;if(0==d&&!b)break;f++;if(b&&f==b)break}b||(b=f);d="";if(128>c){for(;0>0];if(!c)return b;b+=String.fromCharCode(c)}}; -e.stringToAscii=function(a,b){return Aa(a,b,!1)};var Ba="undefined"!==typeof TextDecoder?new TextDecoder("utf8"):void 0; -function Ca(a,b){for(var c=b;a[c];)++c;if(16d?c+=String.fromCharCode(d):(d-=65536,c+=String.fromCharCode(55296|d>> -10,56320|d&1023)))):c+=String.fromCharCode(d)}}e.UTF8ArrayToString=Ca;e.UTF8ToString=function(a){return Ca(F,a)}; -function Da(a,b,c,d){if(!(0=h&&(h=65536+((h&1023)<<10)|a.charCodeAt(++g)&1023);if(127>=h){if(c>=d)break;b[c++]=h}else{if(2047>=h){if(c+1>=d)break;b[c++]=192|h>>6}else{if(65535>=h){if(c+2>=d)break;b[c++]=224|h>>12}else{if(2097151>=h){if(c+3>=d)break;b[c++]=240|h>>18}else{if(67108863>=h){if(c+4>=d)break;b[c++]=248|h>>24}else{if(c+5>=d)break;b[c++]=252|h>>30;b[c++]=128|h>>24&63}b[c++]=128|h>>18&63}b[c++]=128| -h>>12&63}b[c++]=128|h>>6&63}b[c++]=128|h&63}}b[c]=0;return c-f}e.stringToUTF8Array=Da;function oa(a,b,c){return Da(a,F,b,c)}e.stringToUTF8=oa;function Ea(a){for(var b=0,c=0;c=d&&(d=65536+((d&1023)<<10)|a.charCodeAt(++c)&1023);127>=d?++b:b=2047>=d?b+2:65535>=d?b+3:2097151>=d?b+4:67108863>=d?b+5:b+6}return b}e.lengthBytesUTF8=Ea;"undefined"!==typeof TextDecoder&&new TextDecoder("utf-16le"); -function Fa(a){return a.replace(/__Z[\w\d_]+/g,function(a){var c;a:{if(e.___cxa_demangle)try{var d=a.substr(1),f=Ea(d)+1,g=E(f);oa(d,g,f);var h=E(4),n=e.___cxa_demangle(g,0,0,h);if(0===xa(h,"i32")&&n){c=B(n);break a}}catch(u){}finally{g&&Ga(g),h&&Ga(h),n&&Ga(n)}else t.A("warning: build with -s DEMANGLE_SUPPORT=1 to link in libcxxabi demangling");c=a}return a===c?a:a+" ["+c+"]"})} -function Ha(){var a;a:{a=Error();if(!a.stack){try{throw Error(0);}catch(b){a=b}if(!a.stack){a="(no stack trace available)";break a}}a=a.stack.toString()}e.extraStackTrace&&(a+="\n"+e.extraStackTrace());return Fa(a)}e.stackTrace=Ha;var buffer,C,F,qa,Ia,w,Ja,va,wa,Ka,v,ya,La,p,Ma,Oa,x;Ka=v=La=p=Ma=Oa=x=0;ya=!1; -function ia(){z("Cannot enlarge memory arrays. Either (1) compile with -s TOTAL_MEMORY=X with X higher than the current value "+ha+", (2) compile with -s ALLOW_MEMORY_GROWTH=1 which adjusts the size at runtime but prevents some optimizations, (3) set Module.TOTAL_MEMORY to a higher value before the program runs, or if you want malloc to return NULL (0) instead of this abort, compile with -s ABORTING_MALLOC=0 ")} -for(var Pa=e.TOTAL_STACK||5242880,ha=e.TOTAL_MEMORY||16777216,G=65536;GG?2*G:G+16777216;G!==ha&&(ha=G);e.buffer?buffer=e.buffer:buffer=new ArrayBuffer(ha);e.HEAP8=C=new Int8Array(buffer);e.HEAP16=qa=new Int16Array(buffer);e.HEAP32=w=new Int32Array(buffer);e.HEAPU8=F=new Uint8Array(buffer);e.HEAPU16=Ia=new Uint16Array(buffer);e.HEAPU32=Ja=new Uint32Array(buffer);e.HEAPF32=va=new Float32Array(buffer);e.HEAPF64=wa=new Float64Array(buffer);w[0]=1668509029;qa[1]=25459; -if(115!==F[2]||99!==F[3])throw"Runtime error: expected the system to be little-endian!";e.HEAP=void 0;e.buffer=buffer;e.HEAP8=C;e.HEAP16=qa;e.HEAP32=w;e.HEAPU8=F;e.HEAPU16=Ia;e.HEAPU32=Ja;e.HEAPF32=va;e.HEAPF64=wa;function Qa(a){for(;0>0]=a.charCodeAt(d);c||(C[b>>0]=0)}e.writeAsciiToMemory=Aa;Math.imul&&-5===Math.imul(4294967295,5)||(Math.imul=function(a,b){var c=a&65535,d=b&65535;return c*d+((a>>>16)*d+c*(b>>>16)<<16)|0});Math.ld=Math.imul; -Math.clz32||(Math.clz32=function(a){a=a>>>0;for(var b=0;32>b;b++)if(a&1<<31-b)return b;return 32});Math.bd=Math.clz32;Math.trunc||(Math.trunc=function(a){return 0>a?Math.ceil(a):Math.floor(a)});Math.trunc=Math.trunc;var ra=Math.abs,ua=Math.ceil,ta=Math.floor,sa=Math.min,Ya=0,Za=null,$a=null;function ab(){Ya++;e.monitorRunDependencies&&e.monitorRunDependencies(Ya)}e.addRunDependency=ab; -function bb(){Ya--;e.monitorRunDependencies&&e.monitorRunDependencies(Ya);if(0==Ya&&(null!==Za&&(clearInterval(Za),Za=null),$a)){var a=$a;$a=null;a()}}e.removeRunDependency=bb;e.preloadedImages={};e.preloadedAudios={};Ka=8;v=Ka+40448;Sa.push(); -D([8,201,188,243,103,230,9,106,59,167,202,132,133,174,103,187,43,248,148,254,114,243,110,60,241,54,29,95,58,245,79,165,209,130,230,173,127,82,14,81,31,108,62,43,140,104,5,155,107,189,65,251,171,217,131,31,121,33,126,19,25,205,224,91,34,174,40,215,152,47,138,66,205,101,239,35,145,68,55,113,47,59,77,236,207,251,192,181,188,219,137,129,165,219,181,233,56,181,72,243,91,194,86,57,25,208,5,182,241,17,241,89,155,79,25,175,164,130,63,146,24,129,109,218,213,94,28,171,66,2,3,163,152,170,7,216,190,111,112,69, -1,91,131,18,140,178,228,78,190,133,49,36,226,180,255,213,195,125,12,85,111,137,123,242,116,93,190,114,177,150,22,59,254,177,222,128,53,18,199,37,167,6,220,155,148,38,105,207,116,241,155,193,210,74,241,158,193,105,155,228,227,37,79,56,134,71,190,239,181,213,140,139,198,157,193,15,101,156,172,119,204,161,12,36,117,2,43,89,111,44,233,45,131,228,166,110,170,132,116,74,212,251,65,189,220,169,176,92,181,83,17,131,218,136,249,118,171,223,102,238,82,81,62,152,16,50,180,45,109,198,49,168,63,33,251,152,200, -39,3,176,228,14,239,190,199,127,89,191,194,143,168,61,243,11,224,198,37,167,10,147,71,145,167,213,111,130,3,224,81,99,202,6,112,110,14,10,103,41,41,20,252,47,210,70,133,10,183,39,38,201,38,92,56,33,27,46,237,42,196,90,252,109,44,77,223,179,149,157,19,13,56,83,222,99,175,139,84,115,10,101,168,178,119,60,187,10,106,118,230,174,237,71,46,201,194,129,59,53,130,20,133,44,114,146,100,3,241,76,161,232,191,162,1,48,66,188,75,102,26,168,145,151,248,208,112,139,75,194,48,190,84,6,163,81,108,199,24,82,239,214, -25,232,146,209,16,169,101,85,36,6,153,214,42,32,113,87,133,53,14,244,184,209,187,50,112,160,106,16,200,208,210,184,22,193,164,25,83,171,65,81,8,108,55,30,153,235,142,223,76,119,72,39,168,72,155,225,181,188,176,52,99,90,201,197,179,12,28,57,203,138,65,227,74,170,216,78,115,227,99,119,79,202,156,91,163,184,178,214,243,111,46,104,252,178,239,93,238,130,143,116,96,47,23,67,111,99,165,120,114,171,240,161,20,120,200,132,236,57,100,26,8,2,199,140,40,30,99,35,250,255,190,144,233,189,130,222,235,108,80,164, -21,121,198,178,247,163,249,190,43,83,114,227,242,120,113,198,156,97,38,234,206,62,39,202,7,194,192,33,199,184,134,209,30,235,224,205,214,125,218,234,120,209,110,238,127,79,125,245,186,111,23,114,170,103,240,6,166,152,200,162,197,125,99,10,174,13,249,190,4,152,63,17,27,71,28,19,53,11,113,27,132,125,4,35,245,119,219,40,147,36,199,64,123,171,202,50,188,190,201,21,10,190,158,60,76,13,16,156,196,103,29,67,182,66,62,203,190,212,197,76,42,126,101,252,156,41,127,89,236,250,214,58,171,111,203,95,23,88,71, -74,140,25,68,108,47,252,255,63,251,255,255,63,255,255,255,63,255,255,255,63,255,255,255,63,255,255,255,63,255,255,255,63,255,255,255,63,255,255,0,0,152,23,248,22,108,5,202,39,149,141,226,28,203,54,255,38,2,7,11,7,58,87,138,1,90,197,186,11,119,190,159,25,190,121,0,0,184,212,16,59,63,66,31,49,153,65,85,40,41,18,237,5,253,168,8,17,56,240,239,19,218,85,70,60,168,201,157,54,58,72,0,0,65,65,54,16,51,122,73,63,187,3,138,52,171,57,183,43,186,254,255,63,255,255,255,63,255,255,255,63,255,255,255,63,255,255, -0,0,160,32,27,40,25,189,164,63,221,1,69,58,213,156,219,21,93,255,255,63,255,255,255,63,255,255,255,63,255,255,255,63,255,127,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,152,23,248,22,108,5,202,39,149,141,226,28,203,54,255,38,2,7,11,7,58,87,138,1,90,197,186,11,119,190,159,25,190,121,0,0,184,212,16,59,63,66,31,49,153,65,85,40,41,18,237,5,253,168,8,17,56,240,239,19,218,85,70,60,168,201,157,54,58,72,0,0,249,54,224,60,78,196,7,24,8,155,249,54,96,17,114,12,181,41, -82,29,226,23,62,17,147,4,49,12,150,100,128,34,48,249,0,0,114,230,184,4,214,245,231,50,182,49,34,12,77,102,42,0,101,86,243,55,168,152,223,12,254,64,129,30,203,216,195,30,143,56,0,0,228,239,64,50,166,85,163,46,124,171,25,6,119,47,225,34,232,40,81,28,41,148,156,18,91,53,9,50,129,70,147,55,139,47,0,0,214,98,172,38,234,244,161,50,13,132,214,48,234,198,9,34,247,38,196,9,155,118,167,46,77,109,61,30,185,141,137,8,172,216,0,0,188,249,196,10,183,119,175,36,206,57,14,51,128,223,102,16,61,14,122,42,203,151,205, -35,57,170,78,27,151,27,25,60,189,92,0,0,218,100,114,8,160,152,32,20,90,123,222,63,4,46,244,4,168,219,84,26,24,182,53,30,49,10,150,21,137,46,144,50,235,106,0,0,190,204,39,60,55,68,124,13,76,113,126,5,211,165,229,37,224,189,154,21,125,42,94,52,154,48,101,63,49,188,56,33,212,172,0,0,55,156,79,6,171,152,48,23,240,224,248,53,13,41,34,54,173,233,97,59,216,197,37,32,67,214,159,61,41,108,72,34,51,204,0,0,203,8,160,29,37,94,176,47,27,137,23,28,249,2,102,18,86,172,90,6,195,173,145,16,239,229,17,20,42,22,254, -57,74,119,0,0,27,198,83,9,39,211,117,0,131,106,157,63,183,120,108,11,55,101,179,55,94,91,117,15,36,144,225,53,218,186,12,40,132,217,0,0,168,90,64,25,60,126,183,59,221,140,229,16,152,241,126,29,176,81,134,52,13,23,72,7,125,188,136,18,93,182,240,28,135,242,0,0,129,237,3,27,75,45,215,38,242,145,250,33,148,182,129,6,58,71,175,13,151,173,75,8,88,151,168,0,98,163,11,36,176,10,0,0,14,8,126,34,227,243,182,18,228,121,95,8,207,27,101,57,49,17,244,31,37,140,107,25,164,101,169,62,80,223,83,19,146,215,0,0,88, -107,162,54,127,114,19,20,92,58,109,9,246,202,43,16,234,239,109,12,163,8,187,16,56,104,42,7,27,170,28,10,30,88,0,0,10,236,109,42,120,162,59,17,156,174,165,7,110,218,196,40,178,151,62,2,135,240,170,6,1,83,236,41,103,237,164,51,15,230,0,0,33,104,97,41,57,179,204,7,190,240,35,13,145,71,162,37,18,16,55,57,213,211,124,38,219,41,89,25,121,230,28,20,227,247,0,0,195,229,24,17,168,194,97,47,25,188,190,18,209,201,230,21,252,75,91,38,211,187,149,5,68,219,7,19,145,101,215,12,202,110,0,0,104,134,160,5,224,189, -40,38,68,195,142,63,142,142,90,18,58,160,117,56,210,65,94,61,146,5,113,32,158,94,237,8,1,213,0,0,46,246,135,15,133,199,52,59,112,18,22,55,24,142,185,57,16,240,89,6,77,59,209,49,215,192,14,57,111,188,239,14,98,233,0,0,55,231,78,36,190,250,4,12,229,68,136,22,119,242,16,24,254,41,169,26,59,234,84,58,15,158,158,41,240,210,14,29,169,56,0,0,60,115,141,42,224,183,42,44,158,143,202,47,216,47,157,48,255,130,214,0,130,188,141,18,136,160,219,33,69,249,92,55,130,188,0,0,240,151,119,52,19,132,225,57,1,115,137, -51,185,46,232,36,174,223,2,31,198,253,210,38,74,197,202,49,18,129,14,35,242,229,0,0,113,118,188,31,197,136,191,31,45,227,88,40,20,242,198,15,116,144,244,24,94,56,71,10,32,29,33,23,217,49,146,4,61,142,0,0,236,125,113,24,144,113,199,59,167,68,225,35,169,234,74,13,185,14,233,19,78,134,3,18,100,31,184,60,179,67,56,18,154,9,0,0,178,29,179,62,202,208,161,12,15,106,80,15,226,9,186,50,143,182,162,8,66,251,100,40,150,136,73,10,141,136,106,36,168,120,0,0,67,67,250,57,142,88,167,1,211,130,11,0,118,243,230,13, -84,246,45,48,156,84,201,23,207,191,92,3,212,250,214,40,18,105,0,0,149,229,176,13,222,61,210,20,182,43,8,58,126,46,143,5,167,235,118,32,5,150,221,56,124,125,177,49,118,21,6,30,134,125,0,0,232,61,115,60,234,120,84,38,41,83,93,34,131,19,225,13,41,56,136,15,181,175,184,24,229,114,135,47,33,251,183,38,185,226,0,0,252,13,6,22,20,190,63,2,160,162,230,5,8,225,23,21,118,134,176,26,16,119,46,37,132,132,172,2,22,192,67,12,197,221,0,0,168,12,130,39,219,42,126,45,15,115,4,61,170,241,235,54,65,144,14,15,50,183, -173,6,25,32,105,25,131,188,206,11,13,186,0,0,8,21,245,21,255,136,27,25,16,202,193,26,245,42,231,48,216,56,226,45,92,248,184,41,162,158,157,32,177,132,140,9,130,130,0,0,175,108,226,54,191,186,109,12,237,123,177,55,11,235,132,53,98,206,10,54,194,160,91,9,232,69,254,61,85,97,2,42,248,17,0,0,250,141,126,37,231,50,240,51,79,24,126,60,104,100,36,32,9,160,140,41,178,226,195,40,217,192,196,25,30,252,203,51,98,130,0,0,106,55,172,59,99,227,63,23,131,71,76,49,202,76,187,45,87,52,79,51,22,187,136,59,111,230, -228,9,68,130,120,37,253,131,0,0,111,219,107,2,44,146,75,1,73,185,52,55,30,245,6,41,124,135,156,41,51,201,22,4,104,81,221,13,104,199,34,23,130,25,0,0,155,252,156,4,19,194,125,23,107,58,109,15,35,179,123,58,235,108,159,53,83,50,135,9,32,243,120,8,83,195,67,12,148,98,0,0,76,130,130,61,72,37,180,3,101,78,83,33,23,141,99,41,223,158,153,2,27,187,213,23,60,68,145,1,88,4,27,54,18,111,0,0,208,52,235,6,32,13,231,21,184,197,75,5,66,144,36,7,57,105,55,34,245,207,83,38,117,8,250,59,172,18,253,61,79,92,0,0,41, -54,69,27,11,112,183,29,48,96,158,53,3,55,247,51,69,246,190,58,136,90,156,24,66,209,165,42,130,230,27,35,58,32,0,0,132,159,248,63,20,30,199,37,69,237,133,18,113,201,122,27,104,18,6,1,125,69,219,49,108,147,155,29,151,247,212,2,15,59,0,0,203,126,108,36,119,195,196,32,151,206,180,27,249,79,187,14,157,236,225,38,33,205,220,59,129,28,24,52,64,207,186,50,42,110,0,0,32,135,188,46,123,128,36,17,200,18,117,54,70,174,193,49,250,58,100,59,195,107,19,3,216,73,225,62,251,229,25,41,97,158,0,0,126,20,164,48,207, -99,192,45,30,32,95,55,253,98,247,17,39,88,10,9,41,250,197,5,246,186,86,17,122,186,36,1,167,213,0,0,255,101,251,51,224,242,44,57,248,87,127,22,30,97,54,49,244,50,5,30,217,65,38,36,196,111,156,56,234,118,189,9,181,157,0,0,198,206,237,24,175,209,118,59,84,244,52,54,180,48,135,1,161,198,218,44,192,24,191,15,82,128,186,24,248,170,102,4,197,56,0,0,8,219,51,25,236,47,184,21,100,10,83,53,138,32,91,40,40,47,40,31,157,104,203,50,104,166,50,23,118,161,72,55,73,230,0,0,57,183,229,17,213,150,243,15,215,46,34, -18,255,12,78,46,224,109,132,60,27,27,115,38,47,167,101,56,162,220,103,5,94,23,0,0,149,214,254,41,251,191,233,59,198,69,67,18,183,86,101,45,172,94,31,55,127,148,94,62,78,186,158,7,143,103,131,27,80,211,0,0,22,18,4,5,199,227,223,22,166,54,184,2,161,125,205,28,63,82,237,47,112,191,103,45,40,65,207,58,125,200,94,12,117,218,0,0,114,133,112,46,97,202,180,43,173,237,172,55,185,30,176,42,233,198,127,45,208,108,136,39,241,13,95,45,220,175,17,40,248,115,0,0,48,169,101,36,199,249,80,0,219,47,53,49,90,112,252, -33,37,30,235,2,42,49,22,15,87,112,157,52,165,35,109,49,113,28,0,0,181,56,70,3,179,253,28,54,113,212,116,49,237,143,23,13,121,140,182,11,9,202,199,15,113,194,160,31,61,58,205,48,145,74,0,0,231,110,219,58,150,107,99,12,126,7,74,52,201,80,55,20,120,156,76,27,66,234,13,58,54,105,86,26,204,7,191,18,78,216,0,0,210,190,46,20,155,91,85,11,152,100,62,42,210,37,43,54,253,77,222,37,213,99,53,14,42,225,156,55,30,159,38,32,37,229,0,0,16,109,158,36,62,123,58,37,35,157,201,42,235,252,183,2,246,211,110,63,23,74, -174,8,27,212,20,40,153,247,18,17,212,243,0,0,63,218,71,19,1,51,14,40,48,198,214,41,51,148,182,6,252,91,75,10,102,176,86,46,186,212,99,1,188,233,55,9,67,10,0,0,7,58,211,41,27,208,44,35,180,202,155,35,42,130,187,28,78,4,244,61,54,131,84,33,144,159,216,1,103,39,75,25,48,174,0,0,166,178,160,32,61,48,28,18,199,149,126,61,119,253,13,39,28,207,213,56,246,76,159,51,252,126,229,63,88,227,112,54,185,108,0,0,202,202,40,12,228,82,89,22,167,29,40,8,243,238,113,26,24,154,140,56,12,214,249,5,94,129,28,30,245,150, -202,6,220,216,0,0,122,236,179,35,168,219,217,54,108,143,18,8,59,75,87,12,125,148,125,36,128,144,54,54,198,88,125,44,243,73,182,2,236,140,0,0,111,65,196,59,152,237,135,36,40,64,176,48,252,72,191,43,167,29,243,50,64,163,150,16,89,205,236,4,126,177,164,56,73,39,0,0,142,189,107,60,139,247,98,58,87,16,150,46,151,237,167,39,245,62,219,10,63,100,82,54,3,68,188,50,217,141,83,11,204,80,0,0,64,70,255,3,62,182,174,9,229,255,82,21,149,31,7,17,83,224,46,38,216,22,176,58,156,201,201,0,236,17,53,36,61,54,0,0,233, -157,238,59,252,241,0,8,182,236,153,1,2,36,106,46,69,49,54,51,95,78,17,45,83,25,34,50,28,127,235,28,226,4,0,0,200,93,229,54,91,72,36,46,148,67,160,44,186,173,86,62,111,66,148,16,1,3,145,18,168,43,251,31,49,228,17,16,49,68,0,0,179,35,227,27,187,18,101,7,3,229,162,42,231,109,138,26,166,215,254,2,89,253,13,38,233,143,111,54,148,185,80,48,176,150,0,0,168,35,27,48,117,33,165,63,173,224,126,40,194,81,223,30,171,157,8,33,228,86,15,9,38,193,135,10,155,97,163,63,34,158,0,0,174,237,132,8,20,79,144,30,207,206, -17,53,126,82,242,61,192,51,21,28,38,8,252,60,119,1,209,34,132,114,58,60,47,253,0,0,228,112,26,7,252,34,208,53,93,71,207,53,215,71,185,23,205,109,48,5,28,153,167,53,237,210,168,34,243,64,181,61,141,80,0,0,132,9,149,41,220,111,185,60,237,223,170,40,59,138,12,48,78,197,73,62,204,169,18,12,119,215,66,60,206,228,230,16,76,21,0,0,17,190,26,14,219,105,191,58,246,32,178,28,150,112,72,46,218,178,37,1,76,6,214,55,56,51,118,9,68,21,225,63,219,227,0,0,99,222,168,31,82,181,38,45,20,196,181,6,15,100,95,50,211, -243,142,10,110,215,233,35,67,22,66,1,141,102,66,62,242,6,0,0,73,52,89,3,216,200,198,51,253,111,164,2,185,4,223,6,246,74,1,61,129,78,112,54,120,216,64,41,247,49,25,56,172,25,0,0,49,54,248,45,78,46,5,41,163,104,64,8,208,231,66,28,172,70,44,0,101,231,92,47,254,59,51,10,154,212,128,36,121,227,0,0,99,107,186,12,75,98,250,56,94,187,179,16,63,157,249,3,10,49,142,40,58,138,204,48,8,161,218,7,62,8,59,3,116,216,0,0,243,197,52,41,1,219,168,59,171,148,22,56,48,215,19,4,64,125,195,58,64,166,187,41,120,243,43, -19,174,241,76,48,114,100,0,0,56,192,62,27,176,252,83,6,118,178,198,32,185,90,84,63,217,80,10,41,188,216,249,32,72,54,8,6,212,70,206,12,172,88,0,0,121,98,36,16,196,143,170,27,161,188,251,52,2,15,65,6,2,151,254,17,166,39,73,30,135,151,45,9,87,181,193,53,99,145,0,0,12,248,253,31,87,105,222,39,182,209,188,21,104,224,41,57,67,136,99,5,221,214,18,9,198,232,43,60,124,151,197,23,75,139,0,0,54,253,212,31,25,195,191,15,107,229,46,22,24,149,205,56,249,4,218,48,234,4,94,47,63,75,139,48,52,218,155,2,173,74,0, -0,221,18,88,53,11,150,138,2,42,14,211,18,213,200,25,17,61,142,247,24,1,91,251,42,182,240,82,51,191,164,94,47,41,112,0,0,39,41,45,26,172,25,115,8,199,115,44,59,144,16,186,54,71,172,131,6,140,43,81,25,221,39,61,11,122,191,182,62,238,176,0,0,209,110,72,61,14,90,57,39,164,182,101,21,146,174,111,17,87,96,117,15,99,39,4,53,9,144,201,37,185,186,114,59,207,156,0,0,141,93,233,53,181,103,181,61,36,170,146,21,90,214,89,8,36,17,52,11,128,4,146,8,97,251,44,35,90,79,92,19,47,124,0,0,202,234,208,27,157,198,26,8, -122,171,212,34,174,93,209,49,208,25,223,36,242,140,247,35,90,51,20,20,208,216,225,18,154,205,0,0,204,74,255,43,214,190,190,57,246,52,246,22,187,227,236,9,1,139,160,62,76,186,34,18,21,232,35,15,122,104,30,22,69,240,0,0,198,87,188,7,143,78,37,8,191,108,39,43,143,232,245,0,73,148,48,22,79,186,180,60,132,168,190,25,59,226,11,34,9,173,0,0,184,10,74,46,182,3,203,40,60,45,14,25,205,77,71,12,123,95,190,26,167,28,27,6,40,186,82,58,190,16,35,48,67,114,0,0,2,99,165,43,202,49,12,42,46,134,241,48,235,77,170,1, -245,224,210,58,167,74,139,54,234,241,65,10,207,186,66,10,209,217,0,0,41,28,41,8,234,107,183,42,174,242,116,58,103,179,107,14,23,228,134,35,201,25,87,28,41,208,238,19,11,251,68,12,181,126,0,0,58,36,209,52,19,220,52,43,219,95,74,53,143,128,73,44,2,132,85,63,24,176,134,52,28,249,206,22,231,148,119,30,80,188,0,0,138,182,93,5,162,69,37,23,159,22,71,31,108,61,185,31,95,215,200,63,55,229,202,49,238,184,203,5,156,206,142,10,6,101,0,0,159,63,74,55,154,19,73,35,144,22,152,0,119,153,233,33,194,90,98,50,246, -185,170,55,19,137,126,60,23,148,223,41,49,77,0,0,167,11,30,48,4,9,44,63,84,167,0,46,109,212,190,61,203,83,39,0,30,227,60,6,107,176,117,5,38,88,178,7,36,34,0,0,218,252,50,18,73,86,132,45,188,119,14,44,233,255,54,0,183,199,72,21,47,0,199,29,191,214,150,57,118,185,169,46,60,114,0,0,95,159,179,30,118,26,112,7,128,148,148,55,77,25,40,24,38,110,77,2,34,210,77,4,146,138,73,12,87,86,237,25,232,150,0,0,177,60,99,0,122,130,159,21,50,17,2,29,218,146,136,22,87,203,31,24,72,200,156,24,12,64,173,44,234,197,60, -39,222,109,0,0,52,107,206,39,169,38,117,31,53,239,89,56,179,246,159,44,128,168,102,58,134,26,190,39,201,213,65,62,193,233,249,62,136,145,0,0,197,243,51,41,52,70,105,6,36,82,18,31,69,220,131,22,8,80,184,7,57,254,237,18,60,129,222,28,109,53,203,41,111,72,0,0,83,15,251,10,107,156,82,43,121,59,242,48,243,224,109,54,98,159,241,8,179,235,34,49,72,62,212,61,90,125,198,8,225,98,0,0,40,247,153,30,137,80,86,47,78,32,18,47,249,126,221,28,103,3,83,42,221,158,252,19,102,251,244,10,37,42,93,26,121,36,0,0,255,235, -170,43,91,20,128,30,131,45,90,23,37,240,252,54,90,74,102,13,246,249,161,11,197,30,0,51,35,26,81,35,215,227,0,0,154,7,176,47,80,27,131,39,156,4,38,57,200,189,231,27,145,36,131,51,218,185,103,41,49,6,255,21,245,168,246,50,57,47,0,0,186,144,86,44,192,92,138,56,15,35,160,2,34,239,207,62,155,139,165,13,158,64,219,36,218,52,152,35,225,132,247,54,234,171,0,0,115,171,247,36,203,2,204,36,119,58,68,20,167,58,245,56,98,210,174,52,20,27,122,14,106,165,27,22,159,12,91,7,163,229,0,0,66,31,86,48,241,143,78,36,19, -162,203,0,106,18,17,35,191,93,206,14,233,93,42,6,193,160,215,41,71,99,15,35,120,55,0,0,134,205,77,1,143,166,228,35,88,27,247,43,37,8,117,49,31,241,220,17,129,96,118,3,245,125,68,19,69,131,82,39,56,204,0,0,115,168,240,8,103,183,173,35,70,135,231,39,63,134,95,49,5,202,16,41,250,110,47,26,181,217,190,43,61,152,245,19,174,147,0,0,17,147,129,56,173,27,231,19,114,20,119,8,132,184,135,15,11,31,237,53,51,248,133,2,117,35,144,30,92,39,114,36,146,127,0,0,37,177,46,44,94,109,126,42,74,23,106,8,39,144,170,2, -18,182,21,36,20,49,122,3,93,15,239,3,251,24,68,3,160,157,0,0,250,215,125,14,40,251,76,41,57,152,145,58,141,132,229,17,9,181,211,2,75,32,187,63,165,139,249,43,239,36,53,41,191,238,0,0,153,137,222,33,107,63,245,55,45,113,31,49,233,112,51,57,154,157,8,56,197,107,251,57,158,38,15,47,195,229,40,35,154,93,0,0,235,236,124,59,254,227,217,15,15,175,127,9,226,228,103,41,115,20,104,46,189,73,224,62,111,3,69,45,157,16,136,33,122,67,0,0,225,129,193,22,13,243,142,13,39,120,249,8,247,243,131,8,135,255,151,18,103, -218,250,35,155,246,50,44,186,79,232,26,145,11,0,0,242,150,127,9,120,202,53,22,205,53,135,44,116,74,141,32,53,115,194,60,104,238,248,45,60,200,155,8,169,248,196,39,239,169,0,0,228,75,192,22,193,86,245,0,44,112,180,41,214,107,226,19,183,61,97,59,58,88,184,27,149,205,215,25,21,101,57,51,20,232,0,0,126,247,12,53,132,214,42,48,219,176,138,10,21,93,253,54,7,66,6,42,126,90,159,32,83,229,91,19,135,123,80,1,216,102,0,0,166,163,234,32,190,94,126,41,210,118,27,59,173,14,45,17,148,246,19,22,77,129,80,7,63,44, -180,63,191,204,249,55,207,81,0,0,90,58,33,7,162,24,82,13,185,98,250,5,158,18,200,28,11,200,195,12,25,135,34,20,243,43,250,3,148,77,120,1,172,98,0,0,69,158,106,52,3,135,52,4,252,78,153,23,96,64,66,22,229,121,37,41,30,120,158,23,57,77,110,26,52,232,124,47,111,35,0,0,43,209,186,39,97,82,63,12,236,225,102,47,58,128,122,53,133,179,45,47,113,189,78,24,191,181,245,8,145,92,18,49,19,202,0,0,242,176,35,23,26,125,166,37,104,86,87,26,68,220,42,28,99,214,163,45,170,147,233,23,193,138,124,40,112,216,96,2,170, -131,0,0,78,65,128,28,229,151,187,54,253,247,108,22,139,161,226,59,20,73,158,32,17,61,113,4,172,133,174,18,193,105,64,44,236,28,0,0,59,154,22,18,75,82,186,50,13,29,35,7,81,249,85,29,144,22,173,45,215,160,140,42,229,180,207,23,130,165,25,24,67,243,0,0,169,16,216,14,49,242,214,19,92,21,0,7,207,79,39,34,79,146,35,31,199,215,107,3,149,204,249,56,53,65,29,36,105,42,0,0,40,71,155,58,35,206,26,62,124,92,20,44,95,250,81,31,102,252,4,59,83,165,97,49,62,172,253,31,15,219,230,0,249,84,0,0,176,141,164,57,108, -13,94,63,254,59,192,51,166,104,133,4,159,69,222,59,109,130,66,7,121,114,22,39,91,154,54,17,15,16,0,0,9,90,198,43,88,115,245,62,192,90,25,53,63,134,210,63,183,102,6,9,48,192,204,35,236,114,183,0,168,100,76,56,217,205,0,0,180,21,188,21,210,132,230,50,105,238,162,37,145,163,64,29,146,141,202,23,59,167,59,22,216,158,220,42,123,148,139,3,233,16,0,0,141,37,170,24,37,152,175,19,131,168,182,43,192,88,98,41,76,117,31,45,90,24,163,30,213,36,4,30,53,224,192,13,138,198,0,0,105,82,231,63,192,240,79,55,130,49, -211,19,1,243,232,29,163,205,125,11,197,45,228,22,87,132,99,1,149,182,208,11,66,247,0,0,213,155,228,23,28,58,96,34,1,142,57,10,253,141,232,44,127,151,53,54,231,114,159,51,24,253,147,48,196,140,198,11,108,64,0,0,95,23,167,53,91,154,237,20,166,66,207,49,116,220,57,46,237,187,222,21,11,86,105,30,40,247,207,3,245,5,65,43,140,45,0,0,42,89,157,59,70,238,222,60,12,94,94,11,103,255,26,33,122,55,157,44,132,233,203,8,187,167,148,10,99,204,224,14,63,199,0,0,69,16,181,20,14,111,50,13,62,91,194,49,188,37,178,49, -187,115,207,40,199,58,245,28,174,88,234,38,98,110,71,63,203,30,0,0,38,0,199,2,4,196,153,14,213,34,100,3,173,145,1,36,177,56,155,26,18,198,46,52,71,100,58,28,230,34,140,56,246,28,0,0,51,133,53,41,155,93,179,30,223,185,180,15,117,254,76,42,16,140,42,19,71,138,86,37,62,136,82,55,149,127,49,37,8,154,0,0,8,186,96,3,119,113,248,44,223,218,13,56,110,111,185,41,101,33,195,15,85,126,245,5,249,49,252,56,6,8,241,32,152,167,0,0,246,247,142,25,88,23,16,37,246,249,120,32,222,253,252,8,89,166,174,56,206,73,33,39, -189,53,46,61,211,118,18,54,77,102,0,0,148,172,30,29,205,191,37,29,238,236,230,56,198,172,78,15,252,207,88,4,116,151,51,18,20,42,147,39,252,197,5,8,81,173,0,0,179,52,201,3,223,154,2,3,78,44,174,48,22,96,125,12,43,2,167,17,96,154,101,7,35,56,134,11,244,221,164,14,17,130,0,0,15,106,44,4,171,152,151,31,55,128,70,36,166,9,223,7,170,40,198,32,214,202,179,25,132,96,102,35,107,178,54,46,161,141,0,0,45,253,52,37,155,55,43,50,82,56,59,15,25,81,227,31,167,23,192,4,40,233,137,36,220,177,209,62,177,152,248,6, -3,225,0,0,13,160,86,20,202,99,60,17,154,215,206,33,103,80,183,36,242,90,83,23,150,93,144,26,187,230,5,4,80,162,100,24,112,157,0,0,131,141,2,47,187,142,88,30,21,150,67,39,110,155,100,37,97,219,105,30,87,104,249,42,165,198,94,56,241,56,241,61,235,167,0,0,209,190,208,25,174,228,0,25,153,145,83,48,210,73,226,40,71,75,128,4,193,221,28,39,253,92,45,54,248,239,75,5,5,98,0,0,250,92,221,39,8,144,131,43,91,75,157,48,223,68,113,34,106,51,70,35,9,77,169,49,205,193,244,36,192,114,35,40,92,91,0,0,140,233,72,30, -230,155,146,25,62,157,38,51,43,243,25,52,191,148,144,6,162,58,195,7,153,94,130,21,168,194,189,45,204,62,0,0,130,31,83,35,140,163,84,46,242,201,194,16,236,154,76,20,255,41,44,2,39,210,249,60,206,92,187,20,68,48,171,9,111,4,0,0,7,218,206,11,44,242,23,20,250,199,85,43,54,23,101,9,208,121,37,3,191,176,194,13,226,172,46,56,214,88,204,18,128,107,0,0,17,39,67,16,220,80,197,2,6,185,22,25,247,203,2,5,207,90,100,25,34,60,188,37,95,83,251,14,120,76,182,9,25,193,0,0,12,97,226,47,139,135,73,18,94,5,52,15,40,139, -228,42,131,207,198,12,27,198,47,37,132,145,104,27,73,31,51,62,225,139,0,0,99,121,37,33,62,29,230,5,28,134,170,52,176,84,99,0,91,196,121,9,78,45,213,46,205,230,242,8,218,122,186,17,8,105,0,0,53,152,111,6,101,150,93,41,83,178,146,28,8,42,15,47,108,127,187,47,228,147,192,5,64,91,188,62,207,223,242,23,72,226,0,0,206,58,226,30,47,229,68,52,210,47,221,20,109,25,31,50,222,21,41,35,210,183,84,29,186,171,11,34,36,227,254,61,61,251,0,0,222,232,34,23,50,189,119,2,238,245,39,45,191,80,156,28,158,138,181,58,54, -80,69,9,42,101,197,51,113,4,111,10,14,81,0,0,81,35,39,16,189,63,31,24,152,16,255,25,126,207,210,28,112,65,205,49,234,172,143,34,235,179,24,5,215,147,176,23,216,109,0,0,75,102,199,63,173,232,31,44,201,23,8,62,240,253,27,31,135,183,65,28,189,230,31,16,157,224,39,52,135,4,253,25,234,22,0,0,109,105,148,16,54,162,121,53,82,175,214,1,169,153,44,62,92,236,215,59,80,124,14,10,172,48,181,21,181,145,43,27,234,254,0,0,136,0,9,24,252,122,87,5,211,66,20,4,243,85,34,7,152,92,205,62,252,74,56,57,6,171,27,14,247, -37,219,26,124,229,0,0,135,213,223,8,237,134,77,30,96,101,2,27,50,142,46,49,94,45,161,53,179,168,234,25,72,179,8,5,61,235,6,45,132,80,0,0,137,14,71,17,254,165,231,57,6,86,31,9,26,88,189,45,93,71,39,41,84,33,155,42,25,22,211,0,102,135,198,24,169,52,0,0,198,76,179,58,133,201,8,2,45,161,48,15,159,93,10,3,200,40,113,13,70,127,252,44,63,165,94,45,144,129,15,48,20,79,0,0,31,104,126,24,190,148,176,23,34,208,29,40,163,51,143,55,185,64,37,38,14,61,156,14,101,76,137,14,169,50,42,52,83,123,0,0,13,217,65,18,4, -196,157,16,131,79,68,50,118,80,60,7,232,99,211,29,123,37,216,16,65,29,237,57,113,146,31,46,77,167,0,0,212,218,122,63,224,98,148,12,63,49,10,10,209,36,148,59,169,200,113,1,98,41,66,55,127,50,239,62,200,107,115,36,134,247,0,0,31,174,193,49,136,40,179,23,42,11,212,44,162,49,150,27,69,88,86,35,174,19,53,55,172,249,44,42,46,209,149,62,1,105,0,0,176,56,40,18,151,193,12,62,48,169,119,28,121,233,206,39,215,13,144,28,10,3,78,45,97,36,33,60,156,8,34,23,222,53,0,0,219,75,122,50,6,66,12,44,196,202,148,20,13, -65,155,26,4,93,163,59,198,15,217,18,36,122,18,56,80,71,11,54,60,141,0,0,44,138,154,38,243,49,77,15,108,41,173,48,77,31,224,56,212,110,35,54,1,116,254,62,12,71,31,36,59,96,88,9,212,155,0,0,45,29,236,52,26,79,51,16,84,244,216,39,27,215,103,2,217,31,105,59,89,202,89,39,254,154,115,36,129,245,216,32,249,234,0,0,82,132,131,12,129,213,249,51,63,181,132,62,21,85,75,61,169,170,153,49,154,131,162,8,117,39,210,56,249,159,14,6,24,229,0,0,103,231,90,4,220,111,205,50,203,113,151,40,231,114,234,28,194,216,229, -6,176,20,56,16,111,70,99,27,187,142,69,47,149,251,0,0,17,14,191,59,43,168,79,33,65,19,159,37,98,28,189,5,184,91,39,2,218,116,54,1,32,197,219,13,106,4,54,5,76,102,0,0,177,108,236,1,47,94,234,15,227,61,88,8,96,95,89,59,254,60,202,63,155,47,249,30,54,203,205,9,65,100,71,42,103,218,0,0,29,190,104,58,137,163,122,58,23,10,116,15,66,113,235,49,222,229,128,23,178,223,143,17,31,196,43,36,5,82,141,42,172,155,0,0,68,138,188,21,148,65,247,59,25,26,21,62,242,93,64,16,104,199,95,26,233,146,150,21,56,61,218,14, -63,15,22,32,1,77,0,0,158,192,219,26,36,83,126,60,98,163,45,24,161,17,8,37,150,19,56,22,31,0,234,38,126,54,93,15,45,99,176,49,51,58,0,0,0,235,218,37,161,212,106,48,107,247,69,38,51,201,250,8,89,209,233,54,206,137,218,50,130,112,149,15,215,247,65,5,102,47,0,0,192,146,57,3,38,158,157,8,193,8,211,21,198,137,123,51,110,208,173,0,8,234,77,37,239,246,51,43,212,219,132,4,92,253,0,0,217,166,106,17,130,66,170,32,241,220,2,55,145,45,178,24,54,56,90,3,134,54,93,60,84,34,125,36,127,65,95,4,148,245,0,0,207,80, -46,63,186,165,65,31,108,184,181,38,15,226,157,36,122,235,188,20,194,106,111,23,246,44,177,49,165,91,105,24,167,202,0,0,192,244,198,58,85,14,184,42,204,196,189,4,51,122,163,19,218,29,113,22,154,47,14,7,78,236,205,25,211,199,95,19,45,15,0,0,88,155,51,50,181,238,158,31,110,101,66,2,228,41,132,26,143,30,231,1,206,247,159,44,127,209,228,61,164,95,225,39,200,62,0,0,178,140,66,31,255,20,84,33,93,181,34,42,89,191,8,14,35,241,208,24,101,5,134,30,235,209,187,20,168,184,176,51,93,29,0,0,155,24,91,9,2,68,123, -57,81,74,4,54,225,75,164,15,189,136,11,47,33,9,30,30,208,80,140,44,80,236,32,16,92,110,0,0,115,18,56,40,62,162,58,44,95,174,61,41,129,165,221,16,216,206,38,1,49,203,166,58,253,57,116,22,2,76,191,40,217,137,0,0,61,119,9,19,187,207,250,0,74,50,39,17,43,160,117,24,143,245,98,15,219,129,188,42,119,3,245,38,117,20,109,9,202,223,0,0,145,29,199,53,178,172,12,51,33,253,148,40,138,139,23,37,35,206,254,26,69,76,112,40,82,28,174,16,233,224,225,6,25,131,0,0,97,138,20,34,35,176,231,2,231,94,68,16,93,212,71,40, -23,138,174,60,69,79,120,27,224,9,183,1,224,92,197,31,172,224,0,0,192,183,55,26,48,115,81,29,245,105,16,49,238,61,52,2,236,81,33,50,123,77,2,0,110,218,205,52,204,130,234,19,144,83,0,0,200,113,39,2,172,37,44,55,153,70,67,20,120,96,102,38,19,28,60,13,8,43,179,39,140,216,6,1,32,47,244,33,192,91,0,0,14,5,162,8,249,11,177,6,119,166,248,21,216,85,189,11,116,137,155,7,185,49,167,29,107,137,49,7,47,73,63,9,55,103,0,0,112,61,29,6,36,105,50,36,43,204,73,51,80,63,235,26,190,109,107,8,106,2,11,18,3,2,162,36,90, -226,149,32,207,228,0,0,191,99,222,2,14,146,219,47,108,198,97,50,161,76,189,14,224,168,102,33,125,140,41,38,229,9,195,52,183,28,233,59,102,67,0,0,205,36,121,33,35,144,26,11,176,214,166,42,150,20,195,14,243,234,104,2,76,248,77,9,238,226,124,45,184,111,66,54,125,46,0,0,144,97,249,6,252,159,20,4,239,37,149,60,65,122,11,60,209,95,167,58,153,165,85,57,123,249,177,26,100,158,216,20,215,123,0,0,246,0,218,43,18,200,69,15,90,105,234,32,7,23,243,3,206,214,39,56,80,210,145,53,94,157,48,38,238,246,172,60,54,131, -0,0,237,65,173,22,85,76,197,14,67,82,3,15,125,13,43,2,3,146,220,24,36,122,6,13,250,26,92,45,106,247,158,36,126,79,0,0,87,45,100,62,25,94,13,61,189,117,247,42,83,28,197,28,46,166,246,40,78,125,3,38,82,5,177,8,170,85,20,29,231,223,0,0,144,134,116,39,73,20,152,62,28,176,48,6,118,19,228,21,125,0,61,19,183,199,74,17,75,201,204,17,74,159,225,50,85,35,0,0,43,88,137,12,197,212,17,31,20,57,201,17,51,22,26,10,88,88,124,42,86,176,23,46,85,143,31,30,156,150,98,60,194,33,0,0,22,127,222,10,88,136,186,54,198,40, -224,11,79,186,46,39,174,36,93,39,176,173,74,22,19,192,86,26,207,230,150,32,102,11,0,0,23,98,197,8,161,9,17,37,189,210,124,62,124,3,15,9,183,127,169,23,45,234,218,41,243,254,179,9,56,6,46,40,251,161,0,0,91,13,6,25,138,192,26,36,194,167,163,3,71,236,132,17,144,203,81,57,103,191,108,2,97,203,34,16,47,60,15,1,2,246,0,0,19,143,248,26,44,212,219,27,247,163,209,61,173,180,149,42,55,234,123,15,177,146,61,42,129,152,241,12,124,176,193,45,54,240,0,0,71,96,216,58,208,103,229,63,174,188,184,41,14,129,78,45,121, -103,144,10,147,221,41,51,25,119,58,24,214,244,66,51,123,142,0,0,42,55,96,4,250,17,64,40,62,139,214,63,145,139,35,58,121,69,81,41,50,8,65,12,64,57,75,26,143,202,194,29,183,16,0,0,75,173,30,4,104,30,162,63,31,60,176,17,218,126,123,29,58,190,118,62,235,59,205,17,113,236,55,51,35,35,3,3,201,191,0,0,237,218,254,6,194,27,75,17,231,227,10,46,204,191,163,17,251,54,45,4,84,55,198,41,219,36,237,13,39,120,108,32,148,122,0,0,62,59,187,53,29,244,158,27,178,60,247,57,251,133,77,29,80,91,63,45,48,250,100,22,202, -77,170,58,143,47,71,60,45,115,0,0,147,102,54,23,123,248,93,49,108,67,88,12,89,91,107,39,230,22,57,37,0,97,149,56,183,124,151,57,163,183,15,36,65,127,0,0,185,195,141,8,6,207,214,23,156,201,116,23,58,73,154,41,25,96,239,23,50,3,33,42,141,66,123,20,14,88,46,37,224,76,0,0,82,222,192,37,219,222,83,48,2,101,160,30,50,200,22,8,22,162,172,54,41,3,54,45,87,237,179,41,198,175,238,3,57,5,0,0,90,254,170,10,44,120,221,48,212,237,154,16,233,44,28,21,226,208,63,2,108,165,154,34,109,233,125,38,241,219,173,35,150, -154,0,0,192,117,217,14,9,245,175,57,12,204,112,30,153,2,98,45,231,14,29,6,246,64,155,49,79,149,162,59,180,233,193,62,246,171,0,0,151,99,76,51,231,47,71,29,147,208,76,7,64,109,79,55,7,33,178,54,148,0,190,43,240,84,25,22,92,64,251,62,198,211,0,0,156,63,203,40,21,52,242,7,11,224,224,5,36,194,29,3,138,70,182,42,75,54,229,32,69,25,175,34,151,87,177,52,13,74,0,0,126,19,195,10,76,150,224,38,97,68,246,26,169,216,150,36,254,83,57,43,170,157,26,60,2,142,59,36,164,4,230,56,189,76,0,0,230,47,192,46,115,197,35, -0,12,214,234,8,150,235,233,36,209,112,195,20,46,77,168,36,0,149,21,54,196,35,24,21,229,108,0,0,75,248,251,32,179,193,136,30,164,184,240,3,239,242,35,49,3,187,206,20,48,204,113,54,139,123,36,22,172,32,207,12,157,75,0,0,72,60,108,35,210,146,123,14,98,94,91,47,248,80,181,25,103,235,183,57,153,96,246,4,83,37,21,12,147,248,254,49,127,253,0,0,98,56,196,25,86,120,16,42,144,102,126,57,96,60,253,41,113,222,27,56,38,26,6,2,109,30,242,31,115,48,77,59,94,56,0,0,83,84,46,20,149,63,22,1,204,200,109,8,8,187,19, -12,107,87,244,43,167,103,120,7,112,86,63,34,58,250,240,58,59,40,0,0,179,217,226,54,170,193,244,18,81,99,141,51,198,160,228,54,65,86,132,15,231,132,169,11,225,117,94,48,241,229,60,5,163,25,0,0,51,175,170,11,151,184,75,21,109,229,75,0,73,71,135,0,165,179,40,53,31,226,151,37,52,210,141,50,177,118,61,54,172,108,0,0,128,4,240,18,172,31,22,54,231,206,13,16,40,1,98,13,32,25,114,54,147,141,97,50,93,53,170,13,106,229,82,59,64,88,0,0,158,207,34,62,138,87,75,22,33,135,227,42,20,149,72,29,186,218,216,29,133, -170,55,26,121,16,20,63,130,200,154,54,12,103,0,0,66,76,245,35,160,123,19,18,142,220,163,41,9,143,6,55,69,37,83,14,59,125,48,22,220,177,143,17,26,77,105,0,87,159,0,0,33,106,235,47,36,113,56,24,120,82,158,33,172,18,158,59,137,221,191,41,92,173,109,37,251,123,229,25,7,32,238,35,123,206,0,0,26,70,34,21,202,76,80,58,39,131,113,60,150,137,194,44,188,160,249,62,25,4,28,46,27,192,207,40,214,72,90,4,246,39,0,0,45,26,48,7,231,43,147,42,70,148,99,40,54,200,6,38,228,232,142,2,157,132,21,35,164,46,173,38,2,100, -106,60,18,229,0,0,185,54,79,17,203,38,139,51,12,57,159,59,216,174,50,38,37,129,169,52,215,208,203,47,97,18,148,47,59,91,97,30,7,100,0,0,10,181,180,36,167,123,44,37,40,235,206,25,18,28,130,54,140,108,123,26,97,127,93,3,249,174,239,22,57,209,163,36,97,218,0,0,111,183,214,20,230,247,216,59,188,93,129,12,237,126,106,57,127,174,254,29,2,47,194,61,82,244,105,22,33,199,56,20,55,162,0,0,218,168,204,13,50,179,100,7,20,141,132,27,127,4,31,28,231,19,17,1,53,249,232,11,195,218,230,61,185,41,197,38,51,247,0,0, -117,228,238,60,147,113,186,11,177,130,215,14,16,10,178,26,171,65,255,10,207,135,0,15,237,213,120,35,252,232,1,43,241,187,0,0,103,80,254,7,2,168,136,17,104,29,180,56,80,98,231,58,36,227,95,49,218,32,243,32,8,97,14,6,181,186,55,46,191,180,0,0,167,195,250,3,27,182,27,24,156,188,127,20,150,18,126,55,15,24,250,61,4,145,206,49,55,22,25,15,251,0,110,54,249,6,0,0,96,33,132,58,128,65,162,33,45,0,129,2,215,75,55,41,126,212,196,5,57,140,138,35,155,166,155,5,12,152,163,49,128,124,0,0,4,226,28,18,163,215,181, -19,82,61,118,38,144,99,201,41,178,47,247,38,114,22,54,29,131,251,100,60,172,88,116,16,202,67,0,0,107,143,74,19,58,17,148,20,142,70,74,42,207,236,177,45,154,31,163,27,99,72,62,20,198,161,63,2,220,184,160,22,234,220,0,0,218,239,230,43,179,164,243,19,150,5,40,7,254,252,83,11,146,109,80,26,225,141,220,27,102,91,191,18,162,200,187,1,62,156,0,0,125,252,174,39,202,60,80,60,125,223,111,51,30,26,242,14,212,213,111,34,51,81,203,2,175,216,35,41,216,121,121,2,183,167,0,0,226,139,200,6,215,234,73,36,39,94,238, -6,52,8,30,11,234,91,119,48,96,103,157,28,187,51,240,32,248,196,168,34,111,93,0,0,93,215,122,13,252,84,185,36,40,44,249,43,169,227,219,42,237,32,188,8,172,206,188,42,113,140,78,45,85,99,99,44,196,173,0,0,68,184,209,18,110,212,36,10,79,72,62,23,176,224,0,39,198,197,139,56,4,15,87,44,134,252,213,32,41,193,112,13,125,245,0,0,55,104,38,33,245,174,46,25,164,198,21,9,12,200,165,1,112,76,99,36,167,214,79,19,144,151,77,47,99,170,103,15,127,112,0,0,9,203,199,60,252,1,52,13,82,67,27,29,40,218,250,49,59,70,113, -24,143,251,135,27,89,95,74,25,153,142,30,24,231,19,0,0,96,145,7,8,40,106,157,47,17,100,87,43,217,174,184,58,101,157,41,52,108,97,247,23,50,30,139,59,62,122,35,50,77,40,0,0,5,238,205,24,73,56,131,1,144,59,236,50,133,236,135,29,168,29,144,6,108,44,148,0,64,98,46,24,160,149,200,40,190,41,0,0,200,81,38,38,102,13,40,57,57,142,105,12,178,109,12,63,249,199,94,48,225,254,108,2,144,234,160,41,67,154,104,54,64,124,0,0,218,138,241,18,88,29,219,6,193,188,189,61,238,100,47,24,212,89,74,61,204,191,190,13,156,125, -142,40,224,72,27,30,33,245,0,0,22,53,149,35,244,43,90,55,129,9,191,5,219,40,189,23,170,214,209,17,243,10,132,9,204,126,181,13,14,216,239,27,104,224,0,0,189,230,208,2,157,131,223,14,49,229,245,48,246,88,52,29,247,203,110,13,65,240,81,8,42,88,226,4,15,73,0,53,34,51,0,0,160,178,40,44,165,139,206,19,98,175,115,40,168,143,125,1,40,183,249,26,55,241,102,0,251,91,239,36,89,250,229,1,231,86,0,0,153,180,154,5,200,79,103,47,10,51,60,39,27,103,202,4,11,188,1,63,25,207,90,6,210,165,91],"i8",4,t.L); -D([87,192,252,43,186,120,0,0,253,151,224,62,99,140,116,32,150,25,37,17,163,187,203,24,145,46,8,2,182,131,19,42,252,250,10,44,193,246,54,55,75,173,0,0,230,172,6,61,179,133,79,18,164,12,162,3,190,205,38,28,35,26,171,41,36,97,18,46,32,76,61,46,82,104,132,60,112,111,0,0,222,213,2,54,210,180,47,18,224,94,172,37,175,89,165,12,117,80,159,57,30,205,99,23,249,54,183,39,0,37,140,34,30,121,0,0,64,27,238,32,185,143,59,50,125,36,150,30,220,22,82,59,140,212,204,3,68,198,39,37,128,95,65,42,90,167,108,39,89,225, -0,0,166,147,143,23,123,153,88,7,222,153,41,3,47,157,142,13,166,207,199,47,168,42,37,62,250,14,74,29,160,202,136,24,51,121,0,0,62,12,192,9,161,232,119,32,47,142,32,17,242,192,163,3,240,89,24,5,245,76,139,21,54,100,149,6,16,193,37,1,11,187,0,0,53,90,149,17,180,96,106,38,167,144,220,5,164,19,193,25,254,82,176,49,234,133,190,52,85,54,246,57,235,20,22,57,103,64,0,0,230,50,221,5,112,110,157,3,126,238,229,19,109,84,237,24,198,191,95,26,29,248,118,18,182,233,137,23,101,80,85,16,90,220,0,0,185,153,74,53,233, -109,159,3,248,188,73,46,29,164,187,60,47,68,89,63,6,136,151,58,220,118,122,54,231,143,41,42,243,74,0,0,203,231,68,5,177,110,81,59,89,3,150,18,109,137,144,1,161,153,78,1,196,149,82,13,227,219,185,51,97,14,92,6,110,21,0,0,55,10,37,45,2,75,78,53,214,156,67,43,87,99,181,37,148,232,75,3,142,169,92,37,147,218,7,25,204,227,103,35,192,107,0,0,202,83,152,5,115,10,239,47,77,245,155,49,231,154,88,58,72,19,22,39,163,136,218,41,188,38,56,4,218,178,51,47,105,66,0,0,103,211,184,53,212,59,86,42,61,138,90,30,126, -41,80,14,253,9,164,49,16,167,50,33,60,114,107,1,176,160,6,7,43,237,0,0,131,171,52,1,74,211,117,8,119,57,67,54,189,230,207,6,116,104,88,38,37,54,220,5,189,162,125,11,120,75,31,11,103,133,0,0,166,19,3,57,61,37,140,35,76,244,152,18,49,255,197,31,231,229,194,34,233,111,18,16,55,182,46,59,208,214,230,6,72,124,0,0,0,144,186,3,234,200,193,55,111,139,94,2,26,231,203,33,196,61,20,0,97,29,216,33,132,22,140,29,252,127,62,29,56,172,0,0,10,207,16,47,101,31,143,54,164,159,110,54,95,67,141,23,8,147,127,17,80,162, -119,11,134,155,6,28,40,194,72,58,101,170,0,0,212,219,6,45,155,189,129,41,129,208,32,10,94,225,143,3,236,41,231,35,166,215,1,5,173,57,1,7,154,234,57,23,13,87,0,0,149,212,30,61,58,251,150,41,213,190,96,36,113,219,232,32,182,187,27,16,71,156,185,25,91,96,47,32,131,80,210,20,174,166,0,0,14,35,45,9,72,126,48,13,132,146,51,41,52,168,140,59,218,245,110,54,128,123,138,48,135,111,187,40,9,10,28,62,181,117,0,0,184,112,21,21,239,247,242,13,176,143,31,17,1,44,233,25,2,142,250,29,83,21,29,30,61,54,82,56,233,120, -136,51,124,82,0,0,14,204,79,3,171,253,218,30,196,132,56,62,10,41,196,31,146,200,89,18,159,56,224,22,10,43,236,29,123,184,190,35,252,68,0,0,10,66,156,49,121,12,252,51,217,137,4,13,47,41,165,3,114,215,211,51,32,158,159,9,73,126,54,49,166,46,165,55,199,210,0,0,145,153,182,11,242,7,146,22,93,23,7,51,176,232,207,62,255,53,245,2,56,136,89,40,102,104,188,39,179,238,145,46,162,222,0,0,223,226,111,49,167,10,157,1,199,155,237,33,216,108,115,39,34,231,185,55,19,178,255,50,197,74,142,2,67,182,245,47,40,174,0, -0,204,201,79,17,9,52,144,48,88,22,70,26,10,175,2,52,38,54,168,56,18,179,61,7,252,110,141,22,184,41,38,63,104,57,0,0,221,55,173,31,37,82,78,6,64,51,143,56,191,93,25,5,26,201,50,45,106,180,96,30,35,129,146,53,210,54,244,46,156,120,0,0,241,133,12,46,70,134,176,43,80,162,163,3,216,148,75,41,166,213,69,57,85,194,119,9,107,146,162,6,56,166,65,36,150,104,0,0,33,222,193,45,204,8,210,49,34,57,80,13,104,103,48,16,31,45,215,5,97,7,23,12,111,37,121,9,227,44,237,15,253,174,0,0,10,42,200,32,189,102,101,63,47,131, -104,54,131,177,137,36,15,177,19,20,70,198,39,27,176,70,138,24,198,38,224,47,72,9,0,0,137,229,200,24,35,254,45,19,237,43,205,23,50,194,127,19,109,140,65,3,71,23,211,45,198,109,100,54,114,91,161,24,165,83,0,0,127,172,200,56,126,249,11,10,39,165,42,30,153,187,144,4,100,73,248,22,129,180,229,12,92,203,187,34,224,248,190,44,69,153,0,0,176,163,174,41,133,14,101,27,169,223,172,45,251,136,222,11,40,245,239,40,236,63,209,54,7,214,130,50,195,146,96,59,239,62,0,0,58,53,158,22,142,231,117,52,110,31,190,43,20, -2,17,40,16,254,213,7,196,137,8,62,53,98,14,7,22,200,26,19,49,42,0,0,103,96,116,37,135,155,100,9,252,139,101,50,182,42,149,34,19,160,27,42,174,29,249,24,164,193,122,34,214,252,2,43,164,21,0,0,102,73,184,41,123,210,139,39,152,255,243,23,183,65,208,19,27,145,108,43,233,188,190,45,152,212,194,63,192,45,64,41,89,89,0,0,106,58,71,7,134,140,153,2,100,66,226,15,35,48,55,0,145,112,42,8,55,8,74,12,148,127,137,10,215,7,157,57,112,3,0,0,115,177,198,43,72,110,50,44,179,254,211,46,31,143,24,54,125,157,95,27,193, -24,49,24,17,142,254,34,200,77,78,12,235,158,0,0,29,167,35,23,54,136,229,20,185,196,112,14,180,175,198,41,14,227,26,58,238,246,175,42,82,217,88,45,67,4,120,60,33,225,0,0,243,5,200,62,253,16,201,29,21,89,153,29,66,221,3,57,125,136,151,46,1,226,200,46,110,81,143,49,253,49,249,19,204,57,0,0,211,72,60,58,4,131,70,6,77,46,145,60,207,205,85,46,187,125,222,2,61,79,154,57,81,49,143,47,145,22,203,17,177,236,0,0,14,88,34,14,215,190,88,15,121,136,111,45,180,37,202,4,199,210,212,27,147,121,255,11,137,150,198, -13,187,25,29,32,76,249,0,0,130,219,39,49,217,143,148,7,232,212,113,35,76,17,251,33,152,246,129,26,173,218,255,18,25,169,37,18,225,25,247,31,156,94,0,0,31,242,196,16,180,46,144,47,166,167,61,16,83,86,42,9,80,210,153,25,108,163,129,0,204,47,22,29,181,26,27,46,204,140,0,0,160,254,157,50,169,155,196,31,143,226,75,38,32,43,183,36,75,165,88,7,114,82,189,47,153,54,196,17,157,24,150,37,248,87,0,0,232,216,143,51,103,96,179,51,172,82,151,6,127,19,57,44,241,168,115,40,192,131,243,25,240,52,28,0,134,209,159, -51,96,98,0,0,23,174,180,50,86,58,161,6,140,25,28,5,224,136,164,52,236,247,30,42,221,37,65,2,127,26,87,27,233,219,10,42,45,188,0,0,2,102,19,1,149,145,46,44,187,165,227,25,3,210,27,49,56,61,59,51,200,223,36,22,208,51,252,45,32,1,202,9,209,135,0,0,172,106,175,24,7,241,160,61,196,247,59,61,27,29,33,42,135,83,116,39,253,179,157,40,38,233,61,32,150,194,33,9,206,113,0,0,22,169,197,8,205,117,129,44,37,15,97,53,84,3,17,23,63,161,74,53,106,143,49,43,176,70,151,30,152,248,79,31,93,253,0,0,218,139,219,58,193, -222,44,5,171,250,246,28,47,5,206,53,229,47,181,7,231,153,242,16,43,125,176,21,173,59,180,15,216,13,0,0,156,82,247,53,88,66,102,23,212,29,213,27,45,230,150,29,56,129,67,52,180,12,79,17,186,34,97,2,7,38,4,53,13,222,0,0,254,136,205,36,11,48,8,15,6,116,183,9,162,49,73,34,23,112,53,58,181,8,38,4,178,249,69,33,40,68,167,27,10,215,0,0,17,109,247,56,52,210,11,50,115,85,81,56,239,3,64,4,21,162,146,2,231,240,251,22,156,230,68,15,147,182,34,8,108,178,0,0,107,53,183,35,199,2,112,48,189,36,38,24,103,25,12,0,5, -51,100,13,67,246,161,19,12,207,51,29,82,130,32,62,28,31,0,0,219,34,158,38,25,236,56,37,63,147,200,57,103,253,79,38,172,78,41,12,6,164,244,14,126,58,82,63,31,63,46,5,235,252,0,0,161,96,34,28,201,182,92,61,203,228,235,36,78,158,67,21,173,36,9,31,73,157,150,34,205,31,141,43,53,144,206,26,170,100,0,0,85,39,138,35,230,5,33,60,6,85,156,20,89,156,134,28,83,170,127,16,45,221,213,5,92,197,202,21,51,143,152,38,144,78,0,0,222,163,204,35,216,39,233,61,202,0,152,34,52,229,84,51,182,219,89,53,65,117,27,9,239,236, -90,35,51,227,161,54,86,174,0,0,77,166,59,24,102,37,150,32,58,90,89,12,226,221,131,57,189,226,64,14,174,23,133,2,251,59,192,4,184,8,87,17,103,195,0,0,253,129,33,42,229,35,51,5,70,241,120,23,40,171,154,24,66,199,100,25,19,186,57,56,128,48,3,54,114,26,180,2,82,58,0,0,45,250,55,32,52,50,79,37,50,196,253,27,93,61,178,15,4,3,65,63,46,5,33,13,216,67,141,29,240,43,120,31,3,229,0,0,218,91,117,29,16,114,151,3,14,241,129,4,251,192,214,23,189,221,11,25,238,39,52,38,159,95,59,13,165,234,210,20,113,69,0,0,117, -119,126,23,184,41,42,34,99,95,217,14,226,100,85,56,181,174,145,18,61,235,14,21,88,238,60,35,229,191,142,26,137,157,0,0,145,102,5,58,234,180,61,63,190,83,146,41,184,95,115,38,232,125,146,16,201,181,147,37,78,185,240,27,210,15,121,42,145,221,0,0,147,50,42,60,120,19,120,63,197,118,52,16,186,27,46,34,86,205,244,2,202,92,41,44,14,45,121,35,69,156,59,46,39,131,0,0,189,249,13,14,134,83,33,47,22,164,38,35,59,173,246,43,150,132,112,57,137,153,250,44,139,225,152,10,184,155,137,31,153,4,0,0,66,192,98,5,177, -201,134,16,162,177,223,56,210,200,72,11,9,214,142,26,62,118,152,25,125,137,22,27,155,138,170,10,228,90,0,0,156,38,121,15,126,51,23,36,191,141,205,7,68,229,54,56,148,74,157,56,128,113,119,48,181,234,81,48,127,1,159,14,217,153,0,0,97,175,133,30,161,4,34,13,107,118,174,20,183,200,181,35,78,15,27,2,219,63,218,58,154,181,142,28,168,9,185,14,194,146,0,0,9,43,106,3,167,217,200,57,212,254,134,34,173,96,235,8,45,121,213,56,28,87,95,8,159,64,187,17,85,192,35,62,76,65,0,0,168,235,181,7,203,198,171,56,108,163, -142,17,254,113,251,42,45,66,223,56,171,93,208,3,141,8,241,61,171,29,35,24,229,254,0,0,92,155,11,13,218,116,69,61,147,71,5,57,175,208,63,32,227,78,193,7,74,230,11,16,17,251,138,37,63,77,100,22,7,56,0,0,244,202,99,60,44,233,142,7,40,213,83,15,202,234,252,35,162,252,106,42,24,211,78,4,10,98,126,38,185,228,58,17,229,66,0,0,200,41,156,22,38,176,235,33,17,95,252,62,218,158,67,41,115,120,94,1,93,48,136,60,113,31,103,12,71,62,56,21,248,159,0,0,161,9,15,30,97,246,138,2,56,40,3,20,110,124,66,40,240,254,14, -48,145,74,187,37,57,56,206,50,84,153,237,32,237,122,0,0,115,125,133,5,122,51,118,17,64,165,244,51,3,204,203,34,216,142,45,3,196,42,244,43,221,199,247,30,140,230,23,21,184,245,0,0,37,231,252,36,43,168,25,22,114,91,108,42,113,244,54,58,231,180,113,23,60,122,65,42,94,223,122,32,40,61,172,28,99,224,0,0,221,49,238,14,229,211,192,9,11,135,4,49,225,157,18,18,215,140,72,26,181,202,238,9,42,225,207,24,56,47,93,34,144,122,0,0,106,141,50,26,35,6,170,46,189,24,220,26,165,206,93,19,178,167,143,48,22,70,38,26, -52,10,224,52,136,233,22,48,99,198,0,0,192,184,201,62,170,237,194,14,194,156,191,18,148,122,84,33,221,23,19,23,157,60,247,43,57,141,195,33,220,87,99,58,49,51,0,0,47,222,150,57,32,33,71,50,75,17,37,11,184,203,183,51,119,233,228,15,168,123,195,44,206,89,164,6,238,183,160,9,252,211,0,0,140,111,82,20,7,137,36,49,104,241,171,55,55,38,109,22,78,218,129,55,83,83,29,45,104,143,161,48,23,105,230,55,240,196,0,0,234,151,230,3,68,35,177,49,133,62,248,5,230,62,158,57,156,209,171,63,104,178,127,40,220,55,2,44,172, -255,208,18,122,193,0,0,135,108,220,30,247,225,142,59,176,42,240,57,95,109,104,56,150,174,31,32,101,220,227,5,174,76,149,53,106,85,11,23,53,57,0,0,27,218,99,49,8,12,75,11,24,49,58,57,131,185,183,3,154,222,31,1,255,117,210,36,140,70,11,57,153,40,223,34,97,143,0,0,110,215,189,3,68,72,204,31,124,110,155,36,140,154,49,20,100,66,90,44,94,211,105,47,95,235,182,62,34,124,201,15,35,120,0,0,144,174,200,14,248,67,22,58,238,93,188,11,186,228,154,44,207,184,241,3,178,54,110,53,134,235,230,33,222,86,60,48,152, -151,0,0,211,68,40,37,171,11,107,42,39,142,24,3,244,150,37,57,226,190,115,28,62,37,37,59,210,61,237,2,105,157,170,56,64,186,0,0,127,107,214,17,60,94,134,22,16,200,125,24,20,148,164,41,122,117,132,18,226,66,110,60,124,116,214,34,214,254,184,27,250,253,0,0,139,23,229,56,25,224,163,42,157,222,120,61,68,119,190,17,216,196,24,26,143,38,7,3,60,185,141,25,146,136,199,60,156,77,0,0,240,188,101,18,18,94,29,32,11,211,199,17,16,222,138,51,105,14,34,15,135,145,166,58,221,58,228,41,136,55,142,51,88,253,0,0,146, -98,153,43,115,234,249,12,223,209,28,15,138,255,134,9,135,251,228,5,146,230,170,32,83,189,21,50,216,77,121,41,224,255,0,0,84,151,85,16,35,164,181,2,84,88,63,42,120,247,66,44,4,34,224,12,112,231,239,2,141,53,69,29,53,87,156,30,60,33,0,0,242,88,180,52,212,9,203,63,221,238,167,54,124,61,20,18,187,144,161,27,145,24,180,14,1,7,37,6,185,214,66,43,109,75,0,0,204,220,5,30,70,0,182,12,229,147,154,1,83,251,232,15,174,114,209,19,229,90,130,27,84,9,3,26,79,93,184,61,206,184,0,0,80,87,109,12,63,131,82,0,51,129, -182,38,218,240,95,29,223,153,189,18,147,211,41,53,164,246,187,9,179,41,152,34,43,48,0,0,26,179,59,55,132,251,247,22,72,123,185,61,215,218,222,7,112,73,95,59,186,120,47,40,2,94,56,7,109,222,249,12,251,3,0,0,158,92,33,61,165,249,50,13,78,13,100,7,177,29,159,22,198,43,87,59,174,106,88,48,224,129,226,47,35,149,84,54,106,243,0,0,180,74,154,29,175,87,212,22,10,124,187,21,97,176,13,31,113,54,122,15,52,237,189,5,31,22,225,3,123,66,52,31,23,75,0,0,247,182,90,35,145,127,183,42,88,245,65,23,124,149,248,13,110, -72,107,34,77,202,217,35,218,95,166,47,120,105,186,25,201,62,0,0,164,35,28,48,166,236,27,61,86,207,73,58,17,86,144,10,194,117,205,57,230,166,224,0,42,108,160,39,168,129,212,0,135,94,0,0,249,134,217,16,172,101,94,8,161,253,204,36,210,97,199,5,162,45,110,44,184,70,87,29,113,30,34,9,231,190,19,25,150,91,0,0,102,12,123,0,72,215,252,60,177,111,200,22,25,185,255,41,52,116,235,44,130,61,145,8,71,164,128,22,195,100,192,48,69,229,0,0,112,212,242,49,73,95,253,33,221,57,162,53,134,163,96,57,151,191,188,25,229, -104,191,49,229,231,85,41,24,163,3,13,106,224,0,0,186,139,100,3,46,100,96,41,68,116,60,28,26,44,60,40,130,152,179,1,124,137,184,15,19,10,88,15,149,94,133,16,164,178,0,0,82,100,251,0,40,173,190,17,178,123,193,9,71,69,21,54,192,49,126,61,62,94,242,62,233,25,102,54,164,173,240,23,79,254,0,0,208,39,171,43,187,72,183,61,252,3,81,4,139,126,208,2,247,7,112,25,99,100,192,37,186,81,134,19,81,207,131,35,144,27,0,0,16,209,211,0,121,157,161,7,87,27,229,7,214,164,242,46,181,154,75,60,5,70,242,21,243,230,181,38, -17,187,151,24,109,155,0,0,60,213,251,8,236,232,48,3,223,205,98,28,43,28,227,32,226,135,154,1,149,74,77,46,219,232,52,11,189,158,202,9,124,78,0,0,230,170,220,23,96,80,206,2,62,211,125,63,47,133,229,2,83,27,104,47,183,125,66,63,22,142,177,16,39,155,29,39,116,23,0,0,255,179,33,37,147,17,166,56,206,80,167,26,250,197,1,15,35,165,36,46,166,175,52,17,94,199,85,20,50,4,140,19,72,2,0,0,126,218,105,2,228,146,107,48,188,139,172,35,164,183,1,28,173,235,14,45,172,240,172,48,126,208,48,62,136,42,40,52,25,150,0, -0,185,167,75,0,234,231,173,37,31,117,65,7,12,28,169,53,32,78,149,44,156,53,220,38,247,126,229,44,237,179,73,49,193,22,0,0,65,215,91,28,148,142,111,29,196,156,154,28,111,0,87,29,236,222,148,10,114,22,157,24,98,144,67,49,0,13,223,31,21,219,0,0,250,131,102,35,234,33,217,32,94,130,192,14,224,212,134,32,149,102,123,18,209,157,115,34,122,248,26,19,254,212,53,15,151,3,0,0,127,87,74,63,221,202,126,61,237,29,152,62,99,56,33,30,215,108,162,53,202,216,74,56,67,54,58,10,195,48,139,22,207,56,0,0,6,111,191,0,103, -230,44,32,113,181,67,16,137,204,4,15,113,101,87,32,192,210,19,48,194,17,21,15,187,156,238,38,106,186,0,0,81,181,29,56,193,189,175,12,254,170,151,6,235,61,69,23,158,142,189,24,149,203,47,8,32,3,27,33,210,44,142,7,119,19,0,0,67,26,35,49,193,231,123,52,159,59,212,26,153,53,69,53,68,47,68,30,147,65,101,59,138,45,221,4,243,9,51,47,197,53,0,0,246,200,32,22,20,185,220,54,231,10,207,35,1,51,233,61,76,157,88,58,219,130,96,57,52,231,108,52,229,142,92,29,54,14,0,0,9,6,212,61,91,241,2,61,107,215,28,24,3,38,100, -16,199,106,53,8,22,191,196,11,18,202,107,24,21,23,9,39,71,253,0,0,83,202,100,42,217,196,139,55,57,71,202,33,201,181,235,4,145,253,65,24,242,144,94,43,44,255,254,10,165,73,237,51,105,48,0,0,127,154,121,43,212,11,220,54,36,132,142,59,84,179,45,6,79,84,125,44,188,230,58,54,222,75,134,13,179,142,10,0,64,108,0,0,50,30,200,19,179,32,115,45,104,63,72,32,32,83,175,30,192,189,220,29,56,168,13,46,144,230,91,35,45,76,5,55,194,149,0,0,182,39,251,0,161,248,9,9,99,87,48,36,175,108,143,27,199,165,106,40,133,181, -226,8,15,177,177,56,157,111,143,19,167,254,0,0,111,185,60,50,223,246,116,0,119,183,247,51,229,90,214,26,18,147,175,54,50,123,211,25,207,151,50,49,194,230,54,26,5,110,0,0,86,151,136,62,166,107,96,55,37,187,4,48,94,38,217,30,242,243,153,24,156,236,101,51,38,130,234,31,132,204,240,34,46,118,0,0,116,183,166,60,129,103,137,23,226,165,79,8,82,204,182,28,25,71,227,2,38,197,19,51,199,195,151,62,188,130,9,37,40,192,0,0,234,210,117,9,92,122,221,27,162,142,78,1,132,62,171,20,30,169,244,8,140,236,246,38,225, -72,83,9,216,247,81,31,7,223,0,0,149,111,147,49,120,182,240,40,122,39,221,59,19,110,177,7,138,124,82,34,98,114,9,33,76,66,244,55,59,0,162,30,97,248,0,0,215,146,76,60,238,71,18,46,69,27,57,20,185,91,211,54,53,41,20,11,205,160,122,31,225,50,160,61,244,98,93,31,62,159,0,0,221,6,73,49,62,255,238,50,134,17,78,41,245,192,136,10,69,2,21,43,46,135,172,24,136,181,102,20,223,169,7,33,210,236,0,0,131,196,168,50,202,92,131,43,53,172,64,16,49,34,195,18,23,129,82,57,187,72,15,35,195,237,249,12,215,94,87,30,204, -160,0,0,169,107,204,18,86,209,89,2,85,96,147,54,247,198,35,13,107,120,223,49,200,37,63,29,35,238,115,56,44,190,72,0,195,171,0,0,238,58,221,5,175,109,60,28,33,47,109,57,163,162,78,5,19,202,118,41,26,107,170,8,14,206,124,60,84,69,41,20,28,109,0,0,247,151,245,61,147,83,141,59,223,58,213,14,170,66,140,7,133,116,212,7,138,0,200,9,119,201,253,61,170,129,35,5,255,175,0,0,187,208,166,36,223,166,50,30,198,253,26,26,189,72,76,39,101,143,65,38,162,98,155,6,49,63,159,63,229,98,88,7,95,94,0,0,249,234,51,16,228, -17,14,26,161,83,246,6,148,203,87,21,114,218,33,39,19,52,175,61,88,115,111,62,169,193,10,20,177,215,0,0,63,94,0,15,145,215,166,54,45,189,57,44,111,140,163,61,90,73,161,1,56,107,46,15,253,255,39,36,5,207,154,34,19,248,0,0,183,126,53,47,128,128,95,11,52,33,190,20,85,111,16,59,244,81,203,37,234,149,87,0,157,159,189,14,237,251,206,35,117,202,0,0,57,222,189,23,16,169,0,11,149,50,4,54,109,94,56,17,21,211,104,25,102,53,92,9,10,225,240,60,157,253,68,16,230,118,0,0,1,172,1,25,180,212,197,18,43,3,210,22,173, -244,140,10,94,211,240,1,26,92,155,1,119,245,92,41,147,123,227,55,13,201,0,0,141,238,120,0,115,36,20,60,66,148,145,6,148,51,200,47,78,246,79,27,170,142,201,61,95,226,155,26,103,97,235,21,142,208,0,0,134,62,166,45,112,211,95,38,222,217,46,2,229,243,189,15,18,244,109,62,213,185,203,5,214,114,141,8,173,18,230,37,46,133,0,0,236,41,145,2,193,25,69,22,129,84,130,36,199,179,142,43,12,8,29,19,179,3,250,34,245,117,210,4,53,121,33,48,166,125,0,0,14,255,217,44,138,187,66,45,174,134,165,12,149,33,48,18,4,191, -39,22,36,29,8,52,17,117,133,1,125,238,26,5,152,244,0,0,34,79,101,17,85,82,15,62,148,238,170,49,8,229,252,61,178,79,217,41,249,6,64,58,27,226,230,27,112,253,51,36,208,144,0,0,225,67,26,32,93,129,119,61,64,135,63,26,79,89,141,53,109,51,112,63,26,120,8,60,83,169,97,15,235,74,135,38,86,205,0,0,250,25,107,7,71,217,187,45,113,157,129,40,65,27,184,53,217,46,41,33,32,196,176,8,115,204,30,29,60,31,22,38,71,218,0,0,247,90,111,50,172,187,137,42,6,194,63,21,165,79,244,30,166,158,86,22,248,29,164,13,23,29,240, -10,243,38,222,53,177,235,0,0,189,93,19,57,150,237,75,54,236,49,134,29,206,235,33,48,240,124,137,41,11,214,171,30,129,173,230,30,55,42,65,29,228,227,0,0,93,4,72,7,249,188,26,36,150,218,149,44,215,191,128,40,165,254,63,56,74,101,32,35,185,64,108,60,114,2,254,22,10,147,0,0,95,69,238,13,151,231,194,47,92,7,228,12,186,249,255,25,255,74,219,11,224,227,76,17,71,10,155,10,28,250,91,25,140,126,0,0,186,156,27,23,96,166,247,28,113,98,70,47,209,89,180,40,74,59,165,3,32,61,216,61,163,242,64,7,140,178,140,49,221, -189,0,0,158,181,152,38,109,174,229,29,67,122,68,19,98,73,214,12,10,38,199,35,207,106,13,44,190,21,235,21,106,36,126,16,248,61,0,0,245,186,146,43,229,153,227,51,139,159,148,20,200,158,33,63,123,134,243,28,196,163,235,10,160,29,12,9,44,230,183,57,143,179,0,0,145,184,203,43,144,64,197,42,227,190,108,50,247,144,49,31,143,154,143,63,208,169,110,32,130,30,190,42,236,192,90,49,56,199,0,0,195,132,154,41,101,215,156,31,145,254,12,8,222,187,83,12,130,187,187,63,178,186,60,6,247,55,37,45,70,37,94,45,63,137, -0,0,141,213,97,7,206,188,234,18,243,226,96,13,2,249,38,19,202,122,223,32,92,141,2,9,10,97,20,54,143,224,73,24,196,184,0,0,164,81,16,29,234,130,58,14,182,197,7,33,23,30,65,29,63,5,197,51,95,218,99,17,74,209,55,14,92,20,91,54,158,143,0,0,64,0,11,5,16,204,194,54,194,173,52,1,124,110,31,61,243,113,54,26,250,79,38,3,53,122,31,39,64,220,167,27,213,8,0,0,161,208,63,27,233,153,56,22,235,43,120,33,131,28,241,53,246,133,178,57,53,42,84,52,255,33,170,41,66,175,107,33,33,161,0,0,127,59,87,19,124,143,149,21,15, -39,182,48,180,23,135,38,136,55,90,38,239,93,62,8,30,52,230,60,11,181,140,60,19,220,0,0,166,43,31,12,161,72,179,10,196,177,4,52,5,28,85,17,112,118,10,41,18,106,67,16,199,195,64,35,167,16,160,46,9,201,0,0,235,156,174,7,46,100,189,0,75,209,242,14,156,122,8,27,34,168,25,33,108,151,85,6,175,115,240,55,119,128,121,11,192,37,0,0,117,226,198,11,77,52,36,28,100,114,88,38,194,119,144,49,55,213,17,45,62,55,56,33,200,192,131,35,4,178,180,58,159,138,0,0,52,60,90,44,219,99,2,62,225,159,148,21,10,176,160,51,174, -88,62,46,158,50,125,46,138,206,73,14,62,203,70,39,221,254,0,0,20,119,61,33,211,47,213,10,118,41,248,27,166,81,173,43,173,0,75,15,178,196,20,58,11,11,142,59,20,198,48,9,46,165,0,0,150,163,182,42,70,83,57,45,105,7,54,17,104,228,134,0,115,179,136,4,122,253,181,56,222,194,72,42,27,175,161,12,14,62,0,0,126,226,128,25,35,121,204,58,162,246,104,52,124,16,4,44,106,198,63,5,173,119,248,7,243,100,121,51,142,190,92,32,68,202,0,0,236,35,16,52,136,97,205,43,10,87,207,62,219,61,118,17,86,175,185,2,38,128,128,11, -152,132,210,50,48,32,76,46,74,52,0,0,135,235,30,30,164,96,226,19,112,93,153,3,191,218,165,19,252,95,76,17,169,71,203,35,63,167,98,4,201,10,193,10,28,110,0,0,75,193,246,8,150,125,186,28,67,1,37,41,206,151,203,53,209,119,40,23,242,141,29,19,38,30,184,37,45,82,153,24,149,216,0,0,31,153,125,29,93,251,216,36,23,126,6,59,202,88,163,16,3,235,64,3,99,32,24,59,40,231,234,7,175,60,142,42,191,254,0,0,86,183,39,33,253,31,234,2,72,112,9,58,42,249,162,16,3,22,180,32,65,105,139,13,45,103,18,31,91,220,11,30,140, -109,0,0,113,37,23,63,42,221,71,21,166,204,205,23,139,182,169,14,78,175,77,19,219,180,160,38,69,17,145,27,191,37,194,55,174,153,0,0,122,241,140,53,205,105,184,55,36,53,130,24,233,114,23,62,241,248,151,0,109,188,107,22,208,168,172,55,111,101,183,47,202,235,0,0,205,12,170,28,125,113,179,17,196,149,206,10,180,132,180,62,16,107,46,3,159,109,40,0,44,176,156,43,200,227,131,51,211,71,0,0,91,92,133,44,86,148,187,51,187,175,200,23,128,134,88,33,17,40,252,23,120,218,104,12,83,68,226,12,245,146,75,19,223,232, -0,0,80,86,70,46,176,156,87,39,213,215,228,33,199,87,237,24,150,197,50,47,103,61,109,19,68,100,178,57,31,49,92,63,87,108,0,0,84,228,231,18,105,111,61,2,13,21,230,48,195,251,187,12,254,98,22,24,234,8,24,18,18,41,131,10,59,198,245,52,104,64,0,0,30,25,239,24,151,55,107,30,39,51,55,60,68,123,72,35,152,209,56,29,246,101,81,48,158,171,122,36,82,201,237,20,216,140,0,0,57,217,197,6,225,183,94,33,224,61,147,58,222,161,104,29,164,126,2,10,131,185,204,47,85,11,94,2,118,108,179,3,85,18,0,0,201,87,231,25,21,63, -157,10,25,67,141,13,251,7,221,34,131,114,74,50,93,240,144,35,68,117,122,45,28,62,205,32,143,123,0,0,111,165,200,22,25,171,66,35,19,66,55,15,13,21,79,2,133,143,208,58,235,212,222,46,105,76,93,24,237,176,198,25,77,148,0,0,137,226,123,26,151,113,211,39,235,23,101,16,55,93,48,53,103,25,198,58,76,216,228,16,193,244,255,1,212,222,101,25,16,167,0,0,90,241,8,46,98,40,174,59,186,0,41,1,114,91,121,26,253,5,195,19,107,149,13,44,230,207,160,25,66,115,164,19,165,134,0,0,8,131,56,1,159,71,147,20,211,84,82,51,150, -68,167,4,119,103,104,53,181,65,163,10,167,3,70,56,233,13,82,24,238,207,0,0,3,110,103,15,89,41,84,36,212,237,132,62,164,205,241,63,206,97,135,30,92,205,144,61,176,142,81,23,165,202,0,37,218,184,0,0,231,246,253,14,157,147,35,18,17,181,243,31,101,19,22,51,146,176,8,40,216,37,115,38,124,77,30,26,1,18,233,55,4,40,0,0,107,52,225,6,119,18,102,40,94,28,175,5,14,196,158,47,90,192,82,17,83,124,216,49,84,190,16,45,96,194,63,26,144,6,0,0,19,108,34,23,83,41,214,46,231,38,96,12,101,78,162,61,164,42,68,6,66,175, -108,23,168,109,226,61,47,36,248,56,99,184,0,0,161,246,161,28,243,71,154,3,163,241,207,8,13,69,47,35,6,225,108,40,199,114,113,27,40,21,118,25,201,242,36,13,140,137,0,0,124,100,79,22,60,8,183,18,202,121,189,50,231,229,243,41,178,147,110,44,74,145,80,17,216,73,85,42,213,170,97,22,247,117,0,0,152,57,30,61,240,128,167,41,138,50,4,58,69,46,178,21,94,78,39,42,8,92,103,10,165,1,191,24,164,180,191,56,19,178,0,0,30,184,95,50,24,247,178,48,94,23,237,61,250,150,5,13,213,195,59,36,14,254,122,24,61,44,193,19,203, -131,176,35,159,34,0,0,52,226,91,34,178,127,248,2,112,80,243,29,195,249,248,32,14,6,110,32,69,154,46,52,209,229,147,63,177,5,182,14,59,75,0,0,98,131,14,18,14,248,237,24,64,184,17,50,179,100,255,57,65,76,192,12,246,183,165,23,135,199,201,43,118,225,142,0,236,94,0,0,94,245,137,34,159,210,152,37,123,112,118,44,56,60,172,29,41,190,101,9,158,192,70,9,32,96,249,4,108,183,45,34,123,159,0,0,222,75,30,62,151,237,52,15,27,43,10,49,58,184,77,57,192,31,199,15,166,208,26,5,227,123,15,1,193,49,225,61,249,50,0,0, -43,29,254,29,48,114,82,25,81,142,135,22,121,66,253,36,196,164,115,59,79,127,43,51,118,62,142,4,221,114,250,16,138,213,0,0,34,9,213,12,110,229,201,51,255,251,214,11,87,136,110,54,84,107,39,40,160,76,164,28,10,241,60,8,22,232,154,33,23,252,0,0,94,121,156,36,248,70,5,9,225,5,232,28,166,170,1,17,237,78,234,39,240,112,90,54,214,12,49,24,68,92,78,28,210,33,0,0,206,142,32,25,14,187,4,0,27,118,251,45,146,18,101,28,214,195,180,43,72,21,110,13,119,161,206,26,29,44,109,62,197,148,0,0,93,223,192,35,227,93,132, -6,47,121,106,21,212,254,123,6,32,171,127,29,29,229,106,43,216,167,51,59,7,17,133,58,15,232,0,0,120,236,201,42,109,164,208,50,159,234,34,51,43,160,87,5,45,71,148,10,143,50,218,37,232,113,7,32,227,216,159,55,209,238,0,0,85,45,89,23,179,103,13,48,146,1,53,14,208,81,110,53,6,177,227,60,140,165,189,63,138,96,82,16,40,241,182,49,46,93,0,0,167,131,81,47,58,116,185,25,66,23,21,17,107,243,158,10,14,149,214,12,154,232,67,28,143,181,94,36,27,39,126,51,146,10,0,0,92,159,143,62,39,45,125,36,25,165,128,24,86,120, -124,24,115,77,64,31,133,208,184,50,226,47,116,63,70,236,112,7,55,172,0,0,60,80,90,50,204,255,160,30,209,225,81,39,59,22,77,37,34,53,231,20,201,156,7,4,242,127,71,26,194,97,176,5,22,197,0,0,70,52,227,25,84,35,135,18,223,133,243,42,20,241,78,34,64,122,161,34,8,244,2,35,52,201,64,24,60,133,14,0,66,137,0,0,137,118,56,38,3,40,78,3,132,249,116,30,158,205,93,63,107,224,228,61,59,180,181,44,216,164,119,16,105,101,229,0,253,169,0,0,38,203,19,57,86,50,202,53,3,109,189,19,0,103,208,58,153,152,92,16,213,63,145, -54,44,138,42,52,40,204,154,9,112,39,0,0,162,167,72,51,207,92,156,63,187,190,21,8,243,70,50,16,233,36,179,50,31,52,73,11,85,165,177,13,108,158,23,47,73,246,0,0,71,130,94,25,133,128,170,2,175,209,108,40,85,17,247,47,151,144,186,56,115,128,155,23,142,23,210,62,242,224,52,52,228,117,0,0,34,45,152,25,117,246,143,40,60,137,173,41,186,109,173,54,125,212,38,55,30,59,92,62,65,7,153,16,80,93,168,16,206,31,0,0,35,51,51,38,54,209,231,17,71,191,74,15,26,7,239,46,156,132,218,4,102,129,53,8,240,3,191,27,216,12, -142,45,209,62,0,0,163,27,214,53,34,241,79,44,148,114,143,55,66,40,202,45,169,158,146,15,162,37,38,31,217,117,238,52,214,34,105,11,79,216,0,0,191,128,57,51,82,95,65,9,175,11,208,13,148,11,220,40,104,67,221,8,141,220,245,27,132,27,24,24,157,26,188,52,253,112,0,0,133,87,183,32,58,163,186,11,97,165,116,29,225,96,13,4,10,107,89,46,71,52,4,41,87,105,105,24,53,52,176,50,223,94,0,0,112,96,225,4,243,238,1,55,93,145,214,47,199,128,96,40,242,67,117,22,117,148,35,41,59,49,4,23,243,247,94,26,1,163,0,0,161,126, -23,30,16,104,52,48,48,161,17,10,240,253,118,13,23,155,15,20,151,232,39,32,129,80,79,62,217,62,71,62,112,115,0,0,252,17,128,19,0,156,4,28,38,86,40,23,235,153,90,22,131,77,10,32,8,194,76,44,86,17,177,30,5,194,232,4,131,110,0,0,125,171,21,63,232,167,45,43,166,249,81,28,186,86,228,43,38,4,195,26,7,200,182,4,26,76,32,15,9,247,98,32,71,193,0,0,167,107,14,16,227,38,157,14,245,247,22,9,209,22,187,13,61,180,225,25,147,226,128,7,189,242,81,8,225,101,66,42,82,249,0,0,193,228,117,1,148,187,235,54,152,43,42,6, -211,158,197,21,85,246,160,63,137,139,218,13,97,248,235,60,42,194,150,14,169,216,0,0,147,14,170,3,138,150,1,36,38,246,177,47,235,80,142,11,143,58,137,30,118,134,198,0,4,117,238,63,116,140,87,27,1,148,0,0,194,218,173,7,162,73,187,35,163,7,123,37,234,206,13,33,244,215,111,46,59,213,116,21,3,100,217,20,17,151,187,12,80,103,0,0,123,177,102,2,184,24,210,3,43,179,43,38,128,40,90,13,2,194,9,31,170,17,226,37,187,145,40,59,103,53,93,52,34,239,0,0,62,200,218,57,13,129,155,10,115,27,52,28,220,219,201,57,62,7, -161,52,184,14,51,39,143,86,199,36,172,94,50,33,87,188,0,0,160,130,211,18,106,5,76,12,226,154,205,46,56,239,114,35,242,39,249,45,44,224,49,43,156,211,146,56,58,147,243,59,247,181,0,0,50,181,180,37,238,42,188,40,91,140,207,26,74,91,194,62,113,211,221,11,131,27,95,37,192,83,35,63,112,212,22,21,67,104,0,0,165,255,44,1,145,145,164,57,71,92,204,40,25,130,80,59,137,67,98,20,239,99,83,29,8,100,7,49,185,172,244,48,221,28,0,0,78,149,33,21,115,98,155,55,138,82,107,51,154,16,38,7,196,138,176,2,229,175,73,44, -253,99,138,31,188,44,131,26,71,30,0,0,47,242,169,52,228,144,127,13,173,226,168,23,72,113,6,2,204,176,53,8,82,46,46,62,33,159,147,14,151,124,214,44,204,42,0,0,39,73,92,55,206,114,215,45,183,80,165,27,177,239,245,18,21,241,237,48,183,223,232,4,146,81,46,45,34,86,58,41,24,213,0,0,212,78,176,63,248,24,235,45,250,255,7,19,196,194,12,51,8,226,141,39,73,20,116,62,99,100,147,43,117,226,108,33,173,144,0,0,80,241,110,11,35,53,117,36,217,148,40,24,133,175,190,43,57,184,34,50,9,101,47,55,255,26,38,56,40,136, -141,30,80,14,0,0,120,182,183,48,206,108,215,9,102,129,99,15,111,196,16,15,241,118,108,43,9,41,175,33,25,186,49,2,57,205,92,18,110,24,0,0,193,31,217,56,203,219,129,30,202,93,83,9,81,137,220,1,17,126,230,55,2,151,32,63,167,74,216,59,1,38,57,24,212,192,0,0,184,31,66,51,46,151,27,60,12,93,165,53,187,124,92,18,152,18,36,55,14,211,172,1,126,46,246,27,219,211,96,35,28,6,0,0,128,205,60,14,161,217,123,37,41,221,252,38,206,210,196,25,128,92,235,5,56,100,73,14,169,123,75,59,0,100,182,26,252,109,0,0,164,53,107, -47,98,248,146,4,135,180,127,50,170,233,205,39,136,173,104,58,204,1,201,24,115,59,81,46,35,136,142,45,166,246,0,0,166,34,244,1,178,191,173,43,44,134,225,30,157,91,93,53,25,111,24,32,213,19,220,52,202,177,56,17,11,0,42,50,247,61,0,0,17,76,149,38,162,143,160,37,139,1,13,22,5,15,41,42,127,255,120,7,84,60,108,52,32,98,55,44,161,48,10,63,162,135,0,0,69,139,42,39,184,204,184,21,183,36,129,39,202,207,36,18,204,50,117,18,131,54,82,6,123,249,206,46,106,209,98,20,173,51,0,0,182,106,112,34,171,28,29,57,218,192, -83,46,116,7,205,2,60,254,76,56,240,242,187,21,69,104,26,8,158,27,129,11,71,225,0,0,5,222,88,29,90,168,161,27,83,39,205,19,81,85,39,22,170,248,33,6,50,94,70,26,63,104,252,24,241,145,170,36,205,130,0,0,182,79,168,7,8,149,235,47,30,2,21,58,67,29,218,8,196,235,185,8,121,128,53,45,232,93,239,10,62,1,178,36,175,28,0,0,9,145,20,39,64,6,198,26,97,103,206,34,90,90,48,7,236,34,22,16,252,227,147,41,129,164,83,46,93,178,22,46,36,188,0,0,17,89,149,10,133,63,163,29,219,82,237,13,152,168,133,31,16,151,131,23,207, -166,191,39,88,210,80,22,194,107,90,63,91,112,0,0,228,0,210,63,79,26,223,46,216,114,46,36,138,212,206,31,41,250,81,0,213,7,246,24,126,10,153,63,220,194,4,41,74,225,0,0,218,192,196,30,50,17,237,45,81,51,234,35,28,158,21,35,232,46,22,31,96,182,6,39,35,57,243,53,142,189,116,46,104,143,0,0,130,255,31,16,229,253,242,8,223,191,16,21,165,63,139,58,187,93,33,62,218,10,67,54,225,109,152,35,129,110,203,39,42,102,0,0,250,9,56,18,183,227,138,35,225,75,149,29,212,44,23,33,253,8,31,5,201,143,205,36,186,40,242,9, -148,139,111,7,56,56,0,0,82,237,31,51,96,212,193,53,219,36,143,45,204,50,127,32,54,204,177,14,72,149,22,16,9,203,125,17,238,131,66,11,163,228,0,0,16,163,194,23,34,153,144,58,3,99,34,1,80,169,171,33,241,161,153,6,169,10,110,8,105,111,174,50,13,57,201,9,38,73,0,0,208,222,39,30,5,218,6,49,224,140,255,53,169,132,141,5,109,59,48,20,92,90,233,51,162,149,191,58,41,239,220,57,55,19,0,0,49,45,189,14,231,193,18,14,209,184,109,48,191,149,6,51,77,248,226,55,145,207,78,9,94,13,201,0,137,6,163,21,6,227,0,0,68,110, -84,18,14,2,173,36,102,130,115,35,175,16,32,47,255,182,13,61,253,65,172,60,136,8,38,52,36,222,248,27,172,14,0,0,176,54,49,54,120,14,195,20,156,221,65,43,106,54,254,58,116,51,214,59,143,216,57,44,113,194,239,12,10,137,3,4,158,59,0,0,138,188,219,44,189,5,251,20,25,248,49,45,206,40,138,43,162,38,91,7,61,174,207,20,241,29,183,43,69,75,5,38,251,250,0,0,63,93,72,47,28,193,35,24,233,238,123,16,32,218,129,50,23,247,222,30,215,3,42,27,183,146,154,44,74,92,82,43,10,187,0,0,117,249,162,60,64,73,78,30,254,191, -112,22,140,190,150,22,137,52,218,23,202,125,128,52,236,152,71,53,96,241,20,39,105,234,0,0,201,141,113,54,232,76,187,43,228,61,18,1,108,211,98,57,225,19,1,62,235,101,172,35,78,13,204,47,59,57,178,2,9,121,0,0,197,231,250,28,196,138,204,24,185,8,144,58,194,237,171,13,221,86,170,26,54,47,91,32,61,241,184,5,100,228,138,28,171,234,0,0,209,199,96,63,49,165,165,9,42,173,117,23,243,121,199,53,141,102,186,9,149,243,110,15,192,81,181,23,126,122,107,32,124,231,0,0,73,36,215,2,202,7,22,59,52,109,152,2,199,61, -28,5,99,67,21,40,250,200,236,48,95,28,50,1,190,59,30,5,207,58,0,0,17,30,35,19,65,245,27,26,230,227,129,54,64,25,58,18,31,9,54,12,102,228,127,38,255,101,93,56,171,93,192,62,243,228,0,0,188,115,235,47,93,225,176,8,152,28,29,21,178,211,249,49,108,40,183,2,168,67,155,6,102,193,241,52,59,180,206,24,99,30,0,0,214,91,240,43,57,193,103,14,101,148,169,18,200,128,91,61,162,236,13,7,173,127,212,11,131,144,254,4,185,111,144,12,12,144,0,0,139,53,13,48,239,180,74,57,93,177,239,4,15,214,20,38,214,57,36,11,92,17, -200,49,149,95,15,31,44,58,122,62,49,108,0,0,80,92,16,31,50,163,240,41,87,82,56,49,222,187,55,56,130,205,51,2,15,208,48,35,98,173,10,25,193,170,216,0,141,90,0,0,233,205,164,56,96,128,108,50,53,60,1,45,153,162,125,1,166,116,255,3,5,201,173,41,54,105,83,14,245,68,172,58,89,192,0,0,235,79,214,50,230,98,248,17,198,146,34,41,100,41,190,28,55,232,164,11,219,93,233,60,142,164,96,47,140,196,64,19,63,217,0,0,89,131,105,52,100,245,62,44,55,218,144,44,251,194,16,56,147,77,140,28,83,113,196,28,35,58,115,50,114, -81,87,21,37,121,0,0,132,188,159,3,53,19,136,8,103,1,122,5,88,164,24,28,126,91,198,42,152,241,138,19,177,65,132,50,219,184,113,26,7,47,0,0,236,27,32,28,120,11,228,62,115,93,221,4,147,218,230,41,204,73,33,14,100,30,192,55,165,223,221,59,92,147,220,60,52,180,0,0,234,88,167,6,50,171,223,20,77,156,241,39,36,198,32,6,145,57,110,1,85,104,37,26,88,153,48,32,103,21,224,25,126,254,0,0,73,182,122,27,87,182,200,19,30,13,18,3,209,193,5,32,59,31,37,9,97,90,56,2,140,152,203,29,160,232,89,26,170,56,0,0,250,254,255, -12,154,88,197,57,173,175,81,6,220,19,1,6,16,133,175,3,67,69,190,61,109,125,18,3,78,157,114,61,186,145,0,0,175,111,127,31,211,188,77,31,220,3,211,47,57,196,188,47,244,146,61,29,159,196,167,37,93,190,206,59,209,100,196,51,229,4,0,0,70,197,51,13,250,69,2,63,50,175,237,5,202,236,215,21,130,215,221,53,131,207,77,49,178,124,138,55,207,114,72,16,88,68,0,0,212,79,11,0,28,70,155,2],"i8",4,t.L+10240); -D([102,115,202,50,62,143,194,11,133,32,218,26,228,184,122,9,114,167,83,7,254,252,221,36,141,48,0,0,158,226,234,32,184,186,237,27,113,208,225,20,195,203,211,0,199,102,66,26,145,222,84,24,185,30,51,63,58,198,166,62,0,140,0,0,75,65,2,39,25,147,74,31,78,197,54,30,160,190,182,62,194,116,201,54,220,232,208,48,157,26,26,18,169,255,153,28,164,239,0,0,61,145,253,43,15,88,229,15,172,158,76,37,187,57,160,41,80,32,141,42,48,33,232,1,77,135,223,61,65,250,169,10,54,54,0,0,61,36,46,5,171,107,62,17,252,170,47,43, -53,196,46,12,216,130,42,26,195,13,145,24,65,83,253,10,46,219,25,30,242,72,0,0,150,40,19,45,230,175,174,50,103,201,198,59,173,238,120,44,252,13,32,25,183,88,182,22,41,47,224,33,202,124,219,37,135,68,0,0,72,82,104,47,74,108,0,35,164,167,106,39,152,86,3,45,6,51,26,22,209,29,164,38,252,30,254,26,69,52,24,22,189,39,0,0,12,103,162,63,218,91,5,2,110,62,39,6,232,10,62,0,116,36,3,53,12,170,114,42,182,136,55,56,242,162,176,14,77,74,0,0,77,118,193,22,247,127,46,2,216,238,155,50,47,83,22,12,73,157,43,48,123, -119,196,29,126,241,164,5,97,0,71,46,171,112,0,0,167,74,178,12,137,191,90,54,48,197,69,19,142,49,66,12,144,24,254,56,127,98,191,57,58,44,128,17,186,66,70,11,123,95,0,0,125,61,105,10,13,29,224,53,198,208,129,60,36,220,122,35,206,71,124,38,243,40,224,15,10,51,43,31,63,49,128,13,112,7,0,0,189,184,127,47,124,241,70,6,164,144,64,62,87,40,25,49,123,216,134,8,101,155,147,48,174,2,13,25,231,76,20,29,57,81,0,0,15,140,144,3,182,176,82,2,168,213,152,63,248,180,12,63,250,71,92,1,186,246,251,35,184,52,191,3,217, -145,15,5,215,252,0,0,115,202,54,46,87,36,221,10,222,62,191,59,218,52,25,50,234,135,72,1,252,74,68,10,164,138,251,61,254,138,181,5,131,207,0,0,52,85,194,46,80,134,36,45,245,16,215,8,54,102,133,37,28,104,202,28,67,34,20,17,56,62,215,25,215,122,99,45,254,9,0,0,125,249,82,55,90,223,36,50,19,102,71,51,215,241,190,11,90,22,166,15,163,25,74,39,83,222,73,59,18,147,166,55,16,134,0,0,242,26,27,31,80,115,95,1,8,62,84,5,213,103,211,42,87,158,249,51,148,108,102,51,55,201,187,48,216,10,232,37,25,211,0,0,65,62, -203,32,241,119,255,37,9,44,185,8,204,19,66,15,20,211,142,41,167,2,59,3,225,243,41,8,117,167,57,27,162,231,0,0,81,253,44,15,135,80,42,58,32,62,232,32,16,176,172,41,208,24,187,47,106,168,1,44,113,180,132,57,233,3,140,35,117,42,0,0,219,66,238,58,175,244,231,3,167,20,7,51,209,22,239,46,217,193,191,44,71,110,187,45,199,15,21,25,109,246,249,9,52,204,0,0,219,123,216,21,4,112,138,24,220,34,36,39,99,235,114,57,16,0,82,33,236,79,255,56,133,24,106,28,72,105,16,38,36,234,0,0,134,160,212,62,25,155,13,61,239,16, -196,41,99,5,215,53,177,244,92,11,239,23,22,15,200,222,69,4,102,179,110,1,143,148,0,0,75,202,43,30,62,0,134,10,26,45,250,3,199,41,202,8,28,65,57,17,128,153,66,17,47,56,163,34,214,254,39,42,76,134,0,0,33,44,84,55,178,169,47,3,92,193,100,42,163,52,125,6,174,67,109,29,20,21,241,27,101,144,172,25,164,164,88,6,132,37,0,0,191,250,43,39,101,140,175,47,179,215,42,12,185,97,232,56,243,213,19,53,49,147,106,23,30,128,68,50,54,199,199,22,179,252,0,0,248,203,30,12,208,135,17,15,164,124,237,46,166,55,124,34,100, -31,66,40,7,51,213,37,42,82,82,60,220,4,113,51,18,126,0,0,21,214,190,48,54,227,22,53,89,159,29,62,99,135,125,26,201,89,18,13,249,106,83,62,67,113,131,28,35,34,226,19,40,113,0,0,134,125,85,20,112,148,153,31,65,255,103,38,227,17,187,63,28,207,166,5,232,41,71,46,114,103,42,52,141,202,191,48,142,75,0,0,185,126,22,53,70,198,102,55,43,105,63,60,195,187,124,53,40,95,172,39,148,183,28,16,74,177,122,21,48,193,255,48,230,253,0,0,60,118,128,7,237,180,224,10,213,145,86,38,164,87,155,34,95,126,192,58,165,113,219, -16,50,37,164,35,229,204,65,48,213,252,0,0,203,81,232,56,128,208,57,21,75,58,70,22,156,139,108,6,177,140,227,50,125,205,54,8,183,99,196,34,84,185,248,42,221,24,0,0,134,246,142,29,193,248,142,51,107,230,114,34,0,61,146,35,246,83,110,38,224,107,151,34,35,82,190,60,16,150,59,11,15,144,0,0,207,168,33,33,159,37,233,28,80,109,21,9,15,253,55,27,89,16,209,9,77,108,84,49,97,173,37,4,24,123,85,48,42,115,0,0,239,128,107,30,207,122,202,51,243,36,148,23,159,229,242,50,113,197,189,60,142,8,3,21,35,141,236,34,217, -184,131,39,69,182,0,0,69,186,113,26,216,194,47,12,255,178,53,14,82,155,235,44,196,179,29,38,149,91,124,43,29,222,6,62,188,65,219,33,124,6,0,0,233,136,152,49,228,201,115,14,180,168,72,36,252,154,174,4,61,103,129,38,165,192,52,24,222,45,110,58,176,206,157,58,144,31,0,0,121,59,17,47,95,242,247,27,101,46,82,25,185,127,212,13,33,168,150,43,199,73,79,5,88,233,16,42,118,5,159,13,190,137,0,0,44,34,98,53,188,237,123,33,96,44,111,30,100,30,209,0,222,186,82,11,205,180,174,0,231,214,10,62,127,123,83,57,164,19, -0,0,69,1,32,40,50,154,197,50,8,76,144,28,235,93,113,62,212,82,154,32,117,224,11,43,44,59,129,46,5,150,83,31,214,201,0,0,187,70,59,52,3,55,249,13,84,82,146,44,254,152,78,59,18,189,93,5,97,23,240,1,212,209,173,10,207,200,175,7,153,97,0,0,72,168,32,12,7,100,61,18,239,216,236,18,41,167,28,42,28,241,173,59,155,197,225,60,82,41,73,30,255,60,194,56,197,1,0,0,59,221,26,18,119,143,111,57,247,216,39,23,209,19,165,38,139,17,38,22,52,108,115,14,144,116,56,61,225,45,169,43,39,234,0,0,221,231,140,54,118,164,120, -45,113,190,225,36,163,181,132,44,120,98,47,28,201,200,58,15,114,229,125,33,10,185,121,60,15,199,0,0,87,247,31,33,237,226,43,58,230,38,194,4,7,93,58,19,155,218,182,34,219,226,67,0,169,75,213,63,223,90,77,20,70,89,0,0,26,3,77,9,42,187,153,34,178,227,255,59,223,30,239,6,150,249,6,4,87,64,227,0,66,0,117,50,119,57,131,13,17,54,0,0,181,96,97,35,141,98,137,29,6,188,126,14,28,201,79,49,204,192,30,9,192,229,189,14,132,14,41,51,125,69,142,27,178,22,0,0,14,220,161,24,253,126,137,17,129,239,163,11,28,171,142, -13,225,212,84,54,24,73,13,25,99,187,248,46,192,152,150,21,15,6,0,0,184,45,179,55,36,74,147,37,243,145,119,36,125,210,181,7,201,133,234,44,16,242,80,40,190,49,249,25,21,113,165,20,75,2,0,0,96,247,100,42,170,62,21,37,149,26,184,5,72,4,218,42,98,232,91,30,49,135,160,56,182,199,9,51,255,214,227,59,159,96,0,0,232,67,105,9,109,61,104,59,93,90,60,39,159,241,199,27,29,35,6,15,70,168,210,8,147,7,132,59,2,10,50,32,138,214,0,0,32,49,19,43,153,16,50,37,162,149,82,4,222,227,158,3,91,139,226,48,222,69,126,44,196, -0,109,24,45,253,127,42,139,219,0,0,249,196,161,12,134,170,208,22,35,40,126,43,50,141,191,19,79,244,22,31,152,246,224,2,196,196,40,23,175,200,227,61,21,120,0,0,21,188,120,55,218,168,199,42,25,30,125,23,133,121,11,45,92,93,195,24,81,204,243,36,221,167,246,26,78,51,122,0,198,193,0,0,48,133,140,46,15,135,155,52,230,216,244,56,123,160,125,11,81,109,108,42,5,144,241,29,227,118,1,4,59,104,243,28,146,195,0,0,199,70,132,57,61,60,12,16,92,113,237,46,104,47,127,59,80,152,25,3,7,81,78,7,208,233,200,51,208,149, -144,47,65,140,0,0,193,38,122,35,236,2,201,7,83,106,191,13,48,150,27,27,22,37,59,16,7,199,144,8,117,2,27,1,97,253,17,29,49,218,0,0,111,77,247,44,179,219,96,20,95,82,129,58,117,177,13,26,211,183,216,25,9,159,5,33,35,157,198,24,215,31,238,37,59,117,0,0,73,220,57,55,164,162,216,10,61,96,85,47,153,182,228,36,35,26,35,63,47,66,177,18,6,193,230,48,171,192,178,57,75,106,0,0,207,213,237,50,119,174,168,57,211,164,164,20,44,211,138,31,171,88,128,58,131,141,155,5,220,151,117,16,162,138,234,35,93,241,0,0,172, -127,152,6,49,40,250,34,121,246,134,10,144,225,67,50,139,60,138,9,251,128,9,38,78,52,241,39,235,196,167,49,247,1,0,0,104,76,23,25,224,156,71,62,99,194,107,31,134,120,215,31,203,249,182,26,202,184,13,4,91,222,34,26,191,205,15,51,78,157,0,0,77,186,218,54,245,134,206,52,97,98,25,3,136,195,126,25,156,203,43,58,99,183,139,1,183,28,56,61,135,93,0,37,126,85,0,0,22,35,165,55,110,40,221,4,165,144,53,36,126,61,110,58,197,134,188,12,87,232,115,13,109,4,126,58,7,152,206,35,126,122,0,0,26,52,245,41,252,75,61,14, -128,107,99,41,25,203,232,49,156,65,1,49,158,58,80,39,178,147,90,8,102,134,160,54,218,58,0,0,204,198,134,37,77,2,86,20,203,251,232,5,109,185,180,53,233,23,16,43,218,252,214,56,82,245,105,19,102,162,136,7,234,191,0,0,93,61,141,2,63,96,86,2,164,206,73,52,92,174,171,4,150,176,48,58,65,194,9,48,45,37,4,8,151,125,95,59,74,50,0,0,132,124,171,22,190,146,200,25,57,132,50,35,31,195,78,8,25,79,31,44,107,13,3,3,19,255,242,33,45,221,149,13,138,100,0,0,211,62,213,47,96,93,36,23,239,204,86,26,231,62,221,15,22,73, -124,31,199,228,130,61,184,213,42,55,89,102,245,2,132,32,0,0,50,113,122,26,148,255,80,28,152,137,112,14,229,28,241,33,84,194,250,58,154,218,81,47,135,52,36,24,176,243,37,13,153,242,0,0,53,91,163,8,214,46,75,47,237,33,161,0,151,34,118,45,26,253,235,8,150,167,64,15,209,187,155,51,172,131,253,47,182,230,0,0,189,7,16,28,110,79,202,21,124,156,153,62,78,39,219,14,254,221,97,25,13,142,15,61,102,50,47,13,192,76,175,60,95,26,0,0,211,13,54,0,75,227,59,53,144,32,14,5,182,13,42,42,71,187,227,12,184,33,224,2,139, -40,155,9,249,22,221,5,83,224,0,0,123,248,36,60,68,54,187,10,43,220,3,1,166,247,97,46,97,20,160,54,214,10,86,2,216,156,243,18,118,105,220,14,28,220,0,0,234,223,152,16,139,153,81,48,151,135,103,42,75,242,44,55,250,87,94,58,160,74,151,35,1,158,197,6,226,157,206,14,21,168,0,0,47,137,109,46,125,167,38,41,88,65,175,45,208,61,120,45,177,3,62,5,94,113,110,35,61,197,15,6,116,24,89,14,71,42,0,0,165,207,206,11,146,222,249,41,32,176,107,49,134,182,88,3,42,59,218,14,142,113,165,17,235,173,221,10,251,195,236,48, -5,79,0,0,83,123,211,21,42,9,52,59,210,140,180,1,124,12,185,31,68,185,52,21,86,216,200,24,221,250,38,20,15,152,122,38,164,83,0,0,170,150,75,8,100,217,121,24,228,204,171,34,84,141,97,10,208,14,152,59,168,134,23,16,38,190,145,58,217,103,174,38,48,217,0,0,134,138,178,2,223,60,177,9,143,151,254,60,235,126,178,45,211,95,203,52,137,25,60,4,126,125,85,44,211,166,202,38,249,110,0,0,14,207,143,31,22,52,238,61,172,111,74,60,121,255,219,22,214,17,52,42,122,27,209,48,169,91,211,34,21,78,40,31,88,125,0,0,89,148, -188,24,39,104,112,0,165,128,55,50,180,2,228,24,196,208,106,61,179,45,0,13,114,18,198,4,12,226,0,23,41,167,0,0,150,76,5,61,207,77,47,58,136,168,28,13,234,14,5,49,238,220,229,62,151,111,127,7,213,246,97,30,115,70,82,48,249,77,0,0,93,13,209,10,27,176,174,11,25,144,132,40,112,179,65,53,181,212,133,29,232,8,211,37,80,128,114,24,75,66,20,59,53,0,0,0,29,0,239,29,105,151,200,19,239,39,186,9,166,245,110,62,33,75,182,35,39,112,244,2,14,242,202,34,159,108,203,40,73,165,0,0,131,71,98,48,159,198,118,53,173,5, -151,44,152,138,7,5,235,86,148,37,98,59,12,51,244,189,108,22,182,65,158,30,155,121,0,0,203,212,46,5,151,199,187,22,160,197,158,0,207,190,55,21,201,110,46,19,13,102,47,2,63,18,205,62,129,54,204,35,121,126,0,0,98,148,187,20,30,152,197,21,18,122,243,57,255,198,213,28,177,87,240,50,123,39,85,42,65,48,200,26,147,40,49,51,61,210,0,0,52,8,99,19,239,131,206,55,127,6,172,61,24,74,252,24,132,8,129,12,234,90,122,46,213,58,120,20,84,12,128,40,79,34,0,0,114,34,122,4,223,28,241,52,92,247,80,10,176,147,164,24,61, -245,9,29,228,232,195,45,196,195,165,45,207,174,140,19,229,187,0,0,215,25,60,24,69,39,217,25,187,87,207,2,107,145,215,46,187,242,142,34,144,51,151,40,41,65,158,35,2,24,51,40,212,194,0,0,141,146,7,5,11,46,202,11,119,201,69,51,197,160,18,32,38,13,38,1,253,125,237,32,65,77,41,6,32,112,62,40,173,101,0,0,154,12,148,60,82,43,32,19,8,51,66,47,78,56,207,51,19,33,220,13,209,137,23,22,229,144,49,31,193,176,159,10,194,46,0,0,77,122,30,5,102,63,101,52,172,189,53,26,246,96,20,16,18,235,127,28,10,212,147,56,194, -132,150,55,140,55,26,41,29,139,0,0,235,62,104,29,127,185,195,41,58,19,211,8,40,206,186,13,62,243,184,4,66,73,217,43,177,202,206,40,230,227,92,26,198,175,0,0,9,69,205,48,172,114,138,7,201,253,221,30,73,213,234,2,87,22,156,35,40,255,113,22,195,43,117,34,116,219,101,8,44,0,0,0,147,66,111,55,30,126,128,40,158,19,197,19,89,45,94,58,16,46,40,11,220,60,35,47,33,145,48,3,205,167,214,30,85,210,0,0,10,116,130,18,137,30,198,54,241,165,5,36,55,14,218,18,227,31,210,10,173,27,188,32,38,1,127,2,121,213,208,44,135, -167,0,0,205,152,31,44,34,103,242,47,140,48,240,23,83,65,34,13,82,33,96,6,115,112,42,54,174,15,135,52,145,18,106,6,57,156,0,0,157,89,252,20,15,120,249,57,107,142,76,6,219,189,201,20,144,65,230,32,201,47,17,60,132,117,213,29,147,210,195,19,184,221,0,0,179,77,182,15,78,53,230,30,65,56,213,29,142,50,121,59,167,214,184,19,249,254,224,46,11,116,203,28,111,138,228,8,20,193,0,0,190,89,2,60,127,58,195,8,30,125,86,20,19,36,96,29,168,209,139,23,250,147,55,59,92,42,252,6,210,22,183,61,55,18,0,0,70,30,8,3,208, -96,123,59,161,158,85,20,21,99,136,20,58,113,52,38,100,176,112,54,130,64,34,55,105,12,254,18,91,108,0,0,112,205,251,11,224,114,126,52,46,166,34,44,154,224,51,52,65,120,228,43,56,143,225,17,35,251,66,45,73,82,220,4,5,203,0,0,75,205,77,6,177,107,185,50,77,18,28,17,102,245,49,12,12,69,10,49,42,151,25,28,86,75,222,10,195,153,21,42,233,225,0,0,44,31,4,59,122,137,45,52,146,178,22,10,171,102,52,17,127,146,119,37,108,102,13,49,122,27,83,28,21,81,165,2,43,86,0,0,60,215,173,43,248,219,97,1,208,183,100,42,64, -118,115,54,143,32,20,28,187,144,211,41,120,151,9,27,68,235,149,6,178,81,0,0,209,216,54,43,135,43,245,61,166,75,115,12,202,195,4,8,108,250,28,44,116,192,31,40,84,93,62,61,7,0,4,12,121,0,0,0,75,243,9,59,220,66,215,53,230,108,198,12,130,249,28,34,229,97,157,51,207,91,138,45,26,134,121,11,199,142,233,60,1,151,0,0,147,87,223,0,51,20,114,51,74,121,204,61,95,14,47,1,113,55,131,22,197,212,198,0,215,21,237,48,43,227,238,18,212,61,0,0,70,47,30,63,142,136,57,23,1,131,119,50,161,199,61,28,82,87,60,22,3,129,75, -22,69,196,108,38,39,75,7,45,54,160,0,0,73,179,255,30,165,137,199,28,79,31,11,63,179,160,56,32,6,141,176,30,30,169,218,7,223,215,179,22,250,0,104,36,191,195,0,0,8,234,76,12,14,228,98,51,219,33,234,32,131,46,214,18,101,82,70,0,208,84,132,41,244,6,197,40,147,234,182,62,133,106,0,0,243,244,98,24,150,179,119,6,106,27,114,61,208,146,198,9,180,48,98,62,35,5,207,36,49,213,89,6,185,46,129,17,182,0,0,0,229,89,169,32,132,224,132,40,197,76,29,57,162,78,82,56,145,187,6,14,118,160,124,1,222,248,253,18,116,199, -194,5,87,96,0,0,168,162,133,35,76,250,102,34,94,198,36,46,15,175,84,20,70,98,242,29,220,107,139,38,221,122,128,36,154,154,44,60,26,154,0,0,43,3,28,23,138,133,54,53,128,201,253,58,133,162,217,26,255,197,102,7,127,127,109,4,221,3,38,0,184,53,63,42,235,113,0,0,159,53,104,22,56,106,173,30,94,117,180,52,93,180,198,36,113,127,187,12,213,91,20,24,246,222,57,29,216,146,152,4,255,210,0,0,28,166,3,42,20,29,185,1,77,87,112,16,26,61,26,30,80,208,157,42,234,10,209,5,202,50,210,9,201,108,193,48,94,133,0,0,7,252, -93,6,171,186,241,55,101,73,228,23,168,211,189,12,211,78,251,2,109,254,47,15,84,127,193,1,124,177,75,23,216,13,0,0,6,215,50,31,32,41,48,0,139,103,160,6,29,41,51,6,6,162,191,21,194,104,74,3,21,31,191,63,172,174,26,18,228,60,0,0,228,217,127,60,223,216,220,2,244,137,30,22,243,144,85,52,237,6,73,9,196,26,65,63,142,40,133,55,184,106,35,16,117,231,0,0,251,211,28,57,237,50,208,54,134,230,155,50,101,255,140,10,74,235,68,8,62,134,12,56,2,175,127,35,211,15,69,49,204,17,0,0,134,13,22,21,233,90,220,36,42,71,211, -13,75,191,199,2,250,57,194,12,78,18,137,35,82,235,29,49,10,164,202,26,165,74,0,0,82,117,143,33,101,68,238,33,195,250,84,0,230,226,68,16,189,221,130,35,224,211,221,37,59,244,198,9,69,249,197,46,80,2,0,0,77,177,16,53,136,37,33,60,227,241,214,51,12,207,27,0,218,23,216,41,127,221,247,53,66,35,8,40,239,38,63,12,25,115,0,0,18,93,114,31,78,250,68,23,80,71,95,11,247,174,144,17,217,191,47,2,40,56,231,40,180,58,253,39,209,44,34,39,116,26,0,0,228,86,172,35,52,69,217,4,112,170,13,25,98,26,130,28,96,143,61,47, -10,215,249,34,69,207,226,0,251,92,101,52,145,126,0,0,88,228,250,41,148,35,65,24,253,151,236,38,157,16,151,2,139,50,123,59,119,169,85,52,9,193,24,2,62,248,22,26,80,199,0,0,152,181,87,23,101,16,90,0,43,26,149,53,12,148,114,23,10,180,199,50,25,83,208,11,181,95,224,33,228,51,126,37,215,234,0,0,102,66,185,44,251,92,154,6,43,241,77,61,233,62,188,51,128,24,163,13,70,145,230,16,33,20,65,8,232,136,227,55,118,165,0,0,200,142,178,33,107,132,47,58,62,159,77,17,253,41,132,11,67,44,216,12,150,191,94,46,146,44, -11,36,217,57,200,47,166,64,0,0,193,214,158,13,99,173,43,26,107,61,89,61,240,22,157,19,194,14,221,30,193,29,6,63,11,232,83,15,221,114,219,12,40,3,0,0,238,254,250,56,155,175,27,59,173,148,180,28,201,55,253,22,38,140,124,13,136,14,101,53,70,140,242,25,191,4,14,38,168,113,0,0,58,152,53,50,52,106,106,6,41,235,188,19,192,13,132,34,227,49,21,62,195,181,73,14,198,77,197,17,228,162,171,19,79,206,0,0,207,222,60,13,100,172,245,51,174,64,247,43,163,72,25,27,82,67,117,48,121,146,128,55,234,179,187,15,228,240, -92,62,201,243,0,0,201,230,176,21,153,173,106,27,154,200,228,6,222,115,254,23,219,189,188,56,183,205,62,10,142,39,34,6,230,82,233,47,190,77,0,0,37,204,178,30,85,225,41,37,174,239,4,5,175,108,196,36,88,243,41,34,184,185,137,41,69,223,174,19,36,15,236,57,254,16,0,0,149,114,133,37,70,104,128,19,22,240,51,52,192,31,57,50,105,32,161,28,40,63,70,56,178,24,194,5,189,255,2,9,42,164,0,0,193,185,126,10,251,223,205,26,85,57,25,21,52,139,112,40,39,196,164,29,147,172,200,26,122,86,212,5,64,152,252,44,160,58,0, -0,152,192,205,47,85,253,131,8,50,128,70,46,218,3,184,2,85,193,153,4,3,27,126,60,167,103,34,50,190,229,203,10,225,52,0,0,226,116,116,42,121,107,44,19,102,63,136,25,60,76,212,55,4,219,114,57,5,33,47,19,151,45,50,29,237,117,183,48,74,166,0,0,146,59,23,15,122,173,91,51,17,118,251,41,5,189,156,31,59,104,101,13,61,134,104,12,190,41,31,57,110,54,144,52,244,16,0,0,194,70,49,35,181,1,8,36,124,219,106,8,69,167,221,46,144,186,8,57,140,150,150,44,17,210,58,53,69,66,101,11,14,133,0,0,88,73,216,40,102,71,191,57, -174,92,204,10,91,172,119,4,106,134,204,0,181,93,110,6,159,116,126,39,109,218,2,58,70,232,0,0,159,207,130,56,237,145,17,3,100,26,12,30,156,205,104,20,173,111,183,24,30,65,100,47,29,84,226,7,83,34,63,46,156,162,0,0,113,173,88,62,38,226,216,61,8,162,163,57,115,125,52,12,187,56,140,30,167,88,250,23,160,48,62,44,55,10,227,41,120,119,0,0,172,67,159,61,7,255,68,45,99,197,74,50,127,4,225,44,135,0,88,63,203,75,56,38,112,255,34,27,105,173,102,27,98,52,0,0,105,200,25,51,184,186,241,61,2,39,235,33,93,87,126, -42,24,220,172,12,191,8,228,32,1,141,252,51,5,102,23,1,24,48,0,0,240,86,184,18,39,219,49,48,191,167,217,35,146,50,161,10,202,59,46,34,53,200,144,24,134,111,123,59,64,9,94,49,95,172,0,0,181,41,237,37,190,97,154,49,180,209,173,18,28,216,194,32,245,133,200,35,105,110,159,45,58,52,239,23,185,135,109,32,40,50,0,0,210,90,209,60,185,73,60,61,78,96,231,14,229,170,235,32,202,225,49,21,208,119,198,2,17,235,68,3,232,5,161,0,119,22,0,0,0,97,201,6,30,16,234,47,99,142,156,46,169,70,192,24,161,204,219,51,183,108, -118,15,180,255,185,49,62,176,206,17,56,63,0,0,7,71,98,50,111,176,138,7,207,27,95,55,2,31,199,21,102,229,156,7,188,24,17,19,83,82,57,0,117,125,21,39,198,112,0,0,172,210,34,61,27,187,49,13,2,206,170,28,155,132,127,55,16,47,223,5,94,130,3,15,180,220,118,58,73,127,241,4,129,40,0,0,104,162,66,15,126,213,122,32,208,143,140,20,133,18,245,48,221,55,97,23,50,152,220,29,32,143,92,60,62,86,192,58,167,161,0,0,168,142,95,36,116,3,234,18,13,144,210,36,229,56,146,28,209,229,159,17,92,87,54,61,83,165,162,35,17,50, -128,40,99,249,0,0,235,153,188,25,193,126,21,47,36,8,182,24,103,141,60,46,139,32,39,52,127,192,136,28,59,10,60,56,31,163,9,37,133,156,0,0,21,163,6,38,196,32,106,56,217,58,150,38,188,28,152,28,64,126,9,14,100,169,44,54,152,127,154,13,220,63,147,8,217,165,0,0,209,104,59,30,214,76,88,13,157,124,26,17,31,77,67,19,237,233,13,24,94,175,26,12,67,179,165,13,200,14,192,34,50,135,0,0,147,20,35,6,80,237,109,51,105,212,196,12,195,160,70,16,150,164,230,37,3,116,144,19,235,4,54,60,220,134,11,38,254,241,0,0,193, -72,136,53,153,102,170,37,1,13,255,37,27,205,254,28,241,211,153,61,125,129,240,52,22,194,221,36,102,187,122,6,32,46,0,0,172,3,217,6,112,106,123,2,203,229,215,26,57,157,88,62,213,46,253,58,57,76,127,10,55,70,132,58,141,185,87,37,40,9,0,0,31,9,205,27,77,58,96,20,252,131,141,10,234,187,73,15,172,238,149,58,36,76,40,30,123,130,42,52,79,15,64,8,86,194,0,0,57,184,116,56,213,161,68,4,24,180,210,19,229,108,69,16,190,174,182,48,200,126,195,55,83,128,90,30,56,240,7,46,3,62,0,0,186,148,5,60,89,57,7,3,218,184, -181,26,63,124,113,57,125,102,143,25,92,29,152,61,68,44,244,7,252,247,88,56,58,209,0,0,19,165,87,3,154,227,253,40,243,35,48,27,209,68,111,20,241,197,34,41,168,14,138,62,98,205,146,4,189,232,45,48,98,230,0,0,126,208,23,32,114,128,168,36,145,216,56,21,137,53,215,0,216,25,164,33,132,34,136,43,93,48,82,36,132,57,79,6,11,171,0,0,66,210,55,31,191,223,87,38,4,75,193,57,129,41,251,39,194,125,88,35,47,31,139,33,67,184,108,15,83,114,44,32,191,64,0,0,136,80,64,38,230,9,118,52,131,85,211,43,144,174,135,12,116, -18,254,38,108,108,250,15,245,4,175,42,21,118,77,55,121,181,0,0,88,53,90,25,145,205,202,43,43,127,74,35,120,225,199,1,172,246,89,27,227,4,94,62,6,8,167,28,7,216,165,63,20,61,0,0,76,223,67,36,177,206,182,26,124,114,29,60,81,184,40,56,130,20,110,53,111,199,164,38,242,248,30,40,17,186,117,47,198,22,0,0,36,252,177,2,182,214,167,55,14,87,247,35,31,7,54,10,37,101,72,18,178,52,177,6,204,81,82,38,11,58,80,41,111,221,0,0,202,116,155,14,24,113,12,41,4,35,50,23,251,154,55,4,236,119,126,37,197,175,199,27,54,254, -134,49,116,172,223,10,230,103,0,0,2,142,208,61,100,69,170,7,136,2,223,26,255,237,81,33,16,128,30,61,168,102,82,26,248,128,215,21,121,11,106,11,250,19,0,0,16,52,176,60,112,7,85,41,125,185,66,26,198,238,43,17,230,199,50,52,174,129,88,13,19,35,167,29,85,17,44,14,99,19,0,0,26,228,78,20,230,234,140,48,106,154,214,55,78,183,213,38,135,130,130,6,203,217,66,48,247,67,164,48,241,116,20,18,108,208,0,0,111,94,41,11,166,19,126,60,82,226,46,22,24,13,225,30,155,145,48,54,211,83,179,2,187,219,10,13,97,1,83,63,21, -88,0,0,81,39,216,35,69,157,171,30,82,84,211,58,65,42,109,17,86,133,178,35,131,206,147,1,153,147,16,27,27,251,188,63,208,133,0,0,98,249,177,14,137,222,8,11,88,49,115,7,90,122,212,33,62,102,245,44,96,185,37,53,41,190,192,56,232,4,33,25,3,31,0,0,243,76,222,44,135,65,85,38,171,102,160,56,81,77,57,16,147,231,154,29,69,155,180,48,231,59,44,2,69,176,210,42,77,56,0,0,102,5,45,37,200,90,30,31,59,167,27,53,229,140,194,16,31,240,198,52,138,182,181,19,251,59,164,28,110,52,111,49,227,214,0,0,194,56,82,30,72,250, -188,34,185,184,236,0,14,215,87,13,64,72,237,2,58,45,132,5,27,164,90,1,245,173,3,59,240,20,0,0,34,121,240,18,30,141,26,58,214,57,73,48,0,54,0,23,210,127,116,2,225,248,28,63,33,9,216,53,32,117,79,53,18,171,0,0,77,233,67,21,191,75,141,61,136,225,152,47,213,169,192,4,221,218,13,26,41,158,209,48,65,236,135,2,11,222,238,60,66,235,0,0,137,77,146,5,145,119,86,1,36,212,214,32,121,163,17,54,76,119,251,13,191,92,117,3,154,220,146,29,201,211,65,27,74,35,0,0,237,170,25,62,213,150,147,12,112,50,103,6,163,55,235, -38,69,32,169,6,184,189,0,59,158,154,13,2,90,148,50,14,241,28,0,0,14,64,47,41,117,169,219,4,188,255,119,60,251,227,187,39,71,23,222,45,173,153,202,13,244,101,56,6,199,197,188,54,255,214,0,0,57,170,168,54,126,58,176,61,85,172,143,39,210,222,152,41,55,217,144,25,18,90,130,22,135,44,65,13,208,151,175,33,134,181,0,0,31,60,73,43,116,77,30,63,184,71,179,45,57,230,107,47,171,29,169,0,83,81,227,17,73,193,194,56,49,201,80,53,50,86,0,0,197,76,59,48,142,175,71,58,46,124,199,33,150,110,12,10,87,2,168,51,159,63, -241,22,123,182,194,60,226,26,108,39,193,95,0,0,40,124,181,37,225,126,206,14,74,236,135,0,243,64,189,29,146,244,94,58,104,62,78,8,238,102,124,12,38,59,48,33,142,236,0,0,181,140,179,12,245,21,46,45,139,148,136,19,211,247,223,2,225,27,234,62,244,3,41,42,235,157,40,30,187,80,195,45,143,184,0,0,215,243,101,25,89,157,254,30,25,199,248,58,137,132,207,19,77,226,168,53,44,101,238,18,3,6,40,35,186,81,171,13,199,214,0,0,126,8,38,5,9,18,80,61,8,3,162,45,32,98,219,62,253,93,184,24,94,16,216,38,28,124,233,44,251, -165,115,3,43,255,0,0,7,153,194,48,7,120,84,50,178,206,226,16,238,91,251,45,199,54,121,16,83,113,19,19,175,136,161,11,73,189,255,4,61,73,0,0,249,129,214,57,249,83,65,22,252,185,254,8,235,187,131,51,102,176,148,44,128,151,252,31,139,136,48,50,215,157,124,63,69,199,0,0,71,18,187,59,13,205,197,0,118,92,212,39,113,205,244,54,140,103,24,40,195,49,229,4,167,120,94,30,174,189,188,8,2,89,0,0,163,14,205,53,180,59,19,56,21,72,172,12,8,58,30,17,179,242,231,50,217,122,121,22,122,178,80,16,93,234,124,30,178,171, -0,0,206,123,48,60,205,196,36,28,100,59,47,32,103,65,218,37,124,212,142,7,12,48,248,18,251,217,112,57,197,239,14,4,238,93,0,0,62,238,201,27,252,188,184,48,197,130,115,62,88,106,232,39,234,17,237,39,9,157,170,43,127,130,130,6,127,214,66,5,129,63,0,0,6,174,154,25,49,108,171,51,3,22,168,13,63,183,236,8,118,98,86,57,17,207,250,6,103,212,130,58,111,63,154,34,200,25,0,0,7,160,228,56,235,251,198,5,182,88,179,11,194,179,59,59,21,236,199,22,169,206,232,18,89,105,222,2,2,116,203,4,248,92,0,0,131,184,104,16, -66,194,143,57,140,254,199,57,177,229,27,37,200,246,61,12,18,98,5,53,74,223,160,31,88,3,151,59,90,180,0,0,167,212,194,38,236,249,91,37,16,251,255,60,206,228,219,48,27,210,78,0,241,92,206,56,83,70,73,58,82,67,147,63,213,182,0,0,113,99,232,58,248,57,55,6,129,204,227,53,155,147,223,22,116,142,253,63,119,130,228,51,223,20,108,61,174,78,232,28,243,71,0,0,51,221,102,60,139,216,76,2,197,109,199,29,252,35,239,35,234,34,176,41,0,84,108,44,107,112,136,53,179,25,240,46,200,97,0,0,250,11,241,54,206,167,238,14, -202,200,32,40,176,186,65,20,106,251,211,5,230,82,102,26,70,52,112,15,149,231,136,39,89,147,0,0,248,47,107,29,51,223,22,32,169,143,108,40,92,176,205,24,135,241,189,3,251,220,212,39,124,24,133,39,9,93,233,10,227,148,0,0,62,175,225,44,84,21,82,55,58,225,191,38,148,16,188,14,179,140,158,45,152,33,146,7,47,25,78,32,246,208,34,17,27,13,0,0,65,226,86,56,179,120,57,32,135,210,109,13,35,133,123,60,87,43,33,27,192,152,203,10,237,169,14,8,122,44,249,46,127,130,0,0,236,147,194,46,46,218,22,24,109,22,3,41,97, -140,233,61,127,104,18,29,244,25,203,59,27,183,176,39,28,143,36,39,15,198,0,0,167,15,184,59,44,23,18,13,134,56,65,48,237,154,246,41,58,159,129,32,76,175,129,6,13,188,47,12,194,216,199,56,87,8,0,0,45,107,54,9,124,132,96,54,171,22,112,13,15,193,141,11,23,71,113,11,119,116,50,31,45,9,114,1,184,142,208,36,67,246,0,0,99,14,199,9,232,176,64,23,111,73,61,53,57,222,226,46,156,46,103,10,217,85,25,23,84,67,0,22,175,149,58,51,170,40,0,0,78,218,87,48,11,226,192,39,139,30,218,4,145,115,22,63,245,183,235,40,29, -159,89,34,122,86,225,32,6,190,139,12,105,43,0,0,181,116,230,51,189,20,119,0,198,170,96,48,57,167,61,54,146,79,138,43,243,38,203,54,93,20,102,26,21,104,137,45,243,162,0,0,65,121,147,14,56,50,78,2,59,165,63,3,95,140,190,8,146,75,124,42,204,67,42,17,0,232,138,6,83,88,86,40,14,98,0,0,86,176,30,25,199,88,128,29,108,56,253,44,227,246,187,0,160,245,21,53,143,26,215,34,217,49,146,37,171,122,242,32,79,60,0,0,171,236,92,32,246,36,150,16,119,184,246,28,32,81,173,32,25,128,120,50,14,207,149,53,58,163,182,40, -82,212,1,36,71,148,0,0,169,223,134,61,110,127,24,36,113,58,153,27,2,41,45,14,220,170,59,16,160,15,120,48,41,78,125,22,166,34,74,56,248,175,0,0,129,38,209,1,219,240,64,28,112,156,159,1,81,106,91,4,249,244,83,15,127,168,174,15,61,253,195,55,77,200,236,18,139,141,0,0,193,169,155,24,174,205,201,35,226,56,211,9,104,41,223,3,228,121,229,14,187,138,9,22,132,62,11,0,55,74,17,30,251,211,0,0,103,178,81,43,127,35,110,24,0,222,26,1,112,117,59,7,52,230,15,55,98,93,129,50,167,124,78,43,233,59,13,53,148,248,0,0, -9,185,43,15,116,176,165,54,153,217,152,53,20,159,64,36,99,127,125,24,228,32,166,28,244,143,168,26,178,130,3,12,201,78,0,0,113,64,207,36,254,224,40,34,123,130,195,26,131,160,133,11,213,186,73,12,97,20,113,3,200,197,77,48,134,175,65,40,43,120,0,0,179,226,32,33,232,99,237,60,167,154,127,52,159,115,63,22,122,33,229,38,51,141,43,57,123,174,219,27,212,135,124,18,166,234,0,0,61,217,90,58,22,76,233,17,157,229,247,19,124,89,174,41,1,90,170,57,97,226,3,42,105,172,3,59,238,86,123,30,50,190,0,0,13,7,46,63,232, -244,15,22,143,169,166,18,49,199,173,42,41,226,71,16,225,14,199,28,72,255,171,52,11,65,122,41,114,75,0,0,128,215,109,41,187,160,46,17,222,195,72,41,116,119,25,45,176,16,60,15,180,205,238,29,2,246,28,46,90,135,83,7,158,89,0,0,28,89,2,10,97,255,57,39,30,90,18,5,150,101,82,61,62,97,253,33,215,250,254,26,90,40,142,28,78,25,255,36,252,169,0,0,220,194,190,41,189,119,43,36,55,37,247,60,87,16,35,34,202,229,101,17,106,232,5,19,232,115,113,56,20,119,206,57,44,156,0,0,89,139,150,45,56,184,1,4,225,194,187,60, -132,235,162,40,9,119,2,27,130,4,235,53,167,166,240,57,155,6,95,0,64,201,0,0,251,114,229,13,2,217,245,59,143,156,12,57,144,45,11,33,226,44,116,53,150,254,134,34,59,1,98,56,38,3,148,8,217,57,0,0,50,51,107,50,213,204,28,10,106,222,229,62,28,52,226,0,49,224,248,11,220,151,78,30,198,78,2,16,187,95,231,46,132,31,0,0,46,213,232,20,140,162,16,21,37,58,220,54,80,139,51,47,194,240,237,57,214,253,9,31,84,194,236,41,242,202,65,27,114,238,0,0,142,169,239,13,43,149,106,51,149,121,194,26,4,26,17,18,114,199,233, -17,230,236,85,32,202,6,205,31,81,66,34,56,19,15,0,0,103,103,40,62,166,221,41,2,220,204,234,44,133,23,156,31,40,219,98,51,158,194,226,15,94,3,197,39,147,93,124,8,213,173,0,0,107,155,245,41,239,0,135,23,250,226,136,24,240,24,227,44,233,211,38,24,181,116,40,10,55,219,199,30,119,84,105,36,225,221,0,0,16,20,203,38,164,88,182,26,207,254,84,49,249,46,206,21,139,78,225,18,113,88,95,29,10,190,92,39,160,0,222,62,43,91,0,0,153,182,198,9,247,87,49,26,27,135,70,62,90,205,213,27,168,130,22,52,94,254,94,27,161, -165,247,54,96,187,75,0,171,95,0,0,170,195,198,1,75,133,204,5,155,81,131,40,250,95,196,42,144,123,47,22,195,68,208,46,158,78,20,61,240,40,156,62,155,45,0,0,79,210,52,26,183,140,141,56,1,116,19,26,50,60,182,45,65,229,46,52,179,183,125,7,57,217,105,49,115,241,80,11,164,228,0,0,20,148,186,30,199,196,253,41,19,79,142,13,234,183,187,33,232,76,211,10,238,51,103,50,111,82,115,28,180,197,185,36,159,77,0,0,104,12,234,59,188,66,16,50,181,146,179,55,217,72,192,16,9,175,111,57,52,58,242,38,148,36,58,42,85,56, -141,37,65,62,0,0,182,237,69,26,220,191,237,50,171,161,205,3,140,81,70,40,47,6,147,6,220,248,47,15,55,127,31,50,146,100,103,49,35,1,0,0,215,36,152,19,242,72,215,61,122,137,201,17,13,147,237,45,110,87,11,63,189,152,143,18,237,142,80,23,87,81,61,14,148,141,0,0,159,72,102,19,34,61,1,40,216,99,176,38,12,174,120,46,143,111,239,54,106,76,47,24,202,162,194,38,251,211,28,56,97,50,0,0,222,19,215,24,106,28,32,57,8,98,142,2,221,190,48,24,147,67,69,37,191,168,68,42,212,32,68,37,59,86,49,9,37,183,0,0,233,80,131, -27,150,148,255,27,183,252,165,4,249,155,180,32,4,21,148,22,167,11,70,11,4,81,228,3,138,162,230,44,81,76,0,0,180,44,59,62,79,10,27,51,2,4,33,55,252,214,124,18,48,158,20,33,4,142,219,49,173,25,37,17,91,136,214,23,228,61,0,0,47,176,126,48,176,206,120,24,207,68,112,40,150,57,138,15,130,6,145,60,165,146,42,2,14,197,221,42,23,16,102,33,42,186,0,0,191,229,228,44,189,217,209,8,23,91,0,9,168,161,242,25,155,174,6,9,210,141,243,15,30,124,232,27,86,162,113,60,17,133,0,0,8,156,120,1,19,165,36,63,98,82,54,5,111, -34,30,42,45,35,0,42,26,251,125,55,193,116,72,13,111,228,115,61,223,236,0,0,171,88,50,61,40,154,213,6,195,77,193,43,98,160,144,52,87,89,171,20,184,203,113,40,207,34,2,54,115,160,75,1,90,140,0,0,143,15,45,2,76,33,248,21,222,74,148,13,112,62,186,54,70,194,8,12,65,30,3,42,121,16,218,59,16,237,210,54,17,104,0,0,238,188,145,63,42,168,48,22,65,216,192,32,199,99,199,51,245,55,241,43,85,177,243,24,220,11,86,19,175,183,5,62,247,206,0,0,51,107,150,1,126,106,211,46,198,106,47,23,168,192,146,15,166,95,36,29,0, -231,204,14,70,18,112,8,221,216,32,19,231,103,0,0,25,191,0,3,117,238,92,28,148,164,254,8,170,93,77,45,146,107,43,53,172,182,62,24,65,149,221,11,131,205,251,3,200,30,0,0,253,206,7,1,115,112,115,28,182,7,90,41,216,223,185,17,1,94,191,43,158,98,37,41,243,210,64,19,173,213,77,58,239,174,0,0,249,161,254,18,241,46,95,44,148,43,69,0,35,212,194,63,196,49,101,16,156,173,118,63,188,131,46,31,116,149,2,34,220,166,0,0,233,69,195,59,145,83,112,44,99,126,143,38,223,118,226,30,5,80,188,44,90,132,14,26,56,48,124, -54,112,31,21,42,241,126,0,0,179,201,214,6,252,48,80,35,124,99,101,8,29,58,19,27,140,186,129,36,226,113,138,48,189,146,89,36,144,250,79,42,107,254,0,0,251,189,72,41,62,226,177,48,0,155,46,28,193,111,60,32,217,86,59,1,21,205,6,45,107,43,135,57,20,208,53,6,233,126,0,0,81,81,249,12,204,65,188,8,68,182,196,2,145,27,32,25,185,209,222,8,112,11,35,3,2,251,139,9,191,81,188,56,213,21,0,0,242,236,248,47,48,31,168,32,148,15,140,29,95,238,19,8,187,249,35,16,226,37,132,3,249,199,78,61,87,100,140,11,183,165,0,0, -88,86,106,41,228,66,224,53,67,86,246,30,144,148,44,5,56,190,41,46,158,36,128,31,140,173,71,4,162,149,28,58,192,132,0,0,209,128,27,24,111,202,89,54,34,253,241,52,7,166,134,41,211,94,114,19,25,100,140,31,8,74,44,2,88,48,224,32,89,38,0,0,15,106,220,20,34,215,110,29,83,87,225,47,80,100,208,16,116,194,119,0,139,158,147,9,101,213,49,55,164,198,113,44,214,254,0,0,224,199,111,23,182,92,227,50,156,64,252,35,194,100,53,29,19,35,174,19,147,107,96,36,71,168,240,63,63,172,249,42,226,141,0,0,85,147,226,24,196, -23,226,44,109,216,32,23,206,164,35,7,47,216,185,35,0,129,225,59,252,112,188,60,180,100,118,19,106,42,0,0,114,40,204,53,62,128,79,1,192,118,76,12,153,142,22,36,254,13,249,40,137,7,114,63,96,199,224,39,18,159,238,55,119,134,0,0,191,218,72,33,63,162,126,62,177,142,215,9,77,174,116,43,193,53,231,58,215,8,59,25,151,109,84,39,36,155,192,36,45,228,0,0,97,19,30,1,90,29,203,29,157,235,119,30,6,92,157,28,50,48,133,51,247,175,51,14,139,13,75,24,139,27,139,33,19,100,0,0,190,66,102,54,160,100,109,55,137,168,139, -21,95,28,36,13,206,139,250,13,160,209,43,0,27,249,194,48,25,1,227,29,106,20,0,0,208,239,131,61,32,93,202,2,29,237,229,55,75,199,165,42,10,135,178,20,231,159,96,26,214,173,40,0,213,12,59,56,24,179,0,0,67,84,49,39,224,28,78,54,153,114,134,46,82,245,110,30,61,161,66,33,130,96,38,50,66,255,53,9,152,1,1,27,105,252,0,0,96,137,210,23,45,88,67,18,23,27,189,9,132,33,253,31,72,181,119,22,90,55,135,3,191,43,137,53,14,254,250,9,206,224,0,0,235,180,253,22,112,189,236,6,157,167,230,34,113,94,247,40,143,146,176, -62,138,213,168,21,174,209,42,63,211,127,136,60,74,151,0,0,132,244,246,41,126,15,39,16,72,35,252,63,142,202,21,7,17,237,144,0,11,244,144,7,77,166,60,0,212,84,31,14,82,85,0,0,227,238,90,29,109,43,65,14,55,129,140,37,217,240,18,10,232,197,112,18,154,233,108,8,145,176,152,35,119,210,102,45,170,91,0,0,23,151,246,48,237,107,74,11,216,238,49,61,106,39,119,23,33,247,218,63,135,25,2,40,229,86,232,55,3,95,216,31,87,138,0,0,144,104,114,53,19,121,108,20,88,209,55,8,171,127,9,36,229,14,10,17,254,58,191,12,16, -208,67,28,210,250,233,23,104,251,0,0,58,120,53,56,206,163,186,1,38,155,231,16,186,196,178,41,79,9,186,36,97,182,133,50,105,232,226,37,99,178,200,55,80,215,0,0,138,164,188,40,78,252,146,17,245,98,223,3,58,125,53,45,120,29,247,7,10,71,238,9,171,160,149,41,120,150,253,35,229,93,0,0,205,65,253,18,3,58,229,33,149,170,248,32,19,103,111,57,63,132,60,45,148,240,136,41],"i8",4,t.L+20480); -D([9,83,181,25,13,96,207,14,90,104,0,0,182,99,239,37,19,13,142,55,235,130,177,49,156,5,52,45,90,200,193,15,237,104,255,45,241,250,139,33,181,122,115,9,24,111,0,0,243,85,198,5,61,27,33,11,65,69,249,39,0,153,86,34,60,85,52,51,224,53,129,16,143,185,17,25,100,117,159,31,9,255,0,0,59,63,166,52,183,31,65,45,39,151,143,23,102,192,14,8,131,101,199,54,121,125,69,28,88,107,55,42,216,125,37,46,236,197,0,0,36,80,0,5,26,221,252,20,91,238,11,35,151,123,217,58,139,236,51,18,254,99,1,41,78,55,31,8,94,6,70,9,37,34, -0,0,249,238,128,49,228,161,218,53,118,151,139,34,38,136,4,0,141,18,123,32,106,236,58,43,227,7,95,46,72,135,61,48,80,250,0,0,17,40,79,63,244,53,54,35,179,19,162,23,233,164,12,26,94,138,166,1,138,28,74,51,114,155,186,62,229,136,164,49,132,107,0,0,18,94,218,17,206,56,184,7,151,178,172,28,5,144,130,49,169,182,162,28,232,228,167,12,218,188,49,30,222,16,143,11,80,247,0,0,235,244,133,3,122,113,46,41,199,235,92,50,189,203,180,33,123,4,114,22,15,23,37,28,153,213,175,15,159,117,123,61,87,60,0,0,5,209,183,16, -196,76,210,1,242,201,87,14,229,18,151,50,244,179,85,52,56,137,217,19,58,42,134,37,235,96,62,30,254,18,0,0,96,74,121,31,238,27,43,22,132,11,233,46,117,153,56,59,29,119,203,39,102,134,106,45,134,119,207,43,53,206,104,60,98,32,0,0,5,93,12,30,206,96,135,24,255,218,114,37,42,20,155,3,72,26,75,8,160,64,236,18,140,213,115,52,247,209,196,48,170,118,0,0,62,230,236,17,221,102,152,21,53,238,230,21,192,115,137,4,75,95,98,2,200,32,203,60,190,250,14,7,87,195,187,29,85,239,0,0,134,192,83,60,23,210,155,56,201,174, -161,9,39,13,87,45,198,4,129,40,23,197,48,24,126,200,204,5,151,239,150,63,99,166,0,0,1,98,1,37,202,64,113,26,14,252,148,57,92,41,179,7,153,195,61,2,38,178,64,44,209,245,251,17,200,218,95,38,65,181,0,0,116,133,117,11,181,7,96,43,233,198,249,52,80,162,153,12,216,243,189,34,235,9,132,50,183,37,216,44,129,128,158,20,149,222,0,0,42,35,103,59,243,199,247,45,180,222,162,21,69,65,168,57,186,215,158,22,252,17,114,7,226,228,20,61,36,171,21,56,211,76,0,0,79,71,133,61,175,226,230,29,141,102,52,22,226,138,18,19, -137,234,90,56,17,249,50,55,254,219,173,50,180,25,56,47,166,141,0,0,247,78,123,61,244,113,126,63,165,215,189,29,193,100,49,7,11,241,255,29,28,116,125,55,79,248,79,45,199,188,26,27,252,19,0,0,234,66,208,61,89,9,117,45,6,253,234,24,145,169,137,62,235,190,147,60,140,39,153,53,27,155,163,59,236,243,49,43,41,115,0,0,161,148,92,47,176,63,163,54,10,79,171,31,199,220,37,18,24,238,104,43,62,229,57,33,146,72,241,54,109,80,77,18,114,146,0,0,194,126,6,31,173,76,79,57,32,82,186,27,117,173,34,10,26,66,232,8,246, -173,253,22,26,27,161,33,156,50,116,24,29,218,0,0,241,54,216,26,60,232,126,21,166,72,155,39,116,38,206,41,102,41,30,9,135,133,217,1,156,199,6,19,38,159,86,61,87,129,0,0,219,168,149,58,203,220,97,23,97,111,211,57,17,49,176,15,184,35,23,27,100,26,153,37,158,65,208,61,192,24,105,3,233,227,0,0,249,28,13,27,252,61,91,0,209,211,132,9,243,229,123,44,251,106,231,2,28,67,170,62,0,187,120,1,91,1,240,14,229,251,0,0,20,226,46,17,144,245,171,30,1,84,49,25,229,165,147,10,120,28,192,0,87,127,67,25,139,90,119,61, -184,204,177,63,79,159,0,0,122,243,133,16,137,8,209,59,131,2,136,60,194,164,109,6,151,157,198,53,245,11,154,37,14,230,242,34,99,76,184,56,156,99,0,0,165,160,97,31,20,5,218,34,239,227,20,60,108,248,148,4,75,44,11,4,125,144,130,6,23,27,172,52,68,80,139,24,31,67,0,0,153,248,206,56,249,223,222,26,36,119,101,21,13,129,170,46,65,114,170,35,92,70,153,55,214,246,56,36,234,249,159,12,152,162,0,0,3,133,116,39,85,159,9,43,124,142,50,49,220,145,131,27,14,172,18,10,126,206,187,24,203,134,251,56,57,123,183,46,61, -153,0,0,226,206,176,62,77,216,156,46,73,170,173,56,166,253,30,62,23,26,245,33,30,30,225,61,133,183,238,30,90,161,123,42,33,165,0,0,128,61,210,38,214,137,168,55,120,212,116,36,201,71,244,2,225,192,98,9,228,114,12,37,51,90,234,21,171,129,174,30,241,117,0,0,126,213,13,40,192,22,170,33,9,89,234,52,110,251,254,11,55,146,98,27,198,47,244,49,127,12,168,57,88,133,191,24,122,160,0,0,19,52,173,33,181,109,174,56,74,104,125,50,0,1,112,46,141,122,123,56,114,33,125,37,110,10,74,31,118,132,87,21,120,102,0,0,114, -166,188,62,129,64,32,9,1,102,198,45,78,69,139,51,166,158,223,11,159,100,155,9,37,105,100,15,158,120,143,54,13,81,0,0,99,133,204,6,108,189,2,48,170,30,16,62,255,214,55,9,146,136,54,22,6,246,10,50,218,138,116,39,54,139,141,18,220,235,0,0,250,204,148,35,58,239,197,38,36,249,4,18,146,228,1,49,190,7,79,29,179,121,141,59,177,249,53,45,21,58,81,12,154,101,0,0,19,78,6,13,132,193,206,41,98,224,241,6,17,120,71,12,21,102,65,61,163,99,254,23,33,7,105,48,37,195,191,32,226,168,0,0,12,204,244,17,196,28,223,59,108, -189,214,13,148,143,230,25,139,136,21,37,108,241,252,45,191,154,192,1,110,227,86,13,151,127,0,0,181,121,57,58,194,102,134,10,226,41,232,39,121,227,35,10,186,80,14,36,123,44,252,13,127,50,38,30,107,115,241,1,34,174,0,0,111,250,80,4,154,53,207,35,150,136,79,61,77,223,30,42,252,96,112,45,142,20,73,50,212,26,247,57,1,67,148,63,145,234,0,0,36,168,252,14,64,100,64,16,174,79,22,34,250,19,131,47,224,97,84,24,25,64,80,49,206,89,206,42,92,43,67,59,141,203,0,0,97,115,34,15,22,244,2,5,47,116,49,57,241,247,71, -43,150,196,203,44,232,33,177,5,179,133,140,24,3,221,35,0,165,51,0,0,39,211,203,59,104,211,70,16,233,174,74,30,136,20,130,19,176,214,110,39,95,3,36,37,142,112,54,24,188,98,202,14,197,176,0,0,54,228,123,45,40,241,90,24,241,160,54,6,29,131,136,10,216,175,178,38,109,128,169,61,56,22,234,23,239,7,208,37,42,238,0,0,161,54,184,23,142,237,187,57,125,239,121,54,253,23,144,1,200,38,245,55,57,187,24,34,77,13,146,27,167,204,207,41,107,111,0,0,132,43,131,6,236,203,247,54,52,249,31,14,162,20,67,38,216,192,233, -62,22,144,226,2,219,227,24,60,215,255,133,34,119,220,0,0,222,158,179,30,130,208,184,43,66,45,97,48,181,12,32,2,49,96,67,2,132,159,209,63,188,75,175,34,208,113,159,6,71,125,0,0,126,96,246,43,82,54,111,50,208,143,42,2,71,223,115,37,119,250,134,60,191,199,136,32,123,80,86,40,233,124,198,30,74,0,0,0,193,177,94,22,137,39,181,21,170,197,229,26,243,89,93,51,127,150,240,2,102,12,243,3,7,199,250,51,109,254,88,20,2,240,0,0,224,42,222,45,17,92,159,54,87,30,209,44,53,215,191,29,133,237,175,38,104,151,210,26, -198,244,13,18,15,34,122,42,78,5,0,0,100,44,195,26,79,66,205,51,132,191,228,10,251,128,191,13,14,94,113,7,61,84,58,1,247,160,58,18,123,0,0,5,18,172,0,0,103,168,177,30,235,182,74,32,152,8,63,37,150,78,151,22,237,163,153,4,204,85,218,2,135,241,186,56,12,235,50,47,142,206,0,0,124,73,25,3,122,11,206,11,2,140,80,18,148,126,108,22,93,177,202,19,164,185,149,39,211,114,88,40,104,114,238,20,74,23,0,0,115,250,154,7,176,78,104,15,56,84,152,11,99,135,206,26,100,230,249,7,177,124,85,16,123,101,193,9,255,234,13, -55,201,204,0,0,103,131,75,53,245,28,32,37,254,107,80,61,89,223,109,29,183,93,106,3,97,81,151,42,12,228,38,37,17,185,82,2,90,94,0,0,202,133,206,17,118,106,202,20,68,250,95,30,207,123,170,26,121,122,75,42,92,197,7,36,44,92,224,21,30,105,50,62,138,174,0,0,157,13,177,23,78,94,97,6,175,252,248,17,39,198,75,41,230,45,184,12,196,12,46,51,222,89,232,2,92,110,43,56,212,0,0,0,237,220,64,49,33,1,132,32,62,146,45,14,94,50,38,22,11,247,135,34,12,25,225,11,125,148,64,54,13,6,102,0,184,135,0,0,232,174,156,28,130, -105,4,2,178,11,39,26,108,17,136,11,99,103,166,4,187,107,134,30,111,15,76,55,59,218,132,20,102,3,0,0,17,183,114,55,142,26,123,42,240,167,91,41,76,98,234,50,1,69,148,38,110,160,241,39,148,153,237,61,164,202,202,48,24,31,0,0,92,200,70,20,70,93,254,15,53,6,28,32,57,130,247,13,222,234,198,54,79,17,219,25,160,250,241,56,246,91,65,36,88,14,0,0,46,151,72,33,156,223,177,61,213,173,221,12,160,211,8,36,244,152,24,8,189,46,6,29,236,160,189,39,126,196,23,18,154,227,0,0,89,18,46,2,207,183,98,60,175,98,19,40,1, -105,206,5,147,113,119,7,128,234,215,51,182,242,99,20,188,73,155,4,64,167,0,0,67,95,74,51,144,92,220,61,213,218,214,49,78,157,151,33,23,229,126,60,153,210,197,23,176,241,31,15,101,188,238,63,169,5,0,0,254,241,8,11,143,94,40,34,253,123,8,58,194,185,159,51,215,119,209,2,118,217,21,16,101,74,78,7,101,91,8,46,228,135,0,0,236,226,213,46,38,43,221,23,215,217,134,39,245,246,200,11,110,204,194,56,139,58,254,53,215,236,140,52,152,29,176,14,78,247,0,0,92,209,196,33,154,3,28,42,185,116,14,60,193,239,169,23,16, -68,74,37,4,3,139,48,146,90,154,39,250,143,209,6,234,53,0,0,234,225,63,63,189,110,78,50,237,149,80,6,12,168,206,24,93,24,59,13,93,127,233,35,136,215,44,45,231,70,89,36,33,173,0,0,186,183,117,20,194,127,63,33,216,179,24,9,57,204,121,14,224,219,140,1,212,183,95,57,211,195,133,55,80,6,166,37,147,149,0,0,253,242,36,53,225,175,226,38,94,56,9,7,50,217,79,25,156,132,214,28,46,169,225,0,186,216,29,51,48,34,74,21,126,46,0,0,133,153,214,15,100,119,113,2,234,42,247,29,219,50,39,12,159,20,207,12,239,55,164,61, -136,231,247,50,173,115,157,29,233,10,0,0,3,160,9,20,4,173,35,39,248,175,225,46,94,80,103,46,208,197,84,26,20,184,127,35,155,78,209,8,185,253,92,38,33,145,0,0,144,43,38,25,127,79,6,55,169,41,204,35,127,48,241,8,183,31,93,2,224,93,124,25,155,236,18,22,176,150,138,33,21,43,0,0,87,117,61,8,153,91,102,36,73,154,72,25,62,92,210,20,111,6,73,7,106,75,53,12,122,170,63,35,130,106,79,1,176,46,0,0,64,190,231,40,50,197,229,15,89,238,64,16,36,37,178,52,242,154,118,36,91,88,112,37,238,119,230,46,165,70,187,58,249, -106,0,0,28,126,56,46,9,184,5,41,159,86,89,15,168,153,253,56,69,129,220,7,13,10,169,39,112,150,100,6,64,90,132,10,129,179,0,0,30,128,130,52,131,190,173,9,93,21,212,27,241,226,83,30,64,249,214,56,50,9,173,42,179,238,68,1,17,129,59,26,102,89,0,0,55,12,135,4,60,82,220,17,173,53,53,61,216,114,176,45,141,78,48,49,29,130,229,35,236,241,245,46,238,22,42,40,154,148,0,0,253,25,44,3,159,203,38,19,62,140,2,24,65,58,174,50,74,91,11,23,173,94,52,61,253,98,7,5,212,6,98,52,132,190,0,0,31,40,241,50,77,41,165,29,118, -195,13,37,87,253,105,21,121,148,57,8,12,210,151,57,209,68,9,5,183,204,50,24,249,239,0,0,130,148,198,22,245,215,109,52,123,22,250,50,4,80,173,58,203,136,188,50,43,211,201,21,31,84,238,23,3,83,12,40,103,152,0,0,215,44,121,47,81,132,193,27,145,138,98,21,212,115,145,24,158,99,153,58,198,86,181,36,199,249,52,8,196,142,86,24,46,208,0,0,161,122,85,29,100,231,136,34,151,194,31,16,179,191,100,7,223,171,214,25,2,168,203,31,146,165,21,8,54,80,145,60,102,168,0,0,52,6,67,1,211,238,6,38,183,164,17,6,159,113,218, -58,97,57,225,48,118,233,99,15,121,77,180,34,0,170,125,14,135,181,0,0,81,177,130,29,50,208,68,45,219,162,251,33,85,15,41,40,204,143,154,16,236,84,132,22,100,109,229,1,144,43,148,14,166,210,0,0,5,148,248,28,211,133,80,16,45,165,76,8,189,66,221,3,167,32,130,20,202,98,185,43,101,117,203,63,16,217,190,33,45,232,0,0,160,59,75,46,215,216,103,33,23,31,191,24,124,189,175,10,92,95,36,63,198,60,92,56,239,59,183,63,135,72,65,4,8,65,0,0,149,85,82,23,112,135,165,33,84,69,6,26,89,97,146,13,19,152,132,43,117,184, -150,41,44,143,102,53,191,93,218,60,55,220,0,0,237,141,217,19,226,38,167,24,132,33,160,56,206,160,200,55,219,94,214,49,20,100,138,60,140,140,12,12,91,40,132,40,162,99,0,0,194,207,209,32,83,95,70,6,165,115,120,28,2,168,253,42,31,70,148,45,83,201,12,20,6,253,118,44,255,185,184,16,43,136,0,0,69,84,4,56,66,105,24,42,238,215,232,1,100,220,220,63,128,240,190,23,117,185,184,4,223,163,124,22,39,81,87,32,21,12,0,0,6,162,84,0,85,31,62,5,50,234,140,37,13,57,21,12,186,40,205,35,153,237,240,36,10,93,17,20,186, -142,130,53,48,47,0,0,175,127,133,3,115,142,68,58,1,151,97,41,135,183,242,11,136,127,239,40,32,61,234,30,213,192,169,40,107,226,218,58,87,199,0,0,164,76,88,32,50,108,103,7,16,76,137,1,68,67,76,31,98,27,198,62,34,200,167,13,87,98,243,63,72,243,115,22,58,240,0,0,93,34,89,20,61,97,52,57,16,141,133,24,139,223,189,62,68,162,2,28,70,38,80,23,129,15,13,58,107,171,235,24,128,250,0,0,7,21,206,62,237,248,173,40,195,89,124,0,180,13,219,10,10,92,66,12,9,130,136,55,96,145,6,12,240,21,228,7,167,11,0,0,68,208,240, -22,80,250,231,25,121,26,230,9,36,245,167,46,170,165,224,46,24,62,167,61,226,137,122,37,64,103,241,40,140,101,0,0,45,135,203,55,187,204,71,55,154,232,140,1,241,216,89,40,85,118,211,59,196,137,117,25,241,96,84,34,186,222,77,48,92,174,0,0,109,117,150,54,92,37,107,45,122,65,97,37,21,88,188,26,103,92,48,63,116,13,102,48,228,172,43,31,228,171,210,18,201,49,0,0,120,174,8,30,55,122,17,47,10,7,209,42,185,242,183,43,131,6,22,52,171,102,45,46,244,155,58,40,91,213,18,34,15,248,0,0,115,224,23,22,209,230,219,16, -179,23,147,3,78,111,47,43,107,134,220,15,95,91,226,57,14,137,235,49,81,205,136,31,88,100,0,0,137,101,175,31,122,121,166,32,53,171,174,51,68,142,66,46,133,161,153,2,31,145,117,27,233,42,46,16,218,111,117,51,159,217,0,0,214,61,16,14,200,81,220,55,154,133,4,0,31,48,129,17,195,122,161,18,22,63,79,8,106,131,63,32,144,86,245,30,71,188,0,0,67,195,247,22,99,11,66,14,198,74,180,35,177,92,77,10,93,57,166,30,27,75,21,43,203,38,213,13,106,10,137,7,30,227,0,0,49,171,78,20,195,14,55,52,7,73,99,14,1,197,107,49, -10,232,248,59,153,140,208,14,48,128,131,59,154,150,63,45,157,88,0,0,106,31,54,17,157,175,107,16,185,141,143,20,72,149,67,24,31,243,144,61,146,128,24,28,96,79,42,42,34,4,23,17,85,98,0,0,65,44,12,26,202,133,229,47,103,108,51,32,21,7,199,32,66,124,219,46,181,130,97,40,168,46,250,34,91,244,205,44,57,19,0,0,43,188,241,41,46,21,124,33,65,58,146,30,31,254,137,4,107,64,163,19,68,63,144,12,122,186,229,58,177,216,88,10,155,159,0,0,175,71,252,24,225,199,18,28,195,222,12,44,12,178,127,55,168,104,181,1,64,109, -202,0,197,124,241,60,216,68,232,46,243,127,0,0,167,67,186,57,51,89,24,62,151,194,186,24,180,198,78,41,23,107,68,51,209,109,36,50,11,154,98,10,6,160,235,41,107,31,0,0,117,55,33,21,2,88,19,6,144,169,66,61,200,78,10,45,0,97,127,44,127,229,164,7,20,182,11,54,58,143,17,28,198,142,0,0,255,255,65,56,249,60,4,56,144,30,245,12,47,40,166,54,113,14,238,45,115,5,13,25,110,48,190,37,54,232,155,41,88,143,0,0,187,171,82,52,52,254,207,50,227,194,149,43,248,203,169,26,174,149,212,21,182,255,176,46,157,184,27,48,121, -16,109,24,222,131,0,0,110,182,78,5,172,93,20,40,24,41,228,60,174,205,23,39,215,99,21,14,49,190,218,62,107,250,9,6,211,40,205,56,240,50,0,0,241,118,146,53,155,48,162,37,94,177,23,42,164,108,137,43,51,104,216,60,61,0,215,46,168,177,29,12,212,99,226,24,118,61,0,0,179,188,156,5,110,153,146,7,96,120,25,27,6,8,102,8,243,62,51,24,107,211,184,29,9,182,221,7,134,222,92,26,118,211,0,0,88,228,69,29,27,178,53,22,211,127,14,37,168,179,169,2,47,4,222,9,149,79,27,21,58,91,136,13,57,57,120,47,129,132,0,0,126,5,121, -23,214,198,146,53,86,229,98,50,10,113,158,2,144,202,178,44,115,206,111,9,74,216,77,0,149,46,227,30,238,56,0,0,125,161,45,21,144,62,40,24,177,70,6,13,194,246,4,55,17,200,11,32,127,193,154,19,137,240,197,24,212,131,71,59,234,59,0,0,210,104,199,44,23,38,193,57,108,65,236,31,227,222,121,51,84,181,225,0,250,250,162,18,239,223,172,55,191,86,253,53,176,195,0,0,197,220,78,58,246,133,62,13,114,27,49,32,80,136,140,19,231,151,89,39,228,0,127,11,117,24,214,9,247,50,232,54,115,110,0,0,228,160,157,21,55,223,199, -44,55,144,103,0,156,246,157,34,39,147,134,2,34,34,84,17,234,139,196,44,123,18,127,48,10,238,0,0,121,185,128,10,9,49,113,2,20,179,171,41,140,126,61,36,4,16,195,7,169,250,101,31,98,39,89,27,249,77,98,55,6,119,0,0,222,207,38,1,65,32,61,19,33,227,239,23,63,141,130,62,23,113,156,42,71,230,117,35,119,71,113,59,86,159,96,42,2,138,0,0,133,226,111,50,45,113,110,51,125,18,239,19,80,10,235,22,164,106,224,57,7,233,241,60,210,128,15,60,166,100,177,8,212,22,0,0,65,180,85,1,155,255,131,15,35,212,100,51,77,4,195, -15,233,177,49,53,152,166,249,45,138,26,100,34,120,148,62,34,248,13,0,0,19,165,207,58,42,47,196,56,234,58,14,38,230,231,1,9,78,156,106,53,67,29,209,40,165,58,214,54,177,251,145,3,204,31,0,0,156,252,122,16,144,110,29,20,135,145,131,9,89,116,123,59,75,180,249,57,12,213,225,56,72,139,71,53,120,16,104,48,93,22,0,0,178,105,220,62,243,193,137,6,114,113,183,38,108,34,152,2,165,134,163,10,215,16,12,25,48,23,138,11,91,235,28,36,43,193,0,0,221,65,221,32,192,166,171,12,0,42,123,18,143,111,135,59,184,118,73,9, -126,34,183,28,151,29,223,12,77,249,15,49,115,49,0,0,77,254,97,57,119,97,189,45,122,25,7,49,226,27,34,5,138,62,167,44,196,196,164,15,63,250,168,39,12,119,225,47,89,208,0,0,194,35,232,42,25,108,77,38,203,100,171,13,125,232,34,14,253,180,85,9,33,119,217,1,254,227,37,53,34,48,152,30,16,69,0,0,107,102,175,44,253,192,88,51,11,227,28,11,241,180,63,63,127,99,244,23,160,107,94,26,43,166,42,16,224,233,149,18,70,19,0,0,39,204,110,63,65,106,37,61,19,46,148,16,7,42,192,60,72,202,176,12,79,209,12,57,247,14,88, -20,24,1,100,5,190,105,0,0,81,95,202,14,38,200,90,8,191,174,201,15,229,198,133,58,221,207,181,5,252,202,90,59,198,98,105,46,103,55,69,53,233,221,0,0,247,56,198,16,207,105,90,43,249,113,149,40,55,250,186,63,80,9,143,63,41,44,205,7,137,29,17,40,56,207,68,26,78,184,0,0,228,136,156,25,22,172,65,62,194,110,212,10,136,79,84,59,154,23,75,32,196,186,1,61,233,54,55,25,218,8,132,24,26,253,0,0,223,200,91,25,89,36,35,39,41,15,192,28,37,117,220,26,220,130,119,23,82,165,1,15,177,191,32,12,114,46,213,30,201,26,0, -0,206,24,128,31,109,109,69,53,139,214,146,24,227,92,105,11,207,199,109,8,203,147,243,63,19,159,107,41,48,118,76,33,228,78,0,0,31,56,72,30,108,152,214,48,19,96,128,14,109,92,210,1,113,230,197,7,67,35,16,45,199,95,139,63,66,32,181,39,143,182,0,0,120,54,71,49,71,186,20,10,112,47,57,20,66,229,21,40,203,112,192,56,86,49,197,56,245,191,13,0,49,13,39,51,118,253,0,0,79,79,20,13,170,59,89,56,55,132,28,0,133,187,163,24,96,214,44,3,244,156,130,59,15,174,61,20,28,222,80,25,4,242,0,0,147,33,122,13,82,220,2,60, -237,70,117,25,60,145,71,26,44,33,234,52,210,9,58,27,158,33,64,59,72,204,232,42,162,133,0,0,58,207,205,48,82,15,50,60,39,36,177,3,231,183,182,49,225,159,2,12,71,11,130,49,130,109,81,48,202,250,21,38,18,156,0,0,176,104,117,55,108,193,192,22,83,176,3,30,6,116,163,43,53,15,101,3,94,177,181,45,64,68,231,63,243,28,255,54,93,210,0,0,156,146,57,31,155,228,132,2,6,240,195,35,7,226,156,8,131,43,217,39,55,211,189,43,190,56,137,4,254,100,221,63,58,122,0,0,19,124,29,39,98,68,249,23,133,163,255,32,254,125,173, -6,100,5,200,42,94,106,250,1,95,37,167,20,250,80,76,13,129,69,0,0,207,99,255,58,84,241,226,24,153,107,217,43,80,149,1,8,112,201,105,29,223,197,67,61,87,139,173,57,37,5,59,22,88,159,0,0,102,243,131,45,52,232,104,43,140,88,40,47,120,59,115,54,12,122,201,29,48,47,12,61,174,233,226,63,196,109,125,39,74,188,0,0,193,51,31,24,153,89,99,29,109,177,71,37,254,126,42,58,166,202,152,55,210,183,222,36,131,99,192,5,158,155,114,32,58,13,0,0,60,190,18,55,203,184,168,1,107,166,70,33,182,99,124,37,114,52,21,0,172,110, -151,28,60,141,55,27,204,100,39,13,215,57,0,0,92,246,111,28,208,103,192,48,76,100,65,10,123,233,189,23,239,232,18,40,25,83,213,9,177,127,191,51,187,213,211,38,146,143,0,0,43,242,119,31,243,62,185,42,53,224,130,15,101,142,92,38,198,38,175,21,166,176,53,7,229,9,221,1,247,253,133,41,203,240,0,0,60,160,9,25,29,139,35,63,97,86,9,10,164,31,99,60,4,64,208,22,148,13,155,12,239,137,249,29,254,196,208,42,37,26,0,0,18,156,80,6,83,115,179,34,101,71,31,61,214,136,255,26,141,237,104,50,97,163,195,5,29,50,77,21, -200,118,174,30,29,56,0,0,2,97,180,46,56,170,144,17,117,175,110,14,27,22,10,22,32,231,129,37,233,92,145,52,181,158,218,35,246,223,214,42,122,164,0,0,85,233,79,56,88,211,206,54,72,206,59,6,104,169,85,38,246,83,138,12,165,249,220,14,121,100,126,56,234,25,21,60,3,167,0,0,189,68,19,22,239,187,172,9,250,119,114,25,113,138,133,39,83,155,25,25,172,181,228,41,14,220,122,4,172,104,77,62,0,213,0,0,88,206,234,6,176,149,101,18,211,17,50,47,232,88,145,31,27,63,160,19,193,53,180,26,108,116,13,21,181,106,241,44, -198,115,0,0,78,101,248,42,92,164,194,5,23,41,141,59,110,227,161,26,170,198,145,45,217,68,38,36,186,65,247,36,206,28,41,45,47,58,0,0,94,29,24,0,252,34,206,18,5,242,170,21,110,234,108,28,222,184,221,14,112,232,52,0,29,218,127,20,27,212,249,60,39,198,0,0,109,136,159,54,152,2,228,9,57,44,190,28,82,1,172,61,142,214,247,33,226,4,88,26,45,59,166,2,145,199,117,39,143,215,0,0,22,139,130,55,126,54,138,19,243,71,72,10,202,99,229,17,160,83,222,6,188,41,208,23,162,63,35,61,183,131,175,62,136,187,0,0,247,93,234, -10,136,206,81,20,156,150,30,58,56,93,160,18,236,99,145,21,4,88,22,55,69,211,141,30,61,193,172,29,54,183,0,0,170,76,50,37,63,204,42,21,57,42,71,41,194,120,217,18,105,46,163,18,81,210,49,54,35,13,188,24,10,254,94,42,40,140,0,0,130,148,239,11,207,113,199,57,89,148,203,17,17,60,225,57,122,235,192,60,125,204,183,63,120,51,25,5,204,232,24,1,163,64,0,0,64,221,84,7,85,28,250,24,248,108,70,3,127,140,137,16,162,233,246,50,53,127,16,18,91,244,252,13,176,12,28,9,41,151,0,0,67,97,163,42,188,36,45,33,147,244,202, -26,149,20,186,54,144,54,223,20,47,119,29,23,209,220,161,62,151,9,145,40,209,145,0,0,255,167,44,12,174,11,182,48,163,33,240,29,101,23,217,0,24,175,39,47,104,181,70,30,80,224,150,39,2,214,229,31,99,137,0,0,104,62,73,48,133,87,80,59,123,171,46,36,227,168,241,30,248,137,116,53,80,197,115,46,87,77,66,8,34,35,73,56,31,45,0,0,127,221,168,12,232,88,27,6,166,129,19,42,213,0,202,49,27,66,87,19,245,128,118,50,253,146,224,37,248,198,57,14,129,48,0,0,242,199,146,10,30,201,87,16,94,145,173,52,144,145,149,5,200, -24,142,0,69,23,177,39,227,37,201,15,10,162,180,56,209,40,0,0,177,63,106,6,162,21,115,3,108,32,46,25,6,74,2,48,110,47,134,54,22,50,212,21,30,93,182,30,155,10,58,49,95,87,0,0,173,85,38,16,42,164,227,38,240,242,58,42,241,92,237,12,237,218,135,14,94,10,111,7,103,45,202,47,169,16,228,54,110,111,0,0,223,23,1,57,145,162,218,6,146,2,1,34,243,238,78,9,218,143,42,42,123,224,155,60,39,162,183,42,147,173,13,36,236,165,0,0,254,98,100,56,207,4,74,32,61,54,74,33,21,124,24,33,28,247,160,31,180,14,230,37,197,0,4, -20,176,151,152,49,157,183,0,0,18,215,42,23,112,93,62,44,144,114,4,33,55,44,99,14,90,185,73,35,81,216,229,57,157,148,176,16,204,68,250,55,83,161,0,0,210,253,72,13,78,217,151,34,156,50,11,47,22,202,79,1,189,154,184,49,199,87,99,12,72,252,178,5,236,79,16,54,148,253,0,0,58,91,207,17,4,220,48,12,16,120,90,27,239,160,206,16,196,36,200,45,35,66,211,48,53,89,97,20,222,171,177,6,84,154,0,0,228,74,164,54,124,93,213,15,214,82,234,33,148,184,63,18,85,95,71,15,162,205,107,56,175,124,171,6,196,114,48,18,97,182, -0,0,224,202,172,31,68,232,18,35,116,51,187,36,22,67,205,34,60,210,31,7,60,57,83,54,29,140,122,18,229,132,153,37,234,8,0,0,69,185,98,14,140,210,188,22,149,142,15,15,167,239,224,45,53,215,197,21,238,51,240,57,36,46,120,34,59,242,174,62,14,98,0,0,94,111,160,38,101,45,144,6,2,55,8,42,91,148,100,16,163,22,183,35,73,8,53,44,55,172,83,2,133,250,62,9,59,56,0,0,114,231,198,19,27,30,125,34,64,176,194,56,46,157,171,61,232,25,90,42,83,181,89,61,76,4,162,27,59,177,26,28,207,84,0,0,54,161,56,6,117,112,93,30,92, -25,56,40,205,56,71,3,43,12,121,13,216,26,103,57,137,215,214,46,128,15,180,12,132,230,0,0,132,37,108,12,66,96,244,43,106,51,87,51,246,250,120,2,46,71,230,1,232,192,156,10,77,98,166,53,56,230,4,57,91,202,0,0,12,193,232,22,16,241,161,51,7,104,189,17,206,23,166,28,180,127,110,48,156,179,247,62,238,160,194,37,191,120,86,53,93,57,0,0,142,99,254,5,76,182,245,48,203,34,105,6,55,1,39,36,76,39,78,58,191,30,250,4,4,93,172,18,22,45,53,55,98,253,0,0,239,20,108,13,200,54,153,5,245,200,147,47,65,29,63,22,8,128, -100,34,187,111,181,59,246,185,220,37,84,13,183,18,81,122,0,0,19,189,63,11,28,134,79,43,247,36,110,42,202,189,171,47,41,55,92,15,50,229,194,31,137,142,77,46,84,180,127,52,237,86,0,0,235,101,109,15,65,143,81,42,36,21,2,4,213,29,68,38,90,35,143,16,210,239,188,35,234,216,144,29,201,16,86,63,225,30,0,0,28,148,34,29,73,174,13,56,17,43,88,35,97,58,189,12,202,250,252,2,61,241,231,42,207,193,115,44,117,111,36,10,105,187,0,0,68,203,54,14,188,67,101,60,145,1,162,28,35,219,162,31,97,125,53,3,98,67,63,22,192, -139,170,58,227,52,141,21,81,21,0,0,104,90,73,31,148,209,107,10,83,30,12,2,124,93,220,48,168,93,32,35,209,194,143,3,55,94,33,53,85,213,241,63,79,171,0,0,204,186,39,52,65,24,229,7,21,46,214,18,55,89,204,28,158,170,196,13,86,194,58,22,99,19,32,53,175,17,25,47,198,59,0,0,166,253,214,42,87,255,12,19,113,180,190,40,72,105,221,6,215,43,192,22,155,136,187,24,219,92,48,44,93,28,48,23,48,142,0,0,103,230,9,106,133,174,103,187,114,243,110,60,58,245,79,165,127,82,14,81,140,104,5,155,171,217,131,31,25,205,224, -91,152,47,138,66,145,68,55,113,207,251,192,181,165,219,181,233,91,194,86,57,241,17,241,89,164,130,63,146,213,94,28,171,152,170,7,216,1,91,131,18,190,133,49,36,195,125,12,85,116,93,190,114,254,177,222,128,167,6,220,155,116,241,155,193,193,105,155,228,134,71,190,239,198,157,193,15,204,161,12,36,111,44,233,45,170,132,116,74,220,169,176,92,218,136,249,118,82,81,62,152,109,198,49,168,200,39,3,176,199,127,89,191,243,11,224,198,71,145,167,213,81,99,202,6,103,41,41,20,133,10,183,39,56,33,27,46,252,109,44, -77,19,13,56,83,84,115,10,101,187,10,106,118,46,201,194,129,133,44,114,146,161,232,191,162,75,102,26,168,112,139,75,194,163,81,108,199,25,232,146,209,36,6,153,214,133,53,14,244,112,160,106,16,22,193,164,25,8,108,55,30,76,119,72,39,181,188,176,52,179,12,28,57,74,170,216,78,79,202,156,91,243,111,46,104,238,130,143,116,111,99,165,120,20,120,200,132,8,2,199,140,250,255,190,144,235,108,80,164,247,163,249,190,242,120,113,198,5,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0, -2,0,0,0,244,153,0,0,0,4,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,196,148,0,0,99,111,110,100,32,61,61,32,49,32,124,124,32,99,111,110,100,32,61,61,32,48,0,46,46,47,98,105,103,110,117,109,46,99,0,98,110,95,99,109,111,118,0,99,111,101,102,32,60,32,48,120,56,48,48,48,48,48,48,48,117,0,98,110,95,109,117,108,116,105,112,108,121,95,114,101,100,117,99,101,95,115,116,101,112,0,114,101,115,91,105,32,43,32,49,93,32,61, -61,32,48,0,98,110,95,109,117,108,116,105,112,108,121,95,114,101,100,117,99,101,0,111,100,100,45,62,97,91,48,93,32,38,32,49,0,98,110,95,105,110,118,101,114,115,101,0,111,100,100,45,62,97,91,56,93,32,38,32,49,0,101,118,101,110,45,62,97,91,48,93,32,38,32,49,0,40,101,118,101,110,45,62,97,91,56,93,32,38,32,49,41,32,61,61,32,48,0,40,101,118,101,110,45,62,97,91,48,93,32,38,32,49,41,32,61,61,32,48,0,112,112,91,48,93,32,38,32,49,0,40,116,101,109,112,32,38,32,48,120,102,102,102,102,102,102,102,102,41,32,61, -61,32,48,0,40,40,117,115,46,97,91,56,93,32,43,32,112,112,91,48,93,32,42,32,102,97,99,116,111,114,41,32,38,32,109,97,115,107,41,32,61,61,32,48,0,98,32,60,61,32,112,114,105,109,101,45,62,118,97,108,91,48,93,0,98,110,95,115,117,98,105,0,97,45,62,118,97,108,91,56,93,32,60,32,48,120,50,48,48,48,48,0,46,46,47,101,99,100,115,97,46,99,0,99,111,110,100,105,116,105,111,110,97,108,95,110,101,103,97,116,101,0,45,51,32,60,61,32,97,32,38,38,32,97,32,60,61,32,48,0,112,111,105,110,116,95,106,97,99,111,98,105,97, -110,95,97,100,100,0,98,110,95,105,115,95,108,101,115,115,40,107,44,32,38,99,117,114,118,101,45,62,111,114,100,101,114,41,0,40,97,46,118,97,108,91,48,93,32,38,32,49,41,32,33,61,32,48,0,115,99,97,108,97,114,95,109,117,108,116,105,112,108,121,0,49,50,51,52,53,54,55,56,57,65,66,67,68,69,70,71,72,74,75,76,77,78,80,81,82,83,84,85,86,87,88,89,90,97,98,99,100,101,102,103,104,105,106,107,109,110,111,112,113,114,115,116,117,118,119,120,121,122,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,47,100,101,118,47,117,114,97,110,100,111,109,0,114,0,108,101,110,95,114,101,97,100,32,61,61,32,108,101,110,0,46,46,47,114,97,110,100,46,99,0,114,97,110,100,111,109,51,50,0,114,119,97,0],"i8",4,t.L+30720);var cb=v;v+=16;e._i64Subtract=db;e._memset=eb;function fb(a,b){J.push(function(){t.t("vi",a,[b])});fb.level=J.length}e._bitshift64Lshr=gb;e._bitshift64Shl=hb; -var K={s:1,m:2,Jc:3,Gb:4,p:5,la:6,Za:7,dc:8,J:9,nb:10,ha:11,Tc:11,Ea:12,R:13,zb:14,pc:15,S:16,ia:17,Uc:18,U:19,ja:20,B:21,g:22,Zb:23,Da:24,C:25,Qc:26,Ab:27,lc:28,K:29,Gc:30,Sb:31,zc:32,wb:33,Dc:34,hc:42,Db:43,ob:44,Jb:45,Kb:46,Lb:47,Rb:48,Rc:49,bc:50,Ib:51,tb:35,ec:37,fb:52,ib:53,Vc:54,$b:55,jb:56,kb:57,ub:35,lb:59,nc:60,cc:61,Nc:62,mc:63,ic:64,jc:65,Fc:66,fc:67,bb:68,Kc:69,pb:70,Ac:71,Ub:72,xb:73,hb:74,uc:76,gb:77,Ec:78,Mb:79,Nb:80,Qb:81,Pb:82,Ob:83,oc:38,ka:39,Vb:36,T:40,vc:95,yc:96,sb:104,ac:105, -cb:97,Cc:91,sc:88,kc:92,Hc:108,rb:111,$a:98,qb:103,Yb:101,Wb:100,Oc:110,Bb:112,Cb:113,Fb:115,eb:114,vb:89,Tb:90,Bc:93,Ic:94,ab:99,Xb:102,Hb:106,qc:107,Pc:109,Sc:87,yb:122,Lc:116,tc:95,gc:123,Eb:84,wc:75,mb:125,rc:131,xc:130,Mc:86},ib={0:"Success",1:"Not super-user",2:"No such file or directory",3:"No such process",4:"Interrupted system call",5:"I/O error",6:"No such device or address",7:"Arg list too long",8:"Exec format error",9:"Bad file number",10:"No children",11:"No more processes",12:"Not enough core", -13:"Permission denied",14:"Bad address",15:"Block device required",16:"Mount device busy",17:"File exists",18:"Cross-device link",19:"No such device",20:"Not a directory",21:"Is a directory",22:"Invalid argument",23:"Too many open files in system",24:"Too many open files",25:"Not a typewriter",26:"Text file busy",27:"File too large",28:"No space left on device",29:"Illegal seek",30:"Read only file system",31:"Too many links",32:"Broken pipe",33:"Math arg out of domain of func",34:"Math result not representable", -35:"File locking deadlock error",36:"File or path name too long",37:"No record locks available",38:"Function not implemented",39:"Directory not empty",40:"Too many symbolic links",42:"No message of desired type",43:"Identifier removed",44:"Channel number out of range",45:"Level 2 not synchronized",46:"Level 3 halted",47:"Level 3 reset",48:"Link number out of range",49:"Protocol driver not attached",50:"No CSI structure available",51:"Level 2 halted",52:"Invalid exchange",53:"Invalid request descriptor", -54:"Exchange full",55:"No anode",56:"Invalid request code",57:"Invalid slot",59:"Bad font file fmt",60:"Device not a stream",61:"No data (for no delay io)",62:"Timer expired",63:"Out of streams resources",64:"Machine is not on the network",65:"Package not installed",66:"The object is remote",67:"The link has been severed",68:"Advertise error",69:"Srmount error",70:"Communication error on send",71:"Protocol error",72:"Multihop attempted",73:"Cross mount point (not really error)",74:"Trying to read unreadable message", -75:"Value too large for defined data type",76:"Given log. name not unique",77:"f.d. invalid for this operation",78:"Remote address changed",79:"Can access a needed shared lib",80:"Accessing a corrupted shared lib",81:".lib section in a.out corrupted",82:"Attempting to link in too many libs",83:"Attempting to exec a shared library",84:"Illegal byte sequence",86:"Streams pipe error",87:"Too many users",88:"Socket operation on non-socket",89:"Destination address required",90:"Message too long",91:"Protocol wrong type for socket", -92:"Protocol not available",93:"Unknown protocol",94:"Socket type not supported",95:"Not supported",96:"Protocol family not supported",97:"Address family not supported by protocol family",98:"Address already in use",99:"Address not available",100:"Network interface is not configured",101:"Network is unreachable",102:"Connection reset by network",103:"Connection aborted",104:"Connection reset by peer",105:"No buffer space available",106:"Socket is already connected",107:"Socket is not connected",108:"Can't send after socket shutdown", -109:"Too many references",110:"Connection timed out",111:"Connection refused",112:"Host is down",113:"Host is unreachable",114:"Socket already connected",115:"Connection already in progress",116:"Stale file handle",122:"Quota exceeded",123:"No medium (in tape drive)",125:"Operation canceled",130:"Previous owner died",131:"State not recoverable"};function jb(a){e.___errno_location&&(w[e.___errno_location()>>2]=a);return a} -function kb(a,b){for(var c=0,d=a.length-1;0<=d;d--){var f=a[d];"."===f?a.splice(d,1):".."===f?(a.splice(d,1),c++):c&&(a.splice(d,1),c--)}if(b)for(;c--;c)a.unshift("..");return a}function lb(a){var b="/"===a.charAt(0),c="/"===a.substr(-1);(a=kb(a.split("/").filter(function(a){return!!a}),!b).join("/"))||b||(a=".");a&&c&&(a+="/");return(b?"/":"")+a} -function mb(a){var b=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/.exec(a).slice(1);a=b[0];b=b[1];if(!a&&!b)return".";b&&(b=b.substr(0,b.length-1));return a+b}function nb(a){if("/"===a)return"/";var b=a.lastIndexOf("/");return-1===b?a:a.substr(b+1)}function pb(){var a=Array.prototype.slice.call(arguments,0);return lb(a.join("/"))}function L(a,b){return lb(a+"/"+b)} -function qb(){for(var a="",b=!1,c=arguments.length-1;-1<=c&&!b;c--){b=0<=c?arguments[c]:"/";if("string"!==typeof b)throw new TypeError("Arguments to path.resolve must be strings");if(!b)return"";a=b+"/"+a;b="/"===b.charAt(0)}a=kb(a.split("/").filter(function(a){return!!a}),!b).join("/");return(b?"/":"")+a||"."}var rb=[];function sb(a,b){rb[a]={input:[],output:[],v:b};tb(a,ub)} -var ub={open:function(a){var b=rb[a.c.rdev];if(!b)throw new M(K.U);a.tty=b;a.seekable=!1},close:function(a){a.tty.v.flush(a.tty)},flush:function(a){a.tty.v.flush(a.tty)},read:function(a,b,c,d){if(!a.tty||!a.tty.v.wa)throw new M(K.la);for(var f=0,g=0;ga.b.length&&(a.b=N.La(a),a.f=a.b.length);if(!a.b||a.b.subarray){var c=a.b?a.b.length:0;c>=b||(b=Math.max(b,c*(1048576>c?2:1.125)|0),0!=c&&(b=Math.max(b,256)),c=a.b,a.b=new Uint8Array(b),0b)a.b.length=b;else for(;a.b.length=a.c.f)return 0;a=Math.min(a.c.f-f,d);assert(0<=a);if(8b)throw new M(K.g);return b},na:function(a,b,c){N.ra(a.c,b+c);a.c.f=Math.max(a.c.f,b+c)},Aa:function(a, -b,c,d,f,g,h){if(32768!==(a.c.mode&61440))throw new M(K.U);c=a.c.b;if(h&2||c.buffer!==b&&c.buffer!==b.buffer){if(0>1)}catch(c){if(!c.code)throw c;throw new M(K[c.code]);}return b.mode},j:function(a){for(var b=[];a.parent!==a;)b.push(a.name),a=a.parent;b.push(a.i.aa.root);b.reverse();return pb.apply(null,b)},sa:{0:"r",1:"r+",2:"r+",64:"r",65:"r+",66:"r+",129:"rx+",193:"rx+",514:"w+",577:"w", -578:"w+",705:"wx",706:"wx+",1024:"a",1025:"a",1026:"a+",1089:"a",1090:"a+",1153:"ax",1154:"ax+",1217:"ax",1218:"ax+",4096:"rs",4098:"rs+"},Ka:function(a){a&=-2099201;a&=-32769;a&=-524289;if(a in Q.sa)return Q.sa[a];throw new M(K.g);},d:{l:function(a){a=Q.j(a);var b;try{b=fs.lstatSync(a)}catch(c){if(!c.code)throw c;throw new M(K[c.code]);}Q.O&&!b.q&&(b.q=4096);Q.O&&!b.blocks&&(b.blocks=(b.size+b.q-1)/b.q|0);return{dev:b.dev,ino:b.ino,mode:b.mode,nlink:b.nlink,uid:b.uid,gid:b.gid,rdev:b.rdev,size:b.size, -atime:b.atime,mtime:b.mtime,ctime:b.ctime,q:b.q,blocks:b.blocks}},h:function(a,b){var c=Q.j(a);try{void 0!==b.mode&&(fs.chmodSync(c,b.mode),a.mode=b.mode),void 0!==b.size&&fs.truncateSync(c,b.size)}catch(d){if(!d.code)throw d;throw new M(K[d.code]);}},lookup:function(a,b){var c=L(Q.j(a),b),c=Q.ua(c);return Q.createNode(a,b,c)},F:function(a,b,c,d){a=Q.createNode(a,b,c,d);b=Q.j(a);try{P(a.mode)?fs.mkdirSync(b,a.mode):fs.writeFileSync(b,"",{mode:a.mode})}catch(f){if(!f.code)throw f;throw new M(K[f.code]); -}return a},rename:function(a,b,c){a=Q.j(a);b=L(Q.j(b),c);try{fs.renameSync(a,b)}catch(d){if(!d.code)throw d;throw new M(K[d.code]);}},unlink:function(a,b){var c=L(Q.j(a),b);try{fs.unlinkSync(c)}catch(d){if(!d.code)throw d;throw new M(K[d.code]);}},rmdir:function(a,b){var c=L(Q.j(a),b);try{fs.rmdirSync(c)}catch(d){if(!d.code)throw d;throw new M(K[d.code]);}},readdir:function(a){a=Q.j(a);try{return fs.readdirSync(a)}catch(b){if(!b.code)throw b;throw new M(K[b.code]);}},symlink:function(a,b,c){a=L(Q.j(a), -b);try{fs.symlinkSync(c,a)}catch(d){if(!d.code)throw d;throw new M(K[d.code]);}},readlink:function(a){var b=Q.j(a);try{return b=fs.readlinkSync(b),b=Bb.relative(Bb.resolve(a.i.aa.root),b)}catch(c){if(!c.code)throw c;throw new M(K[c.code]);}}},e:{open:function(a){var b=Q.j(a.c);try{32768===(a.c.mode&61440)&&(a.H=fs.openSync(b,Q.Ka(a.flags)))}catch(c){if(!c.code)throw c;throw new M(K[c.code]);}},close:function(a){try{32768===(a.c.mode&61440)&&a.H&&fs.closeSync(a.H)}catch(b){if(!b.code)throw b;throw new M(K[b.code]); -}},read:function(a,b,c,d,f){if(0===d)return 0;var g=new Buffer(d),h;try{h=fs.readSync(a.H,g,0,d,f)}catch(n){throw new M(K[n.code]);}if(0b)throw new M(K.g);return b}}};v+=16; -v+=16;v+=16;var Cb=null,Db=[null],Eb=[],Fb=1,R=null,Gb=!0,S={},M=null,zb={}; -function T(a,b){a=qb("/",a);b=b||{};if(!a)return{path:"",c:null};var c={ta:!0,ea:0},d;for(d in c)void 0===b[d]&&(b[d]=c[d]);if(8>>0)%R.length}function Jb(a){var b=Ib(a.parent.id,a.name);a.u=R[b];R[b]=a}function Ab(a,b){var c;if(c=(c=Kb(a,"x"))?c:a.d.lookup?0:K.R)throw new M(c,a);for(c=R[Ib(a.id,b)];c;c=c.u){var d=c.name;if(c.parent.id===a.id&&d===b)return c}return a.d.lookup(a,b)} -function yb(a,b,c,d){Lb||(Lb=function(a,b,c,d){a||(a=this);this.parent=a;this.i=a.i;this.G=null;this.id=Fb++;this.name=b;this.mode=c;this.d={};this.e={};this.rdev=d},Lb.prototype={},Object.defineProperties(Lb.prototype,{read:{get:function(){return 365===(this.mode&365)},set:function(a){a?this.mode|=365:this.mode&=-366}},write:{get:function(){return 146===(this.mode&146)},set:function(a){a?this.mode|=146:this.mode&=-147}},Qa:{get:function(){return P(this.mode)}},Pa:{get:function(){return 8192===(this.mode& -61440)}}}));a=new Lb(a,b,c,d);Jb(a);return a}function P(a){return 16384===(a&61440)}var Mb={r:0,rs:1052672,"r+":2,w:577,wx:705,xw:705,"w+":578,"wx+":706,"xw+":706,a:1089,ax:1217,xa:1217,"a+":1090,"ax+":1218,"xa+":1218};function Nb(a){var b=["r","w","rw"][a&3];a&512&&(b+="w");return b}function Kb(a,b){if(Gb)return 0;if(-1===b.indexOf("r")||a.mode&292){if(-1!==b.indexOf("w")&&!(a.mode&146)||-1!==b.indexOf("x")&&!(a.mode&73))return K.R}else return K.R;return 0} -function Ob(a,b){try{return Ab(a,b),K.ia}catch(c){}return Kb(a,"wx")}function Pb(a){var b;b=4096;for(a=a||0;a<=b;a++)if(!Eb[a])return a;throw new M(K.Da);} -function Qb(a,b){Rb||(Rb=function(){},Rb.prototype={},Object.defineProperties(Rb.prototype,{object:{get:function(){return this.c},set:function(a){this.c=a}},od:{get:function(){return 1!==(this.flags&2097155)}},pd:{get:function(){return 0!==(this.flags&2097155)}},nd:{get:function(){return this.flags&1024}}}));var c=new Rb,d;for(d in a)c[d]=a[d];a=c;c=Pb(b);a.fd=c;return Eb[c]=a}var xb={open:function(a){a.e=Db[a.c.rdev].e;a.e.open&&a.e.open(a)},o:function(){throw new M(K.K);}}; -function tb(a,b){Db[a]={e:b}}function Sb(a,b){var c="/"===b,d=!b,f;if(c&&Cb)throw new M(K.S);if(!c&&!d){f=T(b,{ta:!1});b=f.path;f=f.c;if(f.G)throw new M(K.S);if(!P(f.mode))throw new M(K.ja);}var d={type:a,aa:{},Ba:b,Ra:[]},g=a.i(d);g.i=d;d.root=g;c?Cb=g:f&&(f.G=d,f.i&&f.i.Ra.push(d))}function Tb(a,b,c){var d=T(a,{parent:!0}).c;a=nb(a);if(!a||"."===a||".."===a)throw new M(K.g);var f=Ob(d,a);if(f)throw new M(f);if(!d.d.F)throw new M(K.s);return d.d.F(d,a,b,c)} -function Ub(a,b){b=(void 0!==b?b:438)&4095;b|=32768;return Tb(a,b,0)}function V(a,b){b=(void 0!==b?b:511)&1023;b|=16384;return Tb(a,b,0)}function Vb(a,b,c){"undefined"===typeof c&&(c=b,b=438);return Tb(a,b|8192,c)}function Wb(a,b){if(!qb(a))throw new M(K.m);var c=T(b,{parent:!0}).c;if(!c)throw new M(K.m);var d=nb(b),f=Ob(c,d);if(f)throw new M(f);if(!c.d.symlink)throw new M(K.s);return c.d.symlink(c,d,a)} -function Hb(a){a=T(a).c;if(!a)throw new M(K.m);if(!a.d.readlink)throw new M(K.g);return qb(U(a.parent),a.d.readlink(a))}function Xb(a,b){var c;"string"===typeof a?c=T(a,{X:!0}).c:c=a;if(!c.d.h)throw new M(K.s);c.d.h(c,{mode:b&4095|c.mode&-4096,timestamp:Date.now()})} -function Yb(a,b,c,d){if(""===a)throw new M(K.m);if("string"===typeof b){var f=Mb[b];if("undefined"===typeof f)throw Error("Unknown file open mode: "+b);b=f}c=b&64?("undefined"===typeof c?438:c)&4095|32768:0;var g;if("object"===typeof a)g=a;else{a=lb(a);try{g=T(a,{X:!(b&131072)}).c}catch(h){}}f=!1;if(b&64)if(g){if(b&128)throw new M(K.ia);}else g=Tb(a,c,0),f=!0;if(!g)throw new M(K.m);8192===(g.mode&61440)&&(b&=-513);if(b&65536&&!P(g.mode))throw new M(K.ja);if(!f&&(c=g?40960===(g.mode&61440)?K.T:P(g.mode)&& -("r"!==Nb(b)||b&512)?K.B:Kb(g,Nb(b)):K.m))throw new M(c);if(b&512){c=g;var n;"string"===typeof c?n=T(c,{X:!0}).c:n=c;if(!n.d.h)throw new M(K.s);if(P(n.mode))throw new M(K.B);if(32768!==(n.mode&61440))throw new M(K.g);if(c=Kb(n,"w"))throw new M(c);n.d.h(n,{size:0,timestamp:Date.now()})}b&=-641;d=Qb({c:g,path:U(g),flags:b,seekable:!0,position:0,e:g.e,Ya:[],error:!1},d);d.e.open&&d.e.open(d);!e.logReadFiles||b&1||(Zb||(Zb={}),a in Zb||(Zb[a]=1,e.printErr("read file: "+a)));try{S.onOpenFile&&(g=0,1!== -(b&2097155)&&(g|=1),0!==(b&2097155)&&(g|=2),S.onOpenFile(a,g))}catch(u){console.log("FS.trackingDelegate['onOpenFile']('"+a+"', flags) threw an exception: "+u.message)}return d}function $b(a){a.Z&&(a.Z=null);try{a.e.close&&a.e.close(a)}catch(b){throw b;}finally{Eb[a.fd]=null}}function ac(a,b,c){if(!a.seekable||!a.e.o)throw new M(K.K);a.position=a.e.o(a,b,c);a.Ya=[]} -function bc(a,b,c,d,f,g){if(0>d||0>f)throw new M(K.g);if(0===(a.flags&2097155))throw new M(K.J);if(P(a.c.mode))throw new M(K.B);if(!a.e.write)throw new M(K.g);a.flags&1024&&ac(a,0,2);var h=!0;if("undefined"===typeof f)f=a.position,h=!1;else if(!a.seekable)throw new M(K.K);b=a.e.write(a,b,c,d,f,g);h||(a.position+=b);try{if(a.path&&S.onWriteToFile)S.onWriteToFile(a.path)}catch(n){console.log("FS.trackingDelegate['onWriteToFile']('"+path+"') threw an exception: "+n.message)}return b} -function cc(){M||(M=function(a,b){this.c=b;this.Va=function(a){this.n=a;for(var b in K)if(K[b]===a){this.code=b;break}};this.Va(a);this.message=ib[a]},M.prototype=Error(),M.prototype.constructor=M,[K.m].forEach(function(a){zb[a]=new M(a);zb[a].stack=""}))}var dc;function ec(a,b){var c=0;a&&(c|=365);b&&(c|=146);return c}function fc(a,b,c,d){a=L("string"===typeof a?a:U(a),b);return Ub(a,ec(c,d))} -function gc(a,b,c,d,f,g){a=b?L("string"===typeof a?a:U(a),b):a;d=ec(d,f);f=Ub(a,d);if(c){if("string"===typeof c){a=Array(c.length);b=0;for(var h=c.length;b>2]}function jc(){var a;a=Y();a=Eb[a];if(!a)throw new M(K.J);return a}e.___muldsi3=kc;e.___muldi3=lc;e._i64Add=mc;e._sbrk=nc;function oc(){oc.D||(oc.D=[]);oc.D.push(t.Q());return oc.D.length-1}e._llvm_bswap_i32=pc;e._memcpy=qc;e._pthread_self=rc;cc();R=Array(4096);Sb(N,"/");V("/tmp");V("/home");V("/home/web_user"); -(function(){V("/dev");tb(259,{read:function(){return 0},write:function(a,b,f,g){return g}});Vb("/dev/null",259);sb(1280,vb);sb(1536,wb);Vb("/dev/tty",1280);Vb("/dev/tty1",1536);var a;if("undefined"!==typeof crypto){var b=new Uint8Array(1);a=function(){crypto.getRandomValues(b);return b[0]}}else a=m?function(){return require("crypto").randomBytes(1)[0]}:function(){return 256*Math.random()|0};W("/dev","random",a);W("/dev","urandom",a);V("/dev/shm");V("/dev/shm/tmp")})();V("/proc");V("/proc/self");V("/proc/self/fd"); -Sb({i:function(){var a=yb("/proc/self","fd",16895,73);a.d={lookup:function(a,c){var d=Eb[+c];if(!d)throw new M(K.J);var f={parent:null,i:{Ba:"fake"},d:{readlink:function(){return d.path}}};return f.parent=f}};return a}},"/proc/self/fd"); -Sa.unshift(function(){if(!e.noFSInit&&!dc){assert(!dc,"FS.init was previously called. If you want to initialize later with custom parameters, remove any earlier calls (note that one is automatically added to the generated code)");dc=!0;cc();e.stdin=e.stdin;e.stdout=e.stdout;e.stderr=e.stderr;e.stdin?W("/dev","stdin",e.stdin):Wb("/dev/tty","/dev/stdin");e.stdout?W("/dev","stdout",null,e.stdout):Wb("/dev/tty","/dev/stdout");e.stderr?W("/dev","stderr",null,e.stderr):Wb("/dev/tty1","/dev/stderr");var a= -Yb("/dev/stdin","r");assert(0===a.fd,"invalid handle for stdin ("+a.fd+")");a=Yb("/dev/stdout","w");assert(1===a.fd,"invalid handle for stdout ("+a.fd+")");a=Yb("/dev/stderr","w");assert(2===a.fd,"invalid handle for stderr ("+a.fd+")")}});Ta.push(function(){Gb=!1});J.push(function(){dc=!1;var a=e._fflush;a&&a(0);for(a=0;athis.length-1||0>a)){var b=a%this.chunkSize;return this.ya(a/this.chunkSize|0)[b]}};n.prototype.Ua=function(a){this.ya=a};n.prototype.oa=function(){var a=new XMLHttpRequest;a.open("HEAD",c,!1);a.send(null);if(!(200<=a.status&&300>a.status||304===a.status))throw Error("Couldn't load "+c+". Status: "+a.status);var b=Number(a.getResponseHeader("Content-length")),d,f=(d=a.getResponseHeader("Accept-Ranges"))&& -"bytes"===d,a=(d=a.getResponseHeader("Content-Encoding"))&&"gzip"===d,g=1048576;f||(g=b);var h=this;h.Ua(function(a){var d=a*g,f=(a+1)*g-1,f=Math.min(f,b-1);if("undefined"===typeof h.M[a]){var n=h.M;if(d>f)throw Error("invalid range ("+d+", "+f+") or no bytes requested!");if(f>b-1)throw Error("only "+b+" bytes available! programmer error!");var q=new XMLHttpRequest;q.open("GET",c,!1);b!==g&&q.setRequestHeader("Range","bytes="+d+"-"+f);"undefined"!=typeof Uint8Array&&(q.responseType="arraybuffer"); -q.overrideMimeType&&q.overrideMimeType("text/plain; charset=x-user-defined");q.send(null);if(!(200<=q.status&&300>q.status||304===q.status))throw Error("Couldn't load "+c+". Status: "+q.status);d=void 0!==q.response?new Uint8Array(q.response||[]):Xa(q.responseText||"",!0);n[a]=d}if("undefined"===typeof h.M[a])throw Error("doXHR failed!");return h.M[a]});if(a||!b)g=b=1,g=b=this.ya(0).length,console.log("LazyFiles on gzip forces download of the whole file when length is accessed");this.Ga=b;this.Fa= -g;this.$=!0};if("undefined"!==typeof XMLHttpRequest){if(!l)throw"Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc";g=new n;Object.defineProperties(g,{length:{get:function(){this.$||this.oa();return this.Ga}},chunkSize:{get:function(){this.$||this.oa();return this.Fa}}});h=void 0}else h=c,g=void 0;var u=fc(a,b,d,f);g?u.b=g:h&&(u.b=null,u.url=h);Object.defineProperties(u,{f:{get:function(){return this.b.length}}});var r={};Object.keys(u.e).forEach(function(a){var b= -u.e[a];r[a]=function(){if(!hc(u))throw new M(K.p);return b.apply(null,arguments)}});r.read=function(a,b,c,d,f){if(!hc(u))throw new M(K.p);a=a.c.b;if(f>=a.length)return 0;d=Math.min(a.length-f,d);assert(0<=d);if(a.slice)for(var g=0;g>2]=Oa;ya=!0;e.Ia={Math:Math,Int8Array:Int8Array,Int16Array:Int16Array,Int32Array:Int32Array,Uint8Array:Uint8Array,Uint16Array:Uint16Array,Uint32Array:Uint32Array,Float32Array:Float32Array,Float64Array:Float64Array,NaN:NaN,Infinity:Infinity}; -e.Ja={abort:z,assert:assert,enlargeMemory:function(){ia()},getTotalMemory:function(){return ha},abortOnCannotGrowMemory:ia,invoke_ii:function(a,b){try{return e.dynCall_ii(a,b)}catch(c){if("number"!==typeof c&&"longjmp"!==c)throw c;Z.setThrew(1,0)}},invoke_iiii:function(a,b,c,d){try{return e.dynCall_iiii(a,b,c,d)}catch(f){if("number"!==typeof f&&"longjmp"!==f)throw f;Z.setThrew(1,0)}},invoke_vi:function(a,b){try{e.dynCall_vi(a,b)}catch(c){if("number"!==typeof c&&"longjmp"!==c)throw c;Z.setThrew(1, -0)}},_pthread_cleanup_pop:function(){assert(fb.level==J.length,"cannot pop if something else added meanwhile!");J.pop();fb.level=J.length},___syscall221:function(a,b){X=b;try{var c=jc();switch(Y()){case 0:var d=Y();return 0>d?-K.g:Yb(c.path,c.flags,0,d).fd;case 1:case 2:return 0;case 3:return c.flags;case 4:return d=Y(),c.flags|=d,0;case 12:case 12:return d=Y(),qa[d+0>>1]=2,0;case 13:case 14:case 13:case 14:return 0;case 16:case 8:return-K.g;case 9:return jb(K.g),-1;default:return-K.g}}catch(f){return"undefined"!== -typeof ic&&f instanceof M||z(f),-f.n}},___syscall54:function(a,b){X=b;try{var c=jc(),d=Y();switch(d){case 21505:return c.tty?0:-K.C;case 21506:return c.tty?0:-K.C;case 21519:if(!c.tty)return-K.C;var f=Y();return w[f>>2]=0;case 21520:return c.tty?-K.g:-K.C;case 21531:f=Y();if(!c.e.Oa)throw new M(K.C);return c.e.Oa(c,d,f);default:z("bad ioctl syscall "+d)}}catch(g){return"undefined"!==typeof ic&&g instanceof M||z(g),-g.n}},___lock:function(){},_abort:function(){e.abort()},_pthread_cleanup_push:fb,___syscall6:function(a, -b){X=b;try{var c=jc();$b(c);return 0}catch(d){return"undefined"!==typeof ic&&d instanceof M||z(d),-d.n}},_llvm_stacksave:oc,___syscall140:function(a,b){X=b;try{var c=jc(),d=Y(),f=Y(),g=Y(),h=Y();assert(0===d);ac(c,f,h);w[g>>2]=c.position;c.Z&&0===f&&0===h&&(c.Z=null);return 0}catch(n){return"undefined"!==typeof ic&&n instanceof M||z(n),-n.n}},___syscall5:function(a,b){X=b;try{var c=B(Y()),d=Y(),f=Y();return Yb(c,d,f).fd}catch(g){return"undefined"!==typeof ic&&g instanceof M||z(g),-g.n}},_emscripten_memcpy_big:function(a, -b,c){F.set(F.subarray(b,b+c),a);return a},_llvm_bswap_i64:function(a,b){var c=pc(b)>>>0,d=pc(a)>>>0;return(Z.setTempRet0(d),c)|0},___unlock:function(){},_llvm_stackrestore:function(a){var b=oc.D[a];oc.D.splice(a,1);t.I(b)},___assert_fail:function(a,b,c,d){ja=!0;throw"Assertion failed: "+B(a)+", at: "+[b?B(b):"unknown filename",c,d?B(d):"unknown function"]+" at "+Ha();},___syscall145:function(a,b){X=b;try{var c=jc(),d=Y(),f;a:{for(var g=Y(),h=0,n=0;n>2],r,q=c,y=w[d+8*n>>2], -H=u,A=void 0,I=C;if(0>H||0>A)throw new M(K.g);if(1===(q.flags&2097155))throw new M(K.J);if(P(q.c.mode))throw new M(K.B);if(!q.e.read)throw new M(K.g);var O=!0;if("undefined"===typeof A)A=q.position,O=!1;else if(!q.seekable)throw new M(K.K);var ob=q.e.read(q,I,y,H,A);O||(q.position+=ob);r=ob;if(0>r){f=-1;break a}h+=r;if(r>2],w[d+(8*n+4)>>2],void 0);if(0>u){f=-1;break a}h+=u}f=h}return f}catch(r){return"undefined"!==typeof ic&&r instanceof M||z(r),-r.n}},___setErrNo:jb,STACKTOP:p,STACK_MAX:Ma,DYNAMICTOP_PTR:x,tempDoublePtr:cb,ABORT:ja};// EMSCRIPTEN_START_ASM -var Z=(function(global,env,buffer) { -"use asm";var a=new global.Int8Array(buffer);var b=new global.Int16Array(buffer);var c=new global.Int32Array(buffer);var d=new global.Uint8Array(buffer);var e=new global.Uint16Array(buffer);var f=new global.Uint32Array(buffer);var g=new global.Float32Array(buffer);var h=new global.Float64Array(buffer);var i=env.STACKTOP|0;var j=env.STACK_MAX|0;var k=env.DYNAMICTOP_PTR|0;var l=env.tempDoublePtr|0;var m=env.ABORT|0;var n=0;var o=0;var p=0;var q=0;var r=global.NaN,s=global.Infinity;var t=0,u=0,v=0,w=0,x=0.0,y=0,z=0,A=0,B=0.0;var C=0;var D=global.Math.floor;var E=global.Math.abs;var F=global.Math.sqrt;var G=global.Math.pow;var H=global.Math.cos;var I=global.Math.sin;var J=global.Math.tan;var K=global.Math.acos;var L=global.Math.asin;var M=global.Math.atan;var N=global.Math.atan2;var O=global.Math.exp;var P=global.Math.log;var Q=global.Math.ceil;var R=global.Math.imul;var S=global.Math.min;var T=global.Math.max;var U=global.Math.clz32;var V=env.abort;var W=env.assert;var X=env.enlargeMemory;var Y=env.getTotalMemory;var Z=env.abortOnCannotGrowMemory;var _=env.invoke_ii;var $=env.invoke_iiii;var aa=env.invoke_vi;var ba=env._pthread_cleanup_pop;var ca=env.___syscall221;var da=env.___syscall54;var ea=env.___lock;var fa=env._abort;var ga=env._pthread_cleanup_push;var ha=env.___syscall6;var ia=env._llvm_stacksave;var ja=env.___syscall140;var ka=env.___syscall5;var la=env._emscripten_memcpy_big;var ma=env._llvm_bswap_i64;var na=env.___unlock;var oa=env._llvm_stackrestore;var pa=env.___assert_fail;var qa=env.___syscall145;var ra=env.___syscall146;var sa=env.___setErrNo;var ta=0.0; -// EMSCRIPTEN_START_FUNCS -function xa(a){a=a|0;var b=0;b=i;i=i+a|0;i=i+15&-16;return b|0}function ya(){return i|0}function za(a){a=a|0;i=a}function Aa(a,b){a=a|0;b=b|0;i=a;j=b}function Ba(a,b){a=a|0;b=b|0;if(!n){n=a;o=b}}function Ca(a){a=a|0;C=a}function Da(){return C|0}function Ea(b,c){b=b|0;c=c|0;a[b>>0]=c>>>24;a[b+1>>0]=c>>>16;a[b+2>>0]=c>>>8;a[b+3>>0]=c;return}function Fa(a,b){a=a|0;b=b|0;var e=0,f=0,g=0,h=0;e=0;f=0;do{h=a+(7-f<<2)|0;h=(d[h+1>>0]|0)<<16|(d[h>>0]|0)<<24|(d[h+2>>0]|0)<<8|(d[h+3>>0]|0);g=f<<1;c[b+(f<<2)>>2]=(h<>>(30-g|0);f=f+1|0}while((f|0)!=8);c[b+32>>2]=e;return}function Ga(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0;e=c[b+32>>2]<<16;f=0;while(1){g=c[b+(7-f<<2)>>2]|0;h=f<<1;i=g>>>(14-h|0)|e;e=d+(f<<2)|0;a[e>>0]=i>>>24;a[e+1>>0]=i>>>16;a[e+2>>0]=i>>>8;a[e+3>>0]=i;f=f+1|0;if((f|0)==8)break;else e=g<>2]=0;a=a+4|0}while((a|0)<(b|0));return}function Ia(a){a=a|0;return (c[a+32>>2]|(c[a+28>>2]|(c[a+24>>2]|(c[a+20>>2]|(c[a+16>>2]|(c[a+12>>2]|(c[a+8>>2]|(c[a+4>>2]|c[a>>2])))))))|0)==0|0}function Ja(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0;d=0;e=8;f=0;while(1){h=c[a+(e<<2)>>2]|0;g=c[b+(e<<2)>>2]|0;d=h>>>0>>0|d<<1;f=h>>>0>g>>>0|f<<1;if((e|0)<=0)break;else e=e+-1|0}return d>>>0>f>>>0|0}function Ka(a,b){a=a|0;b=b|0;var d=0,e=0;d=0;e=0;do{e=c[b+(d<<2)>>2]^c[a+(d<<2)>>2]|e;d=d+1|0}while((d|0)!=9);return (e|0)==0|0}function La(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0;g=0-b|0;h=b+-1|0;if((b|1|0)==1)f=0;else pa(38200,38223,270,38235);do{c[a+(f<<2)>>2]=c[e+(f<<2)>>2]&h|c[d+(f<<2)>>2]&g;f=f+1|0}while((f|0)!=9);return}function Ma(a){a=a|0;var b=0,d=0,e=0,f=0;b=8;d=c[a+32>>2]|0;do{e=b;b=b+-1|0;f=d;d=c[a+(b<<2)>>2]|0;c[a+(e<<2)>>2]=d>>>29&1|f<<1&1073741822}while((e|0)>1);c[a>>2]=c[a>>2]<<1&1073741822;return}function Na(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,i=0;d=c[a>>2]|0;f=0-(d&1)|0;d=((c[b>>2]&f)+d|0)>>>1;e=0;do{i=e;e=e+1|0;g=(c[b+(e<<2)>>2]&f)+(c[a+(e<<2)>>2]|0)|0;h=(g<<29&536870912)+d|0;c[a+(i<<2)>>2]=h&1073741823;d=(h>>>30)+(g>>>1)|0}while((e|0)!=8);c[a+32>>2]=d;return}function Oa(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0;e=b&255;b=0;do{f=a+(b<<2)|0;c[f>>2]=R(c[f>>2]|0,e)|0;b=b+1|0}while((b|0)!=9);Pa(a,d);return}function Pa(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0;g=(c[a+32>>2]|0)>>>16;i=c[a>>2]|0;h=pc(c[b>>2]|0,0,g|0,0)|0;d=C;e=kc(i|0,536870912,h|0,d|0)|0;f=C;d=kc(i|0,0,h|0,d|0)|0;c[a>>2]=d&1073741823;d=1;while(1){l=mc(e|0,f|0,30)|0;k=C;i=a+(d<<2)|0;j=c[i>>2]|0;f=pc(c[b+(d<<2)>>2]|0,0,g|0,0)|0;h=C;k=qc(l|0,k|0,-2147483648,536870911)|0;j=qc(k|0,C|0,j|0,0)|0;e=kc(j|0,C|0,f|0,h|0)|0;c[i>>2]=e&1073741823;d=d+1|0;if((d|0)==9)break;else f=C}return}function Qa(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0;h=i;i=i+48|0;g=h;d=0;e=8;f=0;while(1){k=c[a+(e<<2)>>2]|0;j=c[b+(e<<2)>>2]|0;d=k>>>0>>0|d<<1;f=k>>>0>j>>>0|f<<1;if((e|0)<=0)break;else e=e+-1|0}f=d>>>0>f>>>0;e=0;d=1;while(1){d=d+1073741823+(c[a+(e<<2)>>2]|0)-(c[b+(e<<2)>>2]|0)|0;c[g+(e<<2)>>2]=d&1073741823;e=e+1|0;if((e|0)==9)break;else d=d>>>30}La(a,f&1,a,g);i=h;return}function Ra(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0;f=0;e=1;while(1){e=e+1073741823+(c[a+(f<<2)>>2]|0)-(c[b+(f<<2)>>2]|0)|0;c[d+(f<<2)>>2]=e&1073741823;f=f+1|0;if((f|0)==9)break;else e=e>>>30}return}function Sa(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0,j=0;h=0;g=0;e=0;i=1;while(1){f=0;do{j=pc(c[b+(h-f<<2)>>2]|0,0,c[a+(f<<2)>>2]|0,0)|0;g=qc(j|0,C|0,g|0,e|0)|0;e=C;f=f+1|0}while((f|0)!=(i|0));c[d+(h<<2)>>2]=g&1073741823;g=mc(g|0,e|0,30)|0;e=C;h=h+1|0;if((h|0)==9){h=9;break}else i=i+1|0}while(1){f=h+-8|0;if((f|0)<9)do{j=pc(c[b+(h-f<<2)>>2]|0,0,c[a+(f<<2)>>2]|0,0)|0;g=qc(j|0,C|0,g|0,e|0)|0;e=C;f=f+1|0}while((f|0)!=9);c[d+(h<<2)>>2]=g&1073741823;g=mc(g|0,e|0,30)|0;h=h+1|0;if((h|0)==17)break;else e=C}c[d+68>>2]=g;return}function Ta(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0;l=a+(d+1<<2)|0;j=(c[l>>2]<<14)+((c[a+(d<<2)>>2]|0)>>>16)|0;k=d+-8|0;e=a+(k<<2)|0;f=c[e>>2]|0;g=pc(c[b>>2]|0,0,j|0,0)|0;h=C;if((j|0)<=-1)pa(38243,38223,417,38262);i=kc(f|0,536870912,g|0,h|0)|0;m=C;h=kc(f|0,0,g|0,h|0)|0;c[e>>2]=h&1073741823;h=mc(i|0,m|0,30)|0;m=C;i=a+(d+-7<<2)|0;f=qc(c[i>>2]|0,0,-2147483648,536870911)|0;e=1;g=C;d=m;do{m=pc(c[b+(e<<2)>>2]|0,0,j|0,0)|0;m=kc(f|0,g|0,m|0,C|0)|0;m=qc(m|0,C|0,h|0,d|0)|0;c[i>>2]=m&1073741823;e=e+1|0;h=mc(m|0,C|0,30)|0;d=C;i=a+(e+k<<2)|0;f=qc(c[i>>2]|0,0,-2147483648,536870911)|0;g=C}while((e|0)!=9);m=qc(f|0,g|0,h|0,d|0)|0;c[l>>2]=m&1073741823;return}function Ua(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0;e=16;while(1){Ta(b,d,e);if(c[b+(e+1<<2)>>2]|0){g=4;break}e=e+-1|0;if((e|0)<=7){f=0;break}}if((g|0)==4)pa(38286,38223,451,38302);do{c[a+(f<<2)>>2]=c[b+(f<<2)>>2];f=f+1|0}while((f|0)!=9);return}function Va(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0;g=i;i=i+80|0;e=g;f=e;h=f+72|0;do{c[f>>2]=0;f=f+4|0}while((f|0)<(h|0));Sa(a,b,e);Ua(b,e,d);i=g;return}function Wa(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0;n=i;i=i+144|0;k=n+72|0;l=n+36|0;m=n;c[l>>2]=1;h=l+4|0;c[h>>2]=0;c[h+4>>2]=0;c[h+8>>2]=0;c[h+12>>2]=0;c[h+16>>2]=0;c[h+20>>2]=0;c[h+24>>2]=0;c[h+28>>2]=0;h=m;d=b;j=h+36|0;do{c[h>>2]=c[d>>2];h=h+4|0;d=d+4|0}while((h|0)<(j|0));e=0;d=1;while(1){j=m+(e<<2)|0;d=(c[j>>2]|0)+d|0;c[j>>2]=d&1073741823;e=e+1|0;if((e|0)==9)break;else d=d>>>30}d=0;e=c[m>>2]|0;do{j=d;d=d+1|0;h=e;e=c[m+(d<<2)>>2]|0;c[m+(j<<2)>>2]=e<<29&536870912|h>>>1}while((d|0)!=8);e=m+32|0;c[e>>2]=(c[e>>2]|0)>>>1;d=0;f=c[m>>2]|0;do{j=d;d=d+1|0;h=f;f=c[m+(d<<2)>>2]|0;c[m+(j<<2)>>2]=f<<29&536870912|h>>>1}while((d|0)!=8);c[e>>2]=(c[e>>2]|0)>>>1;e=0;do{g=(e|0)==8;d=0;f=c[m+(e<<2)>>2]|0;do{if(g&(f|0)==0)break;if(f&1|0){h=k;j=h+72|0;do{c[h>>2]=0;h=h+4|0}while((h|0)<(j|0));Sa(a,l,k);Ua(l,k,b)}f=f>>>1;h=k;j=h+72|0;do{c[h>>2]=0;h=h+4|0}while((h|0)<(j|0));Sa(a,a,k);Ua(a,k,b);d=d+1|0}while(d>>>0<30);e=e+1|0}while((e|0)!=9);Qa(l,b);h=a;d=l;j=h+36|0;do{c[h>>2]=c[d>>2];h=h+4|0;d=d+4|0}while((h|0)<(j|0));i=n;return}function Xa(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0;v=i;i=i+112|0;d=v+72|0;u=v+32|0;t=v;Pa(a,b);Qa(a,b);e=c[b>>2]|0;f=0;while(1){r=f;f=f+1|0;g=c[b+(f<<2)>>2]|0;h=r<<1;p=g<<30-h|e;c[t+(r<<2)>>2]=p;c[d+(r<<2)>>2]=p;if((f|0)==8)break;else e=g>>>(h+2|0)}e=c[a>>2]|0;f=0;while(1){r=f;f=f+1|0;b=c[a+(f<<2)>>2]|0;g=r<<1;c[u+(r<<2)>>2]=b<<30-g|e;if((f|0)==8)break;else e=b>>>(g+2|0)}o=d+36|0;c[o>>2]=8;p=u+36|0;c[p>>2]=8;r=d+32|0;c[r>>2]=1;c[u+32>>2]=0;f=0;n=u;e=8;g=c[d>>2]|0;b=1;a:while(1){if(!(g&1)){q=7;break}if(!(b&1)){q=10;break}l=n+36|0;b=e;while(1){e=b+-1|0;if(c[n+(e<<2)>>2]|0)break;c[l>>2]=e;if((b|0)<1)break a;else b=e}e=c[n>>2]|0;if(!e){g=n+32|0;do{e=0;do{m=e;e=e+1|0;c[n+(m<<2)>>2]=c[n+(e<<2)>>2]}while((e|0)!=8);c[g>>2]=0;b=(c[l>>2]|0)+-1|0;c[l>>2]=b;f=f+32|0;e=c[n>>2]|0}while((e|0)==0)}k=0;while(1)if(!(e&1<0){e=e>>>k;if((b|0)>1){j=32-k|0;g=1;h=n;while(1){b=n+(g<<2)|0;c[h>>2]=c[b>>2]<>2]|0)>>>k;if((e|0)<(c[l>>2]|0)){g=e;e=h;h=b}else break}}else{g=0;h=e;b=n;e=1}c[b>>2]=h;if(!h)c[l>>2]=(c[l>>2]|0)+-1;else g=e;e=n+(g<<2)|0;b=c[e>>2]<>2]=(c[e>>2]|0)>>>h|b;b=c[e>>2]<>2]=b;m=k+f|0}else m=f;if(!(c[n>>2]&1)){q=32;break}if(c[n+32>>2]&1|0){q=34;break}f=c[o>>2]|0;e=f-(c[p>>2]|0)|0;if(!e){e=f;while(1){b=e+-1|0;if((e|0)<=0){q=38;break}e=c[d+(b<<2)>>2]|0;f=u+(b<<2)|0;if((e|0)==(c[f>>2]|0))e=b;else break}if((q|0)==38){q=0;if(!e){q=56;break}f=u+(b<<2)|0;e=c[d+(b<<2)>>2]|0}e=e>>>0>(c[f>>2]|0)>>>0?1:-1}n=(e|0)>0;l=n?u:d;n=n?d:u;k=l+36|0;h=c[k>>2]|0;if((h|0)>0){e=0;f=1;b=0;while(1){j=n+(e<<2)|0;w=c[j>>2]|0;g=c[l+(e<<2)>>2]|0;f=qc(f|0,b|0,-1,0)|0;f=qc(f|0,C|0,w|0,0)|0;g=kc(f|0,C|0,g|0,0)|0;f=C;c[j>>2]=g;e=e+1|0;if((e|0)<(h|0))b=0;else{b=e;g=0;break}}}else{b=0;f=1;g=0}j=n+36|0;e=c[j>>2]|0;if((b|0)<(e|0)){e=g;while(1){w=n+(b<<2)|0;g=c[w>>2]|0;e=qc(f|0,e|0,-1,0)|0;e=qc(e|0,C|0,g|0,0)|0;c[w>>2]=e;b=b+1|0;e=c[j>>2]|0;if((b|0)>=(e|0))break;else{f=C;e=0}}}if((e|0)>8){f=8;g=0;b=0}else{f=8;g=0;b=0;while(1){w=l+(f<<2)|0;j=c[n+(f<<2)>>2]|0;h=qc(c[w>>2]|0,0,g|0,b|0)|0;j=qc(h|0,C|0,j|0,0)|0;g=C;c[w>>2]=j;w=f;f=f+-1|0;if((w|0)<=(e|0))break;else b=0}h=c[k>>2]|0;b=0}if((f|0)>=(h|0))while(1){w=l+(f<<2)|0;j=qc(c[w>>2]|0,0,g|0,b|0)|0;c[w>>2]=j;if((f|0)>(c[k>>2]|0)){f=f+-1|0;g=C;b=0}else break}g=c[l>>2]|0;if(!(g&1)){q=51;break}b=c[l+32>>2]|0;if(!(b&1)){q=53;break}if(c[n>>2]&1|0){q=55;break}else f=m}if((q|0)==7)pa(38321,38223,646,38335);else if((q|0)==10)pa(38346,38223,647,38335);else if((q|0)==32)pa(38360,38223,699,38335);else if((q|0)==34)pa(38375,38223,700,38335);else if((q|0)==51)pa(38321,38223,757,38335);else if((q|0)==53)pa(38346,38223,758,38335);else if((q|0)==55)pa(38397,38223,759,38335);else if((q|0)==56){l=c[t>>2]|0;if(!(l&1))pa(38419,38223,786,38335);f=l+-1|0;e=l+-2|0;if(!f)k=e;else{do{f=R(f,f)|0;e=R(f+1|0,e)|0}while((f|0)!=0);k=e}b:do if((m|0)>31){j=d+4|0;e=m;while(1){w=c[r>>2]|0;b=R(w,k)|0;q=pc(l|0,0,b|0,0)|0;w=qc(q|0,C|0,w|0,0)|0;if(!((w|0)==0&0==0))break;f=0;g=C;h=0;while(1){w=f;f=f+1|0;o=c[d+(7-w<<2)>>2]|0;p=pc(c[t+(f<<2)>>2]|0,0,b|0,0)|0;q=C;o=qc(o|0,0,g|0,h|0)|0;q=qc(o|0,C|0,p|0,q|0)|0;g=C;c[d+(8-w<<2)>>2]=q;if((f|0)==7)break;else h=0}c[j>>2]=g;e=e+-32|0;if((e|0)<=31){s=e;break b}}pa(38429,38223,802,38335)}else s=m;while(0);if((s|0)>0){w=(1<>2]|0;h=(R(e,k)|0)&w;if((R(h,l)|0)+e&w|0)pa(38454,38223,821,38335);b=pc(h|0,0,l|0,0)|0;b=qc(b|0,C|0,e|0,0)|0;b=mc(b|0,C|0,s|0)|0;f=32-s|0;e=0;g=C;while(1){w=e;e=e+1|0;s=c[d+(7-w<<2)>>2]|0;r=pc(c[t+(e<<2)>>2]|0,0,h|0,0)|0;s=qc(r|0,C|0,s|0,0)|0;s=nc(s|0,C|0,f|0)|0;s=qc(s|0,C|0,b|0,g|0)|0;b=C;c[d+(8-w<<2)>>2]=s;if((e|0)==7)break;else g=0}c[d+4>>2]=b;e=0;f=0}else{e=0;f=0}do{s=c[d+(8-e<<2)>>2]|0;w=e<<1;c[a+(e<<2)>>2]=s<>>(30-w|0);e=e+1|0}while((e|0)!=8);c[a+32>>2]=f;c[t>>2]=0;c[t+4>>2]=0;c[t+8>>2]=0;c[t+12>>2]=0;c[t+16>>2]=0;c[t+20>>2]=0;c[t+24>>2]=0;c[t+28>>2]=0;e=d+40|0;do{c[d>>2]=0;d=d+4|0}while((d|0)<(e|0));d=u;e=d+40|0;do{c[d>>2]=0;d=d+4|0}while((d|0)<(e|0))}i=v;return}function Ya(a,b){a=a|0;b=b|0;var d=0,e=0,f=0;e=0;d=0;while(1){f=a+(e<<2)|0;d=(c[f>>2]|0)+d+(c[b+(e<<2)>>2]|0)|0;c[f>>2]=d&1073741823;e=e+1|0;if((e|0)==9)break;else d=d>>>30}return}function Za(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0;e=0;do{f=a+(e<<2)|0;c[f>>2]=(c[f>>2]|0)+(c[b+(e<<2)>>2]|0);e=e+1|0}while((e|0)!=9);Pa(a,d);return}function _a(a,b,d){a=a|0;b=b|0;d=d|0;var e=0;if((c[d>>2]|0)>>>0>>0)pa(38495,38223,883,38514);b=(c[a>>2]|0)-b|0;c[a>>2]=b;b=b+(c[d>>2]|0)|0;c[a>>2]=b&1073741823;e=1;do{b=(c[a+(e<<2)>>2]|0)+(b>>>30)+(c[d+(e<<2)>>2]|0)|0;c[a+(e<<2)>>2]=b&1073741823;e=e+1|0}while((e|0)!=9);return}function $a(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0;g=0;f=1;while(1){f=f+1073741823+(c[a+(g<<2)>>2]|0)+(c[e+(g<<2)>>2]<<1)-(c[b+(g<<2)>>2]|0)|0;c[d+(g<<2)>>2]=f&1073741823;g=g+1|0;if((g|0)==9)break;else f=f>>>30}return}function ab(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0;n=i;i=i+144|0;k=n+108|0;e=n+72|0;l=n+36|0;m=n;do if(!(bb(b)|0)){if(bb(d)|0){e=d;f=b;g=e+72|0;do{c[e>>2]=c[f>>2];e=e+4|0;f=f+4|0}while((e|0)<(g|0));break}if(cb(b,d)|0){db(a,d);break}if(!(eb(b,d)|0)){$a(d,b,e,a);Xa(e,a);h=d+36|0;j=b+36|0;$a(h,j,k,a);Va(e,k,a);e=l;f=k;g=e+36|0;do{c[e>>2]=c[f>>2];e=e+4|0;f=f+4|0}while((e|0)<(g|0));Va(l,l,a);e=m;f=b;g=e+36|0;do{c[e>>2]=c[f>>2];e=e+4|0;f=f+4|0}while((e|0)<(g|0));Za(m,d,a);$a(l,m,l,a);Pa(l,a);Qa(l,a);$a(b,l,m,a);Va(k,m,a);$a(m,j,m,a);Pa(m,a);Qa(m,a);e=d;f=l;g=e+36|0;do{c[e>>2]=c[f>>2];e=e+4|0;f=f+4|0}while((e|0)<(g|0));e=h;f=m;g=e+36|0;do{c[e>>2]=c[f>>2];e=e+4|0;f=f+4|0}while((e|0)<(g|0));break}else{Ha(d);Ha(d+36|0);break}}while(0);i=n;return}function bb(a){a=a|0;if(!(Ia(a)|0))a=0;else a=(Ia(a+36|0)|0)!=0;return a&1|0}function cb(a,b){a=a|0;b=b|0;if(!(Ka(a,b)|0))a=0;else a=(Ka(a+36|0,b+36|0)|0)!=0;return a&1|0}function db(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0,l=0;j=i;i=i+112|0;d=j+72|0;e=j+36|0;f=j;do if(!(bb(b)|0)){g=b+36|0;if(!(Ia(g)|0)){h=d;k=g;l=h+36|0;do{c[h>>2]=c[k>>2];h=h+4|0;k=k+4|0}while((h|0)<(l|0));Oa(d,2,a);Xa(d,a);h=e;k=b;l=h+36|0;do{c[h>>2]=c[k>>2];h=h+4|0;k=k+4|0}while((h|0)<(l|0));Va(e,e,a);Oa(e,3,a);_a(e,0-(c[a+180>>2]|0)|0,a);Va(e,d,a);h=e;k=d;l=h+36|0;do{c[h>>2]=c[k>>2];h=h+4|0;k=k+4|0}while((h|0)<(l|0));Va(e,e,a);h=f;k=b;l=h+36|0;do{c[h>>2]=c[k>>2];h=h+4|0;k=k+4|0}while((h|0)<(l|0));Ma(f);$a(e,f,e,a);Pa(e,a);Qa(e,a);$a(b,e,f,a);Va(d,f,a);$a(f,g,f,a);Pa(f,a);Qa(f,a);h=b;k=e;l=h+36|0;do{c[h>>2]=c[k>>2];h=h+4|0;k=k+4|0}while((h|0)<(l|0));h=g;k=f;l=h+36|0;do{c[h>>2]=c[k>>2];h=h+4|0;k=k+4|0}while((h|0)<(l|0));break}else{Ha(b);Ha(g);break}}while(0);i=j;return}function eb(a,b){a=a|0;b=b|0;var c=0;if((Ka(a,b)|0)!=0?(c=a+36|0,(Ia(c)|0)==0):0)a=(Ka(c,b+36|0)|0)==0&1;else a=0;return a|0}function fb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0,j=0;g=b+32|0;if((c[g>>2]|0)>>>0>=131072)pa(38522,38542,181,38553);h=a&1073741823;f=~a;a=c[b>>2]|0;e=(c[d>>2]<<1)+1073741824-a|0;c[b>>2]=h&e|a&f;a=0;do{a=a+1|0;i=b+(a<<2)|0;j=c[i>>2]|0;e=(e>>>30)+1073741823+(c[d+(a<<2)>>2]<<1)-j|0;c[i>>2]=h&e|j&f}while((a|0)!=8);if((c[g>>2]|0)>>>0<131072)return;else pa(38522,38542,189,38553)}function gb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0;e=b+72|0;hb(e,d);g=b;h=e;i=g+36|0;do{c[g>>2]=c[h>>2];g=g+4|0;h=h+4|0}while((g|0)<(i|0));Va(e,b,d);f=b+36|0;g=f;h=b;i=g+36|0;do{c[g>>2]=c[h>>2];g=g+4|0;h=h+4|0}while((g|0)<(i|0));Va(e,f,d);Va(a,b,d);Va(a+36|0,f,d);return}function hb(a,b){a=a|0;b=b|0;var d=0,e=0,f=0;e=a+32|0;while(1){d=0;f=Kb()|0;do{c[a+(d<<2)>>2]=f&1073741823;d=d+1|0;f=Kb()|0}while((d|0)!=8);c[e>>2]=f&65535;if(Ia(a)|0)continue;if(Ja(a,b)|0)break}return}function ib(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0;e=b+36|0;f=e;g=a+72|0;h=f+36|0;do{c[f>>2]=c[g>>2];f=f+4|0;g=g+4|0}while((f|0)<(h|0));Xa(e,d);f=b;g=e;h=f+36|0;do{c[f>>2]=c[g>>2];f=f+4|0;g=g+4|0}while((f|0)<(h|0));Va(b,b,d);Va(b,e,d);Va(a,b,d);Va(a+36|0,e,d);Qa(b,d);Qa(e,d);return}function jb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0;s=i;i=i+288|0;k=s+252|0;l=s+216|0;m=s+180|0;n=s+144|0;o=s+108|0;p=s+72|0;q=s+36|0;g=s;e=c[d+180>>2]|0;if((e+3|0)>>>0>=4)pa(38572,38542,248,38590);h=b+72|0;r=p;t=h;u=r+36|0;do{c[r>>2]=c[t>>2];r=r+4|0;t=t+4|0}while((r|0)<(u|0));Va(p,p,d);r=q;t=h;u=r+36|0;do{c[r>>2]=c[t>>2];r=r+4|0;t=t+4|0}while((r|0)<(u|0));Va(p,q,d);j=(e|0)!=0;if(j){e=0-e|0;r=g;t=p;u=r+36|0;do{c[r>>2]=c[t>>2];r=r+4|0;t=t+4|0}while((r|0)<(u|0));Va(g,g,d);Oa(g,e&255,d)}Va(a,p,d);r=l;t=p;u=r+36|0;do{c[r>>2]=c[t>>2];r=r+4|0;t=t+4|0}while((r|0)<(u|0));$a(l,b,l,d);Pa(l,d);Ya(p,b);f=Ka(l,d)|0;Va(a+36|0,q,d);e=b+36|0;$a(q,e,k,d);Ya(q,e);r=m;t=b;u=r+36|0;do{c[r>>2]=c[t>>2];r=r+4|0;t=t+4|0}while((r|0)<(u|0));Va(m,m,d);Oa(m,3,d);if(j)$a(m,g,m,d);La(k,f,m,k);La(l,f,q,l);r=o;t=l;u=r+36|0;do{c[r>>2]=c[t>>2];r=r+4|0;t=t+4|0}while((r|0)<(u|0));Va(o,o,d);r=n;t=l;u=r+36|0;do{c[r>>2]=c[t>>2];r=r+4|0;t=t+4|0}while((r|0)<(u|0));Va(o,n,d);Va(p,o,d);Va(q,n,d);Va(l,h,d);r=b;t=k;u=r+36|0;do{c[r>>2]=c[t>>2];r=r+4|0;t=t+4|0}while((r|0)<(u|0));Va(b,b,d);$a(b,o,b,d);Pa(b,d);$a(o,b,e,d);$a(e,b,e,d);Va(k,e,d);$a(e,n,e,d);Na(e,d);Pa(e,d);i=s;return}function kb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0;n=i;i=i+144|0;l=n+108|0;m=n;if(!(Ja(b,a+108|0)|0))pa(38609,38542,553,38658);j=c[b>>2]|0;g=(j&1)+-1|0;f=1;e=0;h=j;do{k=f+1073741823+h-(c[a+108+(e<<2)>>2]&g)|0;c[l+(e<<2)>>2]=k&1073741823;f=k>>>30;e=e+1|0;h=c[b+(e<<2)>>2]|0;j=h|j}while((e|0)!=8);k=l+32|0;c[k>>2]=f+65535+h-(c[a+140>>2]&g);e=c[l>>2]|0;if(!(e&1))pa(38638,38542,576,38658);if(!j){Ha(d);Ha(d+36|0)}else{gb(a+220+((((e>>>4&1)+15^e)>>>1&7)*72|0)|0,m,a);h=m+36|0;g=1;do{f=0;e=e>>>4;b=l;do{f=f+1|0;j=b;b=l+(f<<2)|0;c[j>>2]=c[b>>2]<<26&1006632960|e;e=(c[b>>2]|0)>>>4}while((f|0)!=8);c[k>>2]=e;e=c[l>>2]|0;b=e>>>4&1;j=b+15^e;fb((j&1)+-1|0,h,a);jb(a+220+(g*576|0)+((j>>>1&7)*72|0)|0,m,a);g=g+1|0}while((g|0)!=64);fb(b+-1|0,h,a);ib(m,d,a)}i=n;return}function lb(b,c,d){b=b|0;c=c|0;d=d|0;b=(b|0)==0?712:b;switch(a[c>>0]|0){case 4:{Fa(c+1|0,d);Fa(c+33|0,d+36|0);b=mb(b,d)|0;break}case 3:case 2:{Fa(c+1|0,d);nb(b,a[c>>0]|0,d,d+36|0);b=mb(b,d)|0;break}default:b=0}return b|0}function mb(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0;k=i;i=i+80|0;d=k+36|0;e=k;if(((bb(b)|0)==0?(Ja(b,a)|0)!=0:0)?(f=b+36|0,(Ja(f,a)|0)!=0):0){g=d;h=f;j=g+36|0;do{c[g>>2]=c[h>>2];g=g+4|0;h=h+4|0}while((g|0)<(j|0));g=e;h=b;j=g+36|0;do{c[g>>2]=c[h>>2];g=g+4|0;h=h+4|0}while((g|0)<(j|0));Va(f,d,a);Qa(d,a);Va(b,e,a);_a(e,0-(c[a+180>>2]|0)|0,a);Va(b,e,a);Za(e,a+184|0,a);Qa(e,a);a=(Ka(e,d)|0)!=0&1}else a=0;i=k;return a|0}function nb(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0;f=e;g=d;h=f+36|0;do{c[f>>2]=c[g>>2];f=f+4|0;g=g+4|0}while((f|0)<(h|0));Va(d,e,a);_a(e,0-(c[a+180>>2]|0)|0,a);Va(d,e,a);Ya(e,a+184|0);Wa(e,a);if((c[e>>2]^b&255)&1|0)Ra(a,e,e);return}function ob(b,c){b=b|0;c=c|0;var d=0,e=0;e=i;i=i+32|0;d=e;switch(a[b>>0]|0){case 4:{Eb(b,65,d);break}case 0:{Eb(b,1,d);break}default:Eb(b,33,d)}Ab(d,32,c);i=e;return}function pb(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0,f=0,g=0,h=0;e=i;i=i+48|0;g=e;f=Lb(b)|0;h=Lb(b)|0;Mb(b,g);ob(a,g+h|0);wb(g,f+20|0,c,d)|0;i=e;return}function qb(b,c,e){b=b|0;c=c|0;e=e|0;var f=0,g=0,h=0,j=0;j=i;i=i+128|0;h=j;f=h;g=f+128|0;do{a[f>>0]=0;f=f+1|0}while((f|0)<(g|0));if(e>>>0>128){Jb(c,e,h);c=0}else{tc(h|0,c|0,e|0)|0;c=0}do{g=h+c|0;f=d[g>>0]|0;a[b+c>>0]=f^92;a[g>>0]=f^54;c=c+1|0}while((c|0)!=128);b=b+128|0;Fb(b);Hb(b,h,128);i=j;return}function rb(a,b){a=a|0;b=b|0;var c=0,d=0,e=0;c=i;i=i+64|0;e=c;d=a+128|0;Ib(d,e);Fb(d);Hb(d,a,128);Hb(d,e,64);Ib(d,b);lc(a|0,0,336)|0;i=c;return}function sb(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;var f=0,g=0;f=i;i=i+336|0;g=f;qb(g,a,b);Hb(g+128|0,c,d);rb(g,e);i=f;return}function tb(b,d,e,f,g,h){b=b|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;var j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0;r=i;i=i+144|0;o=r+104|0;p=r+40|0;q=r;if((f|0)<0)f=0;else{a[o>>0]=c[d+36>>2]&1|2;n=o+1|0;Ga(d,n);Ea(o+33|0,f);f=b+108|0;j=p+32|0;while(1){sb(e,32,o,37,p);Fa(p,q);if(Ja(q,f)|0?(kb(b,q,g),ab(b,d,g),(bb(g)|0)==0):0)break;a[o>>0]=1;k=n;l=j;m=k+32|0;do{a[k>>0]=a[l>>0]|0;k=k+1|0;l=l+1|0}while((k|0)<(m|0))}if(h|0){k=h;l=j;m=k+32|0;do{a[k>>0]=a[l>>0]|0;k=k+1|0;l=l+1|0}while((k|0)<(m|0))}k=o;m=k+37|0;do{a[k>>0]=0;k=k+1|0}while((k|0)<(m|0));k=p;m=k+64|0;do{a[k>>0]=0;k=k+1|0}while((k|0)<(m|0));k=q;m=k+36|0;do{c[k>>2]=0;k=k+4|0}while((k|0)<(m|0));f=1}i=r;return f|0}function ub(b,d,e,f,g,h,j){b=b|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;j=j|0;var k=0,l=0,m=0,n=0,o=0;n=i;i=i+192|0;l=n+152|0;o=n;m=n+120|0;k=n+72|0;tb(712,b,d,e,o,0)|0;a[l>>0]=c[o+36>>2]&1|2;Ga(o,l+1|0);if(j){b=Lb(f)|0;a[m>>0]=0;a[m+1>>0]=20;ob(l,m+2|0);Eb(m,22,k);Mb(f,m);Ab(k,32,m+b|0);b=(wb(m,b+20|0,g,54)|0)!=0&1}else{pb(l,f,g,h);b=1}i=n;return b|0}function vb(b,e,f,g){b=b|0;e=e|0;f=f|0;g=g|0;var h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0;q=i;a:do if((g|0)>0){h=0;do{if(a[f+h>>0]|0)break a;h=h+1|0}while((h|0)<(g|0))}else h=0;while(0);o=(((g-h|0)*138|0)>>>0)/100|0;n=o+1|0;p=i;i=i+((1*n|0)+15&-16)|0;lc(p|0,0,n|0)|0;if((h|0)<(g|0)){j=o;m=h;do{k=a[f+m>>0]|0;if((o|0)>(j|0)|k<<24>>24!=0){k=k&255;l=o;while(1){r=p+l|0;k=(d[r>>0]<<8)+k|0;a[r>>0]=(k|0)%58|0;l=l+-1|0;if((l|0)>(j|0)|(k+57|0)>>>0>114)k=(k|0)/58|0;else{j=l;break}}}else j=o;m=m+1|0}while((m|0)!=(g|0));j=0}else j=0;while(1){if(a[p+j>>0]|0)break;k=j+1|0;if((j|0)<(o|0))j=k;else{j=k;break}}k=n+h-j|0;if((c[e>>2]|0)>>>0>k>>>0){if(!h)h=0;else lc(b|0,49,h|0)|0;if((j|0)<=(o|0))while(1){a[b+h>>0]=a[38674+(d[p+j>>0]|0)>>0]|0;h=h+1|0;if((j|0)<(o|0))j=j+1|0;else break}a[b+h>>0]=0;j=1}else{j=0;h=k}c[e>>2]=h+1;i=q;return j|0}function wb(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,j=0,k=0,l=0;g=i;i=i+16|0;f=g;if((b|0)>128)a=0;else{j=b+32|0;h=ia()|0;k=i;i=i+((1*j|0)+15&-16)|0;l=k+b|0;tc(k|0,a|0,b|0)|0;Eb(a,b,l);Eb(l,32,l);c[f>>2]=e;a=vb(d,f,k,b+4|0)|0;lc(k|0,0,j|0)|0;a=a?c[f>>2]|0:0;oa(h|0)}i=g;return a|0}function xb(a,b){a=a|0;b=b|0;var e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0;s=(d[b+1>>0]|0)<<8|(d[b>>0]|0)|(d[b+2>>0]|0)<<16|(d[b+3>>0]|0)<<24;D=(d[b+5>>0]|0)<<8|(d[b+4>>0]|0)|(d[b+6>>0]|0)<<16|(d[b+7>>0]|0)<<24;v=(d[b+9>>0]|0)<<8|(d[b+8>>0]|0)|(d[b+10>>0]|0)<<16|(d[b+11>>0]|0)<<24;f=(d[b+13>>0]|0)<<8|(d[b+12>>0]|0)|(d[b+14>>0]|0)<<16|(d[b+15>>0]|0)<<24;x=(d[b+17>>0]|0)<<8|(d[b+16>>0]|0)|(d[b+18>>0]|0)<<16|(d[b+19>>0]|0)<<24;t=(d[b+21>>0]|0)<<8|(d[b+20>>0]|0)|(d[b+22>>0]|0)<<16|(d[b+23>>0]|0)<<24;y=(d[b+25>>0]|0)<<8|(d[b+24>>0]|0)|(d[b+26>>0]|0)<<16|(d[b+27>>0]|0)<<24;z=(d[b+29>>0]|0)<<8|(d[b+28>>0]|0)|(d[b+30>>0]|0)<<16|(d[b+31>>0]|0)<<24;B=(d[b+33>>0]|0)<<8|(d[b+32>>0]|0)|(d[b+34>>0]|0)<<16|(d[b+35>>0]|0)<<24;i=(d[b+37>>0]|0)<<8|(d[b+36>>0]|0)|(d[b+38>>0]|0)<<16|(d[b+39>>0]|0)<<24;F=(d[b+41>>0]|0)<<8|(d[b+40>>0]|0)|(d[b+42>>0]|0)<<16|(d[b+43>>0]|0)<<24;l=(d[b+45>>0]|0)<<8|(d[b+44>>0]|0)|(d[b+46>>0]|0)<<16|(d[b+47>>0]|0)<<24;H=(d[b+49>>0]|0)<<8|(d[b+48>>0]|0)|(d[b+50>>0]|0)<<16|(d[b+51>>0]|0)<<24;u=(d[b+53>>0]|0)<<8|(d[b+52>>0]|0)|(d[b+54>>0]|0)<<16|(d[b+55>>0]|0)<<24;m=(d[b+57>>0]|0)<<8|(d[b+56>>0]|0)|(d[b+58>>0]|0)<<16|(d[b+59>>0]|0)<<24;w=(d[b+61>>0]|0)<<8|(d[b+60>>0]|0)|(d[b+62>>0]|0)<<16|(d[b+63>>0]|0)<<24;b=a+8|0;A=c[b>>2]|0;p=a+12|0;e=c[p>>2]|0;n=a+16|0;r=c[n>>2]|0;k=a+20|0;I=c[k>>2]|0;g=a+24|0;E=c[g>>2]|0;j=A+s+(r^e^I)|0;j=(j<<11|j>>>21)+E|0;C=r<<10|r>>>22;A=t+1352829926+A+((r|~I)^e)|0;A=(A<<8|A>>>24)+E|0;o=E+D+(C^e^j)|0;o=(o<<14|o>>>18)+I|0;G=e<<10|e>>>22;E=m+1352829926+E+(A^(e|~C))|0;E=(E<<9|E>>>23)+I|0;J=I+v+(j^G^o)|0;J=(J<<15|J>>>17)+C|0;j=j<<10|j>>>22;I=z+1352829926+I+(E^(A|~G))|0;I=(I<<9|I>>>23)+C|0;A=A<<10|A>>>22;a=C+f+(o^j^J)|0;a=(a<<12|a>>>20)+G|0;o=o<<10|o>>>22;C=s+1352829926+C+(I^(E|~A))|0;C=(C<<11|C>>>21)+G|0;E=E<<10|E>>>22;h=G+x+(J^o^a)|0;h=(h<<5|h>>>27)+j|0;J=J<<10|J>>>22;G=i+1352829926+G+(C^(I|~E))|0;G=(G<<13|G>>>19)+A|0;I=I<<10|I>>>22;j=j+t+(a^J^h)|0;j=(j<<8|j>>>24)+o|0;a=a<<10|a>>>22;A=v+1352829926+A+(G^(C|~I))|0;A=(A<<15|A>>>17)+E|0;C=C<<10|C>>>22;o=o+y+(h^a^j)|0;o=(o<<7|o>>>25)+J|0;h=h<<10|h>>>22;E=l+1352829926+E+(A^(G|~C))|0;E=(E<<15|E>>>17)+I|0;G=G<<10|G>>>22;J=J+z+(j^h^o)|0;J=(J<<9|J>>>23)+a|0;j=j<<10|j>>>22;I=x+1352829926+I+(E^(A|~G))|0;I=(I<<5|I>>>27)+C|0;A=A<<10|A>>>22;a=a+B+(o^j^J)|0;a=(a<<11|a>>>21)+h|0;o=o<<10|o>>>22;C=u+1352829926+C+(I^(E|~A))|0;C=(C<<7|C>>>25)+G|0;E=E<<10|E>>>22;h=h+i+(J^o^a)|0;h=(h<<13|h>>>19)+j|0;J=J<<10|J>>>22;G=y+1352829926+G+(C^(I|~E))|0;G=(G<<7|G>>>25)+A|0;I=I<<10|I>>>22;j=j+F+(a^J^h)|0;j=(j<<14|j>>>18)+o|0;a=a<<10|a>>>22;A=w+1352829926+A+(G^(C|~I))|0;A=(A<<8|A>>>24)+E|0;C=C<<10|C>>>22;o=o+l+(h^a^j)|0;o=(o<<15|o>>>17)+J|0;h=h<<10|h>>>22;E=B+1352829926+E+(A^(G|~C))|0;E=(E<<11|E>>>21)+I|0;G=G<<10|G>>>22;J=J+H+(j^h^o)|0;J=(J<<6|J>>>26)+a|0;j=j<<10|j>>>22;I=D+1352829926+I+(E^(A|~G))|0;I=(I<<14|I>>>18)+C|0;A=A<<10|A>>>22;a=a+u+(o^j^J)|0;a=(a<<7|a>>>25)+h|0;o=o<<10|o>>>22;C=F+1352829926+C+(I^(E|~A))|0;C=(C<<14|C>>>18)+G|0;E=E<<10|E>>>22;h=h+m+(J^o^a)|0;h=(h<<9|h>>>23)+j|0;J=J<<10|J>>>22;G=f+1352829926+G+(C^(I|~E))|0;G=(G<<12|G>>>20)+A|0;I=I<<10|I>>>22;j=j+w+(a^J^h)|0;j=(j<<8|j>>>24)+o|0;a=a<<10|a>>>22;A=H+1352829926+A+(G^(C|~I))|0;A=(A<<6|A>>>26)+E|0;C=C<<10|C>>>22;o=z+1518500249+o+(j&h|a&~j)|0;o=(o<<7|o>>>25)+J|0;h=h<<10|h>>>22;E=y+1548603684+E+(A&C|G&~C)|0;E=(E<<9|E>>>23)+I|0;G=G<<10|G>>>22;J=x+1518500249+J+(o&j|h&~o)|0;J=(J<<6|J>>>26)+a|0;j=j<<10|j>>>22;I=l+1548603684+I+(E&G|A&~G)|0;I=(I<<13|I>>>19)+C|0;A=A<<10|A>>>22;a=u+1518500249+a+(J&o|j&~J)|0;a=(a<<8|a>>>24)+h|0;o=o<<10|o>>>22;C=f+1548603684+C+(I&A|E&~A)|0;C=(C<<15|C>>>17)+G|0;E=E<<10|E>>>22;h=D+1518500249+h+(a&J|o&~a)|0;h=(h<<13|h>>>19)+j|0;J=J<<10|J>>>22;G=z+1548603684+G+(C&E|I&~E)|0;G=(G<<7|G>>>25)+A|0;I=I<<10|I>>>22;j=F+1518500249+j+(h&a|J&~h)|0;j=(j<<11|j>>>21)+o|0;a=a<<10|a>>>22;A=s+1548603684+A+(G&I|C&~I)|0;A=(A<<12|A>>>20)+E|0;C=C<<10|C>>>22;o=y+1518500249+o+(j&h|a&~j)|0;o=(o<<9|o>>>23)+J|0;h=h<<10|h>>>22;E=u+1548603684+E+(A&C|G&~C)|0;E=(E<<8|E>>>24)+I|0;G=G<<10|G>>>22;J=w+1518500249+J+(o&j|h&~o)|0;J=(J<<7|J>>>25)+a|0;j=j<<10|j>>>22;I=t+1548603684+I+(E&G|A&~G)|0;I=(I<<9|I>>>23)+C|0;A=A<<10|A>>>22;a=f+1518500249+a+(J&o|j&~J)|0;a=(a<<15|a>>>17)+h|0;o=o<<10|o>>>22;C=F+1548603684+C+(I&A|E&~A)|0;C=(C<<11|C>>>21)+G|0;E=E<<10|E>>>22;h=H+1518500249+h+(a&J|o&~a)|0;h=(h<<7|h>>>25)+j|0;J=J<<10|J>>>22;G=m+1548603684+G+(C&E|I&~E)|0;G=(G<<7|G>>>25)+A|0;I=I<<10|I>>>22;j=s+1518500249+j+(h&a|J&~h)|0;j=(j<<12|j>>>20)+o|0;a=a<<10|a>>>22;A=w+1548603684+A+(G&I|C&~I)|0;A=(A<<7|A>>>25)+E|0;C=C<<10|C>>>22;o=i+1518500249+o+(j&h|a&~j)|0;o=(o<<15|o>>>17)+J|0;h=h<<10|h>>>22;E=B+1548603684+E+(A&C|G&~C)|0;E=(E<<12|E>>>20)+I|0;G=G<<10|G>>>22;J=t+1518500249+J+(o&j|h&~o)|0;J=(J<<9|J>>>23)+a|0;j=j<<10|j>>>22;I=H+1548603684+I+(E&G|A&~G)|0;I=(I<<7|I>>>25)+C|0;A=A<<10|A>>>22;a=v+1518500249+a+(J&o|j&~J)|0;a=(a<<11|a>>>21)+h|0;o=o<<10|o>>>22;C=x+1548603684+C+(I&A|E&~A)|0;C=(C<<6|C>>>26)+G|0;E=E<<10|E>>>22;h=m+1518500249+h+(a&J|o&~a)|0;h=(h<<7|h>>>25)+j|0;J=J<<10|J>>>22;G=i+1548603684+G+(C&E|I&~E)|0;G=(G<<15|G>>>17)+A|0;I=I<<10|I>>>22;j=l+1518500249+j+(h&a|J&~h)|0;j=(j<<13|j>>>19)+o|0;a=a<<10|a>>>22;A=D+1548603684+A+(G&I|C&~I)|0;A=(A<<13|A>>>19)+E|0;C=C<<10|C>>>22;q=~j;o=B+1518500249+o+(j&h|a&q)|0;o=(o<<12|o>>>20)+J|0;h=h<<10|h>>>22;E=v+1548603684+E+(A&C|G&~C)|0;E=(E<<11|E>>>21)+I|0;G=G<<10|G>>>22;q=f+1859775393+J+((o|q)^h)|0;q=(q<<11|q>>>21)+a|0;j=j<<10|j>>>22;I=w+1836072691+I+((E|~A)^G)|0;I=(I<<9|I>>>23)+C|0;A=A<<10|A>>>22;a=F+1859775393+a+((q|~o)^j)|0;a=(a<<13|a>>>19)+h|0;o=o<<10|o>>>22;C=t+1836072691+C+((I|~E)^A)|0;C=(C<<7|C>>>25)+G|0;E=E<<10|E>>>22;h=m+1859775393+h+((a|~q)^o)|0;h=(h<<6|h>>>26)+j|0;q=q<<10|q>>>22;G=D+1836072691+G+((C|~I)^E)|0;G=(G<<15|G>>>17)+A|0;I=I<<10|I>>>22;j=x+1859775393+j+((h|~a)^q)|0;j=(j<<7|j>>>25)+o|0;a=a<<10|a>>>22;A=f+1836072691+A+((G|~C)^I)|0;A=(A<<11|A>>>21)+E|0;C=C<<10|C>>>22;o=i+1859775393+o+((j|~h)^a)|0;o=(o<<14|o>>>18)+q|0;h=h<<10|h>>>22;E=z+1836072691+E+((A|~G)^C)|0;E=(E<<8|E>>>24)+I|0;G=G<<10|G>>>22;q=w+1859775393+q+((o|~j)^h)|0;q=(q<<9|q>>>23)+a|0;j=j<<10|j>>>22;I=m+1836072691+I+((E|~A)^G)|0;I=(I<<6|I>>>26)+C|0;A=A<<10|A>>>22;a=B+1859775393+a+((q|~o)^j)|0;a=(a<<13|a>>>19)+h|0;o=o<<10|o>>>22;C=y+1836072691+C+((I|~E)^A)|0;C=(C<<6|C>>>26)+G|0;E=E<<10|E>>>22;h=D+1859775393+h+((a|~q)^o)|0;h=(h<<15|h>>>17)+j|0;q=q<<10|q>>>22;G=i+1836072691+G+((C|~I)^E)|0;G=(G<<14|G>>>18)+A|0;I=I<<10|I>>>22;j=v+1859775393+j+((h|~a)^q)|0;j=(j<<14|j>>>18)+o|0;a=a<<10|a>>>22;A=l+1836072691+A+((G|~C)^I)|0;A=(A<<12|A>>>20)+E|0;C=C<<10|C>>>22;o=z+1859775393+o+((j|~h)^a)|0;o=(o<<8|o>>>24)+q|0;h=h<<10|h>>>22;E=B+1836072691+E+((A|~G)^C)|0;E=(E<<13|E>>>19)+I|0;G=G<<10|G>>>22;q=s+1859775393+q+((o|~j)^h)|0;q=(q<<13|q>>>19)+a|0;j=j<<10|j>>>22;I=H+1836072691+I+((E|~A)^G)|0;I=(I<<5|I>>>27)+C|0;A=A<<10|A>>>22;a=y+1859775393+a+((q|~o)^j)|0;a=(a<<6|a>>>26)+h|0;o=o<<10|o>>>22;C=v+1836072691+C+((I|~E)^A)|0;C=(C<<14|C>>>18)+G|0;E=E<<10|E>>>22;h=u+1859775393+h+((a|~q)^o)|0;h=(h<<5|h>>>27)+j|0;q=q<<10|q>>>22;G=F+1836072691+G+((C|~I)^E)|0;G=(G<<13|G>>>19)+A|0;I=I<<10|I>>>22;j=l+1859775393+j+((h|~a)^q)|0;j=(j<<12|j>>>20)+o|0;a=a<<10|a>>>22;A=s+1836072691+A+((G|~C)^I)|0;A=(A<<13|A>>>19)+E|0;C=C<<10|C>>>22;o=t+1859775393+o+((j|~h)^a)|0;o=(o<<7|o>>>25)+q|0;h=h<<10|h>>>22;E=x+1836072691+E+((A|~G)^C)|0;E=(E<<7|E>>>25)+I|0;G=G<<10|G>>>22;q=H+1859775393+q+((o|~j)^h)|0;q=(q<<5|q>>>27)+a|0;j=j<<10|j>>>22;I=u+1836072691+I+((E|~A)^G)|0;I=(I<<5|I>>>27)+C|0;A=A<<10|A>>>22;a=D+-1894007588+a+(q&j|o&~j)|0;a=(a<<11|a>>>21)+h|0;o=o<<10|o>>>22;C=B+2053994217+C+(I&E|A&~I)|0;C=(C<<15|C>>>17)+G|0;E=E<<10|E>>>22;h=i+-1894007588+h+(a&o|q&~o)|0;h=(h<<12|h>>>20)+j|0;q=q<<10|q>>>22;G=y+2053994217+G+(C&I|E&~C)|0;G=(G<<5|G>>>27)+A|0;I=I<<10|I>>>22;j=l+-1894007588+j+(h&q|a&~q)|0;j=(j<<14|j>>>18)+o|0;a=a<<10|a>>>22;A=x+2053994217+A+(G&C|I&~G)|0;A=(A<<8|A>>>24)+E|0;C=C<<10|C>>>22;o=F+-1894007588+o+(j&a|h&~a)|0;o=(o<<15|o>>>17)+q|0;h=h<<10|h>>>22;E=D+2053994217+E+(A&G|C&~A)|0;E=(E<<11|E>>>21)+I|0;G=G<<10|G>>>22;q=s+-1894007588+q+(o&h|j&~h)|0;q=(q<<14|q>>>18)+a|0;j=j<<10|j>>>22;I=f+2053994217+I+(E&A|G&~E)|0;I=(I<<14|I>>>18)+C|0;A=A<<10|A>>>22;a=B+-1894007588+a+(q&j|o&~j)|0;a=(a<<15|a>>>17)+h|0;o=o<<10|o>>>22;C=l+2053994217+C+(I&E|A&~I)|0;C=(C<<14|C>>>18)+G|0;E=E<<10|E>>>22;h=H+-1894007588+h+(a&o|q&~o)|0;h=(h<<9|h>>>23)+j|0;q=q<<10|q>>>22;G=w+2053994217+G+(C&I|E&~C)|0;G=(G<<6|G>>>26)+A|0;I=I<<10|I>>>22;j=x+-1894007588+j+(h&q|a&~q)|0;j=(j<<8|j>>>24)+o|0;a=a<<10|a>>>22;A=s+2053994217+A+(G&C|I&~G)|0;A=(A<<14|A>>>18)+E|0;C=C<<10|C>>>22;o=u+-1894007588+o+(j&a|h&~a)|0;o=(o<<9|o>>>23)+q|0;h=h<<10|h>>>22;E=t+2053994217+E+(A&G|C&~A)|0;E=(E<<6|E>>>26)+I|0;G=G<<10|G>>>22;q=f+-1894007588+q+(o&h|j&~h)|0;q=(q<<14|q>>>18)+a|0;j=j<<10|j>>>22;I=H+2053994217+I+(E&A|G&~E)|0;I=(I<<9|I>>>23)+C|0;A=A<<10|A>>>22;a=z+-1894007588+a+(q&j|o&~j)|0;a=(a<<5|a>>>27)+h|0;o=o<<10|o>>>22;C=v+2053994217+C+(I&E|A&~I)|0;C=(C<<12|C>>>20)+G|0;E=E<<10|E>>>22;h=w+-1894007588+h+(a&o|q&~o)|0;h=(h<<6|h>>>26)+j|0;q=q<<10|q>>>22;G=u+2053994217+G+(C&I|E&~C)|0;G=(G<<9|G>>>23)+A|0;I=I<<10|I>>>22;j=m+-1894007588+j+(h&q|a&~q)|0;j=(j<<8|j>>>24)+o|0;a=a<<10|a>>>22;A=i+2053994217+A+(G&C|I&~G)|0;A=(A<<12|A>>>20)+E|0;C=C<<10|C>>>22;o=t+-1894007588+o+(j&a|h&~a)|0;o=(o<<6|o>>>26)+q|0;h=h<<10|h>>>22;E=z+2053994217+E+(A&G|C&~A)|0;E=(E<<5|E>>>27)+I|0;G=G<<10|G>>>22;q=y+-1894007588+q+(o&h|j&~h)|0;q=(q<<5|q>>>27)+a|0;j=j<<10|j>>>22;I=F+2053994217+I+(E&A|G&~E)|0;I=(I<<15|I>>>17)+C|0;A=A<<10|A>>>22;a=v+-1894007588+a+(q&j|o&~j)|0;a=(a<<12|a>>>20)+h|0;o=o<<10|o>>>22;C=m+2053994217+C+(I&E|A&~I)|0;C=(C<<8|C>>>24)+G|0;E=E<<10|E>>>22;h=x+-1454113458+h+(a^(q|~o))|0;h=(h<<9|h>>>23)+j|0;q=q<<10|q>>>22;G=G+H+(I^E^C)|0;G=(G<<8|G>>>24)+A|0;I=I<<10|I>>>22;j=s+-1454113458+j+(h^(a|~q))|0;j=(j<<15|j>>>17)+o|0;a=a<<10|a>>>22;A=A+w+(C^I^G)|0;A=(A<<5|A>>>27)+E|0;C=C<<10|C>>>22;o=t+-1454113458+o+(j^(h|~a))|0;o=(o<<5|o>>>27)+q|0;h=h<<10|h>>>22;E=E+F+(G^C^A)|0;E=(E<<12|E>>>20)+I|0;G=G<<10|G>>>22;q=i+-1454113458+q+(o^(j|~h))|0;q=(q<<11|q>>>21)+a|0;j=j<<10|j>>>22;x=I+x+(A^G^E)|0;x=(x<<9|x>>>23)+C|0;A=A<<10|A>>>22;a=z+-1454113458+a+(q^(o|~j))|0;a=(a<<6|a>>>26)+h|0;o=o<<10|o>>>22;C=C+D+(E^A^x)|0;C=(C<<12|C>>>20)+G|0;E=E<<10|E>>>22;h=H+-1454113458+h+(a^(q|~o))|0;h=(h<<8|h>>>24)+j|0;q=q<<10|q>>>22;t=G+t+(x^E^C)|0;t=(t<<5|t>>>27)+A|0;x=x<<10|x>>>22;j=v+-1454113458+j+(h^(a|~q))|0;j=(j<<13|j>>>19)+o|0;a=a<<10|a>>>22;A=A+B+(C^x^t)|0;A=(A<<14|A>>>18)+E|0;C=C<<10|C>>>22;o=F+-1454113458+o+(j^(h|~a))|0;o=(o<<12|o>>>20)+q|0;h=h<<10|h>>>22;z=E+z+(t^C^A)|0;z=(z<<6|z>>>26)+x|0;t=t<<10|t>>>22;q=m+-1454113458+q+(o^(j|~h))|0;q=(q<<5|q>>>27)+a|0;j=j<<10|j>>>22;x=x+y+(A^t^z)|0;x=(x<<8|x>>>24)+C|0;A=A<<10|A>>>22;a=D+-1454113458+a+(q^(o|~j))|0;a=(a<<12|a>>>20)+h|0;o=o<<10|o>>>22;v=C+v+(z^A^x)|0;v=(v<<13|v>>>19)+t|0;z=z<<10|z>>>22;h=f+-1454113458+h+(a^(q|~o))|0;h=(h<<13|h>>>19)+j|0;q=q<<10|q>>>22;t=t+u+(x^z^v)|0;t=(t<<6|t>>>26)+A|0;x=x<<10|x>>>22;j=B+-1454113458+j+(h^(a|~q))|0;j=(j<<14|j>>>18)+o|0;a=a<<10|a>>>22;m=A+m+(v^x^t)|0;m=(m<<5|m>>>27)+z|0;v=v<<10|v>>>22;o=l+-1454113458+o+(j^(h|~a))|0;o=(o<<11|o>>>21)+q|0;h=h<<10|h>>>22;s=z+s+(t^v^m)|0;s=(s<<15|s>>>17)+x|0;t=t<<10|t>>>22;q=y+-1454113458+q+(o^(j|~h))|0;q=(q<<8|q>>>24)+a|0;j=j<<10|j>>>22;f=x+f+(m^t^s)|0;f=(f<<13|f>>>19)+v|0;m=m<<10|m>>>22;a=w+-1454113458+a+(q^(o|~j))|0;a=(a<<5|a>>>27)+h|0;o=o<<10|o>>>22;i=v+i+(s^m^f)|0;i=(i<<11|i>>>21)+t|0;s=s<<10|s>>>22;h=u+-1454113458+h+(a^(q|~o))|0;l=t+l+(f^s^i)|0;c[p>>2]=s+r+(q<<10|q>>>22);c[n>>2]=m+(c[k>>2]|0)+o;c[k>>2]=j+(c[g>>2]|0)+m+(l<<11|l>>>21);c[g>>2]=j+(c[b>>2]|0)+i+(h<<6|h>>>26);c[b>>2]=(f<<10|f>>>22)+e+a;return}function yb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0;if(d|0){h=c[a>>2]|0;e=h&63;f=64-e|0;h=h+d|0;c[a>>2]=h;if(h>>>0>>0){h=a+4|0;c[h>>2]=(c[h>>2]|0)+1}if(!((e|0)==0|f>>>0>d>>>0)){tc(a+28+e|0,b|0,f|0)|0;xb(a,a+28|0);e=0;b=b+f|0;d=d-f|0}if(d>>>0>63){g=d+-64|0;h=g&-64;f=b+(h+64)|0;while(1){xb(a,b);d=d+-64|0;if(d>>>0<=63)break;else b=b+64|0}b=f;d=g-h|0}if(d|0)tc(a+28+e|0,b|0,d|0)|0}return}function zb(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0;e=i;i=i+16|0;f=e;g=c[b>>2]|0;h=c[b+4>>2]|0;a[f>>0]=g<<3;a[f+1>>0]=g>>>5;a[f+2>>0]=g>>>13;a[f+3>>0]=g>>>21;a[f+4>>0]=h<<3|g>>>29;a[f+5>>0]=h>>>5;a[f+6>>0]=h>>>13;a[f+7>>0]=h>>>21;g=g&63;yb(b,38733,(g>>>0<56?56:120)-g|0);yb(b,f,8);f=b+8|0;a[d>>0]=c[f>>2];a[d+1>>0]=(c[f>>2]|0)>>>8;a[d+2>>0]=(c[f>>2]|0)>>>16;a[d+3>>0]=(c[f>>2]|0)>>>24;f=b+12|0;a[d+4>>0]=c[f>>2];a[d+5>>0]=(c[f>>2]|0)>>>8;a[d+6>>0]=(c[f>>2]|0)>>>16;a[d+7>>0]=(c[f>>2]|0)>>>24;f=b+16|0;a[d+8>>0]=c[f>>2];a[d+9>>0]=(c[f>>2]|0)>>>8;a[d+10>>0]=(c[f>>2]|0)>>>16;a[d+11>>0]=(c[f>>2]|0)>>>24;f=b+20|0;a[d+12>>0]=c[f>>2];a[d+13>>0]=(c[f>>2]|0)>>>8;a[d+14>>0]=(c[f>>2]|0)>>>16;a[d+15>>0]=(c[f>>2]|0)>>>24;b=b+24|0;a[d+16>>0]=c[b>>2];a[d+17>>0]=(c[b>>2]|0)>>>8;a[d+18>>0]=(c[b>>2]|0)>>>16;a[d+19>>0]=(c[b>>2]|0)>>>24;i=e;return}function Ab(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0;h=i;i=i+96|0;e=h;f=e+8|0;g=e;j=g+92|0;do{c[g>>2]=0;g=g+4|0}while((g|0)<(j|0));c[f>>2]=1732584193;c[e+12>>2]=-271733879;c[e+16>>2]=-1732584194;c[e+20>>2]=271733878;c[e+24>>2]=-1009589776;yb(e,a,b);zb(e,d);i=h;return}function Bb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0;y=i;i=i+64|0;t=y;u=c[a>>2]|0;v=a+4|0;w=a+8|0;x=a+12|0;q=a+16|0;r=a+20|0;s=a+24|0;p=a+28|0;g=0;o=u;a=c[p>>2]|0;h=c[s>>2]|0;j=c[r>>2]|0;k=c[q>>2]|0;e=c[x>>2]|0;l=c[w>>2]|0;f=c[v>>2]|0;while(1){n=((k>>>6|k<<26)^(k>>>11|k<<21)^(k>>>25|k<<7))+a+(h&~k^j&k)+(c[37828+(g<<2)>>2]|0)|0;a=c[b>>2]|0;c[t+(g<<2)>>2]=a;a=n+a|0;e=a+e|0;a=((o>>>2|o<<30)^(o>>>13|o<<19)^(o>>>22|o<<10))+(o&(l^f)^l&f)+a|0;g=g+1|0;if((g|0)==16){n=16;m=a;g=e;a=l;e=o;break}else{C=o;B=f;A=l;z=k;m=j;n=h;b=b+4|0;o=a;k=e;f=C;l=B;e=A;j=z;h=m;a=n}}while(1){A=n;n=n+1|0;z=c[t+((n&15)<<2)>>2]|0;b=c[t+((A+14&15)<<2)>>2]|0;C=((g>>>6|g<<26)^(g>>>11|g<<21)^(g>>>25|g<<7))+h+(j&~g^k&g)+(c[37828+(A<<2)>>2]|0)|0;B=t+((A&15)<<2)|0;b=((z>>>18|z<<14)^z>>>3^(z>>>7|z<<25))+(c[t+((A+9&15)<<2)>>2]|0)+(c[B>>2]|0)+((b>>>19|b<<13)^b>>>10^(b>>>17|b<<15))|0;c[B>>2]=b;b=C+b|0;a=b+a|0;b=((m>>>2|m<<30)^(m>>>13|m<<19)^(m>>>22|m<<10))+(m&(f^e)^f&e)+b|0;if((n|0)==64)break;else{o=m;z=e;A=f;B=g;C=k;h=j;m=b;g=a;e=o;f=z;a=A;k=B;j=C}}c[d>>2]=u+b;c[d+4>>2]=(c[v>>2]|0)+m;c[d+8>>2]=(c[w>>2]|0)+e;c[d+12>>2]=(c[x>>2]|0)+f;c[d+16>>2]=(c[q>>2]|0)+a;c[d+20>>2]=(c[r>>2]|0)+g;c[d+24>>2]=(c[s>>2]|0)+k;c[d+28>>2]=(c[p>>2]|0)+j;i=y;return}function Cb(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0;do if(e|0){n=b+32|0;g=n;h=c[g>>2]|0;g=c[g+4>>2]|0;f=mc(h|0,g|0,3)|0;f=f&63;if(f){i=64-f|0;j=b+40|0;f=j+f|0;if(i>>>0>e>>>0){tc(f|0,d|0,e|0)|0;b=qc(h|0,g|0,e<<3|0,0)|0;c[n>>2]=b;c[n+4>>2]=C;break}tc(f|0,d|0,i|0)|0;m=qc(h|0,g|0,i<<3|0,0)|0;f=n;c[f>>2]=m;c[f+4>>2]=C;e=e-i|0;f=0;do{m=b+40+(f<<2)|0;c[m>>2]=sc(c[m>>2]|0)|0;f=f+1|0}while((f|0)!=16);Bb(b,j,b);d=d+i|0}if(e>>>0>63){j=b+40|0;l=e+-64|0;m=l&-64;k=m+64|0;i=d;while(1){f=j;g=i;h=f+64|0;do{a[f>>0]=a[g>>0]|0;f=f+1|0;g=g+1|0}while((f|0)<(h|0));f=0;do{h=b+40+(f<<2)|0;c[h>>2]=sc(c[h>>2]|0)|0;f=f+1|0}while((f|0)!=16);Bb(b,j,b);g=n;g=qc(c[g>>2]|0,c[g+4>>2]|0,512,0)|0;h=n;c[h>>2]=g;c[h+4>>2]=C;e=e+-64|0;if(e>>>0<=63)break;else i=i+64|0}d=d+k|0;e=l-m|0}if(e|0){tc(b+40|0,d|0,e|0)|0;b=n;b=qc(c[b>>2]|0,c[b+4>>2]|0,e<<3|0,0)|0;c[n>>2]=b;c[n+4>>2]=C}}while(0);return}function Db(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0;if(d){h=b+32|0;f=h;f=mc(c[f>>2]|0,c[f+4>>2]|0,3)|0;f=f&63;e=f+1|0;g=b+40|0;a[g+f>>0]=-128;if(e>>>0>56){lc(g+e|0,0,f^63|0)|0;e=0;do{f=b+40+(e<<2)|0;c[f>>2]=sc(c[f>>2]|0)|0;e=e+1|0}while((e|0)!=16);Bb(b,g,b);e=0}lc(g+e|0,0,56-e|0)|0;e=0;do{f=b+40+(e<<2)|0;c[f>>2]=sc(c[f>>2]|0)|0;e=e+1|0}while((e|0)!=14);e=c[h>>2]|0;c[b+96>>2]=c[h+4>>2];c[b+100>>2]=e;Bb(b,g,b);e=0;do{h=b+(e<<2)|0;c[h>>2]=sc(c[h>>2]|0)|0;e=e+1|0}while((e|0)!=8);e=d;f=b;g=e+32|0;do{a[e>>0]=a[f>>0]|0;e=e+1|0;f=f+1|0}while((e|0)<(g|0))}e=b;g=e+104|0;do{c[e>>2]=0;e=e+4|0}while((e|0)<(g|0));return}function Eb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0;g=i;i=i+112|0;e=g;c[e>>2]=c[9449];c[e+4>>2]=c[9450];c[e+8>>2]=c[9451];c[e+12>>2]=c[9452];c[e+16>>2]=c[9453];c[e+20>>2]=c[9454];c[e+24>>2]=c[9455];c[e+28>>2]=c[9456];f=e+32|0;h=f+72|0;do{c[f>>2]=0;f=f+4|0}while((f|0)<(h|0));Cb(e,a,b);Db(e,d);i=g;return}function Fb(a){a=a|0;var b=0,d=0,e=0;if(a|0){b=a;d=8;e=b+64|0;do{c[b>>2]=c[d>>2];b=b+4|0;d=d+4|0}while((b|0)<(e|0));lc(a+64|0,0,144)|0}return}function Gb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0,X=0,Y=0,Z=0,_=0;L=i;i=i+128|0;F=L;K=a;J=c[K>>2]|0;K=c[K+4>>2]|0;B=a+8|0;w=B;D=a+16|0;e=D;E=a+24|0;f=E;G=a+32|0;p=G;H=a+40|0;q=H;I=a+48|0;m=I;A=a+56|0;h=A;j=0;l=J;u=K;t=c[w>>2]|0;z=c[e>>2]|0;w=c[w+4>>2]|0;a=c[e+4>>2]|0;e=c[f>>2]|0;f=c[f+4>>2]|0;o=c[p>>2]|0;p=c[p+4>>2]|0;g=c[h>>2]|0;h=c[h+4>>2]|0;r=c[q>>2]|0;q=c[q+4>>2]|0;k=c[m>>2]|0;m=c[m+4>>2]|0;while(1){v=mc(o|0,p|0,14)|0;N=C;x=nc(o|0,p|0,50)|0;N=N|C;y=mc(o|0,p|0,18)|0;O=C;M=nc(o|0,p|0,46)|0;O=N^(O|C);N=mc(o|0,p|0,41)|0;n=C;s=nc(o|0,p|0,23)|0;n=qc((v|x)^(y|M)^(N|s)|0,O^(n|C)|0,g|0,h|0)|0;n=qc(n|0,C|0,k&~o^r&o|0,m&~p^q&p|0)|0;O=72+(j<<3)|0;O=qc(n|0,C|0,c[O>>2]|0,c[O+4>>2]|0)|0;n=b;g=c[n>>2]|0;n=c[n+4>>2]|0;s=F+(j<<3)|0;c[s>>2]=g;c[s+4>>2]=n;n=qc(O|0,C|0,g|0,n|0)|0;g=C;O=mc(l|0,u|0,28)|0;s=C;N=nc(l|0,u|0,36)|0;s=s|C;M=mc(l|0,u|0,34)|0;y=C;h=nc(l|0,u|0,30)|0;y=s^(y|C);s=mc(l|0,u|0,39)|0;x=C;v=nc(l|0,u|0,25)|0;x=qc((O|N)^(M|h)^(s|v)|0,y^(x|C)|0,l&(z^t)^z&t|0,u&(a^w)^a&w|0)|0;y=C;e=qc(n|0,g|0,e|0,f|0)|0;f=C;g=qc(x|0,y|0,n|0,g|0)|0;n=C;j=j+1|0;if((j|0)==16){y=16;x=e;v=f;s=p;p=g;j=t;h=u;g=w;b=z;break}else{x=p;y=o;h=m;M=k;N=u;O=l;b=b+8|0;l=g;u=n;o=e;p=f;m=q;k=r;q=x;r=y;g=M;f=a;e=z;a=w;w=N;z=t;t=O}}while(1){t=y;y=y+1|0;T=F+((y&15)<<3)|0;W=c[T>>2]|0;T=c[T+4>>2]|0;S=mc(W|0,T|0,1)|0;Q=C;R=nc(W|0,T|0,63)|0;Q=Q|C;V=mc(W|0,T|0,8)|0;O=C;U=nc(W|0,T|0,56)|0;O=O|C;T=mc(W|0,T|0,7)|0;Q=O^C^Q;O=F+((t+14&15)<<3)|0;W=c[O>>2]|0;O=c[O+4>>2]|0;u=mc(W|0,O|0,19)|0;e=C;f=nc(W|0,O|0,45)|0;e=e|C;N=mc(W|0,O|0,61)|0;_=C;w=nc(W|0,O|0,3)|0;_=_|C;O=mc(W|0,O|0,6)|0;e=_^C^e;_=mc(x|0,v|0,14)|0;W=C;Z=nc(x|0,v|0,50)|0;W=W|C;Y=mc(x|0,v|0,18)|0;P=C;X=nc(x|0,v|0,46)|0;P=W^(P|C);W=mc(x|0,v|0,41)|0;z=C;M=nc(x|0,v|0,23)|0;m=qc((_|Z)^(Y|X)^(W|M)|0,P^(z|C)|0,k|0,m|0)|0;m=qc(m|0,C|0,r&~x^o&x|0,q&~v^s&v|0)|0;z=72+(t<<3)|0;z=qc(m|0,C|0,c[z>>2]|0,c[z+4>>2]|0)|0;m=C;P=F+((t+9&15)<<3)|0;t=F+((t&15)<<3)|0;M=t;k=c[M>>2]|0;M=c[M+4>>2]|0;P=qc((V|U)^T^(S|R)|0,Q|0,c[P>>2]|0,c[P+4>>2]|0)|0;M=qc(P|0,C|0,k|0,M|0)|0;e=qc(M|0,C|0,(N|w)^O^(u|f)|0,e|0)|0;f=C;c[t>>2]=e;c[t+4>>2]=f;f=qc(z|0,m|0,e|0,f|0)|0;e=C;m=mc(p|0,n|0,28)|0;z=C;t=nc(p|0,n|0,36)|0;z=z|C;u=mc(p|0,n|0,34)|0;O=C;w=nc(p|0,n|0,30)|0;O=z^(O|C);z=mc(p|0,n|0,39)|0;N=C;M=nc(p|0,n|0,25)|0;N=qc((m|t)^(u|w)^(z|M)|0,O^(N|C)|0,p&(j^l)^j&l|0,n&(g^h)^g&h|0)|0;O=C;a=qc(f|0,e|0,b|0,a|0)|0;b=C;e=qc(N|0,O|0,f|0,e|0)|0;f=C;if((y|0)==80)break;else{X=n;Y=p;Z=v;_=x;m=q;k=r;x=a;v=b;p=e;n=f;a=g;b=j;g=h;h=X;j=l;l=Y;q=s;r=o;s=Z;o=_}}_=qc(J|0,K|0,e|0,f|0)|0;Z=d;c[Z>>2]=_;c[Z+4>>2]=C;Z=B;Z=qc(c[Z>>2]|0,c[Z+4>>2]|0,p|0,n|0)|0;_=d+8|0;c[_>>2]=Z;c[_+4>>2]=C;_=D;_=qc(c[_>>2]|0,c[_+4>>2]|0,l|0,h|0)|0;Z=d+16|0;c[Z>>2]=_;c[Z+4>>2]=C;Z=E;Z=qc(c[Z>>2]|0,c[Z+4>>2]|0,j|0,g|0)|0;_=d+24|0;c[_>>2]=Z;c[_+4>>2]=C;_=G;_=qc(c[_>>2]|0,c[_+4>>2]|0,a|0,b|0)|0;Z=d+32|0;c[Z>>2]=_;c[Z+4>>2]=C;Z=H;Z=qc(c[Z>>2]|0,c[Z+4>>2]|0,x|0,v|0)|0;_=d+40|0;c[_>>2]=Z;c[_+4>>2]=C;_=I;_=qc(c[_>>2]|0,c[_+4>>2]|0,o|0,s|0)|0;Z=d+48|0;c[Z>>2]=_;c[Z+4>>2]=C;Z=A;Z=qc(c[Z>>2]|0,c[Z+4>>2]|0,r|0,q|0)|0;_=d+56|0;c[_>>2]=Z;c[_+4>>2]=C;i=L;return}function Hb(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0;do if(e|0){o=b+64|0;g=o;h=c[g>>2]|0;g=c[g+4>>2]|0;f=mc(h|0,g|0,3)|0;f=f&127;if(f){i=128-f|0;j=b+80|0;f=j+f|0;if(i>>>0>e>>>0){tc(f|0,d|0,e|0)|0;n=e<<3;m=qc(h|0,g|0,n|0,0)|0;l=C;c[o>>2]=m;c[o+4>>2]=l;if(!(l>>>0<0|(l|0)==0&m>>>0>>0))break;o=b+72|0;b=o;b=qc(c[b>>2]|0,c[b+4>>2]|0,1,0)|0;c[o>>2]=b;c[o+4>>2]=C;break}tc(f|0,d|0,i|0)|0;n=i<<3;m=qc(h|0,g|0,n|0,0)|0;l=C;k=o;c[k>>2]=m;c[k+4>>2]=l;if(l>>>0<0|(l|0)==0&m>>>0>>0){n=b+72|0;m=n;m=qc(c[m>>2]|0,c[m+4>>2]|0,1,0)|0;c[n>>2]=m;c[n+4>>2]=C}e=e-i|0;f=0;do{n=b+80+(f<<3)|0;m=n;m=ma(c[m>>2]|0,c[m+4>>2]|0)|0;c[n>>2]=m;c[n+4>>2]=C;f=f+1|0}while((f|0)!=16);Gb(b,j,b);d=d+i|0}if(e>>>0>127){j=b+80|0;k=b+72|0;m=e+-128|0;n=m&-128;l=n+128|0;i=d;while(1){f=j;g=i;h=f+128|0;do{a[f>>0]=a[g>>0]|0;f=f+1|0;g=g+1|0}while((f|0)<(h|0));f=0;do{h=b+80+(f<<3)|0;g=h;g=ma(c[g>>2]|0,c[g+4>>2]|0)|0;c[h>>2]=g;c[h+4>>2]=C;f=f+1|0}while((f|0)!=16);Gb(b,j,b);g=o;h=c[g>>2]|0;g=c[g+4>>2]|0;p=qc(h|0,g|0,1024,0)|0;f=o;c[f>>2]=p;c[f+4>>2]=C;if(g>>>0>4294967295|(g|0)==-1&h>>>0>4294966271){h=k;h=qc(c[h>>2]|0,c[h+4>>2]|0,1,0)|0;p=k;c[p>>2]=h;c[p+4>>2]=C}e=e+-128|0;if(e>>>0<=127)break;else i=i+128|0}d=d+l|0;e=m-n|0}if(e|0?(tc(b+80|0,d|0,e|0)|0,p=e<<3,n=o,n=qc(c[n>>2]|0,c[n+4>>2]|0,p|0,0)|0,m=C,o,c[o>>2]=n,c[o+4>>2]=m,m>>>0<0|(m|0)==0&n>>>0

>>0):0){p=b+72|0;o=p;o=qc(c[o>>2]|0,c[o+4>>2]|0,1,0)|0;c[p>>2]=o;c[p+4>>2]=C}}while(0);return}function Ib(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0;if(d){h=b+64|0;f=h;f=mc(c[f>>2]|0,c[f+4>>2]|0,3)|0;f=f&127;e=f+1|0;g=b+80|0;a[g+f>>0]=-128;if(e>>>0>112){lc(g+e|0,0,f^127|0)|0;e=0;do{f=b+80+(e<<3)|0;i=f;i=ma(c[i>>2]|0,c[i+4>>2]|0)|0;c[f>>2]=i;c[f+4>>2]=C;e=e+1|0}while((e|0)!=16);Gb(b,g,b);e=0}lc(g+e|0,0,112-e|0)|0;e=0;do{i=b+80+(e<<3)|0;f=i;f=ma(c[f>>2]|0,c[f+4>>2]|0)|0;c[i>>2]=f;c[i+4>>2]=C;e=e+1|0}while((e|0)!=14);f=b+72|0;e=c[f+4>>2]|0;i=b+192|0;c[i>>2]=c[f>>2];c[i+4>>2]=e;i=c[h+4>>2]|0;e=b+200|0;c[e>>2]=c[h>>2];c[e+4>>2]=i;Gb(b,g,b);e=0;do{i=b+(e<<3)|0;h=i;h=ma(c[h>>2]|0,c[h+4>>2]|0)|0;c[i>>2]=h;c[i+4>>2]=C;e=e+1|0}while((e|0)!=8);e=d;f=b;g=e+64|0;do{a[e>>0]=a[f>>0]|0;e=e+1|0;f=f+1|0}while((e|0)<(g|0))}lc(b|0,0,208)|0;return}function Jb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0;g=i;i=i+208|0;e=g;f=e;h=8;j=f+64|0;do{c[f>>2]=c[h>>2];f=f+4|0;h=h+4|0}while((f|0)<(j|0));lc(e+64|0,0,144)|0;Hb(e,a,b);Ib(e,d);i=g;return}function Kb(){var a=0,b=0,d=0;d=i;i=i+16|0;b=d;a=c[9714]|0;if(!a){a=bc(38797,38810)|0;c[9714]=a}if((gc(b,1,4,a)|0)==4){i=d;return c[b>>2]|0}else pa(38812,38828,60,38838);return 0}function Lb(a){a=a|0;if(a>>>0>=256)if(a>>>0<65536)a=2;else a=a>>>0<16777216?3:4;else a=1;return a|0}function Mb(b,c){b=b|0;c=c|0;var d=0;if(b>>>0<=16777215)if(b>>>0<=65535){if(b>>>0>255)d=6}else d=4;else{a[c>>0]=b>>>24;c=c+1|0;d=4}if((d|0)==4){a[c>>0]=b>>>16;c=c+1|0;d=6}if((d|0)==6){a[c>>0]=b>>>8;c=c+1|0}a[c>>0]=b;return}function Nb(a){a=a|0;var b=0,d=0;b=i;i=i+16|0;d=b;c[d>>2]=c[a+60>>2];a=Qb(ha(6,d|0)|0)|0;i=b;return a|0}function Ob(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0;m=i;i=i+48|0;h=m+16|0;g=m;f=m+32|0;c[f>>2]=d;j=f+4|0;l=b+48|0;n=c[l>>2]|0;c[j>>2]=e-((n|0)!=0&1);k=b+44|0;c[f+8>>2]=c[k>>2];c[f+12>>2]=n;if(!(c[9715]|0)){c[h>>2]=c[b+60>>2];c[h+4>>2]=f;c[h+8>>2]=2;f=Qb(qa(145,h|0)|0)|0}else{ga(1,b|0);c[g>>2]=c[b+60>>2];c[g+4>>2]=f;c[g+8>>2]=2;f=Qb(qa(145,g|0)|0)|0;ba(0)}if((f|0)>=1){j=c[j>>2]|0;if(f>>>0>j>>>0){g=c[k>>2]|0;h=b+4|0;c[h>>2]=g;c[b+8>>2]=g+(f-j);if(!(c[l>>2]|0))f=e;else{c[h>>2]=g+1;a[d+(e+-1)>>0]=a[g>>0]|0;f=e}}}else{c[b>>2]=c[b>>2]|f&48^16;c[b+8>>2]=0;c[b+4>>2]=0}i=m;return f|0}function Pb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0;f=i;i=i+32|0;g=f;e=f+20|0;c[g>>2]=c[a+60>>2];c[g+4>>2]=0;c[g+8>>2]=b;c[g+12>>2]=e;c[g+16>>2]=d;if((Qb(ja(140,g|0)|0)|0)<0){c[e>>2]=-1;a=-1}else a=c[e>>2]|0;i=f;return a|0}function Qb(a){a=a|0;if(a>>>0>4294963200){c[(Rb()|0)>>2]=0-a;a=-1}return a|0}function Rb(){var a=0;if(!(c[9715]|0))a=38904;else a=c[(uc()|0)+64>>2]|0;return a|0}function Sb(a){a=a|0;if(!(c[a+68>>2]|0))Tb(a);return}function Tb(a){a=a|0;return}function Ub(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0;q=i;i=i+48|0;n=q+16|0;m=q;j=q+32|0;o=a+28|0;h=c[o>>2]|0;c[j>>2]=h;p=a+20|0;h=(c[p>>2]|0)-h|0;c[j+4>>2]=h;c[j+8>>2]=b;c[j+12>>2]=d;k=a+60|0;l=a+44|0;g=2;b=h+d|0;while(1){if(!(c[9715]|0)){c[n>>2]=c[k>>2];c[n+4>>2]=j;c[n+8>>2]=g;f=Qb(ra(146,n|0)|0)|0}else{ga(2,a|0);c[m>>2]=c[k>>2];c[m+4>>2]=j;c[m+8>>2]=g;f=Qb(ra(146,m|0)|0)|0;ba(0)}if((b|0)==(f|0)){b=6;break}if((f|0)<0){b=8;break}b=b-f|0;e=c[j+4>>2]|0;if(f>>>0<=e>>>0)if((g|0)==2){c[o>>2]=(c[o>>2]|0)+f;g=2;h=j}else h=j;else{h=c[l>>2]|0;c[o>>2]=h;c[p>>2]=h;f=f-e|0;g=g+-1|0;h=j+8|0;e=c[j+12>>2]|0}c[h>>2]=(c[h>>2]|0)+f;c[h+4>>2]=e-f;j=h}if((b|0)==6){n=c[l>>2]|0;c[a+16>>2]=n+(c[a+48>>2]|0);a=n;c[o>>2]=a;c[p>>2]=a}else if((b|0)==8){c[a+16>>2]=0;c[o>>2]=0;c[p>>2]=0;c[a>>2]=c[a>>2]|32;if((g|0)==2)d=0;else d=d-(c[j+4>>2]|0)|0}i=q;return d|0}function Vb(a){a=a|0;if(!(c[a+68>>2]|0))Tb(a);return}function Wb(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0;g=i;i=i+80|0;f=g;c[b+36>>2]=3;if((c[b>>2]&64|0)==0?(c[f>>2]=c[b+60>>2],c[f+4>>2]=21505,c[f+8>>2]=g+12,da(54,f|0)|0):0)a[b+75>>0]=-1;f=Ub(b,d,e)|0;i=g;return f|0}function Xb(b){b=b|0;var d=0,e=0;d=b+74|0;e=a[d>>0]|0;a[d>>0]=e+255|e;d=b+20|0;e=b+44|0;if((c[d>>2]|0)>>>0>(c[e>>2]|0)>>>0)va[c[b+36>>2]&7](b,0,0)|0;c[b+16>>2]=0;c[b+28>>2]=0;c[d>>2]=0;d=c[b>>2]|0;if(d&20)if(!(d&4))d=-1;else{c[b>>2]=d|32;d=-1}else{d=c[e>>2]|0;c[b+8>>2]=d;c[b+4>>2]=d;d=0}return d|0}function Yb(a){a=a|0;return 0}function Zb(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,i=0;h=d&255;f=(e|0)!=0;a:do if(f&(b&3|0)!=0){g=d&255;while(1){if((a[b>>0]|0)==g<<24>>24){i=6;break a}b=b+1|0;e=e+-1|0;f=(e|0)!=0;if(!(f&(b&3|0)!=0)){i=5;break}}}else i=5;while(0);if((i|0)==5)if(f)i=6;else e=0;b:do if((i|0)==6){g=d&255;if((a[b>>0]|0)!=g<<24>>24){f=R(h,16843009)|0;c:do if(e>>>0>3)while(1){h=c[b>>2]^f;if((h&-2139062144^-2139062144)&h+-16843009|0)break;b=b+4|0;e=e+-4|0;if(e>>>0<=3){i=11;break c}}else i=11;while(0);if((i|0)==11)if(!e){e=0;break}while(1){if((a[b>>0]|0)==g<<24>>24)break b;b=b+1|0;e=e+-1|0;if(!e){e=0;break}}}}while(0);return (e|0?b:0)|0}function _b(b){b=b|0;var d=0,e=0,f=0;f=b;a:do if(!(f&3))e=4;else{d=f;while(1){if(!(a[b>>0]|0)){b=d;break a}b=b+1|0;d=b;if(!(d&3)){e=4;break}}}while(0);if((e|0)==4){while(1){d=c[b>>2]|0;if(!((d&-2139062144^-2139062144)&d+-16843009))b=b+4|0;else break}if((d&255)<<24>>24)do b=b+1|0;while((a[b>>0]|0)!=0)}return b-f|0}function $b(b,c){b=b|0;c=c|0;b=ac(b,c)|0;return ((a[b>>0]|0)==(c&255)<<24>>24?b:0)|0}function ac(b,d){b=b|0;d=d|0;var e=0,f=0,g=0;f=d&255;a:do if(!f)b=b+(_b(b)|0)|0;else{if(b&3){e=d&255;do{g=a[b>>0]|0;if(g<<24>>24==0?1:g<<24>>24==e<<24>>24)break a;b=b+1|0}while((b&3|0)!=0)}f=R(f,16843009)|0;e=c[b>>2]|0;b:do if(!((e&-2139062144^-2139062144)&e+-16843009))do{g=e^f;if((g&-2139062144^-2139062144)&g+-16843009|0)break b;b=b+4|0;e=c[b>>2]|0}while(!((e&-2139062144^-2139062144)&e+-16843009|0));while(0);e=d&255;while(1){g=a[b>>0]|0;if(g<<24>>24==0?1:g<<24>>24==e<<24>>24)break;else b=b+1|0}}while(0);return b|0}function bc(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0;g=i;i=i+32|0;f=g+16|0;e=g;if(Zb(38847,a[d>>0]|0,4)|0){h=cc(d)|0|32768;c[e>>2]=b;c[e+4>>2]=h;c[e+8>>2]=438;e=Qb(ka(5,e|0)|0)|0;if((e|0)>=0){b=dc(e,d)|0;if(!b){c[f>>2]=e;ha(6,f|0)|0;b=0}}else b=0}else{c[(Rb()|0)>>2]=22;b=0}i=g;return b|0}function cc(b){b=b|0;var c=0,d=0,e=0;d=($b(b,43)|0)==0;c=a[b>>0]|0;d=d?c<<24>>24!=114&1:2;e=($b(b,120)|0)==0;d=e?d:d|128;b=($b(b,101)|0)==0;b=b?d:d|524288;b=c<<24>>24==114?b:b|64;b=c<<24>>24==119?b|512:b;return (c<<24>>24==97?b|1024:b)|0}function dc(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0;o=i;i=i+112|0;n=o+40|0;l=o+24|0;k=o+16|0;g=o;m=o+52|0;f=a[d>>0]|0;if(Zb(38847,f<<24>>24,4)|0){e=hc(1144)|0;if(!e)e=0;else{h=e;j=h+112|0;do{c[h>>2]=0;h=h+4|0}while((h|0)<(j|0));if(!($b(d,43)|0))c[e>>2]=f<<24>>24==114?8:4;if($b(d,101)|0){c[g>>2]=b;c[g+4>>2]=2;c[g+8>>2]=1;ca(221,g|0)|0;f=a[d>>0]|0}if(f<<24>>24==97){c[k>>2]=b;c[k+4>>2]=3;f=ca(221,k|0)|0;if(!(f&1024)){c[l>>2]=b;c[l+4>>2]=4;c[l+8>>2]=f|1024;ca(221,l|0)|0}d=c[e>>2]|128;c[e>>2]=d}else d=c[e>>2]|0;c[e+60>>2]=b;c[e+44>>2]=e+120;c[e+48>>2]=1024;f=e+75|0;a[f>>0]=-1;if((d&8|0)==0?(c[n>>2]=b,c[n+4>>2]=21505,c[n+8>>2]=m,(da(54,n|0)|0)==0):0)a[f>>0]=10;c[e+32>>2]=4;c[e+36>>2]=3;c[e+40>>2]=2;c[e+12>>2]=1;if(!(c[9716]|0))c[e+76>>2]=-1;ea(38888);f=c[9721]|0;c[e+56>>2]=f;if(f|0)c[f+52>>2]=e;c[9721]=e;na(38888)}}else{c[(Rb()|0)>>2]=22;e=0}i=o;return e|0}function ec(a){a=a|0;var b=0,d=0;do if(a){if((c[a+76>>2]|0)<=-1){b=fc(a)|0;break}d=(Yb(a)|0)==0;b=fc(a)|0;if(!d)Tb(a)}else{if(!(c[9549]|0))b=0;else b=ec(c[9549]|0)|0;ea(38888);a=c[9721]|0;if(a)do{if((c[a+76>>2]|0)>-1)d=Yb(a)|0;else d=0;if((c[a+20>>2]|0)>>>0>(c[a+28>>2]|0)>>>0)b=fc(a)|0|b;if(d|0)Tb(a);a=c[a+56>>2]|0}while((a|0)!=0);na(38888)}while(0);return b|0}function fc(a){a=a|0;var b=0,d=0,e=0,f=0,g=0,h=0;b=a+20|0;h=a+28|0;if((c[b>>2]|0)>>>0>(c[h>>2]|0)>>>0?(va[c[a+36>>2]&7](a,0,0)|0,(c[b>>2]|0)==0):0)a=-1;else{d=a+4|0;e=c[d>>2]|0;f=a+8|0;g=c[f>>2]|0;if(e>>>0>>0)va[c[a+40>>2]&7](a,e-g|0,1)|0;c[a+16>>2]=0;c[h>>2]=0;c[b>>2]=0;c[f>>2]=0;c[d>>2]=0;a=0}return a|0}function gc(b,d,e,f){b=b|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,i=0,j=0,k=0,l=0;k=R(e,d)|0;if((c[f+76>>2]|0)>-1)j=Yb(f)|0;else j=0;g=f+74|0;i=a[g>>0]|0;a[g>>0]=i+255|i;g=f+4|0;i=c[g>>2]|0;h=(c[f+8>>2]|0)-i|0;if((h|0)>0){h=h>>>0>>0?h:k;tc(b|0,i|0,h|0)|0;c[g>>2]=i+h;g=k-h|0;b=b+h|0}else g=k;a:do if(!g)l=13;else{i=f+32|0;while(1){if(Xb(f)|0)break;h=va[c[i>>2]&7](f,b,g)|0;if((h+1|0)>>>0<2)break;g=g-h|0;if(!g){l=13;break a}else b=b+h|0}if(j|0)Tb(f);e=((k-g|0)>>>0)/(d>>>0)|0}while(0);if((l|0)==13)if(j)Tb(f);return e|0}function hc(a){a=a|0;var b=0,d=0,e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0;L=i;i=i+16|0;p=L;do if(a>>>0<245){o=a>>>0<11?16:a+11&-8;a=o>>>3;t=c[9727]|0;d=t>>>a;if(d&3|0){a=(d&1^1)+a|0;d=38948+(a<<1<<2)|0;e=d+8|0;f=c[e>>2]|0;g=f+8|0;h=c[g>>2]|0;do if((d|0)!=(h|0)){if(h>>>0<(c[9731]|0)>>>0)fa();b=h+12|0;if((c[b>>2]|0)==(f|0)){c[b>>2]=d;c[e>>2]=h;break}else fa()}else c[9727]=t&~(1<>2]=K|3;K=f+K+4|0;c[K>>2]=c[K>>2]|1;K=g;i=L;return K|0}s=c[9729]|0;if(o>>>0>s>>>0){if(d|0){j=2<>>12&16;a=a>>>j;e=a>>>5&8;a=a>>>e;g=a>>>2&4;a=a>>>g;d=a>>>1&2;a=a>>>d;b=a>>>1&1;b=(e|j|g|d|b)+(a>>>b)|0;a=38948+(b<<1<<2)|0;d=a+8|0;g=c[d>>2]|0;j=g+8|0;e=c[j>>2]|0;do if((a|0)!=(e|0)){if(e>>>0<(c[9731]|0)>>>0)fa();f=e+12|0;if((c[f>>2]|0)==(g|0)){c[f>>2]=a;c[d>>2]=e;k=t;break}else fa()}else{k=t&~(1<>2]=o|3;e=g+o|0;c[e+4>>2]=h|1;c[e+h>>2]=h;if(s|0){f=c[9732]|0;b=s>>>3;d=38948+(b<<1<<2)|0;b=1<>2]|0;if(a>>>0<(c[9731]|0)>>>0)fa();else{l=a;m=b}}else{c[9727]=k|b;l=d;m=d+8|0}c[m>>2]=f;c[l+12>>2]=f;c[f+8>>2]=l;c[f+12>>2]=d}c[9729]=h;c[9732]=e;K=j;i=L;return K|0}l=c[9728]|0;if(l){a=(l&0-l)+-1|0;J=a>>>12&16;a=a>>>J;I=a>>>5&8;a=a>>>I;K=a>>>2&4;a=a>>>K;j=a>>>1&2;a=a>>>j;k=a>>>1&1;k=c[39212+((I|J|K|j|k)+(a>>>k)<<2)>>2]|0;a=k;j=k;k=(c[k+4>>2]&-8)-o|0;while(1){b=c[a+16>>2]|0;if(!b){b=c[a+20>>2]|0;if(!b)break}K=(c[b+4>>2]&-8)-o|0;J=K>>>0>>0;a=b;j=J?b:j;k=J?K:k}f=c[9731]|0;if(j>>>0>>0)fa();h=j+o|0;if(j>>>0>=h>>>0)fa();g=c[j+24>>2]|0;d=c[j+12>>2]|0;do if((d|0)==(j|0)){a=j+20|0;b=c[a>>2]|0;if(!b){a=j+16|0;b=c[a>>2]|0;if(!b){n=0;break}}while(1){d=b+20|0;e=c[d>>2]|0;if(e|0){b=e;a=d;continue}d=b+16|0;e=c[d>>2]|0;if(!e)break;else{b=e;a=d}}if(a>>>0>>0)fa();else{c[a>>2]=0;n=b;break}}else{e=c[j+8>>2]|0;if(e>>>0>>0)fa();b=e+12|0;if((c[b>>2]|0)!=(j|0))fa();a=d+8|0;if((c[a>>2]|0)==(j|0)){c[b>>2]=d;c[a>>2]=e;n=d;break}else fa()}while(0);do if(g|0){b=c[j+28>>2]|0;a=39212+(b<<2)|0;if((j|0)==(c[a>>2]|0)){c[a>>2]=n;if(!n){c[9728]=l&~(1<>>0<(c[9731]|0)>>>0)fa();b=g+16|0;if((c[b>>2]|0)==(j|0))c[b>>2]=n;else c[g+20>>2]=n;if(!n)break}a=c[9731]|0;if(n>>>0>>0)fa();c[n+24>>2]=g;b=c[j+16>>2]|0;do if(b|0)if(b>>>0>>0)fa();else{c[n+16>>2]=b;c[b+24>>2]=n;break}while(0);b=c[j+20>>2]|0;if(b|0)if(b>>>0<(c[9731]|0)>>>0)fa();else{c[n+20>>2]=b;c[b+24>>2]=n;break}}while(0);if(k>>>0<16){K=k+o|0;c[j+4>>2]=K|3;K=j+K+4|0;c[K>>2]=c[K>>2]|1}else{c[j+4>>2]=o|3;c[h+4>>2]=k|1;c[h+k>>2]=k;if(s|0){e=c[9732]|0;b=s>>>3;d=38948+(b<<1<<2)|0;b=1<>2]|0;if(a>>>0<(c[9731]|0)>>>0)fa();else{q=a;r=b}}else{c[9727]=t|b;q=d;r=d+8|0}c[r>>2]=e;c[q+12>>2]=e;c[e+8>>2]=q;c[e+12>>2]=d}c[9729]=k;c[9732]=h}K=j+8|0;i=L;return K|0}}}else if(a>>>0<=4294967231){a=a+11|0;o=a&-8;l=c[9728]|0;if(l){e=0-o|0;a=a>>>8;if(a)if(o>>>0>16777215)k=31;else{r=(a+1048320|0)>>>16&8;D=a<>>16&4;D=D<>>16&2;k=14-(q|r|k)+(D<>>15)|0;k=o>>>(k+7|0)&1|k<<1}else k=0;a=c[39212+(k<<2)>>2]|0;a:do if(!a){d=0;f=0;D=86}else{f=0;j=a;h=o<<((k|0)==31?0:25-(k>>>1)|0);d=0;while(1){a=(c[j+4>>2]&-8)-o|0;if(a>>>0>>0)if(!a){a=j;e=0;d=j;D=90;break a}else{f=j;e=a}a=c[j+20>>2]|0;j=c[j+16+(h>>>31<<2)>>2]|0;d=(a|0)==0|(a|0)==(j|0)?d:a;a=(j|0)==0;if(a){D=86;break}else h=h<<(a&1^1)}}while(0);if((D|0)==86){if((d|0)==0&(f|0)==0){a=2<>>12&16;r=r>>>m;k=r>>>5&8;r=r>>>k;n=r>>>2&4;r=r>>>n;q=r>>>1&2;r=r>>>q;d=r>>>1&1;d=c[39212+((k|m|n|q|d)+(r>>>d)<<2)>>2]|0}if(!d){k=f;j=e}else{a=f;D=90}}if((D|0)==90)while(1){D=0;r=(c[d+4>>2]&-8)-o|0;f=r>>>0>>0;e=f?r:e;a=f?d:a;f=c[d+16>>2]|0;if(f|0){d=f;D=90;continue}d=c[d+20>>2]|0;if(!d){k=a;j=e;break}else D=90}if((k|0)!=0?j>>>0<((c[9729]|0)-o|0)>>>0:0){f=c[9731]|0;if(k>>>0>>0)fa();h=k+o|0;if(k>>>0>=h>>>0)fa();g=c[k+24>>2]|0;d=c[k+12>>2]|0;do if((d|0)==(k|0)){a=k+20|0;b=c[a>>2]|0;if(!b){a=k+16|0;b=c[a>>2]|0;if(!b){s=0;break}}while(1){d=b+20|0;e=c[d>>2]|0;if(e|0){b=e;a=d;continue}d=b+16|0;e=c[d>>2]|0;if(!e)break;else{b=e;a=d}}if(a>>>0>>0)fa();else{c[a>>2]=0;s=b;break}}else{e=c[k+8>>2]|0;if(e>>>0>>0)fa();b=e+12|0;if((c[b>>2]|0)!=(k|0))fa();a=d+8|0;if((c[a>>2]|0)==(k|0)){c[b>>2]=d;c[a>>2]=e;s=d;break}else fa()}while(0);do if(g){b=c[k+28>>2]|0;a=39212+(b<<2)|0;if((k|0)==(c[a>>2]|0)){c[a>>2]=s;if(!s){t=l&~(1<>>0<(c[9731]|0)>>>0)fa();b=g+16|0;if((c[b>>2]|0)==(k|0))c[b>>2]=s;else c[g+20>>2]=s;if(!s){t=l;break}}a=c[9731]|0;if(s>>>0>>0)fa();c[s+24>>2]=g;b=c[k+16>>2]|0;do if(b|0)if(b>>>0>>0)fa();else{c[s+16>>2]=b;c[b+24>>2]=s;break}while(0);b=c[k+20>>2]|0;if(b)if(b>>>0<(c[9731]|0)>>>0)fa();else{c[s+20>>2]=b;c[b+24>>2]=s;t=l;break}else t=l}else t=l;while(0);do if(j>>>0>=16){c[k+4>>2]=o|3;c[h+4>>2]=j|1;c[h+j>>2]=j;b=j>>>3;if(j>>>0<256){d=38948+(b<<1<<2)|0;a=c[9727]|0;b=1<>2]|0;if(a>>>0<(c[9731]|0)>>>0)fa();else{B=a;C=b}}else{c[9727]=a|b;B=d;C=d+8|0}c[C>>2]=h;c[B+12>>2]=h;c[h+8>>2]=B;c[h+12>>2]=d;break}b=j>>>8;if(b)if(j>>>0>16777215)b=31;else{J=(b+1048320|0)>>>16&8;K=b<>>16&4;K=K<>>16&2;b=14-(I|J|b)+(K<>>15)|0;b=j>>>(b+7|0)&1|b<<1}else b=0;d=39212+(b<<2)|0;c[h+28>>2]=b;a=h+16|0;c[a+4>>2]=0;c[a>>2]=0;a=1<>2]=h;c[h+24>>2]=d;c[h+12>>2]=h;c[h+8>>2]=h;break}a=j<<((b|0)==31?0:25-(b>>>1)|0);e=c[d>>2]|0;while(1){if((c[e+4>>2]&-8|0)==(j|0)){D=148;break}d=e+16+(a>>>31<<2)|0;b=c[d>>2]|0;if(!b){D=145;break}else{a=a<<1;e=b}}if((D|0)==145)if(d>>>0<(c[9731]|0)>>>0)fa();else{c[d>>2]=h;c[h+24>>2]=e;c[h+12>>2]=h;c[h+8>>2]=h;break}else if((D|0)==148){b=e+8|0;a=c[b>>2]|0;K=c[9731]|0;if(a>>>0>=K>>>0&e>>>0>=K>>>0){c[a+12>>2]=h;c[b>>2]=h;c[h+8>>2]=a;c[h+12>>2]=e;c[h+24>>2]=0;break}else fa()}}else{K=j+o|0;c[k+4>>2]=K|3;K=k+K+4|0;c[K>>2]=c[K>>2]|1}while(0);K=k+8|0;i=L;return K|0}}}else o=-1;while(0);d=c[9729]|0;if(d>>>0>=o>>>0){b=d-o|0;a=c[9732]|0;if(b>>>0>15){K=a+o|0;c[9732]=K;c[9729]=b;c[K+4>>2]=b|1;c[K+b>>2]=b;c[a+4>>2]=o|3}else{c[9729]=0;c[9732]=0;c[a+4>>2]=d|3;K=a+d+4|0;c[K>>2]=c[K>>2]|1}K=a+8|0;i=L;return K|0}j=c[9730]|0;if(j>>>0>o>>>0){I=j-o|0;c[9730]=I;K=c[9733]|0;J=K+o|0;c[9733]=J;c[J+4>>2]=I|1;c[K+4>>2]=o|3;K=K+8|0;i=L;return K|0}if(!(c[9845]|0)){c[9847]=4096;c[9846]=4096;c[9848]=-1;c[9849]=-1;c[9850]=0;c[9838]=0;a=p&-16^1431655768;c[p>>2]=a;c[9845]=a;a=4096}else a=c[9847]|0;k=o+48|0;l=o+47|0;h=a+l|0;f=0-a|0;m=h&f;if(m>>>0<=o>>>0){K=0;i=L;return K|0}a=c[9837]|0;if(a|0?(B=c[9835]|0,C=B+m|0,C>>>0<=B>>>0|C>>>0>a>>>0):0){K=0;i=L;return K|0}b:do if(!(c[9838]&4)){d=c[9733]|0;c:do if(d){e=39356;while(1){a=c[e>>2]|0;if(a>>>0<=d>>>0?(u=e+4|0,(a+(c[u>>2]|0)|0)>>>0>d>>>0):0)break;a=c[e+8>>2]|0;if(!a){D=172;break c}else e=a}d=h-j&f;if(d>>>0<2147483647){a=rc(d|0)|0;if((a|0)==((c[e>>2]|0)+(c[u>>2]|0)|0)){if((a|0)!=(-1|0)){h=d;g=a;D=190;break b}}else{b=d;D=180}}}else D=172;while(0);do if(((D|0)==172?(g=rc(0)|0,(g|0)!=(-1|0)):0)?(b=g,v=c[9846]|0,w=v+-1|0,b=((w&b|0)==0?0:(w+b&0-v)-b|0)+m|0,v=c[9835]|0,w=b+v|0,b>>>0>o>>>0&b>>>0<2147483647):0){C=c[9837]|0;if(C|0?w>>>0<=v>>>0|w>>>0>C>>>0:0)break;a=rc(b|0)|0;if((a|0)==(g|0)){h=b;D=190;break b}else D=180}while(0);d:do if((D|0)==180){d=0-b|0;do if(k>>>0>b>>>0&(b>>>0<2147483647&(a|0)!=(-1|0))?(x=c[9847]|0,x=l-b+x&0-x,x>>>0<2147483647):0)if((rc(x|0)|0)==(-1|0)){rc(d|0)|0;break d}else{b=x+b|0;break}while(0);if((a|0)!=(-1|0)){h=b;g=a;D=190;break b}}while(0);c[9838]=c[9838]|4;D=187}else D=187;while(0);if((((D|0)==187?m>>>0<2147483647:0)?(A=rc(m|0)|0,y=rc(0)|0,A>>>0>>0&((A|0)!=(-1|0)&(y|0)!=(-1|0))):0)?(z=y-A|0,z>>>0>(o+40|0)>>>0):0){h=z;g=A;D=190}if((D|0)==190){b=(c[9835]|0)+h|0;c[9835]=b;if(b>>>0>(c[9836]|0)>>>0)c[9836]=b;l=c[9733]|0;do if(l){b=39356;while(1){a=c[b>>2]|0;d=b+4|0;e=c[d>>2]|0;if((g|0)==(a+e|0)){D=200;break}f=c[b+8>>2]|0;if(!f)break;else b=f}if(((D|0)==200?(c[b+12>>2]&8|0)==0:0)?l>>>0>>0&l>>>0>=a>>>0:0){c[d>>2]=e+h;K=l+8|0;K=(K&7|0)==0?0:0-K&7;J=l+K|0;K=h-K+(c[9730]|0)|0;c[9733]=J;c[9730]=K;c[J+4>>2]=K|1;c[J+K+4>>2]=40;c[9734]=c[9849];break}b=c[9731]|0;if(g>>>0>>0){c[9731]=g;j=g}else j=b;a=g+h|0;b=39356;while(1){if((c[b>>2]|0)==(a|0)){D=208;break}b=c[b+8>>2]|0;if(!b){a=39356;break}}if((D|0)==208)if(!(c[b+12>>2]&8)){c[b>>2]=g;n=b+4|0;c[n>>2]=(c[n>>2]|0)+h;n=g+8|0;n=g+((n&7|0)==0?0:0-n&7)|0;b=a+8|0;b=a+((b&7|0)==0?0:0-b&7)|0;m=n+o|0;k=b-n-o|0;c[n+4>>2]=o|3;do if((b|0)!=(l|0)){if((b|0)==(c[9732]|0)){K=(c[9729]|0)+k|0;c[9729]=K;c[9732]=m;c[m+4>>2]=K|1;c[m+K>>2]=K;break}a=c[b+4>>2]|0;if((a&3|0)==1){h=a&-8;f=a>>>3;e:do if(a>>>0>=256){g=c[b+24>>2]|0;e=c[b+12>>2]|0;do if((e|0)==(b|0)){e=b+16|0;d=e+4|0;a=c[d>>2]|0;if(!a){a=c[e>>2]|0;if(!a){I=0;break}else d=e}while(1){e=a+20|0;f=c[e>>2]|0;if(f|0){a=f;d=e;continue}e=a+16|0;f=c[e>>2]|0;if(!f)break;else{a=f;d=e}}if(d>>>0>>0)fa();else{c[d>>2]=0;I=a;break}}else{f=c[b+8>>2]|0;if(f>>>0>>0)fa();a=f+12|0;if((c[a>>2]|0)!=(b|0))fa();d=e+8|0;if((c[d>>2]|0)==(b|0)){c[a>>2]=e;c[d>>2]=f;I=e;break}else fa()}while(0);if(!g)break;a=c[b+28>>2]|0;d=39212+(a<<2)|0;do if((b|0)!=(c[d>>2]|0)){if(g>>>0<(c[9731]|0)>>>0)fa();a=g+16|0;if((c[a>>2]|0)==(b|0))c[a>>2]=I;else c[g+20>>2]=I;if(!I)break e}else{c[d>>2]=I;if(I|0)break;c[9728]=c[9728]&~(1<>>0>>0)fa();c[I+24>>2]=g;a=b+16|0;d=c[a>>2]|0;do if(d|0)if(d>>>0>>0)fa();else{c[I+16>>2]=d;c[d+24>>2]=I;break}while(0);a=c[a+4>>2]|0;if(!a)break;if(a>>>0<(c[9731]|0)>>>0)fa();else{c[I+20>>2]=a;c[a+24>>2]=I;break}}else{d=c[b+8>>2]|0;e=c[b+12>>2]|0;a=38948+(f<<1<<2)|0;do if((d|0)!=(a|0)){if(d>>>0>>0)fa();if((c[d+12>>2]|0)==(b|0))break;fa()}while(0);if((e|0)==(d|0)){c[9727]=c[9727]&~(1<>>0>>0)fa();a=e+8|0;if((c[a>>2]|0)==(b|0)){F=a;break}fa()}while(0);c[d+12>>2]=e;c[F>>2]=d}while(0);b=b+h|0;f=h+k|0}else f=k;b=b+4|0;c[b>>2]=c[b>>2]&-2;c[m+4>>2]=f|1;c[m+f>>2]=f;b=f>>>3;if(f>>>0<256){d=38948+(b<<1<<2)|0;a=c[9727]|0;b=1<>2]|0;if(a>>>0>=(c[9731]|0)>>>0){J=a;K=b;break}fa()}while(0);c[K>>2]=m;c[J+12>>2]=m;c[m+8>>2]=J;c[m+12>>2]=d;break}b=f>>>8;do if(!b)b=0;else{if(f>>>0>16777215){b=31;break}J=(b+1048320|0)>>>16&8;K=b<>>16&4;K=K<>>16&2;b=14-(I|J|b)+(K<>>15)|0;b=f>>>(b+7|0)&1|b<<1}while(0);e=39212+(b<<2)|0;c[m+28>>2]=b;a=m+16|0;c[a+4>>2]=0;c[a>>2]=0;a=c[9728]|0;d=1<>2]=m;c[m+24>>2]=e;c[m+12>>2]=m;c[m+8>>2]=m;break}a=f<<((b|0)==31?0:25-(b>>>1)|0);e=c[e>>2]|0;while(1){if((c[e+4>>2]&-8|0)==(f|0)){D=278;break}d=e+16+(a>>>31<<2)|0;b=c[d>>2]|0;if(!b){D=275;break}else{a=a<<1;e=b}}if((D|0)==275)if(d>>>0<(c[9731]|0)>>>0)fa();else{c[d>>2]=m;c[m+24>>2]=e;c[m+12>>2]=m;c[m+8>>2]=m;break}else if((D|0)==278){b=e+8|0;a=c[b>>2]|0;K=c[9731]|0;if(a>>>0>=K>>>0&e>>>0>=K>>>0){c[a+12>>2]=m;c[b>>2]=m;c[m+8>>2]=a;c[m+12>>2]=e;c[m+24>>2]=0;break}else fa()}}else{K=(c[9730]|0)+k|0;c[9730]=K;c[9733]=m;c[m+4>>2]=K|1}while(0);K=n+8|0;i=L;return K|0}else a=39356;while(1){b=c[a>>2]|0;if(b>>>0<=l>>>0?(E=b+(c[a+4>>2]|0)|0,E>>>0>l>>>0):0)break;a=c[a+8>>2]|0}f=E+-47|0;a=f+8|0;a=f+((a&7|0)==0?0:0-a&7)|0;f=l+16|0;a=a>>>0>>0?l:a;b=a+8|0;d=g+8|0;d=(d&7|0)==0?0:0-d&7;K=g+d|0;d=h+-40-d|0;c[9733]=K;c[9730]=d;c[K+4>>2]=d|1;c[K+d+4>>2]=40;c[9734]=c[9849];d=a+4|0;c[d>>2]=27;c[b>>2]=c[9839];c[b+4>>2]=c[9840];c[b+8>>2]=c[9841];c[b+12>>2]=c[9842];c[9839]=g;c[9840]=h;c[9842]=0;c[9841]=b;b=a+24|0;do{b=b+4|0;c[b>>2]=7}while((b+4|0)>>>0>>0);if((a|0)!=(l|0)){g=a-l|0;c[d>>2]=c[d>>2]&-2;c[l+4>>2]=g|1;c[a>>2]=g;b=g>>>3;if(g>>>0<256){d=38948+(b<<1<<2)|0;a=c[9727]|0;b=1<>2]|0;if(a>>>0<(c[9731]|0)>>>0)fa();else{G=a;H=b}}else{c[9727]=a|b;G=d;H=d+8|0}c[H>>2]=l;c[G+12>>2]=l;c[l+8>>2]=G;c[l+12>>2]=d;break}b=g>>>8;if(b)if(g>>>0>16777215)d=31;else{J=(b+1048320|0)>>>16&8;K=b<>>16&4;K=K<>>16&2;d=14-(I|J|d)+(K<>>15)|0;d=g>>>(d+7|0)&1|d<<1}else d=0;e=39212+(d<<2)|0;c[l+28>>2]=d;c[l+20>>2]=0;c[f>>2]=0;b=c[9728]|0;a=1<>2]=l;c[l+24>>2]=e;c[l+12>>2]=l;c[l+8>>2]=l;break}a=g<<((d|0)==31?0:25-(d>>>1)|0);e=c[e>>2]|0;while(1){if((c[e+4>>2]&-8|0)==(g|0)){D=304;break}d=e+16+(a>>>31<<2)|0;b=c[d>>2]|0;if(!b){D=301;break}else{a=a<<1;e=b}}if((D|0)==301)if(d>>>0<(c[9731]|0)>>>0)fa();else{c[d>>2]=l;c[l+24>>2]=e;c[l+12>>2]=l;c[l+8>>2]=l;break}else if((D|0)==304){b=e+8|0;a=c[b>>2]|0;K=c[9731]|0;if(a>>>0>=K>>>0&e>>>0>=K>>>0){c[a+12>>2]=l;c[b>>2]=l;c[l+8>>2]=a;c[l+12>>2]=e;c[l+24>>2]=0;break}else fa()}}}else{K=c[9731]|0;if((K|0)==0|g>>>0>>0)c[9731]=g;c[9839]=g;c[9840]=h;c[9842]=0;c[9736]=c[9845];c[9735]=-1;b=0;do{K=38948+(b<<1<<2)|0;c[K+12>>2]=K;c[K+8>>2]=K;b=b+1|0}while((b|0)!=32);K=g+8|0;K=(K&7|0)==0?0:0-K&7;J=g+K|0;K=h+-40-K|0;c[9733]=J;c[9730]=K;c[J+4>>2]=K|1;c[J+K+4>>2]=40;c[9734]=c[9849]}while(0);b=c[9730]|0;if(b>>>0>o>>>0){I=b-o|0;c[9730]=I;K=c[9733]|0;J=K+o|0;c[9733]=J;c[J+4>>2]=I|1;c[K+4>>2]=o|3;K=K+8|0;i=L;return K|0}}c[(Rb()|0)>>2]=12;K=0;i=L;return K|0}function ic(a){a=a|0;var b=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0;if(!a)return;d=a+-8|0;h=c[9731]|0;if(d>>>0>>0)fa();a=c[a+-4>>2]|0;b=a&3;if((b|0)==1)fa();e=a&-8;n=d+e|0;do if(!(a&1)){a=c[d>>2]|0;if(!b)return;k=d+(0-a)|0;j=a+e|0;if(k>>>0>>0)fa();if((k|0)==(c[9732]|0)){a=n+4|0;b=c[a>>2]|0;if((b&3|0)!=3){q=k;f=j;break}c[9729]=j;c[a>>2]=b&-2;c[k+4>>2]=j|1;c[k+j>>2]=j;return}e=a>>>3;if(a>>>0<256){b=c[k+8>>2]|0;d=c[k+12>>2]|0;a=38948+(e<<1<<2)|0;if((b|0)!=(a|0)){if(b>>>0>>0)fa();if((c[b+12>>2]|0)!=(k|0))fa()}if((d|0)==(b|0)){c[9727]=c[9727]&~(1<>>0>>0)fa();a=d+8|0;if((c[a>>2]|0)==(k|0))g=a;else fa()}else g=d+8|0;c[b+12>>2]=d;c[g>>2]=b;q=k;f=j;break}g=c[k+24>>2]|0;d=c[k+12>>2]|0;do if((d|0)==(k|0)){d=k+16|0;b=d+4|0;a=c[b>>2]|0;if(!a){a=c[d>>2]|0;if(!a){i=0;break}else b=d}while(1){d=a+20|0;e=c[d>>2]|0;if(e|0){a=e;b=d;continue}d=a+16|0;e=c[d>>2]|0;if(!e)break;else{a=e;b=d}}if(b>>>0>>0)fa();else{c[b>>2]=0;i=a;break}}else{e=c[k+8>>2]|0;if(e>>>0>>0)fa();a=e+12|0;if((c[a>>2]|0)!=(k|0))fa();b=d+8|0;if((c[b>>2]|0)==(k|0)){c[a>>2]=d;c[b>>2]=e;i=d;break}else fa()}while(0);if(g){a=c[k+28>>2]|0;b=39212+(a<<2)|0;if((k|0)==(c[b>>2]|0)){c[b>>2]=i;if(!i){c[9728]=c[9728]&~(1<>>0<(c[9731]|0)>>>0)fa();a=g+16|0;if((c[a>>2]|0)==(k|0))c[a>>2]=i;else c[g+20>>2]=i;if(!i){q=k;f=j;break}}d=c[9731]|0;if(i>>>0>>0)fa();c[i+24>>2]=g;a=k+16|0;b=c[a>>2]|0;do if(b|0)if(b>>>0>>0)fa();else{c[i+16>>2]=b;c[b+24>>2]=i;break}while(0);a=c[a+4>>2]|0;if(a)if(a>>>0<(c[9731]|0)>>>0)fa();else{c[i+20>>2]=a;c[a+24>>2]=i;q=k;f=j;break}else{q=k;f=j}}else{q=k;f=j}}else{q=d;f=e}while(0);if(q>>>0>=n>>>0)fa();a=n+4|0;b=c[a>>2]|0;if(!(b&1))fa();if(!(b&2)){if((n|0)==(c[9733]|0)){p=(c[9730]|0)+f|0;c[9730]=p;c[9733]=q;c[q+4>>2]=p|1;if((q|0)!=(c[9732]|0))return;c[9732]=0;c[9729]=0;return}if((n|0)==(c[9732]|0)){p=(c[9729]|0)+f|0;c[9729]=p;c[9732]=q;c[q+4>>2]=p|1;c[q+p>>2]=p;return}f=(b&-8)+f|0;e=b>>>3;do if(b>>>0>=256){g=c[n+24>>2]|0;a=c[n+12>>2]|0;do if((a|0)==(n|0)){d=n+16|0;b=d+4|0;a=c[b>>2]|0;if(!a){a=c[d>>2]|0;if(!a){m=0;break}else b=d}while(1){d=a+20|0;e=c[d>>2]|0;if(e|0){a=e;b=d;continue}d=a+16|0;e=c[d>>2]|0;if(!e)break;else{a=e;b=d}}if(b>>>0<(c[9731]|0)>>>0)fa();else{c[b>>2]=0;m=a;break}}else{b=c[n+8>>2]|0;if(b>>>0<(c[9731]|0)>>>0)fa();d=b+12|0;if((c[d>>2]|0)!=(n|0))fa();e=a+8|0;if((c[e>>2]|0)==(n|0)){c[d>>2]=a;c[e>>2]=b;m=a;break}else fa()}while(0);if(g|0){a=c[n+28>>2]|0;b=39212+(a<<2)|0;if((n|0)==(c[b>>2]|0)){c[b>>2]=m;if(!m){c[9728]=c[9728]&~(1<>>0<(c[9731]|0)>>>0)fa();a=g+16|0;if((c[a>>2]|0)==(n|0))c[a>>2]=m;else c[g+20>>2]=m;if(!m)break}d=c[9731]|0;if(m>>>0>>0)fa();c[m+24>>2]=g;a=n+16|0;b=c[a>>2]|0;do if(b|0)if(b>>>0>>0)fa();else{c[m+16>>2]=b;c[b+24>>2]=m;break}while(0);a=c[a+4>>2]|0;if(a|0)if(a>>>0<(c[9731]|0)>>>0)fa();else{c[m+20>>2]=a;c[a+24>>2]=m;break}}}else{b=c[n+8>>2]|0;d=c[n+12>>2]|0;a=38948+(e<<1<<2)|0;if((b|0)!=(a|0)){if(b>>>0<(c[9731]|0)>>>0)fa();if((c[b+12>>2]|0)!=(n|0))fa()}if((d|0)==(b|0)){c[9727]=c[9727]&~(1<>>0<(c[9731]|0)>>>0)fa();a=d+8|0;if((c[a>>2]|0)==(n|0))l=a;else fa()}else l=d+8|0;c[b+12>>2]=d;c[l>>2]=b}while(0);c[q+4>>2]=f|1;c[q+f>>2]=f;if((q|0)==(c[9732]|0)){c[9729]=f;return}}else{c[a>>2]=b&-2;c[q+4>>2]=f|1;c[q+f>>2]=f}a=f>>>3;if(f>>>0<256){d=38948+(a<<1<<2)|0;b=c[9727]|0;a=1<>2]|0;if(b>>>0<(c[9731]|0)>>>0)fa();else{o=b;p=a}}else{c[9727]=b|a;o=d;p=d+8|0}c[p>>2]=q;c[o+12>>2]=q;c[q+8>>2]=o;c[q+12>>2]=d;return}a=f>>>8;if(a)if(f>>>0>16777215)a=31;else{o=(a+1048320|0)>>>16&8;p=a<>>16&4;p=p<>>16&2;a=14-(n|o|a)+(p<>>15)|0;a=f>>>(a+7|0)&1|a<<1}else a=0;e=39212+(a<<2)|0;c[q+28>>2]=a;c[q+20>>2]=0;c[q+16>>2]=0;b=c[9728]|0;d=1<>>1)|0);e=c[e>>2]|0;while(1){if((c[e+4>>2]&-8|0)==(f|0)){a=130;break}d=e+16+(b>>>31<<2)|0;a=c[d>>2]|0;if(!a){a=127;break}else{b=b<<1;e=a}}if((a|0)==127)if(d>>>0<(c[9731]|0)>>>0)fa();else{c[d>>2]=q;c[q+24>>2]=e;c[q+12>>2]=q;c[q+8>>2]=q;break}else if((a|0)==130){a=e+8|0;b=c[a>>2]|0;p=c[9731]|0;if(b>>>0>=p>>>0&e>>>0>=p>>>0){c[b+12>>2]=q;c[a>>2]=q;c[q+8>>2]=b;c[q+12>>2]=e;c[q+24>>2]=0;break}else fa()}}else{c[9728]=b|d;c[e>>2]=q;c[q+24>>2]=e;c[q+12>>2]=q;c[q+8>>2]=q}while(0);q=(c[9735]|0)+-1|0;c[9735]=q;if(!q)a=39364;else return;while(1){a=c[a>>2]|0;if(!a)break;else a=a+8|0}c[9735]=-1;return}function jc(){}function kc(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;d=b-d-(c>>>0>a>>>0|0)>>>0;return (C=d,a-c>>>0|0)|0}function lc(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,i=0;f=b+e|0;if((e|0)>=20){d=d&255;h=b&3;i=d|d<<8|d<<16|d<<24;g=f&~3;if(h){h=b+4-h|0;while((b|0)<(h|0)){a[b>>0]=d;b=b+1|0}}while((b|0)<(g|0)){c[b>>2]=i;b=b+4|0}}while((b|0)<(f|0)){a[b>>0]=d;b=b+1|0}return b-e|0}function mc(a,b,c){a=a|0;b=b|0;c=c|0;if((c|0)<32){C=b>>>c;return a>>>c|(b&(1<>>c-32|0}function nc(a,b,c){a=a|0;b=b|0;c=c|0;if((c|0)<32){C=b<>>32-c;return a<>>16;a=(c>>>16)+(R(e,d)|0)|0;e=b>>>16;b=R(e,f)|0;return (C=(a>>>16)+(R(e,d)|0)+(((a&65535)+b|0)>>>16)|0,a+b<<16|c&65535|0)|0}function pc(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0,f=0;e=a;f=c;c=oc(e,f)|0;a=C;return (C=(R(b,f)|0)+(R(d,e)|0)+a|a&0,c|0|0)|0}function qc(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;c=a+c>>>0;return (C=b+d+(c>>>0>>0|0)>>>0,c|0)|0}function rc(a){a=a|0;var b=0,d=0;d=a+15&-16|0;b=c[k>>2]|0;a=b+d|0;if((d|0)>0&(a|0)<(b|0)|(a|0)<0){Z()|0;sa(12);return -1}c[k>>2]=a;if((a|0)>(Y()|0)?(X()|0)==0:0){sa(12);c[k>>2]=b;return -1}return b|0}function sc(a){a=a|0;return (a&255)<<24|(a>>8&255)<<16|(a>>16&255)<<8|a>>>24|0}function tc(b,d,e){b=b|0;d=d|0;e=e|0;var f=0;if((e|0)>=4096)return la(b|0,d|0,e|0)|0;f=b|0;if((b&3)==(d&3)){while(b&3){if(!e)return f|0;a[b>>0]=a[d>>0]|0;b=b+1|0;d=d+1|0;e=e-1|0}while((e|0)>=4){c[b>>2]=c[d>>2];b=b+4|0;d=d+4|0;e=e-4|0}}while((e|0)>0){a[b>>0]=a[d>>0]|0;b=b+1|0;d=d+1|0;e=e-1|0}return f|0}function uc(){return 0}function vc(a,b){a=a|0;b=b|0;return ua[a&1](b|0)|0}function wc(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;return va[a&7](b|0,c|0,d|0)|0}function xc(a,b){a=a|0;b=b|0;wa[a&3](b|0)}function yc(a){a=a|0;V(0);return 0}function zc(a,b,c){a=a|0;b=b|0;c=c|0;V(1);return 0}function Ac(a){a=a|0;V(2)} - -// EMSCRIPTEN_END_FUNCS -var ua=[yc,Nb];var va=[zc,Wb,Pb,Ub,Ob,zc,zc,zc];var wa=[Ac,Sb,Vb,Ac];return{___muldsi3:oc,_sbrk:rc,_i64Subtract:kc,_free:ic,_ecdsa_read_pubkey:lb,_i64Add:qc,_pthread_self:uc,_memset:lc,_malloc:hc,_memcpy:tc,_llvm_bswap_i32:sc,___muldi3:pc,_bitshift64Lshr:mc,_fflush:ec,_hdnode_public_ckd_address_optimized:ub,___errno_location:Rb,_bitshift64Shl:nc,runPostSets:jc,stackAlloc:xa,stackSave:ya,stackRestore:za,establishStackSpace:Aa,setThrew:Ba,setTempRet0:Ca,getTempRet0:Da,dynCall_ii:vc,dynCall_iiii:wc,dynCall_vi:xc}}) - - -// EMSCRIPTEN_END_ASM -(e.Ia,e.Ja,buffer),kc=e.___muldsi3=Z.___muldsi3,E=e._malloc=Z._malloc,db=e._i64Subtract=Z._i64Subtract,Ga=e._free=Z._free;e.runPostSets=Z.runPostSets; -var sc=e._ecdsa_read_pubkey=Z._ecdsa_read_pubkey,mc=e._i64Add=Z._i64Add,rc=e._pthread_self=Z._pthread_self,eb=e._memset=Z._memset,nc=e._sbrk=Z._sbrk,qc=e._memcpy=Z._memcpy;e.___errno_location=Z.___errno_location;var lc=e.___muldi3=Z.___muldi3,gb=e._bitshift64Lshr=Z._bitshift64Lshr;e._fflush=Z._fflush;var tc=e._hdnode_public_ckd_address_optimized=Z._hdnode_public_ckd_address_optimized,pc=e._llvm_bswap_i32=Z._llvm_bswap_i32,hb=e._bitshift64Shl=Z._bitshift64Shl;e.dynCall_ii=Z.dynCall_ii; -e.dynCall_iiii=Z.dynCall_iiii;e.dynCall_vi=Z.dynCall_vi;t.P=Z.stackAlloc;t.Q=Z.stackSave;t.I=Z.stackRestore;t.cd=Z.establishStackSpace;t.Wa=Z.setTempRet0;t.Na=Z.getTempRet0;function ga(a){this.name="ExitStatus";this.message="Program terminated with exit("+a+")";this.status=a}ga.prototype=Error();ga.prototype.constructor=ga;var uc=null,$a=function vc(){e.calledRun||wc();e.calledRun||($a=vc)}; -e.callMain=e.ad=function(a){function b(){for(var a=0;3>a;a++)d.push(0)}a=a||[];za||(za=!0,Qa(Sa));var c=a.length+1,d=[D(Xa(e.thisProgram),"i8",0)];b();for(var f=0;f Date: Tue, 25 Jul 2017 00:14:35 +0200 Subject: [PATCH 457/627] gitignore: add attic+vscode --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 683ecbe3e..4ef6dddfd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +.vscode/ +_attic/ *.o *.d *.exe From af06a997cbb83e733e224be0dff2c8d7d8b49daf Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 25 Jul 2017 17:59:26 +0200 Subject: [PATCH 458/627] refactor ecdsa_get_address_segwit_p2sh{,_raw} --- bip32.c | 2 +- ecdsa.c | 24 ++++++++++++++---------- ecdsa.h | 3 ++- test_check.c | 5 ++++- 4 files changed, 21 insertions(+), 13 deletions(-) diff --git a/bip32.c b/bip32.c index cfa05ed61..6adc7cdf9 100644 --- a/bip32.c +++ b/bip32.c @@ -298,7 +298,7 @@ void hdnode_public_ckd_address_optimized(const curve_point *pub, const uint8_t * switch (addrformat) { case 1: // Segwit-in-P2SH - ecdsa_get_address_segwit(child_pubkey, version, addr, addrsize); + ecdsa_get_address_segwit_p2sh(child_pubkey, version, addr, addrsize); break; default: // normal address ecdsa_get_address(child_pubkey, version, addr, addrsize); diff --git a/ecdsa.c b/ecdsa.c index 995afc5e7..a2e1f430a 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -907,21 +907,25 @@ void ecdsa_get_address(const uint8_t *pub_key, uint32_t version, char *addr, int MEMSET_BZERO(raw, sizeof(raw)); } -void ecdsa_get_address_segwit(const uint8_t *pub_key, uint32_t version, char *addr, int addrsize) +void ecdsa_get_address_segwit_p2sh_raw(const uint8_t *pub_key, uint32_t version, uint8_t *addr_raw) { - uint8_t raw[MAX_ADDR_RAW_SIZE]; size_t prefix_len = address_prefix_bytes_len(version); uint8_t digest[32]; - raw[0] = 0; // version byte - raw[1] = 20; // push 20 bytes - ecdsa_get_pubkeyhash(pub_key, raw + 2); - sha256_Raw(raw, 22, digest); - address_write_prefix_bytes(version, raw); - ripemd160(digest, 32, raw + prefix_len); + addr_raw[0] = 0; // version byte + addr_raw[1] = 20; // push 20 bytes + ecdsa_get_pubkeyhash(pub_key, addr_raw + 2); + sha256_Raw(addr_raw, 22, digest); + address_write_prefix_bytes(version, addr_raw); + ripemd160(digest, 32, addr_raw + prefix_len); +} + +void ecdsa_get_address_segwit_p2sh(const uint8_t *pub_key, uint32_t version, char *addr, int addrsize) +{ + uint8_t raw[MAX_ADDR_RAW_SIZE]; + size_t prefix_len = address_prefix_bytes_len(version); + ecdsa_get_address_segwit_p2sh_raw(pub_key, version, raw); base58_encode_check(raw, prefix_len + 20, addr, addrsize); - // not as important to clear these, but we might as well MEMSET_BZERO(raw, sizeof(raw)); - MEMSET_BZERO(digest, sizeof(digest)); } void ecdsa_get_wif(const uint8_t *priv_key, uint32_t version, char *wif, int wifsize) diff --git a/ecdsa.h b/ecdsa.h index bd55451f0..d21a3855d 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -74,7 +74,8 @@ void ecdsa_get_public_key65(const ecdsa_curve *curve, const uint8_t *priv_key, u void ecdsa_get_pubkeyhash(const uint8_t *pub_key, uint8_t *pubkeyhash); void ecdsa_get_address_raw(const uint8_t *pub_key, uint32_t version, uint8_t *addr_raw); void ecdsa_get_address(const uint8_t *pub_key, uint32_t version, char *addr, int addrsize); -void ecdsa_get_address_segwit(const uint8_t *pub_key, uint32_t version, char *addr, int addrsize); +void ecdsa_get_address_segwit_p2sh_raw(const uint8_t *pub_key, uint32_t version, uint8_t *addr_raw); +void ecdsa_get_address_segwit_p2sh(const uint8_t *pub_key, uint32_t version, char *addr, int addrsize); void ecdsa_get_wif(const uint8_t *priv_key, uint32_t version, char *wif, int wifsize); int ecdsa_address_decode(const char *addr, uint32_t version, uint8_t *out); diff --git a/test_check.c b/test_check.c index bd2e2d82c..9dde96926 100644 --- a/test_check.c +++ b/test_check.c @@ -2317,24 +2317,28 @@ START_TEST(test_address) ecdsa_get_address(pub_key, 111, address, sizeof(address)); ck_assert_str_eq(address, "mhfJsQNnrXB3uuYZqvywARTDfuvyjg4RBh"); ecdsa_get_address(pub_key, 52, address, sizeof(address)); ck_assert_str_eq(address, "MxiimznnxsqMfLKTQBL8Z2PoY9jKpjgkCu"); ecdsa_get_address(pub_key, 48, address, sizeof(address)); ck_assert_str_eq(address, "LMNJqZbe89yrPbm7JVzrcXJf28hZ1rKPaH"); + ecdsa_get_address_segwit_p2sh(pub_key, 5, address, sizeof(address)); ck_assert_str_eq(address, "34PyTHn74syS796eTgsyoLfwoBC3cwLn6p"); memcpy(pub_key, fromhex("025b1654a0e78d28810094f6c5a96b8efb8a65668b578f170ac2b1f83bc63ba856"), 33); ecdsa_get_address(pub_key, 0, address, sizeof(address)); ck_assert_str_eq(address, "19Ywfm3witp6C1yBMy4NRYHY2347WCRBfQ"); ecdsa_get_address(pub_key, 111, address, sizeof(address)); ck_assert_str_eq(address, "mp4txp8vXvFLy8So5Y2kFTVrt2epN6YzdP"); ecdsa_get_address(pub_key, 52, address, sizeof(address)); ck_assert_str_eq(address, "N58JsQYveGueiZDgdnNwe4SSkGTAToutAY"); ecdsa_get_address(pub_key, 48, address, sizeof(address)); ck_assert_str_eq(address, "LTmtvyMmoZ49SpfLY73fhZMJEFRPdyohKh"); + ecdsa_get_address_segwit_p2sh(pub_key, 5, address, sizeof(address)); ck_assert_str_eq(address, "35trq6eeuHf6VL9L8pQv46x3vegHnHoTuB"); memcpy(pub_key, fromhex("03433f246a12e6486a51ff08802228c61cf895175a9b49ed4766ea9a9294a3c7fe"), 33); ecdsa_get_address(pub_key, 0, address, sizeof(address)); ck_assert_str_eq(address, "1FWE2bn3MWhc4QidcF6AvEWpK77sSi2cAP"); ecdsa_get_address(pub_key, 111, address, sizeof(address)); ck_assert_str_eq(address, "mv2BKes2AY8rqXCFKp4Yk9j9B6iaMfWRLN"); ecdsa_get_address(pub_key, 52, address, sizeof(address)); ck_assert_str_eq(address, "NB5bEFH2GtoAawy8t4Qk8kfj3LWvQs3MhB"); ecdsa_get_address(pub_key, 48, address, sizeof(address)); ck_assert_str_eq(address, "LZjBHp5sSAwfKDQnnP5UCFaaXKV9YheGxQ"); + ecdsa_get_address_segwit_p2sh(pub_key, 5, address, sizeof(address)); ck_assert_str_eq(address, "3456DYaKUWuY6RWWw8Hp5CftHLcQN29h9Y"); memcpy(pub_key, fromhex("03aeb03abeee0f0f8b4f7a5d65ce31f9570cef9f72c2dd8a19b4085a30ab033d48"), 33); ecdsa_get_address(pub_key, 0, address, sizeof(address)); ck_assert_str_eq(address, "1yrZb8dhdevoqpUEGi2tUccUEeiMKeLcs"); ecdsa_get_address(pub_key, 111, address, sizeof(address)); ck_assert_str_eq(address, "mgVoreDcWf6BaxJ5wqgQiPpwLEFRLSr8U8"); ecdsa_get_address(pub_key, 52, address, sizeof(address)); ck_assert_str_eq(address, "MwZDmEdcd1kVLP4yW62c6zmXCU3mNbveDo"); ecdsa_get_address(pub_key, 48, address, sizeof(address)); ck_assert_str_eq(address, "LLCopoSTnHtz4eWdQQhLAVgNgT1zTi4QBK"); + ecdsa_get_address_segwit_p2sh(pub_key, 5, address, sizeof(address)); ck_assert_str_eq(address, "3DBU4tJ9tkMR9fnmCtjW48kjvseoNLQZXd"); memcpy(pub_key, fromhex("0496e8f2093f018aff6c2e2da5201ee528e2c8accbf9cac51563d33a7bb74a016054201c025e2a5d96b1629b95194e806c63eb96facaedc733b1a4b70ab3b33e3a"), 65); ecdsa_get_address(pub_key, 0, address, sizeof(address)); ck_assert_str_eq(address, "194SZbL75xCCGBbKtMsyWLE5r9s2V6mhVM"); @@ -3133,7 +3137,6 @@ START_TEST(test_multibyte_address) ecdsa_get_address(pub_key, 0x12345678, address, sizeof(address)); ck_assert_str_eq(address, "BrsGxAHga3VbopvSnb3gmLvMBhJNCGuDxBZL44"); ecdsa_get_address(pub_key, 0xffffffff, address, sizeof(address)); ck_assert_str_eq(address, "3diW7paWGJyZRLGqMJZ55DMfPExob8QxQHkrfYT"); - res = ecdsa_address_decode("1C7zdTfnkzmr13HfA2vNm5SJYRK6nEKyq8", 0, decode); ck_assert_int_eq(res, 1); ck_assert_mem_eq(decode, fromhex("0079fbfc3f34e7745860d76137da68f362380c606c"), 21); From dfdb4d2d766506e9f54dd2c69c5e664fe4e39304 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sat, 27 May 2017 10:34:21 +0100 Subject: [PATCH 459/627] bip32: Fix NULL dereference for EdDSA --- bip32.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bip32.c b/bip32.c index 6adc7cdf9..4a84478f6 100644 --- a/bip32.c +++ b/bip32.c @@ -94,7 +94,7 @@ int hdnode_from_xprv(uint32_t depth, uint32_t child_num, const uint8_t *chain_co const curve_info *info = get_curve_by_name(curve); if (info == 0) { failed = true; - } else { + } else if (info->params) { bignum256 a; bn_read_be(private_key, &a); if (bn_is_zero(&a)) { // == 0 From 558bc429ec308dd9cac314810d1b2219b4f85863 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Wed, 26 Jul 2017 11:32:48 +0100 Subject: [PATCH 460/627] bignum: Add bn_digitcount --- bignum.h | 11 +++++++++++ test_check.c | 31 +++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/bignum.h b/bignum.h index 8e23ab976..7ba6204ee 100644 --- a/bignum.h +++ b/bignum.h @@ -81,6 +81,17 @@ static inline void bn_copy(const bignum256 *a, bignum256 *b) { int bn_bitcount(const bignum256 *a); +static inline int bn_digitcount(const bignum256 *a) +{ + int bitcount = bn_bitcount(a); + + if (bitcount == 256) { + return 78; + } else { + return bitcount * 78 / 256 + 1; + } +} + void bn_zero(bignum256 *a); int bn_is_zero(const bignum256 *a); diff --git a/test_check.c b/test_check.c index 9dde96926..e81ddba15 100644 --- a/test_check.c +++ b/test_check.c @@ -350,6 +350,36 @@ START_TEST(test_bignum_bitcount) } END_TEST +START_TEST(test_bignum_digitcount) +{ + bignum256 a; + + bn_zero(&a); + ck_assert_int_eq(bn_digitcount(&a), 1); + + bn_one(&a); + ck_assert_int_eq(bn_digitcount(&a), 1); + + bn_read_uint32(10, &a); + ck_assert_int_eq(bn_digitcount(&a), 2); + + bn_read_uint32(11, &a); + ck_assert_int_eq(bn_digitcount(&a), 2); + + bn_read_uint32(100, &a); + ck_assert_int_eq(bn_digitcount(&a), 3); + + bn_read_uint32(0x3fffffff, &a); + ck_assert_int_eq(bn_digitcount(&a), 10); + + bn_read_uint32(0xffffffff, &a); + ck_assert_int_eq(bn_digitcount(&a), 10); + + bn_read_be(fromhex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), &a); + ck_assert_int_eq(bn_digitcount(&a), 78); +} +END_TEST + START_TEST(test_bignum_is_less) { bignum256 a; @@ -3193,6 +3223,7 @@ Suite *test_suite(void) tcase_add_test(tc, test_bignum_is_even); tcase_add_test(tc, test_bignum_is_odd); tcase_add_test(tc, test_bignum_bitcount); + tcase_add_test(tc, test_bignum_digitcount); tcase_add_test(tc, test_bignum_is_less); tcase_add_test(tc, test_bignum_format); suite_add_tcase(s, tc); From 22ebd62b85905b7a8dd72d7ea5201f8b69201acd Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Wed, 26 Jul 2017 11:16:17 +0100 Subject: [PATCH 461/627] test_check: Update bn_format tests --- test_check.c | 64 ++++++++++++++++++++++++++-------------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/test_check.c b/test_check.c index e81ddba15..e7fe044ad 100644 --- a/test_check.c +++ b/test_check.c @@ -406,28 +406,28 @@ START_TEST(test_bignum_format) { bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000000"), &a); r = bn_format(&a, NULL, NULL, 0, buf, sizeof(buf)); - ck_assert_int_eq(r, 3); - ck_assert_str_eq(buf, "0.0"); + ck_assert_int_eq(r, 1); + ck_assert_str_eq(buf, "0"); bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000000"), &a); r = bn_format(&a, "", "", 0, buf, sizeof(buf)); - ck_assert_int_eq(r, 3); - ck_assert_str_eq(buf, "0.0"); + ck_assert_int_eq(r, 1); + ck_assert_str_eq(buf, "0"); bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000000"), &a); r = bn_format(&a, NULL, "SFFX", 0, buf, sizeof(buf)); - ck_assert_int_eq(r, 3 + 4); - ck_assert_str_eq(buf, "0.0SFFX"); + ck_assert_int_eq(r, 1 + 4); + ck_assert_str_eq(buf, "0SFFX"); bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000000"), &a); r = bn_format(&a, "PRFX", NULL, 0, buf, sizeof(buf)); - ck_assert_int_eq(r, 4 + 3); - ck_assert_str_eq(buf, "PRFX0.0"); + ck_assert_int_eq(r, 4 + 1); + ck_assert_str_eq(buf, "PRFX0"); bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000000"), &a); r = bn_format(&a, "PRFX", "SFFX", 0, buf, sizeof(buf)); - ck_assert_int_eq(r, 4 + 3 + 4); - ck_assert_str_eq(buf, "PRFX0.0SFFX"); + ck_assert_int_eq(r, 4 + 1 + 4); + ck_assert_str_eq(buf, "PRFX0SFFX"); bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000000"), &a); r = bn_format(&a, NULL, NULL, 18, buf, sizeof(buf)); @@ -436,53 +436,53 @@ START_TEST(test_bignum_format) { bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000001"), &a); r = bn_format(&a, NULL, NULL, 0, buf, sizeof(buf)); - ck_assert_int_eq(r, 3); - ck_assert_str_eq(buf, "1.0"); + ck_assert_int_eq(r, 1); + ck_assert_str_eq(buf, "1"); bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000002"), &a); r = bn_format(&a, NULL, NULL, 0, buf, sizeof(buf)); - ck_assert_int_eq(r, 3); - ck_assert_str_eq(buf, "2.0"); + ck_assert_int_eq(r, 1); + ck_assert_str_eq(buf, "2"); bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000005"), &a); r = bn_format(&a, NULL, NULL, 0, buf, sizeof(buf)); - ck_assert_int_eq(r, 3); - ck_assert_str_eq(buf, "5.0"); + ck_assert_int_eq(r, 1); + ck_assert_str_eq(buf, "5"); bn_read_be(fromhex("000000000000000000000000000000000000000000000000000000000000000a"), &a); r = bn_format(&a, NULL, NULL, 0, buf, sizeof(buf)); - ck_assert_int_eq(r, 4); - ck_assert_str_eq(buf, "10.0"); + ck_assert_int_eq(r, 2); + ck_assert_str_eq(buf, "10"); bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000014"), &a); r = bn_format(&a, NULL, NULL, 0, buf, sizeof(buf)); - ck_assert_int_eq(r, 4); - ck_assert_str_eq(buf, "20.0"); + ck_assert_int_eq(r, 2); + ck_assert_str_eq(buf, "20"); bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000032"), &a); r = bn_format(&a, NULL, NULL, 0, buf, sizeof(buf)); - ck_assert_int_eq(r, 4); - ck_assert_str_eq(buf, "50.0"); + ck_assert_int_eq(r, 2); + ck_assert_str_eq(buf, "50"); bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000064"), &a); r = bn_format(&a, NULL, NULL, 0, buf, sizeof(buf)); - ck_assert_int_eq(r, 5); - ck_assert_str_eq(buf, "100.0"); + ck_assert_int_eq(r, 3); + ck_assert_str_eq(buf, "100"); bn_read_be(fromhex("00000000000000000000000000000000000000000000000000000000000000c8"), &a); r = bn_format(&a, NULL, NULL, 0, buf, sizeof(buf)); - ck_assert_int_eq(r, 5); - ck_assert_str_eq(buf, "200.0"); + ck_assert_int_eq(r, 3); + ck_assert_str_eq(buf, "200"); bn_read_be(fromhex("00000000000000000000000000000000000000000000000000000000000001f4"), &a); r = bn_format(&a, NULL, NULL, 0, buf, sizeof(buf)); - ck_assert_int_eq(r, 5); - ck_assert_str_eq(buf, "500.0"); + ck_assert_int_eq(r, 3); + ck_assert_str_eq(buf, "500"); bn_read_be(fromhex("00000000000000000000000000000000000000000000000000000000000003e8"), &a); r = bn_format(&a, NULL, NULL, 0, buf, sizeof(buf)); - ck_assert_int_eq(r, 6); - ck_assert_str_eq(buf, "1000.0"); + ck_assert_int_eq(r, 4); + ck_assert_str_eq(buf, "1000"); bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000989680"), &a); r = bn_format(&a, NULL, NULL, 7, buf, sizeof(buf)); @@ -491,8 +491,8 @@ START_TEST(test_bignum_format) { bn_read_be(fromhex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), &a); r = bn_format(&a, NULL, NULL, 0, buf, sizeof(buf)); - ck_assert_int_eq(r, 80); - ck_assert_str_eq(buf, "115792089237316195423570985008687907853269984665640564039457584007913129639935.0"); + ck_assert_int_eq(r, 78); + ck_assert_str_eq(buf, "115792089237316195423570985008687907853269984665640564039457584007913129639935"); bn_read_be(fromhex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), &a); r = bn_format(&a, NULL, NULL, 1, buf, sizeof(buf)); From 88527dde7aaceb96431d3391e07a762c591770df Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Wed, 26 Jul 2017 16:12:10 +0100 Subject: [PATCH 462/627] bignum: Add exponent and trailing to bn_format --- bignum.c | 106 ++++++++++++++++++++++++++++++++++----------------- bignum.h | 4 +- test_check.c | 50 ++++++++++++------------ 3 files changed, 98 insertions(+), 62 deletions(-) diff --git a/bignum.c b/bignum.c index c06bd53da..caca7b607 100644 --- a/bignum.c +++ b/bignum.c @@ -960,56 +960,90 @@ void bn_divmod1000(bignum256 *a, uint32_t *r) *r = rem; } -// 2^256 has 78 digits in decimal (+ 1 for decimal point, + 1 for leading zero, + 1 for trailing zero) -#define DIGITLEN (78 + 1 + 1 + 1) - -int bn_format(const bignum256 *amnt, const char *prefix, const char *suffix, int decimals, char *out, int outlen) +size_t bn_format(const bignum256 *amnt, const char *prefix, const char *suffix, unsigned int decimals, int exponent, bool trailing, char *out, size_t outlen) { - // convert bignum to characters + size_t prefixlen = prefix ? strlen(prefix) : 0; + size_t suffixlen = suffix ? strlen(suffix) : 0; + + char *start = &out[prefixlen + suffixlen], *end = &out[outlen]; + char *str = end; + +#define BN_FORMAT_PUSH_CHECKED(c) \ + do { \ + if (str == start) return 0; \ + *--str = (c); \ + } while (0) + +#define BN_FORMAT_PUSH(n) \ + do { \ + if (exponent < 0) { \ + exponent++; \ + } else { \ + if ((n) > 0 || trailing || str != end || decimals <= 1) { \ + BN_FORMAT_PUSH_CHECKED('0' + (n)); \ + } \ + if (decimals > 0 && decimals-- == 1) { \ + BN_FORMAT_PUSH_CHECKED('.'); \ + } \ + } \ + } while (0) + bignum256 val; memcpy(&val, amnt, sizeof(bignum256)); - char digits[DIGITLEN]; - memset(digits, '0', DIGITLEN); - int pos = 1; // keep one trailing zero - for (int i = 0; i < 78 / 3; i++) { + + if (bn_is_zero(&val)) { + exponent = 0; + } + + for (; exponent > 0; exponent--) { + BN_FORMAT_PUSH(0); + } + + unsigned int digits = bn_digitcount(&val); + for (unsigned int i = 0; i < digits / 3; i++) { uint32_t limb; bn_divmod1000(&val, &limb); - if (pos == decimals + 1) { digits[DIGITLEN - 1 - pos] = '.'; pos++; } - digits[DIGITLEN - 1 - pos] = '0' + (limb % 10); pos++; - if (pos == decimals + 1) { digits[DIGITLEN - 1 - pos] = '.'; pos++; } - digits[DIGITLEN - 1 - pos] = '0' + ((limb / 10) % 10); pos++; - if (pos == decimals + 1) { digits[DIGITLEN - 1 - pos] = '.'; pos++; } - digits[DIGITLEN - 1 - pos] = '0' + ((limb / 100) % 10); pos++; + + BN_FORMAT_PUSH(limb % 10); + limb /= 10; + BN_FORMAT_PUSH(limb % 10); + limb /= 10; + BN_FORMAT_PUSH(limb % 10); } - // drop leading zeroes - int digitstart = 0; - while (digitstart < DIGITLEN - 1 && digits[digitstart] == '0' && digits[digitstart + 1] >= '0' && digits[digitstart + 1] <= '9') { - digitstart++; + if (digits % 3 != 0) { + uint32_t limb; + bn_divmod1000(&val, &limb); + + switch (digits % 3) { + case 2: + BN_FORMAT_PUSH(limb % 10); + limb /= 10; + //-fallthrough + + case 1: + BN_FORMAT_PUSH(limb % 10); + break; + } } - // drop trailing zeroes - int digitend = DIGITLEN - 1; - while (digitend > 0 && digits[digitend] == '0' && digits[digitend - 1] >= '0' && digits[digitend - 1] <= '9') { - digitend--; + while (decimals > 0 || str[0] == '\0' || str[0] == '.') { + BN_FORMAT_PUSH(0); } - int digitslen = digitend - digitstart + 1; - int prefixlen = prefix != NULL ? strlen(prefix) : 0; - int suffixlen = suffix != NULL ? strlen(suffix) : 0; + size_t len = end - str; + memmove(&out[prefixlen], str, len); - // output buffer is too small - if (prefixlen + digitslen + suffixlen + 1 > outlen) { - return 0; + if (prefixlen) { + memcpy(out, prefix, prefixlen); + } + if (suffixlen) { + memcpy(&out[prefixlen + len], suffix, suffixlen); } - // copy result to output buffer - memcpy(out, prefix, prefixlen); - memcpy(out + prefixlen, digits + digitstart, digitslen); - memcpy(out + prefixlen + digitslen, suffix, suffixlen); - out[prefixlen + digitslen + suffixlen] = 0; - - return prefixlen + digitslen + suffixlen; + size_t length = prefixlen + len + suffixlen; + out[length] = '\0'; + return length; } #if USE_BN_PRINT diff --git a/bignum.h b/bignum.h index 7ba6204ee..16067cf8d 100644 --- a/bignum.h +++ b/bignum.h @@ -25,6 +25,8 @@ #ifndef __BIGNUM_H__ #define __BIGNUM_H__ +#include +#include #include #include "options.h" @@ -156,7 +158,7 @@ void bn_divmod58(bignum256 *a, uint32_t *r); void bn_divmod1000(bignum256 *a, uint32_t *r); -int bn_format(const bignum256 *amnt, const char *prefix, const char *suffix, int decimals, char *out, int outlen); +size_t bn_format(const bignum256 *amnt, const char *prefix, const char *suffix, unsigned int decimals, int exponent, bool trailing, char *out, size_t outlen); #if USE_BN_PRINT void bn_print(const bignum256 *a); diff --git a/test_check.c b/test_check.c index e7fe044ad..2f0491f42 100644 --- a/test_check.c +++ b/test_check.c @@ -405,127 +405,127 @@ START_TEST(test_bignum_format) { int r; bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000000"), &a); - r = bn_format(&a, NULL, NULL, 0, buf, sizeof(buf)); + r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); ck_assert_int_eq(r, 1); ck_assert_str_eq(buf, "0"); bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000000"), &a); - r = bn_format(&a, "", "", 0, buf, sizeof(buf)); + r = bn_format(&a, "", "", 0, 0, false, buf, sizeof(buf)); ck_assert_int_eq(r, 1); ck_assert_str_eq(buf, "0"); bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000000"), &a); - r = bn_format(&a, NULL, "SFFX", 0, buf, sizeof(buf)); + r = bn_format(&a, NULL, "SFFX", 0, 0, false, buf, sizeof(buf)); ck_assert_int_eq(r, 1 + 4); ck_assert_str_eq(buf, "0SFFX"); bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000000"), &a); - r = bn_format(&a, "PRFX", NULL, 0, buf, sizeof(buf)); + r = bn_format(&a, "PRFX", NULL, 0, 0, false, buf, sizeof(buf)); ck_assert_int_eq(r, 4 + 1); ck_assert_str_eq(buf, "PRFX0"); bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000000"), &a); - r = bn_format(&a, "PRFX", "SFFX", 0, buf, sizeof(buf)); + r = bn_format(&a, "PRFX", "SFFX", 0, 0, false, buf, sizeof(buf)); ck_assert_int_eq(r, 4 + 1 + 4); ck_assert_str_eq(buf, "PRFX0SFFX"); bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000000"), &a); - r = bn_format(&a, NULL, NULL, 18, buf, sizeof(buf)); + r = bn_format(&a, NULL, NULL, 18, 0, false, buf, sizeof(buf)); ck_assert_int_eq(r, 3); ck_assert_str_eq(buf, "0.0"); bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000001"), &a); - r = bn_format(&a, NULL, NULL, 0, buf, sizeof(buf)); + r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); ck_assert_int_eq(r, 1); ck_assert_str_eq(buf, "1"); bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000002"), &a); - r = bn_format(&a, NULL, NULL, 0, buf, sizeof(buf)); + r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); ck_assert_int_eq(r, 1); ck_assert_str_eq(buf, "2"); bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000005"), &a); - r = bn_format(&a, NULL, NULL, 0, buf, sizeof(buf)); + r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); ck_assert_int_eq(r, 1); ck_assert_str_eq(buf, "5"); bn_read_be(fromhex("000000000000000000000000000000000000000000000000000000000000000a"), &a); - r = bn_format(&a, NULL, NULL, 0, buf, sizeof(buf)); + r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); ck_assert_int_eq(r, 2); ck_assert_str_eq(buf, "10"); bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000014"), &a); - r = bn_format(&a, NULL, NULL, 0, buf, sizeof(buf)); + r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); ck_assert_int_eq(r, 2); ck_assert_str_eq(buf, "20"); bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000032"), &a); - r = bn_format(&a, NULL, NULL, 0, buf, sizeof(buf)); + r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); ck_assert_int_eq(r, 2); ck_assert_str_eq(buf, "50"); bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000064"), &a); - r = bn_format(&a, NULL, NULL, 0, buf, sizeof(buf)); + r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); ck_assert_int_eq(r, 3); ck_assert_str_eq(buf, "100"); bn_read_be(fromhex("00000000000000000000000000000000000000000000000000000000000000c8"), &a); - r = bn_format(&a, NULL, NULL, 0, buf, sizeof(buf)); + r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); ck_assert_int_eq(r, 3); ck_assert_str_eq(buf, "200"); bn_read_be(fromhex("00000000000000000000000000000000000000000000000000000000000001f4"), &a); - r = bn_format(&a, NULL, NULL, 0, buf, sizeof(buf)); + r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); ck_assert_int_eq(r, 3); ck_assert_str_eq(buf, "500"); bn_read_be(fromhex("00000000000000000000000000000000000000000000000000000000000003e8"), &a); - r = bn_format(&a, NULL, NULL, 0, buf, sizeof(buf)); + r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); ck_assert_int_eq(r, 4); ck_assert_str_eq(buf, "1000"); bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000989680"), &a); - r = bn_format(&a, NULL, NULL, 7, buf, sizeof(buf)); + r = bn_format(&a, NULL, NULL, 7, 0, false, buf, sizeof(buf)); ck_assert_int_eq(r, 3); ck_assert_str_eq(buf, "1.0"); bn_read_be(fromhex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), &a); - r = bn_format(&a, NULL, NULL, 0, buf, sizeof(buf)); + r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); ck_assert_int_eq(r, 78); ck_assert_str_eq(buf, "115792089237316195423570985008687907853269984665640564039457584007913129639935"); bn_read_be(fromhex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), &a); - r = bn_format(&a, NULL, NULL, 1, buf, sizeof(buf)); + r = bn_format(&a, NULL, NULL, 1, 0, false, buf, sizeof(buf)); ck_assert_int_eq(r, 79); ck_assert_str_eq(buf, "11579208923731619542357098500868790785326998466564056403945758400791312963993.5"); bn_read_be(fromhex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), &a); - r = bn_format(&a, NULL, NULL, 2, buf, sizeof(buf)); + r = bn_format(&a, NULL, NULL, 2, 0, false, buf, sizeof(buf)); ck_assert_int_eq(r, 79); ck_assert_str_eq(buf, "1157920892373161954235709850086879078532699846656405640394575840079131296399.35"); bn_read_be(fromhex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), &a); - r = bn_format(&a, NULL, NULL, 8, buf, sizeof(buf)); + r = bn_format(&a, NULL, NULL, 8, 0, false, buf, sizeof(buf)); ck_assert_int_eq(r, 79); ck_assert_str_eq(buf, "1157920892373161954235709850086879078532699846656405640394575840079131.29639935"); bn_read_be(fromhex("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffe3bbb00"), &a); - r = bn_format(&a, NULL, NULL, 8, buf, sizeof(buf)); + r = bn_format(&a, NULL, NULL, 8, 0, false, buf, sizeof(buf)); ck_assert_int_eq(r, 72); ck_assert_str_eq(buf, "1157920892373161954235709850086879078532699846656405640394575840079131.0"); bn_read_be(fromhex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), &a); - r = bn_format(&a, NULL, NULL, 18, buf, sizeof(buf)); + r = bn_format(&a, NULL, NULL, 18, 0, false, buf, sizeof(buf)); ck_assert_int_eq(r, 79); ck_assert_str_eq(buf, "115792089237316195423570985008687907853269984665640564039457.584007913129639935"); bn_read_be(fromhex("fffffffffffffffffffffffffffffffffffffffffffffffff7e52fe5afe40000"), &a); - r = bn_format(&a, NULL, NULL, 18, buf, sizeof(buf)); + r = bn_format(&a, NULL, NULL, 18, 0, false, buf, sizeof(buf)); ck_assert_int_eq(r, 62); ck_assert_str_eq(buf, "115792089237316195423570985008687907853269984665640564039457.0"); bn_read_be(fromhex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), &a); - r = bn_format(&a, "quite a long prefix", "even longer suffix", 60, buf, sizeof(buf)); + r = bn_format(&a, "quite a long prefix", "even longer suffix", 60, 0, false, buf, sizeof(buf)); ck_assert_int_eq(r, 116); ck_assert_str_eq(buf, "quite a long prefix115792089237316195.423570985008687907853269984665640564039457584007913129639935even longer suffix"); } From da586bb37a71e477f0eaef9c7ba99945aa6f42d6 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Wed, 26 Jul 2017 16:41:40 +0100 Subject: [PATCH 463/627] test_check: Add more bn_format tests --- test_check.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/test_check.c b/test_check.c index 2f0491f42..87567b72d 100644 --- a/test_check.c +++ b/test_check.c @@ -409,6 +409,21 @@ START_TEST(test_bignum_format) { ck_assert_int_eq(r, 1); ck_assert_str_eq(buf, "0"); + bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000000"), &a); + r = bn_format(&a, NULL, NULL, 20, 0, true, buf, sizeof(buf)); + ck_assert_int_eq(r, 22); + ck_assert_str_eq(buf, "0.00000000000000000000"); + + bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000000"), &a); + r = bn_format(&a, NULL, NULL, 0, 5, false, buf, sizeof(buf)); + ck_assert_int_eq(r, 1); + ck_assert_str_eq(buf, "0"); + + bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000000"), &a); + r = bn_format(&a, NULL, NULL, 0, -5, false, buf, sizeof(buf)); + ck_assert_int_eq(r, 1); + ck_assert_str_eq(buf, "0"); + bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000000"), &a); r = bn_format(&a, "", "", 0, 0, false, buf, sizeof(buf)); ck_assert_int_eq(r, 1); @@ -439,6 +454,11 @@ START_TEST(test_bignum_format) { ck_assert_int_eq(r, 1); ck_assert_str_eq(buf, "1"); + bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000001"), &a); + r = bn_format(&a, NULL, NULL, 6, 6, true, buf, sizeof(buf)); + ck_assert_int_eq(r, 8); + ck_assert_str_eq(buf, "1.000000"); + bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000002"), &a); r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); ck_assert_int_eq(r, 1); @@ -524,6 +544,16 @@ START_TEST(test_bignum_format) { ck_assert_int_eq(r, 62); ck_assert_str_eq(buf, "115792089237316195423570985008687907853269984665640564039457.0"); + bn_read_be(fromhex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), &a); + r = bn_format(&a, NULL, NULL, 78, 0, false, buf, sizeof(buf)); + ck_assert_int_eq(r, 80); + ck_assert_str_eq(buf, "0.115792089237316195423570985008687907853269984665640564039457584007913129639935"); + + bn_read_be(fromhex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), &a); + r = bn_format(&a, NULL, NULL, 0, 10, false, buf, sizeof(buf)); + ck_assert_int_eq(r, 88); + ck_assert_str_eq(buf, "1157920892373161954235709850086879078532699846656405640394575840079131296399350000000000"); + bn_read_be(fromhex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), &a); r = bn_format(&a, "quite a long prefix", "even longer suffix", 60, 0, false, buf, sizeof(buf)); ck_assert_int_eq(r, 116); From 66993f9e9248d9d74a0c9997a95461bcd4a9dbe8 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Wed, 26 Jul 2017 18:05:48 +0100 Subject: [PATCH 464/627] bignum: Add bn_format_uint64 --- bignum.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/bignum.h b/bignum.h index 16067cf8d..ec64094f3 100644 --- a/bignum.h +++ b/bignum.h @@ -160,6 +160,14 @@ void bn_divmod1000(bignum256 *a, uint32_t *r); size_t bn_format(const bignum256 *amnt, const char *prefix, const char *suffix, unsigned int decimals, int exponent, bool trailing, char *out, size_t outlen); +static inline size_t bn_format_uint64(uint64_t amount, const char *prefix, const char *suffix, unsigned int decimals, int exponent, bool trailing, char *out, size_t outlen) +{ + bignum256 amnt; + bn_read_uint64(amount, &amnt); + + return bn_format(&amnt, prefix, suffix, decimals, exponent, trailing, out, outlen); +} + #if USE_BN_PRINT void bn_print(const bignum256 *a); void bn_print_raw(const bignum256 *a); From fd78df0e57ba16c253f61fa4c9f245fa8feebde5 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 27 Jul 2017 18:43:26 +0200 Subject: [PATCH 465/627] test: add more tests for bitcount and digitcount --- test_check.c | 42 ++++++++++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/test_check.c b/test_check.c index 87567b72d..5ac25193b 100644 --- a/test_check.c +++ b/test_check.c @@ -334,11 +334,27 @@ END_TEST START_TEST(test_bignum_bitcount) { - bignum256 a; + bignum256 a, b; bn_zero(&a); ck_assert_int_eq(bn_bitcount(&a), 0); + bn_one(&a); + ck_assert_int_eq(bn_bitcount(&a), 1); + + // test for 10000 and 11111 when i=5 + for (int i = 2; i <= 256; i++) { + bn_one(&a); + bn_one(&b); + for (int j = 2; j <= i; j++) { + bn_lshift(&a); + bn_lshift(&b); + bn_addi(&b, 1); + } + ck_assert_int_eq(bn_bitcount(&a), i); + ck_assert_int_eq(bn_bitcount(&b), i); + } + bn_read_uint32(0x3fffffff, &a); ck_assert_int_eq(bn_bitcount(&a), 30); @@ -357,17 +373,19 @@ START_TEST(test_bignum_digitcount) bn_zero(&a); ck_assert_int_eq(bn_digitcount(&a), 1); - bn_one(&a); - ck_assert_int_eq(bn_digitcount(&a), 1); - - bn_read_uint32(10, &a); - ck_assert_int_eq(bn_digitcount(&a), 2); - - bn_read_uint32(11, &a); - ck_assert_int_eq(bn_digitcount(&a), 2); - - bn_read_uint32(100, &a); - ck_assert_int_eq(bn_digitcount(&a), 3); + // test for 10000 and 99999 when i=5 + for (int i = 1; i <= 19; i++) { + uint64_t m = 1; + uint64_t n = 9; + for (int j = 2; j <= i; j++) { + m = m * 10; + n = n * 10 + 9; + } + bn_read_uint64(m, &a); + ck_assert_int_eq(bn_digitcount(&a), i); + bn_read_uint64(n, &a); + ck_assert_int_eq(bn_digitcount(&a), i); + } bn_read_uint32(0x3fffffff, &a); ck_assert_int_eq(bn_digitcount(&a), 10); From 5dbdf18b6c2ef1d95a7787bd57ab1e1126f439c0 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 27 Jul 2017 19:21:56 +0200 Subject: [PATCH 466/627] bignum: rename bn_digitcount to bn_maxdigitcount (can return value one higher than the real result) --- bignum.c | 2 +- bignum.h | 2 +- test_check.c | 12 ++++++------ 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/bignum.c b/bignum.c index caca7b607..8c33d7038 100644 --- a/bignum.c +++ b/bignum.c @@ -999,7 +999,7 @@ size_t bn_format(const bignum256 *amnt, const char *prefix, const char *suffix, BN_FORMAT_PUSH(0); } - unsigned int digits = bn_digitcount(&val); + unsigned int digits = bn_maxdigitcount(&val); for (unsigned int i = 0; i < digits / 3; i++) { uint32_t limb; bn_divmod1000(&val, &limb); diff --git a/bignum.h b/bignum.h index ec64094f3..30d4ba0ef 100644 --- a/bignum.h +++ b/bignum.h @@ -83,7 +83,7 @@ static inline void bn_copy(const bignum256 *a, bignum256 *b) { int bn_bitcount(const bignum256 *a); -static inline int bn_digitcount(const bignum256 *a) +static inline int bn_maxdigitcount(const bignum256 *a) { int bitcount = bn_bitcount(a); diff --git a/test_check.c b/test_check.c index 5ac25193b..693024b18 100644 --- a/test_check.c +++ b/test_check.c @@ -371,7 +371,7 @@ START_TEST(test_bignum_digitcount) bignum256 a; bn_zero(&a); - ck_assert_int_eq(bn_digitcount(&a), 1); + ck_assert_int_eq(bn_maxdigitcount(&a), 1); // test for 10000 and 99999 when i=5 for (int i = 1; i <= 19; i++) { @@ -382,19 +382,19 @@ START_TEST(test_bignum_digitcount) n = n * 10 + 9; } bn_read_uint64(m, &a); - ck_assert_int_eq(bn_digitcount(&a), i); + ck_assert_int_eq(bn_maxdigitcount(&a), i); bn_read_uint64(n, &a); - ck_assert_int_eq(bn_digitcount(&a), i); + ck_assert_int_eq(bn_maxdigitcount(&a), i + 1); } bn_read_uint32(0x3fffffff, &a); - ck_assert_int_eq(bn_digitcount(&a), 10); + ck_assert_int_eq(bn_maxdigitcount(&a), 10); bn_read_uint32(0xffffffff, &a); - ck_assert_int_eq(bn_digitcount(&a), 10); + ck_assert_int_eq(bn_maxdigitcount(&a), 10); bn_read_be(fromhex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), &a); - ck_assert_int_eq(bn_digitcount(&a), 78); + ck_assert_int_eq(bn_maxdigitcount(&a), 78); } END_TEST From ea7e1b860d1ba5c5b029fa47df00c64576f5c2fe Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 27 Jul 2017 19:28:00 +0200 Subject: [PATCH 467/627] test: reorder function in source --- test_check.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/test_check.c b/test_check.c index 693024b18..37c775c4e 100644 --- a/test_check.c +++ b/test_check.c @@ -332,6 +332,25 @@ START_TEST(test_bignum_is_odd) } END_TEST +START_TEST(test_bignum_is_less) +{ + bignum256 a; + bignum256 b; + + bn_read_uint32(0x1234, &a); + bn_read_uint32(0x8765, &b); + + ck_assert_int_eq(bn_is_less(&a, &b), 1); + ck_assert_int_eq(bn_is_less(&b, &a), 0); + + bn_zero(&a); + bn_read_be(fromhex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), &b); + + ck_assert_int_eq(bn_is_less(&a, &b), 1); + ck_assert_int_eq(bn_is_less(&b, &a), 0); +} +END_TEST + START_TEST(test_bignum_bitcount) { bignum256 a, b; @@ -398,25 +417,6 @@ START_TEST(test_bignum_digitcount) } END_TEST -START_TEST(test_bignum_is_less) -{ - bignum256 a; - bignum256 b; - - bn_read_uint32(0x1234, &a); - bn_read_uint32(0x8765, &b); - - ck_assert_int_eq(bn_is_less(&a, &b), 1); - ck_assert_int_eq(bn_is_less(&b, &a), 0); - - bn_zero(&a); - bn_read_be(fromhex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), &b); - - ck_assert_int_eq(bn_is_less(&a, &b), 1); - ck_assert_int_eq(bn_is_less(&b, &a), 0); -} -END_TEST - START_TEST(test_bignum_format) { bignum256 a; char buf[128]; From 5e1a3ad6e092666d6e1264cb0b555c98595aae41 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 27 Jul 2017 19:57:04 +0200 Subject: [PATCH 468/627] tests: add more tests for bn_format{,_uint64} --- test_check.c | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/test_check.c b/test_check.c index 37c775c4e..80aadc530 100644 --- a/test_check.c +++ b/test_check.c @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -417,6 +418,29 @@ START_TEST(test_bignum_digitcount) } END_TEST +START_TEST(test_bignum_format_uint64) { + char buf[128], str[128]; + int r; + // test for 10000 and 99999 when i=5 + for (int i = 1; i <= 19; i++) { + uint64_t m = 1; + uint64_t n = 9; + for (int j = 2; j <= i; j++) { + m = m * 10; + n = n * 10 + 9; + } + sprintf(str, "%" PRIu64, m); + r = bn_format_uint64(m, NULL, NULL, 0, 0, false, buf, sizeof(buf)); + ck_assert_int_eq(r, strlen(str)); + ck_assert_str_eq(buf, str); + sprintf(str, "%" PRIu64, n); + r = bn_format_uint64(n, NULL, NULL, 0, 0, false, buf, sizeof(buf)); + ck_assert_int_eq(r, strlen(str)); + ck_assert_str_eq(buf, str); + } +} +END_TEST + START_TEST(test_bignum_format) { bignum256 a; char buf[128]; @@ -487,6 +511,11 @@ START_TEST(test_bignum_format) { ck_assert_int_eq(r, 1); ck_assert_str_eq(buf, "5"); + bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000009"), &a); + r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); + ck_assert_int_eq(r, 1); + ck_assert_str_eq(buf, "9"); + bn_read_be(fromhex("000000000000000000000000000000000000000000000000000000000000000a"), &a); r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); ck_assert_int_eq(r, 2); @@ -502,6 +531,11 @@ START_TEST(test_bignum_format) { ck_assert_int_eq(r, 2); ck_assert_str_eq(buf, "50"); + bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000063"), &a); + r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); + ck_assert_int_eq(r, 2); + ck_assert_str_eq(buf, "99"); + bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000064"), &a); r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); ck_assert_int_eq(r, 3); @@ -517,6 +551,11 @@ START_TEST(test_bignum_format) { ck_assert_int_eq(r, 3); ck_assert_str_eq(buf, "500"); + bn_read_be(fromhex("00000000000000000000000000000000000000000000000000000000000003e7"), &a); + r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); + ck_assert_int_eq(r, 3); + ck_assert_str_eq(buf, "999"); + bn_read_be(fromhex("00000000000000000000000000000000000000000000000000000000000003e8"), &a); r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); ck_assert_int_eq(r, 4); @@ -3274,6 +3313,7 @@ Suite *test_suite(void) tcase_add_test(tc, test_bignum_digitcount); tcase_add_test(tc, test_bignum_is_less); tcase_add_test(tc, test_bignum_format); + tcase_add_test(tc, test_bignum_format_uint64); suite_add_tcase(s, tc); tc = tcase_create("base32"); From 43ea1392f205690283308d6a5d11386a5d808f26 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Thu, 27 Jul 2017 19:22:23 +0100 Subject: [PATCH 469/627] bignum: rename bn_maxdigitcount to bn_digitcount This reverts commit 5dbdf18b6c2ef1d95a7787bd57ab1e1126f439c0. --- bignum.c | 2 +- bignum.h | 2 +- test_check.c | 12 ++++++------ 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/bignum.c b/bignum.c index 8c33d7038..caca7b607 100644 --- a/bignum.c +++ b/bignum.c @@ -999,7 +999,7 @@ size_t bn_format(const bignum256 *amnt, const char *prefix, const char *suffix, BN_FORMAT_PUSH(0); } - unsigned int digits = bn_maxdigitcount(&val); + unsigned int digits = bn_digitcount(&val); for (unsigned int i = 0; i < digits / 3; i++) { uint32_t limb; bn_divmod1000(&val, &limb); diff --git a/bignum.h b/bignum.h index 30d4ba0ef..ec64094f3 100644 --- a/bignum.h +++ b/bignum.h @@ -83,7 +83,7 @@ static inline void bn_copy(const bignum256 *a, bignum256 *b) { int bn_bitcount(const bignum256 *a); -static inline int bn_maxdigitcount(const bignum256 *a) +static inline int bn_digitcount(const bignum256 *a) { int bitcount = bn_bitcount(a); diff --git a/test_check.c b/test_check.c index 80aadc530..bdd0f671f 100644 --- a/test_check.c +++ b/test_check.c @@ -391,7 +391,7 @@ START_TEST(test_bignum_digitcount) bignum256 a; bn_zero(&a); - ck_assert_int_eq(bn_maxdigitcount(&a), 1); + ck_assert_int_eq(bn_digitcount(&a), 1); // test for 10000 and 99999 when i=5 for (int i = 1; i <= 19; i++) { @@ -402,19 +402,19 @@ START_TEST(test_bignum_digitcount) n = n * 10 + 9; } bn_read_uint64(m, &a); - ck_assert_int_eq(bn_maxdigitcount(&a), i); + ck_assert_int_eq(bn_digitcount(&a), i); bn_read_uint64(n, &a); - ck_assert_int_eq(bn_maxdigitcount(&a), i + 1); + ck_assert_int_eq(bn_digitcount(&a), i); } bn_read_uint32(0x3fffffff, &a); - ck_assert_int_eq(bn_maxdigitcount(&a), 10); + ck_assert_int_eq(bn_digitcount(&a), 10); bn_read_uint32(0xffffffff, &a); - ck_assert_int_eq(bn_maxdigitcount(&a), 10); + ck_assert_int_eq(bn_digitcount(&a), 10); bn_read_be(fromhex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), &a); - ck_assert_int_eq(bn_maxdigitcount(&a), 78); + ck_assert_int_eq(bn_digitcount(&a), 78); } END_TEST From 85cb0b4f2ca8145d3c8495f738d812ee9cfab899 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Thu, 27 Jul 2017 19:25:00 +0100 Subject: [PATCH 470/627] bignum: Fix bn_digitcount bn_digitcount used to use bn_bitcount. This would give the maximum digits, which would often be higher than the actual number. This would result in leading zeroes in bn_format. --- bignum.c | 25 +++++++++++++++++++++++++ bignum.h | 11 +---------- 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/bignum.c b/bignum.c index caca7b607..d0e2b2825 100644 --- a/bignum.c +++ b/bignum.c @@ -195,6 +195,31 @@ int bn_bitcount(const bignum256 *a) return 0; } +#define DIGITS 78 // log10(2 ^ 256) + +unsigned int bn_digitcount(const bignum256 *a) +{ + bignum256 val; + memcpy(&val, a, sizeof(bignum256)); + + unsigned int digits = 1; + + for (unsigned int i = 0; i < DIGITS; i += 3) { + uint32_t limb; + bn_divmod1000(&val, &limb); + + if (limb >= 100) { + digits = i + 3; + } else if (limb >= 10) { + digits = i + 2; + } else if (limb >= 1) { + digits = i + 1; + } + } + + return digits; +} + // sets a bignum to zero. void bn_zero(bignum256 *a) { diff --git a/bignum.h b/bignum.h index ec64094f3..f96cad665 100644 --- a/bignum.h +++ b/bignum.h @@ -83,16 +83,7 @@ static inline void bn_copy(const bignum256 *a, bignum256 *b) { int bn_bitcount(const bignum256 *a); -static inline int bn_digitcount(const bignum256 *a) -{ - int bitcount = bn_bitcount(a); - - if (bitcount == 256) { - return 78; - } else { - return bitcount * 78 / 256 + 1; - } -} +unsigned int bn_digitcount(const bignum256 *a); void bn_zero(bignum256 *a); From 658004419635505ac75300870a0bbc049ad354ee Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Thu, 27 Jul 2017 20:01:57 +0100 Subject: [PATCH 471/627] test_check: Clean up test_bignum tests This also tests zero --- test_check.c | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/test_check.c b/test_check.c index bdd0f671f..839195745 100644 --- a/test_check.c +++ b/test_check.c @@ -393,18 +393,15 @@ START_TEST(test_bignum_digitcount) bn_zero(&a); ck_assert_int_eq(bn_digitcount(&a), 1); - // test for 10000 and 99999 when i=5 - for (int i = 1; i <= 19; i++) { - uint64_t m = 1; - uint64_t n = 9; - for (int j = 2; j <= i; j++) { - m = m * 10; - n = n * 10 + 9; - } + // test for (10^i) and (10^i) - 1 + uint64_t m = 1; + for (int i = 0; i <= 19; i++, m *= 10) { bn_read_uint64(m, &a); - ck_assert_int_eq(bn_digitcount(&a), i); + ck_assert_int_eq(bn_digitcount(&a), i + 1); + + uint64_t n = m - 1; bn_read_uint64(n, &a); - ck_assert_int_eq(bn_digitcount(&a), i); + ck_assert_int_eq(bn_digitcount(&a), n == 0 ? 1 : i); } bn_read_uint32(0x3fffffff, &a); @@ -421,18 +418,15 @@ END_TEST START_TEST(test_bignum_format_uint64) { char buf[128], str[128]; int r; - // test for 10000 and 99999 when i=5 - for (int i = 1; i <= 19; i++) { - uint64_t m = 1; - uint64_t n = 9; - for (int j = 2; j <= i; j++) { - m = m * 10; - n = n * 10 + 9; - } + // test for (10^i) and (10^i) - 1 + uint64_t m = 1; + for (int i = 0; i <= 19; i++, m *= 10) { sprintf(str, "%" PRIu64, m); r = bn_format_uint64(m, NULL, NULL, 0, 0, false, buf, sizeof(buf)); ck_assert_int_eq(r, strlen(str)); ck_assert_str_eq(buf, str); + + uint64_t n = m - 1; sprintf(str, "%" PRIu64, n); r = bn_format_uint64(n, NULL, NULL, 0, 0, false, buf, sizeof(buf)); ck_assert_int_eq(r, strlen(str)); From ea30ebe393dd68cbc734aa3b1a5c6f25171c18a7 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 10 Aug 2017 15:49:12 +0200 Subject: [PATCH 472/627] cleanup context in ripemd160/sha3 --- ripemd160.c | 6 +++++- sha3.c | 4 ++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/ripemd160.c b/ripemd160.c index 031f42202..6a62279c4 100644 --- a/ripemd160.c +++ b/ripemd160.c @@ -25,9 +25,11 @@ * http://ehash.iaik.tugraz.at/wiki/RIPEMD-160 */ -#include "ripemd160.h" #include +#include "ripemd160.h" +#include "macros.h" + /* * 32-bit integer manipulation macros (little endian) */ @@ -325,6 +327,8 @@ void ripemd160_Final( RIPEMD160_CTX *ctx, uint8_t output[RIPEMD160_DIGEST_LENGTH PUT_UINT32_LE( ctx->state[2], output, 8 ); PUT_UINT32_LE( ctx->state[3], output, 12 ); PUT_UINT32_LE( ctx->state[4], output, 16 ); + + MEMSET_BZERO(ctx, sizeof(RIPEMD160_CTX)); } /* diff --git a/sha3.c b/sha3.c index a3496e20f..9da744d4d 100644 --- a/sha3.c +++ b/sha3.c @@ -19,7 +19,9 @@ #include #include + #include "sha3.h" +#include "macros.h" #define I64(x) x##LL #define ROTL64(qword, n) ((qword) << (n) ^ ((qword) >> (64 - (n)))) @@ -329,6 +331,7 @@ void sha3_Final(SHA3_CTX *ctx, unsigned char* result) assert(block_size > digest_length); if (result) me64_to_le_str(result, ctx->hash, digest_length); + MEMSET_BZERO(ctx, sizeof(SHA3_CTX)); } #if USE_KECCAK @@ -357,6 +360,7 @@ void keccak_Final(SHA3_CTX *ctx, unsigned char* result) assert(block_size > digest_length); if (result) me64_to_le_str(result, ctx->hash, digest_length); + MEMSET_BZERO(ctx, sizeof(SHA3_CTX)); } void keccak_256(const unsigned char* data, size_t len, unsigned char* digest) From f9ab9f828b9de106072cfc7130ff75498091f578 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Mon, 31 Jul 2017 20:58:31 +0100 Subject: [PATCH 473/627] aes: Fix sequence point warning --- CMakeLists.txt | 4 ---- Makefile | 1 - aes/aeskey.c | 20 ++++++++++++++------ 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6133c903a..177863d03 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,10 +7,6 @@ add_library(TrezorCrypto STATIC ${SOURCES}) target_include_directories(TrezorCrypto PUBLIC .) target_include_directories(TrezorCrypto PUBLIC ed25519-donna) -# disable sequence point warnings where they are expected -set_source_files_properties(aeskey.c PROPERTIES - COMPILE_FLAGS -Wno-sequence-point) - target_compile_options(TrezorCrypto PRIVATE "-std=c99") if(MSVC) diff --git a/Makefile b/Makefile index f2598d737..f79de905e 100644 --- a/Makefile +++ b/Makefile @@ -24,7 +24,6 @@ CFLAGS += $(OPTFLAGS) \ -Werror # disable sequence point warning because of AES code -CFLAGS += -Wno-sequence-point CFLAGS += -I. CFLAGS += -Iaes CFLAGS += -Ichacha20poly1305 diff --git a/aes/aeskey.c b/aes/aeskey.c index 16e9607ff..94119185a 100644 --- a/aes/aeskey.c +++ b/aes/aeskey.c @@ -393,8 +393,11 @@ AES_RETURN aes_xi(decrypt_key192)(const unsigned char *key, aes_decrypt_ctx cx[1 cx->ks[v(48,(3))] = ss[3] = word_in(key, 3); #ifdef DEC_KS_UNROLL - cx->ks[v(48,(4))] = ff(ss[4] = word_in(key, 4)); - cx->ks[v(48,(5))] = ff(ss[5] = word_in(key, 5)); + ss[4] = word_in(key, 4); + ss[5] = word_in(key, 5); + + cx->ks[v(48,(4))] = ff(ss[4]); + cx->ks[v(48,(5))] = ff(ss[5]); kdf6(cx->ks, 0); kd6(cx->ks, 1); kd6(cx->ks, 2); kd6(cx->ks, 3); kd6(cx->ks, 4); kd6(cx->ks, 5); @@ -485,10 +488,15 @@ AES_RETURN aes_xi(decrypt_key256)(const unsigned char *key, aes_decrypt_ctx cx[1 cx->ks[v(56,(3))] = ss[3] = word_in(key, 3); #ifdef DEC_KS_UNROLL - cx->ks[v(56,(4))] = ff(ss[4] = word_in(key, 4)); - cx->ks[v(56,(5))] = ff(ss[5] = word_in(key, 5)); - cx->ks[v(56,(6))] = ff(ss[6] = word_in(key, 6)); - cx->ks[v(56,(7))] = ff(ss[7] = word_in(key, 7)); + ss[4] = word_in(key, 4); + ss[5] = word_in(key, 5); + ss[6] = word_in(key, 6); + ss[7] = word_in(key, 7); + + cx->ks[v(56,(4))] = ff(ss[4]); + cx->ks[v(56,(5))] = ff(ss[5]); + cx->ks[v(56,(6))] = ff(ss[6]); + cx->ks[v(56,(7))] = ff(ss[7]); kdf8(cx->ks, 0); kd8(cx->ks, 1); kd8(cx->ks, 2); kd8(cx->ks, 3); kd8(cx->ks, 4); kd8(cx->ks, 5); From b472f64c6162ec7616136d22515574ec010d4775 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Mon, 31 Jul 2017 21:23:11 +0100 Subject: [PATCH 474/627] aes: Add aestst Removed all the Windows and C++ specific parts. Fixed bug when -DAES_N_BLOCK (changed length from 1 to AES_BLOCK_SIZE) and use new name aes_init instead of gen_tabs when -DSTATIC_TABLES --- aes/aestst.c | 180 +++++++++++++++++++++++++++++++++++++++++++++++++++ aes/aestst.h | 85 ++++++++++++++++++++++++ 2 files changed, 265 insertions(+) create mode 100644 aes/aestst.c create mode 100644 aes/aestst.h diff --git a/aes/aestst.c b/aes/aestst.c new file mode 100644 index 000000000..15feb8ba2 --- /dev/null +++ b/aes/aestst.c @@ -0,0 +1,180 @@ +/* + --------------------------------------------------------------------------- + Copyright (c) 1998-2008, Brian Gladman, Worcester, UK. All rights reserved. + + LICENSE TERMS + + The redistribution and use of this software (with or without changes) + is allowed without the payment of fees or royalties provided that: + + 1. source code distributions include the above copyright notice, this + list of conditions and the following disclaimer; + + 2. binary distributions include the above copyright notice, this list + of conditions and the following disclaimer in their documentation; + + 3. the name of the copyright holder is not used to endorse products + built using this software without specific written permission. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and/or fitness for purpose. + --------------------------------------------------------------------------- + Issue Date: 20/12/2007 +*/ + +// Correct Output (for variable block size - AES_BLOCK_SIZE undefined): + +// lengths: block = 16 bytes, key = 16 bytes +// key = 2b7e151628aed2a6abf7158809cf4f3c +// input = 3243f6a8885a308d313198a2e0370734 +// encrypt = 3925841d02dc09fbdc118597196a0b32 +// decrypt = 3243f6a8885a308d313198a2e0370734 + +// lengths: block = 16 bytes, key = 24 bytes +// key = 2b7e151628aed2a6abf7158809cf4f3c762e7160f38b4da5 +// input = 3243f6a8885a308d313198a2e0370734 +// encrypt = f9fb29aefc384a250340d833b87ebc00 +// decrypt = 3243f6a8885a308d313198a2e0370734 + +// lengths: block = 16 bytes, key = 32 bytes +// key = 2b7e151628aed2a6abf7158809cf4f3c762e7160f38b4da56a784d9045190cfe +// input = 3243f6a8885a308d313198a2e0370734 +// encrypt = 1a6e6c2c662e7da6501ffb62bc9e93f3 +// decrypt = 3243f6a8885a308d313198a2e0370734 + +#include +#include + +#include "aes.h" +#include "aestst.h" + +void out_state(long s0, long s1, long s2, long s3) +{ + printf("\n%08x%08x508x%08x", s0, s1, s2, s3); +} + +void oblk(char m[], unsigned char v[], unsigned long n) +{ unsigned long i; + + printf("\n%s", m); + + for(i = 0; i < n; ++i) + printf("%02x", v[i]); +} + +void message(const char *s) { printf(s); } + +unsigned char pih[32] = // hex digits of pi +{ + 0x32, 0x43, 0xf6, 0xa8, 0x88, 0x5a, 0x30, 0x8d, + 0x31, 0x31, 0x98, 0xa2, 0xe0, 0x37, 0x07, 0x34, + 0x4a, 0x40, 0x93, 0x82, 0x22, 0x99, 0xf3, 0x1d, + 0x00, 0x82, 0xef, 0xa9, 0x8e, 0xc4, 0xe6, 0xc8 +}; + +unsigned char exh[32] = // hex digits of e +{ + 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, + 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c, + 0x76, 0x2e, 0x71, 0x60, 0xf3, 0x8b, 0x4d, 0xa5, + 0x6a, 0x78, 0x4d, 0x90, 0x45, 0x19, 0x0c, 0xfe +}; + +unsigned char res[3][32] = +{ + { 0x39, 0x25, 0x84, 0x1d, 0x02, 0xdc, 0x09, 0xfb, + 0xdc, 0x11, 0x85, 0x97, 0x19, 0x6a, 0x0b, 0x32 + }, + { 0xf9, 0xfb, 0x29, 0xae, 0xfc, 0x38, 0x4a, 0x25, + 0x03, 0x40, 0xd8, 0x33, 0xb8, 0x7e, 0xbc, 0x00 + }, + { 0x1a, 0x6e, 0x6c, 0x2c, 0x66, 0x2e, 0x7d, 0xa6, + 0x50, 0x1f, 0xfb, 0x62, 0xbc, 0x9e, 0x93, 0xf3 + } +}; + +void cycles(volatile uint64_t *rtn) +{ +#if defined( _MSCVER ) + __asm // read the Pentium Time Stamp Counter + { cpuid + rdtsc + mov ecx,rtn + mov [ecx],eax + mov [ecx+4],edx + cpuid + } +#elif defined( __GNUC__ ) + __asm__ __volatile__("rdtsc": "=A" (*rtn)); +#endif +} + +int main(void) +{ unsigned char out[32], ret[32], err = 0; + f_ectx alge[1]; + f_dctx algd[1]; + +#if defined(STATIC_TABLES) + aes_init(); +#endif + + message("\nRun tests for the AES algorithm"); + + memset(&alge, 0, sizeof(aes_encrypt_ctx)); + memset(&algd, 0, sizeof(aes_decrypt_ctx)); + +#if defined( AES_128 ) + memset(out, 0xcc, 16); memset(ret, 0xcc, 16); + printf("\n\n// lengths: block = 16, bytes, key = 16 bytes"); + f_enc_key128(alge, exh); + oblk("// key = ", exh, 16); + oblk("// input = ", pih, 16); + do_enc(alge, pih, out, 1); + oblk("// encrypt = ", out, 16); + if(memcmp(out, res[0], 16)) { message (" error"); err += 1; } + f_dec_key128(algd, exh); + do_dec(algd, out, ret, 1); + oblk("// decrypt = ", ret, 16); + if(memcmp(ret, pih, 16)) { message (" error"); err += 2; } +#endif + +#if defined( AES_192 ) + memset(out, 0xcc, 16); memset(ret, 0xcc, 16); + printf("\n\n// lengths: block = 16, bytes, key = 24 bytes"); + f_enc_key192(alge, exh); + oblk("// key = ", exh, 24); + oblk("// input = ", pih, 16); + do_enc(alge, pih, out, 1); + oblk("// encrypt = ", out, 16); + if(memcmp(out, res[1], 16)) { message (" error"); err += 4; } + f_dec_key192(algd, exh); + do_dec(algd, out, ret, 1); + oblk("// decrypt = ", ret, 16); + if(memcmp(ret, pih, 16)) { message (" error"); err += 8; } +#endif + +#if defined( AES_256 ) + memset(out, 0xcc, 16); memset(ret, 0xcc, 16); + printf("\n\n// lengths: block = 16, bytes, key = 32 bytes"); + f_enc_key256(alge, exh); + oblk("// key = ", exh, 32); + oblk("// input = ", pih, 16); + do_enc(alge, pih, out, 1); + oblk("// encrypt = ", out, 16); + if(memcmp(out, res[2], 16)) { message (" error"); err += 16; } + f_dec_key256(algd, exh); + do_dec(algd, out, ret, 1); + oblk("// decrypt = ", ret, 16); + if(memcmp(ret, pih, 16)) { message (" error"); err += 32; } +#endif + + if(!err) + message("\n\nThese values are all correct\n\n"); + else + message("\n\nSome values are in error\n\n"); + + return 0; +} diff --git a/aes/aestst.h b/aes/aestst.h new file mode 100644 index 000000000..1689e63cc --- /dev/null +++ b/aes/aestst.h @@ -0,0 +1,85 @@ +/* +--------------------------------------------------------------------------- +Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved. + +The redistribution and use of this software (with or without changes) +is allowed without the payment of fees or royalties provided that: + + source code distributions include the above copyright notice, this + list of conditions and the following disclaimer; + + binary distributions include the above copyright notice, this list + of conditions and the following disclaimer in their documentation. + +This software is provided 'as is' with no explicit or implied warranties +in respect of its operation, including, but not limited to, correctness +and fitness for purpose. +--------------------------------------------------------------------------- +Issue Date: 20/12/2007 +*/ + +// The following definitions are required for testing only, They are not needed +// for AES (Rijndael) implementation. They are used to allow C, C++ and DLL +// data access and subroutine calls to be expressed in the same form in the +// testing code. + +#ifndef AESTST_H +#define AESTST_H + +#define f_info(x) (x)->inf.b[2] +#define f_ectx aes_encrypt_ctx +#define f_enc_key128(a,b) aes_encrypt_key128((b),(a)) +#define f_enc_key192(a,b) aes_encrypt_key192((b),(a)) +#define f_enc_key256(a,b) aes_encrypt_key256((b),(a)) +#define f_enc_key(a,b,c) aes_encrypt_key((b),(c),(a)) +#define f_enc_blk(a,b,c) aes_encrypt((b),(c),(a)) + +#define f_dctx aes_decrypt_ctx +#define f_dec_key128(a,b) aes_decrypt_key128((b),(a)) +#define f_dec_key192(a,b) aes_decrypt_key192((b),(a)) +#define f_dec_key256(a,b) aes_decrypt_key256((b),(a)) +#define f_dec_key(a,b,c) aes_decrypt_key((b),(c),(a)) +#define f_dec_blk(a,b,c) aes_decrypt((b),(c),(a)) + +#define f_talign(a,b) aes_test_alignment_detection(b) +#define f_mode_reset(a) aes_mode_reset(a) +#define f_ecb_enc(a,b,c,d) aes_ecb_encrypt((b),(c),(d),(a)) +#define f_ecb_dec(a,b,c,d) aes_ecb_decrypt((b),(c),(d),(a)) +#define f_cbc_enc(a,b,c,d,e) aes_cbc_encrypt((b),(c),(d),(e),(a)) +#define f_cbc_dec(a,b,c,d,e) aes_cbc_decrypt((b),(c),(d),(e),(a)) +#define f_cfb_enc(a,b,c,d,e) aes_cfb_encrypt((b),(c),(d),(e),(a)) +#define f_cfb_dec(a,b,c,d,e) aes_cfb_decrypt((b),(c),(d),(e),(a)) +#define f_ofb_cry(a,b,c,d,e) aes_ofb_crypt((b),(c),(d),(e),(a)) +#define f_ctr_cry(a,b,c,d,e,f) aes_ctr_crypt((b),(c),(d),(e),(f),(a)) + +#define ek_name128 "aes_encrypt_key128" +#define ek_name192 "aes_encrypt_key192" +#define ek_name256 "aes_encrypt_key256" +#define ek_name "aes_encrypt_key" +#define eb_name "aes_encrypt" + +#define dk_name128 "aes_decrypt_key128" +#define dk_name192 "aes_decrypt_key192" +#define dk_name256 "aes_decrypt_key256" +#define dk_name "aes_decrypt_key" +#define db_name "aes_decrypt" + +#define eres_name "aes_mode_reset" +#define ecbe_name "aes_ecb_encrypt" +#define ecbd_name "aes_ecb_decrypt" +#define cbce_name "aes_cbc_encrypt" +#define cbcd_name "aes_cbc_decrypt" +#define cfbe_name "aes_cfb_encrypt" +#define cfbd_name "aes_cfb_decrypt" +#define ofb_name "aes_ofb_crypt" +#define ctr_name "aes_ctr_crypt" + +#ifndef AES_N_BLOCK +#define do_enc(a,b,c,d) f_enc_blk(a, b, c) +#define do_dec(a,b,c,d) f_dec_blk(a, b, c) +#else +#define do_enc(a,b,c,d) f_ecb_enc(a, b, c, AES_BLOCK_SIZE) +#define do_dec(a,b,c,d) f_ecb_dec(a, b, c, AES_BLOCK_SIZE) +#endif + +#endif From 6e51be6fe24f42e2f4a6317b5046c6d8365ed827 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Thu, 1 Jun 2017 15:59:25 +0100 Subject: [PATCH 475/627] Add ge25519_scalarmult to ed25519-donna This reverts commit b1bee409e72bf92283803ff53aef754040a54a2e. --- ed25519-donna/ed25519-donna-impl-base.h | 73 +++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/ed25519-donna/ed25519-donna-impl-base.h b/ed25519-donna/ed25519-donna-impl-base.h index b12b012ca..e727acca8 100644 --- a/ed25519-donna/ed25519-donna-impl-base.h +++ b/ed25519-donna/ed25519-donna-impl-base.h @@ -313,6 +313,44 @@ DONNA_INLINE static void ge25519_cmove_stride4(long * r, long * p, long * pos, l } #define HAS_CMOVE_STRIDE4 +DONNA_INLINE static void ge25519_cmove_stride4b(long * r, long * p, long * pos, long * n, int stride) { + long x0=p[0], x1=p[1], x2=p[2], x3=p[3], y0, y1, y2, y3; + for(p+=stride; p= 0; i--) { + int k=abs(slide1[i]); + ge25519_double_partial(r, r); + ge25519_double_partial(r, r); + ge25519_double_partial(r, r); + ge25519_double_p1p1(&t, r); + ge25519_move_conditional_pniels_array(&pre, pre1, k, 9); + ge25519_p1p1_to_full(r, &t); + ge25519_pnielsadd_p1p1(&t, r, &pre, (unsigned char)slide1[i] >> 7); + ge25519_p1p1_to_partial(r, &t); + } +} + static void ge25519_scalarmult_base_choose_niels(ge25519_niels *t, const uint8_t table[256][96], uint32_t pos, signed char b) { bignum25519 neg; From 1caade58b3cb8d6d60821b22ecd6a90dfbb06042 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Thu, 1 Jun 2017 16:08:55 +0100 Subject: [PATCH 476/627] ed25519-donna: Add ed25519_scalarmult --- ed25519-donna/ed25519-keccak.h | 2 ++ ed25519-donna/ed25519-sha3.h | 2 ++ ed25519-donna/ed25519.c | 20 ++++++++++++++++++++ ed25519-donna/ed25519.h | 2 ++ 4 files changed, 26 insertions(+) diff --git a/ed25519-donna/ed25519-keccak.h b/ed25519-donna/ed25519-keccak.h index e122a9fda..d5321800e 100644 --- a/ed25519-donna/ed25519-keccak.h +++ b/ed25519-donna/ed25519-keccak.h @@ -12,6 +12,8 @@ void ed25519_publickey_keccak(const ed25519_secret_key sk, ed25519_public_key pk int ed25519_sign_open_keccak(const unsigned char *m, size_t mlen, const ed25519_public_key pk, const ed25519_signature RS); void ed25519_sign_keccak(const unsigned char *m, size_t mlen, const ed25519_secret_key sk, const ed25519_public_key pk, ed25519_signature RS); +int ed25519_scalarmult_keccak(ed25519_public_key res, const ed25519_secret_key sk, const ed25519_public_key pk); + #if defined(__cplusplus) } #endif diff --git a/ed25519-donna/ed25519-sha3.h b/ed25519-donna/ed25519-sha3.h index 0779c5559..58748a555 100644 --- a/ed25519-donna/ed25519-sha3.h +++ b/ed25519-donna/ed25519-sha3.h @@ -12,6 +12,8 @@ void ed25519_publickey_sha3(const ed25519_secret_key sk, ed25519_public_key pk); int ed25519_sign_open_sha3(const unsigned char *m, size_t mlen, const ed25519_public_key pk, const ed25519_signature RS); void ed25519_sign_sha3(const unsigned char *m, size_t mlen, const ed25519_secret_key sk, const ed25519_public_key pk, ed25519_signature RS); +int ed25519_scalarmult_sha3(ed25519_public_key res, const ed25519_secret_key sk, const ed25519_public_key pk); + #if defined(__cplusplus) } #endif diff --git a/ed25519-donna/ed25519.c b/ed25519-donna/ed25519.c index b54d505db..a8946cbbf 100644 --- a/ed25519-donna/ed25519.c +++ b/ed25519-donna/ed25519.c @@ -139,6 +139,26 @@ ED25519_FN(ed25519_sign_open) (const unsigned char *m, size_t mlen, const ed2551 return ed25519_verify(RS, checkR, 32) ? 0 : -1; } +int +ED25519_FN(ed25519_scalarmult) (ed25519_public_key res, const ed25519_secret_key sk, const ed25519_public_key pk) { + bignum256modm a; + ge25519 ALIGN(16) A, P; + hash_512bits extsk; + + ed25519_extsk(extsk, sk); + expand256_modm(a, extsk, 32); + + if (!ge25519_unpack_negative_vartime(&P, pk)) { + return -1; + } + + ge25519_scalarmult(&A, &P, a); + curve25519_neg(A.x, A.x); + ge25519_pack(res, &A); + return 0; +} + + #ifndef ED25519_SUFFIX #include "curve25519-donna-scalarmult-base.h" diff --git a/ed25519-donna/ed25519.h b/ed25519-donna/ed25519.h index af5cbb277..b42afdc1b 100644 --- a/ed25519-donna/ed25519.h +++ b/ed25519-donna/ed25519.h @@ -18,6 +18,8 @@ void ed25519_publickey(const ed25519_secret_key sk, ed25519_public_key pk); int ed25519_sign_open(const unsigned char *m, size_t mlen, const ed25519_public_key pk, const ed25519_signature RS); void ed25519_sign(const unsigned char *m, size_t mlen, const ed25519_secret_key sk, const ed25519_public_key pk, ed25519_signature RS); +int ed25519_scalarmult(ed25519_public_key res, const ed25519_secret_key sk, const ed25519_public_key pk); + void curve25519_scalarmult(curve25519_key mypublic, const curve25519_key secret, const curve25519_key basepoint); void curve25519_scalarmult_basepoint(curve25519_key mypublic, const curve25519_key secret); From 3983f330cf71f6dee6da436e360cb5fe107b62c7 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Mon, 31 Jul 2017 15:40:09 +0100 Subject: [PATCH 477/627] ed25519-donna: Remove duplicate static code --- Makefile | 4 +- ed25519-donna/curve25519-donna-32bit.c | 545 ++++++++++++++++++ ed25519-donna/curve25519-donna-32bit.h | 539 +---------------- ed25519-donna/curve25519-donna-helpers.c | 66 +++ ed25519-donna/curve25519-donna-helpers.h | 51 +- .../curve25519-donna-scalarmult-base.c | 67 +++ .../curve25519-donna-scalarmult-base.h | 59 +- ed25519-donna/ed25519-donna-32bit-tables.c | 63 ++ ed25519-donna/ed25519-donna-32bit-tables.h | 54 +- ed25519-donna/ed25519-donna-basepoint-table.c | 3 +- ed25519-donna/ed25519-donna-impl-base.c | 454 +++++++++++++++ ed25519-donna/ed25519-donna-impl-base.h | 439 +------------- ed25519-donna/ed25519-donna-portable.h | 6 - ed25519-donna/ed25519-donna.h | 11 - ed25519-donna/modm-donna-32bit.c | 358 ++++++++++++ ed25519-donna/modm-donna-32bit.h | 341 +---------- 16 files changed, 1612 insertions(+), 1448 deletions(-) create mode 100644 ed25519-donna/curve25519-donna-32bit.c create mode 100644 ed25519-donna/curve25519-donna-helpers.c create mode 100644 ed25519-donna/curve25519-donna-scalarmult-base.c create mode 100644 ed25519-donna/ed25519-donna-32bit-tables.c create mode 100644 ed25519-donna/ed25519-donna-impl-base.c create mode 100644 ed25519-donna/modm-donna-32bit.c diff --git a/Makefile b/Makefile index f79de905e..6f1051b41 100644 --- a/Makefile +++ b/Makefile @@ -43,7 +43,9 @@ SRCS += ripemd160.c SRCS += sha2.c SRCS += sha3.c SRCS += aes/aescrypt.c aes/aeskey.c aes/aestab.c aes/aes_modes.c -SRCS += ed25519-donna/ed25519.c ed25519-donna/ed25519-donna-basepoint-table.c ed25519-donna/ed25519-sha3.c ed25519-donna/ed25519-keccak.c +SRCS += ed25519-donna/curve25519-donna-32bit.c ed25519-donna/curve25519-donna-helpers.c ed25519-donna/modm-donna-32bit.c +SRCS += ed25519-donna/ed25519-donna-basepoint-table.c ed25519-donna/ed25519-donna-32bit-tables.c ed25519-donna/ed25519-donna-impl-base.c +SRCS += ed25519-donna/ed25519.c ed25519-donna/curve25519-donna-scalarmult-base.c ed25519-donna/ed25519-sha3.c ed25519-donna/ed25519-keccak.c SRCS += blake2b.c blake2s.c SRCS += chacha20poly1305/chacha20poly1305.c chacha20poly1305/chacha_merged.c chacha20poly1305/poly1305-donna.c chacha20poly1305/rfc7539.c diff --git a/ed25519-donna/curve25519-donna-32bit.c b/ed25519-donna/curve25519-donna-32bit.c new file mode 100644 index 000000000..2579c60d1 --- /dev/null +++ b/ed25519-donna/curve25519-donna-32bit.c @@ -0,0 +1,545 @@ +/* + Public domain by Andrew M. + See: https://github.com/floodyberry/curve25519-donna + + 32 bit integer curve25519 implementation +*/ + +#include "ed25519-donna.h" + +static const uint32_t reduce_mask_25 = (1 << 25) - 1; +static const uint32_t reduce_mask_26 = (1 << 26) - 1; + +/* out = in */ +void curve25519_copy(bignum25519 out, const bignum25519 in) { + out[0] = in[0]; + out[1] = in[1]; + out[2] = in[2]; + out[3] = in[3]; + out[4] = in[4]; + out[5] = in[5]; + out[6] = in[6]; + out[7] = in[7]; + out[8] = in[8]; + out[9] = in[9]; +} + +/* out = a + b */ +void curve25519_add(bignum25519 out, const bignum25519 a, const bignum25519 b) { + out[0] = a[0] + b[0]; + out[1] = a[1] + b[1]; + out[2] = a[2] + b[2]; + out[3] = a[3] + b[3]; + out[4] = a[4] + b[4]; + out[5] = a[5] + b[5]; + out[6] = a[6] + b[6]; + out[7] = a[7] + b[7]; + out[8] = a[8] + b[8]; + out[9] = a[9] + b[9]; +} + +void curve25519_add_after_basic(bignum25519 out, const bignum25519 a, const bignum25519 b) { + uint32_t c; + out[0] = a[0] + b[0] ; c = (out[0] >> 26); out[0] &= reduce_mask_26; + out[1] = a[1] + b[1] + c; c = (out[1] >> 25); out[1] &= reduce_mask_25; + out[2] = a[2] + b[2] + c; c = (out[2] >> 26); out[2] &= reduce_mask_26; + out[3] = a[3] + b[3] + c; c = (out[3] >> 25); out[3] &= reduce_mask_25; + out[4] = a[4] + b[4] + c; c = (out[4] >> 26); out[4] &= reduce_mask_26; + out[5] = a[5] + b[5] + c; c = (out[5] >> 25); out[5] &= reduce_mask_25; + out[6] = a[6] + b[6] + c; c = (out[6] >> 26); out[6] &= reduce_mask_26; + out[7] = a[7] + b[7] + c; c = (out[7] >> 25); out[7] &= reduce_mask_25; + out[8] = a[8] + b[8] + c; c = (out[8] >> 26); out[8] &= reduce_mask_26; + out[9] = a[9] + b[9] + c; c = (out[9] >> 25); out[9] &= reduce_mask_25; + out[0] += 19 * c; +} + +void curve25519_add_reduce(bignum25519 out, const bignum25519 a, const bignum25519 b) { + uint32_t c; + out[0] = a[0] + b[0] ; c = (out[0] >> 26); out[0] &= reduce_mask_26; + out[1] = a[1] + b[1] + c; c = (out[1] >> 25); out[1] &= reduce_mask_25; + out[2] = a[2] + b[2] + c; c = (out[2] >> 26); out[2] &= reduce_mask_26; + out[3] = a[3] + b[3] + c; c = (out[3] >> 25); out[3] &= reduce_mask_25; + out[4] = a[4] + b[4] + c; c = (out[4] >> 26); out[4] &= reduce_mask_26; + out[5] = a[5] + b[5] + c; c = (out[5] >> 25); out[5] &= reduce_mask_25; + out[6] = a[6] + b[6] + c; c = (out[6] >> 26); out[6] &= reduce_mask_26; + out[7] = a[7] + b[7] + c; c = (out[7] >> 25); out[7] &= reduce_mask_25; + out[8] = a[8] + b[8] + c; c = (out[8] >> 26); out[8] &= reduce_mask_26; + out[9] = a[9] + b[9] + c; c = (out[9] >> 25); out[9] &= reduce_mask_25; + out[0] += 19 * c; +} + +/* multiples of p */ +static const uint32_t twoP0 = 0x07ffffda; +static const uint32_t twoP13579 = 0x03fffffe; +static const uint32_t twoP2468 = 0x07fffffe; +static const uint32_t fourP0 = 0x0fffffb4; +static const uint32_t fourP13579 = 0x07fffffc; +static const uint32_t fourP2468 = 0x0ffffffc; + +/* out = a - b */ +void curve25519_sub(bignum25519 out, const bignum25519 a, const bignum25519 b) { + uint32_t c; + out[0] = twoP0 + a[0] - b[0] ; c = (out[0] >> 26); out[0] &= reduce_mask_26; + out[1] = twoP13579 + a[1] - b[1] + c; c = (out[1] >> 25); out[1] &= reduce_mask_25; + out[2] = twoP2468 + a[2] - b[2] + c; c = (out[2] >> 26); out[2] &= reduce_mask_26; + out[3] = twoP13579 + a[3] - b[3] + c; c = (out[3] >> 25); out[3] &= reduce_mask_25; + out[4] = twoP2468 + a[4] - b[4] + c; + out[5] = twoP13579 + a[5] - b[5] ; + out[6] = twoP2468 + a[6] - b[6] ; + out[7] = twoP13579 + a[7] - b[7] ; + out[8] = twoP2468 + a[8] - b[8] ; + out[9] = twoP13579 + a[9] - b[9] ; +} + +/* out = in * scalar */ +void curve25519_scalar_product(bignum25519 out, const bignum25519 in, const uint32_t scalar) { + uint64_t a; + uint32_t c; + a = mul32x32_64(in[0], scalar); out[0] = (uint32_t)a & reduce_mask_26; c = (uint32_t)(a >> 26); + a = mul32x32_64(in[1], scalar) + c; out[1] = (uint32_t)a & reduce_mask_25; c = (uint32_t)(a >> 25); + a = mul32x32_64(in[2], scalar) + c; out[2] = (uint32_t)a & reduce_mask_26; c = (uint32_t)(a >> 26); + a = mul32x32_64(in[3], scalar) + c; out[3] = (uint32_t)a & reduce_mask_25; c = (uint32_t)(a >> 25); + a = mul32x32_64(in[4], scalar) + c; out[4] = (uint32_t)a & reduce_mask_26; c = (uint32_t)(a >> 26); + a = mul32x32_64(in[5], scalar) + c; out[5] = (uint32_t)a & reduce_mask_25; c = (uint32_t)(a >> 25); + a = mul32x32_64(in[6], scalar) + c; out[6] = (uint32_t)a & reduce_mask_26; c = (uint32_t)(a >> 26); + a = mul32x32_64(in[7], scalar) + c; out[7] = (uint32_t)a & reduce_mask_25; c = (uint32_t)(a >> 25); + a = mul32x32_64(in[8], scalar) + c; out[8] = (uint32_t)a & reduce_mask_26; c = (uint32_t)(a >> 26); + a = mul32x32_64(in[9], scalar) + c; out[9] = (uint32_t)a & reduce_mask_25; c = (uint32_t)(a >> 25); + out[0] += c * 19; +} + +/* out = a - b, where a is the result of a basic op (add,sub) */ +void curve25519_sub_after_basic(bignum25519 out, const bignum25519 a, const bignum25519 b) { + uint32_t c; + out[0] = fourP0 + a[0] - b[0] ; c = (out[0] >> 26); out[0] &= reduce_mask_26; + out[1] = fourP13579 + a[1] - b[1] + c; c = (out[1] >> 25); out[1] &= reduce_mask_25; + out[2] = fourP2468 + a[2] - b[2] + c; c = (out[2] >> 26); out[2] &= reduce_mask_26; + out[3] = fourP13579 + a[3] - b[3] + c; c = (out[3] >> 25); out[3] &= reduce_mask_25; + out[4] = fourP2468 + a[4] - b[4] + c; c = (out[4] >> 26); out[4] &= reduce_mask_26; + out[5] = fourP13579 + a[5] - b[5] + c; c = (out[5] >> 25); out[5] &= reduce_mask_25; + out[6] = fourP2468 + a[6] - b[6] + c; c = (out[6] >> 26); out[6] &= reduce_mask_26; + out[7] = fourP13579 + a[7] - b[7] + c; c = (out[7] >> 25); out[7] &= reduce_mask_25; + out[8] = fourP2468 + a[8] - b[8] + c; c = (out[8] >> 26); out[8] &= reduce_mask_26; + out[9] = fourP13579 + a[9] - b[9] + c; c = (out[9] >> 25); out[9] &= reduce_mask_25; + out[0] += 19 * c; +} + +void curve25519_sub_reduce(bignum25519 out, const bignum25519 a, const bignum25519 b) { + uint32_t c; + out[0] = fourP0 + a[0] - b[0] ; c = (out[0] >> 26); out[0] &= reduce_mask_26; + out[1] = fourP13579 + a[1] - b[1] + c; c = (out[1] >> 25); out[1] &= reduce_mask_25; + out[2] = fourP2468 + a[2] - b[2] + c; c = (out[2] >> 26); out[2] &= reduce_mask_26; + out[3] = fourP13579 + a[3] - b[3] + c; c = (out[3] >> 25); out[3] &= reduce_mask_25; + out[4] = fourP2468 + a[4] - b[4] + c; c = (out[4] >> 26); out[4] &= reduce_mask_26; + out[5] = fourP13579 + a[5] - b[5] + c; c = (out[5] >> 25); out[5] &= reduce_mask_25; + out[6] = fourP2468 + a[6] - b[6] + c; c = (out[6] >> 26); out[6] &= reduce_mask_26; + out[7] = fourP13579 + a[7] - b[7] + c; c = (out[7] >> 25); out[7] &= reduce_mask_25; + out[8] = fourP2468 + a[8] - b[8] + c; c = (out[8] >> 26); out[8] &= reduce_mask_26; + out[9] = fourP13579 + a[9] - b[9] + c; c = (out[9] >> 25); out[9] &= reduce_mask_25; + out[0] += 19 * c; +} + +/* out = -a */ +void curve25519_neg(bignum25519 out, const bignum25519 a) { + uint32_t c; + out[0] = twoP0 - a[0] ; c = (out[0] >> 26); out[0] &= reduce_mask_26; + out[1] = twoP13579 - a[1] + c; c = (out[1] >> 25); out[1] &= reduce_mask_25; + out[2] = twoP2468 - a[2] + c; c = (out[2] >> 26); out[2] &= reduce_mask_26; + out[3] = twoP13579 - a[3] + c; c = (out[3] >> 25); out[3] &= reduce_mask_25; + out[4] = twoP2468 - a[4] + c; c = (out[4] >> 26); out[4] &= reduce_mask_26; + out[5] = twoP13579 - a[5] + c; c = (out[5] >> 25); out[5] &= reduce_mask_25; + out[6] = twoP2468 - a[6] + c; c = (out[6] >> 26); out[6] &= reduce_mask_26; + out[7] = twoP13579 - a[7] + c; c = (out[7] >> 25); out[7] &= reduce_mask_25; + out[8] = twoP2468 - a[8] + c; c = (out[8] >> 26); out[8] &= reduce_mask_26; + out[9] = twoP13579 - a[9] + c; c = (out[9] >> 25); out[9] &= reduce_mask_25; + out[0] += 19 * c; +} + +/* out = a * b */ +#define curve25519_mul_noinline curve25519_mul +void curve25519_mul(bignum25519 out, const bignum25519 a, const bignum25519 b) { + uint32_t r0,r1,r2,r3,r4,r5,r6,r7,r8,r9; + uint32_t s0,s1,s2,s3,s4,s5,s6,s7,s8,s9; + uint64_t m0,m1,m2,m3,m4,m5,m6,m7,m8,m9,c; + uint32_t p; + + r0 = b[0]; + r1 = b[1]; + r2 = b[2]; + r3 = b[3]; + r4 = b[4]; + r5 = b[5]; + r6 = b[6]; + r7 = b[7]; + r8 = b[8]; + r9 = b[9]; + + s0 = a[0]; + s1 = a[1]; + s2 = a[2]; + s3 = a[3]; + s4 = a[4]; + s5 = a[5]; + s6 = a[6]; + s7 = a[7]; + s8 = a[8]; + s9 = a[9]; + + m1 = mul32x32_64(r0, s1) + mul32x32_64(r1, s0); + m3 = mul32x32_64(r0, s3) + mul32x32_64(r1, s2) + mul32x32_64(r2, s1) + mul32x32_64(r3, s0); + m5 = mul32x32_64(r0, s5) + mul32x32_64(r1, s4) + mul32x32_64(r2, s3) + mul32x32_64(r3, s2) + mul32x32_64(r4, s1) + mul32x32_64(r5, s0); + m7 = mul32x32_64(r0, s7) + mul32x32_64(r1, s6) + mul32x32_64(r2, s5) + mul32x32_64(r3, s4) + mul32x32_64(r4, s3) + mul32x32_64(r5, s2) + mul32x32_64(r6, s1) + mul32x32_64(r7, s0); + m9 = mul32x32_64(r0, s9) + mul32x32_64(r1, s8) + mul32x32_64(r2, s7) + mul32x32_64(r3, s6) + mul32x32_64(r4, s5) + mul32x32_64(r5, s4) + mul32x32_64(r6, s3) + mul32x32_64(r7, s2) + mul32x32_64(r8, s1) + mul32x32_64(r9, s0); + + r1 *= 2; + r3 *= 2; + r5 *= 2; + r7 *= 2; + + m0 = mul32x32_64(r0, s0); + m2 = mul32x32_64(r0, s2) + mul32x32_64(r1, s1) + mul32x32_64(r2, s0); + m4 = mul32x32_64(r0, s4) + mul32x32_64(r1, s3) + mul32x32_64(r2, s2) + mul32x32_64(r3, s1) + mul32x32_64(r4, s0); + m6 = mul32x32_64(r0, s6) + mul32x32_64(r1, s5) + mul32x32_64(r2, s4) + mul32x32_64(r3, s3) + mul32x32_64(r4, s2) + mul32x32_64(r5, s1) + mul32x32_64(r6, s0); + m8 = mul32x32_64(r0, s8) + mul32x32_64(r1, s7) + mul32x32_64(r2, s6) + mul32x32_64(r3, s5) + mul32x32_64(r4, s4) + mul32x32_64(r5, s3) + mul32x32_64(r6, s2) + mul32x32_64(r7, s1) + mul32x32_64(r8, s0); + + r1 *= 19; + r2 *= 19; + r3 = (r3 / 2) * 19; + r4 *= 19; + r5 = (r5 / 2) * 19; + r6 *= 19; + r7 = (r7 / 2) * 19; + r8 *= 19; + r9 *= 19; + + m1 += (mul32x32_64(r9, s2) + mul32x32_64(r8, s3) + mul32x32_64(r7, s4) + mul32x32_64(r6, s5) + mul32x32_64(r5, s6) + mul32x32_64(r4, s7) + mul32x32_64(r3, s8) + mul32x32_64(r2, s9)); + m3 += (mul32x32_64(r9, s4) + mul32x32_64(r8, s5) + mul32x32_64(r7, s6) + mul32x32_64(r6, s7) + mul32x32_64(r5, s8) + mul32x32_64(r4, s9)); + m5 += (mul32x32_64(r9, s6) + mul32x32_64(r8, s7) + mul32x32_64(r7, s8) + mul32x32_64(r6, s9)); + m7 += (mul32x32_64(r9, s8) + mul32x32_64(r8, s9)); + + r3 *= 2; + r5 *= 2; + r7 *= 2; + r9 *= 2; + + m0 += (mul32x32_64(r9, s1) + mul32x32_64(r8, s2) + mul32x32_64(r7, s3) + mul32x32_64(r6, s4) + mul32x32_64(r5, s5) + mul32x32_64(r4, s6) + mul32x32_64(r3, s7) + mul32x32_64(r2, s8) + mul32x32_64(r1, s9)); + m2 += (mul32x32_64(r9, s3) + mul32x32_64(r8, s4) + mul32x32_64(r7, s5) + mul32x32_64(r6, s6) + mul32x32_64(r5, s7) + mul32x32_64(r4, s8) + mul32x32_64(r3, s9)); + m4 += (mul32x32_64(r9, s5) + mul32x32_64(r8, s6) + mul32x32_64(r7, s7) + mul32x32_64(r6, s8) + mul32x32_64(r5, s9)); + m6 += (mul32x32_64(r9, s7) + mul32x32_64(r8, s8) + mul32x32_64(r7, s9)); + m8 += (mul32x32_64(r9, s9)); + + r0 = (uint32_t)m0 & reduce_mask_26; c = (m0 >> 26); + m1 += c; r1 = (uint32_t)m1 & reduce_mask_25; c = (m1 >> 25); + m2 += c; r2 = (uint32_t)m2 & reduce_mask_26; c = (m2 >> 26); + m3 += c; r3 = (uint32_t)m3 & reduce_mask_25; c = (m3 >> 25); + m4 += c; r4 = (uint32_t)m4 & reduce_mask_26; c = (m4 >> 26); + m5 += c; r5 = (uint32_t)m5 & reduce_mask_25; c = (m5 >> 25); + m6 += c; r6 = (uint32_t)m6 & reduce_mask_26; c = (m6 >> 26); + m7 += c; r7 = (uint32_t)m7 & reduce_mask_25; c = (m7 >> 25); + m8 += c; r8 = (uint32_t)m8 & reduce_mask_26; c = (m8 >> 26); + m9 += c; r9 = (uint32_t)m9 & reduce_mask_25; p = (uint32_t)(m9 >> 25); + m0 = r0 + mul32x32_64(p,19); r0 = (uint32_t)m0 & reduce_mask_26; p = (uint32_t)(m0 >> 26); + r1 += p; + + out[0] = r0; + out[1] = r1; + out[2] = r2; + out[3] = r3; + out[4] = r4; + out[5] = r5; + out[6] = r6; + out[7] = r7; + out[8] = r8; + out[9] = r9; +} + +/* out = in * in */ +void curve25519_square(bignum25519 out, const bignum25519 in) { + uint32_t r0,r1,r2,r3,r4,r5,r6,r7,r8,r9; + uint32_t d6,d7,d8,d9; + uint64_t m0,m1,m2,m3,m4,m5,m6,m7,m8,m9,c; + uint32_t p; + + r0 = in[0]; + r1 = in[1]; + r2 = in[2]; + r3 = in[3]; + r4 = in[4]; + r5 = in[5]; + r6 = in[6]; + r7 = in[7]; + r8 = in[8]; + r9 = in[9]; + + m0 = mul32x32_64(r0, r0); + r0 *= 2; + m1 = mul32x32_64(r0, r1); + m2 = mul32x32_64(r0, r2) + mul32x32_64(r1, r1 * 2); + r1 *= 2; + m3 = mul32x32_64(r0, r3) + mul32x32_64(r1, r2 ); + m4 = mul32x32_64(r0, r4) + mul32x32_64(r1, r3 * 2) + mul32x32_64(r2, r2); + r2 *= 2; + m5 = mul32x32_64(r0, r5) + mul32x32_64(r1, r4 ) + mul32x32_64(r2, r3); + m6 = mul32x32_64(r0, r6) + mul32x32_64(r1, r5 * 2) + mul32x32_64(r2, r4) + mul32x32_64(r3, r3 * 2); + r3 *= 2; + m7 = mul32x32_64(r0, r7) + mul32x32_64(r1, r6 ) + mul32x32_64(r2, r5) + mul32x32_64(r3, r4 ); + m8 = mul32x32_64(r0, r8) + mul32x32_64(r1, r7 * 2) + mul32x32_64(r2, r6) + mul32x32_64(r3, r5 * 2) + mul32x32_64(r4, r4 ); + m9 = mul32x32_64(r0, r9) + mul32x32_64(r1, r8 ) + mul32x32_64(r2, r7) + mul32x32_64(r3, r6 ) + mul32x32_64(r4, r5 * 2); + + d6 = r6 * 19; + d7 = r7 * 2 * 19; + d8 = r8 * 19; + d9 = r9 * 2 * 19; + + m0 += (mul32x32_64(d9, r1 ) + mul32x32_64(d8, r2 ) + mul32x32_64(d7, r3 ) + mul32x32_64(d6, r4 * 2) + mul32x32_64(r5, r5 * 2 * 19)); + m1 += (mul32x32_64(d9, r2 / 2) + mul32x32_64(d8, r3 ) + mul32x32_64(d7, r4 ) + mul32x32_64(d6, r5 * 2)); + m2 += (mul32x32_64(d9, r3 ) + mul32x32_64(d8, r4 * 2) + mul32x32_64(d7, r5 * 2) + mul32x32_64(d6, r6 )); + m3 += (mul32x32_64(d9, r4 ) + mul32x32_64(d8, r5 * 2) + mul32x32_64(d7, r6 )); + m4 += (mul32x32_64(d9, r5 * 2) + mul32x32_64(d8, r6 * 2) + mul32x32_64(d7, r7 )); + m5 += (mul32x32_64(d9, r6 ) + mul32x32_64(d8, r7 * 2)); + m6 += (mul32x32_64(d9, r7 * 2) + mul32x32_64(d8, r8 )); + m7 += (mul32x32_64(d9, r8 )); + m8 += (mul32x32_64(d9, r9 )); + + r0 = (uint32_t)m0 & reduce_mask_26; c = (m0 >> 26); + m1 += c; r1 = (uint32_t)m1 & reduce_mask_25; c = (m1 >> 25); + m2 += c; r2 = (uint32_t)m2 & reduce_mask_26; c = (m2 >> 26); + m3 += c; r3 = (uint32_t)m3 & reduce_mask_25; c = (m3 >> 25); + m4 += c; r4 = (uint32_t)m4 & reduce_mask_26; c = (m4 >> 26); + m5 += c; r5 = (uint32_t)m5 & reduce_mask_25; c = (m5 >> 25); + m6 += c; r6 = (uint32_t)m6 & reduce_mask_26; c = (m6 >> 26); + m7 += c; r7 = (uint32_t)m7 & reduce_mask_25; c = (m7 >> 25); + m8 += c; r8 = (uint32_t)m8 & reduce_mask_26; c = (m8 >> 26); + m9 += c; r9 = (uint32_t)m9 & reduce_mask_25; p = (uint32_t)(m9 >> 25); + m0 = r0 + mul32x32_64(p,19); r0 = (uint32_t)m0 & reduce_mask_26; p = (uint32_t)(m0 >> 26); + r1 += p; + + out[0] = r0; + out[1] = r1; + out[2] = r2; + out[3] = r3; + out[4] = r4; + out[5] = r5; + out[6] = r6; + out[7] = r7; + out[8] = r8; + out[9] = r9; +} + +/* out = in ^ (2 * count) */ +void curve25519_square_times(bignum25519 out, const bignum25519 in, int count) { + uint32_t r0,r1,r2,r3,r4,r5,r6,r7,r8,r9; + uint32_t d6,d7,d8,d9; + uint64_t m0,m1,m2,m3,m4,m5,m6,m7,m8,m9,c; + uint32_t p; + + r0 = in[0]; + r1 = in[1]; + r2 = in[2]; + r3 = in[3]; + r4 = in[4]; + r5 = in[5]; + r6 = in[6]; + r7 = in[7]; + r8 = in[8]; + r9 = in[9]; + + do { + m0 = mul32x32_64(r0, r0); + r0 *= 2; + m1 = mul32x32_64(r0, r1); + m2 = mul32x32_64(r0, r2) + mul32x32_64(r1, r1 * 2); + r1 *= 2; + m3 = mul32x32_64(r0, r3) + mul32x32_64(r1, r2 ); + m4 = mul32x32_64(r0, r4) + mul32x32_64(r1, r3 * 2) + mul32x32_64(r2, r2); + r2 *= 2; + m5 = mul32x32_64(r0, r5) + mul32x32_64(r1, r4 ) + mul32x32_64(r2, r3); + m6 = mul32x32_64(r0, r6) + mul32x32_64(r1, r5 * 2) + mul32x32_64(r2, r4) + mul32x32_64(r3, r3 * 2); + r3 *= 2; + m7 = mul32x32_64(r0, r7) + mul32x32_64(r1, r6 ) + mul32x32_64(r2, r5) + mul32x32_64(r3, r4 ); + m8 = mul32x32_64(r0, r8) + mul32x32_64(r1, r7 * 2) + mul32x32_64(r2, r6) + mul32x32_64(r3, r5 * 2) + mul32x32_64(r4, r4 ); + m9 = mul32x32_64(r0, r9) + mul32x32_64(r1, r8 ) + mul32x32_64(r2, r7) + mul32x32_64(r3, r6 ) + mul32x32_64(r4, r5 * 2); + + d6 = r6 * 19; + d7 = r7 * 2 * 19; + d8 = r8 * 19; + d9 = r9 * 2 * 19; + + m0 += (mul32x32_64(d9, r1 ) + mul32x32_64(d8, r2 ) + mul32x32_64(d7, r3 ) + mul32x32_64(d6, r4 * 2) + mul32x32_64(r5, r5 * 2 * 19)); + m1 += (mul32x32_64(d9, r2 / 2) + mul32x32_64(d8, r3 ) + mul32x32_64(d7, r4 ) + mul32x32_64(d6, r5 * 2)); + m2 += (mul32x32_64(d9, r3 ) + mul32x32_64(d8, r4 * 2) + mul32x32_64(d7, r5 * 2) + mul32x32_64(d6, r6 )); + m3 += (mul32x32_64(d9, r4 ) + mul32x32_64(d8, r5 * 2) + mul32x32_64(d7, r6 )); + m4 += (mul32x32_64(d9, r5 * 2) + mul32x32_64(d8, r6 * 2) + mul32x32_64(d7, r7 )); + m5 += (mul32x32_64(d9, r6 ) + mul32x32_64(d8, r7 * 2)); + m6 += (mul32x32_64(d9, r7 * 2) + mul32x32_64(d8, r8 )); + m7 += (mul32x32_64(d9, r8 )); + m8 += (mul32x32_64(d9, r9 )); + + r0 = (uint32_t)m0 & reduce_mask_26; c = (m0 >> 26); + m1 += c; r1 = (uint32_t)m1 & reduce_mask_25; c = (m1 >> 25); + m2 += c; r2 = (uint32_t)m2 & reduce_mask_26; c = (m2 >> 26); + m3 += c; r3 = (uint32_t)m3 & reduce_mask_25; c = (m3 >> 25); + m4 += c; r4 = (uint32_t)m4 & reduce_mask_26; c = (m4 >> 26); + m5 += c; r5 = (uint32_t)m5 & reduce_mask_25; c = (m5 >> 25); + m6 += c; r6 = (uint32_t)m6 & reduce_mask_26; c = (m6 >> 26); + m7 += c; r7 = (uint32_t)m7 & reduce_mask_25; c = (m7 >> 25); + m8 += c; r8 = (uint32_t)m8 & reduce_mask_26; c = (m8 >> 26); + m9 += c; r9 = (uint32_t)m9 & reduce_mask_25; p = (uint32_t)(m9 >> 25); + m0 = r0 + mul32x32_64(p,19); r0 = (uint32_t)m0 & reduce_mask_26; p = (uint32_t)(m0 >> 26); + r1 += p; + } while (--count); + + out[0] = r0; + out[1] = r1; + out[2] = r2; + out[3] = r3; + out[4] = r4; + out[5] = r5; + out[6] = r6; + out[7] = r7; + out[8] = r8; + out[9] = r9; +} + +/* Take a little-endian, 32-byte number and expand it into polynomial form */ +void curve25519_expand(bignum25519 out, const unsigned char in[32]) { + const union { uint8_t b[2]; uint16_t s; } endian_check = {{1,0}}; + uint32_t x0,x1,x2,x3,x4,x5,x6,x7; + if (endian_check.s == 1) { + /* Take care, this only works when in is aligned */ + x0 = *(uint32_t *)(in + 0); + x1 = *(uint32_t *)(in + 4); + x2 = *(uint32_t *)(in + 8); + x3 = *(uint32_t *)(in + 12); + x4 = *(uint32_t *)(in + 16); + x5 = *(uint32_t *)(in + 20); + x6 = *(uint32_t *)(in + 24); + x7 = *(uint32_t *)(in + 28); + } else { + #define F(s) \ + ((((uint32_t)in[s + 0]) ) | \ + (((uint32_t)in[s + 1]) << 8) | \ + (((uint32_t)in[s + 2]) << 16) | \ + (((uint32_t)in[s + 3]) << 24)) + x0 = F(0); + x1 = F(4); + x2 = F(8); + x3 = F(12); + x4 = F(16); + x5 = F(20); + x6 = F(24); + x7 = F(28); + #undef F + } + + out[0] = ( x0 ) & reduce_mask_26; + out[1] = ((((uint64_t)x1 << 32) | x0) >> 26) & reduce_mask_25; + out[2] = ((((uint64_t)x2 << 32) | x1) >> 19) & reduce_mask_26; + out[3] = ((((uint64_t)x3 << 32) | x2) >> 13) & reduce_mask_25; + out[4] = (( x3) >> 6) & reduce_mask_26; + out[5] = ( x4 ) & reduce_mask_25; + out[6] = ((((uint64_t)x5 << 32) | x4) >> 25) & reduce_mask_26; + out[7] = ((((uint64_t)x6 << 32) | x5) >> 19) & reduce_mask_25; + out[8] = ((((uint64_t)x7 << 32) | x6) >> 12) & reduce_mask_26; + out[9] = (( x7) >> 6) & reduce_mask_25; /* ignore the top bit */ +} + +/* Take a fully reduced polynomial form number and contract it into a + * little-endian, 32-byte array + */ +void curve25519_contract(unsigned char out[32], const bignum25519 in) { + bignum25519 f; + curve25519_copy(f, in); + + #define carry_pass() \ + f[1] += f[0] >> 26; f[0] &= reduce_mask_26; \ + f[2] += f[1] >> 25; f[1] &= reduce_mask_25; \ + f[3] += f[2] >> 26; f[2] &= reduce_mask_26; \ + f[4] += f[3] >> 25; f[3] &= reduce_mask_25; \ + f[5] += f[4] >> 26; f[4] &= reduce_mask_26; \ + f[6] += f[5] >> 25; f[5] &= reduce_mask_25; \ + f[7] += f[6] >> 26; f[6] &= reduce_mask_26; \ + f[8] += f[7] >> 25; f[7] &= reduce_mask_25; \ + f[9] += f[8] >> 26; f[8] &= reduce_mask_26; + + #define carry_pass_full() \ + carry_pass() \ + f[0] += 19 * (f[9] >> 25); f[9] &= reduce_mask_25; + + #define carry_pass_final() \ + carry_pass() \ + f[9] &= reduce_mask_25; + + carry_pass_full() + carry_pass_full() + + /* now t is between 0 and 2^255-1, properly carried. */ + /* case 1: between 0 and 2^255-20. case 2: between 2^255-19 and 2^255-1. */ + f[0] += 19; + carry_pass_full() + + /* now between 19 and 2^255-1 in both cases, and offset by 19. */ + f[0] += (reduce_mask_26 + 1) - 19; + f[1] += (reduce_mask_25 + 1) - 1; + f[2] += (reduce_mask_26 + 1) - 1; + f[3] += (reduce_mask_25 + 1) - 1; + f[4] += (reduce_mask_26 + 1) - 1; + f[5] += (reduce_mask_25 + 1) - 1; + f[6] += (reduce_mask_26 + 1) - 1; + f[7] += (reduce_mask_25 + 1) - 1; + f[8] += (reduce_mask_26 + 1) - 1; + f[9] += (reduce_mask_25 + 1) - 1; + + /* now between 2^255 and 2^256-20, and offset by 2^255. */ + carry_pass_final() + + #undef carry_pass + #undef carry_full + #undef carry_final + + f[1] <<= 2; + f[2] <<= 3; + f[3] <<= 5; + f[4] <<= 6; + f[6] <<= 1; + f[7] <<= 3; + f[8] <<= 4; + f[9] <<= 6; + + #define F(i, s) \ + out[s+0] |= (unsigned char )(f[i] & 0xff); \ + out[s+1] = (unsigned char )((f[i] >> 8) & 0xff); \ + out[s+2] = (unsigned char )((f[i] >> 16) & 0xff); \ + out[s+3] = (unsigned char )((f[i] >> 24) & 0xff); + + out[0] = 0; + out[16] = 0; + F(0,0); + F(1,3); + F(2,6); + F(3,9); + F(4,12); + F(5,16); + F(6,19); + F(7,22); + F(8,25); + F(9,28); + #undef F +} + +/* if (iswap) swap(a, b) */ +void curve25519_swap_conditional(bignum25519 a, bignum25519 b, uint32_t iswap) { + const uint32_t swap = (uint32_t)(-(int32_t)iswap); + uint32_t x0,x1,x2,x3,x4,x5,x6,x7,x8,x9; + + x0 = swap & (a[0] ^ b[0]); a[0] ^= x0; b[0] ^= x0; + x1 = swap & (a[1] ^ b[1]); a[1] ^= x1; b[1] ^= x1; + x2 = swap & (a[2] ^ b[2]); a[2] ^= x2; b[2] ^= x2; + x3 = swap & (a[3] ^ b[3]); a[3] ^= x3; b[3] ^= x3; + x4 = swap & (a[4] ^ b[4]); a[4] ^= x4; b[4] ^= x4; + x5 = swap & (a[5] ^ b[5]); a[5] ^= x5; b[5] ^= x5; + x6 = swap & (a[6] ^ b[6]); a[6] ^= x6; b[6] ^= x6; + x7 = swap & (a[7] ^ b[7]); a[7] ^= x7; b[7] ^= x7; + x8 = swap & (a[8] ^ b[8]); a[8] ^= x8; b[8] ^= x8; + x9 = swap & (a[9] ^ b[9]); a[9] ^= x9; b[9] ^= x9; +} diff --git a/ed25519-donna/curve25519-donna-32bit.h b/ed25519-donna/curve25519-donna-32bit.h index 07882043f..19de6325c 100644 --- a/ed25519-donna/curve25519-donna-32bit.h +++ b/ed25519-donna/curve25519-donna-32bit.h @@ -7,556 +7,47 @@ typedef uint32_t bignum25519[10]; -static const uint32_t reduce_mask_25 = (1 << 25) - 1; -static const uint32_t reduce_mask_26 = (1 << 26) - 1; - /* out = in */ -DONNA_INLINE static void -curve25519_copy(bignum25519 out, const bignum25519 in) { - out[0] = in[0]; - out[1] = in[1]; - out[2] = in[2]; - out[3] = in[3]; - out[4] = in[4]; - out[5] = in[5]; - out[6] = in[6]; - out[7] = in[7]; - out[8] = in[8]; - out[9] = in[9]; -} +void curve25519_copy(bignum25519 out, const bignum25519 in); /* out = a + b */ -DONNA_INLINE static void -curve25519_add(bignum25519 out, const bignum25519 a, const bignum25519 b) { - out[0] = a[0] + b[0]; - out[1] = a[1] + b[1]; - out[2] = a[2] + b[2]; - out[3] = a[3] + b[3]; - out[4] = a[4] + b[4]; - out[5] = a[5] + b[5]; - out[6] = a[6] + b[6]; - out[7] = a[7] + b[7]; - out[8] = a[8] + b[8]; - out[9] = a[9] + b[9]; -} - -DONNA_INLINE static void -curve25519_add_after_basic(bignum25519 out, const bignum25519 a, const bignum25519 b) { - uint32_t c; - out[0] = a[0] + b[0] ; c = (out[0] >> 26); out[0] &= reduce_mask_26; - out[1] = a[1] + b[1] + c; c = (out[1] >> 25); out[1] &= reduce_mask_25; - out[2] = a[2] + b[2] + c; c = (out[2] >> 26); out[2] &= reduce_mask_26; - out[3] = a[3] + b[3] + c; c = (out[3] >> 25); out[3] &= reduce_mask_25; - out[4] = a[4] + b[4] + c; c = (out[4] >> 26); out[4] &= reduce_mask_26; - out[5] = a[5] + b[5] + c; c = (out[5] >> 25); out[5] &= reduce_mask_25; - out[6] = a[6] + b[6] + c; c = (out[6] >> 26); out[6] &= reduce_mask_26; - out[7] = a[7] + b[7] + c; c = (out[7] >> 25); out[7] &= reduce_mask_25; - out[8] = a[8] + b[8] + c; c = (out[8] >> 26); out[8] &= reduce_mask_26; - out[9] = a[9] + b[9] + c; c = (out[9] >> 25); out[9] &= reduce_mask_25; - out[0] += 19 * c; -} +void curve25519_add(bignum25519 out, const bignum25519 a, const bignum25519 b); -DONNA_INLINE static void -curve25519_add_reduce(bignum25519 out, const bignum25519 a, const bignum25519 b) { - uint32_t c; - out[0] = a[0] + b[0] ; c = (out[0] >> 26); out[0] &= reduce_mask_26; - out[1] = a[1] + b[1] + c; c = (out[1] >> 25); out[1] &= reduce_mask_25; - out[2] = a[2] + b[2] + c; c = (out[2] >> 26); out[2] &= reduce_mask_26; - out[3] = a[3] + b[3] + c; c = (out[3] >> 25); out[3] &= reduce_mask_25; - out[4] = a[4] + b[4] + c; c = (out[4] >> 26); out[4] &= reduce_mask_26; - out[5] = a[5] + b[5] + c; c = (out[5] >> 25); out[5] &= reduce_mask_25; - out[6] = a[6] + b[6] + c; c = (out[6] >> 26); out[6] &= reduce_mask_26; - out[7] = a[7] + b[7] + c; c = (out[7] >> 25); out[7] &= reduce_mask_25; - out[8] = a[8] + b[8] + c; c = (out[8] >> 26); out[8] &= reduce_mask_26; - out[9] = a[9] + b[9] + c; c = (out[9] >> 25); out[9] &= reduce_mask_25; - out[0] += 19 * c; -} +void curve25519_add_after_basic(bignum25519 out, const bignum25519 a, const bignum25519 b); -/* multiples of p */ -static const uint32_t twoP0 = 0x07ffffda; -static const uint32_t twoP13579 = 0x03fffffe; -static const uint32_t twoP2468 = 0x07fffffe; -static const uint32_t fourP0 = 0x0fffffb4; -static const uint32_t fourP13579 = 0x07fffffc; -static const uint32_t fourP2468 = 0x0ffffffc; +void curve25519_add_reduce(bignum25519 out, const bignum25519 a, const bignum25519 b); /* out = a - b */ -DONNA_INLINE static void -curve25519_sub(bignum25519 out, const bignum25519 a, const bignum25519 b) { - uint32_t c; - out[0] = twoP0 + a[0] - b[0] ; c = (out[0] >> 26); out[0] &= reduce_mask_26; - out[1] = twoP13579 + a[1] - b[1] + c; c = (out[1] >> 25); out[1] &= reduce_mask_25; - out[2] = twoP2468 + a[2] - b[2] + c; c = (out[2] >> 26); out[2] &= reduce_mask_26; - out[3] = twoP13579 + a[3] - b[3] + c; c = (out[3] >> 25); out[3] &= reduce_mask_25; - out[4] = twoP2468 + a[4] - b[4] + c; - out[5] = twoP13579 + a[5] - b[5] ; - out[6] = twoP2468 + a[6] - b[6] ; - out[7] = twoP13579 + a[7] - b[7] ; - out[8] = twoP2468 + a[8] - b[8] ; - out[9] = twoP13579 + a[9] - b[9] ; -} - -DONNA_INLINE DONNA_UNUSED static void -curve25519_scalar_product(bignum25519 out, const bignum25519 in, const uint32_t scalar); +void curve25519_sub(bignum25519 out, const bignum25519 a, const bignum25519 b); /* out = in * scalar */ -void curve25519_scalar_product(bignum25519 out, const bignum25519 in, const uint32_t scalar) { - uint64_t a; - uint32_t c; - a = mul32x32_64(in[0], scalar); out[0] = (uint32_t)a & reduce_mask_26; c = (uint32_t)(a >> 26); - a = mul32x32_64(in[1], scalar) + c; out[1] = (uint32_t)a & reduce_mask_25; c = (uint32_t)(a >> 25); - a = mul32x32_64(in[2], scalar) + c; out[2] = (uint32_t)a & reduce_mask_26; c = (uint32_t)(a >> 26); - a = mul32x32_64(in[3], scalar) + c; out[3] = (uint32_t)a & reduce_mask_25; c = (uint32_t)(a >> 25); - a = mul32x32_64(in[4], scalar) + c; out[4] = (uint32_t)a & reduce_mask_26; c = (uint32_t)(a >> 26); - a = mul32x32_64(in[5], scalar) + c; out[5] = (uint32_t)a & reduce_mask_25; c = (uint32_t)(a >> 25); - a = mul32x32_64(in[6], scalar) + c; out[6] = (uint32_t)a & reduce_mask_26; c = (uint32_t)(a >> 26); - a = mul32x32_64(in[7], scalar) + c; out[7] = (uint32_t)a & reduce_mask_25; c = (uint32_t)(a >> 25); - a = mul32x32_64(in[8], scalar) + c; out[8] = (uint32_t)a & reduce_mask_26; c = (uint32_t)(a >> 26); - a = mul32x32_64(in[9], scalar) + c; out[9] = (uint32_t)a & reduce_mask_25; c = (uint32_t)(a >> 25); - out[0] += c * 19; -} +void curve25519_scalar_product(bignum25519 out, const bignum25519 in, const uint32_t scalar); /* out = a - b, where a is the result of a basic op (add,sub) */ -DONNA_INLINE static void -curve25519_sub_after_basic(bignum25519 out, const bignum25519 a, const bignum25519 b) { - uint32_t c; - out[0] = fourP0 + a[0] - b[0] ; c = (out[0] >> 26); out[0] &= reduce_mask_26; - out[1] = fourP13579 + a[1] - b[1] + c; c = (out[1] >> 25); out[1] &= reduce_mask_25; - out[2] = fourP2468 + a[2] - b[2] + c; c = (out[2] >> 26); out[2] &= reduce_mask_26; - out[3] = fourP13579 + a[3] - b[3] + c; c = (out[3] >> 25); out[3] &= reduce_mask_25; - out[4] = fourP2468 + a[4] - b[4] + c; c = (out[4] >> 26); out[4] &= reduce_mask_26; - out[5] = fourP13579 + a[5] - b[5] + c; c = (out[5] >> 25); out[5] &= reduce_mask_25; - out[6] = fourP2468 + a[6] - b[6] + c; c = (out[6] >> 26); out[6] &= reduce_mask_26; - out[7] = fourP13579 + a[7] - b[7] + c; c = (out[7] >> 25); out[7] &= reduce_mask_25; - out[8] = fourP2468 + a[8] - b[8] + c; c = (out[8] >> 26); out[8] &= reduce_mask_26; - out[9] = fourP13579 + a[9] - b[9] + c; c = (out[9] >> 25); out[9] &= reduce_mask_25; - out[0] += 19 * c; -} +void curve25519_sub_after_basic(bignum25519 out, const bignum25519 a, const bignum25519 b); -DONNA_INLINE static void -curve25519_sub_reduce(bignum25519 out, const bignum25519 a, const bignum25519 b) { - uint32_t c; - out[0] = fourP0 + a[0] - b[0] ; c = (out[0] >> 26); out[0] &= reduce_mask_26; - out[1] = fourP13579 + a[1] - b[1] + c; c = (out[1] >> 25); out[1] &= reduce_mask_25; - out[2] = fourP2468 + a[2] - b[2] + c; c = (out[2] >> 26); out[2] &= reduce_mask_26; - out[3] = fourP13579 + a[3] - b[3] + c; c = (out[3] >> 25); out[3] &= reduce_mask_25; - out[4] = fourP2468 + a[4] - b[4] + c; c = (out[4] >> 26); out[4] &= reduce_mask_26; - out[5] = fourP13579 + a[5] - b[5] + c; c = (out[5] >> 25); out[5] &= reduce_mask_25; - out[6] = fourP2468 + a[6] - b[6] + c; c = (out[6] >> 26); out[6] &= reduce_mask_26; - out[7] = fourP13579 + a[7] - b[7] + c; c = (out[7] >> 25); out[7] &= reduce_mask_25; - out[8] = fourP2468 + a[8] - b[8] + c; c = (out[8] >> 26); out[8] &= reduce_mask_26; - out[9] = fourP13579 + a[9] - b[9] + c; c = (out[9] >> 25); out[9] &= reduce_mask_25; - out[0] += 19 * c; -} +void curve25519_sub_reduce(bignum25519 out, const bignum25519 a, const bignum25519 b); /* out = -a */ -DONNA_INLINE static void -curve25519_neg(bignum25519 out, const bignum25519 a) { - uint32_t c; - out[0] = twoP0 - a[0] ; c = (out[0] >> 26); out[0] &= reduce_mask_26; - out[1] = twoP13579 - a[1] + c; c = (out[1] >> 25); out[1] &= reduce_mask_25; - out[2] = twoP2468 - a[2] + c; c = (out[2] >> 26); out[2] &= reduce_mask_26; - out[3] = twoP13579 - a[3] + c; c = (out[3] >> 25); out[3] &= reduce_mask_25; - out[4] = twoP2468 - a[4] + c; c = (out[4] >> 26); out[4] &= reduce_mask_26; - out[5] = twoP13579 - a[5] + c; c = (out[5] >> 25); out[5] &= reduce_mask_25; - out[6] = twoP2468 - a[6] + c; c = (out[6] >> 26); out[6] &= reduce_mask_26; - out[7] = twoP13579 - a[7] + c; c = (out[7] >> 25); out[7] &= reduce_mask_25; - out[8] = twoP2468 - a[8] + c; c = (out[8] >> 26); out[8] &= reduce_mask_26; - out[9] = twoP13579 - a[9] + c; c = (out[9] >> 25); out[9] &= reduce_mask_25; - out[0] += 19 * c; -} +void curve25519_neg(bignum25519 out, const bignum25519 a); /* out = a * b */ #define curve25519_mul_noinline curve25519_mul -DONNA_INLINE static void -curve25519_mul(bignum25519 out, const bignum25519 a, const bignum25519 b) { - uint32_t r0,r1,r2,r3,r4,r5,r6,r7,r8,r9; - uint32_t s0,s1,s2,s3,s4,s5,s6,s7,s8,s9; - uint64_t m0,m1,m2,m3,m4,m5,m6,m7,m8,m9,c; - uint32_t p; - - r0 = b[0]; - r1 = b[1]; - r2 = b[2]; - r3 = b[3]; - r4 = b[4]; - r5 = b[5]; - r6 = b[6]; - r7 = b[7]; - r8 = b[8]; - r9 = b[9]; - - s0 = a[0]; - s1 = a[1]; - s2 = a[2]; - s3 = a[3]; - s4 = a[4]; - s5 = a[5]; - s6 = a[6]; - s7 = a[7]; - s8 = a[8]; - s9 = a[9]; - - m1 = mul32x32_64(r0, s1) + mul32x32_64(r1, s0); - m3 = mul32x32_64(r0, s3) + mul32x32_64(r1, s2) + mul32x32_64(r2, s1) + mul32x32_64(r3, s0); - m5 = mul32x32_64(r0, s5) + mul32x32_64(r1, s4) + mul32x32_64(r2, s3) + mul32x32_64(r3, s2) + mul32x32_64(r4, s1) + mul32x32_64(r5, s0); - m7 = mul32x32_64(r0, s7) + mul32x32_64(r1, s6) + mul32x32_64(r2, s5) + mul32x32_64(r3, s4) + mul32x32_64(r4, s3) + mul32x32_64(r5, s2) + mul32x32_64(r6, s1) + mul32x32_64(r7, s0); - m9 = mul32x32_64(r0, s9) + mul32x32_64(r1, s8) + mul32x32_64(r2, s7) + mul32x32_64(r3, s6) + mul32x32_64(r4, s5) + mul32x32_64(r5, s4) + mul32x32_64(r6, s3) + mul32x32_64(r7, s2) + mul32x32_64(r8, s1) + mul32x32_64(r9, s0); - - r1 *= 2; - r3 *= 2; - r5 *= 2; - r7 *= 2; - - m0 = mul32x32_64(r0, s0); - m2 = mul32x32_64(r0, s2) + mul32x32_64(r1, s1) + mul32x32_64(r2, s0); - m4 = mul32x32_64(r0, s4) + mul32x32_64(r1, s3) + mul32x32_64(r2, s2) + mul32x32_64(r3, s1) + mul32x32_64(r4, s0); - m6 = mul32x32_64(r0, s6) + mul32x32_64(r1, s5) + mul32x32_64(r2, s4) + mul32x32_64(r3, s3) + mul32x32_64(r4, s2) + mul32x32_64(r5, s1) + mul32x32_64(r6, s0); - m8 = mul32x32_64(r0, s8) + mul32x32_64(r1, s7) + mul32x32_64(r2, s6) + mul32x32_64(r3, s5) + mul32x32_64(r4, s4) + mul32x32_64(r5, s3) + mul32x32_64(r6, s2) + mul32x32_64(r7, s1) + mul32x32_64(r8, s0); - - r1 *= 19; - r2 *= 19; - r3 = (r3 / 2) * 19; - r4 *= 19; - r5 = (r5 / 2) * 19; - r6 *= 19; - r7 = (r7 / 2) * 19; - r8 *= 19; - r9 *= 19; - - m1 += (mul32x32_64(r9, s2) + mul32x32_64(r8, s3) + mul32x32_64(r7, s4) + mul32x32_64(r6, s5) + mul32x32_64(r5, s6) + mul32x32_64(r4, s7) + mul32x32_64(r3, s8) + mul32x32_64(r2, s9)); - m3 += (mul32x32_64(r9, s4) + mul32x32_64(r8, s5) + mul32x32_64(r7, s6) + mul32x32_64(r6, s7) + mul32x32_64(r5, s8) + mul32x32_64(r4, s9)); - m5 += (mul32x32_64(r9, s6) + mul32x32_64(r8, s7) + mul32x32_64(r7, s8) + mul32x32_64(r6, s9)); - m7 += (mul32x32_64(r9, s8) + mul32x32_64(r8, s9)); - - r3 *= 2; - r5 *= 2; - r7 *= 2; - r9 *= 2; - - m0 += (mul32x32_64(r9, s1) + mul32x32_64(r8, s2) + mul32x32_64(r7, s3) + mul32x32_64(r6, s4) + mul32x32_64(r5, s5) + mul32x32_64(r4, s6) + mul32x32_64(r3, s7) + mul32x32_64(r2, s8) + mul32x32_64(r1, s9)); - m2 += (mul32x32_64(r9, s3) + mul32x32_64(r8, s4) + mul32x32_64(r7, s5) + mul32x32_64(r6, s6) + mul32x32_64(r5, s7) + mul32x32_64(r4, s8) + mul32x32_64(r3, s9)); - m4 += (mul32x32_64(r9, s5) + mul32x32_64(r8, s6) + mul32x32_64(r7, s7) + mul32x32_64(r6, s8) + mul32x32_64(r5, s9)); - m6 += (mul32x32_64(r9, s7) + mul32x32_64(r8, s8) + mul32x32_64(r7, s9)); - m8 += (mul32x32_64(r9, s9)); - - r0 = (uint32_t)m0 & reduce_mask_26; c = (m0 >> 26); - m1 += c; r1 = (uint32_t)m1 & reduce_mask_25; c = (m1 >> 25); - m2 += c; r2 = (uint32_t)m2 & reduce_mask_26; c = (m2 >> 26); - m3 += c; r3 = (uint32_t)m3 & reduce_mask_25; c = (m3 >> 25); - m4 += c; r4 = (uint32_t)m4 & reduce_mask_26; c = (m4 >> 26); - m5 += c; r5 = (uint32_t)m5 & reduce_mask_25; c = (m5 >> 25); - m6 += c; r6 = (uint32_t)m6 & reduce_mask_26; c = (m6 >> 26); - m7 += c; r7 = (uint32_t)m7 & reduce_mask_25; c = (m7 >> 25); - m8 += c; r8 = (uint32_t)m8 & reduce_mask_26; c = (m8 >> 26); - m9 += c; r9 = (uint32_t)m9 & reduce_mask_25; p = (uint32_t)(m9 >> 25); - m0 = r0 + mul32x32_64(p,19); r0 = (uint32_t)m0 & reduce_mask_26; p = (uint32_t)(m0 >> 26); - r1 += p; - - out[0] = r0; - out[1] = r1; - out[2] = r2; - out[3] = r3; - out[4] = r4; - out[5] = r5; - out[6] = r6; - out[7] = r7; - out[8] = r8; - out[9] = r9; -} +void curve25519_mul(bignum25519 out, const bignum25519 a, const bignum25519 b); /* out = in * in */ -DONNA_INLINE static void -curve25519_square(bignum25519 out, const bignum25519 in) { - uint32_t r0,r1,r2,r3,r4,r5,r6,r7,r8,r9; - uint32_t d6,d7,d8,d9; - uint64_t m0,m1,m2,m3,m4,m5,m6,m7,m8,m9,c; - uint32_t p; - - r0 = in[0]; - r1 = in[1]; - r2 = in[2]; - r3 = in[3]; - r4 = in[4]; - r5 = in[5]; - r6 = in[6]; - r7 = in[7]; - r8 = in[8]; - r9 = in[9]; - - m0 = mul32x32_64(r0, r0); - r0 *= 2; - m1 = mul32x32_64(r0, r1); - m2 = mul32x32_64(r0, r2) + mul32x32_64(r1, r1 * 2); - r1 *= 2; - m3 = mul32x32_64(r0, r3) + mul32x32_64(r1, r2 ); - m4 = mul32x32_64(r0, r4) + mul32x32_64(r1, r3 * 2) + mul32x32_64(r2, r2); - r2 *= 2; - m5 = mul32x32_64(r0, r5) + mul32x32_64(r1, r4 ) + mul32x32_64(r2, r3); - m6 = mul32x32_64(r0, r6) + mul32x32_64(r1, r5 * 2) + mul32x32_64(r2, r4) + mul32x32_64(r3, r3 * 2); - r3 *= 2; - m7 = mul32x32_64(r0, r7) + mul32x32_64(r1, r6 ) + mul32x32_64(r2, r5) + mul32x32_64(r3, r4 ); - m8 = mul32x32_64(r0, r8) + mul32x32_64(r1, r7 * 2) + mul32x32_64(r2, r6) + mul32x32_64(r3, r5 * 2) + mul32x32_64(r4, r4 ); - m9 = mul32x32_64(r0, r9) + mul32x32_64(r1, r8 ) + mul32x32_64(r2, r7) + mul32x32_64(r3, r6 ) + mul32x32_64(r4, r5 * 2); - - d6 = r6 * 19; - d7 = r7 * 2 * 19; - d8 = r8 * 19; - d9 = r9 * 2 * 19; - - m0 += (mul32x32_64(d9, r1 ) + mul32x32_64(d8, r2 ) + mul32x32_64(d7, r3 ) + mul32x32_64(d6, r4 * 2) + mul32x32_64(r5, r5 * 2 * 19)); - m1 += (mul32x32_64(d9, r2 / 2) + mul32x32_64(d8, r3 ) + mul32x32_64(d7, r4 ) + mul32x32_64(d6, r5 * 2)); - m2 += (mul32x32_64(d9, r3 ) + mul32x32_64(d8, r4 * 2) + mul32x32_64(d7, r5 * 2) + mul32x32_64(d6, r6 )); - m3 += (mul32x32_64(d9, r4 ) + mul32x32_64(d8, r5 * 2) + mul32x32_64(d7, r6 )); - m4 += (mul32x32_64(d9, r5 * 2) + mul32x32_64(d8, r6 * 2) + mul32x32_64(d7, r7 )); - m5 += (mul32x32_64(d9, r6 ) + mul32x32_64(d8, r7 * 2)); - m6 += (mul32x32_64(d9, r7 * 2) + mul32x32_64(d8, r8 )); - m7 += (mul32x32_64(d9, r8 )); - m8 += (mul32x32_64(d9, r9 )); - - r0 = (uint32_t)m0 & reduce_mask_26; c = (m0 >> 26); - m1 += c; r1 = (uint32_t)m1 & reduce_mask_25; c = (m1 >> 25); - m2 += c; r2 = (uint32_t)m2 & reduce_mask_26; c = (m2 >> 26); - m3 += c; r3 = (uint32_t)m3 & reduce_mask_25; c = (m3 >> 25); - m4 += c; r4 = (uint32_t)m4 & reduce_mask_26; c = (m4 >> 26); - m5 += c; r5 = (uint32_t)m5 & reduce_mask_25; c = (m5 >> 25); - m6 += c; r6 = (uint32_t)m6 & reduce_mask_26; c = (m6 >> 26); - m7 += c; r7 = (uint32_t)m7 & reduce_mask_25; c = (m7 >> 25); - m8 += c; r8 = (uint32_t)m8 & reduce_mask_26; c = (m8 >> 26); - m9 += c; r9 = (uint32_t)m9 & reduce_mask_25; p = (uint32_t)(m9 >> 25); - m0 = r0 + mul32x32_64(p,19); r0 = (uint32_t)m0 & reduce_mask_26; p = (uint32_t)(m0 >> 26); - r1 += p; - - out[0] = r0; - out[1] = r1; - out[2] = r2; - out[3] = r3; - out[4] = r4; - out[5] = r5; - out[6] = r6; - out[7] = r7; - out[8] = r8; - out[9] = r9; -} +void curve25519_square(bignum25519 out, const bignum25519 in); /* out = in ^ (2 * count) */ -static void -curve25519_square_times(bignum25519 out, const bignum25519 in, int count) { - uint32_t r0,r1,r2,r3,r4,r5,r6,r7,r8,r9; - uint32_t d6,d7,d8,d9; - uint64_t m0,m1,m2,m3,m4,m5,m6,m7,m8,m9,c; - uint32_t p; - - r0 = in[0]; - r1 = in[1]; - r2 = in[2]; - r3 = in[3]; - r4 = in[4]; - r5 = in[5]; - r6 = in[6]; - r7 = in[7]; - r8 = in[8]; - r9 = in[9]; - - do { - m0 = mul32x32_64(r0, r0); - r0 *= 2; - m1 = mul32x32_64(r0, r1); - m2 = mul32x32_64(r0, r2) + mul32x32_64(r1, r1 * 2); - r1 *= 2; - m3 = mul32x32_64(r0, r3) + mul32x32_64(r1, r2 ); - m4 = mul32x32_64(r0, r4) + mul32x32_64(r1, r3 * 2) + mul32x32_64(r2, r2); - r2 *= 2; - m5 = mul32x32_64(r0, r5) + mul32x32_64(r1, r4 ) + mul32x32_64(r2, r3); - m6 = mul32x32_64(r0, r6) + mul32x32_64(r1, r5 * 2) + mul32x32_64(r2, r4) + mul32x32_64(r3, r3 * 2); - r3 *= 2; - m7 = mul32x32_64(r0, r7) + mul32x32_64(r1, r6 ) + mul32x32_64(r2, r5) + mul32x32_64(r3, r4 ); - m8 = mul32x32_64(r0, r8) + mul32x32_64(r1, r7 * 2) + mul32x32_64(r2, r6) + mul32x32_64(r3, r5 * 2) + mul32x32_64(r4, r4 ); - m9 = mul32x32_64(r0, r9) + mul32x32_64(r1, r8 ) + mul32x32_64(r2, r7) + mul32x32_64(r3, r6 ) + mul32x32_64(r4, r5 * 2); - - d6 = r6 * 19; - d7 = r7 * 2 * 19; - d8 = r8 * 19; - d9 = r9 * 2 * 19; - - m0 += (mul32x32_64(d9, r1 ) + mul32x32_64(d8, r2 ) + mul32x32_64(d7, r3 ) + mul32x32_64(d6, r4 * 2) + mul32x32_64(r5, r5 * 2 * 19)); - m1 += (mul32x32_64(d9, r2 / 2) + mul32x32_64(d8, r3 ) + mul32x32_64(d7, r4 ) + mul32x32_64(d6, r5 * 2)); - m2 += (mul32x32_64(d9, r3 ) + mul32x32_64(d8, r4 * 2) + mul32x32_64(d7, r5 * 2) + mul32x32_64(d6, r6 )); - m3 += (mul32x32_64(d9, r4 ) + mul32x32_64(d8, r5 * 2) + mul32x32_64(d7, r6 )); - m4 += (mul32x32_64(d9, r5 * 2) + mul32x32_64(d8, r6 * 2) + mul32x32_64(d7, r7 )); - m5 += (mul32x32_64(d9, r6 ) + mul32x32_64(d8, r7 * 2)); - m6 += (mul32x32_64(d9, r7 * 2) + mul32x32_64(d8, r8 )); - m7 += (mul32x32_64(d9, r8 )); - m8 += (mul32x32_64(d9, r9 )); - - r0 = (uint32_t)m0 & reduce_mask_26; c = (m0 >> 26); - m1 += c; r1 = (uint32_t)m1 & reduce_mask_25; c = (m1 >> 25); - m2 += c; r2 = (uint32_t)m2 & reduce_mask_26; c = (m2 >> 26); - m3 += c; r3 = (uint32_t)m3 & reduce_mask_25; c = (m3 >> 25); - m4 += c; r4 = (uint32_t)m4 & reduce_mask_26; c = (m4 >> 26); - m5 += c; r5 = (uint32_t)m5 & reduce_mask_25; c = (m5 >> 25); - m6 += c; r6 = (uint32_t)m6 & reduce_mask_26; c = (m6 >> 26); - m7 += c; r7 = (uint32_t)m7 & reduce_mask_25; c = (m7 >> 25); - m8 += c; r8 = (uint32_t)m8 & reduce_mask_26; c = (m8 >> 26); - m9 += c; r9 = (uint32_t)m9 & reduce_mask_25; p = (uint32_t)(m9 >> 25); - m0 = r0 + mul32x32_64(p,19); r0 = (uint32_t)m0 & reduce_mask_26; p = (uint32_t)(m0 >> 26); - r1 += p; - } while (--count); - - out[0] = r0; - out[1] = r1; - out[2] = r2; - out[3] = r3; - out[4] = r4; - out[5] = r5; - out[6] = r6; - out[7] = r7; - out[8] = r8; - out[9] = r9; -} +void curve25519_square_times(bignum25519 out, const bignum25519 in, int count); /* Take a little-endian, 32-byte number and expand it into polynomial form */ -static void -curve25519_expand(bignum25519 out, const unsigned char in[32]) { - static const union { uint8_t b[2]; uint16_t s; } endian_check = {{1,0}}; - uint32_t x0,x1,x2,x3,x4,x5,x6,x7; - if (endian_check.s == 1) { - /* Take care, this only works when in is aligned */ - x0 = *(uint32_t *)(in + 0); - x1 = *(uint32_t *)(in + 4); - x2 = *(uint32_t *)(in + 8); - x3 = *(uint32_t *)(in + 12); - x4 = *(uint32_t *)(in + 16); - x5 = *(uint32_t *)(in + 20); - x6 = *(uint32_t *)(in + 24); - x7 = *(uint32_t *)(in + 28); - } else { - #define F(s) \ - ((((uint32_t)in[s + 0]) ) | \ - (((uint32_t)in[s + 1]) << 8) | \ - (((uint32_t)in[s + 2]) << 16) | \ - (((uint32_t)in[s + 3]) << 24)) - x0 = F(0); - x1 = F(4); - x2 = F(8); - x3 = F(12); - x4 = F(16); - x5 = F(20); - x6 = F(24); - x7 = F(28); - #undef F - } - - out[0] = ( x0 ) & reduce_mask_26; - out[1] = ((((uint64_t)x1 << 32) | x0) >> 26) & reduce_mask_25; - out[2] = ((((uint64_t)x2 << 32) | x1) >> 19) & reduce_mask_26; - out[3] = ((((uint64_t)x3 << 32) | x2) >> 13) & reduce_mask_25; - out[4] = (( x3) >> 6) & reduce_mask_26; - out[5] = ( x4 ) & reduce_mask_25; - out[6] = ((((uint64_t)x5 << 32) | x4) >> 25) & reduce_mask_26; - out[7] = ((((uint64_t)x6 << 32) | x5) >> 19) & reduce_mask_25; - out[8] = ((((uint64_t)x7 << 32) | x6) >> 12) & reduce_mask_26; - out[9] = (( x7) >> 6) & reduce_mask_25; /* ignore the top bit */ -} +void curve25519_expand(bignum25519 out, const unsigned char in[32]); /* Take a fully reduced polynomial form number and contract it into a * little-endian, 32-byte array */ -static void -curve25519_contract(unsigned char out[32], const bignum25519 in) { - bignum25519 f; - curve25519_copy(f, in); - - #define carry_pass() \ - f[1] += f[0] >> 26; f[0] &= reduce_mask_26; \ - f[2] += f[1] >> 25; f[1] &= reduce_mask_25; \ - f[3] += f[2] >> 26; f[2] &= reduce_mask_26; \ - f[4] += f[3] >> 25; f[3] &= reduce_mask_25; \ - f[5] += f[4] >> 26; f[4] &= reduce_mask_26; \ - f[6] += f[5] >> 25; f[5] &= reduce_mask_25; \ - f[7] += f[6] >> 26; f[6] &= reduce_mask_26; \ - f[8] += f[7] >> 25; f[7] &= reduce_mask_25; \ - f[9] += f[8] >> 26; f[8] &= reduce_mask_26; - - #define carry_pass_full() \ - carry_pass() \ - f[0] += 19 * (f[9] >> 25); f[9] &= reduce_mask_25; - - #define carry_pass_final() \ - carry_pass() \ - f[9] &= reduce_mask_25; - - carry_pass_full() - carry_pass_full() - - /* now t is between 0 and 2^255-1, properly carried. */ - /* case 1: between 0 and 2^255-20. case 2: between 2^255-19 and 2^255-1. */ - f[0] += 19; - carry_pass_full() - - /* now between 19 and 2^255-1 in both cases, and offset by 19. */ - f[0] += (reduce_mask_26 + 1) - 19; - f[1] += (reduce_mask_25 + 1) - 1; - f[2] += (reduce_mask_26 + 1) - 1; - f[3] += (reduce_mask_25 + 1) - 1; - f[4] += (reduce_mask_26 + 1) - 1; - f[5] += (reduce_mask_25 + 1) - 1; - f[6] += (reduce_mask_26 + 1) - 1; - f[7] += (reduce_mask_25 + 1) - 1; - f[8] += (reduce_mask_26 + 1) - 1; - f[9] += (reduce_mask_25 + 1) - 1; - - /* now between 2^255 and 2^256-20, and offset by 2^255. */ - carry_pass_final() - - #undef carry_pass - #undef carry_full - #undef carry_final - - f[1] <<= 2; - f[2] <<= 3; - f[3] <<= 5; - f[4] <<= 6; - f[6] <<= 1; - f[7] <<= 3; - f[8] <<= 4; - f[9] <<= 6; - - #define F(i, s) \ - out[s+0] |= (unsigned char )(f[i] & 0xff); \ - out[s+1] = (unsigned char )((f[i] >> 8) & 0xff); \ - out[s+2] = (unsigned char )((f[i] >> 16) & 0xff); \ - out[s+3] = (unsigned char )((f[i] >> 24) & 0xff); - - out[0] = 0; - out[16] = 0; - F(0,0); - F(1,3); - F(2,6); - F(3,9); - F(4,12); - F(5,16); - F(6,19); - F(7,22); - F(8,25); - F(9,28); - #undef F -} +void curve25519_contract(unsigned char out[32], const bignum25519 in); /* if (iswap) swap(a, b) */ -DONNA_INLINE static void -curve25519_swap_conditional(bignum25519 a, bignum25519 b, uint32_t iswap) { - const uint32_t swap = (uint32_t)(-(int32_t)iswap); - uint32_t x0,x1,x2,x3,x4,x5,x6,x7,x8,x9; - - x0 = swap & (a[0] ^ b[0]); a[0] ^= x0; b[0] ^= x0; - x1 = swap & (a[1] ^ b[1]); a[1] ^= x1; b[1] ^= x1; - x2 = swap & (a[2] ^ b[2]); a[2] ^= x2; b[2] ^= x2; - x3 = swap & (a[3] ^ b[3]); a[3] ^= x3; b[3] ^= x3; - x4 = swap & (a[4] ^ b[4]); a[4] ^= x4; b[4] ^= x4; - x5 = swap & (a[5] ^ b[5]); a[5] ^= x5; b[5] ^= x5; - x6 = swap & (a[6] ^ b[6]); a[6] ^= x6; b[6] ^= x6; - x7 = swap & (a[7] ^ b[7]); a[7] ^= x7; b[7] ^= x7; - x8 = swap & (a[8] ^ b[8]); a[8] ^= x8; b[8] ^= x8; - x9 = swap & (a[9] ^ b[9]); a[9] ^= x9; b[9] ^= x9; -} +void curve25519_swap_conditional(bignum25519 a, bignum25519 b, uint32_t iswap); diff --git a/ed25519-donna/curve25519-donna-helpers.c b/ed25519-donna/curve25519-donna-helpers.c new file mode 100644 index 000000000..fe926d395 --- /dev/null +++ b/ed25519-donna/curve25519-donna-helpers.c @@ -0,0 +1,66 @@ +/* + Public domain by Andrew M. + See: https://github.com/floodyberry/curve25519-donna + + Curve25519 implementation agnostic helpers +*/ + +#include "ed25519-donna.h" + +/* + * In: b = 2^5 - 2^0 + * Out: b = 2^250 - 2^0 + */ +void curve25519_pow_two5mtwo0_two250mtwo0(bignum25519 b) { + bignum25519 ALIGN(16) t0,c; + + /* 2^5 - 2^0 */ /* b */ + /* 2^10 - 2^5 */ curve25519_square_times(t0, b, 5); + /* 2^10 - 2^0 */ curve25519_mul_noinline(b, t0, b); + /* 2^20 - 2^10 */ curve25519_square_times(t0, b, 10); + /* 2^20 - 2^0 */ curve25519_mul_noinline(c, t0, b); + /* 2^40 - 2^20 */ curve25519_square_times(t0, c, 20); + /* 2^40 - 2^0 */ curve25519_mul_noinline(t0, t0, c); + /* 2^50 - 2^10 */ curve25519_square_times(t0, t0, 10); + /* 2^50 - 2^0 */ curve25519_mul_noinline(b, t0, b); + /* 2^100 - 2^50 */ curve25519_square_times(t0, b, 50); + /* 2^100 - 2^0 */ curve25519_mul_noinline(c, t0, b); + /* 2^200 - 2^100 */ curve25519_square_times(t0, c, 100); + /* 2^200 - 2^0 */ curve25519_mul_noinline(t0, t0, c); + /* 2^250 - 2^50 */ curve25519_square_times(t0, t0, 50); + /* 2^250 - 2^0 */ curve25519_mul_noinline(b, t0, b); +} + +/* + * z^(p - 2) = z(2^255 - 21) + */ +void curve25519_recip(bignum25519 out, const bignum25519 z) { + bignum25519 ALIGN(16) a,t0,b; + + /* 2 */ curve25519_square_times(a, z, 1); /* a = 2 */ + /* 8 */ curve25519_square_times(t0, a, 2); + /* 9 */ curve25519_mul_noinline(b, t0, z); /* b = 9 */ + /* 11 */ curve25519_mul_noinline(a, b, a); /* a = 11 */ + /* 22 */ curve25519_square_times(t0, a, 1); + /* 2^5 - 2^0 = 31 */ curve25519_mul_noinline(b, t0, b); + /* 2^250 - 2^0 */ curve25519_pow_two5mtwo0_two250mtwo0(b); + /* 2^255 - 2^5 */ curve25519_square_times(b, b, 5); + /* 2^255 - 21 */ curve25519_mul_noinline(out, b, a); +} + +/* + * z^((p-5)/8) = z^(2^252 - 3) + */ +void curve25519_pow_two252m3(bignum25519 two252m3, const bignum25519 z) { + bignum25519 ALIGN(16) b,c,t0; + + /* 2 */ curve25519_square_times(c, z, 1); /* c = 2 */ + /* 8 */ curve25519_square_times(t0, c, 2); /* t0 = 8 */ + /* 9 */ curve25519_mul_noinline(b, t0, z); /* b = 9 */ + /* 11 */ curve25519_mul_noinline(c, b, c); /* c = 11 */ + /* 22 */ curve25519_square_times(t0, c, 1); + /* 2^5 - 2^0 = 31 */ curve25519_mul_noinline(b, t0, b); + /* 2^250 - 2^0 */ curve25519_pow_two5mtwo0_two250mtwo0(b); + /* 2^252 - 2^2 */ curve25519_square_times(b, b, 2); + /* 2^252 - 3 */ curve25519_mul_noinline(two252m3, b, z); +} diff --git a/ed25519-donna/curve25519-donna-helpers.h b/ed25519-donna/curve25519-donna-helpers.h index e4058ff5e..62fde9099 100644 --- a/ed25519-donna/curve25519-donna-helpers.h +++ b/ed25519-donna/curve25519-donna-helpers.h @@ -9,59 +9,14 @@ * In: b = 2^5 - 2^0 * Out: b = 2^250 - 2^0 */ -static void -curve25519_pow_two5mtwo0_two250mtwo0(bignum25519 b) { - bignum25519 ALIGN(16) t0,c; - - /* 2^5 - 2^0 */ /* b */ - /* 2^10 - 2^5 */ curve25519_square_times(t0, b, 5); - /* 2^10 - 2^0 */ curve25519_mul_noinline(b, t0, b); - /* 2^20 - 2^10 */ curve25519_square_times(t0, b, 10); - /* 2^20 - 2^0 */ curve25519_mul_noinline(c, t0, b); - /* 2^40 - 2^20 */ curve25519_square_times(t0, c, 20); - /* 2^40 - 2^0 */ curve25519_mul_noinline(t0, t0, c); - /* 2^50 - 2^10 */ curve25519_square_times(t0, t0, 10); - /* 2^50 - 2^0 */ curve25519_mul_noinline(b, t0, b); - /* 2^100 - 2^50 */ curve25519_square_times(t0, b, 50); - /* 2^100 - 2^0 */ curve25519_mul_noinline(c, t0, b); - /* 2^200 - 2^100 */ curve25519_square_times(t0, c, 100); - /* 2^200 - 2^0 */ curve25519_mul_noinline(t0, t0, c); - /* 2^250 - 2^50 */ curve25519_square_times(t0, t0, 50); - /* 2^250 - 2^0 */ curve25519_mul_noinline(b, t0, b); -} +void curve25519_pow_two5mtwo0_two250mtwo0(bignum25519 b); /* * z^(p - 2) = z(2^255 - 21) */ -static void -curve25519_recip(bignum25519 out, const bignum25519 z) { - bignum25519 ALIGN(16) a,t0,b; - - /* 2 */ curve25519_square_times(a, z, 1); /* a = 2 */ - /* 8 */ curve25519_square_times(t0, a, 2); - /* 9 */ curve25519_mul_noinline(b, t0, z); /* b = 9 */ - /* 11 */ curve25519_mul_noinline(a, b, a); /* a = 11 */ - /* 22 */ curve25519_square_times(t0, a, 1); - /* 2^5 - 2^0 = 31 */ curve25519_mul_noinline(b, t0, b); - /* 2^250 - 2^0 */ curve25519_pow_two5mtwo0_two250mtwo0(b); - /* 2^255 - 2^5 */ curve25519_square_times(b, b, 5); - /* 2^255 - 21 */ curve25519_mul_noinline(out, b, a); -} +void curve25519_recip(bignum25519 out, const bignum25519 z); /* * z^((p-5)/8) = z^(2^252 - 3) */ -static void -curve25519_pow_two252m3(bignum25519 two252m3, const bignum25519 z) { - bignum25519 ALIGN(16) b,c,t0; - - /* 2 */ curve25519_square_times(c, z, 1); /* c = 2 */ - /* 8 */ curve25519_square_times(t0, c, 2); /* t0 = 8 */ - /* 9 */ curve25519_mul_noinline(b, t0, z); /* b = 9 */ - /* 11 */ curve25519_mul_noinline(c, b, c); /* c = 11 */ - /* 22 */ curve25519_square_times(t0, c, 1); - /* 2^5 - 2^0 = 31 */ curve25519_mul_noinline(b, t0, b); - /* 2^250 - 2^0 */ curve25519_pow_two5mtwo0_two250mtwo0(b); - /* 2^252 - 2^2 */ curve25519_square_times(b, b, 2); - /* 2^252 - 3 */ curve25519_mul_noinline(two252m3, b, z); -} +void curve25519_pow_two252m3(bignum25519 two252m3, const bignum25519 z); diff --git a/ed25519-donna/curve25519-donna-scalarmult-base.c b/ed25519-donna/curve25519-donna-scalarmult-base.c new file mode 100644 index 000000000..6feacb37e --- /dev/null +++ b/ed25519-donna/curve25519-donna-scalarmult-base.c @@ -0,0 +1,67 @@ +#include "ed25519-donna.h" +#include "ed25519.h" + +/* Calculates nQ where Q is the x-coordinate of a point on the curve + * + * mypublic: the packed little endian x coordinate of the resulting curve point + * n: a little endian, 32-byte number + * basepoint: a packed little endian point of the curve + */ + +void curve25519_scalarmult_donna(curve25519_key mypublic, const curve25519_key n, const curve25519_key basepoint) { + bignum25519 nqpqx = {1}, nqpqz = {0}, nqz = {1}, nqx; + bignum25519 q, qx, qpqx, qqx, zzz, zmone; + size_t bit, lastbit; + int32_t i; + + curve25519_expand(q, basepoint); + curve25519_copy(nqx, q); + + /* bit 255 is always 0, and bit 254 is always 1, so skip bit 255 and + start pre-swapped on bit 254 */ + lastbit = 1; + + /* we are doing bits 254..3 in the loop, but are swapping in bits 253..2 */ + for (i = 253; i >= 2; i--) { + curve25519_add(qx, nqx, nqz); + curve25519_sub(nqz, nqx, nqz); + curve25519_add(qpqx, nqpqx, nqpqz); + curve25519_sub(nqpqz, nqpqx, nqpqz); + curve25519_mul(nqpqx, qpqx, nqz); + curve25519_mul(nqpqz, qx, nqpqz); + curve25519_add(qqx, nqpqx, nqpqz); + curve25519_sub(nqpqz, nqpqx, nqpqz); + curve25519_square(nqpqz, nqpqz); + curve25519_square(nqpqx, qqx); + curve25519_mul(nqpqz, nqpqz, q); + curve25519_square(qx, qx); + curve25519_square(nqz, nqz); + curve25519_mul(nqx, qx, nqz); + curve25519_sub(nqz, qx, nqz); + curve25519_scalar_product(zzz, nqz, 121665); + curve25519_add(zzz, zzz, qx); + curve25519_mul(nqz, nqz, zzz); + + bit = (n[i/8] >> (i & 7)) & 1; + curve25519_swap_conditional(nqx, nqpqx, bit ^ lastbit); + curve25519_swap_conditional(nqz, nqpqz, bit ^ lastbit); + lastbit = bit; + } + + /* the final 3 bits are always zero, so we only need to double */ + for (i = 0; i < 3; i++) { + curve25519_add(qx, nqx, nqz); + curve25519_sub(nqz, nqx, nqz); + curve25519_square(qx, qx); + curve25519_square(nqz, nqz); + curve25519_mul(nqx, qx, nqz); + curve25519_sub(nqz, qx, nqz); + curve25519_scalar_product(zzz, nqz, 121665); + curve25519_add(zzz, zzz, qx); + curve25519_mul(nqz, nqz, zzz); + } + + curve25519_recip(zmone, nqz); + curve25519_mul(nqz, nqx, zmone); + curve25519_contract(mypublic, nqz); +} diff --git a/ed25519-donna/curve25519-donna-scalarmult-base.h b/ed25519-donna/curve25519-donna-scalarmult-base.h index ff1010122..9f3d79895 100644 --- a/ed25519-donna/curve25519-donna-scalarmult-base.h +++ b/ed25519-donna/curve25519-donna-scalarmult-base.h @@ -5,61 +5,4 @@ * basepoint: a packed little endian point of the curve */ -static void -curve25519_scalarmult_donna(curve25519_key mypublic, const curve25519_key n, const curve25519_key basepoint) { - bignum25519 nqpqx = {1}, nqpqz = {0}, nqz = {1}, nqx; - bignum25519 q, qx, qpqx, qqx, zzz, zmone; - size_t bit, lastbit; - int32_t i; - - curve25519_expand(q, basepoint); - curve25519_copy(nqx, q); - - /* bit 255 is always 0, and bit 254 is always 1, so skip bit 255 and - start pre-swapped on bit 254 */ - lastbit = 1; - - /* we are doing bits 254..3 in the loop, but are swapping in bits 253..2 */ - for (i = 253; i >= 2; i--) { - curve25519_add(qx, nqx, nqz); - curve25519_sub(nqz, nqx, nqz); - curve25519_add(qpqx, nqpqx, nqpqz); - curve25519_sub(nqpqz, nqpqx, nqpqz); - curve25519_mul(nqpqx, qpqx, nqz); - curve25519_mul(nqpqz, qx, nqpqz); - curve25519_add(qqx, nqpqx, nqpqz); - curve25519_sub(nqpqz, nqpqx, nqpqz); - curve25519_square(nqpqz, nqpqz); - curve25519_square(nqpqx, qqx); - curve25519_mul(nqpqz, nqpqz, q); - curve25519_square(qx, qx); - curve25519_square(nqz, nqz); - curve25519_mul(nqx, qx, nqz); - curve25519_sub(nqz, qx, nqz); - curve25519_scalar_product(zzz, nqz, 121665); - curve25519_add(zzz, zzz, qx); - curve25519_mul(nqz, nqz, zzz); - - bit = (n[i/8] >> (i & 7)) & 1; - curve25519_swap_conditional(nqx, nqpqx, bit ^ lastbit); - curve25519_swap_conditional(nqz, nqpqz, bit ^ lastbit); - lastbit = bit; - } - - /* the final 3 bits are always zero, so we only need to double */ - for (i = 0; i < 3; i++) { - curve25519_add(qx, nqx, nqz); - curve25519_sub(nqz, nqx, nqz); - curve25519_square(qx, qx); - curve25519_square(nqz, nqz); - curve25519_mul(nqx, qx, nqz); - curve25519_sub(nqz, qx, nqz); - curve25519_scalar_product(zzz, nqz, 121665); - curve25519_add(zzz, zzz, qx); - curve25519_mul(nqz, nqz, zzz); - } - - curve25519_recip(zmone, nqz); - curve25519_mul(nqz, nqx, zmone); - curve25519_contract(mypublic, nqz); -} +void curve25519_scalarmult_donna(curve25519_key mypublic, const curve25519_key n, const curve25519_key basepoint); diff --git a/ed25519-donna/ed25519-donna-32bit-tables.c b/ed25519-donna/ed25519-donna-32bit-tables.c new file mode 100644 index 000000000..fd2236b05 --- /dev/null +++ b/ed25519-donna/ed25519-donna-32bit-tables.c @@ -0,0 +1,63 @@ +#include "ed25519-donna.h" + +const ge25519 ALIGN(16) ge25519_basepoint = { + {0x0325d51a,0x018b5823,0x00f6592a,0x0104a92d,0x01a4b31d,0x01d6dc5c,0x027118fe,0x007fd814,0x013cd6e5,0x0085a4db}, + {0x02666658,0x01999999,0x00cccccc,0x01333333,0x01999999,0x00666666,0x03333333,0x00cccccc,0x02666666,0x01999999}, + {0x00000001,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000}, + {0x01b7dda3,0x01a2ace9,0x025eadbb,0x0003ba8a,0x0083c27e,0x00abe37d,0x01274732,0x00ccacdd,0x00fd78b7,0x019e1d7c} +}; + +/* + d +*/ + +const bignum25519 ALIGN(16) ge25519_ecd = { + 0x035978a3,0x00d37284,0x03156ebd,0x006a0a0e,0x0001c029,0x0179e898,0x03a03cbb,0x01ce7198,0x02e2b6ff,0x01480db3 +}; + +const bignum25519 ALIGN(16) ge25519_ec2d = { + 0x02b2f159,0x01a6e509,0x022add7a,0x00d4141d,0x00038052,0x00f3d130,0x03407977,0x019ce331,0x01c56dff,0x00901b67 +}; + +/* + sqrt(-1) +*/ + +const bignum25519 ALIGN(16) ge25519_sqrtneg1 = { + 0x020ea0b0,0x0186c9d2,0x008f189d,0x0035697f,0x00bd0c60,0x01fbd7a7,0x02804c9e,0x01e16569,0x0004fc1d,0x00ae0c92 +}; + +const ge25519_niels ALIGN(16) ge25519_niels_sliding_multiples[32] = { + {{0x0340913e,0x000e4175,0x03d673a2,0x002e8a05,0x03f4e67c,0x008f8a09,0x00c21a34,0x004cf4b8,0x01298f81,0x0113f4be},{0x018c3b85,0x0124f1bd,0x01c325f7,0x0037dc60,0x033e4cb7,0x003d42c2,0x01a44c32,0x014ca4e1,0x03a33d4b,0x001f3e74},{0x037aaa68,0x00448161,0x0093d579,0x011e6556,0x009b67a0,0x0143598c,0x01bee5ee,0x00b50b43,0x0289f0c6,0x01bc45ed}}, + {{0x00fcd265,0x0047fa29,0x034faacc,0x01ef2e0d,0x00ef4d4f,0x014bd6bd,0x00f98d10,0x014c5026,0x007555bd,0x00aae456},{0x00ee9730,0x016c2a13,0x017155e4,0x01874432,0x00096a10,0x01016732,0x01a8014f,0x011e9823,0x01b9a80f,0x01e85938},{0x01d0d889,0x01a4cfc3,0x034c4295,0x0110e1ae,0x0162508c,0x00f2db4c,0x0072a2c6,0x0098da2e,0x02f12b9b,0x0168a09a}}, + {{0x0047d6ba,0x0060b0e9,0x0136eff2,0x008a5939,0x03540053,0x0064a087,0x02788e5c,0x00be7c67,0x033eb1b5,0x005529f9},{0x00a5bb33,0x00af1102,0x01a05442,0x001e3af7,0x02354123,0x00bfec44,0x01f5862d,0x00dd7ba3,0x03146e20,0x00a51733},{0x012a8285,0x00f6fc60,0x023f9797,0x003e85ee,0x009c3820,0x01bda72d,0x01b3858d,0x00d35683,0x0296b3bb,0x010eaaf9}}, + {{0x023221b1,0x01cb26aa,0x0074f74d,0x0099ddd1,0x01b28085,0x00192c3a,0x013b27c9,0x00fc13bd,0x01d2e531,0x0075bb75},{0x004ea3bf,0x00973425,0x001a4d63,0x01d59cee,0x01d1c0d4,0x00542e49,0x01294114,0x004fce36,0x029283c9,0x01186fa9},{0x01b8b3a2,0x00db7200,0x00935e30,0x003829f5,0x02cc0d7d,0x0077adf3,0x0220dd2c,0x0014ea53,0x01c6a0f9,0x01ea7eec}}, + {{0x039d8064,0x01885f80,0x00337e6d,0x01b7a902,0x02628206,0x015eb044,0x01e30473,0x0191f2d9,0x011fadc9,0x01270169},{0x02a8632f,0x0199e2a9,0x00d8b365,0x017a8de2,0x02994279,0x0086f5b5,0x0119e4e3,0x01eb39d6,0x0338add7,0x00d2e7b4},{0x0045af1b,0x013a2fe4,0x0245e0d6,0x014538ce,0x038bfe0f,0x01d4cf16,0x037e14c9,0x0160d55e,0x0021b008,0x01cf05c8}}, + {{0x01864348,0x01d6c092,0x0070262b,0x014bb844,0x00fb5acd,0x008deb95,0x003aaab5,0x00eff474,0x00029d5c,0x0062ad66},{0x02802ade,0x01c02122,0x01c4e5f7,0x00781181,0x039767fb,0x01703406,0x0342388b,0x01f5e227,0x022546d8,0x0109d6ab},{0x016089e9,0x00cb317f,0x00949b05,0x01099417,0x000c7ad2,0x011a8622,0x0088ccda,0x01290886,0x022b53df,0x00f71954}}, + {{0x027fbf93,0x01c04ecc,0x01ed6a0d,0x004cdbbb,0x02bbf3af,0x00ad5968,0x01591955,0x0094f3a2,0x02d17602,0x00099e20},{0x02007f6d,0x003088a8,0x03db77ee,0x00d5ade6,0x02fe12ce,0x0107ba07,0x0107097d,0x00482a6f,0x02ec346f,0x008d3f5f},{0x032ea378,0x0028465c,0x028e2a6c,0x018efc6e,0x0090df9a,0x01a7e533,0x039bfc48,0x010c745d,0x03daa097,0x0125ee9b}}, + {{0x028ccf0b,0x00f36191,0x021ac081,0x012154c8,0x034e0a6e,0x01b25192,0x00180403,0x01d7eea1,0x00218d05,0x010ed735},{0x03cfeaa0,0x01b300c4,0x008da499,0x0068c4e1,0x0219230a,0x01f2d4d0,0x02defd60,0x00e565b7,0x017f12de,0x018788a4},{0x03d0b516,0x009d8be6,0x03ddcbb3,0x0071b9fe,0x03ace2bd,0x01d64270,0x032d3ec9,0x01084065,0x0210ae4d,0x01447584}}, + {{0x0020de87,0x00e19211,0x01b68102,0x00b5ac97,0x022873c0,0x01942d25,0x01271394,0x0102073f,0x02fe2482,0x01c69ff9},{0x010e9d81,0x019dbbe5,0x0089f258,0x006e06b8,0x02951883,0x018f1248,0x019b3237,0x00bc7553,0x024ddb85,0x01b4c964},{0x01c8c854,0x0060ae29,0x01406d8e,0x01cff2f9,0x00cff451,0x01778d0c,0x03ac8c41,0x01552e59,0x036559ee,0x011d1b12}}, + {{0x00741147,0x0151b219,0x01092690,0x00e877e6,0x01f4d6bb,0x0072a332,0x01cd3b03,0x00dadff2,0x0097db5e,0x0086598d},{0x01c69a2b,0x01decf1b,0x02c2fa6e,0x013b7c4f,0x037beac8,0x013a16b5,0x028e7bda,0x01f6e8ac,0x01e34fe9,0x01726947},{0x01f10e67,0x003c73de,0x022b7ea2,0x010f32c2,0x03ff776a,0x00142277,0x01d38b88,0x00776138,0x03c60822,0x01201140}}, + {{0x0236d175,0x0008748e,0x03c6476d,0x013f4cdc,0x02eed02a,0x00838a47,0x032e7210,0x018bcbb3,0x00858de4,0x01dc7826},{0x00a37fc7,0x0127b40b,0x01957884,0x011d30ad,0x02816683,0x016e0e23,0x00b76be4,0x012db115,0x02516506,0x0154ce62},{0x00451edf,0x00bd749e,0x03997342,0x01cc2c4c,0x00eb6975,0x01a59508,0x03a516cf,0x00c228ef,0x0168ff5a,0x01697b47}}, + {{0x00527359,0x01783156,0x03afd75c,0x00ce56dc,0x00e4b970,0x001cabe9,0x029e0f6d,0x0188850c,0x0135fefd,0x00066d80},{0x02150e83,0x01448abf,0x02bb0232,0x012bf259,0x033c8268,0x00711e20,0x03fc148f,0x005e0e70,0x017d8bf9,0x0112b2e2},{0x02134b83,0x001a0517,0x0182c3cc,0x00792182,0x0313d799,0x001a3ed7,0x0344547e,0x01f24a0d,0x03de6ad2,0x00543127}}, + {{0x00dca868,0x00618f27,0x015a1709,0x00ddc38a,0x0320fd13,0x0036168d,0x0371ab06,0x01783fc7,0x0391e05f,0x01e29b5d},{0x01471138,0x00fca542,0x00ca31cf,0x01ca7bad,0x0175bfbc,0x01a708ad,0x03bce212,0x01244215,0x0075bb99,0x01acad68},{0x03a0b976,0x01dc12d1,0x011aab17,0x00aba0ba,0x029806cd,0x0142f590,0x018fd8ea,0x01a01545,0x03c4ad55,0x01c971ff}}, + {{0x00d098c0,0x000afdc7,0x006cd230,0x01276af3,0x03f905b2,0x0102994c,0x002eb8a4,0x015cfbeb,0x025f855f,0x01335518},{0x01cf99b2,0x0099c574,0x01a69c88,0x00881510,0x01cd4b54,0x0112109f,0x008abdc5,0x0074647a,0x0277cb1f,0x01e53324},{0x02ac5053,0x01b109b0,0x024b095e,0x016997b3,0x02f26bb6,0x00311021,0x00197885,0x01d0a55a,0x03b6fcc8,0x01c020d5}}, + {{0x02584a34,0x00e7eee0,0x03257a03,0x011e95a3,0x011ead91,0x00536202,0x00b1ce24,0x008516c6,0x03669d6d,0x004ea4a8},{0x00773f01,0x0019c9ce,0x019f6171,0x01d4afde,0x02e33323,0x01ad29b6,0x02ead1dc,0x01ed51a5,0x01851ad0,0x001bbdfa},{0x00577de5,0x00ddc730,0x038b9952,0x00f281ae,0x01d50390,0x0002e071,0x000780ec,0x010d448d,0x01f8a2af,0x00f0a5b7}}, + {{0x031f2541,0x00d34bae,0x0323ff9d,0x003a056d,0x02e25443,0x00a1ad05,0x00d1bee8,0x002f7f8e,0x03007477,0x002a24b1},{0x0114a713,0x01457e76,0x032255d5,0x01cc647f,0x02a4bdef,0x0153d730,0x00118bcf,0x00f755ff,0x013490c7,0x01ea674e},{0x02bda3e8,0x00bb490d,0x00f291ea,0x000abf40,0x01dea321,0x002f9ce0,0x00b2b193,0x00fa54b5,0x0128302f,0x00a19d8b}}, + {{0x022ef5bd,0x01638af3,0x038c6f8a,0x01a33a3d,0x039261b2,0x01bb89b8,0x010bcf9d,0x00cf42a9,0x023d6f17,0x01da1bca},{0x00e35b25,0x000d824f,0x0152e9cf,0x00ed935d,0x020b8460,0x01c7b83f,0x00c969e5,0x01a74198,0x0046a9d9,0x00cbc768},{0x01597c6a,0x0144a99b,0x00a57551,0x0018269c,0x023c464c,0x0009b022,0x00ee39e1,0x0114c7f2,0x038a9ad2,0x01584c17}}, + {{0x03b0c0d5,0x00b30a39,0x038a6ce4,0x01ded83a,0x01c277a6,0x01010a61,0x0346d3eb,0x018d995e,0x02f2c57c,0x000c286b},{0x0092aed1,0x0125e37b,0x027ca201,0x001a6b6b,0x03290f55,0x0047ba48,0x018d916c,0x01a59062,0x013e35d4,0x0002abb1},{0x003ad2aa,0x007ddcc0,0x00c10f76,0x0001590b,0x002cfca6,0x000ed23e,0x00ee4329,0x00900f04,0x01c24065,0x0082fa70}}, + {{0x02025e60,0x003912b8,0x0327041c,0x017e5ee5,0x02c0ecec,0x015a0d1c,0x02b1ce7c,0x0062220b,0x0145067e,0x01a5d931},{0x009673a6,0x00e1f609,0x00927c2a,0x016faa37,0x01650ef0,0x016f63b5,0x03cd40e1,0x003bc38f,0x0361f0ac,0x01d42acc},{0x02f81037,0x008ca0e8,0x017e23d1,0x011debfe,0x01bcbb68,0x002e2563,0x03e8add6,0x000816e5,0x03fb7075,0x0153e5ac}}, + {{0x02b11ecd,0x016bf185,0x008f22ef,0x00e7d2bb,0x0225d92e,0x00ece785,0x00508873,0x017e16f5,0x01fbe85d,0x01e39a0e},{0x01669279,0x017c810a,0x024941f5,0x0023ebeb,0x00eb7688,0x005760f1,0x02ca4146,0x0073cde7,0x0052bb75,0x00f5ffa7},{0x03b8856b,0x00cb7dcd,0x02f14e06,0x001820d0,0x01d74175,0x00e59e22,0x03fba550,0x00484641,0x03350088,0x01c3c9a3}}, + {{0x00dcf355,0x0104481c,0x0022e464,0x01f73fe7,0x00e03325,0x0152b698,0x02ef769a,0x00973663,0x00039b8c,0x0101395b},{0x01805f47,0x019160ec,0x03832cd0,0x008b06eb,0x03d4d717,0x004cb006,0x03a75b8f,0x013b3d30,0x01cfad88,0x01f034d1},{0x0078338a,0x01c7d2e3,0x02bc2b23,0x018b3f05,0x0280d9aa,0x005f3d44,0x0220a95a,0x00eeeb97,0x0362aaec,0x00835d51}}, + {{0x01b9f543,0x013fac4d,0x02ad93ae,0x018ef464,0x0212cdf7,0x01138ba9,0x011583ab,0x019c3d26,0x028790b4,0x00e2e2b6},{0x033bb758,0x01f0dbf1,0x03734bd1,0x0129b1e5,0x02b3950e,0x003bc922,0x01a53ec8,0x018c5532,0x006f3cee,0x00ae3c79},{0x0351f95d,0x0012a737,0x03d596b8,0x017658fe,0x00ace54a,0x008b66da,0x0036c599,0x012a63a2,0x032ceba1,0x00126bac}}, + {{0x03dcfe7e,0x019f4f18,0x01c81aee,0x0044bc2b,0x00827165,0x014f7c13,0x03b430f0,0x00bf96cc,0x020c8d62,0x01471997},{0x01fc7931,0x001f42dd,0x00ba754a,0x005bd339,0x003fbe49,0x016b3930,0x012a159c,0x009f83b0,0x03530f67,0x01e57b85},{0x02ecbd81,0x0096c294,0x01fce4a9,0x017701a5,0x0175047d,0x00ee4a31,0x012686e5,0x008efcd4,0x0349dc54,0x01b3466f}}, + {{0x02179ca3,0x01d86414,0x03f0afd0,0x00305964,0x015c7428,0x0099711e,0x015d5442,0x00c71014,0x01b40b2e,0x01d483cf},{0x01afc386,0x01984859,0x036203ff,0x0045c6a8,0x0020a8aa,0x00990baa,0x03313f10,0x007ceede,0x027429e4,0x017806ce},{0x039357a1,0x0142f8f4,0x0294a7b6,0x00eaccf4,0x0259edb3,0x01311e6e,0x004d326f,0x0130c346,0x01ccef3c,0x01c424b2}}, + {{0x0364918c,0x00148fc0,0x01638a7b,0x01a1fd5b,0x028ad013,0x0081e5a4,0x01a54f33,0x0174e101,0x003d0257,0x003a856c},{0x00051dcf,0x00f62b1d,0x0143d0ad,0x0042adbd,0x000fda90,0x01743ceb,0x0173e5e4,0x017bc749,0x03b7137a,0x0105ce96},{0x00f9218a,0x015b8c7c,0x00e102f8,0x0158d7e2,0x0169a5b8,0x00b2f176,0x018b347a,0x014cfef2,0x0214a4e3,0x017f1595}}, + {{0x006d7ae5,0x0195c371,0x0391e26d,0x0062a7c6,0x003f42ab,0x010dad86,0x024f8198,0x01542b2a,0x0014c454,0x0189c471},{0x0390988e,0x00b8799d,0x02e44912,0x0078e2e6,0x00075654,0x01923eed,0x0040cd72,0x00a37c76,0x0009d466,0x00c8531d},{0x02651770,0x00609d01,0x0286c265,0x0134513c,0x00ee9281,0x005d223c,0x035c760c,0x00679b36,0x0073ecb8,0x016faa50}}, + {{0x02c89be4,0x016fc244,0x02f38c83,0x018beb72,0x02b3ce2c,0x0097b065,0x034f017b,0x01dd957f,0x00148f61,0x00eab357},{0x0343d2f8,0x003398fc,0x011e368e,0x00782a1f,0x00019eea,0x00117b6f,0x0128d0d1,0x01a5e6bb,0x01944f1b,0x012b41e1},{0x03318301,0x018ecd30,0x0104d0b1,0x0038398b,0x03726701,0x019da88c,0x002d9769,0x00a7a681,0x031d9028,0x00ebfc32}}, + {{0x0220405e,0x0171face,0x02d930f8,0x017f6d6a,0x023b8c47,0x0129d5f9,0x02972456,0x00a3a524,0x006f4cd2,0x004439fa},{0x00c53505,0x0190c2fd,0x00507244,0x009930f9,0x01a39270,0x01d327c6,0x0399bc47,0x01cfe13d,0x0332bd99,0x00b33e7d},{0x0203f5e4,0x003627b5,0x00018af8,0x01478581,0x004a2218,0x002e3bb7,0x039384d0,0x0146ea62,0x020b9693,0x0017155f}}, + {{0x03c97e6f,0x00738c47,0x03b5db1f,0x01808fcf,0x01e8fc98,0x01ed25dd,0x01bf5045,0x00eb5c2b,0x0178fe98,0x01b85530},{0x01c20eb0,0x01aeec22,0x030b9eee,0x01b7d07e,0x0187e16f,0x014421fb,0x009fa731,0x0040b6d7,0x00841861,0x00a27fbc},{0x02d69abf,0x0058cdbf,0x0129f9ec,0x013c19ae,0x026c5b93,0x013a7fe7,0x004bb2ba,0x0063226f,0x002a95ca,0x01abefd9}}, + {{0x02f5d2c1,0x00378318,0x03734fb5,0x01258073,0x0263f0f6,0x01ad70e0,0x01b56d06,0x01188fbd,0x011b9503,0x0036d2e1},{0x0113a8cc,0x01541c3e,0x02ac2bbc,0x01d95867,0x01f47459,0x00ead489,0x00ab5b48,0x01db3b45,0x00edb801,0x004b024f},{0x00b8190f,0x011fe4c2,0x00621f82,0x010508d7,0x001a5a76,0x00c7d7fd,0x03aab96d,0x019cd9dc,0x019c6635,0x00ceaa1e}}, + {{0x01085cf2,0x01fd47af,0x03e3f5e1,0x004b3e99,0x01e3d46a,0x0060033c,0x015ff0a8,0x0150cdd8,0x029e8e21,0x008cf1bc},{0x00156cb1,0x003d623f,0x01a4f069,0x00d8d053,0x01b68aea,0x01ca5ab6,0x0316ae43,0x0134dc44,0x001c8d58,0x0084b343},{0x0318c781,0x0135441f,0x03a51a5e,0x019293f4,0x0048bb37,0x013d3341,0x0143151e,0x019c74e1,0x00911914,0x0076ddde}}, + {{0x006bc26f,0x00d48e5f,0x00227bbe,0x00629ea8,0x01ea5f8b,0x0179a330,0x027a1d5f,0x01bf8f8e,0x02d26e2a,0x00c6b65e},{0x01701ab6,0x0051da77,0x01b4b667,0x00a0ce7c,0x038ae37b,0x012ac852,0x03a0b0fe,0x0097c2bb,0x00a017d2,0x01eb8b2a},{0x0120b962,0x0005fb42,0x0353b6fd,0x0061f8ce,0x007a1463,0x01560a64,0x00e0a792,0x01907c92,0x013a6622,0x007b47f1}} +}; diff --git a/ed25519-donna/ed25519-donna-32bit-tables.h b/ed25519-donna/ed25519-donna-32bit-tables.h index c977c26eb..f76a832cf 100644 --- a/ed25519-donna/ed25519-donna-32bit-tables.h +++ b/ed25519-donna/ed25519-donna-32bit-tables.h @@ -1,61 +1,17 @@ -static const ge25519 ALIGN(16) ge25519_basepoint = { - {0x0325d51a,0x018b5823,0x00f6592a,0x0104a92d,0x01a4b31d,0x01d6dc5c,0x027118fe,0x007fd814,0x013cd6e5,0x0085a4db}, - {0x02666658,0x01999999,0x00cccccc,0x01333333,0x01999999,0x00666666,0x03333333,0x00cccccc,0x02666666,0x01999999}, - {0x00000001,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000}, - {0x01b7dda3,0x01a2ace9,0x025eadbb,0x0003ba8a,0x0083c27e,0x00abe37d,0x01274732,0x00ccacdd,0x00fd78b7,0x019e1d7c} -}; +extern const ge25519 ALIGN(16) ge25519_basepoint; /* d */ -static const bignum25519 ALIGN(16) ge25519_ecd = { - 0x035978a3,0x00d37284,0x03156ebd,0x006a0a0e,0x0001c029,0x0179e898,0x03a03cbb,0x01ce7198,0x02e2b6ff,0x01480db3 -}; +extern const bignum25519 ALIGN(16) ge25519_ecd; -static const bignum25519 ALIGN(16) ge25519_ec2d = { - 0x02b2f159,0x01a6e509,0x022add7a,0x00d4141d,0x00038052,0x00f3d130,0x03407977,0x019ce331,0x01c56dff,0x00901b67 -}; +extern const bignum25519 ALIGN(16) ge25519_ec2d; /* sqrt(-1) */ -static const bignum25519 ALIGN(16) ge25519_sqrtneg1 = { - 0x020ea0b0,0x0186c9d2,0x008f189d,0x0035697f,0x00bd0c60,0x01fbd7a7,0x02804c9e,0x01e16569,0x0004fc1d,0x00ae0c92 -}; +extern const bignum25519 ALIGN(16) ge25519_sqrtneg1; -static const ge25519_niels ALIGN(16) ge25519_niels_sliding_multiples[32] = { - {{0x0340913e,0x000e4175,0x03d673a2,0x002e8a05,0x03f4e67c,0x008f8a09,0x00c21a34,0x004cf4b8,0x01298f81,0x0113f4be},{0x018c3b85,0x0124f1bd,0x01c325f7,0x0037dc60,0x033e4cb7,0x003d42c2,0x01a44c32,0x014ca4e1,0x03a33d4b,0x001f3e74},{0x037aaa68,0x00448161,0x0093d579,0x011e6556,0x009b67a0,0x0143598c,0x01bee5ee,0x00b50b43,0x0289f0c6,0x01bc45ed}}, - {{0x00fcd265,0x0047fa29,0x034faacc,0x01ef2e0d,0x00ef4d4f,0x014bd6bd,0x00f98d10,0x014c5026,0x007555bd,0x00aae456},{0x00ee9730,0x016c2a13,0x017155e4,0x01874432,0x00096a10,0x01016732,0x01a8014f,0x011e9823,0x01b9a80f,0x01e85938},{0x01d0d889,0x01a4cfc3,0x034c4295,0x0110e1ae,0x0162508c,0x00f2db4c,0x0072a2c6,0x0098da2e,0x02f12b9b,0x0168a09a}}, - {{0x0047d6ba,0x0060b0e9,0x0136eff2,0x008a5939,0x03540053,0x0064a087,0x02788e5c,0x00be7c67,0x033eb1b5,0x005529f9},{0x00a5bb33,0x00af1102,0x01a05442,0x001e3af7,0x02354123,0x00bfec44,0x01f5862d,0x00dd7ba3,0x03146e20,0x00a51733},{0x012a8285,0x00f6fc60,0x023f9797,0x003e85ee,0x009c3820,0x01bda72d,0x01b3858d,0x00d35683,0x0296b3bb,0x010eaaf9}}, - {{0x023221b1,0x01cb26aa,0x0074f74d,0x0099ddd1,0x01b28085,0x00192c3a,0x013b27c9,0x00fc13bd,0x01d2e531,0x0075bb75},{0x004ea3bf,0x00973425,0x001a4d63,0x01d59cee,0x01d1c0d4,0x00542e49,0x01294114,0x004fce36,0x029283c9,0x01186fa9},{0x01b8b3a2,0x00db7200,0x00935e30,0x003829f5,0x02cc0d7d,0x0077adf3,0x0220dd2c,0x0014ea53,0x01c6a0f9,0x01ea7eec}}, - {{0x039d8064,0x01885f80,0x00337e6d,0x01b7a902,0x02628206,0x015eb044,0x01e30473,0x0191f2d9,0x011fadc9,0x01270169},{0x02a8632f,0x0199e2a9,0x00d8b365,0x017a8de2,0x02994279,0x0086f5b5,0x0119e4e3,0x01eb39d6,0x0338add7,0x00d2e7b4},{0x0045af1b,0x013a2fe4,0x0245e0d6,0x014538ce,0x038bfe0f,0x01d4cf16,0x037e14c9,0x0160d55e,0x0021b008,0x01cf05c8}}, - {{0x01864348,0x01d6c092,0x0070262b,0x014bb844,0x00fb5acd,0x008deb95,0x003aaab5,0x00eff474,0x00029d5c,0x0062ad66},{0x02802ade,0x01c02122,0x01c4e5f7,0x00781181,0x039767fb,0x01703406,0x0342388b,0x01f5e227,0x022546d8,0x0109d6ab},{0x016089e9,0x00cb317f,0x00949b05,0x01099417,0x000c7ad2,0x011a8622,0x0088ccda,0x01290886,0x022b53df,0x00f71954}}, - {{0x027fbf93,0x01c04ecc,0x01ed6a0d,0x004cdbbb,0x02bbf3af,0x00ad5968,0x01591955,0x0094f3a2,0x02d17602,0x00099e20},{0x02007f6d,0x003088a8,0x03db77ee,0x00d5ade6,0x02fe12ce,0x0107ba07,0x0107097d,0x00482a6f,0x02ec346f,0x008d3f5f},{0x032ea378,0x0028465c,0x028e2a6c,0x018efc6e,0x0090df9a,0x01a7e533,0x039bfc48,0x010c745d,0x03daa097,0x0125ee9b}}, - {{0x028ccf0b,0x00f36191,0x021ac081,0x012154c8,0x034e0a6e,0x01b25192,0x00180403,0x01d7eea1,0x00218d05,0x010ed735},{0x03cfeaa0,0x01b300c4,0x008da499,0x0068c4e1,0x0219230a,0x01f2d4d0,0x02defd60,0x00e565b7,0x017f12de,0x018788a4},{0x03d0b516,0x009d8be6,0x03ddcbb3,0x0071b9fe,0x03ace2bd,0x01d64270,0x032d3ec9,0x01084065,0x0210ae4d,0x01447584}}, - {{0x0020de87,0x00e19211,0x01b68102,0x00b5ac97,0x022873c0,0x01942d25,0x01271394,0x0102073f,0x02fe2482,0x01c69ff9},{0x010e9d81,0x019dbbe5,0x0089f258,0x006e06b8,0x02951883,0x018f1248,0x019b3237,0x00bc7553,0x024ddb85,0x01b4c964},{0x01c8c854,0x0060ae29,0x01406d8e,0x01cff2f9,0x00cff451,0x01778d0c,0x03ac8c41,0x01552e59,0x036559ee,0x011d1b12}}, - {{0x00741147,0x0151b219,0x01092690,0x00e877e6,0x01f4d6bb,0x0072a332,0x01cd3b03,0x00dadff2,0x0097db5e,0x0086598d},{0x01c69a2b,0x01decf1b,0x02c2fa6e,0x013b7c4f,0x037beac8,0x013a16b5,0x028e7bda,0x01f6e8ac,0x01e34fe9,0x01726947},{0x01f10e67,0x003c73de,0x022b7ea2,0x010f32c2,0x03ff776a,0x00142277,0x01d38b88,0x00776138,0x03c60822,0x01201140}}, - {{0x0236d175,0x0008748e,0x03c6476d,0x013f4cdc,0x02eed02a,0x00838a47,0x032e7210,0x018bcbb3,0x00858de4,0x01dc7826},{0x00a37fc7,0x0127b40b,0x01957884,0x011d30ad,0x02816683,0x016e0e23,0x00b76be4,0x012db115,0x02516506,0x0154ce62},{0x00451edf,0x00bd749e,0x03997342,0x01cc2c4c,0x00eb6975,0x01a59508,0x03a516cf,0x00c228ef,0x0168ff5a,0x01697b47}}, - {{0x00527359,0x01783156,0x03afd75c,0x00ce56dc,0x00e4b970,0x001cabe9,0x029e0f6d,0x0188850c,0x0135fefd,0x00066d80},{0x02150e83,0x01448abf,0x02bb0232,0x012bf259,0x033c8268,0x00711e20,0x03fc148f,0x005e0e70,0x017d8bf9,0x0112b2e2},{0x02134b83,0x001a0517,0x0182c3cc,0x00792182,0x0313d799,0x001a3ed7,0x0344547e,0x01f24a0d,0x03de6ad2,0x00543127}}, - {{0x00dca868,0x00618f27,0x015a1709,0x00ddc38a,0x0320fd13,0x0036168d,0x0371ab06,0x01783fc7,0x0391e05f,0x01e29b5d},{0x01471138,0x00fca542,0x00ca31cf,0x01ca7bad,0x0175bfbc,0x01a708ad,0x03bce212,0x01244215,0x0075bb99,0x01acad68},{0x03a0b976,0x01dc12d1,0x011aab17,0x00aba0ba,0x029806cd,0x0142f590,0x018fd8ea,0x01a01545,0x03c4ad55,0x01c971ff}}, - {{0x00d098c0,0x000afdc7,0x006cd230,0x01276af3,0x03f905b2,0x0102994c,0x002eb8a4,0x015cfbeb,0x025f855f,0x01335518},{0x01cf99b2,0x0099c574,0x01a69c88,0x00881510,0x01cd4b54,0x0112109f,0x008abdc5,0x0074647a,0x0277cb1f,0x01e53324},{0x02ac5053,0x01b109b0,0x024b095e,0x016997b3,0x02f26bb6,0x00311021,0x00197885,0x01d0a55a,0x03b6fcc8,0x01c020d5}}, - {{0x02584a34,0x00e7eee0,0x03257a03,0x011e95a3,0x011ead91,0x00536202,0x00b1ce24,0x008516c6,0x03669d6d,0x004ea4a8},{0x00773f01,0x0019c9ce,0x019f6171,0x01d4afde,0x02e33323,0x01ad29b6,0x02ead1dc,0x01ed51a5,0x01851ad0,0x001bbdfa},{0x00577de5,0x00ddc730,0x038b9952,0x00f281ae,0x01d50390,0x0002e071,0x000780ec,0x010d448d,0x01f8a2af,0x00f0a5b7}}, - {{0x031f2541,0x00d34bae,0x0323ff9d,0x003a056d,0x02e25443,0x00a1ad05,0x00d1bee8,0x002f7f8e,0x03007477,0x002a24b1},{0x0114a713,0x01457e76,0x032255d5,0x01cc647f,0x02a4bdef,0x0153d730,0x00118bcf,0x00f755ff,0x013490c7,0x01ea674e},{0x02bda3e8,0x00bb490d,0x00f291ea,0x000abf40,0x01dea321,0x002f9ce0,0x00b2b193,0x00fa54b5,0x0128302f,0x00a19d8b}}, - {{0x022ef5bd,0x01638af3,0x038c6f8a,0x01a33a3d,0x039261b2,0x01bb89b8,0x010bcf9d,0x00cf42a9,0x023d6f17,0x01da1bca},{0x00e35b25,0x000d824f,0x0152e9cf,0x00ed935d,0x020b8460,0x01c7b83f,0x00c969e5,0x01a74198,0x0046a9d9,0x00cbc768},{0x01597c6a,0x0144a99b,0x00a57551,0x0018269c,0x023c464c,0x0009b022,0x00ee39e1,0x0114c7f2,0x038a9ad2,0x01584c17}}, - {{0x03b0c0d5,0x00b30a39,0x038a6ce4,0x01ded83a,0x01c277a6,0x01010a61,0x0346d3eb,0x018d995e,0x02f2c57c,0x000c286b},{0x0092aed1,0x0125e37b,0x027ca201,0x001a6b6b,0x03290f55,0x0047ba48,0x018d916c,0x01a59062,0x013e35d4,0x0002abb1},{0x003ad2aa,0x007ddcc0,0x00c10f76,0x0001590b,0x002cfca6,0x000ed23e,0x00ee4329,0x00900f04,0x01c24065,0x0082fa70}}, - {{0x02025e60,0x003912b8,0x0327041c,0x017e5ee5,0x02c0ecec,0x015a0d1c,0x02b1ce7c,0x0062220b,0x0145067e,0x01a5d931},{0x009673a6,0x00e1f609,0x00927c2a,0x016faa37,0x01650ef0,0x016f63b5,0x03cd40e1,0x003bc38f,0x0361f0ac,0x01d42acc},{0x02f81037,0x008ca0e8,0x017e23d1,0x011debfe,0x01bcbb68,0x002e2563,0x03e8add6,0x000816e5,0x03fb7075,0x0153e5ac}}, - {{0x02b11ecd,0x016bf185,0x008f22ef,0x00e7d2bb,0x0225d92e,0x00ece785,0x00508873,0x017e16f5,0x01fbe85d,0x01e39a0e},{0x01669279,0x017c810a,0x024941f5,0x0023ebeb,0x00eb7688,0x005760f1,0x02ca4146,0x0073cde7,0x0052bb75,0x00f5ffa7},{0x03b8856b,0x00cb7dcd,0x02f14e06,0x001820d0,0x01d74175,0x00e59e22,0x03fba550,0x00484641,0x03350088,0x01c3c9a3}}, - {{0x00dcf355,0x0104481c,0x0022e464,0x01f73fe7,0x00e03325,0x0152b698,0x02ef769a,0x00973663,0x00039b8c,0x0101395b},{0x01805f47,0x019160ec,0x03832cd0,0x008b06eb,0x03d4d717,0x004cb006,0x03a75b8f,0x013b3d30,0x01cfad88,0x01f034d1},{0x0078338a,0x01c7d2e3,0x02bc2b23,0x018b3f05,0x0280d9aa,0x005f3d44,0x0220a95a,0x00eeeb97,0x0362aaec,0x00835d51}}, - {{0x01b9f543,0x013fac4d,0x02ad93ae,0x018ef464,0x0212cdf7,0x01138ba9,0x011583ab,0x019c3d26,0x028790b4,0x00e2e2b6},{0x033bb758,0x01f0dbf1,0x03734bd1,0x0129b1e5,0x02b3950e,0x003bc922,0x01a53ec8,0x018c5532,0x006f3cee,0x00ae3c79},{0x0351f95d,0x0012a737,0x03d596b8,0x017658fe,0x00ace54a,0x008b66da,0x0036c599,0x012a63a2,0x032ceba1,0x00126bac}}, - {{0x03dcfe7e,0x019f4f18,0x01c81aee,0x0044bc2b,0x00827165,0x014f7c13,0x03b430f0,0x00bf96cc,0x020c8d62,0x01471997},{0x01fc7931,0x001f42dd,0x00ba754a,0x005bd339,0x003fbe49,0x016b3930,0x012a159c,0x009f83b0,0x03530f67,0x01e57b85},{0x02ecbd81,0x0096c294,0x01fce4a9,0x017701a5,0x0175047d,0x00ee4a31,0x012686e5,0x008efcd4,0x0349dc54,0x01b3466f}}, - {{0x02179ca3,0x01d86414,0x03f0afd0,0x00305964,0x015c7428,0x0099711e,0x015d5442,0x00c71014,0x01b40b2e,0x01d483cf},{0x01afc386,0x01984859,0x036203ff,0x0045c6a8,0x0020a8aa,0x00990baa,0x03313f10,0x007ceede,0x027429e4,0x017806ce},{0x039357a1,0x0142f8f4,0x0294a7b6,0x00eaccf4,0x0259edb3,0x01311e6e,0x004d326f,0x0130c346,0x01ccef3c,0x01c424b2}}, - {{0x0364918c,0x00148fc0,0x01638a7b,0x01a1fd5b,0x028ad013,0x0081e5a4,0x01a54f33,0x0174e101,0x003d0257,0x003a856c},{0x00051dcf,0x00f62b1d,0x0143d0ad,0x0042adbd,0x000fda90,0x01743ceb,0x0173e5e4,0x017bc749,0x03b7137a,0x0105ce96},{0x00f9218a,0x015b8c7c,0x00e102f8,0x0158d7e2,0x0169a5b8,0x00b2f176,0x018b347a,0x014cfef2,0x0214a4e3,0x017f1595}}, - {{0x006d7ae5,0x0195c371,0x0391e26d,0x0062a7c6,0x003f42ab,0x010dad86,0x024f8198,0x01542b2a,0x0014c454,0x0189c471},{0x0390988e,0x00b8799d,0x02e44912,0x0078e2e6,0x00075654,0x01923eed,0x0040cd72,0x00a37c76,0x0009d466,0x00c8531d},{0x02651770,0x00609d01,0x0286c265,0x0134513c,0x00ee9281,0x005d223c,0x035c760c,0x00679b36,0x0073ecb8,0x016faa50}}, - {{0x02c89be4,0x016fc244,0x02f38c83,0x018beb72,0x02b3ce2c,0x0097b065,0x034f017b,0x01dd957f,0x00148f61,0x00eab357},{0x0343d2f8,0x003398fc,0x011e368e,0x00782a1f,0x00019eea,0x00117b6f,0x0128d0d1,0x01a5e6bb,0x01944f1b,0x012b41e1},{0x03318301,0x018ecd30,0x0104d0b1,0x0038398b,0x03726701,0x019da88c,0x002d9769,0x00a7a681,0x031d9028,0x00ebfc32}}, - {{0x0220405e,0x0171face,0x02d930f8,0x017f6d6a,0x023b8c47,0x0129d5f9,0x02972456,0x00a3a524,0x006f4cd2,0x004439fa},{0x00c53505,0x0190c2fd,0x00507244,0x009930f9,0x01a39270,0x01d327c6,0x0399bc47,0x01cfe13d,0x0332bd99,0x00b33e7d},{0x0203f5e4,0x003627b5,0x00018af8,0x01478581,0x004a2218,0x002e3bb7,0x039384d0,0x0146ea62,0x020b9693,0x0017155f}}, - {{0x03c97e6f,0x00738c47,0x03b5db1f,0x01808fcf,0x01e8fc98,0x01ed25dd,0x01bf5045,0x00eb5c2b,0x0178fe98,0x01b85530},{0x01c20eb0,0x01aeec22,0x030b9eee,0x01b7d07e,0x0187e16f,0x014421fb,0x009fa731,0x0040b6d7,0x00841861,0x00a27fbc},{0x02d69abf,0x0058cdbf,0x0129f9ec,0x013c19ae,0x026c5b93,0x013a7fe7,0x004bb2ba,0x0063226f,0x002a95ca,0x01abefd9}}, - {{0x02f5d2c1,0x00378318,0x03734fb5,0x01258073,0x0263f0f6,0x01ad70e0,0x01b56d06,0x01188fbd,0x011b9503,0x0036d2e1},{0x0113a8cc,0x01541c3e,0x02ac2bbc,0x01d95867,0x01f47459,0x00ead489,0x00ab5b48,0x01db3b45,0x00edb801,0x004b024f},{0x00b8190f,0x011fe4c2,0x00621f82,0x010508d7,0x001a5a76,0x00c7d7fd,0x03aab96d,0x019cd9dc,0x019c6635,0x00ceaa1e}}, - {{0x01085cf2,0x01fd47af,0x03e3f5e1,0x004b3e99,0x01e3d46a,0x0060033c,0x015ff0a8,0x0150cdd8,0x029e8e21,0x008cf1bc},{0x00156cb1,0x003d623f,0x01a4f069,0x00d8d053,0x01b68aea,0x01ca5ab6,0x0316ae43,0x0134dc44,0x001c8d58,0x0084b343},{0x0318c781,0x0135441f,0x03a51a5e,0x019293f4,0x0048bb37,0x013d3341,0x0143151e,0x019c74e1,0x00911914,0x0076ddde}}, - {{0x006bc26f,0x00d48e5f,0x00227bbe,0x00629ea8,0x01ea5f8b,0x0179a330,0x027a1d5f,0x01bf8f8e,0x02d26e2a,0x00c6b65e},{0x01701ab6,0x0051da77,0x01b4b667,0x00a0ce7c,0x038ae37b,0x012ac852,0x03a0b0fe,0x0097c2bb,0x00a017d2,0x01eb8b2a},{0x0120b962,0x0005fb42,0x0353b6fd,0x0061f8ce,0x007a1463,0x01560a64,0x00e0a792,0x01907c92,0x013a6622,0x007b47f1}} -}; +extern const ge25519_niels ALIGN(16) ge25519_niels_sliding_multiples[32]; diff --git a/ed25519-donna/ed25519-donna-basepoint-table.c b/ed25519-donna/ed25519-donna-basepoint-table.c index 7a05f8935..cd5d18728 100644 --- a/ed25519-donna/ed25519-donna-basepoint-table.c +++ b/ed25519-donna/ed25519-donna-basepoint-table.c @@ -1,5 +1,4 @@ -#include "ed25519-donna-portable.h" -#include "ed25519-donna-basepoint-table.h" +#include "ed25519-donna.h" /* multiples of the base point in packed {ysubx, xaddy, t2d} form */ const uint8_t ALIGN(16) ge25519_niels_base_multiples[256][96] = { diff --git a/ed25519-donna/ed25519-donna-impl-base.c b/ed25519-donna/ed25519-donna-impl-base.c new file mode 100644 index 000000000..28ac75819 --- /dev/null +++ b/ed25519-donna/ed25519-donna-impl-base.c @@ -0,0 +1,454 @@ +#include "ed25519-donna.h" + +/* + Timing safe memory compare +*/ +int ed25519_verify(const unsigned char *x, const unsigned char *y, size_t len) { + size_t differentbits = 0; + while (len--) + differentbits |= (*x++ ^ *y++); + return (int) (1 & ((differentbits - 1) >> 8)); +} + +/* + conversions +*/ + +void ge25519_p1p1_to_partial(ge25519 *r, const ge25519_p1p1 *p) { + curve25519_mul(r->x, p->x, p->t); + curve25519_mul(r->y, p->y, p->z); + curve25519_mul(r->z, p->z, p->t); +} + +void ge25519_p1p1_to_full(ge25519 *r, const ge25519_p1p1 *p) { + curve25519_mul(r->x, p->x, p->t); + curve25519_mul(r->y, p->y, p->z); + curve25519_mul(r->z, p->z, p->t); + curve25519_mul(r->t, p->x, p->y); +} + +void ge25519_full_to_pniels(ge25519_pniels *p, const ge25519 *r) { + curve25519_sub(p->ysubx, r->y, r->x); + curve25519_add(p->xaddy, r->y, r->x); + curve25519_copy(p->z, r->z); + curve25519_mul(p->t2d, r->t, ge25519_ec2d); +} + +/* + adding & doubling +*/ + +void ge25519_double_p1p1(ge25519_p1p1 *r, const ge25519 *p) { + bignum25519 a,b,c; + + curve25519_square(a, p->x); + curve25519_square(b, p->y); + curve25519_square(c, p->z); + curve25519_add_reduce(c, c, c); + curve25519_add(r->x, p->x, p->y); + curve25519_square(r->x, r->x); + curve25519_add(r->y, b, a); + curve25519_sub(r->z, b, a); + curve25519_sub_after_basic(r->x, r->x, r->y); + curve25519_sub_after_basic(r->t, c, r->z); +} + +#ifndef ED25519_NO_PRECOMP +void ge25519_nielsadd2_p1p1(ge25519_p1p1 *r, const ge25519 *p, const ge25519_niels *q, unsigned char signbit) { + const bignum25519 *qb = (const bignum25519 *)q; + bignum25519 *rb = (bignum25519 *)r; + bignum25519 a,b,c; + + curve25519_sub(a, p->y, p->x); + curve25519_add(b, p->y, p->x); + curve25519_mul(a, a, qb[signbit]); /* x for +, y for - */ + curve25519_mul(r->x, b, qb[signbit^1]); /* y for +, x for - */ + curve25519_add(r->y, r->x, a); + curve25519_sub(r->x, r->x, a); + curve25519_mul(c, p->t, q->t2d); + curve25519_add_reduce(r->t, p->z, p->z); + curve25519_copy(r->z, r->t); + curve25519_add(rb[2+signbit], rb[2+signbit], c); /* z for +, t for - */ + curve25519_sub(rb[2+(signbit^1)], rb[2+(signbit^1)], c); /* t for +, z for - */ +} +#endif + +void ge25519_pnielsadd_p1p1(ge25519_p1p1 *r, const ge25519 *p, const ge25519_pniels *q, unsigned char signbit) { + const bignum25519 *qb = (const bignum25519 *)q; + bignum25519 *rb = (bignum25519 *)r; + bignum25519 a,b,c; + + curve25519_sub(a, p->y, p->x); + curve25519_add(b, p->y, p->x); + curve25519_mul(a, a, qb[signbit]); /* ysubx for +, xaddy for - */ + curve25519_mul(r->x, b, qb[signbit^1]); /* xaddy for +, ysubx for - */ + curve25519_add(r->y, r->x, a); + curve25519_sub(r->x, r->x, a); + curve25519_mul(c, p->t, q->t2d); + curve25519_mul(r->t, p->z, q->z); + curve25519_add_reduce(r->t, r->t, r->t); + curve25519_copy(r->z, r->t); + curve25519_add(rb[2+signbit], rb[2+signbit], c); /* z for +, t for - */ + curve25519_sub(rb[2+(signbit^1)], rb[2+(signbit^1)], c); /* t for +, z for - */ +} + +void ge25519_double_partial(ge25519 *r, const ge25519 *p) { + ge25519_p1p1 t; + ge25519_double_p1p1(&t, p); + ge25519_p1p1_to_partial(r, &t); +} + +void ge25519_double(ge25519 *r, const ge25519 *p) { + ge25519_p1p1 t; + ge25519_double_p1p1(&t, p); + ge25519_p1p1_to_full(r, &t); +} + +void ge25519_nielsadd2(ge25519 *r, const ge25519_niels *q) { + bignum25519 a,b,c,e,f,g,h; + + curve25519_sub(a, r->y, r->x); + curve25519_add(b, r->y, r->x); + curve25519_mul(a, a, q->ysubx); + curve25519_mul(e, b, q->xaddy); + curve25519_add(h, e, a); + curve25519_sub(e, e, a); + curve25519_mul(c, r->t, q->t2d); + curve25519_add(f, r->z, r->z); + curve25519_add_after_basic(g, f, c); + curve25519_sub_after_basic(f, f, c); + curve25519_mul(r->x, e, f); + curve25519_mul(r->y, h, g); + curve25519_mul(r->z, g, f); + curve25519_mul(r->t, e, h); +} + +void ge25519_pnielsadd(ge25519_pniels *r, const ge25519 *p, const ge25519_pniels *q) { + bignum25519 a,b,c,x,y,z,t; + + curve25519_sub(a, p->y, p->x); + curve25519_add(b, p->y, p->x); + curve25519_mul(a, a, q->ysubx); + curve25519_mul(x, b, q->xaddy); + curve25519_add(y, x, a); + curve25519_sub(x, x, a); + curve25519_mul(c, p->t, q->t2d); + curve25519_mul(t, p->z, q->z); + curve25519_add(t, t, t); + curve25519_add_after_basic(z, t, c); + curve25519_sub_after_basic(t, t, c); + curve25519_mul(r->xaddy, x, t); + curve25519_mul(r->ysubx, y, z); + curve25519_mul(r->z, z, t); + curve25519_mul(r->t2d, x, y); + curve25519_copy(y, r->ysubx); + curve25519_sub(r->ysubx, r->ysubx, r->xaddy); + curve25519_add(r->xaddy, r->xaddy, y); + curve25519_mul(r->t2d, r->t2d, ge25519_ec2d); +} + + +/* + pack & unpack +*/ + +void ge25519_pack(unsigned char r[32], const ge25519 *p) { + bignum25519 tx, ty, zi; + unsigned char parity[32]; + curve25519_recip(zi, p->z); + curve25519_mul(tx, p->x, zi); + curve25519_mul(ty, p->y, zi); + curve25519_contract(r, ty); + curve25519_contract(parity, tx); + r[31] ^= ((parity[0] & 1) << 7); +} + +int ge25519_unpack_negative_vartime(ge25519 *r, const unsigned char p[32]) { + const unsigned char zero[32] = {0}; + const bignum25519 one = {1}; + unsigned char parity = p[31] >> 7; + unsigned char check[32]; + bignum25519 t, root, num, den, d3; + + curve25519_expand(r->y, p); + curve25519_copy(r->z, one); + curve25519_square(num, r->y); /* x = y^2 */ + curve25519_mul(den, num, ge25519_ecd); /* den = dy^2 */ + curve25519_sub_reduce(num, num, r->z); /* x = y^1 - 1 */ + curve25519_add(den, den, r->z); /* den = dy^2 + 1 */ + + /* Computation of sqrt(num/den) */ + /* 1.: computation of num^((p-5)/8)*den^((7p-35)/8) = (num*den^7)^((p-5)/8) */ + curve25519_square(t, den); + curve25519_mul(d3, t, den); + curve25519_square(r->x, d3); + curve25519_mul(r->x, r->x, den); + curve25519_mul(r->x, r->x, num); + curve25519_pow_two252m3(r->x, r->x); + + /* 2. computation of r->x = num * den^3 * (num*den^7)^((p-5)/8) */ + curve25519_mul(r->x, r->x, d3); + curve25519_mul(r->x, r->x, num); + + /* 3. Check if either of the roots works: */ + curve25519_square(t, r->x); + curve25519_mul(t, t, den); + curve25519_sub_reduce(root, t, num); + curve25519_contract(check, root); + if (!ed25519_verify(check, zero, 32)) { + curve25519_add_reduce(t, t, num); + curve25519_contract(check, t); + if (!ed25519_verify(check, zero, 32)) + return 0; + curve25519_mul(r->x, r->x, ge25519_sqrtneg1); + } + + curve25519_contract(check, r->x); + if ((check[0] & 1) == parity) { + curve25519_copy(t, r->x); + curve25519_neg(r->x, t); + } + curve25519_mul(r->t, r->x, r->y); + return 1; +} + +/* + scalarmults +*/ + +void ge25519_set_neutral(ge25519 *r) +{ + memset(r, 0, sizeof(ge25519)); + r->y[0] = 1; + r->z[0] = 1; +} + +#define S1_SWINDOWSIZE 5 +#define S1_TABLE_SIZE (1<<(S1_SWINDOWSIZE-2)) +#ifdef ED25519_NO_PRECOMP +#define S2_SWINDOWSIZE 5 +#else +#define S2_SWINDOWSIZE 7 +#endif +#define S2_TABLE_SIZE (1<<(S2_SWINDOWSIZE-2)) + +/* computes [s1]p1 + [s2]base */ +void ge25519_double_scalarmult_vartime(ge25519 *r, const ge25519 *p1, const bignum256modm s1, const bignum256modm s2) { + signed char slide1[256], slide2[256]; + ge25519_pniels pre1[S1_TABLE_SIZE]; +#ifdef ED25519_NO_PRECOMP + ge25519_pniels pre2[S2_TABLE_SIZE]; +#endif + ge25519 dp; + ge25519_p1p1 t; + int32_t i; + + contract256_slidingwindow_modm(slide1, s1, S1_SWINDOWSIZE); + contract256_slidingwindow_modm(slide2, s2, S2_SWINDOWSIZE); + + ge25519_double(&dp, p1); + ge25519_full_to_pniels(pre1, p1); + for (i = 0; i < S1_TABLE_SIZE - 1; i++) + ge25519_pnielsadd(&pre1[i+1], &dp, &pre1[i]); + +#ifdef ED25519_NO_PRECOMP + ge25519_double(&dp, &ge25519_basepoint); + ge25519_full_to_pniels(pre2, &ge25519_basepoint); + for (i = 0; i < S2_TABLE_SIZE - 1; i++) + ge25519_pnielsadd(&pre2[i+1], &dp, &pre2[i]); +#endif + + ge25519_set_neutral(r); + + i = 255; + while ((i >= 0) && !(slide1[i] | slide2[i])) + i--; + + for (; i >= 0; i--) { + ge25519_double_p1p1(&t, r); + + if (slide1[i]) { + ge25519_p1p1_to_full(r, &t); + ge25519_pnielsadd_p1p1(&t, r, &pre1[abs(slide1[i]) / 2], (unsigned char)slide1[i] >> 7); + } + + if (slide2[i]) { + ge25519_p1p1_to_full(r, &t); +#ifdef ED25519_NO_PRECOMP + ge25519_pnielsadd_p1p1(&t, r, &pre2[abs(slide2[i]) / 2], (unsigned char)slide2[i] >> 7); +#else + ge25519_nielsadd2_p1p1(&t, r, &ge25519_niels_sliding_multiples[abs(slide2[i]) / 2], (unsigned char)slide2[i] >> 7); +#endif + } + + ge25519_p1p1_to_partial(r, &t); + } +} + +/* + * The following conditional move stuff uses conditional moves. + * I will check on which compilers this works, and provide suitable + * workarounds for those where it doesn't. + * + * This works on gcc 4.x and above with -O3. Don't use -O2, this will + * cause the code to not generate conditional moves. Don't use any -march= + * with less than i686 on x86 + */ +static void ge25519_cmove_stride4(long * r, long * p, long * pos, long * n, int stride) { + long x0=r[0], x1=r[1], x2=r[2], x3=r[3], y0, y1, y2, y3; + for(; p= 0; i--) { + int k=abs(slide1[i]); + ge25519_double_partial(r, r); + ge25519_double_partial(r, r); + ge25519_double_partial(r, r); + ge25519_double_p1p1(&t, r); + ge25519_move_conditional_pniels_array(&pre, pre1, k, 9); + ge25519_p1p1_to_full(r, &t); + ge25519_pnielsadd_p1p1(&t, r, &pre, (unsigned char)slide1[i] >> 7); + ge25519_p1p1_to_partial(r, &t); + } +} + +void ge25519_scalarmult_base_choose_niels(ge25519_niels *t, const uint8_t table[256][96], uint32_t pos, signed char b) { + bignum25519 neg; + uint32_t sign = (uint32_t)((unsigned char)b >> 7); + uint32_t mask = ~(sign - 1); + uint32_t u = (b + mask) ^ mask; + + /* ysubx, xaddy, t2d in packed form. initialize to ysubx = 1, xaddy = 1, t2d = 0 */ + uint8_t packed[96] = {0}; + packed[0] = 1; + packed[32] = 1; + + ge25519_move_conditional_niels_array((ge25519_niels *)packed, &table[pos*8], u-1, 8); + + /* expand in to t */ + curve25519_expand(t->ysubx, packed + 0); + curve25519_expand(t->xaddy, packed + 32); + curve25519_expand(t->t2d , packed + 64); + + /* adjust for sign */ + curve25519_swap_conditional(t->ysubx, t->xaddy, sign); + curve25519_neg(neg, t->t2d); + curve25519_swap_conditional(t->t2d, neg, sign); +} + +/* computes [s]basepoint */ +void ge25519_scalarmult_base_niels(ge25519 *r, const uint8_t basepoint_table[256][96], const bignum256modm s) { + signed char b[64]; + uint32_t i; + ge25519_niels t; + + contract256_window4_modm(b, s); + + ge25519_scalarmult_base_choose_niels(&t, basepoint_table, 0, b[1]); + curve25519_sub_reduce(r->x, t.xaddy, t.ysubx); + curve25519_add_reduce(r->y, t.xaddy, t.ysubx); + memset(r->z, 0, sizeof(bignum25519)); + curve25519_copy(r->t, t.t2d); + r->z[0] = 2; + for (i = 3; i < 64; i += 2) { + ge25519_scalarmult_base_choose_niels(&t, basepoint_table, i / 2, b[i]); + ge25519_nielsadd2(r, &t); + } + ge25519_double_partial(r, r); + ge25519_double_partial(r, r); + ge25519_double_partial(r, r); + ge25519_double(r, r); + ge25519_scalarmult_base_choose_niels(&t, basepoint_table, 0, b[0]); + curve25519_mul(t.t2d, t.t2d, ge25519_ecd); + ge25519_nielsadd2(r, &t); + for(i = 2; i < 64; i += 2) { + ge25519_scalarmult_base_choose_niels(&t, basepoint_table, i / 2, b[i]); + ge25519_nielsadd2(r, &t); + } +} diff --git a/ed25519-donna/ed25519-donna-impl-base.h b/ed25519-donna/ed25519-donna-impl-base.h index e727acca8..559c837d7 100644 --- a/ed25519-donna/ed25519-donna-impl-base.h +++ b/ed25519-donna/ed25519-donna-impl-base.h @@ -1,455 +1,60 @@ +/* + Timing safe memory compare +*/ +int ed25519_verify(const unsigned char *x, const unsigned char *y, size_t len); + /* conversions */ -DONNA_INLINE static void -ge25519_p1p1_to_partial(ge25519 *r, const ge25519_p1p1 *p) { - curve25519_mul(r->x, p->x, p->t); - curve25519_mul(r->y, p->y, p->z); - curve25519_mul(r->z, p->z, p->t); -} +void ge25519_p1p1_to_partial(ge25519 *r, const ge25519_p1p1 *p); -DONNA_INLINE static void -ge25519_p1p1_to_full(ge25519 *r, const ge25519_p1p1 *p) { - curve25519_mul(r->x, p->x, p->t); - curve25519_mul(r->y, p->y, p->z); - curve25519_mul(r->z, p->z, p->t); - curve25519_mul(r->t, p->x, p->y); -} +void ge25519_p1p1_to_full(ge25519 *r, const ge25519_p1p1 *p); -static void -ge25519_full_to_pniels(ge25519_pniels *p, const ge25519 *r) { - curve25519_sub(p->ysubx, r->y, r->x); - curve25519_add(p->xaddy, r->y, r->x); - curve25519_copy(p->z, r->z); - curve25519_mul(p->t2d, r->t, ge25519_ec2d); -} +void ge25519_full_to_pniels(ge25519_pniels *p, const ge25519 *r); /* adding & doubling */ -static void -ge25519_double_p1p1(ge25519_p1p1 *r, const ge25519 *p) { - bignum25519 a,b,c; - - curve25519_square(a, p->x); - curve25519_square(b, p->y); - curve25519_square(c, p->z); - curve25519_add_reduce(c, c, c); - curve25519_add(r->x, p->x, p->y); - curve25519_square(r->x, r->x); - curve25519_add(r->y, b, a); - curve25519_sub(r->z, b, a); - curve25519_sub_after_basic(r->x, r->x, r->y); - curve25519_sub_after_basic(r->t, c, r->z); -} +void ge25519_double_p1p1(ge25519_p1p1 *r, const ge25519 *p); #ifndef ED25519_NO_PRECOMP -static void -ge25519_nielsadd2_p1p1(ge25519_p1p1 *r, const ge25519 *p, const ge25519_niels *q, unsigned char signbit) { - const bignum25519 *qb = (const bignum25519 *)q; - bignum25519 *rb = (bignum25519 *)r; - bignum25519 a,b,c; - - curve25519_sub(a, p->y, p->x); - curve25519_add(b, p->y, p->x); - curve25519_mul(a, a, qb[signbit]); /* x for +, y for - */ - curve25519_mul(r->x, b, qb[signbit^1]); /* y for +, x for - */ - curve25519_add(r->y, r->x, a); - curve25519_sub(r->x, r->x, a); - curve25519_mul(c, p->t, q->t2d); - curve25519_add_reduce(r->t, p->z, p->z); - curve25519_copy(r->z, r->t); - curve25519_add(rb[2+signbit], rb[2+signbit], c); /* z for +, t for - */ - curve25519_sub(rb[2+(signbit^1)], rb[2+(signbit^1)], c); /* t for +, z for - */ -} +void ge25519_nielsadd2_p1p1(ge25519_p1p1 *r, const ge25519 *p, const ge25519_niels *q, unsigned char signbit); #endif -static void -ge25519_pnielsadd_p1p1(ge25519_p1p1 *r, const ge25519 *p, const ge25519_pniels *q, unsigned char signbit) { - const bignum25519 *qb = (const bignum25519 *)q; - bignum25519 *rb = (bignum25519 *)r; - bignum25519 a,b,c; - - curve25519_sub(a, p->y, p->x); - curve25519_add(b, p->y, p->x); - curve25519_mul(a, a, qb[signbit]); /* ysubx for +, xaddy for - */ - curve25519_mul(r->x, b, qb[signbit^1]); /* xaddy for +, ysubx for - */ - curve25519_add(r->y, r->x, a); - curve25519_sub(r->x, r->x, a); - curve25519_mul(c, p->t, q->t2d); - curve25519_mul(r->t, p->z, q->z); - curve25519_add_reduce(r->t, r->t, r->t); - curve25519_copy(r->z, r->t); - curve25519_add(rb[2+signbit], rb[2+signbit], c); /* z for +, t for - */ - curve25519_sub(rb[2+(signbit^1)], rb[2+(signbit^1)], c); /* t for +, z for - */ -} +void ge25519_pnielsadd_p1p1(ge25519_p1p1 *r, const ge25519 *p, const ge25519_pniels *q, unsigned char signbit); -static void -ge25519_double_partial(ge25519 *r, const ge25519 *p) { - ge25519_p1p1 t; - ge25519_double_p1p1(&t, p); - ge25519_p1p1_to_partial(r, &t); -} +void ge25519_double_partial(ge25519 *r, const ge25519 *p); -static void -ge25519_double(ge25519 *r, const ge25519 *p) { - ge25519_p1p1 t; - ge25519_double_p1p1(&t, p); - ge25519_p1p1_to_full(r, &t); -} +void ge25519_double(ge25519 *r, const ge25519 *p); -static void -ge25519_nielsadd2(ge25519 *r, const ge25519_niels *q) { - bignum25519 a,b,c,e,f,g,h; +void ge25519_nielsadd2(ge25519 *r, const ge25519_niels *q); - curve25519_sub(a, r->y, r->x); - curve25519_add(b, r->y, r->x); - curve25519_mul(a, a, q->ysubx); - curve25519_mul(e, b, q->xaddy); - curve25519_add(h, e, a); - curve25519_sub(e, e, a); - curve25519_mul(c, r->t, q->t2d); - curve25519_add(f, r->z, r->z); - curve25519_add_after_basic(g, f, c); - curve25519_sub_after_basic(f, f, c); - curve25519_mul(r->x, e, f); - curve25519_mul(r->y, h, g); - curve25519_mul(r->z, g, f); - curve25519_mul(r->t, e, h); -} - -static void -ge25519_pnielsadd(ge25519_pniels *r, const ge25519 *p, const ge25519_pniels *q) { - bignum25519 a,b,c,x,y,z,t; - - curve25519_sub(a, p->y, p->x); - curve25519_add(b, p->y, p->x); - curve25519_mul(a, a, q->ysubx); - curve25519_mul(x, b, q->xaddy); - curve25519_add(y, x, a); - curve25519_sub(x, x, a); - curve25519_mul(c, p->t, q->t2d); - curve25519_mul(t, p->z, q->z); - curve25519_add(t, t, t); - curve25519_add_after_basic(z, t, c); - curve25519_sub_after_basic(t, t, c); - curve25519_mul(r->xaddy, x, t); - curve25519_mul(r->ysubx, y, z); - curve25519_mul(r->z, z, t); - curve25519_mul(r->t2d, x, y); - curve25519_copy(y, r->ysubx); - curve25519_sub(r->ysubx, r->ysubx, r->xaddy); - curve25519_add(r->xaddy, r->xaddy, y); - curve25519_mul(r->t2d, r->t2d, ge25519_ec2d); -} +void ge25519_pnielsadd(ge25519_pniels *r, const ge25519 *p, const ge25519_pniels *q); /* pack & unpack */ -static void -ge25519_pack(unsigned char r[32], const ge25519 *p) { - bignum25519 tx, ty, zi; - unsigned char parity[32]; - curve25519_recip(zi, p->z); - curve25519_mul(tx, p->x, zi); - curve25519_mul(ty, p->y, zi); - curve25519_contract(r, ty); - curve25519_contract(parity, tx); - r[31] ^= ((parity[0] & 1) << 7); -} - -static int ge25519_unpack_negative_vartime(ge25519 *r, const unsigned char p[32]) { - static const unsigned char zero[32] = {0}; - static const bignum25519 one = {1}; - unsigned char parity = p[31] >> 7; - unsigned char check[32]; - bignum25519 t, root, num, den, d3; - - curve25519_expand(r->y, p); - curve25519_copy(r->z, one); - curve25519_square(num, r->y); /* x = y^2 */ - curve25519_mul(den, num, ge25519_ecd); /* den = dy^2 */ - curve25519_sub_reduce(num, num, r->z); /* x = y^1 - 1 */ - curve25519_add(den, den, r->z); /* den = dy^2 + 1 */ - - /* Computation of sqrt(num/den) */ - /* 1.: computation of num^((p-5)/8)*den^((7p-35)/8) = (num*den^7)^((p-5)/8) */ - curve25519_square(t, den); - curve25519_mul(d3, t, den); - curve25519_square(r->x, d3); - curve25519_mul(r->x, r->x, den); - curve25519_mul(r->x, r->x, num); - curve25519_pow_two252m3(r->x, r->x); +void ge25519_pack(unsigned char r[32], const ge25519 *p); - /* 2. computation of r->x = num * den^3 * (num*den^7)^((p-5)/8) */ - curve25519_mul(r->x, r->x, d3); - curve25519_mul(r->x, r->x, num); - - /* 3. Check if either of the roots works: */ - curve25519_square(t, r->x); - curve25519_mul(t, t, den); - curve25519_sub_reduce(root, t, num); - curve25519_contract(check, root); - if (!ed25519_verify(check, zero, 32)) { - curve25519_add_reduce(t, t, num); - curve25519_contract(check, t); - if (!ed25519_verify(check, zero, 32)) - return 0; - curve25519_mul(r->x, r->x, ge25519_sqrtneg1); - } - - curve25519_contract(check, r->x); - if ((check[0] & 1) == parity) { - curve25519_copy(t, r->x); - curve25519_neg(r->x, t); - } - curve25519_mul(r->t, r->x, r->y); - return 1; -} +int ge25519_unpack_negative_vartime(ge25519 *r, const unsigned char p[32]); /* scalarmults */ -DONNA_INLINE static void ge25519_set_neutral(ge25519 *r) -{ - memset(r, 0, sizeof(ge25519)); - r->y[0] = 1; - r->z[0] = 1; -} - -#define S1_SWINDOWSIZE 5 -#define S1_TABLE_SIZE (1<<(S1_SWINDOWSIZE-2)) -#ifdef ED25519_NO_PRECOMP -#define S2_SWINDOWSIZE 5 -#else -#define S2_SWINDOWSIZE 7 -#endif -#define S2_TABLE_SIZE (1<<(S2_SWINDOWSIZE-2)) +void ge25519_set_neutral(ge25519 *r); /* computes [s1]p1 + [s2]base */ -static void ge25519_double_scalarmult_vartime(ge25519 *r, const ge25519 *p1, const bignum256modm s1, const bignum256modm s2) { - signed char slide1[256], slide2[256]; - ge25519_pniels pre1[S1_TABLE_SIZE]; -#ifdef ED25519_NO_PRECOMP - ge25519_pniels pre2[S2_TABLE_SIZE]; -#endif - ge25519 dp; - ge25519_p1p1 t; - int32_t i; - - contract256_slidingwindow_modm(slide1, s1, S1_SWINDOWSIZE); - contract256_slidingwindow_modm(slide2, s2, S2_SWINDOWSIZE); - - ge25519_double(&dp, p1); - ge25519_full_to_pniels(pre1, p1); - for (i = 0; i < S1_TABLE_SIZE - 1; i++) - ge25519_pnielsadd(&pre1[i+1], &dp, &pre1[i]); - -#ifdef ED25519_NO_PRECOMP - ge25519_double(&dp, &ge25519_basepoint); - ge25519_full_to_pniels(pre2, &ge25519_basepoint); - for (i = 0; i < S2_TABLE_SIZE - 1; i++) - ge25519_pnielsadd(&pre2[i+1], &dp, &pre2[i]); -#endif - - ge25519_set_neutral(r); - - i = 255; - while ((i >= 0) && !(slide1[i] | slide2[i])) - i--; - - for (; i >= 0; i--) { - ge25519_double_p1p1(&t, r); - - if (slide1[i]) { - ge25519_p1p1_to_full(r, &t); - ge25519_pnielsadd_p1p1(&t, r, &pre1[abs(slide1[i]) / 2], (unsigned char)slide1[i] >> 7); - } - - if (slide2[i]) { - ge25519_p1p1_to_full(r, &t); -#ifdef ED25519_NO_PRECOMP - ge25519_pnielsadd_p1p1(&t, r, &pre2[abs(slide2[i]) / 2], (unsigned char)slide2[i] >> 7); -#else - ge25519_nielsadd2_p1p1(&t, r, &ge25519_niels_sliding_multiples[abs(slide2[i]) / 2], (unsigned char)slide2[i] >> 7); -#endif - } - - ge25519_p1p1_to_partial(r, &t); - } -} - -/* - * The following conditional move stuff uses conditional moves. - * I will check on which compilers this works, and provide suitable - * workarounds for those where it doesn't. - * - * This works on gcc 4.x and above with -O3. Don't use -O2, this will - * cause the code to not generate conditional moves. Don't use any -march= - * with less than i686 on x86 - */ -DONNA_INLINE static void ge25519_cmove_stride4(long * r, long * p, long * pos, long * n, int stride) { - long x0=r[0], x1=r[1], x2=r[2], x3=r[3], y0, y1, y2, y3; - for(; p= 0; i--) { - int k=abs(slide1[i]); - ge25519_double_partial(r, r); - ge25519_double_partial(r, r); - ge25519_double_partial(r, r); - ge25519_double_p1p1(&t, r); - ge25519_move_conditional_pniels_array(&pre, pre1, k, 9); - ge25519_p1p1_to_full(r, &t); - ge25519_pnielsadd_p1p1(&t, r, &pre, (unsigned char)slide1[i] >> 7); - ge25519_p1p1_to_partial(r, &t); - } -} - -static void -ge25519_scalarmult_base_choose_niels(ge25519_niels *t, const uint8_t table[256][96], uint32_t pos, signed char b) { - bignum25519 neg; - uint32_t sign = (uint32_t)((unsigned char)b >> 7); - uint32_t mask = ~(sign - 1); - uint32_t u = (b + mask) ^ mask; - - /* ysubx, xaddy, t2d in packed form. initialize to ysubx = 1, xaddy = 1, t2d = 0 */ - uint8_t packed[96] = {0}; - packed[0] = 1; - packed[32] = 1; - - ge25519_move_conditional_niels_array((ge25519_niels *)packed, &table[pos*8], u-1, 8); - - /* expand in to t */ - curve25519_expand(t->ysubx, packed + 0); - curve25519_expand(t->xaddy, packed + 32); - curve25519_expand(t->t2d , packed + 64); - - /* adjust for sign */ - curve25519_swap_conditional(t->ysubx, t->xaddy, sign); - curve25519_neg(neg, t->t2d); - curve25519_swap_conditional(t->t2d, neg, sign); -} +void ge25519_scalarmult_base_choose_niels(ge25519_niels *t, const uint8_t table[256][96], uint32_t pos, signed char b); /* computes [s]basepoint */ -static void -ge25519_scalarmult_base_niels(ge25519 *r, const uint8_t basepoint_table[256][96], const bignum256modm s) { - signed char b[64]; - uint32_t i; - ge25519_niels t; - - contract256_window4_modm(b, s); - - ge25519_scalarmult_base_choose_niels(&t, basepoint_table, 0, b[1]); - curve25519_sub_reduce(r->x, t.xaddy, t.ysubx); - curve25519_add_reduce(r->y, t.xaddy, t.ysubx); - memset(r->z, 0, sizeof(bignum25519)); - curve25519_copy(r->t, t.t2d); - r->z[0] = 2; - for (i = 3; i < 64; i += 2) { - ge25519_scalarmult_base_choose_niels(&t, basepoint_table, i / 2, b[i]); - ge25519_nielsadd2(r, &t); - } - ge25519_double_partial(r, r); - ge25519_double_partial(r, r); - ge25519_double_partial(r, r); - ge25519_double(r, r); - ge25519_scalarmult_base_choose_niels(&t, basepoint_table, 0, b[0]); - curve25519_mul(t.t2d, t.t2d, ge25519_ecd); - ge25519_nielsadd2(r, &t); - for(i = 2; i < 64; i += 2) { - ge25519_scalarmult_base_choose_niels(&t, basepoint_table, i / 2, b[i]); - ge25519_nielsadd2(r, &t); - } -} +void ge25519_scalarmult_base_niels(ge25519 *r, const uint8_t basepoint_table[256][96], const bignum256modm s); diff --git a/ed25519-donna/ed25519-donna-portable.h b/ed25519-donna/ed25519-donna-portable.h index 70c950488..2fa0ac56e 100644 --- a/ed25519-donna/ed25519-donna-portable.h +++ b/ed25519-donna/ed25519-donna-portable.h @@ -4,12 +4,6 @@ #include #include -#ifdef __GNUC__ -#define DONNA_UNUSED __attribute__((unused)) -#else -#define DONNA_UNUSED -#endif - #define DONNA_INLINE #undef ALIGN #define ALIGN(x) __attribute__((aligned(x))) diff --git a/ed25519-donna/ed25519-donna.h b/ed25519-donna/ed25519-donna.h index f72cb7e66..1cf3186e2 100644 --- a/ed25519-donna/ed25519-donna.h +++ b/ed25519-donna/ed25519-donna.h @@ -18,17 +18,6 @@ typedef unsigned char hash_512bits[64]; -/* - Timing safe memory compare -*/ -static int -ed25519_verify(const unsigned char *x, const unsigned char *y, size_t len) { - size_t differentbits = 0; - while (len--) - differentbits |= (*x++ ^ *y++); - return (int) (1 & ((differentbits - 1) >> 8)); -} - /* * Arithmetic on the twisted Edwards curve -x^2 + y^2 = 1 + dx^2y^2 * with d = -(121665/121666) = 37095705934669439343138083508754565189542113879843219016388785533085940283555 diff --git a/ed25519-donna/modm-donna-32bit.c b/ed25519-donna/modm-donna-32bit.c new file mode 100644 index 000000000..9ed296cf3 --- /dev/null +++ b/ed25519-donna/modm-donna-32bit.c @@ -0,0 +1,358 @@ +/* + Public domain by Andrew M. +*/ + +#include "ed25519-donna.h" + +/* + Arithmetic modulo the group order n = 2^252 + 27742317777372353535851937790883648493 = 7237005577332262213973186563042994240857116359379907606001950938285454250989 + + k = 32 + b = 1 << 8 = 256 + m = 2^252 + 27742317777372353535851937790883648493 = 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed + mu = floor( b^(k*2) / m ) = 0xfffffffffffffffffffffffffffffffeb2106215d086329a7ed9ce5a30a2c131b +*/ + +static const bignum256modm modm_m = { + 0x1cf5d3ed, 0x20498c69, 0x2f79cd65, 0x37be77a8, + 0x00000014, 0x00000000, 0x00000000, 0x00000000, + 0x00001000 +}; + +static const bignum256modm modm_mu = { + 0x0a2c131b, 0x3673968c, 0x06329a7e, 0x01885742, + 0x3fffeb21, 0x3fffffff, 0x3fffffff, 0x3fffffff, + 0x000fffff +}; + +static bignum256modm_element_t +lt_modm(bignum256modm_element_t a, bignum256modm_element_t b) { + return (a - b) >> 31; +} + +/* see HAC, Alg. 14.42 Step 4 */ +void reduce256_modm(bignum256modm r) { + bignum256modm t; + bignum256modm_element_t b = 0, pb, mask; + + /* t = r - m */ + pb = 0; + pb += modm_m[0]; b = lt_modm(r[0], pb); t[0] = (r[0] - pb + (b << 30)); pb = b; + pb += modm_m[1]; b = lt_modm(r[1], pb); t[1] = (r[1] - pb + (b << 30)); pb = b; + pb += modm_m[2]; b = lt_modm(r[2], pb); t[2] = (r[2] - pb + (b << 30)); pb = b; + pb += modm_m[3]; b = lt_modm(r[3], pb); t[3] = (r[3] - pb + (b << 30)); pb = b; + pb += modm_m[4]; b = lt_modm(r[4], pb); t[4] = (r[4] - pb + (b << 30)); pb = b; + pb += modm_m[5]; b = lt_modm(r[5], pb); t[5] = (r[5] - pb + (b << 30)); pb = b; + pb += modm_m[6]; b = lt_modm(r[6], pb); t[6] = (r[6] - pb + (b << 30)); pb = b; + pb += modm_m[7]; b = lt_modm(r[7], pb); t[7] = (r[7] - pb + (b << 30)); pb = b; + pb += modm_m[8]; b = lt_modm(r[8], pb); t[8] = (r[8] - pb + (b << 16)); + + /* keep r if r was smaller than m */ + mask = b - 1; + r[0] ^= mask & (r[0] ^ t[0]); + r[1] ^= mask & (r[1] ^ t[1]); + r[2] ^= mask & (r[2] ^ t[2]); + r[3] ^= mask & (r[3] ^ t[3]); + r[4] ^= mask & (r[4] ^ t[4]); + r[5] ^= mask & (r[5] ^ t[5]); + r[6] ^= mask & (r[6] ^ t[6]); + r[7] ^= mask & (r[7] ^ t[7]); + r[8] ^= mask & (r[8] ^ t[8]); +} + +/* + Barrett reduction, see HAC, Alg. 14.42 + + Instead of passing in x, pre-process in to q1 and r1 for efficiency +*/ +void barrett_reduce256_modm(bignum256modm r, const bignum256modm q1, const bignum256modm r1) { + bignum256modm q3, r2; + uint64_t c; + bignum256modm_element_t f, b, pb; + + /* q1 = x >> 248 = 264 bits = 9 30 bit elements + q2 = mu * q1 + q3 = (q2 / 256(32+1)) = q2 / (2^8)^(32+1) = q2 >> 264 */ + c = mul32x32_64(modm_mu[0], q1[7]) + mul32x32_64(modm_mu[1], q1[6]) + mul32x32_64(modm_mu[2], q1[5]) + mul32x32_64(modm_mu[3], q1[4]) + mul32x32_64(modm_mu[4], q1[3]) + mul32x32_64(modm_mu[5], q1[2]) + mul32x32_64(modm_mu[6], q1[1]) + mul32x32_64(modm_mu[7], q1[0]); + c >>= 30; + c += mul32x32_64(modm_mu[0], q1[8]) + mul32x32_64(modm_mu[1], q1[7]) + mul32x32_64(modm_mu[2], q1[6]) + mul32x32_64(modm_mu[3], q1[5]) + mul32x32_64(modm_mu[4], q1[4]) + mul32x32_64(modm_mu[5], q1[3]) + mul32x32_64(modm_mu[6], q1[2]) + mul32x32_64(modm_mu[7], q1[1]) + mul32x32_64(modm_mu[8], q1[0]); + f = (bignum256modm_element_t)c; q3[0] = (f >> 24) & 0x3f; c >>= 30; + c += mul32x32_64(modm_mu[1], q1[8]) + mul32x32_64(modm_mu[2], q1[7]) + mul32x32_64(modm_mu[3], q1[6]) + mul32x32_64(modm_mu[4], q1[5]) + mul32x32_64(modm_mu[5], q1[4]) + mul32x32_64(modm_mu[6], q1[3]) + mul32x32_64(modm_mu[7], q1[2]) + mul32x32_64(modm_mu[8], q1[1]); + f = (bignum256modm_element_t)c; q3[0] |= (f << 6) & 0x3fffffff; q3[1] = (f >> 24) & 0x3f; c >>= 30; + c += mul32x32_64(modm_mu[2], q1[8]) + mul32x32_64(modm_mu[3], q1[7]) + mul32x32_64(modm_mu[4], q1[6]) + mul32x32_64(modm_mu[5], q1[5]) + mul32x32_64(modm_mu[6], q1[4]) + mul32x32_64(modm_mu[7], q1[3]) + mul32x32_64(modm_mu[8], q1[2]); + f = (bignum256modm_element_t)c; q3[1] |= (f << 6) & 0x3fffffff; q3[2] = (f >> 24) & 0x3f; c >>= 30; + c += mul32x32_64(modm_mu[3], q1[8]) + mul32x32_64(modm_mu[4], q1[7]) + mul32x32_64(modm_mu[5], q1[6]) + mul32x32_64(modm_mu[6], q1[5]) + mul32x32_64(modm_mu[7], q1[4]) + mul32x32_64(modm_mu[8], q1[3]); + f = (bignum256modm_element_t)c; q3[2] |= (f << 6) & 0x3fffffff; q3[3] = (f >> 24) & 0x3f; c >>= 30; + c += mul32x32_64(modm_mu[4], q1[8]) + mul32x32_64(modm_mu[5], q1[7]) + mul32x32_64(modm_mu[6], q1[6]) + mul32x32_64(modm_mu[7], q1[5]) + mul32x32_64(modm_mu[8], q1[4]); + f = (bignum256modm_element_t)c; q3[3] |= (f << 6) & 0x3fffffff; q3[4] = (f >> 24) & 0x3f; c >>= 30; + c += mul32x32_64(modm_mu[5], q1[8]) + mul32x32_64(modm_mu[6], q1[7]) + mul32x32_64(modm_mu[7], q1[6]) + mul32x32_64(modm_mu[8], q1[5]); + f = (bignum256modm_element_t)c; q3[4] |= (f << 6) & 0x3fffffff; q3[5] = (f >> 24) & 0x3f; c >>= 30; + c += mul32x32_64(modm_mu[6], q1[8]) + mul32x32_64(modm_mu[7], q1[7]) + mul32x32_64(modm_mu[8], q1[6]); + f = (bignum256modm_element_t)c; q3[5] |= (f << 6) & 0x3fffffff; q3[6] = (f >> 24) & 0x3f; c >>= 30; + c += mul32x32_64(modm_mu[7], q1[8]) + mul32x32_64(modm_mu[8], q1[7]); + f = (bignum256modm_element_t)c; q3[6] |= (f << 6) & 0x3fffffff; q3[7] = (f >> 24) & 0x3f; c >>= 30; + c += mul32x32_64(modm_mu[8], q1[8]); + f = (bignum256modm_element_t)c; q3[7] |= (f << 6) & 0x3fffffff; q3[8] = (bignum256modm_element_t)(c >> 24); + + /* r1 = (x mod 256^(32+1)) = x mod (2^8)(31+1) = x & ((1 << 264) - 1) + r2 = (q3 * m) mod (256^(32+1)) = (q3 * m) & ((1 << 264) - 1) */ + c = mul32x32_64(modm_m[0], q3[0]); + r2[0] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30; + c += mul32x32_64(modm_m[0], q3[1]) + mul32x32_64(modm_m[1], q3[0]); + r2[1] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30; + c += mul32x32_64(modm_m[0], q3[2]) + mul32x32_64(modm_m[1], q3[1]) + mul32x32_64(modm_m[2], q3[0]); + r2[2] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30; + c += mul32x32_64(modm_m[0], q3[3]) + mul32x32_64(modm_m[1], q3[2]) + mul32x32_64(modm_m[2], q3[1]) + mul32x32_64(modm_m[3], q3[0]); + r2[3] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30; + c += mul32x32_64(modm_m[0], q3[4]) + mul32x32_64(modm_m[1], q3[3]) + mul32x32_64(modm_m[2], q3[2]) + mul32x32_64(modm_m[3], q3[1]) + mul32x32_64(modm_m[4], q3[0]); + r2[4] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30; + c += mul32x32_64(modm_m[0], q3[5]) + mul32x32_64(modm_m[1], q3[4]) + mul32x32_64(modm_m[2], q3[3]) + mul32x32_64(modm_m[3], q3[2]) + mul32x32_64(modm_m[4], q3[1]) + mul32x32_64(modm_m[5], q3[0]); + r2[5] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30; + c += mul32x32_64(modm_m[0], q3[6]) + mul32x32_64(modm_m[1], q3[5]) + mul32x32_64(modm_m[2], q3[4]) + mul32x32_64(modm_m[3], q3[3]) + mul32x32_64(modm_m[4], q3[2]) + mul32x32_64(modm_m[5], q3[1]) + mul32x32_64(modm_m[6], q3[0]); + r2[6] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30; + c += mul32x32_64(modm_m[0], q3[7]) + mul32x32_64(modm_m[1], q3[6]) + mul32x32_64(modm_m[2], q3[5]) + mul32x32_64(modm_m[3], q3[4]) + mul32x32_64(modm_m[4], q3[3]) + mul32x32_64(modm_m[5], q3[2]) + mul32x32_64(modm_m[6], q3[1]) + mul32x32_64(modm_m[7], q3[0]); + r2[7] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30; + c += mul32x32_64(modm_m[0], q3[8]) + mul32x32_64(modm_m[1], q3[7]) + mul32x32_64(modm_m[2], q3[6]) + mul32x32_64(modm_m[3], q3[5]) + mul32x32_64(modm_m[4], q3[4]) + mul32x32_64(modm_m[5], q3[3]) + mul32x32_64(modm_m[6], q3[2]) + mul32x32_64(modm_m[7], q3[1]) + mul32x32_64(modm_m[8], q3[0]); + r2[8] = (bignum256modm_element_t)(c & 0xffffff); + + /* r = r1 - r2 + if (r < 0) r += (1 << 264) */ + pb = 0; + pb += r2[0]; b = lt_modm(r1[0], pb); r[0] = (r1[0] - pb + (b << 30)); pb = b; + pb += r2[1]; b = lt_modm(r1[1], pb); r[1] = (r1[1] - pb + (b << 30)); pb = b; + pb += r2[2]; b = lt_modm(r1[2], pb); r[2] = (r1[2] - pb + (b << 30)); pb = b; + pb += r2[3]; b = lt_modm(r1[3], pb); r[3] = (r1[3] - pb + (b << 30)); pb = b; + pb += r2[4]; b = lt_modm(r1[4], pb); r[4] = (r1[4] - pb + (b << 30)); pb = b; + pb += r2[5]; b = lt_modm(r1[5], pb); r[5] = (r1[5] - pb + (b << 30)); pb = b; + pb += r2[6]; b = lt_modm(r1[6], pb); r[6] = (r1[6] - pb + (b << 30)); pb = b; + pb += r2[7]; b = lt_modm(r1[7], pb); r[7] = (r1[7] - pb + (b << 30)); pb = b; + pb += r2[8]; b = lt_modm(r1[8], pb); r[8] = (r1[8] - pb + (b << 24)); + + reduce256_modm(r); + reduce256_modm(r); +} + +/* addition modulo m */ +void add256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y) { + bignum256modm_element_t c; + + c = x[0] + y[0]; r[0] = c & 0x3fffffff; c >>= 30; + c += x[1] + y[1]; r[1] = c & 0x3fffffff; c >>= 30; + c += x[2] + y[2]; r[2] = c & 0x3fffffff; c >>= 30; + c += x[3] + y[3]; r[3] = c & 0x3fffffff; c >>= 30; + c += x[4] + y[4]; r[4] = c & 0x3fffffff; c >>= 30; + c += x[5] + y[5]; r[5] = c & 0x3fffffff; c >>= 30; + c += x[6] + y[6]; r[6] = c & 0x3fffffff; c >>= 30; + c += x[7] + y[7]; r[7] = c & 0x3fffffff; c >>= 30; + c += x[8] + y[8]; r[8] = c; + + reduce256_modm(r); +} + +/* multiplication modulo m */ +void mul256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y) { + bignum256modm r1, q1; + uint64_t c; + bignum256modm_element_t f; + + /* r1 = (x mod 256^(32+1)) = x mod (2^8)(31+1) = x & ((1 << 264) - 1) + q1 = x >> 248 = 264 bits = 9 30 bit elements */ + c = mul32x32_64(x[0], y[0]); + f = (bignum256modm_element_t)c; r1[0] = (f & 0x3fffffff); c >>= 30; + c += mul32x32_64(x[0], y[1]) + mul32x32_64(x[1], y[0]); + f = (bignum256modm_element_t)c; r1[1] = (f & 0x3fffffff); c >>= 30; + c += mul32x32_64(x[0], y[2]) + mul32x32_64(x[1], y[1]) + mul32x32_64(x[2], y[0]); + f = (bignum256modm_element_t)c; r1[2] = (f & 0x3fffffff); c >>= 30; + c += mul32x32_64(x[0], y[3]) + mul32x32_64(x[1], y[2]) + mul32x32_64(x[2], y[1]) + mul32x32_64(x[3], y[0]); + f = (bignum256modm_element_t)c; r1[3] = (f & 0x3fffffff); c >>= 30; + c += mul32x32_64(x[0], y[4]) + mul32x32_64(x[1], y[3]) + mul32x32_64(x[2], y[2]) + mul32x32_64(x[3], y[1]) + mul32x32_64(x[4], y[0]); + f = (bignum256modm_element_t)c; r1[4] = (f & 0x3fffffff); c >>= 30; + c += mul32x32_64(x[0], y[5]) + mul32x32_64(x[1], y[4]) + mul32x32_64(x[2], y[3]) + mul32x32_64(x[3], y[2]) + mul32x32_64(x[4], y[1]) + mul32x32_64(x[5], y[0]); + f = (bignum256modm_element_t)c; r1[5] = (f & 0x3fffffff); c >>= 30; + c += mul32x32_64(x[0], y[6]) + mul32x32_64(x[1], y[5]) + mul32x32_64(x[2], y[4]) + mul32x32_64(x[3], y[3]) + mul32x32_64(x[4], y[2]) + mul32x32_64(x[5], y[1]) + mul32x32_64(x[6], y[0]); + f = (bignum256modm_element_t)c; r1[6] = (f & 0x3fffffff); c >>= 30; + c += mul32x32_64(x[0], y[7]) + mul32x32_64(x[1], y[6]) + mul32x32_64(x[2], y[5]) + mul32x32_64(x[3], y[4]) + mul32x32_64(x[4], y[3]) + mul32x32_64(x[5], y[2]) + mul32x32_64(x[6], y[1]) + mul32x32_64(x[7], y[0]); + f = (bignum256modm_element_t)c; r1[7] = (f & 0x3fffffff); c >>= 30; + c += mul32x32_64(x[0], y[8]) + mul32x32_64(x[1], y[7]) + mul32x32_64(x[2], y[6]) + mul32x32_64(x[3], y[5]) + mul32x32_64(x[4], y[4]) + mul32x32_64(x[5], y[3]) + mul32x32_64(x[6], y[2]) + mul32x32_64(x[7], y[1]) + mul32x32_64(x[8], y[0]); + f = (bignum256modm_element_t)c; r1[8] = (f & 0x00ffffff); q1[0] = (f >> 8) & 0x3fffff; c >>= 30; + c += mul32x32_64(x[1], y[8]) + mul32x32_64(x[2], y[7]) + mul32x32_64(x[3], y[6]) + mul32x32_64(x[4], y[5]) + mul32x32_64(x[5], y[4]) + mul32x32_64(x[6], y[3]) + mul32x32_64(x[7], y[2]) + mul32x32_64(x[8], y[1]); + f = (bignum256modm_element_t)c; q1[0] = (q1[0] | (f << 22)) & 0x3fffffff; q1[1] = (f >> 8) & 0x3fffff; c >>= 30; + c += mul32x32_64(x[2], y[8]) + mul32x32_64(x[3], y[7]) + mul32x32_64(x[4], y[6]) + mul32x32_64(x[5], y[5]) + mul32x32_64(x[6], y[4]) + mul32x32_64(x[7], y[3]) + mul32x32_64(x[8], y[2]); + f = (bignum256modm_element_t)c; q1[1] = (q1[1] | (f << 22)) & 0x3fffffff; q1[2] = (f >> 8) & 0x3fffff; c >>= 30; + c += mul32x32_64(x[3], y[8]) + mul32x32_64(x[4], y[7]) + mul32x32_64(x[5], y[6]) + mul32x32_64(x[6], y[5]) + mul32x32_64(x[7], y[4]) + mul32x32_64(x[8], y[3]); + f = (bignum256modm_element_t)c; q1[2] = (q1[2] | (f << 22)) & 0x3fffffff; q1[3] = (f >> 8) & 0x3fffff; c >>= 30; + c += mul32x32_64(x[4], y[8]) + mul32x32_64(x[5], y[7]) + mul32x32_64(x[6], y[6]) + mul32x32_64(x[7], y[5]) + mul32x32_64(x[8], y[4]); + f = (bignum256modm_element_t)c; q1[3] = (q1[3] | (f << 22)) & 0x3fffffff; q1[4] = (f >> 8) & 0x3fffff; c >>= 30; + c += mul32x32_64(x[5], y[8]) + mul32x32_64(x[6], y[7]) + mul32x32_64(x[7], y[6]) + mul32x32_64(x[8], y[5]); + f = (bignum256modm_element_t)c; q1[4] = (q1[4] | (f << 22)) & 0x3fffffff; q1[5] = (f >> 8) & 0x3fffff; c >>= 30; + c += mul32x32_64(x[6], y[8]) + mul32x32_64(x[7], y[7]) + mul32x32_64(x[8], y[6]); + f = (bignum256modm_element_t)c; q1[5] = (q1[5] | (f << 22)) & 0x3fffffff; q1[6] = (f >> 8) & 0x3fffff; c >>= 30; + c += mul32x32_64(x[7], y[8]) + mul32x32_64(x[8], y[7]); + f = (bignum256modm_element_t)c; q1[6] = (q1[6] | (f << 22)) & 0x3fffffff; q1[7] = (f >> 8) & 0x3fffff; c >>= 30; + c += mul32x32_64(x[8], y[8]); + f = (bignum256modm_element_t)c; q1[7] = (q1[7] | (f << 22)) & 0x3fffffff; q1[8] = (f >> 8) & 0x3fffff; + + barrett_reduce256_modm(r, q1, r1); +} + +void expand256_modm(bignum256modm out, const unsigned char *in, size_t len) { + unsigned char work[64] = {0}; + bignum256modm_element_t x[16]; + bignum256modm q1; + + memcpy(work, in, len); + x[0] = U8TO32_LE(work + 0); + x[1] = U8TO32_LE(work + 4); + x[2] = U8TO32_LE(work + 8); + x[3] = U8TO32_LE(work + 12); + x[4] = U8TO32_LE(work + 16); + x[5] = U8TO32_LE(work + 20); + x[6] = U8TO32_LE(work + 24); + x[7] = U8TO32_LE(work + 28); + x[8] = U8TO32_LE(work + 32); + x[9] = U8TO32_LE(work + 36); + x[10] = U8TO32_LE(work + 40); + x[11] = U8TO32_LE(work + 44); + x[12] = U8TO32_LE(work + 48); + x[13] = U8TO32_LE(work + 52); + x[14] = U8TO32_LE(work + 56); + x[15] = U8TO32_LE(work + 60); + + /* r1 = (x mod 256^(32+1)) = x mod (2^8)(31+1) = x & ((1 << 264) - 1) */ + out[0] = ( x[0]) & 0x3fffffff; + out[1] = ((x[ 0] >> 30) | (x[ 1] << 2)) & 0x3fffffff; + out[2] = ((x[ 1] >> 28) | (x[ 2] << 4)) & 0x3fffffff; + out[3] = ((x[ 2] >> 26) | (x[ 3] << 6)) & 0x3fffffff; + out[4] = ((x[ 3] >> 24) | (x[ 4] << 8)) & 0x3fffffff; + out[5] = ((x[ 4] >> 22) | (x[ 5] << 10)) & 0x3fffffff; + out[6] = ((x[ 5] >> 20) | (x[ 6] << 12)) & 0x3fffffff; + out[7] = ((x[ 6] >> 18) | (x[ 7] << 14)) & 0x3fffffff; + out[8] = ((x[ 7] >> 16) | (x[ 8] << 16)) & 0x00ffffff; + + /* 8*31 = 248 bits, no need to reduce */ + if (len < 32) + return; + + /* q1 = x >> 248 = 264 bits = 9 30 bit elements */ + q1[0] = ((x[ 7] >> 24) | (x[ 8] << 8)) & 0x3fffffff; + q1[1] = ((x[ 8] >> 22) | (x[ 9] << 10)) & 0x3fffffff; + q1[2] = ((x[ 9] >> 20) | (x[10] << 12)) & 0x3fffffff; + q1[3] = ((x[10] >> 18) | (x[11] << 14)) & 0x3fffffff; + q1[4] = ((x[11] >> 16) | (x[12] << 16)) & 0x3fffffff; + q1[5] = ((x[12] >> 14) | (x[13] << 18)) & 0x3fffffff; + q1[6] = ((x[13] >> 12) | (x[14] << 20)) & 0x3fffffff; + q1[7] = ((x[14] >> 10) | (x[15] << 22)) & 0x3fffffff; + q1[8] = ((x[15] >> 8) ); + + barrett_reduce256_modm(out, q1, out); +} + +void expand_raw256_modm(bignum256modm out, const unsigned char in[32]) { + bignum256modm_element_t x[8]; + + x[0] = U8TO32_LE(in + 0); + x[1] = U8TO32_LE(in + 4); + x[2] = U8TO32_LE(in + 8); + x[3] = U8TO32_LE(in + 12); + x[4] = U8TO32_LE(in + 16); + x[5] = U8TO32_LE(in + 20); + x[6] = U8TO32_LE(in + 24); + x[7] = U8TO32_LE(in + 28); + + out[0] = ( x[0]) & 0x3fffffff; + out[1] = ((x[ 0] >> 30) | (x[ 1] << 2)) & 0x3fffffff; + out[2] = ((x[ 1] >> 28) | (x[ 2] << 4)) & 0x3fffffff; + out[3] = ((x[ 2] >> 26) | (x[ 3] << 6)) & 0x3fffffff; + out[4] = ((x[ 3] >> 24) | (x[ 4] << 8)) & 0x3fffffff; + out[5] = ((x[ 4] >> 22) | (x[ 5] << 10)) & 0x3fffffff; + out[6] = ((x[ 5] >> 20) | (x[ 6] << 12)) & 0x3fffffff; + out[7] = ((x[ 6] >> 18) | (x[ 7] << 14)) & 0x3fffffff; + out[8] = ((x[ 7] >> 16) ) & 0x0000ffff; +} + +void contract256_modm(unsigned char out[32], const bignum256modm in) { + U32TO8_LE(out + 0, (in[0] ) | (in[1] << 30)); + U32TO8_LE(out + 4, (in[1] >> 2) | (in[2] << 28)); + U32TO8_LE(out + 8, (in[2] >> 4) | (in[3] << 26)); + U32TO8_LE(out + 12, (in[3] >> 6) | (in[4] << 24)); + U32TO8_LE(out + 16, (in[4] >> 8) | (in[5] << 22)); + U32TO8_LE(out + 20, (in[5] >> 10) | (in[6] << 20)); + U32TO8_LE(out + 24, (in[6] >> 12) | (in[7] << 18)); + U32TO8_LE(out + 28, (in[7] >> 14) | (in[8] << 16)); +} + +void contract256_window4_modm(signed char r[64], const bignum256modm in) { + char carry; + signed char *quads = r; + bignum256modm_element_t i, j, v; + + for (i = 0; i < 8; i += 2) { + v = in[i]; + for (j = 0; j < 7; j++) { + *quads++ = (v & 15); + v >>= 4; + } + v |= (in[i+1] << 2); + for (j = 0; j < 8; j++) { + *quads++ = (v & 15); + v >>= 4; + } + } + v = in[8]; + *quads++ = (v & 15); v >>= 4; + *quads++ = (v & 15); v >>= 4; + *quads++ = (v & 15); v >>= 4; + *quads++ = (v & 15); v >>= 4; + + /* making it signed */ + carry = 0; + for(i = 0; i < 63; i++) { + r[i] += carry; + r[i+1] += (r[i] >> 4); + r[i] &= 15; + carry = (r[i] >> 3); + r[i] -= (carry << 4); + } + r[63] += carry; +} + +void contract256_slidingwindow_modm(signed char r[256], const bignum256modm s, int windowsize) { + int i,j,k,b; + int m = (1 << (windowsize - 1)) - 1, soplen = 256; + signed char *bits = r; + bignum256modm_element_t v; + + /* first put the binary expansion into r */ + for (i = 0; i < 8; i++) { + v = s[i]; + for (j = 0; j < 30; j++, v >>= 1) + *bits++ = (v & 1); + } + v = s[8]; + for (j = 0; j < 16; j++, v >>= 1) + *bits++ = (v & 1); + + /* Making it sliding window */ + for (j = 0; j < soplen; j++) { + if (!r[j]) + continue; + + for (b = 1; (b < (soplen - j)) && (b <= 6); b++) { + if ((r[j] + (r[j + b] << b)) <= m) { + r[j] += r[j + b] << b; + r[j + b] = 0; + } else if ((r[j] - (r[j + b] << b)) >= -m) { + r[j] -= r[j + b] << b; + for (k = j + b; k < soplen; k++) { + if (!r[k]) { + r[k] = 1; + break; + } + r[k] = 0; + } + } else if (r[j + b]) { + break; + } + } + } +} diff --git a/ed25519-donna/modm-donna-32bit.h b/ed25519-donna/modm-donna-32bit.h index 74501f7f3..129e3b113 100644 --- a/ed25519-donna/modm-donna-32bit.h +++ b/ed25519-donna/modm-donna-32bit.h @@ -18,351 +18,28 @@ typedef uint32_t bignum256modm_element_t; typedef bignum256modm_element_t bignum256modm[9]; -static const bignum256modm modm_m = { - 0x1cf5d3ed, 0x20498c69, 0x2f79cd65, 0x37be77a8, - 0x00000014, 0x00000000, 0x00000000, 0x00000000, - 0x00001000 -}; - -static const bignum256modm modm_mu = { - 0x0a2c131b, 0x3673968c, 0x06329a7e, 0x01885742, - 0x3fffeb21, 0x3fffffff, 0x3fffffff, 0x3fffffff, - 0x000fffff -}; - -static bignum256modm_element_t -lt_modm(bignum256modm_element_t a, bignum256modm_element_t b) { - return (a - b) >> 31; -} - /* see HAC, Alg. 14.42 Step 4 */ -static void -reduce256_modm(bignum256modm r) { - bignum256modm t; - bignum256modm_element_t b = 0, pb, mask; - - /* t = r - m */ - pb = 0; - pb += modm_m[0]; b = lt_modm(r[0], pb); t[0] = (r[0] - pb + (b << 30)); pb = b; - pb += modm_m[1]; b = lt_modm(r[1], pb); t[1] = (r[1] - pb + (b << 30)); pb = b; - pb += modm_m[2]; b = lt_modm(r[2], pb); t[2] = (r[2] - pb + (b << 30)); pb = b; - pb += modm_m[3]; b = lt_modm(r[3], pb); t[3] = (r[3] - pb + (b << 30)); pb = b; - pb += modm_m[4]; b = lt_modm(r[4], pb); t[4] = (r[4] - pb + (b << 30)); pb = b; - pb += modm_m[5]; b = lt_modm(r[5], pb); t[5] = (r[5] - pb + (b << 30)); pb = b; - pb += modm_m[6]; b = lt_modm(r[6], pb); t[6] = (r[6] - pb + (b << 30)); pb = b; - pb += modm_m[7]; b = lt_modm(r[7], pb); t[7] = (r[7] - pb + (b << 30)); pb = b; - pb += modm_m[8]; b = lt_modm(r[8], pb); t[8] = (r[8] - pb + (b << 16)); - - /* keep r if r was smaller than m */ - mask = b - 1; - r[0] ^= mask & (r[0] ^ t[0]); - r[1] ^= mask & (r[1] ^ t[1]); - r[2] ^= mask & (r[2] ^ t[2]); - r[3] ^= mask & (r[3] ^ t[3]); - r[4] ^= mask & (r[4] ^ t[4]); - r[5] ^= mask & (r[5] ^ t[5]); - r[6] ^= mask & (r[6] ^ t[6]); - r[7] ^= mask & (r[7] ^ t[7]); - r[8] ^= mask & (r[8] ^ t[8]); -} +void reduce256_modm(bignum256modm r); /* Barrett reduction, see HAC, Alg. 14.42 Instead of passing in x, pre-process in to q1 and r1 for efficiency */ -static void -barrett_reduce256_modm(bignum256modm r, const bignum256modm q1, const bignum256modm r1) { - bignum256modm q3, r2; - uint64_t c; - bignum256modm_element_t f, b, pb; - - /* q1 = x >> 248 = 264 bits = 9 30 bit elements - q2 = mu * q1 - q3 = (q2 / 256(32+1)) = q2 / (2^8)^(32+1) = q2 >> 264 */ - c = mul32x32_64(modm_mu[0], q1[7]) + mul32x32_64(modm_mu[1], q1[6]) + mul32x32_64(modm_mu[2], q1[5]) + mul32x32_64(modm_mu[3], q1[4]) + mul32x32_64(modm_mu[4], q1[3]) + mul32x32_64(modm_mu[5], q1[2]) + mul32x32_64(modm_mu[6], q1[1]) + mul32x32_64(modm_mu[7], q1[0]); - c >>= 30; - c += mul32x32_64(modm_mu[0], q1[8]) + mul32x32_64(modm_mu[1], q1[7]) + mul32x32_64(modm_mu[2], q1[6]) + mul32x32_64(modm_mu[3], q1[5]) + mul32x32_64(modm_mu[4], q1[4]) + mul32x32_64(modm_mu[5], q1[3]) + mul32x32_64(modm_mu[6], q1[2]) + mul32x32_64(modm_mu[7], q1[1]) + mul32x32_64(modm_mu[8], q1[0]); - f = (bignum256modm_element_t)c; q3[0] = (f >> 24) & 0x3f; c >>= 30; - c += mul32x32_64(modm_mu[1], q1[8]) + mul32x32_64(modm_mu[2], q1[7]) + mul32x32_64(modm_mu[3], q1[6]) + mul32x32_64(modm_mu[4], q1[5]) + mul32x32_64(modm_mu[5], q1[4]) + mul32x32_64(modm_mu[6], q1[3]) + mul32x32_64(modm_mu[7], q1[2]) + mul32x32_64(modm_mu[8], q1[1]); - f = (bignum256modm_element_t)c; q3[0] |= (f << 6) & 0x3fffffff; q3[1] = (f >> 24) & 0x3f; c >>= 30; - c += mul32x32_64(modm_mu[2], q1[8]) + mul32x32_64(modm_mu[3], q1[7]) + mul32x32_64(modm_mu[4], q1[6]) + mul32x32_64(modm_mu[5], q1[5]) + mul32x32_64(modm_mu[6], q1[4]) + mul32x32_64(modm_mu[7], q1[3]) + mul32x32_64(modm_mu[8], q1[2]); - f = (bignum256modm_element_t)c; q3[1] |= (f << 6) & 0x3fffffff; q3[2] = (f >> 24) & 0x3f; c >>= 30; - c += mul32x32_64(modm_mu[3], q1[8]) + mul32x32_64(modm_mu[4], q1[7]) + mul32x32_64(modm_mu[5], q1[6]) + mul32x32_64(modm_mu[6], q1[5]) + mul32x32_64(modm_mu[7], q1[4]) + mul32x32_64(modm_mu[8], q1[3]); - f = (bignum256modm_element_t)c; q3[2] |= (f << 6) & 0x3fffffff; q3[3] = (f >> 24) & 0x3f; c >>= 30; - c += mul32x32_64(modm_mu[4], q1[8]) + mul32x32_64(modm_mu[5], q1[7]) + mul32x32_64(modm_mu[6], q1[6]) + mul32x32_64(modm_mu[7], q1[5]) + mul32x32_64(modm_mu[8], q1[4]); - f = (bignum256modm_element_t)c; q3[3] |= (f << 6) & 0x3fffffff; q3[4] = (f >> 24) & 0x3f; c >>= 30; - c += mul32x32_64(modm_mu[5], q1[8]) + mul32x32_64(modm_mu[6], q1[7]) + mul32x32_64(modm_mu[7], q1[6]) + mul32x32_64(modm_mu[8], q1[5]); - f = (bignum256modm_element_t)c; q3[4] |= (f << 6) & 0x3fffffff; q3[5] = (f >> 24) & 0x3f; c >>= 30; - c += mul32x32_64(modm_mu[6], q1[8]) + mul32x32_64(modm_mu[7], q1[7]) + mul32x32_64(modm_mu[8], q1[6]); - f = (bignum256modm_element_t)c; q3[5] |= (f << 6) & 0x3fffffff; q3[6] = (f >> 24) & 0x3f; c >>= 30; - c += mul32x32_64(modm_mu[7], q1[8]) + mul32x32_64(modm_mu[8], q1[7]); - f = (bignum256modm_element_t)c; q3[6] |= (f << 6) & 0x3fffffff; q3[7] = (f >> 24) & 0x3f; c >>= 30; - c += mul32x32_64(modm_mu[8], q1[8]); - f = (bignum256modm_element_t)c; q3[7] |= (f << 6) & 0x3fffffff; q3[8] = (bignum256modm_element_t)(c >> 24); - - /* r1 = (x mod 256^(32+1)) = x mod (2^8)(31+1) = x & ((1 << 264) - 1) - r2 = (q3 * m) mod (256^(32+1)) = (q3 * m) & ((1 << 264) - 1) */ - c = mul32x32_64(modm_m[0], q3[0]); - r2[0] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30; - c += mul32x32_64(modm_m[0], q3[1]) + mul32x32_64(modm_m[1], q3[0]); - r2[1] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30; - c += mul32x32_64(modm_m[0], q3[2]) + mul32x32_64(modm_m[1], q3[1]) + mul32x32_64(modm_m[2], q3[0]); - r2[2] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30; - c += mul32x32_64(modm_m[0], q3[3]) + mul32x32_64(modm_m[1], q3[2]) + mul32x32_64(modm_m[2], q3[1]) + mul32x32_64(modm_m[3], q3[0]); - r2[3] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30; - c += mul32x32_64(modm_m[0], q3[4]) + mul32x32_64(modm_m[1], q3[3]) + mul32x32_64(modm_m[2], q3[2]) + mul32x32_64(modm_m[3], q3[1]) + mul32x32_64(modm_m[4], q3[0]); - r2[4] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30; - c += mul32x32_64(modm_m[0], q3[5]) + mul32x32_64(modm_m[1], q3[4]) + mul32x32_64(modm_m[2], q3[3]) + mul32x32_64(modm_m[3], q3[2]) + mul32x32_64(modm_m[4], q3[1]) + mul32x32_64(modm_m[5], q3[0]); - r2[5] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30; - c += mul32x32_64(modm_m[0], q3[6]) + mul32x32_64(modm_m[1], q3[5]) + mul32x32_64(modm_m[2], q3[4]) + mul32x32_64(modm_m[3], q3[3]) + mul32x32_64(modm_m[4], q3[2]) + mul32x32_64(modm_m[5], q3[1]) + mul32x32_64(modm_m[6], q3[0]); - r2[6] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30; - c += mul32x32_64(modm_m[0], q3[7]) + mul32x32_64(modm_m[1], q3[6]) + mul32x32_64(modm_m[2], q3[5]) + mul32x32_64(modm_m[3], q3[4]) + mul32x32_64(modm_m[4], q3[3]) + mul32x32_64(modm_m[5], q3[2]) + mul32x32_64(modm_m[6], q3[1]) + mul32x32_64(modm_m[7], q3[0]); - r2[7] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30; - c += mul32x32_64(modm_m[0], q3[8]) + mul32x32_64(modm_m[1], q3[7]) + mul32x32_64(modm_m[2], q3[6]) + mul32x32_64(modm_m[3], q3[5]) + mul32x32_64(modm_m[4], q3[4]) + mul32x32_64(modm_m[5], q3[3]) + mul32x32_64(modm_m[6], q3[2]) + mul32x32_64(modm_m[7], q3[1]) + mul32x32_64(modm_m[8], q3[0]); - r2[8] = (bignum256modm_element_t)(c & 0xffffff); - - /* r = r1 - r2 - if (r < 0) r += (1 << 264) */ - pb = 0; - pb += r2[0]; b = lt_modm(r1[0], pb); r[0] = (r1[0] - pb + (b << 30)); pb = b; - pb += r2[1]; b = lt_modm(r1[1], pb); r[1] = (r1[1] - pb + (b << 30)); pb = b; - pb += r2[2]; b = lt_modm(r1[2], pb); r[2] = (r1[2] - pb + (b << 30)); pb = b; - pb += r2[3]; b = lt_modm(r1[3], pb); r[3] = (r1[3] - pb + (b << 30)); pb = b; - pb += r2[4]; b = lt_modm(r1[4], pb); r[4] = (r1[4] - pb + (b << 30)); pb = b; - pb += r2[5]; b = lt_modm(r1[5], pb); r[5] = (r1[5] - pb + (b << 30)); pb = b; - pb += r2[6]; b = lt_modm(r1[6], pb); r[6] = (r1[6] - pb + (b << 30)); pb = b; - pb += r2[7]; b = lt_modm(r1[7], pb); r[7] = (r1[7] - pb + (b << 30)); pb = b; - pb += r2[8]; b = lt_modm(r1[8], pb); r[8] = (r1[8] - pb + (b << 24)); - - reduce256_modm(r); - reduce256_modm(r); -} +void barrett_reduce256_modm(bignum256modm r, const bignum256modm q1, const bignum256modm r1); /* addition modulo m */ -static void add256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y) { - bignum256modm_element_t c; - - c = x[0] + y[0]; r[0] = c & 0x3fffffff; c >>= 30; - c += x[1] + y[1]; r[1] = c & 0x3fffffff; c >>= 30; - c += x[2] + y[2]; r[2] = c & 0x3fffffff; c >>= 30; - c += x[3] + y[3]; r[3] = c & 0x3fffffff; c >>= 30; - c += x[4] + y[4]; r[4] = c & 0x3fffffff; c >>= 30; - c += x[5] + y[5]; r[5] = c & 0x3fffffff; c >>= 30; - c += x[6] + y[6]; r[6] = c & 0x3fffffff; c >>= 30; - c += x[7] + y[7]; r[7] = c & 0x3fffffff; c >>= 30; - c += x[8] + y[8]; r[8] = c; - - reduce256_modm(r); -} +void add256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y); /* multiplication modulo m */ -static void mul256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y) { - bignum256modm r1, q1; - uint64_t c; - bignum256modm_element_t f; - - /* r1 = (x mod 256^(32+1)) = x mod (2^8)(31+1) = x & ((1 << 264) - 1) - q1 = x >> 248 = 264 bits = 9 30 bit elements */ - c = mul32x32_64(x[0], y[0]); - f = (bignum256modm_element_t)c; r1[0] = (f & 0x3fffffff); c >>= 30; - c += mul32x32_64(x[0], y[1]) + mul32x32_64(x[1], y[0]); - f = (bignum256modm_element_t)c; r1[1] = (f & 0x3fffffff); c >>= 30; - c += mul32x32_64(x[0], y[2]) + mul32x32_64(x[1], y[1]) + mul32x32_64(x[2], y[0]); - f = (bignum256modm_element_t)c; r1[2] = (f & 0x3fffffff); c >>= 30; - c += mul32x32_64(x[0], y[3]) + mul32x32_64(x[1], y[2]) + mul32x32_64(x[2], y[1]) + mul32x32_64(x[3], y[0]); - f = (bignum256modm_element_t)c; r1[3] = (f & 0x3fffffff); c >>= 30; - c += mul32x32_64(x[0], y[4]) + mul32x32_64(x[1], y[3]) + mul32x32_64(x[2], y[2]) + mul32x32_64(x[3], y[1]) + mul32x32_64(x[4], y[0]); - f = (bignum256modm_element_t)c; r1[4] = (f & 0x3fffffff); c >>= 30; - c += mul32x32_64(x[0], y[5]) + mul32x32_64(x[1], y[4]) + mul32x32_64(x[2], y[3]) + mul32x32_64(x[3], y[2]) + mul32x32_64(x[4], y[1]) + mul32x32_64(x[5], y[0]); - f = (bignum256modm_element_t)c; r1[5] = (f & 0x3fffffff); c >>= 30; - c += mul32x32_64(x[0], y[6]) + mul32x32_64(x[1], y[5]) + mul32x32_64(x[2], y[4]) + mul32x32_64(x[3], y[3]) + mul32x32_64(x[4], y[2]) + mul32x32_64(x[5], y[1]) + mul32x32_64(x[6], y[0]); - f = (bignum256modm_element_t)c; r1[6] = (f & 0x3fffffff); c >>= 30; - c += mul32x32_64(x[0], y[7]) + mul32x32_64(x[1], y[6]) + mul32x32_64(x[2], y[5]) + mul32x32_64(x[3], y[4]) + mul32x32_64(x[4], y[3]) + mul32x32_64(x[5], y[2]) + mul32x32_64(x[6], y[1]) + mul32x32_64(x[7], y[0]); - f = (bignum256modm_element_t)c; r1[7] = (f & 0x3fffffff); c >>= 30; - c += mul32x32_64(x[0], y[8]) + mul32x32_64(x[1], y[7]) + mul32x32_64(x[2], y[6]) + mul32x32_64(x[3], y[5]) + mul32x32_64(x[4], y[4]) + mul32x32_64(x[5], y[3]) + mul32x32_64(x[6], y[2]) + mul32x32_64(x[7], y[1]) + mul32x32_64(x[8], y[0]); - f = (bignum256modm_element_t)c; r1[8] = (f & 0x00ffffff); q1[0] = (f >> 8) & 0x3fffff; c >>= 30; - c += mul32x32_64(x[1], y[8]) + mul32x32_64(x[2], y[7]) + mul32x32_64(x[3], y[6]) + mul32x32_64(x[4], y[5]) + mul32x32_64(x[5], y[4]) + mul32x32_64(x[6], y[3]) + mul32x32_64(x[7], y[2]) + mul32x32_64(x[8], y[1]); - f = (bignum256modm_element_t)c; q1[0] = (q1[0] | (f << 22)) & 0x3fffffff; q1[1] = (f >> 8) & 0x3fffff; c >>= 30; - c += mul32x32_64(x[2], y[8]) + mul32x32_64(x[3], y[7]) + mul32x32_64(x[4], y[6]) + mul32x32_64(x[5], y[5]) + mul32x32_64(x[6], y[4]) + mul32x32_64(x[7], y[3]) + mul32x32_64(x[8], y[2]); - f = (bignum256modm_element_t)c; q1[1] = (q1[1] | (f << 22)) & 0x3fffffff; q1[2] = (f >> 8) & 0x3fffff; c >>= 30; - c += mul32x32_64(x[3], y[8]) + mul32x32_64(x[4], y[7]) + mul32x32_64(x[5], y[6]) + mul32x32_64(x[6], y[5]) + mul32x32_64(x[7], y[4]) + mul32x32_64(x[8], y[3]); - f = (bignum256modm_element_t)c; q1[2] = (q1[2] | (f << 22)) & 0x3fffffff; q1[3] = (f >> 8) & 0x3fffff; c >>= 30; - c += mul32x32_64(x[4], y[8]) + mul32x32_64(x[5], y[7]) + mul32x32_64(x[6], y[6]) + mul32x32_64(x[7], y[5]) + mul32x32_64(x[8], y[4]); - f = (bignum256modm_element_t)c; q1[3] = (q1[3] | (f << 22)) & 0x3fffffff; q1[4] = (f >> 8) & 0x3fffff; c >>= 30; - c += mul32x32_64(x[5], y[8]) + mul32x32_64(x[6], y[7]) + mul32x32_64(x[7], y[6]) + mul32x32_64(x[8], y[5]); - f = (bignum256modm_element_t)c; q1[4] = (q1[4] | (f << 22)) & 0x3fffffff; q1[5] = (f >> 8) & 0x3fffff; c >>= 30; - c += mul32x32_64(x[6], y[8]) + mul32x32_64(x[7], y[7]) + mul32x32_64(x[8], y[6]); - f = (bignum256modm_element_t)c; q1[5] = (q1[5] | (f << 22)) & 0x3fffffff; q1[6] = (f >> 8) & 0x3fffff; c >>= 30; - c += mul32x32_64(x[7], y[8]) + mul32x32_64(x[8], y[7]); - f = (bignum256modm_element_t)c; q1[6] = (q1[6] | (f << 22)) & 0x3fffffff; q1[7] = (f >> 8) & 0x3fffff; c >>= 30; - c += mul32x32_64(x[8], y[8]); - f = (bignum256modm_element_t)c; q1[7] = (q1[7] | (f << 22)) & 0x3fffffff; q1[8] = (f >> 8) & 0x3fffff; - - barrett_reduce256_modm(r, q1, r1); -} - -static void expand256_modm(bignum256modm out, const unsigned char *in, size_t len) { - unsigned char work[64] = {0}; - bignum256modm_element_t x[16]; - bignum256modm q1; - - memcpy(work, in, len); - x[0] = U8TO32_LE(work + 0); - x[1] = U8TO32_LE(work + 4); - x[2] = U8TO32_LE(work + 8); - x[3] = U8TO32_LE(work + 12); - x[4] = U8TO32_LE(work + 16); - x[5] = U8TO32_LE(work + 20); - x[6] = U8TO32_LE(work + 24); - x[7] = U8TO32_LE(work + 28); - x[8] = U8TO32_LE(work + 32); - x[9] = U8TO32_LE(work + 36); - x[10] = U8TO32_LE(work + 40); - x[11] = U8TO32_LE(work + 44); - x[12] = U8TO32_LE(work + 48); - x[13] = U8TO32_LE(work + 52); - x[14] = U8TO32_LE(work + 56); - x[15] = U8TO32_LE(work + 60); - - /* r1 = (x mod 256^(32+1)) = x mod (2^8)(31+1) = x & ((1 << 264) - 1) */ - out[0] = ( x[0]) & 0x3fffffff; - out[1] = ((x[ 0] >> 30) | (x[ 1] << 2)) & 0x3fffffff; - out[2] = ((x[ 1] >> 28) | (x[ 2] << 4)) & 0x3fffffff; - out[3] = ((x[ 2] >> 26) | (x[ 3] << 6)) & 0x3fffffff; - out[4] = ((x[ 3] >> 24) | (x[ 4] << 8)) & 0x3fffffff; - out[5] = ((x[ 4] >> 22) | (x[ 5] << 10)) & 0x3fffffff; - out[6] = ((x[ 5] >> 20) | (x[ 6] << 12)) & 0x3fffffff; - out[7] = ((x[ 6] >> 18) | (x[ 7] << 14)) & 0x3fffffff; - out[8] = ((x[ 7] >> 16) | (x[ 8] << 16)) & 0x00ffffff; - - /* 8*31 = 248 bits, no need to reduce */ - if (len < 32) - return; - - /* q1 = x >> 248 = 264 bits = 9 30 bit elements */ - q1[0] = ((x[ 7] >> 24) | (x[ 8] << 8)) & 0x3fffffff; - q1[1] = ((x[ 8] >> 22) | (x[ 9] << 10)) & 0x3fffffff; - q1[2] = ((x[ 9] >> 20) | (x[10] << 12)) & 0x3fffffff; - q1[3] = ((x[10] >> 18) | (x[11] << 14)) & 0x3fffffff; - q1[4] = ((x[11] >> 16) | (x[12] << 16)) & 0x3fffffff; - q1[5] = ((x[12] >> 14) | (x[13] << 18)) & 0x3fffffff; - q1[6] = ((x[13] >> 12) | (x[14] << 20)) & 0x3fffffff; - q1[7] = ((x[14] >> 10) | (x[15] << 22)) & 0x3fffffff; - q1[8] = ((x[15] >> 8) ); - - barrett_reduce256_modm(out, q1, out); -} - -DONNA_UNUSED static void -expand_raw256_modm(bignum256modm out, const unsigned char in[32]); - -void expand_raw256_modm(bignum256modm out, const unsigned char in[32]) { - bignum256modm_element_t x[8]; - - x[0] = U8TO32_LE(in + 0); - x[1] = U8TO32_LE(in + 4); - x[2] = U8TO32_LE(in + 8); - x[3] = U8TO32_LE(in + 12); - x[4] = U8TO32_LE(in + 16); - x[5] = U8TO32_LE(in + 20); - x[6] = U8TO32_LE(in + 24); - x[7] = U8TO32_LE(in + 28); - - out[0] = ( x[0]) & 0x3fffffff; - out[1] = ((x[ 0] >> 30) | (x[ 1] << 2)) & 0x3fffffff; - out[2] = ((x[ 1] >> 28) | (x[ 2] << 4)) & 0x3fffffff; - out[3] = ((x[ 2] >> 26) | (x[ 3] << 6)) & 0x3fffffff; - out[4] = ((x[ 3] >> 24) | (x[ 4] << 8)) & 0x3fffffff; - out[5] = ((x[ 4] >> 22) | (x[ 5] << 10)) & 0x3fffffff; - out[6] = ((x[ 5] >> 20) | (x[ 6] << 12)) & 0x3fffffff; - out[7] = ((x[ 6] >> 18) | (x[ 7] << 14)) & 0x3fffffff; - out[8] = ((x[ 7] >> 16) ) & 0x0000ffff; -} - -static void contract256_modm(unsigned char out[32], const bignum256modm in) { - U32TO8_LE(out + 0, (in[0] ) | (in[1] << 30)); - U32TO8_LE(out + 4, (in[1] >> 2) | (in[2] << 28)); - U32TO8_LE(out + 8, (in[2] >> 4) | (in[3] << 26)); - U32TO8_LE(out + 12, (in[3] >> 6) | (in[4] << 24)); - U32TO8_LE(out + 16, (in[4] >> 8) | (in[5] << 22)); - U32TO8_LE(out + 20, (in[5] >> 10) | (in[6] << 20)); - U32TO8_LE(out + 24, (in[6] >> 12) | (in[7] << 18)); - U32TO8_LE(out + 28, (in[7] >> 14) | (in[8] << 16)); -} - -static void contract256_window4_modm(signed char r[64], const bignum256modm in) { - char carry; - signed char *quads = r; - bignum256modm_element_t i, j, v; - - for (i = 0; i < 8; i += 2) { - v = in[i]; - for (j = 0; j < 7; j++) { - *quads++ = (v & 15); - v >>= 4; - } - v |= (in[i+1] << 2); - for (j = 0; j < 8; j++) { - *quads++ = (v & 15); - v >>= 4; - } - } - v = in[8]; - *quads++ = (v & 15); v >>= 4; - *quads++ = (v & 15); v >>= 4; - *quads++ = (v & 15); v >>= 4; - *quads++ = (v & 15); v >>= 4; +void mul256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y); - /* making it signed */ - carry = 0; - for(i = 0; i < 63; i++) { - r[i] += carry; - r[i+1] += (r[i] >> 4); - r[i] &= 15; - carry = (r[i] >> 3); - r[i] -= (carry << 4); - } - r[63] += carry; -} +void expand256_modm(bignum256modm out, const unsigned char *in, size_t len); -static void contract256_slidingwindow_modm(signed char r[256], const bignum256modm s, int windowsize) { - int i,j,k,b; - int m = (1 << (windowsize - 1)) - 1, soplen = 256; - signed char *bits = r; - bignum256modm_element_t v; +void expand_raw256_modm(bignum256modm out, const unsigned char in[32]); - /* first put the binary expansion into r */ - for (i = 0; i < 8; i++) { - v = s[i]; - for (j = 0; j < 30; j++, v >>= 1) - *bits++ = (v & 1); - } - v = s[8]; - for (j = 0; j < 16; j++, v >>= 1) - *bits++ = (v & 1); +void contract256_modm(unsigned char out[32], const bignum256modm in); - /* Making it sliding window */ - for (j = 0; j < soplen; j++) { - if (!r[j]) - continue; +void contract256_window4_modm(signed char r[64], const bignum256modm in); - for (b = 1; (b < (soplen - j)) && (b <= 6); b++) { - if ((r[j] + (r[j + b] << b)) <= m) { - r[j] += r[j + b] << b; - r[j + b] = 0; - } else if ((r[j] - (r[j + b] << b)) >= -m) { - r[j] -= r[j + b] << b; - for (k = j + b; k < soplen; k++) { - if (!r[k]) { - r[k] = 1; - break; - } - r[k] = 0; - } - } else if (r[j + b]) { - break; - } - } - } -} +void contract256_slidingwindow_modm(signed char r[256], const bignum256modm s, int windowsize); From cc3ab711971499ebd684eed81fe6b4f2f2ba3677 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Mon, 31 Jul 2017 15:44:02 +0100 Subject: [PATCH 478/627] CMakeLists: Copy SOURCES from Makefile --- CMakeLists.txt | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 177863d03..31eb67575 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,10 +1,25 @@ cmake_minimum_required(VERSION 2.8) -set(SOURCES address.c aes/aescrypt.c aes/aeskey.c aes/aes_modes.c aes/aestab.c base32.c base58.c bignum.c bip32.c bip39.c ecdsa.c hmac.c nist256p1.c pbkdf2.c rand.c ripemd160.c secp256k1.c sha2.c sha3.c ed25519-donna/ed25519.c ed25519-donna/ed25519-donna-basepoint-table.c ed25519-donna/ed25519-sha3.c ed25519-donna/ed25519-keccak.c) +set(SOURCES + bignum.c ecdsa.c curves.c secp256k1.c nist256p1.c rand.c hmac.c bip32.c bip39.c pbkdf2.c base58.c base32.c + address.c + script.c + ripemd160.c + sha2.c + sha3.c + aes/aescrypt.c aes/aeskey.c aes/aestab.c aes/aes_modes.c + ed25519-donna/curve25519-donna-32bit.c ed25519-donna/curve25519-donna-helpers.c ed25519-donna/modm-donna-32bit.c + ed25519-donna/ed25519-donna-basepoint-table.c ed25519-donna/ed25519-donna-32bit-tables.c ed25519-donna/ed25519-donna-impl-base.c + ed25519-donna/ed25519.c ed25519-donna/curve25519-donna-scalarmult-base.c ed25519-donna/ed25519-sha3.c ed25519-donna/ed25519-keccak.c + blake2b.c blake2s.c + chacha20poly1305/chacha20poly1305.c chacha20poly1305/chacha_merged.c chacha20poly1305/poly1305-donna.c chacha20poly1305/rfc7539.c +) add_library(TrezorCrypto STATIC ${SOURCES}) target_include_directories(TrezorCrypto PUBLIC .) +target_include_directories(TrezorCrypto PUBLIC aes) +target_include_directories(TrezorCrypto PUBLIC chacha20poly1305) target_include_directories(TrezorCrypto PUBLIC ed25519-donna) target_compile_options(TrezorCrypto PRIVATE "-std=c99") From cb30b580551ae1e9339ed0c1f7874103e25d46b0 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sat, 12 Aug 2017 12:43:49 +0100 Subject: [PATCH 479/627] rc4: Initial commit --- CMakeLists.txt | 1 + Makefile | 1 + rc4.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++ rc4.h | 37 +++++++++++++++++++++++++++++++++ 4 files changed, 95 insertions(+) create mode 100644 rc4.c create mode 100644 rc4.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 31eb67575..e977f725a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,6 +13,7 @@ set(SOURCES ed25519-donna/ed25519.c ed25519-donna/curve25519-donna-scalarmult-base.c ed25519-donna/ed25519-sha3.c ed25519-donna/ed25519-keccak.c blake2b.c blake2s.c chacha20poly1305/chacha20poly1305.c chacha20poly1305/chacha_merged.c chacha20poly1305/poly1305-donna.c chacha20poly1305/rfc7539.c + rc4.c ) add_library(TrezorCrypto STATIC ${SOURCES}) diff --git a/Makefile b/Makefile index 6f1051b41..d83725ebf 100644 --- a/Makefile +++ b/Makefile @@ -48,6 +48,7 @@ SRCS += ed25519-donna/ed25519-donna-basepoint-table.c ed25519-donna/ed25519-don SRCS += ed25519-donna/ed25519.c ed25519-donna/curve25519-donna-scalarmult-base.c ed25519-donna/ed25519-sha3.c ed25519-donna/ed25519-keccak.c SRCS += blake2b.c blake2s.c SRCS += chacha20poly1305/chacha20poly1305.c chacha20poly1305/chacha_merged.c chacha20poly1305/poly1305-donna.c chacha20poly1305/rfc7539.c +SRCS += rc4.c OBJS = $(SRCS:.c=.o) diff --git a/rc4.c b/rc4.c new file mode 100644 index 000000000..db9eb1ffa --- /dev/null +++ b/rc4.c @@ -0,0 +1,56 @@ +/** + * Copyright (c) 2017 Saleem Rashid + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, E1PRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "rc4.h" + +static inline void rc4_swap(RC4_CTX *ctx, uint8_t i, uint8_t j) { + uint8_t temp = ctx->S[i]; + ctx->S[i] = ctx->S[j]; + ctx->S[j] = temp; +} + +void rc4_init(RC4_CTX *ctx, const uint8_t *key, size_t length) { + ctx->i = 0; + ctx->j = 0; + + for (size_t i = 0; i < 256; i++) { + ctx->S[i] = i; + } + + uint8_t j = 0; + for (size_t i = 0; i < 256; i++) { + j += ctx->S[i] + key[i % length]; + rc4_swap(ctx, i, j); + } +} + +void rc4_encrypt(RC4_CTX *ctx, uint8_t *buffer, size_t length) { + for (size_t idx = 0; idx < length; idx++) { + ctx->i++; + ctx->j += ctx->S[ctx->i]; + + rc4_swap(ctx, ctx->i, ctx->j); + + uint8_t K = ctx->S[(ctx->S[ctx->i] + ctx->S[ctx->j]) % 256]; + buffer[idx] ^= K; + } +} diff --git a/rc4.h b/rc4.h new file mode 100644 index 000000000..7b56e4a3d --- /dev/null +++ b/rc4.h @@ -0,0 +1,37 @@ +/** + * Copyright (c) 2017 Saleem Rashid + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __RC4_H__ +#define __RC4_H__ + +#include +#include + +typedef struct { + uint8_t S[256]; + uint8_t i, j; +} RC4_CTX; + +void rc4_init(RC4_CTX *ctx, const uint8_t *key, size_t length); +void rc4_encrypt(RC4_CTX *ctx, uint8_t *buffer, size_t length); + +#endif From 90d84ea1735de13fe1c7522c1d8d573251b24f59 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sat, 12 Aug 2017 12:44:01 +0100 Subject: [PATCH 480/627] test_check: Add RC4 tests --- test_check.c | 216 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 216 insertions(+) diff --git a/test_check.c b/test_check.c index 839195745..f86b69f0d 100644 --- a/test_check.c +++ b/test_check.c @@ -57,6 +57,7 @@ #include "script.h" #include "rfc6979.h" #include "address.h" +#include "rc4.h" /* * This is a clever trick to make Valgrind's Memcheck verify code @@ -3281,6 +3282,217 @@ START_TEST(test_multibyte_address) } END_TEST +// https://tools.ietf.org/html/rfc6229#section-2 +START_TEST(test_rc4_rfc6229) +{ + static const size_t offsets[] = { + 0x0, + 0xf0, + 0x1f0, + 0x2f0, + 0x3f0, + 0x5f0, + 0x7f0, + 0xbf0, + 0xff0, + }; + + static const struct { + char key[65]; + char vectors[sizeof(offsets) / sizeof(*offsets)][65]; + } tests[] = { + { + "0102030405", + { + "b2396305f03dc027ccc3524a0a1118a8" "6982944f18fc82d589c403a47a0d0919", + "28cb1132c96ce286421dcaadb8b69eae" "1cfcf62b03eddb641d77dfcf7f8d8c93", + "42b7d0cdd918a8a33dd51781c81f4041" "6459844432a7da923cfb3eb4980661f6", + "ec10327bde2beefd18f9277680457e22" "eb62638d4f0ba1fe9fca20e05bf8ff2b", + "45129048e6a0ed0b56b490338f078da5" "30abbcc7c20b01609f23ee2d5f6bb7df", + "3294f744d8f9790507e70f62e5bbceea" "d8729db41882259bee4f825325f5a130", + "1eb14a0c13b3bf47fa2a0ba93ad45b8b" "cc582f8ba9f265e2b1be9112e975d2d7", + "f2e30f9bd102ecbf75aaade9bc35c43c" "ec0e11c479dc329dc8da7968fe965681", + "068326a2118416d21f9d04b2cd1ca050" "ff25b58995996707e51fbdf08b34d875", + } + }, { + "01020304050607", + { + "293f02d47f37c9b633f2af5285feb46b" "e620f1390d19bd84e2e0fd752031afc1", + "914f02531c9218810df60f67e338154c" "d0fdb583073ce85ab83917740ec011d5", + "75f81411e871cffa70b90c74c592e454" "0bb87202938dad609e87a5a1b079e5e4", + "c2911246b612e7e7b903dfeda1dad866" "32828f91502b6291368de8081de36fc2", + "f3b9a7e3b297bf9ad804512f9063eff1" "8ecb67a9ba1f55a5a067e2b026a3676f", + "d2aa902bd42d0d7cfd340cd45810529f" "78b272c96e42eab4c60bd914e39d06e3", + "f4332fd31a079396ee3cee3f2a4ff049" "05459781d41fda7f30c1be7e1246c623", + "adfd3868b8e51485d5e610017e3dd609" "ad26581c0c5be45f4cea01db2f3805d5", + "f3172ceffc3b3d997c85ccd5af1a950c" "e74b0b9731227fd37c0ec08a47ddd8b8", + } + }, { + "0102030405060708", + { + "97ab8a1bf0afb96132f2f67258da15a8" "8263efdb45c4a18684ef87e6b19e5b09", + "9636ebc9841926f4f7d1f362bddf6e18" "d0a990ff2c05fef5b90373c9ff4b870a", + "73239f1db7f41d80b643c0c52518ec63" "163b319923a6bdb4527c626126703c0f", + "49d6c8af0f97144a87df21d91472f966" "44173a103b6616c5d5ad1cee40c863d0", + "273c9c4b27f322e4e716ef53a47de7a4" "c6d0e7b226259fa9023490b26167ad1d", + "1fe8986713f07c3d9ae1c163ff8cf9d3" "8369e1a965610be887fbd0c79162aafb", + "0a0127abb44484b9fbef5abcae1b579f" "c2cdadc6402e8ee866e1f37bdb47e42c", + "26b51ea37df8e1d6f76fc3b66a7429b3" "bc7683205d4f443dc1f29dda3315c87b", + "d5fa5a3469d29aaaf83d23589db8c85b" "3fb46e2c8f0f068edce8cdcd7dfc5862", + } + }, { + "0102030405060708090a", + { + "ede3b04643e586cc907dc21851709902" "03516ba78f413beb223aa5d4d2df6711", + "3cfd6cb58ee0fdde640176ad0000044d" "48532b21fb6079c9114c0ffd9c04a1ad", + "3e8cea98017109979084b1ef92f99d86" "e20fb49bdb337ee48b8d8dc0f4afeffe", + "5c2521eacd7966f15e056544bea0d315" "e067a7031931a246a6c3875d2f678acb", + "a64f70af88ae56b6f87581c0e23e6b08" "f449031de312814ec6f319291f4a0516", + "bdae85924b3cb1d0a2e33a30c6d79599" "8a0feddbac865a09bcd127fb562ed60a", + "b55a0a5b51a12a8be34899c3e047511a" "d9a09cea3ce75fe39698070317a71339", + "552225ed1177f44584ac8cfa6c4eb5fc" "7e82cbabfc95381b080998442129c2f8", + "1f135ed14ce60a91369d2322bef25e3c" "08b6be45124a43e2eb77953f84dc8553", + } + }, { + "0102030405060708090a0b0c0d0e0f10", + { + "9ac7cc9a609d1ef7b2932899cde41b97" "5248c4959014126a6e8a84f11d1a9e1c", + "065902e4b620f6cc36c8589f66432f2b" "d39d566bc6bce3010768151549f3873f", + "b6d1e6c4a5e4771cad79538df295fb11" "c68c1d5c559a974123df1dbc52a43b89", + "c5ecf88de897fd57fed301701b82a259" "eccbe13de1fcc91c11a0b26c0bc8fa4d", + "e7a72574f8782ae26aabcf9ebcd66065" "bdf0324e6083dcc6d3cedd3ca8c53c16", + "b40110c4190b5622a96116b0017ed297" "ffa0b514647ec04f6306b892ae661181", + "d03d1bc03cd33d70dff9fa5d71963ebd" "8a44126411eaa78bd51e8d87a8879bf5", + "fabeb76028ade2d0e48722e46c4615a3" "c05d88abd50357f935a63c59ee537623", + "ff38265c1642c1abe8d3c2fe5e572bf8" "a36a4c301ae8ac13610ccbc12256cacc", + } + }, { + "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20", + { + "eaa6bd25880bf93d3f5d1e4ca2611d91" "cfa45c9f7e714b54bdfa80027cb14380", + "114ae344ded71b35f2e60febad727fd8" "02e1e7056b0f623900496422943e97b6", + "91cb93c787964e10d9527d999c6f936b" "49b18b42f8e8367cbeb5ef104ba1c7cd", + "87084b3ba700bade955610672745b374" "e7a7b9e9ec540d5ff43bdb12792d1b35", + "c799b596738f6b018c76c74b1759bd90" "7fec5bfd9f9b89ce6548309092d7e958", + "40f250b26d1f096a4afd4c340a588815" "3e34135c79db010200767651cf263073", + "f656abccf88dd827027b2ce917d464ec" "18b62503bfbc077fbabb98f20d98ab34", + "8aed95ee5b0dcbfbef4eb21d3a3f52f9" "625a1ab00ee39a5327346bddb01a9c18", + "a13a7c79c7e119b5ab0296ab28c300b9" "f3e4c0a2e02d1d01f7f0a74618af2b48", + } + }, { + "833222772a", + { + "80ad97bdc973df8a2e879e92a497efda" "20f060c2f2e5126501d3d4fea10d5fc0", + "faa148e99046181fec6b2085f3b20ed9" "f0daf5bab3d596839857846f73fbfe5a", + "1c7e2fc4639232fe297584b296996bc8" "3db9b249406cc8edffac55ccd322ba12", + "e4f9f7e0066154bbd125b745569bc897" "75d5ef262b44c41a9cf63ae14568e1b9", + "6da453dbf81e82334a3d8866cb50a1e3" "7828d074119cab5c22b294d7a9bfa0bb", + "adb89cea9a15fbe617295bd04b8ca05c" "6251d87fd4aaae9a7e4ad5c217d3f300", + "e7119bd6dd9b22afe8f89585432881e2" "785b60fd7ec4e9fcb6545f350d660fab", + "afecc037fdb7b0838eb3d70bcd268382" "dbc1a7b49d57358cc9fa6d61d73b7cf0", + "6349d126a37afcba89794f9804914fdc" "bf42c3018c2f7c66bfde524975768115", + } + }, { + "1910833222772a", + { + "bc9222dbd3274d8fc66d14ccbda6690b" "7ae627410c9a2be693df5bb7485a63e3", + "3f0931aa03defb300f060103826f2a64" "beaa9ec8d59bb68129f3027c96361181", + "74e04db46d28648d7dee8a0064b06cfe" "9b5e81c62fe023c55be42f87bbf932b8", + "ce178fc1826efecbc182f57999a46140" "8bdf55cd55061c06dba6be11de4a578a", + "626f5f4dce652501f3087d39c92cc349" "42daac6a8f9ab9a7fd137c6037825682", + "cc03fdb79192a207312f53f5d4dc33d9" "f70f14122a1c98a3155d28b8a0a8a41d", + "2a3a307ab2708a9c00fe0b42f9c2d6a1" "862617627d2261eab0b1246597ca0ae9", + "55f877ce4f2e1ddbbf8e13e2cde0fdc8" "1b1556cb935f173337705fbb5d501fc1", + "ecd0e96602be7f8d5092816cccf2c2e9" "027881fab4993a1c262024a94fff3f61", + } + }, { + "641910833222772a", + { + "bbf609de9413172d07660cb680716926" "46101a6dab43115d6c522b4fe93604a9", + "cbe1fff21c96f3eef61e8fe0542cbdf0" "347938bffa4009c512cfb4034b0dd1a7", + "7867a786d00a7147904d76ddf1e520e3" "8d3e9e1caefcccb3fbf8d18f64120b32", + "942337f8fd76f0fae8c52d7954810672" "b8548c10f51667f6e60e182fa19b30f7", + "0211c7c6190c9efd1237c34c8f2e06c4" "bda64f65276d2aacb8f90212203a808e", + "bd3820f732ffb53ec193e79d33e27c73" "d0168616861907d482e36cdac8cf5749", + "97b0f0f224b2d2317114808fb03af7a0" "e59616e469787939a063ceea9af956d1", + "c47e0dc1660919c11101208f9e69aa1f" "5ae4f12896b8379a2aad89b5b553d6b0", + "6b6b098d0c293bc2993d80bf0518b6d9" "8170cc3ccd92a698621b939dd38fe7b9", + } + }, { + "8b37641910833222772a", + { + "ab65c26eddb287600db2fda10d1e605c" "bb759010c29658f2c72d93a2d16d2930", + "b901e8036ed1c383cd3c4c4dd0a6ab05" "3d25ce4922924c55f064943353d78a6c", + "12c1aa44bbf87e75e611f69b2c38f49b" "28f2b3434b65c09877470044c6ea170d", + "bd9ef822de5288196134cf8af7839304" "67559c23f052158470a296f725735a32", + "8bab26fbc2c12b0f13e2ab185eabf241" "31185a6d696f0cfa9b42808b38e132a2", + "564d3dae183c5234c8af1e51061c44b5" "3c0778a7b5f72d3c23a3135c7d67b9f4", + "f34369890fcf16fb517dcaae4463b2dd" "02f31c81e8200731b899b028e791bfa7", + "72da646283228c14300853701795616f" "4e0a8c6f7934a788e2265e81d6d0c8f4", + "438dd5eafea0111b6f36b4b938da2a68" "5f6bfc73815874d97100f086979357d8", + } + }, { + "ebb46227c6cc8b37641910833222772a", + { + "720c94b63edf44e131d950ca211a5a30" "c366fdeacf9ca80436be7c358424d20b", + "b3394a40aabf75cba42282ef25a0059f" "4847d81da4942dbc249defc48c922b9f", + "08128c469f275342adda202b2b58da95" "970dacef40ad98723bac5d6955b81761", + "3cb89993b07b0ced93de13d2a11013ac" "ef2d676f1545c2c13dc680a02f4adbfe", + "b60595514f24bc9fe522a6cad7393644" "b515a8c5011754f59003058bdb81514e", + "3c70047e8cbc038e3b9820db601da495" "1175da6ee756de46a53e2b075660b770", + "00a542bba02111cc2c65b38ebdba587e" "5865fdbb5b48064104e830b380f2aede", + "34b21ad2ad44e999db2d7f0863f0d9b6" "84a9218fc36e8a5f2ccfbeae53a27d25", + "a2221a11b833ccb498a59540f0545f4a" "5bbeb4787d59e5373fdbea6c6f75c29b", + } + }, { + "c109163908ebe51debb46227c6cc8b37641910833222772a", + { + "54b64e6b5a20b5e2ec84593dc7989da7" "c135eee237a85465ff97dc03924f45ce", + "cfcc922fb4a14ab45d6175aabbf2d201" "837b87e2a446ad0ef798acd02b94124f", + "17a6dbd664926a0636b3f4c37a4f4694" "4a5f9f26aeeed4d4a25f632d305233d9", + "80a3d01ef00c8e9a4209c17f4eeb358c" "d15e7d5ffaaabc0207bf200a117793a2", + "349682bf588eaa52d0aa1560346aeafa" "f5854cdb76c889e3ad63354e5f7275e3", + "532c7ceccb39df3236318405a4b1279c" "baefe6d9ceb651842260e0d1e05e3b90", + "e82d8c6db54e3c633f581c952ba04207" "4b16e50abd381bd70900a9cd9a62cb23", + "3682ee33bd148bd9f58656cd8f30d9fb" "1e5a0b8475045d9b20b2628624edfd9e", + "63edd684fb826282fe528f9c0e9237bc" "e4dd2e98d6960fae0b43545456743391", + } + }, { + "1ada31d5cf688221c109163908ebe51debb46227c6cc8b37641910833222772a", + { + "dd5bcb0018e922d494759d7c395d02d3" "c8446f8f77abf737685353eb89a1c9eb", + "af3e30f9c095045938151575c3fb9098" "f8cb6274db99b80b1d2012a98ed48f0e", + "25c3005a1cb85de076259839ab7198ab" "9dcbc183e8cb994b727b75be3180769c", + "a1d3078dfa9169503ed9d4491dee4eb2" "8514a5495858096f596e4bcd66b10665", + "5f40d59ec1b03b33738efa60b2255d31" "3477c7f764a41baceff90bf14f92b7cc", + "ac4e95368d99b9eb78b8da8f81ffa795" "8c3c13f8c2388bb73f38576e65b7c446", + "13c4b9c1dfb66579eddd8a280b9f7316" "ddd27820550126698efaadc64b64f66e", + "f08f2e66d28ed143f3a237cf9de73559" "9ea36c525531b880ba124334f57b0b70", + "d5a39e3dfcc50280bac4a6b5aa0dca7d" "370b1c1fe655916d97fd0d47ca1d72b8", + } + } + }; + + RC4_CTX ctx; + uint8_t key[64]; + uint8_t buffer[0x1010]; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + size_t length = strlen(tests[i].key) / 2; + memcpy(key, fromhex(tests[i].key), length); + memset(buffer, 0, sizeof(buffer)); + + rc4_init(&ctx, key, length); + rc4_encrypt(&ctx, buffer, sizeof(buffer)); + + for (size_t j = 0; j < (sizeof(offsets) / sizeof(*offsets)); j++) { + size_t size = strlen(tests[i].vectors[j]) / 2; + ck_assert_mem_eq(&buffer[offsets[j]], fromhex(tests[i].vectors[j]), size); + } + } +} +END_TEST + // define test suite and cases Suite *test_suite(void) { @@ -3472,6 +3684,10 @@ Suite *test_suite(void) tcase_add_test(tc, test_multibyte_address); suite_add_tcase(s, tc); + tc = tcase_create("rc4"); + tcase_add_test(tc, test_rc4_rfc6229); + suite_add_tcase(s, tc); + return s; } From ae126e5ae8c16e738616d745156a4b3d3f71c60c Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Mon, 14 Aug 2017 13:18:22 +0100 Subject: [PATCH 481/627] aestst: Remove #if defined(STATIC_TABLES) This looks like an upstream bug because aes_init() is a no-op when STATIC_TABLES is defined. --- aes/aestst.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/aes/aestst.c b/aes/aestst.c index 15feb8ba2..e34b60728 100644 --- a/aes/aestst.c +++ b/aes/aestst.c @@ -117,9 +117,7 @@ int main(void) f_ectx alge[1]; f_dctx algd[1]; -#if defined(STATIC_TABLES) aes_init(); -#endif message("\nRun tests for the AES algorithm"); From 2b25724f136893e5a8318700358083c3ca5577ac Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Mon, 14 Aug 2017 13:25:17 +0100 Subject: [PATCH 482/627] aestst: Allow compilation with stricter warnings --- aes/aestst | Bin 0 -> 91104 bytes aes/aestst.c | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) create mode 100755 aes/aestst diff --git a/aes/aestst b/aes/aestst new file mode 100755 index 0000000000000000000000000000000000000000..446065d2bb956c6ea7b3f3971f8dd56678725d2f GIT binary patch literal 91104 zcmeFa2Ygi3-t|9|0!au-=%Gn~fPl1N06}VC5&{C!L8SK*iVzSG>Fp4jN)r)K5fBkj zF(RTS6zRQpM9|Qybjbg^_RK&;y!SruzkJ@$|Go1(D`(C=d+)RBnsv_l;T;}bH^#?q zw|PIlwyHLrEeLR@RQFt1(DG@X>b45DKwEWNAzP#^9oPMVH{Y|zyPjg+qo-P%FJ=5d z1t0!A=a|QxZ1Wzych^z(`=?Lc$?hxOqs!rYJ?*)Eda^s+dyG(n_!RLRz2($A zmAmFCcg<7IdpzxFnD^-IpZX>=@$~Q6ql;_$c#q1fPlI#uo%DUPWlsNg9OF*5d5_+5 z4JoH~{->WXPsT=``~Bm%c-kM~IeNNlD;3whL;13$;yRUx>)w07pb~>BlrK@fY{~w8 zN|rJGR{hFbtA0~+C+|2$aHckA1sZBycOK|4`)e!p{DR9j-mcN5uWfbRTE~<>2zcj> zuY9W8m8Q@4ldp%kzdiqN1Ck@2b14I9nV*xc_C7B?|39Qx{fG1-|BxO>dIWg(^EL?) z&n9wS3KV!w`V7)C+cMbhKD!B+kB%Dt^0vMM;``g$w(TF^zGKg}9lP~x+ogT?I9uO- z-FwG(vGwZQt7EUeT<$oiecLYGd$*74KBP0JDy|~^;@kFW-@Ui3ZS5xY+IH&PuXES# z{o_0LYf`UfT%X>Zo3!r`r`%n8_37=&-PWD;`5C+S?jCQeRkwDHnr+LJEc@hJnUdw) zUGrfL_?Z9Gxev2#H-Bw5@A}Nzy?aKjln=SCv;n!g2P)@hD!|9Pf4%!|0ax`&@$6G? zdOJ`0-Ki1gx;NcBjE7 zM{fvNZ%ZwAgQV0#xA+^HuR7m!-c41VKb^{_&;^}qD9-OT=Vx@TCZ10+=SOv}rk!7D z&L?u-Wg6$^6V;??zpGg zcJkav4S(Iq3nMigDPyVHk@S6pDSh>3>=&M|r@Dmp@n1se(4u2ZP8}mCK^7`3&y|$g zl;!(6+7)YEN$HW_-0~ZpPOdVQTdq;HDPL2Hru^VeAFFgNz?3;Ay~?Mi_=URG?=ko^Wu}#}*2$DPg(ztqrD=7o zKT?)u;%su2qTagI;&4yhMLcz@f7G4RU3ZYX?$9wyH8_*Y{ZZP~u$%(}T=#Km>cuW3 z?{+88GRd)%-S+wu`b%uuK;lb981n?V6j+SQc1k5W^| zCJh)(MZ?LPvYK<|FkzCJb6^poQ>8>!?=i$*d-&B#`;yo|NevwEi5I zYg>ET#9C)!N1wgcph?}y{!5|8*vT24=1^rB`BJlmjE}J03eD#-JuOOGn#NA{&#z8Y zyvqWL&&g6hGmcZ1ddAkNr@NF4%{PYOvDsR$*Ik~T(~R>}MwiZTXc}AeG38^EAN$5y z*J6`Xs>RxWiQV%!KAZ|a_f#0H3je9T5mi2*9@~IYv7@UDrvO#bp5WMoDqA^AIq@(x zH6@lV{Nn#6`Rr=W2%2TPxt=QNkFvKu--R6R^V-(tSZhzLbtBe#Ok0ynYF5t=q#E~i z_Ln26ajbRIef>MG$65zcnvx-Q?B)2vbte~EtTg)xcmB{srz44l7CU;qJ*AX#RXj1^ zf|(Kbc$(Y1>Ap=U*G=lv@d|asTItuPIZqsQjpkd)qksK*#JvUa87n7!FR}<7yN*Lt z^QdM~O~nDOgjxYEXN`b_P*=ihehI^aokN11K`v( z5)fsMm%=M2k?T_En3qFrw#uhD(xl1@+~-!S$ZK6fd&fs!;%{BGV5mvx6nV|!)UkzR zmy+X2*vv_sE_c}O;_4-ryL5+*q|{m%b{e>Zg|dV28U7 z@}7Q!(?hK}-$y-1$VnaDkMf;*+i&AL=}PO9ZEy*jtxM=J?sJUuuF0X9(nYn3Y8}-k zs_pt|)@D|y*=PRkd$EoZ=x%7@mgvyL%V00qk`O$>IcbS4*k!~az!EZ#2bIfd&iMIAdJ8KouP_dp}&M~H#7A~!FS$i2X z4Tx%Y4lf>>cv2&nd^yaNr%GMqK9s*)d-SFVHi>iX5{*S&tz-5Fdq#Uh+ree6XLGT$ zk}q<8fh}@1oW0bFMf!mK#67J?p6x{9S+*1V?6NkK7O8hLrJ4G))1O4U)C<~oJE2jS zbGmmW9J3CXBF^GW<}$MoIGPoZP$#Q*ewo@D&fp1Vnwfet$u8&gr&DZB=vP9WaPQ<& zz%$+4bgO37JIT&TW_GP@33XUllgu)62Cueuc~==N-Qitnlw%gO3RoMOPgBd2HNYhN z%S8}nrTpJr1T4>gUIf;K=dJ-w;4_PWQP}HQ1oX{}@c(!fuk7u?fF0e0KQf4dO8iy$T;&j`;< zTKAIAhr66}4S~3nZbCzqQV` zWtCv^?@}8mqwS~tuM6%`F?-3ZT|)(-iC3NwrE_=%mvvN3MIF%zwJN);6ObC*NEMeo z3>NL!>>Uj2M6|WuJK)@K9d{c6`&#!Y;?j)3;wk#|Hw%PS5t_IQF0O7)HEGPLd(zzN zCp2*zw3cStqOHSG&evS-oqjCMywOhY#Bt+eOdcZ?ZYZ3ArGch%w9PX>SKy0iXWP2W zXKZNVW0S!Q)B%%+uXL1}_Hb%QN=185?BzY%@9xx-_ z)Hfz5&8%oDXgdSPf-qBLR?lO~)8DwKv*Q^*O*pe;I&S8V`O>;$W0{@ux9!!JTmG9J z_Pl9}|J#JA?a!Gp?;Nqy=*v3K%srX0p^Pn)Hpn|qf0;Q$8uVVeHrocb5;&bL~{&Y3+`MXW+dj5_}Gk<@XyC~<+v#F1^ z&*hM2&v`bSd+&K?Q1Vsdz>f}txXm+*JPm)-ki`nQhQn}dBGI(=VVa+-DCg7#+~Jx1 zWZi#4d)98Pp)^95s#pUHJ%v~VPqZ#h~@Wm`b{&Ul3AKthycV_&_l30J5Bl@ zJP!AG;h!IeyQF;{Zipwq);140TB-W!0Ul9k^c|;3o`>KX3B^UVsq8MZMtK%8k0)fg z?3`Gd7d~c%dmnyRnnyotn@0-s8Jz7!c`c33q z0?gdO<(%juH-xR9VJRW&sJW(s(5**gdP<(6)28qkFKJ`oYHjn1e(GUYv5Q!fmpuFDFWZK9 zO6)Y=Ke4|c3$v{*g;R;1j?9au3jv&^qtI|rRq!v@fhOZ$u7#iC zs6%Uk1@u2#4C2p!xe%!JKVAfVX~loG2;xo7XBNRAllZ^72)tAHJ z5Gc<-P!5Dc!7WkFHq%v)be2b`x$8S%GOBff@LbXkOe5&_>L_%)oN#sF`U!7SA=$kD-ZI zqn&M*m_Csr>VIT5s{1zry~jM!w`C$t!{+WOGv&3CtgZCz$+T%2(@Y(6wlbPu6;ZKf zj-KiD=-#I@$K2AjrxSOSnbgGnebQE`3I-+3oS7$oCf7Y@`!w|CG2Q)UQ!MXnwps(g z(0MuBWo=9=lo>4gNC(%dgPNSDQ${t^{B-IxXXeEdGoUed#w7heGHo0FSEr4)FHh#| z=>xKR=9o71h@NdX(?&*jXVUJtv{RR6+L$tCZnt~R%x-f}9n+=>aKF(0&u4DGDtczS z{U=j*_&=Dou^&-ELqp*g`y|26+s~y2iUJ?~DXYMIvt9j=y&D`;# zlDWI4A$RXI-qimyQ<9rHdGB)pM#?ig&8~wcZ>f?r+buNlDMfm?lyYLqCk(qzdkaFj ztD=Vg*q-hl?zJwMe5Qk0`KjS$<8+TJbC^bKW3xU~@h3Y~<^s8Su$xxEJYw#0bD1e* zUI&Jd->fV~kKQJ^tOFuS)~Ne|H|-LrERmHI3s#ZTSgF4MgJZ$hXQlF;1GnK5^J+SSa@_`z08fGeSEu*>Qaj4KS2*AH_gG|%d? znq_q*wBl)jJOp>6|oPePalC%RgQlz)A^C+~5ozZ>7*=^TajY zjNNX>W~+Wglq1QCiF8?~T@Ge4rU);TLlaZ1nBwfBn1tdhT+U_lRZD2%ad+`(2QN2C zWB56mo4KsrE(dmV@6u6@^;S$-E5+qFO!F#4S;?V^hpm{(yqu@DNmD&^=&jM^%vh4w z1yt;E2G2KZ={MGcX&>(-T#hYKjy*2NHkX=O-HM5|SWx@uWkS|jR-3xc>86AF{jln@ zg5CW(?CB<_41|j}*p9tXjst8u2hHSXuy+G1rbUAP>bCkNWqDpvm-oqs1nXhWu z+25%Sm*ZlTb&@SlB?)uQ&}o}GZaU|>N5t9_fPX}(&hNg zIoGU*C~LoSu4x5CrC~l{&09&CXvcAD`6|_H&0B2_=jb*2{j|FmYe{3{BrG#!`I#_x zFe6pMYV95(XYuha>l)Vk?BsVAl!56bIxLTkzAeZfKkBVyb+ zmbQj~;=3vPwA_j69Ks&!9l$dynTv9%*c zzk8Y~>w$|L{D!$?kkTkzP)7ThSlYU0vZ+t>QKb?hXS2VI`X--jR-QXeF*bP;ou%j& zlS73FNMR<2M(%f6KW)&!I_|-iZfPb5+1!>FlgG8Qx4;&g$;549M{ZOEG7tY6diJKFl4oA4VK7VRK=T;#22$5HZ~ z^y*0OSR>! zMoa3LU%zMvzQefbrgQSQkZGts>wS@8ZvnzJOB za&`~_9e#6^o5%&zGqa=_i)0cvM>{sKl424no4BCuW)o}eSjp1V8bYI_I;k4>{$@*$ z&<%;?Nif5CI@-F#FRJ{5ht~OM2d=Z(vNK1h!H!hA$t|p(CUDAfdcaY3o@h*q9+tsyg_WyCF@WX1kF{F@uOkLmUrv59u;9q)KuwGfUp(EOCT? zZNZya4U5ZJd<`Ve(;HW5YBUUFr_l>1Dr|epzc+1rz7su1q~oSoO7gkFPSTQ6u0i*PyZXX`9L}XW2Cg zYuy9txWn%;H=#LERw~rHJtm>-${6P=^GmNm;bjs%VpH;#5W>B|8Z=r$rMSESvUT&6 zS&b1cXA?%+ag`MqNtR94174zyGIca7!f-Rh#iOkI=KX_n%zJJIy8l$*=`{jR*rs)? zslAZUd+G{iF{do}_3qyu1yY^j-V4mYI}YF{>zxam%Uy#jl4*UQ8d#F%g`s@rlyJv+ zl(N-3%&MOiuG{R)ShbNxrG9uc<7(BX-gu=sV~WyXOtt!Y!lrK zMgIbGahNANKgTJnO@K8lSRvb$Z#Erqry*6*O+*#r1DT(llV& z(-z!Z&#M*vTNCrIOCZi?KKl1QL4`_Jh#U0GA5#0<3Y9K1$X2RUM9seqM{o|w2$lBr(gH@ZiG0yKS4p%8rQjZ*Z6MzUx|q5 z5Z9+;Pj2ZbUp%72V9FOaZLAXEEaN_ZTCPdA&i(&#`}T2h5gq&V>({wse2{JXGoMu3 zU;j__gal^HkSBAl?3r`t$Xg+@Z1M6XD!v$5zT_*#sugtfjqTQASXAf6aV`7R@6dR7 zbZlI!_?XTOhc_7()1l>CuXaB@ZTHG6ADsB%;i#>PZX|5_^6;v&a}WM_e%6LXk0)+j zadYIf!>d!~?fLe%Nn1a8JZk-lKbJh5v|-VoBX_O3GIQ^mKR!HitkMr}A1IU9cT>@i zdu@qW*5$W+Q=4DTKB`q}#u-u9{btwsqW`{vpA9)#E7NiTl?=82*!haU8u+V+o(;~HJc_fhoqOw(iUzxtc+`_UId zW;ef{bL{JPvrg&1>E)l_+4;(8;a0_Zo6>Mx)n{ ze)vX{Jy!La+sD_gzv)C(|K%E?-ZrLv_ucOg?RsS1TUC}Hc)_{&aJKwwcLkLCcAc;P z#9zx~7=5W?&e;zlbG&=I)WCWNCl7KR8`q=l_76KXOP*H0`wYt`@1 zwdwqSIuH>2&B8%Jb5g zUou53zgH&Hf@{@seSNV=`n6{Y1^+&ycjuJ39edv&AK(Ahl)-~ee$}$}?$ym}toyWj z+wDv1HHo@(^v-MN4n1uBIO*5McXnJDy!pzpw~~L`-TCOP9XlM|${CQ!C z#3kPs{Q0x514oP-o!&~AknO#>Gjf0U?!1qO2Gv?IAbs5*dxtgrrfc4oAGE02b5=uV zyRmg5-$|%hbl{${9rB&3(kJVV!h-_Wmm1)6KCGGZkDPB*_|vCup$8eFO3pdde$w=l zapT8re0$D>?E~Na!38b(#;$@k-KyV&{g``l@n#{k1Q5Y5GO6ZmkyOuhDUASlu2Ia<_SNe!2#O-pd#i zdZd$Iy8V5!=Uv|~JnPQEWnQ`*Te-mLnk6gVX%kWUe$z{HzO$cse@)P}318-TJaR#v z{XdN^arC<>g*Pwzpwcg&O)oun@2S_{JGQsch@_3LP1&;9wea@E0ZUVVAGZ4J^^S>` zA9f24>iU(BZ;v%$;qNSdAyeOFWlJ{x=#>}S%q&v5c0%EDt`S3Pgr4vBs?V8r4YH;7 zem(q_t4pPgb^4Uw*&;swzGm+fKm78?!9yx8vA_A!H`(I~t;yXrbZmuY_DSVhXPH%? zdfs`ZUafV$Q-Rv2yBB@q!LYJTZ}hJ=d`E+jH#fBQ?|7 ze>uLf*tSDgv!(q0Yo2qLZ>GO-?NLbTgT;eaz4v+F??3pV=khV%cKCGa{MI9Wdbi2s zZ%4m2XUXK4S)XeEXMg~*LjZXpfZ`Cqix9vo5P$;$XaNB<6FbV>&Ab{x*z%wZfCCV~ zNeEy)1h5$bxCa5;fB>#S0B0e9DiA<<2;e0MAOZr&1OeoN0MbJM!4N=a2%t9v&>sRA z1Oe2B0BS%0Z6Sar5WpP>;2{L?D+F)>0yqW%?1lh#Kmfl$04pGXg%H5^5Wv?Ez-S0y z0t7Gv0+?7Fc1RB2LWV-00JQZ9|*t+0aSnh3PAuR zA%IB`z<3B?4g~Nn1h4=C_yPh*gaCeo0QN%wryziJ5Wp4);4TDk69Tvb0i1&XDnkG- zLjc7ffcy|Z7zB_T0!Rk|WP|`ZK>&RqfPN6bU1h5zaSOx)n1Od#1 z01_a85fH$62;d9^kO~3Zf&ex`06QUoeGtH52w(^V@FoNh2LW`20GdGnts#Kw5WuSt zKmiD#Cg{kO%>M3;`^I0H#6!qac785Ws8*U>^i<5(3x)0c?N({(t~3Kmd;*fNKyy zPY9q31n?#VFcbo43js8O0HPs)SO~xu0tkTsazX%EA%K@5fL9=Z5)eQH1keitXa@nj z1py3!0A7axnm_8 z2;egaU>pRH00GQ}0N#ZFf*^qO5I`6NkQV}|3IRAFfJg|SC}0_Xz)41xd#Kmg4k zfHxq3x)4AV1kfG=h=Ty$h5!aa08Jr)77)N|5I_wGAP@rZg8;HX053oQRUm-U5WtHN zKrsm5D+pjM1n>m}um}Pe3js`k0Omsg??C`ZAb|Z4z|!0{9*RSPlVv3IU9O0475Kb0C0O5Po)f|6`EjkpG8~{|Ax(8<787k^j?>|MQUl zlaT+TkpD}N|BI0StC0U|kpIV!{|Au&n~?uokpI6S|1Tr|Q<4AIk^f&H|35?ie~0}4 z9{K-1^8X{`|5W7vNaTMd&XB9 z$p3ec|9z1E?UDaqBL6={{(pu1{~7r|1Nr|U^4~)Kk4OHWK>qJT{wE{=Q!$o~N3e=g*IR^)$GwaEY9k^d>k|NF@QTgd;D$p78Q|8>a!?a2QqoG{$p5#H|DBQlJ(2$oyiKGk^g@n|Nlh(KS2J^LH0r`Ix`F|Vve;4_`7x{l2`M(qSpM?A$g8Yw1{&zwCcSHWyK>pW7 z{ zFUbG7$p80{|09t9Q;`1)k^f7P|ErPziOBz8>!VZ{)uV`CkY5-vasH4Eg^u^1mYT|0U#qA>@B3^52g9&w~8Vi~O&J{I8At ze*^j76!||K`Tr*Jza#R$7xMoQ^8X0(e;e|DBl7<$^8Z)l|4rooBjo>L z!6@({(0^Md6^sXE!4yyvxWEQ*5}XIy053vqZ-eQ8|9FON5m*Nbf-2w&s0;MprO5zl zfcs!Qs1JCHW-AFk23;}f=i;4ZigI)QPZ8<-8U zgZ*G3Xa%+djAmPBkOa2b3LjshY8Y}tT_wmDb~CWDW_7%&YS244Vu zCV{nJAJF@wJK!v60sO&g@C}Ft>A-GK9J~Ogf~}w$2n9YM8LR+50$*SUS-?cl6TAZ6 z1(`q;cnx#~$H4_K3)}#^z)o-ttOCD-{$M6p2I4^h@CW!3lmlbI8E_B03{pTIFaVqa zy+JK-9pnOUg1n$8*a$4p2Yd%QfDo`0goB?zZtxH^169GR;1{qL3;NsnEszhK084-qOaSS@Cg1>Hfy^KbybfLjBfurl7PJEm!Eo?7$O*m$bwEZ?0-OUw zz!6@({ zCD0GiQqjD z2l|3o&;UFFm%;boC};z+ff&#nEC!RoM_>$?1`dNSfIgGJTCfiUfji(VXaW4eYVZw+ z2I;_VP#nAfrh=`Y8VChGAQ`LxKLTH12U);G&=b4@-UXRJ6nG7E1;@b!FbmuOyTDFx z4XgscgZ^M9SO(%j0q_U-5|jgD!5MH5ybMx69xwo$0=+>ka2@0VZ-Ts_DA))r&71$11gU%ok{Fea!O91Uy2md7i2B9Jt1wI6&Kq?py%7Q7N zCUAib;3PN?wt*(#Z7>~_0gJ#oP!LoBS3q4b17rX-zBtU2lDCVWy-6S2e0@9#RAAfmS?Vb0r{{AKz0 z^3LUB%d=ISfqZj$r1DGUz03EO=Put`F%0r^b=~%5#?IE1zHS5Q-;IJb*lH`RDS$<+aN{mq#pboAqatzb=njUb12?h3oe8op7=0tG-iYbwQuXqyq z*^0GLJcr^lQBjVQ)OaWRV9QA~&8 z92EDV_yfhzD7HZHBZ|vWe2HRH6mO$A9>sykx0b&ze_6hz{B(Ke@?hni%OjOXE^k(z zt-NCSjPf?+C(2KjZz+#m9HvJb1+?C>B5-vOIIe3&?L(9DzJx`QY;1sTqWoj|@$!nj-n#r%d7tt$<)_LomoF{f zSRTH7UwN^L1&~iKpHrT@JY~fn$fuW=DX&%@yy6oS3m^|!p1I-$AX)me(!MTYj@VcKOqaH;~USPhN2cis6uFEq`7y7>Xm1 zuPy&su^95Q75}051bN?zVNi^P{AmmnpkngY91;wr?MniEXim6cCh+=FM7o)fx z#dIjnL2)07KTr&fVha>MqPQHzmnb$x@ivO%Q5=YTYx(=~m*rc^PnUNt4_4l}JW_e& z@@D1P$}5)7i2N@sKT&?Nd`o%k@{r~6%9oe7DF0Y~yu4zsw=REG-lsfG`Kj{DB>&gEmvvsIjdd~Fh*4#j84x0e^Mm*cQdPD2_uhDTT|*$H|v_d2KrWEFi0^afoo-&O$G9t(k9x+Q_{z#|}Aq%bHC zs)0K|Z`<|q@H21@TnBH0!@vQu0Y9(_=w+c^2!?~1z#q&3=|N^N0-OOC!HeK)FaQLC z(V#fU1#*Mlpe0xU8i7jSAovCp1-}8k;M5PctQfsW)aNpY01v@eKrbD8fNkI>pckaF zh4eDB1=t04gR5XEcmQew*+6;`H5NpJd%y?CVrl>?16fIWVbu_P3aW#t;63mWr~v*1 zYe6D73i5+6pck_@!CtTf1cNN#5@-u%0T;*tHh{%o7|_euPM|f&3HpO}U?g}A90vtJ zF)$5G05L!>a94w@;3Q}RGJs>?G$;dJ0YRWPNCzT8E3gji1Is`M@Gj7c;Im*b_ycSP zFN0oSGB^PAV)%0q2bzIf-~#9jhJfWD0IUInKp{{P z5%dLB!MC6bhy}jjHV6UjK{?PId=JKfWRMrk1HXd1U^d7Ex`QKN3YZQ)1TTQ`;5^s~ znt~$W6qp1)1{TN&eg?mT8lW490v~`9AQY?wO~4NzJ20N$P>yebx4{k26Z8QaL1|zI zUBOG>F*pRi00Y5RFbZq|?|}Q@bx;dj17Cvu;1jR{%moWUKad2z1CPM_pfD&8s)0LT zJ17f21LweX@FqA693UI;1DilWupWeinZO^+0qH?zFan$b7r~3*YcK!=g3+Kj$OUqP z-k>E|02+Zx;2`)06a~M5QeX^d4E6whE`td05PSvR06oAq@Dr#A>VUeS1=t04gR5XE zcmQgGdcX71zaEp*Z>xTVW0}=1X_cfpg(8_MuOMCaZmsh1Jl3+5Cg7&)gUW43EF@R z;21a!%79lu5U35(fk@B_tONVNGSC6M3ub_`U@-UtYz8lbUSKjf0P2I!K^$lXZh;G+ zGZ+Gvg8;Aw3<8BfNstFD0;|9;AO)NN@gN^~75oSiz(mj&R0ZFHE+7{8g4-YjvGDI?ArD7W-q<; z&L58-=lu52p$_%F_~Q3V0|(BTx^-)GzEPt-vbJoge*c|!#$UaEKik)@zkYE_ty)_i zT)UPb>dP-LeY1am*S4R0@+f-6iVFqj&i%RZ!i9Iv_UkwE!=$7)27LG3x?dkX%2Vb2 z_m|f#T)0PE`SLA?RjU^D=bbw~qqlE=ty|f$tr~vz*{wb2&Xv7){d&NeH{X2!i^GTe zcW^iw7t5BdT7aKl@Qh8H8pRYW*!iRN>)VtL4=?ia%$Xkt`TK{KnltCyko4&TBQs|% zpL@iJ4^N#rQ)S1+i-qgI_+t0rUw^&h!hiwuGY1Cd&O3VaycWfa$Cu5Ot7Q4yxl0`H z-TUiREn8lBW5I$43mY}MJ+M-xdfy#9*#4bwzS-HRXwkP%{PtVbHl<3vnPtqFS&JGs z{`31id!)4ZFFRc>UOghB-ER*c<{SLgSDO>xc;oW^9zA}Vylq=d*Pnhm(ywC0SEtvh zb8>dwy8BnQXpu5@*RDE0?B3mTXXl>sL6=JXd`KMpUwQEnkm6({k;^@%G9*kT?GnsX;Q4%uu9XW zeUV|pgwc~?VzzF&a;0d`)vNav$(ptD;*%!_uWi%jO!f>J@_u>j*uZ0_Pgm+xrcAT= zS6-=~H7MwX_iEQZ7Mw0!P;6vm-0D`X&dy)AuJw=m_Vup0Y}wTf9Xc$k`0l$)95ZGt z+;{fu%QprOPB`$#A7v6YZ?4(<<(FSS+N;-h_Q{hceRbeKr@8g(@2&m$=cfTvxt(`lsxHV+Rlv>M|pAQQN2=B9I&4Fu!22H3_s8F9)B}?|JkS9-M z^F@oU_g}SY)2v^9X}B#VrQpXWP7FK{`hX7WsS&{ zF=LL-KmUC6(C@!H#?+|s%kFO7R*#B`T3_^o4_3A;QR1x^LPImXy>jKYB~6+o<%z!(VN0|;O;1dtH|_z?p53Ib>X0W^RBd?A3(A%J%vfSeFO2MFMI2w)Bb z5Dfu*1OZfs0LDWA*&u+65Wp4)AOi$&2?FQ}0X%{LEz`3jqW`0PjNp{ULzH5I{8uAQ%E@1Oar00NOwR zMIeBWA%IW_;9CeF5CSL<0elDnRDl2rLjc_&fE^IPde{l$)9R!dM0@w@zT!sLC zf&gM5fFlsVs}R6R2w*=1kOBeJfdG0!0L37Ha}Ypw2w)=wa0miu3IR-q0CqtDVGuw% z2w)@xa18=*K>%wYfZrg1n-IWb2p|apm(#7fL|eiPauHp5I{u;pg9C^0|FQY0n~y3mO%i2Kmad6 z05c$f1rWe&2w)EcFdPEt0s#zz0KR|#MneEwA%LO~z&;3|G6XOf0yqN!%kVfYuN|ZwTNj1h5DKSONhogaBTK01_a8G7vyb2;g-H z;5!Il5(Ll*0@w=yoQ42aK>+t5fb!UQfPxUfPzYcy1dtyBH~|41hXBSw0AnG5X%IjS2w(#QuoMC~3<3B<0Cor< zGX(G{1ke@&xCa63h5+7$09rr*FG2v{LjV;ZfGiNeHxPgm0{8&}=nDZ@5Wr#xAQ1v6 z00F!Q0YpFmwIP612w)HdFa!da3IW`O07gInIUs9*fPoOeRtR7e1h54Hcn1Qw4*|Rm0n~y3u0a4_LIC?AfKMQR6%fE&2w))u&<_Gg zf&jjQ03JaA??V8EA%OA_Ks5;94g|0r0w@asd!6Ifb|eSI0P^g0`P|b=0E`HA%M&fzz7K73I412>~pC02)C6l^}qF5WqJOKv4+bHwd5<1TY2yXbb`DfdI7sFGBzk5WqtS z;428=4G5qI1h5SP_z4222m#cA0O~>jEg*nh5WsE-;3@>L6ashv0n~&5>OlZb2w*G( z5Dfv`g8+OWfZ-580|=lp1TY^0SONhwgaAH;0IEX(Qz3x&Ab^h`fC>=6pAf)W2p|yx zI0^yehXBGLfK&+JCIqk-0@wio1VaE>Ab?8{KwAi476jme0CGS88z6wi5Wp}9pb7-g z2?A&h0px@L`a=NiAb^n&z-th|aR{IQ1W*hDm<9n%fB<43fGZHdY6u`J1aJ}pXafOc zfB=p`0H+~aFe0s%~c z0H#9#A3^{xKmg+*fb$T*P6(hW1W*J5I0XSrf&e~-04xX~BLwg>1n@fqPy+(!1_4At z03SdAB_M!M2w)`y&;$bb0RqSl0U-Z>LH^%G{$D}<-$wqYBL5E}|4$mM={I7@nzl8jsiu})q{I`(*_mTfsk^f&K|ED1TA0YpukpJHx|Jx$} zqmlmwk^ha6|7Vf^A0qz;Apd_w{#QZ%*G2xvA^(RV|Nlh(k4FA?L;g2J{_jEl-$VYN zLH>V%{O^GLFNXXNK>p7_{>LEyKSKVOM*hEy{0~C@mqPxBApawg|GAO>r;z_UkpK0O z|HG007m)v%k^gy-|1FUJWs(2ok^je$|ErMyZy^5{BL4>>|Gz{2zk~d5g#15&{BMK& z&w~74g#6c=T^sU08Tnrw`Tra8e=zbt5&6F#`9B%?-xc}a5BWbG`9B-^zY_UB7Ww}J z@_!@p|25?QW#s=j8Px3XLy-TQk^gIu|7DQ>za#&XkpDT6|MQUlpCbQV z$p0qD|4PXJ49NdU$p1~q|DMSIBFO*6$p5v-|Ln;BFOmPpkpG>K|MAHGtjPcOkpIER z|5)VzYUKZX21{9lIrzlr?ch5X-&{J(|#uZ8>%L;m+c{$E4>*FpZbLjG4k{x?Vd_ecKELjG?< z{(p@8PeJ}yMgGr3{e+=?}H}ZcJ^1mqZza{ej1?2zR z$p0nC|6a)d;&#@p570}r01yTuKy@$z=xw-O$k}uIRvN=m7D6olvrfA?&gLlVVhP6y zRCIV)YU%>cQ--IehH)M+A~m%L#}*u0a2&+3FUJWSlXRS#ni|2)m&{8|9l^2Nr=)WX zU!Iy8;ETnxwlhu8&*@rZ;*$0K$a|fpnm}XBOrgXiyDNP&nlG6Kmetx&T zr2Ku~PEBo~%pqYhA>nmGGrScr!d5L;rDD#=0!mhS7nn^xjgR-E^j2Uu_siu?reEYlcLO_S4s>kgysdp2}3uLU5P-nUvr2QTkeaXDris(sU>b z_JeTRQ=G9%Q-74|uN895&o|H~C?w*^jiNG;O>GTk%#*m!!w^o|g@jG@sSy%B#kWRC z#ALr3Aw?$nM}?Fgmo6%#!sztA{p=y7qeF@e4v8QSeW1ZL*8j47$Ie}`x;`%5B>%~N zQ+%hY3Hqr1IO=aVIW;w_7D>k^^~XG~{vm&_zvjQHzcN*Br~Zh!si|xIIH65b)c(n8 z|0KVtkRs#M{?X}t=lF#bX`H6rWOmPCFpXWXAT@Pikh{F6|FxgjJ}W4sG<8zW_X>f2_vWj9it40(B5b7q54-*PZ8=- zb^p767U=CcpLU)jQ)E8gW3cD^uHMG;kwvLbrwZ<4PWQofdUAyMCce?fyVtyXE5&m? zkNfhI>wi8@?W3gGp270m#pq&3UO+poj!Q)52ptM~p7Qr-RWW_|2ApXMpg|Dc}f zuXlW}dCrG;uHW;Vdrm!f`Tzdlo$qU&d3&}6g*_8f-gAuc9GiJ3?3n_wp7DPs*;cX8 zn7ls610NjEG<2bO%Z-OYr0pY<42Z(4ND;KyZZ-d-}HW$DQd z$Lvo|zns2oo$Bw8D)7P0ytYwSKcBMU_sz9x)_f(RNUi!!i$=U$(oxb8QKq!x<j4d~9_ zw}?AaC$aT&KJNUNx$4e;`ek>fCp+SqG9Pn)_o@r9mm*WJyuWnxuUp;j;Yo z4M;yl2YWz6GWz)^-C`+(AS=>u}SoA%fZjjzkBa^3iz*9X<+l6B%<|Mp-hwY z)juFzz(ifJr)x=KdVLSLPK}5Cu4f@3@H`2AH`?&m7N}17-5JB*fWYJWZsPC50>3At z-#w*=2M(tje)sh~BCtC3_&w0~B7vLq{h_{>4wQrF_ekF>1j@zqd#vx(gCunPY<8W* z28F63yE$nPv`KgHF()m8Vs+wYf0aYKAme7HvuiB61?^X50d}>vZ_sqr7Hm%9gReH16NgO2H>m^oPxbVesHnUf_!=XFxtoU9DGrjwHPqLf)3G*`8iGHpu=x}z%& zdoKKSB8)D)fU)Xm*=Uw0f8ly{)u`UW=j{4i?ehA+6uv% zMKwF47K~Cgl_vEaZ)z4>NExaMU9I{m*_9qToIie*-QTr1{HmDm=>p#6B>f_;hDrST zf1%rleWkC<%vT$8<^QGmTA$Q(xzwiMW#mc$nQZA#s6ZM1q|2=omgG0&U@2Q1e9}`q zeVI!7x`394QN zCziy3+Qmu9X0wL{G#|sa>^=M20$S*sEqnLgU2FlbtHd>1u-cI)w@y>Kjk|P?VYD)!?E>Xa7oaW#>(5!vO?~-n;eESzv)N|9k#^~sZ;KlTACN9MQlNHEw3R(7AhlXn=xZYQ%xQjAbjtJV?)}lXe_n~7 zeN)*aa^<__x&Hjhc6e$g7EG1h_GGS3N&9DGycLP=@@3(=KL4&F)2ddU%)#z5Hv5VV z-pbCBl&_oTdVUDobn(oShM4k}=enK}^s#^G$Do*A=?Nm=jAzTYtLV;1@Sk^Rn^Jed zJ88zUG~dn5ig+^@Oy}uvJMuR5UiPjZhTCT#b-duoG@YA{_h$Mu?VLO<(aQJMA5-D>olz#eD2@2a%_6zxdu<)K_~`eh^-y@QWu| zns%36Z7u@GxWw?bLIb#Due6)ZtdDsh=V+fBK}ykHTpGh^S&9}N$jMG}kI)I#R}xw4 zi8FV1o4vA5!l|*~MNd`Qi5Y-d0dt;Chwn|AlrNK~-Jbo*q|%nE>QZ^H%=13j*ynz! zw)8K}HT_QYAy?7<4$s*S=B$k8OusEf`#U{njX5i}HBEa=TgLpgEi5CN)Fi^*h(p5& zdkYSYh~pCDM0i@6iQDR9pR4wojXqy>JO0{>zi^@Hr>*!XiV6O`>?QKe%Nz91|63SA zwvx*j%}+p}P2WlsoR>c+=wJS?R|MHgNy-QT-AXOsAOs95^*RS3V0fuy4nn|`QunD< z2$)f_G%1Bapow2Et=AOhRmBdz_}M<-uScX#p`#M1&#LF~)Z^n(r*7%#^nKSHFq;N$2Mq^DW2p zaW>ytN=VL__o~5MS@C5H&wJM$2U_&>oirgaaR#6UEtd`3xC7>lrdv~dJr&! zKdm@5H3!=K>he7#k?Q^8lx(h#@?Q5fxl*~NTwf{I5M2yermrK-*Twoe!F>HlU#FU{ zpXlo%eGS#@+EcU{8|35t>qkXQE@eJ$E&P~y`ixkRabVEvv3N;DqIEYIXxm1rI z{LCHLVdtxHw!)mT`^;Hq-j!wU+1F;j{2JG4WufMb0a||<1EQ$L45qGlW+J2MW2ly* zy}fCcXUmvZY^GUT$!(g|Ud>uejqYZ(Pt&aS$`qK@)2t3^)>3muv&`8V*upfcqi&wL zfN4+&4YKv;+|M?H-g*}F4}3LGT}8Oc$NP9!j`aWEFKG8#F3rIFo3*U53p10aMeAL_ zmHD30y?~W$uJ`j^f3kqJwllgHur6kFFJSZ4y@1VE_X0Lw-3wS>Lz0;h`zgDYN@;Co zKIUyCNBi7IfBD`%WCfQt!|VunTHGQk8gFs-Xy#3lh}jr`Sp07IlzZZ zIYdgPawI_`68vnxvUfboPVd{a?4Er~(2Okq!Ls|$Db!EA>07QjjqxACpLApSBPvX< z@eH*2tC<0sM4xU-4)k3h=H+8@Zsm)~>1+O`+Wc3M5}@hy8KR5iAIyPIfF{;wq$jbv zCs9-EGr^Onjn5}QlkGFrlPGRfqNd$vkteaDJ26mPV*f$2^6W_2=i2O#l?^;6s??-#aY%}2ZgHT zR6>|1f&01>GUcadnai05WXWNFdi$*0FTmT6Y+39X{3qC-v@QG7i)u^`Z)0j_Arr!j zyLif0%jpx&zdb5xua?t2EHCD)oh6e!bNcGxvufm2t8+cgtgN}yoHCqwo;Fxl^X9cX zvNWt>W*@V7a#_>eK5HOkI(IH)mVBELO8;qTU4KtCp}YhUQC-Y!jvuYGzZ%6>51A{%zeWdHFBz%FO~E(?a5FS zFKN@P^bRpY<&WelPd^B9{!4m>-Yln5e@%j&o+fC;K3$kvKIZ^YtR4b z46-oOu7mVXrz8B`qj|cn z?m73Kzv@<1H;xE|EM0u`z4t$ld+xdCzN&h+H;SwXCP=l{e6zEmD@22C6LAM_F1RiNnth6kWQZ)srJ>&BnAm=ZTNBQifE{YcJ(` zyyje<@A1+#!ojgJIV+KvpZ@CEr#GE_$Jy)FDkqg3{-XYTZQYJUvMIeMIV!P^)^lq8 z2nWv?k}s*mz3J)6WoweNf0SH0FFB_rIqCh$Pj7jDa`u{UbJk6J$&=_?<9ersWs0ToJ4-D9!lP_CH*30e&h_JO79`-9sNhM z)w{v=qJGVy??>Ya@}utwc66rQc!m9db6oPLD$$sp`ZvidyOJY6k-o{f?AYYY^u6h) znm>QK^ACw}6PHbN-aan5EZsz6)p|W0Wg7YmaueB^s`A-rCT*)%j;83RK+M zN}%(-L_@lHzVlF`p?RnCjYLE1!^B4=N=weiDNR4s`cm^&=X%OIGaFjl=9ZklV|Z%w z&en9d^Igif6-(^0UpU&xe6lbvIr@TR;ezDouEkd@PA_mSYe>!@bK9DCobEj8o4Y*S z!Zlp8eeP3p)03#$&p1arpCTY#n!9ywsdcIbE^Ca-xwvohE=c~lu*7}k|PXZE&6LfE_pa>gUZ_$?W4fGZErO5~B z(MVfz#JuFDuK8Q}I_JaZIG=MGzEyJmH_?!FW;8Sp&VB06Zs%I(xa2^W(?*~3zMdTL zuA;9xoRdgyn%Dj5kn}XY>r`nXZUa; zG0sU+HLly&)#ZB1ZN11XWHX&^zgJLh$NCJNcj;B4o&1qiuB)eoT;A=?_IC94t77iT zEK3#F_Z7VMQWp;!mv0W3H0SAzyx>$TpYERFk~uU3xw=e3ZhNMfRs97TdtIuhFW=py zKT7#xt~;OYq_>@h)VLG_(`U}IIKd$AOa+76m818a_62Rq<~xBh+-h%NR-e%?U%UQ+L>B{ZxqXi-GJ-s`&$VTwZ z2i7AlrCzbj;I@>=F|*F3{^`vYiy7`e;%3#-(QLl%AgNnTT~9BXol5gvcP`&OwKKbM zs#nNf*;kOHSk+DSiiyT%H(=DrSjlLQ+>VTfEaw29)}P4w5K#xr69&d(-)I=0u*jH#PTqrF?dN zca}Oo*FnWhp=14gTI`!=o!Qjf-PC;1jHYI)YCf&^bLObN_MQ!@mxmbJZNf)4L!uK) zljo8L=%bfE^7PTg#V*bjIuOccW<*@;S>Q&wtBt2fj+(X|4}tK&hcV>wT*pxhw&NMi zM`_Q^7xS51@QG(Jc%(Iwb{%pIjq$<;Jh38PJf4d2Ms3_1FKos$r{VPbA|nG6{amy? z#5b)HAMWJ;e1s8AsMW~+!iQENd%UPfDY`2kYX@}wBoIXQWgof(SzFhts=82fLajg+ z3KHs4WNlq5V!H5%0o>fT$k$1Wj-cP(pxgQrwgbQuhcv@YMRih4Ep~|C@Y}W;*>C&M zDrEmjpvta;u15kvWTAjOfUK=6?mFoDimz)0vQUsvE0MKz#a#zoU-WgYL>3AXY7Mfs zu9Y!=HHoWFlaxXYS%hXntwI*hN-FzHe{Gf`cAv|K(Mi8Z!1SLjf@x7kC z*Ram7VFj|#$$~4kqXf0oPsrLe#C^L$9uuvWbeLLMPL=CW{D2RyV;IE;1x_o1FC$7C z$d80FN+_2SF$M7avBoQP0r8S@3h3fEb#*xfv`45R#Q^(-I8teIbfv(a71|N1oYsUk zKC{wwlcdAgnsObAUl2HG8<1y&5;6hcvqH4mMxF%PHqO*(QK{uXm&d8pa-g12L)8M@ zEJVBIz@8VH-|~z3t4MThlT=!c;=KX~EeGo409Fv%D5jB(nh5Z^2$4f31@Kow ztP@Eht}Um4Hqk8%zMxl&0&Etd7^G>yX8Sa4ilzZuD>QDQCIEP!MOeW`-Yvj?N;*t8 zy$;3Mbit?w<~WrmKcH6$HKZ8ehlFVNGq6FQ##5z++D^THz2PQilOOF-~1m zP66!}YDh7_D}*RfpeqITIiYc*HNn^re74GZc%h`SYN5D7;5090G!n~cAkPY=PAFt8 z4R)YdMMtZ_2exQQL&s9;$l?~32HGIhV|ib?Ek(=nw$v%xEj3^`Nf_S}VI;B1DJ{qe zi<;`ee}>4-d|f%#ls1|uVNKLZh^J&hT(}QvSaF?EObIK7wzEa+9QJIyC2@=5s-WU( zQFWSh(okd}^PtEcA9QfMA}|g2*K89f#@#?i`pdo5hX9WeVwytKhyfWdlwpdtQRNhW z0f4W?l1iwec!R(}r~-LRD5HXwlv6(FuerA6qXa$5U#>070Uj^Jz;Ylb3PmiZ$1?gl zSJGjM8d|PH@dkm@43ib*G?06QGD;}#;8_h|+FvV;7!hfN0_A5=eANY_G~EC_!(W7b zSqf_bmr6QPo0-y;0$b+O^mL+W!2U&OJlSXhfTS##wnAW+3N6$`fSCwU*9q`ZA)5dRLwTHo>RqorE?B*czevlkEotct}#|cfaVbtmyY) zf=uvNRzoq>2)IeoaJzwSiBqZHfqt=)Vt|heQMyT23hetnEoe8eqpSr~3!N=MucXp$ z6z>r@h<6}A5ekAq*9CButgdJ`5vjj{u8C8r-9Rt%S7zf-(+B~tkW|{OX}}6TjkIAW zE7&cPa(`f#z^-juh!gj_kAac!V!=BuDAzf)XRL_&QjXv%Arv ze;Ssv)Pf5H`ii95G89meInbkox=0$?Tj?<)Us@W4pUC&RjWkNIu%Zk24<7kiBdK&R zir4ut$50)LUl&*(5;=a-Kpq#0KIsvK)&yGrfSxZ_gGxJpq5@qlRDIGTS)vkMzd2C9M{dHhpc?%Bps&M?m84dDsY-%ZfhFI$AvOVD7?z006rWcYLfvj zrSE0%RVR|BwLsSi6?(NOz>*LHbAWtLC}RIyxzpSyslX`i5LoNcn_wV!2}M^=6x}R< zyCOtw8^Bijl9=Btk~GZ%x<;tbt3?6!2{AAS$n8QA`%%2dhjl0ZyA>259`)mE5%(ttOp^AC(7N+ptV4@2_@Vhpr4OZsXCyK3N_>@fZyiGBj;;yj1kULqnvyaq?0v^hELd#;6Dc8YxWQ%&sF+&0i~db*n@1y#fb&Rv;f0N@&jt5P$a` zwjAgyzNi({0Mq_549kHWB@|dL#kcwE9-m6;P`pv#v?7?>lm>#oHyb4s8dP-GSJ?kv z(z<|1BMvD349%j_s08||$ZExUuo4kqqrd#InLLtdf&zG^5Vf&-`2*4+lwoX7x$X;6 z+~dPkMY#^e3uO6AD}r^SfqYUZbwZ)~Ng>cL2z3-wwQ)oQ_(Y6ImIK^l*QhNA(kN@( zFs-xhol?9Z45RphzaqkNATJ9=+eU5D-39PiSpdV$0(!YnL(KwsWsFG80(h&xu(CsV zKLX@2p-8hv%X+rhU*=e#4#f`&9CQef2ZR!87Qmxq84NcI=m|m%H4ETbF(MfcaHYSz zqFF$05{fkI87YqSmq0x&pqTU5OoFv4ARiG*Xj%Y><5hTCFiS}AxkR#$N~#ZISo3gx z3mxX}kf|`CTx9Q%IY#rL@F@X_4_TO0@x-@FCP(_-u)gRli!A=2sPb9%KSXekq^HyJ zT{>c0BK_LJzZ*}DCd=zf4Uit|OONrT>jUX}NWn{YzX9pe zv8d%3zm}u@TE_Xcl#U1Ac%Sb$pRY0CI}v;neZCWXz6m~GIR$H1NH_n0tmb7I&E~w{ zaxVCd=R(kaE};>e_uIh*zbRY@TEitYi1U7%xZpR73qi}cgvN2+Zyy)@CUU`U<%zOh zuJxBu9@0%HwhOFRdRp?z6M$SLl#y!iUfRKG8n7)wJJQf-)nIZX;OB&Vv?0Hj6aV>2 zxe??>SvVUjvGMdW4jgNQv#AoN_p8LVR7vqumhw1o_K3vf*O6dn)PwnBLlokJb3K^9 zFG6p5otj8UuMyz?smQgwzFd)B(!2F{PhY1ulkD_;RN}G{2+t8Ev)-UjNC_L0g8U}YGy4td(a%G*CTO@`G@Z3C zn&^1JRzb((qH6)`+Ln5cj*0N#vc^KR-?eR`5t@D~8qc>idV6R**&}v{N}((%dqeF! znE6gUMGR3BG}MbG?L252e1x1r)6EcdK}Un=I>Tbh?tvl54^)tc+*2aoSK0E7igqW{ zr@UL8v@Nw!Ej_u8eydG@$yYbhufpgI6W0+9FkUaGxINcA~P6NTs)gD%BGiIoj-ytP+ODHZ#{5mI_155($qni%@;A zN%zCHPl%1z85{M%n_|yWbx_TMIbW|}77c{Ilvyz6X)&v8dCRiN?6@r8p!yER{Zfp) z^^h@AcIy&)uqb8um(hX)t_1%^o2RG4^{m^wD0rw^Jy4gpiGIMc2Qg6)(j zY45X$maaOLXlism*-opLbSHd+n`%j?<|DnqVILjb87tcD2QwmQ6KjSmpB4Q(tk=rG z8NorZE#>c6Ys2TT4Go0EwBAfe2S39z$zO6V(|v&W{Eo!w zb~{e>=G@F?wXMKmxy&7U0gFKWz69*&ss${cJt=l8?5`_8!5+dIk$c}yR^3WQcadhi zTY7c8h1$YSe<-Y|v{Lu6d6o=kSiy(cA1nVbi!Foz`xD@5#f;A9>=&`{6H>2|qj#tF#g%Ynj zh8VAdH*7hKj;XbXrDNA2vK>IA;``;ltVJw!PIQi?@wqKkVFG2Gzdj}pXiw36;f>DV zjTTGo&ch*f=K(=~txVTF{L}$APwhJok%QdfHC^xj;7{vY*YNsR#QR^XdH61G46}4H=Y@5y3 z825b^tcR~BiqBWaeeTlqbyyv-*`53Mz)}zQ&K5VXOVH9EEDQcVpyq3uUf$foUJoCi zBfef!-PecHefa|r)$s78ukUI4YaHu#YH;eezzVkrENb}1fJKPiZs5NviQV`QYK)Qg zUhh6Ut~&sphKF78bgPN!a*8I5nrq+8IiMacZLi>3I%->y7Q~PR?mc=A@2G`KH;HRk zSW&A7$rin-v%FbzG5x8^8@Ll%57+Jx7q64VUeHH!G3!yk%e%a;MwUCtEV!U7X@!5zqPap6p=C3>?E4s=8tMrMif2L1MqFGKM?vIlA{~gD_|2reKiMfi$YZLPUh)Vn=ouxXMFf6c2pS+1tfapIhJPPp5 zxZ3t4{zDhsAGJ|%0HX3QHwqB__=Q+m3(PIG+9rMfJ;1Y~CYa#N+1Z?)_R|cDLJ;~N|NE9!R~*n0 zV1A;iwi_~Ew;cLz2*HoH8=slf_lNA=P;D77PTlt}nH{V_P_ll#@|04gpRX)Me!j94 z`}xY+QnC+A2}aK}d083#EEL~mt&JjbLY1xSp?hy>e~lu3Q)oGbkeE>mjq&okxqrR8 zjQtiG7jtMJBo<0&tf7S6NpsIybEu{F5NcjN%`Ulux z@k1!BlaLyv{E#X)0>rDZ>V)W}X%>?=ubaQ(wLdSA0=-KM*+=A^Q11G(&L8uj;wNeo=7bS zq#K9&<}7;6v`C?cPE+Lxr4#kH8R-3G{`;m%{>!FH!JDQabCKwnMY8+y#;U7Cev72$ zb=wnAyiQ>KzA8QpGy=I^DEbw2MBzi^IDj__QNM!Dn<7-8_X+hVe#?eXS$91M-xP*= zi@`gcIY9ZYa5O|XXv0 z1)dS|;@IP>@{$!`nk3Bnou%RvZZb7U6npc^DR5005;wS(*@n6uR!z*_ z6STaU&A4RLT(vxK0=nH@Fs6wViZ(zoRx7?ciG{ z{7sc?0l)VO$$|5oLzV#Nply@HI(yTyNY?NxqEM z0nXjNO{l|?pg!Ya!mS41G2fZo+Y){t()3!XW? zW{$QfuXh^>lV)(O_POcjL8@|t>m9;9QCZyHy`<7u0`1`I75=6ezjreUaV(2H;Jj*x zHGuDZmF$N_{pTi=Zu(y_XJ5wB-=KDbCyV)?AHN_qS|Qw;?))d`)m=L zTvbd)0k=LbaMq?kP+3GXK)4&EF5T1=Q!tV2tH^CpovnWy0a z)o=PudOlte*l!tfMc~{PG-o$itk+~pDZb*hfcJKhnW8*f#``XN%yye@61YDZtBL2g z$}-@+TVzi3Ya*FSm4FckC<-u`_B>ftNkn#ueo~eK$^1cH zJ~~`pAURsn21%p*_sQD>7mqZQe$jhJ75=Dvyqr`CHCxs(o0?RPT2&EGDz74*QdmjD zdWNZ875Rs&CuAlJ^BR`7mU|52(Fhfa%-RQ2lWiuf4y#D^?K$tKlUb@AU;!W-1?4>!dKNi|MAUlBiA zy-*Q9Mm>2`B|XO~b#o=WQ7x#5AE(q{CI0a-8yQHdZs#Gu|#@rYky3>w@K>>^K$7!gxB+(zQ}l- zq50$U(#=)$+*<|TrE!X9iK{j-fzQ)pkK5_>6^d@Av{`lZ_4fBsh*fggst_yL*HIYg7gIN62gK$~J7rvV@yc^A zT;wiVzR-246q4>#?!vXp&%Lnq{4k~HWeOfaOO~&87cCVHOBb$G?viB}opAJvx)kYvYvX=6Y3cwph$`XO-K!>Owd0;i?PI zXAiE*wD)9Hf5|H@Sg>SS>v`w9(_5yu%v5f+Gvj5b8nUZngWIuwgWHwK^#n|3s{TSQ z?{x(Ti}khlY=CXLMQ(2JIPYF z^&%p4=JIZ-nC;{i_V7nu^_4u9@Uq$iomt}n%T3%1#M;IDU3t}?TTh0z7mHG9fr5!` zwZ&cP*y%H8***o-G0@SY!;kzZ9i81w8rjJR(~yf@w_|gL`zq6uyD}SYz2_D>lxiss z^m>_gO1*+f*CR)c&KCMrOTN#`ww!xjYqOW>mQr`V)Y4wc^>jApI#mmo)@O?ARZHhU zp7fd2D;UbgY@wLz%ZCas(F)m~3=2rEzsFN8+FdP_ZRzf#qLS-QR>O%v&fUXknQQCdWnMUpFtU09_KrxQ@|)`RDL1he|YV+KGc7kWROB0$1Yh0eXYwWH;Vp4 zp4S7ukfx=PoQs?I2h@Vg%R~f+kdUdpC^1c_aeRAlBZp7%zym+j(vjl z8|P!BEMs3{o)7VIYs=#tjr3xl(`00uLwgo;ZKK4N$9Wqm+AHk7{V3lVk;lFU>5ClT z)`fZj-9;I@ew^QtjsT;i(e{5<oVRV&V=I)vJ_aEZR;b@;J{x0P;wWpbYZh z;dH#nKWT%MkMbT Date: Mon, 14 Aug 2017 13:25:35 +0100 Subject: [PATCH 483/627] Travis CI: Run aestst --- .travis.yml | 1 + Makefile | 3 +++ 2 files changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index 2ebf2ea7d..8f2c902d3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,6 +21,7 @@ install: script: - make + - ./aes/aestst - ./test_check - CK_TIMEOUT_MULTIPLIER=20 valgrind -q --error-exitcode=1 ./test_check - ./test_openssl 1000 diff --git a/Makefile b/Makefile index d83725ebf..78b694677 100644 --- a/Makefile +++ b/Makefile @@ -60,6 +60,9 @@ all: test_check test_openssl test_speed tools libtrezor-crypto.so %.o: %.c %.h options.h $(CC) $(CFLAGS) -o $@ -c $< +aes/aestst: aes/aestst.o aes/aescrypt.o aes/aeskey.o aes/aestab.o + $(CC) $^ -o $@ + test_check: test_check.o $(OBJS) $(CC) test_check.o $(OBJS) $(TESTLIBS) -o test_check From 8503bec3523ec9c7d3a383ac405579b879500bd3 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Mon, 14 Aug 2017 13:26:36 +0100 Subject: [PATCH 484/627] Makefile: Remove obsolete comment --- Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/Makefile b/Makefile index 78b694677..8cb10eb69 100644 --- a/Makefile +++ b/Makefile @@ -23,7 +23,6 @@ CFLAGS += $(OPTFLAGS) \ -Wformat-security \ -Werror -# disable sequence point warning because of AES code CFLAGS += -I. CFLAGS += -Iaes CFLAGS += -Ichacha20poly1305 From c7be1c4694addda2c301ecce61a96935c7f6e5e7 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Tue, 15 Aug 2017 09:43:37 +0100 Subject: [PATCH 485/627] gitignore: Add aestst --- .gitignore | 1 + aes/aestst | Bin 91104 -> 0 bytes 2 files changed, 1 insertion(+) delete mode 100755 aes/aestst diff --git a/.gitignore b/.gitignore index 4ef6dddfd..a826ffce5 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ _attic/ test_openssl test_speed test_check +aes/aestst *.os *.so *.pyc diff --git a/aes/aestst b/aes/aestst deleted file mode 100755 index 446065d2bb956c6ea7b3f3971f8dd56678725d2f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 91104 zcmeFa2Ygi3-t|9|0!au-=%Gn~fPl1N06}VC5&{C!L8SK*iVzSG>Fp4jN)r)K5fBkj zF(RTS6zRQpM9|Qybjbg^_RK&;y!SruzkJ@$|Go1(D`(C=d+)RBnsv_l;T;}bH^#?q zw|PIlwyHLrEeLR@RQFt1(DG@X>b45DKwEWNAzP#^9oPMVH{Y|zyPjg+qo-P%FJ=5d z1t0!A=a|QxZ1Wzych^z(`=?Lc$?hxOqs!rYJ?*)Eda^s+dyG(n_!RLRz2($A zmAmFCcg<7IdpzxFnD^-IpZX>=@$~Q6ql;_$c#q1fPlI#uo%DUPWlsNg9OF*5d5_+5 z4JoH~{->WXPsT=``~Bm%c-kM~IeNNlD;3whL;13$;yRUx>)w07pb~>BlrK@fY{~w8 zN|rJGR{hFbtA0~+C+|2$aHckA1sZBycOK|4`)e!p{DR9j-mcN5uWfbRTE~<>2zcj> zuY9W8m8Q@4ldp%kzdiqN1Ck@2b14I9nV*xc_C7B?|39Qx{fG1-|BxO>dIWg(^EL?) z&n9wS3KV!w`V7)C+cMbhKD!B+kB%Dt^0vMM;``g$w(TF^zGKg}9lP~x+ogT?I9uO- z-FwG(vGwZQt7EUeT<$oiecLYGd$*74KBP0JDy|~^;@kFW-@Ui3ZS5xY+IH&PuXES# z{o_0LYf`UfT%X>Zo3!r`r`%n8_37=&-PWD;`5C+S?jCQeRkwDHnr+LJEc@hJnUdw) zUGrfL_?Z9Gxev2#H-Bw5@A}Nzy?aKjln=SCv;n!g2P)@hD!|9Pf4%!|0ax`&@$6G? zdOJ`0-Ki1gx;NcBjE7 zM{fvNZ%ZwAgQV0#xA+^HuR7m!-c41VKb^{_&;^}qD9-OT=Vx@TCZ10+=SOv}rk!7D z&L?u-Wg6$^6V;??zpGg zcJkav4S(Iq3nMigDPyVHk@S6pDSh>3>=&M|r@Dmp@n1se(4u2ZP8}mCK^7`3&y|$g zl;!(6+7)YEN$HW_-0~ZpPOdVQTdq;HDPL2Hru^VeAFFgNz?3;Ay~?Mi_=URG?=ko^Wu}#}*2$DPg(ztqrD=7o zKT?)u;%su2qTagI;&4yhMLcz@f7G4RU3ZYX?$9wyH8_*Y{ZZP~u$%(}T=#Km>cuW3 z?{+88GRd)%-S+wu`b%uuK;lb981n?V6j+SQc1k5W^| zCJh)(MZ?LPvYK<|FkzCJb6^poQ>8>!?=i$*d-&B#`;yo|NevwEi5I zYg>ET#9C)!N1wgcph?}y{!5|8*vT24=1^rB`BJlmjE}J03eD#-JuOOGn#NA{&#z8Y zyvqWL&&g6hGmcZ1ddAkNr@NF4%{PYOvDsR$*Ik~T(~R>}MwiZTXc}AeG38^EAN$5y z*J6`Xs>RxWiQV%!KAZ|a_f#0H3je9T5mi2*9@~IYv7@UDrvO#bp5WMoDqA^AIq@(x zH6@lV{Nn#6`Rr=W2%2TPxt=QNkFvKu--R6R^V-(tSZhzLbtBe#Ok0ynYF5t=q#E~i z_Ln26ajbRIef>MG$65zcnvx-Q?B)2vbte~EtTg)xcmB{srz44l7CU;qJ*AX#RXj1^ zf|(Kbc$(Y1>Ap=U*G=lv@d|asTItuPIZqsQjpkd)qksK*#JvUa87n7!FR}<7yN*Lt z^QdM~O~nDOgjxYEXN`b_P*=ihehI^aokN11K`v( z5)fsMm%=M2k?T_En3qFrw#uhD(xl1@+~-!S$ZK6fd&fs!;%{BGV5mvx6nV|!)UkzR zmy+X2*vv_sE_c}O;_4-ryL5+*q|{m%b{e>Zg|dV28U7 z@}7Q!(?hK}-$y-1$VnaDkMf;*+i&AL=}PO9ZEy*jtxM=J?sJUuuF0X9(nYn3Y8}-k zs_pt|)@D|y*=PRkd$EoZ=x%7@mgvyL%V00qk`O$>IcbS4*k!~az!EZ#2bIfd&iMIAdJ8KouP_dp}&M~H#7A~!FS$i2X z4Tx%Y4lf>>cv2&nd^yaNr%GMqK9s*)d-SFVHi>iX5{*S&tz-5Fdq#Uh+ree6XLGT$ zk}q<8fh}@1oW0bFMf!mK#67J?p6x{9S+*1V?6NkK7O8hLrJ4G))1O4U)C<~oJE2jS zbGmmW9J3CXBF^GW<}$MoIGPoZP$#Q*ewo@D&fp1Vnwfet$u8&gr&DZB=vP9WaPQ<& zz%$+4bgO37JIT&TW_GP@33XUllgu)62Cueuc~==N-Qitnlw%gO3RoMOPgBd2HNYhN z%S8}nrTpJr1T4>gUIf;K=dJ-w;4_PWQP}HQ1oX{}@c(!fuk7u?fF0e0KQf4dO8iy$T;&j`;< zTKAIAhr66}4S~3nZbCzqQV` zWtCv^?@}8mqwS~tuM6%`F?-3ZT|)(-iC3NwrE_=%mvvN3MIF%zwJN);6ObC*NEMeo z3>NL!>>Uj2M6|WuJK)@K9d{c6`&#!Y;?j)3;wk#|Hw%PS5t_IQF0O7)HEGPLd(zzN zCp2*zw3cStqOHSG&evS-oqjCMywOhY#Bt+eOdcZ?ZYZ3ArGch%w9PX>SKy0iXWP2W zXKZNVW0S!Q)B%%+uXL1}_Hb%QN=185?BzY%@9xx-_ z)Hfz5&8%oDXgdSPf-qBLR?lO~)8DwKv*Q^*O*pe;I&S8V`O>;$W0{@ux9!!JTmG9J z_Pl9}|J#JA?a!Gp?;Nqy=*v3K%srX0p^Pn)Hpn|qf0;Q$8uVVeHrocb5;&bL~{&Y3+`MXW+dj5_}Gk<@XyC~<+v#F1^ z&*hM2&v`bSd+&K?Q1Vsdz>f}txXm+*JPm)-ki`nQhQn}dBGI(=VVa+-DCg7#+~Jx1 zWZi#4d)98Pp)^95s#pUHJ%v~VPqZ#h~@Wm`b{&Ul3AKthycV_&_l30J5Bl@ zJP!AG;h!IeyQF;{Zipwq);140TB-W!0Ul9k^c|;3o`>KX3B^UVsq8MZMtK%8k0)fg z?3`Gd7d~c%dmnyRnnyotn@0-s8Jz7!c`c33q z0?gdO<(%juH-xR9VJRW&sJW(s(5**gdP<(6)28qkFKJ`oYHjn1e(GUYv5Q!fmpuFDFWZK9 zO6)Y=Ke4|c3$v{*g;R;1j?9au3jv&^qtI|rRq!v@fhOZ$u7#iC zs6%Uk1@u2#4C2p!xe%!JKVAfVX~loG2;xo7XBNRAllZ^72)tAHJ z5Gc<-P!5Dc!7WkFHq%v)be2b`x$8S%GOBff@LbXkOe5&_>L_%)oN#sF`U!7SA=$kD-ZI zqn&M*m_Csr>VIT5s{1zry~jM!w`C$t!{+WOGv&3CtgZCz$+T%2(@Y(6wlbPu6;ZKf zj-KiD=-#I@$K2AjrxSOSnbgGnebQE`3I-+3oS7$oCf7Y@`!w|CG2Q)UQ!MXnwps(g z(0MuBWo=9=lo>4gNC(%dgPNSDQ${t^{B-IxXXeEdGoUed#w7heGHo0FSEr4)FHh#| z=>xKR=9o71h@NdX(?&*jXVUJtv{RR6+L$tCZnt~R%x-f}9n+=>aKF(0&u4DGDtczS z{U=j*_&=Dou^&-ELqp*g`y|26+s~y2iUJ?~DXYMIvt9j=y&D`;# zlDWI4A$RXI-qimyQ<9rHdGB)pM#?ig&8~wcZ>f?r+buNlDMfm?lyYLqCk(qzdkaFj ztD=Vg*q-hl?zJwMe5Qk0`KjS$<8+TJbC^bKW3xU~@h3Y~<^s8Su$xxEJYw#0bD1e* zUI&Jd->fV~kKQJ^tOFuS)~Ne|H|-LrERmHI3s#ZTSgF4MgJZ$hXQlF;1GnK5^J+SSa@_`z08fGeSEu*>Qaj4KS2*AH_gG|%d? znq_q*wBl)jJOp>6|oPePalC%RgQlz)A^C+~5ozZ>7*=^TajY zjNNX>W~+Wglq1QCiF8?~T@Ge4rU);TLlaZ1nBwfBn1tdhT+U_lRZD2%ad+`(2QN2C zWB56mo4KsrE(dmV@6u6@^;S$-E5+qFO!F#4S;?V^hpm{(yqu@DNmD&^=&jM^%vh4w z1yt;E2G2KZ={MGcX&>(-T#hYKjy*2NHkX=O-HM5|SWx@uWkS|jR-3xc>86AF{jln@ zg5CW(?CB<_41|j}*p9tXjst8u2hHSXuy+G1rbUAP>bCkNWqDpvm-oqs1nXhWu z+25%Sm*ZlTb&@SlB?)uQ&}o}GZaU|>N5t9_fPX}(&hNg zIoGU*C~LoSu4x5CrC~l{&09&CXvcAD`6|_H&0B2_=jb*2{j|FmYe{3{BrG#!`I#_x zFe6pMYV95(XYuha>l)Vk?BsVAl!56bIxLTkzAeZfKkBVyb+ zmbQj~;=3vPwA_j69Ks&!9l$dynTv9%*c zzk8Y~>w$|L{D!$?kkTkzP)7ThSlYU0vZ+t>QKb?hXS2VI`X--jR-QXeF*bP;ou%j& zlS73FNMR<2M(%f6KW)&!I_|-iZfPb5+1!>FlgG8Qx4;&g$;549M{ZOEG7tY6diJKFl4oA4VK7VRK=T;#22$5HZ~ z^y*0OSR>! zMoa3LU%zMvzQefbrgQSQkZGts>wS@8ZvnzJOB za&`~_9e#6^o5%&zGqa=_i)0cvM>{sKl424no4BCuW)o}eSjp1V8bYI_I;k4>{$@*$ z&<%;?Nif5CI@-F#FRJ{5ht~OM2d=Z(vNK1h!H!hA$t|p(CUDAfdcaY3o@h*q9+tsyg_WyCF@WX1kF{F@uOkLmUrv59u;9q)KuwGfUp(EOCT? zZNZya4U5ZJd<`Ve(;HW5YBUUFr_l>1Dr|epzc+1rz7su1q~oSoO7gkFPSTQ6u0i*PyZXX`9L}XW2Cg zYuy9txWn%;H=#LERw~rHJtm>-${6P=^GmNm;bjs%VpH;#5W>B|8Z=r$rMSESvUT&6 zS&b1cXA?%+ag`MqNtR94174zyGIca7!f-Rh#iOkI=KX_n%zJJIy8l$*=`{jR*rs)? zslAZUd+G{iF{do}_3qyu1yY^j-V4mYI}YF{>zxam%Uy#jl4*UQ8d#F%g`s@rlyJv+ zl(N-3%&MOiuG{R)ShbNxrG9uc<7(BX-gu=sV~WyXOtt!Y!lrK zMgIbGahNANKgTJnO@K8lSRvb$Z#Erqry*6*O+*#r1DT(llV& z(-z!Z&#M*vTNCrIOCZi?KKl1QL4`_Jh#U0GA5#0<3Y9K1$X2RUM9seqM{o|w2$lBr(gH@ZiG0yKS4p%8rQjZ*Z6MzUx|q5 z5Z9+;Pj2ZbUp%72V9FOaZLAXEEaN_ZTCPdA&i(&#`}T2h5gq&V>({wse2{JXGoMu3 zU;j__gal^HkSBAl?3r`t$Xg+@Z1M6XD!v$5zT_*#sugtfjqTQASXAf6aV`7R@6dR7 zbZlI!_?XTOhc_7()1l>CuXaB@ZTHG6ADsB%;i#>PZX|5_^6;v&a}WM_e%6LXk0)+j zadYIf!>d!~?fLe%Nn1a8JZk-lKbJh5v|-VoBX_O3GIQ^mKR!HitkMr}A1IU9cT>@i zdu@qW*5$W+Q=4DTKB`q}#u-u9{btwsqW`{vpA9)#E7NiTl?=82*!haU8u+V+o(;~HJc_fhoqOw(iUzxtc+`_UId zW;ef{bL{JPvrg&1>E)l_+4;(8;a0_Zo6>Mx)n{ ze)vX{Jy!La+sD_gzv)C(|K%E?-ZrLv_ucOg?RsS1TUC}Hc)_{&aJKwwcLkLCcAc;P z#9zx~7=5W?&e;zlbG&=I)WCWNCl7KR8`q=l_76KXOP*H0`wYt`@1 zwdwqSIuH>2&B8%Jb5g zUou53zgH&Hf@{@seSNV=`n6{Y1^+&ycjuJ39edv&AK(Ahl)-~ee$}$}?$ym}toyWj z+wDv1HHo@(^v-MN4n1uBIO*5McXnJDy!pzpw~~L`-TCOP9XlM|${CQ!C z#3kPs{Q0x514oP-o!&~AknO#>Gjf0U?!1qO2Gv?IAbs5*dxtgrrfc4oAGE02b5=uV zyRmg5-$|%hbl{${9rB&3(kJVV!h-_Wmm1)6KCGGZkDPB*_|vCup$8eFO3pdde$w=l zapT8re0$D>?E~Na!38b(#;$@k-KyV&{g``l@n#{k1Q5Y5GO6ZmkyOuhDUASlu2Ia<_SNe!2#O-pd#i zdZd$Iy8V5!=Uv|~JnPQEWnQ`*Te-mLnk6gVX%kWUe$z{HzO$cse@)P}318-TJaR#v z{XdN^arC<>g*Pwzpwcg&O)oun@2S_{JGQsch@_3LP1&;9wea@E0ZUVVAGZ4J^^S>` zA9f24>iU(BZ;v%$;qNSdAyeOFWlJ{x=#>}S%q&v5c0%EDt`S3Pgr4vBs?V8r4YH;7 zem(q_t4pPgb^4Uw*&;swzGm+fKm78?!9yx8vA_A!H`(I~t;yXrbZmuY_DSVhXPH%? zdfs`ZUafV$Q-Rv2yBB@q!LYJTZ}hJ=d`E+jH#fBQ?|7 ze>uLf*tSDgv!(q0Yo2qLZ>GO-?NLbTgT;eaz4v+F??3pV=khV%cKCGa{MI9Wdbi2s zZ%4m2XUXK4S)XeEXMg~*LjZXpfZ`Cqix9vo5P$;$XaNB<6FbV>&Ab{x*z%wZfCCV~ zNeEy)1h5$bxCa5;fB>#S0B0e9DiA<<2;e0MAOZr&1OeoN0MbJM!4N=a2%t9v&>sRA z1Oe2B0BS%0Z6Sar5WpP>;2{L?D+F)>0yqW%?1lh#Kmfl$04pGXg%H5^5Wv?Ez-S0y z0t7Gv0+?7Fc1RB2LWV-00JQZ9|*t+0aSnh3PAuR zA%IB`z<3B?4g~Nn1h4=C_yPh*gaCeo0QN%wryziJ5Wp4);4TDk69Tvb0i1&XDnkG- zLjc7ffcy|Z7zB_T0!Rk|WP|`ZK>&RqfPN6bU1h5zaSOx)n1Od#1 z01_a85fH$62;d9^kO~3Zf&ex`06QUoeGtH52w(^V@FoNh2LW`20GdGnts#Kw5WuSt zKmiD#Cg{kO%>M3;`^I0H#6!qac785Ws8*U>^i<5(3x)0c?N({(t~3Kmd;*fNKyy zPY9q31n?#VFcbo43js8O0HPs)SO~xu0tkTsazX%EA%K@5fL9=Z5)eQH1keitXa@nj z1py3!0A7axnm_8 z2;egaU>pRH00GQ}0N#ZFf*^qO5I`6NkQV}|3IRAFfJg|SC}0_Xz)41xd#Kmg4k zfHxq3x)4AV1kfG=h=Ty$h5!aa08Jr)77)N|5I_wGAP@rZg8;HX053oQRUm-U5WtHN zKrsm5D+pjM1n>m}um}Pe3js`k0Omsg??C`ZAb|Z4z|!0{9*RSPlVv3IU9O0475Kb0C0O5Po)f|6`EjkpG8~{|Ax(8<787k^j?>|MQUl zlaT+TkpD}N|BI0StC0U|kpIV!{|Au&n~?uokpI6S|1Tr|Q<4AIk^f&H|35?ie~0}4 z9{K-1^8X{`|5W7vNaTMd&XB9 z$p3ec|9z1E?UDaqBL6={{(pu1{~7r|1Nr|U^4~)Kk4OHWK>qJT{wE{=Q!$o~N3e=g*IR^)$GwaEY9k^d>k|NF@QTgd;D$p78Q|8>a!?a2QqoG{$p5#H|DBQlJ(2$oyiKGk^g@n|Nlh(KS2J^LH0r`Ix`F|Vve;4_`7x{l2`M(qSpM?A$g8Yw1{&zwCcSHWyK>pW7 z{ zFUbG7$p80{|09t9Q;`1)k^f7P|ErPziOBz8>!VZ{)uV`CkY5-vasH4Eg^u^1mYT|0U#qA>@B3^52g9&w~8Vi~O&J{I8At ze*^j76!||K`Tr*Jza#R$7xMoQ^8X0(e;e|DBl7<$^8Z)l|4rooBjo>L z!6@({(0^Md6^sXE!4yyvxWEQ*5}XIy053vqZ-eQ8|9FON5m*Nbf-2w&s0;MprO5zl zfcs!Qs1JCHW-AFk23;}f=i;4ZigI)QPZ8<-8U zgZ*G3Xa%+djAmPBkOa2b3LjshY8Y}tT_wmDb~CWDW_7%&YS244Vu zCV{nJAJF@wJK!v60sO&g@C}Ft>A-GK9J~Ogf~}w$2n9YM8LR+50$*SUS-?cl6TAZ6 z1(`q;cnx#~$H4_K3)}#^z)o-ttOCD-{$M6p2I4^h@CW!3lmlbI8E_B03{pTIFaVqa zy+JK-9pnOUg1n$8*a$4p2Yd%QfDo`0goB?zZtxH^169GR;1{qL3;NsnEszhK084-qOaSS@Cg1>Hfy^KbybfLjBfurl7PJEm!Eo?7$O*m$bwEZ?0-OUw zz!6@({ zCD0GiQqjD z2l|3o&;UFFm%;boC};z+ff&#nEC!RoM_>$?1`dNSfIgGJTCfiUfji(VXaW4eYVZw+ z2I;_VP#nAfrh=`Y8VChGAQ`LxKLTH12U);G&=b4@-UXRJ6nG7E1;@b!FbmuOyTDFx z4XgscgZ^M9SO(%j0q_U-5|jgD!5MH5ybMx69xwo$0=+>ka2@0VZ-Ts_DA))r&71$11gU%ok{Fea!O91Uy2md7i2B9Jt1wI6&Kq?py%7Q7N zCUAib;3PN?wt*(#Z7>~_0gJ#oP!LoBS3q4b17rX-zBtU2lDCVWy-6S2e0@9#RAAfmS?Vb0r{{AKz0 z^3LUB%d=ISfqZj$r1DGUz03EO=Put`F%0r^b=~%5#?IE1zHS5Q-;IJb*lH`RDS$<+aN{mq#pboAqatzb=njUb12?h3oe8op7=0tG-iYbwQuXqyq z*^0GLJcr^lQBjVQ)OaWRV9QA~&8 z92EDV_yfhzD7HZHBZ|vWe2HRH6mO$A9>sykx0b&ze_6hz{B(Ke@?hni%OjOXE^k(z zt-NCSjPf?+C(2KjZz+#m9HvJb1+?C>B5-vOIIe3&?L(9DzJx`QY;1sTqWoj|@$!nj-n#r%d7tt$<)_LomoF{f zSRTH7UwN^L1&~iKpHrT@JY~fn$fuW=DX&%@yy6oS3m^|!p1I-$AX)me(!MTYj@VcKOqaH;~USPhN2cis6uFEq`7y7>Xm1 zuPy&su^95Q75}051bN?zVNi^P{AmmnpkngY91;wr?MniEXim6cCh+=FM7o)fx z#dIjnL2)07KTr&fVha>MqPQHzmnb$x@ivO%Q5=YTYx(=~m*rc^PnUNt4_4l}JW_e& z@@D1P$}5)7i2N@sKT&?Nd`o%k@{r~6%9oe7DF0Y~yu4zsw=REG-lsfG`Kj{DB>&gEmvvsIjdd~Fh*4#j84x0e^Mm*cQdPD2_uhDTT|*$H|v_d2KrWEFi0^afoo-&O$G9t(k9x+Q_{z#|}Aq%bHC zs)0K|Z`<|q@H21@TnBH0!@vQu0Y9(_=w+c^2!?~1z#q&3=|N^N0-OOC!HeK)FaQLC z(V#fU1#*Mlpe0xU8i7jSAovCp1-}8k;M5PctQfsW)aNpY01v@eKrbD8fNkI>pckaF zh4eDB1=t04gR5XEcmQew*+6;`H5NpJd%y?CVrl>?16fIWVbu_P3aW#t;63mWr~v*1 zYe6D73i5+6pck_@!CtTf1cNN#5@-u%0T;*tHh{%o7|_euPM|f&3HpO}U?g}A90vtJ zF)$5G05L!>a94w@;3Q}RGJs>?G$;dJ0YRWPNCzT8E3gji1Is`M@Gj7c;Im*b_ycSP zFN0oSGB^PAV)%0q2bzIf-~#9jhJfWD0IUInKp{{P z5%dLB!MC6bhy}jjHV6UjK{?PId=JKfWRMrk1HXd1U^d7Ex`QKN3YZQ)1TTQ`;5^s~ znt~$W6qp1)1{TN&eg?mT8lW490v~`9AQY?wO~4NzJ20N$P>yebx4{k26Z8QaL1|zI zUBOG>F*pRi00Y5RFbZq|?|}Q@bx;dj17Cvu;1jR{%moWUKad2z1CPM_pfD&8s)0LT zJ17f21LweX@FqA693UI;1DilWupWeinZO^+0qH?zFan$b7r~3*YcK!=g3+Kj$OUqP z-k>E|02+Zx;2`)06a~M5QeX^d4E6whE`td05PSvR06oAq@Dr#A>VUeS1=t04gR5XE zcmQgGdcX71zaEp*Z>xTVW0}=1X_cfpg(8_MuOMCaZmsh1Jl3+5Cg7&)gUW43EF@R z;21a!%79lu5U35(fk@B_tONVNGSC6M3ub_`U@-UtYz8lbUSKjf0P2I!K^$lXZh;G+ zGZ+Gvg8;Aw3<8BfNstFD0;|9;AO)NN@gN^~75oSiz(mj&R0ZFHE+7{8g4-YjvGDI?ArD7W-q<; z&L58-=lu52p$_%F_~Q3V0|(BTx^-)GzEPt-vbJoge*c|!#$UaEKik)@zkYE_ty)_i zT)UPb>dP-LeY1am*S4R0@+f-6iVFqj&i%RZ!i9Iv_UkwE!=$7)27LG3x?dkX%2Vb2 z_m|f#T)0PE`SLA?RjU^D=bbw~qqlE=ty|f$tr~vz*{wb2&Xv7){d&NeH{X2!i^GTe zcW^iw7t5BdT7aKl@Qh8H8pRYW*!iRN>)VtL4=?ia%$Xkt`TK{KnltCyko4&TBQs|% zpL@iJ4^N#rQ)S1+i-qgI_+t0rUw^&h!hiwuGY1Cd&O3VaycWfa$Cu5Ot7Q4yxl0`H z-TUiREn8lBW5I$43mY}MJ+M-xdfy#9*#4bwzS-HRXwkP%{PtVbHl<3vnPtqFS&JGs z{`31id!)4ZFFRc>UOghB-ER*c<{SLgSDO>xc;oW^9zA}Vylq=d*Pnhm(ywC0SEtvh zb8>dwy8BnQXpu5@*RDE0?B3mTXXl>sL6=JXd`KMpUwQEnkm6({k;^@%G9*kT?GnsX;Q4%uu9XW zeUV|pgwc~?VzzF&a;0d`)vNav$(ptD;*%!_uWi%jO!f>J@_u>j*uZ0_Pgm+xrcAT= zS6-=~H7MwX_iEQZ7Mw0!P;6vm-0D`X&dy)AuJw=m_Vup0Y}wTf9Xc$k`0l$)95ZGt z+;{fu%QprOPB`$#A7v6YZ?4(<<(FSS+N;-h_Q{hceRbeKr@8g(@2&m$=cfTvxt(`lsxHV+Rlv>M|pAQQN2=B9I&4Fu!22H3_s8F9)B}?|JkS9-M z^F@oU_g}SY)2v^9X}B#VrQpXWP7FK{`hX7WsS&{ zF=LL-KmUC6(C@!H#?+|s%kFO7R*#B`T3_^o4_3A;QR1x^LPImXy>jKYB~6+o<%z!(VN0|;O;1dtH|_z?p53Ib>X0W^RBd?A3(A%J%vfSeFO2MFMI2w)Bb z5Dfu*1OZfs0LDWA*&u+65Wp4)AOi$&2?FQ}0X%{LEz`3jqW`0PjNp{ULzH5I{8uAQ%E@1Oar00NOwR zMIeBWA%IW_;9CeF5CSL<0elDnRDl2rLjc_&fE^IPde{l$)9R!dM0@w@zT!sLC zf&gM5fFlsVs}R6R2w*=1kOBeJfdG0!0L37Ha}Ypw2w)=wa0miu3IR-q0CqtDVGuw% z2w)@xa18=*K>%wYfZrg1n-IWb2p|apm(#7fL|eiPauHp5I{u;pg9C^0|FQY0n~y3mO%i2Kmad6 z05c$f1rWe&2w)EcFdPEt0s#zz0KR|#MneEwA%LO~z&;3|G6XOf0yqN!%kVfYuN|ZwTNj1h5DKSONhogaBTK01_a8G7vyb2;g-H z;5!Il5(Ll*0@w=yoQ42aK>+t5fb!UQfPxUfPzYcy1dtyBH~|41hXBSw0AnG5X%IjS2w(#QuoMC~3<3B<0Cor< zGX(G{1ke@&xCa63h5+7$09rr*FG2v{LjV;ZfGiNeHxPgm0{8&}=nDZ@5Wr#xAQ1v6 z00F!Q0YpFmwIP612w)HdFa!da3IW`O07gInIUs9*fPoOeRtR7e1h54Hcn1Qw4*|Rm0n~y3u0a4_LIC?AfKMQR6%fE&2w))u&<_Gg zf&jjQ03JaA??V8EA%OA_Ks5;94g|0r0w@asd!6Ifb|eSI0P^g0`P|b=0E`HA%M&fzz7K73I412>~pC02)C6l^}qF5WqJOKv4+bHwd5<1TY2yXbb`DfdI7sFGBzk5WqtS z;428=4G5qI1h5SP_z4222m#cA0O~>jEg*nh5WsE-;3@>L6ashv0n~&5>OlZb2w*G( z5Dfv`g8+OWfZ-580|=lp1TY^0SONhwgaAH;0IEX(Qz3x&Ab^h`fC>=6pAf)W2p|yx zI0^yehXBGLfK&+JCIqk-0@wio1VaE>Ab?8{KwAi476jme0CGS88z6wi5Wp}9pb7-g z2?A&h0px@L`a=NiAb^n&z-th|aR{IQ1W*hDm<9n%fB<43fGZHdY6u`J1aJ}pXafOc zfB=p`0H+~aFe0s%~c z0H#9#A3^{xKmg+*fb$T*P6(hW1W*J5I0XSrf&e~-04xX~BLwg>1n@fqPy+(!1_4At z03SdAB_M!M2w)`y&;$bb0RqSl0U-Z>LH^%G{$D}<-$wqYBL5E}|4$mM={I7@nzl8jsiu})q{I`(*_mTfsk^f&K|ED1TA0YpukpJHx|Jx$} zqmlmwk^ha6|7Vf^A0qz;Apd_w{#QZ%*G2xvA^(RV|Nlh(k4FA?L;g2J{_jEl-$VYN zLH>V%{O^GLFNXXNK>p7_{>LEyKSKVOM*hEy{0~C@mqPxBApawg|GAO>r;z_UkpK0O z|HG007m)v%k^gy-|1FUJWs(2ok^je$|ErMyZy^5{BL4>>|Gz{2zk~d5g#15&{BMK& z&w~74g#6c=T^sU08Tnrw`Tra8e=zbt5&6F#`9B%?-xc}a5BWbG`9B-^zY_UB7Ww}J z@_!@p|25?QW#s=j8Px3XLy-TQk^gIu|7DQ>za#&XkpDT6|MQUlpCbQV z$p0qD|4PXJ49NdU$p1~q|DMSIBFO*6$p5v-|Ln;BFOmPpkpG>K|MAHGtjPcOkpIER z|5)VzYUKZX21{9lIrzlr?ch5X-&{J(|#uZ8>%L;m+c{$E4>*FpZbLjG4k{x?Vd_ecKELjG?< z{(p@8PeJ}yMgGr3{e+=?}H}ZcJ^1mqZza{ej1?2zR z$p0nC|6a)d;&#@p570}r01yTuKy@$z=xw-O$k}uIRvN=m7D6olvrfA?&gLlVVhP6y zRCIV)YU%>cQ--IehH)M+A~m%L#}*u0a2&+3FUJWSlXRS#ni|2)m&{8|9l^2Nr=)WX zU!Iy8;ETnxwlhu8&*@rZ;*$0K$a|fpnm}XBOrgXiyDNP&nlG6Kmetx&T zr2Ku~PEBo~%pqYhA>nmGGrScr!d5L;rDD#=0!mhS7nn^xjgR-E^j2Uu_siu?reEYlcLO_S4s>kgysdp2}3uLU5P-nUvr2QTkeaXDris(sU>b z_JeTRQ=G9%Q-74|uN895&o|H~C?w*^jiNG;O>GTk%#*m!!w^o|g@jG@sSy%B#kWRC z#ALr3Aw?$nM}?Fgmo6%#!sztA{p=y7qeF@e4v8QSeW1ZL*8j47$Ie}`x;`%5B>%~N zQ+%hY3Hqr1IO=aVIW;w_7D>k^^~XG~{vm&_zvjQHzcN*Br~Zh!si|xIIH65b)c(n8 z|0KVtkRs#M{?X}t=lF#bX`H6rWOmPCFpXWXAT@Pikh{F6|FxgjJ}W4sG<8zW_X>f2_vWj9it40(B5b7q54-*PZ8=- zb^p767U=CcpLU)jQ)E8gW3cD^uHMG;kwvLbrwZ<4PWQofdUAyMCce?fyVtyXE5&m? zkNfhI>wi8@?W3gGp270m#pq&3UO+poj!Q)52ptM~p7Qr-RWW_|2ApXMpg|Dc}f zuXlW}dCrG;uHW;Vdrm!f`Tzdlo$qU&d3&}6g*_8f-gAuc9GiJ3?3n_wp7DPs*;cX8 zn7ls610NjEG<2bO%Z-OYr0pY<42Z(4ND;KyZZ-d-}HW$DQd z$Lvo|zns2oo$Bw8D)7P0ytYwSKcBMU_sz9x)_f(RNUi!!i$=U$(oxb8QKq!x<j4d~9_ zw}?AaC$aT&KJNUNx$4e;`ek>fCp+SqG9Pn)_o@r9mm*WJyuWnxuUp;j;Yo z4M;yl2YWz6GWz)^-C`+(AS=>u}SoA%fZjjzkBa^3iz*9X<+l6B%<|Mp-hwY z)juFzz(ifJr)x=KdVLSLPK}5Cu4f@3@H`2AH`?&m7N}17-5JB*fWYJWZsPC50>3At z-#w*=2M(tje)sh~BCtC3_&w0~B7vLq{h_{>4wQrF_ekF>1j@zqd#vx(gCunPY<8W* z28F63yE$nPv`KgHF()m8Vs+wYf0aYKAme7HvuiB61?^X50d}>vZ_sqr7Hm%9gReH16NgO2H>m^oPxbVesHnUf_!=XFxtoU9DGrjwHPqLf)3G*`8iGHpu=x}z%& zdoKKSB8)D)fU)Xm*=Uw0f8ly{)u`UW=j{4i?ehA+6uv% zMKwF47K~Cgl_vEaZ)z4>NExaMU9I{m*_9qToIie*-QTr1{HmDm=>p#6B>f_;hDrST zf1%rleWkC<%vT$8<^QGmTA$Q(xzwiMW#mc$nQZA#s6ZM1q|2=omgG0&U@2Q1e9}`q zeVI!7x`394QN zCziy3+Qmu9X0wL{G#|sa>^=M20$S*sEqnLgU2FlbtHd>1u-cI)w@y>Kjk|P?VYD)!?E>Xa7oaW#>(5!vO?~-n;eESzv)N|9k#^~sZ;KlTACN9MQlNHEw3R(7AhlXn=xZYQ%xQjAbjtJV?)}lXe_n~7 zeN)*aa^<__x&Hjhc6e$g7EG1h_GGS3N&9DGycLP=@@3(=KL4&F)2ddU%)#z5Hv5VV z-pbCBl&_oTdVUDobn(oShM4k}=enK}^s#^G$Do*A=?Nm=jAzTYtLV;1@Sk^Rn^Jed zJ88zUG~dn5ig+^@Oy}uvJMuR5UiPjZhTCT#b-duoG@YA{_h$Mu?VLO<(aQJMA5-D>olz#eD2@2a%_6zxdu<)K_~`eh^-y@QWu| zns%36Z7u@GxWw?bLIb#Due6)ZtdDsh=V+fBK}ykHTpGh^S&9}N$jMG}kI)I#R}xw4 zi8FV1o4vA5!l|*~MNd`Qi5Y-d0dt;Chwn|AlrNK~-Jbo*q|%nE>QZ^H%=13j*ynz! zw)8K}HT_QYAy?7<4$s*S=B$k8OusEf`#U{njX5i}HBEa=TgLpgEi5CN)Fi^*h(p5& zdkYSYh~pCDM0i@6iQDR9pR4wojXqy>JO0{>zi^@Hr>*!XiV6O`>?QKe%Nz91|63SA zwvx*j%}+p}P2WlsoR>c+=wJS?R|MHgNy-QT-AXOsAOs95^*RS3V0fuy4nn|`QunD< z2$)f_G%1Bapow2Et=AOhRmBdz_}M<-uScX#p`#M1&#LF~)Z^n(r*7%#^nKSHFq;N$2Mq^DW2p zaW>ytN=VL__o~5MS@C5H&wJM$2U_&>oirgaaR#6UEtd`3xC7>lrdv~dJr&! zKdm@5H3!=K>he7#k?Q^8lx(h#@?Q5fxl*~NTwf{I5M2yermrK-*Twoe!F>HlU#FU{ zpXlo%eGS#@+EcU{8|35t>qkXQE@eJ$E&P~y`ixkRabVEvv3N;DqIEYIXxm1rI z{LCHLVdtxHw!)mT`^;Hq-j!wU+1F;j{2JG4WufMb0a||<1EQ$L45qGlW+J2MW2ly* zy}fCcXUmvZY^GUT$!(g|Ud>uejqYZ(Pt&aS$`qK@)2t3^)>3muv&`8V*upfcqi&wL zfN4+&4YKv;+|M?H-g*}F4}3LGT}8Oc$NP9!j`aWEFKG8#F3rIFo3*U53p10aMeAL_ zmHD30y?~W$uJ`j^f3kqJwllgHur6kFFJSZ4y@1VE_X0Lw-3wS>Lz0;h`zgDYN@;Co zKIUyCNBi7IfBD`%WCfQt!|VunTHGQk8gFs-Xy#3lh}jr`Sp07IlzZZ zIYdgPawI_`68vnxvUfboPVd{a?4Er~(2Okq!Ls|$Db!EA>07QjjqxACpLApSBPvX< z@eH*2tC<0sM4xU-4)k3h=H+8@Zsm)~>1+O`+Wc3M5}@hy8KR5iAIyPIfF{;wq$jbv zCs9-EGr^Onjn5}QlkGFrlPGRfqNd$vkteaDJ26mPV*f$2^6W_2=i2O#l?^;6s??-#aY%}2ZgHT zR6>|1f&01>GUcadnai05WXWNFdi$*0FTmT6Y+39X{3qC-v@QG7i)u^`Z)0j_Arr!j zyLif0%jpx&zdb5xua?t2EHCD)oh6e!bNcGxvufm2t8+cgtgN}yoHCqwo;Fxl^X9cX zvNWt>W*@V7a#_>eK5HOkI(IH)mVBELO8;qTU4KtCp}YhUQC-Y!jvuYGzZ%6>51A{%zeWdHFBz%FO~E(?a5FS zFKN@P^bRpY<&WelPd^B9{!4m>-Yln5e@%j&o+fC;K3$kvKIZ^YtR4b z46-oOu7mVXrz8B`qj|cn z?m73Kzv@<1H;xE|EM0u`z4t$ld+xdCzN&h+H;SwXCP=l{e6zEmD@22C6LAM_F1RiNnth6kWQZ)srJ>&BnAm=ZTNBQifE{YcJ(` zyyje<@A1+#!ojgJIV+KvpZ@CEr#GE_$Jy)FDkqg3{-XYTZQYJUvMIeMIV!P^)^lq8 z2nWv?k}s*mz3J)6WoweNf0SH0FFB_rIqCh$Pj7jDa`u{UbJk6J$&=_?<9ersWs0ToJ4-D9!lP_CH*30e&h_JO79`-9sNhM z)w{v=qJGVy??>Ya@}utwc66rQc!m9db6oPLD$$sp`ZvidyOJY6k-o{f?AYYY^u6h) znm>QK^ACw}6PHbN-aan5EZsz6)p|W0Wg7YmaueB^s`A-rCT*)%j;83RK+M zN}%(-L_@lHzVlF`p?RnCjYLE1!^B4=N=weiDNR4s`cm^&=X%OIGaFjl=9ZklV|Z%w z&en9d^Igif6-(^0UpU&xe6lbvIr@TR;ezDouEkd@PA_mSYe>!@bK9DCobEj8o4Y*S z!Zlp8eeP3p)03#$&p1arpCTY#n!9ywsdcIbE^Ca-xwvohE=c~lu*7}k|PXZE&6LfE_pa>gUZ_$?W4fGZErO5~B z(MVfz#JuFDuK8Q}I_JaZIG=MGzEyJmH_?!FW;8Sp&VB06Zs%I(xa2^W(?*~3zMdTL zuA;9xoRdgyn%Dj5kn}XY>r`nXZUa; zG0sU+HLly&)#ZB1ZN11XWHX&^zgJLh$NCJNcj;B4o&1qiuB)eoT;A=?_IC94t77iT zEK3#F_Z7VMQWp;!mv0W3H0SAzyx>$TpYERFk~uU3xw=e3ZhNMfRs97TdtIuhFW=py zKT7#xt~;OYq_>@h)VLG_(`U}IIKd$AOa+76m818a_62Rq<~xBh+-h%NR-e%?U%UQ+L>B{ZxqXi-GJ-s`&$VTwZ z2i7AlrCzbj;I@>=F|*F3{^`vYiy7`e;%3#-(QLl%AgNnTT~9BXol5gvcP`&OwKKbM zs#nNf*;kOHSk+DSiiyT%H(=DrSjlLQ+>VTfEaw29)}P4w5K#xr69&d(-)I=0u*jH#PTqrF?dN zca}Oo*FnWhp=14gTI`!=o!Qjf-PC;1jHYI)YCf&^bLObN_MQ!@mxmbJZNf)4L!uK) zljo8L=%bfE^7PTg#V*bjIuOccW<*@;S>Q&wtBt2fj+(X|4}tK&hcV>wT*pxhw&NMi zM`_Q^7xS51@QG(Jc%(Iwb{%pIjq$<;Jh38PJf4d2Ms3_1FKos$r{VPbA|nG6{amy? z#5b)HAMWJ;e1s8AsMW~+!iQENd%UPfDY`2kYX@}wBoIXQWgof(SzFhts=82fLajg+ z3KHs4WNlq5V!H5%0o>fT$k$1Wj-cP(pxgQrwgbQuhcv@YMRih4Ep~|C@Y}W;*>C&M zDrEmjpvta;u15kvWTAjOfUK=6?mFoDimz)0vQUsvE0MKz#a#zoU-WgYL>3AXY7Mfs zu9Y!=HHoWFlaxXYS%hXntwI*hN-FzHe{Gf`cAv|K(Mi8Z!1SLjf@x7kC z*Ram7VFj|#$$~4kqXf0oPsrLe#C^L$9uuvWbeLLMPL=CW{D2RyV;IE;1x_o1FC$7C z$d80FN+_2SF$M7avBoQP0r8S@3h3fEb#*xfv`45R#Q^(-I8teIbfv(a71|N1oYsUk zKC{wwlcdAgnsObAUl2HG8<1y&5;6hcvqH4mMxF%PHqO*(QK{uXm&d8pa-g12L)8M@ zEJVBIz@8VH-|~z3t4MThlT=!c;=KX~EeGo409Fv%D5jB(nh5Z^2$4f31@Kow ztP@Eht}Um4Hqk8%zMxl&0&Etd7^G>yX8Sa4ilzZuD>QDQCIEP!MOeW`-Yvj?N;*t8 zy$;3Mbit?w<~WrmKcH6$HKZ8ehlFVNGq6FQ##5z++D^THz2PQilOOF-~1m zP66!}YDh7_D}*RfpeqITIiYc*HNn^re74GZc%h`SYN5D7;5090G!n~cAkPY=PAFt8 z4R)YdMMtZ_2exQQL&s9;$l?~32HGIhV|ib?Ek(=nw$v%xEj3^`Nf_S}VI;B1DJ{qe zi<;`ee}>4-d|f%#ls1|uVNKLZh^J&hT(}QvSaF?EObIK7wzEa+9QJIyC2@=5s-WU( zQFWSh(okd}^PtEcA9QfMA}|g2*K89f#@#?i`pdo5hX9WeVwytKhyfWdlwpdtQRNhW z0f4W?l1iwec!R(}r~-LRD5HXwlv6(FuerA6qXa$5U#>070Uj^Jz;Ylb3PmiZ$1?gl zSJGjM8d|PH@dkm@43ib*G?06QGD;}#;8_h|+FvV;7!hfN0_A5=eANY_G~EC_!(W7b zSqf_bmr6QPo0-y;0$b+O^mL+W!2U&OJlSXhfTS##wnAW+3N6$`fSCwU*9q`ZA)5dRLwTHo>RqorE?B*czevlkEotct}#|cfaVbtmyY) zf=uvNRzoq>2)IeoaJzwSiBqZHfqt=)Vt|heQMyT23hetnEoe8eqpSr~3!N=MucXp$ z6z>r@h<6}A5ekAq*9CButgdJ`5vjj{u8C8r-9Rt%S7zf-(+B~tkW|{OX}}6TjkIAW zE7&cPa(`f#z^-juh!gj_kAac!V!=BuDAzf)XRL_&QjXv%Arv ze;Ssv)Pf5H`ii95G89meInbkox=0$?Tj?<)Us@W4pUC&RjWkNIu%Zk24<7kiBdK&R zir4ut$50)LUl&*(5;=a-Kpq#0KIsvK)&yGrfSxZ_gGxJpq5@qlRDIGTS)vkMzd2C9M{dHhpc?%Bps&M?m84dDsY-%ZfhFI$AvOVD7?z006rWcYLfvj zrSE0%RVR|BwLsSi6?(NOz>*LHbAWtLC}RIyxzpSyslX`i5LoNcn_wV!2}M^=6x}R< zyCOtw8^Bijl9=Btk~GZ%x<;tbt3?6!2{AAS$n8QA`%%2dhjl0ZyA>259`)mE5%(ttOp^AC(7N+ptV4@2_@Vhpr4OZsXCyK3N_>@fZyiGBj;;yj1kULqnvyaq?0v^hELd#;6Dc8YxWQ%&sF+&0i~db*n@1y#fb&Rv;f0N@&jt5P$a` zwjAgyzNi({0Mq_549kHWB@|dL#kcwE9-m6;P`pv#v?7?>lm>#oHyb4s8dP-GSJ?kv z(z<|1BMvD349%j_s08||$ZExUuo4kqqrd#InLLtdf&zG^5Vf&-`2*4+lwoX7x$X;6 z+~dPkMY#^e3uO6AD}r^SfqYUZbwZ)~Ng>cL2z3-wwQ)oQ_(Y6ImIK^l*QhNA(kN@( zFs-xhol?9Z45RphzaqkNATJ9=+eU5D-39PiSpdV$0(!YnL(KwsWsFG80(h&xu(CsV zKLX@2p-8hv%X+rhU*=e#4#f`&9CQef2ZR!87Qmxq84NcI=m|m%H4ETbF(MfcaHYSz zqFF$05{fkI87YqSmq0x&pqTU5OoFv4ARiG*Xj%Y><5hTCFiS}AxkR#$N~#ZISo3gx z3mxX}kf|`CTx9Q%IY#rL@F@X_4_TO0@x-@FCP(_-u)gRli!A=2sPb9%KSXekq^HyJ zT{>c0BK_LJzZ*}DCd=zf4Uit|OONrT>jUX}NWn{YzX9pe zv8d%3zm}u@TE_Xcl#U1Ac%Sb$pRY0CI}v;neZCWXz6m~GIR$H1NH_n0tmb7I&E~w{ zaxVCd=R(kaE};>e_uIh*zbRY@TEitYi1U7%xZpR73qi}cgvN2+Zyy)@CUU`U<%zOh zuJxBu9@0%HwhOFRdRp?z6M$SLl#y!iUfRKG8n7)wJJQf-)nIZX;OB&Vv?0Hj6aV>2 zxe??>SvVUjvGMdW4jgNQv#AoN_p8LVR7vqumhw1o_K3vf*O6dn)PwnBLlokJb3K^9 zFG6p5otj8UuMyz?smQgwzFd)B(!2F{PhY1ulkD_;RN}G{2+t8Ev)-UjNC_L0g8U}YGy4td(a%G*CTO@`G@Z3C zn&^1JRzb((qH6)`+Ln5cj*0N#vc^KR-?eR`5t@D~8qc>idV6R**&}v{N}((%dqeF! znE6gUMGR3BG}MbG?L252e1x1r)6EcdK}Un=I>Tbh?tvl54^)tc+*2aoSK0E7igqW{ zr@UL8v@Nw!Ej_u8eydG@$yYbhufpgI6W0+9FkUaGxINcA~P6NTs)gD%BGiIoj-ytP+ODHZ#{5mI_155($qni%@;A zN%zCHPl%1z85{M%n_|yWbx_TMIbW|}77c{Ilvyz6X)&v8dCRiN?6@r8p!yER{Zfp) z^^h@AcIy&)uqb8um(hX)t_1%^o2RG4^{m^wD0rw^Jy4gpiGIMc2Qg6)(j zY45X$maaOLXlism*-opLbSHd+n`%j?<|DnqVILjb87tcD2QwmQ6KjSmpB4Q(tk=rG z8NorZE#>c6Ys2TT4Go0EwBAfe2S39z$zO6V(|v&W{Eo!w zb~{e>=G@F?wXMKmxy&7U0gFKWz69*&ss${cJt=l8?5`_8!5+dIk$c}yR^3WQcadhi zTY7c8h1$YSe<-Y|v{Lu6d6o=kSiy(cA1nVbi!Foz`xD@5#f;A9>=&`{6H>2|qj#tF#g%Ynj zh8VAdH*7hKj;XbXrDNA2vK>IA;``;ltVJw!PIQi?@wqKkVFG2Gzdj}pXiw36;f>DV zjTTGo&ch*f=K(=~txVTF{L}$APwhJok%QdfHC^xj;7{vY*YNsR#QR^XdH61G46}4H=Y@5y3 z825b^tcR~BiqBWaeeTlqbyyv-*`53Mz)}zQ&K5VXOVH9EEDQcVpyq3uUf$foUJoCi zBfef!-PecHefa|r)$s78ukUI4YaHu#YH;eezzVkrENb}1fJKPiZs5NviQV`QYK)Qg zUhh6Ut~&sphKF78bgPN!a*8I5nrq+8IiMacZLi>3I%->y7Q~PR?mc=A@2G`KH;HRk zSW&A7$rin-v%FbzG5x8^8@Ll%57+Jx7q64VUeHH!G3!yk%e%a;MwUCtEV!U7X@!5zqPap6p=C3>?E4s=8tMrMif2L1MqFGKM?vIlA{~gD_|2reKiMfi$YZLPUh)Vn=ouxXMFf6c2pS+1tfapIhJPPp5 zxZ3t4{zDhsAGJ|%0HX3QHwqB__=Q+m3(PIG+9rMfJ;1Y~CYa#N+1Z?)_R|cDLJ;~N|NE9!R~*n0 zV1A;iwi_~Ew;cLz2*HoH8=slf_lNA=P;D77PTlt}nH{V_P_ll#@|04gpRX)Me!j94 z`}xY+QnC+A2}aK}d083#EEL~mt&JjbLY1xSp?hy>e~lu3Q)oGbkeE>mjq&okxqrR8 zjQtiG7jtMJBo<0&tf7S6NpsIybEu{F5NcjN%`Ulux z@k1!BlaLyv{E#X)0>rDZ>V)W}X%>?=ubaQ(wLdSA0=-KM*+=A^Q11G(&L8uj;wNeo=7bS zq#K9&<}7;6v`C?cPE+Lxr4#kH8R-3G{`;m%{>!FH!JDQabCKwnMY8+y#;U7Cev72$ zb=wnAyiQ>KzA8QpGy=I^DEbw2MBzi^IDj__QNM!Dn<7-8_X+hVe#?eXS$91M-xP*= zi@`gcIY9ZYa5O|XXv0 z1)dS|;@IP>@{$!`nk3Bnou%RvZZb7U6npc^DR5005;wS(*@n6uR!z*_ z6STaU&A4RLT(vxK0=nH@Fs6wViZ(zoRx7?ciG{ z{7sc?0l)VO$$|5oLzV#Nply@HI(yTyNY?NxqEM z0nXjNO{l|?pg!Ya!mS41G2fZo+Y){t()3!XW? zW{$QfuXh^>lV)(O_POcjL8@|t>m9;9QCZyHy`<7u0`1`I75=6ezjreUaV(2H;Jj*x zHGuDZmF$N_{pTi=Zu(y_XJ5wB-=KDbCyV)?AHN_qS|Qw;?))d`)m=L zTvbd)0k=LbaMq?kP+3GXK)4&EF5T1=Q!tV2tH^CpovnWy0a z)o=PudOlte*l!tfMc~{PG-o$itk+~pDZb*hfcJKhnW8*f#``XN%yye@61YDZtBL2g z$}-@+TVzi3Ya*FSm4FckC<-u`_B>ftNkn#ueo~eK$^1cH zJ~~`pAURsn21%p*_sQD>7mqZQe$jhJ75=Dvyqr`CHCxs(o0?RPT2&EGDz74*QdmjD zdWNZ875Rs&CuAlJ^BR`7mU|52(Fhfa%-RQ2lWiuf4y#D^?K$tKlUb@AU;!W-1?4>!dKNi|MAUlBiA zy-*Q9Mm>2`B|XO~b#o=WQ7x#5AE(q{CI0a-8yQHdZs#Gu|#@rYky3>w@K>>^K$7!gxB+(zQ}l- zq50$U(#=)$+*<|TrE!X9iK{j-fzQ)pkK5_>6^d@Av{`lZ_4fBsh*fggst_yL*HIYg7gIN62gK$~J7rvV@yc^A zT;wiVzR-246q4>#?!vXp&%Lnq{4k~HWeOfaOO~&87cCVHOBb$G?viB}opAJvx)kYvYvX=6Y3cwph$`XO-K!>Owd0;i?PI zXAiE*wD)9Hf5|H@Sg>SS>v`w9(_5yu%v5f+Gvj5b8nUZngWIuwgWHwK^#n|3s{TSQ z?{x(Ti}khlY=CXLMQ(2JIPYF z^&%p4=JIZ-nC;{i_V7nu^_4u9@Uq$iomt}n%T3%1#M;IDU3t}?TTh0z7mHG9fr5!` zwZ&cP*y%H8***o-G0@SY!;kzZ9i81w8rjJR(~yf@w_|gL`zq6uyD}SYz2_D>lxiss z^m>_gO1*+f*CR)c&KCMrOTN#`ww!xjYqOW>mQr`V)Y4wc^>jApI#mmo)@O?ARZHhU zp7fd2D;UbgY@wLz%ZCas(F)m~3=2rEzsFN8+FdP_ZRzf#qLS-QR>O%v&fUXknQQCdWnMUpFtU09_KrxQ@|)`RDL1he|YV+KGc7kWROB0$1Yh0eXYwWH;Vp4 zp4S7ukfx=PoQs?I2h@Vg%R~f+kdUdpC^1c_aeRAlBZp7%zym+j(vjl z8|P!BEMs3{o)7VIYs=#tjr3xl(`00uLwgo;ZKK4N$9Wqm+AHk7{V3lVk;lFU>5ClT z)`fZj-9;I@ew^QtjsT;i(e{5<oVRV&V=I)vJ_aEZR;b@;J{x0P;wWpbYZh z;dH#nKWT%MkMbT Date: Tue, 15 Aug 2017 11:20:26 +0100 Subject: [PATCH 486/627] Makefile: Add aes/aestst to default goal --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 8cb10eb69..4149da37a 100644 --- a/Makefile +++ b/Makefile @@ -54,7 +54,7 @@ OBJS = $(SRCS:.c=.o) TESTLIBS = $(shell pkg-config --libs check) -lrt -lpthread -lm TESTSSLLIBS = -lcrypto -all: test_check test_openssl test_speed tools libtrezor-crypto.so +all: test_check test_openssl test_speed aes/aestst tools libtrezor-crypto.so %.o: %.c %.h options.h $(CC) $(CFLAGS) -o $@ -c $< From 9dfc6a4477a7ac344ab630441e0b76d5d623a313 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Thu, 10 Aug 2017 16:31:21 +0200 Subject: [PATCH 487/627] introduce confidential macro, mark confidential items --- bip32.c | 33 ++++++++++++++-------- bip39.c | 23 ++++++++++----- ecdsa.c | 12 +++++--- hmac.c | 83 ++++++++++++++++++++++++++++++------------------------- options.h | 5 ++++ 5 files changed, 96 insertions(+), 60 deletions(-) diff --git a/bip32.c b/bip32.c index 4a84478f6..58ee61273 100644 --- a/bip32.c +++ b/bip32.c @@ -122,7 +122,7 @@ int hdnode_from_xprv(uint32_t depth, uint32_t child_num, const uint8_t *chain_co int hdnode_from_seed(const uint8_t *seed, int seed_len, const char* curve, HDNode *out) { - uint8_t I[32 + 32]; + static CONFIDENTIAL uint8_t I[32 + 32]; memset(out, 0, sizeof(HDNode)); out->depth = 0; out->child_num = 0; @@ -130,8 +130,10 @@ int hdnode_from_seed(const uint8_t *seed, int seed_len, const char* curve, HDNod if (out->curve == 0) { return 0; } - hmac_sha512((const uint8_t*) out->curve->bip32_name, - strlen(out->curve->bip32_name), seed, seed_len, I); + static CONFIDENTIAL HMAC_SHA512_CTX ctx; + hmac_sha512_Init(&ctx, (const uint8_t*) out->curve->bip32_name, strlen(out->curve->bip32_name)); + hmac_sha512_Update(&ctx, seed, seed_len); + hmac_sha512_Final(&ctx, I); if (out->curve->params) { bignum256 a; @@ -141,8 +143,9 @@ int hdnode_from_seed(const uint8_t *seed, int seed_len, const char* curve, HDNod && bn_is_less(&a, &out->curve->params->order)) { // < order break; } - hmac_sha512((const uint8_t*) out->curve->bip32_name, - strlen(out->curve->bip32_name), I, sizeof(I), I); + hmac_sha512_Init(&ctx, (const uint8_t*) out->curve->bip32_name, strlen(out->curve->bip32_name)); + hmac_sha512_Update(&ctx, I, sizeof(I)); + hmac_sha512_Final(&ctx, I); } MEMSET_BZERO(&a, sizeof(a)); } @@ -168,9 +171,9 @@ uint32_t hdnode_fingerprint(HDNode *node) int hdnode_private_ckd(HDNode *inout, uint32_t i) { - uint8_t data[1 + 32 + 4]; - uint8_t I[32 + 32]; - bignum256 a, b; + static CONFIDENTIAL uint8_t data[1 + 32 + 4]; + static CONFIDENTIAL uint8_t I[32 + 32]; + static CONFIDENTIAL bignum256 a, b; if (i & 0x80000000) { // private derivation data[0] = 0; @@ -186,7 +189,11 @@ int hdnode_private_ckd(HDNode *inout, uint32_t i) bn_read_be(inout->private_key, &a); - hmac_sha512(inout->chain_code, 32, data, sizeof(data), I); + static CONFIDENTIAL HMAC_SHA512_CTX ctx; + hmac_sha512_Init(&ctx, inout->chain_code, 32); + hmac_sha512_Update(&ctx, data, sizeof(data)); + hmac_sha512_Final(&ctx, I); + if (inout->curve->params) { while (true) { bool failed = false; @@ -208,7 +215,9 @@ int hdnode_private_ckd(HDNode *inout, uint32_t i) data[0] = 1; memcpy(data + 1, I + 32, 32); - hmac_sha512(inout->chain_code, 32, data, sizeof(data), I); + hmac_sha512_Init(&ctx, inout->chain_code, 32); + hmac_sha512_Update(&ctx, data, sizeof(data)); + hmac_sha512_Final(&ctx, I); } } else { memcpy(inout->private_key, I, 32); @@ -308,10 +317,10 @@ void hdnode_public_ckd_address_optimized(const curve_point *pub, const uint8_t * #if USE_BIP32_CACHE static bool private_ckd_cache_root_set = false; -static HDNode private_ckd_cache_root; +static CONFIDENTIAL HDNode private_ckd_cache_root; static int private_ckd_cache_index = 0; -static struct { +static CONFIDENTIAL struct { bool set; size_t depth; uint32_t i[BIP32_CACHE_MAXDEPTH]; diff --git a/bip39.c b/bip39.c index ef7a40e5f..7539944d0 100644 --- a/bip39.c +++ b/bip39.c @@ -31,12 +31,13 @@ #include "pbkdf2.h" #include "bip39_english.h" #include "options.h" +#include "macros.h" #if USE_BIP39_CACHE static int bip39_cache_index = 0; -static struct { +static CONFIDENTIAL struct { bool set; char mnemonic[256]; char passphrase[64]; @@ -52,7 +53,9 @@ const char *mnemonic_generate(int strength) } uint8_t data[32]; random_buffer(data, 32); - return mnemonic_from_data(data, strength / 8); + const char *r = mnemonic_from_data(data, strength / 8); + MEMSET_BZERO(data, sizeof(data)); + return r; } const uint16_t *mnemonic_generate_indexes(int strength) @@ -62,7 +65,9 @@ const uint16_t *mnemonic_generate_indexes(int strength) } uint8_t data[32]; random_buffer(data, 32); - return mnemonic_from_data_indexes(data, strength / 8); + const uint16_t *r = mnemonic_from_data_indexes(data, strength / 8); + MEMSET_BZERO(data, sizeof(data)); + return r; } const char *mnemonic_from_data(const uint8_t *data, int len) @@ -80,7 +85,7 @@ const char *mnemonic_from_data(const uint8_t *data, int len) memcpy(bits, data, len); int mlen = len * 3 / 4; - static char mnemo[24 * 10]; + static CONFIDENTIAL char mnemo[24 * 10]; int i, j, idx; char *p = mnemo; @@ -95,6 +100,7 @@ const char *mnemonic_from_data(const uint8_t *data, int len) *p = (i < mlen - 1) ? ' ' : 0; p++; } + MEMSET_BZERO(bits, sizeof(bits)); return mnemo; } @@ -114,7 +120,7 @@ const uint16_t *mnemonic_from_data_indexes(const uint8_t *data, int len) memcpy(bits, data, len); int mlen = len * 3 / 4; - static uint16_t mnemo[24]; + static CONFIDENTIAL uint16_t mnemo[24]; int i, j, idx; for (i = 0; i < mlen; i++) { @@ -125,6 +131,7 @@ const uint16_t *mnemonic_from_data_indexes(const uint8_t *data, int len) } mnemo[i] = idx; } + MEMSET_BZERO(bits, sizeof(bits)); return mnemo; } @@ -153,7 +160,8 @@ int mnemonic_check(const char *mnemonic) char current_word[10]; uint32_t j, k, ki, bi; uint8_t bits[32 + 1]; - memset(bits, 0, sizeof(bits)); + + MEMSET_BZERO(bits, sizeof(bits)); i = 0; bi = 0; while (mnemonic[i]) { j = 0; @@ -221,7 +229,7 @@ void mnemonic_to_seed(const char *mnemonic, const char *passphrase, uint8_t seed uint8_t salt[8 + 256]; memcpy(salt, "mnemonic", 8); memcpy(salt + 8, passphrase, passphraselen); - PBKDF2_HMAC_SHA512_CTX pctx; + static CONFIDENTIAL PBKDF2_HMAC_SHA512_CTX pctx; pbkdf2_hmac_sha512_Init(&pctx, (const uint8_t *)mnemonic, strlen(mnemonic), salt, passphraselen + 8); if (progress_callback) { progress_callback(0, BIP39_PBKDF2_ROUNDS); @@ -233,6 +241,7 @@ void mnemonic_to_seed(const char *mnemonic, const char *passphrase, uint8_t seed } } pbkdf2_hmac_sha512_Final(&pctx, seed); + MEMSET_BZERO(salt, sizeof(salt)); #if USE_BIP39_CACHE // store to cache if (mnemoniclen < 256 && passphraselen < 64) { diff --git a/ecdsa.c b/ecdsa.c index a2e1f430a..e259aa7e8 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -434,13 +434,13 @@ void point_multiply(const ecdsa_curve *curve, const bignum256 *k, const curve_po assert (bn_is_less(k, &curve->order)); int i, j; - bignum256 a; + static CONFIDENTIAL bignum256 a; uint32_t *aptr; uint32_t abits; int ashift; uint32_t is_even = (k->val[0] & 1) - 1; uint32_t bits, sign, nsign; - jacobian_curve_point jres; + static CONFIDENTIAL jacobian_curve_point jres; curve_point pmult[8]; const bignum256 *prime = &curve->prime; @@ -542,6 +542,8 @@ void point_multiply(const ecdsa_curve *curve, const bignum256 *k, const curve_po } conditional_negate(sign, &jres.z, prime); jacobian_to_curve(&jres, res, prime); + MEMSET_BZERO(&a, sizeof(a)); + MEMSET_BZERO(&jres, sizeof(jres)); } #if USE_PRECOMPUTED_CP @@ -553,10 +555,10 @@ void scalar_multiply(const ecdsa_curve *curve, const bignum256 *k, curve_point * assert (bn_is_less(k, &curve->order)); int i, j; - bignum256 a; + static CONFIDENTIAL bignum256 a; uint32_t is_even = (k->val[0] & 1) - 1; uint32_t lowbits; - jacobian_curve_point jres; + static CONFIDENTIAL jacobian_curve_point jres; const bignum256 *prime = &curve->prime; // is_even = 0xffffffff if k is even, 0 otherwise. @@ -628,6 +630,8 @@ void scalar_multiply(const ecdsa_curve *curve, const bignum256 *k, curve_point * } conditional_negate(((a.val[0] >> 4) & 1) - 1, &jres.y, prime); jacobian_to_curve(&jres, res, prime); + MEMSET_BZERO(&a, sizeof(a)); + MEMSET_BZERO(&jres, sizeof(jres)); } #else diff --git a/hmac.c b/hmac.c index c866687e2..03af92cdb 100644 --- a/hmac.c +++ b/hmac.c @@ -24,11 +24,12 @@ #include #include "hmac.h" +#include "options.h" #include "macros.h" void hmac_sha256_Init(HMAC_SHA256_CTX *hctx, const uint8_t *key, const uint32_t keylen) { - uint8_t i_key_pad[SHA256_BLOCK_LENGTH]; + static CONFIDENTIAL uint8_t i_key_pad[SHA256_BLOCK_LENGTH]; memset(i_key_pad, 0, SHA256_BLOCK_LENGTH); if (keylen > SHA256_BLOCK_LENGTH) { sha256_Raw(key, keylen, i_key_pad); @@ -51,19 +52,17 @@ void hmac_sha256_Update(HMAC_SHA256_CTX *hctx, const uint8_t *msg, const uint32_ void hmac_sha256_Final(HMAC_SHA256_CTX *hctx, uint8_t *hmac) { - uint8_t hash[SHA256_DIGEST_LENGTH]; - sha256_Final(&(hctx->ctx), hash); + sha256_Final(&(hctx->ctx), hmac); sha256_Init(&(hctx->ctx)); sha256_Update(&(hctx->ctx), hctx->o_key_pad, SHA256_BLOCK_LENGTH); - sha256_Update(&(hctx->ctx), hash, SHA256_DIGEST_LENGTH); + sha256_Update(&(hctx->ctx), hmac, SHA256_DIGEST_LENGTH); sha256_Final(&(hctx->ctx), hmac); - MEMSET_BZERO(hash, sizeof(hash)); MEMSET_BZERO(hctx, sizeof(HMAC_SHA256_CTX)); } void hmac_sha256(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, const uint32_t msglen, uint8_t *hmac) { - HMAC_SHA256_CTX hctx; + static CONFIDENTIAL HMAC_SHA256_CTX hctx; hmac_sha256_Init(&hctx, key, keylen); hmac_sha256_Update(&hctx, msg, msglen); hmac_sha256_Final(&hctx, hmac); @@ -71,35 +70,41 @@ void hmac_sha256(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, void hmac_sha256_prepare(const uint8_t *key, const uint32_t keylen, uint32_t *opad_digest, uint32_t *ipad_digest) { - int i; - uint32_t buf[SHA256_BLOCK_LENGTH/sizeof(uint32_t)]; - uint32_t o_key_pad[16], i_key_pad[16]; + static CONFIDENTIAL uint32_t key_pad[SHA256_BLOCK_LENGTH/sizeof(uint32_t)]; - memset(buf, 0, SHA256_BLOCK_LENGTH); + MEMSET_BZERO(key_pad, sizeof(key_pad)); if (keylen > SHA256_BLOCK_LENGTH) { - sha256_Raw(key, keylen, (uint8_t*) buf); + static CONFIDENTIAL SHA256_CTX context; + sha256_Init(&context); + sha256_Update(&context, key, keylen); + sha256_Final(&context, (uint8_t*)key_pad); } else { - memcpy(buf, key, keylen); + memcpy(key_pad, key, keylen); } - for (i = 0; i < 16; i++) { + /* compute o_key_pad and its digest */ + for (int i = 0; i < SHA256_BLOCK_LENGTH/(int)sizeof(uint32_t); i++) { uint32_t data; #if BYTE_ORDER == LITTLE_ENDIAN - REVERSE32(buf[i], data); + REVERSE32(key_pad[i], data); #else - data = buf[i]; + data = key_pad[i]; #endif - o_key_pad[i] = data ^ 0x5c5c5c5c; - i_key_pad[i] = data ^ 0x36363636; + key_pad[i] = data ^ 0x5c5c5c5c; } + sha256_Transform(sha256_initial_hash_value, key_pad, opad_digest); - sha256_Transform(sha256_initial_hash_value, o_key_pad, opad_digest); - sha256_Transform(sha256_initial_hash_value, i_key_pad, ipad_digest); + /* convert o_key_pad to i_key_pad and compute its digest */ + for (int i = 0; i < SHA256_BLOCK_LENGTH/(int)sizeof(uint32_t); i++) { + key_pad[i] = key_pad[i] ^ 0x5c5c5c5c ^ 0x36363636; + } + sha256_Transform(sha256_initial_hash_value, key_pad, ipad_digest); + MEMSET_BZERO(key_pad, sizeof(key_pad)); } void hmac_sha512_Init(HMAC_SHA512_CTX *hctx, const uint8_t *key, const uint32_t keylen) { - uint8_t i_key_pad[SHA512_BLOCK_LENGTH]; + static CONFIDENTIAL uint8_t i_key_pad[SHA512_BLOCK_LENGTH]; memset(i_key_pad, 0, SHA512_BLOCK_LENGTH); if (keylen > SHA512_BLOCK_LENGTH) { sha512_Raw(key, keylen, i_key_pad); @@ -122,13 +127,11 @@ void hmac_sha512_Update(HMAC_SHA512_CTX *hctx, const uint8_t *msg, const uint32_ void hmac_sha512_Final(HMAC_SHA512_CTX *hctx, uint8_t *hmac) { - uint8_t hash[SHA512_DIGEST_LENGTH]; - sha512_Final(&(hctx->ctx), hash); + sha512_Final(&(hctx->ctx), hmac); sha512_Init(&(hctx->ctx)); sha512_Update(&(hctx->ctx), hctx->o_key_pad, SHA512_BLOCK_LENGTH); - sha512_Update(&(hctx->ctx), hash, SHA512_DIGEST_LENGTH); + sha512_Update(&(hctx->ctx), hmac, SHA512_DIGEST_LENGTH); sha512_Final(&(hctx->ctx), hmac); - MEMSET_BZERO(hash, sizeof(hash)); MEMSET_BZERO(hctx, sizeof(HMAC_SHA512_CTX)); } @@ -142,28 +145,34 @@ void hmac_sha512(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, void hmac_sha512_prepare(const uint8_t *key, const uint32_t keylen, uint64_t *opad_digest, uint64_t *ipad_digest) { - int i; - uint64_t buf[SHA512_BLOCK_LENGTH/sizeof(uint64_t)]; - uint64_t o_key_pad[16], i_key_pad[16]; + static CONFIDENTIAL uint64_t key_pad[SHA512_BLOCK_LENGTH/sizeof(uint64_t)]; - memset(buf, 0, SHA512_BLOCK_LENGTH); + MEMSET_BZERO(key_pad, sizeof(key_pad)); if (keylen > SHA512_BLOCK_LENGTH) { - sha512_Raw(key, keylen, (uint8_t*)buf); + static CONFIDENTIAL SHA512_CTX context; + sha512_Init(&context); + sha512_Update(&context, key, keylen); + sha512_Final(&context, (uint8_t*)key_pad); } else { - memcpy(buf, key, keylen); + memcpy(key_pad, key, keylen); } - for (i = 0; i < 16; i++) { + /* compute o_key_pad and its digest */ + for (int i = 0; i < SHA512_BLOCK_LENGTH/(int)sizeof(uint64_t); i++) { uint64_t data; #if BYTE_ORDER == LITTLE_ENDIAN - REVERSE64(buf[i], data); + REVERSE64(key_pad[i], data); #else - data = buf[i]; + data = key_pad[i]; #endif - o_key_pad[i] = data ^ 0x5c5c5c5c5c5c5c5c; - i_key_pad[i] = data ^ 0x3636363636363636; + key_pad[i] = data ^ 0x5c5c5c5c5c5c5c5c; } + sha512_Transform(sha512_initial_hash_value, key_pad, opad_digest); - sha512_Transform(sha512_initial_hash_value, o_key_pad, opad_digest); - sha512_Transform(sha512_initial_hash_value, i_key_pad, ipad_digest); + /* convert o_key_pad to i_key_pad and compute its digest */ + for (int i = 0; i < SHA512_BLOCK_LENGTH/(int)sizeof(uint64_t); i++) { + key_pad[i] = key_pad[i] ^ 0x5c5c5c5c5c5c5c5c ^ 0x3636363636363636; + } + sha512_Transform(sha512_initial_hash_value, key_pad, ipad_digest); + MEMSET_BZERO(key_pad, sizeof(key_pad)); } diff --git a/options.h b/options.h index a8a1f499d..79d3f6ec0 100644 --- a/options.h +++ b/options.h @@ -71,4 +71,9 @@ #define USE_KECCAK 1 #endif +// add way how to mark confidential data +#ifndef CONFIDENTIAL +#define CONFIDENTIAL +#endif + #endif From 7c3b2d520993cdbdac66dff6515781a23208a4b3 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Thu, 18 May 2017 20:17:35 +0100 Subject: [PATCH 488/627] options: Add NEM support --- Makefile | 1 + options.h | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/Makefile b/Makefile index 4149da37a..0b00418ab 100644 --- a/Makefile +++ b/Makefile @@ -29,6 +29,7 @@ CFLAGS += -Ichacha20poly1305 CFLAGS += -Ied25519-donna CFLAGS += -DUSE_ETHEREUM=1 CFLAGS += -DUSE_GRAPHENE=1 +CFLAGS += -DUSE_NEM=1 # disable certain optimizations and features when small footprint is required ifdef SMALL diff --git a/options.h b/options.h index 79d3f6ec0..2a542157e 100644 --- a/options.h +++ b/options.h @@ -66,6 +66,11 @@ #define USE_GRAPHENE 0 #endif +// support NEM operations +#ifndef USE_NEM +#define USE_NEM 0 +#endif + // support Keccak hashing #ifndef USE_KECCAK #define USE_KECCAK 1 From 8edc0c58d3c4bd01b19ccb2b63e36804220b560c Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Fri, 19 May 2017 18:17:24 +0100 Subject: [PATCH 489/627] bip32: Add hdnode_get_nem_address --- CMakeLists.txt | 1 + Makefile | 1 + bip32.c | 14 +++++++++++ bip32.h | 4 ++++ nem.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++ nem.h | 39 ++++++++++++++++++++++++++++++ 6 files changed, 123 insertions(+) create mode 100644 nem.c create mode 100644 nem.h diff --git a/CMakeLists.txt b/CMakeLists.txt index e977f725a..83397e656 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,6 +14,7 @@ set(SOURCES blake2b.c blake2s.c chacha20poly1305/chacha20poly1305.c chacha20poly1305/chacha_merged.c chacha20poly1305/poly1305-donna.c chacha20poly1305/rfc7539.c rc4.c + nem.c ) add_library(TrezorCrypto STATIC ${SOURCES}) diff --git a/Makefile b/Makefile index 0b00418ab..a42b9c18e 100644 --- a/Makefile +++ b/Makefile @@ -49,6 +49,7 @@ SRCS += ed25519-donna/ed25519.c ed25519-donna/curve25519-donna-scalarmult-base. SRCS += blake2b.c blake2s.c SRCS += chacha20poly1305/chacha20poly1305.c chacha20poly1305/chacha_merged.c chacha20poly1305/poly1305-donna.c chacha20poly1305/rfc7539.c SRCS += rc4.c +SRCS += nem.c OBJS = $(SRCS:.c=.o) diff --git a/bip32.c b/bip32.c index 58ee61273..1dadc9aa5 100644 --- a/bip32.c +++ b/bip32.c @@ -43,6 +43,9 @@ #if USE_KECCAK #include "ed25519-keccak.h" #endif +#if USE_NEM +#include "nem.h" +#endif const curve_info ed25519_info = { /* bip32_name */ @@ -444,6 +447,17 @@ int hdnode_get_ethereum_pubkeyhash(const HDNode *node, uint8_t *pubkeyhash) } #endif +#if USE_NEM +int hdnode_get_nem_address(HDNode *node, uint8_t version, char *address) { + if (node->curve != &ed25519_keccak_info) { + return 0; + } + + hdnode_fill_public_key(node); + return nem_get_address(&node->public_key[1], version, address); +} +#endif + // msg is a data to be signed // msg_len is the message length int hdnode_sign(HDNode *node, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64])) diff --git a/bip32.h b/bip32.h index 71d9b8ed7..83a285cff 100644 --- a/bip32.h +++ b/bip32.h @@ -72,6 +72,10 @@ void hdnode_fill_public_key(HDNode *node); int hdnode_get_ethereum_pubkeyhash(const HDNode *node, uint8_t *pubkeyhash); #endif +#if USE_NEM +int hdnode_get_nem_address(HDNode *node, uint8_t version, char *address); +#endif + int hdnode_sign(HDNode *node, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64])); int hdnode_sign_digest(HDNode *node, const uint8_t *digest, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64])); diff --git a/nem.c b/nem.c new file mode 100644 index 000000000..c8c6ab002 --- /dev/null +++ b/nem.c @@ -0,0 +1,64 @@ +/** + * Copyright (c) 2017 Saleem Rashid + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, E1PRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "nem.h" + +#include +#include + +#include "base32.h" +#include "macros.h" +#include "ripemd160.h" +#include "sha3.h" + +void nem_get_address_raw(const ed25519_public_key public_key, uint8_t version, uint8_t *address) { + uint8_t hash[SHA3_256_DIGEST_LENGTH]; + + /* 1. Perform 256-bit Sha3 on the public key */ + keccak_256(public_key, sizeof(ed25519_public_key), hash); + + /* 2. Perform 160-bit Ripemd of hash resulting from step 1. */ + ripemd160(hash, SHA3_256_DIGEST_LENGTH, &address[1]); + + /* 3. Prepend version byte to Ripemd hash (either 0x68 or 0x98) */ + address[0] = version; + + /* 4. Perform 256-bit Sha3 on the result, take the first four bytes as a checksum */ + keccak_256(address, 1 + RIPEMD160_DIGEST_LENGTH, hash); + + /* 5. Concatenate output of step 3 and the checksum from step 4 */ + memcpy(&address[1 + RIPEMD160_DIGEST_LENGTH], hash, 4); + + MEMSET_BZERO(hash, sizeof(hash)); +} + +bool nem_get_address(const ed25519_public_key public_key, uint8_t version, char *address) { + uint8_t pubkeyhash[NEM_ADDRESS_SIZE_RAW]; + + nem_get_address_raw(public_key, version, pubkeyhash); + + char *ret = base32_encode(pubkeyhash, sizeof(pubkeyhash), address, NEM_ADDRESS_SIZE + 1, BASE32_ALPHABET_RFC4648); + + MEMSET_BZERO(pubkeyhash, sizeof(pubkeyhash)); + + return (ret != NULL); +} diff --git a/nem.h b/nem.h new file mode 100644 index 000000000..294ba71a8 --- /dev/null +++ b/nem.h @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2017 Saleem Rashid + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __NEM_H__ +#define __NEM_H__ + +#include +#include + +#define NEM_NETWORK_MAINNET 0x68 +#define NEM_NETWORK_TESTNET 0x98 +#define NEM_NETWORK_MIJIN 0x60 + +#define NEM_ADDRESS_SIZE 40 +#define NEM_ADDRESS_SIZE_RAW 25 + +void nem_get_address_raw(const ed25519_public_key public_key, uint8_t version, uint8_t *address); +bool nem_get_address(const ed25519_public_key public_key, uint8_t version, char *address); + +#endif From 501c778812c2c81596dabe768ca10c070bfafad2 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sat, 27 May 2017 10:34:21 +0100 Subject: [PATCH 490/627] test_check: Add test_nem_address --- test_check.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 61 insertions(+), 5 deletions(-) diff --git a/test_check.c b/test_check.c index f86b69f0d..b99b1a251 100644 --- a/test_check.c +++ b/test_check.c @@ -58,6 +58,7 @@ #include "rfc6979.h" #include "address.h" #include "rc4.h" +#include "nem.h" /* * This is a clever trick to make Valgrind's Memcheck verify code @@ -90,6 +91,13 @@ const uint8_t *fromhex(const char *str) return buf; } +void nem_private_key(const char *reversed_hex, ed25519_secret_key private_key) { + const uint8_t *reversed_key = fromhex(reversed_hex); + for (size_t j = 0; j < sizeof(ed25519_secret_key); j++) { + private_key[j] = reversed_key[sizeof(ed25519_secret_key) - j - 1]; + } +} + START_TEST(test_bignum_read_be) { bignum256 a; @@ -2948,11 +2956,7 @@ START_TEST(test_ed25519_keccak) ed25519_signature signature; for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - // For some reason, NEM stores private keys in big endian - const uint8_t *reversed_key = fromhex(tests[i].private_key); - for (size_t j = 0; j < 32; j++) { - private_key[j] = reversed_key[32 - j - 1]; - } + nem_private_key(tests[i].private_key, private_key); MARK_SECRET_DATA(private_key, sizeof(private_key)); ed25519_publickey_keccak(private_key, public_key); @@ -3224,6 +3228,54 @@ START_TEST(test_ethereum_address) } END_TEST +// test vectors from https://raw.githubusercontent.com/NemProject/nem-test-vectors/master/1.test-keys.dat +START_TEST(test_nem_address) +{ + static const struct { + const char *private_key; + const char *public_key; + const char *address; + } tests[] = { + { "575dbb3062267eff57c970a336ebbc8fbcfe12c5bd3ed7bc11eb0481d7704ced", "c5f54ba980fcbb657dbaaa42700539b207873e134d2375efeab5f1ab52f87844", "NDD2CT6LQLIYQ56KIXI3ENTM6EK3D44P5JFXJ4R4", }, + { "5b0e3fa5d3b49a79022d7c1e121ba1cbbf4db5821f47ab8c708ef88defc29bfe", "96eb2a145211b1b7ab5f0d4b14f8abc8d695c7aee31a3cfc2d4881313c68eea3", "NABHFGE5ORQD3LE4O6B7JUFN47ECOFBFASC3SCAC", }, + { "738ba9bb9110aea8f15caa353aca5653b4bdfca1db9f34d0efed2ce1325aeeda", "2d8425e4ca2d8926346c7a7ca39826acd881a8639e81bd68820409c6e30d142a", "NAVOZX4HDVOAR4W6K4WJHWPD3MOFU27DFHC7KZOZ", }, + { "e8bf9bc0f35c12d8c8bf94dd3a8b5b4034f1063948e3cc5304e55e31aa4b95a6", "4feed486777ed38e44c489c7c4e93a830e4c4a907fa19a174e630ef0f6ed0409", "NBZ6JK5YOCU6UPSSZ5D3G27UHAPHTY5HDQMGE6TT", }, + { "c325ea529674396db5675939e7988883d59a5fc17a28ca977e3ba85370232a83", "83ee32e4e145024d29bca54f71fa335a98b3e68283f1a3099c4d4ae113b53e54", "NCQW2P5DNZ5BBXQVGS367DQ4AHC3RXOEVGRCLY6V", }, + { "a811cb7a80a7227ae61f6da536534ee3c2744e3c7e4b85f3e0df3c6a9c5613df", "6d34c04f3a0e42f0c3c6f50e475ae018cfa2f56df58c481ad4300424a6270cbb", "NA5IG3XFXZHIPJ5QLKX2FBJPEZYPMBPPK2ZRC3EH", }, + { "9c66de1ec77f4dfaaebdf9c8bc599ca7e8e6f0bc71390ffee2c9dd3f3619242a", "a8fefd72a3b833dc7c7ed7d57ed86906dac22f88f1f4331873eb2da3152a3e77", "NAABHVFJDBM74XMJJ52R7QN2MTTG2ZUXPQS62QZ7", }, + { "c56bc16ecf727878c15e24f4ae68569600ac7b251218a44ef50ce54175776edc", "c92f761e6d83d20068fd46fe4bd5b97f4c6ba05d23180679b718d1f3e4fb066e", "NCLK3OLMHR3F2E3KSBUIZ4K5PNWUDN37MLSJBJZP", }, + { "9dd73599283882fa1561ddfc9be5830b5dd453c90465d3fe5eeb646a3606374e", "eaf16a4833e59370a04ccd5c63395058de34877b48c17174c71db5ed37b537ed", "ND3AHW4VTI5R5QE5V44KIGPRU5FBJ5AFUCJXOY5H", }, + { "d9639dc6f49dad02a42fd8c217f1b1b4f8ce31ccd770388b645e639c72ff24fa", "0f74a2f537cd9c986df018994dde75bdeee05e35eb9fe27adf506ca8475064f7", "NCTZ4YAP43ONK3UYTASQVNDMBO24ZHJE65F3QPYE", }, + { "efc1992cd50b70ca55ac12c07aa5d026a8b78ffe28a7dbffc9228b26e02c38c1", "2ebff201255f6cf948c78f528658b99a7c13ac791942fa22d59af610558111f5", "NDQ2TMCMXBSFPZQPE2YKH6XLC24HD6LUMN6Z4GIC", }, + { "143a815e92e43f3ed1a921ee48cd143931b88b7c3d8e1e981f743c2a5be3c5ba", "419ed11d48730e4ae2c93f0ea4df853b8d578713a36dab227517cf965861af4e", "NA32IDDW2C53BDSBJNFL3Z6UU3J5CJZJMCZDXCF4", }, + { "bc1a082f5ac6fdd3a83ade211e5986ac0551bad6c7da96727ec744e5df963e2a", "a160e6f9112233a7ce94202ed7a4443e1dac444b5095f9fecbb965fba3f92cac", "NADUCEQLC3FTGB25GTA5HOUTB53CBVQNVOIP7NTJ", }, + { "4e47b4c6f4c7886e49ec109c61f4af5cfbb1637283218941d55a7f9fe1053f72", "fbb91b16df828e21a9802980a44fc757c588bc1382a4cea429d6fa2ae0333f56", "NBAF3BFLLPWH33MYE6VUPP5T6DQBZBKIDEQKZQOE", }, + { "efc4389da48ce49f85365cfa578c746530e9eac42db1b64ec346119b1becd347", "2232f24dda0f2ded3ecd831210d4e8521a096b50cadd5a34f3f7083374e1ec12", "NBOGTK2I2ATOGGD7ZFJHROG5MWL7XCKAUKSWIVSA", }, + { "bdba57c78ca7da16a3360efd13f06276284db8c40351de7fcd38ba0c35ac754d", "c334c6c0dad5aaa2a0d0fb4c6032cb6a0edd96bf61125b5ea9062d5a00ee0eee", "NCLERTEFYXKLK7RA4MVACEFMXMK3P7QMWTM7FBW2", }, + { "20694c1ec3c4a311bcdb29ed2edc428f6d4f9a4c429ad6a5bf3222084e35695f", "518c4de412efa93de06a55947d11f697639443916ec8fcf04ebc3e6d17d0bd93", "NB5V4BPIJHXVONO7UGMJDPFARMFA73BOBNOOYCOV", }, + { "e0d4f3760ac107b33c22c2cac24ab2f520b282684f5f66a4212ff95d926323ce", "b3d16f4ead9de67c290144da535a0ed2504b03c05e5f1ceb8c7863762f786857", "NC4PBAO5TPCAVQKBVOC4F6DMZP3CFSQBU46PSKBD", }, + { "efa9afc617412093c9c7a7c211a5332dd556f941e1a88c494ec860608610eea2", "7e7716e4cebceb731d6f1fd28676f34888e9a0000fcfa1471db1c616c2ddf559", "NCFW2LPXIWLBWAQN2QVIWEOD7IVDO3HQBD2OU56K", }, + { "d98499b3db61944684ce06a91735af4e14105338473fcf6ebe2b0bcada3dfd21", "114171230ad6f8522a000cdc73fbc5c733b30bb71f2b146ccbdf34499f79a810", "NCUKWDY3J3THKQHAKOK5ALF6ANJQABZHCH7VN6DP", }, + }; + + HDNode node; + ed25519_secret_key private_key; + uint8_t chain_code[32]; + char address[41]; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + nem_private_key(tests[i].private_key, private_key); + + ck_assert(hdnode_from_xprv(0, 0, chain_code, private_key, ED25519_KECCAK_NAME, &node)); + + ck_assert(hdnode_get_nem_address(&node, NEM_NETWORK_MAINNET, address)); + ck_assert_str_eq(address, tests[i].address); + + ck_assert_mem_eq(&node.public_key[1], fromhex(tests[i].public_key), 32); + } +} +END_TEST + START_TEST(test_multibyte_address) { uint8_t priv_key[32]; @@ -3680,6 +3732,10 @@ Suite *test_suite(void) tcase_add_test(tc, test_ethereum_pubkeyhash); suite_add_tcase(s, tc); + tc = tcase_create("nem_address"); + tcase_add_test(tc, test_nem_address); + suite_add_tcase(s, tc); + tc = tcase_create("multibyte_address"); tcase_add_test(tc, test_multibyte_address); suite_add_tcase(s, tc); From fd0952621e2e462d699e305be6e3e848208f814f Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Wed, 31 May 2017 13:03:39 +0100 Subject: [PATCH 491/627] nem: Add nem_network_name --- nem.c | 13 +++++++++++++ nem.h | 2 ++ 2 files changed, 15 insertions(+) diff --git a/nem.c b/nem.c index c8c6ab002..d0f05894b 100644 --- a/nem.c +++ b/nem.c @@ -30,6 +30,19 @@ #include "ripemd160.h" #include "sha3.h" +const char *nem_network_name(uint8_t network) { + switch (network) { + case NEM_NETWORK_MAINNET: + return "NEM Mainnet"; + case NEM_NETWORK_TESTNET: + return "NEM Testnet"; + case NEM_NETWORK_MIJIN: + return "Mijin"; + default: + return NULL; + } +} + void nem_get_address_raw(const ed25519_public_key public_key, uint8_t version, uint8_t *address) { uint8_t hash[SHA3_256_DIGEST_LENGTH]; diff --git a/nem.h b/nem.h index 294ba71a8..ae4d0b08b 100644 --- a/nem.h +++ b/nem.h @@ -33,6 +33,8 @@ #define NEM_ADDRESS_SIZE 40 #define NEM_ADDRESS_SIZE_RAW 25 +const char *nem_network_name(uint8_t network); + void nem_get_address_raw(const ed25519_public_key public_key, uint8_t version, uint8_t *address); bool nem_get_address(const ed25519_public_key public_key, uint8_t version, char *address); From 9888aab3522d0223e3bf5be0714e05ec5fa63114 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Wed, 31 May 2017 15:39:56 +0100 Subject: [PATCH 492/627] nem: Add nem_validate_address --- nem.c | 29 ++++++++++++++++++++++++++++- nem.h | 3 +++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/nem.c b/nem.c index d0f05894b..22b61454d 100644 --- a/nem.c +++ b/nem.c @@ -72,6 +72,33 @@ bool nem_get_address(const ed25519_public_key public_key, uint8_t version, char char *ret = base32_encode(pubkeyhash, sizeof(pubkeyhash), address, NEM_ADDRESS_SIZE + 1, BASE32_ALPHABET_RFC4648); MEMSET_BZERO(pubkeyhash, sizeof(pubkeyhash)); - return (ret != NULL); } + +bool nem_validate_address_raw(const uint8_t *address, uint8_t network) { + if (!nem_network_name(network) || address[0] != network) { + return false; + } + + uint8_t hash[SHA3_256_DIGEST_LENGTH]; + + keccak_256(address, 1 + RIPEMD160_DIGEST_LENGTH, hash); + bool valid = (memcmp(&address[1 + RIPEMD160_DIGEST_LENGTH], hash, 4) == 0); + + MEMSET_BZERO(hash, sizeof(hash)); + return valid; +} + +bool nem_validate_address(const char *address, uint8_t network) { + uint8_t pubkeyhash[NEM_ADDRESS_SIZE_RAW]; + + if (strlen(address) != NEM_ADDRESS_SIZE) { + return false; + } + + uint8_t *ret = base32_decode(address, NEM_ADDRESS_SIZE, pubkeyhash, sizeof(pubkeyhash), BASE32_ALPHABET_RFC4648); + bool valid = (ret != NULL) && nem_validate_address_raw(pubkeyhash, network); + + MEMSET_BZERO(pubkeyhash, sizeof(pubkeyhash)); + return valid; +} diff --git a/nem.h b/nem.h index ae4d0b08b..6e551a620 100644 --- a/nem.h +++ b/nem.h @@ -38,4 +38,7 @@ const char *nem_network_name(uint8_t network); void nem_get_address_raw(const ed25519_public_key public_key, uint8_t version, uint8_t *address); bool nem_get_address(const ed25519_public_key public_key, uint8_t version, char *address); +bool nem_validate_address_raw(const uint8_t *address, uint8_t network); +bool nem_validate_address(const char *address, uint8_t network); + #endif From e1a511092ac572e70655a6c1d6a2faf3944ab258 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Tue, 30 May 2017 13:21:58 +0100 Subject: [PATCH 493/627] nem: Add transaction serialization methods --- nem.c | 484 +++++++++++++++++++++++++++++++++++++++++++++++- nem.h | 127 +++++++++++++ nem_serialize.h | 23 +++ 3 files changed, 633 insertions(+), 1 deletion(-) create mode 100644 nem_serialize.h diff --git a/nem.c b/nem.c index 22b61454d..ace8670b4 100644 --- a/nem.c +++ b/nem.c @@ -22,10 +22,10 @@ #include "nem.h" -#include #include #include "base32.h" +#include "ed25519-keccak.h" #include "macros.h" #include "ripemd160.h" #include "sha3.h" @@ -43,6 +43,57 @@ const char *nem_network_name(uint8_t network) { } } +static inline void nem_write_u32(nem_transaction_ctx *ctx, uint32_t data) { + ctx->buffer[ctx->offset++] = (data >> 0) & 0xff; + ctx->buffer[ctx->offset++] = (data >> 8) & 0xff; + ctx->buffer[ctx->offset++] = (data >> 16) & 0xff; + ctx->buffer[ctx->offset++] = (data >> 24) & 0xff; +} + +static inline void nem_write_u64(nem_transaction_ctx *ctx, uint64_t data) { + nem_write_u32(ctx, (data >> 0) & 0xffffffff); + nem_write_u32(ctx, (data >> 32) & 0xffffffff); +} + +static inline void nem_write(nem_transaction_ctx *ctx, const uint8_t *data, uint32_t length) { + nem_write_u32(ctx, length); + + memcpy(&ctx->buffer[ctx->offset], data, length); + ctx->offset += length; +} + +static inline bool nem_can_write(nem_transaction_ctx *ctx, size_t needed) { + return (ctx->offset + needed) <= ctx->size; +} + +static inline bool nem_write_mosaic_str(nem_transaction_ctx *ctx, const char *name, const char *value) { + uint32_t name_length = strlen(name); + uint32_t value_length = strlen(value); + +#define NEM_SERIALIZE \ + serialize_u32(sizeof(uint32_t) + name_length + sizeof(uint32_t) + value_length) \ + serialize_write((uint8_t *) name, name_length) \ + serialize_write((uint8_t *) value, value_length) + +#include "nem_serialize.h" + + return true; +} + +static inline bool nem_write_mosaic_bool(nem_transaction_ctx *ctx, const char *name, bool value) { + return nem_write_mosaic_str(ctx, name, value ? "true" : "false"); +} + +static inline bool nem_write_mosaic_u64(nem_transaction_ctx *ctx, const char *name, uint64_t value) { + char buffer[21]; + + if (bn_format_uint64(value, NULL, NULL, 0, 0, false, buffer, sizeof(buffer)) == 0) { + return false; + } + + return nem_write_mosaic_str(ctx, name, buffer); +} + void nem_get_address_raw(const ed25519_public_key public_key, uint8_t version, uint8_t *address) { uint8_t hash[SHA3_256_DIGEST_LENGTH]; @@ -102,3 +153,434 @@ bool nem_validate_address(const char *address, uint8_t network) { MEMSET_BZERO(pubkeyhash, sizeof(pubkeyhash)); return valid; } + +void nem_transaction_start(nem_transaction_ctx *ctx, const ed25519_public_key public_key, uint8_t *buffer, size_t size) { + memcpy(ctx->public_key, public_key, sizeof(ctx->public_key)); + + ctx->buffer = buffer; + ctx->offset = 0; + ctx->size = size; +} + +size_t nem_transaction_end(nem_transaction_ctx *ctx, const ed25519_secret_key private_key, ed25519_signature signature) { + if (private_key != NULL && signature != NULL) { + ed25519_sign_keccak(ctx->buffer, ctx->offset, private_key, ctx->public_key, signature); + } + + return ctx->offset; +} + +bool nem_transaction_write_common(nem_transaction_ctx *ctx, + uint32_t type, + uint32_t version, + uint32_t timestamp, + const ed25519_public_key signer, + uint64_t fee, + uint32_t deadline) { + +#define NEM_SERIALIZE \ + serialize_u32(type) \ + serialize_u32(version) \ + serialize_u32(timestamp) \ + serialize_write(signer, sizeof(ed25519_public_key)) \ + serialize_u64(fee) \ + serialize_u32(deadline) + +#include "nem_serialize.h" + + return true; +} + +bool nem_transaction_create_transfer(nem_transaction_ctx *ctx, + uint8_t network, + uint32_t timestamp, + const ed25519_public_key signer, + uint64_t fee, + uint32_t deadline, + const char *recipient, + uint64_t amount, + const uint8_t *payload, + uint32_t length, + bool encrypted, + uint32_t mosaics) { + + if (!signer) { + signer = ctx->public_key; + } + + if (!payload) { + length = 0; + } + + bool ret = nem_transaction_write_common(ctx, + NEM_TRANSACTION_TYPE_TRANSFER, + network << 24 | (mosaics ? 2 : 1), + timestamp, + signer, + fee, + deadline); + if (!ret) return false; + +#define NEM_SERIALIZE \ + serialize_write((uint8_t *) recipient, NEM_ADDRESS_SIZE) \ + serialize_u64(amount) + +#include "nem_serialize.h" + + if (length) { + +#define NEM_SERIALIZE \ + serialize_u32(sizeof(uint32_t) + sizeof(uint32_t) + length) \ + serialize_u32(encrypted ? 0x02 : 0x01) \ + serialize_write(payload, length) + +#include "nem_serialize.h" + + } else { + +#define NEM_SERIALIZE \ + serialize_u32(0) + +#include "nem_serialize.h" + + } + + if (mosaics) { + +#define NEM_SERIALIZE \ + serialize_u32(mosaics) + +#include "nem_serialize.h" + + } + + return true; +} + +bool nem_transaction_write_mosaic(nem_transaction_ctx *ctx, + const char *namespace, + const char *mosaic, + uint64_t quantity) { + + size_t namespace_length = strlen(namespace); + size_t mosaic_length = strlen(mosaic); + size_t identifier_length = sizeof(uint32_t) + namespace_length + sizeof(uint32_t) + mosaic_length; + +#define NEM_SERIALIZE \ + serialize_u32(sizeof(uint32_t) + sizeof(uint64_t) + identifier_length) \ + serialize_u32(identifier_length) \ + serialize_write((uint8_t *) namespace, namespace_length) \ + serialize_write((uint8_t *) mosaic, mosaic_length) \ + serialize_u64(quantity) + +#include "nem_serialize.h" + + return true; +} + +bool nem_transaction_create_multisig(nem_transaction_ctx *ctx, + uint8_t network, + uint32_t timestamp, + const ed25519_public_key signer, + uint64_t fee, + uint32_t deadline, + const nem_transaction_ctx *inner) { + + if (!signer) { + signer = ctx->public_key; + } + + bool ret = nem_transaction_write_common(ctx, + NEM_TRANSACTION_TYPE_MULTISIG, + network << 24 | 1, + timestamp, + signer, + fee, + deadline); + if (!ret) return false; + +#define NEM_SERIALIZE \ + serialize_write(inner->buffer, inner->offset) + +#include "nem_serialize.h" + + return true; +} + +bool nem_transaction_create_multisig_signature(nem_transaction_ctx *ctx, + uint8_t network, + uint32_t timestamp, + const ed25519_public_key signer, + uint64_t fee, + uint32_t deadline, + const nem_transaction_ctx *inner) { + + if (!signer) { + signer = ctx->public_key; + } + + bool ret = nem_transaction_write_common(ctx, + NEM_TRANSACTION_TYPE_MULTISIG_SIGNATURE, + network << 24 | 1, + timestamp, + signer, + fee, + deadline); + if (!ret) return false; + + char address[NEM_ADDRESS_SIZE + 1]; + nem_get_address(inner->public_key, network, address); + + uint8_t hash[SHA3_256_DIGEST_LENGTH]; + keccak_256(inner->buffer, inner->offset, hash); + +#define NEM_SERIALIZE \ + serialize_u32(sizeof(uint32_t) + SHA3_256_DIGEST_LENGTH) \ + serialize_write(hash, SHA3_256_DIGEST_LENGTH) \ + serialize_write((uint8_t *) address, NEM_ADDRESS_SIZE) + +#include "nem_serialize.h" + + return true; +} + +bool nem_transaction_create_provision_namespace(nem_transaction_ctx *ctx, + uint8_t network, + uint32_t timestamp, + const ed25519_public_key signer, + uint64_t fee, + uint32_t deadline, + const char *namespace, + const char *parent, + const char *rental_sink, + uint64_t rental_fee) { + + if (!signer) { + signer = ctx->public_key; + } + + bool ret = nem_transaction_write_common(ctx, + NEM_TRANSACTION_TYPE_PROVISION_NAMESPACE, + network << 24 | 1, + timestamp, + signer, + fee, + deadline); + if (!ret) return false; + + if (parent) { + +#define NEM_SERIALIZE \ + serialize_write((uint8_t *) rental_sink, NEM_ADDRESS_SIZE) \ + serialize_u64(rental_fee) \ + serialize_write((uint8_t *) namespace, strlen(namespace)) \ + serialize_write((uint8_t *) parent, strlen(parent)) + +#include "nem_serialize.h" + + } else { + +#define NEM_SERIALIZE \ + serialize_write((uint8_t *) rental_sink, NEM_ADDRESS_SIZE) \ + serialize_u64(rental_fee) \ + serialize_write((uint8_t *) namespace, strlen(namespace)) \ + serialize_u32(0xffffffff) + +#include "nem_serialize.h" + + } + + return true; +} + +bool nem_transaction_create_mosaic_creation(nem_transaction_ctx *ctx, + uint8_t network, + uint32_t timestamp, + const ed25519_public_key signer, + uint64_t fee, + uint32_t deadline, + const char *namespace, + const char *mosaic, + const char *description, + uint32_t divisibility, + uint64_t supply, + bool mutable_supply, + bool transferable, + uint32_t levy_type, + uint64_t levy_fee, + const char *levy_address, + const char *levy_namespace, + const char *levy_mosaic, + const char *creation_sink, + uint64_t creation_fee) { + + if (!signer) { + signer = ctx->public_key; + } + + bool ret = nem_transaction_write_common(ctx, + NEM_TRANSACTION_TYPE_MOSAIC_CREATION, + network << 24 | 1, + timestamp, + signer, + fee, + deadline); + if (!ret) return false; + + size_t namespace_length = strlen(namespace); + size_t mosaic_length = strlen(mosaic); + size_t identifier_length = sizeof(uint32_t) + namespace_length + sizeof(uint32_t) + mosaic_length; + + // This length will be rewritten later on + nem_transaction_ctx state; + memcpy(&state, ctx, sizeof(state)); + +#define NEM_SERIALIZE \ + serialize_u32(0) \ + serialize_write(signer, sizeof(ed25519_public_key)) \ + serialize_u32(identifier_length) \ + serialize_write((uint8_t *) namespace, namespace_length) \ + serialize_write((uint8_t *) mosaic, mosaic_length) \ + serialize_write((uint8_t *) description, strlen(description)) \ + serialize_u32(4) // Number of properties + +#include "nem_serialize.h" + + if (!nem_write_mosaic_u64(ctx, "divisibility", divisibility)) return false; + if (!nem_write_mosaic_u64(ctx, "initialSupply", supply)) return false; + if (!nem_write_mosaic_bool(ctx, "supplyMutable", mutable_supply)) return false; + if (!nem_write_mosaic_bool(ctx, "transferable", transferable)) return false; + + if (levy_type) { + size_t levy_namespace_length = strlen(levy_namespace); + size_t levy_mosaic_length = strlen(levy_mosaic); + size_t levy_identifier_length = sizeof(uint32_t) + levy_namespace_length + sizeof(uint32_t) + levy_mosaic_length; + +#define NEM_SERIALIZE \ + serialize_u32(sizeof(uint32_t) + sizeof(uint32_t) + NEM_ADDRESS_SIZE + sizeof(uint32_t) + levy_identifier_length + sizeof(uint64_t)) \ + serialize_u32(levy_type) \ + serialize_write((uint8_t *) levy_address, NEM_ADDRESS_SIZE) \ + serialize_u32(levy_identifier_length) \ + serialize_write((uint8_t *) levy_namespace, levy_namespace_length) \ + serialize_write((uint8_t *) levy_mosaic, levy_mosaic_length) \ + serialize_u64(levy_fee) + +#include "nem_serialize.h" + + } else { + +#define NEM_SERIALIZE \ + serialize_u32(0) + +#include "nem_serialize.h" + + } + + // Rewrite length + nem_write_u32(&state, ctx->offset - state.offset - sizeof(uint32_t)); + +#define NEM_SERIALIZE \ + serialize_write((uint8_t *) creation_sink, NEM_ADDRESS_SIZE) \ + serialize_u64(creation_fee) + +#include "nem_serialize.h" + + return true; + +} + +bool nem_transaction_create_mosaic_supply_change(nem_transaction_ctx *ctx, + uint8_t network, + uint32_t timestamp, + const ed25519_public_key signer, + uint64_t fee, + uint32_t deadline, + const char *namespace, + const char *mosaic, + uint32_t type, + uint64_t delta) { + + if (!signer) { + signer = ctx->public_key; + } + + bool ret = nem_transaction_write_common(ctx, + NEM_TRANSACTION_TYPE_MOSAIC_SUPPLY_CHANGE, + network << 24 | 1, + timestamp, + signer, + fee, + deadline); + if (!ret) return false; + + size_t namespace_length = strlen(namespace); + size_t mosaic_length = strlen(mosaic); + size_t identifier_length = sizeof(uint32_t) + namespace_length + sizeof(uint32_t) + mosaic_length; + +#define NEM_SERIALIZE \ + serialize_u32(identifier_length) \ + serialize_write((uint8_t *) namespace, namespace_length) \ + serialize_write((uint8_t *) mosaic, mosaic_length) \ + serialize_u32(type) \ + serialize_u64(delta) + +#include "nem_serialize.h" + + return true; +} + +bool nem_transaction_create_aggregate_modification(nem_transaction_ctx *ctx, + uint8_t network, + uint32_t timestamp, + const ed25519_public_key signer, + uint64_t fee, + uint32_t deadline, + uint32_t modifications, + bool relative_change) { + + if (!signer) { + signer = ctx->public_key; + } + + bool ret = nem_transaction_write_common(ctx, + NEM_TRANSACTION_TYPE_AGGREGATE_MODIFICATION, + network << 24 | (relative_change ? 2 : 1), + timestamp, + signer, + fee, + deadline); + if (!ret) return false; + +#define NEM_SERIALIZE \ + serialize_u32(modifications) + +#include "nem_serialize.h" + + return true; +} + +bool nem_transaction_write_cosignatory_modification(nem_transaction_ctx *ctx, + uint32_t type, + const ed25519_public_key cosignatory) { + +#define NEM_SERIALIZE \ + serialize_u32(sizeof(uint32_t) + sizeof(uint32_t) + sizeof(ed25519_public_key)) \ + serialize_u32(type) \ + serialize_write(cosignatory, sizeof(ed25519_public_key)) + +#include "nem_serialize.h" + + return true; +} + +bool nem_transaction_write_minimum_cosignatories(nem_transaction_ctx *ctx, + int32_t relative_change) { + +#define NEM_SERIALIZE \ + serialize_u32(sizeof(uint32_t)) \ + serialize_u32((uint32_t) relative_change) + +#include "nem_serialize.h" + + return true; +} diff --git a/nem.h b/nem.h index 6e551a620..2e3de9480 100644 --- a/nem.h +++ b/nem.h @@ -24,8 +24,16 @@ #define __NEM_H__ #include +#include #include +#include "bip32.h" +#include "ed25519.h" + +#define NEM_LEVY_PERCENTILE_DIVISOR 4 +#define NEM_MAX_DIVISIBILITY 6 +#define NEM_MAX_SUPPLY 9000000000 + #define NEM_NETWORK_MAINNET 0x68 #define NEM_NETWORK_TESTNET 0x98 #define NEM_NETWORK_MIJIN 0x60 @@ -33,6 +41,21 @@ #define NEM_ADDRESS_SIZE 40 #define NEM_ADDRESS_SIZE_RAW 25 +#define NEM_TRANSACTION_TYPE_TRANSFER 0x0101 +#define NEM_TRANSACTION_TYPE_AGGREGATE_MODIFICATION 0x1001 +#define NEM_TRANSACTION_TYPE_MULTISIG_SIGNATURE 0x1002 +#define NEM_TRANSACTION_TYPE_MULTISIG 0x1004 +#define NEM_TRANSACTION_TYPE_PROVISION_NAMESPACE 0x2001 +#define NEM_TRANSACTION_TYPE_MOSAIC_CREATION 0x4001 +#define NEM_TRANSACTION_TYPE_MOSAIC_SUPPLY_CHANGE 0x4002 + +typedef struct { + ed25519_public_key public_key; + uint8_t *buffer; + size_t offset; + size_t size; +} nem_transaction_ctx; + const char *nem_network_name(uint8_t network); void nem_get_address_raw(const ed25519_public_key public_key, uint8_t version, uint8_t *address); @@ -41,4 +64,108 @@ bool nem_get_address(const ed25519_public_key public_key, uint8_t version, char bool nem_validate_address_raw(const uint8_t *address, uint8_t network); bool nem_validate_address(const char *address, uint8_t network); +void nem_transaction_start(nem_transaction_ctx *ctx, const ed25519_public_key public_key, uint8_t *buffer, size_t size); +size_t nem_transaction_end(nem_transaction_ctx *ctx, const ed25519_secret_key private_key, ed25519_signature signature); + +bool nem_transaction_write_common(nem_transaction_ctx *context, + uint32_t type, + uint32_t version, + uint32_t timestamp, + const ed25519_public_key signer, + uint64_t fee, + uint32_t deadline); + +bool nem_transaction_create_transfer(nem_transaction_ctx *context, + uint8_t network, + uint32_t timestamp, + const ed25519_public_key signer, + uint64_t fee, + uint32_t deadline, + const char *recipient, + uint64_t amount, + const uint8_t *payload, + uint32_t length, + bool encrypted, + uint32_t mosaics); + +bool nem_transaction_write_mosaic(nem_transaction_ctx *ctx, + const char *namespace, + const char *mosaic, + uint64_t quantity); + +bool nem_transaction_create_multisig(nem_transaction_ctx *ctx, + uint8_t network, + uint32_t timestamp, + const ed25519_public_key signer, + uint64_t fee, + uint32_t deadline, + const nem_transaction_ctx *inner); + +bool nem_transaction_create_multisig_signature(nem_transaction_ctx *ctx, + uint8_t network, + uint32_t timestamp, + const ed25519_public_key signer, + uint64_t fee, + uint32_t deadline, + const nem_transaction_ctx *inner); + +bool nem_transaction_create_provision_namespace(nem_transaction_ctx *ctx, + uint8_t network, + uint32_t timestamp, + const ed25519_public_key signer, + uint64_t fee, + uint32_t deadline, + const char *namespace, + const char *parent, + const char *rental_sink, + uint64_t rental_fee); + +bool nem_transaction_create_mosaic_creation(nem_transaction_ctx *ctx, + uint8_t network, + uint32_t timestamp, + const ed25519_public_key signer, + uint64_t fee, + uint32_t deadline, + const char *namespace, + const char *mosaic, + const char *description, + uint32_t divisibility, + uint64_t supply, + bool mutable_supply, + bool transferable, + uint32_t levy_type, + uint64_t levy_fee, + const char *levy_address, + const char *levy_namespace, + const char *levy_mosaic, + const char *creation_sink, + uint64_t creation_fee); + +bool nem_transaction_create_mosaic_supply_change(nem_transaction_ctx *ctx, + uint8_t network, + uint32_t timestamp, + const ed25519_public_key signer, + uint64_t fee, + uint32_t deadline, + const char *namespace, + const char *mosaic, + uint32_t type, + uint64_t delta); + +bool nem_transaction_create_aggregate_modification(nem_transaction_ctx *ctx, + uint8_t network, + uint32_t timestamp, + const ed25519_public_key signer, + uint64_t fee, + uint32_t deadline, + uint32_t modifications, + bool relative_change); + +bool nem_transaction_write_cosignatory_modification(nem_transaction_ctx *ctx, + uint32_t type, + const ed25519_public_key cosignatory); + +bool nem_transaction_write_minimum_cosignatories(nem_transaction_ctx *ctx, + int32_t relative_change); + #endif diff --git a/nem_serialize.h b/nem_serialize.h new file mode 100644 index 000000000..479581fcb --- /dev/null +++ b/nem_serialize.h @@ -0,0 +1,23 @@ +#define serialize_u32(data) + sizeof(uint32_t) +#define serialize_u64(data) + sizeof(uint64_t) +#define serialize_write(data, length) + (length) + +if (!nem_can_write(ctx, NEM_SERIALIZE)) { + return false; +} + +#undef serialize_u32 +#undef serialize_u64 +#undef serialize_write + +#define serialize_u32(data) nem_write_u32(ctx, (data)); +#define serialize_u64(data) nem_write_u64(ctx, (data)); +#define serialize_write(data, length) nem_write(ctx, (data), (length)); + +NEM_SERIALIZE + +#undef serialize_u32 +#undef serialize_u64 +#undef serialize_write + +#undef NEM_SERIALIZE From abda0f6504473b61ad25ab8e1eaff11134b779fe Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Thu, 1 Jun 2017 16:12:33 +0100 Subject: [PATCH 494/627] bip32: Add hdnode_nem_get_shared_key --- bip32.c | 20 ++++++++++++++++++++ bip32.h | 2 ++ 2 files changed, 22 insertions(+) diff --git a/bip32.c b/bip32.c index 1dadc9aa5..e58755071 100644 --- a/bip32.c +++ b/bip32.c @@ -456,6 +456,26 @@ int hdnode_get_nem_address(HDNode *node, uint8_t version, char *address) { hdnode_fill_public_key(node); return nem_get_address(&node->public_key[1], version, address); } + +int hdnode_get_nem_shared_key(const HDNode *node, const ed25519_public_key peer_public_key, const uint8_t *salt, ed25519_public_key mul, uint8_t *shared_key) { + if (node->curve != &ed25519_keccak_info) { + return 0; + } + + // sizeof(ed25519_public_key) == SHA3_256_DIGEST_LENGTH + if (mul == NULL) mul = shared_key; + + if (ed25519_scalarmult_keccak(mul, node->private_key, peer_public_key)) { + return 0; + } + + for (size_t i = 0; i < 32; i++) { + shared_key[i] = mul[i] ^ salt[i]; + } + + keccak_256(shared_key, 32, shared_key); + return 1; +} #endif // msg is a data to be signed diff --git a/bip32.h b/bip32.h index 83a285cff..3499fdc75 100644 --- a/bip32.h +++ b/bip32.h @@ -28,6 +28,7 @@ #include #include #include "ecdsa.h" +#include "ed25519.h" #include "options.h" typedef struct { @@ -74,6 +75,7 @@ int hdnode_get_ethereum_pubkeyhash(const HDNode *node, uint8_t *pubkeyhash); #if USE_NEM int hdnode_get_nem_address(HDNode *node, uint8_t version, char *address); +int hdnode_get_nem_shared_key(const HDNode *node, const ed25519_public_key peer_public_key, const uint8_t *salt, ed25519_public_key mul, uint8_t *shared_key); #endif int hdnode_sign(HDNode *node, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64])); From e1818468c79318e0e234be84c52d4cac80731990 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Thu, 1 Jun 2017 17:02:07 +0100 Subject: [PATCH 495/627] test_check: Add test_nem_derive --- test_check.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/test_check.c b/test_check.c index b99b1a251..4116410cf 100644 --- a/test_check.c +++ b/test_check.c @@ -3276,6 +3276,57 @@ START_TEST(test_nem_address) } END_TEST +// test vectors from https://raw.githubusercontent.com/NemProject/nem-test-vectors/master/3.test-derive.dat +START_TEST(test_nem_derive) +{ + static const struct { + const char *salt; + const char *private_key; + const char *public_key; + const char *mul; + const char *shared_key; + } tests[] = { + { "ad63ac08f9afc85eb0bf4f8881ca6eaa0215924c87aa2f137d56109bb76c6f98", "e8857f8e488d4e6d4b71bcd44bb4cff49208c32651e1f6500c3b58cafeb8def6", "9d8e5f200b05a2638fb084a375408cabd6d5989590d96e3eea5f2cb34668178e", "a8352060ba5718745ee4d78b9df564e0fbe13f50d50ab15a8dd524159d81d18b", "990a5f611c65fbcde735378bdec38e1039c5466503511e8c645bbe42795c752b", }, + { "96104f0a28f9cca40901c066cd435134662a3b053eb6c8df80ee0d05dc941963", "d7f67b5f52cbcd1a1367e0376a8eb1012b634acfcf35e8322bae8b22bb9e8dea", "9735c92d150dcee0ade5a8d1822f46a4db22c9cda25f33773ae856fe374a3e8a", "ea14d521d83328dba70982d42094300585818cc2da609fdb1f73bb32235576ff", "b498aa21d4ba4879ea9fd4225e93bacc760dcd9c119f8f38ab0716457d1a6f85", }, + { "d8f94a0bbb1de80aea17aab42e2ffb982e73fc49b649a318479e951e392d8728", "d026ddb445fb3bbf3020e4b55ed7b5f9b7fd1278c34978ca1a6ed6b358dadbae", "d19e6beca3b26b9d1abc127835ebeb7a6c19c33dec8ec472e1c4d458202f4ec8", "0d561f54728ad837ae108ec66c2ece2bb3b26041d3ee9b77fdc6d36d9ebfb2e3", "d012afe3d1d932304e613c91545bf571cf2c7281d6cafa8e81393a551f675540", }, + { "3f8c969678a8abdbfb76866a142c284a6f01636c1c1607947436e0d2c30d5245", "c522b38c391d1c3fa539cc58802bc66ac34bb3c73accd7f41b47f539bedcd016", "ea5b6a0053237f7712b1d2347c447d3e83e0f2191762d07e1f53f8eb7f2dfeaa", "23cccd3b63a9456e4425098b6df36f28c8999461a85e4b2b0c8d8f53c62c9ea9", "7e27efa50eed1c2ac51a12089cbab6a192624709c7330c016d5bc9af146584c1", }, + { "e66415c58b981c7f1f2b8f45a42149e9144616ff6de49ff83d97000ac6f6f992", "2f1b82be8e65d610a4e588f000a89a733a9de98ffc1ac9d55e138b3b0a855da0", "65aeda1b47f66c978a4a41d4dcdfbd8eab5cdeb135695c2b0c28f54417b1486d", "43e5b0a5cc8146c03ac63e6f8cf3d8825a9ca1ed53ea4a88304af4ddf5461b33", "bb4ab31c334e55d378937978c90bb33779b23cd5ef4c68342a394f4ec8fa1ada", }, + { "58487c9818c9d28ddf97cb09c13331941e05d0b62bf4c35ee368de80b552e4d1", "f3869b68183b2e4341307653e8f659bd7cd20e37ea5c00f5a9e203a8fa92359a", "c7e4153a18b4162f5c1f60e1ba483264aa5bb3f4889dca45b434fcd30b9cf56f", "5ae9408ab3156b8828c3e639730bd5e5db93d7afe2cee3fcda98079316c5bb3a", "0224d85ae8f17bfe127ec24b8960b7639a0dbde9c8c39a0575b939448687bb14", }, + { "ad66f3b654844e53d6fb3568134fae75672ba63868c113659d3ca58c2c39d24f", "d38f2ef8dfdc7224fef596130c3f4ff68ac83d3f932a56ee908061466ac28572", "d0c79d0340dc66f0a895ce5ad60a933cf6be659569096fb9d4b81e5d32292372", "1ea22db4708ed585ab541a4c70c3069f8e2c0c1faa188ddade3efaa53c8329f6", "886a7187246934aedf2794748deadfe038c9fd7e78d4b7be76c5a651440ac843", }, + { "eed48604eab279c6ad8128aa83483a3da0928271a4cae1a5745671284e1fb89d", "e2342a8450fc0adfa0ea2fbd0b1d28f100f0a3a905a3da29de34d1353afa7df7", "d2dbe07e0f2dbc3dbb01c70092e3c4247d12827ddcd8d76534fd740a65c30de2", "4c4b30eb6a2bfa17312f5729b4212cb51c2eee8fbfaea82a0e957ca68f4f6a30", "dcae613ac5641ff9d4c3ca58632245f93b0b8657fe4d48bac7b062cc53dd21ad", }, + { "f35b315287b268c0d0b386fb5b31810f65e1c4497cffae24527f69a3abac3884", "049016230dbef7a14a439e5ab2f6d12e78cb8df127db4e0c312673b3c361e350", "1b3b1925a8a535cd7d78725d25298f45bba8ca3dee2cdaabf14241c9b51b37c4", "04c9685dae1f8eb72a6438f24a87dc83a56d79c9024edf7e01aa1ae34656f29e", "b48469d0428c223b93cd1fe34bb2cafd3fb78a8fa15f98f89f1ac9c0ce7c9001", }, + { "d6cf082c5d9a96e756a94a2e27703138580a7c7c1af505c96c3abf7ab6802e1d", "67cd02b0b8b0adcf6fdd4d4d64a1f4193ced68bb8605d0ec941a62011326d140", "a842d5127c93a435e4672dcadd9fccbfd0e9208c79c5404848b298597eccdbdb", "d5c6bd6d81b99659d0bafe91025b6ecf73b16c6b07931cf44718b13f00fde3f7", "8aa160795b587f4be53aa35d26e9b618b4cd6ec765b523bc908e53c258ca8fd4", }, + { "dda32c91c95527a645b00dd05d13f0b98ed612a726ce5f5221431430b7660944", "eba026f92a8ffb5e95060a22e15d597fe838a99a0b2bbcb423c933b6bc718c50", "7dbaf9c313a1ff9128c54d6cd740c7d0cc46bca588e7910d438dd619ca4fd69a", "5bb20a145de83ba27a0c261e1f54bfd7dcea61888fc2eebbe6166876f7b000b8", "3a96f152ad8bf355cccb307e4a40108aa17f8e925522a2b5bb0b3f1e1a262914", }, + { "63c500acbd4ff747f7dadde7d3286482894ac4d7fe68f396712bca29879aa65c", "9663cd3c2030a5fe4a3ea3cc9a1d182b3a63ade68616aaeb4caf40b495f6f227", "b1e7d9070ac820d986d839b79f7aa594dcf708473529dad87af8682cc6197374", "1f7a97584d8db9f395b9ac4447de4b33c5c1f5020187cd4996286a49b07eb8a7", "4d2a974ec12dcf525b5654d31053460850c3092648b7e15598b7131d2930e9fb", }, + { "91f340961029398cc8bcd906388044a6801d24328efdf919d8ed0c609862a073", "45a588500d00142e2226231c01fd11ac6f842ab6a85872418f5b6a1999f8bd98", "397233c96069b6f4a57d6e93f759fa327222eaef71fc981afa673b248206df3f", "062123ef9782e3893f7b2e1d557b4ecce92b9f9aa8577e76380f228b75152f84", "235848cb04230a16d8978aa7c19fe7fbff3ebe29389ea6eb24fb8bc3cb50afc6", }, + { "46120b4da6ba4eb54fb65213cfef99b812c86f7c42a1de1107f8e8c12c0c3b6b", "cc19a97a99ad71ce348bcf831c0218e6a1f0a8d52186cabe6298b56f24e640f9", "c54631bb62f0f9d86b3301fcb2a671621e655e578c95504af5f78da83f7fec4f", "ab73cc20c75260ff3a7cefea8039291d4d15114a07a9250375628cca32225bb6", "70040a360b6a2dfa881272ef4fa6616e2e8fcc45194fa2a21a1eef1160271cd5", }, + { "f0a69ded09f1d731ab9561d0c3a40b7ef30bcb2bf60f92beccd8734e2441403d", "ea732822a381c46a7ac9999bf5ef85e16b7460b26aaf6c1a1c6ffa8c8c82c923", "110decbff79c382b1e60af4259564a3c473087792350b24fca98ae9a74ba9dd9", "81bdee95aecdcf821a9d682f79056f1abdcf1245d2f3b55244447881a283e0d4", "1bc29d4470ccf97d4e35e8d3cd4b12e3ebf2cb0a82425d35984aeedf7ad0f6f9", }, + { "e79cf4536fb1547e57626c0f1a87f71a396fdfb985b00731c0c2876a00645eda", "04213fc02b59c372e3e7f53faa71a2f73b31064102cb6fc8b68432ba7cdf7eb4", "ca1c750aaed53bc30dac07d0696ed86bcd7cdbbcbd3d15bb90d90cb5c6117bac", "c68cd0872a42a3a64e8a229ef7fcad3d722047d5af966f7dda4d4e32d0d57203", "bfdd3d07563d966d95afe4b8abea4b567265fceea8c4ecddb0946256c33e07b2", }, + { "81a40db4cddaf076e0206bd2b0fa7470a72cc456bad34aa3a0469a4859f286be", "52156799fd86cc63345cdbffd65ef4f5f8df0ffd9906a40af5f41d269bbcff5d", "54d61aa0b0b17a87f1376fe89cd8cd6b314827c1f1b9e5e7b20e7a7eee2a8335", "4553fb2cab8555068c32f86ceb692bbf1c2beeaf21627ef1b1be57344b52eea8", "55096b6710ade3bbe38702458ee13faa10c24413261bc076f17675dcbf2c4ee6", }, + { "d28e4a9e6832a3a4dad014a2bf1f666f01093cbba8b9ad4d1dcad3ea10cb42b9", "8ca134404c8fa199b0c72cb53cfa0adcf196dfa560fb521017cce5cbace3ba59", "3a6c39a1e5f9f550f1debedd9a0bc84210cce5f9834797db8f14122bf5817e45", "eb632ca818b4f659630226a339a3ce536b31c8e1e686fea8da3760e8abc20b8e", "9fbb3fbaf1cd54ee0cd90685f59b082545983f1f662ef701332379306a6ad546", }, + { "f9c4bfad9e2a3d98c44c12734881a6f217d6c9523cc210772fad1297993454b4", "b85960fcadda8d0a0960559b6b7818a0d8d4574b4e928b17c9b498fa9ffab4ef", "6a1d0ef23ce0b40a7077ecb7b7264945054e3bdb58ee25e1b0ee8b3e19dbfcdc", "bb145dddcb75074a6a03249fca1aa7d6fa9549e3ed965f138ca5e7071b7878f2", "87d3faea4a98e41009eb8625611ea0fc12094c295af540c126c14a0f55afa76e", }, + { "656df4789a369d220aceb7b318517787d27004ecccedea019d623bcb2d79f5ff", "acf83e30afb2a5066728ec5d93564c08abe5e68e3a2a2ff953bdcf4d44f9da06", "bdda65efe56d7890286aada1452f62f85ba157d0b4621ba641de15d8d1c9e331", "958beef5dc6babc6de383c32ad7dd3a6d6eb8bb3236ed5558eec0f9eb31e5458", "6f6d4ee36d9d76e462c9635adfbb6073134a276cfc7cb86762004ec47197afa0", }, + }; + + HDNode node; + ed25519_secret_key private_key; + uint8_t chain_code[32]; + ed25519_public_key public_key, mul; + uint8_t shared_key[SHA3_256_DIGEST_LENGTH]; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + nem_private_key(tests[i].private_key, private_key); + + ck_assert(hdnode_from_xprv(0, 0, chain_code, private_key, ED25519_KECCAK_NAME, &node)); + memcpy(public_key, fromhex(tests[i].public_key), 32); + + ck_assert(hdnode_get_nem_shared_key(&node, public_key, fromhex(tests[i].salt), mul, shared_key)); + ck_assert_mem_eq(mul, fromhex(tests[i].mul), sizeof(mul)); + ck_assert_mem_eq(shared_key, fromhex(tests[i].shared_key), sizeof(shared_key)); + } +} +END_TEST + START_TEST(test_multibyte_address) { uint8_t priv_key[32]; @@ -3736,6 +3787,10 @@ Suite *test_suite(void) tcase_add_test(tc, test_nem_address); suite_add_tcase(s, tc); + tc = tcase_create("nem_encryption"); + tcase_add_test(tc, test_nem_derive); + suite_add_tcase(s, tc); + tc = tcase_create("multibyte_address"); tcase_add_test(tc, test_multibyte_address); suite_add_tcase(s, tc); From ce0f3919e3685c53e5af4aca1c3efed9806f6a7a Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sun, 11 Jun 2017 17:28:07 +0100 Subject: [PATCH 496/627] bip32: Add hdnode_nem_{en,de}crypt --- bip32.c | 60 +++++++++++++++++++++++++++++++++++++++ bip32.h | 2 ++ nem.h | 8 ++++++ tools/nem_test_vectors.rb | 3 ++ 4 files changed, 73 insertions(+) diff --git a/bip32.c b/bip32.c index e58755071..7c3417c91 100644 --- a/bip32.c +++ b/bip32.c @@ -25,6 +25,7 @@ #include #include +#include "aes.h" #include "address.h" #include "bignum.h" #include "hmac.h" @@ -476,6 +477,65 @@ int hdnode_get_nem_shared_key(const HDNode *node, const ed25519_public_key peer_ keccak_256(shared_key, 32, shared_key); return 1; } + +int hdnode_nem_encrypt(const HDNode *node, const ed25519_public_key public_key, uint8_t *iv, const uint8_t *salt, const uint8_t *payload, size_t size, uint8_t *buffer) { + uint8_t last_block[AES_BLOCK_SIZE]; + uint8_t remainder = size % AES_BLOCK_SIZE; + + // Round down to last whole block + size -= remainder; + // Copy old last block + memcpy(last_block, &payload[size], remainder); + // Pad new last block with number of missing bytes + memset(&last_block[remainder], AES_BLOCK_SIZE - remainder, AES_BLOCK_SIZE - remainder); + + uint8_t shared_key[SHA3_256_DIGEST_LENGTH]; + if (!hdnode_get_nem_shared_key(node, public_key, salt, NULL, shared_key)) { + return 0; + } + + aes_encrypt_ctx ctx; + + int ret = aes_encrypt_key256(shared_key, &ctx); + MEMSET_BZERO(shared_key, sizeof(shared_key)); + + if (ret != EXIT_SUCCESS) { + return 0; + } + + if (aes_cbc_encrypt(payload, buffer, size, iv, &ctx) != EXIT_SUCCESS) { + return 0; + } + + if (aes_cbc_encrypt(last_block, &buffer[size], sizeof(last_block), iv, &ctx) != EXIT_SUCCESS) { + return 0; + } + + return 1; +} + +int hdnode_nem_decrypt(const HDNode *node, const ed25519_public_key public_key, uint8_t *iv, const uint8_t *salt, const uint8_t *payload, size_t size, uint8_t *buffer) { + uint8_t shared_key[SHA3_256_DIGEST_LENGTH]; + + if (!hdnode_get_nem_shared_key(node, public_key, salt, NULL, shared_key)) { + return 0; + } + + aes_decrypt_ctx ctx; + + int ret = aes_decrypt_key256(shared_key, &ctx); + MEMSET_BZERO(shared_key, sizeof(shared_key)); + + if (ret != EXIT_SUCCESS) { + return 0; + } + + if (aes_cbc_decrypt(payload, buffer, size, iv, &ctx) != EXIT_SUCCESS) { + return 0; + } + + return 1; +} #endif // msg is a data to be signed diff --git a/bip32.h b/bip32.h index 3499fdc75..043c50c58 100644 --- a/bip32.h +++ b/bip32.h @@ -76,6 +76,8 @@ int hdnode_get_ethereum_pubkeyhash(const HDNode *node, uint8_t *pubkeyhash); #if USE_NEM int hdnode_get_nem_address(HDNode *node, uint8_t version, char *address); int hdnode_get_nem_shared_key(const HDNode *node, const ed25519_public_key peer_public_key, const uint8_t *salt, ed25519_public_key mul, uint8_t *shared_key); +int hdnode_nem_encrypt(const HDNode *node, const ed25519_public_key public_key, uint8_t *iv, const uint8_t *salt, const uint8_t *payload, size_t size, uint8_t *buffer); +int hdnode_nem_decrypt(const HDNode *node, const ed25519_public_key public_key, uint8_t *iv, const uint8_t *salt, const uint8_t *payload, size_t size, uint8_t *buffer); #endif int hdnode_sign(HDNode *node, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64])); diff --git a/nem.h b/nem.h index 2e3de9480..f4b181a00 100644 --- a/nem.h +++ b/nem.h @@ -49,6 +49,14 @@ #define NEM_TRANSACTION_TYPE_MOSAIC_CREATION 0x4001 #define NEM_TRANSACTION_TYPE_MOSAIC_SUPPLY_CHANGE 0x4002 +#define NEM_SALT_SIZE sizeof(ed25519_public_key) + +#define NEM_ENCRYPTED_SIZE(size) (((size) + AES_BLOCK_SIZE - 1) / AES_BLOCK_SIZE * AES_BLOCK_SIZE) +#define NEM_ENCRYPTED_PAYLOAD_SIZE(size) (AES_BLOCK_SIZE + NEM_SALT_SIZE + NEM_ENCRYPTED_SIZE(size)) + +#define NEM_DECRYPTED_SIZE(buffer, size) ((size) - ((buffer)[(size) - 1])) +#define NEM_DECRYPTED_PAYLOAD_SIZE(buffer, size) NEM_DECRYPTED_SIZE((buffer), (size) - AES_BLOCK_SIZE - NEM_SALT_SIZE) + typedef struct { ed25519_public_key public_key; uint8_t *buffer; diff --git a/tools/nem_test_vectors.rb b/tools/nem_test_vectors.rb index 8d43239cd..9bb487927 100755 --- a/tools/nem_test_vectors.rb +++ b/tools/nem_test_vectors.rb @@ -59,6 +59,9 @@ end def load_data_line(line) abort 'Line does not begin with colon' unless line.slice!(0) == ':' + line.strip! + line.chomp!(',') + values = line.split(':').each(&:strip!) values.pop if values.last.empty? From 3808a30381a225f393b6de9580f5257f4100f852 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sun, 25 Jun 2017 18:23:14 +0100 Subject: [PATCH 497/627] test_check: Add test_nem_cipher --- test_check.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/test_check.c b/test_check.c index 4116410cf..a4e84c814 100644 --- a/test_check.c +++ b/test_check.c @@ -3327,6 +3327,77 @@ START_TEST(test_nem_derive) } END_TEST +// test vectors from https://raw.githubusercontent.com/NemProject/nem-test-vectors/master/4.test-cipher.dat +START_TEST(test_nem_cipher) +{ + static const struct { + const char *private_key; + const char *public_key; + const char *salt; + const char *iv; + const char *input; + const char *output; + } tests[] = { + { "3140f94c79f249787d1ec75a97a885980eb8f0a7d9b7aa03e7200296e422b2b6", "57a70eb553a7b3fd621f0dba6abf51312ea2e2a2a1e19d0305516730f4bcbd21", "83616c67f076d356fd1288a6e0fd7a60488ba312a3adf0088b1b33c7655c3e6a", "a73ff5c32f8fd055b09775817a6a3f95", "86ddb9e713a8ebf67a51830eff03b837e147c20d75e67b2a54aa29e98c", "70815da779b1b954d7a7f00c16940e9917a0412a06a444b539bf147603eef87f", }, + { "3140f94c79f249787d1ec75a97a885980eb8f0a7d9b7aa03e7200296e422b2b6", "57a70eb553a7b3fd621f0dba6abf51312ea2e2a2a1e19d0305516730f4bcbd21", "703ce0b1d276b10eef35672df03234385a903460db18ba9d4e05b3ad31abb284", "91246c2d5493867c4fa3e78f85963677", "86ddb9e713a8ebf67a51830eff03b837e147c20d75e67b2a54aa29e98c", "564b2f40d42c0efc1bd6f057115a5abd1564cae36d7ccacf5d825d38401aa894", }, + { "3140f94c79f249787d1ec75a97a885980eb8f0a7d9b7aa03e7200296e422b2b6", "57a70eb553a7b3fd621f0dba6abf51312ea2e2a2a1e19d0305516730f4bcbd21", "b22e8e8e7373ac31ca7f0f6eb8b93130aba5266772a658593f3a11792e7e8d92", "9f8e33d82374dad6aac0e3dbe7aea704", "86ddb9e713a8ebf67a51830eff03b837e147c20d75e67b2a54aa29e98c", "7cab88d00a3fc656002eccbbd966e1d5d14a3090d92cf502cdbf843515625dcf", }, + { "3140f94c79f249787d1ec75a97a885980eb8f0a7d9b7aa03e7200296e422b2b6", "57a70eb553a7b3fd621f0dba6abf51312ea2e2a2a1e19d0305516730f4bcbd21", "af646c54cd153dffe453b60efbceeb85c1e95a414ea0036c4da94afb3366f5d9", "6acdf8e01acc8074ddc807281b6af888", "86ddb9e713a8ebf67a51830eff03b837e147c20d75e67b2a54aa29e98c", "aa70543a485b63a4dd141bb7fd78019092ac6fad731e914280a287c7467bae1a", }, + { "3140f94c79f249787d1ec75a97a885980eb8f0a7d9b7aa03e7200296e422b2b6", "57a70eb553a7b3fd621f0dba6abf51312ea2e2a2a1e19d0305516730f4bcbd21", "d9c0d386636c8a024935c024589f9cd39e820a16485b14951e690a967830e269", "f2e9f18aeb374965f54d2f4e31189a8f", "86ddb9e713a8ebf67a51830eff03b837e147c20d75e67b2a54aa29e98c", "33d97c216ea6498dfddabf94c2e2403d73efc495e9b284d9d90aaff840217d25", }, + { "d5c0762ecea2cd6b5c56751b58debcb32713aab348f4a59c493e38beb3244f3a", "66a35941d615b5644d19c2a602c363ada8b1a8a0dac3682623852dcab4afac04", "06c227baac1ae3b0b1dc583f4850f13f9ba5d53be4a98fa5c3ea16217847530d", "3735123e78c44895df6ea33fa57e9a72", "86ddb9e713a8ebf67a51830eff03b837e147c20d75e67b2a54aa29e98c", "d5b5d66ba8cee0eb7ecf95b143fa77a46d6de13749e12eff40f5a7e649167ccb", }, + { "d5c0762ecea2cd6b5c56751b58debcb32713aab348f4a59c493e38beb3244f3a", "66a35941d615b5644d19c2a602c363ada8b1a8a0dac3682623852dcab4afac04", "92f55ba5bc6fc2f23e3eedc299357c71518e36ba2447a4da7a9dfe9dfeb107b5", "1cbc4982e53e370052af97ab088fa942", "86ddb9e713a8ebf67a51830eff03b837e147c20d75e67b2a54aa29e98c", "d48ef1ef526d805656cfc932aff259eadb17aa3391dde1877a722cba31d935b2", }, + { "d5c0762ecea2cd6b5c56751b58debcb32713aab348f4a59c493e38beb3244f3a", "66a35941d615b5644d19c2a602c363ada8b1a8a0dac3682623852dcab4afac04", "10f15a39ba49866292a43b7781bc71ca8bbd4889f1616461caf056bcb91b0158", "c40d531d92bfee969dce91417346c892", "49de3cd5890e0cd0559f143807ff688ff62789b7236a332b7d7255ec0b4e73e6b3a4", "e6d75afdb542785669b42198577c5b358d95397d71ec6f5835dca46d332cc08dbf73ea790b7bcb169a65719c0d55054c", }, + { "d5c0762ecea2cd6b5c56751b58debcb32713aab348f4a59c493e38beb3244f3a", "66a35941d615b5644d19c2a602c363ada8b1a8a0dac3682623852dcab4afac04", "9c01ed42b219b3bbe1a43ae9d7af5c1dd09363baacfdba8f4d03d1046915e26e", "059a35d5f83249e632790015ed6518b9", "49de3cd5890e0cd0559f143807ff688ff62789b7236a332b7d7255ec0b4e73e6b3a4", "5ef11aadff2eccee8b712dab968fa842eb770818ec0e6663ed242ea8b6bbc1c66d6285ee5b5f03d55dfee382fb4fa25d", }, + { "d5c0762ecea2cd6b5c56751b58debcb32713aab348f4a59c493e38beb3244f3a", "66a35941d615b5644d19c2a602c363ada8b1a8a0dac3682623852dcab4afac04", "bc1067e2a7415ea45ff1ca9894338c591ff15f2e57ae2789ae31b9d5bea0f11e", "8c73f0d6613898daeefa3cf8b0686d37", "49de3cd5890e0cd0559f143807ff688ff62789b7236a332b7d7255ec0b4e73e6b3a4", "6d220213b1878cd40a458f2a1e6e3b48040455fdf504dcd857f4f2ca1ad642e3a44fc401d04e339d302f66a9fad3d919", }, + { "9ef87ba8aa2e664bdfdb978b98bc30fb61773d9298e7b8c72911683eeff41921", "441e76d7e53be0a967181076a842f69c20fd8c0e3f0ce3aa421b490b059fe094", "cf4a21cb790552165827b678ca9695fcaf77566d382325112ff79483455de667", "bfbf5482e06f55b88bdd9e053b7eee6e", "49de3cd5890e0cd0559f143807ff688ff62789b7236a332b7d7255ec0b4e73e6b3a4", "1198a78c29c215d5c450f7b8513ead253160bc9fde80d9cc8e6bee2efe9713cf5a09d6293c41033271c9e8c22036a28b", }, + { "9ef87ba8aa2e664bdfdb978b98bc30fb61773d9298e7b8c72911683eeff41921", "441e76d7e53be0a967181076a842f69c20fd8c0e3f0ce3aa421b490b059fe094", "eba5eae8aef79114082c3e70baef95bb02edf13b3897e8be7a70272962ef8838", "af9a56da3da18e2fbd2948a16332532b", "49de3cd5890e0cd0559f143807ff688ff62789b7236a332b7d7255ec0b4e73e6b3a4", "1062ab5fbbdee9042ad35bdadfd3047c0a2127fe0f001da1be1b0582185edfc9687be8d68f85795833bb04af9cedd3bb", }, + { "9ef87ba8aa2e664bdfdb978b98bc30fb61773d9298e7b8c72911683eeff41921", "441e76d7e53be0a967181076a842f69c20fd8c0e3f0ce3aa421b490b059fe094", "518f8dfd0c138f1ffb4ea8029db15441d70abd893c3d767dc668f23ba7770e27", "42d28307974a1b2a2d921d270cfce03b", "49de3cd5890e0cd0559f143807ff688ff62789b7236a332b7d7255ec0b4e73e6b3a4", "005e49fb7c5da540a84b034c853fc9f78a6b901ea495aed0c2abd4f08f1a96f9ffefc6a57f1ac09e0aea95ca0f03ffd8", }, + { "9ef87ba8aa2e664bdfdb978b98bc30fb61773d9298e7b8c72911683eeff41921", "441e76d7e53be0a967181076a842f69c20fd8c0e3f0ce3aa421b490b059fe094", "582fdf58b53715c26e10ba809e8f2ab70502e5a3d4e9a81100b7227732ab0bbc", "91f2aad3189bb2edc93bc891e73911ba", "49de3cd5890e0cd0559f143807ff688ff62789b7236a332b7d7255ec0b4e73e6b3a4", "821a69cb16c57f0cb866e590b38069e35faec3ae18f158bb067db83a11237d29ab1e6b868b3147236a0958f15c2e2167", }, + { "9ef87ba8aa2e664bdfdb978b98bc30fb61773d9298e7b8c72911683eeff41921", "441e76d7e53be0a967181076a842f69c20fd8c0e3f0ce3aa421b490b059fe094", "a415b4c006118fb72fc37b2746ef288e23ac45c8ff7ade5f368a31557b6ac93a", "2b7c5f75606c0b8106c6489ea5657a9e", "24512b714aefd5cbc4bcc4ef44ce6c67ffc447c65460a6c6e4a92e85", "2781d5ee8ef1cb1596f8902b33dfae5045f84a987ca58173af5830dbce386062", }, + { "ed93c5a101ab53382ceee4f7e6b5aa112621d3bb9d18891509b1834ede235bcc", "5a5e14c633d7d269302849d739d80344ff14db51d7bcda86045723f05c4e4541", "47e73ec362ea82d3a7c5d55532ad51d2cdf5316b981b2b2bd542b0efa027e8ea", "b2193f59030c8d05a7d3577b7f64dd33", "24512b714aefd5cbc4bcc4ef44ce6c67ffc447c65460a6c6e4a92e85", "3f43912db8dd6672b9996e5272e18c4b88fec9d7e8372db9c5f4709a4af1d86f", }, + { "ed93c5a101ab53382ceee4f7e6b5aa112621d3bb9d18891509b1834ede235bcc", "5a5e14c633d7d269302849d739d80344ff14db51d7bcda86045723f05c4e4541", "aaa006c57b6d1e402650577fe9787d8d285f4bacd7c01f998be49c766f8860c7", "130304ddb9adc8870cf56bcae9487b7f", "24512b714aefd5cbc4bcc4ef44ce6c67ffc447c65460a6c6e4a92e85", "878cc7d8c0ef8dac0182a78eedc8080a402f59d8062a6b4ca8f4a74f3c3b3de7", }, + { "ed93c5a101ab53382ceee4f7e6b5aa112621d3bb9d18891509b1834ede235bcc", "5a5e14c633d7d269302849d739d80344ff14db51d7bcda86045723f05c4e4541", "28dc7ccd6c2a939eef64b8be7b9ae248295e7fcd8471c22fa2f98733fea97611", "cb13890d3a11bc0a7433738263006710", "24512b714aefd5cbc4bcc4ef44ce6c67ffc447c65460a6c6e4a92e85", "e74ded846bebfa912fa1720e4c1415e6e5df7e7a1a7fedb5665d68f1763209a4", }, + { "ed93c5a101ab53382ceee4f7e6b5aa112621d3bb9d18891509b1834ede235bcc", "5a5e14c633d7d269302849d739d80344ff14db51d7bcda86045723f05c4e4541", "79974fa2cad95154d0873902c153ccc3e7d54b17f2eeb3f29b6344cad9365a9a", "22123357979d20f44cc8eb0263d84e0e", "24512b714aefd5cbc4bcc4ef44ce6c67ffc447c65460a6c6e4a92e85", "eb14dec7b8b64d81a2ee4db07b0adf144d4f79a519bbf332b823583fa2d45405", }, + { "ed93c5a101ab53382ceee4f7e6b5aa112621d3bb9d18891509b1834ede235bcc", "5a5e14c633d7d269302849d739d80344ff14db51d7bcda86045723f05c4e4541", "3409a6f8c4dcd9bd04144eb67e55a98696b674735b01bf1196191f29871ef966", "a823a0965969380ea1f8659ea5fd8fdd", "24512b714aefd5cbc4bcc4ef44ce6c67ffc447c65460a6c6e4a92e85", "00a7eb708eae745847173f8217efb05be13059710aee632e3f471ac3c6202b51", }, + }; + + HDNode node; + ed25519_secret_key private_key; + uint8_t chain_code[32]; + ed25519_public_key public_key; + uint8_t salt[sizeof(public_key)]; + + uint8_t iv[AES_BLOCK_SIZE]; + uint8_t buffer[FROMHEX_MAXLEN]; + + uint8_t input[FROMHEX_MAXLEN]; + uint8_t output[FROMHEX_MAXLEN]; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + nem_private_key(tests[i].private_key, private_key); + + ck_assert(hdnode_from_xprv(0, 0, chain_code, private_key, ED25519_KECCAK_NAME, &node)); + memcpy(public_key, fromhex(tests[i].public_key), 32); + memcpy(salt, fromhex(tests[i].salt), sizeof(salt)); + + size_t input_size = strlen(tests[i].input) / 2; + size_t output_size = strlen(tests[i].output) / 2; + + memcpy(input, fromhex(tests[i].input), input_size); + memcpy(output, fromhex(tests[i].output), output_size); + + memcpy(iv, fromhex(tests[i].iv), sizeof(iv)); + ck_assert(hdnode_nem_encrypt(&node, public_key, iv, salt, input, input_size, buffer)); + ck_assert_int_eq(output_size, NEM_ENCRYPTED_SIZE(input_size)); + ck_assert_mem_eq(buffer, output, output_size); + + memcpy(iv, fromhex(tests[i].iv), sizeof(iv)); + ck_assert(hdnode_nem_decrypt(&node, public_key, iv, salt, output, output_size, buffer)); + ck_assert_int_eq(input_size, NEM_DECRYPTED_SIZE(buffer, output_size)); + ck_assert_mem_eq(buffer, input, input_size); + } +} +END_TEST + START_TEST(test_multibyte_address) { uint8_t priv_key[32]; @@ -3789,6 +3860,7 @@ Suite *test_suite(void) tc = tcase_create("nem_encryption"); tcase_add_test(tc, test_nem_derive); + tcase_add_test(tc, test_nem_cipher); suite_add_tcase(s, tc); tc = tcase_create("multibyte_address"); From 9c919856747a6a519e5a553cc9b67f1c408337af Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Mon, 24 Jul 2017 13:47:12 +0100 Subject: [PATCH 498/627] test_check: Add nem_transaction test case --- test_check.c | 395 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 395 insertions(+) diff --git a/test_check.c b/test_check.c index a4e84c814..cf59bcade 100644 --- a/test_check.c +++ b/test_check.c @@ -3398,6 +3398,392 @@ START_TEST(test_nem_cipher) } END_TEST +START_TEST(test_nem_transaction_transfer) +{ + nem_transaction_ctx ctx; + + uint8_t buffer[1024], hash[SHA3_256_DIGEST_LENGTH]; + + // http://bob.nem.ninja:8765/#/transfer/0acbf8df91e6a65dc56c56c43d65f31ff2a6a48d06fc66e78c7f3436faf3e74f + + nem_transaction_start(&ctx, fromhex("e59ef184a612d4c3c4d89b5950eb57262c69862b2f96e59c5043bf41765c482f"), buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_transfer(&ctx, + NEM_NETWORK_TESTNET, 0, NULL, 0, 0, + "TBGIMRE4SBFRUJXMH7DVF2IBY36L2EDWZ37GVSC4", 50000000000000, + NULL, 0, false, + 0)); + + keccak_256(ctx.buffer, ctx.offset, hash); + ck_assert_mem_eq(hash, fromhex("0acbf8df91e6a65dc56c56c43d65f31ff2a6a48d06fc66e78c7f3436faf3e74f"), sizeof(hash)); + + // http://bob.nem.ninja:8765/#/transfer/3409d9ece28d6296d6d5e220a7e3cb8641a3fb235ffcbd20c95da64f003ace6c + + nem_transaction_start(&ctx, fromhex("994793ba1c789fa9bdea918afc9b06e2d0309beb1081ac5b6952991e4defd324"), buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_transfer(&ctx, + NEM_NETWORK_TESTNET, 14072100, NULL, 194000000, 14075700, + "TBLOODPLWOWMZ2TARX4RFPOSOWLULHXMROBN2WXI", 3000000, + (uint8_t *) "sending you 3 pairs of paddles\n", 31, false, + 2)); + + ck_assert(nem_transaction_write_mosaic(&ctx, + "gimre.games.pong", "paddles", 2)); + + ck_assert(nem_transaction_write_mosaic(&ctx, + "nem", "xem", 44000000)); + + keccak_256(ctx.buffer, ctx.offset, hash); + ck_assert_mem_eq(hash, fromhex("3409d9ece28d6296d6d5e220a7e3cb8641a3fb235ffcbd20c95da64f003ace6c"), sizeof(hash)); + + // http://chain.nem.ninja/#/transfer/e90e98614c7598fbfa4db5411db1b331d157c2f86b558fb7c943d013ed9f71cb + + nem_transaction_start(&ctx, fromhex("8d07f90fb4bbe7715fa327c926770166a11be2e494a970605f2e12557f66c9b9"), buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_transfer(&ctx, + NEM_NETWORK_MAINNET, 0, NULL, 0, 0, + "NBT3WHA2YXG2IR4PWKFFMO772JWOITTD2V4PECSB", 5175000000000, + (uint8_t *) "Good luck!", 10, false, + 0)); + + keccak_256(ctx.buffer, ctx.offset, hash); + ck_assert_mem_eq(hash, fromhex("e90e98614c7598fbfa4db5411db1b331d157c2f86b558fb7c943d013ed9f71cb"), sizeof(hash)); + + // http://chain.nem.ninja/#/transfer/40e89160e6f83d37f7c82defc0afe2c1605ae8c919134570a51dd27ea1bb516c + + nem_transaction_start(&ctx, fromhex("f85ab43dad059b9d2331ddacc384ad925d3467f03207182e01296bacfb242d01"), buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_transfer(&ctx, + NEM_NETWORK_MAINNET, 77229, NULL, 30000000, 80829, + "NALICEPFLZQRZGPRIJTMJOCPWDNECXTNNG7QLSG3", 30000000, + fromhex("4d9dcf9186967d30be93d6d5404ded22812dbbae7c3f0de5" + "01bcd7228cba45bded13000eec7b4c6215fc4d3588168c92" + "18167cec98e6977359153a4132e050f594548e61e0dc61c1" + "53f0f53c5e65c595239c9eb7c4e7d48e0f4bb8b1dd2f5ddc"), 96, true, + 0)); + + keccak_256(ctx.buffer, ctx.offset, hash); + ck_assert_mem_eq(hash, fromhex("40e89160e6f83d37f7c82defc0afe2c1605ae8c919134570a51dd27ea1bb516c"), sizeof(hash)); + + // http://chain.nem.ninja/#/transfer/882dca18dcbe075e15e0ec5a1d7e6ccd69cc0f1309ffd3fde227bfbc107b3f6e + + nem_transaction_start(&ctx, fromhex("f85ab43dad059b9d2331ddacc384ad925d3467f03207182e01296bacfb242d01"), buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_transfer(&ctx, + NEM_NETWORK_MAINNET, 26730750, NULL, 179500000, 26734350, + "NBE223WPKEBHQPCYUC4U4CDUQCRRFMPZLOQLB5OP", 1000000, + (uint8_t *) "enjoy! :)", 9, false, + 1)); + + ck_assert(nem_transaction_write_mosaic(&ctx, + "imre.g", "tokens", 1)); + + keccak_256(ctx.buffer, ctx.offset, hash); + ck_assert_mem_eq(hash, fromhex("882dca18dcbe075e15e0ec5a1d7e6ccd69cc0f1309ffd3fde227bfbc107b3f6e"), sizeof(hash)); +} +END_TEST + +START_TEST(test_nem_transaction_multisig) +{ + nem_transaction_ctx ctx, other_trans; + + uint8_t buffer[1024], inner[1024]; + const uint8_t *signature; + + // http://bob.nem.ninja:8765/#/multisig/7d3a7087023ee29005262016706818579a2b5499eb9ca76bad98c1e6f4c46642 + + nem_transaction_start(&other_trans, fromhex("abac2ee3d4aaa7a3bfb65261a00cc04c761521527dd3f2cf741e2815cbba83ac"), inner, sizeof(inner)); + + ck_assert(nem_transaction_create_aggregate_modification(&other_trans, + NEM_NETWORK_TESTNET, 3939039, NULL, 16000000, 3960639, + 1, false)); + + ck_assert(nem_transaction_write_cosignatory_modification(&other_trans, 2, fromhex("e6cff9b3725a91f31089c3acca0fac3e341c00b1c8c6e9578f66c4514509c3b3"))); + + nem_transaction_start(&ctx, fromhex("59d89076964742ef2a2089d26a5aa1d2c7a7bb052a46c1de159891e91ad3d76e"), buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_multisig(&ctx, + NEM_NETWORK_TESTNET, 3939039, NULL, 6000000, 3960639, + &other_trans)); + + signature = fromhex("933930a8828b560168bddb3137df9252048678d829aa5135fa27bb306ff6562efb92755462988b852b0314bde058487d00e47816b6fb7df6bcfd7e1f150d1d00"); + ck_assert_int_eq(ed25519_sign_open_keccak(ctx.buffer, ctx.offset, ctx.public_key, signature), 0); + + nem_transaction_start(&ctx, fromhex("71cba4f2a28fd19f902ba40e9937994154d9eeaad0631d25d525ec37922567d4"), buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_multisig_signature(&ctx, + NEM_NETWORK_TESTNET, 3939891, NULL, 6000000, 3961491, + &other_trans)); + + signature = fromhex("a849f13bfeeba808a8a4a79d579febe584d831a3a6ad03da3b9d008530b3d7a79fcf7156121cd7ee847029d94af7ea7a683ca8e643dc5e5f489557c2054b830b"); + ck_assert_int_eq(ed25519_sign_open_keccak(ctx.buffer, ctx.offset, ctx.public_key, signature), 0); + + // http://chain.nem.ninja/#/multisig/1016cf3bdd61bd57b9b2b07b6ff2dee390279d8d899265bdc23d42360abe2e6c + + nem_transaction_start(&other_trans, fromhex("a1df5306355766bd2f9a64efdc089eb294be265987b3359093ae474c051d7d5a"), inner, sizeof(inner)); + + ck_assert(nem_transaction_create_provision_namespace(&other_trans, + NEM_NETWORK_MAINNET, 59414272, NULL, 20000000, 59500672, + "dim", NULL, + "NAMESPACEWH4MKFMBCVFERDPOOP4FK7MTBXDPZZA", 5000000000)); + + nem_transaction_start(&ctx, fromhex("cfe58463f0eaebceb5d00717f8aead49171a5d7c08f6b1299bd534f11715acc9"), buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_multisig(&ctx, + NEM_NETWORK_MAINNET, 59414272, NULL, 6000000, 59500672, + &other_trans)); + + signature = fromhex("52a876a37511068fe214bd710b2284823921ec7318c01e083419a062eae5369c9c11c3abfdb590f65c717fab82873431d52be62e10338cb5656d1833bbdac70c"); + ck_assert_int_eq(ed25519_sign_open_keccak(ctx.buffer, ctx.offset, ctx.public_key, signature), 0); + + nem_transaction_start(&ctx, fromhex("1b49b80203007117d034e45234ffcdf402c044aeef6dbb06351f346ca892bce2"), buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_multisig_signature(&ctx, + NEM_NETWORK_MAINNET, 59414342, NULL, 6000000, 59500742, + &other_trans)); + + signature = fromhex("b9a59239e5d06992c28840034ff7a7f13da9c4e6f4a6f72c1b1806c3b602f83a7d727a345371f5d15abf958208a32359c6dd77bde92273ada8ea6fda3dc76b00"); + ck_assert_int_eq(ed25519_sign_open_keccak(ctx.buffer, ctx.offset, ctx.public_key, signature), 0); + + nem_transaction_start(&ctx, fromhex("7ba4b39209f1b9846b098fe43f74381e43cb2882ccde780f558a63355840aa87"), buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_multisig_signature(&ctx, + NEM_NETWORK_MAINNET, 59414381, NULL, 6000000, 59500781, + &other_trans)); + + signature = fromhex("e874ae9f069f0538008631d2df9f2e8a59944ff182e8672f743d2700fb99224aafb7a0ab09c4e9ea39ee7c8ca04a8a3d6103ae1122d87772e871761d4f00ca01"); + ck_assert_int_eq(ed25519_sign_open_keccak(ctx.buffer, ctx.offset, ctx.public_key, signature), 0); +} +END_TEST + +START_TEST(test_nem_transaction_provision_namespace) +{ + nem_transaction_ctx ctx; + + uint8_t buffer[1024], hash[SHA3_256_DIGEST_LENGTH]; + + // http://bob.nem.ninja:8765/#/namespace/f7cab28da57204d01a907c697836577a4ae755e6c9bac60dcc318494a22debb3 + + nem_transaction_start(&ctx, fromhex("84afa1bbc993b7f5536344914dde86141e61f8cbecaf8c9cefc07391f3287cf5"), buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_provision_namespace(&ctx, + NEM_NETWORK_TESTNET, 56999445, NULL, 20000000, 57003045, + "gimre", NULL, + "TAMESPACEWH4MKFMBCVFERDPOOP4FK7MTDJEYP35", 5000000000)); + + keccak_256(ctx.buffer, ctx.offset, hash); + ck_assert_mem_eq(hash, fromhex("f7cab28da57204d01a907c697836577a4ae755e6c9bac60dcc318494a22debb3"), sizeof(hash)); + + // http://bob.nem.ninja:8765/#/namespace/7ddd5fe607e1bfb5606e0ac576024c318c8300d237273117d4db32a60c49524d + + nem_transaction_start(&ctx, fromhex("244fa194e2509ac0d2fbc18779c2618d8c2ebb61c16a3bcbebcf448c661ba8dc"), buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_provision_namespace(&ctx, + NEM_NETWORK_TESTNET, 21496797, NULL, 108000000, 21500397, + "misc", "alice", + "TAMESPACEWH4MKFMBCVFERDPOOP4FK7MTDJEYP35", 5000000000)); + + keccak_256(ctx.buffer, ctx.offset, hash); + ck_assert_mem_eq(hash, fromhex("7ddd5fe607e1bfb5606e0ac576024c318c8300d237273117d4db32a60c49524d"), sizeof(hash)); + + // http://chain.nem.ninja/#/namespace/57071aad93ca125dc231dc02c07ad8610cd243d35068f9b36a7d231383907569 + + nem_transaction_start(&ctx, fromhex("9f3c14f304309c8b72b2821339c4428793b1518bea72d58dd01f19d523518614"), buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_provision_namespace(&ctx, + NEM_NETWORK_MAINNET, 26699717, NULL, 108000000, 26703317, + "sex", NULL, + "NAMESPACEWH4MKFMBCVFERDPOOP4FK7MTBXDPZZA", 50000000000)); + + keccak_256(ctx.buffer, ctx.offset, hash); + ck_assert_mem_eq(hash, fromhex("57071aad93ca125dc231dc02c07ad8610cd243d35068f9b36a7d231383907569"), sizeof(hash)); +} +END_TEST + +START_TEST(test_nem_transaction_mosaic_creation) +{ + nem_transaction_ctx ctx; + + uint8_t buffer[1024], hash[SHA3_256_DIGEST_LENGTH]; + + // http://bob.nem.ninja:8765/#/mosaic/68364353c29105e6d361ad1a42abbccbf419cfc7adb8b74c8f35d8f8bdaca3fa/0 + + nem_transaction_start(&ctx, fromhex("994793ba1c789fa9bdea918afc9b06e2d0309beb1081ac5b6952991e4defd324"), buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_mosaic_creation(&ctx, + NEM_NETWORK_TESTNET, 14070896, NULL, 108000000, 14074496, + "gimre.games.pong", "paddles", + "Paddles for the bong game.\n", + 0, 10000, true, true, + 0, 0, NULL, NULL, NULL, + "TBMOSAICOD4F54EE5CDMR23CCBGOAM2XSJBR5OLC", 50000000000)); + + keccak_256(ctx.buffer, ctx.offset, hash); + ck_assert_mem_eq(hash, fromhex("68364353c29105e6d361ad1a42abbccbf419cfc7adb8b74c8f35d8f8bdaca3fa"), sizeof(hash)); + + // http://bob.nem.ninja:8765/#/mosaic/b2f4a98113ff1f3a8f1e9d7197aa982545297fe0aa3fa6094af8031569953a55/0 + + nem_transaction_start(&ctx, fromhex("244fa194e2509ac0d2fbc18779c2618d8c2ebb61c16a3bcbebcf448c661ba8dc"), buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_mosaic_creation(&ctx, + NEM_NETWORK_TESTNET, 21497248, NULL, 108000000, 21500848, + "alice.misc", "bar", + "Special offer: get one bar extra by bying one foo!", + 0, 1000, false, true, + 1, 1, "TALICE2GMA34CXHD7XLJQ536NM5UNKQHTORNNT2J", "nem", "xem", + "TBMOSAICOD4F54EE5CDMR23CCBGOAM2XSJBR5OLC", 50000000000)); + + keccak_256(ctx.buffer, ctx.offset, hash); + ck_assert_mem_eq(hash, fromhex("b2f4a98113ff1f3a8f1e9d7197aa982545297fe0aa3fa6094af8031569953a55"), sizeof(hash)); + + // http://chain.nem.ninja/#/mosaic/269c6fda657aba3053a0e5b138c075808cc20e244e1182d9b730798b60a1f77b/0 + + nem_transaction_start(&ctx, fromhex("58956ac77951622dc5f1c938affbf017c458e30e6b21ddb5783d38b302531f23"), buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_mosaic_creation(&ctx, + NEM_NETWORK_MAINNET, 26729938, NULL, 108000000, 26733538, + "jabo38", "red_token", + "This token is to celebrate the release of Namespaces and Mosaics on the NEM system. " + "This token was the fist ever mosaic created other than nem.xem. " + "There are only 10,000 Red Tokens that will ever be created. " + "It has no levy and can be traded freely among third parties.", + 2, 10000, false, true, + 0, 0, NULL, NULL, NULL, + "NBMOSAICOD4F54EE5CDMR23CCBGOAM2XSIUX6TRS", 50000000000)); + + keccak_256(ctx.buffer, ctx.offset, hash); + ck_assert_mem_eq(hash, fromhex("269c6fda657aba3053a0e5b138c075808cc20e244e1182d9b730798b60a1f77b"), sizeof(hash)); + + // http://chain.nem.ninja/#/mosaic/e8dc14821dbea4831d9051f86158ef348001447968fc22c01644fdaf2bda75c6/0 + + nem_transaction_start(&ctx, fromhex("a1df5306355766bd2f9a64efdc089eb294be265987b3359093ae474c051d7d5a"), buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_mosaic_creation(&ctx, + NEM_NETWORK_MAINNET, 69251020, NULL, 20000000, 69337420, + "dim", "coin", + "DIM COIN", + 6, 9000000000, false, true, + 2, 10, "NCGGLVO2G3CUACVI5GNX2KRBJSQCN4RDL2ZWJ4DP", "dim", "coin", + "NBMOSAICOD4F54EE5CDMR23CCBGOAM2XSIUX6TRS", 500000000)); + + keccak_256(ctx.buffer, ctx.offset, hash); + ck_assert_mem_eq(hash, fromhex("e8dc14821dbea4831d9051f86158ef348001447968fc22c01644fdaf2bda75c6"), sizeof(hash)); +} +END_TEST + +START_TEST(test_nem_transaction_mosaic_supply_change) +{ + nem_transaction_ctx ctx; + + uint8_t buffer[1024], hash[SHA3_256_DIGEST_LENGTH]; + + // http://bigalice2.nem.ninja:7890/transaction/get?hash=33a50fdd4a54913643a580b2af08b9a5b51b7cee922bde380e84c573a7969c50 + + nem_transaction_start(&ctx, fromhex("994793ba1c789fa9bdea918afc9b06e2d0309beb1081ac5b6952991e4defd324"), buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_mosaic_supply_change(&ctx, + NEM_NETWORK_TESTNET, 14071648, NULL, 108000000, 14075248, + "gimre.games.pong", "paddles", + 1, 1234)); + + keccak_256(ctx.buffer, ctx.offset, hash); + ck_assert_mem_eq(hash, fromhex("33a50fdd4a54913643a580b2af08b9a5b51b7cee922bde380e84c573a7969c50"), sizeof(hash)); + + // http://bigalice2.nem.ninja:7890/transaction/get?hash=1ce8e8894d077a66ff22294b000825d090a60742ec407efd80eb8b19657704f2 + + nem_transaction_start(&ctx, fromhex("84afa1bbc993b7f5536344914dde86141e61f8cbecaf8c9cefc07391f3287cf5"), buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_mosaic_supply_change(&ctx, + NEM_NETWORK_TESTNET, 14126909, NULL, 108000000, 14130509, + "jabo38_ltd.fuzzy_kittens_cafe", "coupons", + 2, 1)); + + keccak_256(ctx.buffer, ctx.offset, hash); + ck_assert_mem_eq(hash, fromhex("1ce8e8894d077a66ff22294b000825d090a60742ec407efd80eb8b19657704f2"), sizeof(hash)); + + // http://bigalice3.nem.ninja:7890/transaction/get?hash=694e493e9576d2bcf60d85747e302ac2e1cc27783187947180d4275a713ff1ff + + nem_transaction_start(&ctx, fromhex("b7ccc27b21ba6cf5c699a8dc86ba6ba98950442597ff9fa30e0abe0f5f4dd05d"), buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_mosaic_supply_change(&ctx, + NEM_NETWORK_MAINNET, 53377685, NULL, 20000000, 53464085, + "abvapp", "abv", + 1, 9000000)); + + keccak_256(ctx.buffer, ctx.offset, hash); + ck_assert_mem_eq(hash, fromhex("694e493e9576d2bcf60d85747e302ac2e1cc27783187947180d4275a713ff1ff"), sizeof(hash)); + + // http://bigalice3.nem.ninja:7890/transaction/get?hash=09836334e123970e068d5b411e4d1df54a3ead10acf1ad5935a2cdd9f9680185 + + nem_transaction_start(&ctx, fromhex("75f001a8641e2ce5c4386883dda561399ed346177411b492a677b73899502f13"), buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_mosaic_supply_change(&ctx, + NEM_NETWORK_MAINNET, 55176304, NULL, 20000000, 55262704, + "sushi", "wasabi", + 2, 20)); + + keccak_256(ctx.buffer, ctx.offset, hash); + ck_assert_mem_eq(hash, fromhex("09836334e123970e068d5b411e4d1df54a3ead10acf1ad5935a2cdd9f9680185"), sizeof(hash)); +} +END_TEST + +START_TEST(test_nem_transaction_aggregate_modification) +{ + nem_transaction_ctx ctx; + + uint8_t buffer[1024], hash[SHA3_256_DIGEST_LENGTH]; + + // http://bob.nem.ninja:8765/#/aggregate/6a55471b17159e5b6cd579c421e95a4e39d92e3f78b0a55ee337e785a601d3a2 + + nem_transaction_start(&ctx, fromhex("462ee976890916e54fa825d26bdd0235f5eb5b6a143c199ab0ae5ee9328e08ce"), buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_aggregate_modification(&ctx, + NEM_NETWORK_TESTNET, 0, NULL, 22000000, 0, + 2, false)); + + ck_assert(nem_transaction_write_cosignatory_modification(&ctx, 1, fromhex("994793ba1c789fa9bdea918afc9b06e2d0309beb1081ac5b6952991e4defd324"))); + ck_assert(nem_transaction_write_cosignatory_modification(&ctx, 1, fromhex("c54d6e33ed1446eedd7f7a80a588dd01857f723687a09200c1917d5524752f8b"))); + + keccak_256(ctx.buffer, ctx.offset, hash); + ck_assert_mem_eq(hash, fromhex("6a55471b17159e5b6cd579c421e95a4e39d92e3f78b0a55ee337e785a601d3a2"), sizeof(hash)); + + // http://bob.nem.ninja:8765/#/aggregate/1fbdae5ba753e68af270930413ae90f671eb8ab58988116684bac0abd5726584 + + nem_transaction_start(&ctx, fromhex("6bf7849c1eec6a2002995cc457dc00c4e29bad5c88de63f51e42dfdcd7b2131d"), buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_aggregate_modification(&ctx, + NEM_NETWORK_TESTNET, 6542254, NULL, 40000000, 6545854, + 4, true)); + + ck_assert(nem_transaction_write_cosignatory_modification(&ctx, 1, fromhex("5f53d076c8c3ec3110b98364bc423092c3ec2be2b1b3c40fd8ab68d54fa39295"))); + ck_assert(nem_transaction_write_cosignatory_modification(&ctx, 1, fromhex("9eb199c2b4d406f64cb7aa5b2b0815264b56ba8fe44d558a6cb423a31a33c4c2"))); + ck_assert(nem_transaction_write_cosignatory_modification(&ctx, 1, fromhex("94b2323dab23a3faba24fa6ddda0ece4fbb06acfedd74e76ad9fae38d006882b"))); + ck_assert(nem_transaction_write_cosignatory_modification(&ctx, 1, fromhex("d88c6ee2a2cd3929d0d76b6b14ecb549d21296ab196a2b3a4cb2536bcce32e87"))); + + ck_assert(nem_transaction_write_minimum_cosignatories(&ctx, 2)); + + keccak_256(ctx.buffer, ctx.offset, hash); + ck_assert_mem_eq(hash, fromhex("1fbdae5ba753e68af270930413ae90f671eb8ab58988116684bac0abd5726584"), sizeof(hash)); + + // http://chain.nem.ninja/#/aggregate/cc64ca69bfa95db2ff7ac1e21fe6d27ece189c603200ebc9778d8bb80ca25c3c + + nem_transaction_start(&ctx, fromhex("f41b99320549741c5cce42d9e4bb836d98c50ed5415d0c3c2912d1bb50e6a0e5"), buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_aggregate_modification(&ctx, + NEM_NETWORK_MAINNET, 0, NULL, 40000000, 0, + 5, false)); + + ck_assert(nem_transaction_write_cosignatory_modification(&ctx, 1, fromhex("1fbdbdde28daf828245e4533765726f0b7790e0b7146e2ce205df3e86366980b"))); + ck_assert(nem_transaction_write_cosignatory_modification(&ctx, 1, fromhex("f94e8702eb1943b23570b1b83be1b81536df35538978820e98bfce8f999e2d37"))); + ck_assert(nem_transaction_write_cosignatory_modification(&ctx, 1, fromhex("826cedee421ff66e708858c17815fcd831a4bb68e3d8956299334e9e24380ba8"))); + ck_assert(nem_transaction_write_cosignatory_modification(&ctx, 1, fromhex("719862cd7d0f4e875a6a0274c9a1738f38f40ad9944179006a54c34724c1274d"))); + ck_assert(nem_transaction_write_cosignatory_modification(&ctx, 1, fromhex("43aa69177018fc3e2bdbeb259c81cddf24be50eef9c5386db51d82386c41475a"))); + + keccak_256(ctx.buffer, ctx.offset, hash); + ck_assert_mem_eq(hash, fromhex("cc64ca69bfa95db2ff7ac1e21fe6d27ece189c603200ebc9778d8bb80ca25c3c"), sizeof(hash)); +} +END_TEST + START_TEST(test_multibyte_address) { uint8_t priv_key[32]; @@ -3863,6 +4249,15 @@ Suite *test_suite(void) tcase_add_test(tc, test_nem_cipher); suite_add_tcase(s, tc); + tc = tcase_create("nem_transaction"); + tcase_add_test(tc, test_nem_transaction_transfer); + tcase_add_test(tc, test_nem_transaction_multisig); + tcase_add_test(tc, test_nem_transaction_provision_namespace); + tcase_add_test(tc, test_nem_transaction_mosaic_creation); + tcase_add_test(tc, test_nem_transaction_mosaic_supply_change); + tcase_add_test(tc, test_nem_transaction_aggregate_modification); + suite_add_tcase(s, tc); + tc = tcase_create("multibyte_address"); tcase_add_test(tc, test_multibyte_address); suite_add_tcase(s, tc); From 56114cc0a6e1b6817262bf886d775ec9de400d8e Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sat, 7 Oct 2017 21:42:45 +0100 Subject: [PATCH 499/627] nem: Add nem_transaction_create_importance_transfer --- nem.c | 31 +++++++++++++++++++++++++++++++ nem.h | 10 ++++++++++ 2 files changed, 41 insertions(+) diff --git a/nem.c b/nem.c index ace8670b4..9b0150ea7 100644 --- a/nem.c +++ b/nem.c @@ -584,3 +584,34 @@ bool nem_transaction_write_minimum_cosignatories(nem_transaction_ctx *ctx, return true; } + +bool nem_transaction_create_importance_transfer(nem_transaction_ctx *ctx, + uint8_t network, + uint32_t timestamp, + const ed25519_public_key signer, + uint64_t fee, + uint32_t deadline, + uint32_t mode, + const ed25519_public_key remote) { + + if (!signer) { + signer = ctx->public_key; + } + + bool ret = nem_transaction_write_common(ctx, + NEM_TRANSACTION_TYPE_IMPORTANCE_TRANSFER, + network << 24 | 1, + timestamp, + signer, + fee, + deadline); + if (!ret) return false; + +#define NEM_SERIALIZE \ + serialize_u32(mode) \ + serialize_write(remote, sizeof(ed25519_public_key)) + +#include "nem_serialize.h" + + return true; +} diff --git a/nem.h b/nem.h index f4b181a00..cc3935eef 100644 --- a/nem.h +++ b/nem.h @@ -42,6 +42,7 @@ #define NEM_ADDRESS_SIZE_RAW 25 #define NEM_TRANSACTION_TYPE_TRANSFER 0x0101 +#define NEM_TRANSACTION_TYPE_IMPORTANCE_TRANSFER 0x0801 #define NEM_TRANSACTION_TYPE_AGGREGATE_MODIFICATION 0x1001 #define NEM_TRANSACTION_TYPE_MULTISIG_SIGNATURE 0x1002 #define NEM_TRANSACTION_TYPE_MULTISIG 0x1004 @@ -176,4 +177,13 @@ bool nem_transaction_write_cosignatory_modification(nem_transaction_ctx *ctx, bool nem_transaction_write_minimum_cosignatories(nem_transaction_ctx *ctx, int32_t relative_change); +bool nem_transaction_create_importance_transfer(nem_transaction_ctx *ctx, + uint8_t network, + uint32_t timestamp, + const ed25519_public_key signer, + uint64_t fee, + uint32_t deadline, + uint32_t mode, + const ed25519_public_key remote); + #endif From 506167e3f20bbe24bb2b7cdbda7057e1155abe02 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Mon, 9 Oct 2017 09:42:37 +0200 Subject: [PATCH 500/627] Bech32 (BIP173) address support --- Makefile | 1 + segwit_addr.c | 187 +++++++++++++++++++++++++++++++++++++++++++++++++ segwit_addr.h | 101 +++++++++++++++++++++++++++ test_check.c | 6 ++ test_segwit.c | 190 ++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 485 insertions(+) create mode 100644 segwit_addr.c create mode 100644 segwit_addr.h create mode 100644 test_segwit.c diff --git a/Makefile b/Makefile index a42b9c18e..19a53b44f 100644 --- a/Makefile +++ b/Makefile @@ -50,6 +50,7 @@ SRCS += blake2b.c blake2s.c SRCS += chacha20poly1305/chacha20poly1305.c chacha20poly1305/chacha_merged.c chacha20poly1305/poly1305-donna.c chacha20poly1305/rfc7539.c SRCS += rc4.c SRCS += nem.c +SRCS += segwit_addr.c OBJS = $(SRCS:.c=.o) diff --git a/segwit_addr.c b/segwit_addr.c new file mode 100644 index 000000000..e5b26ec91 --- /dev/null +++ b/segwit_addr.c @@ -0,0 +1,187 @@ +/* Copyright (c) 2017 Pieter Wuille + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include +#include + +#include "segwit_addr.h" + +uint32_t bech32_polymod_step(uint32_t pre) { + uint8_t b = pre >> 25; + return ((pre & 0x1FFFFFF) << 5) ^ + (-((b >> 0) & 1) & 0x3b6a57b2UL) ^ + (-((b >> 1) & 1) & 0x26508e6dUL) ^ + (-((b >> 2) & 1) & 0x1ea119faUL) ^ + (-((b >> 3) & 1) & 0x3d4233ddUL) ^ + (-((b >> 4) & 1) & 0x2a1462b3UL); +} + +static const char* charset = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"; + +static const int8_t charset_rev[128] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 15, -1, 10, 17, 21, 20, 26, 30, 7, 5, -1, -1, -1, -1, -1, -1, + -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1, + 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1, + -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1, + 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1 +}; + +int bech32_encode(char *output, const char *hrp, const uint8_t *data, size_t data_len) { + uint32_t chk = 1; + size_t i = 0; + while (hrp[i] != 0) { + if (hrp[i] >= 'A' && hrp[i] <= 'Z') return 0; + if (!(hrp[i] >> 5)) return 0; + chk = bech32_polymod_step(chk) ^ (hrp[i] >> 5); + ++i; + } + if (i + 7 + data_len > 90) return 0; + chk = bech32_polymod_step(chk); + while (*hrp != 0) { + chk = bech32_polymod_step(chk) ^ (*hrp & 0x1f); + *(output++) = *(hrp++); + } + *(output++) = '1'; + for (i = 0; i < data_len; ++i) { + if (*data >> 5) return 0; + chk = bech32_polymod_step(chk) ^ (*data); + *(output++) = charset[*(data++)]; + } + for (i = 0; i < 6; ++i) { + chk = bech32_polymod_step(chk); + } + chk ^= 1; + for (i = 0; i < 6; ++i) { + *(output++) = charset[(chk >> ((5 - i) * 5)) & 0x1f]; + } + *output = 0; + return 1; +} + +int bech32_decode(char* hrp, uint8_t *data, size_t *data_len, const char *input) { + uint32_t chk = 1; + size_t i; + size_t input_len = strlen(input); + size_t hrp_len; + int have_lower = 0, have_upper = 0; + if (input_len < 8 || input_len > 90) { + return 0; + } + *data_len = 0; + while (*data_len < input_len && input[(input_len - 1) - *data_len] != '1') { + ++(*data_len); + } + hrp_len = input_len - (1 + *data_len); + if (hrp_len < 1 || *data_len < 6) { + return 0; + } + *(data_len) -= 6; + for (i = 0; i < hrp_len; ++i) { + int ch = input[i]; + if (ch < 33 || ch > 126) { + return 0; + } + if (ch >= 'a' && ch <= 'z') { + have_lower = 1; + } else if (ch >= 'A' && ch <= 'Z') { + have_upper = 1; + ch = (ch - 'A') + 'a'; + } + hrp[i] = ch; + chk = bech32_polymod_step(chk) ^ (ch >> 5); + } + hrp[i] = 0; + chk = bech32_polymod_step(chk); + for (i = 0; i < hrp_len; ++i) { + chk = bech32_polymod_step(chk) ^ (input[i] & 0x1f); + } + ++i; + while (i < input_len) { + int v = (input[i] & 0x80) ? -1 : charset_rev[(int)input[i]]; + if (input[i] >= 'a' && input[i] <= 'z') have_lower = 1; + if (input[i] >= 'A' && input[i] <= 'Z') have_upper = 1; + if (v == -1) { + return 0; + } + chk = bech32_polymod_step(chk) ^ v; + if (i + 6 < input_len) { + data[i - (1 + hrp_len)] = v; + } + ++i; + } + if (have_lower && have_upper) { + return 0; + } + return chk == 1; +} + +static int convert_bits(uint8_t* out, size_t* outlen, int outbits, const uint8_t* in, size_t inlen, int inbits, int pad) { + uint32_t val = 0; + int bits = 0; + uint32_t maxv = (((uint32_t)1) << outbits) - 1; + while (inlen--) { + val = (val << inbits) | *(in++); + bits += inbits; + while (bits >= outbits) { + bits -= outbits; + out[(*outlen)++] = (val >> bits) & maxv; + } + } + if (pad) { + if (bits) { + out[(*outlen)++] = (val << (outbits - bits)) & maxv; + } + } else if (((val << (outbits - bits)) & maxv) || bits >= inbits) { + return 0; + } + return 1; +} + +int segwit_addr_encode(char *output, const char *hrp, int witver, const uint8_t *witprog, size_t witprog_len) { + uint8_t data[65]; + size_t datalen = 0; + if (witver > 16) return 0; + if (witver == 0 && witprog_len != 20 && witprog_len != 32) return 0; + if (witprog_len < 2 || witprog_len > 40) return 0; + data[0] = witver; + convert_bits(data + 1, &datalen, 5, witprog, witprog_len, 8, 1); + ++datalen; + return bech32_encode(output, hrp, data, datalen); +} + +int segwit_addr_decode(int* witver, uint8_t* witdata, size_t* witdata_len, const char* hrp, const char* addr) { + uint8_t data[84]; + char hrp_actual[84]; + size_t data_len; + if (!bech32_decode(hrp_actual, data, &data_len, addr)) return 0; + if (data_len == 0 || data_len > 65) return 0; + if (strncmp(hrp, hrp_actual, 84) != 0) return 0; + if (data[0] > 16) return 0; + *witdata_len = 0; + if (!convert_bits(witdata, witdata_len, 8, data + 1, data_len - 1, 5, 0)) return 0; + if (*witdata_len < 2 || *witdata_len > 40) return 0; + if (data[0] == 0 && *witdata_len != 20 && *witdata_len != 32) return 0; + *witver = data[0]; + return 1; +} diff --git a/segwit_addr.h b/segwit_addr.h new file mode 100644 index 000000000..dbec91b02 --- /dev/null +++ b/segwit_addr.h @@ -0,0 +1,101 @@ +/* Copyright (c) 2017 Pieter Wuille + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef _SEGWIT_ADDR_H_ +#define _SEGWIT_ADDR_H_ 1 + +#include + +/** Encode a SegWit address + * + * Out: output: Pointer to a buffer of size 73 + strlen(hrp) that will be + * updated to contain the null-terminated address. + * In: hrp: Pointer to the null-terminated human readable part to use + * (chain/network specific). + * ver: Version of the witness program (between 0 and 16 inclusive). + * prog: Data bytes for the witness program (between 2 and 40 bytes). + * prog_len: Number of data bytes in prog. + * Returns 1 if successful. + */ +int segwit_addr_encode( + char *output, + const char *hrp, + int ver, + const uint8_t *prog, + size_t prog_len +); + +/** Decode a SegWit address + * + * Out: ver: Pointer to an int that will be updated to contain the witness + * program version (between 0 and 16 inclusive). + * prog: Pointer to a buffer of size 40 that will be updated to + * contain the witness program bytes. + * prog_len: Pointer to a size_t that will be updated to contain the length + * of bytes in prog. + * hrp: Pointer to the null-terminated human readable part that is + * expected (chain/network specific). + * addr: Pointer to the null-terminated address. + * Returns 1 if successful. + */ +int segwit_addr_decode( + int* ver, + uint8_t* prog, + size_t* prog_len, + const char* hrp, + const char* addr +); + +/** Encode a Bech32 string + * + * Out: output: Pointer to a buffer of size strlen(hrp) + data_len + 8 that + * will be updated to contain the null-terminated Bech32 string. + * In: hrp : Pointer to the null-terminated human readable part. + * data : Pointer to an array of 5-bit values. + * data_len: Length of the data array. + * Returns 1 if successful. + */ +int bech32_encode( + char *output, + const char *hrp, + const uint8_t *data, + size_t data_len +); + +/** Decode a Bech32 string + * + * Out: hrp: Pointer to a buffer of size strlen(input) - 6. Will be + * updated to contain the null-terminated human readable part. + * data: Pointer to a buffer of size strlen(input) - 8 that will + * hold the encoded 5-bit data values. + * data_len: Pointer to a size_t that will be updated to be the number + * of entries in data. + * In: input: Pointer to a null-terminated Bech32 string. + * Returns 1 if succesful. + */ +int bech32_decode( + char *hrp, + uint8_t *data, + size_t *data_len, + const char *input +); + +#endif diff --git a/test_check.c b/test_check.c index cf59bcade..e05d65041 100644 --- a/test_check.c +++ b/test_check.c @@ -4053,6 +4053,8 @@ START_TEST(test_rc4_rfc6229) } END_TEST +#include "test_segwit.c" + // define test suite and cases Suite *test_suite(void) { @@ -4266,6 +4268,10 @@ Suite *test_suite(void) tcase_add_test(tc, test_rc4_rfc6229); suite_add_tcase(s, tc); + tc = tcase_create("segwit"); + tcase_add_test(tc, test_segwit); + suite_add_tcase(s, tc); + return s; } diff --git a/test_segwit.c b/test_segwit.c new file mode 100644 index 000000000..6ebae766f --- /dev/null +++ b/test_segwit.c @@ -0,0 +1,190 @@ +#include +#include +#include +#include + +#include "segwit_addr.h" + +static const char* valid_checksum[] = { + "A12UEL5L", + "an83characterlonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1tt5tgs", + "abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw", + "11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc8247j", + "split1checkupstagehandshakeupstreamerranterredcaperred2y9e3w", +}; + +static const char* invalid_checksum[] = { + " 1nwldj5", + "\x7f""1axkwrx", + "an84characterslonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1569pvx", + "pzry9x0s0muk", + "1pzry9x0s0muk", + "x1b4n0q5v", + "li1dgmt3", + "de1lg7wt\xff", +}; + +struct valid_address_data { + const char* address; + size_t scriptPubKeyLen; + const uint8_t scriptPubKey[42]; +}; + +struct invalid_address_data { + const char* hrp; + int version; + size_t program_length; +}; + +static struct valid_address_data valid_address[] = { + { + "BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4", + 22, { + 0x00, 0x14, 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, + 0x94, 0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6 + } + }, + { + "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7", + 34, { + 0x00, 0x20, 0x18, 0x63, 0x14, 0x3c, 0x14, 0xc5, 0x16, 0x68, 0x04, + 0xbd, 0x19, 0x20, 0x33, 0x56, 0xda, 0x13, 0x6c, 0x98, 0x56, 0x78, + 0xcd, 0x4d, 0x27, 0xa1, 0xb8, 0xc6, 0x32, 0x96, 0x04, 0x90, 0x32, + 0x62 + } + }, + { + "bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7k7grplx", + 42, { + 0x51, 0x28, 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, + 0x94, 0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6, + 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, 0x94, 0x1c, + 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6 + } + }, + { + "BC1SW50QA3JX3S", + 4, { + 0x60, 0x02, 0x75, 0x1e + } + }, + { + "bc1zw508d6qejxtdg4y5r3zarvaryvg6kdaj", + 18, { + 0x52, 0x10, 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, + 0x94, 0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23 + } + }, + { + "tb1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesrxh6hy", + 34, { + 0x00, 0x20, 0x00, 0x00, 0x00, 0xc4, 0xa5, 0xca, 0xd4, 0x62, 0x21, + 0xb2, 0xa1, 0x87, 0x90, 0x5e, 0x52, 0x66, 0x36, 0x2b, 0x99, 0xd5, + 0xe9, 0x1c, 0x6c, 0xe2, 0x4d, 0x16, 0x5d, 0xab, 0x93, 0xe8, 0x64, + 0x33 + } + } +}; + +static const char* invalid_address[] = { + "tc1qw508d6qejxtdg4y5r3zarvary0c5xw7kg3g4ty", + "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t5", + "BC13W508D6QEJXTDG4Y5R3ZARVARY0C5XW7KN40WF2", + "bc1rw5uspcuh", + "bc10w508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kw5rljs90", + "BC1QR508D6QEJXTDG4Y5R3ZARVARYV98GJ9P", + "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sL5k7", + "bc1zw508d6qejxtdg4y5r3zarvaryvqyzf3du", + "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3pjxtptv", + "bc1gmk9yu", +}; + +static struct invalid_address_data invalid_address_enc[] = { + {"BC", 0, 20}, + {"bc", 0, 21}, + {"bc", 17, 32}, + {"bc", 1, 1}, + {"bc", 16, 41}, +}; + +static void segwit_scriptpubkey(uint8_t* scriptpubkey, size_t* scriptpubkeylen, int witver, const uint8_t* witprog, size_t witprog_len) { + scriptpubkey[0] = witver ? (0x50 + witver) : 0; + scriptpubkey[1] = witprog_len; + memcpy(scriptpubkey + 2, witprog, witprog_len); + *scriptpubkeylen = witprog_len + 2; +} + +int my_strncasecmp(const char *s1, const char *s2, size_t n) { + size_t i = 0; + while (i < n) { + char c1 = s1[i]; + char c2 = s2[i]; + if (c1 >= 'A' && c1 <= 'Z') c1 = (c1 - 'A') + 'a'; + if (c2 >= 'A' && c2 <= 'Z') c2 = (c2 - 'A') + 'a'; + if (c1 < c2) return -1; + if (c1 > c2) return 1; + if (c1 == 0) return 0; + ++i; + } + return 0; +} + +START_TEST(test_segwit) +{ + size_t i; + for (i = 0; i < sizeof(valid_checksum) / sizeof(valid_checksum[0]); ++i) { + uint8_t data[82]; + char rebuild[92]; + char hrp[84]; + size_t data_len; + int res = bech32_decode(hrp, data, &data_len, valid_checksum[i]); + ck_assert_int_eq(res, 1); + res = bech32_encode(rebuild, hrp, data, data_len); + ck_assert_int_eq(res, 1); + ck_assert_int_eq(my_strncasecmp(rebuild, valid_checksum[i], 92), 0); + } + for (i = 0; i < sizeof(invalid_checksum) / sizeof(invalid_checksum[0]); ++i) { + uint8_t data[82]; + char hrp[84]; + size_t data_len; + int res = bech32_decode(hrp, data, &data_len, invalid_checksum[i]); + ck_assert_int_eq(res, 0); + } + for (i = 0; i < sizeof(valid_address) / sizeof(valid_address[0]); ++i) { + uint8_t witprog[40]; + size_t witprog_len; + int witver; + const char* hrp = "bc"; + uint8_t scriptpubkey[42]; + size_t scriptpubkey_len; + char rebuild[93]; + int ret = segwit_addr_decode(&witver, witprog, &witprog_len, hrp, valid_address[i].address); + if (!ret) { + hrp = "tb"; + ret = segwit_addr_decode(&witver, witprog, &witprog_len, hrp, valid_address[i].address); + } + ck_assert_int_eq(ret, 1); + segwit_scriptpubkey(scriptpubkey, &scriptpubkey_len, witver, witprog, witprog_len); + ck_assert_int_eq(scriptpubkey_len, valid_address[i].scriptPubKeyLen); + ck_assert_int_eq(memcmp(scriptpubkey, valid_address[i].scriptPubKey, scriptpubkey_len), 0); + ck_assert_int_eq(segwit_addr_encode(rebuild, hrp, witver, witprog, witprog_len), 1); + ck_assert_int_eq(my_strncasecmp(valid_address[i].address, rebuild, 93), 0); + } + for (i = 0; i < sizeof(invalid_address) / sizeof(invalid_address[0]); ++i) { + uint8_t witprog[40]; + size_t witprog_len; + int witver; + int ret = segwit_addr_decode(&witver, witprog, &witprog_len, "bc", invalid_address[i]); + ck_assert_int_eq(ret, 0); + ret = segwit_addr_decode(&witver, witprog, &witprog_len, "tb", invalid_address[i]); + ck_assert_int_eq(ret, 0); + } + for (i = 0; i < sizeof(invalid_address_enc) / sizeof(invalid_address_enc[0]); ++i) { + char rebuild[93]; + static const uint8_t program[42] = {0}; + int ret = segwit_addr_encode(rebuild, invalid_address_enc[i].hrp, invalid_address_enc[i].version, program, invalid_address_enc[i].program_length); + ck_assert_int_eq(ret, 0); + } +} +END_TEST + From a5653dafe7e6948d86ffe7cad03853766a669b1e Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Tue, 31 Oct 2017 18:47:45 +0100 Subject: [PATCH 501/627] Increased length of addresses --- ecdsa.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/ecdsa.h b/ecdsa.h index d21a3855d..90c607010 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -48,10 +48,16 @@ typedef struct { } ecdsa_curve; +// 4 byte prefix + 40 byte data (segwit) #define MAX_ADDR_RAW_SIZE (4 + 40) +// bottle neck is segwit bech32: +// 4 human readable prefix + 1 separator + 64 data + 6 checksum + 1 NUL +// the standard says 83 characters in hrp, but currently all coins use only 2 +#define MAX_ADDR_SIZE (4+1+64+6+1) +// 4 byte prefix + 32 byte privkey + 1 byte compressed marker #define MAX_WIF_RAW_SIZE (4 + 32 + 1) -#define MAX_ADDR_SIZE (54) -#define MAX_WIF_SIZE (58) +// (4+32+1 + 4 [checksum]) * 8 / log2(58) plus NUL. +#define MAX_WIF_SIZE (57) void point_copy(const curve_point *cp1, curve_point *cp2); void point_add(const ecdsa_curve *curve, const curve_point *cp1, curve_point *cp2); From f366fb81c5fa154ce1004f3619014c9034305bf7 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Tue, 31 Oct 2017 19:16:07 +0100 Subject: [PATCH 502/627] Updated to latest from bech32 repository. hrp is ASCII character, not 5 bit words --- segwit_addr.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/segwit_addr.c b/segwit_addr.c index e5b26ec91..8202d8418 100644 --- a/segwit_addr.c +++ b/segwit_addr.c @@ -51,9 +51,13 @@ int bech32_encode(char *output, const char *hrp, const uint8_t *data, size_t dat uint32_t chk = 1; size_t i = 0; while (hrp[i] != 0) { - if (hrp[i] >= 'A' && hrp[i] <= 'Z') return 0; - if (!(hrp[i] >> 5)) return 0; - chk = bech32_polymod_step(chk) ^ (hrp[i] >> 5); + int ch = hrp[i]; + if (ch < 33 || ch > 126) { + return 0; + } + + if (ch >= 'A' && ch <= 'Z') return 0; + chk = bech32_polymod_step(chk) ^ (ch >> 5); ++i; } if (i + 7 + data_len > 90) return 0; From 95a522bf1a453880050521661258d7943e966d1f Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 3 Nov 2017 18:52:23 +0100 Subject: [PATCH 503/627] fix typo --- ecdsa.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ecdsa.h b/ecdsa.h index 90c607010..84d1665b4 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -52,11 +52,11 @@ typedef struct { #define MAX_ADDR_RAW_SIZE (4 + 40) // bottle neck is segwit bech32: // 4 human readable prefix + 1 separator + 64 data + 6 checksum + 1 NUL -// the standard says 83 characters in hrp, but currently all coins use only 2 -#define MAX_ADDR_SIZE (4+1+64+6+1) +// the standard says 83 characters in hrp, but currently all coins use max 4 +#define MAX_ADDR_SIZE (4 + 1 + 64 + 6 + 1) // 4 byte prefix + 32 byte privkey + 1 byte compressed marker #define MAX_WIF_RAW_SIZE (4 + 32 + 1) -// (4+32+1 + 4 [checksum]) * 8 / log2(58) plus NUL. +// (4 + 32 + 1 + 4 [checksum]) * 8 / log2(58) plus NUL. #define MAX_WIF_SIZE (57) void point_copy(const curve_point *cp1, curve_point *cp2); From a70caa3dbce79195be634e7c5cf04631414581ef Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sat, 9 Dec 2017 17:59:20 +0000 Subject: [PATCH 504/627] hasher: Initial commit --- CMakeLists.txt | 1 + Makefile | 1 + hasher.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++ hasher.h | 53 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 121 insertions(+) create mode 100644 hasher.c create mode 100644 hasher.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 83397e656..987a6f6c9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,6 +7,7 @@ set(SOURCES ripemd160.c sha2.c sha3.c + hasher.c aes/aescrypt.c aes/aeskey.c aes/aestab.c aes/aes_modes.c ed25519-donna/curve25519-donna-32bit.c ed25519-donna/curve25519-donna-helpers.c ed25519-donna/modm-donna-32bit.c ed25519-donna/ed25519-donna-basepoint-table.c ed25519-donna/ed25519-donna-32bit-tables.c ed25519-donna/ed25519-donna-impl-base.c diff --git a/Makefile b/Makefile index 19a53b44f..4d5e9faa4 100644 --- a/Makefile +++ b/Makefile @@ -42,6 +42,7 @@ SRCS += script.c SRCS += ripemd160.c SRCS += sha2.c SRCS += sha3.c +SRCS += hasher.c SRCS += aes/aescrypt.c aes/aeskey.c aes/aestab.c aes/aes_modes.c SRCS += ed25519-donna/curve25519-donna-32bit.c ed25519-donna/curve25519-donna-helpers.c ed25519-donna/modm-donna-32bit.c SRCS += ed25519-donna/ed25519-donna-basepoint-table.c ed25519-donna/ed25519-donna-32bit-tables.c ed25519-donna/ed25519-donna-impl-base.c diff --git a/hasher.c b/hasher.c new file mode 100644 index 000000000..aa73e45d2 --- /dev/null +++ b/hasher.c @@ -0,0 +1,66 @@ +/** + * Copyright (c) 2017 Saleem Rashid + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "hasher.h" + +void hasher_Init(Hasher *hasher, HasherType type) { + hasher->type = type; + + switch (hasher->type) { + case HASHER_SHA2: + sha256_Init(&hasher->ctx.sha2); + break; + } +} + +void hasher_Reset(Hasher *hasher) { + hasher_Init(hasher, hasher->type); +} + +void hasher_Update(Hasher *hasher, const uint8_t *data, size_t length) { + switch (hasher->type) { + case HASHER_SHA2: + sha256_Update(&hasher->ctx.sha2, data, length); + break; + } +} + +void hasher_Final(Hasher *hasher, uint8_t hash[HASHER_DIGEST_LENGTH]) { + switch (hasher->type) { + case HASHER_SHA2: + sha256_Final(&hasher->ctx.sha2, hash); + break; + } +} + +void hasher_Double(Hasher *hasher, uint8_t hash[HASHER_DIGEST_LENGTH]) { + hasher_Final(hasher, hash); + hasher_Raw(hasher->type, hash, HASHER_DIGEST_LENGTH, hash); +} + +void hasher_Raw(HasherType type, const uint8_t *data, size_t length, uint8_t hash[HASHER_DIGEST_LENGTH]) { + Hasher hasher; + + hasher_Init(&hasher, type); + hasher_Update(&hasher, data, length); + hasher_Final(&hasher, hash); +} diff --git a/hasher.h b/hasher.h new file mode 100644 index 000000000..5fa70b408 --- /dev/null +++ b/hasher.h @@ -0,0 +1,53 @@ +/** + * Copyright (c) 2017 Saleem Rashid + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __HASHER_H__ +#define __HASHER_H__ + +#include +#include + +#include "sha2.h" + +#define HASHER_DIGEST_LENGTH 32 + +typedef enum { + HASHER_SHA2, +} HasherType; + +typedef struct { + HasherType type; + + union { + SHA256_CTX sha2; + } ctx; +} Hasher; + +void hasher_Init(Hasher *hasher, HasherType type); +void hasher_Reset(Hasher *hasher); +void hasher_Update(Hasher *hasher, const uint8_t *data, size_t length); +void hasher_Final(Hasher *hasher, uint8_t hash[HASHER_DIGEST_LENGTH]); +void hasher_Double(Hasher *hasher, uint8_t hash[HASHER_DIGEST_LENGTH]); + +void hasher_Raw(HasherType type, const uint8_t *data, size_t length, uint8_t hash[HASHER_DIGEST_LENGTH]); + +#endif From b41a51805f6adf8481c6ac0d3fcf98282d89f132 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sat, 9 Dec 2017 17:59:44 +0000 Subject: [PATCH 505/627] Use hasher_Raw instead of sha256_Raw --- base58.c | 16 ++--- base58.h | 7 +- bip32.c | 44 ++++++------ bip32.h | 3 +- ecdsa.c | 64 ++++++++--------- ecdsa.h | 23 +++--- nist256p1.c | 6 +- script.c | 8 +-- secp256k1.c | 6 +- test_check.c | 150 ++++++++++++++++++++-------------------- tools/bip39bruteforce.c | 4 +- tools/xpubaddrgen.c | 2 +- 12 files changed, 168 insertions(+), 165 deletions(-) diff --git a/base58.c b/base58.c index 0c26943ca..528a75047 100644 --- a/base58.c +++ b/base58.c @@ -123,15 +123,15 @@ bool b58tobin(void *bin, size_t *binszp, const char *b58) return true; } -int b58check(const void *bin, size_t binsz, const char *base58str) +int b58check(const void *bin, size_t binsz, HasherType hasher_type, const char *base58str) { unsigned char buf[32]; const uint8_t *binc = bin; unsigned i; if (binsz < 4) return -4; - sha256_Raw(bin, binsz - 4, buf); - sha256_Raw(buf, 32, buf); + hasher_Raw(hasher_type, bin, binsz - 4, buf); + hasher_Raw(hasher_type, buf, 32, buf); if (memcmp(&binc[binsz - 4], buf, 4)) return -1; @@ -188,7 +188,7 @@ bool b58enc(char *b58, size_t *b58sz, const void *data, size_t binsz) return true; } -int base58_encode_check(const uint8_t *data, int datalen, char *str, int strsize) +int base58_encode_check(const uint8_t *data, int datalen, HasherType hasher_type, char *str, int strsize) { if (datalen > 128) { return 0; @@ -196,15 +196,15 @@ int base58_encode_check(const uint8_t *data, int datalen, char *str, int strsize uint8_t buf[datalen + 32]; uint8_t *hash = buf + datalen; memcpy(buf, data, datalen); - sha256_Raw(data, datalen, hash); - sha256_Raw(hash, 32, hash); + hasher_Raw(hasher_type, data, datalen, hash); + hasher_Raw(hasher_type, hash, 32, hash); size_t res = strsize; bool success = b58enc(str, &res, buf, datalen + 4); MEMSET_BZERO(buf, sizeof(buf)); return success ? res : 0; } -int base58_decode_check(const char *str, uint8_t *data, int datalen) +int base58_decode_check(const char *str, HasherType hasher_type, uint8_t *data, int datalen) { if (datalen > 128) { return 0; @@ -215,7 +215,7 @@ int base58_decode_check(const char *str, uint8_t *data, int datalen) return 0; } uint8_t *nd = d + datalen + 4 - res; - if (b58check(nd, res, str) < 0) { + if (b58check(nd, res, hasher_type, str) < 0) { return 0; } memcpy(data, nd, res - 4); diff --git a/base58.h b/base58.h index 977d66733..41b0b7d4c 100644 --- a/base58.h +++ b/base58.h @@ -26,14 +26,15 @@ #include #include +#include "hasher.h" #include "options.h" -int base58_encode_check(const uint8_t *data, int len, char *str, int strsize); -int base58_decode_check(const char *str, uint8_t *data, int datalen); +int base58_encode_check(const uint8_t *data, int len, HasherType hasher_type, char *str, int strsize); +int base58_decode_check(const char *str, HasherType hasher_type, uint8_t *data, int datalen); // Private bool b58tobin(void *bin, size_t *binszp, const char *b58); -int b58check(const void *bin, size_t binsz, const char *base58str); +int b58check(const void *bin, size_t binsz, HasherType hasher_type, const char *base58str); bool b58enc(char *b58, size_t *b58sz, const void *data, size_t binsz); #if USE_GRAPHENE diff --git a/bip32.c b/bip32.c index 7c3417c91..f0d949038 100644 --- a/bip32.c +++ b/bip32.c @@ -49,29 +49,29 @@ #endif const curve_info ed25519_info = { - /* bip32_name */ - "ed25519 seed", - 0 + .bip32_name = "ed25519 seed", + .params = NULL, + .hasher_type = HASHER_SHA2, }; const curve_info ed25519_sha3_info = { - /* bip32_name */ - "ed25519-sha3 seed", - 0 + .bip32_name = "ed25519-sha3 seed", + .params = NULL, + .hasher_type = HASHER_SHA2, }; #if USE_KECCAK const curve_info ed25519_keccak_info = { - /* bip32_name */ - "ed25519-keccak seed", - 0 + .bip32_name = "ed25519-keccak seed", + .params = NULL, + .hasher_type = HASHER_SHA2, }; #endif const curve_info curve25519_info = { - /* bip32_name */ - "curve25519 seed", - 0 + .bip32_name = "curve25519 seed", + .params = NULL, + .hasher_type = HASHER_SHA2, }; int hdnode_from_xpub(uint32_t depth, uint32_t child_num, const uint8_t *chain_code, const uint8_t *public_key, const char* curve, HDNode *out) @@ -166,7 +166,7 @@ uint32_t hdnode_fingerprint(HDNode *node) uint32_t fingerprint; hdnode_fill_public_key(node); - sha256_Raw(node->public_key, 33, digest); + hasher_Raw(node->curve->hasher_type, node->public_key, 33, digest); ripemd160(digest, 32, digest); fingerprint = (digest[0] << 24) + (digest[1] << 16) + (digest[2] << 8) + digest[3]; MEMSET_BZERO(digest, sizeof(digest)); @@ -300,7 +300,7 @@ int hdnode_public_ckd(HDNode *inout, uint32_t i) return 1; } -void hdnode_public_ckd_address_optimized(const curve_point *pub, const uint8_t *chain_code, uint32_t i, uint32_t version, char *addr, int addrsize, int addrformat) +void hdnode_public_ckd_address_optimized(const curve_point *pub, const uint8_t *chain_code, uint32_t i, uint32_t version, HasherType hasher_type, char *addr, int addrsize, int addrformat) { uint8_t child_pubkey[33]; curve_point b; @@ -311,10 +311,10 @@ void hdnode_public_ckd_address_optimized(const curve_point *pub, const uint8_t * switch (addrformat) { case 1: // Segwit-in-P2SH - ecdsa_get_address_segwit_p2sh(child_pubkey, version, addr, addrsize); + ecdsa_get_address_segwit_p2sh(child_pubkey, version, hasher_type, addr, addrsize); break; default: // normal address - ecdsa_get_address(child_pubkey, version, addr, addrsize); + ecdsa_get_address(child_pubkey, version, hasher_type, addr, addrsize); break; } } @@ -396,13 +396,13 @@ int hdnode_private_ckd_cached(HDNode *inout, const uint32_t *i, size_t i_count, void hdnode_get_address_raw(HDNode *node, uint32_t version, uint8_t *addr_raw) { hdnode_fill_public_key(node); - ecdsa_get_address_raw(node->public_key, version, addr_raw); + ecdsa_get_address_raw(node->public_key, version, node->curve->hasher_type, addr_raw); } void hdnode_get_address(HDNode *node, uint32_t version, char *addr, int addrsize) { hdnode_fill_public_key(node); - ecdsa_get_address(node->public_key, version, addr, addrsize); + ecdsa_get_address(node->public_key, version, node->curve->hasher_type, addr, addrsize); } void hdnode_fill_public_key(HDNode *node) @@ -543,7 +543,7 @@ int hdnode_nem_decrypt(const HDNode *node, const ed25519_public_key public_key, int hdnode_sign(HDNode *node, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64])) { if (node->curve->params) { - return ecdsa_sign(node->curve->params, node->private_key, msg, msg_len, sig, pby, is_canonical); + return ecdsa_sign(node->curve->params, node->curve->hasher_type, node->private_key, msg, msg_len, sig, pby, is_canonical); } else if (node->curve == &curve25519_info) { return 1; // signatures are not supported } else { @@ -609,7 +609,7 @@ static int hdnode_serialize(const HDNode *node, uint32_t fingerprint, uint32_t v node_data[45] = 0; memcpy(node_data + 46, node->private_key, 32); } - int ret = base58_encode_check(node_data, sizeof(node_data), str, strsize); + int ret = base58_encode_check(node_data, sizeof(node_data), node->curve->hasher_type, str, strsize); MEMSET_BZERO(node_data, sizeof(node_data)); return ret; } @@ -629,10 +629,10 @@ int hdnode_deserialize(const char *str, uint32_t version_public, uint32_t versio { uint8_t node_data[78]; memset(node, 0, sizeof(HDNode)); - if (base58_decode_check(str, node_data, sizeof(node_data)) != sizeof(node_data)) { + node->curve = get_curve_by_name(SECP256K1_NAME); + if (base58_decode_check(str, node->curve->hasher_type, node_data, sizeof(node_data)) != sizeof(node_data)) { return -1; } - node->curve = get_curve_by_name(SECP256K1_NAME); uint32_t version = read_be(node_data); if (version == version_public) { MEMSET_BZERO(node->private_key, sizeof(node->private_key)); diff --git a/bip32.h b/bip32.h index 043c50c58..14437c1ce 100644 --- a/bip32.h +++ b/bip32.h @@ -34,6 +34,7 @@ typedef struct { const char *bip32_name; // string for generating BIP32 xprv from seed const ecdsa_curve *params; // ecdsa curve parameters, null for ed25519 + HasherType hasher_type; // hasher type for BIP32 and ECDSA } curve_info; typedef struct { @@ -59,7 +60,7 @@ int hdnode_public_ckd_cp(const ecdsa_curve *curve, const curve_point *parent, co int hdnode_public_ckd(HDNode *inout, uint32_t i); -void hdnode_public_ckd_address_optimized(const curve_point *pub, const uint8_t *chain_code, uint32_t i, uint32_t version, char *addr, int addrsize, int addrformat); +void hdnode_public_ckd_address_optimized(const curve_point *pub, const uint8_t *chain_code, uint32_t i, uint32_t version, HasherType hasher_type, char *addr, int addrsize, int addrformat); #if USE_BIP32_CACHE int hdnode_private_ckd_cached(HDNode *inout, const uint32_t *i, size_t i_count, uint32_t *fingerprint); diff --git a/ecdsa.c b/ecdsa.c index e259aa7e8..28e4ce310 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -715,10 +715,10 @@ void generate_k_rfc6979(bignum256 *k, rfc6979_state *state) // msg is a data to be signed // msg_len is the message length -int ecdsa_sign(const ecdsa_curve *curve, const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64])) +int ecdsa_sign(const ecdsa_curve *curve, HasherType hasher_type, const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64])) { uint8_t hash[32]; - sha256_Raw(msg, msg_len, hash); + hasher_Raw(hasher_type, msg, msg_len, hash); int res = ecdsa_sign_digest(curve, priv_key, hash, sig, pby, is_canonical); MEMSET_BZERO(hash, sizeof(hash)); return res; @@ -727,11 +727,11 @@ int ecdsa_sign(const ecdsa_curve *curve, const uint8_t *priv_key, const uint8_t // msg is a data to be signed // msg_len is the message length -int ecdsa_sign_double(const ecdsa_curve *curve, const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64])) +int ecdsa_sign_double(const ecdsa_curve *curve, HasherType hasher_type, const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64])) { uint8_t hash[32]; - sha256_Raw(msg, msg_len, hash); - sha256_Raw(hash, 32, hash); + hasher_Raw(hasher_type, msg, msg_len, hash); + hasher_Raw(hasher_type, hash, 32, hash); int res = ecdsa_sign_digest(curve, priv_key, hash, sig, pby, is_canonical); MEMSET_BZERO(hash, sizeof(hash)); return res; @@ -880,75 +880,75 @@ int ecdsa_uncompress_pubkey(const ecdsa_curve *curve, const uint8_t *pub_key, ui return 1; } -void ecdsa_get_pubkeyhash(const uint8_t *pub_key, uint8_t *pubkeyhash) +void ecdsa_get_pubkeyhash(const uint8_t *pub_key, HasherType hasher_type, uint8_t *pubkeyhash) { - uint8_t h[32]; + uint8_t h[HASHER_DIGEST_LENGTH]; if (pub_key[0] == 0x04) { // uncompressed format - sha256_Raw(pub_key, 65, h); + hasher_Raw(hasher_type, pub_key, 65, h); } else if (pub_key[0] == 0x00) { // point at infinity - sha256_Raw(pub_key, 1, h); - } else { - sha256_Raw(pub_key, 33, h); // expecting compressed format + hasher_Raw(hasher_type, pub_key, 1, h); + } else { // expecting compressed format + hasher_Raw(hasher_type, pub_key, 33, h); } - ripemd160(h, 32, pubkeyhash); + ripemd160(h, HASHER_DIGEST_LENGTH, pubkeyhash); MEMSET_BZERO(h, sizeof(h)); } -void ecdsa_get_address_raw(const uint8_t *pub_key, uint32_t version, uint8_t *addr_raw) +void ecdsa_get_address_raw(const uint8_t *pub_key, uint32_t version, HasherType hasher_type, uint8_t *addr_raw) { size_t prefix_len = address_prefix_bytes_len(version); address_write_prefix_bytes(version, addr_raw); - ecdsa_get_pubkeyhash(pub_key, addr_raw + prefix_len); + ecdsa_get_pubkeyhash(pub_key, hasher_type, addr_raw + prefix_len); } -void ecdsa_get_address(const uint8_t *pub_key, uint32_t version, char *addr, int addrsize) +void ecdsa_get_address(const uint8_t *pub_key, uint32_t version, HasherType hasher_type, char *addr, int addrsize) { uint8_t raw[MAX_ADDR_RAW_SIZE]; size_t prefix_len = address_prefix_bytes_len(version); - ecdsa_get_address_raw(pub_key, version, raw); - base58_encode_check(raw, 20 + prefix_len, addr, addrsize); + ecdsa_get_address_raw(pub_key, version, hasher_type, raw); + base58_encode_check(raw, 20 + prefix_len, hasher_type, addr, addrsize); // not as important to clear this one, but we might as well MEMSET_BZERO(raw, sizeof(raw)); } -void ecdsa_get_address_segwit_p2sh_raw(const uint8_t *pub_key, uint32_t version, uint8_t *addr_raw) +void ecdsa_get_address_segwit_p2sh_raw(const uint8_t *pub_key, uint32_t version, HasherType hasher_type, uint8_t *addr_raw) { size_t prefix_len = address_prefix_bytes_len(version); uint8_t digest[32]; addr_raw[0] = 0; // version byte addr_raw[1] = 20; // push 20 bytes - ecdsa_get_pubkeyhash(pub_key, addr_raw + 2); - sha256_Raw(addr_raw, 22, digest); + ecdsa_get_pubkeyhash(pub_key, hasher_type, addr_raw + 2); + hasher_Raw(hasher_type, addr_raw, 22, digest); address_write_prefix_bytes(version, addr_raw); ripemd160(digest, 32, addr_raw + prefix_len); } -void ecdsa_get_address_segwit_p2sh(const uint8_t *pub_key, uint32_t version, char *addr, int addrsize) +void ecdsa_get_address_segwit_p2sh(const uint8_t *pub_key, uint32_t version, HasherType hasher_type, char *addr, int addrsize) { uint8_t raw[MAX_ADDR_RAW_SIZE]; size_t prefix_len = address_prefix_bytes_len(version); - ecdsa_get_address_segwit_p2sh_raw(pub_key, version, raw); - base58_encode_check(raw, prefix_len + 20, addr, addrsize); + ecdsa_get_address_segwit_p2sh_raw(pub_key, version, hasher_type, raw); + base58_encode_check(raw, prefix_len + 20, hasher_type, addr, addrsize); MEMSET_BZERO(raw, sizeof(raw)); } -void ecdsa_get_wif(const uint8_t *priv_key, uint32_t version, char *wif, int wifsize) +void ecdsa_get_wif(const uint8_t *priv_key, uint32_t version, HasherType hasher_type, char *wif, int wifsize) { uint8_t wif_raw[MAX_WIF_RAW_SIZE]; size_t prefix_len = address_prefix_bytes_len(version); address_write_prefix_bytes(version, wif_raw); memcpy(wif_raw + prefix_len, priv_key, 32); wif_raw[prefix_len + 32] = 0x01; - base58_encode_check(wif_raw, prefix_len + 32 + 1, wif, wifsize); + base58_encode_check(wif_raw, prefix_len + 32 + 1, hasher_type, wif, wifsize); // private keys running around our stack can cause trouble MEMSET_BZERO(wif_raw, sizeof(wif_raw)); } -int ecdsa_address_decode(const char *addr, uint32_t version, uint8_t *out) +int ecdsa_address_decode(const char *addr, uint32_t version, HasherType hasher_type, uint8_t *out) { if (!addr) return 0; int prefix_len = address_prefix_bytes_len(version); - return base58_decode_check(addr, out, 20 + prefix_len) == 20 + prefix_len + return base58_decode_check(addr, hasher_type, out, 20 + prefix_len) == 20 + prefix_len && address_check_prefix(out, version); } @@ -1029,20 +1029,20 @@ int ecdsa_validate_pubkey(const ecdsa_curve *curve, const curve_point *pub) // msg is a data that was signed // msg_len is the message length -int ecdsa_verify(const ecdsa_curve *curve, const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, uint32_t msg_len) +int ecdsa_verify(const ecdsa_curve *curve, HasherType hasher_type, const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, uint32_t msg_len) { uint8_t hash[32]; - sha256_Raw(msg, msg_len, hash); + hasher_Raw(hasher_type, msg, msg_len, hash); int res = ecdsa_verify_digest(curve, pub_key, sig, hash); MEMSET_BZERO(hash, sizeof(hash)); return res; } -int ecdsa_verify_double(const ecdsa_curve *curve, const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, uint32_t msg_len) +int ecdsa_verify_double(const ecdsa_curve *curve, HasherType hasher_type, const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, uint32_t msg_len) { uint8_t hash[32]; - sha256_Raw(msg, msg_len, hash); - sha256_Raw(hash, 32, hash); + hasher_Raw(hasher_type, msg, msg_len, hash); + hasher_Raw(hasher_type, hash, 32, hash); int res = ecdsa_verify_digest(curve, pub_key, sig, hash); MEMSET_BZERO(hash, sizeof(hash)); return res; diff --git a/ecdsa.h b/ecdsa.h index 84d1665b4..d9bd1d1e6 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -27,6 +27,7 @@ #include #include "options.h" #include "bignum.h" +#include "hasher.h" // curve point x and y typedef struct { @@ -72,23 +73,23 @@ int ecdh_multiply(const ecdsa_curve *curve, const uint8_t *priv_key, const uint8 void uncompress_coords(const ecdsa_curve *curve, uint8_t odd, const bignum256 *x, bignum256 *y); int ecdsa_uncompress_pubkey(const ecdsa_curve *curve, const uint8_t *pub_key, uint8_t *uncompressed); -int ecdsa_sign(const ecdsa_curve *curve, const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64])); -int ecdsa_sign_double(const ecdsa_curve *curve, const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64])); +int ecdsa_sign(const ecdsa_curve *curve, HasherType hasher_type, const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64])); +int ecdsa_sign_double(const ecdsa_curve *curve, HasherType hasher_type, const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64])); int ecdsa_sign_digest(const ecdsa_curve *curve, const uint8_t *priv_key, const uint8_t *digest, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64])); void ecdsa_get_public_key33(const ecdsa_curve *curve, const uint8_t *priv_key, uint8_t *pub_key); void ecdsa_get_public_key65(const ecdsa_curve *curve, const uint8_t *priv_key, uint8_t *pub_key); -void ecdsa_get_pubkeyhash(const uint8_t *pub_key, uint8_t *pubkeyhash); -void ecdsa_get_address_raw(const uint8_t *pub_key, uint32_t version, uint8_t *addr_raw); -void ecdsa_get_address(const uint8_t *pub_key, uint32_t version, char *addr, int addrsize); -void ecdsa_get_address_segwit_p2sh_raw(const uint8_t *pub_key, uint32_t version, uint8_t *addr_raw); -void ecdsa_get_address_segwit_p2sh(const uint8_t *pub_key, uint32_t version, char *addr, int addrsize); -void ecdsa_get_wif(const uint8_t *priv_key, uint32_t version, char *wif, int wifsize); +void ecdsa_get_pubkeyhash(const uint8_t *pub_key, HasherType hasher_type, uint8_t *pubkeyhash); +void ecdsa_get_address_raw(const uint8_t *pub_key, uint32_t version, HasherType hasher_type, uint8_t *addr_raw); +void ecdsa_get_address(const uint8_t *pub_key, uint32_t version, HasherType hasher_type, char *addr, int addrsize); +void ecdsa_get_address_segwit_p2sh_raw(const uint8_t *pub_key, uint32_t version, HasherType hasher_type, uint8_t *addr_raw); +void ecdsa_get_address_segwit_p2sh(const uint8_t *pub_key, uint32_t version, HasherType hasher_type, char *addr, int addrsize); +void ecdsa_get_wif(const uint8_t *priv_key, uint32_t version, HasherType hasher_type, char *wif, int wifsize); -int ecdsa_address_decode(const char *addr, uint32_t version, uint8_t *out); +int ecdsa_address_decode(const char *addr, uint32_t version, HasherType hasher_type, uint8_t *out); int ecdsa_read_pubkey(const ecdsa_curve *curve, const uint8_t *pub_key, curve_point *pub); int ecdsa_validate_pubkey(const ecdsa_curve *curve, const curve_point *pub); -int ecdsa_verify(const ecdsa_curve *curve, const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, uint32_t msg_len); -int ecdsa_verify_double(const ecdsa_curve *curve, const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, uint32_t msg_len); +int ecdsa_verify(const ecdsa_curve *curve, HasherType hasher_type, const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, uint32_t msg_len); +int ecdsa_verify_double(const ecdsa_curve *curve, HasherType hasher_type, const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, uint32_t msg_len); int ecdsa_verify_digest(const ecdsa_curve *curve, const uint8_t *pub_key, const uint8_t *sig, const uint8_t *digest); int ecdsa_verify_digest_recover(const ecdsa_curve *curve, uint8_t *pub_key, const uint8_t *sig, const uint8_t *digest, int recid); int ecdsa_sig_to_der(const uint8_t *sig, uint8_t *der); diff --git a/nist256p1.c b/nist256p1.c index 4c1d971bf..ef61ac5e0 100644 --- a/nist256p1.c +++ b/nist256p1.c @@ -56,7 +56,7 @@ const ecdsa_curve nist256p1 = { }; const curve_info nist256p1_info = { - /* bip32_name */ - "Nist256p1 seed", - &nist256p1 + .bip32_name = "Nist256p1 seed", + .params = &nist256p1, + .hasher_type = HASHER_SHA2, }; diff --git a/script.c b/script.c index 185d28fae..ed6f821a0 100644 --- a/script.c +++ b/script.c @@ -32,14 +32,14 @@ int script_output_to_address(const uint8_t *script, int scriptlen, char *addr, i if (scriptlen == 25 && script[0] == 0x76 && script[1] == 0xA9 && script[2] == 0x14 && script[23] == 0x88 && script[24] == 0xAC) { raw[0] = 0x00; memcpy(raw + 1, script + 3, 20); - return base58_encode_check(raw, 1 + 20, addr, addrsize); + return base58_encode_check(raw, 1 + 20, HASHER_SHA2, addr, addrsize); } // P2SH if (scriptlen == 23 && script[0] == 0xA9 && script[1] == 0x14 && script[22] == 0x87) { raw[0] = 0x05; memcpy(raw + 1, script + 2, 20); - return base58_encode_check(raw, 1 + 20, addr, addrsize); + return base58_encode_check(raw, 1 + 20, HASHER_SHA2, addr, addrsize); } // P2WPKH @@ -48,7 +48,7 @@ int script_output_to_address(const uint8_t *script, int scriptlen, char *addr, i raw[1] = 0x00; raw[2] = 0x00; memcpy(raw + 3, script + 2, 20); - return base58_encode_check(raw, 3 + 20, addr, addrsize); + return base58_encode_check(raw, 3 + 20, HASHER_SHA2, addr, addrsize); } // P2WSH @@ -57,7 +57,7 @@ int script_output_to_address(const uint8_t *script, int scriptlen, char *addr, i raw[1] = 0x00; raw[2] = 0x00; memcpy(raw + 3, script + 2, 32); - return base58_encode_check(raw, 3 + 32, addr, addrsize); + return base58_encode_check(raw, 3 + 32, HASHER_SHA2, addr, addrsize); } return 0; diff --git a/secp256k1.c b/secp256k1.c index aa4964171..c607aa472 100644 --- a/secp256k1.c +++ b/secp256k1.c @@ -56,7 +56,7 @@ const ecdsa_curve secp256k1 = { }; const curve_info secp256k1_info = { - /* bip32_name */ - "Bitcoin seed", - &secp256k1 + .bip32_name = "Bitcoin seed", + .params = &secp256k1, + .hasher_type = HASHER_SHA2, }; diff --git a/test_check.c b/test_check.c index e05d65041..900399737 100644 --- a/test_check.c +++ b/test_check.c @@ -732,11 +732,11 @@ START_TEST(test_base58) int len = strlen(*raw) / 2; memcpy(rawn, fromhex(*raw), len); - r = base58_encode_check(rawn, len, strn, sizeof(strn)); + r = base58_encode_check(rawn, len, HASHER_SHA2, strn, sizeof(strn)); ck_assert_int_eq((size_t)r, strlen(*str) + 1); ck_assert_str_eq(strn, *str); - r = base58_decode_check(strn, rawn, len); + r = base58_decode_check(strn, HASHER_SHA2, rawn, len); ck_assert_int_eq(r, len); ck_assert_mem_eq(rawn, fromhex(*raw), len); @@ -1139,9 +1139,9 @@ START_TEST(test_bip32_optimized) memcpy(&node, &root, sizeof(HDNode)); hdnode_public_ckd(&node, i); hdnode_fill_public_key(&node); - ecdsa_get_address(node.public_key, 0, addr1, sizeof(addr1)); + ecdsa_get_address(node.public_key, 0, HASHER_SHA2, addr1, sizeof(addr1)); // optimized - hdnode_public_ckd_address_optimized(&pub, root.chain_code, i, 0, addr2, sizeof(addr2), 0); + hdnode_public_ckd_address_optimized(&pub, root.chain_code, i, 0, HASHER_SHA2, addr2, sizeof(addr2), 0); // check ck_assert_str_eq(addr1, addr2); } @@ -2433,50 +2433,50 @@ START_TEST(test_address) uint8_t pub_key[65]; memcpy(pub_key, fromhex("0226659c1cf7321c178c07437150639ff0c5b7679c7ea195253ed9abda2e081a37"), 33); - ecdsa_get_address(pub_key, 0, address, sizeof(address)); ck_assert_str_eq(address, "139MaMHp3Vjo8o4x8N1ZLWEtovLGvBsg6s"); - ecdsa_get_address(pub_key, 111, address, sizeof(address)); ck_assert_str_eq(address, "mhfJsQNnrXB3uuYZqvywARTDfuvyjg4RBh"); - ecdsa_get_address(pub_key, 52, address, sizeof(address)); ck_assert_str_eq(address, "MxiimznnxsqMfLKTQBL8Z2PoY9jKpjgkCu"); - ecdsa_get_address(pub_key, 48, address, sizeof(address)); ck_assert_str_eq(address, "LMNJqZbe89yrPbm7JVzrcXJf28hZ1rKPaH"); - ecdsa_get_address_segwit_p2sh(pub_key, 5, address, sizeof(address)); ck_assert_str_eq(address, "34PyTHn74syS796eTgsyoLfwoBC3cwLn6p"); + ecdsa_get_address(pub_key, 0, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "139MaMHp3Vjo8o4x8N1ZLWEtovLGvBsg6s"); + ecdsa_get_address(pub_key, 111, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "mhfJsQNnrXB3uuYZqvywARTDfuvyjg4RBh"); + ecdsa_get_address(pub_key, 52, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "MxiimznnxsqMfLKTQBL8Z2PoY9jKpjgkCu"); + ecdsa_get_address(pub_key, 48, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "LMNJqZbe89yrPbm7JVzrcXJf28hZ1rKPaH"); + ecdsa_get_address_segwit_p2sh(pub_key, 5, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "34PyTHn74syS796eTgsyoLfwoBC3cwLn6p"); memcpy(pub_key, fromhex("025b1654a0e78d28810094f6c5a96b8efb8a65668b578f170ac2b1f83bc63ba856"), 33); - ecdsa_get_address(pub_key, 0, address, sizeof(address)); ck_assert_str_eq(address, "19Ywfm3witp6C1yBMy4NRYHY2347WCRBfQ"); - ecdsa_get_address(pub_key, 111, address, sizeof(address)); ck_assert_str_eq(address, "mp4txp8vXvFLy8So5Y2kFTVrt2epN6YzdP"); - ecdsa_get_address(pub_key, 52, address, sizeof(address)); ck_assert_str_eq(address, "N58JsQYveGueiZDgdnNwe4SSkGTAToutAY"); - ecdsa_get_address(pub_key, 48, address, sizeof(address)); ck_assert_str_eq(address, "LTmtvyMmoZ49SpfLY73fhZMJEFRPdyohKh"); - ecdsa_get_address_segwit_p2sh(pub_key, 5, address, sizeof(address)); ck_assert_str_eq(address, "35trq6eeuHf6VL9L8pQv46x3vegHnHoTuB"); + ecdsa_get_address(pub_key, 0, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "19Ywfm3witp6C1yBMy4NRYHY2347WCRBfQ"); + ecdsa_get_address(pub_key, 111, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "mp4txp8vXvFLy8So5Y2kFTVrt2epN6YzdP"); + ecdsa_get_address(pub_key, 52, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "N58JsQYveGueiZDgdnNwe4SSkGTAToutAY"); + ecdsa_get_address(pub_key, 48, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "LTmtvyMmoZ49SpfLY73fhZMJEFRPdyohKh"); + ecdsa_get_address_segwit_p2sh(pub_key, 5, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "35trq6eeuHf6VL9L8pQv46x3vegHnHoTuB"); memcpy(pub_key, fromhex("03433f246a12e6486a51ff08802228c61cf895175a9b49ed4766ea9a9294a3c7fe"), 33); - ecdsa_get_address(pub_key, 0, address, sizeof(address)); ck_assert_str_eq(address, "1FWE2bn3MWhc4QidcF6AvEWpK77sSi2cAP"); - ecdsa_get_address(pub_key, 111, address, sizeof(address)); ck_assert_str_eq(address, "mv2BKes2AY8rqXCFKp4Yk9j9B6iaMfWRLN"); - ecdsa_get_address(pub_key, 52, address, sizeof(address)); ck_assert_str_eq(address, "NB5bEFH2GtoAawy8t4Qk8kfj3LWvQs3MhB"); - ecdsa_get_address(pub_key, 48, address, sizeof(address)); ck_assert_str_eq(address, "LZjBHp5sSAwfKDQnnP5UCFaaXKV9YheGxQ"); - ecdsa_get_address_segwit_p2sh(pub_key, 5, address, sizeof(address)); ck_assert_str_eq(address, "3456DYaKUWuY6RWWw8Hp5CftHLcQN29h9Y"); + ecdsa_get_address(pub_key, 0, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "1FWE2bn3MWhc4QidcF6AvEWpK77sSi2cAP"); + ecdsa_get_address(pub_key, 111, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "mv2BKes2AY8rqXCFKp4Yk9j9B6iaMfWRLN"); + ecdsa_get_address(pub_key, 52, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "NB5bEFH2GtoAawy8t4Qk8kfj3LWvQs3MhB"); + ecdsa_get_address(pub_key, 48, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "LZjBHp5sSAwfKDQnnP5UCFaaXKV9YheGxQ"); + ecdsa_get_address_segwit_p2sh(pub_key, 5, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "3456DYaKUWuY6RWWw8Hp5CftHLcQN29h9Y"); memcpy(pub_key, fromhex("03aeb03abeee0f0f8b4f7a5d65ce31f9570cef9f72c2dd8a19b4085a30ab033d48"), 33); - ecdsa_get_address(pub_key, 0, address, sizeof(address)); ck_assert_str_eq(address, "1yrZb8dhdevoqpUEGi2tUccUEeiMKeLcs"); - ecdsa_get_address(pub_key, 111, address, sizeof(address)); ck_assert_str_eq(address, "mgVoreDcWf6BaxJ5wqgQiPpwLEFRLSr8U8"); - ecdsa_get_address(pub_key, 52, address, sizeof(address)); ck_assert_str_eq(address, "MwZDmEdcd1kVLP4yW62c6zmXCU3mNbveDo"); - ecdsa_get_address(pub_key, 48, address, sizeof(address)); ck_assert_str_eq(address, "LLCopoSTnHtz4eWdQQhLAVgNgT1zTi4QBK"); - ecdsa_get_address_segwit_p2sh(pub_key, 5, address, sizeof(address)); ck_assert_str_eq(address, "3DBU4tJ9tkMR9fnmCtjW48kjvseoNLQZXd"); + ecdsa_get_address(pub_key, 0, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "1yrZb8dhdevoqpUEGi2tUccUEeiMKeLcs"); + ecdsa_get_address(pub_key, 111, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "mgVoreDcWf6BaxJ5wqgQiPpwLEFRLSr8U8"); + ecdsa_get_address(pub_key, 52, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "MwZDmEdcd1kVLP4yW62c6zmXCU3mNbveDo"); + ecdsa_get_address(pub_key, 48, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "LLCopoSTnHtz4eWdQQhLAVgNgT1zTi4QBK"); + ecdsa_get_address_segwit_p2sh(pub_key, 5, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "3DBU4tJ9tkMR9fnmCtjW48kjvseoNLQZXd"); memcpy(pub_key, fromhex("0496e8f2093f018aff6c2e2da5201ee528e2c8accbf9cac51563d33a7bb74a016054201c025e2a5d96b1629b95194e806c63eb96facaedc733b1a4b70ab3b33e3a"), 65); - ecdsa_get_address(pub_key, 0, address, sizeof(address)); ck_assert_str_eq(address, "194SZbL75xCCGBbKtMsyWLE5r9s2V6mhVM"); - ecdsa_get_address(pub_key, 111, address, sizeof(address)); ck_assert_str_eq(address, "moaPreR5tydT3J4wbvrMLFSQi9TjPCiZc6"); - ecdsa_get_address(pub_key, 52, address, sizeof(address)); ck_assert_str_eq(address, "N4domEq61LHkniqqABCYirNzaPG5NRU8GH"); - ecdsa_get_address(pub_key, 48, address, sizeof(address)); ck_assert_str_eq(address, "LTHPpodwAcSFWzHV4VsGnMHr4NEJajMnKX"); + ecdsa_get_address(pub_key, 0, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "194SZbL75xCCGBbKtMsyWLE5r9s2V6mhVM"); + ecdsa_get_address(pub_key, 111, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "moaPreR5tydT3J4wbvrMLFSQi9TjPCiZc6"); + ecdsa_get_address(pub_key, 52, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "N4domEq61LHkniqqABCYirNzaPG5NRU8GH"); + ecdsa_get_address(pub_key, 48, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "LTHPpodwAcSFWzHV4VsGnMHr4NEJajMnKX"); memcpy(pub_key, fromhex("0498010f8a687439ff497d3074beb4519754e72c4b6220fb669224749591dde416f3961f8ece18f8689bb32235e436874d2174048b86118a00afbd5a4f33a24f0f"), 65); - ecdsa_get_address(pub_key, 0, address, sizeof(address)); ck_assert_str_eq(address, "1A2WfBD4BJFwYHFPc5KgktqtbdJLBuVKc4"); - ecdsa_get_address(pub_key, 111, address, sizeof(address)); ck_assert_str_eq(address, "mpYTxEJ2zKhCKPj1KeJ4ap4DTcu39T3uzD"); - ecdsa_get_address(pub_key, 52, address, sizeof(address)); ck_assert_str_eq(address, "N5bsrpi36gMW4pVtsteFyQzoKrhPE7nkxK"); - ecdsa_get_address(pub_key, 48, address, sizeof(address)); ck_assert_str_eq(address, "LUFTvPWtFxVzo5wYnDJz2uueoqfcMYiuxH"); + ecdsa_get_address(pub_key, 0, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "1A2WfBD4BJFwYHFPc5KgktqtbdJLBuVKc4"); + ecdsa_get_address(pub_key, 111, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "mpYTxEJ2zKhCKPj1KeJ4ap4DTcu39T3uzD"); + ecdsa_get_address(pub_key, 52, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "N5bsrpi36gMW4pVtsteFyQzoKrhPE7nkxK"); + ecdsa_get_address(pub_key, 48, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "LUFTvPWtFxVzo5wYnDJz2uueoqfcMYiuxH"); memcpy(pub_key, fromhex("04f80490839af36d13701ec3f9eebdac901b51c362119d74553a3c537faff31b17e2a59ebddbdac9e87b816307a7ed5b826b8f40b92719086238e1bebf19b77a4d"), 65); - ecdsa_get_address(pub_key, 0, address, sizeof(address)); ck_assert_str_eq(address, "19J81hrPnQxg9UGx45ibTieCkb2ttm8CLL"); - ecdsa_get_address(pub_key, 111, address, sizeof(address)); ck_assert_str_eq(address, "mop5JkwNbSPvvakZmegyHdrXcadbjLazww"); - ecdsa_get_address(pub_key, 52, address, sizeof(address)); ck_assert_str_eq(address, "N4sVDMMNho4Eg1XTKu3AgEo7UpRwq3aNbn"); - ecdsa_get_address(pub_key, 48, address, sizeof(address)); ck_assert_str_eq(address, "LTX5GvADs5CjQGy7EDhtjjhxxoQB2Uhicd"); + ecdsa_get_address(pub_key, 0, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "19J81hrPnQxg9UGx45ibTieCkb2ttm8CLL"); + ecdsa_get_address(pub_key, 111, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "mop5JkwNbSPvvakZmegyHdrXcadbjLazww"); + ecdsa_get_address(pub_key, 52, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "N4sVDMMNho4Eg1XTKu3AgEo7UpRwq3aNbn"); + ecdsa_get_address(pub_key, 48, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "LTX5GvADs5CjQGy7EDhtjjhxxoQB2Uhicd"); } END_TEST @@ -2563,16 +2563,16 @@ START_TEST(test_wif) char wif[53]; memcpy(priv_key, fromhex("1111111111111111111111111111111111111111111111111111111111111111"), 32); - ecdsa_get_wif(priv_key, 0x80, wif, sizeof(wif)); ck_assert_str_eq(wif, "KwntMbt59tTsj8xqpqYqRRWufyjGunvhSyeMo3NTYpFYzZbXJ5Hp"); - ecdsa_get_wif(priv_key, 0xEF, wif, sizeof(wif)); ck_assert_str_eq(wif, "cN9spWsvaxA8taS7DFMxnk1yJD2gaF2PX1npuTpy3vuZFJdwavaw"); + ecdsa_get_wif(priv_key, 0x80, HASHER_SHA2, wif, sizeof(wif)); ck_assert_str_eq(wif, "KwntMbt59tTsj8xqpqYqRRWufyjGunvhSyeMo3NTYpFYzZbXJ5Hp"); + ecdsa_get_wif(priv_key, 0xEF, HASHER_SHA2, wif, sizeof(wif)); ck_assert_str_eq(wif, "cN9spWsvaxA8taS7DFMxnk1yJD2gaF2PX1npuTpy3vuZFJdwavaw"); memcpy(priv_key, fromhex("dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"), 32); - ecdsa_get_wif(priv_key, 0x80, wif, sizeof(wif)); ck_assert_str_eq(wif, "L4ezQvyC6QoBhxB4GVs9fAPhUKtbaXYUn8YTqoeXwbevQq4U92vN"); - ecdsa_get_wif(priv_key, 0xEF, wif, sizeof(wif)); ck_assert_str_eq(wif, "cV1ysqy3XUVSsPeKeugH2Utm6ZC1EyeArAgvxE73SiJvfa6AJng7"); + ecdsa_get_wif(priv_key, 0x80, HASHER_SHA2, wif, sizeof(wif)); ck_assert_str_eq(wif, "L4ezQvyC6QoBhxB4GVs9fAPhUKtbaXYUn8YTqoeXwbevQq4U92vN"); + ecdsa_get_wif(priv_key, 0xEF, HASHER_SHA2, wif, sizeof(wif)); ck_assert_str_eq(wif, "cV1ysqy3XUVSsPeKeugH2Utm6ZC1EyeArAgvxE73SiJvfa6AJng7"); memcpy(priv_key, fromhex("47f7616ea6f9b923076625b4488115de1ef1187f760e65f89eb6f4f7ff04b012"), 32); - ecdsa_get_wif(priv_key, 0x80, wif, sizeof(wif)); ck_assert_str_eq(wif, "KydbzBtk6uc7M6dXwEgTEH2sphZxSPbmDSz6kUUHi4eUpSQuhEbq"); - ecdsa_get_wif(priv_key, 0xEF, wif, sizeof(wif)); ck_assert_str_eq(wif, "cPzbT6tbXyJNWY6oKeVabbXwSvsN6qhTHV8ZrtvoDBJV5BRY1G5Q"); + ecdsa_get_wif(priv_key, 0x80, HASHER_SHA2, wif, sizeof(wif)); ck_assert_str_eq(wif, "KydbzBtk6uc7M6dXwEgTEH2sphZxSPbmDSz6kUUHi4eUpSQuhEbq"); + ecdsa_get_wif(priv_key, 0xEF, HASHER_SHA2, wif, sizeof(wif)); ck_assert_str_eq(wif, "cPzbT6tbXyJNWY6oKeVabbXwSvsN6qhTHV8ZrtvoDBJV5BRY1G5Q"); } END_TEST @@ -2581,48 +2581,48 @@ START_TEST(test_address_decode) int res; uint8_t decode[MAX_ADDR_RAW_SIZE]; - res = ecdsa_address_decode("1JwSSubhmg6iPtRjtyqhUYYH7bZg3Lfy1T", 0, decode); + res = ecdsa_address_decode("1JwSSubhmg6iPtRjtyqhUYYH7bZg3Lfy1T", 0, HASHER_SHA2, decode); ck_assert_int_eq(res, 1); ck_assert_mem_eq(decode, fromhex("00c4c5d791fcb4654a1ef5e03fe0ad3d9c598f9827"), 21); - res = ecdsa_address_decode("myTPjxggahXyAzuMcYp5JTkbybANyLsYBW", 111, decode); + res = ecdsa_address_decode("myTPjxggahXyAzuMcYp5JTkbybANyLsYBW", 111, HASHER_SHA2, decode); ck_assert_int_eq(res, 1); ck_assert_mem_eq(decode, fromhex("6fc4c5d791fcb4654a1ef5e03fe0ad3d9c598f9827"), 21); - res = ecdsa_address_decode("NEWoeZ6gh4CGvRgFAoAGh4hBqpxizGT6gZ", 52, decode); + res = ecdsa_address_decode("NEWoeZ6gh4CGvRgFAoAGh4hBqpxizGT6gZ", 52, HASHER_SHA2, decode); ck_assert_int_eq(res, 1); ck_assert_mem_eq(decode, fromhex("34c4c5d791fcb4654a1ef5e03fe0ad3d9c598f9827"), 21); - res = ecdsa_address_decode("LdAPi7uXrLLmeh7u57pzkZc3KovxEDYRJq", 48, decode); + res = ecdsa_address_decode("LdAPi7uXrLLmeh7u57pzkZc3KovxEDYRJq", 48, HASHER_SHA2, decode); ck_assert_int_eq(res, 1); ck_assert_mem_eq(decode, fromhex("30c4c5d791fcb4654a1ef5e03fe0ad3d9c598f9827"), 21); - res = ecdsa_address_decode("1C7zdTfnkzmr13HfA2vNm5SJYRK6nEKyq8", 0, decode); + res = ecdsa_address_decode("1C7zdTfnkzmr13HfA2vNm5SJYRK6nEKyq8", 0, HASHER_SHA2, decode); ck_assert_int_eq(res, 1); ck_assert_mem_eq(decode, fromhex("0079fbfc3f34e7745860d76137da68f362380c606c"), 21); - res = ecdsa_address_decode("mrdwvWkma2D6n9mGsbtkazedQQuoksnqJV", 111, decode); + res = ecdsa_address_decode("mrdwvWkma2D6n9mGsbtkazedQQuoksnqJV", 111, HASHER_SHA2, decode); ck_assert_int_eq(res, 1); ck_assert_mem_eq(decode, fromhex("6f79fbfc3f34e7745860d76137da68f362380c606c"), 21); - res = ecdsa_address_decode("N7hMq7AmgNsQXaYARrEwybbDGei9mcPNqr", 52, decode); + res = ecdsa_address_decode("N7hMq7AmgNsQXaYARrEwybbDGei9mcPNqr", 52, HASHER_SHA2, decode); ck_assert_int_eq(res, 1); ck_assert_mem_eq(decode, fromhex("3479fbfc3f34e7745860d76137da68f362380c606c"), 21); - res = ecdsa_address_decode("LWLwtfycqf1uFqypLAug36W4kdgNwrZdNs", 48, decode); + res = ecdsa_address_decode("LWLwtfycqf1uFqypLAug36W4kdgNwrZdNs", 48, HASHER_SHA2, decode); ck_assert_int_eq(res, 1); ck_assert_mem_eq(decode, fromhex("3079fbfc3f34e7745860d76137da68f362380c606c"), 21); // invalid char - res = ecdsa_address_decode("1JwSSubhmg6i000jtyqhUYYH7bZg3Lfy1T", 0, decode); + res = ecdsa_address_decode("1JwSSubhmg6i000jtyqhUYYH7bZg3Lfy1T", 0, HASHER_SHA2, decode); ck_assert_int_eq(res, 0); // invalid address - res = ecdsa_address_decode("1111Subhmg6iPtRjtyqhUYYH7bZg3Lfy1T", 0, decode); + res = ecdsa_address_decode("1111Subhmg6iPtRjtyqhUYYH7bZg3Lfy1T", 0, HASHER_SHA2, decode); ck_assert_int_eq(res, 0); // invalid version - res = ecdsa_address_decode("LWLwtfycqf1uFqypLAug36W4kdgNwrZdNs", 0, decode); + res = ecdsa_address_decode("LWLwtfycqf1uFqypLAug36W4kdgNwrZdNs", 0, HASHER_SHA2, decode); ck_assert_int_eq(res, 0); } END_TEST @@ -3794,50 +3794,50 @@ START_TEST(test_multibyte_address) int res; memcpy(priv_key, fromhex("47f7616ea6f9b923076625b4488115de1ef1187f760e65f89eb6f4f7ff04b012"), 32); - ecdsa_get_wif(priv_key, 0, wif, sizeof(wif)); ck_assert_str_eq(wif, "13QtoXmbhELWcrwD9YA9KzvXy5rTaptiNuFR8L8ArpBNn4xmQj4N"); - ecdsa_get_wif(priv_key, 0x12, wif, sizeof(wif)); ck_assert_str_eq(wif, "3hrF6SFnqzpzABB36uGDf8dJSuUCcMmoJrTmCWMshRkBr2Vx86qJ"); - ecdsa_get_wif(priv_key, 0x1234, wif, sizeof(wif)); ck_assert_str_eq(wif, "CtPTF9awbVbfDWGepGdVhB3nBhr4HktUGya8nf8dLxgC8tbqBreB9"); - ecdsa_get_wif(priv_key, 0x123456, wif, sizeof(wif)); ck_assert_str_eq(wif, "uTrDevVQt5QZgoL3iJ1cPWHaCz7ZMBncM7QXZfCegtxiMHqBvWoYJa"); - ecdsa_get_wif(priv_key, 0x12345678, wif, sizeof(wif)); ck_assert_str_eq(wif, "4zZWMzv1SVbs95pmLXWrXJVp9ntPEam1mfwb6CXBLn9MpWNxLg9huYgv"); - ecdsa_get_wif(priv_key, 0xffffffff, wif, sizeof(wif)); ck_assert_str_eq(wif, "y9KVfV1RJXcTxpVjeuh6WYWh8tMwnAUeyUwDEiRviYdrJ61njTmnfUjE"); + ecdsa_get_wif(priv_key, 0, HASHER_SHA2, wif, sizeof(wif)); ck_assert_str_eq(wif, "13QtoXmbhELWcrwD9YA9KzvXy5rTaptiNuFR8L8ArpBNn4xmQj4N"); + ecdsa_get_wif(priv_key, 0x12, HASHER_SHA2, wif, sizeof(wif)); ck_assert_str_eq(wif, "3hrF6SFnqzpzABB36uGDf8dJSuUCcMmoJrTmCWMshRkBr2Vx86qJ"); + ecdsa_get_wif(priv_key, 0x1234, HASHER_SHA2, wif, sizeof(wif)); ck_assert_str_eq(wif, "CtPTF9awbVbfDWGepGdVhB3nBhr4HktUGya8nf8dLxgC8tbqBreB9"); + ecdsa_get_wif(priv_key, 0x123456, HASHER_SHA2, wif, sizeof(wif)); ck_assert_str_eq(wif, "uTrDevVQt5QZgoL3iJ1cPWHaCz7ZMBncM7QXZfCegtxiMHqBvWoYJa"); + ecdsa_get_wif(priv_key, 0x12345678, HASHER_SHA2, wif, sizeof(wif)); ck_assert_str_eq(wif, "4zZWMzv1SVbs95pmLXWrXJVp9ntPEam1mfwb6CXBLn9MpWNxLg9huYgv"); + ecdsa_get_wif(priv_key, 0xffffffff, HASHER_SHA2, wif, sizeof(wif)); ck_assert_str_eq(wif, "y9KVfV1RJXcTxpVjeuh6WYWh8tMwnAUeyUwDEiRviYdrJ61njTmnfUjE"); memcpy(pub_key, fromhex("0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71"), 33); - ecdsa_get_address(pub_key, 0, address, sizeof(address)); ck_assert_str_eq(address, "1C7zdTfnkzmr13HfA2vNm5SJYRK6nEKyq8"); - ecdsa_get_address(pub_key, 0x12, address, sizeof(address)); ck_assert_str_eq(address, "8SCrMR2yYF7ciqoDbav7VLLTsVx5dTVPPq"); - ecdsa_get_address(pub_key, 0x1234, address, sizeof(address)); ck_assert_str_eq(address, "ZLH8q1UgMPg8o2s1MD55YVMpPV7vqms9kiV"); - ecdsa_get_address(pub_key, 0x123456, address, sizeof(address)); ck_assert_str_eq(address, "3ThqvsQVFnbiF66NwHtfe2j6AKn75DpLKpQSq"); - ecdsa_get_address(pub_key, 0x12345678, address, sizeof(address)); ck_assert_str_eq(address, "BrsGxAHga3VbopvSnb3gmLvMBhJNCGuDxBZL44"); - ecdsa_get_address(pub_key, 0xffffffff, address, sizeof(address)); ck_assert_str_eq(address, "3diW7paWGJyZRLGqMJZ55DMfPExob8QxQHkrfYT"); - - res = ecdsa_address_decode("1C7zdTfnkzmr13HfA2vNm5SJYRK6nEKyq8", 0, decode); + ecdsa_get_address(pub_key, 0, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "1C7zdTfnkzmr13HfA2vNm5SJYRK6nEKyq8"); + ecdsa_get_address(pub_key, 0x12, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "8SCrMR2yYF7ciqoDbav7VLLTsVx5dTVPPq"); + ecdsa_get_address(pub_key, 0x1234, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "ZLH8q1UgMPg8o2s1MD55YVMpPV7vqms9kiV"); + ecdsa_get_address(pub_key, 0x123456, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "3ThqvsQVFnbiF66NwHtfe2j6AKn75DpLKpQSq"); + ecdsa_get_address(pub_key, 0x12345678, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "BrsGxAHga3VbopvSnb3gmLvMBhJNCGuDxBZL44"); + ecdsa_get_address(pub_key, 0xffffffff, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "3diW7paWGJyZRLGqMJZ55DMfPExob8QxQHkrfYT"); + + res = ecdsa_address_decode("1C7zdTfnkzmr13HfA2vNm5SJYRK6nEKyq8", 0, HASHER_SHA2, decode); ck_assert_int_eq(res, 1); ck_assert_mem_eq(decode, fromhex("0079fbfc3f34e7745860d76137da68f362380c606c"), 21); - res = ecdsa_address_decode("8SCrMR2yYF7ciqoDbav7VLLTsVx5dTVPPq", 0x12, decode); + res = ecdsa_address_decode("8SCrMR2yYF7ciqoDbav7VLLTsVx5dTVPPq", 0x12, HASHER_SHA2, decode); ck_assert_int_eq(res, 1); ck_assert_mem_eq(decode, fromhex("1279fbfc3f34e7745860d76137da68f362380c606c"), 21); - res = ecdsa_address_decode("ZLH8q1UgMPg8o2s1MD55YVMpPV7vqms9kiV", 0x1234, decode); + res = ecdsa_address_decode("ZLH8q1UgMPg8o2s1MD55YVMpPV7vqms9kiV", 0x1234, HASHER_SHA2, decode); ck_assert_int_eq(res, 1); ck_assert_mem_eq(decode, fromhex("123479fbfc3f34e7745860d76137da68f362380c606c"), 21); - res = ecdsa_address_decode("3ThqvsQVFnbiF66NwHtfe2j6AKn75DpLKpQSq", 0x123456, decode); + res = ecdsa_address_decode("3ThqvsQVFnbiF66NwHtfe2j6AKn75DpLKpQSq", 0x123456, HASHER_SHA2, decode); ck_assert_int_eq(res, 1); ck_assert_mem_eq(decode, fromhex("12345679fbfc3f34e7745860d76137da68f362380c606c"), 21); - res = ecdsa_address_decode("BrsGxAHga3VbopvSnb3gmLvMBhJNCGuDxBZL44", 0x12345678, decode); + res = ecdsa_address_decode("BrsGxAHga3VbopvSnb3gmLvMBhJNCGuDxBZL44", 0x12345678, HASHER_SHA2, decode); ck_assert_int_eq(res, 1); ck_assert_mem_eq(decode, fromhex("1234567879fbfc3f34e7745860d76137da68f362380c606c"), 21); - res = ecdsa_address_decode("3diW7paWGJyZRLGqMJZ55DMfPExob8QxQHkrfYT", 0xffffffff, decode); + res = ecdsa_address_decode("3diW7paWGJyZRLGqMJZ55DMfPExob8QxQHkrfYT", 0xffffffff, HASHER_SHA2, decode); ck_assert_int_eq(res, 1); ck_assert_mem_eq(decode, fromhex("ffffffff79fbfc3f34e7745860d76137da68f362380c606c"), 21); // wrong length - res = ecdsa_address_decode("BrsGxAHga3VbopvSnb3gmLvMBhJNCGuDxBZL44", 0x123456, decode); + res = ecdsa_address_decode("BrsGxAHga3VbopvSnb3gmLvMBhJNCGuDxBZL44", 0x123456, HASHER_SHA2, decode); ck_assert_int_eq(res, 0); // wrong address prefix - res = ecdsa_address_decode("BrsGxAHga3VbopvSnb3gmLvMBhJNCGuDxBZL44", 0x22345678, decode); + res = ecdsa_address_decode("BrsGxAHga3VbopvSnb3gmLvMBhJNCGuDxBZL44", 0x22345678, HASHER_SHA2, decode); ck_assert_int_eq(res, 0); // wrong checksum - res = ecdsa_address_decode("BrsGxAHga3VbopvSnb3gmLvMBhJNCGuDxBZL45", 0x12345678, decode); + res = ecdsa_address_decode("BrsGxAHga3VbopvSnb3gmLvMBhJNCGuDxBZL45", 0x12345678, HASHER_SHA2, decode); ck_assert_int_eq(res, 0); } END_TEST diff --git a/tools/bip39bruteforce.c b/tools/bip39bruteforce.c index 7bb2a33f3..10fd69da7 100644 --- a/tools/bip39bruteforce.c +++ b/tools/bip39bruteforce.c @@ -44,7 +44,7 @@ int main(int argc, char **argv) fprintf(stderr, "\"%s\" is not a valid mnemonic\n", mnemonic); return 2; } - if (!ecdsa_address_decode(address, 0, addr)) { + if (!ecdsa_address_decode(address, 0, HASHER_SHA2, addr)) { fprintf(stderr, "\"%s\" is not a valid address\n", address); return 3; } @@ -70,7 +70,7 @@ int main(int argc, char **argv) hdnode_private_ckd(&node, 0); hdnode_private_ckd(&node, 0); hdnode_fill_public_key(&node); - ecdsa_get_pubkeyhash(node.public_key, pubkeyhash); + ecdsa_get_pubkeyhash(node.public_key, HASHER_SHA2, pubkeyhash); if (memcmp(addr + 1, pubkeyhash, 20) == 0) { found = 1; break; diff --git a/tools/xpubaddrgen.c b/tools/xpubaddrgen.c index b1bc5a5e4..59e0f7283 100644 --- a/tools/xpubaddrgen.c +++ b/tools/xpubaddrgen.c @@ -21,7 +21,7 @@ void process_job(uint32_t jobid, const char *xpub, uint32_t change, uint32_t fro for (i = from; i < to; i++) { memcpy(&child, &node, sizeof(HDNode)); hdnode_public_ckd(&child, i); - ecdsa_get_address(child.public_key, 0, address, sizeof(address)); + ecdsa_get_address(child.public_key, 0, HASHER_SHA2, address, sizeof(address)); printf("%d %d %s\n", jobid, i, address); } } From 7cdbec2d116087763cddec74c402c8e95b4301d0 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sat, 9 Dec 2017 22:51:16 +0000 Subject: [PATCH 506/627] blake256: Initial commit --- CMakeLists.txt | 1 + Makefile | 1 + blake256.c | 374 +++++++++++++++++++++++++++++++++++++++++++++++++ blake256.h | 76 ++++++++++ test_check.c | 42 ++++++ 5 files changed, 494 insertions(+) create mode 100644 blake256.c create mode 100644 blake256.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 987a6f6c9..81e51f906 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,6 +12,7 @@ set(SOURCES ed25519-donna/curve25519-donna-32bit.c ed25519-donna/curve25519-donna-helpers.c ed25519-donna/modm-donna-32bit.c ed25519-donna/ed25519-donna-basepoint-table.c ed25519-donna/ed25519-donna-32bit-tables.c ed25519-donna/ed25519-donna-impl-base.c ed25519-donna/ed25519.c ed25519-donna/curve25519-donna-scalarmult-base.c ed25519-donna/ed25519-sha3.c ed25519-donna/ed25519-keccak.c + blake256.c blake2b.c blake2s.c chacha20poly1305/chacha20poly1305.c chacha20poly1305/chacha_merged.c chacha20poly1305/poly1305-donna.c chacha20poly1305/rfc7539.c rc4.c diff --git a/Makefile b/Makefile index 4d5e9faa4..ae23e4456 100644 --- a/Makefile +++ b/Makefile @@ -47,6 +47,7 @@ SRCS += aes/aescrypt.c aes/aeskey.c aes/aestab.c aes/aes_modes.c SRCS += ed25519-donna/curve25519-donna-32bit.c ed25519-donna/curve25519-donna-helpers.c ed25519-donna/modm-donna-32bit.c SRCS += ed25519-donna/ed25519-donna-basepoint-table.c ed25519-donna/ed25519-donna-32bit-tables.c ed25519-donna/ed25519-donna-impl-base.c SRCS += ed25519-donna/ed25519.c ed25519-donna/curve25519-donna-scalarmult-base.c ed25519-donna/ed25519-sha3.c ed25519-donna/ed25519-keccak.c +SRCS += blake256.c SRCS += blake2b.c blake2s.c SRCS += chacha20poly1305/chacha20poly1305.c chacha20poly1305/chacha_merged.c chacha20poly1305/poly1305-donna.c chacha20poly1305/rfc7539.c SRCS += rc4.c diff --git a/blake256.c b/blake256.c new file mode 100644 index 000000000..66f34268f --- /dev/null +++ b/blake256.c @@ -0,0 +1,374 @@ +// Copyright (c) 2014-2017, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +/* + * The blake256_* and blake224_* functions are largely copied from + * blake256_light.c and blake224_light.c from the BLAKE website: + * + * http://131002.net/blake/ + * + * The hmac_* functions implement HMAC-BLAKE-256 and HMAC-BLAKE-224. + * HMAC is specified by RFC 2104. + */ + +#include +#include +#include "blake256.h" + +#define U8TO32(p) \ + (((uint32_t)((p)[0]) << 24) | ((uint32_t)((p)[1]) << 16) | \ + ((uint32_t)((p)[2]) << 8) | ((uint32_t)((p)[3]) )) +#define U32TO8(p, v) \ + (p)[0] = (uint8_t)((v) >> 24); (p)[1] = (uint8_t)((v) >> 16); \ + (p)[2] = (uint8_t)((v) >> 8); (p)[3] = (uint8_t)((v) ); + +static const uint8_t sigma[][16] = { + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15}, + {14,10, 4, 8, 9,15,13, 6, 1,12, 0, 2,11, 7, 5, 3}, + {11, 8,12, 0, 5, 2,15,13,10,14, 3, 6, 7, 1, 9, 4}, + { 7, 9, 3, 1,13,12,11,14, 2, 6, 5,10, 4, 0,15, 8}, + { 9, 0, 5, 7, 2, 4,10,15,14, 1,11,12, 6, 8, 3,13}, + { 2,12, 6,10, 0,11, 8, 3, 4,13, 7, 5,15,14, 1, 9}, + {12, 5, 1,15,14,13, 4,10, 0, 7, 6, 3, 9, 2, 8,11}, + {13,11, 7,14,12, 1, 3, 9, 5, 0,15, 4, 8, 6, 2,10}, + { 6,15,14, 9,11, 3, 0, 8,12, 2,13, 7, 1, 4,10, 5}, + {10, 2, 8, 4, 7, 6, 1, 5,15,11, 9,14, 3,12,13, 0}, + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15}, + {14,10, 4, 8, 9,15,13, 6, 1,12, 0, 2,11, 7, 5, 3}, + {11, 8,12, 0, 5, 2,15,13,10,14, 3, 6, 7, 1, 9, 4}, + { 7, 9, 3, 1,13,12,11,14, 2, 6, 5,10, 4, 0,15, 8} +}; + +static const uint32_t cst[16] = { + 0x243F6A88, 0x85A308D3, 0x13198A2E, 0x03707344, + 0xA4093822, 0x299F31D0, 0x082EFA98, 0xEC4E6C89, + 0x452821E6, 0x38D01377, 0xBE5466CF, 0x34E90C6C, + 0xC0AC29B7, 0xC97C50DD, 0x3F84D5B5, 0xB5470917 +}; + +static const uint8_t padding[] = { + 0x80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +}; + + +static void blake256_compress(BLAKE256_CTX *S, const uint8_t *block) { + uint32_t v[16], m[16], i; + +#define ROT(x,n) (((x)<<(32-n))|((x)>>(n))) +#define G(a,b,c,d,e) \ + v[a] += (m[sigma[i][e]] ^ cst[sigma[i][e+1]]) + v[b]; \ + v[d] = ROT(v[d] ^ v[a],16); \ + v[c] += v[d]; \ + v[b] = ROT(v[b] ^ v[c],12); \ + v[a] += (m[sigma[i][e+1]] ^ cst[sigma[i][e]])+v[b]; \ + v[d] = ROT(v[d] ^ v[a], 8); \ + v[c] += v[d]; \ + v[b] = ROT(v[b] ^ v[c], 7); + + for (i = 0; i < 16; ++i) m[i] = U8TO32(block + i * 4); + for (i = 0; i < 8; ++i) v[i] = S->h[i]; + v[ 8] = S->s[0] ^ 0x243F6A88; + v[ 9] = S->s[1] ^ 0x85A308D3; + v[10] = S->s[2] ^ 0x13198A2E; + v[11] = S->s[3] ^ 0x03707344; + v[12] = 0xA4093822; + v[13] = 0x299F31D0; + v[14] = 0x082EFA98; + v[15] = 0xEC4E6C89; + + if (S->nullt == 0) { + v[12] ^= S->t[0]; + v[13] ^= S->t[0]; + v[14] ^= S->t[1]; + v[15] ^= S->t[1]; + } + + for (i = 0; i < 14; ++i) { + G(0, 4, 8, 12, 0); + G(1, 5, 9, 13, 2); + G(2, 6, 10, 14, 4); + G(3, 7, 11, 15, 6); + G(3, 4, 9, 14, 14); + G(2, 7, 8, 13, 12); + G(0, 5, 10, 15, 8); + G(1, 6, 11, 12, 10); + } + + for (i = 0; i < 16; ++i) S->h[i % 8] ^= v[i]; + for (i = 0; i < 8; ++i) S->h[i] ^= S->s[i % 4]; +} + +void blake256_Init(BLAKE256_CTX *S) { + S->h[0] = 0x6A09E667; + S->h[1] = 0xBB67AE85; + S->h[2] = 0x3C6EF372; + S->h[3] = 0xA54FF53A; + S->h[4] = 0x510E527F; + S->h[5] = 0x9B05688C; + S->h[6] = 0x1F83D9AB; + S->h[7] = 0x5BE0CD19; + S->t[0] = S->t[1] = S->buflen = S->nullt = 0; + S->s[0] = S->s[1] = S->s[2] = S->s[3] = 0; +} + +void blake224_Init(BLAKE256_CTX *S) { + S->h[0] = 0xC1059ED8; + S->h[1] = 0x367CD507; + S->h[2] = 0x3070DD17; + S->h[3] = 0xF70E5939; + S->h[4] = 0xFFC00B31; + S->h[5] = 0x68581511; + S->h[6] = 0x64F98FA7; + S->h[7] = 0xBEFA4FA4; + S->t[0] = S->t[1] = S->buflen = S->nullt = 0; + S->s[0] = S->s[1] = S->s[2] = S->s[3] = 0; +} + +// datalen = number of bits +static void blake256_update(BLAKE256_CTX *S, const uint8_t *data, size_t datalen) { + int left = S->buflen >> 3; + int fill = 64 - left; + + if (left && (((datalen >> 3) & 0x3F) >= (unsigned) fill)) { + memcpy((void *) (S->buf + left), (void *) data, fill); + S->t[0] += 512; + if (S->t[0] == 0) S->t[1]++; + blake256_compress(S, S->buf); + data += fill; + datalen -= (fill << 3); + left = 0; + } + + while (datalen >= 512) { + S->t[0] += 512; + if (S->t[0] == 0) S->t[1]++; + blake256_compress(S, data); + data += 64; + datalen -= 512; + } + + if (datalen > 0) { + memcpy((void *) (S->buf + left), (void *) data, datalen >> 3); + S->buflen = (left << 3) + datalen; + } else { + S->buflen = 0; + } +} + +// datalen = number of bytes +void blake256_Update(BLAKE256_CTX *S, const uint8_t *data, size_t datalen) { + blake256_update(S, data, datalen * 8); +} + +// datalen = number of bits +static void blake224_update(BLAKE256_CTX *S, const uint8_t *data, size_t datalen) { + blake256_update(S, data, datalen); +} + +// datalen = number of bytes +void blake224_Update(BLAKE256_CTX *S, const uint8_t *data, size_t datalen) { + blake224_update(S, data, datalen * 8); +} + +static void blake256_final_h(BLAKE256_CTX *S, uint8_t *digest, uint8_t pa, uint8_t pb) { + uint8_t msglen[8]; + uint32_t lo = S->t[0] + S->buflen, hi = S->t[1]; + if (lo < (unsigned) S->buflen) hi++; + U32TO8(msglen + 0, hi); + U32TO8(msglen + 4, lo); + + if (S->buflen == 440) { /* one padding byte */ + S->t[0] -= 8; + blake256_update(S, &pa, 8); + } else { + if (S->buflen < 440) { /* enough space to fill the block */ + if (S->buflen == 0) S->nullt = 1; + S->t[0] -= 440 - S->buflen; + blake256_update(S, padding, 440 - S->buflen); + } else { /* need 2 compressions */ + S->t[0] -= 512 - S->buflen; + blake256_update(S, padding, 512 - S->buflen); + S->t[0] -= 440; + blake256_update(S, padding + 1, 440); + S->nullt = 1; + } + blake256_update(S, &pb, 8); + S->t[0] -= 8; + } + S->t[0] -= 64; + blake256_update(S, msglen, 64); + + U32TO8(digest + 0, S->h[0]); + U32TO8(digest + 4, S->h[1]); + U32TO8(digest + 8, S->h[2]); + U32TO8(digest + 12, S->h[3]); + U32TO8(digest + 16, S->h[4]); + U32TO8(digest + 20, S->h[5]); + U32TO8(digest + 24, S->h[6]); + U32TO8(digest + 28, S->h[7]); +} + +void blake256_Final(BLAKE256_CTX *S, uint8_t *digest) { + blake256_final_h(S, digest, 0x81, 0x01); +} + +void blake224_Final(BLAKE256_CTX *S, uint8_t *digest) { + blake256_final_h(S, digest, 0x80, 0x00); +} + +// inlen = number of bytes +void blake256(const uint8_t *in, size_t inlen, uint8_t *out) { + BLAKE256_CTX S; + blake256_Init(&S); + blake256_Update(&S, in, inlen); + blake256_Final(&S, out); +} + +// inlen = number of bytes +void blake224(const uint8_t *in, size_t inlen, uint8_t *out) { + BLAKE256_CTX S; + blake224_Init(&S); + blake224_Update(&S, in, inlen); + blake224_Final(&S, out); +} + +// keylen = number of bytes +void hmac_blake256_Init(HMAC_BLAKE256_CTX *S, const uint8_t *_key, size_t keylen) { + const uint8_t *key = _key; + uint8_t keyhash[32]; + uint8_t pad[64]; + size_t i; + + if (keylen > 64) { + blake256(key, keylen, keyhash); + key = keyhash; + keylen = 32; + } + + blake256_Init(&S->inner); + memset(pad, 0x36, 64); + for (i = 0; i < keylen; ++i) { + pad[i] ^= key[i]; + } + blake256_update(&S->inner, pad, 512); + + blake256_Init(&S->outer); + memset(pad, 0x5c, 64); + for (i = 0; i < keylen; ++i) { + pad[i] ^= key[i]; + } + blake256_update(&S->outer, pad, 512); + + memset(keyhash, 0, 32); +} + +// keylen = number of bytes +void hmac_blake224_Init(HMAC_BLAKE256_CTX *S, const uint8_t *_key, size_t keylen) { + const uint8_t *key = _key; + uint8_t keyhash[32]; + uint8_t pad[64]; + size_t i; + + if (keylen > 64) { + blake256(key, keylen, keyhash); + key = keyhash; + keylen = 28; + } + + blake224_Init(&S->inner); + memset(pad, 0x36, 64); + for (i = 0; i < keylen; ++i) { + pad[i] ^= key[i]; + } + blake224_update(&S->inner, pad, 512); + + blake224_Init(&S->outer); + memset(pad, 0x5c, 64); + for (i = 0; i < keylen; ++i) { + pad[i] ^= key[i]; + } + blake224_update(&S->outer, pad, 512); + + memset(keyhash, 0, 32); +} + +// datalen = number of bits +static void hmac_blake256_update(HMAC_BLAKE256_CTX *S, const uint8_t *data, size_t datalen) { + // update the inner BLAKE256_CTX + blake256_update(&S->inner, data, datalen); +} + +// datalen = number of bytes +void hmac_blake256_Update(HMAC_BLAKE256_CTX *S, const uint8_t *data, size_t datalen) { + hmac_blake256_update(S, data, datalen * 8); +} + +// datalen = number of bits +static void hmac_blake224_update(HMAC_BLAKE256_CTX *S, const uint8_t *data, size_t datalen) { + // update the inner BLAKE256_CTX + blake224_update(&S->inner, data, datalen); +} + +// datalen = number of bytes +void hmac_blake224_Update(HMAC_BLAKE256_CTX *S, const uint8_t *data, size_t datalen) { + hmac_blake224_update(S, data, datalen * 8); +} + +void hmac_blake256_Final(HMAC_BLAKE256_CTX *S, uint8_t *digest) { + uint8_t ihash[32]; + blake256_Final(&S->inner, ihash); + blake256_update(&S->outer, ihash, 256); + blake256_Final(&S->outer, digest); + memset(ihash, 0, 32); +} + +void hmac_blake224_Final(HMAC_BLAKE256_CTX *S, uint8_t *digest) { + uint8_t ihash[32]; + blake224_Final(&S->inner, ihash); + blake224_update(&S->outer, ihash, 224); + blake224_Final(&S->outer, digest); + memset(ihash, 0, 32); +} + +// keylen = number of bytes; inlen = number of bytes +void hmac_blake256(const uint8_t *key, size_t keylen, const uint8_t *in, size_t inlen, uint8_t *out) { + HMAC_BLAKE256_CTX S; + hmac_blake256_Init(&S, key, keylen); + hmac_blake256_Update(&S, in, inlen); + hmac_blake256_Final(&S, out); +} + +// keylen = number of bytes; inlen = number of bytes +void hmac_blake224(const uint8_t *key, size_t keylen, const uint8_t *in, size_t inlen, uint8_t *out) { + HMAC_BLAKE256_CTX S; + hmac_blake224_Init(&S, key, keylen); + hmac_blake224_Update(&S, in, inlen); + hmac_blake224_Final(&S, out); +} diff --git a/blake256.h b/blake256.h new file mode 100644 index 000000000..0d2eb977c --- /dev/null +++ b/blake256.h @@ -0,0 +1,76 @@ +// Copyright (c) 2014-2017, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers + +#ifndef __BLAKE256_H__ +#define __BLAKE256_H__ + +#include + +#define BLAKE224_DIGEST_LENGTH 28 +#define BLAKE256_DIGEST_LENGTH 32 + +typedef struct { + uint32_t h[8], s[4], t[2]; + int buflen, nullt; + uint8_t buf[64]; +} BLAKE256_CTX; + +typedef struct { + BLAKE256_CTX inner; + BLAKE256_CTX outer; +} HMAC_BLAKE256_CTX; + +void blake256_Init(BLAKE256_CTX *); +void blake224_Init(BLAKE256_CTX *); + +void blake256_Update(BLAKE256_CTX *, const uint8_t *, size_t); +void blake224_Update(BLAKE256_CTX *, const uint8_t *, size_t); + +void blake256_Final(BLAKE256_CTX *, uint8_t *); +void blake224_Final(BLAKE256_CTX *, uint8_t *); + +void blake256(const uint8_t *, size_t, uint8_t *); +void blake224(const uint8_t *, size_t, uint8_t *); + +/* HMAC functions: */ + +void hmac_blake256_Init(HMAC_BLAKE256_CTX *, const uint8_t *, size_t); +void hmac_blake224_Init(HMAC_BLAKE256_CTX *, const uint8_t *, size_t); + +void hmac_blake256_Update(HMAC_BLAKE256_CTX *, const uint8_t *, size_t); +void hmac_blake224_Update(HMAC_BLAKE256_CTX *, const uint8_t *, size_t); + +void hmac_blake256_Final(HMAC_BLAKE256_CTX *, uint8_t *); +void hmac_blake224_Final(HMAC_BLAKE256_CTX *, uint8_t *); + +void hmac_blake256(const uint8_t *, size_t, const uint8_t *, size_t, uint8_t *); +void hmac_blake224(const uint8_t *, size_t, const uint8_t *, size_t, uint8_t *); + +#endif /* __BLAKE256_H__ */ diff --git a/test_check.c b/test_check.c index 900399737..906542a9f 100644 --- a/test_check.c +++ b/test_check.c @@ -47,6 +47,7 @@ #include "rand.h" #include "sha2.h" #include "sha3.h" +#include "blake256.h" #include "blake2b.h" #include "blake2s.h" #include "curves.h" @@ -2138,6 +2139,43 @@ START_TEST(test_keccak_256) } END_TEST +START_TEST(test_blake256) +{ + struct { + const char *hash; + const char *data; + } tests[] = { + { "716f6e863f744b9ac22c97ec7b76ea5f5908bc5b2f67c61510bfc4751384ea7a", "", }, + { "e104256a2bc501f459d03fac96b9014f593e22d30f4de525fa680c3aa189eb4f", "cc", }, + { "8f341148be7e354fdf38b693d8c6b4e0bd57301a734f6fd35cd85b8491c3ddcd", "41fb", }, + { "bc334d1069099f10c601883ac6f3e7e9787c6aa53171f76a21923cc5ad3ab937", "1f877c", }, + { "b672a16f53982bab1e77685b71c0a5f6703ffd46a1c834be69f614bd128d658e", "c1ecfdfc", }, + { "d9134b2899057a7d8d320cc99e3e116982bc99d3c69d260a7f1ed3da8be68d99", "21f134ac57", }, + { "637923bd29a35aa3ecbbd2a50549fc32c14cf0fdcaf41c3194dd7414fd224815", "c6f50bb74e29", }, + { "70c092fd5c8c21e9ef4bbc82a5c7819e262a530a748caf285ff0cba891954f1e", "119713cc83eeef", }, + { "fdf092993edbb7a0dc7ca67f04051bbd14481639da0808947aff8bfab5abed4b", "4a4f202484512526", }, + { "6f6fc234bf35beae1a366c44c520c59ad5aa70351b5f5085e21e1fe2bfcee709", "1f66ab4185ed9b6375", }, + { "4fdaf89e2a0e78c000061b59455e0ea93a4445b440e7562c8f0cfa165c93de2e", "eed7422227613b6f53c9", }, + { "d6b780eee9c811f664393dc2c58b5a68c92b3c9fe9ceb70371d33ece63b5787e", "eaeed5cdffd89dece455f1", }, + { "d0015071d3e7ed048c764850d76406eceae52b8e2e6e5a2c3aa92ae880485b34", "5be43c90f22902e4fe8ed2d3", }, + { "9b0207902f9932f7a85c24722e93e31f6ed2c75c406509aa0f2f6d1cab046ce4", "a746273228122f381c3b46e4f1", }, + { "258020d5b04a814f2b72c1c661e1f5a5c395d9799e5eee8b8519cf7300e90cb1", "3c5871cd619c69a63b540eb5a625", }, + { "4adae3b55baa907fefc253365fdd99d8398befd0551ed6bf9a2a2784d3c304d1", "fa22874bcc068879e8ef11a69f0722", }, + { "6dd10d772f8d5b4a96c3c5d30878cd9a1073fa835bfe6d2b924fa64a1fab1711", "52a608ab21ccdd8a4457a57ede782176", }, + { "0b8741ddf2259d3af2901eb1ae354f22836442c965556f5c1eb89501191cb46a", "82e192e4043ddcd12ecf52969d0f807eed", }, + { "f48a754ca8193a82643150ab94038b5dd170b4ebd1e0751b78cfb0a98fa5076a", "75683dcb556140c522543bb6e9098b21a21e", }, + { "5698409ab856b74d9fa5e9b259dfa46001f89041752da424e56e491577b88c86", "06e4efe45035e61faaf4287b4d8d1f12ca97e5", }, + }; + + uint8_t hash[BLAKE256_DIGEST_LENGTH]; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + blake256(fromhex(tests[i].data), i, hash); + ck_assert_mem_eq(hash, fromhex(tests[i].hash), BLAKE256_DIGEST_LENGTH); + } +} +END_TEST + // test vectors from https://raw.githubusercontent.com/BLAKE2/BLAKE2/master/testvectors/blake2b-kat.txt START_TEST(test_blake2b) { @@ -4174,6 +4212,10 @@ Suite *test_suite(void) tcase_add_test(tc, test_keccak_256); suite_add_tcase(s, tc); + tc = tcase_create("blake"); + tcase_add_test(tc, test_blake256); + suite_add_tcase(s, tc); + tc = tcase_create("blake2"); tcase_add_test(tc, test_blake2b); tcase_add_test(tc, test_blake2s); From 6b813bc473d6aed226e82c5ef14d4e6bd3428acb Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sun, 10 Dec 2017 11:10:59 +0000 Subject: [PATCH 507/627] hasher: Add HASHER_BLAKE --- hasher.c | 9 +++++++++ hasher.h | 3 +++ 2 files changed, 12 insertions(+) diff --git a/hasher.c b/hasher.c index aa73e45d2..edd1ac766 100644 --- a/hasher.c +++ b/hasher.c @@ -29,6 +29,9 @@ void hasher_Init(Hasher *hasher, HasherType type) { case HASHER_SHA2: sha256_Init(&hasher->ctx.sha2); break; + case HASHER_BLAKE: + blake256_Init(&hasher->ctx.blake); + break; } } @@ -41,6 +44,9 @@ void hasher_Update(Hasher *hasher, const uint8_t *data, size_t length) { case HASHER_SHA2: sha256_Update(&hasher->ctx.sha2, data, length); break; + case HASHER_BLAKE: + blake256_Update(&hasher->ctx.blake, data, length); + break; } } @@ -49,6 +55,9 @@ void hasher_Final(Hasher *hasher, uint8_t hash[HASHER_DIGEST_LENGTH]) { case HASHER_SHA2: sha256_Final(&hasher->ctx.sha2, hash); break; + case HASHER_BLAKE: + blake256_Final(&hasher->ctx.blake, hash); + break; } } diff --git a/hasher.h b/hasher.h index 5fa70b408..57b70b231 100644 --- a/hasher.h +++ b/hasher.h @@ -27,11 +27,13 @@ #include #include "sha2.h" +#include "blake256.h" #define HASHER_DIGEST_LENGTH 32 typedef enum { HASHER_SHA2, + HASHER_BLAKE, } HasherType; typedef struct { @@ -39,6 +41,7 @@ typedef struct { union { SHA256_CTX sha2; + BLAKE256_CTX blake; } ctx; } Hasher; From 173c62f0f3159046eb141ceb1504a77e82d1d0b2 Mon Sep 17 00:00:00 2001 From: Peter Banik Date: Sun, 10 Dec 2017 00:22:41 +0100 Subject: [PATCH 508/627] Fixed test suite to use generic hasher functions --- test_openssl.c | 7 ++++--- test_speed.c | 25 +++++++++++++------------ 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/test_openssl.c b/test_openssl.c index f1446ad3c..44a4fae39 100644 --- a/test_openssl.c +++ b/test_openssl.c @@ -29,6 +29,7 @@ #include "ecdsa.h" #include "rand.h" +#include "hasher.h" #include "nist256p1.h" #include "secp256k1.h" @@ -75,7 +76,7 @@ void openssl_check(unsigned int iterations, int nid, const ecdsa_curve *curve) } // use our ECDSA signer to sign the message with the key - if (ecdsa_sign(curve, priv_key, msg, msg_len, sig, NULL, NULL) != 0) { + if (ecdsa_sign(curve, HASHER_SHA2, priv_key, msg, msg_len, sig, NULL, NULL) != 0) { printf("trezor-crypto signing failed\n"); return; } @@ -85,11 +86,11 @@ void openssl_check(unsigned int iterations, int nid, const ecdsa_curve *curve) ecdsa_get_public_key65(curve, priv_key, pub_key65); // use our ECDSA verifier to verify the message signature - if (ecdsa_verify(curve, pub_key65, sig, msg, msg_len) != 0) { + if (ecdsa_verify(curve, HASHER_SHA2, pub_key65, sig, msg, msg_len) != 0) { printf("trezor-crypto verification failed (pub_key_len = 65)\n"); return; } - if (ecdsa_verify(curve, pub_key33, sig, msg, msg_len) != 0) { + if (ecdsa_verify(curve, HASHER_SHA2, pub_key33, sig, msg, msg_len) != 0) { printf("trezor-crypto verification failed (pub_key_len = 33)\n"); return; } diff --git a/test_speed.c b/test_speed.c index 24b97f2f5..1140b84c8 100644 --- a/test_speed.c +++ b/test_speed.c @@ -9,6 +9,7 @@ #include "secp256k1.h" #include "nist256p1.h" #include "ed25519.h" +#include "hasher.h" static uint8_t msg[256]; @@ -28,7 +29,7 @@ void bench_sign_secp256k1(int iterations) memcpy(priv, "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", 32); for (int i = 0 ; i < iterations; i++) { - ecdsa_sign(curve, priv, msg, sizeof(msg), sig, &pby, NULL); + ecdsa_sign(curve, HASHER_SHA2, priv, msg, sizeof(msg), sig, &pby, NULL); } } @@ -41,7 +42,7 @@ void bench_sign_nist256p1(int iterations) memcpy(priv, "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", 32); for (int i = 0 ; i < iterations; i++) { - ecdsa_sign(curve, priv, msg, sizeof(msg), sig, &pby, NULL); + ecdsa_sign(curve, HASHER_SHA2, priv, msg, sizeof(msg), sig, &pby, NULL); } } @@ -67,10 +68,10 @@ void bench_verify_secp256k1_33(int iterations) memcpy(priv, "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", 32); ecdsa_get_public_key33(curve, priv, pub); - ecdsa_sign(curve, priv, msg, sizeof(msg), sig, &pby, NULL); + ecdsa_sign(curve, HASHER_SHA2, priv, msg, sizeof(msg), sig, &pby, NULL); for (int i = 0 ; i < iterations; i++) { - ecdsa_verify(curve, pub, sig, msg, sizeof(msg)); + ecdsa_verify(curve, HASHER_SHA2, pub, sig, msg, sizeof(msg)); } } @@ -82,10 +83,10 @@ void bench_verify_secp256k1_65(int iterations) memcpy(priv, "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", 32); ecdsa_get_public_key65(curve, priv, pub); - ecdsa_sign(curve, priv, msg, sizeof(msg), sig, &pby, NULL); + ecdsa_sign(curve, HASHER_SHA2, priv, msg, sizeof(msg), sig, &pby, NULL); for (int i = 0 ; i < iterations; i++) { - ecdsa_verify(curve, pub, sig, msg, sizeof(msg)); + ecdsa_verify(curve, HASHER_SHA2, pub, sig, msg, sizeof(msg)); } } @@ -97,10 +98,10 @@ void bench_verify_nist256p1_33(int iterations) memcpy(priv, "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", 32); ecdsa_get_public_key33(curve, priv, pub); - ecdsa_sign(curve, priv, msg, sizeof(msg), sig, &pby, NULL); + ecdsa_sign(curve, HASHER_SHA2, priv, msg, sizeof(msg), sig, &pby, NULL); for (int i = 0 ; i < iterations; i++) { - ecdsa_verify(curve, pub, sig, msg, sizeof(msg)); + ecdsa_verify(curve, HASHER_SHA2, pub, sig, msg, sizeof(msg)); } } @@ -112,10 +113,10 @@ void bench_verify_nist256p1_65(int iterations) memcpy(priv, "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", 32); ecdsa_get_public_key65(curve, priv, pub); - ecdsa_sign(curve, priv, msg, sizeof(msg), sig, &pby, NULL); + ecdsa_sign(curve, HASHER_SHA2, priv, msg, sizeof(msg), sig, &pby, NULL); for (int i = 0 ; i < iterations; i++) { - ecdsa_verify(curve, pub, sig, msg, sizeof(msg)); + ecdsa_verify(curve, HASHER_SHA2, pub, sig, msg, sizeof(msg)); } } @@ -164,7 +165,7 @@ void bench_ckd_normal(int iterations) memcpy(&node, &root, sizeof(HDNode)); hdnode_public_ckd(&node, i); hdnode_fill_public_key(&node); - ecdsa_get_address(node.public_key, 0, addr, sizeof(addr)); + ecdsa_get_address(node.public_key, HASHER_SHA2, 0, addr, sizeof(addr)); } } @@ -174,7 +175,7 @@ void bench_ckd_optimized(int iterations) curve_point pub; ecdsa_read_pubkey(&secp256k1, root.public_key, &pub); for (int i = 0; i < iterations; i++) { - hdnode_public_ckd_address_optimized(&pub, root.chain_code, i, 0, addr, sizeof(addr), false); + hdnode_public_ckd_address_optimized(&pub, root.chain_code, i, 0, HASHER_SHA2, addr, sizeof(addr), false); } } From 8e725f4d3ed1889fd4196674bf6bfa4e74d13692 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sun, 10 Dec 2017 11:22:39 +0000 Subject: [PATCH 509/627] test_openssl: Fix SHA2 name conflict --- test_openssl.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/test_openssl.c b/test_openssl.c index 44a4fae39..dcec83c77 100644 --- a/test_openssl.c +++ b/test_openssl.c @@ -21,9 +21,15 @@ * OTHER DEALINGS IN THE SOFTWARE. */ +/* OpenSSL's SHA256_CTX/SHA512_CTX conflicts with our own */ +#define SHA256_CTX _openssl_SHA256_CTX +#define SHA512_CTX _openssl_SHA512_CTX #include #include #include +#undef SHA256_CTX +#undef SHA512_CTX + #include #include @@ -37,7 +43,7 @@ void openssl_check(unsigned int iterations, int nid, const ecdsa_curve *curve) { uint8_t sig[64], pub_key33[33], pub_key65[65], priv_key[32], msg[256], buffer[1000], hash[32], *p; - SHA256_CTX sha256; + struct SHA256state_st sha256; EC_GROUP *ecgroup; ecgroup = EC_GROUP_new_by_curve_name(nid); @@ -101,6 +107,7 @@ void openssl_check(unsigned int iterations, int nid, const ecdsa_curve *curve) BN_bin2bn(sig + 32, 32, signature->s); // compute the digest of the message + // note: these are OpenSSL functions, not our own SHA256_Init(&sha256); SHA256_Update(&sha256, msg, msg_len); SHA256_Final(hash, &sha256); From b41f5407cc7a37dfbaf7f69901371fcbf50994cc Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sun, 10 Dec 2017 11:29:43 +0000 Subject: [PATCH 510/627] test_check: Attribute test vectors to Monero --- test_check.c | 1 + 1 file changed, 1 insertion(+) diff --git a/test_check.c b/test_check.c index 906542a9f..713c9b4ea 100644 --- a/test_check.c +++ b/test_check.c @@ -2139,6 +2139,7 @@ START_TEST(test_keccak_256) } END_TEST +// test vectors from https://raw.githubusercontent.com/monero-project/monero/master/tests/hash/tests-extra-blake.txt START_TEST(test_blake256) { struct { From 136c62e9703cc5dfef88f3f67c3fc31cbb623299 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sun, 10 Dec 2017 12:35:02 +0000 Subject: [PATCH 511/627] bip32: Add curve to hdnode_deserialize --- bip32.c | 4 ++-- bip32.h | 2 +- test_check.c | 48 ++++++++++++++++++++++----------------------- tools/xpubaddrgen.c | 3 ++- 4 files changed, 29 insertions(+), 28 deletions(-) diff --git a/bip32.c b/bip32.c index f0d949038..eee5a9d22 100644 --- a/bip32.c +++ b/bip32.c @@ -625,11 +625,11 @@ int hdnode_serialize_private(const HDNode *node, uint32_t fingerprint, uint32_t } // check for validity of curve point in case of public data not performed -int hdnode_deserialize(const char *str, uint32_t version_public, uint32_t version_private, HDNode *node, uint32_t *fingerprint) +int hdnode_deserialize(const char *str, uint32_t version_public, uint32_t version_private, const char *curve, HDNode *node, uint32_t *fingerprint) { uint8_t node_data[78]; memset(node, 0, sizeof(HDNode)); - node->curve = get_curve_by_name(SECP256K1_NAME); + node->curve = get_curve_by_name(curve); if (base58_decode_check(str, node->curve->hasher_type, node_data, sizeof(node_data)) != sizeof(node_data)) { return -1; } diff --git a/bip32.h b/bip32.h index 14437c1ce..980f5c850 100644 --- a/bip32.h +++ b/bip32.h @@ -90,7 +90,7 @@ int hdnode_serialize_public(const HDNode *node, uint32_t fingerprint, uint32_t v int hdnode_serialize_private(const HDNode *node, uint32_t fingerprint, uint32_t version, char *str, int strsize); -int hdnode_deserialize(const char *str, uint32_t version_public, uint32_t version_private, HDNode *node, uint32_t *fingerprint); +int hdnode_deserialize(const char *str, uint32_t version_public, uint32_t version_private, const char *curve, HDNode *node, uint32_t *fingerprint); void hdnode_get_address_raw(HDNode *node, uint32_t version, uint8_t *addr_raw); void hdnode_get_address(HDNode *node, uint32_t version, char *addr, int addrsize); diff --git a/test_check.c b/test_check.c index 713c9b4ea..3cff9e3ea 100644 --- a/test_check.c +++ b/test_check.c @@ -832,12 +832,12 @@ START_TEST(test_bip32_vector_1) ck_assert_mem_eq(node.public_key, fromhex("0339a36013301597daef41fbe593a02cc513d0b55527ec2df1050e2e8ff49c85c2"), 33); hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, sizeof(str)); ck_assert_str_eq(str, "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi"); - r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, &node2, NULL); ck_assert_int_eq(r, 0); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); ck_assert_int_eq(r, 0); hdnode_fill_public_key(&node2); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); ck_assert_str_eq(str, "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8"); - r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, &node2, NULL); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); memset(&node3.private_key, 0, 32); ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); @@ -852,12 +852,12 @@ START_TEST(test_bip32_vector_1) ck_assert_mem_eq(node.public_key, fromhex("035a784662a4a20a65bf6aab9ae98a6c068a81c52e4b032c0fb5400c706cfccc56"), 33); hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, sizeof(str)); ck_assert_str_eq(str, "xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7"); - r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, &node2, NULL); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); hdnode_fill_public_key(&node2); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); ck_assert_str_eq(str, "xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw"); - r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, &node2, NULL); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); memset(&node3.private_key, 0, 32); ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); @@ -872,12 +872,12 @@ START_TEST(test_bip32_vector_1) ck_assert_mem_eq(node.public_key, fromhex("03501e454bf00751f24b1b489aa925215d66af2234e3891c3b21a52bedb3cd711c"), 33); hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, sizeof(str)); ck_assert_str_eq(str, "xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs"); - r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, &node2, NULL); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); hdnode_fill_public_key(&node2); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); ck_assert_str_eq(str, "xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFHKkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ"); - r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, &node2, NULL); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); memset(&node3.private_key, 0, 32); ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); @@ -892,12 +892,12 @@ START_TEST(test_bip32_vector_1) ck_assert_mem_eq(node.public_key, fromhex("0357bfe1e341d01c69fe5654309956cbea516822fba8a601743a012a7896ee8dc2"), 33); hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, sizeof(str)); ck_assert_str_eq(str, "xprv9z4pot5VBttmtdRTWfWQmoH1taj2axGVzFqSb8C9xaxKymcFzXBDptWmT7FwuEzG3ryjH4ktypQSAewRiNMjANTtpgP4mLTj34bhnZX7UiM"); - r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, &node2, NULL); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); hdnode_fill_public_key(&node2); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); ck_assert_str_eq(str, "xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5"); - r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, &node2, NULL); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); memset(&node3.private_key, 0, 32); ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); @@ -912,12 +912,12 @@ START_TEST(test_bip32_vector_1) ck_assert_mem_eq(node.public_key, fromhex("02e8445082a72f29b75ca48748a914df60622a609cacfce8ed0e35804560741d29"), 33); hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, sizeof(str)); ck_assert_str_eq(str, "xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334"); - r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, &node2, NULL); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); hdnode_fill_public_key(&node2); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); ck_assert_str_eq(str, "xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV"); - r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, &node2, NULL); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); memset(&node3.private_key, 0, 32); ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); @@ -932,12 +932,12 @@ START_TEST(test_bip32_vector_1) ck_assert_mem_eq(node.public_key, fromhex("022a471424da5e657499d1ff51cb43c47481a03b1e77f951fe64cec9f5a48f7011"), 33); hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, sizeof(str)); ck_assert_str_eq(str, "xprvA41z7zogVVwxVSgdKUHDy1SKmdb533PjDz7J6N6mV6uS3ze1ai8FHa8kmHScGpWmj4WggLyQjgPie1rFSruoUihUZREPSL39UNdE3BBDu76"); - r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, &node2, NULL); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); hdnode_fill_public_key(&node2); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); ck_assert_str_eq(str, "xpub6H1LXWLaKsWFhvm6RVpEL9P4KfRZSW7abD2ttkWP3SSQvnyA8FSVqNTEcYFgJS2UaFcxupHiYkro49S8yGasTvXEYBVPamhGW6cFJodrTHy"); - r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, &node2, NULL); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); memset(&node3.private_key, 0, 32); ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); @@ -964,12 +964,12 @@ START_TEST(test_bip32_vector_2) ck_assert_mem_eq(node.public_key, fromhex("03cbcaa9c98c877a26977d00825c956a238e8dddfbd322cce4f74b0b5bd6ace4a7"), 33); hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, sizeof(str)); ck_assert_str_eq(str, "xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U"); - r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, &node2, NULL); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); hdnode_fill_public_key(&node2); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); ck_assert_str_eq(str, "xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB"); - r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, &node2, NULL); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); memset(&node3.private_key, 0, 32); ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); @@ -985,12 +985,12 @@ START_TEST(test_bip32_vector_2) ck_assert_mem_eq(node.public_key, fromhex("02fc9e5af0ac8d9b3cecfe2a888e2117ba3d089d8585886c9c826b6b22a98d12ea"), 33); hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, sizeof(str)); ck_assert_str_eq(str, "xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt"); - r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, &node2, NULL); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); hdnode_fill_public_key(&node2); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); ck_assert_str_eq(str, "xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH"); - r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, &node2, NULL); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); memset(&node3.private_key, 0, 32); ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); @@ -1006,12 +1006,12 @@ START_TEST(test_bip32_vector_2) ck_assert_mem_eq(node.public_key, fromhex("03c01e7425647bdefa82b12d9bad5e3e6865bee0502694b94ca58b666abc0a5c3b"), 33); hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, sizeof(str)); ck_assert_str_eq(str, "xprv9wSp6B7kry3Vj9m1zSnLvN3xH8RdsPP1Mh7fAaR7aRLcQMKTR2vidYEeEg2mUCTAwCd6vnxVrcjfy2kRgVsFawNzmjuHc2YmYRmagcEPdU9"); - r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, &node2, NULL); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); hdnode_fill_public_key(&node2); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); ck_assert_str_eq(str, "xpub6ASAVgeehLbnwdqV6UKMHVzgqAG8Gr6riv3Fxxpj8ksbH9ebxaEyBLZ85ySDhKiLDBrQSARLq1uNRts8RuJiHjaDMBU4Zn9h8LZNnBC5y4a"); - r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, &node2, NULL); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); memset(&node3.private_key, 0, 32); ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); @@ -1027,12 +1027,12 @@ START_TEST(test_bip32_vector_2) ck_assert_mem_eq(node.public_key, fromhex("03a7d1d856deb74c508e05031f9895dab54626251b3806e16b4bd12e781a7df5b9"), 33); hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, sizeof(str)); ck_assert_str_eq(str, "xprv9zFnWC6h2cLgpmSA46vutJzBcfJ8yaJGg8cX1e5StJh45BBciYTRXSd25UEPVuesF9yog62tGAQtHjXajPPdbRCHuWS6T8XA2ECKADdw4Ef"); - r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, &node2, NULL); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); hdnode_fill_public_key(&node2); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); ck_assert_str_eq(str, "xpub6DF8uhdarytz3FWdA8TvFSvvAh8dP3283MY7p2V4SeE2wyWmG5mg5EwVvmdMVCQcoNJxGoWaU9DCWh89LojfZ537wTfunKau47EL2dhHKon"); - r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, &node2, NULL); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); memset(&node3.private_key, 0, 32); ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); @@ -1048,12 +1048,12 @@ START_TEST(test_bip32_vector_2) ck_assert_mem_eq(node.public_key, fromhex("02d2b36900396c9282fa14628566582f206a5dd0bcc8d5e892611806cafb0301f0"), 33); hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, sizeof(str)); ck_assert_str_eq(str, "xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc"); - r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, &node2, NULL); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); hdnode_fill_public_key(&node2); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); ck_assert_str_eq(str, "xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL"); - r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, &node2, NULL); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); memset(&node3.private_key, 0, 32); ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); @@ -1069,12 +1069,12 @@ START_TEST(test_bip32_vector_2) ck_assert_mem_eq(node.public_key, fromhex("024d902e1a2fc7a8755ab5b694c575fce742c48d9ff192e63df5193e4c7afe1f9c"), 33); hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, sizeof(str)); ck_assert_str_eq(str, "xprvA2nrNbFZABcdryreWet9Ea4LvTJcGsqrMzxHx98MMrotbir7yrKCEXw7nadnHM8Dq38EGfSh6dqA9QWTyefMLEcBYJUuekgW4BYPJcr9E7j"); - r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, &node2, NULL); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); hdnode_fill_public_key(&node2); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); ck_assert_str_eq(str, "xpub6FnCn6nSzZAw5Tw7cgR9bi15UV96gLZhjDstkXXxvCLsUXBGXPdSnLFbdpq8p9HmGsApME5hQTZ3emM2rnY5agb9rXpVGyy3bdW6EEgAtqt"); - r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, &node2, NULL); ck_assert_int_eq(r, 0); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); memset(&node3.private_key, 0, 32); ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); diff --git a/tools/xpubaddrgen.c b/tools/xpubaddrgen.c index 59e0f7283..361686e6d 100644 --- a/tools/xpubaddrgen.c +++ b/tools/xpubaddrgen.c @@ -3,6 +3,7 @@ #include #include #include "bip32.h" +#include "curves.h" #include "ecdsa.h" #define VERSION_PUBLIC 0x0488b21e @@ -11,7 +12,7 @@ void process_job(uint32_t jobid, const char *xpub, uint32_t change, uint32_t from, uint32_t to) { HDNode node, child; - if (change > 1 || to <= from || hdnode_deserialize(xpub, VERSION_PUBLIC, VERSION_PRIVATE, &node, NULL) != 0) { + if (change > 1 || to <= from || hdnode_deserialize(xpub, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node, NULL) != 0) { printf("%d error\n", jobid); return; } From 764cc4c6e8ef32e7e1a77f0496ae090f11a36def Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sun, 10 Dec 2017 12:50:22 +0000 Subject: [PATCH 512/627] bip32: Add secp256k1-decred --- bip32.c | 3 + curves.c | 1 + curves.h | 1 + secp256k1.c | 6 ++ secp256k1.h | 1 + test_check.c | 299 +++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 311 insertions(+) diff --git a/bip32.c b/bip32.c index eee5a9d22..97588bdda 100644 --- a/bip32.c +++ b/bip32.c @@ -662,6 +662,9 @@ const curve_info *get_curve_by_name(const char *curve_name) { if (strcmp(curve_name, SECP256K1_NAME) == 0) { return &secp256k1_info; } + if (strcmp(curve_name, SECP256K1_DECRED_NAME) == 0) { + return &secp256k1_decred_info; + } if (strcmp(curve_name, NIST256P1_NAME) == 0) { return &nist256p1_info; } diff --git a/curves.c b/curves.c index 42863cdb0..f81ea28ad 100644 --- a/curves.c +++ b/curves.c @@ -23,6 +23,7 @@ #include "curves.h" const char SECP256K1_NAME[] = "secp256k1"; +const char SECP256K1_DECRED_NAME[] = "secp256k1-decred"; const char NIST256P1_NAME[] = "nist256p1"; const char ED25519_NAME[] = "ed25519"; const char ED25519_SHA3_NAME[] = "ed25519-sha3"; diff --git a/curves.h b/curves.h index cd95e0848..9257dcc10 100644 --- a/curves.h +++ b/curves.h @@ -26,6 +26,7 @@ #include "options.h" extern const char SECP256K1_NAME[]; +extern const char SECP256K1_DECRED_NAME[]; extern const char NIST256P1_NAME[]; extern const char ED25519_NAME[]; extern const char ED25519_SHA3_NAME[]; diff --git a/secp256k1.c b/secp256k1.c index c607aa472..155d2c17d 100644 --- a/secp256k1.c +++ b/secp256k1.c @@ -60,3 +60,9 @@ const curve_info secp256k1_info = { .params = &secp256k1, .hasher_type = HASHER_SHA2, }; + +const curve_info secp256k1_decred_info = { + .bip32_name = "Decred seed", + .params = &secp256k1, + .hasher_type = HASHER_BLAKE, +}; diff --git a/secp256k1.h b/secp256k1.h index fe82f35e2..803cde263 100644 --- a/secp256k1.h +++ b/secp256k1.h @@ -31,5 +31,6 @@ extern const ecdsa_curve secp256k1; extern const curve_info secp256k1_info; +extern const curve_info secp256k1_decred_info; #endif diff --git a/test_check.c b/test_check.c index 3cff9e3ea..64813e70b 100644 --- a/test_check.c +++ b/test_check.c @@ -76,6 +76,9 @@ #define VERSION_PUBLIC 0x0488b21e #define VERSION_PRIVATE 0x0488ade4 +#define DECRED_VERSION_PUBLIC 0x02fda926 +#define DECRED_VERSION_PRIVATE 0x02fda4e8 + const uint8_t *fromhex(const char *str) { static uint8_t buf[FROMHEX_MAXLEN]; @@ -1566,6 +1569,297 @@ START_TEST(test_bip32_ed25519_vector_2) } END_TEST +// test vector 1 from https://github.com/decred/dcrd/blob/master/hdkeychain/extendedkey_test.go +START_TEST(test_bip32_decred_vector_1) +{ + HDNode node, node2, node3; + uint32_t fingerprint; + char str[112]; + int r; + + // init m + hdnode_from_seed(fromhex("000102030405060708090a0b0c0d0e0f"), 16, SECP256K1_NAME, &node); + + // secp256k1_decred_info.bip32_name != "Bitcoin seed" so we cannot use it in hdnode_from_seed + node.curve = &secp256k1_decred_info; + + // [Chain m] + fingerprint = 0; + ck_assert_int_eq(fingerprint, 0x00000000); + ck_assert_mem_eq(node.chain_code, fromhex("873dff81c02f525623fd1fe5167eac3a55a049de3d314bb42ee227ffed37d508"), 32); + ck_assert_mem_eq(node.private_key, fromhex("e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35"), 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq(node.public_key, fromhex("0339a36013301597daef41fbe593a02cc513d0b55527ec2df1050e2e8ff49c85c2"), 33); + hdnode_serialize_private(&node, fingerprint, DECRED_VERSION_PRIVATE, str, sizeof(str)); + ck_assert_str_eq(str, "dprv3hCznBesA6jBtmoyVFPfyMSZ1qYZ3WdjdebquvkEfmRfxC9VFEFi2YDaJqHnx7uGe75eGSa3Mn3oHK11hBW7KZUrPxwbCPBmuCi1nwm182s"); + r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, sizeof(str)); + ck_assert_str_eq(str, "dpubZ9169KDAEUnyoBhjjmT2VaEodr6pUTDoqCEAeqgbfr2JfkB88BbK77jbTYbcYXb2FVz7DKBdW4P618yd51MwF8DjKVopSbS7Lkgi6bowX5w"); + r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memset(&node3.private_key, 0, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); + + // [Chain m/0'] + fingerprint = hdnode_fingerprint(&node); + hdnode_private_ckd_prime(&node, 0); + ck_assert_int_eq(fingerprint, 0xbc495588); + ck_assert_mem_eq(node.chain_code, fromhex("47fdacbd0f1097043b78c63c20c34ef4ed9a111d980047ad16282c7ae6236141"), 32); + ck_assert_mem_eq(node.private_key, fromhex("edb2e14f9ee77d26dd93b4ecede8d16ed408ce149b6cd80b0715a2d911a0afea"), 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq(node.public_key, fromhex("035a784662a4a20a65bf6aab9ae98a6c068a81c52e4b032c0fb5400c706cfccc56"), 33); + hdnode_serialize_private(&node, fingerprint, DECRED_VERSION_PRIVATE, str, sizeof(str)); + ck_assert_str_eq(str, "dprv3kUQDBztdyjKuwnaL3hfKYpT7W6X2huYH5d61YSWFBebSYwEBHAXJkCpQ7rvMAxPzKqxVCGLvBqWvGxXjAyMJsV1XwKkfnQCM9KctC8k8bk"); + r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, sizeof(str)); + ck_assert_str_eq(str, "dpubZCGVaKZBiMo7pMgLaZm1qmchjWenTeVcUdFQkTNsFGFEA6xs4EW8PKiqYqP7HBAitt9Hw16VQkQ1tjsZQSHNWFc6bEK6bLqrbco24FzBTY4"); + r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memset(&node3.private_key, 0, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); + + // [Chain m/0'/1] + fingerprint = hdnode_fingerprint(&node); + hdnode_private_ckd(&node, 1); + ck_assert_int_eq(fingerprint, 0xc67bc2ef); + ck_assert_mem_eq(node.chain_code, fromhex("2a7857631386ba23dacac34180dd1983734e444fdbf774041578e9b6adb37c19"), 32); + ck_assert_mem_eq(node.private_key, fromhex("3c6cb8d0f6a264c91ea8b5030fadaa8e538b020f0a387421a12de9319dc93368"), 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq(node.public_key, fromhex("03501e454bf00751f24b1b489aa925215d66af2234e3891c3b21a52bedb3cd711c"), 33); + hdnode_serialize_private(&node, fingerprint, DECRED_VERSION_PRIVATE, str, sizeof(str)); + ck_assert_str_eq(str, "dprv3nRtCZ5VAoHW4RUwQgRafSNRPUDFrmsgyY71A5eoZceVfuyL9SbZe2rcbwDW2UwpkEniE4urffgbypegscNchPajWzy9QS4cRxF8QYXsZtq"); + r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, sizeof(str)); + ck_assert_str_eq(str, "dpubZEDyZgdnFBMHxqNhfCUwBfAg1UmXHiTmB5jKtzbAZhF8PTzy2PwAicNdkg1CmW6TARxQeUbgC7nAQenJts4YoG3KMiqcjsjgeMvwLc43w6C"); + r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memset(&node3.private_key, 0, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); + + // [Chain m/0'/1/2'] + fingerprint = hdnode_fingerprint(&node); + hdnode_private_ckd_prime(&node, 2); + ck_assert_int_eq(fingerprint, 0xe7072187); + ck_assert_mem_eq(node.chain_code, fromhex("04466b9cc8e161e966409ca52986c584f07e9dc81f735db683c3ff6ec7b1503f"), 32); + ck_assert_mem_eq(node.private_key, fromhex("cbce0d719ecf7431d88e6a89fa1483e02e35092af60c042b1df2ff59fa424dca"), 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq(node.public_key, fromhex("0357bfe1e341d01c69fe5654309956cbea516822fba8a601743a012a7896ee8dc2"), 33); + hdnode_serialize_private(&node, fingerprint, DECRED_VERSION_PRIVATE, str, sizeof(str)); + ck_assert_str_eq(str, "dprv3pYtkZK168vgrU38gXkUSjHQ2LGpEUzQ9fXrR8fGUR59YviSnm6U82XjQYhpJEUPnVcC9bguJBQU5xVM4VFcDHu9BgScGPA6mQMH4bn5Cth"); + r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, sizeof(str)); + ck_assert_str_eq(str, "dpubZGLz7gsJAWzUksvtw3opxx5eeLq5fRaUMDABA3bdUVfnGUk5fiS5Cc3kZGTjWtYr3jrEavQQnAF6jv2WCpZtFX4uFgifXqev6ED1TM9rTCB"); + r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memset(&node3.private_key, 0, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); + + // [Chain m/0'/1/2'/2] + fingerprint = hdnode_fingerprint(&node); + hdnode_private_ckd(&node, 2); + ck_assert_int_eq(fingerprint, 0xbcbbc1c4); + ck_assert_mem_eq(node.chain_code, fromhex("cfb71883f01676f587d023cc53a35bc7f88f724b1f8c2892ac1275ac822a3edd"), 32); + ck_assert_mem_eq(node.private_key, fromhex("0f479245fb19a38a1954c5c7c0ebab2f9bdfd96a17563ef28a6a4b1a2a764ef4"), 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq(node.public_key, fromhex("02e8445082a72f29b75ca48748a914df60622a609cacfce8ed0e35804560741d29"), 33); + hdnode_serialize_private(&node, fingerprint, DECRED_VERSION_PRIVATE, str, sizeof(str)); + ck_assert_str_eq(str, "dprv3r7zqYFjT3NiNzdnwGxGpYh6S1TJCp1zA6mSEGaqLBJFnCB94cRMp7YYLR49aTZHZ7ya1CXwQJ6rodKeU9NgQTxkPSK7pzgZRgjYkQ7rgJh"); + r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, sizeof(str)); + ck_assert_str_eq(str, "dpubZHv6Cfp2XRSWHQXZBo1dLmVM421Zdkc4MePkyBXCLFttVkCmwZkxth4ZV9PzkFP3DtD5xcVq2CPSYpJMWMaoxu1ixz4GNZFVcE2xnHP6chJ"); + r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memset(&node3.private_key, 0, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); + + // [Chain m/0'/1/2'/2/1000000000] + fingerprint = hdnode_fingerprint(&node); + hdnode_private_ckd(&node, 1000000000); + ck_assert_int_eq(fingerprint, 0xe58b52e4); + ck_assert_mem_eq(node.chain_code, fromhex("c783e67b921d2beb8f6b389cc646d7263b4145701dadd2161548a8b078e65e9e"), 32); + ck_assert_mem_eq(node.private_key, fromhex("471b76e389e528d6de6d816857e012c5455051cad6660850e58372a6c3e6e7c8"), 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq(node.public_key, fromhex("022a471424da5e657499d1ff51cb43c47481a03b1e77f951fe64cec9f5a48f7011"), 33); + hdnode_serialize_private(&node, fingerprint, DECRED_VERSION_PRIVATE, str, sizeof(str)); + ck_assert_str_eq(str, "dprv3tJXnTDSb3uE6Euo6WvvhFKfBMNfxuJt5smqyPoHEoomoBMQyhYoQSKJAHWtWxmuqdUVb8q9J2NaTkF6rYm6XDrSotkJ55bM21fffa7VV97"); + r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, sizeof(str)); + ck_assert_str_eq(str, "dpubZL6d9amjfRy1zeoZM2zHDU7uoMvwPqtxHRQAiJjeEtQQWjP3retQV1qKJyzUd6ZJNgbJGXjtc5pdoBcTTYTLoxQzvV9JJCzCjB2eCWpRf8T"); + r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memset(&node3.private_key, 0, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); +} +END_TEST + +// test vector 2 from https://github.com/decred/dcrd/blob/master/hdkeychain/extendedkey_test.go +START_TEST(test_bip32_decred_vector_2) +{ + HDNode node, node2, node3; + uint32_t fingerprint; + char str[112]; + int r; + + // init m + hdnode_from_seed(fromhex("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), 64, SECP256K1_NAME, &node); + + // secp256k1_decred_info.bip32_name != "Bitcoin seed" so we cannot use it in hdnode_from_seed + node.curve = &secp256k1_decred_info; + + // [Chain m] + fingerprint = 0; + ck_assert_int_eq(fingerprint, 0x00000000); + ck_assert_mem_eq(node.chain_code, fromhex("60499f801b896d83179a4374aeb7822aaeaceaa0db1f85ee3e904c4defbd9689"), 32); + ck_assert_mem_eq(node.private_key, fromhex("4b03d6fc340455b363f51020ad3ecca4f0850280cf436c70c727923f6db46c3e"), 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq(node.public_key, fromhex("03cbcaa9c98c877a26977d00825c956a238e8dddfbd322cce4f74b0b5bd6ace4a7"), 33); + hdnode_serialize_private(&node, fingerprint, DECRED_VERSION_PRIVATE, str, sizeof(str)); + ck_assert_str_eq(str, "dprv3hCznBesA6jBtPKJbQTxRZAKG2gyj8tZKEPaCsV4e9YYFBAgRP2eTSPAeu4r8dTMt9q51j2Vdt5zNqj7jbtovvocrP1qLj6WUTLF9xYQt4y"); + r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, sizeof(str)); + ck_assert_str_eq(str, "dpubZ9169KDAEUnynoD4qvXJwmxZt3FFA5UdWn1twnRReE9AxjCKJLNFY1uBoegbFmwzA4Du7yqnu8tLivhrCCH6P3DgBS1HH5vmf8MpNXvvYT9"); + r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memset(&node3.private_key, 0, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); + + // [Chain m/0] + fingerprint = hdnode_fingerprint(&node); + r = hdnode_private_ckd(&node, 0); + ck_assert_int_eq(r, 1); + ck_assert_int_eq(fingerprint, 0x2524c9d3); + ck_assert_mem_eq(node.chain_code, fromhex("f0909affaa7ee7abe5dd4e100598d4dc53cd709d5a5c2cac40e7412f232f7c9c"), 32); + ck_assert_mem_eq(node.private_key, fromhex("abe74a98f6c7eabee0428f53798f0ab8aa1bd37873999041703c742f15ac7e1e"), 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq(node.public_key, fromhex("02fc9e5af0ac8d9b3cecfe2a888e2117ba3d089d8585886c9c826b6b22a98d12ea"), 33); + hdnode_serialize_private(&node, fingerprint, DECRED_VERSION_PRIVATE, str, sizeof(str)); + ck_assert_str_eq(str, "dprv3jMy45BuuDETfxi59P8NTSjHPrNVq4wPRfLgRd57923L2hosj5NUEqiLYQ4i7fJtUpiXZLr2wUeToJY2Tm5sCpAJdajEHDmieVJiPQNXwu9"); + r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, sizeof(str)); + ck_assert_str_eq(str, "dpubZBA4RCkCybJFaNbqPuBiyfXY1rvmG1XTdCy1AY1U96dxkFqWc2i5KREMh7NYPpy7ZPMhdpFMAesex3JdFDfX4J5FEW3HjSacqEYPfwb9Cj7"); + r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memset(&node3.private_key, 0, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); + + // [Chain m/0/2147483647'] + fingerprint = hdnode_fingerprint(&node); + r = hdnode_private_ckd_prime(&node, 2147483647); + ck_assert_int_eq(r, 1); + ck_assert_int_eq(fingerprint, 0x6035c6ad); + ck_assert_mem_eq(node.chain_code, fromhex("be17a268474a6bb9c61e1d720cf6215e2a88c5406c4aee7b38547f585c9a37d9"), 32); + ck_assert_mem_eq(node.private_key, fromhex("877c779ad9687164e9c2f4f0f4ff0340814392330693ce95a58fe18fd52e6e93"), 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq(node.public_key, fromhex("03c01e7425647bdefa82b12d9bad5e3e6865bee0502694b94ca58b666abc0a5c3b"), 33); + hdnode_serialize_private(&node, fingerprint, DECRED_VERSION_PRIVATE, str, sizeof(str)); + ck_assert_str_eq(str, "dprv3mgHPRgK838mLK6T1p6WeBoJoJtXA1pGTHjqFuyHekcM7UTuER8fGweRRsoLqSuHa98uskVPnJnfWZEBUC1AVmXnSCPDvUFKydXNnnPHTuQ"); + r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, sizeof(str)); + ck_assert_str_eq(str, "dpubZDUNkZEcCRCZEizDGL9sAQbZRKSnaxQLeqN9zpueeqCyq2VY7NUGMXASacsK96S8XzNjq3YgFgwLtj8MJBToW6To9U5zxuazEyh89bjR1xA"); + r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memset(&node3.private_key, 0, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); + + // [Chain m/0/2147483647'/1] + fingerprint = hdnode_fingerprint(&node); + r = hdnode_private_ckd(&node, 1); + ck_assert_int_eq(r, 1); + ck_assert_int_eq(fingerprint, 0x36fc7080); + ck_assert_mem_eq(node.chain_code, fromhex("f366f48f1ea9f2d1d3fe958c95ca84ea18e4c4ddb9366c336c927eb246fb38cb"), 32); + ck_assert_mem_eq(node.private_key, fromhex("704addf544a06e5ee4bea37098463c23613da32020d604506da8c0518e1da4b7"), 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq(node.public_key, fromhex("03a7d1d856deb74c508e05031f9895dab54626251b3806e16b4bd12e781a7df5b9"), 33); + hdnode_serialize_private(&node, fingerprint, DECRED_VERSION_PRIVATE, str, sizeof(str)); + ck_assert_str_eq(str, "dprv3oFqwZZ9bJcUmhAeJyyshvrTWtrAsHfcRYQbEzNiiH5nGvM6wVTDn6woQEz92b2EHTYZBtLi82jKEnxSouA3cVaW8YWBsw5c3f4mwAhA3d2"); + r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, sizeof(str)); + ck_assert_str_eq(str, "dpubZF3wJh7SfggGg74QZW3EE9ei8uQSJEFgd62uyuK5iMgQzUNjpSnprgTpYz3d6Q3fXXtEEXQqpzWcP4LUVuXFsgA8JKt1Hot5kyUk4pPRhDz"); + r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memset(&node3.private_key, 0, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); + + // [Chain m/0/2147483647'/1/2147483646'] + fingerprint = hdnode_fingerprint(&node); + r = hdnode_private_ckd_prime(&node, 2147483646); + ck_assert_int_eq(r, 1); + ck_assert_int_eq(fingerprint, 0x45309b4c); + ck_assert_mem_eq(node.chain_code, fromhex("637807030d55d01f9a0cb3a7839515d796bd07706386a6eddf06cc29a65a0e29"), 32); + ck_assert_mem_eq(node.private_key, fromhex("f1c7c871a54a804afe328b4c83a1c33b8e5ff48f5087273f04efa83b247d6a2d"), 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq(node.public_key, fromhex("02d2b36900396c9282fa14628566582f206a5dd0bcc8d5e892611806cafb0301f0"), 33); + hdnode_serialize_private(&node, fingerprint, DECRED_VERSION_PRIVATE, str, sizeof(str)); + ck_assert_str_eq(str, "dprv3qF3177i87wMirg6sraDvqty8yZg6THpXFPSXuM5AShBiiUQbq8FhSZDGkYmBNR3RKfBrxzkKDBpsRFJfTnQfLsvpPPqRnakat6hHQA43X9"); + r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, sizeof(str)); + ck_assert_str_eq(str, "dpubZH38NEg1CW19dGZs8NdaT4hDkz7wXPstio1mGpHSAXHpSGW3UnTrn25ERT1Mp8ae5GMoQHMbgQiPrChMXQMdx3UqS8YqFkT1pqait8fY92u"); + r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memset(&node3.private_key, 0, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); + + // [Chain m/0/2147483647'/1/2147483646'/2] + fingerprint = hdnode_fingerprint(&node); + r = hdnode_private_ckd(&node, 2); + ck_assert_int_eq(r, 1); + ck_assert_int_eq(fingerprint, 0x3491a5e6); + ck_assert_mem_eq(node.chain_code, fromhex("9452b549be8cea3ecb7a84bec10dcfd94afe4d129ebfd3b3cb58eedf394ed271"), 32); + ck_assert_mem_eq(node.private_key, fromhex("bb7d39bdb83ecf58f2fd82b6d918341cbef428661ef01ab97c28a4842125ac23"), 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq(node.public_key, fromhex("024d902e1a2fc7a8755ab5b694c575fce742c48d9ff192e63df5193e4c7afe1f9c"), 33); + hdnode_serialize_private(&node, fingerprint, DECRED_VERSION_PRIVATE, str, sizeof(str)); + ck_assert_str_eq(str, "dprv3s15tfqzxhw8Kmo7RBEqMeyvC7uGekLniSmvbs3bckpxQ6ks1KKqfmH144Jgh3PLxkyZRcS367kp7DrtUmnG16NpnsoNhxSXRgKbJJ7MUQR"); + r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, sizeof(str)); + ck_assert_str_eq(str, "dpubZJoBFoQJ35zvEBgsfhJBssnAp8TY5gvruzQFLmyxcqRb7enVtGfSkLo2CkAZJMpa6T2fx6fUtvTgXtUvSVgAZ56bEwGxQsToeZfFV8VadE1"); + r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memset(&node3.private_key, 0, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); + + // init m + hdnode_deserialize("dpubZF4LSCdF9YKZfNzTVYhz4RBxsjYXqms8AQnMBHXZ8GUKoRSigG7kQnKiJt5pzk93Q8FxcdVBEkQZruSXduGtWnkwXzGnjbSovQ97dCxqaXc", DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node, NULL); + + // test public derivation + // [Chain m/0] + fingerprint = hdnode_fingerprint(&node); + r = hdnode_public_ckd(&node, 0); + ck_assert_int_eq(r, 1); + ck_assert_int_eq(fingerprint, 0x6a19cfb3); + ck_assert_mem_eq(node.chain_code, fromhex("dcfe00831741a3a4803955147cdfc7053d69b167b1d03b5f9e63934217a005fd"), 32); + ck_assert_mem_eq(node.public_key, fromhex("029555ea7bde276cd2c42c4502f40b5d16469fb310ae3aeee2a9000455f41b0866"), 33); + hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, sizeof(str)); + ck_assert_str_eq(str, "dpubZHJs2Z3PtHbbpaXQCi5wBKPhU8tC5ztBKUYBCYNGKk8eZ1EmBs3MhnLJbxHFMAahGnDnZT7qZxC7AXKP8PB6BDNUZgkG77moNMRmXyQ6s6s"); + r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); + ck_assert_mem_eq(&node2, &node, sizeof(HDNode)); +} +END_TEST + START_TEST(test_ecdsa_signature) { int res; @@ -4169,6 +4463,11 @@ Suite *test_suite(void) tcase_add_test(tc, test_bip32_ecdh_errors); suite_add_tcase(s, tc); + tc = tcase_create("bip32-decred"); + tcase_add_test(tc, test_bip32_decred_vector_1); + tcase_add_test(tc, test_bip32_decred_vector_2); + suite_add_tcase(s, tc); + tc = tcase_create("ecdsa"); tcase_add_test(tc, test_ecdsa_signature); suite_add_tcase(s, tc); From 921b59e1d84a21ae3d846779017d839114345e4e Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 13 Dec 2017 20:11:37 +0100 Subject: [PATCH 513/627] blake256: add BLAKE256_BLOCK_LENGTH --- blake256.h | 1 + 1 file changed, 1 insertion(+) diff --git a/blake256.h b/blake256.h index 0d2eb977c..ff273a417 100644 --- a/blake256.h +++ b/blake256.h @@ -35,6 +35,7 @@ #define BLAKE224_DIGEST_LENGTH 28 #define BLAKE256_DIGEST_LENGTH 32 +#define BLAKE256_BLOCK_LENGTH 64 typedef struct { uint32_t h[8], s[4], t[2]; From d41556d7fc4f3390b9e2f0d3c9a7d089f3443654 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Fri, 15 Dec 2017 20:24:30 +0000 Subject: [PATCH 514/627] nem: Remove NEM_DECRYPTED_PAYLOAD_SIZE It is broken and completely useless --- nem.h | 1 - 1 file changed, 1 deletion(-) diff --git a/nem.h b/nem.h index cc3935eef..b6e419726 100644 --- a/nem.h +++ b/nem.h @@ -56,7 +56,6 @@ #define NEM_ENCRYPTED_PAYLOAD_SIZE(size) (AES_BLOCK_SIZE + NEM_SALT_SIZE + NEM_ENCRYPTED_SIZE(size)) #define NEM_DECRYPTED_SIZE(buffer, size) ((size) - ((buffer)[(size) - 1])) -#define NEM_DECRYPTED_PAYLOAD_SIZE(buffer, size) NEM_DECRYPTED_SIZE((buffer), (size) - AES_BLOCK_SIZE - NEM_SALT_SIZE) typedef struct { ed25519_public_key public_key; From 44480ca15db7e79c14b3832ccfb5c01c5fef969b Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Fri, 15 Dec 2017 21:23:39 +0000 Subject: [PATCH 515/627] nem: Fix NEM_ENCRYPTED_SIZE Include the extra padding block for multiples of AES_BLOCK_SIZE --- nem.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nem.h b/nem.h index b6e419726..67de2e630 100644 --- a/nem.h +++ b/nem.h @@ -52,7 +52,7 @@ #define NEM_SALT_SIZE sizeof(ed25519_public_key) -#define NEM_ENCRYPTED_SIZE(size) (((size) + AES_BLOCK_SIZE - 1) / AES_BLOCK_SIZE * AES_BLOCK_SIZE) +#define NEM_ENCRYPTED_SIZE(size) (((size) + AES_BLOCK_SIZE) / AES_BLOCK_SIZE * AES_BLOCK_SIZE) #define NEM_ENCRYPTED_PAYLOAD_SIZE(size) (AES_BLOCK_SIZE + NEM_SALT_SIZE + NEM_ENCRYPTED_SIZE(size)) #define NEM_DECRYPTED_SIZE(buffer, size) ((size) - ((buffer)[(size) - 1])) From 74e74f5eed886ff871dc1fb36088e4b465917689 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Fri, 15 Dec 2017 21:35:19 +0000 Subject: [PATCH 516/627] nem: Prevent underflow in NEM_DECRYPTED_SIZE --- nem.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/nem.h b/nem.h index 67de2e630..14e3203c5 100644 --- a/nem.h +++ b/nem.h @@ -55,7 +55,10 @@ #define NEM_ENCRYPTED_SIZE(size) (((size) + AES_BLOCK_SIZE) / AES_BLOCK_SIZE * AES_BLOCK_SIZE) #define NEM_ENCRYPTED_PAYLOAD_SIZE(size) (AES_BLOCK_SIZE + NEM_SALT_SIZE + NEM_ENCRYPTED_SIZE(size)) -#define NEM_DECRYPTED_SIZE(buffer, size) ((size) - ((buffer)[(size) - 1])) +#define _NEM_PADDING_SIZE(buffer, size) ((buffer)[(size) - 1]) +#define NEM_PADDING_SIZE(buffer, size) (_NEM_PADDING_SIZE(buffer, size) > (size) ? (size) : _NEM_PADDING_SIZE(buffer, size)) + +#define NEM_DECRYPTED_SIZE(buffer, size) ((size) - NEM_PADDING_SIZE(buffer, size)) typedef struct { ed25519_public_key public_key; From 27824675550a7e3ed0ce08d3c64068d44647962c Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Wed, 20 Dec 2017 20:09:12 +0000 Subject: [PATCH 517/627] blake256: Replace with working implementation --- blake256.c | 579 ++++++++++++++++++++--------------------------------- blake256.h | 30 +-- 2 files changed, 223 insertions(+), 386 deletions(-) diff --git a/blake256.c b/blake256.c index 66f34268f..99871e5e3 100644 --- a/blake256.c +++ b/blake256.c @@ -1,374 +1,235 @@ -// Copyright (c) 2014-2017, The Monero Project -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without modification, are -// permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this list of -// conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright notice, this list -// of conditions and the following disclaimer in the documentation and/or other -// materials provided with the distribution. -// -// 3. Neither the name of the copyright holder nor the names of its contributors may be -// used to endorse or promote products derived from this software without specific -// prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF -// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// - /* - * The blake256_* and blake224_* functions are largely copied from - * blake256_light.c and blake224_light.c from the BLAKE website: - * - * http://131002.net/blake/ - * - * The hmac_* functions implement HMAC-BLAKE-256 and HMAC-BLAKE-224. - * HMAC is specified by RFC 2104. + BLAKE reference C implementation + + Copyright (c) 2012 Jean-Philippe Aumasson + + To the extent possible under law, the author(s) have dedicated all copyright + and related and neighboring rights to this software to the public domain + worldwide. This software is distributed without any warranty. + + You should have received a copy of the CC0 Public Domain Dedication along with + this software. If not, see . */ +#include "blake256.h" #include -#include -#include "blake256.h" -#define U8TO32(p) \ - (((uint32_t)((p)[0]) << 24) | ((uint32_t)((p)[1]) << 16) | \ - ((uint32_t)((p)[2]) << 8) | ((uint32_t)((p)[3]) )) -#define U32TO8(p, v) \ - (p)[0] = (uint8_t)((v) >> 24); (p)[1] = (uint8_t)((v) >> 16); \ - (p)[2] = (uint8_t)((v) >> 8); (p)[3] = (uint8_t)((v) ); - -static const uint8_t sigma[][16] = { - { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15}, - {14,10, 4, 8, 9,15,13, 6, 1,12, 0, 2,11, 7, 5, 3}, - {11, 8,12, 0, 5, 2,15,13,10,14, 3, 6, 7, 1, 9, 4}, - { 7, 9, 3, 1,13,12,11,14, 2, 6, 5,10, 4, 0,15, 8}, - { 9, 0, 5, 7, 2, 4,10,15,14, 1,11,12, 6, 8, 3,13}, - { 2,12, 6,10, 0,11, 8, 3, 4,13, 7, 5,15,14, 1, 9}, - {12, 5, 1,15,14,13, 4,10, 0, 7, 6, 3, 9, 2, 8,11}, - {13,11, 7,14,12, 1, 3, 9, 5, 0,15, 4, 8, 6, 2,10}, - { 6,15,14, 9,11, 3, 0, 8,12, 2,13, 7, 1, 4,10, 5}, - {10, 2, 8, 4, 7, 6, 1, 5,15,11, 9,14, 3,12,13, 0}, - { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15}, - {14,10, 4, 8, 9,15,13, 6, 1,12, 0, 2,11, 7, 5, 3}, - {11, 8,12, 0, 5, 2,15,13,10,14, 3, 6, 7, 1, 9, 4}, - { 7, 9, 3, 1,13,12,11,14, 2, 6, 5,10, 4, 0,15, 8} +#define U8TO32_BIG(p) \ + (((uint32_t)((p)[0]) << 24) | ((uint32_t)((p)[1]) << 16) | \ + ((uint32_t)((p)[2]) << 8) | ((uint32_t)((p)[3]) )) + +#define U32TO8_BIG(p, v) \ + (p)[0] = (uint8_t)((v) >> 24); (p)[1] = (uint8_t)((v) >> 16); \ + (p)[2] = (uint8_t)((v) >> 8); (p)[3] = (uint8_t)((v) ); + +static const uint8_t sigma[][16] = +{ + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, + {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 }, + {11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 }, + { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 }, + { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 }, + { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 }, + {12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 }, + {13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 }, + { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 }, + {10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 }, + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, + {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 }, + {11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 }, + { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 }, + { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 }, + { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } }; -static const uint32_t cst[16] = { - 0x243F6A88, 0x85A308D3, 0x13198A2E, 0x03707344, - 0xA4093822, 0x299F31D0, 0x082EFA98, 0xEC4E6C89, - 0x452821E6, 0x38D01377, 0xBE5466CF, 0x34E90C6C, - 0xC0AC29B7, 0xC97C50DD, 0x3F84D5B5, 0xB5470917 +static const uint32_t u256[16] = +{ + 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, + 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89, + 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, + 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917 }; -static const uint8_t padding[] = { - 0x80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +static const uint8_t padding[129] = +{ + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - -static void blake256_compress(BLAKE256_CTX *S, const uint8_t *block) { - uint32_t v[16], m[16], i; - -#define ROT(x,n) (((x)<<(32-n))|((x)>>(n))) -#define G(a,b,c,d,e) \ - v[a] += (m[sigma[i][e]] ^ cst[sigma[i][e+1]]) + v[b]; \ - v[d] = ROT(v[d] ^ v[a],16); \ - v[c] += v[d]; \ - v[b] = ROT(v[b] ^ v[c],12); \ - v[a] += (m[sigma[i][e+1]] ^ cst[sigma[i][e]])+v[b]; \ - v[d] = ROT(v[d] ^ v[a], 8); \ - v[c] += v[d]; \ - v[b] = ROT(v[b] ^ v[c], 7); - - for (i = 0; i < 16; ++i) m[i] = U8TO32(block + i * 4); - for (i = 0; i < 8; ++i) v[i] = S->h[i]; - v[ 8] = S->s[0] ^ 0x243F6A88; - v[ 9] = S->s[1] ^ 0x85A308D3; - v[10] = S->s[2] ^ 0x13198A2E; - v[11] = S->s[3] ^ 0x03707344; - v[12] = 0xA4093822; - v[13] = 0x299F31D0; - v[14] = 0x082EFA98; - v[15] = 0xEC4E6C89; - - if (S->nullt == 0) { - v[12] ^= S->t[0]; - v[13] ^= S->t[0]; - v[14] ^= S->t[1]; - v[15] ^= S->t[1]; - } - - for (i = 0; i < 14; ++i) { - G(0, 4, 8, 12, 0); - G(1, 5, 9, 13, 2); - G(2, 6, 10, 14, 4); - G(3, 7, 11, 15, 6); - G(3, 4, 9, 14, 14); - G(2, 7, 8, 13, 12); - G(0, 5, 10, 15, 8); - G(1, 6, 11, 12, 10); - } - - for (i = 0; i < 16; ++i) S->h[i % 8] ^= v[i]; - for (i = 0; i < 8; ++i) S->h[i] ^= S->s[i % 4]; -} - -void blake256_Init(BLAKE256_CTX *S) { - S->h[0] = 0x6A09E667; - S->h[1] = 0xBB67AE85; - S->h[2] = 0x3C6EF372; - S->h[3] = 0xA54FF53A; - S->h[4] = 0x510E527F; - S->h[5] = 0x9B05688C; - S->h[6] = 0x1F83D9AB; - S->h[7] = 0x5BE0CD19; - S->t[0] = S->t[1] = S->buflen = S->nullt = 0; - S->s[0] = S->s[1] = S->s[2] = S->s[3] = 0; -} - -void blake224_Init(BLAKE256_CTX *S) { - S->h[0] = 0xC1059ED8; - S->h[1] = 0x367CD507; - S->h[2] = 0x3070DD17; - S->h[3] = 0xF70E5939; - S->h[4] = 0xFFC00B31; - S->h[5] = 0x68581511; - S->h[6] = 0x64F98FA7; - S->h[7] = 0xBEFA4FA4; - S->t[0] = S->t[1] = S->buflen = S->nullt = 0; - S->s[0] = S->s[1] = S->s[2] = S->s[3] = 0; -} - -// datalen = number of bits -static void blake256_update(BLAKE256_CTX *S, const uint8_t *data, size_t datalen) { - int left = S->buflen >> 3; - int fill = 64 - left; - - if (left && (((datalen >> 3) & 0x3F) >= (unsigned) fill)) { - memcpy((void *) (S->buf + left), (void *) data, fill); - S->t[0] += 512; - if (S->t[0] == 0) S->t[1]++; - blake256_compress(S, S->buf); - data += fill; - datalen -= (fill << 3); - left = 0; - } - - while (datalen >= 512) { - S->t[0] += 512; - if (S->t[0] == 0) S->t[1]++; - blake256_compress(S, data); - data += 64; - datalen -= 512; - } - - if (datalen > 0) { - memcpy((void *) (S->buf + left), (void *) data, datalen >> 3); - S->buflen = (left << 3) + datalen; - } else { - S->buflen = 0; - } -} - -// datalen = number of bytes -void blake256_Update(BLAKE256_CTX *S, const uint8_t *data, size_t datalen) { - blake256_update(S, data, datalen * 8); -} - -// datalen = number of bits -static void blake224_update(BLAKE256_CTX *S, const uint8_t *data, size_t datalen) { - blake256_update(S, data, datalen); -} - -// datalen = number of bytes -void blake224_Update(BLAKE256_CTX *S, const uint8_t *data, size_t datalen) { - blake224_update(S, data, datalen * 8); -} - -static void blake256_final_h(BLAKE256_CTX *S, uint8_t *digest, uint8_t pa, uint8_t pb) { - uint8_t msglen[8]; - uint32_t lo = S->t[0] + S->buflen, hi = S->t[1]; - if (lo < (unsigned) S->buflen) hi++; - U32TO8(msglen + 0, hi); - U32TO8(msglen + 4, lo); - - if (S->buflen == 440) { /* one padding byte */ - S->t[0] -= 8; - blake256_update(S, &pa, 8); - } else { - if (S->buflen < 440) { /* enough space to fill the block */ - if (S->buflen == 0) S->nullt = 1; - S->t[0] -= 440 - S->buflen; - blake256_update(S, padding, 440 - S->buflen); - } else { /* need 2 compressions */ - S->t[0] -= 512 - S->buflen; - blake256_update(S, padding, 512 - S->buflen); - S->t[0] -= 440; - blake256_update(S, padding + 1, 440); - S->nullt = 1; - } - blake256_update(S, &pb, 8); - S->t[0] -= 8; - } - S->t[0] -= 64; - blake256_update(S, msglen, 64); - - U32TO8(digest + 0, S->h[0]); - U32TO8(digest + 4, S->h[1]); - U32TO8(digest + 8, S->h[2]); - U32TO8(digest + 12, S->h[3]); - U32TO8(digest + 16, S->h[4]); - U32TO8(digest + 20, S->h[5]); - U32TO8(digest + 24, S->h[6]); - U32TO8(digest + 28, S->h[7]); -} - -void blake256_Final(BLAKE256_CTX *S, uint8_t *digest) { - blake256_final_h(S, digest, 0x81, 0x01); -} - -void blake224_Final(BLAKE256_CTX *S, uint8_t *digest) { - blake256_final_h(S, digest, 0x80, 0x00); -} - -// inlen = number of bytes -void blake256(const uint8_t *in, size_t inlen, uint8_t *out) { - BLAKE256_CTX S; - blake256_Init(&S); - blake256_Update(&S, in, inlen); - blake256_Final(&S, out); -} - -// inlen = number of bytes -void blake224(const uint8_t *in, size_t inlen, uint8_t *out) { - BLAKE256_CTX S; - blake224_Init(&S); - blake224_Update(&S, in, inlen); - blake224_Final(&S, out); -} - -// keylen = number of bytes -void hmac_blake256_Init(HMAC_BLAKE256_CTX *S, const uint8_t *_key, size_t keylen) { - const uint8_t *key = _key; - uint8_t keyhash[32]; - uint8_t pad[64]; - size_t i; - - if (keylen > 64) { - blake256(key, keylen, keyhash); - key = keyhash; - keylen = 32; - } - - blake256_Init(&S->inner); - memset(pad, 0x36, 64); - for (i = 0; i < keylen; ++i) { - pad[i] ^= key[i]; - } - blake256_update(&S->inner, pad, 512); - - blake256_Init(&S->outer); - memset(pad, 0x5c, 64); - for (i = 0; i < keylen; ++i) { - pad[i] ^= key[i]; - } - blake256_update(&S->outer, pad, 512); - - memset(keyhash, 0, 32); -} - -// keylen = number of bytes -void hmac_blake224_Init(HMAC_BLAKE256_CTX *S, const uint8_t *_key, size_t keylen) { - const uint8_t *key = _key; - uint8_t keyhash[32]; - uint8_t pad[64]; - size_t i; - - if (keylen > 64) { - blake256(key, keylen, keyhash); - key = keyhash; - keylen = 28; - } - - blake224_Init(&S->inner); - memset(pad, 0x36, 64); - for (i = 0; i < keylen; ++i) { - pad[i] ^= key[i]; +static void blake256_compress( BLAKE256_CTX *S, const uint8_t *block ) +{ + uint32_t v[16], m[16], i; +#define ROT(x,n) (((x)<<(32-n))|( (x)>>(n))) +#define G(a,b,c,d,e) \ + v[a] += (m[sigma[i][e]] ^ u256[sigma[i][e+1]]) + v[b]; \ + v[d] = ROT( v[d] ^ v[a],16); \ + v[c] += v[d]; \ + v[b] = ROT( v[b] ^ v[c],12); \ + v[a] += (m[sigma[i][e+1]] ^ u256[sigma[i][e]])+v[b]; \ + v[d] = ROT( v[d] ^ v[a], 8); \ + v[c] += v[d]; \ + v[b] = ROT( v[b] ^ v[c], 7); + + for( i = 0; i < 16; ++i ) m[i] = U8TO32_BIG( block + i * 4 ); + + for( i = 0; i < 8; ++i ) v[i] = S->h[i]; + + v[ 8] = S->s[0] ^ u256[0]; + v[ 9] = S->s[1] ^ u256[1]; + v[10] = S->s[2] ^ u256[2]; + v[11] = S->s[3] ^ u256[3]; + v[12] = u256[4]; + v[13] = u256[5]; + v[14] = u256[6]; + v[15] = u256[7]; + + /* don't xor t when the block is only padding */ + if ( !S->nullt ) + { + v[12] ^= S->t[0]; + v[13] ^= S->t[0]; + v[14] ^= S->t[1]; + v[15] ^= S->t[1]; + } + + for( i = 0; i < 14; ++i ) + { + /* column step */ + G( 0, 4, 8, 12, 0 ); + G( 1, 5, 9, 13, 2 ); + G( 2, 6, 10, 14, 4 ); + G( 3, 7, 11, 15, 6 ); + /* diagonal step */ + G( 0, 5, 10, 15, 8 ); + G( 1, 6, 11, 12, 10 ); + G( 2, 7, 8, 13, 12 ); + G( 3, 4, 9, 14, 14 ); + } + + for( i = 0; i < 16; ++i ) S->h[i % 8] ^= v[i]; + + for( i = 0; i < 8 ; ++i ) S->h[i] ^= S->s[i % 4]; +} + + +void blake256_Init( BLAKE256_CTX *S ) +{ + S->h[0] = 0x6a09e667; + S->h[1] = 0xbb67ae85; + S->h[2] = 0x3c6ef372; + S->h[3] = 0xa54ff53a; + S->h[4] = 0x510e527f; + S->h[5] = 0x9b05688c; + S->h[6] = 0x1f83d9ab; + S->h[7] = 0x5be0cd19; + S->t[0] = S->t[1] = S->buflen = S->nullt = 0; + S->s[0] = S->s[1] = S->s[2] = S->s[3] = 0; +} + + +void blake256_Update( BLAKE256_CTX *S, const uint8_t *in, size_t inlen ) +{ + size_t left = S->buflen; + size_t fill = 64 - left; + + /* data left and data received fill a block */ + if( left && ( inlen >= fill ) ) + { + memcpy( ( void * ) ( S->buf + left ), ( void * ) in, fill ); + S->t[0] += 512; + + if ( S->t[0] == 0 ) S->t[1]++; + + blake256_compress( S, S->buf ); + in += fill; + inlen -= fill; + left = 0; + } + + /* compress blocks of data received */ + while( inlen >= 64 ) + { + S->t[0] += 512; + + if ( S->t[0] == 0 ) S->t[1]++; + + blake256_compress( S, in ); + in += 64; + inlen -= 64; + } + + /* store any data left */ + if( inlen > 0 ) + { + memcpy( ( void * ) ( S->buf + left ), \ + ( void * ) in, ( size_t ) inlen ); + S->buflen = left + ( int )inlen; + } + else S->buflen = 0; +} + + +void blake256_Final( BLAKE256_CTX *S, uint8_t *out ) +{ + uint8_t msglen[8], zo = 0x01, oo = 0x81; + uint32_t lo = S->t[0] + ( S->buflen << 3 ), hi = S->t[1]; + + /* support for hashing more than 2^32 bits */ + if ( lo < ( S->buflen << 3 ) ) hi++; + + U32TO8_BIG( msglen + 0, hi ); + U32TO8_BIG( msglen + 4, lo ); + + if ( S->buflen == 55 ) /* one padding byte */ + { + S->t[0] -= 8; + blake256_Update( S, &oo, 1 ); + } + else + { + if ( S->buflen < 55 ) /* enough space to fill the block */ + { + if ( !S->buflen ) S->nullt = 1; + + S->t[0] -= 440 - ( S->buflen << 3 ); + blake256_Update( S, padding, 55 - S->buflen ); } - blake224_update(&S->inner, pad, 512); - - blake224_Init(&S->outer); - memset(pad, 0x5c, 64); - for (i = 0; i < keylen; ++i) { - pad[i] ^= key[i]; + else /* need 2 compressions */ + { + S->t[0] -= 512 - ( S->buflen << 3 ); + blake256_Update( S, padding, 64 - S->buflen ); + S->t[0] -= 440; + blake256_Update( S, padding + 1, 55 ); + S->nullt = 1; } - blake224_update(&S->outer, pad, 512); - - memset(keyhash, 0, 32); -} - -// datalen = number of bits -static void hmac_blake256_update(HMAC_BLAKE256_CTX *S, const uint8_t *data, size_t datalen) { - // update the inner BLAKE256_CTX - blake256_update(&S->inner, data, datalen); -} - -// datalen = number of bytes -void hmac_blake256_Update(HMAC_BLAKE256_CTX *S, const uint8_t *data, size_t datalen) { - hmac_blake256_update(S, data, datalen * 8); -} - -// datalen = number of bits -static void hmac_blake224_update(HMAC_BLAKE256_CTX *S, const uint8_t *data, size_t datalen) { - // update the inner BLAKE256_CTX - blake224_update(&S->inner, data, datalen); -} - -// datalen = number of bytes -void hmac_blake224_Update(HMAC_BLAKE256_CTX *S, const uint8_t *data, size_t datalen) { - hmac_blake224_update(S, data, datalen * 8); -} - -void hmac_blake256_Final(HMAC_BLAKE256_CTX *S, uint8_t *digest) { - uint8_t ihash[32]; - blake256_Final(&S->inner, ihash); - blake256_update(&S->outer, ihash, 256); - blake256_Final(&S->outer, digest); - memset(ihash, 0, 32); -} - -void hmac_blake224_Final(HMAC_BLAKE256_CTX *S, uint8_t *digest) { - uint8_t ihash[32]; - blake224_Final(&S->inner, ihash); - blake224_update(&S->outer, ihash, 224); - blake224_Final(&S->outer, digest); - memset(ihash, 0, 32); -} - -// keylen = number of bytes; inlen = number of bytes -void hmac_blake256(const uint8_t *key, size_t keylen, const uint8_t *in, size_t inlen, uint8_t *out) { - HMAC_BLAKE256_CTX S; - hmac_blake256_Init(&S, key, keylen); - hmac_blake256_Update(&S, in, inlen); - hmac_blake256_Final(&S, out); -} -// keylen = number of bytes; inlen = number of bytes -void hmac_blake224(const uint8_t *key, size_t keylen, const uint8_t *in, size_t inlen, uint8_t *out) { - HMAC_BLAKE256_CTX S; - hmac_blake224_Init(&S, key, keylen); - hmac_blake224_Update(&S, in, inlen); - hmac_blake224_Final(&S, out); + blake256_Update( S, &zo, 1 ); + S->t[0] -= 8; + } + + S->t[0] -= 64; + blake256_Update( S, msglen, 8 ); + U32TO8_BIG( out + 0, S->h[0] ); + U32TO8_BIG( out + 4, S->h[1] ); + U32TO8_BIG( out + 8, S->h[2] ); + U32TO8_BIG( out + 12, S->h[3] ); + U32TO8_BIG( out + 16, S->h[4] ); + U32TO8_BIG( out + 20, S->h[5] ); + U32TO8_BIG( out + 24, S->h[6] ); + U32TO8_BIG( out + 28, S->h[7] ); +} + + +void blake256( const uint8_t *in, size_t inlen, uint8_t *out ) +{ + BLAKE256_CTX S; + blake256_Init( &S ); + blake256_Update( &S, in, inlen ); + blake256_Final( &S, out ); } diff --git a/blake256.h b/blake256.h index ff273a417..313b6260e 100644 --- a/blake256.h +++ b/blake256.h @@ -32,46 +32,22 @@ #define __BLAKE256_H__ #include +#include -#define BLAKE224_DIGEST_LENGTH 28 #define BLAKE256_DIGEST_LENGTH 32 #define BLAKE256_BLOCK_LENGTH 64 typedef struct { uint32_t h[8], s[4], t[2]; - int buflen, nullt; + size_t buflen; + uint8_t nullt; uint8_t buf[64]; } BLAKE256_CTX; -typedef struct { - BLAKE256_CTX inner; - BLAKE256_CTX outer; -} HMAC_BLAKE256_CTX; - void blake256_Init(BLAKE256_CTX *); -void blake224_Init(BLAKE256_CTX *); - void blake256_Update(BLAKE256_CTX *, const uint8_t *, size_t); -void blake224_Update(BLAKE256_CTX *, const uint8_t *, size_t); - void blake256_Final(BLAKE256_CTX *, uint8_t *); -void blake224_Final(BLAKE256_CTX *, uint8_t *); void blake256(const uint8_t *, size_t, uint8_t *); -void blake224(const uint8_t *, size_t, uint8_t *); - -/* HMAC functions: */ - -void hmac_blake256_Init(HMAC_BLAKE256_CTX *, const uint8_t *, size_t); -void hmac_blake224_Init(HMAC_BLAKE256_CTX *, const uint8_t *, size_t); - -void hmac_blake256_Update(HMAC_BLAKE256_CTX *, const uint8_t *, size_t); -void hmac_blake224_Update(HMAC_BLAKE256_CTX *, const uint8_t *, size_t); - -void hmac_blake256_Final(HMAC_BLAKE256_CTX *, uint8_t *); -void hmac_blake224_Final(HMAC_BLAKE256_CTX *, uint8_t *); - -void hmac_blake256(const uint8_t *, size_t, const uint8_t *, size_t, uint8_t *); -void hmac_blake224(const uint8_t *, size_t, const uint8_t *, size_t, uint8_t *); #endif /* __BLAKE256_H__ */ From 8d8bc9c762b504ee8c66f94d93600d417d92841e Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 2 Jan 2018 14:14:49 +0100 Subject: [PATCH 518/627] bip39: use static modifier --- bip39_english.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bip39_english.h b/bip39_english.h index 233acc2f8..77607ba7f 100644 --- a/bip39_english.h +++ b/bip39_english.h @@ -21,7 +21,7 @@ * OTHER DEALINGS IN THE SOFTWARE. */ -const char * const wordlist[] = { +static const char * const wordlist[] = { "abandon", "ability", "able", From a54c5fe89e2d9e970480281a69178a195f3bb19f Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 7 Jan 2018 21:51:33 +0100 Subject: [PATCH 519/627] test_openssl: fix build with openssl 1.1.0+ OpenSSL 1.1.0 made R and S fields of ECDSA_SIG structure internal. We need to use ECDSA_SIG_set0 function now. For some reason the test fails, but previously the code was not even possible to compile with OpenSSL 1.1.0. Still need to figure out why the test fails :-( --- test_openssl.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/test_openssl.c b/test_openssl.c index dcec83c77..1817afcd3 100644 --- a/test_openssl.c +++ b/test_openssl.c @@ -24,9 +24,11 @@ /* OpenSSL's SHA256_CTX/SHA512_CTX conflicts with our own */ #define SHA256_CTX _openssl_SHA256_CTX #define SHA512_CTX _openssl_SHA512_CTX +#include #include #include #include +#include #undef SHA256_CTX #undef SHA512_CTX @@ -103,8 +105,14 @@ void openssl_check(unsigned int iterations, int nid, const ecdsa_curve *curve) // copy signature to the OpenSSL struct ECDSA_SIG *signature = ECDSA_SIG_new(); +#if OPENSSL_VERSION_NUMBER < 0x10100000L BN_bin2bn(sig, 32, signature->r); BN_bin2bn(sig + 32, 32, signature->s); +#else + BIGNUM *R = BN_bin2bn(sig, 32, NULL); + BIGNUM *S = BN_bin2bn(sig + 32, 32, NULL); + ECDSA_SIG_set0(signature, R, S); +#endif // compute the digest of the message // note: these are OpenSSL functions, not our own @@ -113,8 +121,9 @@ void openssl_check(unsigned int iterations, int nid, const ecdsa_curve *curve) SHA256_Final(hash, &sha256); // verify all went well, i.e. we can decrypt our signature with OpenSSL - if (ECDSA_do_verify(hash, 32, signature, eckey) != 1) { - printf("OpenSSL verification failed\n"); + int v = ECDSA_do_verify(hash, 32, signature, eckey); + if (v != 1) { + printf("OpenSSL verification failed (%d)\n", v); return; } From cb8c910a0c76900df4c076cca226b56d28820f69 Mon Sep 17 00:00:00 2001 From: "Peter D. Gray" Date: Fri, 12 Jan 2018 11:24:47 -0500 Subject: [PATCH 520/627] Makefile: simplify include path, move subdirs to where used in C files --- Makefile | 5 +---- bip32.c | 8 ++++---- bip32.h | 2 +- nem.c | 2 +- nem.h | 2 +- test_check.c | 6 +++--- test_speed.c | 2 +- 7 files changed, 12 insertions(+), 15 deletions(-) diff --git a/Makefile b/Makefile index ae23e4456..b1b90259c 100644 --- a/Makefile +++ b/Makefile @@ -24,9 +24,6 @@ CFLAGS += $(OPTFLAGS) \ -Werror CFLAGS += -I. -CFLAGS += -Iaes -CFLAGS += -Ichacha20poly1305 -CFLAGS += -Ied25519-donna CFLAGS += -DUSE_ETHEREUM=1 CFLAGS += -DUSE_GRAPHENE=1 CFLAGS += -DUSE_NEM=1 @@ -56,7 +53,7 @@ SRCS += segwit_addr.c OBJS = $(SRCS:.c=.o) -TESTLIBS = $(shell pkg-config --libs check) -lrt -lpthread -lm +TESTLIBS = $(shell pkg-config --libs check) -lpthread -lm TESTSSLLIBS = -lcrypto all: test_check test_openssl test_speed aes/aestst tools libtrezor-crypto.so diff --git a/bip32.c b/bip32.c index 97588bdda..e6ac015b5 100644 --- a/bip32.c +++ b/bip32.c @@ -25,7 +25,7 @@ #include #include -#include "aes.h" +#include "aes/aes.h" #include "address.h" #include "bignum.h" #include "hmac.h" @@ -39,10 +39,10 @@ #include "curves.h" #include "secp256k1.h" #include "nist256p1.h" -#include "ed25519.h" -#include "ed25519-sha3.h" +#include "ed25519-donna/ed25519.h" +#include "ed25519-donna/ed25519-sha3.h" #if USE_KECCAK -#include "ed25519-keccak.h" +#include "ed25519-donna/ed25519-keccak.h" #endif #if USE_NEM #include "nem.h" diff --git a/bip32.h b/bip32.h index 980f5c850..9e73d75ca 100644 --- a/bip32.h +++ b/bip32.h @@ -28,7 +28,7 @@ #include #include #include "ecdsa.h" -#include "ed25519.h" +#include "ed25519-donna/ed25519.h" #include "options.h" typedef struct { diff --git a/nem.c b/nem.c index 9b0150ea7..f70076498 100644 --- a/nem.c +++ b/nem.c @@ -25,7 +25,7 @@ #include #include "base32.h" -#include "ed25519-keccak.h" +#include "ed25519-donna/ed25519-keccak.h" #include "macros.h" #include "ripemd160.h" #include "sha3.h" diff --git a/nem.h b/nem.h index 14e3203c5..fe7f7b68f 100644 --- a/nem.h +++ b/nem.h @@ -28,7 +28,7 @@ #include #include "bip32.h" -#include "ed25519.h" +#include "ed25519-donna/ed25519.h" #define NEM_LEVY_PERCENTILE_DIVISOR 4 #define NEM_MAX_DIVISIBILITY 6 diff --git a/test_check.c b/test_check.c index 64813e70b..918cd0540 100644 --- a/test_check.c +++ b/test_check.c @@ -36,7 +36,7 @@ #include "options.h" -#include "aes.h" +#include "aes/aes.h" #include "bignum.h" #include "base32.h" #include "base58.h" @@ -53,8 +53,8 @@ #include "curves.h" #include "secp256k1.h" #include "nist256p1.h" -#include "ed25519.h" -#include "ed25519-keccak.h" +#include "ed25519-donna/ed25519.h" +#include "ed25519-donna/ed25519-keccak.h" #include "script.h" #include "rfc6979.h" #include "address.h" diff --git a/test_speed.c b/test_speed.c index 1140b84c8..cff4aee2a 100644 --- a/test_speed.c +++ b/test_speed.c @@ -8,7 +8,7 @@ #include "bip32.h" #include "secp256k1.h" #include "nist256p1.h" -#include "ed25519.h" +#include "ed25519-donna/ed25519.h" #include "hasher.h" static uint8_t msg[256]; From 65e976d70c3f196b8548824b02551254219f2412 Mon Sep 17 00:00:00 2001 From: "Peter D. Gray" Date: Fri, 12 Jan 2018 13:17:58 -0500 Subject: [PATCH 521/627] rand.c: platform depedenant code can be removed using CPP flag --- rand.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/rand.c b/rand.c index 2770c30ec..9d43850f7 100644 --- a/rand.c +++ b/rand.c @@ -30,6 +30,8 @@ #include "rand.h" +#ifndef RAND_PLATFORM_INDEPENDANT + static FILE *frand = NULL; int finalize_rand(void) @@ -62,13 +64,6 @@ uint32_t random32(void) #endif } -uint32_t random_uniform(uint32_t n) -{ - uint32_t x, max = 0xFFFFFFFF - (0xFFFFFFFF % n); - while ((x = random32()) >= max); - return x / (max / n); -} - void random_buffer(uint8_t *buf, size_t len) { #ifdef _WIN32 @@ -87,6 +82,19 @@ void random_buffer(uint8_t *buf, size_t len) #endif } +#endif /* RAND_PLATFORM_INDEPENDANT */ + +// +// Following code should be platform independant +// + +uint32_t random_uniform(uint32_t n) +{ + uint32_t x, max = 0xFFFFFFFF - (0xFFFFFFFF % n); + while ((x = random32()) >= max); + return x / (max / n); +} + void random_permute(char *str, size_t len) { int i, j; From 46fa586b1206f741c26881ef41c14f40c7522313 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 13 Jan 2018 15:07:19 +0100 Subject: [PATCH 522/627] further work on making rand.{c,h} more global --- rand.c | 78 ++++++++++++++++++++++------------------------------------ rand.h | 6 ++++- 2 files changed, 34 insertions(+), 50 deletions(-) diff --git a/rand.c b/rand.c index 9d43850f7..8a288c983 100644 --- a/rand.c +++ b/rand.c @@ -21,71 +21,42 @@ * OTHER DEALINGS IN THE SOFTWARE. */ -#include -#ifdef _WIN32 -#include -#else -#include -#endif - #include "rand.h" -#ifndef RAND_PLATFORM_INDEPENDANT - -static FILE *frand = NULL; +#ifndef RAND_PLATFORM_INDEPENDENT -int finalize_rand(void) -{ +#include #ifdef _WIN32 - return 0; +#include #else - if (!frand) return 0; - int err = fclose(frand); - frand = NULL; - return err; +#include #endif -} uint32_t random32(void) { #ifdef _WIN32 - srand((unsigned)time(NULL)); + static int initialized = 0; + if (!initialized) { + srand((unsigned)time(NULL)); + initialized = 1; + } return ((rand() % 0xFF) | ((rand() % 0xFF) << 8) | ((rand() % 0xFF) << 16) | ((rand() % 0xFF) << 24)); #else - uint32_t r; - size_t len = sizeof(r); + static FILE *frand = NULL; if (!frand) { frand = fopen("/dev/urandom", "r"); } - size_t len_read = fread(&r, 1, len, frand); - (void)len_read; - assert(len_read == len); + uint32_t r; + size_t len_read = fread(&r, 1, sizeof(r), frand); + assert(len_read == sizeof(r)); return r; #endif } -void random_buffer(uint8_t *buf, size_t len) -{ -#ifdef _WIN32 - srand((unsigned)time(NULL)); - size_t i; - for (i = 0; i < len; i++) { - buf[i] = rand() % 0xFF; - } -#else - if (!frand) { - frand = fopen("/dev/urandom", "r"); - } - size_t len_read = fread(buf, 1, len, frand); - (void)len_read; - assert(len_read == len); -#endif -} - -#endif /* RAND_PLATFORM_INDEPENDANT */ +#endif /* RAND_PLATFORM_INDEPENDENT */ // -// Following code should be platform independant +// The following code is platform independent // uint32_t random_uniform(uint32_t n) @@ -95,13 +66,22 @@ uint32_t random_uniform(uint32_t n) return x / (max / n); } +void random_buffer(uint8_t *buf, size_t len) +{ + uint32_t r = 0; + for (size_t i = 0; i < len; i++) { + if (i % 4 == 0) { + r = random32(); + } + buf[i] = (r >> ((i % 4) * 8)) & 0xFF; + } +} + void random_permute(char *str, size_t len) { - int i, j; - char t; - for (i = len - 1; i >= 1; i--) { - j = random_uniform(i + 1); - t = str[j]; + for (int i = len - 1; i >= 1; i--) { + int j = random_uniform(i + 1); + char t = str[j]; str[j] = str[i]; str[i] = t; } diff --git a/rand.h b/rand.h index 3c9655999..6eceef5de 100644 --- a/rand.h +++ b/rand.h @@ -27,8 +27,12 @@ #include #include -int finalize_rand(void); +#ifndef RAND_PLATFORM_INDEPENDENT + uint32_t random32(void); + +#endif /* RAND_PLATFORM_INDEPENDENT */ + uint32_t random_uniform(uint32_t n); void random_buffer(uint8_t *buf, size_t len); void random_permute(char *buf, size_t len); From b3f026c742eaea8fdd66b437b411962779f3dec0 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 13 Jan 2018 15:14:45 +0100 Subject: [PATCH 523/627] extern declaration of random32 --- rand.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/rand.h b/rand.h index 6eceef5de..1696919ca 100644 --- a/rand.h +++ b/rand.h @@ -31,6 +31,10 @@ uint32_t random32(void); +#else + +extern uint32_t random32(void); + #endif /* RAND_PLATFORM_INDEPENDENT */ uint32_t random_uniform(uint32_t n); From 0d8a3beeaf22af837f558a5b5e9ae98cdd47a767 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 13 Jan 2018 15:16:34 +0100 Subject: [PATCH 524/627] declare random32 always --- rand.h | 9 --------- 1 file changed, 9 deletions(-) diff --git a/rand.h b/rand.h index 1696919ca..1053fef29 100644 --- a/rand.h +++ b/rand.h @@ -27,16 +27,7 @@ #include #include -#ifndef RAND_PLATFORM_INDEPENDENT - uint32_t random32(void); - -#else - -extern uint32_t random32(void); - -#endif /* RAND_PLATFORM_INDEPENDENT */ - uint32_t random_uniform(uint32_t n); void random_buffer(uint8_t *buf, size_t len); void random_permute(char *buf, size_t len); From 72841c4fa16e46897410623731698b7ddee3a448 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 15 Jan 2018 18:28:02 +0100 Subject: [PATCH 525/627] declare random_buffer as weak symbol --- rand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rand.c b/rand.c index 8a288c983..975bf18d5 100644 --- a/rand.c +++ b/rand.c @@ -66,7 +66,7 @@ uint32_t random_uniform(uint32_t n) return x / (max / n); } -void random_buffer(uint8_t *buf, size_t len) +void __attribute__((weak)) random_buffer(uint8_t *buf, size_t len) { uint32_t r = 0; for (size_t i = 0; i < len; i++) { From b7f73ee3ff78e09c266a30dbc31407558d471615 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 16 Jan 2018 19:41:27 +0100 Subject: [PATCH 526/627] use explicit_bzero --- base58.c | 5 ++-- bignum.c | 13 +++++------ bip32.c | 49 +++++++++++++++++++-------------------- bip39.c | 13 +++++------ blake2b.c | 5 ++-- blake2s.c | 5 ++-- ecdsa.c | 67 ++++++++++++++++++++++++++--------------------------- hmac.c | 17 +++++++------- macros.h | 6 ----- nem.c | 9 ++++--- pbkdf2.c | 5 ++-- rfc6979.c | 8 +++---- ripemd160.c | 3 +-- sha2.c | 43 +++++++++++++++++----------------- sha3.c | 5 ++-- 15 files changed, 117 insertions(+), 136 deletions(-) delete mode 100644 macros.h diff --git a/base58.c b/base58.c index 528a75047..7ca8b013f 100644 --- a/base58.c +++ b/base58.c @@ -26,7 +26,6 @@ #include #include "base58.h" #include "sha2.h" -#include "macros.h" #include "ripemd160.h" static const int8_t b58digits_map[] = { @@ -200,7 +199,7 @@ int base58_encode_check(const uint8_t *data, int datalen, HasherType hasher_type hasher_Raw(hasher_type, hash, 32, hash); size_t res = strsize; bool success = b58enc(str, &res, buf, datalen + 4); - MEMSET_BZERO(buf, sizeof(buf)); + explicit_bzero(buf, sizeof(buf)); return success ? res : 0; } @@ -254,7 +253,7 @@ int base58gph_encode_check(const uint8_t *data, int datalen, char *str, int strs ripemd160(data, datalen, hash); // No double SHA256, but a single RIPEMD160 size_t res = strsize; bool success = b58enc(str, &res, buf, datalen + 4); - MEMSET_BZERO(buf, sizeof(buf)); + explicit_bzero(buf, sizeof(buf)); return success ? res : 0; } diff --git a/bignum.c b/bignum.c index d0e2b2825..803fd7836 100644 --- a/bignum.c +++ b/bignum.c @@ -27,7 +27,6 @@ #include #include #include "bignum.h" -#include "macros.h" /* big number library */ @@ -490,7 +489,7 @@ void bn_multiply(const bignum256 *k, bignum256 *x, const bignum256 *prime) uint32_t res[18] = {0}; bn_multiply_long(k, x, res); bn_multiply_reduce(x, res, prime); - MEMSET_BZERO(res, sizeof(res)); + explicit_bzero(res, sizeof(res)); } // partly reduce x modulo prime @@ -552,8 +551,8 @@ void bn_sqrt(bignum256 *x, const bignum256 *prime) } bn_mod(&res, prime); memcpy(x, &res, sizeof(bignum256)); - MEMSET_BZERO(&res, sizeof(res)); - MEMSET_BZERO(&p, sizeof(p)); + explicit_bzero(&res, sizeof(res)); + explicit_bzero(&p, sizeof(p)); } #if ! USE_INVERSE_FAST @@ -861,9 +860,9 @@ void bn_inverse(bignum256 *x, const bignum256 *prime) x->val[i] = temp32; // let's wipe all temp buffers - MEMSET_BZERO(pp, sizeof(pp)); - MEMSET_BZERO(&us, sizeof(us)); - MEMSET_BZERO(&vr, sizeof(vr)); + explicit_bzero(pp, sizeof(pp)); + explicit_bzero(&us, sizeof(us)); + explicit_bzero(&vr, sizeof(vr)); } #endif diff --git a/bip32.c b/bip32.c index e6ac015b5..1f22f193a 100644 --- a/bip32.c +++ b/bip32.c @@ -35,7 +35,6 @@ #include "sha3.h" #include "ripemd160.h" #include "base58.h" -#include "macros.h" #include "curves.h" #include "secp256k1.h" #include "nist256p1.h" @@ -87,7 +86,7 @@ int hdnode_from_xpub(uint32_t depth, uint32_t child_num, const uint8_t *chain_co out->depth = depth; out->child_num = child_num; memcpy(out->chain_code, chain_code, 32); - MEMSET_BZERO(out->private_key, 32); + explicit_bzero(out->private_key, 32); memcpy(out->public_key, public_key, 33); return 1; } @@ -108,7 +107,7 @@ int hdnode_from_xprv(uint32_t depth, uint32_t child_num, const uint8_t *chain_co failed = true; } } - MEMSET_BZERO(&a, sizeof(a)); + explicit_bzero(&a, sizeof(a)); } if (failed) { @@ -120,7 +119,7 @@ int hdnode_from_xprv(uint32_t depth, uint32_t child_num, const uint8_t *chain_co out->child_num = child_num; memcpy(out->chain_code, chain_code, 32); memcpy(out->private_key, private_key, 32); - MEMSET_BZERO(out->public_key, sizeof(out->public_key)); + explicit_bzero(out->public_key, sizeof(out->public_key)); return 1; } @@ -151,12 +150,12 @@ int hdnode_from_seed(const uint8_t *seed, int seed_len, const char* curve, HDNod hmac_sha512_Update(&ctx, I, sizeof(I)); hmac_sha512_Final(&ctx, I); } - MEMSET_BZERO(&a, sizeof(a)); + explicit_bzero(&a, sizeof(a)); } memcpy(out->private_key, I, 32); memcpy(out->chain_code, I + 32, 32); - MEMSET_BZERO(out->public_key, sizeof(out->public_key)); - MEMSET_BZERO(I, sizeof(I)); + explicit_bzero(out->public_key, sizeof(out->public_key)); + explicit_bzero(I, sizeof(I)); return 1; } @@ -169,7 +168,7 @@ uint32_t hdnode_fingerprint(HDNode *node) hasher_Raw(node->curve->hasher_type, node->public_key, 33, digest); ripemd160(digest, 32, digest); fingerprint = (digest[0] << 24) + (digest[1] << 16) + (digest[2] << 8) + digest[3]; - MEMSET_BZERO(digest, sizeof(digest)); + explicit_bzero(digest, sizeof(digest)); return fingerprint; } @@ -230,13 +229,13 @@ int hdnode_private_ckd(HDNode *inout, uint32_t i) memcpy(inout->chain_code, I + 32, 32); inout->depth++; inout->child_num = i; - MEMSET_BZERO(inout->public_key, sizeof(inout->public_key)); + explicit_bzero(inout->public_key, sizeof(inout->public_key)); // making sure to wipe our memory - MEMSET_BZERO(&a, sizeof(a)); - MEMSET_BZERO(&b, sizeof(b)); - MEMSET_BZERO(I, sizeof(I)); - MEMSET_BZERO(data, sizeof(data)); + explicit_bzero(&a, sizeof(a)); + explicit_bzero(&b, sizeof(b)); + explicit_bzero(I, sizeof(I)); + explicit_bzero(data, sizeof(data)); return 1; } @@ -265,9 +264,9 @@ int hdnode_public_ckd_cp(const ecdsa_curve *curve, const curve_point *parent, co } // Wipe all stack data. - MEMSET_BZERO(data, sizeof(data)); - MEMSET_BZERO(I, sizeof(I)); - MEMSET_BZERO(&c, sizeof(c)); + explicit_bzero(data, sizeof(data)); + explicit_bzero(I, sizeof(I)); + explicit_bzero(&c, sizeof(c)); return 1; } } @@ -287,15 +286,15 @@ int hdnode_public_ckd(HDNode *inout, uint32_t i) if (!hdnode_public_ckd_cp(inout->curve->params, &parent, inout->chain_code, i, &child, inout->chain_code)) { return 0; } - memset(inout->private_key, 0, 32); + explicit_bzero(inout->private_key, 32); inout->depth++; inout->child_num = i; inout->public_key[0] = 0x02 | (child.y.val[0] & 0x01); bn_write_be(&child.x, inout->public_key + 1); // Wipe all stack data. - MEMSET_BZERO(&parent, sizeof(parent)); - MEMSET_BZERO(&child, sizeof(child)); + explicit_bzero(&parent, sizeof(parent)); + explicit_bzero(&child, sizeof(child)); return 1; } @@ -350,7 +349,7 @@ int hdnode_private_ckd_cached(HDNode *inout, const uint32_t *i, size_t i_count, if (!private_ckd_cache_root_set || memcmp(&private_ckd_cache_root, inout, sizeof(HDNode)) != 0) { // clear the cache private_ckd_cache_index = 0; - memset(private_ckd_cache, 0, sizeof(private_ckd_cache)); + explicit_bzero(private_ckd_cache, sizeof(private_ckd_cache)); // setup new root memcpy(&private_ckd_cache_root, inout, sizeof(HDNode)); private_ckd_cache_root_set = true; @@ -497,7 +496,7 @@ int hdnode_nem_encrypt(const HDNode *node, const ed25519_public_key public_key, aes_encrypt_ctx ctx; int ret = aes_encrypt_key256(shared_key, &ctx); - MEMSET_BZERO(shared_key, sizeof(shared_key)); + explicit_bzero(shared_key, sizeof(shared_key)); if (ret != EXIT_SUCCESS) { return 0; @@ -524,7 +523,7 @@ int hdnode_nem_decrypt(const HDNode *node, const ed25519_public_key public_key, aes_decrypt_ctx ctx; int ret = aes_decrypt_key256(shared_key, &ctx); - MEMSET_BZERO(shared_key, sizeof(shared_key)); + explicit_bzero(shared_key, sizeof(shared_key)); if (ret != EXIT_SUCCESS) { return 0; @@ -610,7 +609,7 @@ static int hdnode_serialize(const HDNode *node, uint32_t fingerprint, uint32_t v memcpy(node_data + 46, node->private_key, 32); } int ret = base58_encode_check(node_data, sizeof(node_data), node->curve->hasher_type, str, strsize); - MEMSET_BZERO(node_data, sizeof(node_data)); + explicit_bzero(node_data, sizeof(node_data)); return ret; } @@ -635,14 +634,14 @@ int hdnode_deserialize(const char *str, uint32_t version_public, uint32_t versio } uint32_t version = read_be(node_data); if (version == version_public) { - MEMSET_BZERO(node->private_key, sizeof(node->private_key)); + explicit_bzero(node->private_key, sizeof(node->private_key)); memcpy(node->public_key, node_data + 45, 33); } else if (version == version_private) { // private node if (node_data[45]) { // invalid data return -2; } memcpy(node->private_key, node_data + 46, 32); - MEMSET_BZERO(node->public_key, sizeof(node->public_key)); + explicit_bzero(node->public_key, sizeof(node->public_key)); } else { return -3; // invalid version } diff --git a/bip39.c b/bip39.c index 7539944d0..a9f43f1ec 100644 --- a/bip39.c +++ b/bip39.c @@ -31,7 +31,6 @@ #include "pbkdf2.h" #include "bip39_english.h" #include "options.h" -#include "macros.h" #if USE_BIP39_CACHE @@ -54,7 +53,7 @@ const char *mnemonic_generate(int strength) uint8_t data[32]; random_buffer(data, 32); const char *r = mnemonic_from_data(data, strength / 8); - MEMSET_BZERO(data, sizeof(data)); + explicit_bzero(data, sizeof(data)); return r; } @@ -66,7 +65,7 @@ const uint16_t *mnemonic_generate_indexes(int strength) uint8_t data[32]; random_buffer(data, 32); const uint16_t *r = mnemonic_from_data_indexes(data, strength / 8); - MEMSET_BZERO(data, sizeof(data)); + explicit_bzero(data, sizeof(data)); return r; } @@ -100,7 +99,7 @@ const char *mnemonic_from_data(const uint8_t *data, int len) *p = (i < mlen - 1) ? ' ' : 0; p++; } - MEMSET_BZERO(bits, sizeof(bits)); + explicit_bzero(bits, sizeof(bits)); return mnemo; } @@ -131,7 +130,7 @@ const uint16_t *mnemonic_from_data_indexes(const uint8_t *data, int len) } mnemo[i] = idx; } - MEMSET_BZERO(bits, sizeof(bits)); + explicit_bzero(bits, sizeof(bits)); return mnemo; } @@ -161,7 +160,7 @@ int mnemonic_check(const char *mnemonic) uint32_t j, k, ki, bi; uint8_t bits[32 + 1]; - MEMSET_BZERO(bits, sizeof(bits)); + explicit_bzero(bits, sizeof(bits)); i = 0; bi = 0; while (mnemonic[i]) { j = 0; @@ -241,7 +240,7 @@ void mnemonic_to_seed(const char *mnemonic, const char *passphrase, uint8_t seed } } pbkdf2_hmac_sha512_Final(&pctx, seed); - MEMSET_BZERO(salt, sizeof(salt)); + explicit_bzero(salt, sizeof(salt)); #if USE_BIP39_CACHE // store to cache if (mnemoniclen < 256 && passphraselen < 64) { diff --git a/blake2b.c b/blake2b.c index 93b4aba44..f59f41536 100644 --- a/blake2b.c +++ b/blake2b.c @@ -15,7 +15,6 @@ #include -#include "macros.h" #include "blake2b.h" #include "blake2_common.h" @@ -160,7 +159,7 @@ int blake2b_InitKey( blake2b_state *S, size_t outlen, const void *key, size_t ke memset( block, 0, BLAKE2B_BLOCKBYTES ); memcpy( block, key, keylen ); blake2b_Update( S, block, BLAKE2B_BLOCKBYTES ); - MEMSET_BZERO( block, BLAKE2B_BLOCKBYTES ); /* Burn the key from stack */ + explicit_bzero( block, BLAKE2B_BLOCKBYTES ); /* Burn the key from stack */ } return 0; } @@ -280,7 +279,7 @@ int blake2b_Final( blake2b_state *S, void *out, size_t outlen ) store64( buffer + sizeof( S->h[i] ) * i, S->h[i] ); memcpy( out, buffer, S->outlen ); - MEMSET_BZERO(buffer, sizeof(buffer)); + explicit_bzero(buffer, sizeof(buffer)); return 0; } diff --git a/blake2s.c b/blake2s.c index c1ad548e2..e64b6504d 100644 --- a/blake2s.c +++ b/blake2s.c @@ -15,7 +15,6 @@ #include -#include "macros.h" #include "blake2s.h" #include "blake2_common.h" @@ -154,7 +153,7 @@ int blake2s_InitKey( blake2s_state *S, size_t outlen, const void *key, size_t ke memset( block, 0, BLAKE2S_BLOCKBYTES ); memcpy( block, key, keylen ); blake2s_Update( S, block, BLAKE2S_BLOCKBYTES ); - MEMSET_BZERO( block, BLAKE2S_BLOCKBYTES ); /* Burn the key from stack */ + explicit_bzero( block, BLAKE2S_BLOCKBYTES ); /* Burn the key from stack */ } return 0; } @@ -272,7 +271,7 @@ int blake2s_Final( blake2s_state *S, void *out, size_t outlen ) store32( buffer + sizeof( S->h[i] ) * i, S->h[i] ); memcpy( out, buffer, outlen ); - MEMSET_BZERO(buffer, sizeof(buffer)); + explicit_bzero(buffer, sizeof(buffer)); return 0; } diff --git a/ecdsa.c b/ecdsa.c index 28e4ce310..2d1e5cf76 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -35,7 +35,6 @@ #include "hmac.h" #include "ecdsa.h" #include "base58.h" -#include "macros.h" #include "secp256k1.h" #include "rfc6979.h" @@ -542,8 +541,8 @@ void point_multiply(const ecdsa_curve *curve, const bignum256 *k, const curve_po } conditional_negate(sign, &jres.z, prime); jacobian_to_curve(&jres, res, prime); - MEMSET_BZERO(&a, sizeof(a)); - MEMSET_BZERO(&jres, sizeof(jres)); + explicit_bzero(&a, sizeof(a)); + explicit_bzero(&jres, sizeof(jres)); } #if USE_PRECOMPUTED_CP @@ -630,8 +629,8 @@ void scalar_multiply(const ecdsa_curve *curve, const bignum256 *k, curve_point * } conditional_negate(((a.val[0] >> 4) & 1) - 1, &jres.y, prime); jacobian_to_curve(&jres, res, prime); - MEMSET_BZERO(&a, sizeof(a)); - MEMSET_BZERO(&jres, sizeof(jres)); + explicit_bzero(&a, sizeof(a)); + explicit_bzero(&jres, sizeof(jres)); } #else @@ -653,12 +652,12 @@ int ecdh_multiply(const ecdsa_curve *curve, const uint8_t *priv_key, const uint8 bignum256 k; bn_read_be(priv_key, &k); point_multiply(curve, &k, &point, &point); - MEMSET_BZERO(&k, sizeof(k)); + explicit_bzero(&k, sizeof(k)); session_key[0] = 0x04; bn_write_be(&point.x, session_key + 1); bn_write_be(&point.y, session_key + 33); - MEMSET_BZERO(&point, sizeof(point)); + explicit_bzero(&point, sizeof(point)); return 0; } @@ -685,8 +684,8 @@ void init_rfc6979(const uint8_t *priv_key, const uint8_t *hash, rfc6979_state *s hmac_sha256(state->k, sizeof(state->k), buf, sizeof(buf), state->k); hmac_sha256(state->k, sizeof(state->k), state->v, sizeof(state->v), state->v); - MEMSET_BZERO(bx, sizeof(bx)); - MEMSET_BZERO(buf, sizeof(buf)); + explicit_bzero(bx, sizeof(bx)); + explicit_bzero(buf, sizeof(buf)); } // generate next number from deterministic random number generator @@ -700,7 +699,7 @@ void generate_rfc6979(uint8_t rnd[32], rfc6979_state *state) hmac_sha256(state->k, sizeof(state->k), buf, sizeof(state->v) + 1, state->k); hmac_sha256(state->k, sizeof(state->k), state->v, sizeof(state->v), state->v); memcpy(rnd, buf, 32); - MEMSET_BZERO(buf, sizeof(buf)); + explicit_bzero(buf, sizeof(buf)); } // generate K in a deterministic way, according to RFC6979 @@ -710,7 +709,7 @@ void generate_k_rfc6979(bignum256 *k, rfc6979_state *state) uint8_t buf[32]; generate_rfc6979(buf, state); bn_read_be(buf, k); - MEMSET_BZERO(buf, sizeof(buf)); + explicit_bzero(buf, sizeof(buf)); } // msg is a data to be signed @@ -720,7 +719,7 @@ int ecdsa_sign(const ecdsa_curve *curve, HasherType hasher_type, const uint8_t * uint8_t hash[32]; hasher_Raw(hasher_type, msg, msg_len, hash); int res = ecdsa_sign_digest(curve, priv_key, hash, sig, pby, is_canonical); - MEMSET_BZERO(hash, sizeof(hash)); + explicit_bzero(hash, sizeof(hash)); return res; } @@ -733,7 +732,7 @@ int ecdsa_sign_double(const ecdsa_curve *curve, HasherType hasher_type, const ui hasher_Raw(hasher_type, msg, msg_len, hash); hasher_Raw(hasher_type, hash, 32, hash); int res = ecdsa_sign_digest(curve, priv_key, hash, sig, pby, is_canonical); - MEMSET_BZERO(hash, sizeof(hash)); + explicit_bzero(hash, sizeof(hash)); return res; } @@ -818,20 +817,20 @@ int ecdsa_sign_digest(const ecdsa_curve *curve, const uint8_t *priv_key, const u *pby = by; } - MEMSET_BZERO(&k, sizeof(k)); - MEMSET_BZERO(&randk, sizeof(randk)); + explicit_bzero(&k, sizeof(k)); + explicit_bzero(&randk, sizeof(randk)); #if USE_RFC6979 - MEMSET_BZERO(&rng, sizeof(rng)); + explicit_bzero(&rng, sizeof(rng)); #endif return 0; } // Too many retries without a valid signature // -> fail with an error - MEMSET_BZERO(&k, sizeof(k)); - MEMSET_BZERO(&randk, sizeof(randk)); + explicit_bzero(&k, sizeof(k)); + explicit_bzero(&randk, sizeof(randk)); #if USE_RFC6979 - MEMSET_BZERO(&rng, sizeof(rng)); + explicit_bzero(&rng, sizeof(rng)); #endif return -1; } @@ -846,8 +845,8 @@ void ecdsa_get_public_key33(const ecdsa_curve *curve, const uint8_t *priv_key, u scalar_multiply(curve, &k, &R); pub_key[0] = 0x02 | (R.y.val[0] & 0x01); bn_write_be(&R.x, pub_key + 1); - MEMSET_BZERO(&R, sizeof(R)); - MEMSET_BZERO(&k, sizeof(k)); + explicit_bzero(&R, sizeof(R)); + explicit_bzero(&k, sizeof(k)); } void ecdsa_get_public_key65(const ecdsa_curve *curve, const uint8_t *priv_key, uint8_t *pub_key) @@ -861,8 +860,8 @@ void ecdsa_get_public_key65(const ecdsa_curve *curve, const uint8_t *priv_key, u pub_key[0] = 0x04; bn_write_be(&R.x, pub_key + 1); bn_write_be(&R.y, pub_key + 33); - MEMSET_BZERO(&R, sizeof(R)); - MEMSET_BZERO(&k, sizeof(k)); + explicit_bzero(&R, sizeof(R)); + explicit_bzero(&k, sizeof(k)); } int ecdsa_uncompress_pubkey(const ecdsa_curve *curve, const uint8_t *pub_key, uint8_t *uncompressed) @@ -891,7 +890,7 @@ void ecdsa_get_pubkeyhash(const uint8_t *pub_key, HasherType hasher_type, uint8_ hasher_Raw(hasher_type, pub_key, 33, h); } ripemd160(h, HASHER_DIGEST_LENGTH, pubkeyhash); - MEMSET_BZERO(h, sizeof(h)); + explicit_bzero(h, sizeof(h)); } void ecdsa_get_address_raw(const uint8_t *pub_key, uint32_t version, HasherType hasher_type, uint8_t *addr_raw) @@ -908,7 +907,7 @@ void ecdsa_get_address(const uint8_t *pub_key, uint32_t version, HasherType hash ecdsa_get_address_raw(pub_key, version, hasher_type, raw); base58_encode_check(raw, 20 + prefix_len, hasher_type, addr, addrsize); // not as important to clear this one, but we might as well - MEMSET_BZERO(raw, sizeof(raw)); + explicit_bzero(raw, sizeof(raw)); } void ecdsa_get_address_segwit_p2sh_raw(const uint8_t *pub_key, uint32_t version, HasherType hasher_type, uint8_t *addr_raw) @@ -929,7 +928,7 @@ void ecdsa_get_address_segwit_p2sh(const uint8_t *pub_key, uint32_t version, Has size_t prefix_len = address_prefix_bytes_len(version); ecdsa_get_address_segwit_p2sh_raw(pub_key, version, hasher_type, raw); base58_encode_check(raw, prefix_len + 20, hasher_type, addr, addrsize); - MEMSET_BZERO(raw, sizeof(raw)); + explicit_bzero(raw, sizeof(raw)); } void ecdsa_get_wif(const uint8_t *priv_key, uint32_t version, HasherType hasher_type, char *wif, int wifsize) @@ -941,7 +940,7 @@ void ecdsa_get_wif(const uint8_t *priv_key, uint32_t version, HasherType hasher_ wif_raw[prefix_len + 32] = 0x01; base58_encode_check(wif_raw, prefix_len + 32 + 1, hasher_type, wif, wifsize); // private keys running around our stack can cause trouble - MEMSET_BZERO(wif_raw, sizeof(wif_raw)); + explicit_bzero(wif_raw, sizeof(wif_raw)); } int ecdsa_address_decode(const char *addr, uint32_t version, HasherType hasher_type, uint8_t *out) @@ -1034,7 +1033,7 @@ int ecdsa_verify(const ecdsa_curve *curve, HasherType hasher_type, const uint8_t uint8_t hash[32]; hasher_Raw(hasher_type, msg, msg_len, hash); int res = ecdsa_verify_digest(curve, pub_key, sig, hash); - MEMSET_BZERO(hash, sizeof(hash)); + explicit_bzero(hash, sizeof(hash)); return res; } @@ -1044,7 +1043,7 @@ int ecdsa_verify_double(const ecdsa_curve *curve, HasherType hasher_type, const hasher_Raw(hasher_type, msg, msg_len, hash); hasher_Raw(hasher_type, hash, 32, hash); int res = ecdsa_verify_digest(curve, pub_key, sig, hash); - MEMSET_BZERO(hash, sizeof(hash)); + explicit_bzero(hash, sizeof(hash)); return res; } @@ -1143,11 +1142,11 @@ int ecdsa_verify_digest(const ecdsa_curve *curve, const uint8_t *pub_key, const } } - MEMSET_BZERO(&pub, sizeof(pub)); - MEMSET_BZERO(&res, sizeof(res)); - MEMSET_BZERO(&r, sizeof(r)); - MEMSET_BZERO(&s, sizeof(s)); - MEMSET_BZERO(&z, sizeof(z)); + explicit_bzero(&pub, sizeof(pub)); + explicit_bzero(&res, sizeof(res)); + explicit_bzero(&r, sizeof(r)); + explicit_bzero(&s, sizeof(s)); + explicit_bzero(&z, sizeof(z)); // all OK return result; diff --git a/hmac.c b/hmac.c index 03af92cdb..ff462c37f 100644 --- a/hmac.c +++ b/hmac.c @@ -25,7 +25,6 @@ #include "hmac.h" #include "options.h" -#include "macros.h" void hmac_sha256_Init(HMAC_SHA256_CTX *hctx, const uint8_t *key, const uint32_t keylen) { @@ -42,7 +41,7 @@ void hmac_sha256_Init(HMAC_SHA256_CTX *hctx, const uint8_t *key, const uint32_t } sha256_Init(&(hctx->ctx)); sha256_Update(&(hctx->ctx), i_key_pad, SHA256_BLOCK_LENGTH); - MEMSET_BZERO(i_key_pad, sizeof(i_key_pad)); + explicit_bzero(i_key_pad, sizeof(i_key_pad)); } void hmac_sha256_Update(HMAC_SHA256_CTX *hctx, const uint8_t *msg, const uint32_t msglen) @@ -57,7 +56,7 @@ void hmac_sha256_Final(HMAC_SHA256_CTX *hctx, uint8_t *hmac) sha256_Update(&(hctx->ctx), hctx->o_key_pad, SHA256_BLOCK_LENGTH); sha256_Update(&(hctx->ctx), hmac, SHA256_DIGEST_LENGTH); sha256_Final(&(hctx->ctx), hmac); - MEMSET_BZERO(hctx, sizeof(HMAC_SHA256_CTX)); + explicit_bzero(hctx, sizeof(HMAC_SHA256_CTX)); } void hmac_sha256(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, const uint32_t msglen, uint8_t *hmac) @@ -72,7 +71,7 @@ void hmac_sha256_prepare(const uint8_t *key, const uint32_t keylen, uint32_t *op { static CONFIDENTIAL uint32_t key_pad[SHA256_BLOCK_LENGTH/sizeof(uint32_t)]; - MEMSET_BZERO(key_pad, sizeof(key_pad)); + explicit_bzero(key_pad, sizeof(key_pad)); if (keylen > SHA256_BLOCK_LENGTH) { static CONFIDENTIAL SHA256_CTX context; sha256_Init(&context); @@ -99,7 +98,7 @@ void hmac_sha256_prepare(const uint8_t *key, const uint32_t keylen, uint32_t *op key_pad[i] = key_pad[i] ^ 0x5c5c5c5c ^ 0x36363636; } sha256_Transform(sha256_initial_hash_value, key_pad, ipad_digest); - MEMSET_BZERO(key_pad, sizeof(key_pad)); + explicit_bzero(key_pad, sizeof(key_pad)); } void hmac_sha512_Init(HMAC_SHA512_CTX *hctx, const uint8_t *key, const uint32_t keylen) @@ -117,7 +116,7 @@ void hmac_sha512_Init(HMAC_SHA512_CTX *hctx, const uint8_t *key, const uint32_t } sha512_Init(&(hctx->ctx)); sha512_Update(&(hctx->ctx), i_key_pad, SHA512_BLOCK_LENGTH); - MEMSET_BZERO(i_key_pad, sizeof(i_key_pad)); + explicit_bzero(i_key_pad, sizeof(i_key_pad)); } void hmac_sha512_Update(HMAC_SHA512_CTX *hctx, const uint8_t *msg, const uint32_t msglen) @@ -132,7 +131,7 @@ void hmac_sha512_Final(HMAC_SHA512_CTX *hctx, uint8_t *hmac) sha512_Update(&(hctx->ctx), hctx->o_key_pad, SHA512_BLOCK_LENGTH); sha512_Update(&(hctx->ctx), hmac, SHA512_DIGEST_LENGTH); sha512_Final(&(hctx->ctx), hmac); - MEMSET_BZERO(hctx, sizeof(HMAC_SHA512_CTX)); + explicit_bzero(hctx, sizeof(HMAC_SHA512_CTX)); } void hmac_sha512(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, const uint32_t msglen, uint8_t *hmac) @@ -147,7 +146,7 @@ void hmac_sha512_prepare(const uint8_t *key, const uint32_t keylen, uint64_t *op { static CONFIDENTIAL uint64_t key_pad[SHA512_BLOCK_LENGTH/sizeof(uint64_t)]; - MEMSET_BZERO(key_pad, sizeof(key_pad)); + explicit_bzero(key_pad, sizeof(key_pad)); if (keylen > SHA512_BLOCK_LENGTH) { static CONFIDENTIAL SHA512_CTX context; sha512_Init(&context); @@ -174,5 +173,5 @@ void hmac_sha512_prepare(const uint8_t *key, const uint32_t keylen, uint64_t *op key_pad[i] = key_pad[i] ^ 0x5c5c5c5c5c5c5c5c ^ 0x3636363636363636; } sha512_Transform(sha512_initial_hash_value, key_pad, ipad_digest); - MEMSET_BZERO(key_pad, sizeof(key_pad)); + explicit_bzero(key_pad, sizeof(key_pad)); } diff --git a/macros.h b/macros.h deleted file mode 100644 index 041289e7c..000000000 --- a/macros.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef __MACROS_H__ -#define __MACROS_H__ - -#define MEMSET_BZERO(p,l) memset((p), 0, (l)) - -#endif diff --git a/nem.c b/nem.c index f70076498..4b226a1c8 100644 --- a/nem.c +++ b/nem.c @@ -26,7 +26,6 @@ #include "base32.h" #include "ed25519-donna/ed25519-keccak.h" -#include "macros.h" #include "ripemd160.h" #include "sha3.h" @@ -112,7 +111,7 @@ void nem_get_address_raw(const ed25519_public_key public_key, uint8_t version, u /* 5. Concatenate output of step 3 and the checksum from step 4 */ memcpy(&address[1 + RIPEMD160_DIGEST_LENGTH], hash, 4); - MEMSET_BZERO(hash, sizeof(hash)); + explicit_bzero(hash, sizeof(hash)); } bool nem_get_address(const ed25519_public_key public_key, uint8_t version, char *address) { @@ -122,7 +121,7 @@ bool nem_get_address(const ed25519_public_key public_key, uint8_t version, char char *ret = base32_encode(pubkeyhash, sizeof(pubkeyhash), address, NEM_ADDRESS_SIZE + 1, BASE32_ALPHABET_RFC4648); - MEMSET_BZERO(pubkeyhash, sizeof(pubkeyhash)); + explicit_bzero(pubkeyhash, sizeof(pubkeyhash)); return (ret != NULL); } @@ -136,7 +135,7 @@ bool nem_validate_address_raw(const uint8_t *address, uint8_t network) { keccak_256(address, 1 + RIPEMD160_DIGEST_LENGTH, hash); bool valid = (memcmp(&address[1 + RIPEMD160_DIGEST_LENGTH], hash, 4) == 0); - MEMSET_BZERO(hash, sizeof(hash)); + explicit_bzero(hash, sizeof(hash)); return valid; } @@ -150,7 +149,7 @@ bool nem_validate_address(const char *address, uint8_t network) { uint8_t *ret = base32_decode(address, NEM_ADDRESS_SIZE, pubkeyhash, sizeof(pubkeyhash), BASE32_ALPHABET_RFC4648); bool valid = (ret != NULL) && nem_validate_address_raw(pubkeyhash, network); - MEMSET_BZERO(pubkeyhash, sizeof(pubkeyhash)); + explicit_bzero(pubkeyhash, sizeof(pubkeyhash)); return valid; } diff --git a/pbkdf2.c b/pbkdf2.c index db3e997d5..f94ef368b 100644 --- a/pbkdf2.c +++ b/pbkdf2.c @@ -25,7 +25,6 @@ #include "pbkdf2.h" #include "hmac.h" #include "sha2.h" -#include "macros.h" void pbkdf2_hmac_sha256_Init(PBKDF2_HMAC_SHA256_CTX *pctx, const uint8_t *pass, int passlen, const uint8_t *salt, int saltlen) { @@ -75,7 +74,7 @@ void pbkdf2_hmac_sha256_Final(PBKDF2_HMAC_SHA256_CTX *pctx, uint8_t *key) } #endif memcpy(key, pctx->f, SHA256_DIGEST_LENGTH); - MEMSET_BZERO(pctx, sizeof(PBKDF2_HMAC_SHA256_CTX)); + explicit_bzero(pctx, sizeof(PBKDF2_HMAC_SHA256_CTX)); } void pbkdf2_hmac_sha256(const uint8_t *pass, int passlen, const uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key) @@ -135,7 +134,7 @@ void pbkdf2_hmac_sha512_Final(PBKDF2_HMAC_SHA512_CTX *pctx, uint8_t *key) } #endif memcpy(key, pctx->f, SHA512_DIGEST_LENGTH); - MEMSET_BZERO(pctx, sizeof(PBKDF2_HMAC_SHA512_CTX)); + explicit_bzero(pctx, sizeof(PBKDF2_HMAC_SHA512_CTX)); } void pbkdf2_hmac_sha512(const uint8_t *pass, int passlen, const uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key) diff --git a/rfc6979.c b/rfc6979.c index c6e50a484..1168645e6 100644 --- a/rfc6979.c +++ b/rfc6979.c @@ -48,8 +48,8 @@ void init_rfc6979(const uint8_t *priv_key, const uint8_t *hash, rfc6979_state *s hmac_sha256(state->k, sizeof(state->k), buf, sizeof(buf), state->k); hmac_sha256(state->k, sizeof(state->k), state->v, sizeof(state->v), state->v); - MEMSET_BZERO(bx, sizeof(bx)); - MEMSET_BZERO(buf, sizeof(buf)); + explicit_bzero(bx, sizeof(bx)); + explicit_bzero(buf, sizeof(buf)); } // generate next number from deterministic random number generator @@ -63,7 +63,7 @@ void generate_rfc6979(uint8_t rnd[32], rfc6979_state *state) hmac_sha256(state->k, sizeof(state->k), buf, sizeof(state->v) + 1, state->k); hmac_sha256(state->k, sizeof(state->k), state->v, sizeof(state->v), state->v); memcpy(rnd, buf, 32); - MEMSET_BZERO(buf, sizeof(buf)); + explicit_bzero(buf, sizeof(buf)); } // generate K in a deterministic way, according to RFC6979 @@ -73,5 +73,5 @@ void generate_k_rfc6979(bignum256 *k, rfc6979_state *state) uint8_t buf[32]; generate_rfc6979(buf, state); bn_read_be(buf, k); - MEMSET_BZERO(buf, sizeof(buf)); + explicit_bzero(buf, sizeof(buf)); } diff --git a/ripemd160.c b/ripemd160.c index 6a62279c4..fb65f71b2 100644 --- a/ripemd160.c +++ b/ripemd160.c @@ -28,7 +28,6 @@ #include #include "ripemd160.h" -#include "macros.h" /* * 32-bit integer manipulation macros (little endian) @@ -328,7 +327,7 @@ void ripemd160_Final( RIPEMD160_CTX *ctx, uint8_t output[RIPEMD160_DIGEST_LENGTH PUT_UINT32_LE( ctx->state[3], output, 12 ); PUT_UINT32_LE( ctx->state[4], output, 16 ); - MEMSET_BZERO(ctx, sizeof(RIPEMD160_CTX)); + explicit_bzero(ctx, sizeof(RIPEMD160_CTX)); } /* diff --git a/sha2.c b/sha2.c index f6ca3072c..1b399e947 100644 --- a/sha2.c +++ b/sha2.c @@ -108,7 +108,6 @@ typedef uint64_t sha2_word64; /* Exactly 8 bytes */ } \ } -#define MEMSET_BZERO(p,l) memset((p), 0, (l)) #define MEMCPY_BCOPY(d,s,l) memcpy((d), (s), (l)) /*** THE SIX LOGICAL FUNCTIONS ****************************************/ @@ -282,7 +281,7 @@ static const char *sha2_hex_digits = "0123456789abcdef"; /*** SHA-1: ***********************************************************/ void sha1_Init(SHA1_CTX* context) { MEMCPY_BCOPY(context->state, sha1_initial_hash_value, SHA1_DIGEST_LENGTH); - MEMSET_BZERO(context->buffer, SHA1_BLOCK_LENGTH); + explicit_bzero(context->buffer, SHA1_BLOCK_LENGTH); context->bitcount = 0; } @@ -592,14 +591,14 @@ void sha1_Final(SHA1_CTX* context, sha2_byte digest[]) { * No digest buffer, so we can do nothing * except clean up and go home */ - MEMSET_BZERO(context, sizeof(SHA1_CTX)); + explicit_bzero(context, sizeof(SHA1_CTX)); return; } usedspace = (context->bitcount >> 3) % SHA1_BLOCK_LENGTH; if (usedspace == 0) { /* Set-up for the last transform: */ - MEMSET_BZERO(context->buffer, SHA1_SHORT_BLOCK_LENGTH); + explicit_bzero(context->buffer, SHA1_SHORT_BLOCK_LENGTH); /* Begin padding with a 1 bit: */ *context->buffer = 0x80; @@ -609,16 +608,16 @@ void sha1_Final(SHA1_CTX* context, sha2_byte digest[]) { if (usedspace <= 56) { /* Set-up for the last transform: */ - MEMSET_BZERO(((uint8_t*)context->buffer) + usedspace, 56 - usedspace); + explicit_bzero(((uint8_t*)context->buffer) + usedspace, 56 - usedspace); } else { if (usedspace < 64) { - MEMSET_BZERO(((uint8_t*)context->buffer) + usedspace, 64 - usedspace); + explicit_bzero(((uint8_t*)context->buffer) + usedspace, 64 - usedspace); } /* Do second-to-last transform: */ sha1_Transform(context->state, context->buffer, context->state); /* And set-up for the last transform: */ - MEMSET_BZERO(context->buffer, 56); + explicit_bzero(context->buffer, 56); } /* Clean up: */ usedspace = 0; @@ -649,7 +648,7 @@ void sha1_Final(SHA1_CTX* context, sha2_byte digest[]) { #endif /* Clean up: */ - MEMSET_BZERO(context, sizeof(SHA1_CTX)); + explicit_bzero(context, sizeof(SHA1_CTX)); } char *sha1_End(SHA1_CTX* context, char buffer[]) { @@ -666,9 +665,9 @@ char *sha1_End(SHA1_CTX* context, char buffer[]) { } *buffer = (char)0; } else { - MEMSET_BZERO(context, sizeof(SHA1_CTX)); + explicit_bzero(context, sizeof(SHA1_CTX)); } - MEMSET_BZERO(digest, SHA1_DIGEST_LENGTH); + explicit_bzero(digest, SHA1_DIGEST_LENGTH); return buffer; } @@ -693,7 +692,7 @@ void sha256_Init(SHA256_CTX* context) { return; } MEMCPY_BCOPY(context->state, sha256_initial_hash_value, SHA256_DIGEST_LENGTH); - MEMSET_BZERO(context->buffer, SHA256_BLOCK_LENGTH); + explicit_bzero(context->buffer, SHA256_BLOCK_LENGTH); context->bitcount = 0; } @@ -930,7 +929,7 @@ void sha256_Final(SHA256_CTX* context, sha2_byte digest[]) { ((uint8_t*)context->buffer)[usedspace++] = 0x80; if (usedspace > SHA256_SHORT_BLOCK_LENGTH) { - MEMSET_BZERO(((uint8_t*)context->buffer) + usedspace, SHA256_BLOCK_LENGTH - usedspace); + explicit_bzero(((uint8_t*)context->buffer) + usedspace, SHA256_BLOCK_LENGTH - usedspace); #if BYTE_ORDER == LITTLE_ENDIAN /* Convert TO host byte order */ @@ -945,7 +944,7 @@ void sha256_Final(SHA256_CTX* context, sha2_byte digest[]) { usedspace = 0; } /* Set-up for the last transform: */ - MEMSET_BZERO(((uint8_t*)context->buffer) + usedspace, SHA256_SHORT_BLOCK_LENGTH - usedspace); + explicit_bzero(((uint8_t*)context->buffer) + usedspace, SHA256_SHORT_BLOCK_LENGTH - usedspace); #if BYTE_ORDER == LITTLE_ENDIAN /* Convert TO host byte order */ @@ -970,7 +969,7 @@ void sha256_Final(SHA256_CTX* context, sha2_byte digest[]) { } /* Clean up state data: */ - MEMSET_BZERO(context, sizeof(SHA256_CTX)); + explicit_bzero(context, sizeof(SHA256_CTX)); usedspace = 0; } @@ -988,9 +987,9 @@ char *sha256_End(SHA256_CTX* context, char buffer[]) { } *buffer = (char)0; } else { - MEMSET_BZERO(context, sizeof(SHA256_CTX)); + explicit_bzero(context, sizeof(SHA256_CTX)); } - MEMSET_BZERO(digest, SHA256_DIGEST_LENGTH); + explicit_bzero(digest, SHA256_DIGEST_LENGTH); return buffer; } @@ -1016,7 +1015,7 @@ void sha512_Init(SHA512_CTX* context) { return; } MEMCPY_BCOPY(context->state, sha512_initial_hash_value, SHA512_DIGEST_LENGTH); - MEMSET_BZERO(context->buffer, SHA512_BLOCK_LENGTH); + explicit_bzero(context->buffer, SHA512_BLOCK_LENGTH); context->bitcount[0] = context->bitcount[1] = 0; } @@ -1233,7 +1232,7 @@ static void sha512_Last(SHA512_CTX* context) { ((uint8_t*)context->buffer)[usedspace++] = 0x80; if (usedspace > SHA512_SHORT_BLOCK_LENGTH) { - MEMSET_BZERO(((uint8_t*)context->buffer) + usedspace, SHA512_BLOCK_LENGTH - usedspace); + explicit_bzero(((uint8_t*)context->buffer) + usedspace, SHA512_BLOCK_LENGTH - usedspace); #if BYTE_ORDER == LITTLE_ENDIAN /* Convert TO host byte order */ @@ -1248,7 +1247,7 @@ static void sha512_Last(SHA512_CTX* context) { usedspace = 0; } /* Set-up for the last transform: */ - MEMSET_BZERO(((uint8_t*)context->buffer) + usedspace, SHA512_SHORT_BLOCK_LENGTH - usedspace); + explicit_bzero(((uint8_t*)context->buffer) + usedspace, SHA512_SHORT_BLOCK_LENGTH - usedspace); #if BYTE_ORDER == LITTLE_ENDIAN /* Convert TO host byte order */ @@ -1280,7 +1279,7 @@ void sha512_Final(SHA512_CTX* context, sha2_byte digest[]) { } /* Zero out state data */ - MEMSET_BZERO(context, sizeof(SHA512_CTX)); + explicit_bzero(context, sizeof(SHA512_CTX)); } char *sha512_End(SHA512_CTX* context, char buffer[]) { @@ -1297,9 +1296,9 @@ char *sha512_End(SHA512_CTX* context, char buffer[]) { } *buffer = (char)0; } else { - MEMSET_BZERO(context, sizeof(SHA512_CTX)); + explicit_bzero(context, sizeof(SHA512_CTX)); } - MEMSET_BZERO(digest, SHA512_DIGEST_LENGTH); + explicit_bzero(digest, SHA512_DIGEST_LENGTH); return buffer; } diff --git a/sha3.c b/sha3.c index 9da744d4d..bba56326a 100644 --- a/sha3.c +++ b/sha3.c @@ -21,7 +21,6 @@ #include #include "sha3.h" -#include "macros.h" #define I64(x) x##LL #define ROTL64(qword, n) ((qword) << (n) ^ ((qword) >> (64 - (n)))) @@ -331,7 +330,7 @@ void sha3_Final(SHA3_CTX *ctx, unsigned char* result) assert(block_size > digest_length); if (result) me64_to_le_str(result, ctx->hash, digest_length); - MEMSET_BZERO(ctx, sizeof(SHA3_CTX)); + explicit_bzero(ctx, sizeof(SHA3_CTX)); } #if USE_KECCAK @@ -360,7 +359,7 @@ void keccak_Final(SHA3_CTX *ctx, unsigned char* result) assert(block_size > digest_length); if (result) me64_to_le_str(result, ctx->hash, digest_length); - MEMSET_BZERO(ctx, sizeof(SHA3_CTX)); + explicit_bzero(ctx, sizeof(SHA3_CTX)); } void keccak_256(const unsigned char* data, size_t len, unsigned char* digest) From bb4c3d052561bd31856a03d975ca226571f6a893 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 18 Jan 2018 15:18:09 +0100 Subject: [PATCH 527/627] introduce and use memzero instead of explicit_bzero --- Makefile | 1 + base58.c | 5 ++-- bignum.c | 13 ++++++----- bip32.c | 49 ++++++++++++++++++++------------------- bip39.c | 13 ++++++----- blake2b.c | 5 ++-- blake2s.c | 5 ++-- ecdsa.c | 67 +++++++++++++++++++++++++++-------------------------- hmac.c | 17 +++++++------- memzero.c | 6 +++++ memzero.h | 8 +++++++ nem.c | 9 +++---- pbkdf2.c | 5 ++-- rfc6979.c | 9 +++---- ripemd160.c | 3 ++- sha2.c | 43 +++++++++++++++++----------------- sha3.c | 5 ++-- 17 files changed, 146 insertions(+), 117 deletions(-) create mode 100644 memzero.c create mode 100644 memzero.h diff --git a/Makefile b/Makefile index b1b90259c..65b77a26d 100644 --- a/Makefile +++ b/Makefile @@ -50,6 +50,7 @@ SRCS += chacha20poly1305/chacha20poly1305.c chacha20poly1305/chacha_merged.c ch SRCS += rc4.c SRCS += nem.c SRCS += segwit_addr.c +SRCS += memzero.c OBJS = $(SRCS:.c=.o) diff --git a/base58.c b/base58.c index 7ca8b013f..c3e960690 100644 --- a/base58.c +++ b/base58.c @@ -27,6 +27,7 @@ #include "base58.h" #include "sha2.h" #include "ripemd160.h" +#include "memzero.h" static const int8_t b58digits_map[] = { -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, @@ -199,7 +200,7 @@ int base58_encode_check(const uint8_t *data, int datalen, HasherType hasher_type hasher_Raw(hasher_type, hash, 32, hash); size_t res = strsize; bool success = b58enc(str, &res, buf, datalen + 4); - explicit_bzero(buf, sizeof(buf)); + memzero(buf, sizeof(buf)); return success ? res : 0; } @@ -253,7 +254,7 @@ int base58gph_encode_check(const uint8_t *data, int datalen, char *str, int strs ripemd160(data, datalen, hash); // No double SHA256, but a single RIPEMD160 size_t res = strsize; bool success = b58enc(str, &res, buf, datalen + 4); - explicit_bzero(buf, sizeof(buf)); + memzero(buf, sizeof(buf)); return success ? res : 0; } diff --git a/bignum.c b/bignum.c index 803fd7836..27e361d67 100644 --- a/bignum.c +++ b/bignum.c @@ -27,6 +27,7 @@ #include #include #include "bignum.h" +#include "memzero.h" /* big number library */ @@ -489,7 +490,7 @@ void bn_multiply(const bignum256 *k, bignum256 *x, const bignum256 *prime) uint32_t res[18] = {0}; bn_multiply_long(k, x, res); bn_multiply_reduce(x, res, prime); - explicit_bzero(res, sizeof(res)); + memzero(res, sizeof(res)); } // partly reduce x modulo prime @@ -551,8 +552,8 @@ void bn_sqrt(bignum256 *x, const bignum256 *prime) } bn_mod(&res, prime); memcpy(x, &res, sizeof(bignum256)); - explicit_bzero(&res, sizeof(res)); - explicit_bzero(&p, sizeof(p)); + memzero(&res, sizeof(res)); + memzero(&p, sizeof(p)); } #if ! USE_INVERSE_FAST @@ -860,9 +861,9 @@ void bn_inverse(bignum256 *x, const bignum256 *prime) x->val[i] = temp32; // let's wipe all temp buffers - explicit_bzero(pp, sizeof(pp)); - explicit_bzero(&us, sizeof(us)); - explicit_bzero(&vr, sizeof(vr)); + memzero(pp, sizeof(pp)); + memzero(&us, sizeof(us)); + memzero(&vr, sizeof(vr)); } #endif diff --git a/bip32.c b/bip32.c index 1f22f193a..fbccb9717 100644 --- a/bip32.c +++ b/bip32.c @@ -46,6 +46,7 @@ #if USE_NEM #include "nem.h" #endif +#include "memzero.h" const curve_info ed25519_info = { .bip32_name = "ed25519 seed", @@ -86,7 +87,7 @@ int hdnode_from_xpub(uint32_t depth, uint32_t child_num, const uint8_t *chain_co out->depth = depth; out->child_num = child_num; memcpy(out->chain_code, chain_code, 32); - explicit_bzero(out->private_key, 32); + memzero(out->private_key, 32); memcpy(out->public_key, public_key, 33); return 1; } @@ -107,7 +108,7 @@ int hdnode_from_xprv(uint32_t depth, uint32_t child_num, const uint8_t *chain_co failed = true; } } - explicit_bzero(&a, sizeof(a)); + memzero(&a, sizeof(a)); } if (failed) { @@ -119,7 +120,7 @@ int hdnode_from_xprv(uint32_t depth, uint32_t child_num, const uint8_t *chain_co out->child_num = child_num; memcpy(out->chain_code, chain_code, 32); memcpy(out->private_key, private_key, 32); - explicit_bzero(out->public_key, sizeof(out->public_key)); + memzero(out->public_key, sizeof(out->public_key)); return 1; } @@ -150,12 +151,12 @@ int hdnode_from_seed(const uint8_t *seed, int seed_len, const char* curve, HDNod hmac_sha512_Update(&ctx, I, sizeof(I)); hmac_sha512_Final(&ctx, I); } - explicit_bzero(&a, sizeof(a)); + memzero(&a, sizeof(a)); } memcpy(out->private_key, I, 32); memcpy(out->chain_code, I + 32, 32); - explicit_bzero(out->public_key, sizeof(out->public_key)); - explicit_bzero(I, sizeof(I)); + memzero(out->public_key, sizeof(out->public_key)); + memzero(I, sizeof(I)); return 1; } @@ -168,7 +169,7 @@ uint32_t hdnode_fingerprint(HDNode *node) hasher_Raw(node->curve->hasher_type, node->public_key, 33, digest); ripemd160(digest, 32, digest); fingerprint = (digest[0] << 24) + (digest[1] << 16) + (digest[2] << 8) + digest[3]; - explicit_bzero(digest, sizeof(digest)); + memzero(digest, sizeof(digest)); return fingerprint; } @@ -229,13 +230,13 @@ int hdnode_private_ckd(HDNode *inout, uint32_t i) memcpy(inout->chain_code, I + 32, 32); inout->depth++; inout->child_num = i; - explicit_bzero(inout->public_key, sizeof(inout->public_key)); + memzero(inout->public_key, sizeof(inout->public_key)); // making sure to wipe our memory - explicit_bzero(&a, sizeof(a)); - explicit_bzero(&b, sizeof(b)); - explicit_bzero(I, sizeof(I)); - explicit_bzero(data, sizeof(data)); + memzero(&a, sizeof(a)); + memzero(&b, sizeof(b)); + memzero(I, sizeof(I)); + memzero(data, sizeof(data)); return 1; } @@ -264,9 +265,9 @@ int hdnode_public_ckd_cp(const ecdsa_curve *curve, const curve_point *parent, co } // Wipe all stack data. - explicit_bzero(data, sizeof(data)); - explicit_bzero(I, sizeof(I)); - explicit_bzero(&c, sizeof(c)); + memzero(data, sizeof(data)); + memzero(I, sizeof(I)); + memzero(&c, sizeof(c)); return 1; } } @@ -286,15 +287,15 @@ int hdnode_public_ckd(HDNode *inout, uint32_t i) if (!hdnode_public_ckd_cp(inout->curve->params, &parent, inout->chain_code, i, &child, inout->chain_code)) { return 0; } - explicit_bzero(inout->private_key, 32); + memzero(inout->private_key, 32); inout->depth++; inout->child_num = i; inout->public_key[0] = 0x02 | (child.y.val[0] & 0x01); bn_write_be(&child.x, inout->public_key + 1); // Wipe all stack data. - explicit_bzero(&parent, sizeof(parent)); - explicit_bzero(&child, sizeof(child)); + memzero(&parent, sizeof(parent)); + memzero(&child, sizeof(child)); return 1; } @@ -349,7 +350,7 @@ int hdnode_private_ckd_cached(HDNode *inout, const uint32_t *i, size_t i_count, if (!private_ckd_cache_root_set || memcmp(&private_ckd_cache_root, inout, sizeof(HDNode)) != 0) { // clear the cache private_ckd_cache_index = 0; - explicit_bzero(private_ckd_cache, sizeof(private_ckd_cache)); + memzero(private_ckd_cache, sizeof(private_ckd_cache)); // setup new root memcpy(&private_ckd_cache_root, inout, sizeof(HDNode)); private_ckd_cache_root_set = true; @@ -496,7 +497,7 @@ int hdnode_nem_encrypt(const HDNode *node, const ed25519_public_key public_key, aes_encrypt_ctx ctx; int ret = aes_encrypt_key256(shared_key, &ctx); - explicit_bzero(shared_key, sizeof(shared_key)); + memzero(shared_key, sizeof(shared_key)); if (ret != EXIT_SUCCESS) { return 0; @@ -523,7 +524,7 @@ int hdnode_nem_decrypt(const HDNode *node, const ed25519_public_key public_key, aes_decrypt_ctx ctx; int ret = aes_decrypt_key256(shared_key, &ctx); - explicit_bzero(shared_key, sizeof(shared_key)); + memzero(shared_key, sizeof(shared_key)); if (ret != EXIT_SUCCESS) { return 0; @@ -609,7 +610,7 @@ static int hdnode_serialize(const HDNode *node, uint32_t fingerprint, uint32_t v memcpy(node_data + 46, node->private_key, 32); } int ret = base58_encode_check(node_data, sizeof(node_data), node->curve->hasher_type, str, strsize); - explicit_bzero(node_data, sizeof(node_data)); + memzero(node_data, sizeof(node_data)); return ret; } @@ -634,14 +635,14 @@ int hdnode_deserialize(const char *str, uint32_t version_public, uint32_t versio } uint32_t version = read_be(node_data); if (version == version_public) { - explicit_bzero(node->private_key, sizeof(node->private_key)); + memzero(node->private_key, sizeof(node->private_key)); memcpy(node->public_key, node_data + 45, 33); } else if (version == version_private) { // private node if (node_data[45]) { // invalid data return -2; } memcpy(node->private_key, node_data + 46, 32); - explicit_bzero(node->public_key, sizeof(node->public_key)); + memzero(node->public_key, sizeof(node->public_key)); } else { return -3; // invalid version } diff --git a/bip39.c b/bip39.c index a9f43f1ec..b1bea4454 100644 --- a/bip39.c +++ b/bip39.c @@ -31,6 +31,7 @@ #include "pbkdf2.h" #include "bip39_english.h" #include "options.h" +#include "memzero.h" #if USE_BIP39_CACHE @@ -53,7 +54,7 @@ const char *mnemonic_generate(int strength) uint8_t data[32]; random_buffer(data, 32); const char *r = mnemonic_from_data(data, strength / 8); - explicit_bzero(data, sizeof(data)); + memzero(data, sizeof(data)); return r; } @@ -65,7 +66,7 @@ const uint16_t *mnemonic_generate_indexes(int strength) uint8_t data[32]; random_buffer(data, 32); const uint16_t *r = mnemonic_from_data_indexes(data, strength / 8); - explicit_bzero(data, sizeof(data)); + memzero(data, sizeof(data)); return r; } @@ -99,7 +100,7 @@ const char *mnemonic_from_data(const uint8_t *data, int len) *p = (i < mlen - 1) ? ' ' : 0; p++; } - explicit_bzero(bits, sizeof(bits)); + memzero(bits, sizeof(bits)); return mnemo; } @@ -130,7 +131,7 @@ const uint16_t *mnemonic_from_data_indexes(const uint8_t *data, int len) } mnemo[i] = idx; } - explicit_bzero(bits, sizeof(bits)); + memzero(bits, sizeof(bits)); return mnemo; } @@ -160,7 +161,7 @@ int mnemonic_check(const char *mnemonic) uint32_t j, k, ki, bi; uint8_t bits[32 + 1]; - explicit_bzero(bits, sizeof(bits)); + memzero(bits, sizeof(bits)); i = 0; bi = 0; while (mnemonic[i]) { j = 0; @@ -240,7 +241,7 @@ void mnemonic_to_seed(const char *mnemonic, const char *passphrase, uint8_t seed } } pbkdf2_hmac_sha512_Final(&pctx, seed); - explicit_bzero(salt, sizeof(salt)); + memzero(salt, sizeof(salt)); #if USE_BIP39_CACHE // store to cache if (mnemoniclen < 256 && passphraselen < 64) { diff --git a/blake2b.c b/blake2b.c index f59f41536..15df01190 100644 --- a/blake2b.c +++ b/blake2b.c @@ -17,6 +17,7 @@ #include "blake2b.h" #include "blake2_common.h" +#include "memzero.h" typedef struct blake2b_param__ { @@ -159,7 +160,7 @@ int blake2b_InitKey( blake2b_state *S, size_t outlen, const void *key, size_t ke memset( block, 0, BLAKE2B_BLOCKBYTES ); memcpy( block, key, keylen ); blake2b_Update( S, block, BLAKE2B_BLOCKBYTES ); - explicit_bzero( block, BLAKE2B_BLOCKBYTES ); /* Burn the key from stack */ + memzero( block, BLAKE2B_BLOCKBYTES ); /* Burn the key from stack */ } return 0; } @@ -279,7 +280,7 @@ int blake2b_Final( blake2b_state *S, void *out, size_t outlen ) store64( buffer + sizeof( S->h[i] ) * i, S->h[i] ); memcpy( out, buffer, S->outlen ); - explicit_bzero(buffer, sizeof(buffer)); + memzero(buffer, sizeof(buffer)); return 0; } diff --git a/blake2s.c b/blake2s.c index e64b6504d..636479b9b 100644 --- a/blake2s.c +++ b/blake2s.c @@ -17,6 +17,7 @@ #include "blake2s.h" #include "blake2_common.h" +#include "memzero.h" typedef struct blake2s_param__ { @@ -153,7 +154,7 @@ int blake2s_InitKey( blake2s_state *S, size_t outlen, const void *key, size_t ke memset( block, 0, BLAKE2S_BLOCKBYTES ); memcpy( block, key, keylen ); blake2s_Update( S, block, BLAKE2S_BLOCKBYTES ); - explicit_bzero( block, BLAKE2S_BLOCKBYTES ); /* Burn the key from stack */ + memzero( block, BLAKE2S_BLOCKBYTES ); /* Burn the key from stack */ } return 0; } @@ -271,7 +272,7 @@ int blake2s_Final( blake2s_state *S, void *out, size_t outlen ) store32( buffer + sizeof( S->h[i] ) * i, S->h[i] ); memcpy( out, buffer, outlen ); - explicit_bzero(buffer, sizeof(buffer)); + memzero(buffer, sizeof(buffer)); return 0; } diff --git a/ecdsa.c b/ecdsa.c index 2d1e5cf76..2e679a8af 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -37,6 +37,7 @@ #include "base58.h" #include "secp256k1.h" #include "rfc6979.h" +#include "memzero.h" // Set cp2 = cp1 void point_copy(const curve_point *cp1, curve_point *cp2) @@ -541,8 +542,8 @@ void point_multiply(const ecdsa_curve *curve, const bignum256 *k, const curve_po } conditional_negate(sign, &jres.z, prime); jacobian_to_curve(&jres, res, prime); - explicit_bzero(&a, sizeof(a)); - explicit_bzero(&jres, sizeof(jres)); + memzero(&a, sizeof(a)); + memzero(&jres, sizeof(jres)); } #if USE_PRECOMPUTED_CP @@ -629,8 +630,8 @@ void scalar_multiply(const ecdsa_curve *curve, const bignum256 *k, curve_point * } conditional_negate(((a.val[0] >> 4) & 1) - 1, &jres.y, prime); jacobian_to_curve(&jres, res, prime); - explicit_bzero(&a, sizeof(a)); - explicit_bzero(&jres, sizeof(jres)); + memzero(&a, sizeof(a)); + memzero(&jres, sizeof(jres)); } #else @@ -652,12 +653,12 @@ int ecdh_multiply(const ecdsa_curve *curve, const uint8_t *priv_key, const uint8 bignum256 k; bn_read_be(priv_key, &k); point_multiply(curve, &k, &point, &point); - explicit_bzero(&k, sizeof(k)); + memzero(&k, sizeof(k)); session_key[0] = 0x04; bn_write_be(&point.x, session_key + 1); bn_write_be(&point.y, session_key + 33); - explicit_bzero(&point, sizeof(point)); + memzero(&point, sizeof(point)); return 0; } @@ -684,8 +685,8 @@ void init_rfc6979(const uint8_t *priv_key, const uint8_t *hash, rfc6979_state *s hmac_sha256(state->k, sizeof(state->k), buf, sizeof(buf), state->k); hmac_sha256(state->k, sizeof(state->k), state->v, sizeof(state->v), state->v); - explicit_bzero(bx, sizeof(bx)); - explicit_bzero(buf, sizeof(buf)); + memzero(bx, sizeof(bx)); + memzero(buf, sizeof(buf)); } // generate next number from deterministic random number generator @@ -699,7 +700,7 @@ void generate_rfc6979(uint8_t rnd[32], rfc6979_state *state) hmac_sha256(state->k, sizeof(state->k), buf, sizeof(state->v) + 1, state->k); hmac_sha256(state->k, sizeof(state->k), state->v, sizeof(state->v), state->v); memcpy(rnd, buf, 32); - explicit_bzero(buf, sizeof(buf)); + memzero(buf, sizeof(buf)); } // generate K in a deterministic way, according to RFC6979 @@ -709,7 +710,7 @@ void generate_k_rfc6979(bignum256 *k, rfc6979_state *state) uint8_t buf[32]; generate_rfc6979(buf, state); bn_read_be(buf, k); - explicit_bzero(buf, sizeof(buf)); + memzero(buf, sizeof(buf)); } // msg is a data to be signed @@ -719,7 +720,7 @@ int ecdsa_sign(const ecdsa_curve *curve, HasherType hasher_type, const uint8_t * uint8_t hash[32]; hasher_Raw(hasher_type, msg, msg_len, hash); int res = ecdsa_sign_digest(curve, priv_key, hash, sig, pby, is_canonical); - explicit_bzero(hash, sizeof(hash)); + memzero(hash, sizeof(hash)); return res; } @@ -732,7 +733,7 @@ int ecdsa_sign_double(const ecdsa_curve *curve, HasherType hasher_type, const ui hasher_Raw(hasher_type, msg, msg_len, hash); hasher_Raw(hasher_type, hash, 32, hash); int res = ecdsa_sign_digest(curve, priv_key, hash, sig, pby, is_canonical); - explicit_bzero(hash, sizeof(hash)); + memzero(hash, sizeof(hash)); return res; } @@ -817,20 +818,20 @@ int ecdsa_sign_digest(const ecdsa_curve *curve, const uint8_t *priv_key, const u *pby = by; } - explicit_bzero(&k, sizeof(k)); - explicit_bzero(&randk, sizeof(randk)); + memzero(&k, sizeof(k)); + memzero(&randk, sizeof(randk)); #if USE_RFC6979 - explicit_bzero(&rng, sizeof(rng)); + memzero(&rng, sizeof(rng)); #endif return 0; } // Too many retries without a valid signature // -> fail with an error - explicit_bzero(&k, sizeof(k)); - explicit_bzero(&randk, sizeof(randk)); + memzero(&k, sizeof(k)); + memzero(&randk, sizeof(randk)); #if USE_RFC6979 - explicit_bzero(&rng, sizeof(rng)); + memzero(&rng, sizeof(rng)); #endif return -1; } @@ -845,8 +846,8 @@ void ecdsa_get_public_key33(const ecdsa_curve *curve, const uint8_t *priv_key, u scalar_multiply(curve, &k, &R); pub_key[0] = 0x02 | (R.y.val[0] & 0x01); bn_write_be(&R.x, pub_key + 1); - explicit_bzero(&R, sizeof(R)); - explicit_bzero(&k, sizeof(k)); + memzero(&R, sizeof(R)); + memzero(&k, sizeof(k)); } void ecdsa_get_public_key65(const ecdsa_curve *curve, const uint8_t *priv_key, uint8_t *pub_key) @@ -860,8 +861,8 @@ void ecdsa_get_public_key65(const ecdsa_curve *curve, const uint8_t *priv_key, u pub_key[0] = 0x04; bn_write_be(&R.x, pub_key + 1); bn_write_be(&R.y, pub_key + 33); - explicit_bzero(&R, sizeof(R)); - explicit_bzero(&k, sizeof(k)); + memzero(&R, sizeof(R)); + memzero(&k, sizeof(k)); } int ecdsa_uncompress_pubkey(const ecdsa_curve *curve, const uint8_t *pub_key, uint8_t *uncompressed) @@ -890,7 +891,7 @@ void ecdsa_get_pubkeyhash(const uint8_t *pub_key, HasherType hasher_type, uint8_ hasher_Raw(hasher_type, pub_key, 33, h); } ripemd160(h, HASHER_DIGEST_LENGTH, pubkeyhash); - explicit_bzero(h, sizeof(h)); + memzero(h, sizeof(h)); } void ecdsa_get_address_raw(const uint8_t *pub_key, uint32_t version, HasherType hasher_type, uint8_t *addr_raw) @@ -907,7 +908,7 @@ void ecdsa_get_address(const uint8_t *pub_key, uint32_t version, HasherType hash ecdsa_get_address_raw(pub_key, version, hasher_type, raw); base58_encode_check(raw, 20 + prefix_len, hasher_type, addr, addrsize); // not as important to clear this one, but we might as well - explicit_bzero(raw, sizeof(raw)); + memzero(raw, sizeof(raw)); } void ecdsa_get_address_segwit_p2sh_raw(const uint8_t *pub_key, uint32_t version, HasherType hasher_type, uint8_t *addr_raw) @@ -928,7 +929,7 @@ void ecdsa_get_address_segwit_p2sh(const uint8_t *pub_key, uint32_t version, Has size_t prefix_len = address_prefix_bytes_len(version); ecdsa_get_address_segwit_p2sh_raw(pub_key, version, hasher_type, raw); base58_encode_check(raw, prefix_len + 20, hasher_type, addr, addrsize); - explicit_bzero(raw, sizeof(raw)); + memzero(raw, sizeof(raw)); } void ecdsa_get_wif(const uint8_t *priv_key, uint32_t version, HasherType hasher_type, char *wif, int wifsize) @@ -940,7 +941,7 @@ void ecdsa_get_wif(const uint8_t *priv_key, uint32_t version, HasherType hasher_ wif_raw[prefix_len + 32] = 0x01; base58_encode_check(wif_raw, prefix_len + 32 + 1, hasher_type, wif, wifsize); // private keys running around our stack can cause trouble - explicit_bzero(wif_raw, sizeof(wif_raw)); + memzero(wif_raw, sizeof(wif_raw)); } int ecdsa_address_decode(const char *addr, uint32_t version, HasherType hasher_type, uint8_t *out) @@ -1033,7 +1034,7 @@ int ecdsa_verify(const ecdsa_curve *curve, HasherType hasher_type, const uint8_t uint8_t hash[32]; hasher_Raw(hasher_type, msg, msg_len, hash); int res = ecdsa_verify_digest(curve, pub_key, sig, hash); - explicit_bzero(hash, sizeof(hash)); + memzero(hash, sizeof(hash)); return res; } @@ -1043,7 +1044,7 @@ int ecdsa_verify_double(const ecdsa_curve *curve, HasherType hasher_type, const hasher_Raw(hasher_type, msg, msg_len, hash); hasher_Raw(hasher_type, hash, 32, hash); int res = ecdsa_verify_digest(curve, pub_key, sig, hash); - explicit_bzero(hash, sizeof(hash)); + memzero(hash, sizeof(hash)); return res; } @@ -1142,11 +1143,11 @@ int ecdsa_verify_digest(const ecdsa_curve *curve, const uint8_t *pub_key, const } } - explicit_bzero(&pub, sizeof(pub)); - explicit_bzero(&res, sizeof(res)); - explicit_bzero(&r, sizeof(r)); - explicit_bzero(&s, sizeof(s)); - explicit_bzero(&z, sizeof(z)); + memzero(&pub, sizeof(pub)); + memzero(&res, sizeof(res)); + memzero(&r, sizeof(r)); + memzero(&s, sizeof(s)); + memzero(&z, sizeof(z)); // all OK return result; diff --git a/hmac.c b/hmac.c index ff462c37f..04448c8f2 100644 --- a/hmac.c +++ b/hmac.c @@ -25,6 +25,7 @@ #include "hmac.h" #include "options.h" +#include "memzero.h" void hmac_sha256_Init(HMAC_SHA256_CTX *hctx, const uint8_t *key, const uint32_t keylen) { @@ -41,7 +42,7 @@ void hmac_sha256_Init(HMAC_SHA256_CTX *hctx, const uint8_t *key, const uint32_t } sha256_Init(&(hctx->ctx)); sha256_Update(&(hctx->ctx), i_key_pad, SHA256_BLOCK_LENGTH); - explicit_bzero(i_key_pad, sizeof(i_key_pad)); + memzero(i_key_pad, sizeof(i_key_pad)); } void hmac_sha256_Update(HMAC_SHA256_CTX *hctx, const uint8_t *msg, const uint32_t msglen) @@ -56,7 +57,7 @@ void hmac_sha256_Final(HMAC_SHA256_CTX *hctx, uint8_t *hmac) sha256_Update(&(hctx->ctx), hctx->o_key_pad, SHA256_BLOCK_LENGTH); sha256_Update(&(hctx->ctx), hmac, SHA256_DIGEST_LENGTH); sha256_Final(&(hctx->ctx), hmac); - explicit_bzero(hctx, sizeof(HMAC_SHA256_CTX)); + memzero(hctx, sizeof(HMAC_SHA256_CTX)); } void hmac_sha256(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, const uint32_t msglen, uint8_t *hmac) @@ -71,7 +72,7 @@ void hmac_sha256_prepare(const uint8_t *key, const uint32_t keylen, uint32_t *op { static CONFIDENTIAL uint32_t key_pad[SHA256_BLOCK_LENGTH/sizeof(uint32_t)]; - explicit_bzero(key_pad, sizeof(key_pad)); + memzero(key_pad, sizeof(key_pad)); if (keylen > SHA256_BLOCK_LENGTH) { static CONFIDENTIAL SHA256_CTX context; sha256_Init(&context); @@ -98,7 +99,7 @@ void hmac_sha256_prepare(const uint8_t *key, const uint32_t keylen, uint32_t *op key_pad[i] = key_pad[i] ^ 0x5c5c5c5c ^ 0x36363636; } sha256_Transform(sha256_initial_hash_value, key_pad, ipad_digest); - explicit_bzero(key_pad, sizeof(key_pad)); + memzero(key_pad, sizeof(key_pad)); } void hmac_sha512_Init(HMAC_SHA512_CTX *hctx, const uint8_t *key, const uint32_t keylen) @@ -116,7 +117,7 @@ void hmac_sha512_Init(HMAC_SHA512_CTX *hctx, const uint8_t *key, const uint32_t } sha512_Init(&(hctx->ctx)); sha512_Update(&(hctx->ctx), i_key_pad, SHA512_BLOCK_LENGTH); - explicit_bzero(i_key_pad, sizeof(i_key_pad)); + memzero(i_key_pad, sizeof(i_key_pad)); } void hmac_sha512_Update(HMAC_SHA512_CTX *hctx, const uint8_t *msg, const uint32_t msglen) @@ -131,7 +132,7 @@ void hmac_sha512_Final(HMAC_SHA512_CTX *hctx, uint8_t *hmac) sha512_Update(&(hctx->ctx), hctx->o_key_pad, SHA512_BLOCK_LENGTH); sha512_Update(&(hctx->ctx), hmac, SHA512_DIGEST_LENGTH); sha512_Final(&(hctx->ctx), hmac); - explicit_bzero(hctx, sizeof(HMAC_SHA512_CTX)); + memzero(hctx, sizeof(HMAC_SHA512_CTX)); } void hmac_sha512(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, const uint32_t msglen, uint8_t *hmac) @@ -146,7 +147,7 @@ void hmac_sha512_prepare(const uint8_t *key, const uint32_t keylen, uint64_t *op { static CONFIDENTIAL uint64_t key_pad[SHA512_BLOCK_LENGTH/sizeof(uint64_t)]; - explicit_bzero(key_pad, sizeof(key_pad)); + memzero(key_pad, sizeof(key_pad)); if (keylen > SHA512_BLOCK_LENGTH) { static CONFIDENTIAL SHA512_CTX context; sha512_Init(&context); @@ -173,5 +174,5 @@ void hmac_sha512_prepare(const uint8_t *key, const uint32_t keylen, uint64_t *op key_pad[i] = key_pad[i] ^ 0x5c5c5c5c5c5c5c5c ^ 0x3636363636363636; } sha512_Transform(sha512_initial_hash_value, key_pad, ipad_digest); - explicit_bzero(key_pad, sizeof(key_pad)); + memzero(key_pad, sizeof(key_pad)); } diff --git a/memzero.c b/memzero.c new file mode 100644 index 000000000..68fad584b --- /dev/null +++ b/memzero.c @@ -0,0 +1,6 @@ +#include + +void memzero(void *s, size_t n) +{ + memset(s, 0, n); +} diff --git a/memzero.h b/memzero.h new file mode 100644 index 000000000..ce51acaef --- /dev/null +++ b/memzero.h @@ -0,0 +1,8 @@ +#ifndef __MEMZERO_H__ +#define __MEMZERO_H__ + +#include + +void memzero(void *s, size_t n); + +#endif diff --git a/nem.c b/nem.c index 4b226a1c8..d5faff008 100644 --- a/nem.c +++ b/nem.c @@ -28,6 +28,7 @@ #include "ed25519-donna/ed25519-keccak.h" #include "ripemd160.h" #include "sha3.h" +#include "memzero.h" const char *nem_network_name(uint8_t network) { switch (network) { @@ -111,7 +112,7 @@ void nem_get_address_raw(const ed25519_public_key public_key, uint8_t version, u /* 5. Concatenate output of step 3 and the checksum from step 4 */ memcpy(&address[1 + RIPEMD160_DIGEST_LENGTH], hash, 4); - explicit_bzero(hash, sizeof(hash)); + memzero(hash, sizeof(hash)); } bool nem_get_address(const ed25519_public_key public_key, uint8_t version, char *address) { @@ -121,7 +122,7 @@ bool nem_get_address(const ed25519_public_key public_key, uint8_t version, char char *ret = base32_encode(pubkeyhash, sizeof(pubkeyhash), address, NEM_ADDRESS_SIZE + 1, BASE32_ALPHABET_RFC4648); - explicit_bzero(pubkeyhash, sizeof(pubkeyhash)); + memzero(pubkeyhash, sizeof(pubkeyhash)); return (ret != NULL); } @@ -135,7 +136,7 @@ bool nem_validate_address_raw(const uint8_t *address, uint8_t network) { keccak_256(address, 1 + RIPEMD160_DIGEST_LENGTH, hash); bool valid = (memcmp(&address[1 + RIPEMD160_DIGEST_LENGTH], hash, 4) == 0); - explicit_bzero(hash, sizeof(hash)); + memzero(hash, sizeof(hash)); return valid; } @@ -149,7 +150,7 @@ bool nem_validate_address(const char *address, uint8_t network) { uint8_t *ret = base32_decode(address, NEM_ADDRESS_SIZE, pubkeyhash, sizeof(pubkeyhash), BASE32_ALPHABET_RFC4648); bool valid = (ret != NULL) && nem_validate_address_raw(pubkeyhash, network); - explicit_bzero(pubkeyhash, sizeof(pubkeyhash)); + memzero(pubkeyhash, sizeof(pubkeyhash)); return valid; } diff --git a/pbkdf2.c b/pbkdf2.c index f94ef368b..e6dbd008b 100644 --- a/pbkdf2.c +++ b/pbkdf2.c @@ -25,6 +25,7 @@ #include "pbkdf2.h" #include "hmac.h" #include "sha2.h" +#include "memzero.h" void pbkdf2_hmac_sha256_Init(PBKDF2_HMAC_SHA256_CTX *pctx, const uint8_t *pass, int passlen, const uint8_t *salt, int saltlen) { @@ -74,7 +75,7 @@ void pbkdf2_hmac_sha256_Final(PBKDF2_HMAC_SHA256_CTX *pctx, uint8_t *key) } #endif memcpy(key, pctx->f, SHA256_DIGEST_LENGTH); - explicit_bzero(pctx, sizeof(PBKDF2_HMAC_SHA256_CTX)); + memzero(pctx, sizeof(PBKDF2_HMAC_SHA256_CTX)); } void pbkdf2_hmac_sha256(const uint8_t *pass, int passlen, const uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key) @@ -134,7 +135,7 @@ void pbkdf2_hmac_sha512_Final(PBKDF2_HMAC_SHA512_CTX *pctx, uint8_t *key) } #endif memcpy(key, pctx->f, SHA512_DIGEST_LENGTH); - explicit_bzero(pctx, sizeof(PBKDF2_HMAC_SHA512_CTX)); + memzero(pctx, sizeof(PBKDF2_HMAC_SHA512_CTX)); } void pbkdf2_hmac_sha512(const uint8_t *pass, int passlen, const uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key) diff --git a/rfc6979.c b/rfc6979.c index 1168645e6..ec808a7cf 100644 --- a/rfc6979.c +++ b/rfc6979.c @@ -25,6 +25,7 @@ #include #include "rfc6979.h" #include "hmac.h" +#include "memzero.h" void init_rfc6979(const uint8_t *priv_key, const uint8_t *hash, rfc6979_state *state) { uint8_t bx[2*32]; @@ -48,8 +49,8 @@ void init_rfc6979(const uint8_t *priv_key, const uint8_t *hash, rfc6979_state *s hmac_sha256(state->k, sizeof(state->k), buf, sizeof(buf), state->k); hmac_sha256(state->k, sizeof(state->k), state->v, sizeof(state->v), state->v); - explicit_bzero(bx, sizeof(bx)); - explicit_bzero(buf, sizeof(buf)); + memzero(bx, sizeof(bx)); + memzero(buf, sizeof(buf)); } // generate next number from deterministic random number generator @@ -63,7 +64,7 @@ void generate_rfc6979(uint8_t rnd[32], rfc6979_state *state) hmac_sha256(state->k, sizeof(state->k), buf, sizeof(state->v) + 1, state->k); hmac_sha256(state->k, sizeof(state->k), state->v, sizeof(state->v), state->v); memcpy(rnd, buf, 32); - explicit_bzero(buf, sizeof(buf)); + memzero(buf, sizeof(buf)); } // generate K in a deterministic way, according to RFC6979 @@ -73,5 +74,5 @@ void generate_k_rfc6979(bignum256 *k, rfc6979_state *state) uint8_t buf[32]; generate_rfc6979(buf, state); bn_read_be(buf, k); - explicit_bzero(buf, sizeof(buf)); + memzero(buf, sizeof(buf)); } diff --git a/ripemd160.c b/ripemd160.c index fb65f71b2..66b13ca3d 100644 --- a/ripemd160.c +++ b/ripemd160.c @@ -28,6 +28,7 @@ #include #include "ripemd160.h" +#include "memzero.h" /* * 32-bit integer manipulation macros (little endian) @@ -327,7 +328,7 @@ void ripemd160_Final( RIPEMD160_CTX *ctx, uint8_t output[RIPEMD160_DIGEST_LENGTH PUT_UINT32_LE( ctx->state[3], output, 12 ); PUT_UINT32_LE( ctx->state[4], output, 16 ); - explicit_bzero(ctx, sizeof(RIPEMD160_CTX)); + memzero(ctx, sizeof(RIPEMD160_CTX)); } /* diff --git a/sha2.c b/sha2.c index 1b399e947..0d27f4335 100644 --- a/sha2.c +++ b/sha2.c @@ -31,6 +31,7 @@ #include #include #include "sha2.h" +#include "memzero.h" /* * ASSERT NOTE: @@ -281,7 +282,7 @@ static const char *sha2_hex_digits = "0123456789abcdef"; /*** SHA-1: ***********************************************************/ void sha1_Init(SHA1_CTX* context) { MEMCPY_BCOPY(context->state, sha1_initial_hash_value, SHA1_DIGEST_LENGTH); - explicit_bzero(context->buffer, SHA1_BLOCK_LENGTH); + memzero(context->buffer, SHA1_BLOCK_LENGTH); context->bitcount = 0; } @@ -591,14 +592,14 @@ void sha1_Final(SHA1_CTX* context, sha2_byte digest[]) { * No digest buffer, so we can do nothing * except clean up and go home */ - explicit_bzero(context, sizeof(SHA1_CTX)); + memzero(context, sizeof(SHA1_CTX)); return; } usedspace = (context->bitcount >> 3) % SHA1_BLOCK_LENGTH; if (usedspace == 0) { /* Set-up for the last transform: */ - explicit_bzero(context->buffer, SHA1_SHORT_BLOCK_LENGTH); + memzero(context->buffer, SHA1_SHORT_BLOCK_LENGTH); /* Begin padding with a 1 bit: */ *context->buffer = 0x80; @@ -608,16 +609,16 @@ void sha1_Final(SHA1_CTX* context, sha2_byte digest[]) { if (usedspace <= 56) { /* Set-up for the last transform: */ - explicit_bzero(((uint8_t*)context->buffer) + usedspace, 56 - usedspace); + memzero(((uint8_t*)context->buffer) + usedspace, 56 - usedspace); } else { if (usedspace < 64) { - explicit_bzero(((uint8_t*)context->buffer) + usedspace, 64 - usedspace); + memzero(((uint8_t*)context->buffer) + usedspace, 64 - usedspace); } /* Do second-to-last transform: */ sha1_Transform(context->state, context->buffer, context->state); /* And set-up for the last transform: */ - explicit_bzero(context->buffer, 56); + memzero(context->buffer, 56); } /* Clean up: */ usedspace = 0; @@ -648,7 +649,7 @@ void sha1_Final(SHA1_CTX* context, sha2_byte digest[]) { #endif /* Clean up: */ - explicit_bzero(context, sizeof(SHA1_CTX)); + memzero(context, sizeof(SHA1_CTX)); } char *sha1_End(SHA1_CTX* context, char buffer[]) { @@ -665,9 +666,9 @@ char *sha1_End(SHA1_CTX* context, char buffer[]) { } *buffer = (char)0; } else { - explicit_bzero(context, sizeof(SHA1_CTX)); + memzero(context, sizeof(SHA1_CTX)); } - explicit_bzero(digest, SHA1_DIGEST_LENGTH); + memzero(digest, SHA1_DIGEST_LENGTH); return buffer; } @@ -692,7 +693,7 @@ void sha256_Init(SHA256_CTX* context) { return; } MEMCPY_BCOPY(context->state, sha256_initial_hash_value, SHA256_DIGEST_LENGTH); - explicit_bzero(context->buffer, SHA256_BLOCK_LENGTH); + memzero(context->buffer, SHA256_BLOCK_LENGTH); context->bitcount = 0; } @@ -929,7 +930,7 @@ void sha256_Final(SHA256_CTX* context, sha2_byte digest[]) { ((uint8_t*)context->buffer)[usedspace++] = 0x80; if (usedspace > SHA256_SHORT_BLOCK_LENGTH) { - explicit_bzero(((uint8_t*)context->buffer) + usedspace, SHA256_BLOCK_LENGTH - usedspace); + memzero(((uint8_t*)context->buffer) + usedspace, SHA256_BLOCK_LENGTH - usedspace); #if BYTE_ORDER == LITTLE_ENDIAN /* Convert TO host byte order */ @@ -944,7 +945,7 @@ void sha256_Final(SHA256_CTX* context, sha2_byte digest[]) { usedspace = 0; } /* Set-up for the last transform: */ - explicit_bzero(((uint8_t*)context->buffer) + usedspace, SHA256_SHORT_BLOCK_LENGTH - usedspace); + memzero(((uint8_t*)context->buffer) + usedspace, SHA256_SHORT_BLOCK_LENGTH - usedspace); #if BYTE_ORDER == LITTLE_ENDIAN /* Convert TO host byte order */ @@ -969,7 +970,7 @@ void sha256_Final(SHA256_CTX* context, sha2_byte digest[]) { } /* Clean up state data: */ - explicit_bzero(context, sizeof(SHA256_CTX)); + memzero(context, sizeof(SHA256_CTX)); usedspace = 0; } @@ -987,9 +988,9 @@ char *sha256_End(SHA256_CTX* context, char buffer[]) { } *buffer = (char)0; } else { - explicit_bzero(context, sizeof(SHA256_CTX)); + memzero(context, sizeof(SHA256_CTX)); } - explicit_bzero(digest, SHA256_DIGEST_LENGTH); + memzero(digest, SHA256_DIGEST_LENGTH); return buffer; } @@ -1015,7 +1016,7 @@ void sha512_Init(SHA512_CTX* context) { return; } MEMCPY_BCOPY(context->state, sha512_initial_hash_value, SHA512_DIGEST_LENGTH); - explicit_bzero(context->buffer, SHA512_BLOCK_LENGTH); + memzero(context->buffer, SHA512_BLOCK_LENGTH); context->bitcount[0] = context->bitcount[1] = 0; } @@ -1232,7 +1233,7 @@ static void sha512_Last(SHA512_CTX* context) { ((uint8_t*)context->buffer)[usedspace++] = 0x80; if (usedspace > SHA512_SHORT_BLOCK_LENGTH) { - explicit_bzero(((uint8_t*)context->buffer) + usedspace, SHA512_BLOCK_LENGTH - usedspace); + memzero(((uint8_t*)context->buffer) + usedspace, SHA512_BLOCK_LENGTH - usedspace); #if BYTE_ORDER == LITTLE_ENDIAN /* Convert TO host byte order */ @@ -1247,7 +1248,7 @@ static void sha512_Last(SHA512_CTX* context) { usedspace = 0; } /* Set-up for the last transform: */ - explicit_bzero(((uint8_t*)context->buffer) + usedspace, SHA512_SHORT_BLOCK_LENGTH - usedspace); + memzero(((uint8_t*)context->buffer) + usedspace, SHA512_SHORT_BLOCK_LENGTH - usedspace); #if BYTE_ORDER == LITTLE_ENDIAN /* Convert TO host byte order */ @@ -1279,7 +1280,7 @@ void sha512_Final(SHA512_CTX* context, sha2_byte digest[]) { } /* Zero out state data */ - explicit_bzero(context, sizeof(SHA512_CTX)); + memzero(context, sizeof(SHA512_CTX)); } char *sha512_End(SHA512_CTX* context, char buffer[]) { @@ -1296,9 +1297,9 @@ char *sha512_End(SHA512_CTX* context, char buffer[]) { } *buffer = (char)0; } else { - explicit_bzero(context, sizeof(SHA512_CTX)); + memzero(context, sizeof(SHA512_CTX)); } - explicit_bzero(digest, SHA512_DIGEST_LENGTH); + memzero(digest, SHA512_DIGEST_LENGTH); return buffer; } diff --git a/sha3.c b/sha3.c index bba56326a..3ef9db8ae 100644 --- a/sha3.c +++ b/sha3.c @@ -21,6 +21,7 @@ #include #include "sha3.h" +#include "memzero.h" #define I64(x) x##LL #define ROTL64(qword, n) ((qword) << (n) ^ ((qword) >> (64 - (n)))) @@ -330,7 +331,7 @@ void sha3_Final(SHA3_CTX *ctx, unsigned char* result) assert(block_size > digest_length); if (result) me64_to_le_str(result, ctx->hash, digest_length); - explicit_bzero(ctx, sizeof(SHA3_CTX)); + memzero(ctx, sizeof(SHA3_CTX)); } #if USE_KECCAK @@ -359,7 +360,7 @@ void keccak_Final(SHA3_CTX *ctx, unsigned char* result) assert(block_size > digest_length); if (result) me64_to_le_str(result, ctx->hash, digest_length); - explicit_bzero(ctx, sizeof(SHA3_CTX)); + memzero(ctx, sizeof(SHA3_CTX)); } void keccak_256(const unsigned char* data, size_t len, unsigned char* digest) From 2e528be1e91dd48c0e55061fbdd40ccf8b285559 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 21 Jan 2018 23:38:32 +0100 Subject: [PATCH 528/627] add warning message to rand.c --- rand.c | 39 +++++++++++++++++---------------------- rand.h | 3 ++- 2 files changed, 19 insertions(+), 23 deletions(-) diff --git a/rand.c b/rand.c index 975bf18d5..0b5c48577 100644 --- a/rand.c +++ b/rand.c @@ -25,32 +25,27 @@ #ifndef RAND_PLATFORM_INDEPENDENT + +#pragma message("NOT SUITABLE FOR PRODUCTION USE!") + +// The following code is not supposed to be used in a production environment. +// It's included only to make the library testable. +// The message above tries to prevent any accidental use outside of the test environment. +// +// You are supposed to replace the random32() function with your own secure code. +// There is also a possibility to replace the random_buffer() function as it is defined as a weak symbol. + #include -#ifdef _WIN32 #include -#else -#include -#endif uint32_t random32(void) { -#ifdef _WIN32 static int initialized = 0; if (!initialized) { srand((unsigned)time(NULL)); initialized = 1; } return ((rand() % 0xFF) | ((rand() % 0xFF) << 8) | ((rand() % 0xFF) << 16) | ((rand() % 0xFF) << 24)); -#else - static FILE *frand = NULL; - if (!frand) { - frand = fopen("/dev/urandom", "r"); - } - uint32_t r; - size_t len_read = fread(&r, 1, sizeof(r), frand); - assert(len_read == sizeof(r)); - return r; -#endif } #endif /* RAND_PLATFORM_INDEPENDENT */ @@ -59,13 +54,6 @@ uint32_t random32(void) // The following code is platform independent // -uint32_t random_uniform(uint32_t n) -{ - uint32_t x, max = 0xFFFFFFFF - (0xFFFFFFFF % n); - while ((x = random32()) >= max); - return x / (max / n); -} - void __attribute__((weak)) random_buffer(uint8_t *buf, size_t len) { uint32_t r = 0; @@ -77,6 +65,13 @@ void __attribute__((weak)) random_buffer(uint8_t *buf, size_t len) } } +uint32_t random_uniform(uint32_t n) +{ + uint32_t x, max = 0xFFFFFFFF - (0xFFFFFFFF % n); + while ((x = random32()) >= max); + return x / (max / n); +} + void random_permute(char *str, size_t len) { for (int i = len - 1; i >= 1; i--) { diff --git a/rand.h b/rand.h index 1053fef29..175bd9607 100644 --- a/rand.h +++ b/rand.h @@ -28,8 +28,9 @@ #include uint32_t random32(void); -uint32_t random_uniform(uint32_t n); void random_buffer(uint8_t *buf, size_t len); + +uint32_t random_uniform(uint32_t n); void random_permute(char *buf, size_t len); #endif From 49272f8d869f1424608760ea52949595c17804e3 Mon Sep 17 00:00:00 2001 From: Tomas Susanka Date: Tue, 20 Mar 2018 17:18:11 +0100 Subject: [PATCH 529/627] bip32/nem: added test data for encryption of block size multiple --- test_check.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test_check.c b/test_check.c index 918cd0540..6c8fa810a 100644 --- a/test_check.c +++ b/test_check.c @@ -3691,6 +3691,12 @@ START_TEST(test_nem_cipher) { "ed93c5a101ab53382ceee4f7e6b5aa112621d3bb9d18891509b1834ede235bcc", "5a5e14c633d7d269302849d739d80344ff14db51d7bcda86045723f05c4e4541", "28dc7ccd6c2a939eef64b8be7b9ae248295e7fcd8471c22fa2f98733fea97611", "cb13890d3a11bc0a7433738263006710", "24512b714aefd5cbc4bcc4ef44ce6c67ffc447c65460a6c6e4a92e85", "e74ded846bebfa912fa1720e4c1415e6e5df7e7a1a7fedb5665d68f1763209a4", }, { "ed93c5a101ab53382ceee4f7e6b5aa112621d3bb9d18891509b1834ede235bcc", "5a5e14c633d7d269302849d739d80344ff14db51d7bcda86045723f05c4e4541", "79974fa2cad95154d0873902c153ccc3e7d54b17f2eeb3f29b6344cad9365a9a", "22123357979d20f44cc8eb0263d84e0e", "24512b714aefd5cbc4bcc4ef44ce6c67ffc447c65460a6c6e4a92e85", "eb14dec7b8b64d81a2ee4db07b0adf144d4f79a519bbf332b823583fa2d45405", }, { "ed93c5a101ab53382ceee4f7e6b5aa112621d3bb9d18891509b1834ede235bcc", "5a5e14c633d7d269302849d739d80344ff14db51d7bcda86045723f05c4e4541", "3409a6f8c4dcd9bd04144eb67e55a98696b674735b01bf1196191f29871ef966", "a823a0965969380ea1f8659ea5fd8fdd", "24512b714aefd5cbc4bcc4ef44ce6c67ffc447c65460a6c6e4a92e85", "00a7eb708eae745847173f8217efb05be13059710aee632e3f471ac3c6202b51", }, + { "a73a0b2686f7d699c018b6b08a352856e556070caa329c26241aec889eefde10", "9b493403bee45ae6277430ef8d0c4163ffd81ace2db6c7821205da09a664a86c", "c25701b9b7328c4ac3d23223d10623bd527c0a98e38ae9c62fbc403c80ab20ae", "4b4ee0e4443779f3af429a749212f476", "b6926d0ec82cec86c0d27ec9a33a0e0f", "f39f7d66e0fde39ecdf58be2c0ef361a17cfd6843e310adbe0ec3118cd72800d", }, + { "a73a0b2686f7d699c018b6b08a352856e556070caa329c26241aec889eefde10", "9b493403bee45ae6277430ef8d0c4163ffd81ace2db6c7821205da09a664a86c", "31d18fdffc480310828778496ff817039df5d6f30bf6d9edd0b4396863d05f93", "418bcbdf52860a450bfacc96920d02cf", "b6926d0ec82cec86c0d27ec9a33a0e0f", "0e6ce9889fe7b3cd82794b0ae27c1f5985d2f2a1f398371a138f8db1df1f54de", }, + { "e2e4dee102fad0f47f60202269605589cd9cf70f816b34016796c74b766f3041", "c5ce283033a3255ae14d42dff1e4c18a224ac79d084b285123421b105ee654c9", "56b4c645f81dbfb6ba0c6d3f1626e1e5cd648eeb36562715f7cd7e9ea86a0d7f", "dc9bdce76d68d2e4d72267cf4e72b022", "b6926d0ec82cec86c0d27ec9a33a0e0f", "dc6f046c3008002041517a7c4f3ababe609cf02616fcccda39c075d1be4175f5", }, + { "e2e4dee102fad0f47f60202269605589cd9cf70f816b34016796c74b766f3041", "c5ce283033a3255ae14d42dff1e4c18a224ac79d084b285123421b105ee654c9", "df180b91986c8c7000792f96d1faa61e30138330430a402322be1855089b0e7f", "ccf9b77341c866465b474e2f4a3b1cf8", "b6926d0ec82cec86c0d27ec9a33a0e0f", "94e4ae89041437f39826704f02cb5d775226f34344635e592846417497a5020b", }, + { "e2e4dee102fad0f47f60202269605589cd9cf70f816b34016796c74b766f3041", "c5ce283033a3255ae14d42dff1e4c18a224ac79d084b285123421b105ee654c9", "a0eee7e84c76e63fdae6e938b43330775eaf17d260e40b98c9e6616b668102a7", "662c681cfec6f6d052ff0e2c1255f2c2", "b6926d0ec82cec86c0d27ec9a33a0e0f", "70bba3c48be9c75a144b1888ca3d21a6b21f52eec133981a024390a6a0ba36f9", }, + { "e2e4dee102fad0f47f60202269605589cd9cf70f816b34016796c74b766f3041", "c5ce283033a3255ae14d42dff1e4c18a224ac79d084b285123421b105ee654c9", "c6acd2d90eb782c3053b366680ffa0e148de81fea198c87bb643869fd97e5cb0", "908dc33ba80520f2f0f04e7890e3a3c0", "b6926d0ec82cec86c0d27ec9a33a0e0f", "f6efe1d76d270aac264aa35d03049d9ce63be1996d543aef00559219c8666f71", }, }; HDNode node; From 009850f6c9afcf60b4c6280afd46868b1a7a1fdd Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Thu, 22 Mar 2018 20:36:22 +0100 Subject: [PATCH 530/627] Fixed undefined behavior This fixes a shift by 32 and shifts on signed integer that overflow. --- address.c | 6 +++--- bignum.c | 18 +++++++++--------- bip32.c | 2 +- nem.c | 16 ++++++++-------- rand.c | 2 +- test_check.c | 2 +- 6 files changed, 23 insertions(+), 23 deletions(-) diff --git a/address.c b/address.c index 1e5587611..4d63f8ee3 100644 --- a/address.c +++ b/address.c @@ -45,12 +45,12 @@ bool address_check_prefix(const uint8_t *addr, uint32_t address_type) return address_type == (uint32_t)(addr[0]); } if (address_type <= 0xFFFF) { - return address_type == ((uint32_t)(addr[0] << 8) | (uint32_t)(addr[1])); + return address_type == (((uint32_t) addr[0] << 8) | ((uint32_t) addr[1])); } if (address_type <= 0xFFFFFF) { - return address_type == ((uint32_t)(addr[0] << 16) | (uint32_t)(addr[1] << 8) | (uint32_t)(addr[2])); + return address_type == (((uint32_t) addr[0] << 16) | ((uint32_t) addr[1] << 8) | ((uint32_t) addr[2])); } - return address_type == ((uint32_t)(addr[0] << 24) | (uint32_t)(addr[1] << 16) | (uint32_t)(addr[2] << 8) | (uint32_t)(addr[3])); + return address_type == (((uint32_t) addr[0] << 24) | ((uint32_t) addr[1] << 16) | ((uint32_t) addr[2] << 8) | ((uint32_t) addr[3])); } #if USE_ETHEREUM diff --git a/bignum.c b/bignum.c index 27e361d67..00600221d 100644 --- a/bignum.c +++ b/bignum.c @@ -111,13 +111,13 @@ void bn_read_be(const uint8_t *in_number, bignum256 *out_number) void bn_write_be(const bignum256 *in_number, uint8_t *out_number) { int i; - uint32_t temp = in_number->val[8] << 16; + uint32_t temp = in_number->val[8]; for (i = 0; i < 8; i++) { - // invariant: temp = (in_number >> 30*(8-i)) << (16 + 2i) + // invariant: temp = (in_number >> 30*(8-i)) uint32_t limb = in_number->val[7 - i]; - temp |= limb >> (14 - 2*i); + temp = (temp << (16 + 2*i)) | (limb >> (14 - 2*i)); write_be(out_number + i * 4, temp); - temp = limb << (18 + 2*i); + temp = limb; } } @@ -146,13 +146,13 @@ void bn_read_le(const uint8_t *in_number, bignum256 *out_number) void bn_write_le(const bignum256 *in_number, uint8_t *out_number) { int i; - uint32_t temp = in_number->val[8] << 16; + uint32_t temp = in_number->val[8]; for (i = 0; i < 8; i++) { - // invariant: temp = (in_number >> 30*(8-i)) << (16 + 2i) + // invariant: temp = (in_number >> 30*(8-i)) uint32_t limb = in_number->val[7 - i]; - temp |= limb >> (14 - 2*i); + temp = (temp << (16 + 2*i)) | (limb >> (14 - 2*i)); write_le(out_number + (7 - i) * 4, temp); - temp = limb << (18 + 2*i); + temp = limb; } } @@ -840,7 +840,7 @@ void bn_inverse(bignum256 *x, const bignum256 *prime) // s + factor*prime mod 2^k == 0 // i.e. factor = s * -1/prime mod 2^k. // Then compute s + factor*prime and shift right by k bits. - uint32_t mask = (1 << k) - 1; + uint32_t mask = (1u << k) - 1; uint32_t factor = (inverse * us.a[8]) & mask; temp = (us.a[8] + (uint64_t) pp[0] * factor) >> k; assert(((us.a[8] + pp[0] * factor) & mask) == 0); diff --git a/bip32.c b/bip32.c index fbccb9717..ea9005bc5 100644 --- a/bip32.c +++ b/bip32.c @@ -168,7 +168,7 @@ uint32_t hdnode_fingerprint(HDNode *node) hdnode_fill_public_key(node); hasher_Raw(node->curve->hasher_type, node->public_key, 33, digest); ripemd160(digest, 32, digest); - fingerprint = (digest[0] << 24) + (digest[1] << 16) + (digest[2] << 8) + digest[3]; + fingerprint = ((uint32_t) digest[0] << 24) + (digest[1] << 16) + (digest[2] << 8) + digest[3]; memzero(digest, sizeof(digest)); return fingerprint; } diff --git a/nem.c b/nem.c index d5faff008..8a4b7c52a 100644 --- a/nem.c +++ b/nem.c @@ -214,7 +214,7 @@ bool nem_transaction_create_transfer(nem_transaction_ctx *ctx, bool ret = nem_transaction_write_common(ctx, NEM_TRANSACTION_TYPE_TRANSFER, - network << 24 | (mosaics ? 2 : 1), + (uint32_t) network << 24 | (mosaics ? 2 : 1), timestamp, signer, fee, @@ -292,7 +292,7 @@ bool nem_transaction_create_multisig(nem_transaction_ctx *ctx, bool ret = nem_transaction_write_common(ctx, NEM_TRANSACTION_TYPE_MULTISIG, - network << 24 | 1, + (uint32_t) network << 24 | 1, timestamp, signer, fee, @@ -321,7 +321,7 @@ bool nem_transaction_create_multisig_signature(nem_transaction_ctx *ctx, bool ret = nem_transaction_write_common(ctx, NEM_TRANSACTION_TYPE_MULTISIG_SIGNATURE, - network << 24 | 1, + (uint32_t) network << 24 | 1, timestamp, signer, fee, @@ -361,7 +361,7 @@ bool nem_transaction_create_provision_namespace(nem_transaction_ctx *ctx, bool ret = nem_transaction_write_common(ctx, NEM_TRANSACTION_TYPE_PROVISION_NAMESPACE, - network << 24 | 1, + (uint32_t) network << 24 | 1, timestamp, signer, fee, @@ -420,7 +420,7 @@ bool nem_transaction_create_mosaic_creation(nem_transaction_ctx *ctx, bool ret = nem_transaction_write_common(ctx, NEM_TRANSACTION_TYPE_MOSAIC_CREATION, - network << 24 | 1, + (uint32_t) network << 24 | 1, timestamp, signer, fee, @@ -506,7 +506,7 @@ bool nem_transaction_create_mosaic_supply_change(nem_transaction_ctx *ctx, bool ret = nem_transaction_write_common(ctx, NEM_TRANSACTION_TYPE_MOSAIC_SUPPLY_CHANGE, - network << 24 | 1, + (uint32_t) network << 24 | 1, timestamp, signer, fee, @@ -544,7 +544,7 @@ bool nem_transaction_create_aggregate_modification(nem_transaction_ctx *ctx, bool ret = nem_transaction_write_common(ctx, NEM_TRANSACTION_TYPE_AGGREGATE_MODIFICATION, - network << 24 | (relative_change ? 2 : 1), + (uint32_t) network << 24 | (relative_change ? 2 : 1), timestamp, signer, fee, @@ -600,7 +600,7 @@ bool nem_transaction_create_importance_transfer(nem_transaction_ctx *ctx, bool ret = nem_transaction_write_common(ctx, NEM_TRANSACTION_TYPE_IMPORTANCE_TRANSFER, - network << 24 | 1, + (uint32_t) network << 24 | 1, timestamp, signer, fee, diff --git a/rand.c b/rand.c index 0b5c48577..4ec8ab2a6 100644 --- a/rand.c +++ b/rand.c @@ -45,7 +45,7 @@ uint32_t random32(void) srand((unsigned)time(NULL)); initialized = 1; } - return ((rand() % 0xFF) | ((rand() % 0xFF) << 8) | ((rand() % 0xFF) << 16) | ((rand() % 0xFF) << 24)); + return ((rand() & 0xFF) | ((rand() & 0xFF) << 8) | ((rand() & 0xFF) << 16) | ((uint32_t) (rand() & 0xFF) << 24)); } #endif /* RAND_PLATFORM_INDEPENDENT */ diff --git a/test_check.c b/test_check.c index 6c8fa810a..728f392f0 100644 --- a/test_check.c +++ b/test_check.c @@ -3028,7 +3028,7 @@ static void test_codepoints_curve(const ecdsa_curve *curve) { for (i = 0; i < 64; i++) { for (j = 0; j < 8; j++) { bn_zero(&a); - a.val[(4*i)/30] = (2*j+1) << (4*i % 30); + a.val[(4*i)/30] = (uint32_t) (2*j+1) << (4*i % 30); bn_normalize(&a); // note that this is not a trivial test. We add 64 curve // points in the table to get that particular curve point. From 3d7d99a3e38ee235c6bbb2ba336074ab4553a41d Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Thu, 22 Mar 2018 22:06:45 +0100 Subject: [PATCH 531/627] Fix out of bounds read b58tobin needs to check if there are more leading zeros requested by the address than there are available --- base58.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/base58.c b/base58.c index c3e960690..7d5670e5b 100644 --- a/base58.c +++ b/base58.c @@ -114,8 +114,13 @@ bool b58tobin(void *bin, size_t *binszp, const char *b58) binu = bin; for (i = 0; i < binsz; ++i) { - if (binu[i]) + if (binu[i]) { + if (zerocount > i) { + /* result too large */ + return false; + } break; + } --*binszp; } *binszp += zerocount; From c70e4401280fc0720922b393d71780dd2ac78611 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Tue, 3 Apr 2018 14:27:07 +0100 Subject: [PATCH 532/627] hasher: Replace hasher_Double with HASHER_*D This allows us to finely control when to use a single hash or a double hash in various places. For example, Bitcoin signatures use double SHA256, but Decred signatures use a single BLAKE256. However, both use double hashes for Base58. --- base58.c | 2 - bip32.c | 42 ++++++++----- bip32.h | 10 ++- ecdsa.c | 68 +++++++------------- ecdsa.h | 20 +++--- hasher.c | 22 +++++-- hasher.h | 4 +- nist256p1.c | 5 +- script.c | 8 +-- secp256k1.c | 10 ++- test_check.c | 150 ++++++++++++++++++++++---------------------- test_speed.c | 4 +- tools/xpubaddrgen.c | 2 +- 13 files changed, 181 insertions(+), 166 deletions(-) diff --git a/base58.c b/base58.c index 7d5670e5b..5afbbd0d4 100644 --- a/base58.c +++ b/base58.c @@ -136,7 +136,6 @@ int b58check(const void *bin, size_t binsz, HasherType hasher_type, const char * if (binsz < 4) return -4; hasher_Raw(hasher_type, bin, binsz - 4, buf); - hasher_Raw(hasher_type, buf, 32, buf); if (memcmp(&binc[binsz - 4], buf, 4)) return -1; @@ -202,7 +201,6 @@ int base58_encode_check(const uint8_t *data, int datalen, HasherType hasher_type uint8_t *hash = buf + datalen; memcpy(buf, data, datalen); hasher_Raw(hasher_type, data, datalen, hash); - hasher_Raw(hasher_type, hash, 32, hash); size_t res = strsize; bool success = b58enc(str, &res, buf, datalen + 4); memzero(buf, sizeof(buf)); diff --git a/bip32.c b/bip32.c index ea9005bc5..4ecfd6e61 100644 --- a/bip32.c +++ b/bip32.c @@ -51,27 +51,39 @@ const curve_info ed25519_info = { .bip32_name = "ed25519 seed", .params = NULL, - .hasher_type = HASHER_SHA2, + .hasher_bip32 = HASHER_SHA2, + .hasher_base58 = HASHER_SHA2D, + .hasher_sign = HASHER_SHA2D, + .hasher_pubkey = HASHER_SHA2, }; const curve_info ed25519_sha3_info = { .bip32_name = "ed25519-sha3 seed", .params = NULL, - .hasher_type = HASHER_SHA2, + .hasher_bip32 = HASHER_SHA2, + .hasher_base58 = HASHER_SHA2D, + .hasher_sign = HASHER_SHA2D, + .hasher_pubkey = HASHER_SHA2, }; #if USE_KECCAK const curve_info ed25519_keccak_info = { .bip32_name = "ed25519-keccak seed", .params = NULL, - .hasher_type = HASHER_SHA2, + .hasher_bip32 = HASHER_SHA2, + .hasher_base58 = HASHER_SHA2D, + .hasher_sign = HASHER_SHA2D, + .hasher_pubkey = HASHER_SHA2, }; #endif const curve_info curve25519_info = { .bip32_name = "curve25519 seed", .params = NULL, - .hasher_type = HASHER_SHA2, + .hasher_bip32 = HASHER_SHA2, + .hasher_base58 = HASHER_SHA2D, + .hasher_sign = HASHER_SHA2D, + .hasher_pubkey = HASHER_SHA2, }; int hdnode_from_xpub(uint32_t depth, uint32_t child_num, const uint8_t *chain_code, const uint8_t *public_key, const char* curve, HDNode *out) @@ -166,7 +178,7 @@ uint32_t hdnode_fingerprint(HDNode *node) uint32_t fingerprint; hdnode_fill_public_key(node); - hasher_Raw(node->curve->hasher_type, node->public_key, 33, digest); + hasher_Raw(node->curve->hasher_bip32, node->public_key, 33, digest); ripemd160(digest, 32, digest); fingerprint = ((uint32_t) digest[0] << 24) + (digest[1] << 16) + (digest[2] << 8) + digest[3]; memzero(digest, sizeof(digest)); @@ -300,7 +312,7 @@ int hdnode_public_ckd(HDNode *inout, uint32_t i) return 1; } -void hdnode_public_ckd_address_optimized(const curve_point *pub, const uint8_t *chain_code, uint32_t i, uint32_t version, HasherType hasher_type, char *addr, int addrsize, int addrformat) +void hdnode_public_ckd_address_optimized(const curve_point *pub, const uint8_t *chain_code, uint32_t i, uint32_t version, HasherType hasher_pubkey, HasherType hasher_base58, char *addr, int addrsize, int addrformat) { uint8_t child_pubkey[33]; curve_point b; @@ -311,10 +323,10 @@ void hdnode_public_ckd_address_optimized(const curve_point *pub, const uint8_t * switch (addrformat) { case 1: // Segwit-in-P2SH - ecdsa_get_address_segwit_p2sh(child_pubkey, version, hasher_type, addr, addrsize); + ecdsa_get_address_segwit_p2sh(child_pubkey, version, hasher_pubkey, hasher_base58, addr, addrsize); break; default: // normal address - ecdsa_get_address(child_pubkey, version, hasher_type, addr, addrsize); + ecdsa_get_address(child_pubkey, version, hasher_pubkey, hasher_base58, addr, addrsize); break; } } @@ -396,13 +408,13 @@ int hdnode_private_ckd_cached(HDNode *inout, const uint32_t *i, size_t i_count, void hdnode_get_address_raw(HDNode *node, uint32_t version, uint8_t *addr_raw) { hdnode_fill_public_key(node); - ecdsa_get_address_raw(node->public_key, version, node->curve->hasher_type, addr_raw); + ecdsa_get_address_raw(node->public_key, version, node->curve->hasher_pubkey, addr_raw); } void hdnode_get_address(HDNode *node, uint32_t version, char *addr, int addrsize) { hdnode_fill_public_key(node); - ecdsa_get_address(node->public_key, version, node->curve->hasher_type, addr, addrsize); + ecdsa_get_address(node->public_key, version, node->curve->hasher_pubkey, node->curve->hasher_base58, addr, addrsize); } void hdnode_fill_public_key(HDNode *node) @@ -540,10 +552,10 @@ int hdnode_nem_decrypt(const HDNode *node, const ed25519_public_key public_key, // msg is a data to be signed // msg_len is the message length -int hdnode_sign(HDNode *node, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64])) +int hdnode_sign(HDNode *node, const uint8_t *msg, uint32_t msg_len, HasherType hasher_sign, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64])) { if (node->curve->params) { - return ecdsa_sign(node->curve->params, node->curve->hasher_type, node->private_key, msg, msg_len, sig, pby, is_canonical); + return ecdsa_sign(node->curve->params, hasher_sign, node->private_key, msg, msg_len, sig, pby, is_canonical); } else if (node->curve == &curve25519_info) { return 1; // signatures are not supported } else { @@ -568,7 +580,7 @@ int hdnode_sign_digest(HDNode *node, const uint8_t *digest, uint8_t *sig, uint8_ } else if (node->curve == &curve25519_info) { return 1; // signatures are not supported } else { - return hdnode_sign(node, digest, 32, sig, pby, is_canonical); + return hdnode_sign(node, digest, 32, 0, sig, pby, is_canonical); } } @@ -609,7 +621,7 @@ static int hdnode_serialize(const HDNode *node, uint32_t fingerprint, uint32_t v node_data[45] = 0; memcpy(node_data + 46, node->private_key, 32); } - int ret = base58_encode_check(node_data, sizeof(node_data), node->curve->hasher_type, str, strsize); + int ret = base58_encode_check(node_data, sizeof(node_data), node->curve->hasher_base58, str, strsize); memzero(node_data, sizeof(node_data)); return ret; } @@ -630,7 +642,7 @@ int hdnode_deserialize(const char *str, uint32_t version_public, uint32_t versio uint8_t node_data[78]; memset(node, 0, sizeof(HDNode)); node->curve = get_curve_by_name(curve); - if (base58_decode_check(str, node->curve->hasher_type, node_data, sizeof(node_data)) != sizeof(node_data)) { + if (base58_decode_check(str, node->curve->hasher_base58, node_data, sizeof(node_data)) != sizeof(node_data)) { return -1; } uint32_t version = read_be(node_data); diff --git a/bip32.h b/bip32.h index 9e73d75ca..081639842 100644 --- a/bip32.h +++ b/bip32.h @@ -34,7 +34,11 @@ typedef struct { const char *bip32_name; // string for generating BIP32 xprv from seed const ecdsa_curve *params; // ecdsa curve parameters, null for ed25519 - HasherType hasher_type; // hasher type for BIP32 and ECDSA + + HasherType hasher_bip32; + HasherType hasher_base58; + HasherType hasher_sign; + HasherType hasher_pubkey; } curve_info; typedef struct { @@ -60,7 +64,7 @@ int hdnode_public_ckd_cp(const ecdsa_curve *curve, const curve_point *parent, co int hdnode_public_ckd(HDNode *inout, uint32_t i); -void hdnode_public_ckd_address_optimized(const curve_point *pub, const uint8_t *chain_code, uint32_t i, uint32_t version, HasherType hasher_type, char *addr, int addrsize, int addrformat); +void hdnode_public_ckd_address_optimized(const curve_point *pub, const uint8_t *chain_code, uint32_t i, uint32_t version, HasherType hasher_pubkey, HasherType hasher_base58, char *addr, int addrsize, int addrformat); #if USE_BIP32_CACHE int hdnode_private_ckd_cached(HDNode *inout, const uint32_t *i, size_t i_count, uint32_t *fingerprint); @@ -81,7 +85,7 @@ int hdnode_nem_encrypt(const HDNode *node, const ed25519_public_key public_key, int hdnode_nem_decrypt(const HDNode *node, const ed25519_public_key public_key, uint8_t *iv, const uint8_t *salt, const uint8_t *payload, size_t size, uint8_t *buffer); #endif -int hdnode_sign(HDNode *node, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64])); +int hdnode_sign(HDNode *node, const uint8_t *msg, uint32_t msg_len, HasherType hasher_sign, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64])); int hdnode_sign_digest(HDNode *node, const uint8_t *digest, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64])); int hdnode_get_shared_key(const HDNode *node, const uint8_t *peer_public_key, uint8_t *session_key, int *result_size); diff --git a/ecdsa.c b/ecdsa.c index 2e679a8af..469ff9cd8 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -715,28 +715,16 @@ void generate_k_rfc6979(bignum256 *k, rfc6979_state *state) // msg is a data to be signed // msg_len is the message length -int ecdsa_sign(const ecdsa_curve *curve, HasherType hasher_type, const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64])) +int ecdsa_sign(const ecdsa_curve *curve, HasherType hasher_sign, const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64])) { uint8_t hash[32]; - hasher_Raw(hasher_type, msg, msg_len, hash); + hasher_Raw(hasher_sign, msg, msg_len, hash); int res = ecdsa_sign_digest(curve, priv_key, hash, sig, pby, is_canonical); memzero(hash, sizeof(hash)); return res; } -// msg is a data to be signed -// msg_len is the message length -int ecdsa_sign_double(const ecdsa_curve *curve, HasherType hasher_type, const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64])) -{ - uint8_t hash[32]; - hasher_Raw(hasher_type, msg, msg_len, hash); - hasher_Raw(hasher_type, hash, 32, hash); - int res = ecdsa_sign_digest(curve, priv_key, hash, sig, pby, is_canonical); - memzero(hash, sizeof(hash)); - return res; -} - // uses secp256k1 curve // priv_key is a 32 byte big endian stored number // sig is 64 bytes long array for the signature @@ -880,75 +868,75 @@ int ecdsa_uncompress_pubkey(const ecdsa_curve *curve, const uint8_t *pub_key, ui return 1; } -void ecdsa_get_pubkeyhash(const uint8_t *pub_key, HasherType hasher_type, uint8_t *pubkeyhash) +void ecdsa_get_pubkeyhash(const uint8_t *pub_key, HasherType hasher_pubkey, uint8_t *pubkeyhash) { uint8_t h[HASHER_DIGEST_LENGTH]; if (pub_key[0] == 0x04) { // uncompressed format - hasher_Raw(hasher_type, pub_key, 65, h); + hasher_Raw(hasher_pubkey, pub_key, 65, h); } else if (pub_key[0] == 0x00) { // point at infinity - hasher_Raw(hasher_type, pub_key, 1, h); + hasher_Raw(hasher_pubkey, pub_key, 1, h); } else { // expecting compressed format - hasher_Raw(hasher_type, pub_key, 33, h); + hasher_Raw(hasher_pubkey, pub_key, 33, h); } ripemd160(h, HASHER_DIGEST_LENGTH, pubkeyhash); memzero(h, sizeof(h)); } -void ecdsa_get_address_raw(const uint8_t *pub_key, uint32_t version, HasherType hasher_type, uint8_t *addr_raw) +void ecdsa_get_address_raw(const uint8_t *pub_key, uint32_t version, HasherType hasher_pubkey, uint8_t *addr_raw) { size_t prefix_len = address_prefix_bytes_len(version); address_write_prefix_bytes(version, addr_raw); - ecdsa_get_pubkeyhash(pub_key, hasher_type, addr_raw + prefix_len); + ecdsa_get_pubkeyhash(pub_key, hasher_pubkey, addr_raw + prefix_len); } -void ecdsa_get_address(const uint8_t *pub_key, uint32_t version, HasherType hasher_type, char *addr, int addrsize) +void ecdsa_get_address(const uint8_t *pub_key, uint32_t version, HasherType hasher_pubkey, HasherType hasher_base58, char *addr, int addrsize) { uint8_t raw[MAX_ADDR_RAW_SIZE]; size_t prefix_len = address_prefix_bytes_len(version); - ecdsa_get_address_raw(pub_key, version, hasher_type, raw); - base58_encode_check(raw, 20 + prefix_len, hasher_type, addr, addrsize); + ecdsa_get_address_raw(pub_key, version, hasher_pubkey, raw); + base58_encode_check(raw, 20 + prefix_len, hasher_base58, addr, addrsize); // not as important to clear this one, but we might as well memzero(raw, sizeof(raw)); } -void ecdsa_get_address_segwit_p2sh_raw(const uint8_t *pub_key, uint32_t version, HasherType hasher_type, uint8_t *addr_raw) +void ecdsa_get_address_segwit_p2sh_raw(const uint8_t *pub_key, uint32_t version, HasherType hasher_pubkey, uint8_t *addr_raw) { size_t prefix_len = address_prefix_bytes_len(version); uint8_t digest[32]; addr_raw[0] = 0; // version byte addr_raw[1] = 20; // push 20 bytes - ecdsa_get_pubkeyhash(pub_key, hasher_type, addr_raw + 2); - hasher_Raw(hasher_type, addr_raw, 22, digest); + ecdsa_get_pubkeyhash(pub_key, hasher_pubkey, addr_raw + 2); + hasher_Raw(hasher_pubkey, addr_raw, 22, digest); address_write_prefix_bytes(version, addr_raw); ripemd160(digest, 32, addr_raw + prefix_len); } -void ecdsa_get_address_segwit_p2sh(const uint8_t *pub_key, uint32_t version, HasherType hasher_type, char *addr, int addrsize) +void ecdsa_get_address_segwit_p2sh(const uint8_t *pub_key, uint32_t version, HasherType hasher_pubkey, HasherType hasher_base58, char *addr, int addrsize) { uint8_t raw[MAX_ADDR_RAW_SIZE]; size_t prefix_len = address_prefix_bytes_len(version); - ecdsa_get_address_segwit_p2sh_raw(pub_key, version, hasher_type, raw); - base58_encode_check(raw, prefix_len + 20, hasher_type, addr, addrsize); + ecdsa_get_address_segwit_p2sh_raw(pub_key, version, hasher_pubkey, raw); + base58_encode_check(raw, prefix_len + 20, hasher_base58, addr, addrsize); memzero(raw, sizeof(raw)); } -void ecdsa_get_wif(const uint8_t *priv_key, uint32_t version, HasherType hasher_type, char *wif, int wifsize) +void ecdsa_get_wif(const uint8_t *priv_key, uint32_t version, HasherType hasher_base58, char *wif, int wifsize) { uint8_t wif_raw[MAX_WIF_RAW_SIZE]; size_t prefix_len = address_prefix_bytes_len(version); address_write_prefix_bytes(version, wif_raw); memcpy(wif_raw + prefix_len, priv_key, 32); wif_raw[prefix_len + 32] = 0x01; - base58_encode_check(wif_raw, prefix_len + 32 + 1, hasher_type, wif, wifsize); + base58_encode_check(wif_raw, prefix_len + 32 + 1, hasher_base58, wif, wifsize); // private keys running around our stack can cause trouble memzero(wif_raw, sizeof(wif_raw)); } -int ecdsa_address_decode(const char *addr, uint32_t version, HasherType hasher_type, uint8_t *out) +int ecdsa_address_decode(const char *addr, uint32_t version, HasherType hasher_base58, uint8_t *out) { if (!addr) return 0; int prefix_len = address_prefix_bytes_len(version); - return base58_decode_check(addr, hasher_type, out, 20 + prefix_len) == 20 + prefix_len + return base58_decode_check(addr, hasher_base58, out, 20 + prefix_len) == 20 + prefix_len && address_check_prefix(out, version); } @@ -1029,20 +1017,10 @@ int ecdsa_validate_pubkey(const ecdsa_curve *curve, const curve_point *pub) // msg is a data that was signed // msg_len is the message length -int ecdsa_verify(const ecdsa_curve *curve, HasherType hasher_type, const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, uint32_t msg_len) -{ - uint8_t hash[32]; - hasher_Raw(hasher_type, msg, msg_len, hash); - int res = ecdsa_verify_digest(curve, pub_key, sig, hash); - memzero(hash, sizeof(hash)); - return res; -} - -int ecdsa_verify_double(const ecdsa_curve *curve, HasherType hasher_type, const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, uint32_t msg_len) +int ecdsa_verify(const ecdsa_curve *curve, HasherType hasher_sign, const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, uint32_t msg_len) { uint8_t hash[32]; - hasher_Raw(hasher_type, msg, msg_len, hash); - hasher_Raw(hasher_type, hash, 32, hash); + hasher_Raw(hasher_sign, msg, msg_len, hash); int res = ecdsa_verify_digest(curve, pub_key, sig, hash); memzero(hash, sizeof(hash)); return res; diff --git a/ecdsa.h b/ecdsa.h index d9bd1d1e6..ad5e47bfa 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -73,23 +73,21 @@ int ecdh_multiply(const ecdsa_curve *curve, const uint8_t *priv_key, const uint8 void uncompress_coords(const ecdsa_curve *curve, uint8_t odd, const bignum256 *x, bignum256 *y); int ecdsa_uncompress_pubkey(const ecdsa_curve *curve, const uint8_t *pub_key, uint8_t *uncompressed); -int ecdsa_sign(const ecdsa_curve *curve, HasherType hasher_type, const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64])); -int ecdsa_sign_double(const ecdsa_curve *curve, HasherType hasher_type, const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64])); +int ecdsa_sign(const ecdsa_curve *curve, HasherType hasher_sign, const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64])); int ecdsa_sign_digest(const ecdsa_curve *curve, const uint8_t *priv_key, const uint8_t *digest, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64])); void ecdsa_get_public_key33(const ecdsa_curve *curve, const uint8_t *priv_key, uint8_t *pub_key); void ecdsa_get_public_key65(const ecdsa_curve *curve, const uint8_t *priv_key, uint8_t *pub_key); -void ecdsa_get_pubkeyhash(const uint8_t *pub_key, HasherType hasher_type, uint8_t *pubkeyhash); -void ecdsa_get_address_raw(const uint8_t *pub_key, uint32_t version, HasherType hasher_type, uint8_t *addr_raw); -void ecdsa_get_address(const uint8_t *pub_key, uint32_t version, HasherType hasher_type, char *addr, int addrsize); -void ecdsa_get_address_segwit_p2sh_raw(const uint8_t *pub_key, uint32_t version, HasherType hasher_type, uint8_t *addr_raw); -void ecdsa_get_address_segwit_p2sh(const uint8_t *pub_key, uint32_t version, HasherType hasher_type, char *addr, int addrsize); -void ecdsa_get_wif(const uint8_t *priv_key, uint32_t version, HasherType hasher_type, char *wif, int wifsize); +void ecdsa_get_pubkeyhash(const uint8_t *pub_key, HasherType hasher_pubkey, uint8_t *pubkeyhash); +void ecdsa_get_address_raw(const uint8_t *pub_key, uint32_t version, HasherType hasher_pubkey, uint8_t *addr_raw); +void ecdsa_get_address(const uint8_t *pub_key, uint32_t version, HasherType hasher_pubkey, HasherType hasher_base58, char *addr, int addrsize); +void ecdsa_get_address_segwit_p2sh_raw(const uint8_t *pub_key, uint32_t version, HasherType hasher_pubkey, uint8_t *addr_raw); +void ecdsa_get_address_segwit_p2sh(const uint8_t *pub_key, uint32_t version, HasherType hasher_pubkey, HasherType hasher_base58, char *addr, int addrsize); +void ecdsa_get_wif(const uint8_t *priv_key, uint32_t version, HasherType hasher_base58, char *wif, int wifsize); -int ecdsa_address_decode(const char *addr, uint32_t version, HasherType hasher_type, uint8_t *out); +int ecdsa_address_decode(const char *addr, uint32_t version, HasherType hasher_base58, uint8_t *out); int ecdsa_read_pubkey(const ecdsa_curve *curve, const uint8_t *pub_key, curve_point *pub); int ecdsa_validate_pubkey(const ecdsa_curve *curve, const curve_point *pub); -int ecdsa_verify(const ecdsa_curve *curve, HasherType hasher_type, const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, uint32_t msg_len); -int ecdsa_verify_double(const ecdsa_curve *curve, HasherType hasher_type, const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, uint32_t msg_len); +int ecdsa_verify(const ecdsa_curve *curve, HasherType hasher_sign, const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, uint32_t msg_len); int ecdsa_verify_digest(const ecdsa_curve *curve, const uint8_t *pub_key, const uint8_t *sig, const uint8_t *digest); int ecdsa_verify_digest_recover(const ecdsa_curve *curve, uint8_t *pub_key, const uint8_t *sig, const uint8_t *digest, int recid); int ecdsa_sig_to_der(const uint8_t *sig, uint8_t *der); diff --git a/hasher.c b/hasher.c index edd1ac766..69c9219ea 100644 --- a/hasher.c +++ b/hasher.c @@ -27,9 +27,11 @@ void hasher_Init(Hasher *hasher, HasherType type) { switch (hasher->type) { case HASHER_SHA2: + case HASHER_SHA2D: sha256_Init(&hasher->ctx.sha2); break; case HASHER_BLAKE: + case HASHER_BLAKED: blake256_Init(&hasher->ctx.blake); break; } @@ -42,9 +44,11 @@ void hasher_Reset(Hasher *hasher) { void hasher_Update(Hasher *hasher, const uint8_t *data, size_t length) { switch (hasher->type) { case HASHER_SHA2: + case HASHER_SHA2D: sha256_Update(&hasher->ctx.sha2, data, length); break; case HASHER_BLAKE: + case HASHER_BLAKED: blake256_Update(&hasher->ctx.blake, data, length); break; } @@ -53,17 +57,27 @@ void hasher_Update(Hasher *hasher, const uint8_t *data, size_t length) { void hasher_Final(Hasher *hasher, uint8_t hash[HASHER_DIGEST_LENGTH]) { switch (hasher->type) { case HASHER_SHA2: + case HASHER_SHA2D: sha256_Final(&hasher->ctx.sha2, hash); break; case HASHER_BLAKE: + case HASHER_BLAKED: blake256_Final(&hasher->ctx.blake, hash); break; } -} -void hasher_Double(Hasher *hasher, uint8_t hash[HASHER_DIGEST_LENGTH]) { - hasher_Final(hasher, hash); - hasher_Raw(hasher->type, hash, HASHER_DIGEST_LENGTH, hash); + switch (hasher->type) { + case HASHER_SHA2D: + hasher_Raw(HASHER_SHA2, hash, HASHER_DIGEST_LENGTH, hash); + break; + + case HASHER_BLAKED: + hasher_Raw(HASHER_BLAKE, hash, HASHER_DIGEST_LENGTH, hash); + break; + + default: + break; + } } void hasher_Raw(HasherType type, const uint8_t *data, size_t length, uint8_t hash[HASHER_DIGEST_LENGTH]) { diff --git a/hasher.h b/hasher.h index 57b70b231..575617031 100644 --- a/hasher.h +++ b/hasher.h @@ -34,6 +34,9 @@ typedef enum { HASHER_SHA2, HASHER_BLAKE, + + HASHER_SHA2D, + HASHER_BLAKED, } HasherType; typedef struct { @@ -49,7 +52,6 @@ void hasher_Init(Hasher *hasher, HasherType type); void hasher_Reset(Hasher *hasher); void hasher_Update(Hasher *hasher, const uint8_t *data, size_t length); void hasher_Final(Hasher *hasher, uint8_t hash[HASHER_DIGEST_LENGTH]); -void hasher_Double(Hasher *hasher, uint8_t hash[HASHER_DIGEST_LENGTH]); void hasher_Raw(HasherType type, const uint8_t *data, size_t length, uint8_t hash[HASHER_DIGEST_LENGTH]); diff --git a/nist256p1.c b/nist256p1.c index ef61ac5e0..1581cce87 100644 --- a/nist256p1.c +++ b/nist256p1.c @@ -58,5 +58,8 @@ const ecdsa_curve nist256p1 = { const curve_info nist256p1_info = { .bip32_name = "Nist256p1 seed", .params = &nist256p1, - .hasher_type = HASHER_SHA2, + .hasher_bip32 = HASHER_SHA2, + .hasher_base58 = HASHER_SHA2D, + .hasher_sign = HASHER_SHA2D, + .hasher_pubkey = HASHER_SHA2, }; diff --git a/script.c b/script.c index ed6f821a0..3ddb3a658 100644 --- a/script.c +++ b/script.c @@ -32,14 +32,14 @@ int script_output_to_address(const uint8_t *script, int scriptlen, char *addr, i if (scriptlen == 25 && script[0] == 0x76 && script[1] == 0xA9 && script[2] == 0x14 && script[23] == 0x88 && script[24] == 0xAC) { raw[0] = 0x00; memcpy(raw + 1, script + 3, 20); - return base58_encode_check(raw, 1 + 20, HASHER_SHA2, addr, addrsize); + return base58_encode_check(raw, 1 + 20, HASHER_SHA2D, addr, addrsize); } // P2SH if (scriptlen == 23 && script[0] == 0xA9 && script[1] == 0x14 && script[22] == 0x87) { raw[0] = 0x05; memcpy(raw + 1, script + 2, 20); - return base58_encode_check(raw, 1 + 20, HASHER_SHA2, addr, addrsize); + return base58_encode_check(raw, 1 + 20, HASHER_SHA2D, addr, addrsize); } // P2WPKH @@ -48,7 +48,7 @@ int script_output_to_address(const uint8_t *script, int scriptlen, char *addr, i raw[1] = 0x00; raw[2] = 0x00; memcpy(raw + 3, script + 2, 20); - return base58_encode_check(raw, 3 + 20, HASHER_SHA2, addr, addrsize); + return base58_encode_check(raw, 3 + 20, HASHER_SHA2D, addr, addrsize); } // P2WSH @@ -57,7 +57,7 @@ int script_output_to_address(const uint8_t *script, int scriptlen, char *addr, i raw[1] = 0x00; raw[2] = 0x00; memcpy(raw + 3, script + 2, 32); - return base58_encode_check(raw, 3 + 32, HASHER_SHA2, addr, addrsize); + return base58_encode_check(raw, 3 + 32, HASHER_SHA2D, addr, addrsize); } return 0; diff --git a/secp256k1.c b/secp256k1.c index 155d2c17d..033a34636 100644 --- a/secp256k1.c +++ b/secp256k1.c @@ -58,11 +58,17 @@ const ecdsa_curve secp256k1 = { const curve_info secp256k1_info = { .bip32_name = "Bitcoin seed", .params = &secp256k1, - .hasher_type = HASHER_SHA2, + .hasher_bip32 = HASHER_SHA2, + .hasher_base58 = HASHER_SHA2D, + .hasher_sign = HASHER_SHA2D, + .hasher_pubkey = HASHER_SHA2, }; const curve_info secp256k1_decred_info = { .bip32_name = "Decred seed", .params = &secp256k1, - .hasher_type = HASHER_BLAKE, + .hasher_bip32 = HASHER_BLAKE, + .hasher_base58 = HASHER_BLAKED, + .hasher_sign = HASHER_BLAKE, + .hasher_pubkey = HASHER_BLAKE, }; diff --git a/test_check.c b/test_check.c index 728f392f0..5a5ad1fca 100644 --- a/test_check.c +++ b/test_check.c @@ -736,11 +736,11 @@ START_TEST(test_base58) int len = strlen(*raw) / 2; memcpy(rawn, fromhex(*raw), len); - r = base58_encode_check(rawn, len, HASHER_SHA2, strn, sizeof(strn)); + r = base58_encode_check(rawn, len, HASHER_SHA2D, strn, sizeof(strn)); ck_assert_int_eq((size_t)r, strlen(*str) + 1); ck_assert_str_eq(strn, *str); - r = base58_decode_check(strn, HASHER_SHA2, rawn, len); + r = base58_decode_check(strn, HASHER_SHA2D, rawn, len); ck_assert_int_eq(r, len); ck_assert_mem_eq(rawn, fromhex(*raw), len); @@ -1143,9 +1143,9 @@ START_TEST(test_bip32_optimized) memcpy(&node, &root, sizeof(HDNode)); hdnode_public_ckd(&node, i); hdnode_fill_public_key(&node); - ecdsa_get_address(node.public_key, 0, HASHER_SHA2, addr1, sizeof(addr1)); + ecdsa_get_address(node.public_key, 0, HASHER_SHA2, HASHER_SHA2D, addr1, sizeof(addr1)); // optimized - hdnode_public_ckd_address_optimized(&pub, root.chain_code, i, 0, HASHER_SHA2, addr2, sizeof(addr2), 0); + hdnode_public_ckd_address_optimized(&pub, root.chain_code, i, 0, HASHER_SHA2, HASHER_SHA2D, addr2, sizeof(addr2), 0); // check ck_assert_str_eq(addr1, addr2); } @@ -2766,50 +2766,50 @@ START_TEST(test_address) uint8_t pub_key[65]; memcpy(pub_key, fromhex("0226659c1cf7321c178c07437150639ff0c5b7679c7ea195253ed9abda2e081a37"), 33); - ecdsa_get_address(pub_key, 0, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "139MaMHp3Vjo8o4x8N1ZLWEtovLGvBsg6s"); - ecdsa_get_address(pub_key, 111, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "mhfJsQNnrXB3uuYZqvywARTDfuvyjg4RBh"); - ecdsa_get_address(pub_key, 52, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "MxiimznnxsqMfLKTQBL8Z2PoY9jKpjgkCu"); - ecdsa_get_address(pub_key, 48, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "LMNJqZbe89yrPbm7JVzrcXJf28hZ1rKPaH"); - ecdsa_get_address_segwit_p2sh(pub_key, 5, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "34PyTHn74syS796eTgsyoLfwoBC3cwLn6p"); + ecdsa_get_address(pub_key, 0, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "139MaMHp3Vjo8o4x8N1ZLWEtovLGvBsg6s"); + ecdsa_get_address(pub_key, 111, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "mhfJsQNnrXB3uuYZqvywARTDfuvyjg4RBh"); + ecdsa_get_address(pub_key, 52, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "MxiimznnxsqMfLKTQBL8Z2PoY9jKpjgkCu"); + ecdsa_get_address(pub_key, 48, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "LMNJqZbe89yrPbm7JVzrcXJf28hZ1rKPaH"); + ecdsa_get_address_segwit_p2sh(pub_key, 5, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "34PyTHn74syS796eTgsyoLfwoBC3cwLn6p"); memcpy(pub_key, fromhex("025b1654a0e78d28810094f6c5a96b8efb8a65668b578f170ac2b1f83bc63ba856"), 33); - ecdsa_get_address(pub_key, 0, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "19Ywfm3witp6C1yBMy4NRYHY2347WCRBfQ"); - ecdsa_get_address(pub_key, 111, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "mp4txp8vXvFLy8So5Y2kFTVrt2epN6YzdP"); - ecdsa_get_address(pub_key, 52, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "N58JsQYveGueiZDgdnNwe4SSkGTAToutAY"); - ecdsa_get_address(pub_key, 48, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "LTmtvyMmoZ49SpfLY73fhZMJEFRPdyohKh"); - ecdsa_get_address_segwit_p2sh(pub_key, 5, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "35trq6eeuHf6VL9L8pQv46x3vegHnHoTuB"); + ecdsa_get_address(pub_key, 0, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "19Ywfm3witp6C1yBMy4NRYHY2347WCRBfQ"); + ecdsa_get_address(pub_key, 111, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "mp4txp8vXvFLy8So5Y2kFTVrt2epN6YzdP"); + ecdsa_get_address(pub_key, 52, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "N58JsQYveGueiZDgdnNwe4SSkGTAToutAY"); + ecdsa_get_address(pub_key, 48, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "LTmtvyMmoZ49SpfLY73fhZMJEFRPdyohKh"); + ecdsa_get_address_segwit_p2sh(pub_key, 5, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "35trq6eeuHf6VL9L8pQv46x3vegHnHoTuB"); memcpy(pub_key, fromhex("03433f246a12e6486a51ff08802228c61cf895175a9b49ed4766ea9a9294a3c7fe"), 33); - ecdsa_get_address(pub_key, 0, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "1FWE2bn3MWhc4QidcF6AvEWpK77sSi2cAP"); - ecdsa_get_address(pub_key, 111, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "mv2BKes2AY8rqXCFKp4Yk9j9B6iaMfWRLN"); - ecdsa_get_address(pub_key, 52, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "NB5bEFH2GtoAawy8t4Qk8kfj3LWvQs3MhB"); - ecdsa_get_address(pub_key, 48, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "LZjBHp5sSAwfKDQnnP5UCFaaXKV9YheGxQ"); - ecdsa_get_address_segwit_p2sh(pub_key, 5, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "3456DYaKUWuY6RWWw8Hp5CftHLcQN29h9Y"); + ecdsa_get_address(pub_key, 0, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "1FWE2bn3MWhc4QidcF6AvEWpK77sSi2cAP"); + ecdsa_get_address(pub_key, 111, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "mv2BKes2AY8rqXCFKp4Yk9j9B6iaMfWRLN"); + ecdsa_get_address(pub_key, 52, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "NB5bEFH2GtoAawy8t4Qk8kfj3LWvQs3MhB"); + ecdsa_get_address(pub_key, 48, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "LZjBHp5sSAwfKDQnnP5UCFaaXKV9YheGxQ"); + ecdsa_get_address_segwit_p2sh(pub_key, 5, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "3456DYaKUWuY6RWWw8Hp5CftHLcQN29h9Y"); memcpy(pub_key, fromhex("03aeb03abeee0f0f8b4f7a5d65ce31f9570cef9f72c2dd8a19b4085a30ab033d48"), 33); - ecdsa_get_address(pub_key, 0, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "1yrZb8dhdevoqpUEGi2tUccUEeiMKeLcs"); - ecdsa_get_address(pub_key, 111, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "mgVoreDcWf6BaxJ5wqgQiPpwLEFRLSr8U8"); - ecdsa_get_address(pub_key, 52, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "MwZDmEdcd1kVLP4yW62c6zmXCU3mNbveDo"); - ecdsa_get_address(pub_key, 48, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "LLCopoSTnHtz4eWdQQhLAVgNgT1zTi4QBK"); - ecdsa_get_address_segwit_p2sh(pub_key, 5, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "3DBU4tJ9tkMR9fnmCtjW48kjvseoNLQZXd"); + ecdsa_get_address(pub_key, 0, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "1yrZb8dhdevoqpUEGi2tUccUEeiMKeLcs"); + ecdsa_get_address(pub_key, 111, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "mgVoreDcWf6BaxJ5wqgQiPpwLEFRLSr8U8"); + ecdsa_get_address(pub_key, 52, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "MwZDmEdcd1kVLP4yW62c6zmXCU3mNbveDo"); + ecdsa_get_address(pub_key, 48, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "LLCopoSTnHtz4eWdQQhLAVgNgT1zTi4QBK"); + ecdsa_get_address_segwit_p2sh(pub_key, 5, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "3DBU4tJ9tkMR9fnmCtjW48kjvseoNLQZXd"); memcpy(pub_key, fromhex("0496e8f2093f018aff6c2e2da5201ee528e2c8accbf9cac51563d33a7bb74a016054201c025e2a5d96b1629b95194e806c63eb96facaedc733b1a4b70ab3b33e3a"), 65); - ecdsa_get_address(pub_key, 0, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "194SZbL75xCCGBbKtMsyWLE5r9s2V6mhVM"); - ecdsa_get_address(pub_key, 111, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "moaPreR5tydT3J4wbvrMLFSQi9TjPCiZc6"); - ecdsa_get_address(pub_key, 52, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "N4domEq61LHkniqqABCYirNzaPG5NRU8GH"); - ecdsa_get_address(pub_key, 48, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "LTHPpodwAcSFWzHV4VsGnMHr4NEJajMnKX"); + ecdsa_get_address(pub_key, 0, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "194SZbL75xCCGBbKtMsyWLE5r9s2V6mhVM"); + ecdsa_get_address(pub_key, 111, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "moaPreR5tydT3J4wbvrMLFSQi9TjPCiZc6"); + ecdsa_get_address(pub_key, 52, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "N4domEq61LHkniqqABCYirNzaPG5NRU8GH"); + ecdsa_get_address(pub_key, 48, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "LTHPpodwAcSFWzHV4VsGnMHr4NEJajMnKX"); memcpy(pub_key, fromhex("0498010f8a687439ff497d3074beb4519754e72c4b6220fb669224749591dde416f3961f8ece18f8689bb32235e436874d2174048b86118a00afbd5a4f33a24f0f"), 65); - ecdsa_get_address(pub_key, 0, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "1A2WfBD4BJFwYHFPc5KgktqtbdJLBuVKc4"); - ecdsa_get_address(pub_key, 111, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "mpYTxEJ2zKhCKPj1KeJ4ap4DTcu39T3uzD"); - ecdsa_get_address(pub_key, 52, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "N5bsrpi36gMW4pVtsteFyQzoKrhPE7nkxK"); - ecdsa_get_address(pub_key, 48, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "LUFTvPWtFxVzo5wYnDJz2uueoqfcMYiuxH"); + ecdsa_get_address(pub_key, 0, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "1A2WfBD4BJFwYHFPc5KgktqtbdJLBuVKc4"); + ecdsa_get_address(pub_key, 111, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "mpYTxEJ2zKhCKPj1KeJ4ap4DTcu39T3uzD"); + ecdsa_get_address(pub_key, 52, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "N5bsrpi36gMW4pVtsteFyQzoKrhPE7nkxK"); + ecdsa_get_address(pub_key, 48, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "LUFTvPWtFxVzo5wYnDJz2uueoqfcMYiuxH"); memcpy(pub_key, fromhex("04f80490839af36d13701ec3f9eebdac901b51c362119d74553a3c537faff31b17e2a59ebddbdac9e87b816307a7ed5b826b8f40b92719086238e1bebf19b77a4d"), 65); - ecdsa_get_address(pub_key, 0, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "19J81hrPnQxg9UGx45ibTieCkb2ttm8CLL"); - ecdsa_get_address(pub_key, 111, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "mop5JkwNbSPvvakZmegyHdrXcadbjLazww"); - ecdsa_get_address(pub_key, 52, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "N4sVDMMNho4Eg1XTKu3AgEo7UpRwq3aNbn"); - ecdsa_get_address(pub_key, 48, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "LTX5GvADs5CjQGy7EDhtjjhxxoQB2Uhicd"); + ecdsa_get_address(pub_key, 0, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "19J81hrPnQxg9UGx45ibTieCkb2ttm8CLL"); + ecdsa_get_address(pub_key, 111, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "mop5JkwNbSPvvakZmegyHdrXcadbjLazww"); + ecdsa_get_address(pub_key, 52, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "N4sVDMMNho4Eg1XTKu3AgEo7UpRwq3aNbn"); + ecdsa_get_address(pub_key, 48, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "LTX5GvADs5CjQGy7EDhtjjhxxoQB2Uhicd"); } END_TEST @@ -2896,16 +2896,16 @@ START_TEST(test_wif) char wif[53]; memcpy(priv_key, fromhex("1111111111111111111111111111111111111111111111111111111111111111"), 32); - ecdsa_get_wif(priv_key, 0x80, HASHER_SHA2, wif, sizeof(wif)); ck_assert_str_eq(wif, "KwntMbt59tTsj8xqpqYqRRWufyjGunvhSyeMo3NTYpFYzZbXJ5Hp"); - ecdsa_get_wif(priv_key, 0xEF, HASHER_SHA2, wif, sizeof(wif)); ck_assert_str_eq(wif, "cN9spWsvaxA8taS7DFMxnk1yJD2gaF2PX1npuTpy3vuZFJdwavaw"); + ecdsa_get_wif(priv_key, 0x80, HASHER_SHA2D, wif, sizeof(wif)); ck_assert_str_eq(wif, "KwntMbt59tTsj8xqpqYqRRWufyjGunvhSyeMo3NTYpFYzZbXJ5Hp"); + ecdsa_get_wif(priv_key, 0xEF, HASHER_SHA2D, wif, sizeof(wif)); ck_assert_str_eq(wif, "cN9spWsvaxA8taS7DFMxnk1yJD2gaF2PX1npuTpy3vuZFJdwavaw"); memcpy(priv_key, fromhex("dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"), 32); - ecdsa_get_wif(priv_key, 0x80, HASHER_SHA2, wif, sizeof(wif)); ck_assert_str_eq(wif, "L4ezQvyC6QoBhxB4GVs9fAPhUKtbaXYUn8YTqoeXwbevQq4U92vN"); - ecdsa_get_wif(priv_key, 0xEF, HASHER_SHA2, wif, sizeof(wif)); ck_assert_str_eq(wif, "cV1ysqy3XUVSsPeKeugH2Utm6ZC1EyeArAgvxE73SiJvfa6AJng7"); + ecdsa_get_wif(priv_key, 0x80, HASHER_SHA2D, wif, sizeof(wif)); ck_assert_str_eq(wif, "L4ezQvyC6QoBhxB4GVs9fAPhUKtbaXYUn8YTqoeXwbevQq4U92vN"); + ecdsa_get_wif(priv_key, 0xEF, HASHER_SHA2D, wif, sizeof(wif)); ck_assert_str_eq(wif, "cV1ysqy3XUVSsPeKeugH2Utm6ZC1EyeArAgvxE73SiJvfa6AJng7"); memcpy(priv_key, fromhex("47f7616ea6f9b923076625b4488115de1ef1187f760e65f89eb6f4f7ff04b012"), 32); - ecdsa_get_wif(priv_key, 0x80, HASHER_SHA2, wif, sizeof(wif)); ck_assert_str_eq(wif, "KydbzBtk6uc7M6dXwEgTEH2sphZxSPbmDSz6kUUHi4eUpSQuhEbq"); - ecdsa_get_wif(priv_key, 0xEF, HASHER_SHA2, wif, sizeof(wif)); ck_assert_str_eq(wif, "cPzbT6tbXyJNWY6oKeVabbXwSvsN6qhTHV8ZrtvoDBJV5BRY1G5Q"); + ecdsa_get_wif(priv_key, 0x80, HASHER_SHA2D, wif, sizeof(wif)); ck_assert_str_eq(wif, "KydbzBtk6uc7M6dXwEgTEH2sphZxSPbmDSz6kUUHi4eUpSQuhEbq"); + ecdsa_get_wif(priv_key, 0xEF, HASHER_SHA2D, wif, sizeof(wif)); ck_assert_str_eq(wif, "cPzbT6tbXyJNWY6oKeVabbXwSvsN6qhTHV8ZrtvoDBJV5BRY1G5Q"); } END_TEST @@ -2914,48 +2914,48 @@ START_TEST(test_address_decode) int res; uint8_t decode[MAX_ADDR_RAW_SIZE]; - res = ecdsa_address_decode("1JwSSubhmg6iPtRjtyqhUYYH7bZg3Lfy1T", 0, HASHER_SHA2, decode); + res = ecdsa_address_decode("1JwSSubhmg6iPtRjtyqhUYYH7bZg3Lfy1T", 0, HASHER_SHA2D, decode); ck_assert_int_eq(res, 1); ck_assert_mem_eq(decode, fromhex("00c4c5d791fcb4654a1ef5e03fe0ad3d9c598f9827"), 21); - res = ecdsa_address_decode("myTPjxggahXyAzuMcYp5JTkbybANyLsYBW", 111, HASHER_SHA2, decode); + res = ecdsa_address_decode("myTPjxggahXyAzuMcYp5JTkbybANyLsYBW", 111, HASHER_SHA2D, decode); ck_assert_int_eq(res, 1); ck_assert_mem_eq(decode, fromhex("6fc4c5d791fcb4654a1ef5e03fe0ad3d9c598f9827"), 21); - res = ecdsa_address_decode("NEWoeZ6gh4CGvRgFAoAGh4hBqpxizGT6gZ", 52, HASHER_SHA2, decode); + res = ecdsa_address_decode("NEWoeZ6gh4CGvRgFAoAGh4hBqpxizGT6gZ", 52, HASHER_SHA2D, decode); ck_assert_int_eq(res, 1); ck_assert_mem_eq(decode, fromhex("34c4c5d791fcb4654a1ef5e03fe0ad3d9c598f9827"), 21); - res = ecdsa_address_decode("LdAPi7uXrLLmeh7u57pzkZc3KovxEDYRJq", 48, HASHER_SHA2, decode); + res = ecdsa_address_decode("LdAPi7uXrLLmeh7u57pzkZc3KovxEDYRJq", 48, HASHER_SHA2D, decode); ck_assert_int_eq(res, 1); ck_assert_mem_eq(decode, fromhex("30c4c5d791fcb4654a1ef5e03fe0ad3d9c598f9827"), 21); - res = ecdsa_address_decode("1C7zdTfnkzmr13HfA2vNm5SJYRK6nEKyq8", 0, HASHER_SHA2, decode); + res = ecdsa_address_decode("1C7zdTfnkzmr13HfA2vNm5SJYRK6nEKyq8", 0, HASHER_SHA2D, decode); ck_assert_int_eq(res, 1); ck_assert_mem_eq(decode, fromhex("0079fbfc3f34e7745860d76137da68f362380c606c"), 21); - res = ecdsa_address_decode("mrdwvWkma2D6n9mGsbtkazedQQuoksnqJV", 111, HASHER_SHA2, decode); + res = ecdsa_address_decode("mrdwvWkma2D6n9mGsbtkazedQQuoksnqJV", 111, HASHER_SHA2D, decode); ck_assert_int_eq(res, 1); ck_assert_mem_eq(decode, fromhex("6f79fbfc3f34e7745860d76137da68f362380c606c"), 21); - res = ecdsa_address_decode("N7hMq7AmgNsQXaYARrEwybbDGei9mcPNqr", 52, HASHER_SHA2, decode); + res = ecdsa_address_decode("N7hMq7AmgNsQXaYARrEwybbDGei9mcPNqr", 52, HASHER_SHA2D, decode); ck_assert_int_eq(res, 1); ck_assert_mem_eq(decode, fromhex("3479fbfc3f34e7745860d76137da68f362380c606c"), 21); - res = ecdsa_address_decode("LWLwtfycqf1uFqypLAug36W4kdgNwrZdNs", 48, HASHER_SHA2, decode); + res = ecdsa_address_decode("LWLwtfycqf1uFqypLAug36W4kdgNwrZdNs", 48, HASHER_SHA2D, decode); ck_assert_int_eq(res, 1); ck_assert_mem_eq(decode, fromhex("3079fbfc3f34e7745860d76137da68f362380c606c"), 21); // invalid char - res = ecdsa_address_decode("1JwSSubhmg6i000jtyqhUYYH7bZg3Lfy1T", 0, HASHER_SHA2, decode); + res = ecdsa_address_decode("1JwSSubhmg6i000jtyqhUYYH7bZg3Lfy1T", 0, HASHER_SHA2D, decode); ck_assert_int_eq(res, 0); // invalid address - res = ecdsa_address_decode("1111Subhmg6iPtRjtyqhUYYH7bZg3Lfy1T", 0, HASHER_SHA2, decode); + res = ecdsa_address_decode("1111Subhmg6iPtRjtyqhUYYH7bZg3Lfy1T", 0, HASHER_SHA2D, decode); ck_assert_int_eq(res, 0); // invalid version - res = ecdsa_address_decode("LWLwtfycqf1uFqypLAug36W4kdgNwrZdNs", 0, HASHER_SHA2, decode); + res = ecdsa_address_decode("LWLwtfycqf1uFqypLAug36W4kdgNwrZdNs", 0, HASHER_SHA2D, decode); ck_assert_int_eq(res, 0); } END_TEST @@ -4133,50 +4133,50 @@ START_TEST(test_multibyte_address) int res; memcpy(priv_key, fromhex("47f7616ea6f9b923076625b4488115de1ef1187f760e65f89eb6f4f7ff04b012"), 32); - ecdsa_get_wif(priv_key, 0, HASHER_SHA2, wif, sizeof(wif)); ck_assert_str_eq(wif, "13QtoXmbhELWcrwD9YA9KzvXy5rTaptiNuFR8L8ArpBNn4xmQj4N"); - ecdsa_get_wif(priv_key, 0x12, HASHER_SHA2, wif, sizeof(wif)); ck_assert_str_eq(wif, "3hrF6SFnqzpzABB36uGDf8dJSuUCcMmoJrTmCWMshRkBr2Vx86qJ"); - ecdsa_get_wif(priv_key, 0x1234, HASHER_SHA2, wif, sizeof(wif)); ck_assert_str_eq(wif, "CtPTF9awbVbfDWGepGdVhB3nBhr4HktUGya8nf8dLxgC8tbqBreB9"); - ecdsa_get_wif(priv_key, 0x123456, HASHER_SHA2, wif, sizeof(wif)); ck_assert_str_eq(wif, "uTrDevVQt5QZgoL3iJ1cPWHaCz7ZMBncM7QXZfCegtxiMHqBvWoYJa"); - ecdsa_get_wif(priv_key, 0x12345678, HASHER_SHA2, wif, sizeof(wif)); ck_assert_str_eq(wif, "4zZWMzv1SVbs95pmLXWrXJVp9ntPEam1mfwb6CXBLn9MpWNxLg9huYgv"); - ecdsa_get_wif(priv_key, 0xffffffff, HASHER_SHA2, wif, sizeof(wif)); ck_assert_str_eq(wif, "y9KVfV1RJXcTxpVjeuh6WYWh8tMwnAUeyUwDEiRviYdrJ61njTmnfUjE"); + ecdsa_get_wif(priv_key, 0, HASHER_SHA2D, wif, sizeof(wif)); ck_assert_str_eq(wif, "13QtoXmbhELWcrwD9YA9KzvXy5rTaptiNuFR8L8ArpBNn4xmQj4N"); + ecdsa_get_wif(priv_key, 0x12, HASHER_SHA2D, wif, sizeof(wif)); ck_assert_str_eq(wif, "3hrF6SFnqzpzABB36uGDf8dJSuUCcMmoJrTmCWMshRkBr2Vx86qJ"); + ecdsa_get_wif(priv_key, 0x1234, HASHER_SHA2D, wif, sizeof(wif)); ck_assert_str_eq(wif, "CtPTF9awbVbfDWGepGdVhB3nBhr4HktUGya8nf8dLxgC8tbqBreB9"); + ecdsa_get_wif(priv_key, 0x123456, HASHER_SHA2D, wif, sizeof(wif)); ck_assert_str_eq(wif, "uTrDevVQt5QZgoL3iJ1cPWHaCz7ZMBncM7QXZfCegtxiMHqBvWoYJa"); + ecdsa_get_wif(priv_key, 0x12345678, HASHER_SHA2D, wif, sizeof(wif)); ck_assert_str_eq(wif, "4zZWMzv1SVbs95pmLXWrXJVp9ntPEam1mfwb6CXBLn9MpWNxLg9huYgv"); + ecdsa_get_wif(priv_key, 0xffffffff, HASHER_SHA2D, wif, sizeof(wif)); ck_assert_str_eq(wif, "y9KVfV1RJXcTxpVjeuh6WYWh8tMwnAUeyUwDEiRviYdrJ61njTmnfUjE"); memcpy(pub_key, fromhex("0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71"), 33); - ecdsa_get_address(pub_key, 0, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "1C7zdTfnkzmr13HfA2vNm5SJYRK6nEKyq8"); - ecdsa_get_address(pub_key, 0x12, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "8SCrMR2yYF7ciqoDbav7VLLTsVx5dTVPPq"); - ecdsa_get_address(pub_key, 0x1234, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "ZLH8q1UgMPg8o2s1MD55YVMpPV7vqms9kiV"); - ecdsa_get_address(pub_key, 0x123456, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "3ThqvsQVFnbiF66NwHtfe2j6AKn75DpLKpQSq"); - ecdsa_get_address(pub_key, 0x12345678, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "BrsGxAHga3VbopvSnb3gmLvMBhJNCGuDxBZL44"); - ecdsa_get_address(pub_key, 0xffffffff, HASHER_SHA2, address, sizeof(address)); ck_assert_str_eq(address, "3diW7paWGJyZRLGqMJZ55DMfPExob8QxQHkrfYT"); - - res = ecdsa_address_decode("1C7zdTfnkzmr13HfA2vNm5SJYRK6nEKyq8", 0, HASHER_SHA2, decode); + ecdsa_get_address(pub_key, 0, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "1C7zdTfnkzmr13HfA2vNm5SJYRK6nEKyq8"); + ecdsa_get_address(pub_key, 0x12, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "8SCrMR2yYF7ciqoDbav7VLLTsVx5dTVPPq"); + ecdsa_get_address(pub_key, 0x1234, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "ZLH8q1UgMPg8o2s1MD55YVMpPV7vqms9kiV"); + ecdsa_get_address(pub_key, 0x123456, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "3ThqvsQVFnbiF66NwHtfe2j6AKn75DpLKpQSq"); + ecdsa_get_address(pub_key, 0x12345678, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "BrsGxAHga3VbopvSnb3gmLvMBhJNCGuDxBZL44"); + ecdsa_get_address(pub_key, 0xffffffff, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "3diW7paWGJyZRLGqMJZ55DMfPExob8QxQHkrfYT"); + + res = ecdsa_address_decode("1C7zdTfnkzmr13HfA2vNm5SJYRK6nEKyq8", 0, HASHER_SHA2D, decode); ck_assert_int_eq(res, 1); ck_assert_mem_eq(decode, fromhex("0079fbfc3f34e7745860d76137da68f362380c606c"), 21); - res = ecdsa_address_decode("8SCrMR2yYF7ciqoDbav7VLLTsVx5dTVPPq", 0x12, HASHER_SHA2, decode); + res = ecdsa_address_decode("8SCrMR2yYF7ciqoDbav7VLLTsVx5dTVPPq", 0x12, HASHER_SHA2D, decode); ck_assert_int_eq(res, 1); ck_assert_mem_eq(decode, fromhex("1279fbfc3f34e7745860d76137da68f362380c606c"), 21); - res = ecdsa_address_decode("ZLH8q1UgMPg8o2s1MD55YVMpPV7vqms9kiV", 0x1234, HASHER_SHA2, decode); + res = ecdsa_address_decode("ZLH8q1UgMPg8o2s1MD55YVMpPV7vqms9kiV", 0x1234, HASHER_SHA2D, decode); ck_assert_int_eq(res, 1); ck_assert_mem_eq(decode, fromhex("123479fbfc3f34e7745860d76137da68f362380c606c"), 21); - res = ecdsa_address_decode("3ThqvsQVFnbiF66NwHtfe2j6AKn75DpLKpQSq", 0x123456, HASHER_SHA2, decode); + res = ecdsa_address_decode("3ThqvsQVFnbiF66NwHtfe2j6AKn75DpLKpQSq", 0x123456, HASHER_SHA2D, decode); ck_assert_int_eq(res, 1); ck_assert_mem_eq(decode, fromhex("12345679fbfc3f34e7745860d76137da68f362380c606c"), 21); - res = ecdsa_address_decode("BrsGxAHga3VbopvSnb3gmLvMBhJNCGuDxBZL44", 0x12345678, HASHER_SHA2, decode); + res = ecdsa_address_decode("BrsGxAHga3VbopvSnb3gmLvMBhJNCGuDxBZL44", 0x12345678, HASHER_SHA2D, decode); ck_assert_int_eq(res, 1); ck_assert_mem_eq(decode, fromhex("1234567879fbfc3f34e7745860d76137da68f362380c606c"), 21); - res = ecdsa_address_decode("3diW7paWGJyZRLGqMJZ55DMfPExob8QxQHkrfYT", 0xffffffff, HASHER_SHA2, decode); + res = ecdsa_address_decode("3diW7paWGJyZRLGqMJZ55DMfPExob8QxQHkrfYT", 0xffffffff, HASHER_SHA2D, decode); ck_assert_int_eq(res, 1); ck_assert_mem_eq(decode, fromhex("ffffffff79fbfc3f34e7745860d76137da68f362380c606c"), 21); // wrong length - res = ecdsa_address_decode("BrsGxAHga3VbopvSnb3gmLvMBhJNCGuDxBZL44", 0x123456, HASHER_SHA2, decode); + res = ecdsa_address_decode("BrsGxAHga3VbopvSnb3gmLvMBhJNCGuDxBZL44", 0x123456, HASHER_SHA2D, decode); ck_assert_int_eq(res, 0); // wrong address prefix - res = ecdsa_address_decode("BrsGxAHga3VbopvSnb3gmLvMBhJNCGuDxBZL44", 0x22345678, HASHER_SHA2, decode); + res = ecdsa_address_decode("BrsGxAHga3VbopvSnb3gmLvMBhJNCGuDxBZL44", 0x22345678, HASHER_SHA2D, decode); ck_assert_int_eq(res, 0); // wrong checksum - res = ecdsa_address_decode("BrsGxAHga3VbopvSnb3gmLvMBhJNCGuDxBZL45", 0x12345678, HASHER_SHA2, decode); + res = ecdsa_address_decode("BrsGxAHga3VbopvSnb3gmLvMBhJNCGuDxBZL45", 0x12345678, HASHER_SHA2D, decode); ck_assert_int_eq(res, 0); } END_TEST diff --git a/test_speed.c b/test_speed.c index cff4aee2a..592186fbb 100644 --- a/test_speed.c +++ b/test_speed.c @@ -165,7 +165,7 @@ void bench_ckd_normal(int iterations) memcpy(&node, &root, sizeof(HDNode)); hdnode_public_ckd(&node, i); hdnode_fill_public_key(&node); - ecdsa_get_address(node.public_key, HASHER_SHA2, 0, addr, sizeof(addr)); + ecdsa_get_address(node.public_key, HASHER_SHA2, HASHER_SHA2D, 0, addr, sizeof(addr)); } } @@ -175,7 +175,7 @@ void bench_ckd_optimized(int iterations) curve_point pub; ecdsa_read_pubkey(&secp256k1, root.public_key, &pub); for (int i = 0; i < iterations; i++) { - hdnode_public_ckd_address_optimized(&pub, root.chain_code, i, 0, HASHER_SHA2, addr, sizeof(addr), false); + hdnode_public_ckd_address_optimized(&pub, root.chain_code, i, 0, HASHER_SHA2, HASHER_SHA2D, addr, sizeof(addr), false); } } diff --git a/tools/xpubaddrgen.c b/tools/xpubaddrgen.c index 361686e6d..54c5ebc98 100644 --- a/tools/xpubaddrgen.c +++ b/tools/xpubaddrgen.c @@ -22,7 +22,7 @@ void process_job(uint32_t jobid, const char *xpub, uint32_t change, uint32_t fro for (i = from; i < to; i++) { memcpy(&child, &node, sizeof(HDNode)); hdnode_public_ckd(&child, i); - ecdsa_get_address(child.public_key, 0, HASHER_SHA2, address, sizeof(address)); + ecdsa_get_address(child.public_key, 0, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); printf("%d %d %s\n", jobid, i, address); } } From b9043659c5c91180c4abfb3ebb603f7b0385f201 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Tue, 3 Apr 2018 16:58:19 +0100 Subject: [PATCH 533/627] test_openssl: Fix failing test --- Makefile | 3 ++- test_openssl.c | 25 ++++++------------------- 2 files changed, 8 insertions(+), 20 deletions(-) diff --git a/Makefile b/Makefile index 65b77a26d..2ef6a1781 100644 --- a/Makefile +++ b/Makefile @@ -27,6 +27,7 @@ CFLAGS += -I. CFLAGS += -DUSE_ETHEREUM=1 CFLAGS += -DUSE_GRAPHENE=1 CFLAGS += -DUSE_NEM=1 +CFLAGS += $(shell pkg-config --cflags openssl) # disable certain optimizations and features when small footprint is required ifdef SMALL @@ -55,7 +56,7 @@ SRCS += memzero.c OBJS = $(SRCS:.c=.o) TESTLIBS = $(shell pkg-config --libs check) -lpthread -lm -TESTSSLLIBS = -lcrypto +TESTSSLLIBS = $(shell pkg-config --libs openssl) all: test_check test_openssl test_speed aes/aestst tools libtrezor-crypto.so diff --git a/test_openssl.c b/test_openssl.c index 1817afcd3..b067bf383 100644 --- a/test_openssl.c +++ b/test_openssl.c @@ -34,6 +34,7 @@ #include #include +#include #include "ecdsa.h" #include "rand.h" @@ -44,7 +45,7 @@ void openssl_check(unsigned int iterations, int nid, const ecdsa_curve *curve) { - uint8_t sig[64], pub_key33[33], pub_key65[65], priv_key[32], msg[256], buffer[1000], hash[32], *p; + uint8_t sig[64], pub_key33[33], pub_key65[65], priv_key[32], msg[256], hash[32]; struct SHA256state_st sha256; EC_GROUP *ecgroup; @@ -64,24 +65,10 @@ void openssl_check(unsigned int iterations, int nid, const ecdsa_curve *curve) // generate the key EC_KEY_generate_key(eckey); // copy key to buffer - p = buffer; - i2d_ECPrivateKey(eckey, &p); - - // size of the key is in buffer[8] and the key begins right after that - int s = buffer[8]; - // extract key data - if (s > 32) { - for (int j = 0; j < 32; j++) { - priv_key[j] = buffer[j + s - 23]; - } - } else { - for (int j = 0; j < 32 - s; j++) { - priv_key[j] = 0; - } - for (int j = 0; j < s; j++) { - priv_key[j + 32 - s] = buffer[j + 9]; - } - } + const BIGNUM *K = EC_KEY_get0_private_key(eckey); + int bn_off = sizeof(priv_key) - BN_num_bytes(K); + memset(priv_key, 0, bn_off); + BN_bn2bin(K, priv_key + bn_off); // use our ECDSA signer to sign the message with the key if (ecdsa_sign(curve, HASHER_SHA2, priv_key, msg, msg_len, sig, NULL, NULL) != 0) { From 877998fa1a044a86ff0fdd3a996f8da93c578156 Mon Sep 17 00:00:00 2001 From: Tomas Susanka Date: Tue, 20 Mar 2018 15:12:18 +0100 Subject: [PATCH 534/627] bip32/nem: IV is copied before encryption --- bip32.c | 6 +++++- bip32.h | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/bip32.c b/bip32.c index 4ecfd6e61..4a565704c 100644 --- a/bip32.c +++ b/bip32.c @@ -490,7 +490,7 @@ int hdnode_get_nem_shared_key(const HDNode *node, const ed25519_public_key peer_ return 1; } -int hdnode_nem_encrypt(const HDNode *node, const ed25519_public_key public_key, uint8_t *iv, const uint8_t *salt, const uint8_t *payload, size_t size, uint8_t *buffer) { +int hdnode_nem_encrypt(const HDNode *node, const ed25519_public_key public_key, const uint8_t *iv_immut, const uint8_t *salt, const uint8_t *payload, size_t size, uint8_t *buffer) { uint8_t last_block[AES_BLOCK_SIZE]; uint8_t remainder = size % AES_BLOCK_SIZE; @@ -501,6 +501,10 @@ int hdnode_nem_encrypt(const HDNode *node, const ed25519_public_key public_key, // Pad new last block with number of missing bytes memset(&last_block[remainder], AES_BLOCK_SIZE - remainder, AES_BLOCK_SIZE - remainder); + // the IV gets mutated, so we make a copy not to touch the original + uint8_t iv[AES_BLOCK_SIZE]; + memcpy(iv, iv_immut, AES_BLOCK_SIZE); + uint8_t shared_key[SHA3_256_DIGEST_LENGTH]; if (!hdnode_get_nem_shared_key(node, public_key, salt, NULL, shared_key)) { return 0; diff --git a/bip32.h b/bip32.h index 081639842..5398ec3cd 100644 --- a/bip32.h +++ b/bip32.h @@ -81,7 +81,7 @@ int hdnode_get_ethereum_pubkeyhash(const HDNode *node, uint8_t *pubkeyhash); #if USE_NEM int hdnode_get_nem_address(HDNode *node, uint8_t version, char *address); int hdnode_get_nem_shared_key(const HDNode *node, const ed25519_public_key peer_public_key, const uint8_t *salt, ed25519_public_key mul, uint8_t *shared_key); -int hdnode_nem_encrypt(const HDNode *node, const ed25519_public_key public_key, uint8_t *iv, const uint8_t *salt, const uint8_t *payload, size_t size, uint8_t *buffer); +int hdnode_nem_encrypt(const HDNode *node, const ed25519_public_key public_key, const uint8_t *iv, const uint8_t *salt, const uint8_t *payload, size_t size, uint8_t *buffer); int hdnode_nem_decrypt(const HDNode *node, const ed25519_public_key public_key, uint8_t *iv, const uint8_t *salt, const uint8_t *payload, size_t size, uint8_t *buffer); #endif From b0af15909649a311c2af3c4d559fcdbbfc21220d Mon Sep 17 00:00:00 2001 From: "Peter D. Gray" Date: Tue, 3 Apr 2018 12:32:48 -0400 Subject: [PATCH 535/627] bip32, options: optionally exclude 25519 curves in BIP32 support --- bip32.c | 6 ++++++ options.h | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/bip32.c b/bip32.c index 4a565704c..8fd2d1ebe 100644 --- a/bip32.c +++ b/bip32.c @@ -421,6 +421,8 @@ void hdnode_fill_public_key(HDNode *node) { if (node->public_key[0] != 0) return; + +#if USE_BIP32_25519_CURVES if (node->curve->params) { ecdsa_get_public_key33(node->curve->params, node->private_key, node->public_key); } else { @@ -437,6 +439,10 @@ void hdnode_fill_public_key(HDNode *node) curve25519_scalarmult_basepoint(node->public_key + 1, node->private_key); } } +#else + + ecdsa_get_public_key33(node->curve->params, node->private_key, node->public_key); +#endif } #if USE_ETHEREUM diff --git a/options.h b/options.h index 2a542157e..e0659cc22 100644 --- a/options.h +++ b/options.h @@ -50,6 +50,11 @@ #define BIP32_CACHE_MAXDEPTH 8 #endif +// support constructing BIP32 nodes from ed25519 and curve25519 curves. +#ifndef USE_BIP32_25519_CURVES +#define USE_BIP32_25519_CURVES 1 +#endif + // implement BIP39 caching #ifndef USE_BIP39_CACHE #define USE_BIP39_CACHE 1 From 2350bb015ca9f7112f29a904fd2a321b55df77ff Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Thu, 29 Mar 2018 15:02:08 +0200 Subject: [PATCH 536/627] Fix another undefined shift. Note that `(1 << j)` is undefined for j == 31, so `(1u << j)` should be used. --- bignum.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bignum.c b/bignum.c index 00600221d..5484002e8 100644 --- a/bignum.c +++ b/bignum.c @@ -324,19 +324,19 @@ void bn_rshift(bignum256 *a) // sets bit in bignum void bn_setbit(bignum256 *a, uint8_t bit) { - a->val[bit / 30] |= (1 << (bit % 30)); + a->val[bit / 30] |= (1u << (bit % 30)); } // clears bit in bignum void bn_clearbit(bignum256 *a, uint8_t bit) { - a->val[bit / 30] &= ~(1 << (bit % 30)); + a->val[bit / 30] &= ~(1u << (bit % 30)); } // tests bit in bignum uint32_t bn_testbit(bignum256 *a, uint8_t bit) { - return a->val[bit / 30] & (1 << (bit % 30)); + return a->val[bit / 30] & (1u << (bit % 30)); } // a = b ^ c @@ -694,7 +694,7 @@ void bn_inverse(bignum256 *x, const bignum256 *prime) } // count up to 32 zero bits of even->a. j = 0; - while ((even->a[0] & (1 << j)) == 0) { + while ((even->a[0] & (1u << j)) == 0) { j++; } if (j > 0) { From 9add21439ad3c52497b0089b133b5d0a607b2722 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Thu, 29 Mar 2018 15:49:12 +0200 Subject: [PATCH 537/627] Adapted sha1 to match sha2 code. Also fixes an unaligned uint32 access. --- sha2.c | 128 +++++++++++++++++++++------------------------------------ 1 file changed, 46 insertions(+), 82 deletions(-) diff --git a/sha2.c b/sha2.c index 0d27f4335..39c1aacef 100644 --- a/sha2.c +++ b/sha2.c @@ -290,25 +290,12 @@ void sha1_Init(SHA1_CTX* context) { /* Unrolled SHA-1 round macros: */ -#if BYTE_ORDER == LITTLE_ENDIAN - -#define ROUND1_0_TO_15(a,b,c,d,e) \ - REVERSE32(*data++, W1[j]); \ - (e) = ROTL32(5, (a)) + Ch((b), (c), (d)) + (e) + \ - K1_0_TO_19 + W1[j]; \ - (b) = ROTL32(30, (b)); \ - j++; - -#else /* BYTE_ORDER == LITTLE_ENDIAN */ - #define ROUND1_0_TO_15(a,b,c,d,e) \ (e) = ROTL32(5, (a)) + Ch((b), (c), (d)) + (e) + \ K1_0_TO_19 + ( W1[j] = *data++ ); \ (b) = ROTL32(30, (b)); \ j++; -#endif /* BYTE_ORDER == LITTLE_ENDIAN */ - #define ROUND1_16_TO_19(a,b,c,d,e) \ T1 = W1[(j+13)&0x0f] ^ W1[(j+8)&0x0f] ^ W1[(j+2)&0x0f] ^ W1[j&0x0f]; \ (e) = ROTL32(5, a) + Ch(b,c,d) + e + K1_0_TO_19 + ( W1[j&0x0f] = ROTL32(1, T1) ); \ @@ -465,14 +452,7 @@ void sha1_Transform(const sha2_word32* state_in, const sha2_word32* data, sha2_w e = state_in[4]; j = 0; do { -#if BYTE_ORDER == LITTLE_ENDIAN - T1 = data[j]; - /* Copy data while converting to host byte order */ - REVERSE32(*data++, W1[j]); - T1 = ROTL32(5, a) + Ch(b, c, d) + e + K1_0_TO_19 + W1[j]; -#else /* BYTE_ORDER == LITTLE_ENDIAN */ T1 = ROTL32(5, a) + Ch(b, c, d) + e + K1_0_TO_19 + (W1[j] = *data++); -#endif /* BYTE_ORDER == LITTLE_ENDIAN */ e = d; d = c; c = ROTL32(30, b); @@ -541,6 +521,7 @@ void sha1_Transform(const sha2_word32* state_in, const sha2_word32* data, sha2_w void sha1_Update(SHA1_CTX* context, const sha2_byte *data, size_t len) { unsigned int freespace, usedspace; + if (len == 0) { /* Calling with no data is valid - we do nothing */ return; @@ -557,6 +538,12 @@ void sha1_Update(SHA1_CTX* context, const sha2_byte *data, size_t len) { context->bitcount += freespace << 3; len -= freespace; data += freespace; +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert TO host byte order */ + for (int j = 0; j < 16; j++) { + REVERSE32(context->buffer[j],context->buffer[j]); + } +#endif sha1_Transform(context->state, context->buffer, context->state); } else { /* The buffer is not yet full */ @@ -569,7 +556,14 @@ void sha1_Update(SHA1_CTX* context, const sha2_byte *data, size_t len) { } while (len >= SHA1_BLOCK_LENGTH) { /* Process as many complete blocks as we can */ - sha1_Transform(context->state, (sha2_word32*)data, context->state); + MEMCPY_BCOPY(context->buffer, data, SHA1_BLOCK_LENGTH); +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert TO host byte order */ + for (int j = 0; j < 16; j++) { + REVERSE32(context->buffer[j],context->buffer[j]); + } +#endif + sha1_Transform(context->state, context->buffer, context->state); context->bitcount += SHA1_BLOCK_LENGTH << 3; len -= SHA1_BLOCK_LENGTH; data += SHA1_BLOCK_LENGTH; @@ -584,72 +578,57 @@ void sha1_Update(SHA1_CTX* context, const sha2_byte *data, size_t len) { } void sha1_Final(SHA1_CTX* context, sha2_byte digest[]) { - sha2_word32 *d = (sha2_word32*)digest; unsigned int usedspace; - if (digest == (sha2_byte*)0) { - /* - * No digest buffer, so we can do nothing - * except clean up and go home - */ - memzero(context, sizeof(SHA1_CTX)); - return; - } - - usedspace = (context->bitcount >> 3) % SHA1_BLOCK_LENGTH; - if (usedspace == 0) { - /* Set-up for the last transform: */ - memzero(context->buffer, SHA1_SHORT_BLOCK_LENGTH); - - /* Begin padding with a 1 bit: */ - *context->buffer = 0x80; - } else { + /* If no digest buffer is passed, we don't bother doing this: */ + if (digest != (sha2_byte*)0) { + usedspace = (context->bitcount >> 3) % SHA1_BLOCK_LENGTH; /* Begin padding with a 1 bit: */ ((uint8_t*)context->buffer)[usedspace++] = 0x80; - if (usedspace <= 56) { - /* Set-up for the last transform: */ - memzero(((uint8_t*)context->buffer) + usedspace, 56 - usedspace); - } else { - if (usedspace < 64) { - memzero(((uint8_t*)context->buffer) + usedspace, 64 - usedspace); + if (usedspace > SHA1_SHORT_BLOCK_LENGTH) { + memzero(((uint8_t*)context->buffer) + usedspace, SHA1_BLOCK_LENGTH - usedspace); + +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert TO host byte order */ + for (int j = 0; j < 16; j++) { + REVERSE32(context->buffer[j],context->buffer[j]); } +#endif /* Do second-to-last transform: */ sha1_Transform(context->state, context->buffer, context->state); - /* And set-up for the last transform: */ - memzero(context->buffer, 56); + /* And prepare the last transform: */ + usedspace = 0; } - /* Clean up: */ - usedspace = 0; - } - /* Set the bit count: */ + /* Set-up for the last transform: */ + memzero(((uint8_t*)context->buffer) + usedspace, SHA1_SHORT_BLOCK_LENGTH - usedspace); + #if BYTE_ORDER == LITTLE_ENDIAN - /* Convert FROM host byte order */ - REVERSE64(context->bitcount,context->bitcount); + /* Convert TO host byte order */ + for (int j = 0; j < 14; j++) { + REVERSE32(context->buffer[j],context->buffer[j]); + } #endif - context->buffer[SHA1_SHORT_BLOCK_LENGTH >> 2] = context->bitcount << 32; - context->buffer[SHA1_SHORT_BLOCK_LENGTH >> 2 | 1] = context->bitcount >> 32; + /* Set the bit count: */ + context->buffer[14] = context->bitcount >> 32; + context->buffer[15] = context->bitcount & 0xffffffff; - /* Final transform: */ - sha1_Transform(context->state, context->buffer, context->state); + /* Final transform: */ + sha1_Transform(context->state, context->buffer, context->state); - /* Save the hash data for output: */ #if BYTE_ORDER == LITTLE_ENDIAN - { - /* Convert TO host byte order */ - int j; - for (j = 0; j < (SHA1_DIGEST_LENGTH >> 2); j++) { + /* Convert FROM host byte order */ + for (int j = 0; j < 5; j++) { REVERSE32(context->state[j],context->state[j]); - *d++ = context->state[j]; } - } -#else - MEMCPY_BCOPY(d, context->state, SHA1_DIGEST_LENGTH); #endif + MEMCPY_BCOPY(digest, context->state, SHA1_DIGEST_LENGTH); + } - /* Clean up: */ + /* Clean up state data: */ memzero(context, sizeof(SHA1_CTX)); + usedspace = 0; } char *sha1_End(SHA1_CTX* context, char buffer[]) { @@ -701,19 +680,6 @@ void sha256_Init(SHA256_CTX* context) { /* Unrolled SHA-256 round macros: */ -#if BYTE_ORDER == LITTLE_ENDIAN - -#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \ - W256[j] = *data++; \ - T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \ - K256[j] + W256[j]; \ - (d) += T1; \ - (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ - j++ - - -#else /* BYTE_ORDER == LITTLE_ENDIAN */ - #define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \ T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \ K256[j] + (W256[j] = *data++); \ @@ -721,8 +687,6 @@ void sha256_Init(SHA256_CTX* context) { (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ j++ -#endif /* BYTE_ORDER == LITTLE_ENDIAN */ - #define ROUND256(a,b,c,d,e,f,g,h) \ s0 = W256[(j+1)&0x0f]; \ s0 = sigma0_256(s0); \ From c61ab76ad7c6730e5d4ecc962069b6c7400f6e95 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Wed, 4 Apr 2018 18:27:28 +0200 Subject: [PATCH 538/627] Reworked bn_format. - Fix off-by-one in buffer size. - Don't return uninitialized stack if number too large. --- bignum.c | 31 +++++++++++++++++++------------ test_check.c | 11 +++++++++++ 2 files changed, 30 insertions(+), 12 deletions(-) diff --git a/bignum.c b/bignum.c index 5484002e8..20c57d922 100644 --- a/bignum.c +++ b/bignum.c @@ -990,7 +990,19 @@ size_t bn_format(const bignum256 *amnt, const char *prefix, const char *suffix, size_t prefixlen = prefix ? strlen(prefix) : 0; size_t suffixlen = suffix ? strlen(suffix) : 0; - char *start = &out[prefixlen + suffixlen], *end = &out[outlen]; + /* add prefix to beginning of out buffer */ + if (prefixlen) { + memcpy(out, prefix, prefixlen); + } + /* add suffix to end of out buffer */ + if (suffixlen) { + memcpy(&out[outlen - suffixlen - 1], suffix, suffixlen); + } + /* nul terminate (even if suffix = NULL) */ + out[outlen - 1] = '\0'; + + /* fill number between prefix and suffix (between start and end) */ + char *start = &out[prefixlen], *end = &out[outlen - suffixlen - 1]; char *str = end; #define BN_FORMAT_PUSH_CHECKED(c) \ @@ -1056,19 +1068,14 @@ size_t bn_format(const bignum256 *amnt, const char *prefix, const char *suffix, BN_FORMAT_PUSH(0); } - size_t len = end - str; + /* finally move number to &out[prefixlen] to close the gap between + * prefix and str. len is length of number + suffix + traling 0 + */ + size_t len = &out[outlen] - str; memmove(&out[prefixlen], str, len); - if (prefixlen) { - memcpy(out, prefix, prefixlen); - } - if (suffixlen) { - memcpy(&out[prefixlen + len], suffix, suffixlen); - } - - size_t length = prefixlen + len + suffixlen; - out[length] = '\0'; - return length; + /* return length of number including prefix and suffix without trailing 0 */ + return prefixlen + len - 1; } #if USE_BN_PRINT diff --git a/test_check.c b/test_check.c index 5a5ad1fca..f6a1024c4 100644 --- a/test_check.c +++ b/test_check.c @@ -622,6 +622,17 @@ START_TEST(test_bignum_format) { r = bn_format(&a, "quite a long prefix", "even longer suffix", 60, 0, false, buf, sizeof(buf)); ck_assert_int_eq(r, 116); ck_assert_str_eq(buf, "quite a long prefix115792089237316195.423570985008687907853269984665640564039457584007913129639935even longer suffix"); + + bn_read_be(fromhex("0000000000000000000000000000000000000000000000000123456789abcdef"), &a); + memset(buf, 'a', sizeof(buf)); + r = bn_format(&a, "prefix", "suffix", 10, 0, false, buf, 31); + ck_assert_str_eq(buf, "prefix8198552.9216486895suffix"); + ck_assert_int_eq(r, 30); + + memset(buf, 'a', sizeof(buf)); + r = bn_format(&a, "prefix", "suffix", 10, 0, false, buf, 30); + ck_assert_int_eq(r, 0); + ck_assert_str_eq(buf, "prefix198552.9216486895suffix"); } END_TEST From e65adcf5caed7eb8e8d6fbcc0d0980a0aeaee917 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Thu, 5 Apr 2018 11:15:05 +0200 Subject: [PATCH 539/627] Added cashaddr support (#120) The new bitcoincash address format. --- Makefile | 4 +- cash_addr.c | 187 ++++++++++++++++++++++++++++++++++++++++++++++++ cash_addr.h | 96 +++++++++++++++++++++++++ ecdsa.h | 12 ++-- test_cashaddr.c | 86 ++++++++++++++++++++++ test_check.c | 5 ++ 6 files changed, 384 insertions(+), 6 deletions(-) create mode 100644 cash_addr.c create mode 100644 cash_addr.h create mode 100644 test_cashaddr.c diff --git a/Makefile b/Makefile index 2ef6a1781..606be78fb 100644 --- a/Makefile +++ b/Makefile @@ -50,7 +50,7 @@ SRCS += blake2b.c blake2s.c SRCS += chacha20poly1305/chacha20poly1305.c chacha20poly1305/chacha_merged.c chacha20poly1305/poly1305-donna.c chacha20poly1305/rfc7539.c SRCS += rc4.c SRCS += nem.c -SRCS += segwit_addr.c +SRCS += segwit_addr.c cash_addr.c SRCS += memzero.c OBJS = $(SRCS:.c=.o) @@ -63,6 +63,8 @@ all: test_check test_openssl test_speed aes/aestst tools libtrezor-crypto.so %.o: %.c %.h options.h $(CC) $(CFLAGS) -o $@ -c $< +test_check.o: test_segwit.c test_cashaddr.c + aes/aestst: aes/aestst.o aes/aescrypt.o aes/aeskey.o aes/aestab.o $(CC) $^ -o $@ diff --git a/cash_addr.c b/cash_addr.c new file mode 100644 index 000000000..48fa912f2 --- /dev/null +++ b/cash_addr.c @@ -0,0 +1,187 @@ +/* Copyright (c) 2017 Jochen Hoenicke + * based on code Copyright (c) 2017 Peter Wuille + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include +#include + +#include "cash_addr.h" + +#define MAX_CASHADDR_SIZE 129 +#define MAX_BASE32_SIZE 104 +#define MAX_DATA_SIZE 65 +#define MAX_HRP_SIZE 20 +#define CHECKSUM_SIZE 8 + +uint64_t cashaddr_polymod_step(uint64_t pre) { + uint8_t b = pre >> 35; + return ((pre & 0x7FFFFFFFFULL) << 5) ^ + (-((b >> 0) & 1) & 0x98f2bc8e61ULL) ^ + (-((b >> 1) & 1) & 0x79b76d99e2ULL) ^ + (-((b >> 2) & 1) & 0xf33e5fb3c4ULL) ^ + (-((b >> 3) & 1) & 0xae2eabe2a8ULL) ^ + (-((b >> 4) & 1) & 0x1e4f43e470ULL); +} + +static const char* charset = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"; + +static const int8_t charset_rev[128] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 15, -1, 10, 17, 21, 20, 26, 30, 7, 5, -1, -1, -1, -1, -1, -1, + -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1, + 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1, + -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1, + 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1 +}; + +int cash_encode(char *output, const char *hrp, const uint8_t *data, size_t data_len) { + uint64_t chk = 1; + size_t i = 0; + while (hrp[i] != 0) { + int ch = hrp[i]; + if (ch < 33 || ch > 126) { + return 0; + } + *(output++) = ch; + chk = cashaddr_polymod_step(chk) ^ (ch & 0x1f); + ++i; + } + if (i + 1 + data_len + CHECKSUM_SIZE > MAX_CASHADDR_SIZE) { + return 0; + } + chk = cashaddr_polymod_step(chk); + *(output++) = ':'; + for (i = 0; i < data_len; ++i) { + if (*data >> 5) return 0; + chk = cashaddr_polymod_step(chk) ^ (*data); + *(output++) = charset[*(data++)]; + } + for (i = 0; i < CHECKSUM_SIZE; ++i) { + chk = cashaddr_polymod_step(chk); + } + chk ^= 1; + for (i = 0; i < CHECKSUM_SIZE; ++i) { + *(output++) = charset[(chk >> ((CHECKSUM_SIZE - 1 - i) * 5)) & 0x1f]; + } + *output = 0; + return 1; +} + +int cash_decode(char* hrp, uint8_t *data, size_t *data_len, const char *input) { + uint64_t chk = 1; + size_t i; + size_t input_len = strlen(input); + size_t hrp_len; + int have_lower = 0, have_upper = 0; + if (input_len < CHECKSUM_SIZE || input_len > MAX_CASHADDR_SIZE) { + return 0; + } + *data_len = 0; + while (*data_len < input_len && input[(input_len - 1) - *data_len] != ':') { + ++(*data_len); + } + hrp_len = input_len - (1 + *data_len); + if (hrp_len < 1 || hrp_len > MAX_HRP_SIZE || + *data_len < CHECKSUM_SIZE || *data_len > CHECKSUM_SIZE + MAX_BASE32_SIZE) { + return 0; + } + // subtract checksum + *(data_len) -= CHECKSUM_SIZE; + for (i = 0; i < hrp_len; ++i) { + int ch = input[i]; + if (ch < 33 || ch > 126) { + return 0; + } + if (ch >= 'a' && ch <= 'z') { + have_lower = 1; + } else if (ch >= 'A' && ch <= 'Z') { + have_upper = 1; + ch = (ch - 'A') + 'a'; + } + hrp[i] = ch; + chk = cashaddr_polymod_step(chk) ^ (ch & 0x1f); + } + hrp[i] = 0; + chk = cashaddr_polymod_step(chk); + ++i; + while (i < input_len) { + int v = (input[i] & 0x80) ? -1 : charset_rev[(int)input[i]]; + if (input[i] >= 'a' && input[i] <= 'z') have_lower = 1; + if (input[i] >= 'A' && input[i] <= 'Z') have_upper = 1; + if (v == -1) { + return 0; + } + chk = cashaddr_polymod_step(chk) ^ v; + if (i + 6 < input_len) { + data[i - (1 + hrp_len)] = v; + } + ++i; + } + if (have_lower && have_upper) { + return 0; + } + return chk == 1; +} + +static int convert_bits(uint8_t* out, size_t* outlen, int outbits, const uint8_t* in, size_t inlen, int inbits, int pad) { + uint32_t val = 0; + int bits = 0; + uint32_t maxv = (((uint32_t)1) << outbits) - 1; + while (inlen--) { + val = (val << inbits) | *(in++); + bits += inbits; + while (bits >= outbits) { + bits -= outbits; + out[(*outlen)++] = (val >> bits) & maxv; + } + } + if (pad) { + if (bits) { + out[(*outlen)++] = (val << (outbits - bits)) & maxv; + } + } else if (((val << (outbits - bits)) & maxv) || bits >= inbits) { + return 0; + } + return 1; +} + +int cash_addr_encode(char *output, const char *hrp, const uint8_t *data, size_t data_len) { + uint8_t base32[MAX_BASE32_SIZE]; + size_t base32len = 0; + if (data_len < 2 || data_len > MAX_DATA_SIZE) return 0; + convert_bits(base32, &base32len, 5, data, data_len, 8, 1); + return cash_encode(output, hrp, base32, base32len); +} + +int cash_addr_decode(uint8_t* witdata, size_t* witdata_len, const char* hrp, const char* addr) { + uint8_t data[MAX_BASE32_SIZE]; + char hrp_actual[MAX_HRP_SIZE+1]; + size_t data_len; + if (!cash_decode(hrp_actual, data, &data_len, addr)) return 0; + if (data_len == 0 || data_len > MAX_BASE32_SIZE) return 0; + if (strncmp(hrp, hrp_actual, MAX_HRP_SIZE + 1) != 0) return 0; + *witdata_len = 0; + if (!convert_bits(witdata, witdata_len, 8, data, data_len, 5, 0)) return 0; + if (*witdata_len < 2 || *witdata_len > MAX_DATA_SIZE) return 0; + return 1; +} diff --git a/cash_addr.h b/cash_addr.h new file mode 100644 index 000000000..e88e76dd9 --- /dev/null +++ b/cash_addr.h @@ -0,0 +1,96 @@ +/* Copyright (c) 2017 Jochen Hoenicke, Pieter Wuille + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef _CASH_ADDR_H_ +#define _CASH_ADDR_H_ 1 + +#include + +/** Encode a Cashaddr address + * + * Out: output: Pointer to a buffer of size 105 + strlen(hrp) that will be + * updated to contain the null-terminated address. + * In: hrp: Pointer to the null-terminated human readable part to use + * (chain/network specific). + * prog: Data bytes for the hash (between 21 and 65 bytes). + * prog_len: Number of data bytes in prog. + * Returns 1 if successful. + */ +int cash_addr_encode( + char *output, + const char *hrp, + const uint8_t *prog, + size_t prog_len +); + +/** Decode a CashAddr address + * + * Out: prog: Pointer to a buffer of size 65 that will be updated to + * contain the witness program bytes. + * prog_len: Pointer to a size_t that will be updated to contain the length + * of bytes in prog. + * hrp: Pointer to the null-terminated human readable part that is + * expected (chain/network specific). + * addr: Pointer to the null-terminated address. + * Returns 1 if successful. + */ +int cash_addr_decode( + uint8_t* prog, + size_t* prog_len, + const char* hrp, + const char* addr +); + +/** Encode a Cash string + * + * Out: output: Pointer to a buffer of size strlen(hrp) + data_len + 8 that + * will be updated to contain the null-terminated Cash string. + * In: hrp : Pointer to the null-terminated human readable part. + * data : Pointer to an array of 5-bit values. + * data_len: Length of the data array. + * Returns 1 if successful. + */ +int cash_encode( + char *output, + const char *hrp, + const uint8_t *data, + size_t data_len +); + +/** Decode a Cash string + * + * Out: hrp: Pointer to a buffer of size strlen(input) - 6. Will be + * updated to contain the null-terminated human readable part. + * data: Pointer to a buffer of size strlen(input) - 8 that will + * hold the encoded 5-bit data values. + * data_len: Pointer to a size_t that will be updated to be the number + * of entries in data. + * In: input: Pointer to a null-terminated Cash string. + * Returns 1 if succesful. + */ +int cash_decode( + char *hrp, + uint8_t *data, + size_t *data_len, + const char *input +); + +#endif diff --git a/ecdsa.h b/ecdsa.h index ad5e47bfa..2d0e4c531 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -50,11 +50,13 @@ typedef struct { } ecdsa_curve; // 4 byte prefix + 40 byte data (segwit) -#define MAX_ADDR_RAW_SIZE (4 + 40) -// bottle neck is segwit bech32: -// 4 human readable prefix + 1 separator + 64 data + 6 checksum + 1 NUL -// the standard says 83 characters in hrp, but currently all coins use max 4 -#define MAX_ADDR_SIZE (4 + 1 + 64 + 6 + 1) +// 1 byte prefix + 64 byte data (cashaddr) +#define MAX_ADDR_RAW_SIZE 65 +// bottle neck is cashaddr +// segwit is at most 90 characters plus NUL separator +// cashaddr: human readable prefix + 1 separator + 104 data + 8 checksum + 1 NUL +// we choose 130 as maximum (including NUL character) +#define MAX_ADDR_SIZE 130 // 4 byte prefix + 32 byte privkey + 1 byte compressed marker #define MAX_WIF_RAW_SIZE (4 + 32 + 1) // (4 + 32 + 1 + 4 [checksum]) * 8 / log2(58) plus NUL. diff --git a/test_cashaddr.c b/test_cashaddr.c new file mode 100644 index 000000000..fe77db829 --- /dev/null +++ b/test_cashaddr.c @@ -0,0 +1,86 @@ +#include +#include +#include +#include + +#include "cash_addr.h" + +static const char* valid_cashchecksum[] = { + "prefix:x64nx6hz", + "p:gpf8m4h7", + "bitcoincash:qpzry9x8gf2tvdw0s3jn54khce6mua7lcw20ayyn", + "bchtest:testnetaddress4d6njnut", + "bchreg:555555555555555555555555555555555555555555555udxmlmrz", +}; + +struct valid_cashaddr_data { + const char* legacy; + const char* cashaddress; +}; + +static struct valid_cashaddr_data valid_cashaddr[] = { + { + "1BpEi6DfDAUFd7GtittLSdBeYJvcoaVggu", + "bitcoincash:qpm2qsznhks23z7629mms6s4cwef74vcwvy22gdx6a" + }, + { + "1KXrWXciRDZUpQwQmuM1DbwsKDLYAYsVLR", + "bitcoincash:qr95sy3j9xwd2ap32xkykttr4cvcu7as4y0qverfuy" + }, + { + "16w1D5WRVKJuZUsSRzdLp9w3YGcgoxDXb", + "bitcoincash:qqq3728yw0y47sqn6l2na30mcw6zm78dzqre909m2r" + }, + { + "3CWFddi6m4ndiGyKqzYvsFYagqDLPVMTzC", + "bitcoincash:ppm2qsznhks23z7629mms6s4cwef74vcwvn0h829pq" + }, + { + "3LDsS579y7sruadqu11beEJoTjdFiFCdX4", + "bitcoincash:pr95sy3j9xwd2ap32xkykttr4cvcu7as4yc93ky28e" + }, + { + "31nwvkZwyPdgzjBJZXfDmSWsC4ZLKpYyUw", + "bitcoincash:pqq3728yw0y47sqn6l2na30mcw6zm78dzq5ucqzc37" + } +}; + +START_TEST(test_cashaddr) +{ + size_t i; + for (i = 0; i < sizeof(valid_cashchecksum) / sizeof(valid_cashchecksum[0]); ++i) { + uint8_t data[82]; + char rebuild[92]; + char hrp[84]; + size_t data_len; + int res = cash_decode(hrp, data, &data_len, valid_cashchecksum[i]); + ck_assert_int_eq(res, 1); + res = cash_encode(rebuild, hrp, data, data_len); + ck_assert_int_eq(res, 1); + printf("%s\n", rebuild); + printf("%s\n", valid_cashchecksum[i]); + ck_assert_int_eq(my_strncasecmp(rebuild, valid_cashchecksum[i], 92), 0); + } + for (i = 0; i < sizeof(valid_cashaddr) / sizeof(valid_cashaddr[0]); ++i) { + uint8_t prog[65]; + size_t prog_len; + const char* hrp = "bitcoincash"; + uint8_t rawdata[65]; + size_t rawdata_len; + char rebuild[93]; + int ret = cash_addr_decode(prog, &prog_len, hrp, valid_cashaddr[i].cashaddress); + ck_assert_int_eq(ret, 1); + ck_assert_int_eq(prog_len, 21); + rawdata_len = base58_decode_check(valid_cashaddr[i].legacy, HASHER_SHA2, rawdata, sizeof(rawdata)); + ck_assert_int_eq(rawdata_len, 21); + ck_assert_int_eq(prog[0], rawdata[0] == 0 ? 0x00 : rawdata[0] == 5 ? 0x08 : -1); + ck_assert_int_eq(memcmp(rawdata + 1, prog + 1, 20), 0); + ret = cash_addr_encode(rebuild, hrp, prog, 21); + ck_assert_int_eq(ret, 1); + printf("%s\n", rebuild); + printf("%s\n", valid_cashaddr[i].cashaddress); + ck_assert_int_eq(my_strncasecmp(rebuild, valid_cashaddr[i].cashaddress, 92), 0); + } +} +END_TEST + diff --git a/test_check.c b/test_check.c index f6a1024c4..00c30caa7 100644 --- a/test_check.c +++ b/test_check.c @@ -4404,6 +4404,7 @@ START_TEST(test_rc4_rfc6229) END_TEST #include "test_segwit.c" +#include "test_cashaddr.c" // define test suite and cases Suite *test_suite(void) @@ -4631,6 +4632,10 @@ Suite *test_suite(void) tcase_add_test(tc, test_segwit); suite_add_tcase(s, tc); + tc = tcase_create("cashaddr"); + tcase_add_test(tc, test_cashaddr); + suite_add_tcase(s, tc); + return s; } From e81fb38ab452f2170769e9c454b10caaf8869974 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 5 Apr 2018 11:52:49 +0200 Subject: [PATCH 540/627] fix cashaddr test --- Makefile | 2 +- test_check.c | 5 +++-- test_cashaddr.c => test_check_cashaddr.h | 2 +- test_segwit.c => test_check_segwit.h | 0 4 files changed, 5 insertions(+), 4 deletions(-) rename test_cashaddr.c => test_check_cashaddr.h (98%) rename test_segwit.c => test_check_segwit.h (100%) diff --git a/Makefile b/Makefile index 606be78fb..88d3146ce 100644 --- a/Makefile +++ b/Makefile @@ -63,7 +63,7 @@ all: test_check test_openssl test_speed aes/aestst tools libtrezor-crypto.so %.o: %.c %.h options.h $(CC) $(CFLAGS) -o $@ -c $< -test_check.o: test_segwit.c test_cashaddr.c +test_check.o: test_check_segwit.h test_check_cashaddr.h aes/aestst: aes/aestst.o aes/aescrypt.o aes/aeskey.o aes/aestab.o $(CC) $^ -o $@ diff --git a/test_check.c b/test_check.c index 00c30caa7..7b6a335ba 100644 --- a/test_check.c +++ b/test_check.c @@ -4403,8 +4403,9 @@ START_TEST(test_rc4_rfc6229) } END_TEST -#include "test_segwit.c" -#include "test_cashaddr.c" +#include "test_check_segwit.h" + +#include "test_check_cashaddr.h" // define test suite and cases Suite *test_suite(void) diff --git a/test_cashaddr.c b/test_check_cashaddr.h similarity index 98% rename from test_cashaddr.c rename to test_check_cashaddr.h index fe77db829..51448de63 100644 --- a/test_cashaddr.c +++ b/test_check_cashaddr.h @@ -71,7 +71,7 @@ START_TEST(test_cashaddr) int ret = cash_addr_decode(prog, &prog_len, hrp, valid_cashaddr[i].cashaddress); ck_assert_int_eq(ret, 1); ck_assert_int_eq(prog_len, 21); - rawdata_len = base58_decode_check(valid_cashaddr[i].legacy, HASHER_SHA2, rawdata, sizeof(rawdata)); + rawdata_len = base58_decode_check(valid_cashaddr[i].legacy, HASHER_SHA2D, rawdata, sizeof(rawdata)); ck_assert_int_eq(rawdata_len, 21); ck_assert_int_eq(prog[0], rawdata[0] == 0 ? 0x00 : rawdata[0] == 5 ? 0x08 : -1); ck_assert_int_eq(memcmp(rawdata + 1, prog + 1, 20), 0); diff --git a/test_segwit.c b/test_check_segwit.h similarity index 100% rename from test_segwit.c rename to test_check_segwit.h From 7111431890f4a47913eb24ebc4f7fd827d6e38fd Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 5 Apr 2018 13:26:59 +0200 Subject: [PATCH 541/627] move tests into tests/ --- .gitignore | 11 ++--- .travis.yml | 11 +++-- CMakeLists.txt | 44 ------------------- Makefile | 26 ++++++----- test_check.c => tests/test_check.c | 0 .../test_check_cashaddr.h | 0 .../test_check_segwit.h | 0 test_curves.py => tests/test_curves.py | 0 test_openssl.c => tests/test_openssl.c | 0 test_speed.c => tests/test_speed.c | 0 10 files changed, 25 insertions(+), 67 deletions(-) delete mode 100644 CMakeLists.txt rename test_check.c => tests/test_check.c (100%) rename test_check_cashaddr.h => tests/test_check_cashaddr.h (100%) rename test_check_segwit.h => tests/test_check_segwit.h (100%) rename test_curves.py => tests/test_curves.py (100%) rename test_openssl.c => tests/test_openssl.c (100%) rename test_speed.c => tests/test_speed.c (100%) diff --git a/.gitignore b/.gitignore index a826ffce5..c98ec5d10 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,14 @@ +.cache/ .vscode/ _attic/ *.o *.d *.exe *~ -test_openssl -test_speed -test_check -aes/aestst +tests/aestst +tests/test_openssl +tests/test_speed +tests/test_check +tests/libtrezor-crypto.so *.os -*.so *.pyc diff --git a/.travis.yml b/.travis.yml index 8f2c902d3..f3e10e1dd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,12 +21,11 @@ install: script: - make - - ./aes/aestst - - ./test_check - - CK_TIMEOUT_MULTIPLIER=20 valgrind -q --error-exitcode=1 ./test_check - - ./test_openssl 1000 - - ITERS=10 py.test - - mkdir _build && cd _build && cmake .. && make && cd .. + - ./tests/aestst + - ./tests/test_check + - CK_TIMEOUT_MULTIPLIER=20 valgrind -q --error-exitcode=1 ./tests/test_check + - ./tests/test_openssl 1000 + - cd ./tests ; ITERS=10 pytest ; cd .. notifications: webhooks: diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100644 index 81e51f906..000000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,44 +0,0 @@ -cmake_minimum_required(VERSION 2.8) - -set(SOURCES - bignum.c ecdsa.c curves.c secp256k1.c nist256p1.c rand.c hmac.c bip32.c bip39.c pbkdf2.c base58.c base32.c - address.c - script.c - ripemd160.c - sha2.c - sha3.c - hasher.c - aes/aescrypt.c aes/aeskey.c aes/aestab.c aes/aes_modes.c - ed25519-donna/curve25519-donna-32bit.c ed25519-donna/curve25519-donna-helpers.c ed25519-donna/modm-donna-32bit.c - ed25519-donna/ed25519-donna-basepoint-table.c ed25519-donna/ed25519-donna-32bit-tables.c ed25519-donna/ed25519-donna-impl-base.c - ed25519-donna/ed25519.c ed25519-donna/curve25519-donna-scalarmult-base.c ed25519-donna/ed25519-sha3.c ed25519-donna/ed25519-keccak.c - blake256.c - blake2b.c blake2s.c - chacha20poly1305/chacha20poly1305.c chacha20poly1305/chacha_merged.c chacha20poly1305/poly1305-donna.c chacha20poly1305/rfc7539.c - rc4.c - nem.c -) - -add_library(TrezorCrypto STATIC ${SOURCES}) - -target_include_directories(TrezorCrypto PUBLIC .) -target_include_directories(TrezorCrypto PUBLIC aes) -target_include_directories(TrezorCrypto PUBLIC chacha20poly1305) -target_include_directories(TrezorCrypto PUBLIC ed25519-donna) - -target_compile_options(TrezorCrypto PRIVATE "-std=c99") - -if(MSVC) - set_source_files_properties(${SOURCES} PROPERTIES LANGUAGE CXX) -endif(MSVC) - -# Build trezor-crypto tests (requires OpenSSL) -if (TREZOR_CRYPTO_TESTS) - add_executable(test_check test_check.c) - target_link_libraries(test_check TrezorCrypto check rt pthread m crypto) - add_test(NAME trezor-crypto COMMAND test_check) - - add_executable(test_openssl test_openssl.c) - target_link_libraries(test_openssl TrezorCrypto check rt pthread m crypto) - add_test(NAME trezor-crypto-openssl COMMAND test_openssl 100) -endif() diff --git a/Makefile b/Makefile index 88d3146ce..ccbc3c7c7 100644 --- a/Makefile +++ b/Makefile @@ -58,27 +58,29 @@ OBJS = $(SRCS:.c=.o) TESTLIBS = $(shell pkg-config --libs check) -lpthread -lm TESTSSLLIBS = $(shell pkg-config --libs openssl) -all: test_check test_openssl test_speed aes/aestst tools libtrezor-crypto.so +all: tools tests %.o: %.c %.h options.h $(CC) $(CFLAGS) -o $@ -c $< -test_check.o: test_check_segwit.h test_check_cashaddr.h +tests: tests/test_check tests/test_openssl tests/test_speed tests/libtrezor-crypto.so tests/aestst -aes/aestst: aes/aestst.o aes/aescrypt.o aes/aeskey.o aes/aestab.o +tests/aestst: aes/aestst.o aes/aescrypt.o aes/aeskey.o aes/aestab.o $(CC) $^ -o $@ -test_check: test_check.o $(OBJS) - $(CC) test_check.o $(OBJS) $(TESTLIBS) -o test_check +tests/test_check.o: tests/test_check_segwit.h tests/test_check_cashaddr.h -test_speed: test_speed.o $(OBJS) - $(CC) test_speed.o $(OBJS) -o test_speed +tests/test_check: tests/test_check.o $(OBJS) + $(CC) tests/test_check.o $(OBJS) $(TESTLIBS) -o tests/test_check -test_openssl: test_openssl.o $(OBJS) - $(CC) test_openssl.o $(OBJS) $(TESTSSLLIBS) -o test_openssl +tests/test_speed: tests/test_speed.o $(OBJS) + $(CC) tests/test_speed.o $(OBJS) -o tests/test_speed -libtrezor-crypto.so: $(SRCS) - $(CC) $(CFLAGS) -fPIC -shared $(SRCS) -o libtrezor-crypto.so +tests/test_openssl: tests/test_openssl.o $(OBJS) + $(CC) tests/test_openssl.o $(OBJS) $(TESTSSLLIBS) -o tests/test_openssl + +tests/libtrezor-crypto.so: $(SRCS) + $(CC) $(CFLAGS) -fPIC -shared $(SRCS) -o tests/libtrezor-crypto.so tools: tools/xpubaddrgen tools/mktable tools/bip39bruteforce @@ -93,5 +95,5 @@ tools/bip39bruteforce: tools/bip39bruteforce.o $(OBJS) clean: rm -f *.o aes/*.o chacha20poly1305/*.o ed25519-donna/*.o - rm -f test_check test_speed test_openssl libtrezor-crypto.so + rm -f tests/test_check tests/test_speed tests/test_openssl tests/libtrezor-crypto.so tests/aestst rm -f tools/*.o tools/xpubaddrgen tools/mktable tools/bip39bruteforce diff --git a/test_check.c b/tests/test_check.c similarity index 100% rename from test_check.c rename to tests/test_check.c diff --git a/test_check_cashaddr.h b/tests/test_check_cashaddr.h similarity index 100% rename from test_check_cashaddr.h rename to tests/test_check_cashaddr.h diff --git a/test_check_segwit.h b/tests/test_check_segwit.h similarity index 100% rename from test_check_segwit.h rename to tests/test_check_segwit.h diff --git a/test_curves.py b/tests/test_curves.py similarity index 100% rename from test_curves.py rename to tests/test_curves.py diff --git a/test_openssl.c b/tests/test_openssl.c similarity index 100% rename from test_openssl.c rename to tests/test_openssl.c diff --git a/test_speed.c b/tests/test_speed.c similarity index 100% rename from test_speed.c rename to tests/test_speed.c From 7ea31aecf75e81c0d05a0e921dc6f856e7879123 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 5 Apr 2018 14:52:59 +0200 Subject: [PATCH 542/627] use python3 in travis --- .travis.yml | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index f3e10e1dd..751b1d44f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,14 +10,16 @@ addons: apt: packages: - check - - cmake - - cmake-data - libssl-dev - - python-pip + - python3-pip - valgrind +env: + global: + - PYTHON=python3 + install: - - pip install --user pytest ecdsa curve25519-donna + - $PYTHON -m pip install --user pytest ecdsa curve25519-donna script: - make @@ -25,7 +27,7 @@ script: - ./tests/test_check - CK_TIMEOUT_MULTIPLIER=20 valgrind -q --error-exitcode=1 ./tests/test_check - ./tests/test_openssl 1000 - - cd ./tests ; ITERS=10 pytest ; cd .. + - cd ./tests ; ITERS=10 $PYTHON -m pytest ; cd .. notifications: webhooks: From 8b61a7e36572b176f60e70d00fba9d368a601fb4 Mon Sep 17 00:00:00 2001 From: onvej-sl Date: Thu, 5 Apr 2018 16:02:07 +0200 Subject: [PATCH 543/627] python3 migration (#149) --- tests/test_curves.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_curves.py b/tests/test_curves.py index 1e0639647..db779166f 100755 --- a/tests/test_curves.py +++ b/tests/test_curves.py @@ -86,7 +86,7 @@ def r(request): @pytest.fixture(params=list(sorted(curves))) def curve(request): name = request.param - curve_ptr = lib.get_curve_by_name(name).contents.params + curve_ptr = lib.get_curve_by_name(bytes(name, "ascii")).contents.params assert curve_ptr, 'curve {} not found'.format(name) curve_obj = curves[name] curve_obj.ptr = c.c_void_p(curve_ptr) @@ -96,7 +96,7 @@ def curve(request): @pytest.fixture(params=points) def point(request): name = request.param.curve - curve_ptr = lib.get_curve_by_name(name).contents.params + curve_ptr = lib.get_curve_by_name(bytes(name, "ascii")).contents.params assert curve_ptr, 'curve {} not found'.format(name) curve_obj = curves[name] curve_obj.ptr = c.c_void_p(curve_ptr) @@ -435,4 +435,4 @@ def test_curve25519_scalarmult_from_gpg(r): res = r.randbytes(32) lib.curve25519_scalarmult(res, sec[::-1], pub[::-1]) expected = 'a93dbdb23e5c99da743e203bd391af79f2b83fb8d0fd6ec813371c71f08f2d4d' - assert binascii.hexlify(bytearray(res)) == expected + assert binascii.hexlify(bytearray(res)) == bytes(expected, "ascii") From 2fdcebfbb6c895927642e6efecabf00d44aad0ae Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Sun, 11 Mar 2018 11:35:45 +0700 Subject: [PATCH 544/627] Add Groestl hash --- Makefile | 4 +- groestl.c | 3113 ++++++++++++++++++++++++++++++++++++++++++++ groestl.h | 321 +++++ groestl_internal.h | 1976 ++++++++++++++++++++++++++++ hasher.c | 9 + hasher.h | 4 + 6 files changed, 5424 insertions(+), 3 deletions(-) create mode 100644 groestl.c create mode 100644 groestl.h create mode 100644 groestl_internal.h diff --git a/Makefile b/Makefile index ccbc3c7c7..851db5b02 100644 --- a/Makefile +++ b/Makefile @@ -10,8 +10,6 @@ CFLAGS += $(OPTFLAGS) \ -Wimplicit-function-declaration \ -Wredundant-decls \ -Wstrict-prototypes \ - -Wundef \ - -Wshadow \ -Wpointer-arith \ -Wformat \ -Wreturn-type \ @@ -21,7 +19,6 @@ CFLAGS += $(OPTFLAGS) \ -Winit-self \ -Wuninitialized \ -Wformat-security \ - -Werror CFLAGS += -I. CFLAGS += -DUSE_ETHEREUM=1 @@ -47,6 +44,7 @@ SRCS += ed25519-donna/ed25519-donna-basepoint-table.c ed25519-donna/ed25519-don SRCS += ed25519-donna/ed25519.c ed25519-donna/curve25519-donna-scalarmult-base.c ed25519-donna/ed25519-sha3.c ed25519-donna/ed25519-keccak.c SRCS += blake256.c SRCS += blake2b.c blake2s.c +SRCS += groestl.c SRCS += chacha20poly1305/chacha20poly1305.c chacha20poly1305/chacha_merged.c chacha20poly1305/poly1305-donna.c chacha20poly1305/rfc7539.c SRCS += rc4.c SRCS += nem.c diff --git a/groestl.c b/groestl.c new file mode 100644 index 000000000..a0c986fbc --- /dev/null +++ b/groestl.c @@ -0,0 +1,3113 @@ +/* $Id: groestl.c 260 2011-07-21 01:02:38Z tp $ */ +/* + * Groestl implementation. + * + * ==========================(LICENSE BEGIN)============================ + * + * Copyright (c) 2007-2010 Projet RNRT SAPHIR + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * ===========================(LICENSE END)============================= + * + * @author Thomas Pornin + */ + +#include +#include + +#define SPH_SMALL_FOOTPRINT 1 + +#include "groestl.h" + +#if SPH_SMALL_FOOTPRINT && !defined SPH_SMALL_FOOTPRINT_GROESTL +#define SPH_SMALL_FOOTPRINT_GROESTL 1 +#endif + +/* + * Apparently, the 32-bit-only version is not faster than the 64-bit + * version unless using the "small footprint" code on a 32-bit machine. + */ +#if !defined SPH_GROESTL_64 +#if SPH_SMALL_FOOTPRINT_GROESTL && !SPH_64_TRUE +#define SPH_GROESTL_64 0 +#else +#define SPH_GROESTL_64 1 +#endif +#endif + +#if !SPH_64 +#undef SPH_GROESTL_64 +#endif + +#ifdef _MSC_VER +#pragma warning (disable: 4146) +#endif + +/* + * The internal representation may use either big-endian or + * little-endian. Using the platform default representation speeds up + * encoding and decoding between bytes and the matrix columns. + */ + +#undef USE_LE +#if SPH_GROESTL_LITTLE_ENDIAN +#define USE_LE 1 +#elif SPH_GROESTL_BIG_ENDIAN +#define USE_LE 0 +#elif SPH_LITTLE_ENDIAN +#define USE_LE 1 +#endif + +#if USE_LE + +#define C32e(x) ((SPH_C32(x) >> 24) \ + | ((SPH_C32(x) >> 8) & SPH_C32(0x0000FF00)) \ + | ((SPH_C32(x) << 8) & SPH_C32(0x00FF0000)) \ + | ((SPH_C32(x) << 24) & SPH_C32(0xFF000000))) +#define dec32e_aligned sph_dec32le_aligned +#define enc32e sph_enc32le +#define B32_0(x) ((x) & 0xFF) +#define B32_1(x) (((x) >> 8) & 0xFF) +#define B32_2(x) (((x) >> 16) & 0xFF) +#define B32_3(x) ((x) >> 24) + +#define R32u(u, d) SPH_T32(((u) << 16) | ((d) >> 16)) +#define R32d(u, d) SPH_T32(((u) >> 16) | ((d) << 16)) + +#define PC32up(j, r) ((sph_u32)((j) + (r))) +#define PC32dn(j, r) 0 +#define QC32up(j, r) SPH_C32(0xFFFFFFFF) +#define QC32dn(j, r) (((sph_u32)(r) << 24) ^ SPH_T32(~((sph_u32)(j) << 24))) + +#if SPH_64 +#define C64e(x) ((SPH_C64(x) >> 56) \ + | ((SPH_C64(x) >> 40) & SPH_C64(0x000000000000FF00)) \ + | ((SPH_C64(x) >> 24) & SPH_C64(0x0000000000FF0000)) \ + | ((SPH_C64(x) >> 8) & SPH_C64(0x00000000FF000000)) \ + | ((SPH_C64(x) << 8) & SPH_C64(0x000000FF00000000)) \ + | ((SPH_C64(x) << 24) & SPH_C64(0x0000FF0000000000)) \ + | ((SPH_C64(x) << 40) & SPH_C64(0x00FF000000000000)) \ + | ((SPH_C64(x) << 56) & SPH_C64(0xFF00000000000000))) +#define dec64e_aligned sph_dec64le_aligned +#define enc64e sph_enc64le +#define B64_0(x) ((x) & 0xFF) +#define B64_1(x) (((x) >> 8) & 0xFF) +#define B64_2(x) (((x) >> 16) & 0xFF) +#define B64_3(x) (((x) >> 24) & 0xFF) +#define B64_4(x) (((x) >> 32) & 0xFF) +#define B64_5(x) (((x) >> 40) & 0xFF) +#define B64_6(x) (((x) >> 48) & 0xFF) +#define B64_7(x) ((x) >> 56) +#define R64 SPH_ROTL64 +#define PC64(j, r) ((sph_u64)((j) + (r))) +#define QC64(j, r) (((sph_u64)(r) << 56) ^ SPH_T64(~((sph_u64)(j) << 56))) +#endif + +#else + +#define C32e(x) SPH_C32(x) +#define dec32e_aligned sph_dec32be_aligned +#define enc32e sph_enc32be +#define B32_0(x) ((x) >> 24) +#define B32_1(x) (((x) >> 16) & 0xFF) +#define B32_2(x) (((x) >> 8) & 0xFF) +#define B32_3(x) ((x) & 0xFF) + +#define R32u(u, d) SPH_T32(((u) >> 16) | ((d) << 16)) +#define R32d(u, d) SPH_T32(((u) << 16) | ((d) >> 16)) + +#define PC32up(j, r) ((sph_u32)((j) + (r)) << 24) +#define PC32dn(j, r) 0 +#define QC32up(j, r) SPH_C32(0xFFFFFFFF) +#define QC32dn(j, r) ((sph_u32)(r) ^ SPH_T32(~(sph_u32)(j))) + +#if SPH_64 +#define C64e(x) SPH_C64(x) +#define dec64e_aligned sph_dec64be_aligned +#define enc64e sph_enc64be +#define B64_0(x) ((x) >> 56) +#define B64_1(x) (((x) >> 48) & 0xFF) +#define B64_2(x) (((x) >> 40) & 0xFF) +#define B64_3(x) (((x) >> 32) & 0xFF) +#define B64_4(x) (((x) >> 24) & 0xFF) +#define B64_5(x) (((x) >> 16) & 0xFF) +#define B64_6(x) (((x) >> 8) & 0xFF) +#define B64_7(x) ((x) & 0xFF) +#define R64 SPH_ROTR64 +#define PC64(j, r) ((sph_u64)((j) + (r)) << 56) +#define QC64(j, r) ((sph_u64)(r) ^ SPH_T64(~(sph_u64)(j))) +#endif + +#endif + +#if SPH_GROESTL_64 + +static const sph_u64 T0[] = { + C64e(0xc632f4a5f497a5c6), C64e(0xf86f978497eb84f8), + C64e(0xee5eb099b0c799ee), C64e(0xf67a8c8d8cf78df6), + C64e(0xffe8170d17e50dff), C64e(0xd60adcbddcb7bdd6), + C64e(0xde16c8b1c8a7b1de), C64e(0x916dfc54fc395491), + C64e(0x6090f050f0c05060), C64e(0x0207050305040302), + C64e(0xce2ee0a9e087a9ce), C64e(0x56d1877d87ac7d56), + C64e(0xe7cc2b192bd519e7), C64e(0xb513a662a67162b5), + C64e(0x4d7c31e6319ae64d), C64e(0xec59b59ab5c39aec), + C64e(0x8f40cf45cf05458f), C64e(0x1fa3bc9dbc3e9d1f), + C64e(0x8949c040c0094089), C64e(0xfa68928792ef87fa), + C64e(0xefd03f153fc515ef), C64e(0xb29426eb267febb2), + C64e(0x8ece40c94007c98e), C64e(0xfbe61d0b1ded0bfb), + C64e(0x416e2fec2f82ec41), C64e(0xb31aa967a97d67b3), + C64e(0x5f431cfd1cbefd5f), C64e(0x456025ea258aea45), + C64e(0x23f9dabfda46bf23), C64e(0x535102f702a6f753), + C64e(0xe445a196a1d396e4), C64e(0x9b76ed5bed2d5b9b), + C64e(0x75285dc25deac275), C64e(0xe1c5241c24d91ce1), + C64e(0x3dd4e9aee97aae3d), C64e(0x4cf2be6abe986a4c), + C64e(0x6c82ee5aeed85a6c), C64e(0x7ebdc341c3fc417e), + C64e(0xf5f3060206f102f5), C64e(0x8352d14fd11d4f83), + C64e(0x688ce45ce4d05c68), C64e(0x515607f407a2f451), + C64e(0xd18d5c345cb934d1), C64e(0xf9e1180818e908f9), + C64e(0xe24cae93aedf93e2), C64e(0xab3e9573954d73ab), + C64e(0x6297f553f5c45362), C64e(0x2a6b413f41543f2a), + C64e(0x081c140c14100c08), C64e(0x9563f652f6315295), + C64e(0x46e9af65af8c6546), C64e(0x9d7fe25ee2215e9d), + C64e(0x3048782878602830), C64e(0x37cff8a1f86ea137), + C64e(0x0a1b110f11140f0a), C64e(0x2febc4b5c45eb52f), + C64e(0x0e151b091b1c090e), C64e(0x247e5a365a483624), + C64e(0x1badb69bb6369b1b), C64e(0xdf98473d47a53ddf), + C64e(0xcda76a266a8126cd), C64e(0x4ef5bb69bb9c694e), + C64e(0x7f334ccd4cfecd7f), C64e(0xea50ba9fbacf9fea), + C64e(0x123f2d1b2d241b12), C64e(0x1da4b99eb93a9e1d), + C64e(0x58c49c749cb07458), C64e(0x3446722e72682e34), + C64e(0x3641772d776c2d36), C64e(0xdc11cdb2cda3b2dc), + C64e(0xb49d29ee2973eeb4), C64e(0x5b4d16fb16b6fb5b), + C64e(0xa4a501f60153f6a4), C64e(0x76a1d74dd7ec4d76), + C64e(0xb714a361a37561b7), C64e(0x7d3449ce49face7d), + C64e(0x52df8d7b8da47b52), C64e(0xdd9f423e42a13edd), + C64e(0x5ecd937193bc715e), C64e(0x13b1a297a2269713), + C64e(0xa6a204f50457f5a6), C64e(0xb901b868b86968b9), + C64e(0x0000000000000000), C64e(0xc1b5742c74992cc1), + C64e(0x40e0a060a0806040), C64e(0xe3c2211f21dd1fe3), + C64e(0x793a43c843f2c879), C64e(0xb69a2ced2c77edb6), + C64e(0xd40dd9bed9b3bed4), C64e(0x8d47ca46ca01468d), + C64e(0x671770d970ced967), C64e(0x72afdd4bdde44b72), + C64e(0x94ed79de7933de94), C64e(0x98ff67d4672bd498), + C64e(0xb09323e8237be8b0), C64e(0x855bde4ade114a85), + C64e(0xbb06bd6bbd6d6bbb), C64e(0xc5bb7e2a7e912ac5), + C64e(0x4f7b34e5349ee54f), C64e(0xedd73a163ac116ed), + C64e(0x86d254c55417c586), C64e(0x9af862d7622fd79a), + C64e(0x6699ff55ffcc5566), C64e(0x11b6a794a7229411), + C64e(0x8ac04acf4a0fcf8a), C64e(0xe9d9301030c910e9), + C64e(0x040e0a060a080604), C64e(0xfe66988198e781fe), + C64e(0xa0ab0bf00b5bf0a0), C64e(0x78b4cc44ccf04478), + C64e(0x25f0d5bad54aba25), C64e(0x4b753ee33e96e34b), + C64e(0xa2ac0ef30e5ff3a2), C64e(0x5d4419fe19bafe5d), + C64e(0x80db5bc05b1bc080), C64e(0x0580858a850a8a05), + C64e(0x3fd3ecadec7ead3f), C64e(0x21fedfbcdf42bc21), + C64e(0x70a8d848d8e04870), C64e(0xf1fd0c040cf904f1), + C64e(0x63197adf7ac6df63), C64e(0x772f58c158eec177), + C64e(0xaf309f759f4575af), C64e(0x42e7a563a5846342), + C64e(0x2070503050403020), C64e(0xe5cb2e1a2ed11ae5), + C64e(0xfdef120e12e10efd), C64e(0xbf08b76db7656dbf), + C64e(0x8155d44cd4194c81), C64e(0x18243c143c301418), + C64e(0x26795f355f4c3526), C64e(0xc3b2712f719d2fc3), + C64e(0xbe8638e13867e1be), C64e(0x35c8fda2fd6aa235), + C64e(0x88c74fcc4f0bcc88), C64e(0x2e654b394b5c392e), + C64e(0x936af957f93d5793), C64e(0x55580df20daaf255), + C64e(0xfc619d829de382fc), C64e(0x7ab3c947c9f4477a), + C64e(0xc827efacef8bacc8), C64e(0xba8832e7326fe7ba), + C64e(0x324f7d2b7d642b32), C64e(0xe642a495a4d795e6), + C64e(0xc03bfba0fb9ba0c0), C64e(0x19aab398b3329819), + C64e(0x9ef668d16827d19e), C64e(0xa322817f815d7fa3), + C64e(0x44eeaa66aa886644), C64e(0x54d6827e82a87e54), + C64e(0x3bdde6abe676ab3b), C64e(0x0b959e839e16830b), + C64e(0x8cc945ca4503ca8c), C64e(0xc7bc7b297b9529c7), + C64e(0x6b056ed36ed6d36b), C64e(0x286c443c44503c28), + C64e(0xa72c8b798b5579a7), C64e(0xbc813de23d63e2bc), + C64e(0x1631271d272c1d16), C64e(0xad379a769a4176ad), + C64e(0xdb964d3b4dad3bdb), C64e(0x649efa56fac85664), + C64e(0x74a6d24ed2e84e74), C64e(0x1436221e22281e14), + C64e(0x92e476db763fdb92), C64e(0x0c121e0a1e180a0c), + C64e(0x48fcb46cb4906c48), C64e(0xb88f37e4376be4b8), + C64e(0x9f78e75de7255d9f), C64e(0xbd0fb26eb2616ebd), + C64e(0x43692aef2a86ef43), C64e(0xc435f1a6f193a6c4), + C64e(0x39dae3a8e372a839), C64e(0x31c6f7a4f762a431), + C64e(0xd38a593759bd37d3), C64e(0xf274868b86ff8bf2), + C64e(0xd583563256b132d5), C64e(0x8b4ec543c50d438b), + C64e(0x6e85eb59ebdc596e), C64e(0xda18c2b7c2afb7da), + C64e(0x018e8f8c8f028c01), C64e(0xb11dac64ac7964b1), + C64e(0x9cf16dd26d23d29c), C64e(0x49723be03b92e049), + C64e(0xd81fc7b4c7abb4d8), C64e(0xacb915fa1543faac), + C64e(0xf3fa090709fd07f3), C64e(0xcfa06f256f8525cf), + C64e(0xca20eaafea8fafca), C64e(0xf47d898e89f38ef4), + C64e(0x476720e9208ee947), C64e(0x1038281828201810), + C64e(0x6f0b64d564ded56f), C64e(0xf073838883fb88f0), + C64e(0x4afbb16fb1946f4a), C64e(0x5cca967296b8725c), + C64e(0x38546c246c702438), C64e(0x575f08f108aef157), + C64e(0x732152c752e6c773), C64e(0x9764f351f3355197), + C64e(0xcbae6523658d23cb), C64e(0xa125847c84597ca1), + C64e(0xe857bf9cbfcb9ce8), C64e(0x3e5d6321637c213e), + C64e(0x96ea7cdd7c37dd96), C64e(0x611e7fdc7fc2dc61), + C64e(0x0d9c9186911a860d), C64e(0x0f9b9485941e850f), + C64e(0xe04bab90abdb90e0), C64e(0x7cbac642c6f8427c), + C64e(0x712657c457e2c471), C64e(0xcc29e5aae583aacc), + C64e(0x90e373d8733bd890), C64e(0x06090f050f0c0506), + C64e(0xf7f4030103f501f7), C64e(0x1c2a36123638121c), + C64e(0xc23cfea3fe9fa3c2), C64e(0x6a8be15fe1d45f6a), + C64e(0xaebe10f91047f9ae), C64e(0x69026bd06bd2d069), + C64e(0x17bfa891a82e9117), C64e(0x9971e858e8295899), + C64e(0x3a5369276974273a), C64e(0x27f7d0b9d04eb927), + C64e(0xd991483848a938d9), C64e(0xebde351335cd13eb), + C64e(0x2be5ceb3ce56b32b), C64e(0x2277553355443322), + C64e(0xd204d6bbd6bfbbd2), C64e(0xa9399070904970a9), + C64e(0x07878089800e8907), C64e(0x33c1f2a7f266a733), + C64e(0x2decc1b6c15ab62d), C64e(0x3c5a66226678223c), + C64e(0x15b8ad92ad2a9215), C64e(0xc9a96020608920c9), + C64e(0x875cdb49db154987), C64e(0xaab01aff1a4fffaa), + C64e(0x50d8887888a07850), C64e(0xa52b8e7a8e517aa5), + C64e(0x03898a8f8a068f03), C64e(0x594a13f813b2f859), + C64e(0x09929b809b128009), C64e(0x1a2339173934171a), + C64e(0x651075da75cada65), C64e(0xd784533153b531d7), + C64e(0x84d551c65113c684), C64e(0xd003d3b8d3bbb8d0), + C64e(0x82dc5ec35e1fc382), C64e(0x29e2cbb0cb52b029), + C64e(0x5ac3997799b4775a), C64e(0x1e2d3311333c111e), + C64e(0x7b3d46cb46f6cb7b), C64e(0xa8b71ffc1f4bfca8), + C64e(0x6d0c61d661dad66d), C64e(0x2c624e3a4e583a2c) +}; + +#if !SPH_SMALL_FOOTPRINT_GROESTL + +static const sph_u64 T1[] = { + C64e(0xc6c632f4a5f497a5), C64e(0xf8f86f978497eb84), + C64e(0xeeee5eb099b0c799), C64e(0xf6f67a8c8d8cf78d), + C64e(0xffffe8170d17e50d), C64e(0xd6d60adcbddcb7bd), + C64e(0xdede16c8b1c8a7b1), C64e(0x91916dfc54fc3954), + C64e(0x606090f050f0c050), C64e(0x0202070503050403), + C64e(0xcece2ee0a9e087a9), C64e(0x5656d1877d87ac7d), + C64e(0xe7e7cc2b192bd519), C64e(0xb5b513a662a67162), + C64e(0x4d4d7c31e6319ae6), C64e(0xecec59b59ab5c39a), + C64e(0x8f8f40cf45cf0545), C64e(0x1f1fa3bc9dbc3e9d), + C64e(0x898949c040c00940), C64e(0xfafa68928792ef87), + C64e(0xefefd03f153fc515), C64e(0xb2b29426eb267feb), + C64e(0x8e8ece40c94007c9), C64e(0xfbfbe61d0b1ded0b), + C64e(0x41416e2fec2f82ec), C64e(0xb3b31aa967a97d67), + C64e(0x5f5f431cfd1cbefd), C64e(0x45456025ea258aea), + C64e(0x2323f9dabfda46bf), C64e(0x53535102f702a6f7), + C64e(0xe4e445a196a1d396), C64e(0x9b9b76ed5bed2d5b), + C64e(0x7575285dc25deac2), C64e(0xe1e1c5241c24d91c), + C64e(0x3d3dd4e9aee97aae), C64e(0x4c4cf2be6abe986a), + C64e(0x6c6c82ee5aeed85a), C64e(0x7e7ebdc341c3fc41), + C64e(0xf5f5f3060206f102), C64e(0x838352d14fd11d4f), + C64e(0x68688ce45ce4d05c), C64e(0x51515607f407a2f4), + C64e(0xd1d18d5c345cb934), C64e(0xf9f9e1180818e908), + C64e(0xe2e24cae93aedf93), C64e(0xabab3e9573954d73), + C64e(0x626297f553f5c453), C64e(0x2a2a6b413f41543f), + C64e(0x08081c140c14100c), C64e(0x959563f652f63152), + C64e(0x4646e9af65af8c65), C64e(0x9d9d7fe25ee2215e), + C64e(0x3030487828786028), C64e(0x3737cff8a1f86ea1), + C64e(0x0a0a1b110f11140f), C64e(0x2f2febc4b5c45eb5), + C64e(0x0e0e151b091b1c09), C64e(0x24247e5a365a4836), + C64e(0x1b1badb69bb6369b), C64e(0xdfdf98473d47a53d), + C64e(0xcdcda76a266a8126), C64e(0x4e4ef5bb69bb9c69), + C64e(0x7f7f334ccd4cfecd), C64e(0xeaea50ba9fbacf9f), + C64e(0x12123f2d1b2d241b), C64e(0x1d1da4b99eb93a9e), + C64e(0x5858c49c749cb074), C64e(0x343446722e72682e), + C64e(0x363641772d776c2d), C64e(0xdcdc11cdb2cda3b2), + C64e(0xb4b49d29ee2973ee), C64e(0x5b5b4d16fb16b6fb), + C64e(0xa4a4a501f60153f6), C64e(0x7676a1d74dd7ec4d), + C64e(0xb7b714a361a37561), C64e(0x7d7d3449ce49face), + C64e(0x5252df8d7b8da47b), C64e(0xdddd9f423e42a13e), + C64e(0x5e5ecd937193bc71), C64e(0x1313b1a297a22697), + C64e(0xa6a6a204f50457f5), C64e(0xb9b901b868b86968), + C64e(0x0000000000000000), C64e(0xc1c1b5742c74992c), + C64e(0x4040e0a060a08060), C64e(0xe3e3c2211f21dd1f), + C64e(0x79793a43c843f2c8), C64e(0xb6b69a2ced2c77ed), + C64e(0xd4d40dd9bed9b3be), C64e(0x8d8d47ca46ca0146), + C64e(0x67671770d970ced9), C64e(0x7272afdd4bdde44b), + C64e(0x9494ed79de7933de), C64e(0x9898ff67d4672bd4), + C64e(0xb0b09323e8237be8), C64e(0x85855bde4ade114a), + C64e(0xbbbb06bd6bbd6d6b), C64e(0xc5c5bb7e2a7e912a), + C64e(0x4f4f7b34e5349ee5), C64e(0xededd73a163ac116), + C64e(0x8686d254c55417c5), C64e(0x9a9af862d7622fd7), + C64e(0x666699ff55ffcc55), C64e(0x1111b6a794a72294), + C64e(0x8a8ac04acf4a0fcf), C64e(0xe9e9d9301030c910), + C64e(0x04040e0a060a0806), C64e(0xfefe66988198e781), + C64e(0xa0a0ab0bf00b5bf0), C64e(0x7878b4cc44ccf044), + C64e(0x2525f0d5bad54aba), C64e(0x4b4b753ee33e96e3), + C64e(0xa2a2ac0ef30e5ff3), C64e(0x5d5d4419fe19bafe), + C64e(0x8080db5bc05b1bc0), C64e(0x050580858a850a8a), + C64e(0x3f3fd3ecadec7ead), C64e(0x2121fedfbcdf42bc), + C64e(0x7070a8d848d8e048), C64e(0xf1f1fd0c040cf904), + C64e(0x6363197adf7ac6df), C64e(0x77772f58c158eec1), + C64e(0xafaf309f759f4575), C64e(0x4242e7a563a58463), + C64e(0x2020705030504030), C64e(0xe5e5cb2e1a2ed11a), + C64e(0xfdfdef120e12e10e), C64e(0xbfbf08b76db7656d), + C64e(0x818155d44cd4194c), C64e(0x1818243c143c3014), + C64e(0x2626795f355f4c35), C64e(0xc3c3b2712f719d2f), + C64e(0xbebe8638e13867e1), C64e(0x3535c8fda2fd6aa2), + C64e(0x8888c74fcc4f0bcc), C64e(0x2e2e654b394b5c39), + C64e(0x93936af957f93d57), C64e(0x5555580df20daaf2), + C64e(0xfcfc619d829de382), C64e(0x7a7ab3c947c9f447), + C64e(0xc8c827efacef8bac), C64e(0xbaba8832e7326fe7), + C64e(0x32324f7d2b7d642b), C64e(0xe6e642a495a4d795), + C64e(0xc0c03bfba0fb9ba0), C64e(0x1919aab398b33298), + C64e(0x9e9ef668d16827d1), C64e(0xa3a322817f815d7f), + C64e(0x4444eeaa66aa8866), C64e(0x5454d6827e82a87e), + C64e(0x3b3bdde6abe676ab), C64e(0x0b0b959e839e1683), + C64e(0x8c8cc945ca4503ca), C64e(0xc7c7bc7b297b9529), + C64e(0x6b6b056ed36ed6d3), C64e(0x28286c443c44503c), + C64e(0xa7a72c8b798b5579), C64e(0xbcbc813de23d63e2), + C64e(0x161631271d272c1d), C64e(0xadad379a769a4176), + C64e(0xdbdb964d3b4dad3b), C64e(0x64649efa56fac856), + C64e(0x7474a6d24ed2e84e), C64e(0x141436221e22281e), + C64e(0x9292e476db763fdb), C64e(0x0c0c121e0a1e180a), + C64e(0x4848fcb46cb4906c), C64e(0xb8b88f37e4376be4), + C64e(0x9f9f78e75de7255d), C64e(0xbdbd0fb26eb2616e), + C64e(0x4343692aef2a86ef), C64e(0xc4c435f1a6f193a6), + C64e(0x3939dae3a8e372a8), C64e(0x3131c6f7a4f762a4), + C64e(0xd3d38a593759bd37), C64e(0xf2f274868b86ff8b), + C64e(0xd5d583563256b132), C64e(0x8b8b4ec543c50d43), + C64e(0x6e6e85eb59ebdc59), C64e(0xdada18c2b7c2afb7), + C64e(0x01018e8f8c8f028c), C64e(0xb1b11dac64ac7964), + C64e(0x9c9cf16dd26d23d2), C64e(0x4949723be03b92e0), + C64e(0xd8d81fc7b4c7abb4), C64e(0xacacb915fa1543fa), + C64e(0xf3f3fa090709fd07), C64e(0xcfcfa06f256f8525), + C64e(0xcaca20eaafea8faf), C64e(0xf4f47d898e89f38e), + C64e(0x47476720e9208ee9), C64e(0x1010382818282018), + C64e(0x6f6f0b64d564ded5), C64e(0xf0f073838883fb88), + C64e(0x4a4afbb16fb1946f), C64e(0x5c5cca967296b872), + C64e(0x3838546c246c7024), C64e(0x57575f08f108aef1), + C64e(0x73732152c752e6c7), C64e(0x979764f351f33551), + C64e(0xcbcbae6523658d23), C64e(0xa1a125847c84597c), + C64e(0xe8e857bf9cbfcb9c), C64e(0x3e3e5d6321637c21), + C64e(0x9696ea7cdd7c37dd), C64e(0x61611e7fdc7fc2dc), + C64e(0x0d0d9c9186911a86), C64e(0x0f0f9b9485941e85), + C64e(0xe0e04bab90abdb90), C64e(0x7c7cbac642c6f842), + C64e(0x71712657c457e2c4), C64e(0xcccc29e5aae583aa), + C64e(0x9090e373d8733bd8), C64e(0x0606090f050f0c05), + C64e(0xf7f7f4030103f501), C64e(0x1c1c2a3612363812), + C64e(0xc2c23cfea3fe9fa3), C64e(0x6a6a8be15fe1d45f), + C64e(0xaeaebe10f91047f9), C64e(0x6969026bd06bd2d0), + C64e(0x1717bfa891a82e91), C64e(0x999971e858e82958), + C64e(0x3a3a536927697427), C64e(0x2727f7d0b9d04eb9), + C64e(0xd9d991483848a938), C64e(0xebebde351335cd13), + C64e(0x2b2be5ceb3ce56b3), C64e(0x2222775533554433), + C64e(0xd2d204d6bbd6bfbb), C64e(0xa9a9399070904970), + C64e(0x0707878089800e89), C64e(0x3333c1f2a7f266a7), + C64e(0x2d2decc1b6c15ab6), C64e(0x3c3c5a6622667822), + C64e(0x1515b8ad92ad2a92), C64e(0xc9c9a96020608920), + C64e(0x87875cdb49db1549), C64e(0xaaaab01aff1a4fff), + C64e(0x5050d8887888a078), C64e(0xa5a52b8e7a8e517a), + C64e(0x0303898a8f8a068f), C64e(0x59594a13f813b2f8), + C64e(0x0909929b809b1280), C64e(0x1a1a233917393417), + C64e(0x65651075da75cada), C64e(0xd7d784533153b531), + C64e(0x8484d551c65113c6), C64e(0xd0d003d3b8d3bbb8), + C64e(0x8282dc5ec35e1fc3), C64e(0x2929e2cbb0cb52b0), + C64e(0x5a5ac3997799b477), C64e(0x1e1e2d3311333c11), + C64e(0x7b7b3d46cb46f6cb), C64e(0xa8a8b71ffc1f4bfc), + C64e(0x6d6d0c61d661dad6), C64e(0x2c2c624e3a4e583a) +}; + +static const sph_u64 T2[] = { + C64e(0xa5c6c632f4a5f497), C64e(0x84f8f86f978497eb), + C64e(0x99eeee5eb099b0c7), C64e(0x8df6f67a8c8d8cf7), + C64e(0x0dffffe8170d17e5), C64e(0xbdd6d60adcbddcb7), + C64e(0xb1dede16c8b1c8a7), C64e(0x5491916dfc54fc39), + C64e(0x50606090f050f0c0), C64e(0x0302020705030504), + C64e(0xa9cece2ee0a9e087), C64e(0x7d5656d1877d87ac), + C64e(0x19e7e7cc2b192bd5), C64e(0x62b5b513a662a671), + C64e(0xe64d4d7c31e6319a), C64e(0x9aecec59b59ab5c3), + C64e(0x458f8f40cf45cf05), C64e(0x9d1f1fa3bc9dbc3e), + C64e(0x40898949c040c009), C64e(0x87fafa68928792ef), + C64e(0x15efefd03f153fc5), C64e(0xebb2b29426eb267f), + C64e(0xc98e8ece40c94007), C64e(0x0bfbfbe61d0b1ded), + C64e(0xec41416e2fec2f82), C64e(0x67b3b31aa967a97d), + C64e(0xfd5f5f431cfd1cbe), C64e(0xea45456025ea258a), + C64e(0xbf2323f9dabfda46), C64e(0xf753535102f702a6), + C64e(0x96e4e445a196a1d3), C64e(0x5b9b9b76ed5bed2d), + C64e(0xc27575285dc25dea), C64e(0x1ce1e1c5241c24d9), + C64e(0xae3d3dd4e9aee97a), C64e(0x6a4c4cf2be6abe98), + C64e(0x5a6c6c82ee5aeed8), C64e(0x417e7ebdc341c3fc), + C64e(0x02f5f5f3060206f1), C64e(0x4f838352d14fd11d), + C64e(0x5c68688ce45ce4d0), C64e(0xf451515607f407a2), + C64e(0x34d1d18d5c345cb9), C64e(0x08f9f9e1180818e9), + C64e(0x93e2e24cae93aedf), C64e(0x73abab3e9573954d), + C64e(0x53626297f553f5c4), C64e(0x3f2a2a6b413f4154), + C64e(0x0c08081c140c1410), C64e(0x52959563f652f631), + C64e(0x654646e9af65af8c), C64e(0x5e9d9d7fe25ee221), + C64e(0x2830304878287860), C64e(0xa13737cff8a1f86e), + C64e(0x0f0a0a1b110f1114), C64e(0xb52f2febc4b5c45e), + C64e(0x090e0e151b091b1c), C64e(0x3624247e5a365a48), + C64e(0x9b1b1badb69bb636), C64e(0x3ddfdf98473d47a5), + C64e(0x26cdcda76a266a81), C64e(0x694e4ef5bb69bb9c), + C64e(0xcd7f7f334ccd4cfe), C64e(0x9feaea50ba9fbacf), + C64e(0x1b12123f2d1b2d24), C64e(0x9e1d1da4b99eb93a), + C64e(0x745858c49c749cb0), C64e(0x2e343446722e7268), + C64e(0x2d363641772d776c), C64e(0xb2dcdc11cdb2cda3), + C64e(0xeeb4b49d29ee2973), C64e(0xfb5b5b4d16fb16b6), + C64e(0xf6a4a4a501f60153), C64e(0x4d7676a1d74dd7ec), + C64e(0x61b7b714a361a375), C64e(0xce7d7d3449ce49fa), + C64e(0x7b5252df8d7b8da4), C64e(0x3edddd9f423e42a1), + C64e(0x715e5ecd937193bc), C64e(0x971313b1a297a226), + C64e(0xf5a6a6a204f50457), C64e(0x68b9b901b868b869), + C64e(0x0000000000000000), C64e(0x2cc1c1b5742c7499), + C64e(0x604040e0a060a080), C64e(0x1fe3e3c2211f21dd), + C64e(0xc879793a43c843f2), C64e(0xedb6b69a2ced2c77), + C64e(0xbed4d40dd9bed9b3), C64e(0x468d8d47ca46ca01), + C64e(0xd967671770d970ce), C64e(0x4b7272afdd4bdde4), + C64e(0xde9494ed79de7933), C64e(0xd49898ff67d4672b), + C64e(0xe8b0b09323e8237b), C64e(0x4a85855bde4ade11), + C64e(0x6bbbbb06bd6bbd6d), C64e(0x2ac5c5bb7e2a7e91), + C64e(0xe54f4f7b34e5349e), C64e(0x16ededd73a163ac1), + C64e(0xc58686d254c55417), C64e(0xd79a9af862d7622f), + C64e(0x55666699ff55ffcc), C64e(0x941111b6a794a722), + C64e(0xcf8a8ac04acf4a0f), C64e(0x10e9e9d9301030c9), + C64e(0x0604040e0a060a08), C64e(0x81fefe66988198e7), + C64e(0xf0a0a0ab0bf00b5b), C64e(0x447878b4cc44ccf0), + C64e(0xba2525f0d5bad54a), C64e(0xe34b4b753ee33e96), + C64e(0xf3a2a2ac0ef30e5f), C64e(0xfe5d5d4419fe19ba), + C64e(0xc08080db5bc05b1b), C64e(0x8a050580858a850a), + C64e(0xad3f3fd3ecadec7e), C64e(0xbc2121fedfbcdf42), + C64e(0x487070a8d848d8e0), C64e(0x04f1f1fd0c040cf9), + C64e(0xdf6363197adf7ac6), C64e(0xc177772f58c158ee), + C64e(0x75afaf309f759f45), C64e(0x634242e7a563a584), + C64e(0x3020207050305040), C64e(0x1ae5e5cb2e1a2ed1), + C64e(0x0efdfdef120e12e1), C64e(0x6dbfbf08b76db765), + C64e(0x4c818155d44cd419), C64e(0x141818243c143c30), + C64e(0x352626795f355f4c), C64e(0x2fc3c3b2712f719d), + C64e(0xe1bebe8638e13867), C64e(0xa23535c8fda2fd6a), + C64e(0xcc8888c74fcc4f0b), C64e(0x392e2e654b394b5c), + C64e(0x5793936af957f93d), C64e(0xf25555580df20daa), + C64e(0x82fcfc619d829de3), C64e(0x477a7ab3c947c9f4), + C64e(0xacc8c827efacef8b), C64e(0xe7baba8832e7326f), + C64e(0x2b32324f7d2b7d64), C64e(0x95e6e642a495a4d7), + C64e(0xa0c0c03bfba0fb9b), C64e(0x981919aab398b332), + C64e(0xd19e9ef668d16827), C64e(0x7fa3a322817f815d), + C64e(0x664444eeaa66aa88), C64e(0x7e5454d6827e82a8), + C64e(0xab3b3bdde6abe676), C64e(0x830b0b959e839e16), + C64e(0xca8c8cc945ca4503), C64e(0x29c7c7bc7b297b95), + C64e(0xd36b6b056ed36ed6), C64e(0x3c28286c443c4450), + C64e(0x79a7a72c8b798b55), C64e(0xe2bcbc813de23d63), + C64e(0x1d161631271d272c), C64e(0x76adad379a769a41), + C64e(0x3bdbdb964d3b4dad), C64e(0x5664649efa56fac8), + C64e(0x4e7474a6d24ed2e8), C64e(0x1e141436221e2228), + C64e(0xdb9292e476db763f), C64e(0x0a0c0c121e0a1e18), + C64e(0x6c4848fcb46cb490), C64e(0xe4b8b88f37e4376b), + C64e(0x5d9f9f78e75de725), C64e(0x6ebdbd0fb26eb261), + C64e(0xef4343692aef2a86), C64e(0xa6c4c435f1a6f193), + C64e(0xa83939dae3a8e372), C64e(0xa43131c6f7a4f762), + C64e(0x37d3d38a593759bd), C64e(0x8bf2f274868b86ff), + C64e(0x32d5d583563256b1), C64e(0x438b8b4ec543c50d), + C64e(0x596e6e85eb59ebdc), C64e(0xb7dada18c2b7c2af), + C64e(0x8c01018e8f8c8f02), C64e(0x64b1b11dac64ac79), + C64e(0xd29c9cf16dd26d23), C64e(0xe04949723be03b92), + C64e(0xb4d8d81fc7b4c7ab), C64e(0xfaacacb915fa1543), + C64e(0x07f3f3fa090709fd), C64e(0x25cfcfa06f256f85), + C64e(0xafcaca20eaafea8f), C64e(0x8ef4f47d898e89f3), + C64e(0xe947476720e9208e), C64e(0x1810103828182820), + C64e(0xd56f6f0b64d564de), C64e(0x88f0f073838883fb), + C64e(0x6f4a4afbb16fb194), C64e(0x725c5cca967296b8), + C64e(0x243838546c246c70), C64e(0xf157575f08f108ae), + C64e(0xc773732152c752e6), C64e(0x51979764f351f335), + C64e(0x23cbcbae6523658d), C64e(0x7ca1a125847c8459), + C64e(0x9ce8e857bf9cbfcb), C64e(0x213e3e5d6321637c), + C64e(0xdd9696ea7cdd7c37), C64e(0xdc61611e7fdc7fc2), + C64e(0x860d0d9c9186911a), C64e(0x850f0f9b9485941e), + C64e(0x90e0e04bab90abdb), C64e(0x427c7cbac642c6f8), + C64e(0xc471712657c457e2), C64e(0xaacccc29e5aae583), + C64e(0xd89090e373d8733b), C64e(0x050606090f050f0c), + C64e(0x01f7f7f4030103f5), C64e(0x121c1c2a36123638), + C64e(0xa3c2c23cfea3fe9f), C64e(0x5f6a6a8be15fe1d4), + C64e(0xf9aeaebe10f91047), C64e(0xd06969026bd06bd2), + C64e(0x911717bfa891a82e), C64e(0x58999971e858e829), + C64e(0x273a3a5369276974), C64e(0xb92727f7d0b9d04e), + C64e(0x38d9d991483848a9), C64e(0x13ebebde351335cd), + C64e(0xb32b2be5ceb3ce56), C64e(0x3322227755335544), + C64e(0xbbd2d204d6bbd6bf), C64e(0x70a9a93990709049), + C64e(0x890707878089800e), C64e(0xa73333c1f2a7f266), + C64e(0xb62d2decc1b6c15a), C64e(0x223c3c5a66226678), + C64e(0x921515b8ad92ad2a), C64e(0x20c9c9a960206089), + C64e(0x4987875cdb49db15), C64e(0xffaaaab01aff1a4f), + C64e(0x785050d8887888a0), C64e(0x7aa5a52b8e7a8e51), + C64e(0x8f0303898a8f8a06), C64e(0xf859594a13f813b2), + C64e(0x800909929b809b12), C64e(0x171a1a2339173934), + C64e(0xda65651075da75ca), C64e(0x31d7d784533153b5), + C64e(0xc68484d551c65113), C64e(0xb8d0d003d3b8d3bb), + C64e(0xc38282dc5ec35e1f), C64e(0xb02929e2cbb0cb52), + C64e(0x775a5ac3997799b4), C64e(0x111e1e2d3311333c), + C64e(0xcb7b7b3d46cb46f6), C64e(0xfca8a8b71ffc1f4b), + C64e(0xd66d6d0c61d661da), C64e(0x3a2c2c624e3a4e58) +}; + +static const sph_u64 T3[] = { + C64e(0x97a5c6c632f4a5f4), C64e(0xeb84f8f86f978497), + C64e(0xc799eeee5eb099b0), C64e(0xf78df6f67a8c8d8c), + C64e(0xe50dffffe8170d17), C64e(0xb7bdd6d60adcbddc), + C64e(0xa7b1dede16c8b1c8), C64e(0x395491916dfc54fc), + C64e(0xc050606090f050f0), C64e(0x0403020207050305), + C64e(0x87a9cece2ee0a9e0), C64e(0xac7d5656d1877d87), + C64e(0xd519e7e7cc2b192b), C64e(0x7162b5b513a662a6), + C64e(0x9ae64d4d7c31e631), C64e(0xc39aecec59b59ab5), + C64e(0x05458f8f40cf45cf), C64e(0x3e9d1f1fa3bc9dbc), + C64e(0x0940898949c040c0), C64e(0xef87fafa68928792), + C64e(0xc515efefd03f153f), C64e(0x7febb2b29426eb26), + C64e(0x07c98e8ece40c940), C64e(0xed0bfbfbe61d0b1d), + C64e(0x82ec41416e2fec2f), C64e(0x7d67b3b31aa967a9), + C64e(0xbefd5f5f431cfd1c), C64e(0x8aea45456025ea25), + C64e(0x46bf2323f9dabfda), C64e(0xa6f753535102f702), + C64e(0xd396e4e445a196a1), C64e(0x2d5b9b9b76ed5bed), + C64e(0xeac27575285dc25d), C64e(0xd91ce1e1c5241c24), + C64e(0x7aae3d3dd4e9aee9), C64e(0x986a4c4cf2be6abe), + C64e(0xd85a6c6c82ee5aee), C64e(0xfc417e7ebdc341c3), + C64e(0xf102f5f5f3060206), C64e(0x1d4f838352d14fd1), + C64e(0xd05c68688ce45ce4), C64e(0xa2f451515607f407), + C64e(0xb934d1d18d5c345c), C64e(0xe908f9f9e1180818), + C64e(0xdf93e2e24cae93ae), C64e(0x4d73abab3e957395), + C64e(0xc453626297f553f5), C64e(0x543f2a2a6b413f41), + C64e(0x100c08081c140c14), C64e(0x3152959563f652f6), + C64e(0x8c654646e9af65af), C64e(0x215e9d9d7fe25ee2), + C64e(0x6028303048782878), C64e(0x6ea13737cff8a1f8), + C64e(0x140f0a0a1b110f11), C64e(0x5eb52f2febc4b5c4), + C64e(0x1c090e0e151b091b), C64e(0x483624247e5a365a), + C64e(0x369b1b1badb69bb6), C64e(0xa53ddfdf98473d47), + C64e(0x8126cdcda76a266a), C64e(0x9c694e4ef5bb69bb), + C64e(0xfecd7f7f334ccd4c), C64e(0xcf9feaea50ba9fba), + C64e(0x241b12123f2d1b2d), C64e(0x3a9e1d1da4b99eb9), + C64e(0xb0745858c49c749c), C64e(0x682e343446722e72), + C64e(0x6c2d363641772d77), C64e(0xa3b2dcdc11cdb2cd), + C64e(0x73eeb4b49d29ee29), C64e(0xb6fb5b5b4d16fb16), + C64e(0x53f6a4a4a501f601), C64e(0xec4d7676a1d74dd7), + C64e(0x7561b7b714a361a3), C64e(0xface7d7d3449ce49), + C64e(0xa47b5252df8d7b8d), C64e(0xa13edddd9f423e42), + C64e(0xbc715e5ecd937193), C64e(0x26971313b1a297a2), + C64e(0x57f5a6a6a204f504), C64e(0x6968b9b901b868b8), + C64e(0x0000000000000000), C64e(0x992cc1c1b5742c74), + C64e(0x80604040e0a060a0), C64e(0xdd1fe3e3c2211f21), + C64e(0xf2c879793a43c843), C64e(0x77edb6b69a2ced2c), + C64e(0xb3bed4d40dd9bed9), C64e(0x01468d8d47ca46ca), + C64e(0xced967671770d970), C64e(0xe44b7272afdd4bdd), + C64e(0x33de9494ed79de79), C64e(0x2bd49898ff67d467), + C64e(0x7be8b0b09323e823), C64e(0x114a85855bde4ade), + C64e(0x6d6bbbbb06bd6bbd), C64e(0x912ac5c5bb7e2a7e), + C64e(0x9ee54f4f7b34e534), C64e(0xc116ededd73a163a), + C64e(0x17c58686d254c554), C64e(0x2fd79a9af862d762), + C64e(0xcc55666699ff55ff), C64e(0x22941111b6a794a7), + C64e(0x0fcf8a8ac04acf4a), C64e(0xc910e9e9d9301030), + C64e(0x080604040e0a060a), C64e(0xe781fefe66988198), + C64e(0x5bf0a0a0ab0bf00b), C64e(0xf0447878b4cc44cc), + C64e(0x4aba2525f0d5bad5), C64e(0x96e34b4b753ee33e), + C64e(0x5ff3a2a2ac0ef30e), C64e(0xbafe5d5d4419fe19), + C64e(0x1bc08080db5bc05b), C64e(0x0a8a050580858a85), + C64e(0x7ead3f3fd3ecadec), C64e(0x42bc2121fedfbcdf), + C64e(0xe0487070a8d848d8), C64e(0xf904f1f1fd0c040c), + C64e(0xc6df6363197adf7a), C64e(0xeec177772f58c158), + C64e(0x4575afaf309f759f), C64e(0x84634242e7a563a5), + C64e(0x4030202070503050), C64e(0xd11ae5e5cb2e1a2e), + C64e(0xe10efdfdef120e12), C64e(0x656dbfbf08b76db7), + C64e(0x194c818155d44cd4), C64e(0x30141818243c143c), + C64e(0x4c352626795f355f), C64e(0x9d2fc3c3b2712f71), + C64e(0x67e1bebe8638e138), C64e(0x6aa23535c8fda2fd), + C64e(0x0bcc8888c74fcc4f), C64e(0x5c392e2e654b394b), + C64e(0x3d5793936af957f9), C64e(0xaaf25555580df20d), + C64e(0xe382fcfc619d829d), C64e(0xf4477a7ab3c947c9), + C64e(0x8bacc8c827efacef), C64e(0x6fe7baba8832e732), + C64e(0x642b32324f7d2b7d), C64e(0xd795e6e642a495a4), + C64e(0x9ba0c0c03bfba0fb), C64e(0x32981919aab398b3), + C64e(0x27d19e9ef668d168), C64e(0x5d7fa3a322817f81), + C64e(0x88664444eeaa66aa), C64e(0xa87e5454d6827e82), + C64e(0x76ab3b3bdde6abe6), C64e(0x16830b0b959e839e), + C64e(0x03ca8c8cc945ca45), C64e(0x9529c7c7bc7b297b), + C64e(0xd6d36b6b056ed36e), C64e(0x503c28286c443c44), + C64e(0x5579a7a72c8b798b), C64e(0x63e2bcbc813de23d), + C64e(0x2c1d161631271d27), C64e(0x4176adad379a769a), + C64e(0xad3bdbdb964d3b4d), C64e(0xc85664649efa56fa), + C64e(0xe84e7474a6d24ed2), C64e(0x281e141436221e22), + C64e(0x3fdb9292e476db76), C64e(0x180a0c0c121e0a1e), + C64e(0x906c4848fcb46cb4), C64e(0x6be4b8b88f37e437), + C64e(0x255d9f9f78e75de7), C64e(0x616ebdbd0fb26eb2), + C64e(0x86ef4343692aef2a), C64e(0x93a6c4c435f1a6f1), + C64e(0x72a83939dae3a8e3), C64e(0x62a43131c6f7a4f7), + C64e(0xbd37d3d38a593759), C64e(0xff8bf2f274868b86), + C64e(0xb132d5d583563256), C64e(0x0d438b8b4ec543c5), + C64e(0xdc596e6e85eb59eb), C64e(0xafb7dada18c2b7c2), + C64e(0x028c01018e8f8c8f), C64e(0x7964b1b11dac64ac), + C64e(0x23d29c9cf16dd26d), C64e(0x92e04949723be03b), + C64e(0xabb4d8d81fc7b4c7), C64e(0x43faacacb915fa15), + C64e(0xfd07f3f3fa090709), C64e(0x8525cfcfa06f256f), + C64e(0x8fafcaca20eaafea), C64e(0xf38ef4f47d898e89), + C64e(0x8ee947476720e920), C64e(0x2018101038281828), + C64e(0xded56f6f0b64d564), C64e(0xfb88f0f073838883), + C64e(0x946f4a4afbb16fb1), C64e(0xb8725c5cca967296), + C64e(0x70243838546c246c), C64e(0xaef157575f08f108), + C64e(0xe6c773732152c752), C64e(0x3551979764f351f3), + C64e(0x8d23cbcbae652365), C64e(0x597ca1a125847c84), + C64e(0xcb9ce8e857bf9cbf), C64e(0x7c213e3e5d632163), + C64e(0x37dd9696ea7cdd7c), C64e(0xc2dc61611e7fdc7f), + C64e(0x1a860d0d9c918691), C64e(0x1e850f0f9b948594), + C64e(0xdb90e0e04bab90ab), C64e(0xf8427c7cbac642c6), + C64e(0xe2c471712657c457), C64e(0x83aacccc29e5aae5), + C64e(0x3bd89090e373d873), C64e(0x0c050606090f050f), + C64e(0xf501f7f7f4030103), C64e(0x38121c1c2a361236), + C64e(0x9fa3c2c23cfea3fe), C64e(0xd45f6a6a8be15fe1), + C64e(0x47f9aeaebe10f910), C64e(0xd2d06969026bd06b), + C64e(0x2e911717bfa891a8), C64e(0x2958999971e858e8), + C64e(0x74273a3a53692769), C64e(0x4eb92727f7d0b9d0), + C64e(0xa938d9d991483848), C64e(0xcd13ebebde351335), + C64e(0x56b32b2be5ceb3ce), C64e(0x4433222277553355), + C64e(0xbfbbd2d204d6bbd6), C64e(0x4970a9a939907090), + C64e(0x0e89070787808980), C64e(0x66a73333c1f2a7f2), + C64e(0x5ab62d2decc1b6c1), C64e(0x78223c3c5a662266), + C64e(0x2a921515b8ad92ad), C64e(0x8920c9c9a9602060), + C64e(0x154987875cdb49db), C64e(0x4fffaaaab01aff1a), + C64e(0xa0785050d8887888), C64e(0x517aa5a52b8e7a8e), + C64e(0x068f0303898a8f8a), C64e(0xb2f859594a13f813), + C64e(0x12800909929b809b), C64e(0x34171a1a23391739), + C64e(0xcada65651075da75), C64e(0xb531d7d784533153), + C64e(0x13c68484d551c651), C64e(0xbbb8d0d003d3b8d3), + C64e(0x1fc38282dc5ec35e), C64e(0x52b02929e2cbb0cb), + C64e(0xb4775a5ac3997799), C64e(0x3c111e1e2d331133), + C64e(0xf6cb7b7b3d46cb46), C64e(0x4bfca8a8b71ffc1f), + C64e(0xdad66d6d0c61d661), C64e(0x583a2c2c624e3a4e) +}; + +#endif + +static const sph_u64 T4[] = { + C64e(0xf497a5c6c632f4a5), C64e(0x97eb84f8f86f9784), + C64e(0xb0c799eeee5eb099), C64e(0x8cf78df6f67a8c8d), + C64e(0x17e50dffffe8170d), C64e(0xdcb7bdd6d60adcbd), + C64e(0xc8a7b1dede16c8b1), C64e(0xfc395491916dfc54), + C64e(0xf0c050606090f050), C64e(0x0504030202070503), + C64e(0xe087a9cece2ee0a9), C64e(0x87ac7d5656d1877d), + C64e(0x2bd519e7e7cc2b19), C64e(0xa67162b5b513a662), + C64e(0x319ae64d4d7c31e6), C64e(0xb5c39aecec59b59a), + C64e(0xcf05458f8f40cf45), C64e(0xbc3e9d1f1fa3bc9d), + C64e(0xc00940898949c040), C64e(0x92ef87fafa689287), + C64e(0x3fc515efefd03f15), C64e(0x267febb2b29426eb), + C64e(0x4007c98e8ece40c9), C64e(0x1ded0bfbfbe61d0b), + C64e(0x2f82ec41416e2fec), C64e(0xa97d67b3b31aa967), + C64e(0x1cbefd5f5f431cfd), C64e(0x258aea45456025ea), + C64e(0xda46bf2323f9dabf), C64e(0x02a6f753535102f7), + C64e(0xa1d396e4e445a196), C64e(0xed2d5b9b9b76ed5b), + C64e(0x5deac27575285dc2), C64e(0x24d91ce1e1c5241c), + C64e(0xe97aae3d3dd4e9ae), C64e(0xbe986a4c4cf2be6a), + C64e(0xeed85a6c6c82ee5a), C64e(0xc3fc417e7ebdc341), + C64e(0x06f102f5f5f30602), C64e(0xd11d4f838352d14f), + C64e(0xe4d05c68688ce45c), C64e(0x07a2f451515607f4), + C64e(0x5cb934d1d18d5c34), C64e(0x18e908f9f9e11808), + C64e(0xaedf93e2e24cae93), C64e(0x954d73abab3e9573), + C64e(0xf5c453626297f553), C64e(0x41543f2a2a6b413f), + C64e(0x14100c08081c140c), C64e(0xf63152959563f652), + C64e(0xaf8c654646e9af65), C64e(0xe2215e9d9d7fe25e), + C64e(0x7860283030487828), C64e(0xf86ea13737cff8a1), + C64e(0x11140f0a0a1b110f), C64e(0xc45eb52f2febc4b5), + C64e(0x1b1c090e0e151b09), C64e(0x5a483624247e5a36), + C64e(0xb6369b1b1badb69b), C64e(0x47a53ddfdf98473d), + C64e(0x6a8126cdcda76a26), C64e(0xbb9c694e4ef5bb69), + C64e(0x4cfecd7f7f334ccd), C64e(0xbacf9feaea50ba9f), + C64e(0x2d241b12123f2d1b), C64e(0xb93a9e1d1da4b99e), + C64e(0x9cb0745858c49c74), C64e(0x72682e343446722e), + C64e(0x776c2d363641772d), C64e(0xcda3b2dcdc11cdb2), + C64e(0x2973eeb4b49d29ee), C64e(0x16b6fb5b5b4d16fb), + C64e(0x0153f6a4a4a501f6), C64e(0xd7ec4d7676a1d74d), + C64e(0xa37561b7b714a361), C64e(0x49face7d7d3449ce), + C64e(0x8da47b5252df8d7b), C64e(0x42a13edddd9f423e), + C64e(0x93bc715e5ecd9371), C64e(0xa226971313b1a297), + C64e(0x0457f5a6a6a204f5), C64e(0xb86968b9b901b868), + C64e(0x0000000000000000), C64e(0x74992cc1c1b5742c), + C64e(0xa080604040e0a060), C64e(0x21dd1fe3e3c2211f), + C64e(0x43f2c879793a43c8), C64e(0x2c77edb6b69a2ced), + C64e(0xd9b3bed4d40dd9be), C64e(0xca01468d8d47ca46), + C64e(0x70ced967671770d9), C64e(0xdde44b7272afdd4b), + C64e(0x7933de9494ed79de), C64e(0x672bd49898ff67d4), + C64e(0x237be8b0b09323e8), C64e(0xde114a85855bde4a), + C64e(0xbd6d6bbbbb06bd6b), C64e(0x7e912ac5c5bb7e2a), + C64e(0x349ee54f4f7b34e5), C64e(0x3ac116ededd73a16), + C64e(0x5417c58686d254c5), C64e(0x622fd79a9af862d7), + C64e(0xffcc55666699ff55), C64e(0xa722941111b6a794), + C64e(0x4a0fcf8a8ac04acf), C64e(0x30c910e9e9d93010), + C64e(0x0a080604040e0a06), C64e(0x98e781fefe669881), + C64e(0x0b5bf0a0a0ab0bf0), C64e(0xccf0447878b4cc44), + C64e(0xd54aba2525f0d5ba), C64e(0x3e96e34b4b753ee3), + C64e(0x0e5ff3a2a2ac0ef3), C64e(0x19bafe5d5d4419fe), + C64e(0x5b1bc08080db5bc0), C64e(0x850a8a050580858a), + C64e(0xec7ead3f3fd3ecad), C64e(0xdf42bc2121fedfbc), + C64e(0xd8e0487070a8d848), C64e(0x0cf904f1f1fd0c04), + C64e(0x7ac6df6363197adf), C64e(0x58eec177772f58c1), + C64e(0x9f4575afaf309f75), C64e(0xa584634242e7a563), + C64e(0x5040302020705030), C64e(0x2ed11ae5e5cb2e1a), + C64e(0x12e10efdfdef120e), C64e(0xb7656dbfbf08b76d), + C64e(0xd4194c818155d44c), C64e(0x3c30141818243c14), + C64e(0x5f4c352626795f35), C64e(0x719d2fc3c3b2712f), + C64e(0x3867e1bebe8638e1), C64e(0xfd6aa23535c8fda2), + C64e(0x4f0bcc8888c74fcc), C64e(0x4b5c392e2e654b39), + C64e(0xf93d5793936af957), C64e(0x0daaf25555580df2), + C64e(0x9de382fcfc619d82), C64e(0xc9f4477a7ab3c947), + C64e(0xef8bacc8c827efac), C64e(0x326fe7baba8832e7), + C64e(0x7d642b32324f7d2b), C64e(0xa4d795e6e642a495), + C64e(0xfb9ba0c0c03bfba0), C64e(0xb332981919aab398), + C64e(0x6827d19e9ef668d1), C64e(0x815d7fa3a322817f), + C64e(0xaa88664444eeaa66), C64e(0x82a87e5454d6827e), + C64e(0xe676ab3b3bdde6ab), C64e(0x9e16830b0b959e83), + C64e(0x4503ca8c8cc945ca), C64e(0x7b9529c7c7bc7b29), + C64e(0x6ed6d36b6b056ed3), C64e(0x44503c28286c443c), + C64e(0x8b5579a7a72c8b79), C64e(0x3d63e2bcbc813de2), + C64e(0x272c1d161631271d), C64e(0x9a4176adad379a76), + C64e(0x4dad3bdbdb964d3b), C64e(0xfac85664649efa56), + C64e(0xd2e84e7474a6d24e), C64e(0x22281e141436221e), + C64e(0x763fdb9292e476db), C64e(0x1e180a0c0c121e0a), + C64e(0xb4906c4848fcb46c), C64e(0x376be4b8b88f37e4), + C64e(0xe7255d9f9f78e75d), C64e(0xb2616ebdbd0fb26e), + C64e(0x2a86ef4343692aef), C64e(0xf193a6c4c435f1a6), + C64e(0xe372a83939dae3a8), C64e(0xf762a43131c6f7a4), + C64e(0x59bd37d3d38a5937), C64e(0x86ff8bf2f274868b), + C64e(0x56b132d5d5835632), C64e(0xc50d438b8b4ec543), + C64e(0xebdc596e6e85eb59), C64e(0xc2afb7dada18c2b7), + C64e(0x8f028c01018e8f8c), C64e(0xac7964b1b11dac64), + C64e(0x6d23d29c9cf16dd2), C64e(0x3b92e04949723be0), + C64e(0xc7abb4d8d81fc7b4), C64e(0x1543faacacb915fa), + C64e(0x09fd07f3f3fa0907), C64e(0x6f8525cfcfa06f25), + C64e(0xea8fafcaca20eaaf), C64e(0x89f38ef4f47d898e), + C64e(0x208ee947476720e9), C64e(0x2820181010382818), + C64e(0x64ded56f6f0b64d5), C64e(0x83fb88f0f0738388), + C64e(0xb1946f4a4afbb16f), C64e(0x96b8725c5cca9672), + C64e(0x6c70243838546c24), C64e(0x08aef157575f08f1), + C64e(0x52e6c773732152c7), C64e(0xf33551979764f351), + C64e(0x658d23cbcbae6523), C64e(0x84597ca1a125847c), + C64e(0xbfcb9ce8e857bf9c), C64e(0x637c213e3e5d6321), + C64e(0x7c37dd9696ea7cdd), C64e(0x7fc2dc61611e7fdc), + C64e(0x911a860d0d9c9186), C64e(0x941e850f0f9b9485), + C64e(0xabdb90e0e04bab90), C64e(0xc6f8427c7cbac642), + C64e(0x57e2c471712657c4), C64e(0xe583aacccc29e5aa), + C64e(0x733bd89090e373d8), C64e(0x0f0c050606090f05), + C64e(0x03f501f7f7f40301), C64e(0x3638121c1c2a3612), + C64e(0xfe9fa3c2c23cfea3), C64e(0xe1d45f6a6a8be15f), + C64e(0x1047f9aeaebe10f9), C64e(0x6bd2d06969026bd0), + C64e(0xa82e911717bfa891), C64e(0xe82958999971e858), + C64e(0x6974273a3a536927), C64e(0xd04eb92727f7d0b9), + C64e(0x48a938d9d9914838), C64e(0x35cd13ebebde3513), + C64e(0xce56b32b2be5ceb3), C64e(0x5544332222775533), + C64e(0xd6bfbbd2d204d6bb), C64e(0x904970a9a9399070), + C64e(0x800e890707878089), C64e(0xf266a73333c1f2a7), + C64e(0xc15ab62d2decc1b6), C64e(0x6678223c3c5a6622), + C64e(0xad2a921515b8ad92), C64e(0x608920c9c9a96020), + C64e(0xdb154987875cdb49), C64e(0x1a4fffaaaab01aff), + C64e(0x88a0785050d88878), C64e(0x8e517aa5a52b8e7a), + C64e(0x8a068f0303898a8f), C64e(0x13b2f859594a13f8), + C64e(0x9b12800909929b80), C64e(0x3934171a1a233917), + C64e(0x75cada65651075da), C64e(0x53b531d7d7845331), + C64e(0x5113c68484d551c6), C64e(0xd3bbb8d0d003d3b8), + C64e(0x5e1fc38282dc5ec3), C64e(0xcb52b02929e2cbb0), + C64e(0x99b4775a5ac39977), C64e(0x333c111e1e2d3311), + C64e(0x46f6cb7b7b3d46cb), C64e(0x1f4bfca8a8b71ffc), + C64e(0x61dad66d6d0c61d6), C64e(0x4e583a2c2c624e3a) +}; + +#if !SPH_SMALL_FOOTPRINT_GROESTL + +static const sph_u64 T5[] = { + C64e(0xa5f497a5c6c632f4), C64e(0x8497eb84f8f86f97), + C64e(0x99b0c799eeee5eb0), C64e(0x8d8cf78df6f67a8c), + C64e(0x0d17e50dffffe817), C64e(0xbddcb7bdd6d60adc), + C64e(0xb1c8a7b1dede16c8), C64e(0x54fc395491916dfc), + C64e(0x50f0c050606090f0), C64e(0x0305040302020705), + C64e(0xa9e087a9cece2ee0), C64e(0x7d87ac7d5656d187), + C64e(0x192bd519e7e7cc2b), C64e(0x62a67162b5b513a6), + C64e(0xe6319ae64d4d7c31), C64e(0x9ab5c39aecec59b5), + C64e(0x45cf05458f8f40cf), C64e(0x9dbc3e9d1f1fa3bc), + C64e(0x40c00940898949c0), C64e(0x8792ef87fafa6892), + C64e(0x153fc515efefd03f), C64e(0xeb267febb2b29426), + C64e(0xc94007c98e8ece40), C64e(0x0b1ded0bfbfbe61d), + C64e(0xec2f82ec41416e2f), C64e(0x67a97d67b3b31aa9), + C64e(0xfd1cbefd5f5f431c), C64e(0xea258aea45456025), + C64e(0xbfda46bf2323f9da), C64e(0xf702a6f753535102), + C64e(0x96a1d396e4e445a1), C64e(0x5bed2d5b9b9b76ed), + C64e(0xc25deac27575285d), C64e(0x1c24d91ce1e1c524), + C64e(0xaee97aae3d3dd4e9), C64e(0x6abe986a4c4cf2be), + C64e(0x5aeed85a6c6c82ee), C64e(0x41c3fc417e7ebdc3), + C64e(0x0206f102f5f5f306), C64e(0x4fd11d4f838352d1), + C64e(0x5ce4d05c68688ce4), C64e(0xf407a2f451515607), + C64e(0x345cb934d1d18d5c), C64e(0x0818e908f9f9e118), + C64e(0x93aedf93e2e24cae), C64e(0x73954d73abab3e95), + C64e(0x53f5c453626297f5), C64e(0x3f41543f2a2a6b41), + C64e(0x0c14100c08081c14), C64e(0x52f63152959563f6), + C64e(0x65af8c654646e9af), C64e(0x5ee2215e9d9d7fe2), + C64e(0x2878602830304878), C64e(0xa1f86ea13737cff8), + C64e(0x0f11140f0a0a1b11), C64e(0xb5c45eb52f2febc4), + C64e(0x091b1c090e0e151b), C64e(0x365a483624247e5a), + C64e(0x9bb6369b1b1badb6), C64e(0x3d47a53ddfdf9847), + C64e(0x266a8126cdcda76a), C64e(0x69bb9c694e4ef5bb), + C64e(0xcd4cfecd7f7f334c), C64e(0x9fbacf9feaea50ba), + C64e(0x1b2d241b12123f2d), C64e(0x9eb93a9e1d1da4b9), + C64e(0x749cb0745858c49c), C64e(0x2e72682e34344672), + C64e(0x2d776c2d36364177), C64e(0xb2cda3b2dcdc11cd), + C64e(0xee2973eeb4b49d29), C64e(0xfb16b6fb5b5b4d16), + C64e(0xf60153f6a4a4a501), C64e(0x4dd7ec4d7676a1d7), + C64e(0x61a37561b7b714a3), C64e(0xce49face7d7d3449), + C64e(0x7b8da47b5252df8d), C64e(0x3e42a13edddd9f42), + C64e(0x7193bc715e5ecd93), C64e(0x97a226971313b1a2), + C64e(0xf50457f5a6a6a204), C64e(0x68b86968b9b901b8), + C64e(0x0000000000000000), C64e(0x2c74992cc1c1b574), + C64e(0x60a080604040e0a0), C64e(0x1f21dd1fe3e3c221), + C64e(0xc843f2c879793a43), C64e(0xed2c77edb6b69a2c), + C64e(0xbed9b3bed4d40dd9), C64e(0x46ca01468d8d47ca), + C64e(0xd970ced967671770), C64e(0x4bdde44b7272afdd), + C64e(0xde7933de9494ed79), C64e(0xd4672bd49898ff67), + C64e(0xe8237be8b0b09323), C64e(0x4ade114a85855bde), + C64e(0x6bbd6d6bbbbb06bd), C64e(0x2a7e912ac5c5bb7e), + C64e(0xe5349ee54f4f7b34), C64e(0x163ac116ededd73a), + C64e(0xc55417c58686d254), C64e(0xd7622fd79a9af862), + C64e(0x55ffcc55666699ff), C64e(0x94a722941111b6a7), + C64e(0xcf4a0fcf8a8ac04a), C64e(0x1030c910e9e9d930), + C64e(0x060a080604040e0a), C64e(0x8198e781fefe6698), + C64e(0xf00b5bf0a0a0ab0b), C64e(0x44ccf0447878b4cc), + C64e(0xbad54aba2525f0d5), C64e(0xe33e96e34b4b753e), + C64e(0xf30e5ff3a2a2ac0e), C64e(0xfe19bafe5d5d4419), + C64e(0xc05b1bc08080db5b), C64e(0x8a850a8a05058085), + C64e(0xadec7ead3f3fd3ec), C64e(0xbcdf42bc2121fedf), + C64e(0x48d8e0487070a8d8), C64e(0x040cf904f1f1fd0c), + C64e(0xdf7ac6df6363197a), C64e(0xc158eec177772f58), + C64e(0x759f4575afaf309f), C64e(0x63a584634242e7a5), + C64e(0x3050403020207050), C64e(0x1a2ed11ae5e5cb2e), + C64e(0x0e12e10efdfdef12), C64e(0x6db7656dbfbf08b7), + C64e(0x4cd4194c818155d4), C64e(0x143c30141818243c), + C64e(0x355f4c352626795f), C64e(0x2f719d2fc3c3b271), + C64e(0xe13867e1bebe8638), C64e(0xa2fd6aa23535c8fd), + C64e(0xcc4f0bcc8888c74f), C64e(0x394b5c392e2e654b), + C64e(0x57f93d5793936af9), C64e(0xf20daaf25555580d), + C64e(0x829de382fcfc619d), C64e(0x47c9f4477a7ab3c9), + C64e(0xacef8bacc8c827ef), C64e(0xe7326fe7baba8832), + C64e(0x2b7d642b32324f7d), C64e(0x95a4d795e6e642a4), + C64e(0xa0fb9ba0c0c03bfb), C64e(0x98b332981919aab3), + C64e(0xd16827d19e9ef668), C64e(0x7f815d7fa3a32281), + C64e(0x66aa88664444eeaa), C64e(0x7e82a87e5454d682), + C64e(0xabe676ab3b3bdde6), C64e(0x839e16830b0b959e), + C64e(0xca4503ca8c8cc945), C64e(0x297b9529c7c7bc7b), + C64e(0xd36ed6d36b6b056e), C64e(0x3c44503c28286c44), + C64e(0x798b5579a7a72c8b), C64e(0xe23d63e2bcbc813d), + C64e(0x1d272c1d16163127), C64e(0x769a4176adad379a), + C64e(0x3b4dad3bdbdb964d), C64e(0x56fac85664649efa), + C64e(0x4ed2e84e7474a6d2), C64e(0x1e22281e14143622), + C64e(0xdb763fdb9292e476), C64e(0x0a1e180a0c0c121e), + C64e(0x6cb4906c4848fcb4), C64e(0xe4376be4b8b88f37), + C64e(0x5de7255d9f9f78e7), C64e(0x6eb2616ebdbd0fb2), + C64e(0xef2a86ef4343692a), C64e(0xa6f193a6c4c435f1), + C64e(0xa8e372a83939dae3), C64e(0xa4f762a43131c6f7), + C64e(0x3759bd37d3d38a59), C64e(0x8b86ff8bf2f27486), + C64e(0x3256b132d5d58356), C64e(0x43c50d438b8b4ec5), + C64e(0x59ebdc596e6e85eb), C64e(0xb7c2afb7dada18c2), + C64e(0x8c8f028c01018e8f), C64e(0x64ac7964b1b11dac), + C64e(0xd26d23d29c9cf16d), C64e(0xe03b92e04949723b), + C64e(0xb4c7abb4d8d81fc7), C64e(0xfa1543faacacb915), + C64e(0x0709fd07f3f3fa09), C64e(0x256f8525cfcfa06f), + C64e(0xafea8fafcaca20ea), C64e(0x8e89f38ef4f47d89), + C64e(0xe9208ee947476720), C64e(0x1828201810103828), + C64e(0xd564ded56f6f0b64), C64e(0x8883fb88f0f07383), + C64e(0x6fb1946f4a4afbb1), C64e(0x7296b8725c5cca96), + C64e(0x246c70243838546c), C64e(0xf108aef157575f08), + C64e(0xc752e6c773732152), C64e(0x51f33551979764f3), + C64e(0x23658d23cbcbae65), C64e(0x7c84597ca1a12584), + C64e(0x9cbfcb9ce8e857bf), C64e(0x21637c213e3e5d63), + C64e(0xdd7c37dd9696ea7c), C64e(0xdc7fc2dc61611e7f), + C64e(0x86911a860d0d9c91), C64e(0x85941e850f0f9b94), + C64e(0x90abdb90e0e04bab), C64e(0x42c6f8427c7cbac6), + C64e(0xc457e2c471712657), C64e(0xaae583aacccc29e5), + C64e(0xd8733bd89090e373), C64e(0x050f0c050606090f), + C64e(0x0103f501f7f7f403), C64e(0x123638121c1c2a36), + C64e(0xa3fe9fa3c2c23cfe), C64e(0x5fe1d45f6a6a8be1), + C64e(0xf91047f9aeaebe10), C64e(0xd06bd2d06969026b), + C64e(0x91a82e911717bfa8), C64e(0x58e82958999971e8), + C64e(0x276974273a3a5369), C64e(0xb9d04eb92727f7d0), + C64e(0x3848a938d9d99148), C64e(0x1335cd13ebebde35), + C64e(0xb3ce56b32b2be5ce), C64e(0x3355443322227755), + C64e(0xbbd6bfbbd2d204d6), C64e(0x70904970a9a93990), + C64e(0x89800e8907078780), C64e(0xa7f266a73333c1f2), + C64e(0xb6c15ab62d2decc1), C64e(0x226678223c3c5a66), + C64e(0x92ad2a921515b8ad), C64e(0x20608920c9c9a960), + C64e(0x49db154987875cdb), C64e(0xff1a4fffaaaab01a), + C64e(0x7888a0785050d888), C64e(0x7a8e517aa5a52b8e), + C64e(0x8f8a068f0303898a), C64e(0xf813b2f859594a13), + C64e(0x809b12800909929b), C64e(0x173934171a1a2339), + C64e(0xda75cada65651075), C64e(0x3153b531d7d78453), + C64e(0xc65113c68484d551), C64e(0xb8d3bbb8d0d003d3), + C64e(0xc35e1fc38282dc5e), C64e(0xb0cb52b02929e2cb), + C64e(0x7799b4775a5ac399), C64e(0x11333c111e1e2d33), + C64e(0xcb46f6cb7b7b3d46), C64e(0xfc1f4bfca8a8b71f), + C64e(0xd661dad66d6d0c61), C64e(0x3a4e583a2c2c624e) +}; + +static const sph_u64 T6[] = { + C64e(0xf4a5f497a5c6c632), C64e(0x978497eb84f8f86f), + C64e(0xb099b0c799eeee5e), C64e(0x8c8d8cf78df6f67a), + C64e(0x170d17e50dffffe8), C64e(0xdcbddcb7bdd6d60a), + C64e(0xc8b1c8a7b1dede16), C64e(0xfc54fc395491916d), + C64e(0xf050f0c050606090), C64e(0x0503050403020207), + C64e(0xe0a9e087a9cece2e), C64e(0x877d87ac7d5656d1), + C64e(0x2b192bd519e7e7cc), C64e(0xa662a67162b5b513), + C64e(0x31e6319ae64d4d7c), C64e(0xb59ab5c39aecec59), + C64e(0xcf45cf05458f8f40), C64e(0xbc9dbc3e9d1f1fa3), + C64e(0xc040c00940898949), C64e(0x928792ef87fafa68), + C64e(0x3f153fc515efefd0), C64e(0x26eb267febb2b294), + C64e(0x40c94007c98e8ece), C64e(0x1d0b1ded0bfbfbe6), + C64e(0x2fec2f82ec41416e), C64e(0xa967a97d67b3b31a), + C64e(0x1cfd1cbefd5f5f43), C64e(0x25ea258aea454560), + C64e(0xdabfda46bf2323f9), C64e(0x02f702a6f7535351), + C64e(0xa196a1d396e4e445), C64e(0xed5bed2d5b9b9b76), + C64e(0x5dc25deac2757528), C64e(0x241c24d91ce1e1c5), + C64e(0xe9aee97aae3d3dd4), C64e(0xbe6abe986a4c4cf2), + C64e(0xee5aeed85a6c6c82), C64e(0xc341c3fc417e7ebd), + C64e(0x060206f102f5f5f3), C64e(0xd14fd11d4f838352), + C64e(0xe45ce4d05c68688c), C64e(0x07f407a2f4515156), + C64e(0x5c345cb934d1d18d), C64e(0x180818e908f9f9e1), + C64e(0xae93aedf93e2e24c), C64e(0x9573954d73abab3e), + C64e(0xf553f5c453626297), C64e(0x413f41543f2a2a6b), + C64e(0x140c14100c08081c), C64e(0xf652f63152959563), + C64e(0xaf65af8c654646e9), C64e(0xe25ee2215e9d9d7f), + C64e(0x7828786028303048), C64e(0xf8a1f86ea13737cf), + C64e(0x110f11140f0a0a1b), C64e(0xc4b5c45eb52f2feb), + C64e(0x1b091b1c090e0e15), C64e(0x5a365a483624247e), + C64e(0xb69bb6369b1b1bad), C64e(0x473d47a53ddfdf98), + C64e(0x6a266a8126cdcda7), C64e(0xbb69bb9c694e4ef5), + C64e(0x4ccd4cfecd7f7f33), C64e(0xba9fbacf9feaea50), + C64e(0x2d1b2d241b12123f), C64e(0xb99eb93a9e1d1da4), + C64e(0x9c749cb0745858c4), C64e(0x722e72682e343446), + C64e(0x772d776c2d363641), C64e(0xcdb2cda3b2dcdc11), + C64e(0x29ee2973eeb4b49d), C64e(0x16fb16b6fb5b5b4d), + C64e(0x01f60153f6a4a4a5), C64e(0xd74dd7ec4d7676a1), + C64e(0xa361a37561b7b714), C64e(0x49ce49face7d7d34), + C64e(0x8d7b8da47b5252df), C64e(0x423e42a13edddd9f), + C64e(0x937193bc715e5ecd), C64e(0xa297a226971313b1), + C64e(0x04f50457f5a6a6a2), C64e(0xb868b86968b9b901), + C64e(0x0000000000000000), C64e(0x742c74992cc1c1b5), + C64e(0xa060a080604040e0), C64e(0x211f21dd1fe3e3c2), + C64e(0x43c843f2c879793a), C64e(0x2ced2c77edb6b69a), + C64e(0xd9bed9b3bed4d40d), C64e(0xca46ca01468d8d47), + C64e(0x70d970ced9676717), C64e(0xdd4bdde44b7272af), + C64e(0x79de7933de9494ed), C64e(0x67d4672bd49898ff), + C64e(0x23e8237be8b0b093), C64e(0xde4ade114a85855b), + C64e(0xbd6bbd6d6bbbbb06), C64e(0x7e2a7e912ac5c5bb), + C64e(0x34e5349ee54f4f7b), C64e(0x3a163ac116ededd7), + C64e(0x54c55417c58686d2), C64e(0x62d7622fd79a9af8), + C64e(0xff55ffcc55666699), C64e(0xa794a722941111b6), + C64e(0x4acf4a0fcf8a8ac0), C64e(0x301030c910e9e9d9), + C64e(0x0a060a080604040e), C64e(0x988198e781fefe66), + C64e(0x0bf00b5bf0a0a0ab), C64e(0xcc44ccf0447878b4), + C64e(0xd5bad54aba2525f0), C64e(0x3ee33e96e34b4b75), + C64e(0x0ef30e5ff3a2a2ac), C64e(0x19fe19bafe5d5d44), + C64e(0x5bc05b1bc08080db), C64e(0x858a850a8a050580), + C64e(0xecadec7ead3f3fd3), C64e(0xdfbcdf42bc2121fe), + C64e(0xd848d8e0487070a8), C64e(0x0c040cf904f1f1fd), + C64e(0x7adf7ac6df636319), C64e(0x58c158eec177772f), + C64e(0x9f759f4575afaf30), C64e(0xa563a584634242e7), + C64e(0x5030504030202070), C64e(0x2e1a2ed11ae5e5cb), + C64e(0x120e12e10efdfdef), C64e(0xb76db7656dbfbf08), + C64e(0xd44cd4194c818155), C64e(0x3c143c3014181824), + C64e(0x5f355f4c35262679), C64e(0x712f719d2fc3c3b2), + C64e(0x38e13867e1bebe86), C64e(0xfda2fd6aa23535c8), + C64e(0x4fcc4f0bcc8888c7), C64e(0x4b394b5c392e2e65), + C64e(0xf957f93d5793936a), C64e(0x0df20daaf2555558), + C64e(0x9d829de382fcfc61), C64e(0xc947c9f4477a7ab3), + C64e(0xefacef8bacc8c827), C64e(0x32e7326fe7baba88), + C64e(0x7d2b7d642b32324f), C64e(0xa495a4d795e6e642), + C64e(0xfba0fb9ba0c0c03b), C64e(0xb398b332981919aa), + C64e(0x68d16827d19e9ef6), C64e(0x817f815d7fa3a322), + C64e(0xaa66aa88664444ee), C64e(0x827e82a87e5454d6), + C64e(0xe6abe676ab3b3bdd), C64e(0x9e839e16830b0b95), + C64e(0x45ca4503ca8c8cc9), C64e(0x7b297b9529c7c7bc), + C64e(0x6ed36ed6d36b6b05), C64e(0x443c44503c28286c), + C64e(0x8b798b5579a7a72c), C64e(0x3de23d63e2bcbc81), + C64e(0x271d272c1d161631), C64e(0x9a769a4176adad37), + C64e(0x4d3b4dad3bdbdb96), C64e(0xfa56fac85664649e), + C64e(0xd24ed2e84e7474a6), C64e(0x221e22281e141436), + C64e(0x76db763fdb9292e4), C64e(0x1e0a1e180a0c0c12), + C64e(0xb46cb4906c4848fc), C64e(0x37e4376be4b8b88f), + C64e(0xe75de7255d9f9f78), C64e(0xb26eb2616ebdbd0f), + C64e(0x2aef2a86ef434369), C64e(0xf1a6f193a6c4c435), + C64e(0xe3a8e372a83939da), C64e(0xf7a4f762a43131c6), + C64e(0x593759bd37d3d38a), C64e(0x868b86ff8bf2f274), + C64e(0x563256b132d5d583), C64e(0xc543c50d438b8b4e), + C64e(0xeb59ebdc596e6e85), C64e(0xc2b7c2afb7dada18), + C64e(0x8f8c8f028c01018e), C64e(0xac64ac7964b1b11d), + C64e(0x6dd26d23d29c9cf1), C64e(0x3be03b92e0494972), + C64e(0xc7b4c7abb4d8d81f), C64e(0x15fa1543faacacb9), + C64e(0x090709fd07f3f3fa), C64e(0x6f256f8525cfcfa0), + C64e(0xeaafea8fafcaca20), C64e(0x898e89f38ef4f47d), + C64e(0x20e9208ee9474767), C64e(0x2818282018101038), + C64e(0x64d564ded56f6f0b), C64e(0x838883fb88f0f073), + C64e(0xb16fb1946f4a4afb), C64e(0x967296b8725c5cca), + C64e(0x6c246c7024383854), C64e(0x08f108aef157575f), + C64e(0x52c752e6c7737321), C64e(0xf351f33551979764), + C64e(0x6523658d23cbcbae), C64e(0x847c84597ca1a125), + C64e(0xbf9cbfcb9ce8e857), C64e(0x6321637c213e3e5d), + C64e(0x7cdd7c37dd9696ea), C64e(0x7fdc7fc2dc61611e), + C64e(0x9186911a860d0d9c), C64e(0x9485941e850f0f9b), + C64e(0xab90abdb90e0e04b), C64e(0xc642c6f8427c7cba), + C64e(0x57c457e2c4717126), C64e(0xe5aae583aacccc29), + C64e(0x73d8733bd89090e3), C64e(0x0f050f0c05060609), + C64e(0x030103f501f7f7f4), C64e(0x36123638121c1c2a), + C64e(0xfea3fe9fa3c2c23c), C64e(0xe15fe1d45f6a6a8b), + C64e(0x10f91047f9aeaebe), C64e(0x6bd06bd2d0696902), + C64e(0xa891a82e911717bf), C64e(0xe858e82958999971), + C64e(0x69276974273a3a53), C64e(0xd0b9d04eb92727f7), + C64e(0x483848a938d9d991), C64e(0x351335cd13ebebde), + C64e(0xceb3ce56b32b2be5), C64e(0x5533554433222277), + C64e(0xd6bbd6bfbbd2d204), C64e(0x9070904970a9a939), + C64e(0x8089800e89070787), C64e(0xf2a7f266a73333c1), + C64e(0xc1b6c15ab62d2dec), C64e(0x66226678223c3c5a), + C64e(0xad92ad2a921515b8), C64e(0x6020608920c9c9a9), + C64e(0xdb49db154987875c), C64e(0x1aff1a4fffaaaab0), + C64e(0x887888a0785050d8), C64e(0x8e7a8e517aa5a52b), + C64e(0x8a8f8a068f030389), C64e(0x13f813b2f859594a), + C64e(0x9b809b1280090992), C64e(0x39173934171a1a23), + C64e(0x75da75cada656510), C64e(0x533153b531d7d784), + C64e(0x51c65113c68484d5), C64e(0xd3b8d3bbb8d0d003), + C64e(0x5ec35e1fc38282dc), C64e(0xcbb0cb52b02929e2), + C64e(0x997799b4775a5ac3), C64e(0x3311333c111e1e2d), + C64e(0x46cb46f6cb7b7b3d), C64e(0x1ffc1f4bfca8a8b7), + C64e(0x61d661dad66d6d0c), C64e(0x4e3a4e583a2c2c62) +}; + +static const sph_u64 T7[] = { + C64e(0x32f4a5f497a5c6c6), C64e(0x6f978497eb84f8f8), + C64e(0x5eb099b0c799eeee), C64e(0x7a8c8d8cf78df6f6), + C64e(0xe8170d17e50dffff), C64e(0x0adcbddcb7bdd6d6), + C64e(0x16c8b1c8a7b1dede), C64e(0x6dfc54fc39549191), + C64e(0x90f050f0c0506060), C64e(0x0705030504030202), + C64e(0x2ee0a9e087a9cece), C64e(0xd1877d87ac7d5656), + C64e(0xcc2b192bd519e7e7), C64e(0x13a662a67162b5b5), + C64e(0x7c31e6319ae64d4d), C64e(0x59b59ab5c39aecec), + C64e(0x40cf45cf05458f8f), C64e(0xa3bc9dbc3e9d1f1f), + C64e(0x49c040c009408989), C64e(0x68928792ef87fafa), + C64e(0xd03f153fc515efef), C64e(0x9426eb267febb2b2), + C64e(0xce40c94007c98e8e), C64e(0xe61d0b1ded0bfbfb), + C64e(0x6e2fec2f82ec4141), C64e(0x1aa967a97d67b3b3), + C64e(0x431cfd1cbefd5f5f), C64e(0x6025ea258aea4545), + C64e(0xf9dabfda46bf2323), C64e(0x5102f702a6f75353), + C64e(0x45a196a1d396e4e4), C64e(0x76ed5bed2d5b9b9b), + C64e(0x285dc25deac27575), C64e(0xc5241c24d91ce1e1), + C64e(0xd4e9aee97aae3d3d), C64e(0xf2be6abe986a4c4c), + C64e(0x82ee5aeed85a6c6c), C64e(0xbdc341c3fc417e7e), + C64e(0xf3060206f102f5f5), C64e(0x52d14fd11d4f8383), + C64e(0x8ce45ce4d05c6868), C64e(0x5607f407a2f45151), + C64e(0x8d5c345cb934d1d1), C64e(0xe1180818e908f9f9), + C64e(0x4cae93aedf93e2e2), C64e(0x3e9573954d73abab), + C64e(0x97f553f5c4536262), C64e(0x6b413f41543f2a2a), + C64e(0x1c140c14100c0808), C64e(0x63f652f631529595), + C64e(0xe9af65af8c654646), C64e(0x7fe25ee2215e9d9d), + C64e(0x4878287860283030), C64e(0xcff8a1f86ea13737), + C64e(0x1b110f11140f0a0a), C64e(0xebc4b5c45eb52f2f), + C64e(0x151b091b1c090e0e), C64e(0x7e5a365a48362424), + C64e(0xadb69bb6369b1b1b), C64e(0x98473d47a53ddfdf), + C64e(0xa76a266a8126cdcd), C64e(0xf5bb69bb9c694e4e), + C64e(0x334ccd4cfecd7f7f), C64e(0x50ba9fbacf9feaea), + C64e(0x3f2d1b2d241b1212), C64e(0xa4b99eb93a9e1d1d), + C64e(0xc49c749cb0745858), C64e(0x46722e72682e3434), + C64e(0x41772d776c2d3636), C64e(0x11cdb2cda3b2dcdc), + C64e(0x9d29ee2973eeb4b4), C64e(0x4d16fb16b6fb5b5b), + C64e(0xa501f60153f6a4a4), C64e(0xa1d74dd7ec4d7676), + C64e(0x14a361a37561b7b7), C64e(0x3449ce49face7d7d), + C64e(0xdf8d7b8da47b5252), C64e(0x9f423e42a13edddd), + C64e(0xcd937193bc715e5e), C64e(0xb1a297a226971313), + C64e(0xa204f50457f5a6a6), C64e(0x01b868b86968b9b9), + C64e(0x0000000000000000), C64e(0xb5742c74992cc1c1), + C64e(0xe0a060a080604040), C64e(0xc2211f21dd1fe3e3), + C64e(0x3a43c843f2c87979), C64e(0x9a2ced2c77edb6b6), + C64e(0x0dd9bed9b3bed4d4), C64e(0x47ca46ca01468d8d), + C64e(0x1770d970ced96767), C64e(0xafdd4bdde44b7272), + C64e(0xed79de7933de9494), C64e(0xff67d4672bd49898), + C64e(0x9323e8237be8b0b0), C64e(0x5bde4ade114a8585), + C64e(0x06bd6bbd6d6bbbbb), C64e(0xbb7e2a7e912ac5c5), + C64e(0x7b34e5349ee54f4f), C64e(0xd73a163ac116eded), + C64e(0xd254c55417c58686), C64e(0xf862d7622fd79a9a), + C64e(0x99ff55ffcc556666), C64e(0xb6a794a722941111), + C64e(0xc04acf4a0fcf8a8a), C64e(0xd9301030c910e9e9), + C64e(0x0e0a060a08060404), C64e(0x66988198e781fefe), + C64e(0xab0bf00b5bf0a0a0), C64e(0xb4cc44ccf0447878), + C64e(0xf0d5bad54aba2525), C64e(0x753ee33e96e34b4b), + C64e(0xac0ef30e5ff3a2a2), C64e(0x4419fe19bafe5d5d), + C64e(0xdb5bc05b1bc08080), C64e(0x80858a850a8a0505), + C64e(0xd3ecadec7ead3f3f), C64e(0xfedfbcdf42bc2121), + C64e(0xa8d848d8e0487070), C64e(0xfd0c040cf904f1f1), + C64e(0x197adf7ac6df6363), C64e(0x2f58c158eec17777), + C64e(0x309f759f4575afaf), C64e(0xe7a563a584634242), + C64e(0x7050305040302020), C64e(0xcb2e1a2ed11ae5e5), + C64e(0xef120e12e10efdfd), C64e(0x08b76db7656dbfbf), + C64e(0x55d44cd4194c8181), C64e(0x243c143c30141818), + C64e(0x795f355f4c352626), C64e(0xb2712f719d2fc3c3), + C64e(0x8638e13867e1bebe), C64e(0xc8fda2fd6aa23535), + C64e(0xc74fcc4f0bcc8888), C64e(0x654b394b5c392e2e), + C64e(0x6af957f93d579393), C64e(0x580df20daaf25555), + C64e(0x619d829de382fcfc), C64e(0xb3c947c9f4477a7a), + C64e(0x27efacef8bacc8c8), C64e(0x8832e7326fe7baba), + C64e(0x4f7d2b7d642b3232), C64e(0x42a495a4d795e6e6), + C64e(0x3bfba0fb9ba0c0c0), C64e(0xaab398b332981919), + C64e(0xf668d16827d19e9e), C64e(0x22817f815d7fa3a3), + C64e(0xeeaa66aa88664444), C64e(0xd6827e82a87e5454), + C64e(0xdde6abe676ab3b3b), C64e(0x959e839e16830b0b), + C64e(0xc945ca4503ca8c8c), C64e(0xbc7b297b9529c7c7), + C64e(0x056ed36ed6d36b6b), C64e(0x6c443c44503c2828), + C64e(0x2c8b798b5579a7a7), C64e(0x813de23d63e2bcbc), + C64e(0x31271d272c1d1616), C64e(0x379a769a4176adad), + C64e(0x964d3b4dad3bdbdb), C64e(0x9efa56fac8566464), + C64e(0xa6d24ed2e84e7474), C64e(0x36221e22281e1414), + C64e(0xe476db763fdb9292), C64e(0x121e0a1e180a0c0c), + C64e(0xfcb46cb4906c4848), C64e(0x8f37e4376be4b8b8), + C64e(0x78e75de7255d9f9f), C64e(0x0fb26eb2616ebdbd), + C64e(0x692aef2a86ef4343), C64e(0x35f1a6f193a6c4c4), + C64e(0xdae3a8e372a83939), C64e(0xc6f7a4f762a43131), + C64e(0x8a593759bd37d3d3), C64e(0x74868b86ff8bf2f2), + C64e(0x83563256b132d5d5), C64e(0x4ec543c50d438b8b), + C64e(0x85eb59ebdc596e6e), C64e(0x18c2b7c2afb7dada), + C64e(0x8e8f8c8f028c0101), C64e(0x1dac64ac7964b1b1), + C64e(0xf16dd26d23d29c9c), C64e(0x723be03b92e04949), + C64e(0x1fc7b4c7abb4d8d8), C64e(0xb915fa1543faacac), + C64e(0xfa090709fd07f3f3), C64e(0xa06f256f8525cfcf), + C64e(0x20eaafea8fafcaca), C64e(0x7d898e89f38ef4f4), + C64e(0x6720e9208ee94747), C64e(0x3828182820181010), + C64e(0x0b64d564ded56f6f), C64e(0x73838883fb88f0f0), + C64e(0xfbb16fb1946f4a4a), C64e(0xca967296b8725c5c), + C64e(0x546c246c70243838), C64e(0x5f08f108aef15757), + C64e(0x2152c752e6c77373), C64e(0x64f351f335519797), + C64e(0xae6523658d23cbcb), C64e(0x25847c84597ca1a1), + C64e(0x57bf9cbfcb9ce8e8), C64e(0x5d6321637c213e3e), + C64e(0xea7cdd7c37dd9696), C64e(0x1e7fdc7fc2dc6161), + C64e(0x9c9186911a860d0d), C64e(0x9b9485941e850f0f), + C64e(0x4bab90abdb90e0e0), C64e(0xbac642c6f8427c7c), + C64e(0x2657c457e2c47171), C64e(0x29e5aae583aacccc), + C64e(0xe373d8733bd89090), C64e(0x090f050f0c050606), + C64e(0xf4030103f501f7f7), C64e(0x2a36123638121c1c), + C64e(0x3cfea3fe9fa3c2c2), C64e(0x8be15fe1d45f6a6a), + C64e(0xbe10f91047f9aeae), C64e(0x026bd06bd2d06969), + C64e(0xbfa891a82e911717), C64e(0x71e858e829589999), + C64e(0x5369276974273a3a), C64e(0xf7d0b9d04eb92727), + C64e(0x91483848a938d9d9), C64e(0xde351335cd13ebeb), + C64e(0xe5ceb3ce56b32b2b), C64e(0x7755335544332222), + C64e(0x04d6bbd6bfbbd2d2), C64e(0x399070904970a9a9), + C64e(0x878089800e890707), C64e(0xc1f2a7f266a73333), + C64e(0xecc1b6c15ab62d2d), C64e(0x5a66226678223c3c), + C64e(0xb8ad92ad2a921515), C64e(0xa96020608920c9c9), + C64e(0x5cdb49db15498787), C64e(0xb01aff1a4fffaaaa), + C64e(0xd8887888a0785050), C64e(0x2b8e7a8e517aa5a5), + C64e(0x898a8f8a068f0303), C64e(0x4a13f813b2f85959), + C64e(0x929b809b12800909), C64e(0x2339173934171a1a), + C64e(0x1075da75cada6565), C64e(0x84533153b531d7d7), + C64e(0xd551c65113c68484), C64e(0x03d3b8d3bbb8d0d0), + C64e(0xdc5ec35e1fc38282), C64e(0xe2cbb0cb52b02929), + C64e(0xc3997799b4775a5a), C64e(0x2d3311333c111e1e), + C64e(0x3d46cb46f6cb7b7b), C64e(0xb71ffc1f4bfca8a8), + C64e(0x0c61d661dad66d6d), C64e(0x624e3a4e583a2c2c) +}; + +#endif + +#define DECL_STATE_SMALL \ + sph_u64 H[8]; + +#define READ_STATE_SMALL(sc) do { \ + memcpy(H, (sc)->state.wide, sizeof H); \ + } while (0) + +#define WRITE_STATE_SMALL(sc) do { \ + memcpy((sc)->state.wide, H, sizeof H); \ + } while (0) + +#if SPH_SMALL_FOOTPRINT_GROESTL + +#define RSTT(d, a, b0, b1, b2, b3, b4, b5, b6, b7) do { \ + t[d] = T0[B64_0(a[b0])] \ + ^ R64(T0[B64_1(a[b1])], 8) \ + ^ R64(T0[B64_2(a[b2])], 16) \ + ^ R64(T0[B64_3(a[b3])], 24) \ + ^ T4[B64_4(a[b4])] \ + ^ R64(T4[B64_5(a[b5])], 8) \ + ^ R64(T4[B64_6(a[b6])], 16) \ + ^ R64(T4[B64_7(a[b7])], 24); \ + } while (0) + +#else + +#define RSTT(d, a, b0, b1, b2, b3, b4, b5, b6, b7) do { \ + t[d] = T0[B64_0(a[b0])] \ + ^ T1[B64_1(a[b1])] \ + ^ T2[B64_2(a[b2])] \ + ^ T3[B64_3(a[b3])] \ + ^ T4[B64_4(a[b4])] \ + ^ T5[B64_5(a[b5])] \ + ^ T6[B64_6(a[b6])] \ + ^ T7[B64_7(a[b7])]; \ + } while (0) + +#endif + +#define ROUND_SMALL_P(a, r) do { \ + sph_u64 t[8]; \ + a[0] ^= PC64(0x00, r); \ + a[1] ^= PC64(0x10, r); \ + a[2] ^= PC64(0x20, r); \ + a[3] ^= PC64(0x30, r); \ + a[4] ^= PC64(0x40, r); \ + a[5] ^= PC64(0x50, r); \ + a[6] ^= PC64(0x60, r); \ + a[7] ^= PC64(0x70, r); \ + RSTT(0, a, 0, 1, 2, 3, 4, 5, 6, 7); \ + RSTT(1, a, 1, 2, 3, 4, 5, 6, 7, 0); \ + RSTT(2, a, 2, 3, 4, 5, 6, 7, 0, 1); \ + RSTT(3, a, 3, 4, 5, 6, 7, 0, 1, 2); \ + RSTT(4, a, 4, 5, 6, 7, 0, 1, 2, 3); \ + RSTT(5, a, 5, 6, 7, 0, 1, 2, 3, 4); \ + RSTT(6, a, 6, 7, 0, 1, 2, 3, 4, 5); \ + RSTT(7, a, 7, 0, 1, 2, 3, 4, 5, 6); \ + a[0] = t[0]; \ + a[1] = t[1]; \ + a[2] = t[2]; \ + a[3] = t[3]; \ + a[4] = t[4]; \ + a[5] = t[5]; \ + a[6] = t[6]; \ + a[7] = t[7]; \ + } while (0) + +#define ROUND_SMALL_Q(a, r) do { \ + sph_u64 t[8]; \ + a[0] ^= QC64(0x00, r); \ + a[1] ^= QC64(0x10, r); \ + a[2] ^= QC64(0x20, r); \ + a[3] ^= QC64(0x30, r); \ + a[4] ^= QC64(0x40, r); \ + a[5] ^= QC64(0x50, r); \ + a[6] ^= QC64(0x60, r); \ + a[7] ^= QC64(0x70, r); \ + RSTT(0, a, 1, 3, 5, 7, 0, 2, 4, 6); \ + RSTT(1, a, 2, 4, 6, 0, 1, 3, 5, 7); \ + RSTT(2, a, 3, 5, 7, 1, 2, 4, 6, 0); \ + RSTT(3, a, 4, 6, 0, 2, 3, 5, 7, 1); \ + RSTT(4, a, 5, 7, 1, 3, 4, 6, 0, 2); \ + RSTT(5, a, 6, 0, 2, 4, 5, 7, 1, 3); \ + RSTT(6, a, 7, 1, 3, 5, 6, 0, 2, 4); \ + RSTT(7, a, 0, 2, 4, 6, 7, 1, 3, 5); \ + a[0] = t[0]; \ + a[1] = t[1]; \ + a[2] = t[2]; \ + a[3] = t[3]; \ + a[4] = t[4]; \ + a[5] = t[5]; \ + a[6] = t[6]; \ + a[7] = t[7]; \ + } while (0) + +#if SPH_SMALL_FOOTPRINT_GROESTL + +#define PERM_SMALL_P(a) do { \ + int r; \ + for (r = 0; r < 10; r ++) \ + ROUND_SMALL_P(a, r); \ + } while (0) + +#define PERM_SMALL_Q(a) do { \ + int r; \ + for (r = 0; r < 10; r ++) \ + ROUND_SMALL_Q(a, r); \ + } while (0) + +#else + +/* + * Apparently, unrolling more than that confuses GCC, resulting in + * lower performance, even though L1 cache would be no problem. + */ +#define PERM_SMALL_P(a) do { \ + int r; \ + for (r = 0; r < 10; r += 2) { \ + ROUND_SMALL_P(a, r + 0); \ + ROUND_SMALL_P(a, r + 1); \ + } \ + } while (0) + +#define PERM_SMALL_Q(a) do { \ + int r; \ + for (r = 0; r < 10; r += 2) { \ + ROUND_SMALL_Q(a, r + 0); \ + ROUND_SMALL_Q(a, r + 1); \ + } \ + } while (0) + +#endif + +#define COMPRESS_SMALL do { \ + sph_u64 g[8], m[8]; \ + size_t u; \ + for (u = 0; u < 8; u ++) { \ + m[u] = dec64e_aligned(buf + (u << 3)); \ + g[u] = m[u] ^ H[u]; \ + } \ + PERM_SMALL_P(g); \ + PERM_SMALL_Q(m); \ + for (u = 0; u < 8; u ++) \ + H[u] ^= g[u] ^ m[u]; \ + } while (0) + +#define FINAL_SMALL do { \ + sph_u64 x[8]; \ + size_t u; \ + memcpy(x, H, sizeof x); \ + PERM_SMALL_P(x); \ + for (u = 0; u < 8; u ++) \ + H[u] ^= x[u]; \ + } while (0) + +#define DECL_STATE_BIG \ + sph_u64 H[16]; + +#define READ_STATE_BIG(sc) do { \ + memcpy(H, (sc)->state.wide, sizeof H); \ + } while (0) + +#define WRITE_STATE_BIG(sc) do { \ + memcpy((sc)->state.wide, H, sizeof H); \ + } while (0) + +#if SPH_SMALL_FOOTPRINT_GROESTL + +#define RBTT(d, a, b0, b1, b2, b3, b4, b5, b6, b7) do { \ + t[d] = T0[B64_0(a[b0])] \ + ^ R64(T0[B64_1(a[b1])], 8) \ + ^ R64(T0[B64_2(a[b2])], 16) \ + ^ R64(T0[B64_3(a[b3])], 24) \ + ^ T4[B64_4(a[b4])] \ + ^ R64(T4[B64_5(a[b5])], 8) \ + ^ R64(T4[B64_6(a[b6])], 16) \ + ^ R64(T4[B64_7(a[b7])], 24); \ + } while (0) + +#else + +#define RBTT(d, a, b0, b1, b2, b3, b4, b5, b6, b7) do { \ + t[d] = T0[B64_0(a[b0])] \ + ^ T1[B64_1(a[b1])] \ + ^ T2[B64_2(a[b2])] \ + ^ T3[B64_3(a[b3])] \ + ^ T4[B64_4(a[b4])] \ + ^ T5[B64_5(a[b5])] \ + ^ T6[B64_6(a[b6])] \ + ^ T7[B64_7(a[b7])]; \ + } while (0) + +#endif + +#if SPH_SMALL_FOOTPRINT_GROESTL + +#define ROUND_BIG_P(a, r) do { \ + sph_u64 t[16]; \ + size_t u; \ + a[0x0] ^= PC64(0x00, r); \ + a[0x1] ^= PC64(0x10, r); \ + a[0x2] ^= PC64(0x20, r); \ + a[0x3] ^= PC64(0x30, r); \ + a[0x4] ^= PC64(0x40, r); \ + a[0x5] ^= PC64(0x50, r); \ + a[0x6] ^= PC64(0x60, r); \ + a[0x7] ^= PC64(0x70, r); \ + a[0x8] ^= PC64(0x80, r); \ + a[0x9] ^= PC64(0x90, r); \ + a[0xA] ^= PC64(0xA0, r); \ + a[0xB] ^= PC64(0xB0, r); \ + a[0xC] ^= PC64(0xC0, r); \ + a[0xD] ^= PC64(0xD0, r); \ + a[0xE] ^= PC64(0xE0, r); \ + a[0xF] ^= PC64(0xF0, r); \ + for (u = 0; u < 16; u += 4) { \ + RBTT(u + 0, a, u + 0, (u + 1) & 0xF, \ + (u + 2) & 0xF, (u + 3) & 0xF, (u + 4) & 0xF, \ + (u + 5) & 0xF, (u + 6) & 0xF, (u + 11) & 0xF); \ + RBTT(u + 1, a, u + 1, (u + 2) & 0xF, \ + (u + 3) & 0xF, (u + 4) & 0xF, (u + 5) & 0xF, \ + (u + 6) & 0xF, (u + 7) & 0xF, (u + 12) & 0xF); \ + RBTT(u + 2, a, u + 2, (u + 3) & 0xF, \ + (u + 4) & 0xF, (u + 5) & 0xF, (u + 6) & 0xF, \ + (u + 7) & 0xF, (u + 8) & 0xF, (u + 13) & 0xF); \ + RBTT(u + 3, a, u + 3, (u + 4) & 0xF, \ + (u + 5) & 0xF, (u + 6) & 0xF, (u + 7) & 0xF, \ + (u + 8) & 0xF, (u + 9) & 0xF, (u + 14) & 0xF); \ + } \ + memcpy(a, t, sizeof t); \ + } while (0) + +#define ROUND_BIG_Q(a, r) do { \ + sph_u64 t[16]; \ + size_t u; \ + a[0x0] ^= QC64(0x00, r); \ + a[0x1] ^= QC64(0x10, r); \ + a[0x2] ^= QC64(0x20, r); \ + a[0x3] ^= QC64(0x30, r); \ + a[0x4] ^= QC64(0x40, r); \ + a[0x5] ^= QC64(0x50, r); \ + a[0x6] ^= QC64(0x60, r); \ + a[0x7] ^= QC64(0x70, r); \ + a[0x8] ^= QC64(0x80, r); \ + a[0x9] ^= QC64(0x90, r); \ + a[0xA] ^= QC64(0xA0, r); \ + a[0xB] ^= QC64(0xB0, r); \ + a[0xC] ^= QC64(0xC0, r); \ + a[0xD] ^= QC64(0xD0, r); \ + a[0xE] ^= QC64(0xE0, r); \ + a[0xF] ^= QC64(0xF0, r); \ + for (u = 0; u < 16; u += 4) { \ + RBTT(u + 0, a, (u + 1) & 0xF, (u + 3) & 0xF, \ + (u + 5) & 0xF, (u + 11) & 0xF, (u + 0) & 0xF, \ + (u + 2) & 0xF, (u + 4) & 0xF, (u + 6) & 0xF); \ + RBTT(u + 1, a, (u + 2) & 0xF, (u + 4) & 0xF, \ + (u + 6) & 0xF, (u + 12) & 0xF, (u + 1) & 0xF, \ + (u + 3) & 0xF, (u + 5) & 0xF, (u + 7) & 0xF); \ + RBTT(u + 2, a, (u + 3) & 0xF, (u + 5) & 0xF, \ + (u + 7) & 0xF, (u + 13) & 0xF, (u + 2) & 0xF, \ + (u + 4) & 0xF, (u + 6) & 0xF, (u + 8) & 0xF); \ + RBTT(u + 3, a, (u + 4) & 0xF, (u + 6) & 0xF, \ + (u + 8) & 0xF, (u + 14) & 0xF, (u + 3) & 0xF, \ + (u + 5) & 0xF, (u + 7) & 0xF, (u + 9) & 0xF); \ + } \ + memcpy(a, t, sizeof t); \ + } while (0) + +#else + +#define ROUND_BIG_P(a, r) do { \ + sph_u64 t[16]; \ + a[0x0] ^= PC64(0x00, r); \ + a[0x1] ^= PC64(0x10, r); \ + a[0x2] ^= PC64(0x20, r); \ + a[0x3] ^= PC64(0x30, r); \ + a[0x4] ^= PC64(0x40, r); \ + a[0x5] ^= PC64(0x50, r); \ + a[0x6] ^= PC64(0x60, r); \ + a[0x7] ^= PC64(0x70, r); \ + a[0x8] ^= PC64(0x80, r); \ + a[0x9] ^= PC64(0x90, r); \ + a[0xA] ^= PC64(0xA0, r); \ + a[0xB] ^= PC64(0xB0, r); \ + a[0xC] ^= PC64(0xC0, r); \ + a[0xD] ^= PC64(0xD0, r); \ + a[0xE] ^= PC64(0xE0, r); \ + a[0xF] ^= PC64(0xF0, r); \ + RBTT(0x0, a, 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0xB); \ + RBTT(0x1, a, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0xC); \ + RBTT(0x2, a, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0xD); \ + RBTT(0x3, a, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xE); \ + RBTT(0x4, a, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xF); \ + RBTT(0x5, a, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0x0); \ + RBTT(0x6, a, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0x1); \ + RBTT(0x7, a, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0x2); \ + RBTT(0x8, a, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0x3); \ + RBTT(0x9, a, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0x4); \ + RBTT(0xA, a, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0x0, 0x5); \ + RBTT(0xB, a, 0xB, 0xC, 0xD, 0xE, 0xF, 0x0, 0x1, 0x6); \ + RBTT(0xC, a, 0xC, 0xD, 0xE, 0xF, 0x0, 0x1, 0x2, 0x7); \ + RBTT(0xD, a, 0xD, 0xE, 0xF, 0x0, 0x1, 0x2, 0x3, 0x8); \ + RBTT(0xE, a, 0xE, 0xF, 0x0, 0x1, 0x2, 0x3, 0x4, 0x9); \ + RBTT(0xF, a, 0xF, 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0xA); \ + a[0x0] = t[0x0]; \ + a[0x1] = t[0x1]; \ + a[0x2] = t[0x2]; \ + a[0x3] = t[0x3]; \ + a[0x4] = t[0x4]; \ + a[0x5] = t[0x5]; \ + a[0x6] = t[0x6]; \ + a[0x7] = t[0x7]; \ + a[0x8] = t[0x8]; \ + a[0x9] = t[0x9]; \ + a[0xA] = t[0xA]; \ + a[0xB] = t[0xB]; \ + a[0xC] = t[0xC]; \ + a[0xD] = t[0xD]; \ + a[0xE] = t[0xE]; \ + a[0xF] = t[0xF]; \ + } while (0) + +#define ROUND_BIG_Q(a, r) do { \ + sph_u64 t[16]; \ + a[0x0] ^= QC64(0x00, r); \ + a[0x1] ^= QC64(0x10, r); \ + a[0x2] ^= QC64(0x20, r); \ + a[0x3] ^= QC64(0x30, r); \ + a[0x4] ^= QC64(0x40, r); \ + a[0x5] ^= QC64(0x50, r); \ + a[0x6] ^= QC64(0x60, r); \ + a[0x7] ^= QC64(0x70, r); \ + a[0x8] ^= QC64(0x80, r); \ + a[0x9] ^= QC64(0x90, r); \ + a[0xA] ^= QC64(0xA0, r); \ + a[0xB] ^= QC64(0xB0, r); \ + a[0xC] ^= QC64(0xC0, r); \ + a[0xD] ^= QC64(0xD0, r); \ + a[0xE] ^= QC64(0xE0, r); \ + a[0xF] ^= QC64(0xF0, r); \ + RBTT(0x0, a, 0x1, 0x3, 0x5, 0xB, 0x0, 0x2, 0x4, 0x6); \ + RBTT(0x1, a, 0x2, 0x4, 0x6, 0xC, 0x1, 0x3, 0x5, 0x7); \ + RBTT(0x2, a, 0x3, 0x5, 0x7, 0xD, 0x2, 0x4, 0x6, 0x8); \ + RBTT(0x3, a, 0x4, 0x6, 0x8, 0xE, 0x3, 0x5, 0x7, 0x9); \ + RBTT(0x4, a, 0x5, 0x7, 0x9, 0xF, 0x4, 0x6, 0x8, 0xA); \ + RBTT(0x5, a, 0x6, 0x8, 0xA, 0x0, 0x5, 0x7, 0x9, 0xB); \ + RBTT(0x6, a, 0x7, 0x9, 0xB, 0x1, 0x6, 0x8, 0xA, 0xC); \ + RBTT(0x7, a, 0x8, 0xA, 0xC, 0x2, 0x7, 0x9, 0xB, 0xD); \ + RBTT(0x8, a, 0x9, 0xB, 0xD, 0x3, 0x8, 0xA, 0xC, 0xE); \ + RBTT(0x9, a, 0xA, 0xC, 0xE, 0x4, 0x9, 0xB, 0xD, 0xF); \ + RBTT(0xA, a, 0xB, 0xD, 0xF, 0x5, 0xA, 0xC, 0xE, 0x0); \ + RBTT(0xB, a, 0xC, 0xE, 0x0, 0x6, 0xB, 0xD, 0xF, 0x1); \ + RBTT(0xC, a, 0xD, 0xF, 0x1, 0x7, 0xC, 0xE, 0x0, 0x2); \ + RBTT(0xD, a, 0xE, 0x0, 0x2, 0x8, 0xD, 0xF, 0x1, 0x3); \ + RBTT(0xE, a, 0xF, 0x1, 0x3, 0x9, 0xE, 0x0, 0x2, 0x4); \ + RBTT(0xF, a, 0x0, 0x2, 0x4, 0xA, 0xF, 0x1, 0x3, 0x5); \ + a[0x0] = t[0x0]; \ + a[0x1] = t[0x1]; \ + a[0x2] = t[0x2]; \ + a[0x3] = t[0x3]; \ + a[0x4] = t[0x4]; \ + a[0x5] = t[0x5]; \ + a[0x6] = t[0x6]; \ + a[0x7] = t[0x7]; \ + a[0x8] = t[0x8]; \ + a[0x9] = t[0x9]; \ + a[0xA] = t[0xA]; \ + a[0xB] = t[0xB]; \ + a[0xC] = t[0xC]; \ + a[0xD] = t[0xD]; \ + a[0xE] = t[0xE]; \ + a[0xF] = t[0xF]; \ + } while (0) + +#endif + +#define PERM_BIG_P(a) do { \ + int r; \ + for (r = 0; r < 14; r += 2) { \ + ROUND_BIG_P(a, r + 0); \ + ROUND_BIG_P(a, r + 1); \ + } \ + } while (0) + +#define PERM_BIG_Q(a) do { \ + int r; \ + for (r = 0; r < 14; r += 2) { \ + ROUND_BIG_Q(a, r + 0); \ + ROUND_BIG_Q(a, r + 1); \ + } \ + } while (0) + +/* obsolete +#if SPH_SMALL_FOOTPRINT_GROESTL + +#define COMPRESS_BIG do { \ + sph_u64 g[16], m[16], *ya; \ + const sph_u64 *yc; \ + size_t u; \ + int i; \ + for (u = 0; u < 16; u ++) { \ + m[u] = dec64e_aligned(buf + (u << 3)); \ + g[u] = m[u] ^ H[u]; \ + } \ + ya = g; \ + yc = CP; \ + for (i = 0; i < 2; i ++) { \ + PERM_BIG(ya, yc); \ + ya = m; \ + yc = CQ; \ + } \ + for (u = 0; u < 16; u ++) { \ + H[u] ^= g[u] ^ m[u]; \ + } \ + } while (0) + +#else +*/ + +#define COMPRESS_BIG do { \ + sph_u64 g[16], m[16]; \ + size_t u; \ + for (u = 0; u < 16; u ++) { \ + m[u] = dec64e_aligned(buf + (u << 3)); \ + g[u] = m[u] ^ H[u]; \ + } \ + PERM_BIG_P(g); \ + PERM_BIG_Q(m); \ + for (u = 0; u < 16; u ++) { \ + H[u] ^= g[u] ^ m[u]; \ + } \ + } while (0) + +/* obsolete +#endif +*/ + +#define FINAL_BIG do { \ + sph_u64 x[16]; \ + size_t u; \ + memcpy(x, H, sizeof x); \ + PERM_BIG_P(x); \ + for (u = 0; u < 16; u ++) \ + H[u] ^= x[u]; \ + } while (0) + +#else + +static const sph_u32 T0up[] = { + C32e(0xc632f4a5), C32e(0xf86f9784), C32e(0xee5eb099), C32e(0xf67a8c8d), + C32e(0xffe8170d), C32e(0xd60adcbd), C32e(0xde16c8b1), C32e(0x916dfc54), + C32e(0x6090f050), C32e(0x02070503), C32e(0xce2ee0a9), C32e(0x56d1877d), + C32e(0xe7cc2b19), C32e(0xb513a662), C32e(0x4d7c31e6), C32e(0xec59b59a), + C32e(0x8f40cf45), C32e(0x1fa3bc9d), C32e(0x8949c040), C32e(0xfa689287), + C32e(0xefd03f15), C32e(0xb29426eb), C32e(0x8ece40c9), C32e(0xfbe61d0b), + C32e(0x416e2fec), C32e(0xb31aa967), C32e(0x5f431cfd), C32e(0x456025ea), + C32e(0x23f9dabf), C32e(0x535102f7), C32e(0xe445a196), C32e(0x9b76ed5b), + C32e(0x75285dc2), C32e(0xe1c5241c), C32e(0x3dd4e9ae), C32e(0x4cf2be6a), + C32e(0x6c82ee5a), C32e(0x7ebdc341), C32e(0xf5f30602), C32e(0x8352d14f), + C32e(0x688ce45c), C32e(0x515607f4), C32e(0xd18d5c34), C32e(0xf9e11808), + C32e(0xe24cae93), C32e(0xab3e9573), C32e(0x6297f553), C32e(0x2a6b413f), + C32e(0x081c140c), C32e(0x9563f652), C32e(0x46e9af65), C32e(0x9d7fe25e), + C32e(0x30487828), C32e(0x37cff8a1), C32e(0x0a1b110f), C32e(0x2febc4b5), + C32e(0x0e151b09), C32e(0x247e5a36), C32e(0x1badb69b), C32e(0xdf98473d), + C32e(0xcda76a26), C32e(0x4ef5bb69), C32e(0x7f334ccd), C32e(0xea50ba9f), + C32e(0x123f2d1b), C32e(0x1da4b99e), C32e(0x58c49c74), C32e(0x3446722e), + C32e(0x3641772d), C32e(0xdc11cdb2), C32e(0xb49d29ee), C32e(0x5b4d16fb), + C32e(0xa4a501f6), C32e(0x76a1d74d), C32e(0xb714a361), C32e(0x7d3449ce), + C32e(0x52df8d7b), C32e(0xdd9f423e), C32e(0x5ecd9371), C32e(0x13b1a297), + C32e(0xa6a204f5), C32e(0xb901b868), C32e(0x00000000), C32e(0xc1b5742c), + C32e(0x40e0a060), C32e(0xe3c2211f), C32e(0x793a43c8), C32e(0xb69a2ced), + C32e(0xd40dd9be), C32e(0x8d47ca46), C32e(0x671770d9), C32e(0x72afdd4b), + C32e(0x94ed79de), C32e(0x98ff67d4), C32e(0xb09323e8), C32e(0x855bde4a), + C32e(0xbb06bd6b), C32e(0xc5bb7e2a), C32e(0x4f7b34e5), C32e(0xedd73a16), + C32e(0x86d254c5), C32e(0x9af862d7), C32e(0x6699ff55), C32e(0x11b6a794), + C32e(0x8ac04acf), C32e(0xe9d93010), C32e(0x040e0a06), C32e(0xfe669881), + C32e(0xa0ab0bf0), C32e(0x78b4cc44), C32e(0x25f0d5ba), C32e(0x4b753ee3), + C32e(0xa2ac0ef3), C32e(0x5d4419fe), C32e(0x80db5bc0), C32e(0x0580858a), + C32e(0x3fd3ecad), C32e(0x21fedfbc), C32e(0x70a8d848), C32e(0xf1fd0c04), + C32e(0x63197adf), C32e(0x772f58c1), C32e(0xaf309f75), C32e(0x42e7a563), + C32e(0x20705030), C32e(0xe5cb2e1a), C32e(0xfdef120e), C32e(0xbf08b76d), + C32e(0x8155d44c), C32e(0x18243c14), C32e(0x26795f35), C32e(0xc3b2712f), + C32e(0xbe8638e1), C32e(0x35c8fda2), C32e(0x88c74fcc), C32e(0x2e654b39), + C32e(0x936af957), C32e(0x55580df2), C32e(0xfc619d82), C32e(0x7ab3c947), + C32e(0xc827efac), C32e(0xba8832e7), C32e(0x324f7d2b), C32e(0xe642a495), + C32e(0xc03bfba0), C32e(0x19aab398), C32e(0x9ef668d1), C32e(0xa322817f), + C32e(0x44eeaa66), C32e(0x54d6827e), C32e(0x3bdde6ab), C32e(0x0b959e83), + C32e(0x8cc945ca), C32e(0xc7bc7b29), C32e(0x6b056ed3), C32e(0x286c443c), + C32e(0xa72c8b79), C32e(0xbc813de2), C32e(0x1631271d), C32e(0xad379a76), + C32e(0xdb964d3b), C32e(0x649efa56), C32e(0x74a6d24e), C32e(0x1436221e), + C32e(0x92e476db), C32e(0x0c121e0a), C32e(0x48fcb46c), C32e(0xb88f37e4), + C32e(0x9f78e75d), C32e(0xbd0fb26e), C32e(0x43692aef), C32e(0xc435f1a6), + C32e(0x39dae3a8), C32e(0x31c6f7a4), C32e(0xd38a5937), C32e(0xf274868b), + C32e(0xd5835632), C32e(0x8b4ec543), C32e(0x6e85eb59), C32e(0xda18c2b7), + C32e(0x018e8f8c), C32e(0xb11dac64), C32e(0x9cf16dd2), C32e(0x49723be0), + C32e(0xd81fc7b4), C32e(0xacb915fa), C32e(0xf3fa0907), C32e(0xcfa06f25), + C32e(0xca20eaaf), C32e(0xf47d898e), C32e(0x476720e9), C32e(0x10382818), + C32e(0x6f0b64d5), C32e(0xf0738388), C32e(0x4afbb16f), C32e(0x5cca9672), + C32e(0x38546c24), C32e(0x575f08f1), C32e(0x732152c7), C32e(0x9764f351), + C32e(0xcbae6523), C32e(0xa125847c), C32e(0xe857bf9c), C32e(0x3e5d6321), + C32e(0x96ea7cdd), C32e(0x611e7fdc), C32e(0x0d9c9186), C32e(0x0f9b9485), + C32e(0xe04bab90), C32e(0x7cbac642), C32e(0x712657c4), C32e(0xcc29e5aa), + C32e(0x90e373d8), C32e(0x06090f05), C32e(0xf7f40301), C32e(0x1c2a3612), + C32e(0xc23cfea3), C32e(0x6a8be15f), C32e(0xaebe10f9), C32e(0x69026bd0), + C32e(0x17bfa891), C32e(0x9971e858), C32e(0x3a536927), C32e(0x27f7d0b9), + C32e(0xd9914838), C32e(0xebde3513), C32e(0x2be5ceb3), C32e(0x22775533), + C32e(0xd204d6bb), C32e(0xa9399070), C32e(0x07878089), C32e(0x33c1f2a7), + C32e(0x2decc1b6), C32e(0x3c5a6622), C32e(0x15b8ad92), C32e(0xc9a96020), + C32e(0x875cdb49), C32e(0xaab01aff), C32e(0x50d88878), C32e(0xa52b8e7a), + C32e(0x03898a8f), C32e(0x594a13f8), C32e(0x09929b80), C32e(0x1a233917), + C32e(0x651075da), C32e(0xd7845331), C32e(0x84d551c6), C32e(0xd003d3b8), + C32e(0x82dc5ec3), C32e(0x29e2cbb0), C32e(0x5ac39977), C32e(0x1e2d3311), + C32e(0x7b3d46cb), C32e(0xa8b71ffc), C32e(0x6d0c61d6), C32e(0x2c624e3a) +}; + +static const sph_u32 T0dn[] = { + C32e(0xf497a5c6), C32e(0x97eb84f8), C32e(0xb0c799ee), C32e(0x8cf78df6), + C32e(0x17e50dff), C32e(0xdcb7bdd6), C32e(0xc8a7b1de), C32e(0xfc395491), + C32e(0xf0c05060), C32e(0x05040302), C32e(0xe087a9ce), C32e(0x87ac7d56), + C32e(0x2bd519e7), C32e(0xa67162b5), C32e(0x319ae64d), C32e(0xb5c39aec), + C32e(0xcf05458f), C32e(0xbc3e9d1f), C32e(0xc0094089), C32e(0x92ef87fa), + C32e(0x3fc515ef), C32e(0x267febb2), C32e(0x4007c98e), C32e(0x1ded0bfb), + C32e(0x2f82ec41), C32e(0xa97d67b3), C32e(0x1cbefd5f), C32e(0x258aea45), + C32e(0xda46bf23), C32e(0x02a6f753), C32e(0xa1d396e4), C32e(0xed2d5b9b), + C32e(0x5deac275), C32e(0x24d91ce1), C32e(0xe97aae3d), C32e(0xbe986a4c), + C32e(0xeed85a6c), C32e(0xc3fc417e), C32e(0x06f102f5), C32e(0xd11d4f83), + C32e(0xe4d05c68), C32e(0x07a2f451), C32e(0x5cb934d1), C32e(0x18e908f9), + C32e(0xaedf93e2), C32e(0x954d73ab), C32e(0xf5c45362), C32e(0x41543f2a), + C32e(0x14100c08), C32e(0xf6315295), C32e(0xaf8c6546), C32e(0xe2215e9d), + C32e(0x78602830), C32e(0xf86ea137), C32e(0x11140f0a), C32e(0xc45eb52f), + C32e(0x1b1c090e), C32e(0x5a483624), C32e(0xb6369b1b), C32e(0x47a53ddf), + C32e(0x6a8126cd), C32e(0xbb9c694e), C32e(0x4cfecd7f), C32e(0xbacf9fea), + C32e(0x2d241b12), C32e(0xb93a9e1d), C32e(0x9cb07458), C32e(0x72682e34), + C32e(0x776c2d36), C32e(0xcda3b2dc), C32e(0x2973eeb4), C32e(0x16b6fb5b), + C32e(0x0153f6a4), C32e(0xd7ec4d76), C32e(0xa37561b7), C32e(0x49face7d), + C32e(0x8da47b52), C32e(0x42a13edd), C32e(0x93bc715e), C32e(0xa2269713), + C32e(0x0457f5a6), C32e(0xb86968b9), C32e(0x00000000), C32e(0x74992cc1), + C32e(0xa0806040), C32e(0x21dd1fe3), C32e(0x43f2c879), C32e(0x2c77edb6), + C32e(0xd9b3bed4), C32e(0xca01468d), C32e(0x70ced967), C32e(0xdde44b72), + C32e(0x7933de94), C32e(0x672bd498), C32e(0x237be8b0), C32e(0xde114a85), + C32e(0xbd6d6bbb), C32e(0x7e912ac5), C32e(0x349ee54f), C32e(0x3ac116ed), + C32e(0x5417c586), C32e(0x622fd79a), C32e(0xffcc5566), C32e(0xa7229411), + C32e(0x4a0fcf8a), C32e(0x30c910e9), C32e(0x0a080604), C32e(0x98e781fe), + C32e(0x0b5bf0a0), C32e(0xccf04478), C32e(0xd54aba25), C32e(0x3e96e34b), + C32e(0x0e5ff3a2), C32e(0x19bafe5d), C32e(0x5b1bc080), C32e(0x850a8a05), + C32e(0xec7ead3f), C32e(0xdf42bc21), C32e(0xd8e04870), C32e(0x0cf904f1), + C32e(0x7ac6df63), C32e(0x58eec177), C32e(0x9f4575af), C32e(0xa5846342), + C32e(0x50403020), C32e(0x2ed11ae5), C32e(0x12e10efd), C32e(0xb7656dbf), + C32e(0xd4194c81), C32e(0x3c301418), C32e(0x5f4c3526), C32e(0x719d2fc3), + C32e(0x3867e1be), C32e(0xfd6aa235), C32e(0x4f0bcc88), C32e(0x4b5c392e), + C32e(0xf93d5793), C32e(0x0daaf255), C32e(0x9de382fc), C32e(0xc9f4477a), + C32e(0xef8bacc8), C32e(0x326fe7ba), C32e(0x7d642b32), C32e(0xa4d795e6), + C32e(0xfb9ba0c0), C32e(0xb3329819), C32e(0x6827d19e), C32e(0x815d7fa3), + C32e(0xaa886644), C32e(0x82a87e54), C32e(0xe676ab3b), C32e(0x9e16830b), + C32e(0x4503ca8c), C32e(0x7b9529c7), C32e(0x6ed6d36b), C32e(0x44503c28), + C32e(0x8b5579a7), C32e(0x3d63e2bc), C32e(0x272c1d16), C32e(0x9a4176ad), + C32e(0x4dad3bdb), C32e(0xfac85664), C32e(0xd2e84e74), C32e(0x22281e14), + C32e(0x763fdb92), C32e(0x1e180a0c), C32e(0xb4906c48), C32e(0x376be4b8), + C32e(0xe7255d9f), C32e(0xb2616ebd), C32e(0x2a86ef43), C32e(0xf193a6c4), + C32e(0xe372a839), C32e(0xf762a431), C32e(0x59bd37d3), C32e(0x86ff8bf2), + C32e(0x56b132d5), C32e(0xc50d438b), C32e(0xebdc596e), C32e(0xc2afb7da), + C32e(0x8f028c01), C32e(0xac7964b1), C32e(0x6d23d29c), C32e(0x3b92e049), + C32e(0xc7abb4d8), C32e(0x1543faac), C32e(0x09fd07f3), C32e(0x6f8525cf), + C32e(0xea8fafca), C32e(0x89f38ef4), C32e(0x208ee947), C32e(0x28201810), + C32e(0x64ded56f), C32e(0x83fb88f0), C32e(0xb1946f4a), C32e(0x96b8725c), + C32e(0x6c702438), C32e(0x08aef157), C32e(0x52e6c773), C32e(0xf3355197), + C32e(0x658d23cb), C32e(0x84597ca1), C32e(0xbfcb9ce8), C32e(0x637c213e), + C32e(0x7c37dd96), C32e(0x7fc2dc61), C32e(0x911a860d), C32e(0x941e850f), + C32e(0xabdb90e0), C32e(0xc6f8427c), C32e(0x57e2c471), C32e(0xe583aacc), + C32e(0x733bd890), C32e(0x0f0c0506), C32e(0x03f501f7), C32e(0x3638121c), + C32e(0xfe9fa3c2), C32e(0xe1d45f6a), C32e(0x1047f9ae), C32e(0x6bd2d069), + C32e(0xa82e9117), C32e(0xe8295899), C32e(0x6974273a), C32e(0xd04eb927), + C32e(0x48a938d9), C32e(0x35cd13eb), C32e(0xce56b32b), C32e(0x55443322), + C32e(0xd6bfbbd2), C32e(0x904970a9), C32e(0x800e8907), C32e(0xf266a733), + C32e(0xc15ab62d), C32e(0x6678223c), C32e(0xad2a9215), C32e(0x608920c9), + C32e(0xdb154987), C32e(0x1a4fffaa), C32e(0x88a07850), C32e(0x8e517aa5), + C32e(0x8a068f03), C32e(0x13b2f859), C32e(0x9b128009), C32e(0x3934171a), + C32e(0x75cada65), C32e(0x53b531d7), C32e(0x5113c684), C32e(0xd3bbb8d0), + C32e(0x5e1fc382), C32e(0xcb52b029), C32e(0x99b4775a), C32e(0x333c111e), + C32e(0x46f6cb7b), C32e(0x1f4bfca8), C32e(0x61dad66d), C32e(0x4e583a2c) +}; + +static const sph_u32 T1up[] = { + C32e(0xc6c632f4), C32e(0xf8f86f97), C32e(0xeeee5eb0), C32e(0xf6f67a8c), + C32e(0xffffe817), C32e(0xd6d60adc), C32e(0xdede16c8), C32e(0x91916dfc), + C32e(0x606090f0), C32e(0x02020705), C32e(0xcece2ee0), C32e(0x5656d187), + C32e(0xe7e7cc2b), C32e(0xb5b513a6), C32e(0x4d4d7c31), C32e(0xecec59b5), + C32e(0x8f8f40cf), C32e(0x1f1fa3bc), C32e(0x898949c0), C32e(0xfafa6892), + C32e(0xefefd03f), C32e(0xb2b29426), C32e(0x8e8ece40), C32e(0xfbfbe61d), + C32e(0x41416e2f), C32e(0xb3b31aa9), C32e(0x5f5f431c), C32e(0x45456025), + C32e(0x2323f9da), C32e(0x53535102), C32e(0xe4e445a1), C32e(0x9b9b76ed), + C32e(0x7575285d), C32e(0xe1e1c524), C32e(0x3d3dd4e9), C32e(0x4c4cf2be), + C32e(0x6c6c82ee), C32e(0x7e7ebdc3), C32e(0xf5f5f306), C32e(0x838352d1), + C32e(0x68688ce4), C32e(0x51515607), C32e(0xd1d18d5c), C32e(0xf9f9e118), + C32e(0xe2e24cae), C32e(0xabab3e95), C32e(0x626297f5), C32e(0x2a2a6b41), + C32e(0x08081c14), C32e(0x959563f6), C32e(0x4646e9af), C32e(0x9d9d7fe2), + C32e(0x30304878), C32e(0x3737cff8), C32e(0x0a0a1b11), C32e(0x2f2febc4), + C32e(0x0e0e151b), C32e(0x24247e5a), C32e(0x1b1badb6), C32e(0xdfdf9847), + C32e(0xcdcda76a), C32e(0x4e4ef5bb), C32e(0x7f7f334c), C32e(0xeaea50ba), + C32e(0x12123f2d), C32e(0x1d1da4b9), C32e(0x5858c49c), C32e(0x34344672), + C32e(0x36364177), C32e(0xdcdc11cd), C32e(0xb4b49d29), C32e(0x5b5b4d16), + C32e(0xa4a4a501), C32e(0x7676a1d7), C32e(0xb7b714a3), C32e(0x7d7d3449), + C32e(0x5252df8d), C32e(0xdddd9f42), C32e(0x5e5ecd93), C32e(0x1313b1a2), + C32e(0xa6a6a204), C32e(0xb9b901b8), C32e(0x00000000), C32e(0xc1c1b574), + C32e(0x4040e0a0), C32e(0xe3e3c221), C32e(0x79793a43), C32e(0xb6b69a2c), + C32e(0xd4d40dd9), C32e(0x8d8d47ca), C32e(0x67671770), C32e(0x7272afdd), + C32e(0x9494ed79), C32e(0x9898ff67), C32e(0xb0b09323), C32e(0x85855bde), + C32e(0xbbbb06bd), C32e(0xc5c5bb7e), C32e(0x4f4f7b34), C32e(0xededd73a), + C32e(0x8686d254), C32e(0x9a9af862), C32e(0x666699ff), C32e(0x1111b6a7), + C32e(0x8a8ac04a), C32e(0xe9e9d930), C32e(0x04040e0a), C32e(0xfefe6698), + C32e(0xa0a0ab0b), C32e(0x7878b4cc), C32e(0x2525f0d5), C32e(0x4b4b753e), + C32e(0xa2a2ac0e), C32e(0x5d5d4419), C32e(0x8080db5b), C32e(0x05058085), + C32e(0x3f3fd3ec), C32e(0x2121fedf), C32e(0x7070a8d8), C32e(0xf1f1fd0c), + C32e(0x6363197a), C32e(0x77772f58), C32e(0xafaf309f), C32e(0x4242e7a5), + C32e(0x20207050), C32e(0xe5e5cb2e), C32e(0xfdfdef12), C32e(0xbfbf08b7), + C32e(0x818155d4), C32e(0x1818243c), C32e(0x2626795f), C32e(0xc3c3b271), + C32e(0xbebe8638), C32e(0x3535c8fd), C32e(0x8888c74f), C32e(0x2e2e654b), + C32e(0x93936af9), C32e(0x5555580d), C32e(0xfcfc619d), C32e(0x7a7ab3c9), + C32e(0xc8c827ef), C32e(0xbaba8832), C32e(0x32324f7d), C32e(0xe6e642a4), + C32e(0xc0c03bfb), C32e(0x1919aab3), C32e(0x9e9ef668), C32e(0xa3a32281), + C32e(0x4444eeaa), C32e(0x5454d682), C32e(0x3b3bdde6), C32e(0x0b0b959e), + C32e(0x8c8cc945), C32e(0xc7c7bc7b), C32e(0x6b6b056e), C32e(0x28286c44), + C32e(0xa7a72c8b), C32e(0xbcbc813d), C32e(0x16163127), C32e(0xadad379a), + C32e(0xdbdb964d), C32e(0x64649efa), C32e(0x7474a6d2), C32e(0x14143622), + C32e(0x9292e476), C32e(0x0c0c121e), C32e(0x4848fcb4), C32e(0xb8b88f37), + C32e(0x9f9f78e7), C32e(0xbdbd0fb2), C32e(0x4343692a), C32e(0xc4c435f1), + C32e(0x3939dae3), C32e(0x3131c6f7), C32e(0xd3d38a59), C32e(0xf2f27486), + C32e(0xd5d58356), C32e(0x8b8b4ec5), C32e(0x6e6e85eb), C32e(0xdada18c2), + C32e(0x01018e8f), C32e(0xb1b11dac), C32e(0x9c9cf16d), C32e(0x4949723b), + C32e(0xd8d81fc7), C32e(0xacacb915), C32e(0xf3f3fa09), C32e(0xcfcfa06f), + C32e(0xcaca20ea), C32e(0xf4f47d89), C32e(0x47476720), C32e(0x10103828), + C32e(0x6f6f0b64), C32e(0xf0f07383), C32e(0x4a4afbb1), C32e(0x5c5cca96), + C32e(0x3838546c), C32e(0x57575f08), C32e(0x73732152), C32e(0x979764f3), + C32e(0xcbcbae65), C32e(0xa1a12584), C32e(0xe8e857bf), C32e(0x3e3e5d63), + C32e(0x9696ea7c), C32e(0x61611e7f), C32e(0x0d0d9c91), C32e(0x0f0f9b94), + C32e(0xe0e04bab), C32e(0x7c7cbac6), C32e(0x71712657), C32e(0xcccc29e5), + C32e(0x9090e373), C32e(0x0606090f), C32e(0xf7f7f403), C32e(0x1c1c2a36), + C32e(0xc2c23cfe), C32e(0x6a6a8be1), C32e(0xaeaebe10), C32e(0x6969026b), + C32e(0x1717bfa8), C32e(0x999971e8), C32e(0x3a3a5369), C32e(0x2727f7d0), + C32e(0xd9d99148), C32e(0xebebde35), C32e(0x2b2be5ce), C32e(0x22227755), + C32e(0xd2d204d6), C32e(0xa9a93990), C32e(0x07078780), C32e(0x3333c1f2), + C32e(0x2d2decc1), C32e(0x3c3c5a66), C32e(0x1515b8ad), C32e(0xc9c9a960), + C32e(0x87875cdb), C32e(0xaaaab01a), C32e(0x5050d888), C32e(0xa5a52b8e), + C32e(0x0303898a), C32e(0x59594a13), C32e(0x0909929b), C32e(0x1a1a2339), + C32e(0x65651075), C32e(0xd7d78453), C32e(0x8484d551), C32e(0xd0d003d3), + C32e(0x8282dc5e), C32e(0x2929e2cb), C32e(0x5a5ac399), C32e(0x1e1e2d33), + C32e(0x7b7b3d46), C32e(0xa8a8b71f), C32e(0x6d6d0c61), C32e(0x2c2c624e) +}; + +static const sph_u32 T1dn[] = { + C32e(0xa5f497a5), C32e(0x8497eb84), C32e(0x99b0c799), C32e(0x8d8cf78d), + C32e(0x0d17e50d), C32e(0xbddcb7bd), C32e(0xb1c8a7b1), C32e(0x54fc3954), + C32e(0x50f0c050), C32e(0x03050403), C32e(0xa9e087a9), C32e(0x7d87ac7d), + C32e(0x192bd519), C32e(0x62a67162), C32e(0xe6319ae6), C32e(0x9ab5c39a), + C32e(0x45cf0545), C32e(0x9dbc3e9d), C32e(0x40c00940), C32e(0x8792ef87), + C32e(0x153fc515), C32e(0xeb267feb), C32e(0xc94007c9), C32e(0x0b1ded0b), + C32e(0xec2f82ec), C32e(0x67a97d67), C32e(0xfd1cbefd), C32e(0xea258aea), + C32e(0xbfda46bf), C32e(0xf702a6f7), C32e(0x96a1d396), C32e(0x5bed2d5b), + C32e(0xc25deac2), C32e(0x1c24d91c), C32e(0xaee97aae), C32e(0x6abe986a), + C32e(0x5aeed85a), C32e(0x41c3fc41), C32e(0x0206f102), C32e(0x4fd11d4f), + C32e(0x5ce4d05c), C32e(0xf407a2f4), C32e(0x345cb934), C32e(0x0818e908), + C32e(0x93aedf93), C32e(0x73954d73), C32e(0x53f5c453), C32e(0x3f41543f), + C32e(0x0c14100c), C32e(0x52f63152), C32e(0x65af8c65), C32e(0x5ee2215e), + C32e(0x28786028), C32e(0xa1f86ea1), C32e(0x0f11140f), C32e(0xb5c45eb5), + C32e(0x091b1c09), C32e(0x365a4836), C32e(0x9bb6369b), C32e(0x3d47a53d), + C32e(0x266a8126), C32e(0x69bb9c69), C32e(0xcd4cfecd), C32e(0x9fbacf9f), + C32e(0x1b2d241b), C32e(0x9eb93a9e), C32e(0x749cb074), C32e(0x2e72682e), + C32e(0x2d776c2d), C32e(0xb2cda3b2), C32e(0xee2973ee), C32e(0xfb16b6fb), + C32e(0xf60153f6), C32e(0x4dd7ec4d), C32e(0x61a37561), C32e(0xce49face), + C32e(0x7b8da47b), C32e(0x3e42a13e), C32e(0x7193bc71), C32e(0x97a22697), + C32e(0xf50457f5), C32e(0x68b86968), C32e(0x00000000), C32e(0x2c74992c), + C32e(0x60a08060), C32e(0x1f21dd1f), C32e(0xc843f2c8), C32e(0xed2c77ed), + C32e(0xbed9b3be), C32e(0x46ca0146), C32e(0xd970ced9), C32e(0x4bdde44b), + C32e(0xde7933de), C32e(0xd4672bd4), C32e(0xe8237be8), C32e(0x4ade114a), + C32e(0x6bbd6d6b), C32e(0x2a7e912a), C32e(0xe5349ee5), C32e(0x163ac116), + C32e(0xc55417c5), C32e(0xd7622fd7), C32e(0x55ffcc55), C32e(0x94a72294), + C32e(0xcf4a0fcf), C32e(0x1030c910), C32e(0x060a0806), C32e(0x8198e781), + C32e(0xf00b5bf0), C32e(0x44ccf044), C32e(0xbad54aba), C32e(0xe33e96e3), + C32e(0xf30e5ff3), C32e(0xfe19bafe), C32e(0xc05b1bc0), C32e(0x8a850a8a), + C32e(0xadec7ead), C32e(0xbcdf42bc), C32e(0x48d8e048), C32e(0x040cf904), + C32e(0xdf7ac6df), C32e(0xc158eec1), C32e(0x759f4575), C32e(0x63a58463), + C32e(0x30504030), C32e(0x1a2ed11a), C32e(0x0e12e10e), C32e(0x6db7656d), + C32e(0x4cd4194c), C32e(0x143c3014), C32e(0x355f4c35), C32e(0x2f719d2f), + C32e(0xe13867e1), C32e(0xa2fd6aa2), C32e(0xcc4f0bcc), C32e(0x394b5c39), + C32e(0x57f93d57), C32e(0xf20daaf2), C32e(0x829de382), C32e(0x47c9f447), + C32e(0xacef8bac), C32e(0xe7326fe7), C32e(0x2b7d642b), C32e(0x95a4d795), + C32e(0xa0fb9ba0), C32e(0x98b33298), C32e(0xd16827d1), C32e(0x7f815d7f), + C32e(0x66aa8866), C32e(0x7e82a87e), C32e(0xabe676ab), C32e(0x839e1683), + C32e(0xca4503ca), C32e(0x297b9529), C32e(0xd36ed6d3), C32e(0x3c44503c), + C32e(0x798b5579), C32e(0xe23d63e2), C32e(0x1d272c1d), C32e(0x769a4176), + C32e(0x3b4dad3b), C32e(0x56fac856), C32e(0x4ed2e84e), C32e(0x1e22281e), + C32e(0xdb763fdb), C32e(0x0a1e180a), C32e(0x6cb4906c), C32e(0xe4376be4), + C32e(0x5de7255d), C32e(0x6eb2616e), C32e(0xef2a86ef), C32e(0xa6f193a6), + C32e(0xa8e372a8), C32e(0xa4f762a4), C32e(0x3759bd37), C32e(0x8b86ff8b), + C32e(0x3256b132), C32e(0x43c50d43), C32e(0x59ebdc59), C32e(0xb7c2afb7), + C32e(0x8c8f028c), C32e(0x64ac7964), C32e(0xd26d23d2), C32e(0xe03b92e0), + C32e(0xb4c7abb4), C32e(0xfa1543fa), C32e(0x0709fd07), C32e(0x256f8525), + C32e(0xafea8faf), C32e(0x8e89f38e), C32e(0xe9208ee9), C32e(0x18282018), + C32e(0xd564ded5), C32e(0x8883fb88), C32e(0x6fb1946f), C32e(0x7296b872), + C32e(0x246c7024), C32e(0xf108aef1), C32e(0xc752e6c7), C32e(0x51f33551), + C32e(0x23658d23), C32e(0x7c84597c), C32e(0x9cbfcb9c), C32e(0x21637c21), + C32e(0xdd7c37dd), C32e(0xdc7fc2dc), C32e(0x86911a86), C32e(0x85941e85), + C32e(0x90abdb90), C32e(0x42c6f842), C32e(0xc457e2c4), C32e(0xaae583aa), + C32e(0xd8733bd8), C32e(0x050f0c05), C32e(0x0103f501), C32e(0x12363812), + C32e(0xa3fe9fa3), C32e(0x5fe1d45f), C32e(0xf91047f9), C32e(0xd06bd2d0), + C32e(0x91a82e91), C32e(0x58e82958), C32e(0x27697427), C32e(0xb9d04eb9), + C32e(0x3848a938), C32e(0x1335cd13), C32e(0xb3ce56b3), C32e(0x33554433), + C32e(0xbbd6bfbb), C32e(0x70904970), C32e(0x89800e89), C32e(0xa7f266a7), + C32e(0xb6c15ab6), C32e(0x22667822), C32e(0x92ad2a92), C32e(0x20608920), + C32e(0x49db1549), C32e(0xff1a4fff), C32e(0x7888a078), C32e(0x7a8e517a), + C32e(0x8f8a068f), C32e(0xf813b2f8), C32e(0x809b1280), C32e(0x17393417), + C32e(0xda75cada), C32e(0x3153b531), C32e(0xc65113c6), C32e(0xb8d3bbb8), + C32e(0xc35e1fc3), C32e(0xb0cb52b0), C32e(0x7799b477), C32e(0x11333c11), + C32e(0xcb46f6cb), C32e(0xfc1f4bfc), C32e(0xd661dad6), C32e(0x3a4e583a) +}; + +static const sph_u32 T2up[] = { + C32e(0xa5c6c632), C32e(0x84f8f86f), C32e(0x99eeee5e), C32e(0x8df6f67a), + C32e(0x0dffffe8), C32e(0xbdd6d60a), C32e(0xb1dede16), C32e(0x5491916d), + C32e(0x50606090), C32e(0x03020207), C32e(0xa9cece2e), C32e(0x7d5656d1), + C32e(0x19e7e7cc), C32e(0x62b5b513), C32e(0xe64d4d7c), C32e(0x9aecec59), + C32e(0x458f8f40), C32e(0x9d1f1fa3), C32e(0x40898949), C32e(0x87fafa68), + C32e(0x15efefd0), C32e(0xebb2b294), C32e(0xc98e8ece), C32e(0x0bfbfbe6), + C32e(0xec41416e), C32e(0x67b3b31a), C32e(0xfd5f5f43), C32e(0xea454560), + C32e(0xbf2323f9), C32e(0xf7535351), C32e(0x96e4e445), C32e(0x5b9b9b76), + C32e(0xc2757528), C32e(0x1ce1e1c5), C32e(0xae3d3dd4), C32e(0x6a4c4cf2), + C32e(0x5a6c6c82), C32e(0x417e7ebd), C32e(0x02f5f5f3), C32e(0x4f838352), + C32e(0x5c68688c), C32e(0xf4515156), C32e(0x34d1d18d), C32e(0x08f9f9e1), + C32e(0x93e2e24c), C32e(0x73abab3e), C32e(0x53626297), C32e(0x3f2a2a6b), + C32e(0x0c08081c), C32e(0x52959563), C32e(0x654646e9), C32e(0x5e9d9d7f), + C32e(0x28303048), C32e(0xa13737cf), C32e(0x0f0a0a1b), C32e(0xb52f2feb), + C32e(0x090e0e15), C32e(0x3624247e), C32e(0x9b1b1bad), C32e(0x3ddfdf98), + C32e(0x26cdcda7), C32e(0x694e4ef5), C32e(0xcd7f7f33), C32e(0x9feaea50), + C32e(0x1b12123f), C32e(0x9e1d1da4), C32e(0x745858c4), C32e(0x2e343446), + C32e(0x2d363641), C32e(0xb2dcdc11), C32e(0xeeb4b49d), C32e(0xfb5b5b4d), + C32e(0xf6a4a4a5), C32e(0x4d7676a1), C32e(0x61b7b714), C32e(0xce7d7d34), + C32e(0x7b5252df), C32e(0x3edddd9f), C32e(0x715e5ecd), C32e(0x971313b1), + C32e(0xf5a6a6a2), C32e(0x68b9b901), C32e(0x00000000), C32e(0x2cc1c1b5), + C32e(0x604040e0), C32e(0x1fe3e3c2), C32e(0xc879793a), C32e(0xedb6b69a), + C32e(0xbed4d40d), C32e(0x468d8d47), C32e(0xd9676717), C32e(0x4b7272af), + C32e(0xde9494ed), C32e(0xd49898ff), C32e(0xe8b0b093), C32e(0x4a85855b), + C32e(0x6bbbbb06), C32e(0x2ac5c5bb), C32e(0xe54f4f7b), C32e(0x16ededd7), + C32e(0xc58686d2), C32e(0xd79a9af8), C32e(0x55666699), C32e(0x941111b6), + C32e(0xcf8a8ac0), C32e(0x10e9e9d9), C32e(0x0604040e), C32e(0x81fefe66), + C32e(0xf0a0a0ab), C32e(0x447878b4), C32e(0xba2525f0), C32e(0xe34b4b75), + C32e(0xf3a2a2ac), C32e(0xfe5d5d44), C32e(0xc08080db), C32e(0x8a050580), + C32e(0xad3f3fd3), C32e(0xbc2121fe), C32e(0x487070a8), C32e(0x04f1f1fd), + C32e(0xdf636319), C32e(0xc177772f), C32e(0x75afaf30), C32e(0x634242e7), + C32e(0x30202070), C32e(0x1ae5e5cb), C32e(0x0efdfdef), C32e(0x6dbfbf08), + C32e(0x4c818155), C32e(0x14181824), C32e(0x35262679), C32e(0x2fc3c3b2), + C32e(0xe1bebe86), C32e(0xa23535c8), C32e(0xcc8888c7), C32e(0x392e2e65), + C32e(0x5793936a), C32e(0xf2555558), C32e(0x82fcfc61), C32e(0x477a7ab3), + C32e(0xacc8c827), C32e(0xe7baba88), C32e(0x2b32324f), C32e(0x95e6e642), + C32e(0xa0c0c03b), C32e(0x981919aa), C32e(0xd19e9ef6), C32e(0x7fa3a322), + C32e(0x664444ee), C32e(0x7e5454d6), C32e(0xab3b3bdd), C32e(0x830b0b95), + C32e(0xca8c8cc9), C32e(0x29c7c7bc), C32e(0xd36b6b05), C32e(0x3c28286c), + C32e(0x79a7a72c), C32e(0xe2bcbc81), C32e(0x1d161631), C32e(0x76adad37), + C32e(0x3bdbdb96), C32e(0x5664649e), C32e(0x4e7474a6), C32e(0x1e141436), + C32e(0xdb9292e4), C32e(0x0a0c0c12), C32e(0x6c4848fc), C32e(0xe4b8b88f), + C32e(0x5d9f9f78), C32e(0x6ebdbd0f), C32e(0xef434369), C32e(0xa6c4c435), + C32e(0xa83939da), C32e(0xa43131c6), C32e(0x37d3d38a), C32e(0x8bf2f274), + C32e(0x32d5d583), C32e(0x438b8b4e), C32e(0x596e6e85), C32e(0xb7dada18), + C32e(0x8c01018e), C32e(0x64b1b11d), C32e(0xd29c9cf1), C32e(0xe0494972), + C32e(0xb4d8d81f), C32e(0xfaacacb9), C32e(0x07f3f3fa), C32e(0x25cfcfa0), + C32e(0xafcaca20), C32e(0x8ef4f47d), C32e(0xe9474767), C32e(0x18101038), + C32e(0xd56f6f0b), C32e(0x88f0f073), C32e(0x6f4a4afb), C32e(0x725c5cca), + C32e(0x24383854), C32e(0xf157575f), C32e(0xc7737321), C32e(0x51979764), + C32e(0x23cbcbae), C32e(0x7ca1a125), C32e(0x9ce8e857), C32e(0x213e3e5d), + C32e(0xdd9696ea), C32e(0xdc61611e), C32e(0x860d0d9c), C32e(0x850f0f9b), + C32e(0x90e0e04b), C32e(0x427c7cba), C32e(0xc4717126), C32e(0xaacccc29), + C32e(0xd89090e3), C32e(0x05060609), C32e(0x01f7f7f4), C32e(0x121c1c2a), + C32e(0xa3c2c23c), C32e(0x5f6a6a8b), C32e(0xf9aeaebe), C32e(0xd0696902), + C32e(0x911717bf), C32e(0x58999971), C32e(0x273a3a53), C32e(0xb92727f7), + C32e(0x38d9d991), C32e(0x13ebebde), C32e(0xb32b2be5), C32e(0x33222277), + C32e(0xbbd2d204), C32e(0x70a9a939), C32e(0x89070787), C32e(0xa73333c1), + C32e(0xb62d2dec), C32e(0x223c3c5a), C32e(0x921515b8), C32e(0x20c9c9a9), + C32e(0x4987875c), C32e(0xffaaaab0), C32e(0x785050d8), C32e(0x7aa5a52b), + C32e(0x8f030389), C32e(0xf859594a), C32e(0x80090992), C32e(0x171a1a23), + C32e(0xda656510), C32e(0x31d7d784), C32e(0xc68484d5), C32e(0xb8d0d003), + C32e(0xc38282dc), C32e(0xb02929e2), C32e(0x775a5ac3), C32e(0x111e1e2d), + C32e(0xcb7b7b3d), C32e(0xfca8a8b7), C32e(0xd66d6d0c), C32e(0x3a2c2c62) +}; + +static const sph_u32 T2dn[] = { + C32e(0xf4a5f497), C32e(0x978497eb), C32e(0xb099b0c7), C32e(0x8c8d8cf7), + C32e(0x170d17e5), C32e(0xdcbddcb7), C32e(0xc8b1c8a7), C32e(0xfc54fc39), + C32e(0xf050f0c0), C32e(0x05030504), C32e(0xe0a9e087), C32e(0x877d87ac), + C32e(0x2b192bd5), C32e(0xa662a671), C32e(0x31e6319a), C32e(0xb59ab5c3), + C32e(0xcf45cf05), C32e(0xbc9dbc3e), C32e(0xc040c009), C32e(0x928792ef), + C32e(0x3f153fc5), C32e(0x26eb267f), C32e(0x40c94007), C32e(0x1d0b1ded), + C32e(0x2fec2f82), C32e(0xa967a97d), C32e(0x1cfd1cbe), C32e(0x25ea258a), + C32e(0xdabfda46), C32e(0x02f702a6), C32e(0xa196a1d3), C32e(0xed5bed2d), + C32e(0x5dc25dea), C32e(0x241c24d9), C32e(0xe9aee97a), C32e(0xbe6abe98), + C32e(0xee5aeed8), C32e(0xc341c3fc), C32e(0x060206f1), C32e(0xd14fd11d), + C32e(0xe45ce4d0), C32e(0x07f407a2), C32e(0x5c345cb9), C32e(0x180818e9), + C32e(0xae93aedf), C32e(0x9573954d), C32e(0xf553f5c4), C32e(0x413f4154), + C32e(0x140c1410), C32e(0xf652f631), C32e(0xaf65af8c), C32e(0xe25ee221), + C32e(0x78287860), C32e(0xf8a1f86e), C32e(0x110f1114), C32e(0xc4b5c45e), + C32e(0x1b091b1c), C32e(0x5a365a48), C32e(0xb69bb636), C32e(0x473d47a5), + C32e(0x6a266a81), C32e(0xbb69bb9c), C32e(0x4ccd4cfe), C32e(0xba9fbacf), + C32e(0x2d1b2d24), C32e(0xb99eb93a), C32e(0x9c749cb0), C32e(0x722e7268), + C32e(0x772d776c), C32e(0xcdb2cda3), C32e(0x29ee2973), C32e(0x16fb16b6), + C32e(0x01f60153), C32e(0xd74dd7ec), C32e(0xa361a375), C32e(0x49ce49fa), + C32e(0x8d7b8da4), C32e(0x423e42a1), C32e(0x937193bc), C32e(0xa297a226), + C32e(0x04f50457), C32e(0xb868b869), C32e(0x00000000), C32e(0x742c7499), + C32e(0xa060a080), C32e(0x211f21dd), C32e(0x43c843f2), C32e(0x2ced2c77), + C32e(0xd9bed9b3), C32e(0xca46ca01), C32e(0x70d970ce), C32e(0xdd4bdde4), + C32e(0x79de7933), C32e(0x67d4672b), C32e(0x23e8237b), C32e(0xde4ade11), + C32e(0xbd6bbd6d), C32e(0x7e2a7e91), C32e(0x34e5349e), C32e(0x3a163ac1), + C32e(0x54c55417), C32e(0x62d7622f), C32e(0xff55ffcc), C32e(0xa794a722), + C32e(0x4acf4a0f), C32e(0x301030c9), C32e(0x0a060a08), C32e(0x988198e7), + C32e(0x0bf00b5b), C32e(0xcc44ccf0), C32e(0xd5bad54a), C32e(0x3ee33e96), + C32e(0x0ef30e5f), C32e(0x19fe19ba), C32e(0x5bc05b1b), C32e(0x858a850a), + C32e(0xecadec7e), C32e(0xdfbcdf42), C32e(0xd848d8e0), C32e(0x0c040cf9), + C32e(0x7adf7ac6), C32e(0x58c158ee), C32e(0x9f759f45), C32e(0xa563a584), + C32e(0x50305040), C32e(0x2e1a2ed1), C32e(0x120e12e1), C32e(0xb76db765), + C32e(0xd44cd419), C32e(0x3c143c30), C32e(0x5f355f4c), C32e(0x712f719d), + C32e(0x38e13867), C32e(0xfda2fd6a), C32e(0x4fcc4f0b), C32e(0x4b394b5c), + C32e(0xf957f93d), C32e(0x0df20daa), C32e(0x9d829de3), C32e(0xc947c9f4), + C32e(0xefacef8b), C32e(0x32e7326f), C32e(0x7d2b7d64), C32e(0xa495a4d7), + C32e(0xfba0fb9b), C32e(0xb398b332), C32e(0x68d16827), C32e(0x817f815d), + C32e(0xaa66aa88), C32e(0x827e82a8), C32e(0xe6abe676), C32e(0x9e839e16), + C32e(0x45ca4503), C32e(0x7b297b95), C32e(0x6ed36ed6), C32e(0x443c4450), + C32e(0x8b798b55), C32e(0x3de23d63), C32e(0x271d272c), C32e(0x9a769a41), + C32e(0x4d3b4dad), C32e(0xfa56fac8), C32e(0xd24ed2e8), C32e(0x221e2228), + C32e(0x76db763f), C32e(0x1e0a1e18), C32e(0xb46cb490), C32e(0x37e4376b), + C32e(0xe75de725), C32e(0xb26eb261), C32e(0x2aef2a86), C32e(0xf1a6f193), + C32e(0xe3a8e372), C32e(0xf7a4f762), C32e(0x593759bd), C32e(0x868b86ff), + C32e(0x563256b1), C32e(0xc543c50d), C32e(0xeb59ebdc), C32e(0xc2b7c2af), + C32e(0x8f8c8f02), C32e(0xac64ac79), C32e(0x6dd26d23), C32e(0x3be03b92), + C32e(0xc7b4c7ab), C32e(0x15fa1543), C32e(0x090709fd), C32e(0x6f256f85), + C32e(0xeaafea8f), C32e(0x898e89f3), C32e(0x20e9208e), C32e(0x28182820), + C32e(0x64d564de), C32e(0x838883fb), C32e(0xb16fb194), C32e(0x967296b8), + C32e(0x6c246c70), C32e(0x08f108ae), C32e(0x52c752e6), C32e(0xf351f335), + C32e(0x6523658d), C32e(0x847c8459), C32e(0xbf9cbfcb), C32e(0x6321637c), + C32e(0x7cdd7c37), C32e(0x7fdc7fc2), C32e(0x9186911a), C32e(0x9485941e), + C32e(0xab90abdb), C32e(0xc642c6f8), C32e(0x57c457e2), C32e(0xe5aae583), + C32e(0x73d8733b), C32e(0x0f050f0c), C32e(0x030103f5), C32e(0x36123638), + C32e(0xfea3fe9f), C32e(0xe15fe1d4), C32e(0x10f91047), C32e(0x6bd06bd2), + C32e(0xa891a82e), C32e(0xe858e829), C32e(0x69276974), C32e(0xd0b9d04e), + C32e(0x483848a9), C32e(0x351335cd), C32e(0xceb3ce56), C32e(0x55335544), + C32e(0xd6bbd6bf), C32e(0x90709049), C32e(0x8089800e), C32e(0xf2a7f266), + C32e(0xc1b6c15a), C32e(0x66226678), C32e(0xad92ad2a), C32e(0x60206089), + C32e(0xdb49db15), C32e(0x1aff1a4f), C32e(0x887888a0), C32e(0x8e7a8e51), + C32e(0x8a8f8a06), C32e(0x13f813b2), C32e(0x9b809b12), C32e(0x39173934), + C32e(0x75da75ca), C32e(0x533153b5), C32e(0x51c65113), C32e(0xd3b8d3bb), + C32e(0x5ec35e1f), C32e(0xcbb0cb52), C32e(0x997799b4), C32e(0x3311333c), + C32e(0x46cb46f6), C32e(0x1ffc1f4b), C32e(0x61d661da), C32e(0x4e3a4e58) +}; + +static const sph_u32 T3up[] = { + C32e(0x97a5c6c6), C32e(0xeb84f8f8), C32e(0xc799eeee), C32e(0xf78df6f6), + C32e(0xe50dffff), C32e(0xb7bdd6d6), C32e(0xa7b1dede), C32e(0x39549191), + C32e(0xc0506060), C32e(0x04030202), C32e(0x87a9cece), C32e(0xac7d5656), + C32e(0xd519e7e7), C32e(0x7162b5b5), C32e(0x9ae64d4d), C32e(0xc39aecec), + C32e(0x05458f8f), C32e(0x3e9d1f1f), C32e(0x09408989), C32e(0xef87fafa), + C32e(0xc515efef), C32e(0x7febb2b2), C32e(0x07c98e8e), C32e(0xed0bfbfb), + C32e(0x82ec4141), C32e(0x7d67b3b3), C32e(0xbefd5f5f), C32e(0x8aea4545), + C32e(0x46bf2323), C32e(0xa6f75353), C32e(0xd396e4e4), C32e(0x2d5b9b9b), + C32e(0xeac27575), C32e(0xd91ce1e1), C32e(0x7aae3d3d), C32e(0x986a4c4c), + C32e(0xd85a6c6c), C32e(0xfc417e7e), C32e(0xf102f5f5), C32e(0x1d4f8383), + C32e(0xd05c6868), C32e(0xa2f45151), C32e(0xb934d1d1), C32e(0xe908f9f9), + C32e(0xdf93e2e2), C32e(0x4d73abab), C32e(0xc4536262), C32e(0x543f2a2a), + C32e(0x100c0808), C32e(0x31529595), C32e(0x8c654646), C32e(0x215e9d9d), + C32e(0x60283030), C32e(0x6ea13737), C32e(0x140f0a0a), C32e(0x5eb52f2f), + C32e(0x1c090e0e), C32e(0x48362424), C32e(0x369b1b1b), C32e(0xa53ddfdf), + C32e(0x8126cdcd), C32e(0x9c694e4e), C32e(0xfecd7f7f), C32e(0xcf9feaea), + C32e(0x241b1212), C32e(0x3a9e1d1d), C32e(0xb0745858), C32e(0x682e3434), + C32e(0x6c2d3636), C32e(0xa3b2dcdc), C32e(0x73eeb4b4), C32e(0xb6fb5b5b), + C32e(0x53f6a4a4), C32e(0xec4d7676), C32e(0x7561b7b7), C32e(0xface7d7d), + C32e(0xa47b5252), C32e(0xa13edddd), C32e(0xbc715e5e), C32e(0x26971313), + C32e(0x57f5a6a6), C32e(0x6968b9b9), C32e(0x00000000), C32e(0x992cc1c1), + C32e(0x80604040), C32e(0xdd1fe3e3), C32e(0xf2c87979), C32e(0x77edb6b6), + C32e(0xb3bed4d4), C32e(0x01468d8d), C32e(0xced96767), C32e(0xe44b7272), + C32e(0x33de9494), C32e(0x2bd49898), C32e(0x7be8b0b0), C32e(0x114a8585), + C32e(0x6d6bbbbb), C32e(0x912ac5c5), C32e(0x9ee54f4f), C32e(0xc116eded), + C32e(0x17c58686), C32e(0x2fd79a9a), C32e(0xcc556666), C32e(0x22941111), + C32e(0x0fcf8a8a), C32e(0xc910e9e9), C32e(0x08060404), C32e(0xe781fefe), + C32e(0x5bf0a0a0), C32e(0xf0447878), C32e(0x4aba2525), C32e(0x96e34b4b), + C32e(0x5ff3a2a2), C32e(0xbafe5d5d), C32e(0x1bc08080), C32e(0x0a8a0505), + C32e(0x7ead3f3f), C32e(0x42bc2121), C32e(0xe0487070), C32e(0xf904f1f1), + C32e(0xc6df6363), C32e(0xeec17777), C32e(0x4575afaf), C32e(0x84634242), + C32e(0x40302020), C32e(0xd11ae5e5), C32e(0xe10efdfd), C32e(0x656dbfbf), + C32e(0x194c8181), C32e(0x30141818), C32e(0x4c352626), C32e(0x9d2fc3c3), + C32e(0x67e1bebe), C32e(0x6aa23535), C32e(0x0bcc8888), C32e(0x5c392e2e), + C32e(0x3d579393), C32e(0xaaf25555), C32e(0xe382fcfc), C32e(0xf4477a7a), + C32e(0x8bacc8c8), C32e(0x6fe7baba), C32e(0x642b3232), C32e(0xd795e6e6), + C32e(0x9ba0c0c0), C32e(0x32981919), C32e(0x27d19e9e), C32e(0x5d7fa3a3), + C32e(0x88664444), C32e(0xa87e5454), C32e(0x76ab3b3b), C32e(0x16830b0b), + C32e(0x03ca8c8c), C32e(0x9529c7c7), C32e(0xd6d36b6b), C32e(0x503c2828), + C32e(0x5579a7a7), C32e(0x63e2bcbc), C32e(0x2c1d1616), C32e(0x4176adad), + C32e(0xad3bdbdb), C32e(0xc8566464), C32e(0xe84e7474), C32e(0x281e1414), + C32e(0x3fdb9292), C32e(0x180a0c0c), C32e(0x906c4848), C32e(0x6be4b8b8), + C32e(0x255d9f9f), C32e(0x616ebdbd), C32e(0x86ef4343), C32e(0x93a6c4c4), + C32e(0x72a83939), C32e(0x62a43131), C32e(0xbd37d3d3), C32e(0xff8bf2f2), + C32e(0xb132d5d5), C32e(0x0d438b8b), C32e(0xdc596e6e), C32e(0xafb7dada), + C32e(0x028c0101), C32e(0x7964b1b1), C32e(0x23d29c9c), C32e(0x92e04949), + C32e(0xabb4d8d8), C32e(0x43faacac), C32e(0xfd07f3f3), C32e(0x8525cfcf), + C32e(0x8fafcaca), C32e(0xf38ef4f4), C32e(0x8ee94747), C32e(0x20181010), + C32e(0xded56f6f), C32e(0xfb88f0f0), C32e(0x946f4a4a), C32e(0xb8725c5c), + C32e(0x70243838), C32e(0xaef15757), C32e(0xe6c77373), C32e(0x35519797), + C32e(0x8d23cbcb), C32e(0x597ca1a1), C32e(0xcb9ce8e8), C32e(0x7c213e3e), + C32e(0x37dd9696), C32e(0xc2dc6161), C32e(0x1a860d0d), C32e(0x1e850f0f), + C32e(0xdb90e0e0), C32e(0xf8427c7c), C32e(0xe2c47171), C32e(0x83aacccc), + C32e(0x3bd89090), C32e(0x0c050606), C32e(0xf501f7f7), C32e(0x38121c1c), + C32e(0x9fa3c2c2), C32e(0xd45f6a6a), C32e(0x47f9aeae), C32e(0xd2d06969), + C32e(0x2e911717), C32e(0x29589999), C32e(0x74273a3a), C32e(0x4eb92727), + C32e(0xa938d9d9), C32e(0xcd13ebeb), C32e(0x56b32b2b), C32e(0x44332222), + C32e(0xbfbbd2d2), C32e(0x4970a9a9), C32e(0x0e890707), C32e(0x66a73333), + C32e(0x5ab62d2d), C32e(0x78223c3c), C32e(0x2a921515), C32e(0x8920c9c9), + C32e(0x15498787), C32e(0x4fffaaaa), C32e(0xa0785050), C32e(0x517aa5a5), + C32e(0x068f0303), C32e(0xb2f85959), C32e(0x12800909), C32e(0x34171a1a), + C32e(0xcada6565), C32e(0xb531d7d7), C32e(0x13c68484), C32e(0xbbb8d0d0), + C32e(0x1fc38282), C32e(0x52b02929), C32e(0xb4775a5a), C32e(0x3c111e1e), + C32e(0xf6cb7b7b), C32e(0x4bfca8a8), C32e(0xdad66d6d), C32e(0x583a2c2c) +}; + +static const sph_u32 T3dn[] = { + C32e(0x32f4a5f4), C32e(0x6f978497), C32e(0x5eb099b0), C32e(0x7a8c8d8c), + C32e(0xe8170d17), C32e(0x0adcbddc), C32e(0x16c8b1c8), C32e(0x6dfc54fc), + C32e(0x90f050f0), C32e(0x07050305), C32e(0x2ee0a9e0), C32e(0xd1877d87), + C32e(0xcc2b192b), C32e(0x13a662a6), C32e(0x7c31e631), C32e(0x59b59ab5), + C32e(0x40cf45cf), C32e(0xa3bc9dbc), C32e(0x49c040c0), C32e(0x68928792), + C32e(0xd03f153f), C32e(0x9426eb26), C32e(0xce40c940), C32e(0xe61d0b1d), + C32e(0x6e2fec2f), C32e(0x1aa967a9), C32e(0x431cfd1c), C32e(0x6025ea25), + C32e(0xf9dabfda), C32e(0x5102f702), C32e(0x45a196a1), C32e(0x76ed5bed), + C32e(0x285dc25d), C32e(0xc5241c24), C32e(0xd4e9aee9), C32e(0xf2be6abe), + C32e(0x82ee5aee), C32e(0xbdc341c3), C32e(0xf3060206), C32e(0x52d14fd1), + C32e(0x8ce45ce4), C32e(0x5607f407), C32e(0x8d5c345c), C32e(0xe1180818), + C32e(0x4cae93ae), C32e(0x3e957395), C32e(0x97f553f5), C32e(0x6b413f41), + C32e(0x1c140c14), C32e(0x63f652f6), C32e(0xe9af65af), C32e(0x7fe25ee2), + C32e(0x48782878), C32e(0xcff8a1f8), C32e(0x1b110f11), C32e(0xebc4b5c4), + C32e(0x151b091b), C32e(0x7e5a365a), C32e(0xadb69bb6), C32e(0x98473d47), + C32e(0xa76a266a), C32e(0xf5bb69bb), C32e(0x334ccd4c), C32e(0x50ba9fba), + C32e(0x3f2d1b2d), C32e(0xa4b99eb9), C32e(0xc49c749c), C32e(0x46722e72), + C32e(0x41772d77), C32e(0x11cdb2cd), C32e(0x9d29ee29), C32e(0x4d16fb16), + C32e(0xa501f601), C32e(0xa1d74dd7), C32e(0x14a361a3), C32e(0x3449ce49), + C32e(0xdf8d7b8d), C32e(0x9f423e42), C32e(0xcd937193), C32e(0xb1a297a2), + C32e(0xa204f504), C32e(0x01b868b8), C32e(0x00000000), C32e(0xb5742c74), + C32e(0xe0a060a0), C32e(0xc2211f21), C32e(0x3a43c843), C32e(0x9a2ced2c), + C32e(0x0dd9bed9), C32e(0x47ca46ca), C32e(0x1770d970), C32e(0xafdd4bdd), + C32e(0xed79de79), C32e(0xff67d467), C32e(0x9323e823), C32e(0x5bde4ade), + C32e(0x06bd6bbd), C32e(0xbb7e2a7e), C32e(0x7b34e534), C32e(0xd73a163a), + C32e(0xd254c554), C32e(0xf862d762), C32e(0x99ff55ff), C32e(0xb6a794a7), + C32e(0xc04acf4a), C32e(0xd9301030), C32e(0x0e0a060a), C32e(0x66988198), + C32e(0xab0bf00b), C32e(0xb4cc44cc), C32e(0xf0d5bad5), C32e(0x753ee33e), + C32e(0xac0ef30e), C32e(0x4419fe19), C32e(0xdb5bc05b), C32e(0x80858a85), + C32e(0xd3ecadec), C32e(0xfedfbcdf), C32e(0xa8d848d8), C32e(0xfd0c040c), + C32e(0x197adf7a), C32e(0x2f58c158), C32e(0x309f759f), C32e(0xe7a563a5), + C32e(0x70503050), C32e(0xcb2e1a2e), C32e(0xef120e12), C32e(0x08b76db7), + C32e(0x55d44cd4), C32e(0x243c143c), C32e(0x795f355f), C32e(0xb2712f71), + C32e(0x8638e138), C32e(0xc8fda2fd), C32e(0xc74fcc4f), C32e(0x654b394b), + C32e(0x6af957f9), C32e(0x580df20d), C32e(0x619d829d), C32e(0xb3c947c9), + C32e(0x27efacef), C32e(0x8832e732), C32e(0x4f7d2b7d), C32e(0x42a495a4), + C32e(0x3bfba0fb), C32e(0xaab398b3), C32e(0xf668d168), C32e(0x22817f81), + C32e(0xeeaa66aa), C32e(0xd6827e82), C32e(0xdde6abe6), C32e(0x959e839e), + C32e(0xc945ca45), C32e(0xbc7b297b), C32e(0x056ed36e), C32e(0x6c443c44), + C32e(0x2c8b798b), C32e(0x813de23d), C32e(0x31271d27), C32e(0x379a769a), + C32e(0x964d3b4d), C32e(0x9efa56fa), C32e(0xa6d24ed2), C32e(0x36221e22), + C32e(0xe476db76), C32e(0x121e0a1e), C32e(0xfcb46cb4), C32e(0x8f37e437), + C32e(0x78e75de7), C32e(0x0fb26eb2), C32e(0x692aef2a), C32e(0x35f1a6f1), + C32e(0xdae3a8e3), C32e(0xc6f7a4f7), C32e(0x8a593759), C32e(0x74868b86), + C32e(0x83563256), C32e(0x4ec543c5), C32e(0x85eb59eb), C32e(0x18c2b7c2), + C32e(0x8e8f8c8f), C32e(0x1dac64ac), C32e(0xf16dd26d), C32e(0x723be03b), + C32e(0x1fc7b4c7), C32e(0xb915fa15), C32e(0xfa090709), C32e(0xa06f256f), + C32e(0x20eaafea), C32e(0x7d898e89), C32e(0x6720e920), C32e(0x38281828), + C32e(0x0b64d564), C32e(0x73838883), C32e(0xfbb16fb1), C32e(0xca967296), + C32e(0x546c246c), C32e(0x5f08f108), C32e(0x2152c752), C32e(0x64f351f3), + C32e(0xae652365), C32e(0x25847c84), C32e(0x57bf9cbf), C32e(0x5d632163), + C32e(0xea7cdd7c), C32e(0x1e7fdc7f), C32e(0x9c918691), C32e(0x9b948594), + C32e(0x4bab90ab), C32e(0xbac642c6), C32e(0x2657c457), C32e(0x29e5aae5), + C32e(0xe373d873), C32e(0x090f050f), C32e(0xf4030103), C32e(0x2a361236), + C32e(0x3cfea3fe), C32e(0x8be15fe1), C32e(0xbe10f910), C32e(0x026bd06b), + C32e(0xbfa891a8), C32e(0x71e858e8), C32e(0x53692769), C32e(0xf7d0b9d0), + C32e(0x91483848), C32e(0xde351335), C32e(0xe5ceb3ce), C32e(0x77553355), + C32e(0x04d6bbd6), C32e(0x39907090), C32e(0x87808980), C32e(0xc1f2a7f2), + C32e(0xecc1b6c1), C32e(0x5a662266), C32e(0xb8ad92ad), C32e(0xa9602060), + C32e(0x5cdb49db), C32e(0xb01aff1a), C32e(0xd8887888), C32e(0x2b8e7a8e), + C32e(0x898a8f8a), C32e(0x4a13f813), C32e(0x929b809b), C32e(0x23391739), + C32e(0x1075da75), C32e(0x84533153), C32e(0xd551c651), C32e(0x03d3b8d3), + C32e(0xdc5ec35e), C32e(0xe2cbb0cb), C32e(0xc3997799), C32e(0x2d331133), + C32e(0x3d46cb46), C32e(0xb71ffc1f), C32e(0x0c61d661), C32e(0x624e3a4e) +}; + +#define DECL_STATE_SMALL \ + sph_u32 H[16]; + +#define READ_STATE_SMALL(sc) do { \ + memcpy(H, (sc)->state.narrow, sizeof H); \ + } while (0) + +#define WRITE_STATE_SMALL(sc) do { \ + memcpy((sc)->state.narrow, H, sizeof H); \ + } while (0) + +#define XCAT(x, y) XCAT_(x, y) +#define XCAT_(x, y) x ## y + +#define RSTT(d0, d1, a, b0, b1, b2, b3, b4, b5, b6, b7) do { \ + t[d0] = T0up[B32_0(a[b0])] \ + ^ T1up[B32_1(a[b1])] \ + ^ T2up[B32_2(a[b2])] \ + ^ T3up[B32_3(a[b3])] \ + ^ T0dn[B32_0(a[b4])] \ + ^ T1dn[B32_1(a[b5])] \ + ^ T2dn[B32_2(a[b6])] \ + ^ T3dn[B32_3(a[b7])]; \ + t[d1] = T0dn[B32_0(a[b0])] \ + ^ T1dn[B32_1(a[b1])] \ + ^ T2dn[B32_2(a[b2])] \ + ^ T3dn[B32_3(a[b3])] \ + ^ T0up[B32_0(a[b4])] \ + ^ T1up[B32_1(a[b5])] \ + ^ T2up[B32_2(a[b6])] \ + ^ T3up[B32_3(a[b7])]; \ + } while (0) + +#define ROUND_SMALL_P(a, r) do { \ + sph_u32 t[16]; \ + a[0x0] ^= PC32up(0x00, r); \ + a[0x1] ^= PC32dn(0x00, r); \ + a[0x2] ^= PC32up(0x10, r); \ + a[0x3] ^= PC32dn(0x10, r); \ + a[0x4] ^= PC32up(0x20, r); \ + a[0x5] ^= PC32dn(0x20, r); \ + a[0x6] ^= PC32up(0x30, r); \ + a[0x7] ^= PC32dn(0x30, r); \ + a[0x8] ^= PC32up(0x40, r); \ + a[0x9] ^= PC32dn(0x40, r); \ + a[0xA] ^= PC32up(0x50, r); \ + a[0xB] ^= PC32dn(0x50, r); \ + a[0xC] ^= PC32up(0x60, r); \ + a[0xD] ^= PC32dn(0x60, r); \ + a[0xE] ^= PC32up(0x70, r); \ + a[0xF] ^= PC32dn(0x70, r); \ + RSTT(0x0, 0x1, a, 0x0, 0x2, 0x4, 0x6, 0x9, 0xB, 0xD, 0xF); \ + RSTT(0x2, 0x3, a, 0x2, 0x4, 0x6, 0x8, 0xB, 0xD, 0xF, 0x1); \ + RSTT(0x4, 0x5, a, 0x4, 0x6, 0x8, 0xA, 0xD, 0xF, 0x1, 0x3); \ + RSTT(0x6, 0x7, a, 0x6, 0x8, 0xA, 0xC, 0xF, 0x1, 0x3, 0x5); \ + RSTT(0x8, 0x9, a, 0x8, 0xA, 0xC, 0xE, 0x1, 0x3, 0x5, 0x7); \ + RSTT(0xA, 0xB, a, 0xA, 0xC, 0xE, 0x0, 0x3, 0x5, 0x7, 0x9); \ + RSTT(0xC, 0xD, a, 0xC, 0xE, 0x0, 0x2, 0x5, 0x7, 0x9, 0xB); \ + RSTT(0xE, 0xF, a, 0xE, 0x0, 0x2, 0x4, 0x7, 0x9, 0xB, 0xD); \ + memcpy(a, t, sizeof t); \ + } while (0) + +#define ROUND_SMALL_Q(a, r) do { \ + sph_u32 t[16]; \ + a[0x0] ^= QC32up(0x00, r); \ + a[0x1] ^= QC32dn(0x00, r); \ + a[0x2] ^= QC32up(0x10, r); \ + a[0x3] ^= QC32dn(0x10, r); \ + a[0x4] ^= QC32up(0x20, r); \ + a[0x5] ^= QC32dn(0x20, r); \ + a[0x6] ^= QC32up(0x30, r); \ + a[0x7] ^= QC32dn(0x30, r); \ + a[0x8] ^= QC32up(0x40, r); \ + a[0x9] ^= QC32dn(0x40, r); \ + a[0xA] ^= QC32up(0x50, r); \ + a[0xB] ^= QC32dn(0x50, r); \ + a[0xC] ^= QC32up(0x60, r); \ + a[0xD] ^= QC32dn(0x60, r); \ + a[0xE] ^= QC32up(0x70, r); \ + a[0xF] ^= QC32dn(0x70, r); \ + RSTT(0x0, 0x1, a, 0x2, 0x6, 0xA, 0xE, 0x1, 0x5, 0x9, 0xD); \ + RSTT(0x2, 0x3, a, 0x4, 0x8, 0xC, 0x0, 0x3, 0x7, 0xB, 0xF); \ + RSTT(0x4, 0x5, a, 0x6, 0xA, 0xE, 0x2, 0x5, 0x9, 0xD, 0x1); \ + RSTT(0x6, 0x7, a, 0x8, 0xC, 0x0, 0x4, 0x7, 0xB, 0xF, 0x3); \ + RSTT(0x8, 0x9, a, 0xA, 0xE, 0x2, 0x6, 0x9, 0xD, 0x1, 0x5); \ + RSTT(0xA, 0xB, a, 0xC, 0x0, 0x4, 0x8, 0xB, 0xF, 0x3, 0x7); \ + RSTT(0xC, 0xD, a, 0xE, 0x2, 0x6, 0xA, 0xD, 0x1, 0x5, 0x9); \ + RSTT(0xE, 0xF, a, 0x0, 0x4, 0x8, 0xC, 0xF, 0x3, 0x7, 0xB); \ + memcpy(a, t, sizeof t); \ + } while (0) + +#if SPH_SMALL_FOOTPRINT_GROESTL + +#define PERM_SMALL_P(a) do { \ + int r; \ + for (r = 0; r < 10; r ++) \ + ROUND_SMALL_P(a, r); \ + } while (0) + +#define PERM_SMALL_Q(a) do { \ + int r; \ + for (r = 0; r < 10; r ++) \ + ROUND_SMALL_Q(a, r); \ + } while (0) + +#else + +#define PERM_SMALL_P(a) do { \ + int r; \ + for (r = 0; r < 10; r += 2) { \ + ROUND_SMALL_P(a, r + 0); \ + ROUND_SMALL_P(a, r + 1); \ + } \ + } while (0) + +#define PERM_SMALL_Q(a) do { \ + int r; \ + for (r = 0; r < 10; r += 2) { \ + ROUND_SMALL_Q(a, r + 0); \ + ROUND_SMALL_Q(a, r + 1); \ + } \ + } while (0) + +#endif + +#define COMPRESS_SMALL do { \ + sph_u32 g[16], m[16]; \ + size_t u; \ + for (u = 0; u < 16; u ++) { \ + m[u] = dec32e_aligned(buf + (u << 2)); \ + g[u] = m[u] ^ H[u]; \ + } \ + PERM_SMALL_P(g); \ + PERM_SMALL_Q(m); \ + for (u = 0; u < 16; u ++) \ + H[u] ^= g[u] ^ m[u]; \ + } while (0) + +#define FINAL_SMALL do { \ + sph_u32 x[16]; \ + size_t u; \ + memcpy(x, H, sizeof x); \ + PERM_SMALL_P(x); \ + for (u = 0; u < 16; u ++) \ + H[u] ^= x[u]; \ + } while (0) + +#define DECL_STATE_BIG \ + sph_u32 H[32]; + +#define READ_STATE_BIG(sc) do { \ + memcpy(H, (sc)->state.narrow, sizeof H); \ + } while (0) + +#define WRITE_STATE_BIG(sc) do { \ + memcpy((sc)->state.narrow, H, sizeof H); \ + } while (0) + +#if SPH_SMALL_FOOTPRINT_GROESTL + +#define RBTT(d0, d1, a, b0, b1, b2, b3, b4, b5, b6, b7) do { \ + sph_u32 fu2 = T0up[B32_2(a[b2])]; \ + sph_u32 fd2 = T0dn[B32_2(a[b2])]; \ + sph_u32 fu3 = T1up[B32_3(a[b3])]; \ + sph_u32 fd3 = T1dn[B32_3(a[b3])]; \ + sph_u32 fu6 = T0up[B32_2(a[b6])]; \ + sph_u32 fd6 = T0dn[B32_2(a[b6])]; \ + sph_u32 fu7 = T1up[B32_3(a[b7])]; \ + sph_u32 fd7 = T1dn[B32_3(a[b7])]; \ + t[d0] = T0up[B32_0(a[b0])] \ + ^ T1up[B32_1(a[b1])] \ + ^ R32u(fu2, fd2) \ + ^ R32u(fu3, fd3) \ + ^ T0dn[B32_0(a[b4])] \ + ^ T1dn[B32_1(a[b5])] \ + ^ R32d(fu6, fd6) \ + ^ R32d(fu7, fd7); \ + t[d1] = T0dn[B32_0(a[b0])] \ + ^ T1dn[B32_1(a[b1])] \ + ^ R32d(fu2, fd2) \ + ^ R32d(fu3, fd3) \ + ^ T0up[B32_0(a[b4])] \ + ^ T1up[B32_1(a[b5])] \ + ^ R32u(fu6, fd6) \ + ^ R32u(fu7, fd7); \ + } while (0) + +#else + +#define RBTT(d0, d1, a, b0, b1, b2, b3, b4, b5, b6, b7) do { \ + t[d0] = T0up[B32_0(a[b0])] \ + ^ T1up[B32_1(a[b1])] \ + ^ T2up[B32_2(a[b2])] \ + ^ T3up[B32_3(a[b3])] \ + ^ T0dn[B32_0(a[b4])] \ + ^ T1dn[B32_1(a[b5])] \ + ^ T2dn[B32_2(a[b6])] \ + ^ T3dn[B32_3(a[b7])]; \ + t[d1] = T0dn[B32_0(a[b0])] \ + ^ T1dn[B32_1(a[b1])] \ + ^ T2dn[B32_2(a[b2])] \ + ^ T3dn[B32_3(a[b3])] \ + ^ T0up[B32_0(a[b4])] \ + ^ T1up[B32_1(a[b5])] \ + ^ T2up[B32_2(a[b6])] \ + ^ T3up[B32_3(a[b7])]; \ + } while (0) + +#endif + +#if SPH_SMALL_FOOTPRINT_GROESTL + +#define ROUND_BIG_P(a, r) do { \ + sph_u32 t[32]; \ + size_t u; \ + a[0x00] ^= PC32up(0x00, r); \ + a[0x01] ^= PC32dn(0x00, r); \ + a[0x02] ^= PC32up(0x10, r); \ + a[0x03] ^= PC32dn(0x10, r); \ + a[0x04] ^= PC32up(0x20, r); \ + a[0x05] ^= PC32dn(0x20, r); \ + a[0x06] ^= PC32up(0x30, r); \ + a[0x07] ^= PC32dn(0x30, r); \ + a[0x08] ^= PC32up(0x40, r); \ + a[0x09] ^= PC32dn(0x40, r); \ + a[0x0A] ^= PC32up(0x50, r); \ + a[0x0B] ^= PC32dn(0x50, r); \ + a[0x0C] ^= PC32up(0x60, r); \ + a[0x0D] ^= PC32dn(0x60, r); \ + a[0x0E] ^= PC32up(0x70, r); \ + a[0x0F] ^= PC32dn(0x70, r); \ + a[0x10] ^= PC32up(0x80, r); \ + a[0x11] ^= PC32dn(0x80, r); \ + a[0x12] ^= PC32up(0x90, r); \ + a[0x13] ^= PC32dn(0x90, r); \ + a[0x14] ^= PC32up(0xA0, r); \ + a[0x15] ^= PC32dn(0xA0, r); \ + a[0x16] ^= PC32up(0xB0, r); \ + a[0x17] ^= PC32dn(0xB0, r); \ + a[0x18] ^= PC32up(0xC0, r); \ + a[0x19] ^= PC32dn(0xC0, r); \ + a[0x1A] ^= PC32up(0xD0, r); \ + a[0x1B] ^= PC32dn(0xD0, r); \ + a[0x1C] ^= PC32up(0xE0, r); \ + a[0x1D] ^= PC32dn(0xE0, r); \ + a[0x1E] ^= PC32up(0xF0, r); \ + a[0x1F] ^= PC32dn(0xF0, r); \ + for (u = 0; u < 32; u += 8) { \ + RBTT(u + 0x00, (u + 0x01) & 0x1F, a, \ + u + 0x00, (u + 0x02) & 0x1F, \ + (u + 0x04) & 0x1F, (u + 0x06) & 0x1F, \ + (u + 0x09) & 0x1F, (u + 0x0B) & 0x1F, \ + (u + 0x0D) & 0x1F, (u + 0x17) & 0x1F); \ + RBTT(u + 0x02, (u + 0x03) & 0x1F, a, \ + u + 0x02, (u + 0x04) & 0x1F, \ + (u + 0x06) & 0x1F, (u + 0x08) & 0x1F, \ + (u + 0x0B) & 0x1F, (u + 0x0D) & 0x1F, \ + (u + 0x0F) & 0x1F, (u + 0x19) & 0x1F); \ + RBTT(u + 0x04, (u + 0x05) & 0x1F, a, \ + u + 0x04, (u + 0x06) & 0x1F, \ + (u + 0x08) & 0x1F, (u + 0x0A) & 0x1F, \ + (u + 0x0D) & 0x1F, (u + 0x0F) & 0x1F, \ + (u + 0x11) & 0x1F, (u + 0x1B) & 0x1F); \ + RBTT(u + 0x06, (u + 0x07) & 0x1F, a, \ + u + 0x06, (u + 0x08) & 0x1F, \ + (u + 0x0A) & 0x1F, (u + 0x0C) & 0x1F, \ + (u + 0x0F) & 0x1F, (u + 0x11) & 0x1F, \ + (u + 0x13) & 0x1F, (u + 0x1D) & 0x1F); \ + } \ + memcpy(a, t, sizeof t); \ + } while (0) + +#define ROUND_BIG_Q(a, r) do { \ + sph_u32 t[32]; \ + size_t u; \ + a[0x00] ^= QC32up(0x00, r); \ + a[0x01] ^= QC32dn(0x00, r); \ + a[0x02] ^= QC32up(0x10, r); \ + a[0x03] ^= QC32dn(0x10, r); \ + a[0x04] ^= QC32up(0x20, r); \ + a[0x05] ^= QC32dn(0x20, r); \ + a[0x06] ^= QC32up(0x30, r); \ + a[0x07] ^= QC32dn(0x30, r); \ + a[0x08] ^= QC32up(0x40, r); \ + a[0x09] ^= QC32dn(0x40, r); \ + a[0x0A] ^= QC32up(0x50, r); \ + a[0x0B] ^= QC32dn(0x50, r); \ + a[0x0C] ^= QC32up(0x60, r); \ + a[0x0D] ^= QC32dn(0x60, r); \ + a[0x0E] ^= QC32up(0x70, r); \ + a[0x0F] ^= QC32dn(0x70, r); \ + a[0x10] ^= QC32up(0x80, r); \ + a[0x11] ^= QC32dn(0x80, r); \ + a[0x12] ^= QC32up(0x90, r); \ + a[0x13] ^= QC32dn(0x90, r); \ + a[0x14] ^= QC32up(0xA0, r); \ + a[0x15] ^= QC32dn(0xA0, r); \ + a[0x16] ^= QC32up(0xB0, r); \ + a[0x17] ^= QC32dn(0xB0, r); \ + a[0x18] ^= QC32up(0xC0, r); \ + a[0x19] ^= QC32dn(0xC0, r); \ + a[0x1A] ^= QC32up(0xD0, r); \ + a[0x1B] ^= QC32dn(0xD0, r); \ + a[0x1C] ^= QC32up(0xE0, r); \ + a[0x1D] ^= QC32dn(0xE0, r); \ + a[0x1E] ^= QC32up(0xF0, r); \ + a[0x1F] ^= QC32dn(0xF0, r); \ + for (u = 0; u < 32; u += 8) { \ + RBTT(u + 0x00, (u + 0x01) & 0x1F, a, \ + (u + 0x02) & 0x1F, (u + 0x06) & 0x1F, \ + (u + 0x0A) & 0x1F, (u + 0x16) & 0x1F, \ + (u + 0x01) & 0x1F, (u + 0x05) & 0x1F, \ + (u + 0x09) & 0x1F, (u + 0x0D) & 0x1F); \ + RBTT(u + 0x02, (u + 0x03) & 0x1F, a, \ + (u + 0x04) & 0x1F, (u + 0x08) & 0x1F, \ + (u + 0x0C) & 0x1F, (u + 0x18) & 0x1F, \ + (u + 0x03) & 0x1F, (u + 0x07) & 0x1F, \ + (u + 0x0B) & 0x1F, (u + 0x0F) & 0x1F); \ + RBTT(u + 0x04, (u + 0x05) & 0x1F, a, \ + (u + 0x06) & 0x1F, (u + 0x0A) & 0x1F, \ + (u + 0x0E) & 0x1F, (u + 0x1A) & 0x1F, \ + (u + 0x05) & 0x1F, (u + 0x09) & 0x1F, \ + (u + 0x0D) & 0x1F, (u + 0x11) & 0x1F); \ + RBTT(u + 0x06, (u + 0x07) & 0x1F, a, \ + (u + 0x08) & 0x1F, (u + 0x0C) & 0x1F, \ + (u + 0x10) & 0x1F, (u + 0x1C) & 0x1F, \ + (u + 0x07) & 0x1F, (u + 0x0B) & 0x1F, \ + (u + 0x0F) & 0x1F, (u + 0x13) & 0x1F); \ + } \ + memcpy(a, t, sizeof t); \ + } while (0) + +#else + +#define ROUND_BIG_P(a, r) do { \ + sph_u32 t[32]; \ + a[0x00] ^= PC32up(0x00, r); \ + a[0x01] ^= PC32dn(0x00, r); \ + a[0x02] ^= PC32up(0x10, r); \ + a[0x03] ^= PC32dn(0x10, r); \ + a[0x04] ^= PC32up(0x20, r); \ + a[0x05] ^= PC32dn(0x20, r); \ + a[0x06] ^= PC32up(0x30, r); \ + a[0x07] ^= PC32dn(0x30, r); \ + a[0x08] ^= PC32up(0x40, r); \ + a[0x09] ^= PC32dn(0x40, r); \ + a[0x0A] ^= PC32up(0x50, r); \ + a[0x0B] ^= PC32dn(0x50, r); \ + a[0x0C] ^= PC32up(0x60, r); \ + a[0x0D] ^= PC32dn(0x60, r); \ + a[0x0E] ^= PC32up(0x70, r); \ + a[0x0F] ^= PC32dn(0x70, r); \ + a[0x10] ^= PC32up(0x80, r); \ + a[0x11] ^= PC32dn(0x80, r); \ + a[0x12] ^= PC32up(0x90, r); \ + a[0x13] ^= PC32dn(0x90, r); \ + a[0x14] ^= PC32up(0xA0, r); \ + a[0x15] ^= PC32dn(0xA0, r); \ + a[0x16] ^= PC32up(0xB0, r); \ + a[0x17] ^= PC32dn(0xB0, r); \ + a[0x18] ^= PC32up(0xC0, r); \ + a[0x19] ^= PC32dn(0xC0, r); \ + a[0x1A] ^= PC32up(0xD0, r); \ + a[0x1B] ^= PC32dn(0xD0, r); \ + a[0x1C] ^= PC32up(0xE0, r); \ + a[0x1D] ^= PC32dn(0xE0, r); \ + a[0x1E] ^= PC32up(0xF0, r); \ + a[0x1F] ^= PC32dn(0xF0, r); \ + RBTT(0x00, 0x01, a, \ + 0x00, 0x02, 0x04, 0x06, 0x09, 0x0B, 0x0D, 0x17); \ + RBTT(0x02, 0x03, a, \ + 0x02, 0x04, 0x06, 0x08, 0x0B, 0x0D, 0x0F, 0x19); \ + RBTT(0x04, 0x05, a, \ + 0x04, 0x06, 0x08, 0x0A, 0x0D, 0x0F, 0x11, 0x1B); \ + RBTT(0x06, 0x07, a, \ + 0x06, 0x08, 0x0A, 0x0C, 0x0F, 0x11, 0x13, 0x1D); \ + RBTT(0x08, 0x09, a, \ + 0x08, 0x0A, 0x0C, 0x0E, 0x11, 0x13, 0x15, 0x1F); \ + RBTT(0x0A, 0x0B, a, \ + 0x0A, 0x0C, 0x0E, 0x10, 0x13, 0x15, 0x17, 0x01); \ + RBTT(0x0C, 0x0D, a, \ + 0x0C, 0x0E, 0x10, 0x12, 0x15, 0x17, 0x19, 0x03); \ + RBTT(0x0E, 0x0F, a, \ + 0x0E, 0x10, 0x12, 0x14, 0x17, 0x19, 0x1B, 0x05); \ + RBTT(0x10, 0x11, a, \ + 0x10, 0x12, 0x14, 0x16, 0x19, 0x1B, 0x1D, 0x07); \ + RBTT(0x12, 0x13, a, \ + 0x12, 0x14, 0x16, 0x18, 0x1B, 0x1D, 0x1F, 0x09); \ + RBTT(0x14, 0x15, a, \ + 0x14, 0x16, 0x18, 0x1A, 0x1D, 0x1F, 0x01, 0x0B); \ + RBTT(0x16, 0x17, a, \ + 0x16, 0x18, 0x1A, 0x1C, 0x1F, 0x01, 0x03, 0x0D); \ + RBTT(0x18, 0x19, a, \ + 0x18, 0x1A, 0x1C, 0x1E, 0x01, 0x03, 0x05, 0x0F); \ + RBTT(0x1A, 0x1B, a, \ + 0x1A, 0x1C, 0x1E, 0x00, 0x03, 0x05, 0x07, 0x11); \ + RBTT(0x1C, 0x1D, a, \ + 0x1C, 0x1E, 0x00, 0x02, 0x05, 0x07, 0x09, 0x13); \ + RBTT(0x1E, 0x1F, a, \ + 0x1E, 0x00, 0x02, 0x04, 0x07, 0x09, 0x0B, 0x15); \ + memcpy(a, t, sizeof t); \ + } while (0) + +#define ROUND_BIG_Q(a, r) do { \ + sph_u32 t[32]; \ + a[0x00] ^= QC32up(0x00, r); \ + a[0x01] ^= QC32dn(0x00, r); \ + a[0x02] ^= QC32up(0x10, r); \ + a[0x03] ^= QC32dn(0x10, r); \ + a[0x04] ^= QC32up(0x20, r); \ + a[0x05] ^= QC32dn(0x20, r); \ + a[0x06] ^= QC32up(0x30, r); \ + a[0x07] ^= QC32dn(0x30, r); \ + a[0x08] ^= QC32up(0x40, r); \ + a[0x09] ^= QC32dn(0x40, r); \ + a[0x0A] ^= QC32up(0x50, r); \ + a[0x0B] ^= QC32dn(0x50, r); \ + a[0x0C] ^= QC32up(0x60, r); \ + a[0x0D] ^= QC32dn(0x60, r); \ + a[0x0E] ^= QC32up(0x70, r); \ + a[0x0F] ^= QC32dn(0x70, r); \ + a[0x10] ^= QC32up(0x80, r); \ + a[0x11] ^= QC32dn(0x80, r); \ + a[0x12] ^= QC32up(0x90, r); \ + a[0x13] ^= QC32dn(0x90, r); \ + a[0x14] ^= QC32up(0xA0, r); \ + a[0x15] ^= QC32dn(0xA0, r); \ + a[0x16] ^= QC32up(0xB0, r); \ + a[0x17] ^= QC32dn(0xB0, r); \ + a[0x18] ^= QC32up(0xC0, r); \ + a[0x19] ^= QC32dn(0xC0, r); \ + a[0x1A] ^= QC32up(0xD0, r); \ + a[0x1B] ^= QC32dn(0xD0, r); \ + a[0x1C] ^= QC32up(0xE0, r); \ + a[0x1D] ^= QC32dn(0xE0, r); \ + a[0x1E] ^= QC32up(0xF0, r); \ + a[0x1F] ^= QC32dn(0xF0, r); \ + RBTT(0x00, 0x01, a, \ + 0x02, 0x06, 0x0A, 0x16, 0x01, 0x05, 0x09, 0x0D); \ + RBTT(0x02, 0x03, a, \ + 0x04, 0x08, 0x0C, 0x18, 0x03, 0x07, 0x0B, 0x0F); \ + RBTT(0x04, 0x05, a, \ + 0x06, 0x0A, 0x0E, 0x1A, 0x05, 0x09, 0x0D, 0x11); \ + RBTT(0x06, 0x07, a, \ + 0x08, 0x0C, 0x10, 0x1C, 0x07, 0x0B, 0x0F, 0x13); \ + RBTT(0x08, 0x09, a, \ + 0x0A, 0x0E, 0x12, 0x1E, 0x09, 0x0D, 0x11, 0x15); \ + RBTT(0x0A, 0x0B, a, \ + 0x0C, 0x10, 0x14, 0x00, 0x0B, 0x0F, 0x13, 0x17); \ + RBTT(0x0C, 0x0D, a, \ + 0x0E, 0x12, 0x16, 0x02, 0x0D, 0x11, 0x15, 0x19); \ + RBTT(0x0E, 0x0F, a, \ + 0x10, 0x14, 0x18, 0x04, 0x0F, 0x13, 0x17, 0x1B); \ + RBTT(0x10, 0x11, a, \ + 0x12, 0x16, 0x1A, 0x06, 0x11, 0x15, 0x19, 0x1D); \ + RBTT(0x12, 0x13, a, \ + 0x14, 0x18, 0x1C, 0x08, 0x13, 0x17, 0x1B, 0x1F); \ + RBTT(0x14, 0x15, a, \ + 0x16, 0x1A, 0x1E, 0x0A, 0x15, 0x19, 0x1D, 0x01); \ + RBTT(0x16, 0x17, a, \ + 0x18, 0x1C, 0x00, 0x0C, 0x17, 0x1B, 0x1F, 0x03); \ + RBTT(0x18, 0x19, a, \ + 0x1A, 0x1E, 0x02, 0x0E, 0x19, 0x1D, 0x01, 0x05); \ + RBTT(0x1A, 0x1B, a, \ + 0x1C, 0x00, 0x04, 0x10, 0x1B, 0x1F, 0x03, 0x07); \ + RBTT(0x1C, 0x1D, a, \ + 0x1E, 0x02, 0x06, 0x12, 0x1D, 0x01, 0x05, 0x09); \ + RBTT(0x1E, 0x1F, a, \ + 0x00, 0x04, 0x08, 0x14, 0x1F, 0x03, 0x07, 0x0B); \ + memcpy(a, t, sizeof t); \ + } while (0) + +#endif + +#if SPH_SMALL_FOOTPRINT_GROESTL + +#define PERM_BIG_P(a) do { \ + int r; \ + for (r = 0; r < 14; r ++) \ + ROUND_BIG_P(a, r); \ + } while (0) + +#define PERM_BIG_Q(a) do { \ + int r; \ + for (r = 0; r < 14; r ++) \ + ROUND_BIG_Q(a, r); \ + } while (0) + +#else + +#define PERM_BIG_P(a) do { \ + int r; \ + for (r = 0; r < 14; r += 2) { \ + ROUND_BIG_P(a, r + 0); \ + ROUND_BIG_P(a, r + 1); \ + } \ + } while (0) + +#define PERM_BIG_Q(a) do { \ + int r; \ + for (r = 0; r < 14; r += 2) { \ + ROUND_BIG_Q(a, r + 0); \ + ROUND_BIG_Q(a, r + 1); \ + } \ + } while (0) + +#endif + +#define COMPRESS_BIG do { \ + sph_u32 g[32], m[32]; \ + size_t u; \ + for (u = 0; u < 32; u ++) { \ + m[u] = dec32e_aligned(buf + (u << 2)); \ + g[u] = m[u] ^ H[u]; \ + } \ + PERM_BIG_P(g); \ + PERM_BIG_Q(m); \ + for (u = 0; u < 32; u ++) \ + H[u] ^= g[u] ^ m[u]; \ + } while (0) + +#define FINAL_BIG do { \ + sph_u32 x[32]; \ + size_t u; \ + memcpy(x, H, sizeof x); \ + PERM_BIG_P(x); \ + for (u = 0; u < 32; u ++) \ + H[u] ^= x[u]; \ + } while (0) + +#endif + +static void +groestl_small_init(sph_groestl_small_context *sc, unsigned out_size) +{ + size_t u; + + sc->ptr = 0; +#if SPH_GROESTL_64 + for (u = 0; u < 7; u ++) + sc->state.wide[u] = 0; +#if USE_LE + sc->state.wide[7] = ((sph_u64)(out_size & 0xFF) << 56) + | ((sph_u64)(out_size & 0xFF00) << 40); +#else + sc->state.wide[7] = (sph_u64)out_size; +#endif +#else + for (u = 0; u < 15; u ++) + sc->state.narrow[u] = 0; +#if USE_LE + sc->state.narrow[15] = ((sph_u32)(out_size & 0xFF) << 24) + | ((sph_u32)(out_size & 0xFF00) << 8); +#else + sc->state.narrow[15] = (sph_u32)out_size; +#endif +#endif +#if SPH_64 + sc->count = 0; +#else + sc->count_high = 0; + sc->count_low = 0; +#endif +} + +static void +groestl_small_core(sph_groestl_small_context *sc, const void *data, size_t len) +{ + unsigned char *buf; + size_t ptr; + DECL_STATE_SMALL + + buf = sc->buf; + ptr = sc->ptr; + if (len < (sizeof sc->buf) - ptr) { + memcpy(buf + ptr, data, len); + ptr += len; + sc->ptr = ptr; + return; + } + + READ_STATE_SMALL(sc); + while (len > 0) { + size_t clen; + + clen = (sizeof sc->buf) - ptr; + if (clen > len) + clen = len; + memcpy(buf + ptr, data, clen); + ptr += clen; + data = (const unsigned char *)data + clen; + len -= clen; + if (ptr == sizeof sc->buf) { + COMPRESS_SMALL; +#if SPH_64 + sc->count ++; +#else + if ((sc->count_low = SPH_T32(sc->count_low + 1)) == 0) + sc->count_high = SPH_T32(sc->count_high + 1); +#endif + ptr = 0; + } + } + WRITE_STATE_SMALL(sc); + sc->ptr = ptr; +} + +static void +groestl_small_close(sph_groestl_small_context *sc, + unsigned ub, unsigned n, void *dst, size_t out_len) +{ + unsigned char pad[72]; + size_t u, ptr, pad_len; +#if SPH_64 + sph_u64 count; +#else + sph_u32 count_high, count_low; +#endif + unsigned z; + DECL_STATE_SMALL + + ptr = sc->ptr; + z = 0x80 >> n; + pad[0] = ((ub & -z) | z) & 0xFF; + if (ptr < 56) { + pad_len = 64 - ptr; +#if SPH_64 + count = SPH_T64(sc->count + 1); +#else + count_low = SPH_T32(sc->count_low + 1); + count_high = SPH_T32(sc->count_high); + if (count_low == 0) + count_high = SPH_T32(count_high + 1); +#endif + } else { + pad_len = 128 - ptr; +#if SPH_64 + count = SPH_T64(sc->count + 2); +#else + count_low = SPH_T32(sc->count_low + 2); + count_high = SPH_T32(sc->count_high); + if (count_low <= 1) + count_high = SPH_T32(count_high + 1); +#endif + } + memset(pad + 1, 0, pad_len - 9); +#if SPH_64 + sph_enc64be(pad + pad_len - 8, count); +#else + sph_enc64be(pad + pad_len - 8, count_high); + sph_enc64be(pad + pad_len - 4, count_low); +#endif + groestl_small_core(sc, pad, pad_len); + READ_STATE_SMALL(sc); + FINAL_SMALL; +#if SPH_GROESTL_64 + for (u = 0; u < 4; u ++) + enc64e(pad + (u << 3), H[u + 4]); +#else + for (u = 0; u < 8; u ++) + enc32e(pad + (u << 2), H[u + 8]); +#endif + memcpy(dst, pad + 32 - out_len, out_len); + groestl_small_init(sc, (unsigned)out_len << 3); +} + +static void +groestl_big_init(sph_groestl_big_context *sc, unsigned out_size) +{ + size_t u; + + sc->ptr = 0; +#if SPH_GROESTL_64 + for (u = 0; u < 15; u ++) + sc->state.wide[u] = 0; +#if USE_LE + sc->state.wide[15] = ((sph_u64)(out_size & 0xFF) << 56) + | ((sph_u64)(out_size & 0xFF00) << 40); +#else + sc->state.wide[15] = (sph_u64)out_size; +#endif +#else + for (u = 0; u < 31; u ++) + sc->state.narrow[u] = 0; +#if USE_LE + sc->state.narrow[31] = ((sph_u32)(out_size & 0xFF) << 24) + | ((sph_u32)(out_size & 0xFF00) << 8); +#else + sc->state.narrow[31] = (sph_u32)out_size; +#endif +#endif +#if SPH_64 + sc->count = 0; +#else + sc->count_high = 0; + sc->count_low = 0; +#endif +} + +static void +groestl_big_core(sph_groestl_big_context *sc, const void *data, size_t len) +{ + unsigned char *buf; + size_t ptr; + DECL_STATE_BIG + + buf = sc->buf; + ptr = sc->ptr; + if (len < (sizeof sc->buf) - ptr) { + memcpy(buf + ptr, data, len); + ptr += len; + sc->ptr = ptr; + return; + } + + READ_STATE_BIG(sc); + while (len > 0) { + size_t clen; + + clen = (sizeof sc->buf) - ptr; + if (clen > len) + clen = len; + memcpy(buf + ptr, data, clen); + ptr += clen; + data = (const unsigned char *)data + clen; + len -= clen; + if (ptr == sizeof sc->buf) { + COMPRESS_BIG; +#if SPH_64 + sc->count ++; +#else + if ((sc->count_low = SPH_T32(sc->count_low + 1)) == 0) + sc->count_high = SPH_T32(sc->count_high + 1); +#endif + ptr = 0; + } + } + WRITE_STATE_BIG(sc); + sc->ptr = ptr; +} + +static void +groestl_big_close(sph_groestl_big_context *sc, + unsigned ub, unsigned n, void *dst, size_t out_len) +{ + unsigned char pad[136]; + size_t ptr, pad_len, u; +#if SPH_64 + sph_u64 count; +#else + sph_u32 count_high, count_low; +#endif + unsigned z; + DECL_STATE_BIG + + ptr = sc->ptr; + z = 0x80 >> n; + pad[0] = ((ub & -z) | z) & 0xFF; + if (ptr < 120) { + pad_len = 128 - ptr; +#if SPH_64 + count = SPH_T64(sc->count + 1); +#else + count_low = SPH_T32(sc->count_low + 1); + count_high = SPH_T32(sc->count_high); + if (count_low == 0) + count_high = SPH_T32(count_high + 1); +#endif + } else { + pad_len = 256 - ptr; +#if SPH_64 + count = SPH_T64(sc->count + 2); +#else + count_low = SPH_T32(sc->count_low + 2); + count_high = SPH_T32(sc->count_high); + if (count_low <= 1) + count_high = SPH_T32(count_high + 1); +#endif + } + memset(pad + 1, 0, pad_len - 9); +#if SPH_64 + sph_enc64be(pad + pad_len - 8, count); +#else + sph_enc64be(pad + pad_len - 8, count_high); + sph_enc64be(pad + pad_len - 4, count_low); +#endif + groestl_big_core(sc, pad, pad_len); + READ_STATE_BIG(sc); + FINAL_BIG; +#if SPH_GROESTL_64 + for (u = 0; u < 8; u ++) + enc64e(pad + (u << 3), H[u + 8]); +#else + for (u = 0; u < 16; u ++) + enc32e(pad + (u << 2), H[u + 16]); +#endif + memcpy(dst, pad + 64 - out_len, out_len); + groestl_big_init(sc, (unsigned)out_len << 3); +} + +/* see sph_groestl.h */ +void +sph_groestl224_init(void *cc) +{ + groestl_small_init((sph_groestl_small_context *)cc, 224); +} + +/* see sph_groestl.h */ +void +sph_groestl224(void *cc, const void *data, size_t len) +{ + groestl_small_core((sph_groestl_small_context *)cc, data, len); +} + +/* see sph_groestl.h */ +void +sph_groestl224_close(void *cc, void *dst) +{ + groestl_small_close((sph_groestl_small_context *)cc, 0, 0, dst, 28); +} + +/* see sph_groestl.h */ +void +sph_groestl224_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + groestl_small_close((sph_groestl_small_context *)cc, ub, n, dst, 28); +} + +/* see sph_groestl.h */ +void +sph_groestl256_init(void *cc) +{ + groestl_small_init((sph_groestl_small_context *)cc, 256); +} + +/* see sph_groestl.h */ +void +sph_groestl256(void *cc, const void *data, size_t len) +{ + groestl_small_core((sph_groestl_small_context *)cc, data, len); +} + +/* see sph_groestl.h */ +void +sph_groestl256_close(void *cc, void *dst) +{ + groestl_small_close((sph_groestl_small_context *)cc, 0, 0, dst, 32); +} + +/* see sph_groestl.h */ +void +sph_groestl256_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + groestl_small_close((sph_groestl_small_context *)cc, ub, n, dst, 32); +} + +/* see sph_groestl.h */ +void +sph_groestl384_init(void *cc) +{ + groestl_big_init((sph_groestl_big_context *)cc, 384); +} + +/* see sph_groestl.h */ +void +sph_groestl384(void *cc, const void *data, size_t len) +{ + groestl_big_core((sph_groestl_big_context *)cc, data, len); +} + +/* see sph_groestl.h */ +void +sph_groestl384_close(void *cc, void *dst) +{ + groestl_big_close((sph_groestl_big_context *)cc, 0, 0, dst, 48); +} + +/* see sph_groestl.h */ +void +sph_groestl384_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + groestl_big_close((sph_groestl_big_context *)cc, ub, n, dst, 48); +} + +/* see sph_groestl.h */ +void +groestl512_Init(void *cc) +{ + groestl_big_init((sph_groestl_big_context *)cc, 512); +} + +/* see sph_groestl.h */ +void +groestl512_Update(void *cc, const void *data, size_t len) +{ + groestl_big_core((sph_groestl_big_context *)cc, data, len); +} + +/* see sph_groestl.h */ +void +groestl512_Final(void *cc, void *dst) +{ + groestl_big_close((sph_groestl_big_context *)cc, 0, 0, dst, 64); +} + +/* see sph_groestl.h */ +void +sph_groestl512_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + groestl_big_close((sph_groestl_big_context *)cc, ub, n, dst, 64); +} diff --git a/groestl.h b/groestl.h new file mode 100644 index 000000000..49506622d --- /dev/null +++ b/groestl.h @@ -0,0 +1,321 @@ +/* $Id: sph_groestl.h 216 2010-06-08 09:46:57Z tp $ */ +/** + * Groestl interface. This code implements Groestl with the recommended + * parameters for SHA-3, with outputs of 224, 256, 384 and 512 bits. + * + * ==========================(LICENSE BEGIN)============================ + * + * Copyright (c) 2007-2010 Projet RNRT SAPHIR + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * ===========================(LICENSE END)============================= + * + * @file sph_groestl.h + * @author Thomas Pornin + */ + +#ifndef SPH_GROESTL_H__ +#define SPH_GROESTL_H__ + +#include +#include "groestl_internal.h" + +/** + * Output size (in bits) for Groestl-224. + */ +#define SPH_SIZE_groestl224 224 + +/** + * Output size (in bits) for Groestl-256. + */ +#define SPH_SIZE_groestl256 256 + +/** + * Output size (in bits) for Groestl-384. + */ +#define SPH_SIZE_groestl384 384 + +/** + * Output size (in bits) for Groestl-512. + */ +#define SPH_SIZE_groestl512 512 + +/** + * This structure is a context for Groestl-224 and Groestl-256 computations: + * it contains the intermediate values and some data from the last + * entered block. Once a Groestl computation has been performed, the + * context can be reused for another computation. + * + * The contents of this structure are private. A running Groestl + * computation can be cloned by copying the context (e.g. with a simple + * memcpy()). + */ +typedef struct { +#ifndef DOXYGEN_IGNORE + unsigned char buf[64]; /* first field, for alignment */ + size_t ptr; + union { +#if SPH_64 + sph_u64 wide[8]; +#endif + sph_u32 narrow[16]; + } state; +#if SPH_64 + sph_u64 count; +#else + sph_u32 count_high, count_low; +#endif +#endif +} sph_groestl_small_context; + +/** + * This structure is a context for Groestl-224 computations. It is + * identical to the common sph_groestl_small_context. + */ +typedef sph_groestl_small_context sph_groestl224_context; + +/** + * This structure is a context for Groestl-256 computations. It is + * identical to the common sph_groestl_small_context. + */ +typedef sph_groestl_small_context sph_groestl256_context; + +/** + * This structure is a context for Groestl-384 and Groestl-512 computations: + * it contains the intermediate values and some data from the last + * entered block. Once a Groestl computation has been performed, the + * context can be reused for another computation. + * + * The contents of this structure are private. A running Groestl + * computation can be cloned by copying the context (e.g. with a simple + * memcpy()). + */ +typedef struct { +#ifndef DOXYGEN_IGNORE + unsigned char buf[128]; /* first field, for alignment */ + size_t ptr; + union { +#if SPH_64 + sph_u64 wide[16]; +#endif + sph_u32 narrow[32]; + } state; +#if SPH_64 + sph_u64 count; +#else + sph_u32 count_high, count_low; +#endif +#endif +} sph_groestl_big_context; + +/** + * This structure is a context for Groestl-384 computations. It is + * identical to the common sph_groestl_small_context. + */ +typedef sph_groestl_big_context sph_groestl384_context; + +/** + * This structure is a context for Groestl-512 computations. It is + * identical to the common sph_groestl_small_context. + */ +typedef sph_groestl_big_context GROESTL512_CTX; + +/** + * Initialize a Groestl-224 context. This process performs no memory allocation. + * + * @param cc the Groestl-224 context (pointer to a + * sph_groestl224_context) + */ +void sph_groestl224_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the Groestl-224 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_groestl224(void *cc, const void *data, size_t len); + +/** + * Terminate the current Groestl-224 computation and output the result into + * the provided buffer. The destination buffer must be wide enough to + * accomodate the result (28 bytes). The context is automatically + * reinitialized. + * + * @param cc the Groestl-224 context + * @param dst the destination buffer + */ +void sph_groestl224_close(void *cc, void *dst); + +/** + * Add a few additional bits (0 to 7) to the current computation, then + * terminate it and output the result in the provided buffer, which must + * be wide enough to accomodate the result (28 bytes). If bit number i + * in ub has value 2^i, then the extra bits are those + * numbered 7 downto 8-n (this is the big-endian convention at the byte + * level). The context is automatically reinitialized. + * + * @param cc the Groestl-224 context + * @param ub the extra bits + * @param n the number of extra bits (0 to 7) + * @param dst the destination buffer + */ +void sph_groestl224_addbits_and_close( + void *cc, unsigned ub, unsigned n, void *dst); + +/** + * Initialize a Groestl-256 context. This process performs no memory allocation. + * + * @param cc the Groestl-256 context (pointer to a + * sph_groestl256_context) + */ +void sph_groestl256_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the Groestl-256 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_groestl256(void *cc, const void *data, size_t len); + +/** + * Terminate the current Groestl-256 computation and output the result into + * the provided buffer. The destination buffer must be wide enough to + * accomodate the result (32 bytes). The context is automatically + * reinitialized. + * + * @param cc the Groestl-256 context + * @param dst the destination buffer + */ +void sph_groestl256_close(void *cc, void *dst); + +/** + * Add a few additional bits (0 to 7) to the current computation, then + * terminate it and output the result in the provided buffer, which must + * be wide enough to accomodate the result (32 bytes). If bit number i + * in ub has value 2^i, then the extra bits are those + * numbered 7 downto 8-n (this is the big-endian convention at the byte + * level). The context is automatically reinitialized. + * + * @param cc the Groestl-256 context + * @param ub the extra bits + * @param n the number of extra bits (0 to 7) + * @param dst the destination buffer + */ +void sph_groestl256_addbits_and_close( + void *cc, unsigned ub, unsigned n, void *dst); + +/** + * Initialize a Groestl-384 context. This process performs no memory allocation. + * + * @param cc the Groestl-384 context (pointer to a + * sph_groestl384_context) + */ +void sph_groestl384_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the Groestl-384 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_groestl384(void *cc, const void *data, size_t len); + +/** + * Terminate the current Groestl-384 computation and output the result into + * the provided buffer. The destination buffer must be wide enough to + * accomodate the result (48 bytes). The context is automatically + * reinitialized. + * + * @param cc the Groestl-384 context + * @param dst the destination buffer + */ +void sph_groestl384_close(void *cc, void *dst); + +/** + * Add a few additional bits (0 to 7) to the current computation, then + * terminate it and output the result in the provided buffer, which must + * be wide enough to accomodate the result (48 bytes). If bit number i + * in ub has value 2^i, then the extra bits are those + * numbered 7 downto 8-n (this is the big-endian convention at the byte + * level). The context is automatically reinitialized. + * + * @param cc the Groestl-384 context + * @param ub the extra bits + * @param n the number of extra bits (0 to 7) + * @param dst the destination buffer + */ +void sph_groestl384_addbits_and_close( + void *cc, unsigned ub, unsigned n, void *dst); + +/** + * Initialize a Groestl-512 context. This process performs no memory allocation. + * + * @param cc the Groestl-512 context (pointer to a + * GROESTL512_CTX) + */ +void groestl512_Init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the Groestl-512 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void groestl512_Update(void *cc, const void *data, size_t len); + +/** + * Terminate the current Groestl-512 computation and output the result into + * the provided buffer. The destination buffer must be wide enough to + * accomodate the result (64 bytes). The context is automatically + * reinitialized. + * + * @param cc the Groestl-512 context + * @param dst the destination buffer + */ +void groestl512_Final(void *cc, void *dst); + +/** + * Add a few additional bits (0 to 7) to the current computation, then + * terminate it and output the result in the provided buffer, which must + * be wide enough to accomodate the result (64 bytes). If bit number i + * in ub has value 2^i, then the extra bits are those + * numbered 7 downto 8-n (this is the big-endian convention at the byte + * level). The context is automatically reinitialized. + * + * @param cc the Groestl-512 context + * @param ub the extra bits + * @param n the number of extra bits (0 to 7) + * @param dst the destination buffer + */ +void sph_groestl512_addbits_and_close( + void *cc, unsigned ub, unsigned n, void *dst); + +#endif diff --git a/groestl_internal.h b/groestl_internal.h new file mode 100644 index 000000000..7295b0b37 --- /dev/null +++ b/groestl_internal.h @@ -0,0 +1,1976 @@ +/* $Id: sph_types.h 260 2011-07-21 01:02:38Z tp $ */ +/** + * Basic type definitions. + * + * This header file defines the generic integer types that will be used + * for the implementation of hash functions; it also contains helper + * functions which encode and decode multi-byte integer values, using + * either little-endian or big-endian conventions. + * + * This file contains a compile-time test on the size of a byte + * (the unsigned char C type). If bytes are not octets, + * i.e. if they do not have a size of exactly 8 bits, then compilation + * is aborted. Architectures where bytes are not octets are relatively + * rare, even in the embedded devices market. We forbid non-octet bytes + * because there is no clear convention on how octet streams are encoded + * on such systems. + * + * ==========================(LICENSE BEGIN)============================ + * + * Copyright (c) 2007-2010 Projet RNRT SAPHIR + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * ===========================(LICENSE END)============================= + * + * @file sph_types.h + * @author Thomas Pornin + */ + +#ifndef SPH_TYPES_H__ +#define SPH_TYPES_H__ + +#include + +/* + * All our I/O functions are defined over octet streams. We do not know + * how to handle input data if bytes are not octets. + */ +#if CHAR_BIT != 8 +#error This code requires 8-bit bytes +#endif + +/* ============= BEGIN documentation block for Doxygen ============ */ + +#ifdef DOXYGEN_IGNORE + +/** @mainpage sphlib C code documentation + * + * @section overview Overview + * + * sphlib is a library which contains implementations of + * various cryptographic hash functions. These pages have been generated + * with doxygen and + * document the API for the C implementations. + * + * The API is described in appropriate header files, which are available + * in the "Files" section. Each hash function family has its own header, + * whose name begins with "sph_" and contains the family + * name. For instance, the API for the RIPEMD hash functions is available + * in the header file sph_ripemd.h. + * + * @section principles API structure and conventions + * + * @subsection io Input/output conventions + * + * In all generality, hash functions operate over strings of bits. + * Individual bits are rarely encountered in C programming or actual + * communication protocols; most protocols converge on the ubiquitous + * "octet" which is a group of eight bits. Data is thus expressed as a + * stream of octets. The C programming language contains the notion of a + * "byte", which is a data unit managed under the type "unsigned + * char". The C standard prescribes that a byte should hold at + * least eight bits, but possibly more. Most modern architectures, even + * in the embedded world, feature eight-bit bytes, i.e. map bytes to + * octets. + * + * Nevertheless, for some of the implemented hash functions, an extra + * API has been added, which allows the input of arbitrary sequences of + * bits: when the computation is about to be closed, 1 to 7 extra bits + * can be added. The functions for which this API is implemented include + * the SHA-2 functions and all SHA-3 candidates. + * + * sphlib defines hash function which may hash octet streams, + * i.e. streams of bits where the number of bits is a multiple of eight. + * The data input functions in the sphlib API expect data + * as anonymous pointers ("const void *") with a length + * (of type "size_t") which gives the input data chunk length + * in bytes. A byte is assumed to be an octet; the sph_types.h + * header contains a compile-time test which prevents compilation on + * architectures where this property is not met. + * + * The hash function output is also converted into bytes. All currently + * implemented hash functions have an output width which is a multiple of + * eight, and this is likely to remain true for new designs. + * + * Most hash functions internally convert input data into 32-bit of 64-bit + * words, using either little-endian or big-endian conversion. The hash + * output also often consists of such words, which are encoded into output + * bytes with a similar endianness convention. Some hash functions have + * been only loosely specified on that subject; when necessary, + * sphlib has been tested against published "reference" + * implementations in order to use the same conventions. + * + * @subsection shortname Function short name + * + * Each implemented hash function has a "short name" which is used + * internally to derive the identifiers for the functions and context + * structures which the function uses. For instance, MD5 has the short + * name "md5". Short names are listed in the next section, + * for the implemented hash functions. In subsequent sections, the + * short name will be assumed to be "XXX": replace with the + * actual hash function name to get the C identifier. + * + * Note: some functions within the same family share the same core + * elements, such as update function or context structure. Correspondingly, + * some of the defined types or functions may actually be macros which + * transparently evaluate to another type or function name. + * + * @subsection context Context structure + * + * Each implemented hash fonction has its own context structure, available + * under the type name "sph_XXX_context" for the hash function + * with short name "XXX". This structure holds all needed + * state for a running hash computation. + * + * The contents of these structures are meant to be opaque, and private + * to the implementation. However, these contents are specified in the + * header files so that application code which uses sphlib + * may access the size of those structures. + * + * The caller is responsible for allocating the context structure, + * whether by dynamic allocation (malloc() or equivalent), + * static allocation (a global permanent variable), as an automatic + * variable ("on the stack"), or by any other mean which ensures proper + * structure alignment. sphlib code performs no dynamic + * allocation by itself. + * + * The context must be initialized before use, using the + * sph_XXX_init() function. This function sets the context + * state to proper initial values for hashing. + * + * Since all state data is contained within the context structure, + * sphlib is thread-safe and reentrant: several hash + * computations may be performed in parallel, provided that they do not + * operate on the same context. Moreover, a running computation can be + * cloned by copying the context (with a simple memcpy()): + * the context and its clone are then independant and may be updated + * with new data and/or closed without interfering with each other. + * Similarly, a context structure can be moved in memory at will: + * context structures contain no pointer, in particular no pointer to + * themselves. + * + * @subsection dataio Data input + * + * Hashed data is input with the sph_XXX() fonction, which + * takes as parameters a pointer to the context, a pointer to the data + * to hash, and the number of data bytes to hash. The context is updated + * with the new data. + * + * Data can be input in one or several calls, with arbitrary input lengths. + * However, it is best, performance wise, to input data by relatively big + * chunks (say a few kilobytes), because this allows sphlib to + * optimize things and avoid internal copying. + * + * When all data has been input, the context can be closed with + * sph_XXX_close(). The hash output is computed and written + * into the provided buffer. The caller must take care to provide a + * buffer of appropriate length; e.g., when using SHA-1, the output is + * a 20-byte word, therefore the output buffer must be at least 20-byte + * long. + * + * For some hash functions, the sph_XXX_addbits_and_close() + * function can be used instead of sph_XXX_close(). This + * function can take a few extra bits to be added at + * the end of the input message. This allows hashing messages with a + * bit length which is not a multiple of 8. The extra bits are provided + * as an unsigned integer value, and a bit count. The bit count must be + * between 0 and 7, inclusive. The extra bits are provided as bits 7 to + * 0 (bits of numerical value 128, 64, 32... downto 0), in that order. + * For instance, to add three bits of value 1, 1 and 0, the unsigned + * integer will have value 192 (1*128 + 1*64 + 0*32) and the bit count + * will be 3. + * + * The SPH_SIZE_XXX macro is defined for each hash function; + * it evaluates to the function output size, expressed in bits. For instance, + * SPH_SIZE_sha1 evaluates to 160. + * + * When closed, the context is automatically reinitialized and can be + * immediately used for another computation. It is not necessary to call + * sph_XXX_init() after a close. Note that + * sph_XXX_init() can still be called to "reset" a context, + * i.e. forget previously input data, and get back to the initial state. + * + * @subsection alignment Data alignment + * + * "Alignment" is a property of data, which is said to be "properly + * aligned" when its emplacement in memory is such that the data can + * be optimally read by full words. This depends on the type of access; + * basically, some hash functions will read data by 32-bit or 64-bit + * words. sphlib does not mandate such alignment for input + * data, but using aligned data can substantially improve performance. + * + * As a rule, it is best to input data by chunks whose length (in bytes) + * is a multiple of eight, and which begins at "generally aligned" + * addresses, such as the base address returned by a call to + * malloc(). + * + * @section functions Implemented functions + * + * We give here the list of implemented functions. They are grouped by + * family; to each family corresponds a specific header file. Each + * individual function has its associated "short name". Please refer to + * the documentation for that header file to get details on the hash + * function denomination and provenance. + * + * Note: the functions marked with a '(64)' in the list below are + * available only if the C compiler provides an integer type of length + * 64 bits or more. Such a type is mandatory in the latest C standard + * (ISO 9899:1999, aka "C99") and is present in several older compilers + * as well, so chances are that such a type is available. + * + * - HAVAL family: file sph_haval.h + * - HAVAL-128/3 (128-bit, 3 passes): short name: haval128_3 + * - HAVAL-128/4 (128-bit, 4 passes): short name: haval128_4 + * - HAVAL-128/5 (128-bit, 5 passes): short name: haval128_5 + * - HAVAL-160/3 (160-bit, 3 passes): short name: haval160_3 + * - HAVAL-160/4 (160-bit, 4 passes): short name: haval160_4 + * - HAVAL-160/5 (160-bit, 5 passes): short name: haval160_5 + * - HAVAL-192/3 (192-bit, 3 passes): short name: haval192_3 + * - HAVAL-192/4 (192-bit, 4 passes): short name: haval192_4 + * - HAVAL-192/5 (192-bit, 5 passes): short name: haval192_5 + * - HAVAL-224/3 (224-bit, 3 passes): short name: haval224_3 + * - HAVAL-224/4 (224-bit, 4 passes): short name: haval224_4 + * - HAVAL-224/5 (224-bit, 5 passes): short name: haval224_5 + * - HAVAL-256/3 (256-bit, 3 passes): short name: haval256_3 + * - HAVAL-256/4 (256-bit, 4 passes): short name: haval256_4 + * - HAVAL-256/5 (256-bit, 5 passes): short name: haval256_5 + * - MD2: file sph_md2.h, short name: md2 + * - MD4: file sph_md4.h, short name: md4 + * - MD5: file sph_md5.h, short name: md5 + * - PANAMA: file sph_panama.h, short name: panama + * - RadioGatun family: file sph_radiogatun.h + * - RadioGatun[32]: short name: radiogatun32 + * - RadioGatun[64]: short name: radiogatun64 (64) + * - RIPEMD family: file sph_ripemd.h + * - RIPEMD: short name: ripemd + * - RIPEMD-128: short name: ripemd128 + * - RIPEMD-160: short name: ripemd160 + * - SHA-0: file sph_sha0.h, short name: sha0 + * - SHA-1: file sph_sha1.h, short name: sha1 + * - SHA-2 family, 32-bit hashes: file sph_sha2.h + * - SHA-224: short name: sha224 + * - SHA-256: short name: sha256 + * - SHA-384: short name: sha384 (64) + * - SHA-512: short name: sha512 (64) + * - Tiger family: file sph_tiger.h + * - Tiger: short name: tiger (64) + * - Tiger2: short name: tiger2 (64) + * - WHIRLPOOL family: file sph_whirlpool.h + * - WHIRLPOOL-0: short name: whirlpool0 (64) + * - WHIRLPOOL-1: short name: whirlpool1 (64) + * - WHIRLPOOL: short name: whirlpool (64) + * + * The fourteen second-round SHA-3 candidates are also implemented; + * when applicable, the implementations follow the "final" specifications + * as published for the third round of the SHA-3 competition (BLAKE, + * Groestl, JH, Keccak and Skein have been tweaked for third round). + * + * - BLAKE family: file sph_blake.h + * - BLAKE-224: short name: blake224 + * - BLAKE-256: short name: blake256 + * - BLAKE-384: short name: blake384 + * - BLAKE-512: short name: blake512 + * - BMW (Blue Midnight Wish) family: file sph_bmw.h + * - BMW-224: short name: bmw224 + * - BMW-256: short name: bmw256 + * - BMW-384: short name: bmw384 (64) + * - BMW-512: short name: bmw512 (64) + * - CubeHash family: file sph_cubehash.h (specified as + * CubeHash16/32 in the CubeHash specification) + * - CubeHash-224: short name: cubehash224 + * - CubeHash-256: short name: cubehash256 + * - CubeHash-384: short name: cubehash384 + * - CubeHash-512: short name: cubehash512 + * - ECHO family: file sph_echo.h + * - ECHO-224: short name: echo224 + * - ECHO-256: short name: echo256 + * - ECHO-384: short name: echo384 + * - ECHO-512: short name: echo512 + * - Fugue family: file sph_fugue.h + * - Fugue-224: short name: fugue224 + * - Fugue-256: short name: fugue256 + * - Fugue-384: short name: fugue384 + * - Fugue-512: short name: fugue512 + * - Groestl family: file sph_groestl.h + * - Groestl-224: short name: groestl224 + * - Groestl-256: short name: groestl256 + * - Groestl-384: short name: groestl384 + * - Groestl-512: short name: groestl512 + * - Hamsi family: file sph_hamsi.h + * - Hamsi-224: short name: hamsi224 + * - Hamsi-256: short name: hamsi256 + * - Hamsi-384: short name: hamsi384 + * - Hamsi-512: short name: hamsi512 + * - JH family: file sph_jh.h + * - JH-224: short name: jh224 + * - JH-256: short name: jh256 + * - JH-384: short name: jh384 + * - JH-512: short name: jh512 + * - Keccak family: file sph_keccak.h + * - Keccak-224: short name: keccak224 + * - Keccak-256: short name: keccak256 + * - Keccak-384: short name: keccak384 + * - Keccak-512: short name: keccak512 + * - Luffa family: file sph_luffa.h + * - Luffa-224: short name: luffa224 + * - Luffa-256: short name: luffa256 + * - Luffa-384: short name: luffa384 + * - Luffa-512: short name: luffa512 + * - Shabal family: file sph_shabal.h + * - Shabal-192: short name: shabal192 + * - Shabal-224: short name: shabal224 + * - Shabal-256: short name: shabal256 + * - Shabal-384: short name: shabal384 + * - Shabal-512: short name: shabal512 + * - SHAvite-3 family: file sph_shavite.h + * - SHAvite-224 (nominally "SHAvite-3 with 224-bit output"): + * short name: shabal224 + * - SHAvite-256 (nominally "SHAvite-3 with 256-bit output"): + * short name: shabal256 + * - SHAvite-384 (nominally "SHAvite-3 with 384-bit output"): + * short name: shabal384 + * - SHAvite-512 (nominally "SHAvite-3 with 512-bit output"): + * short name: shabal512 + * - SIMD family: file sph_simd.h + * - SIMD-224: short name: simd224 + * - SIMD-256: short name: simd256 + * - SIMD-384: short name: simd384 + * - SIMD-512: short name: simd512 + * - Skein family: file sph_skein.h + * - Skein-224 (nominally specified as Skein-512-224): short name: + * skein224 (64) + * - Skein-256 (nominally specified as Skein-512-256): short name: + * skein256 (64) + * - Skein-384 (nominally specified as Skein-512-384): short name: + * skein384 (64) + * - Skein-512 (nominally specified as Skein-512-512): short name: + * skein512 (64) + * + * For the second-round SHA-3 candidates, the functions are as specified + * for round 2, i.e. with the "tweaks" that some candidates added + * between round 1 and round 2. Also, some of the submitted packages for + * round 2 contained errors, in the specification, reference code, or + * both. sphlib implements the corrected versions. + */ + +/** @hideinitializer + * Unsigned integer type whose length is at least 32 bits; on most + * architectures, it will have a width of exactly 32 bits. Unsigned C + * types implement arithmetics modulo a power of 2; use the + * SPH_T32() macro to ensure that the value is truncated + * to exactly 32 bits. Unless otherwise specified, all macros and + * functions which accept sph_u32 values assume that these + * values fit on 32 bits, i.e. do not exceed 2^32-1, even on architectures + * where sph_u32 is larger than that. + */ +typedef __arch_dependant__ sph_u32; + +/** @hideinitializer + * Signed integer type corresponding to sph_u32; it has + * width 32 bits or more. + */ +typedef __arch_dependant__ sph_s32; + +/** @hideinitializer + * Unsigned integer type whose length is at least 64 bits; on most + * architectures which feature such a type, it will have a width of + * exactly 64 bits. C99-compliant platform will have this type; it + * is also defined when the GNU compiler (gcc) is used, and on + * platforms where unsigned long is large enough. If this + * type is not available, then some hash functions which depends on + * a 64-bit type will not be available (most notably SHA-384, SHA-512, + * Tiger and WHIRLPOOL). + */ +typedef __arch_dependant__ sph_u64; + +/** @hideinitializer + * Signed integer type corresponding to sph_u64; it has + * width 64 bits or more. + */ +typedef __arch_dependant__ sph_s64; + +/** + * This macro expands the token x into a suitable + * constant expression of type sph_u32. Depending on + * how this type is defined, a suffix such as UL may + * be appended to the argument. + * + * @param x the token to expand into a suitable constant expression + */ +#define SPH_C32(x) + +/** + * Truncate a 32-bit value to exactly 32 bits. On most systems, this is + * a no-op, recognized as such by the compiler. + * + * @param x the value to truncate (of type sph_u32) + */ +#define SPH_T32(x) + +/** + * Rotate a 32-bit value by a number of bits to the left. The rotate + * count must reside between 1 and 31. This macro assumes that its + * first argument fits in 32 bits (no extra bit allowed on machines where + * sph_u32 is wider); both arguments may be evaluated + * several times. + * + * @param x the value to rotate (of type sph_u32) + * @param n the rotation count (between 1 and 31, inclusive) + */ +#define SPH_ROTL32(x, n) + +/** + * Rotate a 32-bit value by a number of bits to the left. The rotate + * count must reside between 1 and 31. This macro assumes that its + * first argument fits in 32 bits (no extra bit allowed on machines where + * sph_u32 is wider); both arguments may be evaluated + * several times. + * + * @param x the value to rotate (of type sph_u32) + * @param n the rotation count (between 1 and 31, inclusive) + */ +#define SPH_ROTR32(x, n) + +/** + * This macro is defined on systems for which a 64-bit type has been + * detected, and is used for sph_u64. + */ +#define SPH_64 + +/** + * This macro is defined on systems for the "native" integer size is + * 64 bits (64-bit values fit in one register). + */ +#define SPH_64_TRUE + +/** + * This macro expands the token x into a suitable + * constant expression of type sph_u64. Depending on + * how this type is defined, a suffix such as ULL may + * be appended to the argument. This macro is defined only if a + * 64-bit type was detected and used for sph_u64. + * + * @param x the token to expand into a suitable constant expression + */ +#define SPH_C64(x) + +/** + * Truncate a 64-bit value to exactly 64 bits. On most systems, this is + * a no-op, recognized as such by the compiler. This macro is defined only + * if a 64-bit type was detected and used for sph_u64. + * + * @param x the value to truncate (of type sph_u64) + */ +#define SPH_T64(x) + +/** + * Rotate a 64-bit value by a number of bits to the left. The rotate + * count must reside between 1 and 63. This macro assumes that its + * first argument fits in 64 bits (no extra bit allowed on machines where + * sph_u64 is wider); both arguments may be evaluated + * several times. This macro is defined only if a 64-bit type was detected + * and used for sph_u64. + * + * @param x the value to rotate (of type sph_u64) + * @param n the rotation count (between 1 and 63, inclusive) + */ +#define SPH_ROTL64(x, n) + +/** + * Rotate a 64-bit value by a number of bits to the left. The rotate + * count must reside between 1 and 63. This macro assumes that its + * first argument fits in 64 bits (no extra bit allowed on machines where + * sph_u64 is wider); both arguments may be evaluated + * several times. This macro is defined only if a 64-bit type was detected + * and used for sph_u64. + * + * @param x the value to rotate (of type sph_u64) + * @param n the rotation count (between 1 and 63, inclusive) + */ +#define SPH_ROTR64(x, n) + +/** + * This macro evaluates to inline or an equivalent construction, + * if available on the compilation platform, or to nothing otherwise. This + * is used to declare inline functions, for which the compiler should + * endeavour to include the code directly in the caller. Inline functions + * are typically defined in header files as replacement for macros. + */ +#define SPH_INLINE + +/** + * This macro is defined if the platform has been detected as using + * little-endian convention. This implies that the sph_u32 + * type (and the sph_u64 type also, if it is defined) has + * an exact width (i.e. exactly 32-bit, respectively 64-bit). + */ +#define SPH_LITTLE_ENDIAN + +/** + * This macro is defined if the platform has been detected as using + * big-endian convention. This implies that the sph_u32 + * type (and the sph_u64 type also, if it is defined) has + * an exact width (i.e. exactly 32-bit, respectively 64-bit). + */ +#define SPH_BIG_ENDIAN + +/** + * This macro is defined if 32-bit words (and 64-bit words, if defined) + * can be read from and written to memory efficiently in little-endian + * convention. This is the case for little-endian platforms, and also + * for the big-endian platforms which have special little-endian access + * opcodes (e.g. Ultrasparc). + */ +#define SPH_LITTLE_FAST + +/** + * This macro is defined if 32-bit words (and 64-bit words, if defined) + * can be read from and written to memory efficiently in big-endian + * convention. This is the case for little-endian platforms, and also + * for the little-endian platforms which have special big-endian access + * opcodes. + */ +#define SPH_BIG_FAST + +/** + * On some platforms, this macro is defined to an unsigned integer type + * into which pointer values may be cast. The resulting value can then + * be tested for being a multiple of 2, 4 or 8, indicating an aligned + * pointer for, respectively, 16-bit, 32-bit or 64-bit memory accesses. + */ +#define SPH_UPTR + +/** + * When defined, this macro indicates that unaligned memory accesses + * are possible with only a minor penalty, and thus should be prefered + * over strategies which first copy data to an aligned buffer. + */ +#define SPH_UNALIGNED + +/** + * Byte-swap a 32-bit word (i.e. 0x12345678 becomes + * 0x78563412). This is an inline function which resorts + * to inline assembly on some platforms, for better performance. + * + * @param x the 32-bit value to byte-swap + * @return the byte-swapped value + */ +static inline sph_u32 sph_bswap32(sph_u32 x); + +/** + * Byte-swap a 64-bit word. This is an inline function which resorts + * to inline assembly on some platforms, for better performance. This + * function is defined only if a suitable 64-bit type was found for + * sph_u64 + * + * @param x the 64-bit value to byte-swap + * @return the byte-swapped value + */ +static inline sph_u64 sph_bswap64(sph_u64 x); + +/** + * Decode a 16-bit unsigned value from memory, in little-endian convention + * (least significant byte comes first). + * + * @param src the source address + * @return the decoded value + */ +static inline unsigned sph_dec16le(const void *src); + +/** + * Encode a 16-bit unsigned value into memory, in little-endian convention + * (least significant byte comes first). + * + * @param dst the destination buffer + * @param val the value to encode + */ +static inline void sph_enc16le(void *dst, unsigned val); + +/** + * Decode a 16-bit unsigned value from memory, in big-endian convention + * (most significant byte comes first). + * + * @param src the source address + * @return the decoded value + */ +static inline unsigned sph_dec16be(const void *src); + +/** + * Encode a 16-bit unsigned value into memory, in big-endian convention + * (most significant byte comes first). + * + * @param dst the destination buffer + * @param val the value to encode + */ +static inline void sph_enc16be(void *dst, unsigned val); + +/** + * Decode a 32-bit unsigned value from memory, in little-endian convention + * (least significant byte comes first). + * + * @param src the source address + * @return the decoded value + */ +static inline sph_u32 sph_dec32le(const void *src); + +/** + * Decode a 32-bit unsigned value from memory, in little-endian convention + * (least significant byte comes first). This function assumes that the + * source address is suitably aligned for a direct access, if the platform + * supports such things; it can thus be marginally faster than the generic + * sph_dec32le() function. + * + * @param src the source address + * @return the decoded value + */ +static inline sph_u32 sph_dec32le_aligned(const void *src); + +/** + * Encode a 32-bit unsigned value into memory, in little-endian convention + * (least significant byte comes first). + * + * @param dst the destination buffer + * @param val the value to encode + */ +static inline void sph_enc32le(void *dst, sph_u32 val); + +/** + * Encode a 32-bit unsigned value into memory, in little-endian convention + * (least significant byte comes first). This function assumes that the + * destination address is suitably aligned for a direct access, if the + * platform supports such things; it can thus be marginally faster than + * the generic sph_enc32le() function. + * + * @param dst the destination buffer + * @param val the value to encode + */ +static inline void sph_enc32le_aligned(void *dst, sph_u32 val); + +/** + * Decode a 32-bit unsigned value from memory, in big-endian convention + * (most significant byte comes first). + * + * @param src the source address + * @return the decoded value + */ +static inline sph_u32 sph_dec32be(const void *src); + +/** + * Decode a 32-bit unsigned value from memory, in big-endian convention + * (most significant byte comes first). This function assumes that the + * source address is suitably aligned for a direct access, if the platform + * supports such things; it can thus be marginally faster than the generic + * sph_dec32be() function. + * + * @param src the source address + * @return the decoded value + */ +static inline sph_u32 sph_dec32be_aligned(const void *src); + +/** + * Encode a 32-bit unsigned value into memory, in big-endian convention + * (most significant byte comes first). + * + * @param dst the destination buffer + * @param val the value to encode + */ +static inline void sph_enc32be(void *dst, sph_u32 val); + +/** + * Encode a 32-bit unsigned value into memory, in big-endian convention + * (most significant byte comes first). This function assumes that the + * destination address is suitably aligned for a direct access, if the + * platform supports such things; it can thus be marginally faster than + * the generic sph_enc32be() function. + * + * @param dst the destination buffer + * @param val the value to encode + */ +static inline void sph_enc32be_aligned(void *dst, sph_u32 val); + +/** + * Decode a 64-bit unsigned value from memory, in little-endian convention + * (least significant byte comes first). This function is defined only + * if a suitable 64-bit type was detected and used for sph_u64. + * + * @param src the source address + * @return the decoded value + */ +static inline sph_u64 sph_dec64le(const void *src); + +/** + * Decode a 64-bit unsigned value from memory, in little-endian convention + * (least significant byte comes first). This function assumes that the + * source address is suitably aligned for a direct access, if the platform + * supports such things; it can thus be marginally faster than the generic + * sph_dec64le() function. This function is defined only + * if a suitable 64-bit type was detected and used for sph_u64. + * + * @param src the source address + * @return the decoded value + */ +static inline sph_u64 sph_dec64le_aligned(const void *src); + +/** + * Encode a 64-bit unsigned value into memory, in little-endian convention + * (least significant byte comes first). This function is defined only + * if a suitable 64-bit type was detected and used for sph_u64. + * + * @param dst the destination buffer + * @param val the value to encode + */ +static inline void sph_enc64le(void *dst, sph_u64 val); + +/** + * Encode a 64-bit unsigned value into memory, in little-endian convention + * (least significant byte comes first). This function assumes that the + * destination address is suitably aligned for a direct access, if the + * platform supports such things; it can thus be marginally faster than + * the generic sph_enc64le() function. This function is defined + * only if a suitable 64-bit type was detected and used for + * sph_u64. + * + * @param dst the destination buffer + * @param val the value to encode + */ +static inline void sph_enc64le_aligned(void *dst, sph_u64 val); + +/** + * Decode a 64-bit unsigned value from memory, in big-endian convention + * (most significant byte comes first). This function is defined only + * if a suitable 64-bit type was detected and used for sph_u64. + * + * @param src the source address + * @return the decoded value + */ +static inline sph_u64 sph_dec64be(const void *src); + +/** + * Decode a 64-bit unsigned value from memory, in big-endian convention + * (most significant byte comes first). This function assumes that the + * source address is suitably aligned for a direct access, if the platform + * supports such things; it can thus be marginally faster than the generic + * sph_dec64be() function. This function is defined only + * if a suitable 64-bit type was detected and used for sph_u64. + * + * @param src the source address + * @return the decoded value + */ +static inline sph_u64 sph_dec64be_aligned(const void *src); + +/** + * Encode a 64-bit unsigned value into memory, in big-endian convention + * (most significant byte comes first). This function is defined only + * if a suitable 64-bit type was detected and used for sph_u64. + * + * @param dst the destination buffer + * @param val the value to encode + */ +static inline void sph_enc64be(void *dst, sph_u64 val); + +/** + * Encode a 64-bit unsigned value into memory, in big-endian convention + * (most significant byte comes first). This function assumes that the + * destination address is suitably aligned for a direct access, if the + * platform supports such things; it can thus be marginally faster than + * the generic sph_enc64be() function. This function is defined + * only if a suitable 64-bit type was detected and used for + * sph_u64. + * + * @param dst the destination buffer + * @param val the value to encode + */ +static inline void sph_enc64be_aligned(void *dst, sph_u64 val); + +#endif + +/* ============== END documentation block for Doxygen ============= */ + +#ifndef DOXYGEN_IGNORE + +/* + * We want to define the types "sph_u32" and "sph_u64" which hold + * unsigned values of at least, respectively, 32 and 64 bits. These + * tests should select appropriate types for most platforms. The + * macro "SPH_64" is defined if the 64-bit is supported. + */ + +#undef SPH_64 +#undef SPH_64_TRUE + +#if defined __STDC__ && __STDC_VERSION__ >= 199901L + +/* + * On C99 implementations, we can use to get an exact 64-bit + * type, if any, or otherwise use a wider type (which must exist, for + * C99 conformance). + */ + +#include + +#ifdef UINT32_MAX +typedef uint32_t sph_u32; +typedef int32_t sph_s32; +#else +typedef uint_fast32_t sph_u32; +typedef int_fast32_t sph_s32; +#endif +#if !SPH_NO_64 +#ifdef UINT64_MAX +typedef uint64_t sph_u64; +typedef int64_t sph_s64; +#else +typedef uint_fast64_t sph_u64; +typedef int_fast64_t sph_s64; +#endif +#endif + +#define SPH_C32(x) ((sph_u32)(x)) +#if !SPH_NO_64 +#define SPH_C64(x) ((sph_u64)(x)) +#define SPH_64 1 +#endif + +#else + +/* + * On non-C99 systems, we use "unsigned int" if it is wide enough, + * "unsigned long" otherwise. This supports all "reasonable" architectures. + * We have to be cautious: pre-C99 preprocessors handle constants + * differently in '#if' expressions. Hence the shifts to test UINT_MAX. + */ + +#if ((UINT_MAX >> 11) >> 11) >= 0x3FF + +typedef unsigned int sph_u32; +typedef int sph_s32; + +#define SPH_C32(x) ((sph_u32)(x ## U)) + +#else + +typedef unsigned long sph_u32; +typedef long sph_s32; + +#define SPH_C32(x) ((sph_u32)(x ## UL)) + +#endif + +#if !SPH_NO_64 + +/* + * We want a 64-bit type. We use "unsigned long" if it is wide enough (as + * is common on 64-bit architectures such as AMD64, Alpha or Sparcv9), + * "unsigned long long" otherwise, if available. We use ULLONG_MAX to + * test whether "unsigned long long" is available; we also know that + * gcc features this type, even if the libc header do not know it. + */ + +#if ((ULONG_MAX >> 31) >> 31) >= 3 + +typedef unsigned long sph_u64; +typedef long sph_s64; + +#define SPH_C64(x) ((sph_u64)(x ## UL)) + +#define SPH_64 1 + +#elif ((ULLONG_MAX >> 31) >> 31) >= 3 || defined __GNUC__ + +typedef unsigned long long sph_u64; +typedef long long sph_s64; + +#define SPH_C64(x) ((sph_u64)(x ## ULL)) + +#define SPH_64 1 + +#else + +/* + * No 64-bit type... + */ + +#endif + +#endif + +#endif + +/* + * If the "unsigned long" type has length 64 bits or more, then this is + * a "true" 64-bit architectures. This is also true with Visual C on + * amd64, even though the "long" type is limited to 32 bits. + */ +#if SPH_64 && (((ULONG_MAX >> 31) >> 31) >= 3 || defined _M_X64) +#define SPH_64_TRUE 1 +#endif + +/* + * Implementation note: some processors have specific opcodes to perform + * a rotation. Recent versions of gcc recognize the expression above and + * use the relevant opcodes, when appropriate. + */ + +#define SPH_T32(x) ((x) & SPH_C32(0xFFFFFFFF)) +#define SPH_ROTL32(x, n) SPH_T32(((x) << (n)) | ((x) >> (32 - (n)))) +#define SPH_ROTR32(x, n) SPH_ROTL32(x, (32 - (n))) + +#if SPH_64 + +#define SPH_T64(x) ((x) & SPH_C64(0xFFFFFFFFFFFFFFFF)) +#define SPH_ROTL64(x, n) SPH_T64(((x) << (n)) | ((x) >> (64 - (n)))) +#define SPH_ROTR64(x, n) SPH_ROTL64(x, (64 - (n))) + +#endif + +#ifndef DOXYGEN_IGNORE +/* + * Define SPH_INLINE to be an "inline" qualifier, if available. We define + * some small macro-like functions which benefit greatly from being inlined. + */ +#if (defined __STDC__ && __STDC_VERSION__ >= 199901L) || defined __GNUC__ +#define SPH_INLINE inline +#elif defined _MSC_VER +#define SPH_INLINE __inline +#else +#define SPH_INLINE +#endif +#endif + +/* + * We define some macros which qualify the architecture. These macros + * may be explicit set externally (e.g. as compiler parameters). The + * code below sets those macros if they are not already defined. + * + * Most macros are boolean, thus evaluate to either zero or non-zero. + * The SPH_UPTR macro is special, in that it evaluates to a C type, + * or is not defined. + * + * SPH_UPTR if defined: unsigned type to cast pointers into + * + * SPH_UNALIGNED non-zero if unaligned accesses are efficient + * SPH_LITTLE_ENDIAN non-zero if architecture is known to be little-endian + * SPH_BIG_ENDIAN non-zero if architecture is known to be big-endian + * SPH_LITTLE_FAST non-zero if little-endian decoding is fast + * SPH_BIG_FAST non-zero if big-endian decoding is fast + * + * If SPH_UPTR is defined, then encoding and decoding of 32-bit and 64-bit + * values will try to be "smart". Either SPH_LITTLE_ENDIAN or SPH_BIG_ENDIAN + * _must_ be non-zero in those situations. The 32-bit and 64-bit types + * _must_ also have an exact width. + * + * SPH_SPARCV9_GCC_32 UltraSPARC-compatible with gcc, 32-bit mode + * SPH_SPARCV9_GCC_64 UltraSPARC-compatible with gcc, 64-bit mode + * SPH_SPARCV9_GCC UltraSPARC-compatible with gcc + * SPH_I386_GCC x86-compatible (32-bit) with gcc + * SPH_I386_MSVC x86-compatible (32-bit) with Microsoft Visual C + * SPH_AMD64_GCC x86-compatible (64-bit) with gcc + * SPH_AMD64_MSVC x86-compatible (64-bit) with Microsoft Visual C + * SPH_PPC32_GCC PowerPC, 32-bit, with gcc + * SPH_PPC64_GCC PowerPC, 64-bit, with gcc + * + * TODO: enhance automatic detection, for more architectures and compilers. + * Endianness is the most important. SPH_UNALIGNED and SPH_UPTR help with + * some very fast functions (e.g. MD4) when using unaligned input data. + * The CPU-specific-with-GCC macros are useful only for inline assembly, + * normally restrained to this header file. + */ + +/* + * 32-bit x86, aka "i386 compatible". + */ +#if defined __i386__ || defined _M_IX86 + +#define SPH_DETECT_UNALIGNED 1 +#define SPH_DETECT_LITTLE_ENDIAN 1 +#define SPH_DETECT_UPTR sph_u32 +#ifdef __GNUC__ +#define SPH_DETECT_I386_GCC 1 +#endif +#ifdef _MSC_VER +#define SPH_DETECT_I386_MSVC 1 +#endif + +/* + * 64-bit x86, hereafter known as "amd64". + */ +#elif defined __x86_64 || defined _M_X64 + +#define SPH_DETECT_UNALIGNED 1 +#define SPH_DETECT_LITTLE_ENDIAN 1 +#define SPH_DETECT_UPTR sph_u64 +#ifdef __GNUC__ +#define SPH_DETECT_AMD64_GCC 1 +#endif +#ifdef _MSC_VER +#define SPH_DETECT_AMD64_MSVC 1 +#endif + +/* + * 64-bit Sparc architecture (implies v9). + */ +#elif ((defined __sparc__ || defined __sparc) && defined __arch64__) \ + || defined __sparcv9 + +#define SPH_DETECT_BIG_ENDIAN 1 +#define SPH_DETECT_UPTR sph_u64 +#ifdef __GNUC__ +#define SPH_DETECT_SPARCV9_GCC_64 1 +#define SPH_DETECT_LITTLE_FAST 1 +#endif + +/* + * 32-bit Sparc. + */ +#elif (defined __sparc__ || defined __sparc) \ + && !(defined __sparcv9 || defined __arch64__) + +#define SPH_DETECT_BIG_ENDIAN 1 +#define SPH_DETECT_UPTR sph_u32 +#if defined __GNUC__ && defined __sparc_v9__ +#define SPH_DETECT_SPARCV9_GCC_32 1 +#define SPH_DETECT_LITTLE_FAST 1 +#endif + +/* + * ARM, little-endian. + */ +#elif defined __arm__ && __ARMEL__ + +#define SPH_DETECT_LITTLE_ENDIAN 1 + +/* + * MIPS, little-endian. + */ +#elif MIPSEL || _MIPSEL || __MIPSEL || __MIPSEL__ + +#define SPH_DETECT_LITTLE_ENDIAN 1 + +/* + * MIPS, big-endian. + */ +#elif MIPSEB || _MIPSEB || __MIPSEB || __MIPSEB__ + +#define SPH_DETECT_BIG_ENDIAN 1 + +/* + * PowerPC. + */ +#elif defined __powerpc__ || defined __POWERPC__ || defined __ppc__ \ + || defined _ARCH_PPC + +/* + * Note: we do not declare cross-endian access to be "fast": even if + * using inline assembly, implementation should still assume that + * keeping the decoded word in a temporary is faster than decoding + * it again. + */ +#if defined __GNUC__ +#if SPH_64_TRUE +#define SPH_DETECT_PPC64_GCC 1 +#else +#define SPH_DETECT_PPC32_GCC 1 +#endif +#endif + +#if defined __BIG_ENDIAN__ || defined _BIG_ENDIAN +#define SPH_DETECT_BIG_ENDIAN 1 +#elif defined __LITTLE_ENDIAN__ || defined _LITTLE_ENDIAN +#define SPH_DETECT_LITTLE_ENDIAN 1 +#endif + +/* + * Itanium, 64-bit. + */ +#elif defined __ia64 || defined __ia64__ \ + || defined __itanium__ || defined _M_IA64 + +#if defined __BIG_ENDIAN__ || defined _BIG_ENDIAN +#define SPH_DETECT_BIG_ENDIAN 1 +#else +#define SPH_DETECT_LITTLE_ENDIAN 1 +#endif +#if defined __LP64__ || defined _LP64 +#define SPH_DETECT_UPTR sph_u64 +#else +#define SPH_DETECT_UPTR sph_u32 +#endif + +#endif + +#if defined SPH_DETECT_SPARCV9_GCC_32 || defined SPH_DETECT_SPARCV9_GCC_64 +#define SPH_DETECT_SPARCV9_GCC 1 +#endif + +#if defined SPH_DETECT_UNALIGNED && !defined SPH_UNALIGNED +#define SPH_UNALIGNED SPH_DETECT_UNALIGNED +#endif +#if defined SPH_DETECT_UPTR && !defined SPH_UPTR +#define SPH_UPTR SPH_DETECT_UPTR +#endif +#if defined SPH_DETECT_LITTLE_ENDIAN && !defined SPH_LITTLE_ENDIAN +#define SPH_LITTLE_ENDIAN SPH_DETECT_LITTLE_ENDIAN +#endif +#if defined SPH_DETECT_BIG_ENDIAN && !defined SPH_BIG_ENDIAN +#define SPH_BIG_ENDIAN SPH_DETECT_BIG_ENDIAN +#endif +#if defined SPH_DETECT_LITTLE_FAST && !defined SPH_LITTLE_FAST +#define SPH_LITTLE_FAST SPH_DETECT_LITTLE_FAST +#endif +#if defined SPH_DETECT_BIG_FAST && !defined SPH_BIG_FAST +#define SPH_BIG_FAST SPH_DETECT_BIG_FAST +#endif +#if defined SPH_DETECT_SPARCV9_GCC_32 && !defined SPH_SPARCV9_GCC_32 +#define SPH_SPARCV9_GCC_32 SPH_DETECT_SPARCV9_GCC_32 +#endif +#if defined SPH_DETECT_SPARCV9_GCC_64 && !defined SPH_SPARCV9_GCC_64 +#define SPH_SPARCV9_GCC_64 SPH_DETECT_SPARCV9_GCC_64 +#endif +#if defined SPH_DETECT_SPARCV9_GCC && !defined SPH_SPARCV9_GCC +#define SPH_SPARCV9_GCC SPH_DETECT_SPARCV9_GCC +#endif +#if defined SPH_DETECT_I386_GCC && !defined SPH_I386_GCC +#define SPH_I386_GCC SPH_DETECT_I386_GCC +#endif +#if defined SPH_DETECT_I386_MSVC && !defined SPH_I386_MSVC +#define SPH_I386_MSVC SPH_DETECT_I386_MSVC +#endif +#if defined SPH_DETECT_AMD64_GCC && !defined SPH_AMD64_GCC +#define SPH_AMD64_GCC SPH_DETECT_AMD64_GCC +#endif +#if defined SPH_DETECT_AMD64_MSVC && !defined SPH_AMD64_MSVC +#define SPH_AMD64_MSVC SPH_DETECT_AMD64_MSVC +#endif +#if defined SPH_DETECT_PPC32_GCC && !defined SPH_PPC32_GCC +#define SPH_PPC32_GCC SPH_DETECT_PPC32_GCC +#endif +#if defined SPH_DETECT_PPC64_GCC && !defined SPH_PPC64_GCC +#define SPH_PPC64_GCC SPH_DETECT_PPC64_GCC +#endif + +#if SPH_LITTLE_ENDIAN && !defined SPH_LITTLE_FAST +#define SPH_LITTLE_FAST 1 +#endif +#if SPH_BIG_ENDIAN && !defined SPH_BIG_FAST +#define SPH_BIG_FAST 1 +#endif + +#if defined SPH_UPTR && !(SPH_LITTLE_ENDIAN || SPH_BIG_ENDIAN) +#error SPH_UPTR defined, but endianness is not known. +#endif + +#if SPH_I386_GCC && !SPH_NO_ASM + +/* + * On x86 32-bit, with gcc, we use the bswapl opcode to byte-swap 32-bit + * values. + */ + +static SPH_INLINE sph_u32 +sph_bswap32(sph_u32 x) +{ + __asm__ __volatile__ ("bswapl %0" : "=r" (x) : "0" (x)); + return x; +} + +#if SPH_64 + +static SPH_INLINE sph_u64 +sph_bswap64(sph_u64 x) +{ + return ((sph_u64)sph_bswap32((sph_u32)x) << 32) + | (sph_u64)sph_bswap32((sph_u32)(x >> 32)); +} + +#endif + +#elif SPH_AMD64_GCC && !SPH_NO_ASM + +/* + * On x86 64-bit, with gcc, we use the bswapl opcode to byte-swap 32-bit + * and 64-bit values. + */ + +static SPH_INLINE sph_u32 +sph_bswap32(sph_u32 x) +{ + __asm__ __volatile__ ("bswapl %0" : "=r" (x) : "0" (x)); + return x; +} + +#if SPH_64 + +static SPH_INLINE sph_u64 +sph_bswap64(sph_u64 x) +{ + __asm__ __volatile__ ("bswapq %0" : "=r" (x) : "0" (x)); + return x; +} + +#endif + +/* + * Disabled code. Apparently, Microsoft Visual C 2005 is smart enough + * to generate proper opcodes for endianness swapping with the pure C + * implementation below. + * + +#elif SPH_I386_MSVC && !SPH_NO_ASM + +static __inline sph_u32 __declspec(naked) __fastcall +sph_bswap32(sph_u32 x) +{ + __asm { + bswap ecx + mov eax,ecx + ret + } +} + +#if SPH_64 + +static SPH_INLINE sph_u64 +sph_bswap64(sph_u64 x) +{ + return ((sph_u64)sph_bswap32((sph_u32)x) << 32) + | (sph_u64)sph_bswap32((sph_u32)(x >> 32)); +} + +#endif + + * + * [end of disabled code] + */ + +#else + +static SPH_INLINE sph_u32 +sph_bswap32(sph_u32 x) +{ + x = SPH_T32((x << 16) | (x >> 16)); + x = ((x & SPH_C32(0xFF00FF00)) >> 8) + | ((x & SPH_C32(0x00FF00FF)) << 8); + return x; +} + +#if SPH_64 + +/** + * Byte-swap a 64-bit value. + * + * @param x the input value + * @return the byte-swapped value + */ +static SPH_INLINE sph_u64 +sph_bswap64(sph_u64 x) +{ + x = SPH_T64((x << 32) | (x >> 32)); + x = ((x & SPH_C64(0xFFFF0000FFFF0000)) >> 16) + | ((x & SPH_C64(0x0000FFFF0000FFFF)) << 16); + x = ((x & SPH_C64(0xFF00FF00FF00FF00)) >> 8) + | ((x & SPH_C64(0x00FF00FF00FF00FF)) << 8); + return x; +} + +#endif + +#endif + +#if SPH_SPARCV9_GCC && !SPH_NO_ASM + +/* + * On UltraSPARC systems, native ordering is big-endian, but it is + * possible to perform little-endian read accesses by specifying the + * address space 0x88 (ASI_PRIMARY_LITTLE). Basically, either we use + * the opcode "lda [%reg]0x88,%dst", where %reg is the register which + * contains the source address and %dst is the destination register, + * or we use "lda [%reg+imm]%asi,%dst", which uses the %asi register + * to get the address space name. The latter format is better since it + * combines an addition and the actual access in a single opcode; but + * it requires the setting (and subsequent resetting) of %asi, which is + * slow. Some operations (i.e. MD5 compression function) combine many + * successive little-endian read accesses, which may share the same + * %asi setting. The macros below contain the appropriate inline + * assembly. + */ + +#define SPH_SPARCV9_SET_ASI \ + sph_u32 sph_sparcv9_asi; \ + __asm__ __volatile__ ( \ + "rd %%asi,%0\n\twr %%g0,0x88,%%asi" : "=r" (sph_sparcv9_asi)); + +#define SPH_SPARCV9_RESET_ASI \ + __asm__ __volatile__ ("wr %%g0,%0,%%asi" : : "r" (sph_sparcv9_asi)); + +#define SPH_SPARCV9_DEC32LE(base, idx) ({ \ + sph_u32 sph_sparcv9_tmp; \ + __asm__ __volatile__ ("lda [%1+" #idx "*4]%%asi,%0" \ + : "=r" (sph_sparcv9_tmp) : "r" (base)); \ + sph_sparcv9_tmp; \ + }) + +#endif + +static SPH_INLINE void +sph_enc16be(void *dst, unsigned val) +{ + ((unsigned char *)dst)[0] = (val >> 8); + ((unsigned char *)dst)[1] = val; +} + +static SPH_INLINE unsigned +sph_dec16be(const void *src) +{ + return ((unsigned)(((const unsigned char *)src)[0]) << 8) + | (unsigned)(((const unsigned char *)src)[1]); +} + +static SPH_INLINE void +sph_enc16le(void *dst, unsigned val) +{ + ((unsigned char *)dst)[0] = val; + ((unsigned char *)dst)[1] = val >> 8; +} + +static SPH_INLINE unsigned +sph_dec16le(const void *src) +{ + return (unsigned)(((const unsigned char *)src)[0]) + | ((unsigned)(((const unsigned char *)src)[1]) << 8); +} + +/** + * Encode a 32-bit value into the provided buffer (big endian convention). + * + * @param dst the destination buffer + * @param val the 32-bit value to encode + */ +static SPH_INLINE void +sph_enc32be(void *dst, sph_u32 val) +{ +#if defined SPH_UPTR +#if SPH_UNALIGNED +#if SPH_LITTLE_ENDIAN + val = sph_bswap32(val); +#endif + *(sph_u32 *)dst = val; +#else + if (((SPH_UPTR)dst & 3) == 0) { +#if SPH_LITTLE_ENDIAN + val = sph_bswap32(val); +#endif + *(sph_u32 *)dst = val; + } else { + ((unsigned char *)dst)[0] = (val >> 24); + ((unsigned char *)dst)[1] = (val >> 16); + ((unsigned char *)dst)[2] = (val >> 8); + ((unsigned char *)dst)[3] = val; + } +#endif +#else + ((unsigned char *)dst)[0] = (val >> 24); + ((unsigned char *)dst)[1] = (val >> 16); + ((unsigned char *)dst)[2] = (val >> 8); + ((unsigned char *)dst)[3] = val; +#endif +} + +/** + * Encode a 32-bit value into the provided buffer (big endian convention). + * The destination buffer must be properly aligned. + * + * @param dst the destination buffer (32-bit aligned) + * @param val the value to encode + */ +static SPH_INLINE void +sph_enc32be_aligned(void *dst, sph_u32 val) +{ +#if SPH_LITTLE_ENDIAN + *(sph_u32 *)dst = sph_bswap32(val); +#elif SPH_BIG_ENDIAN + *(sph_u32 *)dst = val; +#else + ((unsigned char *)dst)[0] = (val >> 24); + ((unsigned char *)dst)[1] = (val >> 16); + ((unsigned char *)dst)[2] = (val >> 8); + ((unsigned char *)dst)[3] = val; +#endif +} + +/** + * Decode a 32-bit value from the provided buffer (big endian convention). + * + * @param src the source buffer + * @return the decoded value + */ +static SPH_INLINE sph_u32 +sph_dec32be(const void *src) +{ +#if defined SPH_UPTR +#if SPH_UNALIGNED +#if SPH_LITTLE_ENDIAN + return sph_bswap32(*(const sph_u32 *)src); +#else + return *(const sph_u32 *)src; +#endif +#else + if (((SPH_UPTR)src & 3) == 0) { +#if SPH_LITTLE_ENDIAN + return sph_bswap32(*(const sph_u32 *)src); +#else + return *(const sph_u32 *)src; +#endif + } else { + return ((sph_u32)(((const unsigned char *)src)[0]) << 24) + | ((sph_u32)(((const unsigned char *)src)[1]) << 16) + | ((sph_u32)(((const unsigned char *)src)[2]) << 8) + | (sph_u32)(((const unsigned char *)src)[3]); + } +#endif +#else + return ((sph_u32)(((const unsigned char *)src)[0]) << 24) + | ((sph_u32)(((const unsigned char *)src)[1]) << 16) + | ((sph_u32)(((const unsigned char *)src)[2]) << 8) + | (sph_u32)(((const unsigned char *)src)[3]); +#endif +} + +/** + * Decode a 32-bit value from the provided buffer (big endian convention). + * The source buffer must be properly aligned. + * + * @param src the source buffer (32-bit aligned) + * @return the decoded value + */ +static SPH_INLINE sph_u32 +sph_dec32be_aligned(const void *src) +{ +#if SPH_LITTLE_ENDIAN + return sph_bswap32(*(const sph_u32 *)src); +#elif SPH_BIG_ENDIAN + return *(const sph_u32 *)src; +#else + return ((sph_u32)(((const unsigned char *)src)[0]) << 24) + | ((sph_u32)(((const unsigned char *)src)[1]) << 16) + | ((sph_u32)(((const unsigned char *)src)[2]) << 8) + | (sph_u32)(((const unsigned char *)src)[3]); +#endif +} + +/** + * Encode a 32-bit value into the provided buffer (little endian convention). + * + * @param dst the destination buffer + * @param val the 32-bit value to encode + */ +static SPH_INLINE void +sph_enc32le(void *dst, sph_u32 val) +{ +#if defined SPH_UPTR +#if SPH_UNALIGNED +#if SPH_BIG_ENDIAN + val = sph_bswap32(val); +#endif + *(sph_u32 *)dst = val; +#else + if (((SPH_UPTR)dst & 3) == 0) { +#if SPH_BIG_ENDIAN + val = sph_bswap32(val); +#endif + *(sph_u32 *)dst = val; + } else { + ((unsigned char *)dst)[0] = val; + ((unsigned char *)dst)[1] = (val >> 8); + ((unsigned char *)dst)[2] = (val >> 16); + ((unsigned char *)dst)[3] = (val >> 24); + } +#endif +#else + ((unsigned char *)dst)[0] = val; + ((unsigned char *)dst)[1] = (val >> 8); + ((unsigned char *)dst)[2] = (val >> 16); + ((unsigned char *)dst)[3] = (val >> 24); +#endif +} + +/** + * Encode a 32-bit value into the provided buffer (little endian convention). + * The destination buffer must be properly aligned. + * + * @param dst the destination buffer (32-bit aligned) + * @param val the value to encode + */ +static SPH_INLINE void +sph_enc32le_aligned(void *dst, sph_u32 val) +{ +#if SPH_LITTLE_ENDIAN + *(sph_u32 *)dst = val; +#elif SPH_BIG_ENDIAN + *(sph_u32 *)dst = sph_bswap32(val); +#else + ((unsigned char *)dst)[0] = val; + ((unsigned char *)dst)[1] = (val >> 8); + ((unsigned char *)dst)[2] = (val >> 16); + ((unsigned char *)dst)[3] = (val >> 24); +#endif +} + +/** + * Decode a 32-bit value from the provided buffer (little endian convention). + * + * @param src the source buffer + * @return the decoded value + */ +static SPH_INLINE sph_u32 +sph_dec32le(const void *src) +{ +#if defined SPH_UPTR +#if SPH_UNALIGNED +#if SPH_BIG_ENDIAN + return sph_bswap32(*(const sph_u32 *)src); +#else + return *(const sph_u32 *)src; +#endif +#else + if (((SPH_UPTR)src & 3) == 0) { +#if SPH_BIG_ENDIAN +#if SPH_SPARCV9_GCC && !SPH_NO_ASM + sph_u32 tmp; + + /* + * "__volatile__" is needed here because without it, + * gcc-3.4.3 miscompiles the code and performs the + * access before the test on the address, thus triggering + * a bus error... + */ + __asm__ __volatile__ ( + "lda [%1]0x88,%0" : "=r" (tmp) : "r" (src)); + return tmp; +/* + * On PowerPC, this turns out not to be worth the effort: the inline + * assembly makes GCC optimizer uncomfortable, which tends to nullify + * the decoding gains. + * + * For most hash functions, using this inline assembly trick changes + * hashing speed by less than 5% and often _reduces_ it. The biggest + * gains are for MD4 (+11%) and CubeHash (+30%). For all others, it is + * less then 10%. The speed gain on CubeHash is probably due to the + * chronic shortage of registers that CubeHash endures; for the other + * functions, the generic code appears to be efficient enough already. + * +#elif (SPH_PPC32_GCC || SPH_PPC64_GCC) && !SPH_NO_ASM + sph_u32 tmp; + + __asm__ __volatile__ ( + "lwbrx %0,0,%1" : "=r" (tmp) : "r" (src)); + return tmp; + */ +#else + return sph_bswap32(*(const sph_u32 *)src); +#endif +#else + return *(const sph_u32 *)src; +#endif + } else { + return (sph_u32)(((const unsigned char *)src)[0]) + | ((sph_u32)(((const unsigned char *)src)[1]) << 8) + | ((sph_u32)(((const unsigned char *)src)[2]) << 16) + | ((sph_u32)(((const unsigned char *)src)[3]) << 24); + } +#endif +#else + return (sph_u32)(((const unsigned char *)src)[0]) + | ((sph_u32)(((const unsigned char *)src)[1]) << 8) + | ((sph_u32)(((const unsigned char *)src)[2]) << 16) + | ((sph_u32)(((const unsigned char *)src)[3]) << 24); +#endif +} + +/** + * Decode a 32-bit value from the provided buffer (little endian convention). + * The source buffer must be properly aligned. + * + * @param src the source buffer (32-bit aligned) + * @return the decoded value + */ +static SPH_INLINE sph_u32 +sph_dec32le_aligned(const void *src) +{ +#if SPH_LITTLE_ENDIAN + return *(const sph_u32 *)src; +#elif SPH_BIG_ENDIAN +#if SPH_SPARCV9_GCC && !SPH_NO_ASM + sph_u32 tmp; + + __asm__ __volatile__ ("lda [%1]0x88,%0" : "=r" (tmp) : "r" (src)); + return tmp; +/* + * Not worth it generally. + * +#elif (SPH_PPC32_GCC || SPH_PPC64_GCC) && !SPH_NO_ASM + sph_u32 tmp; + + __asm__ __volatile__ ("lwbrx %0,0,%1" : "=r" (tmp) : "r" (src)); + return tmp; + */ +#else + return sph_bswap32(*(const sph_u32 *)src); +#endif +#else + return (sph_u32)(((const unsigned char *)src)[0]) + | ((sph_u32)(((const unsigned char *)src)[1]) << 8) + | ((sph_u32)(((const unsigned char *)src)[2]) << 16) + | ((sph_u32)(((const unsigned char *)src)[3]) << 24); +#endif +} + +#if SPH_64 + +/** + * Encode a 64-bit value into the provided buffer (big endian convention). + * + * @param dst the destination buffer + * @param val the 64-bit value to encode + */ +static SPH_INLINE void +sph_enc64be(void *dst, sph_u64 val) +{ +#if defined SPH_UPTR +#if SPH_UNALIGNED +#if SPH_LITTLE_ENDIAN + val = sph_bswap64(val); +#endif + *(sph_u64 *)dst = val; +#else + if (((SPH_UPTR)dst & 7) == 0) { +#if SPH_LITTLE_ENDIAN + val = sph_bswap64(val); +#endif + *(sph_u64 *)dst = val; + } else { + ((unsigned char *)dst)[0] = (val >> 56); + ((unsigned char *)dst)[1] = (val >> 48); + ((unsigned char *)dst)[2] = (val >> 40); + ((unsigned char *)dst)[3] = (val >> 32); + ((unsigned char *)dst)[4] = (val >> 24); + ((unsigned char *)dst)[5] = (val >> 16); + ((unsigned char *)dst)[6] = (val >> 8); + ((unsigned char *)dst)[7] = val; + } +#endif +#else + ((unsigned char *)dst)[0] = (val >> 56); + ((unsigned char *)dst)[1] = (val >> 48); + ((unsigned char *)dst)[2] = (val >> 40); + ((unsigned char *)dst)[3] = (val >> 32); + ((unsigned char *)dst)[4] = (val >> 24); + ((unsigned char *)dst)[5] = (val >> 16); + ((unsigned char *)dst)[6] = (val >> 8); + ((unsigned char *)dst)[7] = val; +#endif +} + +/** + * Encode a 64-bit value into the provided buffer (big endian convention). + * The destination buffer must be properly aligned. + * + * @param dst the destination buffer (64-bit aligned) + * @param val the value to encode + */ +static SPH_INLINE void +sph_enc64be_aligned(void *dst, sph_u64 val) +{ +#if SPH_LITTLE_ENDIAN + *(sph_u64 *)dst = sph_bswap64(val); +#elif SPH_BIG_ENDIAN + *(sph_u64 *)dst = val; +#else + ((unsigned char *)dst)[0] = (val >> 56); + ((unsigned char *)dst)[1] = (val >> 48); + ((unsigned char *)dst)[2] = (val >> 40); + ((unsigned char *)dst)[3] = (val >> 32); + ((unsigned char *)dst)[4] = (val >> 24); + ((unsigned char *)dst)[5] = (val >> 16); + ((unsigned char *)dst)[6] = (val >> 8); + ((unsigned char *)dst)[7] = val; +#endif +} + +/** + * Decode a 64-bit value from the provided buffer (big endian convention). + * + * @param src the source buffer + * @return the decoded value + */ +static SPH_INLINE sph_u64 +sph_dec64be(const void *src) +{ +#if defined SPH_UPTR +#if SPH_UNALIGNED +#if SPH_LITTLE_ENDIAN + return sph_bswap64(*(const sph_u64 *)src); +#else + return *(const sph_u64 *)src; +#endif +#else + if (((SPH_UPTR)src & 7) == 0) { +#if SPH_LITTLE_ENDIAN + return sph_bswap64(*(const sph_u64 *)src); +#else + return *(const sph_u64 *)src; +#endif + } else { + return ((sph_u64)(((const unsigned char *)src)[0]) << 56) + | ((sph_u64)(((const unsigned char *)src)[1]) << 48) + | ((sph_u64)(((const unsigned char *)src)[2]) << 40) + | ((sph_u64)(((const unsigned char *)src)[3]) << 32) + | ((sph_u64)(((const unsigned char *)src)[4]) << 24) + | ((sph_u64)(((const unsigned char *)src)[5]) << 16) + | ((sph_u64)(((const unsigned char *)src)[6]) << 8) + | (sph_u64)(((const unsigned char *)src)[7]); + } +#endif +#else + return ((sph_u64)(((const unsigned char *)src)[0]) << 56) + | ((sph_u64)(((const unsigned char *)src)[1]) << 48) + | ((sph_u64)(((const unsigned char *)src)[2]) << 40) + | ((sph_u64)(((const unsigned char *)src)[3]) << 32) + | ((sph_u64)(((const unsigned char *)src)[4]) << 24) + | ((sph_u64)(((const unsigned char *)src)[5]) << 16) + | ((sph_u64)(((const unsigned char *)src)[6]) << 8) + | (sph_u64)(((const unsigned char *)src)[7]); +#endif +} + +/** + * Decode a 64-bit value from the provided buffer (big endian convention). + * The source buffer must be properly aligned. + * + * @param src the source buffer (64-bit aligned) + * @return the decoded value + */ +static SPH_INLINE sph_u64 +sph_dec64be_aligned(const void *src) +{ +#if SPH_LITTLE_ENDIAN + return sph_bswap64(*(const sph_u64 *)src); +#elif SPH_BIG_ENDIAN + return *(const sph_u64 *)src; +#else + return ((sph_u64)(((const unsigned char *)src)[0]) << 56) + | ((sph_u64)(((const unsigned char *)src)[1]) << 48) + | ((sph_u64)(((const unsigned char *)src)[2]) << 40) + | ((sph_u64)(((const unsigned char *)src)[3]) << 32) + | ((sph_u64)(((const unsigned char *)src)[4]) << 24) + | ((sph_u64)(((const unsigned char *)src)[5]) << 16) + | ((sph_u64)(((const unsigned char *)src)[6]) << 8) + | (sph_u64)(((const unsigned char *)src)[7]); +#endif +} + +/** + * Encode a 64-bit value into the provided buffer (little endian convention). + * + * @param dst the destination buffer + * @param val the 64-bit value to encode + */ +static SPH_INLINE void +sph_enc64le(void *dst, sph_u64 val) +{ +#if defined SPH_UPTR +#if SPH_UNALIGNED +#if SPH_BIG_ENDIAN + val = sph_bswap64(val); +#endif + *(sph_u64 *)dst = val; +#else + if (((SPH_UPTR)dst & 7) == 0) { +#if SPH_BIG_ENDIAN + val = sph_bswap64(val); +#endif + *(sph_u64 *)dst = val; + } else { + ((unsigned char *)dst)[0] = val; + ((unsigned char *)dst)[1] = (val >> 8); + ((unsigned char *)dst)[2] = (val >> 16); + ((unsigned char *)dst)[3] = (val >> 24); + ((unsigned char *)dst)[4] = (val >> 32); + ((unsigned char *)dst)[5] = (val >> 40); + ((unsigned char *)dst)[6] = (val >> 48); + ((unsigned char *)dst)[7] = (val >> 56); + } +#endif +#else + ((unsigned char *)dst)[0] = val; + ((unsigned char *)dst)[1] = (val >> 8); + ((unsigned char *)dst)[2] = (val >> 16); + ((unsigned char *)dst)[3] = (val >> 24); + ((unsigned char *)dst)[4] = (val >> 32); + ((unsigned char *)dst)[5] = (val >> 40); + ((unsigned char *)dst)[6] = (val >> 48); + ((unsigned char *)dst)[7] = (val >> 56); +#endif +} + +/** + * Encode a 64-bit value into the provided buffer (little endian convention). + * The destination buffer must be properly aligned. + * + * @param dst the destination buffer (64-bit aligned) + * @param val the value to encode + */ +static SPH_INLINE void +sph_enc64le_aligned(void *dst, sph_u64 val) +{ +#if SPH_LITTLE_ENDIAN + *(sph_u64 *)dst = val; +#elif SPH_BIG_ENDIAN + *(sph_u64 *)dst = sph_bswap64(val); +#else + ((unsigned char *)dst)[0] = val; + ((unsigned char *)dst)[1] = (val >> 8); + ((unsigned char *)dst)[2] = (val >> 16); + ((unsigned char *)dst)[3] = (val >> 24); + ((unsigned char *)dst)[4] = (val >> 32); + ((unsigned char *)dst)[5] = (val >> 40); + ((unsigned char *)dst)[6] = (val >> 48); + ((unsigned char *)dst)[7] = (val >> 56); +#endif +} + +/** + * Decode a 64-bit value from the provided buffer (little endian convention). + * + * @param src the source buffer + * @return the decoded value + */ +static SPH_INLINE sph_u64 +sph_dec64le(const void *src) +{ +#if defined SPH_UPTR +#if SPH_UNALIGNED +#if SPH_BIG_ENDIAN + return sph_bswap64(*(const sph_u64 *)src); +#else + return *(const sph_u64 *)src; +#endif +#else + if (((SPH_UPTR)src & 7) == 0) { +#if SPH_BIG_ENDIAN +#if SPH_SPARCV9_GCC_64 && !SPH_NO_ASM + sph_u64 tmp; + + __asm__ __volatile__ ( + "ldxa [%1]0x88,%0" : "=r" (tmp) : "r" (src)); + return tmp; +/* + * Not worth it generally. + * +#elif SPH_PPC32_GCC && !SPH_NO_ASM + return (sph_u64)sph_dec32le_aligned(src) + | ((sph_u64)sph_dec32le_aligned( + (const char *)src + 4) << 32); +#elif SPH_PPC64_GCC && !SPH_NO_ASM + sph_u64 tmp; + + __asm__ __volatile__ ( + "ldbrx %0,0,%1" : "=r" (tmp) : "r" (src)); + return tmp; + */ +#else + return sph_bswap64(*(const sph_u64 *)src); +#endif +#else + return *(const sph_u64 *)src; +#endif + } else { + return (sph_u64)(((const unsigned char *)src)[0]) + | ((sph_u64)(((const unsigned char *)src)[1]) << 8) + | ((sph_u64)(((const unsigned char *)src)[2]) << 16) + | ((sph_u64)(((const unsigned char *)src)[3]) << 24) + | ((sph_u64)(((const unsigned char *)src)[4]) << 32) + | ((sph_u64)(((const unsigned char *)src)[5]) << 40) + | ((sph_u64)(((const unsigned char *)src)[6]) << 48) + | ((sph_u64)(((const unsigned char *)src)[7]) << 56); + } +#endif +#else + return (sph_u64)(((const unsigned char *)src)[0]) + | ((sph_u64)(((const unsigned char *)src)[1]) << 8) + | ((sph_u64)(((const unsigned char *)src)[2]) << 16) + | ((sph_u64)(((const unsigned char *)src)[3]) << 24) + | ((sph_u64)(((const unsigned char *)src)[4]) << 32) + | ((sph_u64)(((const unsigned char *)src)[5]) << 40) + | ((sph_u64)(((const unsigned char *)src)[6]) << 48) + | ((sph_u64)(((const unsigned char *)src)[7]) << 56); +#endif +} + +/** + * Decode a 64-bit value from the provided buffer (little endian convention). + * The source buffer must be properly aligned. + * + * @param src the source buffer (64-bit aligned) + * @return the decoded value + */ +static SPH_INLINE sph_u64 +sph_dec64le_aligned(const void *src) +{ +#if SPH_LITTLE_ENDIAN + return *(const sph_u64 *)src; +#elif SPH_BIG_ENDIAN +#if SPH_SPARCV9_GCC_64 && !SPH_NO_ASM + sph_u64 tmp; + + __asm__ __volatile__ ("ldxa [%1]0x88,%0" : "=r" (tmp) : "r" (src)); + return tmp; +/* + * Not worth it generally. + * +#elif SPH_PPC32_GCC && !SPH_NO_ASM + return (sph_u64)sph_dec32le_aligned(src) + | ((sph_u64)sph_dec32le_aligned((const char *)src + 4) << 32); +#elif SPH_PPC64_GCC && !SPH_NO_ASM + sph_u64 tmp; + + __asm__ __volatile__ ("ldbrx %0,0,%1" : "=r" (tmp) : "r" (src)); + return tmp; + */ +#else + return sph_bswap64(*(const sph_u64 *)src); +#endif +#else + return (sph_u64)(((const unsigned char *)src)[0]) + | ((sph_u64)(((const unsigned char *)src)[1]) << 8) + | ((sph_u64)(((const unsigned char *)src)[2]) << 16) + | ((sph_u64)(((const unsigned char *)src)[3]) << 24) + | ((sph_u64)(((const unsigned char *)src)[4]) << 32) + | ((sph_u64)(((const unsigned char *)src)[5]) << 40) + | ((sph_u64)(((const unsigned char *)src)[6]) << 48) + | ((sph_u64)(((const unsigned char *)src)[7]) << 56); +#endif +} + +#endif + +#endif /* Doxygen excluded block */ + +#endif diff --git a/hasher.c b/hasher.c index 69c9219ea..93881be61 100644 --- a/hasher.c +++ b/hasher.c @@ -34,6 +34,9 @@ void hasher_Init(Hasher *hasher, HasherType type) { case HASHER_BLAKED: blake256_Init(&hasher->ctx.blake); break; + case HASHER_GROESTL: + groestl512_Init(&hasher->ctx.groestl); + break; } } @@ -51,6 +54,9 @@ void hasher_Update(Hasher *hasher, const uint8_t *data, size_t length) { case HASHER_BLAKED: blake256_Update(&hasher->ctx.blake, data, length); break; + case HASHER_GROESTL: + groestl512_Update(&hasher->ctx.groestl, data, length); + break; } } @@ -64,6 +70,9 @@ void hasher_Final(Hasher *hasher, uint8_t hash[HASHER_DIGEST_LENGTH]) { case HASHER_BLAKED: blake256_Final(&hasher->ctx.blake, hash); break; + case HASHER_GROESTL: + groestl512_Final(&hasher->ctx.groestl, hash); + break; } switch (hasher->type) { diff --git a/hasher.h b/hasher.h index 575617031..4fa722f50 100644 --- a/hasher.h +++ b/hasher.h @@ -28,6 +28,7 @@ #include "sha2.h" #include "blake256.h" +#include "groestl.h" #define HASHER_DIGEST_LENGTH 32 @@ -37,6 +38,8 @@ typedef enum { HASHER_SHA2D, HASHER_BLAKED, + + HASHER_GROESTL, } HasherType; typedef struct { @@ -45,6 +48,7 @@ typedef struct { union { SHA256_CTX sha2; BLAKE256_CTX blake; + GROESTL512_CTX groestl; } ctx; } Hasher; From 08512053c45b5d41c5026acfb1e1b5e866e8cf5c Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Wed, 4 Apr 2018 18:34:07 +0700 Subject: [PATCH 545/627] Groestl hash: do it twice and truncate to 256 bits --- groestl.c | 12 ++++++++++++ groestl.h | 3 +++ hasher.c | 12 +++++------- hasher.h | 2 +- 4 files changed, 21 insertions(+), 8 deletions(-) diff --git a/groestl.c b/groestl.c index a0c986fbc..260863e29 100644 --- a/groestl.c +++ b/groestl.c @@ -3105,6 +3105,18 @@ groestl512_Final(void *cc, void *dst) groestl_big_close((sph_groestl_big_context *)cc, 0, 0, dst, 64); } +void +groestl512_DoubleTrunc(void *cc, void *dst) +{ + char buf[64]; + + groestl512_Final(cc, buf); + groestl512_Init(cc); + groestl512_Update(cc, buf, sizeof(buf)); + groestl512_Final(cc, buf); + memcpy(dst, buf, 32); +} + /* see sph_groestl.h */ void sph_groestl512_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) diff --git a/groestl.h b/groestl.h index 49506622d..08263f3da 100644 --- a/groestl.h +++ b/groestl.h @@ -302,6 +302,9 @@ void groestl512_Update(void *cc, const void *data, size_t len); */ void groestl512_Final(void *cc, void *dst); + +void groestl512_DoubleTrunc(void *cc, void *dst); + /** * Add a few additional bits (0 to 7) to the current computation, then * terminate it and output the result in the provided buffer, which must diff --git a/hasher.c b/hasher.c index 93881be61..b8d0b919b 100644 --- a/hasher.c +++ b/hasher.c @@ -34,7 +34,7 @@ void hasher_Init(Hasher *hasher, HasherType type) { case HASHER_BLAKED: blake256_Init(&hasher->ctx.blake); break; - case HASHER_GROESTL: + case HASHER_GROESTLD_TRUNC: groestl512_Init(&hasher->ctx.groestl); break; } @@ -54,7 +54,7 @@ void hasher_Update(Hasher *hasher, const uint8_t *data, size_t length) { case HASHER_BLAKED: blake256_Update(&hasher->ctx.blake, data, length); break; - case HASHER_GROESTL: + case HASHER_GROESTLD_TRUNC: groestl512_Update(&hasher->ctx.groestl, data, length); break; } @@ -70,20 +70,18 @@ void hasher_Final(Hasher *hasher, uint8_t hash[HASHER_DIGEST_LENGTH]) { case HASHER_BLAKED: blake256_Final(&hasher->ctx.blake, hash); break; - case HASHER_GROESTL: - groestl512_Final(&hasher->ctx.groestl, hash); - break; + case HASHER_GROESTLD_TRUNC: + groestl512_DoubleTrunc(&hasher->ctx.groestl, hash); + return; } switch (hasher->type) { case HASHER_SHA2D: hasher_Raw(HASHER_SHA2, hash, HASHER_DIGEST_LENGTH, hash); break; - case HASHER_BLAKED: hasher_Raw(HASHER_BLAKE, hash, HASHER_DIGEST_LENGTH, hash); break; - default: break; } diff --git a/hasher.h b/hasher.h index 4fa722f50..673cf9fa7 100644 --- a/hasher.h +++ b/hasher.h @@ -39,7 +39,7 @@ typedef enum { HASHER_SHA2D, HASHER_BLAKED, - HASHER_GROESTL, + HASHER_GROESTLD_TRUNC, /* Double Groestl512 hasher truncated to 256 bits */ } HasherType; typedef struct { From 5cb15e34204f34e38c6581c758cdcc8ca5a647b8 Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Wed, 4 Apr 2018 18:58:41 +0700 Subject: [PATCH 546/627] Add tests for GRS addresses --- tests/test_check.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/test_check.c b/tests/test_check.c index 7b6a335ba..0fc5a6d34 100644 --- a/tests/test_check.c +++ b/tests/test_check.c @@ -2781,6 +2781,7 @@ START_TEST(test_address) ecdsa_get_address(pub_key, 111, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "mhfJsQNnrXB3uuYZqvywARTDfuvyjg4RBh"); ecdsa_get_address(pub_key, 52, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "MxiimznnxsqMfLKTQBL8Z2PoY9jKpjgkCu"); ecdsa_get_address(pub_key, 48, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "LMNJqZbe89yrPbm7JVzrcXJf28hZ1rKPaH"); + ecdsa_get_address(pub_key, 36, HASHER_SHA2, HASHER_GROESTLD_TRUNC, address, sizeof(address)); ck_assert_str_eq(address, "FXK52G2BbzRLaQ651U12o23DU5cEQdhvU6"); ecdsa_get_address_segwit_p2sh(pub_key, 5, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "34PyTHn74syS796eTgsyoLfwoBC3cwLn6p"); memcpy(pub_key, fromhex("025b1654a0e78d28810094f6c5a96b8efb8a65668b578f170ac2b1f83bc63ba856"), 33); @@ -2788,6 +2789,7 @@ START_TEST(test_address) ecdsa_get_address(pub_key, 111, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "mp4txp8vXvFLy8So5Y2kFTVrt2epN6YzdP"); ecdsa_get_address(pub_key, 52, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "N58JsQYveGueiZDgdnNwe4SSkGTAToutAY"); ecdsa_get_address(pub_key, 48, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "LTmtvyMmoZ49SpfLY73fhZMJEFRPdyohKh"); + ecdsa_get_address(pub_key, 36, HASHER_SHA2, HASHER_GROESTLD_TRUNC, address, sizeof(address)); ck_assert_str_eq(address, "Fdif7fnKHPVddczJF53qt45rgCL51yWN6x"); ecdsa_get_address_segwit_p2sh(pub_key, 5, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "35trq6eeuHf6VL9L8pQv46x3vegHnHoTuB"); memcpy(pub_key, fromhex("03433f246a12e6486a51ff08802228c61cf895175a9b49ed4766ea9a9294a3c7fe"), 33); @@ -2795,6 +2797,7 @@ START_TEST(test_address) ecdsa_get_address(pub_key, 111, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "mv2BKes2AY8rqXCFKp4Yk9j9B6iaMfWRLN"); ecdsa_get_address(pub_key, 52, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "NB5bEFH2GtoAawy8t4Qk8kfj3LWvQs3MhB"); ecdsa_get_address(pub_key, 48, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "LZjBHp5sSAwfKDQnnP5UCFaaXKV9YheGxQ"); + ecdsa_get_address(pub_key, 36, HASHER_SHA2, HASHER_GROESTLD_TRUNC, address, sizeof(address)); ck_assert_str_eq(address, "FjfwUWWQv1P9W1jkVM5eNkK8yGPq5XyZZy"); ecdsa_get_address_segwit_p2sh(pub_key, 5, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "3456DYaKUWuY6RWWw8Hp5CftHLcQN29h9Y"); memcpy(pub_key, fromhex("03aeb03abeee0f0f8b4f7a5d65ce31f9570cef9f72c2dd8a19b4085a30ab033d48"), 33); @@ -2802,6 +2805,7 @@ START_TEST(test_address) ecdsa_get_address(pub_key, 111, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "mgVoreDcWf6BaxJ5wqgQiPpwLEFRLSr8U8"); ecdsa_get_address(pub_key, 52, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "MwZDmEdcd1kVLP4yW62c6zmXCU3mNbveDo"); ecdsa_get_address(pub_key, 48, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "LLCopoSTnHtz4eWdQQhLAVgNgT1zTi4QBK"); + ecdsa_get_address(pub_key, 36, HASHER_SHA2, HASHER_GROESTLD_TRUNC, address, sizeof(address)); ck_assert_str_eq(address, "FW9a1Vs1G8LUFSqb7NhWLzQw8PvfwAxmxA"); ecdsa_get_address_segwit_p2sh(pub_key, 5, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "3DBU4tJ9tkMR9fnmCtjW48kjvseoNLQZXd"); memcpy(pub_key, fromhex("0496e8f2093f018aff6c2e2da5201ee528e2c8accbf9cac51563d33a7bb74a016054201c025e2a5d96b1629b95194e806c63eb96facaedc733b1a4b70ab3b33e3a"), 65); @@ -2809,18 +2813,21 @@ START_TEST(test_address) ecdsa_get_address(pub_key, 111, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "moaPreR5tydT3J4wbvrMLFSQi9TjPCiZc6"); ecdsa_get_address(pub_key, 52, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "N4domEq61LHkniqqABCYirNzaPG5NRU8GH"); ecdsa_get_address(pub_key, 48, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "LTHPpodwAcSFWzHV4VsGnMHr4NEJajMnKX"); + ecdsa_get_address(pub_key, 36, HASHER_SHA2, HASHER_GROESTLD_TRUNC, address, sizeof(address)); ck_assert_str_eq(address, "FdEA1W4UeSsjhncSmTsSxr2QWK8z2xGkjc"); memcpy(pub_key, fromhex("0498010f8a687439ff497d3074beb4519754e72c4b6220fb669224749591dde416f3961f8ece18f8689bb32235e436874d2174048b86118a00afbd5a4f33a24f0f"), 65); ecdsa_get_address(pub_key, 0, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "1A2WfBD4BJFwYHFPc5KgktqtbdJLBuVKc4"); ecdsa_get_address(pub_key, 111, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "mpYTxEJ2zKhCKPj1KeJ4ap4DTcu39T3uzD"); ecdsa_get_address(pub_key, 52, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "N5bsrpi36gMW4pVtsteFyQzoKrhPE7nkxK"); ecdsa_get_address(pub_key, 48, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "LUFTvPWtFxVzo5wYnDJz2uueoqfcMYiuxH"); + ecdsa_get_address(pub_key, 36, HASHER_SHA2, HASHER_GROESTLD_TRUNC, address, sizeof(address)); ck_assert_str_eq(address, "FeCE75wRjnwUytGWVBKADQeDFnaHpJ8t3B"); memcpy(pub_key, fromhex("04f80490839af36d13701ec3f9eebdac901b51c362119d74553a3c537faff31b17e2a59ebddbdac9e87b816307a7ed5b826b8f40b92719086238e1bebf19b77a4d"), 65); ecdsa_get_address(pub_key, 0, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "19J81hrPnQxg9UGx45ibTieCkb2ttm8CLL"); ecdsa_get_address(pub_key, 111, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "mop5JkwNbSPvvakZmegyHdrXcadbjLazww"); ecdsa_get_address(pub_key, 52, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "N4sVDMMNho4Eg1XTKu3AgEo7UpRwq3aNbn"); ecdsa_get_address(pub_key, 48, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "LTX5GvADs5CjQGy7EDhtjjhxxoQB2Uhicd"); + ecdsa_get_address(pub_key, 36, HASHER_SHA2, HASHER_GROESTLD_TRUNC, address, sizeof(address)); ck_assert_str_eq(address, "FdTqTcamLueDb5J4wBi4vESXQkJrS54H6k"); } END_TEST From e7281cf9f5145cd81a9789a91efc8c9f0567cee8 Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Wed, 4 Apr 2018 19:39:56 +0700 Subject: [PATCH 547/627] Add GRS curve --- bip32.c | 3 +++ curves.c | 1 + curves.h | 1 + secp256k1.c | 9 +++++++++ secp256k1.h | 1 + 5 files changed, 15 insertions(+) diff --git a/bip32.c b/bip32.c index 8fd2d1ebe..aa044bf8e 100644 --- a/bip32.c +++ b/bip32.c @@ -687,6 +687,9 @@ const curve_info *get_curve_by_name(const char *curve_name) { if (strcmp(curve_name, SECP256K1_DECRED_NAME) == 0) { return &secp256k1_decred_info; } + if (strcmp(curve_name, SECP256K1_GROESTL_NAME) == 0) { + return &secp256k1_groestl_info; + } if (strcmp(curve_name, NIST256P1_NAME) == 0) { return &nist256p1_info; } diff --git a/curves.c b/curves.c index f81ea28ad..5ff645c26 100644 --- a/curves.c +++ b/curves.c @@ -24,6 +24,7 @@ const char SECP256K1_NAME[] = "secp256k1"; const char SECP256K1_DECRED_NAME[] = "secp256k1-decred"; +const char SECP256K1_GROESTL_NAME[] = "secp256k1-groestl"; const char NIST256P1_NAME[] = "nist256p1"; const char ED25519_NAME[] = "ed25519"; const char ED25519_SHA3_NAME[] = "ed25519-sha3"; diff --git a/curves.h b/curves.h index 9257dcc10..5fbab0f41 100644 --- a/curves.h +++ b/curves.h @@ -27,6 +27,7 @@ extern const char SECP256K1_NAME[]; extern const char SECP256K1_DECRED_NAME[]; +extern const char SECP256K1_GROESTL_NAME[]; extern const char NIST256P1_NAME[]; extern const char ED25519_NAME[]; extern const char ED25519_SHA3_NAME[]; diff --git a/secp256k1.c b/secp256k1.c index 033a34636..0f5ab1afa 100644 --- a/secp256k1.c +++ b/secp256k1.c @@ -72,3 +72,12 @@ const curve_info secp256k1_decred_info = { .hasher_sign = HASHER_BLAKE, .hasher_pubkey = HASHER_BLAKE, }; + +const curve_info secp256k1_groestl_info = { + .bip32_name = "Bitcoin seed", + .params = &secp256k1, + .hasher_bip32 = HASHER_SHA2, + .hasher_base58 = HASHER_GROESTLD_TRUNC, + .hasher_sign = HASHER_SHA2, + .hasher_pubkey = HASHER_SHA2, +}; diff --git a/secp256k1.h b/secp256k1.h index 803cde263..a5442e50c 100644 --- a/secp256k1.h +++ b/secp256k1.h @@ -32,5 +32,6 @@ extern const ecdsa_curve secp256k1; extern const curve_info secp256k1_info; extern const curve_info secp256k1_decred_info; +extern const curve_info secp256k1_groestl_info; #endif From 9e08e8ce634f932f4c2c881583e71890b495e8ad Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Thu, 5 Apr 2018 00:28:42 +0700 Subject: [PATCH 548/627] Groestl hash cleanup - Remove unused code - Remove x86 specific optimizations (to test code which closer to ARM on emulator) - Fix -Wundef warnings --- Makefile | 1 + groestl.c | 2071 +------------------------------------------- groestl.h | 227 +---- groestl_internal.h | 1535 +------------------------------- 4 files changed, 41 insertions(+), 3793 deletions(-) diff --git a/Makefile b/Makefile index 851db5b02..25682d241 100644 --- a/Makefile +++ b/Makefile @@ -10,6 +10,7 @@ CFLAGS += $(OPTFLAGS) \ -Wimplicit-function-declaration \ -Wredundant-decls \ -Wstrict-prototypes \ + -Wundef \ -Wpointer-arith \ -Wformat \ -Wreturn-type \ diff --git a/groestl.c b/groestl.c index 260863e29..8db8bb339 100644 --- a/groestl.c +++ b/groestl.c @@ -1,4 +1,5 @@ -/* $Id: groestl.c 260 2011-07-21 01:02:38Z tp $ */ +/* Groestl hash from https://github.com/Groestlcoin/vanitygen + * Trezor adaptation by Yura Pakhuchiy . */ /* * Groestl implementation. * @@ -33,51 +34,9 @@ #include #include -#define SPH_SMALL_FOOTPRINT 1 - +#include "groestl_internal.h" #include "groestl.h" -#if SPH_SMALL_FOOTPRINT && !defined SPH_SMALL_FOOTPRINT_GROESTL -#define SPH_SMALL_FOOTPRINT_GROESTL 1 -#endif - -/* - * Apparently, the 32-bit-only version is not faster than the 64-bit - * version unless using the "small footprint" code on a 32-bit machine. - */ -#if !defined SPH_GROESTL_64 -#if SPH_SMALL_FOOTPRINT_GROESTL && !SPH_64_TRUE -#define SPH_GROESTL_64 0 -#else -#define SPH_GROESTL_64 1 -#endif -#endif - -#if !SPH_64 -#undef SPH_GROESTL_64 -#endif - -#ifdef _MSC_VER -#pragma warning (disable: 4146) -#endif - -/* - * The internal representation may use either big-endian or - * little-endian. Using the platform default representation speeds up - * encoding and decoding between bytes and the matrix columns. - */ - -#undef USE_LE -#if SPH_GROESTL_LITTLE_ENDIAN -#define USE_LE 1 -#elif SPH_GROESTL_BIG_ENDIAN -#define USE_LE 0 -#elif SPH_LITTLE_ENDIAN -#define USE_LE 1 -#endif - -#if USE_LE - #define C32e(x) ((SPH_C32(x) >> 24) \ | ((SPH_C32(x) >> 8) & SPH_C32(0x0000FF00)) \ | ((SPH_C32(x) << 8) & SPH_C32(0x00FF0000)) \ @@ -97,7 +56,6 @@ #define QC32up(j, r) SPH_C32(0xFFFFFFFF) #define QC32dn(j, r) (((sph_u32)(r) << 24) ^ SPH_T32(~((sph_u32)(j) << 24))) -#if SPH_64 #define C64e(x) ((SPH_C64(x) >> 56) \ | ((SPH_C64(x) >> 40) & SPH_C64(0x000000000000FF00)) \ | ((SPH_C64(x) >> 24) & SPH_C64(0x0000000000FF0000)) \ @@ -119,1550 +77,7 @@ #define R64 SPH_ROTL64 #define PC64(j, r) ((sph_u64)((j) + (r))) #define QC64(j, r) (((sph_u64)(r) << 56) ^ SPH_T64(~((sph_u64)(j) << 56))) -#endif - -#else - -#define C32e(x) SPH_C32(x) -#define dec32e_aligned sph_dec32be_aligned -#define enc32e sph_enc32be -#define B32_0(x) ((x) >> 24) -#define B32_1(x) (((x) >> 16) & 0xFF) -#define B32_2(x) (((x) >> 8) & 0xFF) -#define B32_3(x) ((x) & 0xFF) - -#define R32u(u, d) SPH_T32(((u) >> 16) | ((d) << 16)) -#define R32d(u, d) SPH_T32(((u) << 16) | ((d) >> 16)) - -#define PC32up(j, r) ((sph_u32)((j) + (r)) << 24) -#define PC32dn(j, r) 0 -#define QC32up(j, r) SPH_C32(0xFFFFFFFF) -#define QC32dn(j, r) ((sph_u32)(r) ^ SPH_T32(~(sph_u32)(j))) - -#if SPH_64 -#define C64e(x) SPH_C64(x) -#define dec64e_aligned sph_dec64be_aligned -#define enc64e sph_enc64be -#define B64_0(x) ((x) >> 56) -#define B64_1(x) (((x) >> 48) & 0xFF) -#define B64_2(x) (((x) >> 40) & 0xFF) -#define B64_3(x) (((x) >> 32) & 0xFF) -#define B64_4(x) (((x) >> 24) & 0xFF) -#define B64_5(x) (((x) >> 16) & 0xFF) -#define B64_6(x) (((x) >> 8) & 0xFF) -#define B64_7(x) ((x) & 0xFF) -#define R64 SPH_ROTR64 -#define PC64(j, r) ((sph_u64)((j) + (r)) << 56) -#define QC64(j, r) ((sph_u64)(r) ^ SPH_T64(~(sph_u64)(j))) -#endif - -#endif - -#if SPH_GROESTL_64 - -static const sph_u64 T0[] = { - C64e(0xc632f4a5f497a5c6), C64e(0xf86f978497eb84f8), - C64e(0xee5eb099b0c799ee), C64e(0xf67a8c8d8cf78df6), - C64e(0xffe8170d17e50dff), C64e(0xd60adcbddcb7bdd6), - C64e(0xde16c8b1c8a7b1de), C64e(0x916dfc54fc395491), - C64e(0x6090f050f0c05060), C64e(0x0207050305040302), - C64e(0xce2ee0a9e087a9ce), C64e(0x56d1877d87ac7d56), - C64e(0xe7cc2b192bd519e7), C64e(0xb513a662a67162b5), - C64e(0x4d7c31e6319ae64d), C64e(0xec59b59ab5c39aec), - C64e(0x8f40cf45cf05458f), C64e(0x1fa3bc9dbc3e9d1f), - C64e(0x8949c040c0094089), C64e(0xfa68928792ef87fa), - C64e(0xefd03f153fc515ef), C64e(0xb29426eb267febb2), - C64e(0x8ece40c94007c98e), C64e(0xfbe61d0b1ded0bfb), - C64e(0x416e2fec2f82ec41), C64e(0xb31aa967a97d67b3), - C64e(0x5f431cfd1cbefd5f), C64e(0x456025ea258aea45), - C64e(0x23f9dabfda46bf23), C64e(0x535102f702a6f753), - C64e(0xe445a196a1d396e4), C64e(0x9b76ed5bed2d5b9b), - C64e(0x75285dc25deac275), C64e(0xe1c5241c24d91ce1), - C64e(0x3dd4e9aee97aae3d), C64e(0x4cf2be6abe986a4c), - C64e(0x6c82ee5aeed85a6c), C64e(0x7ebdc341c3fc417e), - C64e(0xf5f3060206f102f5), C64e(0x8352d14fd11d4f83), - C64e(0x688ce45ce4d05c68), C64e(0x515607f407a2f451), - C64e(0xd18d5c345cb934d1), C64e(0xf9e1180818e908f9), - C64e(0xe24cae93aedf93e2), C64e(0xab3e9573954d73ab), - C64e(0x6297f553f5c45362), C64e(0x2a6b413f41543f2a), - C64e(0x081c140c14100c08), C64e(0x9563f652f6315295), - C64e(0x46e9af65af8c6546), C64e(0x9d7fe25ee2215e9d), - C64e(0x3048782878602830), C64e(0x37cff8a1f86ea137), - C64e(0x0a1b110f11140f0a), C64e(0x2febc4b5c45eb52f), - C64e(0x0e151b091b1c090e), C64e(0x247e5a365a483624), - C64e(0x1badb69bb6369b1b), C64e(0xdf98473d47a53ddf), - C64e(0xcda76a266a8126cd), C64e(0x4ef5bb69bb9c694e), - C64e(0x7f334ccd4cfecd7f), C64e(0xea50ba9fbacf9fea), - C64e(0x123f2d1b2d241b12), C64e(0x1da4b99eb93a9e1d), - C64e(0x58c49c749cb07458), C64e(0x3446722e72682e34), - C64e(0x3641772d776c2d36), C64e(0xdc11cdb2cda3b2dc), - C64e(0xb49d29ee2973eeb4), C64e(0x5b4d16fb16b6fb5b), - C64e(0xa4a501f60153f6a4), C64e(0x76a1d74dd7ec4d76), - C64e(0xb714a361a37561b7), C64e(0x7d3449ce49face7d), - C64e(0x52df8d7b8da47b52), C64e(0xdd9f423e42a13edd), - C64e(0x5ecd937193bc715e), C64e(0x13b1a297a2269713), - C64e(0xa6a204f50457f5a6), C64e(0xb901b868b86968b9), - C64e(0x0000000000000000), C64e(0xc1b5742c74992cc1), - C64e(0x40e0a060a0806040), C64e(0xe3c2211f21dd1fe3), - C64e(0x793a43c843f2c879), C64e(0xb69a2ced2c77edb6), - C64e(0xd40dd9bed9b3bed4), C64e(0x8d47ca46ca01468d), - C64e(0x671770d970ced967), C64e(0x72afdd4bdde44b72), - C64e(0x94ed79de7933de94), C64e(0x98ff67d4672bd498), - C64e(0xb09323e8237be8b0), C64e(0x855bde4ade114a85), - C64e(0xbb06bd6bbd6d6bbb), C64e(0xc5bb7e2a7e912ac5), - C64e(0x4f7b34e5349ee54f), C64e(0xedd73a163ac116ed), - C64e(0x86d254c55417c586), C64e(0x9af862d7622fd79a), - C64e(0x6699ff55ffcc5566), C64e(0x11b6a794a7229411), - C64e(0x8ac04acf4a0fcf8a), C64e(0xe9d9301030c910e9), - C64e(0x040e0a060a080604), C64e(0xfe66988198e781fe), - C64e(0xa0ab0bf00b5bf0a0), C64e(0x78b4cc44ccf04478), - C64e(0x25f0d5bad54aba25), C64e(0x4b753ee33e96e34b), - C64e(0xa2ac0ef30e5ff3a2), C64e(0x5d4419fe19bafe5d), - C64e(0x80db5bc05b1bc080), C64e(0x0580858a850a8a05), - C64e(0x3fd3ecadec7ead3f), C64e(0x21fedfbcdf42bc21), - C64e(0x70a8d848d8e04870), C64e(0xf1fd0c040cf904f1), - C64e(0x63197adf7ac6df63), C64e(0x772f58c158eec177), - C64e(0xaf309f759f4575af), C64e(0x42e7a563a5846342), - C64e(0x2070503050403020), C64e(0xe5cb2e1a2ed11ae5), - C64e(0xfdef120e12e10efd), C64e(0xbf08b76db7656dbf), - C64e(0x8155d44cd4194c81), C64e(0x18243c143c301418), - C64e(0x26795f355f4c3526), C64e(0xc3b2712f719d2fc3), - C64e(0xbe8638e13867e1be), C64e(0x35c8fda2fd6aa235), - C64e(0x88c74fcc4f0bcc88), C64e(0x2e654b394b5c392e), - C64e(0x936af957f93d5793), C64e(0x55580df20daaf255), - C64e(0xfc619d829de382fc), C64e(0x7ab3c947c9f4477a), - C64e(0xc827efacef8bacc8), C64e(0xba8832e7326fe7ba), - C64e(0x324f7d2b7d642b32), C64e(0xe642a495a4d795e6), - C64e(0xc03bfba0fb9ba0c0), C64e(0x19aab398b3329819), - C64e(0x9ef668d16827d19e), C64e(0xa322817f815d7fa3), - C64e(0x44eeaa66aa886644), C64e(0x54d6827e82a87e54), - C64e(0x3bdde6abe676ab3b), C64e(0x0b959e839e16830b), - C64e(0x8cc945ca4503ca8c), C64e(0xc7bc7b297b9529c7), - C64e(0x6b056ed36ed6d36b), C64e(0x286c443c44503c28), - C64e(0xa72c8b798b5579a7), C64e(0xbc813de23d63e2bc), - C64e(0x1631271d272c1d16), C64e(0xad379a769a4176ad), - C64e(0xdb964d3b4dad3bdb), C64e(0x649efa56fac85664), - C64e(0x74a6d24ed2e84e74), C64e(0x1436221e22281e14), - C64e(0x92e476db763fdb92), C64e(0x0c121e0a1e180a0c), - C64e(0x48fcb46cb4906c48), C64e(0xb88f37e4376be4b8), - C64e(0x9f78e75de7255d9f), C64e(0xbd0fb26eb2616ebd), - C64e(0x43692aef2a86ef43), C64e(0xc435f1a6f193a6c4), - C64e(0x39dae3a8e372a839), C64e(0x31c6f7a4f762a431), - C64e(0xd38a593759bd37d3), C64e(0xf274868b86ff8bf2), - C64e(0xd583563256b132d5), C64e(0x8b4ec543c50d438b), - C64e(0x6e85eb59ebdc596e), C64e(0xda18c2b7c2afb7da), - C64e(0x018e8f8c8f028c01), C64e(0xb11dac64ac7964b1), - C64e(0x9cf16dd26d23d29c), C64e(0x49723be03b92e049), - C64e(0xd81fc7b4c7abb4d8), C64e(0xacb915fa1543faac), - C64e(0xf3fa090709fd07f3), C64e(0xcfa06f256f8525cf), - C64e(0xca20eaafea8fafca), C64e(0xf47d898e89f38ef4), - C64e(0x476720e9208ee947), C64e(0x1038281828201810), - C64e(0x6f0b64d564ded56f), C64e(0xf073838883fb88f0), - C64e(0x4afbb16fb1946f4a), C64e(0x5cca967296b8725c), - C64e(0x38546c246c702438), C64e(0x575f08f108aef157), - C64e(0x732152c752e6c773), C64e(0x9764f351f3355197), - C64e(0xcbae6523658d23cb), C64e(0xa125847c84597ca1), - C64e(0xe857bf9cbfcb9ce8), C64e(0x3e5d6321637c213e), - C64e(0x96ea7cdd7c37dd96), C64e(0x611e7fdc7fc2dc61), - C64e(0x0d9c9186911a860d), C64e(0x0f9b9485941e850f), - C64e(0xe04bab90abdb90e0), C64e(0x7cbac642c6f8427c), - C64e(0x712657c457e2c471), C64e(0xcc29e5aae583aacc), - C64e(0x90e373d8733bd890), C64e(0x06090f050f0c0506), - C64e(0xf7f4030103f501f7), C64e(0x1c2a36123638121c), - C64e(0xc23cfea3fe9fa3c2), C64e(0x6a8be15fe1d45f6a), - C64e(0xaebe10f91047f9ae), C64e(0x69026bd06bd2d069), - C64e(0x17bfa891a82e9117), C64e(0x9971e858e8295899), - C64e(0x3a5369276974273a), C64e(0x27f7d0b9d04eb927), - C64e(0xd991483848a938d9), C64e(0xebde351335cd13eb), - C64e(0x2be5ceb3ce56b32b), C64e(0x2277553355443322), - C64e(0xd204d6bbd6bfbbd2), C64e(0xa9399070904970a9), - C64e(0x07878089800e8907), C64e(0x33c1f2a7f266a733), - C64e(0x2decc1b6c15ab62d), C64e(0x3c5a66226678223c), - C64e(0x15b8ad92ad2a9215), C64e(0xc9a96020608920c9), - C64e(0x875cdb49db154987), C64e(0xaab01aff1a4fffaa), - C64e(0x50d8887888a07850), C64e(0xa52b8e7a8e517aa5), - C64e(0x03898a8f8a068f03), C64e(0x594a13f813b2f859), - C64e(0x09929b809b128009), C64e(0x1a2339173934171a), - C64e(0x651075da75cada65), C64e(0xd784533153b531d7), - C64e(0x84d551c65113c684), C64e(0xd003d3b8d3bbb8d0), - C64e(0x82dc5ec35e1fc382), C64e(0x29e2cbb0cb52b029), - C64e(0x5ac3997799b4775a), C64e(0x1e2d3311333c111e), - C64e(0x7b3d46cb46f6cb7b), C64e(0xa8b71ffc1f4bfca8), - C64e(0x6d0c61d661dad66d), C64e(0x2c624e3a4e583a2c) -}; - -#if !SPH_SMALL_FOOTPRINT_GROESTL - -static const sph_u64 T1[] = { - C64e(0xc6c632f4a5f497a5), C64e(0xf8f86f978497eb84), - C64e(0xeeee5eb099b0c799), C64e(0xf6f67a8c8d8cf78d), - C64e(0xffffe8170d17e50d), C64e(0xd6d60adcbddcb7bd), - C64e(0xdede16c8b1c8a7b1), C64e(0x91916dfc54fc3954), - C64e(0x606090f050f0c050), C64e(0x0202070503050403), - C64e(0xcece2ee0a9e087a9), C64e(0x5656d1877d87ac7d), - C64e(0xe7e7cc2b192bd519), C64e(0xb5b513a662a67162), - C64e(0x4d4d7c31e6319ae6), C64e(0xecec59b59ab5c39a), - C64e(0x8f8f40cf45cf0545), C64e(0x1f1fa3bc9dbc3e9d), - C64e(0x898949c040c00940), C64e(0xfafa68928792ef87), - C64e(0xefefd03f153fc515), C64e(0xb2b29426eb267feb), - C64e(0x8e8ece40c94007c9), C64e(0xfbfbe61d0b1ded0b), - C64e(0x41416e2fec2f82ec), C64e(0xb3b31aa967a97d67), - C64e(0x5f5f431cfd1cbefd), C64e(0x45456025ea258aea), - C64e(0x2323f9dabfda46bf), C64e(0x53535102f702a6f7), - C64e(0xe4e445a196a1d396), C64e(0x9b9b76ed5bed2d5b), - C64e(0x7575285dc25deac2), C64e(0xe1e1c5241c24d91c), - C64e(0x3d3dd4e9aee97aae), C64e(0x4c4cf2be6abe986a), - C64e(0x6c6c82ee5aeed85a), C64e(0x7e7ebdc341c3fc41), - C64e(0xf5f5f3060206f102), C64e(0x838352d14fd11d4f), - C64e(0x68688ce45ce4d05c), C64e(0x51515607f407a2f4), - C64e(0xd1d18d5c345cb934), C64e(0xf9f9e1180818e908), - C64e(0xe2e24cae93aedf93), C64e(0xabab3e9573954d73), - C64e(0x626297f553f5c453), C64e(0x2a2a6b413f41543f), - C64e(0x08081c140c14100c), C64e(0x959563f652f63152), - C64e(0x4646e9af65af8c65), C64e(0x9d9d7fe25ee2215e), - C64e(0x3030487828786028), C64e(0x3737cff8a1f86ea1), - C64e(0x0a0a1b110f11140f), C64e(0x2f2febc4b5c45eb5), - C64e(0x0e0e151b091b1c09), C64e(0x24247e5a365a4836), - C64e(0x1b1badb69bb6369b), C64e(0xdfdf98473d47a53d), - C64e(0xcdcda76a266a8126), C64e(0x4e4ef5bb69bb9c69), - C64e(0x7f7f334ccd4cfecd), C64e(0xeaea50ba9fbacf9f), - C64e(0x12123f2d1b2d241b), C64e(0x1d1da4b99eb93a9e), - C64e(0x5858c49c749cb074), C64e(0x343446722e72682e), - C64e(0x363641772d776c2d), C64e(0xdcdc11cdb2cda3b2), - C64e(0xb4b49d29ee2973ee), C64e(0x5b5b4d16fb16b6fb), - C64e(0xa4a4a501f60153f6), C64e(0x7676a1d74dd7ec4d), - C64e(0xb7b714a361a37561), C64e(0x7d7d3449ce49face), - C64e(0x5252df8d7b8da47b), C64e(0xdddd9f423e42a13e), - C64e(0x5e5ecd937193bc71), C64e(0x1313b1a297a22697), - C64e(0xa6a6a204f50457f5), C64e(0xb9b901b868b86968), - C64e(0x0000000000000000), C64e(0xc1c1b5742c74992c), - C64e(0x4040e0a060a08060), C64e(0xe3e3c2211f21dd1f), - C64e(0x79793a43c843f2c8), C64e(0xb6b69a2ced2c77ed), - C64e(0xd4d40dd9bed9b3be), C64e(0x8d8d47ca46ca0146), - C64e(0x67671770d970ced9), C64e(0x7272afdd4bdde44b), - C64e(0x9494ed79de7933de), C64e(0x9898ff67d4672bd4), - C64e(0xb0b09323e8237be8), C64e(0x85855bde4ade114a), - C64e(0xbbbb06bd6bbd6d6b), C64e(0xc5c5bb7e2a7e912a), - C64e(0x4f4f7b34e5349ee5), C64e(0xededd73a163ac116), - C64e(0x8686d254c55417c5), C64e(0x9a9af862d7622fd7), - C64e(0x666699ff55ffcc55), C64e(0x1111b6a794a72294), - C64e(0x8a8ac04acf4a0fcf), C64e(0xe9e9d9301030c910), - C64e(0x04040e0a060a0806), C64e(0xfefe66988198e781), - C64e(0xa0a0ab0bf00b5bf0), C64e(0x7878b4cc44ccf044), - C64e(0x2525f0d5bad54aba), C64e(0x4b4b753ee33e96e3), - C64e(0xa2a2ac0ef30e5ff3), C64e(0x5d5d4419fe19bafe), - C64e(0x8080db5bc05b1bc0), C64e(0x050580858a850a8a), - C64e(0x3f3fd3ecadec7ead), C64e(0x2121fedfbcdf42bc), - C64e(0x7070a8d848d8e048), C64e(0xf1f1fd0c040cf904), - C64e(0x6363197adf7ac6df), C64e(0x77772f58c158eec1), - C64e(0xafaf309f759f4575), C64e(0x4242e7a563a58463), - C64e(0x2020705030504030), C64e(0xe5e5cb2e1a2ed11a), - C64e(0xfdfdef120e12e10e), C64e(0xbfbf08b76db7656d), - C64e(0x818155d44cd4194c), C64e(0x1818243c143c3014), - C64e(0x2626795f355f4c35), C64e(0xc3c3b2712f719d2f), - C64e(0xbebe8638e13867e1), C64e(0x3535c8fda2fd6aa2), - C64e(0x8888c74fcc4f0bcc), C64e(0x2e2e654b394b5c39), - C64e(0x93936af957f93d57), C64e(0x5555580df20daaf2), - C64e(0xfcfc619d829de382), C64e(0x7a7ab3c947c9f447), - C64e(0xc8c827efacef8bac), C64e(0xbaba8832e7326fe7), - C64e(0x32324f7d2b7d642b), C64e(0xe6e642a495a4d795), - C64e(0xc0c03bfba0fb9ba0), C64e(0x1919aab398b33298), - C64e(0x9e9ef668d16827d1), C64e(0xa3a322817f815d7f), - C64e(0x4444eeaa66aa8866), C64e(0x5454d6827e82a87e), - C64e(0x3b3bdde6abe676ab), C64e(0x0b0b959e839e1683), - C64e(0x8c8cc945ca4503ca), C64e(0xc7c7bc7b297b9529), - C64e(0x6b6b056ed36ed6d3), C64e(0x28286c443c44503c), - C64e(0xa7a72c8b798b5579), C64e(0xbcbc813de23d63e2), - C64e(0x161631271d272c1d), C64e(0xadad379a769a4176), - C64e(0xdbdb964d3b4dad3b), C64e(0x64649efa56fac856), - C64e(0x7474a6d24ed2e84e), C64e(0x141436221e22281e), - C64e(0x9292e476db763fdb), C64e(0x0c0c121e0a1e180a), - C64e(0x4848fcb46cb4906c), C64e(0xb8b88f37e4376be4), - C64e(0x9f9f78e75de7255d), C64e(0xbdbd0fb26eb2616e), - C64e(0x4343692aef2a86ef), C64e(0xc4c435f1a6f193a6), - C64e(0x3939dae3a8e372a8), C64e(0x3131c6f7a4f762a4), - C64e(0xd3d38a593759bd37), C64e(0xf2f274868b86ff8b), - C64e(0xd5d583563256b132), C64e(0x8b8b4ec543c50d43), - C64e(0x6e6e85eb59ebdc59), C64e(0xdada18c2b7c2afb7), - C64e(0x01018e8f8c8f028c), C64e(0xb1b11dac64ac7964), - C64e(0x9c9cf16dd26d23d2), C64e(0x4949723be03b92e0), - C64e(0xd8d81fc7b4c7abb4), C64e(0xacacb915fa1543fa), - C64e(0xf3f3fa090709fd07), C64e(0xcfcfa06f256f8525), - C64e(0xcaca20eaafea8faf), C64e(0xf4f47d898e89f38e), - C64e(0x47476720e9208ee9), C64e(0x1010382818282018), - C64e(0x6f6f0b64d564ded5), C64e(0xf0f073838883fb88), - C64e(0x4a4afbb16fb1946f), C64e(0x5c5cca967296b872), - C64e(0x3838546c246c7024), C64e(0x57575f08f108aef1), - C64e(0x73732152c752e6c7), C64e(0x979764f351f33551), - C64e(0xcbcbae6523658d23), C64e(0xa1a125847c84597c), - C64e(0xe8e857bf9cbfcb9c), C64e(0x3e3e5d6321637c21), - C64e(0x9696ea7cdd7c37dd), C64e(0x61611e7fdc7fc2dc), - C64e(0x0d0d9c9186911a86), C64e(0x0f0f9b9485941e85), - C64e(0xe0e04bab90abdb90), C64e(0x7c7cbac642c6f842), - C64e(0x71712657c457e2c4), C64e(0xcccc29e5aae583aa), - C64e(0x9090e373d8733bd8), C64e(0x0606090f050f0c05), - C64e(0xf7f7f4030103f501), C64e(0x1c1c2a3612363812), - C64e(0xc2c23cfea3fe9fa3), C64e(0x6a6a8be15fe1d45f), - C64e(0xaeaebe10f91047f9), C64e(0x6969026bd06bd2d0), - C64e(0x1717bfa891a82e91), C64e(0x999971e858e82958), - C64e(0x3a3a536927697427), C64e(0x2727f7d0b9d04eb9), - C64e(0xd9d991483848a938), C64e(0xebebde351335cd13), - C64e(0x2b2be5ceb3ce56b3), C64e(0x2222775533554433), - C64e(0xd2d204d6bbd6bfbb), C64e(0xa9a9399070904970), - C64e(0x0707878089800e89), C64e(0x3333c1f2a7f266a7), - C64e(0x2d2decc1b6c15ab6), C64e(0x3c3c5a6622667822), - C64e(0x1515b8ad92ad2a92), C64e(0xc9c9a96020608920), - C64e(0x87875cdb49db1549), C64e(0xaaaab01aff1a4fff), - C64e(0x5050d8887888a078), C64e(0xa5a52b8e7a8e517a), - C64e(0x0303898a8f8a068f), C64e(0x59594a13f813b2f8), - C64e(0x0909929b809b1280), C64e(0x1a1a233917393417), - C64e(0x65651075da75cada), C64e(0xd7d784533153b531), - C64e(0x8484d551c65113c6), C64e(0xd0d003d3b8d3bbb8), - C64e(0x8282dc5ec35e1fc3), C64e(0x2929e2cbb0cb52b0), - C64e(0x5a5ac3997799b477), C64e(0x1e1e2d3311333c11), - C64e(0x7b7b3d46cb46f6cb), C64e(0xa8a8b71ffc1f4bfc), - C64e(0x6d6d0c61d661dad6), C64e(0x2c2c624e3a4e583a) -}; - -static const sph_u64 T2[] = { - C64e(0xa5c6c632f4a5f497), C64e(0x84f8f86f978497eb), - C64e(0x99eeee5eb099b0c7), C64e(0x8df6f67a8c8d8cf7), - C64e(0x0dffffe8170d17e5), C64e(0xbdd6d60adcbddcb7), - C64e(0xb1dede16c8b1c8a7), C64e(0x5491916dfc54fc39), - C64e(0x50606090f050f0c0), C64e(0x0302020705030504), - C64e(0xa9cece2ee0a9e087), C64e(0x7d5656d1877d87ac), - C64e(0x19e7e7cc2b192bd5), C64e(0x62b5b513a662a671), - C64e(0xe64d4d7c31e6319a), C64e(0x9aecec59b59ab5c3), - C64e(0x458f8f40cf45cf05), C64e(0x9d1f1fa3bc9dbc3e), - C64e(0x40898949c040c009), C64e(0x87fafa68928792ef), - C64e(0x15efefd03f153fc5), C64e(0xebb2b29426eb267f), - C64e(0xc98e8ece40c94007), C64e(0x0bfbfbe61d0b1ded), - C64e(0xec41416e2fec2f82), C64e(0x67b3b31aa967a97d), - C64e(0xfd5f5f431cfd1cbe), C64e(0xea45456025ea258a), - C64e(0xbf2323f9dabfda46), C64e(0xf753535102f702a6), - C64e(0x96e4e445a196a1d3), C64e(0x5b9b9b76ed5bed2d), - C64e(0xc27575285dc25dea), C64e(0x1ce1e1c5241c24d9), - C64e(0xae3d3dd4e9aee97a), C64e(0x6a4c4cf2be6abe98), - C64e(0x5a6c6c82ee5aeed8), C64e(0x417e7ebdc341c3fc), - C64e(0x02f5f5f3060206f1), C64e(0x4f838352d14fd11d), - C64e(0x5c68688ce45ce4d0), C64e(0xf451515607f407a2), - C64e(0x34d1d18d5c345cb9), C64e(0x08f9f9e1180818e9), - C64e(0x93e2e24cae93aedf), C64e(0x73abab3e9573954d), - C64e(0x53626297f553f5c4), C64e(0x3f2a2a6b413f4154), - C64e(0x0c08081c140c1410), C64e(0x52959563f652f631), - C64e(0x654646e9af65af8c), C64e(0x5e9d9d7fe25ee221), - C64e(0x2830304878287860), C64e(0xa13737cff8a1f86e), - C64e(0x0f0a0a1b110f1114), C64e(0xb52f2febc4b5c45e), - C64e(0x090e0e151b091b1c), C64e(0x3624247e5a365a48), - C64e(0x9b1b1badb69bb636), C64e(0x3ddfdf98473d47a5), - C64e(0x26cdcda76a266a81), C64e(0x694e4ef5bb69bb9c), - C64e(0xcd7f7f334ccd4cfe), C64e(0x9feaea50ba9fbacf), - C64e(0x1b12123f2d1b2d24), C64e(0x9e1d1da4b99eb93a), - C64e(0x745858c49c749cb0), C64e(0x2e343446722e7268), - C64e(0x2d363641772d776c), C64e(0xb2dcdc11cdb2cda3), - C64e(0xeeb4b49d29ee2973), C64e(0xfb5b5b4d16fb16b6), - C64e(0xf6a4a4a501f60153), C64e(0x4d7676a1d74dd7ec), - C64e(0x61b7b714a361a375), C64e(0xce7d7d3449ce49fa), - C64e(0x7b5252df8d7b8da4), C64e(0x3edddd9f423e42a1), - C64e(0x715e5ecd937193bc), C64e(0x971313b1a297a226), - C64e(0xf5a6a6a204f50457), C64e(0x68b9b901b868b869), - C64e(0x0000000000000000), C64e(0x2cc1c1b5742c7499), - C64e(0x604040e0a060a080), C64e(0x1fe3e3c2211f21dd), - C64e(0xc879793a43c843f2), C64e(0xedb6b69a2ced2c77), - C64e(0xbed4d40dd9bed9b3), C64e(0x468d8d47ca46ca01), - C64e(0xd967671770d970ce), C64e(0x4b7272afdd4bdde4), - C64e(0xde9494ed79de7933), C64e(0xd49898ff67d4672b), - C64e(0xe8b0b09323e8237b), C64e(0x4a85855bde4ade11), - C64e(0x6bbbbb06bd6bbd6d), C64e(0x2ac5c5bb7e2a7e91), - C64e(0xe54f4f7b34e5349e), C64e(0x16ededd73a163ac1), - C64e(0xc58686d254c55417), C64e(0xd79a9af862d7622f), - C64e(0x55666699ff55ffcc), C64e(0x941111b6a794a722), - C64e(0xcf8a8ac04acf4a0f), C64e(0x10e9e9d9301030c9), - C64e(0x0604040e0a060a08), C64e(0x81fefe66988198e7), - C64e(0xf0a0a0ab0bf00b5b), C64e(0x447878b4cc44ccf0), - C64e(0xba2525f0d5bad54a), C64e(0xe34b4b753ee33e96), - C64e(0xf3a2a2ac0ef30e5f), C64e(0xfe5d5d4419fe19ba), - C64e(0xc08080db5bc05b1b), C64e(0x8a050580858a850a), - C64e(0xad3f3fd3ecadec7e), C64e(0xbc2121fedfbcdf42), - C64e(0x487070a8d848d8e0), C64e(0x04f1f1fd0c040cf9), - C64e(0xdf6363197adf7ac6), C64e(0xc177772f58c158ee), - C64e(0x75afaf309f759f45), C64e(0x634242e7a563a584), - C64e(0x3020207050305040), C64e(0x1ae5e5cb2e1a2ed1), - C64e(0x0efdfdef120e12e1), C64e(0x6dbfbf08b76db765), - C64e(0x4c818155d44cd419), C64e(0x141818243c143c30), - C64e(0x352626795f355f4c), C64e(0x2fc3c3b2712f719d), - C64e(0xe1bebe8638e13867), C64e(0xa23535c8fda2fd6a), - C64e(0xcc8888c74fcc4f0b), C64e(0x392e2e654b394b5c), - C64e(0x5793936af957f93d), C64e(0xf25555580df20daa), - C64e(0x82fcfc619d829de3), C64e(0x477a7ab3c947c9f4), - C64e(0xacc8c827efacef8b), C64e(0xe7baba8832e7326f), - C64e(0x2b32324f7d2b7d64), C64e(0x95e6e642a495a4d7), - C64e(0xa0c0c03bfba0fb9b), C64e(0x981919aab398b332), - C64e(0xd19e9ef668d16827), C64e(0x7fa3a322817f815d), - C64e(0x664444eeaa66aa88), C64e(0x7e5454d6827e82a8), - C64e(0xab3b3bdde6abe676), C64e(0x830b0b959e839e16), - C64e(0xca8c8cc945ca4503), C64e(0x29c7c7bc7b297b95), - C64e(0xd36b6b056ed36ed6), C64e(0x3c28286c443c4450), - C64e(0x79a7a72c8b798b55), C64e(0xe2bcbc813de23d63), - C64e(0x1d161631271d272c), C64e(0x76adad379a769a41), - C64e(0x3bdbdb964d3b4dad), C64e(0x5664649efa56fac8), - C64e(0x4e7474a6d24ed2e8), C64e(0x1e141436221e2228), - C64e(0xdb9292e476db763f), C64e(0x0a0c0c121e0a1e18), - C64e(0x6c4848fcb46cb490), C64e(0xe4b8b88f37e4376b), - C64e(0x5d9f9f78e75de725), C64e(0x6ebdbd0fb26eb261), - C64e(0xef4343692aef2a86), C64e(0xa6c4c435f1a6f193), - C64e(0xa83939dae3a8e372), C64e(0xa43131c6f7a4f762), - C64e(0x37d3d38a593759bd), C64e(0x8bf2f274868b86ff), - C64e(0x32d5d583563256b1), C64e(0x438b8b4ec543c50d), - C64e(0x596e6e85eb59ebdc), C64e(0xb7dada18c2b7c2af), - C64e(0x8c01018e8f8c8f02), C64e(0x64b1b11dac64ac79), - C64e(0xd29c9cf16dd26d23), C64e(0xe04949723be03b92), - C64e(0xb4d8d81fc7b4c7ab), C64e(0xfaacacb915fa1543), - C64e(0x07f3f3fa090709fd), C64e(0x25cfcfa06f256f85), - C64e(0xafcaca20eaafea8f), C64e(0x8ef4f47d898e89f3), - C64e(0xe947476720e9208e), C64e(0x1810103828182820), - C64e(0xd56f6f0b64d564de), C64e(0x88f0f073838883fb), - C64e(0x6f4a4afbb16fb194), C64e(0x725c5cca967296b8), - C64e(0x243838546c246c70), C64e(0xf157575f08f108ae), - C64e(0xc773732152c752e6), C64e(0x51979764f351f335), - C64e(0x23cbcbae6523658d), C64e(0x7ca1a125847c8459), - C64e(0x9ce8e857bf9cbfcb), C64e(0x213e3e5d6321637c), - C64e(0xdd9696ea7cdd7c37), C64e(0xdc61611e7fdc7fc2), - C64e(0x860d0d9c9186911a), C64e(0x850f0f9b9485941e), - C64e(0x90e0e04bab90abdb), C64e(0x427c7cbac642c6f8), - C64e(0xc471712657c457e2), C64e(0xaacccc29e5aae583), - C64e(0xd89090e373d8733b), C64e(0x050606090f050f0c), - C64e(0x01f7f7f4030103f5), C64e(0x121c1c2a36123638), - C64e(0xa3c2c23cfea3fe9f), C64e(0x5f6a6a8be15fe1d4), - C64e(0xf9aeaebe10f91047), C64e(0xd06969026bd06bd2), - C64e(0x911717bfa891a82e), C64e(0x58999971e858e829), - C64e(0x273a3a5369276974), C64e(0xb92727f7d0b9d04e), - C64e(0x38d9d991483848a9), C64e(0x13ebebde351335cd), - C64e(0xb32b2be5ceb3ce56), C64e(0x3322227755335544), - C64e(0xbbd2d204d6bbd6bf), C64e(0x70a9a93990709049), - C64e(0x890707878089800e), C64e(0xa73333c1f2a7f266), - C64e(0xb62d2decc1b6c15a), C64e(0x223c3c5a66226678), - C64e(0x921515b8ad92ad2a), C64e(0x20c9c9a960206089), - C64e(0x4987875cdb49db15), C64e(0xffaaaab01aff1a4f), - C64e(0x785050d8887888a0), C64e(0x7aa5a52b8e7a8e51), - C64e(0x8f0303898a8f8a06), C64e(0xf859594a13f813b2), - C64e(0x800909929b809b12), C64e(0x171a1a2339173934), - C64e(0xda65651075da75ca), C64e(0x31d7d784533153b5), - C64e(0xc68484d551c65113), C64e(0xb8d0d003d3b8d3bb), - C64e(0xc38282dc5ec35e1f), C64e(0xb02929e2cbb0cb52), - C64e(0x775a5ac3997799b4), C64e(0x111e1e2d3311333c), - C64e(0xcb7b7b3d46cb46f6), C64e(0xfca8a8b71ffc1f4b), - C64e(0xd66d6d0c61d661da), C64e(0x3a2c2c624e3a4e58) -}; - -static const sph_u64 T3[] = { - C64e(0x97a5c6c632f4a5f4), C64e(0xeb84f8f86f978497), - C64e(0xc799eeee5eb099b0), C64e(0xf78df6f67a8c8d8c), - C64e(0xe50dffffe8170d17), C64e(0xb7bdd6d60adcbddc), - C64e(0xa7b1dede16c8b1c8), C64e(0x395491916dfc54fc), - C64e(0xc050606090f050f0), C64e(0x0403020207050305), - C64e(0x87a9cece2ee0a9e0), C64e(0xac7d5656d1877d87), - C64e(0xd519e7e7cc2b192b), C64e(0x7162b5b513a662a6), - C64e(0x9ae64d4d7c31e631), C64e(0xc39aecec59b59ab5), - C64e(0x05458f8f40cf45cf), C64e(0x3e9d1f1fa3bc9dbc), - C64e(0x0940898949c040c0), C64e(0xef87fafa68928792), - C64e(0xc515efefd03f153f), C64e(0x7febb2b29426eb26), - C64e(0x07c98e8ece40c940), C64e(0xed0bfbfbe61d0b1d), - C64e(0x82ec41416e2fec2f), C64e(0x7d67b3b31aa967a9), - C64e(0xbefd5f5f431cfd1c), C64e(0x8aea45456025ea25), - C64e(0x46bf2323f9dabfda), C64e(0xa6f753535102f702), - C64e(0xd396e4e445a196a1), C64e(0x2d5b9b9b76ed5bed), - C64e(0xeac27575285dc25d), C64e(0xd91ce1e1c5241c24), - C64e(0x7aae3d3dd4e9aee9), C64e(0x986a4c4cf2be6abe), - C64e(0xd85a6c6c82ee5aee), C64e(0xfc417e7ebdc341c3), - C64e(0xf102f5f5f3060206), C64e(0x1d4f838352d14fd1), - C64e(0xd05c68688ce45ce4), C64e(0xa2f451515607f407), - C64e(0xb934d1d18d5c345c), C64e(0xe908f9f9e1180818), - C64e(0xdf93e2e24cae93ae), C64e(0x4d73abab3e957395), - C64e(0xc453626297f553f5), C64e(0x543f2a2a6b413f41), - C64e(0x100c08081c140c14), C64e(0x3152959563f652f6), - C64e(0x8c654646e9af65af), C64e(0x215e9d9d7fe25ee2), - C64e(0x6028303048782878), C64e(0x6ea13737cff8a1f8), - C64e(0x140f0a0a1b110f11), C64e(0x5eb52f2febc4b5c4), - C64e(0x1c090e0e151b091b), C64e(0x483624247e5a365a), - C64e(0x369b1b1badb69bb6), C64e(0xa53ddfdf98473d47), - C64e(0x8126cdcda76a266a), C64e(0x9c694e4ef5bb69bb), - C64e(0xfecd7f7f334ccd4c), C64e(0xcf9feaea50ba9fba), - C64e(0x241b12123f2d1b2d), C64e(0x3a9e1d1da4b99eb9), - C64e(0xb0745858c49c749c), C64e(0x682e343446722e72), - C64e(0x6c2d363641772d77), C64e(0xa3b2dcdc11cdb2cd), - C64e(0x73eeb4b49d29ee29), C64e(0xb6fb5b5b4d16fb16), - C64e(0x53f6a4a4a501f601), C64e(0xec4d7676a1d74dd7), - C64e(0x7561b7b714a361a3), C64e(0xface7d7d3449ce49), - C64e(0xa47b5252df8d7b8d), C64e(0xa13edddd9f423e42), - C64e(0xbc715e5ecd937193), C64e(0x26971313b1a297a2), - C64e(0x57f5a6a6a204f504), C64e(0x6968b9b901b868b8), - C64e(0x0000000000000000), C64e(0x992cc1c1b5742c74), - C64e(0x80604040e0a060a0), C64e(0xdd1fe3e3c2211f21), - C64e(0xf2c879793a43c843), C64e(0x77edb6b69a2ced2c), - C64e(0xb3bed4d40dd9bed9), C64e(0x01468d8d47ca46ca), - C64e(0xced967671770d970), C64e(0xe44b7272afdd4bdd), - C64e(0x33de9494ed79de79), C64e(0x2bd49898ff67d467), - C64e(0x7be8b0b09323e823), C64e(0x114a85855bde4ade), - C64e(0x6d6bbbbb06bd6bbd), C64e(0x912ac5c5bb7e2a7e), - C64e(0x9ee54f4f7b34e534), C64e(0xc116ededd73a163a), - C64e(0x17c58686d254c554), C64e(0x2fd79a9af862d762), - C64e(0xcc55666699ff55ff), C64e(0x22941111b6a794a7), - C64e(0x0fcf8a8ac04acf4a), C64e(0xc910e9e9d9301030), - C64e(0x080604040e0a060a), C64e(0xe781fefe66988198), - C64e(0x5bf0a0a0ab0bf00b), C64e(0xf0447878b4cc44cc), - C64e(0x4aba2525f0d5bad5), C64e(0x96e34b4b753ee33e), - C64e(0x5ff3a2a2ac0ef30e), C64e(0xbafe5d5d4419fe19), - C64e(0x1bc08080db5bc05b), C64e(0x0a8a050580858a85), - C64e(0x7ead3f3fd3ecadec), C64e(0x42bc2121fedfbcdf), - C64e(0xe0487070a8d848d8), C64e(0xf904f1f1fd0c040c), - C64e(0xc6df6363197adf7a), C64e(0xeec177772f58c158), - C64e(0x4575afaf309f759f), C64e(0x84634242e7a563a5), - C64e(0x4030202070503050), C64e(0xd11ae5e5cb2e1a2e), - C64e(0xe10efdfdef120e12), C64e(0x656dbfbf08b76db7), - C64e(0x194c818155d44cd4), C64e(0x30141818243c143c), - C64e(0x4c352626795f355f), C64e(0x9d2fc3c3b2712f71), - C64e(0x67e1bebe8638e138), C64e(0x6aa23535c8fda2fd), - C64e(0x0bcc8888c74fcc4f), C64e(0x5c392e2e654b394b), - C64e(0x3d5793936af957f9), C64e(0xaaf25555580df20d), - C64e(0xe382fcfc619d829d), C64e(0xf4477a7ab3c947c9), - C64e(0x8bacc8c827efacef), C64e(0x6fe7baba8832e732), - C64e(0x642b32324f7d2b7d), C64e(0xd795e6e642a495a4), - C64e(0x9ba0c0c03bfba0fb), C64e(0x32981919aab398b3), - C64e(0x27d19e9ef668d168), C64e(0x5d7fa3a322817f81), - C64e(0x88664444eeaa66aa), C64e(0xa87e5454d6827e82), - C64e(0x76ab3b3bdde6abe6), C64e(0x16830b0b959e839e), - C64e(0x03ca8c8cc945ca45), C64e(0x9529c7c7bc7b297b), - C64e(0xd6d36b6b056ed36e), C64e(0x503c28286c443c44), - C64e(0x5579a7a72c8b798b), C64e(0x63e2bcbc813de23d), - C64e(0x2c1d161631271d27), C64e(0x4176adad379a769a), - C64e(0xad3bdbdb964d3b4d), C64e(0xc85664649efa56fa), - C64e(0xe84e7474a6d24ed2), C64e(0x281e141436221e22), - C64e(0x3fdb9292e476db76), C64e(0x180a0c0c121e0a1e), - C64e(0x906c4848fcb46cb4), C64e(0x6be4b8b88f37e437), - C64e(0x255d9f9f78e75de7), C64e(0x616ebdbd0fb26eb2), - C64e(0x86ef4343692aef2a), C64e(0x93a6c4c435f1a6f1), - C64e(0x72a83939dae3a8e3), C64e(0x62a43131c6f7a4f7), - C64e(0xbd37d3d38a593759), C64e(0xff8bf2f274868b86), - C64e(0xb132d5d583563256), C64e(0x0d438b8b4ec543c5), - C64e(0xdc596e6e85eb59eb), C64e(0xafb7dada18c2b7c2), - C64e(0x028c01018e8f8c8f), C64e(0x7964b1b11dac64ac), - C64e(0x23d29c9cf16dd26d), C64e(0x92e04949723be03b), - C64e(0xabb4d8d81fc7b4c7), C64e(0x43faacacb915fa15), - C64e(0xfd07f3f3fa090709), C64e(0x8525cfcfa06f256f), - C64e(0x8fafcaca20eaafea), C64e(0xf38ef4f47d898e89), - C64e(0x8ee947476720e920), C64e(0x2018101038281828), - C64e(0xded56f6f0b64d564), C64e(0xfb88f0f073838883), - C64e(0x946f4a4afbb16fb1), C64e(0xb8725c5cca967296), - C64e(0x70243838546c246c), C64e(0xaef157575f08f108), - C64e(0xe6c773732152c752), C64e(0x3551979764f351f3), - C64e(0x8d23cbcbae652365), C64e(0x597ca1a125847c84), - C64e(0xcb9ce8e857bf9cbf), C64e(0x7c213e3e5d632163), - C64e(0x37dd9696ea7cdd7c), C64e(0xc2dc61611e7fdc7f), - C64e(0x1a860d0d9c918691), C64e(0x1e850f0f9b948594), - C64e(0xdb90e0e04bab90ab), C64e(0xf8427c7cbac642c6), - C64e(0xe2c471712657c457), C64e(0x83aacccc29e5aae5), - C64e(0x3bd89090e373d873), C64e(0x0c050606090f050f), - C64e(0xf501f7f7f4030103), C64e(0x38121c1c2a361236), - C64e(0x9fa3c2c23cfea3fe), C64e(0xd45f6a6a8be15fe1), - C64e(0x47f9aeaebe10f910), C64e(0xd2d06969026bd06b), - C64e(0x2e911717bfa891a8), C64e(0x2958999971e858e8), - C64e(0x74273a3a53692769), C64e(0x4eb92727f7d0b9d0), - C64e(0xa938d9d991483848), C64e(0xcd13ebebde351335), - C64e(0x56b32b2be5ceb3ce), C64e(0x4433222277553355), - C64e(0xbfbbd2d204d6bbd6), C64e(0x4970a9a939907090), - C64e(0x0e89070787808980), C64e(0x66a73333c1f2a7f2), - C64e(0x5ab62d2decc1b6c1), C64e(0x78223c3c5a662266), - C64e(0x2a921515b8ad92ad), C64e(0x8920c9c9a9602060), - C64e(0x154987875cdb49db), C64e(0x4fffaaaab01aff1a), - C64e(0xa0785050d8887888), C64e(0x517aa5a52b8e7a8e), - C64e(0x068f0303898a8f8a), C64e(0xb2f859594a13f813), - C64e(0x12800909929b809b), C64e(0x34171a1a23391739), - C64e(0xcada65651075da75), C64e(0xb531d7d784533153), - C64e(0x13c68484d551c651), C64e(0xbbb8d0d003d3b8d3), - C64e(0x1fc38282dc5ec35e), C64e(0x52b02929e2cbb0cb), - C64e(0xb4775a5ac3997799), C64e(0x3c111e1e2d331133), - C64e(0xf6cb7b7b3d46cb46), C64e(0x4bfca8a8b71ffc1f), - C64e(0xdad66d6d0c61d661), C64e(0x583a2c2c624e3a4e) -}; - -#endif - -static const sph_u64 T4[] = { - C64e(0xf497a5c6c632f4a5), C64e(0x97eb84f8f86f9784), - C64e(0xb0c799eeee5eb099), C64e(0x8cf78df6f67a8c8d), - C64e(0x17e50dffffe8170d), C64e(0xdcb7bdd6d60adcbd), - C64e(0xc8a7b1dede16c8b1), C64e(0xfc395491916dfc54), - C64e(0xf0c050606090f050), C64e(0x0504030202070503), - C64e(0xe087a9cece2ee0a9), C64e(0x87ac7d5656d1877d), - C64e(0x2bd519e7e7cc2b19), C64e(0xa67162b5b513a662), - C64e(0x319ae64d4d7c31e6), C64e(0xb5c39aecec59b59a), - C64e(0xcf05458f8f40cf45), C64e(0xbc3e9d1f1fa3bc9d), - C64e(0xc00940898949c040), C64e(0x92ef87fafa689287), - C64e(0x3fc515efefd03f15), C64e(0x267febb2b29426eb), - C64e(0x4007c98e8ece40c9), C64e(0x1ded0bfbfbe61d0b), - C64e(0x2f82ec41416e2fec), C64e(0xa97d67b3b31aa967), - C64e(0x1cbefd5f5f431cfd), C64e(0x258aea45456025ea), - C64e(0xda46bf2323f9dabf), C64e(0x02a6f753535102f7), - C64e(0xa1d396e4e445a196), C64e(0xed2d5b9b9b76ed5b), - C64e(0x5deac27575285dc2), C64e(0x24d91ce1e1c5241c), - C64e(0xe97aae3d3dd4e9ae), C64e(0xbe986a4c4cf2be6a), - C64e(0xeed85a6c6c82ee5a), C64e(0xc3fc417e7ebdc341), - C64e(0x06f102f5f5f30602), C64e(0xd11d4f838352d14f), - C64e(0xe4d05c68688ce45c), C64e(0x07a2f451515607f4), - C64e(0x5cb934d1d18d5c34), C64e(0x18e908f9f9e11808), - C64e(0xaedf93e2e24cae93), C64e(0x954d73abab3e9573), - C64e(0xf5c453626297f553), C64e(0x41543f2a2a6b413f), - C64e(0x14100c08081c140c), C64e(0xf63152959563f652), - C64e(0xaf8c654646e9af65), C64e(0xe2215e9d9d7fe25e), - C64e(0x7860283030487828), C64e(0xf86ea13737cff8a1), - C64e(0x11140f0a0a1b110f), C64e(0xc45eb52f2febc4b5), - C64e(0x1b1c090e0e151b09), C64e(0x5a483624247e5a36), - C64e(0xb6369b1b1badb69b), C64e(0x47a53ddfdf98473d), - C64e(0x6a8126cdcda76a26), C64e(0xbb9c694e4ef5bb69), - C64e(0x4cfecd7f7f334ccd), C64e(0xbacf9feaea50ba9f), - C64e(0x2d241b12123f2d1b), C64e(0xb93a9e1d1da4b99e), - C64e(0x9cb0745858c49c74), C64e(0x72682e343446722e), - C64e(0x776c2d363641772d), C64e(0xcda3b2dcdc11cdb2), - C64e(0x2973eeb4b49d29ee), C64e(0x16b6fb5b5b4d16fb), - C64e(0x0153f6a4a4a501f6), C64e(0xd7ec4d7676a1d74d), - C64e(0xa37561b7b714a361), C64e(0x49face7d7d3449ce), - C64e(0x8da47b5252df8d7b), C64e(0x42a13edddd9f423e), - C64e(0x93bc715e5ecd9371), C64e(0xa226971313b1a297), - C64e(0x0457f5a6a6a204f5), C64e(0xb86968b9b901b868), - C64e(0x0000000000000000), C64e(0x74992cc1c1b5742c), - C64e(0xa080604040e0a060), C64e(0x21dd1fe3e3c2211f), - C64e(0x43f2c879793a43c8), C64e(0x2c77edb6b69a2ced), - C64e(0xd9b3bed4d40dd9be), C64e(0xca01468d8d47ca46), - C64e(0x70ced967671770d9), C64e(0xdde44b7272afdd4b), - C64e(0x7933de9494ed79de), C64e(0x672bd49898ff67d4), - C64e(0x237be8b0b09323e8), C64e(0xde114a85855bde4a), - C64e(0xbd6d6bbbbb06bd6b), C64e(0x7e912ac5c5bb7e2a), - C64e(0x349ee54f4f7b34e5), C64e(0x3ac116ededd73a16), - C64e(0x5417c58686d254c5), C64e(0x622fd79a9af862d7), - C64e(0xffcc55666699ff55), C64e(0xa722941111b6a794), - C64e(0x4a0fcf8a8ac04acf), C64e(0x30c910e9e9d93010), - C64e(0x0a080604040e0a06), C64e(0x98e781fefe669881), - C64e(0x0b5bf0a0a0ab0bf0), C64e(0xccf0447878b4cc44), - C64e(0xd54aba2525f0d5ba), C64e(0x3e96e34b4b753ee3), - C64e(0x0e5ff3a2a2ac0ef3), C64e(0x19bafe5d5d4419fe), - C64e(0x5b1bc08080db5bc0), C64e(0x850a8a050580858a), - C64e(0xec7ead3f3fd3ecad), C64e(0xdf42bc2121fedfbc), - C64e(0xd8e0487070a8d848), C64e(0x0cf904f1f1fd0c04), - C64e(0x7ac6df6363197adf), C64e(0x58eec177772f58c1), - C64e(0x9f4575afaf309f75), C64e(0xa584634242e7a563), - C64e(0x5040302020705030), C64e(0x2ed11ae5e5cb2e1a), - C64e(0x12e10efdfdef120e), C64e(0xb7656dbfbf08b76d), - C64e(0xd4194c818155d44c), C64e(0x3c30141818243c14), - C64e(0x5f4c352626795f35), C64e(0x719d2fc3c3b2712f), - C64e(0x3867e1bebe8638e1), C64e(0xfd6aa23535c8fda2), - C64e(0x4f0bcc8888c74fcc), C64e(0x4b5c392e2e654b39), - C64e(0xf93d5793936af957), C64e(0x0daaf25555580df2), - C64e(0x9de382fcfc619d82), C64e(0xc9f4477a7ab3c947), - C64e(0xef8bacc8c827efac), C64e(0x326fe7baba8832e7), - C64e(0x7d642b32324f7d2b), C64e(0xa4d795e6e642a495), - C64e(0xfb9ba0c0c03bfba0), C64e(0xb332981919aab398), - C64e(0x6827d19e9ef668d1), C64e(0x815d7fa3a322817f), - C64e(0xaa88664444eeaa66), C64e(0x82a87e5454d6827e), - C64e(0xe676ab3b3bdde6ab), C64e(0x9e16830b0b959e83), - C64e(0x4503ca8c8cc945ca), C64e(0x7b9529c7c7bc7b29), - C64e(0x6ed6d36b6b056ed3), C64e(0x44503c28286c443c), - C64e(0x8b5579a7a72c8b79), C64e(0x3d63e2bcbc813de2), - C64e(0x272c1d161631271d), C64e(0x9a4176adad379a76), - C64e(0x4dad3bdbdb964d3b), C64e(0xfac85664649efa56), - C64e(0xd2e84e7474a6d24e), C64e(0x22281e141436221e), - C64e(0x763fdb9292e476db), C64e(0x1e180a0c0c121e0a), - C64e(0xb4906c4848fcb46c), C64e(0x376be4b8b88f37e4), - C64e(0xe7255d9f9f78e75d), C64e(0xb2616ebdbd0fb26e), - C64e(0x2a86ef4343692aef), C64e(0xf193a6c4c435f1a6), - C64e(0xe372a83939dae3a8), C64e(0xf762a43131c6f7a4), - C64e(0x59bd37d3d38a5937), C64e(0x86ff8bf2f274868b), - C64e(0x56b132d5d5835632), C64e(0xc50d438b8b4ec543), - C64e(0xebdc596e6e85eb59), C64e(0xc2afb7dada18c2b7), - C64e(0x8f028c01018e8f8c), C64e(0xac7964b1b11dac64), - C64e(0x6d23d29c9cf16dd2), C64e(0x3b92e04949723be0), - C64e(0xc7abb4d8d81fc7b4), C64e(0x1543faacacb915fa), - C64e(0x09fd07f3f3fa0907), C64e(0x6f8525cfcfa06f25), - C64e(0xea8fafcaca20eaaf), C64e(0x89f38ef4f47d898e), - C64e(0x208ee947476720e9), C64e(0x2820181010382818), - C64e(0x64ded56f6f0b64d5), C64e(0x83fb88f0f0738388), - C64e(0xb1946f4a4afbb16f), C64e(0x96b8725c5cca9672), - C64e(0x6c70243838546c24), C64e(0x08aef157575f08f1), - C64e(0x52e6c773732152c7), C64e(0xf33551979764f351), - C64e(0x658d23cbcbae6523), C64e(0x84597ca1a125847c), - C64e(0xbfcb9ce8e857bf9c), C64e(0x637c213e3e5d6321), - C64e(0x7c37dd9696ea7cdd), C64e(0x7fc2dc61611e7fdc), - C64e(0x911a860d0d9c9186), C64e(0x941e850f0f9b9485), - C64e(0xabdb90e0e04bab90), C64e(0xc6f8427c7cbac642), - C64e(0x57e2c471712657c4), C64e(0xe583aacccc29e5aa), - C64e(0x733bd89090e373d8), C64e(0x0f0c050606090f05), - C64e(0x03f501f7f7f40301), C64e(0x3638121c1c2a3612), - C64e(0xfe9fa3c2c23cfea3), C64e(0xe1d45f6a6a8be15f), - C64e(0x1047f9aeaebe10f9), C64e(0x6bd2d06969026bd0), - C64e(0xa82e911717bfa891), C64e(0xe82958999971e858), - C64e(0x6974273a3a536927), C64e(0xd04eb92727f7d0b9), - C64e(0x48a938d9d9914838), C64e(0x35cd13ebebde3513), - C64e(0xce56b32b2be5ceb3), C64e(0x5544332222775533), - C64e(0xd6bfbbd2d204d6bb), C64e(0x904970a9a9399070), - C64e(0x800e890707878089), C64e(0xf266a73333c1f2a7), - C64e(0xc15ab62d2decc1b6), C64e(0x6678223c3c5a6622), - C64e(0xad2a921515b8ad92), C64e(0x608920c9c9a96020), - C64e(0xdb154987875cdb49), C64e(0x1a4fffaaaab01aff), - C64e(0x88a0785050d88878), C64e(0x8e517aa5a52b8e7a), - C64e(0x8a068f0303898a8f), C64e(0x13b2f859594a13f8), - C64e(0x9b12800909929b80), C64e(0x3934171a1a233917), - C64e(0x75cada65651075da), C64e(0x53b531d7d7845331), - C64e(0x5113c68484d551c6), C64e(0xd3bbb8d0d003d3b8), - C64e(0x5e1fc38282dc5ec3), C64e(0xcb52b02929e2cbb0), - C64e(0x99b4775a5ac39977), C64e(0x333c111e1e2d3311), - C64e(0x46f6cb7b7b3d46cb), C64e(0x1f4bfca8a8b71ffc), - C64e(0x61dad66d6d0c61d6), C64e(0x4e583a2c2c624e3a) -}; - -#if !SPH_SMALL_FOOTPRINT_GROESTL - -static const sph_u64 T5[] = { - C64e(0xa5f497a5c6c632f4), C64e(0x8497eb84f8f86f97), - C64e(0x99b0c799eeee5eb0), C64e(0x8d8cf78df6f67a8c), - C64e(0x0d17e50dffffe817), C64e(0xbddcb7bdd6d60adc), - C64e(0xb1c8a7b1dede16c8), C64e(0x54fc395491916dfc), - C64e(0x50f0c050606090f0), C64e(0x0305040302020705), - C64e(0xa9e087a9cece2ee0), C64e(0x7d87ac7d5656d187), - C64e(0x192bd519e7e7cc2b), C64e(0x62a67162b5b513a6), - C64e(0xe6319ae64d4d7c31), C64e(0x9ab5c39aecec59b5), - C64e(0x45cf05458f8f40cf), C64e(0x9dbc3e9d1f1fa3bc), - C64e(0x40c00940898949c0), C64e(0x8792ef87fafa6892), - C64e(0x153fc515efefd03f), C64e(0xeb267febb2b29426), - C64e(0xc94007c98e8ece40), C64e(0x0b1ded0bfbfbe61d), - C64e(0xec2f82ec41416e2f), C64e(0x67a97d67b3b31aa9), - C64e(0xfd1cbefd5f5f431c), C64e(0xea258aea45456025), - C64e(0xbfda46bf2323f9da), C64e(0xf702a6f753535102), - C64e(0x96a1d396e4e445a1), C64e(0x5bed2d5b9b9b76ed), - C64e(0xc25deac27575285d), C64e(0x1c24d91ce1e1c524), - C64e(0xaee97aae3d3dd4e9), C64e(0x6abe986a4c4cf2be), - C64e(0x5aeed85a6c6c82ee), C64e(0x41c3fc417e7ebdc3), - C64e(0x0206f102f5f5f306), C64e(0x4fd11d4f838352d1), - C64e(0x5ce4d05c68688ce4), C64e(0xf407a2f451515607), - C64e(0x345cb934d1d18d5c), C64e(0x0818e908f9f9e118), - C64e(0x93aedf93e2e24cae), C64e(0x73954d73abab3e95), - C64e(0x53f5c453626297f5), C64e(0x3f41543f2a2a6b41), - C64e(0x0c14100c08081c14), C64e(0x52f63152959563f6), - C64e(0x65af8c654646e9af), C64e(0x5ee2215e9d9d7fe2), - C64e(0x2878602830304878), C64e(0xa1f86ea13737cff8), - C64e(0x0f11140f0a0a1b11), C64e(0xb5c45eb52f2febc4), - C64e(0x091b1c090e0e151b), C64e(0x365a483624247e5a), - C64e(0x9bb6369b1b1badb6), C64e(0x3d47a53ddfdf9847), - C64e(0x266a8126cdcda76a), C64e(0x69bb9c694e4ef5bb), - C64e(0xcd4cfecd7f7f334c), C64e(0x9fbacf9feaea50ba), - C64e(0x1b2d241b12123f2d), C64e(0x9eb93a9e1d1da4b9), - C64e(0x749cb0745858c49c), C64e(0x2e72682e34344672), - C64e(0x2d776c2d36364177), C64e(0xb2cda3b2dcdc11cd), - C64e(0xee2973eeb4b49d29), C64e(0xfb16b6fb5b5b4d16), - C64e(0xf60153f6a4a4a501), C64e(0x4dd7ec4d7676a1d7), - C64e(0x61a37561b7b714a3), C64e(0xce49face7d7d3449), - C64e(0x7b8da47b5252df8d), C64e(0x3e42a13edddd9f42), - C64e(0x7193bc715e5ecd93), C64e(0x97a226971313b1a2), - C64e(0xf50457f5a6a6a204), C64e(0x68b86968b9b901b8), - C64e(0x0000000000000000), C64e(0x2c74992cc1c1b574), - C64e(0x60a080604040e0a0), C64e(0x1f21dd1fe3e3c221), - C64e(0xc843f2c879793a43), C64e(0xed2c77edb6b69a2c), - C64e(0xbed9b3bed4d40dd9), C64e(0x46ca01468d8d47ca), - C64e(0xd970ced967671770), C64e(0x4bdde44b7272afdd), - C64e(0xde7933de9494ed79), C64e(0xd4672bd49898ff67), - C64e(0xe8237be8b0b09323), C64e(0x4ade114a85855bde), - C64e(0x6bbd6d6bbbbb06bd), C64e(0x2a7e912ac5c5bb7e), - C64e(0xe5349ee54f4f7b34), C64e(0x163ac116ededd73a), - C64e(0xc55417c58686d254), C64e(0xd7622fd79a9af862), - C64e(0x55ffcc55666699ff), C64e(0x94a722941111b6a7), - C64e(0xcf4a0fcf8a8ac04a), C64e(0x1030c910e9e9d930), - C64e(0x060a080604040e0a), C64e(0x8198e781fefe6698), - C64e(0xf00b5bf0a0a0ab0b), C64e(0x44ccf0447878b4cc), - C64e(0xbad54aba2525f0d5), C64e(0xe33e96e34b4b753e), - C64e(0xf30e5ff3a2a2ac0e), C64e(0xfe19bafe5d5d4419), - C64e(0xc05b1bc08080db5b), C64e(0x8a850a8a05058085), - C64e(0xadec7ead3f3fd3ec), C64e(0xbcdf42bc2121fedf), - C64e(0x48d8e0487070a8d8), C64e(0x040cf904f1f1fd0c), - C64e(0xdf7ac6df6363197a), C64e(0xc158eec177772f58), - C64e(0x759f4575afaf309f), C64e(0x63a584634242e7a5), - C64e(0x3050403020207050), C64e(0x1a2ed11ae5e5cb2e), - C64e(0x0e12e10efdfdef12), C64e(0x6db7656dbfbf08b7), - C64e(0x4cd4194c818155d4), C64e(0x143c30141818243c), - C64e(0x355f4c352626795f), C64e(0x2f719d2fc3c3b271), - C64e(0xe13867e1bebe8638), C64e(0xa2fd6aa23535c8fd), - C64e(0xcc4f0bcc8888c74f), C64e(0x394b5c392e2e654b), - C64e(0x57f93d5793936af9), C64e(0xf20daaf25555580d), - C64e(0x829de382fcfc619d), C64e(0x47c9f4477a7ab3c9), - C64e(0xacef8bacc8c827ef), C64e(0xe7326fe7baba8832), - C64e(0x2b7d642b32324f7d), C64e(0x95a4d795e6e642a4), - C64e(0xa0fb9ba0c0c03bfb), C64e(0x98b332981919aab3), - C64e(0xd16827d19e9ef668), C64e(0x7f815d7fa3a32281), - C64e(0x66aa88664444eeaa), C64e(0x7e82a87e5454d682), - C64e(0xabe676ab3b3bdde6), C64e(0x839e16830b0b959e), - C64e(0xca4503ca8c8cc945), C64e(0x297b9529c7c7bc7b), - C64e(0xd36ed6d36b6b056e), C64e(0x3c44503c28286c44), - C64e(0x798b5579a7a72c8b), C64e(0xe23d63e2bcbc813d), - C64e(0x1d272c1d16163127), C64e(0x769a4176adad379a), - C64e(0x3b4dad3bdbdb964d), C64e(0x56fac85664649efa), - C64e(0x4ed2e84e7474a6d2), C64e(0x1e22281e14143622), - C64e(0xdb763fdb9292e476), C64e(0x0a1e180a0c0c121e), - C64e(0x6cb4906c4848fcb4), C64e(0xe4376be4b8b88f37), - C64e(0x5de7255d9f9f78e7), C64e(0x6eb2616ebdbd0fb2), - C64e(0xef2a86ef4343692a), C64e(0xa6f193a6c4c435f1), - C64e(0xa8e372a83939dae3), C64e(0xa4f762a43131c6f7), - C64e(0x3759bd37d3d38a59), C64e(0x8b86ff8bf2f27486), - C64e(0x3256b132d5d58356), C64e(0x43c50d438b8b4ec5), - C64e(0x59ebdc596e6e85eb), C64e(0xb7c2afb7dada18c2), - C64e(0x8c8f028c01018e8f), C64e(0x64ac7964b1b11dac), - C64e(0xd26d23d29c9cf16d), C64e(0xe03b92e04949723b), - C64e(0xb4c7abb4d8d81fc7), C64e(0xfa1543faacacb915), - C64e(0x0709fd07f3f3fa09), C64e(0x256f8525cfcfa06f), - C64e(0xafea8fafcaca20ea), C64e(0x8e89f38ef4f47d89), - C64e(0xe9208ee947476720), C64e(0x1828201810103828), - C64e(0xd564ded56f6f0b64), C64e(0x8883fb88f0f07383), - C64e(0x6fb1946f4a4afbb1), C64e(0x7296b8725c5cca96), - C64e(0x246c70243838546c), C64e(0xf108aef157575f08), - C64e(0xc752e6c773732152), C64e(0x51f33551979764f3), - C64e(0x23658d23cbcbae65), C64e(0x7c84597ca1a12584), - C64e(0x9cbfcb9ce8e857bf), C64e(0x21637c213e3e5d63), - C64e(0xdd7c37dd9696ea7c), C64e(0xdc7fc2dc61611e7f), - C64e(0x86911a860d0d9c91), C64e(0x85941e850f0f9b94), - C64e(0x90abdb90e0e04bab), C64e(0x42c6f8427c7cbac6), - C64e(0xc457e2c471712657), C64e(0xaae583aacccc29e5), - C64e(0xd8733bd89090e373), C64e(0x050f0c050606090f), - C64e(0x0103f501f7f7f403), C64e(0x123638121c1c2a36), - C64e(0xa3fe9fa3c2c23cfe), C64e(0x5fe1d45f6a6a8be1), - C64e(0xf91047f9aeaebe10), C64e(0xd06bd2d06969026b), - C64e(0x91a82e911717bfa8), C64e(0x58e82958999971e8), - C64e(0x276974273a3a5369), C64e(0xb9d04eb92727f7d0), - C64e(0x3848a938d9d99148), C64e(0x1335cd13ebebde35), - C64e(0xb3ce56b32b2be5ce), C64e(0x3355443322227755), - C64e(0xbbd6bfbbd2d204d6), C64e(0x70904970a9a93990), - C64e(0x89800e8907078780), C64e(0xa7f266a73333c1f2), - C64e(0xb6c15ab62d2decc1), C64e(0x226678223c3c5a66), - C64e(0x92ad2a921515b8ad), C64e(0x20608920c9c9a960), - C64e(0x49db154987875cdb), C64e(0xff1a4fffaaaab01a), - C64e(0x7888a0785050d888), C64e(0x7a8e517aa5a52b8e), - C64e(0x8f8a068f0303898a), C64e(0xf813b2f859594a13), - C64e(0x809b12800909929b), C64e(0x173934171a1a2339), - C64e(0xda75cada65651075), C64e(0x3153b531d7d78453), - C64e(0xc65113c68484d551), C64e(0xb8d3bbb8d0d003d3), - C64e(0xc35e1fc38282dc5e), C64e(0xb0cb52b02929e2cb), - C64e(0x7799b4775a5ac399), C64e(0x11333c111e1e2d33), - C64e(0xcb46f6cb7b7b3d46), C64e(0xfc1f4bfca8a8b71f), - C64e(0xd661dad66d6d0c61), C64e(0x3a4e583a2c2c624e) -}; - -static const sph_u64 T6[] = { - C64e(0xf4a5f497a5c6c632), C64e(0x978497eb84f8f86f), - C64e(0xb099b0c799eeee5e), C64e(0x8c8d8cf78df6f67a), - C64e(0x170d17e50dffffe8), C64e(0xdcbddcb7bdd6d60a), - C64e(0xc8b1c8a7b1dede16), C64e(0xfc54fc395491916d), - C64e(0xf050f0c050606090), C64e(0x0503050403020207), - C64e(0xe0a9e087a9cece2e), C64e(0x877d87ac7d5656d1), - C64e(0x2b192bd519e7e7cc), C64e(0xa662a67162b5b513), - C64e(0x31e6319ae64d4d7c), C64e(0xb59ab5c39aecec59), - C64e(0xcf45cf05458f8f40), C64e(0xbc9dbc3e9d1f1fa3), - C64e(0xc040c00940898949), C64e(0x928792ef87fafa68), - C64e(0x3f153fc515efefd0), C64e(0x26eb267febb2b294), - C64e(0x40c94007c98e8ece), C64e(0x1d0b1ded0bfbfbe6), - C64e(0x2fec2f82ec41416e), C64e(0xa967a97d67b3b31a), - C64e(0x1cfd1cbefd5f5f43), C64e(0x25ea258aea454560), - C64e(0xdabfda46bf2323f9), C64e(0x02f702a6f7535351), - C64e(0xa196a1d396e4e445), C64e(0xed5bed2d5b9b9b76), - C64e(0x5dc25deac2757528), C64e(0x241c24d91ce1e1c5), - C64e(0xe9aee97aae3d3dd4), C64e(0xbe6abe986a4c4cf2), - C64e(0xee5aeed85a6c6c82), C64e(0xc341c3fc417e7ebd), - C64e(0x060206f102f5f5f3), C64e(0xd14fd11d4f838352), - C64e(0xe45ce4d05c68688c), C64e(0x07f407a2f4515156), - C64e(0x5c345cb934d1d18d), C64e(0x180818e908f9f9e1), - C64e(0xae93aedf93e2e24c), C64e(0x9573954d73abab3e), - C64e(0xf553f5c453626297), C64e(0x413f41543f2a2a6b), - C64e(0x140c14100c08081c), C64e(0xf652f63152959563), - C64e(0xaf65af8c654646e9), C64e(0xe25ee2215e9d9d7f), - C64e(0x7828786028303048), C64e(0xf8a1f86ea13737cf), - C64e(0x110f11140f0a0a1b), C64e(0xc4b5c45eb52f2feb), - C64e(0x1b091b1c090e0e15), C64e(0x5a365a483624247e), - C64e(0xb69bb6369b1b1bad), C64e(0x473d47a53ddfdf98), - C64e(0x6a266a8126cdcda7), C64e(0xbb69bb9c694e4ef5), - C64e(0x4ccd4cfecd7f7f33), C64e(0xba9fbacf9feaea50), - C64e(0x2d1b2d241b12123f), C64e(0xb99eb93a9e1d1da4), - C64e(0x9c749cb0745858c4), C64e(0x722e72682e343446), - C64e(0x772d776c2d363641), C64e(0xcdb2cda3b2dcdc11), - C64e(0x29ee2973eeb4b49d), C64e(0x16fb16b6fb5b5b4d), - C64e(0x01f60153f6a4a4a5), C64e(0xd74dd7ec4d7676a1), - C64e(0xa361a37561b7b714), C64e(0x49ce49face7d7d34), - C64e(0x8d7b8da47b5252df), C64e(0x423e42a13edddd9f), - C64e(0x937193bc715e5ecd), C64e(0xa297a226971313b1), - C64e(0x04f50457f5a6a6a2), C64e(0xb868b86968b9b901), - C64e(0x0000000000000000), C64e(0x742c74992cc1c1b5), - C64e(0xa060a080604040e0), C64e(0x211f21dd1fe3e3c2), - C64e(0x43c843f2c879793a), C64e(0x2ced2c77edb6b69a), - C64e(0xd9bed9b3bed4d40d), C64e(0xca46ca01468d8d47), - C64e(0x70d970ced9676717), C64e(0xdd4bdde44b7272af), - C64e(0x79de7933de9494ed), C64e(0x67d4672bd49898ff), - C64e(0x23e8237be8b0b093), C64e(0xde4ade114a85855b), - C64e(0xbd6bbd6d6bbbbb06), C64e(0x7e2a7e912ac5c5bb), - C64e(0x34e5349ee54f4f7b), C64e(0x3a163ac116ededd7), - C64e(0x54c55417c58686d2), C64e(0x62d7622fd79a9af8), - C64e(0xff55ffcc55666699), C64e(0xa794a722941111b6), - C64e(0x4acf4a0fcf8a8ac0), C64e(0x301030c910e9e9d9), - C64e(0x0a060a080604040e), C64e(0x988198e781fefe66), - C64e(0x0bf00b5bf0a0a0ab), C64e(0xcc44ccf0447878b4), - C64e(0xd5bad54aba2525f0), C64e(0x3ee33e96e34b4b75), - C64e(0x0ef30e5ff3a2a2ac), C64e(0x19fe19bafe5d5d44), - C64e(0x5bc05b1bc08080db), C64e(0x858a850a8a050580), - C64e(0xecadec7ead3f3fd3), C64e(0xdfbcdf42bc2121fe), - C64e(0xd848d8e0487070a8), C64e(0x0c040cf904f1f1fd), - C64e(0x7adf7ac6df636319), C64e(0x58c158eec177772f), - C64e(0x9f759f4575afaf30), C64e(0xa563a584634242e7), - C64e(0x5030504030202070), C64e(0x2e1a2ed11ae5e5cb), - C64e(0x120e12e10efdfdef), C64e(0xb76db7656dbfbf08), - C64e(0xd44cd4194c818155), C64e(0x3c143c3014181824), - C64e(0x5f355f4c35262679), C64e(0x712f719d2fc3c3b2), - C64e(0x38e13867e1bebe86), C64e(0xfda2fd6aa23535c8), - C64e(0x4fcc4f0bcc8888c7), C64e(0x4b394b5c392e2e65), - C64e(0xf957f93d5793936a), C64e(0x0df20daaf2555558), - C64e(0x9d829de382fcfc61), C64e(0xc947c9f4477a7ab3), - C64e(0xefacef8bacc8c827), C64e(0x32e7326fe7baba88), - C64e(0x7d2b7d642b32324f), C64e(0xa495a4d795e6e642), - C64e(0xfba0fb9ba0c0c03b), C64e(0xb398b332981919aa), - C64e(0x68d16827d19e9ef6), C64e(0x817f815d7fa3a322), - C64e(0xaa66aa88664444ee), C64e(0x827e82a87e5454d6), - C64e(0xe6abe676ab3b3bdd), C64e(0x9e839e16830b0b95), - C64e(0x45ca4503ca8c8cc9), C64e(0x7b297b9529c7c7bc), - C64e(0x6ed36ed6d36b6b05), C64e(0x443c44503c28286c), - C64e(0x8b798b5579a7a72c), C64e(0x3de23d63e2bcbc81), - C64e(0x271d272c1d161631), C64e(0x9a769a4176adad37), - C64e(0x4d3b4dad3bdbdb96), C64e(0xfa56fac85664649e), - C64e(0xd24ed2e84e7474a6), C64e(0x221e22281e141436), - C64e(0x76db763fdb9292e4), C64e(0x1e0a1e180a0c0c12), - C64e(0xb46cb4906c4848fc), C64e(0x37e4376be4b8b88f), - C64e(0xe75de7255d9f9f78), C64e(0xb26eb2616ebdbd0f), - C64e(0x2aef2a86ef434369), C64e(0xf1a6f193a6c4c435), - C64e(0xe3a8e372a83939da), C64e(0xf7a4f762a43131c6), - C64e(0x593759bd37d3d38a), C64e(0x868b86ff8bf2f274), - C64e(0x563256b132d5d583), C64e(0xc543c50d438b8b4e), - C64e(0xeb59ebdc596e6e85), C64e(0xc2b7c2afb7dada18), - C64e(0x8f8c8f028c01018e), C64e(0xac64ac7964b1b11d), - C64e(0x6dd26d23d29c9cf1), C64e(0x3be03b92e0494972), - C64e(0xc7b4c7abb4d8d81f), C64e(0x15fa1543faacacb9), - C64e(0x090709fd07f3f3fa), C64e(0x6f256f8525cfcfa0), - C64e(0xeaafea8fafcaca20), C64e(0x898e89f38ef4f47d), - C64e(0x20e9208ee9474767), C64e(0x2818282018101038), - C64e(0x64d564ded56f6f0b), C64e(0x838883fb88f0f073), - C64e(0xb16fb1946f4a4afb), C64e(0x967296b8725c5cca), - C64e(0x6c246c7024383854), C64e(0x08f108aef157575f), - C64e(0x52c752e6c7737321), C64e(0xf351f33551979764), - C64e(0x6523658d23cbcbae), C64e(0x847c84597ca1a125), - C64e(0xbf9cbfcb9ce8e857), C64e(0x6321637c213e3e5d), - C64e(0x7cdd7c37dd9696ea), C64e(0x7fdc7fc2dc61611e), - C64e(0x9186911a860d0d9c), C64e(0x9485941e850f0f9b), - C64e(0xab90abdb90e0e04b), C64e(0xc642c6f8427c7cba), - C64e(0x57c457e2c4717126), C64e(0xe5aae583aacccc29), - C64e(0x73d8733bd89090e3), C64e(0x0f050f0c05060609), - C64e(0x030103f501f7f7f4), C64e(0x36123638121c1c2a), - C64e(0xfea3fe9fa3c2c23c), C64e(0xe15fe1d45f6a6a8b), - C64e(0x10f91047f9aeaebe), C64e(0x6bd06bd2d0696902), - C64e(0xa891a82e911717bf), C64e(0xe858e82958999971), - C64e(0x69276974273a3a53), C64e(0xd0b9d04eb92727f7), - C64e(0x483848a938d9d991), C64e(0x351335cd13ebebde), - C64e(0xceb3ce56b32b2be5), C64e(0x5533554433222277), - C64e(0xd6bbd6bfbbd2d204), C64e(0x9070904970a9a939), - C64e(0x8089800e89070787), C64e(0xf2a7f266a73333c1), - C64e(0xc1b6c15ab62d2dec), C64e(0x66226678223c3c5a), - C64e(0xad92ad2a921515b8), C64e(0x6020608920c9c9a9), - C64e(0xdb49db154987875c), C64e(0x1aff1a4fffaaaab0), - C64e(0x887888a0785050d8), C64e(0x8e7a8e517aa5a52b), - C64e(0x8a8f8a068f030389), C64e(0x13f813b2f859594a), - C64e(0x9b809b1280090992), C64e(0x39173934171a1a23), - C64e(0x75da75cada656510), C64e(0x533153b531d7d784), - C64e(0x51c65113c68484d5), C64e(0xd3b8d3bbb8d0d003), - C64e(0x5ec35e1fc38282dc), C64e(0xcbb0cb52b02929e2), - C64e(0x997799b4775a5ac3), C64e(0x3311333c111e1e2d), - C64e(0x46cb46f6cb7b7b3d), C64e(0x1ffc1f4bfca8a8b7), - C64e(0x61d661dad66d6d0c), C64e(0x4e3a4e583a2c2c62) -}; - -static const sph_u64 T7[] = { - C64e(0x32f4a5f497a5c6c6), C64e(0x6f978497eb84f8f8), - C64e(0x5eb099b0c799eeee), C64e(0x7a8c8d8cf78df6f6), - C64e(0xe8170d17e50dffff), C64e(0x0adcbddcb7bdd6d6), - C64e(0x16c8b1c8a7b1dede), C64e(0x6dfc54fc39549191), - C64e(0x90f050f0c0506060), C64e(0x0705030504030202), - C64e(0x2ee0a9e087a9cece), C64e(0xd1877d87ac7d5656), - C64e(0xcc2b192bd519e7e7), C64e(0x13a662a67162b5b5), - C64e(0x7c31e6319ae64d4d), C64e(0x59b59ab5c39aecec), - C64e(0x40cf45cf05458f8f), C64e(0xa3bc9dbc3e9d1f1f), - C64e(0x49c040c009408989), C64e(0x68928792ef87fafa), - C64e(0xd03f153fc515efef), C64e(0x9426eb267febb2b2), - C64e(0xce40c94007c98e8e), C64e(0xe61d0b1ded0bfbfb), - C64e(0x6e2fec2f82ec4141), C64e(0x1aa967a97d67b3b3), - C64e(0x431cfd1cbefd5f5f), C64e(0x6025ea258aea4545), - C64e(0xf9dabfda46bf2323), C64e(0x5102f702a6f75353), - C64e(0x45a196a1d396e4e4), C64e(0x76ed5bed2d5b9b9b), - C64e(0x285dc25deac27575), C64e(0xc5241c24d91ce1e1), - C64e(0xd4e9aee97aae3d3d), C64e(0xf2be6abe986a4c4c), - C64e(0x82ee5aeed85a6c6c), C64e(0xbdc341c3fc417e7e), - C64e(0xf3060206f102f5f5), C64e(0x52d14fd11d4f8383), - C64e(0x8ce45ce4d05c6868), C64e(0x5607f407a2f45151), - C64e(0x8d5c345cb934d1d1), C64e(0xe1180818e908f9f9), - C64e(0x4cae93aedf93e2e2), C64e(0x3e9573954d73abab), - C64e(0x97f553f5c4536262), C64e(0x6b413f41543f2a2a), - C64e(0x1c140c14100c0808), C64e(0x63f652f631529595), - C64e(0xe9af65af8c654646), C64e(0x7fe25ee2215e9d9d), - C64e(0x4878287860283030), C64e(0xcff8a1f86ea13737), - C64e(0x1b110f11140f0a0a), C64e(0xebc4b5c45eb52f2f), - C64e(0x151b091b1c090e0e), C64e(0x7e5a365a48362424), - C64e(0xadb69bb6369b1b1b), C64e(0x98473d47a53ddfdf), - C64e(0xa76a266a8126cdcd), C64e(0xf5bb69bb9c694e4e), - C64e(0x334ccd4cfecd7f7f), C64e(0x50ba9fbacf9feaea), - C64e(0x3f2d1b2d241b1212), C64e(0xa4b99eb93a9e1d1d), - C64e(0xc49c749cb0745858), C64e(0x46722e72682e3434), - C64e(0x41772d776c2d3636), C64e(0x11cdb2cda3b2dcdc), - C64e(0x9d29ee2973eeb4b4), C64e(0x4d16fb16b6fb5b5b), - C64e(0xa501f60153f6a4a4), C64e(0xa1d74dd7ec4d7676), - C64e(0x14a361a37561b7b7), C64e(0x3449ce49face7d7d), - C64e(0xdf8d7b8da47b5252), C64e(0x9f423e42a13edddd), - C64e(0xcd937193bc715e5e), C64e(0xb1a297a226971313), - C64e(0xa204f50457f5a6a6), C64e(0x01b868b86968b9b9), - C64e(0x0000000000000000), C64e(0xb5742c74992cc1c1), - C64e(0xe0a060a080604040), C64e(0xc2211f21dd1fe3e3), - C64e(0x3a43c843f2c87979), C64e(0x9a2ced2c77edb6b6), - C64e(0x0dd9bed9b3bed4d4), C64e(0x47ca46ca01468d8d), - C64e(0x1770d970ced96767), C64e(0xafdd4bdde44b7272), - C64e(0xed79de7933de9494), C64e(0xff67d4672bd49898), - C64e(0x9323e8237be8b0b0), C64e(0x5bde4ade114a8585), - C64e(0x06bd6bbd6d6bbbbb), C64e(0xbb7e2a7e912ac5c5), - C64e(0x7b34e5349ee54f4f), C64e(0xd73a163ac116eded), - C64e(0xd254c55417c58686), C64e(0xf862d7622fd79a9a), - C64e(0x99ff55ffcc556666), C64e(0xb6a794a722941111), - C64e(0xc04acf4a0fcf8a8a), C64e(0xd9301030c910e9e9), - C64e(0x0e0a060a08060404), C64e(0x66988198e781fefe), - C64e(0xab0bf00b5bf0a0a0), C64e(0xb4cc44ccf0447878), - C64e(0xf0d5bad54aba2525), C64e(0x753ee33e96e34b4b), - C64e(0xac0ef30e5ff3a2a2), C64e(0x4419fe19bafe5d5d), - C64e(0xdb5bc05b1bc08080), C64e(0x80858a850a8a0505), - C64e(0xd3ecadec7ead3f3f), C64e(0xfedfbcdf42bc2121), - C64e(0xa8d848d8e0487070), C64e(0xfd0c040cf904f1f1), - C64e(0x197adf7ac6df6363), C64e(0x2f58c158eec17777), - C64e(0x309f759f4575afaf), C64e(0xe7a563a584634242), - C64e(0x7050305040302020), C64e(0xcb2e1a2ed11ae5e5), - C64e(0xef120e12e10efdfd), C64e(0x08b76db7656dbfbf), - C64e(0x55d44cd4194c8181), C64e(0x243c143c30141818), - C64e(0x795f355f4c352626), C64e(0xb2712f719d2fc3c3), - C64e(0x8638e13867e1bebe), C64e(0xc8fda2fd6aa23535), - C64e(0xc74fcc4f0bcc8888), C64e(0x654b394b5c392e2e), - C64e(0x6af957f93d579393), C64e(0x580df20daaf25555), - C64e(0x619d829de382fcfc), C64e(0xb3c947c9f4477a7a), - C64e(0x27efacef8bacc8c8), C64e(0x8832e7326fe7baba), - C64e(0x4f7d2b7d642b3232), C64e(0x42a495a4d795e6e6), - C64e(0x3bfba0fb9ba0c0c0), C64e(0xaab398b332981919), - C64e(0xf668d16827d19e9e), C64e(0x22817f815d7fa3a3), - C64e(0xeeaa66aa88664444), C64e(0xd6827e82a87e5454), - C64e(0xdde6abe676ab3b3b), C64e(0x959e839e16830b0b), - C64e(0xc945ca4503ca8c8c), C64e(0xbc7b297b9529c7c7), - C64e(0x056ed36ed6d36b6b), C64e(0x6c443c44503c2828), - C64e(0x2c8b798b5579a7a7), C64e(0x813de23d63e2bcbc), - C64e(0x31271d272c1d1616), C64e(0x379a769a4176adad), - C64e(0x964d3b4dad3bdbdb), C64e(0x9efa56fac8566464), - C64e(0xa6d24ed2e84e7474), C64e(0x36221e22281e1414), - C64e(0xe476db763fdb9292), C64e(0x121e0a1e180a0c0c), - C64e(0xfcb46cb4906c4848), C64e(0x8f37e4376be4b8b8), - C64e(0x78e75de7255d9f9f), C64e(0x0fb26eb2616ebdbd), - C64e(0x692aef2a86ef4343), C64e(0x35f1a6f193a6c4c4), - C64e(0xdae3a8e372a83939), C64e(0xc6f7a4f762a43131), - C64e(0x8a593759bd37d3d3), C64e(0x74868b86ff8bf2f2), - C64e(0x83563256b132d5d5), C64e(0x4ec543c50d438b8b), - C64e(0x85eb59ebdc596e6e), C64e(0x18c2b7c2afb7dada), - C64e(0x8e8f8c8f028c0101), C64e(0x1dac64ac7964b1b1), - C64e(0xf16dd26d23d29c9c), C64e(0x723be03b92e04949), - C64e(0x1fc7b4c7abb4d8d8), C64e(0xb915fa1543faacac), - C64e(0xfa090709fd07f3f3), C64e(0xa06f256f8525cfcf), - C64e(0x20eaafea8fafcaca), C64e(0x7d898e89f38ef4f4), - C64e(0x6720e9208ee94747), C64e(0x3828182820181010), - C64e(0x0b64d564ded56f6f), C64e(0x73838883fb88f0f0), - C64e(0xfbb16fb1946f4a4a), C64e(0xca967296b8725c5c), - C64e(0x546c246c70243838), C64e(0x5f08f108aef15757), - C64e(0x2152c752e6c77373), C64e(0x64f351f335519797), - C64e(0xae6523658d23cbcb), C64e(0x25847c84597ca1a1), - C64e(0x57bf9cbfcb9ce8e8), C64e(0x5d6321637c213e3e), - C64e(0xea7cdd7c37dd9696), C64e(0x1e7fdc7fc2dc6161), - C64e(0x9c9186911a860d0d), C64e(0x9b9485941e850f0f), - C64e(0x4bab90abdb90e0e0), C64e(0xbac642c6f8427c7c), - C64e(0x2657c457e2c47171), C64e(0x29e5aae583aacccc), - C64e(0xe373d8733bd89090), C64e(0x090f050f0c050606), - C64e(0xf4030103f501f7f7), C64e(0x2a36123638121c1c), - C64e(0x3cfea3fe9fa3c2c2), C64e(0x8be15fe1d45f6a6a), - C64e(0xbe10f91047f9aeae), C64e(0x026bd06bd2d06969), - C64e(0xbfa891a82e911717), C64e(0x71e858e829589999), - C64e(0x5369276974273a3a), C64e(0xf7d0b9d04eb92727), - C64e(0x91483848a938d9d9), C64e(0xde351335cd13ebeb), - C64e(0xe5ceb3ce56b32b2b), C64e(0x7755335544332222), - C64e(0x04d6bbd6bfbbd2d2), C64e(0x399070904970a9a9), - C64e(0x878089800e890707), C64e(0xc1f2a7f266a73333), - C64e(0xecc1b6c15ab62d2d), C64e(0x5a66226678223c3c), - C64e(0xb8ad92ad2a921515), C64e(0xa96020608920c9c9), - C64e(0x5cdb49db15498787), C64e(0xb01aff1a4fffaaaa), - C64e(0xd8887888a0785050), C64e(0x2b8e7a8e517aa5a5), - C64e(0x898a8f8a068f0303), C64e(0x4a13f813b2f85959), - C64e(0x929b809b12800909), C64e(0x2339173934171a1a), - C64e(0x1075da75cada6565), C64e(0x84533153b531d7d7), - C64e(0xd551c65113c68484), C64e(0x03d3b8d3bbb8d0d0), - C64e(0xdc5ec35e1fc38282), C64e(0xe2cbb0cb52b02929), - C64e(0xc3997799b4775a5a), C64e(0x2d3311333c111e1e), - C64e(0x3d46cb46f6cb7b7b), C64e(0xb71ffc1f4bfca8a8), - C64e(0x0c61d661dad66d6d), C64e(0x624e3a4e583a2c2c) -}; - -#endif -#define DECL_STATE_SMALL \ - sph_u64 H[8]; - -#define READ_STATE_SMALL(sc) do { \ - memcpy(H, (sc)->state.wide, sizeof H); \ - } while (0) - -#define WRITE_STATE_SMALL(sc) do { \ - memcpy((sc)->state.wide, H, sizeof H); \ - } while (0) - -#if SPH_SMALL_FOOTPRINT_GROESTL - -#define RSTT(d, a, b0, b1, b2, b3, b4, b5, b6, b7) do { \ - t[d] = T0[B64_0(a[b0])] \ - ^ R64(T0[B64_1(a[b1])], 8) \ - ^ R64(T0[B64_2(a[b2])], 16) \ - ^ R64(T0[B64_3(a[b3])], 24) \ - ^ T4[B64_4(a[b4])] \ - ^ R64(T4[B64_5(a[b5])], 8) \ - ^ R64(T4[B64_6(a[b6])], 16) \ - ^ R64(T4[B64_7(a[b7])], 24); \ - } while (0) - -#else - -#define RSTT(d, a, b0, b1, b2, b3, b4, b5, b6, b7) do { \ - t[d] = T0[B64_0(a[b0])] \ - ^ T1[B64_1(a[b1])] \ - ^ T2[B64_2(a[b2])] \ - ^ T3[B64_3(a[b3])] \ - ^ T4[B64_4(a[b4])] \ - ^ T5[B64_5(a[b5])] \ - ^ T6[B64_6(a[b6])] \ - ^ T7[B64_7(a[b7])]; \ - } while (0) - -#endif - -#define ROUND_SMALL_P(a, r) do { \ - sph_u64 t[8]; \ - a[0] ^= PC64(0x00, r); \ - a[1] ^= PC64(0x10, r); \ - a[2] ^= PC64(0x20, r); \ - a[3] ^= PC64(0x30, r); \ - a[4] ^= PC64(0x40, r); \ - a[5] ^= PC64(0x50, r); \ - a[6] ^= PC64(0x60, r); \ - a[7] ^= PC64(0x70, r); \ - RSTT(0, a, 0, 1, 2, 3, 4, 5, 6, 7); \ - RSTT(1, a, 1, 2, 3, 4, 5, 6, 7, 0); \ - RSTT(2, a, 2, 3, 4, 5, 6, 7, 0, 1); \ - RSTT(3, a, 3, 4, 5, 6, 7, 0, 1, 2); \ - RSTT(4, a, 4, 5, 6, 7, 0, 1, 2, 3); \ - RSTT(5, a, 5, 6, 7, 0, 1, 2, 3, 4); \ - RSTT(6, a, 6, 7, 0, 1, 2, 3, 4, 5); \ - RSTT(7, a, 7, 0, 1, 2, 3, 4, 5, 6); \ - a[0] = t[0]; \ - a[1] = t[1]; \ - a[2] = t[2]; \ - a[3] = t[3]; \ - a[4] = t[4]; \ - a[5] = t[5]; \ - a[6] = t[6]; \ - a[7] = t[7]; \ - } while (0) - -#define ROUND_SMALL_Q(a, r) do { \ - sph_u64 t[8]; \ - a[0] ^= QC64(0x00, r); \ - a[1] ^= QC64(0x10, r); \ - a[2] ^= QC64(0x20, r); \ - a[3] ^= QC64(0x30, r); \ - a[4] ^= QC64(0x40, r); \ - a[5] ^= QC64(0x50, r); \ - a[6] ^= QC64(0x60, r); \ - a[7] ^= QC64(0x70, r); \ - RSTT(0, a, 1, 3, 5, 7, 0, 2, 4, 6); \ - RSTT(1, a, 2, 4, 6, 0, 1, 3, 5, 7); \ - RSTT(2, a, 3, 5, 7, 1, 2, 4, 6, 0); \ - RSTT(3, a, 4, 6, 0, 2, 3, 5, 7, 1); \ - RSTT(4, a, 5, 7, 1, 3, 4, 6, 0, 2); \ - RSTT(5, a, 6, 0, 2, 4, 5, 7, 1, 3); \ - RSTT(6, a, 7, 1, 3, 5, 6, 0, 2, 4); \ - RSTT(7, a, 0, 2, 4, 6, 7, 1, 3, 5); \ - a[0] = t[0]; \ - a[1] = t[1]; \ - a[2] = t[2]; \ - a[3] = t[3]; \ - a[4] = t[4]; \ - a[5] = t[5]; \ - a[6] = t[6]; \ - a[7] = t[7]; \ - } while (0) - -#if SPH_SMALL_FOOTPRINT_GROESTL - -#define PERM_SMALL_P(a) do { \ - int r; \ - for (r = 0; r < 10; r ++) \ - ROUND_SMALL_P(a, r); \ - } while (0) - -#define PERM_SMALL_Q(a) do { \ - int r; \ - for (r = 0; r < 10; r ++) \ - ROUND_SMALL_Q(a, r); \ - } while (0) - -#else - -/* - * Apparently, unrolling more than that confuses GCC, resulting in - * lower performance, even though L1 cache would be no problem. - */ -#define PERM_SMALL_P(a) do { \ - int r; \ - for (r = 0; r < 10; r += 2) { \ - ROUND_SMALL_P(a, r + 0); \ - ROUND_SMALL_P(a, r + 1); \ - } \ - } while (0) - -#define PERM_SMALL_Q(a) do { \ - int r; \ - for (r = 0; r < 10; r += 2) { \ - ROUND_SMALL_Q(a, r + 0); \ - ROUND_SMALL_Q(a, r + 1); \ - } \ - } while (0) - -#endif - -#define COMPRESS_SMALL do { \ - sph_u64 g[8], m[8]; \ - size_t u; \ - for (u = 0; u < 8; u ++) { \ - m[u] = dec64e_aligned(buf + (u << 3)); \ - g[u] = m[u] ^ H[u]; \ - } \ - PERM_SMALL_P(g); \ - PERM_SMALL_Q(m); \ - for (u = 0; u < 8; u ++) \ - H[u] ^= g[u] ^ m[u]; \ - } while (0) - -#define FINAL_SMALL do { \ - sph_u64 x[8]; \ - size_t u; \ - memcpy(x, H, sizeof x); \ - PERM_SMALL_P(x); \ - for (u = 0; u < 8; u ++) \ - H[u] ^= x[u]; \ - } while (0) - -#define DECL_STATE_BIG \ - sph_u64 H[16]; - -#define READ_STATE_BIG(sc) do { \ - memcpy(H, (sc)->state.wide, sizeof H); \ - } while (0) - -#define WRITE_STATE_BIG(sc) do { \ - memcpy((sc)->state.wide, H, sizeof H); \ - } while (0) - -#if SPH_SMALL_FOOTPRINT_GROESTL - -#define RBTT(d, a, b0, b1, b2, b3, b4, b5, b6, b7) do { \ - t[d] = T0[B64_0(a[b0])] \ - ^ R64(T0[B64_1(a[b1])], 8) \ - ^ R64(T0[B64_2(a[b2])], 16) \ - ^ R64(T0[B64_3(a[b3])], 24) \ - ^ T4[B64_4(a[b4])] \ - ^ R64(T4[B64_5(a[b5])], 8) \ - ^ R64(T4[B64_6(a[b6])], 16) \ - ^ R64(T4[B64_7(a[b7])], 24); \ - } while (0) - -#else - -#define RBTT(d, a, b0, b1, b2, b3, b4, b5, b6, b7) do { \ - t[d] = T0[B64_0(a[b0])] \ - ^ T1[B64_1(a[b1])] \ - ^ T2[B64_2(a[b2])] \ - ^ T3[B64_3(a[b3])] \ - ^ T4[B64_4(a[b4])] \ - ^ T5[B64_5(a[b5])] \ - ^ T6[B64_6(a[b6])] \ - ^ T7[B64_7(a[b7])]; \ - } while (0) - -#endif - -#if SPH_SMALL_FOOTPRINT_GROESTL - -#define ROUND_BIG_P(a, r) do { \ - sph_u64 t[16]; \ - size_t u; \ - a[0x0] ^= PC64(0x00, r); \ - a[0x1] ^= PC64(0x10, r); \ - a[0x2] ^= PC64(0x20, r); \ - a[0x3] ^= PC64(0x30, r); \ - a[0x4] ^= PC64(0x40, r); \ - a[0x5] ^= PC64(0x50, r); \ - a[0x6] ^= PC64(0x60, r); \ - a[0x7] ^= PC64(0x70, r); \ - a[0x8] ^= PC64(0x80, r); \ - a[0x9] ^= PC64(0x90, r); \ - a[0xA] ^= PC64(0xA0, r); \ - a[0xB] ^= PC64(0xB0, r); \ - a[0xC] ^= PC64(0xC0, r); \ - a[0xD] ^= PC64(0xD0, r); \ - a[0xE] ^= PC64(0xE0, r); \ - a[0xF] ^= PC64(0xF0, r); \ - for (u = 0; u < 16; u += 4) { \ - RBTT(u + 0, a, u + 0, (u + 1) & 0xF, \ - (u + 2) & 0xF, (u + 3) & 0xF, (u + 4) & 0xF, \ - (u + 5) & 0xF, (u + 6) & 0xF, (u + 11) & 0xF); \ - RBTT(u + 1, a, u + 1, (u + 2) & 0xF, \ - (u + 3) & 0xF, (u + 4) & 0xF, (u + 5) & 0xF, \ - (u + 6) & 0xF, (u + 7) & 0xF, (u + 12) & 0xF); \ - RBTT(u + 2, a, u + 2, (u + 3) & 0xF, \ - (u + 4) & 0xF, (u + 5) & 0xF, (u + 6) & 0xF, \ - (u + 7) & 0xF, (u + 8) & 0xF, (u + 13) & 0xF); \ - RBTT(u + 3, a, u + 3, (u + 4) & 0xF, \ - (u + 5) & 0xF, (u + 6) & 0xF, (u + 7) & 0xF, \ - (u + 8) & 0xF, (u + 9) & 0xF, (u + 14) & 0xF); \ - } \ - memcpy(a, t, sizeof t); \ - } while (0) - -#define ROUND_BIG_Q(a, r) do { \ - sph_u64 t[16]; \ - size_t u; \ - a[0x0] ^= QC64(0x00, r); \ - a[0x1] ^= QC64(0x10, r); \ - a[0x2] ^= QC64(0x20, r); \ - a[0x3] ^= QC64(0x30, r); \ - a[0x4] ^= QC64(0x40, r); \ - a[0x5] ^= QC64(0x50, r); \ - a[0x6] ^= QC64(0x60, r); \ - a[0x7] ^= QC64(0x70, r); \ - a[0x8] ^= QC64(0x80, r); \ - a[0x9] ^= QC64(0x90, r); \ - a[0xA] ^= QC64(0xA0, r); \ - a[0xB] ^= QC64(0xB0, r); \ - a[0xC] ^= QC64(0xC0, r); \ - a[0xD] ^= QC64(0xD0, r); \ - a[0xE] ^= QC64(0xE0, r); \ - a[0xF] ^= QC64(0xF0, r); \ - for (u = 0; u < 16; u += 4) { \ - RBTT(u + 0, a, (u + 1) & 0xF, (u + 3) & 0xF, \ - (u + 5) & 0xF, (u + 11) & 0xF, (u + 0) & 0xF, \ - (u + 2) & 0xF, (u + 4) & 0xF, (u + 6) & 0xF); \ - RBTT(u + 1, a, (u + 2) & 0xF, (u + 4) & 0xF, \ - (u + 6) & 0xF, (u + 12) & 0xF, (u + 1) & 0xF, \ - (u + 3) & 0xF, (u + 5) & 0xF, (u + 7) & 0xF); \ - RBTT(u + 2, a, (u + 3) & 0xF, (u + 5) & 0xF, \ - (u + 7) & 0xF, (u + 13) & 0xF, (u + 2) & 0xF, \ - (u + 4) & 0xF, (u + 6) & 0xF, (u + 8) & 0xF); \ - RBTT(u + 3, a, (u + 4) & 0xF, (u + 6) & 0xF, \ - (u + 8) & 0xF, (u + 14) & 0xF, (u + 3) & 0xF, \ - (u + 5) & 0xF, (u + 7) & 0xF, (u + 9) & 0xF); \ - } \ - memcpy(a, t, sizeof t); \ - } while (0) - -#else - -#define ROUND_BIG_P(a, r) do { \ - sph_u64 t[16]; \ - a[0x0] ^= PC64(0x00, r); \ - a[0x1] ^= PC64(0x10, r); \ - a[0x2] ^= PC64(0x20, r); \ - a[0x3] ^= PC64(0x30, r); \ - a[0x4] ^= PC64(0x40, r); \ - a[0x5] ^= PC64(0x50, r); \ - a[0x6] ^= PC64(0x60, r); \ - a[0x7] ^= PC64(0x70, r); \ - a[0x8] ^= PC64(0x80, r); \ - a[0x9] ^= PC64(0x90, r); \ - a[0xA] ^= PC64(0xA0, r); \ - a[0xB] ^= PC64(0xB0, r); \ - a[0xC] ^= PC64(0xC0, r); \ - a[0xD] ^= PC64(0xD0, r); \ - a[0xE] ^= PC64(0xE0, r); \ - a[0xF] ^= PC64(0xF0, r); \ - RBTT(0x0, a, 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0xB); \ - RBTT(0x1, a, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0xC); \ - RBTT(0x2, a, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0xD); \ - RBTT(0x3, a, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xE); \ - RBTT(0x4, a, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xF); \ - RBTT(0x5, a, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0x0); \ - RBTT(0x6, a, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0x1); \ - RBTT(0x7, a, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0x2); \ - RBTT(0x8, a, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0x3); \ - RBTT(0x9, a, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0x4); \ - RBTT(0xA, a, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0x0, 0x5); \ - RBTT(0xB, a, 0xB, 0xC, 0xD, 0xE, 0xF, 0x0, 0x1, 0x6); \ - RBTT(0xC, a, 0xC, 0xD, 0xE, 0xF, 0x0, 0x1, 0x2, 0x7); \ - RBTT(0xD, a, 0xD, 0xE, 0xF, 0x0, 0x1, 0x2, 0x3, 0x8); \ - RBTT(0xE, a, 0xE, 0xF, 0x0, 0x1, 0x2, 0x3, 0x4, 0x9); \ - RBTT(0xF, a, 0xF, 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0xA); \ - a[0x0] = t[0x0]; \ - a[0x1] = t[0x1]; \ - a[0x2] = t[0x2]; \ - a[0x3] = t[0x3]; \ - a[0x4] = t[0x4]; \ - a[0x5] = t[0x5]; \ - a[0x6] = t[0x6]; \ - a[0x7] = t[0x7]; \ - a[0x8] = t[0x8]; \ - a[0x9] = t[0x9]; \ - a[0xA] = t[0xA]; \ - a[0xB] = t[0xB]; \ - a[0xC] = t[0xC]; \ - a[0xD] = t[0xD]; \ - a[0xE] = t[0xE]; \ - a[0xF] = t[0xF]; \ - } while (0) - -#define ROUND_BIG_Q(a, r) do { \ - sph_u64 t[16]; \ - a[0x0] ^= QC64(0x00, r); \ - a[0x1] ^= QC64(0x10, r); \ - a[0x2] ^= QC64(0x20, r); \ - a[0x3] ^= QC64(0x30, r); \ - a[0x4] ^= QC64(0x40, r); \ - a[0x5] ^= QC64(0x50, r); \ - a[0x6] ^= QC64(0x60, r); \ - a[0x7] ^= QC64(0x70, r); \ - a[0x8] ^= QC64(0x80, r); \ - a[0x9] ^= QC64(0x90, r); \ - a[0xA] ^= QC64(0xA0, r); \ - a[0xB] ^= QC64(0xB0, r); \ - a[0xC] ^= QC64(0xC0, r); \ - a[0xD] ^= QC64(0xD0, r); \ - a[0xE] ^= QC64(0xE0, r); \ - a[0xF] ^= QC64(0xF0, r); \ - RBTT(0x0, a, 0x1, 0x3, 0x5, 0xB, 0x0, 0x2, 0x4, 0x6); \ - RBTT(0x1, a, 0x2, 0x4, 0x6, 0xC, 0x1, 0x3, 0x5, 0x7); \ - RBTT(0x2, a, 0x3, 0x5, 0x7, 0xD, 0x2, 0x4, 0x6, 0x8); \ - RBTT(0x3, a, 0x4, 0x6, 0x8, 0xE, 0x3, 0x5, 0x7, 0x9); \ - RBTT(0x4, a, 0x5, 0x7, 0x9, 0xF, 0x4, 0x6, 0x8, 0xA); \ - RBTT(0x5, a, 0x6, 0x8, 0xA, 0x0, 0x5, 0x7, 0x9, 0xB); \ - RBTT(0x6, a, 0x7, 0x9, 0xB, 0x1, 0x6, 0x8, 0xA, 0xC); \ - RBTT(0x7, a, 0x8, 0xA, 0xC, 0x2, 0x7, 0x9, 0xB, 0xD); \ - RBTT(0x8, a, 0x9, 0xB, 0xD, 0x3, 0x8, 0xA, 0xC, 0xE); \ - RBTT(0x9, a, 0xA, 0xC, 0xE, 0x4, 0x9, 0xB, 0xD, 0xF); \ - RBTT(0xA, a, 0xB, 0xD, 0xF, 0x5, 0xA, 0xC, 0xE, 0x0); \ - RBTT(0xB, a, 0xC, 0xE, 0x0, 0x6, 0xB, 0xD, 0xF, 0x1); \ - RBTT(0xC, a, 0xD, 0xF, 0x1, 0x7, 0xC, 0xE, 0x0, 0x2); \ - RBTT(0xD, a, 0xE, 0x0, 0x2, 0x8, 0xD, 0xF, 0x1, 0x3); \ - RBTT(0xE, a, 0xF, 0x1, 0x3, 0x9, 0xE, 0x0, 0x2, 0x4); \ - RBTT(0xF, a, 0x0, 0x2, 0x4, 0xA, 0xF, 0x1, 0x3, 0x5); \ - a[0x0] = t[0x0]; \ - a[0x1] = t[0x1]; \ - a[0x2] = t[0x2]; \ - a[0x3] = t[0x3]; \ - a[0x4] = t[0x4]; \ - a[0x5] = t[0x5]; \ - a[0x6] = t[0x6]; \ - a[0x7] = t[0x7]; \ - a[0x8] = t[0x8]; \ - a[0x9] = t[0x9]; \ - a[0xA] = t[0xA]; \ - a[0xB] = t[0xB]; \ - a[0xC] = t[0xC]; \ - a[0xD] = t[0xD]; \ - a[0xE] = t[0xE]; \ - a[0xF] = t[0xF]; \ - } while (0) - -#endif - -#define PERM_BIG_P(a) do { \ - int r; \ - for (r = 0; r < 14; r += 2) { \ - ROUND_BIG_P(a, r + 0); \ - ROUND_BIG_P(a, r + 1); \ - } \ - } while (0) - -#define PERM_BIG_Q(a) do { \ - int r; \ - for (r = 0; r < 14; r += 2) { \ - ROUND_BIG_Q(a, r + 0); \ - ROUND_BIG_Q(a, r + 1); \ - } \ - } while (0) - -/* obsolete -#if SPH_SMALL_FOOTPRINT_GROESTL - -#define COMPRESS_BIG do { \ - sph_u64 g[16], m[16], *ya; \ - const sph_u64 *yc; \ - size_t u; \ - int i; \ - for (u = 0; u < 16; u ++) { \ - m[u] = dec64e_aligned(buf + (u << 3)); \ - g[u] = m[u] ^ H[u]; \ - } \ - ya = g; \ - yc = CP; \ - for (i = 0; i < 2; i ++) { \ - PERM_BIG(ya, yc); \ - ya = m; \ - yc = CQ; \ - } \ - for (u = 0; u < 16; u ++) { \ - H[u] ^= g[u] ^ m[u]; \ - } \ - } while (0) - -#else -*/ - -#define COMPRESS_BIG do { \ - sph_u64 g[16], m[16]; \ - size_t u; \ - for (u = 0; u < 16; u ++) { \ - m[u] = dec64e_aligned(buf + (u << 3)); \ - g[u] = m[u] ^ H[u]; \ - } \ - PERM_BIG_P(g); \ - PERM_BIG_Q(m); \ - for (u = 0; u < 16; u ++) { \ - H[u] ^= g[u] ^ m[u]; \ - } \ - } while (0) - -/* obsolete -#endif -*/ - -#define FINAL_BIG do { \ - sph_u64 x[16]; \ - size_t u; \ - memcpy(x, H, sizeof x); \ - PERM_BIG_P(x); \ - for (u = 0; u < 16; u ++) \ - H[u] ^= x[u]; \ - } while (0) - -#else static const sph_u32 T0up[] = { C32e(0xc632f4a5), C32e(0xf86f9784), C32e(0xee5eb099), C32e(0xf67a8c8d), @@ -2291,8 +706,6 @@ static const sph_u32 T3dn[] = { memcpy(a, t, sizeof t); \ } while (0) -#if SPH_SMALL_FOOTPRINT_GROESTL - #define PERM_SMALL_P(a) do { \ int r; \ for (r = 0; r < 10; r ++) \ @@ -2305,25 +718,6 @@ static const sph_u32 T3dn[] = { ROUND_SMALL_Q(a, r); \ } while (0) -#else - -#define PERM_SMALL_P(a) do { \ - int r; \ - for (r = 0; r < 10; r += 2) { \ - ROUND_SMALL_P(a, r + 0); \ - ROUND_SMALL_P(a, r + 1); \ - } \ - } while (0) - -#define PERM_SMALL_Q(a) do { \ - int r; \ - for (r = 0; r < 10; r += 2) { \ - ROUND_SMALL_Q(a, r + 0); \ - ROUND_SMALL_Q(a, r + 1); \ - } \ - } while (0) - -#endif #define COMPRESS_SMALL do { \ sph_u32 g[16], m[16]; \ @@ -2358,7 +752,6 @@ static const sph_u32 T3dn[] = { memcpy((sc)->state.narrow, H, sizeof H); \ } while (0) -#if SPH_SMALL_FOOTPRINT_GROESTL #define RBTT(d0, d1, a, b0, b1, b2, b3, b4, b5, b6, b7) do { \ sph_u32 fu2 = T0up[B32_2(a[b2])]; \ @@ -2387,30 +780,6 @@ static const sph_u32 T3dn[] = { ^ R32u(fu7, fd7); \ } while (0) -#else - -#define RBTT(d0, d1, a, b0, b1, b2, b3, b4, b5, b6, b7) do { \ - t[d0] = T0up[B32_0(a[b0])] \ - ^ T1up[B32_1(a[b1])] \ - ^ T2up[B32_2(a[b2])] \ - ^ T3up[B32_3(a[b3])] \ - ^ T0dn[B32_0(a[b4])] \ - ^ T1dn[B32_1(a[b5])] \ - ^ T2dn[B32_2(a[b6])] \ - ^ T3dn[B32_3(a[b7])]; \ - t[d1] = T0dn[B32_0(a[b0])] \ - ^ T1dn[B32_1(a[b1])] \ - ^ T2dn[B32_2(a[b2])] \ - ^ T3dn[B32_3(a[b3])] \ - ^ T0up[B32_0(a[b4])] \ - ^ T1up[B32_1(a[b5])] \ - ^ T2up[B32_2(a[b6])] \ - ^ T3up[B32_3(a[b7])]; \ - } while (0) - -#endif - -#if SPH_SMALL_FOOTPRINT_GROESTL #define ROUND_BIG_P(a, r) do { \ sph_u32 t[32]; \ @@ -2532,149 +901,6 @@ static const sph_u32 T3dn[] = { memcpy(a, t, sizeof t); \ } while (0) -#else - -#define ROUND_BIG_P(a, r) do { \ - sph_u32 t[32]; \ - a[0x00] ^= PC32up(0x00, r); \ - a[0x01] ^= PC32dn(0x00, r); \ - a[0x02] ^= PC32up(0x10, r); \ - a[0x03] ^= PC32dn(0x10, r); \ - a[0x04] ^= PC32up(0x20, r); \ - a[0x05] ^= PC32dn(0x20, r); \ - a[0x06] ^= PC32up(0x30, r); \ - a[0x07] ^= PC32dn(0x30, r); \ - a[0x08] ^= PC32up(0x40, r); \ - a[0x09] ^= PC32dn(0x40, r); \ - a[0x0A] ^= PC32up(0x50, r); \ - a[0x0B] ^= PC32dn(0x50, r); \ - a[0x0C] ^= PC32up(0x60, r); \ - a[0x0D] ^= PC32dn(0x60, r); \ - a[0x0E] ^= PC32up(0x70, r); \ - a[0x0F] ^= PC32dn(0x70, r); \ - a[0x10] ^= PC32up(0x80, r); \ - a[0x11] ^= PC32dn(0x80, r); \ - a[0x12] ^= PC32up(0x90, r); \ - a[0x13] ^= PC32dn(0x90, r); \ - a[0x14] ^= PC32up(0xA0, r); \ - a[0x15] ^= PC32dn(0xA0, r); \ - a[0x16] ^= PC32up(0xB0, r); \ - a[0x17] ^= PC32dn(0xB0, r); \ - a[0x18] ^= PC32up(0xC0, r); \ - a[0x19] ^= PC32dn(0xC0, r); \ - a[0x1A] ^= PC32up(0xD0, r); \ - a[0x1B] ^= PC32dn(0xD0, r); \ - a[0x1C] ^= PC32up(0xE0, r); \ - a[0x1D] ^= PC32dn(0xE0, r); \ - a[0x1E] ^= PC32up(0xF0, r); \ - a[0x1F] ^= PC32dn(0xF0, r); \ - RBTT(0x00, 0x01, a, \ - 0x00, 0x02, 0x04, 0x06, 0x09, 0x0B, 0x0D, 0x17); \ - RBTT(0x02, 0x03, a, \ - 0x02, 0x04, 0x06, 0x08, 0x0B, 0x0D, 0x0F, 0x19); \ - RBTT(0x04, 0x05, a, \ - 0x04, 0x06, 0x08, 0x0A, 0x0D, 0x0F, 0x11, 0x1B); \ - RBTT(0x06, 0x07, a, \ - 0x06, 0x08, 0x0A, 0x0C, 0x0F, 0x11, 0x13, 0x1D); \ - RBTT(0x08, 0x09, a, \ - 0x08, 0x0A, 0x0C, 0x0E, 0x11, 0x13, 0x15, 0x1F); \ - RBTT(0x0A, 0x0B, a, \ - 0x0A, 0x0C, 0x0E, 0x10, 0x13, 0x15, 0x17, 0x01); \ - RBTT(0x0C, 0x0D, a, \ - 0x0C, 0x0E, 0x10, 0x12, 0x15, 0x17, 0x19, 0x03); \ - RBTT(0x0E, 0x0F, a, \ - 0x0E, 0x10, 0x12, 0x14, 0x17, 0x19, 0x1B, 0x05); \ - RBTT(0x10, 0x11, a, \ - 0x10, 0x12, 0x14, 0x16, 0x19, 0x1B, 0x1D, 0x07); \ - RBTT(0x12, 0x13, a, \ - 0x12, 0x14, 0x16, 0x18, 0x1B, 0x1D, 0x1F, 0x09); \ - RBTT(0x14, 0x15, a, \ - 0x14, 0x16, 0x18, 0x1A, 0x1D, 0x1F, 0x01, 0x0B); \ - RBTT(0x16, 0x17, a, \ - 0x16, 0x18, 0x1A, 0x1C, 0x1F, 0x01, 0x03, 0x0D); \ - RBTT(0x18, 0x19, a, \ - 0x18, 0x1A, 0x1C, 0x1E, 0x01, 0x03, 0x05, 0x0F); \ - RBTT(0x1A, 0x1B, a, \ - 0x1A, 0x1C, 0x1E, 0x00, 0x03, 0x05, 0x07, 0x11); \ - RBTT(0x1C, 0x1D, a, \ - 0x1C, 0x1E, 0x00, 0x02, 0x05, 0x07, 0x09, 0x13); \ - RBTT(0x1E, 0x1F, a, \ - 0x1E, 0x00, 0x02, 0x04, 0x07, 0x09, 0x0B, 0x15); \ - memcpy(a, t, sizeof t); \ - } while (0) - -#define ROUND_BIG_Q(a, r) do { \ - sph_u32 t[32]; \ - a[0x00] ^= QC32up(0x00, r); \ - a[0x01] ^= QC32dn(0x00, r); \ - a[0x02] ^= QC32up(0x10, r); \ - a[0x03] ^= QC32dn(0x10, r); \ - a[0x04] ^= QC32up(0x20, r); \ - a[0x05] ^= QC32dn(0x20, r); \ - a[0x06] ^= QC32up(0x30, r); \ - a[0x07] ^= QC32dn(0x30, r); \ - a[0x08] ^= QC32up(0x40, r); \ - a[0x09] ^= QC32dn(0x40, r); \ - a[0x0A] ^= QC32up(0x50, r); \ - a[0x0B] ^= QC32dn(0x50, r); \ - a[0x0C] ^= QC32up(0x60, r); \ - a[0x0D] ^= QC32dn(0x60, r); \ - a[0x0E] ^= QC32up(0x70, r); \ - a[0x0F] ^= QC32dn(0x70, r); \ - a[0x10] ^= QC32up(0x80, r); \ - a[0x11] ^= QC32dn(0x80, r); \ - a[0x12] ^= QC32up(0x90, r); \ - a[0x13] ^= QC32dn(0x90, r); \ - a[0x14] ^= QC32up(0xA0, r); \ - a[0x15] ^= QC32dn(0xA0, r); \ - a[0x16] ^= QC32up(0xB0, r); \ - a[0x17] ^= QC32dn(0xB0, r); \ - a[0x18] ^= QC32up(0xC0, r); \ - a[0x19] ^= QC32dn(0xC0, r); \ - a[0x1A] ^= QC32up(0xD0, r); \ - a[0x1B] ^= QC32dn(0xD0, r); \ - a[0x1C] ^= QC32up(0xE0, r); \ - a[0x1D] ^= QC32dn(0xE0, r); \ - a[0x1E] ^= QC32up(0xF0, r); \ - a[0x1F] ^= QC32dn(0xF0, r); \ - RBTT(0x00, 0x01, a, \ - 0x02, 0x06, 0x0A, 0x16, 0x01, 0x05, 0x09, 0x0D); \ - RBTT(0x02, 0x03, a, \ - 0x04, 0x08, 0x0C, 0x18, 0x03, 0x07, 0x0B, 0x0F); \ - RBTT(0x04, 0x05, a, \ - 0x06, 0x0A, 0x0E, 0x1A, 0x05, 0x09, 0x0D, 0x11); \ - RBTT(0x06, 0x07, a, \ - 0x08, 0x0C, 0x10, 0x1C, 0x07, 0x0B, 0x0F, 0x13); \ - RBTT(0x08, 0x09, a, \ - 0x0A, 0x0E, 0x12, 0x1E, 0x09, 0x0D, 0x11, 0x15); \ - RBTT(0x0A, 0x0B, a, \ - 0x0C, 0x10, 0x14, 0x00, 0x0B, 0x0F, 0x13, 0x17); \ - RBTT(0x0C, 0x0D, a, \ - 0x0E, 0x12, 0x16, 0x02, 0x0D, 0x11, 0x15, 0x19); \ - RBTT(0x0E, 0x0F, a, \ - 0x10, 0x14, 0x18, 0x04, 0x0F, 0x13, 0x17, 0x1B); \ - RBTT(0x10, 0x11, a, \ - 0x12, 0x16, 0x1A, 0x06, 0x11, 0x15, 0x19, 0x1D); \ - RBTT(0x12, 0x13, a, \ - 0x14, 0x18, 0x1C, 0x08, 0x13, 0x17, 0x1B, 0x1F); \ - RBTT(0x14, 0x15, a, \ - 0x16, 0x1A, 0x1E, 0x0A, 0x15, 0x19, 0x1D, 0x01); \ - RBTT(0x16, 0x17, a, \ - 0x18, 0x1C, 0x00, 0x0C, 0x17, 0x1B, 0x1F, 0x03); \ - RBTT(0x18, 0x19, a, \ - 0x1A, 0x1E, 0x02, 0x0E, 0x19, 0x1D, 0x01, 0x05); \ - RBTT(0x1A, 0x1B, a, \ - 0x1C, 0x00, 0x04, 0x10, 0x1B, 0x1F, 0x03, 0x07); \ - RBTT(0x1C, 0x1D, a, \ - 0x1E, 0x02, 0x06, 0x12, 0x1D, 0x01, 0x05, 0x09); \ - RBTT(0x1E, 0x1F, a, \ - 0x00, 0x04, 0x08, 0x14, 0x1F, 0x03, 0x07, 0x0B); \ - memcpy(a, t, sizeof t); \ - } while (0) - -#endif - -#if SPH_SMALL_FOOTPRINT_GROESTL #define PERM_BIG_P(a) do { \ int r; \ @@ -2688,25 +914,6 @@ static const sph_u32 T3dn[] = { ROUND_BIG_Q(a, r); \ } while (0) -#else - -#define PERM_BIG_P(a) do { \ - int r; \ - for (r = 0; r < 14; r += 2) { \ - ROUND_BIG_P(a, r + 0); \ - ROUND_BIG_P(a, r + 1); \ - } \ - } while (0) - -#define PERM_BIG_Q(a) do { \ - int r; \ - for (r = 0; r < 14; r += 2) { \ - ROUND_BIG_Q(a, r + 0); \ - ROUND_BIG_Q(a, r + 1); \ - } \ - } while (0) - -#endif #define COMPRESS_BIG do { \ sph_u32 g[32], m[32]; \ @@ -2730,141 +937,6 @@ static const sph_u32 T3dn[] = { H[u] ^= x[u]; \ } while (0) -#endif - -static void -groestl_small_init(sph_groestl_small_context *sc, unsigned out_size) -{ - size_t u; - - sc->ptr = 0; -#if SPH_GROESTL_64 - for (u = 0; u < 7; u ++) - sc->state.wide[u] = 0; -#if USE_LE - sc->state.wide[7] = ((sph_u64)(out_size & 0xFF) << 56) - | ((sph_u64)(out_size & 0xFF00) << 40); -#else - sc->state.wide[7] = (sph_u64)out_size; -#endif -#else - for (u = 0; u < 15; u ++) - sc->state.narrow[u] = 0; -#if USE_LE - sc->state.narrow[15] = ((sph_u32)(out_size & 0xFF) << 24) - | ((sph_u32)(out_size & 0xFF00) << 8); -#else - sc->state.narrow[15] = (sph_u32)out_size; -#endif -#endif -#if SPH_64 - sc->count = 0; -#else - sc->count_high = 0; - sc->count_low = 0; -#endif -} - -static void -groestl_small_core(sph_groestl_small_context *sc, const void *data, size_t len) -{ - unsigned char *buf; - size_t ptr; - DECL_STATE_SMALL - - buf = sc->buf; - ptr = sc->ptr; - if (len < (sizeof sc->buf) - ptr) { - memcpy(buf + ptr, data, len); - ptr += len; - sc->ptr = ptr; - return; - } - - READ_STATE_SMALL(sc); - while (len > 0) { - size_t clen; - - clen = (sizeof sc->buf) - ptr; - if (clen > len) - clen = len; - memcpy(buf + ptr, data, clen); - ptr += clen; - data = (const unsigned char *)data + clen; - len -= clen; - if (ptr == sizeof sc->buf) { - COMPRESS_SMALL; -#if SPH_64 - sc->count ++; -#else - if ((sc->count_low = SPH_T32(sc->count_low + 1)) == 0) - sc->count_high = SPH_T32(sc->count_high + 1); -#endif - ptr = 0; - } - } - WRITE_STATE_SMALL(sc); - sc->ptr = ptr; -} - -static void -groestl_small_close(sph_groestl_small_context *sc, - unsigned ub, unsigned n, void *dst, size_t out_len) -{ - unsigned char pad[72]; - size_t u, ptr, pad_len; -#if SPH_64 - sph_u64 count; -#else - sph_u32 count_high, count_low; -#endif - unsigned z; - DECL_STATE_SMALL - - ptr = sc->ptr; - z = 0x80 >> n; - pad[0] = ((ub & -z) | z) & 0xFF; - if (ptr < 56) { - pad_len = 64 - ptr; -#if SPH_64 - count = SPH_T64(sc->count + 1); -#else - count_low = SPH_T32(sc->count_low + 1); - count_high = SPH_T32(sc->count_high); - if (count_low == 0) - count_high = SPH_T32(count_high + 1); -#endif - } else { - pad_len = 128 - ptr; -#if SPH_64 - count = SPH_T64(sc->count + 2); -#else - count_low = SPH_T32(sc->count_low + 2); - count_high = SPH_T32(sc->count_high); - if (count_low <= 1) - count_high = SPH_T32(count_high + 1); -#endif - } - memset(pad + 1, 0, pad_len - 9); -#if SPH_64 - sph_enc64be(pad + pad_len - 8, count); -#else - sph_enc64be(pad + pad_len - 8, count_high); - sph_enc64be(pad + pad_len - 4, count_low); -#endif - groestl_small_core(sc, pad, pad_len); - READ_STATE_SMALL(sc); - FINAL_SMALL; -#if SPH_GROESTL_64 - for (u = 0; u < 4; u ++) - enc64e(pad + (u << 3), H[u + 4]); -#else - for (u = 0; u < 8; u ++) - enc32e(pad + (u << 2), H[u + 8]); -#endif - memcpy(dst, pad + 32 - out_len, out_len); - groestl_small_init(sc, (unsigned)out_len << 3); -} static void groestl_big_init(sph_groestl_big_context *sc, unsigned out_size) @@ -2872,31 +944,11 @@ groestl_big_init(sph_groestl_big_context *sc, unsigned out_size) size_t u; sc->ptr = 0; -#if SPH_GROESTL_64 - for (u = 0; u < 15; u ++) - sc->state.wide[u] = 0; -#if USE_LE - sc->state.wide[15] = ((sph_u64)(out_size & 0xFF) << 56) - | ((sph_u64)(out_size & 0xFF00) << 40); -#else - sc->state.wide[15] = (sph_u64)out_size; -#endif -#else for (u = 0; u < 31; u ++) sc->state.narrow[u] = 0; -#if USE_LE sc->state.narrow[31] = ((sph_u32)(out_size & 0xFF) << 24) | ((sph_u32)(out_size & 0xFF00) << 8); -#else - sc->state.narrow[31] = (sph_u32)out_size; -#endif -#endif -#if SPH_64 sc->count = 0; -#else - sc->count_high = 0; - sc->count_low = 0; -#endif } static void @@ -2928,12 +980,7 @@ groestl_big_core(sph_groestl_big_context *sc, const void *data, size_t len) len -= clen; if (ptr == sizeof sc->buf) { COMPRESS_BIG; -#if SPH_64 sc->count ++; -#else - if ((sc->count_low = SPH_T32(sc->count_low + 1)) == 0) - sc->count_high = SPH_T32(sc->count_high + 1); -#endif ptr = 0; } } @@ -2947,11 +994,7 @@ groestl_big_close(sph_groestl_big_context *sc, { unsigned char pad[136]; size_t ptr, pad_len, u; -#if SPH_64 sph_u64 count; -#else - sph_u32 count_high, count_low; -#endif unsigned z; DECL_STATE_BIG @@ -2960,130 +1003,22 @@ groestl_big_close(sph_groestl_big_context *sc, pad[0] = ((ub & -z) | z) & 0xFF; if (ptr < 120) { pad_len = 128 - ptr; -#if SPH_64 count = SPH_T64(sc->count + 1); -#else - count_low = SPH_T32(sc->count_low + 1); - count_high = SPH_T32(sc->count_high); - if (count_low == 0) - count_high = SPH_T32(count_high + 1); -#endif } else { pad_len = 256 - ptr; -#if SPH_64 count = SPH_T64(sc->count + 2); -#else - count_low = SPH_T32(sc->count_low + 2); - count_high = SPH_T32(sc->count_high); - if (count_low <= 1) - count_high = SPH_T32(count_high + 1); -#endif } memset(pad + 1, 0, pad_len - 9); -#if SPH_64 sph_enc64be(pad + pad_len - 8, count); -#else - sph_enc64be(pad + pad_len - 8, count_high); - sph_enc64be(pad + pad_len - 4, count_low); -#endif groestl_big_core(sc, pad, pad_len); READ_STATE_BIG(sc); FINAL_BIG; -#if SPH_GROESTL_64 - for (u = 0; u < 8; u ++) - enc64e(pad + (u << 3), H[u + 8]); -#else for (u = 0; u < 16; u ++) enc32e(pad + (u << 2), H[u + 16]); -#endif memcpy(dst, pad + 64 - out_len, out_len); groestl_big_init(sc, (unsigned)out_len << 3); } -/* see sph_groestl.h */ -void -sph_groestl224_init(void *cc) -{ - groestl_small_init((sph_groestl_small_context *)cc, 224); -} - -/* see sph_groestl.h */ -void -sph_groestl224(void *cc, const void *data, size_t len) -{ - groestl_small_core((sph_groestl_small_context *)cc, data, len); -} - -/* see sph_groestl.h */ -void -sph_groestl224_close(void *cc, void *dst) -{ - groestl_small_close((sph_groestl_small_context *)cc, 0, 0, dst, 28); -} - -/* see sph_groestl.h */ -void -sph_groestl224_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) -{ - groestl_small_close((sph_groestl_small_context *)cc, ub, n, dst, 28); -} - -/* see sph_groestl.h */ -void -sph_groestl256_init(void *cc) -{ - groestl_small_init((sph_groestl_small_context *)cc, 256); -} - -/* see sph_groestl.h */ -void -sph_groestl256(void *cc, const void *data, size_t len) -{ - groestl_small_core((sph_groestl_small_context *)cc, data, len); -} - -/* see sph_groestl.h */ -void -sph_groestl256_close(void *cc, void *dst) -{ - groestl_small_close((sph_groestl_small_context *)cc, 0, 0, dst, 32); -} - -/* see sph_groestl.h */ -void -sph_groestl256_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) -{ - groestl_small_close((sph_groestl_small_context *)cc, ub, n, dst, 32); -} - -/* see sph_groestl.h */ -void -sph_groestl384_init(void *cc) -{ - groestl_big_init((sph_groestl_big_context *)cc, 384); -} - -/* see sph_groestl.h */ -void -sph_groestl384(void *cc, const void *data, size_t len) -{ - groestl_big_core((sph_groestl_big_context *)cc, data, len); -} - -/* see sph_groestl.h */ -void -sph_groestl384_close(void *cc, void *dst) -{ - groestl_big_close((sph_groestl_big_context *)cc, 0, 0, dst, 48); -} - -/* see sph_groestl.h */ -void -sph_groestl384_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) -{ - groestl_big_close((sph_groestl_big_context *)cc, ub, n, dst, 48); -} - /* see sph_groestl.h */ void groestl512_Init(void *cc) diff --git a/groestl.h b/groestl.h index 08263f3da..533d8c0bb 100644 --- a/groestl.h +++ b/groestl.h @@ -1,4 +1,5 @@ -/* $Id: sph_groestl.h 216 2010-06-08 09:46:57Z tp $ */ +/* Groestl hash from https://github.com/Groestlcoin/vanitygen + * Trezor adaptation by Yura Pakhuchiy . */ /** * Groestl interface. This code implements Groestl with the recommended * parameters for SHA-3, with outputs of 224, 256, 384 and 512 bits. @@ -32,71 +33,10 @@ * @author Thomas Pornin */ -#ifndef SPH_GROESTL_H__ -#define SPH_GROESTL_H__ +#ifndef GROESTL_H__ +#define GROESTL_H__ #include -#include "groestl_internal.h" - -/** - * Output size (in bits) for Groestl-224. - */ -#define SPH_SIZE_groestl224 224 - -/** - * Output size (in bits) for Groestl-256. - */ -#define SPH_SIZE_groestl256 256 - -/** - * Output size (in bits) for Groestl-384. - */ -#define SPH_SIZE_groestl384 384 - -/** - * Output size (in bits) for Groestl-512. - */ -#define SPH_SIZE_groestl512 512 - -/** - * This structure is a context for Groestl-224 and Groestl-256 computations: - * it contains the intermediate values and some data from the last - * entered block. Once a Groestl computation has been performed, the - * context can be reused for another computation. - * - * The contents of this structure are private. A running Groestl - * computation can be cloned by copying the context (e.g. with a simple - * memcpy()). - */ -typedef struct { -#ifndef DOXYGEN_IGNORE - unsigned char buf[64]; /* first field, for alignment */ - size_t ptr; - union { -#if SPH_64 - sph_u64 wide[8]; -#endif - sph_u32 narrow[16]; - } state; -#if SPH_64 - sph_u64 count; -#else - sph_u32 count_high, count_low; -#endif -#endif -} sph_groestl_small_context; - -/** - * This structure is a context for Groestl-224 computations. It is - * identical to the common sph_groestl_small_context. - */ -typedef sph_groestl_small_context sph_groestl224_context; - -/** - * This structure is a context for Groestl-256 computations. It is - * identical to the common sph_groestl_small_context. - */ -typedef sph_groestl_small_context sph_groestl256_context; /** * This structure is a context for Groestl-384 and Groestl-512 computations: @@ -109,170 +49,17 @@ typedef sph_groestl_small_context sph_groestl256_context; * memcpy()). */ typedef struct { -#ifndef DOXYGEN_IGNORE unsigned char buf[128]; /* first field, for alignment */ size_t ptr; union { -#if SPH_64 - sph_u64 wide[16]; -#endif - sph_u32 narrow[32]; + uint64_t wide[16]; + uint32_t narrow[32]; } state; -#if SPH_64 - sph_u64 count; -#else - sph_u32 count_high, count_low; -#endif -#endif + uint64_t count; } sph_groestl_big_context; -/** - * This structure is a context for Groestl-384 computations. It is - * identical to the common sph_groestl_small_context. - */ -typedef sph_groestl_big_context sph_groestl384_context; - -/** - * This structure is a context for Groestl-512 computations. It is - * identical to the common sph_groestl_small_context. - */ typedef sph_groestl_big_context GROESTL512_CTX; -/** - * Initialize a Groestl-224 context. This process performs no memory allocation. - * - * @param cc the Groestl-224 context (pointer to a - * sph_groestl224_context) - */ -void sph_groestl224_init(void *cc); - -/** - * Process some data bytes. It is acceptable that len is zero - * (in which case this function does nothing). - * - * @param cc the Groestl-224 context - * @param data the input data - * @param len the input data length (in bytes) - */ -void sph_groestl224(void *cc, const void *data, size_t len); - -/** - * Terminate the current Groestl-224 computation and output the result into - * the provided buffer. The destination buffer must be wide enough to - * accomodate the result (28 bytes). The context is automatically - * reinitialized. - * - * @param cc the Groestl-224 context - * @param dst the destination buffer - */ -void sph_groestl224_close(void *cc, void *dst); - -/** - * Add a few additional bits (0 to 7) to the current computation, then - * terminate it and output the result in the provided buffer, which must - * be wide enough to accomodate the result (28 bytes). If bit number i - * in ub has value 2^i, then the extra bits are those - * numbered 7 downto 8-n (this is the big-endian convention at the byte - * level). The context is automatically reinitialized. - * - * @param cc the Groestl-224 context - * @param ub the extra bits - * @param n the number of extra bits (0 to 7) - * @param dst the destination buffer - */ -void sph_groestl224_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); - -/** - * Initialize a Groestl-256 context. This process performs no memory allocation. - * - * @param cc the Groestl-256 context (pointer to a - * sph_groestl256_context) - */ -void sph_groestl256_init(void *cc); - -/** - * Process some data bytes. It is acceptable that len is zero - * (in which case this function does nothing). - * - * @param cc the Groestl-256 context - * @param data the input data - * @param len the input data length (in bytes) - */ -void sph_groestl256(void *cc, const void *data, size_t len); - -/** - * Terminate the current Groestl-256 computation and output the result into - * the provided buffer. The destination buffer must be wide enough to - * accomodate the result (32 bytes). The context is automatically - * reinitialized. - * - * @param cc the Groestl-256 context - * @param dst the destination buffer - */ -void sph_groestl256_close(void *cc, void *dst); - -/** - * Add a few additional bits (0 to 7) to the current computation, then - * terminate it and output the result in the provided buffer, which must - * be wide enough to accomodate the result (32 bytes). If bit number i - * in ub has value 2^i, then the extra bits are those - * numbered 7 downto 8-n (this is the big-endian convention at the byte - * level). The context is automatically reinitialized. - * - * @param cc the Groestl-256 context - * @param ub the extra bits - * @param n the number of extra bits (0 to 7) - * @param dst the destination buffer - */ -void sph_groestl256_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); - -/** - * Initialize a Groestl-384 context. This process performs no memory allocation. - * - * @param cc the Groestl-384 context (pointer to a - * sph_groestl384_context) - */ -void sph_groestl384_init(void *cc); - -/** - * Process some data bytes. It is acceptable that len is zero - * (in which case this function does nothing). - * - * @param cc the Groestl-384 context - * @param data the input data - * @param len the input data length (in bytes) - */ -void sph_groestl384(void *cc, const void *data, size_t len); - -/** - * Terminate the current Groestl-384 computation and output the result into - * the provided buffer. The destination buffer must be wide enough to - * accomodate the result (48 bytes). The context is automatically - * reinitialized. - * - * @param cc the Groestl-384 context - * @param dst the destination buffer - */ -void sph_groestl384_close(void *cc, void *dst); - -/** - * Add a few additional bits (0 to 7) to the current computation, then - * terminate it and output the result in the provided buffer, which must - * be wide enough to accomodate the result (48 bytes). If bit number i - * in ub has value 2^i, then the extra bits are those - * numbered 7 downto 8-n (this is the big-endian convention at the byte - * level). The context is automatically reinitialized. - * - * @param cc the Groestl-384 context - * @param ub the extra bits - * @param n the number of extra bits (0 to 7) - * @param dst the destination buffer - */ -void sph_groestl384_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); - /** * Initialize a Groestl-512 context. This process performs no memory allocation. * diff --git a/groestl_internal.h b/groestl_internal.h index 7295b0b37..193680146 100644 --- a/groestl_internal.h +++ b/groestl_internal.h @@ -1,4 +1,5 @@ -/* $Id: sph_types.h 260 2011-07-21 01:02:38Z tp $ */ +/* Groestl hash from https://github.com/Groestlcoin/vanitygen + * Trezor adaptation by Yura Pakhuchiy . */ /** * Basic type definitions. * @@ -44,8 +45,8 @@ * @author Thomas Pornin */ -#ifndef SPH_TYPES_H__ -#define SPH_TYPES_H__ +#ifndef GROESTL_INTERNAL_H__ +#define GROESTL_INTERNAL_H__ #include @@ -57,998 +58,45 @@ #error This code requires 8-bit bytes #endif -/* ============= BEGIN documentation block for Doxygen ============ */ - -#ifdef DOXYGEN_IGNORE - -/** @mainpage sphlib C code documentation - * - * @section overview Overview - * - * sphlib is a library which contains implementations of - * various cryptographic hash functions. These pages have been generated - * with doxygen and - * document the API for the C implementations. - * - * The API is described in appropriate header files, which are available - * in the "Files" section. Each hash function family has its own header, - * whose name begins with "sph_" and contains the family - * name. For instance, the API for the RIPEMD hash functions is available - * in the header file sph_ripemd.h. - * - * @section principles API structure and conventions - * - * @subsection io Input/output conventions - * - * In all generality, hash functions operate over strings of bits. - * Individual bits are rarely encountered in C programming or actual - * communication protocols; most protocols converge on the ubiquitous - * "octet" which is a group of eight bits. Data is thus expressed as a - * stream of octets. The C programming language contains the notion of a - * "byte", which is a data unit managed under the type "unsigned - * char". The C standard prescribes that a byte should hold at - * least eight bits, but possibly more. Most modern architectures, even - * in the embedded world, feature eight-bit bytes, i.e. map bytes to - * octets. - * - * Nevertheless, for some of the implemented hash functions, an extra - * API has been added, which allows the input of arbitrary sequences of - * bits: when the computation is about to be closed, 1 to 7 extra bits - * can be added. The functions for which this API is implemented include - * the SHA-2 functions and all SHA-3 candidates. - * - * sphlib defines hash function which may hash octet streams, - * i.e. streams of bits where the number of bits is a multiple of eight. - * The data input functions in the sphlib API expect data - * as anonymous pointers ("const void *") with a length - * (of type "size_t") which gives the input data chunk length - * in bytes. A byte is assumed to be an octet; the sph_types.h - * header contains a compile-time test which prevents compilation on - * architectures where this property is not met. - * - * The hash function output is also converted into bytes. All currently - * implemented hash functions have an output width which is a multiple of - * eight, and this is likely to remain true for new designs. - * - * Most hash functions internally convert input data into 32-bit of 64-bit - * words, using either little-endian or big-endian conversion. The hash - * output also often consists of such words, which are encoded into output - * bytes with a similar endianness convention. Some hash functions have - * been only loosely specified on that subject; when necessary, - * sphlib has been tested against published "reference" - * implementations in order to use the same conventions. - * - * @subsection shortname Function short name - * - * Each implemented hash function has a "short name" which is used - * internally to derive the identifiers for the functions and context - * structures which the function uses. For instance, MD5 has the short - * name "md5". Short names are listed in the next section, - * for the implemented hash functions. In subsequent sections, the - * short name will be assumed to be "XXX": replace with the - * actual hash function name to get the C identifier. - * - * Note: some functions within the same family share the same core - * elements, such as update function or context structure. Correspondingly, - * some of the defined types or functions may actually be macros which - * transparently evaluate to another type or function name. - * - * @subsection context Context structure - * - * Each implemented hash fonction has its own context structure, available - * under the type name "sph_XXX_context" for the hash function - * with short name "XXX". This structure holds all needed - * state for a running hash computation. - * - * The contents of these structures are meant to be opaque, and private - * to the implementation. However, these contents are specified in the - * header files so that application code which uses sphlib - * may access the size of those structures. - * - * The caller is responsible for allocating the context structure, - * whether by dynamic allocation (malloc() or equivalent), - * static allocation (a global permanent variable), as an automatic - * variable ("on the stack"), or by any other mean which ensures proper - * structure alignment. sphlib code performs no dynamic - * allocation by itself. - * - * The context must be initialized before use, using the - * sph_XXX_init() function. This function sets the context - * state to proper initial values for hashing. - * - * Since all state data is contained within the context structure, - * sphlib is thread-safe and reentrant: several hash - * computations may be performed in parallel, provided that they do not - * operate on the same context. Moreover, a running computation can be - * cloned by copying the context (with a simple memcpy()): - * the context and its clone are then independant and may be updated - * with new data and/or closed without interfering with each other. - * Similarly, a context structure can be moved in memory at will: - * context structures contain no pointer, in particular no pointer to - * themselves. - * - * @subsection dataio Data input - * - * Hashed data is input with the sph_XXX() fonction, which - * takes as parameters a pointer to the context, a pointer to the data - * to hash, and the number of data bytes to hash. The context is updated - * with the new data. - * - * Data can be input in one or several calls, with arbitrary input lengths. - * However, it is best, performance wise, to input data by relatively big - * chunks (say a few kilobytes), because this allows sphlib to - * optimize things and avoid internal copying. - * - * When all data has been input, the context can be closed with - * sph_XXX_close(). The hash output is computed and written - * into the provided buffer. The caller must take care to provide a - * buffer of appropriate length; e.g., when using SHA-1, the output is - * a 20-byte word, therefore the output buffer must be at least 20-byte - * long. - * - * For some hash functions, the sph_XXX_addbits_and_close() - * function can be used instead of sph_XXX_close(). This - * function can take a few extra bits to be added at - * the end of the input message. This allows hashing messages with a - * bit length which is not a multiple of 8. The extra bits are provided - * as an unsigned integer value, and a bit count. The bit count must be - * between 0 and 7, inclusive. The extra bits are provided as bits 7 to - * 0 (bits of numerical value 128, 64, 32... downto 0), in that order. - * For instance, to add three bits of value 1, 1 and 0, the unsigned - * integer will have value 192 (1*128 + 1*64 + 0*32) and the bit count - * will be 3. - * - * The SPH_SIZE_XXX macro is defined for each hash function; - * it evaluates to the function output size, expressed in bits. For instance, - * SPH_SIZE_sha1 evaluates to 160. - * - * When closed, the context is automatically reinitialized and can be - * immediately used for another computation. It is not necessary to call - * sph_XXX_init() after a close. Note that - * sph_XXX_init() can still be called to "reset" a context, - * i.e. forget previously input data, and get back to the initial state. - * - * @subsection alignment Data alignment - * - * "Alignment" is a property of data, which is said to be "properly - * aligned" when its emplacement in memory is such that the data can - * be optimally read by full words. This depends on the type of access; - * basically, some hash functions will read data by 32-bit or 64-bit - * words. sphlib does not mandate such alignment for input - * data, but using aligned data can substantially improve performance. - * - * As a rule, it is best to input data by chunks whose length (in bytes) - * is a multiple of eight, and which begins at "generally aligned" - * addresses, such as the base address returned by a call to - * malloc(). - * - * @section functions Implemented functions - * - * We give here the list of implemented functions. They are grouped by - * family; to each family corresponds a specific header file. Each - * individual function has its associated "short name". Please refer to - * the documentation for that header file to get details on the hash - * function denomination and provenance. - * - * Note: the functions marked with a '(64)' in the list below are - * available only if the C compiler provides an integer type of length - * 64 bits or more. Such a type is mandatory in the latest C standard - * (ISO 9899:1999, aka "C99") and is present in several older compilers - * as well, so chances are that such a type is available. - * - * - HAVAL family: file sph_haval.h - * - HAVAL-128/3 (128-bit, 3 passes): short name: haval128_3 - * - HAVAL-128/4 (128-bit, 4 passes): short name: haval128_4 - * - HAVAL-128/5 (128-bit, 5 passes): short name: haval128_5 - * - HAVAL-160/3 (160-bit, 3 passes): short name: haval160_3 - * - HAVAL-160/4 (160-bit, 4 passes): short name: haval160_4 - * - HAVAL-160/5 (160-bit, 5 passes): short name: haval160_5 - * - HAVAL-192/3 (192-bit, 3 passes): short name: haval192_3 - * - HAVAL-192/4 (192-bit, 4 passes): short name: haval192_4 - * - HAVAL-192/5 (192-bit, 5 passes): short name: haval192_5 - * - HAVAL-224/3 (224-bit, 3 passes): short name: haval224_3 - * - HAVAL-224/4 (224-bit, 4 passes): short name: haval224_4 - * - HAVAL-224/5 (224-bit, 5 passes): short name: haval224_5 - * - HAVAL-256/3 (256-bit, 3 passes): short name: haval256_3 - * - HAVAL-256/4 (256-bit, 4 passes): short name: haval256_4 - * - HAVAL-256/5 (256-bit, 5 passes): short name: haval256_5 - * - MD2: file sph_md2.h, short name: md2 - * - MD4: file sph_md4.h, short name: md4 - * - MD5: file sph_md5.h, short name: md5 - * - PANAMA: file sph_panama.h, short name: panama - * - RadioGatun family: file sph_radiogatun.h - * - RadioGatun[32]: short name: radiogatun32 - * - RadioGatun[64]: short name: radiogatun64 (64) - * - RIPEMD family: file sph_ripemd.h - * - RIPEMD: short name: ripemd - * - RIPEMD-128: short name: ripemd128 - * - RIPEMD-160: short name: ripemd160 - * - SHA-0: file sph_sha0.h, short name: sha0 - * - SHA-1: file sph_sha1.h, short name: sha1 - * - SHA-2 family, 32-bit hashes: file sph_sha2.h - * - SHA-224: short name: sha224 - * - SHA-256: short name: sha256 - * - SHA-384: short name: sha384 (64) - * - SHA-512: short name: sha512 (64) - * - Tiger family: file sph_tiger.h - * - Tiger: short name: tiger (64) - * - Tiger2: short name: tiger2 (64) - * - WHIRLPOOL family: file sph_whirlpool.h - * - WHIRLPOOL-0: short name: whirlpool0 (64) - * - WHIRLPOOL-1: short name: whirlpool1 (64) - * - WHIRLPOOL: short name: whirlpool (64) - * - * The fourteen second-round SHA-3 candidates are also implemented; - * when applicable, the implementations follow the "final" specifications - * as published for the third round of the SHA-3 competition (BLAKE, - * Groestl, JH, Keccak and Skein have been tweaked for third round). - * - * - BLAKE family: file sph_blake.h - * - BLAKE-224: short name: blake224 - * - BLAKE-256: short name: blake256 - * - BLAKE-384: short name: blake384 - * - BLAKE-512: short name: blake512 - * - BMW (Blue Midnight Wish) family: file sph_bmw.h - * - BMW-224: short name: bmw224 - * - BMW-256: short name: bmw256 - * - BMW-384: short name: bmw384 (64) - * - BMW-512: short name: bmw512 (64) - * - CubeHash family: file sph_cubehash.h (specified as - * CubeHash16/32 in the CubeHash specification) - * - CubeHash-224: short name: cubehash224 - * - CubeHash-256: short name: cubehash256 - * - CubeHash-384: short name: cubehash384 - * - CubeHash-512: short name: cubehash512 - * - ECHO family: file sph_echo.h - * - ECHO-224: short name: echo224 - * - ECHO-256: short name: echo256 - * - ECHO-384: short name: echo384 - * - ECHO-512: short name: echo512 - * - Fugue family: file sph_fugue.h - * - Fugue-224: short name: fugue224 - * - Fugue-256: short name: fugue256 - * - Fugue-384: short name: fugue384 - * - Fugue-512: short name: fugue512 - * - Groestl family: file sph_groestl.h - * - Groestl-224: short name: groestl224 - * - Groestl-256: short name: groestl256 - * - Groestl-384: short name: groestl384 - * - Groestl-512: short name: groestl512 - * - Hamsi family: file sph_hamsi.h - * - Hamsi-224: short name: hamsi224 - * - Hamsi-256: short name: hamsi256 - * - Hamsi-384: short name: hamsi384 - * - Hamsi-512: short name: hamsi512 - * - JH family: file sph_jh.h - * - JH-224: short name: jh224 - * - JH-256: short name: jh256 - * - JH-384: short name: jh384 - * - JH-512: short name: jh512 - * - Keccak family: file sph_keccak.h - * - Keccak-224: short name: keccak224 - * - Keccak-256: short name: keccak256 - * - Keccak-384: short name: keccak384 - * - Keccak-512: short name: keccak512 - * - Luffa family: file sph_luffa.h - * - Luffa-224: short name: luffa224 - * - Luffa-256: short name: luffa256 - * - Luffa-384: short name: luffa384 - * - Luffa-512: short name: luffa512 - * - Shabal family: file sph_shabal.h - * - Shabal-192: short name: shabal192 - * - Shabal-224: short name: shabal224 - * - Shabal-256: short name: shabal256 - * - Shabal-384: short name: shabal384 - * - Shabal-512: short name: shabal512 - * - SHAvite-3 family: file sph_shavite.h - * - SHAvite-224 (nominally "SHAvite-3 with 224-bit output"): - * short name: shabal224 - * - SHAvite-256 (nominally "SHAvite-3 with 256-bit output"): - * short name: shabal256 - * - SHAvite-384 (nominally "SHAvite-3 with 384-bit output"): - * short name: shabal384 - * - SHAvite-512 (nominally "SHAvite-3 with 512-bit output"): - * short name: shabal512 - * - SIMD family: file sph_simd.h - * - SIMD-224: short name: simd224 - * - SIMD-256: short name: simd256 - * - SIMD-384: short name: simd384 - * - SIMD-512: short name: simd512 - * - Skein family: file sph_skein.h - * - Skein-224 (nominally specified as Skein-512-224): short name: - * skein224 (64) - * - Skein-256 (nominally specified as Skein-512-256): short name: - * skein256 (64) - * - Skein-384 (nominally specified as Skein-512-384): short name: - * skein384 (64) - * - Skein-512 (nominally specified as Skein-512-512): short name: - * skein512 (64) - * - * For the second-round SHA-3 candidates, the functions are as specified - * for round 2, i.e. with the "tweaks" that some candidates added - * between round 1 and round 2. Also, some of the submitted packages for - * round 2 contained errors, in the specification, reference code, or - * both. sphlib implements the corrected versions. - */ - -/** @hideinitializer - * Unsigned integer type whose length is at least 32 bits; on most - * architectures, it will have a width of exactly 32 bits. Unsigned C - * types implement arithmetics modulo a power of 2; use the - * SPH_T32() macro to ensure that the value is truncated - * to exactly 32 bits. Unless otherwise specified, all macros and - * functions which accept sph_u32 values assume that these - * values fit on 32 bits, i.e. do not exceed 2^32-1, even on architectures - * where sph_u32 is larger than that. - */ -typedef __arch_dependant__ sph_u32; - -/** @hideinitializer - * Signed integer type corresponding to sph_u32; it has - * width 32 bits or more. - */ -typedef __arch_dependant__ sph_s32; - -/** @hideinitializer - * Unsigned integer type whose length is at least 64 bits; on most - * architectures which feature such a type, it will have a width of - * exactly 64 bits. C99-compliant platform will have this type; it - * is also defined when the GNU compiler (gcc) is used, and on - * platforms where unsigned long is large enough. If this - * type is not available, then some hash functions which depends on - * a 64-bit type will not be available (most notably SHA-384, SHA-512, - * Tiger and WHIRLPOOL). - */ -typedef __arch_dependant__ sph_u64; - -/** @hideinitializer - * Signed integer type corresponding to sph_u64; it has - * width 64 bits or more. - */ -typedef __arch_dependant__ sph_s64; - -/** - * This macro expands the token x into a suitable - * constant expression of type sph_u32. Depending on - * how this type is defined, a suffix such as UL may - * be appended to the argument. - * - * @param x the token to expand into a suitable constant expression - */ -#define SPH_C32(x) - -/** - * Truncate a 32-bit value to exactly 32 bits. On most systems, this is - * a no-op, recognized as such by the compiler. - * - * @param x the value to truncate (of type sph_u32) - */ -#define SPH_T32(x) - -/** - * Rotate a 32-bit value by a number of bits to the left. The rotate - * count must reside between 1 and 31. This macro assumes that its - * first argument fits in 32 bits (no extra bit allowed on machines where - * sph_u32 is wider); both arguments may be evaluated - * several times. - * - * @param x the value to rotate (of type sph_u32) - * @param n the rotation count (between 1 and 31, inclusive) - */ -#define SPH_ROTL32(x, n) - -/** - * Rotate a 32-bit value by a number of bits to the left. The rotate - * count must reside between 1 and 31. This macro assumes that its - * first argument fits in 32 bits (no extra bit allowed on machines where - * sph_u32 is wider); both arguments may be evaluated - * several times. - * - * @param x the value to rotate (of type sph_u32) - * @param n the rotation count (between 1 and 31, inclusive) - */ -#define SPH_ROTR32(x, n) - -/** - * This macro is defined on systems for which a 64-bit type has been - * detected, and is used for sph_u64. - */ -#define SPH_64 - -/** - * This macro is defined on systems for the "native" integer size is - * 64 bits (64-bit values fit in one register). - */ -#define SPH_64_TRUE - -/** - * This macro expands the token x into a suitable - * constant expression of type sph_u64. Depending on - * how this type is defined, a suffix such as ULL may - * be appended to the argument. This macro is defined only if a - * 64-bit type was detected and used for sph_u64. - * - * @param x the token to expand into a suitable constant expression - */ -#define SPH_C64(x) - -/** - * Truncate a 64-bit value to exactly 64 bits. On most systems, this is - * a no-op, recognized as such by the compiler. This macro is defined only - * if a 64-bit type was detected and used for sph_u64. - * - * @param x the value to truncate (of type sph_u64) - */ -#define SPH_T64(x) - -/** - * Rotate a 64-bit value by a number of bits to the left. The rotate - * count must reside between 1 and 63. This macro assumes that its - * first argument fits in 64 bits (no extra bit allowed on machines where - * sph_u64 is wider); both arguments may be evaluated - * several times. This macro is defined only if a 64-bit type was detected - * and used for sph_u64. - * - * @param x the value to rotate (of type sph_u64) - * @param n the rotation count (between 1 and 63, inclusive) - */ -#define SPH_ROTL64(x, n) - -/** - * Rotate a 64-bit value by a number of bits to the left. The rotate - * count must reside between 1 and 63. This macro assumes that its - * first argument fits in 64 bits (no extra bit allowed on machines where - * sph_u64 is wider); both arguments may be evaluated - * several times. This macro is defined only if a 64-bit type was detected - * and used for sph_u64. - * - * @param x the value to rotate (of type sph_u64) - * @param n the rotation count (between 1 and 63, inclusive) - */ -#define SPH_ROTR64(x, n) - -/** - * This macro evaluates to inline or an equivalent construction, - * if available on the compilation platform, or to nothing otherwise. This - * is used to declare inline functions, for which the compiler should - * endeavour to include the code directly in the caller. Inline functions - * are typically defined in header files as replacement for macros. - */ -#define SPH_INLINE - -/** - * This macro is defined if the platform has been detected as using - * little-endian convention. This implies that the sph_u32 - * type (and the sph_u64 type also, if it is defined) has - * an exact width (i.e. exactly 32-bit, respectively 64-bit). - */ -#define SPH_LITTLE_ENDIAN - -/** - * This macro is defined if the platform has been detected as using - * big-endian convention. This implies that the sph_u32 - * type (and the sph_u64 type also, if it is defined) has - * an exact width (i.e. exactly 32-bit, respectively 64-bit). - */ -#define SPH_BIG_ENDIAN - -/** - * This macro is defined if 32-bit words (and 64-bit words, if defined) - * can be read from and written to memory efficiently in little-endian - * convention. This is the case for little-endian platforms, and also - * for the big-endian platforms which have special little-endian access - * opcodes (e.g. Ultrasparc). - */ -#define SPH_LITTLE_FAST - -/** - * This macro is defined if 32-bit words (and 64-bit words, if defined) - * can be read from and written to memory efficiently in big-endian - * convention. This is the case for little-endian platforms, and also - * for the little-endian platforms which have special big-endian access - * opcodes. - */ -#define SPH_BIG_FAST - -/** - * On some platforms, this macro is defined to an unsigned integer type - * into which pointer values may be cast. The resulting value can then - * be tested for being a multiple of 2, 4 or 8, indicating an aligned - * pointer for, respectively, 16-bit, 32-bit or 64-bit memory accesses. - */ -#define SPH_UPTR - -/** - * When defined, this macro indicates that unaligned memory accesses - * are possible with only a minor penalty, and thus should be prefered - * over strategies which first copy data to an aligned buffer. - */ -#define SPH_UNALIGNED - -/** - * Byte-swap a 32-bit word (i.e. 0x12345678 becomes - * 0x78563412). This is an inline function which resorts - * to inline assembly on some platforms, for better performance. - * - * @param x the 32-bit value to byte-swap - * @return the byte-swapped value - */ -static inline sph_u32 sph_bswap32(sph_u32 x); - -/** - * Byte-swap a 64-bit word. This is an inline function which resorts - * to inline assembly on some platforms, for better performance. This - * function is defined only if a suitable 64-bit type was found for - * sph_u64 - * - * @param x the 64-bit value to byte-swap - * @return the byte-swapped value - */ -static inline sph_u64 sph_bswap64(sph_u64 x); - -/** - * Decode a 16-bit unsigned value from memory, in little-endian convention - * (least significant byte comes first). - * - * @param src the source address - * @return the decoded value - */ -static inline unsigned sph_dec16le(const void *src); - -/** - * Encode a 16-bit unsigned value into memory, in little-endian convention - * (least significant byte comes first). - * - * @param dst the destination buffer - * @param val the value to encode - */ -static inline void sph_enc16le(void *dst, unsigned val); - -/** - * Decode a 16-bit unsigned value from memory, in big-endian convention - * (most significant byte comes first). - * - * @param src the source address - * @return the decoded value - */ -static inline unsigned sph_dec16be(const void *src); - -/** - * Encode a 16-bit unsigned value into memory, in big-endian convention - * (most significant byte comes first). - * - * @param dst the destination buffer - * @param val the value to encode - */ -static inline void sph_enc16be(void *dst, unsigned val); - -/** - * Decode a 32-bit unsigned value from memory, in little-endian convention - * (least significant byte comes first). - * - * @param src the source address - * @return the decoded value - */ -static inline sph_u32 sph_dec32le(const void *src); - -/** - * Decode a 32-bit unsigned value from memory, in little-endian convention - * (least significant byte comes first). This function assumes that the - * source address is suitably aligned for a direct access, if the platform - * supports such things; it can thus be marginally faster than the generic - * sph_dec32le() function. - * - * @param src the source address - * @return the decoded value - */ -static inline sph_u32 sph_dec32le_aligned(const void *src); - -/** - * Encode a 32-bit unsigned value into memory, in little-endian convention - * (least significant byte comes first). - * - * @param dst the destination buffer - * @param val the value to encode - */ -static inline void sph_enc32le(void *dst, sph_u32 val); - -/** - * Encode a 32-bit unsigned value into memory, in little-endian convention - * (least significant byte comes first). This function assumes that the - * destination address is suitably aligned for a direct access, if the - * platform supports such things; it can thus be marginally faster than - * the generic sph_enc32le() function. - * - * @param dst the destination buffer - * @param val the value to encode - */ -static inline void sph_enc32le_aligned(void *dst, sph_u32 val); - -/** - * Decode a 32-bit unsigned value from memory, in big-endian convention - * (most significant byte comes first). - * - * @param src the source address - * @return the decoded value - */ -static inline sph_u32 sph_dec32be(const void *src); - -/** - * Decode a 32-bit unsigned value from memory, in big-endian convention - * (most significant byte comes first). This function assumes that the - * source address is suitably aligned for a direct access, if the platform - * supports such things; it can thus be marginally faster than the generic - * sph_dec32be() function. - * - * @param src the source address - * @return the decoded value - */ -static inline sph_u32 sph_dec32be_aligned(const void *src); - -/** - * Encode a 32-bit unsigned value into memory, in big-endian convention - * (most significant byte comes first). - * - * @param dst the destination buffer - * @param val the value to encode - */ -static inline void sph_enc32be(void *dst, sph_u32 val); - -/** - * Encode a 32-bit unsigned value into memory, in big-endian convention - * (most significant byte comes first). This function assumes that the - * destination address is suitably aligned for a direct access, if the - * platform supports such things; it can thus be marginally faster than - * the generic sph_enc32be() function. - * - * @param dst the destination buffer - * @param val the value to encode - */ -static inline void sph_enc32be_aligned(void *dst, sph_u32 val); - -/** - * Decode a 64-bit unsigned value from memory, in little-endian convention - * (least significant byte comes first). This function is defined only - * if a suitable 64-bit type was detected and used for sph_u64. - * - * @param src the source address - * @return the decoded value - */ -static inline sph_u64 sph_dec64le(const void *src); - -/** - * Decode a 64-bit unsigned value from memory, in little-endian convention - * (least significant byte comes first). This function assumes that the - * source address is suitably aligned for a direct access, if the platform - * supports such things; it can thus be marginally faster than the generic - * sph_dec64le() function. This function is defined only - * if a suitable 64-bit type was detected and used for sph_u64. - * - * @param src the source address - * @return the decoded value - */ -static inline sph_u64 sph_dec64le_aligned(const void *src); - -/** - * Encode a 64-bit unsigned value into memory, in little-endian convention - * (least significant byte comes first). This function is defined only - * if a suitable 64-bit type was detected and used for sph_u64. - * - * @param dst the destination buffer - * @param val the value to encode - */ -static inline void sph_enc64le(void *dst, sph_u64 val); - -/** - * Encode a 64-bit unsigned value into memory, in little-endian convention - * (least significant byte comes first). This function assumes that the - * destination address is suitably aligned for a direct access, if the - * platform supports such things; it can thus be marginally faster than - * the generic sph_enc64le() function. This function is defined - * only if a suitable 64-bit type was detected and used for - * sph_u64. - * - * @param dst the destination buffer - * @param val the value to encode - */ -static inline void sph_enc64le_aligned(void *dst, sph_u64 val); - -/** - * Decode a 64-bit unsigned value from memory, in big-endian convention - * (most significant byte comes first). This function is defined only - * if a suitable 64-bit type was detected and used for sph_u64. - * - * @param src the source address - * @return the decoded value - */ -static inline sph_u64 sph_dec64be(const void *src); - -/** - * Decode a 64-bit unsigned value from memory, in big-endian convention - * (most significant byte comes first). This function assumes that the - * source address is suitably aligned for a direct access, if the platform - * supports such things; it can thus be marginally faster than the generic - * sph_dec64be() function. This function is defined only - * if a suitable 64-bit type was detected and used for sph_u64. - * - * @param src the source address - * @return the decoded value - */ -static inline sph_u64 sph_dec64be_aligned(const void *src); - -/** - * Encode a 64-bit unsigned value into memory, in big-endian convention - * (most significant byte comes first). This function is defined only - * if a suitable 64-bit type was detected and used for sph_u64. - * - * @param dst the destination buffer - * @param val the value to encode - */ -static inline void sph_enc64be(void *dst, sph_u64 val); - -/** - * Encode a 64-bit unsigned value into memory, in big-endian convention - * (most significant byte comes first). This function assumes that the - * destination address is suitably aligned for a direct access, if the - * platform supports such things; it can thus be marginally faster than - * the generic sph_enc64be() function. This function is defined - * only if a suitable 64-bit type was detected and used for - * sph_u64. - * - * @param dst the destination buffer - * @param val the value to encode - */ -static inline void sph_enc64be_aligned(void *dst, sph_u64 val); - -#endif - -/* ============== END documentation block for Doxygen ============= */ - -#ifndef DOXYGEN_IGNORE - -/* - * We want to define the types "sph_u32" and "sph_u64" which hold - * unsigned values of at least, respectively, 32 and 64 bits. These - * tests should select appropriate types for most platforms. The - * macro "SPH_64" is defined if the 64-bit is supported. - */ - -#undef SPH_64 -#undef SPH_64_TRUE - #if defined __STDC__ && __STDC_VERSION__ >= 199901L -/* - * On C99 implementations, we can use to get an exact 64-bit - * type, if any, or otherwise use a wider type (which must exist, for - * C99 conformance). - */ - #include -#ifdef UINT32_MAX typedef uint32_t sph_u32; typedef int32_t sph_s32; -#else -typedef uint_fast32_t sph_u32; -typedef int_fast32_t sph_s32; -#endif -#if !SPH_NO_64 -#ifdef UINT64_MAX typedef uint64_t sph_u64; typedef int64_t sph_s64; -#else -typedef uint_fast64_t sph_u64; -typedef int_fast64_t sph_s64; -#endif -#endif #define SPH_C32(x) ((sph_u32)(x)) -#if !SPH_NO_64 #define SPH_C64(x) ((sph_u64)(x)) -#define SPH_64 1 -#endif #else - -/* - * On non-C99 systems, we use "unsigned int" if it is wide enough, - * "unsigned long" otherwise. This supports all "reasonable" architectures. - * We have to be cautious: pre-C99 preprocessors handle constants - * differently in '#if' expressions. Hence the shifts to test UINT_MAX. - */ - -#if ((UINT_MAX >> 11) >> 11) >= 0x3FF - -typedef unsigned int sph_u32; -typedef int sph_s32; - -#define SPH_C32(x) ((sph_u32)(x ## U)) - -#else - -typedef unsigned long sph_u32; -typedef long sph_s32; - -#define SPH_C32(x) ((sph_u32)(x ## UL)) - +#error We need at least C99 compiler #endif -#if !SPH_NO_64 - -/* - * We want a 64-bit type. We use "unsigned long" if it is wide enough (as - * is common on 64-bit architectures such as AMD64, Alpha or Sparcv9), - * "unsigned long long" otherwise, if available. We use ULLONG_MAX to - * test whether "unsigned long long" is available; we also know that - * gcc features this type, even if the libc header do not know it. - */ - -#if ((ULONG_MAX >> 31) >> 31) >= 3 - -typedef unsigned long sph_u64; -typedef long sph_s64; - -#define SPH_C64(x) ((sph_u64)(x ## UL)) - -#define SPH_64 1 - -#elif ((ULLONG_MAX >> 31) >> 31) >= 3 || defined __GNUC__ - -typedef unsigned long long sph_u64; -typedef long long sph_s64; - -#define SPH_C64(x) ((sph_u64)(x ## ULL)) - -#define SPH_64 1 - -#else - -/* - * No 64-bit type... - */ - -#endif - -#endif - -#endif - -/* - * If the "unsigned long" type has length 64 bits or more, then this is - * a "true" 64-bit architectures. This is also true with Visual C on - * amd64, even though the "long" type is limited to 32 bits. - */ -#if SPH_64 && (((ULONG_MAX >> 31) >> 31) >= 3 || defined _M_X64) -#define SPH_64_TRUE 1 -#endif - -/* - * Implementation note: some processors have specific opcodes to perform - * a rotation. Recent versions of gcc recognize the expression above and - * use the relevant opcodes, when appropriate. - */ - #define SPH_T32(x) ((x) & SPH_C32(0xFFFFFFFF)) #define SPH_ROTL32(x, n) SPH_T32(((x) << (n)) | ((x) >> (32 - (n)))) #define SPH_ROTR32(x, n) SPH_ROTL32(x, (32 - (n))) -#if SPH_64 - #define SPH_T64(x) ((x) & SPH_C64(0xFFFFFFFFFFFFFFFF)) #define SPH_ROTL64(x, n) SPH_T64(((x) << (n)) | ((x) >> (64 - (n)))) #define SPH_ROTR64(x, n) SPH_ROTL64(x, (64 - (n))) -#endif - -#ifndef DOXYGEN_IGNORE -/* - * Define SPH_INLINE to be an "inline" qualifier, if available. We define - * some small macro-like functions which benefit greatly from being inlined. - */ -#if (defined __STDC__ && __STDC_VERSION__ >= 199901L) || defined __GNUC__ -#define SPH_INLINE inline -#elif defined _MSC_VER -#define SPH_INLINE __inline -#else -#define SPH_INLINE -#endif -#endif - -/* - * We define some macros which qualify the architecture. These macros - * may be explicit set externally (e.g. as compiler parameters). The - * code below sets those macros if they are not already defined. - * - * Most macros are boolean, thus evaluate to either zero or non-zero. - * The SPH_UPTR macro is special, in that it evaluates to a C type, - * or is not defined. - * - * SPH_UPTR if defined: unsigned type to cast pointers into - * - * SPH_UNALIGNED non-zero if unaligned accesses are efficient - * SPH_LITTLE_ENDIAN non-zero if architecture is known to be little-endian - * SPH_BIG_ENDIAN non-zero if architecture is known to be big-endian - * SPH_LITTLE_FAST non-zero if little-endian decoding is fast - * SPH_BIG_FAST non-zero if big-endian decoding is fast - * - * If SPH_UPTR is defined, then encoding and decoding of 32-bit and 64-bit - * values will try to be "smart". Either SPH_LITTLE_ENDIAN or SPH_BIG_ENDIAN - * _must_ be non-zero in those situations. The 32-bit and 64-bit types - * _must_ also have an exact width. - * - * SPH_SPARCV9_GCC_32 UltraSPARC-compatible with gcc, 32-bit mode - * SPH_SPARCV9_GCC_64 UltraSPARC-compatible with gcc, 64-bit mode - * SPH_SPARCV9_GCC UltraSPARC-compatible with gcc - * SPH_I386_GCC x86-compatible (32-bit) with gcc - * SPH_I386_MSVC x86-compatible (32-bit) with Microsoft Visual C - * SPH_AMD64_GCC x86-compatible (64-bit) with gcc - * SPH_AMD64_MSVC x86-compatible (64-bit) with Microsoft Visual C - * SPH_PPC32_GCC PowerPC, 32-bit, with gcc - * SPH_PPC64_GCC PowerPC, 64-bit, with gcc - * - * TODO: enhance automatic detection, for more architectures and compilers. - * Endianness is the most important. SPH_UNALIGNED and SPH_UPTR help with - * some very fast functions (e.g. MD4) when using unaligned input data. - * The CPU-specific-with-GCC macros are useful only for inline assembly, - * normally restrained to this header file. - */ - /* * 32-bit x86, aka "i386 compatible". */ #if defined __i386__ || defined _M_IX86 -#define SPH_DETECT_UNALIGNED 1 #define SPH_DETECT_LITTLE_ENDIAN 1 -#define SPH_DETECT_UPTR sph_u32 -#ifdef __GNUC__ -#define SPH_DETECT_I386_GCC 1 -#endif -#ifdef _MSC_VER -#define SPH_DETECT_I386_MSVC 1 -#endif +#define SPH_DETECT_BIG_ENDIAN 0 /* * 64-bit x86, hereafter known as "amd64". */ #elif defined __x86_64 || defined _M_X64 -#define SPH_DETECT_UNALIGNED 1 #define SPH_DETECT_LITTLE_ENDIAN 1 -#define SPH_DETECT_UPTR sph_u64 -#ifdef __GNUC__ -#define SPH_DETECT_AMD64_GCC 1 -#endif -#ifdef _MSC_VER -#define SPH_DETECT_AMD64_MSVC 1 -#endif - -/* - * 64-bit Sparc architecture (implies v9). - */ -#elif ((defined __sparc__ || defined __sparc) && defined __arch64__) \ - || defined __sparcv9 - -#define SPH_DETECT_BIG_ENDIAN 1 -#define SPH_DETECT_UPTR sph_u64 -#ifdef __GNUC__ -#define SPH_DETECT_SPARCV9_GCC_64 1 -#define SPH_DETECT_LITTLE_FAST 1 -#endif - -/* - * 32-bit Sparc. - */ -#elif (defined __sparc__ || defined __sparc) \ - && !(defined __sparcv9 || defined __arch64__) - -#define SPH_DETECT_BIG_ENDIAN 1 -#define SPH_DETECT_UPTR sph_u32 -#if defined __GNUC__ && defined __sparc_v9__ -#define SPH_DETECT_SPARCV9_GCC_32 1 -#define SPH_DETECT_LITTLE_FAST 1 -#endif +#define SPH_DETECT_BIG_ENDIAN 0 /* * ARM, little-endian. @@ -1056,213 +104,19 @@ typedef long long sph_s64; #elif defined __arm__ && __ARMEL__ #define SPH_DETECT_LITTLE_ENDIAN 1 - -/* - * MIPS, little-endian. - */ -#elif MIPSEL || _MIPSEL || __MIPSEL || __MIPSEL__ - -#define SPH_DETECT_LITTLE_ENDIAN 1 - -/* - * MIPS, big-endian. - */ -#elif MIPSEB || _MIPSEB || __MIPSEB || __MIPSEB__ - -#define SPH_DETECT_BIG_ENDIAN 1 - -/* - * PowerPC. - */ -#elif defined __powerpc__ || defined __POWERPC__ || defined __ppc__ \ - || defined _ARCH_PPC - -/* - * Note: we do not declare cross-endian access to be "fast": even if - * using inline assembly, implementation should still assume that - * keeping the decoded word in a temporary is faster than decoding - * it again. - */ -#if defined __GNUC__ -#if SPH_64_TRUE -#define SPH_DETECT_PPC64_GCC 1 -#else -#define SPH_DETECT_PPC32_GCC 1 -#endif -#endif - -#if defined __BIG_ENDIAN__ || defined _BIG_ENDIAN -#define SPH_DETECT_BIG_ENDIAN 1 -#elif defined __LITTLE_ENDIAN__ || defined _LITTLE_ENDIAN -#define SPH_DETECT_LITTLE_ENDIAN 1 -#endif - -/* - * Itanium, 64-bit. - */ -#elif defined __ia64 || defined __ia64__ \ - || defined __itanium__ || defined _M_IA64 - -#if defined __BIG_ENDIAN__ || defined _BIG_ENDIAN -#define SPH_DETECT_BIG_ENDIAN 1 -#else -#define SPH_DETECT_LITTLE_ENDIAN 1 -#endif -#if defined __LP64__ || defined _LP64 -#define SPH_DETECT_UPTR sph_u64 -#else -#define SPH_DETECT_UPTR sph_u32 -#endif +#define SPH_DETECT_BIG_ENDIAN 0 #endif -#if defined SPH_DETECT_SPARCV9_GCC_32 || defined SPH_DETECT_SPARCV9_GCC_64 -#define SPH_DETECT_SPARCV9_GCC 1 -#endif -#if defined SPH_DETECT_UNALIGNED && !defined SPH_UNALIGNED -#define SPH_UNALIGNED SPH_DETECT_UNALIGNED -#endif -#if defined SPH_DETECT_UPTR && !defined SPH_UPTR -#define SPH_UPTR SPH_DETECT_UPTR -#endif #if defined SPH_DETECT_LITTLE_ENDIAN && !defined SPH_LITTLE_ENDIAN #define SPH_LITTLE_ENDIAN SPH_DETECT_LITTLE_ENDIAN #endif #if defined SPH_DETECT_BIG_ENDIAN && !defined SPH_BIG_ENDIAN #define SPH_BIG_ENDIAN SPH_DETECT_BIG_ENDIAN -#endif -#if defined SPH_DETECT_LITTLE_FAST && !defined SPH_LITTLE_FAST -#define SPH_LITTLE_FAST SPH_DETECT_LITTLE_FAST -#endif -#if defined SPH_DETECT_BIG_FAST && !defined SPH_BIG_FAST -#define SPH_BIG_FAST SPH_DETECT_BIG_FAST -#endif -#if defined SPH_DETECT_SPARCV9_GCC_32 && !defined SPH_SPARCV9_GCC_32 -#define SPH_SPARCV9_GCC_32 SPH_DETECT_SPARCV9_GCC_32 -#endif -#if defined SPH_DETECT_SPARCV9_GCC_64 && !defined SPH_SPARCV9_GCC_64 -#define SPH_SPARCV9_GCC_64 SPH_DETECT_SPARCV9_GCC_64 -#endif -#if defined SPH_DETECT_SPARCV9_GCC && !defined SPH_SPARCV9_GCC -#define SPH_SPARCV9_GCC SPH_DETECT_SPARCV9_GCC -#endif -#if defined SPH_DETECT_I386_GCC && !defined SPH_I386_GCC -#define SPH_I386_GCC SPH_DETECT_I386_GCC -#endif -#if defined SPH_DETECT_I386_MSVC && !defined SPH_I386_MSVC -#define SPH_I386_MSVC SPH_DETECT_I386_MSVC -#endif -#if defined SPH_DETECT_AMD64_GCC && !defined SPH_AMD64_GCC -#define SPH_AMD64_GCC SPH_DETECT_AMD64_GCC -#endif -#if defined SPH_DETECT_AMD64_MSVC && !defined SPH_AMD64_MSVC -#define SPH_AMD64_MSVC SPH_DETECT_AMD64_MSVC -#endif -#if defined SPH_DETECT_PPC32_GCC && !defined SPH_PPC32_GCC -#define SPH_PPC32_GCC SPH_DETECT_PPC32_GCC -#endif -#if defined SPH_DETECT_PPC64_GCC && !defined SPH_PPC64_GCC -#define SPH_PPC64_GCC SPH_DETECT_PPC64_GCC -#endif - -#if SPH_LITTLE_ENDIAN && !defined SPH_LITTLE_FAST -#define SPH_LITTLE_FAST 1 -#endif -#if SPH_BIG_ENDIAN && !defined SPH_BIG_FAST -#define SPH_BIG_FAST 1 -#endif - -#if defined SPH_UPTR && !(SPH_LITTLE_ENDIAN || SPH_BIG_ENDIAN) -#error SPH_UPTR defined, but endianness is not known. -#endif - -#if SPH_I386_GCC && !SPH_NO_ASM - -/* - * On x86 32-bit, with gcc, we use the bswapl opcode to byte-swap 32-bit - * values. - */ - -static SPH_INLINE sph_u32 -sph_bswap32(sph_u32 x) -{ - __asm__ __volatile__ ("bswapl %0" : "=r" (x) : "0" (x)); - return x; -} - -#if SPH_64 - -static SPH_INLINE sph_u64 -sph_bswap64(sph_u64 x) -{ - return ((sph_u64)sph_bswap32((sph_u32)x) << 32) - | (sph_u64)sph_bswap32((sph_u32)(x >> 32)); -} - -#endif - -#elif SPH_AMD64_GCC && !SPH_NO_ASM - -/* - * On x86 64-bit, with gcc, we use the bswapl opcode to byte-swap 32-bit - * and 64-bit values. - */ - -static SPH_INLINE sph_u32 -sph_bswap32(sph_u32 x) -{ - __asm__ __volatile__ ("bswapl %0" : "=r" (x) : "0" (x)); - return x; -} - -#if SPH_64 - -static SPH_INLINE sph_u64 -sph_bswap64(sph_u64 x) -{ - __asm__ __volatile__ ("bswapq %0" : "=r" (x) : "0" (x)); - return x; -} - -#endif - -/* - * Disabled code. Apparently, Microsoft Visual C 2005 is smart enough - * to generate proper opcodes for endianness swapping with the pure C - * implementation below. - * - -#elif SPH_I386_MSVC && !SPH_NO_ASM - -static __inline sph_u32 __declspec(naked) __fastcall -sph_bswap32(sph_u32 x) -{ - __asm { - bswap ecx - mov eax,ecx - ret - } -} - -#if SPH_64 - -static SPH_INLINE sph_u64 -sph_bswap64(sph_u64 x) -{ - return ((sph_u64)sph_bswap32((sph_u32)x) << 32) - | (sph_u64)sph_bswap32((sph_u32)(x >> 32)); -} - #endif - * - * [end of disabled code] - */ - -#else - -static SPH_INLINE sph_u32 +static inline sph_u32 sph_bswap32(sph_u32 x) { x = SPH_T32((x << 16) | (x >> 16)); @@ -1271,15 +125,13 @@ sph_bswap32(sph_u32 x) return x; } -#if SPH_64 - /** * Byte-swap a 64-bit value. * * @param x the input value * @return the byte-swapped value */ -static SPH_INLINE sph_u64 +static inline sph_u64 sph_bswap64(sph_u64 x) { x = SPH_T64((x << 32) | (x >> 32)); @@ -1290,67 +142,28 @@ sph_bswap64(sph_u64 x) return x; } -#endif - -#endif - -#if SPH_SPARCV9_GCC && !SPH_NO_ASM - -/* - * On UltraSPARC systems, native ordering is big-endian, but it is - * possible to perform little-endian read accesses by specifying the - * address space 0x88 (ASI_PRIMARY_LITTLE). Basically, either we use - * the opcode "lda [%reg]0x88,%dst", where %reg is the register which - * contains the source address and %dst is the destination register, - * or we use "lda [%reg+imm]%asi,%dst", which uses the %asi register - * to get the address space name. The latter format is better since it - * combines an addition and the actual access in a single opcode; but - * it requires the setting (and subsequent resetting) of %asi, which is - * slow. Some operations (i.e. MD5 compression function) combine many - * successive little-endian read accesses, which may share the same - * %asi setting. The macros below contain the appropriate inline - * assembly. - */ - -#define SPH_SPARCV9_SET_ASI \ - sph_u32 sph_sparcv9_asi; \ - __asm__ __volatile__ ( \ - "rd %%asi,%0\n\twr %%g0,0x88,%%asi" : "=r" (sph_sparcv9_asi)); - -#define SPH_SPARCV9_RESET_ASI \ - __asm__ __volatile__ ("wr %%g0,%0,%%asi" : : "r" (sph_sparcv9_asi)); - -#define SPH_SPARCV9_DEC32LE(base, idx) ({ \ - sph_u32 sph_sparcv9_tmp; \ - __asm__ __volatile__ ("lda [%1+" #idx "*4]%%asi,%0" \ - : "=r" (sph_sparcv9_tmp) : "r" (base)); \ - sph_sparcv9_tmp; \ - }) - -#endif - -static SPH_INLINE void +static inline void sph_enc16be(void *dst, unsigned val) { ((unsigned char *)dst)[0] = (val >> 8); ((unsigned char *)dst)[1] = val; } -static SPH_INLINE unsigned +static inline unsigned sph_dec16be(const void *src) { return ((unsigned)(((const unsigned char *)src)[0]) << 8) | (unsigned)(((const unsigned char *)src)[1]); } -static SPH_INLINE void +static inline void sph_enc16le(void *dst, unsigned val) { ((unsigned char *)dst)[0] = val; ((unsigned char *)dst)[1] = val >> 8; } -static SPH_INLINE unsigned +static inline unsigned sph_dec16le(const void *src) { return (unsigned)(((const unsigned char *)src)[0]) @@ -1363,34 +176,13 @@ sph_dec16le(const void *src) * @param dst the destination buffer * @param val the 32-bit value to encode */ -static SPH_INLINE void +static inline void sph_enc32be(void *dst, sph_u32 val) { -#if defined SPH_UPTR -#if SPH_UNALIGNED -#if SPH_LITTLE_ENDIAN - val = sph_bswap32(val); -#endif - *(sph_u32 *)dst = val; -#else - if (((SPH_UPTR)dst & 3) == 0) { -#if SPH_LITTLE_ENDIAN - val = sph_bswap32(val); -#endif - *(sph_u32 *)dst = val; - } else { - ((unsigned char *)dst)[0] = (val >> 24); - ((unsigned char *)dst)[1] = (val >> 16); - ((unsigned char *)dst)[2] = (val >> 8); - ((unsigned char *)dst)[3] = val; - } -#endif -#else ((unsigned char *)dst)[0] = (val >> 24); ((unsigned char *)dst)[1] = (val >> 16); ((unsigned char *)dst)[2] = (val >> 8); ((unsigned char *)dst)[3] = val; -#endif } /** @@ -1400,7 +192,7 @@ sph_enc32be(void *dst, sph_u32 val) * @param dst the destination buffer (32-bit aligned) * @param val the value to encode */ -static SPH_INLINE void +static inline void sph_enc32be_aligned(void *dst, sph_u32 val) { #if SPH_LITTLE_ENDIAN @@ -1421,36 +213,13 @@ sph_enc32be_aligned(void *dst, sph_u32 val) * @param src the source buffer * @return the decoded value */ -static SPH_INLINE sph_u32 +static inline sph_u32 sph_dec32be(const void *src) { -#if defined SPH_UPTR -#if SPH_UNALIGNED -#if SPH_LITTLE_ENDIAN - return sph_bswap32(*(const sph_u32 *)src); -#else - return *(const sph_u32 *)src; -#endif -#else - if (((SPH_UPTR)src & 3) == 0) { -#if SPH_LITTLE_ENDIAN - return sph_bswap32(*(const sph_u32 *)src); -#else - return *(const sph_u32 *)src; -#endif - } else { - return ((sph_u32)(((const unsigned char *)src)[0]) << 24) - | ((sph_u32)(((const unsigned char *)src)[1]) << 16) - | ((sph_u32)(((const unsigned char *)src)[2]) << 8) - | (sph_u32)(((const unsigned char *)src)[3]); - } -#endif -#else return ((sph_u32)(((const unsigned char *)src)[0]) << 24) | ((sph_u32)(((const unsigned char *)src)[1]) << 16) | ((sph_u32)(((const unsigned char *)src)[2]) << 8) | (sph_u32)(((const unsigned char *)src)[3]); -#endif } /** @@ -1460,7 +229,7 @@ sph_dec32be(const void *src) * @param src the source buffer (32-bit aligned) * @return the decoded value */ -static SPH_INLINE sph_u32 +static inline sph_u32 sph_dec32be_aligned(const void *src) { #if SPH_LITTLE_ENDIAN @@ -1481,34 +250,13 @@ sph_dec32be_aligned(const void *src) * @param dst the destination buffer * @param val the 32-bit value to encode */ -static SPH_INLINE void +static inline void sph_enc32le(void *dst, sph_u32 val) { -#if defined SPH_UPTR -#if SPH_UNALIGNED -#if SPH_BIG_ENDIAN - val = sph_bswap32(val); -#endif - *(sph_u32 *)dst = val; -#else - if (((SPH_UPTR)dst & 3) == 0) { -#if SPH_BIG_ENDIAN - val = sph_bswap32(val); -#endif - *(sph_u32 *)dst = val; - } else { - ((unsigned char *)dst)[0] = val; - ((unsigned char *)dst)[1] = (val >> 8); - ((unsigned char *)dst)[2] = (val >> 16); - ((unsigned char *)dst)[3] = (val >> 24); - } -#endif -#else ((unsigned char *)dst)[0] = val; ((unsigned char *)dst)[1] = (val >> 8); ((unsigned char *)dst)[2] = (val >> 16); ((unsigned char *)dst)[3] = (val >> 24); -#endif } /** @@ -1518,7 +266,7 @@ sph_enc32le(void *dst, sph_u32 val) * @param dst the destination buffer (32-bit aligned) * @param val the value to encode */ -static SPH_INLINE void +static inline void sph_enc32le_aligned(void *dst, sph_u32 val) { #if SPH_LITTLE_ENDIAN @@ -1539,69 +287,13 @@ sph_enc32le_aligned(void *dst, sph_u32 val) * @param src the source buffer * @return the decoded value */ -static SPH_INLINE sph_u32 +static inline sph_u32 sph_dec32le(const void *src) { -#if defined SPH_UPTR -#if SPH_UNALIGNED -#if SPH_BIG_ENDIAN - return sph_bswap32(*(const sph_u32 *)src); -#else - return *(const sph_u32 *)src; -#endif -#else - if (((SPH_UPTR)src & 3) == 0) { -#if SPH_BIG_ENDIAN -#if SPH_SPARCV9_GCC && !SPH_NO_ASM - sph_u32 tmp; - - /* - * "__volatile__" is needed here because without it, - * gcc-3.4.3 miscompiles the code and performs the - * access before the test on the address, thus triggering - * a bus error... - */ - __asm__ __volatile__ ( - "lda [%1]0x88,%0" : "=r" (tmp) : "r" (src)); - return tmp; -/* - * On PowerPC, this turns out not to be worth the effort: the inline - * assembly makes GCC optimizer uncomfortable, which tends to nullify - * the decoding gains. - * - * For most hash functions, using this inline assembly trick changes - * hashing speed by less than 5% and often _reduces_ it. The biggest - * gains are for MD4 (+11%) and CubeHash (+30%). For all others, it is - * less then 10%. The speed gain on CubeHash is probably due to the - * chronic shortage of registers that CubeHash endures; for the other - * functions, the generic code appears to be efficient enough already. - * -#elif (SPH_PPC32_GCC || SPH_PPC64_GCC) && !SPH_NO_ASM - sph_u32 tmp; - - __asm__ __volatile__ ( - "lwbrx %0,0,%1" : "=r" (tmp) : "r" (src)); - return tmp; - */ -#else - return sph_bswap32(*(const sph_u32 *)src); -#endif -#else - return *(const sph_u32 *)src; -#endif - } else { - return (sph_u32)(((const unsigned char *)src)[0]) - | ((sph_u32)(((const unsigned char *)src)[1]) << 8) - | ((sph_u32)(((const unsigned char *)src)[2]) << 16) - | ((sph_u32)(((const unsigned char *)src)[3]) << 24); - } -#endif -#else return (sph_u32)(((const unsigned char *)src)[0]) | ((sph_u32)(((const unsigned char *)src)[1]) << 8) | ((sph_u32)(((const unsigned char *)src)[2]) << 16) | ((sph_u32)(((const unsigned char *)src)[3]) << 24); -#endif } /** @@ -1611,29 +303,13 @@ sph_dec32le(const void *src) * @param src the source buffer (32-bit aligned) * @return the decoded value */ -static SPH_INLINE sph_u32 +static inline sph_u32 sph_dec32le_aligned(const void *src) { #if SPH_LITTLE_ENDIAN return *(const sph_u32 *)src; #elif SPH_BIG_ENDIAN -#if SPH_SPARCV9_GCC && !SPH_NO_ASM - sph_u32 tmp; - - __asm__ __volatile__ ("lda [%1]0x88,%0" : "=r" (tmp) : "r" (src)); - return tmp; -/* - * Not worth it generally. - * -#elif (SPH_PPC32_GCC || SPH_PPC64_GCC) && !SPH_NO_ASM - sph_u32 tmp; - - __asm__ __volatile__ ("lwbrx %0,0,%1" : "=r" (tmp) : "r" (src)); - return tmp; - */ -#else return sph_bswap32(*(const sph_u32 *)src); -#endif #else return (sph_u32)(((const unsigned char *)src)[0]) | ((sph_u32)(((const unsigned char *)src)[1]) << 8) @@ -1642,41 +318,15 @@ sph_dec32le_aligned(const void *src) #endif } -#if SPH_64 - /** * Encode a 64-bit value into the provided buffer (big endian convention). * * @param dst the destination buffer * @param val the 64-bit value to encode */ -static SPH_INLINE void +static inline void sph_enc64be(void *dst, sph_u64 val) { -#if defined SPH_UPTR -#if SPH_UNALIGNED -#if SPH_LITTLE_ENDIAN - val = sph_bswap64(val); -#endif - *(sph_u64 *)dst = val; -#else - if (((SPH_UPTR)dst & 7) == 0) { -#if SPH_LITTLE_ENDIAN - val = sph_bswap64(val); -#endif - *(sph_u64 *)dst = val; - } else { - ((unsigned char *)dst)[0] = (val >> 56); - ((unsigned char *)dst)[1] = (val >> 48); - ((unsigned char *)dst)[2] = (val >> 40); - ((unsigned char *)dst)[3] = (val >> 32); - ((unsigned char *)dst)[4] = (val >> 24); - ((unsigned char *)dst)[5] = (val >> 16); - ((unsigned char *)dst)[6] = (val >> 8); - ((unsigned char *)dst)[7] = val; - } -#endif -#else ((unsigned char *)dst)[0] = (val >> 56); ((unsigned char *)dst)[1] = (val >> 48); ((unsigned char *)dst)[2] = (val >> 40); @@ -1685,7 +335,6 @@ sph_enc64be(void *dst, sph_u64 val) ((unsigned char *)dst)[5] = (val >> 16); ((unsigned char *)dst)[6] = (val >> 8); ((unsigned char *)dst)[7] = val; -#endif } /** @@ -1695,7 +344,7 @@ sph_enc64be(void *dst, sph_u64 val) * @param dst the destination buffer (64-bit aligned) * @param val the value to encode */ -static SPH_INLINE void +static inline void sph_enc64be_aligned(void *dst, sph_u64 val) { #if SPH_LITTLE_ENDIAN @@ -1720,35 +369,9 @@ sph_enc64be_aligned(void *dst, sph_u64 val) * @param src the source buffer * @return the decoded value */ -static SPH_INLINE sph_u64 +static inline sph_u64 sph_dec64be(const void *src) { -#if defined SPH_UPTR -#if SPH_UNALIGNED -#if SPH_LITTLE_ENDIAN - return sph_bswap64(*(const sph_u64 *)src); -#else - return *(const sph_u64 *)src; -#endif -#else - if (((SPH_UPTR)src & 7) == 0) { -#if SPH_LITTLE_ENDIAN - return sph_bswap64(*(const sph_u64 *)src); -#else - return *(const sph_u64 *)src; -#endif - } else { - return ((sph_u64)(((const unsigned char *)src)[0]) << 56) - | ((sph_u64)(((const unsigned char *)src)[1]) << 48) - | ((sph_u64)(((const unsigned char *)src)[2]) << 40) - | ((sph_u64)(((const unsigned char *)src)[3]) << 32) - | ((sph_u64)(((const unsigned char *)src)[4]) << 24) - | ((sph_u64)(((const unsigned char *)src)[5]) << 16) - | ((sph_u64)(((const unsigned char *)src)[6]) << 8) - | (sph_u64)(((const unsigned char *)src)[7]); - } -#endif -#else return ((sph_u64)(((const unsigned char *)src)[0]) << 56) | ((sph_u64)(((const unsigned char *)src)[1]) << 48) | ((sph_u64)(((const unsigned char *)src)[2]) << 40) @@ -1757,7 +380,6 @@ sph_dec64be(const void *src) | ((sph_u64)(((const unsigned char *)src)[5]) << 16) | ((sph_u64)(((const unsigned char *)src)[6]) << 8) | (sph_u64)(((const unsigned char *)src)[7]); -#endif } /** @@ -1767,7 +389,7 @@ sph_dec64be(const void *src) * @param src the source buffer (64-bit aligned) * @return the decoded value */ -static SPH_INLINE sph_u64 +static inline sph_u64 sph_dec64be_aligned(const void *src) { #if SPH_LITTLE_ENDIAN @@ -1792,33 +414,9 @@ sph_dec64be_aligned(const void *src) * @param dst the destination buffer * @param val the 64-bit value to encode */ -static SPH_INLINE void +static inline void sph_enc64le(void *dst, sph_u64 val) { -#if defined SPH_UPTR -#if SPH_UNALIGNED -#if SPH_BIG_ENDIAN - val = sph_bswap64(val); -#endif - *(sph_u64 *)dst = val; -#else - if (((SPH_UPTR)dst & 7) == 0) { -#if SPH_BIG_ENDIAN - val = sph_bswap64(val); -#endif - *(sph_u64 *)dst = val; - } else { - ((unsigned char *)dst)[0] = val; - ((unsigned char *)dst)[1] = (val >> 8); - ((unsigned char *)dst)[2] = (val >> 16); - ((unsigned char *)dst)[3] = (val >> 24); - ((unsigned char *)dst)[4] = (val >> 32); - ((unsigned char *)dst)[5] = (val >> 40); - ((unsigned char *)dst)[6] = (val >> 48); - ((unsigned char *)dst)[7] = (val >> 56); - } -#endif -#else ((unsigned char *)dst)[0] = val; ((unsigned char *)dst)[1] = (val >> 8); ((unsigned char *)dst)[2] = (val >> 16); @@ -1827,7 +425,6 @@ sph_enc64le(void *dst, sph_u64 val) ((unsigned char *)dst)[5] = (val >> 40); ((unsigned char *)dst)[6] = (val >> 48); ((unsigned char *)dst)[7] = (val >> 56); -#endif } /** @@ -1837,7 +434,7 @@ sph_enc64le(void *dst, sph_u64 val) * @param dst the destination buffer (64-bit aligned) * @param val the value to encode */ -static SPH_INLINE void +static inline void sph_enc64le_aligned(void *dst, sph_u64 val) { #if SPH_LITTLE_ENDIAN @@ -1862,57 +459,9 @@ sph_enc64le_aligned(void *dst, sph_u64 val) * @param src the source buffer * @return the decoded value */ -static SPH_INLINE sph_u64 +static inline sph_u64 sph_dec64le(const void *src) { -#if defined SPH_UPTR -#if SPH_UNALIGNED -#if SPH_BIG_ENDIAN - return sph_bswap64(*(const sph_u64 *)src); -#else - return *(const sph_u64 *)src; -#endif -#else - if (((SPH_UPTR)src & 7) == 0) { -#if SPH_BIG_ENDIAN -#if SPH_SPARCV9_GCC_64 && !SPH_NO_ASM - sph_u64 tmp; - - __asm__ __volatile__ ( - "ldxa [%1]0x88,%0" : "=r" (tmp) : "r" (src)); - return tmp; -/* - * Not worth it generally. - * -#elif SPH_PPC32_GCC && !SPH_NO_ASM - return (sph_u64)sph_dec32le_aligned(src) - | ((sph_u64)sph_dec32le_aligned( - (const char *)src + 4) << 32); -#elif SPH_PPC64_GCC && !SPH_NO_ASM - sph_u64 tmp; - - __asm__ __volatile__ ( - "ldbrx %0,0,%1" : "=r" (tmp) : "r" (src)); - return tmp; - */ -#else - return sph_bswap64(*(const sph_u64 *)src); -#endif -#else - return *(const sph_u64 *)src; -#endif - } else { - return (sph_u64)(((const unsigned char *)src)[0]) - | ((sph_u64)(((const unsigned char *)src)[1]) << 8) - | ((sph_u64)(((const unsigned char *)src)[2]) << 16) - | ((sph_u64)(((const unsigned char *)src)[3]) << 24) - | ((sph_u64)(((const unsigned char *)src)[4]) << 32) - | ((sph_u64)(((const unsigned char *)src)[5]) << 40) - | ((sph_u64)(((const unsigned char *)src)[6]) << 48) - | ((sph_u64)(((const unsigned char *)src)[7]) << 56); - } -#endif -#else return (sph_u64)(((const unsigned char *)src)[0]) | ((sph_u64)(((const unsigned char *)src)[1]) << 8) | ((sph_u64)(((const unsigned char *)src)[2]) << 16) @@ -1921,7 +470,6 @@ sph_dec64le(const void *src) | ((sph_u64)(((const unsigned char *)src)[5]) << 40) | ((sph_u64)(((const unsigned char *)src)[6]) << 48) | ((sph_u64)(((const unsigned char *)src)[7]) << 56); -#endif } /** @@ -1931,32 +479,13 @@ sph_dec64le(const void *src) * @param src the source buffer (64-bit aligned) * @return the decoded value */ -static SPH_INLINE sph_u64 +static inline sph_u64 sph_dec64le_aligned(const void *src) { #if SPH_LITTLE_ENDIAN return *(const sph_u64 *)src; #elif SPH_BIG_ENDIAN -#if SPH_SPARCV9_GCC_64 && !SPH_NO_ASM - sph_u64 tmp; - - __asm__ __volatile__ ("ldxa [%1]0x88,%0" : "=r" (tmp) : "r" (src)); - return tmp; -/* - * Not worth it generally. - * -#elif SPH_PPC32_GCC && !SPH_NO_ASM - return (sph_u64)sph_dec32le_aligned(src) - | ((sph_u64)sph_dec32le_aligned((const char *)src + 4) << 32); -#elif SPH_PPC64_GCC && !SPH_NO_ASM - sph_u64 tmp; - - __asm__ __volatile__ ("ldbrx %0,0,%1" : "=r" (tmp) : "r" (src)); - return tmp; - */ -#else return sph_bswap64(*(const sph_u64 *)src); -#endif #else return (sph_u64)(((const unsigned char *)src)[0]) | ((sph_u64)(((const unsigned char *)src)[1]) << 8) @@ -1970,7 +499,3 @@ sph_dec64le_aligned(const void *src) } #endif - -#endif /* Doxygen excluded block */ - -#endif From f15605bd45855a750a2453bdacb74d83344bcea0 Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Thu, 5 Apr 2018 03:13:16 +0700 Subject: [PATCH 549/627] Groestl hash: fix -Wshadow warnings --- Makefile | 2 ++ groestl.c | 24 ++++++++++++------------ 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/Makefile b/Makefile index 25682d241..b8f63417f 100644 --- a/Makefile +++ b/Makefile @@ -11,6 +11,7 @@ CFLAGS += $(OPTFLAGS) \ -Wredundant-decls \ -Wstrict-prototypes \ -Wundef \ + -Wshadow \ -Wpointer-arith \ -Wformat \ -Wreturn-type \ @@ -20,6 +21,7 @@ CFLAGS += $(OPTFLAGS) \ -Winit-self \ -Wuninitialized \ -Wformat-security \ + -Werror CFLAGS += -I. CFLAGS += -DUSE_ETHEREUM=1 diff --git a/groestl.c b/groestl.c index 8db8bb339..e0ea63e9e 100644 --- a/groestl.c +++ b/groestl.c @@ -917,24 +917,24 @@ static const sph_u32 T3dn[] = { #define COMPRESS_BIG do { \ sph_u32 g[32], m[32]; \ - size_t u; \ - for (u = 0; u < 32; u ++) { \ - m[u] = dec32e_aligned(buf + (u << 2)); \ - g[u] = m[u] ^ H[u]; \ + size_t uu; \ + for (uu = 0; uu < 32; uu ++) { \ + m[uu] = dec32e_aligned(buf + (uu << 2)); \ + g[uu] = m[uu] ^ H[uu]; \ } \ PERM_BIG_P(g); \ PERM_BIG_Q(m); \ - for (u = 0; u < 32; u ++) \ - H[u] ^= g[u] ^ m[u]; \ + for (uu = 0; uu < 32; uu ++) \ + H[uu] ^= g[uu] ^ m[uu]; \ } while (0) #define FINAL_BIG do { \ sph_u32 x[32]; \ - size_t u; \ + size_t uu; \ memcpy(x, H, sizeof x); \ PERM_BIG_P(x); \ - for (u = 0; u < 32; u ++) \ - H[u] ^= x[u]; \ + for (uu = 0; uu < 32; uu ++) \ + H[uu] ^= x[uu]; \ } while (0) @@ -993,7 +993,7 @@ groestl_big_close(sph_groestl_big_context *sc, unsigned ub, unsigned n, void *dst, size_t out_len) { unsigned char pad[136]; - size_t ptr, pad_len, u; + size_t ptr, pad_len, u2; sph_u64 count; unsigned z; DECL_STATE_BIG @@ -1013,8 +1013,8 @@ groestl_big_close(sph_groestl_big_context *sc, groestl_big_core(sc, pad, pad_len); READ_STATE_BIG(sc); FINAL_BIG; - for (u = 0; u < 16; u ++) - enc32e(pad + (u << 2), H[u + 16]); + for (u2 = 0; u2 < 16; u2 ++) + enc32e(pad + (u2 << 2), H[u2 + 16]); memcpy(dst, pad + 64 - out_len, out_len); groestl_big_init(sc, (unsigned)out_len << 3); } From c861ad8bbc5749438270d0006961a20ef0e8204a Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Thu, 5 Apr 2018 03:27:57 +0700 Subject: [PATCH 550/627] Groestl hash: more cleanups --- groestl.c | 11 ----------- groestl.h | 18 +----------------- 2 files changed, 1 insertion(+), 28 deletions(-) diff --git a/groestl.c b/groestl.c index e0ea63e9e..de3784cbf 100644 --- a/groestl.c +++ b/groestl.c @@ -1019,21 +1019,18 @@ groestl_big_close(sph_groestl_big_context *sc, groestl_big_init(sc, (unsigned)out_len << 3); } -/* see sph_groestl.h */ void groestl512_Init(void *cc) { groestl_big_init((sph_groestl_big_context *)cc, 512); } -/* see sph_groestl.h */ void groestl512_Update(void *cc, const void *data, size_t len) { groestl_big_core((sph_groestl_big_context *)cc, data, len); } -/* see sph_groestl.h */ void groestl512_Final(void *cc, void *dst) { @@ -1046,15 +1043,7 @@ groestl512_DoubleTrunc(void *cc, void *dst) char buf[64]; groestl512_Final(cc, buf); - groestl512_Init(cc); groestl512_Update(cc, buf, sizeof(buf)); groestl512_Final(cc, buf); memcpy(dst, buf, 32); } - -/* see sph_groestl.h */ -void -sph_groestl512_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) -{ - groestl_big_close((sph_groestl_big_context *)cc, ub, n, dst, 64); -} diff --git a/groestl.h b/groestl.h index 533d8c0bb..aeabf9442 100644 --- a/groestl.h +++ b/groestl.h @@ -89,23 +89,7 @@ void groestl512_Update(void *cc, const void *data, size_t len); */ void groestl512_Final(void *cc, void *dst); - +/* Calculate double Groestl-512 hash and truncate it to 256-bits. */ void groestl512_DoubleTrunc(void *cc, void *dst); -/** - * Add a few additional bits (0 to 7) to the current computation, then - * terminate it and output the result in the provided buffer, which must - * be wide enough to accomodate the result (64 bytes). If bit number i - * in ub has value 2^i, then the extra bits are those - * numbered 7 downto 8-n (this is the big-endian convention at the byte - * level). The context is automatically reinitialized. - * - * @param cc the Groestl-512 context - * @param ub the extra bits - * @param n the number of extra bits (0 to 7) - * @param dst the destination buffer - */ -void sph_groestl512_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); - #endif From bd81c2c6e7ed2ba8a2abfb5cba834b21ecb5f679 Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Thu, 5 Apr 2018 03:47:20 +0700 Subject: [PATCH 551/627] Groestl hash: remove even more dead code --- groestl.c | 268 ------------------------------------------------------ 1 file changed, 268 deletions(-) diff --git a/groestl.c b/groestl.c index de3784cbf..f72fe0fc0 100644 --- a/groestl.c +++ b/groestl.c @@ -347,274 +347,6 @@ static const sph_u32 T1dn[] = { C32e(0xcb46f6cb), C32e(0xfc1f4bfc), C32e(0xd661dad6), C32e(0x3a4e583a) }; -static const sph_u32 T2up[] = { - C32e(0xa5c6c632), C32e(0x84f8f86f), C32e(0x99eeee5e), C32e(0x8df6f67a), - C32e(0x0dffffe8), C32e(0xbdd6d60a), C32e(0xb1dede16), C32e(0x5491916d), - C32e(0x50606090), C32e(0x03020207), C32e(0xa9cece2e), C32e(0x7d5656d1), - C32e(0x19e7e7cc), C32e(0x62b5b513), C32e(0xe64d4d7c), C32e(0x9aecec59), - C32e(0x458f8f40), C32e(0x9d1f1fa3), C32e(0x40898949), C32e(0x87fafa68), - C32e(0x15efefd0), C32e(0xebb2b294), C32e(0xc98e8ece), C32e(0x0bfbfbe6), - C32e(0xec41416e), C32e(0x67b3b31a), C32e(0xfd5f5f43), C32e(0xea454560), - C32e(0xbf2323f9), C32e(0xf7535351), C32e(0x96e4e445), C32e(0x5b9b9b76), - C32e(0xc2757528), C32e(0x1ce1e1c5), C32e(0xae3d3dd4), C32e(0x6a4c4cf2), - C32e(0x5a6c6c82), C32e(0x417e7ebd), C32e(0x02f5f5f3), C32e(0x4f838352), - C32e(0x5c68688c), C32e(0xf4515156), C32e(0x34d1d18d), C32e(0x08f9f9e1), - C32e(0x93e2e24c), C32e(0x73abab3e), C32e(0x53626297), C32e(0x3f2a2a6b), - C32e(0x0c08081c), C32e(0x52959563), C32e(0x654646e9), C32e(0x5e9d9d7f), - C32e(0x28303048), C32e(0xa13737cf), C32e(0x0f0a0a1b), C32e(0xb52f2feb), - C32e(0x090e0e15), C32e(0x3624247e), C32e(0x9b1b1bad), C32e(0x3ddfdf98), - C32e(0x26cdcda7), C32e(0x694e4ef5), C32e(0xcd7f7f33), C32e(0x9feaea50), - C32e(0x1b12123f), C32e(0x9e1d1da4), C32e(0x745858c4), C32e(0x2e343446), - C32e(0x2d363641), C32e(0xb2dcdc11), C32e(0xeeb4b49d), C32e(0xfb5b5b4d), - C32e(0xf6a4a4a5), C32e(0x4d7676a1), C32e(0x61b7b714), C32e(0xce7d7d34), - C32e(0x7b5252df), C32e(0x3edddd9f), C32e(0x715e5ecd), C32e(0x971313b1), - C32e(0xf5a6a6a2), C32e(0x68b9b901), C32e(0x00000000), C32e(0x2cc1c1b5), - C32e(0x604040e0), C32e(0x1fe3e3c2), C32e(0xc879793a), C32e(0xedb6b69a), - C32e(0xbed4d40d), C32e(0x468d8d47), C32e(0xd9676717), C32e(0x4b7272af), - C32e(0xde9494ed), C32e(0xd49898ff), C32e(0xe8b0b093), C32e(0x4a85855b), - C32e(0x6bbbbb06), C32e(0x2ac5c5bb), C32e(0xe54f4f7b), C32e(0x16ededd7), - C32e(0xc58686d2), C32e(0xd79a9af8), C32e(0x55666699), C32e(0x941111b6), - C32e(0xcf8a8ac0), C32e(0x10e9e9d9), C32e(0x0604040e), C32e(0x81fefe66), - C32e(0xf0a0a0ab), C32e(0x447878b4), C32e(0xba2525f0), C32e(0xe34b4b75), - C32e(0xf3a2a2ac), C32e(0xfe5d5d44), C32e(0xc08080db), C32e(0x8a050580), - C32e(0xad3f3fd3), C32e(0xbc2121fe), C32e(0x487070a8), C32e(0x04f1f1fd), - C32e(0xdf636319), C32e(0xc177772f), C32e(0x75afaf30), C32e(0x634242e7), - C32e(0x30202070), C32e(0x1ae5e5cb), C32e(0x0efdfdef), C32e(0x6dbfbf08), - C32e(0x4c818155), C32e(0x14181824), C32e(0x35262679), C32e(0x2fc3c3b2), - C32e(0xe1bebe86), C32e(0xa23535c8), C32e(0xcc8888c7), C32e(0x392e2e65), - C32e(0x5793936a), C32e(0xf2555558), C32e(0x82fcfc61), C32e(0x477a7ab3), - C32e(0xacc8c827), C32e(0xe7baba88), C32e(0x2b32324f), C32e(0x95e6e642), - C32e(0xa0c0c03b), C32e(0x981919aa), C32e(0xd19e9ef6), C32e(0x7fa3a322), - C32e(0x664444ee), C32e(0x7e5454d6), C32e(0xab3b3bdd), C32e(0x830b0b95), - C32e(0xca8c8cc9), C32e(0x29c7c7bc), C32e(0xd36b6b05), C32e(0x3c28286c), - C32e(0x79a7a72c), C32e(0xe2bcbc81), C32e(0x1d161631), C32e(0x76adad37), - C32e(0x3bdbdb96), C32e(0x5664649e), C32e(0x4e7474a6), C32e(0x1e141436), - C32e(0xdb9292e4), C32e(0x0a0c0c12), C32e(0x6c4848fc), C32e(0xe4b8b88f), - C32e(0x5d9f9f78), C32e(0x6ebdbd0f), C32e(0xef434369), C32e(0xa6c4c435), - C32e(0xa83939da), C32e(0xa43131c6), C32e(0x37d3d38a), C32e(0x8bf2f274), - C32e(0x32d5d583), C32e(0x438b8b4e), C32e(0x596e6e85), C32e(0xb7dada18), - C32e(0x8c01018e), C32e(0x64b1b11d), C32e(0xd29c9cf1), C32e(0xe0494972), - C32e(0xb4d8d81f), C32e(0xfaacacb9), C32e(0x07f3f3fa), C32e(0x25cfcfa0), - C32e(0xafcaca20), C32e(0x8ef4f47d), C32e(0xe9474767), C32e(0x18101038), - C32e(0xd56f6f0b), C32e(0x88f0f073), C32e(0x6f4a4afb), C32e(0x725c5cca), - C32e(0x24383854), C32e(0xf157575f), C32e(0xc7737321), C32e(0x51979764), - C32e(0x23cbcbae), C32e(0x7ca1a125), C32e(0x9ce8e857), C32e(0x213e3e5d), - C32e(0xdd9696ea), C32e(0xdc61611e), C32e(0x860d0d9c), C32e(0x850f0f9b), - C32e(0x90e0e04b), C32e(0x427c7cba), C32e(0xc4717126), C32e(0xaacccc29), - C32e(0xd89090e3), C32e(0x05060609), C32e(0x01f7f7f4), C32e(0x121c1c2a), - C32e(0xa3c2c23c), C32e(0x5f6a6a8b), C32e(0xf9aeaebe), C32e(0xd0696902), - C32e(0x911717bf), C32e(0x58999971), C32e(0x273a3a53), C32e(0xb92727f7), - C32e(0x38d9d991), C32e(0x13ebebde), C32e(0xb32b2be5), C32e(0x33222277), - C32e(0xbbd2d204), C32e(0x70a9a939), C32e(0x89070787), C32e(0xa73333c1), - C32e(0xb62d2dec), C32e(0x223c3c5a), C32e(0x921515b8), C32e(0x20c9c9a9), - C32e(0x4987875c), C32e(0xffaaaab0), C32e(0x785050d8), C32e(0x7aa5a52b), - C32e(0x8f030389), C32e(0xf859594a), C32e(0x80090992), C32e(0x171a1a23), - C32e(0xda656510), C32e(0x31d7d784), C32e(0xc68484d5), C32e(0xb8d0d003), - C32e(0xc38282dc), C32e(0xb02929e2), C32e(0x775a5ac3), C32e(0x111e1e2d), - C32e(0xcb7b7b3d), C32e(0xfca8a8b7), C32e(0xd66d6d0c), C32e(0x3a2c2c62) -}; - -static const sph_u32 T2dn[] = { - C32e(0xf4a5f497), C32e(0x978497eb), C32e(0xb099b0c7), C32e(0x8c8d8cf7), - C32e(0x170d17e5), C32e(0xdcbddcb7), C32e(0xc8b1c8a7), C32e(0xfc54fc39), - C32e(0xf050f0c0), C32e(0x05030504), C32e(0xe0a9e087), C32e(0x877d87ac), - C32e(0x2b192bd5), C32e(0xa662a671), C32e(0x31e6319a), C32e(0xb59ab5c3), - C32e(0xcf45cf05), C32e(0xbc9dbc3e), C32e(0xc040c009), C32e(0x928792ef), - C32e(0x3f153fc5), C32e(0x26eb267f), C32e(0x40c94007), C32e(0x1d0b1ded), - C32e(0x2fec2f82), C32e(0xa967a97d), C32e(0x1cfd1cbe), C32e(0x25ea258a), - C32e(0xdabfda46), C32e(0x02f702a6), C32e(0xa196a1d3), C32e(0xed5bed2d), - C32e(0x5dc25dea), C32e(0x241c24d9), C32e(0xe9aee97a), C32e(0xbe6abe98), - C32e(0xee5aeed8), C32e(0xc341c3fc), C32e(0x060206f1), C32e(0xd14fd11d), - C32e(0xe45ce4d0), C32e(0x07f407a2), C32e(0x5c345cb9), C32e(0x180818e9), - C32e(0xae93aedf), C32e(0x9573954d), C32e(0xf553f5c4), C32e(0x413f4154), - C32e(0x140c1410), C32e(0xf652f631), C32e(0xaf65af8c), C32e(0xe25ee221), - C32e(0x78287860), C32e(0xf8a1f86e), C32e(0x110f1114), C32e(0xc4b5c45e), - C32e(0x1b091b1c), C32e(0x5a365a48), C32e(0xb69bb636), C32e(0x473d47a5), - C32e(0x6a266a81), C32e(0xbb69bb9c), C32e(0x4ccd4cfe), C32e(0xba9fbacf), - C32e(0x2d1b2d24), C32e(0xb99eb93a), C32e(0x9c749cb0), C32e(0x722e7268), - C32e(0x772d776c), C32e(0xcdb2cda3), C32e(0x29ee2973), C32e(0x16fb16b6), - C32e(0x01f60153), C32e(0xd74dd7ec), C32e(0xa361a375), C32e(0x49ce49fa), - C32e(0x8d7b8da4), C32e(0x423e42a1), C32e(0x937193bc), C32e(0xa297a226), - C32e(0x04f50457), C32e(0xb868b869), C32e(0x00000000), C32e(0x742c7499), - C32e(0xa060a080), C32e(0x211f21dd), C32e(0x43c843f2), C32e(0x2ced2c77), - C32e(0xd9bed9b3), C32e(0xca46ca01), C32e(0x70d970ce), C32e(0xdd4bdde4), - C32e(0x79de7933), C32e(0x67d4672b), C32e(0x23e8237b), C32e(0xde4ade11), - C32e(0xbd6bbd6d), C32e(0x7e2a7e91), C32e(0x34e5349e), C32e(0x3a163ac1), - C32e(0x54c55417), C32e(0x62d7622f), C32e(0xff55ffcc), C32e(0xa794a722), - C32e(0x4acf4a0f), C32e(0x301030c9), C32e(0x0a060a08), C32e(0x988198e7), - C32e(0x0bf00b5b), C32e(0xcc44ccf0), C32e(0xd5bad54a), C32e(0x3ee33e96), - C32e(0x0ef30e5f), C32e(0x19fe19ba), C32e(0x5bc05b1b), C32e(0x858a850a), - C32e(0xecadec7e), C32e(0xdfbcdf42), C32e(0xd848d8e0), C32e(0x0c040cf9), - C32e(0x7adf7ac6), C32e(0x58c158ee), C32e(0x9f759f45), C32e(0xa563a584), - C32e(0x50305040), C32e(0x2e1a2ed1), C32e(0x120e12e1), C32e(0xb76db765), - C32e(0xd44cd419), C32e(0x3c143c30), C32e(0x5f355f4c), C32e(0x712f719d), - C32e(0x38e13867), C32e(0xfda2fd6a), C32e(0x4fcc4f0b), C32e(0x4b394b5c), - C32e(0xf957f93d), C32e(0x0df20daa), C32e(0x9d829de3), C32e(0xc947c9f4), - C32e(0xefacef8b), C32e(0x32e7326f), C32e(0x7d2b7d64), C32e(0xa495a4d7), - C32e(0xfba0fb9b), C32e(0xb398b332), C32e(0x68d16827), C32e(0x817f815d), - C32e(0xaa66aa88), C32e(0x827e82a8), C32e(0xe6abe676), C32e(0x9e839e16), - C32e(0x45ca4503), C32e(0x7b297b95), C32e(0x6ed36ed6), C32e(0x443c4450), - C32e(0x8b798b55), C32e(0x3de23d63), C32e(0x271d272c), C32e(0x9a769a41), - C32e(0x4d3b4dad), C32e(0xfa56fac8), C32e(0xd24ed2e8), C32e(0x221e2228), - C32e(0x76db763f), C32e(0x1e0a1e18), C32e(0xb46cb490), C32e(0x37e4376b), - C32e(0xe75de725), C32e(0xb26eb261), C32e(0x2aef2a86), C32e(0xf1a6f193), - C32e(0xe3a8e372), C32e(0xf7a4f762), C32e(0x593759bd), C32e(0x868b86ff), - C32e(0x563256b1), C32e(0xc543c50d), C32e(0xeb59ebdc), C32e(0xc2b7c2af), - C32e(0x8f8c8f02), C32e(0xac64ac79), C32e(0x6dd26d23), C32e(0x3be03b92), - C32e(0xc7b4c7ab), C32e(0x15fa1543), C32e(0x090709fd), C32e(0x6f256f85), - C32e(0xeaafea8f), C32e(0x898e89f3), C32e(0x20e9208e), C32e(0x28182820), - C32e(0x64d564de), C32e(0x838883fb), C32e(0xb16fb194), C32e(0x967296b8), - C32e(0x6c246c70), C32e(0x08f108ae), C32e(0x52c752e6), C32e(0xf351f335), - C32e(0x6523658d), C32e(0x847c8459), C32e(0xbf9cbfcb), C32e(0x6321637c), - C32e(0x7cdd7c37), C32e(0x7fdc7fc2), C32e(0x9186911a), C32e(0x9485941e), - C32e(0xab90abdb), C32e(0xc642c6f8), C32e(0x57c457e2), C32e(0xe5aae583), - C32e(0x73d8733b), C32e(0x0f050f0c), C32e(0x030103f5), C32e(0x36123638), - C32e(0xfea3fe9f), C32e(0xe15fe1d4), C32e(0x10f91047), C32e(0x6bd06bd2), - C32e(0xa891a82e), C32e(0xe858e829), C32e(0x69276974), C32e(0xd0b9d04e), - C32e(0x483848a9), C32e(0x351335cd), C32e(0xceb3ce56), C32e(0x55335544), - C32e(0xd6bbd6bf), C32e(0x90709049), C32e(0x8089800e), C32e(0xf2a7f266), - C32e(0xc1b6c15a), C32e(0x66226678), C32e(0xad92ad2a), C32e(0x60206089), - C32e(0xdb49db15), C32e(0x1aff1a4f), C32e(0x887888a0), C32e(0x8e7a8e51), - C32e(0x8a8f8a06), C32e(0x13f813b2), C32e(0x9b809b12), C32e(0x39173934), - C32e(0x75da75ca), C32e(0x533153b5), C32e(0x51c65113), C32e(0xd3b8d3bb), - C32e(0x5ec35e1f), C32e(0xcbb0cb52), C32e(0x997799b4), C32e(0x3311333c), - C32e(0x46cb46f6), C32e(0x1ffc1f4b), C32e(0x61d661da), C32e(0x4e3a4e58) -}; - -static const sph_u32 T3up[] = { - C32e(0x97a5c6c6), C32e(0xeb84f8f8), C32e(0xc799eeee), C32e(0xf78df6f6), - C32e(0xe50dffff), C32e(0xb7bdd6d6), C32e(0xa7b1dede), C32e(0x39549191), - C32e(0xc0506060), C32e(0x04030202), C32e(0x87a9cece), C32e(0xac7d5656), - C32e(0xd519e7e7), C32e(0x7162b5b5), C32e(0x9ae64d4d), C32e(0xc39aecec), - C32e(0x05458f8f), C32e(0x3e9d1f1f), C32e(0x09408989), C32e(0xef87fafa), - C32e(0xc515efef), C32e(0x7febb2b2), C32e(0x07c98e8e), C32e(0xed0bfbfb), - C32e(0x82ec4141), C32e(0x7d67b3b3), C32e(0xbefd5f5f), C32e(0x8aea4545), - C32e(0x46bf2323), C32e(0xa6f75353), C32e(0xd396e4e4), C32e(0x2d5b9b9b), - C32e(0xeac27575), C32e(0xd91ce1e1), C32e(0x7aae3d3d), C32e(0x986a4c4c), - C32e(0xd85a6c6c), C32e(0xfc417e7e), C32e(0xf102f5f5), C32e(0x1d4f8383), - C32e(0xd05c6868), C32e(0xa2f45151), C32e(0xb934d1d1), C32e(0xe908f9f9), - C32e(0xdf93e2e2), C32e(0x4d73abab), C32e(0xc4536262), C32e(0x543f2a2a), - C32e(0x100c0808), C32e(0x31529595), C32e(0x8c654646), C32e(0x215e9d9d), - C32e(0x60283030), C32e(0x6ea13737), C32e(0x140f0a0a), C32e(0x5eb52f2f), - C32e(0x1c090e0e), C32e(0x48362424), C32e(0x369b1b1b), C32e(0xa53ddfdf), - C32e(0x8126cdcd), C32e(0x9c694e4e), C32e(0xfecd7f7f), C32e(0xcf9feaea), - C32e(0x241b1212), C32e(0x3a9e1d1d), C32e(0xb0745858), C32e(0x682e3434), - C32e(0x6c2d3636), C32e(0xa3b2dcdc), C32e(0x73eeb4b4), C32e(0xb6fb5b5b), - C32e(0x53f6a4a4), C32e(0xec4d7676), C32e(0x7561b7b7), C32e(0xface7d7d), - C32e(0xa47b5252), C32e(0xa13edddd), C32e(0xbc715e5e), C32e(0x26971313), - C32e(0x57f5a6a6), C32e(0x6968b9b9), C32e(0x00000000), C32e(0x992cc1c1), - C32e(0x80604040), C32e(0xdd1fe3e3), C32e(0xf2c87979), C32e(0x77edb6b6), - C32e(0xb3bed4d4), C32e(0x01468d8d), C32e(0xced96767), C32e(0xe44b7272), - C32e(0x33de9494), C32e(0x2bd49898), C32e(0x7be8b0b0), C32e(0x114a8585), - C32e(0x6d6bbbbb), C32e(0x912ac5c5), C32e(0x9ee54f4f), C32e(0xc116eded), - C32e(0x17c58686), C32e(0x2fd79a9a), C32e(0xcc556666), C32e(0x22941111), - C32e(0x0fcf8a8a), C32e(0xc910e9e9), C32e(0x08060404), C32e(0xe781fefe), - C32e(0x5bf0a0a0), C32e(0xf0447878), C32e(0x4aba2525), C32e(0x96e34b4b), - C32e(0x5ff3a2a2), C32e(0xbafe5d5d), C32e(0x1bc08080), C32e(0x0a8a0505), - C32e(0x7ead3f3f), C32e(0x42bc2121), C32e(0xe0487070), C32e(0xf904f1f1), - C32e(0xc6df6363), C32e(0xeec17777), C32e(0x4575afaf), C32e(0x84634242), - C32e(0x40302020), C32e(0xd11ae5e5), C32e(0xe10efdfd), C32e(0x656dbfbf), - C32e(0x194c8181), C32e(0x30141818), C32e(0x4c352626), C32e(0x9d2fc3c3), - C32e(0x67e1bebe), C32e(0x6aa23535), C32e(0x0bcc8888), C32e(0x5c392e2e), - C32e(0x3d579393), C32e(0xaaf25555), C32e(0xe382fcfc), C32e(0xf4477a7a), - C32e(0x8bacc8c8), C32e(0x6fe7baba), C32e(0x642b3232), C32e(0xd795e6e6), - C32e(0x9ba0c0c0), C32e(0x32981919), C32e(0x27d19e9e), C32e(0x5d7fa3a3), - C32e(0x88664444), C32e(0xa87e5454), C32e(0x76ab3b3b), C32e(0x16830b0b), - C32e(0x03ca8c8c), C32e(0x9529c7c7), C32e(0xd6d36b6b), C32e(0x503c2828), - C32e(0x5579a7a7), C32e(0x63e2bcbc), C32e(0x2c1d1616), C32e(0x4176adad), - C32e(0xad3bdbdb), C32e(0xc8566464), C32e(0xe84e7474), C32e(0x281e1414), - C32e(0x3fdb9292), C32e(0x180a0c0c), C32e(0x906c4848), C32e(0x6be4b8b8), - C32e(0x255d9f9f), C32e(0x616ebdbd), C32e(0x86ef4343), C32e(0x93a6c4c4), - C32e(0x72a83939), C32e(0x62a43131), C32e(0xbd37d3d3), C32e(0xff8bf2f2), - C32e(0xb132d5d5), C32e(0x0d438b8b), C32e(0xdc596e6e), C32e(0xafb7dada), - C32e(0x028c0101), C32e(0x7964b1b1), C32e(0x23d29c9c), C32e(0x92e04949), - C32e(0xabb4d8d8), C32e(0x43faacac), C32e(0xfd07f3f3), C32e(0x8525cfcf), - C32e(0x8fafcaca), C32e(0xf38ef4f4), C32e(0x8ee94747), C32e(0x20181010), - C32e(0xded56f6f), C32e(0xfb88f0f0), C32e(0x946f4a4a), C32e(0xb8725c5c), - C32e(0x70243838), C32e(0xaef15757), C32e(0xe6c77373), C32e(0x35519797), - C32e(0x8d23cbcb), C32e(0x597ca1a1), C32e(0xcb9ce8e8), C32e(0x7c213e3e), - C32e(0x37dd9696), C32e(0xc2dc6161), C32e(0x1a860d0d), C32e(0x1e850f0f), - C32e(0xdb90e0e0), C32e(0xf8427c7c), C32e(0xe2c47171), C32e(0x83aacccc), - C32e(0x3bd89090), C32e(0x0c050606), C32e(0xf501f7f7), C32e(0x38121c1c), - C32e(0x9fa3c2c2), C32e(0xd45f6a6a), C32e(0x47f9aeae), C32e(0xd2d06969), - C32e(0x2e911717), C32e(0x29589999), C32e(0x74273a3a), C32e(0x4eb92727), - C32e(0xa938d9d9), C32e(0xcd13ebeb), C32e(0x56b32b2b), C32e(0x44332222), - C32e(0xbfbbd2d2), C32e(0x4970a9a9), C32e(0x0e890707), C32e(0x66a73333), - C32e(0x5ab62d2d), C32e(0x78223c3c), C32e(0x2a921515), C32e(0x8920c9c9), - C32e(0x15498787), C32e(0x4fffaaaa), C32e(0xa0785050), C32e(0x517aa5a5), - C32e(0x068f0303), C32e(0xb2f85959), C32e(0x12800909), C32e(0x34171a1a), - C32e(0xcada6565), C32e(0xb531d7d7), C32e(0x13c68484), C32e(0xbbb8d0d0), - C32e(0x1fc38282), C32e(0x52b02929), C32e(0xb4775a5a), C32e(0x3c111e1e), - C32e(0xf6cb7b7b), C32e(0x4bfca8a8), C32e(0xdad66d6d), C32e(0x583a2c2c) -}; - -static const sph_u32 T3dn[] = { - C32e(0x32f4a5f4), C32e(0x6f978497), C32e(0x5eb099b0), C32e(0x7a8c8d8c), - C32e(0xe8170d17), C32e(0x0adcbddc), C32e(0x16c8b1c8), C32e(0x6dfc54fc), - C32e(0x90f050f0), C32e(0x07050305), C32e(0x2ee0a9e0), C32e(0xd1877d87), - C32e(0xcc2b192b), C32e(0x13a662a6), C32e(0x7c31e631), C32e(0x59b59ab5), - C32e(0x40cf45cf), C32e(0xa3bc9dbc), C32e(0x49c040c0), C32e(0x68928792), - C32e(0xd03f153f), C32e(0x9426eb26), C32e(0xce40c940), C32e(0xe61d0b1d), - C32e(0x6e2fec2f), C32e(0x1aa967a9), C32e(0x431cfd1c), C32e(0x6025ea25), - C32e(0xf9dabfda), C32e(0x5102f702), C32e(0x45a196a1), C32e(0x76ed5bed), - C32e(0x285dc25d), C32e(0xc5241c24), C32e(0xd4e9aee9), C32e(0xf2be6abe), - C32e(0x82ee5aee), C32e(0xbdc341c3), C32e(0xf3060206), C32e(0x52d14fd1), - C32e(0x8ce45ce4), C32e(0x5607f407), C32e(0x8d5c345c), C32e(0xe1180818), - C32e(0x4cae93ae), C32e(0x3e957395), C32e(0x97f553f5), C32e(0x6b413f41), - C32e(0x1c140c14), C32e(0x63f652f6), C32e(0xe9af65af), C32e(0x7fe25ee2), - C32e(0x48782878), C32e(0xcff8a1f8), C32e(0x1b110f11), C32e(0xebc4b5c4), - C32e(0x151b091b), C32e(0x7e5a365a), C32e(0xadb69bb6), C32e(0x98473d47), - C32e(0xa76a266a), C32e(0xf5bb69bb), C32e(0x334ccd4c), C32e(0x50ba9fba), - C32e(0x3f2d1b2d), C32e(0xa4b99eb9), C32e(0xc49c749c), C32e(0x46722e72), - C32e(0x41772d77), C32e(0x11cdb2cd), C32e(0x9d29ee29), C32e(0x4d16fb16), - C32e(0xa501f601), C32e(0xa1d74dd7), C32e(0x14a361a3), C32e(0x3449ce49), - C32e(0xdf8d7b8d), C32e(0x9f423e42), C32e(0xcd937193), C32e(0xb1a297a2), - C32e(0xa204f504), C32e(0x01b868b8), C32e(0x00000000), C32e(0xb5742c74), - C32e(0xe0a060a0), C32e(0xc2211f21), C32e(0x3a43c843), C32e(0x9a2ced2c), - C32e(0x0dd9bed9), C32e(0x47ca46ca), C32e(0x1770d970), C32e(0xafdd4bdd), - C32e(0xed79de79), C32e(0xff67d467), C32e(0x9323e823), C32e(0x5bde4ade), - C32e(0x06bd6bbd), C32e(0xbb7e2a7e), C32e(0x7b34e534), C32e(0xd73a163a), - C32e(0xd254c554), C32e(0xf862d762), C32e(0x99ff55ff), C32e(0xb6a794a7), - C32e(0xc04acf4a), C32e(0xd9301030), C32e(0x0e0a060a), C32e(0x66988198), - C32e(0xab0bf00b), C32e(0xb4cc44cc), C32e(0xf0d5bad5), C32e(0x753ee33e), - C32e(0xac0ef30e), C32e(0x4419fe19), C32e(0xdb5bc05b), C32e(0x80858a85), - C32e(0xd3ecadec), C32e(0xfedfbcdf), C32e(0xa8d848d8), C32e(0xfd0c040c), - C32e(0x197adf7a), C32e(0x2f58c158), C32e(0x309f759f), C32e(0xe7a563a5), - C32e(0x70503050), C32e(0xcb2e1a2e), C32e(0xef120e12), C32e(0x08b76db7), - C32e(0x55d44cd4), C32e(0x243c143c), C32e(0x795f355f), C32e(0xb2712f71), - C32e(0x8638e138), C32e(0xc8fda2fd), C32e(0xc74fcc4f), C32e(0x654b394b), - C32e(0x6af957f9), C32e(0x580df20d), C32e(0x619d829d), C32e(0xb3c947c9), - C32e(0x27efacef), C32e(0x8832e732), C32e(0x4f7d2b7d), C32e(0x42a495a4), - C32e(0x3bfba0fb), C32e(0xaab398b3), C32e(0xf668d168), C32e(0x22817f81), - C32e(0xeeaa66aa), C32e(0xd6827e82), C32e(0xdde6abe6), C32e(0x959e839e), - C32e(0xc945ca45), C32e(0xbc7b297b), C32e(0x056ed36e), C32e(0x6c443c44), - C32e(0x2c8b798b), C32e(0x813de23d), C32e(0x31271d27), C32e(0x379a769a), - C32e(0x964d3b4d), C32e(0x9efa56fa), C32e(0xa6d24ed2), C32e(0x36221e22), - C32e(0xe476db76), C32e(0x121e0a1e), C32e(0xfcb46cb4), C32e(0x8f37e437), - C32e(0x78e75de7), C32e(0x0fb26eb2), C32e(0x692aef2a), C32e(0x35f1a6f1), - C32e(0xdae3a8e3), C32e(0xc6f7a4f7), C32e(0x8a593759), C32e(0x74868b86), - C32e(0x83563256), C32e(0x4ec543c5), C32e(0x85eb59eb), C32e(0x18c2b7c2), - C32e(0x8e8f8c8f), C32e(0x1dac64ac), C32e(0xf16dd26d), C32e(0x723be03b), - C32e(0x1fc7b4c7), C32e(0xb915fa15), C32e(0xfa090709), C32e(0xa06f256f), - C32e(0x20eaafea), C32e(0x7d898e89), C32e(0x6720e920), C32e(0x38281828), - C32e(0x0b64d564), C32e(0x73838883), C32e(0xfbb16fb1), C32e(0xca967296), - C32e(0x546c246c), C32e(0x5f08f108), C32e(0x2152c752), C32e(0x64f351f3), - C32e(0xae652365), C32e(0x25847c84), C32e(0x57bf9cbf), C32e(0x5d632163), - C32e(0xea7cdd7c), C32e(0x1e7fdc7f), C32e(0x9c918691), C32e(0x9b948594), - C32e(0x4bab90ab), C32e(0xbac642c6), C32e(0x2657c457), C32e(0x29e5aae5), - C32e(0xe373d873), C32e(0x090f050f), C32e(0xf4030103), C32e(0x2a361236), - C32e(0x3cfea3fe), C32e(0x8be15fe1), C32e(0xbe10f910), C32e(0x026bd06b), - C32e(0xbfa891a8), C32e(0x71e858e8), C32e(0x53692769), C32e(0xf7d0b9d0), - C32e(0x91483848), C32e(0xde351335), C32e(0xe5ceb3ce), C32e(0x77553355), - C32e(0x04d6bbd6), C32e(0x39907090), C32e(0x87808980), C32e(0xc1f2a7f2), - C32e(0xecc1b6c1), C32e(0x5a662266), C32e(0xb8ad92ad), C32e(0xa9602060), - C32e(0x5cdb49db), C32e(0xb01aff1a), C32e(0xd8887888), C32e(0x2b8e7a8e), - C32e(0x898a8f8a), C32e(0x4a13f813), C32e(0x929b809b), C32e(0x23391739), - C32e(0x1075da75), C32e(0x84533153), C32e(0xd551c651), C32e(0x03d3b8d3), - C32e(0xdc5ec35e), C32e(0xe2cbb0cb), C32e(0xc3997799), C32e(0x2d331133), - C32e(0x3d46cb46), C32e(0xb71ffc1f), C32e(0x0c61d661), C32e(0x624e3a4e) -}; - #define DECL_STATE_SMALL \ sph_u32 H[16]; From 1adcaea9cdee8ded8658d64a405ea725dbba0fc0 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 23 Apr 2018 15:20:01 +0100 Subject: [PATCH 552/627] remove debug printfs from test_check_cashaddr --- tests/test_check_cashaddr.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/test_check_cashaddr.h b/tests/test_check_cashaddr.h index 51448de63..de93d0140 100644 --- a/tests/test_check_cashaddr.h +++ b/tests/test_check_cashaddr.h @@ -57,8 +57,6 @@ START_TEST(test_cashaddr) ck_assert_int_eq(res, 1); res = cash_encode(rebuild, hrp, data, data_len); ck_assert_int_eq(res, 1); - printf("%s\n", rebuild); - printf("%s\n", valid_cashchecksum[i]); ck_assert_int_eq(my_strncasecmp(rebuild, valid_cashchecksum[i], 92), 0); } for (i = 0; i < sizeof(valid_cashaddr) / sizeof(valid_cashaddr[0]); ++i) { @@ -77,8 +75,6 @@ START_TEST(test_cashaddr) ck_assert_int_eq(memcmp(rawdata + 1, prog + 1, 20), 0); ret = cash_addr_encode(rebuild, hrp, prog, 21); ck_assert_int_eq(ret, 1); - printf("%s\n", rebuild); - printf("%s\n", valid_cashaddr[i].cashaddress); ck_assert_int_eq(my_strncasecmp(rebuild, valid_cashaddr[i].cashaddress, 92), 0); } } From 5708a7257f15473ed3f634ceeca8833077487c84 Mon Sep 17 00:00:00 2001 From: Dusan Klinec Date: Fri, 27 Apr 2018 17:59:58 +0200 Subject: [PATCH 553/627] ed25519-donna/modm: comment typo fix --- ed25519-donna/modm-donna-32bit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ed25519-donna/modm-donna-32bit.c b/ed25519-donna/modm-donna-32bit.c index 9ed296cf3..86607c169 100644 --- a/ed25519-donna/modm-donna-32bit.c +++ b/ed25519-donna/modm-donna-32bit.c @@ -94,7 +94,7 @@ void barrett_reduce256_modm(bignum256modm r, const bignum256modm q1, const bignu c += mul32x32_64(modm_mu[8], q1[8]); f = (bignum256modm_element_t)c; q3[7] |= (f << 6) & 0x3fffffff; q3[8] = (bignum256modm_element_t)(c >> 24); - /* r1 = (x mod 256^(32+1)) = x mod (2^8)(31+1) = x & ((1 << 264) - 1) + /* r1 = (x mod 256^(32+1)) = x mod (2^8)(32+1) = x & ((1 << 264) - 1) r2 = (q3 * m) mod (256^(32+1)) = (q3 * m) & ((1 << 264) - 1) */ c = mul32x32_64(modm_m[0], q3[0]); r2[0] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30; From 6a20ba5586cf45ab27bc8ba4773d83bd090d61cc Mon Sep 17 00:00:00 2001 From: Dusan Klinec Date: Fri, 27 Apr 2018 18:37:02 +0200 Subject: [PATCH 554/627] ed25519-donna/modm: neg, sub added --- ed25519-donna/modm-donna-32bit.c | 27 +++++++ ed25519-donna/modm-donna-32bit.h | 6 ++ tests/test_check.c | 135 +++++++++++++++++++++++++++++++ 3 files changed, 168 insertions(+) diff --git a/ed25519-donna/modm-donna-32bit.c b/ed25519-donna/modm-donna-32bit.c index 86607c169..0b4ad74ff 100644 --- a/ed25519-donna/modm-donna-32bit.c +++ b/ed25519-donna/modm-donna-32bit.c @@ -149,6 +149,33 @@ void add256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y) reduce256_modm(r); } +/* -x modulo m */ +void neg256_modm(bignum256modm r, const bignum256modm x) { + bignum256modm_element_t b = 0, pb; + + /* r = m - x */ + pb = 0; + pb += x[0]; b = lt_modm(modm_m[0], pb); r[0] = (modm_m[0] - pb + (b << 30)); pb = b; + pb += x[1]; b = lt_modm(modm_m[1], pb); r[1] = (modm_m[1] - pb + (b << 30)); pb = b; + pb += x[2]; b = lt_modm(modm_m[2], pb); r[2] = (modm_m[2] - pb + (b << 30)); pb = b; + pb += x[3]; b = lt_modm(modm_m[3], pb); r[3] = (modm_m[3] - pb + (b << 30)); pb = b; + pb += x[4]; b = lt_modm(modm_m[4], pb); r[4] = (modm_m[4] - pb + (b << 30)); pb = b; + pb += x[5]; b = lt_modm(modm_m[5], pb); r[5] = (modm_m[5] - pb + (b << 30)); pb = b; + pb += x[6]; b = lt_modm(modm_m[6], pb); r[6] = (modm_m[6] - pb + (b << 30)); pb = b; + pb += x[7]; b = lt_modm(modm_m[7], pb); r[7] = (modm_m[7] - pb + (b << 30)); pb = b; + pb += x[8]; b = lt_modm(modm_m[8], pb); r[8] = (modm_m[8] - pb + (b << 16)); + + // if x==0, reduction is required + reduce256_modm(r); +} + +/* subtraction x-y % m */ +void sub256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y) { + bignum256modm negy; + neg256_modm(negy, y); + add256_modm(r, x, negy); +} + /* multiplication modulo m */ void mul256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y) { bignum256modm r1, q1; diff --git a/ed25519-donna/modm-donna-32bit.h b/ed25519-donna/modm-donna-32bit.h index 129e3b113..21306c799 100644 --- a/ed25519-donna/modm-donna-32bit.h +++ b/ed25519-donna/modm-donna-32bit.h @@ -31,6 +31,12 @@ void barrett_reduce256_modm(bignum256modm r, const bignum256modm q1, const bignu /* addition modulo m */ void add256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y); +/* -x modulo m */ +void neg256_modm(bignum256modm r, const bignum256modm x); + +/* subtraction x-y modulo m */ +void sub256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y); + /* multiplication modulo m */ void mul256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y); diff --git a/tests/test_check.c b/tests/test_check.c index 0fc5a6d34..3038809b2 100644 --- a/tests/test_check.c +++ b/tests/test_check.c @@ -54,6 +54,7 @@ #include "secp256k1.h" #include "nist256p1.h" #include "ed25519-donna/ed25519.h" +#include "ed25519-donna/ed25519-donna.h" #include "ed25519-donna/ed25519-keccak.h" #include "script.h" #include "rfc6979.h" @@ -3377,6 +3378,134 @@ START_TEST(test_ed25519_cosi) { } END_TEST +START_TEST(test_ed25519_modl_add) +{ + char tests[][3][65] = { + {"0000000000000000000000000000000000000000000000000000000000000000", + "0000000000000000000000000000000000000000000000000000000000000000", + "0000000000000000000000000000000000000000000000000000000000000000", + }, + + {"eef80ad5a9aad8b35b84f6a4eb3a7e2b222f403d455d8cdf40ad27e4cd5ae90a", + "0000000000000000000000000000000000000000000000000000000000000000", + "eef80ad5a9aad8b35b84f6a4eb3a7e2b222f403d455d8cdf40ad27e4cd5ae90a" + }, + + {"0000000000000000000000000000000000000000000000000000000000000000", + "eef80ad5a9aad8b35b84f6a4eb3a7e2b222f403d455d8cdf40ad27e4cd5ae90a", + "eef80ad5a9aad8b35b84f6a4eb3a7e2b222f403d455d8cdf40ad27e4cd5ae90a" + }, + + {"0100000000000000000000000000000000000000000000000000000000000000", + "0200000000000000000000000000000000000000000000000000000000000000", + "0300000000000000000000000000000000000000000000000000000000000000" + }, + + {"e3d3f55c1a631258d69cf7a2def9de1400000000000000000000000000000010", + "0a00000000000000000000000000000000000000000000000000000000000000", + "0000000000000000000000000000000000000000000000000000000000000000" + }, + + {"f7bb3bf42b3e58e2edd06f173fc7bfbc7aaf657217946b75648447101136aa08", + "3c16b013109cc27ff39805be2abe04ba4cd6a8526a1d3023047693e950936c06", + "33d2eb073cda1a62e16975d56985c476c7850ec581b19b9868fadaf961c9160f" + }, + }; + + unsigned char buff[32]; + bignum256modm a={0}, b={0}, c={0}; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + expand256_modm(a, fromhex(tests[i][0]), 32); + expand256_modm(b, fromhex(tests[i][1]), 32); + add256_modm(c, a, b); + contract256_modm(buff, c); + ck_assert_mem_eq(buff, fromhex(tests[i][2]), 32); + } +} +END_TEST + +START_TEST(test_ed25519_modl_neg) +{ + char tests[][2][65] = { + {"05d0f55c1a631258d69cf7a2def9de1400000000000000000000000000000010", + "e803000000000000000000000000000000000000000000000000000000000000"}, + + {"4d4df45c1a631258d69cf7a2def9de1400000000000000000000000000000010", + "a086010000000000000000000000000000000000000000000000000000000000"}, + + {"25958944a1b7d4073975ca48996a1d740d0ed98ceec366760c5358da681e9608", + "c83e6c1879ab3d509d272d5a458fc1a0f2f12673113c9989f3aca72597e16907"}, + + {"0100000000000000000000000000000000000000000000000000000000000000", + "ecd3f55c1a631258d69cf7a2def9de1400000000000000000000000000000010"}, + + {"ecd3f55c1a631258d69cf7a2def9de1400000000000000000000000000000010", + "0100000000000000000000000000000000000000000000000000000000000000"}, + + {"0000000000000000000000000000000000000000000000000000000000000000", + "0000000000000000000000000000000000000000000000000000000000000000"}, + }; + + unsigned char buff[32]; + bignum256modm a={0}, b={0}; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + expand256_modm(a, fromhex(tests[i][0]), 32); + neg256_modm(b, a); + contract256_modm((unsigned char *) buff, b); + ck_assert_mem_eq(buff, fromhex(tests[i][1]), 32); + } +} +END_TEST + +START_TEST(test_ed25519_modl_sub) +{ + char tests[][3][65] = { + {"0000000000000000000000000000000000000000000000000000000000000000", + "0000000000000000000000000000000000000000000000000000000000000000", + "0000000000000000000000000000000000000000000000000000000000000000", + }, + + {"eef80ad5a9aad8b35b84f6a4eb3a7e2b222f403d455d8cdf40ad27e4cd5ae90a", + "53732f60e51ee3a48d21d2d526548c0dadbb79a185678fd7710613d0e76aad0c", + "8859d1d1deee0767a4ff1b72a3e0d0327573c69bbff5fc07cfa61414e6ef3b0e" + }, + + {"eef80ad5a9aad8b35b84f6a4eb3a7e2b222f403d455d8cdf40ad27e4cd5ae90a", + "0000000000000000000000000000000000000000000000000000000000000000", + "eef80ad5a9aad8b35b84f6a4eb3a7e2b222f403d455d8cdf40ad27e4cd5ae90a" + }, + + {"0000000000000000000000000000000000000000000000000000000000000000", + "39897fbebf137a34572b014b0638ac0186d17874e3cc142ebdfe24327f5b8509", + "b44a769e5a4f98237f71f657d8c132137a2e878b1c33ebd14201dbcd80a47a06" + }, + + {"0200000000000000000000000000000000000000000000000000000000000000", + "e3d3f55c1a631258d69cf7a2def9de1400000000000000000000000000000010", + "0c00000000000000000000000000000000000000000000000000000000000000" + }, + + {"e3d3f55c1a631258d69cf7a2def9de1400000000000000000000000000000010", + "0800000000000000000000000000000000000000000000000000000000000000", + "dbd3f55c1a631258d69cf7a2def9de1400000000000000000000000000000010" + }, + }; + + unsigned char buff[32]; + bignum256modm a={0}, b={0}, c={0}; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + expand256_modm(a, fromhex(tests[i][0]), 32); + expand256_modm(b, fromhex(tests[i][1]), 32); + sub256_modm(c, a, b); + contract256_modm(buff, c); + ck_assert_mem_eq(buff, fromhex(tests[i][2]), 32); + } +} +END_TEST + static void test_bip32_ecdh_init_node(HDNode *node, const char *seed_str, const char *curve_name) { hdnode_from_seed((const uint8_t *)seed_str, strlen(seed_str), curve_name, node); hdnode_fill_public_key(node); @@ -4602,6 +4731,12 @@ Suite *test_suite(void) tcase_add_test(tc, test_ed25519_cosi); suite_add_tcase(s, tc); + tc = tcase_create("ed25519_modm"); + tcase_add_test(tc, test_ed25519_modl_add); + tcase_add_test(tc, test_ed25519_modl_neg); + tcase_add_test(tc, test_ed25519_modl_sub); + suite_add_tcase(s, tc); + tc = tcase_create("script"); tcase_add_test(tc, test_output_script); suite_add_tcase(s, tc); From 60805d00010bb6966da2ee87e6216e8bbc0ffd66 Mon Sep 17 00:00:00 2001 From: Dusan Klinec Date: Sat, 28 Apr 2018 17:25:24 +0200 Subject: [PATCH 555/627] ed25519-donna/modm: sub more effective - using trick: https://www.imperialviolet.org/2010/12/04/ecc.html --- ed25519-donna/modm-donna-32bit.c | 19 ++++++++-- tests/test_check.c | 60 ++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 3 deletions(-) diff --git a/ed25519-donna/modm-donna-32bit.c b/ed25519-donna/modm-donna-32bit.c index 0b4ad74ff..f658c4308 100644 --- a/ed25519-donna/modm-donna-32bit.c +++ b/ed25519-donna/modm-donna-32bit.c @@ -169,11 +169,24 @@ void neg256_modm(bignum256modm r, const bignum256modm x) { reduce256_modm(r); } +/* consts for subtraction, > p */ +/* Emilia Kasper trick, https://www.imperialviolet.org/2010/12/04/ecc.html */ +static const uint32_t twoP[] = { + 0x5cf5d3ed, 0x60498c68, 0x6f79cd64, 0x77be77a7, 0x40000013, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0xfff}; + /* subtraction x-y % m */ void sub256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y) { - bignum256modm negy; - neg256_modm(negy, y); - add256_modm(r, x, negy); + bignum256modm_element_t c = 0; + c = twoP[0] + x[0] - y[0]; r[0] = c & 0x3fffffff; c >>= 30; + c += twoP[1] + x[1] - y[1]; r[1] = c & 0x3fffffff; c >>= 30; + c += twoP[2] + x[2] - y[2]; r[2] = c & 0x3fffffff; c >>= 30; + c += twoP[3] + x[3] - y[3]; r[3] = c & 0x3fffffff; c >>= 30; + c += twoP[4] + x[4] - y[4]; r[4] = c & 0x3fffffff; c >>= 30; + c += twoP[5] + x[5] - y[5]; r[5] = c & 0x3fffffff; c >>= 30; + c += twoP[6] + x[6] - y[6]; r[6] = c & 0x3fffffff; c >>= 30; + c += twoP[7] + x[7] - y[7]; r[7] = c & 0x3fffffff; c >>= 30; + c += twoP[8] + x[8] - y[8]; r[8] = c; + reduce256_modm(r); } /* multiplication modulo m */ diff --git a/tests/test_check.c b/tests/test_check.c index 3038809b2..527c4977e 100644 --- a/tests/test_check.c +++ b/tests/test_check.c @@ -3472,6 +3472,11 @@ START_TEST(test_ed25519_modl_sub) "8859d1d1deee0767a4ff1b72a3e0d0327573c69bbff5fc07cfa61414e6ef3b0e" }, + {"9d91e26dbe7a14fdca9f5b20d13e828dc8c1ffe03fe90136a6bba507436ce500", + "9ca406705ccce65eb8cbf63706d3df09fcc67216c0dc3990270731aacbb2e607", + "eec0d15a7c1140f6e8705c8ba9658198ccfa8cca7f0cc8a57eb4745d77b9fe08" + }, + {"eef80ad5a9aad8b35b84f6a4eb3a7e2b222f403d455d8cdf40ad27e4cd5ae90a", "0000000000000000000000000000000000000000000000000000000000000000", "eef80ad5a9aad8b35b84f6a4eb3a7e2b222f403d455d8cdf40ad27e4cd5ae90a" @@ -3491,6 +3496,61 @@ START_TEST(test_ed25519_modl_sub) "0800000000000000000000000000000000000000000000000000000000000000", "dbd3f55c1a631258d69cf7a2def9de1400000000000000000000000000000010" }, + + {"ecd3f55c1a631258d69cf7a2def9de1400000000000000000000000000000010", + "0000000000000000000000000000000000000000000000000000000000000000", + "ecd3f55c1a631258d69cf7a2def9de1400000000000000000000000000000010" + }, + + {"0000000000000000000000000000000000000000000000000000000000000000", + "ecd3f55c1a631258d69cf7a2def9de1400000000000000000000000000000010", + "0100000000000000000000000000000000000000000000000000000000000000" + }, + + {"0000000000000000000000000000000000000000000000000000000000000000", + "0000000000000000000000000000000000000000000000000000000000000010", + "edd3f55c1a631258d69cf7a2def9de1400000000000000000000000000000000" + }, + + {"0000000000000000000000000000000000000000000000000000000000000000", + "ffffff3f00000000000000000000000000000000000000000000000000000010", + "eed3f51c1a631258d69cf7a2def9de1400000000000000000000000000000000" + }, + + {"0000000000000000000000000000000000000000000000000000000000000000", + "edd3f55c1a631258d69cf7a2def9de1400000000000000000000000000000000", + "0000000000000000000000000000000000000000000000000000000000000010" + }, + + {"0000000000000000000000000000000000000000000000000000000000000000", + "e75f947f11d49d25a137fac8757538a980dec23811235cf63c48ee6bc6e4ed03", + "067461dd088f74323565fdd96884a66b7f213dc7eedca309c3b71194391b120c" + }, + + {"0000000000000000000000000000000000000000000000000000000000000000", + "ecd3f55c1a631258d69cf7a2def9de140000000000000000000000000000ff0f", + "0100000000000000000000000000000000000000000000000000000000000100" + }, + + {"0000000000000000000000000000000000000000000000000000000000000000", + "edd3f55c1a631258d69cf7a2def9de140000000000000000000004000000ff0f", + "0000000000000000000000000000000000000000000000000000fcffffff0000" + }, + + {"0000000000000000000000000000000000000000000000000000000000000000", + "edd3f55c1a631258d69cf7a2def9de150000c0ffffffffffffffffffffffff0f", + "000000000000000000000000000000ffffff3f00000000000000000000000000" + }, + + {"0000000000000000000000000000000000000000000000000000000000000000", + "edd3f55c1a631258d69cf7a2def9de1200000000000000000000000000000110", + "edd3f55c1a631258d69cf7a2def9de160000000000000000000000000000ff0f" + }, + + {"0000000000000000000000000000000000000000000000000000000000000000", + "edd3f55c1a631258d69cf7a2def9de1300000000000000000000000000000010", + "0000000000000000000000000000000100000000000000000000000000000000" + }, }; unsigned char buff[32]; From 10788a82a11472428e1dae8e4e8d2b92d2edd8ad Mon Sep 17 00:00:00 2001 From: Dusan Klinec Date: Wed, 16 May 2018 02:12:17 +0200 Subject: [PATCH 556/627] ed25519: aA + bB double scalarmult added - required for monero --- Makefile | 1 + ed25519-donna/ed25519-donna-impl-base.c | 47 +++++++++++++++++++++++++ ed25519-donna/ed25519-donna-impl-base.h | 5 +++ options.h | 5 +++ 4 files changed, 58 insertions(+) diff --git a/Makefile b/Makefile index b8f63417f..8be364f6b 100644 --- a/Makefile +++ b/Makefile @@ -27,6 +27,7 @@ CFLAGS += -I. CFLAGS += -DUSE_ETHEREUM=1 CFLAGS += -DUSE_GRAPHENE=1 CFLAGS += -DUSE_NEM=1 +CFLAGS += -DUSE_MONERO=1 CFLAGS += $(shell pkg-config --cflags openssl) # disable certain optimizations and features when small footprint is required diff --git a/ed25519-donna/ed25519-donna-impl-base.c b/ed25519-donna/ed25519-donna-impl-base.c index 28ac75819..eb50a2bad 100644 --- a/ed25519-donna/ed25519-donna-impl-base.c +++ b/ed25519-donna/ed25519-donna-impl-base.c @@ -285,6 +285,53 @@ void ge25519_double_scalarmult_vartime(ge25519 *r, const ge25519 *p1, const bign } } +/* computes [s1]p1 + [s2]p2 */ +#if USE_MONERO +void ge25519_double_scalarmult_vartime2(ge25519 *r, const ge25519 *p1, const bignum256modm s1, const ge25519 *p2, const bignum256modm s2) { + signed char slide1[256], slide2[256]; + ge25519_pniels pre1[S1_TABLE_SIZE]; + ge25519_pniels pre2[S1_TABLE_SIZE]; + ge25519 dp; + ge25519_p1p1 t; + int32_t i; + + contract256_slidingwindow_modm(slide1, s1, S1_SWINDOWSIZE); + contract256_slidingwindow_modm(slide2, s2, S1_SWINDOWSIZE); + + ge25519_double(&dp, p1); + ge25519_full_to_pniels(pre1, p1); + for (i = 0; i < S1_TABLE_SIZE - 1; i++) + ge25519_pnielsadd(&pre1[i+1], &dp, &pre1[i]); + + ge25519_double(&dp, p2); + ge25519_full_to_pniels(pre2, p2); + for (i = 0; i < S1_TABLE_SIZE - 1; i++) + ge25519_pnielsadd(&pre2[i+1], &dp, &pre2[i]); + + ge25519_set_neutral(r); + + i = 255; + while ((i >= 0) && !(slide1[i] | slide2[i])) + i--; + + for (; i >= 0; i--) { + ge25519_double_p1p1(&t, r); + + if (slide1[i]) { + ge25519_p1p1_to_full(r, &t); + ge25519_pnielsadd_p1p1(&t, r, &pre1[abs(slide1[i]) / 2], (unsigned char)slide1[i] >> 7); + } + + if (slide2[i]) { + ge25519_p1p1_to_full(r, &t); + ge25519_pnielsadd_p1p1(&t, r, &pre2[abs(slide2[i]) / 2], (unsigned char)slide2[i] >> 7); + } + + ge25519_p1p1_to_partial(r, &t); + } +} +#endif + /* * The following conditional move stuff uses conditional moves. * I will check on which compilers this works, and provide suitable diff --git a/ed25519-donna/ed25519-donna-impl-base.h b/ed25519-donna/ed25519-donna-impl-base.h index 559c837d7..d5edf95a0 100644 --- a/ed25519-donna/ed25519-donna-impl-base.h +++ b/ed25519-donna/ed25519-donna-impl-base.h @@ -23,6 +23,11 @@ void ge25519_double_p1p1(ge25519_p1p1 *r, const ge25519 *p); void ge25519_nielsadd2_p1p1(ge25519_p1p1 *r, const ge25519 *p, const ge25519_niels *q, unsigned char signbit); #endif +/* computes [s1]p1 + [s2]p2 */ +#if USE_MONERO +void ge25519_double_scalarmult_vartime2(ge25519 *r, const ge25519 *p1, const bignum256modm s1, const ge25519 *p2, const bignum256modm s2); +#endif + void ge25519_pnielsadd_p1p1(ge25519_p1p1 *r, const ge25519 *p, const ge25519_pniels *q, unsigned char signbit); void ge25519_double_partial(ge25519 *r, const ge25519 *p); diff --git a/options.h b/options.h index e0659cc22..e30997c82 100644 --- a/options.h +++ b/options.h @@ -76,6 +76,11 @@ #define USE_NEM 0 #endif +// support MONERO operations +#ifndef USE_MONERO +#define USE_MONERO 0 +#endif + // support Keccak hashing #ifndef USE_KECCAK #define USE_KECCAK 1 From 28d12252769e88482d3c2afdfb208f537d694091 Mon Sep 17 00:00:00 2001 From: Dusan Klinec Date: Fri, 18 May 2018 18:55:10 +0200 Subject: [PATCH 557/627] tests: test for ge25519_double_scalarmult_vartime2 added --- tests/test_check.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/tests/test_check.c b/tests/test_check.c index 527c4977e..388aec337 100644 --- a/tests/test_check.c +++ b/tests/test_check.c @@ -3566,6 +3566,47 @@ START_TEST(test_ed25519_modl_sub) } END_TEST +START_TEST(test_ge25519_double_scalarmult_vartime2) +{ + char tests[][5][65] = { + {"c537208ed4985e66e9f7a35c9a69448a732ba93960bbbd2823604f7ae9e3ed08", "365233e5af17c8888d5ce508787464f4642e91a6212b1b104e6c3769535601b1", "a84f871580176708b4ac21843cb197ad96e8456034442b50859c83c5807b9901", "f022360d1bce903fa3ac58ae42f997328b31f477b8d576a9f6d26fc1d08f14ea", "bf25da82c6b210948b823ae48422a2dcd205d3c94842e68ac27e5cbeaa704ebc"}, + {"4abfabc0dda33588a98127ef3bfe724fed286395fe15932e898b5621661ea102", "e5fd79d03f5df8edfc8def663dcb96bba6cadf857f2ae6f6f51f52f8d14079b7", "4754c286b23e3c1b50054fe3937ebdc4ec01b28da5d05fb6111798b42fc5bf06", "b7e7f9464b98de5bfcf6b02c1b7053cc359df407ad59d943523c6d2ee773b2f6", "6d7d5f729bfa4882dbff8e477cd2b4c354ba347f10e7b178a24f3f16a4e0fec6"}, + {"19f2af4d04cb8181f1fe0d01fe9bb9ecc476c67ceb4a9830dae1bc7fe5fe3b04", "d3c462f4f30991220387a1fbbd1ba1dc45ce058c70a8fb1475071e7b4f0fc463", "577790e025c1fd2014db44a8d613c4e2ab1f248a4a6d14b5d39cbbafd7b20f06", "1376c6837f131f6cd1a45b1056297d2314aa0ac5f7d581d2d878261eb3259b4d", "ce790760ada87dd819b59e4f6765d836d346567ec34f02bbcfcae0585c1d758f"}, + {"cf209db9e7ee85f1e648924ec97edd86b56a833b25707519d4fbe64fd50e150a", "804f0806087dc665a26230ed5fd44c062980ee182a6bd7dbdb33df018c983778", "30d3c448cb08935309753b3051366f52328ca1d9a0b63c72b989edee0da32b0e", "98e3c973a7e85b5eab8111521c66ca584bed5597f060ab0c6b5cdeece502ac48", "2646276e1305396a1b2473690066011a39789570a09e10ce1a013c8f32cd5bea"}, + {"b0a0ffeea67b656c4c585ba58ff528a6f45d2f915db98e4a14a8ff17f27fc105", "4fabe16274f6af526ee053028485db6acd13804e02dcdddccc4183a319ab9e1c", "1e140bb08a936ac6b7437644ca0769f3c165c7aa5501d49f064a0346179b4008", "68fc1be64fb68761542a655b8dbebf50980f1fbc1845528df8d8a06bf89a1495", "7dab86994b47014efe38493fc2b62ffcead806da6e0d73c992db8cb5618a19dc"}, + {"0fee422c2294b06ca83bc3704384dffc580e7ff5921881e51a755e5f9b80af03", "4359a663ead3f7ffc3a0ead5c3c2bde348017e7bfa620f21759c32e469a16dfe", "532066e3eec29334fffc37b17178dfbac3bee15f7845f01449ddbaf5e57a7b0c", "32e46c2fb99402837631c8175db31cdd334c145f922be9070d62e6d9c493c3ea", "8c7b7d2d61cdb648960434d894787426a76d16dd46949c7aa4b85dcf1054b4d5"}, + {"3a712d5b7ceb5257dcf6e6bb06548de6ef3deba5d456cd91fc305a12b46b5d01", "5e7da62e3ec42cf3e554639dd4d2006754ee6839b720cadba94a26b73b1665ee", "2a518ecab17a2d9dde219c775bcf4f2306b190bef2dea34fb65b8e4dccc13405", "3b5d66a4dfb068923b3bc21cc8b40b59e12f845e0b85a86d394db0fa310bf185", "2ec17f1cc0be093e9cdb741a991c0f417230dea275cd7babdad35e949e250521"}, + {"5f815f2d65cef584c5e5d48b2d3d3e4cae310d70b328f88af6e9f63c52b4c90d", "8a539a8c6b2339922b31cf4bc064f1fedeb3912fd89585d79dfcff2a60aee295", "385f7132b72db04146b9e472736b32adfca29556b4775a743c18e2bfab939007", "884aaf96d625968ddb2582922a87abca131272884c47f6b86890ebccf0a79d5b", "a7afdaf24fe8472d8b89e95c3ce4a40bdf700af7cedee44ed3aa5ccca09839bd"}, + {"a043340d072df16a8ab5135f8c1d601bff14c5aba01b9212b886ad71fe164506", "52f6de5fa0fae32d4020a54d395319509d6b92092a0bf849fb34e73f8e71fc99", "37d7472d360164da29e6dcb8f9796976022571c5df4ddf7e30e9a579ba13d509", "8c369e3fd5b1112e4437b1f09e987acca4966f2f8c5227eb15ace240a2c64cc7", "fc795fe7baff5c3ac98366e6882f25874ea2b0a649d16f139e5c54ea47042a1e"}, + {"97a3268db03fa184c8cba020bf216fc789292fa9615a28962385b86870ffd70f", "a76c215587022bb9252ece4c5afeb0e65b820834cd41ac76e6c062d3eea75dc6", "8310271017154cbddf7005e24eb9a9a86777b3f42fa5e35095eafaac4eb24802", "b822665c2406083c851ecaa91ea67aa740c057e7679b5755cee60a6c63f17fd6", "f83e2444527056eba595d49bde40b2e8da76d2c145f203331d26e94560993fbc"}, + {"edaad13efad39f26298e86ba8d06a46e59122232c9529bd22f2f656595421e00", "f38e56a79f5159eb3b581dea537ec12c9c6fac381b2cf6073e27fc621197cb62", "1eea79485954b5958d9d5478f86133af1088806d923535d483b115ab23099a0f", "b32c5e57d57db7a349f4ab845f12a5045c52b4a7a5bce7fd54a1a255b0118185", "3bfb42b4ffd2c6cfc8cce9e4187dc6fbcaecd9d44a4ca1d2b68b97410bb25b81"}, + {"b15eaebe0fc83cb11d755a6f067b710204d4a59101078d8286454b652879080a", "4667a2e61d9df1690f5c33c4168e480f7e26d2f0998168ebdc0a39712946f741", "125379da1a88bfdf5b928f8795d3ea5415ef8c3d9106eb16934c3842873fd707", "8727a692a25e38b1afa98e3dd5bf88815dec6d9810c1fd8a31b56b3de8630f1e", "540883dde400b909e9955a276c20e13d99252ebe542750b8bfbbe5c3b87c51e3"}, + {"e42bdd4af3121bea644a90a76b2007615621ee5b842b9a74c4334ac309478706", "6dc4ab715d3bb975ebfd0f08e2b6f3f39922d0121ae518a8f8d2952ea2fe0b5d", "0285059b0095c97f4a50d43c7726c64c2830bf2b55dfa934ebba7ad71064dc07", "f738c0a3cee31fd8f438f282aa6c823fccfa49cf7b5c86fbf9d56bf0394b6d8d", "a1bd106841e55010decd95a170a1d0dd11780fd00759819e024b15ea3a83b4be"}, + {"5077c30fd08795dbdc7a230c050ca07e316fa3b040fd0dac45907036ab25dd0e", "96f0897f000e49e2439a9166cab40ebc125a31b82851f0541516c19683e7bfaf", "2b67d79a2efdc6451508e7f3c97c4a61b135bb839c02338bb444ef8208dd970b", "7ef4cd7cdc29c2b88ccff49898b5d0b7be5993f93c5772476feec9dc57d7b6e3", "62449b901b25760c964704b28efc184fbd5947e83851ebaf3bbfeb6f742f679f"}, + {"a4b3ce6928fe8f77d13e65ae255eee8310ab0d75bca47028b4570f0511a66006", "4e9da8d77ee337e3bcce3730ccfff2121728641c7bb4fdeb2155890f998af09a", "ff01a5075569d0f6afee45da065c72f5841f46ce772917ef75eb4d230473580f", "36ca32da8a10f4083f5a60ee21868d9d448548d49c56f19cbe6005005e34f816", "99df362a3b762cc1cbb70bc5ddff3c8614ed306037013102e387ef32e7f2494f"}, + {"074aa76351dceb752aa09887d9aca932d5821f58eedb4988fd64d8548e3f2c09", "588b4552f3b98b2f77aee2ef8cc72f88acd424c4373b3e3626393ed2ea24cbda", "f2d9175633f2e3c661b01172b4b4176850cd5b3098ffb0f927e0a5e19c1c8a02", "a6c34868736b2517fd46f57a4e30805ffd475e44a8b1413078f43d9cb3d6edd6", "46e1e7d7b1e939dd5c07c8363af01f4f9dae7c3d10f237ff9776ddc4a1903771"}, + {"ae1c8abd5a542208ee0aa93ffbf0b8e5a957edc4854fe2b48153c5c85bbf3d08", "5e084b9541a70bd5bef400be6525c5a806a5b7fb12de38b07dcd35a22c57edbe", "d95f179a215fb322d81720bf3aecde78d6d676d6f941455d0e0920f1e3619707", "c3e5d43221824de51d8f95705de69c80a2440c0483ca88549d639aee15390429", "df9fea42d3b5ac243244abb4ca4948a69493becddc5d5906f9a4e4c5645b0eab"}, + {"2f1c5adedb7341dc7638bafacc6024bd48255197ea2347fc05714b9341dd4403", "47f55263001542f796c928988f641f59d0cd43294fc8d8616b184bfe9dddf368", "aa5e884e782ab116151c609680c37b1a49b52f23bce5e2ebf28dd8532510d20b", "ef2d6d97ad1a18edfce6450c1e70295b2c7ed2bc749ea8b438a523eae078d1f3", "2396a355c6ae8e2ac24da8f55a674c96fc4cc69b38678b2bd8eb91b96f462bca"}, + {"0242e14105ced74e91cf4d4dcd22a9c09279018901d2fb8319eb54c2a1c4900a", "fcb62a6c520d31fa46efeb4a1000330653b3402f575c2ddc0c688f527e7b97be", "73a7e2e0602e5345f040dedc4db67f6d8e37c5fca3bbb124fa43963d76dbbb08", "152bf4a3305c656f77e292b1256cc470da4d3f6efc3667199db4316d7f431174", "c21ba2080013dfb225e06378d9ac27df623df552526cfddbf9e71bb1d4705dd9"}, + {"07fab4fc7b02fbcf868ffb0326cf60425fef2af1fbad83a8926cc62c2b5dff05", "29ff12c5e052eb5829e8334e0e082c5edde1f293d2b4ed499a79bcca20e48010", "97afb3dd9167877b432a23503aad1ab39188b9be07cc124ceb3fbdbd8d8b890a", "ed121240a2f4591eeedbfd880305ccd17e522673900b03279fb66e73583514ae", "b27f209e88ce5701766565e231e8123adb1df9c9f1dc461920acbc2b38d9f6d7"}, + }; + + unsigned char buff[32]; + bignum256modm a={0}, b={0}; + ge25519 A, B, R; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + expand256_modm(a, fromhex(tests[i][0]), 32); + expand256_modm(b, fromhex(tests[i][2]), 32); + ge25519_unpack_negative_vartime(&A, fromhex(tests[i][1])); curve25519_neg(A.x, A.x); curve25519_neg(A.t, A.t); + ge25519_unpack_negative_vartime(&B, fromhex(tests[i][3])); curve25519_neg(B.x, B.x); curve25519_neg(B.t, B.t); + ge25519_double_scalarmult_vartime2(&R, &A, a, &B, b); + ge25519_pack(buff, &R); + ck_assert_mem_eq(buff, fromhex(tests[i][4]), 32); + } +} +END_TEST + static void test_bip32_ecdh_init_node(HDNode *node, const char *seed_str, const char *curve_name) { hdnode_from_seed((const uint8_t *)seed_str, strlen(seed_str), curve_name, node); hdnode_fill_public_key(node); @@ -4797,6 +4838,10 @@ Suite *test_suite(void) tcase_add_test(tc, test_ed25519_modl_sub); suite_add_tcase(s, tc); + tc = tcase_create("ed25519_ge"); + tcase_add_test(tc, test_ge25519_double_scalarmult_vartime2); + suite_add_tcase(s, tc); + tc = tcase_create("script"); tcase_add_test(tc, test_output_script); suite_add_tcase(s, tc); From 1a7483d43d43dfcc3adea0a16c73749f4180197a Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 22 May 2018 16:55:22 +0200 Subject: [PATCH 558/627] cashaddr: fix whitespace --- cash_addr.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/cash_addr.c b/cash_addr.c index 48fa912f2..0e6922c00 100644 --- a/cash_addr.c +++ b/cash_addr.c @@ -62,13 +62,13 @@ int cash_encode(char *output, const char *hrp, const uint8_t *data, size_t data_ if (ch < 33 || ch > 126) { return 0; } - *(output++) = ch; + *(output++) = ch; chk = cashaddr_polymod_step(chk) ^ (ch & 0x1f); ++i; } - if (i + 1 + data_len + CHECKSUM_SIZE > MAX_CASHADDR_SIZE) { - return 0; - } + if (i + 1 + data_len + CHECKSUM_SIZE > MAX_CASHADDR_SIZE) { + return 0; + } chk = cashaddr_polymod_step(chk); *(output++) = ':'; for (i = 0; i < data_len; ++i) { @@ -102,10 +102,10 @@ int cash_decode(char* hrp, uint8_t *data, size_t *data_len, const char *input) { } hrp_len = input_len - (1 + *data_len); if (hrp_len < 1 || hrp_len > MAX_HRP_SIZE || - *data_len < CHECKSUM_SIZE || *data_len > CHECKSUM_SIZE + MAX_BASE32_SIZE) { + *data_len < CHECKSUM_SIZE || *data_len > CHECKSUM_SIZE + MAX_BASE32_SIZE) { return 0; } - // subtract checksum + // subtract checksum *(data_len) -= CHECKSUM_SIZE; for (i = 0; i < hrp_len; ++i) { int ch = input[i]; From afbe3e75517f36c6f15117b9dcf41477459e65bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Vejpustek?= Date: Fri, 25 May 2018 14:39:45 +0200 Subject: [PATCH 559/627] fix rfc7539 padding --- chacha20poly1305/rfc7539.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/chacha20poly1305/rfc7539.c b/chacha20poly1305/rfc7539.c index 585a695d9..8aa3b8f0a 100644 --- a/chacha20poly1305/rfc7539.c +++ b/chacha20poly1305/rfc7539.c @@ -26,7 +26,8 @@ void rfc7539_init(chacha20poly1305_ctx *ctx, uint8_t key[32], uint8_t nonce[12]) void rfc7539_auth(chacha20poly1305_ctx *ctx, uint8_t *in, size_t n) { uint8_t padding[16] = {0}; poly1305_update(&ctx->poly1305, in, n); - poly1305_update(&ctx->poly1305, padding, 16 - n%16); + if (n % 16 != 0) + poly1305_update(&ctx->poly1305, padding, 16 - n%16); } // Compute RFC 7539-style Poly1305 MAC. @@ -37,7 +38,8 @@ void rfc7539_finish(chacha20poly1305_ctx *ctx, int64_t alen, int64_t plen, uint8 memcpy(lengths, &alen, sizeof(int64_t)); memcpy(lengths + 8, &plen, sizeof(int64_t)); - poly1305_update(&ctx->poly1305, padding, 16 - plen%16); + if (plen % 16 != 0) + poly1305_update(&ctx->poly1305, padding, 16 - plen%16); poly1305_update(&ctx->poly1305, lengths, 16); poly1305_finish(&ctx->poly1305, mac); From dba23617280ea75b434bbca4699abfd1524fdbe2 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 12 Jun 2018 19:04:28 +0200 Subject: [PATCH 560/627] add overwinter hashers --- hasher.c | 39 +++++++++++++++++++++++++++++---------- hasher.h | 7 +++++++ 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/hasher.c b/hasher.c index b8d0b919b..3d7eac309 100644 --- a/hasher.c +++ b/hasher.c @@ -37,6 +37,18 @@ void hasher_Init(Hasher *hasher, HasherType type) { case HASHER_GROESTLD_TRUNC: groestl512_Init(&hasher->ctx.groestl); break; + case HASHER_OVERWINTER_PREVOUTS: + blake2b_InitKey(&hasher->ctx.blake2b, 32, "ZcashPrevoutHash", 16); + break; + case HASHER_OVERWINTER_SEQUENCE: + blake2b_InitKey(&hasher->ctx.blake2b, 32, "ZcashSequencHash", 16); + break; + case HASHER_OVERWINTER_OUTPUTS: + blake2b_InitKey(&hasher->ctx.blake2b, 32, "ZcashOutputsHash", 16); + break; + case HASHER_OVERWINTER_PREIMAGE: + blake2b_InitKey(&hasher->ctx.blake2b, 32, "ZcashSigHash\x19\x1b\xa8\x5b", 16); // BRANCH_ID = 0x5ba81b19 + break; } } @@ -57,32 +69,39 @@ void hasher_Update(Hasher *hasher, const uint8_t *data, size_t length) { case HASHER_GROESTLD_TRUNC: groestl512_Update(&hasher->ctx.groestl, data, length); break; + case HASHER_OVERWINTER_PREVOUTS: + case HASHER_OVERWINTER_SEQUENCE: + case HASHER_OVERWINTER_OUTPUTS: + case HASHER_OVERWINTER_PREIMAGE: + blake2b_Update(&hasher->ctx.blake2b, data, length); + break; } } void hasher_Final(Hasher *hasher, uint8_t hash[HASHER_DIGEST_LENGTH]) { switch (hasher->type) { case HASHER_SHA2: + sha256_Final(&hasher->ctx.sha2, hash); + break; case HASHER_SHA2D: sha256_Final(&hasher->ctx.sha2, hash); + hasher_Raw(HASHER_SHA2, hash, HASHER_DIGEST_LENGTH, hash); break; case HASHER_BLAKE: + blake256_Final(&hasher->ctx.blake, hash); + break; case HASHER_BLAKED: blake256_Final(&hasher->ctx.blake, hash); + hasher_Raw(HASHER_BLAKE, hash, HASHER_DIGEST_LENGTH, hash); break; case HASHER_GROESTLD_TRUNC: groestl512_DoubleTrunc(&hasher->ctx.groestl, hash); - return; - } - - switch (hasher->type) { - case HASHER_SHA2D: - hasher_Raw(HASHER_SHA2, hash, HASHER_DIGEST_LENGTH, hash); - break; - case HASHER_BLAKED: - hasher_Raw(HASHER_BLAKE, hash, HASHER_DIGEST_LENGTH, hash); break; - default: + case HASHER_OVERWINTER_PREVOUTS: + case HASHER_OVERWINTER_SEQUENCE: + case HASHER_OVERWINTER_OUTPUTS: + case HASHER_OVERWINTER_PREIMAGE: + blake2b_Final(&hasher->ctx.blake2b, hash, 32); break; } } diff --git a/hasher.h b/hasher.h index 673cf9fa7..3a561673c 100644 --- a/hasher.h +++ b/hasher.h @@ -29,6 +29,7 @@ #include "sha2.h" #include "blake256.h" #include "groestl.h" +#include "blake2b.h" #define HASHER_DIGEST_LENGTH 32 @@ -40,6 +41,11 @@ typedef enum { HASHER_BLAKED, HASHER_GROESTLD_TRUNC, /* Double Groestl512 hasher truncated to 256 bits */ + + HASHER_OVERWINTER_PREVOUTS, + HASHER_OVERWINTER_SEQUENCE, + HASHER_OVERWINTER_OUTPUTS, + HASHER_OVERWINTER_PREIMAGE, } HasherType; typedef struct { @@ -49,6 +55,7 @@ typedef struct { SHA256_CTX sha2; BLAKE256_CTX blake; GROESTL512_CTX groestl; + BLAKE2B_CTX blake2b; } ctx; } Hasher; From a4c1d028654284beeb80ce2f4cbd15221ac2a397 Mon Sep 17 00:00:00 2001 From: Karel Bilek Date: Thu, 14 Jun 2018 04:08:33 +0200 Subject: [PATCH 561/627] blake2b: Add init with personal key Necessary for zcash hashing --- blake2b.c | 20 ++++++++++++++++++++ blake2b.h | 1 + 2 files changed, 21 insertions(+) diff --git a/blake2b.c b/blake2b.c index 15df01190..26a2f9e08 100644 --- a/blake2b.c +++ b/blake2b.c @@ -131,6 +131,26 @@ int blake2b_Init( blake2b_state *S, size_t outlen ) return blake2b_init_param( S, P ); } +int blake2b_InitPersonal( blake2b_state *S, size_t outlen, const void *personal ) +{ + blake2b_param P[1]; + + if ( ( !outlen ) || ( outlen > BLAKE2B_OUTBYTES ) ) return -1; + + P->digest_length = (uint8_t)outlen; + P->key_length = 0; + P->fanout = 1; + P->depth = 1; + store32( &P->leaf_length, 0 ); + store32( &P->node_offset, 0 ); + store32( &P->xof_length, 0 ); + P->node_depth = 0; + P->inner_length = 0; + memset( P->reserved, 0, sizeof( P->reserved ) ); + memset( P->salt, 0, sizeof( P->salt ) ); + memcpy( P->personal, personal, BLAKE2B_PERSONALBYTES ); + return blake2b_init_param( S, P ); +} int blake2b_InitKey( blake2b_state *S, size_t outlen, const void *key, size_t keylen ) { diff --git a/blake2b.h b/blake2b.h index 772a5cfe4..1c067ee16 100644 --- a/blake2b.h +++ b/blake2b.h @@ -30,6 +30,7 @@ typedef struct __blake2b_state #define BLAKE2B_KEY_LENGTH BLAKE2B_KEYBYTES int blake2b_Init(blake2b_state *S, size_t outlen); +int blake2b_InitPersonal(blake2b_state *S, size_t outlen, const void *personal); int blake2b_InitKey(blake2b_state *S, size_t outlen, const void *key, size_t keylen); int blake2b_Update(blake2b_state *S, const void *pin, size_t inlen); int blake2b_Final(blake2b_state *S, void *out, size_t outlen); From 620902b9b365457926d51308d91f99be5ab9ea1a Mon Sep 17 00:00:00 2001 From: Karel Bilek Date: Thu, 14 Jun 2018 04:49:50 +0200 Subject: [PATCH 562/627] blake2b: Fix overwinter hashers --- hasher.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hasher.c b/hasher.c index 3d7eac309..c8cf93be7 100644 --- a/hasher.c +++ b/hasher.c @@ -38,16 +38,16 @@ void hasher_Init(Hasher *hasher, HasherType type) { groestl512_Init(&hasher->ctx.groestl); break; case HASHER_OVERWINTER_PREVOUTS: - blake2b_InitKey(&hasher->ctx.blake2b, 32, "ZcashPrevoutHash", 16); + blake2b_InitPersonal(&hasher->ctx.blake2b, 32, "ZcashPrevoutHash"); break; case HASHER_OVERWINTER_SEQUENCE: - blake2b_InitKey(&hasher->ctx.blake2b, 32, "ZcashSequencHash", 16); + blake2b_InitPersonal(&hasher->ctx.blake2b, 32, "ZcashSequencHash"); break; case HASHER_OVERWINTER_OUTPUTS: - blake2b_InitKey(&hasher->ctx.blake2b, 32, "ZcashOutputsHash", 16); + blake2b_InitPersonal(&hasher->ctx.blake2b, 32, "ZcashOutputsHash"); break; case HASHER_OVERWINTER_PREIMAGE: - blake2b_InitKey(&hasher->ctx.blake2b, 32, "ZcashSigHash\x19\x1b\xa8\x5b", 16); // BRANCH_ID = 0x5ba81b19 + blake2b_InitPersonal(&hasher->ctx.blake2b, 32, "ZcashSigHash\x19\x1b\xa8\x5b"); // BRANCH_ID = 0x5ba81b19 break; } } From 669acd7331fc02b6ef41c4a91112e6e6d6e831be Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 15 Jun 2018 10:19:10 +0200 Subject: [PATCH 563/627] blake2b: add personal_len to blake2b_InitPersonal --- blake2b.c | 3 ++- blake2b.h | 2 +- hasher.c | 8 ++++---- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/blake2b.c b/blake2b.c index 26a2f9e08..67d97e7e6 100644 --- a/blake2b.c +++ b/blake2b.c @@ -131,11 +131,12 @@ int blake2b_Init( blake2b_state *S, size_t outlen ) return blake2b_init_param( S, P ); } -int blake2b_InitPersonal( blake2b_state *S, size_t outlen, const void *personal ) +int blake2b_InitPersonal( blake2b_state *S, size_t outlen, const void *personal, size_t personal_len) { blake2b_param P[1]; if ( ( !outlen ) || ( outlen > BLAKE2B_OUTBYTES ) ) return -1; + if ( ( !personal ) || ( personal_len != BLAKE2B_PERSONALBYTES ) ) return -1; P->digest_length = (uint8_t)outlen; P->key_length = 0; diff --git a/blake2b.h b/blake2b.h index 1c067ee16..1b2656745 100644 --- a/blake2b.h +++ b/blake2b.h @@ -30,7 +30,7 @@ typedef struct __blake2b_state #define BLAKE2B_KEY_LENGTH BLAKE2B_KEYBYTES int blake2b_Init(blake2b_state *S, size_t outlen); -int blake2b_InitPersonal(blake2b_state *S, size_t outlen, const void *personal); +int blake2b_InitPersonal(blake2b_state *S, size_t outlen, const void *personal, size_t personal_len); int blake2b_InitKey(blake2b_state *S, size_t outlen, const void *key, size_t keylen); int blake2b_Update(blake2b_state *S, const void *pin, size_t inlen); int blake2b_Final(blake2b_state *S, void *out, size_t outlen); diff --git a/hasher.c b/hasher.c index c8cf93be7..a52eefdd3 100644 --- a/hasher.c +++ b/hasher.c @@ -38,16 +38,16 @@ void hasher_Init(Hasher *hasher, HasherType type) { groestl512_Init(&hasher->ctx.groestl); break; case HASHER_OVERWINTER_PREVOUTS: - blake2b_InitPersonal(&hasher->ctx.blake2b, 32, "ZcashPrevoutHash"); + blake2b_InitPersonal(&hasher->ctx.blake2b, 32, "ZcashPrevoutHash", 16); break; case HASHER_OVERWINTER_SEQUENCE: - blake2b_InitPersonal(&hasher->ctx.blake2b, 32, "ZcashSequencHash"); + blake2b_InitPersonal(&hasher->ctx.blake2b, 32, "ZcashSequencHash", 16); break; case HASHER_OVERWINTER_OUTPUTS: - blake2b_InitPersonal(&hasher->ctx.blake2b, 32, "ZcashOutputsHash"); + blake2b_InitPersonal(&hasher->ctx.blake2b, 32, "ZcashOutputsHash", 16); break; case HASHER_OVERWINTER_PREIMAGE: - blake2b_InitPersonal(&hasher->ctx.blake2b, 32, "ZcashSigHash\x19\x1b\xa8\x5b"); // BRANCH_ID = 0x5ba81b19 + blake2b_InitPersonal(&hasher->ctx.blake2b, 32, "ZcashSigHash\x19\x1b\xa8\x5b", 16); // BRANCH_ID = 0x5ba81b19 break; } } From c26867d6f2d75a3d5da85f8f9f4a40195525ad4d Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 19 Jun 2018 18:03:31 +0200 Subject: [PATCH 564/627] blake2s: add InitPersonal --- blake2b.h | 2 +- blake2s.c | 23 +++++++++++++++++++++++ blake2s.h | 1 + 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/blake2b.h b/blake2b.h index 1b2656745..1a43e92d1 100644 --- a/blake2b.h +++ b/blake2b.h @@ -30,8 +30,8 @@ typedef struct __blake2b_state #define BLAKE2B_KEY_LENGTH BLAKE2B_KEYBYTES int blake2b_Init(blake2b_state *S, size_t outlen); -int blake2b_InitPersonal(blake2b_state *S, size_t outlen, const void *personal, size_t personal_len); int blake2b_InitKey(blake2b_state *S, size_t outlen, const void *key, size_t keylen); +int blake2b_InitPersonal(blake2b_state *S, size_t outlen, const void *personal, size_t personal_len); int blake2b_Update(blake2b_state *S, const void *pin, size_t inlen); int blake2b_Final(blake2b_state *S, void *out, size_t outlen); diff --git a/blake2s.c b/blake2s.c index 636479b9b..57435e7a1 100644 --- a/blake2s.c +++ b/blake2s.c @@ -126,6 +126,29 @@ int blake2s_Init( blake2s_state *S, size_t outlen ) return blake2s_init_param( S, P ); } +int blake2s_InitPersonal( blake2s_state *S, size_t outlen, const void *personal, size_t personal_len) +{ + blake2s_param P[1]; + + if ( ( !outlen ) || ( outlen > BLAKE2S_OUTBYTES ) ) return -1; + if ( ( !personal ) || ( personal_len != BLAKE2S_PERSONALBYTES ) ) return -1; + + P->digest_length = (uint8_t)outlen; + P->key_length = 0; + P->fanout = 1; + P->depth = 1; + store32( &P->leaf_length, 0 ); + store32( &P->node_offset, 0 ); + store16( &P->xof_length, 0 ); + P->node_depth = 0; + P->inner_length = 0; + /* memset(P->reserved, 0, sizeof(P->reserved) ); */ + memset( P->salt, 0, sizeof( P->salt ) ); + memcpy( P->personal, personal, BLAKE2S_PERSONALBYTES ); + return blake2s_init_param( S, P ); +} + + int blake2s_InitKey( blake2s_state *S, size_t outlen, const void *key, size_t keylen ) { blake2s_param P[1]; diff --git a/blake2s.h b/blake2s.h index dd34bf194..57991bc91 100644 --- a/blake2s.h +++ b/blake2s.h @@ -31,6 +31,7 @@ typedef struct __blake2s_state int blake2s_Init(blake2s_state *S, size_t outlen); int blake2s_InitKey(blake2s_state *S, size_t outlen, const void *key, size_t keylen); +int blake2s_InitPersonal(blake2s_state *S, size_t outlen, const void *personal, size_t personal_len); int blake2s_Update(blake2s_state *S, const void *pin, size_t inlen); int blake2s_Final(blake2s_state *S, void *out, size_t outlen); From f586155d808be7467e31da907b0106b4c31a0d1d Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Fri, 22 Jun 2018 00:33:26 +0200 Subject: [PATCH 565/627] Fix unaligned access in curve25519 Use only the safe conversion from uint8_t to uint32_t. Actually, the ARM gcc-compiler is good enough to detect this pattern. --- ed25519-donna/curve25519-donna-32bit.c | 33 ++++++++------------------ 1 file changed, 10 insertions(+), 23 deletions(-) diff --git a/ed25519-donna/curve25519-donna-32bit.c b/ed25519-donna/curve25519-donna-32bit.c index 2579c60d1..972f913e9 100644 --- a/ed25519-donna/curve25519-donna-32bit.c +++ b/ed25519-donna/curve25519-donna-32bit.c @@ -403,34 +403,21 @@ void curve25519_square_times(bignum25519 out, const bignum25519 in, int count) { /* Take a little-endian, 32-byte number and expand it into polynomial form */ void curve25519_expand(bignum25519 out, const unsigned char in[32]) { - const union { uint8_t b[2]; uint16_t s; } endian_check = {{1,0}}; uint32_t x0,x1,x2,x3,x4,x5,x6,x7; - if (endian_check.s == 1) { - /* Take care, this only works when in is aligned */ - x0 = *(uint32_t *)(in + 0); - x1 = *(uint32_t *)(in + 4); - x2 = *(uint32_t *)(in + 8); - x3 = *(uint32_t *)(in + 12); - x4 = *(uint32_t *)(in + 16); - x5 = *(uint32_t *)(in + 20); - x6 = *(uint32_t *)(in + 24); - x7 = *(uint32_t *)(in + 28); - } else { - #define F(s) \ + #define F(s) \ ((((uint32_t)in[s + 0]) ) | \ (((uint32_t)in[s + 1]) << 8) | \ (((uint32_t)in[s + 2]) << 16) | \ (((uint32_t)in[s + 3]) << 24)) - x0 = F(0); - x1 = F(4); - x2 = F(8); - x3 = F(12); - x4 = F(16); - x5 = F(20); - x6 = F(24); - x7 = F(28); - #undef F - } + x0 = F(0); + x1 = F(4); + x2 = F(8); + x3 = F(12); + x4 = F(16); + x5 = F(20); + x6 = F(24); + x7 = F(28); + #undef F out[0] = ( x0 ) & reduce_mask_26; out[1] = ((((uint64_t)x1 << 32) | x0) >> 26) & reduce_mask_25; From 4153e662b60a0d83c1be15150f18483a37e9092c Mon Sep 17 00:00:00 2001 From: Ilan Date: Tue, 19 Jun 2018 14:52:39 -0300 Subject: [PATCH 566/627] Implement RSKIP-60 checksum address encoding --- address.c | 18 ++++++++++++++++-- address.h | 2 +- tests/test_check.c | 44 +++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 60 insertions(+), 4 deletions(-) diff --git a/address.c b/address.c index 4d63f8ee3..3fa9f8927 100644 --- a/address.c +++ b/address.c @@ -22,6 +22,9 @@ */ #include "address.h" +#include +#include +#include "bignum.h" size_t address_prefix_bytes_len(uint32_t address_type) { @@ -56,7 +59,7 @@ bool address_check_prefix(const uint8_t *addr, uint32_t address_type) #if USE_ETHEREUM #include "sha3.h" -void ethereum_address_checksum(const uint8_t *addr, char *address) +void ethereum_address_checksum(const uint8_t *addr, char *address, bool rskip60, uint8_t chain_id) { const char *hex = "0123456789abcdef"; for (int i = 0; i < 20; i++) { @@ -64,8 +67,19 @@ void ethereum_address_checksum(const uint8_t *addr, char *address) address[i * 2 + 1] = hex[addr[i] & 0xF]; } address[40] = 0; + + SHA3_CTX ctx; uint8_t hash[32]; - keccak_256((const uint8_t *)address, 40, hash); + keccak_256_Init(&ctx); + if(rskip60) + { + char prefix[16]; + int prefix_size = bn_format_uint64(chain_id, NULL, "0x", 0, 0, false, prefix, sizeof(prefix)); + keccak_Update(&ctx, (const uint8_t *)prefix, prefix_size); + } + keccak_Update(&ctx, (const uint8_t *)address, 40); + keccak_Final(&ctx, hash); + for (int i = 0; i < 20; i++) { if (hash[i] & 0x80 && address[i * 2 ] >= 'a' && address[i * 2 ] <= 'f') { address[i * 2] -= 0x20; diff --git a/address.h b/address.h index 307cf8dc8..c70a1f28a 100644 --- a/address.h +++ b/address.h @@ -33,7 +33,7 @@ size_t address_prefix_bytes_len(uint32_t address_type); void address_write_prefix_bytes(uint32_t address_type, uint8_t *out); bool address_check_prefix(const uint8_t *addr, uint32_t address_type); #if USE_ETHEREUM -void ethereum_address_checksum(const uint8_t *addr, char *address); +void ethereum_address_checksum(const uint8_t *addr, char *address, bool rskip60, uint8_t chain_id); #endif #endif diff --git a/tests/test_check.c b/tests/test_check.c index 388aec337..7af2136f1 100644 --- a/tests/test_check.c +++ b/tests/test_check.c @@ -3802,7 +3802,45 @@ START_TEST(test_ethereum_address) const char **vec = vectors; while (*vec) { memcpy(addr, fromhex(*vec), 20); - ethereum_address_checksum(addr, address); + ethereum_address_checksum(addr, address, false, 1); + ck_assert_str_eq(address, *vec); + vec++; + } +} +END_TEST + +// test vectors from https://github.com/rsksmart/RSKIPs/blob/master/IPs/RSKIP60.md +START_TEST(test_rsk_address) +{ + uint8_t addr[20]; + char address[41]; + + static const char *rskip60_chain30[] = { + "5aaEB6053f3e94c9b9a09f33669435E7ef1bEAeD", + "Fb6916095cA1Df60bb79ce92cE3EA74c37c5d359", + "DBF03B407c01E7CD3cBea99509D93F8Dddc8C6FB", + "D1220A0Cf47c7B9BE7a2e6ba89F429762E7B9adB", + 0 + }; + const char **vec = rskip60_chain30; + while (*vec) { + memcpy(addr, fromhex(*vec), 20); + ethereum_address_checksum(addr, address, true, 30); + ck_assert_str_eq(address, *vec); + vec++; + } + + static const char *rskip60_chain31[] = { + "5aAeb6053F3e94c9b9A09F33669435E7EF1BEaEd", + "Fb6916095CA1dF60bb79CE92ce3Ea74C37c5D359", + "dbF03B407C01E7cd3cbEa99509D93f8dDDc8C6fB", + "d1220a0CF47c7B9Be7A2E6Ba89f429762E7b9adB", + 0 + }; + vec = rskip60_chain31; + while (*vec) { + memcpy(addr, fromhex(*vec), 20); + ethereum_address_checksum(addr, address, true, 31); ck_assert_str_eq(address, *vec); vec++; } @@ -4744,6 +4782,10 @@ Suite *test_suite(void) tcase_add_test(tc, test_ethereum_address); suite_add_tcase(s, tc); + tc = tcase_create("rsk_address"); + tcase_add_test(tc, test_rsk_address); + suite_add_tcase(s, tc); + tc = tcase_create("wif"); tcase_add_test(tc, test_wif); suite_add_tcase(s, tc); From 3e8974ff8871263a70b7fbb9a27a1da5b0d810f7 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 27 Jun 2018 16:53:18 +0200 Subject: [PATCH 567/627] address: fix ethereum address computation, chain_id is uint32 --- address.c | 7 ++----- address.h | 2 +- tests/test_check.c | 2 +- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/address.c b/address.c index 3fa9f8927..c63b501ac 100644 --- a/address.c +++ b/address.c @@ -22,8 +22,6 @@ */ #include "address.h" -#include -#include #include "bignum.h" size_t address_prefix_bytes_len(uint32_t address_type) @@ -59,7 +57,7 @@ bool address_check_prefix(const uint8_t *addr, uint32_t address_type) #if USE_ETHEREUM #include "sha3.h" -void ethereum_address_checksum(const uint8_t *addr, char *address, bool rskip60, uint8_t chain_id) +void ethereum_address_checksum(const uint8_t *addr, char *address, bool rskip60, uint32_t chain_id) { const char *hex = "0123456789abcdef"; for (int i = 0; i < 20; i++) { @@ -71,8 +69,7 @@ void ethereum_address_checksum(const uint8_t *addr, char *address, bool rskip60, SHA3_CTX ctx; uint8_t hash[32]; keccak_256_Init(&ctx); - if(rskip60) - { + if (rskip60) { char prefix[16]; int prefix_size = bn_format_uint64(chain_id, NULL, "0x", 0, 0, false, prefix, sizeof(prefix)); keccak_Update(&ctx, (const uint8_t *)prefix, prefix_size); diff --git a/address.h b/address.h index c70a1f28a..7c5925e06 100644 --- a/address.h +++ b/address.h @@ -33,7 +33,7 @@ size_t address_prefix_bytes_len(uint32_t address_type); void address_write_prefix_bytes(uint32_t address_type, uint8_t *out); bool address_check_prefix(const uint8_t *addr, uint32_t address_type); #if USE_ETHEREUM -void ethereum_address_checksum(const uint8_t *addr, char *address, bool rskip60, uint8_t chain_id); +void ethereum_address_checksum(const uint8_t *addr, char *address, bool rskip60, uint32_t chain_id); #endif #endif diff --git a/tests/test_check.c b/tests/test_check.c index 7af2136f1..6be915998 100644 --- a/tests/test_check.c +++ b/tests/test_check.c @@ -3802,7 +3802,7 @@ START_TEST(test_ethereum_address) const char **vec = vectors; while (*vec) { memcpy(addr, fromhex(*vec), 20); - ethereum_address_checksum(addr, address, false, 1); + ethereum_address_checksum(addr, address, false, 0); ck_assert_str_eq(address, *vec); vec++; } From 18b109e2bd6790d8156b90f0ea3e8801b70edad5 Mon Sep 17 00:00:00 2001 From: jmuravsky Date: Tue, 19 Jun 2018 11:50:59 +0200 Subject: [PATCH 568/627] Add Cardano currency support --- Makefile | 1 + bip32.c | 220 ++++++++++++++++++++++++++++- bip32.h | 7 + bip39.c | 61 +++++++++ bip39.h | 2 + curves.c | 1 + curves.h | 1 + ed25519-donna/ed25519.c | 60 ++++++++ ed25519-donna/ed25519.h | 6 + tests/test_check.c | 296 ++++++++++++++++++++++++++++++++++++++++ 10 files changed, 651 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 8be364f6b..9bf421eca 100644 --- a/Makefile +++ b/Makefile @@ -28,6 +28,7 @@ CFLAGS += -DUSE_ETHEREUM=1 CFLAGS += -DUSE_GRAPHENE=1 CFLAGS += -DUSE_NEM=1 CFLAGS += -DUSE_MONERO=1 +CFLAGS += -DUSE_CARDANO=1 CFLAGS += $(shell pkg-config --cflags openssl) # disable certain optimizations and features when small footprint is required diff --git a/bip32.c b/bip32.c index aa044bf8e..b36ddde78 100644 --- a/bip32.c +++ b/bip32.c @@ -46,6 +46,11 @@ #if USE_NEM #include "nem.h" #endif +#if USE_CARDANO +#include "ed25519-donna/modm-donna-32bit.h" +#include "blake2b.h" +#include "bip39.h" +#endif #include "memzero.h" const curve_info ed25519_info = { @@ -57,6 +62,15 @@ const curve_info ed25519_info = { .hasher_pubkey = HASHER_SHA2, }; +const curve_info ed25519_cardano_info = { + .bip32_name = "ed25519 cardano seed", + .params = NULL, + .hasher_bip32 = HASHER_SHA2, + .hasher_base58 = HASHER_SHA2D, + .hasher_sign = HASHER_SHA2D, + .hasher_pubkey = HASHER_SHA2, +}; + const curve_info ed25519_sha3_info = { .bip32_name = "ed25519-sha3 seed", .params = NULL, @@ -100,6 +114,7 @@ int hdnode_from_xpub(uint32_t depth, uint32_t child_num, const uint8_t *chain_co out->child_num = child_num; memcpy(out->chain_code, chain_code, 32); memzero(out->private_key, 32); + memzero(out->private_key_extension,32); memcpy(out->public_key, public_key, 33); return 1; } @@ -133,6 +148,7 @@ int hdnode_from_xprv(uint32_t depth, uint32_t child_num, const uint8_t *chain_co memcpy(out->chain_code, chain_code, 32); memcpy(out->private_key, private_key, 32); memzero(out->public_key, sizeof(out->public_key)); + memzero(out->private_key_extension, sizeof(out->private_key_extension)); return 1; } @@ -252,6 +268,195 @@ int hdnode_private_ckd(HDNode *inout, uint32_t i) return 1; } +#ifdef USE_CARDANO +static void multiply8(uint8_t *dst, uint8_t *src, int bytes) +{ + int i; + uint8_t prev_acc = 0; + for (i = 0; i < bytes; i++) { + dst[i] = (src[i] << 3) + (prev_acc & 0x8); + prev_acc = src[i] >> 5; + } +} + +static void add_256bits(uint8_t *dst, uint8_t *src1, uint8_t *src2) +{ + int i; + for (i = 0; i < 32; i++) { + uint8_t a = src1[i]; + uint8_t b = src2[i]; + uint16_t r = a + b; + dst[i] = r & 0xff; + } +} + +int ed25519_scalar_add(const uint8_t *sk1, const uint8_t *sk2, uint8_t *res) +{ + bignum256modm s1, s2; + expand256_modm(s1, sk1, 32); + expand256_modm(s2, sk2, 32); + add256_modm(s1, s1, s2); + contract256_modm(res, s1); + return 0; +} + +int hdnode_private_ckd_cardano(HDNode *inout, uint32_t i) +{ + //checks for hardened/non-hardened derivation, keysize 32 means we are dealing with public key and thus non-h, keysize 64 is for private key + int keysize = 32; + if(i & 0x80000000){ + keysize = 64; + } + + static CONFIDENTIAL uint8_t data[1 + 64 + 4]; + static CONFIDENTIAL uint8_t I[32 + 32]; + static CONFIDENTIAL bignum256 a, b; + static CONFIDENTIAL uint8_t priv_key[64]; + static CONFIDENTIAL uint8_t res_key[64]; + + memcpy(priv_key, inout->private_key, 32); + memcpy(priv_key + 32, inout->private_key_extension, 32); + + if (keysize == 64) { // private derivation + data[0] = 0; + memcpy(data + 1, inout->private_key, 32); + memcpy(data + 1 + 32, inout->private_key_extension, 32); + } else { // public derivation + hdnode_fill_public_key(inout); + data[0] = 2; + memcpy(data + 1, inout->public_key + 1, 32); + } + write_be(data + keysize + 1, i); + + bn_read_be(priv_key, &a); + + static CONFIDENTIAL HMAC_SHA512_CTX ctx; + hmac_sha512_Init(&ctx, inout->chain_code, 32); + hmac_sha512_Update(&ctx, data, 1 + keysize + 4); + hmac_sha512_Final(&ctx, I); + + static CONFIDENTIAL uint8_t zl8[32]; + multiply8(zl8,I,32); + ed25519_scalar_add(zl8,priv_key,res_key); + add_256bits(res_key+32,I+32,priv_key+32); + memcpy(inout->private_key, res_key, 32); + memcpy(inout->private_key_extension, res_key + 32, 32); + + if(keysize == 64){ + data[0]=1; + }else{ + data[0]=3; + } + hmac_sha512_Init(&ctx, inout->chain_code, 32); + hmac_sha512_Update(&ctx, data, 1 + keysize + 4); + hmac_sha512_Final(&ctx, I); + + memcpy(inout->chain_code, I + 32, 32); + inout->depth++; + inout->child_num = i; + memzero(inout->public_key, sizeof(inout->public_key)); + + // making sure to wipe our memory + memzero(&a, sizeof(a)); + memzero(&b, sizeof(b)); + memzero(I, sizeof(I)); + memzero(data, sizeof(data)); + memzero(priv_key, sizeof(priv_key)); + memzero(res_key, sizeof(res_key)); + return 1; +} + +void decitoa(int val, char * out){ + + static char buf[32] = {0}; + + int i = 30; + + for(; val && i ; --i, val /= 10){ + buf[i] = "0123456789"[val % 10]; + } + + memcpy(out,&buf[i+1],strlen(&buf[i+1])+1); +} + +int hdnode_from_seed_cardano(uint8_t *seed, int seed_len, HDNode *out){ + uint8_t hash[32]; + uint8_t cbor[32+2]; + + if(seed_len < 24){ + // cbor encodes length directly into first byte if its smaller than 24 + seed[1] = 64 | seed_len; + blake2b(seed + 1, seed_len + 1, hash, 32); + }else{ + seed[0] = 88; + seed[1] = seed_len; + blake2b(seed, seed_len + 2, hash, 32); + } + + cbor[0] = 88; // 64 means its byte array, 24 means its length has 8 bits + cbor[1] = 32; // length of the byte array + memcpy(cbor + 2, hash, 32); + char salt[21]; + memcpy(salt, "Root Seed Chain xyzw", 16); + char c[21]; + uint8_t hmac[64]; + uint8_t secret[64]; + uint8_t public[32]; + uint8_t chain_code[32]; + int failed = 1; + memset(out, 0, sizeof(HDNode)); + out->depth = 0; + out->child_num = 0; + out->curve = get_curve_by_name(ED25519_CARDANO_NAME); + + static CONFIDENTIAL HMAC_SHA512_CTX ctx; + for(int i = 1; i <= 1000; i++){ + hmac_sha512_Init(&ctx, cbor, 34); + decitoa(i, c); + memcpy(salt + 16, c, strlen(c) + 1); + hmac_sha512_Update(&ctx, (unsigned char *)salt, strlen(salt)); + hmac_sha512_Final(&ctx, hmac); + ed25519_publickey(hmac, public); + sha512_Raw(hmac, 32, secret); + secret[0] &= 248; + secret[31] &= 127; + secret[31] |= 64; + if (secret[31] & 0x20) { + continue; + } + memcpy(chain_code, hmac + 32, 32); + failed = 0; + break; + } + + memzero(hash, 32); + memzero(cbor, 34); + memzero(salt, strlen(salt) + 1); + memzero(c, strlen(c) + 1); + + if(failed){ + memzero(seed, sizeof(seed)); + memzero(secret, sizeof(secret)); + memzero(chain_code, sizeof(chain_code)); + memzero(hmac, sizeof(hmac)); + return 0; + } + + memcpy(out->private_key, secret, 32); + memcpy(out->private_key_extension, secret + 32, 32); + + memcpy(out->chain_code, chain_code, 32); + out->public_key[0] = 1; + memcpy(out->public_key + 1, public, 32); + memzero(seed, sizeof(seed)); + memzero(secret, sizeof(secret)); + memzero(chain_code, sizeof(chain_code)); + memzero(hmac, sizeof(hmac)); + + return 1; +} +#endif + int hdnode_public_ckd_cp(const ecdsa_curve *curve, const curve_point *parent, const uint8_t *parent_chain_code, uint32_t i, curve_point *child, uint8_t *child_chain_code) { uint8_t data[1 + 32 + 4]; uint8_t I[32 + 32]; @@ -270,7 +475,7 @@ int hdnode_public_ckd_cp(const ecdsa_curve *curve, const curve_point *parent, co bn_read_be(I, &c); if (bn_is_less(&c, &curve->order)) { // < order scalar_multiply(curve, &c, child); // b = c * G - point_add(curve, parent, child); // b = a + b + point_add(curve, parent, child); // b = a + b if (!point_is_infinity(child)) { if (child_chain_code) { memcpy(child_chain_code, I + 32, 32); @@ -371,8 +576,8 @@ int hdnode_private_ckd_cached(HDNode *inout, const uint32_t *i, size_t i_count, int j; for (j = 0; j < BIP32_CACHE_SIZE; j++) { if (private_ckd_cache[j].set && - private_ckd_cache[j].depth == i_count - 1 && - memcmp(private_ckd_cache[j].i, i, (i_count - 1) * sizeof(uint32_t)) == 0 && + private_ckd_cache[j].depth == i_count - 1 && + memcmp(private_ckd_cache[j].i, i, (i_count - 1) * sizeof(uint32_t)) == 0 && private_ckd_cache[j].node.curve == inout->curve) { memcpy(inout, &(private_ckd_cache[j].node), sizeof(HDNode)); found = true; @@ -437,11 +642,15 @@ void hdnode_fill_public_key(HDNode *node) #endif } else if (node->curve == &curve25519_info) { curve25519_scalarmult_basepoint(node->public_key + 1, node->private_key); +#ifdef USE_CARDANO + } else if (node->curve == &ed25519_cardano_info){ + ed25519_publickey_ext(node->private_key, node->private_key_extension, node->public_key + 1); +#endif } } #else - ecdsa_get_public_key33(node->curve->params, node->private_key, node->public_key); + ecdsa_get_public_key33(node->curve->params, node->private_key, node->public_key); #endif } @@ -696,6 +905,9 @@ const curve_info *get_curve_by_name(const char *curve_name) { if (strcmp(curve_name, ED25519_NAME) == 0) { return &ed25519_info; } + if (strcmp(curve_name, ED25519_CARDANO_NAME) == 0) { + return &ed25519_cardano_info; + } if (strcmp(curve_name, ED25519_SHA3_NAME) == 0) { return &ed25519_sha3_info; } diff --git a/bip32.h b/bip32.h index 5398ec3cd..1cdc01621 100644 --- a/bip32.h +++ b/bip32.h @@ -45,7 +45,10 @@ typedef struct { uint32_t depth; uint32_t child_num; uint8_t chain_code[32]; + uint8_t private_key[32]; + uint8_t private_key_extension[32]; + uint8_t public_key[33]; const curve_info *curve; } HDNode; @@ -59,6 +62,10 @@ int hdnode_from_seed(const uint8_t *seed, int seed_len, const char *curve, HDNod #define hdnode_private_ckd_prime(X, I) hdnode_private_ckd((X), ((I) | 0x80000000)) int hdnode_private_ckd(HDNode *inout, uint32_t i); +#ifdef USE_CARDANO +int hdnode_private_ckd_cardano(HDNode *inout, uint32_t i); +int hdnode_from_seed_cardano(uint8_t *seed, int seed_len, HDNode *out); +#endif int hdnode_public_ckd_cp(const ecdsa_curve *curve, const curve_point *parent, const uint8_t *parent_chain_code, uint32_t i, curve_point *child, uint8_t *child_chain_code); diff --git a/bip39.c b/bip39.c index b1bea4454..464294620 100644 --- a/bip39.c +++ b/bip39.c @@ -136,6 +136,67 @@ const uint16_t *mnemonic_from_data_indexes(const uint8_t *data, int len) return mnemo; } +int mnemonic_to_entropy(const char *mnemonic, uint8_t *entropy){ + if (!mnemonic) { + return 0; + } + + uint32_t i, n; + + i = 0; n = 0; + while (mnemonic[i]) { + if (mnemonic[i] == ' ') { + n++; + } + i++; + } + n++; + // check number of words + if (n != 12 && n != 18 && n != 24) { + return 0; + } + + char current_word[10]; + uint32_t j, k, ki, bi; + uint8_t bits[32 + 1]; + + memzero(bits, sizeof(bits)); + i = 0; bi = 0; + while (mnemonic[i]) { + j = 0; + while (mnemonic[i] != ' ' && mnemonic[i] != 0) { + if (j >= sizeof(current_word) - 1) { + return 0; + } + current_word[j] = mnemonic[i]; + i++; j++; + } + current_word[j] = 0; + if (mnemonic[i] != 0) i++; + k = 0; + for (;;) { + if (!wordlist[k]) { // word not found + return 0; + } + if (strcmp(current_word, wordlist[k]) == 0) { // word found on index k + for (ki = 0; ki < 11; ki++) { + if (k & (1 << (10 - ki))) { + bits[bi / 8] |= 1 << (7 - (bi % 8)); + } + bi++; + } + break; + } + k++; + } + } + if (bi != n * 11) { + return 0; + } + memcpy(entropy,bits,sizeof(bits)); + return (n*11); +} + int mnemonic_check(const char *mnemonic) { if (!mnemonic) { diff --git a/bip39.h b/bip39.h index 385f3d4fe..b4216b47c 100644 --- a/bip39.h +++ b/bip39.h @@ -36,6 +36,8 @@ const uint16_t *mnemonic_from_data_indexes(const uint8_t *data, int len); int mnemonic_check(const char *mnemonic); +int mnemonic_to_entropy(const char *mnemonic, uint8_t *entropy); + // passphrase must be at most 256 characters or code may crash void mnemonic_to_seed(const char *mnemonic, const char *passphrase, uint8_t seed[512 / 8], void (*progress_callback)(uint32_t current, uint32_t total)); diff --git a/curves.c b/curves.c index 5ff645c26..64244560b 100644 --- a/curves.c +++ b/curves.c @@ -27,6 +27,7 @@ const char SECP256K1_DECRED_NAME[] = "secp256k1-decred"; const char SECP256K1_GROESTL_NAME[] = "secp256k1-groestl"; const char NIST256P1_NAME[] = "nist256p1"; const char ED25519_NAME[] = "ed25519"; +const char ED25519_CARDANO_NAME[] = "ed25519 cardano seed"; const char ED25519_SHA3_NAME[] = "ed25519-sha3"; #if USE_KECCAK const char ED25519_KECCAK_NAME[] = "ed25519-keccak"; diff --git a/curves.h b/curves.h index 5fbab0f41..8fdd3c55d 100644 --- a/curves.h +++ b/curves.h @@ -30,6 +30,7 @@ extern const char SECP256K1_DECRED_NAME[]; extern const char SECP256K1_GROESTL_NAME[]; extern const char NIST256P1_NAME[]; extern const char ED25519_NAME[]; +extern const char ED25519_CARDANO_NAME[]; extern const char ED25519_SHA3_NAME[]; #if USE_KECCAK extern const char ED25519_KECCAK_NAME[]; diff --git a/ed25519-donna/ed25519.c b/ed25519-donna/ed25519.c index a8946cbbf..46b676a62 100644 --- a/ed25519-donna/ed25519.c +++ b/ed25519-donna/ed25519.c @@ -48,11 +48,29 @@ ED25519_FN(ed25519_publickey) (const ed25519_secret_key sk, ed25519_public_key p /* A = aB */ ed25519_extsk(extsk, sk); + expand256_modm(a, extsk, 32); ge25519_scalarmult_base_niels(&A, ge25519_niels_base_multiples, a); ge25519_pack(pk, &A); } +#ifdef USE_CARDANO +void +ED25519_FN(ed25519_publickey_ext) (const ed25519_secret_key sk, const ed25519_secret_key skext, ed25519_public_key pk) { + bignum256modm a; + ge25519 ALIGN(16) A; + hash_512bits extsk; + + /* we don't stretch the key through hashing first since its already 64 bytes */ + + memcpy(extsk, sk, 32); + memcpy(extsk+32, skext, 32); + expand256_modm(a, extsk, 32); + ge25519_scalarmult_base_niels(&A, ge25519_niels_base_multiples, a); + ge25519_pack(pk, &A); +} +#endif + void ED25519_FN(ed25519_cosi_sign) (const unsigned char *m, size_t mlen, const ed25519_secret_key sk, const ed25519_secret_key nonce, const ed25519_public_key R, const ed25519_public_key pk, ed25519_cosi_signature sig) { bignum256modm r, S, a; @@ -88,6 +106,7 @@ ED25519_FN(ed25519_sign) (const unsigned char *m, size_t mlen, const ed25519_sec ed25519_extsk(extsk, sk); + /* r = H(aExt[32..64], m) */ ed25519_hash_init(&ctx); ed25519_hash_update(&ctx, extsk + 32, 32); @@ -114,6 +133,47 @@ ED25519_FN(ed25519_sign) (const unsigned char *m, size_t mlen, const ed25519_sec contract256_modm(RS + 32, S); } +#ifdef USE_CARDANO +void +ED25519_FN(ed25519_sign_ext) (const unsigned char *m, size_t mlen, const ed25519_secret_key sk, const ed25519_secret_key skext, const ed25519_public_key pk, ed25519_signature RS) { + ed25519_hash_context ctx; + bignum256modm r, S, a; + ge25519 ALIGN(16) R; + hash_512bits extsk, hashr, hram; + + /* we don't stretch the key through hashing first since its already 64 bytes */ + + memcpy(extsk, sk, 32); + memcpy(extsk+32, skext, 32); + + + /* r = H(aExt[32..64], m) */ + ed25519_hash_init(&ctx); + ed25519_hash_update(&ctx, extsk + 32, 32); + ed25519_hash_update(&ctx, m, mlen); + ed25519_hash_final(&ctx, hashr); + expand256_modm(r, hashr, 64); + + /* R = rB */ + ge25519_scalarmult_base_niels(&R, ge25519_niels_base_multiples, r); + ge25519_pack(RS, &R); + + /* S = H(R,A,m).. */ + ed25519_hram(hram, RS, pk, m, mlen); + expand256_modm(S, hram, 64); + + /* S = H(R,A,m)a */ + expand256_modm(a, extsk, 32); + mul256_modm(S, S, a); + + /* S = (r + H(R,A,m)a) */ + add256_modm(S, S, r); + + /* S = (r + H(R,A,m)a) mod L */ + contract256_modm(RS + 32, S); +} +#endif + int ED25519_FN(ed25519_sign_open) (const unsigned char *m, size_t mlen, const ed25519_public_key pk, const ed25519_signature RS) { ge25519 ALIGN(16) R, A; diff --git a/ed25519-donna/ed25519.h b/ed25519-donna/ed25519.h index b42afdc1b..78b77eec4 100644 --- a/ed25519-donna/ed25519.h +++ b/ed25519-donna/ed25519.h @@ -14,9 +14,15 @@ typedef unsigned char curve25519_key[32]; typedef unsigned char ed25519_cosi_signature[32]; void ed25519_publickey(const ed25519_secret_key sk, ed25519_public_key pk); +#ifdef USE_CARDANO +void ed25519_publickey_ext(const ed25519_secret_key sk, const ed25519_secret_key skext, ed25519_public_key pk); +#endif int ed25519_sign_open(const unsigned char *m, size_t mlen, const ed25519_public_key pk, const ed25519_signature RS); void ed25519_sign(const unsigned char *m, size_t mlen, const ed25519_secret_key sk, const ed25519_public_key pk, ed25519_signature RS); +#ifdef USE_CARDANO +void ed25519_sign_ext(const unsigned char *m, size_t mlen, const ed25519_secret_key sk, const ed25519_secret_key skext, const ed25519_public_key pk, ed25519_signature RS); +#endif int ed25519_scalarmult(ed25519_public_key res, const ed25519_secret_key sk, const ed25519_public_key pk); diff --git a/tests/test_check.c b/tests/test_check.c index 6be915998..d9d55ab9f 100644 --- a/tests/test_check.c +++ b/tests/test_check.c @@ -1872,6 +1872,141 @@ START_TEST(test_bip32_decred_vector_2) } END_TEST +// https://github.com/input-output-hk/cardano-crypto/blob/master/tests/goldens/cardano/crypto/wallet/BIP39-128 +START_TEST(test_bip32_cardano_hdnode_vector_1) +{ + HDNode node; + + uint8_t seed[66]; + int seed_len = mnemonic_to_entropy("ring crime symptom enough erupt lady behave ramp apart settle citizen junk", seed + 2); + hdnode_from_seed_cardano(seed, seed_len / 8, &node); + + ck_assert_mem_eq(node.chain_code, fromhex("739f4b3caca4c9ad4fcd4bdc2ef42c8601af8d6946999ef85ef6ae84f66e72eb"), 32); + ck_assert_mem_eq(node.private_key, fromhex("6065a956b1b34145c4416fdc3ba3276801850e91a77a31a7be782463288aea53"), 32); + ck_assert_mem_eq(node.private_key_extension, fromhex("60ba6e25b1a02157fb69c5d1d7b96c4619736e545447069a6a6f0ba90844bc8e"), 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq(node.public_key + 1, fromhex("64b20fa082b3143d6b5eed42c6ef63f99599d0888afe060620abc1b319935fe1"), 32); +} +END_TEST + +START_TEST(test_bip32_cardano_hdnode_vector_2) +{ + HDNode node; + + uint8_t seed[66]; + int seed_len = mnemonic_to_entropy("ring crime symptom enough erupt lady behave ramp apart settle citizen junk", seed + 2); + hdnode_from_seed_cardano(seed, seed_len / 8, &node); + + hdnode_private_ckd_cardano(&node, 0x80000000); + + ck_assert_mem_eq(node.chain_code, fromhex("6755cb82e892d6614c007a5efbceb21d95a5244e269d0e206b48b9a495390b03"), 32); + ck_assert_mem_eq(node.private_key, fromhex("e7d27516538403a53a8b041656a3f570909df641a0ab811fe7d87c9ba02a830c"), 32); + ck_assert_mem_eq(node.private_key_extension, fromhex("794a2c54ad8b525b781773c87d38cbf4197636bc427a9d551368286fe4c294a4"), 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq(node.public_key + 1, fromhex("95bb82ffd5707716bc65170ab4e8dafeed90fbe0ce9258713b7751e962d931df"), 32); +} +END_TEST + +START_TEST(test_bip32_cardano_hdnode_vector_3) +{ + HDNode node; + + uint8_t seed[66]; + int seed_len = mnemonic_to_entropy("ring crime symptom enough erupt lady behave ramp apart settle citizen junk", seed + 2); + hdnode_from_seed_cardano(seed, seed_len / 8, &node); + + hdnode_private_ckd_cardano(&node, 0x80000001); + + ck_assert_mem_eq(node.chain_code, fromhex("47a242713bd18608231147c066b6083bfc1e9066fec9f621844c84fed6228a34"), 32); + ck_assert_mem_eq(node.private_key, fromhex("9b5a3d9a4c60bcd49bb64b72c082b164314d0f61d842f2575fd1d4fb30a28a0c"), 32); + ck_assert_mem_eq(node.private_key_extension, fromhex("b093e376f41eb7bf80abcd0073a52455d25b5d21815bc758e5f6f81536aedebb"), 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq(node.public_key + 1, fromhex("79fc8154554b97e4c56ef2f9dbb4c1421ff19509688931a1e964bda5dec0f19f"), 32); +} +END_TEST + +START_TEST(test_bip32_cardano_hdnode_vector_4) +{ + HDNode node; + + uint8_t seed[66]; + int seed_len = mnemonic_to_entropy("ring crime symptom enough erupt lady behave ramp apart settle citizen junk", seed + 2); + hdnode_from_seed_cardano(seed, seed_len / 8, &node); + + hdnode_private_ckd_cardano(&node, 0x80000000); + hdnode_private_ckd_cardano(&node, 0x80000001); + + ck_assert_mem_eq(node.chain_code, fromhex("d6798491b9fa4612370ae5ef3c623a0b6872f3ad8f26970885fa67c83bdc425e"), 32); + ck_assert_mem_eq(node.private_key, fromhex("52e0c98aa600cfdcd1ff28fcda5227ed87063f4a98547a78b771052cf102b40c"), 32); + ck_assert_mem_eq(node.private_key_extension, fromhex("6c18d9f8075b1a6a1833540607479bd58b7beb8a83d2bb01ca7ae02452a25803"), 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq(node.public_key + 1, fromhex("dc907c7c06e6314eedd9e18c9f6c6f9cc4e205fb1c70da608234c319f1f7b0d6"), 32); +} +END_TEST + +START_TEST(test_bip32_cardano_hdnode_vector_5) +{ + HDNode node; + + uint8_t seed[66]; + int seed_len = mnemonic_to_entropy("ring crime symptom enough erupt lady behave ramp apart settle citizen junk", seed + 2); + hdnode_from_seed_cardano(seed, seed_len / 8, &node); + + hdnode_private_ckd_cardano(&node, 0x80000000); + hdnode_private_ckd_cardano(&node, 0x80000001); + hdnode_private_ckd_cardano(&node, 0x80000002); + + ck_assert_mem_eq(node.chain_code, fromhex("4169a2a32e3618a903e930bd1a713033a38f92389093408394e29ac37a1752ea"), 32); + ck_assert_mem_eq(node.private_key, fromhex("11fd6462a3a92b35c22703f6f1c124ddcf36b7c2b09cc2784f320e1cfa12ec04"), 32); + ck_assert_mem_eq(node.private_key_extension, fromhex("c2785803c61c46aeca192a1bb1b7b20a8c4cc7fa01db57fc5d1d8a5473402352"), 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq(node.public_key + 1, fromhex("839775a41876e328986aa26168958bba1176e67819b357eea84afceab8b1db78"), 32); +} +END_TEST + +START_TEST(test_bip32_cardano_hdnode_vector_6) +{ + HDNode node; + + uint8_t seed[66]; + int seed_len = mnemonic_to_entropy("ring crime symptom enough erupt lady behave ramp apart settle citizen junk", seed + 2); + hdnode_from_seed_cardano(seed, seed_len / 8, &node); + + hdnode_private_ckd_cardano(&node, 0x80000000); + hdnode_private_ckd_cardano(&node, 0x80000001); + hdnode_private_ckd_cardano(&node, 0x80000002); + hdnode_private_ckd_cardano(&node, 0x80000002); + + ck_assert_mem_eq(node.chain_code, fromhex("3ae9c99a5925cba2dcf121baf3a0254f3dea23c129f9eb70a8a7e8897c5199ba"), 32); + ck_assert_mem_eq(node.private_key, fromhex("5b1e5cad02274ba461f4708d8598d3497faf8fe3e894a379573aa6ac3a03e505"), 32); + ck_assert_mem_eq(node.private_key_extension, fromhex("ba179d2e3c67aabb486c48d16002b51ad32eab434c738a1550962313b07098cd"), 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq(node.public_key + 1, fromhex("75eb8d197ec8627c85af88e66aa1e49065dd8ac98ed8991db52ece01635dfb76"), 32); +} +END_TEST + +START_TEST(test_bip32_cardano_hdnode_vector_7) +{ + HDNode node; + + uint8_t seed[66]; + int seed_len = mnemonic_to_entropy("ring crime symptom enough erupt lady behave ramp apart settle citizen junk", seed + 2); + hdnode_from_seed_cardano(seed, seed_len / 8, &node); + + hdnode_private_ckd_cardano(&node, 0x80000000); + hdnode_private_ckd_cardano(&node, 0x80000001); + hdnode_private_ckd_cardano(&node, 0x80000002); + hdnode_private_ckd_cardano(&node, 0x80000002); + hdnode_private_ckd_cardano(&node, 0xBB9ACA00); + + ck_assert_mem_eq(node.chain_code, fromhex("15c450b86dd7dd83b31951d9ee03eb1a7925161d817bd517c69cf09e3671f1ca"), 32); + ck_assert_mem_eq(node.private_key, fromhex("624b47150f58dfa44284fbc63c9f99b9b79f808c4955a461f0e2be44eb0be50d"), 32); + ck_assert_mem_eq(node.private_key_extension, fromhex("097aa006d694b165ef37cf23562e5967c96e49255d2f20faae478dee83aa5b02"), 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq(node.public_key + 1, fromhex("0588589cd9b51dfc028cf225674069cbe52e0e70deb02dc45b79b26ee3548b00"), 32); +} +END_TEST + START_TEST(test_ecdsa_signature) { int res; @@ -2772,6 +2907,74 @@ START_TEST(test_mnemonic_check) } END_TEST +START_TEST(test_mnemonic_to_entropy) +{ + static const char *vectors[] = { + "00000000000000000000000000000000", + "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about", + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", + "legal winner thank year wave sausage worth useful legal winner thank yellow", + "80808080808080808080808080808080", + "letter advice cage absurd amount doctor acoustic avoid letter advice cage above", + "ffffffffffffffffffffffffffffffff", + "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong", + "000000000000000000000000000000000000000000000000", + "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon agent", + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", + "legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal will", + "808080808080808080808080808080808080808080808080", + "letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter always", + "ffffffffffffffffffffffffffffffffffffffffffffffff", + "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo when", + "0000000000000000000000000000000000000000000000000000000000000000", + "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon art", + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", + "legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth title", + "8080808080808080808080808080808080808080808080808080808080808080", + "letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic bless", + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo vote", + "77c2b00716cec7213839159e404db50d", + "jelly better achieve collect unaware mountain thought cargo oxygen act hood bridge", + "b63a9c59a6e641f288ebc103017f1da9f8290b3da6bdef7b", + "renew stay biology evidence goat welcome casual join adapt armor shuffle fault little machine walk stumble urge swap", + "3e141609b97933b66a060dcddc71fad1d91677db872031e85f4c015c5e7e8982", + "dignity pass list indicate nasty swamp pool script soccer toe leaf photo multiply desk host tomato cradle drill spread actor shine dismiss champion exotic", + "0460ef47585604c5660618db2e6a7e7f", + "afford alter spike radar gate glance object seek swamp infant panel yellow", + "72f60ebac5dd8add8d2a25a797102c3ce21bc029c200076f", + "indicate race push merry suffer human cruise dwarf pole review arch keep canvas theme poem divorce alter left", + "2c85efc7f24ee4573d2b81a6ec66cee209b2dcbd09d8eddc51e0215b0b68e416", + "clutch control vehicle tonight unusual clog visa ice plunge glimpse recipe series open hour vintage deposit universe tip job dress radar refuse motion taste", + "eaebabb2383351fd31d703840b32e9e2", + "turtle front uncle idea crush write shrug there lottery flower risk shell", + "7ac45cfe7722ee6c7ba84fbc2d5bd61b45cb2fe5eb65aa78", + "kiss carry display unusual confirm curtain upgrade antique rotate hello void custom frequent obey nut hole price segment", + "4fa1a8bc3e6d80ee1316050e862c1812031493212b7ec3f3bb1b08f168cabeef", + "exile ask congress lamp submit jacket era scheme attend cousin alcohol catch course end lucky hurt sentence oven short ball bird grab wing top", + "18ab19a9f54a9274f03e5209a2ac8a91", + "board flee heavy tunnel powder denial science ski answer betray cargo cat", + "18a2e1d81b8ecfb2a333adcb0c17a5b9eb76cc5d05db91a4", + "board blade invite damage undo sun mimic interest slam gaze truly inherit resist great inject rocket museum chief", + "15da872c95a13dd738fbf50e427583ad61f18fd99f628c417a61cf8343c90419", + "beyond stage sleep clip because twist token leaf atom beauty genius food business side grid unable middle armed observe pair crouch tonight away coconut", + 0, + 0, + }; + + const char **a, **b; + uint8_t entropy[64]; + + a = vectors; + b = vectors + 1; + while (*a && *b) { + mnemonic_to_entropy(*b,entropy); + ck_assert_mem_eq(entropy, fromhex(*a), strlen(*a) / 2); + a += 2; b += 2; + } +} +END_TEST + START_TEST(test_address) { char address[36]; @@ -3607,6 +3810,81 @@ START_TEST(test_ge25519_double_scalarmult_vartime2) } END_TEST +// https://github.com/input-output-hk/cardano-crypto/blob/master/tests/goldens/cardano/crypto/wallet/BIP39-128 +START_TEST(test_ed25519_cardano_sign_vectors) +{ + ed25519_public_key public_key; + ed25519_secret_key secret_key; + ed25519_secret_key secret_key_extension; + ed25519_signature signature; + + static const char *vectors[] = { + "6065a956b1b34145c4416fdc3ba3276801850e91a77a31a7be782463288aea53", // private key + "60ba6e25b1a02157fb69c5d1d7b96c4619736e545447069a6a6f0ba90844bc8e", // private key extension + "64b20fa082b3143d6b5eed42c6ef63f99599d0888afe060620abc1b319935fe1", // public key + "45b1a75fe3119e13c6f60ab9ba674b42f946fdc558e07c83dfa0751c2eba69c79331bd8a4a975662b23628a438a0eba76367e44c12ca91b39ec59063f860f10d", // signature + + "e7d27516538403a53a8b041656a3f570909df641a0ab811fe7d87c9ba02a830c", // private key + "794a2c54ad8b525b781773c87d38cbf4197636bc427a9d551368286fe4c294a4", // private key extension + "95bb82ffd5707716bc65170ab4e8dafeed90fbe0ce9258713b7751e962d931df", // public key + "f2c9171782e7df7665126ac545ae53b05964b0160536efdb545e2460dbbec2b19ec6b338b8f1bf4dfee94360ed024b115e37b1d7e6f3f9ae4beb79539428560f", // signature + + "9b5a3d9a4c60bcd49bb64b72c082b164314d0f61d842f2575fd1d4fb30a28a0c", // private key + "b093e376f41eb7bf80abcd0073a52455d25b5d21815bc758e5f6f81536aedebb", // private key extension + "79fc8154554b97e4c56ef2f9dbb4c1421ff19509688931a1e964bda5dec0f19f", // public key + "2ba1439ae648a7e8da7c9ab1ee6da94fd4ebe37abd0978306e8fba2afa8f111a88a993dbf008bedae9167f4f68409e4c9ddaf02cba12418447b1848907ad800f", // signature + + "52e0c98aa600cfdcd1ff28fcda5227ed87063f4a98547a78b771052cf102b40c", // private key + "6c18d9f8075b1a6a1833540607479bd58b7beb8a83d2bb01ca7ae02452a25803", // private key extension + "dc907c7c06e6314eedd9e18c9f6c6f9cc4e205fb1c70da608234c319f1f7b0d6", // public key + "0cd34f84e0d2fcb1800bdb0e869b9041349955ced66aedbe6bda187ebe8d36a62a05b39647e92fcc42aa7a7368174240afba08b8c81f981a22f942d6bd781602", // signature + + "11fd6462a3a92b35c22703f6f1c124ddcf36b7c2b09cc2784f320e1cfa12ec04", // private key + "c2785803c61c46aeca192a1bb1b7b20a8c4cc7fa01db57fc5d1d8a5473402352", // private key extension + "839775a41876e328986aa26168958bba1176e67819b357eea84afceab8b1db78", // public key + "e41f73db2f8d2896a687802b2be76b7cabb73dfbb4891494883a0cbd9bbb9e5f9d3e14d2d0b06c6674333508496db660936737c0efd9511514147dac79fa4905", // signature + + "5b1e5cad02274ba461f4708d8598d3497faf8fe3e894a379573aa6ac3a03e505", // private key + "ba179d2e3c67aabb486c48d16002b51ad32eab434c738a1550962313b07098cd", // private key extension + "75eb8d197ec8627c85af88e66aa1e49065dd8ac98ed8991db52ece01635dfb76", // public key + "631015357cee3051116b4c2ff4d1c5beb13b6e5023635aa1eeb0563cadf0d4fbc10bd5e31b4a4220c67875558c41b5cc0328104ae39cc7ff20ff0c2bda598906", // signature + + "624b47150f58dfa44284fbc63c9f99b9b79f808c4955a461f0e2be44eb0be50d", // private key + "097aa006d694b165ef37cf23562e5967c96e49255d2f20faae478dee83aa5b02", // private key extension + "0588589cd9b51dfc028cf225674069cbe52e0e70deb02dc45b79b26ee3548b00", // public key + "1de1d275428ba9491a433cd473cd076c027f61e7a8b5391df9dea5cb4bc88d8a57b095906a30b13e68259851a8dd3f57b6f0ffa37a5d3ffc171240f2d404f901", // signature + + 0, 0, + }; + + const char **test_data; + test_data = vectors; + while (*test_data) { + memcpy(secret_key, fromhex(*test_data), 32); + MARK_SECRET_DATA(secret_key, sizeof(secret_key)); + + memcpy(secret_key_extension, fromhex(*(test_data + 1)), 32); + MARK_SECRET_DATA(secret_key_extension, sizeof(secret_key_extension)); + + ed25519_publickey_ext(secret_key, secret_key_extension, public_key); + UNMARK_SECRET_DATA(public_key, sizeof(public_key)); + + ck_assert_mem_eq(public_key, fromhex(*(test_data + 2)), 32); + + const uint8_t * message = (const uint8_t *) "Hello World"; + ed25519_sign_ext(message, 11, secret_key, secret_key_extension, public_key, signature); + UNMARK_SECRET_DATA(signature, sizeof(signature)); + + ck_assert_mem_eq(signature, fromhex(*(test_data + 3)), 64); + + UNMARK_SECRET_DATA(secret_key, sizeof(secret_key)); + UNMARK_SECRET_DATA(secret_key_extension, sizeof(secret_key_extension)); + + test_data += 4; + } +} +END_TEST + static void test_bip32_ecdh_init_node(HDNode *node, const char *seed_str, const char *curve_name) { hdnode_from_seed((const uint8_t *)seed_str, strlen(seed_str), curve_name, node); hdnode_fill_public_key(node); @@ -4762,6 +5040,16 @@ Suite *test_suite(void) tcase_add_test(tc, test_bip32_decred_vector_2); suite_add_tcase(s, tc); + tc = tcase_create("bip32-cardano"); + tcase_add_test(tc, test_bip32_cardano_hdnode_vector_1); + tcase_add_test(tc, test_bip32_cardano_hdnode_vector_2); + tcase_add_test(tc, test_bip32_cardano_hdnode_vector_3); + tcase_add_test(tc, test_bip32_cardano_hdnode_vector_4); + tcase_add_test(tc, test_bip32_cardano_hdnode_vector_5); + tcase_add_test(tc, test_bip32_cardano_hdnode_vector_6); + tcase_add_test(tc, test_bip32_cardano_hdnode_vector_7); + suite_add_tcase(s,tc); + tc = tcase_create("ecdsa"); tcase_add_test(tc, test_ecdsa_signature); suite_add_tcase(s, tc); @@ -4829,6 +5117,10 @@ Suite *test_suite(void) tcase_add_test(tc, test_mnemonic_check); suite_add_tcase(s, tc); + tc = tcase_create("bip39-cardano"); + tcase_add_test(tc, test_mnemonic_to_entropy); + suite_add_tcase(s,tc); + tc = tcase_create("pubkey_validity"); tcase_add_test(tc, test_pubkey_validity); suite_add_tcase(s, tc); @@ -4884,6 +5176,10 @@ Suite *test_suite(void) tcase_add_test(tc, test_ge25519_double_scalarmult_vartime2); suite_add_tcase(s, tc); + tc = tcase_create("ed25519-cardano"); + tcase_add_test(tc, test_ed25519_cardano_sign_vectors); + suite_add_tcase(s,tc); + tc = tcase_create("script"); tcase_add_test(tc, test_output_script); suite_add_tcase(s, tc); From 1730601d3017bf3fab271663895abff8457e3652 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 10 Jul 2018 20:02:53 +0200 Subject: [PATCH 569/627] refactor mnemonic_check and mnemonic_to_entropy, style changes --- Makefile | 2 +- bip32.c | 54 ++++---- bip32.h | 2 +- bip39.c | 94 ++++--------- ed25519-donna/ed25519.c | 4 +- ed25519-donna/ed25519.h | 4 +- tests/test_check.c | 255 ++++-------------------------------- tests/test_check_cardano.h | 216 ++++++++++++++++++++++++++++++ tests/test_check_cashaddr.h | 6 - tests/test_check_segwit.h | 6 - 10 files changed, 292 insertions(+), 351 deletions(-) create mode 100644 tests/test_check_cardano.h diff --git a/Makefile b/Makefile index 9bf421eca..6ccba84e5 100644 --- a/Makefile +++ b/Makefile @@ -71,7 +71,7 @@ tests: tests/test_check tests/test_openssl tests/test_speed tests/libtrezor-cryp tests/aestst: aes/aestst.o aes/aescrypt.o aes/aeskey.o aes/aestab.o $(CC) $^ -o $@ -tests/test_check.o: tests/test_check_segwit.h tests/test_check_cashaddr.h +tests/test_check.o: tests/test_check_cardano.h tests/test_check_cashaddr.h tests/test_check_segwit.h tests/test_check: tests/test_check.o $(OBJS) $(CC) tests/test_check.o $(OBJS) $(TESTLIBS) -o tests/test_check diff --git a/bip32.c b/bip32.c index b36ddde78..8baa885b7 100644 --- a/bip32.c +++ b/bip32.c @@ -268,12 +268,11 @@ int hdnode_private_ckd(HDNode *inout, uint32_t i) return 1; } -#ifdef USE_CARDANO +#if USE_CARDANO static void multiply8(uint8_t *dst, uint8_t *src, int bytes) { - int i; uint8_t prev_acc = 0; - for (i = 0; i < bytes; i++) { + for (int i = 0; i < bytes; i++) { dst[i] = (src[i] << 3) + (prev_acc & 0x8); prev_acc = src[i] >> 5; } @@ -281,8 +280,7 @@ static void multiply8(uint8_t *dst, uint8_t *src, int bytes) static void add_256bits(uint8_t *dst, uint8_t *src1, uint8_t *src2) { - int i; - for (i = 0; i < 32; i++) { + for (int i = 0; i < 32; i++) { uint8_t a = src1[i]; uint8_t b = src2[i]; uint16_t r = a + b; @@ -290,7 +288,7 @@ static void add_256bits(uint8_t *dst, uint8_t *src1, uint8_t *src2) } } -int ed25519_scalar_add(const uint8_t *sk1, const uint8_t *sk2, uint8_t *res) +static int ed25519_scalar_add(const uint8_t *sk1, const uint8_t *sk2, uint8_t *res) { bignum256modm s1, s2; expand256_modm(s1, sk1, 32); @@ -302,9 +300,9 @@ int ed25519_scalar_add(const uint8_t *sk1, const uint8_t *sk2, uint8_t *res) int hdnode_private_ckd_cardano(HDNode *inout, uint32_t i) { - //checks for hardened/non-hardened derivation, keysize 32 means we are dealing with public key and thus non-h, keysize 64 is for private key + // checks for hardened/non-hardened derivation, keysize 32 means we are dealing with public key and thus non-h, keysize 64 is for private key int keysize = 32; - if(i & 0x80000000){ + if (i & 0x80000000) { keysize = 64; } @@ -342,10 +340,10 @@ int hdnode_private_ckd_cardano(HDNode *inout, uint32_t i) memcpy(inout->private_key, res_key, 32); memcpy(inout->private_key_extension, res_key + 32, 32); - if(keysize == 64){ - data[0]=1; - }else{ - data[0]=3; + if (keysize == 64) { + data[0] = 1; + } else { + data[0] = 3; } hmac_sha512_Init(&ctx, inout->chain_code, 32); hmac_sha512_Update(&ctx, data, 1 + keysize + 4); @@ -366,28 +364,24 @@ int hdnode_private_ckd_cardano(HDNode *inout, uint32_t i) return 1; } -void decitoa(int val, char * out){ - - static char buf[32] = {0}; - - int i = 30; - - for(; val && i ; --i, val /= 10){ - buf[i] = "0123456789"[val % 10]; - } - - memcpy(out,&buf[i+1],strlen(&buf[i+1])+1); +static void decitoa(int val, char *out) { + static char buf[32] = {0}; + int i = 30; + for (; val && i; --i, val /= 10) { + buf[i] = "0123456789"[val % 10]; + } + memcpy(out, &buf[i + 1], strlen(&buf[i + 1]) + 1); } -int hdnode_from_seed_cardano(uint8_t *seed, int seed_len, HDNode *out){ +int hdnode_from_seed_cardano(uint8_t *seed, int seed_len, HDNode *out) { uint8_t hash[32]; uint8_t cbor[32+2]; - if(seed_len < 24){ + if (seed_len < 24) { // cbor encodes length directly into first byte if its smaller than 24 seed[1] = 64 | seed_len; blake2b(seed + 1, seed_len + 1, hash, 32); - }else{ + } else { seed[0] = 88; seed[1] = seed_len; blake2b(seed, seed_len + 2, hash, 32); @@ -410,7 +404,7 @@ int hdnode_from_seed_cardano(uint8_t *seed, int seed_len, HDNode *out){ out->curve = get_curve_by_name(ED25519_CARDANO_NAME); static CONFIDENTIAL HMAC_SHA512_CTX ctx; - for(int i = 1; i <= 1000; i++){ + for (int i = 1; i <= 1000; i++){ hmac_sha512_Init(&ctx, cbor, 34); decitoa(i, c); memcpy(salt + 16, c, strlen(c) + 1); @@ -434,7 +428,7 @@ int hdnode_from_seed_cardano(uint8_t *seed, int seed_len, HDNode *out){ memzero(salt, strlen(salt) + 1); memzero(c, strlen(c) + 1); - if(failed){ + if (failed) { memzero(seed, sizeof(seed)); memzero(secret, sizeof(secret)); memzero(chain_code, sizeof(chain_code)); @@ -642,8 +636,8 @@ void hdnode_fill_public_key(HDNode *node) #endif } else if (node->curve == &curve25519_info) { curve25519_scalarmult_basepoint(node->public_key + 1, node->private_key); -#ifdef USE_CARDANO - } else if (node->curve == &ed25519_cardano_info){ +#if USE_CARDANO + } else if (node->curve == &ed25519_cardano_info) { ed25519_publickey_ext(node->private_key, node->private_key_extension, node->public_key + 1); #endif } diff --git a/bip32.h b/bip32.h index 1cdc01621..c98019658 100644 --- a/bip32.h +++ b/bip32.h @@ -62,7 +62,7 @@ int hdnode_from_seed(const uint8_t *seed, int seed_len, const char *curve, HDNod #define hdnode_private_ckd_prime(X, I) hdnode_private_ckd((X), ((I) | 0x80000000)) int hdnode_private_ckd(HDNode *inout, uint32_t i); -#ifdef USE_CARDANO +#if USE_CARDANO int hdnode_private_ckd_cardano(HDNode *inout, uint32_t i); int hdnode_from_seed_cardano(uint8_t *seed, int seed_len, HDNode *out); #endif diff --git a/bip39.c b/bip39.c index 464294620..ac4e4fb36 100644 --- a/bip39.c +++ b/bip39.c @@ -136,14 +136,14 @@ const uint16_t *mnemonic_from_data_indexes(const uint8_t *data, int len) return mnemo; } -int mnemonic_to_entropy(const char *mnemonic, uint8_t *entropy){ +int mnemonic_to_entropy(const char *mnemonic, uint8_t *entropy) +{ if (!mnemonic) { return 0; } - uint32_t i, n; + uint32_t i = 0, n = 0; - i = 0; n = 0; while (mnemonic[i]) { if (mnemonic[i] == ' ') { n++; @@ -151,17 +151,18 @@ int mnemonic_to_entropy(const char *mnemonic, uint8_t *entropy){ i++; } n++; + // check number of words if (n != 12 && n != 18 && n != 24) { return 0; } char current_word[10]; - uint32_t j, k, ki, bi; + uint32_t j, k, ki, bi = 0; uint8_t bits[32 + 1]; memzero(bits, sizeof(bits)); - i = 0; bi = 0; + i = 0; while (mnemonic[i]) { j = 0; while (mnemonic[i] != ' ' && mnemonic[i] != 0) { @@ -172,7 +173,9 @@ int mnemonic_to_entropy(const char *mnemonic, uint8_t *entropy){ i++; j++; } current_word[j] = 0; - if (mnemonic[i] != 0) i++; + if (mnemonic[i] != 0) { + i++; + } k = 0; for (;;) { if (!wordlist[k]) { // word not found @@ -193,78 +196,27 @@ int mnemonic_to_entropy(const char *mnemonic, uint8_t *entropy){ if (bi != n * 11) { return 0; } - memcpy(entropy,bits,sizeof(bits)); - return (n*11); + memcpy(entropy, bits, sizeof(bits)); + return n * 11; } int mnemonic_check(const char *mnemonic) { - if (!mnemonic) { - return 0; - } - - uint32_t i, n; - - i = 0; n = 0; - while (mnemonic[i]) { - if (mnemonic[i] == ' ') { - n++; - } - i++; - } - n++; - // check number of words - if (n != 12 && n != 18 && n != 24) { - return 0; - } - - char current_word[10]; - uint32_t j, k, ki, bi; uint8_t bits[32 + 1]; - - memzero(bits, sizeof(bits)); - i = 0; bi = 0; - while (mnemonic[i]) { - j = 0; - while (mnemonic[i] != ' ' && mnemonic[i] != 0) { - if (j >= sizeof(current_word) - 1) { - return 0; - } - current_word[j] = mnemonic[i]; - i++; j++; - } - current_word[j] = 0; - if (mnemonic[i] != 0) i++; - k = 0; - for (;;) { - if (!wordlist[k]) { // word not found - return 0; - } - if (strcmp(current_word, wordlist[k]) == 0) { // word found on index k - for (ki = 0; ki < 11; ki++) { - if (k & (1 << (10 - ki))) { - bits[bi / 8] |= 1 << (7 - (bi % 8)); - } - bi++; - } - break; - } - k++; - } - } - if (bi != n * 11) { + int seed_len = mnemonic_to_entropy(mnemonic, bits); + if (seed_len != (12 * 11) && seed_len != (18 * 11) && seed_len != (24 * 11)) { return 0; } - bits[32] = bits[n * 4 / 3]; - sha256_Raw(bits, n * 4 / 3, bits); - if (n == 12) { - return (bits[0] & 0xF0) == (bits[32] & 0xF0); // compare first 4 bits - } else - if (n == 18) { - return (bits[0] & 0xFC) == (bits[32] & 0xFC); // compare first 6 bits - } else - if (n == 24) { - return bits[0] == bits[32]; // compare 8 bits + int words = seed_len / 11; + + uint8_t checksum = bits[words * 4 / 3]; + sha256_Raw(bits, words * 4 / 3, bits); + if (words == 12) { + return (bits[0] & 0xF0) == (checksum & 0xF0); // compare first 4 bits + } else if (words == 18) { + return (bits[0] & 0xFC) == (checksum & 0xFC); // compare first 6 bits + } else if (words == 24) { + return bits[0] == checksum; // compare 8 bits } return 0; } diff --git a/ed25519-donna/ed25519.c b/ed25519-donna/ed25519.c index 46b676a62..880b59d84 100644 --- a/ed25519-donna/ed25519.c +++ b/ed25519-donna/ed25519.c @@ -54,7 +54,7 @@ ED25519_FN(ed25519_publickey) (const ed25519_secret_key sk, ed25519_public_key p ge25519_pack(pk, &A); } -#ifdef USE_CARDANO +#if USE_CARDANO void ED25519_FN(ed25519_publickey_ext) (const ed25519_secret_key sk, const ed25519_secret_key skext, ed25519_public_key pk) { bignum256modm a; @@ -133,7 +133,7 @@ ED25519_FN(ed25519_sign) (const unsigned char *m, size_t mlen, const ed25519_sec contract256_modm(RS + 32, S); } -#ifdef USE_CARDANO +#if USE_CARDANO void ED25519_FN(ed25519_sign_ext) (const unsigned char *m, size_t mlen, const ed25519_secret_key sk, const ed25519_secret_key skext, const ed25519_public_key pk, ed25519_signature RS) { ed25519_hash_context ctx; diff --git a/ed25519-donna/ed25519.h b/ed25519-donna/ed25519.h index 78b77eec4..9d9838d14 100644 --- a/ed25519-donna/ed25519.h +++ b/ed25519-donna/ed25519.h @@ -14,13 +14,13 @@ typedef unsigned char curve25519_key[32]; typedef unsigned char ed25519_cosi_signature[32]; void ed25519_publickey(const ed25519_secret_key sk, ed25519_public_key pk); -#ifdef USE_CARDANO +#if USE_CARDANO void ed25519_publickey_ext(const ed25519_secret_key sk, const ed25519_secret_key skext, ed25519_public_key pk); #endif int ed25519_sign_open(const unsigned char *m, size_t mlen, const ed25519_public_key pk, const ed25519_signature RS); void ed25519_sign(const unsigned char *m, size_t mlen, const ed25519_secret_key sk, const ed25519_public_key pk, ed25519_signature RS); -#ifdef USE_CARDANO +#if USE_CARDANO void ed25519_sign_ext(const unsigned char *m, size_t mlen, const ed25519_secret_key sk, const ed25519_secret_key skext, const ed25519_public_key pk, ed25519_signature RS); #endif diff --git a/tests/test_check.c b/tests/test_check.c index d9d55ab9f..7db4e1d63 100644 --- a/tests/test_check.c +++ b/tests/test_check.c @@ -1872,141 +1872,6 @@ START_TEST(test_bip32_decred_vector_2) } END_TEST -// https://github.com/input-output-hk/cardano-crypto/blob/master/tests/goldens/cardano/crypto/wallet/BIP39-128 -START_TEST(test_bip32_cardano_hdnode_vector_1) -{ - HDNode node; - - uint8_t seed[66]; - int seed_len = mnemonic_to_entropy("ring crime symptom enough erupt lady behave ramp apart settle citizen junk", seed + 2); - hdnode_from_seed_cardano(seed, seed_len / 8, &node); - - ck_assert_mem_eq(node.chain_code, fromhex("739f4b3caca4c9ad4fcd4bdc2ef42c8601af8d6946999ef85ef6ae84f66e72eb"), 32); - ck_assert_mem_eq(node.private_key, fromhex("6065a956b1b34145c4416fdc3ba3276801850e91a77a31a7be782463288aea53"), 32); - ck_assert_mem_eq(node.private_key_extension, fromhex("60ba6e25b1a02157fb69c5d1d7b96c4619736e545447069a6a6f0ba90844bc8e"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key + 1, fromhex("64b20fa082b3143d6b5eed42c6ef63f99599d0888afe060620abc1b319935fe1"), 32); -} -END_TEST - -START_TEST(test_bip32_cardano_hdnode_vector_2) -{ - HDNode node; - - uint8_t seed[66]; - int seed_len = mnemonic_to_entropy("ring crime symptom enough erupt lady behave ramp apart settle citizen junk", seed + 2); - hdnode_from_seed_cardano(seed, seed_len / 8, &node); - - hdnode_private_ckd_cardano(&node, 0x80000000); - - ck_assert_mem_eq(node.chain_code, fromhex("6755cb82e892d6614c007a5efbceb21d95a5244e269d0e206b48b9a495390b03"), 32); - ck_assert_mem_eq(node.private_key, fromhex("e7d27516538403a53a8b041656a3f570909df641a0ab811fe7d87c9ba02a830c"), 32); - ck_assert_mem_eq(node.private_key_extension, fromhex("794a2c54ad8b525b781773c87d38cbf4197636bc427a9d551368286fe4c294a4"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key + 1, fromhex("95bb82ffd5707716bc65170ab4e8dafeed90fbe0ce9258713b7751e962d931df"), 32); -} -END_TEST - -START_TEST(test_bip32_cardano_hdnode_vector_3) -{ - HDNode node; - - uint8_t seed[66]; - int seed_len = mnemonic_to_entropy("ring crime symptom enough erupt lady behave ramp apart settle citizen junk", seed + 2); - hdnode_from_seed_cardano(seed, seed_len / 8, &node); - - hdnode_private_ckd_cardano(&node, 0x80000001); - - ck_assert_mem_eq(node.chain_code, fromhex("47a242713bd18608231147c066b6083bfc1e9066fec9f621844c84fed6228a34"), 32); - ck_assert_mem_eq(node.private_key, fromhex("9b5a3d9a4c60bcd49bb64b72c082b164314d0f61d842f2575fd1d4fb30a28a0c"), 32); - ck_assert_mem_eq(node.private_key_extension, fromhex("b093e376f41eb7bf80abcd0073a52455d25b5d21815bc758e5f6f81536aedebb"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key + 1, fromhex("79fc8154554b97e4c56ef2f9dbb4c1421ff19509688931a1e964bda5dec0f19f"), 32); -} -END_TEST - -START_TEST(test_bip32_cardano_hdnode_vector_4) -{ - HDNode node; - - uint8_t seed[66]; - int seed_len = mnemonic_to_entropy("ring crime symptom enough erupt lady behave ramp apart settle citizen junk", seed + 2); - hdnode_from_seed_cardano(seed, seed_len / 8, &node); - - hdnode_private_ckd_cardano(&node, 0x80000000); - hdnode_private_ckd_cardano(&node, 0x80000001); - - ck_assert_mem_eq(node.chain_code, fromhex("d6798491b9fa4612370ae5ef3c623a0b6872f3ad8f26970885fa67c83bdc425e"), 32); - ck_assert_mem_eq(node.private_key, fromhex("52e0c98aa600cfdcd1ff28fcda5227ed87063f4a98547a78b771052cf102b40c"), 32); - ck_assert_mem_eq(node.private_key_extension, fromhex("6c18d9f8075b1a6a1833540607479bd58b7beb8a83d2bb01ca7ae02452a25803"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key + 1, fromhex("dc907c7c06e6314eedd9e18c9f6c6f9cc4e205fb1c70da608234c319f1f7b0d6"), 32); -} -END_TEST - -START_TEST(test_bip32_cardano_hdnode_vector_5) -{ - HDNode node; - - uint8_t seed[66]; - int seed_len = mnemonic_to_entropy("ring crime symptom enough erupt lady behave ramp apart settle citizen junk", seed + 2); - hdnode_from_seed_cardano(seed, seed_len / 8, &node); - - hdnode_private_ckd_cardano(&node, 0x80000000); - hdnode_private_ckd_cardano(&node, 0x80000001); - hdnode_private_ckd_cardano(&node, 0x80000002); - - ck_assert_mem_eq(node.chain_code, fromhex("4169a2a32e3618a903e930bd1a713033a38f92389093408394e29ac37a1752ea"), 32); - ck_assert_mem_eq(node.private_key, fromhex("11fd6462a3a92b35c22703f6f1c124ddcf36b7c2b09cc2784f320e1cfa12ec04"), 32); - ck_assert_mem_eq(node.private_key_extension, fromhex("c2785803c61c46aeca192a1bb1b7b20a8c4cc7fa01db57fc5d1d8a5473402352"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key + 1, fromhex("839775a41876e328986aa26168958bba1176e67819b357eea84afceab8b1db78"), 32); -} -END_TEST - -START_TEST(test_bip32_cardano_hdnode_vector_6) -{ - HDNode node; - - uint8_t seed[66]; - int seed_len = mnemonic_to_entropy("ring crime symptom enough erupt lady behave ramp apart settle citizen junk", seed + 2); - hdnode_from_seed_cardano(seed, seed_len / 8, &node); - - hdnode_private_ckd_cardano(&node, 0x80000000); - hdnode_private_ckd_cardano(&node, 0x80000001); - hdnode_private_ckd_cardano(&node, 0x80000002); - hdnode_private_ckd_cardano(&node, 0x80000002); - - ck_assert_mem_eq(node.chain_code, fromhex("3ae9c99a5925cba2dcf121baf3a0254f3dea23c129f9eb70a8a7e8897c5199ba"), 32); - ck_assert_mem_eq(node.private_key, fromhex("5b1e5cad02274ba461f4708d8598d3497faf8fe3e894a379573aa6ac3a03e505"), 32); - ck_assert_mem_eq(node.private_key_extension, fromhex("ba179d2e3c67aabb486c48d16002b51ad32eab434c738a1550962313b07098cd"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key + 1, fromhex("75eb8d197ec8627c85af88e66aa1e49065dd8ac98ed8991db52ece01635dfb76"), 32); -} -END_TEST - -START_TEST(test_bip32_cardano_hdnode_vector_7) -{ - HDNode node; - - uint8_t seed[66]; - int seed_len = mnemonic_to_entropy("ring crime symptom enough erupt lady behave ramp apart settle citizen junk", seed + 2); - hdnode_from_seed_cardano(seed, seed_len / 8, &node); - - hdnode_private_ckd_cardano(&node, 0x80000000); - hdnode_private_ckd_cardano(&node, 0x80000001); - hdnode_private_ckd_cardano(&node, 0x80000002); - hdnode_private_ckd_cardano(&node, 0x80000002); - hdnode_private_ckd_cardano(&node, 0xBB9ACA00); - - ck_assert_mem_eq(node.chain_code, fromhex("15c450b86dd7dd83b31951d9ee03eb1a7925161d817bd517c69cf09e3671f1ca"), 32); - ck_assert_mem_eq(node.private_key, fromhex("624b47150f58dfa44284fbc63c9f99b9b79f808c4955a461f0e2be44eb0be50d"), 32); - ck_assert_mem_eq(node.private_key_extension, fromhex("097aa006d694b165ef37cf23562e5967c96e49255d2f20faae478dee83aa5b02"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key + 1, fromhex("0588589cd9b51dfc028cf225674069cbe52e0e70deb02dc45b79b26ee3548b00"), 32); -} -END_TEST - START_TEST(test_ecdsa_signature) { int res; @@ -2014,7 +1879,6 @@ START_TEST(test_ecdsa_signature) uint8_t pubkey[65]; const ecdsa_curve *curve = &secp256k1; - // sha2(sha2("\x18Bitcoin Signed Message:\n\x0cHello World!")) memcpy(digest, fromhex("de4e9524586d6fce45667f9ff12f661e79870c4105fa0fb58af976619bb11432"), 32); // r = 2: Four points should exist @@ -2968,8 +2832,11 @@ START_TEST(test_mnemonic_to_entropy) a = vectors; b = vectors + 1; while (*a && *b) { - mnemonic_to_entropy(*b,entropy); - ck_assert_mem_eq(entropy, fromhex(*a), strlen(*a) / 2); + int seed_len = mnemonic_to_entropy(*b, entropy); + ck_assert_int_eq(seed_len % 33, 0); + seed_len = seed_len * 4 / 33; + ck_assert_int_eq(seed_len, strlen(*a) / 2); + ck_assert_mem_eq(entropy, fromhex(*a), seed_len); a += 2; b += 2; } } @@ -3810,81 +3677,6 @@ START_TEST(test_ge25519_double_scalarmult_vartime2) } END_TEST -// https://github.com/input-output-hk/cardano-crypto/blob/master/tests/goldens/cardano/crypto/wallet/BIP39-128 -START_TEST(test_ed25519_cardano_sign_vectors) -{ - ed25519_public_key public_key; - ed25519_secret_key secret_key; - ed25519_secret_key secret_key_extension; - ed25519_signature signature; - - static const char *vectors[] = { - "6065a956b1b34145c4416fdc3ba3276801850e91a77a31a7be782463288aea53", // private key - "60ba6e25b1a02157fb69c5d1d7b96c4619736e545447069a6a6f0ba90844bc8e", // private key extension - "64b20fa082b3143d6b5eed42c6ef63f99599d0888afe060620abc1b319935fe1", // public key - "45b1a75fe3119e13c6f60ab9ba674b42f946fdc558e07c83dfa0751c2eba69c79331bd8a4a975662b23628a438a0eba76367e44c12ca91b39ec59063f860f10d", // signature - - "e7d27516538403a53a8b041656a3f570909df641a0ab811fe7d87c9ba02a830c", // private key - "794a2c54ad8b525b781773c87d38cbf4197636bc427a9d551368286fe4c294a4", // private key extension - "95bb82ffd5707716bc65170ab4e8dafeed90fbe0ce9258713b7751e962d931df", // public key - "f2c9171782e7df7665126ac545ae53b05964b0160536efdb545e2460dbbec2b19ec6b338b8f1bf4dfee94360ed024b115e37b1d7e6f3f9ae4beb79539428560f", // signature - - "9b5a3d9a4c60bcd49bb64b72c082b164314d0f61d842f2575fd1d4fb30a28a0c", // private key - "b093e376f41eb7bf80abcd0073a52455d25b5d21815bc758e5f6f81536aedebb", // private key extension - "79fc8154554b97e4c56ef2f9dbb4c1421ff19509688931a1e964bda5dec0f19f", // public key - "2ba1439ae648a7e8da7c9ab1ee6da94fd4ebe37abd0978306e8fba2afa8f111a88a993dbf008bedae9167f4f68409e4c9ddaf02cba12418447b1848907ad800f", // signature - - "52e0c98aa600cfdcd1ff28fcda5227ed87063f4a98547a78b771052cf102b40c", // private key - "6c18d9f8075b1a6a1833540607479bd58b7beb8a83d2bb01ca7ae02452a25803", // private key extension - "dc907c7c06e6314eedd9e18c9f6c6f9cc4e205fb1c70da608234c319f1f7b0d6", // public key - "0cd34f84e0d2fcb1800bdb0e869b9041349955ced66aedbe6bda187ebe8d36a62a05b39647e92fcc42aa7a7368174240afba08b8c81f981a22f942d6bd781602", // signature - - "11fd6462a3a92b35c22703f6f1c124ddcf36b7c2b09cc2784f320e1cfa12ec04", // private key - "c2785803c61c46aeca192a1bb1b7b20a8c4cc7fa01db57fc5d1d8a5473402352", // private key extension - "839775a41876e328986aa26168958bba1176e67819b357eea84afceab8b1db78", // public key - "e41f73db2f8d2896a687802b2be76b7cabb73dfbb4891494883a0cbd9bbb9e5f9d3e14d2d0b06c6674333508496db660936737c0efd9511514147dac79fa4905", // signature - - "5b1e5cad02274ba461f4708d8598d3497faf8fe3e894a379573aa6ac3a03e505", // private key - "ba179d2e3c67aabb486c48d16002b51ad32eab434c738a1550962313b07098cd", // private key extension - "75eb8d197ec8627c85af88e66aa1e49065dd8ac98ed8991db52ece01635dfb76", // public key - "631015357cee3051116b4c2ff4d1c5beb13b6e5023635aa1eeb0563cadf0d4fbc10bd5e31b4a4220c67875558c41b5cc0328104ae39cc7ff20ff0c2bda598906", // signature - - "624b47150f58dfa44284fbc63c9f99b9b79f808c4955a461f0e2be44eb0be50d", // private key - "097aa006d694b165ef37cf23562e5967c96e49255d2f20faae478dee83aa5b02", // private key extension - "0588589cd9b51dfc028cf225674069cbe52e0e70deb02dc45b79b26ee3548b00", // public key - "1de1d275428ba9491a433cd473cd076c027f61e7a8b5391df9dea5cb4bc88d8a57b095906a30b13e68259851a8dd3f57b6f0ffa37a5d3ffc171240f2d404f901", // signature - - 0, 0, - }; - - const char **test_data; - test_data = vectors; - while (*test_data) { - memcpy(secret_key, fromhex(*test_data), 32); - MARK_SECRET_DATA(secret_key, sizeof(secret_key)); - - memcpy(secret_key_extension, fromhex(*(test_data + 1)), 32); - MARK_SECRET_DATA(secret_key_extension, sizeof(secret_key_extension)); - - ed25519_publickey_ext(secret_key, secret_key_extension, public_key); - UNMARK_SECRET_DATA(public_key, sizeof(public_key)); - - ck_assert_mem_eq(public_key, fromhex(*(test_data + 2)), 32); - - const uint8_t * message = (const uint8_t *) "Hello World"; - ed25519_sign_ext(message, 11, secret_key, secret_key_extension, public_key, signature); - UNMARK_SECRET_DATA(signature, sizeof(signature)); - - ck_assert_mem_eq(signature, fromhex(*(test_data + 3)), 64); - - UNMARK_SECRET_DATA(secret_key, sizeof(secret_key)); - UNMARK_SECRET_DATA(secret_key_extension, sizeof(secret_key_extension)); - - test_data += 4; - } -} -END_TEST - static void test_bip32_ecdh_init_node(HDNode *node, const char *seed_str, const char *curve_name) { hdnode_from_seed((const uint8_t *)seed_str, strlen(seed_str), curve_name, node); hdnode_fill_public_key(node); @@ -4957,9 +4749,12 @@ START_TEST(test_rc4_rfc6229) END_TEST #include "test_check_segwit.h" - #include "test_check_cashaddr.h" +#if USE_CARDANO +#include "test_check_cardano.h" +#endif + // define test suite and cases Suite *test_suite(void) { @@ -5040,16 +4835,6 @@ Suite *test_suite(void) tcase_add_test(tc, test_bip32_decred_vector_2); suite_add_tcase(s, tc); - tc = tcase_create("bip32-cardano"); - tcase_add_test(tc, test_bip32_cardano_hdnode_vector_1); - tcase_add_test(tc, test_bip32_cardano_hdnode_vector_2); - tcase_add_test(tc, test_bip32_cardano_hdnode_vector_3); - tcase_add_test(tc, test_bip32_cardano_hdnode_vector_4); - tcase_add_test(tc, test_bip32_cardano_hdnode_vector_5); - tcase_add_test(tc, test_bip32_cardano_hdnode_vector_6); - tcase_add_test(tc, test_bip32_cardano_hdnode_vector_7); - suite_add_tcase(s,tc); - tc = tcase_create("ecdsa"); tcase_add_test(tc, test_ecdsa_signature); suite_add_tcase(s, tc); @@ -5115,11 +4900,8 @@ Suite *test_suite(void) tc = tcase_create("bip39"); tcase_add_test(tc, test_mnemonic); tcase_add_test(tc, test_mnemonic_check); - suite_add_tcase(s, tc); - - tc = tcase_create("bip39-cardano"); tcase_add_test(tc, test_mnemonic_to_entropy); - suite_add_tcase(s,tc); + suite_add_tcase(s, tc); tc = tcase_create("pubkey_validity"); tcase_add_test(tc, test_pubkey_validity); @@ -5176,10 +4958,6 @@ Suite *test_suite(void) tcase_add_test(tc, test_ge25519_double_scalarmult_vartime2); suite_add_tcase(s, tc); - tc = tcase_create("ed25519-cardano"); - tcase_add_test(tc, test_ed25519_cardano_sign_vectors); - suite_add_tcase(s,tc); - tc = tcase_create("script"); tcase_add_test(tc, test_output_script); suite_add_tcase(s, tc); @@ -5222,6 +5000,19 @@ Suite *test_suite(void) tcase_add_test(tc, test_cashaddr); suite_add_tcase(s, tc); +#if USE_CARDANO + tc = tcase_create("bip32-cardano"); + tcase_add_test(tc, test_bip32_cardano_hdnode_vector_1); + tcase_add_test(tc, test_bip32_cardano_hdnode_vector_2); + tcase_add_test(tc, test_bip32_cardano_hdnode_vector_3); + tcase_add_test(tc, test_bip32_cardano_hdnode_vector_4); + tcase_add_test(tc, test_bip32_cardano_hdnode_vector_5); + tcase_add_test(tc, test_bip32_cardano_hdnode_vector_6); + tcase_add_test(tc, test_bip32_cardano_hdnode_vector_7); + tcase_add_test(tc, test_ed25519_cardano_sign_vectors); + suite_add_tcase(s,tc); +#endif + return s; } diff --git a/tests/test_check_cardano.h b/tests/test_check_cardano.h new file mode 100644 index 000000000..58f87b989 --- /dev/null +++ b/tests/test_check_cardano.h @@ -0,0 +1,216 @@ +// https://github.com/input-output-hk/cardano-crypto/blob/master/tests/goldens/cardano/crypto/wallet/BIP39-128 +START_TEST(test_bip32_cardano_hdnode_vector_1) +{ + HDNode node; + + uint8_t seed[66]; + int seed_len = mnemonic_to_entropy("ring crime symptom enough erupt lady behave ramp apart settle citizen junk", seed + 2); + ck_assert_int_eq(seed_len, 132); + hdnode_from_seed_cardano(seed, seed_len / 8, &node); + + ck_assert_mem_eq(node.chain_code, fromhex("739f4b3caca4c9ad4fcd4bdc2ef42c8601af8d6946999ef85ef6ae84f66e72eb"), 32); + ck_assert_mem_eq(node.private_key, fromhex("6065a956b1b34145c4416fdc3ba3276801850e91a77a31a7be782463288aea53"), 32); + ck_assert_mem_eq(node.private_key_extension, fromhex("60ba6e25b1a02157fb69c5d1d7b96c4619736e545447069a6a6f0ba90844bc8e"), 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq(node.public_key + 1, fromhex("64b20fa082b3143d6b5eed42c6ef63f99599d0888afe060620abc1b319935fe1"), 32); +} +END_TEST + +START_TEST(test_bip32_cardano_hdnode_vector_2) +{ + HDNode node; + + uint8_t seed[66]; + int seed_len = mnemonic_to_entropy("ring crime symptom enough erupt lady behave ramp apart settle citizen junk", seed + 2); + ck_assert_int_eq(seed_len, 132); + hdnode_from_seed_cardano(seed, seed_len / 8, &node); + + hdnode_private_ckd_cardano(&node, 0x80000000); + + ck_assert_mem_eq(node.chain_code, fromhex("6755cb82e892d6614c007a5efbceb21d95a5244e269d0e206b48b9a495390b03"), 32); + ck_assert_mem_eq(node.private_key, fromhex("e7d27516538403a53a8b041656a3f570909df641a0ab811fe7d87c9ba02a830c"), 32); + ck_assert_mem_eq(node.private_key_extension, fromhex("794a2c54ad8b525b781773c87d38cbf4197636bc427a9d551368286fe4c294a4"), 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq(node.public_key + 1, fromhex("95bb82ffd5707716bc65170ab4e8dafeed90fbe0ce9258713b7751e962d931df"), 32); +} +END_TEST + +START_TEST(test_bip32_cardano_hdnode_vector_3) +{ + HDNode node; + + uint8_t seed[66]; + int seed_len = mnemonic_to_entropy("ring crime symptom enough erupt lady behave ramp apart settle citizen junk", seed + 2); + ck_assert_int_eq(seed_len, 132); + hdnode_from_seed_cardano(seed, seed_len / 8, &node); + + hdnode_private_ckd_cardano(&node, 0x80000001); + + ck_assert_mem_eq(node.chain_code, fromhex("47a242713bd18608231147c066b6083bfc1e9066fec9f621844c84fed6228a34"), 32); + ck_assert_mem_eq(node.private_key, fromhex("9b5a3d9a4c60bcd49bb64b72c082b164314d0f61d842f2575fd1d4fb30a28a0c"), 32); + ck_assert_mem_eq(node.private_key_extension, fromhex("b093e376f41eb7bf80abcd0073a52455d25b5d21815bc758e5f6f81536aedebb"), 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq(node.public_key + 1, fromhex("79fc8154554b97e4c56ef2f9dbb4c1421ff19509688931a1e964bda5dec0f19f"), 32); +} +END_TEST + +START_TEST(test_bip32_cardano_hdnode_vector_4) +{ + HDNode node; + + uint8_t seed[66]; + int seed_len = mnemonic_to_entropy("ring crime symptom enough erupt lady behave ramp apart settle citizen junk", seed + 2); + ck_assert_int_eq(seed_len, 132); + hdnode_from_seed_cardano(seed, seed_len / 8, &node); + + hdnode_private_ckd_cardano(&node, 0x80000000); + hdnode_private_ckd_cardano(&node, 0x80000001); + + ck_assert_mem_eq(node.chain_code, fromhex("d6798491b9fa4612370ae5ef3c623a0b6872f3ad8f26970885fa67c83bdc425e"), 32); + ck_assert_mem_eq(node.private_key, fromhex("52e0c98aa600cfdcd1ff28fcda5227ed87063f4a98547a78b771052cf102b40c"), 32); + ck_assert_mem_eq(node.private_key_extension, fromhex("6c18d9f8075b1a6a1833540607479bd58b7beb8a83d2bb01ca7ae02452a25803"), 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq(node.public_key + 1, fromhex("dc907c7c06e6314eedd9e18c9f6c6f9cc4e205fb1c70da608234c319f1f7b0d6"), 32); +} +END_TEST + +START_TEST(test_bip32_cardano_hdnode_vector_5) +{ + HDNode node; + + uint8_t seed[66]; + int seed_len = mnemonic_to_entropy("ring crime symptom enough erupt lady behave ramp apart settle citizen junk", seed + 2); + ck_assert_int_eq(seed_len, 132); + hdnode_from_seed_cardano(seed, seed_len / 8, &node); + + hdnode_private_ckd_cardano(&node, 0x80000000); + hdnode_private_ckd_cardano(&node, 0x80000001); + hdnode_private_ckd_cardano(&node, 0x80000002); + + ck_assert_mem_eq(node.chain_code, fromhex("4169a2a32e3618a903e930bd1a713033a38f92389093408394e29ac37a1752ea"), 32); + ck_assert_mem_eq(node.private_key, fromhex("11fd6462a3a92b35c22703f6f1c124ddcf36b7c2b09cc2784f320e1cfa12ec04"), 32); + ck_assert_mem_eq(node.private_key_extension, fromhex("c2785803c61c46aeca192a1bb1b7b20a8c4cc7fa01db57fc5d1d8a5473402352"), 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq(node.public_key + 1, fromhex("839775a41876e328986aa26168958bba1176e67819b357eea84afceab8b1db78"), 32); +} +END_TEST + +START_TEST(test_bip32_cardano_hdnode_vector_6) +{ + HDNode node; + + uint8_t seed[66]; + int seed_len = mnemonic_to_entropy("ring crime symptom enough erupt lady behave ramp apart settle citizen junk", seed + 2); + ck_assert_int_eq(seed_len, 132); + hdnode_from_seed_cardano(seed, seed_len / 8, &node); + + hdnode_private_ckd_cardano(&node, 0x80000000); + hdnode_private_ckd_cardano(&node, 0x80000001); + hdnode_private_ckd_cardano(&node, 0x80000002); + hdnode_private_ckd_cardano(&node, 0x80000002); + + ck_assert_mem_eq(node.chain_code, fromhex("3ae9c99a5925cba2dcf121baf3a0254f3dea23c129f9eb70a8a7e8897c5199ba"), 32); + ck_assert_mem_eq(node.private_key, fromhex("5b1e5cad02274ba461f4708d8598d3497faf8fe3e894a379573aa6ac3a03e505"), 32); + ck_assert_mem_eq(node.private_key_extension, fromhex("ba179d2e3c67aabb486c48d16002b51ad32eab434c738a1550962313b07098cd"), 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq(node.public_key + 1, fromhex("75eb8d197ec8627c85af88e66aa1e49065dd8ac98ed8991db52ece01635dfb76"), 32); +} +END_TEST + +START_TEST(test_bip32_cardano_hdnode_vector_7) +{ + HDNode node; + + uint8_t seed[66]; + int seed_len = mnemonic_to_entropy("ring crime symptom enough erupt lady behave ramp apart settle citizen junk", seed + 2); + ck_assert_int_eq(seed_len, 132); + hdnode_from_seed_cardano(seed, seed_len / 8, &node); + + hdnode_private_ckd_cardano(&node, 0x80000000); + hdnode_private_ckd_cardano(&node, 0x80000001); + hdnode_private_ckd_cardano(&node, 0x80000002); + hdnode_private_ckd_cardano(&node, 0x80000002); + hdnode_private_ckd_cardano(&node, 0xBB9ACA00); + + ck_assert_mem_eq(node.chain_code, fromhex("15c450b86dd7dd83b31951d9ee03eb1a7925161d817bd517c69cf09e3671f1ca"), 32); + ck_assert_mem_eq(node.private_key, fromhex("624b47150f58dfa44284fbc63c9f99b9b79f808c4955a461f0e2be44eb0be50d"), 32); + ck_assert_mem_eq(node.private_key_extension, fromhex("097aa006d694b165ef37cf23562e5967c96e49255d2f20faae478dee83aa5b02"), 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq(node.public_key + 1, fromhex("0588589cd9b51dfc028cf225674069cbe52e0e70deb02dc45b79b26ee3548b00"), 32); +} +END_TEST + +// https://github.com/input-output-hk/cardano-crypto/blob/master/tests/goldens/cardano/crypto/wallet/BIP39-128 +START_TEST(test_ed25519_cardano_sign_vectors) +{ + ed25519_public_key public_key; + ed25519_secret_key secret_key; + ed25519_secret_key secret_key_extension; + ed25519_signature signature; + + static const char *vectors[] = { + "6065a956b1b34145c4416fdc3ba3276801850e91a77a31a7be782463288aea53", // private key + "60ba6e25b1a02157fb69c5d1d7b96c4619736e545447069a6a6f0ba90844bc8e", // private key extension + "64b20fa082b3143d6b5eed42c6ef63f99599d0888afe060620abc1b319935fe1", // public key + "45b1a75fe3119e13c6f60ab9ba674b42f946fdc558e07c83dfa0751c2eba69c79331bd8a4a975662b23628a438a0eba76367e44c12ca91b39ec59063f860f10d", // signature + + "e7d27516538403a53a8b041656a3f570909df641a0ab811fe7d87c9ba02a830c", // private key + "794a2c54ad8b525b781773c87d38cbf4197636bc427a9d551368286fe4c294a4", // private key extension + "95bb82ffd5707716bc65170ab4e8dafeed90fbe0ce9258713b7751e962d931df", // public key + "f2c9171782e7df7665126ac545ae53b05964b0160536efdb545e2460dbbec2b19ec6b338b8f1bf4dfee94360ed024b115e37b1d7e6f3f9ae4beb79539428560f", // signature + + "9b5a3d9a4c60bcd49bb64b72c082b164314d0f61d842f2575fd1d4fb30a28a0c", // private key + "b093e376f41eb7bf80abcd0073a52455d25b5d21815bc758e5f6f81536aedebb", // private key extension + "79fc8154554b97e4c56ef2f9dbb4c1421ff19509688931a1e964bda5dec0f19f", // public key + "2ba1439ae648a7e8da7c9ab1ee6da94fd4ebe37abd0978306e8fba2afa8f111a88a993dbf008bedae9167f4f68409e4c9ddaf02cba12418447b1848907ad800f", // signature + + "52e0c98aa600cfdcd1ff28fcda5227ed87063f4a98547a78b771052cf102b40c", // private key + "6c18d9f8075b1a6a1833540607479bd58b7beb8a83d2bb01ca7ae02452a25803", // private key extension + "dc907c7c06e6314eedd9e18c9f6c6f9cc4e205fb1c70da608234c319f1f7b0d6", // public key + "0cd34f84e0d2fcb1800bdb0e869b9041349955ced66aedbe6bda187ebe8d36a62a05b39647e92fcc42aa7a7368174240afba08b8c81f981a22f942d6bd781602", // signature + + "11fd6462a3a92b35c22703f6f1c124ddcf36b7c2b09cc2784f320e1cfa12ec04", // private key + "c2785803c61c46aeca192a1bb1b7b20a8c4cc7fa01db57fc5d1d8a5473402352", // private key extension + "839775a41876e328986aa26168958bba1176e67819b357eea84afceab8b1db78", // public key + "e41f73db2f8d2896a687802b2be76b7cabb73dfbb4891494883a0cbd9bbb9e5f9d3e14d2d0b06c6674333508496db660936737c0efd9511514147dac79fa4905", // signature + + "5b1e5cad02274ba461f4708d8598d3497faf8fe3e894a379573aa6ac3a03e505", // private key + "ba179d2e3c67aabb486c48d16002b51ad32eab434c738a1550962313b07098cd", // private key extension + "75eb8d197ec8627c85af88e66aa1e49065dd8ac98ed8991db52ece01635dfb76", // public key + "631015357cee3051116b4c2ff4d1c5beb13b6e5023635aa1eeb0563cadf0d4fbc10bd5e31b4a4220c67875558c41b5cc0328104ae39cc7ff20ff0c2bda598906", // signature + + "624b47150f58dfa44284fbc63c9f99b9b79f808c4955a461f0e2be44eb0be50d", // private key + "097aa006d694b165ef37cf23562e5967c96e49255d2f20faae478dee83aa5b02", // private key extension + "0588589cd9b51dfc028cf225674069cbe52e0e70deb02dc45b79b26ee3548b00", // public key + "1de1d275428ba9491a433cd473cd076c027f61e7a8b5391df9dea5cb4bc88d8a57b095906a30b13e68259851a8dd3f57b6f0ffa37a5d3ffc171240f2d404f901", // signature + + 0, 0, + }; + + const char **test_data; + test_data = vectors; + while (*test_data) { + memcpy(secret_key, fromhex(*test_data), 32); + MARK_SECRET_DATA(secret_key, sizeof(secret_key)); + + memcpy(secret_key_extension, fromhex(*(test_data + 1)), 32); + MARK_SECRET_DATA(secret_key_extension, sizeof(secret_key_extension)); + + ed25519_publickey_ext(secret_key, secret_key_extension, public_key); + UNMARK_SECRET_DATA(public_key, sizeof(public_key)); + + ck_assert_mem_eq(public_key, fromhex(*(test_data + 2)), 32); + + const uint8_t * message = (const uint8_t *) "Hello World"; + ed25519_sign_ext(message, 11, secret_key, secret_key_extension, public_key, signature); + UNMARK_SECRET_DATA(signature, sizeof(signature)); + + ck_assert_mem_eq(signature, fromhex(*(test_data + 3)), 64); + + UNMARK_SECRET_DATA(secret_key, sizeof(secret_key)); + UNMARK_SECRET_DATA(secret_key_extension, sizeof(secret_key_extension)); + + test_data += 4; + } +} +END_TEST diff --git a/tests/test_check_cashaddr.h b/tests/test_check_cashaddr.h index de93d0140..cc4608730 100644 --- a/tests/test_check_cashaddr.h +++ b/tests/test_check_cashaddr.h @@ -1,8 +1,3 @@ -#include -#include -#include -#include - #include "cash_addr.h" static const char* valid_cashchecksum[] = { @@ -79,4 +74,3 @@ START_TEST(test_cashaddr) } } END_TEST - diff --git a/tests/test_check_segwit.h b/tests/test_check_segwit.h index 6ebae766f..c0b7ef403 100644 --- a/tests/test_check_segwit.h +++ b/tests/test_check_segwit.h @@ -1,8 +1,3 @@ -#include -#include -#include -#include - #include "segwit_addr.h" static const char* valid_checksum[] = { @@ -187,4 +182,3 @@ START_TEST(test_segwit) } } END_TEST - From ff001a0f12565a0d7d51ad3ce5e11e98db6afc25 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 10 Jul 2018 20:21:18 +0200 Subject: [PATCH 570/627] bip32: drop ugly decitoa --- bip32.c | 45 ++++++++++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/bip32.c b/bip32.c index 8baa885b7..158deaba5 100644 --- a/bip32.c +++ b/bip32.c @@ -364,15 +364,6 @@ int hdnode_private_ckd_cardano(HDNode *inout, uint32_t i) return 1; } -static void decitoa(int val, char *out) { - static char buf[32] = {0}; - int i = 30; - for (; val && i; --i, val /= 10) { - buf[i] = "0123456789"[val % 10]; - } - memcpy(out, &buf[i + 1], strlen(&buf[i + 1]) + 1); -} - int hdnode_from_seed_cardano(uint8_t *seed, int seed_len, HDNode *out) { uint8_t hash[32]; uint8_t cbor[32+2]; @@ -390,9 +381,8 @@ int hdnode_from_seed_cardano(uint8_t *seed, int seed_len, HDNode *out) { cbor[0] = 88; // 64 means its byte array, 24 means its length has 8 bits cbor[1] = 32; // length of the byte array memcpy(cbor + 2, hash, 32); - char salt[21]; - memcpy(salt, "Root Seed Chain xyzw", 16); - char c[21]; + uint8_t salt[21]; + memcpy(salt, "Root Seed Chain ", 16); uint8_t hmac[64]; uint8_t secret[64]; uint8_t public[32]; @@ -403,12 +393,30 @@ int hdnode_from_seed_cardano(uint8_t *seed, int seed_len, HDNode *out) { out->child_num = 0; out->curve = get_curve_by_name(ED25519_CARDANO_NAME); + int saltlen; static CONFIDENTIAL HMAC_SHA512_CTX ctx; for (int i = 1; i <= 1000; i++){ hmac_sha512_Init(&ctx, cbor, 34); - decitoa(i, c); - memcpy(salt + 16, c, strlen(c) + 1); - hmac_sha512_Update(&ctx, (unsigned char *)salt, strlen(salt)); + if (i < 10) { + salt[16] = '0' + (i); + saltlen = 16 + 1; + } else if (i < 100) { + salt[16] = '0' + (i / 10); + salt[17] = '0' + (i % 10); + saltlen = 16 + 2; + } else if (i < 1000) { + salt[16] = '0' + (i / 100); + salt[17] = '0' + ((i / 10) % 10); + salt[18] = '0' + (i % 10); + saltlen = 16 + 3; + } else { + salt[16] = '0' + (i / 1000); + salt[17] = '0' + ((i / 100) % 10); + salt[18] = '0' + ((i / 10) % 10); + salt[19] = '0' + (i % 10); + saltlen = 16 + 4; + } + hmac_sha512_Update(&ctx, salt, saltlen); hmac_sha512_Final(&ctx, hmac); ed25519_publickey(hmac, public); sha512_Raw(hmac, 32, secret); @@ -423,10 +431,9 @@ int hdnode_from_seed_cardano(uint8_t *seed, int seed_len, HDNode *out) { break; } - memzero(hash, 32); - memzero(cbor, 34); - memzero(salt, strlen(salt) + 1); - memzero(c, strlen(c) + 1); + memzero(hash, sizeof(hash)); + memzero(cbor, sizeof(cbor)); + memzero(salt, sizeof(salt)); if (failed) { memzero(seed, sizeof(seed)); From 957b8129bded180c8ac3106e61ff79a1a3df8893 Mon Sep 17 00:00:00 2001 From: Dusan Klinec Date: Wed, 11 Jul 2018 21:26:07 +0200 Subject: [PATCH 571/627] Allow to compile without Valgrind --- Makefile | 3 +++ tests/test_check.c | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/Makefile b/Makefile index 6ccba84e5..5c10ecdf5 100644 --- a/Makefile +++ b/Makefile @@ -23,7 +23,10 @@ CFLAGS += $(OPTFLAGS) \ -Wformat-security \ -Werror +VALGRIND ?= 1 + CFLAGS += -I. +CFLAGS += -DVALGRIND=$(VALGRIND) CFLAGS += -DUSE_ETHEREUM=1 CFLAGS += -DUSE_GRAPHENE=1 CFLAGS += -DUSE_NEM=1 diff --git a/tests/test_check.c b/tests/test_check.c index 7db4e1d63..48601966a 100644 --- a/tests/test_check.c +++ b/tests/test_check.c @@ -31,8 +31,10 @@ #include #include "check_mem.h" +#if VALGRIND #include #include +#endif #include "options.h" @@ -62,6 +64,7 @@ #include "rc4.h" #include "nem.h" +#if VALGRIND /* * This is a clever trick to make Valgrind's Memcheck verify code * is constant-time with respect to secret data. @@ -71,6 +74,10 @@ #define MARK_SECRET_DATA(addr, len) VALGRIND_MAKE_MEM_UNDEFINED(addr, len) /* Call before secret data is freed or to mark non-secret data (public keys or signatures) */ #define UNMARK_SECRET_DATA(addr, len) VALGRIND_MAKE_MEM_DEFINED (addr, len) +#else +#define MARK_SECRET_DATA(addr, len) +#define UNMARK_SECRET_DATA(addr, len) +#endif #define FROMHEX_MAXLEN 512 From 9b2de9584d96a625753db88fb0561fb43c6022c2 Mon Sep 17 00:00:00 2001 From: matejcik Date: Thu, 12 Jul 2018 15:19:51 +0200 Subject: [PATCH 572/627] test_curves: do not rely on CWD --- .travis.yml | 2 +- tests/test_curves.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 751b1d44f..f3b47fbdb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,7 +27,7 @@ script: - ./tests/test_check - CK_TIMEOUT_MULTIPLIER=20 valgrind -q --error-exitcode=1 ./tests/test_check - ./tests/test_openssl 1000 - - cd ./tests ; ITERS=10 $PYTHON -m pytest ; cd .. + - ITERS=10 $PYTHON -m pytest tests/ notifications: webhooks: diff --git a/tests/test_curves.py b/tests/test_curves.py index db779166f..028ecef6a 100755 --- a/tests/test_curves.py +++ b/tests/test_curves.py @@ -40,7 +40,8 @@ points = [ random_iters = int(os.environ.get('ITERS', 1)) -lib = c.cdll.LoadLibrary('./libtrezor-crypto.so') +DIR = os.path.abspath(os.path.dirname(__file__)) +lib = c.cdll.LoadLibrary(os.path.join(DIR, 'libtrezor-crypto.so')) class curve_info(c.Structure): _fields_ = [("bip32_name", c.c_char_p), From 8318ac35fc12765334d71106ce7c9078f8b8ab68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Vejpustek?= Date: Mon, 16 Jul 2018 12:37:47 +0200 Subject: [PATCH 573/627] fix ed25519-donna signature malleability --- ed25519-donna/ed25519.c | 4 +++- ed25519-donna/modm-donna-32bit.c | 12 ++++++++++++ ed25519-donna/modm-donna-32bit.h | 2 ++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/ed25519-donna/ed25519.c b/ed25519-donna/ed25519.c index 880b59d84..7403d3364 100644 --- a/ed25519-donna/ed25519.c +++ b/ed25519-donna/ed25519.c @@ -189,7 +189,9 @@ ED25519_FN(ed25519_sign_open) (const unsigned char *m, size_t mlen, const ed2551 expand256_modm(hram, hash, 64); /* S */ - expand256_modm(S, RS + 32, 32); + expand_raw256_modm(S, RS + 32); + if (!is_reduced256_modm(S)) + return -1; /* SB - H(R,A,m)A */ ge25519_double_scalarmult_vartime(&R, &A, hram, S); diff --git a/ed25519-donna/modm-donna-32bit.c b/ed25519-donna/modm-donna-32bit.c index f658c4308..0086cd2cc 100644 --- a/ed25519-donna/modm-donna-32bit.c +++ b/ed25519-donna/modm-donna-32bit.c @@ -310,6 +310,18 @@ void expand_raw256_modm(bignum256modm out, const unsigned char in[32]) { out[8] = ((x[ 7] >> 16) ) & 0x0000ffff; } +int is_reduced256_modm(const bignum256modm in) +{ + int i; + uint32_t res1 = 0; + uint32_t res2 = 0; + for (i = 8; i >= 0; i--) { + res1 = (res1 << 1) | (in[i] < modm_m[i]); + res2 = (res2 << 1) | (in[i] > modm_m[i]); + } + return res1 > res2; +} + void contract256_modm(unsigned char out[32], const bignum256modm in) { U32TO8_LE(out + 0, (in[0] ) | (in[1] << 30)); U32TO8_LE(out + 4, (in[1] >> 2) | (in[2] << 28)); diff --git a/ed25519-donna/modm-donna-32bit.h b/ed25519-donna/modm-donna-32bit.h index 21306c799..f34633645 100644 --- a/ed25519-donna/modm-donna-32bit.h +++ b/ed25519-donna/modm-donna-32bit.h @@ -44,6 +44,8 @@ void expand256_modm(bignum256modm out, const unsigned char *in, size_t len); void expand_raw256_modm(bignum256modm out, const unsigned char in[32]); +int is_reduced256_modm(const bignum256modm in); + void contract256_modm(unsigned char out[32], const bignum256modm in); void contract256_window4_modm(signed char r[64], const bignum256modm in); From 02a988cd26c16b37a7fbbd44031b5aee7b688ff1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Vejpustek?= Date: Mon, 16 Jul 2018 12:53:55 +0200 Subject: [PATCH 574/627] integrate Wycheproof tests --- .gitmodules | 3 + .travis.yml | 2 +- Makefile | 2 +- README.md | 1 + tests/test_wycheproof.py | 643 +++++++++++++++++++++++++++++++++++++++ tests/wycheproof | 1 + 6 files changed, 650 insertions(+), 2 deletions(-) create mode 100644 .gitmodules create mode 100755 tests/test_wycheproof.py create mode 160000 tests/wycheproof diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..fb12cdfd4 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "tests/wycheproof"] + path = tests/wycheproof + url = https://github.com/google/wycheproof diff --git a/.travis.yml b/.travis.yml index f3b47fbdb..090e8af7e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,7 +19,7 @@ env: - PYTHON=python3 install: - - $PYTHON -m pip install --user pytest ecdsa curve25519-donna + - $PYTHON -m pip install --user pytest ecdsa curve25519-donna pyasn1 script: - make diff --git a/Makefile b/Makefile index 5c10ecdf5..c3ba7f469 100644 --- a/Makefile +++ b/Makefile @@ -86,7 +86,7 @@ tests/test_openssl: tests/test_openssl.o $(OBJS) $(CC) tests/test_openssl.o $(OBJS) $(TESTSSLLIBS) -o tests/test_openssl tests/libtrezor-crypto.so: $(SRCS) - $(CC) $(CFLAGS) -fPIC -shared $(SRCS) -o tests/libtrezor-crypto.so + $(CC) $(CFLAGS) -DAES_VAR -fPIC -shared $(SRCS) -o tests/libtrezor-crypto.so tools: tools/xpubaddrgen tools/mktable tools/bip39bruteforce diff --git a/README.md b/README.md index 556356029..a31c781bb 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,7 @@ These include: - Chacha20-Poly1305 - unit tests (using Check - check.sf.net; in test_check.c) - tests against OpenSSL (in test_openssl.c) +- integrated Wycheproof tests Distibuted under MIT License. diff --git a/tests/test_wycheproof.py b/tests/test_wycheproof.py new file mode 100755 index 000000000..0cc8e3ace --- /dev/null +++ b/tests/test_wycheproof.py @@ -0,0 +1,643 @@ +#!/usr/bin/python +import os +from pyasn1.codec.der.decoder import decode as der_decode +from pyasn1.codec.der.encoder import encode as der_encode +from pyasn1.codec.ber.decoder import decode as ber_decode +from pyasn1.type import univ, namedtype +from binascii import unhexlify, hexlify +import json +import ctypes +import pytest + + +class EcSignature(univ.Sequence): + componentType = namedtype.NamedTypes( + namedtype.NamedType('r', univ.Integer()), + namedtype.NamedType('s', univ.Integer()) + ) + + +class EcKeyInfo(univ.Sequence): + componentType = namedtype.NamedTypes( + namedtype.NamedType('key_type', univ.ObjectIdentifier()), + namedtype.NamedType('curve_name', univ.ObjectIdentifier()) + ) + + +class EcPublicKey(univ.Sequence): + componentType = namedtype.NamedTypes( + namedtype.NamedType('key_info', EcKeyInfo()), + namedtype.NamedType('public_key', univ.BitString()) + ) + + +class EdKeyInfo(univ.Sequence): + componentType = namedtype.NamedTypes( + namedtype.NamedType('key_type', univ.ObjectIdentifier()), + ) + + +class EdPublicKey(univ.Sequence): + componentType = namedtype.NamedTypes( + namedtype.NamedType('key_info', EdKeyInfo()), + namedtype.NamedType('public_key', univ.BitString()) + ) + + +class ParseError(Exception): + pass + + +class NotSupported(Exception): + pass + + +class DataError(Exception): + pass + + +class curve_info(ctypes.Structure): + _fields_ = [("bip32_name", ctypes.c_char_p), ("params", ctypes.c_void_p)] + + +def keys_in_dict(dictionary, keys): + return keys <= set(dictionary.keys()) + + +def parse_eddsa_signature(signature): + if len(signature) != 64: + raise ParseError("Not a valid EdDSA signature") + return signature + + +def parse_ecdh256_privkey(private_key): + if private_key < 0 or private_key.bit_length() > 256: + raise ParseError("Not a valid 256 bit ECDH private key") + return private_key.to_bytes(32, byteorder='big') + + +def parse_signed_hex(string): + if len(string) % 2 == 1: + string = '0' + string + number = int(string, 16) + if int(string[0], 16) & 8: + return -number + else: + return number + + +def parse_result(result): + if result == "valid": + return True + elif result == "invalid": + return False + elif result == "acceptable": + return None + else: + raise DataError() + + +def is_valid_der(data): + try: + structure, _ = der_decode(data) + return data == der_encode(structure) + except: + return False + + +def parse_ed_pubkey(public_key): + try: + public_key, _ = ber_decode(public_key, asn1Spec=EdPublicKey()) + except Exception: + raise ParseError("Not a BER encoded Edwards curve public key") + + if not public_key['key_info']['key_type'] == univ.ObjectIdentifier('1.3.101.112'): + raise ParseError("Not a BER encoded Edwards curve public key") + + public_key = bytes(public_key['public_key'].asOctets()) + + return public_key + + +def parse_ec_pubkey(public_key): + try: + public_key, _ = ber_decode(public_key, asn1Spec=EcPublicKey()) + except Exception: + raise ParseError("Not a BER encoded named elliptic curve public key") + + if not public_key['key_info']['key_type'] == univ.ObjectIdentifier('1.2.840.10045.2.1'): + raise ParseError("Not a BER encoded named elliptic curve public key") + curve_identifier = public_key['key_info']['curve_name'] + curve_name = get_curve_name_by_identifier(curve_identifier) + + if curve_name is None: + raise NotSupported('Unsupported named elliptic curve: {}'.format(curve_identifier)) + + try: + public_key = bytes(public_key['public_key'].asOctets()) + except: + raise ParseError("Not a BER encoded named elliptic curve public key") + + return curve_name, public_key + + +def parse_ecdsa256_signature(signature): + s = signature + if not is_valid_der(signature): + raise ParseError("Not a valid DER") + try: + signature, _ = der_decode(signature, asn1Spec=EcSignature()) + except: + raise ParseError("Not a valid DER encoded ECDSA signature") + try: + r = int(signature['r']).to_bytes(32, byteorder='big') + s = int(signature['s']).to_bytes(32, byteorder='big') + signature = r + s + except: + raise ParseError("Not a valid DER encoded 256 bit ECDSA signature") + return signature + + +def parse_digest(name): + if name == "SHA-256": + return 0 + else: + raise NotSupported("Unsupported hash function: {}".format(name)) + + +def get_curve_by_name(name): + lib.get_curve_by_name.restype = ctypes.c_void_p + curve = lib.get_curve_by_name(bytes(name, 'ascii')) + if curve == None: + return None + curve = ctypes.cast(curve, ctypes.POINTER(curve_info)) + return ctypes.c_void_p(curve.contents.params) + + +def parse_curve_name(name): + if name == 'secp256r1': + return 'nist256p1' + elif name == 'secp256k1': + return 'secp256k1' + elif name == 'curve25519': + return 'curve25519' + else: + return None + + +def get_curve_name_by_identifier(identifier): + if identifier == univ.ObjectIdentifier('1.3.132.0.10'): + return 'secp256k1' + elif identifier == univ.ObjectIdentifier('1.2.840.10045.3.1.7'): + return 'nist256p1' + else: + return None + + +def chacha_poly_encrypt(key, iv, associated_data, plaintext): + context = bytes(context_structure_length) + tag = bytes(16) + ciphertext = bytes(len(plaintext)) + lib.rfc7539_init(context, key, iv) + lib.rfc7539_auth(context, associated_data, len(associated_data)) + lib.chacha20poly1305_encrypt(context, plaintext, ciphertext, len(plaintext)) + lib.rfc7539_finish(context, len(associated_data), len(plaintext), tag) + return ciphertext, tag + + +def chacha_poly_decrypt(key, iv, associated_data, ciphertext, tag): + context = bytes(context_structure_length) + computed_tag = bytes(16) + plaintext = bytes(len(ciphertext)) + lib.rfc7539_init(context, key, iv) + lib.rfc7539_auth(context, associated_data, len(associated_data)) + lib.chacha20poly1305_decrypt(context, ciphertext, plaintext, len(ciphertext)) + lib.rfc7539_finish(context, len(associated_data), len(ciphertext), computed_tag) + return plaintext if tag == computed_tag else False + + +def add_pkcs_padding(data): + padding_length = 16 - len(data) % 16 + return data + bytes([padding_length]*padding_length) + + +def remove_pkcs_padding(data): + padding_length = data[-1] + if not (0 < padding_length <= 16 and data[-padding_length:] == bytes([padding_length]*padding_length)): + return False + else: + return data[:-padding_length] + + +def aes_encrypt_initialise(key, context): + if len(key) == (128/8): + lib.aes_encrypt_key128(key, context) + elif len(key) == (192/8): + lib.aes_encrypt_key192(key, context) + elif len(key) == (256/8): + lib.aes_encrypt_key256(key, context) + else: + raise NotSupported("Unsupported key length: {}".format(len(key)*8)) + + +def aes_cbc_encrypt(key, iv, plaintext): + plaintext = add_pkcs_padding(plaintext) + context = bytes(context_structure_length) + ciphertext = bytes(len(plaintext)) + aes_encrypt_initialise(key, context) + lib.aes_cbc_encrypt(plaintext, ciphertext, len(plaintext), bytes(bytearray(iv)), context) + return ciphertext + + +def aes_decrypt_initialise(key, context): + if len(key) == (128/8): + lib.aes_decrypt_key128(key, context) + elif len(key) == (192/8): + lib.aes_decrypt_key192(key, context) + elif len(key) == (256/8): + lib.aes_decrypt_key256(key, context) + else: + raise NotSupported("Unsupported AES key length: {}".format(len(key)*8)) + + +def aes_cbc_decrypt(key, iv, ciphertext): + context = bytes(context_structure_length) + plaintext = bytes(len(ciphertext)) + aes_decrypt_initialise(key, context) + lib.aes_cbc_decrypt(ciphertext, plaintext, len(ciphertext), iv, context) + return remove_pkcs_padding(plaintext) + + +def load_json_testvectors(filename): + try: + result = json.loads(open(os.path.join(testvectors_directory, filename)).read()) + except: + raise DataError() + return result + + +def generate_aes(filename): + vectors = [] + + data = load_json_testvectors(filename) + + if not keys_in_dict(data, {'algorithm', 'testGroups'}): + raise DataError() + + if data['algorithm'] != 'AES-CBC-PKCS5': + raise DataError() + + for test_group in data['testGroups']: + if not keys_in_dict(test_group, {'tests'}): + raise DataError() + + for test in test_group['tests']: + if not keys_in_dict(test, {'key', 'iv', 'msg', 'ct', 'result'}): + raise DataError() + try: + key = unhexlify(test['key']) + iv = unhexlify(test['iv']) + plaintext = unhexlify(test['msg']) + ciphertext = unhexlify(test['ct']) + result = parse_result(test['result']) + except: + raise DataError() + + if len(key) not in [128/8, 192/8, 256/8]: + continue + + if result is None: + continue + + vectors.append((hexlify(key), hexlify(iv), hexlify(plaintext), hexlify(ciphertext), result)) + return vectors + + +def generate_chacha_poly(filename): + vectors = [] + + data = load_json_testvectors(filename) + + if not keys_in_dict(data, {'algorithm', 'testGroups'}): + raise DataError() + + if data['algorithm'] != 'CHACHA20-POLY1305': + raise DataError() + + for test_group in data['testGroups']: + if not keys_in_dict(test_group, {'tests'}): + raise DataError() + + for test in test_group['tests']: + if not keys_in_dict(test, {'key', 'iv', 'aad', 'msg', 'ct', 'tag', 'result'}): + raise DataError() + try: + key = unhexlify(test['key']) + iv = unhexlify(test['iv']) + associated_data = unhexlify(test['aad']) + plaintext = unhexlify(test['msg']) + ciphertext = unhexlify(test['ct']) + tag = unhexlify(test['tag']) + result = parse_result(test['result']) + except: + raise DataError() + + if result is None: + continue + + vectors.append((hexlify(key), hexlify(iv), hexlify(associated_data), hexlify(plaintext), hexlify(ciphertext), hexlify(tag), result)) + return vectors + + +def generate_curve25519_dh(filename): + vectors = [] + + data = load_json_testvectors(filename) + + if not keys_in_dict(data, {'algorithm', 'testGroups'}): + raise DataError() + + if data['algorithm'] != 'X25519': + raise DataError() + + for test_group in data['testGroups']: + if not keys_in_dict(test_group, {'tests'}): + raise DataError() + + for test in test_group['tests']: + if not keys_in_dict(test, {'public', 'private', 'shared', 'result', 'curve'}): + raise DataError() + + try: + public_key = unhexlify(test['public']) + curve_name = parse_curve_name(test['curve']) + private_key = unhexlify(test['private']) + shared = unhexlify(test['shared']) + result = parse_result(test['result']) + except: + raise DataError() + + if curve_name != 'curve25519': + continue + if result is None: + continue + + vectors.append((hexlify(public_key), hexlify(private_key), hexlify(shared), result)) + + return vectors + +def generate_ecdh(filename): + vectors = [] + + data = load_json_testvectors(filename) + + if not keys_in_dict(data, {'algorithm', 'testGroups'}): + raise DataError() + + if data['algorithm'] != 'ECDH': + raise DataError() + + for test_group in data['testGroups']: + if not keys_in_dict(test_group, {'tests'}): + raise DataError() + + for test in test_group['tests']: + if not keys_in_dict(test, {'public', 'private', 'shared', 'result', 'curve'}): + raise DataError() + + try: + public_key = unhexlify(test['public']) + curve_name = parse_curve_name(test['curve']) + private_key = parse_signed_hex(test['private']) + shared = unhexlify(test['shared']) + result = parse_result(test['result']) + except: + raise DataError() + + try: + private_key = parse_ecdh256_privkey(private_key) + except ParseError: + continue + + try: + key_curve_name, public_key = parse_ec_pubkey(public_key) + except NotSupported: + continue + except ParseError: + continue + + if key_curve_name != curve_name: + continue + if result is None: + continue + + vectors.append((curve_name, hexlify(public_key), hexlify(private_key), hexlify(shared), result)) + + return vectors + + +def generate_ecdsa(filename): + vectors = [] + + data = load_json_testvectors(filename) + + if not keys_in_dict(data, {'algorithm', 'testGroups'}): + raise DataError() + + if data['algorithm'] != 'ECDSA': + raise DataError() + + for test_group in data['testGroups']: + if not keys_in_dict(test_group, {'tests', 'keyDer', 'sha'}): + raise DataError() + + try: + public_key = unhexlify(test_group['keyDer']) + except: + raise DataError() + + try: + curve_name, public_key = parse_ec_pubkey(public_key) + except NotSupported: + continue + except ParseError: + continue + + try: + hasher = parse_digest(test_group['sha']) + except NotSupported: + continue + + for test in test_group['tests']: + if not keys_in_dict(test, {'sig', 'msg', 'result'}): + raise DataError() + + try: + signature = unhexlify(test['sig']) + message = unhexlify(test['msg']) + result = parse_result(test['result']) + except: + raise DataError() + + if result is None: + continue + + try: + signature = parse_ecdsa256_signature(signature) + except ParseError: + continue + + vectors.append((curve_name, hexlify(public_key), hasher, hexlify(message), hexlify(signature), result)) + + return vectors + + +def generate_eddsa(filename): + vectors = [] + + data = load_json_testvectors(filename) + + + if not keys_in_dict(data, {'algorithm', 'testGroups'}): + raise DataError() + + if data['algorithm'] != 'EDDSA': + raise DataError() + + for test_group in data['testGroups']: + if not keys_in_dict(test_group, {'tests', 'keyDer'}): + raise DataError() + + try: + public_key = unhexlify(test_group['keyDer']) + except: + raise DataError() + + try: + public_key = parse_ed_pubkey(public_key) + except ParseError: + continue + + for test in test_group['tests']: + if not keys_in_dict(test, {'sig', 'msg', 'result'}): + raise DataError() + + try: + signature = unhexlify(test['sig']) + message = unhexlify(test['msg']) + result = parse_result(test['result']) + except: + raise DataError() + + if result is None: + continue + + try: + signature = parse_eddsa_signature(signature) + except ParseError: + continue + + vectors.append((hexlify(public_key), hexlify(message), hexlify(signature), result)) + + return vectors + + +dir = os.path.abspath(os.path.dirname(__file__)) +lib = ctypes.cdll.LoadLibrary(os.path.join(dir, 'libtrezor-crypto.so')) +testvectors_directory = os.path.join(dir, 'wycheproof/testvectors') +context_structure_length = 1024 + +ecdh_vectors = generate_ecdh("ecdh_test.json") +curve25519_dh_vectors = generate_curve25519_dh("x25519_test.json") +eddsa_vectors = generate_eddsa("eddsa_test.json") +ecdsa_vectors = generate_ecdsa("ecdsa_test.json") + generate_ecdsa("ecdsa_secp256k1_sha256_test.json") + generate_ecdsa("ecdsa_secp256r1_sha256_test.json") +ecdh_vectors = generate_ecdh("ecdh_test.json") + generate_ecdh("ecdh_secp256k1_test.json") + generate_ecdh("ecdh_secp256r1_test.json") +chacha_poly_vectors = generate_chacha_poly("chacha20_poly1305_test.json") +aes_vectors = generate_aes("aes_cbc_pkcs5_test.json") + + +@pytest.mark.parametrize("public_key, message, signature, result", eddsa_vectors) +def test_eddsa(public_key, message, signature, result): + public_key = unhexlify(public_key) + signature = unhexlify(signature) + message = unhexlify(message) + + computed_result = lib.ed25519_sign_open(message, len(message), public_key, signature) == 0 + assert result == computed_result + + +@pytest.mark.parametrize("curve_name, public_key, hasher, message, signature, result", ecdsa_vectors) +def test_ecdsa(curve_name, public_key, hasher, message, signature, result): + curve = get_curve_by_name(curve_name) + if curve is None: + raise NotSupported("Curve not supported: {}".format(curve_Name)) + + public_key = unhexlify(public_key) + signature = unhexlify(signature) + message = unhexlify(message) + + computed_result = lib.ecdsa_verify(curve, hasher, public_key, signature, message, len(message)) == 0 + assert result == computed_result + + +@pytest.mark.parametrize("public_key, private_key, shared, result", curve25519_dh_vectors) +def test_curve25519_dh(public_key, private_key, shared, result): + public_key = unhexlify(public_key) + private_key = unhexlify(private_key) + shared = unhexlify(shared) + + computed_shared = bytes([0]*32) + lib.curve25519_scalarmult(computed_shared, private_key, public_key) + computed_result = shared == computed_shared + assert result == computed_result + + +@pytest.mark.parametrize("curve_name, public_key, private_key, shared, result", ecdh_vectors) +def test_ecdh(curve_name, public_key, private_key, shared, result): + curve = get_curve_by_name(curve_name) + if curve is None: + raise NotSupported("Curve not supported: {}".format(curve_name)) + + public_key = unhexlify(public_key) + private_key = unhexlify(private_key) + shared = unhexlify(shared) + + computed_shared = bytes([0]*2*32) + lib.ecdh_multiply(curve, private_key, public_key, computed_shared) + computed_shared = computed_shared[1:33] + computed_result = shared == computed_shared + assert result == computed_result + + +@pytest.mark.parametrize("key, iv, associated_data, plaintext, ciphertext, tag, result", chacha_poly_vectors) +def test_chacha_poly(key, iv, associated_data, plaintext, ciphertext, tag, result): + key = unhexlify(key) + iv = unhexlify(iv) + associated_data = unhexlify(associated_data) + plaintext = unhexlify(plaintext) + ciphertext = unhexlify(ciphertext) + tag = unhexlify(tag) + + computed_ciphertext, computed_tag = chacha_poly_encrypt(key, iv, associated_data, plaintext) + computed_result = ciphertext == computed_ciphertext and tag == computed_tag + assert result == computed_result + + computed_plaintext = chacha_poly_decrypt(key, iv, associated_data, ciphertext, tag) + computed_result = plaintext == computed_plaintext + assert result == computed_result + + +@pytest.mark.parametrize("key, iv, plaintext, ciphertext, result", aes_vectors) +def test_aes(key, iv, plaintext, ciphertext, result): + key = unhexlify(key) + iv = unhexlify(iv) + plaintext = unhexlify(plaintext) + ciphertext = unhexlify(ciphertext) + + computed_ciphertext = aes_cbc_encrypt(key, iv, plaintext) + computed_result = ciphertext == computed_ciphertext + assert result == computed_result + + computed_plaintext = aes_cbc_decrypt(key, bytes(iv), ciphertext) + computed_result = plaintext == computed_plaintext + assert result == computed_result diff --git a/tests/wycheproof b/tests/wycheproof new file mode 160000 index 000000000..2904be69e --- /dev/null +++ b/tests/wycheproof @@ -0,0 +1 @@ +Subproject commit 2904be69e9d666bf3064fdc15093747e695cfae6 From 2de6d876a35d208a351b478ead529bcefc11dfff Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 16 Jul 2018 14:38:09 +0200 Subject: [PATCH 575/627] python: reformat python scripts using black --- setup.py | 48 +++--- tests/test_curves.py | 160 +++++++++++++----- tests/test_wycheproof.py | 354 ++++++++++++++++++++++++--------------- 3 files changed, 355 insertions(+), 207 deletions(-) diff --git a/setup.py b/setup.py index ea76ea7ce..24a639d69 100755 --- a/setup.py +++ b/setup.py @@ -1,37 +1,39 @@ #!/usr/bin/python from distutils.core import setup from distutils.extension import Extension + from Cython.Build import cythonize from Cython.Distutils import build_ext srcs = [ - 'nist256p1', - 'base58', - 'bignum', - 'bip32', - 'ecdsa', - 'curve25519', - 'hmac', - 'rand', - 'ripemd160', - 'secp256k1', - 'sha2', + "nist256p1", + "base58", + "bignum", + "bip32", + "ecdsa", + "curve25519", + "hmac", + "rand", + "ripemd160", + "secp256k1", + "sha2", ] extensions = [ - Extension('TrezorCrypto', - sources = ['TrezorCrypto.pyx', 'c.pxd'] + [ x + '.c' for x in srcs ], - extra_compile_args = [], - ) + Extension( + "TrezorCrypto", + sources=["TrezorCrypto.pyx", "c.pxd"] + [x + ".c" for x in srcs], + extra_compile_args=[], + ) ] setup( - name = 'TrezorCrypto', - version = '0.0.0', - description = 'Cython wrapper around trezor-crypto library', - author = 'Pavol Rusnak', - author_email = 'stick@satoshilabs.com', - url = 'https://github.com/trezor/trezor-crypto', - cmdclass = {'build_ext': build_ext}, - ext_modules = cythonize(extensions), + name="TrezorCrypto", + version="0.0.0", + description="Cython wrapper around trezor-crypto library", + author="Pavol Rusnak", + author_email="stick@satoshilabs.com", + url="https://github.com/trezor/trezor-crypto", + cmdclass={"build_ext": build_ext}, + ext_modules=cythonize(extensions), ) diff --git a/tests/test_curves.py b/tests/test_curves.py index 028ecef6a..a6db9cee6 100755 --- a/tests/test_curves.py +++ b/tests/test_curves.py @@ -1,13 +1,15 @@ #!/usr/bin/py.test +import binascii import ctypes as c -import curve25519 -import random -import ecdsa import hashlib -import binascii import os +import random + +import curve25519 +import ecdsa import pytest + def bytes2num(s): res = 0 for i, b in enumerate(reversed(bytearray(s))): @@ -15,10 +17,8 @@ def bytes2num(s): return res -curves = { - 'nist256p1': ecdsa.curves.NIST256p, - 'secp256k1': ecdsa.curves.SECP256k1 -} +curves = {"nist256p1": ecdsa.curves.NIST256p, "secp256k1": ecdsa.curves.SECP256k1} + class Point: def __init__(self, name, x, y): @@ -26,30 +26,70 @@ class Point: self.x = x self.y = y + points = [ - Point('secp256k1', 0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798, 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8), - Point('secp256k1', 0x1, 0x4218f20ae6c646b363db68605822fb14264ca8d2587fdd6fbc750d587e76a7ee), - Point('secp256k1', 0x2, 0x66fbe727b2ba09e09f5a98d70a5efce8424c5fa425bbda1c511f860657b8535e), - Point('secp256k1', 0x1b,0x1adcea1cf831b0ad1653e769d1a229091d0cc68d4b0328691b9caacc76e37c90), - Point('nist256p1', 0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296, 0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5), - Point('nist256p1', 0x0, 0x66485c780e2f83d72433bd5d84a06bb6541c2af31dae871728bf856a174f93f4), - Point('nist256p1', 0x0, 0x99b7a386f1d07c29dbcc42a27b5f9449abe3d50de25178e8d7407a95e8b06c0b), - Point('nist256p1', 0xaf8bbdfe8cdd5577acbf345b543d28cf402f4e94d3865b97ea0787f2d3aa5d22,0x35802b8b376b995265918b078bc109c21a535176585c40f519aca52d6afc147c), - Point('nist256p1', 0x80000, 0x580610071f440f0dcc14a22e2d5d5afc1224c0cd11a3b4b51b8ecd2224ee1ce2) + Point( + "secp256k1", + 0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798, + 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8, + ), + Point( + "secp256k1", + 0x1, + 0x4218f20ae6c646b363db68605822fb14264ca8d2587fdd6fbc750d587e76a7ee, + ), + Point( + "secp256k1", + 0x2, + 0x66fbe727b2ba09e09f5a98d70a5efce8424c5fa425bbda1c511f860657b8535e, + ), + Point( + "secp256k1", + 0x1b, + 0x1adcea1cf831b0ad1653e769d1a229091d0cc68d4b0328691b9caacc76e37c90, + ), + Point( + "nist256p1", + 0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296, + 0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5, + ), + Point( + "nist256p1", + 0x0, + 0x66485c780e2f83d72433bd5d84a06bb6541c2af31dae871728bf856a174f93f4, + ), + Point( + "nist256p1", + 0x0, + 0x99b7a386f1d07c29dbcc42a27b5f9449abe3d50de25178e8d7407a95e8b06c0b, + ), + Point( + "nist256p1", + 0xaf8bbdfe8cdd5577acbf345b543d28cf402f4e94d3865b97ea0787f2d3aa5d22, + 0x35802b8b376b995265918b078bc109c21a535176585c40f519aca52d6afc147c, + ), + Point( + "nist256p1", + 0x80000, + 0x580610071f440f0dcc14a22e2d5d5afc1224c0cd11a3b4b51b8ecd2224ee1ce2, + ), ] -random_iters = int(os.environ.get('ITERS', 1)) +random_iters = int(os.environ.get("ITERS", 1)) DIR = os.path.abspath(os.path.dirname(__file__)) -lib = c.cdll.LoadLibrary(os.path.join(DIR, 'libtrezor-crypto.so')) +lib = c.cdll.LoadLibrary(os.path.join(DIR, "libtrezor-crypto.so")) + class curve_info(c.Structure): - _fields_ = [("bip32_name", c.c_char_p), - ("params", c.c_void_p)] + _fields_ = [("bip32_name", c.c_char_p), ("params", c.c_void_p)] + + lib.get_curve_by_name.restype = c.POINTER(curve_info) BIGNUM = c.c_uint32 * 9 + class Random(random.Random): def randbytes(self, n): buf = (c.c_uint8 * n)() @@ -74,36 +114,40 @@ def int2bn(x, bn_type=BIGNUM): def bn2int(b): x = 0 for i in range(len(b)): - x += (b[i] << (30 * i)) + x += b[i] << (30 * i) return x @pytest.fixture(params=range(random_iters)) def r(request): seed = request.param - return Random(seed + int(os.environ.get('SEED', 0))) + return Random(seed + int(os.environ.get("SEED", 0))) @pytest.fixture(params=list(sorted(curves))) def curve(request): name = request.param curve_ptr = lib.get_curve_by_name(bytes(name, "ascii")).contents.params - assert curve_ptr, 'curve {} not found'.format(name) + assert curve_ptr, "curve {} not found".format(name) curve_obj = curves[name] curve_obj.ptr = c.c_void_p(curve_ptr) curve_obj.p = curve_obj.curve.p() # shorthand return curve_obj + @pytest.fixture(params=points) def point(request): name = request.param.curve curve_ptr = lib.get_curve_by_name(bytes(name, "ascii")).contents.params - assert curve_ptr, 'curve {} not found'.format(name) + assert curve_ptr, "curve {} not found".format(name) curve_obj = curves[name] curve_obj.ptr = c.c_void_p(curve_ptr) - curve_obj.p = ecdsa.ellipticcurve.Point(curve_obj.curve, request.param.x, request.param.y) + curve_obj.p = ecdsa.ellipticcurve.Point( + curve_obj.curve, request.param.x, request.param.y + ) return curve_obj + def test_inverse(curve, r): x = r.randrange(1, curve.p) y = int2bn(x) @@ -138,7 +182,7 @@ def test_is_equal(curve, r): def test_is_zero(curve, r): - x = r.randrange(0, curve.p); + x = r.randrange(0, curve.p) assert lib.bn_is_zero(int2bn(x)) == (not x) @@ -156,7 +200,7 @@ def test_simple_comparisons(): def test_mult_half(curve, r): - x = r.randrange(0, 2*curve.p) + x = r.randrange(0, 2 * curve.p) y = int2bn(x) lib.bn_mult_half(y, int2bn(curve.p)) y = bn2int(y) @@ -172,7 +216,7 @@ def test_subtractmod(curve, r): z = int2bn(0) lib.bn_subtractmod(int2bn(x), int2bn(y), z, int2bn(curve.p)) z = bn2int(z) - z_ = x + 2*curve.p - y + z_ = x + 2 * curve.p - y assert z == z_ @@ -219,7 +263,7 @@ def test_multiply(curve, r): p_ = int2bn(curve.p) lib.bn_multiply(k, z_, p_) z_ = bn2int(z_) - assert z_ < 2*curve.p + assert z_ < 2 * curve.p if z_ >= curve.p: z_ = z_ - curve.p assert z_ == z @@ -249,36 +293,51 @@ def test_multiply2(curve, r): def test_fast_mod(curve, r): - x = r.randrange(0, 128*curve.p) + x = r.randrange(0, 128 * curve.p) y = int2bn(x) lib.bn_fast_mod(y, int2bn(curve.p)) y = bn2int(y) - assert y < 2*curve.p + assert y < 2 * curve.p if y >= curve.p: y -= curve.p assert x % curve.p == y def test_mod(curve, r): - x = r.randrange(0, 2*curve.p) + x = r.randrange(0, 2 * curve.p) y = int2bn(x) lib.bn_mod(y, int2bn(curve.p)) assert bn2int(y) == x % curve.p + def test_mod_specific(curve): p = curve.p - for x in [0, 1, 2, p - 2, p - 1, p, p + 1, p + 2, 2*p - 2, 2*p - 1]: + for x in [0, 1, 2, p - 2, p - 1, p, p + 1, p + 2, 2 * p - 2, 2 * p - 1]: y = int2bn(x) lib.bn_mod(y, int2bn(curve.p)) assert bn2int(y) == x % p + POINT = BIGNUM * 2 -to_POINT = lambda p: POINT(int2bn(p.x()), int2bn(p.y())) -from_POINT = lambda p: (bn2int(p[0]), bn2int(p[1])) + + +def to_POINT(p): + return POINT(int2bn(p.x()), int2bn(p.y())) + + +def from_POINT(p): + return lambda p: (bn2int(p[0]), bn2int(p[1])) + JACOBIAN = BIGNUM * 3 -to_JACOBIAN = lambda jp: JACOBIAN(int2bn(jp[0]), int2bn(jp[1]), int2bn(jp[2])) -from_JACOBIAN = lambda p: (bn2int(p[0]), bn2int(p[1]), bn2int(p[2])) + + +def to_JACOBIAN(jp): + return JACOBIAN(int2bn(jp[0]), int2bn(jp[1]), int2bn(jp[2])) + + +def from_JACOBIAN(p): + return (bn2int(p[0]), bn2int(p[1]), bn2int(p[2])) def test_point_multiply(curve, r): @@ -294,7 +353,7 @@ def test_point_multiply(curve, r): def test_point_add(curve, r): p1 = r.randpoint(curve) p2 = r.randpoint(curve) - #print '-' * 80 + # print '-' * 80 q = p1 + p2 q1 = to_POINT(p1) q2 = to_POINT(p2) @@ -332,7 +391,7 @@ def test_cond_negate(curve, r): lib.conditional_negate(0, a, int2bn(curve.p)) assert bn2int(a) == x lib.conditional_negate(-1, a, int2bn(curve.p)) - assert bn2int(a) == 2*curve.p - x + assert bn2int(a) == 2 * curve.p - x def test_jacobian_add(curve, r): @@ -348,6 +407,7 @@ def test_jacobian_add(curve, r): p_ = p1 + p2 assert (p_.x(), p_.y()) == q + def test_jacobian_add_double(curve, r): p1 = r.randpoint(curve) p2 = p1 @@ -361,6 +421,7 @@ def test_jacobian_add_double(curve, r): p_ = p1 + p2 assert (p_.x(), p_.y()) == q + def test_jacobian_double(curve, r): p = r.randpoint(curve) p2 = p.double() @@ -373,6 +434,7 @@ def test_jacobian_double(curve, r): q = from_POINT(q) assert (p2.x(), p2.y()) == q + def sigdecode(sig, _): return map(bytes2num, [sig[:32], sig[32:]]) @@ -385,15 +447,17 @@ def test_sign(curve, r): lib.ecdsa_sign_digest(curve.ptr, priv, digest, sig, c.c_void_p(0), c.c_void_p(0)) exp = bytes2num(priv) - sk = ecdsa.SigningKey.from_secret_exponent(exp, curve, - hashfunc=hashlib.sha256) + sk = ecdsa.SigningKey.from_secret_exponent(exp, curve, hashfunc=hashlib.sha256) vk = sk.get_verifying_key() - sig_ref = sk.sign_digest_deterministic(digest, hashfunc=hashlib.sha256, sigencode=ecdsa.util.sigencode_string_canonize) + sig_ref = sk.sign_digest_deterministic( + digest, hashfunc=hashlib.sha256, sigencode=ecdsa.util.sigencode_string_canonize + ) assert binascii.hexlify(sig) == binascii.hexlify(sig_ref) assert vk.verify_digest(sig, digest, sigdecode) + def test_validate_pubkey(curve, r): p = r.randpoint(curve) assert lib.ecdsa_validate_pubkey(curve.ptr, to_POINT(p)) @@ -431,9 +495,13 @@ def test_curve25519_pubkey(r): def test_curve25519_scalarmult_from_gpg(r): - sec = binascii.unhexlify('4a1e76f133afb29dbc7860bcbc16d0e829009cc15c2f81ed26de1179b1d9c938') - pub = binascii.unhexlify('5d6fc75c016e85b17f54e0128a216d5f9229f25bac1ec85cecab8daf48621b31') + sec = binascii.unhexlify( + "4a1e76f133afb29dbc7860bcbc16d0e829009cc15c2f81ed26de1179b1d9c938" + ) + pub = binascii.unhexlify( + "5d6fc75c016e85b17f54e0128a216d5f9229f25bac1ec85cecab8daf48621b31" + ) res = r.randbytes(32) lib.curve25519_scalarmult(res, sec[::-1], pub[::-1]) - expected = 'a93dbdb23e5c99da743e203bd391af79f2b83fb8d0fd6ec813371c71f08f2d4d' + expected = "a93dbdb23e5c99da743e203bd391af79f2b83fb8d0fd6ec813371c71f08f2d4d" assert binascii.hexlify(bytearray(res)) == bytes(expected, "ascii") diff --git a/tests/test_wycheproof.py b/tests/test_wycheproof.py index 0cc8e3ace..08fe1ab9a 100755 --- a/tests/test_wycheproof.py +++ b/tests/test_wycheproof.py @@ -1,46 +1,47 @@ #!/usr/bin/python +import ctypes +import json import os +from binascii import hexlify, unhexlify + +import pytest +from pyasn1.codec.ber.decoder import decode as ber_decode from pyasn1.codec.der.decoder import decode as der_decode from pyasn1.codec.der.encoder import encode as der_encode -from pyasn1.codec.ber.decoder import decode as ber_decode -from pyasn1.type import univ, namedtype -from binascii import unhexlify, hexlify -import json -import ctypes -import pytest +from pyasn1.type import namedtype, univ class EcSignature(univ.Sequence): componentType = namedtype.NamedTypes( - namedtype.NamedType('r', univ.Integer()), - namedtype.NamedType('s', univ.Integer()) + namedtype.NamedType("r", univ.Integer()), + namedtype.NamedType("s", univ.Integer()), ) class EcKeyInfo(univ.Sequence): componentType = namedtype.NamedTypes( - namedtype.NamedType('key_type', univ.ObjectIdentifier()), - namedtype.NamedType('curve_name', univ.ObjectIdentifier()) + namedtype.NamedType("key_type", univ.ObjectIdentifier()), + namedtype.NamedType("curve_name", univ.ObjectIdentifier()), ) class EcPublicKey(univ.Sequence): componentType = namedtype.NamedTypes( - namedtype.NamedType('key_info', EcKeyInfo()), - namedtype.NamedType('public_key', univ.BitString()) + namedtype.NamedType("key_info", EcKeyInfo()), + namedtype.NamedType("public_key", univ.BitString()), ) class EdKeyInfo(univ.Sequence): componentType = namedtype.NamedTypes( - namedtype.NamedType('key_type', univ.ObjectIdentifier()), + namedtype.NamedType("key_type", univ.ObjectIdentifier()) ) class EdPublicKey(univ.Sequence): componentType = namedtype.NamedTypes( - namedtype.NamedType('key_info', EdKeyInfo()), - namedtype.NamedType('public_key', univ.BitString()) + namedtype.NamedType("key_info", EdKeyInfo()), + namedtype.NamedType("public_key", univ.BitString()), ) @@ -73,12 +74,12 @@ def parse_eddsa_signature(signature): def parse_ecdh256_privkey(private_key): if private_key < 0 or private_key.bit_length() > 256: raise ParseError("Not a valid 256 bit ECDH private key") - return private_key.to_bytes(32, byteorder='big') + return private_key.to_bytes(32, byteorder="big") def parse_signed_hex(string): if len(string) % 2 == 1: - string = '0' + string + string = "0" + string number = int(string, 16) if int(string[0], 16) & 8: return -number @@ -111,10 +112,10 @@ def parse_ed_pubkey(public_key): except Exception: raise ParseError("Not a BER encoded Edwards curve public key") - if not public_key['key_info']['key_type'] == univ.ObjectIdentifier('1.3.101.112'): + if not public_key["key_info"]["key_type"] == univ.ObjectIdentifier("1.3.101.112"): raise ParseError("Not a BER encoded Edwards curve public key") - public_key = bytes(public_key['public_key'].asOctets()) + public_key = bytes(public_key["public_key"].asOctets()) return public_key @@ -125,16 +126,20 @@ def parse_ec_pubkey(public_key): except Exception: raise ParseError("Not a BER encoded named elliptic curve public key") - if not public_key['key_info']['key_type'] == univ.ObjectIdentifier('1.2.840.10045.2.1'): + if not public_key["key_info"]["key_type"] == univ.ObjectIdentifier( + "1.2.840.10045.2.1" + ): raise ParseError("Not a BER encoded named elliptic curve public key") - curve_identifier = public_key['key_info']['curve_name'] + curve_identifier = public_key["key_info"]["curve_name"] curve_name = get_curve_name_by_identifier(curve_identifier) if curve_name is None: - raise NotSupported('Unsupported named elliptic curve: {}'.format(curve_identifier)) + raise NotSupported( + "Unsupported named elliptic curve: {}".format(curve_identifier) + ) try: - public_key = bytes(public_key['public_key'].asOctets()) + public_key = bytes(public_key["public_key"].asOctets()) except: raise ParseError("Not a BER encoded named elliptic curve public key") @@ -150,8 +155,8 @@ def parse_ecdsa256_signature(signature): except: raise ParseError("Not a valid DER encoded ECDSA signature") try: - r = int(signature['r']).to_bytes(32, byteorder='big') - s = int(signature['s']).to_bytes(32, byteorder='big') + r = int(signature["r"]).to_bytes(32, byteorder="big") + s = int(signature["s"]).to_bytes(32, byteorder="big") signature = r + s except: raise ParseError("Not a valid DER encoded 256 bit ECDSA signature") @@ -167,29 +172,29 @@ def parse_digest(name): def get_curve_by_name(name): lib.get_curve_by_name.restype = ctypes.c_void_p - curve = lib.get_curve_by_name(bytes(name, 'ascii')) - if curve == None: + curve = lib.get_curve_by_name(bytes(name, "ascii")) + if curve is None: return None curve = ctypes.cast(curve, ctypes.POINTER(curve_info)) return ctypes.c_void_p(curve.contents.params) def parse_curve_name(name): - if name == 'secp256r1': - return 'nist256p1' - elif name == 'secp256k1': - return 'secp256k1' - elif name == 'curve25519': - return 'curve25519' + if name == "secp256r1": + return "nist256p1" + elif name == "secp256k1": + return "secp256k1" + elif name == "curve25519": + return "curve25519" else: return None def get_curve_name_by_identifier(identifier): - if identifier == univ.ObjectIdentifier('1.3.132.0.10'): - return 'secp256k1' - elif identifier == univ.ObjectIdentifier('1.2.840.10045.3.1.7'): - return 'nist256p1' + if identifier == univ.ObjectIdentifier("1.3.132.0.10"): + return "secp256k1" + elif identifier == univ.ObjectIdentifier("1.2.840.10045.3.1.7"): + return "nist256p1" else: return None @@ -218,26 +223,29 @@ def chacha_poly_decrypt(key, iv, associated_data, ciphertext, tag): def add_pkcs_padding(data): padding_length = 16 - len(data) % 16 - return data + bytes([padding_length]*padding_length) + return data + bytes([padding_length] * padding_length) def remove_pkcs_padding(data): padding_length = data[-1] - if not (0 < padding_length <= 16 and data[-padding_length:] == bytes([padding_length]*padding_length)): + if not ( + 0 < padding_length <= 16 + and data[-padding_length:] == bytes([padding_length] * padding_length) + ): return False else: return data[:-padding_length] def aes_encrypt_initialise(key, context): - if len(key) == (128/8): + if len(key) == (128 / 8): lib.aes_encrypt_key128(key, context) - elif len(key) == (192/8): + elif len(key) == (192 / 8): lib.aes_encrypt_key192(key, context) - elif len(key) == (256/8): + elif len(key) == (256 / 8): lib.aes_encrypt_key256(key, context) else: - raise NotSupported("Unsupported key length: {}".format(len(key)*8)) + raise NotSupported("Unsupported key length: {}".format(len(key) * 8)) def aes_cbc_encrypt(key, iv, plaintext): @@ -245,19 +253,21 @@ def aes_cbc_encrypt(key, iv, plaintext): context = bytes(context_structure_length) ciphertext = bytes(len(plaintext)) aes_encrypt_initialise(key, context) - lib.aes_cbc_encrypt(plaintext, ciphertext, len(plaintext), bytes(bytearray(iv)), context) + lib.aes_cbc_encrypt( + plaintext, ciphertext, len(plaintext), bytes(bytearray(iv)), context + ) return ciphertext def aes_decrypt_initialise(key, context): - if len(key) == (128/8): + if len(key) == (128 / 8): lib.aes_decrypt_key128(key, context) - elif len(key) == (192/8): + elif len(key) == (192 / 8): lib.aes_decrypt_key192(key, context) - elif len(key) == (256/8): + elif len(key) == (256 / 8): lib.aes_decrypt_key256(key, context) else: - raise NotSupported("Unsupported AES key length: {}".format(len(key)*8)) + raise NotSupported("Unsupported AES key length: {}".format(len(key) * 8)) def aes_cbc_decrypt(key, iv, ciphertext): @@ -281,35 +291,43 @@ def generate_aes(filename): data = load_json_testvectors(filename) - if not keys_in_dict(data, {'algorithm', 'testGroups'}): + if not keys_in_dict(data, {"algorithm", "testGroups"}): raise DataError() - if data['algorithm'] != 'AES-CBC-PKCS5': + if data["algorithm"] != "AES-CBC-PKCS5": raise DataError() - for test_group in data['testGroups']: - if not keys_in_dict(test_group, {'tests'}): + for test_group in data["testGroups"]: + if not keys_in_dict(test_group, {"tests"}): raise DataError() - for test in test_group['tests']: - if not keys_in_dict(test, {'key', 'iv', 'msg', 'ct', 'result'}): + for test in test_group["tests"]: + if not keys_in_dict(test, {"key", "iv", "msg", "ct", "result"}): raise DataError() try: - key = unhexlify(test['key']) - iv = unhexlify(test['iv']) - plaintext = unhexlify(test['msg']) - ciphertext = unhexlify(test['ct']) - result = parse_result(test['result']) + key = unhexlify(test["key"]) + iv = unhexlify(test["iv"]) + plaintext = unhexlify(test["msg"]) + ciphertext = unhexlify(test["ct"]) + result = parse_result(test["result"]) except: raise DataError() - if len(key) not in [128/8, 192/8, 256/8]: + if len(key) not in [128 / 8, 192 / 8, 256 / 8]: continue if result is None: continue - vectors.append((hexlify(key), hexlify(iv), hexlify(plaintext), hexlify(ciphertext), result)) + vectors.append( + ( + hexlify(key), + hexlify(iv), + hexlify(plaintext), + hexlify(ciphertext), + result, + ) + ) return vectors @@ -318,34 +336,46 @@ def generate_chacha_poly(filename): data = load_json_testvectors(filename) - if not keys_in_dict(data, {'algorithm', 'testGroups'}): + if not keys_in_dict(data, {"algorithm", "testGroups"}): raise DataError() - if data['algorithm'] != 'CHACHA20-POLY1305': + if data["algorithm"] != "CHACHA20-POLY1305": raise DataError() - for test_group in data['testGroups']: - if not keys_in_dict(test_group, {'tests'}): + for test_group in data["testGroups"]: + if not keys_in_dict(test_group, {"tests"}): raise DataError() - for test in test_group['tests']: - if not keys_in_dict(test, {'key', 'iv', 'aad', 'msg', 'ct', 'tag', 'result'}): + for test in test_group["tests"]: + if not keys_in_dict( + test, {"key", "iv", "aad", "msg", "ct", "tag", "result"} + ): raise DataError() try: - key = unhexlify(test['key']) - iv = unhexlify(test['iv']) - associated_data = unhexlify(test['aad']) - plaintext = unhexlify(test['msg']) - ciphertext = unhexlify(test['ct']) - tag = unhexlify(test['tag']) - result = parse_result(test['result']) + key = unhexlify(test["key"]) + iv = unhexlify(test["iv"]) + associated_data = unhexlify(test["aad"]) + plaintext = unhexlify(test["msg"]) + ciphertext = unhexlify(test["ct"]) + tag = unhexlify(test["tag"]) + result = parse_result(test["result"]) except: raise DataError() if result is None: continue - vectors.append((hexlify(key), hexlify(iv), hexlify(associated_data), hexlify(plaintext), hexlify(ciphertext), hexlify(tag), result)) + vectors.append( + ( + hexlify(key), + hexlify(iv), + hexlify(associated_data), + hexlify(plaintext), + hexlify(ciphertext), + hexlify(tag), + result, + ) + ) return vectors @@ -354,63 +384,70 @@ def generate_curve25519_dh(filename): data = load_json_testvectors(filename) - if not keys_in_dict(data, {'algorithm', 'testGroups'}): + if not keys_in_dict(data, {"algorithm", "testGroups"}): raise DataError() - if data['algorithm'] != 'X25519': + if data["algorithm"] != "X25519": raise DataError() - for test_group in data['testGroups']: - if not keys_in_dict(test_group, {'tests'}): + for test_group in data["testGroups"]: + if not keys_in_dict(test_group, {"tests"}): raise DataError() - for test in test_group['tests']: - if not keys_in_dict(test, {'public', 'private', 'shared', 'result', 'curve'}): + for test in test_group["tests"]: + if not keys_in_dict( + test, {"public", "private", "shared", "result", "curve"} + ): raise DataError() try: - public_key = unhexlify(test['public']) - curve_name = parse_curve_name(test['curve']) - private_key = unhexlify(test['private']) - shared = unhexlify(test['shared']) - result = parse_result(test['result']) + public_key = unhexlify(test["public"]) + curve_name = parse_curve_name(test["curve"]) + private_key = unhexlify(test["private"]) + shared = unhexlify(test["shared"]) + result = parse_result(test["result"]) except: raise DataError() - if curve_name != 'curve25519': + if curve_name != "curve25519": continue if result is None: continue - vectors.append((hexlify(public_key), hexlify(private_key), hexlify(shared), result)) + vectors.append( + (hexlify(public_key), hexlify(private_key), hexlify(shared), result) + ) return vectors + def generate_ecdh(filename): vectors = [] data = load_json_testvectors(filename) - if not keys_in_dict(data, {'algorithm', 'testGroups'}): + if not keys_in_dict(data, {"algorithm", "testGroups"}): raise DataError() - if data['algorithm'] != 'ECDH': + if data["algorithm"] != "ECDH": raise DataError() - for test_group in data['testGroups']: - if not keys_in_dict(test_group, {'tests'}): + for test_group in data["testGroups"]: + if not keys_in_dict(test_group, {"tests"}): raise DataError() - for test in test_group['tests']: - if not keys_in_dict(test, {'public', 'private', 'shared', 'result', 'curve'}): + for test in test_group["tests"]: + if not keys_in_dict( + test, {"public", "private", "shared", "result", "curve"} + ): raise DataError() try: - public_key = unhexlify(test['public']) - curve_name = parse_curve_name(test['curve']) - private_key = parse_signed_hex(test['private']) - shared = unhexlify(test['shared']) - result = parse_result(test['result']) + public_key = unhexlify(test["public"]) + curve_name = parse_curve_name(test["curve"]) + private_key = parse_signed_hex(test["private"]) + shared = unhexlify(test["shared"]) + result = parse_result(test["result"]) except: raise DataError() @@ -431,7 +468,15 @@ def generate_ecdh(filename): if result is None: continue - vectors.append((curve_name, hexlify(public_key), hexlify(private_key), hexlify(shared), result)) + vectors.append( + ( + curve_name, + hexlify(public_key), + hexlify(private_key), + hexlify(shared), + result, + ) + ) return vectors @@ -441,18 +486,18 @@ def generate_ecdsa(filename): data = load_json_testvectors(filename) - if not keys_in_dict(data, {'algorithm', 'testGroups'}): + if not keys_in_dict(data, {"algorithm", "testGroups"}): raise DataError() - if data['algorithm'] != 'ECDSA': + if data["algorithm"] != "ECDSA": raise DataError() - for test_group in data['testGroups']: - if not keys_in_dict(test_group, {'tests', 'keyDer', 'sha'}): + for test_group in data["testGroups"]: + if not keys_in_dict(test_group, {"tests", "keyDer", "sha"}): raise DataError() try: - public_key = unhexlify(test_group['keyDer']) + public_key = unhexlify(test_group["keyDer"]) except: raise DataError() @@ -464,18 +509,18 @@ def generate_ecdsa(filename): continue try: - hasher = parse_digest(test_group['sha']) + hasher = parse_digest(test_group["sha"]) except NotSupported: continue - for test in test_group['tests']: - if not keys_in_dict(test, {'sig', 'msg', 'result'}): + for test in test_group["tests"]: + if not keys_in_dict(test, {"sig", "msg", "result"}): raise DataError() try: - signature = unhexlify(test['sig']) - message = unhexlify(test['msg']) - result = parse_result(test['result']) + signature = unhexlify(test["sig"]) + message = unhexlify(test["msg"]) + result = parse_result(test["result"]) except: raise DataError() @@ -487,7 +532,16 @@ def generate_ecdsa(filename): except ParseError: continue - vectors.append((curve_name, hexlify(public_key), hasher, hexlify(message), hexlify(signature), result)) + vectors.append( + ( + curve_name, + hexlify(public_key), + hasher, + hexlify(message), + hexlify(signature), + result, + ) + ) return vectors @@ -497,19 +551,18 @@ def generate_eddsa(filename): data = load_json_testvectors(filename) - - if not keys_in_dict(data, {'algorithm', 'testGroups'}): + if not keys_in_dict(data, {"algorithm", "testGroups"}): raise DataError() - if data['algorithm'] != 'EDDSA': + if data["algorithm"] != "EDDSA": raise DataError() - for test_group in data['testGroups']: - if not keys_in_dict(test_group, {'tests', 'keyDer'}): + for test_group in data["testGroups"]: + if not keys_in_dict(test_group, {"tests", "keyDer"}): raise DataError() try: - public_key = unhexlify(test_group['keyDer']) + public_key = unhexlify(test_group["keyDer"]) except: raise DataError() @@ -518,14 +571,14 @@ def generate_eddsa(filename): except ParseError: continue - for test in test_group['tests']: - if not keys_in_dict(test, {'sig', 'msg', 'result'}): + for test in test_group["tests"]: + if not keys_in_dict(test, {"sig", "msg", "result"}): raise DataError() try: - signature = unhexlify(test['sig']) - message = unhexlify(test['msg']) - result = parse_result(test['result']) + signature = unhexlify(test["sig"]) + message = unhexlify(test["msg"]) + result = parse_result(test["result"]) except: raise DataError() @@ -537,21 +590,31 @@ def generate_eddsa(filename): except ParseError: continue - vectors.append((hexlify(public_key), hexlify(message), hexlify(signature), result)) + vectors.append( + (hexlify(public_key), hexlify(message), hexlify(signature), result) + ) return vectors dir = os.path.abspath(os.path.dirname(__file__)) -lib = ctypes.cdll.LoadLibrary(os.path.join(dir, 'libtrezor-crypto.so')) -testvectors_directory = os.path.join(dir, 'wycheproof/testvectors') +lib = ctypes.cdll.LoadLibrary(os.path.join(dir, "libtrezor-crypto.so")) +testvectors_directory = os.path.join(dir, "wycheproof/testvectors") context_structure_length = 1024 ecdh_vectors = generate_ecdh("ecdh_test.json") curve25519_dh_vectors = generate_curve25519_dh("x25519_test.json") eddsa_vectors = generate_eddsa("eddsa_test.json") -ecdsa_vectors = generate_ecdsa("ecdsa_test.json") + generate_ecdsa("ecdsa_secp256k1_sha256_test.json") + generate_ecdsa("ecdsa_secp256r1_sha256_test.json") -ecdh_vectors = generate_ecdh("ecdh_test.json") + generate_ecdh("ecdh_secp256k1_test.json") + generate_ecdh("ecdh_secp256r1_test.json") +ecdsa_vectors = ( + generate_ecdsa("ecdsa_test.json") + + generate_ecdsa("ecdsa_secp256k1_sha256_test.json") + + generate_ecdsa("ecdsa_secp256r1_sha256_test.json") +) +ecdh_vectors = ( + generate_ecdh("ecdh_test.json") + + generate_ecdh("ecdh_secp256k1_test.json") + + generate_ecdh("ecdh_secp256r1_test.json") +) chacha_poly_vectors = generate_chacha_poly("chacha20_poly1305_test.json") aes_vectors = generate_aes("aes_cbc_pkcs5_test.json") @@ -562,37 +625,48 @@ def test_eddsa(public_key, message, signature, result): signature = unhexlify(signature) message = unhexlify(message) - computed_result = lib.ed25519_sign_open(message, len(message), public_key, signature) == 0 + computed_result = ( + lib.ed25519_sign_open(message, len(message), public_key, signature) == 0 + ) assert result == computed_result -@pytest.mark.parametrize("curve_name, public_key, hasher, message, signature, result", ecdsa_vectors) +@pytest.mark.parametrize( + "curve_name, public_key, hasher, message, signature, result", ecdsa_vectors +) def test_ecdsa(curve_name, public_key, hasher, message, signature, result): curve = get_curve_by_name(curve_name) if curve is None: - raise NotSupported("Curve not supported: {}".format(curve_Name)) + raise NotSupported("Curve not supported: {}".format(curve_name)) public_key = unhexlify(public_key) signature = unhexlify(signature) message = unhexlify(message) - computed_result = lib.ecdsa_verify(curve, hasher, public_key, signature, message, len(message)) == 0 + computed_result = ( + lib.ecdsa_verify(curve, hasher, public_key, signature, message, len(message)) + == 0 + ) assert result == computed_result -@pytest.mark.parametrize("public_key, private_key, shared, result", curve25519_dh_vectors) +@pytest.mark.parametrize( + "public_key, private_key, shared, result", curve25519_dh_vectors +) def test_curve25519_dh(public_key, private_key, shared, result): public_key = unhexlify(public_key) private_key = unhexlify(private_key) shared = unhexlify(shared) - computed_shared = bytes([0]*32) + computed_shared = bytes([0] * 32) lib.curve25519_scalarmult(computed_shared, private_key, public_key) computed_result = shared == computed_shared assert result == computed_result -@pytest.mark.parametrize("curve_name, public_key, private_key, shared, result", ecdh_vectors) +@pytest.mark.parametrize( + "curve_name, public_key, private_key, shared, result", ecdh_vectors +) def test_ecdh(curve_name, public_key, private_key, shared, result): curve = get_curve_by_name(curve_name) if curve is None: @@ -602,14 +676,16 @@ def test_ecdh(curve_name, public_key, private_key, shared, result): private_key = unhexlify(private_key) shared = unhexlify(shared) - computed_shared = bytes([0]*2*32) + computed_shared = bytes([0] * 2 * 32) lib.ecdh_multiply(curve, private_key, public_key, computed_shared) computed_shared = computed_shared[1:33] computed_result = shared == computed_shared assert result == computed_result -@pytest.mark.parametrize("key, iv, associated_data, plaintext, ciphertext, tag, result", chacha_poly_vectors) +@pytest.mark.parametrize( + "key, iv, associated_data, plaintext, ciphertext, tag, result", chacha_poly_vectors +) def test_chacha_poly(key, iv, associated_data, plaintext, ciphertext, tag, result): key = unhexlify(key) iv = unhexlify(iv) @@ -618,7 +694,9 @@ def test_chacha_poly(key, iv, associated_data, plaintext, ciphertext, tag, resul ciphertext = unhexlify(ciphertext) tag = unhexlify(tag) - computed_ciphertext, computed_tag = chacha_poly_encrypt(key, iv, associated_data, plaintext) + computed_ciphertext, computed_tag = chacha_poly_encrypt( + key, iv, associated_data, plaintext + ) computed_result = ciphertext == computed_ciphertext and tag == computed_tag assert result == computed_result From 5cd84e6870664982a113eeffb7047b35a9eeb1b0 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 16 Jul 2018 14:51:50 +0200 Subject: [PATCH 576/627] tests: fix test_curves bug introduced in last commit --- tests/test_curves.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_curves.py b/tests/test_curves.py index a6db9cee6..7056cb636 100755 --- a/tests/test_curves.py +++ b/tests/test_curves.py @@ -326,7 +326,7 @@ def to_POINT(p): def from_POINT(p): - return lambda p: (bn2int(p[0]), bn2int(p[1])) + return (bn2int(p[0]), bn2int(p[1])) JACOBIAN = BIGNUM * 3 From a7463bcb852f1b553a941e8dd753b87ca9a88d57 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 20 Jul 2018 11:14:51 +0200 Subject: [PATCH 577/627] tests: don't use AES_VAR for tests/libtrezor-crypto.so --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index c3ba7f469..a5e3deb88 100644 --- a/Makefile +++ b/Makefile @@ -86,7 +86,7 @@ tests/test_openssl: tests/test_openssl.o $(OBJS) $(CC) tests/test_openssl.o $(OBJS) $(TESTSSLLIBS) -o tests/test_openssl tests/libtrezor-crypto.so: $(SRCS) - $(CC) $(CFLAGS) -DAES_VAR -fPIC -shared $(SRCS) -o tests/libtrezor-crypto.so + $(CC) $(CFLAGS) -DAES_128 -DAES_192 -fPIC -shared $(SRCS) -o tests/libtrezor-crypto.so tools: tools/xpubaddrgen tools/mktable tools/bip39bruteforce From f481530aea8be6dc067f0752197d70825a0447bf Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 29 Jul 2018 17:46:02 +0200 Subject: [PATCH 578/627] tests: add bip32_vector_3 --- tests/test_check.c | 51 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 2 deletions(-) diff --git a/tests/test_check.c b/tests/test_check.c index 48601966a..ad9a2c933 100644 --- a/tests/test_check.c +++ b/tests/test_check.c @@ -834,7 +834,7 @@ START_TEST(test_bignum_divmod) } END_TEST -// test vector 1 from https://en.bitcoin.it/wiki/BIP_0032_TestVectors +// test vector 1 from https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#test-vector-1 START_TEST(test_bip32_vector_1) { HDNode node, node2, node3; @@ -966,7 +966,7 @@ START_TEST(test_bip32_vector_1) } END_TEST -// test vector 2 from https://en.bitcoin.it/wiki/BIP_0032_TestVectors +// test vector 2 from https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#test-vector-2 START_TEST(test_bip32_vector_2) { HDNode node, node2, node3; @@ -1117,6 +1117,52 @@ START_TEST(test_bip32_vector_2) } END_TEST +// test vector 3 from https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#test-vector-3 +START_TEST(test_bip32_vector_3) +{ + HDNode node, node2, node3; + uint32_t fingerprint; + char str[112]; + int r; + + // init m + hdnode_from_seed(fromhex("4b381541583be4423346c643850da4b320e46a87ae3d2a4e6da11eba819cd4acba45d239319ac14f863b8d5ab5a0d0c64d2e8a1e7d1457df2e5a3c51c73235be"), 64, SECP256K1_NAME, &node); + + // [Chain m] + fingerprint = 0; + ck_assert_int_eq(fingerprint, 0x00000000); + hdnode_fill_public_key(&node); + hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, sizeof(str)); + ck_assert_str_eq(str, "xprv9s21ZrQH143K25QhxbucbDDuQ4naNntJRi4KUfWT7xo4EKsHt2QJDu7KXp1A3u7Bi1j8ph3EGsZ9Xvz9dGuVrtHHs7pXeTzjuxBrCmmhgC6"); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); + ck_assert_str_eq(str, "xpub661MyMwAqRbcEZVB4dScxMAdx6d4nFc9nvyvH3v4gJL378CSRZiYmhRoP7mBy6gSPSCYk6SzXPTf3ND1cZAceL7SfJ1Z3GC8vBgp2epUt13"); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memset(&node3.private_key, 0, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); + + // [Chain m/0'] + fingerprint = hdnode_fingerprint(&node); + r = hdnode_private_ckd_prime(&node, 0); + ck_assert_int_eq(r, 1); + hdnode_fill_public_key(&node); + hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, sizeof(str)); + ck_assert_str_eq(str, "xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L"); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); + ck_assert_str_eq(str, "xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y"); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memset(&node3.private_key, 0, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); +} +END_TEST + START_TEST(test_bip32_compare) { HDNode node1, node2, node3; @@ -4812,6 +4858,7 @@ Suite *test_suite(void) tc = tcase_create("bip32"); tcase_add_test(tc, test_bip32_vector_1); tcase_add_test(tc, test_bip32_vector_2); + tcase_add_test(tc, test_bip32_vector_3); tcase_add_test(tc, test_bip32_compare); tcase_add_test(tc, test_bip32_optimized); tcase_add_test(tc, test_bip32_cache_1); From 456037599f1b694597e2bcccbac1cbcb23c33942 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 31 Jul 2018 14:20:18 +0200 Subject: [PATCH 579/627] hasher: add HASHER_SHA3{,K} --- Makefile | 3 ++- ed25519-donna/ed25519-donna.h | 5 +++++ hasher.c | 20 ++++++++++++++++++++ hasher.h | 19 +++++++++++++------ 4 files changed, 40 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index a5e3deb88..837e0ecd0 100644 --- a/Makefile +++ b/Makefile @@ -29,8 +29,9 @@ CFLAGS += -I. CFLAGS += -DVALGRIND=$(VALGRIND) CFLAGS += -DUSE_ETHEREUM=1 CFLAGS += -DUSE_GRAPHENE=1 -CFLAGS += -DUSE_NEM=1 +CFLAGS += -DUSE_KECCAK=1 CFLAGS += -DUSE_MONERO=1 +CFLAGS += -DUSE_NEM=1 CFLAGS += -DUSE_CARDANO=1 CFLAGS += $(shell pkg-config --cflags openssl) diff --git a/ed25519-donna/ed25519-donna.h b/ed25519-donna/ed25519-donna.h index 1cf3186e2..d3c340227 100644 --- a/ed25519-donna/ed25519-donna.h +++ b/ed25519-donna/ed25519-donna.h @@ -8,6 +8,9 @@ Bo-Yin Yang */ +#ifndef ED25519_DONNA_H +#define ED25519_DONNA_H + #include "ed25519-donna-portable.h" #include "curve25519-donna-32bit.h" @@ -45,3 +48,5 @@ typedef struct ge25519_pniels_t { #include "ed25519-donna-32bit-tables.h" #include "ed25519-donna-impl-base.h" + +#endif diff --git a/hasher.c b/hasher.c index a52eefdd3..762bc321a 100644 --- a/hasher.c +++ b/hasher.c @@ -30,6 +30,12 @@ void hasher_Init(Hasher *hasher, HasherType type) { case HASHER_SHA2D: sha256_Init(&hasher->ctx.sha2); break; + case HASHER_SHA3: +#if USE_KECCAK + case HASHER_SHA3K: +#endif + sha3_256_Init(&hasher->ctx.sha3); + break; case HASHER_BLAKE: case HASHER_BLAKED: blake256_Init(&hasher->ctx.blake); @@ -62,6 +68,12 @@ void hasher_Update(Hasher *hasher, const uint8_t *data, size_t length) { case HASHER_SHA2D: sha256_Update(&hasher->ctx.sha2, data, length); break; + case HASHER_SHA3: +#if USE_KECCAK + case HASHER_SHA3K: +#endif + sha3_Update(&hasher->ctx.sha3, data, length); + break; case HASHER_BLAKE: case HASHER_BLAKED: blake256_Update(&hasher->ctx.blake, data, length); @@ -87,6 +99,14 @@ void hasher_Final(Hasher *hasher, uint8_t hash[HASHER_DIGEST_LENGTH]) { sha256_Final(&hasher->ctx.sha2, hash); hasher_Raw(HASHER_SHA2, hash, HASHER_DIGEST_LENGTH, hash); break; + case HASHER_SHA3: + sha3_Final(&hasher->ctx.sha3, hash); + break; +#if USE_KECCAK + case HASHER_SHA3K: + keccak_Final(&hasher->ctx.sha3, hash); + break; +#endif case HASHER_BLAKE: blake256_Final(&hasher->ctx.blake, hash); break; diff --git a/hasher.h b/hasher.h index 3a561673c..fe4f5f7b1 100644 --- a/hasher.h +++ b/hasher.h @@ -27,6 +27,7 @@ #include #include "sha2.h" +#include "sha3.h" #include "blake256.h" #include "groestl.h" #include "blake2b.h" @@ -35,9 +36,14 @@ typedef enum { HASHER_SHA2, - HASHER_BLAKE, - HASHER_SHA2D, + + HASHER_SHA3, +#if USE_KECCAK + HASHER_SHA3K, +#endif + + HASHER_BLAKE, HASHER_BLAKED, HASHER_GROESTLD_TRUNC, /* Double Groestl512 hasher truncated to 256 bits */ @@ -52,10 +58,11 @@ typedef struct { HasherType type; union { - SHA256_CTX sha2; - BLAKE256_CTX blake; - GROESTL512_CTX groestl; - BLAKE2B_CTX blake2b; + SHA256_CTX sha2; // for HASHER_SHA2{,D} + SHA3_CTX sha3; // for HASHER_SHA3{,K} + BLAKE256_CTX blake; // for HASHER_BLAKE{,D} + GROESTL512_CTX groestl; // for HASHER_GROESTLD_TRUNC + BLAKE2B_CTX blake2b; // for HASHER_OVERWINTER_* } ctx; } Hasher; From 0b0f01fb59290fd6c2790fef0578d3257b64ea9d Mon Sep 17 00:00:00 2001 From: Matheus Degiovani Date: Thu, 26 Jul 2018 14:11:55 -0300 Subject: [PATCH 580/627] Fix decred bip32 name --- secp256k1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/secp256k1.c b/secp256k1.c index 0f5ab1afa..fb62f8c93 100644 --- a/secp256k1.c +++ b/secp256k1.c @@ -65,7 +65,7 @@ const curve_info secp256k1_info = { }; const curve_info secp256k1_decred_info = { - .bip32_name = "Decred seed", + .bip32_name = "Bitcoin seed", .params = &secp256k1, .hasher_bip32 = HASHER_BLAKE, .hasher_base58 = HASHER_BLAKED, From 5d62454c6a7fef411517125b363d3e244414adbc Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 1 Aug 2018 13:40:31 +0200 Subject: [PATCH 581/627] refactor hashers, introduce HASHER_SHA2_RIPEMD160 --- bip32.c | 19 ++++------ bip32.h | 1 - ecdsa.c | 15 ++++---- hasher.c | 13 +++++++ hasher.h | 2 ++ nist256p1.c | 3 +- secp256k1.c | 9 ++--- tests/test_check.c | 90 +++++++++++++++++++++++----------------------- 8 files changed, 76 insertions(+), 76 deletions(-) diff --git a/bip32.c b/bip32.c index 158deaba5..d7d7baa14 100644 --- a/bip32.c +++ b/bip32.c @@ -33,7 +33,6 @@ #include "bip32.h" #include "sha2.h" #include "sha3.h" -#include "ripemd160.h" #include "base58.h" #include "curves.h" #include "secp256k1.h" @@ -56,48 +55,43 @@ const curve_info ed25519_info = { .bip32_name = "ed25519 seed", .params = NULL, - .hasher_bip32 = HASHER_SHA2, .hasher_base58 = HASHER_SHA2D, .hasher_sign = HASHER_SHA2D, - .hasher_pubkey = HASHER_SHA2, + .hasher_pubkey = HASHER_SHA2_RIPEMD, }; const curve_info ed25519_cardano_info = { .bip32_name = "ed25519 cardano seed", .params = NULL, - .hasher_bip32 = HASHER_SHA2, .hasher_base58 = HASHER_SHA2D, .hasher_sign = HASHER_SHA2D, - .hasher_pubkey = HASHER_SHA2, + .hasher_pubkey = HASHER_SHA2_RIPEMD, }; const curve_info ed25519_sha3_info = { .bip32_name = "ed25519-sha3 seed", .params = NULL, - .hasher_bip32 = HASHER_SHA2, .hasher_base58 = HASHER_SHA2D, .hasher_sign = HASHER_SHA2D, - .hasher_pubkey = HASHER_SHA2, + .hasher_pubkey = HASHER_SHA2_RIPEMD, }; #if USE_KECCAK const curve_info ed25519_keccak_info = { .bip32_name = "ed25519-keccak seed", .params = NULL, - .hasher_bip32 = HASHER_SHA2, .hasher_base58 = HASHER_SHA2D, .hasher_sign = HASHER_SHA2D, - .hasher_pubkey = HASHER_SHA2, + .hasher_pubkey = HASHER_SHA2_RIPEMD, }; #endif const curve_info curve25519_info = { .bip32_name = "curve25519 seed", .params = NULL, - .hasher_bip32 = HASHER_SHA2, .hasher_base58 = HASHER_SHA2D, .hasher_sign = HASHER_SHA2D, - .hasher_pubkey = HASHER_SHA2, + .hasher_pubkey = HASHER_SHA2_RIPEMD, }; int hdnode_from_xpub(uint32_t depth, uint32_t child_num, const uint8_t *chain_code, const uint8_t *public_key, const char* curve, HDNode *out) @@ -194,8 +188,7 @@ uint32_t hdnode_fingerprint(HDNode *node) uint32_t fingerprint; hdnode_fill_public_key(node); - hasher_Raw(node->curve->hasher_bip32, node->public_key, 33, digest); - ripemd160(digest, 32, digest); + hasher_Raw(node->curve->hasher_pubkey, node->public_key, 33, digest); fingerprint = ((uint32_t) digest[0] << 24) + (digest[1] << 16) + (digest[2] << 8) + digest[3]; memzero(digest, sizeof(digest)); return fingerprint; diff --git a/bip32.h b/bip32.h index c98019658..f633c532a 100644 --- a/bip32.h +++ b/bip32.h @@ -35,7 +35,6 @@ typedef struct { const char *bip32_name; // string for generating BIP32 xprv from seed const ecdsa_curve *params; // ecdsa curve parameters, null for ed25519 - HasherType hasher_bip32; HasherType hasher_base58; HasherType hasher_sign; HasherType hasher_pubkey; diff --git a/ecdsa.c b/ecdsa.c index 469ff9cd8..c910bb938 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -30,8 +30,6 @@ #include "address.h" #include "bignum.h" #include "rand.h" -#include "sha2.h" -#include "ripemd160.h" #include "hmac.h" #include "ecdsa.h" #include "base58.h" @@ -878,7 +876,7 @@ void ecdsa_get_pubkeyhash(const uint8_t *pub_key, HasherType hasher_pubkey, uint } else { // expecting compressed format hasher_Raw(hasher_pubkey, pub_key, 33, h); } - ripemd160(h, HASHER_DIGEST_LENGTH, pubkeyhash); + memcpy(pubkeyhash, h, 20); memzero(h, sizeof(h)); } @@ -901,14 +899,13 @@ void ecdsa_get_address(const uint8_t *pub_key, uint32_t version, HasherType hash void ecdsa_get_address_segwit_p2sh_raw(const uint8_t *pub_key, uint32_t version, HasherType hasher_pubkey, uint8_t *addr_raw) { + uint8_t buf[32 + 2]; + buf[0] = 0; // version byte + buf[1] = 20; // push 20 bytes + ecdsa_get_pubkeyhash(pub_key, hasher_pubkey, buf + 2); size_t prefix_len = address_prefix_bytes_len(version); - uint8_t digest[32]; - addr_raw[0] = 0; // version byte - addr_raw[1] = 20; // push 20 bytes - ecdsa_get_pubkeyhash(pub_key, hasher_pubkey, addr_raw + 2); - hasher_Raw(hasher_pubkey, addr_raw, 22, digest); address_write_prefix_bytes(version, addr_raw); - ripemd160(digest, 32, addr_raw + prefix_len); + hasher_Raw(hasher_pubkey, buf, 22, addr_raw + prefix_len); } void ecdsa_get_address_segwit_p2sh(const uint8_t *pub_key, uint32_t version, HasherType hasher_pubkey, HasherType hasher_base58, char *addr, int addrsize) diff --git a/hasher.c b/hasher.c index 762bc321a..b6564e8de 100644 --- a/hasher.c +++ b/hasher.c @@ -21,6 +21,7 @@ */ #include "hasher.h" +#include "ripemd160.h" void hasher_Init(Hasher *hasher, HasherType type) { hasher->type = type; @@ -28,6 +29,7 @@ void hasher_Init(Hasher *hasher, HasherType type) { switch (hasher->type) { case HASHER_SHA2: case HASHER_SHA2D: + case HASHER_SHA2_RIPEMD: sha256_Init(&hasher->ctx.sha2); break; case HASHER_SHA3: @@ -38,6 +40,7 @@ void hasher_Init(Hasher *hasher, HasherType type) { break; case HASHER_BLAKE: case HASHER_BLAKED: + case HASHER_BLAKE_RIPEMD: blake256_Init(&hasher->ctx.blake); break; case HASHER_GROESTLD_TRUNC: @@ -66,6 +69,7 @@ void hasher_Update(Hasher *hasher, const uint8_t *data, size_t length) { switch (hasher->type) { case HASHER_SHA2: case HASHER_SHA2D: + case HASHER_SHA2_RIPEMD: sha256_Update(&hasher->ctx.sha2, data, length); break; case HASHER_SHA3: @@ -76,6 +80,7 @@ void hasher_Update(Hasher *hasher, const uint8_t *data, size_t length) { break; case HASHER_BLAKE: case HASHER_BLAKED: + case HASHER_BLAKE_RIPEMD: blake256_Update(&hasher->ctx.blake, data, length); break; case HASHER_GROESTLD_TRUNC: @@ -99,6 +104,10 @@ void hasher_Final(Hasher *hasher, uint8_t hash[HASHER_DIGEST_LENGTH]) { sha256_Final(&hasher->ctx.sha2, hash); hasher_Raw(HASHER_SHA2, hash, HASHER_DIGEST_LENGTH, hash); break; + case HASHER_SHA2_RIPEMD: + sha256_Final(&hasher->ctx.sha2, hash); + ripemd160(hash, HASHER_DIGEST_LENGTH, hash); + break; case HASHER_SHA3: sha3_Final(&hasher->ctx.sha3, hash); break; @@ -114,6 +123,10 @@ void hasher_Final(Hasher *hasher, uint8_t hash[HASHER_DIGEST_LENGTH]) { blake256_Final(&hasher->ctx.blake, hash); hasher_Raw(HASHER_BLAKE, hash, HASHER_DIGEST_LENGTH, hash); break; + case HASHER_BLAKE_RIPEMD: + blake256_Final(&hasher->ctx.blake, hash); + ripemd160(hash, HASHER_DIGEST_LENGTH, hash); + break; case HASHER_GROESTLD_TRUNC: groestl512_DoubleTrunc(&hasher->ctx.groestl, hash); break; diff --git a/hasher.h b/hasher.h index fe4f5f7b1..7e748bf8e 100644 --- a/hasher.h +++ b/hasher.h @@ -37,6 +37,7 @@ typedef enum { HASHER_SHA2, HASHER_SHA2D, + HASHER_SHA2_RIPEMD, HASHER_SHA3, #if USE_KECCAK @@ -45,6 +46,7 @@ typedef enum { HASHER_BLAKE, HASHER_BLAKED, + HASHER_BLAKE_RIPEMD, HASHER_GROESTLD_TRUNC, /* Double Groestl512 hasher truncated to 256 bits */ diff --git a/nist256p1.c b/nist256p1.c index 1581cce87..79d4f5bd4 100644 --- a/nist256p1.c +++ b/nist256p1.c @@ -58,8 +58,7 @@ const ecdsa_curve nist256p1 = { const curve_info nist256p1_info = { .bip32_name = "Nist256p1 seed", .params = &nist256p1, - .hasher_bip32 = HASHER_SHA2, .hasher_base58 = HASHER_SHA2D, .hasher_sign = HASHER_SHA2D, - .hasher_pubkey = HASHER_SHA2, + .hasher_pubkey = HASHER_SHA2_RIPEMD, }; diff --git a/secp256k1.c b/secp256k1.c index fb62f8c93..95981eed3 100644 --- a/secp256k1.c +++ b/secp256k1.c @@ -58,26 +58,23 @@ const ecdsa_curve secp256k1 = { const curve_info secp256k1_info = { .bip32_name = "Bitcoin seed", .params = &secp256k1, - .hasher_bip32 = HASHER_SHA2, .hasher_base58 = HASHER_SHA2D, .hasher_sign = HASHER_SHA2D, - .hasher_pubkey = HASHER_SHA2, + .hasher_pubkey = HASHER_SHA2_RIPEMD, }; const curve_info secp256k1_decred_info = { .bip32_name = "Bitcoin seed", .params = &secp256k1, - .hasher_bip32 = HASHER_BLAKE, .hasher_base58 = HASHER_BLAKED, .hasher_sign = HASHER_BLAKE, - .hasher_pubkey = HASHER_BLAKE, + .hasher_pubkey = HASHER_BLAKE_RIPEMD, }; const curve_info secp256k1_groestl_info = { .bip32_name = "Bitcoin seed", .params = &secp256k1, - .hasher_bip32 = HASHER_SHA2, .hasher_base58 = HASHER_GROESTLD_TRUNC, .hasher_sign = HASHER_SHA2, - .hasher_pubkey = HASHER_SHA2, + .hasher_pubkey = HASHER_SHA2_RIPEMD, }; diff --git a/tests/test_check.c b/tests/test_check.c index ad9a2c933..ae932e915 100644 --- a/tests/test_check.c +++ b/tests/test_check.c @@ -2901,57 +2901,57 @@ START_TEST(test_address) uint8_t pub_key[65]; memcpy(pub_key, fromhex("0226659c1cf7321c178c07437150639ff0c5b7679c7ea195253ed9abda2e081a37"), 33); - ecdsa_get_address(pub_key, 0, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "139MaMHp3Vjo8o4x8N1ZLWEtovLGvBsg6s"); - ecdsa_get_address(pub_key, 111, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "mhfJsQNnrXB3uuYZqvywARTDfuvyjg4RBh"); - ecdsa_get_address(pub_key, 52, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "MxiimznnxsqMfLKTQBL8Z2PoY9jKpjgkCu"); - ecdsa_get_address(pub_key, 48, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "LMNJqZbe89yrPbm7JVzrcXJf28hZ1rKPaH"); - ecdsa_get_address(pub_key, 36, HASHER_SHA2, HASHER_GROESTLD_TRUNC, address, sizeof(address)); ck_assert_str_eq(address, "FXK52G2BbzRLaQ651U12o23DU5cEQdhvU6"); - ecdsa_get_address_segwit_p2sh(pub_key, 5, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "34PyTHn74syS796eTgsyoLfwoBC3cwLn6p"); + ecdsa_get_address(pub_key, 0, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "139MaMHp3Vjo8o4x8N1ZLWEtovLGvBsg6s"); + ecdsa_get_address(pub_key, 111, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "mhfJsQNnrXB3uuYZqvywARTDfuvyjg4RBh"); + ecdsa_get_address(pub_key, 52, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "MxiimznnxsqMfLKTQBL8Z2PoY9jKpjgkCu"); + ecdsa_get_address(pub_key, 48, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "LMNJqZbe89yrPbm7JVzrcXJf28hZ1rKPaH"); + ecdsa_get_address(pub_key, 36, HASHER_SHA2_RIPEMD, HASHER_GROESTLD_TRUNC, address, sizeof(address)); ck_assert_str_eq(address, "FXK52G2BbzRLaQ651U12o23DU5cEQdhvU6"); + ecdsa_get_address_segwit_p2sh(pub_key, 5, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "34PyTHn74syS796eTgsyoLfwoBC3cwLn6p"); memcpy(pub_key, fromhex("025b1654a0e78d28810094f6c5a96b8efb8a65668b578f170ac2b1f83bc63ba856"), 33); - ecdsa_get_address(pub_key, 0, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "19Ywfm3witp6C1yBMy4NRYHY2347WCRBfQ"); - ecdsa_get_address(pub_key, 111, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "mp4txp8vXvFLy8So5Y2kFTVrt2epN6YzdP"); - ecdsa_get_address(pub_key, 52, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "N58JsQYveGueiZDgdnNwe4SSkGTAToutAY"); - ecdsa_get_address(pub_key, 48, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "LTmtvyMmoZ49SpfLY73fhZMJEFRPdyohKh"); - ecdsa_get_address(pub_key, 36, HASHER_SHA2, HASHER_GROESTLD_TRUNC, address, sizeof(address)); ck_assert_str_eq(address, "Fdif7fnKHPVddczJF53qt45rgCL51yWN6x"); - ecdsa_get_address_segwit_p2sh(pub_key, 5, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "35trq6eeuHf6VL9L8pQv46x3vegHnHoTuB"); + ecdsa_get_address(pub_key, 0, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "19Ywfm3witp6C1yBMy4NRYHY2347WCRBfQ"); + ecdsa_get_address(pub_key, 111, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "mp4txp8vXvFLy8So5Y2kFTVrt2epN6YzdP"); + ecdsa_get_address(pub_key, 52, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "N58JsQYveGueiZDgdnNwe4SSkGTAToutAY"); + ecdsa_get_address(pub_key, 48, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "LTmtvyMmoZ49SpfLY73fhZMJEFRPdyohKh"); + ecdsa_get_address(pub_key, 36, HASHER_SHA2_RIPEMD, HASHER_GROESTLD_TRUNC, address, sizeof(address)); ck_assert_str_eq(address, "Fdif7fnKHPVddczJF53qt45rgCL51yWN6x"); + ecdsa_get_address_segwit_p2sh(pub_key, 5, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "35trq6eeuHf6VL9L8pQv46x3vegHnHoTuB"); memcpy(pub_key, fromhex("03433f246a12e6486a51ff08802228c61cf895175a9b49ed4766ea9a9294a3c7fe"), 33); - ecdsa_get_address(pub_key, 0, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "1FWE2bn3MWhc4QidcF6AvEWpK77sSi2cAP"); - ecdsa_get_address(pub_key, 111, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "mv2BKes2AY8rqXCFKp4Yk9j9B6iaMfWRLN"); - ecdsa_get_address(pub_key, 52, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "NB5bEFH2GtoAawy8t4Qk8kfj3LWvQs3MhB"); - ecdsa_get_address(pub_key, 48, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "LZjBHp5sSAwfKDQnnP5UCFaaXKV9YheGxQ"); - ecdsa_get_address(pub_key, 36, HASHER_SHA2, HASHER_GROESTLD_TRUNC, address, sizeof(address)); ck_assert_str_eq(address, "FjfwUWWQv1P9W1jkVM5eNkK8yGPq5XyZZy"); - ecdsa_get_address_segwit_p2sh(pub_key, 5, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "3456DYaKUWuY6RWWw8Hp5CftHLcQN29h9Y"); + ecdsa_get_address(pub_key, 0, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "1FWE2bn3MWhc4QidcF6AvEWpK77sSi2cAP"); + ecdsa_get_address(pub_key, 111, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "mv2BKes2AY8rqXCFKp4Yk9j9B6iaMfWRLN"); + ecdsa_get_address(pub_key, 52, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "NB5bEFH2GtoAawy8t4Qk8kfj3LWvQs3MhB"); + ecdsa_get_address(pub_key, 48, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "LZjBHp5sSAwfKDQnnP5UCFaaXKV9YheGxQ"); + ecdsa_get_address(pub_key, 36, HASHER_SHA2_RIPEMD, HASHER_GROESTLD_TRUNC, address, sizeof(address)); ck_assert_str_eq(address, "FjfwUWWQv1P9W1jkVM5eNkK8yGPq5XyZZy"); + ecdsa_get_address_segwit_p2sh(pub_key, 5, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "3456DYaKUWuY6RWWw8Hp5CftHLcQN29h9Y"); memcpy(pub_key, fromhex("03aeb03abeee0f0f8b4f7a5d65ce31f9570cef9f72c2dd8a19b4085a30ab033d48"), 33); - ecdsa_get_address(pub_key, 0, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "1yrZb8dhdevoqpUEGi2tUccUEeiMKeLcs"); - ecdsa_get_address(pub_key, 111, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "mgVoreDcWf6BaxJ5wqgQiPpwLEFRLSr8U8"); - ecdsa_get_address(pub_key, 52, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "MwZDmEdcd1kVLP4yW62c6zmXCU3mNbveDo"); - ecdsa_get_address(pub_key, 48, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "LLCopoSTnHtz4eWdQQhLAVgNgT1zTi4QBK"); - ecdsa_get_address(pub_key, 36, HASHER_SHA2, HASHER_GROESTLD_TRUNC, address, sizeof(address)); ck_assert_str_eq(address, "FW9a1Vs1G8LUFSqb7NhWLzQw8PvfwAxmxA"); - ecdsa_get_address_segwit_p2sh(pub_key, 5, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "3DBU4tJ9tkMR9fnmCtjW48kjvseoNLQZXd"); + ecdsa_get_address(pub_key, 0, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "1yrZb8dhdevoqpUEGi2tUccUEeiMKeLcs"); + ecdsa_get_address(pub_key, 111, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "mgVoreDcWf6BaxJ5wqgQiPpwLEFRLSr8U8"); + ecdsa_get_address(pub_key, 52, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "MwZDmEdcd1kVLP4yW62c6zmXCU3mNbveDo"); + ecdsa_get_address(pub_key, 48, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "LLCopoSTnHtz4eWdQQhLAVgNgT1zTi4QBK"); + ecdsa_get_address(pub_key, 36, HASHER_SHA2_RIPEMD, HASHER_GROESTLD_TRUNC, address, sizeof(address)); ck_assert_str_eq(address, "FW9a1Vs1G8LUFSqb7NhWLzQw8PvfwAxmxA"); + ecdsa_get_address_segwit_p2sh(pub_key, 5, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "3DBU4tJ9tkMR9fnmCtjW48kjvseoNLQZXd"); memcpy(pub_key, fromhex("0496e8f2093f018aff6c2e2da5201ee528e2c8accbf9cac51563d33a7bb74a016054201c025e2a5d96b1629b95194e806c63eb96facaedc733b1a4b70ab3b33e3a"), 65); - ecdsa_get_address(pub_key, 0, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "194SZbL75xCCGBbKtMsyWLE5r9s2V6mhVM"); - ecdsa_get_address(pub_key, 111, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "moaPreR5tydT3J4wbvrMLFSQi9TjPCiZc6"); - ecdsa_get_address(pub_key, 52, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "N4domEq61LHkniqqABCYirNzaPG5NRU8GH"); - ecdsa_get_address(pub_key, 48, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "LTHPpodwAcSFWzHV4VsGnMHr4NEJajMnKX"); - ecdsa_get_address(pub_key, 36, HASHER_SHA2, HASHER_GROESTLD_TRUNC, address, sizeof(address)); ck_assert_str_eq(address, "FdEA1W4UeSsjhncSmTsSxr2QWK8z2xGkjc"); + ecdsa_get_address(pub_key, 0, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "194SZbL75xCCGBbKtMsyWLE5r9s2V6mhVM"); + ecdsa_get_address(pub_key, 111, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "moaPreR5tydT3J4wbvrMLFSQi9TjPCiZc6"); + ecdsa_get_address(pub_key, 52, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "N4domEq61LHkniqqABCYirNzaPG5NRU8GH"); + ecdsa_get_address(pub_key, 48, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "LTHPpodwAcSFWzHV4VsGnMHr4NEJajMnKX"); + ecdsa_get_address(pub_key, 36, HASHER_SHA2_RIPEMD, HASHER_GROESTLD_TRUNC, address, sizeof(address)); ck_assert_str_eq(address, "FdEA1W4UeSsjhncSmTsSxr2QWK8z2xGkjc"); memcpy(pub_key, fromhex("0498010f8a687439ff497d3074beb4519754e72c4b6220fb669224749591dde416f3961f8ece18f8689bb32235e436874d2174048b86118a00afbd5a4f33a24f0f"), 65); - ecdsa_get_address(pub_key, 0, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "1A2WfBD4BJFwYHFPc5KgktqtbdJLBuVKc4"); - ecdsa_get_address(pub_key, 111, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "mpYTxEJ2zKhCKPj1KeJ4ap4DTcu39T3uzD"); - ecdsa_get_address(pub_key, 52, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "N5bsrpi36gMW4pVtsteFyQzoKrhPE7nkxK"); - ecdsa_get_address(pub_key, 48, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "LUFTvPWtFxVzo5wYnDJz2uueoqfcMYiuxH"); - ecdsa_get_address(pub_key, 36, HASHER_SHA2, HASHER_GROESTLD_TRUNC, address, sizeof(address)); ck_assert_str_eq(address, "FeCE75wRjnwUytGWVBKADQeDFnaHpJ8t3B"); + ecdsa_get_address(pub_key, 0, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "1A2WfBD4BJFwYHFPc5KgktqtbdJLBuVKc4"); + ecdsa_get_address(pub_key, 111, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "mpYTxEJ2zKhCKPj1KeJ4ap4DTcu39T3uzD"); + ecdsa_get_address(pub_key, 52, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "N5bsrpi36gMW4pVtsteFyQzoKrhPE7nkxK"); + ecdsa_get_address(pub_key, 48, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "LUFTvPWtFxVzo5wYnDJz2uueoqfcMYiuxH"); + ecdsa_get_address(pub_key, 36, HASHER_SHA2_RIPEMD, HASHER_GROESTLD_TRUNC, address, sizeof(address)); ck_assert_str_eq(address, "FeCE75wRjnwUytGWVBKADQeDFnaHpJ8t3B"); memcpy(pub_key, fromhex("04f80490839af36d13701ec3f9eebdac901b51c362119d74553a3c537faff31b17e2a59ebddbdac9e87b816307a7ed5b826b8f40b92719086238e1bebf19b77a4d"), 65); - ecdsa_get_address(pub_key, 0, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "19J81hrPnQxg9UGx45ibTieCkb2ttm8CLL"); - ecdsa_get_address(pub_key, 111, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "mop5JkwNbSPvvakZmegyHdrXcadbjLazww"); - ecdsa_get_address(pub_key, 52, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "N4sVDMMNho4Eg1XTKu3AgEo7UpRwq3aNbn"); - ecdsa_get_address(pub_key, 48, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "LTX5GvADs5CjQGy7EDhtjjhxxoQB2Uhicd"); - ecdsa_get_address(pub_key, 36, HASHER_SHA2, HASHER_GROESTLD_TRUNC, address, sizeof(address)); ck_assert_str_eq(address, "FdTqTcamLueDb5J4wBi4vESXQkJrS54H6k"); + ecdsa_get_address(pub_key, 0, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "19J81hrPnQxg9UGx45ibTieCkb2ttm8CLL"); + ecdsa_get_address(pub_key, 111, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "mop5JkwNbSPvvakZmegyHdrXcadbjLazww"); + ecdsa_get_address(pub_key, 52, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "N4sVDMMNho4Eg1XTKu3AgEo7UpRwq3aNbn"); + ecdsa_get_address(pub_key, 48, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "LTX5GvADs5CjQGy7EDhtjjhxxoQB2Uhicd"); + ecdsa_get_address(pub_key, 36, HASHER_SHA2_RIPEMD, HASHER_GROESTLD_TRUNC, address, sizeof(address)); ck_assert_str_eq(address, "FdTqTcamLueDb5J4wBi4vESXQkJrS54H6k"); } END_TEST @@ -4550,12 +4550,12 @@ START_TEST(test_multibyte_address) ecdsa_get_wif(priv_key, 0xffffffff, HASHER_SHA2D, wif, sizeof(wif)); ck_assert_str_eq(wif, "y9KVfV1RJXcTxpVjeuh6WYWh8tMwnAUeyUwDEiRviYdrJ61njTmnfUjE"); memcpy(pub_key, fromhex("0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71"), 33); - ecdsa_get_address(pub_key, 0, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "1C7zdTfnkzmr13HfA2vNm5SJYRK6nEKyq8"); - ecdsa_get_address(pub_key, 0x12, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "8SCrMR2yYF7ciqoDbav7VLLTsVx5dTVPPq"); - ecdsa_get_address(pub_key, 0x1234, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "ZLH8q1UgMPg8o2s1MD55YVMpPV7vqms9kiV"); - ecdsa_get_address(pub_key, 0x123456, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "3ThqvsQVFnbiF66NwHtfe2j6AKn75DpLKpQSq"); - ecdsa_get_address(pub_key, 0x12345678, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "BrsGxAHga3VbopvSnb3gmLvMBhJNCGuDxBZL44"); - ecdsa_get_address(pub_key, 0xffffffff, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "3diW7paWGJyZRLGqMJZ55DMfPExob8QxQHkrfYT"); + ecdsa_get_address(pub_key, 0, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "1C7zdTfnkzmr13HfA2vNm5SJYRK6nEKyq8"); + ecdsa_get_address(pub_key, 0x12, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "8SCrMR2yYF7ciqoDbav7VLLTsVx5dTVPPq"); + ecdsa_get_address(pub_key, 0x1234, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "ZLH8q1UgMPg8o2s1MD55YVMpPV7vqms9kiV"); + ecdsa_get_address(pub_key, 0x123456, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "3ThqvsQVFnbiF66NwHtfe2j6AKn75DpLKpQSq"); + ecdsa_get_address(pub_key, 0x12345678, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "BrsGxAHga3VbopvSnb3gmLvMBhJNCGuDxBZL44"); + ecdsa_get_address(pub_key, 0xffffffff, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "3diW7paWGJyZRLGqMJZ55DMfPExob8QxQHkrfYT"); res = ecdsa_address_decode("1C7zdTfnkzmr13HfA2vNm5SJYRK6nEKyq8", 0, HASHER_SHA2D, decode); ck_assert_int_eq(res, 1); From d454a48b5169fddacd169e6ca4124b69449501c9 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 14 Aug 2018 13:05:21 +0200 Subject: [PATCH 582/627] aes: update to newest version --- aes/aes.h | 51 ++++++++----- aes/aes_modes.c | 16 ++-- aes/aescrypt.c | 20 ++--- aes/aeskey.c | 14 ++-- aes/aesopt.h | 24 +++--- aes/aestst.h | 4 +- aes/brg_types.h | 191 ------------------------------------------------ 7 files changed, 72 insertions(+), 248 deletions(-) delete mode 100644 aes/brg_types.h diff --git a/aes/aes.h b/aes/aes.h index 8cc0526ae..878943b57 100644 --- a/aes/aes.h +++ b/aes/aes.h @@ -15,7 +15,7 @@ This software is provided 'as is' with no explicit or implied warranties in respect of its operation, including, but not limited to, correctness and fitness for purpose. --------------------------------------------------------------------------- -Issue Date: 20/12/2007 +Issue Date: 02/08/2018 This file contains the definitions required to use AES in C. See aesopt.h for optimisation details. @@ -25,32 +25,43 @@ Issue Date: 20/12/2007 #define _AES_H #include +#include -/* This include is used to find 8 & 32 bit unsigned integer types */ -#include "brg_types.h" +#define VOID_RETURN void +#define INT_RETURN int +#define ALIGN_OFFSET(x,n) (((intptr_t)(x)) & ((n) - 1)) +#define ALIGN_FLOOR(x,n) ((uint8_t*)(x) - ( ((intptr_t)(x)) & ((n) - 1))) +#define ALIGN_CEIL(x,n) ((uint8_t*)(x) + (-((intptr_t)(x)) & ((n) - 1))) #if defined(__cplusplus) extern "C" { #endif -// #define AES_128 /* if a fast 128 bit key scheduler is needed */ -// #define AES_192 /* if a fast 192 bit key scheduler is needed */ -#define AES_256 /* if a fast 256 bit key scheduler is needed */ -// #define AES_VAR /* if variable key size scheduler is needed */ -#define AES_MODES /* if support is needed for modes */ +// #define AES_128 /* if a fast 128 bit key scheduler is needed */ +// #define AES_192 /* if a fast 192 bit key scheduler is needed */ +#define AES_256 /* if a fast 256 bit key scheduler is needed */ +// #define AES_VAR /* if variable key size scheduler is needed */ +#if 1 +# define AES_MODES /* if support is needed for modes in the C code */ +#endif /* (these will use AES_NI if it is present) */ +#if 0 /* add this to make direct calls to the AES_NI */ +# /* implemented CBC and CTR modes available */ +# define ADD_AESNI_MODE_CALLS +#endif -/* The following must also be set in assembler files if being used */ +/* The following must also be set in assembler files if being used */ -#define AES_ENCRYPT /* if support for encryption is needed */ -#define AES_DECRYPT /* if support for decryption is needed */ +#define AES_ENCRYPT /* if support for encryption is needed */ +#define AES_DECRYPT /* if support for decryption is needed */ -#define AES_BLOCK_SIZE 16 /* the AES block size in bytes */ -#define N_COLS 4 /* the number of columns in the state */ +#define AES_BLOCK_SIZE_P2 4 /* AES block size as a power of 2 */ +#define AES_BLOCK_SIZE (1 << AES_BLOCK_SIZE_P2) /* AES block size */ +#define N_COLS 4 /* the number of columns in the state */ -/* The key schedule length is 11, 13 or 15 16-byte blocks for 128, */ -/* 192 or 256-bit keys respectively. That is 176, 208 or 240 bytes */ -/* or 44, 52 or 60 32-bit words. */ +/* The key schedule length is 11, 13 or 15 16-byte blocks for 128, */ +/* 192 or 256-bit keys respectively. That is 176, 208 or 240 bytes */ +/* or 44, 52 or 60 32-bit words. */ #if defined( AES_VAR ) || defined( AES_256 ) #define KS_LENGTH 60 @@ -62,10 +73,10 @@ extern "C" #define AES_RETURN INT_RETURN -/* the character array 'inf' in the following structures is used */ -/* to hold AES context information. This AES code uses cx->inf.b[0] */ -/* to hold the number of rounds multiplied by 16. The other three */ -/* elements can be used by code that implements additional modes */ +/* the character array 'inf' in the following structures is used */ +/* to hold AES context information. This AES code uses cx->inf.b[0] */ +/* to hold the number of rounds multiplied by 16. The other three */ +/* elements can be used by code that implements additional modes */ typedef union { uint32_t l; diff --git a/aes/aes_modes.c b/aes/aes_modes.c index 744395e0e..352752ed9 100644 --- a/aes/aes_modes.c +++ b/aes/aes_modes.c @@ -136,7 +136,7 @@ AES_RETURN aes_mode_reset(aes_encrypt_ctx ctx[1]) AES_RETURN aes_ecb_encrypt(const unsigned char *ibuf, unsigned char *obuf, int len, const aes_encrypt_ctx ctx[1]) -{ int nb = len >> 4; +{ int nb = len >> AES_BLOCK_SIZE_P2; if(len & (AES_BLOCK_SIZE - 1)) return EXIT_FAILURE; @@ -198,7 +198,7 @@ AES_RETURN aes_ecb_encrypt(const unsigned char *ibuf, unsigned char *obuf, AES_RETURN aes_ecb_decrypt(const unsigned char *ibuf, unsigned char *obuf, int len, const aes_decrypt_ctx ctx[1]) -{ int nb = len >> 4; +{ int nb = len >> AES_BLOCK_SIZE_P2; if(len & (AES_BLOCK_SIZE - 1)) return EXIT_FAILURE; @@ -260,7 +260,7 @@ AES_RETURN aes_ecb_decrypt(const unsigned char *ibuf, unsigned char *obuf, AES_RETURN aes_cbc_encrypt(const unsigned char *ibuf, unsigned char *obuf, int len, unsigned char *iv, const aes_encrypt_ctx ctx[1]) -{ int nb = len >> 4; +{ int nb = len >> AES_BLOCK_SIZE_P2; if(len & (AES_BLOCK_SIZE - 1)) return EXIT_FAILURE; @@ -358,7 +358,7 @@ AES_RETURN aes_cbc_encrypt(const unsigned char *ibuf, unsigned char *obuf, AES_RETURN aes_cbc_decrypt(const unsigned char *ibuf, unsigned char *obuf, int len, unsigned char *iv, const aes_decrypt_ctx ctx[1]) { unsigned char tmp[AES_BLOCK_SIZE]; - int nb = len >> 4; + int nb = len >> AES_BLOCK_SIZE_P2; if(len & (AES_BLOCK_SIZE - 1)) return EXIT_FAILURE; @@ -469,7 +469,7 @@ AES_RETURN aes_cfb_encrypt(const unsigned char *ibuf, unsigned char *obuf, b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos); } - if((nb = (len - cnt) >> 4) != 0) /* process whole blocks */ + if((nb = (len - cnt) >> AES_BLOCK_SIZE_P2) != 0) /* process whole blocks */ { #if defined( USE_VIA_ACE_IF_PRESENT ) @@ -597,7 +597,7 @@ AES_RETURN aes_cfb_decrypt(const unsigned char *ibuf, unsigned char *obuf, b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos); } - if((nb = (len - cnt) >> 4) != 0) /* process whole blocks */ + if((nb = (len - cnt) >> AES_BLOCK_SIZE_P2) != 0) /* process whole blocks */ { #if defined( USE_VIA_ACE_IF_PRESENT ) @@ -735,7 +735,7 @@ AES_RETURN aes_ofb_crypt(const unsigned char *ibuf, unsigned char *obuf, b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos); } - if((nb = (len - cnt) >> 4) != 0) /* process whole blocks */ + if((nb = (len - cnt) >> AES_BLOCK_SIZE_P2) != 0) /* process whole blocks */ { #if defined( USE_VIA_ACE_IF_PRESENT ) @@ -880,7 +880,7 @@ AES_RETURN aes_ctr_crypt(const unsigned char *ibuf, unsigned char *obuf, { blen = (len > BFR_LENGTH ? BFR_LENGTH : len), len -= blen; - for(i = 0, ip = buf; i < (blen >> 4); ++i) + for(i = 0, ip = buf; i < (blen >> AES_BLOCK_SIZE_P2); ++i) { memcpy(ip, cbuf, AES_BLOCK_SIZE); ctr_inc(cbuf); diff --git a/aes/aescrypt.c b/aes/aescrypt.c index 8c7c7f24c..74bdf7be6 100644 --- a/aes/aescrypt.c +++ b/aes/aescrypt.c @@ -55,7 +55,7 @@ extern "C" so we need to control this with the following VC++ pragmas */ -#if defined( _MSC_VER ) && !defined( _WIN64 ) +#if defined( _MSC_VER ) && !defined( _WIN64 ) && !defined( __clang__ ) #pragma optimize( "s", on ) #endif @@ -101,7 +101,7 @@ AES_RETURN aes_xi(encrypt)(const unsigned char *in, unsigned char *out, const ae dec_fmvars; /* declare variables for fwd_mcol() if needed */ #endif - if(cx->inf.b[0] != 10 * 16 && cx->inf.b[0] != 12 * 16 && cx->inf.b[0] != 14 * 16) + if(cx->inf.b[0] != 10 * AES_BLOCK_SIZE && cx->inf.b[0] != 12 * AES_BLOCK_SIZE && cx->inf.b[0] != 14 * AES_BLOCK_SIZE) return EXIT_FAILURE; kp = cx->ks; @@ -111,17 +111,17 @@ AES_RETURN aes_xi(encrypt)(const unsigned char *in, unsigned char *out, const ae switch(cx->inf.b[0]) { - case 14 * 16: + case 14 * AES_BLOCK_SIZE: round(fwd_rnd, b1, b0, kp + 1 * N_COLS); round(fwd_rnd, b0, b1, kp + 2 * N_COLS); kp += 2 * N_COLS; //-fallthrough - case 12 * 16: + case 12 * AES_BLOCK_SIZE: round(fwd_rnd, b1, b0, kp + 1 * N_COLS); round(fwd_rnd, b0, b1, kp + 2 * N_COLS); kp += 2 * N_COLS; //-fallthrough - case 10 * 16: + case 10 * AES_BLOCK_SIZE: round(fwd_rnd, b1, b0, kp + 1 * N_COLS); round(fwd_rnd, b0, b1, kp + 2 * N_COLS); round(fwd_rnd, b1, b0, kp + 3 * N_COLS); @@ -175,7 +175,7 @@ AES_RETURN aes_xi(encrypt)(const unsigned char *in, unsigned char *out, const ae so we need to control this with the following VC++ pragmas */ -#if defined( _MSC_VER ) && !defined( _WIN64 ) +#if defined( _MSC_VER ) && !defined( _WIN64 ) && !defined( __clang__ ) #pragma optimize( "t", on ) #endif @@ -236,7 +236,7 @@ AES_RETURN aes_xi(decrypt)(const unsigned char *in, unsigned char *out, const ae #endif const uint32_t *kp; - if(cx->inf.b[0] != 10 * 16 && cx->inf.b[0] != 12 * 16 && cx->inf.b[0] != 14 * 16) + if(cx->inf.b[0] != 10 * AES_BLOCK_SIZE && cx->inf.b[0] != 12 * AES_BLOCK_SIZE && cx->inf.b[0] != 14 * AES_BLOCK_SIZE) return EXIT_FAILURE; kp = cx->ks + (key_ofs ? (cx->inf.b[0] >> 2) : 0); @@ -247,15 +247,15 @@ AES_RETURN aes_xi(decrypt)(const unsigned char *in, unsigned char *out, const ae kp = cx->ks + (key_ofs ? 0 : (cx->inf.b[0] >> 2)); switch(cx->inf.b[0]) { - case 14 * 16: + case 14 * AES_BLOCK_SIZE: round(inv_rnd, b1, b0, rnd_key(-13)); round(inv_rnd, b0, b1, rnd_key(-12)); //-fallthrough - case 12 * 16: + case 12 * AES_BLOCK_SIZE: round(inv_rnd, b1, b0, rnd_key(-11)); round(inv_rnd, b0, b1, rnd_key(-10)); //-fallthrough - case 10 * 16: + case 10 * AES_BLOCK_SIZE: round(inv_rnd, b1, b0, rnd_key(-9)); round(inv_rnd, b0, b1, rnd_key(-8)); round(inv_rnd, b1, b0, rnd_key(-7)); diff --git a/aes/aeskey.c b/aes/aeskey.c index 94119185a..0ec5f8954 100644 --- a/aes/aeskey.c +++ b/aes/aeskey.c @@ -101,7 +101,7 @@ AES_RETURN aes_xi(encrypt_key128)(const unsigned char *key, aes_encrypt_ctx cx[1 #endif ke4(cx->ks, 9); cx->inf.l = 0; - cx->inf.b[0] = 10 * 16; + cx->inf.b[0] = 10 * AES_BLOCK_SIZE; #ifdef USE_VIA_ACE_IF_PRESENT if(VIA_ACE_AVAILABLE) @@ -150,7 +150,7 @@ AES_RETURN aes_xi(encrypt_key192)(const unsigned char *key, aes_encrypt_ctx cx[1 #endif kef6(cx->ks, 7); cx->inf.l = 0; - cx->inf.b[0] = 12 * 16; + cx->inf.b[0] = 12 * AES_BLOCK_SIZE; #ifdef USE_VIA_ACE_IF_PRESENT if(VIA_ACE_AVAILABLE) @@ -202,7 +202,7 @@ AES_RETURN aes_xi(encrypt_key256)(const unsigned char *key, aes_encrypt_ctx cx[1 #endif kef8(cx->ks, 6); cx->inf.l = 0; - cx->inf.b[0] = 14 * 16; + cx->inf.b[0] = 14 * AES_BLOCK_SIZE; #ifdef USE_VIA_ACE_IF_PRESENT if(VIA_ACE_AVAILABLE) @@ -329,7 +329,7 @@ AES_RETURN aes_xi(decrypt_key128)(const unsigned char *key, aes_decrypt_ctx cx[1 } #endif cx->inf.l = 0; - cx->inf.b[0] = 10 * 16; + cx->inf.b[0] = 10 * AES_BLOCK_SIZE; #ifdef USE_VIA_ACE_IF_PRESENT if(VIA_ACE_AVAILABLE) @@ -395,7 +395,6 @@ AES_RETURN aes_xi(decrypt_key192)(const unsigned char *key, aes_decrypt_ctx cx[1 #ifdef DEC_KS_UNROLL ss[4] = word_in(key, 4); ss[5] = word_in(key, 5); - cx->ks[v(48,(4))] = ff(ss[4]); cx->ks[v(48,(5))] = ff(ss[5]); kdf6(cx->ks, 0); kd6(cx->ks, 1); @@ -417,7 +416,7 @@ AES_RETURN aes_xi(decrypt_key192)(const unsigned char *key, aes_decrypt_ctx cx[1 } #endif cx->inf.l = 0; - cx->inf.b[0] = 12 * 16; + cx->inf.b[0] = 12 * AES_BLOCK_SIZE; #ifdef USE_VIA_ACE_IF_PRESENT if(VIA_ACE_AVAILABLE) @@ -492,7 +491,6 @@ AES_RETURN aes_xi(decrypt_key256)(const unsigned char *key, aes_decrypt_ctx cx[1 ss[5] = word_in(key, 5); ss[6] = word_in(key, 6); ss[7] = word_in(key, 7); - cx->ks[v(56,(4))] = ff(ss[4]); cx->ks[v(56,(5))] = ff(ss[5]); cx->ks[v(56,(6))] = ff(ss[6]); @@ -518,7 +516,7 @@ AES_RETURN aes_xi(decrypt_key256)(const unsigned char *key, aes_decrypt_ctx cx[1 } #endif cx->inf.l = 0; - cx->inf.b[0] = 14 * 16; + cx->inf.b[0] = 14 * AES_BLOCK_SIZE; #ifdef USE_VIA_ACE_IF_PRESENT if(VIA_ACE_AVAILABLE) diff --git a/aes/aesopt.h b/aes/aesopt.h index a1ef045df..4fa9841eb 100644 --- a/aes/aesopt.h +++ b/aes/aesopt.h @@ -64,7 +64,7 @@ Issue Date: 20/12/2007 Class AESencrypt for encryption - Construtors: + Constructors: AESencrypt(void) AESencrypt(const unsigned char *key) - 128 bit key Members: @@ -74,7 +74,7 @@ Issue Date: 20/12/2007 AES_RETURN encrypt(const unsigned char *in, unsigned char *out) const Class AESdecrypt for encryption - Construtors: + Constructors: AESdecrypt(void) AESdecrypt(const unsigned char *key) - 128 bit key Members: @@ -165,16 +165,21 @@ Issue Date: 20/12/2007 /* 2. Intel AES AND VIA ACE SUPPORT */ -#if defined( __GNUC__ ) && defined( __i386__ ) \ +#if defined( __GNUC__ ) && defined( __i386__ ) && !defined(__BEOS__) \ || defined( _WIN32 ) && defined( _M_IX86 ) && !(defined( _WIN64 ) \ || defined( _WIN32_WCE ) || defined( _MSC_VER ) && ( _MSC_VER <= 800 )) # define VIA_ACE_POSSIBLE #endif -#if (defined( _WIN64 ) && defined( _MSC_VER )) \ - || (defined( __GNUC__ ) && defined( __x86_64__ )) \ - && !(defined( INTEL_AES_POSSIBLE )) -# define INTEL_AES_POSSIBLE +/* AESNI is supported by all Windows x64 compilers, but for Linux/GCC + we have to test for SSE 2, SSE 3, and AES to before enabling it; */ +#if !defined( INTEL_AES_POSSIBLE ) +# if defined( _WIN64 ) && defined( _MSC_VER ) \ + || defined( __GNUC__ ) && defined( __x86_64__ ) && \ + defined( __SSE2__ ) && defined( __SSE3__ ) && \ + defined( __AES__ ) +# define INTEL_AES_POSSIBLE +# endif #endif /* Define this option if support for the Intel AESNI is required @@ -184,10 +189,11 @@ Issue Date: 20/12/2007 AESNI uses a decryption key schedule with the first decryption round key at the high end of the key scedule with the following round keys at lower positions in memory. So AES_REV_DKS must NOT - be defined when AESNI will be used. ALthough it is unlikely that + be defined when AESNI will be used. Although it is unlikely that assembler code will be used with an AESNI build, if it is then AES_REV_DKS must NOT be defined when the assembler files are - built + built (the definition of USE_INTEL_AES_IF_PRESENT in the assembler + code files must match that here if they are used). */ #if 0 && defined( INTEL_AES_POSSIBLE ) && !defined( USE_INTEL_AES_IF_PRESENT ) diff --git a/aes/aestst.h b/aes/aestst.h index 1689e63cc..3c5461c3c 100644 --- a/aes/aestst.h +++ b/aes/aestst.h @@ -78,8 +78,8 @@ Issue Date: 20/12/2007 #define do_enc(a,b,c,d) f_enc_blk(a, b, c) #define do_dec(a,b,c,d) f_dec_blk(a, b, c) #else -#define do_enc(a,b,c,d) f_ecb_enc(a, b, c, AES_BLOCK_SIZE) -#define do_dec(a,b,c,d) f_ecb_dec(a, b, c, AES_BLOCK_SIZE) +#define do_enc(a,b,c,d) f_ecb_enc(a, b, c, 1) +#define do_dec(a,b,c,d) f_ecb_dec(a, b, c, 1) #endif #endif diff --git a/aes/brg_types.h b/aes/brg_types.h deleted file mode 100644 index 307319bf6..000000000 --- a/aes/brg_types.h +++ /dev/null @@ -1,191 +0,0 @@ -/* ---------------------------------------------------------------------------- -Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved. - -The redistribution and use of this software (with or without changes) -is allowed without the payment of fees or royalties provided that: - - source code distributions include the above copyright notice, this - list of conditions and the following disclaimer; - - binary distributions include the above copyright notice, this list - of conditions and the following disclaimer in their documentation. - -This software is provided 'as is' with no explicit or implied warranties -in respect of its operation, including, but not limited to, correctness -and fitness for purpose. ---------------------------------------------------------------------------- -Issue Date: 20/12/2007 - - The unsigned integer types defined here are of the form uint_t where - is the length of the type; for example, the unsigned 32-bit type is - 'uint32_t'. These are NOT the same as the 'C99 integer types' that are - defined in the inttypes.h and stdint.h headers since attempts to use these - types have shown that support for them is still highly variable. However, - since the latter are of the form uint_t, a regular expression search - and replace (in VC++ search on 'uint_{:z}t' and replace with 'uint\1_t') - can be used to convert the types used here to the C99 standard types. -*/ - -#ifndef _BRG_TYPES_H -#define _BRG_TYPES_H - -#if defined(__cplusplus) -extern "C" { -#endif - -#include -#include - -#if defined( _MSC_VER ) && ( _MSC_VER >= 1300 ) -# include -# define ptrint_t intptr_t -#elif defined( __ECOS__ ) -# define intptr_t unsigned int -# define ptrint_t intptr_t -#elif defined( __GNUC__ ) && ( __GNUC__ >= 3 ) -# define ptrint_t intptr_t -#else -# define ptrint_t int -#endif - -#ifndef BRG_UI32 -# define BRG_UI32 -# if UINT_MAX == 4294967295u -# define li_32(h) 0x##h##u -# elif ULONG_MAX == 4294967295u -# define li_32(h) 0x##h##ul -# elif defined( _CRAY ) -# error This code needs 32-bit data types, which Cray machines do not provide -# else -# error Please define uint32_t as a 32-bit unsigned integer type in brg_types.h -# endif -#endif - -#ifndef BRG_UI64 -# if defined( __BORLANDC__ ) && !defined( __MSDOS__ ) -# define BRG_UI64 -# define li_64(h) 0x##h##ui64 -# elif defined( _MSC_VER ) && ( _MSC_VER < 1300 ) /* 1300 == VC++ 7.0 */ -# define BRG_UI64 -# define li_64(h) 0x##h##ui64 -# elif defined( __sun ) && defined( ULONG_MAX ) && ULONG_MAX == 0xfffffffful -# define BRG_UI64 -# define li_64(h) 0x##h##ull -# elif defined( __MVS__ ) -# define BRG_UI64 -# define li_64(h) 0x##h##ull -# elif defined( UINT_MAX ) && UINT_MAX > 4294967295u -# if UINT_MAX == 18446744073709551615u -# define BRG_UI64 -# define li_64(h) 0x##h##u -# endif -# elif defined( ULONG_MAX ) && ULONG_MAX > 4294967295u -# if ULONG_MAX == 18446744073709551615ul -# define BRG_UI64 -# define li_64(h) 0x##h##ul -# endif -# elif defined( ULLONG_MAX ) && ULLONG_MAX > 4294967295u -# if ULLONG_MAX == 18446744073709551615ull -# define BRG_UI64 -# define li_64(h) 0x##h##ull -# endif -# elif defined( ULONG_LONG_MAX ) && ULONG_LONG_MAX > 4294967295u -# if ULONG_LONG_MAX == 18446744073709551615ull -# define BRG_UI64 -# define li_64(h) 0x##h##ull -# endif -# endif -#endif - -#if !defined( BRG_UI64 ) -# if defined( NEED_UINT_64T ) -# error Please define uint64_t as an unsigned 64 bit type in brg_types.h -# endif -#endif - -#ifndef RETURN_VALUES -# define RETURN_VALUES -# if defined( DLL_EXPORT ) -# if defined( _MSC_VER ) || defined ( __INTEL_COMPILER ) -# define VOID_RETURN __declspec( dllexport ) void __stdcall -# define INT_RETURN __declspec( dllexport ) int __stdcall -# elif defined( __GNUC__ ) -# define VOID_RETURN __declspec( __dllexport__ ) void -# define INT_RETURN __declspec( __dllexport__ ) int -# else -# error Use of the DLL is only available on the Microsoft, Intel and GCC compilers -# endif -# elif defined( DLL_IMPORT ) -# if defined( _MSC_VER ) || defined ( __INTEL_COMPILER ) -# define VOID_RETURN __declspec( dllimport ) void __stdcall -# define INT_RETURN __declspec( dllimport ) int __stdcall -# elif defined( __GNUC__ ) -# define VOID_RETURN __declspec( __dllimport__ ) void -# define INT_RETURN __declspec( __dllimport__ ) int -# else -# error Use of the DLL is only available on the Microsoft, Intel and GCC compilers -# endif -# elif defined( __WATCOMC__ ) -# define VOID_RETURN void __cdecl -# define INT_RETURN int __cdecl -# else -# define VOID_RETURN void -# define INT_RETURN int -# endif -#endif - -/* These defines are used to detect and set the memory alignment of pointers. - Note that offsets are in bytes. - - ALIGN_OFFSET(x,n) return the positive or zero offset of - the memory addressed by the pointer 'x' - from an address that is aligned on an - 'n' byte boundary ('n' is a power of 2) - - ALIGN_FLOOR(x,n) return a pointer that points to memory - that is aligned on an 'n' byte boundary - and is not higher than the memory address - pointed to by 'x' ('n' is a power of 2) - - ALIGN_CEIL(x,n) return a pointer that points to memory - that is aligned on an 'n' byte boundary - and is not lower than the memory address - pointed to by 'x' ('n' is a power of 2) -*/ - -#define ALIGN_OFFSET(x,n) (((ptrint_t)(x)) & ((n) - 1)) -#define ALIGN_FLOOR(x,n) ((uint8_t*)(x) - ( ((ptrint_t)(x)) & ((n) - 1))) -#define ALIGN_CEIL(x,n) ((uint8_t*)(x) + (-((ptrint_t)(x)) & ((n) - 1))) - -/* These defines are used to declare buffers in a way that allows - faster operations on longer variables to be used. In all these - defines 'size' must be a power of 2 and >= 8. NOTE that the - buffer size is in bytes but the type length is in bits - - UNIT_TYPEDEF(x,size) declares a variable 'x' of length - 'size' bits - - BUFR_TYPEDEF(x,size,bsize) declares a buffer 'x' of length 'bsize' - bytes defined as an array of variables - each of 'size' bits (bsize must be a - multiple of size / 8) - - UNIT_CAST(x,size) casts a variable to a type of - length 'size' bits - - UPTR_CAST(x,size) casts a pointer to a pointer to a - varaiable of length 'size' bits -*/ - -#define UI_TYPE(size) uint##size##_t -#define UNIT_TYPEDEF(x,size) typedef UI_TYPE(size) x -#define BUFR_TYPEDEF(x,size,bsize) typedef UI_TYPE(size) x[bsize / (size >> 3)] -#define UNIT_CAST(x,size) ((UI_TYPE(size) )(x)) -#define UPTR_CAST(x,size) ((UI_TYPE(size)*)(x)) - -#if defined(__cplusplus) -} -#endif - -#endif From 72da171f28a0c79d6d96708b5aeb9f41cef707b2 Mon Sep 17 00:00:00 2001 From: Dusan Klinec Date: Mon, 20 Aug 2018 14:23:26 +0200 Subject: [PATCH 583/627] ed25519: double scalarmult fix - return fully valid ed point --- ed25519-donna/ed25519-donna-impl-base.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ed25519-donna/ed25519-donna-impl-base.c b/ed25519-donna/ed25519-donna-impl-base.c index eb50a2bad..4771f132d 100644 --- a/ed25519-donna/ed25519-donna-impl-base.c +++ b/ed25519-donna/ed25519-donna-impl-base.c @@ -243,6 +243,7 @@ void ge25519_double_scalarmult_vartime(ge25519 *r, const ge25519 *p1, const bign ge25519_p1p1 t; int32_t i; + memset(&t, 0, sizeof(ge25519_p1p1)); contract256_slidingwindow_modm(slide1, s1, S1_SWINDOWSIZE); contract256_slidingwindow_modm(slide2, s2, S2_SWINDOWSIZE); @@ -283,6 +284,7 @@ void ge25519_double_scalarmult_vartime(ge25519 *r, const ge25519 *p1, const bign ge25519_p1p1_to_partial(r, &t); } + curve25519_mul(r->t, t.x, t.y); } /* computes [s1]p1 + [s2]p2 */ @@ -295,6 +297,7 @@ void ge25519_double_scalarmult_vartime2(ge25519 *r, const ge25519 *p1, const big ge25519_p1p1 t; int32_t i; + memset(&t, 0, sizeof(ge25519_p1p1)); contract256_slidingwindow_modm(slide1, s1, S1_SWINDOWSIZE); contract256_slidingwindow_modm(slide2, s2, S1_SWINDOWSIZE); @@ -329,6 +332,7 @@ void ge25519_double_scalarmult_vartime2(ge25519 *r, const ge25519 *p1, const big ge25519_p1p1_to_partial(r, &t); } + curve25519_mul(r->t, t.x, t.y); } #endif From f1eca083831f0f8d5e0ade5d2960ac98672db277 Mon Sep 17 00:00:00 2001 From: Dusan Klinec Date: Sat, 18 Aug 2018 02:24:48 +0200 Subject: [PATCH 584/627] ed25519: scalarmult fixes - operation result parameter can be the same as operation input parameter - operation returns full extended Edwards point --- ed25519-donna/ed25519-donna-impl-base.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/ed25519-donna/ed25519-donna-impl-base.c b/ed25519-donna/ed25519-donna-impl-base.c index 4771f132d..128445676 100644 --- a/ed25519-donna/ed25519-donna-impl-base.c +++ b/ed25519-donna/ed25519-donna-impl-base.c @@ -425,12 +425,12 @@ void ge25519_scalarmult(ge25519 *r, const ge25519 *p1, const bignum256modm s1) { contract256_window4_modm(slide1, s1); - /* set neutral */ - ge25519_set_neutral(r); - - ge25519_full_to_pniels(pre1, r); ge25519_full_to_pniels(pre1+1, p1); ge25519_double(&d1, p1); + + ge25519_set_neutral(r); + ge25519_full_to_pniels(pre1, r); + ge25519_full_to_pniels(pre1+2, &d1); for (i = 1; i < 7; i++) { ge25519_pnielsadd(&pre1[i+2], &d1, &pre1[i]); @@ -447,6 +447,7 @@ void ge25519_scalarmult(ge25519 *r, const ge25519 *p1, const bignum256modm s1) { ge25519_pnielsadd_p1p1(&t, r, &pre, (unsigned char)slide1[i] >> 7); ge25519_p1p1_to_partial(r, &t); } + curve25519_mul(r->t, t.x, t.y); } void ge25519_scalarmult_base_choose_niels(ge25519_niels *t, const uint8_t table[256][96], uint32_t pos, signed char b) { From b9edb3b976de624e036c60c27120ea08284267cf Mon Sep 17 00:00:00 2001 From: Dusan Klinec Date: Tue, 21 Aug 2018 21:21:40 +0200 Subject: [PATCH 585/627] ed25519: ROTR, ROTL removed from header file - redundant, not used in trezor-crypto - clashes with another ROTR from poly1305 header files if included together --- ed25519-donna/ed25519-donna-portable.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/ed25519-donna/ed25519-donna-portable.h b/ed25519-donna/ed25519-donna-portable.h index 2fa0ac56e..ceeb55741 100644 --- a/ed25519-donna/ed25519-donna-portable.h +++ b/ed25519-donna/ed25519-donna-portable.h @@ -7,8 +7,6 @@ #define DONNA_INLINE #undef ALIGN #define ALIGN(x) __attribute__((aligned(x))) -#define ROTL32(a,b) (((a) << (b)) | ((a) >> (32 - b))) -#define ROTR32(a,b) (((a) >> (b)) | ((a) << (32 - b))) static inline void U32TO8_LE(unsigned char *p, const uint32_t v) { p[0] = (unsigned char)(v ); From bf1e1b13a62e9172976f39feb6b0865703e33d6b Mon Sep 17 00:00:00 2001 From: Dusan Klinec Date: Tue, 21 Aug 2018 21:39:08 +0200 Subject: [PATCH 586/627] chacha20poly1305: header polution reduction - including chacah20poly1305.h polutes general namespace with macros defined in ecrypt-portable.h and ecrypt-machine.h which are needed only for .c files and should not leak to general namespace - I've extracted types definition from ecrypt-portable.h to ecrypt-types.h as types are needed for interface definition in ecypt-sync.h which is needed in chacha20poly1305.h --- chacha20poly1305/chacha20poly1305.c | 1 + chacha20poly1305/chacha_merged.c | 1 + chacha20poly1305/ecrypt-portable.h | 37 +------------------- chacha20poly1305/ecrypt-sync.h | 2 +- chacha20poly1305/ecrypt-types.h | 53 +++++++++++++++++++++++++++++ chacha20poly1305/rfc7539.c | 1 + 6 files changed, 58 insertions(+), 37 deletions(-) create mode 100644 chacha20poly1305/ecrypt-types.h diff --git a/chacha20poly1305/chacha20poly1305.c b/chacha20poly1305/chacha20poly1305.c index 70662a03d..d75ddd162 100644 --- a/chacha20poly1305/chacha20poly1305.c +++ b/chacha20poly1305/chacha20poly1305.c @@ -3,6 +3,7 @@ // than performance. #include "chacha20poly1305.h" +#include "ecrypt-portable.h" void hchacha20(ECRYPT_ctx *x,u8 *c); diff --git a/chacha20poly1305/chacha_merged.c b/chacha20poly1305/chacha_merged.c index f2845846c..95779f3d6 100644 --- a/chacha20poly1305/chacha_merged.c +++ b/chacha20poly1305/chacha_merged.c @@ -5,6 +5,7 @@ Public domain. */ #include "ecrypt-sync.h" +#include "ecrypt-portable.h" #define ROTATE(v,c) (ROTL32(v,c)) #define XOR(v,w) ((v) ^ (w)) diff --git a/chacha20poly1305/ecrypt-portable.h b/chacha20poly1305/ecrypt-portable.h index 438a464a7..da1a79f2a 100644 --- a/chacha20poly1305/ecrypt-portable.h +++ b/chacha20poly1305/ecrypt-portable.h @@ -21,45 +21,10 @@ #define ECRYPT_PORTABLE #include "ecrypt-config.h" +#include "ecrypt-types.h" /* ------------------------------------------------------------------------- */ -/* - * The following types are defined (if available): - * - * u8: unsigned integer type, at least 8 bits - * u16: unsigned integer type, at least 16 bits - * u32: unsigned integer type, at least 32 bits - * u64: unsigned integer type, at least 64 bits - * - * s8, s16, s32, s64 -> signed counterparts of u8, u16, u32, u64 - * - * The selection of minimum-width integer types is taken care of by - * 'ecrypt-config.h'. Note: to enable 64-bit types on 32-bit - * compilers, it might be necessary to switch from ISO C90 mode to ISO - * C99 mode (e.g., gcc -std=c99). - */ - -#ifdef I8T -typedef signed I8T s8; -typedef unsigned I8T u8; -#endif - -#ifdef I16T -typedef signed I16T s16; -typedef unsigned I16T u16; -#endif - -#ifdef I32T -typedef signed I32T s32; -typedef unsigned I32T u32; -#endif - -#ifdef I64T -typedef signed I64T s64; -typedef unsigned I64T u64; -#endif - /* * The following macros are used to obtain exact-width results. */ diff --git a/chacha20poly1305/ecrypt-sync.h b/chacha20poly1305/ecrypt-sync.h index 5f363d4c8..7b8467361 100644 --- a/chacha20poly1305/ecrypt-sync.h +++ b/chacha20poly1305/ecrypt-sync.h @@ -12,7 +12,7 @@ #ifndef ECRYPT_SYNC #define ECRYPT_SYNC -#include "ecrypt-portable.h" +#include "ecrypt-types.h" /* ------------------------------------------------------------------------- */ diff --git a/chacha20poly1305/ecrypt-types.h b/chacha20poly1305/ecrypt-types.h new file mode 100644 index 000000000..e608e220a --- /dev/null +++ b/chacha20poly1305/ecrypt-types.h @@ -0,0 +1,53 @@ +/* ecrypt-types.h */ + +/* + * *** Please do not edit this file. *** + * + * The default macros can be overridden for specific architectures by + * editing 'ecrypt-machine.h'. + */ + +#ifndef ECRYPT_TYPES +#define ECRYPT_TYPES + +#include "ecrypt-config.h" + +/* ------------------------------------------------------------------------- */ + +/* + * The following types are defined (if available): + * + * u8: unsigned integer type, at least 8 bits + * u16: unsigned integer type, at least 16 bits + * u32: unsigned integer type, at least 32 bits + * u64: unsigned integer type, at least 64 bits + * + * s8, s16, s32, s64 -> signed counterparts of u8, u16, u32, u64 + * + * The selection of minimum-width integer types is taken care of by + * 'ecrypt-config.h'. Note: to enable 64-bit types on 32-bit + * compilers, it might be necessary to switch from ISO C90 mode to ISO + * C99 mode (e.g., gcc -std=c99). + */ + +#ifdef I8T +typedef signed I8T s8; +typedef unsigned I8T u8; +#endif + +#ifdef I16T +typedef signed I16T s16; +typedef unsigned I16T u16; +#endif + +#ifdef I32T +typedef signed I32T s32; +typedef unsigned I32T u32; +#endif + +#ifdef I64T +typedef signed I64T s64; +typedef unsigned I64T u64; +#endif + +#endif diff --git a/chacha20poly1305/rfc7539.c b/chacha20poly1305/rfc7539.c index 8aa3b8f0a..7958e6437 100644 --- a/chacha20poly1305/rfc7539.c +++ b/chacha20poly1305/rfc7539.c @@ -3,6 +3,7 @@ #include #include "rfc7539.h" +#include "ecrypt-portable.h" // Initialize the ChaCha20 + Poly1305 context for encryption or decryption // using a 32 byte key and 12 byte nonce as in the RFC 7539 style. From 1863045da447103e1aa56eb1df9f03dd1c4a9eee Mon Sep 17 00:00:00 2001 From: leoreinaux Date: Thu, 30 Aug 2018 07:02:42 -0300 Subject: [PATCH 587/627] add smartcash curve (#176) --- bip32.c | 3 +++ curves.c | 1 + curves.h | 1 + secp256k1.c | 8 ++++++++ secp256k1.h | 1 + 5 files changed, 14 insertions(+) diff --git a/bip32.c b/bip32.c index d7d7baa14..7a510f3b1 100644 --- a/bip32.c +++ b/bip32.c @@ -893,6 +893,9 @@ const curve_info *get_curve_by_name(const char *curve_name) { if (strcmp(curve_name, SECP256K1_GROESTL_NAME) == 0) { return &secp256k1_groestl_info; } + if (strcmp(curve_name, SECP256K1_SMART_NAME) == 0) { + return &secp256k1_smart_info; + } if (strcmp(curve_name, NIST256P1_NAME) == 0) { return &nist256p1_info; } diff --git a/curves.c b/curves.c index 64244560b..972339bdd 100644 --- a/curves.c +++ b/curves.c @@ -25,6 +25,7 @@ const char SECP256K1_NAME[] = "secp256k1"; const char SECP256K1_DECRED_NAME[] = "secp256k1-decred"; const char SECP256K1_GROESTL_NAME[] = "secp256k1-groestl"; +const char SECP256K1_SMART_NAME[] = "secp256k1-smart"; const char NIST256P1_NAME[] = "nist256p1"; const char ED25519_NAME[] = "ed25519"; const char ED25519_CARDANO_NAME[] = "ed25519 cardano seed"; diff --git a/curves.h b/curves.h index 8fdd3c55d..34b796eb0 100644 --- a/curves.h +++ b/curves.h @@ -28,6 +28,7 @@ extern const char SECP256K1_NAME[]; extern const char SECP256K1_DECRED_NAME[]; extern const char SECP256K1_GROESTL_NAME[]; +extern const char SECP256K1_SMART_NAME[]; extern const char NIST256P1_NAME[]; extern const char ED25519_NAME[]; extern const char ED25519_CARDANO_NAME[]; diff --git a/secp256k1.c b/secp256k1.c index 95981eed3..e125806cb 100644 --- a/secp256k1.c +++ b/secp256k1.c @@ -78,3 +78,11 @@ const curve_info secp256k1_groestl_info = { .hasher_sign = HASHER_SHA2, .hasher_pubkey = HASHER_SHA2_RIPEMD, }; + +const curve_info secp256k1_smart_info = { + .bip32_name = "Bitcoin seed", + .params = &secp256k1, + .hasher_base58 = HASHER_SHA3K, + .hasher_sign = HASHER_SHA2, + .hasher_pubkey = HASHER_SHA2_RIPEMD, +}; diff --git a/secp256k1.h b/secp256k1.h index a5442e50c..234ca97a9 100644 --- a/secp256k1.h +++ b/secp256k1.h @@ -33,5 +33,6 @@ extern const ecdsa_curve secp256k1; extern const curve_info secp256k1_info; extern const curve_info secp256k1_decred_info; extern const curve_info secp256k1_groestl_info; +extern const curve_info secp256k1_smart_info; #endif From 4aea73e4bbd2f6239d8c3a940e0d0b6f17048d8c Mon Sep 17 00:00:00 2001 From: Dusan Klinec Date: Thu, 5 Jul 2018 02:10:34 +0200 Subject: [PATCH 588/627] xmr: monero crypto implemented, tests --- Makefile | 7 +- base58.c | 5 +- base58.h | 3 + ed25519-donna/ge25519.c | 378 ++++++++++ ed25519-donna/ge25519.h | 77 ++ ed25519-donna/modm-donna-32bit.c | 117 ++- ed25519-donna/modm-donna-32bit.h | 27 + monero/base58.c | 243 ++++++ monero/base58.h | 43 ++ monero/int-util.h | 77 ++ monero/monero.h | 21 + monero/range_proof.c | 115 +++ monero/range_proof.h | 30 + monero/serialize.c | 54 ++ monero/serialize.h | 15 + monero/xmr.c | 159 ++++ monero/xmr.h | 67 ++ tests/test_check.c | 49 ++ tests/test_check_monero.h | 1216 ++++++++++++++++++++++++++++++ 19 files changed, 2694 insertions(+), 9 deletions(-) create mode 100644 ed25519-donna/ge25519.c create mode 100644 ed25519-donna/ge25519.h create mode 100644 monero/base58.c create mode 100644 monero/base58.h create mode 100644 monero/int-util.h create mode 100644 monero/monero.h create mode 100644 monero/range_proof.c create mode 100644 monero/range_proof.h create mode 100644 monero/serialize.c create mode 100644 monero/serialize.h create mode 100644 monero/xmr.c create mode 100644 monero/xmr.h create mode 100644 tests/test_check_monero.h diff --git a/Makefile b/Makefile index 837e0ecd0..3bad57c8a 100644 --- a/Makefile +++ b/Makefile @@ -51,6 +51,11 @@ SRCS += aes/aescrypt.c aes/aeskey.c aes/aestab.c aes/aes_modes.c SRCS += ed25519-donna/curve25519-donna-32bit.c ed25519-donna/curve25519-donna-helpers.c ed25519-donna/modm-donna-32bit.c SRCS += ed25519-donna/ed25519-donna-basepoint-table.c ed25519-donna/ed25519-donna-32bit-tables.c ed25519-donna/ed25519-donna-impl-base.c SRCS += ed25519-donna/ed25519.c ed25519-donna/curve25519-donna-scalarmult-base.c ed25519-donna/ed25519-sha3.c ed25519-donna/ed25519-keccak.c +SRCS += ed25519-donna/ge25519.c +SRCS += monero/base58.c +SRCS += monero/serialize.c +SRCS += monero/xmr.c +SRCS += monero/range_proof.c SRCS += blake256.c SRCS += blake2b.c blake2s.c SRCS += groestl.c @@ -75,7 +80,7 @@ tests: tests/test_check tests/test_openssl tests/test_speed tests/libtrezor-cryp tests/aestst: aes/aestst.o aes/aescrypt.o aes/aeskey.o aes/aestab.o $(CC) $^ -o $@ -tests/test_check.o: tests/test_check_cardano.h tests/test_check_cashaddr.h tests/test_check_segwit.h +tests/test_check.o: tests/test_check_cardano.h tests/test_check_monero.h tests/test_check_cashaddr.h tests/test_check_segwit.h tests/test_check: tests/test_check.o $(OBJS) $(CC) tests/test_check.o $(OBJS) $(TESTLIBS) -o tests/test_check diff --git a/base58.c b/base58.c index 5afbbd0d4..6825ae56b 100644 --- a/base58.c +++ b/base58.c @@ -29,7 +29,8 @@ #include "ripemd160.h" #include "memzero.h" -static const int8_t b58digits_map[] = { +const char b58digits_ordered[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; +const int8_t b58digits_map[] = { -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, @@ -148,8 +149,6 @@ int b58check(const void *bin, size_t binsz, HasherType hasher_type, const char * return binc[0]; } -static const char b58digits_ordered[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; - bool b58enc(char *b58, size_t *b58sz, const void *data, size_t binsz) { const uint8_t *bin = data; diff --git a/base58.h b/base58.h index 41b0b7d4c..0fa9167bf 100644 --- a/base58.h +++ b/base58.h @@ -29,6 +29,9 @@ #include "hasher.h" #include "options.h" +extern const char b58digits_ordered[]; +extern const int8_t b58digits_map[]; + int base58_encode_check(const uint8_t *data, int len, HasherType hasher_type, char *str, int strsize); int base58_decode_check(const char *str, HasherType hasher_type, uint8_t *data, int datalen); diff --git a/ed25519-donna/ge25519.c b/ed25519-donna/ge25519.c new file mode 100644 index 000000000..da1fac7b7 --- /dev/null +++ b/ed25519-donna/ge25519.c @@ -0,0 +1,378 @@ +// +// Created by Dusan Klinec on 29/04/2018. +// + +#include +#include "ge25519.h" + +static const uint32_t reduce_mask_25 = (1 << 25) - 1; +static const uint32_t reduce_mask_26 = (1 << 26) - 1; + +/* sqrt(x) is such an integer y that 0 <= y <= p - 1, y % 2 = 0, and y^2 = x (mod p). */ +/* d = -121665 / 121666 */ +static const bignum25519 ALIGN(16) fe_d = { + 0x35978a3, 0x0d37284, 0x3156ebd, 0x06a0a0e, 0x001c029, 0x179e898, 0x3a03cbb, 0x1ce7198, 0x2e2b6ff, 0x1480db3}; /* d */ +static const bignum25519 ALIGN(16) fe_sqrtm1 = { + 0x20ea0b0, 0x186c9d2, 0x08f189d, 0x035697f, 0x0bd0c60, 0x1fbd7a7, 0x2804c9e, 0x1e16569, 0x004fc1d, 0x0ae0c92}; /* sqrt(-1) */ +//static const bignum25519 ALIGN(16) fe_d2 = { +// 0x2b2f159, 0x1a6e509, 0x22add7a, 0x0d4141d, 0x0038052, 0x0f3d130, 0x3407977, 0x19ce331, 0x1c56dff, 0x0901b67}; /* 2 * d */ + +/* A = 2 * (1 - d) / (1 + d) = 486662 */ +static const bignum25519 ALIGN(16) fe_ma2 = { + 0x33de3c9, 0x1fff236, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff}; /* -A^2 */ +static const bignum25519 ALIGN(16) fe_ma = { + 0x3f892e7, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff}; /* -A */ +static const bignum25519 ALIGN(16) fe_fffb1 = { + 0x1e3bdff, 0x025a2b3, 0x18e5bab, 0x0ba36ac, 0x0b9afed, 0x004e61c, 0x31d645f, 0x09d1bea, 0x102529e, 0x0063810}; /* sqrt(-2 * A * (A + 2)) */ +static const bignum25519 ALIGN(16) fe_fffb2 = { + 0x383650d, 0x066df27, 0x10405a4, 0x1cfdd48, 0x2b887f2, 0x1e9a041, 0x1d7241f, 0x0612dc5, 0x35fba5d, 0x0cbe787}; /* sqrt(2 * A * (A + 2)) */ +static const bignum25519 ALIGN(16) fe_fffb3 = { + 0x0cfd387, 0x1209e3a, 0x3bad4fc, 0x18ad34d, 0x2ff6c02, 0x0f25d12, 0x15cdfe0, 0x0e208ed, 0x32eb3df, 0x062d7bb}; /* sqrt(-sqrt(-1) * A * (A + 2)) */ +static const bignum25519 ALIGN(16) fe_fffb4 = { + 0x2b39186, 0x14640ed, 0x14930a7, 0x04509fa, 0x3b91bf0, 0x0f7432e, 0x07a443f, 0x17f24d8, 0x031067d, 0x0690fcc}; /* sqrt(sqrt(-1) * A * (A + 2)) */ + +void curve25519_set(bignum25519 r, uint32_t x){ + r[0] = x & reduce_mask_26; x >>= 26; + r[1] = x & reduce_mask_25; + r[2] = 0; + r[3] = 0; + r[4] = 0; + r[5] = 0; + r[6] = 0; + r[7] = 0; + r[8] = 0; + r[9] = 0; +} + +void curve25519_set_d(bignum25519 r){ + curve25519_copy(r, ge25519_ecd); +} + +void curve25519_set_2d(bignum25519 r){ + curve25519_copy(r, ge25519_ec2d); +} + +void curve25519_set_sqrtneg1(bignum25519 r){ + curve25519_copy(r, ge25519_sqrtneg1); +} + +int curve25519_isnegative(const bignum25519 f) { + unsigned char s[32]; + curve25519_contract(s, f); + return s[0] & 1; +} + +int curve25519_isnonzero(const bignum25519 f) { + unsigned char s[32]; + curve25519_contract(s, f); + return ((((int) (s[0] | s[1] | s[2] | s[3] | s[4] | s[5] | s[6] | s[7] | s[8] | + s[9] | s[10] | s[11] | s[12] | s[13] | s[14] | s[15] | s[16] | s[17] | + s[18] | s[19] | s[20] | s[21] | s[22] | s[23] | s[24] | s[25] | s[26] | + s[27] | s[28] | s[29] | s[30] | s[31]) - 1) >> 8) + 1) & 0x1; +} + +void curve25519_reduce(bignum25519 out, const bignum25519 in) { + uint32_t c; + out[0] = in[0] ; c = (out[0] >> 26); out[0] &= reduce_mask_26; + out[1] = in[1] + c; c = (out[1] >> 25); out[1] &= reduce_mask_25; + out[2] = in[2] + c; c = (out[2] >> 26); out[2] &= reduce_mask_26; + out[3] = in[3] + c; c = (out[3] >> 25); out[3] &= reduce_mask_25; + out[4] = in[4] + c; c = (out[4] >> 26); out[4] &= reduce_mask_26; + out[5] = in[5] + c; c = (out[5] >> 25); out[5] &= reduce_mask_25; + out[6] = in[6] + c; c = (out[6] >> 26); out[6] &= reduce_mask_26; + out[7] = in[7] + c; c = (out[7] >> 25); out[7] &= reduce_mask_25; + out[8] = in[8] + c; c = (out[8] >> 26); out[8] &= reduce_mask_26; + out[9] = in[9] + c; c = (out[9] >> 25); out[9] &= reduce_mask_25; + out[0] += 19 * c; +} + +static void curve25519_divpowm1(bignum25519 r, const bignum25519 u, const bignum25519 v) { + bignum25519 v3={0}, uv7={0}, t0={0}, t1={0}, t2={0}; + int i; + + curve25519_square(v3, v); + curve25519_mul(v3, v3, v); /* v3 = v^3 */ + curve25519_square(uv7, v3); + curve25519_mul(uv7, uv7, v); + curve25519_mul(uv7, uv7, u); /* uv7 = uv^7 */ + + /*fe_pow22523(uv7, uv7);*/ + /* From fe_pow22523.c */ + + curve25519_square(t0, uv7); + curve25519_square(t1, t0); + curve25519_square(t1, t1); + curve25519_mul(t1, uv7, t1); + curve25519_mul(t0, t0, t1); + curve25519_square(t0, t0); + curve25519_mul(t0, t1, t0); + curve25519_square(t1, t0); + for (i = 0; i < 4; ++i) { + curve25519_square(t1, t1); + } + curve25519_mul(t0, t1, t0); + curve25519_square(t1, t0); + for (i = 0; i < 9; ++i) { + curve25519_square(t1, t1); + } + curve25519_mul(t1, t1, t0); + curve25519_square(t2, t1); + for (i = 0; i < 19; ++i) { + curve25519_square(t2, t2); + } + curve25519_mul(t1, t2, t1); + for (i = 0; i < 10; ++i) { + curve25519_square(t1, t1); + } + curve25519_mul(t0, t1, t0); + curve25519_square(t1, t0); + for (i = 0; i < 49; ++i) { + curve25519_square(t1, t1); + } + curve25519_mul(t1, t1, t0); + curve25519_square(t2, t1); + for (i = 0; i < 99; ++i) { + curve25519_square(t2, t2); + } + curve25519_mul(t1, t2, t1); + for (i = 0; i < 50; ++i) { + curve25519_square(t1, t1); + } + curve25519_mul(t0, t1, t0); + curve25519_square(t0, t0); + curve25519_square(t0, t0); + curve25519_mul(t0, t0, uv7); + + /* End fe_pow22523.c */ + /* t0 = (uv^7)^((q-5)/8) */ + curve25519_mul(t0, t0, v3); + curve25519_mul(r, t0, u); /* u^(m+1)v^(-(m+1)) */ +} + +void curve25519_expand_reduce(bignum25519 out, const unsigned char in[32]) { + uint32_t x0,x1,x2,x3,x4,x5,x6,x7; +#define F(s) \ + ((((uint32_t)in[s + 0]) ) | \ + (((uint32_t)in[s + 1]) << 8) | \ + (((uint32_t)in[s + 2]) << 16) | \ + (((uint32_t)in[s + 3]) << 24)) + x0 = F(0); + x1 = F(4); + x2 = F(8); + x3 = F(12); + x4 = F(16); + x5 = F(20); + x6 = F(24); + x7 = F(28); +#undef F + + out[0] = ( x0 ) & reduce_mask_26; + out[1] = ((((uint64_t)x1 << 32) | x0) >> 26) & reduce_mask_25; + out[2] = ((((uint64_t)x2 << 32) | x1) >> 19) & reduce_mask_26; + out[3] = ((((uint64_t)x3 << 32) | x2) >> 13) & reduce_mask_25; + out[4] = (( x3) >> 6) & reduce_mask_26; + out[5] = ( x4 ) & reduce_mask_25; + out[6] = ((((uint64_t)x5 << 32) | x4) >> 25) & reduce_mask_26; + out[7] = ((((uint64_t)x6 << 32) | x5) >> 19) & reduce_mask_25; + out[8] = ((((uint64_t)x7 << 32) | x6) >> 12) & reduce_mask_26; + out[9] = (( x7) >> 6); // & reduce_mask_25; /* ignore the top bit */ + out[0] += 19 * (out[9] >> 25); + out[9] &= reduce_mask_25; +} + +int ge25519_check(const ge25519 *r){ + /* return (z % q != 0 and + x * y % q == z * t % q and + (y * y - x * x - z * z - ed25519.d * t * t) % q == 0) + */ + + bignum25519 z={0}, lhs={0}, rhs={0}, tmp={0}, res={0}; + curve25519_reduce(z, r->z); + + curve25519_mul(lhs, r->x, r->y); + curve25519_mul(rhs, r->z, r->t); + curve25519_sub_reduce(lhs, lhs, rhs); + + curve25519_square(res, r->y); + curve25519_square(tmp, r->x); + curve25519_sub_reduce(res, res, tmp); + curve25519_square(tmp, r->z); + curve25519_sub_reduce(res, res, tmp); + curve25519_square(tmp, r->t); + curve25519_mul(tmp, tmp, ge25519_ecd); + curve25519_sub_reduce(res, res, tmp); + + const int c1 = curve25519_isnonzero(z); + const int c2 = curve25519_isnonzero(lhs); + const int c3 = curve25519_isnonzero(res); + return c1 & (c2^0x1) & (c3^0x1); +} + +int ge25519_eq(const ge25519 *a, const ge25519 *b){ + int eq = 1; + bignum25519 t1={0}, t2={0}; + + eq &= ge25519_check(a); + eq &= ge25519_check(b); + + curve25519_mul(t1, a->x, b->z); + curve25519_mul(t2, b->x, a->z); + curve25519_sub_reduce(t1, t1, t2); + eq &= curve25519_isnonzero(t1) ^ 1; + + curve25519_mul(t1, a->y, b->z); + curve25519_mul(t2, b->y, a->z); + curve25519_sub_reduce(t1, t1, t2); + eq &= curve25519_isnonzero(t1) ^ 1; + + return eq; +} + +void ge25519_copy(ge25519 *dst, const ge25519 *src){ + curve25519_copy(dst->x, src->x); + curve25519_copy(dst->y, src->y); + curve25519_copy(dst->z, src->z); + curve25519_copy(dst->t, src->t); +} + +void ge25519_set_base(ge25519 *r){ + ge25519_copy(r, &ge25519_basepoint); +} + +void ge25519_mul8(ge25519 *r, const ge25519 *t) { + ge25519_double_partial(r, t); + ge25519_double_partial(r, r); + ge25519_double(r, r); +} + +void ge25519_neg_partial(ge25519 *r){ + curve25519_neg(r->x, r->x); +} + +void ge25519_neg_full(ge25519 *r){ + curve25519_neg(r->x, r->x); + curve25519_neg(r->t, r->t); +} + +void ge25519_reduce(ge25519 *r, const ge25519 *t){ + curve25519_reduce(r->x, t->x); + curve25519_reduce(r->y, t->y); + curve25519_reduce(r->z, t->z); + curve25519_reduce(r->t, t->t); +} + +void ge25519_norm(ge25519 *r, const ge25519 * t){ + bignum25519 zinv; + curve25519_recip(zinv, t->z); + curve25519_mul(r->x, t->x, zinv); + curve25519_mul(r->y, t->y, zinv); + curve25519_mul(r->t, r->x, r->y); + curve25519_set(r->z, 1); +} + +void ge25519_add(ge25519 *r, const ge25519 *p, const ge25519 *q, unsigned char signbit) { + ge25519_pniels P_ni; + ge25519_p1p1 P_11; + + ge25519_full_to_pniels(&P_ni, q); + ge25519_pnielsadd_p1p1(&P_11, p, &P_ni, signbit); + ge25519_p1p1_to_full(r, &P_11); +} + +void ge25519_fromfe_frombytes_vartime(ge25519 *r, const unsigned char *s){ + bignum25519 u={0}, v={0}, w={0}, x={0}, y={0}, z={0}; + unsigned char sign; + + curve25519_expand_reduce(u, s); + + curve25519_square(v, u); + curve25519_add_reduce(v, v, v); /* 2 * u^2 */ + curve25519_set(w, 1); + curve25519_add_reduce(w, v, w); /* w = 2 * u^2 + 1 */ + + curve25519_square(x, w); /* w^2 */ + curve25519_mul(y, fe_ma2, v); /* -2 * A^2 * u^2 */ + curve25519_add_reduce(x, x, y); /* x = w^2 - 2 * A^2 * u^2 */ + + curve25519_divpowm1(r->x, w, x); /* (w / x)^(m + 1) */ + curve25519_square(y, r->x); + curve25519_mul(x, y, x); + curve25519_sub_reduce(y, w, x); + curve25519_copy(z, fe_ma); + + if (curve25519_isnonzero(y)) { + curve25519_add_reduce(y, w, x); + if (curve25519_isnonzero(y)) { + goto negative; + } else { + curve25519_mul(r->x, r->x, fe_fffb1); + } + } else { + curve25519_mul(r->x, r->x, fe_fffb2); + } + curve25519_mul(r->x, r->x, u); /* u * sqrt(2 * A * (A + 2) * w / x) */ + curve25519_mul(z, z, v); /* -2 * A * u^2 */ + sign = 0; + goto setsign; +negative: + curve25519_mul(x, x, fe_sqrtm1); + curve25519_sub_reduce(y, w, x); + if (curve25519_isnonzero(y)) { + assert((curve25519_add_reduce(y, w, x), !curve25519_isnonzero(y))); + curve25519_mul(r->x, r->x, fe_fffb3); + } else { + curve25519_mul(r->x, r->x, fe_fffb4); + } + /* r->x = sqrt(A * (A + 2) * w / x) */ + /* z = -A */ + sign = 1; +setsign: + if (curve25519_isnegative(r->x) != sign) { + assert(curve25519_isnonzero(r->x)); + curve25519_neg(r->x, r->x); + } + curve25519_add_reduce(r->z, z, w); + curve25519_sub_reduce(r->y, z, w); + curve25519_mul(r->x, r->x, r->z); + + // Partial form, saving from T coord computation . + // Later is mul8 discarding T anyway. + // rt = ((rx * ry % q) * inv(rz)) % q + // curve25519_mul(x, r->x, r->y); + // curve25519_recip(z, r->z); + // curve25519_mul(r->t, x, z); + +#if !defined(NDEBUG) + { + bignum25519 check_x={0}, check_y={0}, check_iz={0}, check_v={0}; + curve25519_recip(check_iz, r->z); + curve25519_mul(check_x, r->x, check_iz); + curve25519_mul(check_y, r->y, check_iz); + curve25519_square(check_x, check_x); + curve25519_square(check_y, check_y); + curve25519_mul(check_v, check_x, check_y); + curve25519_mul(check_v, fe_d, check_v); + curve25519_add_reduce(check_v, check_v, check_x); + curve25519_sub_reduce(check_v, check_v, check_y); + curve25519_set(check_x, 1); + curve25519_add_reduce(check_v, check_v, check_x); + assert(!curve25519_isnonzero(check_v)); + } +#endif +} + +int ge25519_unpack_vartime(ge25519 *r, const unsigned char *s){ + int res = ge25519_unpack_negative_vartime(r, s); + ge25519_neg_full(r); + return res; +} + +void ge25519_scalarmult_base_wrapper(ge25519 *r, const bignum256modm s){ + ge25519_scalarmult_base_niels(r, ge25519_niels_base_multiples, s); + ge25519_norm(r, r); +} + +void ge25519_scalarmult_wrapper(ge25519 *r, const ge25519 *P, const bignum256modm a){ + ge25519_scalarmult(r, P, a); + ge25519_norm(r, r); +} diff --git a/ed25519-donna/ge25519.h b/ed25519-donna/ge25519.h new file mode 100644 index 000000000..964c6aef1 --- /dev/null +++ b/ed25519-donna/ge25519.h @@ -0,0 +1,77 @@ +// +// Created by Dusan Klinec on 29/04/2018. +// + +#ifndef GE25519_H +#define GE25519_H + +#include +#include "ed25519-donna.h" + +/* uint32_t to Zmod(2^255-19) */ +void curve25519_set(bignum25519 r, uint32_t x); + +/* set d */ +void curve25519_set_d(bignum25519 r); + +/* set 2d */ +void curve25519_set_2d(bignum25519 r); + +/* set sqrt(-1) */ +void curve25519_set_sqrtneg1(bignum25519 r); + +/* constant time Zmod(2^255-19) negative test */ +int curve25519_isnegative(const bignum25519 f); + +/* constant time Zmod(2^255-19) non-zero test */ +int curve25519_isnonzero(const bignum25519 f); + +/* reduce Zmod(2^255-19) */ +void curve25519_reduce(bignum25519 r, const bignum25519 in); + +/* Zmod(2^255-19) from byte array to bignum25519 expansion with modular reduction */ +void curve25519_expand_reduce(bignum25519 out, const unsigned char in[32]); + +/* check if r is on curve */ +int ge25519_check(const ge25519 *r); + +/* a == b */ +int ge25519_eq(const ge25519 *a, const ge25519 *b); + +/* copies one point to another */ +void ge25519_copy(ge25519 *dst, const ge25519 *src); + +/* sets B point to r */ +void ge25519_set_base(ge25519 *r); + +/* 8*P */ +void ge25519_mul8(ge25519 *r, const ge25519 *t); + +/* -P */ +void ge25519_neg_partial(ge25519 *r); + +/* -P */ +void ge25519_neg_full(ge25519 *r); + +/* reduce all coords */ +void ge25519_reduce(ge25519 *r, const ge25519 *t); + +/* normalizes coords. (x, y, 1, x*y) */ +void ge25519_norm(ge25519 *r, const ge25519 * t); + +/* Simple addition */ +void ge25519_add(ge25519 *r, const ge25519 *a, const ge25519 *b, unsigned char signbit); + +/* point from bytes, used in H_p() */ +void ge25519_fromfe_frombytes_vartime(ge25519 *r, const unsigned char *s); + +/* point from bytes */ +int ge25519_unpack_vartime(ge25519 *r, const unsigned char *s); + +/* aG, wrapper for niels base mult. */ +void ge25519_scalarmult_base_wrapper(ge25519 *r, const bignum256modm s); + +/* aP, wrapper. General purpose, normalizes after multiplication */ +void ge25519_scalarmult_wrapper(ge25519 *r, const ge25519 *P, const bignum256modm a); + +#endif diff --git a/ed25519-donna/modm-donna-32bit.c b/ed25519-donna/modm-donna-32bit.c index 0086cd2cc..de2f5220e 100644 --- a/ed25519-donna/modm-donna-32bit.c +++ b/ed25519-donna/modm-donna-32bit.c @@ -216,13 +216,13 @@ void mul256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y) c += mul32x32_64(x[0], y[8]) + mul32x32_64(x[1], y[7]) + mul32x32_64(x[2], y[6]) + mul32x32_64(x[3], y[5]) + mul32x32_64(x[4], y[4]) + mul32x32_64(x[5], y[3]) + mul32x32_64(x[6], y[2]) + mul32x32_64(x[7], y[1]) + mul32x32_64(x[8], y[0]); f = (bignum256modm_element_t)c; r1[8] = (f & 0x00ffffff); q1[0] = (f >> 8) & 0x3fffff; c >>= 30; c += mul32x32_64(x[1], y[8]) + mul32x32_64(x[2], y[7]) + mul32x32_64(x[3], y[6]) + mul32x32_64(x[4], y[5]) + mul32x32_64(x[5], y[4]) + mul32x32_64(x[6], y[3]) + mul32x32_64(x[7], y[2]) + mul32x32_64(x[8], y[1]); - f = (bignum256modm_element_t)c; q1[0] = (q1[0] | (f << 22)) & 0x3fffffff; q1[1] = (f >> 8) & 0x3fffff; c >>= 30; + f = (bignum256modm_element_t)c; q1[0] = (q1[0] | (f << 22)) & 0x3fffffff; q1[1] = (f >> 8) & 0x3fffff; c >>= 30; c += mul32x32_64(x[2], y[8]) + mul32x32_64(x[3], y[7]) + mul32x32_64(x[4], y[6]) + mul32x32_64(x[5], y[5]) + mul32x32_64(x[6], y[4]) + mul32x32_64(x[7], y[3]) + mul32x32_64(x[8], y[2]); - f = (bignum256modm_element_t)c; q1[1] = (q1[1] | (f << 22)) & 0x3fffffff; q1[2] = (f >> 8) & 0x3fffff; c >>= 30; + f = (bignum256modm_element_t)c; q1[1] = (q1[1] | (f << 22)) & 0x3fffffff; q1[2] = (f >> 8) & 0x3fffff; c >>= 30; c += mul32x32_64(x[3], y[8]) + mul32x32_64(x[4], y[7]) + mul32x32_64(x[5], y[6]) + mul32x32_64(x[6], y[5]) + mul32x32_64(x[7], y[4]) + mul32x32_64(x[8], y[3]); - f = (bignum256modm_element_t)c; q1[2] = (q1[2] | (f << 22)) & 0x3fffffff; q1[3] = (f >> 8) & 0x3fffff; c >>= 30; + f = (bignum256modm_element_t)c; q1[2] = (q1[2] | (f << 22)) & 0x3fffffff; q1[3] = (f >> 8) & 0x3fffff; c >>= 30; c += mul32x32_64(x[4], y[8]) + mul32x32_64(x[5], y[7]) + mul32x32_64(x[6], y[6]) + mul32x32_64(x[7], y[5]) + mul32x32_64(x[8], y[4]); - f = (bignum256modm_element_t)c; q1[3] = (q1[3] | (f << 22)) & 0x3fffffff; q1[4] = (f >> 8) & 0x3fffff; c >>= 30; + f = (bignum256modm_element_t)c; q1[3] = (q1[3] | (f << 22)) & 0x3fffffff; q1[4] = (f >> 8) & 0x3fffff; c >>= 30; c += mul32x32_64(x[5], y[8]) + mul32x32_64(x[6], y[7]) + mul32x32_64(x[7], y[6]) + mul32x32_64(x[8], y[5]); f = (bignum256modm_element_t)c; q1[4] = (q1[4] | (f << 22)) & 0x3fffffff; q1[5] = (f >> 8) & 0x3fffff; c >>= 30; c += mul32x32_64(x[6], y[8]) + mul32x32_64(x[7], y[7]) + mul32x32_64(x[8], y[6]); @@ -282,7 +282,7 @@ void expand256_modm(bignum256modm out, const unsigned char *in, size_t len) { q1[5] = ((x[12] >> 14) | (x[13] << 18)) & 0x3fffffff; q1[6] = ((x[13] >> 12) | (x[14] << 20)) & 0x3fffffff; q1[7] = ((x[14] >> 10) | (x[15] << 22)) & 0x3fffffff; - q1[8] = ((x[15] >> 8) ); + q1[8] = ((x[15] >> 8) ); barrett_reduce256_modm(out, q1, out); } @@ -408,3 +408,110 @@ void contract256_slidingwindow_modm(signed char r[256], const bignum256modm s, i } } } + +void set256_modm(bignum256modm r, uint64_t v) { + r[0] = (bignum256modm_element_t) (v & 0x3fffffff); v >>= 30; + r[1] = (bignum256modm_element_t) (v & 0x3fffffff); v >>= 30; + r[2] = (bignum256modm_element_t) (v & 0x3fffffff); + r[3] = 0; + r[4] = 0; + r[5] = 0; + r[6] = 0; + r[7] = 0; + r[8] = 0; +} + +int get256_modm(uint64_t * v, const bignum256modm r){ + *v = 0; + int con1 = 0; + +#define NONZ(x) ((((((int64_t)(x)) - 1) >> 32) + 1) & 1) + bignum256modm_element_t c = 0; + c = r[0]; *v += (uint64_t)c & 0x3fffffff; c >>= 30; // 30 + c += r[1]; *v += ((uint64_t)c & 0x3fffffff) << 30; c >>= 30; // 60 + c += r[2]; *v += ((uint64_t)c & 0xf) << 60; con1 |= NONZ(c>>4); c >>= 30; // 64 bits + c += r[3]; con1 |= NONZ(c); c >>= 30; + c += r[4]; con1 |= NONZ(c); c >>= 30; + c += r[5]; con1 |= NONZ(c); c >>= 30; + c += r[6]; con1 |= NONZ(c); c >>= 30; + c += r[7]; con1 |= NONZ(c); c >>= 30; + c += r[8]; con1 |= NONZ(c); c >>= 30; + con1 |= NONZ(c); +#undef NONZ + + return con1 ^ 1; +} + +int eq256_modm(const bignum256modm x, const bignum256modm y){ + size_t differentbits = 0; + int len = bignum256modm_limb_size; + while (len--) { + differentbits |= (*x++ ^ *y++); + } + return (int) (1 & ((differentbits - 1) >> bignum256modm_bits_per_limb)); +} + +int cmp256_modm(const bignum256modm x, const bignum256modm y){ + int len = 2*bignum256modm_limb_size; + uint32_t a_gt = 0; + uint32_t b_gt = 0; + + // 16B chunks + while (len--) { + const uint32_t ln = (const uint32_t) len; + const uint32_t a = (x[ln>>1] >> 16*(ln & 1)) & 0xffff; + const uint32_t b = (y[ln>>1] >> 16*(ln & 1)) & 0xffff; + + const uint32_t limb_a_gt = ((b - a) >> 16) & 1; + const uint32_t limb_b_gt = ((a - b) >> 16) & 1; + a_gt |= limb_a_gt & ~b_gt; + b_gt |= limb_b_gt & ~a_gt; + } + + return a_gt - b_gt; +} + +int iszero256_modm(const bignum256modm x){ + size_t differentbits = 0; + int len = bignum256modm_limb_size; + while (len--) { + differentbits |= (*x++); + } + return (int) (1 & ((differentbits - 1) >> bignum256modm_bits_per_limb)); +} + +void copy256_modm(bignum256modm r, const bignum256modm x){ + r[0] = x[0]; + r[1] = x[1]; + r[2] = x[2]; + r[3] = x[3]; + r[4] = x[4]; + r[5] = x[5]; + r[6] = x[6]; + r[7] = x[7]; + r[8] = x[8]; +} + +int check256_modm(const bignum256modm x){ + int ok = 1; + bignum256modm t={0}, z={0}; + + ok &= iszero256_modm(x) ^ 1; + barrett_reduce256_modm(t, z, x); + ok &= eq256_modm(t, x); + return ok; +} + +void mulsub256_modm(bignum256modm r, const bignum256modm a, const bignum256modm b, const bignum256modm c){ + //(cc - aa * bb) % l + bignum256modm t={0}; + mul256_modm(t, a, b); + sub256_modm(r, c, t); +} + +void muladd256_modm(bignum256modm r, const bignum256modm a, const bignum256modm b, const bignum256modm c){ + //(cc + aa * bb) % l + bignum256modm t={0}; + mul256_modm(t, a, b); + add256_modm(r, c, t); +} diff --git a/ed25519-donna/modm-donna-32bit.h b/ed25519-donna/modm-donna-32bit.h index f34633645..98090f2fe 100644 --- a/ed25519-donna/modm-donna-32bit.h +++ b/ed25519-donna/modm-donna-32bit.h @@ -51,3 +51,30 @@ void contract256_modm(unsigned char out[32], const bignum256modm in); void contract256_window4_modm(signed char r[64], const bignum256modm in); void contract256_slidingwindow_modm(signed char r[256], const bignum256modm s, int windowsize); + +/* 64bit uint to scalar value */ +void set256_modm(bignum256modm r, uint64_t v); + +/* scalar value to 64bit uint */ +int get256_modm(uint64_t * v, const bignum256modm r); + +/* equality test on two reduced scalar values */ +int eq256_modm(const bignum256modm x, const bignum256modm y); + +/* comparison of two reduced scalar values */ +int cmp256_modm(const bignum256modm x, const bignum256modm y); + +/* scalar null check, has to be reduced */ +int iszero256_modm(const bignum256modm x); + +/* simple copy, no reduction */ +void copy256_modm(bignum256modm r, const bignum256modm x); + +/* check if nonzero && same after reduction */ +int check256_modm(const bignum256modm x); + +/* (cc - aa * bb) % l */ +void mulsub256_modm(bignum256modm r, const bignum256modm a, const bignum256modm b, const bignum256modm c); + +/* (cc + aa * bb) % l */ +void muladd256_modm(bignum256modm r, const bignum256modm a, const bignum256modm b, const bignum256modm c); diff --git a/monero/base58.c b/monero/base58.c new file mode 100644 index 000000000..8769f11f9 --- /dev/null +++ b/monero/base58.c @@ -0,0 +1,243 @@ +// Copyright (c) 2014-2018, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers + +#include +#include +#include +#include +#include "base58.h" +#include "int-util.h" +#include "sha2.h" +#include "../base58.h" + +const size_t alphabet_size = 58; // sizeof(b58digits_ordered) - 1; +const size_t encoded_block_sizes[] = {0, 2, 3, 5, 6, 7, 9, 10, 11}; +const size_t full_block_size = sizeof(encoded_block_sizes) / sizeof(encoded_block_sizes[0]) - 1; +const size_t full_encoded_block_size = 11; // encoded_block_sizes[full_block_size]; +const size_t addr_checksum_size = 4; +const int decoded_block_sizes[] = {0, -1, 1, 2, -1, 3, 4, 5, -1, 6, 7, 8}; +#define reverse_alphabet(letter) ((int8_t) b58digits_map[(int)letter]) + + +uint64_t uint_8be_to_64(const uint8_t* data, size_t size) +{ + assert(1 <= size && size <= sizeof(uint64_t)); + + uint64_t res = 0; + switch (9 - size) + { + case 1: res |= *data++; /* FALLTHRU */ + case 2: res <<= 8; res |= *data++; /* FALLTHRU */ + case 3: res <<= 8; res |= *data++; /* FALLTHRU */ + case 4: res <<= 8; res |= *data++; /* FALLTHRU */ + case 5: res <<= 8; res |= *data++; /* FALLTHRU */ + case 6: res <<= 8; res |= *data++; /* FALLTHRU */ + case 7: res <<= 8; res |= *data++; /* FALLTHRU */ + case 8: res <<= 8; res |= *data; break; + default: assert(false); + } + + return res; +} + +void uint_64_to_8be(uint64_t num, size_t size, uint8_t* data) +{ + assert(1 <= size && size <= sizeof(uint64_t)); + + uint64_t num_be = SWAP64(num); + memcpy(data, (uint8_t*)(&num_be) + sizeof(uint64_t) - size, size); +} + +void encode_block(const char* block, size_t size, char* res) +{ + assert(1 <= size && size <= full_block_size); + + uint64_t num = uint_8be_to_64((uint8_t*)(block), size); + int i = ((int)(encoded_block_sizes[size])) - 1; + while (0 <= i) + { + uint64_t remainder = num % alphabet_size; + num /= alphabet_size; + res[i] = b58digits_ordered[remainder]; + --i; + } +} + +bool decode_block(const char* block, size_t size, char* res) +{ + assert(1 <= size && size <= full_encoded_block_size); + + int res_size = decoded_block_sizes[size]; + if (res_size <= 0) + return false; // Invalid block size + + uint64_t res_num = 0; + uint64_t order = 1; + for (size_t i = size - 1; i < size; --i) + { + int digit = reverse_alphabet(block[i]); + if (digit < 0) + return false; // Invalid symbol + + uint64_t product_hi; + uint64_t tmp = res_num + mul128(order, (uint64_t) digit, &product_hi); + if (tmp < res_num || 0 != product_hi) + return false; // Overflow + + res_num = tmp; + order *= alphabet_size; // Never overflows, 58^10 < 2^64 + } + + if ((size_t)res_size < full_block_size && (UINT64_C(1) << (8 * res_size)) <= res_num) + return false; // Overflow + + uint_64_to_8be(res_num, res_size, (uint8_t*)(res)); + + return true; +} + + +bool xmr_base58_encode(char *b58, size_t *b58sz, const void *data, size_t binsz) +{ + if (binsz==0) + return true; + + const char * data_bin = data; + size_t full_block_count = binsz / full_block_size; + size_t last_block_size = binsz % full_block_size; + size_t res_size = full_block_count * full_encoded_block_size + encoded_block_sizes[last_block_size]; + + if (b58sz){ + if (res_size >= *b58sz){ + return false; + } + *b58sz = res_size; + } + + for (size_t i = 0; i < full_block_count; ++i) + { + encode_block(data_bin + i * full_block_size, full_block_size, b58 + i * full_encoded_block_size); + } + + if (0 < last_block_size) + { + encode_block(data_bin + full_block_count * full_block_size, last_block_size, b58 + full_block_count * full_encoded_block_size); + } + + return true; +} + +bool xmr_base58_decode(const char *b58, size_t b58sz, void *data, size_t *binsz) +{ + if (b58sz == 0) { + *binsz = 0; + return true; + } + + size_t full_block_count = b58sz / full_encoded_block_size; + size_t last_block_size = b58sz % full_encoded_block_size; + int last_block_decoded_size = decoded_block_sizes[last_block_size]; + if (last_block_decoded_size < 0) { + *binsz = 0; + return false; // Invalid enc length + } + + size_t data_size = full_block_count * full_block_size + last_block_decoded_size; + if (*binsz < data_size){ + *binsz = 0; + return false; + } + + char * data_bin = data; + for (size_t i = 0; i < full_block_count; ++i) + { + if (!decode_block(b58 + i * full_encoded_block_size, full_encoded_block_size, data_bin + i * full_block_size)) + return false; + } + + if (0 < last_block_size) + { + if (!decode_block(b58 + full_block_count * full_encoded_block_size, last_block_size, + data_bin + full_block_count * full_block_size)) + return false; + } + + return true; +} + +int xmr_base58_addr_encode_check(uint64_t tag, const uint8_t *data, size_t binsz, char *b58, size_t b58sz) +{ + if (binsz > 128 || tag > 127) { // tag varint + return false; + } + + size_t b58size = b58sz; + uint8_t buf[binsz + 1 + HASHER_DIGEST_LENGTH]; + uint8_t *hash = buf + binsz + 1; + buf[0] = (uint8_t) tag; + memcpy(buf + 1, data, binsz); + hasher_Raw(HASHER_SHA3K, buf, binsz + 1, hash); + + bool r = xmr_base58_encode(b58, &b58size, buf, binsz + 1 + addr_checksum_size); + return (int) (!r ? 0 : b58size); +} + +int xmr_base58_addr_decode_check(const char *addr, size_t sz, uint64_t *tag, void *data, size_t datalen) +{ + size_t buflen = 1 + 64 + addr_checksum_size; + uint8_t buf[buflen]; + uint8_t hash[HASHER_DIGEST_LENGTH]; + + if (!xmr_base58_decode(addr, sz, buf, &buflen)){ + return 0; + } + + size_t res_size = buflen - addr_checksum_size - 1; + if (datalen < res_size){ + return 0; + } + + if (buflen <= addr_checksum_size+1) { + return 0; + } + + hasher_Raw(HASHER_SHA3K, buf, buflen - addr_checksum_size, hash); + if (memcmp(hash, buf + buflen - addr_checksum_size, addr_checksum_size) != 0){ + return 0; + } + + *tag = buf[0]; + if (*tag > 127){ + return false; // varint + } + + memcpy(data, buf+1, res_size); + return (int) res_size; +} diff --git a/monero/base58.h b/monero/base58.h new file mode 100644 index 000000000..628b38eb8 --- /dev/null +++ b/monero/base58.h @@ -0,0 +1,43 @@ +// Copyright (c) 2014-2018, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers + +#ifndef __XMR_BASE58_H__ +#define __XMR_BASE58_H__ + +#include +#include "hasher.h" +#include "options.h" + +int xmr_base58_addr_encode_check(uint64_t tag, const uint8_t *data, size_t binsz, char *b58, size_t b58sz); +int xmr_base58_addr_decode_check(const char *addr, size_t sz, uint64_t *tag, void *data, size_t datalen); +bool xmr_base58_encode(char *b58, size_t *b58sz, const void *data, size_t binsz); +bool xmr_base58_decode(const char *b58, size_t b58sz, void *data, size_t *binsz); + +#endif \ No newline at end of file diff --git a/monero/int-util.h b/monero/int-util.h new file mode 100644 index 000000000..c6fb225b4 --- /dev/null +++ b/monero/int-util.h @@ -0,0 +1,77 @@ +// Copyright (c) 2014-2018, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers + +#pragma once + +#include +#include + +static inline uint64_t hi_dword(uint64_t val) { + return val >> 32; +} + +static inline uint64_t lo_dword(uint64_t val) { + return val & 0xFFFFFFFF; +} + +static inline uint64_t mul128(uint64_t multiplier, uint64_t multiplicand, uint64_t* product_hi) { + // multiplier = ab = a * 2^32 + b + // multiplicand = cd = c * 2^32 + d + // ab * cd = a * c * 2^64 + (a * d + b * c) * 2^32 + b * d + uint64_t a = hi_dword(multiplier); + uint64_t b = lo_dword(multiplier); + uint64_t c = hi_dword(multiplicand); + uint64_t d = lo_dword(multiplicand); + + uint64_t ac = a * c; + uint64_t ad = a * d; + uint64_t bc = b * c; + uint64_t bd = b * d; + + uint64_t adbc = ad + bc; + uint64_t adbc_carry = adbc < ad ? 1 : 0; + + // multiplier * multiplicand = product_hi * 2^64 + product_lo + uint64_t product_lo = bd + (adbc << 32); + uint64_t product_lo_carry = product_lo < bd ? 1 : 0; + *product_hi = ac + (adbc >> 32) + (adbc_carry << 32) + product_lo_carry; + assert(ac <= *product_hi); + + return product_lo; +} + +#define SWAP64(x) ((((uint64_t) (x) & 0x00000000000000ff) << 56) | \ + (((uint64_t) (x) & 0x000000000000ff00) << 40) | \ + (((uint64_t) (x) & 0x0000000000ff0000) << 24) | \ + (((uint64_t) (x) & 0x00000000ff000000) << 8) | \ + (((uint64_t) (x) & 0x000000ff00000000) >> 8) | \ + (((uint64_t) (x) & 0x0000ff0000000000) >> 24) | \ + (((uint64_t) (x) & 0x00ff000000000000) >> 40) | \ + (((uint64_t) (x) & 0xff00000000000000) >> 56)) diff --git a/monero/monero.h b/monero/monero.h new file mode 100644 index 000000000..d281f333b --- /dev/null +++ b/monero/monero.h @@ -0,0 +1,21 @@ +// +// Created by Dusan Klinec on 10/05/2018. +// + +#ifndef TREZOR_CRYPTO_MONERO_H +#define TREZOR_CRYPTO_MONERO_H + +#if !USE_MONERO +#error "Compile with -DUSE_MONERO=1" +#endif + +#if !USE_KECCAK +#error "Compile with -DUSE_KECCAK=1" +#endif + +#include "base58.h" +#include "serialize.h" +#include "xmr.h" +#include "range_proof.h" + +#endif //TREZOR_CRYPTO_MONERO_H diff --git a/monero/range_proof.c b/monero/range_proof.c new file mode 100644 index 000000000..aaad23dec --- /dev/null +++ b/monero/range_proof.c @@ -0,0 +1,115 @@ +// +// Created by Dusan Klinec on 10/05/2018. +// + +#include "range_proof.h" + + +static void xmr_hash_ge25519_to_scalar(bignum256modm r, const ge25519 *p){ + unsigned char buff[32]; + ge25519_pack(buff, p); + xmr_hash_to_scalar(r, buff, sizeof(buff)); +} + +void xmr_gen_range_sig(xmr_range_sig_t * sig, ge25519 * C, bignum256modm mask, xmr_amount amount, bignum256modm * last_mask){ + bignum256modm ai[64]; + bignum256modm alpha[64]; + xmr_gen_range_sig_ex(sig, C, mask, amount, last_mask, ai, alpha); +} + +void xmr_gen_range_sig_ex(xmr_range_sig_t * sig, ge25519 * C, bignum256modm mask, xmr_amount amount, bignum256modm * last_mask, + bignum256modm ai[64], bignum256modm alpha[64]) +{ + const unsigned n = XMR_ATOMS; + bignum256modm a={0}; + bignum256modm si={0}; + bignum256modm c={0}; + bignum256modm ee={0}; + unsigned char buff[32]; + + Hasher kck; + xmr_hasher_init(&kck); + + ge25519 C_acc; + ge25519 C_h; + ge25519 C_tmp; + ge25519 L; + ge25519 Zero; + + ge25519_set_neutral(&Zero); + ge25519_set_neutral(&C_acc); + ge25519_set_xmr_h(&C_h); + set256_modm(a, 0); + +#define BB(i) ((amount>>(i)) & 1) + + // First pass, generates: ai, alpha, Ci, ee, s1 + for(unsigned ii=0; iiCi[ii], &C_tmp); + + if (BB(ii) == 0) { + xmr_random_scalar(si); + xmr_hash_ge25519_to_scalar(c, &L); + + ge25519_add(&C_tmp, &C_tmp, &C_h, 1); // Ci[ii] -= c_h + xmr_add_keys2_vartime(&L, si, c, &C_tmp); + + // Set s1[ii] to sigs + contract256_modm(sig->asig.s1[ii], si); + } + + ge25519_pack(buff, &L); + xmr_hasher_update(&kck, buff, sizeof(buff)); + + ge25519_double(&C_h, &C_h); // c_H = crypto.scalarmult(c_H, 2) + } + + // Compute ee + xmr_hasher_final(&kck, buff); + expand256_modm(ee, buff, sizeof(buff)); + + ge25519_set_xmr_h(&C_h); + + // Second pass, s0, s1 + for(unsigned ii=0; iiasig.s0[ii], si); + + } else { + xmr_random_scalar(si); + contract256_modm(sig->asig.s0[ii], si); + + ge25519_unpack_vartime(&C_tmp, sig->Ci[ii]); + xmr_add_keys2_vartime(&L, si, ee, &C_tmp); + xmr_hash_ge25519_to_scalar(c, &L); + + mulsub256_modm(si, ai[ii], c, alpha[ii]); + contract256_modm(sig->asig.s1[ii], si); + } + + ge25519_double(&C_h, &C_h); // c_H = crypto.scalarmult(c_H, 2) + } + + ge25519_copy(C, &C_acc); + copy256_modm(mask, a); + contract256_modm(sig->asig.ee, ee); +#undef BB +} + diff --git a/monero/range_proof.h b/monero/range_proof.h new file mode 100644 index 000000000..cd846a095 --- /dev/null +++ b/monero/range_proof.h @@ -0,0 +1,30 @@ +// +// Created by Dusan Klinec on 10/05/2018. +// + +#ifndef TREZOR_CRYPTO_RANGE_PROOF_H +#define TREZOR_CRYPTO_RANGE_PROOF_H + +#include "xmr.h" +#define XMR_ATOMS 64 + +typedef uint64_t xmr_amount; +typedef xmr_key_t xmr_key64_t[64]; + +typedef struct xmr_boro_sig { + xmr_key64_t s0; + xmr_key64_t s1; + xmr_key_t ee; +} xmr_boro_sig_t; + +typedef struct range_sig { + xmr_boro_sig_t asig; + xmr_key64_t Ci; +} xmr_range_sig_t; + + +void xmr_gen_range_sig(xmr_range_sig_t * sig, ge25519 * C, bignum256modm mask, xmr_amount amount, bignum256modm * last_mask); +void xmr_gen_range_sig_ex(xmr_range_sig_t * sig, ge25519 * C, bignum256modm mask, xmr_amount amount, bignum256modm * last_mask, + bignum256modm ai[64], bignum256modm alpha[64]); + +#endif //TREZOR_CRYPTO_RANGE_PROOF_H diff --git a/monero/serialize.c b/monero/serialize.c new file mode 100644 index 000000000..ee6aab420 --- /dev/null +++ b/monero/serialize.c @@ -0,0 +1,54 @@ +// +// Created by Dusan Klinec on 02/05/2018. +// + +#include "serialize.h" + +int xmr_size_varint(uint64_t num){ + int ctr = 1; + while (num >= 0x80) { + ++ctr; + num >>= 7; + } + return ctr; +} + +int xmr_write_varint(uint8_t * buff, size_t buff_size, uint64_t num){ + unsigned ctr = 0; + while (num >= 0x80 && ctr < buff_size) { + *buff = (uint8_t) (((num) & 0x7f) | 0x80); + ++buff; + ++ctr; + num >>= 7; + } + + /* writes the last one to dest */ + if (ctr < buff_size) { + *buff = (uint8_t) num; + ++ctr; + } + return ctr <= buff_size ? (int)ctr : -1; +} + +int xmr_read_varint(uint8_t * buff, size_t buff_size, uint64_t *val) { + unsigned read = 0; + int finished_ok = 0; + *val = 0; + + for (int shift = 0; read < buff_size; shift += 7, ++read) { + uint8_t byte = buff[read]; + if (byte == 0 && shift != 0) { + return -1; + } + + *val |= (uint64_t)(byte & 0x7f) << shift; + + /* If there is no next */ + if ((byte & 0x80) == 0) { + finished_ok = 1; + break; + } + } + return finished_ok ? (int)read + 1 : -2; +} + diff --git a/monero/serialize.h b/monero/serialize.h new file mode 100644 index 000000000..f2b0fb903 --- /dev/null +++ b/monero/serialize.h @@ -0,0 +1,15 @@ +// +// Created by Dusan Klinec on 02/05/2018. +// + +#ifndef TREZOR_XMR_SERIALIZE_H +#define TREZOR_XMR_SERIALIZE_H + +#include +#include + +int xmr_size_varint(uint64_t num); +int xmr_write_varint(uint8_t * buff, size_t buff_size, uint64_t num); +int xmr_read_varint(uint8_t * buff, size_t buff_size, uint64_t *val); + +#endif //TREZOR_XMR_SERIALIZE_H diff --git a/monero/xmr.c b/monero/xmr.c new file mode 100644 index 000000000..ccac66d95 --- /dev/null +++ b/monero/xmr.c @@ -0,0 +1,159 @@ +// +// Created by Dusan Klinec on 10/05/2018. +// + +#include "xmr.h" +#include "int-util.h" +#include "serialize.h" +#include "rand.h" + + +const ge25519 ALIGN(16) xmr_h = { + {0x1861ec7, 0x1ceac77, 0x2f11626, 0x1f261d3, 0x346107c, 0x06d8c4a, 0x254201d, 0x1675c09, 0x1301c3f, 0x0211d73}, + {0x326feb4, 0x12e30cc, 0x0cf54b4, 0x1117305, 0x318f5d5, 0x06cf754, 0x2e578a1, 0x1daf058, 0x34430a1, 0x04410e9}, + {0x0fde4d2, 0x0774049, 0x22ca951, 0x05aec2b, 0x07a36a5, 0x1394f13, 0x3c5385c, 0x1adb924, 0x2b6c581, 0x0a55fa4}, + {0x24517f7, 0x05ee936, 0x3acf5d9, 0x14b08aa, 0x3363738, 0x1051745, 0x360601e, 0x0f3f2c9, 0x1ead2cd, 0x1d3e3df} +}; + + +void ge25519_set_xmr_h(ge25519 *r){ + ge25519_copy(r, &xmr_h); +} + +void xmr_random_scalar(bignum256modm m){ + unsigned char buff[32]={0}; + random_buffer(buff, sizeof(buff)); + expand256_modm(m, buff, sizeof(buff)); +} + +void xmr_fast_hash(uint8_t * hash, const void *data, size_t length){ + hasher_Raw(HASHER_SHA3K, data, length, hash); +} + +void xmr_hasher_init(Hasher * hasher){ + hasher_Init(hasher, HASHER_SHA3K); +} + +void xmr_hasher_update(Hasher * hasher, const void *data, size_t length){ + hasher_Update(hasher, data, length); +} + +void xmr_hasher_final(Hasher * hasher, uint8_t * hash){ + hasher_Final(hasher, hash); +} + +void xmr_hasher_copy(Hasher * dst, const Hasher * src){ + memcpy(dst, src, sizeof(Hasher)); +} + +void xmr_hash_to_scalar(bignum256modm r, const void *data, size_t length){ + uint8_t hash[HASHER_DIGEST_LENGTH]; + hasher_Raw(HASHER_SHA3K, data, length, hash); + expand256_modm(r, hash, HASHER_DIGEST_LENGTH); +} + +void xmr_hash_to_ec(ge25519 *P, const void *data, size_t length){ + ge25519 point2; + uint8_t hash[HASHER_DIGEST_LENGTH]; + hasher_Raw(HASHER_SHA3K, data, length, hash); + + ge25519_fromfe_frombytes_vartime(&point2, hash); + ge25519_mul8(P, &point2); +} + +void xmr_derivation_to_scalar(bignum256modm s, const ge25519 * p, uint32_t output_index){ + uint8_t buff[32 + 8]; + ge25519_pack(buff, p); + int written = xmr_write_varint(buff + 32, 8, output_index); + xmr_hash_to_scalar(s, buff, 32u + written); +} + +void xmr_generate_key_derivation(ge25519 * r, const ge25519 * A, const bignum256modm b){ + ge25519 bA; + ge25519_scalarmult(&bA, A, b); + ge25519_norm(&bA, &bA); + ge25519_mul8(r, &bA); +} + +void xmr_derive_private_key(bignum256modm s, const ge25519 * deriv, uint32_t idx, const bignum256modm base){ + xmr_derivation_to_scalar(s, deriv, idx); + add256_modm(s, s, base); +} + +void xmr_derive_public_key(ge25519 * r, const ge25519 * deriv, uint32_t idx, const ge25519 * base){ + bignum256modm s={0}; + ge25519 p2; + ge25519_pniels Bp; + ge25519_p1p1 p1; + + xmr_derivation_to_scalar(s, deriv, idx); + ge25519_scalarmult_base_niels(&p2, ge25519_niels_base_multiples, s); + ge25519_norm(&p2, &p2); + + ge25519_full_to_pniels(&Bp, base); + ge25519_pnielsadd_p1p1(&p1, &p2, &Bp, 0); + ge25519_p1p1_to_full(r, &p1); +} + +void xmr_add_keys2(ge25519 * r, const bignum256modm a, const bignum256modm b, const ge25519 * B){ + // aG + bB, G is basepoint + ge25519 aG, bB; + ge25519_pniels bBn; + ge25519_p1p1 p1; + ge25519_scalarmult_base_niels(&aG, ge25519_niels_base_multiples, a); + ge25519_scalarmult(&bB, B, b); + ge25519_norm(&bB, &bB); + ge25519_norm(&aG, &aG); + + ge25519_full_to_pniels(&bBn, &bB); + ge25519_pnielsadd_p1p1(&p1, &aG, &bBn, 0); + ge25519_p1p1_to_full(r, &p1); +} + +void xmr_add_keys2_vartime(ge25519 * r, const bignum256modm a, const bignum256modm b, const ge25519 * B){ + // aG + bB, G is basepoint + ge25519_double_scalarmult_vartime(r, B, b, a); + ge25519_norm(r, r); +} + +void xmr_add_keys3(ge25519 * r, const bignum256modm a, const ge25519 * A, const bignum256modm b, const ge25519 * B){ + // aA + bB + ge25519 aA, bB; + ge25519_pniels bBn; + ge25519_p1p1 p1; + ge25519_scalarmult(&aA, A, a); + ge25519_scalarmult(&bB, B, b); + ge25519_norm(&bB, &bB); + ge25519_norm(&aA, &aA); + + ge25519_full_to_pniels(&bBn, &bB); + ge25519_pnielsadd_p1p1(&p1, &aA, &bBn, 0); + ge25519_p1p1_to_full(r, &p1); +} + +void xmr_add_keys3_vartime(ge25519 * r, const bignum256modm a, const ge25519 * A, const bignum256modm b, const ge25519 * B){ + // aA + bB + ge25519_double_scalarmult_vartime2(r, A, a, B, b); + ge25519_norm(r, r); +} + +void xmr_get_subaddress_secret_key(bignum256modm r, uint32_t major, uint32_t minor, const bignum256modm m){ + const char prefix[] = "SubAddr"; + unsigned char buff[32]; + contract256_modm(buff, m); + + char data[sizeof(prefix) + sizeof(buff) + 2 * sizeof(uint32_t)]; + memcpy(data, prefix, sizeof(prefix)); + memcpy(data + sizeof(prefix), buff, sizeof(buff)); + memcpy(data + sizeof(prefix) + sizeof(buff), &major, sizeof(uint32_t)); + memcpy(data + sizeof(prefix) + sizeof(buff) + sizeof(uint32_t), &minor, sizeof(uint32_t)); + + xmr_hash_to_scalar(r, data, sizeof(data)); +} + +void xmr_gen_c(ge25519 * r, const bignum256modm a, uint64_t amount){ + // C = aG + bH + bignum256modm b={0}; + set256_modm(b, amount); + xmr_add_keys2(r, a, b, &xmr_h); +} diff --git a/monero/xmr.h b/monero/xmr.h new file mode 100644 index 000000000..4e37da9a1 --- /dev/null +++ b/monero/xmr.h @@ -0,0 +1,67 @@ +// +// Created by Dusan Klinec on 10/05/2018. +// + +#ifndef TREZOR_CRYPTO_XMR_H +#define TREZOR_CRYPTO_XMR_H + +#include +#include "hasher.h" + +extern const ge25519 ALIGN(16) xmr_h; + +typedef unsigned char xmr_key_t[32]; + +typedef struct xmr_ctkey { + xmr_key_t dest; + xmr_key_t mask; +} xmr_ctkey_t; + +/* sets H point to r */ +void ge25519_set_xmr_h(ge25519 *r); + +/* random scalar value */ +void xmr_random_scalar(bignum256modm m); + +/* cn_fast_hash */ +void xmr_fast_hash(uint8_t * hash, const void *data, size_t length); + +/* incremental hashing wrappers */ +void xmr_hasher_init(Hasher * hasher); +void xmr_hasher_update(Hasher * hasher, const void *data, size_t length); +void xmr_hasher_final(Hasher * hasher, uint8_t * hash); +void xmr_hasher_copy(Hasher * dst, const Hasher * src); + +/* H_s(buffer) */ +void xmr_hash_to_scalar(bignum256modm r, const void *data, size_t length); + +/* H_p(buffer) */ +void xmr_hash_to_ec(ge25519 *P, const void *data, size_t length); + +/* derivation to scalar value */ +void xmr_derivation_to_scalar(bignum256modm s, const ge25519 * p, uint32_t output_index); + +/* derivation */ +void xmr_generate_key_derivation(ge25519 * r, const ge25519 * A, const bignum256modm b); + +/* H_s(derivation || varint(output_index)) + base */ +void xmr_derive_private_key(bignum256modm s, const ge25519 * deriv, uint32_t idx, const bignum256modm base); + +/* H_s(derivation || varint(output_index))G + base */ +void xmr_derive_public_key(ge25519 * r, const ge25519 * deriv, uint32_t idx, const ge25519 * base); + +/* aG + bB, G is basepoint */ +void xmr_add_keys2(ge25519 * r, const bignum256modm a, const bignum256modm b, const ge25519 * B); +void xmr_add_keys2_vartime(ge25519 * r, const bignum256modm a, const bignum256modm b, const ge25519 * B); + +/* aA + bB */ +void xmr_add_keys3(ge25519 * r, const bignum256modm a, const ge25519 * A, const bignum256modm b, const ge25519 * B); +void xmr_add_keys3_vartime(ge25519 * r, const bignum256modm a, const ge25519 * A, const bignum256modm b, const ge25519 * B); + +/* subaddress secret */ +void xmr_get_subaddress_secret_key(bignum256modm r, uint32_t major, uint32_t minor, const bignum256modm m); + +/* Generates Pedersen commitment C = aG + bH */ +void xmr_gen_c(ge25519 * r, const bignum256modm a, uint64_t amount); + +#endif //TREZOR_CRYPTO_XMR_H diff --git a/tests/test_check.c b/tests/test_check.c index ae932e915..86389b46a 100644 --- a/tests/test_check.c +++ b/tests/test_check.c @@ -58,11 +58,13 @@ #include "ed25519-donna/ed25519.h" #include "ed25519-donna/ed25519-donna.h" #include "ed25519-donna/ed25519-keccak.h" +#include "ed25519-donna/ge25519.h" #include "script.h" #include "rfc6979.h" #include "address.h" #include "rc4.h" #include "nem.h" +#include "monero/monero.h" #if VALGRIND /* @@ -4808,6 +4810,10 @@ END_TEST #include "test_check_cardano.h" #endif +#if USE_MONERO +#include "test_check_monero.h" +#endif + // define test suite and cases Suite *test_suite(void) { @@ -5008,9 +5014,11 @@ Suite *test_suite(void) tcase_add_test(tc, test_ed25519_modl_sub); suite_add_tcase(s, tc); +#if USE_MONERO tc = tcase_create("ed25519_ge"); tcase_add_test(tc, test_ge25519_double_scalarmult_vartime2); suite_add_tcase(s, tc); +#endif tc = tcase_create("script"); tcase_add_test(tc, test_output_script); @@ -5067,6 +5075,47 @@ Suite *test_suite(void) suite_add_tcase(s,tc); #endif +#if USE_MONERO + tc = tcase_create("xmr_base58"); + tcase_add_test(tc, test_xmr_base58); + suite_add_tcase(s, tc); + + tc = tcase_create("xmr_crypto"); + tcase_add_test(tc, test_xmr_getset256_modm); + tcase_add_test(tc, test_xmr_cmp256_modm); + tcase_add_test(tc, test_xmr_copy_check_modm); + tcase_add_test(tc, test_xmr_mulsub256_modm); + tcase_add_test(tc, test_xmr_muladd256_modm); + tcase_add_test(tc, test_xmr_curve25519_set); + tcase_add_test(tc, test_xmr_curve25519_consts); + tcase_add_test(tc, test_xmr_curve25519_tests); + tcase_add_test(tc, test_xmr_curve25519_expand_reduce); + tcase_add_test(tc, test_xmr_ge25519_base); + tcase_add_test(tc, test_xmr_ge25519_check); + tcase_add_test(tc, test_xmr_ge25519_scalarmult_base_wrapper); + tcase_add_test(tc, test_xmr_ge25519_scalarmult_wrapper); + tcase_add_test(tc, test_xmr_ge25519_ops); + suite_add_tcase(s, tc); + + tc = tcase_create("xmr_xmr"); + tcase_add_test(tc, test_xmr_check_point); + tcase_add_test(tc, test_xmr_h); + tcase_add_test(tc, test_xmr_fast_hash); + tcase_add_test(tc, test_xmr_hasher); + tcase_add_test(tc, test_xmr_hash_to_scalar); + tcase_add_test(tc, test_xmr_hash_to_ec); + tcase_add_test(tc, test_xmr_derivation_to_scalar); + tcase_add_test(tc, test_xmr_generate_key_derivation); + tcase_add_test(tc, test_xmr_derive_private_key); + tcase_add_test(tc, test_xmr_derive_public_key); + tcase_add_test(tc, test_xmr_add_keys2); + tcase_add_test(tc, test_xmr_add_keys3); + tcase_add_test(tc, test_xmr_get_subaddress_secret_key); + tcase_add_test(tc, test_xmr_gen_c); + tcase_add_test(tc, test_xmr_varint); + tcase_add_test(tc, test_xmr_gen_range_sig); + suite_add_tcase(s, tc); +#endif return s; } diff --git a/tests/test_check_monero.h b/tests/test_check_monero.h new file mode 100644 index 000000000..c76edefc1 --- /dev/null +++ b/tests/test_check_monero.h @@ -0,0 +1,1216 @@ +#if USE_MONERO +START_TEST(test_xmr_base58) +{ + static const struct { + uint64_t tag; + char *v1; + char *v2; + } tests[] = { + {0x12, + "3bec484c5d7f0246af520aab550452b5b6013733feabebd681c4a60d457b7fc12d5918e31d3c003da3c778592c07b398ad6f961a67082a75fd49394d51e69bbe", + "43tpGG9PKbwCpjRvNLn1jwXPpnacw2uVUcszAtgmDiVcZK4VgHwjJT9BJz1WGF9eMxSYASp8yNMkuLjeQfWqJn3CNWdWfzV" + }, + {0x12, + "639050436fa36c8288706771412c5972461578d564188cd7fc6f81d6973d064fa461afe66fb23879936d7225051bebbf7f3ae0c801a90bb99fbb346b2fd4d702", + "45PwgoUKaDHNqLL8o3okzLL7biv7GqPVmd8LTcTrYVrMEKdSYwFcyJfMLSRpfU3nh8Z2m81FJD4sUY3nXCdGe61k1HAp8T1" + }, + {53, + "5a10cca900ee47a7f412cd661b29f5ab356d6a1951884593bb170b5ec8b6f2e83b1da411527d062c9fedeb2dad669f2f5585a00a88462b8c95c809a630e5734c", + "9vacMKaj8JJV6MnwDzh2oNVdwTLJfTDyNRiB6NzV9TT7fqvzLivH2dB8Tv7VYR3ncn8vCb3KdNMJzQWrPAF1otYJ9cPKpkr" + }, + }; + + uint8_t rawn[512]; + char strn[512]; + int r; + uint64_t tag; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + const char *raw = tests[i].v1; + const char *str = tests[i].v2; + const size_t len = strlen(raw) / 2; + + memcpy(rawn, fromhex(raw), len); + + r = xmr_base58_addr_encode_check(tests[i].tag, rawn, len, strn, sizeof(strn)); + ck_assert_int_eq((size_t) r, strlen(str)); + ck_assert_mem_eq(strn, str, r); + + r = xmr_base58_addr_decode_check(strn, r, &tag, rawn, len); + ck_assert_int_eq(r, len); + ck_assert_mem_eq(rawn, fromhex(raw), len); + } +} +END_TEST + + +START_TEST(test_xmr_getset256_modm) +{ + static const struct { + uint64_t val; + int r; + char *a; + } tests[] = { + {0x0, 1, + "0000000000000000000000000000000000000000000000000000000000000000"}, + {0x7fffffffULL, 1, + "ffffff7f00000000000000000000000000000000000000000000000000000000"}, + {0x7fffffffffffffffULL, 1, + "ffffffffffffff7f000000000000000000000000000000000000000000000000"}, + {0xdeadc0deULL, 1, + "dec0adde00000000000000000000000000000000000000000000000000000000"}, + {0x0, 0, + "dec0adde000000000000000000000000000000000000000000000000000000ff"}, + {0x0, 0, + "ffffffffffffffffff0000000000000000000000000000000000000000000000"}, + }; + + uint8_t rawn[32]; + uint64_t v1; + bignum256modm a1 = {0}; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + int get_res = tests[i].r; + if (get_res) { + set256_modm(a1, tests[i].val); + ck_assert_int_eq(get256_modm(&v1, a1), 1); + ck_assert(v1 == tests[i].val); + + contract256_modm(rawn, a1); + ck_assert_mem_eq(rawn, fromhex(tests[i].a), 32); + + } else { + expand256_modm(a1, fromhex(tests[i].a), 32); + ck_assert_int_eq(get256_modm(&v1, a1), 0); + } + } +} +END_TEST + + +START_TEST(test_xmr_cmp256_modm) +{ + static const struct { + char *a; + char *b; + int res_eq; + int res_cmp; + int res_is_zero_a; + } tests[] = { + { + "0000000000000000000000000000000000000000000000000000000000000000", + "0000000000000000000000000000000000000000000000000000000000000000", + 1, 0, 1 + }, + { + "0000000000000000000000000000000000000000000000000000000000000000", + "0100000000000000000000000000000000000000000000000000000000000000", + 0, -1, 1 + }, + { + "dec0adde00000000000000000000000000000000000000000000000000000000", + "dec0adde00000000000000000000000000000000000000000000000000000000", + 1, 0, 0 + }, + { + "863346d8863c461cde2ec7c2759352c2b952228f33a86ca06bb79574bbe5c30d", + "3ddbd65a6d3ba5e2ab120603685a353a27ce3fd21dfdbea7952d2dd26f1ca00a", + 0, 1, 0 + }, + { + "f7667f392edbea6e224b1aa9fbf2a3b238b4f977fb4a8f39130cc45f49b5c40a", + "b41b9b1e7e80be71cf290ed4bded58924086b8ac6bdfa1faa0c80c255f074d07", + 0, 1, 0 + }, + { + "0e4005c7826de8f9978749903f40efd140e4ae6d3bed09e558fcce8367b27501", + "0e4005c7826de8f9978749903f40efd140e4ae6d3bed09e558fcce8367b27504", + 0, -1, 0 + }, + { + "0e4005c7826de8f9978749903f40efd140e4ae6d3bed09e558fcce8367b27504", + "0e4005c7826de8f9978749903f40efd140e4ae6d3bed09e558fcce8367b27504", + 1, 0, 0 + }, + { + "0e4005c7826de8f9978749903f40efd140e4ae6d3bed09e558fcce8367b27504", + "0e4005c7826de8f9978749903f41efd140e4ae6d3bed09e558fcce8367b27504", + 0, -1, 0 + }, + }; + + bignum256modm a1 = {0}, a2 = {0}; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + expand256_modm(a1, fromhex(tests[i].a), 32); + expand256_modm(a2, fromhex(tests[i].b), 32); + + ck_assert_int_eq(eq256_modm(a1, a2), tests[i].res_eq); + ck_assert_int_eq(cmp256_modm(a1, a2), tests[i].res_cmp); + ck_assert_int_eq(iszero256_modm(a1), tests[i].res_is_zero_a); + } +} +END_TEST + + +START_TEST(test_xmr_copy_check_modm) +{ + static const struct { + int check; + char *a; + } tests[] = { + {0, + "0000000000000000000000000000000000000000000000000000000000000000"}, + {1, + "ffffff7f00000000000000000000000000000000000000000000000000000000"}, + {1, + "ffffffffffffff7f000000000000000000000000000000000000000000000000"}, + {1, + "dec0adde00000000000000000000000000000000000000000000000000000000"}, + {0, + "dec0adde000000000000000000000fffffffffffffffffffffffffffffffffff"}, + }; + + bignum256modm a1 = {0}, a2 = {0}; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + expand_raw256_modm(a1, fromhex(tests[i].a)); + copy256_modm(a2, a1); + ck_assert_int_eq(eq256_modm(a1, a2), 1); + ck_assert_int_eq(check256_modm(a1), tests[i].check); + } + +} +END_TEST + + +START_TEST(test_xmr_mulsub256_modm) +{ + static const struct { + char *a; + char *b; + char *c; + char *r; + } tests[] = { + { + "713c199348cf7d14b67ae6265ea49c02c8647f07afcbcb6f8d3254b3db972e02", + "4e48a7b7a03ab1106fdfa9441a03c97c644395a12ac4b8effac7344e0719c200", + "1a5711b8c43bcab0161a620368d82727e1d027dc248f420d9bb4db2486c16405", + "6edcc08aa6ec3a5b3d333b5f826be7de9c268be8aaf9521586fbcccbed3b1c0c", + }, + { + "d4ade2c62d34af8cfd9daec6f46bf7e57962a8aa46935cb11fab64fa599b4700", + "22ea7989a9f4d34cd8c9442e03b5062dfe8493757cd18a63411cb1a25e44960f", + "772053e613f0859387badcefeb7fbe551a05b00b9337539c8d72661de5929806", + "a5063258df4520b33e97c0a46d80feeace5c251fc7ef7a938d160b8f25795106", + }, + { + "01fd2ef25c8221277a2b6daf1f1642bacb8d6ac0dd4f62731cdd73e26eb77900", + "0611b9357530aa638428002769ce0ad553421e971bea1f10d7009bf26d9af805", + "dfece232068b2f8059ca569f345baaed13ab464eb3bebb99de5625dc90a8cf03", + "85752e62bd8085c7c02d5edeb74969d22f1a5bb34349258d2e96de300176bb07", + }, + }; + + bignum256modm a = {0}, b = {0}, c = {0}, r = {0}, r2 = {0}; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + expand256_modm(a, fromhex(tests[i].a), 32); + expand256_modm(b, fromhex(tests[i].b), 32); + expand256_modm(c, fromhex(tests[i].c), 32); + expand256_modm(r, fromhex(tests[i].r), 32); + mulsub256_modm(r2, a, b, c); + ck_assert_int_eq(eq256_modm(r, r2), 1); + } +} +END_TEST + + +START_TEST(test_xmr_muladd256_modm) +{ + static const struct { + char *a; + char *b; + char *c; + char *r; + } tests[] = { + { + "7c3fd8abfbe2be3739d91679ac8dbda086961b941e0d4a00561f758927d8aa09", + "ac2d8d37e4f344aa4040d0f0fc29d45423ab7e69ecacb94ca9fc36819e0e990e", + "2f03f1bac09bc7d002848b68be069dc98b2db028390ae37e13a5166fcae08105", + "dce113add3392f08e3b38b7d31e237eba5066e5a95a1fdbf755b92d05e1ec70b", + }, + { + "6979b70f6198d043f4b14e2069f7b89cc9f09e3465e71d472946443989e0e80c", + "8dd5177bc8d7c5bd58c0be74b336952a73ac259ebb812ac8cd755773c6aab807", + "d7658e508a7454ccfb29e2890d6156ac10e18ebe6e00cc5a2d2d87a5080c7f06", + "51b33f6263772781cdbab26ef48870eaf94899894a437dac39496f15b9d0ae00", + }, + { + "ebfdb4eabedb1fb9a45b3204735b0511871e20358392fa16a851c519e3a29b09", + "59d98831e9f9e24260158986c4d4035438de9b8876cc11bdcf4c364c75f72908", + "93bce4764eee97dc67f2e37da40bc5641f2cdc637285d273287a3d4383b68f02", + "21547ca6855c85d5adcd673b9d801d0cb0f10dced8f8b68a8c2f74163defde0e", + }, + }; + + bignum256modm a = {0}, b = {0}, c = {0}, r = {0}, r2 = {0}; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + expand256_modm(a, fromhex(tests[i].a), 32); + expand256_modm(b, fromhex(tests[i].b), 32); + expand256_modm(c, fromhex(tests[i].c), 32); + expand256_modm(r, fromhex(tests[i].r), 32); + muladd256_modm(r2, a, b, c); + ck_assert_int_eq(eq256_modm(r, r2), 1); + } + +} +END_TEST + + +START_TEST(test_xmr_curve25519_set) +{ + static const struct { + uint32_t val; + char *a; + } tests[] = { + {0x0, + "0000000000000000000000000000000000000000000000000000000000000000"}, + {0x1, + "0100000000000000000000000000000000000000000000000000000000000000"}, + {0xdeadc0deUL, + "dec0adde00000000000000000000000000000000000000000000000000000000"}, + }; + + unsigned char buff[32]; + bignum25519 a = {0}; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + curve25519_set(a, tests[i].val); + curve25519_contract(buff, a); + ck_assert_mem_eq(buff, fromhex(tests[i].a), 32); + } +} +END_TEST + + +START_TEST(test_xmr_curve25519_consts) +{ + char *d = "a3785913ca4deb75abd841414d0a700098e879777940c78c73fe6f2bee6c0352"; + char *d2 = "59f1b226949bd6eb56b183829a14e00030d1f3eef2808e19e7fcdf56dcd90624"; + char *sqrtneg1 = "b0a00e4a271beec478e42fad0618432fa7d7fb3d99004d2b0bdfc14f8024832b"; + + unsigned char buff[32]; + bignum25519 a = {0}; + + curve25519_set_d(a); + curve25519_contract(buff, a); + ck_assert_mem_eq(buff, fromhex(d), 32); + + curve25519_set_2d(a); + curve25519_contract(buff, a); + ck_assert_mem_eq(buff, fromhex(d2), 32); + + curve25519_set_sqrtneg1(a); + curve25519_contract(buff, a); + ck_assert_mem_eq(buff, fromhex(sqrtneg1), 32); +} +END_TEST + + +START_TEST(test_xmr_curve25519_tests) +{ + static const struct { + char *a; + int res_neg; + int res_nonzero; + } tests[] = { + { + "0000000000000000000000000000000000000000000000000000000000000000", + 0, 0, + }, + { + "0100000000000000000000000000000000000000000000000000000000000000", + 1, 1, + }, + { + "05737aa6100ee54283dc0d483b8e39e61846f6b3736908243d0c824d250b3139", + 1, 1, + }, + { + "95587a5ef6900fa8e32d6a41bd8090b1e33e694284323d1d1f02d69865f2bc15", + 1, 1, + }, + { + "02587a5ef6900fa8e32d6a41bd8090b1e33e694284323d1d1f02d69865f2bc15", + 0, 1, + }, + }; + + bignum25519 a = {0}; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + curve25519_expand(a, fromhex(tests[i].a)); + ck_assert_int_eq(curve25519_isnegative(a), tests[i].res_neg); + ck_assert_int_eq(curve25519_isnonzero(a), tests[i].res_nonzero); + } +} +END_TEST + + +START_TEST(test_xmr_curve25519_expand_reduce) +{ + static const struct { + char *a; + char *b; + } tests[] = { + { + "dec0adde00000000000000000000000000000000000000000000000000000000", + "dec0adde00000000000000000000000000000000000000000000000000000000" + }, + { + "95587a5ef6900fa8e32d6a41bd8090b1e33e694284323d1d1f02d69865f2bc15", + "95587a5ef6900fa8e32d6a41bd8090b1e33e694284323d1d1f02d69865f2bc15" + }, + { + "95587a5ef6900fa8e32d6a41bd8090b1e33e694284323d1d1f02d69865f2bcff", + "a8587a5ef6900fa8e32d6a41bd8090b1e33e694284323d1d1f02d69865f2bc7f" + }, + { + "95587a5ef6900fa8e32d6affbd8090b1e33e694284323fffff02d69865f2bcff", + "a8587a5ef6900fa8e32d6affbd8090b1e33e694284323fffff02d69865f2bc7f" + }, + }; + + unsigned char buff[32]; + bignum25519 a = {0}; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + curve25519_expand_reduce(a, fromhex(tests[i].a)); + curve25519_contract(buff, a); + ck_assert_mem_eq(buff, fromhex(tests[i].b), 32); + } + +} +END_TEST + + +START_TEST(test_xmr_ge25519_base) +{ + unsigned char buff[32]; + char *base = "5866666666666666666666666666666666666666666666666666666666666666"; + ge25519 b; + ge25519_set_base(&b); + ge25519_pack(buff, &b); + ck_assert_mem_eq(buff, fromhex(base), 32); +} +END_TEST + + +START_TEST(test_xmr_ge25519_check) +{ + static const struct { + char *x; + char *y; + char *z; + char *t; + int r; + } tests[] = { + { + "4ff97748221f954414f836d84e8e7e207786bcd20eb67044756dca307e792c60", + "2c7be86ab07488ba43e8e03d85a67625cfbf98c8544de4c877241b7aaafc7f63", + "0100000000000000000000000000000000000000000000000000000000000000", + "3ec65b03954ce7432525b9b3f4a9f5747f57b40903d1bf8892527366325fe036", 1 + }, + { + "358fd25e4b84397d207e23cf3a75819bd6b2254cabc990b31ad63873cc38fc7c", + "ca48045f790145a1eec3946dfd73747fde0fdb4238607e0a203f8ef5bef90e0e", + "0100000000000000000000000000000000000000000000000000000000000000", + "6c5e5cbae4b05e149d0aca50bf7b4112acbbe6233ace9c8bd5bcedf34df9ce0b", 1 + }, + { + "4ff97748221f954414f836d84e8e7e207786bcd20eb6704475ffca307e792c60", + "2c7be86ab07488ba43e8e03d85a67625cfbf98c8544de4c877241b7aaafc7f63", + "0100000000000000000000000000000000000000000000000000000000000000", + "3ec65b03954ce7432525b9b3f4a9f5747f57b40903d1bf8892527366325fe036", 0 + }, + { + "358fd25e4b84397d207e23cf3a75819bd6b2254cabc990b31ad63873cc38fc7c", + "ca48045f790145a1eec3946dfd73747fdfffdb4238607e0a203f8ef5bef90e0e", + "0100000000000000000000000000000000000000000000000000000000000000", + "6c5e5cbae4b05e149d0aca50bf7b4112acbbe6233ace9c8bd5bcedf34df9ce0b", 0 + }, + { + "358fd25e4b84397d207e23cf3a75819bd6b2254cabc990b31ad63873cc38fc7c", + "ca48045f790145a1eec3946dfd73747fdfffdb4238607e0a203f8ef5bef90e0e", + "0100000000000000000000000000000000000000000000000000000000000000", + "6c5e5ffae4b05e149d0aca50bf7b4112acbbe6233ace9c8bd5bcedf34df9ce0b", 0 + }, + }; + + struct ge25519_t p; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + curve25519_expand_reduce(p.x, fromhex(tests[i].x)); + curve25519_expand_reduce(p.y, fromhex(tests[i].y)); + curve25519_expand_reduce(p.z, fromhex(tests[i].z)); + curve25519_expand_reduce(p.t, fromhex(tests[i].t)); + ck_assert_int_eq(ge25519_check(&p), tests[i].r); + } +} +END_TEST + + +START_TEST(test_xmr_ge25519_scalarmult_base_wrapper) +{ + static const struct { + char *sc; + char *pt; + } tests[] = { + { + "40be740e26bd1c84f5a8fec737c0ed30e87bd45adfcd91e320f8dfb68b1a870e", + "b7a8b2f3dbfd41b38d20aec733a316dbfc2633503799cd36f38570cafc8ea887", + }, + { + "1b3746add992215d427e43a58354c11ff9e6dfa1c187250938f7f9334fa41d05", + "e2a1bfbe38a9749fe6ede79d923b778fa4c89393473d633bec01fa68617d0828", + }, + { + "69af25c54090a9746d3f6043348452429ffd53c1530fa114fd0055b70d61020f", + "6bf1783b0a7495d5f6c36605dca95e723ca120a306c255084787f09b12771124", + }, + { + "0000000000000000000000000000000000000000000000000000000000000000", + "0100000000000000000000000000000000000000000000000000000000000000", + }, + { + "0100000000000000000000000000000000000000000000000000000000000000", + "5866666666666666666666666666666666666666666666666666666666666666", + }, + { + "0800000000000000000000000000000000000000000000000000000000000000", + "b4b937fca95b2f1e93e41e62fc3c78818ff38a66096fad6e7973e5c90006d321", + }, + { + "ffffffffffffffff000000000000000000000000000000000000000000000000", + "e185757a3fdc6519a6e7bebd97aa52bdc999e4c87d5c3aad0d995763ab6c6985", + }, + }; + + ge25519 pt, pt2; + bignum256modm sc; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + expand256_modm(sc, fromhex(tests[i].sc), 32); + ge25519_unpack_vartime(&pt, fromhex(tests[i].pt)); + ge25519_scalarmult_base_wrapper(&pt2, sc); + ck_assert_int_eq(ge25519_eq(&pt, &pt2), 1); + } +} +END_TEST + + +START_TEST(test_xmr_ge25519_scalarmult_wrapper) +{ + static const struct { + char *sc; + char *pt; + char *pt2; + } tests[] = { + { + "0000000000000000000000000000000000000000000000000000000000000000", + "5cbb3b2784c16f0e7eb4f2a7f93288552bb24ec51c5e01504c1e6885cfbca6d0", + "0100000000000000000000000000000000000000000000000000000000000000", + }, + { + "0100000000000000000000000000000000000000000000000000000000000000", + "f39b6770008d069acb92eb95329dec2cb0054da024e437a1bdf1ae06527deff6", + "f39b6770008d069acb92eb95329dec2cb0054da024e437a1bdf1ae06527deff6", + }, + { + "3930000000000000000000000000000000000000000000000000000000000000", + "2835b3983e3cc01a640fd188bf6bbbafbf997a3344d800eed22e4e82a412941c", + "2fe8b2dd0f23e02fca6989e170135584d684583c0a44f6a7d3ebd964685d36c7", + }, + { + "ffffffffffffffff000000000000000000000000000000000000000000000000", + "bb8af7a53a8f1b477c810e833a84cdc789a6b81a6b6417be4f97ffd9ae0fe0b8", + "3a5c9a7dacca9dd8827881f38c36aad7d402a5efc2cab58c7553b903876e1491", + }, + { + "864203a09e1c788a482685c739af07355ebb2c840b7de6af87eff5f19ee3b807", + "d404a9bbf351e7320ea6d11cdeeccaf505f706731cb5e5d839b950edb7ba6286", + "11e09c89e0be7663e0e2d4a01fb05d6a3fd84a78a6fa4fd7daaacf2d19311a38", + }, + { + "3e01f05920a238e33766814d10f0c3a3e975072399ad90a823d4808db1d85209", + "52a2d35798a0ac209b8fa194fe398b869aba5f20d80ee3d8ca77759a8e0bae0d", + "4256addc2f036150f3fdc0a7905f01285239d6dd4eecc4be8e3b134eef4639fe", + }, + { + "ad63d591716a9e89a024a074bc6ce661268d1bb3665f91e8b981f189b1a49507", + "3928bde7a92e1341c3dfee35a66fa5639204f5b9747963278af430145028648d", + "9c959003ba91004956df98800a5024d94031db5ac659675b26350657d93c34f9", + }, + }; + + ge25519 pt, pt2, pt3; + bignum256modm sc; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + expand256_modm(sc, fromhex(tests[i].sc), 32); + ge25519_unpack_vartime(&pt, fromhex(tests[i].pt)); + ge25519_unpack_vartime(&pt2, fromhex(tests[i].pt2)); + ge25519_scalarmult_wrapper(&pt3, &pt, sc); + ck_assert_int_eq(ge25519_eq(&pt3, &pt2), 1); + } +} +END_TEST + + +START_TEST(test_xmr_ge25519_ops) +{ + int tests[] = {1, 2, 7, 8, 637, 9912, 12345}; + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + struct ge25519_t a, b, c, d; + bignum256modm s1 = {0}, s2 = {0}, s3 = {0}; + + set256_modm(s1, tests[i]); + set256_modm(s2, 8 * tests[i]); + set256_modm(s3, 8); + + ge25519_scalarmult_base_wrapper(&a, s1); + ge25519_mul8(&b, &a); + ge25519_scalarmult_base_wrapper(&c, s2); + ck_assert_int_eq(ge25519_eq(&b, &c), 1); + + ge25519_scalarmult_wrapper(&d, &a, s3); + ck_assert_int_eq(ge25519_eq(&d, &c), 1); + + ge25519_copy(&a, &b); + ge25519_neg_full(&b); + ck_assert_int_eq(ge25519_eq(&b, &c), 0); + + ge25519_add(&c, &a, &b, 0); + set256_modm(s2, 0); + ge25519_scalarmult_base_wrapper(&a, s2); + ck_assert_int_eq(ge25519_eq(&a, &c), 1); + } +} +END_TEST + + +START_TEST(test_xmr_check_point) +{ + static const struct { + char *p; + bool on; + } tests[] = { + {"001000a93e0e6937b4feaf079e418a028ca85459aa39ac3871b94076f88ca608", true}, + {"54863a0464c008acc99cffb179bc6cf34eb1bbdf6c29f7a070a7c6376ae30ab5", true}, + {"bebe3c84092c0f7a92704cafb16562cc45c47f45e84baec8d4bba3559d1c1808", true}, + {"00000000000000c60073ec000000000000ff0000000000000000000000000080", false}, + {"00000000000000004e0000000000000000000000000000000000000000000000", false}, + {"0000008b0000000000000000b200000000000000000000000000000000000080", false}, + {"a0953eebe2f676256c37af4f6f84f32d397aaf3b73606e96c5ddfcecbb1ceec8", false}, + {"a82cd837efee505ec8425769ea925bee869ec3c78a57708c64c2ef2bd6ad3b88", false}, + {"031c56cfc99758f6f025630e77c6dea0b853c3ab0bf6cf8c8dab03d1a4618178", false}, + }; + + ge25519 tmp; + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + int res = ge25519_unpack_negative_vartime(&tmp, fromhex(tests[i].p)); + ck_assert_int_eq(ge25519_check(&tmp), tests[i].on); + ck_assert_int_eq(res, tests[i].on); + } +} +END_TEST + + +START_TEST(test_xmr_h) +{ + char *H = "8b655970153799af2aeadc9ff1add0ea6c7251d54154cfa92c173a0dd39c1f94"; + ge25519 H2, Z; + ge25519_p1p1 P_11; + ge25519_pniels P_ni; + uint8_t buff[32] = {0}; + + ge25519_pack(buff, &xmr_h); + ck_assert_mem_eq(buff, fromhex(H), 32); + + int res = ge25519_unpack_vartime(&H2, buff); + ck_assert_int_eq(res, 1); + ck_assert_int_eq(ge25519_eq(&xmr_h, &xmr_h), 1); + ck_assert_int_eq(ge25519_eq(&H2, &xmr_h), 1); + + res = ge25519_unpack_negative_vartime(&H2, buff); + ck_assert_int_eq(res, 1); + ck_assert_int_eq(ge25519_eq(&H2, &xmr_h), 0); + ge25519_neg_full(&H2); + ck_assert_int_eq(ge25519_eq(&H2, &xmr_h), 1); + + ge25519_full_to_pniels(&P_ni, &xmr_h); + ge25519_pnielsadd_p1p1(&P_11, &H2, &P_ni, 1); + ge25519_p1p1_to_full(&H2, &P_11); + ge25519_set_neutral(&Z); + ck_assert_int_eq(ge25519_eq(&Z, &H2), 1); +} +END_TEST + + +START_TEST(test_xmr_fast_hash) +{ + uint8_t hash[32]; + char tests[][2][65] = { + {"", "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"}, + {"00", "bc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a"}, + {"000102", "f84a97f1f0a956e738abd85c2e0a5026f8874e3ec09c8f012159dfeeaab2b156"}, + {"000102030405", "51e8babe8b42352100dffa7f7b3843c95245d3d545c6cbf5052e80258ae80627"}, + {"000102030406", "74e7a0111ee2390dc68269a549a76dcfb553ca1260035eae982d669ff6494f32"}, + {"000102030407", "3a81c5d02a87786343f88414aae150a09f6933b1d3bb660d0a9ac54e12e5cd86"}, + {"259ef2aba8feb473cf39058a0fe30b9ff6d245b42b6826687ebd6b63128aff64", "7fb4d1c8e32f7414fe8c7b2774ec05bff6845e4278565d17f95559513a244da2"}, + {"44caa1c26187afe8dacc5d91cb8a51282334d9308a818fe4d3607275e2a61f05", "2998fe52f8b9883149babd9c546912c3edfbd3cd98896a0e57b1b5929fa5ff7b"}, + }; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + xmr_fast_hash(hash, fromhex(tests[i][0]), strlen(tests[i][0]) / 2); + ck_assert_mem_eq(hash, fromhex(tests[i][1]), 32); + } +} +END_TEST + + +START_TEST(test_xmr_hasher) +{ + Hasher hasher; + uint8_t hash[32]; + + static const struct { + char * chunk[3]; + char * hash; + } tests[] = { + { {"00", "01", "02"}, + "f84a97f1f0a956e738abd85c2e0a5026f8874e3ec09c8f012159dfeeaab2b156"}, + { {"001122334455667788", "00", ""}, + "72a228ee8d0d01c815f112ce315cfc215a0594abcec24162304ae0ffda139d9e"}, + { {"001000a93e0e6937b4feaf079e418a028ca85459aa39ac3871b94076f88ca608", "", "00112233445566"}, + "c3deafd96ff10cc190c6024548c344f6401cfe5151ab2fcd40df7cc501147e01"}, + }; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + xmr_hasher_init(&hasher); + for(int j = 0; j < 3; j++){ + xmr_hasher_update(&hasher, fromhex(tests[i].chunk[j]), strlen(tests[i].chunk[j]) / 2); + } + xmr_hasher_final(&hasher, hash); + ck_assert_mem_eq(hash, fromhex(tests[i].hash), 32); + } +} +END_TEST + + +START_TEST(test_xmr_hash_to_scalar) +{ + bignum256modm a1; + unsigned char out[32]; + char tests[][2][65] = { + {"", "4a078e76cd41a3d3b534b83dc6f2ea2de500b653ca82273b7bfad8045d85a400"}, + {"00", "5497c9b6a7059553835f85118dc089d66512f7b477d66591ff96a9e064bcc90a"}, + {"000102", "5727ca206dbafa2e099b022ed528f5bdf7874e3ec09c8f012159dfeeaab2b106"}, + {"000102030405", "7740cf04577c107153a50b3abe44859f5245d3d545c6cbf5052e80258ae80607"}, + {"000102030406", "ad6bbffaceb8020543ac82bcadb9d090b553ca1260035eae982d669ff6494f02"}, + {"000102030407", "d2e116e9576ee5a29011c8fcb41259f99e6933b1d3bb660d0a9ac54e12e5cd06"}, + {"259ef2aba8feb473cf39058a0fe30b9ff6d245b42b6826687ebd6b63128aff64", "3d6d3727dc50bca39e6ccfc9c12950eef5845e4278565d17f95559513a244d02"}, + {"44caa1c26187afe8dacc5d91cb8a51282334d9308a818fe4d3607275e2a61f05", "aecc45c83f0408c96c70f8273e94f930edfbd3cd98896a0e57b1b5929fa5ff0b"}, + }; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + xmr_hash_to_scalar(a1, fromhex(tests[i][0]), strlen(tests[i][0]) / 2); + contract256_modm(out, a1); + ck_assert_mem_eq(out, fromhex(tests[i][1]), 32); + } +} +END_TEST + + +START_TEST(test_xmr_hash_to_ec) +{ + ge25519 p1; + unsigned char out[32]; + char tests[][2][65] = { + {"", "d6d7d783ab18e1be65586adb7902a4175b737ef0b902875e1d1d5c5cf0478c0b"}, + {"00", "8e2fecb36320bc4e192e10ef54afc7c83fbeb0c38b7debd4fea51301f0bd4f3d"}, + {"000102", "73b233e2e75d81b9657a857e38e7ab2bc3600e5c56622b9fe4b976ff312220fa"}, + {"000102030405", "bebe3c84092c0f7a92704cafb16562cc45c47f45e84baec8d4bba3559d1c1808"}, + {"000102030406", "525567a6a40a94f2d916bc1efea234bbd3b9162403ec2faba871a90f8d0d487e"}, + {"000102030407", "99b1be2a92cbd22b24b48fb7a9daadd4d13a56915c4f6ed696f271ad5bdbc149"}, + {"42f6835bf83114a1f5f6076fe79bdfa0bd67c74b88f127d54572d3910dd09201", "54863a0464c008acc99cffb179bc6cf34eb1bbdf6c29f7a070a7c6376ae30ab5"}, + {"44caa1c26187afe8dacc5d91cb8a51282334d9308a818fe4d3607275e2a61f05", "001000a93e0e6937b4feaf079e418a028ca85459aa39ac3871b94076f88ca608"}, + }; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + xmr_hash_to_ec(&p1, fromhex(tests[i][0]), strlen(tests[i][0]) / 2); + ge25519_pack(out, &p1); + ck_assert_mem_eq(out, fromhex(tests[i][1]), 32); + } +} +END_TEST + + +START_TEST(test_xmr_derivation_to_scalar) +{ + static const struct { + char *pt; + uint32_t idx; + char *sc; + } tests[] = { + { + "c655b2d9d2670a1c9f26f7586b6d6b1ec5173b8b33bca64c3d305a42d66738b1", 0, + "ca7ce31b273dd1ac00dc3553e654fb66036804800e27c826bd2b78649243900b", + }, + { + "2b1dbd7a007dcc4d729fa8359705595599737fcef60afb36b379fe033095dca7", 1, + "60afd5a63b14845d3b92d16eac386713e4ff617fdc5c1a07c3212098c1f5610c", + }, + { + "a48ed3797225dab4b4316b5e40107b6bd63e5f4dc517ba602774d703576ec771", 24, + "fe81804091e50a5c2233faa6277360fbe1948ea15dddbae62c1d40bbd1918606", + }, + { + "fa27b5b39741f5341b4e89269e3a05ff7e76ec7739843872468fc4bec8475410", 65537, + "1ba36841f57aa8b799c4dd02b39d53e5fb7780d3f09f91a57a86dcb418d8d506", + }, + }; + + ge25519 pt; + bignum256modm sc, sc2; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + expand256_modm(sc, fromhex(tests[i].sc), 32); + ge25519_unpack_vartime(&pt, fromhex(tests[i].pt)); + + xmr_derivation_to_scalar(sc2, &pt, tests[i].idx); + ck_assert_int_eq(eq256_modm(sc, sc2), 1); + + xmr_derivation_to_scalar(sc2, &pt, tests[i].idx + 1); + ck_assert_int_eq(eq256_modm(sc, sc2), 0); + } +} +END_TEST + + +START_TEST(test_xmr_generate_key_derivation) +{ + static const struct { + char *pt; + char *sc; + char *r; + } tests[] = { + { + "38f94f27c8037aff025e365275ed1029fd636dda5f69e5f98fdcf92e0a28f31a", + "8f1c73ee5327a43264a7b60b9e7882312b582f33e89846a8694dbf094bb3a90a", + "1fbfe4dcc8c824c274649545f297fa320cd4c1689b1d0ff4887567c4d4a75649", + }, + { + "26785c3941a32f194228eb659c5ee305e63868896defc50ee6c4e0e92d1e246a", + "dbbffec4686ba8ab25e2f1b04c0e7ae51c5143c91353bfb5998430ebe365a609", + "cca34db8dd682ec164d8973b555253934596b77849ef7709d9321121c25aba02", + }, + { + "43505a8ce7248f70d3aae4f57fb59c254ce2b2a0cc2bcf50f2344e51d59b36b3", + "19a802e35f6ff94efe96ec016effe04e635bbd9c1ce2612d5ba2ee4659456b06", + "fc6c93a93f77ff89c18b9abf95b28ec8591ab97eee8e4afee93aa766a4bd3934", + }, + }; + + ge25519 pt, pt2, pt3; + bignum256modm sc; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + expand256_modm(sc, fromhex(tests[i].sc), 32); + ge25519_unpack_vartime(&pt, fromhex(tests[i].pt)); + ge25519_unpack_vartime(&pt2, fromhex(tests[i].r)); + xmr_generate_key_derivation(&pt3, &pt, sc); + ck_assert_int_eq(ge25519_eq(&pt3, &pt2), 1); + ck_assert_int_eq(ge25519_eq(&pt3, &pt), 0); + } +} +END_TEST + + +START_TEST(test_xmr_derive_private_key) +{ + static const struct { + char *pt; + uint32_t idx; + char *base; + char *r; + } tests[] = { + { + "0541d8f069e5e80a892e39bbf1944ef578008cf9ecf1d100760a05858c1b709e", 0, + "76967eeb0a3d181bb0b384be71c680a4287599f27b2ddbd07f8e06ab6f2c880e", + "45728c5cb658e470790f124a01699d2126832b7e5c6b7760b6f11119b96ad603", + }, + { + "fc6e0bd785a84e62c9ac8a97e0e604a79494bc2cf7b3b38ef8af7791c87b5bb8", 1, + "32fbe149562b7ccb34bc4105b87b2a834024799336c8eea5e94df77f1ae9a807", + "64508e83bbadf63f8ecfae4d9dcdd39a4ba23508a545e1a37026f0fa2539d601", + }, + { + "f6bd7a72dc9444dc7e09a0eb4d312d36fe173693d6405b132a5b090297a04ea9", 65537, + "333a8fcce6726457e4222a87b9b475c1fcf985f756c2029fcb39184c0a5c4804", + "37c16a22da4c0082ebf4bf807403b169f75142a9bd8560ed45f3f9347218260e", + }, + }; + + ge25519 pt; + bignum256modm base, res, res_exp; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + expand256_modm(base, fromhex(tests[i].base), 32); + expand256_modm(res_exp, fromhex(tests[i].r), 32); + ge25519_unpack_vartime(&pt, fromhex(tests[i].pt)); + + xmr_derive_private_key(res, &pt, tests[i].idx, base); + ck_assert_int_eq(eq256_modm(res, res_exp), 1); + ck_assert_int_eq(eq256_modm(res, base), 0); + } +} +END_TEST + + +START_TEST(test_xmr_derive_public_key) +{ + static const struct { + char *pt; + uint32_t idx; + char *base; + char *r; + } tests[] = { + { + "653f03e7766d472826aa49793bc0cfde698e6745ae5e4217980ba307739f2ed9", 0, + "2a393f0858732970ac8dea003b17e1ce9371f0a045bd9b7af0d998262739f4cc", + "f7a3db27c45f265f6a68a30137ca44289a6cf1a6db2cf482c59ebfb0142ad419", + }, + { + "338e93f61e6470a5cc71c07b8caedd1a9a28da037aab65c1ca5538501b012c81", 1, + "af3a1d39397d778731c4510110fd117dc02f756e390713d58f94a06203ce39eb", + "779e2a043c881f06aba1952741fd753098615c4fafa8f62748467ab9bac43241", + }, + { + "7735e9476440927b89b18d7a1e0645b218a1a6d28c642aebb16c1dba0926d5e4", 65537, + "62c3eed062bd602f7f2164c69ad0b5a8eb3ea560c930f6b41abfc1c4839ea432", + "6da4ebd29498d16c4e813abb3e328c83f9b01a7ba1da6e818071f8ec563626c8", + }, + }; + + ge25519 pt, base, res, res_exp; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + ge25519_unpack_vartime(&pt, fromhex(tests[i].pt)); + ge25519_unpack_vartime(&base, fromhex(tests[i].base)); + ge25519_unpack_vartime(&res_exp, fromhex(tests[i].r)); + + xmr_derive_public_key(&res, &pt, tests[i].idx, &base); + + ck_assert_int_eq(ge25519_eq(&res, &res_exp), 1); + ck_assert_int_eq(ge25519_eq(&res, &base), 0); + } +} +END_TEST + + +START_TEST(test_xmr_add_keys2) +{ + static const struct { + char *a; + char *b; + char *B; + char *r; + } tests[] = { + { + "631238da9578d7cb8db16fc4322671bfcb251cc5228b060664800ec1895be608", + "f9a73fca0be058415a148f9e2871be59e1fc7ae6f6193199125237e0d7c1630f", + "ef5ca4fc90f330e825adcdc953da0b3becd853aa819219842790bb39775f2255", + "06623fd0e7a3d787a4d224f6ca2fdab2dcd9d1221578515974b9c4dee65fdcf5", + }, + { + "dac2e629e5c75c312253b19d1d3a0a423158fdd9cdcf4c7a7bf2717d0b748602", + "0483d98d750d4977b499cefd558a0a61580823a37da2b011501e24718e6c7f0a", + "51fd3cd2f1a603ec7be3b35da9c105d91c4304e6a63facf48d7730712cedc0ee", + "f7a5d645ba01a5b7ccbe9636d14422bb587fc529317b23761f0e39222b783b87", + }, + { + "817c4d2fd3e841d860bdab6b7ccf098f3e637eca468d0a3825c50b71f61d0e0c", + "1f6c4795d7fb0d53b5775874ac4c0963607d2b7bd11a7c5d10735badc4a27207", + "bef0e0ed09d602bbe1dd38358b5f8fca27fcad60a69440f104441c3fc68df9c7", + "bc0fc824d74eca0e10eacd0bc2f3322e0bcb02a44ce53f2f5f1fc472f99be8d2", + }, + }; + + bignum256modm a, b; + ge25519 B, res, res_exp; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + expand256_modm(a, fromhex(tests[i].a), 32); + expand256_modm(b, fromhex(tests[i].b), 32); + ge25519_unpack_vartime(&B, fromhex(tests[i].B)); + ge25519_unpack_vartime(&res_exp, fromhex(tests[i].r)); + + xmr_add_keys2(&res, a, b, &B); + ck_assert_int_eq(ge25519_eq(&res, &res_exp), 1); + ck_assert_int_eq(ge25519_eq(&res, &B), 0); + + xmr_add_keys2_vartime(&res, a, b, &B); + ck_assert_int_eq(ge25519_eq(&res, &res_exp), 1); + ck_assert_int_eq(ge25519_eq(&res, &B), 0); + } +} +END_TEST + + +START_TEST(test_xmr_add_keys3) +{ + static const struct { + char *a; + char *A; + char *b; + char *B; + char *r; + } tests[] = { + { + "7048b8c4603ae194c502fa458b0e11a4c7a330852bbef66b7c1d67e9f919f509", + "9167c5b182758699baeb421e7f1200272fc775e4c7c7c183cc47261dccbb569f", + "c2cb2bc0249fc7be8eb9b3bed7d37aa6f2c3f433abb3a4a00b13bed64b61f30b", + "b3ec53b07a1be70ac8d0fa365b86f0d6d4cbf98641e7704b3d684558e2ea59ef", + "4dc016d702d599bde5eaeb2bf0c2d0d3f6b9cede961bc539bcb369c3b3086358", + }, + { + "e9794a6652940474958936f07f3904d514228553247633cfb7ae8ffa9fa0f406", + "0e51cea6df2f6f56a9935689364f0d295a7c89f51d40efb2518c17d1b9db792b", + "c132e7be08afdd93984c52c6e1c596edc6b8fc8f1faed95f55e2f819ee806706", + "1a0e03c6858f6cf1b43f4b8456c03144af553bbbd050e152834fd1615b577cb3", + "088f19c6727f8704373d391a36c230395d386f69edb4151ecf8afcd27793fff5", + }, + { + "88920b0c96b15cc04e879f53a76f85f3c7a2a5f275b2772b5b74ee83372aea00", + "e95731ab61a98fedcded475cf21b4ecf2ef9f1adecefba8fdc476a5bb1cf60f9", + "c86026b66c1045fb69e4f24ff6c15d4fad4d565e646938a2ffb7db37ccb4100d", + "d80cbf2986c12e4c7ebac1e55abbdfc4212c00aec8bc90c965becf863262a074", + "047cebaeb3ec2132e7386ba52531b04070206ba1106565c0fbd7d7280694568a", + }, + }; + + bignum256modm a, b; + ge25519 A, B, res, res_exp; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + expand256_modm(a, fromhex(tests[i].a), 32); + expand256_modm(b, fromhex(tests[i].b), 32); + ge25519_unpack_vartime(&A, fromhex(tests[i].A)); + ge25519_unpack_vartime(&B, fromhex(tests[i].B)); + ge25519_unpack_vartime(&res_exp, fromhex(tests[i].r)); + + xmr_add_keys3(&res, a, &A, b, &B); + ck_assert_int_eq(ge25519_eq(&res, &res_exp), 1); + ck_assert_int_eq(ge25519_eq(&res, &B), 0); + + xmr_add_keys3_vartime(&res, a, &A, b, &B); + ck_assert_int_eq(ge25519_eq(&res, &res_exp), 1); + ck_assert_int_eq(ge25519_eq(&res, &B), 0); + } +} +END_TEST + + +START_TEST(test_xmr_get_subaddress_secret_key) +{ + static const struct { + uint32_t major, minor; + char *m; + char *r; + } tests[] = { + { + 0, 0, + "36fad9f7bff465c15a755f1482fb2ecc3a4e434303df906882234e42b5813207", + "8a510a9fe1824b49abbae05958084f9c9098775f29e15427309177882471cf01", + }, + { + 0, 1, + "36fad9f7bff465c15a755f1482fb2ecc3a4e434303df906882234e42b5813207", + "2bbc9366c04abb0523e2b2d6e709670ffe6645bacedfee968d9c6bc8eefe9c0f", + }, + { + 100, 100, + "36fad9f7bff465c15a755f1482fb2ecc3a4e434303df906882234e42b5813207", + "c3837d41fedeaed126cf4fc1a5ea47b8b7f38f6a64aa534e3dd45a3c93f37600", + }, + }; + + bignum256modm m, res, res_exp; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + expand256_modm(m, fromhex(tests[i].m), 32); + expand256_modm(res_exp, fromhex(tests[i].r), 32); + xmr_get_subaddress_secret_key(res, tests[i].major, tests[i].minor, m); + + ck_assert_int_eq(eq256_modm(res, res_exp), 1); + ck_assert_int_eq(eq256_modm(res, m), 0); + } +} +END_TEST + + +START_TEST(test_xmr_gen_c) +{ + static const struct { + char *a; + uint64_t amount; + char *r; + } tests[] = { + { + "e3e6558c291bbb98aa691d068b67d59dc520afb23fdd51bf65283626fc2ad903", 0, + "ef19d73bdf3749240b80ee7695f53ad7c2fc2cf868a93209799f41212d099750", + }, + { + "6788c9579c377f3228680bd0e6d01b1ee0c763b35ed39d36fa2146cc2ee16e0e", 1, + "4913b9af4f2725d87a4404c22cf366597d1c1e6a1f510ae14081d8b7c5a9de77", + }, + { + "ad9e89d67012935540427c241756d6a9d260c5e134603c41d31e24f8651bef08", 65537, + "f005721da08f24e68314abed3ddfd94165e4be3813398fb126e3f366820b9c90", + }, + { + "fdbb70ff07be24d98de3bffa0a33756646497224318fb7fe136f0e7789d12607", 0xffffffffffffffffULL, + "a9c38927f299c5f14c98a1a9c9981e59c606ff597274b9b709e1356f12e1498c", + }, + }; + + bignum256modm a; + ge25519 res, res_exp; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + expand256_modm(a, fromhex(tests[i].a), 32); + ge25519_unpack_vartime(&res_exp, fromhex(tests[i].r)); + xmr_gen_c(&res, a, tests[i].amount); + + ck_assert_int_eq(ge25519_eq(&res, &res_exp), 1); + } +} +END_TEST + + +START_TEST(test_xmr_varint) +{ + static const struct { + uint64_t x; + char *r; + } tests[] = { + { + 0, + "00", + }, + { + 24, + "18", + }, + { + 65535, + "ffff03", + }, + { + 65537, + "818004", + }, + { + 0x7fffffffULL, + "ffffffff07", + }, + { + 0xffffffffULL, + "ffffffff0f", + }, + { + 0xffffffffffffffffULL, + "ffffffffffffffffff01", + }, + { + 0xdeadc0deULL, + "de81b7f50d", + }, + }; + + uint64_t val; + unsigned char buff[64]; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + int s1 = xmr_size_varint(tests[i].x); + int written = 0; + int read = 0; + + ck_assert_int_eq(s1, strlen(tests[i].r)/2); + written = xmr_write_varint(buff, sizeof(buff), tests[i].x); + ck_assert_int_eq(s1, written); + ck_assert_mem_eq(buff, fromhex(tests[i].r), strlen(tests[i].r)/2); + + read = xmr_read_varint(buff, sizeof(buff), &val); + ck_assert_int_eq(read, written); + ck_assert(tests[i].x == val); + } +} +END_TEST + + +START_TEST(test_xmr_gen_range_sig) +{ + uint64_t tests[] = { + 0, 1, 65535, 65537, 0xffffffffffffffffULL, 0xdeadc0deULL, + }; + + unsigned char buff[32]; + xmr_range_sig_t sig; + ge25519 C, Ctmp, Cb, Ch, P1, P2, LL; + bignum256modm mask, hsh, ee, s, ee_comp; + Hasher hasher; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + xmr_gen_range_sig(&sig, &C, mask, tests[i], NULL); + + ge25519_set_neutral(&Ctmp); + for(int j = 0; j < XMR_ATOMS; j++){ + ge25519_unpack_vartime(&Cb, sig.Ci[j]); + ge25519_add(&Ctmp, &Ctmp, &Cb, 0); + } + + ck_assert_int_eq(ge25519_eq(&C, &Ctmp), 1); + + xmr_hasher_init(&hasher); + ge25519_set_xmr_h(&Ch); + expand256_modm(ee, sig.asig.ee, 32); + + for(int j = 0; j < XMR_ATOMS; j++){ + ge25519_unpack_vartime(&P1, sig.Ci[j]); + ge25519_add(&P2, &P1, &Ch, 1); + expand256_modm(s, sig.asig.s0[j], 32); + + xmr_add_keys2(&LL, s, ee, &P1); + ge25519_pack(buff, &LL); + xmr_hash_to_scalar(hsh, buff, 32); + + expand256_modm(s, sig.asig.s1[j], 32); + xmr_add_keys2(&LL, s, hsh, &P2); + + ge25519_pack(buff, &LL); + xmr_hasher_update(&hasher, buff, 32); + + ge25519_double(&Ch, &Ch); + } + + xmr_hasher_final(&hasher, buff); + expand256_modm(ee_comp, buff, 32); + ck_assert_int_eq(eq256_modm(ee, ee_comp), 1); + } +} +END_TEST +#endif From 13f51319d8d02a0b8ecea26f6b9623f12ed02068 Mon Sep 17 00:00:00 2001 From: Dusan Klinec Date: Tue, 21 Aug 2018 15:38:14 +0200 Subject: [PATCH 589/627] updates to the monero branch --- ed25519-donna/ge25519.c | 6 ------ ed25519-donna/ge25519.h | 3 --- monero/xmr.c | 29 +++-------------------------- tests/test_check.c | 2 +- tests/test_check_monero.h | 17 +++++++++++++---- 5 files changed, 17 insertions(+), 40 deletions(-) diff --git a/ed25519-donna/ge25519.c b/ed25519-donna/ge25519.c index da1fac7b7..7bb3d2e20 100644 --- a/ed25519-donna/ge25519.c +++ b/ed25519-donna/ge25519.c @@ -369,10 +369,4 @@ int ge25519_unpack_vartime(ge25519 *r, const unsigned char *s){ void ge25519_scalarmult_base_wrapper(ge25519 *r, const bignum256modm s){ ge25519_scalarmult_base_niels(r, ge25519_niels_base_multiples, s); - ge25519_norm(r, r); -} - -void ge25519_scalarmult_wrapper(ge25519 *r, const ge25519 *P, const bignum256modm a){ - ge25519_scalarmult(r, P, a); - ge25519_norm(r, r); } diff --git a/ed25519-donna/ge25519.h b/ed25519-donna/ge25519.h index 964c6aef1..f94fe6236 100644 --- a/ed25519-donna/ge25519.h +++ b/ed25519-donna/ge25519.h @@ -71,7 +71,4 @@ int ge25519_unpack_vartime(ge25519 *r, const unsigned char *s); /* aG, wrapper for niels base mult. */ void ge25519_scalarmult_base_wrapper(ge25519 *r, const bignum256modm s); -/* aP, wrapper. General purpose, normalizes after multiplication */ -void ge25519_scalarmult_wrapper(ge25519 *r, const ge25519 *P, const bignum256modm a); - #endif diff --git a/monero/xmr.c b/monero/xmr.c index ccac66d95..7a3576348 100644 --- a/monero/xmr.c +++ b/monero/xmr.c @@ -71,7 +71,6 @@ void xmr_derivation_to_scalar(bignum256modm s, const ge25519 * p, uint32_t outpu void xmr_generate_key_derivation(ge25519 * r, const ge25519 * A, const bignum256modm b){ ge25519 bA; ge25519_scalarmult(&bA, A, b); - ge25519_norm(&bA, &bA); ge25519_mul8(r, &bA); } @@ -83,58 +82,36 @@ void xmr_derive_private_key(bignum256modm s, const ge25519 * deriv, uint32_t idx void xmr_derive_public_key(ge25519 * r, const ge25519 * deriv, uint32_t idx, const ge25519 * base){ bignum256modm s={0}; ge25519 p2; - ge25519_pniels Bp; - ge25519_p1p1 p1; xmr_derivation_to_scalar(s, deriv, idx); ge25519_scalarmult_base_niels(&p2, ge25519_niels_base_multiples, s); - ge25519_norm(&p2, &p2); - - ge25519_full_to_pniels(&Bp, base); - ge25519_pnielsadd_p1p1(&p1, &p2, &Bp, 0); - ge25519_p1p1_to_full(r, &p1); + ge25519_add(r, base, &p2, 0); } void xmr_add_keys2(ge25519 * r, const bignum256modm a, const bignum256modm b, const ge25519 * B){ // aG + bB, G is basepoint ge25519 aG, bB; - ge25519_pniels bBn; - ge25519_p1p1 p1; ge25519_scalarmult_base_niels(&aG, ge25519_niels_base_multiples, a); ge25519_scalarmult(&bB, B, b); - ge25519_norm(&bB, &bB); - ge25519_norm(&aG, &aG); - - ge25519_full_to_pniels(&bBn, &bB); - ge25519_pnielsadd_p1p1(&p1, &aG, &bBn, 0); - ge25519_p1p1_to_full(r, &p1); + ge25519_add(r, &aG, &bB, 0); } void xmr_add_keys2_vartime(ge25519 * r, const bignum256modm a, const bignum256modm b, const ge25519 * B){ // aG + bB, G is basepoint ge25519_double_scalarmult_vartime(r, B, b, a); - ge25519_norm(r, r); } void xmr_add_keys3(ge25519 * r, const bignum256modm a, const ge25519 * A, const bignum256modm b, const ge25519 * B){ // aA + bB ge25519 aA, bB; - ge25519_pniels bBn; - ge25519_p1p1 p1; ge25519_scalarmult(&aA, A, a); ge25519_scalarmult(&bB, B, b); - ge25519_norm(&bB, &bB); - ge25519_norm(&aA, &aA); - - ge25519_full_to_pniels(&bBn, &bB); - ge25519_pnielsadd_p1p1(&p1, &aA, &bBn, 0); - ge25519_p1p1_to_full(r, &p1); + ge25519_add(r, &aA, &bB, 0); } void xmr_add_keys3_vartime(ge25519 * r, const bignum256modm a, const ge25519 * A, const bignum256modm b, const ge25519 * B){ // aA + bB ge25519_double_scalarmult_vartime2(r, A, a, B, b); - ge25519_norm(r, r); } void xmr_get_subaddress_secret_key(bignum256modm r, uint32_t major, uint32_t minor, const bignum256modm m){ diff --git a/tests/test_check.c b/tests/test_check.c index 86389b46a..c609eb080 100644 --- a/tests/test_check.c +++ b/tests/test_check.c @@ -5093,7 +5093,7 @@ Suite *test_suite(void) tcase_add_test(tc, test_xmr_ge25519_base); tcase_add_test(tc, test_xmr_ge25519_check); tcase_add_test(tc, test_xmr_ge25519_scalarmult_base_wrapper); - tcase_add_test(tc, test_xmr_ge25519_scalarmult_wrapper); + tcase_add_test(tc, test_xmr_ge25519_scalarmult); tcase_add_test(tc, test_xmr_ge25519_ops); suite_add_tcase(s, tc); diff --git a/tests/test_check_monero.h b/tests/test_check_monero.h index c76edefc1..86e355d2a 100644 --- a/tests/test_check_monero.h +++ b/tests/test_check_monero.h @@ -511,7 +511,7 @@ START_TEST(test_xmr_ge25519_scalarmult_base_wrapper) END_TEST -START_TEST(test_xmr_ge25519_scalarmult_wrapper) +START_TEST(test_xmr_ge25519_scalarmult) { static const struct { char *sc; @@ -562,7 +562,7 @@ START_TEST(test_xmr_ge25519_scalarmult_wrapper) expand256_modm(sc, fromhex(tests[i].sc), 32); ge25519_unpack_vartime(&pt, fromhex(tests[i].pt)); ge25519_unpack_vartime(&pt2, fromhex(tests[i].pt2)); - ge25519_scalarmult_wrapper(&pt3, &pt, sc); + ge25519_scalarmult(&pt3, &pt, sc); ck_assert_int_eq(ge25519_eq(&pt3, &pt2), 1); } } @@ -574,18 +574,27 @@ START_TEST(test_xmr_ge25519_ops) int tests[] = {1, 2, 7, 8, 637, 9912, 12345}; for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { struct ge25519_t a, b, c, d; - bignum256modm s1 = {0}, s2 = {0}, s3 = {0}; + bignum256modm s1 = {0}, s2 = {0}, s3 = {0}, s4 = {0}; set256_modm(s1, tests[i]); set256_modm(s2, 8 * tests[i]); set256_modm(s3, 8); + set256_modm(s4, 2); + + ge25519_scalarmult_base_niels(&a, ge25519_niels_base_multiples, s1); + ge25519_scalarmult_base_niels(&b, ge25519_niels_base_multiples, s2); + ge25519_scalarmult(&c, &a, s4); + ge25519_scalarmult(&c, &c, s4); + ge25519_scalarmult(&c, &c, s4); + ck_assert_int_eq(ge25519_eq(&c, &b), 1); + ck_assert_int_eq(ge25519_eq(&a, &b), 0); ge25519_scalarmult_base_wrapper(&a, s1); ge25519_mul8(&b, &a); ge25519_scalarmult_base_wrapper(&c, s2); ck_assert_int_eq(ge25519_eq(&b, &c), 1); - ge25519_scalarmult_wrapper(&d, &a, s3); + ge25519_scalarmult(&d, &a, s3); ck_assert_int_eq(ge25519_eq(&d, &c), 1); ge25519_copy(&a, &b); From cabc926b39c693e75961d0843b7952323f729db2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Vejpustek?= Date: Mon, 3 Sep 2018 16:21:41 +0200 Subject: [PATCH 590/627] move ge25519.c into curve25519-donna-32bit.c and ed25519-donna-impl-base.c (#177) --- Makefile | 1 - ed25519-donna/curve25519-donna-32bit.c | 149 ++++++++++ ed25519-donna/curve25519-donna-32bit.h | 26 ++ ed25519-donna/ed25519-donna-impl-base.c | 216 ++++++++++++++ ed25519-donna/ed25519-donna-impl-base.h | 39 +++ ed25519-donna/ge25519.c | 372 ------------------------ ed25519-donna/ge25519.h | 74 ----- monero/xmr.h | 2 +- tests/test_check.c | 1 - 9 files changed, 431 insertions(+), 449 deletions(-) delete mode 100644 ed25519-donna/ge25519.c delete mode 100644 ed25519-donna/ge25519.h diff --git a/Makefile b/Makefile index 3bad57c8a..6d14fec61 100644 --- a/Makefile +++ b/Makefile @@ -51,7 +51,6 @@ SRCS += aes/aescrypt.c aes/aeskey.c aes/aestab.c aes/aes_modes.c SRCS += ed25519-donna/curve25519-donna-32bit.c ed25519-donna/curve25519-donna-helpers.c ed25519-donna/modm-donna-32bit.c SRCS += ed25519-donna/ed25519-donna-basepoint-table.c ed25519-donna/ed25519-donna-32bit-tables.c ed25519-donna/ed25519-donna-impl-base.c SRCS += ed25519-donna/ed25519.c ed25519-donna/curve25519-donna-scalarmult-base.c ed25519-donna/ed25519-sha3.c ed25519-donna/ed25519-keccak.c -SRCS += ed25519-donna/ge25519.c SRCS += monero/base58.c SRCS += monero/serialize.c SRCS += monero/xmr.c diff --git a/ed25519-donna/curve25519-donna-32bit.c b/ed25519-donna/curve25519-donna-32bit.c index 972f913e9..b50f29e68 100644 --- a/ed25519-donna/curve25519-donna-32bit.c +++ b/ed25519-donna/curve25519-donna-32bit.c @@ -530,3 +530,152 @@ void curve25519_swap_conditional(bignum25519 a, bignum25519 b, uint32_t iswap) { x8 = swap & (a[8] ^ b[8]); a[8] ^= x8; b[8] ^= x8; x9 = swap & (a[9] ^ b[9]); a[9] ^= x9; b[9] ^= x9; } + +void curve25519_set(bignum25519 r, uint32_t x){ + r[0] = x & reduce_mask_26; x >>= 26; + r[1] = x & reduce_mask_25; + r[2] = 0; + r[3] = 0; + r[4] = 0; + r[5] = 0; + r[6] = 0; + r[7] = 0; + r[8] = 0; + r[9] = 0; +} + +void curve25519_set_d(bignum25519 r){ + curve25519_copy(r, ge25519_ecd); +} + +void curve25519_set_2d(bignum25519 r){ + curve25519_copy(r, ge25519_ec2d); +} + +void curve25519_set_sqrtneg1(bignum25519 r){ + curve25519_copy(r, ge25519_sqrtneg1); +} + +int curve25519_isnegative(const bignum25519 f) { + unsigned char s[32]; + curve25519_contract(s, f); + return s[0] & 1; +} + +int curve25519_isnonzero(const bignum25519 f) { + unsigned char s[32]; + curve25519_contract(s, f); + return ((((int) (s[0] | s[1] | s[2] | s[3] | s[4] | s[5] | s[6] | s[7] | s[8] | + s[9] | s[10] | s[11] | s[12] | s[13] | s[14] | s[15] | s[16] | s[17] | + s[18] | s[19] | s[20] | s[21] | s[22] | s[23] | s[24] | s[25] | s[26] | + s[27] | s[28] | s[29] | s[30] | s[31]) - 1) >> 8) + 1) & 0x1; +} + +void curve25519_reduce(bignum25519 out, const bignum25519 in) { + uint32_t c; + out[0] = in[0] ; c = (out[0] >> 26); out[0] &= reduce_mask_26; + out[1] = in[1] + c; c = (out[1] >> 25); out[1] &= reduce_mask_25; + out[2] = in[2] + c; c = (out[2] >> 26); out[2] &= reduce_mask_26; + out[3] = in[3] + c; c = (out[3] >> 25); out[3] &= reduce_mask_25; + out[4] = in[4] + c; c = (out[4] >> 26); out[4] &= reduce_mask_26; + out[5] = in[5] + c; c = (out[5] >> 25); out[5] &= reduce_mask_25; + out[6] = in[6] + c; c = (out[6] >> 26); out[6] &= reduce_mask_26; + out[7] = in[7] + c; c = (out[7] >> 25); out[7] &= reduce_mask_25; + out[8] = in[8] + c; c = (out[8] >> 26); out[8] &= reduce_mask_26; + out[9] = in[9] + c; c = (out[9] >> 25); out[9] &= reduce_mask_25; + out[0] += 19 * c; +} + +void curve25519_divpowm1(bignum25519 r, const bignum25519 u, const bignum25519 v) { + bignum25519 v3={0}, uv7={0}, t0={0}, t1={0}, t2={0}; + int i; + + curve25519_square(v3, v); + curve25519_mul(v3, v3, v); /* v3 = v^3 */ + curve25519_square(uv7, v3); + curve25519_mul(uv7, uv7, v); + curve25519_mul(uv7, uv7, u); /* uv7 = uv^7 */ + + /*fe_pow22523(uv7, uv7);*/ + /* From fe_pow22523.c */ + + curve25519_square(t0, uv7); + curve25519_square(t1, t0); + curve25519_square(t1, t1); + curve25519_mul(t1, uv7, t1); + curve25519_mul(t0, t0, t1); + curve25519_square(t0, t0); + curve25519_mul(t0, t1, t0); + curve25519_square(t1, t0); + for (i = 0; i < 4; ++i) { + curve25519_square(t1, t1); + } + curve25519_mul(t0, t1, t0); + curve25519_square(t1, t0); + for (i = 0; i < 9; ++i) { + curve25519_square(t1, t1); + } + curve25519_mul(t1, t1, t0); + curve25519_square(t2, t1); + for (i = 0; i < 19; ++i) { + curve25519_square(t2, t2); + } + curve25519_mul(t1, t2, t1); + for (i = 0; i < 10; ++i) { + curve25519_square(t1, t1); + } + curve25519_mul(t0, t1, t0); + curve25519_square(t1, t0); + for (i = 0; i < 49; ++i) { + curve25519_square(t1, t1); + } + curve25519_mul(t1, t1, t0); + curve25519_square(t2, t1); + for (i = 0; i < 99; ++i) { + curve25519_square(t2, t2); + } + curve25519_mul(t1, t2, t1); + for (i = 0; i < 50; ++i) { + curve25519_square(t1, t1); + } + curve25519_mul(t0, t1, t0); + curve25519_square(t0, t0); + curve25519_square(t0, t0); + curve25519_mul(t0, t0, uv7); + + /* End fe_pow22523.c */ + /* t0 = (uv^7)^((q-5)/8) */ + curve25519_mul(t0, t0, v3); + curve25519_mul(r, t0, u); /* u^(m+1)v^(-(m+1)) */ +} + +void curve25519_expand_reduce(bignum25519 out, const unsigned char in[32]) { + uint32_t x0,x1,x2,x3,x4,x5,x6,x7; +#define F(s) \ + ((((uint32_t)in[s + 0]) ) | \ + (((uint32_t)in[s + 1]) << 8) | \ + (((uint32_t)in[s + 2]) << 16) | \ + (((uint32_t)in[s + 3]) << 24)) + x0 = F(0); + x1 = F(4); + x2 = F(8); + x3 = F(12); + x4 = F(16); + x5 = F(20); + x6 = F(24); + x7 = F(28); +#undef F + + out[0] = ( x0 ) & reduce_mask_26; + out[1] = ((((uint64_t)x1 << 32) | x0) >> 26) & reduce_mask_25; + out[2] = ((((uint64_t)x2 << 32) | x1) >> 19) & reduce_mask_26; + out[3] = ((((uint64_t)x3 << 32) | x2) >> 13) & reduce_mask_25; + out[4] = (( x3) >> 6) & reduce_mask_26; + out[5] = ( x4 ) & reduce_mask_25; + out[6] = ((((uint64_t)x5 << 32) | x4) >> 25) & reduce_mask_26; + out[7] = ((((uint64_t)x6 << 32) | x5) >> 19) & reduce_mask_25; + out[8] = ((((uint64_t)x7 << 32) | x6) >> 12) & reduce_mask_26; + out[9] = (( x7) >> 6); // & reduce_mask_25; /* ignore the top bit */ + out[0] += 19 * (out[9] >> 25); + out[9] &= reduce_mask_25; +} diff --git a/ed25519-donna/curve25519-donna-32bit.h b/ed25519-donna/curve25519-donna-32bit.h index 19de6325c..87bea94f9 100644 --- a/ed25519-donna/curve25519-donna-32bit.h +++ b/ed25519-donna/curve25519-donna-32bit.h @@ -51,3 +51,29 @@ void curve25519_contract(unsigned char out[32], const bignum25519 in); /* if (iswap) swap(a, b) */ void curve25519_swap_conditional(bignum25519 a, bignum25519 b, uint32_t iswap); + +/* uint32_t to Zmod(2^255-19) */ +void curve25519_set(bignum25519 r, uint32_t x); + +/* set d */ +void curve25519_set_d(bignum25519 r); + +/* set 2d */ +void curve25519_set_2d(bignum25519 r); + +/* set sqrt(-1) */ +void curve25519_set_sqrtneg1(bignum25519 r); + +/* constant time Zmod(2^255-19) negative test */ +int curve25519_isnegative(const bignum25519 f); + +/* constant time Zmod(2^255-19) non-zero test */ +int curve25519_isnonzero(const bignum25519 f); + +/* reduce Zmod(2^255-19) */ +void curve25519_reduce(bignum25519 r, const bignum25519 in); + +void curve25519_divpowm1(bignum25519 r, const bignum25519 u, const bignum25519 v); + +/* Zmod(2^255-19) from byte array to bignum25519 expansion with modular reduction */ +void curve25519_expand_reduce(bignum25519 out, const unsigned char in[32]); diff --git a/ed25519-donna/ed25519-donna-impl-base.c b/ed25519-donna/ed25519-donna-impl-base.c index 128445676..00bbfb6f2 100644 --- a/ed25519-donna/ed25519-donna-impl-base.c +++ b/ed25519-donna/ed25519-donna-impl-base.c @@ -1,5 +1,30 @@ +#include #include "ed25519-donna.h" +/* sqrt(x) is such an integer y that 0 <= y <= p - 1, y % 2 = 0, and y^2 = x (mod p). */ +/* d = -121665 / 121666 */ +static const bignum25519 ALIGN(16) fe_d = { + 0x35978a3, 0x0d37284, 0x3156ebd, 0x06a0a0e, 0x001c029, 0x179e898, 0x3a03cbb, 0x1ce7198, 0x2e2b6ff, 0x1480db3}; /* d */ +static const bignum25519 ALIGN(16) fe_sqrtm1 = { + 0x20ea0b0, 0x186c9d2, 0x08f189d, 0x035697f, 0x0bd0c60, 0x1fbd7a7, 0x2804c9e, 0x1e16569, 0x004fc1d, 0x0ae0c92}; /* sqrt(-1) */ +//static const bignum25519 ALIGN(16) fe_d2 = { +// 0x2b2f159, 0x1a6e509, 0x22add7a, 0x0d4141d, 0x0038052, 0x0f3d130, 0x3407977, 0x19ce331, 0x1c56dff, 0x0901b67}; /* 2 * d */ + +/* A = 2 * (1 - d) / (1 + d) = 486662 */ +static const bignum25519 ALIGN(16) fe_ma2 = { + 0x33de3c9, 0x1fff236, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff}; /* -A^2 */ +static const bignum25519 ALIGN(16) fe_ma = { + 0x3f892e7, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff}; /* -A */ +static const bignum25519 ALIGN(16) fe_fffb1 = { + 0x1e3bdff, 0x025a2b3, 0x18e5bab, 0x0ba36ac, 0x0b9afed, 0x004e61c, 0x31d645f, 0x09d1bea, 0x102529e, 0x0063810}; /* sqrt(-2 * A * (A + 2)) */ +static const bignum25519 ALIGN(16) fe_fffb2 = { + 0x383650d, 0x066df27, 0x10405a4, 0x1cfdd48, 0x2b887f2, 0x1e9a041, 0x1d7241f, 0x0612dc5, 0x35fba5d, 0x0cbe787}; /* sqrt(2 * A * (A + 2)) */ +static const bignum25519 ALIGN(16) fe_fffb3 = { + 0x0cfd387, 0x1209e3a, 0x3bad4fc, 0x18ad34d, 0x2ff6c02, 0x0f25d12, 0x15cdfe0, 0x0e208ed, 0x32eb3df, 0x062d7bb}; /* sqrt(-sqrt(-1) * A * (A + 2)) */ +static const bignum25519 ALIGN(16) fe_fffb4 = { + 0x2b39186, 0x14640ed, 0x14930a7, 0x04509fa, 0x3b91bf0, 0x0f7432e, 0x07a443f, 0x17f24d8, 0x031067d, 0x0690fcc}; /* sqrt(sqrt(-1) * A * (A + 2)) */ + + /* Timing safe memory compare */ @@ -504,3 +529,194 @@ void ge25519_scalarmult_base_niels(ge25519 *r, const uint8_t basepoint_table[256 ge25519_nielsadd2(r, &t); } } + +int ge25519_check(const ge25519 *r){ + /* return (z % q != 0 and + x * y % q == z * t % q and + (y * y - x * x - z * z - ed25519.d * t * t) % q == 0) + */ + + bignum25519 z={0}, lhs={0}, rhs={0}, tmp={0}, res={0}; + curve25519_reduce(z, r->z); + + curve25519_mul(lhs, r->x, r->y); + curve25519_mul(rhs, r->z, r->t); + curve25519_sub_reduce(lhs, lhs, rhs); + + curve25519_square(res, r->y); + curve25519_square(tmp, r->x); + curve25519_sub_reduce(res, res, tmp); + curve25519_square(tmp, r->z); + curve25519_sub_reduce(res, res, tmp); + curve25519_square(tmp, r->t); + curve25519_mul(tmp, tmp, ge25519_ecd); + curve25519_sub_reduce(res, res, tmp); + + const int c1 = curve25519_isnonzero(z); + const int c2 = curve25519_isnonzero(lhs); + const int c3 = curve25519_isnonzero(res); + return c1 & (c2^0x1) & (c3^0x1); +} + +int ge25519_eq(const ge25519 *a, const ge25519 *b){ + int eq = 1; + bignum25519 t1={0}, t2={0}; + + eq &= ge25519_check(a); + eq &= ge25519_check(b); + + curve25519_mul(t1, a->x, b->z); + curve25519_mul(t2, b->x, a->z); + curve25519_sub_reduce(t1, t1, t2); + eq &= curve25519_isnonzero(t1) ^ 1; + + curve25519_mul(t1, a->y, b->z); + curve25519_mul(t2, b->y, a->z); + curve25519_sub_reduce(t1, t1, t2); + eq &= curve25519_isnonzero(t1) ^ 1; + + return eq; +} + +void ge25519_copy(ge25519 *dst, const ge25519 *src){ + curve25519_copy(dst->x, src->x); + curve25519_copy(dst->y, src->y); + curve25519_copy(dst->z, src->z); + curve25519_copy(dst->t, src->t); +} + +void ge25519_set_base(ge25519 *r){ + ge25519_copy(r, &ge25519_basepoint); +} + +void ge25519_mul8(ge25519 *r, const ge25519 *t) { + ge25519_double_partial(r, t); + ge25519_double_partial(r, r); + ge25519_double(r, r); +} + +void ge25519_neg_partial(ge25519 *r){ + curve25519_neg(r->x, r->x); +} + +void ge25519_neg_full(ge25519 *r){ + curve25519_neg(r->x, r->x); + curve25519_neg(r->t, r->t); +} + +void ge25519_reduce(ge25519 *r, const ge25519 *t){ + curve25519_reduce(r->x, t->x); + curve25519_reduce(r->y, t->y); + curve25519_reduce(r->z, t->z); + curve25519_reduce(r->t, t->t); +} + +void ge25519_norm(ge25519 *r, const ge25519 * t){ + bignum25519 zinv; + curve25519_recip(zinv, t->z); + curve25519_mul(r->x, t->x, zinv); + curve25519_mul(r->y, t->y, zinv); + curve25519_mul(r->t, r->x, r->y); + curve25519_set(r->z, 1); +} + +void ge25519_add(ge25519 *r, const ge25519 *p, const ge25519 *q, unsigned char signbit) { + ge25519_pniels P_ni; + ge25519_p1p1 P_11; + + ge25519_full_to_pniels(&P_ni, q); + ge25519_pnielsadd_p1p1(&P_11, p, &P_ni, signbit); + ge25519_p1p1_to_full(r, &P_11); +} + +void ge25519_fromfe_frombytes_vartime(ge25519 *r, const unsigned char *s){ + bignum25519 u={0}, v={0}, w={0}, x={0}, y={0}, z={0}; + unsigned char sign; + + curve25519_expand_reduce(u, s); + + curve25519_square(v, u); + curve25519_add_reduce(v, v, v); /* 2 * u^2 */ + curve25519_set(w, 1); + curve25519_add_reduce(w, v, w); /* w = 2 * u^2 + 1 */ + + curve25519_square(x, w); /* w^2 */ + curve25519_mul(y, fe_ma2, v); /* -2 * A^2 * u^2 */ + curve25519_add_reduce(x, x, y); /* x = w^2 - 2 * A^2 * u^2 */ + + curve25519_divpowm1(r->x, w, x); /* (w / x)^(m + 1) */ + curve25519_square(y, r->x); + curve25519_mul(x, y, x); + curve25519_sub_reduce(y, w, x); + curve25519_copy(z, fe_ma); + + if (curve25519_isnonzero(y)) { + curve25519_add_reduce(y, w, x); + if (curve25519_isnonzero(y)) { + goto negative; + } else { + curve25519_mul(r->x, r->x, fe_fffb1); + } + } else { + curve25519_mul(r->x, r->x, fe_fffb2); + } + curve25519_mul(r->x, r->x, u); /* u * sqrt(2 * A * (A + 2) * w / x) */ + curve25519_mul(z, z, v); /* -2 * A * u^2 */ + sign = 0; + goto setsign; +negative: + curve25519_mul(x, x, fe_sqrtm1); + curve25519_sub_reduce(y, w, x); + if (curve25519_isnonzero(y)) { + assert((curve25519_add_reduce(y, w, x), !curve25519_isnonzero(y))); + curve25519_mul(r->x, r->x, fe_fffb3); + } else { + curve25519_mul(r->x, r->x, fe_fffb4); + } + /* r->x = sqrt(A * (A + 2) * w / x) */ + /* z = -A */ + sign = 1; +setsign: + if (curve25519_isnegative(r->x) != sign) { + assert(curve25519_isnonzero(r->x)); + curve25519_neg(r->x, r->x); + } + curve25519_add_reduce(r->z, z, w); + curve25519_sub_reduce(r->y, z, w); + curve25519_mul(r->x, r->x, r->z); + + // Partial form, saving from T coord computation . + // Later is mul8 discarding T anyway. + // rt = ((rx * ry % q) * inv(rz)) % q + // curve25519_mul(x, r->x, r->y); + // curve25519_recip(z, r->z); + // curve25519_mul(r->t, x, z); + +#if !defined(NDEBUG) + { + bignum25519 check_x={0}, check_y={0}, check_iz={0}, check_v={0}; + curve25519_recip(check_iz, r->z); + curve25519_mul(check_x, r->x, check_iz); + curve25519_mul(check_y, r->y, check_iz); + curve25519_square(check_x, check_x); + curve25519_square(check_y, check_y); + curve25519_mul(check_v, check_x, check_y); + curve25519_mul(check_v, fe_d, check_v); + curve25519_add_reduce(check_v, check_v, check_x); + curve25519_sub_reduce(check_v, check_v, check_y); + curve25519_set(check_x, 1); + curve25519_add_reduce(check_v, check_v, check_x); + assert(!curve25519_isnonzero(check_v)); + } +#endif +} + +int ge25519_unpack_vartime(ge25519 *r, const unsigned char *s){ + int res = ge25519_unpack_negative_vartime(r, s); + ge25519_neg_full(r); + return res; +} + +void ge25519_scalarmult_base_wrapper(ge25519 *r, const bignum256modm s){ + ge25519_scalarmult_base_niels(r, ge25519_niels_base_multiples, s); +} diff --git a/ed25519-donna/ed25519-donna-impl-base.h b/ed25519-donna/ed25519-donna-impl-base.h index d5edf95a0..342a6448a 100644 --- a/ed25519-donna/ed25519-donna-impl-base.h +++ b/ed25519-donna/ed25519-donna-impl-base.h @@ -63,3 +63,42 @@ void ge25519_scalarmult_base_choose_niels(ge25519_niels *t, const uint8_t table[ /* computes [s]basepoint */ void ge25519_scalarmult_base_niels(ge25519 *r, const uint8_t basepoint_table[256][96], const bignum256modm s); + +/* check if r is on curve */ +int ge25519_check(const ge25519 *r); + +/* a == b */ +int ge25519_eq(const ge25519 *a, const ge25519 *b); + +/* copies one point to another */ +void ge25519_copy(ge25519 *dst, const ge25519 *src); + +/* sets B point to r */ +void ge25519_set_base(ge25519 *r); + +/* 8*P */ +void ge25519_mul8(ge25519 *r, const ge25519 *t); + +/* -P */ +void ge25519_neg_partial(ge25519 *r); + +/* -P */ +void ge25519_neg_full(ge25519 *r); + +/* reduce all coords */ +void ge25519_reduce(ge25519 *r, const ge25519 *t); + +/* normalizes coords. (x, y, 1, x*y) */ +void ge25519_norm(ge25519 *r, const ge25519 * t); + +/* Simple addition */ +void ge25519_add(ge25519 *r, const ge25519 *a, const ge25519 *b, unsigned char signbit); + +/* point from bytes, used in H_p() */ +void ge25519_fromfe_frombytes_vartime(ge25519 *r, const unsigned char *s); + +/* point from bytes */ +int ge25519_unpack_vartime(ge25519 *r, const unsigned char *s); + +/* aG, wrapper for niels base mult. */ +void ge25519_scalarmult_base_wrapper(ge25519 *r, const bignum256modm s); diff --git a/ed25519-donna/ge25519.c b/ed25519-donna/ge25519.c deleted file mode 100644 index 7bb3d2e20..000000000 --- a/ed25519-donna/ge25519.c +++ /dev/null @@ -1,372 +0,0 @@ -// -// Created by Dusan Klinec on 29/04/2018. -// - -#include -#include "ge25519.h" - -static const uint32_t reduce_mask_25 = (1 << 25) - 1; -static const uint32_t reduce_mask_26 = (1 << 26) - 1; - -/* sqrt(x) is such an integer y that 0 <= y <= p - 1, y % 2 = 0, and y^2 = x (mod p). */ -/* d = -121665 / 121666 */ -static const bignum25519 ALIGN(16) fe_d = { - 0x35978a3, 0x0d37284, 0x3156ebd, 0x06a0a0e, 0x001c029, 0x179e898, 0x3a03cbb, 0x1ce7198, 0x2e2b6ff, 0x1480db3}; /* d */ -static const bignum25519 ALIGN(16) fe_sqrtm1 = { - 0x20ea0b0, 0x186c9d2, 0x08f189d, 0x035697f, 0x0bd0c60, 0x1fbd7a7, 0x2804c9e, 0x1e16569, 0x004fc1d, 0x0ae0c92}; /* sqrt(-1) */ -//static const bignum25519 ALIGN(16) fe_d2 = { -// 0x2b2f159, 0x1a6e509, 0x22add7a, 0x0d4141d, 0x0038052, 0x0f3d130, 0x3407977, 0x19ce331, 0x1c56dff, 0x0901b67}; /* 2 * d */ - -/* A = 2 * (1 - d) / (1 + d) = 486662 */ -static const bignum25519 ALIGN(16) fe_ma2 = { - 0x33de3c9, 0x1fff236, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff}; /* -A^2 */ -static const bignum25519 ALIGN(16) fe_ma = { - 0x3f892e7, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff}; /* -A */ -static const bignum25519 ALIGN(16) fe_fffb1 = { - 0x1e3bdff, 0x025a2b3, 0x18e5bab, 0x0ba36ac, 0x0b9afed, 0x004e61c, 0x31d645f, 0x09d1bea, 0x102529e, 0x0063810}; /* sqrt(-2 * A * (A + 2)) */ -static const bignum25519 ALIGN(16) fe_fffb2 = { - 0x383650d, 0x066df27, 0x10405a4, 0x1cfdd48, 0x2b887f2, 0x1e9a041, 0x1d7241f, 0x0612dc5, 0x35fba5d, 0x0cbe787}; /* sqrt(2 * A * (A + 2)) */ -static const bignum25519 ALIGN(16) fe_fffb3 = { - 0x0cfd387, 0x1209e3a, 0x3bad4fc, 0x18ad34d, 0x2ff6c02, 0x0f25d12, 0x15cdfe0, 0x0e208ed, 0x32eb3df, 0x062d7bb}; /* sqrt(-sqrt(-1) * A * (A + 2)) */ -static const bignum25519 ALIGN(16) fe_fffb4 = { - 0x2b39186, 0x14640ed, 0x14930a7, 0x04509fa, 0x3b91bf0, 0x0f7432e, 0x07a443f, 0x17f24d8, 0x031067d, 0x0690fcc}; /* sqrt(sqrt(-1) * A * (A + 2)) */ - -void curve25519_set(bignum25519 r, uint32_t x){ - r[0] = x & reduce_mask_26; x >>= 26; - r[1] = x & reduce_mask_25; - r[2] = 0; - r[3] = 0; - r[4] = 0; - r[5] = 0; - r[6] = 0; - r[7] = 0; - r[8] = 0; - r[9] = 0; -} - -void curve25519_set_d(bignum25519 r){ - curve25519_copy(r, ge25519_ecd); -} - -void curve25519_set_2d(bignum25519 r){ - curve25519_copy(r, ge25519_ec2d); -} - -void curve25519_set_sqrtneg1(bignum25519 r){ - curve25519_copy(r, ge25519_sqrtneg1); -} - -int curve25519_isnegative(const bignum25519 f) { - unsigned char s[32]; - curve25519_contract(s, f); - return s[0] & 1; -} - -int curve25519_isnonzero(const bignum25519 f) { - unsigned char s[32]; - curve25519_contract(s, f); - return ((((int) (s[0] | s[1] | s[2] | s[3] | s[4] | s[5] | s[6] | s[7] | s[8] | - s[9] | s[10] | s[11] | s[12] | s[13] | s[14] | s[15] | s[16] | s[17] | - s[18] | s[19] | s[20] | s[21] | s[22] | s[23] | s[24] | s[25] | s[26] | - s[27] | s[28] | s[29] | s[30] | s[31]) - 1) >> 8) + 1) & 0x1; -} - -void curve25519_reduce(bignum25519 out, const bignum25519 in) { - uint32_t c; - out[0] = in[0] ; c = (out[0] >> 26); out[0] &= reduce_mask_26; - out[1] = in[1] + c; c = (out[1] >> 25); out[1] &= reduce_mask_25; - out[2] = in[2] + c; c = (out[2] >> 26); out[2] &= reduce_mask_26; - out[3] = in[3] + c; c = (out[3] >> 25); out[3] &= reduce_mask_25; - out[4] = in[4] + c; c = (out[4] >> 26); out[4] &= reduce_mask_26; - out[5] = in[5] + c; c = (out[5] >> 25); out[5] &= reduce_mask_25; - out[6] = in[6] + c; c = (out[6] >> 26); out[6] &= reduce_mask_26; - out[7] = in[7] + c; c = (out[7] >> 25); out[7] &= reduce_mask_25; - out[8] = in[8] + c; c = (out[8] >> 26); out[8] &= reduce_mask_26; - out[9] = in[9] + c; c = (out[9] >> 25); out[9] &= reduce_mask_25; - out[0] += 19 * c; -} - -static void curve25519_divpowm1(bignum25519 r, const bignum25519 u, const bignum25519 v) { - bignum25519 v3={0}, uv7={0}, t0={0}, t1={0}, t2={0}; - int i; - - curve25519_square(v3, v); - curve25519_mul(v3, v3, v); /* v3 = v^3 */ - curve25519_square(uv7, v3); - curve25519_mul(uv7, uv7, v); - curve25519_mul(uv7, uv7, u); /* uv7 = uv^7 */ - - /*fe_pow22523(uv7, uv7);*/ - /* From fe_pow22523.c */ - - curve25519_square(t0, uv7); - curve25519_square(t1, t0); - curve25519_square(t1, t1); - curve25519_mul(t1, uv7, t1); - curve25519_mul(t0, t0, t1); - curve25519_square(t0, t0); - curve25519_mul(t0, t1, t0); - curve25519_square(t1, t0); - for (i = 0; i < 4; ++i) { - curve25519_square(t1, t1); - } - curve25519_mul(t0, t1, t0); - curve25519_square(t1, t0); - for (i = 0; i < 9; ++i) { - curve25519_square(t1, t1); - } - curve25519_mul(t1, t1, t0); - curve25519_square(t2, t1); - for (i = 0; i < 19; ++i) { - curve25519_square(t2, t2); - } - curve25519_mul(t1, t2, t1); - for (i = 0; i < 10; ++i) { - curve25519_square(t1, t1); - } - curve25519_mul(t0, t1, t0); - curve25519_square(t1, t0); - for (i = 0; i < 49; ++i) { - curve25519_square(t1, t1); - } - curve25519_mul(t1, t1, t0); - curve25519_square(t2, t1); - for (i = 0; i < 99; ++i) { - curve25519_square(t2, t2); - } - curve25519_mul(t1, t2, t1); - for (i = 0; i < 50; ++i) { - curve25519_square(t1, t1); - } - curve25519_mul(t0, t1, t0); - curve25519_square(t0, t0); - curve25519_square(t0, t0); - curve25519_mul(t0, t0, uv7); - - /* End fe_pow22523.c */ - /* t0 = (uv^7)^((q-5)/8) */ - curve25519_mul(t0, t0, v3); - curve25519_mul(r, t0, u); /* u^(m+1)v^(-(m+1)) */ -} - -void curve25519_expand_reduce(bignum25519 out, const unsigned char in[32]) { - uint32_t x0,x1,x2,x3,x4,x5,x6,x7; -#define F(s) \ - ((((uint32_t)in[s + 0]) ) | \ - (((uint32_t)in[s + 1]) << 8) | \ - (((uint32_t)in[s + 2]) << 16) | \ - (((uint32_t)in[s + 3]) << 24)) - x0 = F(0); - x1 = F(4); - x2 = F(8); - x3 = F(12); - x4 = F(16); - x5 = F(20); - x6 = F(24); - x7 = F(28); -#undef F - - out[0] = ( x0 ) & reduce_mask_26; - out[1] = ((((uint64_t)x1 << 32) | x0) >> 26) & reduce_mask_25; - out[2] = ((((uint64_t)x2 << 32) | x1) >> 19) & reduce_mask_26; - out[3] = ((((uint64_t)x3 << 32) | x2) >> 13) & reduce_mask_25; - out[4] = (( x3) >> 6) & reduce_mask_26; - out[5] = ( x4 ) & reduce_mask_25; - out[6] = ((((uint64_t)x5 << 32) | x4) >> 25) & reduce_mask_26; - out[7] = ((((uint64_t)x6 << 32) | x5) >> 19) & reduce_mask_25; - out[8] = ((((uint64_t)x7 << 32) | x6) >> 12) & reduce_mask_26; - out[9] = (( x7) >> 6); // & reduce_mask_25; /* ignore the top bit */ - out[0] += 19 * (out[9] >> 25); - out[9] &= reduce_mask_25; -} - -int ge25519_check(const ge25519 *r){ - /* return (z % q != 0 and - x * y % q == z * t % q and - (y * y - x * x - z * z - ed25519.d * t * t) % q == 0) - */ - - bignum25519 z={0}, lhs={0}, rhs={0}, tmp={0}, res={0}; - curve25519_reduce(z, r->z); - - curve25519_mul(lhs, r->x, r->y); - curve25519_mul(rhs, r->z, r->t); - curve25519_sub_reduce(lhs, lhs, rhs); - - curve25519_square(res, r->y); - curve25519_square(tmp, r->x); - curve25519_sub_reduce(res, res, tmp); - curve25519_square(tmp, r->z); - curve25519_sub_reduce(res, res, tmp); - curve25519_square(tmp, r->t); - curve25519_mul(tmp, tmp, ge25519_ecd); - curve25519_sub_reduce(res, res, tmp); - - const int c1 = curve25519_isnonzero(z); - const int c2 = curve25519_isnonzero(lhs); - const int c3 = curve25519_isnonzero(res); - return c1 & (c2^0x1) & (c3^0x1); -} - -int ge25519_eq(const ge25519 *a, const ge25519 *b){ - int eq = 1; - bignum25519 t1={0}, t2={0}; - - eq &= ge25519_check(a); - eq &= ge25519_check(b); - - curve25519_mul(t1, a->x, b->z); - curve25519_mul(t2, b->x, a->z); - curve25519_sub_reduce(t1, t1, t2); - eq &= curve25519_isnonzero(t1) ^ 1; - - curve25519_mul(t1, a->y, b->z); - curve25519_mul(t2, b->y, a->z); - curve25519_sub_reduce(t1, t1, t2); - eq &= curve25519_isnonzero(t1) ^ 1; - - return eq; -} - -void ge25519_copy(ge25519 *dst, const ge25519 *src){ - curve25519_copy(dst->x, src->x); - curve25519_copy(dst->y, src->y); - curve25519_copy(dst->z, src->z); - curve25519_copy(dst->t, src->t); -} - -void ge25519_set_base(ge25519 *r){ - ge25519_copy(r, &ge25519_basepoint); -} - -void ge25519_mul8(ge25519 *r, const ge25519 *t) { - ge25519_double_partial(r, t); - ge25519_double_partial(r, r); - ge25519_double(r, r); -} - -void ge25519_neg_partial(ge25519 *r){ - curve25519_neg(r->x, r->x); -} - -void ge25519_neg_full(ge25519 *r){ - curve25519_neg(r->x, r->x); - curve25519_neg(r->t, r->t); -} - -void ge25519_reduce(ge25519 *r, const ge25519 *t){ - curve25519_reduce(r->x, t->x); - curve25519_reduce(r->y, t->y); - curve25519_reduce(r->z, t->z); - curve25519_reduce(r->t, t->t); -} - -void ge25519_norm(ge25519 *r, const ge25519 * t){ - bignum25519 zinv; - curve25519_recip(zinv, t->z); - curve25519_mul(r->x, t->x, zinv); - curve25519_mul(r->y, t->y, zinv); - curve25519_mul(r->t, r->x, r->y); - curve25519_set(r->z, 1); -} - -void ge25519_add(ge25519 *r, const ge25519 *p, const ge25519 *q, unsigned char signbit) { - ge25519_pniels P_ni; - ge25519_p1p1 P_11; - - ge25519_full_to_pniels(&P_ni, q); - ge25519_pnielsadd_p1p1(&P_11, p, &P_ni, signbit); - ge25519_p1p1_to_full(r, &P_11); -} - -void ge25519_fromfe_frombytes_vartime(ge25519 *r, const unsigned char *s){ - bignum25519 u={0}, v={0}, w={0}, x={0}, y={0}, z={0}; - unsigned char sign; - - curve25519_expand_reduce(u, s); - - curve25519_square(v, u); - curve25519_add_reduce(v, v, v); /* 2 * u^2 */ - curve25519_set(w, 1); - curve25519_add_reduce(w, v, w); /* w = 2 * u^2 + 1 */ - - curve25519_square(x, w); /* w^2 */ - curve25519_mul(y, fe_ma2, v); /* -2 * A^2 * u^2 */ - curve25519_add_reduce(x, x, y); /* x = w^2 - 2 * A^2 * u^2 */ - - curve25519_divpowm1(r->x, w, x); /* (w / x)^(m + 1) */ - curve25519_square(y, r->x); - curve25519_mul(x, y, x); - curve25519_sub_reduce(y, w, x); - curve25519_copy(z, fe_ma); - - if (curve25519_isnonzero(y)) { - curve25519_add_reduce(y, w, x); - if (curve25519_isnonzero(y)) { - goto negative; - } else { - curve25519_mul(r->x, r->x, fe_fffb1); - } - } else { - curve25519_mul(r->x, r->x, fe_fffb2); - } - curve25519_mul(r->x, r->x, u); /* u * sqrt(2 * A * (A + 2) * w / x) */ - curve25519_mul(z, z, v); /* -2 * A * u^2 */ - sign = 0; - goto setsign; -negative: - curve25519_mul(x, x, fe_sqrtm1); - curve25519_sub_reduce(y, w, x); - if (curve25519_isnonzero(y)) { - assert((curve25519_add_reduce(y, w, x), !curve25519_isnonzero(y))); - curve25519_mul(r->x, r->x, fe_fffb3); - } else { - curve25519_mul(r->x, r->x, fe_fffb4); - } - /* r->x = sqrt(A * (A + 2) * w / x) */ - /* z = -A */ - sign = 1; -setsign: - if (curve25519_isnegative(r->x) != sign) { - assert(curve25519_isnonzero(r->x)); - curve25519_neg(r->x, r->x); - } - curve25519_add_reduce(r->z, z, w); - curve25519_sub_reduce(r->y, z, w); - curve25519_mul(r->x, r->x, r->z); - - // Partial form, saving from T coord computation . - // Later is mul8 discarding T anyway. - // rt = ((rx * ry % q) * inv(rz)) % q - // curve25519_mul(x, r->x, r->y); - // curve25519_recip(z, r->z); - // curve25519_mul(r->t, x, z); - -#if !defined(NDEBUG) - { - bignum25519 check_x={0}, check_y={0}, check_iz={0}, check_v={0}; - curve25519_recip(check_iz, r->z); - curve25519_mul(check_x, r->x, check_iz); - curve25519_mul(check_y, r->y, check_iz); - curve25519_square(check_x, check_x); - curve25519_square(check_y, check_y); - curve25519_mul(check_v, check_x, check_y); - curve25519_mul(check_v, fe_d, check_v); - curve25519_add_reduce(check_v, check_v, check_x); - curve25519_sub_reduce(check_v, check_v, check_y); - curve25519_set(check_x, 1); - curve25519_add_reduce(check_v, check_v, check_x); - assert(!curve25519_isnonzero(check_v)); - } -#endif -} - -int ge25519_unpack_vartime(ge25519 *r, const unsigned char *s){ - int res = ge25519_unpack_negative_vartime(r, s); - ge25519_neg_full(r); - return res; -} - -void ge25519_scalarmult_base_wrapper(ge25519 *r, const bignum256modm s){ - ge25519_scalarmult_base_niels(r, ge25519_niels_base_multiples, s); -} diff --git a/ed25519-donna/ge25519.h b/ed25519-donna/ge25519.h deleted file mode 100644 index f94fe6236..000000000 --- a/ed25519-donna/ge25519.h +++ /dev/null @@ -1,74 +0,0 @@ -// -// Created by Dusan Klinec on 29/04/2018. -// - -#ifndef GE25519_H -#define GE25519_H - -#include -#include "ed25519-donna.h" - -/* uint32_t to Zmod(2^255-19) */ -void curve25519_set(bignum25519 r, uint32_t x); - -/* set d */ -void curve25519_set_d(bignum25519 r); - -/* set 2d */ -void curve25519_set_2d(bignum25519 r); - -/* set sqrt(-1) */ -void curve25519_set_sqrtneg1(bignum25519 r); - -/* constant time Zmod(2^255-19) negative test */ -int curve25519_isnegative(const bignum25519 f); - -/* constant time Zmod(2^255-19) non-zero test */ -int curve25519_isnonzero(const bignum25519 f); - -/* reduce Zmod(2^255-19) */ -void curve25519_reduce(bignum25519 r, const bignum25519 in); - -/* Zmod(2^255-19) from byte array to bignum25519 expansion with modular reduction */ -void curve25519_expand_reduce(bignum25519 out, const unsigned char in[32]); - -/* check if r is on curve */ -int ge25519_check(const ge25519 *r); - -/* a == b */ -int ge25519_eq(const ge25519 *a, const ge25519 *b); - -/* copies one point to another */ -void ge25519_copy(ge25519 *dst, const ge25519 *src); - -/* sets B point to r */ -void ge25519_set_base(ge25519 *r); - -/* 8*P */ -void ge25519_mul8(ge25519 *r, const ge25519 *t); - -/* -P */ -void ge25519_neg_partial(ge25519 *r); - -/* -P */ -void ge25519_neg_full(ge25519 *r); - -/* reduce all coords */ -void ge25519_reduce(ge25519 *r, const ge25519 *t); - -/* normalizes coords. (x, y, 1, x*y) */ -void ge25519_norm(ge25519 *r, const ge25519 * t); - -/* Simple addition */ -void ge25519_add(ge25519 *r, const ge25519 *a, const ge25519 *b, unsigned char signbit); - -/* point from bytes, used in H_p() */ -void ge25519_fromfe_frombytes_vartime(ge25519 *r, const unsigned char *s); - -/* point from bytes */ -int ge25519_unpack_vartime(ge25519 *r, const unsigned char *s); - -/* aG, wrapper for niels base mult. */ -void ge25519_scalarmult_base_wrapper(ge25519 *r, const bignum256modm s); - -#endif diff --git a/monero/xmr.h b/monero/xmr.h index 4e37da9a1..83cdf83b4 100644 --- a/monero/xmr.h +++ b/monero/xmr.h @@ -5,7 +5,7 @@ #ifndef TREZOR_CRYPTO_XMR_H #define TREZOR_CRYPTO_XMR_H -#include +#include "ed25519-donna/ed25519-donna.h" #include "hasher.h" extern const ge25519 ALIGN(16) xmr_h; diff --git a/tests/test_check.c b/tests/test_check.c index c609eb080..d3a552333 100644 --- a/tests/test_check.c +++ b/tests/test_check.c @@ -58,7 +58,6 @@ #include "ed25519-donna/ed25519.h" #include "ed25519-donna/ed25519-donna.h" #include "ed25519-donna/ed25519-keccak.h" -#include "ed25519-donna/ge25519.h" #include "script.h" #include "rfc6979.h" #include "address.h" From d2bc03fb59f399e039f5232a6152cc6005925e7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Du=C5=A1an=20Plav=C3=A1k?= Date: Wed, 5 Sep 2018 11:08:36 +0100 Subject: [PATCH 591/627] replace cardano with v2 (#179) --- bip32.c | 162 +++++++++----------------- bip32.h | 2 +- bip39.c | 2 +- pbkdf2.c | 61 +++++++--- pbkdf2.h | 8 +- tests/test_check.c | 18 +-- tests/test_check_cardano.h | 233 ++++++++++++++++++------------------- 7 files changed, 231 insertions(+), 255 deletions(-) diff --git a/bip32.c b/bip32.c index 7a510f3b1..50f1466dd 100644 --- a/bip32.c +++ b/bip32.c @@ -49,6 +49,7 @@ #include "ed25519-donna/modm-donna-32bit.h" #include "blake2b.h" #include "bip39.h" +#include "pbkdf2.h" #endif #include "memzero.h" @@ -262,49 +263,56 @@ int hdnode_private_ckd(HDNode *inout, uint32_t i) } #if USE_CARDANO +/* sk1 is zl8 and contains only 29 bytes of active data, + * so it's not going to overflow when adding to sk2 */ +void scalar_add_no_overflow(const uint8_t * sk1, const uint8_t * sk2, uint8_t * res) +{ + uint16_t r = 0; int i; + for (i = 0; i < 32; i++) { + r = (uint16_t) sk1[i] + (uint16_t) sk2[i] + r; + res[i] = (uint8_t) r; + r >>= 8; + } +} + static void multiply8(uint8_t *dst, uint8_t *src, int bytes) { + int i; uint8_t prev_acc = 0; - for (int i = 0; i < bytes; i++) { - dst[i] = (src[i] << 3) + (prev_acc & 0x8); + for (i = 0; i < bytes; i++) { + dst[i] = (src[i] << 3) + (prev_acc & 0x7); prev_acc = src[i] >> 5; } + dst[bytes] = src[bytes-1] >> 5; } static void add_256bits(uint8_t *dst, uint8_t *src1, uint8_t *src2) { - for (int i = 0; i < 32; i++) { + int i; uint8_t carry = 0; + for (i = 0; i < 32; i++) { uint8_t a = src1[i]; uint8_t b = src2[i]; - uint16_t r = a + b; + uint16_t r = (uint16_t) a + (uint16_t) b + (uint16_t) carry; dst[i] = r & 0xff; + carry = (r >= 0x100) ? 1 : 0; } } -static int ed25519_scalar_add(const uint8_t *sk1, const uint8_t *sk2, uint8_t *res) -{ - bignum256modm s1, s2; - expand256_modm(s1, sk1, 32); - expand256_modm(s2, sk2, 32); - add256_modm(s1, s1, s2); - contract256_modm(res, s1); - return 0; -} - -int hdnode_private_ckd_cardano(HDNode *inout, uint32_t i) +int hdnode_private_ckd_cardano(HDNode *inout, uint32_t index) { // checks for hardened/non-hardened derivation, keysize 32 means we are dealing with public key and thus non-h, keysize 64 is for private key int keysize = 32; - if (i & 0x80000000) { + if (index & 0x80000000) { keysize = 64; } static CONFIDENTIAL uint8_t data[1 + 64 + 4]; - static CONFIDENTIAL uint8_t I[32 + 32]; - static CONFIDENTIAL bignum256 a, b; + static CONFIDENTIAL uint8_t z[32 + 32]; static CONFIDENTIAL uint8_t priv_key[64]; static CONFIDENTIAL uint8_t res_key[64]; + write_le(data + keysize + 1, index); + memcpy(priv_key, inout->private_key, 32); memcpy(priv_key + 32, inout->private_key_extension, 32); @@ -317,19 +325,23 @@ int hdnode_private_ckd_cardano(HDNode *inout, uint32_t i) data[0] = 2; memcpy(data + 1, inout->public_key + 1, 32); } - write_be(data + keysize + 1, i); - - bn_read_be(priv_key, &a); static CONFIDENTIAL HMAC_SHA512_CTX ctx; hmac_sha512_Init(&ctx, inout->chain_code, 32); hmac_sha512_Update(&ctx, data, 1 + keysize + 4); - hmac_sha512_Final(&ctx, I); + hmac_sha512_Final(&ctx, z); static CONFIDENTIAL uint8_t zl8[32]; - multiply8(zl8,I,32); - ed25519_scalar_add(zl8,priv_key,res_key); - add_256bits(res_key+32,I+32,priv_key+32); + memset(zl8, 0, 32); + + /* get 8 * Zl */ + multiply8(zl8, z, 28); + /* Kl = 8*Zl + parent(K)l */ + scalar_add_no_overflow(zl8, priv_key, res_key); + + /* Kr = Zr + parent(K)r */ + add_256bits(res_key + 32, z+32, priv_key+32); + memcpy(inout->private_key, res_key, 32); memcpy(inout->private_key_extension, res_key + 32, 32); @@ -340,112 +352,42 @@ int hdnode_private_ckd_cardano(HDNode *inout, uint32_t i) } hmac_sha512_Init(&ctx, inout->chain_code, 32); hmac_sha512_Update(&ctx, data, 1 + keysize + 4); - hmac_sha512_Final(&ctx, I); + hmac_sha512_Final(&ctx, z); - memcpy(inout->chain_code, I + 32, 32); + memcpy(inout->chain_code, z + 32, 32); inout->depth++; - inout->child_num = i; + inout->child_num = index; memzero(inout->public_key, sizeof(inout->public_key)); // making sure to wipe our memory - memzero(&a, sizeof(a)); - memzero(&b, sizeof(b)); - memzero(I, sizeof(I)); + memzero(z, sizeof(z)); memzero(data, sizeof(data)); memzero(priv_key, sizeof(priv_key)); memzero(res_key, sizeof(res_key)); return 1; } -int hdnode_from_seed_cardano(uint8_t *seed, int seed_len, HDNode *out) { - uint8_t hash[32]; - uint8_t cbor[32+2]; +int hdnode_from_seed_cardano(uint8_t *pass, int pass_len, uint8_t *seed, int seed_len, HDNode *out) { + uint8_t secret[96]; + pbkdf2_hmac_sha512(pass, pass_len, seed, seed_len, 4096, secret, 96); + + secret[0] &= 248; + secret[31] &= 31; + secret[31] |= 64; - if (seed_len < 24) { - // cbor encodes length directly into first byte if its smaller than 24 - seed[1] = 64 | seed_len; - blake2b(seed + 1, seed_len + 1, hash, 32); - } else { - seed[0] = 88; - seed[1] = seed_len; - blake2b(seed, seed_len + 2, hash, 32); - } - - cbor[0] = 88; // 64 means its byte array, 24 means its length has 8 bits - cbor[1] = 32; // length of the byte array - memcpy(cbor + 2, hash, 32); - uint8_t salt[21]; - memcpy(salt, "Root Seed Chain ", 16); - uint8_t hmac[64]; - uint8_t secret[64]; - uint8_t public[32]; - uint8_t chain_code[32]; - int failed = 1; memset(out, 0, sizeof(HDNode)); out->depth = 0; out->child_num = 0; out->curve = get_curve_by_name(ED25519_CARDANO_NAME); - int saltlen; - static CONFIDENTIAL HMAC_SHA512_CTX ctx; - for (int i = 1; i <= 1000; i++){ - hmac_sha512_Init(&ctx, cbor, 34); - if (i < 10) { - salt[16] = '0' + (i); - saltlen = 16 + 1; - } else if (i < 100) { - salt[16] = '0' + (i / 10); - salt[17] = '0' + (i % 10); - saltlen = 16 + 2; - } else if (i < 1000) { - salt[16] = '0' + (i / 100); - salt[17] = '0' + ((i / 10) % 10); - salt[18] = '0' + (i % 10); - saltlen = 16 + 3; - } else { - salt[16] = '0' + (i / 1000); - salt[17] = '0' + ((i / 100) % 10); - salt[18] = '0' + ((i / 10) % 10); - salt[19] = '0' + (i % 10); - saltlen = 16 + 4; - } - hmac_sha512_Update(&ctx, salt, saltlen); - hmac_sha512_Final(&ctx, hmac); - ed25519_publickey(hmac, public); - sha512_Raw(hmac, 32, secret); - secret[0] &= 248; - secret[31] &= 127; - secret[31] |= 64; - if (secret[31] & 0x20) { - continue; - } - memcpy(chain_code, hmac + 32, 32); - failed = 0; - break; - } - - memzero(hash, sizeof(hash)); - memzero(cbor, sizeof(cbor)); - memzero(salt, sizeof(salt)); - - if (failed) { - memzero(seed, sizeof(seed)); - memzero(secret, sizeof(secret)); - memzero(chain_code, sizeof(chain_code)); - memzero(hmac, sizeof(hmac)); - return 0; - } - memcpy(out->private_key, secret, 32); memcpy(out->private_key_extension, secret + 32, 32); - memcpy(out->chain_code, chain_code, 32); - out->public_key[0] = 1; - memcpy(out->public_key + 1, public, 32); - memzero(seed, sizeof(seed)); + out->public_key[0] = 0; + hdnode_fill_public_key(out); + + memcpy(out->chain_code, secret + 64, 32); memzero(secret, sizeof(secret)); - memzero(chain_code, sizeof(chain_code)); - memzero(hmac, sizeof(hmac)); return 1; } diff --git a/bip32.h b/bip32.h index f633c532a..2c2f799ae 100644 --- a/bip32.h +++ b/bip32.h @@ -63,7 +63,7 @@ int hdnode_from_seed(const uint8_t *seed, int seed_len, const char *curve, HDNod int hdnode_private_ckd(HDNode *inout, uint32_t i); #if USE_CARDANO int hdnode_private_ckd_cardano(HDNode *inout, uint32_t i); -int hdnode_from_seed_cardano(uint8_t *seed, int seed_len, HDNode *out); +int hdnode_from_seed_cardano(uint8_t *pass, int pass_len, uint8_t *seed, int seed_len, HDNode *out); #endif int hdnode_public_ckd_cp(const ecdsa_curve *curve, const curve_point *parent, const uint8_t *parent_chain_code, uint32_t i, curve_point *child, uint8_t *child_chain_code); diff --git a/bip39.c b/bip39.c index ac4e4fb36..8608fd456 100644 --- a/bip39.c +++ b/bip39.c @@ -243,7 +243,7 @@ void mnemonic_to_seed(const char *mnemonic, const char *passphrase, uint8_t seed memcpy(salt, "mnemonic", 8); memcpy(salt + 8, passphrase, passphraselen); static CONFIDENTIAL PBKDF2_HMAC_SHA512_CTX pctx; - pbkdf2_hmac_sha512_Init(&pctx, (const uint8_t *)mnemonic, strlen(mnemonic), salt, passphraselen + 8); + pbkdf2_hmac_sha512_Init(&pctx, (const uint8_t *)mnemonic, strlen(mnemonic), salt, passphraselen + 8, 1); if (progress_callback) { progress_callback(0, BIP39_PBKDF2_ROUNDS); } diff --git a/pbkdf2.c b/pbkdf2.c index e6dbd008b..04c11e8af 100644 --- a/pbkdf2.c +++ b/pbkdf2.c @@ -27,10 +27,11 @@ #include "sha2.h" #include "memzero.h" -void pbkdf2_hmac_sha256_Init(PBKDF2_HMAC_SHA256_CTX *pctx, const uint8_t *pass, int passlen, const uint8_t *salt, int saltlen) +#define CEILING_POS(X) ((X-(uint32_t)(X)) > 0 ? (uint32_t)(X+1) : (uint32_t)(X)) + +void pbkdf2_hmac_sha256_Init(PBKDF2_HMAC_SHA256_CTX *pctx, const uint8_t *pass, int passlen, const uint8_t *salt, int saltlen, uint32_t blocknr) { SHA256_CTX ctx; - uint32_t blocknr = 1; #if BYTE_ORDER == LITTLE_ENDIAN REVERSE32(blocknr, blocknr); #endif @@ -78,18 +79,34 @@ void pbkdf2_hmac_sha256_Final(PBKDF2_HMAC_SHA256_CTX *pctx, uint8_t *key) memzero(pctx, sizeof(PBKDF2_HMAC_SHA256_CTX)); } -void pbkdf2_hmac_sha256(const uint8_t *pass, int passlen, const uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key) +void pbkdf2_hmac_sha256(const uint8_t *pass, int passlen, const uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key, int keylen) { - PBKDF2_HMAC_SHA256_CTX pctx; - pbkdf2_hmac_sha256_Init(&pctx, pass, passlen, salt, saltlen); - pbkdf2_hmac_sha256_Update(&pctx, iterations); - pbkdf2_hmac_sha256_Final(&pctx, key); + uint32_t blocks_count = (uint32_t) CEILING_POS((float) keylen / SHA256_DIGEST_LENGTH); + + int unfinished_key_size = keylen; + for (uint32_t blocknr = 1; blocknr <= blocks_count; blocknr++) { + PBKDF2_HMAC_SHA256_CTX pctx; + pbkdf2_hmac_sha256_Init(&pctx, pass, passlen, salt, saltlen, blocknr); + pbkdf2_hmac_sha256_Update(&pctx, iterations); + + unsigned int key_offset = (blocknr - 1) * SHA256_DIGEST_LENGTH; + uint8_t diggest[SHA256_DIGEST_LENGTH]; + + pbkdf2_hmac_sha256_Final(&pctx, diggest); + + if (unfinished_key_size > SHA256_DIGEST_LENGTH) { + memcpy(key + key_offset, diggest, SHA256_DIGEST_LENGTH); + unfinished_key_size -= SHA256_DIGEST_LENGTH; + } else { + memcpy(key + key_offset, diggest, unfinished_key_size); + unfinished_key_size = 0; + } + } } -void pbkdf2_hmac_sha512_Init(PBKDF2_HMAC_SHA512_CTX *pctx, const uint8_t *pass, int passlen, const uint8_t *salt, int saltlen) +void pbkdf2_hmac_sha512_Init(PBKDF2_HMAC_SHA512_CTX *pctx, const uint8_t *pass, int passlen, const uint8_t *salt, int saltlen, uint32_t blocknr) { SHA512_CTX ctx; - uint32_t blocknr = 1; #if BYTE_ORDER == LITTLE_ENDIAN REVERSE32(blocknr, blocknr); #endif @@ -138,10 +155,26 @@ void pbkdf2_hmac_sha512_Final(PBKDF2_HMAC_SHA512_CTX *pctx, uint8_t *key) memzero(pctx, sizeof(PBKDF2_HMAC_SHA512_CTX)); } -void pbkdf2_hmac_sha512(const uint8_t *pass, int passlen, const uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key) +void pbkdf2_hmac_sha512(const uint8_t *pass, int passlen, const uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key, int keylen) { - PBKDF2_HMAC_SHA512_CTX pctx; - pbkdf2_hmac_sha512_Init(&pctx, pass, passlen, salt, saltlen); - pbkdf2_hmac_sha512_Update(&pctx, iterations); - pbkdf2_hmac_sha512_Final(&pctx, key); + uint32_t blocks_count = (uint32_t) CEILING_POS((float) keylen / SHA512_DIGEST_LENGTH); + + int unfinished_key_size = keylen; + for (uint32_t blocknr = 1; blocknr <= blocks_count; blocknr++) { + PBKDF2_HMAC_SHA512_CTX pctx; + pbkdf2_hmac_sha512_Init(&pctx, pass, passlen, salt, saltlen, blocknr); + pbkdf2_hmac_sha512_Update(&pctx, iterations); + + unsigned int key_offset = (blocknr - 1) * SHA512_DIGEST_LENGTH; + uint8_t diggest[SHA512_DIGEST_LENGTH]; + pbkdf2_hmac_sha512_Final(&pctx, diggest); + + if (unfinished_key_size > SHA512_DIGEST_LENGTH) { + memcpy(key + key_offset, diggest, SHA512_DIGEST_LENGTH); + unfinished_key_size -= SHA512_DIGEST_LENGTH; + } else { + memcpy(key + key_offset, diggest, unfinished_key_size); + unfinished_key_size = 0; + } + } } diff --git a/pbkdf2.h b/pbkdf2.h index e77f29187..e3f440c8f 100644 --- a/pbkdf2.h +++ b/pbkdf2.h @@ -43,14 +43,14 @@ typedef struct _PBKDF2_HMAC_SHA512_CTX { char first; } PBKDF2_HMAC_SHA512_CTX; -void pbkdf2_hmac_sha256_Init(PBKDF2_HMAC_SHA256_CTX *pctx, const uint8_t *pass, int passlen, const uint8_t *salt, int saltlen); +void pbkdf2_hmac_sha256_Init(PBKDF2_HMAC_SHA256_CTX *pctx, const uint8_t *pass, int passlen, const uint8_t *salt, int saltlen, uint32_t blocknr); void pbkdf2_hmac_sha256_Update(PBKDF2_HMAC_SHA256_CTX *pctx, uint32_t iterations); void pbkdf2_hmac_sha256_Final(PBKDF2_HMAC_SHA256_CTX *pctx, uint8_t *key); -void pbkdf2_hmac_sha256(const uint8_t *pass, int passlen, const uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key); +void pbkdf2_hmac_sha256(const uint8_t *pass, int passlen, const uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key, int keylen); -void pbkdf2_hmac_sha512_Init(PBKDF2_HMAC_SHA512_CTX *pctx, const uint8_t *pass, int passlen, const uint8_t *salt, int saltlen); +void pbkdf2_hmac_sha512_Init(PBKDF2_HMAC_SHA512_CTX *pctx, const uint8_t *pass, int passlen, const uint8_t *salt, int saltlen, uint32_t blocknr); void pbkdf2_hmac_sha512_Update(PBKDF2_HMAC_SHA512_CTX *pctx, uint32_t iterations); void pbkdf2_hmac_sha512_Final(PBKDF2_HMAC_SHA512_CTX *pctx, uint8_t *key); -void pbkdf2_hmac_sha512(const uint8_t *pass, int passlen, const uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key); +void pbkdf2_hmac_sha512(const uint8_t *pass, int passlen, const uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key, int keylen); #endif diff --git a/tests/test_check.c b/tests/test_check.c index d3a552333..6c6564564 100644 --- a/tests/test_check.c +++ b/tests/test_check.c @@ -2586,19 +2586,19 @@ START_TEST(test_pbkdf2_hmac_sha256) uint8_t k[40], s[40]; strcpy((char *)s, "salt"); - pbkdf2_hmac_sha256((uint8_t *)"password", 8, s, 4, 1, k); + pbkdf2_hmac_sha256((uint8_t *)"password", 8, s, 4, 1, k, 32); ck_assert_mem_eq(k, fromhex("120fb6cffcf8b32c43e7225256c4f837a86548c92ccc35480805987cb70be17b"), 32); strcpy((char *)s, "salt"); - pbkdf2_hmac_sha256((uint8_t *)"password", 8, s, 4, 2, k); + pbkdf2_hmac_sha256((uint8_t *)"password", 8, s, 4, 2, k, 32); ck_assert_mem_eq(k, fromhex("ae4d0c95af6b46d32d0adff928f06dd02a303f8ef3c251dfd6e2d85a95474c43"), 32); strcpy((char *)s, "salt"); - pbkdf2_hmac_sha256((uint8_t *)"password", 8, s, 4, 4096, k); + pbkdf2_hmac_sha256((uint8_t *)"password", 8, s, 4, 4096, k, 32); ck_assert_mem_eq(k, fromhex("c5e478d59288c841aa530db6845c4c8d962893a001ce4e11a4963873aa98134a"), 32); strcpy((char *)s, "saltSALTsaltSALTsaltSALTsaltSALTsalt"); - pbkdf2_hmac_sha256((uint8_t *)"passwordPASSWORDpassword", 3*8, s, 9*4, 4096, k); + pbkdf2_hmac_sha256((uint8_t *)"passwordPASSWORDpassword", 3*8, s, 9*4, 4096, k, 32); ck_assert_mem_eq(k, fromhex("348c89dbcbd32b2f32d814b8116e84cf2b17347ebc1800181c4e2a1fb8dd53e1"), 32); } END_TEST @@ -2609,19 +2609,19 @@ START_TEST(test_pbkdf2_hmac_sha512) uint8_t k[64], s[40]; strcpy((char *)s, "salt"); - pbkdf2_hmac_sha512((uint8_t *)"password", 8, s, 4, 1, k); + pbkdf2_hmac_sha512((uint8_t *)"password", 8, s, 4, 1, k, 64); ck_assert_mem_eq(k, fromhex("867f70cf1ade02cff3752599a3a53dc4af34c7a669815ae5d513554e1c8cf252c02d470a285a0501bad999bfe943c08f050235d7d68b1da55e63f73b60a57fce"), 64); strcpy((char *)s, "salt"); - pbkdf2_hmac_sha512((uint8_t *)"password", 8, s, 4, 2, k); + pbkdf2_hmac_sha512((uint8_t *)"password", 8, s, 4, 2, k, 64); ck_assert_mem_eq(k, fromhex("e1d9c16aa681708a45f5c7c4e215ceb66e011a2e9f0040713f18aefdb866d53cf76cab2868a39b9f7840edce4fef5a82be67335c77a6068e04112754f27ccf4e"), 64); strcpy((char *)s, "salt"); - pbkdf2_hmac_sha512((uint8_t *)"password", 8, s, 4, 4096, k); + pbkdf2_hmac_sha512((uint8_t *)"password", 8, s, 4, 4096, k, 64); ck_assert_mem_eq(k, fromhex("d197b1b33db0143e018b12f3d1d1479e6cdebdcc97c5c0f87f6902e072f457b5143f30602641b3d55cd335988cb36b84376060ecd532e039b742a239434af2d5"), 64); strcpy((char *)s, "saltSALTsaltSALTsaltSALTsaltSALTsalt"); - pbkdf2_hmac_sha512((uint8_t *)"passwordPASSWORDpassword", 3*8, s, 9*4, 4096, k); + pbkdf2_hmac_sha512((uint8_t *)"passwordPASSWORDpassword", 3*8, s, 9*4, 4096, k, 64); ck_assert_mem_eq(k, fromhex("8c0511f4c6e597c6ac6315d8f0362e225f3c501495ba23b868c005174dc4ee71115b59f9e60cd9532fa33e0f75aefe30225c583a186cd82bd4daea9724a3d3b8"), 64); } END_TEST @@ -5063,6 +5063,7 @@ Suite *test_suite(void) #if USE_CARDANO tc = tcase_create("bip32-cardano"); + tcase_add_test(tc, test_bip32_cardano_hdnode_vector_1); tcase_add_test(tc, test_bip32_cardano_hdnode_vector_2); tcase_add_test(tc, test_bip32_cardano_hdnode_vector_3); @@ -5070,6 +5071,7 @@ Suite *test_suite(void) tcase_add_test(tc, test_bip32_cardano_hdnode_vector_5); tcase_add_test(tc, test_bip32_cardano_hdnode_vector_6); tcase_add_test(tc, test_bip32_cardano_hdnode_vector_7); + tcase_add_test(tc, test_ed25519_cardano_sign_vectors); suite_add_tcase(s,tc); #endif diff --git a/tests/test_check_cardano.h b/tests/test_check_cardano.h index 58f87b989..8c1f5be2a 100644 --- a/tests/test_check_cardano.h +++ b/tests/test_check_cardano.h @@ -1,18 +1,92 @@ // https://github.com/input-output-hk/cardano-crypto/blob/master/tests/goldens/cardano/crypto/wallet/BIP39-128 +START_TEST(test_ed25519_cardano_sign_vectors) +{ + ed25519_public_key public_key; + ed25519_secret_key secret_key; + ed25519_secret_key secret_key_extension; + ed25519_signature signature; + + static const char *vectors[] = { + "6065a956b1b34145c4416fdc3ba3276801850e91a77a31a7be782463288aea53", // private key + "60ba6e25b1a02157fb69c5d1d7b96c4619736e545447069a6a6f0ba90844bc8e", // private key extension + "64b20fa082b3143d6b5eed42c6ef63f99599d0888afe060620abc1b319935fe1", // public key + "45b1a75fe3119e13c6f60ab9ba674b42f946fdc558e07c83dfa0751c2eba69c79331bd8a4a975662b23628a438a0eba76367e44c12ca91b39ec59063f860f10d", // signature + + "e7d27516538403a53a8b041656a3f570909df641a0ab811fe7d87c9ba02a830c", // private key + "794a2c54ad8b525b781773c87d38cbf4197636bc427a9d551368286fe4c294a4", // private key extension + "95bb82ffd5707716bc65170ab4e8dafeed90fbe0ce9258713b7751e962d931df", // public key + "f2c9171782e7df7665126ac545ae53b05964b0160536efdb545e2460dbbec2b19ec6b338b8f1bf4dfee94360ed024b115e37b1d7e6f3f9ae4beb79539428560f", // signature + + "9b5a3d9a4c60bcd49bb64b72c082b164314d0f61d842f2575fd1d4fb30a28a0c", // private key + "b093e376f41eb7bf80abcd0073a52455d25b5d21815bc758e5f6f81536aedebb", // private key extension + "79fc8154554b97e4c56ef2f9dbb4c1421ff19509688931a1e964bda5dec0f19f", // public key + "2ba1439ae648a7e8da7c9ab1ee6da94fd4ebe37abd0978306e8fba2afa8f111a88a993dbf008bedae9167f4f68409e4c9ddaf02cba12418447b1848907ad800f", // signature + + "52e0c98aa600cfdcd1ff28fcda5227ed87063f4a98547a78b771052cf102b40c", // private key + "6c18d9f8075b1a6a1833540607479bd58b7beb8a83d2bb01ca7ae02452a25803", // private key extension + "dc907c7c06e6314eedd9e18c9f6c6f9cc4e205fb1c70da608234c319f1f7b0d6", // public key + "0cd34f84e0d2fcb1800bdb0e869b9041349955ced66aedbe6bda187ebe8d36a62a05b39647e92fcc42aa7a7368174240afba08b8c81f981a22f942d6bd781602", // signature + + "11fd6462a3a92b35c22703f6f1c124ddcf36b7c2b09cc2784f320e1cfa12ec04", // private key + "c2785803c61c46aeca192a1bb1b7b20a8c4cc7fa01db57fc5d1d8a5473402352", // private key extension + "839775a41876e328986aa26168958bba1176e67819b357eea84afceab8b1db78", // public key + "e41f73db2f8d2896a687802b2be76b7cabb73dfbb4891494883a0cbd9bbb9e5f9d3e14d2d0b06c6674333508496db660936737c0efd9511514147dac79fa4905", // signature + + "5b1e5cad02274ba461f4708d8598d3497faf8fe3e894a379573aa6ac3a03e505", // private key + "ba179d2e3c67aabb486c48d16002b51ad32eab434c738a1550962313b07098cd", // private key extension + "75eb8d197ec8627c85af88e66aa1e49065dd8ac98ed8991db52ece01635dfb76", // public key + "631015357cee3051116b4c2ff4d1c5beb13b6e5023635aa1eeb0563cadf0d4fbc10bd5e31b4a4220c67875558c41b5cc0328104ae39cc7ff20ff0c2bda598906", // signature + + "624b47150f58dfa44284fbc63c9f99b9b79f808c4955a461f0e2be44eb0be50d", // private key + "097aa006d694b165ef37cf23562e5967c96e49255d2f20faae478dee83aa5b02", // private key extension + "0588589cd9b51dfc028cf225674069cbe52e0e70deb02dc45b79b26ee3548b00", // public key + "1de1d275428ba9491a433cd473cd076c027f61e7a8b5391df9dea5cb4bc88d8a57b095906a30b13e68259851a8dd3f57b6f0ffa37a5d3ffc171240f2d404f901", // signature + + 0, 0, + }; + + const char **test_data; + test_data = vectors; + while (*test_data) { + memcpy(secret_key, fromhex(*test_data), 32); + MARK_SECRET_DATA(secret_key, sizeof(secret_key)); + + memcpy(secret_key_extension, fromhex(*(test_data + 1)), 32); + MARK_SECRET_DATA(secret_key_extension, sizeof(secret_key_extension)); + + ed25519_publickey_ext(secret_key, secret_key_extension, public_key); + UNMARK_SECRET_DATA(public_key, sizeof(public_key)); + + ck_assert_mem_eq(public_key, fromhex(*(test_data + 2)), 32); + + const uint8_t * message = (const uint8_t *) "Hello World"; + ed25519_sign_ext(message, 11, secret_key, secret_key_extension, public_key, signature); + UNMARK_SECRET_DATA(signature, sizeof(signature)); + + ck_assert_mem_eq(signature, fromhex(*(test_data + 3)), 64); + + UNMARK_SECRET_DATA(secret_key, sizeof(secret_key)); + UNMARK_SECRET_DATA(secret_key_extension, sizeof(secret_key_extension)); + + test_data += 4; + } +} +END_TEST + START_TEST(test_bip32_cardano_hdnode_vector_1) { HDNode node; uint8_t seed[66]; - int seed_len = mnemonic_to_entropy("ring crime symptom enough erupt lady behave ramp apart settle citizen junk", seed + 2); + int seed_len = mnemonic_to_entropy("ring crime symptom enough erupt lady behave ramp apart settle citizen junk", seed); ck_assert_int_eq(seed_len, 132); - hdnode_from_seed_cardano(seed, seed_len / 8, &node); + hdnode_from_seed_cardano(NULL, 0, seed, seed_len / 8, &node); - ck_assert_mem_eq(node.chain_code, fromhex("739f4b3caca4c9ad4fcd4bdc2ef42c8601af8d6946999ef85ef6ae84f66e72eb"), 32); - ck_assert_mem_eq(node.private_key, fromhex("6065a956b1b34145c4416fdc3ba3276801850e91a77a31a7be782463288aea53"), 32); - ck_assert_mem_eq(node.private_key_extension, fromhex("60ba6e25b1a02157fb69c5d1d7b96c4619736e545447069a6a6f0ba90844bc8e"), 32); + ck_assert_mem_eq(node.chain_code, fromhex("affbc325d9027c0f2d9f925b1dcf6c12bf5c1dd08904474066a4f2c00db56173"), 32); + ck_assert_mem_eq(node.private_key, fromhex("08a14df748e477a69d21c97c56db151fc19e2521f31dd0ac5360f269e5b6ea46"), 32); + ck_assert_mem_eq(node.private_key_extension, fromhex("daeb991f2d2128e2525415c56a07f4366baa26c1e48572a5e073934b6de35fbc"), 32); hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key + 1, fromhex("64b20fa082b3143d6b5eed42c6ef63f99599d0888afe060620abc1b319935fe1"), 32); + ck_assert_mem_eq(node.public_key + 1, fromhex("9a1d04808b4c0682816961cf666e82a7fd35949658aba5354c517eccf12aacb4"), 32); } END_TEST @@ -21,17 +95,17 @@ START_TEST(test_bip32_cardano_hdnode_vector_2) HDNode node; uint8_t seed[66]; - int seed_len = mnemonic_to_entropy("ring crime symptom enough erupt lady behave ramp apart settle citizen junk", seed + 2); + int seed_len = mnemonic_to_entropy("ring crime symptom enough erupt lady behave ramp apart settle citizen junk", seed); ck_assert_int_eq(seed_len, 132); - hdnode_from_seed_cardano(seed, seed_len / 8, &node); + hdnode_from_seed_cardano(NULL, 0, seed, seed_len / 8, &node); hdnode_private_ckd_cardano(&node, 0x80000000); - ck_assert_mem_eq(node.chain_code, fromhex("6755cb82e892d6614c007a5efbceb21d95a5244e269d0e206b48b9a495390b03"), 32); - ck_assert_mem_eq(node.private_key, fromhex("e7d27516538403a53a8b041656a3f570909df641a0ab811fe7d87c9ba02a830c"), 32); - ck_assert_mem_eq(node.private_key_extension, fromhex("794a2c54ad8b525b781773c87d38cbf4197636bc427a9d551368286fe4c294a4"), 32); + ck_assert_mem_eq(node.chain_code, fromhex("104c6a0736e501c9bfe2966ba3773f5320495b19c3f2ed222234850af2ccd5b1"), 32); + ck_assert_mem_eq(node.private_key, fromhex("6064bf06b2e981d7c9792b1482eeecd40ec3cfa12143f4a1f149d48ce8b6ea46"), 32); + ck_assert_mem_eq(node.private_key_extension, fromhex("64aa9a16331f14c981b769efcf96addcc4c6db44047fe7a7feae0be23d33bf54"), 32); hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key + 1, fromhex("95bb82ffd5707716bc65170ab4e8dafeed90fbe0ce9258713b7751e962d931df"), 32); + ck_assert_mem_eq(node.public_key + 1, fromhex("c651c14a13c2311fc30a7acf244add1fdac3683e7ba89b4571e4cbcab509b915"), 32); } END_TEST @@ -40,17 +114,17 @@ START_TEST(test_bip32_cardano_hdnode_vector_3) HDNode node; uint8_t seed[66]; - int seed_len = mnemonic_to_entropy("ring crime symptom enough erupt lady behave ramp apart settle citizen junk", seed + 2); + int seed_len = mnemonic_to_entropy("ring crime symptom enough erupt lady behave ramp apart settle citizen junk", seed); ck_assert_int_eq(seed_len, 132); - hdnode_from_seed_cardano(seed, seed_len / 8, &node); + hdnode_from_seed_cardano(NULL, 0, seed, seed_len / 8, &node); hdnode_private_ckd_cardano(&node, 0x80000001); - ck_assert_mem_eq(node.chain_code, fromhex("47a242713bd18608231147c066b6083bfc1e9066fec9f621844c84fed6228a34"), 32); - ck_assert_mem_eq(node.private_key, fromhex("9b5a3d9a4c60bcd49bb64b72c082b164314d0f61d842f2575fd1d4fb30a28a0c"), 32); - ck_assert_mem_eq(node.private_key_extension, fromhex("b093e376f41eb7bf80abcd0073a52455d25b5d21815bc758e5f6f81536aedebb"), 32); + ck_assert_mem_eq(node.chain_code, fromhex("da99870d7e69de2a76f255ba8c7ed22428c7e5b0a8df978753c707c95ec3d4ca"), 32); + ck_assert_mem_eq(node.private_key, fromhex("c85fa69f4a1891fd98d1d1fc5f0cf9b1d6e44b0e6906744ab23ea766edb6ea46"), 32); + ck_assert_mem_eq(node.private_key_extension, fromhex("b4fc241feffe840b8a54a26ab447f5a5caa31032db3a8091fca14f38b86ed539"), 32); hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key + 1, fromhex("79fc8154554b97e4c56ef2f9dbb4c1421ff19509688931a1e964bda5dec0f19f"), 32); + ck_assert_mem_eq(node.public_key + 1, fromhex("5a5b0c92530cd366f05cf072509c806f904262c259e79a0080bbd5ee35706bb1"), 32); } END_TEST @@ -59,18 +133,18 @@ START_TEST(test_bip32_cardano_hdnode_vector_4) HDNode node; uint8_t seed[66]; - int seed_len = mnemonic_to_entropy("ring crime symptom enough erupt lady behave ramp apart settle citizen junk", seed + 2); + int seed_len = mnemonic_to_entropy("ring crime symptom enough erupt lady behave ramp apart settle citizen junk", seed); ck_assert_int_eq(seed_len, 132); - hdnode_from_seed_cardano(seed, seed_len / 8, &node); + hdnode_from_seed_cardano(NULL, 0, seed, seed_len / 8, &node); hdnode_private_ckd_cardano(&node, 0x80000000); hdnode_private_ckd_cardano(&node, 0x80000001); - ck_assert_mem_eq(node.chain_code, fromhex("d6798491b9fa4612370ae5ef3c623a0b6872f3ad8f26970885fa67c83bdc425e"), 32); - ck_assert_mem_eq(node.private_key, fromhex("52e0c98aa600cfdcd1ff28fcda5227ed87063f4a98547a78b771052cf102b40c"), 32); - ck_assert_mem_eq(node.private_key_extension, fromhex("6c18d9f8075b1a6a1833540607479bd58b7beb8a83d2bb01ca7ae02452a25803"), 32); + ck_assert_mem_eq(node.chain_code, fromhex("b40c44dfd9be08591b62be7f9991c85f812d8196927f3c824d9fcb17d275089e"), 32); + ck_assert_mem_eq(node.private_key, fromhex("d064dcf1449d9c3e47f5b422680343561989035bf2e4e23fc34cb61fedb6ea46"), 32); + ck_assert_mem_eq(node.private_key_extension, fromhex("a3071959013af95aaecf78a7a2e1b9838bbbc4864d6a8a2295243782078345cd"), 32); hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key + 1, fromhex("dc907c7c06e6314eedd9e18c9f6c6f9cc4e205fb1c70da608234c319f1f7b0d6"), 32); + ck_assert_mem_eq(node.public_key + 1, fromhex("aaaca5e7adc69a03ef1f5c017ed02879e8ca871df028461ed9bf19fb8fa15038"), 32); } END_TEST @@ -79,19 +153,19 @@ START_TEST(test_bip32_cardano_hdnode_vector_5) HDNode node; uint8_t seed[66]; - int seed_len = mnemonic_to_entropy("ring crime symptom enough erupt lady behave ramp apart settle citizen junk", seed + 2); + int seed_len = mnemonic_to_entropy("ring crime symptom enough erupt lady behave ramp apart settle citizen junk", seed); ck_assert_int_eq(seed_len, 132); - hdnode_from_seed_cardano(seed, seed_len / 8, &node); + hdnode_from_seed_cardano(NULL, 0, seed, seed_len / 8, &node); hdnode_private_ckd_cardano(&node, 0x80000000); hdnode_private_ckd_cardano(&node, 0x80000001); hdnode_private_ckd_cardano(&node, 0x80000002); - ck_assert_mem_eq(node.chain_code, fromhex("4169a2a32e3618a903e930bd1a713033a38f92389093408394e29ac37a1752ea"), 32); - ck_assert_mem_eq(node.private_key, fromhex("11fd6462a3a92b35c22703f6f1c124ddcf36b7c2b09cc2784f320e1cfa12ec04"), 32); - ck_assert_mem_eq(node.private_key_extension, fromhex("c2785803c61c46aeca192a1bb1b7b20a8c4cc7fa01db57fc5d1d8a5473402352"), 32); + ck_assert_mem_eq(node.chain_code, fromhex("2593896baf92f6ab2c0f253787ab16be0244ba95e0d48ba09da1a7fd3f926c72"), 32); + ck_assert_mem_eq(node.private_key, fromhex("0811b6d5d6f7120cb05d4ce5453d6ce42825c2a8e53b6d370a6b05ccf4b6ea46"), 32); + ck_assert_mem_eq(node.private_key_extension, fromhex("5bebf1eea68acd04932653d944b064b10baaf5886dd73c185cc285059bf93363"), 32); hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key + 1, fromhex("839775a41876e328986aa26168958bba1176e67819b357eea84afceab8b1db78"), 32); + ck_assert_mem_eq(node.public_key + 1, fromhex("1c87a32c5babad2fe33e0586bdc523574c6126f8368bc76598e17ea46201f980"), 32); } END_TEST @@ -100,20 +174,20 @@ START_TEST(test_bip32_cardano_hdnode_vector_6) HDNode node; uint8_t seed[66]; - int seed_len = mnemonic_to_entropy("ring crime symptom enough erupt lady behave ramp apart settle citizen junk", seed + 2); + int seed_len = mnemonic_to_entropy("ring crime symptom enough erupt lady behave ramp apart settle citizen junk", seed); ck_assert_int_eq(seed_len, 132); - hdnode_from_seed_cardano(seed, seed_len / 8, &node); + hdnode_from_seed_cardano(NULL, 0, seed, seed_len / 8, &node); hdnode_private_ckd_cardano(&node, 0x80000000); hdnode_private_ckd_cardano(&node, 0x80000001); hdnode_private_ckd_cardano(&node, 0x80000002); hdnode_private_ckd_cardano(&node, 0x80000002); - ck_assert_mem_eq(node.chain_code, fromhex("3ae9c99a5925cba2dcf121baf3a0254f3dea23c129f9eb70a8a7e8897c5199ba"), 32); - ck_assert_mem_eq(node.private_key, fromhex("5b1e5cad02274ba461f4708d8598d3497faf8fe3e894a379573aa6ac3a03e505"), 32); - ck_assert_mem_eq(node.private_key_extension, fromhex("ba179d2e3c67aabb486c48d16002b51ad32eab434c738a1550962313b07098cd"), 32); + ck_assert_mem_eq(node.chain_code, fromhex("fe8c6c2ab1e30385513fcffb49dcfe3e7805260425ea76b3b72b9f5bbe3b3d40"), 32); + ck_assert_mem_eq(node.private_key, fromhex("6019b9f5ef6ca530b657bcdb500de5455db8d51afb951fa045b6fbb3f6b6ea46"), 32); + ck_assert_mem_eq(node.private_key_extension, fromhex("466332cb097934b43008701e7e27044aa56c7859019e4eba18d91a3bea23dff7"), 32); hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key + 1, fromhex("75eb8d197ec8627c85af88e66aa1e49065dd8ac98ed8991db52ece01635dfb76"), 32); + ck_assert_mem_eq(node.public_key + 1, fromhex("0b8f04755481ced76b4e5795aaafdb3cbd757c10fe60e9c58f48cf29a7ec3575"), 32); } END_TEST @@ -122,9 +196,9 @@ START_TEST(test_bip32_cardano_hdnode_vector_7) HDNode node; uint8_t seed[66]; - int seed_len = mnemonic_to_entropy("ring crime symptom enough erupt lady behave ramp apart settle citizen junk", seed + 2); + int seed_len = mnemonic_to_entropy("ring crime symptom enough erupt lady behave ramp apart settle citizen junk", seed); ck_assert_int_eq(seed_len, 132); - hdnode_from_seed_cardano(seed, seed_len / 8, &node); + hdnode_from_seed_cardano(NULL, 0, seed, seed_len / 8, &node); hdnode_private_ckd_cardano(&node, 0x80000000); hdnode_private_ckd_cardano(&node, 0x80000001); @@ -132,85 +206,10 @@ START_TEST(test_bip32_cardano_hdnode_vector_7) hdnode_private_ckd_cardano(&node, 0x80000002); hdnode_private_ckd_cardano(&node, 0xBB9ACA00); - ck_assert_mem_eq(node.chain_code, fromhex("15c450b86dd7dd83b31951d9ee03eb1a7925161d817bd517c69cf09e3671f1ca"), 32); - ck_assert_mem_eq(node.private_key, fromhex("624b47150f58dfa44284fbc63c9f99b9b79f808c4955a461f0e2be44eb0be50d"), 32); - ck_assert_mem_eq(node.private_key_extension, fromhex("097aa006d694b165ef37cf23562e5967c96e49255d2f20faae478dee83aa5b02"), 32); + ck_assert_mem_eq(node.chain_code, fromhex("ff77c08d37471c1d4cedd3fae2642c009324d9712492efc74dedab09c9bf973c"), 32); + ck_assert_mem_eq(node.private_key, fromhex("488f34840bba516f7920f91676b8681d0dd833b4ce14468e0810b255f9b6ea46"), 32); + ck_assert_mem_eq(node.private_key_extension, fromhex("01eccef768a79859f824a1d3c3e35e131184e2940c3fca9a4c9b307741f65363"), 32); hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key + 1, fromhex("0588589cd9b51dfc028cf225674069cbe52e0e70deb02dc45b79b26ee3548b00"), 32); -} -END_TEST - -// https://github.com/input-output-hk/cardano-crypto/blob/master/tests/goldens/cardano/crypto/wallet/BIP39-128 -START_TEST(test_ed25519_cardano_sign_vectors) -{ - ed25519_public_key public_key; - ed25519_secret_key secret_key; - ed25519_secret_key secret_key_extension; - ed25519_signature signature; - - static const char *vectors[] = { - "6065a956b1b34145c4416fdc3ba3276801850e91a77a31a7be782463288aea53", // private key - "60ba6e25b1a02157fb69c5d1d7b96c4619736e545447069a6a6f0ba90844bc8e", // private key extension - "64b20fa082b3143d6b5eed42c6ef63f99599d0888afe060620abc1b319935fe1", // public key - "45b1a75fe3119e13c6f60ab9ba674b42f946fdc558e07c83dfa0751c2eba69c79331bd8a4a975662b23628a438a0eba76367e44c12ca91b39ec59063f860f10d", // signature - - "e7d27516538403a53a8b041656a3f570909df641a0ab811fe7d87c9ba02a830c", // private key - "794a2c54ad8b525b781773c87d38cbf4197636bc427a9d551368286fe4c294a4", // private key extension - "95bb82ffd5707716bc65170ab4e8dafeed90fbe0ce9258713b7751e962d931df", // public key - "f2c9171782e7df7665126ac545ae53b05964b0160536efdb545e2460dbbec2b19ec6b338b8f1bf4dfee94360ed024b115e37b1d7e6f3f9ae4beb79539428560f", // signature - - "9b5a3d9a4c60bcd49bb64b72c082b164314d0f61d842f2575fd1d4fb30a28a0c", // private key - "b093e376f41eb7bf80abcd0073a52455d25b5d21815bc758e5f6f81536aedebb", // private key extension - "79fc8154554b97e4c56ef2f9dbb4c1421ff19509688931a1e964bda5dec0f19f", // public key - "2ba1439ae648a7e8da7c9ab1ee6da94fd4ebe37abd0978306e8fba2afa8f111a88a993dbf008bedae9167f4f68409e4c9ddaf02cba12418447b1848907ad800f", // signature - - "52e0c98aa600cfdcd1ff28fcda5227ed87063f4a98547a78b771052cf102b40c", // private key - "6c18d9f8075b1a6a1833540607479bd58b7beb8a83d2bb01ca7ae02452a25803", // private key extension - "dc907c7c06e6314eedd9e18c9f6c6f9cc4e205fb1c70da608234c319f1f7b0d6", // public key - "0cd34f84e0d2fcb1800bdb0e869b9041349955ced66aedbe6bda187ebe8d36a62a05b39647e92fcc42aa7a7368174240afba08b8c81f981a22f942d6bd781602", // signature - - "11fd6462a3a92b35c22703f6f1c124ddcf36b7c2b09cc2784f320e1cfa12ec04", // private key - "c2785803c61c46aeca192a1bb1b7b20a8c4cc7fa01db57fc5d1d8a5473402352", // private key extension - "839775a41876e328986aa26168958bba1176e67819b357eea84afceab8b1db78", // public key - "e41f73db2f8d2896a687802b2be76b7cabb73dfbb4891494883a0cbd9bbb9e5f9d3e14d2d0b06c6674333508496db660936737c0efd9511514147dac79fa4905", // signature - - "5b1e5cad02274ba461f4708d8598d3497faf8fe3e894a379573aa6ac3a03e505", // private key - "ba179d2e3c67aabb486c48d16002b51ad32eab434c738a1550962313b07098cd", // private key extension - "75eb8d197ec8627c85af88e66aa1e49065dd8ac98ed8991db52ece01635dfb76", // public key - "631015357cee3051116b4c2ff4d1c5beb13b6e5023635aa1eeb0563cadf0d4fbc10bd5e31b4a4220c67875558c41b5cc0328104ae39cc7ff20ff0c2bda598906", // signature - - "624b47150f58dfa44284fbc63c9f99b9b79f808c4955a461f0e2be44eb0be50d", // private key - "097aa006d694b165ef37cf23562e5967c96e49255d2f20faae478dee83aa5b02", // private key extension - "0588589cd9b51dfc028cf225674069cbe52e0e70deb02dc45b79b26ee3548b00", // public key - "1de1d275428ba9491a433cd473cd076c027f61e7a8b5391df9dea5cb4bc88d8a57b095906a30b13e68259851a8dd3f57b6f0ffa37a5d3ffc171240f2d404f901", // signature - - 0, 0, - }; - - const char **test_data; - test_data = vectors; - while (*test_data) { - memcpy(secret_key, fromhex(*test_data), 32); - MARK_SECRET_DATA(secret_key, sizeof(secret_key)); - - memcpy(secret_key_extension, fromhex(*(test_data + 1)), 32); - MARK_SECRET_DATA(secret_key_extension, sizeof(secret_key_extension)); - - ed25519_publickey_ext(secret_key, secret_key_extension, public_key); - UNMARK_SECRET_DATA(public_key, sizeof(public_key)); - - ck_assert_mem_eq(public_key, fromhex(*(test_data + 2)), 32); - - const uint8_t * message = (const uint8_t *) "Hello World"; - ed25519_sign_ext(message, 11, secret_key, secret_key_extension, public_key, signature); - UNMARK_SECRET_DATA(signature, sizeof(signature)); - - ck_assert_mem_eq(signature, fromhex(*(test_data + 3)), 64); - - UNMARK_SECRET_DATA(secret_key, sizeof(secret_key)); - UNMARK_SECRET_DATA(secret_key_extension, sizeof(secret_key_extension)); - - test_data += 4; - } + ck_assert_mem_eq(node.public_key + 1, fromhex("148605be54585773b44ba87e79265149ae444c4cc37cb1f8db8c08482fba293b"), 32); } END_TEST From e929313f533814cd762c9600d9d8a7cc5d5d4c06 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 5 Sep 2018 12:16:23 +0200 Subject: [PATCH 592/627] small changes to cardano due to last commit --- bip32.c | 7 ++----- bip32.h | 3 ++- tests/test_check_cardano.h | 14 +++++++------- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/bip32.c b/bip32.c index 50f1466dd..9935bd596 100644 --- a/bip32.c +++ b/bip32.c @@ -46,9 +46,6 @@ #include "nem.h" #endif #if USE_CARDANO -#include "ed25519-donna/modm-donna-32bit.h" -#include "blake2b.h" -#include "bip39.h" #include "pbkdf2.h" #endif #include "memzero.h" @@ -367,8 +364,8 @@ int hdnode_private_ckd_cardano(HDNode *inout, uint32_t index) return 1; } -int hdnode_from_seed_cardano(uint8_t *pass, int pass_len, uint8_t *seed, int seed_len, HDNode *out) { - uint8_t secret[96]; +int hdnode_from_seed_cardano(const uint8_t *pass, int pass_len, const uint8_t *seed, int seed_len, HDNode *out) { + static CONFIDENTIAL uint8_t secret[96]; pbkdf2_hmac_sha512(pass, pass_len, seed, seed_len, 4096, secret, 96); secret[0] &= 248; diff --git a/bip32.h b/bip32.h index 2c2f799ae..8b76d65ca 100644 --- a/bip32.h +++ b/bip32.h @@ -61,9 +61,10 @@ int hdnode_from_seed(const uint8_t *seed, int seed_len, const char *curve, HDNod #define hdnode_private_ckd_prime(X, I) hdnode_private_ckd((X), ((I) | 0x80000000)) int hdnode_private_ckd(HDNode *inout, uint32_t i); + #if USE_CARDANO int hdnode_private_ckd_cardano(HDNode *inout, uint32_t i); -int hdnode_from_seed_cardano(uint8_t *pass, int pass_len, uint8_t *seed, int seed_len, HDNode *out); +int hdnode_from_seed_cardano(const uint8_t *pass, int pass_len, const uint8_t *seed, int seed_len, HDNode *out); #endif int hdnode_public_ckd_cp(const ecdsa_curve *curve, const curve_point *parent, const uint8_t *parent_chain_code, uint32_t i, curve_point *child, uint8_t *child_chain_code); diff --git a/tests/test_check_cardano.h b/tests/test_check_cardano.h index 8c1f5be2a..4c734dfad 100644 --- a/tests/test_check_cardano.h +++ b/tests/test_check_cardano.h @@ -80,7 +80,7 @@ START_TEST(test_bip32_cardano_hdnode_vector_1) uint8_t seed[66]; int seed_len = mnemonic_to_entropy("ring crime symptom enough erupt lady behave ramp apart settle citizen junk", seed); ck_assert_int_eq(seed_len, 132); - hdnode_from_seed_cardano(NULL, 0, seed, seed_len / 8, &node); + hdnode_from_seed_cardano((const uint8_t *)"", 0, seed, seed_len / 8, &node); ck_assert_mem_eq(node.chain_code, fromhex("affbc325d9027c0f2d9f925b1dcf6c12bf5c1dd08904474066a4f2c00db56173"), 32); ck_assert_mem_eq(node.private_key, fromhex("08a14df748e477a69d21c97c56db151fc19e2521f31dd0ac5360f269e5b6ea46"), 32); @@ -97,7 +97,7 @@ START_TEST(test_bip32_cardano_hdnode_vector_2) uint8_t seed[66]; int seed_len = mnemonic_to_entropy("ring crime symptom enough erupt lady behave ramp apart settle citizen junk", seed); ck_assert_int_eq(seed_len, 132); - hdnode_from_seed_cardano(NULL, 0, seed, seed_len / 8, &node); + hdnode_from_seed_cardano((const uint8_t *)"", 0, seed, seed_len / 8, &node); hdnode_private_ckd_cardano(&node, 0x80000000); @@ -116,7 +116,7 @@ START_TEST(test_bip32_cardano_hdnode_vector_3) uint8_t seed[66]; int seed_len = mnemonic_to_entropy("ring crime symptom enough erupt lady behave ramp apart settle citizen junk", seed); ck_assert_int_eq(seed_len, 132); - hdnode_from_seed_cardano(NULL, 0, seed, seed_len / 8, &node); + hdnode_from_seed_cardano((const uint8_t *)"", 0, seed, seed_len / 8, &node); hdnode_private_ckd_cardano(&node, 0x80000001); @@ -135,7 +135,7 @@ START_TEST(test_bip32_cardano_hdnode_vector_4) uint8_t seed[66]; int seed_len = mnemonic_to_entropy("ring crime symptom enough erupt lady behave ramp apart settle citizen junk", seed); ck_assert_int_eq(seed_len, 132); - hdnode_from_seed_cardano(NULL, 0, seed, seed_len / 8, &node); + hdnode_from_seed_cardano((const uint8_t *)"", 0, seed, seed_len / 8, &node); hdnode_private_ckd_cardano(&node, 0x80000000); hdnode_private_ckd_cardano(&node, 0x80000001); @@ -155,7 +155,7 @@ START_TEST(test_bip32_cardano_hdnode_vector_5) uint8_t seed[66]; int seed_len = mnemonic_to_entropy("ring crime symptom enough erupt lady behave ramp apart settle citizen junk", seed); ck_assert_int_eq(seed_len, 132); - hdnode_from_seed_cardano(NULL, 0, seed, seed_len / 8, &node); + hdnode_from_seed_cardano((const uint8_t *)"", 0, seed, seed_len / 8, &node); hdnode_private_ckd_cardano(&node, 0x80000000); hdnode_private_ckd_cardano(&node, 0x80000001); @@ -176,7 +176,7 @@ START_TEST(test_bip32_cardano_hdnode_vector_6) uint8_t seed[66]; int seed_len = mnemonic_to_entropy("ring crime symptom enough erupt lady behave ramp apart settle citizen junk", seed); ck_assert_int_eq(seed_len, 132); - hdnode_from_seed_cardano(NULL, 0, seed, seed_len / 8, &node); + hdnode_from_seed_cardano((const uint8_t *)"", 0, seed, seed_len / 8, &node); hdnode_private_ckd_cardano(&node, 0x80000000); hdnode_private_ckd_cardano(&node, 0x80000001); @@ -198,7 +198,7 @@ START_TEST(test_bip32_cardano_hdnode_vector_7) uint8_t seed[66]; int seed_len = mnemonic_to_entropy("ring crime symptom enough erupt lady behave ramp apart settle citizen junk", seed); ck_assert_int_eq(seed_len, 132); - hdnode_from_seed_cardano(NULL, 0, seed, seed_len / 8, &node); + hdnode_from_seed_cardano((const uint8_t *)"", 0, seed, seed_len / 8, &node); hdnode_private_ckd_cardano(&node, 0x80000000); hdnode_private_ckd_cardano(&node, 0x80000001); From 9da140fbf8dde92d862be485890b03bf414cc4cd Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 5 Sep 2018 12:38:57 +0200 Subject: [PATCH 593/627] drop float usage from pbkdf2 --- pbkdf2.c | 6 ++---- tests/test_check.c | 39 +++++++++++++++++++-------------------- 2 files changed, 21 insertions(+), 24 deletions(-) diff --git a/pbkdf2.c b/pbkdf2.c index 04c11e8af..ade3077d9 100644 --- a/pbkdf2.c +++ b/pbkdf2.c @@ -27,8 +27,6 @@ #include "sha2.h" #include "memzero.h" -#define CEILING_POS(X) ((X-(uint32_t)(X)) > 0 ? (uint32_t)(X+1) : (uint32_t)(X)) - void pbkdf2_hmac_sha256_Init(PBKDF2_HMAC_SHA256_CTX *pctx, const uint8_t *pass, int passlen, const uint8_t *salt, int saltlen, uint32_t blocknr) { SHA256_CTX ctx; @@ -81,7 +79,7 @@ void pbkdf2_hmac_sha256_Final(PBKDF2_HMAC_SHA256_CTX *pctx, uint8_t *key) void pbkdf2_hmac_sha256(const uint8_t *pass, int passlen, const uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key, int keylen) { - uint32_t blocks_count = (uint32_t) CEILING_POS((float) keylen / SHA256_DIGEST_LENGTH); + uint32_t blocks_count = (keylen + SHA256_DIGEST_LENGTH - 1) / SHA256_DIGEST_LENGTH; int unfinished_key_size = keylen; for (uint32_t blocknr = 1; blocknr <= blocks_count; blocknr++) { @@ -157,7 +155,7 @@ void pbkdf2_hmac_sha512_Final(PBKDF2_HMAC_SHA512_CTX *pctx, uint8_t *key) void pbkdf2_hmac_sha512(const uint8_t *pass, int passlen, const uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key, int keylen) { - uint32_t blocks_count = (uint32_t) CEILING_POS((float) keylen / SHA512_DIGEST_LENGTH); + uint32_t blocks_count = (keylen + SHA512_DIGEST_LENGTH - 1) / SHA512_DIGEST_LENGTH; int unfinished_key_size = keylen; for (uint32_t blocknr = 1; blocknr <= blocks_count; blocknr++) { diff --git a/tests/test_check.c b/tests/test_check.c index 6c6564564..d9413b134 100644 --- a/tests/test_check.c +++ b/tests/test_check.c @@ -2580,48 +2580,47 @@ START_TEST(test_blake2s) } END_TEST -// test vectors from https://stackoverflow.com/questions/5130513/pbkdf2-hmac-sha2-test-vectors START_TEST(test_pbkdf2_hmac_sha256) { - uint8_t k[40], s[40]; + uint8_t k[64]; - strcpy((char *)s, "salt"); - pbkdf2_hmac_sha256((uint8_t *)"password", 8, s, 4, 1, k, 32); + // test vectors from https://stackoverflow.com/questions/5130513/pbkdf2-hmac-sha2-test-vectors + pbkdf2_hmac_sha256((const uint8_t *)"password", 8, (const uint8_t *)"salt", 4, 1, k, 32); ck_assert_mem_eq(k, fromhex("120fb6cffcf8b32c43e7225256c4f837a86548c92ccc35480805987cb70be17b"), 32); - strcpy((char *)s, "salt"); - pbkdf2_hmac_sha256((uint8_t *)"password", 8, s, 4, 2, k, 32); + pbkdf2_hmac_sha256((const uint8_t *)"password", 8, (const uint8_t *)"salt", 4, 2, k, 32); ck_assert_mem_eq(k, fromhex("ae4d0c95af6b46d32d0adff928f06dd02a303f8ef3c251dfd6e2d85a95474c43"), 32); - strcpy((char *)s, "salt"); - pbkdf2_hmac_sha256((uint8_t *)"password", 8, s, 4, 4096, k, 32); + pbkdf2_hmac_sha256((const uint8_t *)"password", 8, (const uint8_t *)"salt", 4, 4096, k, 32); ck_assert_mem_eq(k, fromhex("c5e478d59288c841aa530db6845c4c8d962893a001ce4e11a4963873aa98134a"), 32); - strcpy((char *)s, "saltSALTsaltSALTsaltSALTsaltSALTsalt"); - pbkdf2_hmac_sha256((uint8_t *)"passwordPASSWORDpassword", 3*8, s, 9*4, 4096, k, 32); - ck_assert_mem_eq(k, fromhex("348c89dbcbd32b2f32d814b8116e84cf2b17347ebc1800181c4e2a1fb8dd53e1"), 32); + pbkdf2_hmac_sha256((const uint8_t *)"passwordPASSWORDpassword", 3 * 8, (const uint8_t *)"saltSALTsaltSALTsaltSALTsaltSALTsalt", 9 * 4, 4096, k, 40); + ck_assert_mem_eq(k, fromhex("348c89dbcbd32b2f32d814b8116e84cf2b17347ebc1800181c4e2a1fb8dd53e1c635518c7dac47e9"), 40); + + pbkdf2_hmac_sha256((const uint8_t *)"pass\x00word", 9, (const uint8_t *)"sa\x00lt", 5, 4096, k, 16); + ck_assert_mem_eq(k, fromhex("89b69d0516f829893c696226650a8687"), 16); + + // test vector from https://tools.ietf.org/html/rfc7914.html#section-11 + pbkdf2_hmac_sha256((const uint8_t *)"passwd", 6, (const uint8_t *)"salt", 4, 1, k, 64); + ck_assert_mem_eq(k, fromhex("55ac046e56e3089fec1691c22544b605f94185216dde0465e68b9d57c20dacbc49ca9cccf179b645991664b39d77ef317c71b845b1e30bd509112041d3a19783"), 64); } END_TEST // test vectors from http://stackoverflow.com/questions/15593184/pbkdf2-hmac-sha-512-test-vectors START_TEST(test_pbkdf2_hmac_sha512) { - uint8_t k[64], s[40]; + uint8_t k[64]; - strcpy((char *)s, "salt"); - pbkdf2_hmac_sha512((uint8_t *)"password", 8, s, 4, 1, k, 64); + pbkdf2_hmac_sha512((uint8_t *)"password", 8, (const uint8_t *)"salt", 4, 1, k, 64); ck_assert_mem_eq(k, fromhex("867f70cf1ade02cff3752599a3a53dc4af34c7a669815ae5d513554e1c8cf252c02d470a285a0501bad999bfe943c08f050235d7d68b1da55e63f73b60a57fce"), 64); - strcpy((char *)s, "salt"); - pbkdf2_hmac_sha512((uint8_t *)"password", 8, s, 4, 2, k, 64); + pbkdf2_hmac_sha512((uint8_t *)"password", 8, (const uint8_t *)"salt", 4, 2, k, 64); ck_assert_mem_eq(k, fromhex("e1d9c16aa681708a45f5c7c4e215ceb66e011a2e9f0040713f18aefdb866d53cf76cab2868a39b9f7840edce4fef5a82be67335c77a6068e04112754f27ccf4e"), 64); - strcpy((char *)s, "salt"); - pbkdf2_hmac_sha512((uint8_t *)"password", 8, s, 4, 4096, k, 64); + pbkdf2_hmac_sha512((uint8_t *)"password", 8, (const uint8_t *)"salt", 4, 4096, k, 64); ck_assert_mem_eq(k, fromhex("d197b1b33db0143e018b12f3d1d1479e6cdebdcc97c5c0f87f6902e072f457b5143f30602641b3d55cd335988cb36b84376060ecd532e039b742a239434af2d5"), 64); - strcpy((char *)s, "saltSALTsaltSALTsaltSALTsaltSALTsalt"); - pbkdf2_hmac_sha512((uint8_t *)"passwordPASSWORDpassword", 3*8, s, 9*4, 4096, k, 64); + pbkdf2_hmac_sha512((uint8_t *)"passwordPASSWORDpassword", 3 * 8, (const uint8_t *)"saltSALTsaltSALTsaltSALTsaltSALTsalt", 9 * 4, 4096, k, 64); ck_assert_mem_eq(k, fromhex("8c0511f4c6e597c6ac6315d8f0362e225f3c501495ba23b868c005174dc4ee71115b59f9e60cd9532fa33e0f75aefe30225c583a186cd82bd4daea9724a3d3b8"), 64); } END_TEST From 0d215161dcb2de9c650a96314ee5d0868caec0a4 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 5 Sep 2018 12:59:37 +0200 Subject: [PATCH 594/627] refactor cardano internal scalar functions --- bip32.c | 37 +++++++++++-------------------------- 1 file changed, 11 insertions(+), 26 deletions(-) diff --git a/bip32.c b/bip32.c index 9935bd596..da64b28ff 100644 --- a/bip32.c +++ b/bip32.c @@ -260,38 +260,23 @@ int hdnode_private_ckd(HDNode *inout, uint32_t i) } #if USE_CARDANO -/* sk1 is zl8 and contains only 29 bytes of active data, - * so it's not going to overflow when adding to sk2 */ -void scalar_add_no_overflow(const uint8_t * sk1, const uint8_t * sk2, uint8_t * res) +static void scalar_multiply8(const uint8_t *src, int bytes, uint8_t *dst) { - uint16_t r = 0; int i; - for (i = 0; i < 32; i++) { - r = (uint16_t) sk1[i] + (uint16_t) sk2[i] + r; - res[i] = (uint8_t) r; - r >>= 8; - } -} - -static void multiply8(uint8_t *dst, uint8_t *src, int bytes) -{ - int i; uint8_t prev_acc = 0; - for (i = 0; i < bytes; i++) { + for (int i = 0; i < bytes; i++) { dst[i] = (src[i] << 3) + (prev_acc & 0x7); prev_acc = src[i] >> 5; } - dst[bytes] = src[bytes-1] >> 5; + dst[bytes] = src[bytes - 1] >> 5; } -static void add_256bits(uint8_t *dst, uint8_t *src1, uint8_t *src2) +static void scalar_add_256bits(const uint8_t *src1, const uint8_t *src2, uint8_t *dst) { - int i; uint8_t carry = 0; - for (i = 0; i < 32; i++) { - uint8_t a = src1[i]; - uint8_t b = src2[i]; - uint16_t r = (uint16_t) a + (uint16_t) b + (uint16_t) carry; + uint16_t r = 0; + for (int i = 0; i < 32; i++) { + r = r + (uint16_t)src1[i] + (uint16_t)src2[i]; dst[i] = r & 0xff; - carry = (r >= 0x100) ? 1 : 0; + r >>= 8; } } @@ -332,12 +317,12 @@ int hdnode_private_ckd_cardano(HDNode *inout, uint32_t index) memset(zl8, 0, 32); /* get 8 * Zl */ - multiply8(zl8, z, 28); + scalar_multiply8(z, 28, zl8); /* Kl = 8*Zl + parent(K)l */ - scalar_add_no_overflow(zl8, priv_key, res_key); + scalar_add_256bits(zl8, priv_key, res_key); /* Kr = Zr + parent(K)r */ - add_256bits(res_key + 32, z+32, priv_key+32); + scalar_add_256bits(z + 32, priv_key + 32, res_key + 32); memcpy(inout->private_key, res_key, 32); memcpy(inout->private_key_extension, res_key + 32, 32); From e6b5538a8e11e8ec80e7edd0b75f9916b4f67db9 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 5 Sep 2018 15:04:32 +0200 Subject: [PATCH 595/627] add USE_CARDANO default to options.h --- options.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/options.h b/options.h index e30997c82..e57654e6c 100644 --- a/options.h +++ b/options.h @@ -81,6 +81,11 @@ #define USE_MONERO 0 #endif +// support CARDANO operations +#ifndef USE_CARDANO +#define USE_CARDANO 0 +#endif + // support Keccak hashing #ifndef USE_KECCAK #define USE_KECCAK 1 From a59742817f8ef89ab02b8093d4f57c3ded770a42 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 5 Sep 2018 16:26:58 +0200 Subject: [PATCH 596/627] include options.h in ed25519.h --- ed25519-donna/ed25519.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ed25519-donna/ed25519.h b/ed25519-donna/ed25519.h index 9d9838d14..6c0b58f0f 100644 --- a/ed25519-donna/ed25519.h +++ b/ed25519-donna/ed25519.h @@ -1,6 +1,8 @@ #ifndef ED25519_H #define ED25519_H +#include "options.h" + #if defined(__cplusplus) extern "C" { #endif From a83c233d7e46e4511c7a4ce8a847c361f51df264 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 5 Sep 2018 17:17:05 +0200 Subject: [PATCH 597/627] fix unused-const-variable --- ed25519-donna/ed25519-donna-impl-base.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ed25519-donna/ed25519-donna-impl-base.c b/ed25519-donna/ed25519-donna-impl-base.c index 00bbfb6f2..2fa1fa424 100644 --- a/ed25519-donna/ed25519-donna-impl-base.c +++ b/ed25519-donna/ed25519-donna-impl-base.c @@ -3,8 +3,10 @@ /* sqrt(x) is such an integer y that 0 <= y <= p - 1, y % 2 = 0, and y^2 = x (mod p). */ /* d = -121665 / 121666 */ +#if !defined(NDEBUG) static const bignum25519 ALIGN(16) fe_d = { 0x35978a3, 0x0d37284, 0x3156ebd, 0x06a0a0e, 0x001c029, 0x179e898, 0x3a03cbb, 0x1ce7198, 0x2e2b6ff, 0x1480db3}; /* d */ +#endif static const bignum25519 ALIGN(16) fe_sqrtm1 = { 0x20ea0b0, 0x186c9d2, 0x08f189d, 0x035697f, 0x0bd0c60, 0x1fbd7a7, 0x2804c9e, 0x1e16569, 0x004fc1d, 0x0ae0c92}; /* sqrt(-1) */ //static const bignum25519 ALIGN(16) fe_d2 = { From 5e85d57def3b83122b89b4cd09717713d0b50ff1 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 5 Sep 2018 17:34:42 +0200 Subject: [PATCH 598/627] minor nitpick in test_bip32_optimized --- tests/test_check.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_check.c b/tests/test_check.c index d9413b134..6af8bafca 100644 --- a/tests/test_check.c +++ b/tests/test_check.c @@ -1209,9 +1209,9 @@ START_TEST(test_bip32_optimized) memcpy(&node, &root, sizeof(HDNode)); hdnode_public_ckd(&node, i); hdnode_fill_public_key(&node); - ecdsa_get_address(node.public_key, 0, HASHER_SHA2, HASHER_SHA2D, addr1, sizeof(addr1)); + ecdsa_get_address(node.public_key, 0, HASHER_SHA2_RIPEMD, HASHER_SHA2D, addr1, sizeof(addr1)); // optimized - hdnode_public_ckd_address_optimized(&pub, root.chain_code, i, 0, HASHER_SHA2, HASHER_SHA2D, addr2, sizeof(addr2), 0); + hdnode_public_ckd_address_optimized(&pub, root.chain_code, i, 0, HASHER_SHA2_RIPEMD, HASHER_SHA2D, addr2, sizeof(addr2), 0); // check ck_assert_str_eq(addr1, addr2); } From f9caee2489aa1ca8a3380c9fc79465a83c848b7f Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 5 Sep 2018 18:30:51 +0200 Subject: [PATCH 599/627] introduce hasher_multisig to curve_info --- bip32.c | 5 +++++ bip32.h | 1 + nist256p1.c | 1 + secp256k1.c | 4 ++++ 4 files changed, 11 insertions(+) diff --git a/bip32.c b/bip32.c index da64b28ff..7f77be56c 100644 --- a/bip32.c +++ b/bip32.c @@ -56,6 +56,7 @@ const curve_info ed25519_info = { .hasher_base58 = HASHER_SHA2D, .hasher_sign = HASHER_SHA2D, .hasher_pubkey = HASHER_SHA2_RIPEMD, + .hasher_multisig = HASHER_SHA2, }; const curve_info ed25519_cardano_info = { @@ -64,6 +65,7 @@ const curve_info ed25519_cardano_info = { .hasher_base58 = HASHER_SHA2D, .hasher_sign = HASHER_SHA2D, .hasher_pubkey = HASHER_SHA2_RIPEMD, + .hasher_multisig = HASHER_SHA2, }; const curve_info ed25519_sha3_info = { @@ -72,6 +74,7 @@ const curve_info ed25519_sha3_info = { .hasher_base58 = HASHER_SHA2D, .hasher_sign = HASHER_SHA2D, .hasher_pubkey = HASHER_SHA2_RIPEMD, + .hasher_multisig = HASHER_SHA2, }; #if USE_KECCAK @@ -81,6 +84,7 @@ const curve_info ed25519_keccak_info = { .hasher_base58 = HASHER_SHA2D, .hasher_sign = HASHER_SHA2D, .hasher_pubkey = HASHER_SHA2_RIPEMD, + .hasher_multisig = HASHER_SHA2, }; #endif @@ -90,6 +94,7 @@ const curve_info curve25519_info = { .hasher_base58 = HASHER_SHA2D, .hasher_sign = HASHER_SHA2D, .hasher_pubkey = HASHER_SHA2_RIPEMD, + .hasher_multisig = HASHER_SHA2, }; int hdnode_from_xpub(uint32_t depth, uint32_t child_num, const uint8_t *chain_code, const uint8_t *public_key, const char* curve, HDNode *out) diff --git a/bip32.h b/bip32.h index 8b76d65ca..2a71afa62 100644 --- a/bip32.h +++ b/bip32.h @@ -38,6 +38,7 @@ typedef struct { HasherType hasher_base58; HasherType hasher_sign; HasherType hasher_pubkey; + HasherType hasher_multisig; } curve_info; typedef struct { diff --git a/nist256p1.c b/nist256p1.c index 79d4f5bd4..9ea796e4e 100644 --- a/nist256p1.c +++ b/nist256p1.c @@ -61,4 +61,5 @@ const curve_info nist256p1_info = { .hasher_base58 = HASHER_SHA2D, .hasher_sign = HASHER_SHA2D, .hasher_pubkey = HASHER_SHA2_RIPEMD, + .hasher_multisig = HASHER_SHA2, }; diff --git a/secp256k1.c b/secp256k1.c index e125806cb..62bbba8e6 100644 --- a/secp256k1.c +++ b/secp256k1.c @@ -61,6 +61,7 @@ const curve_info secp256k1_info = { .hasher_base58 = HASHER_SHA2D, .hasher_sign = HASHER_SHA2D, .hasher_pubkey = HASHER_SHA2_RIPEMD, + .hasher_multisig = HASHER_SHA2, }; const curve_info secp256k1_decred_info = { @@ -69,6 +70,7 @@ const curve_info secp256k1_decred_info = { .hasher_base58 = HASHER_BLAKED, .hasher_sign = HASHER_BLAKE, .hasher_pubkey = HASHER_BLAKE_RIPEMD, + .hasher_multisig = HASHER_BLAKE, }; const curve_info secp256k1_groestl_info = { @@ -77,6 +79,7 @@ const curve_info secp256k1_groestl_info = { .hasher_base58 = HASHER_GROESTLD_TRUNC, .hasher_sign = HASHER_SHA2, .hasher_pubkey = HASHER_SHA2_RIPEMD, + .hasher_multisig = HASHER_SHA2, }; const curve_info secp256k1_smart_info = { @@ -85,4 +88,5 @@ const curve_info secp256k1_smart_info = { .hasher_base58 = HASHER_SHA3K, .hasher_sign = HASHER_SHA2, .hasher_pubkey = HASHER_SHA2_RIPEMD, + .hasher_multisig = HASHER_SHA2, }; From b679a6b2a73ed8adfe236cfa0ba73c5d86661633 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 5 Sep 2018 19:53:35 +0200 Subject: [PATCH 600/627] rename hasher_multisig to hasher_script --- bip32.c | 10 +++++----- bip32.h | 2 +- nist256p1.c | 2 +- secp256k1.c | 8 ++++---- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/bip32.c b/bip32.c index 7f77be56c..54e26b42e 100644 --- a/bip32.c +++ b/bip32.c @@ -56,7 +56,7 @@ const curve_info ed25519_info = { .hasher_base58 = HASHER_SHA2D, .hasher_sign = HASHER_SHA2D, .hasher_pubkey = HASHER_SHA2_RIPEMD, - .hasher_multisig = HASHER_SHA2, + .hasher_script = HASHER_SHA2, }; const curve_info ed25519_cardano_info = { @@ -65,7 +65,7 @@ const curve_info ed25519_cardano_info = { .hasher_base58 = HASHER_SHA2D, .hasher_sign = HASHER_SHA2D, .hasher_pubkey = HASHER_SHA2_RIPEMD, - .hasher_multisig = HASHER_SHA2, + .hasher_script = HASHER_SHA2, }; const curve_info ed25519_sha3_info = { @@ -74,7 +74,7 @@ const curve_info ed25519_sha3_info = { .hasher_base58 = HASHER_SHA2D, .hasher_sign = HASHER_SHA2D, .hasher_pubkey = HASHER_SHA2_RIPEMD, - .hasher_multisig = HASHER_SHA2, + .hasher_script = HASHER_SHA2, }; #if USE_KECCAK @@ -84,7 +84,7 @@ const curve_info ed25519_keccak_info = { .hasher_base58 = HASHER_SHA2D, .hasher_sign = HASHER_SHA2D, .hasher_pubkey = HASHER_SHA2_RIPEMD, - .hasher_multisig = HASHER_SHA2, + .hasher_script = HASHER_SHA2, }; #endif @@ -94,7 +94,7 @@ const curve_info curve25519_info = { .hasher_base58 = HASHER_SHA2D, .hasher_sign = HASHER_SHA2D, .hasher_pubkey = HASHER_SHA2_RIPEMD, - .hasher_multisig = HASHER_SHA2, + .hasher_script = HASHER_SHA2, }; int hdnode_from_xpub(uint32_t depth, uint32_t child_num, const uint8_t *chain_code, const uint8_t *public_key, const char* curve, HDNode *out) diff --git a/bip32.h b/bip32.h index 2a71afa62..c0a04b5f8 100644 --- a/bip32.h +++ b/bip32.h @@ -38,7 +38,7 @@ typedef struct { HasherType hasher_base58; HasherType hasher_sign; HasherType hasher_pubkey; - HasherType hasher_multisig; + HasherType hasher_script; } curve_info; typedef struct { diff --git a/nist256p1.c b/nist256p1.c index 9ea796e4e..7cffa5c39 100644 --- a/nist256p1.c +++ b/nist256p1.c @@ -61,5 +61,5 @@ const curve_info nist256p1_info = { .hasher_base58 = HASHER_SHA2D, .hasher_sign = HASHER_SHA2D, .hasher_pubkey = HASHER_SHA2_RIPEMD, - .hasher_multisig = HASHER_SHA2, + .hasher_script = HASHER_SHA2, }; diff --git a/secp256k1.c b/secp256k1.c index 62bbba8e6..f7ec89042 100644 --- a/secp256k1.c +++ b/secp256k1.c @@ -61,7 +61,7 @@ const curve_info secp256k1_info = { .hasher_base58 = HASHER_SHA2D, .hasher_sign = HASHER_SHA2D, .hasher_pubkey = HASHER_SHA2_RIPEMD, - .hasher_multisig = HASHER_SHA2, + .hasher_script = HASHER_SHA2, }; const curve_info secp256k1_decred_info = { @@ -70,7 +70,7 @@ const curve_info secp256k1_decred_info = { .hasher_base58 = HASHER_BLAKED, .hasher_sign = HASHER_BLAKE, .hasher_pubkey = HASHER_BLAKE_RIPEMD, - .hasher_multisig = HASHER_BLAKE, + .hasher_script = HASHER_BLAKE, }; const curve_info secp256k1_groestl_info = { @@ -79,7 +79,7 @@ const curve_info secp256k1_groestl_info = { .hasher_base58 = HASHER_GROESTLD_TRUNC, .hasher_sign = HASHER_SHA2, .hasher_pubkey = HASHER_SHA2_RIPEMD, - .hasher_multisig = HASHER_SHA2, + .hasher_script = HASHER_SHA2, }; const curve_info secp256k1_smart_info = { @@ -88,5 +88,5 @@ const curve_info secp256k1_smart_info = { .hasher_base58 = HASHER_SHA3K, .hasher_sign = HASHER_SHA2, .hasher_pubkey = HASHER_SHA2_RIPEMD, - .hasher_multisig = HASHER_SHA2, + .hasher_script = HASHER_SHA2, }; From 9c2cfb04704b1419e7d1aebbb21b192fbf49644d Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 11 Sep 2018 17:53:02 +0200 Subject: [PATCH 601/627] refactor pbkdf2 functions to make them more readable --- pbkdf2.c | 53 ++++++++++++++++++++++++++--------------------------- 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/pbkdf2.c b/pbkdf2.c index ade3077d9..23644ea73 100644 --- a/pbkdf2.c +++ b/pbkdf2.c @@ -79,25 +79,24 @@ void pbkdf2_hmac_sha256_Final(PBKDF2_HMAC_SHA256_CTX *pctx, uint8_t *key) void pbkdf2_hmac_sha256(const uint8_t *pass, int passlen, const uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key, int keylen) { - uint32_t blocks_count = (keylen + SHA256_DIGEST_LENGTH - 1) / SHA256_DIGEST_LENGTH; - - int unfinished_key_size = keylen; + uint32_t last_block_size = keylen % SHA256_DIGEST_LENGTH; + uint32_t blocks_count = keylen / SHA256_DIGEST_LENGTH; + if (last_block_size) { + blocks_count++; + } else { + last_block_size = SHA256_DIGEST_LENGTH; + } for (uint32_t blocknr = 1; blocknr <= blocks_count; blocknr++) { PBKDF2_HMAC_SHA256_CTX pctx; pbkdf2_hmac_sha256_Init(&pctx, pass, passlen, salt, saltlen, blocknr); pbkdf2_hmac_sha256_Update(&pctx, iterations); - - unsigned int key_offset = (blocknr - 1) * SHA256_DIGEST_LENGTH; - uint8_t diggest[SHA256_DIGEST_LENGTH]; - - pbkdf2_hmac_sha256_Final(&pctx, diggest); - - if (unfinished_key_size > SHA256_DIGEST_LENGTH) { - memcpy(key + key_offset, diggest, SHA256_DIGEST_LENGTH); - unfinished_key_size -= SHA256_DIGEST_LENGTH; + uint8_t digest[SHA256_DIGEST_LENGTH]; + pbkdf2_hmac_sha256_Final(&pctx, digest); + uint32_t key_offset = (blocknr - 1) * SHA256_DIGEST_LENGTH; + if (blocknr < blocks_count) { + memcpy(key + key_offset, digest, SHA256_DIGEST_LENGTH); } else { - memcpy(key + key_offset, diggest, unfinished_key_size); - unfinished_key_size = 0; + memcpy(key + key_offset, digest, last_block_size); } } } @@ -155,24 +154,24 @@ void pbkdf2_hmac_sha512_Final(PBKDF2_HMAC_SHA512_CTX *pctx, uint8_t *key) void pbkdf2_hmac_sha512(const uint8_t *pass, int passlen, const uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key, int keylen) { - uint32_t blocks_count = (keylen + SHA512_DIGEST_LENGTH - 1) / SHA512_DIGEST_LENGTH; - - int unfinished_key_size = keylen; + uint32_t last_block_size = keylen % SHA512_DIGEST_LENGTH; + uint32_t blocks_count = keylen / SHA512_DIGEST_LENGTH; + if (last_block_size) { + blocks_count++; + } else { + last_block_size = SHA512_DIGEST_LENGTH; + } for (uint32_t blocknr = 1; blocknr <= blocks_count; blocknr++) { PBKDF2_HMAC_SHA512_CTX pctx; pbkdf2_hmac_sha512_Init(&pctx, pass, passlen, salt, saltlen, blocknr); pbkdf2_hmac_sha512_Update(&pctx, iterations); - - unsigned int key_offset = (blocknr - 1) * SHA512_DIGEST_LENGTH; - uint8_t diggest[SHA512_DIGEST_LENGTH]; - pbkdf2_hmac_sha512_Final(&pctx, diggest); - - if (unfinished_key_size > SHA512_DIGEST_LENGTH) { - memcpy(key + key_offset, diggest, SHA512_DIGEST_LENGTH); - unfinished_key_size -= SHA512_DIGEST_LENGTH; + uint8_t digest[SHA512_DIGEST_LENGTH]; + pbkdf2_hmac_sha512_Final(&pctx, digest); + uint32_t key_offset = (blocknr - 1) * SHA512_DIGEST_LENGTH; + if (blocknr < blocks_count) { + memcpy(key + key_offset, digest, SHA512_DIGEST_LENGTH); } else { - memcpy(key + key_offset, diggest, unfinished_key_size); - unfinished_key_size = 0; + memcpy(key + key_offset, digest, last_block_size); } } } From f9523f97df2c965835001d551738bbe1b93b53df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Nussbaumer?= Date: Thu, 13 Sep 2018 14:58:29 +0200 Subject: [PATCH 602/627] Improve function naming (#181) Changes the `ecdsa_verify_digest_recover` function to `ecdsa_recover_pub_from_sig`, to avoid confusion Fix #180 --- ecdsa.c | 4 ++-- ecdsa.h | 2 +- tests/test_check.c | 30 +++++++++++++++--------------- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/ecdsa.c b/ecdsa.c index c910bb938..c0717902a 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -1024,8 +1024,8 @@ int ecdsa_verify(const ecdsa_curve *curve, HasherType hasher_sign, const uint8_t } // Compute public key from signature and recovery id. -// returns 0 if verification succeeded -int ecdsa_verify_digest_recover(const ecdsa_curve *curve, uint8_t *pub_key, const uint8_t *sig, const uint8_t *digest, int recid) +// returns 0 if the key is successfully recovered +int ecdsa_recover_pub_from_sig (const ecdsa_curve *curve, uint8_t *pub_key, const uint8_t *sig, const uint8_t *digest, int recid) { bignum256 r, s, e; curve_point cp, cp2; diff --git a/ecdsa.h b/ecdsa.h index 2d0e4c531..6afb542f2 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -91,7 +91,7 @@ int ecdsa_read_pubkey(const ecdsa_curve *curve, const uint8_t *pub_key, curve_po int ecdsa_validate_pubkey(const ecdsa_curve *curve, const curve_point *pub); int ecdsa_verify(const ecdsa_curve *curve, HasherType hasher_sign, const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, uint32_t msg_len); int ecdsa_verify_digest(const ecdsa_curve *curve, const uint8_t *pub_key, const uint8_t *sig, const uint8_t *digest); -int ecdsa_verify_digest_recover(const ecdsa_curve *curve, uint8_t *pub_key, const uint8_t *sig, const uint8_t *digest, int recid); +int ecdsa_recover_pub_from_sig (const ecdsa_curve *curve, uint8_t *pub_key, const uint8_t *sig, const uint8_t *digest, int recid); int ecdsa_sig_to_der(const uint8_t *sig, uint8_t *der); #endif diff --git a/tests/test_check.c b/tests/test_check.c index 6af8bafca..25baeccca 100644 --- a/tests/test_check.c +++ b/tests/test_check.c @@ -1936,55 +1936,55 @@ START_TEST(test_ecdsa_signature) // sha2(sha2("\x18Bitcoin Signed Message:\n\x0cHello World!")) memcpy(digest, fromhex("de4e9524586d6fce45667f9ff12f661e79870c4105fa0fb58af976619bb11432"), 32); // r = 2: Four points should exist - res = ecdsa_verify_digest_recover(curve, pubkey, fromhex("00000000000000000000000000000000000000000000000000000000000000020123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), digest, 0); + res = ecdsa_recover_pub_from_sig (curve, pubkey, fromhex ("00000000000000000000000000000000000000000000000000000000000000020123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), digest, 0); ck_assert_int_eq(res, 0); ck_assert_mem_eq(pubkey, fromhex("043fc5bf5fec35b6ffe6fd246226d312742a8c296bfa57dd22da509a2e348529b7ddb9faf8afe1ecda3c05e7b2bda47ee1f5a87e952742b22afca560b29d972fcf"), 65); - res = ecdsa_verify_digest_recover(curve, pubkey, fromhex("00000000000000000000000000000000000000000000000000000000000000020123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), digest, 1); + res = ecdsa_recover_pub_from_sig (curve, pubkey, fromhex ("00000000000000000000000000000000000000000000000000000000000000020123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), digest, 1); ck_assert_int_eq(res, 0); ck_assert_mem_eq(pubkey, fromhex("0456d8089137b1fd0d890f8c7d4a04d0fd4520a30b19518ee87bd168ea12ed8090329274c4c6c0d9df04515776f2741eeffc30235d596065d718c3973e19711ad0"), 65); - res = ecdsa_verify_digest_recover(curve, pubkey, fromhex("00000000000000000000000000000000000000000000000000000000000000020123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), digest, 2); + res = ecdsa_recover_pub_from_sig (curve, pubkey, fromhex ("00000000000000000000000000000000000000000000000000000000000000020123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), digest, 2); ck_assert_int_eq(res, 0); ck_assert_mem_eq(pubkey, fromhex("04cee0e740f41aab39156844afef0182dea2a8026885b10454a2d539df6f6df9023abfcb0f01c50bef3c0fa8e59a998d07441e18b1c60583ef75cc8b912fb21a15"), 65); - res = ecdsa_verify_digest_recover(curve, pubkey, fromhex("00000000000000000000000000000000000000000000000000000000000000020123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), digest, 3); + res = ecdsa_recover_pub_from_sig (curve, pubkey, fromhex ("00000000000000000000000000000000000000000000000000000000000000020123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), digest, 3); ck_assert_int_eq(res, 0); ck_assert_mem_eq(pubkey, fromhex("0490d2bd2e9a564d6e1d8324fc6ad00aa4ae597684ecf4abea58bdfe7287ea4fa72968c2e5b0b40999ede3d7898d94e82c3f8dc4536a567a4bd45998c826a4c4b2"), 65); memcpy(digest, fromhex("0000000000000000000000000000000000000000000000000000000000000000"), 32); // r = 7: No point P with P.x = 7, but P.x = (order + 7) exists - res = ecdsa_verify_digest_recover(curve, pubkey, fromhex("00000000000000000000000000000000000000000000000000000000000000070123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), digest, 2); + res = ecdsa_recover_pub_from_sig (curve, pubkey, fromhex ("00000000000000000000000000000000000000000000000000000000000000070123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), digest, 2); ck_assert_int_eq(res, 0); ck_assert_mem_eq(pubkey, fromhex("044d81bb47a31ffc6cf1f780ecb1e201ec47214b651650867c07f13ad06e12a1b040de78f8dbda700f4d3cd7ee21b3651a74c7661809699d2be7ea0992b0d39797"), 65); - res = ecdsa_verify_digest_recover(curve, pubkey, fromhex("00000000000000000000000000000000000000000000000000000000000000070123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), digest, 3); + res = ecdsa_recover_pub_from_sig (curve, pubkey, fromhex ("00000000000000000000000000000000000000000000000000000000000000070123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), digest, 3); ck_assert_int_eq(res, 0); ck_assert_mem_eq(pubkey, fromhex("044d81bb47a31ffc6cf1f780ecb1e201ec47214b651650867c07f13ad06e12a1b0bf21870724258ff0b2c32811de4c9ae58b3899e7f69662d41815f66c4f2c6498"), 65); - res = ecdsa_verify_digest_recover(curve, pubkey, fromhex("00000000000000000000000000000000000000000000000000000000000000070123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), digest, 0); + res = ecdsa_recover_pub_from_sig (curve, pubkey, fromhex ("00000000000000000000000000000000000000000000000000000000000000070123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), digest, 0); ck_assert_int_eq(res, 1); memcpy(digest, fromhex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), 32); // r = 1: Two points P with P.x = 1, but P.x = (order + 7) doesn't exist - res = ecdsa_verify_digest_recover(curve, pubkey, fromhex("00000000000000000000000000000000000000000000000000000000000000010123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), digest, 0); + res = ecdsa_recover_pub_from_sig (curve, pubkey, fromhex ("00000000000000000000000000000000000000000000000000000000000000010123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), digest, 0); ck_assert_int_eq(res, 0); ck_assert_mem_eq(pubkey, fromhex("045d330b2f89dbfca149828277bae852dd4aebfe136982cb531a88e9e7a89463fe71519f34ea8feb9490c707f14bc38c9ece51762bfd034ea014719b7c85d2871b"), 65); - res = ecdsa_verify_digest_recover(curve, pubkey, fromhex("00000000000000000000000000000000000000000000000000000000000000010123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), digest, 1); + res = ecdsa_recover_pub_from_sig (curve, pubkey, fromhex ("00000000000000000000000000000000000000000000000000000000000000010123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), digest, 1); ck_assert_int_eq(res, 0); ck_assert_mem_eq(pubkey, fromhex("049e609c3950e70d6f3e3f3c81a473b1d5ca72739d51debdd80230ae80cab05134a94285375c834a417e8115c546c41da83a263087b79ef1cae25c7b3c738daa2b"), 65); // r = 0 is always invalid - res = ecdsa_verify_digest_recover(curve, pubkey, fromhex("00000000000000000000000000000000000000000000000000000000000000010123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), digest, 2); + res = ecdsa_recover_pub_from_sig (curve, pubkey, fromhex ("00000000000000000000000000000000000000000000000000000000000000010123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), digest, 2); ck_assert_int_eq(res, 1); - res = ecdsa_verify_digest_recover(curve, pubkey, fromhex("00000000000000000000000000000000000000000000000000000000000000000123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), digest, 0); + res = ecdsa_recover_pub_from_sig (curve, pubkey, fromhex ("00000000000000000000000000000000000000000000000000000000000000000123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), digest, 0); ck_assert_int_eq(res, 1); // r >= order is always invalid - res = ecdsa_verify_digest_recover(curve, pubkey, fromhex("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641410123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), digest, 0); + res = ecdsa_recover_pub_from_sig (curve, pubkey, fromhex ("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641410123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), digest, 0); ck_assert_int_eq(res, 1); // check that overflow of r is handled - res = ecdsa_verify_digest_recover(curve, pubkey, fromhex("000000000000000000000000000000014551231950B75FC4402DA1722FC9BAEE0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), digest, 2); + res = ecdsa_recover_pub_from_sig (curve, pubkey, fromhex ("000000000000000000000000000000014551231950B75FC4402DA1722FC9BAEE0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), digest, 2); ck_assert_int_eq(res, 1); // s = 0 is always invalid - res = ecdsa_verify_digest_recover(curve, pubkey, fromhex("00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000"), digest, 0); + res = ecdsa_recover_pub_from_sig (curve, pubkey, fromhex ("00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000"), digest, 0); ck_assert_int_eq(res, 1); // s >= order is always invalid - res = ecdsa_verify_digest_recover(curve, pubkey, fromhex("0000000000000000000000000000000000000000000000000000000000000002fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"), digest, 0); + res = ecdsa_recover_pub_from_sig (curve, pubkey, fromhex ("0000000000000000000000000000000000000000000000000000000000000002fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"), digest, 0); ck_assert_int_eq(res, 1); } END_TEST From 2b7d9bd57930170d3c7fcec880fe4a57b7b53f16 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 30 Sep 2018 15:40:18 +0200 Subject: [PATCH 603/627] use env where possible --- setup.py | 2 +- tests/test_wycheproof.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 24a639d69..aee3dd4a9 100755 --- a/setup.py +++ b/setup.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python from distutils.core import setup from distutils.extension import Extension diff --git a/tests/test_wycheproof.py b/tests/test_wycheproof.py index 08fe1ab9a..3bdedbfac 100755 --- a/tests/test_wycheproof.py +++ b/tests/test_wycheproof.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python import ctypes import json import os From 60b5b7032c7e38695b405ce50b4d65223b2fd0e3 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 16 Oct 2018 11:29:45 +0200 Subject: [PATCH 604/627] hasher: add HASHER_SAPLING_PREIMAGE --- hasher.c | 7 ++++++- hasher.h | 3 ++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/hasher.c b/hasher.c index b6564e8de..dfcb64a76 100644 --- a/hasher.c +++ b/hasher.c @@ -56,7 +56,10 @@ void hasher_Init(Hasher *hasher, HasherType type) { blake2b_InitPersonal(&hasher->ctx.blake2b, 32, "ZcashOutputsHash", 16); break; case HASHER_OVERWINTER_PREIMAGE: - blake2b_InitPersonal(&hasher->ctx.blake2b, 32, "ZcashSigHash\x19\x1b\xa8\x5b", 16); // BRANCH_ID = 0x5ba81b19 + blake2b_InitPersonal(&hasher->ctx.blake2b, 32, "ZcashSigHash\x19\x1b\xa8\x5b", 16); // BRANCH_ID = 0x5ba81b19 / Overwinter + break; + case HASHER_SAPLING_PREIMAGE: + blake2b_InitPersonal(&hasher->ctx.blake2b, 32, "ZcashSigHash\xbb\x09\xb8\x76", 16); // BRANCH_ID = 0x76b809bb / Sapling break; } } @@ -90,6 +93,7 @@ void hasher_Update(Hasher *hasher, const uint8_t *data, size_t length) { case HASHER_OVERWINTER_SEQUENCE: case HASHER_OVERWINTER_OUTPUTS: case HASHER_OVERWINTER_PREIMAGE: + case HASHER_SAPLING_PREIMAGE: blake2b_Update(&hasher->ctx.blake2b, data, length); break; } @@ -134,6 +138,7 @@ void hasher_Final(Hasher *hasher, uint8_t hash[HASHER_DIGEST_LENGTH]) { case HASHER_OVERWINTER_SEQUENCE: case HASHER_OVERWINTER_OUTPUTS: case HASHER_OVERWINTER_PREIMAGE: + case HASHER_SAPLING_PREIMAGE: blake2b_Final(&hasher->ctx.blake2b, hash, 32); break; } diff --git a/hasher.h b/hasher.h index 7e748bf8e..e008efdef 100644 --- a/hasher.h +++ b/hasher.h @@ -54,6 +54,7 @@ typedef enum { HASHER_OVERWINTER_SEQUENCE, HASHER_OVERWINTER_OUTPUTS, HASHER_OVERWINTER_PREIMAGE, + HASHER_SAPLING_PREIMAGE, } HasherType; typedef struct { @@ -64,7 +65,7 @@ typedef struct { SHA3_CTX sha3; // for HASHER_SHA3{,K} BLAKE256_CTX blake; // for HASHER_BLAKE{,D} GROESTL512_CTX groestl; // for HASHER_GROESTLD_TRUNC - BLAKE2B_CTX blake2b; // for HASHER_OVERWINTER_* + BLAKE2B_CTX blake2b; // for HASHER_OVERWINTER_*, HASHER_SAPLING_* } ctx; } Hasher; From a938a1c9019969ec8b63713e9402a932e8e0d9a8 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 16 Oct 2018 11:29:58 +0200 Subject: [PATCH 605/627] nix: add shell.nix --- shell.nix | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 shell.nix diff --git a/shell.nix b/shell.nix new file mode 100644 index 000000000..52601dd7b --- /dev/null +++ b/shell.nix @@ -0,0 +1,6 @@ +with import {}; + +stdenv.mkDerivation { + name = "trezor-crypto-dev"; + buildInputs = [ gnumake gcc pkgconfig openssl check ]; +} From eacfa751f9264ab34f479441bc9837482fa9d883 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 23 Oct 2018 18:01:44 +0200 Subject: [PATCH 606/627] base58: bail out when output buffer is empty --- base58.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/base58.c b/base58.c index 6825ae56b..92612a933 100644 --- a/base58.c +++ b/base58.c @@ -44,6 +44,11 @@ const int8_t b58digits_map[] = { bool b58tobin(void *bin, size_t *binszp, const char *b58) { size_t binsz = *binszp; + + if (binsz == 0) { + return false; + } + const unsigned char *b58u = (const unsigned char*)b58; unsigned char *binu = bin; size_t outisz = (binsz + 3) / 4; From 5c6b47288323a6cafe331304d2708a3c2a45f4b0 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 23 Oct 2018 17:33:49 +0200 Subject: [PATCH 607/627] fix signed/unsigned comparison --- cash_addr.c | 2 +- segwit_addr.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cash_addr.c b/cash_addr.c index 0e6922c00..a9f3457b3 100644 --- a/cash_addr.c +++ b/cash_addr.c @@ -101,7 +101,7 @@ int cash_decode(char* hrp, uint8_t *data, size_t *data_len, const char *input) { ++(*data_len); } hrp_len = input_len - (1 + *data_len); - if (hrp_len < 1 || hrp_len > MAX_HRP_SIZE || + if (1 + *data_len >= input_len || hrp_len > MAX_HRP_SIZE || *data_len < CHECKSUM_SIZE || *data_len > CHECKSUM_SIZE + MAX_BASE32_SIZE) { return 0; } diff --git a/segwit_addr.c b/segwit_addr.c index 8202d8418..f5b8af638 100644 --- a/segwit_addr.c +++ b/segwit_addr.c @@ -97,7 +97,7 @@ int bech32_decode(char* hrp, uint8_t *data, size_t *data_len, const char *input) ++(*data_len); } hrp_len = input_len - (1 + *data_len); - if (hrp_len < 1 || *data_len < 6) { + if (1 + *data_len >= input_len || *data_len < 6) { return 0; } *(data_len) -= 6; From 2bbbc3e15573294c6dd0273d2a8542ba42507eb0 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 25 Oct 2018 11:57:03 +0200 Subject: [PATCH 608/627] cash_addr: fix hardcoded value of CHECKSUM_SIZE --- cash_addr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cash_addr.c b/cash_addr.c index a9f3457b3..0d7948a3b 100644 --- a/cash_addr.c +++ b/cash_addr.c @@ -132,7 +132,7 @@ int cash_decode(char* hrp, uint8_t *data, size_t *data_len, const char *input) { return 0; } chk = cashaddr_polymod_step(chk) ^ v; - if (i + 6 < input_len) { + if (i + CHECKSUM_SIZE < input_len) { data[i - (1 + hrp_len)] = v; } ++i; From 7079277fb0aa5db9c7cbbdec9117b8239aeccff7 Mon Sep 17 00:00:00 2001 From: Andrew Kozlik <42678794+andrewkozlik@users.noreply.github.com> Date: Fri, 30 Nov 2018 15:17:52 +0100 Subject: [PATCH 609/627] Fix counter initialization bug in rfc7539_init(). Fix const correctness in rfc7539.h and chacha20poly1305.h. (#188) --- chacha20poly1305/chacha20poly1305.c | 8 ++++---- chacha20poly1305/chacha20poly1305.h | 8 ++++---- chacha20poly1305/rfc7539.c | 5 +++-- chacha20poly1305/rfc7539.h | 4 ++-- 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/chacha20poly1305/chacha20poly1305.c b/chacha20poly1305/chacha20poly1305.c index d75ddd162..e585f0951 100644 --- a/chacha20poly1305/chacha20poly1305.c +++ b/chacha20poly1305/chacha20poly1305.c @@ -10,7 +10,7 @@ void hchacha20(ECRYPT_ctx *x,u8 *c); // Initialize the XChaCha20 + Poly1305 context for encryption or decryption // using a 32 byte key and 24 byte nonce. The key and the first 16 bytes of // the nonce are used as input to HChaCha20 to derive the Chacha20 key. -void xchacha20poly1305_init(chacha20poly1305_ctx *ctx, uint8_t key[32], uint8_t nonce[24]) { +void xchacha20poly1305_init(chacha20poly1305_ctx *ctx, const uint8_t key[32], const uint8_t nonce[24]) { unsigned char subkey[32] = {0}; unsigned char block0[64] = {0}; ECRYPT_ctx tmp; @@ -37,20 +37,20 @@ void xchacha20poly1305_init(chacha20poly1305_ctx *ctx, uint8_t key[32], uint8_t // Encrypt n bytes of plaintext where n must be evenly divisible by the // Chacha20 blocksize of 64, except for the final n bytes of plaintext. -void chacha20poly1305_encrypt(chacha20poly1305_ctx *ctx, uint8_t *in, uint8_t *out, size_t n) { +void chacha20poly1305_encrypt(chacha20poly1305_ctx *ctx, const uint8_t *in, uint8_t *out, size_t n) { ECRYPT_encrypt_bytes(&ctx->chacha20, in, out, n); poly1305_update(&ctx->poly1305, out, n); } // Decrypt n bytes of ciphertext where n must be evenly divisible by the // Chacha20 blocksize of 64, except for the final n bytes of ciphertext. -void chacha20poly1305_decrypt(chacha20poly1305_ctx *ctx, uint8_t *in, uint8_t *out, size_t n) { +void chacha20poly1305_decrypt(chacha20poly1305_ctx *ctx, const uint8_t *in, uint8_t *out, size_t n) { poly1305_update(&ctx->poly1305, in, n); ECRYPT_encrypt_bytes(&ctx->chacha20, in, out, n); } // Include authenticated data in the Poly1305 MAC. -void chacha20poly1305_auth(chacha20poly1305_ctx *ctx, uint8_t *in, size_t n) { +void chacha20poly1305_auth(chacha20poly1305_ctx *ctx, const uint8_t *in, size_t n) { poly1305_update(&ctx->poly1305, in, n); } diff --git a/chacha20poly1305/chacha20poly1305.h b/chacha20poly1305/chacha20poly1305.h index d02ea0c60..1f501f12e 100644 --- a/chacha20poly1305/chacha20poly1305.h +++ b/chacha20poly1305/chacha20poly1305.h @@ -10,10 +10,10 @@ typedef struct { poly1305_context poly1305; } chacha20poly1305_ctx; -void xchacha20poly1305_init(chacha20poly1305_ctx *ctx, uint8_t key[32], uint8_t nonce[24]); -void chacha20poly1305_encrypt(chacha20poly1305_ctx *ctx, uint8_t *in, uint8_t *out, size_t n); -void chacha20poly1305_decrypt(chacha20poly1305_ctx *ctx, uint8_t *in, uint8_t *out, size_t n); -void chacha20poly1305_auth(chacha20poly1305_ctx *ctx, uint8_t *in, size_t n); +void xchacha20poly1305_init(chacha20poly1305_ctx *ctx, const uint8_t key[32], const uint8_t nonce[24]); +void chacha20poly1305_encrypt(chacha20poly1305_ctx *ctx, const uint8_t *in, uint8_t *out, size_t n); +void chacha20poly1305_decrypt(chacha20poly1305_ctx *ctx, const uint8_t *in, uint8_t *out, size_t n); +void chacha20poly1305_auth(chacha20poly1305_ctx *ctx, const uint8_t *in, size_t n); void chacha20poly1305_finish(chacha20poly1305_ctx *ctx, uint8_t mac[16]); #endif // CHACHA20POLY1305_H diff --git a/chacha20poly1305/rfc7539.c b/chacha20poly1305/rfc7539.c index 7958e6437..94e5f0b23 100644 --- a/chacha20poly1305/rfc7539.c +++ b/chacha20poly1305/rfc7539.c @@ -7,10 +7,11 @@ // Initialize the ChaCha20 + Poly1305 context for encryption or decryption // using a 32 byte key and 12 byte nonce as in the RFC 7539 style. -void rfc7539_init(chacha20poly1305_ctx *ctx, uint8_t key[32], uint8_t nonce[12]) { +void rfc7539_init(chacha20poly1305_ctx *ctx, const uint8_t key[32], const uint8_t nonce[12]) { unsigned char block0[64] = {0}; ECRYPT_keysetup(&ctx->chacha20, key, 256, 16); + ctx->chacha20.input[12] = 0; ctx->chacha20.input[13] = U8TO32_LITTLE(nonce + 0); ctx->chacha20.input[14] = U8TO32_LITTLE(nonce + 4); ctx->chacha20.input[15] = U8TO32_LITTLE(nonce + 8); @@ -24,7 +25,7 @@ void rfc7539_init(chacha20poly1305_ctx *ctx, uint8_t key[32], uint8_t nonce[12]) // Include authenticated data in the Poly1305 MAC using the RFC 7539 // style with 16 byte padding. This must only be called once and prior // to encryption or decryption. -void rfc7539_auth(chacha20poly1305_ctx *ctx, uint8_t *in, size_t n) { +void rfc7539_auth(chacha20poly1305_ctx *ctx, const uint8_t *in, size_t n) { uint8_t padding[16] = {0}; poly1305_update(&ctx->poly1305, in, n); if (n % 16 != 0) diff --git a/chacha20poly1305/rfc7539.h b/chacha20poly1305/rfc7539.h index 2bd4990b6..75e3d1d7e 100644 --- a/chacha20poly1305/rfc7539.h +++ b/chacha20poly1305/rfc7539.h @@ -3,8 +3,8 @@ #include "chacha20poly1305.h" -void rfc7539_init(chacha20poly1305_ctx *ctx, uint8_t key[32], uint8_t nonce[12]); -void rfc7539_auth(chacha20poly1305_ctx *ctx, uint8_t *in, size_t n); +void rfc7539_init(chacha20poly1305_ctx *ctx, const uint8_t key[32], const uint8_t nonce[12]); +void rfc7539_auth(chacha20poly1305_ctx *ctx, const uint8_t *in, size_t n); void rfc7539_finish(chacha20poly1305_ctx *ctx, int64_t alen, int64_t plen, uint8_t mac[16]); #endif // RFC7539_H From c5227fdb969520de41664bfa4b66e74e718d72c4 Mon Sep 17 00:00:00 2001 From: andrew Date: Wed, 5 Dec 2018 22:05:17 +0100 Subject: [PATCH 610/627] rand.c: for testing purposes seed the pseudorandom number generator with 0 instead of the current time. This is needed to ensure identical pseudorandom outputs when running tests. --- rand.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/rand.c b/rand.c index 4ec8ab2a6..8f9bfb476 100644 --- a/rand.c +++ b/rand.c @@ -26,26 +26,31 @@ #ifndef RAND_PLATFORM_INDEPENDENT -#pragma message("NOT SUITABLE FOR PRODUCTION USE!") +#pragma message("NOT SUITABLE FOR PRODUCTION USE! Replace random8() and random32() functions with your own secure code.") // The following code is not supposed to be used in a production environment. // It's included only to make the library testable. // The message above tries to prevent any accidental use outside of the test environment. // -// You are supposed to replace the random32() function with your own secure code. +// You are supposed to replace the random8() and random32() function with your own secure code. // There is also a possibility to replace the random_buffer() function as it is defined as a weak symbol. -#include -#include +static uint8_t random8(void) +{ + // Linear congruential generator used in glibc + // https://en.wikipedia.org/wiki/Linear_congruential_generator + static int seed = 0; + seed = (1103515245 * seed + 12345) & 0x7FFFFFFF; + return seed & 0xFF; +} uint32_t random32(void) { - static int initialized = 0; - if (!initialized) { - srand((unsigned)time(NULL)); - initialized = 1; - } - return ((rand() & 0xFF) | ((rand() & 0xFF) << 8) | ((rand() & 0xFF) << 16) | ((uint32_t) (rand() & 0xFF) << 24)); + uint32_t r1 = random8(); + uint32_t r2 = random8(); + uint32_t r3 = random8(); + uint32_t r4 = random8(); + return ((r1 << 24) | (r2 << 16) | (r3 << 8) | r4); } #endif /* RAND_PLATFORM_INDEPENDENT */ From 54727e66509543b2ed01ec288d1d0c243e449a7a Mon Sep 17 00:00:00 2001 From: Tomas Susanka Date: Tue, 18 Dec 2018 11:56:25 +0100 Subject: [PATCH 611/627] rand: switch to 'Numerical Recipes' constants and remove random8 to increase period --- rand.c | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/rand.c b/rand.c index 8f9bfb476..109d15807 100644 --- a/rand.c +++ b/rand.c @@ -35,22 +35,13 @@ // You are supposed to replace the random8() and random32() function with your own secure code. // There is also a possibility to replace the random_buffer() function as it is defined as a weak symbol. -static uint8_t random8(void) -{ - // Linear congruential generator used in glibc - // https://en.wikipedia.org/wiki/Linear_congruential_generator - static int seed = 0; - seed = (1103515245 * seed + 12345) & 0x7FFFFFFF; - return seed & 0xFF; -} - uint32_t random32(void) { - uint32_t r1 = random8(); - uint32_t r2 = random8(); - uint32_t r3 = random8(); - uint32_t r4 = random8(); - return ((r1 << 24) | (r2 << 16) | (r3 << 8) | r4); + // Linear congruential generator used in glibc + // https://en.wikipedia.org/wiki/Linear_congruential_generator + static uint32_t seed = 0; + seed = 1664525 * seed + 1013904223; + return seed; } #endif /* RAND_PLATFORM_INDEPENDENT */ From b9e8adc16091f8ec162f40111d8fb6339381f0d9 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 18 Dec 2018 12:08:49 +0100 Subject: [PATCH 612/627] rand: fix typo --- rand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rand.c b/rand.c index 109d15807..70743ae6f 100644 --- a/rand.c +++ b/rand.c @@ -37,7 +37,7 @@ uint32_t random32(void) { - // Linear congruential generator used in glibc + // Linear congruential generator from Numerical Recipes // https://en.wikipedia.org/wiki/Linear_congruential_generator static uint32_t seed = 0; seed = 1664525 * seed + 1013904223; From c34e8ab3bd50243b78331e2aecf1aa169003ca28 Mon Sep 17 00:00:00 2001 From: Tomas Susanka Date: Wed, 2 Jan 2019 14:22:37 +0100 Subject: [PATCH 613/627] rand: add a reseed function to be used in tests --- rand.c | 11 ++++++++--- rand.h | 1 + 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/rand.c b/rand.c index 70743ae6f..411c755a3 100644 --- a/rand.c +++ b/rand.c @@ -25,8 +25,7 @@ #ifndef RAND_PLATFORM_INDEPENDENT - -#pragma message("NOT SUITABLE FOR PRODUCTION USE! Replace random8() and random32() functions with your own secure code.") +#pragma message("NOT SUITABLE FOR PRODUCTION USE! Replace random32() function with your own secure code.") // The following code is not supposed to be used in a production environment. // It's included only to make the library testable. @@ -35,11 +34,17 @@ // You are supposed to replace the random8() and random32() function with your own secure code. // There is also a possibility to replace the random_buffer() function as it is defined as a weak symbol. +static uint32_t seed = 0; + +void random_reseed(const uint32_t value) +{ + seed = value; +} + uint32_t random32(void) { // Linear congruential generator from Numerical Recipes // https://en.wikipedia.org/wiki/Linear_congruential_generator - static uint32_t seed = 0; seed = 1664525 * seed + 1013904223; return seed; } diff --git a/rand.h b/rand.h index 175bd9607..49d9cfaf2 100644 --- a/rand.h +++ b/rand.h @@ -27,6 +27,7 @@ #include #include +void random_reseed(const uint32_t value); uint32_t random32(void); void random_buffer(uint8_t *buf, size_t len); From 5cb2c71f0834e934de9f1f92447be15a863a46cf Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 23 Jan 2019 15:45:25 +0100 Subject: [PATCH 614/627] bignum: add assumption about i to bn_multiply_reduce_step --- bignum.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bignum.c b/bignum.c index 20c57d922..a6bba0a66 100644 --- a/bignum.c +++ b/bignum.c @@ -425,6 +425,7 @@ void bn_multiply_long(const bignum256 *k, const bignum256 *x, uint32_t res[18]) // auxiliary function for multiplication. // reduces res modulo prime. +// assumes i >= 8 and i <= 16 // assumes res normalized, res < 2^(30(i-7)) * 2 * prime // guarantees res normalized, res < 2^(30(i-8)) * 2 * prime void bn_multiply_reduce_step(uint32_t res[18], const bignum256 *prime, uint32_t i) { @@ -436,6 +437,7 @@ void bn_multiply_reduce_step(uint32_t res[18], const bignum256 *prime, uint32_t // 0 <= coef < 2^31 // subtract (coef * 2^(30k) * prime) from res // note that we unrolled the first iteration + assert(i >= 8 && i <= 16); uint32_t j; uint32_t coef = (res[i] >> 16) + (res[i + 1] << 14); uint64_t temp = 0x2000000000000000ull + res[i - 8] - prime->val[0] * (uint64_t)coef; From c316e775a2152db255ace96b6b65ac0f20525ec0 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 23 Jan 2019 16:43:34 +0100 Subject: [PATCH 615/627] replace all usage of memset(_, 0, _) with memzero --- base58.c | 4 +- bip32.c | 10 ++--- blake2b.c | 22 +++++----- blake2s.c | 22 +++++----- ed25519-donna/ed25519-donna-impl-base.c | 9 ++-- groestl.c | 4 +- hmac.c | 4 +- pbkdf2.c | 4 +- ripemd160.c | 2 +- sha3.c | 6 +-- shell.nix | 2 +- tests/test_check.c | 58 +++++++++++++------------ tests/test_openssl.c | 4 +- 13 files changed, 79 insertions(+), 72 deletions(-) diff --git a/base58.c b/base58.c index 92612a933..cd74617b8 100644 --- a/base58.c +++ b/base58.c @@ -63,7 +63,7 @@ bool b58tobin(void *bin, size_t *binszp, const char *b58) b58sz = strlen(b58); - memset(outi, 0, outisz * sizeof(*outi)); + memzero(outi, sizeof(outi)); // Leading zeros, just count for (i = 0; i < b58sz && b58u[i] == '1'; ++i) @@ -166,7 +166,7 @@ bool b58enc(char *b58, size_t *b58sz, const void *data, size_t binsz) size = (binsz - zcount) * 138 / 100 + 1; uint8_t buf[size]; - memset(buf, 0, size); + memzero(buf, size); for (i = zcount, high = size - 1; i < (ssize_t)binsz; ++i, high = j) { diff --git a/bip32.c b/bip32.c index 54e26b42e..8d6291f51 100644 --- a/bip32.c +++ b/bip32.c @@ -152,7 +152,7 @@ int hdnode_from_xprv(uint32_t depth, uint32_t child_num, const uint8_t *chain_co int hdnode_from_seed(const uint8_t *seed, int seed_len, const char* curve, HDNode *out) { static CONFIDENTIAL uint8_t I[32 + 32]; - memset(out, 0, sizeof(HDNode)); + memzero(out, sizeof(HDNode)); out->depth = 0; out->child_num = 0; out->curve = get_curve_by_name(curve); @@ -319,7 +319,7 @@ int hdnode_private_ckd_cardano(HDNode *inout, uint32_t index) hmac_sha512_Final(&ctx, z); static CONFIDENTIAL uint8_t zl8[32]; - memset(zl8, 0, 32); + memzero(zl8, 32); /* get 8 * Zl */ scalar_multiply8(z, 28, zl8); @@ -362,7 +362,7 @@ int hdnode_from_seed_cardano(const uint8_t *pass, int pass_len, const uint8_t *s secret[31] &= 31; secret[31] |= 64; - memset(out, 0, sizeof(HDNode)); + memzero(out, sizeof(HDNode)); out->depth = 0; out->child_num = 0; out->curve = get_curve_by_name(ED25519_CARDANO_NAME); @@ -516,7 +516,7 @@ int hdnode_private_ckd_cached(HDNode *inout, const uint32_t *i, size_t i_count, if (hdnode_private_ckd(inout, i[k]) == 0) return 0; } // and save it - memset(&(private_ckd_cache[private_ckd_cache_index]), 0, sizeof(private_ckd_cache[private_ckd_cache_index])); + memzero(&(private_ckd_cache[private_ckd_cache_index]), sizeof(private_ckd_cache[private_ckd_cache_index])); private_ckd_cache[private_ckd_cache_index].set = true; private_ckd_cache[private_ckd_cache_index].depth = i_count - 1; memcpy(private_ckd_cache[private_ckd_cache_index].i, i, (i_count - 1) * sizeof(uint32_t)); @@ -782,7 +782,7 @@ int hdnode_serialize_private(const HDNode *node, uint32_t fingerprint, uint32_t int hdnode_deserialize(const char *str, uint32_t version_public, uint32_t version_private, const char *curve, HDNode *node, uint32_t *fingerprint) { uint8_t node_data[78]; - memset(node, 0, sizeof(HDNode)); + memzero(node, sizeof(HDNode)); node->curve = get_curve_by_name(curve); if (base58_decode_check(str, node->curve->hasher_base58, node_data, sizeof(node_data)) != sizeof(node_data)) { return -1; diff --git a/blake2b.c b/blake2b.c index 67d97e7e6..0074bc18d 100644 --- a/blake2b.c +++ b/blake2b.c @@ -87,7 +87,7 @@ static void blake2b_increment_counter( blake2b_state *S, const uint64_t inc ) static void blake2b_init0( blake2b_state *S ) { size_t i; - memset( S, 0, sizeof( blake2b_state ) ); + memzero( S, sizeof( blake2b_state ) ); for( i = 0; i < 8; ++i ) S->h[i] = blake2b_IV[i]; } @@ -125,9 +125,9 @@ int blake2b_Init( blake2b_state *S, size_t outlen ) store32( &P->xof_length, 0 ); P->node_depth = 0; P->inner_length = 0; - memset( P->reserved, 0, sizeof( P->reserved ) ); - memset( P->salt, 0, sizeof( P->salt ) ); - memset( P->personal, 0, sizeof( P->personal ) ); + memzero( P->reserved, sizeof( P->reserved ) ); + memzero( P->salt, sizeof( P->salt ) ); + memzero( P->personal, sizeof( P->personal ) ); return blake2b_init_param( S, P ); } @@ -147,8 +147,8 @@ int blake2b_InitPersonal( blake2b_state *S, size_t outlen, const void *personal, store32( &P->xof_length, 0 ); P->node_depth = 0; P->inner_length = 0; - memset( P->reserved, 0, sizeof( P->reserved ) ); - memset( P->salt, 0, sizeof( P->salt ) ); + memzero( P->reserved, sizeof( P->reserved ) ); + memzero( P->salt, sizeof( P->salt ) ); memcpy( P->personal, personal, BLAKE2B_PERSONALBYTES ); return blake2b_init_param( S, P ); } @@ -170,15 +170,15 @@ int blake2b_InitKey( blake2b_state *S, size_t outlen, const void *key, size_t ke store32( &P->xof_length, 0 ); P->node_depth = 0; P->inner_length = 0; - memset( P->reserved, 0, sizeof( P->reserved ) ); - memset( P->salt, 0, sizeof( P->salt ) ); - memset( P->personal, 0, sizeof( P->personal ) ); + memzero( P->reserved, sizeof( P->reserved ) ); + memzero( P->salt, sizeof( P->salt ) ); + memzero( P->personal, sizeof( P->personal ) ); if( blake2b_init_param( S, P ) < 0 ) return -1; { uint8_t block[BLAKE2B_BLOCKBYTES]; - memset( block, 0, BLAKE2B_BLOCKBYTES ); + memzero( block, BLAKE2B_BLOCKBYTES ); memcpy( block, key, keylen ); blake2b_Update( S, block, BLAKE2B_BLOCKBYTES ); memzero( block, BLAKE2B_BLOCKBYTES ); /* Burn the key from stack */ @@ -294,7 +294,7 @@ int blake2b_Final( blake2b_state *S, void *out, size_t outlen ) blake2b_increment_counter( S, S->buflen ); blake2b_set_lastblock( S ); - memset( S->buf + S->buflen, 0, BLAKE2B_BLOCKBYTES - S->buflen ); /* Padding */ + memzero( S->buf + S->buflen, BLAKE2B_BLOCKBYTES - S->buflen ); /* Padding */ blake2b_compress( S, S->buf ); for( i = 0; i < 8; ++i ) /* Output full hash to temp buffer */ diff --git a/blake2s.c b/blake2s.c index 57435e7a1..8dc6516b6 100644 --- a/blake2s.c +++ b/blake2s.c @@ -82,7 +82,7 @@ static void blake2s_increment_counter( blake2s_state *S, const uint32_t inc ) static void blake2s_init0( blake2s_state *S ) { size_t i; - memset( S, 0, sizeof( blake2s_state ) ); + memzero( S, sizeof( blake2s_state ) ); for( i = 0; i < 8; ++i ) S->h[i] = blake2s_IV[i]; } @@ -120,9 +120,9 @@ int blake2s_Init( blake2s_state *S, size_t outlen ) store16( &P->xof_length, 0 ); P->node_depth = 0; P->inner_length = 0; - /* memset(P->reserved, 0, sizeof(P->reserved) ); */ - memset( P->salt, 0, sizeof( P->salt ) ); - memset( P->personal, 0, sizeof( P->personal ) ); + /* memzero(P->reserved, sizeof(P->reserved) ); */ + memzero( P->salt, sizeof( P->salt ) ); + memzero( P->personal, sizeof( P->personal ) ); return blake2s_init_param( S, P ); } @@ -142,8 +142,8 @@ int blake2s_InitPersonal( blake2s_state *S, size_t outlen, const void *personal, store16( &P->xof_length, 0 ); P->node_depth = 0; P->inner_length = 0; - /* memset(P->reserved, 0, sizeof(P->reserved) ); */ - memset( P->salt, 0, sizeof( P->salt ) ); + /* memzero(P->reserved, sizeof(P->reserved) ); */ + memzero( P->salt, sizeof( P->salt ) ); memcpy( P->personal, personal, BLAKE2S_PERSONALBYTES ); return blake2s_init_param( S, P ); } @@ -166,15 +166,15 @@ int blake2s_InitKey( blake2s_state *S, size_t outlen, const void *key, size_t ke store16( &P->xof_length, 0 ); P->node_depth = 0; P->inner_length = 0; - /* memset(P->reserved, 0, sizeof(P->reserved) ); */ - memset( P->salt, 0, sizeof( P->salt ) ); - memset( P->personal, 0, sizeof( P->personal ) ); + /* memzero(P->reserved, sizeof(P->reserved) ); */ + memzero( P->salt, sizeof( P->salt ) ); + memzero( P->personal, sizeof( P->personal ) ); if( blake2s_init_param( S, P ) < 0 ) return -1; { uint8_t block[BLAKE2S_BLOCKBYTES]; - memset( block, 0, BLAKE2S_BLOCKBYTES ); + memzero( block, BLAKE2S_BLOCKBYTES ); memcpy( block, key, keylen ); blake2s_Update( S, block, BLAKE2S_BLOCKBYTES ); memzero( block, BLAKE2S_BLOCKBYTES ); /* Burn the key from stack */ @@ -288,7 +288,7 @@ int blake2s_Final( blake2s_state *S, void *out, size_t outlen ) blake2s_increment_counter( S, ( uint32_t )S->buflen ); blake2s_set_lastblock( S ); - memset( S->buf + S->buflen, 0, BLAKE2S_BLOCKBYTES - S->buflen ); /* Padding */ + memzero( S->buf + S->buflen, BLAKE2S_BLOCKBYTES - S->buflen ); /* Padding */ blake2s_compress( S, S->buf ); for( i = 0; i < 8; ++i ) /* Output full hash to temp buffer */ diff --git a/ed25519-donna/ed25519-donna-impl-base.c b/ed25519-donna/ed25519-donna-impl-base.c index 2fa1fa424..fcd1c0053 100644 --- a/ed25519-donna/ed25519-donna-impl-base.c +++ b/ed25519-donna/ed25519-donna-impl-base.c @@ -1,5 +1,6 @@ #include #include "ed25519-donna.h" +#include "memzero.h" /* sqrt(x) is such an integer y that 0 <= y <= p - 1, y % 2 = 0, and y^2 = x (mod p). */ /* d = -121665 / 121666 */ @@ -245,7 +246,7 @@ int ge25519_unpack_negative_vartime(ge25519 *r, const unsigned char p[32]) { void ge25519_set_neutral(ge25519 *r) { - memset(r, 0, sizeof(ge25519)); + memzero(r, sizeof(ge25519)); r->y[0] = 1; r->z[0] = 1; } @@ -270,7 +271,7 @@ void ge25519_double_scalarmult_vartime(ge25519 *r, const ge25519 *p1, const bign ge25519_p1p1 t; int32_t i; - memset(&t, 0, sizeof(ge25519_p1p1)); + memzero(&t, sizeof(ge25519_p1p1)); contract256_slidingwindow_modm(slide1, s1, S1_SWINDOWSIZE); contract256_slidingwindow_modm(slide2, s2, S2_SWINDOWSIZE); @@ -324,7 +325,7 @@ void ge25519_double_scalarmult_vartime2(ge25519 *r, const ge25519 *p1, const big ge25519_p1p1 t; int32_t i; - memset(&t, 0, sizeof(ge25519_p1p1)); + memzero(&t, sizeof(ge25519_p1p1)); contract256_slidingwindow_modm(slide1, s1, S1_SWINDOWSIZE); contract256_slidingwindow_modm(slide2, s2, S1_SWINDOWSIZE); @@ -512,7 +513,7 @@ void ge25519_scalarmult_base_niels(ge25519 *r, const uint8_t basepoint_table[256 ge25519_scalarmult_base_choose_niels(&t, basepoint_table, 0, b[1]); curve25519_sub_reduce(r->x, t.xaddy, t.ysubx); curve25519_add_reduce(r->y, t.xaddy, t.ysubx); - memset(r->z, 0, sizeof(bignum25519)); + memzero(r->z, sizeof(bignum25519)); curve25519_copy(r->t, t.t2d); r->z[0] = 2; for (i = 3; i < 64; i += 2) { diff --git a/groestl.c b/groestl.c index f72fe0fc0..8efe82a86 100644 --- a/groestl.c +++ b/groestl.c @@ -36,6 +36,8 @@ #include "groestl_internal.h" #include "groestl.h" +#include "memzero.h" + #define C32e(x) ((SPH_C32(x) >> 24) \ | ((SPH_C32(x) >> 8) & SPH_C32(0x0000FF00)) \ @@ -740,7 +742,7 @@ groestl_big_close(sph_groestl_big_context *sc, pad_len = 256 - ptr; count = SPH_T64(sc->count + 2); } - memset(pad + 1, 0, pad_len - 9); + memzero(pad + 1, pad_len - 9); sph_enc64be(pad + pad_len - 8, count); groestl_big_core(sc, pad, pad_len); READ_STATE_BIG(sc); diff --git a/hmac.c b/hmac.c index 04448c8f2..0a0946012 100644 --- a/hmac.c +++ b/hmac.c @@ -30,7 +30,7 @@ void hmac_sha256_Init(HMAC_SHA256_CTX *hctx, const uint8_t *key, const uint32_t keylen) { static CONFIDENTIAL uint8_t i_key_pad[SHA256_BLOCK_LENGTH]; - memset(i_key_pad, 0, SHA256_BLOCK_LENGTH); + memzero(i_key_pad, SHA256_BLOCK_LENGTH); if (keylen > SHA256_BLOCK_LENGTH) { sha256_Raw(key, keylen, i_key_pad); } else { @@ -105,7 +105,7 @@ void hmac_sha256_prepare(const uint8_t *key, const uint32_t keylen, uint32_t *op void hmac_sha512_Init(HMAC_SHA512_CTX *hctx, const uint8_t *key, const uint32_t keylen) { static CONFIDENTIAL uint8_t i_key_pad[SHA512_BLOCK_LENGTH]; - memset(i_key_pad, 0, SHA512_BLOCK_LENGTH); + memzero(i_key_pad, SHA512_BLOCK_LENGTH); if (keylen > SHA512_BLOCK_LENGTH) { sha512_Raw(key, keylen, i_key_pad); } else { diff --git a/pbkdf2.c b/pbkdf2.c index 23644ea73..719fc89e2 100644 --- a/pbkdf2.c +++ b/pbkdf2.c @@ -35,7 +35,7 @@ void pbkdf2_hmac_sha256_Init(PBKDF2_HMAC_SHA256_CTX *pctx, const uint8_t *pass, #endif hmac_sha256_prepare(pass, passlen, pctx->odig, pctx->idig); - memset(pctx->g, 0, sizeof(pctx->g)); + memzero(pctx->g, sizeof(pctx->g)); pctx->g[8] = 0x80000000; pctx->g[15] = (SHA256_BLOCK_LENGTH + SHA256_DIGEST_LENGTH) * 8; @@ -109,7 +109,7 @@ void pbkdf2_hmac_sha512_Init(PBKDF2_HMAC_SHA512_CTX *pctx, const uint8_t *pass, #endif hmac_sha512_prepare(pass, passlen, pctx->odig, pctx->idig); - memset(pctx->g, 0, sizeof(pctx->g)); + memzero(pctx->g, sizeof(pctx->g)); pctx->g[8] = 0x8000000000000000; pctx->g[15] = (SHA512_BLOCK_LENGTH + SHA512_DIGEST_LENGTH) * 8; diff --git a/ripemd160.c b/ripemd160.c index 66b13ca3d..60d007acf 100644 --- a/ripemd160.c +++ b/ripemd160.c @@ -58,7 +58,7 @@ */ void ripemd160_Init(RIPEMD160_CTX *ctx) { - memset(ctx, 0, sizeof(RIPEMD160_CTX)); + memzero(ctx, sizeof(RIPEMD160_CTX)); ctx->total[0] = 0; ctx->total[1] = 0; ctx->state[0] = 0x67452301; diff --git a/sha3.c b/sha3.c index 3ef9db8ae..7cc2b7d40 100644 --- a/sha3.c +++ b/sha3.c @@ -48,7 +48,7 @@ static void keccak_Init(SHA3_CTX *ctx, unsigned bits) /* NB: The Keccak capacity parameter = bits * 2 */ unsigned rate = 1600 - bits * 2; - memset(ctx, 0, sizeof(SHA3_CTX)); + memzero(ctx, sizeof(SHA3_CTX)); ctx->block_size = rate / 8; assert(rate <= 1600 && (rate % 64) == 0); } @@ -320,7 +320,7 @@ void sha3_Final(SHA3_CTX *ctx, unsigned char* result) if (!(ctx->rest & SHA3_FINALIZED)) { /* clear the rest of the data queue */ - memset((char*)ctx->message + ctx->rest, 0, block_size - ctx->rest); + memzero((char*)ctx->message + ctx->rest, block_size - ctx->rest); ((char*)ctx->message)[ctx->rest] |= 0x06; ((char*)ctx->message)[block_size - 1] |= 0x80; @@ -349,7 +349,7 @@ void keccak_Final(SHA3_CTX *ctx, unsigned char* result) if (!(ctx->rest & SHA3_FINALIZED)) { /* clear the rest of the data queue */ - memset((char*)ctx->message + ctx->rest, 0, block_size - ctx->rest); + memzero((char*)ctx->message + ctx->rest, block_size - ctx->rest); ((char*)ctx->message)[ctx->rest] |= 0x01; ((char*)ctx->message)[block_size - 1] |= 0x80; diff --git a/shell.nix b/shell.nix index 52601dd7b..0cfc3dd05 100644 --- a/shell.nix +++ b/shell.nix @@ -2,5 +2,5 @@ with import {}; stdenv.mkDerivation { name = "trezor-crypto-dev"; - buildInputs = [ gnumake gcc pkgconfig openssl check ]; + buildInputs = [ gnumake gcc pkgconfig openssl check valgrind ]; } diff --git a/tests/test_check.c b/tests/test_check.c index 25baeccca..e72c16a2a 100644 --- a/tests/test_check.c +++ b/tests/test_check.c @@ -64,6 +64,8 @@ #include "rc4.h" #include "nem.h" #include "monero/monero.h" +#include "memzero.h" + #if VALGRIND /* @@ -862,7 +864,7 @@ START_TEST(test_bip32_vector_1) ck_assert_str_eq(str, "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8"); r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); - memset(&node3.private_key, 0, 32); + memzero(&node3.private_key, 32); ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); // [Chain m/0'] @@ -882,7 +884,7 @@ START_TEST(test_bip32_vector_1) ck_assert_str_eq(str, "xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw"); r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); - memset(&node3.private_key, 0, 32); + memzero(&node3.private_key, 32); ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); // [Chain m/0'/1] @@ -902,7 +904,7 @@ START_TEST(test_bip32_vector_1) ck_assert_str_eq(str, "xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFHKkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ"); r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); - memset(&node3.private_key, 0, 32); + memzero(&node3.private_key, 32); ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); // [Chain m/0'/1/2'] @@ -922,7 +924,7 @@ START_TEST(test_bip32_vector_1) ck_assert_str_eq(str, "xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5"); r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); - memset(&node3.private_key, 0, 32); + memzero(&node3.private_key, 32); ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); // [Chain m/0'/1/2'/2] @@ -942,7 +944,7 @@ START_TEST(test_bip32_vector_1) ck_assert_str_eq(str, "xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV"); r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); - memset(&node3.private_key, 0, 32); + memzero(&node3.private_key, 32); ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); // [Chain m/0'/1/2'/2/1000000000] @@ -962,7 +964,7 @@ START_TEST(test_bip32_vector_1) ck_assert_str_eq(str, "xpub6H1LXWLaKsWFhvm6RVpEL9P4KfRZSW7abD2ttkWP3SSQvnyA8FSVqNTEcYFgJS2UaFcxupHiYkro49S8yGasTvXEYBVPamhGW6cFJodrTHy"); r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); - memset(&node3.private_key, 0, 32); + memzero(&node3.private_key, 32); ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); } END_TEST @@ -994,7 +996,7 @@ START_TEST(test_bip32_vector_2) ck_assert_str_eq(str, "xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB"); r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); - memset(&node3.private_key, 0, 32); + memzero(&node3.private_key, 32); ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); // [Chain m/0] @@ -1015,7 +1017,7 @@ START_TEST(test_bip32_vector_2) ck_assert_str_eq(str, "xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH"); r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); - memset(&node3.private_key, 0, 32); + memzero(&node3.private_key, 32); ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); // [Chain m/0/2147483647'] @@ -1036,7 +1038,7 @@ START_TEST(test_bip32_vector_2) ck_assert_str_eq(str, "xpub6ASAVgeehLbnwdqV6UKMHVzgqAG8Gr6riv3Fxxpj8ksbH9ebxaEyBLZ85ySDhKiLDBrQSARLq1uNRts8RuJiHjaDMBU4Zn9h8LZNnBC5y4a"); r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); - memset(&node3.private_key, 0, 32); + memzero(&node3.private_key, 32); ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); // [Chain m/0/2147483647'/1] @@ -1057,7 +1059,7 @@ START_TEST(test_bip32_vector_2) ck_assert_str_eq(str, "xpub6DF8uhdarytz3FWdA8TvFSvvAh8dP3283MY7p2V4SeE2wyWmG5mg5EwVvmdMVCQcoNJxGoWaU9DCWh89LojfZ537wTfunKau47EL2dhHKon"); r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); - memset(&node3.private_key, 0, 32); + memzero(&node3.private_key, 32); ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); // [Chain m/0/2147483647'/1/2147483646'] @@ -1078,7 +1080,7 @@ START_TEST(test_bip32_vector_2) ck_assert_str_eq(str, "xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL"); r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); - memset(&node3.private_key, 0, 32); + memzero(&node3.private_key, 32); ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); // [Chain m/0/2147483647'/1/2147483646'/2] @@ -1099,7 +1101,7 @@ START_TEST(test_bip32_vector_2) ck_assert_str_eq(str, "xpub6FnCn6nSzZAw5Tw7cgR9bi15UV96gLZhjDstkXXxvCLsUXBGXPdSnLFbdpq8p9HmGsApME5hQTZ3emM2rnY5agb9rXpVGyy3bdW6EEgAtqt"); r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); - memset(&node3.private_key, 0, 32); + memzero(&node3.private_key, 32); ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); // init m @@ -1142,7 +1144,7 @@ START_TEST(test_bip32_vector_3) ck_assert_str_eq(str, "xpub661MyMwAqRbcEZVB4dScxMAdx6d4nFc9nvyvH3v4gJL378CSRZiYmhRoP7mBy6gSPSCYk6SzXPTf3ND1cZAceL7SfJ1Z3GC8vBgp2epUt13"); r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); - memset(&node3.private_key, 0, 32); + memzero(&node3.private_key, 32); ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); // [Chain m/0'] @@ -1159,7 +1161,7 @@ START_TEST(test_bip32_vector_3) ck_assert_str_eq(str, "xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y"); r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); - memset(&node3.private_key, 0, 32); + memzero(&node3.private_key, 32); ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); } END_TEST @@ -1517,7 +1519,7 @@ START_TEST(test_bip32_nist_repeat) ck_assert_mem_eq(node2.public_key, fromhex("0235bfee614c0d5b2cae260000bb1d0d84b270099ad790022c1ae0b2e782efe120"), 33); memcpy(&node2, &node, sizeof(HDNode)); - memset(&node2.private_key, 0, 32); + memzero(&node2.private_key, 32); r = hdnode_public_ckd(&node2, 33941); ck_assert_int_eq(r, 1); ck_assert_int_eq(fingerprint, 0x3e2b7bc6); @@ -1665,7 +1667,7 @@ START_TEST(test_bip32_decred_vector_1) ck_assert_str_eq(str, "dpubZ9169KDAEUnyoBhjjmT2VaEodr6pUTDoqCEAeqgbfr2JfkB88BbK77jbTYbcYXb2FVz7DKBdW4P618yd51MwF8DjKVopSbS7Lkgi6bowX5w"); r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); - memset(&node3.private_key, 0, 32); + memzero(&node3.private_key, 32); ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); // [Chain m/0'] @@ -1685,7 +1687,7 @@ START_TEST(test_bip32_decred_vector_1) ck_assert_str_eq(str, "dpubZCGVaKZBiMo7pMgLaZm1qmchjWenTeVcUdFQkTNsFGFEA6xs4EW8PKiqYqP7HBAitt9Hw16VQkQ1tjsZQSHNWFc6bEK6bLqrbco24FzBTY4"); r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); - memset(&node3.private_key, 0, 32); + memzero(&node3.private_key, 32); ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); // [Chain m/0'/1] @@ -1705,7 +1707,7 @@ START_TEST(test_bip32_decred_vector_1) ck_assert_str_eq(str, "dpubZEDyZgdnFBMHxqNhfCUwBfAg1UmXHiTmB5jKtzbAZhF8PTzy2PwAicNdkg1CmW6TARxQeUbgC7nAQenJts4YoG3KMiqcjsjgeMvwLc43w6C"); r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); - memset(&node3.private_key, 0, 32); + memzero(&node3.private_key, 32); ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); // [Chain m/0'/1/2'] @@ -1725,7 +1727,7 @@ START_TEST(test_bip32_decred_vector_1) ck_assert_str_eq(str, "dpubZGLz7gsJAWzUksvtw3opxx5eeLq5fRaUMDABA3bdUVfnGUk5fiS5Cc3kZGTjWtYr3jrEavQQnAF6jv2WCpZtFX4uFgifXqev6ED1TM9rTCB"); r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); - memset(&node3.private_key, 0, 32); + memzero(&node3.private_key, 32); ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); // [Chain m/0'/1/2'/2] @@ -1745,7 +1747,7 @@ START_TEST(test_bip32_decred_vector_1) ck_assert_str_eq(str, "dpubZHv6Cfp2XRSWHQXZBo1dLmVM421Zdkc4MePkyBXCLFttVkCmwZkxth4ZV9PzkFP3DtD5xcVq2CPSYpJMWMaoxu1ixz4GNZFVcE2xnHP6chJ"); r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); - memset(&node3.private_key, 0, 32); + memzero(&node3.private_key, 32); ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); // [Chain m/0'/1/2'/2/1000000000] @@ -1765,7 +1767,7 @@ START_TEST(test_bip32_decred_vector_1) ck_assert_str_eq(str, "dpubZL6d9amjfRy1zeoZM2zHDU7uoMvwPqtxHRQAiJjeEtQQWjP3retQV1qKJyzUd6ZJNgbJGXjtc5pdoBcTTYTLoxQzvV9JJCzCjB2eCWpRf8T"); r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); - memset(&node3.private_key, 0, 32); + memzero(&node3.private_key, 32); ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); } END_TEST @@ -1800,7 +1802,7 @@ START_TEST(test_bip32_decred_vector_2) ck_assert_str_eq(str, "dpubZ9169KDAEUnynoD4qvXJwmxZt3FFA5UdWn1twnRReE9AxjCKJLNFY1uBoegbFmwzA4Du7yqnu8tLivhrCCH6P3DgBS1HH5vmf8MpNXvvYT9"); r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); - memset(&node3.private_key, 0, 32); + memzero(&node3.private_key, 32); ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); // [Chain m/0] @@ -1821,7 +1823,7 @@ START_TEST(test_bip32_decred_vector_2) ck_assert_str_eq(str, "dpubZBA4RCkCybJFaNbqPuBiyfXY1rvmG1XTdCy1AY1U96dxkFqWc2i5KREMh7NYPpy7ZPMhdpFMAesex3JdFDfX4J5FEW3HjSacqEYPfwb9Cj7"); r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); - memset(&node3.private_key, 0, 32); + memzero(&node3.private_key, 32); ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); // [Chain m/0/2147483647'] @@ -1842,7 +1844,7 @@ START_TEST(test_bip32_decred_vector_2) ck_assert_str_eq(str, "dpubZDUNkZEcCRCZEizDGL9sAQbZRKSnaxQLeqN9zpueeqCyq2VY7NUGMXASacsK96S8XzNjq3YgFgwLtj8MJBToW6To9U5zxuazEyh89bjR1xA"); r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); - memset(&node3.private_key, 0, 32); + memzero(&node3.private_key, 32); ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); // [Chain m/0/2147483647'/1] @@ -1863,7 +1865,7 @@ START_TEST(test_bip32_decred_vector_2) ck_assert_str_eq(str, "dpubZF3wJh7SfggGg74QZW3EE9ei8uQSJEFgd62uyuK5iMgQzUNjpSnprgTpYz3d6Q3fXXtEEXQqpzWcP4LUVuXFsgA8JKt1Hot5kyUk4pPRhDz"); r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); - memset(&node3.private_key, 0, 32); + memzero(&node3.private_key, 32); ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); // [Chain m/0/2147483647'/1/2147483646'] @@ -1884,7 +1886,7 @@ START_TEST(test_bip32_decred_vector_2) ck_assert_str_eq(str, "dpubZH38NEg1CW19dGZs8NdaT4hDkz7wXPstio1mGpHSAXHpSGW3UnTrn25ERT1Mp8ae5GMoQHMbgQiPrChMXQMdx3UqS8YqFkT1pqait8fY92u"); r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); - memset(&node3.private_key, 0, 32); + memzero(&node3.private_key, 32); ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); // [Chain m/0/2147483647'/1/2147483646'/2] @@ -1905,7 +1907,7 @@ START_TEST(test_bip32_decred_vector_2) ck_assert_str_eq(str, "dpubZJoBFoQJ35zvEBgsfhJBssnAp8TY5gvruzQFLmyxcqRb7enVtGfSkLo2CkAZJMpa6T2fx6fUtvTgXtUvSVgAZ56bEwGxQsToeZfFV8VadE1"); r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); memcpy(&node3, &node, sizeof(HDNode)); - memset(&node3.private_key, 0, 32); + memzero(&node3.private_key, 32); ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); // init m @@ -4788,7 +4790,7 @@ START_TEST(test_rc4_rfc6229) for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { size_t length = strlen(tests[i].key) / 2; memcpy(key, fromhex(tests[i].key), length); - memset(buffer, 0, sizeof(buffer)); + memzero(buffer, sizeof(buffer)); rc4_init(&ctx, key, length); rc4_encrypt(&ctx, buffer, sizeof(buffer)); diff --git a/tests/test_openssl.c b/tests/test_openssl.c index b067bf383..d0a80f074 100644 --- a/tests/test_openssl.c +++ b/tests/test_openssl.c @@ -43,6 +43,8 @@ #include "nist256p1.h" #include "secp256k1.h" +#include "memzero.h" + void openssl_check(unsigned int iterations, int nid, const ecdsa_curve *curve) { uint8_t sig[64], pub_key33[33], pub_key65[65], priv_key[32], msg[256], hash[32]; @@ -67,7 +69,7 @@ void openssl_check(unsigned int iterations, int nid, const ecdsa_curve *curve) // copy key to buffer const BIGNUM *K = EC_KEY_get0_private_key(eckey); int bn_off = sizeof(priv_key) - BN_num_bytes(K); - memset(priv_key, 0, bn_off); + memzero(priv_key, bn_off); BN_bn2bin(K, priv_key + bn_off); // use our ECDSA signer to sign the message with the key From d1c52401e4c76c74a10455682ace0655b7aa644c Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 23 Jan 2019 18:35:30 +0100 Subject: [PATCH 616/627] bip39: remove indexes functions, add mnemonic_clear function --- bip39.c | 43 +++---------------------------------------- bip39.h | 4 +--- 2 files changed, 4 insertions(+), 43 deletions(-) diff --git a/bip39.c b/bip39.c index 8608fd456..f639c94f3 100644 --- a/bip39.c +++ b/bip39.c @@ -58,17 +58,7 @@ const char *mnemonic_generate(int strength) return r; } -const uint16_t *mnemonic_generate_indexes(int strength) -{ - if (strength % 32 || strength < 128 || strength > 256) { - return 0; - } - uint8_t data[32]; - random_buffer(data, 32); - const uint16_t *r = mnemonic_from_data_indexes(data, strength / 8); - memzero(data, sizeof(data)); - return r; -} +static CONFIDENTIAL char mnemo[24 * 10]; const char *mnemonic_from_data(const uint8_t *data, int len) { @@ -85,7 +75,6 @@ const char *mnemonic_from_data(const uint8_t *data, int len) memcpy(bits, data, len); int mlen = len * 3 / 4; - static CONFIDENTIAL char mnemo[24 * 10]; int i, j, idx; char *p = mnemo; @@ -105,35 +94,9 @@ const char *mnemonic_from_data(const uint8_t *data, int len) return mnemo; } -const uint16_t *mnemonic_from_data_indexes(const uint8_t *data, int len) +void mnemonic_clear(void) { - if (len % 4 || len < 16 || len > 32) { - return 0; - } - - uint8_t bits[32 + 1]; - - sha256_Raw(data, len, bits); - // checksum - bits[len] = bits[0]; - // data - memcpy(bits, data, len); - - int mlen = len * 3 / 4; - static CONFIDENTIAL uint16_t mnemo[24]; - - int i, j, idx; - for (i = 0; i < mlen; i++) { - idx = 0; - for (j = 0; j < 11; j++) { - idx <<= 1; - idx += (bits[(i * 11 + j) / 8] & (1 << (7 - ((i * 11 + j) % 8)))) > 0; - } - mnemo[i] = idx; - } - memzero(bits, sizeof(bits)); - - return mnemo; + memzero(mnemo, sizeof(mnemo)); } int mnemonic_to_entropy(const char *mnemonic, uint8_t *entropy) diff --git a/bip39.h b/bip39.h index b4216b47c..1020d05f3 100644 --- a/bip39.h +++ b/bip39.h @@ -29,10 +29,8 @@ #define BIP39_PBKDF2_ROUNDS 2048 const char *mnemonic_generate(int strength); // strength in bits -const uint16_t *mnemonic_generate_indexes(int strength); // strength in bits - const char *mnemonic_from_data(const uint8_t *data, int len); -const uint16_t *mnemonic_from_data_indexes(const uint8_t *data, int len); +void mnemonic_clear(void); int mnemonic_check(const char *mnemonic); From e829823f1e2d7e0be86276b8878ec2fff7b05666 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 23 Jan 2019 19:39:17 +0100 Subject: [PATCH 617/627] use memzero from libsodium --- memzero.c | 23 +++++++++++++++++++++-- memzero.h | 2 +- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/memzero.c b/memzero.c index 68fad584b..6fda42119 100644 --- a/memzero.c +++ b/memzero.c @@ -1,6 +1,25 @@ #include +#include -void memzero(void *s, size_t n) +// taken from https://github.com/jedisct1/libsodium/blob/1647f0d53ae0e370378a9195477e3df0a792408f/src/libsodium/sodium/utils.c#L102-L130 + +void memzero(void *const pnt, const size_t len) { - memset(s, 0, n); +#ifdef _WIN32 + SecureZeroMemory(pnt, len); +#elif defined(HAVE_MEMSET_S) + memset_s(pnt, (rsize_t) len, 0, (rsize_t) len); +#elif defined(HAVE_EXPLICIT_BZERO) + explicit_bzero(pnt, len); +#elif defined(HAVE_EXPLICIT_MEMSET) + explicit_memset(pnt, 0, len); +#else + volatile unsigned char *volatile pnt_ = + (volatile unsigned char *volatile) pnt; + size_t i = (size_t) 0U; + + while (i < len) { + pnt_[i++] = 0U; + } +#endif } diff --git a/memzero.h b/memzero.h index ce51acaef..a7797d2b3 100644 --- a/memzero.h +++ b/memzero.h @@ -3,6 +3,6 @@ #include -void memzero(void *s, size_t n); +void memzero(void * const pnt, const size_t len); #endif From b7e99aa76c36417b797add2addba03121b758e66 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 23 Jan 2019 20:04:57 +0100 Subject: [PATCH 618/627] bip39: truncate long passphrases (more than 256 characters) --- bip39.c | 8 ++++---- bip39.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/bip39.c b/bip39.c index f639c94f3..2d0a9640c 100644 --- a/bip39.c +++ b/bip39.c @@ -184,12 +184,12 @@ int mnemonic_check(const char *mnemonic) return 0; } -// passphrase must be at most 256 characters or code may crash +// passphrase must be at most 256 characters otherwise it would be truncated void mnemonic_to_seed(const char *mnemonic, const char *passphrase, uint8_t seed[512 / 8], void (*progress_callback)(uint32_t current, uint32_t total)) { - int passphraselen = strlen(passphrase); -#if USE_BIP39_CACHE int mnemoniclen = strlen(mnemonic); + int passphraselen = strnlen(passphrase, 256); +#if USE_BIP39_CACHE // check cache if (mnemoniclen < 256 && passphraselen < 64) { for (int i = 0; i < BIP39_CACHE_SIZE; i++) { @@ -206,7 +206,7 @@ void mnemonic_to_seed(const char *mnemonic, const char *passphrase, uint8_t seed memcpy(salt, "mnemonic", 8); memcpy(salt + 8, passphrase, passphraselen); static CONFIDENTIAL PBKDF2_HMAC_SHA512_CTX pctx; - pbkdf2_hmac_sha512_Init(&pctx, (const uint8_t *)mnemonic, strlen(mnemonic), salt, passphraselen + 8, 1); + pbkdf2_hmac_sha512_Init(&pctx, (const uint8_t *)mnemonic, mnemoniclen, salt, passphraselen + 8, 1); if (progress_callback) { progress_callback(0, BIP39_PBKDF2_ROUNDS); } diff --git a/bip39.h b/bip39.h index 1020d05f3..ac76101d7 100644 --- a/bip39.h +++ b/bip39.h @@ -36,7 +36,7 @@ int mnemonic_check(const char *mnemonic); int mnemonic_to_entropy(const char *mnemonic, uint8_t *entropy); -// passphrase must be at most 256 characters or code may crash +// passphrase must be at most 256 characters otherwise it would be truncated void mnemonic_to_seed(const char *mnemonic, const char *passphrase, uint8_t seed[512 / 8], void (*progress_callback)(uint32_t current, uint32_t total)); const char * const *mnemonic_wordlist(void); From 8c2bac95945f3542b74be5cbf0ff16bab511f122 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 31 Jan 2019 19:05:53 +0100 Subject: [PATCH 619/627] hasher: don't hardcore zcash stuff into hasher --- hasher.c | 36 +++++++++++------------------------- hasher.h | 14 +++++++------- 2 files changed, 18 insertions(+), 32 deletions(-) diff --git a/hasher.c b/hasher.c index dfcb64a76..35f27ea81 100644 --- a/hasher.c +++ b/hasher.c @@ -23,8 +23,9 @@ #include "hasher.h" #include "ripemd160.h" -void hasher_Init(Hasher *hasher, HasherType type) { +void hasher_InitParam(Hasher *hasher, HasherType type, const void *param) { hasher->type = type; + hasher->param = param; switch (hasher->type) { case HASHER_SHA2: @@ -46,26 +47,17 @@ void hasher_Init(Hasher *hasher, HasherType type) { case HASHER_GROESTLD_TRUNC: groestl512_Init(&hasher->ctx.groestl); break; - case HASHER_OVERWINTER_PREVOUTS: - blake2b_InitPersonal(&hasher->ctx.blake2b, 32, "ZcashPrevoutHash", 16); + case HASHER_BLAKE2B: + blake2b_Init(&hasher->ctx.blake2b, 32); break; - case HASHER_OVERWINTER_SEQUENCE: - blake2b_InitPersonal(&hasher->ctx.blake2b, 32, "ZcashSequencHash", 16); - break; - case HASHER_OVERWINTER_OUTPUTS: - blake2b_InitPersonal(&hasher->ctx.blake2b, 32, "ZcashOutputsHash", 16); - break; - case HASHER_OVERWINTER_PREIMAGE: - blake2b_InitPersonal(&hasher->ctx.blake2b, 32, "ZcashSigHash\x19\x1b\xa8\x5b", 16); // BRANCH_ID = 0x5ba81b19 / Overwinter - break; - case HASHER_SAPLING_PREIMAGE: - blake2b_InitPersonal(&hasher->ctx.blake2b, 32, "ZcashSigHash\xbb\x09\xb8\x76", 16); // BRANCH_ID = 0x76b809bb / Sapling + case HASHER_BLAKE2B_PERSONAL: + blake2b_InitPersonal(&hasher->ctx.blake2b, 32, hasher->param, 16); break; } } void hasher_Reset(Hasher *hasher) { - hasher_Init(hasher, hasher->type); + hasher_InitParam(hasher, hasher->type, hasher->param); } void hasher_Update(Hasher *hasher, const uint8_t *data, size_t length) { @@ -89,11 +81,8 @@ void hasher_Update(Hasher *hasher, const uint8_t *data, size_t length) { case HASHER_GROESTLD_TRUNC: groestl512_Update(&hasher->ctx.groestl, data, length); break; - case HASHER_OVERWINTER_PREVOUTS: - case HASHER_OVERWINTER_SEQUENCE: - case HASHER_OVERWINTER_OUTPUTS: - case HASHER_OVERWINTER_PREIMAGE: - case HASHER_SAPLING_PREIMAGE: + case HASHER_BLAKE2B: + case HASHER_BLAKE2B_PERSONAL: blake2b_Update(&hasher->ctx.blake2b, data, length); break; } @@ -134,11 +123,8 @@ void hasher_Final(Hasher *hasher, uint8_t hash[HASHER_DIGEST_LENGTH]) { case HASHER_GROESTLD_TRUNC: groestl512_DoubleTrunc(&hasher->ctx.groestl, hash); break; - case HASHER_OVERWINTER_PREVOUTS: - case HASHER_OVERWINTER_SEQUENCE: - case HASHER_OVERWINTER_OUTPUTS: - case HASHER_OVERWINTER_PREIMAGE: - case HASHER_SAPLING_PREIMAGE: + case HASHER_BLAKE2B: + case HASHER_BLAKE2B_PERSONAL: blake2b_Final(&hasher->ctx.blake2b, hash, 32); break; } diff --git a/hasher.h b/hasher.h index e008efdef..b4cc5426c 100644 --- a/hasher.h +++ b/hasher.h @@ -50,11 +50,8 @@ typedef enum { HASHER_GROESTLD_TRUNC, /* Double Groestl512 hasher truncated to 256 bits */ - HASHER_OVERWINTER_PREVOUTS, - HASHER_OVERWINTER_SEQUENCE, - HASHER_OVERWINTER_OUTPUTS, - HASHER_OVERWINTER_PREIMAGE, - HASHER_SAPLING_PREIMAGE, + HASHER_BLAKE2B, + HASHER_BLAKE2B_PERSONAL, } HasherType; typedef struct { @@ -65,11 +62,14 @@ typedef struct { SHA3_CTX sha3; // for HASHER_SHA3{,K} BLAKE256_CTX blake; // for HASHER_BLAKE{,D} GROESTL512_CTX groestl; // for HASHER_GROESTLD_TRUNC - BLAKE2B_CTX blake2b; // for HASHER_OVERWINTER_*, HASHER_SAPLING_* + BLAKE2B_CTX blake2b; // for HASHER_BLAKE2B{,_PERSONAL} } ctx; + + const void *param; } Hasher; -void hasher_Init(Hasher *hasher, HasherType type); +void hasher_InitParam(Hasher *hasher, HasherType type, const void *param); +inline void hasher_Init(Hasher *hasher, HasherType type) { hasher_InitParam(hasher, type, NULL); } void hasher_Reset(Hasher *hasher); void hasher_Update(Hasher *hasher, const uint8_t *data, size_t length); void hasher_Final(Hasher *hasher, uint8_t hash[HASHER_DIGEST_LENGTH]); From 21391dc5be9917bc32a518cf98376f79103727af Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 31 Jan 2019 19:18:06 +0100 Subject: [PATCH 620/627] hasher: add param_size to hasher_InitParam --- hasher.c | 9 +++++++-- hasher.h | 5 +++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/hasher.c b/hasher.c index 35f27ea81..6430ee95a 100644 --- a/hasher.c +++ b/hasher.c @@ -23,9 +23,10 @@ #include "hasher.h" #include "ripemd160.h" -void hasher_InitParam(Hasher *hasher, HasherType type, const void *param) { +void hasher_InitParam(Hasher *hasher, HasherType type, const void *param, uint32_t param_size) { hasher->type = type; hasher->param = param; + hasher->param_size = param_size; switch (hasher->type) { case HASHER_SHA2: @@ -56,8 +57,12 @@ void hasher_InitParam(Hasher *hasher, HasherType type, const void *param) { } } +void hasher_Init(Hasher *hasher, HasherType type) { + hasher_InitParam(hasher, type, NULL, 0); +} + void hasher_Reset(Hasher *hasher) { - hasher_InitParam(hasher, hasher->type, hasher->param); + hasher_InitParam(hasher, hasher->type, hasher->param, hasher->param_size); } void hasher_Update(Hasher *hasher, const uint8_t *data, size_t length) { diff --git a/hasher.h b/hasher.h index b4cc5426c..0cde1df8b 100644 --- a/hasher.h +++ b/hasher.h @@ -66,10 +66,11 @@ typedef struct { } ctx; const void *param; + uint32_t param_size; } Hasher; -void hasher_InitParam(Hasher *hasher, HasherType type, const void *param); -inline void hasher_Init(Hasher *hasher, HasherType type) { hasher_InitParam(hasher, type, NULL); } +void hasher_InitParam(Hasher *hasher, HasherType type, const void *param, uint32_t param_size); +void hasher_Init(Hasher *hasher, HasherType type); void hasher_Reset(Hasher *hasher); void hasher_Update(Hasher *hasher, const uint8_t *data, size_t length); void hasher_Final(Hasher *hasher, uint8_t hash[HASHER_DIGEST_LENGTH]); From ad51a5451c2055b1f8b65eea00a68f01b9824fee Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 16 Feb 2019 15:04:34 +0100 Subject: [PATCH 621/627] hasher: use param_size in call to blake2b_InitPersonal --- hasher.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hasher.c b/hasher.c index 6430ee95a..dac3e9bf5 100644 --- a/hasher.c +++ b/hasher.c @@ -52,7 +52,7 @@ void hasher_InitParam(Hasher *hasher, HasherType type, const void *param, uint32 blake2b_Init(&hasher->ctx.blake2b, 32); break; case HASHER_BLAKE2B_PERSONAL: - blake2b_InitPersonal(&hasher->ctx.blake2b, 32, hasher->param, 16); + blake2b_InitPersonal(&hasher->ctx.blake2b, 32, hasher->param, hasher->param_size); break; } } From b2a0d55fd6cdbeadb8c415304c15d0e30046ff3b Mon Sep 17 00:00:00 2001 From: Andrew Kozlik <42678794+andrewkozlik@users.noreply.github.com> Date: Sat, 16 Feb 2019 16:03:46 +0100 Subject: [PATCH 622/627] memzero: automate the selection of the implementation (#196) --- memzero.c | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/memzero.c b/memzero.c index 6fda42119..b3cb3f99c 100644 --- a/memzero.c +++ b/memzero.c @@ -1,7 +1,43 @@ +#ifndef __STDC_WANT_LIB_EXT1__ +#define __STDC_WANT_LIB_EXT1__ 1 // C11's bounds-checking interface. +#endif #include + +#ifdef _WIN32 +#include +#endif + +#ifdef __unix__ #include +#include +#endif + +// C11's bounds-checking interface. +#if defined(__STDC_LIB_EXT1__) +#define HAVE_MEMSET_S 1 +#endif + +// GNU C Library version 2.25 or later. +#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 25) +#define HAVE_EXPLICIT_BZERO 1 +#endif + +// FreeBSD version 11.0 or later. +#if defined(__FreeBSD__) && __FreeBSD_version >= 1100037 +#define HAVE_EXPLICIT_BZERO 1 +#endif + +// OpenBSD version 5.5 or later. +#if defined(__OpenBSD__) && OpenBSD >= 201405 +#define HAVE_EXPLICIT_BZERO 1 +#endif + +// NetBSD version 7.2 or later. +#if defined(__NetBSD__) && __NetBSD_Version__ >= 702000000 +#define HAVE_EXPLICIT_MEMSET 1 +#endif -// taken from https://github.com/jedisct1/libsodium/blob/1647f0d53ae0e370378a9195477e3df0a792408f/src/libsodium/sodium/utils.c#L102-L130 +// Adapted from https://github.com/jedisct1/libsodium/blob/1647f0d53ae0e370378a9195477e3df0a792408f/src/libsodium/sodium/utils.c#L102-L130 void memzero(void *const pnt, const size_t len) { From e3caf14c438168eb103a5d7d54ce11f4cab9db82 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 16 Feb 2019 16:14:12 +0100 Subject: [PATCH 623/627] memzero: add newlib support --- memzero.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/memzero.c b/memzero.c index b3cb3f99c..3c3a7383d 100644 --- a/memzero.c +++ b/memzero.c @@ -18,7 +18,12 @@ #endif // GNU C Library version 2.25 or later. -#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 25) +#if defined(__GLIBC__) && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 25)) +#define HAVE_EXPLICIT_BZERO 1 +#endif + +// Newlib +#if defined( __NEWLIB__) #define HAVE_EXPLICIT_BZERO 1 #endif From 2ac59892b78e0ef62a5424a63ad1b650bfd7a0e2 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sat, 16 Feb 2019 15:00:56 +0100 Subject: [PATCH 624/627] nem: refactor serialization code --- nem.c | 242 +++++++++++++++++++----------------------------- nem_serialize.h | 23 ----- 2 files changed, 97 insertions(+), 168 deletions(-) delete mode 100644 nem_serialize.h diff --git a/nem.c b/nem.c index 8a4b7c52a..39c9ac586 100644 --- a/nem.c +++ b/nem.c @@ -30,6 +30,16 @@ #include "sha3.h" #include "memzero.h" +#define CAN_WRITE(NEEDED) ((ctx->offset + (NEEDED)) <= ctx->size) + +#define SERIALIZE_U32(DATA) \ + do { if (!nem_write_u32(ctx, (DATA))) return false; } while (0) +#define SERIALIZE_U64(DATA) \ + do { if (!nem_write_u64(ctx, (DATA))) return false; } while (0) +#define SERIALIZE_TAGGED(DATA, LENGTH) \ + do { if (!nem_write_tagged(ctx, (DATA), (LENGTH))) return false; } while (0) + + const char *nem_network_name(uint8_t network) { switch (network) { case NEM_NETWORK_MAINNET: @@ -43,39 +53,49 @@ const char *nem_network_name(uint8_t network) { } } -static inline void nem_write_u32(nem_transaction_ctx *ctx, uint32_t data) { +static inline bool nem_write_checked(nem_transaction_ctx *ctx, const uint8_t *data, uint32_t length) { + if (!CAN_WRITE(length)) { + return false; + } + + memcpy(&ctx->buffer[ctx->offset], data, length); + ctx->offset += length; + return true; +} + +static inline bool nem_write_u32(nem_transaction_ctx *ctx, uint32_t data) { + if (!CAN_WRITE(4)) { + return false; + } + ctx->buffer[ctx->offset++] = (data >> 0) & 0xff; ctx->buffer[ctx->offset++] = (data >> 8) & 0xff; ctx->buffer[ctx->offset++] = (data >> 16) & 0xff; ctx->buffer[ctx->offset++] = (data >> 24) & 0xff; -} -static inline void nem_write_u64(nem_transaction_ctx *ctx, uint64_t data) { - nem_write_u32(ctx, (data >> 0) & 0xffffffff); - nem_write_u32(ctx, (data >> 32) & 0xffffffff); + return true; } -static inline void nem_write(nem_transaction_ctx *ctx, const uint8_t *data, uint32_t length) { - nem_write_u32(ctx, length); +static inline bool nem_write_u64(nem_transaction_ctx *ctx, uint64_t data) { + SERIALIZE_U32((data >> 0) & 0xffffffff); + SERIALIZE_U32((data >> 32) & 0xffffffff); - memcpy(&ctx->buffer[ctx->offset], data, length); - ctx->offset += length; + return true; } -static inline bool nem_can_write(nem_transaction_ctx *ctx, size_t needed) { - return (ctx->offset + needed) <= ctx->size; +static inline bool nem_write_tagged(nem_transaction_ctx *ctx, const uint8_t *data, uint32_t length) { + SERIALIZE_U32(length); + + return nem_write_checked(ctx, data, length); } static inline bool nem_write_mosaic_str(nem_transaction_ctx *ctx, const char *name, const char *value) { uint32_t name_length = strlen(name); uint32_t value_length = strlen(value); -#define NEM_SERIALIZE \ - serialize_u32(sizeof(uint32_t) + name_length + sizeof(uint32_t) + value_length) \ - serialize_write((uint8_t *) name, name_length) \ - serialize_write((uint8_t *) value, value_length) - -#include "nem_serialize.h" + SERIALIZE_U32(sizeof(uint32_t) + name_length + sizeof(uint32_t) + value_length); + SERIALIZE_TAGGED((const uint8_t *) name, name_length); + SERIALIZE_TAGGED((const uint8_t *) value, value_length); return true; } @@ -178,15 +198,12 @@ bool nem_transaction_write_common(nem_transaction_ctx *ctx, uint64_t fee, uint32_t deadline) { -#define NEM_SERIALIZE \ - serialize_u32(type) \ - serialize_u32(version) \ - serialize_u32(timestamp) \ - serialize_write(signer, sizeof(ed25519_public_key)) \ - serialize_u64(fee) \ - serialize_u32(deadline) - -#include "nem_serialize.h" + SERIALIZE_U32(type); + SERIALIZE_U32(version); + SERIALIZE_U32(timestamp); + SERIALIZE_TAGGED(signer, sizeof(ed25519_public_key)); + SERIALIZE_U64(fee); + SERIALIZE_U32(deadline); return true; } @@ -221,36 +238,20 @@ bool nem_transaction_create_transfer(nem_transaction_ctx *ctx, deadline); if (!ret) return false; -#define NEM_SERIALIZE \ - serialize_write((uint8_t *) recipient, NEM_ADDRESS_SIZE) \ - serialize_u64(amount) - -#include "nem_serialize.h" + SERIALIZE_TAGGED((const uint8_t *) recipient, NEM_ADDRESS_SIZE); + SERIALIZE_U64(amount); if (length) { - -#define NEM_SERIALIZE \ - serialize_u32(sizeof(uint32_t) + sizeof(uint32_t) + length) \ - serialize_u32(encrypted ? 0x02 : 0x01) \ - serialize_write(payload, length) - -#include "nem_serialize.h" - + SERIALIZE_U32(sizeof(uint32_t) + sizeof(uint32_t) + length); + SERIALIZE_U32(encrypted ? 0x02 : 0x01); + SERIALIZE_TAGGED(payload, length); } else { - -#define NEM_SERIALIZE \ - serialize_u32(0) - -#include "nem_serialize.h" - + SERIALIZE_U32(0); } if (mosaics) { -#define NEM_SERIALIZE \ - serialize_u32(mosaics) - -#include "nem_serialize.h" + SERIALIZE_U32(mosaics); } @@ -266,14 +267,11 @@ bool nem_transaction_write_mosaic(nem_transaction_ctx *ctx, size_t mosaic_length = strlen(mosaic); size_t identifier_length = sizeof(uint32_t) + namespace_length + sizeof(uint32_t) + mosaic_length; -#define NEM_SERIALIZE \ - serialize_u32(sizeof(uint32_t) + sizeof(uint64_t) + identifier_length) \ - serialize_u32(identifier_length) \ - serialize_write((uint8_t *) namespace, namespace_length) \ - serialize_write((uint8_t *) mosaic, mosaic_length) \ - serialize_u64(quantity) - -#include "nem_serialize.h" + SERIALIZE_U32(sizeof(uint32_t) + sizeof(uint64_t) + identifier_length); + SERIALIZE_U32(identifier_length); + SERIALIZE_TAGGED((const uint8_t *) namespace, namespace_length); + SERIALIZE_TAGGED((const uint8_t *) mosaic, mosaic_length); + SERIALIZE_U64(quantity); return true; } @@ -299,10 +297,7 @@ bool nem_transaction_create_multisig(nem_transaction_ctx *ctx, deadline); if (!ret) return false; -#define NEM_SERIALIZE \ - serialize_write(inner->buffer, inner->offset) - -#include "nem_serialize.h" + SERIALIZE_TAGGED(inner->buffer, inner->offset); return true; } @@ -334,12 +329,9 @@ bool nem_transaction_create_multisig_signature(nem_transaction_ctx *ctx, uint8_t hash[SHA3_256_DIGEST_LENGTH]; keccak_256(inner->buffer, inner->offset, hash); -#define NEM_SERIALIZE \ - serialize_u32(sizeof(uint32_t) + SHA3_256_DIGEST_LENGTH) \ - serialize_write(hash, SHA3_256_DIGEST_LENGTH) \ - serialize_write((uint8_t *) address, NEM_ADDRESS_SIZE) - -#include "nem_serialize.h" + SERIALIZE_U32(sizeof(uint32_t) + SHA3_256_DIGEST_LENGTH); + SERIALIZE_TAGGED(hash, SHA3_256_DIGEST_LENGTH); + SERIALIZE_TAGGED((const uint8_t *) address, NEM_ADDRESS_SIZE); return true; } @@ -369,25 +361,15 @@ bool nem_transaction_create_provision_namespace(nem_transaction_ctx *ctx, if (!ret) return false; if (parent) { - -#define NEM_SERIALIZE \ - serialize_write((uint8_t *) rental_sink, NEM_ADDRESS_SIZE) \ - serialize_u64(rental_fee) \ - serialize_write((uint8_t *) namespace, strlen(namespace)) \ - serialize_write((uint8_t *) parent, strlen(parent)) - -#include "nem_serialize.h" - + SERIALIZE_TAGGED((const uint8_t *) rental_sink, NEM_ADDRESS_SIZE); + SERIALIZE_U64(rental_fee); + SERIALIZE_TAGGED((const uint8_t *) namespace, strlen(namespace)); + SERIALIZE_TAGGED((const uint8_t *) parent, strlen(parent)); } else { - -#define NEM_SERIALIZE \ - serialize_write((uint8_t *) rental_sink, NEM_ADDRESS_SIZE) \ - serialize_u64(rental_fee) \ - serialize_write((uint8_t *) namespace, strlen(namespace)) \ - serialize_u32(0xffffffff) - -#include "nem_serialize.h" - + SERIALIZE_TAGGED((const uint8_t *) rental_sink, NEM_ADDRESS_SIZE); + SERIALIZE_U64(rental_fee); + SERIALIZE_TAGGED((const uint8_t *) namespace, strlen(namespace)); + SERIALIZE_U32(0xffffffff); } return true; @@ -435,16 +417,13 @@ bool nem_transaction_create_mosaic_creation(nem_transaction_ctx *ctx, nem_transaction_ctx state; memcpy(&state, ctx, sizeof(state)); -#define NEM_SERIALIZE \ - serialize_u32(0) \ - serialize_write(signer, sizeof(ed25519_public_key)) \ - serialize_u32(identifier_length) \ - serialize_write((uint8_t *) namespace, namespace_length) \ - serialize_write((uint8_t *) mosaic, mosaic_length) \ - serialize_write((uint8_t *) description, strlen(description)) \ - serialize_u32(4) // Number of properties - -#include "nem_serialize.h" + SERIALIZE_U32(0); + SERIALIZE_TAGGED(signer, sizeof(ed25519_public_key)); + SERIALIZE_U32(identifier_length); + SERIALIZE_TAGGED((const uint8_t *) namespace, namespace_length); + SERIALIZE_TAGGED((const uint8_t *) mosaic, mosaic_length); + SERIALIZE_TAGGED((const uint8_t *) description, strlen(description)); + SERIALIZE_U32(4); // Number of properties if (!nem_write_mosaic_u64(ctx, "divisibility", divisibility)) return false; if (!nem_write_mosaic_u64(ctx, "initialSupply", supply)) return false; @@ -456,34 +435,22 @@ bool nem_transaction_create_mosaic_creation(nem_transaction_ctx *ctx, size_t levy_mosaic_length = strlen(levy_mosaic); size_t levy_identifier_length = sizeof(uint32_t) + levy_namespace_length + sizeof(uint32_t) + levy_mosaic_length; -#define NEM_SERIALIZE \ - serialize_u32(sizeof(uint32_t) + sizeof(uint32_t) + NEM_ADDRESS_SIZE + sizeof(uint32_t) + levy_identifier_length + sizeof(uint64_t)) \ - serialize_u32(levy_type) \ - serialize_write((uint8_t *) levy_address, NEM_ADDRESS_SIZE) \ - serialize_u32(levy_identifier_length) \ - serialize_write((uint8_t *) levy_namespace, levy_namespace_length) \ - serialize_write((uint8_t *) levy_mosaic, levy_mosaic_length) \ - serialize_u64(levy_fee) - -#include "nem_serialize.h" - + SERIALIZE_U32(sizeof(uint32_t) + sizeof(uint32_t) + NEM_ADDRESS_SIZE + sizeof(uint32_t) + levy_identifier_length + sizeof(uint64_t)); + SERIALIZE_U32(levy_type); + SERIALIZE_TAGGED((const uint8_t *) levy_address, NEM_ADDRESS_SIZE); + SERIALIZE_U32(levy_identifier_length); + SERIALIZE_TAGGED((const uint8_t *) levy_namespace, levy_namespace_length); + SERIALIZE_TAGGED((const uint8_t *) levy_mosaic, levy_mosaic_length); + SERIALIZE_U64(levy_fee); } else { - -#define NEM_SERIALIZE \ - serialize_u32(0) - -#include "nem_serialize.h" - + SERIALIZE_U32(0); } // Rewrite length nem_write_u32(&state, ctx->offset - state.offset - sizeof(uint32_t)); -#define NEM_SERIALIZE \ - serialize_write((uint8_t *) creation_sink, NEM_ADDRESS_SIZE) \ - serialize_u64(creation_fee) - -#include "nem_serialize.h" + SERIALIZE_TAGGED((const uint8_t *) creation_sink, NEM_ADDRESS_SIZE); + SERIALIZE_U64(creation_fee); return true; @@ -517,14 +484,11 @@ bool nem_transaction_create_mosaic_supply_change(nem_transaction_ctx *ctx, size_t mosaic_length = strlen(mosaic); size_t identifier_length = sizeof(uint32_t) + namespace_length + sizeof(uint32_t) + mosaic_length; -#define NEM_SERIALIZE \ - serialize_u32(identifier_length) \ - serialize_write((uint8_t *) namespace, namespace_length) \ - serialize_write((uint8_t *) mosaic, mosaic_length) \ - serialize_u32(type) \ - serialize_u64(delta) - -#include "nem_serialize.h" + SERIALIZE_U32(identifier_length); + SERIALIZE_TAGGED((const uint8_t *) namespace, namespace_length); + SERIALIZE_TAGGED((const uint8_t *) mosaic, mosaic_length); + SERIALIZE_U32(type); + SERIALIZE_U64(delta); return true; } @@ -551,10 +515,7 @@ bool nem_transaction_create_aggregate_modification(nem_transaction_ctx *ctx, deadline); if (!ret) return false; -#define NEM_SERIALIZE \ - serialize_u32(modifications) - -#include "nem_serialize.h" + SERIALIZE_U32(modifications); return true; } @@ -563,12 +524,9 @@ bool nem_transaction_write_cosignatory_modification(nem_transaction_ctx *ctx, uint32_t type, const ed25519_public_key cosignatory) { -#define NEM_SERIALIZE \ - serialize_u32(sizeof(uint32_t) + sizeof(uint32_t) + sizeof(ed25519_public_key)) \ - serialize_u32(type) \ - serialize_write(cosignatory, sizeof(ed25519_public_key)) - -#include "nem_serialize.h" + SERIALIZE_U32(sizeof(uint32_t) + sizeof(uint32_t) + sizeof(ed25519_public_key)); + SERIALIZE_U32(type); + SERIALIZE_TAGGED(cosignatory, sizeof(ed25519_public_key)); return true; } @@ -576,11 +534,8 @@ bool nem_transaction_write_cosignatory_modification(nem_transaction_ctx *ctx, bool nem_transaction_write_minimum_cosignatories(nem_transaction_ctx *ctx, int32_t relative_change) { -#define NEM_SERIALIZE \ - serialize_u32(sizeof(uint32_t)) \ - serialize_u32((uint32_t) relative_change) - -#include "nem_serialize.h" + SERIALIZE_U32(sizeof(uint32_t)); + SERIALIZE_U32((uint32_t) relative_change); return true; } @@ -607,11 +562,8 @@ bool nem_transaction_create_importance_transfer(nem_transaction_ctx *ctx, deadline); if (!ret) return false; -#define NEM_SERIALIZE \ - serialize_u32(mode) \ - serialize_write(remote, sizeof(ed25519_public_key)) - -#include "nem_serialize.h" + SERIALIZE_U32(mode); + SERIALIZE_TAGGED(remote, sizeof(ed25519_public_key)); return true; } diff --git a/nem_serialize.h b/nem_serialize.h deleted file mode 100644 index 479581fcb..000000000 --- a/nem_serialize.h +++ /dev/null @@ -1,23 +0,0 @@ -#define serialize_u32(data) + sizeof(uint32_t) -#define serialize_u64(data) + sizeof(uint64_t) -#define serialize_write(data, length) + (length) - -if (!nem_can_write(ctx, NEM_SERIALIZE)) { - return false; -} - -#undef serialize_u32 -#undef serialize_u64 -#undef serialize_write - -#define serialize_u32(data) nem_write_u32(ctx, (data)); -#define serialize_u64(data) nem_write_u64(ctx, (data)); -#define serialize_write(data, length) nem_write(ctx, (data), (length)); - -NEM_SERIALIZE - -#undef serialize_u32 -#undef serialize_u64 -#undef serialize_write - -#undef NEM_SERIALIZE From 4211ce389f6795d844809b0ba66a84082038ca04 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 16 Feb 2019 15:45:06 +0100 Subject: [PATCH 625/627] bignum: check values of decimals and exponent in bn_format --- bignum.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/bignum.c b/bignum.c index a6bba0a66..30e711d02 100644 --- a/bignum.c +++ b/bignum.c @@ -989,6 +989,12 @@ void bn_divmod1000(bignum256 *a, uint32_t *r) size_t bn_format(const bignum256 *amnt, const char *prefix, const char *suffix, unsigned int decimals, int exponent, bool trailing, char *out, size_t outlen) { + // sanity check, 2**256 ~ 10**77; we should never need decimals/exponent bigger than that + if (decimals > 80 || exponent < -20 || exponent > 80) { + memzero(out, outlen); + return 0; + } + size_t prefixlen = prefix ? strlen(prefix) : 0; size_t suffixlen = suffix ? strlen(suffix) : 0; From 8434b2468cef18f582ee6470d22e16f018f1b72a Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 26 Mar 2019 18:55:50 +0100 Subject: [PATCH 626/627] tools: fix arguments to ecdsa functions --- tools/bip39bruteforce.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/bip39bruteforce.c b/tools/bip39bruteforce.c index 10fd69da7..be2fa5b76 100644 --- a/tools/bip39bruteforce.c +++ b/tools/bip39bruteforce.c @@ -5,6 +5,7 @@ #include "bip32.h" #include "ecdsa.h" #include "curves.h" +#include "secp256k1.h" char iter[256]; uint8_t seed[512 / 8]; @@ -44,7 +45,7 @@ int main(int argc, char **argv) fprintf(stderr, "\"%s\" is not a valid mnemonic\n", mnemonic); return 2; } - if (!ecdsa_address_decode(address, 0, HASHER_SHA2, addr)) { + if (!ecdsa_address_decode(address, 0, secp256k1_info.hasher_base58, addr)) { fprintf(stderr, "\"%s\" is not a valid address\n", address); return 3; } @@ -70,7 +71,7 @@ int main(int argc, char **argv) hdnode_private_ckd(&node, 0); hdnode_private_ckd(&node, 0); hdnode_fill_public_key(&node); - ecdsa_get_pubkeyhash(node.public_key, HASHER_SHA2, pubkeyhash); + ecdsa_get_pubkeyhash(node.public_key, secp256k1_info.hasher_pubkey, pubkeyhash); if (memcmp(addr + 1, pubkeyhash, 20) == 0) { found = 1; break; From 0c622d62e1f1e052c2292d39093222ce358ca7b0 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 29 Mar 2019 15:44:55 +0100 Subject: [PATCH 627/627] format: start using clang-format with style=Google --- .clang-format | 2 + address.c | 102 +- address.h | 5 +- base32.c | 317 +- base32.h | 9 +- base58.c | 417 +- base58.h | 14 +- bignum.c | 1696 +++-- bignum.h | 57 +- bip32.c | 1378 ++-- bip32.h | 96 +- bip39.c | 355 +- bip39.h | 9 +- bip39_english.h | 2393 +------ blake2_common.h | 38 +- cash_addr.c | 262 +- cash_addr.h | 41 +- ecdsa.c | 1968 +++--- ecdsa.h | 91 +- hasher.c | 195 +- hasher.h | 54 +- hmac.c | 248 +- hmac.h | 32 +- memzero.c | 32 +- memzero.h | 2 +- monero/monero.h | 4 +- monero/range_proof.c | 162 +- monero/range_proof.h | 19 +- monero/serialize.c | 85 +- monero/serialize.h | 6 +- monero/xmr.c | 181 +- monero/xmr.h | 41 +- nem.c | 833 +-- nem.h | 219 +- nist256p1.c | 55 +- nist256p1.h | 2 +- options.h | 2 +- pbkdf2.c | 240 +- pbkdf2.h | 42 +- rand.c | 69 +- rc4.c | 44 +- rc4.h | 6 +- rfc6979.c | 71 +- rfc6979.h | 5 +- ripemd160.h | 16 +- script.c | 68 +- script.h | 3 +- secp256k1.c | 89 +- secp256k1.h | 2 +- segwit_addr.h | 44 +- shell.nix | 2 +- tests/test_check.c | 12755 ++++++++++++++++++++++------------ tests/test_check_cardano.h | 546 +- tests/test_check_cashaddr.h | 119 +- tests/test_check_monero.h | 2187 +++--- tests/test_check_segwit.h | 292 +- tests/test_openssl.c | 179 +- tests/test_speed.c | 308 +- tools/bip39bruteforce.c | 125 +- tools/mktable.c | 106 +- tools/xpubaddrgen.c | 74 +- 61 files changed, 15355 insertions(+), 13459 deletions(-) create mode 100644 .clang-format diff --git a/.clang-format b/.clang-format new file mode 100644 index 000000000..58d4b3b68 --- /dev/null +++ b/.clang-format @@ -0,0 +1,2 @@ +--- +BasedOnStyle: Google diff --git a/address.c b/address.c index c63b501ac..2862c9548 100644 --- a/address.c +++ b/address.c @@ -24,66 +24,68 @@ #include "address.h" #include "bignum.h" -size_t address_prefix_bytes_len(uint32_t address_type) -{ - if (address_type <= 0xFF) return 1; - if (address_type <= 0xFFFF) return 2; - if (address_type <= 0xFFFFFF) return 3; - return 4; +size_t address_prefix_bytes_len(uint32_t address_type) { + if (address_type <= 0xFF) return 1; + if (address_type <= 0xFFFF) return 2; + if (address_type <= 0xFFFFFF) return 3; + return 4; } -void address_write_prefix_bytes(uint32_t address_type, uint8_t *out) -{ - if (address_type > 0xFFFFFF) *(out++) = address_type >> 24; - if (address_type > 0xFFFF) *(out++) = (address_type >> 16) & 0xFF; - if (address_type > 0xFF) *(out++) = (address_type >> 8) & 0xFF; - *(out++) = address_type & 0xFF; +void address_write_prefix_bytes(uint32_t address_type, uint8_t *out) { + if (address_type > 0xFFFFFF) *(out++) = address_type >> 24; + if (address_type > 0xFFFF) *(out++) = (address_type >> 16) & 0xFF; + if (address_type > 0xFF) *(out++) = (address_type >> 8) & 0xFF; + *(out++) = address_type & 0xFF; } -bool address_check_prefix(const uint8_t *addr, uint32_t address_type) -{ - if (address_type <= 0xFF) { - return address_type == (uint32_t)(addr[0]); - } - if (address_type <= 0xFFFF) { - return address_type == (((uint32_t) addr[0] << 8) | ((uint32_t) addr[1])); - } - if (address_type <= 0xFFFFFF) { - return address_type == (((uint32_t) addr[0] << 16) | ((uint32_t) addr[1] << 8) | ((uint32_t) addr[2])); - } - return address_type == (((uint32_t) addr[0] << 24) | ((uint32_t) addr[1] << 16) | ((uint32_t) addr[2] << 8) | ((uint32_t) addr[3])); +bool address_check_prefix(const uint8_t *addr, uint32_t address_type) { + if (address_type <= 0xFF) { + return address_type == (uint32_t)(addr[0]); + } + if (address_type <= 0xFFFF) { + return address_type == (((uint32_t)addr[0] << 8) | ((uint32_t)addr[1])); + } + if (address_type <= 0xFFFFFF) { + return address_type == (((uint32_t)addr[0] << 16) | + ((uint32_t)addr[1] << 8) | ((uint32_t)addr[2])); + } + return address_type == + (((uint32_t)addr[0] << 24) | ((uint32_t)addr[1] << 16) | + ((uint32_t)addr[2] << 8) | ((uint32_t)addr[3])); } #if USE_ETHEREUM #include "sha3.h" -void ethereum_address_checksum(const uint8_t *addr, char *address, bool rskip60, uint32_t chain_id) -{ - const char *hex = "0123456789abcdef"; - for (int i = 0; i < 20; i++) { - address[i * 2] = hex[(addr[i] >> 4) & 0xF]; - address[i * 2 + 1] = hex[addr[i] & 0xF]; - } - address[40] = 0; +void ethereum_address_checksum(const uint8_t *addr, char *address, bool rskip60, + uint32_t chain_id) { + const char *hex = "0123456789abcdef"; + for (int i = 0; i < 20; i++) { + address[i * 2] = hex[(addr[i] >> 4) & 0xF]; + address[i * 2 + 1] = hex[addr[i] & 0xF]; + } + address[40] = 0; - SHA3_CTX ctx; - uint8_t hash[32]; - keccak_256_Init(&ctx); - if (rskip60) { - char prefix[16]; - int prefix_size = bn_format_uint64(chain_id, NULL, "0x", 0, 0, false, prefix, sizeof(prefix)); - keccak_Update(&ctx, (const uint8_t *)prefix, prefix_size); - } - keccak_Update(&ctx, (const uint8_t *)address, 40); - keccak_Final(&ctx, hash); + SHA3_CTX ctx; + uint8_t hash[32]; + keccak_256_Init(&ctx); + if (rskip60) { + char prefix[16]; + int prefix_size = bn_format_uint64(chain_id, NULL, "0x", 0, 0, false, + prefix, sizeof(prefix)); + keccak_Update(&ctx, (const uint8_t *)prefix, prefix_size); + } + keccak_Update(&ctx, (const uint8_t *)address, 40); + keccak_Final(&ctx, hash); - for (int i = 0; i < 20; i++) { - if (hash[i] & 0x80 && address[i * 2 ] >= 'a' && address[i * 2 ] <= 'f') { - address[i * 2] -= 0x20; - } - if (hash[i] & 0x08 && address[i * 2 + 1] >= 'a' && address[i * 2 + 1] <= 'f') { - address[i * 2 + 1] -= 0x20; - } - } + for (int i = 0; i < 20; i++) { + if (hash[i] & 0x80 && address[i * 2] >= 'a' && address[i * 2] <= 'f') { + address[i * 2] -= 0x20; + } + if (hash[i] & 0x08 && address[i * 2 + 1] >= 'a' && + address[i * 2 + 1] <= 'f') { + address[i * 2 + 1] -= 0x20; + } + } } #endif diff --git a/address.h b/address.h index 7c5925e06..8147f2c35 100644 --- a/address.h +++ b/address.h @@ -24,16 +24,17 @@ #ifndef __ADDRESS_H__ #define __ADDRESS_H__ -#include #include #include +#include #include "options.h" size_t address_prefix_bytes_len(uint32_t address_type); void address_write_prefix_bytes(uint32_t address_type, uint8_t *out); bool address_check_prefix(const uint8_t *addr, uint32_t address_type); #if USE_ETHEREUM -void ethereum_address_checksum(const uint8_t *addr, char *address, bool rskip60, uint32_t chain_id); +void ethereum_address_checksum(const uint8_t *addr, char *address, bool rskip60, + uint32_t chain_id); #endif #endif diff --git a/base32.c b/base32.c index 06760ccae..b2dccad8a 100644 --- a/base32.c +++ b/base32.c @@ -27,207 +27,214 @@ const char *BASE32_ALPHABET_RFC4648 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ23456789"; static inline void base32_5to8(const uint8_t *in, uint8_t length, uint8_t *out); -static inline bool base32_8to5(const uint8_t *in, uint8_t length, uint8_t *out, const char *alphabet); -static inline void base32_8to5_raw(const uint8_t *in, uint8_t length, uint8_t *out); +static inline bool base32_8to5(const uint8_t *in, uint8_t length, uint8_t *out, + const char *alphabet); +static inline void base32_8to5_raw(const uint8_t *in, uint8_t length, + uint8_t *out); -static inline int base32_encode_character(uint8_t decoded, const char *alphabet); +static inline int base32_encode_character(uint8_t decoded, + const char *alphabet); static inline int base32_decode_character(char encoded, const char *alphabet); -char *base32_encode(const uint8_t *in, size_t inlen, char *out, size_t outlen, const char *alphabet) { - size_t length = base32_encoded_length(inlen); - if (outlen <= length) { - return NULL; - } +char *base32_encode(const uint8_t *in, size_t inlen, char *out, size_t outlen, + const char *alphabet) { + size_t length = base32_encoded_length(inlen); + if (outlen <= length) { + return NULL; + } - base32_encode_unsafe(in, inlen, (uint8_t *) out); + base32_encode_unsafe(in, inlen, (uint8_t *)out); - for (size_t i = 0; i < length; i++) { - int ret = base32_encode_character(out[i], alphabet); + for (size_t i = 0; i < length; i++) { + int ret = base32_encode_character(out[i], alphabet); - if (ret == -1) { - return false; - } else { - out[i] = ret; - } - } + if (ret == -1) { + return false; + } else { + out[i] = ret; + } + } - out[length] = '\0'; - return &out[length]; + out[length] = '\0'; + return &out[length]; } -uint8_t *base32_decode(const char *in, size_t inlen, uint8_t *out, size_t outlen, const char *alphabet) { - size_t length = base32_decoded_length(inlen); - if (outlen < length) { - return NULL; - } +uint8_t *base32_decode(const char *in, size_t inlen, uint8_t *out, + size_t outlen, const char *alphabet) { + size_t length = base32_decoded_length(inlen); + if (outlen < length) { + return NULL; + } - if (!base32_decode_unsafe((uint8_t *) in, inlen, (uint8_t *) out, alphabet)) { - return NULL; - } + if (!base32_decode_unsafe((uint8_t *)in, inlen, (uint8_t *)out, alphabet)) { + return NULL; + } - return &out[length]; + return &out[length]; } void base32_encode_unsafe(const uint8_t *in, size_t inlen, uint8_t *out) { - uint8_t remainder = inlen % 5; - size_t limit = inlen - remainder; + uint8_t remainder = inlen % 5; + size_t limit = inlen - remainder; - size_t i, j; - for (i = 0, j = 0; i < limit; i += 5, j += 8) { - base32_5to8(&in[i], 5, &out[j]); - } + size_t i, j; + for (i = 0, j = 0; i < limit; i += 5, j += 8) { + base32_5to8(&in[i], 5, &out[j]); + } - if (remainder) base32_5to8(&in[i], remainder, &out[j]); + if (remainder) base32_5to8(&in[i], remainder, &out[j]); } -bool base32_decode_unsafe(const uint8_t *in, size_t inlen, uint8_t *out, const char *alphabet) { - uint8_t remainder = inlen % 8; - size_t limit = inlen - remainder; +bool base32_decode_unsafe(const uint8_t *in, size_t inlen, uint8_t *out, + const char *alphabet) { + uint8_t remainder = inlen % 8; + size_t limit = inlen - remainder; - size_t i, j; - for (i = 0, j = 0; i < limit; i += 8, j += 5) { - if (!base32_8to5(&in[i], 8, &out[j], alphabet)) { - return false; - } - } + size_t i, j; + for (i = 0, j = 0; i < limit; i += 8, j += 5) { + if (!base32_8to5(&in[i], 8, &out[j], alphabet)) { + return false; + } + } - if (remainder && !base32_8to5(&in[i], remainder, &out[j], alphabet)) { - return false; - } + if (remainder && !base32_8to5(&in[i], remainder, &out[j], alphabet)) { + return false; + } - return true; + return true; } size_t base32_encoded_length(size_t inlen) { - uint8_t remainder = inlen % 5; + uint8_t remainder = inlen % 5; - return (inlen / 5) * 8 + (remainder * 8 + 4) / 5; + return (inlen / 5) * 8 + (remainder * 8 + 4) / 5; } size_t base32_decoded_length(size_t inlen) { - uint8_t remainder = inlen % 8; + uint8_t remainder = inlen % 8; - return (inlen / 8) * 5 + (remainder * 5) / 8; + return (inlen / 8) * 5 + (remainder * 5) / 8; } void base32_5to8(const uint8_t *in, uint8_t length, uint8_t *out) { - if (length >= 1) { - out[0] = (in[0] >> 3); - out[1] = (in[0] & 7) << 2; - } - - if (length >= 2) { - out[1] |= (in[1] >> 6); - out[2] = (in[1] >> 1) & 31; - out[3] = (in[1] & 1) << 4; - } - - if (length >= 3) { - out[3] |= (in[2] >> 4); - out[4] = (in[2] & 15) << 1; - } - - if (length >= 4) { - out[4] |= (in[3] >> 7); - out[5] = (in[3] >> 2) & 31; - out[6] = (in[3] & 3) << 3; - } - - if (length >= 5) { - out[6] |= (in[4] >> 5); - out[7] = (in[4] & 31); - } + if (length >= 1) { + out[0] = (in[0] >> 3); + out[1] = (in[0] & 7) << 2; + } + + if (length >= 2) { + out[1] |= (in[1] >> 6); + out[2] = (in[1] >> 1) & 31; + out[3] = (in[1] & 1) << 4; + } + + if (length >= 3) { + out[3] |= (in[2] >> 4); + out[4] = (in[2] & 15) << 1; + } + + if (length >= 4) { + out[4] |= (in[3] >> 7); + out[5] = (in[3] >> 2) & 31; + out[6] = (in[3] & 3) << 3; + } + + if (length >= 5) { + out[6] |= (in[4] >> 5); + out[7] = (in[4] & 31); + } } -bool base32_8to5(const uint8_t *in, uint8_t length, uint8_t *out, const char *alphabet) { - if (length == 1 || length == 3 || length == 6 || length > 8) { - return false; - } +bool base32_8to5(const uint8_t *in, uint8_t length, uint8_t *out, + const char *alphabet) { + if (length == 1 || length == 3 || length == 6 || length > 8) { + return false; + } - if (alphabet) { - uint8_t decoded[length]; + if (alphabet) { + uint8_t decoded[length]; - for (size_t i = 0; i < length; i++) { - int ret = base32_decode_character(in[i], alphabet); + for (size_t i = 0; i < length; i++) { + int ret = base32_decode_character(in[i], alphabet); - if (ret == -1) { - return false; - } else { - decoded[i] = ret; - } - } + if (ret == -1) { + return false; + } else { + decoded[i] = ret; + } + } - base32_8to5_raw(decoded, length, out); - } else { - base32_8to5_raw(in, length, out); - } + base32_8to5_raw(decoded, length, out); + } else { + base32_8to5_raw(in, length, out); + } - return true; + return true; } void base32_8to5_raw(const uint8_t *in, uint8_t length, uint8_t *out) { - if (length >= 2) { - out[0] = (in[0] << 3); - out[0] |= (in[1] >> 2); - } - - if (length >= 4) { - out[1] = (in[1] & 3) << 6; - out[1] |= (in[2] << 1); - out[1] |= (in[3] >> 4); - } - - if (length >= 5) { - out[2] = (in[3] & 15) << 4; - out[2] |= (in[4] >> 1); - } - - if (length >= 7) { - out[3] = (in[4] & 1) << 7; - out[3] |= (in[5] << 2); - out[3] |= (in[6] >> 3); - } - - if (length >= 8) { - out[4] = (in[6] & 7) << 5; - out[4] |= (in[7] & 31); - } + if (length >= 2) { + out[0] = (in[0] << 3); + out[0] |= (in[1] >> 2); + } + + if (length >= 4) { + out[1] = (in[1] & 3) << 6; + out[1] |= (in[2] << 1); + out[1] |= (in[3] >> 4); + } + + if (length >= 5) { + out[2] = (in[3] & 15) << 4; + out[2] |= (in[4] >> 1); + } + + if (length >= 7) { + out[3] = (in[4] & 1) << 7; + out[3] |= (in[5] << 2); + out[3] |= (in[6] >> 3); + } + + if (length >= 8) { + out[4] = (in[6] & 7) << 5; + out[4] |= (in[7] & 31); + } } int base32_encode_character(uint8_t decoded, const char *alphabet) { - if (decoded >> 5) { - return -1; - } - - if (alphabet == BASE32_ALPHABET_RFC4648) { - if (decoded < 26) { - return 'A' + decoded; - } else { - return '2' - 26 + decoded; - } - } - - return alphabet[decoded]; + if (decoded >> 5) { + return -1; + } + + if (alphabet == BASE32_ALPHABET_RFC4648) { + if (decoded < 26) { + return 'A' + decoded; + } else { + return '2' - 26 + decoded; + } + } + + return alphabet[decoded]; } int base32_decode_character(char encoded, const char *alphabet) { - if (alphabet == BASE32_ALPHABET_RFC4648) { - if (encoded >= 'A' && encoded <= 'Z') { - return encoded - 'A'; - } else if (encoded >= 'a' && encoded <= 'z') { - return encoded - 'a'; - } else if (encoded >= '2' && encoded <= '7') { - return encoded - '2' + 26; - } else { - return -1; - } - } - - const char *occurrence = strchr(alphabet, encoded); - - if (occurrence) { - return occurrence - alphabet; - } else { - return -1; - } + if (alphabet == BASE32_ALPHABET_RFC4648) { + if (encoded >= 'A' && encoded <= 'Z') { + return encoded - 'A'; + } else if (encoded >= 'a' && encoded <= 'z') { + return encoded - 'a'; + } else if (encoded >= '2' && encoded <= '7') { + return encoded - '2' + 26; + } else { + return -1; + } + } + + const char *occurrence = strchr(alphabet, encoded); + + if (occurrence) { + return occurrence - alphabet; + } else { + return -1; + } } diff --git a/base32.h b/base32.h index 250997967..8b5cc8513 100644 --- a/base32.h +++ b/base32.h @@ -29,11 +29,14 @@ extern const char *BASE32_ALPHABET_RFC4648; -char *base32_encode(const uint8_t *in, size_t inlen, char *out, size_t outlen, const char *alphabet); +char *base32_encode(const uint8_t *in, size_t inlen, char *out, size_t outlen, + const char *alphabet); void base32_encode_unsafe(const uint8_t *in, size_t inlen, uint8_t *out); -uint8_t *base32_decode(const char *in, size_t inlen, uint8_t *out, size_t outlen, const char *alphabet); -bool base32_decode_unsafe(const uint8_t *in, size_t inlen, uint8_t *out, const char *alphabet); +uint8_t *base32_decode(const char *in, size_t inlen, uint8_t *out, + size_t outlen, const char *alphabet); +bool base32_decode_unsafe(const uint8_t *in, size_t inlen, uint8_t *out, + const char *alphabet); size_t base32_encoded_length(size_t inlen); size_t base32_decoded_length(size_t inlen); diff --git a/base58.c b/base58.c index cd74617b8..d3a1ddb7e 100644 --- a/base58.c +++ b/base58.c @@ -21,265 +21,248 @@ * OTHER DEALINGS IN THE SOFTWARE. */ -#include +#include "base58.h" #include +#include #include -#include "base58.h" -#include "sha2.h" -#include "ripemd160.h" #include "memzero.h" +#include "ripemd160.h" +#include "sha2.h" -const char b58digits_ordered[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; +const char b58digits_ordered[] = + "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; const int8_t b58digits_map[] = { - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1, 0, 1, 2, 3, 4, 5, 6, 7, 8,-1,-1,-1,-1,-1,-1, - -1, 9,10,11,12,13,14,15,16,-1,17,18,19,20,21,-1, - 22,23,24,25,26,27,28,29,30,31,32,-1,-1,-1,-1,-1, - -1,33,34,35,36,37,38,39,40,41,42,43,-1,44,45,46, - 47,48,49,50,51,52,53,54,55,56,57,-1,-1,-1,-1,-1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, + 8, -1, -1, -1, -1, -1, -1, -1, 9, 10, 11, 12, 13, 14, 15, 16, -1, 17, 18, + 19, 20, 21, -1, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, -1, -1, -1, -1, + -1, -1, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, -1, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, -1, -1, -1, -1, }; -bool b58tobin(void *bin, size_t *binszp, const char *b58) -{ - size_t binsz = *binszp; +bool b58tobin(void *bin, size_t *binszp, const char *b58) { + size_t binsz = *binszp; - if (binsz == 0) { - return false; - } + if (binsz == 0) { + return false; + } - const unsigned char *b58u = (const unsigned char*)b58; - unsigned char *binu = bin; - size_t outisz = (binsz + 3) / 4; - uint32_t outi[outisz]; - uint64_t t; - uint32_t c; - size_t i, j; - uint8_t bytesleft = binsz % 4; - uint32_t zeromask = bytesleft ? (0xffffffff << (bytesleft * 8)) : 0; - unsigned zerocount = 0; - size_t b58sz; + const unsigned char *b58u = (const unsigned char *)b58; + unsigned char *binu = bin; + size_t outisz = (binsz + 3) / 4; + uint32_t outi[outisz]; + uint64_t t; + uint32_t c; + size_t i, j; + uint8_t bytesleft = binsz % 4; + uint32_t zeromask = bytesleft ? (0xffffffff << (bytesleft * 8)) : 0; + unsigned zerocount = 0; + size_t b58sz; - b58sz = strlen(b58); + b58sz = strlen(b58); - memzero(outi, sizeof(outi)); + memzero(outi, sizeof(outi)); - // Leading zeros, just count - for (i = 0; i < b58sz && b58u[i] == '1'; ++i) - ++zerocount; + // Leading zeros, just count + for (i = 0; i < b58sz && b58u[i] == '1'; ++i) ++zerocount; - for ( ; i < b58sz; ++i) - { - if (b58u[i] & 0x80) - // High-bit set on invalid digit - return false; - if (b58digits_map[b58u[i]] == -1) - // Invalid base58 digit - return false; - c = (unsigned)b58digits_map[b58u[i]]; - for (j = outisz; j--; ) - { - t = ((uint64_t)outi[j]) * 58 + c; - c = (t & 0x3f00000000) >> 32; - outi[j] = t & 0xffffffff; - } - if (c) - // Output number too big (carry to the next int32) - return false; - if (outi[0] & zeromask) - // Output number too big (last int32 filled too far) - return false; - } + for (; i < b58sz; ++i) { + if (b58u[i] & 0x80) + // High-bit set on invalid digit + return false; + if (b58digits_map[b58u[i]] == -1) + // Invalid base58 digit + return false; + c = (unsigned)b58digits_map[b58u[i]]; + for (j = outisz; j--;) { + t = ((uint64_t)outi[j]) * 58 + c; + c = (t & 0x3f00000000) >> 32; + outi[j] = t & 0xffffffff; + } + if (c) + // Output number too big (carry to the next int32) + return false; + if (outi[0] & zeromask) + // Output number too big (last int32 filled too far) + return false; + } - j = 0; - switch (bytesleft) { - case 3: - *(binu++) = (outi[0] & 0xff0000) >> 16; - //-fallthrough - case 2: - *(binu++) = (outi[0] & 0xff00) >> 8; - //-fallthrough - case 1: - *(binu++) = (outi[0] & 0xff); - ++j; - //-fallthrough - default: - break; - } + j = 0; + switch (bytesleft) { + case 3: + *(binu++) = (outi[0] & 0xff0000) >> 16; + //-fallthrough + case 2: + *(binu++) = (outi[0] & 0xff00) >> 8; + //-fallthrough + case 1: + *(binu++) = (outi[0] & 0xff); + ++j; + //-fallthrough + default: + break; + } - for (; j < outisz; ++j) - { - *(binu++) = (outi[j] >> 0x18) & 0xff; - *(binu++) = (outi[j] >> 0x10) & 0xff; - *(binu++) = (outi[j] >> 8) & 0xff; - *(binu++) = (outi[j] >> 0) & 0xff; - } + for (; j < outisz; ++j) { + *(binu++) = (outi[j] >> 0x18) & 0xff; + *(binu++) = (outi[j] >> 0x10) & 0xff; + *(binu++) = (outi[j] >> 8) & 0xff; + *(binu++) = (outi[j] >> 0) & 0xff; + } - // Count canonical base58 byte count - binu = bin; - for (i = 0; i < binsz; ++i) - { - if (binu[i]) { - if (zerocount > i) { - /* result too large */ - return false; - } - break; - } - --*binszp; - } - *binszp += zerocount; + // Count canonical base58 byte count + binu = bin; + for (i = 0; i < binsz; ++i) { + if (binu[i]) { + if (zerocount > i) { + /* result too large */ + return false; + } + break; + } + --*binszp; + } + *binszp += zerocount; - return true; + return true; } -int b58check(const void *bin, size_t binsz, HasherType hasher_type, const char *base58str) -{ - unsigned char buf[32]; - const uint8_t *binc = bin; - unsigned i; - if (binsz < 4) - return -4; - hasher_Raw(hasher_type, bin, binsz - 4, buf); - if (memcmp(&binc[binsz - 4], buf, 4)) - return -1; +int b58check(const void *bin, size_t binsz, HasherType hasher_type, + const char *base58str) { + unsigned char buf[32]; + const uint8_t *binc = bin; + unsigned i; + if (binsz < 4) return -4; + hasher_Raw(hasher_type, bin, binsz - 4, buf); + if (memcmp(&binc[binsz - 4], buf, 4)) return -1; - // Check number of zeros is correct AFTER verifying checksum (to avoid possibility of accessing base58str beyond the end) - for (i = 0; binc[i] == '\0' && base58str[i] == '1'; ++i) - {} // Just finding the end of zeros, nothing to do in loop - if (binc[i] == '\0' || base58str[i] == '1') - return -3; + // Check number of zeros is correct AFTER verifying checksum (to avoid + // possibility of accessing base58str beyond the end) + for (i = 0; binc[i] == '\0' && base58str[i] == '1'; ++i) { + } // Just finding the end of zeros, nothing to do in loop + if (binc[i] == '\0' || base58str[i] == '1') return -3; - return binc[0]; + return binc[0]; } -bool b58enc(char *b58, size_t *b58sz, const void *data, size_t binsz) -{ - const uint8_t *bin = data; - int carry; - ssize_t i, j, high, zcount = 0; - size_t size; +bool b58enc(char *b58, size_t *b58sz, const void *data, size_t binsz) { + const uint8_t *bin = data; + int carry; + ssize_t i, j, high, zcount = 0; + size_t size; - while (zcount < (ssize_t)binsz && !bin[zcount]) - ++zcount; + while (zcount < (ssize_t)binsz && !bin[zcount]) ++zcount; - size = (binsz - zcount) * 138 / 100 + 1; - uint8_t buf[size]; - memzero(buf, size); + size = (binsz - zcount) * 138 / 100 + 1; + uint8_t buf[size]; + memzero(buf, size); - for (i = zcount, high = size - 1; i < (ssize_t)binsz; ++i, high = j) - { - for (carry = bin[i], j = size - 1; (j > high) || carry; --j) - { - carry += 256 * buf[j]; - buf[j] = carry % 58; - carry /= 58; - } - } + for (i = zcount, high = size - 1; i < (ssize_t)binsz; ++i, high = j) { + for (carry = bin[i], j = size - 1; (j > high) || carry; --j) { + carry += 256 * buf[j]; + buf[j] = carry % 58; + carry /= 58; + } + } - for (j = 0; j < (ssize_t)size && !buf[j]; ++j); + for (j = 0; j < (ssize_t)size && !buf[j]; ++j) + ; - if (*b58sz <= zcount + size - j) - { - *b58sz = zcount + size - j + 1; - return false; - } + if (*b58sz <= zcount + size - j) { + *b58sz = zcount + size - j + 1; + return false; + } - if (zcount) - memset(b58, '1', zcount); - for (i = zcount; j < (ssize_t)size; ++i, ++j) - b58[i] = b58digits_ordered[buf[j]]; - b58[i] = '\0'; - *b58sz = i + 1; + if (zcount) memset(b58, '1', zcount); + for (i = zcount; j < (ssize_t)size; ++i, ++j) + b58[i] = b58digits_ordered[buf[j]]; + b58[i] = '\0'; + *b58sz = i + 1; - return true; + return true; } -int base58_encode_check(const uint8_t *data, int datalen, HasherType hasher_type, char *str, int strsize) -{ - if (datalen > 128) { - return 0; - } - uint8_t buf[datalen + 32]; - uint8_t *hash = buf + datalen; - memcpy(buf, data, datalen); - hasher_Raw(hasher_type, data, datalen, hash); - size_t res = strsize; - bool success = b58enc(str, &res, buf, datalen + 4); - memzero(buf, sizeof(buf)); - return success ? res : 0; +int base58_encode_check(const uint8_t *data, int datalen, + HasherType hasher_type, char *str, int strsize) { + if (datalen > 128) { + return 0; + } + uint8_t buf[datalen + 32]; + uint8_t *hash = buf + datalen; + memcpy(buf, data, datalen); + hasher_Raw(hasher_type, data, datalen, hash); + size_t res = strsize; + bool success = b58enc(str, &res, buf, datalen + 4); + memzero(buf, sizeof(buf)); + return success ? res : 0; } -int base58_decode_check(const char *str, HasherType hasher_type, uint8_t *data, int datalen) -{ - if (datalen > 128) { - return 0; - } - uint8_t d[datalen + 4]; - size_t res = datalen + 4; - if (b58tobin(d, &res, str) != true) { - return 0; - } - uint8_t *nd = d + datalen + 4 - res; - if (b58check(nd, res, hasher_type, str) < 0) { - return 0; - } - memcpy(data, nd, res - 4); - return res - 4; +int base58_decode_check(const char *str, HasherType hasher_type, uint8_t *data, + int datalen) { + if (datalen > 128) { + return 0; + } + uint8_t d[datalen + 4]; + size_t res = datalen + 4; + if (b58tobin(d, &res, str) != true) { + return 0; + } + uint8_t *nd = d + datalen + 4 - res; + if (b58check(nd, res, hasher_type, str) < 0) { + return 0; + } + memcpy(data, nd, res - 4); + return res - 4; } #if USE_GRAPHENE -int b58gphcheck(const void *bin, size_t binsz, const char *base58str) -{ - unsigned char buf[32]; - const uint8_t *binc = bin; - unsigned i; - if (binsz < 4) - return -4; - ripemd160(bin, binsz - 4, buf); // No double SHA256, but a single RIPEMD160 - if (memcmp(&binc[binsz - 4], buf, 4)) - return -1; +int b58gphcheck(const void *bin, size_t binsz, const char *base58str) { + unsigned char buf[32]; + const uint8_t *binc = bin; + unsigned i; + if (binsz < 4) return -4; + ripemd160(bin, binsz - 4, buf); // No double SHA256, but a single RIPEMD160 + if (memcmp(&binc[binsz - 4], buf, 4)) return -1; - // Check number of zeros is correct AFTER verifying checksum (to avoid possibility of accessing base58str beyond the end) - for (i = 0; binc[i] == '\0' && base58str[i] == '1'; ++i) - {} // Just finding the end of zeros, nothing to do in loop - if (binc[i] == '\0' || base58str[i] == '1') - return -3; + // Check number of zeros is correct AFTER verifying checksum (to avoid + // possibility of accessing base58str beyond the end) + for (i = 0; binc[i] == '\0' && base58str[i] == '1'; ++i) { + } // Just finding the end of zeros, nothing to do in loop + if (binc[i] == '\0' || base58str[i] == '1') return -3; - return binc[0]; + return binc[0]; } -int base58gph_encode_check(const uint8_t *data, int datalen, char *str, int strsize) -{ - if (datalen > 128) { - return 0; - } - uint8_t buf[datalen + 32]; - uint8_t *hash = buf + datalen; - memcpy(buf, data, datalen); - ripemd160(data, datalen, hash); // No double SHA256, but a single RIPEMD160 - size_t res = strsize; - bool success = b58enc(str, &res, buf, datalen + 4); - memzero(buf, sizeof(buf)); - return success ? res : 0; +int base58gph_encode_check(const uint8_t *data, int datalen, char *str, + int strsize) { + if (datalen > 128) { + return 0; + } + uint8_t buf[datalen + 32]; + uint8_t *hash = buf + datalen; + memcpy(buf, data, datalen); + ripemd160(data, datalen, hash); // No double SHA256, but a single RIPEMD160 + size_t res = strsize; + bool success = b58enc(str, &res, buf, datalen + 4); + memzero(buf, sizeof(buf)); + return success ? res : 0; } -int base58gph_decode_check(const char *str, uint8_t *data, int datalen) -{ - if (datalen > 128) { - return 0; - } - uint8_t d[datalen + 4]; - size_t res = datalen + 4; - if (b58tobin(d, &res, str) != true) { - return 0; - } - uint8_t *nd = d + datalen + 4 - res; - if (b58gphcheck(nd, res, str) < 0) { - return 0; - } - memcpy(data, nd, res - 4); - return res - 4; +int base58gph_decode_check(const char *str, uint8_t *data, int datalen) { + if (datalen > 128) { + return 0; + } + uint8_t d[datalen + 4]; + size_t res = datalen + 4; + if (b58tobin(d, &res, str) != true) { + return 0; + } + uint8_t *nd = d + datalen + 4 - res; + if (b58gphcheck(nd, res, str) < 0) { + return 0; + } + memcpy(data, nd, res - 4); + return res - 4; } #endif diff --git a/base58.h b/base58.h index 0fa9167bf..97cb54e60 100644 --- a/base58.h +++ b/base58.h @@ -24,24 +24,28 @@ #ifndef __BASE58_H__ #define __BASE58_H__ -#include #include +#include #include "hasher.h" #include "options.h" extern const char b58digits_ordered[]; extern const int8_t b58digits_map[]; -int base58_encode_check(const uint8_t *data, int len, HasherType hasher_type, char *str, int strsize); -int base58_decode_check(const char *str, HasherType hasher_type, uint8_t *data, int datalen); +int base58_encode_check(const uint8_t *data, int len, HasherType hasher_type, + char *str, int strsize); +int base58_decode_check(const char *str, HasherType hasher_type, uint8_t *data, + int datalen); // Private bool b58tobin(void *bin, size_t *binszp, const char *b58); -int b58check(const void *bin, size_t binsz, HasherType hasher_type, const char *base58str); +int b58check(const void *bin, size_t binsz, HasherType hasher_type, + const char *base58str); bool b58enc(char *b58, size_t *b58sz, const void *data, size_t binsz); #if USE_GRAPHENE -int base58gph_encode_check(const uint8_t *data, int datalen, char *str, int strsize); +int base58gph_encode_check(const uint8_t *data, int datalen, char *str, + int strsize); int base58gph_decode_check(const char *str, uint8_t *data, int datalen); int b58gphcheck(const void *bin, size_t binsz, const char *base58str); #endif diff --git a/bignum.c b/bignum.c index 30e711d02..11f3dba52 100644 --- a/bignum.c +++ b/bignum.c @@ -23,10 +23,10 @@ * OTHER DEALINGS IN THE SOFTWARE. */ +#include "bignum.h" +#include #include #include -#include -#include "bignum.h" #include "memzero.h" /* big number library */ @@ -54,298 +54,272 @@ * 2^256 and it must be a prime number. */ -inline uint32_t read_be(const uint8_t *data) -{ - return (((uint32_t)data[0]) << 24) | - (((uint32_t)data[1]) << 16) | - (((uint32_t)data[2]) << 8) | - (((uint32_t)data[3])); +inline uint32_t read_be(const uint8_t *data) { + return (((uint32_t)data[0]) << 24) | (((uint32_t)data[1]) << 16) | + (((uint32_t)data[2]) << 8) | (((uint32_t)data[3])); } -inline void write_be(uint8_t *data, uint32_t x) -{ - data[0] = x >> 24; - data[1] = x >> 16; - data[2] = x >> 8; - data[3] = x; +inline void write_be(uint8_t *data, uint32_t x) { + data[0] = x >> 24; + data[1] = x >> 16; + data[2] = x >> 8; + data[3] = x; } -inline uint32_t read_le(const uint8_t *data) -{ - return (((uint32_t)data[3]) << 24) | - (((uint32_t)data[2]) << 16) | - (((uint32_t)data[1]) << 8) | - (((uint32_t)data[0])); +inline uint32_t read_le(const uint8_t *data) { + return (((uint32_t)data[3]) << 24) | (((uint32_t)data[2]) << 16) | + (((uint32_t)data[1]) << 8) | (((uint32_t)data[0])); } -inline void write_le(uint8_t *data, uint32_t x) -{ - data[3] = x >> 24; - data[2] = x >> 16; - data[1] = x >> 8; - data[0] = x; +inline void write_le(uint8_t *data, uint32_t x) { + data[3] = x >> 24; + data[2] = x >> 16; + data[1] = x >> 8; + data[0] = x; } // convert a raw bigendian 256 bit value into a normalized bignum. // out_number is partly reduced (since it fits in 256 bit). -void bn_read_be(const uint8_t *in_number, bignum256 *out_number) -{ - int i; - uint32_t temp = 0; - for (i = 0; i < 8; i++) { - // invariant: temp = (in_number % 2^(32i)) >> 30i - // get next limb = (in_number % 2^(32(i+1))) >> 32i - uint32_t limb = read_be(in_number + (7 - i) * 4); - // temp = (in_number % 2^(32(i+1))) << 30i - temp |= limb << (2*i); - // store 30 bits into val[i] - out_number->val[i]= temp & 0x3FFFFFFF; - // prepare temp for next round - temp = limb >> (30 - 2*i); - } - out_number->val[8] = temp; +void bn_read_be(const uint8_t *in_number, bignum256 *out_number) { + int i; + uint32_t temp = 0; + for (i = 0; i < 8; i++) { + // invariant: temp = (in_number % 2^(32i)) >> 30i + // get next limb = (in_number % 2^(32(i+1))) >> 32i + uint32_t limb = read_be(in_number + (7 - i) * 4); + // temp = (in_number % 2^(32(i+1))) << 30i + temp |= limb << (2 * i); + // store 30 bits into val[i] + out_number->val[i] = temp & 0x3FFFFFFF; + // prepare temp for next round + temp = limb >> (30 - 2 * i); + } + out_number->val[8] = temp; } // convert a normalized bignum to a raw bigendian 256 bit number. // in_number must be fully reduced. -void bn_write_be(const bignum256 *in_number, uint8_t *out_number) -{ - int i; - uint32_t temp = in_number->val[8]; - for (i = 0; i < 8; i++) { - // invariant: temp = (in_number >> 30*(8-i)) - uint32_t limb = in_number->val[7 - i]; - temp = (temp << (16 + 2*i)) | (limb >> (14 - 2*i)); - write_be(out_number + i * 4, temp); - temp = limb; - } +void bn_write_be(const bignum256 *in_number, uint8_t *out_number) { + int i; + uint32_t temp = in_number->val[8]; + for (i = 0; i < 8; i++) { + // invariant: temp = (in_number >> 30*(8-i)) + uint32_t limb = in_number->val[7 - i]; + temp = (temp << (16 + 2 * i)) | (limb >> (14 - 2 * i)); + write_be(out_number + i * 4, temp); + temp = limb; + } } // convert a raw little endian 256 bit value into a normalized bignum. // out_number is partly reduced (since it fits in 256 bit). -void bn_read_le(const uint8_t *in_number, bignum256 *out_number) -{ - int i; - uint32_t temp = 0; - for (i = 0; i < 8; i++) { - // invariant: temp = (in_number % 2^(32i)) >> 30i - // get next limb = (in_number % 2^(32(i+1))) >> 32i - uint32_t limb = read_le(in_number + i * 4); - // temp = (in_number % 2^(32(i+1))) << 30i - temp |= limb << (2*i); - // store 30 bits into val[i] - out_number->val[i]= temp & 0x3FFFFFFF; - // prepare temp for next round - temp = limb >> (30 - 2*i); - } - out_number->val[8] = temp; +void bn_read_le(const uint8_t *in_number, bignum256 *out_number) { + int i; + uint32_t temp = 0; + for (i = 0; i < 8; i++) { + // invariant: temp = (in_number % 2^(32i)) >> 30i + // get next limb = (in_number % 2^(32(i+1))) >> 32i + uint32_t limb = read_le(in_number + i * 4); + // temp = (in_number % 2^(32(i+1))) << 30i + temp |= limb << (2 * i); + // store 30 bits into val[i] + out_number->val[i] = temp & 0x3FFFFFFF; + // prepare temp for next round + temp = limb >> (30 - 2 * i); + } + out_number->val[8] = temp; } // convert a normalized bignum to a raw little endian 256 bit number. // in_number must be fully reduced. -void bn_write_le(const bignum256 *in_number, uint8_t *out_number) -{ - int i; - uint32_t temp = in_number->val[8]; - for (i = 0; i < 8; i++) { - // invariant: temp = (in_number >> 30*(8-i)) - uint32_t limb = in_number->val[7 - i]; - temp = (temp << (16 + 2*i)) | (limb >> (14 - 2*i)); - write_le(out_number + (7 - i) * 4, temp); - temp = limb; - } +void bn_write_le(const bignum256 *in_number, uint8_t *out_number) { + int i; + uint32_t temp = in_number->val[8]; + for (i = 0; i < 8; i++) { + // invariant: temp = (in_number >> 30*(8-i)) + uint32_t limb = in_number->val[7 - i]; + temp = (temp << (16 + 2 * i)) | (limb >> (14 - 2 * i)); + write_le(out_number + (7 - i) * 4, temp); + temp = limb; + } } -void bn_read_uint32(uint32_t in_number, bignum256 *out_number) -{ - out_number->val[0] = in_number & 0x3FFFFFFF; - out_number->val[1] = in_number >> 30; - out_number->val[2] = 0; - out_number->val[3] = 0; - out_number->val[4] = 0; - out_number->val[5] = 0; - out_number->val[6] = 0; - out_number->val[7] = 0; - out_number->val[8] = 0; +void bn_read_uint32(uint32_t in_number, bignum256 *out_number) { + out_number->val[0] = in_number & 0x3FFFFFFF; + out_number->val[1] = in_number >> 30; + out_number->val[2] = 0; + out_number->val[3] = 0; + out_number->val[4] = 0; + out_number->val[5] = 0; + out_number->val[6] = 0; + out_number->val[7] = 0; + out_number->val[8] = 0; } -void bn_read_uint64(uint64_t in_number, bignum256 *out_number) -{ - out_number->val[0] = in_number & 0x3FFFFFFF; - out_number->val[1] = (in_number >>= 30) & 0x3FFFFFFF; - out_number->val[2] = in_number >>= 30; - out_number->val[3] = 0; - out_number->val[4] = 0; - out_number->val[5] = 0; - out_number->val[6] = 0; - out_number->val[7] = 0; - out_number->val[8] = 0; +void bn_read_uint64(uint64_t in_number, bignum256 *out_number) { + out_number->val[0] = in_number & 0x3FFFFFFF; + out_number->val[1] = (in_number >>= 30) & 0x3FFFFFFF; + out_number->val[2] = in_number >>= 30; + out_number->val[3] = 0; + out_number->val[4] = 0; + out_number->val[5] = 0; + out_number->val[6] = 0; + out_number->val[7] = 0; + out_number->val[8] = 0; } // a must be normalized -int bn_bitcount(const bignum256 *a) -{ - int i; - for (i = 8; i >= 0; i--) { - int tmp = a->val[i]; - if (tmp != 0) { - return i * 30 + (32 - __builtin_clz(tmp)); - } - } - return 0; +int bn_bitcount(const bignum256 *a) { + int i; + for (i = 8; i >= 0; i--) { + int tmp = a->val[i]; + if (tmp != 0) { + return i * 30 + (32 - __builtin_clz(tmp)); + } + } + return 0; } -#define DIGITS 78 // log10(2 ^ 256) +#define DIGITS 78 // log10(2 ^ 256) -unsigned int bn_digitcount(const bignum256 *a) -{ - bignum256 val; - memcpy(&val, a, sizeof(bignum256)); +unsigned int bn_digitcount(const bignum256 *a) { + bignum256 val; + memcpy(&val, a, sizeof(bignum256)); - unsigned int digits = 1; + unsigned int digits = 1; - for (unsigned int i = 0; i < DIGITS; i += 3) { - uint32_t limb; - bn_divmod1000(&val, &limb); + for (unsigned int i = 0; i < DIGITS; i += 3) { + uint32_t limb; + bn_divmod1000(&val, &limb); - if (limb >= 100) { - digits = i + 3; - } else if (limb >= 10) { - digits = i + 2; - } else if (limb >= 1) { - digits = i + 1; - } - } + if (limb >= 100) { + digits = i + 3; + } else if (limb >= 10) { + digits = i + 2; + } else if (limb >= 1) { + digits = i + 1; + } + } - return digits; + return digits; } // sets a bignum to zero. -void bn_zero(bignum256 *a) -{ - int i; - for (i = 0; i < 9; i++) { - a->val[i] = 0; - } +void bn_zero(bignum256 *a) { + int i; + for (i = 0; i < 9; i++) { + a->val[i] = 0; + } } // sets a bignum to one. -void bn_one(bignum256 *a) -{ - a->val[0] = 1; - a->val[1] = 0; - a->val[2] = 0; - a->val[3] = 0; - a->val[4] = 0; - a->val[5] = 0; - a->val[6] = 0; - a->val[7] = 0; - a->val[8] = 0; +void bn_one(bignum256 *a) { + a->val[0] = 1; + a->val[1] = 0; + a->val[2] = 0; + a->val[3] = 0; + a->val[4] = 0; + a->val[5] = 0; + a->val[6] = 0; + a->val[7] = 0; + a->val[8] = 0; } // checks that a bignum is zero. // a must be normalized // function is constant time (on some architectures, in particular ARM). -int bn_is_zero(const bignum256 *a) -{ - int i; - uint32_t result = 0; - for (i = 0; i < 9; i++) { - result |= a->val[i]; - } - return !result; +int bn_is_zero(const bignum256 *a) { + int i; + uint32_t result = 0; + for (i = 0; i < 9; i++) { + result |= a->val[i]; + } + return !result; } // Check whether a < b // a and b must be normalized // function is constant time (on some architectures, in particular ARM). -int bn_is_less(const bignum256 *a, const bignum256 *b) -{ - int i; - uint32_t res1 = 0; - uint32_t res2 = 0; - for (i = 8; i >= 0; i--) { - res1 = (res1 << 1) | (a->val[i] < b->val[i]); - res2 = (res2 << 1) | (a->val[i] > b->val[i]); - } - return res1 > res2; +int bn_is_less(const bignum256 *a, const bignum256 *b) { + int i; + uint32_t res1 = 0; + uint32_t res2 = 0; + for (i = 8; i >= 0; i--) { + res1 = (res1 << 1) | (a->val[i] < b->val[i]); + res2 = (res2 << 1) | (a->val[i] > b->val[i]); + } + return res1 > res2; } // Check whether a == b // a and b must be normalized // function is constant time (on some architectures, in particular ARM). int bn_is_equal(const bignum256 *a, const bignum256 *b) { - int i; - uint32_t result = 0; - for (i = 0; i < 9; i++) { - result |= (a->val[i] ^ b->val[i]); - } - return !result; + int i; + uint32_t result = 0; + for (i = 0; i < 9; i++) { + result |= (a->val[i] ^ b->val[i]); + } + return !result; } // Assigns res = cond ? truecase : falsecase // assumes that cond is either 0 or 1. // function is constant time. -void bn_cmov(bignum256 *res, int cond, const bignum256 *truecase, const bignum256 *falsecase) -{ - int i; - uint32_t tmask = (uint32_t) -cond; - uint32_t fmask = ~tmask; - - assert (cond == 1 || cond == 0); - for (i = 0; i < 9; i++) { - res->val[i] = (truecase->val[i] & tmask) | - (falsecase->val[i] & fmask); - } +void bn_cmov(bignum256 *res, int cond, const bignum256 *truecase, + const bignum256 *falsecase) { + int i; + uint32_t tmask = (uint32_t)-cond; + uint32_t fmask = ~tmask; + + assert(cond == 1 || cond == 0); + for (i = 0; i < 9; i++) { + res->val[i] = (truecase->val[i] & tmask) | (falsecase->val[i] & fmask); + } } // shift number to the left, i.e multiply it by 2. // a must be normalized. The result is normalized but not reduced. -void bn_lshift(bignum256 *a) -{ - int i; - for (i = 8; i > 0; i--) { - a->val[i] = ((a->val[i] << 1) & 0x3FFFFFFF) | ((a->val[i - 1] & 0x20000000) >> 29); - } - a->val[0] = (a->val[0] << 1) & 0x3FFFFFFF; +void bn_lshift(bignum256 *a) { + int i; + for (i = 8; i > 0; i--) { + a->val[i] = + ((a->val[i] << 1) & 0x3FFFFFFF) | ((a->val[i - 1] & 0x20000000) >> 29); + } + a->val[0] = (a->val[0] << 1) & 0x3FFFFFFF; } // shift number to the right, i.e divide by 2 while rounding down. // a must be normalized. The result is normalized. -void bn_rshift(bignum256 *a) -{ - int i; - for (i = 0; i < 8; i++) { - a->val[i] = (a->val[i] >> 1) | ((a->val[i + 1] & 1) << 29); - } - a->val[8] >>= 1; +void bn_rshift(bignum256 *a) { + int i; + for (i = 0; i < 8; i++) { + a->val[i] = (a->val[i] >> 1) | ((a->val[i + 1] & 1) << 29); + } + a->val[8] >>= 1; } // sets bit in bignum -void bn_setbit(bignum256 *a, uint8_t bit) -{ - a->val[bit / 30] |= (1u << (bit % 30)); +void bn_setbit(bignum256 *a, uint8_t bit) { + a->val[bit / 30] |= (1u << (bit % 30)); } // clears bit in bignum -void bn_clearbit(bignum256 *a, uint8_t bit) -{ - a->val[bit / 30] &= ~(1u << (bit % 30)); +void bn_clearbit(bignum256 *a, uint8_t bit) { + a->val[bit / 30] &= ~(1u << (bit % 30)); } // tests bit in bignum -uint32_t bn_testbit(bignum256 *a, uint8_t bit) -{ - return a->val[bit / 30] & (1u << (bit % 30)); +uint32_t bn_testbit(bignum256 *a, uint8_t bit) { + return a->val[bit / 30] & (1u << (bit % 30)); } // a = b ^ c -void bn_xor(bignum256 *a, const bignum256 *b, const bignum256 *c) -{ - int i; - for (i = 0; i < 9; i++) { - a->val[i] = b->val[i] ^ c->val[i]; - } +void bn_xor(bignum256 *a, const bignum256 *b, const bignum256 *c) { + int i; + for (i = 0; i < 9; i++) { + a->val[i] = b->val[i] ^ c->val[i]; + } } // multiply x by 1/2 modulo prime. @@ -353,74 +327,69 @@ void bn_xor(bignum256 *a, const bignum256 *b, const bignum256 *c) // assumes x is normalized. // if x was partly reduced, it is also partly reduced on exit. // function is constant time. -void bn_mult_half(bignum256 * x, const bignum256 *prime) -{ - int j; - uint32_t xodd = -(x->val[0] & 1); - // compute x = x/2 mod prime - // if x is odd compute (x+prime)/2 - uint32_t tmp1 = (x->val[0] + (prime->val[0] & xodd)) >> 1; - for (j = 0; j < 8; j++) { - uint32_t tmp2 = (x->val[j+1] + (prime->val[j+1] & xodd)); - tmp1 += (tmp2 & 1) << 29; - x->val[j] = tmp1 & 0x3fffffff; - tmp1 >>= 30; - tmp1 += tmp2 >> 1; - } - x->val[8] = tmp1; +void bn_mult_half(bignum256 *x, const bignum256 *prime) { + int j; + uint32_t xodd = -(x->val[0] & 1); + // compute x = x/2 mod prime + // if x is odd compute (x+prime)/2 + uint32_t tmp1 = (x->val[0] + (prime->val[0] & xodd)) >> 1; + for (j = 0; j < 8; j++) { + uint32_t tmp2 = (x->val[j + 1] + (prime->val[j + 1] & xodd)); + tmp1 += (tmp2 & 1) << 29; + x->val[j] = tmp1 & 0x3fffffff; + tmp1 >>= 30; + tmp1 += tmp2 >> 1; + } + x->val[8] = tmp1; } // multiply x by k modulo prime. // assumes x is normalized, 0 <= k <= 4. // guarantees x is partly reduced. -void bn_mult_k(bignum256 *x, uint8_t k, const bignum256 *prime) -{ - int j; - for (j = 0; j < 9; j++) { - x->val[j] = k * x->val[j]; - } - bn_fast_mod(x, prime); +void bn_mult_k(bignum256 *x, uint8_t k, const bignum256 *prime) { + int j; + for (j = 0; j < 9; j++) { + x->val[j] = k * x->val[j]; + } + bn_fast_mod(x, prime); } // compute x = x mod prime by computing x >= prime ? x - prime : x. // assumes x partly reduced, guarantees x fully reduced. -void bn_mod(bignum256 *x, const bignum256 *prime) -{ - const int flag = bn_is_less(x, prime); // x < prime - bignum256 temp; - bn_subtract(x, prime, &temp); // temp = x - prime - bn_cmov(x, flag, x, &temp); +void bn_mod(bignum256 *x, const bignum256 *prime) { + const int flag = bn_is_less(x, prime); // x < prime + bignum256 temp; + bn_subtract(x, prime, &temp); // temp = x - prime + bn_cmov(x, flag, x, &temp); } // auxiliary function for multiplication. // compute k * x as a 540 bit number in base 2^30 (normalized). // assumes that k and x are normalized. -void bn_multiply_long(const bignum256 *k, const bignum256 *x, uint32_t res[18]) -{ - int i, j; - uint64_t temp = 0; - - // compute lower half of long multiplication - for (i = 0; i < 9; i++) - { - for (j = 0; j <= i; j++) { - // no overflow, since 9*2^60 < 2^64 - temp += k->val[j] * (uint64_t)x->val[i - j]; - } - res[i] = temp & 0x3FFFFFFFu; - temp >>= 30; - } - // compute upper half - for (; i < 17; i++) - { - for (j = i - 8; j < 9 ; j++) { - // no overflow, since 9*2^60 < 2^64 - temp += k->val[j] * (uint64_t)x->val[i - j]; - } - res[i] = temp & 0x3FFFFFFFu; - temp >>= 30; - } - res[17] = temp; +void bn_multiply_long(const bignum256 *k, const bignum256 *x, + uint32_t res[18]) { + int i, j; + uint64_t temp = 0; + + // compute lower half of long multiplication + for (i = 0; i < 9; i++) { + for (j = 0; j <= i; j++) { + // no overflow, since 9*2^60 < 2^64 + temp += k->val[j] * (uint64_t)x->val[i - j]; + } + res[i] = temp & 0x3FFFFFFFu; + temp >>= 30; + } + // compute upper half + for (; i < 17; i++) { + for (j = i - 8; j < 9; j++) { + // no overflow, since 9*2^60 < 2^64 + temp += k->val[j] * (uint64_t)x->val[i - j]; + } + res[i] = temp & 0x3FFFFFFFu; + temp >>= 30; + } + res[17] = temp; } // auxiliary function for multiplication. @@ -428,71 +397,72 @@ void bn_multiply_long(const bignum256 *k, const bignum256 *x, uint32_t res[18]) // assumes i >= 8 and i <= 16 // assumes res normalized, res < 2^(30(i-7)) * 2 * prime // guarantees res normalized, res < 2^(30(i-8)) * 2 * prime -void bn_multiply_reduce_step(uint32_t res[18], const bignum256 *prime, uint32_t i) { - // let k = i-8. - // on entry: - // 0 <= res < 2^(30k + 31) * prime - // estimate coef = (res / prime / 2^30k) - // by coef = res / 2^(30k + 256) rounded down - // 0 <= coef < 2^31 - // subtract (coef * 2^(30k) * prime) from res - // note that we unrolled the first iteration - assert(i >= 8 && i <= 16); - uint32_t j; - uint32_t coef = (res[i] >> 16) + (res[i + 1] << 14); - uint64_t temp = 0x2000000000000000ull + res[i - 8] - prime->val[0] * (uint64_t)coef; - assert (coef < 0x80000000u); - res[i - 8] = temp & 0x3FFFFFFF; - for (j = 1; j < 9; j++) { - temp >>= 30; - // Note: coeff * prime->val[j] <= (2^31-1) * (2^30-1) - // Hence, this addition will not underflow. - temp += 0x1FFFFFFF80000000ull + res[i - 8 + j] - prime->val[j] * (uint64_t)coef; - res[i - 8 + j] = temp & 0x3FFFFFFF; - // 0 <= temp < 2^61 + 2^30 - } - temp >>= 30; - temp += 0x1FFFFFFF80000000ull + res[i - 8 + j]; - res[i - 8 + j] = temp & 0x3FFFFFFF; - // we rely on the fact that prime > 2^256 - 2^224 - // res = oldres - coef*2^(30k) * prime; - // and - // coef * 2^(30k + 256) <= oldres < (coef+1) * 2^(30k + 256) - // Hence, 0 <= res < 2^30k (2^256 + coef * (2^256 - prime)) - // < 2^30k (2^256 + 2^31 * 2^224) - // < 2^30k (2 * prime) +void bn_multiply_reduce_step(uint32_t res[18], const bignum256 *prime, + uint32_t i) { + // let k = i-8. + // on entry: + // 0 <= res < 2^(30k + 31) * prime + // estimate coef = (res / prime / 2^30k) + // by coef = res / 2^(30k + 256) rounded down + // 0 <= coef < 2^31 + // subtract (coef * 2^(30k) * prime) from res + // note that we unrolled the first iteration + assert(i >= 8 && i <= 16); + uint32_t j; + uint32_t coef = (res[i] >> 16) + (res[i + 1] << 14); + uint64_t temp = + 0x2000000000000000ull + res[i - 8] - prime->val[0] * (uint64_t)coef; + assert(coef < 0x80000000u); + res[i - 8] = temp & 0x3FFFFFFF; + for (j = 1; j < 9; j++) { + temp >>= 30; + // Note: coeff * prime->val[j] <= (2^31-1) * (2^30-1) + // Hence, this addition will not underflow. + temp += + 0x1FFFFFFF80000000ull + res[i - 8 + j] - prime->val[j] * (uint64_t)coef; + res[i - 8 + j] = temp & 0x3FFFFFFF; + // 0 <= temp < 2^61 + 2^30 + } + temp >>= 30; + temp += 0x1FFFFFFF80000000ull + res[i - 8 + j]; + res[i - 8 + j] = temp & 0x3FFFFFFF; + // we rely on the fact that prime > 2^256 - 2^224 + // res = oldres - coef*2^(30k) * prime; + // and + // coef * 2^(30k + 256) <= oldres < (coef+1) * 2^(30k + 256) + // Hence, 0 <= res < 2^30k (2^256 + coef * (2^256 - prime)) + // < 2^30k (2^256 + 2^31 * 2^224) + // < 2^30k (2 * prime) } - // auxiliary function for multiplication. // reduces x = res modulo prime. // assumes res normalized, res < 2^270 * 2 * prime // guarantees x partly reduced, i.e., x < 2 * prime -void bn_multiply_reduce(bignum256 *x, uint32_t res[18], const bignum256 *prime) -{ - int i; - // res = k * x is a normalized number (every limb < 2^30) - // 0 <= res < 2^270 * 2 * prime. - for (i = 16; i >= 8; i--) { - bn_multiply_reduce_step(res, prime, i); - assert(res[i + 1] == 0); - } - // store the result - for (i = 0; i < 9; i++) { - x->val[i] = res[i]; - } +void bn_multiply_reduce(bignum256 *x, uint32_t res[18], + const bignum256 *prime) { + int i; + // res = k * x is a normalized number (every limb < 2^30) + // 0 <= res < 2^270 * 2 * prime. + for (i = 16; i >= 8; i--) { + bn_multiply_reduce_step(res, prime, i); + assert(res[i + 1] == 0); + } + // store the result + for (i = 0; i < 9; i++) { + x->val[i] = res[i]; + } } // Compute x := k * x (mod prime) // both inputs must be smaller than 180 * prime. // result is partly reduced (0 <= x < 2 * prime) // This only works for primes between 2^256-2^224 and 2^256. -void bn_multiply(const bignum256 *k, bignum256 *x, const bignum256 *prime) -{ - uint32_t res[18] = {0}; - bn_multiply_long(k, x, res); - bn_multiply_reduce(x, res, prime); - memzero(res, sizeof(res)); +void bn_multiply(const bignum256 *k, bignum256 *x, const bignum256 *prime) { + uint32_t res[18] = {0}; + bn_multiply_long(k, x, res); + bn_multiply_reduce(x, res, prime); + memzero(res, sizeof(res)); } // partly reduce x modulo prime @@ -500,97 +470,95 @@ void bn_multiply(const bignum256 *k, bignum256 *x, const bignum256 *prime) // x can be any number that fits. // prime must be between (2^256 - 2^224) and 2^256 // result is partly reduced, smaller than 2*prime -void bn_fast_mod(bignum256 *x, const bignum256 *prime) -{ - int j; - uint32_t coef; - uint64_t temp; - - coef = x->val[8] >> 16; - // substract (coef * prime) from x - // note that we unrolled the first iteration - temp = 0x2000000000000000ull + x->val[0] - prime->val[0] * (uint64_t)coef; - x->val[0] = temp & 0x3FFFFFFF; - for (j = 1; j < 9; j++) { - temp >>= 30; - temp += 0x1FFFFFFF80000000ull + x->val[j] - prime->val[j] * (uint64_t)coef; - x->val[j] = temp & 0x3FFFFFFF; - } +void bn_fast_mod(bignum256 *x, const bignum256 *prime) { + int j; + uint32_t coef; + uint64_t temp; + + coef = x->val[8] >> 16; + // substract (coef * prime) from x + // note that we unrolled the first iteration + temp = 0x2000000000000000ull + x->val[0] - prime->val[0] * (uint64_t)coef; + x->val[0] = temp & 0x3FFFFFFF; + for (j = 1; j < 9; j++) { + temp >>= 30; + temp += 0x1FFFFFFF80000000ull + x->val[j] - prime->val[j] * (uint64_t)coef; + x->val[j] = temp & 0x3FFFFFFF; + } } // square root of x = x^((p+1)/4) // http://en.wikipedia.org/wiki/Quadratic_residue#Prime_or_prime_power_modulus // assumes x is normalized but not necessarily reduced. // guarantees x is reduced -void bn_sqrt(bignum256 *x, const bignum256 *prime) -{ - // this method compute x^1/2 = x^(prime+1)/4 - uint32_t i, j, limb; - bignum256 res, p; - bn_one(&res); - // compute p = (prime+1)/4 - memcpy(&p, prime, sizeof(bignum256)); - bn_addi(&p, 1); - bn_rshift(&p); - bn_rshift(&p); - for (i = 0; i < 9; i++) { - // invariants: - // x = old(x)^(2^(i*30)) - // res = old(x)^(p % 2^(i*30)) - // get the i-th limb of prime - 2 - limb = p.val[i]; - for (j = 0; j < 30; j++) { - // invariants: - // x = old(x)^(2^(i*30+j)) - // res = old(x)^(p % 2^(i*30+j)) - // limb = (p % 2^(i*30+30)) / 2^(i*30+j) - if (i == 8 && limb == 0) break; - if (limb & 1) { - bn_multiply(x, &res, prime); - } - limb >>= 1; - bn_multiply(x, x, prime); - } - } - bn_mod(&res, prime); - memcpy(x, &res, sizeof(bignum256)); - memzero(&res, sizeof(res)); - memzero(&p, sizeof(p)); +void bn_sqrt(bignum256 *x, const bignum256 *prime) { + // this method compute x^1/2 = x^(prime+1)/4 + uint32_t i, j, limb; + bignum256 res, p; + bn_one(&res); + // compute p = (prime+1)/4 + memcpy(&p, prime, sizeof(bignum256)); + bn_addi(&p, 1); + bn_rshift(&p); + bn_rshift(&p); + for (i = 0; i < 9; i++) { + // invariants: + // x = old(x)^(2^(i*30)) + // res = old(x)^(p % 2^(i*30)) + // get the i-th limb of prime - 2 + limb = p.val[i]; + for (j = 0; j < 30; j++) { + // invariants: + // x = old(x)^(2^(i*30+j)) + // res = old(x)^(p % 2^(i*30+j)) + // limb = (p % 2^(i*30+30)) / 2^(i*30+j) + if (i == 8 && limb == 0) break; + if (limb & 1) { + bn_multiply(x, &res, prime); + } + limb >>= 1; + bn_multiply(x, x, prime); + } + } + bn_mod(&res, prime); + memcpy(x, &res, sizeof(bignum256)); + memzero(&res, sizeof(res)); + memzero(&p, sizeof(p)); } -#if ! USE_INVERSE_FAST +#if !USE_INVERSE_FAST // in field G_prime, small but slow -void bn_inverse(bignum256 *x, const bignum256 *prime) -{ - // this method compute x^-1 = x^(prime-2) - uint32_t i, j, limb; - bignum256 res; - bn_one(&res); - for (i = 0; i < 9; i++) { - // invariants: - // x = old(x)^(2^(i*30)) - // res = old(x)^((prime-2) % 2^(i*30)) - // get the i-th limb of prime - 2 - limb = prime->val[i]; - // this is not enough in general but fine for secp256k1 & nist256p1 because prime->val[0] > 1 - if (i == 0) limb -= 2; - for (j = 0; j < 30; j++) { - // invariants: - // x = old(x)^(2^(i*30+j)) - // res = old(x)^((prime-2) % 2^(i*30+j)) - // limb = ((prime-2) % 2^(i*30+30)) / 2^(i*30+j) - // early abort when only zero bits follow - if (i == 8 && limb == 0) break; - if (limb & 1) { - bn_multiply(x, &res, prime); - } - limb >>= 1; - bn_multiply(x, x, prime); - } - } - bn_mod(&res, prime); - memcpy(x, &res, sizeof(bignum256)); +void bn_inverse(bignum256 *x, const bignum256 *prime) { + // this method compute x^-1 = x^(prime-2) + uint32_t i, j, limb; + bignum256 res; + bn_one(&res); + for (i = 0; i < 9; i++) { + // invariants: + // x = old(x)^(2^(i*30)) + // res = old(x)^((prime-2) % 2^(i*30)) + // get the i-th limb of prime - 2 + limb = prime->val[i]; + // this is not enough in general but fine for secp256k1 & nist256p1 because + // prime->val[0] > 1 + if (i == 0) limb -= 2; + for (j = 0; j < 30; j++) { + // invariants: + // x = old(x)^(2^(i*30+j)) + // res = old(x)^((prime-2) % 2^(i*30+j)) + // limb = ((prime-2) % 2^(i*30+30)) / 2^(i*30+j) + // early abort when only zero bits follow + if (i == 8 && limb == 0) break; + if (limb & 1) { + bn_multiply(x, &res, prime); + } + limb >>= 1; + bn_multiply(x, x, prime); + } + } + bn_mod(&res, prime); + memcpy(x, &res, sizeof(bignum256)); } #else @@ -598,513 +566,503 @@ void bn_inverse(bignum256 *x, const bignum256 *prime) // in field G_prime, big and complicated but fast // the input must not be 0 mod prime. // the result is smaller than prime -void bn_inverse(bignum256 *x, const bignum256 *prime) -{ - int i, j, k, cmp; - struct combo { - uint32_t a[9]; - int len1; - } us, vr, *odd, *even; - uint32_t pp[8]; - uint32_t temp32; - uint64_t temp; - - // The algorithm is based on Schroeppel et. al. "Almost Modular Inverse" - // algorithm. We keep four values u,v,r,s in the combo registers - // us and vr. us stores u in the first len1 limbs (little endian) - // and s in the last 9-len1 limbs (big endian). vr stores v and r. - // This is because both u*s and v*r are guaranteed to fit in 8 limbs, so - // their components are guaranteed to fit in 9. During the algorithm, - // the length of u and v shrinks while r and s grow. - // u,v,r,s correspond to F,G,B,C in Schroeppel's algorithm. - - // reduce x modulo prime. This is necessary as it has to fit in 8 limbs. - bn_fast_mod(x, prime); - bn_mod(x, prime); - // convert x and prime to 8x32 bit limb form - temp32 = prime->val[0]; - for (i = 0; i < 8; i++) { - temp32 |= prime->val[i + 1] << (30-2*i); - us.a[i] = pp[i] = temp32; - temp32 = prime->val[i + 1] >> (2+2*i); - } - temp32 = x->val[0]; - for (i = 0; i < 8; i++) { - temp32 |= x->val[i + 1] << (30-2*i); - vr.a[i] = temp32; - temp32 = x->val[i + 1] >> (2+2*i); - } - us.len1 = 8; - vr.len1 = 8; - // set s = 1 and r = 0 - us.a[8] = 1; - vr.a[8] = 0; - // set k = 0. - k = 0; - - // only one of the numbers u,v can be even at any time. We - // let even point to that number and odd to the other. - // Initially the prime u is guaranteed to be odd. - odd = &us; - even = &vr; - - // u = prime, v = x - // r = 0 , s = 1 - // k = 0 - for (;;) { - // invariants: - // let u = limbs us.a[0..u.len1-1] in little endian, - // let s = limbs us.a[u.len..8] in big endian, - // let v = limbs vr.a[0..u.len1-1] in little endian, - // let r = limbs vr.a[u.len..8] in big endian, - // r,s >= 0 ; u,v >= 1 - // x*-r = u*2^k mod prime - // x*s = v*2^k mod prime - // u*s + v*r = prime - // floor(log2(u)) + floor(log2(v)) + k <= 510 - // max(u,v) <= 2^k (*) see comment at end of loop - // gcd(u,v) = 1 - // {odd,even} = {&us, &vr} - // odd->a[0] and odd->a[8] are odd - // even->a[0] or even->a[8] is even - // - // first u/v are large and r/s small - // later u/v are small and r/s large - assert(odd->a[0] & 1); - assert(odd->a[8] & 1); - - // adjust length of even. - while (even->a[even->len1 - 1] == 0) { - even->len1--; - // if input was 0, return. - // This simple check prevents crashing with stack underflow - // or worse undesired behaviour for illegal input. - if (even->len1 < 0) - return; - } - - // reduce even->a while it is even - while (even->a[0] == 0) { - // shift right first part of even by a limb - // and shift left second part of even by a limb. - for (i = 0; i < 8; i++) { - even->a[i] = even->a[i+1]; - } - even->a[i] = 0; - even->len1--; - k += 32; - } - // count up to 32 zero bits of even->a. - j = 0; - while ((even->a[0] & (1u << j)) == 0) { - j++; - } - if (j > 0) { - // shift first part of even right by j bits. - for (i = 0; i + 1 < even->len1; i++) { - even->a[i] = (even->a[i] >> j) | (even->a[i + 1] << (32 - j)); - } - even->a[i] = (even->a[i] >> j); - if (even->a[i] == 0) { - even->len1--; - } else { - i++; - } - - // shift second part of even left by j bits. - for (; i < 8; i++) { - even->a[i] = (even->a[i] << j) | (even->a[i + 1] >> (32 - j)); - } - even->a[i] = (even->a[i] << j); - // add j bits to k. - k += j; - } - // invariant is reestablished. - // now both a[0] are odd. - assert(odd->a[0] & 1); - assert(odd->a[8] & 1); - assert(even->a[0] & 1); - assert((even->a[8] & 1) == 0); - - // cmp > 0 if us.a[0..len1-1] > vr.a[0..len1-1], - // cmp = 0 if equal, < 0 if less. - cmp = us.len1 - vr.len1; - if (cmp == 0) { - i = us.len1 - 1; - while (i >= 0 && us.a[i] == vr.a[i]) i--; - // both are equal to 1 and we are done. - if (i == -1) - break; - cmp = us.a[i] > vr.a[i] ? 1 : -1; - } - if (cmp > 0) { - even = &us; - odd = &vr; - } else { - even = &vr; - odd = &us; - } - - // now even > odd. - - // even->a[0..len1-1] = (even->a[0..len1-1] - odd->a[0..len1-1]); - temp = 1; - for (i = 0; i < odd->len1; i++) { - temp += 0xFFFFFFFFull + even->a[i] - odd->a[i]; - even->a[i] = temp & 0xFFFFFFFF; - temp >>= 32; - } - for (; i < even->len1; i++) { - temp += 0xFFFFFFFFull + even->a[i]; - even->a[i] = temp & 0xFFFFFFFF; - temp >>= 32; - } - // odd->a[len1..8] = (odd->b[len1..8] + even->b[len1..8]); - temp = 0; - for (i = 8; i >= even->len1; i--) { - temp += (uint64_t) odd->a[i] + even->a[i]; - odd->a[i] = temp & 0xFFFFFFFF; - temp >>= 32; - } - for (; i >= odd->len1; i--) { - temp += (uint64_t) odd->a[i]; - odd->a[i] = temp & 0xFFFFFFFF; - temp >>= 32; - } - // note that - // if u > v: - // u'2^k = (u - v) 2^k = x(-r) - xs = x(-(r+s)) = x(-r') mod prime - // u's' + v'r' = (u-v)s + v(r+s) = us + vr - // if u < v: - // v'2^k = (v - u) 2^k = xs - x(-r) = x(s+r) = xs' mod prime - // u's' + v'r' = u(s+r) + (v-u)r = us + vr - - // even->a[0] is difference between two odd numbers, hence even. - // odd->a[8] is sum of even and odd number, hence odd. - assert(odd->a[0] & 1); - assert(odd->a[8] & 1); - assert((even->a[0] & 1) == 0); - - // The invariants are (almost) reestablished. - // The invariant max(u,v) <= 2^k can be invalidated at this point, - // because odd->a[len1..8] was changed. We only have - // - // odd->a[len1..8] <= 2^{k+1} - // - // Since even->a[0] is even, k will be incremented at the beginning - // of the next loop while odd->a[len1..8] remains unchanged. - // So after that, odd->a[len1..8] <= 2^k will hold again. - } - // In the last iteration we had u = v and gcd(u,v) = 1. - // Hence, u=1, v=1, s+r = prime, k <= 510, 2^k > max(s,r) >= prime/2 - // This implies 0 <= s < prime and 255 <= k <= 510. - // - // The invariants also give us x*s = 2^k mod prime, - // hence s = 2^k * x^-1 mod prime. - // We need to compute s/2^k mod prime. - - // First we compute inverse = -prime^-1 mod 2^32, which we need later. - // We use the Explicit Quadratic Modular inverse algorithm. - // http://arxiv.org/pdf/1209.6626.pdf - // a^-1 = (2-a) * PROD_i (1 + (a - 1)^(2^i)) mod 2^32 - // the product will converge quickly, because (a-1)^(2^i) will be - // zero mod 2^32 after at most five iterations. - // We want to compute -prime^-1 so we start with (pp[0]-2). - assert(pp[0] & 1); - uint32_t amone = pp[0]-1; - uint32_t inverse = pp[0] - 2; - while (amone) { - amone *= amone; - inverse *= (amone + 1); - } - - while (k >= 32) { - // compute s / 2^32 modulo prime. - // Idea: compute factor, such that - // s + factor*prime mod 2^32 == 0 - // i.e. factor = s * -1/prime mod 2^32. - // Then compute s + factor*prime and shift right by 32 bits. - uint32_t factor = (inverse * us.a[8]) & 0xffffffff; - temp = us.a[8] + (uint64_t) pp[0] * factor; - assert((temp & 0xffffffff) == 0); - temp >>= 32; - for (i = 0; i < 7; i++) { - temp += us.a[8-(i+1)] + (uint64_t) pp[i+1] * factor; - us.a[8-i] = temp & 0xffffffff; - temp >>= 32; - } - us.a[8-i] = temp & 0xffffffff; - k -= 32; - } - if (k > 0) { - // compute s / 2^k modulo prime. - // Same idea: compute factor, such that - // s + factor*prime mod 2^k == 0 - // i.e. factor = s * -1/prime mod 2^k. - // Then compute s + factor*prime and shift right by k bits. - uint32_t mask = (1u << k) - 1; - uint32_t factor = (inverse * us.a[8]) & mask; - temp = (us.a[8] + (uint64_t) pp[0] * factor) >> k; - assert(((us.a[8] + pp[0] * factor) & mask) == 0); - for (i = 0; i < 7; i++) { - temp += (us.a[8-(i+1)] + (uint64_t) pp[i+1] * factor) << (32 - k); - us.a[8-i] = temp & 0xffffffff; - temp >>= 32; - } - us.a[8-i] = temp & 0xffffffff; - } - - // convert s to bignum style - temp32 = 0; - for (i = 0; i < 8; i++) { - x->val[i] = ((us.a[8-i] << (2 * i)) & 0x3FFFFFFFu) | temp32; - temp32 = us.a[8-i] >> (30 - 2 * i); - } - x->val[i] = temp32; - - // let's wipe all temp buffers - memzero(pp, sizeof(pp)); - memzero(&us, sizeof(us)); - memzero(&vr, sizeof(vr)); +void bn_inverse(bignum256 *x, const bignum256 *prime) { + int i, j, k, cmp; + struct combo { + uint32_t a[9]; + int len1; + } us, vr, *odd, *even; + uint32_t pp[8]; + uint32_t temp32; + uint64_t temp; + + // The algorithm is based on Schroeppel et. al. "Almost Modular Inverse" + // algorithm. We keep four values u,v,r,s in the combo registers + // us and vr. us stores u in the first len1 limbs (little endian) + // and s in the last 9-len1 limbs (big endian). vr stores v and r. + // This is because both u*s and v*r are guaranteed to fit in 8 limbs, so + // their components are guaranteed to fit in 9. During the algorithm, + // the length of u and v shrinks while r and s grow. + // u,v,r,s correspond to F,G,B,C in Schroeppel's algorithm. + + // reduce x modulo prime. This is necessary as it has to fit in 8 limbs. + bn_fast_mod(x, prime); + bn_mod(x, prime); + // convert x and prime to 8x32 bit limb form + temp32 = prime->val[0]; + for (i = 0; i < 8; i++) { + temp32 |= prime->val[i + 1] << (30 - 2 * i); + us.a[i] = pp[i] = temp32; + temp32 = prime->val[i + 1] >> (2 + 2 * i); + } + temp32 = x->val[0]; + for (i = 0; i < 8; i++) { + temp32 |= x->val[i + 1] << (30 - 2 * i); + vr.a[i] = temp32; + temp32 = x->val[i + 1] >> (2 + 2 * i); + } + us.len1 = 8; + vr.len1 = 8; + // set s = 1 and r = 0 + us.a[8] = 1; + vr.a[8] = 0; + // set k = 0. + k = 0; + + // only one of the numbers u,v can be even at any time. We + // let even point to that number and odd to the other. + // Initially the prime u is guaranteed to be odd. + odd = &us; + even = &vr; + + // u = prime, v = x + // r = 0 , s = 1 + // k = 0 + for (;;) { + // invariants: + // let u = limbs us.a[0..u.len1-1] in little endian, + // let s = limbs us.a[u.len..8] in big endian, + // let v = limbs vr.a[0..u.len1-1] in little endian, + // let r = limbs vr.a[u.len..8] in big endian, + // r,s >= 0 ; u,v >= 1 + // x*-r = u*2^k mod prime + // x*s = v*2^k mod prime + // u*s + v*r = prime + // floor(log2(u)) + floor(log2(v)) + k <= 510 + // max(u,v) <= 2^k (*) see comment at end of loop + // gcd(u,v) = 1 + // {odd,even} = {&us, &vr} + // odd->a[0] and odd->a[8] are odd + // even->a[0] or even->a[8] is even + // + // first u/v are large and r/s small + // later u/v are small and r/s large + assert(odd->a[0] & 1); + assert(odd->a[8] & 1); + + // adjust length of even. + while (even->a[even->len1 - 1] == 0) { + even->len1--; + // if input was 0, return. + // This simple check prevents crashing with stack underflow + // or worse undesired behaviour for illegal input. + if (even->len1 < 0) return; + } + + // reduce even->a while it is even + while (even->a[0] == 0) { + // shift right first part of even by a limb + // and shift left second part of even by a limb. + for (i = 0; i < 8; i++) { + even->a[i] = even->a[i + 1]; + } + even->a[i] = 0; + even->len1--; + k += 32; + } + // count up to 32 zero bits of even->a. + j = 0; + while ((even->a[0] & (1u << j)) == 0) { + j++; + } + if (j > 0) { + // shift first part of even right by j bits. + for (i = 0; i + 1 < even->len1; i++) { + even->a[i] = (even->a[i] >> j) | (even->a[i + 1] << (32 - j)); + } + even->a[i] = (even->a[i] >> j); + if (even->a[i] == 0) { + even->len1--; + } else { + i++; + } + + // shift second part of even left by j bits. + for (; i < 8; i++) { + even->a[i] = (even->a[i] << j) | (even->a[i + 1] >> (32 - j)); + } + even->a[i] = (even->a[i] << j); + // add j bits to k. + k += j; + } + // invariant is reestablished. + // now both a[0] are odd. + assert(odd->a[0] & 1); + assert(odd->a[8] & 1); + assert(even->a[0] & 1); + assert((even->a[8] & 1) == 0); + + // cmp > 0 if us.a[0..len1-1] > vr.a[0..len1-1], + // cmp = 0 if equal, < 0 if less. + cmp = us.len1 - vr.len1; + if (cmp == 0) { + i = us.len1 - 1; + while (i >= 0 && us.a[i] == vr.a[i]) i--; + // both are equal to 1 and we are done. + if (i == -1) break; + cmp = us.a[i] > vr.a[i] ? 1 : -1; + } + if (cmp > 0) { + even = &us; + odd = &vr; + } else { + even = &vr; + odd = &us; + } + + // now even > odd. + + // even->a[0..len1-1] = (even->a[0..len1-1] - odd->a[0..len1-1]); + temp = 1; + for (i = 0; i < odd->len1; i++) { + temp += 0xFFFFFFFFull + even->a[i] - odd->a[i]; + even->a[i] = temp & 0xFFFFFFFF; + temp >>= 32; + } + for (; i < even->len1; i++) { + temp += 0xFFFFFFFFull + even->a[i]; + even->a[i] = temp & 0xFFFFFFFF; + temp >>= 32; + } + // odd->a[len1..8] = (odd->b[len1..8] + even->b[len1..8]); + temp = 0; + for (i = 8; i >= even->len1; i--) { + temp += (uint64_t)odd->a[i] + even->a[i]; + odd->a[i] = temp & 0xFFFFFFFF; + temp >>= 32; + } + for (; i >= odd->len1; i--) { + temp += (uint64_t)odd->a[i]; + odd->a[i] = temp & 0xFFFFFFFF; + temp >>= 32; + } + // note that + // if u > v: + // u'2^k = (u - v) 2^k = x(-r) - xs = x(-(r+s)) = x(-r') mod prime + // u's' + v'r' = (u-v)s + v(r+s) = us + vr + // if u < v: + // v'2^k = (v - u) 2^k = xs - x(-r) = x(s+r) = xs' mod prime + // u's' + v'r' = u(s+r) + (v-u)r = us + vr + + // even->a[0] is difference between two odd numbers, hence even. + // odd->a[8] is sum of even and odd number, hence odd. + assert(odd->a[0] & 1); + assert(odd->a[8] & 1); + assert((even->a[0] & 1) == 0); + + // The invariants are (almost) reestablished. + // The invariant max(u,v) <= 2^k can be invalidated at this point, + // because odd->a[len1..8] was changed. We only have + // + // odd->a[len1..8] <= 2^{k+1} + // + // Since even->a[0] is even, k will be incremented at the beginning + // of the next loop while odd->a[len1..8] remains unchanged. + // So after that, odd->a[len1..8] <= 2^k will hold again. + } + // In the last iteration we had u = v and gcd(u,v) = 1. + // Hence, u=1, v=1, s+r = prime, k <= 510, 2^k > max(s,r) >= prime/2 + // This implies 0 <= s < prime and 255 <= k <= 510. + // + // The invariants also give us x*s = 2^k mod prime, + // hence s = 2^k * x^-1 mod prime. + // We need to compute s/2^k mod prime. + + // First we compute inverse = -prime^-1 mod 2^32, which we need later. + // We use the Explicit Quadratic Modular inverse algorithm. + // http://arxiv.org/pdf/1209.6626.pdf + // a^-1 = (2-a) * PROD_i (1 + (a - 1)^(2^i)) mod 2^32 + // the product will converge quickly, because (a-1)^(2^i) will be + // zero mod 2^32 after at most five iterations. + // We want to compute -prime^-1 so we start with (pp[0]-2). + assert(pp[0] & 1); + uint32_t amone = pp[0] - 1; + uint32_t inverse = pp[0] - 2; + while (amone) { + amone *= amone; + inverse *= (amone + 1); + } + + while (k >= 32) { + // compute s / 2^32 modulo prime. + // Idea: compute factor, such that + // s + factor*prime mod 2^32 == 0 + // i.e. factor = s * -1/prime mod 2^32. + // Then compute s + factor*prime and shift right by 32 bits. + uint32_t factor = (inverse * us.a[8]) & 0xffffffff; + temp = us.a[8] + (uint64_t)pp[0] * factor; + assert((temp & 0xffffffff) == 0); + temp >>= 32; + for (i = 0; i < 7; i++) { + temp += us.a[8 - (i + 1)] + (uint64_t)pp[i + 1] * factor; + us.a[8 - i] = temp & 0xffffffff; + temp >>= 32; + } + us.a[8 - i] = temp & 0xffffffff; + k -= 32; + } + if (k > 0) { + // compute s / 2^k modulo prime. + // Same idea: compute factor, such that + // s + factor*prime mod 2^k == 0 + // i.e. factor = s * -1/prime mod 2^k. + // Then compute s + factor*prime and shift right by k bits. + uint32_t mask = (1u << k) - 1; + uint32_t factor = (inverse * us.a[8]) & mask; + temp = (us.a[8] + (uint64_t)pp[0] * factor) >> k; + assert(((us.a[8] + pp[0] * factor) & mask) == 0); + for (i = 0; i < 7; i++) { + temp += (us.a[8 - (i + 1)] + (uint64_t)pp[i + 1] * factor) << (32 - k); + us.a[8 - i] = temp & 0xffffffff; + temp >>= 32; + } + us.a[8 - i] = temp & 0xffffffff; + } + + // convert s to bignum style + temp32 = 0; + for (i = 0; i < 8; i++) { + x->val[i] = ((us.a[8 - i] << (2 * i)) & 0x3FFFFFFFu) | temp32; + temp32 = us.a[8 - i] >> (30 - 2 * i); + } + x->val[i] = temp32; + + // let's wipe all temp buffers + memzero(pp, sizeof(pp)); + memzero(&us, sizeof(us)); + memzero(&vr, sizeof(vr)); } #endif -void bn_normalize(bignum256 *a) { - bn_addi(a, 0); -} +void bn_normalize(bignum256 *a) { bn_addi(a, 0); } // add two numbers a = a + b // assumes that a, b are normalized // guarantees that a is normalized -void bn_add(bignum256 *a, const bignum256 *b) -{ - int i; - uint32_t tmp = 0; - for (i = 0; i < 9; i++) { - tmp += a->val[i] + b->val[i]; - a->val[i] = tmp & 0x3FFFFFFF; - tmp >>= 30; - } +void bn_add(bignum256 *a, const bignum256 *b) { + int i; + uint32_t tmp = 0; + for (i = 0; i < 9; i++) { + tmp += a->val[i] + b->val[i]; + a->val[i] = tmp & 0x3FFFFFFF; + tmp >>= 30; + } } -void bn_addmod(bignum256 *a, const bignum256 *b, const bignum256 *prime) -{ - int i; - for (i = 0; i < 9; i++) { - a->val[i] += b->val[i]; - } - bn_fast_mod(a, prime); +void bn_addmod(bignum256 *a, const bignum256 *b, const bignum256 *prime) { + int i; + for (i = 0; i < 9; i++) { + a->val[i] += b->val[i]; + } + bn_fast_mod(a, prime); } void bn_addi(bignum256 *a, uint32_t b) { - int i; - uint32_t tmp = b; - for (i = 0; i < 9; i++) { - tmp += a->val[i]; - a->val[i] = tmp & 0x3FFFFFFF; - tmp >>= 30; - } + int i; + uint32_t tmp = b; + for (i = 0; i < 9; i++) { + tmp += a->val[i]; + a->val[i] = tmp & 0x3FFFFFFF; + tmp >>= 30; + } } void bn_subi(bignum256 *a, uint32_t b, const bignum256 *prime) { - assert (b <= prime->val[0]); - // the possible underflow will be taken care of when adding the prime - a->val[0] -= b; - bn_add(a, prime); + assert(b <= prime->val[0]); + // the possible underflow will be taken care of when adding the prime + a->val[0] -= b; + bn_add(a, prime); } // res = a - b mod prime. More exactly res = a + (2*prime - b). // b must be a partly reduced number // result is normalized but not reduced. -void bn_subtractmod(const bignum256 *a, const bignum256 *b, bignum256 *res, const bignum256 *prime) -{ - int i; - uint32_t temp = 1; - for (i = 0; i < 9; i++) { - temp += 0x3FFFFFFF + a->val[i] + 2u * prime->val[i] - b->val[i]; - res->val[i] = temp & 0x3FFFFFFF; - temp >>= 30; - } +void bn_subtractmod(const bignum256 *a, const bignum256 *b, bignum256 *res, + const bignum256 *prime) { + int i; + uint32_t temp = 1; + for (i = 0; i < 9; i++) { + temp += 0x3FFFFFFF + a->val[i] + 2u * prime->val[i] - b->val[i]; + res->val[i] = temp & 0x3FFFFFFF; + temp >>= 30; + } } // res = a - b ; a > b -void bn_subtract(const bignum256 *a, const bignum256 *b, bignum256 *res) -{ - int i; - uint32_t tmp = 1; - for (i = 0; i < 9; i++) { - tmp += 0x3FFFFFFF + a->val[i] - b->val[i]; - res->val[i] = tmp & 0x3FFFFFFF; - tmp >>= 30; - } +void bn_subtract(const bignum256 *a, const bignum256 *b, bignum256 *res) { + int i; + uint32_t tmp = 1; + for (i = 0; i < 9; i++) { + tmp += 0x3FFFFFFF + a->val[i] - b->val[i]; + res->val[i] = tmp & 0x3FFFFFFF; + tmp >>= 30; + } } // a / 58 = a (+r) -void bn_divmod58(bignum256 *a, uint32_t *r) -{ - int i; - uint32_t rem, tmp; - rem = a->val[8] % 58; - a->val[8] /= 58; - for (i = 7; i >= 0; i--) { - // invariants: - // rem = old(a) >> 30(i+1) % 58 - // a[i+1..8] = old(a[i+1..8])/58 - // a[0..i] = old(a[0..i]) - // 2^30 == 18512790*58 + 4 - tmp = rem * 4 + a->val[i]; - // set a[i] = (rem * 2^30 + a[i])/58 - // = rem * 18512790 + (rem * 4 + a[i])/58 - a->val[i] = rem * 18512790 + (tmp / 58); - // set rem = (rem * 2^30 + a[i]) mod 58 - // = (rem * 4 + a[i]) mod 58 - rem = tmp % 58; - } - *r = rem; +void bn_divmod58(bignum256 *a, uint32_t *r) { + int i; + uint32_t rem, tmp; + rem = a->val[8] % 58; + a->val[8] /= 58; + for (i = 7; i >= 0; i--) { + // invariants: + // rem = old(a) >> 30(i+1) % 58 + // a[i+1..8] = old(a[i+1..8])/58 + // a[0..i] = old(a[0..i]) + // 2^30 == 18512790*58 + 4 + tmp = rem * 4 + a->val[i]; + // set a[i] = (rem * 2^30 + a[i])/58 + // = rem * 18512790 + (rem * 4 + a[i])/58 + a->val[i] = rem * 18512790 + (tmp / 58); + // set rem = (rem * 2^30 + a[i]) mod 58 + // = (rem * 4 + a[i]) mod 58 + rem = tmp % 58; + } + *r = rem; } // a / 1000 = a (+r) -void bn_divmod1000(bignum256 *a, uint32_t *r) -{ - int i; - uint32_t rem, tmp; - rem = a->val[8] % 1000; - a->val[8] /= 1000; - for (i = 7; i >= 0; i--) { - // invariants: - // rem = old(a) >> 30(i+1) % 1000 - // a[i+1..8] = old(a[i+1..8])/1000 - // a[0..i] = old(a[0..i]) - // 2^30 == 1073741*1000 + 824 - tmp = rem * 824 + a->val[i]; - // set a[i] = (rem * 2^30 + a[i])/1000 - // = rem * 1073741 + (rem * 824 + a[i])/1000 - a->val[i] = rem * 1073741 + (tmp / 1000); - // set rem = (rem * 2^30 + a[i]) mod 1000 - // = (rem * 824 + a[i]) mod 1000 - rem = tmp % 1000; - } - *r = rem; +void bn_divmod1000(bignum256 *a, uint32_t *r) { + int i; + uint32_t rem, tmp; + rem = a->val[8] % 1000; + a->val[8] /= 1000; + for (i = 7; i >= 0; i--) { + // invariants: + // rem = old(a) >> 30(i+1) % 1000 + // a[i+1..8] = old(a[i+1..8])/1000 + // a[0..i] = old(a[0..i]) + // 2^30 == 1073741*1000 + 824 + tmp = rem * 824 + a->val[i]; + // set a[i] = (rem * 2^30 + a[i])/1000 + // = rem * 1073741 + (rem * 824 + a[i])/1000 + a->val[i] = rem * 1073741 + (tmp / 1000); + // set rem = (rem * 2^30 + a[i]) mod 1000 + // = (rem * 824 + a[i]) mod 1000 + rem = tmp % 1000; + } + *r = rem; } -size_t bn_format(const bignum256 *amnt, const char *prefix, const char *suffix, unsigned int decimals, int exponent, bool trailing, char *out, size_t outlen) -{ - // sanity check, 2**256 ~ 10**77; we should never need decimals/exponent bigger than that - if (decimals > 80 || exponent < -20 || exponent > 80) { - memzero(out, outlen); - return 0; - } - - size_t prefixlen = prefix ? strlen(prefix) : 0; - size_t suffixlen = suffix ? strlen(suffix) : 0; - - /* add prefix to beginning of out buffer */ - if (prefixlen) { - memcpy(out, prefix, prefixlen); - } - /* add suffix to end of out buffer */ - if (suffixlen) { - memcpy(&out[outlen - suffixlen - 1], suffix, suffixlen); - } - /* nul terminate (even if suffix = NULL) */ - out[outlen - 1] = '\0'; - - /* fill number between prefix and suffix (between start and end) */ - char *start = &out[prefixlen], *end = &out[outlen - suffixlen - 1]; - char *str = end; +size_t bn_format(const bignum256 *amnt, const char *prefix, const char *suffix, + unsigned int decimals, int exponent, bool trailing, char *out, + size_t outlen) { + // sanity check, 2**256 ~ 10**77; we should never need decimals/exponent + // bigger than that + if (decimals > 80 || exponent < -20 || exponent > 80) { + memzero(out, outlen); + return 0; + } + + size_t prefixlen = prefix ? strlen(prefix) : 0; + size_t suffixlen = suffix ? strlen(suffix) : 0; + + /* add prefix to beginning of out buffer */ + if (prefixlen) { + memcpy(out, prefix, prefixlen); + } + /* add suffix to end of out buffer */ + if (suffixlen) { + memcpy(&out[outlen - suffixlen - 1], suffix, suffixlen); + } + /* nul terminate (even if suffix = NULL) */ + out[outlen - 1] = '\0'; + + /* fill number between prefix and suffix (between start and end) */ + char *start = &out[prefixlen], *end = &out[outlen - suffixlen - 1]; + char *str = end; #define BN_FORMAT_PUSH_CHECKED(c) \ - do { \ - if (str == start) return 0; \ - *--str = (c); \ - } while (0) - -#define BN_FORMAT_PUSH(n) \ - do { \ - if (exponent < 0) { \ - exponent++; \ - } else { \ - if ((n) > 0 || trailing || str != end || decimals <= 1) { \ - BN_FORMAT_PUSH_CHECKED('0' + (n)); \ - } \ - if (decimals > 0 && decimals-- == 1) { \ - BN_FORMAT_PUSH_CHECKED('.'); \ - } \ - } \ - } while (0) - - bignum256 val; - memcpy(&val, amnt, sizeof(bignum256)); - - if (bn_is_zero(&val)) { - exponent = 0; - } - - for (; exponent > 0; exponent--) { - BN_FORMAT_PUSH(0); - } - - unsigned int digits = bn_digitcount(&val); - for (unsigned int i = 0; i < digits / 3; i++) { - uint32_t limb; - bn_divmod1000(&val, &limb); - - BN_FORMAT_PUSH(limb % 10); - limb /= 10; - BN_FORMAT_PUSH(limb % 10); - limb /= 10; - BN_FORMAT_PUSH(limb % 10); - } - - if (digits % 3 != 0) { - uint32_t limb; - bn_divmod1000(&val, &limb); - - switch (digits % 3) { - case 2: - BN_FORMAT_PUSH(limb % 10); - limb /= 10; - //-fallthrough - - case 1: - BN_FORMAT_PUSH(limb % 10); - break; - } - } - - while (decimals > 0 || str[0] == '\0' || str[0] == '.') { - BN_FORMAT_PUSH(0); - } - - /* finally move number to &out[prefixlen] to close the gap between - * prefix and str. len is length of number + suffix + traling 0 - */ - size_t len = &out[outlen] - str; - memmove(&out[prefixlen], str, len); - - /* return length of number including prefix and suffix without trailing 0 */ - return prefixlen + len - 1; + do { \ + if (str == start) return 0; \ + *--str = (c); \ + } while (0) + +#define BN_FORMAT_PUSH(n) \ + do { \ + if (exponent < 0) { \ + exponent++; \ + } else { \ + if ((n) > 0 || trailing || str != end || decimals <= 1) { \ + BN_FORMAT_PUSH_CHECKED('0' + (n)); \ + } \ + if (decimals > 0 && decimals-- == 1) { \ + BN_FORMAT_PUSH_CHECKED('.'); \ + } \ + } \ + } while (0) + + bignum256 val; + memcpy(&val, amnt, sizeof(bignum256)); + + if (bn_is_zero(&val)) { + exponent = 0; + } + + for (; exponent > 0; exponent--) { + BN_FORMAT_PUSH(0); + } + + unsigned int digits = bn_digitcount(&val); + for (unsigned int i = 0; i < digits / 3; i++) { + uint32_t limb; + bn_divmod1000(&val, &limb); + + BN_FORMAT_PUSH(limb % 10); + limb /= 10; + BN_FORMAT_PUSH(limb % 10); + limb /= 10; + BN_FORMAT_PUSH(limb % 10); + } + + if (digits % 3 != 0) { + uint32_t limb; + bn_divmod1000(&val, &limb); + + switch (digits % 3) { + case 2: + BN_FORMAT_PUSH(limb % 10); + limb /= 10; + //-fallthrough + + case 1: + BN_FORMAT_PUSH(limb % 10); + break; + } + } + + while (decimals > 0 || str[0] == '\0' || str[0] == '.') { + BN_FORMAT_PUSH(0); + } + + /* finally move number to &out[prefixlen] to close the gap between + * prefix and str. len is length of number + suffix + traling 0 + */ + size_t len = &out[outlen] - str; + memmove(&out[prefixlen], str, len); + + /* return length of number including prefix and suffix without trailing 0 */ + return prefixlen + len - 1; } #if USE_BN_PRINT -void bn_print(const bignum256 *a) -{ - printf("%04x", a->val[8] & 0x0000FFFF); - printf("%08x", (a->val[7] << 2) | ((a->val[6] & 0x30000000) >> 28)); - printf("%07x", a->val[6] & 0x0FFFFFFF); - printf("%08x", (a->val[5] << 2) | ((a->val[4] & 0x30000000) >> 28)); - printf("%07x", a->val[4] & 0x0FFFFFFF); - printf("%08x", (a->val[3] << 2) | ((a->val[2] & 0x30000000) >> 28)); - printf("%07x", a->val[2] & 0x0FFFFFFF); - printf("%08x", (a->val[1] << 2) | ((a->val[0] & 0x30000000) >> 28)); - printf("%07x", a->val[0] & 0x0FFFFFFF); +void bn_print(const bignum256 *a) { + printf("%04x", a->val[8] & 0x0000FFFF); + printf("%08x", (a->val[7] << 2) | ((a->val[6] & 0x30000000) >> 28)); + printf("%07x", a->val[6] & 0x0FFFFFFF); + printf("%08x", (a->val[5] << 2) | ((a->val[4] & 0x30000000) >> 28)); + printf("%07x", a->val[4] & 0x0FFFFFFF); + printf("%08x", (a->val[3] << 2) | ((a->val[2] & 0x30000000) >> 28)); + printf("%07x", a->val[2] & 0x0FFFFFFF); + printf("%08x", (a->val[1] << 2) | ((a->val[0] & 0x30000000) >> 28)); + printf("%07x", a->val[0] & 0x0FFFFFFF); } -void bn_print_raw(const bignum256 *a) -{ - int i; - for (i = 0; i <= 8; i++) { - printf("0x%08x, ", a->val[i]); - } +void bn_print_raw(const bignum256 *a) { + int i; + for (i = 0; i <= 8; i++) { + printf("0x%08x, ", a->val[i]); + } } #endif diff --git a/bignum.h b/bignum.h index f96cad665..e0225be20 100644 --- a/bignum.h +++ b/bignum.h @@ -33,7 +33,7 @@ // bignum256 are 256 bits stored as 8*30 bit + 1*16 bit // val[0] are lowest 30 bits, val[8] highest 16 bits typedef struct { - uint32_t val[9]; + uint32_t val[9]; } bignum256; // read 4 big endian bytes into uint32 @@ -60,26 +60,22 @@ void bn_read_uint32(uint32_t in_number, bignum256 *out_number); void bn_read_uint64(uint64_t in_number, bignum256 *out_number); -static inline uint32_t bn_write_uint32(const bignum256 *in_number) -{ - return in_number->val[0] | (in_number->val[1] << 30); +static inline uint32_t bn_write_uint32(const bignum256 *in_number) { + return in_number->val[0] | (in_number->val[1] << 30); } -static inline uint64_t bn_write_uint64(const bignum256 *in_number) -{ - uint64_t tmp; - tmp = in_number->val[2]; - tmp <<= 30; - tmp |= in_number->val[1]; - tmp <<= 30; - tmp |= in_number->val[0]; - return tmp; +static inline uint64_t bn_write_uint64(const bignum256 *in_number) { + uint64_t tmp; + tmp = in_number->val[2]; + tmp <<= 30; + tmp |= in_number->val[1]; + tmp <<= 30; + tmp |= in_number->val[0]; + return tmp; } // copies number a to b -static inline void bn_copy(const bignum256 *a, bignum256 *b) { - *b = *a; -} +static inline void bn_copy(const bignum256 *a, bignum256 *b) { *b = *a; } int bn_bitcount(const bignum256 *a); @@ -92,18 +88,17 @@ int bn_is_zero(const bignum256 *a); void bn_one(bignum256 *a); static inline int bn_is_even(const bignum256 *a) { - return (a->val[0] & 1) == 0; + return (a->val[0] & 1) == 0; } -static inline int bn_is_odd(const bignum256 *a) { - return (a->val[0] & 1) == 1; -} +static inline int bn_is_odd(const bignum256 *a) { return (a->val[0] & 1) == 1; } int bn_is_less(const bignum256 *a, const bignum256 *b); int bn_is_equal(const bignum256 *a, const bignum256 *b); -void bn_cmov(bignum256 *res, int cond, const bignum256 *truecase, const bignum256 *falsecase); +void bn_cmov(bignum256 *res, int cond, const bignum256 *truecase, + const bignum256 *falsecase); void bn_lshift(bignum256 *a); @@ -141,7 +136,8 @@ void bn_addi(bignum256 *a, uint32_t b); void bn_subi(bignum256 *a, uint32_t b, const bignum256 *prime); -void bn_subtractmod(const bignum256 *a, const bignum256 *b, bignum256 *res, const bignum256 *prime); +void bn_subtractmod(const bignum256 *a, const bignum256 *b, bignum256 *res, + const bignum256 *prime); void bn_subtract(const bignum256 *a, const bignum256 *b, bignum256 *res); @@ -149,14 +145,19 @@ void bn_divmod58(bignum256 *a, uint32_t *r); void bn_divmod1000(bignum256 *a, uint32_t *r); -size_t bn_format(const bignum256 *amnt, const char *prefix, const char *suffix, unsigned int decimals, int exponent, bool trailing, char *out, size_t outlen); +size_t bn_format(const bignum256 *amnt, const char *prefix, const char *suffix, + unsigned int decimals, int exponent, bool trailing, char *out, + size_t outlen); -static inline size_t bn_format_uint64(uint64_t amount, const char *prefix, const char *suffix, unsigned int decimals, int exponent, bool trailing, char *out, size_t outlen) -{ - bignum256 amnt; - bn_read_uint64(amount, &amnt); +static inline size_t bn_format_uint64(uint64_t amount, const char *prefix, + const char *suffix, unsigned int decimals, + int exponent, bool trailing, char *out, + size_t outlen) { + bignum256 amnt; + bn_read_uint64(amount, &amnt); - return bn_format(&amnt, prefix, suffix, decimals, exponent, trailing, out, outlen); + return bn_format(&amnt, prefix, suffix, decimals, exponent, trailing, out, + outlen); } #if USE_BN_PRINT diff --git a/bip32.c b/bip32.c index 8d6291f51..75dbd33ee 100644 --- a/bip32.c +++ b/bip32.c @@ -22,23 +22,23 @@ * OTHER DEALINGS IN THE SOFTWARE. */ -#include #include +#include -#include "aes/aes.h" #include "address.h" +#include "aes/aes.h" +#include "base58.h" #include "bignum.h" -#include "hmac.h" -#include "ecdsa.h" #include "bip32.h" -#include "sha2.h" -#include "sha3.h" -#include "base58.h" #include "curves.h" -#include "secp256k1.h" -#include "nist256p1.h" -#include "ed25519-donna/ed25519.h" +#include "ecdsa.h" #include "ed25519-donna/ed25519-sha3.h" +#include "ed25519-donna/ed25519.h" +#include "hmac.h" +#include "nist256p1.h" +#include "secp256k1.h" +#include "sha2.h" +#include "sha3.h" #if USE_KECCAK #include "ed25519-donna/ed25519-keccak.h" #endif @@ -51,412 +51,423 @@ #include "memzero.h" const curve_info ed25519_info = { - .bip32_name = "ed25519 seed", - .params = NULL, - .hasher_base58 = HASHER_SHA2D, - .hasher_sign = HASHER_SHA2D, - .hasher_pubkey = HASHER_SHA2_RIPEMD, - .hasher_script = HASHER_SHA2, + .bip32_name = "ed25519 seed", + .params = NULL, + .hasher_base58 = HASHER_SHA2D, + .hasher_sign = HASHER_SHA2D, + .hasher_pubkey = HASHER_SHA2_RIPEMD, + .hasher_script = HASHER_SHA2, }; const curve_info ed25519_cardano_info = { - .bip32_name = "ed25519 cardano seed", - .params = NULL, - .hasher_base58 = HASHER_SHA2D, - .hasher_sign = HASHER_SHA2D, - .hasher_pubkey = HASHER_SHA2_RIPEMD, - .hasher_script = HASHER_SHA2, + .bip32_name = "ed25519 cardano seed", + .params = NULL, + .hasher_base58 = HASHER_SHA2D, + .hasher_sign = HASHER_SHA2D, + .hasher_pubkey = HASHER_SHA2_RIPEMD, + .hasher_script = HASHER_SHA2, }; const curve_info ed25519_sha3_info = { - .bip32_name = "ed25519-sha3 seed", - .params = NULL, - .hasher_base58 = HASHER_SHA2D, - .hasher_sign = HASHER_SHA2D, - .hasher_pubkey = HASHER_SHA2_RIPEMD, - .hasher_script = HASHER_SHA2, + .bip32_name = "ed25519-sha3 seed", + .params = NULL, + .hasher_base58 = HASHER_SHA2D, + .hasher_sign = HASHER_SHA2D, + .hasher_pubkey = HASHER_SHA2_RIPEMD, + .hasher_script = HASHER_SHA2, }; #if USE_KECCAK const curve_info ed25519_keccak_info = { - .bip32_name = "ed25519-keccak seed", - .params = NULL, - .hasher_base58 = HASHER_SHA2D, - .hasher_sign = HASHER_SHA2D, - .hasher_pubkey = HASHER_SHA2_RIPEMD, - .hasher_script = HASHER_SHA2, + .bip32_name = "ed25519-keccak seed", + .params = NULL, + .hasher_base58 = HASHER_SHA2D, + .hasher_sign = HASHER_SHA2D, + .hasher_pubkey = HASHER_SHA2_RIPEMD, + .hasher_script = HASHER_SHA2, }; #endif const curve_info curve25519_info = { - .bip32_name = "curve25519 seed", - .params = NULL, - .hasher_base58 = HASHER_SHA2D, - .hasher_sign = HASHER_SHA2D, - .hasher_pubkey = HASHER_SHA2_RIPEMD, - .hasher_script = HASHER_SHA2, + .bip32_name = "curve25519 seed", + .params = NULL, + .hasher_base58 = HASHER_SHA2D, + .hasher_sign = HASHER_SHA2D, + .hasher_pubkey = HASHER_SHA2_RIPEMD, + .hasher_script = HASHER_SHA2, }; -int hdnode_from_xpub(uint32_t depth, uint32_t child_num, const uint8_t *chain_code, const uint8_t *public_key, const char* curve, HDNode *out) -{ - const curve_info *info = get_curve_by_name(curve); - if (info == 0) { - return 0; - } - if (public_key[0] != 0x02 && public_key[0] != 0x03) { // invalid pubkey - return 0; - } - out->curve = info; - out->depth = depth; - out->child_num = child_num; - memcpy(out->chain_code, chain_code, 32); - memzero(out->private_key, 32); - memzero(out->private_key_extension,32); - memcpy(out->public_key, public_key, 33); - return 1; +int hdnode_from_xpub(uint32_t depth, uint32_t child_num, + const uint8_t *chain_code, const uint8_t *public_key, + const char *curve, HDNode *out) { + const curve_info *info = get_curve_by_name(curve); + if (info == 0) { + return 0; + } + if (public_key[0] != 0x02 && public_key[0] != 0x03) { // invalid pubkey + return 0; + } + out->curve = info; + out->depth = depth; + out->child_num = child_num; + memcpy(out->chain_code, chain_code, 32); + memzero(out->private_key, 32); + memzero(out->private_key_extension, 32); + memcpy(out->public_key, public_key, 33); + return 1; } -int hdnode_from_xprv(uint32_t depth, uint32_t child_num, const uint8_t *chain_code, const uint8_t *private_key, const char* curve, HDNode *out) -{ - bool failed = false; - const curve_info *info = get_curve_by_name(curve); - if (info == 0) { - failed = true; - } else if (info->params) { - bignum256 a; - bn_read_be(private_key, &a); - if (bn_is_zero(&a)) { // == 0 - failed = true; - } else { - if (!bn_is_less(&a, &info->params->order)) { // >= order - failed = true; - } - } - memzero(&a, sizeof(a)); - } - - if (failed) { - return 0; - } - - out->curve = info; - out->depth = depth; - out->child_num = child_num; - memcpy(out->chain_code, chain_code, 32); - memcpy(out->private_key, private_key, 32); - memzero(out->public_key, sizeof(out->public_key)); - memzero(out->private_key_extension, sizeof(out->private_key_extension)); - return 1; +int hdnode_from_xprv(uint32_t depth, uint32_t child_num, + const uint8_t *chain_code, const uint8_t *private_key, + const char *curve, HDNode *out) { + bool failed = false; + const curve_info *info = get_curve_by_name(curve); + if (info == 0) { + failed = true; + } else if (info->params) { + bignum256 a; + bn_read_be(private_key, &a); + if (bn_is_zero(&a)) { // == 0 + failed = true; + } else { + if (!bn_is_less(&a, &info->params->order)) { // >= order + failed = true; + } + } + memzero(&a, sizeof(a)); + } + + if (failed) { + return 0; + } + + out->curve = info; + out->depth = depth; + out->child_num = child_num; + memcpy(out->chain_code, chain_code, 32); + memcpy(out->private_key, private_key, 32); + memzero(out->public_key, sizeof(out->public_key)); + memzero(out->private_key_extension, sizeof(out->private_key_extension)); + return 1; } -int hdnode_from_seed(const uint8_t *seed, int seed_len, const char* curve, HDNode *out) -{ - static CONFIDENTIAL uint8_t I[32 + 32]; - memzero(out, sizeof(HDNode)); - out->depth = 0; - out->child_num = 0; - out->curve = get_curve_by_name(curve); - if (out->curve == 0) { - return 0; - } - static CONFIDENTIAL HMAC_SHA512_CTX ctx; - hmac_sha512_Init(&ctx, (const uint8_t*) out->curve->bip32_name, strlen(out->curve->bip32_name)); - hmac_sha512_Update(&ctx, seed, seed_len); - hmac_sha512_Final(&ctx, I); - - if (out->curve->params) { - bignum256 a; - while (true) { - bn_read_be(I, &a); - if (!bn_is_zero(&a) // != 0 - && bn_is_less(&a, &out->curve->params->order)) { // < order - break; - } - hmac_sha512_Init(&ctx, (const uint8_t*) out->curve->bip32_name, strlen(out->curve->bip32_name)); - hmac_sha512_Update(&ctx, I, sizeof(I)); - hmac_sha512_Final(&ctx, I); - } - memzero(&a, sizeof(a)); - } - memcpy(out->private_key, I, 32); - memcpy(out->chain_code, I + 32, 32); - memzero(out->public_key, sizeof(out->public_key)); - memzero(I, sizeof(I)); - return 1; +int hdnode_from_seed(const uint8_t *seed, int seed_len, const char *curve, + HDNode *out) { + static CONFIDENTIAL uint8_t I[32 + 32]; + memzero(out, sizeof(HDNode)); + out->depth = 0; + out->child_num = 0; + out->curve = get_curve_by_name(curve); + if (out->curve == 0) { + return 0; + } + static CONFIDENTIAL HMAC_SHA512_CTX ctx; + hmac_sha512_Init(&ctx, (const uint8_t *)out->curve->bip32_name, + strlen(out->curve->bip32_name)); + hmac_sha512_Update(&ctx, seed, seed_len); + hmac_sha512_Final(&ctx, I); + + if (out->curve->params) { + bignum256 a; + while (true) { + bn_read_be(I, &a); + if (!bn_is_zero(&a) // != 0 + && bn_is_less(&a, &out->curve->params->order)) { // < order + break; + } + hmac_sha512_Init(&ctx, (const uint8_t *)out->curve->bip32_name, + strlen(out->curve->bip32_name)); + hmac_sha512_Update(&ctx, I, sizeof(I)); + hmac_sha512_Final(&ctx, I); + } + memzero(&a, sizeof(a)); + } + memcpy(out->private_key, I, 32); + memcpy(out->chain_code, I + 32, 32); + memzero(out->public_key, sizeof(out->public_key)); + memzero(I, sizeof(I)); + return 1; } -uint32_t hdnode_fingerprint(HDNode *node) -{ - uint8_t digest[32]; - uint32_t fingerprint; +uint32_t hdnode_fingerprint(HDNode *node) { + uint8_t digest[32]; + uint32_t fingerprint; - hdnode_fill_public_key(node); - hasher_Raw(node->curve->hasher_pubkey, node->public_key, 33, digest); - fingerprint = ((uint32_t) digest[0] << 24) + (digest[1] << 16) + (digest[2] << 8) + digest[3]; - memzero(digest, sizeof(digest)); - return fingerprint; + hdnode_fill_public_key(node); + hasher_Raw(node->curve->hasher_pubkey, node->public_key, 33, digest); + fingerprint = ((uint32_t)digest[0] << 24) + (digest[1] << 16) + + (digest[2] << 8) + digest[3]; + memzero(digest, sizeof(digest)); + return fingerprint; } -int hdnode_private_ckd(HDNode *inout, uint32_t i) -{ - static CONFIDENTIAL uint8_t data[1 + 32 + 4]; - static CONFIDENTIAL uint8_t I[32 + 32]; - static CONFIDENTIAL bignum256 a, b; - - if (i & 0x80000000) { // private derivation - data[0] = 0; - memcpy(data + 1, inout->private_key, 32); - } else { // public derivation - if (!inout->curve->params) { - return 0; - } - hdnode_fill_public_key(inout); - memcpy(data, inout->public_key, 33); - } - write_be(data + 33, i); - - bn_read_be(inout->private_key, &a); - - static CONFIDENTIAL HMAC_SHA512_CTX ctx; - hmac_sha512_Init(&ctx, inout->chain_code, 32); - hmac_sha512_Update(&ctx, data, sizeof(data)); - hmac_sha512_Final(&ctx, I); - - if (inout->curve->params) { - while (true) { - bool failed = false; - bn_read_be(I, &b); - if (!bn_is_less(&b, &inout->curve->params->order)) { // >= order - failed = true; - } else { - bn_add(&b, &a); - bn_mod(&b, &inout->curve->params->order); - if (bn_is_zero(&b)) { - failed = true; - } - } - - if (!failed) { - bn_write_be(&b, inout->private_key); - break; - } - - data[0] = 1; - memcpy(data + 1, I + 32, 32); - hmac_sha512_Init(&ctx, inout->chain_code, 32); - hmac_sha512_Update(&ctx, data, sizeof(data)); - hmac_sha512_Final(&ctx, I); - } - } else { - memcpy(inout->private_key, I, 32); - } - - memcpy(inout->chain_code, I + 32, 32); - inout->depth++; - inout->child_num = i; - memzero(inout->public_key, sizeof(inout->public_key)); - - // making sure to wipe our memory - memzero(&a, sizeof(a)); - memzero(&b, sizeof(b)); - memzero(I, sizeof(I)); - memzero(data, sizeof(data)); - return 1; +int hdnode_private_ckd(HDNode *inout, uint32_t i) { + static CONFIDENTIAL uint8_t data[1 + 32 + 4]; + static CONFIDENTIAL uint8_t I[32 + 32]; + static CONFIDENTIAL bignum256 a, b; + + if (i & 0x80000000) { // private derivation + data[0] = 0; + memcpy(data + 1, inout->private_key, 32); + } else { // public derivation + if (!inout->curve->params) { + return 0; + } + hdnode_fill_public_key(inout); + memcpy(data, inout->public_key, 33); + } + write_be(data + 33, i); + + bn_read_be(inout->private_key, &a); + + static CONFIDENTIAL HMAC_SHA512_CTX ctx; + hmac_sha512_Init(&ctx, inout->chain_code, 32); + hmac_sha512_Update(&ctx, data, sizeof(data)); + hmac_sha512_Final(&ctx, I); + + if (inout->curve->params) { + while (true) { + bool failed = false; + bn_read_be(I, &b); + if (!bn_is_less(&b, &inout->curve->params->order)) { // >= order + failed = true; + } else { + bn_add(&b, &a); + bn_mod(&b, &inout->curve->params->order); + if (bn_is_zero(&b)) { + failed = true; + } + } + + if (!failed) { + bn_write_be(&b, inout->private_key); + break; + } + + data[0] = 1; + memcpy(data + 1, I + 32, 32); + hmac_sha512_Init(&ctx, inout->chain_code, 32); + hmac_sha512_Update(&ctx, data, sizeof(data)); + hmac_sha512_Final(&ctx, I); + } + } else { + memcpy(inout->private_key, I, 32); + } + + memcpy(inout->chain_code, I + 32, 32); + inout->depth++; + inout->child_num = i; + memzero(inout->public_key, sizeof(inout->public_key)); + + // making sure to wipe our memory + memzero(&a, sizeof(a)); + memzero(&b, sizeof(b)); + memzero(I, sizeof(I)); + memzero(data, sizeof(data)); + return 1; } #if USE_CARDANO -static void scalar_multiply8(const uint8_t *src, int bytes, uint8_t *dst) -{ - uint8_t prev_acc = 0; - for (int i = 0; i < bytes; i++) { - dst[i] = (src[i] << 3) + (prev_acc & 0x7); - prev_acc = src[i] >> 5; - } - dst[bytes] = src[bytes - 1] >> 5; +static void scalar_multiply8(const uint8_t *src, int bytes, uint8_t *dst) { + uint8_t prev_acc = 0; + for (int i = 0; i < bytes; i++) { + dst[i] = (src[i] << 3) + (prev_acc & 0x7); + prev_acc = src[i] >> 5; + } + dst[bytes] = src[bytes - 1] >> 5; } -static void scalar_add_256bits(const uint8_t *src1, const uint8_t *src2, uint8_t *dst) -{ - uint16_t r = 0; - for (int i = 0; i < 32; i++) { - r = r + (uint16_t)src1[i] + (uint16_t)src2[i]; - dst[i] = r & 0xff; - r >>= 8; - } +static void scalar_add_256bits(const uint8_t *src1, const uint8_t *src2, + uint8_t *dst) { + uint16_t r = 0; + for (int i = 0; i < 32; i++) { + r = r + (uint16_t)src1[i] + (uint16_t)src2[i]; + dst[i] = r & 0xff; + r >>= 8; + } } -int hdnode_private_ckd_cardano(HDNode *inout, uint32_t index) -{ - // checks for hardened/non-hardened derivation, keysize 32 means we are dealing with public key and thus non-h, keysize 64 is for private key - int keysize = 32; - if (index & 0x80000000) { - keysize = 64; - } - - static CONFIDENTIAL uint8_t data[1 + 64 + 4]; - static CONFIDENTIAL uint8_t z[32 + 32]; - static CONFIDENTIAL uint8_t priv_key[64]; - static CONFIDENTIAL uint8_t res_key[64]; - - write_le(data + keysize + 1, index); - - memcpy(priv_key, inout->private_key, 32); - memcpy(priv_key + 32, inout->private_key_extension, 32); - - if (keysize == 64) { // private derivation - data[0] = 0; - memcpy(data + 1, inout->private_key, 32); - memcpy(data + 1 + 32, inout->private_key_extension, 32); - } else { // public derivation - hdnode_fill_public_key(inout); - data[0] = 2; - memcpy(data + 1, inout->public_key + 1, 32); - } - - static CONFIDENTIAL HMAC_SHA512_CTX ctx; - hmac_sha512_Init(&ctx, inout->chain_code, 32); - hmac_sha512_Update(&ctx, data, 1 + keysize + 4); - hmac_sha512_Final(&ctx, z); - - static CONFIDENTIAL uint8_t zl8[32]; - memzero(zl8, 32); - - /* get 8 * Zl */ - scalar_multiply8(z, 28, zl8); - /* Kl = 8*Zl + parent(K)l */ - scalar_add_256bits(zl8, priv_key, res_key); - - /* Kr = Zr + parent(K)r */ - scalar_add_256bits(z + 32, priv_key + 32, res_key + 32); - - memcpy(inout->private_key, res_key, 32); - memcpy(inout->private_key_extension, res_key + 32, 32); - - if (keysize == 64) { - data[0] = 1; - } else { - data[0] = 3; - } - hmac_sha512_Init(&ctx, inout->chain_code, 32); - hmac_sha512_Update(&ctx, data, 1 + keysize + 4); - hmac_sha512_Final(&ctx, z); - - memcpy(inout->chain_code, z + 32, 32); - inout->depth++; - inout->child_num = index; - memzero(inout->public_key, sizeof(inout->public_key)); - - // making sure to wipe our memory - memzero(z, sizeof(z)); - memzero(data, sizeof(data)); - memzero(priv_key, sizeof(priv_key)); - memzero(res_key, sizeof(res_key)); - return 1; +int hdnode_private_ckd_cardano(HDNode *inout, uint32_t index) { + // checks for hardened/non-hardened derivation, keysize 32 means we are + // dealing with public key and thus non-h, keysize 64 is for private key + int keysize = 32; + if (index & 0x80000000) { + keysize = 64; + } + + static CONFIDENTIAL uint8_t data[1 + 64 + 4]; + static CONFIDENTIAL uint8_t z[32 + 32]; + static CONFIDENTIAL uint8_t priv_key[64]; + static CONFIDENTIAL uint8_t res_key[64]; + + write_le(data + keysize + 1, index); + + memcpy(priv_key, inout->private_key, 32); + memcpy(priv_key + 32, inout->private_key_extension, 32); + + if (keysize == 64) { // private derivation + data[0] = 0; + memcpy(data + 1, inout->private_key, 32); + memcpy(data + 1 + 32, inout->private_key_extension, 32); + } else { // public derivation + hdnode_fill_public_key(inout); + data[0] = 2; + memcpy(data + 1, inout->public_key + 1, 32); + } + + static CONFIDENTIAL HMAC_SHA512_CTX ctx; + hmac_sha512_Init(&ctx, inout->chain_code, 32); + hmac_sha512_Update(&ctx, data, 1 + keysize + 4); + hmac_sha512_Final(&ctx, z); + + static CONFIDENTIAL uint8_t zl8[32]; + memzero(zl8, 32); + + /* get 8 * Zl */ + scalar_multiply8(z, 28, zl8); + /* Kl = 8*Zl + parent(K)l */ + scalar_add_256bits(zl8, priv_key, res_key); + + /* Kr = Zr + parent(K)r */ + scalar_add_256bits(z + 32, priv_key + 32, res_key + 32); + + memcpy(inout->private_key, res_key, 32); + memcpy(inout->private_key_extension, res_key + 32, 32); + + if (keysize == 64) { + data[0] = 1; + } else { + data[0] = 3; + } + hmac_sha512_Init(&ctx, inout->chain_code, 32); + hmac_sha512_Update(&ctx, data, 1 + keysize + 4); + hmac_sha512_Final(&ctx, z); + + memcpy(inout->chain_code, z + 32, 32); + inout->depth++; + inout->child_num = index; + memzero(inout->public_key, sizeof(inout->public_key)); + + // making sure to wipe our memory + memzero(z, sizeof(z)); + memzero(data, sizeof(data)); + memzero(priv_key, sizeof(priv_key)); + memzero(res_key, sizeof(res_key)); + return 1; } -int hdnode_from_seed_cardano(const uint8_t *pass, int pass_len, const uint8_t *seed, int seed_len, HDNode *out) { - static CONFIDENTIAL uint8_t secret[96]; - pbkdf2_hmac_sha512(pass, pass_len, seed, seed_len, 4096, secret, 96); - - secret[0] &= 248; - secret[31] &= 31; - secret[31] |= 64; +int hdnode_from_seed_cardano(const uint8_t *pass, int pass_len, + const uint8_t *seed, int seed_len, HDNode *out) { + static CONFIDENTIAL uint8_t secret[96]; + pbkdf2_hmac_sha512(pass, pass_len, seed, seed_len, 4096, secret, 96); + + secret[0] &= 248; + secret[31] &= 31; + secret[31] |= 64; - memzero(out, sizeof(HDNode)); - out->depth = 0; - out->child_num = 0; - out->curve = get_curve_by_name(ED25519_CARDANO_NAME); + memzero(out, sizeof(HDNode)); + out->depth = 0; + out->child_num = 0; + out->curve = get_curve_by_name(ED25519_CARDANO_NAME); - memcpy(out->private_key, secret, 32); - memcpy(out->private_key_extension, secret + 32, 32); + memcpy(out->private_key, secret, 32); + memcpy(out->private_key_extension, secret + 32, 32); - out->public_key[0] = 0; - hdnode_fill_public_key(out); + out->public_key[0] = 0; + hdnode_fill_public_key(out); - memcpy(out->chain_code, secret + 64, 32); - memzero(secret, sizeof(secret)); + memcpy(out->chain_code, secret + 64, 32); + memzero(secret, sizeof(secret)); - return 1; + return 1; } #endif -int hdnode_public_ckd_cp(const ecdsa_curve *curve, const curve_point *parent, const uint8_t *parent_chain_code, uint32_t i, curve_point *child, uint8_t *child_chain_code) { - uint8_t data[1 + 32 + 4]; - uint8_t I[32 + 32]; - bignum256 c; - - if (i & 0x80000000) { // private derivation - return 0; - } - - data[0] = 0x02 | (parent->y.val[0] & 0x01); - bn_write_be(&parent->x, data + 1); - write_be(data + 33, i); - - while (true) { - hmac_sha512(parent_chain_code, 32, data, sizeof(data), I); - bn_read_be(I, &c); - if (bn_is_less(&c, &curve->order)) { // < order - scalar_multiply(curve, &c, child); // b = c * G - point_add(curve, parent, child); // b = a + b - if (!point_is_infinity(child)) { - if (child_chain_code) { - memcpy(child_chain_code, I + 32, 32); - } - - // Wipe all stack data. - memzero(data, sizeof(data)); - memzero(I, sizeof(I)); - memzero(&c, sizeof(c)); - return 1; - } - } - - data[0] = 1; - memcpy(data + 1, I + 32, 32); - } +int hdnode_public_ckd_cp(const ecdsa_curve *curve, const curve_point *parent, + const uint8_t *parent_chain_code, uint32_t i, + curve_point *child, uint8_t *child_chain_code) { + uint8_t data[1 + 32 + 4]; + uint8_t I[32 + 32]; + bignum256 c; + + if (i & 0x80000000) { // private derivation + return 0; + } + + data[0] = 0x02 | (parent->y.val[0] & 0x01); + bn_write_be(&parent->x, data + 1); + write_be(data + 33, i); + + while (true) { + hmac_sha512(parent_chain_code, 32, data, sizeof(data), I); + bn_read_be(I, &c); + if (bn_is_less(&c, &curve->order)) { // < order + scalar_multiply(curve, &c, child); // b = c * G + point_add(curve, parent, child); // b = a + b + if (!point_is_infinity(child)) { + if (child_chain_code) { + memcpy(child_chain_code, I + 32, 32); + } + + // Wipe all stack data. + memzero(data, sizeof(data)); + memzero(I, sizeof(I)); + memzero(&c, sizeof(c)); + return 1; + } + } + + data[0] = 1; + memcpy(data + 1, I + 32, 32); + } } -int hdnode_public_ckd(HDNode *inout, uint32_t i) -{ - curve_point parent, child; - - if (!ecdsa_read_pubkey(inout->curve->params, inout->public_key, &parent)) { - return 0; - } - if (!hdnode_public_ckd_cp(inout->curve->params, &parent, inout->chain_code, i, &child, inout->chain_code)) { - return 0; - } - memzero(inout->private_key, 32); - inout->depth++; - inout->child_num = i; - inout->public_key[0] = 0x02 | (child.y.val[0] & 0x01); - bn_write_be(&child.x, inout->public_key + 1); - - // Wipe all stack data. - memzero(&parent, sizeof(parent)); - memzero(&child, sizeof(child)); - - return 1; +int hdnode_public_ckd(HDNode *inout, uint32_t i) { + curve_point parent, child; + + if (!ecdsa_read_pubkey(inout->curve->params, inout->public_key, &parent)) { + return 0; + } + if (!hdnode_public_ckd_cp(inout->curve->params, &parent, inout->chain_code, i, + &child, inout->chain_code)) { + return 0; + } + memzero(inout->private_key, 32); + inout->depth++; + inout->child_num = i; + inout->public_key[0] = 0x02 | (child.y.val[0] & 0x01); + bn_write_be(&child.x, inout->public_key + 1); + + // Wipe all stack data. + memzero(&parent, sizeof(parent)); + memzero(&child, sizeof(child)); + + return 1; } -void hdnode_public_ckd_address_optimized(const curve_point *pub, const uint8_t *chain_code, uint32_t i, uint32_t version, HasherType hasher_pubkey, HasherType hasher_base58, char *addr, int addrsize, int addrformat) -{ - uint8_t child_pubkey[33]; - curve_point b; - - hdnode_public_ckd_cp(&secp256k1, pub, chain_code, i, &b, NULL); - child_pubkey[0] = 0x02 | (b.y.val[0] & 0x01); - bn_write_be(&b.x, child_pubkey + 1); - - switch (addrformat) { - case 1: // Segwit-in-P2SH - ecdsa_get_address_segwit_p2sh(child_pubkey, version, hasher_pubkey, hasher_base58, addr, addrsize); - break; - default: // normal address - ecdsa_get_address(child_pubkey, version, hasher_pubkey, hasher_base58, addr, addrsize); - break; - } +void hdnode_public_ckd_address_optimized(const curve_point *pub, + const uint8_t *chain_code, uint32_t i, + uint32_t version, + HasherType hasher_pubkey, + HasherType hasher_base58, char *addr, + int addrsize, int addrformat) { + uint8_t child_pubkey[33]; + curve_point b; + + hdnode_public_ckd_cp(&secp256k1, pub, chain_code, i, &b, NULL); + child_pubkey[0] = 0x02 | (b.y.val[0] & 0x01); + bn_write_be(&b.x, child_pubkey + 1); + + switch (addrformat) { + case 1: // Segwit-in-P2SH + ecdsa_get_address_segwit_p2sh(child_pubkey, version, hasher_pubkey, + hasher_base58, addr, addrsize); + break; + default: // normal address + ecdsa_get_address(child_pubkey, version, hasher_pubkey, hasher_base58, + addr, addrsize); + break; + } } #if USE_BIP32_CACHE @@ -465,385 +476,412 @@ static CONFIDENTIAL HDNode private_ckd_cache_root; static int private_ckd_cache_index = 0; static CONFIDENTIAL struct { - bool set; - size_t depth; - uint32_t i[BIP32_CACHE_MAXDEPTH]; - HDNode node; + bool set; + size_t depth; + uint32_t i[BIP32_CACHE_MAXDEPTH]; + HDNode node; } private_ckd_cache[BIP32_CACHE_SIZE]; -int hdnode_private_ckd_cached(HDNode *inout, const uint32_t *i, size_t i_count, uint32_t *fingerprint) -{ - if (i_count == 0) { - // no way how to compute parent fingerprint - return 1; - } - if (i_count == 1) { - if (fingerprint) { - *fingerprint = hdnode_fingerprint(inout); - } - if (hdnode_private_ckd(inout, i[0]) == 0) return 0; - return 1; - } - - bool found = false; - // if root is not set or not the same - if (!private_ckd_cache_root_set || memcmp(&private_ckd_cache_root, inout, sizeof(HDNode)) != 0) { - // clear the cache - private_ckd_cache_index = 0; - memzero(private_ckd_cache, sizeof(private_ckd_cache)); - // setup new root - memcpy(&private_ckd_cache_root, inout, sizeof(HDNode)); - private_ckd_cache_root_set = true; - } else { - // try to find parent - int j; - for (j = 0; j < BIP32_CACHE_SIZE; j++) { - if (private_ckd_cache[j].set && - private_ckd_cache[j].depth == i_count - 1 && - memcmp(private_ckd_cache[j].i, i, (i_count - 1) * sizeof(uint32_t)) == 0 && - private_ckd_cache[j].node.curve == inout->curve) { - memcpy(inout, &(private_ckd_cache[j].node), sizeof(HDNode)); - found = true; - break; - } - } - } - - // else derive parent - if (!found) { - size_t k; - for (k = 0; k < i_count - 1; k++) { - if (hdnode_private_ckd(inout, i[k]) == 0) return 0; - } - // and save it - memzero(&(private_ckd_cache[private_ckd_cache_index]), sizeof(private_ckd_cache[private_ckd_cache_index])); - private_ckd_cache[private_ckd_cache_index].set = true; - private_ckd_cache[private_ckd_cache_index].depth = i_count - 1; - memcpy(private_ckd_cache[private_ckd_cache_index].i, i, (i_count - 1) * sizeof(uint32_t)); - memcpy(&(private_ckd_cache[private_ckd_cache_index].node), inout, sizeof(HDNode)); - private_ckd_cache_index = (private_ckd_cache_index + 1) % BIP32_CACHE_SIZE; - } - - if (fingerprint) { - *fingerprint = hdnode_fingerprint(inout); - } - if (hdnode_private_ckd(inout, i[i_count - 1]) == 0) return 0; - - return 1; +int hdnode_private_ckd_cached(HDNode *inout, const uint32_t *i, size_t i_count, + uint32_t *fingerprint) { + if (i_count == 0) { + // no way how to compute parent fingerprint + return 1; + } + if (i_count == 1) { + if (fingerprint) { + *fingerprint = hdnode_fingerprint(inout); + } + if (hdnode_private_ckd(inout, i[0]) == 0) return 0; + return 1; + } + + bool found = false; + // if root is not set or not the same + if (!private_ckd_cache_root_set || + memcmp(&private_ckd_cache_root, inout, sizeof(HDNode)) != 0) { + // clear the cache + private_ckd_cache_index = 0; + memzero(private_ckd_cache, sizeof(private_ckd_cache)); + // setup new root + memcpy(&private_ckd_cache_root, inout, sizeof(HDNode)); + private_ckd_cache_root_set = true; + } else { + // try to find parent + int j; + for (j = 0; j < BIP32_CACHE_SIZE; j++) { + if (private_ckd_cache[j].set && + private_ckd_cache[j].depth == i_count - 1 && + memcmp(private_ckd_cache[j].i, i, (i_count - 1) * sizeof(uint32_t)) == + 0 && + private_ckd_cache[j].node.curve == inout->curve) { + memcpy(inout, &(private_ckd_cache[j].node), sizeof(HDNode)); + found = true; + break; + } + } + } + + // else derive parent + if (!found) { + size_t k; + for (k = 0; k < i_count - 1; k++) { + if (hdnode_private_ckd(inout, i[k]) == 0) return 0; + } + // and save it + memzero(&(private_ckd_cache[private_ckd_cache_index]), + sizeof(private_ckd_cache[private_ckd_cache_index])); + private_ckd_cache[private_ckd_cache_index].set = true; + private_ckd_cache[private_ckd_cache_index].depth = i_count - 1; + memcpy(private_ckd_cache[private_ckd_cache_index].i, i, + (i_count - 1) * sizeof(uint32_t)); + memcpy(&(private_ckd_cache[private_ckd_cache_index].node), inout, + sizeof(HDNode)); + private_ckd_cache_index = (private_ckd_cache_index + 1) % BIP32_CACHE_SIZE; + } + + if (fingerprint) { + *fingerprint = hdnode_fingerprint(inout); + } + if (hdnode_private_ckd(inout, i[i_count - 1]) == 0) return 0; + + return 1; } #endif -void hdnode_get_address_raw(HDNode *node, uint32_t version, uint8_t *addr_raw) -{ - hdnode_fill_public_key(node); - ecdsa_get_address_raw(node->public_key, version, node->curve->hasher_pubkey, addr_raw); +void hdnode_get_address_raw(HDNode *node, uint32_t version, uint8_t *addr_raw) { + hdnode_fill_public_key(node); + ecdsa_get_address_raw(node->public_key, version, node->curve->hasher_pubkey, + addr_raw); } -void hdnode_get_address(HDNode *node, uint32_t version, char *addr, int addrsize) -{ - hdnode_fill_public_key(node); - ecdsa_get_address(node->public_key, version, node->curve->hasher_pubkey, node->curve->hasher_base58, addr, addrsize); +void hdnode_get_address(HDNode *node, uint32_t version, char *addr, + int addrsize) { + hdnode_fill_public_key(node); + ecdsa_get_address(node->public_key, version, node->curve->hasher_pubkey, + node->curve->hasher_base58, addr, addrsize); } -void hdnode_fill_public_key(HDNode *node) -{ - if (node->public_key[0] != 0) - return; +void hdnode_fill_public_key(HDNode *node) { + if (node->public_key[0] != 0) return; #if USE_BIP32_25519_CURVES - if (node->curve->params) { - ecdsa_get_public_key33(node->curve->params, node->private_key, node->public_key); - } else { - node->public_key[0] = 1; - if (node->curve == &ed25519_info) { - ed25519_publickey(node->private_key, node->public_key + 1); - } else if (node->curve == &ed25519_sha3_info) { - ed25519_publickey_sha3(node->private_key, node->public_key + 1); + if (node->curve->params) { + ecdsa_get_public_key33(node->curve->params, node->private_key, + node->public_key); + } else { + node->public_key[0] = 1; + if (node->curve == &ed25519_info) { + ed25519_publickey(node->private_key, node->public_key + 1); + } else if (node->curve == &ed25519_sha3_info) { + ed25519_publickey_sha3(node->private_key, node->public_key + 1); #if USE_KECCAK - } else if (node->curve == &ed25519_keccak_info) { - ed25519_publickey_keccak(node->private_key, node->public_key + 1); + } else if (node->curve == &ed25519_keccak_info) { + ed25519_publickey_keccak(node->private_key, node->public_key + 1); #endif - } else if (node->curve == &curve25519_info) { - curve25519_scalarmult_basepoint(node->public_key + 1, node->private_key); + } else if (node->curve == &curve25519_info) { + curve25519_scalarmult_basepoint(node->public_key + 1, node->private_key); #if USE_CARDANO - } else if (node->curve == &ed25519_cardano_info) { - ed25519_publickey_ext(node->private_key, node->private_key_extension, node->public_key + 1); + } else if (node->curve == &ed25519_cardano_info) { + ed25519_publickey_ext(node->private_key, node->private_key_extension, + node->public_key + 1); #endif - } - } + } + } #else - ecdsa_get_public_key33(node->curve->params, node->private_key, node->public_key); + ecdsa_get_public_key33(node->curve->params, node->private_key, + node->public_key); #endif } #if USE_ETHEREUM -int hdnode_get_ethereum_pubkeyhash(const HDNode *node, uint8_t *pubkeyhash) -{ - uint8_t buf[65]; - SHA3_CTX ctx; +int hdnode_get_ethereum_pubkeyhash(const HDNode *node, uint8_t *pubkeyhash) { + uint8_t buf[65]; + SHA3_CTX ctx; - /* get uncompressed public key */ - ecdsa_get_public_key65(node->curve->params, node->private_key, buf); + /* get uncompressed public key */ + ecdsa_get_public_key65(node->curve->params, node->private_key, buf); - /* compute sha3 of x and y coordinate without 04 prefix */ - sha3_256_Init(&ctx); - sha3_Update(&ctx, buf + 1, 64); - keccak_Final(&ctx, buf); + /* compute sha3 of x and y coordinate without 04 prefix */ + sha3_256_Init(&ctx); + sha3_Update(&ctx, buf + 1, 64); + keccak_Final(&ctx, buf); - /* result are the least significant 160 bits */ - memcpy(pubkeyhash, buf + 12, 20); + /* result are the least significant 160 bits */ + memcpy(pubkeyhash, buf + 12, 20); - return 1; + return 1; } #endif #if USE_NEM int hdnode_get_nem_address(HDNode *node, uint8_t version, char *address) { - if (node->curve != &ed25519_keccak_info) { - return 0; - } + if (node->curve != &ed25519_keccak_info) { + return 0; + } - hdnode_fill_public_key(node); - return nem_get_address(&node->public_key[1], version, address); + hdnode_fill_public_key(node); + return nem_get_address(&node->public_key[1], version, address); } -int hdnode_get_nem_shared_key(const HDNode *node, const ed25519_public_key peer_public_key, const uint8_t *salt, ed25519_public_key mul, uint8_t *shared_key) { - if (node->curve != &ed25519_keccak_info) { - return 0; - } +int hdnode_get_nem_shared_key(const HDNode *node, + const ed25519_public_key peer_public_key, + const uint8_t *salt, ed25519_public_key mul, + uint8_t *shared_key) { + if (node->curve != &ed25519_keccak_info) { + return 0; + } - // sizeof(ed25519_public_key) == SHA3_256_DIGEST_LENGTH - if (mul == NULL) mul = shared_key; + // sizeof(ed25519_public_key) == SHA3_256_DIGEST_LENGTH + if (mul == NULL) mul = shared_key; - if (ed25519_scalarmult_keccak(mul, node->private_key, peer_public_key)) { - return 0; - } + if (ed25519_scalarmult_keccak(mul, node->private_key, peer_public_key)) { + return 0; + } - for (size_t i = 0; i < 32; i++) { - shared_key[i] = mul[i] ^ salt[i]; - } + for (size_t i = 0; i < 32; i++) { + shared_key[i] = mul[i] ^ salt[i]; + } - keccak_256(shared_key, 32, shared_key); - return 1; + keccak_256(shared_key, 32, shared_key); + return 1; } -int hdnode_nem_encrypt(const HDNode *node, const ed25519_public_key public_key, const uint8_t *iv_immut, const uint8_t *salt, const uint8_t *payload, size_t size, uint8_t *buffer) { - uint8_t last_block[AES_BLOCK_SIZE]; - uint8_t remainder = size % AES_BLOCK_SIZE; +int hdnode_nem_encrypt(const HDNode *node, const ed25519_public_key public_key, + const uint8_t *iv_immut, const uint8_t *salt, + const uint8_t *payload, size_t size, uint8_t *buffer) { + uint8_t last_block[AES_BLOCK_SIZE]; + uint8_t remainder = size % AES_BLOCK_SIZE; - // Round down to last whole block - size -= remainder; - // Copy old last block - memcpy(last_block, &payload[size], remainder); - // Pad new last block with number of missing bytes - memset(&last_block[remainder], AES_BLOCK_SIZE - remainder, AES_BLOCK_SIZE - remainder); + // Round down to last whole block + size -= remainder; + // Copy old last block + memcpy(last_block, &payload[size], remainder); + // Pad new last block with number of missing bytes + memset(&last_block[remainder], AES_BLOCK_SIZE - remainder, + AES_BLOCK_SIZE - remainder); - // the IV gets mutated, so we make a copy not to touch the original - uint8_t iv[AES_BLOCK_SIZE]; - memcpy(iv, iv_immut, AES_BLOCK_SIZE); + // the IV gets mutated, so we make a copy not to touch the original + uint8_t iv[AES_BLOCK_SIZE]; + memcpy(iv, iv_immut, AES_BLOCK_SIZE); - uint8_t shared_key[SHA3_256_DIGEST_LENGTH]; - if (!hdnode_get_nem_shared_key(node, public_key, salt, NULL, shared_key)) { - return 0; - } + uint8_t shared_key[SHA3_256_DIGEST_LENGTH]; + if (!hdnode_get_nem_shared_key(node, public_key, salt, NULL, shared_key)) { + return 0; + } - aes_encrypt_ctx ctx; + aes_encrypt_ctx ctx; - int ret = aes_encrypt_key256(shared_key, &ctx); - memzero(shared_key, sizeof(shared_key)); + int ret = aes_encrypt_key256(shared_key, &ctx); + memzero(shared_key, sizeof(shared_key)); - if (ret != EXIT_SUCCESS) { - return 0; - } + if (ret != EXIT_SUCCESS) { + return 0; + } - if (aes_cbc_encrypt(payload, buffer, size, iv, &ctx) != EXIT_SUCCESS) { - return 0; - } + if (aes_cbc_encrypt(payload, buffer, size, iv, &ctx) != EXIT_SUCCESS) { + return 0; + } - if (aes_cbc_encrypt(last_block, &buffer[size], sizeof(last_block), iv, &ctx) != EXIT_SUCCESS) { - return 0; - } + if (aes_cbc_encrypt(last_block, &buffer[size], sizeof(last_block), iv, + &ctx) != EXIT_SUCCESS) { + return 0; + } - return 1; + return 1; } -int hdnode_nem_decrypt(const HDNode *node, const ed25519_public_key public_key, uint8_t *iv, const uint8_t *salt, const uint8_t *payload, size_t size, uint8_t *buffer) { - uint8_t shared_key[SHA3_256_DIGEST_LENGTH]; +int hdnode_nem_decrypt(const HDNode *node, const ed25519_public_key public_key, + uint8_t *iv, const uint8_t *salt, const uint8_t *payload, + size_t size, uint8_t *buffer) { + uint8_t shared_key[SHA3_256_DIGEST_LENGTH]; - if (!hdnode_get_nem_shared_key(node, public_key, salt, NULL, shared_key)) { - return 0; - } + if (!hdnode_get_nem_shared_key(node, public_key, salt, NULL, shared_key)) { + return 0; + } - aes_decrypt_ctx ctx; + aes_decrypt_ctx ctx; - int ret = aes_decrypt_key256(shared_key, &ctx); - memzero(shared_key, sizeof(shared_key)); + int ret = aes_decrypt_key256(shared_key, &ctx); + memzero(shared_key, sizeof(shared_key)); - if (ret != EXIT_SUCCESS) { - return 0; - } + if (ret != EXIT_SUCCESS) { + return 0; + } - if (aes_cbc_decrypt(payload, buffer, size, iv, &ctx) != EXIT_SUCCESS) { - return 0; - } + if (aes_cbc_decrypt(payload, buffer, size, iv, &ctx) != EXIT_SUCCESS) { + return 0; + } - return 1; + return 1; } #endif // msg is a data to be signed // msg_len is the message length -int hdnode_sign(HDNode *node, const uint8_t *msg, uint32_t msg_len, HasherType hasher_sign, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64])) -{ - if (node->curve->params) { - return ecdsa_sign(node->curve->params, hasher_sign, node->private_key, msg, msg_len, sig, pby, is_canonical); - } else if (node->curve == &curve25519_info) { - return 1; // signatures are not supported - } else { - hdnode_fill_public_key(node); - if (node->curve == &ed25519_info) { - ed25519_sign(msg, msg_len, node->private_key, node->public_key + 1, sig); - } else if (node->curve == &ed25519_sha3_info) { - ed25519_sign_sha3(msg, msg_len, node->private_key, node->public_key + 1, sig); +int hdnode_sign(HDNode *node, const uint8_t *msg, uint32_t msg_len, + HasherType hasher_sign, uint8_t *sig, uint8_t *pby, + int (*is_canonical)(uint8_t by, uint8_t sig[64])) { + if (node->curve->params) { + return ecdsa_sign(node->curve->params, hasher_sign, node->private_key, msg, + msg_len, sig, pby, is_canonical); + } else if (node->curve == &curve25519_info) { + return 1; // signatures are not supported + } else { + hdnode_fill_public_key(node); + if (node->curve == &ed25519_info) { + ed25519_sign(msg, msg_len, node->private_key, node->public_key + 1, sig); + } else if (node->curve == &ed25519_sha3_info) { + ed25519_sign_sha3(msg, msg_len, node->private_key, node->public_key + 1, + sig); #if USE_KECCAK - } else if (node->curve == &ed25519_keccak_info) { - ed25519_sign_keccak(msg, msg_len, node->private_key, node->public_key + 1, sig); + } else if (node->curve == &ed25519_keccak_info) { + ed25519_sign_keccak(msg, msg_len, node->private_key, node->public_key + 1, + sig); #endif - } - return 0; - } + } + return 0; + } } -int hdnode_sign_digest(HDNode *node, const uint8_t *digest, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64])) -{ - if (node->curve->params) { - return ecdsa_sign_digest(node->curve->params, node->private_key, digest, sig, pby, is_canonical); - } else if (node->curve == &curve25519_info) { - return 1; // signatures are not supported - } else { - return hdnode_sign(node, digest, 32, 0, sig, pby, is_canonical); - } +int hdnode_sign_digest(HDNode *node, const uint8_t *digest, uint8_t *sig, + uint8_t *pby, + int (*is_canonical)(uint8_t by, uint8_t sig[64])) { + if (node->curve->params) { + return ecdsa_sign_digest(node->curve->params, node->private_key, digest, + sig, pby, is_canonical); + } else if (node->curve == &curve25519_info) { + return 1; // signatures are not supported + } else { + return hdnode_sign(node, digest, 32, 0, sig, pby, is_canonical); + } } -int hdnode_get_shared_key(const HDNode *node, const uint8_t *peer_public_key, uint8_t *session_key, int *result_size) -{ - // Use elliptic curve Diffie-Helman to compute shared session key - if (node->curve->params) { - if (ecdh_multiply(node->curve->params, node->private_key, peer_public_key, session_key) != 0) { - return 1; - } - *result_size = 65; - return 0; - } else if (node->curve == &curve25519_info) { - session_key[0] = 0x04; - if (peer_public_key[0] != 0x40) { - return 1; // Curve25519 public key should start with 0x40 byte. - } - curve25519_scalarmult(session_key + 1, node->private_key, peer_public_key + 1); - *result_size = 33; - return 0; - } else { - *result_size = 0; - return 1; // ECDH is not supported - } +int hdnode_get_shared_key(const HDNode *node, const uint8_t *peer_public_key, + uint8_t *session_key, int *result_size) { + // Use elliptic curve Diffie-Helman to compute shared session key + if (node->curve->params) { + if (ecdh_multiply(node->curve->params, node->private_key, peer_public_key, + session_key) != 0) { + return 1; + } + *result_size = 65; + return 0; + } else if (node->curve == &curve25519_info) { + session_key[0] = 0x04; + if (peer_public_key[0] != 0x40) { + return 1; // Curve25519 public key should start with 0x40 byte. + } + curve25519_scalarmult(session_key + 1, node->private_key, + peer_public_key + 1); + *result_size = 33; + return 0; + } else { + *result_size = 0; + return 1; // ECDH is not supported + } } -static int hdnode_serialize(const HDNode *node, uint32_t fingerprint, uint32_t version, char use_public, char *str, int strsize) -{ - uint8_t node_data[78]; - write_be(node_data, version); - node_data[4] = node->depth; - write_be(node_data + 5, fingerprint); - write_be(node_data + 9, node->child_num); - memcpy(node_data + 13, node->chain_code, 32); - if (use_public) { - memcpy(node_data + 45, node->public_key, 33); - } else { - node_data[45] = 0; - memcpy(node_data + 46, node->private_key, 32); - } - int ret = base58_encode_check(node_data, sizeof(node_data), node->curve->hasher_base58, str, strsize); - memzero(node_data, sizeof(node_data)); - return ret; +static int hdnode_serialize(const HDNode *node, uint32_t fingerprint, + uint32_t version, char use_public, char *str, + int strsize) { + uint8_t node_data[78]; + write_be(node_data, version); + node_data[4] = node->depth; + write_be(node_data + 5, fingerprint); + write_be(node_data + 9, node->child_num); + memcpy(node_data + 13, node->chain_code, 32); + if (use_public) { + memcpy(node_data + 45, node->public_key, 33); + } else { + node_data[45] = 0; + memcpy(node_data + 46, node->private_key, 32); + } + int ret = base58_encode_check(node_data, sizeof(node_data), + node->curve->hasher_base58, str, strsize); + memzero(node_data, sizeof(node_data)); + return ret; } -int hdnode_serialize_public(const HDNode *node, uint32_t fingerprint, uint32_t version, char *str, int strsize) -{ - return hdnode_serialize(node, fingerprint, version, 1, str, strsize); +int hdnode_serialize_public(const HDNode *node, uint32_t fingerprint, + uint32_t version, char *str, int strsize) { + return hdnode_serialize(node, fingerprint, version, 1, str, strsize); } -int hdnode_serialize_private(const HDNode *node, uint32_t fingerprint, uint32_t version, char *str, int strsize) -{ - return hdnode_serialize(node, fingerprint, version, 0, str, strsize); +int hdnode_serialize_private(const HDNode *node, uint32_t fingerprint, + uint32_t version, char *str, int strsize) { + return hdnode_serialize(node, fingerprint, version, 0, str, strsize); } // check for validity of curve point in case of public data not performed -int hdnode_deserialize(const char *str, uint32_t version_public, uint32_t version_private, const char *curve, HDNode *node, uint32_t *fingerprint) -{ - uint8_t node_data[78]; - memzero(node, sizeof(HDNode)); - node->curve = get_curve_by_name(curve); - if (base58_decode_check(str, node->curve->hasher_base58, node_data, sizeof(node_data)) != sizeof(node_data)) { - return -1; - } - uint32_t version = read_be(node_data); - if (version == version_public) { - memzero(node->private_key, sizeof(node->private_key)); - memcpy(node->public_key, node_data + 45, 33); - } else if (version == version_private) { // private node - if (node_data[45]) { // invalid data - return -2; - } - memcpy(node->private_key, node_data + 46, 32); - memzero(node->public_key, sizeof(node->public_key)); - } else { - return -3; // invalid version - } - node->depth = node_data[4]; - if (fingerprint) { - *fingerprint = read_be(node_data + 5); - } - node->child_num = read_be(node_data + 9); - memcpy(node->chain_code, node_data + 13, 32); - return 0; +int hdnode_deserialize(const char *str, uint32_t version_public, + uint32_t version_private, const char *curve, + HDNode *node, uint32_t *fingerprint) { + uint8_t node_data[78]; + memzero(node, sizeof(HDNode)); + node->curve = get_curve_by_name(curve); + if (base58_decode_check(str, node->curve->hasher_base58, node_data, + sizeof(node_data)) != sizeof(node_data)) { + return -1; + } + uint32_t version = read_be(node_data); + if (version == version_public) { + memzero(node->private_key, sizeof(node->private_key)); + memcpy(node->public_key, node_data + 45, 33); + } else if (version == version_private) { // private node + if (node_data[45]) { // invalid data + return -2; + } + memcpy(node->private_key, node_data + 46, 32); + memzero(node->public_key, sizeof(node->public_key)); + } else { + return -3; // invalid version + } + node->depth = node_data[4]; + if (fingerprint) { + *fingerprint = read_be(node_data + 5); + } + node->child_num = read_be(node_data + 9); + memcpy(node->chain_code, node_data + 13, 32); + return 0; } const curve_info *get_curve_by_name(const char *curve_name) { - if (curve_name == 0) { - return 0; - } - if (strcmp(curve_name, SECP256K1_NAME) == 0) { - return &secp256k1_info; - } - if (strcmp(curve_name, SECP256K1_DECRED_NAME) == 0) { - return &secp256k1_decred_info; - } - if (strcmp(curve_name, SECP256K1_GROESTL_NAME) == 0) { - return &secp256k1_groestl_info; - } - if (strcmp(curve_name, SECP256K1_SMART_NAME) == 0) { - return &secp256k1_smart_info; - } - if (strcmp(curve_name, NIST256P1_NAME) == 0) { - return &nist256p1_info; - } - if (strcmp(curve_name, ED25519_NAME) == 0) { - return &ed25519_info; - } - if (strcmp(curve_name, ED25519_CARDANO_NAME) == 0) { - return &ed25519_cardano_info; - } - if (strcmp(curve_name, ED25519_SHA3_NAME) == 0) { - return &ed25519_sha3_info; - } + if (curve_name == 0) { + return 0; + } + if (strcmp(curve_name, SECP256K1_NAME) == 0) { + return &secp256k1_info; + } + if (strcmp(curve_name, SECP256K1_DECRED_NAME) == 0) { + return &secp256k1_decred_info; + } + if (strcmp(curve_name, SECP256K1_GROESTL_NAME) == 0) { + return &secp256k1_groestl_info; + } + if (strcmp(curve_name, SECP256K1_SMART_NAME) == 0) { + return &secp256k1_smart_info; + } + if (strcmp(curve_name, NIST256P1_NAME) == 0) { + return &nist256p1_info; + } + if (strcmp(curve_name, ED25519_NAME) == 0) { + return &ed25519_info; + } + if (strcmp(curve_name, ED25519_CARDANO_NAME) == 0) { + return &ed25519_cardano_info; + } + if (strcmp(curve_name, ED25519_SHA3_NAME) == 0) { + return &ed25519_sha3_info; + } #if USE_KECCAK - if (strcmp(curve_name, ED25519_KECCAK_NAME) == 0) { - return &ed25519_keccak_info; - } + if (strcmp(curve_name, ED25519_KECCAK_NAME) == 0) { + return &ed25519_keccak_info; + } #endif - if (strcmp(curve_name, CURVE25519_NAME) == 0) { - return &curve25519_info; - } - return 0; + if (strcmp(curve_name, CURVE25519_NAME) == 0) { + return &curve25519_info; + } + return 0; } diff --git a/bip32.h b/bip32.h index c0a04b5f8..995a7aea9 100644 --- a/bip32.h +++ b/bip32.h @@ -24,58 +24,73 @@ #ifndef __BIP32_H__ #define __BIP32_H__ +#include #include #include -#include #include "ecdsa.h" #include "ed25519-donna/ed25519.h" #include "options.h" typedef struct { - const char *bip32_name; // string for generating BIP32 xprv from seed - const ecdsa_curve *params; // ecdsa curve parameters, null for ed25519 + const char *bip32_name; // string for generating BIP32 xprv from seed + const ecdsa_curve *params; // ecdsa curve parameters, null for ed25519 - HasherType hasher_base58; - HasherType hasher_sign; - HasherType hasher_pubkey; - HasherType hasher_script; + HasherType hasher_base58; + HasherType hasher_sign; + HasherType hasher_pubkey; + HasherType hasher_script; } curve_info; typedef struct { - uint32_t depth; - uint32_t child_num; - uint8_t chain_code[32]; + uint32_t depth; + uint32_t child_num; + uint8_t chain_code[32]; - uint8_t private_key[32]; - uint8_t private_key_extension[32]; + uint8_t private_key[32]; + uint8_t private_key_extension[32]; - uint8_t public_key[33]; - const curve_info *curve; + uint8_t public_key[33]; + const curve_info *curve; } HDNode; -int hdnode_from_xpub(uint32_t depth, uint32_t child_num, const uint8_t *chain_code, const uint8_t *public_key, const char *curve, HDNode *out); +int hdnode_from_xpub(uint32_t depth, uint32_t child_num, + const uint8_t *chain_code, const uint8_t *public_key, + const char *curve, HDNode *out); -int hdnode_from_xprv(uint32_t depth, uint32_t child_num, const uint8_t *chain_code, const uint8_t *private_key, const char *curve, HDNode *out); +int hdnode_from_xprv(uint32_t depth, uint32_t child_num, + const uint8_t *chain_code, const uint8_t *private_key, + const char *curve, HDNode *out); -int hdnode_from_seed(const uint8_t *seed, int seed_len, const char *curve, HDNode *out); +int hdnode_from_seed(const uint8_t *seed, int seed_len, const char *curve, + HDNode *out); -#define hdnode_private_ckd_prime(X, I) hdnode_private_ckd((X), ((I) | 0x80000000)) +#define hdnode_private_ckd_prime(X, I) \ + hdnode_private_ckd((X), ((I) | 0x80000000)) int hdnode_private_ckd(HDNode *inout, uint32_t i); #if USE_CARDANO int hdnode_private_ckd_cardano(HDNode *inout, uint32_t i); -int hdnode_from_seed_cardano(const uint8_t *pass, int pass_len, const uint8_t *seed, int seed_len, HDNode *out); +int hdnode_from_seed_cardano(const uint8_t *pass, int pass_len, + const uint8_t *seed, int seed_len, HDNode *out); #endif -int hdnode_public_ckd_cp(const ecdsa_curve *curve, const curve_point *parent, const uint8_t *parent_chain_code, uint32_t i, curve_point *child, uint8_t *child_chain_code); +int hdnode_public_ckd_cp(const ecdsa_curve *curve, const curve_point *parent, + const uint8_t *parent_chain_code, uint32_t i, + curve_point *child, uint8_t *child_chain_code); int hdnode_public_ckd(HDNode *inout, uint32_t i); -void hdnode_public_ckd_address_optimized(const curve_point *pub, const uint8_t *chain_code, uint32_t i, uint32_t version, HasherType hasher_pubkey, HasherType hasher_base58, char *addr, int addrsize, int addrformat); +void hdnode_public_ckd_address_optimized(const curve_point *pub, + const uint8_t *chain_code, uint32_t i, + uint32_t version, + HasherType hasher_pubkey, + HasherType hasher_base58, char *addr, + int addrsize, int addrformat); #if USE_BIP32_CACHE -int hdnode_private_ckd_cached(HDNode *inout, const uint32_t *i, size_t i_count, uint32_t *fingerprint); +int hdnode_private_ckd_cached(HDNode *inout, const uint32_t *i, size_t i_count, + uint32_t *fingerprint); #endif uint32_t hdnode_fingerprint(HDNode *node); @@ -88,24 +103,41 @@ int hdnode_get_ethereum_pubkeyhash(const HDNode *node, uint8_t *pubkeyhash); #if USE_NEM int hdnode_get_nem_address(HDNode *node, uint8_t version, char *address); -int hdnode_get_nem_shared_key(const HDNode *node, const ed25519_public_key peer_public_key, const uint8_t *salt, ed25519_public_key mul, uint8_t *shared_key); -int hdnode_nem_encrypt(const HDNode *node, const ed25519_public_key public_key, const uint8_t *iv, const uint8_t *salt, const uint8_t *payload, size_t size, uint8_t *buffer); -int hdnode_nem_decrypt(const HDNode *node, const ed25519_public_key public_key, uint8_t *iv, const uint8_t *salt, const uint8_t *payload, size_t size, uint8_t *buffer); +int hdnode_get_nem_shared_key(const HDNode *node, + const ed25519_public_key peer_public_key, + const uint8_t *salt, ed25519_public_key mul, + uint8_t *shared_key); +int hdnode_nem_encrypt(const HDNode *node, const ed25519_public_key public_key, + const uint8_t *iv, const uint8_t *salt, + const uint8_t *payload, size_t size, uint8_t *buffer); +int hdnode_nem_decrypt(const HDNode *node, const ed25519_public_key public_key, + uint8_t *iv, const uint8_t *salt, const uint8_t *payload, + size_t size, uint8_t *buffer); #endif -int hdnode_sign(HDNode *node, const uint8_t *msg, uint32_t msg_len, HasherType hasher_sign, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64])); -int hdnode_sign_digest(HDNode *node, const uint8_t *digest, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64])); +int hdnode_sign(HDNode *node, const uint8_t *msg, uint32_t msg_len, + HasherType hasher_sign, uint8_t *sig, uint8_t *pby, + int (*is_canonical)(uint8_t by, uint8_t sig[64])); +int hdnode_sign_digest(HDNode *node, const uint8_t *digest, uint8_t *sig, + uint8_t *pby, + int (*is_canonical)(uint8_t by, uint8_t sig[64])); -int hdnode_get_shared_key(const HDNode *node, const uint8_t *peer_public_key, uint8_t *session_key, int *result_size); +int hdnode_get_shared_key(const HDNode *node, const uint8_t *peer_public_key, + uint8_t *session_key, int *result_size); -int hdnode_serialize_public(const HDNode *node, uint32_t fingerprint, uint32_t version, char *str, int strsize); +int hdnode_serialize_public(const HDNode *node, uint32_t fingerprint, + uint32_t version, char *str, int strsize); -int hdnode_serialize_private(const HDNode *node, uint32_t fingerprint, uint32_t version, char *str, int strsize); +int hdnode_serialize_private(const HDNode *node, uint32_t fingerprint, + uint32_t version, char *str, int strsize); -int hdnode_deserialize(const char *str, uint32_t version_public, uint32_t version_private, const char *curve, HDNode *node, uint32_t *fingerprint); +int hdnode_deserialize(const char *str, uint32_t version_public, + uint32_t version_private, const char *curve, + HDNode *node, uint32_t *fingerprint); void hdnode_get_address_raw(HDNode *node, uint32_t version, uint8_t *addr_raw); -void hdnode_get_address(HDNode *node, uint32_t version, char *addr, int addrsize); +void hdnode_get_address(HDNode *node, uint32_t version, char *addr, + int addrsize); const curve_info *get_curve_by_name(const char *curve_name); diff --git a/bip39.c b/bip39.c index 2d0a9640c..6252f7126 100644 --- a/bip39.c +++ b/bip39.c @@ -21,216 +21,211 @@ * OTHER DEALINGS IN THE SOFTWARE. */ -#include #include +#include #include "bip39.h" +#include "bip39_english.h" #include "hmac.h" +#include "memzero.h" +#include "options.h" +#include "pbkdf2.h" #include "rand.h" #include "sha2.h" -#include "pbkdf2.h" -#include "bip39_english.h" -#include "options.h" -#include "memzero.h" #if USE_BIP39_CACHE static int bip39_cache_index = 0; static CONFIDENTIAL struct { - bool set; - char mnemonic[256]; - char passphrase[64]; - uint8_t seed[512 / 8]; + bool set; + char mnemonic[256]; + char passphrase[64]; + uint8_t seed[512 / 8]; } bip39_cache[BIP39_CACHE_SIZE]; #endif -const char *mnemonic_generate(int strength) -{ - if (strength % 32 || strength < 128 || strength > 256) { - return 0; - } - uint8_t data[32]; - random_buffer(data, 32); - const char *r = mnemonic_from_data(data, strength / 8); - memzero(data, sizeof(data)); - return r; +const char *mnemonic_generate(int strength) { + if (strength % 32 || strength < 128 || strength > 256) { + return 0; + } + uint8_t data[32]; + random_buffer(data, 32); + const char *r = mnemonic_from_data(data, strength / 8); + memzero(data, sizeof(data)); + return r; } static CONFIDENTIAL char mnemo[24 * 10]; -const char *mnemonic_from_data(const uint8_t *data, int len) -{ - if (len % 4 || len < 16 || len > 32) { - return 0; - } - - uint8_t bits[32 + 1]; - - sha256_Raw(data, len, bits); - // checksum - bits[len] = bits[0]; - // data - memcpy(bits, data, len); - - int mlen = len * 3 / 4; - - int i, j, idx; - char *p = mnemo; - for (i = 0; i < mlen; i++) { - idx = 0; - for (j = 0; j < 11; j++) { - idx <<= 1; - idx += (bits[(i * 11 + j) / 8] & (1 << (7 - ((i * 11 + j) % 8)))) > 0; - } - strcpy(p, wordlist[idx]); - p += strlen(wordlist[idx]); - *p = (i < mlen - 1) ? ' ' : 0; - p++; - } - memzero(bits, sizeof(bits)); - - return mnemo; +const char *mnemonic_from_data(const uint8_t *data, int len) { + if (len % 4 || len < 16 || len > 32) { + return 0; + } + + uint8_t bits[32 + 1]; + + sha256_Raw(data, len, bits); + // checksum + bits[len] = bits[0]; + // data + memcpy(bits, data, len); + + int mlen = len * 3 / 4; + + int i, j, idx; + char *p = mnemo; + for (i = 0; i < mlen; i++) { + idx = 0; + for (j = 0; j < 11; j++) { + idx <<= 1; + idx += (bits[(i * 11 + j) / 8] & (1 << (7 - ((i * 11 + j) % 8)))) > 0; + } + strcpy(p, wordlist[idx]); + p += strlen(wordlist[idx]); + *p = (i < mlen - 1) ? ' ' : 0; + p++; + } + memzero(bits, sizeof(bits)); + + return mnemo; } -void mnemonic_clear(void) -{ - memzero(mnemo, sizeof(mnemo)); +void mnemonic_clear(void) { memzero(mnemo, sizeof(mnemo)); } + +int mnemonic_to_entropy(const char *mnemonic, uint8_t *entropy) { + if (!mnemonic) { + return 0; + } + + uint32_t i = 0, n = 0; + + while (mnemonic[i]) { + if (mnemonic[i] == ' ') { + n++; + } + i++; + } + n++; + + // check number of words + if (n != 12 && n != 18 && n != 24) { + return 0; + } + + char current_word[10]; + uint32_t j, k, ki, bi = 0; + uint8_t bits[32 + 1]; + + memzero(bits, sizeof(bits)); + i = 0; + while (mnemonic[i]) { + j = 0; + while (mnemonic[i] != ' ' && mnemonic[i] != 0) { + if (j >= sizeof(current_word) - 1) { + return 0; + } + current_word[j] = mnemonic[i]; + i++; + j++; + } + current_word[j] = 0; + if (mnemonic[i] != 0) { + i++; + } + k = 0; + for (;;) { + if (!wordlist[k]) { // word not found + return 0; + } + if (strcmp(current_word, wordlist[k]) == 0) { // word found on index k + for (ki = 0; ki < 11; ki++) { + if (k & (1 << (10 - ki))) { + bits[bi / 8] |= 1 << (7 - (bi % 8)); + } + bi++; + } + break; + } + k++; + } + } + if (bi != n * 11) { + return 0; + } + memcpy(entropy, bits, sizeof(bits)); + return n * 11; } -int mnemonic_to_entropy(const char *mnemonic, uint8_t *entropy) -{ - if (!mnemonic) { - return 0; - } - - uint32_t i = 0, n = 0; - - while (mnemonic[i]) { - if (mnemonic[i] == ' ') { - n++; - } - i++; - } - n++; - - // check number of words - if (n != 12 && n != 18 && n != 24) { - return 0; - } - - char current_word[10]; - uint32_t j, k, ki, bi = 0; - uint8_t bits[32 + 1]; - - memzero(bits, sizeof(bits)); - i = 0; - while (mnemonic[i]) { - j = 0; - while (mnemonic[i] != ' ' && mnemonic[i] != 0) { - if (j >= sizeof(current_word) - 1) { - return 0; - } - current_word[j] = mnemonic[i]; - i++; j++; - } - current_word[j] = 0; - if (mnemonic[i] != 0) { - i++; - } - k = 0; - for (;;) { - if (!wordlist[k]) { // word not found - return 0; - } - if (strcmp(current_word, wordlist[k]) == 0) { // word found on index k - for (ki = 0; ki < 11; ki++) { - if (k & (1 << (10 - ki))) { - bits[bi / 8] |= 1 << (7 - (bi % 8)); - } - bi++; - } - break; - } - k++; - } - } - if (bi != n * 11) { - return 0; - } - memcpy(entropy, bits, sizeof(bits)); - return n * 11; -} - -int mnemonic_check(const char *mnemonic) -{ - uint8_t bits[32 + 1]; - int seed_len = mnemonic_to_entropy(mnemonic, bits); - if (seed_len != (12 * 11) && seed_len != (18 * 11) && seed_len != (24 * 11)) { - return 0; - } - int words = seed_len / 11; - - uint8_t checksum = bits[words * 4 / 3]; - sha256_Raw(bits, words * 4 / 3, bits); - if (words == 12) { - return (bits[0] & 0xF0) == (checksum & 0xF0); // compare first 4 bits - } else if (words == 18) { - return (bits[0] & 0xFC) == (checksum & 0xFC); // compare first 6 bits - } else if (words == 24) { - return bits[0] == checksum; // compare 8 bits - } - return 0; +int mnemonic_check(const char *mnemonic) { + uint8_t bits[32 + 1]; + int seed_len = mnemonic_to_entropy(mnemonic, bits); + if (seed_len != (12 * 11) && seed_len != (18 * 11) && seed_len != (24 * 11)) { + return 0; + } + int words = seed_len / 11; + + uint8_t checksum = bits[words * 4 / 3]; + sha256_Raw(bits, words * 4 / 3, bits); + if (words == 12) { + return (bits[0] & 0xF0) == (checksum & 0xF0); // compare first 4 bits + } else if (words == 18) { + return (bits[0] & 0xFC) == (checksum & 0xFC); // compare first 6 bits + } else if (words == 24) { + return bits[0] == checksum; // compare 8 bits + } + return 0; } // passphrase must be at most 256 characters otherwise it would be truncated -void mnemonic_to_seed(const char *mnemonic, const char *passphrase, uint8_t seed[512 / 8], void (*progress_callback)(uint32_t current, uint32_t total)) -{ - int mnemoniclen = strlen(mnemonic); - int passphraselen = strnlen(passphrase, 256); +void mnemonic_to_seed(const char *mnemonic, const char *passphrase, + uint8_t seed[512 / 8], + void (*progress_callback)(uint32_t current, + uint32_t total)) { + int mnemoniclen = strlen(mnemonic); + int passphraselen = strnlen(passphrase, 256); #if USE_BIP39_CACHE - // check cache - if (mnemoniclen < 256 && passphraselen < 64) { - for (int i = 0; i < BIP39_CACHE_SIZE; i++) { - if (!bip39_cache[i].set) continue; - if (strcmp(bip39_cache[i].mnemonic, mnemonic) != 0) continue; - if (strcmp(bip39_cache[i].passphrase, passphrase) != 0) continue; - // found the correct entry - memcpy(seed, bip39_cache[i].seed, 512 / 8); - return; - } - } + // check cache + if (mnemoniclen < 256 && passphraselen < 64) { + for (int i = 0; i < BIP39_CACHE_SIZE; i++) { + if (!bip39_cache[i].set) continue; + if (strcmp(bip39_cache[i].mnemonic, mnemonic) != 0) continue; + if (strcmp(bip39_cache[i].passphrase, passphrase) != 0) continue; + // found the correct entry + memcpy(seed, bip39_cache[i].seed, 512 / 8); + return; + } + } #endif - uint8_t salt[8 + 256]; - memcpy(salt, "mnemonic", 8); - memcpy(salt + 8, passphrase, passphraselen); - static CONFIDENTIAL PBKDF2_HMAC_SHA512_CTX pctx; - pbkdf2_hmac_sha512_Init(&pctx, (const uint8_t *)mnemonic, mnemoniclen, salt, passphraselen + 8, 1); - if (progress_callback) { - progress_callback(0, BIP39_PBKDF2_ROUNDS); - } - for (int i = 0; i < 16; i++) { - pbkdf2_hmac_sha512_Update(&pctx, BIP39_PBKDF2_ROUNDS / 16); - if (progress_callback) { - progress_callback((i + 1) * BIP39_PBKDF2_ROUNDS / 16, BIP39_PBKDF2_ROUNDS); - } - } - pbkdf2_hmac_sha512_Final(&pctx, seed); - memzero(salt, sizeof(salt)); + uint8_t salt[8 + 256]; + memcpy(salt, "mnemonic", 8); + memcpy(salt + 8, passphrase, passphraselen); + static CONFIDENTIAL PBKDF2_HMAC_SHA512_CTX pctx; + pbkdf2_hmac_sha512_Init(&pctx, (const uint8_t *)mnemonic, mnemoniclen, salt, + passphraselen + 8, 1); + if (progress_callback) { + progress_callback(0, BIP39_PBKDF2_ROUNDS); + } + for (int i = 0; i < 16; i++) { + pbkdf2_hmac_sha512_Update(&pctx, BIP39_PBKDF2_ROUNDS / 16); + if (progress_callback) { + progress_callback((i + 1) * BIP39_PBKDF2_ROUNDS / 16, + BIP39_PBKDF2_ROUNDS); + } + } + pbkdf2_hmac_sha512_Final(&pctx, seed); + memzero(salt, sizeof(salt)); #if USE_BIP39_CACHE - // store to cache - if (mnemoniclen < 256 && passphraselen < 64) { - bip39_cache[bip39_cache_index].set = true; - strcpy(bip39_cache[bip39_cache_index].mnemonic, mnemonic); - strcpy(bip39_cache[bip39_cache_index].passphrase, passphrase); - memcpy(bip39_cache[bip39_cache_index].seed, seed, 512 / 8); - bip39_cache_index = (bip39_cache_index + 1) % BIP39_CACHE_SIZE; - } + // store to cache + if (mnemoniclen < 256 && passphraselen < 64) { + bip39_cache[bip39_cache_index].set = true; + strcpy(bip39_cache[bip39_cache_index].mnemonic, mnemonic); + strcpy(bip39_cache[bip39_cache_index].passphrase, passphrase); + memcpy(bip39_cache[bip39_cache_index].seed, seed, 512 / 8); + bip39_cache_index = (bip39_cache_index + 1) % BIP39_CACHE_SIZE; + } #endif } -const char * const *mnemonic_wordlist(void) -{ - return wordlist; -} +const char *const *mnemonic_wordlist(void) { return wordlist; } diff --git a/bip39.h b/bip39.h index ac76101d7..a2c3eb8c0 100644 --- a/bip39.h +++ b/bip39.h @@ -28,7 +28,7 @@ #define BIP39_PBKDF2_ROUNDS 2048 -const char *mnemonic_generate(int strength); // strength in bits +const char *mnemonic_generate(int strength); // strength in bits const char *mnemonic_from_data(const uint8_t *data, int len); void mnemonic_clear(void); @@ -37,8 +37,11 @@ int mnemonic_check(const char *mnemonic); int mnemonic_to_entropy(const char *mnemonic, uint8_t *entropy); // passphrase must be at most 256 characters otherwise it would be truncated -void mnemonic_to_seed(const char *mnemonic, const char *passphrase, uint8_t seed[512 / 8], void (*progress_callback)(uint32_t current, uint32_t total)); +void mnemonic_to_seed(const char *mnemonic, const char *passphrase, + uint8_t seed[512 / 8], + void (*progress_callback)(uint32_t current, + uint32_t total)); -const char * const *mnemonic_wordlist(void); +const char *const *mnemonic_wordlist(void); #endif diff --git a/bip39_english.h b/bip39_english.h index 77607ba7f..c57fca365 100644 --- a/bip39_english.h +++ b/bip39_english.h @@ -21,2054 +21,347 @@ * OTHER DEALINGS IN THE SOFTWARE. */ -static const char * const wordlist[] = { -"abandon", -"ability", -"able", -"about", -"above", -"absent", -"absorb", -"abstract", -"absurd", -"abuse", -"access", -"accident", -"account", -"accuse", -"achieve", -"acid", -"acoustic", -"acquire", -"across", -"act", -"action", -"actor", -"actress", -"actual", -"adapt", -"add", -"addict", -"address", -"adjust", -"admit", -"adult", -"advance", -"advice", -"aerobic", -"affair", -"afford", -"afraid", -"again", -"age", -"agent", -"agree", -"ahead", -"aim", -"air", -"airport", -"aisle", -"alarm", -"album", -"alcohol", -"alert", -"alien", -"all", -"alley", -"allow", -"almost", -"alone", -"alpha", -"already", -"also", -"alter", -"always", -"amateur", -"amazing", -"among", -"amount", -"amused", -"analyst", -"anchor", -"ancient", -"anger", -"angle", -"angry", -"animal", -"ankle", -"announce", -"annual", -"another", -"answer", -"antenna", -"antique", -"anxiety", -"any", -"apart", -"apology", -"appear", -"apple", -"approve", -"april", -"arch", -"arctic", -"area", -"arena", -"argue", -"arm", -"armed", -"armor", -"army", -"around", -"arrange", -"arrest", -"arrive", -"arrow", -"art", -"artefact", -"artist", -"artwork", -"ask", -"aspect", -"assault", -"asset", -"assist", -"assume", -"asthma", -"athlete", -"atom", -"attack", -"attend", -"attitude", -"attract", -"auction", -"audit", -"august", -"aunt", -"author", -"auto", -"autumn", -"average", -"avocado", -"avoid", -"awake", -"aware", -"away", -"awesome", -"awful", -"awkward", -"axis", -"baby", -"bachelor", -"bacon", -"badge", -"bag", -"balance", -"balcony", -"ball", -"bamboo", -"banana", -"banner", -"bar", -"barely", -"bargain", -"barrel", -"base", -"basic", -"basket", -"battle", -"beach", -"bean", -"beauty", -"because", -"become", -"beef", -"before", -"begin", -"behave", -"behind", -"believe", -"below", -"belt", -"bench", -"benefit", -"best", -"betray", -"better", -"between", -"beyond", -"bicycle", -"bid", -"bike", -"bind", -"biology", -"bird", -"birth", -"bitter", -"black", -"blade", -"blame", -"blanket", -"blast", -"bleak", -"bless", -"blind", -"blood", -"blossom", -"blouse", -"blue", -"blur", -"blush", -"board", -"boat", -"body", -"boil", -"bomb", -"bone", -"bonus", -"book", -"boost", -"border", -"boring", -"borrow", -"boss", -"bottom", -"bounce", -"box", -"boy", -"bracket", -"brain", -"brand", -"brass", -"brave", -"bread", -"breeze", -"brick", -"bridge", -"brief", -"bright", -"bring", -"brisk", -"broccoli", -"broken", -"bronze", -"broom", -"brother", -"brown", -"brush", -"bubble", -"buddy", -"budget", -"buffalo", -"build", -"bulb", -"bulk", -"bullet", -"bundle", -"bunker", -"burden", -"burger", -"burst", -"bus", -"business", -"busy", -"butter", -"buyer", -"buzz", -"cabbage", -"cabin", -"cable", -"cactus", -"cage", -"cake", -"call", -"calm", -"camera", -"camp", -"can", -"canal", -"cancel", -"candy", -"cannon", -"canoe", -"canvas", -"canyon", -"capable", -"capital", -"captain", -"car", -"carbon", -"card", -"cargo", -"carpet", -"carry", -"cart", -"case", -"cash", -"casino", -"castle", -"casual", -"cat", -"catalog", -"catch", -"category", -"cattle", -"caught", -"cause", -"caution", -"cave", -"ceiling", -"celery", -"cement", -"census", -"century", -"cereal", -"certain", -"chair", -"chalk", -"champion", -"change", -"chaos", -"chapter", -"charge", -"chase", -"chat", -"cheap", -"check", -"cheese", -"chef", -"cherry", -"chest", -"chicken", -"chief", -"child", -"chimney", -"choice", -"choose", -"chronic", -"chuckle", -"chunk", -"churn", -"cigar", -"cinnamon", -"circle", -"citizen", -"city", -"civil", -"claim", -"clap", -"clarify", -"claw", -"clay", -"clean", -"clerk", -"clever", -"click", -"client", -"cliff", -"climb", -"clinic", -"clip", -"clock", -"clog", -"close", -"cloth", -"cloud", -"clown", -"club", -"clump", -"cluster", -"clutch", -"coach", -"coast", -"coconut", -"code", -"coffee", -"coil", -"coin", -"collect", -"color", -"column", -"combine", -"come", -"comfort", -"comic", -"common", -"company", -"concert", -"conduct", -"confirm", -"congress", -"connect", -"consider", -"control", -"convince", -"cook", -"cool", -"copper", -"copy", -"coral", -"core", -"corn", -"correct", -"cost", -"cotton", -"couch", -"country", -"couple", -"course", -"cousin", -"cover", -"coyote", -"crack", -"cradle", -"craft", -"cram", -"crane", -"crash", -"crater", -"crawl", -"crazy", -"cream", -"credit", -"creek", -"crew", -"cricket", -"crime", -"crisp", -"critic", -"crop", -"cross", -"crouch", -"crowd", -"crucial", -"cruel", -"cruise", -"crumble", -"crunch", -"crush", -"cry", -"crystal", -"cube", -"culture", -"cup", -"cupboard", -"curious", -"current", -"curtain", -"curve", -"cushion", -"custom", -"cute", -"cycle", -"dad", -"damage", -"damp", -"dance", -"danger", -"daring", -"dash", -"daughter", -"dawn", -"day", -"deal", -"debate", -"debris", -"decade", -"december", -"decide", -"decline", -"decorate", -"decrease", -"deer", -"defense", -"define", -"defy", -"degree", -"delay", -"deliver", -"demand", -"demise", -"denial", -"dentist", -"deny", -"depart", -"depend", -"deposit", -"depth", -"deputy", -"derive", -"describe", -"desert", -"design", -"desk", -"despair", -"destroy", -"detail", -"detect", -"develop", -"device", -"devote", -"diagram", -"dial", -"diamond", -"diary", -"dice", -"diesel", -"diet", -"differ", -"digital", -"dignity", -"dilemma", -"dinner", -"dinosaur", -"direct", -"dirt", -"disagree", -"discover", -"disease", -"dish", -"dismiss", -"disorder", -"display", -"distance", -"divert", -"divide", -"divorce", -"dizzy", -"doctor", -"document", -"dog", -"doll", -"dolphin", -"domain", -"donate", -"donkey", -"donor", -"door", -"dose", -"double", -"dove", -"draft", -"dragon", -"drama", -"drastic", -"draw", -"dream", -"dress", -"drift", -"drill", -"drink", -"drip", -"drive", -"drop", -"drum", -"dry", -"duck", -"dumb", -"dune", -"during", -"dust", -"dutch", -"duty", -"dwarf", -"dynamic", -"eager", -"eagle", -"early", -"earn", -"earth", -"easily", -"east", -"easy", -"echo", -"ecology", -"economy", -"edge", -"edit", -"educate", -"effort", -"egg", -"eight", -"either", -"elbow", -"elder", -"electric", -"elegant", -"element", -"elephant", -"elevator", -"elite", -"else", -"embark", -"embody", -"embrace", -"emerge", -"emotion", -"employ", -"empower", -"empty", -"enable", -"enact", -"end", -"endless", -"endorse", -"enemy", -"energy", -"enforce", -"engage", -"engine", -"enhance", -"enjoy", -"enlist", -"enough", -"enrich", -"enroll", -"ensure", -"enter", -"entire", -"entry", -"envelope", -"episode", -"equal", -"equip", -"era", -"erase", -"erode", -"erosion", -"error", -"erupt", -"escape", -"essay", -"essence", -"estate", -"eternal", -"ethics", -"evidence", -"evil", -"evoke", -"evolve", -"exact", -"example", -"excess", -"exchange", -"excite", -"exclude", -"excuse", -"execute", -"exercise", -"exhaust", -"exhibit", -"exile", -"exist", -"exit", -"exotic", -"expand", -"expect", -"expire", -"explain", -"expose", -"express", -"extend", -"extra", -"eye", -"eyebrow", -"fabric", -"face", -"faculty", -"fade", -"faint", -"faith", -"fall", -"false", -"fame", -"family", -"famous", -"fan", -"fancy", -"fantasy", -"farm", -"fashion", -"fat", -"fatal", -"father", -"fatigue", -"fault", -"favorite", -"feature", -"february", -"federal", -"fee", -"feed", -"feel", -"female", -"fence", -"festival", -"fetch", -"fever", -"few", -"fiber", -"fiction", -"field", -"figure", -"file", -"film", -"filter", -"final", -"find", -"fine", -"finger", -"finish", -"fire", -"firm", -"first", -"fiscal", -"fish", -"fit", -"fitness", -"fix", -"flag", -"flame", -"flash", -"flat", -"flavor", -"flee", -"flight", -"flip", -"float", -"flock", -"floor", -"flower", -"fluid", -"flush", -"fly", -"foam", -"focus", -"fog", -"foil", -"fold", -"follow", -"food", -"foot", -"force", -"forest", -"forget", -"fork", -"fortune", -"forum", -"forward", -"fossil", -"foster", -"found", -"fox", -"fragile", -"frame", -"frequent", -"fresh", -"friend", -"fringe", -"frog", -"front", -"frost", -"frown", -"frozen", -"fruit", -"fuel", -"fun", -"funny", -"furnace", -"fury", -"future", -"gadget", -"gain", -"galaxy", -"gallery", -"game", -"gap", -"garage", -"garbage", -"garden", -"garlic", -"garment", -"gas", -"gasp", -"gate", -"gather", -"gauge", -"gaze", -"general", -"genius", -"genre", -"gentle", -"genuine", -"gesture", -"ghost", -"giant", -"gift", -"giggle", -"ginger", -"giraffe", -"girl", -"give", -"glad", -"glance", -"glare", -"glass", -"glide", -"glimpse", -"globe", -"gloom", -"glory", -"glove", -"glow", -"glue", -"goat", -"goddess", -"gold", -"good", -"goose", -"gorilla", -"gospel", -"gossip", -"govern", -"gown", -"grab", -"grace", -"grain", -"grant", -"grape", -"grass", -"gravity", -"great", -"green", -"grid", -"grief", -"grit", -"grocery", -"group", -"grow", -"grunt", -"guard", -"guess", -"guide", -"guilt", -"guitar", -"gun", -"gym", -"habit", -"hair", -"half", -"hammer", -"hamster", -"hand", -"happy", -"harbor", -"hard", -"harsh", -"harvest", -"hat", -"have", -"hawk", -"hazard", -"head", -"health", -"heart", -"heavy", -"hedgehog", -"height", -"hello", -"helmet", -"help", -"hen", -"hero", -"hidden", -"high", -"hill", -"hint", -"hip", -"hire", -"history", -"hobby", -"hockey", -"hold", -"hole", -"holiday", -"hollow", -"home", -"honey", -"hood", -"hope", -"horn", -"horror", -"horse", -"hospital", -"host", -"hotel", -"hour", -"hover", -"hub", -"huge", -"human", -"humble", -"humor", -"hundred", -"hungry", -"hunt", -"hurdle", -"hurry", -"hurt", -"husband", -"hybrid", -"ice", -"icon", -"idea", -"identify", -"idle", -"ignore", -"ill", -"illegal", -"illness", -"image", -"imitate", -"immense", -"immune", -"impact", -"impose", -"improve", -"impulse", -"inch", -"include", -"income", -"increase", -"index", -"indicate", -"indoor", -"industry", -"infant", -"inflict", -"inform", -"inhale", -"inherit", -"initial", -"inject", -"injury", -"inmate", -"inner", -"innocent", -"input", -"inquiry", -"insane", -"insect", -"inside", -"inspire", -"install", -"intact", -"interest", -"into", -"invest", -"invite", -"involve", -"iron", -"island", -"isolate", -"issue", -"item", -"ivory", -"jacket", -"jaguar", -"jar", -"jazz", -"jealous", -"jeans", -"jelly", -"jewel", -"job", -"join", -"joke", -"journey", -"joy", -"judge", -"juice", -"jump", -"jungle", -"junior", -"junk", -"just", -"kangaroo", -"keen", -"keep", -"ketchup", -"key", -"kick", -"kid", -"kidney", -"kind", -"kingdom", -"kiss", -"kit", -"kitchen", -"kite", -"kitten", -"kiwi", -"knee", -"knife", -"knock", -"know", -"lab", -"label", -"labor", -"ladder", -"lady", -"lake", -"lamp", -"language", -"laptop", -"large", -"later", -"latin", -"laugh", -"laundry", -"lava", -"law", -"lawn", -"lawsuit", -"layer", -"lazy", -"leader", -"leaf", -"learn", -"leave", -"lecture", -"left", -"leg", -"legal", -"legend", -"leisure", -"lemon", -"lend", -"length", -"lens", -"leopard", -"lesson", -"letter", -"level", -"liar", -"liberty", -"library", -"license", -"life", -"lift", -"light", -"like", -"limb", -"limit", -"link", -"lion", -"liquid", -"list", -"little", -"live", -"lizard", -"load", -"loan", -"lobster", -"local", -"lock", -"logic", -"lonely", -"long", -"loop", -"lottery", -"loud", -"lounge", -"love", -"loyal", -"lucky", -"luggage", -"lumber", -"lunar", -"lunch", -"luxury", -"lyrics", -"machine", -"mad", -"magic", -"magnet", -"maid", -"mail", -"main", -"major", -"make", -"mammal", -"man", -"manage", -"mandate", -"mango", -"mansion", -"manual", -"maple", -"marble", -"march", -"margin", -"marine", -"market", -"marriage", -"mask", -"mass", -"master", -"match", -"material", -"math", -"matrix", -"matter", -"maximum", -"maze", -"meadow", -"mean", -"measure", -"meat", -"mechanic", -"medal", -"media", -"melody", -"melt", -"member", -"memory", -"mention", -"menu", -"mercy", -"merge", -"merit", -"merry", -"mesh", -"message", -"metal", -"method", -"middle", -"midnight", -"milk", -"million", -"mimic", -"mind", -"minimum", -"minor", -"minute", -"miracle", -"mirror", -"misery", -"miss", -"mistake", -"mix", -"mixed", -"mixture", -"mobile", -"model", -"modify", -"mom", -"moment", -"monitor", -"monkey", -"monster", -"month", -"moon", -"moral", -"more", -"morning", -"mosquito", -"mother", -"motion", -"motor", -"mountain", -"mouse", -"move", -"movie", -"much", -"muffin", -"mule", -"multiply", -"muscle", -"museum", -"mushroom", -"music", -"must", -"mutual", -"myself", -"mystery", -"myth", -"naive", -"name", -"napkin", -"narrow", -"nasty", -"nation", -"nature", -"near", -"neck", -"need", -"negative", -"neglect", -"neither", -"nephew", -"nerve", -"nest", -"net", -"network", -"neutral", -"never", -"news", -"next", -"nice", -"night", -"noble", -"noise", -"nominee", -"noodle", -"normal", -"north", -"nose", -"notable", -"note", -"nothing", -"notice", -"novel", -"now", -"nuclear", -"number", -"nurse", -"nut", -"oak", -"obey", -"object", -"oblige", -"obscure", -"observe", -"obtain", -"obvious", -"occur", -"ocean", -"october", -"odor", -"off", -"offer", -"office", -"often", -"oil", -"okay", -"old", -"olive", -"olympic", -"omit", -"once", -"one", -"onion", -"online", -"only", -"open", -"opera", -"opinion", -"oppose", -"option", -"orange", -"orbit", -"orchard", -"order", -"ordinary", -"organ", -"orient", -"original", -"orphan", -"ostrich", -"other", -"outdoor", -"outer", -"output", -"outside", -"oval", -"oven", -"over", -"own", -"owner", -"oxygen", -"oyster", -"ozone", -"pact", -"paddle", -"page", -"pair", -"palace", -"palm", -"panda", -"panel", -"panic", -"panther", -"paper", -"parade", -"parent", -"park", -"parrot", -"party", -"pass", -"patch", -"path", -"patient", -"patrol", -"pattern", -"pause", -"pave", -"payment", -"peace", -"peanut", -"pear", -"peasant", -"pelican", -"pen", -"penalty", -"pencil", -"people", -"pepper", -"perfect", -"permit", -"person", -"pet", -"phone", -"photo", -"phrase", -"physical", -"piano", -"picnic", -"picture", -"piece", -"pig", -"pigeon", -"pill", -"pilot", -"pink", -"pioneer", -"pipe", -"pistol", -"pitch", -"pizza", -"place", -"planet", -"plastic", -"plate", -"play", -"please", -"pledge", -"pluck", -"plug", -"plunge", -"poem", -"poet", -"point", -"polar", -"pole", -"police", -"pond", -"pony", -"pool", -"popular", -"portion", -"position", -"possible", -"post", -"potato", -"pottery", -"poverty", -"powder", -"power", -"practice", -"praise", -"predict", -"prefer", -"prepare", -"present", -"pretty", -"prevent", -"price", -"pride", -"primary", -"print", -"priority", -"prison", -"private", -"prize", -"problem", -"process", -"produce", -"profit", -"program", -"project", -"promote", -"proof", -"property", -"prosper", -"protect", -"proud", -"provide", -"public", -"pudding", -"pull", -"pulp", -"pulse", -"pumpkin", -"punch", -"pupil", -"puppy", -"purchase", -"purity", -"purpose", -"purse", -"push", -"put", -"puzzle", -"pyramid", -"quality", -"quantum", -"quarter", -"question", -"quick", -"quit", -"quiz", -"quote", -"rabbit", -"raccoon", -"race", -"rack", -"radar", -"radio", -"rail", -"rain", -"raise", -"rally", -"ramp", -"ranch", -"random", -"range", -"rapid", -"rare", -"rate", -"rather", -"raven", -"raw", -"razor", -"ready", -"real", -"reason", -"rebel", -"rebuild", -"recall", -"receive", -"recipe", -"record", -"recycle", -"reduce", -"reflect", -"reform", -"refuse", -"region", -"regret", -"regular", -"reject", -"relax", -"release", -"relief", -"rely", -"remain", -"remember", -"remind", -"remove", -"render", -"renew", -"rent", -"reopen", -"repair", -"repeat", -"replace", -"report", -"require", -"rescue", -"resemble", -"resist", -"resource", -"response", -"result", -"retire", -"retreat", -"return", -"reunion", -"reveal", -"review", -"reward", -"rhythm", -"rib", -"ribbon", -"rice", -"rich", -"ride", -"ridge", -"rifle", -"right", -"rigid", -"ring", -"riot", -"ripple", -"risk", -"ritual", -"rival", -"river", -"road", -"roast", -"robot", -"robust", -"rocket", -"romance", -"roof", -"rookie", -"room", -"rose", -"rotate", -"rough", -"round", -"route", -"royal", -"rubber", -"rude", -"rug", -"rule", -"run", -"runway", -"rural", -"sad", -"saddle", -"sadness", -"safe", -"sail", -"salad", -"salmon", -"salon", -"salt", -"salute", -"same", -"sample", -"sand", -"satisfy", -"satoshi", -"sauce", -"sausage", -"save", -"say", -"scale", -"scan", -"scare", -"scatter", -"scene", -"scheme", -"school", -"science", -"scissors", -"scorpion", -"scout", -"scrap", -"screen", -"script", -"scrub", -"sea", -"search", -"season", -"seat", -"second", -"secret", -"section", -"security", -"seed", -"seek", -"segment", -"select", -"sell", -"seminar", -"senior", -"sense", -"sentence", -"series", -"service", -"session", -"settle", -"setup", -"seven", -"shadow", -"shaft", -"shallow", -"share", -"shed", -"shell", -"sheriff", -"shield", -"shift", -"shine", -"ship", -"shiver", -"shock", -"shoe", -"shoot", -"shop", -"short", -"shoulder", -"shove", -"shrimp", -"shrug", -"shuffle", -"shy", -"sibling", -"sick", -"side", -"siege", -"sight", -"sign", -"silent", -"silk", -"silly", -"silver", -"similar", -"simple", -"since", -"sing", -"siren", -"sister", -"situate", -"six", -"size", -"skate", -"sketch", -"ski", -"skill", -"skin", -"skirt", -"skull", -"slab", -"slam", -"sleep", -"slender", -"slice", -"slide", -"slight", -"slim", -"slogan", -"slot", -"slow", -"slush", -"small", -"smart", -"smile", -"smoke", -"smooth", -"snack", -"snake", -"snap", -"sniff", -"snow", -"soap", -"soccer", -"social", -"sock", -"soda", -"soft", -"solar", -"soldier", -"solid", -"solution", -"solve", -"someone", -"song", -"soon", -"sorry", -"sort", -"soul", -"sound", -"soup", -"source", -"south", -"space", -"spare", -"spatial", -"spawn", -"speak", -"special", -"speed", -"spell", -"spend", -"sphere", -"spice", -"spider", -"spike", -"spin", -"spirit", -"split", -"spoil", -"sponsor", -"spoon", -"sport", -"spot", -"spray", -"spread", -"spring", -"spy", -"square", -"squeeze", -"squirrel", -"stable", -"stadium", -"staff", -"stage", -"stairs", -"stamp", -"stand", -"start", -"state", -"stay", -"steak", -"steel", -"stem", -"step", -"stereo", -"stick", -"still", -"sting", -"stock", -"stomach", -"stone", -"stool", -"story", -"stove", -"strategy", -"street", -"strike", -"strong", -"struggle", -"student", -"stuff", -"stumble", -"style", -"subject", -"submit", -"subway", -"success", -"such", -"sudden", -"suffer", -"sugar", -"suggest", -"suit", -"summer", -"sun", -"sunny", -"sunset", -"super", -"supply", -"supreme", -"sure", -"surface", -"surge", -"surprise", -"surround", -"survey", -"suspect", -"sustain", -"swallow", -"swamp", -"swap", -"swarm", -"swear", -"sweet", -"swift", -"swim", -"swing", -"switch", -"sword", -"symbol", -"symptom", -"syrup", -"system", -"table", -"tackle", -"tag", -"tail", -"talent", -"talk", -"tank", -"tape", -"target", -"task", -"taste", -"tattoo", -"taxi", -"teach", -"team", -"tell", -"ten", -"tenant", -"tennis", -"tent", -"term", -"test", -"text", -"thank", -"that", -"theme", -"then", -"theory", -"there", -"they", -"thing", -"this", -"thought", -"three", -"thrive", -"throw", -"thumb", -"thunder", -"ticket", -"tide", -"tiger", -"tilt", -"timber", -"time", -"tiny", -"tip", -"tired", -"tissue", -"title", -"toast", -"tobacco", -"today", -"toddler", -"toe", -"together", -"toilet", -"token", -"tomato", -"tomorrow", -"tone", -"tongue", -"tonight", -"tool", -"tooth", -"top", -"topic", -"topple", -"torch", -"tornado", -"tortoise", -"toss", -"total", -"tourist", -"toward", -"tower", -"town", -"toy", -"track", -"trade", -"traffic", -"tragic", -"train", -"transfer", -"trap", -"trash", -"travel", -"tray", -"treat", -"tree", -"trend", -"trial", -"tribe", -"trick", -"trigger", -"trim", -"trip", -"trophy", -"trouble", -"truck", -"true", -"truly", -"trumpet", -"trust", -"truth", -"try", -"tube", -"tuition", -"tumble", -"tuna", -"tunnel", -"turkey", -"turn", -"turtle", -"twelve", -"twenty", -"twice", -"twin", -"twist", -"two", -"type", -"typical", -"ugly", -"umbrella", -"unable", -"unaware", -"uncle", -"uncover", -"under", -"undo", -"unfair", -"unfold", -"unhappy", -"uniform", -"unique", -"unit", -"universe", -"unknown", -"unlock", -"until", -"unusual", -"unveil", -"update", -"upgrade", -"uphold", -"upon", -"upper", -"upset", -"urban", -"urge", -"usage", -"use", -"used", -"useful", -"useless", -"usual", -"utility", -"vacant", -"vacuum", -"vague", -"valid", -"valley", -"valve", -"van", -"vanish", -"vapor", -"various", -"vast", -"vault", -"vehicle", -"velvet", -"vendor", -"venture", -"venue", -"verb", -"verify", -"version", -"very", -"vessel", -"veteran", -"viable", -"vibrant", -"vicious", -"victory", -"video", -"view", -"village", -"vintage", -"violin", -"virtual", -"virus", -"visa", -"visit", -"visual", -"vital", -"vivid", -"vocal", -"voice", -"void", -"volcano", -"volume", -"vote", -"voyage", -"wage", -"wagon", -"wait", -"walk", -"wall", -"walnut", -"want", -"warfare", -"warm", -"warrior", -"wash", -"wasp", -"waste", -"water", -"wave", -"way", -"wealth", -"weapon", -"wear", -"weasel", -"weather", -"web", -"wedding", -"weekend", -"weird", -"welcome", -"west", -"wet", -"whale", -"what", -"wheat", -"wheel", -"when", -"where", -"whip", -"whisper", -"wide", -"width", -"wife", -"wild", -"will", -"win", -"window", -"wine", -"wing", -"wink", -"winner", -"winter", -"wire", -"wisdom", -"wise", -"wish", -"witness", -"wolf", -"woman", -"wonder", -"wood", -"wool", -"word", -"work", -"world", -"worry", -"worth", -"wrap", -"wreck", -"wrestle", -"wrist", -"write", -"wrong", -"yard", -"year", -"yellow", -"you", -"young", -"youth", -"zebra", -"zero", -"zone", -"zoo", -0, +static const char* const wordlist[] = { + "abandon", "ability", "able", "about", "above", "absent", + "absorb", "abstract", "absurd", "abuse", "access", "accident", + "account", "accuse", "achieve", "acid", "acoustic", "acquire", + "across", "act", "action", "actor", "actress", "actual", + "adapt", "add", "addict", "address", "adjust", "admit", + "adult", "advance", "advice", "aerobic", "affair", "afford", + "afraid", "again", "age", "agent", "agree", "ahead", + "aim", "air", "airport", "aisle", "alarm", "album", + "alcohol", "alert", "alien", "all", "alley", "allow", + "almost", "alone", "alpha", "already", "also", "alter", + "always", "amateur", "amazing", "among", "amount", "amused", + "analyst", "anchor", "ancient", "anger", "angle", "angry", + "animal", "ankle", "announce", "annual", "another", "answer", + "antenna", "antique", "anxiety", "any", "apart", "apology", + "appear", "apple", "approve", "april", "arch", "arctic", + "area", "arena", "argue", "arm", "armed", "armor", + "army", "around", "arrange", "arrest", "arrive", "arrow", + "art", "artefact", "artist", "artwork", "ask", "aspect", + "assault", "asset", "assist", "assume", "asthma", "athlete", + "atom", "attack", "attend", "attitude", "attract", "auction", + "audit", "august", "aunt", "author", "auto", "autumn", + "average", "avocado", "avoid", "awake", "aware", "away", + "awesome", "awful", "awkward", "axis", "baby", "bachelor", + "bacon", "badge", "bag", "balance", "balcony", "ball", + "bamboo", "banana", "banner", "bar", "barely", "bargain", + "barrel", "base", "basic", "basket", "battle", "beach", + "bean", "beauty", "because", "become", "beef", "before", + "begin", "behave", "behind", "believe", "below", "belt", + "bench", "benefit", "best", "betray", "better", "between", + "beyond", "bicycle", "bid", "bike", "bind", "biology", + "bird", "birth", "bitter", "black", "blade", "blame", + "blanket", "blast", "bleak", "bless", "blind", "blood", + "blossom", "blouse", "blue", "blur", "blush", "board", + "boat", "body", "boil", "bomb", "bone", "bonus", + "book", "boost", "border", "boring", "borrow", "boss", + "bottom", "bounce", "box", "boy", "bracket", "brain", + "brand", "brass", "brave", "bread", "breeze", "brick", + "bridge", "brief", "bright", "bring", "brisk", "broccoli", + "broken", "bronze", "broom", "brother", "brown", "brush", + "bubble", "buddy", "budget", "buffalo", "build", "bulb", + "bulk", "bullet", "bundle", "bunker", "burden", "burger", + "burst", "bus", "business", "busy", "butter", "buyer", + "buzz", "cabbage", "cabin", "cable", "cactus", "cage", + "cake", "call", "calm", "camera", "camp", "can", + "canal", "cancel", "candy", "cannon", "canoe", "canvas", + "canyon", "capable", "capital", "captain", "car", "carbon", + "card", "cargo", "carpet", "carry", "cart", "case", + "cash", "casino", "castle", "casual", "cat", "catalog", + "catch", "category", "cattle", "caught", "cause", "caution", + "cave", "ceiling", "celery", "cement", "census", "century", + "cereal", "certain", "chair", "chalk", "champion", "change", + "chaos", "chapter", "charge", "chase", "chat", "cheap", + "check", "cheese", "chef", "cherry", "chest", "chicken", + "chief", "child", "chimney", "choice", "choose", "chronic", + "chuckle", "chunk", "churn", "cigar", "cinnamon", "circle", + "citizen", "city", "civil", "claim", "clap", "clarify", + "claw", "clay", "clean", "clerk", "clever", "click", + "client", "cliff", "climb", "clinic", "clip", "clock", + "clog", "close", "cloth", "cloud", "clown", "club", + "clump", "cluster", "clutch", "coach", "coast", "coconut", + "code", "coffee", "coil", "coin", "collect", "color", + "column", "combine", "come", "comfort", "comic", "common", + "company", "concert", "conduct", "confirm", "congress", "connect", + "consider", "control", "convince", "cook", "cool", "copper", + "copy", "coral", "core", "corn", "correct", "cost", + "cotton", "couch", "country", "couple", "course", "cousin", + "cover", "coyote", "crack", "cradle", "craft", "cram", + "crane", "crash", "crater", "crawl", "crazy", "cream", + "credit", "creek", "crew", "cricket", "crime", "crisp", + "critic", "crop", "cross", "crouch", "crowd", "crucial", + "cruel", "cruise", "crumble", "crunch", "crush", "cry", + "crystal", "cube", "culture", "cup", "cupboard", "curious", + "current", "curtain", "curve", "cushion", "custom", "cute", + "cycle", "dad", "damage", "damp", "dance", "danger", + "daring", "dash", "daughter", "dawn", "day", "deal", + "debate", "debris", "decade", "december", "decide", "decline", + "decorate", "decrease", "deer", "defense", "define", "defy", + "degree", "delay", "deliver", "demand", "demise", "denial", + "dentist", "deny", "depart", "depend", "deposit", "depth", + "deputy", "derive", "describe", "desert", "design", "desk", + "despair", "destroy", "detail", "detect", "develop", "device", + "devote", "diagram", "dial", "diamond", "diary", "dice", + "diesel", "diet", "differ", "digital", "dignity", "dilemma", + "dinner", "dinosaur", "direct", "dirt", "disagree", "discover", + "disease", "dish", "dismiss", "disorder", "display", "distance", + "divert", "divide", "divorce", "dizzy", "doctor", "document", + "dog", "doll", "dolphin", "domain", "donate", "donkey", + "donor", "door", "dose", "double", "dove", "draft", + "dragon", "drama", "drastic", "draw", "dream", "dress", + "drift", "drill", "drink", "drip", "drive", "drop", + "drum", "dry", "duck", "dumb", "dune", "during", + "dust", "dutch", "duty", "dwarf", "dynamic", "eager", + "eagle", "early", "earn", "earth", "easily", "east", + "easy", "echo", "ecology", "economy", "edge", "edit", + "educate", "effort", "egg", "eight", "either", "elbow", + "elder", "electric", "elegant", "element", "elephant", "elevator", + "elite", "else", "embark", "embody", "embrace", "emerge", + "emotion", "employ", "empower", "empty", "enable", "enact", + "end", "endless", "endorse", "enemy", "energy", "enforce", + "engage", "engine", "enhance", "enjoy", "enlist", "enough", + "enrich", "enroll", "ensure", "enter", "entire", "entry", + "envelope", "episode", "equal", "equip", "era", "erase", + "erode", "erosion", "error", "erupt", "escape", "essay", + "essence", "estate", "eternal", "ethics", "evidence", "evil", + "evoke", "evolve", "exact", "example", "excess", "exchange", + "excite", "exclude", "excuse", "execute", "exercise", "exhaust", + "exhibit", "exile", "exist", "exit", "exotic", "expand", + "expect", "expire", "explain", "expose", "express", "extend", + "extra", "eye", "eyebrow", "fabric", "face", "faculty", + "fade", "faint", "faith", "fall", "false", "fame", + "family", "famous", "fan", "fancy", "fantasy", "farm", + "fashion", "fat", "fatal", "father", "fatigue", "fault", + "favorite", "feature", "february", "federal", "fee", "feed", + "feel", "female", "fence", "festival", "fetch", "fever", + "few", "fiber", "fiction", "field", "figure", "file", + "film", "filter", "final", "find", "fine", "finger", + "finish", "fire", "firm", "first", "fiscal", "fish", + "fit", "fitness", "fix", "flag", "flame", "flash", + "flat", "flavor", "flee", "flight", "flip", "float", + "flock", "floor", "flower", "fluid", "flush", "fly", + "foam", "focus", "fog", "foil", "fold", "follow", + "food", "foot", "force", "forest", "forget", "fork", + "fortune", "forum", "forward", "fossil", "foster", "found", + "fox", "fragile", "frame", "frequent", "fresh", "friend", + "fringe", "frog", "front", "frost", "frown", "frozen", + "fruit", "fuel", "fun", "funny", "furnace", "fury", + "future", "gadget", "gain", "galaxy", "gallery", "game", + "gap", "garage", "garbage", "garden", "garlic", "garment", + "gas", "gasp", "gate", "gather", "gauge", "gaze", + "general", "genius", "genre", "gentle", "genuine", "gesture", + "ghost", "giant", "gift", "giggle", "ginger", "giraffe", + "girl", "give", "glad", "glance", "glare", "glass", + "glide", "glimpse", "globe", "gloom", "glory", "glove", + "glow", "glue", "goat", "goddess", "gold", "good", + "goose", "gorilla", "gospel", "gossip", "govern", "gown", + "grab", "grace", "grain", "grant", "grape", "grass", + "gravity", "great", "green", "grid", "grief", "grit", + "grocery", "group", "grow", "grunt", "guard", "guess", + "guide", "guilt", "guitar", "gun", "gym", "habit", + "hair", "half", "hammer", "hamster", "hand", "happy", + "harbor", "hard", "harsh", "harvest", "hat", "have", + "hawk", "hazard", "head", "health", "heart", "heavy", + "hedgehog", "height", "hello", "helmet", "help", "hen", + "hero", "hidden", "high", "hill", "hint", "hip", + "hire", "history", "hobby", "hockey", "hold", "hole", + "holiday", "hollow", "home", "honey", "hood", "hope", + "horn", "horror", "horse", "hospital", "host", "hotel", + "hour", "hover", "hub", "huge", "human", "humble", + "humor", "hundred", "hungry", "hunt", "hurdle", "hurry", + "hurt", "husband", "hybrid", "ice", "icon", "idea", + "identify", "idle", "ignore", "ill", "illegal", "illness", + "image", "imitate", "immense", "immune", "impact", "impose", + "improve", "impulse", "inch", "include", "income", "increase", + "index", "indicate", "indoor", "industry", "infant", "inflict", + "inform", "inhale", "inherit", "initial", "inject", "injury", + "inmate", "inner", "innocent", "input", "inquiry", "insane", + "insect", "inside", "inspire", "install", "intact", "interest", + "into", "invest", "invite", "involve", "iron", "island", + "isolate", "issue", "item", "ivory", "jacket", "jaguar", + "jar", "jazz", "jealous", "jeans", "jelly", "jewel", + "job", "join", "joke", "journey", "joy", "judge", + "juice", "jump", "jungle", "junior", "junk", "just", + "kangaroo", "keen", "keep", "ketchup", "key", "kick", + "kid", "kidney", "kind", "kingdom", "kiss", "kit", + "kitchen", "kite", "kitten", "kiwi", "knee", "knife", + "knock", "know", "lab", "label", "labor", "ladder", + "lady", "lake", "lamp", "language", "laptop", "large", + "later", "latin", "laugh", "laundry", "lava", "law", + "lawn", "lawsuit", "layer", "lazy", "leader", "leaf", + "learn", "leave", "lecture", "left", "leg", "legal", + "legend", "leisure", "lemon", "lend", "length", "lens", + "leopard", "lesson", "letter", "level", "liar", "liberty", + "library", "license", "life", "lift", "light", "like", + "limb", "limit", "link", "lion", "liquid", "list", + "little", "live", "lizard", "load", "loan", "lobster", + "local", "lock", "logic", "lonely", "long", "loop", + "lottery", "loud", "lounge", "love", "loyal", "lucky", + "luggage", "lumber", "lunar", "lunch", "luxury", "lyrics", + "machine", "mad", "magic", "magnet", "maid", "mail", + "main", "major", "make", "mammal", "man", "manage", + "mandate", "mango", "mansion", "manual", "maple", "marble", + "march", "margin", "marine", "market", "marriage", "mask", + "mass", "master", "match", "material", "math", "matrix", + "matter", "maximum", "maze", "meadow", "mean", "measure", + "meat", "mechanic", "medal", "media", "melody", "melt", + "member", "memory", "mention", "menu", "mercy", "merge", + "merit", "merry", "mesh", "message", "metal", "method", + "middle", "midnight", "milk", "million", "mimic", "mind", + "minimum", "minor", "minute", "miracle", "mirror", "misery", + "miss", "mistake", "mix", "mixed", "mixture", "mobile", + "model", "modify", "mom", "moment", "monitor", "monkey", + "monster", "month", "moon", "moral", "more", "morning", + "mosquito", "mother", "motion", "motor", "mountain", "mouse", + "move", "movie", "much", "muffin", "mule", "multiply", + "muscle", "museum", "mushroom", "music", "must", "mutual", + "myself", "mystery", "myth", "naive", "name", "napkin", + "narrow", "nasty", "nation", "nature", "near", "neck", + "need", "negative", "neglect", "neither", "nephew", "nerve", + "nest", "net", "network", "neutral", "never", "news", + "next", "nice", "night", "noble", "noise", "nominee", + "noodle", "normal", "north", "nose", "notable", "note", + "nothing", "notice", "novel", "now", "nuclear", "number", + "nurse", "nut", "oak", "obey", "object", "oblige", + "obscure", "observe", "obtain", "obvious", "occur", "ocean", + "october", "odor", "off", "offer", "office", "often", + "oil", "okay", "old", "olive", "olympic", "omit", + "once", "one", "onion", "online", "only", "open", + "opera", "opinion", "oppose", "option", "orange", "orbit", + "orchard", "order", "ordinary", "organ", "orient", "original", + "orphan", "ostrich", "other", "outdoor", "outer", "output", + "outside", "oval", "oven", "over", "own", "owner", + "oxygen", "oyster", "ozone", "pact", "paddle", "page", + "pair", "palace", "palm", "panda", "panel", "panic", + "panther", "paper", "parade", "parent", "park", "parrot", + "party", "pass", "patch", "path", "patient", "patrol", + "pattern", "pause", "pave", "payment", "peace", "peanut", + "pear", "peasant", "pelican", "pen", "penalty", "pencil", + "people", "pepper", "perfect", "permit", "person", "pet", + "phone", "photo", "phrase", "physical", "piano", "picnic", + "picture", "piece", "pig", "pigeon", "pill", "pilot", + "pink", "pioneer", "pipe", "pistol", "pitch", "pizza", + "place", "planet", "plastic", "plate", "play", "please", + "pledge", "pluck", "plug", "plunge", "poem", "poet", + "point", "polar", "pole", "police", "pond", "pony", + "pool", "popular", "portion", "position", "possible", "post", + "potato", "pottery", "poverty", "powder", "power", "practice", + "praise", "predict", "prefer", "prepare", "present", "pretty", + "prevent", "price", "pride", "primary", "print", "priority", + "prison", "private", "prize", "problem", "process", "produce", + "profit", "program", "project", "promote", "proof", "property", + "prosper", "protect", "proud", "provide", "public", "pudding", + "pull", "pulp", "pulse", "pumpkin", "punch", "pupil", + "puppy", "purchase", "purity", "purpose", "purse", "push", + "put", "puzzle", "pyramid", "quality", "quantum", "quarter", + "question", "quick", "quit", "quiz", "quote", "rabbit", + "raccoon", "race", "rack", "radar", "radio", "rail", + "rain", "raise", "rally", "ramp", "ranch", "random", + "range", "rapid", "rare", "rate", "rather", "raven", + "raw", "razor", "ready", "real", "reason", "rebel", + "rebuild", "recall", "receive", "recipe", "record", "recycle", + "reduce", "reflect", "reform", "refuse", "region", "regret", + "regular", "reject", "relax", "release", "relief", "rely", + "remain", "remember", "remind", "remove", "render", "renew", + "rent", "reopen", "repair", "repeat", "replace", "report", + "require", "rescue", "resemble", "resist", "resource", "response", + "result", "retire", "retreat", "return", "reunion", "reveal", + "review", "reward", "rhythm", "rib", "ribbon", "rice", + "rich", "ride", "ridge", "rifle", "right", "rigid", + "ring", "riot", "ripple", "risk", "ritual", "rival", + "river", "road", "roast", "robot", "robust", "rocket", + "romance", "roof", "rookie", "room", "rose", "rotate", + "rough", "round", "route", "royal", "rubber", "rude", + "rug", "rule", "run", "runway", "rural", "sad", + "saddle", "sadness", "safe", "sail", "salad", "salmon", + "salon", "salt", "salute", "same", "sample", "sand", + "satisfy", "satoshi", "sauce", "sausage", "save", "say", + "scale", "scan", "scare", "scatter", "scene", "scheme", + "school", "science", "scissors", "scorpion", "scout", "scrap", + "screen", "script", "scrub", "sea", "search", "season", + "seat", "second", "secret", "section", "security", "seed", + "seek", "segment", "select", "sell", "seminar", "senior", + "sense", "sentence", "series", "service", "session", "settle", + "setup", "seven", "shadow", "shaft", "shallow", "share", + "shed", "shell", "sheriff", "shield", "shift", "shine", + "ship", "shiver", "shock", "shoe", "shoot", "shop", + "short", "shoulder", "shove", "shrimp", "shrug", "shuffle", + "shy", "sibling", "sick", "side", "siege", "sight", + "sign", "silent", "silk", "silly", "silver", "similar", + "simple", "since", "sing", "siren", "sister", "situate", + "six", "size", "skate", "sketch", "ski", "skill", + "skin", "skirt", "skull", "slab", "slam", "sleep", + "slender", "slice", "slide", "slight", "slim", "slogan", + "slot", "slow", "slush", "small", "smart", "smile", + "smoke", "smooth", "snack", "snake", "snap", "sniff", + "snow", "soap", "soccer", "social", "sock", "soda", + "soft", "solar", "soldier", "solid", "solution", "solve", + "someone", "song", "soon", "sorry", "sort", "soul", + "sound", "soup", "source", "south", "space", "spare", + "spatial", "spawn", "speak", "special", "speed", "spell", + "spend", "sphere", "spice", "spider", "spike", "spin", + "spirit", "split", "spoil", "sponsor", "spoon", "sport", + "spot", "spray", "spread", "spring", "spy", "square", + "squeeze", "squirrel", "stable", "stadium", "staff", "stage", + "stairs", "stamp", "stand", "start", "state", "stay", + "steak", "steel", "stem", "step", "stereo", "stick", + "still", "sting", "stock", "stomach", "stone", "stool", + "story", "stove", "strategy", "street", "strike", "strong", + "struggle", "student", "stuff", "stumble", "style", "subject", + "submit", "subway", "success", "such", "sudden", "suffer", + "sugar", "suggest", "suit", "summer", "sun", "sunny", + "sunset", "super", "supply", "supreme", "sure", "surface", + "surge", "surprise", "surround", "survey", "suspect", "sustain", + "swallow", "swamp", "swap", "swarm", "swear", "sweet", + "swift", "swim", "swing", "switch", "sword", "symbol", + "symptom", "syrup", "system", "table", "tackle", "tag", + "tail", "talent", "talk", "tank", "tape", "target", + "task", "taste", "tattoo", "taxi", "teach", "team", + "tell", "ten", "tenant", "tennis", "tent", "term", + "test", "text", "thank", "that", "theme", "then", + "theory", "there", "they", "thing", "this", "thought", + "three", "thrive", "throw", "thumb", "thunder", "ticket", + "tide", "tiger", "tilt", "timber", "time", "tiny", + "tip", "tired", "tissue", "title", "toast", "tobacco", + "today", "toddler", "toe", "together", "toilet", "token", + "tomato", "tomorrow", "tone", "tongue", "tonight", "tool", + "tooth", "top", "topic", "topple", "torch", "tornado", + "tortoise", "toss", "total", "tourist", "toward", "tower", + "town", "toy", "track", "trade", "traffic", "tragic", + "train", "transfer", "trap", "trash", "travel", "tray", + "treat", "tree", "trend", "trial", "tribe", "trick", + "trigger", "trim", "trip", "trophy", "trouble", "truck", + "true", "truly", "trumpet", "trust", "truth", "try", + "tube", "tuition", "tumble", "tuna", "tunnel", "turkey", + "turn", "turtle", "twelve", "twenty", "twice", "twin", + "twist", "two", "type", "typical", "ugly", "umbrella", + "unable", "unaware", "uncle", "uncover", "under", "undo", + "unfair", "unfold", "unhappy", "uniform", "unique", "unit", + "universe", "unknown", "unlock", "until", "unusual", "unveil", + "update", "upgrade", "uphold", "upon", "upper", "upset", + "urban", "urge", "usage", "use", "used", "useful", + "useless", "usual", "utility", "vacant", "vacuum", "vague", + "valid", "valley", "valve", "van", "vanish", "vapor", + "various", "vast", "vault", "vehicle", "velvet", "vendor", + "venture", "venue", "verb", "verify", "version", "very", + "vessel", "veteran", "viable", "vibrant", "vicious", "victory", + "video", "view", "village", "vintage", "violin", "virtual", + "virus", "visa", "visit", "visual", "vital", "vivid", + "vocal", "voice", "void", "volcano", "volume", "vote", + "voyage", "wage", "wagon", "wait", "walk", "wall", + "walnut", "want", "warfare", "warm", "warrior", "wash", + "wasp", "waste", "water", "wave", "way", "wealth", + "weapon", "wear", "weasel", "weather", "web", "wedding", + "weekend", "weird", "welcome", "west", "wet", "whale", + "what", "wheat", "wheel", "when", "where", "whip", + "whisper", "wide", "width", "wife", "wild", "will", + "win", "window", "wine", "wing", "wink", "winner", + "winter", "wire", "wisdom", "wise", "wish", "witness", + "wolf", "woman", "wonder", "wood", "wool", "word", + "work", "world", "worry", "worth", "wrap", "wreck", + "wrestle", "wrist", "write", "wrong", "yard", "year", + "yellow", "you", "young", "youth", "zebra", "zero", + "zone", "zoo", 0, }; diff --git a/blake2_common.h b/blake2_common.h index 40c6da3b5..0a7a3ad91 100644 --- a/blake2_common.h +++ b/blake2_common.h @@ -1,39 +1,25 @@ -static inline uint32_t load32( const void *src ) -{ - uint32_t w; - memcpy(&w, src, sizeof w); - return w; +static inline uint32_t load32(const void *src) { + uint32_t w; + memcpy(&w, src, sizeof w); + return w; } -static inline uint64_t load64( const void *src ) -{ +static inline uint64_t load64(const void *src) { uint64_t w; memcpy(&w, src, sizeof w); return w; } -static inline void store16( void *dst, uint16_t w ) -{ - memcpy(dst, &w, sizeof w); -} +static inline void store16(void *dst, uint16_t w) { memcpy(dst, &w, sizeof w); } -static inline void store32( void *dst, uint32_t w ) -{ - memcpy(dst, &w, sizeof w); -} +static inline void store32(void *dst, uint32_t w) { memcpy(dst, &w, sizeof w); } -static inline void store64( void *dst, uint64_t w ) -{ - memcpy(dst, &w, sizeof w); -} +static inline void store64(void *dst, uint64_t w) { memcpy(dst, &w, sizeof w); } -static inline uint32_t rotr32( const uint32_t w, const unsigned c ) -{ - return ( w >> c ) | ( w << ( 32 - c ) ); +static inline uint32_t rotr32(const uint32_t w, const unsigned c) { + return (w >> c) | (w << (32 - c)); } -static inline uint64_t rotr64( const uint64_t w, const unsigned c ) -{ - return ( w >> c ) | ( w << ( 64 - c ) ); +static inline uint64_t rotr64(const uint64_t w, const unsigned c) { + return (w >> c) | (w << (64 - c)); } - diff --git a/cash_addr.c b/cash_addr.c index 0d7948a3b..4617cf7c6 100644 --- a/cash_addr.c +++ b/cash_addr.c @@ -19,8 +19,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include #include +#include #include #include "cash_addr.h" @@ -32,156 +32,158 @@ #define CHECKSUM_SIZE 8 uint64_t cashaddr_polymod_step(uint64_t pre) { - uint8_t b = pre >> 35; - return ((pre & 0x7FFFFFFFFULL) << 5) ^ - (-((b >> 0) & 1) & 0x98f2bc8e61ULL) ^ - (-((b >> 1) & 1) & 0x79b76d99e2ULL) ^ - (-((b >> 2) & 1) & 0xf33e5fb3c4ULL) ^ - (-((b >> 3) & 1) & 0xae2eabe2a8ULL) ^ - (-((b >> 4) & 1) & 0x1e4f43e470ULL); + uint8_t b = pre >> 35; + return ((pre & 0x7FFFFFFFFULL) << 5) ^ (-((b >> 0) & 1) & 0x98f2bc8e61ULL) ^ + (-((b >> 1) & 1) & 0x79b76d99e2ULL) ^ + (-((b >> 2) & 1) & 0xf33e5fb3c4ULL) ^ + (-((b >> 3) & 1) & 0xae2eabe2a8ULL) ^ + (-((b >> 4) & 1) & 0x1e4f43e470ULL); } static const char* charset = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"; static const int8_t charset_rev[128] = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 15, -1, 10, 17, 21, 20, 26, 30, 7, 5, -1, -1, -1, -1, -1, -1, - -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1, - 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1, - -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1, - 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1 -}; + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 15, -1, 10, 17, 21, 20, 26, 30, 7, + 5, -1, -1, -1, -1, -1, -1, -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, + 31, 27, 19, -1, 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, + -1, -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1, 1, 0, + 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1}; -int cash_encode(char *output, const char *hrp, const uint8_t *data, size_t data_len) { - uint64_t chk = 1; - size_t i = 0; - while (hrp[i] != 0) { - int ch = hrp[i]; - if (ch < 33 || ch > 126) { - return 0; - } - *(output++) = ch; - chk = cashaddr_polymod_step(chk) ^ (ch & 0x1f); - ++i; - } - if (i + 1 + data_len + CHECKSUM_SIZE > MAX_CASHADDR_SIZE) { - return 0; +int cash_encode(char* output, const char* hrp, const uint8_t* data, + size_t data_len) { + uint64_t chk = 1; + size_t i = 0; + while (hrp[i] != 0) { + int ch = hrp[i]; + if (ch < 33 || ch > 126) { + return 0; } + *(output++) = ch; + chk = cashaddr_polymod_step(chk) ^ (ch & 0x1f); + ++i; + } + if (i + 1 + data_len + CHECKSUM_SIZE > MAX_CASHADDR_SIZE) { + return 0; + } + chk = cashaddr_polymod_step(chk); + *(output++) = ':'; + for (i = 0; i < data_len; ++i) { + if (*data >> 5) return 0; + chk = cashaddr_polymod_step(chk) ^ (*data); + *(output++) = charset[*(data++)]; + } + for (i = 0; i < CHECKSUM_SIZE; ++i) { chk = cashaddr_polymod_step(chk); - *(output++) = ':'; - for (i = 0; i < data_len; ++i) { - if (*data >> 5) return 0; - chk = cashaddr_polymod_step(chk) ^ (*data); - *(output++) = charset[*(data++)]; - } - for (i = 0; i < CHECKSUM_SIZE; ++i) { - chk = cashaddr_polymod_step(chk); - } - chk ^= 1; - for (i = 0; i < CHECKSUM_SIZE; ++i) { - *(output++) = charset[(chk >> ((CHECKSUM_SIZE - 1 - i) * 5)) & 0x1f]; - } - *output = 0; - return 1; + } + chk ^= 1; + for (i = 0; i < CHECKSUM_SIZE; ++i) { + *(output++) = charset[(chk >> ((CHECKSUM_SIZE - 1 - i) * 5)) & 0x1f]; + } + *output = 0; + return 1; } -int cash_decode(char* hrp, uint8_t *data, size_t *data_len, const char *input) { - uint64_t chk = 1; - size_t i; - size_t input_len = strlen(input); - size_t hrp_len; - int have_lower = 0, have_upper = 0; - if (input_len < CHECKSUM_SIZE || input_len > MAX_CASHADDR_SIZE) { - return 0; +int cash_decode(char* hrp, uint8_t* data, size_t* data_len, const char* input) { + uint64_t chk = 1; + size_t i; + size_t input_len = strlen(input); + size_t hrp_len; + int have_lower = 0, have_upper = 0; + if (input_len < CHECKSUM_SIZE || input_len > MAX_CASHADDR_SIZE) { + return 0; + } + *data_len = 0; + while (*data_len < input_len && input[(input_len - 1) - *data_len] != ':') { + ++(*data_len); + } + hrp_len = input_len - (1 + *data_len); + if (1 + *data_len >= input_len || hrp_len > MAX_HRP_SIZE || + *data_len < CHECKSUM_SIZE || + *data_len > CHECKSUM_SIZE + MAX_BASE32_SIZE) { + return 0; + } + // subtract checksum + *(data_len) -= CHECKSUM_SIZE; + for (i = 0; i < hrp_len; ++i) { + int ch = input[i]; + if (ch < 33 || ch > 126) { + return 0; } - *data_len = 0; - while (*data_len < input_len && input[(input_len - 1) - *data_len] != ':') { - ++(*data_len); + if (ch >= 'a' && ch <= 'z') { + have_lower = 1; + } else if (ch >= 'A' && ch <= 'Z') { + have_upper = 1; + ch = (ch - 'A') + 'a'; } - hrp_len = input_len - (1 + *data_len); - if (1 + *data_len >= input_len || hrp_len > MAX_HRP_SIZE || - *data_len < CHECKSUM_SIZE || *data_len > CHECKSUM_SIZE + MAX_BASE32_SIZE) { - return 0; + hrp[i] = ch; + chk = cashaddr_polymod_step(chk) ^ (ch & 0x1f); + } + hrp[i] = 0; + chk = cashaddr_polymod_step(chk); + ++i; + while (i < input_len) { + int v = (input[i] & 0x80) ? -1 : charset_rev[(int)input[i]]; + if (input[i] >= 'a' && input[i] <= 'z') have_lower = 1; + if (input[i] >= 'A' && input[i] <= 'Z') have_upper = 1; + if (v == -1) { + return 0; } - // subtract checksum - *(data_len) -= CHECKSUM_SIZE; - for (i = 0; i < hrp_len; ++i) { - int ch = input[i]; - if (ch < 33 || ch > 126) { - return 0; - } - if (ch >= 'a' && ch <= 'z') { - have_lower = 1; - } else if (ch >= 'A' && ch <= 'Z') { - have_upper = 1; - ch = (ch - 'A') + 'a'; - } - hrp[i] = ch; - chk = cashaddr_polymod_step(chk) ^ (ch & 0x1f); + chk = cashaddr_polymod_step(chk) ^ v; + if (i + CHECKSUM_SIZE < input_len) { + data[i - (1 + hrp_len)] = v; } - hrp[i] = 0; - chk = cashaddr_polymod_step(chk); ++i; - while (i < input_len) { - int v = (input[i] & 0x80) ? -1 : charset_rev[(int)input[i]]; - if (input[i] >= 'a' && input[i] <= 'z') have_lower = 1; - if (input[i] >= 'A' && input[i] <= 'Z') have_upper = 1; - if (v == -1) { - return 0; - } - chk = cashaddr_polymod_step(chk) ^ v; - if (i + CHECKSUM_SIZE < input_len) { - data[i - (1 + hrp_len)] = v; - } - ++i; - } - if (have_lower && have_upper) { - return 0; - } - return chk == 1; + } + if (have_lower && have_upper) { + return 0; + } + return chk == 1; } -static int convert_bits(uint8_t* out, size_t* outlen, int outbits, const uint8_t* in, size_t inlen, int inbits, int pad) { - uint32_t val = 0; - int bits = 0; - uint32_t maxv = (((uint32_t)1) << outbits) - 1; - while (inlen--) { - val = (val << inbits) | *(in++); - bits += inbits; - while (bits >= outbits) { - bits -= outbits; - out[(*outlen)++] = (val >> bits) & maxv; - } +static int convert_bits(uint8_t* out, size_t* outlen, int outbits, + const uint8_t* in, size_t inlen, int inbits, int pad) { + uint32_t val = 0; + int bits = 0; + uint32_t maxv = (((uint32_t)1) << outbits) - 1; + while (inlen--) { + val = (val << inbits) | *(in++); + bits += inbits; + while (bits >= outbits) { + bits -= outbits; + out[(*outlen)++] = (val >> bits) & maxv; } - if (pad) { - if (bits) { - out[(*outlen)++] = (val << (outbits - bits)) & maxv; - } - } else if (((val << (outbits - bits)) & maxv) || bits >= inbits) { - return 0; + } + if (pad) { + if (bits) { + out[(*outlen)++] = (val << (outbits - bits)) & maxv; } - return 1; + } else if (((val << (outbits - bits)) & maxv) || bits >= inbits) { + return 0; + } + return 1; } -int cash_addr_encode(char *output, const char *hrp, const uint8_t *data, size_t data_len) { - uint8_t base32[MAX_BASE32_SIZE]; - size_t base32len = 0; - if (data_len < 2 || data_len > MAX_DATA_SIZE) return 0; - convert_bits(base32, &base32len, 5, data, data_len, 8, 1); - return cash_encode(output, hrp, base32, base32len); +int cash_addr_encode(char* output, const char* hrp, const uint8_t* data, + size_t data_len) { + uint8_t base32[MAX_BASE32_SIZE]; + size_t base32len = 0; + if (data_len < 2 || data_len > MAX_DATA_SIZE) return 0; + convert_bits(base32, &base32len, 5, data, data_len, 8, 1); + return cash_encode(output, hrp, base32, base32len); } -int cash_addr_decode(uint8_t* witdata, size_t* witdata_len, const char* hrp, const char* addr) { - uint8_t data[MAX_BASE32_SIZE]; - char hrp_actual[MAX_HRP_SIZE+1]; - size_t data_len; - if (!cash_decode(hrp_actual, data, &data_len, addr)) return 0; - if (data_len == 0 || data_len > MAX_BASE32_SIZE) return 0; - if (strncmp(hrp, hrp_actual, MAX_HRP_SIZE + 1) != 0) return 0; - *witdata_len = 0; - if (!convert_bits(witdata, witdata_len, 8, data, data_len, 5, 0)) return 0; - if (*witdata_len < 2 || *witdata_len > MAX_DATA_SIZE) return 0; - return 1; +int cash_addr_decode(uint8_t* witdata, size_t* witdata_len, const char* hrp, + const char* addr) { + uint8_t data[MAX_BASE32_SIZE]; + char hrp_actual[MAX_HRP_SIZE + 1]; + size_t data_len; + if (!cash_decode(hrp_actual, data, &data_len, addr)) return 0; + if (data_len == 0 || data_len > MAX_BASE32_SIZE) return 0; + if (strncmp(hrp, hrp_actual, MAX_HRP_SIZE + 1) != 0) return 0; + *witdata_len = 0; + if (!convert_bits(witdata, witdata_len, 8, data, data_len, 5, 0)) return 0; + if (*witdata_len < 2 || *witdata_len > MAX_DATA_SIZE) return 0; + return 1; } diff --git a/cash_addr.h b/cash_addr.h index e88e76dd9..fd7dd44f8 100644 --- a/cash_addr.h +++ b/cash_addr.h @@ -34,30 +34,20 @@ * prog_len: Number of data bytes in prog. * Returns 1 if successful. */ -int cash_addr_encode( - char *output, - const char *hrp, - const uint8_t *prog, - size_t prog_len -); +int cash_addr_encode(char *output, const char *hrp, const uint8_t *prog, + size_t prog_len); /** Decode a CashAddr address * * Out: prog: Pointer to a buffer of size 65 that will be updated to * contain the witness program bytes. - * prog_len: Pointer to a size_t that will be updated to contain the length - * of bytes in prog. - * hrp: Pointer to the null-terminated human readable part that is - * expected (chain/network specific). - * addr: Pointer to the null-terminated address. - * Returns 1 if successful. + * prog_len: Pointer to a size_t that will be updated to contain the + * length of bytes in prog. hrp: Pointer to the null-terminated human + * readable part that is expected (chain/network specific). addr: Pointer to + * the null-terminated address. Returns 1 if successful. */ -int cash_addr_decode( - uint8_t* prog, - size_t* prog_len, - const char* hrp, - const char* addr -); +int cash_addr_decode(uint8_t *prog, size_t *prog_len, const char *hrp, + const char *addr); /** Encode a Cash string * @@ -68,12 +58,8 @@ int cash_addr_decode( * data_len: Length of the data array. * Returns 1 if successful. */ -int cash_encode( - char *output, - const char *hrp, - const uint8_t *data, - size_t data_len -); +int cash_encode(char *output, const char *hrp, const uint8_t *data, + size_t data_len); /** Decode a Cash string * @@ -86,11 +72,6 @@ int cash_encode( * In: input: Pointer to a null-terminated Cash string. * Returns 1 if succesful. */ -int cash_decode( - char *hrp, - uint8_t *data, - size_t *data_len, - const char *input -); +int cash_decode(char *hrp, uint8_t *data, size_t *data_len, const char *input); #endif diff --git a/ecdsa.c b/ecdsa.c index c0717902a..f566cdd97 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -22,705 +22,698 @@ * OTHER DEALINGS IN THE SOFTWARE. */ +#include #include #include #include -#include #include "address.h" +#include "base58.h" #include "bignum.h" -#include "rand.h" -#include "hmac.h" #include "ecdsa.h" -#include "base58.h" -#include "secp256k1.h" -#include "rfc6979.h" +#include "hmac.h" #include "memzero.h" +#include "rand.h" +#include "rfc6979.h" +#include "secp256k1.h" // Set cp2 = cp1 -void point_copy(const curve_point *cp1, curve_point *cp2) -{ - *cp2 = *cp1; -} +void point_copy(const curve_point *cp1, curve_point *cp2) { *cp2 = *cp1; } // cp2 = cp1 + cp2 -void point_add(const ecdsa_curve *curve, const curve_point *cp1, curve_point *cp2) -{ - bignum256 lambda, inv, xr, yr; - - if (point_is_infinity(cp1)) { - return; - } - if (point_is_infinity(cp2)) { - point_copy(cp1, cp2); - return; - } - if (point_is_equal(cp1, cp2)) { - point_double(curve, cp2); - return; - } - if (point_is_negative_of(cp1, cp2)) { - point_set_infinity(cp2); - return; - } - - bn_subtractmod(&(cp2->x), &(cp1->x), &inv, &curve->prime); - bn_inverse(&inv, &curve->prime); - bn_subtractmod(&(cp2->y), &(cp1->y), &lambda, &curve->prime); - bn_multiply(&inv, &lambda, &curve->prime); - - // xr = lambda^2 - x1 - x2 - xr = lambda; - bn_multiply(&xr, &xr, &curve->prime); - yr = cp1->x; - bn_addmod(&yr, &(cp2->x), &curve->prime); - bn_subtractmod(&xr, &yr, &xr, &curve->prime); - bn_fast_mod(&xr, &curve->prime); - bn_mod(&xr, &curve->prime); - - // yr = lambda (x1 - xr) - y1 - bn_subtractmod(&(cp1->x), &xr, &yr, &curve->prime); - bn_multiply(&lambda, &yr, &curve->prime); - bn_subtractmod(&yr, &(cp1->y), &yr, &curve->prime); - bn_fast_mod(&yr, &curve->prime); - bn_mod(&yr, &curve->prime); - - cp2->x = xr; - cp2->y = yr; +void point_add(const ecdsa_curve *curve, const curve_point *cp1, + curve_point *cp2) { + bignum256 lambda, inv, xr, yr; + + if (point_is_infinity(cp1)) { + return; + } + if (point_is_infinity(cp2)) { + point_copy(cp1, cp2); + return; + } + if (point_is_equal(cp1, cp2)) { + point_double(curve, cp2); + return; + } + if (point_is_negative_of(cp1, cp2)) { + point_set_infinity(cp2); + return; + } + + bn_subtractmod(&(cp2->x), &(cp1->x), &inv, &curve->prime); + bn_inverse(&inv, &curve->prime); + bn_subtractmod(&(cp2->y), &(cp1->y), &lambda, &curve->prime); + bn_multiply(&inv, &lambda, &curve->prime); + + // xr = lambda^2 - x1 - x2 + xr = lambda; + bn_multiply(&xr, &xr, &curve->prime); + yr = cp1->x; + bn_addmod(&yr, &(cp2->x), &curve->prime); + bn_subtractmod(&xr, &yr, &xr, &curve->prime); + bn_fast_mod(&xr, &curve->prime); + bn_mod(&xr, &curve->prime); + + // yr = lambda (x1 - xr) - y1 + bn_subtractmod(&(cp1->x), &xr, &yr, &curve->prime); + bn_multiply(&lambda, &yr, &curve->prime); + bn_subtractmod(&yr, &(cp1->y), &yr, &curve->prime); + bn_fast_mod(&yr, &curve->prime); + bn_mod(&yr, &curve->prime); + + cp2->x = xr; + cp2->y = yr; } // cp = cp + cp -void point_double(const ecdsa_curve *curve, curve_point *cp) -{ - bignum256 lambda, xr, yr; - - if (point_is_infinity(cp)) { - return; - } - if (bn_is_zero(&(cp->y))) { - point_set_infinity(cp); - return; - } - - // lambda = (3 x^2 + a) / (2 y) - lambda = cp->y; - bn_mult_k(&lambda, 2, &curve->prime); - bn_inverse(&lambda, &curve->prime); - - xr = cp->x; - bn_multiply(&xr, &xr, &curve->prime); - bn_mult_k(&xr, 3, &curve->prime); - bn_subi(&xr, -curve->a, &curve->prime); - bn_multiply(&xr, &lambda, &curve->prime); - - // xr = lambda^2 - 2*x - xr = lambda; - bn_multiply(&xr, &xr, &curve->prime); - yr = cp->x; - bn_lshift(&yr); - bn_subtractmod(&xr, &yr, &xr, &curve->prime); - bn_fast_mod(&xr, &curve->prime); - bn_mod(&xr, &curve->prime); - - // yr = lambda (x - xr) - y - bn_subtractmod(&(cp->x), &xr, &yr, &curve->prime); - bn_multiply(&lambda, &yr, &curve->prime); - bn_subtractmod(&yr, &(cp->y), &yr, &curve->prime); - bn_fast_mod(&yr, &curve->prime); - bn_mod(&yr, &curve->prime); - - cp->x = xr; - cp->y = yr; +void point_double(const ecdsa_curve *curve, curve_point *cp) { + bignum256 lambda, xr, yr; + + if (point_is_infinity(cp)) { + return; + } + if (bn_is_zero(&(cp->y))) { + point_set_infinity(cp); + return; + } + + // lambda = (3 x^2 + a) / (2 y) + lambda = cp->y; + bn_mult_k(&lambda, 2, &curve->prime); + bn_inverse(&lambda, &curve->prime); + + xr = cp->x; + bn_multiply(&xr, &xr, &curve->prime); + bn_mult_k(&xr, 3, &curve->prime); + bn_subi(&xr, -curve->a, &curve->prime); + bn_multiply(&xr, &lambda, &curve->prime); + + // xr = lambda^2 - 2*x + xr = lambda; + bn_multiply(&xr, &xr, &curve->prime); + yr = cp->x; + bn_lshift(&yr); + bn_subtractmod(&xr, &yr, &xr, &curve->prime); + bn_fast_mod(&xr, &curve->prime); + bn_mod(&xr, &curve->prime); + + // yr = lambda (x - xr) - y + bn_subtractmod(&(cp->x), &xr, &yr, &curve->prime); + bn_multiply(&lambda, &yr, &curve->prime); + bn_subtractmod(&yr, &(cp->y), &yr, &curve->prime); + bn_fast_mod(&yr, &curve->prime); + bn_mod(&yr, &curve->prime); + + cp->x = xr; + cp->y = yr; } // set point to internal representation of point at infinity -void point_set_infinity(curve_point *p) -{ - bn_zero(&(p->x)); - bn_zero(&(p->y)); +void point_set_infinity(curve_point *p) { + bn_zero(&(p->x)); + bn_zero(&(p->y)); } // return true iff p represent point at infinity // both coords are zero in internal representation -int point_is_infinity(const curve_point *p) -{ - return bn_is_zero(&(p->x)) && bn_is_zero(&(p->y)); +int point_is_infinity(const curve_point *p) { + return bn_is_zero(&(p->x)) && bn_is_zero(&(p->y)); } // return true iff both points are equal -int point_is_equal(const curve_point *p, const curve_point *q) -{ - return bn_is_equal(&(p->x), &(q->x)) && bn_is_equal(&(p->y), &(q->y)); +int point_is_equal(const curve_point *p, const curve_point *q) { + return bn_is_equal(&(p->x), &(q->x)) && bn_is_equal(&(p->y), &(q->y)); } // returns true iff p == -q // expects p and q be valid points on curve other than point at infinity -int point_is_negative_of(const curve_point *p, const curve_point *q) -{ - // if P == (x, y), then -P would be (x, -y) on this curve - if (!bn_is_equal(&(p->x), &(q->x))) { - return 0; - } - - // we shouldn't hit this for a valid point - if (bn_is_zero(&(p->y))) { - return 0; - } - - return !bn_is_equal(&(p->y), &(q->y)); +int point_is_negative_of(const curve_point *p, const curve_point *q) { + // if P == (x, y), then -P would be (x, -y) on this curve + if (!bn_is_equal(&(p->x), &(q->x))) { + return 0; + } + + // we shouldn't hit this for a valid point + if (bn_is_zero(&(p->y))) { + return 0; + } + + return !bn_is_equal(&(p->y), &(q->y)); } // Negate a (modulo prime) if cond is 0xffffffff, keep it if cond is 0. // The timing of this function does not depend on cond. -void conditional_negate(uint32_t cond, bignum256 *a, const bignum256 *prime) -{ - int j; - uint32_t tmp = 1; - assert(a->val[8] < 0x20000); - for (j = 0; j < 8; j++) { - tmp += 0x3fffffff + 2*prime->val[j] - a->val[j]; - a->val[j] = ((tmp & 0x3fffffff) & cond) | (a->val[j] & ~cond); - tmp >>= 30; - } - tmp += 0x3fffffff + 2*prime->val[j] - a->val[j]; - a->val[j] = ((tmp & 0x3fffffff) & cond) | (a->val[j] & ~cond); - assert(a->val[8] < 0x20000); +void conditional_negate(uint32_t cond, bignum256 *a, const bignum256 *prime) { + int j; + uint32_t tmp = 1; + assert(a->val[8] < 0x20000); + for (j = 0; j < 8; j++) { + tmp += 0x3fffffff + 2 * prime->val[j] - a->val[j]; + a->val[j] = ((tmp & 0x3fffffff) & cond) | (a->val[j] & ~cond); + tmp >>= 30; + } + tmp += 0x3fffffff + 2 * prime->val[j] - a->val[j]; + a->val[j] = ((tmp & 0x3fffffff) & cond) | (a->val[j] & ~cond); + assert(a->val[8] < 0x20000); } typedef struct jacobian_curve_point { - bignum256 x, y, z; + bignum256 x, y, z; } jacobian_curve_point; // generate random K for signing/side-channel noise static void generate_k_random(bignum256 *k, const bignum256 *prime) { - do { - int i; - for (i = 0; i < 8; i++) { - k->val[i] = random32() & 0x3FFFFFFF; - } - k->val[8] = random32() & 0xFFFF; - // check that k is in range and not zero. - } while (bn_is_zero(k) || !bn_is_less(k, prime)); + do { + int i; + for (i = 0; i < 8; i++) { + k->val[i] = random32() & 0x3FFFFFFF; + } + k->val[8] = random32() & 0xFFFF; + // check that k is in range and not zero. + } while (bn_is_zero(k) || !bn_is_less(k, prime)); } -void curve_to_jacobian(const curve_point *p, jacobian_curve_point *jp, const bignum256 *prime) { - // randomize z coordinate - generate_k_random(&jp->z, prime); +void curve_to_jacobian(const curve_point *p, jacobian_curve_point *jp, + const bignum256 *prime) { + // randomize z coordinate + generate_k_random(&jp->z, prime); - jp->x = jp->z; - bn_multiply(&jp->z, &jp->x, prime); - // x = z^2 - jp->y = jp->x; - bn_multiply(&jp->z, &jp->y, prime); - // y = z^3 + jp->x = jp->z; + bn_multiply(&jp->z, &jp->x, prime); + // x = z^2 + jp->y = jp->x; + bn_multiply(&jp->z, &jp->y, prime); + // y = z^3 - bn_multiply(&p->x, &jp->x, prime); - bn_multiply(&p->y, &jp->y, prime); + bn_multiply(&p->x, &jp->x, prime); + bn_multiply(&p->y, &jp->y, prime); } -void jacobian_to_curve(const jacobian_curve_point *jp, curve_point *p, const bignum256 *prime) { - p->y = jp->z; - bn_inverse(&p->y, prime); - // p->y = z^-1 - p->x = p->y; - bn_multiply(&p->x, &p->x, prime); - // p->x = z^-2 - bn_multiply(&p->x, &p->y, prime); - // p->y = z^-3 - bn_multiply(&jp->x, &p->x, prime); - // p->x = jp->x * z^-2 - bn_multiply(&jp->y, &p->y, prime); - // p->y = jp->y * z^-3 - bn_mod(&p->x, prime); - bn_mod(&p->y, prime); +void jacobian_to_curve(const jacobian_curve_point *jp, curve_point *p, + const bignum256 *prime) { + p->y = jp->z; + bn_inverse(&p->y, prime); + // p->y = z^-1 + p->x = p->y; + bn_multiply(&p->x, &p->x, prime); + // p->x = z^-2 + bn_multiply(&p->x, &p->y, prime); + // p->y = z^-3 + bn_multiply(&jp->x, &p->x, prime); + // p->x = jp->x * z^-2 + bn_multiply(&jp->y, &p->y, prime); + // p->y = jp->y * z^-3 + bn_mod(&p->x, prime); + bn_mod(&p->y, prime); } -void point_jacobian_add(const curve_point *p1, jacobian_curve_point *p2, const ecdsa_curve *curve) { - bignum256 r, h, r2; - bignum256 hcby, hsqx; - bignum256 xz, yz, az; - int is_doubling; - const bignum256 *prime = &curve->prime; - int a = curve->a; - - assert (-3 <= a && a <= 0); - - /* First we bring p1 to the same denominator: - * x1' := x1 * z2^2 - * y1' := y1 * z2^3 - */ - /* - * lambda = ((y1' - y2)/z2^3) / ((x1' - x2)/z2^2) - * = (y1' - y2) / (x1' - x2) z2 - * x3/z3^2 = lambda^2 - (x1' + x2)/z2^2 - * y3/z3^3 = 1/2 lambda * (2x3/z3^2 - (x1' + x2)/z2^2) + (y1'+y2)/z2^3 - * - * For the special case x1=x2, y1=y2 (doubling) we have - * lambda = 3/2 ((x2/z2^2)^2 + a) / (y2/z2^3) - * = 3/2 (x2^2 + a*z2^4) / y2*z2) - * - * to get rid of fraction we write lambda as - * lambda = r / (h*z2) - * with r = is_doubling ? 3/2 x2^2 + az2^4 : (y1 - y2) - * h = is_doubling ? y1+y2 : (x1 - x2) - * - * With z3 = h*z2 (the denominator of lambda) - * we get x3 = lambda^2*z3^2 - (x1' + x2)/z2^2*z3^2 - * = r^2 - h^2 * (x1' + x2) - * and y3 = 1/2 r * (2x3 - h^2*(x1' + x2)) + h^3*(y1' + y2) - */ - - /* h = x1 - x2 - * r = y1 - y2 - * x3 = r^2 - h^3 - 2*h^2*x2 - * y3 = r*(h^2*x2 - x3) - h^3*y2 - * z3 = h*z2 - */ - - xz = p2->z; - bn_multiply(&xz, &xz, prime); // xz = z2^2 - yz = p2->z; - bn_multiply(&xz, &yz, prime); // yz = z2^3 - - if (a != 0) { - az = xz; - bn_multiply(&az, &az, prime); // az = z2^4 - bn_mult_k(&az, -a, prime); // az = -az2^4 - } - - bn_multiply(&p1->x, &xz, prime); // xz = x1' = x1*z2^2; - h = xz; - bn_subtractmod(&h, &p2->x, &h, prime); - bn_fast_mod(&h, prime); - // h = x1' - x2; - - bn_add(&xz, &p2->x); - // xz = x1' + x2 - - // check for h == 0 % prime. Note that h never normalizes to - // zero, since h = x1' + 2*prime - x2 > 0 and a positive - // multiple of prime is always normalized to prime by - // bn_fast_mod. - is_doubling = bn_is_equal(&h, prime); - - bn_multiply(&p1->y, &yz, prime); // yz = y1' = y1*z2^3; - bn_subtractmod(&yz, &p2->y, &r, prime); - // r = y1' - y2; - - bn_add(&yz, &p2->y); - // yz = y1' + y2 - - r2 = p2->x; - bn_multiply(&r2, &r2, prime); - bn_mult_k(&r2, 3, prime); - - if (a != 0) { - // subtract -a z2^4, i.e, add a z2^4 - bn_subtractmod(&r2, &az, &r2, prime); - } - bn_cmov(&r, is_doubling, &r2, &r); - bn_cmov(&h, is_doubling, &yz, &h); - - - // hsqx = h^2 - hsqx = h; - bn_multiply(&hsqx, &hsqx, prime); - - // hcby = h^3 - hcby = h; - bn_multiply(&hsqx, &hcby, prime); - - // hsqx = h^2 * (x1 + x2) - bn_multiply(&xz, &hsqx, prime); - - // hcby = h^3 * (y1 + y2) - bn_multiply(&yz, &hcby, prime); - - // z3 = h*z2 - bn_multiply(&h, &p2->z, prime); - - // x3 = r^2 - h^2 (x1 + x2) - p2->x = r; - bn_multiply(&p2->x, &p2->x, prime); - bn_subtractmod(&p2->x, &hsqx, &p2->x, prime); - bn_fast_mod(&p2->x, prime); - - // y3 = 1/2 (r*(h^2 (x1 + x2) - 2x3) - h^3 (y1 + y2)) - bn_subtractmod(&hsqx, &p2->x, &p2->y, prime); - bn_subtractmod(&p2->y, &p2->x, &p2->y, prime); - bn_multiply(&r, &p2->y, prime); - bn_subtractmod(&p2->y, &hcby, &p2->y, prime); - bn_mult_half(&p2->y, prime); - bn_fast_mod(&p2->y, prime); +void point_jacobian_add(const curve_point *p1, jacobian_curve_point *p2, + const ecdsa_curve *curve) { + bignum256 r, h, r2; + bignum256 hcby, hsqx; + bignum256 xz, yz, az; + int is_doubling; + const bignum256 *prime = &curve->prime; + int a = curve->a; + + assert(-3 <= a && a <= 0); + + /* First we bring p1 to the same denominator: + * x1' := x1 * z2^2 + * y1' := y1 * z2^3 + */ + /* + * lambda = ((y1' - y2)/z2^3) / ((x1' - x2)/z2^2) + * = (y1' - y2) / (x1' - x2) z2 + * x3/z3^2 = lambda^2 - (x1' + x2)/z2^2 + * y3/z3^3 = 1/2 lambda * (2x3/z3^2 - (x1' + x2)/z2^2) + (y1'+y2)/z2^3 + * + * For the special case x1=x2, y1=y2 (doubling) we have + * lambda = 3/2 ((x2/z2^2)^2 + a) / (y2/z2^3) + * = 3/2 (x2^2 + a*z2^4) / y2*z2) + * + * to get rid of fraction we write lambda as + * lambda = r / (h*z2) + * with r = is_doubling ? 3/2 x2^2 + az2^4 : (y1 - y2) + * h = is_doubling ? y1+y2 : (x1 - x2) + * + * With z3 = h*z2 (the denominator of lambda) + * we get x3 = lambda^2*z3^2 - (x1' + x2)/z2^2*z3^2 + * = r^2 - h^2 * (x1' + x2) + * and y3 = 1/2 r * (2x3 - h^2*(x1' + x2)) + h^3*(y1' + y2) + */ + + /* h = x1 - x2 + * r = y1 - y2 + * x3 = r^2 - h^3 - 2*h^2*x2 + * y3 = r*(h^2*x2 - x3) - h^3*y2 + * z3 = h*z2 + */ + + xz = p2->z; + bn_multiply(&xz, &xz, prime); // xz = z2^2 + yz = p2->z; + bn_multiply(&xz, &yz, prime); // yz = z2^3 + + if (a != 0) { + az = xz; + bn_multiply(&az, &az, prime); // az = z2^4 + bn_mult_k(&az, -a, prime); // az = -az2^4 + } + + bn_multiply(&p1->x, &xz, prime); // xz = x1' = x1*z2^2; + h = xz; + bn_subtractmod(&h, &p2->x, &h, prime); + bn_fast_mod(&h, prime); + // h = x1' - x2; + + bn_add(&xz, &p2->x); + // xz = x1' + x2 + + // check for h == 0 % prime. Note that h never normalizes to + // zero, since h = x1' + 2*prime - x2 > 0 and a positive + // multiple of prime is always normalized to prime by + // bn_fast_mod. + is_doubling = bn_is_equal(&h, prime); + + bn_multiply(&p1->y, &yz, prime); // yz = y1' = y1*z2^3; + bn_subtractmod(&yz, &p2->y, &r, prime); + // r = y1' - y2; + + bn_add(&yz, &p2->y); + // yz = y1' + y2 + + r2 = p2->x; + bn_multiply(&r2, &r2, prime); + bn_mult_k(&r2, 3, prime); + + if (a != 0) { + // subtract -a z2^4, i.e, add a z2^4 + bn_subtractmod(&r2, &az, &r2, prime); + } + bn_cmov(&r, is_doubling, &r2, &r); + bn_cmov(&h, is_doubling, &yz, &h); + + // hsqx = h^2 + hsqx = h; + bn_multiply(&hsqx, &hsqx, prime); + + // hcby = h^3 + hcby = h; + bn_multiply(&hsqx, &hcby, prime); + + // hsqx = h^2 * (x1 + x2) + bn_multiply(&xz, &hsqx, prime); + + // hcby = h^3 * (y1 + y2) + bn_multiply(&yz, &hcby, prime); + + // z3 = h*z2 + bn_multiply(&h, &p2->z, prime); + + // x3 = r^2 - h^2 (x1 + x2) + p2->x = r; + bn_multiply(&p2->x, &p2->x, prime); + bn_subtractmod(&p2->x, &hsqx, &p2->x, prime); + bn_fast_mod(&p2->x, prime); + + // y3 = 1/2 (r*(h^2 (x1 + x2) - 2x3) - h^3 (y1 + y2)) + bn_subtractmod(&hsqx, &p2->x, &p2->y, prime); + bn_subtractmod(&p2->y, &p2->x, &p2->y, prime); + bn_multiply(&r, &p2->y, prime); + bn_subtractmod(&p2->y, &hcby, &p2->y, prime); + bn_mult_half(&p2->y, prime); + bn_fast_mod(&p2->y, prime); } void point_jacobian_double(jacobian_curve_point *p, const ecdsa_curve *curve) { - bignum256 az4, m, msq, ysq, xysq; - const bignum256 *prime = &curve->prime; - - assert (-3 <= curve->a && curve->a <= 0); - /* usual algorithm: - * - * lambda = (3((x/z^2)^2 + a) / 2y/z^3) = (3x^2 + az^4)/2yz - * x3/z3^2 = lambda^2 - 2x/z^2 - * y3/z3^3 = lambda * (x/z^2 - x3/z3^2) - y/z^3 - * - * to get rid of fraction we set - * m = (3 x^2 + az^4) / 2 - * Hence, - * lambda = m / yz = m / z3 - * - * With z3 = yz (the denominator of lambda) - * we get x3 = lambda^2*z3^2 - 2*x/z^2*z3^2 - * = m^2 - 2*xy^2 - * and y3 = (lambda * (x/z^2 - x3/z3^2) - y/z^3) * z3^3 - * = m * (xy^2 - x3) - y^4 - */ - - /* m = (3*x^2 + a z^4) / 2 - * x3 = m^2 - 2*xy^2 - * y3 = m*(xy^2 - x3) - 8y^4 - * z3 = y*z - */ - - m = p->x; - bn_multiply(&m, &m, prime); - bn_mult_k(&m, 3, prime); - - az4 = p->z; - bn_multiply(&az4, &az4, prime); - bn_multiply(&az4, &az4, prime); - bn_mult_k(&az4, -curve->a, prime); - bn_subtractmod(&m, &az4, &m, prime); - bn_mult_half(&m, prime); - - // msq = m^2 - msq = m; - bn_multiply(&msq, &msq, prime); - // ysq = y^2 - ysq = p->y; - bn_multiply(&ysq, &ysq, prime); - // xysq = xy^2 - xysq = p->x; - bn_multiply(&ysq, &xysq, prime); - - // z3 = yz - bn_multiply(&p->y, &p->z, prime); - - // x3 = m^2 - 2*xy^2 - p->x = xysq; - bn_lshift(&p->x); - bn_fast_mod(&p->x, prime); - bn_subtractmod(&msq, &p->x, &p->x, prime); - bn_fast_mod(&p->x, prime); - - // y3 = m*(xy^2 - x3) - y^4 - bn_subtractmod(&xysq, &p->x, &p->y, prime); - bn_multiply(&m, &p->y, prime); - bn_multiply(&ysq, &ysq, prime); - bn_subtractmod(&p->y, &ysq, &p->y, prime); - bn_fast_mod(&p->y, prime); + bignum256 az4, m, msq, ysq, xysq; + const bignum256 *prime = &curve->prime; + + assert(-3 <= curve->a && curve->a <= 0); + /* usual algorithm: + * + * lambda = (3((x/z^2)^2 + a) / 2y/z^3) = (3x^2 + az^4)/2yz + * x3/z3^2 = lambda^2 - 2x/z^2 + * y3/z3^3 = lambda * (x/z^2 - x3/z3^2) - y/z^3 + * + * to get rid of fraction we set + * m = (3 x^2 + az^4) / 2 + * Hence, + * lambda = m / yz = m / z3 + * + * With z3 = yz (the denominator of lambda) + * we get x3 = lambda^2*z3^2 - 2*x/z^2*z3^2 + * = m^2 - 2*xy^2 + * and y3 = (lambda * (x/z^2 - x3/z3^2) - y/z^3) * z3^3 + * = m * (xy^2 - x3) - y^4 + */ + + /* m = (3*x^2 + a z^4) / 2 + * x3 = m^2 - 2*xy^2 + * y3 = m*(xy^2 - x3) - 8y^4 + * z3 = y*z + */ + + m = p->x; + bn_multiply(&m, &m, prime); + bn_mult_k(&m, 3, prime); + + az4 = p->z; + bn_multiply(&az4, &az4, prime); + bn_multiply(&az4, &az4, prime); + bn_mult_k(&az4, -curve->a, prime); + bn_subtractmod(&m, &az4, &m, prime); + bn_mult_half(&m, prime); + + // msq = m^2 + msq = m; + bn_multiply(&msq, &msq, prime); + // ysq = y^2 + ysq = p->y; + bn_multiply(&ysq, &ysq, prime); + // xysq = xy^2 + xysq = p->x; + bn_multiply(&ysq, &xysq, prime); + + // z3 = yz + bn_multiply(&p->y, &p->z, prime); + + // x3 = m^2 - 2*xy^2 + p->x = xysq; + bn_lshift(&p->x); + bn_fast_mod(&p->x, prime); + bn_subtractmod(&msq, &p->x, &p->x, prime); + bn_fast_mod(&p->x, prime); + + // y3 = m*(xy^2 - x3) - y^4 + bn_subtractmod(&xysq, &p->x, &p->y, prime); + bn_multiply(&m, &p->y, prime); + bn_multiply(&ysq, &ysq, prime); + bn_subtractmod(&p->y, &ysq, &p->y, prime); + bn_fast_mod(&p->y, prime); } // res = k * p -void point_multiply(const ecdsa_curve *curve, const bignum256 *k, const curve_point *p, curve_point *res) -{ - // this algorithm is loosely based on - // Katsuyuki Okeya and Tsuyoshi Takagi, The Width-w NAF Method Provides - // Small Memory and Fast Elliptic Scalar Multiplications Secure against - // Side Channel Attacks. - assert (bn_is_less(k, &curve->order)); - - int i, j; - static CONFIDENTIAL bignum256 a; - uint32_t *aptr; - uint32_t abits; - int ashift; - uint32_t is_even = (k->val[0] & 1) - 1; - uint32_t bits, sign, nsign; - static CONFIDENTIAL jacobian_curve_point jres; - curve_point pmult[8]; - const bignum256 *prime = &curve->prime; - - // is_even = 0xffffffff if k is even, 0 otherwise. - - // add 2^256. - // make number odd: subtract curve->order if even - uint32_t tmp = 1; - uint32_t is_non_zero = 0; - for (j = 0; j < 8; j++) { - is_non_zero |= k->val[j]; - tmp += 0x3fffffff + k->val[j] - (curve->order.val[j] & is_even); - a.val[j] = tmp & 0x3fffffff; - tmp >>= 30; - } - is_non_zero |= k->val[j]; - a.val[j] = tmp + 0xffff + k->val[j] - (curve->order.val[j] & is_even); - assert((a.val[0] & 1) != 0); - - // special case 0*p: just return zero. We don't care about constant time. - if (!is_non_zero) { - point_set_infinity(res); - return; - } - - // Now a = k + 2^256 (mod curve->order) and a is odd. - // - // The idea is to bring the new a into the form. - // sum_{i=0..64} a[i] 16^i, where |a[i]| < 16 and a[i] is odd. - // a[0] is odd, since a is odd. If a[i] would be even, we can - // add 1 to it and subtract 16 from a[i-1]. Afterwards, - // a[64] = 1, which is the 2^256 that we added before. - // - // Since k = a - 2^256 (mod curve->order), we can compute - // k*p = sum_{i=0..63} a[i] 16^i * p - // - // We compute |a[i]| * p in advance for all possible - // values of |a[i]| * p. pmult[i] = (2*i+1) * p - // We compute p, 3*p, ..., 15*p and store it in the table pmult. - // store p^2 temporarily in pmult[7] - pmult[7] = *p; - point_double(curve, &pmult[7]); - // compute 3*p, etc by repeatedly adding p^2. - pmult[0] = *p; - for (i = 1; i < 8; i++) { - pmult[i] = pmult[7]; - point_add(curve, &pmult[i-1], &pmult[i]); - } - - // now compute res = sum_{i=0..63} a[i] * 16^i * p step by step, - // starting with i = 63. - // initialize jres = |a[63]| * p. - // Note that a[i] = a>>(4*i) & 0xf if (a&0x10) != 0 - // and - (16 - (a>>(4*i) & 0xf)) otherwise. We can compute this as - // ((a ^ (((a >> 4) & 1) - 1)) & 0xf) >> 1 - // since a is odd. - aptr = &a.val[8]; - abits = *aptr; - ashift = 12; - bits = abits >> ashift; - sign = (bits >> 4) - 1; - bits ^= sign; - bits &= 15; - curve_to_jacobian(&pmult[bits>>1], &jres, prime); - for (i = 62; i >= 0; i--) { - // sign = sign(a[i+1]) (0xffffffff for negative, 0 for positive) - // invariant jres = (-1)^sign sum_{j=i+1..63} (a[j] * 16^{j-i-1} * p) - // abits >> (ashift - 4) = lowbits(a >> (i*4)) - - point_jacobian_double(&jres, curve); - point_jacobian_double(&jres, curve); - point_jacobian_double(&jres, curve); - point_jacobian_double(&jres, curve); - - // get lowest 5 bits of a >> (i*4). - ashift -= 4; - if (ashift < 0) { - // the condition only depends on the iteration number and - // leaks no private information to a side-channel. - bits = abits << (-ashift); - abits = *(--aptr); - ashift += 30; - bits |= abits >> ashift; - } else { - bits = abits >> ashift; - } - bits &= 31; - nsign = (bits >> 4) - 1; - bits ^= nsign; - bits &= 15; - - // negate last result to make signs of this round and the - // last round equal. - conditional_negate(sign ^ nsign, &jres.z, prime); - - // add odd factor - point_jacobian_add(&pmult[bits >> 1], &jres, curve); - sign = nsign; - } - conditional_negate(sign, &jres.z, prime); - jacobian_to_curve(&jres, res, prime); - memzero(&a, sizeof(a)); - memzero(&jres, sizeof(jres)); +void point_multiply(const ecdsa_curve *curve, const bignum256 *k, + const curve_point *p, curve_point *res) { + // this algorithm is loosely based on + // Katsuyuki Okeya and Tsuyoshi Takagi, The Width-w NAF Method Provides + // Small Memory and Fast Elliptic Scalar Multiplications Secure against + // Side Channel Attacks. + assert(bn_is_less(k, &curve->order)); + + int i, j; + static CONFIDENTIAL bignum256 a; + uint32_t *aptr; + uint32_t abits; + int ashift; + uint32_t is_even = (k->val[0] & 1) - 1; + uint32_t bits, sign, nsign; + static CONFIDENTIAL jacobian_curve_point jres; + curve_point pmult[8]; + const bignum256 *prime = &curve->prime; + + // is_even = 0xffffffff if k is even, 0 otherwise. + + // add 2^256. + // make number odd: subtract curve->order if even + uint32_t tmp = 1; + uint32_t is_non_zero = 0; + for (j = 0; j < 8; j++) { + is_non_zero |= k->val[j]; + tmp += 0x3fffffff + k->val[j] - (curve->order.val[j] & is_even); + a.val[j] = tmp & 0x3fffffff; + tmp >>= 30; + } + is_non_zero |= k->val[j]; + a.val[j] = tmp + 0xffff + k->val[j] - (curve->order.val[j] & is_even); + assert((a.val[0] & 1) != 0); + + // special case 0*p: just return zero. We don't care about constant time. + if (!is_non_zero) { + point_set_infinity(res); + return; + } + + // Now a = k + 2^256 (mod curve->order) and a is odd. + // + // The idea is to bring the new a into the form. + // sum_{i=0..64} a[i] 16^i, where |a[i]| < 16 and a[i] is odd. + // a[0] is odd, since a is odd. If a[i] would be even, we can + // add 1 to it and subtract 16 from a[i-1]. Afterwards, + // a[64] = 1, which is the 2^256 that we added before. + // + // Since k = a - 2^256 (mod curve->order), we can compute + // k*p = sum_{i=0..63} a[i] 16^i * p + // + // We compute |a[i]| * p in advance for all possible + // values of |a[i]| * p. pmult[i] = (2*i+1) * p + // We compute p, 3*p, ..., 15*p and store it in the table pmult. + // store p^2 temporarily in pmult[7] + pmult[7] = *p; + point_double(curve, &pmult[7]); + // compute 3*p, etc by repeatedly adding p^2. + pmult[0] = *p; + for (i = 1; i < 8; i++) { + pmult[i] = pmult[7]; + point_add(curve, &pmult[i - 1], &pmult[i]); + } + + // now compute res = sum_{i=0..63} a[i] * 16^i * p step by step, + // starting with i = 63. + // initialize jres = |a[63]| * p. + // Note that a[i] = a>>(4*i) & 0xf if (a&0x10) != 0 + // and - (16 - (a>>(4*i) & 0xf)) otherwise. We can compute this as + // ((a ^ (((a >> 4) & 1) - 1)) & 0xf) >> 1 + // since a is odd. + aptr = &a.val[8]; + abits = *aptr; + ashift = 12; + bits = abits >> ashift; + sign = (bits >> 4) - 1; + bits ^= sign; + bits &= 15; + curve_to_jacobian(&pmult[bits >> 1], &jres, prime); + for (i = 62; i >= 0; i--) { + // sign = sign(a[i+1]) (0xffffffff for negative, 0 for positive) + // invariant jres = (-1)^sign sum_{j=i+1..63} (a[j] * 16^{j-i-1} * p) + // abits >> (ashift - 4) = lowbits(a >> (i*4)) + + point_jacobian_double(&jres, curve); + point_jacobian_double(&jres, curve); + point_jacobian_double(&jres, curve); + point_jacobian_double(&jres, curve); + + // get lowest 5 bits of a >> (i*4). + ashift -= 4; + if (ashift < 0) { + // the condition only depends on the iteration number and + // leaks no private information to a side-channel. + bits = abits << (-ashift); + abits = *(--aptr); + ashift += 30; + bits |= abits >> ashift; + } else { + bits = abits >> ashift; + } + bits &= 31; + nsign = (bits >> 4) - 1; + bits ^= nsign; + bits &= 15; + + // negate last result to make signs of this round and the + // last round equal. + conditional_negate(sign ^ nsign, &jres.z, prime); + + // add odd factor + point_jacobian_add(&pmult[bits >> 1], &jres, curve); + sign = nsign; + } + conditional_negate(sign, &jres.z, prime); + jacobian_to_curve(&jres, res, prime); + memzero(&a, sizeof(a)); + memzero(&jres, sizeof(jres)); } #if USE_PRECOMPUTED_CP // res = k * G // k must be a normalized number with 0 <= k < curve->order -void scalar_multiply(const ecdsa_curve *curve, const bignum256 *k, curve_point *res) -{ - assert (bn_is_less(k, &curve->order)); - - int i, j; - static CONFIDENTIAL bignum256 a; - uint32_t is_even = (k->val[0] & 1) - 1; - uint32_t lowbits; - static CONFIDENTIAL jacobian_curve_point jres; - const bignum256 *prime = &curve->prime; - - // is_even = 0xffffffff if k is even, 0 otherwise. - - // add 2^256. - // make number odd: subtract curve->order if even - uint32_t tmp = 1; - uint32_t is_non_zero = 0; - for (j = 0; j < 8; j++) { - is_non_zero |= k->val[j]; - tmp += 0x3fffffff + k->val[j] - (curve->order.val[j] & is_even); - a.val[j] = tmp & 0x3fffffff; - tmp >>= 30; - } - is_non_zero |= k->val[j]; - a.val[j] = tmp + 0xffff + k->val[j] - (curve->order.val[j] & is_even); - assert((a.val[0] & 1) != 0); - - // special case 0*G: just return zero. We don't care about constant time. - if (!is_non_zero) { - point_set_infinity(res); - return; - } - - // Now a = k + 2^256 (mod curve->order) and a is odd. - // - // The idea is to bring the new a into the form. - // sum_{i=0..64} a[i] 16^i, where |a[i]| < 16 and a[i] is odd. - // a[0] is odd, since a is odd. If a[i] would be even, we can - // add 1 to it and subtract 16 from a[i-1]. Afterwards, - // a[64] = 1, which is the 2^256 that we added before. - // - // Since k = a - 2^256 (mod curve->order), we can compute - // k*G = sum_{i=0..63} a[i] 16^i * G - // - // We have a big table curve->cp that stores all possible - // values of |a[i]| 16^i * G. - // curve->cp[i][j] = (2*j+1) * 16^i * G - - // now compute res = sum_{i=0..63} a[i] * 16^i * G step by step. - // initial res = |a[0]| * G. Note that a[0] = a & 0xf if (a&0x10) != 0 - // and - (16 - (a & 0xf)) otherwise. We can compute this as - // ((a ^ (((a >> 4) & 1) - 1)) & 0xf) >> 1 - // since a is odd. - lowbits = a.val[0] & ((1 << 5) - 1); - lowbits ^= (lowbits >> 4) - 1; - lowbits &= 15; - curve_to_jacobian(&curve->cp[0][lowbits >> 1], &jres, prime); - for (i = 1; i < 64; i ++) { - // invariant res = sign(a[i-1]) sum_{j=0..i-1} (a[j] * 16^j * G) - - // shift a by 4 places. - for (j = 0; j < 8; j++) { - a.val[j] = (a.val[j] >> 4) | ((a.val[j + 1] & 0xf) << 26); - } - a.val[j] >>= 4; - // a = old(a)>>(4*i) - // a is even iff sign(a[i-1]) = -1 - - lowbits = a.val[0] & ((1 << 5) - 1); - lowbits ^= (lowbits >> 4) - 1; - lowbits &= 15; - // negate last result to make signs of this round and the - // last round equal. - conditional_negate((lowbits & 1) - 1, &jres.y, prime); - - // add odd factor - point_jacobian_add(&curve->cp[i][lowbits >> 1], &jres, curve); - } - conditional_negate(((a.val[0] >> 4) & 1) - 1, &jres.y, prime); - jacobian_to_curve(&jres, res, prime); - memzero(&a, sizeof(a)); - memzero(&jres, sizeof(jres)); +void scalar_multiply(const ecdsa_curve *curve, const bignum256 *k, + curve_point *res) { + assert(bn_is_less(k, &curve->order)); + + int i, j; + static CONFIDENTIAL bignum256 a; + uint32_t is_even = (k->val[0] & 1) - 1; + uint32_t lowbits; + static CONFIDENTIAL jacobian_curve_point jres; + const bignum256 *prime = &curve->prime; + + // is_even = 0xffffffff if k is even, 0 otherwise. + + // add 2^256. + // make number odd: subtract curve->order if even + uint32_t tmp = 1; + uint32_t is_non_zero = 0; + for (j = 0; j < 8; j++) { + is_non_zero |= k->val[j]; + tmp += 0x3fffffff + k->val[j] - (curve->order.val[j] & is_even); + a.val[j] = tmp & 0x3fffffff; + tmp >>= 30; + } + is_non_zero |= k->val[j]; + a.val[j] = tmp + 0xffff + k->val[j] - (curve->order.val[j] & is_even); + assert((a.val[0] & 1) != 0); + + // special case 0*G: just return zero. We don't care about constant time. + if (!is_non_zero) { + point_set_infinity(res); + return; + } + + // Now a = k + 2^256 (mod curve->order) and a is odd. + // + // The idea is to bring the new a into the form. + // sum_{i=0..64} a[i] 16^i, where |a[i]| < 16 and a[i] is odd. + // a[0] is odd, since a is odd. If a[i] would be even, we can + // add 1 to it and subtract 16 from a[i-1]. Afterwards, + // a[64] = 1, which is the 2^256 that we added before. + // + // Since k = a - 2^256 (mod curve->order), we can compute + // k*G = sum_{i=0..63} a[i] 16^i * G + // + // We have a big table curve->cp that stores all possible + // values of |a[i]| 16^i * G. + // curve->cp[i][j] = (2*j+1) * 16^i * G + + // now compute res = sum_{i=0..63} a[i] * 16^i * G step by step. + // initial res = |a[0]| * G. Note that a[0] = a & 0xf if (a&0x10) != 0 + // and - (16 - (a & 0xf)) otherwise. We can compute this as + // ((a ^ (((a >> 4) & 1) - 1)) & 0xf) >> 1 + // since a is odd. + lowbits = a.val[0] & ((1 << 5) - 1); + lowbits ^= (lowbits >> 4) - 1; + lowbits &= 15; + curve_to_jacobian(&curve->cp[0][lowbits >> 1], &jres, prime); + for (i = 1; i < 64; i++) { + // invariant res = sign(a[i-1]) sum_{j=0..i-1} (a[j] * 16^j * G) + + // shift a by 4 places. + for (j = 0; j < 8; j++) { + a.val[j] = (a.val[j] >> 4) | ((a.val[j + 1] & 0xf) << 26); + } + a.val[j] >>= 4; + // a = old(a)>>(4*i) + // a is even iff sign(a[i-1]) = -1 + + lowbits = a.val[0] & ((1 << 5) - 1); + lowbits ^= (lowbits >> 4) - 1; + lowbits &= 15; + // negate last result to make signs of this round and the + // last round equal. + conditional_negate((lowbits & 1) - 1, &jres.y, prime); + + // add odd factor + point_jacobian_add(&curve->cp[i][lowbits >> 1], &jres, curve); + } + conditional_negate(((a.val[0] >> 4) & 1) - 1, &jres.y, prime); + jacobian_to_curve(&jres, res, prime); + memzero(&a, sizeof(a)); + memzero(&jres, sizeof(jres)); } #else -void scalar_multiply(const ecdsa_curve *curve, const bignum256 *k, curve_point *res) -{ - point_multiply(curve, k, &curve->G, res); +void scalar_multiply(const ecdsa_curve *curve, const bignum256 *k, + curve_point *res) { + point_multiply(curve, k, &curve->G, res); } #endif -int ecdh_multiply(const ecdsa_curve *curve, const uint8_t *priv_key, const uint8_t *pub_key, uint8_t *session_key) -{ - curve_point point; - if (!ecdsa_read_pubkey(curve, pub_key, &point)) { - return 1; - } +int ecdh_multiply(const ecdsa_curve *curve, const uint8_t *priv_key, + const uint8_t *pub_key, uint8_t *session_key) { + curve_point point; + if (!ecdsa_read_pubkey(curve, pub_key, &point)) { + return 1; + } - bignum256 k; - bn_read_be(priv_key, &k); - point_multiply(curve, &k, &point, &point); - memzero(&k, sizeof(k)); + bignum256 k; + bn_read_be(priv_key, &k); + point_multiply(curve, &k, &point, &point); + memzero(&k, sizeof(k)); - session_key[0] = 0x04; - bn_write_be(&point.x, session_key + 1); - bn_write_be(&point.y, session_key + 33); - memzero(&point, sizeof(point)); + session_key[0] = 0x04; + bn_write_be(&point.x, session_key + 1); + bn_write_be(&point.y, session_key + 33); + memzero(&point, sizeof(point)); - return 0; + return 0; } -void init_rfc6979(const uint8_t *priv_key, const uint8_t *hash, rfc6979_state *state) { - uint8_t bx[2*32]; - uint8_t buf[32 + 1 + 2*32]; +void init_rfc6979(const uint8_t *priv_key, const uint8_t *hash, + rfc6979_state *state) { + uint8_t bx[2 * 32]; + uint8_t buf[32 + 1 + 2 * 32]; - memcpy(bx, priv_key, 32); - memcpy(bx+32, hash, 32); + memcpy(bx, priv_key, 32); + memcpy(bx + 32, hash, 32); - memset(state->v, 1, sizeof(state->v)); - memset(state->k, 0, sizeof(state->k)); + memset(state->v, 1, sizeof(state->v)); + memset(state->k, 0, sizeof(state->k)); - memcpy(buf, state->v, sizeof(state->v)); - buf[sizeof(state->v)] = 0x00; - memcpy(buf + sizeof(state->v) + 1, bx, 64); - hmac_sha256(state->k, sizeof(state->k), buf, sizeof(buf), state->k); - hmac_sha256(state->k, sizeof(state->k), state->v, sizeof(state->v), state->v); + memcpy(buf, state->v, sizeof(state->v)); + buf[sizeof(state->v)] = 0x00; + memcpy(buf + sizeof(state->v) + 1, bx, 64); + hmac_sha256(state->k, sizeof(state->k), buf, sizeof(buf), state->k); + hmac_sha256(state->k, sizeof(state->k), state->v, sizeof(state->v), state->v); - memcpy(buf, state->v, sizeof(state->v)); - buf[sizeof(state->v)] = 0x01; - memcpy(buf + sizeof(state->v) + 1, bx, 64); - hmac_sha256(state->k, sizeof(state->k), buf, sizeof(buf), state->k); - hmac_sha256(state->k, sizeof(state->k), state->v, sizeof(state->v), state->v); + memcpy(buf, state->v, sizeof(state->v)); + buf[sizeof(state->v)] = 0x01; + memcpy(buf + sizeof(state->v) + 1, bx, 64); + hmac_sha256(state->k, sizeof(state->k), buf, sizeof(buf), state->k); + hmac_sha256(state->k, sizeof(state->k), state->v, sizeof(state->v), state->v); - memzero(bx, sizeof(bx)); - memzero(buf, sizeof(buf)); + memzero(bx, sizeof(bx)); + memzero(buf, sizeof(buf)); } // generate next number from deterministic random number generator -void generate_rfc6979(uint8_t rnd[32], rfc6979_state *state) -{ - uint8_t buf[32 + 1]; - - hmac_sha256(state->k, sizeof(state->k), state->v, sizeof(state->v), state->v); - memcpy(buf, state->v, sizeof(state->v)); - buf[sizeof(state->v)] = 0x00; - hmac_sha256(state->k, sizeof(state->k), buf, sizeof(state->v) + 1, state->k); - hmac_sha256(state->k, sizeof(state->k), state->v, sizeof(state->v), state->v); - memcpy(rnd, buf, 32); - memzero(buf, sizeof(buf)); +void generate_rfc6979(uint8_t rnd[32], rfc6979_state *state) { + uint8_t buf[32 + 1]; + + hmac_sha256(state->k, sizeof(state->k), state->v, sizeof(state->v), state->v); + memcpy(buf, state->v, sizeof(state->v)); + buf[sizeof(state->v)] = 0x00; + hmac_sha256(state->k, sizeof(state->k), buf, sizeof(state->v) + 1, state->k); + hmac_sha256(state->k, sizeof(state->k), state->v, sizeof(state->v), state->v); + memcpy(rnd, buf, 32); + memzero(buf, sizeof(buf)); } // generate K in a deterministic way, according to RFC6979 // http://tools.ietf.org/html/rfc6979 -void generate_k_rfc6979(bignum256 *k, rfc6979_state *state) -{ - uint8_t buf[32]; - generate_rfc6979(buf, state); - bn_read_be(buf, k); - memzero(buf, sizeof(buf)); +void generate_k_rfc6979(bignum256 *k, rfc6979_state *state) { + uint8_t buf[32]; + generate_rfc6979(buf, state); + bn_read_be(buf, k); + memzero(buf, sizeof(buf)); } // msg is a data to be signed // msg_len is the message length -int ecdsa_sign(const ecdsa_curve *curve, HasherType hasher_sign, const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64])) -{ - uint8_t hash[32]; - hasher_Raw(hasher_sign, msg, msg_len, hash); - int res = ecdsa_sign_digest(curve, priv_key, hash, sig, pby, is_canonical); - memzero(hash, sizeof(hash)); - return res; - +int ecdsa_sign(const ecdsa_curve *curve, HasherType hasher_sign, + const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, + uint8_t *sig, uint8_t *pby, + int (*is_canonical)(uint8_t by, uint8_t sig[64])) { + uint8_t hash[32]; + hasher_Raw(hasher_sign, msg, msg_len, hash); + int res = ecdsa_sign_digest(curve, priv_key, hash, sig, pby, is_canonical); + memzero(hash, sizeof(hash)); + return res; } // uses secp256k1 curve @@ -729,245 +722,251 @@ int ecdsa_sign(const ecdsa_curve *curve, HasherType hasher_sign, const uint8_t * // digest is 32 bytes of digest // is_canonical is an optional function that checks if the signature // conforms to additional coin-specific rules. -int ecdsa_sign_digest(const ecdsa_curve *curve, const uint8_t *priv_key, const uint8_t *digest, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64])) -{ - int i; - curve_point R; - bignum256 k, z, randk; - bignum256 *s = &R.y; - uint8_t by; // signature recovery byte +int ecdsa_sign_digest(const ecdsa_curve *curve, const uint8_t *priv_key, + const uint8_t *digest, uint8_t *sig, uint8_t *pby, + int (*is_canonical)(uint8_t by, uint8_t sig[64])) { + int i; + curve_point R; + bignum256 k, z, randk; + bignum256 *s = &R.y; + uint8_t by; // signature recovery byte #if USE_RFC6979 - rfc6979_state rng; - init_rfc6979(priv_key, digest, &rng); + rfc6979_state rng; + init_rfc6979(priv_key, digest, &rng); #endif - bn_read_be(digest, &z); - - for (i = 0; i < 10000; i++) { + bn_read_be(digest, &z); + for (i = 0; i < 10000; i++) { #if USE_RFC6979 - // generate K deterministically - generate_k_rfc6979(&k, &rng); - // if k is too big or too small, we don't like it - if (bn_is_zero(&k) || !bn_is_less(&k, &curve->order)) { - continue; - } + // generate K deterministically + generate_k_rfc6979(&k, &rng); + // if k is too big or too small, we don't like it + if (bn_is_zero(&k) || !bn_is_less(&k, &curve->order)) { + continue; + } #else - // generate random number k - generate_k_random(&k, &curve->order); + // generate random number k + generate_k_random(&k, &curve->order); #endif - // compute k*G - scalar_multiply(curve, &k, &R); - by = R.y.val[0] & 1; - // r = (rx mod n) - if (!bn_is_less(&R.x, &curve->order)) { - bn_subtract(&R.x, &curve->order, &R.x); - by |= 2; - } - // if r is zero, we retry - if (bn_is_zero(&R.x)) { - continue; - } - - // randomize operations to counter side-channel attacks - generate_k_random(&randk, &curve->order); - bn_multiply(&randk, &k, &curve->order); // k*rand - bn_inverse(&k, &curve->order); // (k*rand)^-1 - bn_read_be(priv_key, s); // priv - bn_multiply(&R.x, s, &curve->order); // R.x*priv - bn_add(s, &z); // R.x*priv + z - bn_multiply(&k, s, &curve->order); // (k*rand)^-1 (R.x*priv + z) - bn_multiply(&randk, s, &curve->order); // k^-1 (R.x*priv + z) - bn_mod(s, &curve->order); - // if s is zero, we retry - if (bn_is_zero(s)) { - continue; - } - - // if S > order/2 => S = -S - if (bn_is_less(&curve->order_half, s)) { - bn_subtract(&curve->order, s, s); - by ^= 1; - } - // we are done, R.x and s is the result signature - bn_write_be(&R.x, sig); - bn_write_be(s, sig + 32); - - // check if the signature is acceptable or retry - if (is_canonical && !is_canonical(by, sig)) { - continue; - } - - if (pby) { - *pby = by; - } - - memzero(&k, sizeof(k)); - memzero(&randk, sizeof(randk)); + // compute k*G + scalar_multiply(curve, &k, &R); + by = R.y.val[0] & 1; + // r = (rx mod n) + if (!bn_is_less(&R.x, &curve->order)) { + bn_subtract(&R.x, &curve->order, &R.x); + by |= 2; + } + // if r is zero, we retry + if (bn_is_zero(&R.x)) { + continue; + } + + // randomize operations to counter side-channel attacks + generate_k_random(&randk, &curve->order); + bn_multiply(&randk, &k, &curve->order); // k*rand + bn_inverse(&k, &curve->order); // (k*rand)^-1 + bn_read_be(priv_key, s); // priv + bn_multiply(&R.x, s, &curve->order); // R.x*priv + bn_add(s, &z); // R.x*priv + z + bn_multiply(&k, s, &curve->order); // (k*rand)^-1 (R.x*priv + z) + bn_multiply(&randk, s, &curve->order); // k^-1 (R.x*priv + z) + bn_mod(s, &curve->order); + // if s is zero, we retry + if (bn_is_zero(s)) { + continue; + } + + // if S > order/2 => S = -S + if (bn_is_less(&curve->order_half, s)) { + bn_subtract(&curve->order, s, s); + by ^= 1; + } + // we are done, R.x and s is the result signature + bn_write_be(&R.x, sig); + bn_write_be(s, sig + 32); + + // check if the signature is acceptable or retry + if (is_canonical && !is_canonical(by, sig)) { + continue; + } + + if (pby) { + *pby = by; + } + + memzero(&k, sizeof(k)); + memzero(&randk, sizeof(randk)); #if USE_RFC6979 - memzero(&rng, sizeof(rng)); + memzero(&rng, sizeof(rng)); #endif - return 0; - } + return 0; + } - // Too many retries without a valid signature - // -> fail with an error - memzero(&k, sizeof(k)); - memzero(&randk, sizeof(randk)); + // Too many retries without a valid signature + // -> fail with an error + memzero(&k, sizeof(k)); + memzero(&randk, sizeof(randk)); #if USE_RFC6979 - memzero(&rng, sizeof(rng)); + memzero(&rng, sizeof(rng)); #endif - return -1; + return -1; } -void ecdsa_get_public_key33(const ecdsa_curve *curve, const uint8_t *priv_key, uint8_t *pub_key) -{ - curve_point R; - bignum256 k; - - bn_read_be(priv_key, &k); - // compute k*G - scalar_multiply(curve, &k, &R); - pub_key[0] = 0x02 | (R.y.val[0] & 0x01); - bn_write_be(&R.x, pub_key + 1); - memzero(&R, sizeof(R)); - memzero(&k, sizeof(k)); +void ecdsa_get_public_key33(const ecdsa_curve *curve, const uint8_t *priv_key, + uint8_t *pub_key) { + curve_point R; + bignum256 k; + + bn_read_be(priv_key, &k); + // compute k*G + scalar_multiply(curve, &k, &R); + pub_key[0] = 0x02 | (R.y.val[0] & 0x01); + bn_write_be(&R.x, pub_key + 1); + memzero(&R, sizeof(R)); + memzero(&k, sizeof(k)); } -void ecdsa_get_public_key65(const ecdsa_curve *curve, const uint8_t *priv_key, uint8_t *pub_key) -{ - curve_point R; - bignum256 k; - - bn_read_be(priv_key, &k); - // compute k*G - scalar_multiply(curve, &k, &R); - pub_key[0] = 0x04; - bn_write_be(&R.x, pub_key + 1); - bn_write_be(&R.y, pub_key + 33); - memzero(&R, sizeof(R)); - memzero(&k, sizeof(k)); +void ecdsa_get_public_key65(const ecdsa_curve *curve, const uint8_t *priv_key, + uint8_t *pub_key) { + curve_point R; + bignum256 k; + + bn_read_be(priv_key, &k); + // compute k*G + scalar_multiply(curve, &k, &R); + pub_key[0] = 0x04; + bn_write_be(&R.x, pub_key + 1); + bn_write_be(&R.y, pub_key + 33); + memzero(&R, sizeof(R)); + memzero(&k, sizeof(k)); } -int ecdsa_uncompress_pubkey(const ecdsa_curve *curve, const uint8_t *pub_key, uint8_t *uncompressed) -{ - curve_point pub; +int ecdsa_uncompress_pubkey(const ecdsa_curve *curve, const uint8_t *pub_key, + uint8_t *uncompressed) { + curve_point pub; - if (!ecdsa_read_pubkey(curve, pub_key, &pub)) { - return 0; - } + if (!ecdsa_read_pubkey(curve, pub_key, &pub)) { + return 0; + } - uncompressed[0] = 4; - bn_write_be(&pub.x, uncompressed + 1); - bn_write_be(&pub.y, uncompressed + 33); + uncompressed[0] = 4; + bn_write_be(&pub.x, uncompressed + 1); + bn_write_be(&pub.y, uncompressed + 33); - return 1; + return 1; } -void ecdsa_get_pubkeyhash(const uint8_t *pub_key, HasherType hasher_pubkey, uint8_t *pubkeyhash) -{ - uint8_t h[HASHER_DIGEST_LENGTH]; - if (pub_key[0] == 0x04) { // uncompressed format - hasher_Raw(hasher_pubkey, pub_key, 65, h); - } else if (pub_key[0] == 0x00) { // point at infinity - hasher_Raw(hasher_pubkey, pub_key, 1, h); - } else { // expecting compressed format - hasher_Raw(hasher_pubkey, pub_key, 33, h); - } - memcpy(pubkeyhash, h, 20); - memzero(h, sizeof(h)); +void ecdsa_get_pubkeyhash(const uint8_t *pub_key, HasherType hasher_pubkey, + uint8_t *pubkeyhash) { + uint8_t h[HASHER_DIGEST_LENGTH]; + if (pub_key[0] == 0x04) { // uncompressed format + hasher_Raw(hasher_pubkey, pub_key, 65, h); + } else if (pub_key[0] == 0x00) { // point at infinity + hasher_Raw(hasher_pubkey, pub_key, 1, h); + } else { // expecting compressed format + hasher_Raw(hasher_pubkey, pub_key, 33, h); + } + memcpy(pubkeyhash, h, 20); + memzero(h, sizeof(h)); } -void ecdsa_get_address_raw(const uint8_t *pub_key, uint32_t version, HasherType hasher_pubkey, uint8_t *addr_raw) -{ - size_t prefix_len = address_prefix_bytes_len(version); - address_write_prefix_bytes(version, addr_raw); - ecdsa_get_pubkeyhash(pub_key, hasher_pubkey, addr_raw + prefix_len); +void ecdsa_get_address_raw(const uint8_t *pub_key, uint32_t version, + HasherType hasher_pubkey, uint8_t *addr_raw) { + size_t prefix_len = address_prefix_bytes_len(version); + address_write_prefix_bytes(version, addr_raw); + ecdsa_get_pubkeyhash(pub_key, hasher_pubkey, addr_raw + prefix_len); } -void ecdsa_get_address(const uint8_t *pub_key, uint32_t version, HasherType hasher_pubkey, HasherType hasher_base58, char *addr, int addrsize) -{ - uint8_t raw[MAX_ADDR_RAW_SIZE]; - size_t prefix_len = address_prefix_bytes_len(version); - ecdsa_get_address_raw(pub_key, version, hasher_pubkey, raw); - base58_encode_check(raw, 20 + prefix_len, hasher_base58, addr, addrsize); - // not as important to clear this one, but we might as well - memzero(raw, sizeof(raw)); +void ecdsa_get_address(const uint8_t *pub_key, uint32_t version, + HasherType hasher_pubkey, HasherType hasher_base58, + char *addr, int addrsize) { + uint8_t raw[MAX_ADDR_RAW_SIZE]; + size_t prefix_len = address_prefix_bytes_len(version); + ecdsa_get_address_raw(pub_key, version, hasher_pubkey, raw); + base58_encode_check(raw, 20 + prefix_len, hasher_base58, addr, addrsize); + // not as important to clear this one, but we might as well + memzero(raw, sizeof(raw)); } -void ecdsa_get_address_segwit_p2sh_raw(const uint8_t *pub_key, uint32_t version, HasherType hasher_pubkey, uint8_t *addr_raw) -{ - uint8_t buf[32 + 2]; - buf[0] = 0; // version byte - buf[1] = 20; // push 20 bytes - ecdsa_get_pubkeyhash(pub_key, hasher_pubkey, buf + 2); - size_t prefix_len = address_prefix_bytes_len(version); - address_write_prefix_bytes(version, addr_raw); - hasher_Raw(hasher_pubkey, buf, 22, addr_raw + prefix_len); +void ecdsa_get_address_segwit_p2sh_raw(const uint8_t *pub_key, uint32_t version, + HasherType hasher_pubkey, + uint8_t *addr_raw) { + uint8_t buf[32 + 2]; + buf[0] = 0; // version byte + buf[1] = 20; // push 20 bytes + ecdsa_get_pubkeyhash(pub_key, hasher_pubkey, buf + 2); + size_t prefix_len = address_prefix_bytes_len(version); + address_write_prefix_bytes(version, addr_raw); + hasher_Raw(hasher_pubkey, buf, 22, addr_raw + prefix_len); } -void ecdsa_get_address_segwit_p2sh(const uint8_t *pub_key, uint32_t version, HasherType hasher_pubkey, HasherType hasher_base58, char *addr, int addrsize) -{ - uint8_t raw[MAX_ADDR_RAW_SIZE]; - size_t prefix_len = address_prefix_bytes_len(version); - ecdsa_get_address_segwit_p2sh_raw(pub_key, version, hasher_pubkey, raw); - base58_encode_check(raw, prefix_len + 20, hasher_base58, addr, addrsize); - memzero(raw, sizeof(raw)); +void ecdsa_get_address_segwit_p2sh(const uint8_t *pub_key, uint32_t version, + HasherType hasher_pubkey, + HasherType hasher_base58, char *addr, + int addrsize) { + uint8_t raw[MAX_ADDR_RAW_SIZE]; + size_t prefix_len = address_prefix_bytes_len(version); + ecdsa_get_address_segwit_p2sh_raw(pub_key, version, hasher_pubkey, raw); + base58_encode_check(raw, prefix_len + 20, hasher_base58, addr, addrsize); + memzero(raw, sizeof(raw)); } -void ecdsa_get_wif(const uint8_t *priv_key, uint32_t version, HasherType hasher_base58, char *wif, int wifsize) -{ - uint8_t wif_raw[MAX_WIF_RAW_SIZE]; - size_t prefix_len = address_prefix_bytes_len(version); - address_write_prefix_bytes(version, wif_raw); - memcpy(wif_raw + prefix_len, priv_key, 32); - wif_raw[prefix_len + 32] = 0x01; - base58_encode_check(wif_raw, prefix_len + 32 + 1, hasher_base58, wif, wifsize); - // private keys running around our stack can cause trouble - memzero(wif_raw, sizeof(wif_raw)); +void ecdsa_get_wif(const uint8_t *priv_key, uint32_t version, + HasherType hasher_base58, char *wif, int wifsize) { + uint8_t wif_raw[MAX_WIF_RAW_SIZE]; + size_t prefix_len = address_prefix_bytes_len(version); + address_write_prefix_bytes(version, wif_raw); + memcpy(wif_raw + prefix_len, priv_key, 32); + wif_raw[prefix_len + 32] = 0x01; + base58_encode_check(wif_raw, prefix_len + 32 + 1, hasher_base58, wif, + wifsize); + // private keys running around our stack can cause trouble + memzero(wif_raw, sizeof(wif_raw)); } -int ecdsa_address_decode(const char *addr, uint32_t version, HasherType hasher_base58, uint8_t *out) -{ - if (!addr) return 0; - int prefix_len = address_prefix_bytes_len(version); - return base58_decode_check(addr, hasher_base58, out, 20 + prefix_len) == 20 + prefix_len - && address_check_prefix(out, version); +int ecdsa_address_decode(const char *addr, uint32_t version, + HasherType hasher_base58, uint8_t *out) { + if (!addr) return 0; + int prefix_len = address_prefix_bytes_len(version); + return base58_decode_check(addr, hasher_base58, out, 20 + prefix_len) == + 20 + prefix_len && + address_check_prefix(out, version); } -void uncompress_coords(const ecdsa_curve *curve, uint8_t odd, const bignum256 *x, bignum256 *y) -{ - // y^2 = x^3 + a*x + b - memcpy(y, x, sizeof(bignum256)); // y is x - bn_multiply(x, y, &curve->prime); // y is x^2 - bn_subi(y, -curve->a, &curve->prime); // y is x^2 + a - bn_multiply(x, y, &curve->prime); // y is x^3 + ax - bn_add(y, &curve->b); // y is x^3 + ax + b - bn_sqrt(y, &curve->prime); // y = sqrt(y) - if ((odd & 0x01) != (y->val[0] & 1)) { - bn_subtract(&curve->prime, y, y); // y = -y - } +void uncompress_coords(const ecdsa_curve *curve, uint8_t odd, + const bignum256 *x, bignum256 *y) { + // y^2 = x^3 + a*x + b + memcpy(y, x, sizeof(bignum256)); // y is x + bn_multiply(x, y, &curve->prime); // y is x^2 + bn_subi(y, -curve->a, &curve->prime); // y is x^2 + a + bn_multiply(x, y, &curve->prime); // y is x^3 + ax + bn_add(y, &curve->b); // y is x^3 + ax + b + bn_sqrt(y, &curve->prime); // y = sqrt(y) + if ((odd & 0x01) != (y->val[0] & 1)) { + bn_subtract(&curve->prime, y, y); // y = -y + } } -int ecdsa_read_pubkey(const ecdsa_curve *curve, const uint8_t *pub_key, curve_point *pub) -{ - if (!curve) { - curve = &secp256k1; - } - if (pub_key[0] == 0x04) { - bn_read_be(pub_key + 1, &(pub->x)); - bn_read_be(pub_key + 33, &(pub->y)); - return ecdsa_validate_pubkey(curve, pub); - } - if (pub_key[0] == 0x02 || pub_key[0] == 0x03) { // compute missing y coords - bn_read_be(pub_key + 1, &(pub->x)); - uncompress_coords(curve, pub_key[0], &(pub->x), &(pub->y)); - return ecdsa_validate_pubkey(curve, pub); - } - // error - return 0; +int ecdsa_read_pubkey(const ecdsa_curve *curve, const uint8_t *pub_key, + curve_point *pub) { + if (!curve) { + curve = &secp256k1; + } + if (pub_key[0] == 0x04) { + bn_read_be(pub_key + 1, &(pub->x)); + bn_read_be(pub_key + 33, &(pub->y)); + return ecdsa_validate_pubkey(curve, pub); + } + if (pub_key[0] == 0x02 || pub_key[0] == 0x03) { // compute missing y coords + bn_read_be(pub_key + 1, &(pub->x)); + uncompress_coords(curve, pub_key[0], &(pub->x), &(pub->y)); + return ecdsa_validate_pubkey(curve, pub); + } + // error + return 0; } // Verifies that: @@ -975,37 +974,37 @@ int ecdsa_read_pubkey(const ecdsa_curve *curve, const uint8_t *pub_key, curve_po // - pub->x and pub->y are in range [0,p-1]. // - pub is on the curve. -int ecdsa_validate_pubkey(const ecdsa_curve *curve, const curve_point *pub) -{ - bignum256 y_2, x3_ax_b; +int ecdsa_validate_pubkey(const ecdsa_curve *curve, const curve_point *pub) { + bignum256 y_2, x3_ax_b; - if (point_is_infinity(pub)) { - return 0; - } + if (point_is_infinity(pub)) { + return 0; + } - if (!bn_is_less(&(pub->x), &curve->prime) || !bn_is_less(&(pub->y), &curve->prime)) { - return 0; - } + if (!bn_is_less(&(pub->x), &curve->prime) || + !bn_is_less(&(pub->y), &curve->prime)) { + return 0; + } - memcpy(&y_2, &(pub->y), sizeof(bignum256)); - memcpy(&x3_ax_b, &(pub->x), sizeof(bignum256)); + memcpy(&y_2, &(pub->y), sizeof(bignum256)); + memcpy(&x3_ax_b, &(pub->x), sizeof(bignum256)); - // y^2 - bn_multiply(&(pub->y), &y_2, &curve->prime); - bn_mod(&y_2, &curve->prime); + // y^2 + bn_multiply(&(pub->y), &y_2, &curve->prime); + bn_mod(&y_2, &curve->prime); - // x^3 + ax + b - bn_multiply(&(pub->x), &x3_ax_b, &curve->prime); // x^2 - bn_subi(&x3_ax_b, -curve->a, &curve->prime); // x^2 + a - bn_multiply(&(pub->x), &x3_ax_b, &curve->prime); // x^3 + ax - bn_addmod(&x3_ax_b, &curve->b, &curve->prime); // x^3 + ax + b - bn_mod(&x3_ax_b, &curve->prime); + // x^3 + ax + b + bn_multiply(&(pub->x), &x3_ax_b, &curve->prime); // x^2 + bn_subi(&x3_ax_b, -curve->a, &curve->prime); // x^2 + a + bn_multiply(&(pub->x), &x3_ax_b, &curve->prime); // x^3 + ax + bn_addmod(&x3_ax_b, &curve->b, &curve->prime); // x^3 + ax + b + bn_mod(&x3_ax_b, &curve->prime); - if (!bn_is_equal(&x3_ax_b, &y_2)) { - return 0; - } + if (!bn_is_equal(&x3_ax_b, &y_2)) { + return 0; + } - return 1; + return 1; } // uses secp256k1 curve @@ -1014,153 +1013,178 @@ int ecdsa_validate_pubkey(const ecdsa_curve *curve, const curve_point *pub) // msg is a data that was signed // msg_len is the message length -int ecdsa_verify(const ecdsa_curve *curve, HasherType hasher_sign, const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, uint32_t msg_len) -{ - uint8_t hash[32]; - hasher_Raw(hasher_sign, msg, msg_len, hash); - int res = ecdsa_verify_digest(curve, pub_key, sig, hash); - memzero(hash, sizeof(hash)); - return res; +int ecdsa_verify(const ecdsa_curve *curve, HasherType hasher_sign, + const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, + uint32_t msg_len) { + uint8_t hash[32]; + hasher_Raw(hasher_sign, msg, msg_len, hash); + int res = ecdsa_verify_digest(curve, pub_key, sig, hash); + memzero(hash, sizeof(hash)); + return res; } // Compute public key from signature and recovery id. // returns 0 if the key is successfully recovered -int ecdsa_recover_pub_from_sig (const ecdsa_curve *curve, uint8_t *pub_key, const uint8_t *sig, const uint8_t *digest, int recid) -{ - bignum256 r, s, e; - curve_point cp, cp2; - - // read r and s - bn_read_be(sig, &r); - bn_read_be(sig + 32, &s); - if (!bn_is_less(&r, &curve->order) || bn_is_zero(&r)) { - return 1; - } - if (!bn_is_less(&s, &curve->order) || bn_is_zero(&s)) { - return 1; - } - // cp = R = k * G (k is secret nonce when signing) - memcpy(&cp.x, &r, sizeof(bignum256)); - if (recid & 2) { - bn_add(&cp.x, &curve->order); - if (!bn_is_less(&cp.x, &curve->prime)) { - return 1; - } - } - // compute y from x - uncompress_coords(curve, recid & 1, &cp.x, &cp.y); - if (!ecdsa_validate_pubkey(curve, &cp)) { - return 1; - } - // e = -digest - bn_read_be(digest, &e); - bn_subtractmod(&curve->order, &e, &e, &curve->order); - bn_fast_mod(&e, &curve->order); - bn_mod(&e, &curve->order); - // r := r^-1 - bn_inverse(&r, &curve->order); - // cp := s * R = s * k *G - point_multiply(curve, &s, &cp, &cp); - // cp2 := -digest * G - scalar_multiply(curve, &e, &cp2); - // cp := (s * k - digest) * G = (r*priv) * G = r * Pub - point_add(curve, &cp2, &cp); - // cp := r^{-1} * r * Pub = Pub - point_multiply(curve, &r, &cp, &cp); - pub_key[0] = 0x04; - bn_write_be(&cp.x, pub_key + 1); - bn_write_be(&cp.y, pub_key + 33); - return 0; +int ecdsa_recover_pub_from_sig(const ecdsa_curve *curve, uint8_t *pub_key, + const uint8_t *sig, const uint8_t *digest, + int recid) { + bignum256 r, s, e; + curve_point cp, cp2; + + // read r and s + bn_read_be(sig, &r); + bn_read_be(sig + 32, &s); + if (!bn_is_less(&r, &curve->order) || bn_is_zero(&r)) { + return 1; + } + if (!bn_is_less(&s, &curve->order) || bn_is_zero(&s)) { + return 1; + } + // cp = R = k * G (k is secret nonce when signing) + memcpy(&cp.x, &r, sizeof(bignum256)); + if (recid & 2) { + bn_add(&cp.x, &curve->order); + if (!bn_is_less(&cp.x, &curve->prime)) { + return 1; + } + } + // compute y from x + uncompress_coords(curve, recid & 1, &cp.x, &cp.y); + if (!ecdsa_validate_pubkey(curve, &cp)) { + return 1; + } + // e = -digest + bn_read_be(digest, &e); + bn_subtractmod(&curve->order, &e, &e, &curve->order); + bn_fast_mod(&e, &curve->order); + bn_mod(&e, &curve->order); + // r := r^-1 + bn_inverse(&r, &curve->order); + // cp := s * R = s * k *G + point_multiply(curve, &s, &cp, &cp); + // cp2 := -digest * G + scalar_multiply(curve, &e, &cp2); + // cp := (s * k - digest) * G = (r*priv) * G = r * Pub + point_add(curve, &cp2, &cp); + // cp := r^{-1} * r * Pub = Pub + point_multiply(curve, &r, &cp, &cp); + pub_key[0] = 0x04; + bn_write_be(&cp.x, pub_key + 1); + bn_write_be(&cp.y, pub_key + 33); + return 0; } // returns 0 if verification succeeded -int ecdsa_verify_digest(const ecdsa_curve *curve, const uint8_t *pub_key, const uint8_t *sig, const uint8_t *digest) -{ - curve_point pub, res; - bignum256 r, s, z; - - if (!ecdsa_read_pubkey(curve, pub_key, &pub)) { - return 1; - } - - bn_read_be(sig, &r); - bn_read_be(sig + 32, &s); - - bn_read_be(digest, &z); - - if (bn_is_zero(&r) || bn_is_zero(&s) || - (!bn_is_less(&r, &curve->order)) || - (!bn_is_less(&s, &curve->order))) return 2; - - bn_inverse(&s, &curve->order); // s^-1 - bn_multiply(&s, &z, &curve->order); // z*s^-1 - bn_mod(&z, &curve->order); - bn_multiply(&r, &s, &curve->order); // r*s^-1 - bn_mod(&s, &curve->order); - - int result = 0; - if (bn_is_zero(&z)) { - // our message hashes to zero - // I don't expect this to happen any time soon - result = 3; - } else { - scalar_multiply(curve, &z, &res); - } - - if (result == 0) { - // both pub and res can be infinity, can have y = 0 OR can be equal -> false negative - point_multiply(curve, &s, &pub, &pub); - point_add(curve, &pub, &res); - bn_mod(&(res.x), &curve->order); - // signature does not match - if (!bn_is_equal(&res.x, &r)) { - result = 5; - } - } - - memzero(&pub, sizeof(pub)); - memzero(&res, sizeof(res)); - memzero(&r, sizeof(r)); - memzero(&s, sizeof(s)); - memzero(&z, sizeof(z)); - - // all OK - return result; +int ecdsa_verify_digest(const ecdsa_curve *curve, const uint8_t *pub_key, + const uint8_t *sig, const uint8_t *digest) { + curve_point pub, res; + bignum256 r, s, z; + + if (!ecdsa_read_pubkey(curve, pub_key, &pub)) { + return 1; + } + + bn_read_be(sig, &r); + bn_read_be(sig + 32, &s); + + bn_read_be(digest, &z); + + if (bn_is_zero(&r) || bn_is_zero(&s) || (!bn_is_less(&r, &curve->order)) || + (!bn_is_less(&s, &curve->order))) + return 2; + + bn_inverse(&s, &curve->order); // s^-1 + bn_multiply(&s, &z, &curve->order); // z*s^-1 + bn_mod(&z, &curve->order); + bn_multiply(&r, &s, &curve->order); // r*s^-1 + bn_mod(&s, &curve->order); + + int result = 0; + if (bn_is_zero(&z)) { + // our message hashes to zero + // I don't expect this to happen any time soon + result = 3; + } else { + scalar_multiply(curve, &z, &res); + } + + if (result == 0) { + // both pub and res can be infinity, can have y = 0 OR can be equal -> false + // negative + point_multiply(curve, &s, &pub, &pub); + point_add(curve, &pub, &res); + bn_mod(&(res.x), &curve->order); + // signature does not match + if (!bn_is_equal(&res.x, &r)) { + result = 5; + } + } + + memzero(&pub, sizeof(pub)); + memzero(&res, sizeof(res)); + memzero(&r, sizeof(r)); + memzero(&s, sizeof(s)); + memzero(&z, sizeof(z)); + + // all OK + return result; } -int ecdsa_sig_to_der(const uint8_t *sig, uint8_t *der) -{ - int i; - uint8_t *p = der, *len, *len1, *len2; - *p = 0x30; p++; // sequence - *p = 0x00; len = p; p++; // len(sequence) - - *p = 0x02; p++; // integer - *p = 0x00; len1 = p; p++; // len(integer) - - // process R - i = 0; - while (sig[i] == 0 && i < 32) { i++; } // skip leading zeroes - if (sig[i] >= 0x80) { // put zero in output if MSB set - *p = 0x00; p++; *len1 = *len1 + 1; - } - while (i < 32) { // copy bytes to output - *p = sig[i]; p++; *len1 = *len1 + 1; i++; - } - - *p = 0x02; p++; // integer - *p = 0x00; len2 = p; p++; // len(integer) - - // process S - i = 32; - while (sig[i] == 0 && i < 64) { i++; } // skip leading zeroes - if (sig[i] >= 0x80) { // put zero in output if MSB set - *p = 0x00; p++; *len2 = *len2 + 1; - } - while (i < 64) { // copy bytes to output - *p = sig[i]; p++; *len2 = *len2 + 1; i++; - } - - *len = *len1 + *len2 + 4; - return *len + 2; +int ecdsa_sig_to_der(const uint8_t *sig, uint8_t *der) { + int i; + uint8_t *p = der, *len, *len1, *len2; + *p = 0x30; + p++; // sequence + *p = 0x00; + len = p; + p++; // len(sequence) + + *p = 0x02; + p++; // integer + *p = 0x00; + len1 = p; + p++; // len(integer) + + // process R + i = 0; + while (sig[i] == 0 && i < 32) { + i++; + } // skip leading zeroes + if (sig[i] >= 0x80) { // put zero in output if MSB set + *p = 0x00; + p++; + *len1 = *len1 + 1; + } + while (i < 32) { // copy bytes to output + *p = sig[i]; + p++; + *len1 = *len1 + 1; + i++; + } + + *p = 0x02; + p++; // integer + *p = 0x00; + len2 = p; + p++; // len(integer) + + // process S + i = 32; + while (sig[i] == 0 && i < 64) { + i++; + } // skip leading zeroes + if (sig[i] >= 0x80) { // put zero in output if MSB set + *p = 0x00; + p++; + *len2 = *len2 + 1; + } + while (i < 64) { // copy bytes to output + *p = sig[i]; + p++; + *len2 = *len2 + 1; + i++; + } + + *len = *len1 + *len2 + 4; + return *len + 2; } diff --git a/ecdsa.h b/ecdsa.h index 6afb542f2..8f8d06457 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -25,26 +25,25 @@ #define __ECDSA_H__ #include -#include "options.h" #include "bignum.h" #include "hasher.h" +#include "options.h" // curve point x and y typedef struct { - bignum256 x, y; + bignum256 x, y; } curve_point; typedef struct { - - bignum256 prime; // prime order of the finite field - curve_point G; // initial curve point - bignum256 order; // order of G - bignum256 order_half; // order of G divided by 2 - int a; // coefficient 'a' of the elliptic curve - bignum256 b; // coefficient 'b' of the elliptic curve + bignum256 prime; // prime order of the finite field + curve_point G; // initial curve point + bignum256 order; // order of G + bignum256 order_half; // order of G divided by 2 + int a; // coefficient 'a' of the elliptic curve + bignum256 b; // coefficient 'b' of the elliptic curve #if USE_PRECOMPUTED_CP - const curve_point cp[64][8]; + const curve_point cp[64][8]; #endif } ecdsa_curve; @@ -63,35 +62,65 @@ typedef struct { #define MAX_WIF_SIZE (57) void point_copy(const curve_point *cp1, curve_point *cp2); -void point_add(const ecdsa_curve *curve, const curve_point *cp1, curve_point *cp2); +void point_add(const ecdsa_curve *curve, const curve_point *cp1, + curve_point *cp2); void point_double(const ecdsa_curve *curve, curve_point *cp); -void point_multiply(const ecdsa_curve *curve, const bignum256 *k, const curve_point *p, curve_point *res); +void point_multiply(const ecdsa_curve *curve, const bignum256 *k, + const curve_point *p, curve_point *res); void point_set_infinity(curve_point *p); int point_is_infinity(const curve_point *p); int point_is_equal(const curve_point *p, const curve_point *q); int point_is_negative_of(const curve_point *p, const curve_point *q); -void scalar_multiply(const ecdsa_curve *curve, const bignum256 *k, curve_point *res); -int ecdh_multiply(const ecdsa_curve *curve, const uint8_t *priv_key, const uint8_t *pub_key, uint8_t *session_key); -void uncompress_coords(const ecdsa_curve *curve, uint8_t odd, const bignum256 *x, bignum256 *y); -int ecdsa_uncompress_pubkey(const ecdsa_curve *curve, const uint8_t *pub_key, uint8_t *uncompressed); +void scalar_multiply(const ecdsa_curve *curve, const bignum256 *k, + curve_point *res); +int ecdh_multiply(const ecdsa_curve *curve, const uint8_t *priv_key, + const uint8_t *pub_key, uint8_t *session_key); +void uncompress_coords(const ecdsa_curve *curve, uint8_t odd, + const bignum256 *x, bignum256 *y); +int ecdsa_uncompress_pubkey(const ecdsa_curve *curve, const uint8_t *pub_key, + uint8_t *uncompressed); -int ecdsa_sign(const ecdsa_curve *curve, HasherType hasher_sign, const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64])); -int ecdsa_sign_digest(const ecdsa_curve *curve, const uint8_t *priv_key, const uint8_t *digest, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64])); -void ecdsa_get_public_key33(const ecdsa_curve *curve, const uint8_t *priv_key, uint8_t *pub_key); -void ecdsa_get_public_key65(const ecdsa_curve *curve, const uint8_t *priv_key, uint8_t *pub_key); -void ecdsa_get_pubkeyhash(const uint8_t *pub_key, HasherType hasher_pubkey, uint8_t *pubkeyhash); -void ecdsa_get_address_raw(const uint8_t *pub_key, uint32_t version, HasherType hasher_pubkey, uint8_t *addr_raw); -void ecdsa_get_address(const uint8_t *pub_key, uint32_t version, HasherType hasher_pubkey, HasherType hasher_base58, char *addr, int addrsize); -void ecdsa_get_address_segwit_p2sh_raw(const uint8_t *pub_key, uint32_t version, HasherType hasher_pubkey, uint8_t *addr_raw); -void ecdsa_get_address_segwit_p2sh(const uint8_t *pub_key, uint32_t version, HasherType hasher_pubkey, HasherType hasher_base58, char *addr, int addrsize); -void ecdsa_get_wif(const uint8_t *priv_key, uint32_t version, HasherType hasher_base58, char *wif, int wifsize); +int ecdsa_sign(const ecdsa_curve *curve, HasherType hasher_sign, + const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, + uint8_t *sig, uint8_t *pby, + int (*is_canonical)(uint8_t by, uint8_t sig[64])); +int ecdsa_sign_digest(const ecdsa_curve *curve, const uint8_t *priv_key, + const uint8_t *digest, uint8_t *sig, uint8_t *pby, + int (*is_canonical)(uint8_t by, uint8_t sig[64])); +void ecdsa_get_public_key33(const ecdsa_curve *curve, const uint8_t *priv_key, + uint8_t *pub_key); +void ecdsa_get_public_key65(const ecdsa_curve *curve, const uint8_t *priv_key, + uint8_t *pub_key); +void ecdsa_get_pubkeyhash(const uint8_t *pub_key, HasherType hasher_pubkey, + uint8_t *pubkeyhash); +void ecdsa_get_address_raw(const uint8_t *pub_key, uint32_t version, + HasherType hasher_pubkey, uint8_t *addr_raw); +void ecdsa_get_address(const uint8_t *pub_key, uint32_t version, + HasherType hasher_pubkey, HasherType hasher_base58, + char *addr, int addrsize); +void ecdsa_get_address_segwit_p2sh_raw(const uint8_t *pub_key, uint32_t version, + HasherType hasher_pubkey, + uint8_t *addr_raw); +void ecdsa_get_address_segwit_p2sh(const uint8_t *pub_key, uint32_t version, + HasherType hasher_pubkey, + HasherType hasher_base58, char *addr, + int addrsize); +void ecdsa_get_wif(const uint8_t *priv_key, uint32_t version, + HasherType hasher_base58, char *wif, int wifsize); -int ecdsa_address_decode(const char *addr, uint32_t version, HasherType hasher_base58, uint8_t *out); -int ecdsa_read_pubkey(const ecdsa_curve *curve, const uint8_t *pub_key, curve_point *pub); +int ecdsa_address_decode(const char *addr, uint32_t version, + HasherType hasher_base58, uint8_t *out); +int ecdsa_read_pubkey(const ecdsa_curve *curve, const uint8_t *pub_key, + curve_point *pub); int ecdsa_validate_pubkey(const ecdsa_curve *curve, const curve_point *pub); -int ecdsa_verify(const ecdsa_curve *curve, HasherType hasher_sign, const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, uint32_t msg_len); -int ecdsa_verify_digest(const ecdsa_curve *curve, const uint8_t *pub_key, const uint8_t *sig, const uint8_t *digest); -int ecdsa_recover_pub_from_sig (const ecdsa_curve *curve, uint8_t *pub_key, const uint8_t *sig, const uint8_t *digest, int recid); +int ecdsa_verify(const ecdsa_curve *curve, HasherType hasher_sign, + const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, + uint32_t msg_len); +int ecdsa_verify_digest(const ecdsa_curve *curve, const uint8_t *pub_key, + const uint8_t *sig, const uint8_t *digest); +int ecdsa_recover_pub_from_sig(const ecdsa_curve *curve, uint8_t *pub_key, + const uint8_t *sig, const uint8_t *digest, + int recid); int ecdsa_sig_to_der(const uint8_t *sig, uint8_t *der); #endif diff --git a/hasher.c b/hasher.c index dac3e9bf5..240cba778 100644 --- a/hasher.c +++ b/hasher.c @@ -23,122 +23,125 @@ #include "hasher.h" #include "ripemd160.h" -void hasher_InitParam(Hasher *hasher, HasherType type, const void *param, uint32_t param_size) { - hasher->type = type; - hasher->param = param; - hasher->param_size = param_size; +void hasher_InitParam(Hasher *hasher, HasherType type, const void *param, + uint32_t param_size) { + hasher->type = type; + hasher->param = param; + hasher->param_size = param_size; - switch (hasher->type) { - case HASHER_SHA2: - case HASHER_SHA2D: - case HASHER_SHA2_RIPEMD: - sha256_Init(&hasher->ctx.sha2); - break; - case HASHER_SHA3: + switch (hasher->type) { + case HASHER_SHA2: + case HASHER_SHA2D: + case HASHER_SHA2_RIPEMD: + sha256_Init(&hasher->ctx.sha2); + break; + case HASHER_SHA3: #if USE_KECCAK - case HASHER_SHA3K: + case HASHER_SHA3K: #endif - sha3_256_Init(&hasher->ctx.sha3); - break; - case HASHER_BLAKE: - case HASHER_BLAKED: - case HASHER_BLAKE_RIPEMD: - blake256_Init(&hasher->ctx.blake); - break; - case HASHER_GROESTLD_TRUNC: - groestl512_Init(&hasher->ctx.groestl); - break; - case HASHER_BLAKE2B: - blake2b_Init(&hasher->ctx.blake2b, 32); - break; - case HASHER_BLAKE2B_PERSONAL: - blake2b_InitPersonal(&hasher->ctx.blake2b, 32, hasher->param, hasher->param_size); - break; - } + sha3_256_Init(&hasher->ctx.sha3); + break; + case HASHER_BLAKE: + case HASHER_BLAKED: + case HASHER_BLAKE_RIPEMD: + blake256_Init(&hasher->ctx.blake); + break; + case HASHER_GROESTLD_TRUNC: + groestl512_Init(&hasher->ctx.groestl); + break; + case HASHER_BLAKE2B: + blake2b_Init(&hasher->ctx.blake2b, 32); + break; + case HASHER_BLAKE2B_PERSONAL: + blake2b_InitPersonal(&hasher->ctx.blake2b, 32, hasher->param, + hasher->param_size); + break; + } } void hasher_Init(Hasher *hasher, HasherType type) { - hasher_InitParam(hasher, type, NULL, 0); + hasher_InitParam(hasher, type, NULL, 0); } void hasher_Reset(Hasher *hasher) { - hasher_InitParam(hasher, hasher->type, hasher->param, hasher->param_size); + hasher_InitParam(hasher, hasher->type, hasher->param, hasher->param_size); } void hasher_Update(Hasher *hasher, const uint8_t *data, size_t length) { - switch (hasher->type) { - case HASHER_SHA2: - case HASHER_SHA2D: - case HASHER_SHA2_RIPEMD: - sha256_Update(&hasher->ctx.sha2, data, length); - break; - case HASHER_SHA3: + switch (hasher->type) { + case HASHER_SHA2: + case HASHER_SHA2D: + case HASHER_SHA2_RIPEMD: + sha256_Update(&hasher->ctx.sha2, data, length); + break; + case HASHER_SHA3: #if USE_KECCAK - case HASHER_SHA3K: + case HASHER_SHA3K: #endif - sha3_Update(&hasher->ctx.sha3, data, length); - break; - case HASHER_BLAKE: - case HASHER_BLAKED: - case HASHER_BLAKE_RIPEMD: - blake256_Update(&hasher->ctx.blake, data, length); - break; - case HASHER_GROESTLD_TRUNC: - groestl512_Update(&hasher->ctx.groestl, data, length); - break; - case HASHER_BLAKE2B: - case HASHER_BLAKE2B_PERSONAL: - blake2b_Update(&hasher->ctx.blake2b, data, length); - break; - } + sha3_Update(&hasher->ctx.sha3, data, length); + break; + case HASHER_BLAKE: + case HASHER_BLAKED: + case HASHER_BLAKE_RIPEMD: + blake256_Update(&hasher->ctx.blake, data, length); + break; + case HASHER_GROESTLD_TRUNC: + groestl512_Update(&hasher->ctx.groestl, data, length); + break; + case HASHER_BLAKE2B: + case HASHER_BLAKE2B_PERSONAL: + blake2b_Update(&hasher->ctx.blake2b, data, length); + break; + } } void hasher_Final(Hasher *hasher, uint8_t hash[HASHER_DIGEST_LENGTH]) { - switch (hasher->type) { - case HASHER_SHA2: - sha256_Final(&hasher->ctx.sha2, hash); - break; - case HASHER_SHA2D: - sha256_Final(&hasher->ctx.sha2, hash); - hasher_Raw(HASHER_SHA2, hash, HASHER_DIGEST_LENGTH, hash); - break; - case HASHER_SHA2_RIPEMD: - sha256_Final(&hasher->ctx.sha2, hash); - ripemd160(hash, HASHER_DIGEST_LENGTH, hash); - break; - case HASHER_SHA3: - sha3_Final(&hasher->ctx.sha3, hash); - break; + switch (hasher->type) { + case HASHER_SHA2: + sha256_Final(&hasher->ctx.sha2, hash); + break; + case HASHER_SHA2D: + sha256_Final(&hasher->ctx.sha2, hash); + hasher_Raw(HASHER_SHA2, hash, HASHER_DIGEST_LENGTH, hash); + break; + case HASHER_SHA2_RIPEMD: + sha256_Final(&hasher->ctx.sha2, hash); + ripemd160(hash, HASHER_DIGEST_LENGTH, hash); + break; + case HASHER_SHA3: + sha3_Final(&hasher->ctx.sha3, hash); + break; #if USE_KECCAK - case HASHER_SHA3K: - keccak_Final(&hasher->ctx.sha3, hash); - break; + case HASHER_SHA3K: + keccak_Final(&hasher->ctx.sha3, hash); + break; #endif - case HASHER_BLAKE: - blake256_Final(&hasher->ctx.blake, hash); - break; - case HASHER_BLAKED: - blake256_Final(&hasher->ctx.blake, hash); - hasher_Raw(HASHER_BLAKE, hash, HASHER_DIGEST_LENGTH, hash); - break; - case HASHER_BLAKE_RIPEMD: - blake256_Final(&hasher->ctx.blake, hash); - ripemd160(hash, HASHER_DIGEST_LENGTH, hash); - break; - case HASHER_GROESTLD_TRUNC: - groestl512_DoubleTrunc(&hasher->ctx.groestl, hash); - break; - case HASHER_BLAKE2B: - case HASHER_BLAKE2B_PERSONAL: - blake2b_Final(&hasher->ctx.blake2b, hash, 32); - break; - } + case HASHER_BLAKE: + blake256_Final(&hasher->ctx.blake, hash); + break; + case HASHER_BLAKED: + blake256_Final(&hasher->ctx.blake, hash); + hasher_Raw(HASHER_BLAKE, hash, HASHER_DIGEST_LENGTH, hash); + break; + case HASHER_BLAKE_RIPEMD: + blake256_Final(&hasher->ctx.blake, hash); + ripemd160(hash, HASHER_DIGEST_LENGTH, hash); + break; + case HASHER_GROESTLD_TRUNC: + groestl512_DoubleTrunc(&hasher->ctx.groestl, hash); + break; + case HASHER_BLAKE2B: + case HASHER_BLAKE2B_PERSONAL: + blake2b_Final(&hasher->ctx.blake2b, hash, 32); + break; + } } -void hasher_Raw(HasherType type, const uint8_t *data, size_t length, uint8_t hash[HASHER_DIGEST_LENGTH]) { - Hasher hasher; +void hasher_Raw(HasherType type, const uint8_t *data, size_t length, + uint8_t hash[HASHER_DIGEST_LENGTH]) { + Hasher hasher; - hasher_Init(&hasher, type); - hasher_Update(&hasher, data, length); - hasher_Final(&hasher, hash); + hasher_Init(&hasher, type); + hasher_Update(&hasher, data, length); + hasher_Final(&hasher, hash); } diff --git a/hasher.h b/hasher.h index 0cde1df8b..8d9c20364 100644 --- a/hasher.h +++ b/hasher.h @@ -26,55 +26,57 @@ #include #include -#include "sha2.h" -#include "sha3.h" #include "blake256.h" -#include "groestl.h" #include "blake2b.h" +#include "groestl.h" +#include "sha2.h" +#include "sha3.h" #define HASHER_DIGEST_LENGTH 32 typedef enum { - HASHER_SHA2, - HASHER_SHA2D, - HASHER_SHA2_RIPEMD, + HASHER_SHA2, + HASHER_SHA2D, + HASHER_SHA2_RIPEMD, - HASHER_SHA3, + HASHER_SHA3, #if USE_KECCAK - HASHER_SHA3K, + HASHER_SHA3K, #endif - HASHER_BLAKE, - HASHER_BLAKED, - HASHER_BLAKE_RIPEMD, + HASHER_BLAKE, + HASHER_BLAKED, + HASHER_BLAKE_RIPEMD, - HASHER_GROESTLD_TRUNC, /* Double Groestl512 hasher truncated to 256 bits */ + HASHER_GROESTLD_TRUNC, /* Double Groestl512 hasher truncated to 256 bits */ - HASHER_BLAKE2B, - HASHER_BLAKE2B_PERSONAL, + HASHER_BLAKE2B, + HASHER_BLAKE2B_PERSONAL, } HasherType; typedef struct { - HasherType type; + HasherType type; - union { - SHA256_CTX sha2; // for HASHER_SHA2{,D} - SHA3_CTX sha3; // for HASHER_SHA3{,K} - BLAKE256_CTX blake; // for HASHER_BLAKE{,D} - GROESTL512_CTX groestl; // for HASHER_GROESTLD_TRUNC - BLAKE2B_CTX blake2b; // for HASHER_BLAKE2B{,_PERSONAL} - } ctx; + union { + SHA256_CTX sha2; // for HASHER_SHA2{,D} + SHA3_CTX sha3; // for HASHER_SHA3{,K} + BLAKE256_CTX blake; // for HASHER_BLAKE{,D} + GROESTL512_CTX groestl; // for HASHER_GROESTLD_TRUNC + BLAKE2B_CTX blake2b; // for HASHER_BLAKE2B{,_PERSONAL} + } ctx; - const void *param; - uint32_t param_size; + const void *param; + uint32_t param_size; } Hasher; -void hasher_InitParam(Hasher *hasher, HasherType type, const void *param, uint32_t param_size); +void hasher_InitParam(Hasher *hasher, HasherType type, const void *param, + uint32_t param_size); void hasher_Init(Hasher *hasher, HasherType type); void hasher_Reset(Hasher *hasher); void hasher_Update(Hasher *hasher, const uint8_t *data, size_t length); void hasher_Final(Hasher *hasher, uint8_t hash[HASHER_DIGEST_LENGTH]); -void hasher_Raw(HasherType type, const uint8_t *data, size_t length, uint8_t hash[HASHER_DIGEST_LENGTH]); +void hasher_Raw(HasherType type, const uint8_t *data, size_t length, + uint8_t hash[HASHER_DIGEST_LENGTH]); #endif diff --git a/hmac.c b/hmac.c index 0a0946012..fa2b68947 100644 --- a/hmac.c +++ b/hmac.c @@ -24,155 +24,153 @@ #include #include "hmac.h" -#include "options.h" #include "memzero.h" +#include "options.h" -void hmac_sha256_Init(HMAC_SHA256_CTX *hctx, const uint8_t *key, const uint32_t keylen) -{ - static CONFIDENTIAL uint8_t i_key_pad[SHA256_BLOCK_LENGTH]; - memzero(i_key_pad, SHA256_BLOCK_LENGTH); - if (keylen > SHA256_BLOCK_LENGTH) { - sha256_Raw(key, keylen, i_key_pad); - } else { - memcpy(i_key_pad, key, keylen); - } - for (int i = 0; i < SHA256_BLOCK_LENGTH; i++) { - hctx->o_key_pad[i] = i_key_pad[i] ^ 0x5c; - i_key_pad[i] ^= 0x36; - } - sha256_Init(&(hctx->ctx)); - sha256_Update(&(hctx->ctx), i_key_pad, SHA256_BLOCK_LENGTH); - memzero(i_key_pad, sizeof(i_key_pad)); +void hmac_sha256_Init(HMAC_SHA256_CTX *hctx, const uint8_t *key, + const uint32_t keylen) { + static CONFIDENTIAL uint8_t i_key_pad[SHA256_BLOCK_LENGTH]; + memzero(i_key_pad, SHA256_BLOCK_LENGTH); + if (keylen > SHA256_BLOCK_LENGTH) { + sha256_Raw(key, keylen, i_key_pad); + } else { + memcpy(i_key_pad, key, keylen); + } + for (int i = 0; i < SHA256_BLOCK_LENGTH; i++) { + hctx->o_key_pad[i] = i_key_pad[i] ^ 0x5c; + i_key_pad[i] ^= 0x36; + } + sha256_Init(&(hctx->ctx)); + sha256_Update(&(hctx->ctx), i_key_pad, SHA256_BLOCK_LENGTH); + memzero(i_key_pad, sizeof(i_key_pad)); } -void hmac_sha256_Update(HMAC_SHA256_CTX *hctx, const uint8_t *msg, const uint32_t msglen) -{ - sha256_Update(&(hctx->ctx), msg, msglen); +void hmac_sha256_Update(HMAC_SHA256_CTX *hctx, const uint8_t *msg, + const uint32_t msglen) { + sha256_Update(&(hctx->ctx), msg, msglen); } -void hmac_sha256_Final(HMAC_SHA256_CTX *hctx, uint8_t *hmac) -{ - sha256_Final(&(hctx->ctx), hmac); - sha256_Init(&(hctx->ctx)); - sha256_Update(&(hctx->ctx), hctx->o_key_pad, SHA256_BLOCK_LENGTH); - sha256_Update(&(hctx->ctx), hmac, SHA256_DIGEST_LENGTH); - sha256_Final(&(hctx->ctx), hmac); - memzero(hctx, sizeof(HMAC_SHA256_CTX)); +void hmac_sha256_Final(HMAC_SHA256_CTX *hctx, uint8_t *hmac) { + sha256_Final(&(hctx->ctx), hmac); + sha256_Init(&(hctx->ctx)); + sha256_Update(&(hctx->ctx), hctx->o_key_pad, SHA256_BLOCK_LENGTH); + sha256_Update(&(hctx->ctx), hmac, SHA256_DIGEST_LENGTH); + sha256_Final(&(hctx->ctx), hmac); + memzero(hctx, sizeof(HMAC_SHA256_CTX)); } -void hmac_sha256(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, const uint32_t msglen, uint8_t *hmac) -{ - static CONFIDENTIAL HMAC_SHA256_CTX hctx; - hmac_sha256_Init(&hctx, key, keylen); - hmac_sha256_Update(&hctx, msg, msglen); - hmac_sha256_Final(&hctx, hmac); +void hmac_sha256(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, + const uint32_t msglen, uint8_t *hmac) { + static CONFIDENTIAL HMAC_SHA256_CTX hctx; + hmac_sha256_Init(&hctx, key, keylen); + hmac_sha256_Update(&hctx, msg, msglen); + hmac_sha256_Final(&hctx, hmac); } -void hmac_sha256_prepare(const uint8_t *key, const uint32_t keylen, uint32_t *opad_digest, uint32_t *ipad_digest) -{ - static CONFIDENTIAL uint32_t key_pad[SHA256_BLOCK_LENGTH/sizeof(uint32_t)]; - - memzero(key_pad, sizeof(key_pad)); - if (keylen > SHA256_BLOCK_LENGTH) { - static CONFIDENTIAL SHA256_CTX context; - sha256_Init(&context); - sha256_Update(&context, key, keylen); - sha256_Final(&context, (uint8_t*)key_pad); - } else { - memcpy(key_pad, key, keylen); - } - - /* compute o_key_pad and its digest */ - for (int i = 0; i < SHA256_BLOCK_LENGTH/(int)sizeof(uint32_t); i++) { - uint32_t data; +void hmac_sha256_prepare(const uint8_t *key, const uint32_t keylen, + uint32_t *opad_digest, uint32_t *ipad_digest) { + static CONFIDENTIAL uint32_t key_pad[SHA256_BLOCK_LENGTH / sizeof(uint32_t)]; + + memzero(key_pad, sizeof(key_pad)); + if (keylen > SHA256_BLOCK_LENGTH) { + static CONFIDENTIAL SHA256_CTX context; + sha256_Init(&context); + sha256_Update(&context, key, keylen); + sha256_Final(&context, (uint8_t *)key_pad); + } else { + memcpy(key_pad, key, keylen); + } + + /* compute o_key_pad and its digest */ + for (int i = 0; i < SHA256_BLOCK_LENGTH / (int)sizeof(uint32_t); i++) { + uint32_t data; #if BYTE_ORDER == LITTLE_ENDIAN - REVERSE32(key_pad[i], data); + REVERSE32(key_pad[i], data); #else - data = key_pad[i]; + data = key_pad[i]; #endif - key_pad[i] = data ^ 0x5c5c5c5c; - } - sha256_Transform(sha256_initial_hash_value, key_pad, opad_digest); - - /* convert o_key_pad to i_key_pad and compute its digest */ - for (int i = 0; i < SHA256_BLOCK_LENGTH/(int)sizeof(uint32_t); i++) { - key_pad[i] = key_pad[i] ^ 0x5c5c5c5c ^ 0x36363636; - } - sha256_Transform(sha256_initial_hash_value, key_pad, ipad_digest); - memzero(key_pad, sizeof(key_pad)); + key_pad[i] = data ^ 0x5c5c5c5c; + } + sha256_Transform(sha256_initial_hash_value, key_pad, opad_digest); + + /* convert o_key_pad to i_key_pad and compute its digest */ + for (int i = 0; i < SHA256_BLOCK_LENGTH / (int)sizeof(uint32_t); i++) { + key_pad[i] = key_pad[i] ^ 0x5c5c5c5c ^ 0x36363636; + } + sha256_Transform(sha256_initial_hash_value, key_pad, ipad_digest); + memzero(key_pad, sizeof(key_pad)); } -void hmac_sha512_Init(HMAC_SHA512_CTX *hctx, const uint8_t *key, const uint32_t keylen) -{ - static CONFIDENTIAL uint8_t i_key_pad[SHA512_BLOCK_LENGTH]; - memzero(i_key_pad, SHA512_BLOCK_LENGTH); - if (keylen > SHA512_BLOCK_LENGTH) { - sha512_Raw(key, keylen, i_key_pad); - } else { - memcpy(i_key_pad, key, keylen); - } - for (int i = 0; i < SHA512_BLOCK_LENGTH; i++) { - hctx->o_key_pad[i] = i_key_pad[i] ^ 0x5c; - i_key_pad[i] ^= 0x36; - } - sha512_Init(&(hctx->ctx)); - sha512_Update(&(hctx->ctx), i_key_pad, SHA512_BLOCK_LENGTH); - memzero(i_key_pad, sizeof(i_key_pad)); +void hmac_sha512_Init(HMAC_SHA512_CTX *hctx, const uint8_t *key, + const uint32_t keylen) { + static CONFIDENTIAL uint8_t i_key_pad[SHA512_BLOCK_LENGTH]; + memzero(i_key_pad, SHA512_BLOCK_LENGTH); + if (keylen > SHA512_BLOCK_LENGTH) { + sha512_Raw(key, keylen, i_key_pad); + } else { + memcpy(i_key_pad, key, keylen); + } + for (int i = 0; i < SHA512_BLOCK_LENGTH; i++) { + hctx->o_key_pad[i] = i_key_pad[i] ^ 0x5c; + i_key_pad[i] ^= 0x36; + } + sha512_Init(&(hctx->ctx)); + sha512_Update(&(hctx->ctx), i_key_pad, SHA512_BLOCK_LENGTH); + memzero(i_key_pad, sizeof(i_key_pad)); } -void hmac_sha512_Update(HMAC_SHA512_CTX *hctx, const uint8_t *msg, const uint32_t msglen) -{ - sha512_Update(&(hctx->ctx), msg, msglen); +void hmac_sha512_Update(HMAC_SHA512_CTX *hctx, const uint8_t *msg, + const uint32_t msglen) { + sha512_Update(&(hctx->ctx), msg, msglen); } -void hmac_sha512_Final(HMAC_SHA512_CTX *hctx, uint8_t *hmac) -{ - sha512_Final(&(hctx->ctx), hmac); - sha512_Init(&(hctx->ctx)); - sha512_Update(&(hctx->ctx), hctx->o_key_pad, SHA512_BLOCK_LENGTH); - sha512_Update(&(hctx->ctx), hmac, SHA512_DIGEST_LENGTH); - sha512_Final(&(hctx->ctx), hmac); - memzero(hctx, sizeof(HMAC_SHA512_CTX)); +void hmac_sha512_Final(HMAC_SHA512_CTX *hctx, uint8_t *hmac) { + sha512_Final(&(hctx->ctx), hmac); + sha512_Init(&(hctx->ctx)); + sha512_Update(&(hctx->ctx), hctx->o_key_pad, SHA512_BLOCK_LENGTH); + sha512_Update(&(hctx->ctx), hmac, SHA512_DIGEST_LENGTH); + sha512_Final(&(hctx->ctx), hmac); + memzero(hctx, sizeof(HMAC_SHA512_CTX)); } -void hmac_sha512(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, const uint32_t msglen, uint8_t *hmac) -{ - HMAC_SHA512_CTX hctx; - hmac_sha512_Init(&hctx, key, keylen); - hmac_sha512_Update(&hctx, msg, msglen); - hmac_sha512_Final(&hctx, hmac); +void hmac_sha512(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, + const uint32_t msglen, uint8_t *hmac) { + HMAC_SHA512_CTX hctx; + hmac_sha512_Init(&hctx, key, keylen); + hmac_sha512_Update(&hctx, msg, msglen); + hmac_sha512_Final(&hctx, hmac); } -void hmac_sha512_prepare(const uint8_t *key, const uint32_t keylen, uint64_t *opad_digest, uint64_t *ipad_digest) -{ - static CONFIDENTIAL uint64_t key_pad[SHA512_BLOCK_LENGTH/sizeof(uint64_t)]; - - memzero(key_pad, sizeof(key_pad)); - if (keylen > SHA512_BLOCK_LENGTH) { - static CONFIDENTIAL SHA512_CTX context; - sha512_Init(&context); - sha512_Update(&context, key, keylen); - sha512_Final(&context, (uint8_t*)key_pad); - } else { - memcpy(key_pad, key, keylen); - } - - /* compute o_key_pad and its digest */ - for (int i = 0; i < SHA512_BLOCK_LENGTH/(int)sizeof(uint64_t); i++) { - uint64_t data; +void hmac_sha512_prepare(const uint8_t *key, const uint32_t keylen, + uint64_t *opad_digest, uint64_t *ipad_digest) { + static CONFIDENTIAL uint64_t key_pad[SHA512_BLOCK_LENGTH / sizeof(uint64_t)]; + + memzero(key_pad, sizeof(key_pad)); + if (keylen > SHA512_BLOCK_LENGTH) { + static CONFIDENTIAL SHA512_CTX context; + sha512_Init(&context); + sha512_Update(&context, key, keylen); + sha512_Final(&context, (uint8_t *)key_pad); + } else { + memcpy(key_pad, key, keylen); + } + + /* compute o_key_pad and its digest */ + for (int i = 0; i < SHA512_BLOCK_LENGTH / (int)sizeof(uint64_t); i++) { + uint64_t data; #if BYTE_ORDER == LITTLE_ENDIAN - REVERSE64(key_pad[i], data); + REVERSE64(key_pad[i], data); #else - data = key_pad[i]; + data = key_pad[i]; #endif - key_pad[i] = data ^ 0x5c5c5c5c5c5c5c5c; - } - sha512_Transform(sha512_initial_hash_value, key_pad, opad_digest); - - /* convert o_key_pad to i_key_pad and compute its digest */ - for (int i = 0; i < SHA512_BLOCK_LENGTH/(int)sizeof(uint64_t); i++) { - key_pad[i] = key_pad[i] ^ 0x5c5c5c5c5c5c5c5c ^ 0x3636363636363636; - } - sha512_Transform(sha512_initial_hash_value, key_pad, ipad_digest); - memzero(key_pad, sizeof(key_pad)); + key_pad[i] = data ^ 0x5c5c5c5c5c5c5c5c; + } + sha512_Transform(sha512_initial_hash_value, key_pad, opad_digest); + + /* convert o_key_pad to i_key_pad and compute its digest */ + for (int i = 0; i < SHA512_BLOCK_LENGTH / (int)sizeof(uint64_t); i++) { + key_pad[i] = key_pad[i] ^ 0x5c5c5c5c5c5c5c5c ^ 0x3636363636363636; + } + sha512_Transform(sha512_initial_hash_value, key_pad, ipad_digest); + memzero(key_pad, sizeof(key_pad)); } diff --git a/hmac.h b/hmac.h index 3cfc0cd0f..3921a171e 100644 --- a/hmac.h +++ b/hmac.h @@ -28,25 +28,33 @@ #include "sha2.h" typedef struct _HMAC_SHA256_CTX { - uint8_t o_key_pad[SHA256_BLOCK_LENGTH]; - SHA256_CTX ctx; + uint8_t o_key_pad[SHA256_BLOCK_LENGTH]; + SHA256_CTX ctx; } HMAC_SHA256_CTX; typedef struct _HMAC_SHA512_CTX { - uint8_t o_key_pad[SHA512_BLOCK_LENGTH]; - SHA512_CTX ctx; + uint8_t o_key_pad[SHA512_BLOCK_LENGTH]; + SHA512_CTX ctx; } HMAC_SHA512_CTX; -void hmac_sha256_Init(HMAC_SHA256_CTX *hctx, const uint8_t *key, const uint32_t keylen); -void hmac_sha256_Update(HMAC_SHA256_CTX *hctx, const uint8_t *msg, const uint32_t msglen); +void hmac_sha256_Init(HMAC_SHA256_CTX *hctx, const uint8_t *key, + const uint32_t keylen); +void hmac_sha256_Update(HMAC_SHA256_CTX *hctx, const uint8_t *msg, + const uint32_t msglen); void hmac_sha256_Final(HMAC_SHA256_CTX *hctx, uint8_t *hmac); -void hmac_sha256(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, const uint32_t msglen, uint8_t *hmac); -void hmac_sha256_prepare(const uint8_t *key, const uint32_t keylen, uint32_t *opad_digest, uint32_t *ipad_digest); +void hmac_sha256(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, + const uint32_t msglen, uint8_t *hmac); +void hmac_sha256_prepare(const uint8_t *key, const uint32_t keylen, + uint32_t *opad_digest, uint32_t *ipad_digest); -void hmac_sha512_Init(HMAC_SHA512_CTX *hctx, const uint8_t *key, const uint32_t keylen); -void hmac_sha512_Update(HMAC_SHA512_CTX *hctx, const uint8_t *msg, const uint32_t msglen); +void hmac_sha512_Init(HMAC_SHA512_CTX *hctx, const uint8_t *key, + const uint32_t keylen); +void hmac_sha512_Update(HMAC_SHA512_CTX *hctx, const uint8_t *msg, + const uint32_t msglen); void hmac_sha512_Final(HMAC_SHA512_CTX *hctx, uint8_t *hmac); -void hmac_sha512(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, const uint32_t msglen, uint8_t *hmac); -void hmac_sha512_prepare(const uint8_t *key, const uint32_t keylen, uint64_t *opad_digest, uint64_t *ipad_digest); +void hmac_sha512(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, + const uint32_t msglen, uint8_t *hmac); +void hmac_sha512_prepare(const uint8_t *key, const uint32_t keylen, + uint64_t *opad_digest, uint64_t *ipad_digest); #endif diff --git a/memzero.c b/memzero.c index 3c3a7383d..6a517ff38 100644 --- a/memzero.c +++ b/memzero.c @@ -1,5 +1,5 @@ #ifndef __STDC_WANT_LIB_EXT1__ -#define __STDC_WANT_LIB_EXT1__ 1 // C11's bounds-checking interface. +#define __STDC_WANT_LIB_EXT1__ 1 // C11's bounds-checking interface. #endif #include @@ -18,12 +18,13 @@ #endif // GNU C Library version 2.25 or later. -#if defined(__GLIBC__) && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 25)) +#if defined(__GLIBC__) && \ + (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 25)) #define HAVE_EXPLICIT_BZERO 1 #endif // Newlib -#if defined( __NEWLIB__) +#if defined(__NEWLIB__) #define HAVE_EXPLICIT_BZERO 1 #endif @@ -42,25 +43,24 @@ #define HAVE_EXPLICIT_MEMSET 1 #endif -// Adapted from https://github.com/jedisct1/libsodium/blob/1647f0d53ae0e370378a9195477e3df0a792408f/src/libsodium/sodium/utils.c#L102-L130 +// Adapted from +// https://github.com/jedisct1/libsodium/blob/1647f0d53ae0e370378a9195477e3df0a792408f/src/libsodium/sodium/utils.c#L102-L130 -void memzero(void *const pnt, const size_t len) -{ +void memzero(void *const pnt, const size_t len) { #ifdef _WIN32 - SecureZeroMemory(pnt, len); + SecureZeroMemory(pnt, len); #elif defined(HAVE_MEMSET_S) - memset_s(pnt, (rsize_t) len, 0, (rsize_t) len); + memset_s(pnt, (rsize_t)len, 0, (rsize_t)len); #elif defined(HAVE_EXPLICIT_BZERO) - explicit_bzero(pnt, len); + explicit_bzero(pnt, len); #elif defined(HAVE_EXPLICIT_MEMSET) - explicit_memset(pnt, 0, len); + explicit_memset(pnt, 0, len); #else - volatile unsigned char *volatile pnt_ = - (volatile unsigned char *volatile) pnt; - size_t i = (size_t) 0U; + volatile unsigned char *volatile pnt_ = (volatile unsigned char *volatile)pnt; + size_t i = (size_t)0U; - while (i < len) { - pnt_[i++] = 0U; - } + while (i < len) { + pnt_[i++] = 0U; + } #endif } diff --git a/memzero.h b/memzero.h index a7797d2b3..0a959fbc2 100644 --- a/memzero.h +++ b/memzero.h @@ -3,6 +3,6 @@ #include -void memzero(void * const pnt, const size_t len); +void memzero(void* const pnt, const size_t len); #endif diff --git a/monero/monero.h b/monero/monero.h index d281f333b..ba436c3a3 100644 --- a/monero/monero.h +++ b/monero/monero.h @@ -14,8 +14,8 @@ #endif #include "base58.h" +#include "range_proof.h" #include "serialize.h" #include "xmr.h" -#include "range_proof.h" -#endif //TREZOR_CRYPTO_MONERO_H +#endif // TREZOR_CRYPTO_MONERO_H diff --git a/monero/range_proof.c b/monero/range_proof.c index aaad23dec..832f6f918 100644 --- a/monero/range_proof.c +++ b/monero/range_proof.c @@ -4,112 +4,112 @@ #include "range_proof.h" - -static void xmr_hash_ge25519_to_scalar(bignum256modm r, const ge25519 *p){ - unsigned char buff[32]; - ge25519_pack(buff, p); - xmr_hash_to_scalar(r, buff, sizeof(buff)); +static void xmr_hash_ge25519_to_scalar(bignum256modm r, const ge25519 *p) { + unsigned char buff[32]; + ge25519_pack(buff, p); + xmr_hash_to_scalar(r, buff, sizeof(buff)); } -void xmr_gen_range_sig(xmr_range_sig_t * sig, ge25519 * C, bignum256modm mask, xmr_amount amount, bignum256modm * last_mask){ - bignum256modm ai[64]; - bignum256modm alpha[64]; - xmr_gen_range_sig_ex(sig, C, mask, amount, last_mask, ai, alpha); +void xmr_gen_range_sig(xmr_range_sig_t *sig, ge25519 *C, bignum256modm mask, + xmr_amount amount, bignum256modm *last_mask) { + bignum256modm ai[64]; + bignum256modm alpha[64]; + xmr_gen_range_sig_ex(sig, C, mask, amount, last_mask, ai, alpha); } -void xmr_gen_range_sig_ex(xmr_range_sig_t * sig, ge25519 * C, bignum256modm mask, xmr_amount amount, bignum256modm * last_mask, - bignum256modm ai[64], bignum256modm alpha[64]) -{ - const unsigned n = XMR_ATOMS; - bignum256modm a={0}; - bignum256modm si={0}; - bignum256modm c={0}; - bignum256modm ee={0}; - unsigned char buff[32]; +void xmr_gen_range_sig_ex(xmr_range_sig_t *sig, ge25519 *C, bignum256modm mask, + xmr_amount amount, bignum256modm *last_mask, + bignum256modm ai[64], bignum256modm alpha[64]) { + const unsigned n = XMR_ATOMS; + bignum256modm a = {0}; + bignum256modm si = {0}; + bignum256modm c = {0}; + bignum256modm ee = {0}; + unsigned char buff[32]; - Hasher kck; - xmr_hasher_init(&kck); + Hasher kck; + xmr_hasher_init(&kck); - ge25519 C_acc; - ge25519 C_h; - ge25519 C_tmp; - ge25519 L; - ge25519 Zero; + ge25519 C_acc; + ge25519 C_h; + ge25519 C_tmp; + ge25519 L; + ge25519 Zero; - ge25519_set_neutral(&Zero); - ge25519_set_neutral(&C_acc); - ge25519_set_xmr_h(&C_h); - set256_modm(a, 0); + ge25519_set_neutral(&Zero); + ge25519_set_neutral(&C_acc); + ge25519_set_xmr_h(&C_h); + set256_modm(a, 0); -#define BB(i) ((amount>>(i)) & 1) +#define BB(i) ((amount >> (i)) & 1) - // First pass, generates: ai, alpha, Ci, ee, s1 - for(unsigned ii=0; iiCi[ii], &C_tmp); + // Set Ci[ii] to sigs + ge25519_pack(sig->Ci[ii], &C_tmp); - if (BB(ii) == 0) { - xmr_random_scalar(si); - xmr_hash_ge25519_to_scalar(c, &L); + if (BB(ii) == 0) { + xmr_random_scalar(si); + xmr_hash_ge25519_to_scalar(c, &L); - ge25519_add(&C_tmp, &C_tmp, &C_h, 1); // Ci[ii] -= c_h - xmr_add_keys2_vartime(&L, si, c, &C_tmp); + ge25519_add(&C_tmp, &C_tmp, &C_h, 1); // Ci[ii] -= c_h + xmr_add_keys2_vartime(&L, si, c, &C_tmp); - // Set s1[ii] to sigs - contract256_modm(sig->asig.s1[ii], si); - } + // Set s1[ii] to sigs + contract256_modm(sig->asig.s1[ii], si); + } - ge25519_pack(buff, &L); - xmr_hasher_update(&kck, buff, sizeof(buff)); + ge25519_pack(buff, &L); + xmr_hasher_update(&kck, buff, sizeof(buff)); - ge25519_double(&C_h, &C_h); // c_H = crypto.scalarmult(c_H, 2) - } + ge25519_double(&C_h, &C_h); // c_H = crypto.scalarmult(c_H, 2) + } - // Compute ee - xmr_hasher_final(&kck, buff); - expand256_modm(ee, buff, sizeof(buff)); + // Compute ee + xmr_hasher_final(&kck, buff); + expand256_modm(ee, buff, sizeof(buff)); - ge25519_set_xmr_h(&C_h); + ge25519_set_xmr_h(&C_h); - // Second pass, s0, s1 - for(unsigned ii=0; iiasig.s0[ii], si); + // Second pass, s0, s1 + for (unsigned ii = 0; ii < n; ++ii) { + if (BB(ii) == 0) { + mulsub256_modm(si, ai[ii], ee, alpha[ii]); + contract256_modm(sig->asig.s0[ii], si); - } else { - xmr_random_scalar(si); - contract256_modm(sig->asig.s0[ii], si); + } else { + xmr_random_scalar(si); + contract256_modm(sig->asig.s0[ii], si); - ge25519_unpack_vartime(&C_tmp, sig->Ci[ii]); - xmr_add_keys2_vartime(&L, si, ee, &C_tmp); - xmr_hash_ge25519_to_scalar(c, &L); + ge25519_unpack_vartime(&C_tmp, sig->Ci[ii]); + xmr_add_keys2_vartime(&L, si, ee, &C_tmp); + xmr_hash_ge25519_to_scalar(c, &L); - mulsub256_modm(si, ai[ii], c, alpha[ii]); - contract256_modm(sig->asig.s1[ii], si); - } + mulsub256_modm(si, ai[ii], c, alpha[ii]); + contract256_modm(sig->asig.s1[ii], si); + } - ge25519_double(&C_h, &C_h); // c_H = crypto.scalarmult(c_H, 2) - } + ge25519_double(&C_h, &C_h); // c_H = crypto.scalarmult(c_H, 2) + } - ge25519_copy(C, &C_acc); - copy256_modm(mask, a); - contract256_modm(sig->asig.ee, ee); + ge25519_copy(C, &C_acc); + copy256_modm(mask, a); + contract256_modm(sig->asig.ee, ee); #undef BB } - diff --git a/monero/range_proof.h b/monero/range_proof.h index cd846a095..f614ab04e 100644 --- a/monero/range_proof.h +++ b/monero/range_proof.h @@ -12,19 +12,20 @@ typedef uint64_t xmr_amount; typedef xmr_key_t xmr_key64_t[64]; typedef struct xmr_boro_sig { - xmr_key64_t s0; - xmr_key64_t s1; - xmr_key_t ee; + xmr_key64_t s0; + xmr_key64_t s1; + xmr_key_t ee; } xmr_boro_sig_t; typedef struct range_sig { - xmr_boro_sig_t asig; - xmr_key64_t Ci; + xmr_boro_sig_t asig; + xmr_key64_t Ci; } xmr_range_sig_t; - -void xmr_gen_range_sig(xmr_range_sig_t * sig, ge25519 * C, bignum256modm mask, xmr_amount amount, bignum256modm * last_mask); -void xmr_gen_range_sig_ex(xmr_range_sig_t * sig, ge25519 * C, bignum256modm mask, xmr_amount amount, bignum256modm * last_mask, +void xmr_gen_range_sig(xmr_range_sig_t* sig, ge25519* C, bignum256modm mask, + xmr_amount amount, bignum256modm* last_mask); +void xmr_gen_range_sig_ex(xmr_range_sig_t* sig, ge25519* C, bignum256modm mask, + xmr_amount amount, bignum256modm* last_mask, bignum256modm ai[64], bignum256modm alpha[64]); -#endif //TREZOR_CRYPTO_RANGE_PROOF_H +#endif // TREZOR_CRYPTO_RANGE_PROOF_H diff --git a/monero/serialize.c b/monero/serialize.c index ee6aab420..ebd323b93 100644 --- a/monero/serialize.c +++ b/monero/serialize.c @@ -4,51 +4,50 @@ #include "serialize.h" -int xmr_size_varint(uint64_t num){ - int ctr = 1; - while (num >= 0x80) { - ++ctr; - num >>= 7; - } - return ctr; +int xmr_size_varint(uint64_t num) { + int ctr = 1; + while (num >= 0x80) { + ++ctr; + num >>= 7; + } + return ctr; } -int xmr_write_varint(uint8_t * buff, size_t buff_size, uint64_t num){ - unsigned ctr = 0; - while (num >= 0x80 && ctr < buff_size) { - *buff = (uint8_t) (((num) & 0x7f) | 0x80); - ++buff; - ++ctr; - num >>= 7; - } - - /* writes the last one to dest */ - if (ctr < buff_size) { - *buff = (uint8_t) num; - ++ctr; - } - return ctr <= buff_size ? (int)ctr : -1; +int xmr_write_varint(uint8_t *buff, size_t buff_size, uint64_t num) { + unsigned ctr = 0; + while (num >= 0x80 && ctr < buff_size) { + *buff = (uint8_t)(((num)&0x7f) | 0x80); + ++buff; + ++ctr; + num >>= 7; + } + + /* writes the last one to dest */ + if (ctr < buff_size) { + *buff = (uint8_t)num; + ++ctr; + } + return ctr <= buff_size ? (int)ctr : -1; } -int xmr_read_varint(uint8_t * buff, size_t buff_size, uint64_t *val) { - unsigned read = 0; - int finished_ok = 0; - *val = 0; - - for (int shift = 0; read < buff_size; shift += 7, ++read) { - uint8_t byte = buff[read]; - if (byte == 0 && shift != 0) { - return -1; - } - - *val |= (uint64_t)(byte & 0x7f) << shift; - - /* If there is no next */ - if ((byte & 0x80) == 0) { - finished_ok = 1; - break; - } - } - return finished_ok ? (int)read + 1 : -2; +int xmr_read_varint(uint8_t *buff, size_t buff_size, uint64_t *val) { + unsigned read = 0; + int finished_ok = 0; + *val = 0; + + for (int shift = 0; read < buff_size; shift += 7, ++read) { + uint8_t byte = buff[read]; + if (byte == 0 && shift != 0) { + return -1; + } + + *val |= (uint64_t)(byte & 0x7f) << shift; + + /* If there is no next */ + if ((byte & 0x80) == 0) { + finished_ok = 1; + break; + } + } + return finished_ok ? (int)read + 1 : -2; } - diff --git a/monero/serialize.h b/monero/serialize.h index f2b0fb903..8d3499007 100644 --- a/monero/serialize.h +++ b/monero/serialize.h @@ -9,7 +9,7 @@ #include int xmr_size_varint(uint64_t num); -int xmr_write_varint(uint8_t * buff, size_t buff_size, uint64_t num); -int xmr_read_varint(uint8_t * buff, size_t buff_size, uint64_t *val); +int xmr_write_varint(uint8_t *buff, size_t buff_size, uint64_t num); +int xmr_read_varint(uint8_t *buff, size_t buff_size, uint64_t *val); -#endif //TREZOR_XMR_SERIALIZE_H +#endif // TREZOR_XMR_SERIALIZE_H diff --git a/monero/xmr.c b/monero/xmr.c index 7a3576348..25199b1b1 100644 --- a/monero/xmr.c +++ b/monero/xmr.c @@ -4,133 +4,140 @@ #include "xmr.h" #include "int-util.h" -#include "serialize.h" #include "rand.h" - +#include "serialize.h" const ge25519 ALIGN(16) xmr_h = { - {0x1861ec7, 0x1ceac77, 0x2f11626, 0x1f261d3, 0x346107c, 0x06d8c4a, 0x254201d, 0x1675c09, 0x1301c3f, 0x0211d73}, - {0x326feb4, 0x12e30cc, 0x0cf54b4, 0x1117305, 0x318f5d5, 0x06cf754, 0x2e578a1, 0x1daf058, 0x34430a1, 0x04410e9}, - {0x0fde4d2, 0x0774049, 0x22ca951, 0x05aec2b, 0x07a36a5, 0x1394f13, 0x3c5385c, 0x1adb924, 0x2b6c581, 0x0a55fa4}, - {0x24517f7, 0x05ee936, 0x3acf5d9, 0x14b08aa, 0x3363738, 0x1051745, 0x360601e, 0x0f3f2c9, 0x1ead2cd, 0x1d3e3df} -}; + {0x1861ec7, 0x1ceac77, 0x2f11626, 0x1f261d3, 0x346107c, 0x06d8c4a, + 0x254201d, 0x1675c09, 0x1301c3f, 0x0211d73}, + {0x326feb4, 0x12e30cc, 0x0cf54b4, 0x1117305, 0x318f5d5, 0x06cf754, + 0x2e578a1, 0x1daf058, 0x34430a1, 0x04410e9}, + {0x0fde4d2, 0x0774049, 0x22ca951, 0x05aec2b, 0x07a36a5, 0x1394f13, + 0x3c5385c, 0x1adb924, 0x2b6c581, 0x0a55fa4}, + {0x24517f7, 0x05ee936, 0x3acf5d9, 0x14b08aa, 0x3363738, 0x1051745, + 0x360601e, 0x0f3f2c9, 0x1ead2cd, 0x1d3e3df}}; +void ge25519_set_xmr_h(ge25519 *r) { ge25519_copy(r, &xmr_h); } -void ge25519_set_xmr_h(ge25519 *r){ - ge25519_copy(r, &xmr_h); +void xmr_random_scalar(bignum256modm m) { + unsigned char buff[32] = {0}; + random_buffer(buff, sizeof(buff)); + expand256_modm(m, buff, sizeof(buff)); } -void xmr_random_scalar(bignum256modm m){ - unsigned char buff[32]={0}; - random_buffer(buff, sizeof(buff)); - expand256_modm(m, buff, sizeof(buff)); +void xmr_fast_hash(uint8_t *hash, const void *data, size_t length) { + hasher_Raw(HASHER_SHA3K, data, length, hash); } -void xmr_fast_hash(uint8_t * hash, const void *data, size_t length){ - hasher_Raw(HASHER_SHA3K, data, length, hash); -} - -void xmr_hasher_init(Hasher * hasher){ - hasher_Init(hasher, HASHER_SHA3K); -} +void xmr_hasher_init(Hasher *hasher) { hasher_Init(hasher, HASHER_SHA3K); } -void xmr_hasher_update(Hasher * hasher, const void *data, size_t length){ - hasher_Update(hasher, data, length); +void xmr_hasher_update(Hasher *hasher, const void *data, size_t length) { + hasher_Update(hasher, data, length); } -void xmr_hasher_final(Hasher * hasher, uint8_t * hash){ - hasher_Final(hasher, hash); +void xmr_hasher_final(Hasher *hasher, uint8_t *hash) { + hasher_Final(hasher, hash); } -void xmr_hasher_copy(Hasher * dst, const Hasher * src){ - memcpy(dst, src, sizeof(Hasher)); +void xmr_hasher_copy(Hasher *dst, const Hasher *src) { + memcpy(dst, src, sizeof(Hasher)); } -void xmr_hash_to_scalar(bignum256modm r, const void *data, size_t length){ - uint8_t hash[HASHER_DIGEST_LENGTH]; - hasher_Raw(HASHER_SHA3K, data, length, hash); - expand256_modm(r, hash, HASHER_DIGEST_LENGTH); +void xmr_hash_to_scalar(bignum256modm r, const void *data, size_t length) { + uint8_t hash[HASHER_DIGEST_LENGTH]; + hasher_Raw(HASHER_SHA3K, data, length, hash); + expand256_modm(r, hash, HASHER_DIGEST_LENGTH); } -void xmr_hash_to_ec(ge25519 *P, const void *data, size_t length){ - ge25519 point2; - uint8_t hash[HASHER_DIGEST_LENGTH]; - hasher_Raw(HASHER_SHA3K, data, length, hash); +void xmr_hash_to_ec(ge25519 *P, const void *data, size_t length) { + ge25519 point2; + uint8_t hash[HASHER_DIGEST_LENGTH]; + hasher_Raw(HASHER_SHA3K, data, length, hash); - ge25519_fromfe_frombytes_vartime(&point2, hash); - ge25519_mul8(P, &point2); + ge25519_fromfe_frombytes_vartime(&point2, hash); + ge25519_mul8(P, &point2); } -void xmr_derivation_to_scalar(bignum256modm s, const ge25519 * p, uint32_t output_index){ - uint8_t buff[32 + 8]; - ge25519_pack(buff, p); - int written = xmr_write_varint(buff + 32, 8, output_index); - xmr_hash_to_scalar(s, buff, 32u + written); +void xmr_derivation_to_scalar(bignum256modm s, const ge25519 *p, + uint32_t output_index) { + uint8_t buff[32 + 8]; + ge25519_pack(buff, p); + int written = xmr_write_varint(buff + 32, 8, output_index); + xmr_hash_to_scalar(s, buff, 32u + written); } -void xmr_generate_key_derivation(ge25519 * r, const ge25519 * A, const bignum256modm b){ - ge25519 bA; - ge25519_scalarmult(&bA, A, b); - ge25519_mul8(r, &bA); +void xmr_generate_key_derivation(ge25519 *r, const ge25519 *A, + const bignum256modm b) { + ge25519 bA; + ge25519_scalarmult(&bA, A, b); + ge25519_mul8(r, &bA); } -void xmr_derive_private_key(bignum256modm s, const ge25519 * deriv, uint32_t idx, const bignum256modm base){ - xmr_derivation_to_scalar(s, deriv, idx); - add256_modm(s, s, base); +void xmr_derive_private_key(bignum256modm s, const ge25519 *deriv, uint32_t idx, + const bignum256modm base) { + xmr_derivation_to_scalar(s, deriv, idx); + add256_modm(s, s, base); } -void xmr_derive_public_key(ge25519 * r, const ge25519 * deriv, uint32_t idx, const ge25519 * base){ - bignum256modm s={0}; - ge25519 p2; +void xmr_derive_public_key(ge25519 *r, const ge25519 *deriv, uint32_t idx, + const ge25519 *base) { + bignum256modm s = {0}; + ge25519 p2; - xmr_derivation_to_scalar(s, deriv, idx); - ge25519_scalarmult_base_niels(&p2, ge25519_niels_base_multiples, s); - ge25519_add(r, base, &p2, 0); + xmr_derivation_to_scalar(s, deriv, idx); + ge25519_scalarmult_base_niels(&p2, ge25519_niels_base_multiples, s); + ge25519_add(r, base, &p2, 0); } -void xmr_add_keys2(ge25519 * r, const bignum256modm a, const bignum256modm b, const ge25519 * B){ - // aG + bB, G is basepoint - ge25519 aG, bB; - ge25519_scalarmult_base_niels(&aG, ge25519_niels_base_multiples, a); - ge25519_scalarmult(&bB, B, b); - ge25519_add(r, &aG, &bB, 0); +void xmr_add_keys2(ge25519 *r, const bignum256modm a, const bignum256modm b, + const ge25519 *B) { + // aG + bB, G is basepoint + ge25519 aG, bB; + ge25519_scalarmult_base_niels(&aG, ge25519_niels_base_multiples, a); + ge25519_scalarmult(&bB, B, b); + ge25519_add(r, &aG, &bB, 0); } -void xmr_add_keys2_vartime(ge25519 * r, const bignum256modm a, const bignum256modm b, const ge25519 * B){ - // aG + bB, G is basepoint - ge25519_double_scalarmult_vartime(r, B, b, a); +void xmr_add_keys2_vartime(ge25519 *r, const bignum256modm a, + const bignum256modm b, const ge25519 *B) { + // aG + bB, G is basepoint + ge25519_double_scalarmult_vartime(r, B, b, a); } -void xmr_add_keys3(ge25519 * r, const bignum256modm a, const ge25519 * A, const bignum256modm b, const ge25519 * B){ - // aA + bB - ge25519 aA, bB; - ge25519_scalarmult(&aA, A, a); - ge25519_scalarmult(&bB, B, b); - ge25519_add(r, &aA, &bB, 0); +void xmr_add_keys3(ge25519 *r, const bignum256modm a, const ge25519 *A, + const bignum256modm b, const ge25519 *B) { + // aA + bB + ge25519 aA, bB; + ge25519_scalarmult(&aA, A, a); + ge25519_scalarmult(&bB, B, b); + ge25519_add(r, &aA, &bB, 0); } -void xmr_add_keys3_vartime(ge25519 * r, const bignum256modm a, const ge25519 * A, const bignum256modm b, const ge25519 * B){ - // aA + bB - ge25519_double_scalarmult_vartime2(r, A, a, B, b); +void xmr_add_keys3_vartime(ge25519 *r, const bignum256modm a, const ge25519 *A, + const bignum256modm b, const ge25519 *B) { + // aA + bB + ge25519_double_scalarmult_vartime2(r, A, a, B, b); } -void xmr_get_subaddress_secret_key(bignum256modm r, uint32_t major, uint32_t minor, const bignum256modm m){ - const char prefix[] = "SubAddr"; - unsigned char buff[32]; - contract256_modm(buff, m); +void xmr_get_subaddress_secret_key(bignum256modm r, uint32_t major, + uint32_t minor, const bignum256modm m) { + const char prefix[] = "SubAddr"; + unsigned char buff[32]; + contract256_modm(buff, m); - char data[sizeof(prefix) + sizeof(buff) + 2 * sizeof(uint32_t)]; - memcpy(data, prefix, sizeof(prefix)); - memcpy(data + sizeof(prefix), buff, sizeof(buff)); - memcpy(data + sizeof(prefix) + sizeof(buff), &major, sizeof(uint32_t)); - memcpy(data + sizeof(prefix) + sizeof(buff) + sizeof(uint32_t), &minor, sizeof(uint32_t)); + char data[sizeof(prefix) + sizeof(buff) + 2 * sizeof(uint32_t)]; + memcpy(data, prefix, sizeof(prefix)); + memcpy(data + sizeof(prefix), buff, sizeof(buff)); + memcpy(data + sizeof(prefix) + sizeof(buff), &major, sizeof(uint32_t)); + memcpy(data + sizeof(prefix) + sizeof(buff) + sizeof(uint32_t), &minor, + sizeof(uint32_t)); - xmr_hash_to_scalar(r, data, sizeof(data)); + xmr_hash_to_scalar(r, data, sizeof(data)); } -void xmr_gen_c(ge25519 * r, const bignum256modm a, uint64_t amount){ - // C = aG + bH - bignum256modm b={0}; - set256_modm(b, amount); - xmr_add_keys2(r, a, b, &xmr_h); +void xmr_gen_c(ge25519 *r, const bignum256modm a, uint64_t amount) { + // C = aG + bH + bignum256modm b = {0}; + set256_modm(b, amount); + xmr_add_keys2(r, a, b, &xmr_h); } diff --git a/monero/xmr.h b/monero/xmr.h index 83cdf83b4..4ef83a06b 100644 --- a/monero/xmr.h +++ b/monero/xmr.h @@ -24,13 +24,13 @@ void ge25519_set_xmr_h(ge25519 *r); void xmr_random_scalar(bignum256modm m); /* cn_fast_hash */ -void xmr_fast_hash(uint8_t * hash, const void *data, size_t length); +void xmr_fast_hash(uint8_t *hash, const void *data, size_t length); /* incremental hashing wrappers */ -void xmr_hasher_init(Hasher * hasher); -void xmr_hasher_update(Hasher * hasher, const void *data, size_t length); -void xmr_hasher_final(Hasher * hasher, uint8_t * hash); -void xmr_hasher_copy(Hasher * dst, const Hasher * src); +void xmr_hasher_init(Hasher *hasher); +void xmr_hasher_update(Hasher *hasher, const void *data, size_t length); +void xmr_hasher_final(Hasher *hasher, uint8_t *hash); +void xmr_hasher_copy(Hasher *dst, const Hasher *src); /* H_s(buffer) */ void xmr_hash_to_scalar(bignum256modm r, const void *data, size_t length); @@ -39,29 +39,38 @@ void xmr_hash_to_scalar(bignum256modm r, const void *data, size_t length); void xmr_hash_to_ec(ge25519 *P, const void *data, size_t length); /* derivation to scalar value */ -void xmr_derivation_to_scalar(bignum256modm s, const ge25519 * p, uint32_t output_index); +void xmr_derivation_to_scalar(bignum256modm s, const ge25519 *p, + uint32_t output_index); /* derivation */ -void xmr_generate_key_derivation(ge25519 * r, const ge25519 * A, const bignum256modm b); +void xmr_generate_key_derivation(ge25519 *r, const ge25519 *A, + const bignum256modm b); /* H_s(derivation || varint(output_index)) + base */ -void xmr_derive_private_key(bignum256modm s, const ge25519 * deriv, uint32_t idx, const bignum256modm base); +void xmr_derive_private_key(bignum256modm s, const ge25519 *deriv, uint32_t idx, + const bignum256modm base); /* H_s(derivation || varint(output_index))G + base */ -void xmr_derive_public_key(ge25519 * r, const ge25519 * deriv, uint32_t idx, const ge25519 * base); +void xmr_derive_public_key(ge25519 *r, const ge25519 *deriv, uint32_t idx, + const ge25519 *base); /* aG + bB, G is basepoint */ -void xmr_add_keys2(ge25519 * r, const bignum256modm a, const bignum256modm b, const ge25519 * B); -void xmr_add_keys2_vartime(ge25519 * r, const bignum256modm a, const bignum256modm b, const ge25519 * B); +void xmr_add_keys2(ge25519 *r, const bignum256modm a, const bignum256modm b, + const ge25519 *B); +void xmr_add_keys2_vartime(ge25519 *r, const bignum256modm a, + const bignum256modm b, const ge25519 *B); /* aA + bB */ -void xmr_add_keys3(ge25519 * r, const bignum256modm a, const ge25519 * A, const bignum256modm b, const ge25519 * B); -void xmr_add_keys3_vartime(ge25519 * r, const bignum256modm a, const ge25519 * A, const bignum256modm b, const ge25519 * B); +void xmr_add_keys3(ge25519 *r, const bignum256modm a, const ge25519 *A, + const bignum256modm b, const ge25519 *B); +void xmr_add_keys3_vartime(ge25519 *r, const bignum256modm a, const ge25519 *A, + const bignum256modm b, const ge25519 *B); /* subaddress secret */ -void xmr_get_subaddress_secret_key(bignum256modm r, uint32_t major, uint32_t minor, const bignum256modm m); +void xmr_get_subaddress_secret_key(bignum256modm r, uint32_t major, + uint32_t minor, const bignum256modm m); /* Generates Pedersen commitment C = aG + bH */ -void xmr_gen_c(ge25519 * r, const bignum256modm a, uint64_t amount); +void xmr_gen_c(ge25519 *r, const bignum256modm a, uint64_t amount); -#endif //TREZOR_CRYPTO_XMR_H +#endif // TREZOR_CRYPTO_XMR_H diff --git a/nem.c b/nem.c index 39c9ac586..5fd55e5d3 100644 --- a/nem.c +++ b/nem.c @@ -26,544 +26,483 @@ #include "base32.h" #include "ed25519-donna/ed25519-keccak.h" +#include "memzero.h" #include "ripemd160.h" #include "sha3.h" -#include "memzero.h" #define CAN_WRITE(NEEDED) ((ctx->offset + (NEEDED)) <= ctx->size) -#define SERIALIZE_U32(DATA) \ - do { if (!nem_write_u32(ctx, (DATA))) return false; } while (0) -#define SERIALIZE_U64(DATA) \ - do { if (!nem_write_u64(ctx, (DATA))) return false; } while (0) -#define SERIALIZE_TAGGED(DATA, LENGTH) \ - do { if (!nem_write_tagged(ctx, (DATA), (LENGTH))) return false; } while (0) - +#define SERIALIZE_U32(DATA) \ + do { \ + if (!nem_write_u32(ctx, (DATA))) return false; \ + } while (0) +#define SERIALIZE_U64(DATA) \ + do { \ + if (!nem_write_u64(ctx, (DATA))) return false; \ + } while (0) +#define SERIALIZE_TAGGED(DATA, LENGTH) \ + do { \ + if (!nem_write_tagged(ctx, (DATA), (LENGTH))) return false; \ + } while (0) const char *nem_network_name(uint8_t network) { - switch (network) { - case NEM_NETWORK_MAINNET: - return "NEM Mainnet"; - case NEM_NETWORK_TESTNET: - return "NEM Testnet"; - case NEM_NETWORK_MIJIN: - return "Mijin"; - default: - return NULL; - } + switch (network) { + case NEM_NETWORK_MAINNET: + return "NEM Mainnet"; + case NEM_NETWORK_TESTNET: + return "NEM Testnet"; + case NEM_NETWORK_MIJIN: + return "Mijin"; + default: + return NULL; + } } -static inline bool nem_write_checked(nem_transaction_ctx *ctx, const uint8_t *data, uint32_t length) { - if (!CAN_WRITE(length)) { - return false; - } +static inline bool nem_write_checked(nem_transaction_ctx *ctx, + const uint8_t *data, uint32_t length) { + if (!CAN_WRITE(length)) { + return false; + } - memcpy(&ctx->buffer[ctx->offset], data, length); - ctx->offset += length; - return true; + memcpy(&ctx->buffer[ctx->offset], data, length); + ctx->offset += length; + return true; } static inline bool nem_write_u32(nem_transaction_ctx *ctx, uint32_t data) { - if (!CAN_WRITE(4)) { - return false; - } + if (!CAN_WRITE(4)) { + return false; + } - ctx->buffer[ctx->offset++] = (data >> 0) & 0xff; - ctx->buffer[ctx->offset++] = (data >> 8) & 0xff; - ctx->buffer[ctx->offset++] = (data >> 16) & 0xff; - ctx->buffer[ctx->offset++] = (data >> 24) & 0xff; + ctx->buffer[ctx->offset++] = (data >> 0) & 0xff; + ctx->buffer[ctx->offset++] = (data >> 8) & 0xff; + ctx->buffer[ctx->offset++] = (data >> 16) & 0xff; + ctx->buffer[ctx->offset++] = (data >> 24) & 0xff; - return true; + return true; } static inline bool nem_write_u64(nem_transaction_ctx *ctx, uint64_t data) { - SERIALIZE_U32((data >> 0) & 0xffffffff); - SERIALIZE_U32((data >> 32) & 0xffffffff); + SERIALIZE_U32((data >> 0) & 0xffffffff); + SERIALIZE_U32((data >> 32) & 0xffffffff); - return true; + return true; } -static inline bool nem_write_tagged(nem_transaction_ctx *ctx, const uint8_t *data, uint32_t length) { - SERIALIZE_U32(length); +static inline bool nem_write_tagged(nem_transaction_ctx *ctx, + const uint8_t *data, uint32_t length) { + SERIALIZE_U32(length); - return nem_write_checked(ctx, data, length); + return nem_write_checked(ctx, data, length); } -static inline bool nem_write_mosaic_str(nem_transaction_ctx *ctx, const char *name, const char *value) { - uint32_t name_length = strlen(name); - uint32_t value_length = strlen(value); +static inline bool nem_write_mosaic_str(nem_transaction_ctx *ctx, + const char *name, const char *value) { + uint32_t name_length = strlen(name); + uint32_t value_length = strlen(value); - SERIALIZE_U32(sizeof(uint32_t) + name_length + sizeof(uint32_t) + value_length); - SERIALIZE_TAGGED((const uint8_t *) name, name_length); - SERIALIZE_TAGGED((const uint8_t *) value, value_length); + SERIALIZE_U32(sizeof(uint32_t) + name_length + sizeof(uint32_t) + + value_length); + SERIALIZE_TAGGED((const uint8_t *)name, name_length); + SERIALIZE_TAGGED((const uint8_t *)value, value_length); - return true; + return true; } -static inline bool nem_write_mosaic_bool(nem_transaction_ctx *ctx, const char *name, bool value) { - return nem_write_mosaic_str(ctx, name, value ? "true" : "false"); +static inline bool nem_write_mosaic_bool(nem_transaction_ctx *ctx, + const char *name, bool value) { + return nem_write_mosaic_str(ctx, name, value ? "true" : "false"); } -static inline bool nem_write_mosaic_u64(nem_transaction_ctx *ctx, const char *name, uint64_t value) { - char buffer[21]; +static inline bool nem_write_mosaic_u64(nem_transaction_ctx *ctx, + const char *name, uint64_t value) { + char buffer[21]; - if (bn_format_uint64(value, NULL, NULL, 0, 0, false, buffer, sizeof(buffer)) == 0) { - return false; - } + if (bn_format_uint64(value, NULL, NULL, 0, 0, false, buffer, + sizeof(buffer)) == 0) { + return false; + } - return nem_write_mosaic_str(ctx, name, buffer); + return nem_write_mosaic_str(ctx, name, buffer); } -void nem_get_address_raw(const ed25519_public_key public_key, uint8_t version, uint8_t *address) { - uint8_t hash[SHA3_256_DIGEST_LENGTH]; +void nem_get_address_raw(const ed25519_public_key public_key, uint8_t version, + uint8_t *address) { + uint8_t hash[SHA3_256_DIGEST_LENGTH]; - /* 1. Perform 256-bit Sha3 on the public key */ - keccak_256(public_key, sizeof(ed25519_public_key), hash); + /* 1. Perform 256-bit Sha3 on the public key */ + keccak_256(public_key, sizeof(ed25519_public_key), hash); - /* 2. Perform 160-bit Ripemd of hash resulting from step 1. */ - ripemd160(hash, SHA3_256_DIGEST_LENGTH, &address[1]); + /* 2. Perform 160-bit Ripemd of hash resulting from step 1. */ + ripemd160(hash, SHA3_256_DIGEST_LENGTH, &address[1]); - /* 3. Prepend version byte to Ripemd hash (either 0x68 or 0x98) */ - address[0] = version; + /* 3. Prepend version byte to Ripemd hash (either 0x68 or 0x98) */ + address[0] = version; - /* 4. Perform 256-bit Sha3 on the result, take the first four bytes as a checksum */ - keccak_256(address, 1 + RIPEMD160_DIGEST_LENGTH, hash); + /* 4. Perform 256-bit Sha3 on the result, take the first four bytes as a + * checksum */ + keccak_256(address, 1 + RIPEMD160_DIGEST_LENGTH, hash); - /* 5. Concatenate output of step 3 and the checksum from step 4 */ - memcpy(&address[1 + RIPEMD160_DIGEST_LENGTH], hash, 4); + /* 5. Concatenate output of step 3 and the checksum from step 4 */ + memcpy(&address[1 + RIPEMD160_DIGEST_LENGTH], hash, 4); - memzero(hash, sizeof(hash)); + memzero(hash, sizeof(hash)); } -bool nem_get_address(const ed25519_public_key public_key, uint8_t version, char *address) { - uint8_t pubkeyhash[NEM_ADDRESS_SIZE_RAW]; +bool nem_get_address(const ed25519_public_key public_key, uint8_t version, + char *address) { + uint8_t pubkeyhash[NEM_ADDRESS_SIZE_RAW]; - nem_get_address_raw(public_key, version, pubkeyhash); + nem_get_address_raw(public_key, version, pubkeyhash); - char *ret = base32_encode(pubkeyhash, sizeof(pubkeyhash), address, NEM_ADDRESS_SIZE + 1, BASE32_ALPHABET_RFC4648); + char *ret = base32_encode(pubkeyhash, sizeof(pubkeyhash), address, + NEM_ADDRESS_SIZE + 1, BASE32_ALPHABET_RFC4648); - memzero(pubkeyhash, sizeof(pubkeyhash)); - return (ret != NULL); + memzero(pubkeyhash, sizeof(pubkeyhash)); + return (ret != NULL); } bool nem_validate_address_raw(const uint8_t *address, uint8_t network) { - if (!nem_network_name(network) || address[0] != network) { - return false; - } + if (!nem_network_name(network) || address[0] != network) { + return false; + } - uint8_t hash[SHA3_256_DIGEST_LENGTH]; + uint8_t hash[SHA3_256_DIGEST_LENGTH]; - keccak_256(address, 1 + RIPEMD160_DIGEST_LENGTH, hash); - bool valid = (memcmp(&address[1 + RIPEMD160_DIGEST_LENGTH], hash, 4) == 0); + keccak_256(address, 1 + RIPEMD160_DIGEST_LENGTH, hash); + bool valid = (memcmp(&address[1 + RIPEMD160_DIGEST_LENGTH], hash, 4) == 0); - memzero(hash, sizeof(hash)); - return valid; + memzero(hash, sizeof(hash)); + return valid; } bool nem_validate_address(const char *address, uint8_t network) { - uint8_t pubkeyhash[NEM_ADDRESS_SIZE_RAW]; + uint8_t pubkeyhash[NEM_ADDRESS_SIZE_RAW]; - if (strlen(address) != NEM_ADDRESS_SIZE) { - return false; - } + if (strlen(address) != NEM_ADDRESS_SIZE) { + return false; + } - uint8_t *ret = base32_decode(address, NEM_ADDRESS_SIZE, pubkeyhash, sizeof(pubkeyhash), BASE32_ALPHABET_RFC4648); - bool valid = (ret != NULL) && nem_validate_address_raw(pubkeyhash, network); + uint8_t *ret = base32_decode(address, NEM_ADDRESS_SIZE, pubkeyhash, + sizeof(pubkeyhash), BASE32_ALPHABET_RFC4648); + bool valid = (ret != NULL) && nem_validate_address_raw(pubkeyhash, network); - memzero(pubkeyhash, sizeof(pubkeyhash)); - return valid; + memzero(pubkeyhash, sizeof(pubkeyhash)); + return valid; } -void nem_transaction_start(nem_transaction_ctx *ctx, const ed25519_public_key public_key, uint8_t *buffer, size_t size) { - memcpy(ctx->public_key, public_key, sizeof(ctx->public_key)); +void nem_transaction_start(nem_transaction_ctx *ctx, + const ed25519_public_key public_key, uint8_t *buffer, + size_t size) { + memcpy(ctx->public_key, public_key, sizeof(ctx->public_key)); - ctx->buffer = buffer; - ctx->offset = 0; - ctx->size = size; + ctx->buffer = buffer; + ctx->offset = 0; + ctx->size = size; } -size_t nem_transaction_end(nem_transaction_ctx *ctx, const ed25519_secret_key private_key, ed25519_signature signature) { - if (private_key != NULL && signature != NULL) { - ed25519_sign_keccak(ctx->buffer, ctx->offset, private_key, ctx->public_key, signature); - } +size_t nem_transaction_end(nem_transaction_ctx *ctx, + const ed25519_secret_key private_key, + ed25519_signature signature) { + if (private_key != NULL && signature != NULL) { + ed25519_sign_keccak(ctx->buffer, ctx->offset, private_key, ctx->public_key, + signature); + } - return ctx->offset; + return ctx->offset; } -bool nem_transaction_write_common(nem_transaction_ctx *ctx, - uint32_t type, - uint32_t version, - uint32_t timestamp, - const ed25519_public_key signer, - uint64_t fee, - uint32_t deadline) { - - SERIALIZE_U32(type); - SERIALIZE_U32(version); - SERIALIZE_U32(timestamp); - SERIALIZE_TAGGED(signer, sizeof(ed25519_public_key)); - SERIALIZE_U64(fee); - SERIALIZE_U32(deadline); - - return true; +bool nem_transaction_write_common(nem_transaction_ctx *ctx, uint32_t type, + uint32_t version, uint32_t timestamp, + const ed25519_public_key signer, uint64_t fee, + uint32_t deadline) { + SERIALIZE_U32(type); + SERIALIZE_U32(version); + SERIALIZE_U32(timestamp); + SERIALIZE_TAGGED(signer, sizeof(ed25519_public_key)); + SERIALIZE_U64(fee); + SERIALIZE_U32(deadline); + + return true; } -bool nem_transaction_create_transfer(nem_transaction_ctx *ctx, - uint8_t network, - uint32_t timestamp, - const ed25519_public_key signer, - uint64_t fee, - uint32_t deadline, - const char *recipient, - uint64_t amount, - const uint8_t *payload, - uint32_t length, - bool encrypted, - uint32_t mosaics) { - - if (!signer) { - signer = ctx->public_key; - } - - if (!payload) { - length = 0; - } - - bool ret = nem_transaction_write_common(ctx, - NEM_TRANSACTION_TYPE_TRANSFER, - (uint32_t) network << 24 | (mosaics ? 2 : 1), - timestamp, - signer, - fee, - deadline); - if (!ret) return false; - - SERIALIZE_TAGGED((const uint8_t *) recipient, NEM_ADDRESS_SIZE); - SERIALIZE_U64(amount); - - if (length) { - SERIALIZE_U32(sizeof(uint32_t) + sizeof(uint32_t) + length); - SERIALIZE_U32(encrypted ? 0x02 : 0x01); - SERIALIZE_TAGGED(payload, length); - } else { - SERIALIZE_U32(0); - } - - if (mosaics) { - - SERIALIZE_U32(mosaics); - - } - - return true; +bool nem_transaction_create_transfer(nem_transaction_ctx *ctx, uint8_t network, + uint32_t timestamp, + const ed25519_public_key signer, + uint64_t fee, uint32_t deadline, + const char *recipient, uint64_t amount, + const uint8_t *payload, uint32_t length, + bool encrypted, uint32_t mosaics) { + if (!signer) { + signer = ctx->public_key; + } + + if (!payload) { + length = 0; + } + + bool ret = + nem_transaction_write_common(ctx, NEM_TRANSACTION_TYPE_TRANSFER, + (uint32_t)network << 24 | (mosaics ? 2 : 1), + timestamp, signer, fee, deadline); + if (!ret) return false; + + SERIALIZE_TAGGED((const uint8_t *)recipient, NEM_ADDRESS_SIZE); + SERIALIZE_U64(amount); + + if (length) { + SERIALIZE_U32(sizeof(uint32_t) + sizeof(uint32_t) + length); + SERIALIZE_U32(encrypted ? 0x02 : 0x01); + SERIALIZE_TAGGED(payload, length); + } else { + SERIALIZE_U32(0); + } + + if (mosaics) { + SERIALIZE_U32(mosaics); + } + + return true; } bool nem_transaction_write_mosaic(nem_transaction_ctx *ctx, - const char *namespace, - const char *mosaic, - uint64_t quantity) { + const char *namespace, const char *mosaic, + uint64_t quantity) { + size_t namespace_length = strlen(namespace); + size_t mosaic_length = strlen(mosaic); + size_t identifier_length = + sizeof(uint32_t) + namespace_length + sizeof(uint32_t) + mosaic_length; + + SERIALIZE_U32(sizeof(uint32_t) + sizeof(uint64_t) + identifier_length); + SERIALIZE_U32(identifier_length); + SERIALIZE_TAGGED((const uint8_t *)namespace, namespace_length); + SERIALIZE_TAGGED((const uint8_t *)mosaic, mosaic_length); + SERIALIZE_U64(quantity); + + return true; +} - size_t namespace_length = strlen(namespace); - size_t mosaic_length = strlen(mosaic); - size_t identifier_length = sizeof(uint32_t) + namespace_length + sizeof(uint32_t) + mosaic_length; +bool nem_transaction_create_multisig(nem_transaction_ctx *ctx, uint8_t network, + uint32_t timestamp, + const ed25519_public_key signer, + uint64_t fee, uint32_t deadline, + const nem_transaction_ctx *inner) { + if (!signer) { + signer = ctx->public_key; + } - SERIALIZE_U32(sizeof(uint32_t) + sizeof(uint64_t) + identifier_length); - SERIALIZE_U32(identifier_length); - SERIALIZE_TAGGED((const uint8_t *) namespace, namespace_length); - SERIALIZE_TAGGED((const uint8_t *) mosaic, mosaic_length); - SERIALIZE_U64(quantity); + bool ret = nem_transaction_write_common(ctx, NEM_TRANSACTION_TYPE_MULTISIG, + (uint32_t)network << 24 | 1, + timestamp, signer, fee, deadline); + if (!ret) return false; - return true; -} + SERIALIZE_TAGGED(inner->buffer, inner->offset); -bool nem_transaction_create_multisig(nem_transaction_ctx *ctx, - uint8_t network, - uint32_t timestamp, - const ed25519_public_key signer, - uint64_t fee, - uint32_t deadline, - const nem_transaction_ctx *inner) { - - if (!signer) { - signer = ctx->public_key; - } - - bool ret = nem_transaction_write_common(ctx, - NEM_TRANSACTION_TYPE_MULTISIG, - (uint32_t) network << 24 | 1, - timestamp, - signer, - fee, - deadline); - if (!ret) return false; - - SERIALIZE_TAGGED(inner->buffer, inner->offset); - - return true; + return true; } -bool nem_transaction_create_multisig_signature(nem_transaction_ctx *ctx, - uint8_t network, - uint32_t timestamp, - const ed25519_public_key signer, - uint64_t fee, - uint32_t deadline, - const nem_transaction_ctx *inner) { - - if (!signer) { - signer = ctx->public_key; - } - - bool ret = nem_transaction_write_common(ctx, - NEM_TRANSACTION_TYPE_MULTISIG_SIGNATURE, - (uint32_t) network << 24 | 1, - timestamp, - signer, - fee, - deadline); - if (!ret) return false; - - char address[NEM_ADDRESS_SIZE + 1]; - nem_get_address(inner->public_key, network, address); - - uint8_t hash[SHA3_256_DIGEST_LENGTH]; - keccak_256(inner->buffer, inner->offset, hash); - - SERIALIZE_U32(sizeof(uint32_t) + SHA3_256_DIGEST_LENGTH); - SERIALIZE_TAGGED(hash, SHA3_256_DIGEST_LENGTH); - SERIALIZE_TAGGED((const uint8_t *) address, NEM_ADDRESS_SIZE); - - return true; -} +bool nem_transaction_create_multisig_signature( + nem_transaction_ctx *ctx, uint8_t network, uint32_t timestamp, + const ed25519_public_key signer, uint64_t fee, uint32_t deadline, + const nem_transaction_ctx *inner) { + if (!signer) { + signer = ctx->public_key; + } -bool nem_transaction_create_provision_namespace(nem_transaction_ctx *ctx, - uint8_t network, - uint32_t timestamp, - const ed25519_public_key signer, - uint64_t fee, - uint32_t deadline, - const char *namespace, - const char *parent, - const char *rental_sink, - uint64_t rental_fee) { - - if (!signer) { - signer = ctx->public_key; - } - - bool ret = nem_transaction_write_common(ctx, - NEM_TRANSACTION_TYPE_PROVISION_NAMESPACE, - (uint32_t) network << 24 | 1, - timestamp, - signer, - fee, - deadline); - if (!ret) return false; - - if (parent) { - SERIALIZE_TAGGED((const uint8_t *) rental_sink, NEM_ADDRESS_SIZE); - SERIALIZE_U64(rental_fee); - SERIALIZE_TAGGED((const uint8_t *) namespace, strlen(namespace)); - SERIALIZE_TAGGED((const uint8_t *) parent, strlen(parent)); - } else { - SERIALIZE_TAGGED((const uint8_t *) rental_sink, NEM_ADDRESS_SIZE); - SERIALIZE_U64(rental_fee); - SERIALIZE_TAGGED((const uint8_t *) namespace, strlen(namespace)); - SERIALIZE_U32(0xffffffff); - } - - return true; -} + bool ret = nem_transaction_write_common( + ctx, NEM_TRANSACTION_TYPE_MULTISIG_SIGNATURE, (uint32_t)network << 24 | 1, + timestamp, signer, fee, deadline); + if (!ret) return false; + + char address[NEM_ADDRESS_SIZE + 1]; + nem_get_address(inner->public_key, network, address); -bool nem_transaction_create_mosaic_creation(nem_transaction_ctx *ctx, - uint8_t network, - uint32_t timestamp, - const ed25519_public_key signer, - uint64_t fee, - uint32_t deadline, - const char *namespace, - const char *mosaic, - const char *description, - uint32_t divisibility, - uint64_t supply, - bool mutable_supply, - bool transferable, - uint32_t levy_type, - uint64_t levy_fee, - const char *levy_address, - const char *levy_namespace, - const char *levy_mosaic, - const char *creation_sink, - uint64_t creation_fee) { - - if (!signer) { - signer = ctx->public_key; - } - - bool ret = nem_transaction_write_common(ctx, - NEM_TRANSACTION_TYPE_MOSAIC_CREATION, - (uint32_t) network << 24 | 1, - timestamp, - signer, - fee, - deadline); - if (!ret) return false; - - size_t namespace_length = strlen(namespace); - size_t mosaic_length = strlen(mosaic); - size_t identifier_length = sizeof(uint32_t) + namespace_length + sizeof(uint32_t) + mosaic_length; - - // This length will be rewritten later on - nem_transaction_ctx state; - memcpy(&state, ctx, sizeof(state)); - - SERIALIZE_U32(0); - SERIALIZE_TAGGED(signer, sizeof(ed25519_public_key)); - SERIALIZE_U32(identifier_length); - SERIALIZE_TAGGED((const uint8_t *) namespace, namespace_length); - SERIALIZE_TAGGED((const uint8_t *) mosaic, mosaic_length); - SERIALIZE_TAGGED((const uint8_t *) description, strlen(description)); - SERIALIZE_U32(4); // Number of properties - - if (!nem_write_mosaic_u64(ctx, "divisibility", divisibility)) return false; - if (!nem_write_mosaic_u64(ctx, "initialSupply", supply)) return false; - if (!nem_write_mosaic_bool(ctx, "supplyMutable", mutable_supply)) return false; - if (!nem_write_mosaic_bool(ctx, "transferable", transferable)) return false; - - if (levy_type) { - size_t levy_namespace_length = strlen(levy_namespace); - size_t levy_mosaic_length = strlen(levy_mosaic); - size_t levy_identifier_length = sizeof(uint32_t) + levy_namespace_length + sizeof(uint32_t) + levy_mosaic_length; - - SERIALIZE_U32(sizeof(uint32_t) + sizeof(uint32_t) + NEM_ADDRESS_SIZE + sizeof(uint32_t) + levy_identifier_length + sizeof(uint64_t)); - SERIALIZE_U32(levy_type); - SERIALIZE_TAGGED((const uint8_t *) levy_address, NEM_ADDRESS_SIZE); - SERIALIZE_U32(levy_identifier_length); - SERIALIZE_TAGGED((const uint8_t *) levy_namespace, levy_namespace_length); - SERIALIZE_TAGGED((const uint8_t *) levy_mosaic, levy_mosaic_length); - SERIALIZE_U64(levy_fee); - } else { - SERIALIZE_U32(0); - } - - // Rewrite length - nem_write_u32(&state, ctx->offset - state.offset - sizeof(uint32_t)); - - SERIALIZE_TAGGED((const uint8_t *) creation_sink, NEM_ADDRESS_SIZE); - SERIALIZE_U64(creation_fee); - - return true; + uint8_t hash[SHA3_256_DIGEST_LENGTH]; + keccak_256(inner->buffer, inner->offset, hash); + SERIALIZE_U32(sizeof(uint32_t) + SHA3_256_DIGEST_LENGTH); + SERIALIZE_TAGGED(hash, SHA3_256_DIGEST_LENGTH); + SERIALIZE_TAGGED((const uint8_t *)address, NEM_ADDRESS_SIZE); + + return true; } -bool nem_transaction_create_mosaic_supply_change(nem_transaction_ctx *ctx, - uint8_t network, - uint32_t timestamp, - const ed25519_public_key signer, - uint64_t fee, - uint32_t deadline, - const char *namespace, - const char *mosaic, - uint32_t type, - uint64_t delta) { - - if (!signer) { - signer = ctx->public_key; - } - - bool ret = nem_transaction_write_common(ctx, - NEM_TRANSACTION_TYPE_MOSAIC_SUPPLY_CHANGE, - (uint32_t) network << 24 | 1, - timestamp, - signer, - fee, - deadline); - if (!ret) return false; - - size_t namespace_length = strlen(namespace); - size_t mosaic_length = strlen(mosaic); - size_t identifier_length = sizeof(uint32_t) + namespace_length + sizeof(uint32_t) + mosaic_length; - - SERIALIZE_U32(identifier_length); - SERIALIZE_TAGGED((const uint8_t *) namespace, namespace_length); - SERIALIZE_TAGGED((const uint8_t *) mosaic, mosaic_length); - SERIALIZE_U32(type); - SERIALIZE_U64(delta); - - return true; +bool nem_transaction_create_provision_namespace( + nem_transaction_ctx *ctx, uint8_t network, uint32_t timestamp, + const ed25519_public_key signer, uint64_t fee, uint32_t deadline, + const char *namespace, const char *parent, const char *rental_sink, + uint64_t rental_fee) { + if (!signer) { + signer = ctx->public_key; + } + + bool ret = nem_transaction_write_common( + ctx, NEM_TRANSACTION_TYPE_PROVISION_NAMESPACE, + (uint32_t)network << 24 | 1, timestamp, signer, fee, deadline); + if (!ret) return false; + + if (parent) { + SERIALIZE_TAGGED((const uint8_t *)rental_sink, NEM_ADDRESS_SIZE); + SERIALIZE_U64(rental_fee); + SERIALIZE_TAGGED((const uint8_t *)namespace, strlen(namespace)); + SERIALIZE_TAGGED((const uint8_t *)parent, strlen(parent)); + } else { + SERIALIZE_TAGGED((const uint8_t *)rental_sink, NEM_ADDRESS_SIZE); + SERIALIZE_U64(rental_fee); + SERIALIZE_TAGGED((const uint8_t *)namespace, strlen(namespace)); + SERIALIZE_U32(0xffffffff); + } + + return true; } -bool nem_transaction_create_aggregate_modification(nem_transaction_ctx *ctx, - uint8_t network, - uint32_t timestamp, - const ed25519_public_key signer, - uint64_t fee, - uint32_t deadline, - uint32_t modifications, - bool relative_change) { - - if (!signer) { - signer = ctx->public_key; - } - - bool ret = nem_transaction_write_common(ctx, - NEM_TRANSACTION_TYPE_AGGREGATE_MODIFICATION, - (uint32_t) network << 24 | (relative_change ? 2 : 1), - timestamp, - signer, - fee, - deadline); - if (!ret) return false; - - SERIALIZE_U32(modifications); - - return true; +bool nem_transaction_create_mosaic_creation( + nem_transaction_ctx *ctx, uint8_t network, uint32_t timestamp, + const ed25519_public_key signer, uint64_t fee, uint32_t deadline, + const char *namespace, const char *mosaic, const char *description, + uint32_t divisibility, uint64_t supply, bool mutable_supply, + bool transferable, uint32_t levy_type, uint64_t levy_fee, + const char *levy_address, const char *levy_namespace, + const char *levy_mosaic, const char *creation_sink, uint64_t creation_fee) { + if (!signer) { + signer = ctx->public_key; + } + + bool ret = nem_transaction_write_common( + ctx, NEM_TRANSACTION_TYPE_MOSAIC_CREATION, (uint32_t)network << 24 | 1, + timestamp, signer, fee, deadline); + if (!ret) return false; + + size_t namespace_length = strlen(namespace); + size_t mosaic_length = strlen(mosaic); + size_t identifier_length = + sizeof(uint32_t) + namespace_length + sizeof(uint32_t) + mosaic_length; + + // This length will be rewritten later on + nem_transaction_ctx state; + memcpy(&state, ctx, sizeof(state)); + + SERIALIZE_U32(0); + SERIALIZE_TAGGED(signer, sizeof(ed25519_public_key)); + SERIALIZE_U32(identifier_length); + SERIALIZE_TAGGED((const uint8_t *)namespace, namespace_length); + SERIALIZE_TAGGED((const uint8_t *)mosaic, mosaic_length); + SERIALIZE_TAGGED((const uint8_t *)description, strlen(description)); + SERIALIZE_U32(4); // Number of properties + + if (!nem_write_mosaic_u64(ctx, "divisibility", divisibility)) return false; + if (!nem_write_mosaic_u64(ctx, "initialSupply", supply)) return false; + if (!nem_write_mosaic_bool(ctx, "supplyMutable", mutable_supply)) + return false; + if (!nem_write_mosaic_bool(ctx, "transferable", transferable)) return false; + + if (levy_type) { + size_t levy_namespace_length = strlen(levy_namespace); + size_t levy_mosaic_length = strlen(levy_mosaic); + size_t levy_identifier_length = sizeof(uint32_t) + levy_namespace_length + + sizeof(uint32_t) + levy_mosaic_length; + + SERIALIZE_U32(sizeof(uint32_t) + sizeof(uint32_t) + NEM_ADDRESS_SIZE + + sizeof(uint32_t) + levy_identifier_length + sizeof(uint64_t)); + SERIALIZE_U32(levy_type); + SERIALIZE_TAGGED((const uint8_t *)levy_address, NEM_ADDRESS_SIZE); + SERIALIZE_U32(levy_identifier_length); + SERIALIZE_TAGGED((const uint8_t *)levy_namespace, levy_namespace_length); + SERIALIZE_TAGGED((const uint8_t *)levy_mosaic, levy_mosaic_length); + SERIALIZE_U64(levy_fee); + } else { + SERIALIZE_U32(0); + } + + // Rewrite length + nem_write_u32(&state, ctx->offset - state.offset - sizeof(uint32_t)); + + SERIALIZE_TAGGED((const uint8_t *)creation_sink, NEM_ADDRESS_SIZE); + SERIALIZE_U64(creation_fee); + + return true; } -bool nem_transaction_write_cosignatory_modification(nem_transaction_ctx *ctx, - uint32_t type, - const ed25519_public_key cosignatory) { +bool nem_transaction_create_mosaic_supply_change( + nem_transaction_ctx *ctx, uint8_t network, uint32_t timestamp, + const ed25519_public_key signer, uint64_t fee, uint32_t deadline, + const char *namespace, const char *mosaic, uint32_t type, uint64_t delta) { + if (!signer) { + signer = ctx->public_key; + } + + bool ret = nem_transaction_write_common( + ctx, NEM_TRANSACTION_TYPE_MOSAIC_SUPPLY_CHANGE, + (uint32_t)network << 24 | 1, timestamp, signer, fee, deadline); + if (!ret) return false; + + size_t namespace_length = strlen(namespace); + size_t mosaic_length = strlen(mosaic); + size_t identifier_length = + sizeof(uint32_t) + namespace_length + sizeof(uint32_t) + mosaic_length; + + SERIALIZE_U32(identifier_length); + SERIALIZE_TAGGED((const uint8_t *)namespace, namespace_length); + SERIALIZE_TAGGED((const uint8_t *)mosaic, mosaic_length); + SERIALIZE_U32(type); + SERIALIZE_U64(delta); + + return true; +} - SERIALIZE_U32(sizeof(uint32_t) + sizeof(uint32_t) + sizeof(ed25519_public_key)); - SERIALIZE_U32(type); - SERIALIZE_TAGGED(cosignatory, sizeof(ed25519_public_key)); +bool nem_transaction_create_aggregate_modification( + nem_transaction_ctx *ctx, uint8_t network, uint32_t timestamp, + const ed25519_public_key signer, uint64_t fee, uint32_t deadline, + uint32_t modifications, bool relative_change) { + if (!signer) { + signer = ctx->public_key; + } - return true; + bool ret = nem_transaction_write_common( + ctx, NEM_TRANSACTION_TYPE_AGGREGATE_MODIFICATION, + (uint32_t)network << 24 | (relative_change ? 2 : 1), timestamp, signer, + fee, deadline); + if (!ret) return false; + + SERIALIZE_U32(modifications); + + return true; } -bool nem_transaction_write_minimum_cosignatories(nem_transaction_ctx *ctx, - int32_t relative_change) { +bool nem_transaction_write_cosignatory_modification( + nem_transaction_ctx *ctx, uint32_t type, + const ed25519_public_key cosignatory) { + SERIALIZE_U32(sizeof(uint32_t) + sizeof(uint32_t) + + sizeof(ed25519_public_key)); + SERIALIZE_U32(type); + SERIALIZE_TAGGED(cosignatory, sizeof(ed25519_public_key)); - SERIALIZE_U32(sizeof(uint32_t)); - SERIALIZE_U32((uint32_t) relative_change); + return true; +} - return true; +bool nem_transaction_write_minimum_cosignatories(nem_transaction_ctx *ctx, + int32_t relative_change) { + SERIALIZE_U32(sizeof(uint32_t)); + SERIALIZE_U32((uint32_t)relative_change); + + return true; } -bool nem_transaction_create_importance_transfer(nem_transaction_ctx *ctx, - uint8_t network, - uint32_t timestamp, - const ed25519_public_key signer, - uint64_t fee, - uint32_t deadline, - uint32_t mode, - const ed25519_public_key remote) { - - if (!signer) { - signer = ctx->public_key; - } - - bool ret = nem_transaction_write_common(ctx, - NEM_TRANSACTION_TYPE_IMPORTANCE_TRANSFER, - (uint32_t) network << 24 | 1, - timestamp, - signer, - fee, - deadline); - if (!ret) return false; - - SERIALIZE_U32(mode); - SERIALIZE_TAGGED(remote, sizeof(ed25519_public_key)); - - return true; +bool nem_transaction_create_importance_transfer( + nem_transaction_ctx *ctx, uint8_t network, uint32_t timestamp, + const ed25519_public_key signer, uint64_t fee, uint32_t deadline, + uint32_t mode, const ed25519_public_key remote) { + if (!signer) { + signer = ctx->public_key; + } + + bool ret = nem_transaction_write_common( + ctx, NEM_TRANSACTION_TYPE_IMPORTANCE_TRANSFER, + (uint32_t)network << 24 | 1, timestamp, signer, fee, deadline); + if (!ret) return false; + + SERIALIZE_U32(mode); + SERIALIZE_TAGGED(remote, sizeof(ed25519_public_key)); + + return true; } diff --git a/nem.h b/nem.h index fe7f7b68f..fe68316fb 100644 --- a/nem.h +++ b/nem.h @@ -31,161 +31,126 @@ #include "ed25519-donna/ed25519.h" #define NEM_LEVY_PERCENTILE_DIVISOR 4 -#define NEM_MAX_DIVISIBILITY 6 -#define NEM_MAX_SUPPLY 9000000000 +#define NEM_MAX_DIVISIBILITY 6 +#define NEM_MAX_SUPPLY 9000000000 #define NEM_NETWORK_MAINNET 0x68 #define NEM_NETWORK_TESTNET 0x98 -#define NEM_NETWORK_MIJIN 0x60 +#define NEM_NETWORK_MIJIN 0x60 #define NEM_ADDRESS_SIZE 40 #define NEM_ADDRESS_SIZE_RAW 25 -#define NEM_TRANSACTION_TYPE_TRANSFER 0x0101 -#define NEM_TRANSACTION_TYPE_IMPORTANCE_TRANSFER 0x0801 -#define NEM_TRANSACTION_TYPE_AGGREGATE_MODIFICATION 0x1001 -#define NEM_TRANSACTION_TYPE_MULTISIG_SIGNATURE 0x1002 -#define NEM_TRANSACTION_TYPE_MULTISIG 0x1004 -#define NEM_TRANSACTION_TYPE_PROVISION_NAMESPACE 0x2001 -#define NEM_TRANSACTION_TYPE_MOSAIC_CREATION 0x4001 -#define NEM_TRANSACTION_TYPE_MOSAIC_SUPPLY_CHANGE 0x4002 +#define NEM_TRANSACTION_TYPE_TRANSFER 0x0101 +#define NEM_TRANSACTION_TYPE_IMPORTANCE_TRANSFER 0x0801 +#define NEM_TRANSACTION_TYPE_AGGREGATE_MODIFICATION 0x1001 +#define NEM_TRANSACTION_TYPE_MULTISIG_SIGNATURE 0x1002 +#define NEM_TRANSACTION_TYPE_MULTISIG 0x1004 +#define NEM_TRANSACTION_TYPE_PROVISION_NAMESPACE 0x2001 +#define NEM_TRANSACTION_TYPE_MOSAIC_CREATION 0x4001 +#define NEM_TRANSACTION_TYPE_MOSAIC_SUPPLY_CHANGE 0x4002 #define NEM_SALT_SIZE sizeof(ed25519_public_key) -#define NEM_ENCRYPTED_SIZE(size) (((size) + AES_BLOCK_SIZE) / AES_BLOCK_SIZE * AES_BLOCK_SIZE) -#define NEM_ENCRYPTED_PAYLOAD_SIZE(size) (AES_BLOCK_SIZE + NEM_SALT_SIZE + NEM_ENCRYPTED_SIZE(size)) +#define NEM_ENCRYPTED_SIZE(size) \ + (((size) + AES_BLOCK_SIZE) / AES_BLOCK_SIZE * AES_BLOCK_SIZE) +#define NEM_ENCRYPTED_PAYLOAD_SIZE(size) \ + (AES_BLOCK_SIZE + NEM_SALT_SIZE + NEM_ENCRYPTED_SIZE(size)) -#define _NEM_PADDING_SIZE(buffer, size) ((buffer)[(size) - 1]) -#define NEM_PADDING_SIZE(buffer, size) (_NEM_PADDING_SIZE(buffer, size) > (size) ? (size) : _NEM_PADDING_SIZE(buffer, size)) +#define _NEM_PADDING_SIZE(buffer, size) ((buffer)[(size)-1]) +#define NEM_PADDING_SIZE(buffer, size) \ + (_NEM_PADDING_SIZE(buffer, size) > (size) ? (size) \ + : _NEM_PADDING_SIZE(buffer, size)) -#define NEM_DECRYPTED_SIZE(buffer, size) ((size) - NEM_PADDING_SIZE(buffer, size)) +#define NEM_DECRYPTED_SIZE(buffer, size) ((size)-NEM_PADDING_SIZE(buffer, size)) typedef struct { - ed25519_public_key public_key; - uint8_t *buffer; - size_t offset; - size_t size; + ed25519_public_key public_key; + uint8_t *buffer; + size_t offset; + size_t size; } nem_transaction_ctx; const char *nem_network_name(uint8_t network); -void nem_get_address_raw(const ed25519_public_key public_key, uint8_t version, uint8_t *address); -bool nem_get_address(const ed25519_public_key public_key, uint8_t version, char *address); +void nem_get_address_raw(const ed25519_public_key public_key, uint8_t version, + uint8_t *address); +bool nem_get_address(const ed25519_public_key public_key, uint8_t version, + char *address); bool nem_validate_address_raw(const uint8_t *address, uint8_t network); bool nem_validate_address(const char *address, uint8_t network); -void nem_transaction_start(nem_transaction_ctx *ctx, const ed25519_public_key public_key, uint8_t *buffer, size_t size); -size_t nem_transaction_end(nem_transaction_ctx *ctx, const ed25519_secret_key private_key, ed25519_signature signature); +void nem_transaction_start(nem_transaction_ctx *ctx, + const ed25519_public_key public_key, uint8_t *buffer, + size_t size); +size_t nem_transaction_end(nem_transaction_ctx *ctx, + const ed25519_secret_key private_key, + ed25519_signature signature); -bool nem_transaction_write_common(nem_transaction_ctx *context, - uint32_t type, - uint32_t version, - uint32_t timestamp, - const ed25519_public_key signer, - uint64_t fee, - uint32_t deadline); +bool nem_transaction_write_common(nem_transaction_ctx *context, uint32_t type, + uint32_t version, uint32_t timestamp, + const ed25519_public_key signer, uint64_t fee, + uint32_t deadline); bool nem_transaction_create_transfer(nem_transaction_ctx *context, - uint8_t network, - uint32_t timestamp, - const ed25519_public_key signer, - uint64_t fee, - uint32_t deadline, - const char *recipient, - uint64_t amount, - const uint8_t *payload, - uint32_t length, - bool encrypted, - uint32_t mosaics); + uint8_t network, uint32_t timestamp, + const ed25519_public_key signer, + uint64_t fee, uint32_t deadline, + const char *recipient, uint64_t amount, + const uint8_t *payload, uint32_t length, + bool encrypted, uint32_t mosaics); bool nem_transaction_write_mosaic(nem_transaction_ctx *ctx, - const char *namespace, - const char *mosaic, - uint64_t quantity); - -bool nem_transaction_create_multisig(nem_transaction_ctx *ctx, - uint8_t network, - uint32_t timestamp, - const ed25519_public_key signer, - uint64_t fee, - uint32_t deadline, - const nem_transaction_ctx *inner); - -bool nem_transaction_create_multisig_signature(nem_transaction_ctx *ctx, - uint8_t network, - uint32_t timestamp, - const ed25519_public_key signer, - uint64_t fee, - uint32_t deadline, - const nem_transaction_ctx *inner); - -bool nem_transaction_create_provision_namespace(nem_transaction_ctx *ctx, - uint8_t network, - uint32_t timestamp, - const ed25519_public_key signer, - uint64_t fee, - uint32_t deadline, - const char *namespace, - const char *parent, - const char *rental_sink, - uint64_t rental_fee); - -bool nem_transaction_create_mosaic_creation(nem_transaction_ctx *ctx, - uint8_t network, - uint32_t timestamp, - const ed25519_public_key signer, - uint64_t fee, - uint32_t deadline, - const char *namespace, - const char *mosaic, - const char *description, - uint32_t divisibility, - uint64_t supply, - bool mutable_supply, - bool transferable, - uint32_t levy_type, - uint64_t levy_fee, - const char *levy_address, - const char *levy_namespace, - const char *levy_mosaic, - const char *creation_sink, - uint64_t creation_fee); - -bool nem_transaction_create_mosaic_supply_change(nem_transaction_ctx *ctx, - uint8_t network, - uint32_t timestamp, - const ed25519_public_key signer, - uint64_t fee, - uint32_t deadline, - const char *namespace, - const char *mosaic, - uint32_t type, - uint64_t delta); - -bool nem_transaction_create_aggregate_modification(nem_transaction_ctx *ctx, - uint8_t network, - uint32_t timestamp, - const ed25519_public_key signer, - uint64_t fee, - uint32_t deadline, - uint32_t modifications, - bool relative_change); - -bool nem_transaction_write_cosignatory_modification(nem_transaction_ctx *ctx, - uint32_t type, - const ed25519_public_key cosignatory); + const char *namespace, const char *mosaic, + uint64_t quantity); + +bool nem_transaction_create_multisig(nem_transaction_ctx *ctx, uint8_t network, + uint32_t timestamp, + const ed25519_public_key signer, + uint64_t fee, uint32_t deadline, + const nem_transaction_ctx *inner); + +bool nem_transaction_create_multisig_signature( + nem_transaction_ctx *ctx, uint8_t network, uint32_t timestamp, + const ed25519_public_key signer, uint64_t fee, uint32_t deadline, + const nem_transaction_ctx *inner); + +bool nem_transaction_create_provision_namespace( + nem_transaction_ctx *ctx, uint8_t network, uint32_t timestamp, + const ed25519_public_key signer, uint64_t fee, uint32_t deadline, + const char *namespace, const char *parent, const char *rental_sink, + uint64_t rental_fee); + +bool nem_transaction_create_mosaic_creation( + nem_transaction_ctx *ctx, uint8_t network, uint32_t timestamp, + const ed25519_public_key signer, uint64_t fee, uint32_t deadline, + const char *namespace, const char *mosaic, const char *description, + uint32_t divisibility, uint64_t supply, bool mutable_supply, + bool transferable, uint32_t levy_type, uint64_t levy_fee, + const char *levy_address, const char *levy_namespace, + const char *levy_mosaic, const char *creation_sink, uint64_t creation_fee); + +bool nem_transaction_create_mosaic_supply_change( + nem_transaction_ctx *ctx, uint8_t network, uint32_t timestamp, + const ed25519_public_key signer, uint64_t fee, uint32_t deadline, + const char *namespace, const char *mosaic, uint32_t type, uint64_t delta); + +bool nem_transaction_create_aggregate_modification( + nem_transaction_ctx *ctx, uint8_t network, uint32_t timestamp, + const ed25519_public_key signer, uint64_t fee, uint32_t deadline, + uint32_t modifications, bool relative_change); + +bool nem_transaction_write_cosignatory_modification( + nem_transaction_ctx *ctx, uint32_t type, + const ed25519_public_key cosignatory); bool nem_transaction_write_minimum_cosignatories(nem_transaction_ctx *ctx, - int32_t relative_change); - -bool nem_transaction_create_importance_transfer(nem_transaction_ctx *ctx, - uint8_t network, - uint32_t timestamp, - const ed25519_public_key signer, - uint64_t fee, - uint32_t deadline, - uint32_t mode, - const ed25519_public_key remote); + int32_t relative_change); + +bool nem_transaction_create_importance_transfer( + nem_transaction_ctx *ctx, uint8_t network, uint32_t timestamp, + const ed25519_public_key signer, uint64_t fee, uint32_t deadline, + uint32_t mode, const ed25519_public_key remote); #endif diff --git a/nist256p1.c b/nist256p1.c index 7cffa5c39..e7e9f3a69 100644 --- a/nist256p1.c +++ b/nist256p1.c @@ -24,42 +24,45 @@ #include "nist256p1.h" const ecdsa_curve nist256p1 = { - /* .prime */ { - /*.val =*/ {0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3f, 0x0, 0x0, 0x1000, 0x3fffc000, 0xffff} - }, + /* .prime */ {/*.val =*/{0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3f, 0x0, 0x0, + 0x1000, 0x3fffc000, 0xffff}}, - /* G */ { - /*.x =*/{/*.val =*/{0x1898c296, 0x1284e517, 0x1eb33a0f, 0xdf604b, 0x2440f277, 0x339b958e, 0x4247f8b, 0x347cb84b, 0x6b17}}, - /*.y =*/{/*.val =*/{0x37bf51f5, 0x2ed901a0, 0x3315ecec, 0x338cd5da, 0xf9e162b, 0x1fad29f0, 0x27f9b8ee, 0x10b8bf86, 0x4fe3}} - }, + /* G */ + {/*.x =*/{/*.val =*/{0x1898c296, 0x1284e517, 0x1eb33a0f, 0xdf604b, + 0x2440f277, 0x339b958e, 0x4247f8b, 0x347cb84b, + 0x6b17}}, + /*.y =*/{/*.val =*/{0x37bf51f5, 0x2ed901a0, 0x3315ecec, 0x338cd5da, + 0xf9e162b, 0x1fad29f0, 0x27f9b8ee, 0x10b8bf86, + 0x4fe3}}}, - /* order */ { - /*.val =*/{0x3c632551, 0xee72b0b, 0x3179e84f, 0x39beab69, 0x3fffffbc, 0x3fffffff, 0xfff, 0x3fffc000, 0xffff} - }, + /* order */ + {/*.val =*/{0x3c632551, 0xee72b0b, 0x3179e84f, 0x39beab69, 0x3fffffbc, + 0x3fffffff, 0xfff, 0x3fffc000, 0xffff}}, - /* order_half */ { - /*.val =*/{0x3e3192a8, 0x27739585, 0x38bcf427, 0x1cdf55b4, 0x3fffffde, 0x3fffffff, 0x7ff, 0x3fffe000, 0x7fff} - }, + /* order_half */ + {/*.val =*/{0x3e3192a8, 0x27739585, 0x38bcf427, 0x1cdf55b4, 0x3fffffde, + 0x3fffffff, 0x7ff, 0x3fffe000, 0x7fff}}, - /* a */ -3, + /* a */ -3, - /* b */ { - /*.val =*/{0x27d2604b, 0x2f38f0f8, 0x53b0f63, 0x741ac33, 0x1886bc65, 0x2ef555da, 0x293e7b3e, 0xd762a8e, 0x5ac6} - } + /* b */ + {/*.val =*/{0x27d2604b, 0x2f38f0f8, 0x53b0f63, 0x741ac33, 0x1886bc65, + 0x2ef555da, 0x293e7b3e, 0xd762a8e, 0x5ac6}} #if USE_PRECOMPUTED_CP - , - /* cp */ { + , + /* cp */ + { #include "nist256p1.table" - } + } #endif }; const curve_info nist256p1_info = { - .bip32_name = "Nist256p1 seed", - .params = &nist256p1, - .hasher_base58 = HASHER_SHA2D, - .hasher_sign = HASHER_SHA2D, - .hasher_pubkey = HASHER_SHA2_RIPEMD, - .hasher_script = HASHER_SHA2, + .bip32_name = "Nist256p1 seed", + .params = &nist256p1, + .hasher_base58 = HASHER_SHA2D, + .hasher_sign = HASHER_SHA2D, + .hasher_pubkey = HASHER_SHA2_RIPEMD, + .hasher_script = HASHER_SHA2, }; diff --git a/nist256p1.h b/nist256p1.h index a1a767efd..02d04025a 100644 --- a/nist256p1.h +++ b/nist256p1.h @@ -26,8 +26,8 @@ #include -#include "ecdsa.h" #include "bip32.h" +#include "ecdsa.h" extern const ecdsa_curve nist256p1; extern const curve_info nist256p1_info; diff --git a/options.h b/options.h index e57654e6c..d3a9c2edf 100644 --- a/options.h +++ b/options.h @@ -52,7 +52,7 @@ // support constructing BIP32 nodes from ed25519 and curve25519 curves. #ifndef USE_BIP32_25519_CURVES -#define USE_BIP32_25519_CURVES 1 +#define USE_BIP32_25519_CURVES 1 #endif // implement BIP39 caching diff --git a/pbkdf2.c b/pbkdf2.c index 719fc89e2..9380b667a 100644 --- a/pbkdf2.c +++ b/pbkdf2.c @@ -21,157 +21,159 @@ * OTHER DEALINGS IN THE SOFTWARE. */ -#include #include "pbkdf2.h" +#include #include "hmac.h" -#include "sha2.h" #include "memzero.h" +#include "sha2.h" -void pbkdf2_hmac_sha256_Init(PBKDF2_HMAC_SHA256_CTX *pctx, const uint8_t *pass, int passlen, const uint8_t *salt, int saltlen, uint32_t blocknr) -{ - SHA256_CTX ctx; +void pbkdf2_hmac_sha256_Init(PBKDF2_HMAC_SHA256_CTX *pctx, const uint8_t *pass, + int passlen, const uint8_t *salt, int saltlen, + uint32_t blocknr) { + SHA256_CTX ctx; #if BYTE_ORDER == LITTLE_ENDIAN - REVERSE32(blocknr, blocknr); + REVERSE32(blocknr, blocknr); #endif - hmac_sha256_prepare(pass, passlen, pctx->odig, pctx->idig); - memzero(pctx->g, sizeof(pctx->g)); - pctx->g[8] = 0x80000000; - pctx->g[15] = (SHA256_BLOCK_LENGTH + SHA256_DIGEST_LENGTH) * 8; + hmac_sha256_prepare(pass, passlen, pctx->odig, pctx->idig); + memzero(pctx->g, sizeof(pctx->g)); + pctx->g[8] = 0x80000000; + pctx->g[15] = (SHA256_BLOCK_LENGTH + SHA256_DIGEST_LENGTH) * 8; - memcpy (ctx.state, pctx->idig, sizeof(pctx->idig)); - ctx.bitcount = SHA256_BLOCK_LENGTH * 8; - sha256_Update(&ctx, salt, saltlen); - sha256_Update(&ctx, (uint8_t*)&blocknr, sizeof(blocknr)); - sha256_Final(&ctx, (uint8_t*)pctx->g); + memcpy(ctx.state, pctx->idig, sizeof(pctx->idig)); + ctx.bitcount = SHA256_BLOCK_LENGTH * 8; + sha256_Update(&ctx, salt, saltlen); + sha256_Update(&ctx, (uint8_t *)&blocknr, sizeof(blocknr)); + sha256_Final(&ctx, (uint8_t *)pctx->g); #if BYTE_ORDER == LITTLE_ENDIAN - for (uint32_t k = 0; k < SHA256_DIGEST_LENGTH / sizeof(uint32_t); k++) { - REVERSE32(pctx->g[k], pctx->g[k]); - } + for (uint32_t k = 0; k < SHA256_DIGEST_LENGTH / sizeof(uint32_t); k++) { + REVERSE32(pctx->g[k], pctx->g[k]); + } #endif - sha256_Transform(pctx->odig, pctx->g, pctx->g); - memcpy(pctx->f, pctx->g, SHA256_DIGEST_LENGTH); - pctx->first = 1; + sha256_Transform(pctx->odig, pctx->g, pctx->g); + memcpy(pctx->f, pctx->g, SHA256_DIGEST_LENGTH); + pctx->first = 1; } -void pbkdf2_hmac_sha256_Update(PBKDF2_HMAC_SHA256_CTX *pctx, uint32_t iterations) -{ - for (uint32_t i = pctx->first; i < iterations; i++) { - sha256_Transform(pctx->idig, pctx->g, pctx->g); - sha256_Transform(pctx->odig, pctx->g, pctx->g); - for (uint32_t j = 0; j < SHA256_DIGEST_LENGTH/sizeof(uint32_t); j++) { - pctx->f[j] ^= pctx->g[j]; - } - } - pctx->first = 0; +void pbkdf2_hmac_sha256_Update(PBKDF2_HMAC_SHA256_CTX *pctx, + uint32_t iterations) { + for (uint32_t i = pctx->first; i < iterations; i++) { + sha256_Transform(pctx->idig, pctx->g, pctx->g); + sha256_Transform(pctx->odig, pctx->g, pctx->g); + for (uint32_t j = 0; j < SHA256_DIGEST_LENGTH / sizeof(uint32_t); j++) { + pctx->f[j] ^= pctx->g[j]; + } + } + pctx->first = 0; } -void pbkdf2_hmac_sha256_Final(PBKDF2_HMAC_SHA256_CTX *pctx, uint8_t *key) -{ +void pbkdf2_hmac_sha256_Final(PBKDF2_HMAC_SHA256_CTX *pctx, uint8_t *key) { #if BYTE_ORDER == LITTLE_ENDIAN - for (uint32_t k = 0; k < SHA256_DIGEST_LENGTH/sizeof(uint32_t); k++) { - REVERSE32(pctx->f[k], pctx->f[k]); - } + for (uint32_t k = 0; k < SHA256_DIGEST_LENGTH / sizeof(uint32_t); k++) { + REVERSE32(pctx->f[k], pctx->f[k]); + } #endif - memcpy(key, pctx->f, SHA256_DIGEST_LENGTH); - memzero(pctx, sizeof(PBKDF2_HMAC_SHA256_CTX)); + memcpy(key, pctx->f, SHA256_DIGEST_LENGTH); + memzero(pctx, sizeof(PBKDF2_HMAC_SHA256_CTX)); } -void pbkdf2_hmac_sha256(const uint8_t *pass, int passlen, const uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key, int keylen) -{ - uint32_t last_block_size = keylen % SHA256_DIGEST_LENGTH; - uint32_t blocks_count = keylen / SHA256_DIGEST_LENGTH; - if (last_block_size) { - blocks_count++; - } else { - last_block_size = SHA256_DIGEST_LENGTH; - } - for (uint32_t blocknr = 1; blocknr <= blocks_count; blocknr++) { - PBKDF2_HMAC_SHA256_CTX pctx; - pbkdf2_hmac_sha256_Init(&pctx, pass, passlen, salt, saltlen, blocknr); - pbkdf2_hmac_sha256_Update(&pctx, iterations); - uint8_t digest[SHA256_DIGEST_LENGTH]; - pbkdf2_hmac_sha256_Final(&pctx, digest); - uint32_t key_offset = (blocknr - 1) * SHA256_DIGEST_LENGTH; - if (blocknr < blocks_count) { - memcpy(key + key_offset, digest, SHA256_DIGEST_LENGTH); - } else { - memcpy(key + key_offset, digest, last_block_size); - } - } +void pbkdf2_hmac_sha256(const uint8_t *pass, int passlen, const uint8_t *salt, + int saltlen, uint32_t iterations, uint8_t *key, + int keylen) { + uint32_t last_block_size = keylen % SHA256_DIGEST_LENGTH; + uint32_t blocks_count = keylen / SHA256_DIGEST_LENGTH; + if (last_block_size) { + blocks_count++; + } else { + last_block_size = SHA256_DIGEST_LENGTH; + } + for (uint32_t blocknr = 1; blocknr <= blocks_count; blocknr++) { + PBKDF2_HMAC_SHA256_CTX pctx; + pbkdf2_hmac_sha256_Init(&pctx, pass, passlen, salt, saltlen, blocknr); + pbkdf2_hmac_sha256_Update(&pctx, iterations); + uint8_t digest[SHA256_DIGEST_LENGTH]; + pbkdf2_hmac_sha256_Final(&pctx, digest); + uint32_t key_offset = (blocknr - 1) * SHA256_DIGEST_LENGTH; + if (blocknr < blocks_count) { + memcpy(key + key_offset, digest, SHA256_DIGEST_LENGTH); + } else { + memcpy(key + key_offset, digest, last_block_size); + } + } } -void pbkdf2_hmac_sha512_Init(PBKDF2_HMAC_SHA512_CTX *pctx, const uint8_t *pass, int passlen, const uint8_t *salt, int saltlen, uint32_t blocknr) -{ - SHA512_CTX ctx; +void pbkdf2_hmac_sha512_Init(PBKDF2_HMAC_SHA512_CTX *pctx, const uint8_t *pass, + int passlen, const uint8_t *salt, int saltlen, + uint32_t blocknr) { + SHA512_CTX ctx; #if BYTE_ORDER == LITTLE_ENDIAN - REVERSE32(blocknr, blocknr); + REVERSE32(blocknr, blocknr); #endif - hmac_sha512_prepare(pass, passlen, pctx->odig, pctx->idig); - memzero(pctx->g, sizeof(pctx->g)); - pctx->g[8] = 0x8000000000000000; - pctx->g[15] = (SHA512_BLOCK_LENGTH + SHA512_DIGEST_LENGTH) * 8; + hmac_sha512_prepare(pass, passlen, pctx->odig, pctx->idig); + memzero(pctx->g, sizeof(pctx->g)); + pctx->g[8] = 0x8000000000000000; + pctx->g[15] = (SHA512_BLOCK_LENGTH + SHA512_DIGEST_LENGTH) * 8; - memcpy (ctx.state, pctx->idig, sizeof(pctx->idig)); - ctx.bitcount[0] = SHA512_BLOCK_LENGTH * 8; - ctx.bitcount[1] = 0; - sha512_Update(&ctx, salt, saltlen); - sha512_Update(&ctx, (uint8_t*)&blocknr, sizeof(blocknr)); - sha512_Final(&ctx, (uint8_t*)pctx->g); + memcpy(ctx.state, pctx->idig, sizeof(pctx->idig)); + ctx.bitcount[0] = SHA512_BLOCK_LENGTH * 8; + ctx.bitcount[1] = 0; + sha512_Update(&ctx, salt, saltlen); + sha512_Update(&ctx, (uint8_t *)&blocknr, sizeof(blocknr)); + sha512_Final(&ctx, (uint8_t *)pctx->g); #if BYTE_ORDER == LITTLE_ENDIAN - for (uint32_t k = 0; k < SHA512_DIGEST_LENGTH / sizeof(uint64_t); k++) { - REVERSE64(pctx->g[k], pctx->g[k]); - } + for (uint32_t k = 0; k < SHA512_DIGEST_LENGTH / sizeof(uint64_t); k++) { + REVERSE64(pctx->g[k], pctx->g[k]); + } #endif - sha512_Transform(pctx->odig, pctx->g, pctx->g); - memcpy(pctx->f, pctx->g, SHA512_DIGEST_LENGTH); - pctx->first = 1; + sha512_Transform(pctx->odig, pctx->g, pctx->g); + memcpy(pctx->f, pctx->g, SHA512_DIGEST_LENGTH); + pctx->first = 1; } -void pbkdf2_hmac_sha512_Update(PBKDF2_HMAC_SHA512_CTX *pctx, uint32_t iterations) -{ - for (uint32_t i = pctx->first; i < iterations; i++) { - sha512_Transform(pctx->idig, pctx->g, pctx->g); - sha512_Transform(pctx->odig, pctx->g, pctx->g); - for (uint32_t j = 0; j < SHA512_DIGEST_LENGTH / sizeof(uint64_t); j++) { - pctx->f[j] ^= pctx->g[j]; - } - } - pctx->first = 0; +void pbkdf2_hmac_sha512_Update(PBKDF2_HMAC_SHA512_CTX *pctx, + uint32_t iterations) { + for (uint32_t i = pctx->first; i < iterations; i++) { + sha512_Transform(pctx->idig, pctx->g, pctx->g); + sha512_Transform(pctx->odig, pctx->g, pctx->g); + for (uint32_t j = 0; j < SHA512_DIGEST_LENGTH / sizeof(uint64_t); j++) { + pctx->f[j] ^= pctx->g[j]; + } + } + pctx->first = 0; } -void pbkdf2_hmac_sha512_Final(PBKDF2_HMAC_SHA512_CTX *pctx, uint8_t *key) -{ +void pbkdf2_hmac_sha512_Final(PBKDF2_HMAC_SHA512_CTX *pctx, uint8_t *key) { #if BYTE_ORDER == LITTLE_ENDIAN - for (uint32_t k = 0; k < SHA512_DIGEST_LENGTH/sizeof(uint64_t); k++) { - REVERSE64(pctx->f[k], pctx->f[k]); - } + for (uint32_t k = 0; k < SHA512_DIGEST_LENGTH / sizeof(uint64_t); k++) { + REVERSE64(pctx->f[k], pctx->f[k]); + } #endif - memcpy(key, pctx->f, SHA512_DIGEST_LENGTH); - memzero(pctx, sizeof(PBKDF2_HMAC_SHA512_CTX)); + memcpy(key, pctx->f, SHA512_DIGEST_LENGTH); + memzero(pctx, sizeof(PBKDF2_HMAC_SHA512_CTX)); } -void pbkdf2_hmac_sha512(const uint8_t *pass, int passlen, const uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key, int keylen) -{ - uint32_t last_block_size = keylen % SHA512_DIGEST_LENGTH; - uint32_t blocks_count = keylen / SHA512_DIGEST_LENGTH; - if (last_block_size) { - blocks_count++; - } else { - last_block_size = SHA512_DIGEST_LENGTH; - } - for (uint32_t blocknr = 1; blocknr <= blocks_count; blocknr++) { - PBKDF2_HMAC_SHA512_CTX pctx; - pbkdf2_hmac_sha512_Init(&pctx, pass, passlen, salt, saltlen, blocknr); - pbkdf2_hmac_sha512_Update(&pctx, iterations); - uint8_t digest[SHA512_DIGEST_LENGTH]; - pbkdf2_hmac_sha512_Final(&pctx, digest); - uint32_t key_offset = (blocknr - 1) * SHA512_DIGEST_LENGTH; - if (blocknr < blocks_count) { - memcpy(key + key_offset, digest, SHA512_DIGEST_LENGTH); - } else { - memcpy(key + key_offset, digest, last_block_size); - } - } +void pbkdf2_hmac_sha512(const uint8_t *pass, int passlen, const uint8_t *salt, + int saltlen, uint32_t iterations, uint8_t *key, + int keylen) { + uint32_t last_block_size = keylen % SHA512_DIGEST_LENGTH; + uint32_t blocks_count = keylen / SHA512_DIGEST_LENGTH; + if (last_block_size) { + blocks_count++; + } else { + last_block_size = SHA512_DIGEST_LENGTH; + } + for (uint32_t blocknr = 1; blocknr <= blocks_count; blocknr++) { + PBKDF2_HMAC_SHA512_CTX pctx; + pbkdf2_hmac_sha512_Init(&pctx, pass, passlen, salt, saltlen, blocknr); + pbkdf2_hmac_sha512_Update(&pctx, iterations); + uint8_t digest[SHA512_DIGEST_LENGTH]; + pbkdf2_hmac_sha512_Final(&pctx, digest); + uint32_t key_offset = (blocknr - 1) * SHA512_DIGEST_LENGTH; + if (blocknr < blocks_count) { + memcpy(key + key_offset, digest, SHA512_DIGEST_LENGTH); + } else { + memcpy(key + key_offset, digest, last_block_size); + } + } } diff --git a/pbkdf2.h b/pbkdf2.h index e3f440c8f..c2e3f04a6 100644 --- a/pbkdf2.h +++ b/pbkdf2.h @@ -28,29 +28,39 @@ #include "sha2.h" typedef struct _PBKDF2_HMAC_SHA256_CTX { - uint32_t odig[SHA256_DIGEST_LENGTH / sizeof(uint32_t)]; - uint32_t idig[SHA256_DIGEST_LENGTH / sizeof(uint32_t)]; - uint32_t f[SHA256_DIGEST_LENGTH / sizeof(uint32_t)]; - uint32_t g[SHA256_BLOCK_LENGTH / sizeof(uint32_t)]; - char first; + uint32_t odig[SHA256_DIGEST_LENGTH / sizeof(uint32_t)]; + uint32_t idig[SHA256_DIGEST_LENGTH / sizeof(uint32_t)]; + uint32_t f[SHA256_DIGEST_LENGTH / sizeof(uint32_t)]; + uint32_t g[SHA256_BLOCK_LENGTH / sizeof(uint32_t)]; + char first; } PBKDF2_HMAC_SHA256_CTX; typedef struct _PBKDF2_HMAC_SHA512_CTX { - uint64_t odig[SHA512_DIGEST_LENGTH / sizeof(uint64_t)]; - uint64_t idig[SHA512_DIGEST_LENGTH / sizeof(uint64_t)]; - uint64_t f[SHA512_DIGEST_LENGTH / sizeof(uint64_t)]; - uint64_t g[SHA512_BLOCK_LENGTH / sizeof(uint64_t)]; - char first; + uint64_t odig[SHA512_DIGEST_LENGTH / sizeof(uint64_t)]; + uint64_t idig[SHA512_DIGEST_LENGTH / sizeof(uint64_t)]; + uint64_t f[SHA512_DIGEST_LENGTH / sizeof(uint64_t)]; + uint64_t g[SHA512_BLOCK_LENGTH / sizeof(uint64_t)]; + char first; } PBKDF2_HMAC_SHA512_CTX; -void pbkdf2_hmac_sha256_Init(PBKDF2_HMAC_SHA256_CTX *pctx, const uint8_t *pass, int passlen, const uint8_t *salt, int saltlen, uint32_t blocknr); -void pbkdf2_hmac_sha256_Update(PBKDF2_HMAC_SHA256_CTX *pctx, uint32_t iterations); +void pbkdf2_hmac_sha256_Init(PBKDF2_HMAC_SHA256_CTX *pctx, const uint8_t *pass, + int passlen, const uint8_t *salt, int saltlen, + uint32_t blocknr); +void pbkdf2_hmac_sha256_Update(PBKDF2_HMAC_SHA256_CTX *pctx, + uint32_t iterations); void pbkdf2_hmac_sha256_Final(PBKDF2_HMAC_SHA256_CTX *pctx, uint8_t *key); -void pbkdf2_hmac_sha256(const uint8_t *pass, int passlen, const uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key, int keylen); +void pbkdf2_hmac_sha256(const uint8_t *pass, int passlen, const uint8_t *salt, + int saltlen, uint32_t iterations, uint8_t *key, + int keylen); -void pbkdf2_hmac_sha512_Init(PBKDF2_HMAC_SHA512_CTX *pctx, const uint8_t *pass, int passlen, const uint8_t *salt, int saltlen, uint32_t blocknr); -void pbkdf2_hmac_sha512_Update(PBKDF2_HMAC_SHA512_CTX *pctx, uint32_t iterations); +void pbkdf2_hmac_sha512_Init(PBKDF2_HMAC_SHA512_CTX *pctx, const uint8_t *pass, + int passlen, const uint8_t *salt, int saltlen, + uint32_t blocknr); +void pbkdf2_hmac_sha512_Update(PBKDF2_HMAC_SHA512_CTX *pctx, + uint32_t iterations); void pbkdf2_hmac_sha512_Final(PBKDF2_HMAC_SHA512_CTX *pctx, uint8_t *key); -void pbkdf2_hmac_sha512(const uint8_t *pass, int passlen, const uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key, int keylen); +void pbkdf2_hmac_sha512(const uint8_t *pass, int passlen, const uint8_t *salt, + int saltlen, uint32_t iterations, uint8_t *key, + int keylen); #endif diff --git a/rand.c b/rand.c index 411c755a3..bed9002cc 100644 --- a/rand.c +++ b/rand.c @@ -25,28 +25,27 @@ #ifndef RAND_PLATFORM_INDEPENDENT -#pragma message("NOT SUITABLE FOR PRODUCTION USE! Replace random32() function with your own secure code.") +#pragma message( \ + "NOT SUITABLE FOR PRODUCTION USE! Replace random32() function with your own secure code.") // The following code is not supposed to be used in a production environment. // It's included only to make the library testable. -// The message above tries to prevent any accidental use outside of the test environment. +// The message above tries to prevent any accidental use outside of the test +// environment. // -// You are supposed to replace the random8() and random32() function with your own secure code. -// There is also a possibility to replace the random_buffer() function as it is defined as a weak symbol. +// You are supposed to replace the random8() and random32() function with your +// own secure code. There is also a possibility to replace the random_buffer() +// function as it is defined as a weak symbol. static uint32_t seed = 0; -void random_reseed(const uint32_t value) -{ - seed = value; -} +void random_reseed(const uint32_t value) { seed = value; } -uint32_t random32(void) -{ - // Linear congruential generator from Numerical Recipes - // https://en.wikipedia.org/wiki/Linear_congruential_generator - seed = 1664525 * seed + 1013904223; - return seed; +uint32_t random32(void) { + // Linear congruential generator from Numerical Recipes + // https://en.wikipedia.org/wiki/Linear_congruential_generator + seed = 1664525 * seed + 1013904223; + return seed; } #endif /* RAND_PLATFORM_INDEPENDENT */ @@ -55,30 +54,28 @@ uint32_t random32(void) // The following code is platform independent // -void __attribute__((weak)) random_buffer(uint8_t *buf, size_t len) -{ - uint32_t r = 0; - for (size_t i = 0; i < len; i++) { - if (i % 4 == 0) { - r = random32(); - } - buf[i] = (r >> ((i % 4) * 8)) & 0xFF; - } +void __attribute__((weak)) random_buffer(uint8_t *buf, size_t len) { + uint32_t r = 0; + for (size_t i = 0; i < len; i++) { + if (i % 4 == 0) { + r = random32(); + } + buf[i] = (r >> ((i % 4) * 8)) & 0xFF; + } } -uint32_t random_uniform(uint32_t n) -{ - uint32_t x, max = 0xFFFFFFFF - (0xFFFFFFFF % n); - while ((x = random32()) >= max); - return x / (max / n); +uint32_t random_uniform(uint32_t n) { + uint32_t x, max = 0xFFFFFFFF - (0xFFFFFFFF % n); + while ((x = random32()) >= max) + ; + return x / (max / n); } -void random_permute(char *str, size_t len) -{ - for (int i = len - 1; i >= 1; i--) { - int j = random_uniform(i + 1); - char t = str[j]; - str[j] = str[i]; - str[i] = t; - } +void random_permute(char *str, size_t len) { + for (int i = len - 1; i >= 1; i--) { + int j = random_uniform(i + 1); + char t = str[j]; + str[j] = str[i]; + str[i] = t; + } } diff --git a/rc4.c b/rc4.c index db9eb1ffa..fea73cab1 100644 --- a/rc4.c +++ b/rc4.c @@ -23,34 +23,34 @@ #include "rc4.h" static inline void rc4_swap(RC4_CTX *ctx, uint8_t i, uint8_t j) { - uint8_t temp = ctx->S[i]; - ctx->S[i] = ctx->S[j]; - ctx->S[j] = temp; + uint8_t temp = ctx->S[i]; + ctx->S[i] = ctx->S[j]; + ctx->S[j] = temp; } void rc4_init(RC4_CTX *ctx, const uint8_t *key, size_t length) { - ctx->i = 0; - ctx->j = 0; - - for (size_t i = 0; i < 256; i++) { - ctx->S[i] = i; - } - - uint8_t j = 0; - for (size_t i = 0; i < 256; i++) { - j += ctx->S[i] + key[i % length]; - rc4_swap(ctx, i, j); - } + ctx->i = 0; + ctx->j = 0; + + for (size_t i = 0; i < 256; i++) { + ctx->S[i] = i; + } + + uint8_t j = 0; + for (size_t i = 0; i < 256; i++) { + j += ctx->S[i] + key[i % length]; + rc4_swap(ctx, i, j); + } } void rc4_encrypt(RC4_CTX *ctx, uint8_t *buffer, size_t length) { - for (size_t idx = 0; idx < length; idx++) { - ctx->i++; - ctx->j += ctx->S[ctx->i]; + for (size_t idx = 0; idx < length; idx++) { + ctx->i++; + ctx->j += ctx->S[ctx->i]; - rc4_swap(ctx, ctx->i, ctx->j); + rc4_swap(ctx, ctx->i, ctx->j); - uint8_t K = ctx->S[(ctx->S[ctx->i] + ctx->S[ctx->j]) % 256]; - buffer[idx] ^= K; - } + uint8_t K = ctx->S[(ctx->S[ctx->i] + ctx->S[ctx->j]) % 256]; + buffer[idx] ^= K; + } } diff --git a/rc4.h b/rc4.h index 7b56e4a3d..8ba8a9b25 100644 --- a/rc4.h +++ b/rc4.h @@ -23,12 +23,12 @@ #ifndef __RC4_H__ #define __RC4_H__ -#include #include +#include typedef struct { - uint8_t S[256]; - uint8_t i, j; + uint8_t S[256]; + uint8_t i, j; } RC4_CTX; void rc4_init(RC4_CTX *ctx, const uint8_t *key, size_t length); diff --git a/rfc6979.c b/rfc6979.c index ec808a7cf..8f5f1c913 100644 --- a/rfc6979.c +++ b/rfc6979.c @@ -22,57 +22,56 @@ * OTHER DEALINGS IN THE SOFTWARE. */ -#include #include "rfc6979.h" +#include #include "hmac.h" #include "memzero.h" -void init_rfc6979(const uint8_t *priv_key, const uint8_t *hash, rfc6979_state *state) { - uint8_t bx[2*32]; - uint8_t buf[32 + 1 + 2*32]; +void init_rfc6979(const uint8_t *priv_key, const uint8_t *hash, + rfc6979_state *state) { + uint8_t bx[2 * 32]; + uint8_t buf[32 + 1 + 2 * 32]; - memcpy(bx, priv_key, 32); - memcpy(bx+32, hash, 32); + memcpy(bx, priv_key, 32); + memcpy(bx + 32, hash, 32); - memset(state->v, 1, sizeof(state->v)); - memset(state->k, 0, sizeof(state->k)); + memset(state->v, 1, sizeof(state->v)); + memset(state->k, 0, sizeof(state->k)); - memcpy(buf, state->v, sizeof(state->v)); - buf[sizeof(state->v)] = 0x00; - memcpy(buf + sizeof(state->v) + 1, bx, 64); - hmac_sha256(state->k, sizeof(state->k), buf, sizeof(buf), state->k); - hmac_sha256(state->k, sizeof(state->k), state->v, sizeof(state->v), state->v); + memcpy(buf, state->v, sizeof(state->v)); + buf[sizeof(state->v)] = 0x00; + memcpy(buf + sizeof(state->v) + 1, bx, 64); + hmac_sha256(state->k, sizeof(state->k), buf, sizeof(buf), state->k); + hmac_sha256(state->k, sizeof(state->k), state->v, sizeof(state->v), state->v); - memcpy(buf, state->v, sizeof(state->v)); - buf[sizeof(state->v)] = 0x01; - memcpy(buf + sizeof(state->v) + 1, bx, 64); - hmac_sha256(state->k, sizeof(state->k), buf, sizeof(buf), state->k); - hmac_sha256(state->k, sizeof(state->k), state->v, sizeof(state->v), state->v); + memcpy(buf, state->v, sizeof(state->v)); + buf[sizeof(state->v)] = 0x01; + memcpy(buf + sizeof(state->v) + 1, bx, 64); + hmac_sha256(state->k, sizeof(state->k), buf, sizeof(buf), state->k); + hmac_sha256(state->k, sizeof(state->k), state->v, sizeof(state->v), state->v); - memzero(bx, sizeof(bx)); - memzero(buf, sizeof(buf)); + memzero(bx, sizeof(bx)); + memzero(buf, sizeof(buf)); } // generate next number from deterministic random number generator -void generate_rfc6979(uint8_t rnd[32], rfc6979_state *state) -{ - uint8_t buf[32 + 1]; +void generate_rfc6979(uint8_t rnd[32], rfc6979_state *state) { + uint8_t buf[32 + 1]; - hmac_sha256(state->k, sizeof(state->k), state->v, sizeof(state->v), state->v); - memcpy(buf, state->v, sizeof(state->v)); - buf[sizeof(state->v)] = 0x00; - hmac_sha256(state->k, sizeof(state->k), buf, sizeof(state->v) + 1, state->k); - hmac_sha256(state->k, sizeof(state->k), state->v, sizeof(state->v), state->v); - memcpy(rnd, buf, 32); - memzero(buf, sizeof(buf)); + hmac_sha256(state->k, sizeof(state->k), state->v, sizeof(state->v), state->v); + memcpy(buf, state->v, sizeof(state->v)); + buf[sizeof(state->v)] = 0x00; + hmac_sha256(state->k, sizeof(state->k), buf, sizeof(state->v) + 1, state->k); + hmac_sha256(state->k, sizeof(state->k), state->v, sizeof(state->v), state->v); + memcpy(rnd, buf, 32); + memzero(buf, sizeof(buf)); } // generate K in a deterministic way, according to RFC6979 // http://tools.ietf.org/html/rfc6979 -void generate_k_rfc6979(bignum256 *k, rfc6979_state *state) -{ - uint8_t buf[32]; - generate_rfc6979(buf, state); - bn_read_be(buf, k); - memzero(buf, sizeof(buf)); +void generate_k_rfc6979(bignum256 *k, rfc6979_state *state) { + uint8_t buf[32]; + generate_rfc6979(buf, state); + bn_read_be(buf, k); + memzero(buf, sizeof(buf)); } diff --git a/rfc6979.h b/rfc6979.h index e541d6ade..30ef0f17a 100644 --- a/rfc6979.h +++ b/rfc6979.h @@ -30,10 +30,11 @@ // rfc6979 pseudo random number generator state typedef struct { - uint8_t v[32], k[32]; + uint8_t v[32], k[32]; } rfc6979_state; -void init_rfc6979(const uint8_t *priv_key, const uint8_t *hash, rfc6979_state *rng); +void init_rfc6979(const uint8_t *priv_key, const uint8_t *hash, + rfc6979_state *rng); void generate_rfc6979(uint8_t rnd[32], rfc6979_state *rng); void generate_k_rfc6979(bignum256 *k, rfc6979_state *rng); diff --git a/ripemd160.h b/ripemd160.h index a62de5cfc..8256b08a1 100644 --- a/ripemd160.h +++ b/ripemd160.h @@ -3,18 +3,20 @@ #include -#define RIPEMD160_BLOCK_LENGTH 64 -#define RIPEMD160_DIGEST_LENGTH 20 +#define RIPEMD160_BLOCK_LENGTH 64 +#define RIPEMD160_DIGEST_LENGTH 20 typedef struct _RIPEMD160_CTX { - uint32_t total[2]; /*!< number of bytes processed */ - uint32_t state[5]; /*!< intermediate digest state */ - uint8_t buffer[RIPEMD160_BLOCK_LENGTH]; /*!< data block being processed */ + uint32_t total[2]; /*!< number of bytes processed */ + uint32_t state[5]; /*!< intermediate digest state */ + uint8_t buffer[RIPEMD160_BLOCK_LENGTH]; /*!< data block being processed */ } RIPEMD160_CTX; void ripemd160_Init(RIPEMD160_CTX *ctx); void ripemd160_Update(RIPEMD160_CTX *ctx, const uint8_t *input, uint32_t ilen); -void ripemd160_Final(RIPEMD160_CTX *ctx, uint8_t output[RIPEMD160_DIGEST_LENGTH]); -void ripemd160(const uint8_t *msg, uint32_t msg_len, uint8_t hash[RIPEMD160_DIGEST_LENGTH]); +void ripemd160_Final(RIPEMD160_CTX *ctx, + uint8_t output[RIPEMD160_DIGEST_LENGTH]); +void ripemd160(const uint8_t *msg, uint32_t msg_len, + uint8_t hash[RIPEMD160_DIGEST_LENGTH]); #endif diff --git a/script.c b/script.c index 3ddb3a658..45691044e 100644 --- a/script.c +++ b/script.c @@ -20,45 +20,47 @@ * OTHER DEALINGS IN THE SOFTWARE. */ +#include "script.h" #include #include "base58.h" -#include "script.h" -int script_output_to_address(const uint8_t *script, int scriptlen, char *addr, int addrsize) -{ - uint8_t raw[35]; +int script_output_to_address(const uint8_t *script, int scriptlen, char *addr, + int addrsize) { + uint8_t raw[35]; - // P2PKH - if (scriptlen == 25 && script[0] == 0x76 && script[1] == 0xA9 && script[2] == 0x14 && script[23] == 0x88 && script[24] == 0xAC) { - raw[0] = 0x00; - memcpy(raw + 1, script + 3, 20); - return base58_encode_check(raw, 1 + 20, HASHER_SHA2D, addr, addrsize); - } + // P2PKH + if (scriptlen == 25 && script[0] == 0x76 && script[1] == 0xA9 && + script[2] == 0x14 && script[23] == 0x88 && script[24] == 0xAC) { + raw[0] = 0x00; + memcpy(raw + 1, script + 3, 20); + return base58_encode_check(raw, 1 + 20, HASHER_SHA2D, addr, addrsize); + } - // P2SH - if (scriptlen == 23 && script[0] == 0xA9 && script[1] == 0x14 && script[22] == 0x87) { - raw[0] = 0x05; - memcpy(raw + 1, script + 2, 20); - return base58_encode_check(raw, 1 + 20, HASHER_SHA2D, addr, addrsize); - } + // P2SH + if (scriptlen == 23 && script[0] == 0xA9 && script[1] == 0x14 && + script[22] == 0x87) { + raw[0] = 0x05; + memcpy(raw + 1, script + 2, 20); + return base58_encode_check(raw, 1 + 20, HASHER_SHA2D, addr, addrsize); + } - // P2WPKH - if (scriptlen == 22 && script[0] == 0x00 && script[1] == 0x14) { - raw[0] = 0x06; - raw[1] = 0x00; - raw[2] = 0x00; - memcpy(raw + 3, script + 2, 20); - return base58_encode_check(raw, 3 + 20, HASHER_SHA2D, addr, addrsize); - } + // P2WPKH + if (scriptlen == 22 && script[0] == 0x00 && script[1] == 0x14) { + raw[0] = 0x06; + raw[1] = 0x00; + raw[2] = 0x00; + memcpy(raw + 3, script + 2, 20); + return base58_encode_check(raw, 3 + 20, HASHER_SHA2D, addr, addrsize); + } - // P2WSH - if (scriptlen == 34 && script[0] == 0x00 && script[1] == 0x20) { - raw[0] = 0x0A; - raw[1] = 0x00; - raw[2] = 0x00; - memcpy(raw + 3, script + 2, 32); - return base58_encode_check(raw, 3 + 32, HASHER_SHA2D, addr, addrsize); - } + // P2WSH + if (scriptlen == 34 && script[0] == 0x00 && script[1] == 0x20) { + raw[0] = 0x0A; + raw[1] = 0x00; + raw[2] = 0x00; + memcpy(raw + 3, script + 2, 32); + return base58_encode_check(raw, 3 + 32, HASHER_SHA2D, addr, addrsize); + } - return 0; + return 0; } diff --git a/script.h b/script.h index 9544bf7ca..c9cc003b8 100644 --- a/script.h +++ b/script.h @@ -25,6 +25,7 @@ #include -int script_output_to_address(const uint8_t *script, int scriptlen, char *addr, int addrsize); +int script_output_to_address(const uint8_t *script, int scriptlen, char *addr, + int addrsize); #endif diff --git a/secp256k1.c b/secp256k1.c index f7ec89042..097c7cc17 100644 --- a/secp256k1.c +++ b/secp256k1.c @@ -24,69 +24,70 @@ #include "secp256k1.h" const ecdsa_curve secp256k1 = { - /* .prime */ { - /*.val =*/ {0x3ffffc2f, 0x3ffffffb, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0xffff} - }, + /* .prime */ {/*.val =*/{0x3ffffc2f, 0x3ffffffb, 0x3fffffff, 0x3fffffff, + 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, + 0xffff}}, - /* G */ { - /*.x =*/{/*.val =*/{0x16f81798, 0x27ca056c, 0x1ce28d95, 0x26ff36cb, 0x70b0702, 0x18a573a, 0xbbac55a, 0x199fbe77, 0x79be}}, - /*.y =*/{/*.val =*/{0x3b10d4b8, 0x311f423f, 0x28554199, 0x5ed1229, 0x1108a8fd, 0x13eff038, 0x3c4655da, 0x369dc9a8, 0x483a}} - }, + /* G */ + {/*.x =*/{/*.val =*/{0x16f81798, 0x27ca056c, 0x1ce28d95, 0x26ff36cb, + 0x70b0702, 0x18a573a, 0xbbac55a, 0x199fbe77, 0x79be}}, + /*.y =*/{/*.val =*/{0x3b10d4b8, 0x311f423f, 0x28554199, 0x5ed1229, + 0x1108a8fd, 0x13eff038, 0x3c4655da, 0x369dc9a8, + 0x483a}}}, - /* order */ { - /*.val =*/{0x10364141, 0x3f497a33, 0x348a03bb, 0x2bb739ab, 0x3ffffeba, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0xffff} - }, + /* order */ + {/*.val =*/{0x10364141, 0x3f497a33, 0x348a03bb, 0x2bb739ab, 0x3ffffeba, + 0x3fffffff, 0x3fffffff, 0x3fffffff, 0xffff}}, - /* order_half */ { - /*.val =*/{0x281b20a0, 0x3fa4bd19, 0x3a4501dd, 0x15db9cd5, 0x3fffff5d, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x7fff} - }, + /* order_half */ + {/*.val =*/{0x281b20a0, 0x3fa4bd19, 0x3a4501dd, 0x15db9cd5, 0x3fffff5d, + 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x7fff}}, - /* a */ 0, + /* a */ 0, - /* b */ { - /*.val =*/{7} - } + /* b */ {/*.val =*/{7}} #if USE_PRECOMPUTED_CP - , - /* cp */ { + , + /* cp */ + { #include "secp256k1.table" - } + } #endif }; const curve_info secp256k1_info = { - .bip32_name = "Bitcoin seed", - .params = &secp256k1, - .hasher_base58 = HASHER_SHA2D, - .hasher_sign = HASHER_SHA2D, - .hasher_pubkey = HASHER_SHA2_RIPEMD, - .hasher_script = HASHER_SHA2, + .bip32_name = "Bitcoin seed", + .params = &secp256k1, + .hasher_base58 = HASHER_SHA2D, + .hasher_sign = HASHER_SHA2D, + .hasher_pubkey = HASHER_SHA2_RIPEMD, + .hasher_script = HASHER_SHA2, }; const curve_info secp256k1_decred_info = { - .bip32_name = "Bitcoin seed", - .params = &secp256k1, - .hasher_base58 = HASHER_BLAKED, - .hasher_sign = HASHER_BLAKE, - .hasher_pubkey = HASHER_BLAKE_RIPEMD, - .hasher_script = HASHER_BLAKE, + .bip32_name = "Bitcoin seed", + .params = &secp256k1, + .hasher_base58 = HASHER_BLAKED, + .hasher_sign = HASHER_BLAKE, + .hasher_pubkey = HASHER_BLAKE_RIPEMD, + .hasher_script = HASHER_BLAKE, }; const curve_info secp256k1_groestl_info = { - .bip32_name = "Bitcoin seed", - .params = &secp256k1, - .hasher_base58 = HASHER_GROESTLD_TRUNC, - .hasher_sign = HASHER_SHA2, - .hasher_pubkey = HASHER_SHA2_RIPEMD, - .hasher_script = HASHER_SHA2, + .bip32_name = "Bitcoin seed", + .params = &secp256k1, + .hasher_base58 = HASHER_GROESTLD_TRUNC, + .hasher_sign = HASHER_SHA2, + .hasher_pubkey = HASHER_SHA2_RIPEMD, + .hasher_script = HASHER_SHA2, }; const curve_info secp256k1_smart_info = { - .bip32_name = "Bitcoin seed", - .params = &secp256k1, - .hasher_base58 = HASHER_SHA3K, - .hasher_sign = HASHER_SHA2, - .hasher_pubkey = HASHER_SHA2_RIPEMD, - .hasher_script = HASHER_SHA2, + .bip32_name = "Bitcoin seed", + .params = &secp256k1, + .hasher_base58 = HASHER_SHA3K, + .hasher_sign = HASHER_SHA2, + .hasher_pubkey = HASHER_SHA2_RIPEMD, + .hasher_script = HASHER_SHA2, }; diff --git a/secp256k1.h b/secp256k1.h index 234ca97a9..3b45e48fe 100644 --- a/secp256k1.h +++ b/secp256k1.h @@ -26,8 +26,8 @@ #include -#include "ecdsa.h" #include "bip32.h" +#include "ecdsa.h" extern const ecdsa_curve secp256k1; extern const curve_info secp256k1_info; diff --git a/segwit_addr.h b/segwit_addr.h index dbec91b02..c842fca2a 100644 --- a/segwit_addr.h +++ b/segwit_addr.h @@ -35,13 +35,8 @@ * prog_len: Number of data bytes in prog. * Returns 1 if successful. */ -int segwit_addr_encode( - char *output, - const char *hrp, - int ver, - const uint8_t *prog, - size_t prog_len -); +int segwit_addr_encode(char *output, const char *hrp, int ver, + const uint8_t *prog, size_t prog_len); /** Decode a SegWit address * @@ -49,20 +44,13 @@ int segwit_addr_encode( * program version (between 0 and 16 inclusive). * prog: Pointer to a buffer of size 40 that will be updated to * contain the witness program bytes. - * prog_len: Pointer to a size_t that will be updated to contain the length - * of bytes in prog. - * hrp: Pointer to the null-terminated human readable part that is - * expected (chain/network specific). - * addr: Pointer to the null-terminated address. - * Returns 1 if successful. + * prog_len: Pointer to a size_t that will be updated to contain the + * length of bytes in prog. hrp: Pointer to the null-terminated human + * readable part that is expected (chain/network specific). addr: Pointer to + * the null-terminated address. Returns 1 if successful. */ -int segwit_addr_decode( - int* ver, - uint8_t* prog, - size_t* prog_len, - const char* hrp, - const char* addr -); +int segwit_addr_decode(int *ver, uint8_t *prog, size_t *prog_len, + const char *hrp, const char *addr); /** Encode a Bech32 string * @@ -73,12 +61,8 @@ int segwit_addr_decode( * data_len: Length of the data array. * Returns 1 if successful. */ -int bech32_encode( - char *output, - const char *hrp, - const uint8_t *data, - size_t data_len -); +int bech32_encode(char *output, const char *hrp, const uint8_t *data, + size_t data_len); /** Decode a Bech32 string * @@ -91,11 +75,7 @@ int bech32_encode( * In: input: Pointer to a null-terminated Bech32 string. * Returns 1 if succesful. */ -int bech32_decode( - char *hrp, - uint8_t *data, - size_t *data_len, - const char *input -); +int bech32_decode(char *hrp, uint8_t *data, size_t *data_len, + const char *input); #endif diff --git a/shell.nix b/shell.nix index 0cfc3dd05..d4493bbb5 100644 --- a/shell.nix +++ b/shell.nix @@ -2,5 +2,5 @@ with import {}; stdenv.mkDerivation { name = "trezor-crypto-dev"; - buildInputs = [ gnumake gcc pkgconfig openssl check valgrind ]; + buildInputs = [ gnumake gcc pkgconfig openssl check valgrind clang-tools ]; } diff --git a/tests/test_check.c b/tests/test_check.c index e72c16a2a..5fe219c4e 100644 --- a/tests/test_check.c +++ b/tests/test_check.c @@ -21,9 +21,9 @@ * OTHER DEALINGS IN THE SOFTWARE. */ +#include #include #include -#include #include #include #include @@ -32,40 +32,39 @@ #include "check_mem.h" #if VALGRIND -#include #include +#include #endif #include "options.h" +#include "address.h" #include "aes/aes.h" -#include "bignum.h" #include "base32.h" #include "base58.h" +#include "bignum.h" #include "bip32.h" #include "bip39.h" -#include "ecdsa.h" -#include "pbkdf2.h" -#include "rand.h" -#include "sha2.h" -#include "sha3.h" #include "blake256.h" #include "blake2b.h" #include "blake2s.h" #include "curves.h" -#include "secp256k1.h" -#include "nist256p1.h" -#include "ed25519-donna/ed25519.h" +#include "ecdsa.h" #include "ed25519-donna/ed25519-donna.h" #include "ed25519-donna/ed25519-keccak.h" -#include "script.h" -#include "rfc6979.h" -#include "address.h" -#include "rc4.h" -#include "nem.h" -#include "monero/monero.h" +#include "ed25519-donna/ed25519.h" #include "memzero.h" - +#include "monero/monero.h" +#include "nem.h" +#include "nist256p1.h" +#include "pbkdf2.h" +#include "rand.h" +#include "rc4.h" +#include "rfc6979.h" +#include "script.h" +#include "secp256k1.h" +#include "sha2.h" +#include "sha3.h" #if VALGRIND /* @@ -74,2121 +73,3672 @@ */ /* Call after secret data is written, before first use */ -#define MARK_SECRET_DATA(addr, len) VALGRIND_MAKE_MEM_UNDEFINED(addr, len) -/* Call before secret data is freed or to mark non-secret data (public keys or signatures) */ -#define UNMARK_SECRET_DATA(addr, len) VALGRIND_MAKE_MEM_DEFINED (addr, len) +#define MARK_SECRET_DATA(addr, len) VALGRIND_MAKE_MEM_UNDEFINED(addr, len) +/* Call before secret data is freed or to mark non-secret data (public keys or + * signatures) */ +#define UNMARK_SECRET_DATA(addr, len) VALGRIND_MAKE_MEM_DEFINED(addr, len) #else -#define MARK_SECRET_DATA(addr, len) +#define MARK_SECRET_DATA(addr, len) #define UNMARK_SECRET_DATA(addr, len) #endif #define FROMHEX_MAXLEN 512 -#define VERSION_PUBLIC 0x0488b21e +#define VERSION_PUBLIC 0x0488b21e #define VERSION_PRIVATE 0x0488ade4 -#define DECRED_VERSION_PUBLIC 0x02fda926 +#define DECRED_VERSION_PUBLIC 0x02fda926 #define DECRED_VERSION_PRIVATE 0x02fda4e8 -const uint8_t *fromhex(const char *str) -{ - static uint8_t buf[FROMHEX_MAXLEN]; - size_t len = strlen(str) / 2; - if (len > FROMHEX_MAXLEN) len = FROMHEX_MAXLEN; - for (size_t i = 0; i < len; i++) { - uint8_t c = 0; - if (str[i * 2] >= '0' && str[i*2] <= '9') c += (str[i * 2] - '0') << 4; - if ((str[i * 2] & ~0x20) >= 'A' && (str[i*2] & ~0x20) <= 'F') c += (10 + (str[i * 2] & ~0x20) - 'A') << 4; - if (str[i * 2 + 1] >= '0' && str[i * 2 + 1] <= '9') c += (str[i * 2 + 1] - '0'); - if ((str[i * 2 + 1] & ~0x20) >= 'A' && (str[i * 2 + 1] & ~0x20) <= 'F') c += (10 + (str[i * 2 + 1] & ~0x20) - 'A'); - buf[i] = c; - } - return buf; +const uint8_t *fromhex(const char *str) { + static uint8_t buf[FROMHEX_MAXLEN]; + size_t len = strlen(str) / 2; + if (len > FROMHEX_MAXLEN) len = FROMHEX_MAXLEN; + for (size_t i = 0; i < len; i++) { + uint8_t c = 0; + if (str[i * 2] >= '0' && str[i * 2] <= '9') c += (str[i * 2] - '0') << 4; + if ((str[i * 2] & ~0x20) >= 'A' && (str[i * 2] & ~0x20) <= 'F') + c += (10 + (str[i * 2] & ~0x20) - 'A') << 4; + if (str[i * 2 + 1] >= '0' && str[i * 2 + 1] <= '9') + c += (str[i * 2 + 1] - '0'); + if ((str[i * 2 + 1] & ~0x20) >= 'A' && (str[i * 2 + 1] & ~0x20) <= 'F') + c += (10 + (str[i * 2 + 1] & ~0x20) - 'A'); + buf[i] = c; + } + return buf; } void nem_private_key(const char *reversed_hex, ed25519_secret_key private_key) { - const uint8_t *reversed_key = fromhex(reversed_hex); - for (size_t j = 0; j < sizeof(ed25519_secret_key); j++) { - private_key[j] = reversed_key[sizeof(ed25519_secret_key) - j - 1]; - } + const uint8_t *reversed_key = fromhex(reversed_hex); + for (size_t j = 0; j < sizeof(ed25519_secret_key); j++) { + private_key[j] = reversed_key[sizeof(ed25519_secret_key) - j - 1]; + } } -START_TEST(test_bignum_read_be) -{ - bignum256 a; - uint8_t input[32]; +START_TEST(test_bignum_read_be) { + bignum256 a; + uint8_t input[32]; - memcpy(input, fromhex("c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd5"), 32); + memcpy( + input, + fromhex( + "c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd5"), + 32); - bn_read_be(input, &a); + bn_read_be(input, &a); - bignum256 b = { { 0x286d8bd5, 0x380c7c17, 0x3c6a2ec1, 0x2d787ef5, 0x14437cd3, 0x25a043f8, 0x1dd5263f, 0x33a162c3, 0x0000c55e } }; + bignum256 b = {{0x286d8bd5, 0x380c7c17, 0x3c6a2ec1, 0x2d787ef5, 0x14437cd3, + 0x25a043f8, 0x1dd5263f, 0x33a162c3, 0x0000c55e}}; - for (int i = 0; i < 9; i++) { - ck_assert_int_eq(a.val[i], b.val[i]); - } + for (int i = 0; i < 9; i++) { + ck_assert_int_eq(a.val[i], b.val[i]); + } } END_TEST -START_TEST(test_bignum_write_be) -{ - bignum256 a = { { 0x286d8bd5, 0x380c7c17, 0x3c6a2ec1, 0x2d787ef5, 0x14437cd3, 0x25a043f8, 0x1dd5263f, 0x33a162c3, 0x0000c55e } }; - uint8_t tmp[32]; +START_TEST(test_bignum_write_be) { + bignum256 a = {{0x286d8bd5, 0x380c7c17, 0x3c6a2ec1, 0x2d787ef5, 0x14437cd3, + 0x25a043f8, 0x1dd5263f, 0x33a162c3, 0x0000c55e}}; + uint8_t tmp[32]; - bn_write_be(&a, tmp); + bn_write_be(&a, tmp); - ck_assert_mem_eq(tmp, fromhex("c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd5"), 32); + ck_assert_mem_eq( + tmp, + fromhex( + "c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd5"), + 32); } END_TEST -START_TEST(test_bignum_is_equal) -{ - bignum256 a = { { 0x286d8bd5, 0x380c7c17, 0x3c6a2ec1, 0x2d787ef5, 0x14437cd3, 0x25a043f8, 0x1dd5263f, 0x33a162c3, 0x0000c55e } }; - bignum256 b = { { 0x286d8bd5, 0x380c7c17, 0x3c6a2ec1, 0x2d787ef5, 0x14437cd3, 0x25a043f8, 0x1dd5263f, 0x33a162c3, 0x0000c55e } }; - bignum256 c = { { 0, } }; - - ck_assert_int_eq(bn_is_equal(&a, &b), 1); - ck_assert_int_eq(bn_is_equal(&c, &c), 1); - ck_assert_int_eq(bn_is_equal(&a, &c), 0); +START_TEST(test_bignum_is_equal) { + bignum256 a = {{0x286d8bd5, 0x380c7c17, 0x3c6a2ec1, 0x2d787ef5, 0x14437cd3, + 0x25a043f8, 0x1dd5263f, 0x33a162c3, 0x0000c55e}}; + bignum256 b = {{0x286d8bd5, 0x380c7c17, 0x3c6a2ec1, 0x2d787ef5, 0x14437cd3, + 0x25a043f8, 0x1dd5263f, 0x33a162c3, 0x0000c55e}}; + bignum256 c = {{ + 0, + }}; + + ck_assert_int_eq(bn_is_equal(&a, &b), 1); + ck_assert_int_eq(bn_is_equal(&c, &c), 1); + ck_assert_int_eq(bn_is_equal(&a, &c), 0); } END_TEST -START_TEST(test_bignum_zero) -{ - bignum256 a; - bignum256 b; +START_TEST(test_bignum_zero) { + bignum256 a; + bignum256 b; - bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000000"), &a); - bn_zero(&b); + bn_read_be( + fromhex( + "0000000000000000000000000000000000000000000000000000000000000000"), + &a); + bn_zero(&b); - ck_assert_int_eq(bn_is_equal(&a, &b), 1); + ck_assert_int_eq(bn_is_equal(&a, &b), 1); } END_TEST -START_TEST(test_bignum_is_zero) -{ - bignum256 a; - - bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000000"), &a); - ck_assert_int_eq(bn_is_zero(&a), 1); - - bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000001"), &a); - ck_assert_int_eq(bn_is_zero(&a), 0); - - bn_read_be(fromhex("1000000000000000000000000000000000000000000000000000000000000000"), &a); - ck_assert_int_eq(bn_is_zero(&a), 0); - - bn_read_be(fromhex("f000000000000000000000000000000000000000000000000000000000000000"), &a); - ck_assert_int_eq(bn_is_zero(&a), 0); +START_TEST(test_bignum_is_zero) { + bignum256 a; + + bn_read_be( + fromhex( + "0000000000000000000000000000000000000000000000000000000000000000"), + &a); + ck_assert_int_eq(bn_is_zero(&a), 1); + + bn_read_be( + fromhex( + "0000000000000000000000000000000000000000000000000000000000000001"), + &a); + ck_assert_int_eq(bn_is_zero(&a), 0); + + bn_read_be( + fromhex( + "1000000000000000000000000000000000000000000000000000000000000000"), + &a); + ck_assert_int_eq(bn_is_zero(&a), 0); + + bn_read_be( + fromhex( + "f000000000000000000000000000000000000000000000000000000000000000"), + &a); + ck_assert_int_eq(bn_is_zero(&a), 0); } END_TEST -START_TEST(test_bignum_one) -{ - bignum256 a; - bignum256 b; +START_TEST(test_bignum_one) { + bignum256 a; + bignum256 b; - bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000001"), &a); - bn_one(&b); + bn_read_be( + fromhex( + "0000000000000000000000000000000000000000000000000000000000000001"), + &a); + bn_one(&b); - ck_assert_int_eq(bn_is_equal(&a, &b), 1); + ck_assert_int_eq(bn_is_equal(&a, &b), 1); } END_TEST -START_TEST(test_bignum_read_le) -{ - bignum256 a; - bignum256 b; +START_TEST(test_bignum_read_le) { + bignum256 a; + bignum256 b; - bn_read_be(fromhex("c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd5"), &a); - bn_read_le(fromhex("d58b6de8051f031eeca2c6d7fbe1b5d37c4314fe1068f96352dd0d8b85ce5ec5"), &b); + bn_read_be( + fromhex( + "c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd5"), + &a); + bn_read_le( + fromhex( + "d58b6de8051f031eeca2c6d7fbe1b5d37c4314fe1068f96352dd0d8b85ce5ec5"), + &b); - ck_assert_int_eq(bn_is_equal(&a, &b), 1); + ck_assert_int_eq(bn_is_equal(&a, &b), 1); } END_TEST -START_TEST(test_bignum_write_le) -{ - bignum256 a; - bignum256 b; - uint8_t tmp[32]; - - bn_read_be(fromhex("c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd5"), &a); - bn_write_le(&a, tmp); - - bn_read_le(tmp, &b); - ck_assert_int_eq(bn_is_equal(&a, &b), 1); - - bn_read_be(fromhex("d58b6de8051f031eeca2c6d7fbe1b5d37c4314fe1068f96352dd0d8b85ce5ec5"), &a); - bn_read_be(tmp, &b); - ck_assert_int_eq(bn_is_equal(&a, &b), 1); +START_TEST(test_bignum_write_le) { + bignum256 a; + bignum256 b; + uint8_t tmp[32]; + + bn_read_be( + fromhex( + "c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd5"), + &a); + bn_write_le(&a, tmp); + + bn_read_le(tmp, &b); + ck_assert_int_eq(bn_is_equal(&a, &b), 1); + + bn_read_be( + fromhex( + "d58b6de8051f031eeca2c6d7fbe1b5d37c4314fe1068f96352dd0d8b85ce5ec5"), + &a); + bn_read_be(tmp, &b); + ck_assert_int_eq(bn_is_equal(&a, &b), 1); } END_TEST -START_TEST(test_bignum_read_uint32) -{ - bignum256 a; - bignum256 b; - - // lowest 30 bits set - bn_read_be(fromhex("000000000000000000000000000000000000000000000000000000003fffffff"), &a); - bn_read_uint32(0x3fffffff, &b); - - ck_assert_int_eq(bn_is_equal(&a, &b), 1); - - // bit 31 set - bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000040000000"), &a); - bn_read_uint32(0x40000000, &b); - ck_assert_int_eq(bn_is_equal(&a, &b), 1); +START_TEST(test_bignum_read_uint32) { + bignum256 a; + bignum256 b; + + // lowest 30 bits set + bn_read_be( + fromhex( + "000000000000000000000000000000000000000000000000000000003fffffff"), + &a); + bn_read_uint32(0x3fffffff, &b); + + ck_assert_int_eq(bn_is_equal(&a, &b), 1); + + // bit 31 set + bn_read_be( + fromhex( + "0000000000000000000000000000000000000000000000000000000040000000"), + &a); + bn_read_uint32(0x40000000, &b); + ck_assert_int_eq(bn_is_equal(&a, &b), 1); } END_TEST -START_TEST(test_bignum_read_uint64) -{ - bignum256 a; - bignum256 b; - - // lowest 30 bits set - bn_read_be(fromhex("000000000000000000000000000000000000000000000000000000003fffffff"), &a); - bn_read_uint64(0x3fffffff, &b); - ck_assert_int_eq(bn_is_equal(&a, &b), 1); - - // bit 31 set - bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000040000000"), &a); - bn_read_uint64(0x40000000, &b); - ck_assert_int_eq(bn_is_equal(&a, &b), 1); - - // bit 33 set - bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000100000000"), &a); - bn_read_uint64(0x100000000LL, &b); - ck_assert_int_eq(bn_is_equal(&a, &b), 1); - - // bit 61 set - bn_read_be(fromhex("0000000000000000000000000000000000000000000000002000000000000000"), &a); - bn_read_uint64(0x2000000000000000LL, &b); - ck_assert_int_eq(bn_is_equal(&a, &b), 1); - - // all 64 bits set - bn_read_be(fromhex("000000000000000000000000000000000000000000000000ffffffffffffffff"), &a); - bn_read_uint64(0xffffffffffffffffLL, &b); - ck_assert_int_eq(bn_is_equal(&a, &b), 1); +START_TEST(test_bignum_read_uint64) { + bignum256 a; + bignum256 b; + + // lowest 30 bits set + bn_read_be( + fromhex( + "000000000000000000000000000000000000000000000000000000003fffffff"), + &a); + bn_read_uint64(0x3fffffff, &b); + ck_assert_int_eq(bn_is_equal(&a, &b), 1); + + // bit 31 set + bn_read_be( + fromhex( + "0000000000000000000000000000000000000000000000000000000040000000"), + &a); + bn_read_uint64(0x40000000, &b); + ck_assert_int_eq(bn_is_equal(&a, &b), 1); + + // bit 33 set + bn_read_be( + fromhex( + "0000000000000000000000000000000000000000000000000000000100000000"), + &a); + bn_read_uint64(0x100000000LL, &b); + ck_assert_int_eq(bn_is_equal(&a, &b), 1); + + // bit 61 set + bn_read_be( + fromhex( + "0000000000000000000000000000000000000000000000002000000000000000"), + &a); + bn_read_uint64(0x2000000000000000LL, &b); + ck_assert_int_eq(bn_is_equal(&a, &b), 1); + + // all 64 bits set + bn_read_be( + fromhex( + "000000000000000000000000000000000000000000000000ffffffffffffffff"), + &a); + bn_read_uint64(0xffffffffffffffffLL, &b); + ck_assert_int_eq(bn_is_equal(&a, &b), 1); } END_TEST -START_TEST(test_bignum_write_uint32) -{ - bignum256 a; - - // lowest 30 bits set - bn_read_be(fromhex("000000000000000000000000000000000000000000000000000000003fffffff"), &a); - ck_assert_int_eq(bn_write_uint32(&a), 0x3fffffff); - - // bit 31 set - bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000040000000"), &a); - ck_assert_int_eq(bn_write_uint32(&a), 0x40000000); +START_TEST(test_bignum_write_uint32) { + bignum256 a; + + // lowest 30 bits set + bn_read_be( + fromhex( + "000000000000000000000000000000000000000000000000000000003fffffff"), + &a); + ck_assert_int_eq(bn_write_uint32(&a), 0x3fffffff); + + // bit 31 set + bn_read_be( + fromhex( + "0000000000000000000000000000000000000000000000000000000040000000"), + &a); + ck_assert_int_eq(bn_write_uint32(&a), 0x40000000); } END_TEST -START_TEST(test_bignum_write_uint64) -{ - bignum256 a; - - // lowest 30 bits set - bn_read_be(fromhex("000000000000000000000000000000000000000000000000000000003fffffff"), &a); - ck_assert_int_eq(bn_write_uint64(&a), 0x3fffffff); - - // bit 31 set - bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000040000000"), &a); - ck_assert_int_eq(bn_write_uint64(&a), 0x40000000); - - // bit 33 set - bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000100000000"), &a); - ck_assert_int_eq(bn_write_uint64(&a), 0x100000000LL); - - // bit 61 set - bn_read_be(fromhex("0000000000000000000000000000000000000000000000002000000000000000"), &a); - ck_assert_int_eq(bn_write_uint64(&a), 0x2000000000000000LL); - - // all 64 bits set - bn_read_be(fromhex("000000000000000000000000000000000000000000000000ffffffffffffffff"), &a); - ck_assert_int_eq(bn_write_uint64(&a), 0xffffffffffffffffLL); +START_TEST(test_bignum_write_uint64) { + bignum256 a; + + // lowest 30 bits set + bn_read_be( + fromhex( + "000000000000000000000000000000000000000000000000000000003fffffff"), + &a); + ck_assert_int_eq(bn_write_uint64(&a), 0x3fffffff); + + // bit 31 set + bn_read_be( + fromhex( + "0000000000000000000000000000000000000000000000000000000040000000"), + &a); + ck_assert_int_eq(bn_write_uint64(&a), 0x40000000); + + // bit 33 set + bn_read_be( + fromhex( + "0000000000000000000000000000000000000000000000000000000100000000"), + &a); + ck_assert_int_eq(bn_write_uint64(&a), 0x100000000LL); + + // bit 61 set + bn_read_be( + fromhex( + "0000000000000000000000000000000000000000000000002000000000000000"), + &a); + ck_assert_int_eq(bn_write_uint64(&a), 0x2000000000000000LL); + + // all 64 bits set + bn_read_be( + fromhex( + "000000000000000000000000000000000000000000000000ffffffffffffffff"), + &a); + ck_assert_int_eq(bn_write_uint64(&a), 0xffffffffffffffffLL); } END_TEST -START_TEST(test_bignum_copy) -{ - bignum256 a; - bignum256 b; +START_TEST(test_bignum_copy) { + bignum256 a; + bignum256 b; - bn_read_be(fromhex("c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd5"), &a); - bn_copy(&a, &b); + bn_read_be( + fromhex( + "c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd5"), + &a); + bn_copy(&a, &b); - ck_assert_int_eq(bn_is_equal(&a, &b), 1); + ck_assert_int_eq(bn_is_equal(&a, &b), 1); } END_TEST -START_TEST(test_bignum_is_even) -{ - bignum256 a; - - bn_read_be(fromhex("c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd5"), &a); - ck_assert_int_eq(bn_is_even(&a), 0); - - bn_read_be(fromhex("c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd2"), &a); - ck_assert_int_eq(bn_is_even(&a), 1); - - bn_read_be(fromhex("c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd0"), &a); - ck_assert_int_eq(bn_is_even(&a), 1); +START_TEST(test_bignum_is_even) { + bignum256 a; + + bn_read_be( + fromhex( + "c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd5"), + &a); + ck_assert_int_eq(bn_is_even(&a), 0); + + bn_read_be( + fromhex( + "c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd2"), + &a); + ck_assert_int_eq(bn_is_even(&a), 1); + + bn_read_be( + fromhex( + "c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd0"), + &a); + ck_assert_int_eq(bn_is_even(&a), 1); } END_TEST -START_TEST(test_bignum_is_odd) -{ - bignum256 a; - - bn_read_be(fromhex("c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd5"), &a); - ck_assert_int_eq(bn_is_odd(&a), 1); - - bn_read_be(fromhex("c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd2"), &a); - ck_assert_int_eq(bn_is_odd(&a), 0); - - bn_read_be(fromhex("c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd0"), &a); - ck_assert_int_eq(bn_is_odd(&a), 0); +START_TEST(test_bignum_is_odd) { + bignum256 a; + + bn_read_be( + fromhex( + "c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd5"), + &a); + ck_assert_int_eq(bn_is_odd(&a), 1); + + bn_read_be( + fromhex( + "c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd2"), + &a); + ck_assert_int_eq(bn_is_odd(&a), 0); + + bn_read_be( + fromhex( + "c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd0"), + &a); + ck_assert_int_eq(bn_is_odd(&a), 0); } END_TEST -START_TEST(test_bignum_is_less) -{ - bignum256 a; - bignum256 b; +START_TEST(test_bignum_is_less) { + bignum256 a; + bignum256 b; - bn_read_uint32(0x1234, &a); - bn_read_uint32(0x8765, &b); + bn_read_uint32(0x1234, &a); + bn_read_uint32(0x8765, &b); - ck_assert_int_eq(bn_is_less(&a, &b), 1); - ck_assert_int_eq(bn_is_less(&b, &a), 0); + ck_assert_int_eq(bn_is_less(&a, &b), 1); + ck_assert_int_eq(bn_is_less(&b, &a), 0); - bn_zero(&a); - bn_read_be(fromhex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), &b); + bn_zero(&a); + bn_read_be( + fromhex( + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), + &b); - ck_assert_int_eq(bn_is_less(&a, &b), 1); - ck_assert_int_eq(bn_is_less(&b, &a), 0); + ck_assert_int_eq(bn_is_less(&a, &b), 1); + ck_assert_int_eq(bn_is_less(&b, &a), 0); } END_TEST -START_TEST(test_bignum_bitcount) -{ - bignum256 a, b; - - bn_zero(&a); - ck_assert_int_eq(bn_bitcount(&a), 0); - - bn_one(&a); - ck_assert_int_eq(bn_bitcount(&a), 1); - - // test for 10000 and 11111 when i=5 - for (int i = 2; i <= 256; i++) { - bn_one(&a); - bn_one(&b); - for (int j = 2; j <= i; j++) { - bn_lshift(&a); - bn_lshift(&b); - bn_addi(&b, 1); - } - ck_assert_int_eq(bn_bitcount(&a), i); - ck_assert_int_eq(bn_bitcount(&b), i); - } - - bn_read_uint32(0x3fffffff, &a); - ck_assert_int_eq(bn_bitcount(&a), 30); - - bn_read_uint32(0xffffffff, &a); - ck_assert_int_eq(bn_bitcount(&a), 32); - - bn_read_be(fromhex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), &a); - ck_assert_int_eq(bn_bitcount(&a), 256); +START_TEST(test_bignum_bitcount) { + bignum256 a, b; + + bn_zero(&a); + ck_assert_int_eq(bn_bitcount(&a), 0); + + bn_one(&a); + ck_assert_int_eq(bn_bitcount(&a), 1); + + // test for 10000 and 11111 when i=5 + for (int i = 2; i <= 256; i++) { + bn_one(&a); + bn_one(&b); + for (int j = 2; j <= i; j++) { + bn_lshift(&a); + bn_lshift(&b); + bn_addi(&b, 1); + } + ck_assert_int_eq(bn_bitcount(&a), i); + ck_assert_int_eq(bn_bitcount(&b), i); + } + + bn_read_uint32(0x3fffffff, &a); + ck_assert_int_eq(bn_bitcount(&a), 30); + + bn_read_uint32(0xffffffff, &a); + ck_assert_int_eq(bn_bitcount(&a), 32); + + bn_read_be( + fromhex( + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), + &a); + ck_assert_int_eq(bn_bitcount(&a), 256); } END_TEST -START_TEST(test_bignum_digitcount) -{ - bignum256 a; +START_TEST(test_bignum_digitcount) { + bignum256 a; - bn_zero(&a); - ck_assert_int_eq(bn_digitcount(&a), 1); + bn_zero(&a); + ck_assert_int_eq(bn_digitcount(&a), 1); - // test for (10^i) and (10^i) - 1 - uint64_t m = 1; - for (int i = 0; i <= 19; i++, m *= 10) { - bn_read_uint64(m, &a); - ck_assert_int_eq(bn_digitcount(&a), i + 1); + // test for (10^i) and (10^i) - 1 + uint64_t m = 1; + for (int i = 0; i <= 19; i++, m *= 10) { + bn_read_uint64(m, &a); + ck_assert_int_eq(bn_digitcount(&a), i + 1); - uint64_t n = m - 1; - bn_read_uint64(n, &a); - ck_assert_int_eq(bn_digitcount(&a), n == 0 ? 1 : i); - } + uint64_t n = m - 1; + bn_read_uint64(n, &a); + ck_assert_int_eq(bn_digitcount(&a), n == 0 ? 1 : i); + } - bn_read_uint32(0x3fffffff, &a); - ck_assert_int_eq(bn_digitcount(&a), 10); + bn_read_uint32(0x3fffffff, &a); + ck_assert_int_eq(bn_digitcount(&a), 10); - bn_read_uint32(0xffffffff, &a); - ck_assert_int_eq(bn_digitcount(&a), 10); + bn_read_uint32(0xffffffff, &a); + ck_assert_int_eq(bn_digitcount(&a), 10); - bn_read_be(fromhex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), &a); - ck_assert_int_eq(bn_digitcount(&a), 78); + bn_read_be( + fromhex( + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), + &a); + ck_assert_int_eq(bn_digitcount(&a), 78); } END_TEST START_TEST(test_bignum_format_uint64) { - char buf[128], str[128]; - int r; - // test for (10^i) and (10^i) - 1 - uint64_t m = 1; - for (int i = 0; i <= 19; i++, m *= 10) { - sprintf(str, "%" PRIu64, m); - r = bn_format_uint64(m, NULL, NULL, 0, 0, false, buf, sizeof(buf)); - ck_assert_int_eq(r, strlen(str)); - ck_assert_str_eq(buf, str); - - uint64_t n = m - 1; - sprintf(str, "%" PRIu64, n); - r = bn_format_uint64(n, NULL, NULL, 0, 0, false, buf, sizeof(buf)); - ck_assert_int_eq(r, strlen(str)); - ck_assert_str_eq(buf, str); - } + char buf[128], str[128]; + int r; + // test for (10^i) and (10^i) - 1 + uint64_t m = 1; + for (int i = 0; i <= 19; i++, m *= 10) { + sprintf(str, "%" PRIu64, m); + r = bn_format_uint64(m, NULL, NULL, 0, 0, false, buf, sizeof(buf)); + ck_assert_int_eq(r, strlen(str)); + ck_assert_str_eq(buf, str); + + uint64_t n = m - 1; + sprintf(str, "%" PRIu64, n); + r = bn_format_uint64(n, NULL, NULL, 0, 0, false, buf, sizeof(buf)); + ck_assert_int_eq(r, strlen(str)); + ck_assert_str_eq(buf, str); + } } END_TEST START_TEST(test_bignum_format) { - bignum256 a; - char buf[128]; - int r; - - bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000000"), &a); - r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); - ck_assert_int_eq(r, 1); - ck_assert_str_eq(buf, "0"); - - bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000000"), &a); - r = bn_format(&a, NULL, NULL, 20, 0, true, buf, sizeof(buf)); - ck_assert_int_eq(r, 22); - ck_assert_str_eq(buf, "0.00000000000000000000"); - - bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000000"), &a); - r = bn_format(&a, NULL, NULL, 0, 5, false, buf, sizeof(buf)); - ck_assert_int_eq(r, 1); - ck_assert_str_eq(buf, "0"); - - bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000000"), &a); - r = bn_format(&a, NULL, NULL, 0, -5, false, buf, sizeof(buf)); - ck_assert_int_eq(r, 1); - ck_assert_str_eq(buf, "0"); - - bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000000"), &a); - r = bn_format(&a, "", "", 0, 0, false, buf, sizeof(buf)); - ck_assert_int_eq(r, 1); - ck_assert_str_eq(buf, "0"); - - bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000000"), &a); - r = bn_format(&a, NULL, "SFFX", 0, 0, false, buf, sizeof(buf)); - ck_assert_int_eq(r, 1 + 4); - ck_assert_str_eq(buf, "0SFFX"); - - bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000000"), &a); - r = bn_format(&a, "PRFX", NULL, 0, 0, false, buf, sizeof(buf)); - ck_assert_int_eq(r, 4 + 1); - ck_assert_str_eq(buf, "PRFX0"); - - bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000000"), &a); - r = bn_format(&a, "PRFX", "SFFX", 0, 0, false, buf, sizeof(buf)); - ck_assert_int_eq(r, 4 + 1 + 4); - ck_assert_str_eq(buf, "PRFX0SFFX"); - - bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000000"), &a); - r = bn_format(&a, NULL, NULL, 18, 0, false, buf, sizeof(buf)); - ck_assert_int_eq(r, 3); - ck_assert_str_eq(buf, "0.0"); - - bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000001"), &a); - r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); - ck_assert_int_eq(r, 1); - ck_assert_str_eq(buf, "1"); - - bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000001"), &a); - r = bn_format(&a, NULL, NULL, 6, 6, true, buf, sizeof(buf)); - ck_assert_int_eq(r, 8); - ck_assert_str_eq(buf, "1.000000"); - - bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000002"), &a); - r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); - ck_assert_int_eq(r, 1); - ck_assert_str_eq(buf, "2"); - - bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000005"), &a); - r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); - ck_assert_int_eq(r, 1); - ck_assert_str_eq(buf, "5"); - - bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000009"), &a); - r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); - ck_assert_int_eq(r, 1); - ck_assert_str_eq(buf, "9"); - - bn_read_be(fromhex("000000000000000000000000000000000000000000000000000000000000000a"), &a); - r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); - ck_assert_int_eq(r, 2); - ck_assert_str_eq(buf, "10"); - - bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000014"), &a); - r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); - ck_assert_int_eq(r, 2); - ck_assert_str_eq(buf, "20"); - - bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000032"), &a); - r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); - ck_assert_int_eq(r, 2); - ck_assert_str_eq(buf, "50"); - - bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000063"), &a); - r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); - ck_assert_int_eq(r, 2); - ck_assert_str_eq(buf, "99"); - - bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000064"), &a); - r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); - ck_assert_int_eq(r, 3); - ck_assert_str_eq(buf, "100"); - - bn_read_be(fromhex("00000000000000000000000000000000000000000000000000000000000000c8"), &a); - r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); - ck_assert_int_eq(r, 3); - ck_assert_str_eq(buf, "200"); - - bn_read_be(fromhex("00000000000000000000000000000000000000000000000000000000000001f4"), &a); - r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); - ck_assert_int_eq(r, 3); - ck_assert_str_eq(buf, "500"); - - bn_read_be(fromhex("00000000000000000000000000000000000000000000000000000000000003e7"), &a); - r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); - ck_assert_int_eq(r, 3); - ck_assert_str_eq(buf, "999"); - - bn_read_be(fromhex("00000000000000000000000000000000000000000000000000000000000003e8"), &a); - r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); - ck_assert_int_eq(r, 4); - ck_assert_str_eq(buf, "1000"); - - bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000989680"), &a); - r = bn_format(&a, NULL, NULL, 7, 0, false, buf, sizeof(buf)); - ck_assert_int_eq(r, 3); - ck_assert_str_eq(buf, "1.0"); - - bn_read_be(fromhex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), &a); - r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); - ck_assert_int_eq(r, 78); - ck_assert_str_eq(buf, "115792089237316195423570985008687907853269984665640564039457584007913129639935"); - - bn_read_be(fromhex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), &a); - r = bn_format(&a, NULL, NULL, 1, 0, false, buf, sizeof(buf)); - ck_assert_int_eq(r, 79); - ck_assert_str_eq(buf, "11579208923731619542357098500868790785326998466564056403945758400791312963993.5"); - - bn_read_be(fromhex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), &a); - r = bn_format(&a, NULL, NULL, 2, 0, false, buf, sizeof(buf)); - ck_assert_int_eq(r, 79); - ck_assert_str_eq(buf, "1157920892373161954235709850086879078532699846656405640394575840079131296399.35"); - - bn_read_be(fromhex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), &a); - r = bn_format(&a, NULL, NULL, 8, 0, false, buf, sizeof(buf)); - ck_assert_int_eq(r, 79); - ck_assert_str_eq(buf, "1157920892373161954235709850086879078532699846656405640394575840079131.29639935"); - - bn_read_be(fromhex("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffe3bbb00"), &a); - r = bn_format(&a, NULL, NULL, 8, 0, false, buf, sizeof(buf)); - ck_assert_int_eq(r, 72); - ck_assert_str_eq(buf, "1157920892373161954235709850086879078532699846656405640394575840079131.0"); - - bn_read_be(fromhex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), &a); - r = bn_format(&a, NULL, NULL, 18, 0, false, buf, sizeof(buf)); - ck_assert_int_eq(r, 79); - ck_assert_str_eq(buf, "115792089237316195423570985008687907853269984665640564039457.584007913129639935"); - - bn_read_be(fromhex("fffffffffffffffffffffffffffffffffffffffffffffffff7e52fe5afe40000"), &a); - r = bn_format(&a, NULL, NULL, 18, 0, false, buf, sizeof(buf)); - ck_assert_int_eq(r, 62); - ck_assert_str_eq(buf, "115792089237316195423570985008687907853269984665640564039457.0"); - - bn_read_be(fromhex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), &a); - r = bn_format(&a, NULL, NULL, 78, 0, false, buf, sizeof(buf)); - ck_assert_int_eq(r, 80); - ck_assert_str_eq(buf, "0.115792089237316195423570985008687907853269984665640564039457584007913129639935"); - - bn_read_be(fromhex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), &a); - r = bn_format(&a, NULL, NULL, 0, 10, false, buf, sizeof(buf)); - ck_assert_int_eq(r, 88); - ck_assert_str_eq(buf, "1157920892373161954235709850086879078532699846656405640394575840079131296399350000000000"); - - bn_read_be(fromhex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), &a); - r = bn_format(&a, "quite a long prefix", "even longer suffix", 60, 0, false, buf, sizeof(buf)); - ck_assert_int_eq(r, 116); - ck_assert_str_eq(buf, "quite a long prefix115792089237316195.423570985008687907853269984665640564039457584007913129639935even longer suffix"); - - bn_read_be(fromhex("0000000000000000000000000000000000000000000000000123456789abcdef"), &a); - memset(buf, 'a', sizeof(buf)); - r = bn_format(&a, "prefix", "suffix", 10, 0, false, buf, 31); - ck_assert_str_eq(buf, "prefix8198552.9216486895suffix"); - ck_assert_int_eq(r, 30); - - memset(buf, 'a', sizeof(buf)); - r = bn_format(&a, "prefix", "suffix", 10, 0, false, buf, 30); - ck_assert_int_eq(r, 0); - ck_assert_str_eq(buf, "prefix198552.9216486895suffix"); + bignum256 a; + char buf[128]; + int r; + + bn_read_be( + fromhex( + "0000000000000000000000000000000000000000000000000000000000000000"), + &a); + r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); + ck_assert_int_eq(r, 1); + ck_assert_str_eq(buf, "0"); + + bn_read_be( + fromhex( + "0000000000000000000000000000000000000000000000000000000000000000"), + &a); + r = bn_format(&a, NULL, NULL, 20, 0, true, buf, sizeof(buf)); + ck_assert_int_eq(r, 22); + ck_assert_str_eq(buf, "0.00000000000000000000"); + + bn_read_be( + fromhex( + "0000000000000000000000000000000000000000000000000000000000000000"), + &a); + r = bn_format(&a, NULL, NULL, 0, 5, false, buf, sizeof(buf)); + ck_assert_int_eq(r, 1); + ck_assert_str_eq(buf, "0"); + + bn_read_be( + fromhex( + "0000000000000000000000000000000000000000000000000000000000000000"), + &a); + r = bn_format(&a, NULL, NULL, 0, -5, false, buf, sizeof(buf)); + ck_assert_int_eq(r, 1); + ck_assert_str_eq(buf, "0"); + + bn_read_be( + fromhex( + "0000000000000000000000000000000000000000000000000000000000000000"), + &a); + r = bn_format(&a, "", "", 0, 0, false, buf, sizeof(buf)); + ck_assert_int_eq(r, 1); + ck_assert_str_eq(buf, "0"); + + bn_read_be( + fromhex( + "0000000000000000000000000000000000000000000000000000000000000000"), + &a); + r = bn_format(&a, NULL, "SFFX", 0, 0, false, buf, sizeof(buf)); + ck_assert_int_eq(r, 1 + 4); + ck_assert_str_eq(buf, "0SFFX"); + + bn_read_be( + fromhex( + "0000000000000000000000000000000000000000000000000000000000000000"), + &a); + r = bn_format(&a, "PRFX", NULL, 0, 0, false, buf, sizeof(buf)); + ck_assert_int_eq(r, 4 + 1); + ck_assert_str_eq(buf, "PRFX0"); + + bn_read_be( + fromhex( + "0000000000000000000000000000000000000000000000000000000000000000"), + &a); + r = bn_format(&a, "PRFX", "SFFX", 0, 0, false, buf, sizeof(buf)); + ck_assert_int_eq(r, 4 + 1 + 4); + ck_assert_str_eq(buf, "PRFX0SFFX"); + + bn_read_be( + fromhex( + "0000000000000000000000000000000000000000000000000000000000000000"), + &a); + r = bn_format(&a, NULL, NULL, 18, 0, false, buf, sizeof(buf)); + ck_assert_int_eq(r, 3); + ck_assert_str_eq(buf, "0.0"); + + bn_read_be( + fromhex( + "0000000000000000000000000000000000000000000000000000000000000001"), + &a); + r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); + ck_assert_int_eq(r, 1); + ck_assert_str_eq(buf, "1"); + + bn_read_be( + fromhex( + "0000000000000000000000000000000000000000000000000000000000000001"), + &a); + r = bn_format(&a, NULL, NULL, 6, 6, true, buf, sizeof(buf)); + ck_assert_int_eq(r, 8); + ck_assert_str_eq(buf, "1.000000"); + + bn_read_be( + fromhex( + "0000000000000000000000000000000000000000000000000000000000000002"), + &a); + r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); + ck_assert_int_eq(r, 1); + ck_assert_str_eq(buf, "2"); + + bn_read_be( + fromhex( + "0000000000000000000000000000000000000000000000000000000000000005"), + &a); + r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); + ck_assert_int_eq(r, 1); + ck_assert_str_eq(buf, "5"); + + bn_read_be( + fromhex( + "0000000000000000000000000000000000000000000000000000000000000009"), + &a); + r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); + ck_assert_int_eq(r, 1); + ck_assert_str_eq(buf, "9"); + + bn_read_be( + fromhex( + "000000000000000000000000000000000000000000000000000000000000000a"), + &a); + r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); + ck_assert_int_eq(r, 2); + ck_assert_str_eq(buf, "10"); + + bn_read_be( + fromhex( + "0000000000000000000000000000000000000000000000000000000000000014"), + &a); + r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); + ck_assert_int_eq(r, 2); + ck_assert_str_eq(buf, "20"); + + bn_read_be( + fromhex( + "0000000000000000000000000000000000000000000000000000000000000032"), + &a); + r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); + ck_assert_int_eq(r, 2); + ck_assert_str_eq(buf, "50"); + + bn_read_be( + fromhex( + "0000000000000000000000000000000000000000000000000000000000000063"), + &a); + r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); + ck_assert_int_eq(r, 2); + ck_assert_str_eq(buf, "99"); + + bn_read_be( + fromhex( + "0000000000000000000000000000000000000000000000000000000000000064"), + &a); + r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); + ck_assert_int_eq(r, 3); + ck_assert_str_eq(buf, "100"); + + bn_read_be( + fromhex( + "00000000000000000000000000000000000000000000000000000000000000c8"), + &a); + r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); + ck_assert_int_eq(r, 3); + ck_assert_str_eq(buf, "200"); + + bn_read_be( + fromhex( + "00000000000000000000000000000000000000000000000000000000000001f4"), + &a); + r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); + ck_assert_int_eq(r, 3); + ck_assert_str_eq(buf, "500"); + + bn_read_be( + fromhex( + "00000000000000000000000000000000000000000000000000000000000003e7"), + &a); + r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); + ck_assert_int_eq(r, 3); + ck_assert_str_eq(buf, "999"); + + bn_read_be( + fromhex( + "00000000000000000000000000000000000000000000000000000000000003e8"), + &a); + r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); + ck_assert_int_eq(r, 4); + ck_assert_str_eq(buf, "1000"); + + bn_read_be( + fromhex( + "0000000000000000000000000000000000000000000000000000000000989680"), + &a); + r = bn_format(&a, NULL, NULL, 7, 0, false, buf, sizeof(buf)); + ck_assert_int_eq(r, 3); + ck_assert_str_eq(buf, "1.0"); + + bn_read_be( + fromhex( + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), + &a); + r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); + ck_assert_int_eq(r, 78); + ck_assert_str_eq(buf, + "11579208923731619542357098500868790785326998466564056403945" + "7584007913129639935"); + + bn_read_be( + fromhex( + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), + &a); + r = bn_format(&a, NULL, NULL, 1, 0, false, buf, sizeof(buf)); + ck_assert_int_eq(r, 79); + ck_assert_str_eq(buf, + "11579208923731619542357098500868790785326998466564056403945" + "758400791312963993.5"); + + bn_read_be( + fromhex( + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), + &a); + r = bn_format(&a, NULL, NULL, 2, 0, false, buf, sizeof(buf)); + ck_assert_int_eq(r, 79); + ck_assert_str_eq(buf, + "11579208923731619542357098500868790785326998466564056403945" + "75840079131296399.35"); + + bn_read_be( + fromhex( + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), + &a); + r = bn_format(&a, NULL, NULL, 8, 0, false, buf, sizeof(buf)); + ck_assert_int_eq(r, 79); + ck_assert_str_eq(buf, + "11579208923731619542357098500868790785326998466564056403945" + "75840079131.29639935"); + + bn_read_be( + fromhex( + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffe3bbb00"), + &a); + r = bn_format(&a, NULL, NULL, 8, 0, false, buf, sizeof(buf)); + ck_assert_int_eq(r, 72); + ck_assert_str_eq(buf, + "11579208923731619542357098500868790785326998466564056403945" + "75840079131.0"); + + bn_read_be( + fromhex( + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), + &a); + r = bn_format(&a, NULL, NULL, 18, 0, false, buf, sizeof(buf)); + ck_assert_int_eq(r, 79); + ck_assert_str_eq(buf, + "11579208923731619542357098500868790785326998466564056403945" + "7.584007913129639935"); + + bn_read_be( + fromhex( + "fffffffffffffffffffffffffffffffffffffffffffffffff7e52fe5afe40000"), + &a); + r = bn_format(&a, NULL, NULL, 18, 0, false, buf, sizeof(buf)); + ck_assert_int_eq(r, 62); + ck_assert_str_eq( + buf, "115792089237316195423570985008687907853269984665640564039457.0"); + + bn_read_be( + fromhex( + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), + &a); + r = bn_format(&a, NULL, NULL, 78, 0, false, buf, sizeof(buf)); + ck_assert_int_eq(r, 80); + ck_assert_str_eq(buf, + "0." + "11579208923731619542357098500868790785326998466564056403945" + "7584007913129639935"); + + bn_read_be( + fromhex( + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), + &a); + r = bn_format(&a, NULL, NULL, 0, 10, false, buf, sizeof(buf)); + ck_assert_int_eq(r, 88); + ck_assert_str_eq(buf, + "11579208923731619542357098500868790785326998466564056403945" + "75840079131296399350000000000"); + + bn_read_be( + fromhex( + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), + &a); + r = bn_format(&a, "quite a long prefix", "even longer suffix", 60, 0, false, + buf, sizeof(buf)); + ck_assert_int_eq(r, 116); + ck_assert_str_eq(buf, + "quite a long " + "prefix115792089237316195." + "42357098500868790785326998466564056403945758400791312963993" + "5even longer suffix"); + + bn_read_be( + fromhex( + "0000000000000000000000000000000000000000000000000123456789abcdef"), + &a); + memset(buf, 'a', sizeof(buf)); + r = bn_format(&a, "prefix", "suffix", 10, 0, false, buf, 31); + ck_assert_str_eq(buf, "prefix8198552.9216486895suffix"); + ck_assert_int_eq(r, 30); + + memset(buf, 'a', sizeof(buf)); + r = bn_format(&a, "prefix", "suffix", 10, 0, false, buf, 30); + ck_assert_int_eq(r, 0); + ck_assert_str_eq(buf, "prefix198552.9216486895suffix"); } END_TEST // https://tools.ietf.org/html/rfc4648#section-10 -START_TEST(test_base32_rfc4648) -{ - static const struct { - const char *decoded; - const char *encoded; - const char *encoded_lowercase; - } tests[] = { - { "", "", ""}, - { "f", "MY", "my" }, - { "fo", "MZXQ", "mzxq" }, - { "foo", "MZXW6", "mzxw6" }, - { "foob", "MZXW6YQ", "mzxw6yq" }, - { "fooba", "MZXW6YTB", "mzxw6ytb" }, - { "foobar", "MZXW6YTBOI", "mzxw6ytboi" }, - }; - - char buffer[64]; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - const char *in = tests[i].decoded; - const char *out = tests[i].encoded; - const char *out_lowercase = tests[i].encoded_lowercase; - - size_t inlen = strlen(in); - size_t outlen = strlen(out); - - ck_assert_int_eq(outlen, base32_encoded_length(inlen)); - ck_assert_int_eq(inlen, base32_decoded_length(outlen)); - - ck_assert(base32_encode((uint8_t *) in, inlen, buffer, sizeof(buffer), BASE32_ALPHABET_RFC4648) != NULL); - ck_assert_str_eq(buffer, out); - - char *ret = (char *) base32_decode(out, outlen, (uint8_t *) buffer, sizeof(buffer), BASE32_ALPHABET_RFC4648); - ck_assert(ret != NULL); - *ret = '\0'; - ck_assert_str_eq(buffer, in); - - ret = (char *) base32_decode(out_lowercase, outlen, (uint8_t *) buffer, sizeof(buffer), BASE32_ALPHABET_RFC4648); - ck_assert(ret != NULL); - *ret = '\0'; - ck_assert_str_eq(buffer, in); - } +START_TEST(test_base32_rfc4648) { + static const struct { + const char *decoded; + const char *encoded; + const char *encoded_lowercase; + } tests[] = { + {"", "", ""}, + {"f", "MY", "my"}, + {"fo", "MZXQ", "mzxq"}, + {"foo", "MZXW6", "mzxw6"}, + {"foob", "MZXW6YQ", "mzxw6yq"}, + {"fooba", "MZXW6YTB", "mzxw6ytb"}, + {"foobar", "MZXW6YTBOI", "mzxw6ytboi"}, + }; + + char buffer[64]; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + const char *in = tests[i].decoded; + const char *out = tests[i].encoded; + const char *out_lowercase = tests[i].encoded_lowercase; + + size_t inlen = strlen(in); + size_t outlen = strlen(out); + + ck_assert_int_eq(outlen, base32_encoded_length(inlen)); + ck_assert_int_eq(inlen, base32_decoded_length(outlen)); + + ck_assert(base32_encode((uint8_t *)in, inlen, buffer, sizeof(buffer), + BASE32_ALPHABET_RFC4648) != NULL); + ck_assert_str_eq(buffer, out); + + char *ret = (char *)base32_decode(out, outlen, (uint8_t *)buffer, + sizeof(buffer), BASE32_ALPHABET_RFC4648); + ck_assert(ret != NULL); + *ret = '\0'; + ck_assert_str_eq(buffer, in); + + ret = (char *)base32_decode(out_lowercase, outlen, (uint8_t *)buffer, + sizeof(buffer), BASE32_ALPHABET_RFC4648); + ck_assert(ret != NULL); + *ret = '\0'; + ck_assert_str_eq(buffer, in); + } } END_TEST -// from https://github.com/bitcoin/bitcoin/blob/master/src/test/data/base58_keys_valid.json -START_TEST(test_base58) -{ - static const char *base58_vector[] = { - "0065a16059864a2fdbc7c99a4723a8395bc6f188eb", "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i", - "0574f209f6ea907e2ea48f74fae05782ae8a665257", "3CMNFxN1oHBc4R1EpboAL5yzHGgE611Xou", - "6f53c0307d6851aa0ce7825ba883c6bd9ad242b486", "mo9ncXisMeAoXwqcV5EWuyncbmCcQN4rVs", - "c46349a418fc4578d10a372b54b45c280cc8c4382f", "2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br", - "80eddbdc1168f1daeadbd3e44c1e3f8f5a284c2029f78ad26af98583a499de5b19", "5Kd3NBUAdUnhyzenEwVLy9pBKxSwXvE9FMPyR4UKZvpe6E3AgLr", - "8055c9bccb9ed68446d1b75273bbce89d7fe013a8acd1625514420fb2aca1a21c401", "Kz6UJmQACJmLtaQj5A3JAge4kVTNQ8gbvXuwbmCj7bsaabudb3RD", - "ef36cb93b9ab1bdabf7fb9f2c04f1b9cc879933530ae7842398eef5a63a56800c2", "9213qJab2HNEpMpYNBa7wHGFKKbkDn24jpANDs2huN3yi4J11ko", - "efb9f4892c9e8282028fea1d2667c4dc5213564d41fc5783896a0d843fc15089f301", "cTpB4YiyKiBcPxnefsDpbnDxFDffjqJob8wGCEDXxgQ7zQoMXJdH", - "006d23156cbbdcc82a5a47eee4c2c7c583c18b6bf4", "1Ax4gZtb7gAit2TivwejZHYtNNLT18PUXJ", - "05fcc5460dd6e2487c7d75b1963625da0e8f4c5975", "3QjYXhTkvuj8qPaXHTTWb5wjXhdsLAAWVy", - "6ff1d470f9b02370fdec2e6b708b08ac431bf7a5f7", "n3ZddxzLvAY9o7184TB4c6FJasAybsw4HZ", - "c4c579342c2c4c9220205e2cdc285617040c924a0a", "2NBFNJTktNa7GZusGbDbGKRZTxdK9VVez3n", - "80a326b95ebae30164217d7a7f57d72ab2b54e3be64928a19da0210b9568d4015e", "5K494XZwps2bGyeL71pWid4noiSNA2cfCibrvRWqcHSptoFn7rc", - "807d998b45c219a1e38e99e7cbd312ef67f77a455a9b50c730c27f02c6f730dfb401", "L1RrrnXkcKut5DEMwtDthjwRcTTwED36thyL1DebVrKuwvohjMNi", - "efd6bca256b5abc5602ec2e1c121a08b0da2556587430bcf7e1898af2224885203", "93DVKyFYwSN6wEo3E2fCrFPUp17FtrtNi2Lf7n4G3garFb16CRj", - "efa81ca4e8f90181ec4b61b6a7eb998af17b2cb04de8a03b504b9e34c4c61db7d901", "cTDVKtMGVYWTHCb1AFjmVbEbWjvKpKqKgMaR3QJxToMSQAhmCeTN", - "007987ccaa53d02c8873487ef919677cd3db7a6912", "1C5bSj1iEGUgSTbziymG7Cn18ENQuT36vv", - "0563bcc565f9e68ee0189dd5cc67f1b0e5f02f45cb", "3AnNxabYGoTxYiTEZwFEnerUoeFXK2Zoks", - "6fef66444b5b17f14e8fae6e7e19b045a78c54fd79", "n3LnJXCqbPjghuVs8ph9CYsAe4Sh4j97wk", - "c4c3e55fceceaa4391ed2a9677f4a4d34eacd021a0", "2NB72XtkjpnATMggui83aEtPawyyKvnbX2o", - "80e75d936d56377f432f404aabb406601f892fd49da90eb6ac558a733c93b47252", "5KaBW9vNtWNhc3ZEDyNCiXLPdVPHCikRxSBWwV9NrpLLa4LsXi9", - "808248bd0375f2f75d7e274ae544fb920f51784480866b102384190b1addfbaa5c01", "L1axzbSyynNYA8mCAhzxkipKkfHtAXYF4YQnhSKcLV8YXA874fgT", - "ef44c4f6a096eac5238291a94cc24c01e3b19b8d8cef72874a079e00a242237a52", "927CnUkUbasYtDwYwVn2j8GdTuACNnKkjZ1rpZd2yBB1CLcnXpo", - "efd1de707020a9059d6d3abaf85e17967c6555151143db13dbb06db78df0f15c6901", "cUcfCMRjiQf85YMzzQEk9d1s5A4K7xL5SmBCLrezqXFuTVefyhY7", - "00adc1cc2081a27206fae25792f28bbc55b831549d", "1Gqk4Tv79P91Cc1STQtU3s1W6277M2CVWu", - "05188f91a931947eddd7432d6e614387e32b244709", "33vt8ViH5jsr115AGkW6cEmEz9MpvJSwDk", - "6f1694f5bc1a7295b600f40018a618a6ea48eeb498", "mhaMcBxNh5cqXm4aTQ6EcVbKtfL6LGyK2H", - "c43b9b3fd7a50d4f08d1a5b0f62f644fa7115ae2f3", "2MxgPqX1iThW3oZVk9KoFcE5M4JpiETssVN", - "80091035445ef105fa1bb125eccfb1882f3fe69592265956ade751fd095033d8d0", "5HtH6GdcwCJA4ggWEL1B3jzBBUB8HPiBi9SBc5h9i4Wk4PSeApR", - "80ab2b4bcdfc91d34dee0ae2a8c6b6668dadaeb3a88b9859743156f462325187af01", "L2xSYmMeVo3Zek3ZTsv9xUrXVAmrWxJ8Ua4cw8pkfbQhcEFhkXT8", - "efb4204389cef18bbe2b353623cbf93e8678fbc92a475b664ae98ed594e6cf0856", "92xFEve1Z9N8Z641KQQS7ByCSb8kGjsDzw6fAmjHN1LZGKQXyMq", - "efe7b230133f1b5489843260236b06edca25f66adb1be455fbd38d4010d48faeef01", "cVM65tdYu1YK37tNoAyGoJTR13VBYFva1vg9FLuPAsJijGvG6NEA", - "00c4c1b72491ede1eedaca00618407ee0b772cad0d", "1JwMWBVLtiqtscbaRHai4pqHokhFCbtoB4", - "05f6fe69bcb548a829cce4c57bf6fff8af3a5981f9", "3QCzvfL4ZRvmJFiWWBVwxfdaNBT8EtxB5y", - "6f261f83568a098a8638844bd7aeca039d5f2352c0", "mizXiucXRCsEriQCHUkCqef9ph9qtPbZZ6", - "c4e930e1834a4d234702773951d627cce82fbb5d2e", "2NEWDzHWwY5ZZp8CQWbB7ouNMLqCia6YRda", - "80d1fab7ab7385ad26872237f1eb9789aa25cc986bacc695e07ac571d6cdac8bc0", "5KQmDryMNDcisTzRp3zEq9e4awRmJrEVU1j5vFRTKpRNYPqYrMg", - "80b0bbede33ef254e8376aceb1510253fc3550efd0fcf84dcd0c9998b288f166b301", "L39Fy7AC2Hhj95gh3Yb2AU5YHh1mQSAHgpNixvm27poizcJyLtUi", - "ef037f4192c630f399d9271e26c575269b1d15be553ea1a7217f0cb8513cef41cb", "91cTVUcgydqyZLgaANpf1fvL55FH53QMm4BsnCADVNYuWuqdVys", - "ef6251e205e8ad508bab5596bee086ef16cd4b239e0cc0c5d7c4e6035441e7d5de01", "cQspfSzsgLeiJGB2u8vrAiWpCU4MxUT6JseWo2SjXy4Qbzn2fwDw", - "005eadaf9bb7121f0f192561a5a62f5e5f54210292", "19dcawoKcZdQz365WpXWMhX6QCUpR9SY4r", - "053f210e7277c899c3a155cc1c90f4106cbddeec6e", "37Sp6Rv3y4kVd1nQ1JV5pfqXccHNyZm1x3", - "6fc8a3c2a09a298592c3e180f02487cd91ba3400b5", "myoqcgYiehufrsnnkqdqbp69dddVDMopJu", - "c499b31df7c9068d1481b596578ddbb4d3bd90baeb", "2N7FuwuUuoTBrDFdrAZ9KxBmtqMLxce9i1C", - "80c7666842503db6dc6ea061f092cfb9c388448629a6fe868d068c42a488b478ae", "5KL6zEaMtPRXZKo1bbMq7JDjjo1bJuQcsgL33je3oY8uSJCR5b4", - "8007f0803fc5399e773555ab1e8939907e9badacc17ca129e67a2f5f2ff84351dd01", "KwV9KAfwbwt51veZWNscRTeZs9CKpojyu1MsPnaKTF5kz69H1UN2", - "efea577acfb5d1d14d3b7b195c321566f12f87d2b77ea3a53f68df7ebf8604a801", "93N87D6uxSBzwXvpokpzg8FFmfQPmvX4xHoWQe3pLdYpbiwT5YV", - "ef0b3b34f0958d8a268193a9814da92c3e8b58b4a4378a542863e34ac289cd830c01", "cMxXusSihaX58wpJ3tNuuUcZEQGt6DKJ1wEpxys88FFaQCYjku9h", - "001ed467017f043e91ed4c44b4e8dd674db211c4e6", "13p1ijLwsnrcuyqcTvJXkq2ASdXqcnEBLE", - "055ece0cadddc415b1980f001785947120acdb36fc", "3ALJH9Y951VCGcVZYAdpA3KchoP9McEj1G", - 0, 0, - }; - const char **raw = base58_vector; - const char **str = base58_vector + 1; - uint8_t rawn[34]; - char strn[53]; - int r; - while (*raw && *str) { - int len = strlen(*raw) / 2; - - memcpy(rawn, fromhex(*raw), len); - r = base58_encode_check(rawn, len, HASHER_SHA2D, strn, sizeof(strn)); - ck_assert_int_eq((size_t)r, strlen(*str) + 1); - ck_assert_str_eq(strn, *str); - - r = base58_decode_check(strn, HASHER_SHA2D, rawn, len); - ck_assert_int_eq(r, len); - ck_assert_mem_eq(rawn, fromhex(*raw), len); - - raw += 2; str += 2; - } +// from +// https://github.com/bitcoin/bitcoin/blob/master/src/test/data/base58_keys_valid.json +START_TEST(test_base58) { + static const char *base58_vector[] = { + "0065a16059864a2fdbc7c99a4723a8395bc6f188eb", + "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i", + "0574f209f6ea907e2ea48f74fae05782ae8a665257", + "3CMNFxN1oHBc4R1EpboAL5yzHGgE611Xou", + "6f53c0307d6851aa0ce7825ba883c6bd9ad242b486", + "mo9ncXisMeAoXwqcV5EWuyncbmCcQN4rVs", + "c46349a418fc4578d10a372b54b45c280cc8c4382f", + "2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br", + "80eddbdc1168f1daeadbd3e44c1e3f8f5a284c2029f78ad26af98583a499de5b19", + "5Kd3NBUAdUnhyzenEwVLy9pBKxSwXvE9FMPyR4UKZvpe6E3AgLr", + "8055c9bccb9ed68446d1b75273bbce89d7fe013a8acd1625514420fb2aca1a21c401", + "Kz6UJmQACJmLtaQj5A3JAge4kVTNQ8gbvXuwbmCj7bsaabudb3RD", + "ef36cb93b9ab1bdabf7fb9f2c04f1b9cc879933530ae7842398eef5a63a56800c2", + "9213qJab2HNEpMpYNBa7wHGFKKbkDn24jpANDs2huN3yi4J11ko", + "efb9f4892c9e8282028fea1d2667c4dc5213564d41fc5783896a0d843fc15089f301", + "cTpB4YiyKiBcPxnefsDpbnDxFDffjqJob8wGCEDXxgQ7zQoMXJdH", + "006d23156cbbdcc82a5a47eee4c2c7c583c18b6bf4", + "1Ax4gZtb7gAit2TivwejZHYtNNLT18PUXJ", + "05fcc5460dd6e2487c7d75b1963625da0e8f4c5975", + "3QjYXhTkvuj8qPaXHTTWb5wjXhdsLAAWVy", + "6ff1d470f9b02370fdec2e6b708b08ac431bf7a5f7", + "n3ZddxzLvAY9o7184TB4c6FJasAybsw4HZ", + "c4c579342c2c4c9220205e2cdc285617040c924a0a", + "2NBFNJTktNa7GZusGbDbGKRZTxdK9VVez3n", + "80a326b95ebae30164217d7a7f57d72ab2b54e3be64928a19da0210b9568d4015e", + "5K494XZwps2bGyeL71pWid4noiSNA2cfCibrvRWqcHSptoFn7rc", + "807d998b45c219a1e38e99e7cbd312ef67f77a455a9b50c730c27f02c6f730dfb401", + "L1RrrnXkcKut5DEMwtDthjwRcTTwED36thyL1DebVrKuwvohjMNi", + "efd6bca256b5abc5602ec2e1c121a08b0da2556587430bcf7e1898af2224885203", + "93DVKyFYwSN6wEo3E2fCrFPUp17FtrtNi2Lf7n4G3garFb16CRj", + "efa81ca4e8f90181ec4b61b6a7eb998af17b2cb04de8a03b504b9e34c4c61db7d901", + "cTDVKtMGVYWTHCb1AFjmVbEbWjvKpKqKgMaR3QJxToMSQAhmCeTN", + "007987ccaa53d02c8873487ef919677cd3db7a6912", + "1C5bSj1iEGUgSTbziymG7Cn18ENQuT36vv", + "0563bcc565f9e68ee0189dd5cc67f1b0e5f02f45cb", + "3AnNxabYGoTxYiTEZwFEnerUoeFXK2Zoks", + "6fef66444b5b17f14e8fae6e7e19b045a78c54fd79", + "n3LnJXCqbPjghuVs8ph9CYsAe4Sh4j97wk", + "c4c3e55fceceaa4391ed2a9677f4a4d34eacd021a0", + "2NB72XtkjpnATMggui83aEtPawyyKvnbX2o", + "80e75d936d56377f432f404aabb406601f892fd49da90eb6ac558a733c93b47252", + "5KaBW9vNtWNhc3ZEDyNCiXLPdVPHCikRxSBWwV9NrpLLa4LsXi9", + "808248bd0375f2f75d7e274ae544fb920f51784480866b102384190b1addfbaa5c01", + "L1axzbSyynNYA8mCAhzxkipKkfHtAXYF4YQnhSKcLV8YXA874fgT", + "ef44c4f6a096eac5238291a94cc24c01e3b19b8d8cef72874a079e00a242237a52", + "927CnUkUbasYtDwYwVn2j8GdTuACNnKkjZ1rpZd2yBB1CLcnXpo", + "efd1de707020a9059d6d3abaf85e17967c6555151143db13dbb06db78df0f15c6901", + "cUcfCMRjiQf85YMzzQEk9d1s5A4K7xL5SmBCLrezqXFuTVefyhY7", + "00adc1cc2081a27206fae25792f28bbc55b831549d", + "1Gqk4Tv79P91Cc1STQtU3s1W6277M2CVWu", + "05188f91a931947eddd7432d6e614387e32b244709", + "33vt8ViH5jsr115AGkW6cEmEz9MpvJSwDk", + "6f1694f5bc1a7295b600f40018a618a6ea48eeb498", + "mhaMcBxNh5cqXm4aTQ6EcVbKtfL6LGyK2H", + "c43b9b3fd7a50d4f08d1a5b0f62f644fa7115ae2f3", + "2MxgPqX1iThW3oZVk9KoFcE5M4JpiETssVN", + "80091035445ef105fa1bb125eccfb1882f3fe69592265956ade751fd095033d8d0", + "5HtH6GdcwCJA4ggWEL1B3jzBBUB8HPiBi9SBc5h9i4Wk4PSeApR", + "80ab2b4bcdfc91d34dee0ae2a8c6b6668dadaeb3a88b9859743156f462325187af01", + "L2xSYmMeVo3Zek3ZTsv9xUrXVAmrWxJ8Ua4cw8pkfbQhcEFhkXT8", + "efb4204389cef18bbe2b353623cbf93e8678fbc92a475b664ae98ed594e6cf0856", + "92xFEve1Z9N8Z641KQQS7ByCSb8kGjsDzw6fAmjHN1LZGKQXyMq", + "efe7b230133f1b5489843260236b06edca25f66adb1be455fbd38d4010d48faeef01", + "cVM65tdYu1YK37tNoAyGoJTR13VBYFva1vg9FLuPAsJijGvG6NEA", + "00c4c1b72491ede1eedaca00618407ee0b772cad0d", + "1JwMWBVLtiqtscbaRHai4pqHokhFCbtoB4", + "05f6fe69bcb548a829cce4c57bf6fff8af3a5981f9", + "3QCzvfL4ZRvmJFiWWBVwxfdaNBT8EtxB5y", + "6f261f83568a098a8638844bd7aeca039d5f2352c0", + "mizXiucXRCsEriQCHUkCqef9ph9qtPbZZ6", + "c4e930e1834a4d234702773951d627cce82fbb5d2e", + "2NEWDzHWwY5ZZp8CQWbB7ouNMLqCia6YRda", + "80d1fab7ab7385ad26872237f1eb9789aa25cc986bacc695e07ac571d6cdac8bc0", + "5KQmDryMNDcisTzRp3zEq9e4awRmJrEVU1j5vFRTKpRNYPqYrMg", + "80b0bbede33ef254e8376aceb1510253fc3550efd0fcf84dcd0c9998b288f166b301", + "L39Fy7AC2Hhj95gh3Yb2AU5YHh1mQSAHgpNixvm27poizcJyLtUi", + "ef037f4192c630f399d9271e26c575269b1d15be553ea1a7217f0cb8513cef41cb", + "91cTVUcgydqyZLgaANpf1fvL55FH53QMm4BsnCADVNYuWuqdVys", + "ef6251e205e8ad508bab5596bee086ef16cd4b239e0cc0c5d7c4e6035441e7d5de01", + "cQspfSzsgLeiJGB2u8vrAiWpCU4MxUT6JseWo2SjXy4Qbzn2fwDw", + "005eadaf9bb7121f0f192561a5a62f5e5f54210292", + "19dcawoKcZdQz365WpXWMhX6QCUpR9SY4r", + "053f210e7277c899c3a155cc1c90f4106cbddeec6e", + "37Sp6Rv3y4kVd1nQ1JV5pfqXccHNyZm1x3", + "6fc8a3c2a09a298592c3e180f02487cd91ba3400b5", + "myoqcgYiehufrsnnkqdqbp69dddVDMopJu", + "c499b31df7c9068d1481b596578ddbb4d3bd90baeb", + "2N7FuwuUuoTBrDFdrAZ9KxBmtqMLxce9i1C", + "80c7666842503db6dc6ea061f092cfb9c388448629a6fe868d068c42a488b478ae", + "5KL6zEaMtPRXZKo1bbMq7JDjjo1bJuQcsgL33je3oY8uSJCR5b4", + "8007f0803fc5399e773555ab1e8939907e9badacc17ca129e67a2f5f2ff84351dd01", + "KwV9KAfwbwt51veZWNscRTeZs9CKpojyu1MsPnaKTF5kz69H1UN2", + "efea577acfb5d1d14d3b7b195c321566f12f87d2b77ea3a53f68df7ebf8604a801", + "93N87D6uxSBzwXvpokpzg8FFmfQPmvX4xHoWQe3pLdYpbiwT5YV", + "ef0b3b34f0958d8a268193a9814da92c3e8b58b4a4378a542863e34ac289cd830c01", + "cMxXusSihaX58wpJ3tNuuUcZEQGt6DKJ1wEpxys88FFaQCYjku9h", + "001ed467017f043e91ed4c44b4e8dd674db211c4e6", + "13p1ijLwsnrcuyqcTvJXkq2ASdXqcnEBLE", + "055ece0cadddc415b1980f001785947120acdb36fc", + "3ALJH9Y951VCGcVZYAdpA3KchoP9McEj1G", + 0, + 0, + }; + const char **raw = base58_vector; + const char **str = base58_vector + 1; + uint8_t rawn[34]; + char strn[53]; + int r; + while (*raw && *str) { + int len = strlen(*raw) / 2; + + memcpy(rawn, fromhex(*raw), len); + r = base58_encode_check(rawn, len, HASHER_SHA2D, strn, sizeof(strn)); + ck_assert_int_eq((size_t)r, strlen(*str) + 1); + ck_assert_str_eq(strn, *str); + + r = base58_decode_check(strn, HASHER_SHA2D, rawn, len); + ck_assert_int_eq(r, len); + ck_assert_mem_eq(rawn, fromhex(*raw), len); + + raw += 2; + str += 2; + } } END_TEST #if USE_GRAPHENE // Graphene Base85CheckEncoding -START_TEST(test_base58gph) -{ - static const char *base58_vector[] = { - "02e649f63f8e8121345fd7f47d0d185a3ccaa843115cd2e9392dcd9b82263bc680", "6dumtt9swxCqwdPZBGXh9YmHoEjFFnNfwHaTqRbQTghGAY2gRz", - "021c7359cd885c0e319924d97e3980206ad64387aff54908241125b3a88b55ca16", "5725vivYpuFWbeyTifZ5KevnHyqXCi5hwHbNU9cYz1FHbFXCxX", - "02f561e0b57a552df3fa1df2d87a906b7a9fc33a83d5d15fa68a644ecb0806b49a", "6kZKHSuxqAwdCYsMvwTcipoTsNE2jmEUNBQufGYywpniBKXWZK", - "03e7595c3e6b58f907bee951dc29796f3757307e700ecf3d09307a0cc4a564eba3", "8b82mpnH8YX1E9RHnU2a2YgLTZ8ooevEGP9N15c1yFqhoBvJur", - 0, 0, - }; - const char **raw = base58_vector; - const char **str = base58_vector + 1; - uint8_t rawn[34]; - char strn[53]; - int r; - while (*raw && *str) { - int len = strlen(*raw) / 2; - - memcpy(rawn, fromhex(*raw), len); - r = base58gph_encode_check(rawn, len, strn, sizeof(strn)); - ck_assert_int_eq((size_t)r, strlen(*str) + 1); - ck_assert_str_eq(strn, *str); - - r = base58gph_decode_check(strn, rawn, len); - ck_assert_int_eq(r, len); - ck_assert_mem_eq(rawn, fromhex(*raw), len); - - raw += 2; str += 2; - } +START_TEST(test_base58gph) { + static const char *base58_vector[] = { + "02e649f63f8e8121345fd7f47d0d185a3ccaa843115cd2e9392dcd9b82263bc680", + "6dumtt9swxCqwdPZBGXh9YmHoEjFFnNfwHaTqRbQTghGAY2gRz", + "021c7359cd885c0e319924d97e3980206ad64387aff54908241125b3a88b55ca16", + "5725vivYpuFWbeyTifZ5KevnHyqXCi5hwHbNU9cYz1FHbFXCxX", + "02f561e0b57a552df3fa1df2d87a906b7a9fc33a83d5d15fa68a644ecb0806b49a", + "6kZKHSuxqAwdCYsMvwTcipoTsNE2jmEUNBQufGYywpniBKXWZK", + "03e7595c3e6b58f907bee951dc29796f3757307e700ecf3d09307a0cc4a564eba3", + "8b82mpnH8YX1E9RHnU2a2YgLTZ8ooevEGP9N15c1yFqhoBvJur", + 0, + 0, + }; + const char **raw = base58_vector; + const char **str = base58_vector + 1; + uint8_t rawn[34]; + char strn[53]; + int r; + while (*raw && *str) { + int len = strlen(*raw) / 2; + + memcpy(rawn, fromhex(*raw), len); + r = base58gph_encode_check(rawn, len, strn, sizeof(strn)); + ck_assert_int_eq((size_t)r, strlen(*str) + 1); + ck_assert_str_eq(strn, *str); + + r = base58gph_decode_check(strn, rawn, len); + ck_assert_int_eq(r, len); + ck_assert_mem_eq(rawn, fromhex(*raw), len); + + raw += 2; + str += 2; + } } END_TEST #endif -START_TEST(test_bignum_divmod) -{ - uint32_t r; - int i; - - bignum256 a = { { 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0xffff} }; - uint32_t ar[] = { 15, 14, 55, 29, 44, 24, 53, 49, 18, 55, 2, 28, 5, 4, 12, 43, 18, 37, 28, 14, 30, 46, 12, 11, 17, 10, 10, 13, 24, 45, 4, 33, 44, 42, 2, 46, 34, 43, 45, 28, 21, 18, 13, 17 }; - - i = 0; - while (!bn_is_zero(&a) && i < 44) { - bn_divmod58(&a, &r); - ck_assert_int_eq(r, ar[i]); - i++; - } - ck_assert_int_eq(i, 44); - - bignum256 b = { { 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0xffff} }; - uint32_t br[] = { 935, 639, 129, 913, 7, 584, 457, 39, 564, 640, 665, 984, 269, 853, 907, 687, 8, 985, 570, 423, 195, 316, 237, 89, 792, 115 }; - - i = 0; - while (!bn_is_zero(&b) && i < 26) { - bn_divmod1000(&b, &r); - ck_assert_int_eq(r, br[i]); - i++; - } - ck_assert_int_eq(i, 26); - +START_TEST(test_bignum_divmod) { + uint32_t r; + int i; + + bignum256 a = {{0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, + 0x3fffffff, 0x3fffffff, 0x3fffffff, 0xffff}}; + uint32_t ar[] = {15, 14, 55, 29, 44, 24, 53, 49, 18, 55, 2, 28, 5, 4, 12, + 43, 18, 37, 28, 14, 30, 46, 12, 11, 17, 10, 10, 13, 24, 45, + 4, 33, 44, 42, 2, 46, 34, 43, 45, 28, 21, 18, 13, 17}; + + i = 0; + while (!bn_is_zero(&a) && i < 44) { + bn_divmod58(&a, &r); + ck_assert_int_eq(r, ar[i]); + i++; + } + ck_assert_int_eq(i, 44); + + bignum256 b = {{0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, + 0x3fffffff, 0x3fffffff, 0x3fffffff, 0xffff}}; + uint32_t br[] = {935, 639, 129, 913, 7, 584, 457, 39, 564, + 640, 665, 984, 269, 853, 907, 687, 8, 985, + 570, 423, 195, 316, 237, 89, 792, 115}; + + i = 0; + while (!bn_is_zero(&b) && i < 26) { + bn_divmod1000(&b, &r); + ck_assert_int_eq(r, br[i]); + i++; + } + ck_assert_int_eq(i, 26); } END_TEST -// test vector 1 from https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#test-vector-1 -START_TEST(test_bip32_vector_1) -{ - HDNode node, node2, node3; - uint32_t fingerprint; - char str[112]; - int r; - - // init m - hdnode_from_seed(fromhex("000102030405060708090a0b0c0d0e0f"), 16, SECP256K1_NAME, &node); - - // [Chain m] - fingerprint = 0; - ck_assert_int_eq(fingerprint, 0x00000000); - ck_assert_mem_eq(node.chain_code, fromhex("873dff81c02f525623fd1fe5167eac3a55a049de3d314bb42ee227ffed37d508"), 32); - ck_assert_mem_eq(node.private_key, fromhex("e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key, fromhex("0339a36013301597daef41fbe593a02cc513d0b55527ec2df1050e2e8ff49c85c2"), 33); - hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, sizeof(str)); - ck_assert_str_eq(str, "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi"); - r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); - ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); - ck_assert_str_eq(str, "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8"); - r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - memcpy(&node3, &node, sizeof(HDNode)); - memzero(&node3.private_key, 32); - ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); - - // [Chain m/0'] - fingerprint = hdnode_fingerprint(&node); - hdnode_private_ckd_prime(&node, 0); - ck_assert_int_eq(fingerprint, 0x3442193e); - ck_assert_mem_eq(node.chain_code, fromhex("47fdacbd0f1097043b78c63c20c34ef4ed9a111d980047ad16282c7ae6236141"), 32); - ck_assert_mem_eq(node.private_key, fromhex("edb2e14f9ee77d26dd93b4ecede8d16ed408ce149b6cd80b0715a2d911a0afea"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key, fromhex("035a784662a4a20a65bf6aab9ae98a6c068a81c52e4b032c0fb5400c706cfccc56"), 33); - hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, sizeof(str)); - ck_assert_str_eq(str, "xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7"); - r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); - ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); - ck_assert_str_eq(str, "xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw"); - r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - memcpy(&node3, &node, sizeof(HDNode)); - memzero(&node3.private_key, 32); - ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); - - // [Chain m/0'/1] - fingerprint = hdnode_fingerprint(&node); - hdnode_private_ckd(&node, 1); - ck_assert_int_eq(fingerprint, 0x5c1bd648); - ck_assert_mem_eq(node.chain_code, fromhex("2a7857631386ba23dacac34180dd1983734e444fdbf774041578e9b6adb37c19"), 32); - ck_assert_mem_eq(node.private_key, fromhex("3c6cb8d0f6a264c91ea8b5030fadaa8e538b020f0a387421a12de9319dc93368"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key, fromhex("03501e454bf00751f24b1b489aa925215d66af2234e3891c3b21a52bedb3cd711c"), 33); - hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, sizeof(str)); - ck_assert_str_eq(str, "xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs"); - r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); - ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); - ck_assert_str_eq(str, "xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFHKkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ"); - r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - memcpy(&node3, &node, sizeof(HDNode)); - memzero(&node3.private_key, 32); - ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); - - // [Chain m/0'/1/2'] - fingerprint = hdnode_fingerprint(&node); - hdnode_private_ckd_prime(&node, 2); - ck_assert_int_eq(fingerprint, 0xbef5a2f9); - ck_assert_mem_eq(node.chain_code, fromhex("04466b9cc8e161e966409ca52986c584f07e9dc81f735db683c3ff6ec7b1503f"), 32); - ck_assert_mem_eq(node.private_key, fromhex("cbce0d719ecf7431d88e6a89fa1483e02e35092af60c042b1df2ff59fa424dca"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key, fromhex("0357bfe1e341d01c69fe5654309956cbea516822fba8a601743a012a7896ee8dc2"), 33); - hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, sizeof(str)); - ck_assert_str_eq(str, "xprv9z4pot5VBttmtdRTWfWQmoH1taj2axGVzFqSb8C9xaxKymcFzXBDptWmT7FwuEzG3ryjH4ktypQSAewRiNMjANTtpgP4mLTj34bhnZX7UiM"); - r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); - ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); - ck_assert_str_eq(str, "xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5"); - r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - memcpy(&node3, &node, sizeof(HDNode)); - memzero(&node3.private_key, 32); - ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); - - // [Chain m/0'/1/2'/2] - fingerprint = hdnode_fingerprint(&node); - hdnode_private_ckd(&node, 2); - ck_assert_int_eq(fingerprint, 0xee7ab90c); - ck_assert_mem_eq(node.chain_code, fromhex("cfb71883f01676f587d023cc53a35bc7f88f724b1f8c2892ac1275ac822a3edd"), 32); - ck_assert_mem_eq(node.private_key, fromhex("0f479245fb19a38a1954c5c7c0ebab2f9bdfd96a17563ef28a6a4b1a2a764ef4"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key, fromhex("02e8445082a72f29b75ca48748a914df60622a609cacfce8ed0e35804560741d29"), 33); - hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, sizeof(str)); - ck_assert_str_eq(str, "xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334"); - r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); - ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); - ck_assert_str_eq(str, "xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV"); - r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - memcpy(&node3, &node, sizeof(HDNode)); - memzero(&node3.private_key, 32); - ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); - - // [Chain m/0'/1/2'/2/1000000000] - fingerprint = hdnode_fingerprint(&node); - hdnode_private_ckd(&node, 1000000000); - ck_assert_int_eq(fingerprint, 0xd880d7d8); - ck_assert_mem_eq(node.chain_code, fromhex("c783e67b921d2beb8f6b389cc646d7263b4145701dadd2161548a8b078e65e9e"), 32); - ck_assert_mem_eq(node.private_key, fromhex("471b76e389e528d6de6d816857e012c5455051cad6660850e58372a6c3e6e7c8"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key, fromhex("022a471424da5e657499d1ff51cb43c47481a03b1e77f951fe64cec9f5a48f7011"), 33); - hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, sizeof(str)); - ck_assert_str_eq(str, "xprvA41z7zogVVwxVSgdKUHDy1SKmdb533PjDz7J6N6mV6uS3ze1ai8FHa8kmHScGpWmj4WggLyQjgPie1rFSruoUihUZREPSL39UNdE3BBDu76"); - r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); - ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); - ck_assert_str_eq(str, "xpub6H1LXWLaKsWFhvm6RVpEL9P4KfRZSW7abD2ttkWP3SSQvnyA8FSVqNTEcYFgJS2UaFcxupHiYkro49S8yGasTvXEYBVPamhGW6cFJodrTHy"); - r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - memcpy(&node3, &node, sizeof(HDNode)); - memzero(&node3.private_key, 32); - ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); +// test vector 1 from +// https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#test-vector-1 +START_TEST(test_bip32_vector_1) { + HDNode node, node2, node3; + uint32_t fingerprint; + char str[112]; + int r; + + // init m + hdnode_from_seed(fromhex("000102030405060708090a0b0c0d0e0f"), 16, + SECP256K1_NAME, &node); + + // [Chain m] + fingerprint = 0; + ck_assert_int_eq(fingerprint, 0x00000000); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "873dff81c02f525623fd1fe5167eac3a55a049de3d314bb42ee227ffed37d508"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "0339a36013301597daef41fbe593a02cc513d0b55527ec2df1050e2e8ff49c85c2"), + 33); + hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, + sizeof(str)); + ck_assert_str_eq(str, + "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqji" + "ChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi"); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, + &node2, NULL); + ck_assert_int_eq(r, 0); + ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); + ck_assert_str_eq(str, + "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2" + "gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8"); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, + &node2, NULL); + ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memzero(&node3.private_key, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); + + // [Chain m/0'] + fingerprint = hdnode_fingerprint(&node); + hdnode_private_ckd_prime(&node, 0); + ck_assert_int_eq(fingerprint, 0x3442193e); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "47fdacbd0f1097043b78c63c20c34ef4ed9a111d980047ad16282c7ae6236141"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "edb2e14f9ee77d26dd93b4ecede8d16ed408ce149b6cd80b0715a2d911a0afea"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "035a784662a4a20a65bf6aab9ae98a6c068a81c52e4b032c0fb5400c706cfccc56"), + 33); + hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, + sizeof(str)); + ck_assert_str_eq(str, + "xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4" + "cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7"); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, + &node2, NULL); + ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); + ck_assert_str_eq(str, + "xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP" + "6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw"); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, + &node2, NULL); + ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memzero(&node3.private_key, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); + + // [Chain m/0'/1] + fingerprint = hdnode_fingerprint(&node); + hdnode_private_ckd(&node, 1); + ck_assert_int_eq(fingerprint, 0x5c1bd648); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "2a7857631386ba23dacac34180dd1983734e444fdbf774041578e9b6adb37c19"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "3c6cb8d0f6a264c91ea8b5030fadaa8e538b020f0a387421a12de9319dc93368"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "03501e454bf00751f24b1b489aa925215d66af2234e3891c3b21a52bedb3cd711c"), + 33); + hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, + sizeof(str)); + ck_assert_str_eq(str, + "xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSx" + "qu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs"); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, + &node2, NULL); + ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); + ck_assert_str_eq(str, + "xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFH" + "KkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ"); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, + &node2, NULL); + ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memzero(&node3.private_key, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); + + // [Chain m/0'/1/2'] + fingerprint = hdnode_fingerprint(&node); + hdnode_private_ckd_prime(&node, 2); + ck_assert_int_eq(fingerprint, 0xbef5a2f9); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "04466b9cc8e161e966409ca52986c584f07e9dc81f735db683c3ff6ec7b1503f"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "cbce0d719ecf7431d88e6a89fa1483e02e35092af60c042b1df2ff59fa424dca"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "0357bfe1e341d01c69fe5654309956cbea516822fba8a601743a012a7896ee8dc2"), + 33); + hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, + sizeof(str)); + ck_assert_str_eq(str, + "xprv9z4pot5VBttmtdRTWfWQmoH1taj2axGVzFqSb8C9xaxKymcFzXBDptW" + "mT7FwuEzG3ryjH4ktypQSAewRiNMjANTtpgP4mLTj34bhnZX7UiM"); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, + &node2, NULL); + ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); + ck_assert_str_eq(str, + "xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgq" + "FJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5"); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, + &node2, NULL); + ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memzero(&node3.private_key, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); + + // [Chain m/0'/1/2'/2] + fingerprint = hdnode_fingerprint(&node); + hdnode_private_ckd(&node, 2); + ck_assert_int_eq(fingerprint, 0xee7ab90c); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "cfb71883f01676f587d023cc53a35bc7f88f724b1f8c2892ac1275ac822a3edd"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "0f479245fb19a38a1954c5c7c0ebab2f9bdfd96a17563ef28a6a4b1a2a764ef4"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "02e8445082a72f29b75ca48748a914df60622a609cacfce8ed0e35804560741d29"), + 33); + hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, + sizeof(str)); + ck_assert_str_eq(str, + "xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Ty" + "h8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334"); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, + &node2, NULL); + ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); + ck_assert_str_eq(str, + "xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJ" + "AyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV"); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, + &node2, NULL); + ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memzero(&node3.private_key, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); + + // [Chain m/0'/1/2'/2/1000000000] + fingerprint = hdnode_fingerprint(&node); + hdnode_private_ckd(&node, 1000000000); + ck_assert_int_eq(fingerprint, 0xd880d7d8); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "c783e67b921d2beb8f6b389cc646d7263b4145701dadd2161548a8b078e65e9e"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "471b76e389e528d6de6d816857e012c5455051cad6660850e58372a6c3e6e7c8"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "022a471424da5e657499d1ff51cb43c47481a03b1e77f951fe64cec9f5a48f7011"), + 33); + hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, + sizeof(str)); + ck_assert_str_eq(str, + "xprvA41z7zogVVwxVSgdKUHDy1SKmdb533PjDz7J6N6mV6uS3ze1ai8FHa8" + "kmHScGpWmj4WggLyQjgPie1rFSruoUihUZREPSL39UNdE3BBDu76"); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, + &node2, NULL); + ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); + ck_assert_str_eq(str, + "xpub6H1LXWLaKsWFhvm6RVpEL9P4KfRZSW7abD2ttkWP3SSQvnyA8FSVqNT" + "EcYFgJS2UaFcxupHiYkro49S8yGasTvXEYBVPamhGW6cFJodrTHy"); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, + &node2, NULL); + ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memzero(&node3.private_key, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); } END_TEST -// test vector 2 from https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#test-vector-2 -START_TEST(test_bip32_vector_2) -{ - HDNode node, node2, node3; - uint32_t fingerprint; - char str[112]; - int r; - - // init m - hdnode_from_seed(fromhex("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), 64, SECP256K1_NAME, &node); - - // [Chain m] - fingerprint = 0; - ck_assert_int_eq(fingerprint, 0x00000000); - ck_assert_mem_eq(node.chain_code, fromhex("60499f801b896d83179a4374aeb7822aaeaceaa0db1f85ee3e904c4defbd9689"), 32); - ck_assert_mem_eq(node.private_key, fromhex("4b03d6fc340455b363f51020ad3ecca4f0850280cf436c70c727923f6db46c3e"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key, fromhex("03cbcaa9c98c877a26977d00825c956a238e8dddfbd322cce4f74b0b5bd6ace4a7"), 33); - hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, sizeof(str)); - ck_assert_str_eq(str, "xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U"); - r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); - ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); - ck_assert_str_eq(str, "xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB"); - r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - memcpy(&node3, &node, sizeof(HDNode)); - memzero(&node3.private_key, 32); - ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); - - // [Chain m/0] - fingerprint = hdnode_fingerprint(&node); - r = hdnode_private_ckd(&node, 0); - ck_assert_int_eq(r, 1); - ck_assert_int_eq(fingerprint, 0xbd16bee5); - ck_assert_mem_eq(node.chain_code, fromhex("f0909affaa7ee7abe5dd4e100598d4dc53cd709d5a5c2cac40e7412f232f7c9c"), 32); - ck_assert_mem_eq(node.private_key, fromhex("abe74a98f6c7eabee0428f53798f0ab8aa1bd37873999041703c742f15ac7e1e"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key, fromhex("02fc9e5af0ac8d9b3cecfe2a888e2117ba3d089d8585886c9c826b6b22a98d12ea"), 33); - hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, sizeof(str)); - ck_assert_str_eq(str, "xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt"); - r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); - ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); - ck_assert_str_eq(str, "xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH"); - r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - memcpy(&node3, &node, sizeof(HDNode)); - memzero(&node3.private_key, 32); - ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); - - // [Chain m/0/2147483647'] - fingerprint = hdnode_fingerprint(&node); - r = hdnode_private_ckd_prime(&node, 2147483647); - ck_assert_int_eq(r, 1); - ck_assert_int_eq(fingerprint, 0x5a61ff8e); - ck_assert_mem_eq(node.chain_code, fromhex("be17a268474a6bb9c61e1d720cf6215e2a88c5406c4aee7b38547f585c9a37d9"), 32); - ck_assert_mem_eq(node.private_key, fromhex("877c779ad9687164e9c2f4f0f4ff0340814392330693ce95a58fe18fd52e6e93"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key, fromhex("03c01e7425647bdefa82b12d9bad5e3e6865bee0502694b94ca58b666abc0a5c3b"), 33); - hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, sizeof(str)); - ck_assert_str_eq(str, "xprv9wSp6B7kry3Vj9m1zSnLvN3xH8RdsPP1Mh7fAaR7aRLcQMKTR2vidYEeEg2mUCTAwCd6vnxVrcjfy2kRgVsFawNzmjuHc2YmYRmagcEPdU9"); - r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); - ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); - ck_assert_str_eq(str, "xpub6ASAVgeehLbnwdqV6UKMHVzgqAG8Gr6riv3Fxxpj8ksbH9ebxaEyBLZ85ySDhKiLDBrQSARLq1uNRts8RuJiHjaDMBU4Zn9h8LZNnBC5y4a"); - r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - memcpy(&node3, &node, sizeof(HDNode)); - memzero(&node3.private_key, 32); - ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); - - // [Chain m/0/2147483647'/1] - fingerprint = hdnode_fingerprint(&node); - r = hdnode_private_ckd(&node, 1); - ck_assert_int_eq(r, 1); - ck_assert_int_eq(fingerprint, 0xd8ab4937); - ck_assert_mem_eq(node.chain_code, fromhex("f366f48f1ea9f2d1d3fe958c95ca84ea18e4c4ddb9366c336c927eb246fb38cb"), 32); - ck_assert_mem_eq(node.private_key, fromhex("704addf544a06e5ee4bea37098463c23613da32020d604506da8c0518e1da4b7"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key, fromhex("03a7d1d856deb74c508e05031f9895dab54626251b3806e16b4bd12e781a7df5b9"), 33); - hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, sizeof(str)); - ck_assert_str_eq(str, "xprv9zFnWC6h2cLgpmSA46vutJzBcfJ8yaJGg8cX1e5StJh45BBciYTRXSd25UEPVuesF9yog62tGAQtHjXajPPdbRCHuWS6T8XA2ECKADdw4Ef"); - r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); - ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); - ck_assert_str_eq(str, "xpub6DF8uhdarytz3FWdA8TvFSvvAh8dP3283MY7p2V4SeE2wyWmG5mg5EwVvmdMVCQcoNJxGoWaU9DCWh89LojfZ537wTfunKau47EL2dhHKon"); - r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - memcpy(&node3, &node, sizeof(HDNode)); - memzero(&node3.private_key, 32); - ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); - - // [Chain m/0/2147483647'/1/2147483646'] - fingerprint = hdnode_fingerprint(&node); - r = hdnode_private_ckd_prime(&node, 2147483646); - ck_assert_int_eq(r, 1); - ck_assert_int_eq(fingerprint, 0x78412e3a); - ck_assert_mem_eq(node.chain_code, fromhex("637807030d55d01f9a0cb3a7839515d796bd07706386a6eddf06cc29a65a0e29"), 32); - ck_assert_mem_eq(node.private_key, fromhex("f1c7c871a54a804afe328b4c83a1c33b8e5ff48f5087273f04efa83b247d6a2d"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key, fromhex("02d2b36900396c9282fa14628566582f206a5dd0bcc8d5e892611806cafb0301f0"), 33); - hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, sizeof(str)); - ck_assert_str_eq(str, "xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc"); - r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); - ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); - ck_assert_str_eq(str, "xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL"); - r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - memcpy(&node3, &node, sizeof(HDNode)); - memzero(&node3.private_key, 32); - ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); - - // [Chain m/0/2147483647'/1/2147483646'/2] - fingerprint = hdnode_fingerprint(&node); - r = hdnode_private_ckd(&node, 2); - ck_assert_int_eq(r, 1); - ck_assert_int_eq(fingerprint, 0x31a507b8); - ck_assert_mem_eq(node.chain_code, fromhex("9452b549be8cea3ecb7a84bec10dcfd94afe4d129ebfd3b3cb58eedf394ed271"), 32); - ck_assert_mem_eq(node.private_key, fromhex("bb7d39bdb83ecf58f2fd82b6d918341cbef428661ef01ab97c28a4842125ac23"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key, fromhex("024d902e1a2fc7a8755ab5b694c575fce742c48d9ff192e63df5193e4c7afe1f9c"), 33); - hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, sizeof(str)); - ck_assert_str_eq(str, "xprvA2nrNbFZABcdryreWet9Ea4LvTJcGsqrMzxHx98MMrotbir7yrKCEXw7nadnHM8Dq38EGfSh6dqA9QWTyefMLEcBYJUuekgW4BYPJcr9E7j"); - r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); - ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); - ck_assert_str_eq(str, "xpub6FnCn6nSzZAw5Tw7cgR9bi15UV96gLZhjDstkXXxvCLsUXBGXPdSnLFbdpq8p9HmGsApME5hQTZ3emM2rnY5agb9rXpVGyy3bdW6EEgAtqt"); - r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - memcpy(&node3, &node, sizeof(HDNode)); - memzero(&node3.private_key, 32); - ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); - - // init m - hdnode_from_seed(fromhex("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), 64, SECP256K1_NAME, &node); - - // test public derivation - // [Chain m/0] - fingerprint = hdnode_fingerprint(&node); - r = hdnode_public_ckd(&node, 0); - ck_assert_int_eq(r, 1); - ck_assert_int_eq(fingerprint, 0xbd16bee5); - ck_assert_mem_eq(node.chain_code, fromhex("f0909affaa7ee7abe5dd4e100598d4dc53cd709d5a5c2cac40e7412f232f7c9c"), 32); - ck_assert_mem_eq(node.private_key, fromhex("0000000000000000000000000000000000000000000000000000000000000000"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key, fromhex("02fc9e5af0ac8d9b3cecfe2a888e2117ba3d089d8585886c9c826b6b22a98d12ea"), 33); +// test vector 2 from +// https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#test-vector-2 +START_TEST(test_bip32_vector_2) { + HDNode node, node2, node3; + uint32_t fingerprint; + char str[112]; + int r; + + // init m + hdnode_from_seed( + fromhex( + "fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c" + "999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), + 64, SECP256K1_NAME, &node); + + // [Chain m] + fingerprint = 0; + ck_assert_int_eq(fingerprint, 0x00000000); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "60499f801b896d83179a4374aeb7822aaeaceaa0db1f85ee3e904c4defbd9689"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "4b03d6fc340455b363f51020ad3ecca4f0850280cf436c70c727923f6db46c3e"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "03cbcaa9c98c877a26977d00825c956a238e8dddfbd322cce4f74b0b5bd6ace4a7"), + 33); + hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, + sizeof(str)); + ck_assert_str_eq(str, + "xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGds" + "o3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U"); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, + &node2, NULL); + ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); + ck_assert_str_eq(str, + "xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSC" + "Gu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB"); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, + &node2, NULL); + ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memzero(&node3.private_key, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); + + // [Chain m/0] + fingerprint = hdnode_fingerprint(&node); + r = hdnode_private_ckd(&node, 0); + ck_assert_int_eq(r, 1); + ck_assert_int_eq(fingerprint, 0xbd16bee5); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "f0909affaa7ee7abe5dd4e100598d4dc53cd709d5a5c2cac40e7412f232f7c9c"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "abe74a98f6c7eabee0428f53798f0ab8aa1bd37873999041703c742f15ac7e1e"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "02fc9e5af0ac8d9b3cecfe2a888e2117ba3d089d8585886c9c826b6b22a98d12ea"), + 33); + hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, + sizeof(str)); + ck_assert_str_eq(str, + "xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT" + "3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt"); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, + &node2, NULL); + ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); + ck_assert_str_eq(str, + "xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGm" + "XUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH"); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, + &node2, NULL); + ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memzero(&node3.private_key, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); + + // [Chain m/0/2147483647'] + fingerprint = hdnode_fingerprint(&node); + r = hdnode_private_ckd_prime(&node, 2147483647); + ck_assert_int_eq(r, 1); + ck_assert_int_eq(fingerprint, 0x5a61ff8e); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "be17a268474a6bb9c61e1d720cf6215e2a88c5406c4aee7b38547f585c9a37d9"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "877c779ad9687164e9c2f4f0f4ff0340814392330693ce95a58fe18fd52e6e93"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "03c01e7425647bdefa82b12d9bad5e3e6865bee0502694b94ca58b666abc0a5c3b"), + 33); + hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, + sizeof(str)); + ck_assert_str_eq(str, + "xprv9wSp6B7kry3Vj9m1zSnLvN3xH8RdsPP1Mh7fAaR7aRLcQMKTR2vidYE" + "eEg2mUCTAwCd6vnxVrcjfy2kRgVsFawNzmjuHc2YmYRmagcEPdU9"); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, + &node2, NULL); + ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); + ck_assert_str_eq(str, + "xpub6ASAVgeehLbnwdqV6UKMHVzgqAG8Gr6riv3Fxxpj8ksbH9ebxaEyBLZ" + "85ySDhKiLDBrQSARLq1uNRts8RuJiHjaDMBU4Zn9h8LZNnBC5y4a"); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, + &node2, NULL); + ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memzero(&node3.private_key, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); + + // [Chain m/0/2147483647'/1] + fingerprint = hdnode_fingerprint(&node); + r = hdnode_private_ckd(&node, 1); + ck_assert_int_eq(r, 1); + ck_assert_int_eq(fingerprint, 0xd8ab4937); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "f366f48f1ea9f2d1d3fe958c95ca84ea18e4c4ddb9366c336c927eb246fb38cb"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "704addf544a06e5ee4bea37098463c23613da32020d604506da8c0518e1da4b7"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "03a7d1d856deb74c508e05031f9895dab54626251b3806e16b4bd12e781a7df5b9"), + 33); + hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, + sizeof(str)); + ck_assert_str_eq(str, + "xprv9zFnWC6h2cLgpmSA46vutJzBcfJ8yaJGg8cX1e5StJh45BBciYTRXSd" + "25UEPVuesF9yog62tGAQtHjXajPPdbRCHuWS6T8XA2ECKADdw4Ef"); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, + &node2, NULL); + ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); + ck_assert_str_eq(str, + "xpub6DF8uhdarytz3FWdA8TvFSvvAh8dP3283MY7p2V4SeE2wyWmG5mg5Ew" + "VvmdMVCQcoNJxGoWaU9DCWh89LojfZ537wTfunKau47EL2dhHKon"); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, + &node2, NULL); + ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memzero(&node3.private_key, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); + + // [Chain m/0/2147483647'/1/2147483646'] + fingerprint = hdnode_fingerprint(&node); + r = hdnode_private_ckd_prime(&node, 2147483646); + ck_assert_int_eq(r, 1); + ck_assert_int_eq(fingerprint, 0x78412e3a); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "637807030d55d01f9a0cb3a7839515d796bd07706386a6eddf06cc29a65a0e29"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "f1c7c871a54a804afe328b4c83a1c33b8e5ff48f5087273f04efa83b247d6a2d"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "02d2b36900396c9282fa14628566582f206a5dd0bcc8d5e892611806cafb0301f0"), + 33); + hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, + sizeof(str)); + ck_assert_str_eq(str, + "xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz" + "7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc"); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, + &node2, NULL); + ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); + ck_assert_str_eq(str, + "xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJ" + "bZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL"); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, + &node2, NULL); + ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memzero(&node3.private_key, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); + + // [Chain m/0/2147483647'/1/2147483646'/2] + fingerprint = hdnode_fingerprint(&node); + r = hdnode_private_ckd(&node, 2); + ck_assert_int_eq(r, 1); + ck_assert_int_eq(fingerprint, 0x31a507b8); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "9452b549be8cea3ecb7a84bec10dcfd94afe4d129ebfd3b3cb58eedf394ed271"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "bb7d39bdb83ecf58f2fd82b6d918341cbef428661ef01ab97c28a4842125ac23"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "024d902e1a2fc7a8755ab5b694c575fce742c48d9ff192e63df5193e4c7afe1f9c"), + 33); + hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, + sizeof(str)); + ck_assert_str_eq(str, + "xprvA2nrNbFZABcdryreWet9Ea4LvTJcGsqrMzxHx98MMrotbir7yrKCEXw" + "7nadnHM8Dq38EGfSh6dqA9QWTyefMLEcBYJUuekgW4BYPJcr9E7j"); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, + &node2, NULL); + ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); + ck_assert_str_eq(str, + "xpub6FnCn6nSzZAw5Tw7cgR9bi15UV96gLZhjDstkXXxvCLsUXBGXPdSnLF" + "bdpq8p9HmGsApME5hQTZ3emM2rnY5agb9rXpVGyy3bdW6EEgAtqt"); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, + &node2, NULL); + ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memzero(&node3.private_key, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); + + // init m + hdnode_from_seed( + fromhex( + "fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c" + "999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), + 64, SECP256K1_NAME, &node); + + // test public derivation + // [Chain m/0] + fingerprint = hdnode_fingerprint(&node); + r = hdnode_public_ckd(&node, 0); + ck_assert_int_eq(r, 1); + ck_assert_int_eq(fingerprint, 0xbd16bee5); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "f0909affaa7ee7abe5dd4e100598d4dc53cd709d5a5c2cac40e7412f232f7c9c"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "0000000000000000000000000000000000000000000000000000000000000000"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "02fc9e5af0ac8d9b3cecfe2a888e2117ba3d089d8585886c9c826b6b22a98d12ea"), + 33); } END_TEST -// test vector 3 from https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#test-vector-3 -START_TEST(test_bip32_vector_3) -{ - HDNode node, node2, node3; - uint32_t fingerprint; - char str[112]; - int r; - - // init m - hdnode_from_seed(fromhex("4b381541583be4423346c643850da4b320e46a87ae3d2a4e6da11eba819cd4acba45d239319ac14f863b8d5ab5a0d0c64d2e8a1e7d1457df2e5a3c51c73235be"), 64, SECP256K1_NAME, &node); - - // [Chain m] - fingerprint = 0; - ck_assert_int_eq(fingerprint, 0x00000000); - hdnode_fill_public_key(&node); - hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, sizeof(str)); - ck_assert_str_eq(str, "xprv9s21ZrQH143K25QhxbucbDDuQ4naNntJRi4KUfWT7xo4EKsHt2QJDu7KXp1A3u7Bi1j8ph3EGsZ9Xvz9dGuVrtHHs7pXeTzjuxBrCmmhgC6"); - r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); - ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); - ck_assert_str_eq(str, "xpub661MyMwAqRbcEZVB4dScxMAdx6d4nFc9nvyvH3v4gJL378CSRZiYmhRoP7mBy6gSPSCYk6SzXPTf3ND1cZAceL7SfJ1Z3GC8vBgp2epUt13"); - r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - memcpy(&node3, &node, sizeof(HDNode)); - memzero(&node3.private_key, 32); - ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); - - // [Chain m/0'] - fingerprint = hdnode_fingerprint(&node); - r = hdnode_private_ckd_prime(&node, 0); - ck_assert_int_eq(r, 1); - hdnode_fill_public_key(&node); - hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, sizeof(str)); - ck_assert_str_eq(str, "xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L"); - r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); - ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); - ck_assert_str_eq(str, "xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y"); - r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - memcpy(&node3, &node, sizeof(HDNode)); - memzero(&node3.private_key, 32); - ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); +// test vector 3 from +// https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#test-vector-3 +START_TEST(test_bip32_vector_3) { + HDNode node, node2, node3; + uint32_t fingerprint; + char str[112]; + int r; + + // init m + hdnode_from_seed( + fromhex( + "4b381541583be4423346c643850da4b320e46a87ae3d2a4e6da11eba819cd4acba45" + "d239319ac14f863b8d5ab5a0d0c64d2e8a1e7d1457df2e5a3c51c73235be"), + 64, SECP256K1_NAME, &node); + + // [Chain m] + fingerprint = 0; + ck_assert_int_eq(fingerprint, 0x00000000); + hdnode_fill_public_key(&node); + hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, + sizeof(str)); + ck_assert_str_eq(str, + "xprv9s21ZrQH143K25QhxbucbDDuQ4naNntJRi4KUfWT7xo4EKsHt2QJDu7" + "KXp1A3u7Bi1j8ph3EGsZ9Xvz9dGuVrtHHs7pXeTzjuxBrCmmhgC6"); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, + &node2, NULL); + ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); + ck_assert_str_eq(str, + "xpub661MyMwAqRbcEZVB4dScxMAdx6d4nFc9nvyvH3v4gJL378CSRZiYmhR" + "oP7mBy6gSPSCYk6SzXPTf3ND1cZAceL7SfJ1Z3GC8vBgp2epUt13"); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, + &node2, NULL); + ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memzero(&node3.private_key, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); + + // [Chain m/0'] + fingerprint = hdnode_fingerprint(&node); + r = hdnode_private_ckd_prime(&node, 0); + ck_assert_int_eq(r, 1); + hdnode_fill_public_key(&node); + hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, + sizeof(str)); + ck_assert_str_eq(str, + "xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu" + "2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L"); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, + &node2, NULL); + ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); + ck_assert_str_eq(str, + "xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrAD" + "WgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y"); + r = hdnode_deserialize(str, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, + &node2, NULL); + ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memzero(&node3.private_key, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); } END_TEST -START_TEST(test_bip32_compare) -{ - HDNode node1, node2, node3; - int i, r; - hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, SECP256K1_NAME, &node1); - hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, SECP256K1_NAME, &node2); - hdnode_fill_public_key(&node2); - for (i = 0; i < 100; i++) { - memcpy(&node3, &node1, sizeof(HDNode)); - hdnode_fill_public_key(&node3); - r = hdnode_private_ckd(&node1, i); ck_assert_int_eq(r, 1); - r = hdnode_public_ckd(&node2, i); ck_assert_int_eq(r, 1); - r = hdnode_public_ckd(&node3, i); ck_assert_int_eq(r, 1); - ck_assert_int_eq(node1.depth, node2.depth); - ck_assert_int_eq(node1.depth, node3.depth); - ck_assert_int_eq(node1.child_num, node2.child_num); - ck_assert_int_eq(node1.child_num, node3.child_num); - ck_assert_mem_eq(node1.chain_code, node2.chain_code, 32); - ck_assert_mem_eq(node1.chain_code, node3.chain_code, 32); - ck_assert_mem_eq(node2.private_key, fromhex("0000000000000000000000000000000000000000000000000000000000000000"), 32); - ck_assert_mem_eq(node3.private_key, fromhex("0000000000000000000000000000000000000000000000000000000000000000"), 32); - hdnode_fill_public_key(&node1); - ck_assert_mem_eq(node1.public_key, node2.public_key, 33); - ck_assert_mem_eq(node1.public_key, node3.public_key, 33); - } +START_TEST(test_bip32_compare) { + HDNode node1, node2, node3; + int i, r; + hdnode_from_seed( + fromhex( + "301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788" + "f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), + 64, SECP256K1_NAME, &node1); + hdnode_from_seed( + fromhex( + "301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788" + "f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), + 64, SECP256K1_NAME, &node2); + hdnode_fill_public_key(&node2); + for (i = 0; i < 100; i++) { + memcpy(&node3, &node1, sizeof(HDNode)); + hdnode_fill_public_key(&node3); + r = hdnode_private_ckd(&node1, i); + ck_assert_int_eq(r, 1); + r = hdnode_public_ckd(&node2, i); + ck_assert_int_eq(r, 1); + r = hdnode_public_ckd(&node3, i); + ck_assert_int_eq(r, 1); + ck_assert_int_eq(node1.depth, node2.depth); + ck_assert_int_eq(node1.depth, node3.depth); + ck_assert_int_eq(node1.child_num, node2.child_num); + ck_assert_int_eq(node1.child_num, node3.child_num); + ck_assert_mem_eq(node1.chain_code, node2.chain_code, 32); + ck_assert_mem_eq(node1.chain_code, node3.chain_code, 32); + ck_assert_mem_eq( + node2.private_key, + fromhex( + "0000000000000000000000000000000000000000000000000000000000000000"), + 32); + ck_assert_mem_eq( + node3.private_key, + fromhex( + "0000000000000000000000000000000000000000000000000000000000000000"), + 32); + hdnode_fill_public_key(&node1); + ck_assert_mem_eq(node1.public_key, node2.public_key, 33); + ck_assert_mem_eq(node1.public_key, node3.public_key, 33); + } } END_TEST -START_TEST(test_bip32_optimized) -{ - HDNode root; - hdnode_from_seed((uint8_t *)"NothingToSeeHere", 16, SECP256K1_NAME, &root); - hdnode_fill_public_key(&root); - - curve_point pub; - ecdsa_read_pubkey(&secp256k1, root.public_key, &pub); - - HDNode node; - char addr1[MAX_ADDR_SIZE], addr2[MAX_ADDR_SIZE]; - - for (int i = 0; i < 40; i++) { - // unoptimized - memcpy(&node, &root, sizeof(HDNode)); - hdnode_public_ckd(&node, i); - hdnode_fill_public_key(&node); - ecdsa_get_address(node.public_key, 0, HASHER_SHA2_RIPEMD, HASHER_SHA2D, addr1, sizeof(addr1)); - // optimized - hdnode_public_ckd_address_optimized(&pub, root.chain_code, i, 0, HASHER_SHA2_RIPEMD, HASHER_SHA2D, addr2, sizeof(addr2), 0); - // check - ck_assert_str_eq(addr1, addr2); - } +START_TEST(test_bip32_optimized) { + HDNode root; + hdnode_from_seed((uint8_t *)"NothingToSeeHere", 16, SECP256K1_NAME, &root); + hdnode_fill_public_key(&root); + + curve_point pub; + ecdsa_read_pubkey(&secp256k1, root.public_key, &pub); + + HDNode node; + char addr1[MAX_ADDR_SIZE], addr2[MAX_ADDR_SIZE]; + + for (int i = 0; i < 40; i++) { + // unoptimized + memcpy(&node, &root, sizeof(HDNode)); + hdnode_public_ckd(&node, i); + hdnode_fill_public_key(&node); + ecdsa_get_address(node.public_key, 0, HASHER_SHA2_RIPEMD, HASHER_SHA2D, + addr1, sizeof(addr1)); + // optimized + hdnode_public_ckd_address_optimized(&pub, root.chain_code, i, 0, + HASHER_SHA2_RIPEMD, HASHER_SHA2D, addr2, + sizeof(addr2), 0); + // check + ck_assert_str_eq(addr1, addr2); + } } END_TEST -START_TEST(test_bip32_cache_1) -{ - HDNode node1, node2; - int i, r; - - // test 1 .. 8 - hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, SECP256K1_NAME, &node1); - hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, SECP256K1_NAME, &node2); - - uint32_t ii[] = {0x80000001, 0x80000002, 0x80000003, 0x80000004, 0x80000005, 0x80000006, 0x80000007, 0x80000008}; - - for (i = 0; i < 8; i++) { - r = hdnode_private_ckd(&node1, ii[i]); ck_assert_int_eq(r, 1); - } - r = hdnode_private_ckd_cached(&node2, ii, 8, NULL); ck_assert_int_eq(r, 1); - ck_assert_mem_eq(&node1, &node2, sizeof(HDNode)); - - hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, SECP256K1_NAME, &node1); - hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, SECP256K1_NAME, &node2); - - // test 1 .. 7, 20 - ii[7] = 20; - for (i = 0; i < 8; i++) { - r = hdnode_private_ckd(&node1, ii[i]); ck_assert_int_eq(r, 1); - } - r = hdnode_private_ckd_cached(&node2, ii, 8, NULL); ck_assert_int_eq(r, 1); - ck_assert_mem_eq(&node1, &node2, sizeof(HDNode)); - - // test different root node - hdnode_from_seed(fromhex("000000002ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, SECP256K1_NAME, &node1); - hdnode_from_seed(fromhex("000000002ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, SECP256K1_NAME, &node2); - - for (i = 0; i < 8; i++) { - r = hdnode_private_ckd(&node1, ii[i]); ck_assert_int_eq(r, 1); - } - r = hdnode_private_ckd_cached(&node2, ii, 8, NULL); ck_assert_int_eq(r, 1); - ck_assert_mem_eq(&node1, &node2, sizeof(HDNode)); +START_TEST(test_bip32_cache_1) { + HDNode node1, node2; + int i, r; + + // test 1 .. 8 + hdnode_from_seed( + fromhex( + "301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788" + "f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), + 64, SECP256K1_NAME, &node1); + hdnode_from_seed( + fromhex( + "301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788" + "f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), + 64, SECP256K1_NAME, &node2); + + uint32_t ii[] = {0x80000001, 0x80000002, 0x80000003, 0x80000004, + 0x80000005, 0x80000006, 0x80000007, 0x80000008}; + + for (i = 0; i < 8; i++) { + r = hdnode_private_ckd(&node1, ii[i]); + ck_assert_int_eq(r, 1); + } + r = hdnode_private_ckd_cached(&node2, ii, 8, NULL); + ck_assert_int_eq(r, 1); + ck_assert_mem_eq(&node1, &node2, sizeof(HDNode)); + + hdnode_from_seed( + fromhex( + "301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788" + "f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), + 64, SECP256K1_NAME, &node1); + hdnode_from_seed( + fromhex( + "301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788" + "f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), + 64, SECP256K1_NAME, &node2); + + // test 1 .. 7, 20 + ii[7] = 20; + for (i = 0; i < 8; i++) { + r = hdnode_private_ckd(&node1, ii[i]); + ck_assert_int_eq(r, 1); + } + r = hdnode_private_ckd_cached(&node2, ii, 8, NULL); + ck_assert_int_eq(r, 1); + ck_assert_mem_eq(&node1, &node2, sizeof(HDNode)); + + // test different root node + hdnode_from_seed( + fromhex( + "000000002ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788" + "f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), + 64, SECP256K1_NAME, &node1); + hdnode_from_seed( + fromhex( + "000000002ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788" + "f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), + 64, SECP256K1_NAME, &node2); + + for (i = 0; i < 8; i++) { + r = hdnode_private_ckd(&node1, ii[i]); + ck_assert_int_eq(r, 1); + } + r = hdnode_private_ckd_cached(&node2, ii, 8, NULL); + ck_assert_int_eq(r, 1); + ck_assert_mem_eq(&node1, &node2, sizeof(HDNode)); } END_TEST -START_TEST(test_bip32_cache_2) -{ - HDNode nodea[9], nodeb[9]; - int i, j, r; - - for (j = 0; j < 9; j++) { - hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, SECP256K1_NAME, &(nodea[j])); - hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, SECP256K1_NAME, &(nodeb[j])); - } - - uint32_t ii[] = {0x80000001, 0x80000002, 0x80000003, 0x80000004, 0x80000005, 0x80000006, 0x80000007, 0x80000008}; - for (j = 0; j < 9; j++) { - // non cached - for (i = 1; i <= j; i++) { - r = hdnode_private_ckd(&(nodea[j]), ii[i - 1]); ck_assert_int_eq(r, 1); - } - // cached - r = hdnode_private_ckd_cached(&(nodeb[j]), ii, j, NULL); ck_assert_int_eq(r, 1); - } - - ck_assert_mem_eq(&(nodea[0]), &(nodeb[0]), sizeof(HDNode)); - ck_assert_mem_eq(&(nodea[1]), &(nodeb[1]), sizeof(HDNode)); - ck_assert_mem_eq(&(nodea[2]), &(nodeb[2]), sizeof(HDNode)); - ck_assert_mem_eq(&(nodea[3]), &(nodeb[3]), sizeof(HDNode)); - ck_assert_mem_eq(&(nodea[4]), &(nodeb[4]), sizeof(HDNode)); - ck_assert_mem_eq(&(nodea[5]), &(nodeb[5]), sizeof(HDNode)); - ck_assert_mem_eq(&(nodea[6]), &(nodeb[6]), sizeof(HDNode)); - ck_assert_mem_eq(&(nodea[7]), &(nodeb[7]), sizeof(HDNode)); - ck_assert_mem_eq(&(nodea[8]), &(nodeb[8]), sizeof(HDNode)); +START_TEST(test_bip32_cache_2) { + HDNode nodea[9], nodeb[9]; + int i, j, r; + + for (j = 0; j < 9; j++) { + hdnode_from_seed( + fromhex( + "301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d627" + "88f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), + 64, SECP256K1_NAME, &(nodea[j])); + hdnode_from_seed( + fromhex( + "301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d627" + "88f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), + 64, SECP256K1_NAME, &(nodeb[j])); + } + + uint32_t ii[] = {0x80000001, 0x80000002, 0x80000003, 0x80000004, + 0x80000005, 0x80000006, 0x80000007, 0x80000008}; + for (j = 0; j < 9; j++) { + // non cached + for (i = 1; i <= j; i++) { + r = hdnode_private_ckd(&(nodea[j]), ii[i - 1]); + ck_assert_int_eq(r, 1); + } + // cached + r = hdnode_private_ckd_cached(&(nodeb[j]), ii, j, NULL); + ck_assert_int_eq(r, 1); + } + + ck_assert_mem_eq(&(nodea[0]), &(nodeb[0]), sizeof(HDNode)); + ck_assert_mem_eq(&(nodea[1]), &(nodeb[1]), sizeof(HDNode)); + ck_assert_mem_eq(&(nodea[2]), &(nodeb[2]), sizeof(HDNode)); + ck_assert_mem_eq(&(nodea[3]), &(nodeb[3]), sizeof(HDNode)); + ck_assert_mem_eq(&(nodea[4]), &(nodeb[4]), sizeof(HDNode)); + ck_assert_mem_eq(&(nodea[5]), &(nodeb[5]), sizeof(HDNode)); + ck_assert_mem_eq(&(nodea[6]), &(nodeb[6]), sizeof(HDNode)); + ck_assert_mem_eq(&(nodea[7]), &(nodeb[7]), sizeof(HDNode)); + ck_assert_mem_eq(&(nodea[8]), &(nodeb[8]), sizeof(HDNode)); } END_TEST -START_TEST(test_bip32_nist_seed) -{ - HDNode node; - - // init m - hdnode_from_seed(fromhex("a7305bc8df8d0951f0cb224c0e95d7707cbdf2c6ce7e8d481fec69c7ff5e9446"), 32, NIST256P1_NAME, &node); - - // [Chain m] - ck_assert_mem_eq(node.private_key, fromhex("3b8c18469a4634517d6d0b65448f8e6c62091b45540a1743c5846be55d47d88f"), 32); - ck_assert_mem_eq(node.chain_code, fromhex("7762f9729fed06121fd13f326884c82f59aa95c57ac492ce8c9654e60efd130c"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key, fromhex("0383619fadcde31063d8c5cb00dbfe1713f3e6fa169d8541a798752a1c1ca0cb20"), 33); - - // init m - hdnode_from_seed(fromhex("aa305bc8df8d0951f0cb29ad4568d7707cbdf2c6ce7e8d481fec69c7ff5e9446"), 32, NIST256P1_NAME, &node); - - // [Chain m] - ck_assert_mem_eq(node.chain_code, fromhex("a81d21f36f987fa0be3b065301bfb6aa9deefbf3dfef6744c37b9a4abc3c68f1"), 32); - ck_assert_mem_eq(node.private_key, fromhex("0e49dc46ce1d8c29d9b80a05e40f5d0cd68cbf02ae98572186f5343be18084bf"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key, fromhex("03aaa4c89acd9a98935330773d3dae55122f3591bac4a40942681768de8df6ba63"), 33); +START_TEST(test_bip32_nist_seed) { + HDNode node; + + // init m + hdnode_from_seed( + fromhex( + "a7305bc8df8d0951f0cb224c0e95d7707cbdf2c6ce7e8d481fec69c7ff5e9446"), + 32, NIST256P1_NAME, &node); + + // [Chain m] + ck_assert_mem_eq( + node.private_key, + fromhex( + "3b8c18469a4634517d6d0b65448f8e6c62091b45540a1743c5846be55d47d88f"), + 32); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "7762f9729fed06121fd13f326884c82f59aa95c57ac492ce8c9654e60efd130c"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "0383619fadcde31063d8c5cb00dbfe1713f3e6fa169d8541a798752a1c1ca0cb20"), + 33); + + // init m + hdnode_from_seed( + fromhex( + "aa305bc8df8d0951f0cb29ad4568d7707cbdf2c6ce7e8d481fec69c7ff5e9446"), + 32, NIST256P1_NAME, &node); + + // [Chain m] + ck_assert_mem_eq( + node.chain_code, + fromhex( + "a81d21f36f987fa0be3b065301bfb6aa9deefbf3dfef6744c37b9a4abc3c68f1"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "0e49dc46ce1d8c29d9b80a05e40f5d0cd68cbf02ae98572186f5343be18084bf"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "03aaa4c89acd9a98935330773d3dae55122f3591bac4a40942681768de8df6ba63"), + 33); } END_TEST -START_TEST(test_bip32_nist_vector_1) -{ - HDNode node; - uint32_t fingerprint; - - // init m - hdnode_from_seed(fromhex("000102030405060708090a0b0c0d0e0f"), 16, NIST256P1_NAME, &node); - - // [Chain m] - fingerprint = 0; - ck_assert_int_eq(fingerprint, 0x00000000); - ck_assert_mem_eq(node.chain_code, fromhex("beeb672fe4621673f722f38529c07392fecaa61015c80c34f29ce8b41b3cb6ea"), 32); - ck_assert_mem_eq(node.private_key, fromhex("612091aaa12e22dd2abef664f8a01a82cae99ad7441b7ef8110424915c268bc2"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key, fromhex("0266874dc6ade47b3ecd096745ca09bcd29638dd52c2c12117b11ed3e458cfa9e8"), 33); - - // [Chain m/0'] - fingerprint = hdnode_fingerprint(&node); - hdnode_private_ckd_prime(&node, 0); - ck_assert_int_eq(fingerprint, 0xbe6105b5); - ck_assert_mem_eq(node.chain_code, fromhex("3460cea53e6a6bb5fb391eeef3237ffd8724bf0a40e94943c98b83825342ee11"), 32); - ck_assert_mem_eq(node.private_key, fromhex("6939694369114c67917a182c59ddb8cafc3004e63ca5d3b84403ba8613debc0c"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key, fromhex("0384610f5ecffe8fda089363a41f56a5c7ffc1d81b59a612d0d649b2d22355590c"), 33); - - // [Chain m/0'/1] - fingerprint = hdnode_fingerprint(&node); - hdnode_private_ckd(&node, 1); - ck_assert_int_eq(fingerprint, 0x9b02312f); - ck_assert_mem_eq(node.chain_code, fromhex("4187afff1aafa8445010097fb99d23aee9f599450c7bd140b6826ac22ba21d0c"), 32); - ck_assert_mem_eq(node.private_key, fromhex("284e9d38d07d21e4e281b645089a94f4cf5a5a81369acf151a1c3a57f18b2129"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key, fromhex("03526c63f8d0b4bbbf9c80df553fe66742df4676b241dabefdef67733e070f6844"), 33); - - // [Chain m/0'/1/2'] - fingerprint = hdnode_fingerprint(&node); - hdnode_private_ckd_prime(&node, 2); - ck_assert_int_eq(fingerprint, 0xb98005c1); - ck_assert_mem_eq(node.chain_code, fromhex("98c7514f562e64e74170cc3cf304ee1ce54d6b6da4f880f313e8204c2a185318"), 32); - ck_assert_mem_eq(node.private_key, fromhex("694596e8a54f252c960eb771a3c41e7e32496d03b954aeb90f61635b8e092aa7"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key, fromhex("0359cf160040778a4b14c5f4d7b76e327ccc8c4a6086dd9451b7482b5a4972dda0"), 33); - - // [Chain m/0'/1/2'/2] - fingerprint = hdnode_fingerprint(&node); - hdnode_private_ckd(&node, 2); - ck_assert_int_eq(fingerprint, 0x0e9f3274); - ck_assert_mem_eq(node.chain_code, fromhex("ba96f776a5c3907d7fd48bde5620ee374d4acfd540378476019eab70790c63a0"), 32); - ck_assert_mem_eq(node.private_key, fromhex("5996c37fd3dd2679039b23ed6f70b506c6b56b3cb5e424681fb0fa64caf82aaa"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key, fromhex("029f871f4cb9e1c97f9f4de9ccd0d4a2f2a171110c61178f84430062230833ff20"), 33); - - // [Chain m/0'/1/2'/2/1000000000] - fingerprint = hdnode_fingerprint(&node); - hdnode_private_ckd(&node, 1000000000); - ck_assert_int_eq(fingerprint, 0x8b2b5c4b); - ck_assert_mem_eq(node.chain_code, fromhex("b9b7b82d326bb9cb5b5b121066feea4eb93d5241103c9e7a18aad40f1dde8059"), 32); - ck_assert_mem_eq(node.private_key, fromhex("21c4f269ef0a5fd1badf47eeacebeeaa3de22eb8e5b0adcd0f27dd99d34d0119"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key, fromhex("02216cd26d31147f72427a453c443ed2cde8a1e53c9cc44e5ddf739725413fe3f4"), 33); +START_TEST(test_bip32_nist_vector_1) { + HDNode node; + uint32_t fingerprint; + + // init m + hdnode_from_seed(fromhex("000102030405060708090a0b0c0d0e0f"), 16, + NIST256P1_NAME, &node); + + // [Chain m] + fingerprint = 0; + ck_assert_int_eq(fingerprint, 0x00000000); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "beeb672fe4621673f722f38529c07392fecaa61015c80c34f29ce8b41b3cb6ea"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "612091aaa12e22dd2abef664f8a01a82cae99ad7441b7ef8110424915c268bc2"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "0266874dc6ade47b3ecd096745ca09bcd29638dd52c2c12117b11ed3e458cfa9e8"), + 33); + + // [Chain m/0'] + fingerprint = hdnode_fingerprint(&node); + hdnode_private_ckd_prime(&node, 0); + ck_assert_int_eq(fingerprint, 0xbe6105b5); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "3460cea53e6a6bb5fb391eeef3237ffd8724bf0a40e94943c98b83825342ee11"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "6939694369114c67917a182c59ddb8cafc3004e63ca5d3b84403ba8613debc0c"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "0384610f5ecffe8fda089363a41f56a5c7ffc1d81b59a612d0d649b2d22355590c"), + 33); + + // [Chain m/0'/1] + fingerprint = hdnode_fingerprint(&node); + hdnode_private_ckd(&node, 1); + ck_assert_int_eq(fingerprint, 0x9b02312f); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "4187afff1aafa8445010097fb99d23aee9f599450c7bd140b6826ac22ba21d0c"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "284e9d38d07d21e4e281b645089a94f4cf5a5a81369acf151a1c3a57f18b2129"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "03526c63f8d0b4bbbf9c80df553fe66742df4676b241dabefdef67733e070f6844"), + 33); + + // [Chain m/0'/1/2'] + fingerprint = hdnode_fingerprint(&node); + hdnode_private_ckd_prime(&node, 2); + ck_assert_int_eq(fingerprint, 0xb98005c1); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "98c7514f562e64e74170cc3cf304ee1ce54d6b6da4f880f313e8204c2a185318"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "694596e8a54f252c960eb771a3c41e7e32496d03b954aeb90f61635b8e092aa7"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "0359cf160040778a4b14c5f4d7b76e327ccc8c4a6086dd9451b7482b5a4972dda0"), + 33); + + // [Chain m/0'/1/2'/2] + fingerprint = hdnode_fingerprint(&node); + hdnode_private_ckd(&node, 2); + ck_assert_int_eq(fingerprint, 0x0e9f3274); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "ba96f776a5c3907d7fd48bde5620ee374d4acfd540378476019eab70790c63a0"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "5996c37fd3dd2679039b23ed6f70b506c6b56b3cb5e424681fb0fa64caf82aaa"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "029f871f4cb9e1c97f9f4de9ccd0d4a2f2a171110c61178f84430062230833ff20"), + 33); + + // [Chain m/0'/1/2'/2/1000000000] + fingerprint = hdnode_fingerprint(&node); + hdnode_private_ckd(&node, 1000000000); + ck_assert_int_eq(fingerprint, 0x8b2b5c4b); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "b9b7b82d326bb9cb5b5b121066feea4eb93d5241103c9e7a18aad40f1dde8059"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "21c4f269ef0a5fd1badf47eeacebeeaa3de22eb8e5b0adcd0f27dd99d34d0119"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "02216cd26d31147f72427a453c443ed2cde8a1e53c9cc44e5ddf739725413fe3f4"), + 33); } END_TEST -START_TEST(test_bip32_nist_vector_2) -{ - HDNode node; - uint32_t fingerprint; - int r; - - // init m - hdnode_from_seed(fromhex("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), 64, NIST256P1_NAME, &node); - - // [Chain m] - fingerprint = 0; - ck_assert_int_eq(fingerprint, 0x00000000); - ck_assert_mem_eq(node.chain_code, fromhex("96cd4465a9644e31528eda3592aa35eb39a9527769ce1855beafc1b81055e75d"), 32); - ck_assert_mem_eq(node.private_key, fromhex("eaa31c2e46ca2962227cf21d73a7ef0ce8b31c756897521eb6c7b39796633357"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key, fromhex("02c9e16154474b3ed5b38218bb0463e008f89ee03e62d22fdcc8014beab25b48fa"), 33); - - // [Chain m/0] - fingerprint = hdnode_fingerprint(&node); - r = hdnode_private_ckd(&node, 0); - ck_assert_int_eq(r, 1); - ck_assert_int_eq(fingerprint, 0x607f628f); - ck_assert_mem_eq(node.chain_code, fromhex("84e9c258bb8557a40e0d041115b376dd55eda99c0042ce29e81ebe4efed9b86a"), 32); - ck_assert_mem_eq(node.private_key, fromhex("d7d065f63a62624888500cdb4f88b6d59c2927fee9e6d0cdff9cad555884df6e"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key, fromhex("039b6df4bece7b6c81e2adfeea4bcf5c8c8a6e40ea7ffa3cf6e8494c61a1fc82cc"), 33); - - // [Chain m/0/2147483647'] - fingerprint = hdnode_fingerprint(&node); - r = hdnode_private_ckd_prime(&node, 2147483647); - ck_assert_int_eq(r, 1); - ck_assert_int_eq(fingerprint, 0x946d2a54); - ck_assert_mem_eq(node.chain_code, fromhex("f235b2bc5c04606ca9c30027a84f353acf4e4683edbd11f635d0dcc1cd106ea6"), 32); - ck_assert_mem_eq(node.private_key, fromhex("96d2ec9316746a75e7793684ed01e3d51194d81a42a3276858a5b7376d4b94b9"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key, fromhex("02f89c5deb1cae4fedc9905f98ae6cbf6cbab120d8cb85d5bd9a91a72f4c068c76"), 33); - - // [Chain m/0/2147483647'/1] - fingerprint = hdnode_fingerprint(&node); - r = hdnode_private_ckd(&node, 1); - ck_assert_int_eq(r, 1); - ck_assert_int_eq(fingerprint, 0x218182d8); - ck_assert_mem_eq(node.chain_code, fromhex("7c0b833106235e452eba79d2bdd58d4086e663bc8cc55e9773d2b5eeda313f3b"), 32); - ck_assert_mem_eq(node.private_key, fromhex("974f9096ea6873a915910e82b29d7c338542ccde39d2064d1cc228f371542bbc"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key, fromhex("03abe0ad54c97c1d654c1852dfdc32d6d3e487e75fa16f0fd6304b9ceae4220c64"), 33); - - // [Chain m/0/2147483647'/1/2147483646'] - fingerprint = hdnode_fingerprint(&node); - r = hdnode_private_ckd_prime(&node, 2147483646); - ck_assert_int_eq(r, 1); - ck_assert_int_eq(fingerprint, 0x931223e4); - ck_assert_mem_eq(node.chain_code, fromhex("5794e616eadaf33413aa309318a26ee0fd5163b70466de7a4512fd4b1a5c9e6a"), 32); - ck_assert_mem_eq(node.private_key, fromhex("da29649bbfaff095cd43819eda9a7be74236539a29094cd8336b07ed8d4eff63"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key, fromhex("03cb8cb067d248691808cd6b5a5a06b48e34ebac4d965cba33e6dc46fe13d9b933"), 33); - - // [Chain m/0/2147483647'/1/2147483646'/2] - fingerprint = hdnode_fingerprint(&node); - r = hdnode_private_ckd(&node, 2); - ck_assert_int_eq(r, 1); - ck_assert_int_eq(fingerprint, 0x956c4629); - ck_assert_mem_eq(node.chain_code, fromhex("3bfb29ee8ac4484f09db09c2079b520ea5616df7820f071a20320366fbe226a7"), 32); - ck_assert_mem_eq(node.private_key, fromhex("bb0a77ba01cc31d77205d51d08bd313b979a71ef4de9b062f8958297e746bd67"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key, fromhex("020ee02e18967237cf62672983b253ee62fa4dd431f8243bfeccdf39dbe181387f"), 33); - - // init m - hdnode_from_seed(fromhex("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), 64, NIST256P1_NAME, &node); - - // test public derivation - // [Chain m/0] - fingerprint = hdnode_fingerprint(&node); - r = hdnode_public_ckd(&node, 0); - ck_assert_int_eq(r, 1); - ck_assert_int_eq(fingerprint, 0x607f628f); - ck_assert_mem_eq(node.chain_code, fromhex("84e9c258bb8557a40e0d041115b376dd55eda99c0042ce29e81ebe4efed9b86a"), 32); - ck_assert_mem_eq(node.private_key, fromhex("0000000000000000000000000000000000000000000000000000000000000000"), 32); - ck_assert_mem_eq(node.public_key, fromhex("039b6df4bece7b6c81e2adfeea4bcf5c8c8a6e40ea7ffa3cf6e8494c61a1fc82cc"), 33); +START_TEST(test_bip32_nist_vector_2) { + HDNode node; + uint32_t fingerprint; + int r; + + // init m + hdnode_from_seed( + fromhex( + "fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c" + "999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), + 64, NIST256P1_NAME, &node); + + // [Chain m] + fingerprint = 0; + ck_assert_int_eq(fingerprint, 0x00000000); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "96cd4465a9644e31528eda3592aa35eb39a9527769ce1855beafc1b81055e75d"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "eaa31c2e46ca2962227cf21d73a7ef0ce8b31c756897521eb6c7b39796633357"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "02c9e16154474b3ed5b38218bb0463e008f89ee03e62d22fdcc8014beab25b48fa"), + 33); + + // [Chain m/0] + fingerprint = hdnode_fingerprint(&node); + r = hdnode_private_ckd(&node, 0); + ck_assert_int_eq(r, 1); + ck_assert_int_eq(fingerprint, 0x607f628f); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "84e9c258bb8557a40e0d041115b376dd55eda99c0042ce29e81ebe4efed9b86a"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "d7d065f63a62624888500cdb4f88b6d59c2927fee9e6d0cdff9cad555884df6e"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "039b6df4bece7b6c81e2adfeea4bcf5c8c8a6e40ea7ffa3cf6e8494c61a1fc82cc"), + 33); + + // [Chain m/0/2147483647'] + fingerprint = hdnode_fingerprint(&node); + r = hdnode_private_ckd_prime(&node, 2147483647); + ck_assert_int_eq(r, 1); + ck_assert_int_eq(fingerprint, 0x946d2a54); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "f235b2bc5c04606ca9c30027a84f353acf4e4683edbd11f635d0dcc1cd106ea6"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "96d2ec9316746a75e7793684ed01e3d51194d81a42a3276858a5b7376d4b94b9"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "02f89c5deb1cae4fedc9905f98ae6cbf6cbab120d8cb85d5bd9a91a72f4c068c76"), + 33); + + // [Chain m/0/2147483647'/1] + fingerprint = hdnode_fingerprint(&node); + r = hdnode_private_ckd(&node, 1); + ck_assert_int_eq(r, 1); + ck_assert_int_eq(fingerprint, 0x218182d8); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "7c0b833106235e452eba79d2bdd58d4086e663bc8cc55e9773d2b5eeda313f3b"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "974f9096ea6873a915910e82b29d7c338542ccde39d2064d1cc228f371542bbc"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "03abe0ad54c97c1d654c1852dfdc32d6d3e487e75fa16f0fd6304b9ceae4220c64"), + 33); + + // [Chain m/0/2147483647'/1/2147483646'] + fingerprint = hdnode_fingerprint(&node); + r = hdnode_private_ckd_prime(&node, 2147483646); + ck_assert_int_eq(r, 1); + ck_assert_int_eq(fingerprint, 0x931223e4); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "5794e616eadaf33413aa309318a26ee0fd5163b70466de7a4512fd4b1a5c9e6a"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "da29649bbfaff095cd43819eda9a7be74236539a29094cd8336b07ed8d4eff63"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "03cb8cb067d248691808cd6b5a5a06b48e34ebac4d965cba33e6dc46fe13d9b933"), + 33); + + // [Chain m/0/2147483647'/1/2147483646'/2] + fingerprint = hdnode_fingerprint(&node); + r = hdnode_private_ckd(&node, 2); + ck_assert_int_eq(r, 1); + ck_assert_int_eq(fingerprint, 0x956c4629); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "3bfb29ee8ac4484f09db09c2079b520ea5616df7820f071a20320366fbe226a7"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "bb0a77ba01cc31d77205d51d08bd313b979a71ef4de9b062f8958297e746bd67"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "020ee02e18967237cf62672983b253ee62fa4dd431f8243bfeccdf39dbe181387f"), + 33); + + // init m + hdnode_from_seed( + fromhex( + "fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c" + "999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), + 64, NIST256P1_NAME, &node); + + // test public derivation + // [Chain m/0] + fingerprint = hdnode_fingerprint(&node); + r = hdnode_public_ckd(&node, 0); + ck_assert_int_eq(r, 1); + ck_assert_int_eq(fingerprint, 0x607f628f); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "84e9c258bb8557a40e0d041115b376dd55eda99c0042ce29e81ebe4efed9b86a"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "0000000000000000000000000000000000000000000000000000000000000000"), + 32); + ck_assert_mem_eq( + node.public_key, + fromhex( + "039b6df4bece7b6c81e2adfeea4bcf5c8c8a6e40ea7ffa3cf6e8494c61a1fc82cc"), + 33); } END_TEST -START_TEST(test_bip32_nist_compare) -{ - HDNode node1, node2, node3; - int i, r; - hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, NIST256P1_NAME, &node1); - hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, NIST256P1_NAME, &node2); - hdnode_fill_public_key(&node2); - for (i = 0; i < 100; i++) { - memcpy(&node3, &node1, sizeof(HDNode)); - hdnode_fill_public_key(&node3); - r = hdnode_private_ckd(&node1, i); ck_assert_int_eq(r, 1); - r = hdnode_public_ckd(&node2, i); ck_assert_int_eq(r, 1); - r = hdnode_public_ckd(&node3, i); ck_assert_int_eq(r, 1); - ck_assert_int_eq(node1.depth, node2.depth); - ck_assert_int_eq(node1.depth, node3.depth); - ck_assert_int_eq(node1.child_num, node2.child_num); - ck_assert_int_eq(node1.child_num, node3.child_num); - ck_assert_mem_eq(node1.chain_code, node2.chain_code, 32); - ck_assert_mem_eq(node1.chain_code, node3.chain_code, 32); - ck_assert_mem_eq(node2.private_key, fromhex("0000000000000000000000000000000000000000000000000000000000000000"), 32); - ck_assert_mem_eq(node3.private_key, fromhex("0000000000000000000000000000000000000000000000000000000000000000"), 32); - hdnode_fill_public_key(&node1); - ck_assert_mem_eq(node1.public_key, node2.public_key, 33); - ck_assert_mem_eq(node1.public_key, node3.public_key, 33); - } +START_TEST(test_bip32_nist_compare) { + HDNode node1, node2, node3; + int i, r; + hdnode_from_seed( + fromhex( + "301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788" + "f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), + 64, NIST256P1_NAME, &node1); + hdnode_from_seed( + fromhex( + "301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788" + "f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), + 64, NIST256P1_NAME, &node2); + hdnode_fill_public_key(&node2); + for (i = 0; i < 100; i++) { + memcpy(&node3, &node1, sizeof(HDNode)); + hdnode_fill_public_key(&node3); + r = hdnode_private_ckd(&node1, i); + ck_assert_int_eq(r, 1); + r = hdnode_public_ckd(&node2, i); + ck_assert_int_eq(r, 1); + r = hdnode_public_ckd(&node3, i); + ck_assert_int_eq(r, 1); + ck_assert_int_eq(node1.depth, node2.depth); + ck_assert_int_eq(node1.depth, node3.depth); + ck_assert_int_eq(node1.child_num, node2.child_num); + ck_assert_int_eq(node1.child_num, node3.child_num); + ck_assert_mem_eq(node1.chain_code, node2.chain_code, 32); + ck_assert_mem_eq(node1.chain_code, node3.chain_code, 32); + ck_assert_mem_eq( + node2.private_key, + fromhex( + "0000000000000000000000000000000000000000000000000000000000000000"), + 32); + ck_assert_mem_eq( + node3.private_key, + fromhex( + "0000000000000000000000000000000000000000000000000000000000000000"), + 32); + hdnode_fill_public_key(&node1); + ck_assert_mem_eq(node1.public_key, node2.public_key, 33); + ck_assert_mem_eq(node1.public_key, node3.public_key, 33); + } } END_TEST -START_TEST(test_bip32_nist_repeat) -{ - HDNode node, node2; - uint32_t fingerprint; - int r; - - // init m - hdnode_from_seed(fromhex("000102030405060708090a0b0c0d0e0f"), 16, NIST256P1_NAME, &node); - - // [Chain m/28578'] - fingerprint = hdnode_fingerprint(&node); - r = hdnode_private_ckd_prime(&node, 28578); - ck_assert_int_eq(r, 1); - ck_assert_int_eq(fingerprint, 0xbe6105b5); - ck_assert_mem_eq(node.chain_code, fromhex("e94c8ebe30c2250a14713212f6449b20f3329105ea15b652ca5bdfc68f6c65c2"), 32); - ck_assert_mem_eq(node.private_key, fromhex("06f0db126f023755d0b8d86d4591718a5210dd8d024e3e14b6159d63f53aa669"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key, fromhex("02519b5554a4872e8c9c1c847115363051ec43e93400e030ba3c36b52a3e70a5b7"), 33); - - memcpy(&node2, &node, sizeof(HDNode)); - fingerprint = hdnode_fingerprint(&node); - r = hdnode_private_ckd(&node2, 33941); - ck_assert_int_eq(r, 1); - ck_assert_int_eq(fingerprint, 0x3e2b7bc6); - ck_assert_mem_eq(node2.chain_code, fromhex("9e87fe95031f14736774cd82f25fd885065cb7c358c1edf813c72af535e83071"), 32); - ck_assert_mem_eq(node2.private_key, fromhex("092154eed4af83e078ff9b84322015aefe5769e31270f62c3f66c33888335f3a"), 32); - hdnode_fill_public_key(&node2); - ck_assert_mem_eq(node2.public_key, fromhex("0235bfee614c0d5b2cae260000bb1d0d84b270099ad790022c1ae0b2e782efe120"), 33); - - memcpy(&node2, &node, sizeof(HDNode)); - memzero(&node2.private_key, 32); - r = hdnode_public_ckd(&node2, 33941); - ck_assert_int_eq(r, 1); - ck_assert_int_eq(fingerprint, 0x3e2b7bc6); - ck_assert_mem_eq(node2.chain_code, fromhex("9e87fe95031f14736774cd82f25fd885065cb7c358c1edf813c72af535e83071"), 32); - hdnode_fill_public_key(&node2); - ck_assert_mem_eq(node2.public_key, fromhex("0235bfee614c0d5b2cae260000bb1d0d84b270099ad790022c1ae0b2e782efe120"), 33); +START_TEST(test_bip32_nist_repeat) { + HDNode node, node2; + uint32_t fingerprint; + int r; + + // init m + hdnode_from_seed(fromhex("000102030405060708090a0b0c0d0e0f"), 16, + NIST256P1_NAME, &node); + + // [Chain m/28578'] + fingerprint = hdnode_fingerprint(&node); + r = hdnode_private_ckd_prime(&node, 28578); + ck_assert_int_eq(r, 1); + ck_assert_int_eq(fingerprint, 0xbe6105b5); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "e94c8ebe30c2250a14713212f6449b20f3329105ea15b652ca5bdfc68f6c65c2"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "06f0db126f023755d0b8d86d4591718a5210dd8d024e3e14b6159d63f53aa669"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "02519b5554a4872e8c9c1c847115363051ec43e93400e030ba3c36b52a3e70a5b7"), + 33); + + memcpy(&node2, &node, sizeof(HDNode)); + fingerprint = hdnode_fingerprint(&node); + r = hdnode_private_ckd(&node2, 33941); + ck_assert_int_eq(r, 1); + ck_assert_int_eq(fingerprint, 0x3e2b7bc6); + ck_assert_mem_eq( + node2.chain_code, + fromhex( + "9e87fe95031f14736774cd82f25fd885065cb7c358c1edf813c72af535e83071"), + 32); + ck_assert_mem_eq( + node2.private_key, + fromhex( + "092154eed4af83e078ff9b84322015aefe5769e31270f62c3f66c33888335f3a"), + 32); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq( + node2.public_key, + fromhex( + "0235bfee614c0d5b2cae260000bb1d0d84b270099ad790022c1ae0b2e782efe120"), + 33); + + memcpy(&node2, &node, sizeof(HDNode)); + memzero(&node2.private_key, 32); + r = hdnode_public_ckd(&node2, 33941); + ck_assert_int_eq(r, 1); + ck_assert_int_eq(fingerprint, 0x3e2b7bc6); + ck_assert_mem_eq( + node2.chain_code, + fromhex( + "9e87fe95031f14736774cd82f25fd885065cb7c358c1edf813c72af535e83071"), + 32); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq( + node2.public_key, + fromhex( + "0235bfee614c0d5b2cae260000bb1d0d84b270099ad790022c1ae0b2e782efe120"), + 33); } END_TEST // test vector 1 from https://en.bitcoin.it/wiki/BIP_0032_TestVectors -START_TEST(test_bip32_ed25519_vector_1) -{ - HDNode node; - - // init m - hdnode_from_seed(fromhex("000102030405060708090a0b0c0d0e0f"), 16, ED25519_NAME, &node); - - // [Chain m] - ck_assert_mem_eq(node.chain_code, fromhex("90046a93de5380a72b5e45010748567d5ea02bbf6522f979e05c0d8d8ca9fffb"), 32); - ck_assert_mem_eq(node.private_key, fromhex("2b4be7f19ee27bbf30c667b642d5f4aa69fd169872f8fc3059c08ebae2eb19e7"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key, fromhex("01a4b2856bfec510abab89753fac1ac0e1112364e7d250545963f135f2a33188ed"), 33); - - // [Chain m/0'] - hdnode_private_ckd_prime(&node, 0); - ck_assert_mem_eq(node.chain_code, fromhex("8b59aa11380b624e81507a27fedda59fea6d0b779a778918a2fd3590e16e9c69"), 32); - ck_assert_mem_eq(node.private_key, fromhex("68e0fe46dfb67e368c75379acec591dad19df3cde26e63b93a8e704f1dade7a3"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key, fromhex("018c8a13df77a28f3445213a0f432fde644acaa215fc72dcdf300d5efaa85d350c"), 33); - - // [Chain m/0'/1'] - hdnode_private_ckd_prime(&node, 1); - ck_assert_mem_eq(node.chain_code, fromhex("a320425f77d1b5c2505a6b1b27382b37368ee640e3557c315416801243552f14"), 32); - ck_assert_mem_eq(node.private_key, fromhex("b1d0bad404bf35da785a64ca1ac54b2617211d2777696fbffaf208f746ae84f2"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key, fromhex("011932a5270f335bed617d5b935c80aedb1a35bd9fc1e31acafd5372c30f5c1187"), 33); - - // [Chain m/0'/1'/2'] - hdnode_private_ckd_prime(&node, 2); - ck_assert_mem_eq(node.chain_code, fromhex("2e69929e00b5ab250f49c3fb1c12f252de4fed2c1db88387094a0f8c4c9ccd6c"), 32); - ck_assert_mem_eq(node.private_key, fromhex("92a5b23c0b8a99e37d07df3fb9966917f5d06e02ddbd909c7e184371463e9fc9"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key, fromhex("01ae98736566d30ed0e9d2f4486a64bc95740d89c7db33f52121f8ea8f76ff0fc1"), 33); - - // [Chain m/0'/1'/2'/2'] - hdnode_private_ckd_prime(&node, 2); - ck_assert_mem_eq(node.chain_code, fromhex("8f6d87f93d750e0efccda017d662a1b31a266e4a6f5993b15f5c1f07f74dd5cc"), 32); - ck_assert_mem_eq(node.private_key, fromhex("30d1dc7e5fc04c31219ab25a27ae00b50f6fd66622f6e9c913253d6511d1e662"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key, fromhex("018abae2d66361c879b900d204ad2cc4984fa2aa344dd7ddc46007329ac76c429c"), 33); - - // [Chain m/0'/1'/2'/2'/1000000000'] - hdnode_private_ckd_prime(&node, 1000000000); - ck_assert_mem_eq(node.chain_code, fromhex("68789923a0cac2cd5a29172a475fe9e0fb14cd6adb5ad98a3fa70333e7afa230"), 32); - ck_assert_mem_eq(node.private_key, fromhex("8f94d394a8e8fd6b1bc2f3f49f5c47e385281d5c17e65324b0f62483e37e8793"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key, fromhex("013c24da049451555d51a7014a37337aa4e12d41e485abccfa46b47dfb2af54b7a"), 33); +START_TEST(test_bip32_ed25519_vector_1) { + HDNode node; + + // init m + hdnode_from_seed(fromhex("000102030405060708090a0b0c0d0e0f"), 16, + ED25519_NAME, &node); + + // [Chain m] + ck_assert_mem_eq( + node.chain_code, + fromhex( + "90046a93de5380a72b5e45010748567d5ea02bbf6522f979e05c0d8d8ca9fffb"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "2b4be7f19ee27bbf30c667b642d5f4aa69fd169872f8fc3059c08ebae2eb19e7"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "01a4b2856bfec510abab89753fac1ac0e1112364e7d250545963f135f2a33188ed"), + 33); + + // [Chain m/0'] + hdnode_private_ckd_prime(&node, 0); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "8b59aa11380b624e81507a27fedda59fea6d0b779a778918a2fd3590e16e9c69"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "68e0fe46dfb67e368c75379acec591dad19df3cde26e63b93a8e704f1dade7a3"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "018c8a13df77a28f3445213a0f432fde644acaa215fc72dcdf300d5efaa85d350c"), + 33); + + // [Chain m/0'/1'] + hdnode_private_ckd_prime(&node, 1); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "a320425f77d1b5c2505a6b1b27382b37368ee640e3557c315416801243552f14"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "b1d0bad404bf35da785a64ca1ac54b2617211d2777696fbffaf208f746ae84f2"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "011932a5270f335bed617d5b935c80aedb1a35bd9fc1e31acafd5372c30f5c1187"), + 33); + + // [Chain m/0'/1'/2'] + hdnode_private_ckd_prime(&node, 2); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "2e69929e00b5ab250f49c3fb1c12f252de4fed2c1db88387094a0f8c4c9ccd6c"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "92a5b23c0b8a99e37d07df3fb9966917f5d06e02ddbd909c7e184371463e9fc9"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "01ae98736566d30ed0e9d2f4486a64bc95740d89c7db33f52121f8ea8f76ff0fc1"), + 33); + + // [Chain m/0'/1'/2'/2'] + hdnode_private_ckd_prime(&node, 2); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "8f6d87f93d750e0efccda017d662a1b31a266e4a6f5993b15f5c1f07f74dd5cc"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "30d1dc7e5fc04c31219ab25a27ae00b50f6fd66622f6e9c913253d6511d1e662"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "018abae2d66361c879b900d204ad2cc4984fa2aa344dd7ddc46007329ac76c429c"), + 33); + + // [Chain m/0'/1'/2'/2'/1000000000'] + hdnode_private_ckd_prime(&node, 1000000000); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "68789923a0cac2cd5a29172a475fe9e0fb14cd6adb5ad98a3fa70333e7afa230"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "8f94d394a8e8fd6b1bc2f3f49f5c47e385281d5c17e65324b0f62483e37e8793"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "013c24da049451555d51a7014a37337aa4e12d41e485abccfa46b47dfb2af54b7a"), + 33); } END_TEST // test vector 2 from https://en.bitcoin.it/wiki/BIP_0032_TestVectors -START_TEST(test_bip32_ed25519_vector_2) -{ - HDNode node; - int r; - - // init m - hdnode_from_seed(fromhex("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), 64, ED25519_NAME, &node); - - // [Chain m] - ck_assert_mem_eq(node.chain_code, fromhex("ef70a74db9c3a5af931b5fe73ed8e1a53464133654fd55e7a66f8570b8e33c3b"), 32); - ck_assert_mem_eq(node.private_key, fromhex("171cb88b1b3c1db25add599712e36245d75bc65a1a5c9e18d76f9f2b1eab4012"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key, fromhex("018fe9693f8fa62a4305a140b9764c5ee01e455963744fe18204b4fb948249308a"), 33); - - // [Chain m/0'] - r = hdnode_private_ckd_prime(&node, 0); - ck_assert_int_eq(r, 1); - ck_assert_mem_eq(node.chain_code, fromhex("0b78a3226f915c082bf118f83618a618ab6dec793752624cbeb622acb562862d"), 32); - ck_assert_mem_eq(node.private_key, fromhex("1559eb2bbec5790b0c65d8693e4d0875b1747f4970ae8b650486ed7470845635"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key, fromhex("0186fab68dcb57aa196c77c5f264f215a112c22a912c10d123b0d03c3c28ef1037"), 33); - - // [Chain m/0'/2147483647'] - r = hdnode_private_ckd_prime(&node, 2147483647); - ck_assert_int_eq(r, 1); - ck_assert_mem_eq(node.chain_code, fromhex("138f0b2551bcafeca6ff2aa88ba8ed0ed8de070841f0c4ef0165df8181eaad7f"), 32); - ck_assert_mem_eq(node.private_key, fromhex("ea4f5bfe8694d8bb74b7b59404632fd5968b774ed545e810de9c32a4fb4192f4"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key, fromhex("015ba3b9ac6e90e83effcd25ac4e58a1365a9e35a3d3ae5eb07b9e4d90bcf7506d"), 33); - - // [Chain m/0'/2147483647'/1'] - r = hdnode_private_ckd_prime(&node, 1); - ck_assert_int_eq(r, 1); - ck_assert_mem_eq(node.chain_code, fromhex("73bd9fff1cfbde33a1b846c27085f711c0fe2d66fd32e139d3ebc28e5a4a6b90"), 32); - ck_assert_mem_eq(node.private_key, fromhex("3757c7577170179c7868353ada796c839135b3d30554bbb74a4b1e4a5a58505c"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key, fromhex("012e66aa57069c86cc18249aecf5cb5a9cebbfd6fadeab056254763874a9352b45"), 33); - - // [Chain m/0'/2147483647'/1'/2147483646'] - r = hdnode_private_ckd_prime(&node, 2147483646); - ck_assert_int_eq(r, 1); - ck_assert_mem_eq(node.chain_code, fromhex("0902fe8a29f9140480a00ef244bd183e8a13288e4412d8389d140aac1794825a"), 32); - ck_assert_mem_eq(node.private_key, fromhex("5837736c89570de861ebc173b1086da4f505d4adb387c6a1b1342d5e4ac9ec72"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key, fromhex("01e33c0f7d81d843c572275f287498e8d408654fdf0d1e065b84e2e6f157aab09b"), 33); - - // [Chain m/0'/2147483647'/1'/2147483646'/2'] - r = hdnode_private_ckd_prime(&node, 2); - ck_assert_int_eq(r, 1); - ck_assert_mem_eq(node.chain_code, fromhex("5d70af781f3a37b829f0d060924d5e960bdc02e85423494afc0b1a41bbe196d4"), 32); - ck_assert_mem_eq(node.private_key, fromhex("551d333177df541ad876a60ea71f00447931c0a9da16f227c11ea080d7391b8d"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key, fromhex("0147150c75db263559a70d5778bf36abbab30fb061ad69f69ece61a72b0cfa4fc0"), 33); +START_TEST(test_bip32_ed25519_vector_2) { + HDNode node; + int r; + + // init m + hdnode_from_seed( + fromhex( + "fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c" + "999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), + 64, ED25519_NAME, &node); + + // [Chain m] + ck_assert_mem_eq( + node.chain_code, + fromhex( + "ef70a74db9c3a5af931b5fe73ed8e1a53464133654fd55e7a66f8570b8e33c3b"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "171cb88b1b3c1db25add599712e36245d75bc65a1a5c9e18d76f9f2b1eab4012"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "018fe9693f8fa62a4305a140b9764c5ee01e455963744fe18204b4fb948249308a"), + 33); + + // [Chain m/0'] + r = hdnode_private_ckd_prime(&node, 0); + ck_assert_int_eq(r, 1); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "0b78a3226f915c082bf118f83618a618ab6dec793752624cbeb622acb562862d"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "1559eb2bbec5790b0c65d8693e4d0875b1747f4970ae8b650486ed7470845635"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "0186fab68dcb57aa196c77c5f264f215a112c22a912c10d123b0d03c3c28ef1037"), + 33); + + // [Chain m/0'/2147483647'] + r = hdnode_private_ckd_prime(&node, 2147483647); + ck_assert_int_eq(r, 1); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "138f0b2551bcafeca6ff2aa88ba8ed0ed8de070841f0c4ef0165df8181eaad7f"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "ea4f5bfe8694d8bb74b7b59404632fd5968b774ed545e810de9c32a4fb4192f4"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "015ba3b9ac6e90e83effcd25ac4e58a1365a9e35a3d3ae5eb07b9e4d90bcf7506d"), + 33); + + // [Chain m/0'/2147483647'/1'] + r = hdnode_private_ckd_prime(&node, 1); + ck_assert_int_eq(r, 1); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "73bd9fff1cfbde33a1b846c27085f711c0fe2d66fd32e139d3ebc28e5a4a6b90"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "3757c7577170179c7868353ada796c839135b3d30554bbb74a4b1e4a5a58505c"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "012e66aa57069c86cc18249aecf5cb5a9cebbfd6fadeab056254763874a9352b45"), + 33); + + // [Chain m/0'/2147483647'/1'/2147483646'] + r = hdnode_private_ckd_prime(&node, 2147483646); + ck_assert_int_eq(r, 1); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "0902fe8a29f9140480a00ef244bd183e8a13288e4412d8389d140aac1794825a"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "5837736c89570de861ebc173b1086da4f505d4adb387c6a1b1342d5e4ac9ec72"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "01e33c0f7d81d843c572275f287498e8d408654fdf0d1e065b84e2e6f157aab09b"), + 33); + + // [Chain m/0'/2147483647'/1'/2147483646'/2'] + r = hdnode_private_ckd_prime(&node, 2); + ck_assert_int_eq(r, 1); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "5d70af781f3a37b829f0d060924d5e960bdc02e85423494afc0b1a41bbe196d4"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "551d333177df541ad876a60ea71f00447931c0a9da16f227c11ea080d7391b8d"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "0147150c75db263559a70d5778bf36abbab30fb061ad69f69ece61a72b0cfa4fc0"), + 33); } END_TEST -// test vector 1 from https://github.com/decred/dcrd/blob/master/hdkeychain/extendedkey_test.go -START_TEST(test_bip32_decred_vector_1) -{ - HDNode node, node2, node3; - uint32_t fingerprint; - char str[112]; - int r; - - // init m - hdnode_from_seed(fromhex("000102030405060708090a0b0c0d0e0f"), 16, SECP256K1_NAME, &node); - - // secp256k1_decred_info.bip32_name != "Bitcoin seed" so we cannot use it in hdnode_from_seed - node.curve = &secp256k1_decred_info; - - // [Chain m] - fingerprint = 0; - ck_assert_int_eq(fingerprint, 0x00000000); - ck_assert_mem_eq(node.chain_code, fromhex("873dff81c02f525623fd1fe5167eac3a55a049de3d314bb42ee227ffed37d508"), 32); - ck_assert_mem_eq(node.private_key, fromhex("e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key, fromhex("0339a36013301597daef41fbe593a02cc513d0b55527ec2df1050e2e8ff49c85c2"), 33); - hdnode_serialize_private(&node, fingerprint, DECRED_VERSION_PRIVATE, str, sizeof(str)); - ck_assert_str_eq(str, "dprv3hCznBesA6jBtmoyVFPfyMSZ1qYZ3WdjdebquvkEfmRfxC9VFEFi2YDaJqHnx7uGe75eGSa3Mn3oHK11hBW7KZUrPxwbCPBmuCi1nwm182s"); - r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); - ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, sizeof(str)); - ck_assert_str_eq(str, "dpubZ9169KDAEUnyoBhjjmT2VaEodr6pUTDoqCEAeqgbfr2JfkB88BbK77jbTYbcYXb2FVz7DKBdW4P618yd51MwF8DjKVopSbS7Lkgi6bowX5w"); - r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - memcpy(&node3, &node, sizeof(HDNode)); - memzero(&node3.private_key, 32); - ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); - - // [Chain m/0'] - fingerprint = hdnode_fingerprint(&node); - hdnode_private_ckd_prime(&node, 0); - ck_assert_int_eq(fingerprint, 0xbc495588); - ck_assert_mem_eq(node.chain_code, fromhex("47fdacbd0f1097043b78c63c20c34ef4ed9a111d980047ad16282c7ae6236141"), 32); - ck_assert_mem_eq(node.private_key, fromhex("edb2e14f9ee77d26dd93b4ecede8d16ed408ce149b6cd80b0715a2d911a0afea"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key, fromhex("035a784662a4a20a65bf6aab9ae98a6c068a81c52e4b032c0fb5400c706cfccc56"), 33); - hdnode_serialize_private(&node, fingerprint, DECRED_VERSION_PRIVATE, str, sizeof(str)); - ck_assert_str_eq(str, "dprv3kUQDBztdyjKuwnaL3hfKYpT7W6X2huYH5d61YSWFBebSYwEBHAXJkCpQ7rvMAxPzKqxVCGLvBqWvGxXjAyMJsV1XwKkfnQCM9KctC8k8bk"); - r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); - ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, sizeof(str)); - ck_assert_str_eq(str, "dpubZCGVaKZBiMo7pMgLaZm1qmchjWenTeVcUdFQkTNsFGFEA6xs4EW8PKiqYqP7HBAitt9Hw16VQkQ1tjsZQSHNWFc6bEK6bLqrbco24FzBTY4"); - r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - memcpy(&node3, &node, sizeof(HDNode)); - memzero(&node3.private_key, 32); - ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); - - // [Chain m/0'/1] - fingerprint = hdnode_fingerprint(&node); - hdnode_private_ckd(&node, 1); - ck_assert_int_eq(fingerprint, 0xc67bc2ef); - ck_assert_mem_eq(node.chain_code, fromhex("2a7857631386ba23dacac34180dd1983734e444fdbf774041578e9b6adb37c19"), 32); - ck_assert_mem_eq(node.private_key, fromhex("3c6cb8d0f6a264c91ea8b5030fadaa8e538b020f0a387421a12de9319dc93368"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key, fromhex("03501e454bf00751f24b1b489aa925215d66af2234e3891c3b21a52bedb3cd711c"), 33); - hdnode_serialize_private(&node, fingerprint, DECRED_VERSION_PRIVATE, str, sizeof(str)); - ck_assert_str_eq(str, "dprv3nRtCZ5VAoHW4RUwQgRafSNRPUDFrmsgyY71A5eoZceVfuyL9SbZe2rcbwDW2UwpkEniE4urffgbypegscNchPajWzy9QS4cRxF8QYXsZtq"); - r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); - ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, sizeof(str)); - ck_assert_str_eq(str, "dpubZEDyZgdnFBMHxqNhfCUwBfAg1UmXHiTmB5jKtzbAZhF8PTzy2PwAicNdkg1CmW6TARxQeUbgC7nAQenJts4YoG3KMiqcjsjgeMvwLc43w6C"); - r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - memcpy(&node3, &node, sizeof(HDNode)); - memzero(&node3.private_key, 32); - ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); - - // [Chain m/0'/1/2'] - fingerprint = hdnode_fingerprint(&node); - hdnode_private_ckd_prime(&node, 2); - ck_assert_int_eq(fingerprint, 0xe7072187); - ck_assert_mem_eq(node.chain_code, fromhex("04466b9cc8e161e966409ca52986c584f07e9dc81f735db683c3ff6ec7b1503f"), 32); - ck_assert_mem_eq(node.private_key, fromhex("cbce0d719ecf7431d88e6a89fa1483e02e35092af60c042b1df2ff59fa424dca"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key, fromhex("0357bfe1e341d01c69fe5654309956cbea516822fba8a601743a012a7896ee8dc2"), 33); - hdnode_serialize_private(&node, fingerprint, DECRED_VERSION_PRIVATE, str, sizeof(str)); - ck_assert_str_eq(str, "dprv3pYtkZK168vgrU38gXkUSjHQ2LGpEUzQ9fXrR8fGUR59YviSnm6U82XjQYhpJEUPnVcC9bguJBQU5xVM4VFcDHu9BgScGPA6mQMH4bn5Cth"); - r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); - ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, sizeof(str)); - ck_assert_str_eq(str, "dpubZGLz7gsJAWzUksvtw3opxx5eeLq5fRaUMDABA3bdUVfnGUk5fiS5Cc3kZGTjWtYr3jrEavQQnAF6jv2WCpZtFX4uFgifXqev6ED1TM9rTCB"); - r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - memcpy(&node3, &node, sizeof(HDNode)); - memzero(&node3.private_key, 32); - ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); - - // [Chain m/0'/1/2'/2] - fingerprint = hdnode_fingerprint(&node); - hdnode_private_ckd(&node, 2); - ck_assert_int_eq(fingerprint, 0xbcbbc1c4); - ck_assert_mem_eq(node.chain_code, fromhex("cfb71883f01676f587d023cc53a35bc7f88f724b1f8c2892ac1275ac822a3edd"), 32); - ck_assert_mem_eq(node.private_key, fromhex("0f479245fb19a38a1954c5c7c0ebab2f9bdfd96a17563ef28a6a4b1a2a764ef4"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key, fromhex("02e8445082a72f29b75ca48748a914df60622a609cacfce8ed0e35804560741d29"), 33); - hdnode_serialize_private(&node, fingerprint, DECRED_VERSION_PRIVATE, str, sizeof(str)); - ck_assert_str_eq(str, "dprv3r7zqYFjT3NiNzdnwGxGpYh6S1TJCp1zA6mSEGaqLBJFnCB94cRMp7YYLR49aTZHZ7ya1CXwQJ6rodKeU9NgQTxkPSK7pzgZRgjYkQ7rgJh"); - r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); - ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, sizeof(str)); - ck_assert_str_eq(str, "dpubZHv6Cfp2XRSWHQXZBo1dLmVM421Zdkc4MePkyBXCLFttVkCmwZkxth4ZV9PzkFP3DtD5xcVq2CPSYpJMWMaoxu1ixz4GNZFVcE2xnHP6chJ"); - r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - memcpy(&node3, &node, sizeof(HDNode)); - memzero(&node3.private_key, 32); - ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); - - // [Chain m/0'/1/2'/2/1000000000] - fingerprint = hdnode_fingerprint(&node); - hdnode_private_ckd(&node, 1000000000); - ck_assert_int_eq(fingerprint, 0xe58b52e4); - ck_assert_mem_eq(node.chain_code, fromhex("c783e67b921d2beb8f6b389cc646d7263b4145701dadd2161548a8b078e65e9e"), 32); - ck_assert_mem_eq(node.private_key, fromhex("471b76e389e528d6de6d816857e012c5455051cad6660850e58372a6c3e6e7c8"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key, fromhex("022a471424da5e657499d1ff51cb43c47481a03b1e77f951fe64cec9f5a48f7011"), 33); - hdnode_serialize_private(&node, fingerprint, DECRED_VERSION_PRIVATE, str, sizeof(str)); - ck_assert_str_eq(str, "dprv3tJXnTDSb3uE6Euo6WvvhFKfBMNfxuJt5smqyPoHEoomoBMQyhYoQSKJAHWtWxmuqdUVb8q9J2NaTkF6rYm6XDrSotkJ55bM21fffa7VV97"); - r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); - ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, sizeof(str)); - ck_assert_str_eq(str, "dpubZL6d9amjfRy1zeoZM2zHDU7uoMvwPqtxHRQAiJjeEtQQWjP3retQV1qKJyzUd6ZJNgbJGXjtc5pdoBcTTYTLoxQzvV9JJCzCjB2eCWpRf8T"); - r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - memcpy(&node3, &node, sizeof(HDNode)); - memzero(&node3.private_key, 32); - ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); +// test vector 1 from +// https://github.com/decred/dcrd/blob/master/hdkeychain/extendedkey_test.go +START_TEST(test_bip32_decred_vector_1) { + HDNode node, node2, node3; + uint32_t fingerprint; + char str[112]; + int r; + + // init m + hdnode_from_seed(fromhex("000102030405060708090a0b0c0d0e0f"), 16, + SECP256K1_NAME, &node); + + // secp256k1_decred_info.bip32_name != "Bitcoin seed" so we cannot use it in + // hdnode_from_seed + node.curve = &secp256k1_decred_info; + + // [Chain m] + fingerprint = 0; + ck_assert_int_eq(fingerprint, 0x00000000); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "873dff81c02f525623fd1fe5167eac3a55a049de3d314bb42ee227ffed37d508"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "0339a36013301597daef41fbe593a02cc513d0b55527ec2df1050e2e8ff49c85c2"), + 33); + hdnode_serialize_private(&node, fingerprint, DECRED_VERSION_PRIVATE, str, + sizeof(str)); + ck_assert_str_eq(str, + "dprv3hCznBesA6jBtmoyVFPfyMSZ1qYZ3WdjdebquvkEfmRfxC9VFEFi2YD" + "aJqHnx7uGe75eGSa3Mn3oHK11hBW7KZUrPxwbCPBmuCi1nwm182s"); + r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, + SECP256K1_DECRED_NAME, &node2, NULL); + ck_assert_int_eq(r, 0); + ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, + sizeof(str)); + ck_assert_str_eq(str, + "dpubZ9169KDAEUnyoBhjjmT2VaEodr6pUTDoqCEAeqgbfr2JfkB88BbK77j" + "bTYbcYXb2FVz7DKBdW4P618yd51MwF8DjKVopSbS7Lkgi6bowX5w"); + r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, + SECP256K1_DECRED_NAME, &node2, NULL); + ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memzero(&node3.private_key, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); + + // [Chain m/0'] + fingerprint = hdnode_fingerprint(&node); + hdnode_private_ckd_prime(&node, 0); + ck_assert_int_eq(fingerprint, 0xbc495588); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "47fdacbd0f1097043b78c63c20c34ef4ed9a111d980047ad16282c7ae6236141"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "edb2e14f9ee77d26dd93b4ecede8d16ed408ce149b6cd80b0715a2d911a0afea"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "035a784662a4a20a65bf6aab9ae98a6c068a81c52e4b032c0fb5400c706cfccc56"), + 33); + hdnode_serialize_private(&node, fingerprint, DECRED_VERSION_PRIVATE, str, + sizeof(str)); + ck_assert_str_eq(str, + "dprv3kUQDBztdyjKuwnaL3hfKYpT7W6X2huYH5d61YSWFBebSYwEBHAXJkC" + "pQ7rvMAxPzKqxVCGLvBqWvGxXjAyMJsV1XwKkfnQCM9KctC8k8bk"); + r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, + SECP256K1_DECRED_NAME, &node2, NULL); + ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, + sizeof(str)); + ck_assert_str_eq(str, + "dpubZCGVaKZBiMo7pMgLaZm1qmchjWenTeVcUdFQkTNsFGFEA6xs4EW8PKi" + "qYqP7HBAitt9Hw16VQkQ1tjsZQSHNWFc6bEK6bLqrbco24FzBTY4"); + r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, + SECP256K1_DECRED_NAME, &node2, NULL); + ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memzero(&node3.private_key, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); + + // [Chain m/0'/1] + fingerprint = hdnode_fingerprint(&node); + hdnode_private_ckd(&node, 1); + ck_assert_int_eq(fingerprint, 0xc67bc2ef); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "2a7857631386ba23dacac34180dd1983734e444fdbf774041578e9b6adb37c19"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "3c6cb8d0f6a264c91ea8b5030fadaa8e538b020f0a387421a12de9319dc93368"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "03501e454bf00751f24b1b489aa925215d66af2234e3891c3b21a52bedb3cd711c"), + 33); + hdnode_serialize_private(&node, fingerprint, DECRED_VERSION_PRIVATE, str, + sizeof(str)); + ck_assert_str_eq(str, + "dprv3nRtCZ5VAoHW4RUwQgRafSNRPUDFrmsgyY71A5eoZceVfuyL9SbZe2r" + "cbwDW2UwpkEniE4urffgbypegscNchPajWzy9QS4cRxF8QYXsZtq"); + r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, + SECP256K1_DECRED_NAME, &node2, NULL); + ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, + sizeof(str)); + ck_assert_str_eq(str, + "dpubZEDyZgdnFBMHxqNhfCUwBfAg1UmXHiTmB5jKtzbAZhF8PTzy2PwAicN" + "dkg1CmW6TARxQeUbgC7nAQenJts4YoG3KMiqcjsjgeMvwLc43w6C"); + r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, + SECP256K1_DECRED_NAME, &node2, NULL); + ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memzero(&node3.private_key, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); + + // [Chain m/0'/1/2'] + fingerprint = hdnode_fingerprint(&node); + hdnode_private_ckd_prime(&node, 2); + ck_assert_int_eq(fingerprint, 0xe7072187); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "04466b9cc8e161e966409ca52986c584f07e9dc81f735db683c3ff6ec7b1503f"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "cbce0d719ecf7431d88e6a89fa1483e02e35092af60c042b1df2ff59fa424dca"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "0357bfe1e341d01c69fe5654309956cbea516822fba8a601743a012a7896ee8dc2"), + 33); + hdnode_serialize_private(&node, fingerprint, DECRED_VERSION_PRIVATE, str, + sizeof(str)); + ck_assert_str_eq(str, + "dprv3pYtkZK168vgrU38gXkUSjHQ2LGpEUzQ9fXrR8fGUR59YviSnm6U82X" + "jQYhpJEUPnVcC9bguJBQU5xVM4VFcDHu9BgScGPA6mQMH4bn5Cth"); + r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, + SECP256K1_DECRED_NAME, &node2, NULL); + ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, + sizeof(str)); + ck_assert_str_eq(str, + "dpubZGLz7gsJAWzUksvtw3opxx5eeLq5fRaUMDABA3bdUVfnGUk5fiS5Cc3" + "kZGTjWtYr3jrEavQQnAF6jv2WCpZtFX4uFgifXqev6ED1TM9rTCB"); + r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, + SECP256K1_DECRED_NAME, &node2, NULL); + ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memzero(&node3.private_key, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); + + // [Chain m/0'/1/2'/2] + fingerprint = hdnode_fingerprint(&node); + hdnode_private_ckd(&node, 2); + ck_assert_int_eq(fingerprint, 0xbcbbc1c4); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "cfb71883f01676f587d023cc53a35bc7f88f724b1f8c2892ac1275ac822a3edd"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "0f479245fb19a38a1954c5c7c0ebab2f9bdfd96a17563ef28a6a4b1a2a764ef4"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "02e8445082a72f29b75ca48748a914df60622a609cacfce8ed0e35804560741d29"), + 33); + hdnode_serialize_private(&node, fingerprint, DECRED_VERSION_PRIVATE, str, + sizeof(str)); + ck_assert_str_eq(str, + "dprv3r7zqYFjT3NiNzdnwGxGpYh6S1TJCp1zA6mSEGaqLBJFnCB94cRMp7Y" + "YLR49aTZHZ7ya1CXwQJ6rodKeU9NgQTxkPSK7pzgZRgjYkQ7rgJh"); + r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, + SECP256K1_DECRED_NAME, &node2, NULL); + ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, + sizeof(str)); + ck_assert_str_eq(str, + "dpubZHv6Cfp2XRSWHQXZBo1dLmVM421Zdkc4MePkyBXCLFttVkCmwZkxth4" + "ZV9PzkFP3DtD5xcVq2CPSYpJMWMaoxu1ixz4GNZFVcE2xnHP6chJ"); + r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, + SECP256K1_DECRED_NAME, &node2, NULL); + ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memzero(&node3.private_key, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); + + // [Chain m/0'/1/2'/2/1000000000] + fingerprint = hdnode_fingerprint(&node); + hdnode_private_ckd(&node, 1000000000); + ck_assert_int_eq(fingerprint, 0xe58b52e4); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "c783e67b921d2beb8f6b389cc646d7263b4145701dadd2161548a8b078e65e9e"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "471b76e389e528d6de6d816857e012c5455051cad6660850e58372a6c3e6e7c8"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "022a471424da5e657499d1ff51cb43c47481a03b1e77f951fe64cec9f5a48f7011"), + 33); + hdnode_serialize_private(&node, fingerprint, DECRED_VERSION_PRIVATE, str, + sizeof(str)); + ck_assert_str_eq(str, + "dprv3tJXnTDSb3uE6Euo6WvvhFKfBMNfxuJt5smqyPoHEoomoBMQyhYoQSK" + "JAHWtWxmuqdUVb8q9J2NaTkF6rYm6XDrSotkJ55bM21fffa7VV97"); + r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, + SECP256K1_DECRED_NAME, &node2, NULL); + ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, + sizeof(str)); + ck_assert_str_eq(str, + "dpubZL6d9amjfRy1zeoZM2zHDU7uoMvwPqtxHRQAiJjeEtQQWjP3retQV1q" + "KJyzUd6ZJNgbJGXjtc5pdoBcTTYTLoxQzvV9JJCzCjB2eCWpRf8T"); + r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, + SECP256K1_DECRED_NAME, &node2, NULL); + ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memzero(&node3.private_key, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); } END_TEST -// test vector 2 from https://github.com/decred/dcrd/blob/master/hdkeychain/extendedkey_test.go -START_TEST(test_bip32_decred_vector_2) -{ - HDNode node, node2, node3; - uint32_t fingerprint; - char str[112]; - int r; - - // init m - hdnode_from_seed(fromhex("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), 64, SECP256K1_NAME, &node); - - // secp256k1_decred_info.bip32_name != "Bitcoin seed" so we cannot use it in hdnode_from_seed - node.curve = &secp256k1_decred_info; - - // [Chain m] - fingerprint = 0; - ck_assert_int_eq(fingerprint, 0x00000000); - ck_assert_mem_eq(node.chain_code, fromhex("60499f801b896d83179a4374aeb7822aaeaceaa0db1f85ee3e904c4defbd9689"), 32); - ck_assert_mem_eq(node.private_key, fromhex("4b03d6fc340455b363f51020ad3ecca4f0850280cf436c70c727923f6db46c3e"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key, fromhex("03cbcaa9c98c877a26977d00825c956a238e8dddfbd322cce4f74b0b5bd6ace4a7"), 33); - hdnode_serialize_private(&node, fingerprint, DECRED_VERSION_PRIVATE, str, sizeof(str)); - ck_assert_str_eq(str, "dprv3hCznBesA6jBtPKJbQTxRZAKG2gyj8tZKEPaCsV4e9YYFBAgRP2eTSPAeu4r8dTMt9q51j2Vdt5zNqj7jbtovvocrP1qLj6WUTLF9xYQt4y"); - r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); - ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, sizeof(str)); - ck_assert_str_eq(str, "dpubZ9169KDAEUnynoD4qvXJwmxZt3FFA5UdWn1twnRReE9AxjCKJLNFY1uBoegbFmwzA4Du7yqnu8tLivhrCCH6P3DgBS1HH5vmf8MpNXvvYT9"); - r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - memcpy(&node3, &node, sizeof(HDNode)); - memzero(&node3.private_key, 32); - ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); - - // [Chain m/0] - fingerprint = hdnode_fingerprint(&node); - r = hdnode_private_ckd(&node, 0); - ck_assert_int_eq(r, 1); - ck_assert_int_eq(fingerprint, 0x2524c9d3); - ck_assert_mem_eq(node.chain_code, fromhex("f0909affaa7ee7abe5dd4e100598d4dc53cd709d5a5c2cac40e7412f232f7c9c"), 32); - ck_assert_mem_eq(node.private_key, fromhex("abe74a98f6c7eabee0428f53798f0ab8aa1bd37873999041703c742f15ac7e1e"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key, fromhex("02fc9e5af0ac8d9b3cecfe2a888e2117ba3d089d8585886c9c826b6b22a98d12ea"), 33); - hdnode_serialize_private(&node, fingerprint, DECRED_VERSION_PRIVATE, str, sizeof(str)); - ck_assert_str_eq(str, "dprv3jMy45BuuDETfxi59P8NTSjHPrNVq4wPRfLgRd57923L2hosj5NUEqiLYQ4i7fJtUpiXZLr2wUeToJY2Tm5sCpAJdajEHDmieVJiPQNXwu9"); - r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); - ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, sizeof(str)); - ck_assert_str_eq(str, "dpubZBA4RCkCybJFaNbqPuBiyfXY1rvmG1XTdCy1AY1U96dxkFqWc2i5KREMh7NYPpy7ZPMhdpFMAesex3JdFDfX4J5FEW3HjSacqEYPfwb9Cj7"); - r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - memcpy(&node3, &node, sizeof(HDNode)); - memzero(&node3.private_key, 32); - ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); - - // [Chain m/0/2147483647'] - fingerprint = hdnode_fingerprint(&node); - r = hdnode_private_ckd_prime(&node, 2147483647); - ck_assert_int_eq(r, 1); - ck_assert_int_eq(fingerprint, 0x6035c6ad); - ck_assert_mem_eq(node.chain_code, fromhex("be17a268474a6bb9c61e1d720cf6215e2a88c5406c4aee7b38547f585c9a37d9"), 32); - ck_assert_mem_eq(node.private_key, fromhex("877c779ad9687164e9c2f4f0f4ff0340814392330693ce95a58fe18fd52e6e93"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key, fromhex("03c01e7425647bdefa82b12d9bad5e3e6865bee0502694b94ca58b666abc0a5c3b"), 33); - hdnode_serialize_private(&node, fingerprint, DECRED_VERSION_PRIVATE, str, sizeof(str)); - ck_assert_str_eq(str, "dprv3mgHPRgK838mLK6T1p6WeBoJoJtXA1pGTHjqFuyHekcM7UTuER8fGweRRsoLqSuHa98uskVPnJnfWZEBUC1AVmXnSCPDvUFKydXNnnPHTuQ"); - r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); - ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, sizeof(str)); - ck_assert_str_eq(str, "dpubZDUNkZEcCRCZEizDGL9sAQbZRKSnaxQLeqN9zpueeqCyq2VY7NUGMXASacsK96S8XzNjq3YgFgwLtj8MJBToW6To9U5zxuazEyh89bjR1xA"); - r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - memcpy(&node3, &node, sizeof(HDNode)); - memzero(&node3.private_key, 32); - ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); - - // [Chain m/0/2147483647'/1] - fingerprint = hdnode_fingerprint(&node); - r = hdnode_private_ckd(&node, 1); - ck_assert_int_eq(r, 1); - ck_assert_int_eq(fingerprint, 0x36fc7080); - ck_assert_mem_eq(node.chain_code, fromhex("f366f48f1ea9f2d1d3fe958c95ca84ea18e4c4ddb9366c336c927eb246fb38cb"), 32); - ck_assert_mem_eq(node.private_key, fromhex("704addf544a06e5ee4bea37098463c23613da32020d604506da8c0518e1da4b7"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key, fromhex("03a7d1d856deb74c508e05031f9895dab54626251b3806e16b4bd12e781a7df5b9"), 33); - hdnode_serialize_private(&node, fingerprint, DECRED_VERSION_PRIVATE, str, sizeof(str)); - ck_assert_str_eq(str, "dprv3oFqwZZ9bJcUmhAeJyyshvrTWtrAsHfcRYQbEzNiiH5nGvM6wVTDn6woQEz92b2EHTYZBtLi82jKEnxSouA3cVaW8YWBsw5c3f4mwAhA3d2"); - r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); - ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, sizeof(str)); - ck_assert_str_eq(str, "dpubZF3wJh7SfggGg74QZW3EE9ei8uQSJEFgd62uyuK5iMgQzUNjpSnprgTpYz3d6Q3fXXtEEXQqpzWcP4LUVuXFsgA8JKt1Hot5kyUk4pPRhDz"); - r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - memcpy(&node3, &node, sizeof(HDNode)); - memzero(&node3.private_key, 32); - ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); - - // [Chain m/0/2147483647'/1/2147483646'] - fingerprint = hdnode_fingerprint(&node); - r = hdnode_private_ckd_prime(&node, 2147483646); - ck_assert_int_eq(r, 1); - ck_assert_int_eq(fingerprint, 0x45309b4c); - ck_assert_mem_eq(node.chain_code, fromhex("637807030d55d01f9a0cb3a7839515d796bd07706386a6eddf06cc29a65a0e29"), 32); - ck_assert_mem_eq(node.private_key, fromhex("f1c7c871a54a804afe328b4c83a1c33b8e5ff48f5087273f04efa83b247d6a2d"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key, fromhex("02d2b36900396c9282fa14628566582f206a5dd0bcc8d5e892611806cafb0301f0"), 33); - hdnode_serialize_private(&node, fingerprint, DECRED_VERSION_PRIVATE, str, sizeof(str)); - ck_assert_str_eq(str, "dprv3qF3177i87wMirg6sraDvqty8yZg6THpXFPSXuM5AShBiiUQbq8FhSZDGkYmBNR3RKfBrxzkKDBpsRFJfTnQfLsvpPPqRnakat6hHQA43X9"); - r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); - ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, sizeof(str)); - ck_assert_str_eq(str, "dpubZH38NEg1CW19dGZs8NdaT4hDkz7wXPstio1mGpHSAXHpSGW3UnTrn25ERT1Mp8ae5GMoQHMbgQiPrChMXQMdx3UqS8YqFkT1pqait8fY92u"); - r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - memcpy(&node3, &node, sizeof(HDNode)); - memzero(&node3.private_key, 32); - ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); - - // [Chain m/0/2147483647'/1/2147483646'/2] - fingerprint = hdnode_fingerprint(&node); - r = hdnode_private_ckd(&node, 2); - ck_assert_int_eq(r, 1); - ck_assert_int_eq(fingerprint, 0x3491a5e6); - ck_assert_mem_eq(node.chain_code, fromhex("9452b549be8cea3ecb7a84bec10dcfd94afe4d129ebfd3b3cb58eedf394ed271"), 32); - ck_assert_mem_eq(node.private_key, fromhex("bb7d39bdb83ecf58f2fd82b6d918341cbef428661ef01ab97c28a4842125ac23"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key, fromhex("024d902e1a2fc7a8755ab5b694c575fce742c48d9ff192e63df5193e4c7afe1f9c"), 33); - hdnode_serialize_private(&node, fingerprint, DECRED_VERSION_PRIVATE, str, sizeof(str)); - ck_assert_str_eq(str, "dprv3s15tfqzxhw8Kmo7RBEqMeyvC7uGekLniSmvbs3bckpxQ6ks1KKqfmH144Jgh3PLxkyZRcS367kp7DrtUmnG16NpnsoNhxSXRgKbJJ7MUQR"); - r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); - ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, sizeof(str)); - ck_assert_str_eq(str, "dpubZJoBFoQJ35zvEBgsfhJBssnAp8TY5gvruzQFLmyxcqRb7enVtGfSkLo2CkAZJMpa6T2fx6fUtvTgXtUvSVgAZ56bEwGxQsToeZfFV8VadE1"); - r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - memcpy(&node3, &node, sizeof(HDNode)); - memzero(&node3.private_key, 32); - ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); - - // init m - hdnode_deserialize("dpubZF4LSCdF9YKZfNzTVYhz4RBxsjYXqms8AQnMBHXZ8GUKoRSigG7kQnKiJt5pzk93Q8FxcdVBEkQZruSXduGtWnkwXzGnjbSovQ97dCxqaXc", DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node, NULL); - - // test public derivation - // [Chain m/0] - fingerprint = hdnode_fingerprint(&node); - r = hdnode_public_ckd(&node, 0); - ck_assert_int_eq(r, 1); - ck_assert_int_eq(fingerprint, 0x6a19cfb3); - ck_assert_mem_eq(node.chain_code, fromhex("dcfe00831741a3a4803955147cdfc7053d69b167b1d03b5f9e63934217a005fd"), 32); - ck_assert_mem_eq(node.public_key, fromhex("029555ea7bde276cd2c42c4502f40b5d16469fb310ae3aeee2a9000455f41b0866"), 33); - hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, sizeof(str)); - ck_assert_str_eq(str, "dpubZHJs2Z3PtHbbpaXQCi5wBKPhU8tC5ztBKUYBCYNGKk8eZ1EmBs3MhnLJbxHFMAahGnDnZT7qZxC7AXKP8PB6BDNUZgkG77moNMRmXyQ6s6s"); - r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - ck_assert_mem_eq(&node2, &node, sizeof(HDNode)); +// test vector 2 from +// https://github.com/decred/dcrd/blob/master/hdkeychain/extendedkey_test.go +START_TEST(test_bip32_decred_vector_2) { + HDNode node, node2, node3; + uint32_t fingerprint; + char str[112]; + int r; + + // init m + hdnode_from_seed( + fromhex( + "fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c" + "999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), + 64, SECP256K1_NAME, &node); + + // secp256k1_decred_info.bip32_name != "Bitcoin seed" so we cannot use it in + // hdnode_from_seed + node.curve = &secp256k1_decred_info; + + // [Chain m] + fingerprint = 0; + ck_assert_int_eq(fingerprint, 0x00000000); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "60499f801b896d83179a4374aeb7822aaeaceaa0db1f85ee3e904c4defbd9689"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "4b03d6fc340455b363f51020ad3ecca4f0850280cf436c70c727923f6db46c3e"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "03cbcaa9c98c877a26977d00825c956a238e8dddfbd322cce4f74b0b5bd6ace4a7"), + 33); + hdnode_serialize_private(&node, fingerprint, DECRED_VERSION_PRIVATE, str, + sizeof(str)); + ck_assert_str_eq(str, + "dprv3hCznBesA6jBtPKJbQTxRZAKG2gyj8tZKEPaCsV4e9YYFBAgRP2eTSP" + "Aeu4r8dTMt9q51j2Vdt5zNqj7jbtovvocrP1qLj6WUTLF9xYQt4y"); + r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, + SECP256K1_DECRED_NAME, &node2, NULL); + ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, + sizeof(str)); + ck_assert_str_eq(str, + "dpubZ9169KDAEUnynoD4qvXJwmxZt3FFA5UdWn1twnRReE9AxjCKJLNFY1u" + "BoegbFmwzA4Du7yqnu8tLivhrCCH6P3DgBS1HH5vmf8MpNXvvYT9"); + r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, + SECP256K1_DECRED_NAME, &node2, NULL); + ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memzero(&node3.private_key, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); + + // [Chain m/0] + fingerprint = hdnode_fingerprint(&node); + r = hdnode_private_ckd(&node, 0); + ck_assert_int_eq(r, 1); + ck_assert_int_eq(fingerprint, 0x2524c9d3); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "f0909affaa7ee7abe5dd4e100598d4dc53cd709d5a5c2cac40e7412f232f7c9c"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "abe74a98f6c7eabee0428f53798f0ab8aa1bd37873999041703c742f15ac7e1e"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "02fc9e5af0ac8d9b3cecfe2a888e2117ba3d089d8585886c9c826b6b22a98d12ea"), + 33); + hdnode_serialize_private(&node, fingerprint, DECRED_VERSION_PRIVATE, str, + sizeof(str)); + ck_assert_str_eq(str, + "dprv3jMy45BuuDETfxi59P8NTSjHPrNVq4wPRfLgRd57923L2hosj5NUEqi" + "LYQ4i7fJtUpiXZLr2wUeToJY2Tm5sCpAJdajEHDmieVJiPQNXwu9"); + r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, + SECP256K1_DECRED_NAME, &node2, NULL); + ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, + sizeof(str)); + ck_assert_str_eq(str, + "dpubZBA4RCkCybJFaNbqPuBiyfXY1rvmG1XTdCy1AY1U96dxkFqWc2i5KRE" + "Mh7NYPpy7ZPMhdpFMAesex3JdFDfX4J5FEW3HjSacqEYPfwb9Cj7"); + r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, + SECP256K1_DECRED_NAME, &node2, NULL); + ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memzero(&node3.private_key, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); + + // [Chain m/0/2147483647'] + fingerprint = hdnode_fingerprint(&node); + r = hdnode_private_ckd_prime(&node, 2147483647); + ck_assert_int_eq(r, 1); + ck_assert_int_eq(fingerprint, 0x6035c6ad); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "be17a268474a6bb9c61e1d720cf6215e2a88c5406c4aee7b38547f585c9a37d9"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "877c779ad9687164e9c2f4f0f4ff0340814392330693ce95a58fe18fd52e6e93"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "03c01e7425647bdefa82b12d9bad5e3e6865bee0502694b94ca58b666abc0a5c3b"), + 33); + hdnode_serialize_private(&node, fingerprint, DECRED_VERSION_PRIVATE, str, + sizeof(str)); + ck_assert_str_eq(str, + "dprv3mgHPRgK838mLK6T1p6WeBoJoJtXA1pGTHjqFuyHekcM7UTuER8fGwe" + "RRsoLqSuHa98uskVPnJnfWZEBUC1AVmXnSCPDvUFKydXNnnPHTuQ"); + r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, + SECP256K1_DECRED_NAME, &node2, NULL); + ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, + sizeof(str)); + ck_assert_str_eq(str, + "dpubZDUNkZEcCRCZEizDGL9sAQbZRKSnaxQLeqN9zpueeqCyq2VY7NUGMXA" + "SacsK96S8XzNjq3YgFgwLtj8MJBToW6To9U5zxuazEyh89bjR1xA"); + r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, + SECP256K1_DECRED_NAME, &node2, NULL); + ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memzero(&node3.private_key, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); + + // [Chain m/0/2147483647'/1] + fingerprint = hdnode_fingerprint(&node); + r = hdnode_private_ckd(&node, 1); + ck_assert_int_eq(r, 1); + ck_assert_int_eq(fingerprint, 0x36fc7080); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "f366f48f1ea9f2d1d3fe958c95ca84ea18e4c4ddb9366c336c927eb246fb38cb"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "704addf544a06e5ee4bea37098463c23613da32020d604506da8c0518e1da4b7"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "03a7d1d856deb74c508e05031f9895dab54626251b3806e16b4bd12e781a7df5b9"), + 33); + hdnode_serialize_private(&node, fingerprint, DECRED_VERSION_PRIVATE, str, + sizeof(str)); + ck_assert_str_eq(str, + "dprv3oFqwZZ9bJcUmhAeJyyshvrTWtrAsHfcRYQbEzNiiH5nGvM6wVTDn6w" + "oQEz92b2EHTYZBtLi82jKEnxSouA3cVaW8YWBsw5c3f4mwAhA3d2"); + r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, + SECP256K1_DECRED_NAME, &node2, NULL); + ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, + sizeof(str)); + ck_assert_str_eq(str, + "dpubZF3wJh7SfggGg74QZW3EE9ei8uQSJEFgd62uyuK5iMgQzUNjpSnprgT" + "pYz3d6Q3fXXtEEXQqpzWcP4LUVuXFsgA8JKt1Hot5kyUk4pPRhDz"); + r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, + SECP256K1_DECRED_NAME, &node2, NULL); + ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memzero(&node3.private_key, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); + + // [Chain m/0/2147483647'/1/2147483646'] + fingerprint = hdnode_fingerprint(&node); + r = hdnode_private_ckd_prime(&node, 2147483646); + ck_assert_int_eq(r, 1); + ck_assert_int_eq(fingerprint, 0x45309b4c); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "637807030d55d01f9a0cb3a7839515d796bd07706386a6eddf06cc29a65a0e29"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "f1c7c871a54a804afe328b4c83a1c33b8e5ff48f5087273f04efa83b247d6a2d"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "02d2b36900396c9282fa14628566582f206a5dd0bcc8d5e892611806cafb0301f0"), + 33); + hdnode_serialize_private(&node, fingerprint, DECRED_VERSION_PRIVATE, str, + sizeof(str)); + ck_assert_str_eq(str, + "dprv3qF3177i87wMirg6sraDvqty8yZg6THpXFPSXuM5AShBiiUQbq8FhSZ" + "DGkYmBNR3RKfBrxzkKDBpsRFJfTnQfLsvpPPqRnakat6hHQA43X9"); + r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, + SECP256K1_DECRED_NAME, &node2, NULL); + ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, + sizeof(str)); + ck_assert_str_eq(str, + "dpubZH38NEg1CW19dGZs8NdaT4hDkz7wXPstio1mGpHSAXHpSGW3UnTrn25" + "ERT1Mp8ae5GMoQHMbgQiPrChMXQMdx3UqS8YqFkT1pqait8fY92u"); + r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, + SECP256K1_DECRED_NAME, &node2, NULL); + ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memzero(&node3.private_key, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); + + // [Chain m/0/2147483647'/1/2147483646'/2] + fingerprint = hdnode_fingerprint(&node); + r = hdnode_private_ckd(&node, 2); + ck_assert_int_eq(r, 1); + ck_assert_int_eq(fingerprint, 0x3491a5e6); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "9452b549be8cea3ecb7a84bec10dcfd94afe4d129ebfd3b3cb58eedf394ed271"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "bb7d39bdb83ecf58f2fd82b6d918341cbef428661ef01ab97c28a4842125ac23"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "024d902e1a2fc7a8755ab5b694c575fce742c48d9ff192e63df5193e4c7afe1f9c"), + 33); + hdnode_serialize_private(&node, fingerprint, DECRED_VERSION_PRIVATE, str, + sizeof(str)); + ck_assert_str_eq(str, + "dprv3s15tfqzxhw8Kmo7RBEqMeyvC7uGekLniSmvbs3bckpxQ6ks1KKqfmH" + "144Jgh3PLxkyZRcS367kp7DrtUmnG16NpnsoNhxSXRgKbJJ7MUQR"); + r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, + SECP256K1_DECRED_NAME, &node2, NULL); + ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, + sizeof(str)); + ck_assert_str_eq(str, + "dpubZJoBFoQJ35zvEBgsfhJBssnAp8TY5gvruzQFLmyxcqRb7enVtGfSkLo" + "2CkAZJMpa6T2fx6fUtvTgXtUvSVgAZ56bEwGxQsToeZfFV8VadE1"); + r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, + SECP256K1_DECRED_NAME, &node2, NULL); + ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memzero(&node3.private_key, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); + + // init m + hdnode_deserialize( + "dpubZF4LSCdF9YKZfNzTVYhz4RBxsjYXqms8AQnMBHXZ8GUKoRSigG7kQnKiJt5pzk93Q8Fx" + "cdVBEkQZruSXduGtWnkwXzGnjbSovQ97dCxqaXc", + DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, + &node, NULL); + + // test public derivation + // [Chain m/0] + fingerprint = hdnode_fingerprint(&node); + r = hdnode_public_ckd(&node, 0); + ck_assert_int_eq(r, 1); + ck_assert_int_eq(fingerprint, 0x6a19cfb3); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "dcfe00831741a3a4803955147cdfc7053d69b167b1d03b5f9e63934217a005fd"), + 32); + ck_assert_mem_eq( + node.public_key, + fromhex( + "029555ea7bde276cd2c42c4502f40b5d16469fb310ae3aeee2a9000455f41b0866"), + 33); + hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, + sizeof(str)); + ck_assert_str_eq(str, + "dpubZHJs2Z3PtHbbpaXQCi5wBKPhU8tC5ztBKUYBCYNGKk8eZ1EmBs3MhnL" + "JbxHFMAahGnDnZT7qZxC7AXKP8PB6BDNUZgkG77moNMRmXyQ6s6s"); + r = hdnode_deserialize(str, DECRED_VERSION_PUBLIC, DECRED_VERSION_PRIVATE, + SECP256K1_DECRED_NAME, &node2, NULL); + ck_assert_int_eq(r, 0); + ck_assert_mem_eq(&node2, &node, sizeof(HDNode)); } END_TEST -START_TEST(test_ecdsa_signature) -{ - int res; - uint8_t digest[32]; - uint8_t pubkey[65]; - const ecdsa_curve *curve = &secp256k1; - - // sha2(sha2("\x18Bitcoin Signed Message:\n\x0cHello World!")) - memcpy(digest, fromhex("de4e9524586d6fce45667f9ff12f661e79870c4105fa0fb58af976619bb11432"), 32); - // r = 2: Four points should exist - res = ecdsa_recover_pub_from_sig (curve, pubkey, fromhex ("00000000000000000000000000000000000000000000000000000000000000020123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), digest, 0); - ck_assert_int_eq(res, 0); - ck_assert_mem_eq(pubkey, fromhex("043fc5bf5fec35b6ffe6fd246226d312742a8c296bfa57dd22da509a2e348529b7ddb9faf8afe1ecda3c05e7b2bda47ee1f5a87e952742b22afca560b29d972fcf"), 65); - res = ecdsa_recover_pub_from_sig (curve, pubkey, fromhex ("00000000000000000000000000000000000000000000000000000000000000020123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), digest, 1); - ck_assert_int_eq(res, 0); - ck_assert_mem_eq(pubkey, fromhex("0456d8089137b1fd0d890f8c7d4a04d0fd4520a30b19518ee87bd168ea12ed8090329274c4c6c0d9df04515776f2741eeffc30235d596065d718c3973e19711ad0"), 65); - res = ecdsa_recover_pub_from_sig (curve, pubkey, fromhex ("00000000000000000000000000000000000000000000000000000000000000020123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), digest, 2); - ck_assert_int_eq(res, 0); - ck_assert_mem_eq(pubkey, fromhex("04cee0e740f41aab39156844afef0182dea2a8026885b10454a2d539df6f6df9023abfcb0f01c50bef3c0fa8e59a998d07441e18b1c60583ef75cc8b912fb21a15"), 65); - res = ecdsa_recover_pub_from_sig (curve, pubkey, fromhex ("00000000000000000000000000000000000000000000000000000000000000020123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), digest, 3); - ck_assert_int_eq(res, 0); - ck_assert_mem_eq(pubkey, fromhex("0490d2bd2e9a564d6e1d8324fc6ad00aa4ae597684ecf4abea58bdfe7287ea4fa72968c2e5b0b40999ede3d7898d94e82c3f8dc4536a567a4bd45998c826a4c4b2"), 65); - - memcpy(digest, fromhex("0000000000000000000000000000000000000000000000000000000000000000"), 32); - // r = 7: No point P with P.x = 7, but P.x = (order + 7) exists - res = ecdsa_recover_pub_from_sig (curve, pubkey, fromhex ("00000000000000000000000000000000000000000000000000000000000000070123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), digest, 2); - ck_assert_int_eq(res, 0); - ck_assert_mem_eq(pubkey, fromhex("044d81bb47a31ffc6cf1f780ecb1e201ec47214b651650867c07f13ad06e12a1b040de78f8dbda700f4d3cd7ee21b3651a74c7661809699d2be7ea0992b0d39797"), 65); - res = ecdsa_recover_pub_from_sig (curve, pubkey, fromhex ("00000000000000000000000000000000000000000000000000000000000000070123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), digest, 3); - ck_assert_int_eq(res, 0); - ck_assert_mem_eq(pubkey, fromhex("044d81bb47a31ffc6cf1f780ecb1e201ec47214b651650867c07f13ad06e12a1b0bf21870724258ff0b2c32811de4c9ae58b3899e7f69662d41815f66c4f2c6498"), 65); - res = ecdsa_recover_pub_from_sig (curve, pubkey, fromhex ("00000000000000000000000000000000000000000000000000000000000000070123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), digest, 0); - ck_assert_int_eq(res, 1); - - memcpy(digest, fromhex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), 32); - // r = 1: Two points P with P.x = 1, but P.x = (order + 7) doesn't exist - res = ecdsa_recover_pub_from_sig (curve, pubkey, fromhex ("00000000000000000000000000000000000000000000000000000000000000010123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), digest, 0); - ck_assert_int_eq(res, 0); - ck_assert_mem_eq(pubkey, fromhex("045d330b2f89dbfca149828277bae852dd4aebfe136982cb531a88e9e7a89463fe71519f34ea8feb9490c707f14bc38c9ece51762bfd034ea014719b7c85d2871b"), 65); - res = ecdsa_recover_pub_from_sig (curve, pubkey, fromhex ("00000000000000000000000000000000000000000000000000000000000000010123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), digest, 1); - ck_assert_int_eq(res, 0); - ck_assert_mem_eq(pubkey, fromhex("049e609c3950e70d6f3e3f3c81a473b1d5ca72739d51debdd80230ae80cab05134a94285375c834a417e8115c546c41da83a263087b79ef1cae25c7b3c738daa2b"), 65); - - // r = 0 is always invalid - res = ecdsa_recover_pub_from_sig (curve, pubkey, fromhex ("00000000000000000000000000000000000000000000000000000000000000010123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), digest, 2); - ck_assert_int_eq(res, 1); - res = ecdsa_recover_pub_from_sig (curve, pubkey, fromhex ("00000000000000000000000000000000000000000000000000000000000000000123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), digest, 0); - ck_assert_int_eq(res, 1); - // r >= order is always invalid - res = ecdsa_recover_pub_from_sig (curve, pubkey, fromhex ("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641410123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), digest, 0); - ck_assert_int_eq(res, 1); - // check that overflow of r is handled - res = ecdsa_recover_pub_from_sig (curve, pubkey, fromhex ("000000000000000000000000000000014551231950B75FC4402DA1722FC9BAEE0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), digest, 2); - ck_assert_int_eq(res, 1); - // s = 0 is always invalid - res = ecdsa_recover_pub_from_sig (curve, pubkey, fromhex ("00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000"), digest, 0); - ck_assert_int_eq(res, 1); - // s >= order is always invalid - res = ecdsa_recover_pub_from_sig (curve, pubkey, fromhex ("0000000000000000000000000000000000000000000000000000000000000002fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"), digest, 0); - ck_assert_int_eq(res, 1); +START_TEST(test_ecdsa_signature) { + int res; + uint8_t digest[32]; + uint8_t pubkey[65]; + const ecdsa_curve *curve = &secp256k1; + + // sha2(sha2("\x18Bitcoin Signed Message:\n\x0cHello World!")) + memcpy( + digest, + fromhex( + "de4e9524586d6fce45667f9ff12f661e79870c4105fa0fb58af976619bb11432"), + 32); + // r = 2: Four points should exist + res = ecdsa_recover_pub_from_sig( + curve, pubkey, + fromhex( + "00000000000000000000000000000000000000000000000000000000000000020123" + "456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), + digest, 0); + ck_assert_int_eq(res, 0); + ck_assert_mem_eq( + pubkey, + fromhex( + "043fc5bf5fec35b6ffe6fd246226d312742a8c296bfa57dd22da509a2e348529b7dd" + "b9faf8afe1ecda3c05e7b2bda47ee1f5a87e952742b22afca560b29d972fcf"), + 65); + res = ecdsa_recover_pub_from_sig( + curve, pubkey, + fromhex( + "00000000000000000000000000000000000000000000000000000000000000020123" + "456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), + digest, 1); + ck_assert_int_eq(res, 0); + ck_assert_mem_eq( + pubkey, + fromhex( + "0456d8089137b1fd0d890f8c7d4a04d0fd4520a30b19518ee87bd168ea12ed809032" + "9274c4c6c0d9df04515776f2741eeffc30235d596065d718c3973e19711ad0"), + 65); + res = ecdsa_recover_pub_from_sig( + curve, pubkey, + fromhex( + "00000000000000000000000000000000000000000000000000000000000000020123" + "456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), + digest, 2); + ck_assert_int_eq(res, 0); + ck_assert_mem_eq( + pubkey, + fromhex( + "04cee0e740f41aab39156844afef0182dea2a8026885b10454a2d539df6f6df9023a" + "bfcb0f01c50bef3c0fa8e59a998d07441e18b1c60583ef75cc8b912fb21a15"), + 65); + res = ecdsa_recover_pub_from_sig( + curve, pubkey, + fromhex( + "00000000000000000000000000000000000000000000000000000000000000020123" + "456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), + digest, 3); + ck_assert_int_eq(res, 0); + ck_assert_mem_eq( + pubkey, + fromhex( + "0490d2bd2e9a564d6e1d8324fc6ad00aa4ae597684ecf4abea58bdfe7287ea4fa729" + "68c2e5b0b40999ede3d7898d94e82c3f8dc4536a567a4bd45998c826a4c4b2"), + 65); + + memcpy( + digest, + fromhex( + "0000000000000000000000000000000000000000000000000000000000000000"), + 32); + // r = 7: No point P with P.x = 7, but P.x = (order + 7) exists + res = ecdsa_recover_pub_from_sig( + curve, pubkey, + fromhex( + "00000000000000000000000000000000000000000000000000000000000000070123" + "456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), + digest, 2); + ck_assert_int_eq(res, 0); + ck_assert_mem_eq( + pubkey, + fromhex( + "044d81bb47a31ffc6cf1f780ecb1e201ec47214b651650867c07f13ad06e12a1b040" + "de78f8dbda700f4d3cd7ee21b3651a74c7661809699d2be7ea0992b0d39797"), + 65); + res = ecdsa_recover_pub_from_sig( + curve, pubkey, + fromhex( + "00000000000000000000000000000000000000000000000000000000000000070123" + "456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), + digest, 3); + ck_assert_int_eq(res, 0); + ck_assert_mem_eq( + pubkey, + fromhex( + "044d81bb47a31ffc6cf1f780ecb1e201ec47214b651650867c07f13ad06e12a1b0bf" + "21870724258ff0b2c32811de4c9ae58b3899e7f69662d41815f66c4f2c6498"), + 65); + res = ecdsa_recover_pub_from_sig( + curve, pubkey, + fromhex( + "00000000000000000000000000000000000000000000000000000000000000070123" + "456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), + digest, 0); + ck_assert_int_eq(res, 1); + + memcpy( + digest, + fromhex( + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), + 32); + // r = 1: Two points P with P.x = 1, but P.x = (order + 7) doesn't exist + res = ecdsa_recover_pub_from_sig( + curve, pubkey, + fromhex( + "00000000000000000000000000000000000000000000000000000000000000010123" + "456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), + digest, 0); + ck_assert_int_eq(res, 0); + ck_assert_mem_eq( + pubkey, + fromhex( + "045d330b2f89dbfca149828277bae852dd4aebfe136982cb531a88e9e7a89463fe71" + "519f34ea8feb9490c707f14bc38c9ece51762bfd034ea014719b7c85d2871b"), + 65); + res = ecdsa_recover_pub_from_sig( + curve, pubkey, + fromhex( + "00000000000000000000000000000000000000000000000000000000000000010123" + "456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), + digest, 1); + ck_assert_int_eq(res, 0); + ck_assert_mem_eq( + pubkey, + fromhex( + "049e609c3950e70d6f3e3f3c81a473b1d5ca72739d51debdd80230ae80cab05134a9" + "4285375c834a417e8115c546c41da83a263087b79ef1cae25c7b3c738daa2b"), + 65); + + // r = 0 is always invalid + res = ecdsa_recover_pub_from_sig( + curve, pubkey, + fromhex( + "00000000000000000000000000000000000000000000000000000000000000010123" + "456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), + digest, 2); + ck_assert_int_eq(res, 1); + res = ecdsa_recover_pub_from_sig( + curve, pubkey, + fromhex( + "00000000000000000000000000000000000000000000000000000000000000000123" + "456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), + digest, 0); + ck_assert_int_eq(res, 1); + // r >= order is always invalid + res = ecdsa_recover_pub_from_sig( + curve, pubkey, + fromhex( + "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641410123" + "456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), + digest, 0); + ck_assert_int_eq(res, 1); + // check that overflow of r is handled + res = ecdsa_recover_pub_from_sig( + curve, pubkey, + fromhex( + "000000000000000000000000000000014551231950B75FC4402DA1722FC9BAEE0123" + "456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), + digest, 2); + ck_assert_int_eq(res, 1); + // s = 0 is always invalid + res = ecdsa_recover_pub_from_sig( + curve, pubkey, + fromhex( + "00000000000000000000000000000000000000000000000000000000000000020000" + "000000000000000000000000000000000000000000000000000000000000"), + digest, 0); + ck_assert_int_eq(res, 1); + // s >= order is always invalid + res = ecdsa_recover_pub_from_sig( + curve, pubkey, + fromhex( + "0000000000000000000000000000000000000000000000000000000000000002ffff" + "fffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"), + digest, 0); + ck_assert_int_eq(res, 1); } END_TEST -#define test_deterministic(KEY, MSG, K) do { \ - sha256_Raw((uint8_t *)MSG, strlen(MSG), buf); \ - init_rfc6979(fromhex(KEY), buf, &rng); \ - generate_k_rfc6979(&k, &rng); \ - bn_write_be(&k, buf); \ - ck_assert_mem_eq(buf, fromhex(K), 32); \ -} while (0) - -START_TEST(test_rfc6979) -{ - bignum256 k; - uint8_t buf[32]; - rfc6979_state rng; - - test_deterministic("c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721", "sample", "a6e3c57dd01abe90086538398355dd4c3b17aa873382b0f24d6129493d8aad60"); - test_deterministic("cca9fbcc1b41e5a95d369eaa6ddcff73b61a4efaa279cfc6567e8daa39cbaf50", "sample", "2df40ca70e639d89528a6b670d9d48d9165fdc0febc0974056bdce192b8e16a3"); - test_deterministic("0000000000000000000000000000000000000000000000000000000000000001", "Satoshi Nakamoto", "8f8a276c19f4149656b280621e358cce24f5f52542772691ee69063b74f15d15"); - test_deterministic("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", "Satoshi Nakamoto", "33a19b60e25fb6f4435af53a3d42d493644827367e6453928554f43e49aa6f90"); - test_deterministic("f8b8af8ce3c7cca5e300d33939540c10d45ce001b8f252bfbc57ba0342904181", "Alan Turing", "525a82b70e67874398067543fd84c83d30c175fdc45fdeee082fe13b1d7cfdf1"); - test_deterministic("0000000000000000000000000000000000000000000000000000000000000001", "All those moments will be lost in time, like tears in rain. Time to die...", "38aa22d72376b4dbc472e06c3ba403ee0a394da63fc58d88686c611aba98d6b3"); - test_deterministic("e91671c46231f833a6406ccbea0e3e392c76c167bac1cb013f6f1013980455c2", "There is a computer disease that anybody who works with computers knows about. It's a very serious disease and it interferes completely with the work. The trouble with computers is that you 'play' with them!", "1f4b84c23a86a221d233f2521be018d9318639d5b8bbd6374a8a59232d16ad3d"); +#define test_deterministic(KEY, MSG, K) \ + do { \ + sha256_Raw((uint8_t *)MSG, strlen(MSG), buf); \ + init_rfc6979(fromhex(KEY), buf, &rng); \ + generate_k_rfc6979(&k, &rng); \ + bn_write_be(&k, buf); \ + ck_assert_mem_eq(buf, fromhex(K), 32); \ + } while (0) + +START_TEST(test_rfc6979) { + bignum256 k; + uint8_t buf[32]; + rfc6979_state rng; + + test_deterministic( + "c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721", + "sample", + "a6e3c57dd01abe90086538398355dd4c3b17aa873382b0f24d6129493d8aad60"); + test_deterministic( + "cca9fbcc1b41e5a95d369eaa6ddcff73b61a4efaa279cfc6567e8daa39cbaf50", + "sample", + "2df40ca70e639d89528a6b670d9d48d9165fdc0febc0974056bdce192b8e16a3"); + test_deterministic( + "0000000000000000000000000000000000000000000000000000000000000001", + "Satoshi Nakamoto", + "8f8a276c19f4149656b280621e358cce24f5f52542772691ee69063b74f15d15"); + test_deterministic( + "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", + "Satoshi Nakamoto", + "33a19b60e25fb6f4435af53a3d42d493644827367e6453928554f43e49aa6f90"); + test_deterministic( + "f8b8af8ce3c7cca5e300d33939540c10d45ce001b8f252bfbc57ba0342904181", + "Alan Turing", + "525a82b70e67874398067543fd84c83d30c175fdc45fdeee082fe13b1d7cfdf1"); + test_deterministic( + "0000000000000000000000000000000000000000000000000000000000000001", + "All those moments will be lost in time, like tears in rain. Time to " + "die...", + "38aa22d72376b4dbc472e06c3ba403ee0a394da63fc58d88686c611aba98d6b3"); + test_deterministic( + "e91671c46231f833a6406ccbea0e3e392c76c167bac1cb013f6f1013980455c2", + "There is a computer disease that anybody who works with computers knows " + "about. It's a very serious disease and it interferes completely with " + "the work. The trouble with computers is that you 'play' with them!", + "1f4b84c23a86a221d233f2521be018d9318639d5b8bbd6374a8a59232d16ad3d"); } END_TEST -// test vectors from http://www.inconteam.com/software-development/41-encryption/55-aes-test-vectors -START_TEST(test_aes) -{ - aes_encrypt_ctx ctxe; - aes_decrypt_ctx ctxd; - uint8_t ibuf[16], obuf[16], iv[16], cbuf[16]; - const char **ivp, **plainp, **cipherp; - - // ECB - static const char *ecb_vector[] = { - // plain cipher - "6bc1bee22e409f96e93d7e117393172a", "f3eed1bdb5d2a03c064b5a7e3db181f8", - "ae2d8a571e03ac9c9eb76fac45af8e51", "591ccb10d410ed26dc5ba74a31362870", - "30c81c46a35ce411e5fbc1191a0a52ef", "b6ed21b99ca6f4f9f153e7b1beafed1d", - "f69f2445df4f9b17ad2b417be66c3710", "23304b7a39f9f3ff067d8d8f9e24ecc7", - 0, 0, - }; - plainp = ecb_vector; - cipherp = ecb_vector + 1; - while (*plainp && *cipherp) { - // encrypt - aes_encrypt_key256(fromhex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), &ctxe); - memcpy(ibuf, fromhex(*plainp), 16); - aes_ecb_encrypt(ibuf, obuf, 16, &ctxe); - ck_assert_mem_eq(obuf, fromhex(*cipherp), 16); - // decrypt - aes_decrypt_key256(fromhex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), &ctxd); - memcpy(ibuf, fromhex(*cipherp), 16); - aes_ecb_decrypt(ibuf, obuf, 16, &ctxd); - ck_assert_mem_eq(obuf, fromhex(*plainp), 16); - plainp += 2; cipherp += 2; - } - - // CBC - static const char *cbc_vector[] = { - // iv plain cipher - "000102030405060708090A0B0C0D0E0F", "6bc1bee22e409f96e93d7e117393172a", "f58c4c04d6e5f1ba779eabfb5f7bfbd6", - "F58C4C04D6E5F1BA779EABFB5F7BFBD6", "ae2d8a571e03ac9c9eb76fac45af8e51", "9cfc4e967edb808d679f777bc6702c7d", - "9CFC4E967EDB808D679F777BC6702C7D", "30c81c46a35ce411e5fbc1191a0a52ef", "39f23369a9d9bacfa530e26304231461", - "39F23369A9D9BACFA530E26304231461", "f69f2445df4f9b17ad2b417be66c3710", "b2eb05e2c39be9fcda6c19078c6a9d1b", - 0, 0, 0, - }; - ivp = cbc_vector; - plainp = cbc_vector + 1; - cipherp = cbc_vector + 2; - while (*plainp && *cipherp) { - // encrypt - aes_encrypt_key256(fromhex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), &ctxe); - memcpy(iv, fromhex(*ivp), 16); - memcpy(ibuf, fromhex(*plainp), 16); - aes_cbc_encrypt(ibuf, obuf, 16, iv, &ctxe); - ck_assert_mem_eq(obuf, fromhex(*cipherp), 16); - // decrypt - aes_decrypt_key256(fromhex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), &ctxd); - memcpy(iv, fromhex(*ivp), 16); - memcpy(ibuf, fromhex(*cipherp), 16); - aes_cbc_decrypt(ibuf, obuf, 16, iv, &ctxd); - ck_assert_mem_eq(obuf, fromhex(*plainp), 16); - ivp += 3; plainp += 3; cipherp += 3; - } - - // CFB - static const char *cfb_vector[] = { - "000102030405060708090A0B0C0D0E0F", "6bc1bee22e409f96e93d7e117393172a", "DC7E84BFDA79164B7ECD8486985D3860", - "DC7E84BFDA79164B7ECD8486985D3860", "ae2d8a571e03ac9c9eb76fac45af8e51", "39ffed143b28b1c832113c6331e5407b", - "39FFED143B28B1C832113C6331E5407B", "30c81c46a35ce411e5fbc1191a0a52ef", "df10132415e54b92a13ed0a8267ae2f9", - "DF10132415E54B92A13ED0A8267AE2F9", "f69f2445df4f9b17ad2b417be66c3710", "75a385741ab9cef82031623d55b1e471", - 0, 0, 0, - }; - ivp = cfb_vector; - plainp = cfb_vector + 1; - cipherp = cfb_vector + 2; - while (*plainp && *cipherp) { - // encrypt - aes_encrypt_key256(fromhex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), &ctxe); - memcpy(iv, fromhex(*ivp), 16); - memcpy(ibuf, fromhex(*plainp), 16); - aes_cfb_encrypt(ibuf, obuf, 16, iv, &ctxe); - ck_assert_mem_eq(obuf, fromhex(*cipherp), 16); - // decrypt (uses encryption) - aes_encrypt_key256(fromhex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), &ctxe); - memcpy(iv, fromhex(*ivp), 16); - memcpy(ibuf, fromhex(*cipherp), 16); - aes_cfb_decrypt(ibuf, obuf, 16, iv, &ctxe); - ck_assert_mem_eq(obuf, fromhex(*plainp), 16); - ivp += 3; plainp += 3; cipherp += 3; - } - - // OFB - static const char *ofb_vector[] = { - "000102030405060708090A0B0C0D0E0F", "6bc1bee22e409f96e93d7e117393172a", "dc7e84bfda79164b7ecd8486985d3860", - "B7BF3A5DF43989DD97F0FA97EBCE2F4A", "ae2d8a571e03ac9c9eb76fac45af8e51", "4febdc6740d20b3ac88f6ad82a4fb08d", - "E1C656305ED1A7A6563805746FE03EDC", "30c81c46a35ce411e5fbc1191a0a52ef", "71ab47a086e86eedf39d1c5bba97c408", - "41635BE625B48AFC1666DD42A09D96E7", "f69f2445df4f9b17ad2b417be66c3710", "0126141d67f37be8538f5a8be740e484", - 0, 0, 0, - }; - ivp = ofb_vector; - plainp = ofb_vector + 1; - cipherp = ofb_vector + 2; - while (*plainp && *cipherp) { - // encrypt - aes_encrypt_key256(fromhex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), &ctxe); - memcpy(iv, fromhex(*ivp), 16); - memcpy(ibuf, fromhex(*plainp), 16); - aes_ofb_encrypt(ibuf, obuf, 16, iv, &ctxe); - ck_assert_mem_eq(obuf, fromhex(*cipherp), 16); - // decrypt (uses encryption) - aes_encrypt_key256(fromhex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), &ctxe); - memcpy(iv, fromhex(*ivp), 16); - memcpy(ibuf, fromhex(*cipherp), 16); - aes_ofb_decrypt(ibuf, obuf, 16, iv, &ctxe); - ck_assert_mem_eq(obuf, fromhex(*plainp), 16); - ivp += 3; plainp += 3; cipherp += 3; - } - - // CTR - static const char *ctr_vector[] = { - // plain cipher - "6bc1bee22e409f96e93d7e117393172a", "601ec313775789a5b7a7f504bbf3d228", - "ae2d8a571e03ac9c9eb76fac45af8e51", "f443e3ca4d62b59aca84e990cacaf5c5", - "30c81c46a35ce411e5fbc1191a0a52ef", "2b0930daa23de94ce87017ba2d84988d", - "f69f2445df4f9b17ad2b417be66c3710", "dfc9c58db67aada613c2dd08457941a6", - 0, 0, - }; - // encrypt - plainp = ctr_vector; - cipherp = ctr_vector + 1; - memcpy(cbuf, fromhex("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"), 16); - aes_encrypt_key256(fromhex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), &ctxe); - while (*plainp && *cipherp) { - memcpy(ibuf, fromhex(*plainp), 16); - aes_ctr_encrypt(ibuf, obuf, 16, cbuf, aes_ctr_cbuf_inc, &ctxe); - ck_assert_mem_eq(obuf, fromhex(*cipherp), 16); - plainp += 2; cipherp += 2; - } - // decrypt (uses encryption) - plainp = ctr_vector; - cipherp = ctr_vector + 1; - memcpy(cbuf, fromhex("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"), 16); - aes_encrypt_key256(fromhex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), &ctxe); - while (*plainp && *cipherp) { - memcpy(ibuf, fromhex(*cipherp), 16); - aes_ctr_decrypt(ibuf, obuf, 16, cbuf, aes_ctr_cbuf_inc, &ctxe); - ck_assert_mem_eq(obuf, fromhex(*plainp), 16); - plainp += 2; cipherp += 2; - } +// test vectors from +// http://www.inconteam.com/software-development/41-encryption/55-aes-test-vectors +START_TEST(test_aes) { + aes_encrypt_ctx ctxe; + aes_decrypt_ctx ctxd; + uint8_t ibuf[16], obuf[16], iv[16], cbuf[16]; + const char **ivp, **plainp, **cipherp; + + // ECB + static const char *ecb_vector[] = { + // plain cipher + "6bc1bee22e409f96e93d7e117393172a", + "f3eed1bdb5d2a03c064b5a7e3db181f8", + "ae2d8a571e03ac9c9eb76fac45af8e51", + "591ccb10d410ed26dc5ba74a31362870", + "30c81c46a35ce411e5fbc1191a0a52ef", + "b6ed21b99ca6f4f9f153e7b1beafed1d", + "f69f2445df4f9b17ad2b417be66c3710", + "23304b7a39f9f3ff067d8d8f9e24ecc7", + 0, + 0, + }; + plainp = ecb_vector; + cipherp = ecb_vector + 1; + while (*plainp && *cipherp) { + // encrypt + aes_encrypt_key256( + fromhex( + "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), + &ctxe); + memcpy(ibuf, fromhex(*plainp), 16); + aes_ecb_encrypt(ibuf, obuf, 16, &ctxe); + ck_assert_mem_eq(obuf, fromhex(*cipherp), 16); + // decrypt + aes_decrypt_key256( + fromhex( + "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), + &ctxd); + memcpy(ibuf, fromhex(*cipherp), 16); + aes_ecb_decrypt(ibuf, obuf, 16, &ctxd); + ck_assert_mem_eq(obuf, fromhex(*plainp), 16); + plainp += 2; + cipherp += 2; + } + + // CBC + static const char *cbc_vector[] = { + // iv plain cipher + "000102030405060708090A0B0C0D0E0F", + "6bc1bee22e409f96e93d7e117393172a", + "f58c4c04d6e5f1ba779eabfb5f7bfbd6", + "F58C4C04D6E5F1BA779EABFB5F7BFBD6", + "ae2d8a571e03ac9c9eb76fac45af8e51", + "9cfc4e967edb808d679f777bc6702c7d", + "9CFC4E967EDB808D679F777BC6702C7D", + "30c81c46a35ce411e5fbc1191a0a52ef", + "39f23369a9d9bacfa530e26304231461", + "39F23369A9D9BACFA530E26304231461", + "f69f2445df4f9b17ad2b417be66c3710", + "b2eb05e2c39be9fcda6c19078c6a9d1b", + 0, + 0, + 0, + }; + ivp = cbc_vector; + plainp = cbc_vector + 1; + cipherp = cbc_vector + 2; + while (*plainp && *cipherp) { + // encrypt + aes_encrypt_key256( + fromhex( + "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), + &ctxe); + memcpy(iv, fromhex(*ivp), 16); + memcpy(ibuf, fromhex(*plainp), 16); + aes_cbc_encrypt(ibuf, obuf, 16, iv, &ctxe); + ck_assert_mem_eq(obuf, fromhex(*cipherp), 16); + // decrypt + aes_decrypt_key256( + fromhex( + "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), + &ctxd); + memcpy(iv, fromhex(*ivp), 16); + memcpy(ibuf, fromhex(*cipherp), 16); + aes_cbc_decrypt(ibuf, obuf, 16, iv, &ctxd); + ck_assert_mem_eq(obuf, fromhex(*plainp), 16); + ivp += 3; + plainp += 3; + cipherp += 3; + } + + // CFB + static const char *cfb_vector[] = { + "000102030405060708090A0B0C0D0E0F", + "6bc1bee22e409f96e93d7e117393172a", + "DC7E84BFDA79164B7ECD8486985D3860", + "DC7E84BFDA79164B7ECD8486985D3860", + "ae2d8a571e03ac9c9eb76fac45af8e51", + "39ffed143b28b1c832113c6331e5407b", + "39FFED143B28B1C832113C6331E5407B", + "30c81c46a35ce411e5fbc1191a0a52ef", + "df10132415e54b92a13ed0a8267ae2f9", + "DF10132415E54B92A13ED0A8267AE2F9", + "f69f2445df4f9b17ad2b417be66c3710", + "75a385741ab9cef82031623d55b1e471", + 0, + 0, + 0, + }; + ivp = cfb_vector; + plainp = cfb_vector + 1; + cipherp = cfb_vector + 2; + while (*plainp && *cipherp) { + // encrypt + aes_encrypt_key256( + fromhex( + "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), + &ctxe); + memcpy(iv, fromhex(*ivp), 16); + memcpy(ibuf, fromhex(*plainp), 16); + aes_cfb_encrypt(ibuf, obuf, 16, iv, &ctxe); + ck_assert_mem_eq(obuf, fromhex(*cipherp), 16); + // decrypt (uses encryption) + aes_encrypt_key256( + fromhex( + "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), + &ctxe); + memcpy(iv, fromhex(*ivp), 16); + memcpy(ibuf, fromhex(*cipherp), 16); + aes_cfb_decrypt(ibuf, obuf, 16, iv, &ctxe); + ck_assert_mem_eq(obuf, fromhex(*plainp), 16); + ivp += 3; + plainp += 3; + cipherp += 3; + } + + // OFB + static const char *ofb_vector[] = { + "000102030405060708090A0B0C0D0E0F", + "6bc1bee22e409f96e93d7e117393172a", + "dc7e84bfda79164b7ecd8486985d3860", + "B7BF3A5DF43989DD97F0FA97EBCE2F4A", + "ae2d8a571e03ac9c9eb76fac45af8e51", + "4febdc6740d20b3ac88f6ad82a4fb08d", + "E1C656305ED1A7A6563805746FE03EDC", + "30c81c46a35ce411e5fbc1191a0a52ef", + "71ab47a086e86eedf39d1c5bba97c408", + "41635BE625B48AFC1666DD42A09D96E7", + "f69f2445df4f9b17ad2b417be66c3710", + "0126141d67f37be8538f5a8be740e484", + 0, + 0, + 0, + }; + ivp = ofb_vector; + plainp = ofb_vector + 1; + cipherp = ofb_vector + 2; + while (*plainp && *cipherp) { + // encrypt + aes_encrypt_key256( + fromhex( + "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), + &ctxe); + memcpy(iv, fromhex(*ivp), 16); + memcpy(ibuf, fromhex(*plainp), 16); + aes_ofb_encrypt(ibuf, obuf, 16, iv, &ctxe); + ck_assert_mem_eq(obuf, fromhex(*cipherp), 16); + // decrypt (uses encryption) + aes_encrypt_key256( + fromhex( + "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), + &ctxe); + memcpy(iv, fromhex(*ivp), 16); + memcpy(ibuf, fromhex(*cipherp), 16); + aes_ofb_decrypt(ibuf, obuf, 16, iv, &ctxe); + ck_assert_mem_eq(obuf, fromhex(*plainp), 16); + ivp += 3; + plainp += 3; + cipherp += 3; + } + + // CTR + static const char *ctr_vector[] = { + // plain cipher + "6bc1bee22e409f96e93d7e117393172a", + "601ec313775789a5b7a7f504bbf3d228", + "ae2d8a571e03ac9c9eb76fac45af8e51", + "f443e3ca4d62b59aca84e990cacaf5c5", + "30c81c46a35ce411e5fbc1191a0a52ef", + "2b0930daa23de94ce87017ba2d84988d", + "f69f2445df4f9b17ad2b417be66c3710", + "dfc9c58db67aada613c2dd08457941a6", + 0, + 0, + }; + // encrypt + plainp = ctr_vector; + cipherp = ctr_vector + 1; + memcpy(cbuf, fromhex("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"), 16); + aes_encrypt_key256( + fromhex( + "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), + &ctxe); + while (*plainp && *cipherp) { + memcpy(ibuf, fromhex(*plainp), 16); + aes_ctr_encrypt(ibuf, obuf, 16, cbuf, aes_ctr_cbuf_inc, &ctxe); + ck_assert_mem_eq(obuf, fromhex(*cipherp), 16); + plainp += 2; + cipherp += 2; + } + // decrypt (uses encryption) + plainp = ctr_vector; + cipherp = ctr_vector + 1; + memcpy(cbuf, fromhex("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"), 16); + aes_encrypt_key256( + fromhex( + "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), + &ctxe); + while (*plainp && *cipherp) { + memcpy(ibuf, fromhex(*cipherp), 16); + aes_ctr_decrypt(ibuf, obuf, 16, cbuf, aes_ctr_cbuf_inc, &ctxe); + ck_assert_mem_eq(obuf, fromhex(*plainp), 16); + plainp += 2; + cipherp += 2; + } } END_TEST -#define TEST1 "abc" -#define TEST2_1 \ - "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" -#define TEST2_2a \ - "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn" -#define TEST2_2b \ - "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu" -#define TEST2_2 TEST2_2a TEST2_2b -#define TEST3 "a" /* times 1000000 */ -#define TEST4a "01234567012345670123456701234567" -#define TEST4b "01234567012345670123456701234567" - /* an exact multiple of 512 bits */ -#define TEST4 TEST4a TEST4b /* times 10 */ - -#define TEST7_1 \ - "\x49\xb2\xae\xc2\x59\x4b\xbe\x3a\x3b\x11\x75\x42\xd9\x4a\xc8" +#define TEST1 "abc" +#define TEST2_1 "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" +#define TEST2_2a "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn" +#define TEST2_2b "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu" +#define TEST2_2 TEST2_2a TEST2_2b +#define TEST3 "a" /* times 1000000 */ +#define TEST4a "01234567012345670123456701234567" +#define TEST4b "01234567012345670123456701234567" +/* an exact multiple of 512 bits */ +#define TEST4 TEST4a TEST4b /* times 10 */ + +#define TEST7_1 "\x49\xb2\xae\xc2\x59\x4b\xbe\x3a\x3b\x11\x75\x42\xd9\x4a\xc8" #define TEST8_1 \ "\x9a\x7d\xfd\xf1\xec\xea\xd0\x6e\xd6\x46\xaa\x55\xfe\x75\x71\x46" -#define TEST9_1 \ +#define TEST9_1 \ "\x65\xf9\x32\x99\x5b\xa4\xce\x2c\xb1\xb4\xa2\xe7\x1a\xe7\x02\x20" \ "\xaa\xce\xc8\x96\x2d\xd4\x49\x9c\xbd\x7c\x88\x7a\x94\xea\xaa\x10" \ "\x1e\xa5\xaa\xbc\x52\x9b\x4e\x7e\x43\x66\x5a\x5a\xf2\xcd\x03\xfe" \ "\x67\x8e\xa6\xa5\x00\x5b\xba\x3b\x08\x22\x04\xc2\x8b\x91\x09\xf4" \ "\x69\xda\xc9\x2a\xaa\xb3\xaa\x7c\x11\xa1\xb3\x2a" -#define TEST10_1 \ +#define TEST10_1 \ "\xf7\x8f\x92\x14\x1b\xcd\x17\x0a\xe8\x9b\x4f\xba\x15\xa1\xd5\x9f" \ "\x3f\xd8\x4d\x22\x3c\x92\x51\xbd\xac\xbb\xae\x61\xd0\x5e\xd1\x15" \ "\xa0\x6a\x7c\xe1\x17\xb7\xbe\xea\xd2\x44\x21\xde\xd9\xc3\x25\x92" \ @@ -2200,68 +3750,69 @@ END_TEST "\x6a\x0f\x85\xe6\xa9\x1d\x39\x6f\x5b\x5c\xbe\x57\x7f\x9b\x38\x80" \ "\x7c\x7d\x52\x3d\x6d\x79\x2f\x6e\xbc\x24\xa4\xec\xf2\xb3\xa4\x27" \ "\xcd\xbb\xfb" -#define length(x) (sizeof(x)-1) +#define length(x) (sizeof(x) - 1) // test vectors from rfc-4634 -START_TEST(test_sha1) -{ - struct { - const char* test; - int length; - int repeatcount; - int extrabits; - int numberExtrabits; - const char* result; - } tests[] = { - /* 1 */ { TEST1, length(TEST1), 1, 0, 0, - "A9993E364706816ABA3E25717850C26C9CD0D89D" }, - /* 2 */ { TEST2_1, length(TEST2_1), 1, 0, 0, - "84983E441C3BD26EBAAE4AA1F95129E5E54670F1" }, - /* 3 */ { TEST3, length(TEST3), 1000000, 0, 0, - "34AA973CD4C4DAA4F61EEB2BDBAD27316534016F" }, - /* 4 */ { TEST4, length(TEST4), 10, 0, 0, - "DEA356A2CDDD90C7A7ECEDC5EBB563934F460452" }, - /* 5 */ { "", 0, 0, 0x98, 5, - "29826B003B906E660EFF4027CE98AF3531AC75BA" }, - /* 6 */ { "\x5e", 1, 1, 0, 0, - "5E6F80A34A9798CAFC6A5DB96CC57BA4C4DB59C2" }, - /* 7 */ { TEST7_1, length(TEST7_1), 1, 0x80, 3, - "6239781E03729919C01955B3FFA8ACB60B988340" }, - /* 8 */ { TEST8_1, length(TEST8_1), 1, 0, 0, - "82ABFF6605DBE1C17DEF12A394FA22A82B544A35" }, - /* 9 */ { TEST9_1, length(TEST9_1), 1, 0xE0, 3, - "8C5B2A5DDAE5A97FC7F9D85661C672ADBF7933D4" }, - /* 10 */ { TEST10_1, length(TEST10_1), 1, 0, 0, - "CB0082C8F197D260991BA6A460E76E202BAD27B3" } - }; - - for (int i = 0; i < 10; i++) { - SHA1_CTX ctx; - uint8_t digest[SHA1_DIGEST_LENGTH]; - sha1_Init(&ctx); - /* extra bits are not supported */ - if (tests[i].numberExtrabits) - continue; - for (int j = 0; j < tests[i].repeatcount; j++) { - sha1_Update(&ctx, (const uint8_t*) tests[i].test, tests[i].length); - } - sha1_Final(&ctx, digest); - ck_assert_mem_eq(digest, fromhex(tests[i].result), SHA1_DIGEST_LENGTH); - } +START_TEST(test_sha1) { + struct { + const char *test; + int length; + int repeatcount; + int extrabits; + int numberExtrabits; + const char *result; + } tests[] = { + /* 1 */ {TEST1, length(TEST1), 1, 0, 0, + "A9993E364706816ABA3E25717850C26C9CD0D89D"}, + /* 2 */ + {TEST2_1, length(TEST2_1), 1, 0, 0, + "84983E441C3BD26EBAAE4AA1F95129E5E54670F1"}, + /* 3 */ + {TEST3, length(TEST3), 1000000, 0, 0, + "34AA973CD4C4DAA4F61EEB2BDBAD27316534016F"}, + /* 4 */ + {TEST4, length(TEST4), 10, 0, 0, + "DEA356A2CDDD90C7A7ECEDC5EBB563934F460452"}, + /* 5 */ {"", 0, 0, 0x98, 5, "29826B003B906E660EFF4027CE98AF3531AC75BA"}, + /* 6 */ {"\x5e", 1, 1, 0, 0, "5E6F80A34A9798CAFC6A5DB96CC57BA4C4DB59C2"}, + /* 7 */ + {TEST7_1, length(TEST7_1), 1, 0x80, 3, + "6239781E03729919C01955B3FFA8ACB60B988340"}, + /* 8 */ + {TEST8_1, length(TEST8_1), 1, 0, 0, + "82ABFF6605DBE1C17DEF12A394FA22A82B544A35"}, + /* 9 */ + {TEST9_1, length(TEST9_1), 1, 0xE0, 3, + "8C5B2A5DDAE5A97FC7F9D85661C672ADBF7933D4"}, + /* 10 */ + {TEST10_1, length(TEST10_1), 1, 0, 0, + "CB0082C8F197D260991BA6A460E76E202BAD27B3"}}; + + for (int i = 0; i < 10; i++) { + SHA1_CTX ctx; + uint8_t digest[SHA1_DIGEST_LENGTH]; + sha1_Init(&ctx); + /* extra bits are not supported */ + if (tests[i].numberExtrabits) continue; + for (int j = 0; j < tests[i].repeatcount; j++) { + sha1_Update(&ctx, (const uint8_t *)tests[i].test, tests[i].length); + } + sha1_Final(&ctx, digest); + ck_assert_mem_eq(digest, fromhex(tests[i].result), SHA1_DIGEST_LENGTH); + } } END_TEST -#define TEST7_256 \ - "\xbe\x27\x46\xc6\xdb\x52\x76\x5f\xdb\x2f\x88\x70\x0f\x9a\x73" +#define TEST7_256 "\xbe\x27\x46\xc6\xdb\x52\x76\x5f\xdb\x2f\x88\x70\x0f\x9a\x73" #define TEST8_256 \ "\xe3\xd7\x25\x70\xdc\xdd\x78\x7c\xe3\x88\x7a\xb2\xcd\x68\x46\x52" -#define TEST9_256 \ +#define TEST9_256 \ "\x3e\x74\x03\x71\xc8\x10\xc2\xb9\x9f\xc0\x4e\x80\x49\x07\xef\x7c" \ "\xf2\x6b\xe2\x8b\x57\xcb\x58\xa3\xe2\xf3\xc0\x07\x16\x6e\x49\xc1" \ "\x2e\x9b\xa3\x4c\x01\x04\x06\x91\x29\xea\x76\x15\x64\x25\x45\x70" \ "\x3a\x2b\xd9\x01\xe1\x6e\xb0\xe0\x5d\xeb\xa0\x14\xeb\xff\x64\x06" \ "\xa0\x7d\x54\x36\x4e\xff\x74\x2d\xa7\x79\xb0\xb3" -#define TEST10_256 \ +#define TEST10_256 \ "\x83\x26\x75\x4e\x22\x77\x37\x2f\x4f\xc1\x2b\x20\x52\x7a\xfe\xf0" \ "\x4d\x8a\x05\x69\x71\xb1\x1a\xd5\x71\x23\xa7\xc1\x37\x76\x00\x00" \ "\xd7\xbe\xf6\xf3\xc1\xf7\xa9\x08\x3a\xa3\x9d\x81\x0d\xb3\x10\x77" \ @@ -2275,59 +3826,75 @@ END_TEST "\x3d\x54\xd6" // test vectors from rfc-4634 -START_TEST(test_sha256) -{ - struct { - const char* test; - int length; - int repeatcount; - int extrabits; - int numberExtrabits; - const char* result; - } tests[] = { - /* 1 */ { TEST1, length(TEST1), 1, 0, 0, "BA7816BF8F01CFEA4141" - "40DE5DAE2223B00361A396177A9CB410FF61F20015AD" }, - /* 2 */ { TEST2_1, length(TEST2_1), 1, 0, 0, "248D6A61D20638B8" - "E5C026930C3E6039A33CE45964FF2167F6ECEDD419DB06C1" }, - /* 3 */ { TEST3, length(TEST3), 1000000, 0, 0, "CDC76E5C9914FB92" - "81A1C7E284D73E67F1809A48A497200E046D39CCC7112CD0" }, - /* 4 */ { TEST4, length(TEST4), 10, 0, 0, "594847328451BDFA" - "85056225462CC1D867D877FB388DF0CE35F25AB5562BFBB5" }, - /* 5 */ { "", 0, 0, 0x68, 5, "D6D3E02A31A84A8CAA9718ED6C2057BE" - "09DB45E7823EB5079CE7A573A3760F95" }, - /* 6 */ { "\x19", 1, 1, 0, 0, "68AA2E2EE5DFF96E3355E6C7EE373E3D" - "6A4E17F75F9518D843709C0C9BC3E3D4" }, - /* 7 */ { TEST7_256, length(TEST7_256), 1, 0x60, 3, "77EC1DC8" - "9C821FF2A1279089FA091B35B8CD960BCAF7DE01C6A7680756BEB972" }, - /* 8 */ { TEST8_256, length(TEST8_256), 1, 0, 0, "175EE69B02BA" - "9B58E2B0A5FD13819CEA573F3940A94F825128CF4209BEABB4E8" }, - /* 9 */ { TEST9_256, length(TEST9_256), 1, 0xA0, 3, "3E9AD646" - "8BBBAD2AC3C2CDC292E018BA5FD70B960CF1679777FCE708FDB066E9" }, - /* 10 */ { TEST10_256, length(TEST10_256), 1, 0, 0, "97DBCA7D" - "F46D62C8A422C941DD7E835B8AD3361763F7E9B2D95F4F0DA6E1CCBC" }, - }; - - for (int i = 0; i < 10; i++) { - SHA256_CTX ctx; - uint8_t digest[SHA256_DIGEST_LENGTH]; - sha256_Init(&ctx); - /* extra bits are not supported */ - if (tests[i].numberExtrabits) - continue; - for (int j = 0; j < tests[i].repeatcount; j++) { - sha256_Update(&ctx, (const uint8_t*) tests[i].test, tests[i].length); - } - sha256_Final(&ctx, digest); - ck_assert_mem_eq(digest, fromhex(tests[i].result), SHA256_DIGEST_LENGTH); - } +START_TEST(test_sha256) { + struct { + const char *test; + int length; + int repeatcount; + int extrabits; + int numberExtrabits; + const char *result; + } tests[] = { + /* 1 */ {TEST1, length(TEST1), 1, 0, 0, + "BA7816BF8F01CFEA4141" + "40DE5DAE2223B00361A396177A9CB410FF61F20015AD"}, + /* 2 */ + {TEST2_1, length(TEST2_1), 1, 0, 0, + "248D6A61D20638B8" + "E5C026930C3E6039A33CE45964FF2167F6ECEDD419DB06C1"}, + /* 3 */ + {TEST3, length(TEST3), 1000000, 0, 0, + "CDC76E5C9914FB92" + "81A1C7E284D73E67F1809A48A497200E046D39CCC7112CD0"}, + /* 4 */ + {TEST4, length(TEST4), 10, 0, 0, + "594847328451BDFA" + "85056225462CC1D867D877FB388DF0CE35F25AB5562BFBB5"}, + /* 5 */ + {"", 0, 0, 0x68, 5, + "D6D3E02A31A84A8CAA9718ED6C2057BE" + "09DB45E7823EB5079CE7A573A3760F95"}, + /* 6 */ + {"\x19", 1, 1, 0, 0, + "68AA2E2EE5DFF96E3355E6C7EE373E3D" + "6A4E17F75F9518D843709C0C9BC3E3D4"}, + /* 7 */ + {TEST7_256, length(TEST7_256), 1, 0x60, 3, + "77EC1DC8" + "9C821FF2A1279089FA091B35B8CD960BCAF7DE01C6A7680756BEB972"}, + /* 8 */ + {TEST8_256, length(TEST8_256), 1, 0, 0, + "175EE69B02BA" + "9B58E2B0A5FD13819CEA573F3940A94F825128CF4209BEABB4E8"}, + /* 9 */ + {TEST9_256, length(TEST9_256), 1, 0xA0, 3, + "3E9AD646" + "8BBBAD2AC3C2CDC292E018BA5FD70B960CF1679777FCE708FDB066E9"}, + /* 10 */ + {TEST10_256, length(TEST10_256), 1, 0, 0, + "97DBCA7D" + "F46D62C8A422C941DD7E835B8AD3361763F7E9B2D95F4F0DA6E1CCBC"}, + }; + + for (int i = 0; i < 10; i++) { + SHA256_CTX ctx; + uint8_t digest[SHA256_DIGEST_LENGTH]; + sha256_Init(&ctx); + /* extra bits are not supported */ + if (tests[i].numberExtrabits) continue; + for (int j = 0; j < tests[i].repeatcount; j++) { + sha256_Update(&ctx, (const uint8_t *)tests[i].test, tests[i].length); + } + sha256_Final(&ctx, digest); + ck_assert_mem_eq(digest, fromhex(tests[i].result), SHA256_DIGEST_LENGTH); + } } END_TEST -#define TEST7_512 \ - "\x08\xec\xb5\x2e\xba\xe1\xf7\x42\x2d\xb6\x2b\xcd\x54\x26\x70" +#define TEST7_512 "\x08\xec\xb5\x2e\xba\xe1\xf7\x42\x2d\xb6\x2b\xcd\x54\x26\x70" #define TEST8_512 \ "\x8d\x4e\x3c\x0e\x38\x89\x19\x14\x91\x81\x6e\x9d\x98\xbf\xf0\xa0" -#define TEST9_512 \ +#define TEST9_512 \ "\x3a\xdd\xec\x85\x59\x32\x16\xd1\x61\x9a\xa0\x2d\x97\x56\x97\x0b" \ "\xfc\x70\xac\xe2\x74\x4f\x7c\x6b\x27\x88\x15\x10\x28\xf7\xb6\xa2" \ "\x55\x0f\xd7\x4a\x7e\x6e\x69\xc2\xc9\xb4\x5f\xc4\x54\x96\x6d\xc3" \ @@ -2337,7 +3904,7 @@ END_TEST "\x4e\xe4\x14\x5b\xee\x2f\xf4\xbb\x12\x3a\xab\x49\x8d\x9d\x44\x79" \ "\x4f\x99\xcc\xad\x89\xa9\xa1\x62\x12\x59\xed\xa7\x0a\x5b\x6d\xd4" \ "\xbd\xd8\x77\x78\xc9\x04\x3b\x93\x84\xf5\x49\x06" -#define TEST10_512 \ +#define TEST10_512 \ "\xa5\x5f\x20\xc4\x11\xaa\xd1\x32\x80\x7a\x50\x2d\x65\x82\x4e\x31" \ "\xa2\x30\x54\x32\xaa\x3d\x06\xd3\xe2\x82\xa8\xd8\x4e\x0d\xe1\xde" \ "\x69\x74\xbf\x49\x54\x69\xfc\x7f\x33\x8f\x80\x54\xd5\x8c\x26\xc4" \ @@ -2355,2456 +3922,4408 @@ END_TEST "\xfb\x40\xd2" // test vectors from rfc-4634 -START_TEST(test_sha512) -{ - struct { - const char* test; - int length; - int repeatcount; - int extrabits; - int numberExtrabits; - const char* result; - } tests[] = { - /* 1 */ { TEST1, length(TEST1), 1, 0, 0, - "DDAF35A193617ABACC417349AE20413112E6FA4E89A97EA2" - "0A9EEEE64B55D39A2192992A274FC1A836BA3C23A3FEEBBD" - "454D4423643CE80E2A9AC94FA54CA49F" }, - /* 2 */ { TEST2_2, length(TEST2_2), 1, 0, 0, - "8E959B75DAE313DA8CF4F72814FC143F8F7779C6EB9F7FA1" - "7299AEADB6889018501D289E4900F7E4331B99DEC4B5433A" - "C7D329EEB6DD26545E96E55B874BE909" }, - /* 3 */ { TEST3, length(TEST3), 1000000, 0, 0, - "E718483D0CE769644E2E42C7BC15B4638E1F98B13B204428" - "5632A803AFA973EBDE0FF244877EA60A4CB0432CE577C31B" - "EB009C5C2C49AA2E4EADB217AD8CC09B" }, - /* 4 */ { TEST4, length(TEST4), 10, 0, 0, - "89D05BA632C699C31231DED4FFC127D5A894DAD412C0E024" - "DB872D1ABD2BA8141A0F85072A9BE1E2AA04CF33C765CB51" - "0813A39CD5A84C4ACAA64D3F3FB7BAE9" }, - /* 5 */ { "", 0, 0, 0xB0, 5, - "D4EE29A9E90985446B913CF1D1376C836F4BE2C1CF3CADA0" - "720A6BF4857D886A7ECB3C4E4C0FA8C7F95214E41DC1B0D2" - "1B22A84CC03BF8CE4845F34DD5BDBAD4" }, - /* 6 */ { "\xD0", 1, 1, 0, 0, - "9992202938E882E73E20F6B69E68A0A7149090423D93C81B" - "AB3F21678D4ACEEEE50E4E8CAFADA4C85A54EA8306826C4A" - "D6E74CECE9631BFA8A549B4AB3FBBA15" }, - /* 7 */ { TEST7_512, length(TEST7_512), 1, 0x80, 3, - "ED8DC78E8B01B69750053DBB7A0A9EDA0FB9E9D292B1ED71" - "5E80A7FE290A4E16664FD913E85854400C5AF05E6DAD316B" - "7359B43E64F8BEC3C1F237119986BBB6" }, - /* 8 */ { TEST8_512, length(TEST8_512), 1, 0, 0, - "CB0B67A4B8712CD73C9AABC0B199E9269B20844AFB75ACBD" - "D1C153C9828924C3DDEDAAFE669C5FDD0BC66F630F677398" - "8213EB1B16F517AD0DE4B2F0C95C90F8" }, - /* 9 */ { TEST9_512, length(TEST9_512), 1, 0x80, 3, - "32BA76FC30EAA0208AEB50FFB5AF1864FDBF17902A4DC0A6" - "82C61FCEA6D92B783267B21080301837F59DE79C6B337DB2" - "526F8A0A510E5E53CAFED4355FE7C2F1" }, - /* 10 */ { TEST10_512, length(TEST10_512), 1, 0, 0, - "C665BEFB36DA189D78822D10528CBF3B12B3EEF726039909" - "C1A16A270D48719377966B957A878E720584779A62825C18" - "DA26415E49A7176A894E7510FD1451F5" } - }; - - for (int i = 0; i < 10; i++) { - SHA512_CTX ctx; - uint8_t digest[SHA512_DIGEST_LENGTH]; - sha512_Init(&ctx); - /* extra bits are not supported */ - if (tests[i].numberExtrabits) - continue; - for (int j = 0; j < tests[i].repeatcount; j++) { - sha512_Update(&ctx, (const uint8_t*) tests[i].test, tests[i].length); - } - sha512_Final(&ctx, digest); - ck_assert_mem_eq(digest, fromhex(tests[i].result), SHA512_DIGEST_LENGTH); - } +START_TEST(test_sha512) { + struct { + const char *test; + int length; + int repeatcount; + int extrabits; + int numberExtrabits; + const char *result; + } tests[] = {/* 1 */ {TEST1, length(TEST1), 1, 0, 0, + "DDAF35A193617ABACC417349AE20413112E6FA4E89A97EA2" + "0A9EEEE64B55D39A2192992A274FC1A836BA3C23A3FEEBBD" + "454D4423643CE80E2A9AC94FA54CA49F"}, + /* 2 */ + {TEST2_2, length(TEST2_2), 1, 0, 0, + "8E959B75DAE313DA8CF4F72814FC143F8F7779C6EB9F7FA1" + "7299AEADB6889018501D289E4900F7E4331B99DEC4B5433A" + "C7D329EEB6DD26545E96E55B874BE909"}, + /* 3 */ + {TEST3, length(TEST3), 1000000, 0, 0, + "E718483D0CE769644E2E42C7BC15B4638E1F98B13B204428" + "5632A803AFA973EBDE0FF244877EA60A4CB0432CE577C31B" + "EB009C5C2C49AA2E4EADB217AD8CC09B"}, + /* 4 */ + {TEST4, length(TEST4), 10, 0, 0, + "89D05BA632C699C31231DED4FFC127D5A894DAD412C0E024" + "DB872D1ABD2BA8141A0F85072A9BE1E2AA04CF33C765CB51" + "0813A39CD5A84C4ACAA64D3F3FB7BAE9"}, + /* 5 */ + {"", 0, 0, 0xB0, 5, + "D4EE29A9E90985446B913CF1D1376C836F4BE2C1CF3CADA0" + "720A6BF4857D886A7ECB3C4E4C0FA8C7F95214E41DC1B0D2" + "1B22A84CC03BF8CE4845F34DD5BDBAD4"}, + /* 6 */ + {"\xD0", 1, 1, 0, 0, + "9992202938E882E73E20F6B69E68A0A7149090423D93C81B" + "AB3F21678D4ACEEEE50E4E8CAFADA4C85A54EA8306826C4A" + "D6E74CECE9631BFA8A549B4AB3FBBA15"}, + /* 7 */ + {TEST7_512, length(TEST7_512), 1, 0x80, 3, + "ED8DC78E8B01B69750053DBB7A0A9EDA0FB9E9D292B1ED71" + "5E80A7FE290A4E16664FD913E85854400C5AF05E6DAD316B" + "7359B43E64F8BEC3C1F237119986BBB6"}, + /* 8 */ + {TEST8_512, length(TEST8_512), 1, 0, 0, + "CB0B67A4B8712CD73C9AABC0B199E9269B20844AFB75ACBD" + "D1C153C9828924C3DDEDAAFE669C5FDD0BC66F630F677398" + "8213EB1B16F517AD0DE4B2F0C95C90F8"}, + /* 9 */ + {TEST9_512, length(TEST9_512), 1, 0x80, 3, + "32BA76FC30EAA0208AEB50FFB5AF1864FDBF17902A4DC0A6" + "82C61FCEA6D92B783267B21080301837F59DE79C6B337DB2" + "526F8A0A510E5E53CAFED4355FE7C2F1"}, + /* 10 */ + {TEST10_512, length(TEST10_512), 1, 0, 0, + "C665BEFB36DA189D78822D10528CBF3B12B3EEF726039909" + "C1A16A270D48719377966B957A878E720584779A62825C18" + "DA26415E49A7176A894E7510FD1451F5"}}; + + for (int i = 0; i < 10; i++) { + SHA512_CTX ctx; + uint8_t digest[SHA512_DIGEST_LENGTH]; + sha512_Init(&ctx); + /* extra bits are not supported */ + if (tests[i].numberExtrabits) continue; + for (int j = 0; j < tests[i].repeatcount; j++) { + sha512_Update(&ctx, (const uint8_t *)tests[i].test, tests[i].length); + } + sha512_Final(&ctx, digest); + ck_assert_mem_eq(digest, fromhex(tests[i].result), SHA512_DIGEST_LENGTH); + } } END_TEST // test vectors from http://www.di-mgt.com.au/sha_testvectors.html -START_TEST(test_sha3_256) -{ - uint8_t digest[SHA3_256_DIGEST_LENGTH]; - - sha3_256((uint8_t *)"", 0, digest); - ck_assert_mem_eq(digest, fromhex("a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a"), SHA3_256_DIGEST_LENGTH); - - sha3_256((uint8_t *)"abc", 3, digest); - ck_assert_mem_eq(digest, fromhex("3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532"), SHA3_256_DIGEST_LENGTH); - - sha3_256((uint8_t *)"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 56, digest); - ck_assert_mem_eq(digest, fromhex("41c0dba2a9d6240849100376a8235e2c82e1b9998a999e21db32dd97496d3376"), SHA3_256_DIGEST_LENGTH); - - sha3_256((uint8_t *)"abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", 112, digest); - ck_assert_mem_eq(digest, fromhex("916f6061fe879741ca6469b43971dfdb28b1a32dc36cb3254e812be27aad1d18"), SHA3_256_DIGEST_LENGTH); +START_TEST(test_sha3_256) { + uint8_t digest[SHA3_256_DIGEST_LENGTH]; + + sha3_256((uint8_t *)"", 0, digest); + ck_assert_mem_eq( + digest, + fromhex( + "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a"), + SHA3_256_DIGEST_LENGTH); + + sha3_256((uint8_t *)"abc", 3, digest); + ck_assert_mem_eq( + digest, + fromhex( + "3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532"), + SHA3_256_DIGEST_LENGTH); + + sha3_256( + (uint8_t *)"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 56, + digest); + ck_assert_mem_eq( + digest, + fromhex( + "41c0dba2a9d6240849100376a8235e2c82e1b9998a999e21db32dd97496d3376"), + SHA3_256_DIGEST_LENGTH); + + sha3_256((uint8_t *)"abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", 112, digest); + ck_assert_mem_eq( + digest, + fromhex( + "916f6061fe879741ca6469b43971dfdb28b1a32dc36cb3254e812be27aad1d18"), + SHA3_256_DIGEST_LENGTH); } END_TEST // test vectors from http://www.di-mgt.com.au/sha_testvectors.html -START_TEST(test_sha3_512) -{ - uint8_t digest[SHA3_512_DIGEST_LENGTH]; - - sha3_512((uint8_t *)"", 0, digest); - ck_assert_mem_eq(digest, fromhex("a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26"), SHA3_512_DIGEST_LENGTH); - - sha3_512((uint8_t *)"abc", 3, digest); - ck_assert_mem_eq(digest, fromhex("b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e10e116e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0"), SHA3_512_DIGEST_LENGTH); - - sha3_512((uint8_t *)"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 56, digest); - ck_assert_mem_eq(digest, fromhex("04a371e84ecfb5b8b77cb48610fca8182dd457ce6f326a0fd3d7ec2f1e91636dee691fbe0c985302ba1b0d8dc78c086346b533b49c030d99a27daf1139d6e75e"), SHA3_512_DIGEST_LENGTH); - - sha3_512((uint8_t *)"abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", 112, digest); - ck_assert_mem_eq(digest, fromhex("afebb2ef542e6579c50cad06d2e578f9f8dd6881d7dc824d26360feebf18a4fa73e3261122948efcfd492e74e82e2189ed0fb440d187f382270cb455f21dd185"), SHA3_512_DIGEST_LENGTH); +START_TEST(test_sha3_512) { + uint8_t digest[SHA3_512_DIGEST_LENGTH]; + + sha3_512((uint8_t *)"", 0, digest); + ck_assert_mem_eq( + digest, + fromhex( + "a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2" + "123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26"), + SHA3_512_DIGEST_LENGTH); + + sha3_512((uint8_t *)"abc", 3, digest); + ck_assert_mem_eq( + digest, + fromhex( + "b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e10e1" + "16e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0"), + SHA3_512_DIGEST_LENGTH); + + sha3_512( + (uint8_t *)"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 56, + digest); + ck_assert_mem_eq( + digest, + fromhex( + "04a371e84ecfb5b8b77cb48610fca8182dd457ce6f326a0fd3d7ec2f1e91636dee69" + "1fbe0c985302ba1b0d8dc78c086346b533b49c030d99a27daf1139d6e75e"), + SHA3_512_DIGEST_LENGTH); + + sha3_512((uint8_t *)"abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", 112, digest); + ck_assert_mem_eq( + digest, + fromhex( + "afebb2ef542e6579c50cad06d2e578f9f8dd6881d7dc824d26360feebf18a4fa73e3" + "261122948efcfd492e74e82e2189ed0fb440d187f382270cb455f21dd185"), + SHA3_512_DIGEST_LENGTH); } END_TEST -// test vectors from https://raw.githubusercontent.com/NemProject/nem-test-vectors/master/0.test-sha3-256.dat -START_TEST(test_keccak_256) -{ - static const struct { - const char *hash; - size_t length; - const char *data; - } tests[] = { - { "4e9e79ab7434f6c7401fb3305d55052ee829b9e46d5d05d43b59fefb32e9a619", 293, "a6151d4904e18ec288243028ceda30556e6c42096af7150d6a7232ca5dba52bd2192e23daa5fa2bea3d4bd95efa2389cd193fcd3376e70a5c097b32c1c62c80af9d710211545f7cdddf63747420281d64529477c61e721273cfd78f8890abb4070e97baa52ac8ff61c26d195fc54c077def7a3f6f79b36e046c1a83ce9674ba1983ec2fb58947de616dd797d6499b0385d5e8a213db9ad5078a8e0c940ff0cb6bf92357ea5609f778c3d1fb1e7e36c35db873361e2be5c125ea7148eff4a035b0cce880a41190b2e22924ad9d1b82433d9c023924f2311315f07b88bfd42850047bf3be785c4ce11c09d7e02065d30f6324365f93c5e7e423a07d754eb314b5fe9db4614275be4be26af017abdc9c338d01368226fe9af1fb1f815e7317bdbb30a0f36dc69", }, - { "c1268babc42d00c3463dc388222100f7e525a74a64665c39f112f788ddb5da42", 376, "9db801077952c2324e0044a4994edfb09b3edfcf669bfdd029f4bf42d5b0eab3056b0bf82708ca7bfadba43c9de806b10a19d0f00c2351ef1086b6b108f306e035c6b61b2e70fd7087ba848601c8a3f626a66666423717ef305a1068bfa3a1f7ffc1e5a78cb6182ffc8a577ca2a821630bf900d0fbba848bdf94b77c5946771b6c3f8c02269bc772ca56098f724536d96be68c284ee1d81697989d40029b8ea63ac1fd85f8b3cae8b194f6834ff65a5858f9498ddbb467995eb2d49cdfc6c05d92038c6e9aaeee85f8222b3784165f12a2c3df4c7a142e26dddfd831d07e22dfecc0eded48a69c8a9e1b97f1a4e0efcd4edd310de0edf82af38a6e4d5ab2a19da586e61210d4f75e7a07e2201f9c8154ca52a414a70d2eb2ac1c5b9a2900b4d871f62fa56f70d03b3dd3704bd644808c45a13231918ea884645b8ec054e8bab2935a66811fe590ddc119ae901dfeb54fc2a87c1e0a236778baab2fa8843709c6676d3c1888ba19d75ec52d73a7d035c143179b93823726b7", }, - { "e83b50e8c83cb676a7dd64c055f53e5110d5a4c62245ceb8f683fd87b2b3ec77", 166, "c070a957550b7b34113ee6543a1918d96d241f27123425db7f7b9004e047ffbe05612e7fa8c54b23c83ea427e625e97b7a28b09a70bf6d91e478eeed01d7907931c29ea86e70f2cdcfb243ccf7f24a1619abf4b5b9e6f75cbf63fc02baf4a820a9790a6b053e50fd94e0ed57037cfc2bab4d95472b97d3c25f434f1cc0b1ede5ba7f15907a42a223933e5e2dfcb518c3531975268c326d60fa911fbb7997eee3ba87656c4fe7", }, - { "8ebd2c9d4ff00e285a9b6b140bfc3cef672016f0098100e1f6f250220af7ce1a", 224, "b502fbdce4045e49e147eff5463d4b3f37f43461518868368e2c78008c84c2db79d12b58107034f67e7d0abfee67add0342dd23dce623f26b9156def87b1d7ac15a6e07301f832610fe869ada13a2b0e3d60aa6bb81bc04487e2e800f5106b0402ee0331df745e021b5ea5e32faf1c7fc1322041d221a54191c0af19948b5f34411937182e30d5cd39b5a6c959d77d92d21bb1de51f1b3411cb6eec00600429916227fb62d2c88e69576f4ac8e5efcde8efa512cc80ce7fb0dfaa6c74d26e898cefe9d4f7dce232a69f2a6a9477aa08366efcdfca117c89cb79eba15a23755e0", }, - { "db3961fdddd0c314289efed5d57363459a6700a7bd015e7a03d3e1d03f046401", 262, "22e203a98ba2c43d8bc3658f0a48a35766df356d6a5e98b0c7222d16d85a00b317207d4aef3fc7cabb67b9d8f5838de0b733e1fd59c31f0667e53286972d7090421ad90d54db2ea40047d0d1700c86f53dbf48da532396307e68edad877dcae481848801b0a5db44dbdba6fc7c63b5cd15281d57ca9e6be96f530b209b59d6127ad2bd8750f3f80798f62521f0d5b42633c2f5a9aaefbed38779b7aded2338d66850b0bb0e33c48e040c99f2dcee7a7ebb3d7416e1c5bf038c19d09682dab67c96dbbfad472e45980aa27d1b301b15f7de4d4f549bad2501931c9d4f1a3b1692dcb4b1b834ddd4a636126702307ddaeec61841693b21887d56e76cc2069dafb557fd6682160f", }, - { "25dd3acacd6bf688c0eace8d33eb7cc550271969142deb769a05b4012f7bb722", 122, "99e7f6e0ed46ec866c43a1ab494998d47e9309a79fde2a629eb63bb2160a5ffd0f2206de9c32dd20e9b23e57ab7422cf82971cc2873ec0e173fe93281c7b33e1c76ac79223a6f435f230bdd30260c00d00986c72a399d3ba70f6e783d834bbf8a6127844def559b8b6db742b2cfd715f7ff29e7b42bf7d567beb", }, - { "00d747c9045c093484290afc161437f11c2ddf5f8a9fc2acae9c7ef5fcf511e5", 440, "50c392f97f8788377f0ab2e2aab196cb017ad157c6f9d022673d39072cc198b06622a5cbd269d1516089fa59e28c3373a92bd54b2ebf1a79811c7e40fdd7bce200e80983fda6e77fc44c44c1b5f87e01cef2f41e1141103f73364e9c2f25a4597e6517ef31b316300b770c69595e0fa6d011df1566a8676a88c7698562273bbfa217cc69d4b5c89a8907b902f7dc14481fefc7da4a810c15a60f5641aae854d2f8cc50cbc393015560f01c94e0d0c075dbcb150ad6eba29dc747919edcaf0231dba3eb3f2b1a87e136a1f0fd4b3d8ee61bad2729e9526a32884f7bcfa41e361add1b4c51dc81463528372b4ec321244de0c541ba00df22b8773cdf4cf898510c867829fa6b4ff11f9627338b9686d905cb7bcdf085080ab842146e0035c808be58cce97827d8926a98bd1ff7c529be3bc14f68c91b2ca4d2f6fc748f56bcf14853b7f8b9aa6d388f0fd82f53fdc4bacf9d9ba10a165f404cf427e199f51bf6773b7c82531e17933f6d8b8d9181e22f8921a2dbb20fc7c8023a87e716e245017c399d0942934f5e085219b3f8d26a196bf8b239438b8e561c28a61ff08872ecb052c5fcb19e2fdbc09565924a50ebee1461c4b414219d4257", }, - { "dadcde7c3603ef419d319ba3d50cf00ad57f3e81566fd11b9b6f461cbb9dcb0f", 338, "18e1df97abccc91e07dc7b7ffab5ee8919d5610721453176aa2089fb96d9a477e1476f507fa1129f04304e960e8017ff41246cacc0153055fc4b1dc6168a74067ebb077cb5aa80a9df6e8b5b821e906531159668c4c164b9e511d8724aedbe17c1f41da8809417d3c30b79ea5a2e3c961f6bac5436d9af6be24a36eebcb17863fed82c0eb8962339eb612d58659dddd2ea06a120b3a2d8a17050be2de367db25a5bef4290c209bdb4c16c4df5a1fe1ead635169a1c35f0a56bc07bcf6ef0e4c2d8573ed7a3b58030fa268c1a5974b097288f01f34d5a1087946410688016882c6c7621aad680d9a25c7a3e5dbcbb07ffdb7243b91031c08a121b40785e96b7ee46770c760f84aca8f36b7c7da64d25c8f73b4d88ff3acb7eeefc0b75144dffea66d2d1f6b42b905b61929ab3f38538393ba5ca9d3c62c61f46fa63789cac14e4e1d8722bf03cceef6e3de91f783b0072616c", }, - { "d184e84a2507fc0f187b640dd5b849a366c0383d9cbdbc6fa30904f054111255", 141, "13b8df9c1bcfddd0aa39b3055f52e2bc36562b6677535994b173f07041d141699db42589d6091ef0e71b645b41ab57577f58c98da966562d24823158f8e1d43b54edea4e61dd66fe8c59ad8405f5a0d9a3eb509a77ae3d8ae4adf926fd3d8d31c3dcccfc140814541010937024cc554e1daaee1b333a66316e7fbebb07ac8dfb134a918b9090b14168012c4824", }, - { "20c19635364a00b151d0168fe5ae03bac6dd7d06030475b40d2e8c577a192f53", 84, "e1e96da4b7d8dcc2b316006503a990ea26a5b200cb7a7edfc14f5ce827f06d8d232ec95b1acdc1422ffc16da11d258f0c7b378f026d64c74b2fb41df8bfd3cd30066caecdc6f76c8163de9309d9fd0cf33d54a29", }, - { "86cc2c428d469e43fb4ee8d38dffbf5128d20d1659dbc45edf4a855399ca730e", 319, "30391840ad14e66c53e1a5aaa03989ff059940b60c44c3b21295a93d023f2e6c7cdcf60208b7d87a7605fb5cee94630d94cad90bc6955328357fa37fea47c09f9cee759c31537187321c7d572e3554eeb90f441a9494575454dfbf8cfd86128da15de9418821ca158856eb84ff6a29a2c8380711e9e6d4955388374fcd3c1ca45b49e0679fc7157f96bc6e4f86ce20a89c12d4449b1ca7056e0b7296fc646f68f6ddbfa6a48e384d63ab68bc75fd69a2add59b8e41c4a0f753935df9a703d7df82a430798b0a67710a78061485a9d15de16f154582082459b4462485ce8a82d35ac6b9498ae40df3a23d5f00e0e86661cb02c52f677fd374c32969ec63028b5dd2c1d4bce67a6d9f79ba5e7eeb5a2763dc9fe2a05aa2ebaad36aaec2541e343a677fb4e6b6a180eff33c93744a4624f6a79f054c6c9e9c5b6928dbe7ba5fca", }, - { "e80eee72a76e6957f7cb7f68c41b92f0ad9aac6e58aa8fc272c1e7364af11c70", 108, "3c210ed15889ae938781d2cebd49d4a8007f163ffba1f7669bccdccf6ad5a1418299d5f4348f5cd03b0ba9e6999ab154e46836c3546feb395d17bcc60f23d7ba0e8efe6aa616c00b6bf552fe1cb5e28e3e7bc39dfc20c63ae3901035e91ddd110e43fe59ed744beeedb6bc1e", }, - { "f971bbae97dd8a034835269fb246867de358a889de6de13672e771d6fb4c89b7", 468, "64e9a3a99c021df8bea59368cfe1cd3b0a4aca33ffcd5cf6028d9307c0b904b8037d056a3c12803f196f74c4d360a3132452d365922b1157e5b0d76f91fb94bebfdcb4d50fa23ed5be3d3c5712219e8666debc8abcd5e6c69a542761a6cbbd1b3c0f0524875204b64d2788465f90cb19b6f6da9f8bec6d6e684196e713549ec83e47cbaeff77838ac4936b312562e2de17c970449d49d214ec2597c6d4f642e6c94a613a0c53285abccd7794a3d72241808594fb4e6e4d5d2c310ef1cdcbfd34805ca2408f554797a6cfd49d0f25ed8927f206acb127e6436e1234902489ec2e7f3058e26c0eba80341bc7ad0da8b8bd80bd1b43c9099269e3f8b68445c69b79d8cf5693d4a0d47a44f9e9114dbb33992d2ea9d3b5b86e4ea57a44a638848de4ac365bb6bb7855305ade62b07ebf0954d70b7c2fb5e6fcc154c7a36fb1756df5f20a84d35696627ebf22d44f40f805c0878ad110bc17dcd66821084ca87902e05bc0afa61161086956b85a6ea900d35c7784d4c361a43fe294e267d5762408be58962cdb4f45a9c0efd7d2335916df3acb98ccfbcf5ee39530540e5f3d3c5f3326a9a536d7bfa37aae2b143e2499b81bf0670e3a418c26c7dc82b293d9bd182dd6435670514237df88d8286e19ce93e0a0db2790", }, - { "b97fd51f4e4eaa40c7a2853010fc46be5be2f43b9520ea0c533b68f728c978a2", 214, "ced3a43193caceb269d2517f4ecb892bb7d57d7201869e28e669b0b17d1c44d286e02734e2210ea9009565832975cc6303b9b6008fe1165b99ae5f1b29962ef042ebad8b676d7433ed2fe0d0d6f4f32b2cb4c519da61552328c2caea799bb2fd907308173a1cd2b798fb0df7d2eaf2ff0be733af74f42889e211843fc80b09952ae7eb246725b91d31c1f7a5503fdf3bc9c269c76519cf2dc3225e862436b587bb74adbad88c773056cfea3bddb1f6533c01125eeae0986e5c817359912c9d0472bf8320b824ee097f82a8e05b9f53a5be7d153225de", }, - { "f0fecf766e4f7522568b3be71843cce3e5fcb10ea96b1a236c8c0a71c9ad55c9", 159, "8aca4de41275f5c4102f66266d70cff1a2d56f58df8d12061c64cb6cd8f616a5bf19c2bb3c91585c695326f561a2d0eb4eef2e202d82dcc9089e4bee82b62a199a11963cd08987d3abd5914def2cdd3c1e4748d46b654f338e3959121e869c18d5327e88090d0ba0ac6762a2b14514cc505af7499f1a22f421dbe978494f9ffe1e88f1c59228f21da5bc9fcc911d022300a443bca17258bdd6cfbbf52fde61", }, - { "5c4f16043c0084bf98499fc7dc4d674ce9c730b7135210acdbf5e41d3dcf317b", 87, "01bbc193d0ee2396a7d8267ad63f18149667b31d8f7f48c8bb0c634755febc9ef1a79e93c475f6cd137ee37d4dc243ea2fdcdc0d098844af2208337b7bbf6930e39e74e23952ac1a19b4d38b83810a10c3b069e4fafb06", }, - { "14b61fc981f7d9449b7b6a2d57eb48cc8f7896f4dced2005291b2a2f38cb4a63", 358, "cbc1709a531438d5ead32cea20a9e4ddc0101ec555ab42b2e378145013cc05a97b9e2c43c89bfa63ae5e9e9ce1fc022035c6b68f0a906ee1f53396d9dbe41cb2bc4bfeb144b005b0f40e0fec872d9c4aca9929ba3cbacd84c58ab43c26f10d345a24692bbd55a76506876768e8e32a461bf160cee953da88920d36ad4aff6eea7126aa6f44a7a6fce770ce43f0f90a20590bdaad3ffcda30ca8e3700f832c62caa5df030c16bcf74aff492466f781eb69863a80663535fc154abd7cfdd02eef1019221cf608b9780f807e507fbbf559b1dfe4e971b4d08fe45263a3c697ba90f9f71bec97e12438b4b12f6a84ab66872b888097089d76c9c2502d9ed2eece6bef8eee1d439782e218f5cc75d38f9886012cdcb4bbe6caf812e97c5a336bcceae38b1109e3243a291ce23d097aaee7d9a711de6886749a7a6d15d7e7cbc4a51b1b4da9fcf139e4a6fd7dc0bc017db624b17fc9b8f847592ed42467c25ad9fe96acbf20c0ffd18", }, - { "47ec7f3a362becbb110867995a0f066a66152603c4d433f11bf51870c67e2864", 354, "0636983353c9ea3f75256ed00b70e8b7cfc6f4e4c0ba3aa9a8da59b6e6ad9dfb5bc2c49f48cc0b4237f87dedf34b888e54ecebf1d435bcd4aab72eb4ce39e5262fb68c6f86423dac123bf59e903989eda7df4a982822d0831521403cedcfe9a5bbea648bb2e7ef8cd81442ea5abe468b3ee8b06376ef8099447255c2fdc1b73af37fe0e0b852ffbc9339868db756680db99e6e9837dbd28c39a69f229044ad7ec772524a6e01f679d25fdc2e736a2418e5dfd7c2ab1348d0f821b777c975244c6cfc2fca5c36ccae7cf1d07b190a9d17a088a1276bd096250b92f53b29b6ef88ef69d744b56fb2ec5078cc0b68a9106943ef242b466097b9e29df11eb5cb0c06c29d7917410ba1097215d6aa4dafd90adff0c3e7221b9e8832613bd9aca8bcc6b2aa7b43acedcbc11aee1b5ba56f77a210be7cf3485ee813e1126c3eeccd8419bbf22c412cad32cc0fc7a73aca4e379651caac3d13d6cf5ca05508fd2d96f3ad94e7", }, - { "73778e7f1943646a89d3c78909e0afbe584071ba5230546a39cd73e44e36d78a", 91, "6217504a26b3395855eab6ddeb79f2e3490d74b80eff343721150ee0c1c02b07186743589f93c22a03dc5ed29fb5bf592de0a089763e83e5b95f9dd524d66c8da3e04c1814e65e68b2810c1b517648aabc266ad62896c51864a7f4", }, - { "35ef6868e750cf0c1d5285992c231d93ec644670fb79cf85324067a9f77fde78", 185, "0118b7fb15f927a977e0b330b4fa351aeeec299d6ba090eb16e5114fc4a6749e5915434a123c112697390c96ea2c26dc613eb5c75f5ecfb6c419317426367e34da0ddc6d7b7612cefa70a22fea0025f5186593b22449dab71f90a49f7de7352e54e0c0bd8837e661ca2127c3313a7268cafdd5ccfbf3bdd7c974b0e7551a2d96766579ef8d2e1f376af74cd1ab62162fc2dc61a8b7ed4163c1caccf20ed73e284da2ed257ec974eee96b502acb2c60a04886465e44debb0317", }, - }; - - uint8_t hash[SHA3_256_DIGEST_LENGTH]; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - keccak_256(fromhex(tests[i].data), tests[i].length, hash); - ck_assert_mem_eq(hash, fromhex(tests[i].hash), SHA3_256_DIGEST_LENGTH); - } +// test vectors from +// https://raw.githubusercontent.com/NemProject/nem-test-vectors/master/0.test-sha3-256.dat +START_TEST(test_keccak_256) { + static const struct { + const char *hash; + size_t length; + const char *data; + } tests[] = { + { + "4e9e79ab7434f6c7401fb3305d55052ee829b9e46d5d05d43b59fefb32e9a619", + 293, + "a6151d4904e18ec288243028ceda30556e6c42096af7150d6a7232ca5dba52bd2192" + "e23daa5fa2bea3d4bd95efa2389cd193fcd3376e70a5c097b32c1c62c80af9d71021" + "1545f7cdddf63747420281d64529477c61e721273cfd78f8890abb4070e97baa52ac" + "8ff61c26d195fc54c077def7a3f6f79b36e046c1a83ce9674ba1983ec2fb58947de6" + "16dd797d6499b0385d5e8a213db9ad5078a8e0c940ff0cb6bf92357ea5609f778c3d" + "1fb1e7e36c35db873361e2be5c125ea7148eff4a035b0cce880a41190b2e22924ad9" + "d1b82433d9c023924f2311315f07b88bfd42850047bf3be785c4ce11c09d7e02065d" + "30f6324365f93c5e7e423a07d754eb314b5fe9db4614275be4be26af017abdc9c338" + "d01368226fe9af1fb1f815e7317bdbb30a0f36dc69", + }, + { + "c1268babc42d00c3463dc388222100f7e525a74a64665c39f112f788ddb5da42", + 376, + "9db801077952c2324e0044a4994edfb09b3edfcf669bfdd029f4bf42d5b0eab3056b" + "0bf82708ca7bfadba43c9de806b10a19d0f00c2351ef1086b6b108f306e035c6b61b" + "2e70fd7087ba848601c8a3f626a66666423717ef305a1068bfa3a1f7ffc1e5a78cb6" + "182ffc8a577ca2a821630bf900d0fbba848bdf94b77c5946771b6c3f8c02269bc772" + "ca56098f724536d96be68c284ee1d81697989d40029b8ea63ac1fd85f8b3cae8b194" + "f6834ff65a5858f9498ddbb467995eb2d49cdfc6c05d92038c6e9aaeee85f8222b37" + "84165f12a2c3df4c7a142e26dddfd831d07e22dfecc0eded48a69c8a9e1b97f1a4e0" + "efcd4edd310de0edf82af38a6e4d5ab2a19da586e61210d4f75e7a07e2201f9c8154" + "ca52a414a70d2eb2ac1c5b9a2900b4d871f62fa56f70d03b3dd3704bd644808c45a1" + "3231918ea884645b8ec054e8bab2935a66811fe590ddc119ae901dfeb54fc2a87c1e" + "0a236778baab2fa8843709c6676d3c1888ba19d75ec52d73a7d035c143179b938237" + "26b7", + }, + { + "e83b50e8c83cb676a7dd64c055f53e5110d5a4c62245ceb8f683fd87b2b3ec77", + 166, + "c070a957550b7b34113ee6543a1918d96d241f27123425db7f7b9004e047ffbe0561" + "2e7fa8c54b23c83ea427e625e97b7a28b09a70bf6d91e478eeed01d7907931c29ea8" + "6e70f2cdcfb243ccf7f24a1619abf4b5b9e6f75cbf63fc02baf4a820a9790a6b053e" + "50fd94e0ed57037cfc2bab4d95472b97d3c25f434f1cc0b1ede5ba7f15907a42a223" + "933e5e2dfcb518c3531975268c326d60fa911fbb7997eee3ba87656c4fe7", + }, + { + "8ebd2c9d4ff00e285a9b6b140bfc3cef672016f0098100e1f6f250220af7ce1a", + 224, + "b502fbdce4045e49e147eff5463d4b3f37f43461518868368e2c78008c84c2db79d1" + "2b58107034f67e7d0abfee67add0342dd23dce623f26b9156def87b1d7ac15a6e073" + "01f832610fe869ada13a2b0e3d60aa6bb81bc04487e2e800f5106b0402ee0331df74" + "5e021b5ea5e32faf1c7fc1322041d221a54191c0af19948b5f34411937182e30d5cd" + "39b5a6c959d77d92d21bb1de51f1b3411cb6eec00600429916227fb62d2c88e69576" + "f4ac8e5efcde8efa512cc80ce7fb0dfaa6c74d26e898cefe9d4f7dce232a69f2a6a9" + "477aa08366efcdfca117c89cb79eba15a23755e0", + }, + { + "db3961fdddd0c314289efed5d57363459a6700a7bd015e7a03d3e1d03f046401", + 262, + "22e203a98ba2c43d8bc3658f0a48a35766df356d6a5e98b0c7222d16d85a00b31720" + "7d4aef3fc7cabb67b9d8f5838de0b733e1fd59c31f0667e53286972d7090421ad90d" + "54db2ea40047d0d1700c86f53dbf48da532396307e68edad877dcae481848801b0a5" + "db44dbdba6fc7c63b5cd15281d57ca9e6be96f530b209b59d6127ad2bd8750f3f807" + "98f62521f0d5b42633c2f5a9aaefbed38779b7aded2338d66850b0bb0e33c48e040c" + "99f2dcee7a7ebb3d7416e1c5bf038c19d09682dab67c96dbbfad472e45980aa27d1b" + "301b15f7de4d4f549bad2501931c9d4f1a3b1692dcb4b1b834ddd4a636126702307d" + "daeec61841693b21887d56e76cc2069dafb557fd6682160f", + }, + { + "25dd3acacd6bf688c0eace8d33eb7cc550271969142deb769a05b4012f7bb722", + 122, + "99e7f6e0ed46ec866c43a1ab494998d47e9309a79fde2a629eb63bb2160a5ffd0f22" + "06de9c32dd20e9b23e57ab7422cf82971cc2873ec0e173fe93281c7b33e1c76ac792" + "23a6f435f230bdd30260c00d00986c72a399d3ba70f6e783d834bbf8a6127844def5" + "59b8b6db742b2cfd715f7ff29e7b42bf7d567beb", + }, + { + "00d747c9045c093484290afc161437f11c2ddf5f8a9fc2acae9c7ef5fcf511e5", + 440, + "50c392f97f8788377f0ab2e2aab196cb017ad157c6f9d022673d39072cc198b06622" + "a5cbd269d1516089fa59e28c3373a92bd54b2ebf1a79811c7e40fdd7bce200e80983" + "fda6e77fc44c44c1b5f87e01cef2f41e1141103f73364e9c2f25a4597e6517ef31b3" + "16300b770c69595e0fa6d011df1566a8676a88c7698562273bbfa217cc69d4b5c89a" + "8907b902f7dc14481fefc7da4a810c15a60f5641aae854d2f8cc50cbc393015560f0" + "1c94e0d0c075dbcb150ad6eba29dc747919edcaf0231dba3eb3f2b1a87e136a1f0fd" + "4b3d8ee61bad2729e9526a32884f7bcfa41e361add1b4c51dc81463528372b4ec321" + "244de0c541ba00df22b8773cdf4cf898510c867829fa6b4ff11f9627338b9686d905" + "cb7bcdf085080ab842146e0035c808be58cce97827d8926a98bd1ff7c529be3bc14f" + "68c91b2ca4d2f6fc748f56bcf14853b7f8b9aa6d388f0fd82f53fdc4bacf9d9ba10a" + "165f404cf427e199f51bf6773b7c82531e17933f6d8b8d9181e22f8921a2dbb20fc7" + "c8023a87e716e245017c399d0942934f5e085219b3f8d26a196bf8b239438b8e561c" + "28a61ff08872ecb052c5fcb19e2fdbc09565924a50ebee1461c4b414219d4257", + }, + { + "dadcde7c3603ef419d319ba3d50cf00ad57f3e81566fd11b9b6f461cbb9dcb0f", + 338, + "18e1df97abccc91e07dc7b7ffab5ee8919d5610721453176aa2089fb96d9a477e147" + "6f507fa1129f04304e960e8017ff41246cacc0153055fc4b1dc6168a74067ebb077c" + "b5aa80a9df6e8b5b821e906531159668c4c164b9e511d8724aedbe17c1f41da88094" + "17d3c30b79ea5a2e3c961f6bac5436d9af6be24a36eebcb17863fed82c0eb8962339" + "eb612d58659dddd2ea06a120b3a2d8a17050be2de367db25a5bef4290c209bdb4c16" + "c4df5a1fe1ead635169a1c35f0a56bc07bcf6ef0e4c2d8573ed7a3b58030fa268c1a" + "5974b097288f01f34d5a1087946410688016882c6c7621aad680d9a25c7a3e5dbcbb" + "07ffdb7243b91031c08a121b40785e96b7ee46770c760f84aca8f36b7c7da64d25c8" + "f73b4d88ff3acb7eeefc0b75144dffea66d2d1f6b42b905b61929ab3f38538393ba5" + "ca9d3c62c61f46fa63789cac14e4e1d8722bf03cceef6e3de91f783b0072616c", + }, + { + "d184e84a2507fc0f187b640dd5b849a366c0383d9cbdbc6fa30904f054111255", + 141, + "13b8df9c1bcfddd0aa39b3055f52e2bc36562b6677535994b173f07041d141699db4" + "2589d6091ef0e71b645b41ab57577f58c98da966562d24823158f8e1d43b54edea4e" + "61dd66fe8c59ad8405f5a0d9a3eb509a77ae3d8ae4adf926fd3d8d31c3dcccfc1408" + "14541010937024cc554e1daaee1b333a66316e7fbebb07ac8dfb134a918b9090b141" + "68012c4824", + }, + { + "20c19635364a00b151d0168fe5ae03bac6dd7d06030475b40d2e8c577a192f53", + 84, + "e1e96da4b7d8dcc2b316006503a990ea26a5b200cb7a7edfc14f5ce827f06d8d232e" + "c95b1acdc1422ffc16da11d258f0c7b378f026d64c74b2fb41df8bfd3cd30066caec" + "dc6f76c8163de9309d9fd0cf33d54a29", + }, + { + "86cc2c428d469e43fb4ee8d38dffbf5128d20d1659dbc45edf4a855399ca730e", + 319, + "30391840ad14e66c53e1a5aaa03989ff059940b60c44c3b21295a93d023f2e6c7cdc" + "f60208b7d87a7605fb5cee94630d94cad90bc6955328357fa37fea47c09f9cee759c" + "31537187321c7d572e3554eeb90f441a9494575454dfbf8cfd86128da15de9418821" + "ca158856eb84ff6a29a2c8380711e9e6d4955388374fcd3c1ca45b49e0679fc7157f" + "96bc6e4f86ce20a89c12d4449b1ca7056e0b7296fc646f68f6ddbfa6a48e384d63ab" + "68bc75fd69a2add59b8e41c4a0f753935df9a703d7df82a430798b0a67710a780614" + "85a9d15de16f154582082459b4462485ce8a82d35ac6b9498ae40df3a23d5f00e0e8" + "6661cb02c52f677fd374c32969ec63028b5dd2c1d4bce67a6d9f79ba5e7eeb5a2763" + "dc9fe2a05aa2ebaad36aaec2541e343a677fb4e6b6a180eff33c93744a4624f6a79f" + "054c6c9e9c5b6928dbe7ba5fca", + }, + { + "e80eee72a76e6957f7cb7f68c41b92f0ad9aac6e58aa8fc272c1e7364af11c70", + 108, + "3c210ed15889ae938781d2cebd49d4a8007f163ffba1f7669bccdccf6ad5a1418299" + "d5f4348f5cd03b0ba9e6999ab154e46836c3546feb395d17bcc60f23d7ba0e8efe6a" + "a616c00b6bf552fe1cb5e28e3e7bc39dfc20c63ae3901035e91ddd110e43fe59ed74" + "4beeedb6bc1e", + }, + { + "f971bbae97dd8a034835269fb246867de358a889de6de13672e771d6fb4c89b7", + 468, + "64e9a3a99c021df8bea59368cfe1cd3b0a4aca33ffcd5cf6028d9307c0b904b8037d" + "056a3c12803f196f74c4d360a3132452d365922b1157e5b0d76f91fb94bebfdcb4d5" + "0fa23ed5be3d3c5712219e8666debc8abcd5e6c69a542761a6cbbd1b3c0f05248752" + "04b64d2788465f90cb19b6f6da9f8bec6d6e684196e713549ec83e47cbaeff77838a" + "c4936b312562e2de17c970449d49d214ec2597c6d4f642e6c94a613a0c53285abccd" + "7794a3d72241808594fb4e6e4d5d2c310ef1cdcbfd34805ca2408f554797a6cfd49d" + "0f25ed8927f206acb127e6436e1234902489ec2e7f3058e26c0eba80341bc7ad0da8" + "b8bd80bd1b43c9099269e3f8b68445c69b79d8cf5693d4a0d47a44f9e9114dbb3399" + "2d2ea9d3b5b86e4ea57a44a638848de4ac365bb6bb7855305ade62b07ebf0954d70b" + "7c2fb5e6fcc154c7a36fb1756df5f20a84d35696627ebf22d44f40f805c0878ad110" + "bc17dcd66821084ca87902e05bc0afa61161086956b85a6ea900d35c7784d4c361a4" + "3fe294e267d5762408be58962cdb4f45a9c0efd7d2335916df3acb98ccfbcf5ee395" + "30540e5f3d3c5f3326a9a536d7bfa37aae2b143e2499b81bf0670e3a418c26c7dc82" + "b293d9bd182dd6435670514237df88d8286e19ce93e0a0db2790", + }, + { + "b97fd51f4e4eaa40c7a2853010fc46be5be2f43b9520ea0c533b68f728c978a2", + 214, + "ced3a43193caceb269d2517f4ecb892bb7d57d7201869e28e669b0b17d1c44d286e0" + "2734e2210ea9009565832975cc6303b9b6008fe1165b99ae5f1b29962ef042ebad8b" + "676d7433ed2fe0d0d6f4f32b2cb4c519da61552328c2caea799bb2fd907308173a1c" + "d2b798fb0df7d2eaf2ff0be733af74f42889e211843fc80b09952ae7eb246725b91d" + "31c1f7a5503fdf3bc9c269c76519cf2dc3225e862436b587bb74adbad88c773056cf" + "ea3bddb1f6533c01125eeae0986e5c817359912c9d0472bf8320b824ee097f82a8e0" + "5b9f53a5be7d153225de", + }, + { + "f0fecf766e4f7522568b3be71843cce3e5fcb10ea96b1a236c8c0a71c9ad55c9", + 159, + "8aca4de41275f5c4102f66266d70cff1a2d56f58df8d12061c64cb6cd8f616a5bf19" + "c2bb3c91585c695326f561a2d0eb4eef2e202d82dcc9089e4bee82b62a199a11963c" + "d08987d3abd5914def2cdd3c1e4748d46b654f338e3959121e869c18d5327e88090d" + "0ba0ac6762a2b14514cc505af7499f1a22f421dbe978494f9ffe1e88f1c59228f21d" + "a5bc9fcc911d022300a443bca17258bdd6cfbbf52fde61", + }, + { + "5c4f16043c0084bf98499fc7dc4d674ce9c730b7135210acdbf5e41d3dcf317b", + 87, + "01bbc193d0ee2396a7d8267ad63f18149667b31d8f7f48c8bb0c634755febc9ef1a7" + "9e93c475f6cd137ee37d4dc243ea2fdcdc0d098844af2208337b7bbf6930e39e74e2" + "3952ac1a19b4d38b83810a10c3b069e4fafb06", + }, + { + "14b61fc981f7d9449b7b6a2d57eb48cc8f7896f4dced2005291b2a2f38cb4a63", + 358, + "cbc1709a531438d5ead32cea20a9e4ddc0101ec555ab42b2e378145013cc05a97b9e" + "2c43c89bfa63ae5e9e9ce1fc022035c6b68f0a906ee1f53396d9dbe41cb2bc4bfeb1" + "44b005b0f40e0fec872d9c4aca9929ba3cbacd84c58ab43c26f10d345a24692bbd55" + "a76506876768e8e32a461bf160cee953da88920d36ad4aff6eea7126aa6f44a7a6fc" + "e770ce43f0f90a20590bdaad3ffcda30ca8e3700f832c62caa5df030c16bcf74aff4" + "92466f781eb69863a80663535fc154abd7cfdd02eef1019221cf608b9780f807e507" + "fbbf559b1dfe4e971b4d08fe45263a3c697ba90f9f71bec97e12438b4b12f6a84ab6" + "6872b888097089d76c9c2502d9ed2eece6bef8eee1d439782e218f5cc75d38f98860" + "12cdcb4bbe6caf812e97c5a336bcceae38b1109e3243a291ce23d097aaee7d9a711d" + "e6886749a7a6d15d7e7cbc4a51b1b4da9fcf139e4a6fd7dc0bc017db624b17fc9b8f" + "847592ed42467c25ad9fe96acbf20c0ffd18", + }, + { + "47ec7f3a362becbb110867995a0f066a66152603c4d433f11bf51870c67e2864", + 354, + "0636983353c9ea3f75256ed00b70e8b7cfc6f4e4c0ba3aa9a8da59b6e6ad9dfb5bc2" + "c49f48cc0b4237f87dedf34b888e54ecebf1d435bcd4aab72eb4ce39e5262fb68c6f" + "86423dac123bf59e903989eda7df4a982822d0831521403cedcfe9a5bbea648bb2e7" + "ef8cd81442ea5abe468b3ee8b06376ef8099447255c2fdc1b73af37fe0e0b852ffbc" + "9339868db756680db99e6e9837dbd28c39a69f229044ad7ec772524a6e01f679d25f" + "dc2e736a2418e5dfd7c2ab1348d0f821b777c975244c6cfc2fca5c36ccae7cf1d07b" + "190a9d17a088a1276bd096250b92f53b29b6ef88ef69d744b56fb2ec5078cc0b68a9" + "106943ef242b466097b9e29df11eb5cb0c06c29d7917410ba1097215d6aa4dafd90a" + "dff0c3e7221b9e8832613bd9aca8bcc6b2aa7b43acedcbc11aee1b5ba56f77a210be" + "7cf3485ee813e1126c3eeccd8419bbf22c412cad32cc0fc7a73aca4e379651caac3d" + "13d6cf5ca05508fd2d96f3ad94e7", + }, + { + "73778e7f1943646a89d3c78909e0afbe584071ba5230546a39cd73e44e36d78a", + 91, + "6217504a26b3395855eab6ddeb79f2e3490d74b80eff343721150ee0c1c02b071867" + "43589f93c22a03dc5ed29fb5bf592de0a089763e83e5b95f9dd524d66c8da3e04c18" + "14e65e68b2810c1b517648aabc266ad62896c51864a7f4", + }, + { + "35ef6868e750cf0c1d5285992c231d93ec644670fb79cf85324067a9f77fde78", + 185, + "0118b7fb15f927a977e0b330b4fa351aeeec299d6ba090eb16e5114fc4a6749e5915" + "434a123c112697390c96ea2c26dc613eb5c75f5ecfb6c419317426367e34da0ddc6d" + "7b7612cefa70a22fea0025f5186593b22449dab71f90a49f7de7352e54e0c0bd8837" + "e661ca2127c3313a7268cafdd5ccfbf3bdd7c974b0e7551a2d96766579ef8d2e1f37" + "6af74cd1ab62162fc2dc61a8b7ed4163c1caccf20ed73e284da2ed257ec974eee96b" + "502acb2c60a04886465e44debb0317", + }, + }; + + uint8_t hash[SHA3_256_DIGEST_LENGTH]; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + keccak_256(fromhex(tests[i].data), tests[i].length, hash); + ck_assert_mem_eq(hash, fromhex(tests[i].hash), SHA3_256_DIGEST_LENGTH); + } } END_TEST -// test vectors from https://raw.githubusercontent.com/monero-project/monero/master/tests/hash/tests-extra-blake.txt -START_TEST(test_blake256) -{ - struct { - const char *hash; - const char *data; - } tests[] = { - { "716f6e863f744b9ac22c97ec7b76ea5f5908bc5b2f67c61510bfc4751384ea7a", "", }, - { "e104256a2bc501f459d03fac96b9014f593e22d30f4de525fa680c3aa189eb4f", "cc", }, - { "8f341148be7e354fdf38b693d8c6b4e0bd57301a734f6fd35cd85b8491c3ddcd", "41fb", }, - { "bc334d1069099f10c601883ac6f3e7e9787c6aa53171f76a21923cc5ad3ab937", "1f877c", }, - { "b672a16f53982bab1e77685b71c0a5f6703ffd46a1c834be69f614bd128d658e", "c1ecfdfc", }, - { "d9134b2899057a7d8d320cc99e3e116982bc99d3c69d260a7f1ed3da8be68d99", "21f134ac57", }, - { "637923bd29a35aa3ecbbd2a50549fc32c14cf0fdcaf41c3194dd7414fd224815", "c6f50bb74e29", }, - { "70c092fd5c8c21e9ef4bbc82a5c7819e262a530a748caf285ff0cba891954f1e", "119713cc83eeef", }, - { "fdf092993edbb7a0dc7ca67f04051bbd14481639da0808947aff8bfab5abed4b", "4a4f202484512526", }, - { "6f6fc234bf35beae1a366c44c520c59ad5aa70351b5f5085e21e1fe2bfcee709", "1f66ab4185ed9b6375", }, - { "4fdaf89e2a0e78c000061b59455e0ea93a4445b440e7562c8f0cfa165c93de2e", "eed7422227613b6f53c9", }, - { "d6b780eee9c811f664393dc2c58b5a68c92b3c9fe9ceb70371d33ece63b5787e", "eaeed5cdffd89dece455f1", }, - { "d0015071d3e7ed048c764850d76406eceae52b8e2e6e5a2c3aa92ae880485b34", "5be43c90f22902e4fe8ed2d3", }, - { "9b0207902f9932f7a85c24722e93e31f6ed2c75c406509aa0f2f6d1cab046ce4", "a746273228122f381c3b46e4f1", }, - { "258020d5b04a814f2b72c1c661e1f5a5c395d9799e5eee8b8519cf7300e90cb1", "3c5871cd619c69a63b540eb5a625", }, - { "4adae3b55baa907fefc253365fdd99d8398befd0551ed6bf9a2a2784d3c304d1", "fa22874bcc068879e8ef11a69f0722", }, - { "6dd10d772f8d5b4a96c3c5d30878cd9a1073fa835bfe6d2b924fa64a1fab1711", "52a608ab21ccdd8a4457a57ede782176", }, - { "0b8741ddf2259d3af2901eb1ae354f22836442c965556f5c1eb89501191cb46a", "82e192e4043ddcd12ecf52969d0f807eed", }, - { "f48a754ca8193a82643150ab94038b5dd170b4ebd1e0751b78cfb0a98fa5076a", "75683dcb556140c522543bb6e9098b21a21e", }, - { "5698409ab856b74d9fa5e9b259dfa46001f89041752da424e56e491577b88c86", "06e4efe45035e61faaf4287b4d8d1f12ca97e5", }, - }; - - uint8_t hash[BLAKE256_DIGEST_LENGTH]; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - blake256(fromhex(tests[i].data), i, hash); - ck_assert_mem_eq(hash, fromhex(tests[i].hash), BLAKE256_DIGEST_LENGTH); - } +// test vectors from +// https://raw.githubusercontent.com/monero-project/monero/master/tests/hash/tests-extra-blake.txt +START_TEST(test_blake256) { + struct { + const char *hash; + const char *data; + } tests[] = { + { + "716f6e863f744b9ac22c97ec7b76ea5f5908bc5b2f67c61510bfc4751384ea7a", + "", + }, + { + "e104256a2bc501f459d03fac96b9014f593e22d30f4de525fa680c3aa189eb4f", + "cc", + }, + { + "8f341148be7e354fdf38b693d8c6b4e0bd57301a734f6fd35cd85b8491c3ddcd", + "41fb", + }, + { + "bc334d1069099f10c601883ac6f3e7e9787c6aa53171f76a21923cc5ad3ab937", + "1f877c", + }, + { + "b672a16f53982bab1e77685b71c0a5f6703ffd46a1c834be69f614bd128d658e", + "c1ecfdfc", + }, + { + "d9134b2899057a7d8d320cc99e3e116982bc99d3c69d260a7f1ed3da8be68d99", + "21f134ac57", + }, + { + "637923bd29a35aa3ecbbd2a50549fc32c14cf0fdcaf41c3194dd7414fd224815", + "c6f50bb74e29", + }, + { + "70c092fd5c8c21e9ef4bbc82a5c7819e262a530a748caf285ff0cba891954f1e", + "119713cc83eeef", + }, + { + "fdf092993edbb7a0dc7ca67f04051bbd14481639da0808947aff8bfab5abed4b", + "4a4f202484512526", + }, + { + "6f6fc234bf35beae1a366c44c520c59ad5aa70351b5f5085e21e1fe2bfcee709", + "1f66ab4185ed9b6375", + }, + { + "4fdaf89e2a0e78c000061b59455e0ea93a4445b440e7562c8f0cfa165c93de2e", + "eed7422227613b6f53c9", + }, + { + "d6b780eee9c811f664393dc2c58b5a68c92b3c9fe9ceb70371d33ece63b5787e", + "eaeed5cdffd89dece455f1", + }, + { + "d0015071d3e7ed048c764850d76406eceae52b8e2e6e5a2c3aa92ae880485b34", + "5be43c90f22902e4fe8ed2d3", + }, + { + "9b0207902f9932f7a85c24722e93e31f6ed2c75c406509aa0f2f6d1cab046ce4", + "a746273228122f381c3b46e4f1", + }, + { + "258020d5b04a814f2b72c1c661e1f5a5c395d9799e5eee8b8519cf7300e90cb1", + "3c5871cd619c69a63b540eb5a625", + }, + { + "4adae3b55baa907fefc253365fdd99d8398befd0551ed6bf9a2a2784d3c304d1", + "fa22874bcc068879e8ef11a69f0722", + }, + { + "6dd10d772f8d5b4a96c3c5d30878cd9a1073fa835bfe6d2b924fa64a1fab1711", + "52a608ab21ccdd8a4457a57ede782176", + }, + { + "0b8741ddf2259d3af2901eb1ae354f22836442c965556f5c1eb89501191cb46a", + "82e192e4043ddcd12ecf52969d0f807eed", + }, + { + "f48a754ca8193a82643150ab94038b5dd170b4ebd1e0751b78cfb0a98fa5076a", + "75683dcb556140c522543bb6e9098b21a21e", + }, + { + "5698409ab856b74d9fa5e9b259dfa46001f89041752da424e56e491577b88c86", + "06e4efe45035e61faaf4287b4d8d1f12ca97e5", + }, + }; + + uint8_t hash[BLAKE256_DIGEST_LENGTH]; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + blake256(fromhex(tests[i].data), i, hash); + ck_assert_mem_eq(hash, fromhex(tests[i].hash), BLAKE256_DIGEST_LENGTH); + } } END_TEST -// test vectors from https://raw.githubusercontent.com/BLAKE2/BLAKE2/master/testvectors/blake2b-kat.txt -START_TEST(test_blake2b) -{ - uint8_t key[BLAKE2B_KEY_LENGTH]; - memcpy(key, fromhex("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f"), BLAKE2B_KEY_LENGTH); - - uint8_t digest[BLAKE2B_DIGEST_LENGTH]; - - blake2b_Key((uint8_t *)"", 0, key, BLAKE2B_KEY_LENGTH, digest, BLAKE2B_DIGEST_LENGTH); - ck_assert_mem_eq(digest, fromhex("10ebb67700b1868efb4417987acf4690ae9d972fb7a590c2f02871799aaa4786b5e996e8f0f4eb981fc214b005f42d2ff4233499391653df7aefcbc13fc51568"), BLAKE2B_DIGEST_LENGTH); - - blake2b_Key(fromhex("000102"), 3, key, BLAKE2B_KEY_LENGTH, digest, BLAKE2B_DIGEST_LENGTH); - ck_assert_mem_eq(digest, fromhex("33d0825dddf7ada99b0e7e307104ad07ca9cfd9692214f1561356315e784f3e5a17e364ae9dbb14cb2036df932b77f4b292761365fb328de7afdc6d8998f5fc1"), BLAKE2B_DIGEST_LENGTH); - - blake2b_Key(fromhex("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637"), 56, key, BLAKE2B_KEY_LENGTH, digest, BLAKE2B_DIGEST_LENGTH); - ck_assert_mem_eq(digest, fromhex("f8f3726ac5a26cc80132493a6fedcb0e60760c09cfc84cad178175986819665e76842d7b9fedf76dddebf5d3f56faaad4477587af21606d396ae570d8e719af2"), BLAKE2B_DIGEST_LENGTH); - - blake2b_Key(fromhex("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f"), 112, key, BLAKE2B_KEY_LENGTH, digest, BLAKE2B_DIGEST_LENGTH); - ck_assert_mem_eq(digest, fromhex("227e3aed8d2cb10b918fcb04f9de3e6d0a57e08476d93759cd7b2ed54a1cbf0239c528fb04bbf288253e601d3bc38b21794afef90b17094a182cac557745e75f"), BLAKE2B_DIGEST_LENGTH); +// test vectors from +// https://raw.githubusercontent.com/BLAKE2/BLAKE2/master/testvectors/blake2b-kat.txt +START_TEST(test_blake2b) { + uint8_t key[BLAKE2B_KEY_LENGTH]; + memcpy(key, + fromhex( + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2" + "02122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f"), + BLAKE2B_KEY_LENGTH); + + uint8_t digest[BLAKE2B_DIGEST_LENGTH]; + + blake2b_Key((uint8_t *)"", 0, key, BLAKE2B_KEY_LENGTH, digest, + BLAKE2B_DIGEST_LENGTH); + ck_assert_mem_eq( + digest, + fromhex( + "10ebb67700b1868efb4417987acf4690ae9d972fb7a590c2f02871799aaa4786b5e9" + "96e8f0f4eb981fc214b005f42d2ff4233499391653df7aefcbc13fc51568"), + BLAKE2B_DIGEST_LENGTH); + + blake2b_Key(fromhex("000102"), 3, key, BLAKE2B_KEY_LENGTH, digest, + BLAKE2B_DIGEST_LENGTH); + ck_assert_mem_eq( + digest, + fromhex( + "33d0825dddf7ada99b0e7e307104ad07ca9cfd9692214f1561356315e784f3e5a17e" + "364ae9dbb14cb2036df932b77f4b292761365fb328de7afdc6d8998f5fc1"), + BLAKE2B_DIGEST_LENGTH); + + blake2b_Key( + fromhex("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" + "202122232425262728292a2b2c2d2e2f3031323334353637"), + 56, key, BLAKE2B_KEY_LENGTH, digest, BLAKE2B_DIGEST_LENGTH); + ck_assert_mem_eq( + digest, + fromhex( + "f8f3726ac5a26cc80132493a6fedcb0e60760c09cfc84cad178175986819665e7684" + "2d7b9fedf76dddebf5d3f56faaad4477587af21606d396ae570d8e719af2"), + BLAKE2B_DIGEST_LENGTH); + + blake2b_Key( + fromhex("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" + "202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f" + "404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f" + "606162636465666768696a6b6c6d6e6f"), + 112, key, BLAKE2B_KEY_LENGTH, digest, BLAKE2B_DIGEST_LENGTH); + ck_assert_mem_eq( + digest, + fromhex( + "227e3aed8d2cb10b918fcb04f9de3e6d0a57e08476d93759cd7b2ed54a1cbf0239c5" + "28fb04bbf288253e601d3bc38b21794afef90b17094a182cac557745e75f"), + BLAKE2B_DIGEST_LENGTH); } END_TEST -// test vectors from https://raw.githubusercontent.com/BLAKE2/BLAKE2/master/testvectors/blake2s-kat.txt -START_TEST(test_blake2s) -{ - uint8_t key[BLAKE2S_KEY_LENGTH]; - memcpy(key, fromhex("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"), BLAKE2S_KEY_LENGTH); - - uint8_t digest[BLAKE2S_DIGEST_LENGTH]; - - blake2s_Key((uint8_t *)"", 0, key, BLAKE2S_KEY_LENGTH, digest, BLAKE2S_DIGEST_LENGTH); - ck_assert_mem_eq(digest, fromhex("48a8997da407876b3d79c0d92325ad3b89cbb754d86ab71aee047ad345fd2c49"), BLAKE2S_DIGEST_LENGTH); - - blake2s_Key(fromhex("000102"), 3, key, BLAKE2S_KEY_LENGTH, digest, BLAKE2S_DIGEST_LENGTH); - ck_assert_mem_eq(digest, fromhex("1d220dbe2ee134661fdf6d9e74b41704710556f2f6e5a091b227697445dbea6b"), BLAKE2S_DIGEST_LENGTH); - - blake2s_Key(fromhex("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637"), 56, key, BLAKE2S_KEY_LENGTH, digest, BLAKE2S_DIGEST_LENGTH); - ck_assert_mem_eq(digest, fromhex("2966b3cfae1e44ea996dc5d686cf25fa053fb6f67201b9e46eade85d0ad6b806"), BLAKE2S_DIGEST_LENGTH); - - blake2s_Key(fromhex("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f"), 112, key, BLAKE2S_KEY_LENGTH, digest, BLAKE2S_DIGEST_LENGTH); - ck_assert_mem_eq(digest, fromhex("90a83585717b75f0e9b725e055eeeeb9e7a028ea7e6cbc07b20917ec0363e38c"), BLAKE2S_DIGEST_LENGTH); +// test vectors from +// https://raw.githubusercontent.com/BLAKE2/BLAKE2/master/testvectors/blake2s-kat.txt +START_TEST(test_blake2s) { + uint8_t key[BLAKE2S_KEY_LENGTH]; + memcpy( + key, + fromhex( + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"), + BLAKE2S_KEY_LENGTH); + + uint8_t digest[BLAKE2S_DIGEST_LENGTH]; + + blake2s_Key((uint8_t *)"", 0, key, BLAKE2S_KEY_LENGTH, digest, + BLAKE2S_DIGEST_LENGTH); + ck_assert_mem_eq( + digest, + fromhex( + "48a8997da407876b3d79c0d92325ad3b89cbb754d86ab71aee047ad345fd2c49"), + BLAKE2S_DIGEST_LENGTH); + + blake2s_Key(fromhex("000102"), 3, key, BLAKE2S_KEY_LENGTH, digest, + BLAKE2S_DIGEST_LENGTH); + ck_assert_mem_eq( + digest, + fromhex( + "1d220dbe2ee134661fdf6d9e74b41704710556f2f6e5a091b227697445dbea6b"), + BLAKE2S_DIGEST_LENGTH); + + blake2s_Key( + fromhex("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" + "202122232425262728292a2b2c2d2e2f3031323334353637"), + 56, key, BLAKE2S_KEY_LENGTH, digest, BLAKE2S_DIGEST_LENGTH); + ck_assert_mem_eq( + digest, + fromhex( + "2966b3cfae1e44ea996dc5d686cf25fa053fb6f67201b9e46eade85d0ad6b806"), + BLAKE2S_DIGEST_LENGTH); + + blake2s_Key( + fromhex("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" + "202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f" + "404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f" + "606162636465666768696a6b6c6d6e6f"), + 112, key, BLAKE2S_KEY_LENGTH, digest, BLAKE2S_DIGEST_LENGTH); + ck_assert_mem_eq( + digest, + fromhex( + "90a83585717b75f0e9b725e055eeeeb9e7a028ea7e6cbc07b20917ec0363e38c"), + BLAKE2S_DIGEST_LENGTH); } END_TEST -START_TEST(test_pbkdf2_hmac_sha256) -{ - uint8_t k[64]; - - // test vectors from https://stackoverflow.com/questions/5130513/pbkdf2-hmac-sha2-test-vectors - pbkdf2_hmac_sha256((const uint8_t *)"password", 8, (const uint8_t *)"salt", 4, 1, k, 32); - ck_assert_mem_eq(k, fromhex("120fb6cffcf8b32c43e7225256c4f837a86548c92ccc35480805987cb70be17b"), 32); - - pbkdf2_hmac_sha256((const uint8_t *)"password", 8, (const uint8_t *)"salt", 4, 2, k, 32); - ck_assert_mem_eq(k, fromhex("ae4d0c95af6b46d32d0adff928f06dd02a303f8ef3c251dfd6e2d85a95474c43"), 32); - - pbkdf2_hmac_sha256((const uint8_t *)"password", 8, (const uint8_t *)"salt", 4, 4096, k, 32); - ck_assert_mem_eq(k, fromhex("c5e478d59288c841aa530db6845c4c8d962893a001ce4e11a4963873aa98134a"), 32); - - pbkdf2_hmac_sha256((const uint8_t *)"passwordPASSWORDpassword", 3 * 8, (const uint8_t *)"saltSALTsaltSALTsaltSALTsaltSALTsalt", 9 * 4, 4096, k, 40); - ck_assert_mem_eq(k, fromhex("348c89dbcbd32b2f32d814b8116e84cf2b17347ebc1800181c4e2a1fb8dd53e1c635518c7dac47e9"), 40); - - pbkdf2_hmac_sha256((const uint8_t *)"pass\x00word", 9, (const uint8_t *)"sa\x00lt", 5, 4096, k, 16); - ck_assert_mem_eq(k, fromhex("89b69d0516f829893c696226650a8687"), 16); - - // test vector from https://tools.ietf.org/html/rfc7914.html#section-11 - pbkdf2_hmac_sha256((const uint8_t *)"passwd", 6, (const uint8_t *)"salt", 4, 1, k, 64); - ck_assert_mem_eq(k, fromhex("55ac046e56e3089fec1691c22544b605f94185216dde0465e68b9d57c20dacbc49ca9cccf179b645991664b39d77ef317c71b845b1e30bd509112041d3a19783"), 64); +START_TEST(test_pbkdf2_hmac_sha256) { + uint8_t k[64]; + + // test vectors from + // https://stackoverflow.com/questions/5130513/pbkdf2-hmac-sha2-test-vectors + pbkdf2_hmac_sha256((const uint8_t *)"password", 8, (const uint8_t *)"salt", 4, + 1, k, 32); + ck_assert_mem_eq( + k, + fromhex( + "120fb6cffcf8b32c43e7225256c4f837a86548c92ccc35480805987cb70be17b"), + 32); + + pbkdf2_hmac_sha256((const uint8_t *)"password", 8, (const uint8_t *)"salt", 4, + 2, k, 32); + ck_assert_mem_eq( + k, + fromhex( + "ae4d0c95af6b46d32d0adff928f06dd02a303f8ef3c251dfd6e2d85a95474c43"), + 32); + + pbkdf2_hmac_sha256((const uint8_t *)"password", 8, (const uint8_t *)"salt", 4, + 4096, k, 32); + ck_assert_mem_eq( + k, + fromhex( + "c5e478d59288c841aa530db6845c4c8d962893a001ce4e11a4963873aa98134a"), + 32); + + pbkdf2_hmac_sha256((const uint8_t *)"passwordPASSWORDpassword", 3 * 8, + (const uint8_t *)"saltSALTsaltSALTsaltSALTsaltSALTsalt", + 9 * 4, 4096, k, 40); + ck_assert_mem_eq(k, + fromhex("348c89dbcbd32b2f32d814b8116e84cf2b17347ebc1800181c4" + "e2a1fb8dd53e1c635518c7dac47e9"), + 40); + + pbkdf2_hmac_sha256((const uint8_t *)"pass\x00word", 9, + (const uint8_t *)"sa\x00lt", 5, 4096, k, 16); + ck_assert_mem_eq(k, fromhex("89b69d0516f829893c696226650a8687"), 16); + + // test vector from https://tools.ietf.org/html/rfc7914.html#section-11 + pbkdf2_hmac_sha256((const uint8_t *)"passwd", 6, (const uint8_t *)"salt", 4, + 1, k, 64); + ck_assert_mem_eq( + k, + fromhex( + "55ac046e56e3089fec1691c22544b605f94185216dde0465e68b9d57c20dacbc49ca" + "9cccf179b645991664b39d77ef317c71b845b1e30bd509112041d3a19783"), + 64); } END_TEST -// test vectors from http://stackoverflow.com/questions/15593184/pbkdf2-hmac-sha-512-test-vectors -START_TEST(test_pbkdf2_hmac_sha512) -{ - uint8_t k[64]; - - pbkdf2_hmac_sha512((uint8_t *)"password", 8, (const uint8_t *)"salt", 4, 1, k, 64); - ck_assert_mem_eq(k, fromhex("867f70cf1ade02cff3752599a3a53dc4af34c7a669815ae5d513554e1c8cf252c02d470a285a0501bad999bfe943c08f050235d7d68b1da55e63f73b60a57fce"), 64); - - pbkdf2_hmac_sha512((uint8_t *)"password", 8, (const uint8_t *)"salt", 4, 2, k, 64); - ck_assert_mem_eq(k, fromhex("e1d9c16aa681708a45f5c7c4e215ceb66e011a2e9f0040713f18aefdb866d53cf76cab2868a39b9f7840edce4fef5a82be67335c77a6068e04112754f27ccf4e"), 64); - - pbkdf2_hmac_sha512((uint8_t *)"password", 8, (const uint8_t *)"salt", 4, 4096, k, 64); - ck_assert_mem_eq(k, fromhex("d197b1b33db0143e018b12f3d1d1479e6cdebdcc97c5c0f87f6902e072f457b5143f30602641b3d55cd335988cb36b84376060ecd532e039b742a239434af2d5"), 64); - - pbkdf2_hmac_sha512((uint8_t *)"passwordPASSWORDpassword", 3 * 8, (const uint8_t *)"saltSALTsaltSALTsaltSALTsaltSALTsalt", 9 * 4, 4096, k, 64); - ck_assert_mem_eq(k, fromhex("8c0511f4c6e597c6ac6315d8f0362e225f3c501495ba23b868c005174dc4ee71115b59f9e60cd9532fa33e0f75aefe30225c583a186cd82bd4daea9724a3d3b8"), 64); +// test vectors from +// http://stackoverflow.com/questions/15593184/pbkdf2-hmac-sha-512-test-vectors +START_TEST(test_pbkdf2_hmac_sha512) { + uint8_t k[64]; + + pbkdf2_hmac_sha512((uint8_t *)"password", 8, (const uint8_t *)"salt", 4, 1, k, + 64); + ck_assert_mem_eq( + k, + fromhex( + "867f70cf1ade02cff3752599a3a53dc4af34c7a669815ae5d513554e1c8cf252c02d" + "470a285a0501bad999bfe943c08f050235d7d68b1da55e63f73b60a57fce"), + 64); + + pbkdf2_hmac_sha512((uint8_t *)"password", 8, (const uint8_t *)"salt", 4, 2, k, + 64); + ck_assert_mem_eq( + k, + fromhex( + "e1d9c16aa681708a45f5c7c4e215ceb66e011a2e9f0040713f18aefdb866d53cf76c" + "ab2868a39b9f7840edce4fef5a82be67335c77a6068e04112754f27ccf4e"), + 64); + + pbkdf2_hmac_sha512((uint8_t *)"password", 8, (const uint8_t *)"salt", 4, 4096, + k, 64); + ck_assert_mem_eq( + k, + fromhex( + "d197b1b33db0143e018b12f3d1d1479e6cdebdcc97c5c0f87f6902e072f457b5143f" + "30602641b3d55cd335988cb36b84376060ecd532e039b742a239434af2d5"), + 64); + + pbkdf2_hmac_sha512((uint8_t *)"passwordPASSWORDpassword", 3 * 8, + (const uint8_t *)"saltSALTsaltSALTsaltSALTsaltSALTsalt", + 9 * 4, 4096, k, 64); + ck_assert_mem_eq( + k, + fromhex( + "8c0511f4c6e597c6ac6315d8f0362e225f3c501495ba23b868c005174dc4ee71115b" + "59f9e60cd9532fa33e0f75aefe30225c583a186cd82bd4daea9724a3d3b8"), + 64); } END_TEST -START_TEST(test_mnemonic) -{ - static const char *vectors[] = { - "00000000000000000000000000000000", - "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about", - "c55257c360c07c72029aebc1b53c05ed0362ada38ead3e3e9efa3708e53495531f09a6987599d18264c1e1c92f2cf141630c7a3c4ab7c81b2f001698e7463b04", - "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", - "legal winner thank year wave sausage worth useful legal winner thank yellow", - "2e8905819b8723fe2c1d161860e5ee1830318dbf49a83bd451cfb8440c28bd6fa457fe1296106559a3c80937a1c1069be3a3a5bd381ee6260e8d9739fce1f607", - "80808080808080808080808080808080", - "letter advice cage absurd amount doctor acoustic avoid letter advice cage above", - "d71de856f81a8acc65e6fc851a38d4d7ec216fd0796d0a6827a3ad6ed5511a30fa280f12eb2e47ed2ac03b5c462a0358d18d69fe4f985ec81778c1b370b652a8", - "ffffffffffffffffffffffffffffffff", - "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong", - "ac27495480225222079d7be181583751e86f571027b0497b5b5d11218e0a8a13332572917f0f8e5a589620c6f15b11c61dee327651a14c34e18231052e48c069", - "000000000000000000000000000000000000000000000000", - "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon agent", - "035895f2f481b1b0f01fcf8c289c794660b289981a78f8106447707fdd9666ca06da5a9a565181599b79f53b844d8a71dd9f439c52a3d7b3e8a79c906ac845fa", - "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", - "legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal will", - "f2b94508732bcbacbcc020faefecfc89feafa6649a5491b8c952cede496c214a0c7b3c392d168748f2d4a612bada0753b52a1c7ac53c1e93abd5c6320b9e95dd", - "808080808080808080808080808080808080808080808080", - "letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter always", - "107d7c02a5aa6f38c58083ff74f04c607c2d2c0ecc55501dadd72d025b751bc27fe913ffb796f841c49b1d33b610cf0e91d3aa239027f5e99fe4ce9e5088cd65", - "ffffffffffffffffffffffffffffffffffffffffffffffff", - "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo when", - "0cd6e5d827bb62eb8fc1e262254223817fd068a74b5b449cc2f667c3f1f985a76379b43348d952e2265b4cd129090758b3e3c2c49103b5051aac2eaeb890a528", - "0000000000000000000000000000000000000000000000000000000000000000", - "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon art", - "bda85446c68413707090a52022edd26a1c9462295029f2e60cd7c4f2bbd3097170af7a4d73245cafa9c3cca8d561a7c3de6f5d4a10be8ed2a5e608d68f92fcc8", - "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", - "legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth title", - "bc09fca1804f7e69da93c2f2028eb238c227f2e9dda30cd63699232578480a4021b146ad717fbb7e451ce9eb835f43620bf5c514db0f8add49f5d121449d3e87", - "8080808080808080808080808080808080808080808080808080808080808080", - "letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic bless", - "c0c519bd0e91a2ed54357d9d1ebef6f5af218a153624cf4f2da911a0ed8f7a09e2ef61af0aca007096df430022f7a2b6fb91661a9589097069720d015e4e982f", - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo vote", - "dd48c104698c30cfe2b6142103248622fb7bb0ff692eebb00089b32d22484e1613912f0a5b694407be899ffd31ed3992c456cdf60f5d4564b8ba3f05a69890ad", - "77c2b00716cec7213839159e404db50d", - "jelly better achieve collect unaware mountain thought cargo oxygen act hood bridge", - "b5b6d0127db1a9d2226af0c3346031d77af31e918dba64287a1b44b8ebf63cdd52676f672a290aae502472cf2d602c051f3e6f18055e84e4c43897fc4e51a6ff", - "b63a9c59a6e641f288ebc103017f1da9f8290b3da6bdef7b", - "renew stay biology evidence goat welcome casual join adapt armor shuffle fault little machine walk stumble urge swap", - "9248d83e06f4cd98debf5b6f010542760df925ce46cf38a1bdb4e4de7d21f5c39366941c69e1bdbf2966e0f6e6dbece898a0e2f0a4c2b3e640953dfe8b7bbdc5", - "3e141609b97933b66a060dcddc71fad1d91677db872031e85f4c015c5e7e8982", - "dignity pass list indicate nasty swamp pool script soccer toe leaf photo multiply desk host tomato cradle drill spread actor shine dismiss champion exotic", - "ff7f3184df8696d8bef94b6c03114dbee0ef89ff938712301d27ed8336ca89ef9635da20af07d4175f2bf5f3de130f39c9d9e8dd0472489c19b1a020a940da67", - "0460ef47585604c5660618db2e6a7e7f", - "afford alter spike radar gate glance object seek swamp infant panel yellow", - "65f93a9f36b6c85cbe634ffc1f99f2b82cbb10b31edc7f087b4f6cb9e976e9faf76ff41f8f27c99afdf38f7a303ba1136ee48a4c1e7fcd3dba7aa876113a36e4", - "72f60ebac5dd8add8d2a25a797102c3ce21bc029c200076f", - "indicate race push merry suffer human cruise dwarf pole review arch keep canvas theme poem divorce alter left", - "3bbf9daa0dfad8229786ace5ddb4e00fa98a044ae4c4975ffd5e094dba9e0bb289349dbe2091761f30f382d4e35c4a670ee8ab50758d2c55881be69e327117ba", - "2c85efc7f24ee4573d2b81a6ec66cee209b2dcbd09d8eddc51e0215b0b68e416", - "clutch control vehicle tonight unusual clog visa ice plunge glimpse recipe series open hour vintage deposit universe tip job dress radar refuse motion taste", - "fe908f96f46668b2d5b37d82f558c77ed0d69dd0e7e043a5b0511c48c2f1064694a956f86360c93dd04052a8899497ce9e985ebe0c8c52b955e6ae86d4ff4449", - "eaebabb2383351fd31d703840b32e9e2", - "turtle front uncle idea crush write shrug there lottery flower risk shell", - "bdfb76a0759f301b0b899a1e3985227e53b3f51e67e3f2a65363caedf3e32fde42a66c404f18d7b05818c95ef3ca1e5146646856c461c073169467511680876c", - "7ac45cfe7722ee6c7ba84fbc2d5bd61b45cb2fe5eb65aa78", - "kiss carry display unusual confirm curtain upgrade antique rotate hello void custom frequent obey nut hole price segment", - "ed56ff6c833c07982eb7119a8f48fd363c4a9b1601cd2de736b01045c5eb8ab4f57b079403485d1c4924f0790dc10a971763337cb9f9c62226f64fff26397c79", - "4fa1a8bc3e6d80ee1316050e862c1812031493212b7ec3f3bb1b08f168cabeef", - "exile ask congress lamp submit jacket era scheme attend cousin alcohol catch course end lucky hurt sentence oven short ball bird grab wing top", - "095ee6f817b4c2cb30a5a797360a81a40ab0f9a4e25ecd672a3f58a0b5ba0687c096a6b14d2c0deb3bdefce4f61d01ae07417d502429352e27695163f7447a8c", - "18ab19a9f54a9274f03e5209a2ac8a91", - "board flee heavy tunnel powder denial science ski answer betray cargo cat", - "6eff1bb21562918509c73cb990260db07c0ce34ff0e3cc4a8cb3276129fbcb300bddfe005831350efd633909f476c45c88253276d9fd0df6ef48609e8bb7dca8", - "18a2e1d81b8ecfb2a333adcb0c17a5b9eb76cc5d05db91a4", - "board blade invite damage undo sun mimic interest slam gaze truly inherit resist great inject rocket museum chief", - "f84521c777a13b61564234bf8f8b62b3afce27fc4062b51bb5e62bdfecb23864ee6ecf07c1d5a97c0834307c5c852d8ceb88e7c97923c0a3b496bedd4e5f88a9", - "15da872c95a13dd738fbf50e427583ad61f18fd99f628c417a61cf8343c90419", - "beyond stage sleep clip because twist token leaf atom beauty genius food business side grid unable middle armed observe pair crouch tonight away coconut", - "b15509eaa2d09d3efd3e006ef42151b30367dc6e3aa5e44caba3fe4d3e352e65101fbdb86a96776b91946ff06f8eac594dc6ee1d3e82a42dfe1b40fef6bcc3fd", - 0, - 0, - 0, - }; - - const char **a, **b, **c, *m; - uint8_t seed[64]; - - a = vectors; - b = vectors + 1; - c = vectors + 2; - while (*a && *b && *c) { - m = mnemonic_from_data(fromhex(*a), strlen(*a) / 2); - ck_assert_str_eq(m, *b); - mnemonic_to_seed(m, "TREZOR", seed, 0); - ck_assert_mem_eq(seed, fromhex(*c), strlen(*c) / 2); +START_TEST(test_mnemonic) { + static const char *vectors[] = { + "00000000000000000000000000000000", + "abandon abandon abandon abandon abandon abandon abandon abandon abandon " + "abandon abandon about", + "c55257c360c07c72029aebc1b53c05ed0362ada38ead3e3e9efa3708e53495531f09a698" + "7599d18264c1e1c92f2cf141630c7a3c4ab7c81b2f001698e7463b04", + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", + "legal winner thank year wave sausage worth useful legal winner thank " + "yellow", + "2e8905819b8723fe2c1d161860e5ee1830318dbf49a83bd451cfb8440c28bd6fa457fe12" + "96106559a3c80937a1c1069be3a3a5bd381ee6260e8d9739fce1f607", + "80808080808080808080808080808080", + "letter advice cage absurd amount doctor acoustic avoid letter advice " + "cage above", + "d71de856f81a8acc65e6fc851a38d4d7ec216fd0796d0a6827a3ad6ed5511a30fa280f12" + "eb2e47ed2ac03b5c462a0358d18d69fe4f985ec81778c1b370b652a8", + "ffffffffffffffffffffffffffffffff", + "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong", + "ac27495480225222079d7be181583751e86f571027b0497b5b5d11218e0a8a1333257291" + "7f0f8e5a589620c6f15b11c61dee327651a14c34e18231052e48c069", + "000000000000000000000000000000000000000000000000", + "abandon abandon abandon abandon abandon abandon abandon abandon abandon " + "abandon abandon abandon abandon abandon abandon abandon abandon agent", + "035895f2f481b1b0f01fcf8c289c794660b289981a78f8106447707fdd9666ca06da5a9a" + "565181599b79f53b844d8a71dd9f439c52a3d7b3e8a79c906ac845fa", + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", + "legal winner thank year wave sausage worth useful legal winner thank " + "year wave sausage worth useful legal will", + "f2b94508732bcbacbcc020faefecfc89feafa6649a5491b8c952cede496c214a0c7b3c39" + "2d168748f2d4a612bada0753b52a1c7ac53c1e93abd5c6320b9e95dd", + "808080808080808080808080808080808080808080808080", + "letter advice cage absurd amount doctor acoustic avoid letter advice " + "cage absurd amount doctor acoustic avoid letter always", + "107d7c02a5aa6f38c58083ff74f04c607c2d2c0ecc55501dadd72d025b751bc27fe913ff" + "b796f841c49b1d33b610cf0e91d3aa239027f5e99fe4ce9e5088cd65", + "ffffffffffffffffffffffffffffffffffffffffffffffff", + "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo " + "when", + "0cd6e5d827bb62eb8fc1e262254223817fd068a74b5b449cc2f667c3f1f985a76379b433" + "48d952e2265b4cd129090758b3e3c2c49103b5051aac2eaeb890a528", + "0000000000000000000000000000000000000000000000000000000000000000", + "abandon abandon abandon abandon abandon abandon abandon abandon abandon " + "abandon abandon abandon abandon abandon abandon abandon abandon abandon " + "abandon abandon abandon abandon abandon art", + "bda85446c68413707090a52022edd26a1c9462295029f2e60cd7c4f2bbd3097170af7a4d" + "73245cafa9c3cca8d561a7c3de6f5d4a10be8ed2a5e608d68f92fcc8", + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", + "legal winner thank year wave sausage worth useful legal winner thank " + "year wave sausage worth useful legal winner thank year wave sausage " + "worth title", + "bc09fca1804f7e69da93c2f2028eb238c227f2e9dda30cd63699232578480a4021b146ad" + "717fbb7e451ce9eb835f43620bf5c514db0f8add49f5d121449d3e87", + "8080808080808080808080808080808080808080808080808080808080808080", + "letter advice cage absurd amount doctor acoustic avoid letter advice " + "cage absurd amount doctor acoustic avoid letter advice cage absurd " + "amount doctor acoustic bless", + "c0c519bd0e91a2ed54357d9d1ebef6f5af218a153624cf4f2da911a0ed8f7a09e2ef61af" + "0aca007096df430022f7a2b6fb91661a9589097069720d015e4e982f", + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo " + "zoo zoo zoo zoo zoo vote", + "dd48c104698c30cfe2b6142103248622fb7bb0ff692eebb00089b32d22484e1613912f0a" + "5b694407be899ffd31ed3992c456cdf60f5d4564b8ba3f05a69890ad", + "77c2b00716cec7213839159e404db50d", + "jelly better achieve collect unaware mountain thought cargo oxygen act " + "hood bridge", + "b5b6d0127db1a9d2226af0c3346031d77af31e918dba64287a1b44b8ebf63cdd52676f67" + "2a290aae502472cf2d602c051f3e6f18055e84e4c43897fc4e51a6ff", + "b63a9c59a6e641f288ebc103017f1da9f8290b3da6bdef7b", + "renew stay biology evidence goat welcome casual join adapt armor " + "shuffle fault little machine walk stumble urge swap", + "9248d83e06f4cd98debf5b6f010542760df925ce46cf38a1bdb4e4de7d21f5c39366941c" + "69e1bdbf2966e0f6e6dbece898a0e2f0a4c2b3e640953dfe8b7bbdc5", + "3e141609b97933b66a060dcddc71fad1d91677db872031e85f4c015c5e7e8982", + "dignity pass list indicate nasty swamp pool script soccer toe leaf " + "photo multiply desk host tomato cradle drill spread actor shine dismiss " + "champion exotic", + "ff7f3184df8696d8bef94b6c03114dbee0ef89ff938712301d27ed8336ca89ef9635da20" + "af07d4175f2bf5f3de130f39c9d9e8dd0472489c19b1a020a940da67", + "0460ef47585604c5660618db2e6a7e7f", + "afford alter spike radar gate glance object seek swamp infant panel " + "yellow", + "65f93a9f36b6c85cbe634ffc1f99f2b82cbb10b31edc7f087b4f6cb9e976e9faf76ff41f" + "8f27c99afdf38f7a303ba1136ee48a4c1e7fcd3dba7aa876113a36e4", + "72f60ebac5dd8add8d2a25a797102c3ce21bc029c200076f", + "indicate race push merry suffer human cruise dwarf pole review arch " + "keep canvas theme poem divorce alter left", + "3bbf9daa0dfad8229786ace5ddb4e00fa98a044ae4c4975ffd5e094dba9e0bb289349dbe" + "2091761f30f382d4e35c4a670ee8ab50758d2c55881be69e327117ba", + "2c85efc7f24ee4573d2b81a6ec66cee209b2dcbd09d8eddc51e0215b0b68e416", + "clutch control vehicle tonight unusual clog visa ice plunge glimpse " + "recipe series open hour vintage deposit universe tip job dress radar " + "refuse motion taste", + "fe908f96f46668b2d5b37d82f558c77ed0d69dd0e7e043a5b0511c48c2f1064694a956f8" + "6360c93dd04052a8899497ce9e985ebe0c8c52b955e6ae86d4ff4449", + "eaebabb2383351fd31d703840b32e9e2", + "turtle front uncle idea crush write shrug there lottery flower risk " + "shell", + "bdfb76a0759f301b0b899a1e3985227e53b3f51e67e3f2a65363caedf3e32fde42a66c40" + "4f18d7b05818c95ef3ca1e5146646856c461c073169467511680876c", + "7ac45cfe7722ee6c7ba84fbc2d5bd61b45cb2fe5eb65aa78", + "kiss carry display unusual confirm curtain upgrade antique rotate hello " + "void custom frequent obey nut hole price segment", + "ed56ff6c833c07982eb7119a8f48fd363c4a9b1601cd2de736b01045c5eb8ab4f57b0794" + "03485d1c4924f0790dc10a971763337cb9f9c62226f64fff26397c79", + "4fa1a8bc3e6d80ee1316050e862c1812031493212b7ec3f3bb1b08f168cabeef", + "exile ask congress lamp submit jacket era scheme attend cousin alcohol " + "catch course end lucky hurt sentence oven short ball bird grab wing top", + "095ee6f817b4c2cb30a5a797360a81a40ab0f9a4e25ecd672a3f58a0b5ba0687c096a6b1" + "4d2c0deb3bdefce4f61d01ae07417d502429352e27695163f7447a8c", + "18ab19a9f54a9274f03e5209a2ac8a91", + "board flee heavy tunnel powder denial science ski answer betray cargo " + "cat", + "6eff1bb21562918509c73cb990260db07c0ce34ff0e3cc4a8cb3276129fbcb300bddfe00" + "5831350efd633909f476c45c88253276d9fd0df6ef48609e8bb7dca8", + "18a2e1d81b8ecfb2a333adcb0c17a5b9eb76cc5d05db91a4", + "board blade invite damage undo sun mimic interest slam gaze truly " + "inherit resist great inject rocket museum chief", + "f84521c777a13b61564234bf8f8b62b3afce27fc4062b51bb5e62bdfecb23864ee6ecf07" + "c1d5a97c0834307c5c852d8ceb88e7c97923c0a3b496bedd4e5f88a9", + "15da872c95a13dd738fbf50e427583ad61f18fd99f628c417a61cf8343c90419", + "beyond stage sleep clip because twist token leaf atom beauty genius " + "food business side grid unable middle armed observe pair crouch tonight " + "away coconut", + "b15509eaa2d09d3efd3e006ef42151b30367dc6e3aa5e44caba3fe4d3e352e65101fbdb8" + "6a96776b91946ff06f8eac594dc6ee1d3e82a42dfe1b40fef6bcc3fd", + 0, + 0, + 0, + }; + + const char **a, **b, **c, *m; + uint8_t seed[64]; + + a = vectors; + b = vectors + 1; + c = vectors + 2; + while (*a && *b && *c) { + m = mnemonic_from_data(fromhex(*a), strlen(*a) / 2); + ck_assert_str_eq(m, *b); + mnemonic_to_seed(m, "TREZOR", seed, 0); + ck_assert_mem_eq(seed, fromhex(*c), strlen(*c) / 2); #if USE_BIP39_CACHE - // try second time to check whether caching results work - mnemonic_to_seed(m, "TREZOR", seed, 0); - ck_assert_mem_eq(seed, fromhex(*c), strlen(*c) / 2); + // try second time to check whether caching results work + mnemonic_to_seed(m, "TREZOR", seed, 0); + ck_assert_mem_eq(seed, fromhex(*c), strlen(*c) / 2); #endif - a += 3; b += 3; c += 3; - } + a += 3; + b += 3; + c += 3; + } } END_TEST -START_TEST(test_mnemonic_check) -{ - static const char *vectors_ok[] = { - "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about", - "legal winner thank year wave sausage worth useful legal winner thank yellow", - "letter advice cage absurd amount doctor acoustic avoid letter advice cage above", - "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong", - "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon agent", - "legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal will", - "letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter always", - "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo when", - "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon art", - "legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth title", - "letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic bless", - "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo vote", - "jelly better achieve collect unaware mountain thought cargo oxygen act hood bridge", - "renew stay biology evidence goat welcome casual join adapt armor shuffle fault little machine walk stumble urge swap", - "dignity pass list indicate nasty swamp pool script soccer toe leaf photo multiply desk host tomato cradle drill spread actor shine dismiss champion exotic", - "afford alter spike radar gate glance object seek swamp infant panel yellow", - "indicate race push merry suffer human cruise dwarf pole review arch keep canvas theme poem divorce alter left", - "clutch control vehicle tonight unusual clog visa ice plunge glimpse recipe series open hour vintage deposit universe tip job dress radar refuse motion taste", - "turtle front uncle idea crush write shrug there lottery flower risk shell", - "kiss carry display unusual confirm curtain upgrade antique rotate hello void custom frequent obey nut hole price segment", - "exile ask congress lamp submit jacket era scheme attend cousin alcohol catch course end lucky hurt sentence oven short ball bird grab wing top", - "board flee heavy tunnel powder denial science ski answer betray cargo cat", - "board blade invite damage undo sun mimic interest slam gaze truly inherit resist great inject rocket museum chief", - "beyond stage sleep clip because twist token leaf atom beauty genius food business side grid unable middle armed observe pair crouch tonight away coconut", - 0, - }; - static const char *vectors_fail[] = { - "above abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about", - "above winner thank year wave sausage worth useful legal winner thank yellow", - "above advice cage absurd amount doctor acoustic avoid letter advice cage above", - "above zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong", - "above abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon agent", - "above winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal will", - "above advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter always", - "above zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo when", - "above abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon art", - "above winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth title", - "above advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic bless", - "above zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo vote", - "above better achieve collect unaware mountain thought cargo oxygen act hood bridge", - "above stay biology evidence goat welcome casual join adapt armor shuffle fault little machine walk stumble urge swap", - "above pass list indicate nasty swamp pool script soccer toe leaf photo multiply desk host tomato cradle drill spread actor shine dismiss champion exotic", - "above alter spike radar gate glance object seek swamp infant panel yellow", - "above race push merry suffer human cruise dwarf pole review arch keep canvas theme poem divorce alter left", - "above control vehicle tonight unusual clog visa ice plunge glimpse recipe series open hour vintage deposit universe tip job dress radar refuse motion taste", - "above front uncle idea crush write shrug there lottery flower risk shell", - "above carry display unusual confirm curtain upgrade antique rotate hello void custom frequent obey nut hole price segment", - "above ask congress lamp submit jacket era scheme attend cousin alcohol catch course end lucky hurt sentence oven short ball bird grab wing top", - "above flee heavy tunnel powder denial science ski answer betray cargo cat", - "above blade invite damage undo sun mimic interest slam gaze truly inherit resist great inject rocket museum chief", - "above stage sleep clip because twist token leaf atom beauty genius food business side grid unable middle armed observe pair crouch tonight away coconut", - "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about", - "winner thank year wave sausage worth useful legal winner thank yellow", - "advice cage absurd amount doctor acoustic avoid letter advice cage above", - "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong", - "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon agent", - "winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal will", - "advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter always", - "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo when", - "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon art", - "winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth title", - "advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic bless", - "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo vote", - "better achieve collect unaware mountain thought cargo oxygen act hood bridge", - "stay biology evidence goat welcome casual join adapt armor shuffle fault little machine walk stumble urge swap", - "pass list indicate nasty swamp pool script soccer toe leaf photo multiply desk host tomato cradle drill spread actor shine dismiss champion exotic", - "alter spike radar gate glance object seek swamp infant panel yellow", - "race push merry suffer human cruise dwarf pole review arch keep canvas theme poem divorce alter left", - "control vehicle tonight unusual clog visa ice plunge glimpse recipe series open hour vintage deposit universe tip job dress radar refuse motion taste", - "front uncle idea crush write shrug there lottery flower risk shell", - "carry display unusual confirm curtain upgrade antique rotate hello void custom frequent obey nut hole price segment", - "ask congress lamp submit jacket era scheme attend cousin alcohol catch course end lucky hurt sentence oven short ball bird grab wing top", - "flee heavy tunnel powder denial science ski answer betray cargo cat", - "blade invite damage undo sun mimic interest slam gaze truly inherit resist great inject rocket museum chief", - "stage sleep clip because twist token leaf atom beauty genius food business side grid unable middle armed observe pair crouch tonight away coconut", - 0, - }; - - const char **m; - int r; - m = vectors_ok; - while (*m) { - r = mnemonic_check(*m); - ck_assert_int_eq(r, 1); - m++; - } - m = vectors_fail; - while (*m) { - r = mnemonic_check(*m); - ck_assert_int_eq(r, 0); - m++; - } +START_TEST(test_mnemonic_check) { + static const char *vectors_ok[] = { + "abandon abandon abandon abandon abandon abandon abandon abandon abandon " + "abandon abandon about", + "legal winner thank year wave sausage worth useful legal winner thank " + "yellow", + "letter advice cage absurd amount doctor acoustic avoid letter advice " + "cage above", + "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong", + "abandon abandon abandon abandon abandon abandon abandon abandon abandon " + "abandon abandon abandon abandon abandon abandon abandon abandon agent", + "legal winner thank year wave sausage worth useful legal winner thank " + "year wave sausage worth useful legal will", + "letter advice cage absurd amount doctor acoustic avoid letter advice " + "cage absurd amount doctor acoustic avoid letter always", + "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo " + "when", + "abandon abandon abandon abandon abandon abandon abandon abandon abandon " + "abandon abandon abandon abandon abandon abandon abandon abandon abandon " + "abandon abandon abandon abandon abandon art", + "legal winner thank year wave sausage worth useful legal winner thank " + "year wave sausage worth useful legal winner thank year wave sausage " + "worth title", + "letter advice cage absurd amount doctor acoustic avoid letter advice " + "cage absurd amount doctor acoustic avoid letter advice cage absurd " + "amount doctor acoustic bless", + "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo " + "zoo zoo zoo zoo zoo vote", + "jelly better achieve collect unaware mountain thought cargo oxygen act " + "hood bridge", + "renew stay biology evidence goat welcome casual join adapt armor " + "shuffle fault little machine walk stumble urge swap", + "dignity pass list indicate nasty swamp pool script soccer toe leaf " + "photo multiply desk host tomato cradle drill spread actor shine dismiss " + "champion exotic", + "afford alter spike radar gate glance object seek swamp infant panel " + "yellow", + "indicate race push merry suffer human cruise dwarf pole review arch " + "keep canvas theme poem divorce alter left", + "clutch control vehicle tonight unusual clog visa ice plunge glimpse " + "recipe series open hour vintage deposit universe tip job dress radar " + "refuse motion taste", + "turtle front uncle idea crush write shrug there lottery flower risk " + "shell", + "kiss carry display unusual confirm curtain upgrade antique rotate hello " + "void custom frequent obey nut hole price segment", + "exile ask congress lamp submit jacket era scheme attend cousin alcohol " + "catch course end lucky hurt sentence oven short ball bird grab wing top", + "board flee heavy tunnel powder denial science ski answer betray cargo " + "cat", + "board blade invite damage undo sun mimic interest slam gaze truly " + "inherit resist great inject rocket museum chief", + "beyond stage sleep clip because twist token leaf atom beauty genius " + "food business side grid unable middle armed observe pair crouch tonight " + "away coconut", + 0, + }; + static const char *vectors_fail[] = { + "above abandon abandon abandon abandon abandon abandon abandon abandon " + "abandon abandon about", + "above winner thank year wave sausage worth useful legal winner thank " + "yellow", + "above advice cage absurd amount doctor acoustic avoid letter advice " + "cage above", + "above zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong", + "above abandon abandon abandon abandon abandon abandon abandon abandon " + "abandon abandon abandon abandon abandon abandon abandon abandon agent", + "above winner thank year wave sausage worth useful legal winner thank " + "year wave sausage worth useful legal will", + "above advice cage absurd amount doctor acoustic avoid letter advice " + "cage absurd amount doctor acoustic avoid letter always", + "above zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo " + "when", + "above abandon abandon abandon abandon abandon abandon abandon abandon " + "abandon abandon abandon abandon abandon abandon abandon abandon abandon " + "abandon abandon abandon abandon abandon art", + "above winner thank year wave sausage worth useful legal winner thank " + "year wave sausage worth useful legal winner thank year wave sausage " + "worth title", + "above advice cage absurd amount doctor acoustic avoid letter advice " + "cage absurd amount doctor acoustic avoid letter advice cage absurd " + "amount doctor acoustic bless", + "above zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo " + "zoo zoo zoo zoo zoo zoo vote", + "above better achieve collect unaware mountain thought cargo oxygen act " + "hood bridge", + "above stay biology evidence goat welcome casual join adapt armor " + "shuffle fault little machine walk stumble urge swap", + "above pass list indicate nasty swamp pool script soccer toe leaf photo " + "multiply desk host tomato cradle drill spread actor shine dismiss " + "champion exotic", + "above alter spike radar gate glance object seek swamp infant panel " + "yellow", + "above race push merry suffer human cruise dwarf pole review arch keep " + "canvas theme poem divorce alter left", + "above control vehicle tonight unusual clog visa ice plunge glimpse " + "recipe series open hour vintage deposit universe tip job dress radar " + "refuse motion taste", + "above front uncle idea crush write shrug there lottery flower risk " + "shell", + "above carry display unusual confirm curtain upgrade antique rotate " + "hello void custom frequent obey nut hole price segment", + "above ask congress lamp submit jacket era scheme attend cousin alcohol " + "catch course end lucky hurt sentence oven short ball bird grab wing top", + "above flee heavy tunnel powder denial science ski answer betray cargo " + "cat", + "above blade invite damage undo sun mimic interest slam gaze truly " + "inherit resist great inject rocket museum chief", + "above stage sleep clip because twist token leaf atom beauty genius food " + "business side grid unable middle armed observe pair crouch tonight away " + "coconut", + "abandon abandon abandon abandon abandon abandon abandon abandon abandon " + "abandon about", + "winner thank year wave sausage worth useful legal winner thank yellow", + "advice cage absurd amount doctor acoustic avoid letter advice cage " + "above", + "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong", + "abandon abandon abandon abandon abandon abandon abandon abandon abandon " + "abandon abandon abandon abandon abandon abandon abandon agent", + "winner thank year wave sausage worth useful legal winner thank year " + "wave sausage worth useful legal will", + "advice cage absurd amount doctor acoustic avoid letter advice cage " + "absurd amount doctor acoustic avoid letter always", + "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo when", + "abandon abandon abandon abandon abandon abandon abandon abandon abandon " + "abandon abandon abandon abandon abandon abandon abandon abandon abandon " + "abandon abandon abandon abandon art", + "winner thank year wave sausage worth useful legal winner thank year " + "wave sausage worth useful legal winner thank year wave sausage worth " + "title", + "advice cage absurd amount doctor acoustic avoid letter advice cage " + "absurd amount doctor acoustic avoid letter advice cage absurd amount " + "doctor acoustic bless", + "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo " + "zoo zoo zoo zoo vote", + "better achieve collect unaware mountain thought cargo oxygen act hood " + "bridge", + "stay biology evidence goat welcome casual join adapt armor shuffle " + "fault little machine walk stumble urge swap", + "pass list indicate nasty swamp pool script soccer toe leaf photo " + "multiply desk host tomato cradle drill spread actor shine dismiss " + "champion exotic", + "alter spike radar gate glance object seek swamp infant panel yellow", + "race push merry suffer human cruise dwarf pole review arch keep canvas " + "theme poem divorce alter left", + "control vehicle tonight unusual clog visa ice plunge glimpse recipe " + "series open hour vintage deposit universe tip job dress radar refuse " + "motion taste", + "front uncle idea crush write shrug there lottery flower risk shell", + "carry display unusual confirm curtain upgrade antique rotate hello void " + "custom frequent obey nut hole price segment", + "ask congress lamp submit jacket era scheme attend cousin alcohol catch " + "course end lucky hurt sentence oven short ball bird grab wing top", + "flee heavy tunnel powder denial science ski answer betray cargo cat", + "blade invite damage undo sun mimic interest slam gaze truly inherit " + "resist great inject rocket museum chief", + "stage sleep clip because twist token leaf atom beauty genius food " + "business side grid unable middle armed observe pair crouch tonight away " + "coconut", + 0, + }; + + const char **m; + int r; + m = vectors_ok; + while (*m) { + r = mnemonic_check(*m); + ck_assert_int_eq(r, 1); + m++; + } + m = vectors_fail; + while (*m) { + r = mnemonic_check(*m); + ck_assert_int_eq(r, 0); + m++; + } } END_TEST -START_TEST(test_mnemonic_to_entropy) -{ - static const char *vectors[] = { - "00000000000000000000000000000000", - "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about", - "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", - "legal winner thank year wave sausage worth useful legal winner thank yellow", - "80808080808080808080808080808080", - "letter advice cage absurd amount doctor acoustic avoid letter advice cage above", - "ffffffffffffffffffffffffffffffff", - "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong", - "000000000000000000000000000000000000000000000000", - "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon agent", - "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", - "legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal will", - "808080808080808080808080808080808080808080808080", - "letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter always", - "ffffffffffffffffffffffffffffffffffffffffffffffff", - "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo when", - "0000000000000000000000000000000000000000000000000000000000000000", - "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon art", - "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", - "legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth title", - "8080808080808080808080808080808080808080808080808080808080808080", - "letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic bless", - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo vote", - "77c2b00716cec7213839159e404db50d", - "jelly better achieve collect unaware mountain thought cargo oxygen act hood bridge", - "b63a9c59a6e641f288ebc103017f1da9f8290b3da6bdef7b", - "renew stay biology evidence goat welcome casual join adapt armor shuffle fault little machine walk stumble urge swap", - "3e141609b97933b66a060dcddc71fad1d91677db872031e85f4c015c5e7e8982", - "dignity pass list indicate nasty swamp pool script soccer toe leaf photo multiply desk host tomato cradle drill spread actor shine dismiss champion exotic", - "0460ef47585604c5660618db2e6a7e7f", - "afford alter spike radar gate glance object seek swamp infant panel yellow", - "72f60ebac5dd8add8d2a25a797102c3ce21bc029c200076f", - "indicate race push merry suffer human cruise dwarf pole review arch keep canvas theme poem divorce alter left", - "2c85efc7f24ee4573d2b81a6ec66cee209b2dcbd09d8eddc51e0215b0b68e416", - "clutch control vehicle tonight unusual clog visa ice plunge glimpse recipe series open hour vintage deposit universe tip job dress radar refuse motion taste", - "eaebabb2383351fd31d703840b32e9e2", - "turtle front uncle idea crush write shrug there lottery flower risk shell", - "7ac45cfe7722ee6c7ba84fbc2d5bd61b45cb2fe5eb65aa78", - "kiss carry display unusual confirm curtain upgrade antique rotate hello void custom frequent obey nut hole price segment", - "4fa1a8bc3e6d80ee1316050e862c1812031493212b7ec3f3bb1b08f168cabeef", - "exile ask congress lamp submit jacket era scheme attend cousin alcohol catch course end lucky hurt sentence oven short ball bird grab wing top", - "18ab19a9f54a9274f03e5209a2ac8a91", - "board flee heavy tunnel powder denial science ski answer betray cargo cat", - "18a2e1d81b8ecfb2a333adcb0c17a5b9eb76cc5d05db91a4", - "board blade invite damage undo sun mimic interest slam gaze truly inherit resist great inject rocket museum chief", - "15da872c95a13dd738fbf50e427583ad61f18fd99f628c417a61cf8343c90419", - "beyond stage sleep clip because twist token leaf atom beauty genius food business side grid unable middle armed observe pair crouch tonight away coconut", - 0, - 0, - }; - - const char **a, **b; - uint8_t entropy[64]; - - a = vectors; - b = vectors + 1; - while (*a && *b) { - int seed_len = mnemonic_to_entropy(*b, entropy); - ck_assert_int_eq(seed_len % 33, 0); - seed_len = seed_len * 4 / 33; - ck_assert_int_eq(seed_len, strlen(*a) / 2); - ck_assert_mem_eq(entropy, fromhex(*a), seed_len); - a += 2; b += 2; - } +START_TEST(test_mnemonic_to_entropy) { + static const char *vectors[] = { + "00000000000000000000000000000000", + "abandon abandon abandon abandon abandon abandon abandon abandon abandon " + "abandon abandon about", + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", + "legal winner thank year wave sausage worth useful legal winner thank " + "yellow", + "80808080808080808080808080808080", + "letter advice cage absurd amount doctor acoustic avoid letter advice " + "cage above", + "ffffffffffffffffffffffffffffffff", + "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong", + "000000000000000000000000000000000000000000000000", + "abandon abandon abandon abandon abandon abandon abandon abandon abandon " + "abandon abandon abandon abandon abandon abandon abandon abandon agent", + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", + "legal winner thank year wave sausage worth useful legal winner thank " + "year wave sausage worth useful legal will", + "808080808080808080808080808080808080808080808080", + "letter advice cage absurd amount doctor acoustic avoid letter advice " + "cage absurd amount doctor acoustic avoid letter always", + "ffffffffffffffffffffffffffffffffffffffffffffffff", + "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo " + "when", + "0000000000000000000000000000000000000000000000000000000000000000", + "abandon abandon abandon abandon abandon abandon abandon abandon abandon " + "abandon abandon abandon abandon abandon abandon abandon abandon abandon " + "abandon abandon abandon abandon abandon art", + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", + "legal winner thank year wave sausage worth useful legal winner thank " + "year wave sausage worth useful legal winner thank year wave sausage " + "worth title", + "8080808080808080808080808080808080808080808080808080808080808080", + "letter advice cage absurd amount doctor acoustic avoid letter advice " + "cage absurd amount doctor acoustic avoid letter advice cage absurd " + "amount doctor acoustic bless", + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo " + "zoo zoo zoo zoo zoo vote", + "77c2b00716cec7213839159e404db50d", + "jelly better achieve collect unaware mountain thought cargo oxygen act " + "hood bridge", + "b63a9c59a6e641f288ebc103017f1da9f8290b3da6bdef7b", + "renew stay biology evidence goat welcome casual join adapt armor " + "shuffle fault little machine walk stumble urge swap", + "3e141609b97933b66a060dcddc71fad1d91677db872031e85f4c015c5e7e8982", + "dignity pass list indicate nasty swamp pool script soccer toe leaf " + "photo multiply desk host tomato cradle drill spread actor shine dismiss " + "champion exotic", + "0460ef47585604c5660618db2e6a7e7f", + "afford alter spike radar gate glance object seek swamp infant panel " + "yellow", + "72f60ebac5dd8add8d2a25a797102c3ce21bc029c200076f", + "indicate race push merry suffer human cruise dwarf pole review arch " + "keep canvas theme poem divorce alter left", + "2c85efc7f24ee4573d2b81a6ec66cee209b2dcbd09d8eddc51e0215b0b68e416", + "clutch control vehicle tonight unusual clog visa ice plunge glimpse " + "recipe series open hour vintage deposit universe tip job dress radar " + "refuse motion taste", + "eaebabb2383351fd31d703840b32e9e2", + "turtle front uncle idea crush write shrug there lottery flower risk " + "shell", + "7ac45cfe7722ee6c7ba84fbc2d5bd61b45cb2fe5eb65aa78", + "kiss carry display unusual confirm curtain upgrade antique rotate hello " + "void custom frequent obey nut hole price segment", + "4fa1a8bc3e6d80ee1316050e862c1812031493212b7ec3f3bb1b08f168cabeef", + "exile ask congress lamp submit jacket era scheme attend cousin alcohol " + "catch course end lucky hurt sentence oven short ball bird grab wing top", + "18ab19a9f54a9274f03e5209a2ac8a91", + "board flee heavy tunnel powder denial science ski answer betray cargo " + "cat", + "18a2e1d81b8ecfb2a333adcb0c17a5b9eb76cc5d05db91a4", + "board blade invite damage undo sun mimic interest slam gaze truly " + "inherit resist great inject rocket museum chief", + "15da872c95a13dd738fbf50e427583ad61f18fd99f628c417a61cf8343c90419", + "beyond stage sleep clip because twist token leaf atom beauty genius " + "food business side grid unable middle armed observe pair crouch tonight " + "away coconut", + 0, + 0, + }; + + const char **a, **b; + uint8_t entropy[64]; + + a = vectors; + b = vectors + 1; + while (*a && *b) { + int seed_len = mnemonic_to_entropy(*b, entropy); + ck_assert_int_eq(seed_len % 33, 0); + seed_len = seed_len * 4 / 33; + ck_assert_int_eq(seed_len, strlen(*a) / 2); + ck_assert_mem_eq(entropy, fromhex(*a), seed_len); + a += 2; + b += 2; + } } END_TEST -START_TEST(test_address) -{ - char address[36]; - uint8_t pub_key[65]; - - memcpy(pub_key, fromhex("0226659c1cf7321c178c07437150639ff0c5b7679c7ea195253ed9abda2e081a37"), 33); - ecdsa_get_address(pub_key, 0, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "139MaMHp3Vjo8o4x8N1ZLWEtovLGvBsg6s"); - ecdsa_get_address(pub_key, 111, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "mhfJsQNnrXB3uuYZqvywARTDfuvyjg4RBh"); - ecdsa_get_address(pub_key, 52, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "MxiimznnxsqMfLKTQBL8Z2PoY9jKpjgkCu"); - ecdsa_get_address(pub_key, 48, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "LMNJqZbe89yrPbm7JVzrcXJf28hZ1rKPaH"); - ecdsa_get_address(pub_key, 36, HASHER_SHA2_RIPEMD, HASHER_GROESTLD_TRUNC, address, sizeof(address)); ck_assert_str_eq(address, "FXK52G2BbzRLaQ651U12o23DU5cEQdhvU6"); - ecdsa_get_address_segwit_p2sh(pub_key, 5, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "34PyTHn74syS796eTgsyoLfwoBC3cwLn6p"); - - memcpy(pub_key, fromhex("025b1654a0e78d28810094f6c5a96b8efb8a65668b578f170ac2b1f83bc63ba856"), 33); - ecdsa_get_address(pub_key, 0, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "19Ywfm3witp6C1yBMy4NRYHY2347WCRBfQ"); - ecdsa_get_address(pub_key, 111, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "mp4txp8vXvFLy8So5Y2kFTVrt2epN6YzdP"); - ecdsa_get_address(pub_key, 52, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "N58JsQYveGueiZDgdnNwe4SSkGTAToutAY"); - ecdsa_get_address(pub_key, 48, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "LTmtvyMmoZ49SpfLY73fhZMJEFRPdyohKh"); - ecdsa_get_address(pub_key, 36, HASHER_SHA2_RIPEMD, HASHER_GROESTLD_TRUNC, address, sizeof(address)); ck_assert_str_eq(address, "Fdif7fnKHPVddczJF53qt45rgCL51yWN6x"); - ecdsa_get_address_segwit_p2sh(pub_key, 5, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "35trq6eeuHf6VL9L8pQv46x3vegHnHoTuB"); - - memcpy(pub_key, fromhex("03433f246a12e6486a51ff08802228c61cf895175a9b49ed4766ea9a9294a3c7fe"), 33); - ecdsa_get_address(pub_key, 0, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "1FWE2bn3MWhc4QidcF6AvEWpK77sSi2cAP"); - ecdsa_get_address(pub_key, 111, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "mv2BKes2AY8rqXCFKp4Yk9j9B6iaMfWRLN"); - ecdsa_get_address(pub_key, 52, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "NB5bEFH2GtoAawy8t4Qk8kfj3LWvQs3MhB"); - ecdsa_get_address(pub_key, 48, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "LZjBHp5sSAwfKDQnnP5UCFaaXKV9YheGxQ"); - ecdsa_get_address(pub_key, 36, HASHER_SHA2_RIPEMD, HASHER_GROESTLD_TRUNC, address, sizeof(address)); ck_assert_str_eq(address, "FjfwUWWQv1P9W1jkVM5eNkK8yGPq5XyZZy"); - ecdsa_get_address_segwit_p2sh(pub_key, 5, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "3456DYaKUWuY6RWWw8Hp5CftHLcQN29h9Y"); - - memcpy(pub_key, fromhex("03aeb03abeee0f0f8b4f7a5d65ce31f9570cef9f72c2dd8a19b4085a30ab033d48"), 33); - ecdsa_get_address(pub_key, 0, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "1yrZb8dhdevoqpUEGi2tUccUEeiMKeLcs"); - ecdsa_get_address(pub_key, 111, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "mgVoreDcWf6BaxJ5wqgQiPpwLEFRLSr8U8"); - ecdsa_get_address(pub_key, 52, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "MwZDmEdcd1kVLP4yW62c6zmXCU3mNbveDo"); - ecdsa_get_address(pub_key, 48, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "LLCopoSTnHtz4eWdQQhLAVgNgT1zTi4QBK"); - ecdsa_get_address(pub_key, 36, HASHER_SHA2_RIPEMD, HASHER_GROESTLD_TRUNC, address, sizeof(address)); ck_assert_str_eq(address, "FW9a1Vs1G8LUFSqb7NhWLzQw8PvfwAxmxA"); - ecdsa_get_address_segwit_p2sh(pub_key, 5, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "3DBU4tJ9tkMR9fnmCtjW48kjvseoNLQZXd"); - - memcpy(pub_key, fromhex("0496e8f2093f018aff6c2e2da5201ee528e2c8accbf9cac51563d33a7bb74a016054201c025e2a5d96b1629b95194e806c63eb96facaedc733b1a4b70ab3b33e3a"), 65); - ecdsa_get_address(pub_key, 0, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "194SZbL75xCCGBbKtMsyWLE5r9s2V6mhVM"); - ecdsa_get_address(pub_key, 111, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "moaPreR5tydT3J4wbvrMLFSQi9TjPCiZc6"); - ecdsa_get_address(pub_key, 52, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "N4domEq61LHkniqqABCYirNzaPG5NRU8GH"); - ecdsa_get_address(pub_key, 48, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "LTHPpodwAcSFWzHV4VsGnMHr4NEJajMnKX"); - ecdsa_get_address(pub_key, 36, HASHER_SHA2_RIPEMD, HASHER_GROESTLD_TRUNC, address, sizeof(address)); ck_assert_str_eq(address, "FdEA1W4UeSsjhncSmTsSxr2QWK8z2xGkjc"); - - memcpy(pub_key, fromhex("0498010f8a687439ff497d3074beb4519754e72c4b6220fb669224749591dde416f3961f8ece18f8689bb32235e436874d2174048b86118a00afbd5a4f33a24f0f"), 65); - ecdsa_get_address(pub_key, 0, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "1A2WfBD4BJFwYHFPc5KgktqtbdJLBuVKc4"); - ecdsa_get_address(pub_key, 111, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "mpYTxEJ2zKhCKPj1KeJ4ap4DTcu39T3uzD"); - ecdsa_get_address(pub_key, 52, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "N5bsrpi36gMW4pVtsteFyQzoKrhPE7nkxK"); - ecdsa_get_address(pub_key, 48, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "LUFTvPWtFxVzo5wYnDJz2uueoqfcMYiuxH"); - ecdsa_get_address(pub_key, 36, HASHER_SHA2_RIPEMD, HASHER_GROESTLD_TRUNC, address, sizeof(address)); ck_assert_str_eq(address, "FeCE75wRjnwUytGWVBKADQeDFnaHpJ8t3B"); - - memcpy(pub_key, fromhex("04f80490839af36d13701ec3f9eebdac901b51c362119d74553a3c537faff31b17e2a59ebddbdac9e87b816307a7ed5b826b8f40b92719086238e1bebf19b77a4d"), 65); - ecdsa_get_address(pub_key, 0, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "19J81hrPnQxg9UGx45ibTieCkb2ttm8CLL"); - ecdsa_get_address(pub_key, 111, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "mop5JkwNbSPvvakZmegyHdrXcadbjLazww"); - ecdsa_get_address(pub_key, 52, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "N4sVDMMNho4Eg1XTKu3AgEo7UpRwq3aNbn"); - ecdsa_get_address(pub_key, 48, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "LTX5GvADs5CjQGy7EDhtjjhxxoQB2Uhicd"); - ecdsa_get_address(pub_key, 36, HASHER_SHA2_RIPEMD, HASHER_GROESTLD_TRUNC, address, sizeof(address)); ck_assert_str_eq(address, "FdTqTcamLueDb5J4wBi4vESXQkJrS54H6k"); +START_TEST(test_address) { + char address[36]; + uint8_t pub_key[65]; + + memcpy( + pub_key, + fromhex( + "0226659c1cf7321c178c07437150639ff0c5b7679c7ea195253ed9abda2e081a37"), + 33); + ecdsa_get_address(pub_key, 0, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, + sizeof(address)); + ck_assert_str_eq(address, "139MaMHp3Vjo8o4x8N1ZLWEtovLGvBsg6s"); + ecdsa_get_address(pub_key, 111, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, + sizeof(address)); + ck_assert_str_eq(address, "mhfJsQNnrXB3uuYZqvywARTDfuvyjg4RBh"); + ecdsa_get_address(pub_key, 52, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, + sizeof(address)); + ck_assert_str_eq(address, "MxiimznnxsqMfLKTQBL8Z2PoY9jKpjgkCu"); + ecdsa_get_address(pub_key, 48, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, + sizeof(address)); + ck_assert_str_eq(address, "LMNJqZbe89yrPbm7JVzrcXJf28hZ1rKPaH"); + ecdsa_get_address(pub_key, 36, HASHER_SHA2_RIPEMD, HASHER_GROESTLD_TRUNC, + address, sizeof(address)); + ck_assert_str_eq(address, "FXK52G2BbzRLaQ651U12o23DU5cEQdhvU6"); + ecdsa_get_address_segwit_p2sh(pub_key, 5, HASHER_SHA2_RIPEMD, HASHER_SHA2D, + address, sizeof(address)); + ck_assert_str_eq(address, "34PyTHn74syS796eTgsyoLfwoBC3cwLn6p"); + + memcpy( + pub_key, + fromhex( + "025b1654a0e78d28810094f6c5a96b8efb8a65668b578f170ac2b1f83bc63ba856"), + 33); + ecdsa_get_address(pub_key, 0, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, + sizeof(address)); + ck_assert_str_eq(address, "19Ywfm3witp6C1yBMy4NRYHY2347WCRBfQ"); + ecdsa_get_address(pub_key, 111, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, + sizeof(address)); + ck_assert_str_eq(address, "mp4txp8vXvFLy8So5Y2kFTVrt2epN6YzdP"); + ecdsa_get_address(pub_key, 52, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, + sizeof(address)); + ck_assert_str_eq(address, "N58JsQYveGueiZDgdnNwe4SSkGTAToutAY"); + ecdsa_get_address(pub_key, 48, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, + sizeof(address)); + ck_assert_str_eq(address, "LTmtvyMmoZ49SpfLY73fhZMJEFRPdyohKh"); + ecdsa_get_address(pub_key, 36, HASHER_SHA2_RIPEMD, HASHER_GROESTLD_TRUNC, + address, sizeof(address)); + ck_assert_str_eq(address, "Fdif7fnKHPVddczJF53qt45rgCL51yWN6x"); + ecdsa_get_address_segwit_p2sh(pub_key, 5, HASHER_SHA2_RIPEMD, HASHER_SHA2D, + address, sizeof(address)); + ck_assert_str_eq(address, "35trq6eeuHf6VL9L8pQv46x3vegHnHoTuB"); + + memcpy( + pub_key, + fromhex( + "03433f246a12e6486a51ff08802228c61cf895175a9b49ed4766ea9a9294a3c7fe"), + 33); + ecdsa_get_address(pub_key, 0, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, + sizeof(address)); + ck_assert_str_eq(address, "1FWE2bn3MWhc4QidcF6AvEWpK77sSi2cAP"); + ecdsa_get_address(pub_key, 111, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, + sizeof(address)); + ck_assert_str_eq(address, "mv2BKes2AY8rqXCFKp4Yk9j9B6iaMfWRLN"); + ecdsa_get_address(pub_key, 52, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, + sizeof(address)); + ck_assert_str_eq(address, "NB5bEFH2GtoAawy8t4Qk8kfj3LWvQs3MhB"); + ecdsa_get_address(pub_key, 48, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, + sizeof(address)); + ck_assert_str_eq(address, "LZjBHp5sSAwfKDQnnP5UCFaaXKV9YheGxQ"); + ecdsa_get_address(pub_key, 36, HASHER_SHA2_RIPEMD, HASHER_GROESTLD_TRUNC, + address, sizeof(address)); + ck_assert_str_eq(address, "FjfwUWWQv1P9W1jkVM5eNkK8yGPq5XyZZy"); + ecdsa_get_address_segwit_p2sh(pub_key, 5, HASHER_SHA2_RIPEMD, HASHER_SHA2D, + address, sizeof(address)); + ck_assert_str_eq(address, "3456DYaKUWuY6RWWw8Hp5CftHLcQN29h9Y"); + + memcpy( + pub_key, + fromhex( + "03aeb03abeee0f0f8b4f7a5d65ce31f9570cef9f72c2dd8a19b4085a30ab033d48"), + 33); + ecdsa_get_address(pub_key, 0, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, + sizeof(address)); + ck_assert_str_eq(address, "1yrZb8dhdevoqpUEGi2tUccUEeiMKeLcs"); + ecdsa_get_address(pub_key, 111, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, + sizeof(address)); + ck_assert_str_eq(address, "mgVoreDcWf6BaxJ5wqgQiPpwLEFRLSr8U8"); + ecdsa_get_address(pub_key, 52, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, + sizeof(address)); + ck_assert_str_eq(address, "MwZDmEdcd1kVLP4yW62c6zmXCU3mNbveDo"); + ecdsa_get_address(pub_key, 48, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, + sizeof(address)); + ck_assert_str_eq(address, "LLCopoSTnHtz4eWdQQhLAVgNgT1zTi4QBK"); + ecdsa_get_address(pub_key, 36, HASHER_SHA2_RIPEMD, HASHER_GROESTLD_TRUNC, + address, sizeof(address)); + ck_assert_str_eq(address, "FW9a1Vs1G8LUFSqb7NhWLzQw8PvfwAxmxA"); + ecdsa_get_address_segwit_p2sh(pub_key, 5, HASHER_SHA2_RIPEMD, HASHER_SHA2D, + address, sizeof(address)); + ck_assert_str_eq(address, "3DBU4tJ9tkMR9fnmCtjW48kjvseoNLQZXd"); + + memcpy( + pub_key, + fromhex( + "0496e8f2093f018aff6c2e2da5201ee528e2c8accbf9cac51563d33a7bb74a016054" + "201c025e2a5d96b1629b95194e806c63eb96facaedc733b1a4b70ab3b33e3a"), + 65); + ecdsa_get_address(pub_key, 0, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, + sizeof(address)); + ck_assert_str_eq(address, "194SZbL75xCCGBbKtMsyWLE5r9s2V6mhVM"); + ecdsa_get_address(pub_key, 111, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, + sizeof(address)); + ck_assert_str_eq(address, "moaPreR5tydT3J4wbvrMLFSQi9TjPCiZc6"); + ecdsa_get_address(pub_key, 52, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, + sizeof(address)); + ck_assert_str_eq(address, "N4domEq61LHkniqqABCYirNzaPG5NRU8GH"); + ecdsa_get_address(pub_key, 48, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, + sizeof(address)); + ck_assert_str_eq(address, "LTHPpodwAcSFWzHV4VsGnMHr4NEJajMnKX"); + ecdsa_get_address(pub_key, 36, HASHER_SHA2_RIPEMD, HASHER_GROESTLD_TRUNC, + address, sizeof(address)); + ck_assert_str_eq(address, "FdEA1W4UeSsjhncSmTsSxr2QWK8z2xGkjc"); + + memcpy( + pub_key, + fromhex( + "0498010f8a687439ff497d3074beb4519754e72c4b6220fb669224749591dde416f3" + "961f8ece18f8689bb32235e436874d2174048b86118a00afbd5a4f33a24f0f"), + 65); + ecdsa_get_address(pub_key, 0, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, + sizeof(address)); + ck_assert_str_eq(address, "1A2WfBD4BJFwYHFPc5KgktqtbdJLBuVKc4"); + ecdsa_get_address(pub_key, 111, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, + sizeof(address)); + ck_assert_str_eq(address, "mpYTxEJ2zKhCKPj1KeJ4ap4DTcu39T3uzD"); + ecdsa_get_address(pub_key, 52, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, + sizeof(address)); + ck_assert_str_eq(address, "N5bsrpi36gMW4pVtsteFyQzoKrhPE7nkxK"); + ecdsa_get_address(pub_key, 48, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, + sizeof(address)); + ck_assert_str_eq(address, "LUFTvPWtFxVzo5wYnDJz2uueoqfcMYiuxH"); + ecdsa_get_address(pub_key, 36, HASHER_SHA2_RIPEMD, HASHER_GROESTLD_TRUNC, + address, sizeof(address)); + ck_assert_str_eq(address, "FeCE75wRjnwUytGWVBKADQeDFnaHpJ8t3B"); + + memcpy( + pub_key, + fromhex( + "04f80490839af36d13701ec3f9eebdac901b51c362119d74553a3c537faff31b17e2" + "a59ebddbdac9e87b816307a7ed5b826b8f40b92719086238e1bebf19b77a4d"), + 65); + ecdsa_get_address(pub_key, 0, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, + sizeof(address)); + ck_assert_str_eq(address, "19J81hrPnQxg9UGx45ibTieCkb2ttm8CLL"); + ecdsa_get_address(pub_key, 111, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, + sizeof(address)); + ck_assert_str_eq(address, "mop5JkwNbSPvvakZmegyHdrXcadbjLazww"); + ecdsa_get_address(pub_key, 52, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, + sizeof(address)); + ck_assert_str_eq(address, "N4sVDMMNho4Eg1XTKu3AgEo7UpRwq3aNbn"); + ecdsa_get_address(pub_key, 48, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, + sizeof(address)); + ck_assert_str_eq(address, "LTX5GvADs5CjQGy7EDhtjjhxxoQB2Uhicd"); + ecdsa_get_address(pub_key, 36, HASHER_SHA2_RIPEMD, HASHER_GROESTLD_TRUNC, + address, sizeof(address)); + ck_assert_str_eq(address, "FdTqTcamLueDb5J4wBi4vESXQkJrS54H6k"); } END_TEST -START_TEST(test_pubkey_validity) -{ - uint8_t pub_key[65]; - curve_point pub; - int res; - const ecdsa_curve *curve = &secp256k1; - - memcpy(pub_key, fromhex("0226659c1cf7321c178c07437150639ff0c5b7679c7ea195253ed9abda2e081a37"), 33); - res = ecdsa_read_pubkey(curve, pub_key, &pub); - ck_assert_int_eq(res, 1); - - memcpy(pub_key, fromhex("025b1654a0e78d28810094f6c5a96b8efb8a65668b578f170ac2b1f83bc63ba856"), 33); - res = ecdsa_read_pubkey(curve, pub_key, &pub); - ck_assert_int_eq(res, 1); - - memcpy(pub_key, fromhex("03433f246a12e6486a51ff08802228c61cf895175a9b49ed4766ea9a9294a3c7fe"), 33); - res = ecdsa_read_pubkey(curve, pub_key, &pub); - ck_assert_int_eq(res, 1); - - memcpy(pub_key, fromhex("03aeb03abeee0f0f8b4f7a5d65ce31f9570cef9f72c2dd8a19b4085a30ab033d48"), 33); - res = ecdsa_read_pubkey(curve, pub_key, &pub); - ck_assert_int_eq(res, 1); - - memcpy(pub_key, fromhex("0496e8f2093f018aff6c2e2da5201ee528e2c8accbf9cac51563d33a7bb74a016054201c025e2a5d96b1629b95194e806c63eb96facaedc733b1a4b70ab3b33e3a"), 65); - res = ecdsa_read_pubkey(curve, pub_key, &pub); - ck_assert_int_eq(res, 1); - - memcpy(pub_key, fromhex("0498010f8a687439ff497d3074beb4519754e72c4b6220fb669224749591dde416f3961f8ece18f8689bb32235e436874d2174048b86118a00afbd5a4f33a24f0f"), 65); - res = ecdsa_read_pubkey(curve, pub_key, &pub); - ck_assert_int_eq(res, 1); - - memcpy(pub_key, fromhex("04f80490839af36d13701ec3f9eebdac901b51c362119d74553a3c537faff31b17e2a59ebddbdac9e87b816307a7ed5b826b8f40b92719086238e1bebf19b77a4d"), 65); - res = ecdsa_read_pubkey(curve, pub_key, &pub); - ck_assert_int_eq(res, 1); - - memcpy(pub_key, fromhex("04f80490839af36d13701ec3f9eebdac901b51c362119d74553a3c537faff31b17e2a59ebddbdac9e87b816307a7ed5b826b8f40b92719086238e1bebf00000000"), 65); - res = ecdsa_read_pubkey(curve, pub_key, &pub); - ck_assert_int_eq(res, 0); - - memcpy(pub_key, fromhex("04f80490839af36d13701ec3f9eebdac901b51c362119d74553a3c537faff31b17e2a59ebddbdac9e87b816307a7ed5b8211111111111111111111111111111111"), 65); - res = ecdsa_read_pubkey(curve, pub_key, &pub); - ck_assert_int_eq(res, 0); - - memcpy(pub_key, fromhex("00"), 1); - res = ecdsa_read_pubkey(curve, pub_key, &pub); - ck_assert_int_eq(res, 0); +START_TEST(test_pubkey_validity) { + uint8_t pub_key[65]; + curve_point pub; + int res; + const ecdsa_curve *curve = &secp256k1; + + memcpy( + pub_key, + fromhex( + "0226659c1cf7321c178c07437150639ff0c5b7679c7ea195253ed9abda2e081a37"), + 33); + res = ecdsa_read_pubkey(curve, pub_key, &pub); + ck_assert_int_eq(res, 1); + + memcpy( + pub_key, + fromhex( + "025b1654a0e78d28810094f6c5a96b8efb8a65668b578f170ac2b1f83bc63ba856"), + 33); + res = ecdsa_read_pubkey(curve, pub_key, &pub); + ck_assert_int_eq(res, 1); + + memcpy( + pub_key, + fromhex( + "03433f246a12e6486a51ff08802228c61cf895175a9b49ed4766ea9a9294a3c7fe"), + 33); + res = ecdsa_read_pubkey(curve, pub_key, &pub); + ck_assert_int_eq(res, 1); + + memcpy( + pub_key, + fromhex( + "03aeb03abeee0f0f8b4f7a5d65ce31f9570cef9f72c2dd8a19b4085a30ab033d48"), + 33); + res = ecdsa_read_pubkey(curve, pub_key, &pub); + ck_assert_int_eq(res, 1); + + memcpy( + pub_key, + fromhex( + "0496e8f2093f018aff6c2e2da5201ee528e2c8accbf9cac51563d33a7bb74a016054" + "201c025e2a5d96b1629b95194e806c63eb96facaedc733b1a4b70ab3b33e3a"), + 65); + res = ecdsa_read_pubkey(curve, pub_key, &pub); + ck_assert_int_eq(res, 1); + + memcpy( + pub_key, + fromhex( + "0498010f8a687439ff497d3074beb4519754e72c4b6220fb669224749591dde416f3" + "961f8ece18f8689bb32235e436874d2174048b86118a00afbd5a4f33a24f0f"), + 65); + res = ecdsa_read_pubkey(curve, pub_key, &pub); + ck_assert_int_eq(res, 1); + + memcpy( + pub_key, + fromhex( + "04f80490839af36d13701ec3f9eebdac901b51c362119d74553a3c537faff31b17e2" + "a59ebddbdac9e87b816307a7ed5b826b8f40b92719086238e1bebf19b77a4d"), + 65); + res = ecdsa_read_pubkey(curve, pub_key, &pub); + ck_assert_int_eq(res, 1); + + memcpy( + pub_key, + fromhex( + "04f80490839af36d13701ec3f9eebdac901b51c362119d74553a3c537faff31b17e2" + "a59ebddbdac9e87b816307a7ed5b826b8f40b92719086238e1bebf00000000"), + 65); + res = ecdsa_read_pubkey(curve, pub_key, &pub); + ck_assert_int_eq(res, 0); + + memcpy( + pub_key, + fromhex( + "04f80490839af36d13701ec3f9eebdac901b51c362119d74553a3c537faff31b17e2" + "a59ebddbdac9e87b816307a7ed5b8211111111111111111111111111111111"), + 65); + res = ecdsa_read_pubkey(curve, pub_key, &pub); + ck_assert_int_eq(res, 0); + + memcpy(pub_key, fromhex("00"), 1); + res = ecdsa_read_pubkey(curve, pub_key, &pub); + ck_assert_int_eq(res, 0); } END_TEST -START_TEST(test_pubkey_uncompress) -{ - uint8_t pub_key[65]; - uint8_t uncompressed[65]; - int res; - const ecdsa_curve *curve = &secp256k1; - - memcpy(pub_key, fromhex("0226659c1cf7321c178c07437150639ff0c5b7679c7ea195253ed9abda2e081a37"), 33); - res = ecdsa_uncompress_pubkey(curve, pub_key, uncompressed); - ck_assert_int_eq(res, 1); - ck_assert_mem_eq(uncompressed, fromhex("0426659c1cf7321c178c07437150639ff0c5b7679c7ea195253ed9abda2e081a37b3cfbad6b39a8ce8cb3a675f53b7b57e120fe067b8035d771fd99e3eba7cf4de"), 65); - - memcpy(pub_key, fromhex("03433f246a12e6486a51ff08802228c61cf895175a9b49ed4766ea9a9294a3c7fe"), 33); - res = ecdsa_uncompress_pubkey(curve, pub_key, uncompressed); - ck_assert_int_eq(res, 1); - ck_assert_mem_eq(uncompressed, fromhex("04433f246a12e6486a51ff08802228c61cf895175a9b49ed4766ea9a9294a3c7feeb4c25bcb840f720a16e8857a011e6b91e0ab2d03dbb5f9762844bb21a7b8ca7"), 65); - - memcpy(pub_key, fromhex("0496e8f2093f018aff6c2e2da5201ee528e2c8accbf9cac51563d33a7bb74a016054201c025e2a5d96b1629b95194e806c63eb96facaedc733b1a4b70ab3b33e3a"), 65); - res = ecdsa_uncompress_pubkey(curve, pub_key, uncompressed); - ck_assert_int_eq(res, 1); - ck_assert_mem_eq(uncompressed, fromhex("0496e8f2093f018aff6c2e2da5201ee528e2c8accbf9cac51563d33a7bb74a016054201c025e2a5d96b1629b95194e806c63eb96facaedc733b1a4b70ab3b33e3a"), 65); - - memcpy(pub_key, fromhex("00"), 1); - res = ecdsa_uncompress_pubkey(curve, pub_key, uncompressed); - ck_assert_int_eq(res, 0); +START_TEST(test_pubkey_uncompress) { + uint8_t pub_key[65]; + uint8_t uncompressed[65]; + int res; + const ecdsa_curve *curve = &secp256k1; + + memcpy( + pub_key, + fromhex( + "0226659c1cf7321c178c07437150639ff0c5b7679c7ea195253ed9abda2e081a37"), + 33); + res = ecdsa_uncompress_pubkey(curve, pub_key, uncompressed); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq( + uncompressed, + fromhex( + "0426659c1cf7321c178c07437150639ff0c5b7679c7ea195253ed9abda2e081a37b3" + "cfbad6b39a8ce8cb3a675f53b7b57e120fe067b8035d771fd99e3eba7cf4de"), + 65); + + memcpy( + pub_key, + fromhex( + "03433f246a12e6486a51ff08802228c61cf895175a9b49ed4766ea9a9294a3c7fe"), + 33); + res = ecdsa_uncompress_pubkey(curve, pub_key, uncompressed); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq( + uncompressed, + fromhex( + "04433f246a12e6486a51ff08802228c61cf895175a9b49ed4766ea9a9294a3c7feeb" + "4c25bcb840f720a16e8857a011e6b91e0ab2d03dbb5f9762844bb21a7b8ca7"), + 65); + + memcpy( + pub_key, + fromhex( + "0496e8f2093f018aff6c2e2da5201ee528e2c8accbf9cac51563d33a7bb74a016054" + "201c025e2a5d96b1629b95194e806c63eb96facaedc733b1a4b70ab3b33e3a"), + 65); + res = ecdsa_uncompress_pubkey(curve, pub_key, uncompressed); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq( + uncompressed, + fromhex( + "0496e8f2093f018aff6c2e2da5201ee528e2c8accbf9cac51563d33a7bb74a016054" + "201c025e2a5d96b1629b95194e806c63eb96facaedc733b1a4b70ab3b33e3a"), + 65); + + memcpy(pub_key, fromhex("00"), 1); + res = ecdsa_uncompress_pubkey(curve, pub_key, uncompressed); + ck_assert_int_eq(res, 0); } END_TEST -START_TEST(test_wif) -{ - uint8_t priv_key[32]; - char wif[53]; - - memcpy(priv_key, fromhex("1111111111111111111111111111111111111111111111111111111111111111"), 32); - ecdsa_get_wif(priv_key, 0x80, HASHER_SHA2D, wif, sizeof(wif)); ck_assert_str_eq(wif, "KwntMbt59tTsj8xqpqYqRRWufyjGunvhSyeMo3NTYpFYzZbXJ5Hp"); - ecdsa_get_wif(priv_key, 0xEF, HASHER_SHA2D, wif, sizeof(wif)); ck_assert_str_eq(wif, "cN9spWsvaxA8taS7DFMxnk1yJD2gaF2PX1npuTpy3vuZFJdwavaw"); - - memcpy(priv_key, fromhex("dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"), 32); - ecdsa_get_wif(priv_key, 0x80, HASHER_SHA2D, wif, sizeof(wif)); ck_assert_str_eq(wif, "L4ezQvyC6QoBhxB4GVs9fAPhUKtbaXYUn8YTqoeXwbevQq4U92vN"); - ecdsa_get_wif(priv_key, 0xEF, HASHER_SHA2D, wif, sizeof(wif)); ck_assert_str_eq(wif, "cV1ysqy3XUVSsPeKeugH2Utm6ZC1EyeArAgvxE73SiJvfa6AJng7"); - - memcpy(priv_key, fromhex("47f7616ea6f9b923076625b4488115de1ef1187f760e65f89eb6f4f7ff04b012"), 32); - ecdsa_get_wif(priv_key, 0x80, HASHER_SHA2D, wif, sizeof(wif)); ck_assert_str_eq(wif, "KydbzBtk6uc7M6dXwEgTEH2sphZxSPbmDSz6kUUHi4eUpSQuhEbq"); - ecdsa_get_wif(priv_key, 0xEF, HASHER_SHA2D, wif, sizeof(wif)); ck_assert_str_eq(wif, "cPzbT6tbXyJNWY6oKeVabbXwSvsN6qhTHV8ZrtvoDBJV5BRY1G5Q"); +START_TEST(test_wif) { + uint8_t priv_key[32]; + char wif[53]; + + memcpy( + priv_key, + fromhex( + "1111111111111111111111111111111111111111111111111111111111111111"), + 32); + ecdsa_get_wif(priv_key, 0x80, HASHER_SHA2D, wif, sizeof(wif)); + ck_assert_str_eq(wif, "KwntMbt59tTsj8xqpqYqRRWufyjGunvhSyeMo3NTYpFYzZbXJ5Hp"); + ecdsa_get_wif(priv_key, 0xEF, HASHER_SHA2D, wif, sizeof(wif)); + ck_assert_str_eq(wif, "cN9spWsvaxA8taS7DFMxnk1yJD2gaF2PX1npuTpy3vuZFJdwavaw"); + + memcpy( + priv_key, + fromhex( + "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"), + 32); + ecdsa_get_wif(priv_key, 0x80, HASHER_SHA2D, wif, sizeof(wif)); + ck_assert_str_eq(wif, "L4ezQvyC6QoBhxB4GVs9fAPhUKtbaXYUn8YTqoeXwbevQq4U92vN"); + ecdsa_get_wif(priv_key, 0xEF, HASHER_SHA2D, wif, sizeof(wif)); + ck_assert_str_eq(wif, "cV1ysqy3XUVSsPeKeugH2Utm6ZC1EyeArAgvxE73SiJvfa6AJng7"); + + memcpy( + priv_key, + fromhex( + "47f7616ea6f9b923076625b4488115de1ef1187f760e65f89eb6f4f7ff04b012"), + 32); + ecdsa_get_wif(priv_key, 0x80, HASHER_SHA2D, wif, sizeof(wif)); + ck_assert_str_eq(wif, "KydbzBtk6uc7M6dXwEgTEH2sphZxSPbmDSz6kUUHi4eUpSQuhEbq"); + ecdsa_get_wif(priv_key, 0xEF, HASHER_SHA2D, wif, sizeof(wif)); + ck_assert_str_eq(wif, "cPzbT6tbXyJNWY6oKeVabbXwSvsN6qhTHV8ZrtvoDBJV5BRY1G5Q"); } END_TEST -START_TEST(test_address_decode) -{ - int res; - uint8_t decode[MAX_ADDR_RAW_SIZE]; - - res = ecdsa_address_decode("1JwSSubhmg6iPtRjtyqhUYYH7bZg3Lfy1T", 0, HASHER_SHA2D, decode); - ck_assert_int_eq(res, 1); - ck_assert_mem_eq(decode, fromhex("00c4c5d791fcb4654a1ef5e03fe0ad3d9c598f9827"), 21); - - res = ecdsa_address_decode("myTPjxggahXyAzuMcYp5JTkbybANyLsYBW", 111, HASHER_SHA2D, decode); - ck_assert_int_eq(res, 1); - ck_assert_mem_eq(decode, fromhex("6fc4c5d791fcb4654a1ef5e03fe0ad3d9c598f9827"), 21); - - res = ecdsa_address_decode("NEWoeZ6gh4CGvRgFAoAGh4hBqpxizGT6gZ", 52, HASHER_SHA2D, decode); - ck_assert_int_eq(res, 1); - ck_assert_mem_eq(decode, fromhex("34c4c5d791fcb4654a1ef5e03fe0ad3d9c598f9827"), 21); - - res = ecdsa_address_decode("LdAPi7uXrLLmeh7u57pzkZc3KovxEDYRJq", 48, HASHER_SHA2D, decode); - ck_assert_int_eq(res, 1); - ck_assert_mem_eq(decode, fromhex("30c4c5d791fcb4654a1ef5e03fe0ad3d9c598f9827"), 21); - - res = ecdsa_address_decode("1C7zdTfnkzmr13HfA2vNm5SJYRK6nEKyq8", 0, HASHER_SHA2D, decode); - ck_assert_int_eq(res, 1); - ck_assert_mem_eq(decode, fromhex("0079fbfc3f34e7745860d76137da68f362380c606c"), 21); - - res = ecdsa_address_decode("mrdwvWkma2D6n9mGsbtkazedQQuoksnqJV", 111, HASHER_SHA2D, decode); - ck_assert_int_eq(res, 1); - ck_assert_mem_eq(decode, fromhex("6f79fbfc3f34e7745860d76137da68f362380c606c"), 21); - - res = ecdsa_address_decode("N7hMq7AmgNsQXaYARrEwybbDGei9mcPNqr", 52, HASHER_SHA2D, decode); - ck_assert_int_eq(res, 1); - ck_assert_mem_eq(decode, fromhex("3479fbfc3f34e7745860d76137da68f362380c606c"), 21); - - res = ecdsa_address_decode("LWLwtfycqf1uFqypLAug36W4kdgNwrZdNs", 48, HASHER_SHA2D, decode); - ck_assert_int_eq(res, 1); - ck_assert_mem_eq(decode, fromhex("3079fbfc3f34e7745860d76137da68f362380c606c"), 21); - - // invalid char - res = ecdsa_address_decode("1JwSSubhmg6i000jtyqhUYYH7bZg3Lfy1T", 0, HASHER_SHA2D, decode); - ck_assert_int_eq(res, 0); - - // invalid address - res = ecdsa_address_decode("1111Subhmg6iPtRjtyqhUYYH7bZg3Lfy1T", 0, HASHER_SHA2D, decode); - ck_assert_int_eq(res, 0); - - // invalid version - res = ecdsa_address_decode("LWLwtfycqf1uFqypLAug36W4kdgNwrZdNs", 0, HASHER_SHA2D, decode); - ck_assert_int_eq(res, 0); +START_TEST(test_address_decode) { + int res; + uint8_t decode[MAX_ADDR_RAW_SIZE]; + + res = ecdsa_address_decode("1JwSSubhmg6iPtRjtyqhUYYH7bZg3Lfy1T", 0, + HASHER_SHA2D, decode); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(decode, + fromhex("00c4c5d791fcb4654a1ef5e03fe0ad3d9c598f9827"), 21); + + res = ecdsa_address_decode("myTPjxggahXyAzuMcYp5JTkbybANyLsYBW", 111, + HASHER_SHA2D, decode); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(decode, + fromhex("6fc4c5d791fcb4654a1ef5e03fe0ad3d9c598f9827"), 21); + + res = ecdsa_address_decode("NEWoeZ6gh4CGvRgFAoAGh4hBqpxizGT6gZ", 52, + HASHER_SHA2D, decode); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(decode, + fromhex("34c4c5d791fcb4654a1ef5e03fe0ad3d9c598f9827"), 21); + + res = ecdsa_address_decode("LdAPi7uXrLLmeh7u57pzkZc3KovxEDYRJq", 48, + HASHER_SHA2D, decode); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(decode, + fromhex("30c4c5d791fcb4654a1ef5e03fe0ad3d9c598f9827"), 21); + + res = ecdsa_address_decode("1C7zdTfnkzmr13HfA2vNm5SJYRK6nEKyq8", 0, + HASHER_SHA2D, decode); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(decode, + fromhex("0079fbfc3f34e7745860d76137da68f362380c606c"), 21); + + res = ecdsa_address_decode("mrdwvWkma2D6n9mGsbtkazedQQuoksnqJV", 111, + HASHER_SHA2D, decode); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(decode, + fromhex("6f79fbfc3f34e7745860d76137da68f362380c606c"), 21); + + res = ecdsa_address_decode("N7hMq7AmgNsQXaYARrEwybbDGei9mcPNqr", 52, + HASHER_SHA2D, decode); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(decode, + fromhex("3479fbfc3f34e7745860d76137da68f362380c606c"), 21); + + res = ecdsa_address_decode("LWLwtfycqf1uFqypLAug36W4kdgNwrZdNs", 48, + HASHER_SHA2D, decode); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(decode, + fromhex("3079fbfc3f34e7745860d76137da68f362380c606c"), 21); + + // invalid char + res = ecdsa_address_decode("1JwSSubhmg6i000jtyqhUYYH7bZg3Lfy1T", 0, + HASHER_SHA2D, decode); + ck_assert_int_eq(res, 0); + + // invalid address + res = ecdsa_address_decode("1111Subhmg6iPtRjtyqhUYYH7bZg3Lfy1T", 0, + HASHER_SHA2D, decode); + ck_assert_int_eq(res, 0); + + // invalid version + res = ecdsa_address_decode("LWLwtfycqf1uFqypLAug36W4kdgNwrZdNs", 0, + HASHER_SHA2D, decode); + ck_assert_int_eq(res, 0); } END_TEST -START_TEST(test_ecdsa_der) -{ - uint8_t sig[64], der[72]; - int res; - - memcpy(sig, fromhex("9a0b7be0d4ed3146ee262b42202841834698bb3ee39c24e7437df208b8b70771"), 32); - memcpy(sig + 32, fromhex("2b79ab1e7736219387dffe8d615bbdba87e11477104b867ef47afed1a5ede781"), 32); - res = ecdsa_sig_to_der(sig, der); - ck_assert_int_eq(res, 71); - ck_assert_mem_eq(der, fromhex("30450221009a0b7be0d4ed3146ee262b42202841834698bb3ee39c24e7437df208b8b7077102202b79ab1e7736219387dffe8d615bbdba87e11477104b867ef47afed1a5ede781"), 71); - - memcpy(sig, fromhex("6666666666666666666666666666666666666666666666666666666666666666"), 32); - memcpy(sig + 32, fromhex("7777777777777777777777777777777777777777777777777777777777777777"), 32); - res = ecdsa_sig_to_der(sig, der); - ck_assert_int_eq(res, 70); - ck_assert_mem_eq(der, fromhex("30440220666666666666666666666666666666666666666666666666666666666666666602207777777777777777777777777777777777777777777777777777777777777777"), 70); - - memcpy(sig, fromhex("6666666666666666666666666666666666666666666666666666666666666666"), 32); - memcpy(sig + 32, fromhex("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"), 32); - res = ecdsa_sig_to_der(sig, der); - ck_assert_int_eq(res, 71); - ck_assert_mem_eq(der, fromhex("304502206666666666666666666666666666666666666666666666666666666666666666022100eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"), 71); - - memcpy(sig, fromhex("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"), 32); - memcpy(sig + 32, fromhex("7777777777777777777777777777777777777777777777777777777777777777"), 32); - res = ecdsa_sig_to_der(sig, der); - ck_assert_int_eq(res, 71); - ck_assert_mem_eq(der, fromhex("3045022100eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee02207777777777777777777777777777777777777777777777777777777777777777"), 71); - - memcpy(sig, fromhex("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"), 32); - memcpy(sig + 32, fromhex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), 32); - res = ecdsa_sig_to_der(sig, der); - ck_assert_int_eq(res, 72); - ck_assert_mem_eq(der, fromhex("3046022100eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee022100ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), 72); - - memcpy(sig, fromhex("0000000000000000000000000000000000000000000000000000000000000066"), 32); - memcpy(sig + 32, fromhex("0000000000000000000000000000000000000000000000000000000000000077"), 32); - res = ecdsa_sig_to_der(sig, der); - ck_assert_int_eq(res, 8); - ck_assert_mem_eq(der, fromhex("3006020166020177"), 8); - - memcpy(sig, fromhex("0000000000000000000000000000000000000000000000000000000000000066"), 32); - memcpy(sig + 32, fromhex("00000000000000000000000000000000000000000000000000000000000000ee"), 32); - res = ecdsa_sig_to_der(sig, der); - ck_assert_int_eq(res, 9); - ck_assert_mem_eq(der, fromhex("3007020166020200ee"), 9); - - memcpy(sig, fromhex("00000000000000000000000000000000000000000000000000000000000000ee"), 32); - memcpy(sig + 32, fromhex("0000000000000000000000000000000000000000000000000000000000000077"), 32); - res = ecdsa_sig_to_der(sig, der); - ck_assert_int_eq(res, 9); - ck_assert_mem_eq(der, fromhex("3007020200ee020177"), 9); - - memcpy(sig, fromhex("00000000000000000000000000000000000000000000000000000000000000ee"), 32); - memcpy(sig + 32, fromhex("00000000000000000000000000000000000000000000000000000000000000ff"), 32); - res = ecdsa_sig_to_der(sig, der); - ck_assert_int_eq(res, 10); - ck_assert_mem_eq(der, fromhex("3008020200ee020200ff"), 10); +START_TEST(test_ecdsa_der) { + uint8_t sig[64], der[72]; + int res; + + memcpy( + sig, + fromhex( + "9a0b7be0d4ed3146ee262b42202841834698bb3ee39c24e7437df208b8b70771"), + 32); + memcpy( + sig + 32, + fromhex( + "2b79ab1e7736219387dffe8d615bbdba87e11477104b867ef47afed1a5ede781"), + 32); + res = ecdsa_sig_to_der(sig, der); + ck_assert_int_eq(res, 71); + ck_assert_mem_eq(der, + fromhex("30450221009a0b7be0d4ed3146ee262b42202841834698bb3ee" + "39c24e7437df208b8b7077102202b79ab1e7736219387dffe8d" + "615bbdba87e11477104b867ef47afed1a5ede781"), + 71); + + memcpy( + sig, + fromhex( + "6666666666666666666666666666666666666666666666666666666666666666"), + 32); + memcpy( + sig + 32, + fromhex( + "7777777777777777777777777777777777777777777777777777777777777777"), + 32); + res = ecdsa_sig_to_der(sig, der); + ck_assert_int_eq(res, 70); + ck_assert_mem_eq(der, + fromhex("304402206666666666666666666666666666666666666666666" + "666666666666666666666022077777777777777777777777777" + "77777777777777777777777777777777777777"), + 70); + + memcpy( + sig, + fromhex( + "6666666666666666666666666666666666666666666666666666666666666666"), + 32); + memcpy( + sig + 32, + fromhex( + "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"), + 32); + res = ecdsa_sig_to_der(sig, der); + ck_assert_int_eq(res, 71); + ck_assert_mem_eq(der, + fromhex("304502206666666666666666666666666666666666666666666" + "666666666666666666666022100eeeeeeeeeeeeeeeeeeeeeeee" + "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"), + 71); + + memcpy( + sig, + fromhex( + "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"), + 32); + memcpy( + sig + 32, + fromhex( + "7777777777777777777777777777777777777777777777777777777777777777"), + 32); + res = ecdsa_sig_to_der(sig, der); + ck_assert_int_eq(res, 71); + ck_assert_mem_eq(der, + fromhex("3045022100eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + "eeeeeeeeeeeeeeeeeeeeeee0220777777777777777777777777" + "7777777777777777777777777777777777777777"), + 71); + + memcpy( + sig, + fromhex( + "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"), + 32); + memcpy( + sig + 32, + fromhex( + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), + 32); + res = ecdsa_sig_to_der(sig, der); + ck_assert_int_eq(res, 72); + ck_assert_mem_eq(der, + fromhex("3046022100eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + "eeeeeeeeeeeeeeeeeeeeeee022100ffffffffffffffffffffff" + "ffffffffffffffffffffffffffffffffffffffffff"), + 72); + + memcpy( + sig, + fromhex( + "0000000000000000000000000000000000000000000000000000000000000066"), + 32); + memcpy( + sig + 32, + fromhex( + "0000000000000000000000000000000000000000000000000000000000000077"), + 32); + res = ecdsa_sig_to_der(sig, der); + ck_assert_int_eq(res, 8); + ck_assert_mem_eq(der, fromhex("3006020166020177"), 8); + + memcpy( + sig, + fromhex( + "0000000000000000000000000000000000000000000000000000000000000066"), + 32); + memcpy( + sig + 32, + fromhex( + "00000000000000000000000000000000000000000000000000000000000000ee"), + 32); + res = ecdsa_sig_to_der(sig, der); + ck_assert_int_eq(res, 9); + ck_assert_mem_eq(der, fromhex("3007020166020200ee"), 9); + + memcpy( + sig, + fromhex( + "00000000000000000000000000000000000000000000000000000000000000ee"), + 32); + memcpy( + sig + 32, + fromhex( + "0000000000000000000000000000000000000000000000000000000000000077"), + 32); + res = ecdsa_sig_to_der(sig, der); + ck_assert_int_eq(res, 9); + ck_assert_mem_eq(der, fromhex("3007020200ee020177"), 9); + + memcpy( + sig, + fromhex( + "00000000000000000000000000000000000000000000000000000000000000ee"), + 32); + memcpy( + sig + 32, + fromhex( + "00000000000000000000000000000000000000000000000000000000000000ff"), + 32); + res = ecdsa_sig_to_der(sig, der); + ck_assert_int_eq(res, 10); + ck_assert_mem_eq(der, fromhex("3008020200ee020200ff"), 10); } END_TEST static void test_codepoints_curve(const ecdsa_curve *curve) { - int i, j; - bignum256 a; - curve_point p, p1; - for (i = 0; i < 64; i++) { - for (j = 0; j < 8; j++) { - bn_zero(&a); - a.val[(4*i)/30] = (uint32_t) (2*j+1) << (4*i % 30); - bn_normalize(&a); - // note that this is not a trivial test. We add 64 curve - // points in the table to get that particular curve point. - scalar_multiply(curve, &a, &p); - ck_assert_mem_eq(&p, &curve->cp[i][j], sizeof(curve_point)); - bn_zero(&p.y); // test that point_multiply curve, is not a noop - point_multiply(curve, &a, &curve->G, &p); - ck_assert_mem_eq(&p, &curve->cp[i][j], sizeof(curve_point)); - // mul 2 test. this should catch bugs - bn_lshift(&a); - bn_mod(&a, &curve->order); - p1 = curve->cp[i][j]; - point_double(curve, &p1); - // note that this is not a trivial test. We add 64 curve - // points in the table to get that particular curve point. - scalar_multiply(curve, &a, &p); - ck_assert_mem_eq(&p, &p1, sizeof(curve_point)); - bn_zero(&p.y); // test that point_multiply curve, is not a noop - point_multiply(curve, &a, &curve->G, &p); - ck_assert_mem_eq(&p, &p1, sizeof(curve_point)); - } - } + int i, j; + bignum256 a; + curve_point p, p1; + for (i = 0; i < 64; i++) { + for (j = 0; j < 8; j++) { + bn_zero(&a); + a.val[(4 * i) / 30] = (uint32_t)(2 * j + 1) << (4 * i % 30); + bn_normalize(&a); + // note that this is not a trivial test. We add 64 curve + // points in the table to get that particular curve point. + scalar_multiply(curve, &a, &p); + ck_assert_mem_eq(&p, &curve->cp[i][j], sizeof(curve_point)); + bn_zero(&p.y); // test that point_multiply curve, is not a noop + point_multiply(curve, &a, &curve->G, &p); + ck_assert_mem_eq(&p, &curve->cp[i][j], sizeof(curve_point)); + // mul 2 test. this should catch bugs + bn_lshift(&a); + bn_mod(&a, &curve->order); + p1 = curve->cp[i][j]; + point_double(curve, &p1); + // note that this is not a trivial test. We add 64 curve + // points in the table to get that particular curve point. + scalar_multiply(curve, &a, &p); + ck_assert_mem_eq(&p, &p1, sizeof(curve_point)); + bn_zero(&p.y); // test that point_multiply curve, is not a noop + point_multiply(curve, &a, &curve->G, &p); + ck_assert_mem_eq(&p, &p1, sizeof(curve_point)); + } + } } -START_TEST(test_codepoints_secp256k1) { test_codepoints_curve(&secp256k1); } END_TEST -START_TEST(test_codepoints_nist256p1) { test_codepoints_curve(&nist256p1); } END_TEST +START_TEST(test_codepoints_secp256k1) { test_codepoints_curve(&secp256k1); } +END_TEST +START_TEST(test_codepoints_nist256p1) { test_codepoints_curve(&nist256p1); } +END_TEST static void test_mult_border_cases_curve(const ecdsa_curve *curve) { - bignum256 a; - curve_point p; - curve_point expected; - bn_zero(&a); // a == 0 - scalar_multiply(curve, &a, &p); - ck_assert(point_is_infinity(&p)); - point_multiply(curve, &a, &p, &p); - ck_assert(point_is_infinity(&p)); - point_multiply(curve, &a, &curve->G, &p); - ck_assert(point_is_infinity(&p)); - - bn_addi(&a, 1); // a == 1 - scalar_multiply(curve, &a, &p); - ck_assert_mem_eq(&p, &curve->G, sizeof(curve_point)); - point_multiply(curve, &a, &curve->G, &p); - ck_assert_mem_eq(&p, &curve->G, sizeof(curve_point)); - - bn_subtract(&curve->order, &a, &a); // a == -1 - expected = curve->G; - bn_subtract(&curve->prime, &expected.y, &expected.y); - scalar_multiply(curve, &a, &p); - ck_assert_mem_eq(&p, &expected, sizeof(curve_point)); - point_multiply(curve, &a, &curve->G, &p); - ck_assert_mem_eq(&p, &expected, sizeof(curve_point)); - - bn_subtract(&curve->order, &a, &a); - bn_addi(&a, 1); // a == 2 - expected = curve->G; - point_add(curve, &expected, &expected); - scalar_multiply(curve, &a, &p); - ck_assert_mem_eq(&p, &expected, sizeof(curve_point)); - point_multiply(curve, &a, &curve->G, &p); - ck_assert_mem_eq(&p, &expected, sizeof(curve_point)); - - bn_subtract(&curve->order, &a, &a); // a == -2 - expected = curve->G; - point_add(curve, &expected, &expected); - bn_subtract(&curve->prime, &expected.y, &expected.y); - scalar_multiply(curve, &a, &p); - ck_assert_mem_eq(&p, &expected, sizeof(curve_point)); - point_multiply(curve, &a, &curve->G, &p); - ck_assert_mem_eq(&p, &expected, sizeof(curve_point)); + bignum256 a; + curve_point p; + curve_point expected; + bn_zero(&a); // a == 0 + scalar_multiply(curve, &a, &p); + ck_assert(point_is_infinity(&p)); + point_multiply(curve, &a, &p, &p); + ck_assert(point_is_infinity(&p)); + point_multiply(curve, &a, &curve->G, &p); + ck_assert(point_is_infinity(&p)); + + bn_addi(&a, 1); // a == 1 + scalar_multiply(curve, &a, &p); + ck_assert_mem_eq(&p, &curve->G, sizeof(curve_point)); + point_multiply(curve, &a, &curve->G, &p); + ck_assert_mem_eq(&p, &curve->G, sizeof(curve_point)); + + bn_subtract(&curve->order, &a, &a); // a == -1 + expected = curve->G; + bn_subtract(&curve->prime, &expected.y, &expected.y); + scalar_multiply(curve, &a, &p); + ck_assert_mem_eq(&p, &expected, sizeof(curve_point)); + point_multiply(curve, &a, &curve->G, &p); + ck_assert_mem_eq(&p, &expected, sizeof(curve_point)); + + bn_subtract(&curve->order, &a, &a); + bn_addi(&a, 1); // a == 2 + expected = curve->G; + point_add(curve, &expected, &expected); + scalar_multiply(curve, &a, &p); + ck_assert_mem_eq(&p, &expected, sizeof(curve_point)); + point_multiply(curve, &a, &curve->G, &p); + ck_assert_mem_eq(&p, &expected, sizeof(curve_point)); + + bn_subtract(&curve->order, &a, &a); // a == -2 + expected = curve->G; + point_add(curve, &expected, &expected); + bn_subtract(&curve->prime, &expected.y, &expected.y); + scalar_multiply(curve, &a, &p); + ck_assert_mem_eq(&p, &expected, sizeof(curve_point)); + point_multiply(curve, &a, &curve->G, &p); + ck_assert_mem_eq(&p, &expected, sizeof(curve_point)); } -START_TEST(test_mult_border_cases_secp256k1) { test_mult_border_cases_curve(&secp256k1); } END_TEST -START_TEST(test_mult_border_cases_nist256p1) { test_mult_border_cases_curve(&nist256p1); } END_TEST +START_TEST(test_mult_border_cases_secp256k1) { + test_mult_border_cases_curve(&secp256k1); +} +END_TEST +START_TEST(test_mult_border_cases_nist256p1) { + test_mult_border_cases_curve(&nist256p1); +} +END_TEST static void test_scalar_mult_curve(const ecdsa_curve *curve) { - int i; - // get two "random" numbers - bignum256 a = curve->G.x; - bignum256 b = curve->G.y; - curve_point p1, p2, p3; - for (i = 0; i < 1000; i++) { - /* test distributivity: (a + b)G = aG + bG */ - bn_mod(&a, &curve->order); - bn_mod(&b, &curve->order); - scalar_multiply(curve, &a, &p1); - scalar_multiply(curve, &b, &p2); - bn_addmod(&a, &b, &curve->order); - bn_mod(&a, &curve->order); - scalar_multiply(curve, &a, &p3); - point_add(curve, &p1, &p2); - ck_assert_mem_eq(&p2, &p3, sizeof(curve_point)); - // new "random" numbers - a = p3.x; - b = p3.y; - } + int i; + // get two "random" numbers + bignum256 a = curve->G.x; + bignum256 b = curve->G.y; + curve_point p1, p2, p3; + for (i = 0; i < 1000; i++) { + /* test distributivity: (a + b)G = aG + bG */ + bn_mod(&a, &curve->order); + bn_mod(&b, &curve->order); + scalar_multiply(curve, &a, &p1); + scalar_multiply(curve, &b, &p2); + bn_addmod(&a, &b, &curve->order); + bn_mod(&a, &curve->order); + scalar_multiply(curve, &a, &p3); + point_add(curve, &p1, &p2); + ck_assert_mem_eq(&p2, &p3, sizeof(curve_point)); + // new "random" numbers + a = p3.x; + b = p3.y; + } } -START_TEST(test_scalar_mult_secp256k1) { test_scalar_mult_curve(&secp256k1); } END_TEST -START_TEST(test_scalar_mult_nist256p1) { test_scalar_mult_curve(&nist256p1); } END_TEST +START_TEST(test_scalar_mult_secp256k1) { test_scalar_mult_curve(&secp256k1); } +END_TEST +START_TEST(test_scalar_mult_nist256p1) { test_scalar_mult_curve(&nist256p1); } +END_TEST static void test_point_mult_curve(const ecdsa_curve *curve) { - int i; - // get two "random" numbers and a "random" point - bignum256 a = curve->G.x; - bignum256 b = curve->G.y; - curve_point p = curve->G; - curve_point p1, p2, p3; - for (i = 0; i < 200; i++) { - /* test distributivity: (a + b)P = aP + bP */ - bn_mod(&a, &curve->order); - bn_mod(&b, &curve->order); - point_multiply(curve, &a, &p, &p1); - point_multiply(curve, &b, &p, &p2); - bn_addmod(&a, &b, &curve->order); - bn_mod(&a, &curve->order); - point_multiply(curve, &a, &p, &p3); - point_add(curve, &p1, &p2); - ck_assert_mem_eq(&p2, &p3, sizeof(curve_point)); - // new "random" numbers and a "random" point - a = p1.x; - b = p1.y; - p = p3; - } + int i; + // get two "random" numbers and a "random" point + bignum256 a = curve->G.x; + bignum256 b = curve->G.y; + curve_point p = curve->G; + curve_point p1, p2, p3; + for (i = 0; i < 200; i++) { + /* test distributivity: (a + b)P = aP + bP */ + bn_mod(&a, &curve->order); + bn_mod(&b, &curve->order); + point_multiply(curve, &a, &p, &p1); + point_multiply(curve, &b, &p, &p2); + bn_addmod(&a, &b, &curve->order); + bn_mod(&a, &curve->order); + point_multiply(curve, &a, &p, &p3); + point_add(curve, &p1, &p2); + ck_assert_mem_eq(&p2, &p3, sizeof(curve_point)); + // new "random" numbers and a "random" point + a = p1.x; + b = p1.y; + p = p3; + } } -START_TEST(test_point_mult_secp256k1) { test_point_mult_curve(&secp256k1); } END_TEST -START_TEST(test_point_mult_nist256p1) { test_point_mult_curve(&nist256p1); } END_TEST +START_TEST(test_point_mult_secp256k1) { test_point_mult_curve(&secp256k1); } +END_TEST +START_TEST(test_point_mult_nist256p1) { test_point_mult_curve(&nist256p1); } +END_TEST static void test_scalar_point_mult_curve(const ecdsa_curve *curve) { - int i; - // get two "random" numbers - bignum256 a = curve->G.x; - bignum256 b = curve->G.y; - curve_point p1, p2; - for (i = 0; i < 200; i++) { - /* test commutativity and associativity: - * a(bG) = (ab)G = b(aG) - */ - bn_mod(&a, &curve->order); - bn_mod(&b, &curve->order); - scalar_multiply(curve, &a, &p1); - point_multiply(curve, &b, &p1, &p1); - - scalar_multiply(curve, &b, &p2); - point_multiply(curve, &a, &p2, &p2); - - ck_assert_mem_eq(&p1, &p2, sizeof(curve_point)); - - bn_multiply(&a, &b, &curve->order); - bn_mod(&b, &curve->order); - scalar_multiply(curve, &b, &p2); - - ck_assert_mem_eq(&p1, &p2, sizeof(curve_point)); - - // new "random" numbers - a = p1.x; - b = p1.y; - } + int i; + // get two "random" numbers + bignum256 a = curve->G.x; + bignum256 b = curve->G.y; + curve_point p1, p2; + for (i = 0; i < 200; i++) { + /* test commutativity and associativity: + * a(bG) = (ab)G = b(aG) + */ + bn_mod(&a, &curve->order); + bn_mod(&b, &curve->order); + scalar_multiply(curve, &a, &p1); + point_multiply(curve, &b, &p1, &p1); + + scalar_multiply(curve, &b, &p2); + point_multiply(curve, &a, &p2, &p2); + + ck_assert_mem_eq(&p1, &p2, sizeof(curve_point)); + + bn_multiply(&a, &b, &curve->order); + bn_mod(&b, &curve->order); + scalar_multiply(curve, &b, &p2); + + ck_assert_mem_eq(&p1, &p2, sizeof(curve_point)); + + // new "random" numbers + a = p1.x; + b = p1.y; + } } -START_TEST(test_scalar_point_mult_secp256k1) { test_scalar_point_mult_curve(&secp256k1); } END_TEST -START_TEST(test_scalar_point_mult_nist256p1) { test_scalar_point_mult_curve(&nist256p1); } END_TEST +START_TEST(test_scalar_point_mult_secp256k1) { + test_scalar_point_mult_curve(&secp256k1); +} +END_TEST +START_TEST(test_scalar_point_mult_nist256p1) { + test_scalar_point_mult_curve(&nist256p1); +} +END_TEST START_TEST(test_ed25519) { - // test vectors from https://github.com/torproject/tor/blob/master/src/test/ed25519_vectors.inc - static const char *vectors[] = { - "26c76712d89d906e6672dafa614c42e5cb1caac8c6568e4d2493087db51f0d36", // secret - "c2247870536a192d142d056abefca68d6193158e7c1a59c1654c954eccaff894", // public - "d23188eac3773a316d46006fa59c095060be8b1a23582a0dd99002a82a0662bd246d8449e172e04c5f46ac0d1404cebe4aabd8a75a1457aa06cae41f3334f104", // selfsig - "fba7a5366b5cb98c2667a18783f5cf8f4f8d1a2ce939ad22a6e685edde85128d", - "1519a3b15816a1aafab0b213892026ebf5c0dc232c58b21088d88cb90e9b940d", - "3a785ac1201c97ee5f6f0d99323960d5f264c7825e61aa7cc81262f15bef75eb4fa5723add9b9d45b12311b6d403eb3ac79ff8e4e631fc3cd51e4ad2185b200b", - "67e3aa7a14fac8445d15e45e38a523481a69ae35513c9e4143eb1c2196729a0e", - "081faa81992e360ea22c06af1aba096e7a73f1c665bc8b3e4e531c46455fd1dd", - "cf431fd0416bfbd20c9d95ef9b723e2acddffb33900edc72195dea95965d52d888d30b7b8a677c0bd8ae1417b1e1a0ec6700deadd5d8b54b6689275e04a04509", - "d51385942033a76dc17f089a59e6a5a7fe80d9c526ae8ddd8c3a506b99d3d0a6", - "73cfa1189a723aad7966137cbffa35140bb40d7e16eae4c40b79b5f0360dd65a", - "2375380cd72d1a6c642aeddff862be8a5804b916acb72c02d9ed052c1561881aa658a5af856fcd6d43113e42f698cd6687c99efeef7f2ce045824440d26c5d00", - "5c8eac469bb3f1b85bc7cd893f52dc42a9ab66f1b02b5ce6a68e9b175d3bb433", - "66c1a77104d86461b6f98f73acf3cd229c80624495d2d74d6fda1e940080a96b", - "2385a472f599ca965bbe4d610e391cdeabeba9c336694b0d6249e551458280be122c2441dd9746a81bbfb9cd619364bab0df37ff4ceb7aefd24469c39d3bc508", - "eda433d483059b6d1ff8b7cfbd0fe406bfb23722c8f3c8252629284573b61b86", - "d21c294db0e64cb2d8976625786ede1d9754186ae8197a64d72f68c792eecc19", - "e500cd0b8cfff35442f88008d894f3a2fa26ef7d3a0ca5714ae0d3e2d40caae58ba7cdf69dd126994dad6be536fcda846d89dd8138d1683cc144c8853dce7607", - "4377c40431c30883c5fbd9bc92ae48d1ed8a47b81d13806beac5351739b5533d", - "c4d58b4cf85a348ff3d410dd936fa460c4f18da962c01b1963792b9dcc8a6ea6", - "d187b9e334b0050154de10bf69b3e4208a584e1a65015ec28b14bcc252cf84b8baa9c94867daa60f2a82d09ba9652d41e8dde292b624afc8d2c26441b95e3c0e", - "c6bbcce615839756aed2cc78b1de13884dd3618f48367a17597a16c1cd7a290b", - "95126f14d86494020665face03f2d42ee2b312a85bc729903eb17522954a1c4a", - "815213640a643d198bd056e02bba74e1c8d2d931643e84497adf3347eb485079c9afe0afce9284cdc084946b561abbb214f1304ca11228ff82702185cf28f60d", - 0, - 0, - 0, - }; - const char **ssk, **spk, **ssig; - ssk = vectors; - spk = vectors + 1; - ssig = vectors + 2; - ed25519_public_key pk; - ed25519_secret_key sk; - ed25519_signature sig; - while (*ssk && *spk && *ssig) { - memcpy(sk, fromhex(*ssk), 32); - MARK_SECRET_DATA(sk, sizeof(sk)); - - ed25519_publickey(sk, pk); - UNMARK_SECRET_DATA(pk, sizeof(pk)); - ck_assert_mem_eq(pk, fromhex(*spk), 32); - - ed25519_sign(pk, 32, sk, pk, sig); - UNMARK_SECRET_DATA(sig, sizeof(sig)); - ck_assert_mem_eq(sig, fromhex(*ssig), 64); - - ssk += 3; - spk += 3; - ssig += 3; - - UNMARK_SECRET_DATA(sk, sizeof(sk)); - } + // test vectors from + // https://github.com/torproject/tor/blob/master/src/test/ed25519_vectors.inc + static const char *vectors[] = { + "26c76712d89d906e6672dafa614c42e5cb1caac8c6568e4d2493087db51f0d3" + "6", // secret + "c2247870536a192d142d056abefca68d6193158e7c1a59c1654c954eccaff89" + "4", // public + "d23188eac3773a316d46006fa59c095060be8b1a23582a0dd99002a82a0662bd" + "246d8449e172e04c5f46ac0d1404cebe4aabd8a75a1457aa06cae41f3334f10" + "4", // selfsig + "fba7a5366b5cb98c2667a18783f5cf8f4f8d1a2ce939ad22a6e685edde85128" + "d", + "1519a3b15816a1aafab0b213892026ebf5c0dc232c58b21088d88cb90e9b940" + "d", + "3a785ac1201c97ee5f6f0d99323960d5f264c7825e61aa7cc81262f15bef75eb" + "4fa5723add9b9d45b12311b6d403eb3ac79ff8e4e631fc3cd51e4ad2185b200" + "b", + "67e3aa7a14fac8445d15e45e38a523481a69ae35513c9e4143eb1c2196729a0" + "e", + "081faa81992e360ea22c06af1aba096e7a73f1c665bc8b3e4e531c46455fd1d" + "d", + "cf431fd0416bfbd20c9d95ef9b723e2acddffb33900edc72195dea95965d52d8" + "88d30b7b8a677c0bd8ae1417b1e1a0ec6700deadd5d8b54b6689275e04a0450" + "9", + "d51385942033a76dc17f089a59e6a5a7fe80d9c526ae8ddd8c3a506b99d3d0a" + "6", + "73cfa1189a723aad7966137cbffa35140bb40d7e16eae4c40b79b5f0360dd65" + "a", + "2375380cd72d1a6c642aeddff862be8a5804b916acb72c02d9ed052c1561881a" + "a658a5af856fcd6d43113e42f698cd6687c99efeef7f2ce045824440d26c5d0" + "0", + "5c8eac469bb3f1b85bc7cd893f52dc42a9ab66f1b02b5ce6a68e9b175d3bb43" + "3", + "66c1a77104d86461b6f98f73acf3cd229c80624495d2d74d6fda1e940080a96" + "b", + "2385a472f599ca965bbe4d610e391cdeabeba9c336694b0d6249e551458280be" + "122c2441dd9746a81bbfb9cd619364bab0df37ff4ceb7aefd24469c39d3bc50" + "8", + "eda433d483059b6d1ff8b7cfbd0fe406bfb23722c8f3c8252629284573b61b8" + "6", + "d21c294db0e64cb2d8976625786ede1d9754186ae8197a64d72f68c792eecc1" + "9", + "e500cd0b8cfff35442f88008d894f3a2fa26ef7d3a0ca5714ae0d3e2d40caae5" + "8ba7cdf69dd126994dad6be536fcda846d89dd8138d1683cc144c8853dce760" + "7", + "4377c40431c30883c5fbd9bc92ae48d1ed8a47b81d13806beac5351739b5533" + "d", + "c4d58b4cf85a348ff3d410dd936fa460c4f18da962c01b1963792b9dcc8a6ea" + "6", + "d187b9e334b0050154de10bf69b3e4208a584e1a65015ec28b14bcc252cf84b8" + "baa9c94867daa60f2a82d09ba9652d41e8dde292b624afc8d2c26441b95e3c0" + "e", + "c6bbcce615839756aed2cc78b1de13884dd3618f48367a17597a16c1cd7a290" + "b", + "95126f14d86494020665face03f2d42ee2b312a85bc729903eb17522954a1c4" + "a", + "815213640a643d198bd056e02bba74e1c8d2d931643e84497adf3347eb485079" + "c9afe0afce9284cdc084946b561abbb214f1304ca11228ff82702185cf28f60" + "d", + 0, + 0, + 0, + }; + const char **ssk, **spk, **ssig; + ssk = vectors; + spk = vectors + 1; + ssig = vectors + 2; + ed25519_public_key pk; + ed25519_secret_key sk; + ed25519_signature sig; + while (*ssk && *spk && *ssig) { + memcpy(sk, fromhex(*ssk), 32); + MARK_SECRET_DATA(sk, sizeof(sk)); + + ed25519_publickey(sk, pk); + UNMARK_SECRET_DATA(pk, sizeof(pk)); + ck_assert_mem_eq(pk, fromhex(*spk), 32); + + ed25519_sign(pk, 32, sk, pk, sig); + UNMARK_SECRET_DATA(sig, sizeof(sig)); + ck_assert_mem_eq(sig, fromhex(*ssig), 64); + + ssk += 3; + spk += 3; + ssig += 3; + + UNMARK_SECRET_DATA(sk, sizeof(sk)); + } } END_TEST -// test vectors from https://raw.githubusercontent.com/NemProject/nem-test-vectors/master/2.test-sign.dat -START_TEST(test_ed25519_keccak) -{ - static const struct { - const char *private_key; - const char *public_key; - const char *signature; - size_t length; - const char *data; - } tests[] = { - { "abf4cf55a2b3f742d7543d9cc17f50447b969e6e06f5ea9195d428ab12b7318d", "8a558c728c21c126181e5e654b404a45b4f0137ce88177435a69978cc6bec1f4", "d9cec0cc0e3465fab229f8e1d6db68ab9cc99a18cb0435f70deb6100948576cd5c0aa1feb550bdd8693ef81eb10a556a622db1f9301986827b96716a7134230c", 41, "8ce03cd60514233b86789729102ea09e867fc6d964dea8c2018ef7d0a2e0e24bf7e348e917116690b9", }, - { "6aa6dad25d3acb3385d5643293133936cdddd7f7e11818771db1ff2f9d3f9215", "bbc8cbb43dda3ecf70a555981a351a064493f09658fffe884c6fab2a69c845c6", "98bca58b075d1748f1c3a7ae18f9341bc18e90d1beb8499e8a654c65d8a0b4fbd2e084661088d1e5069187a2811996ae31f59463668ef0f8cb0ac46a726e7902", 49, "e4a92208a6fc52282b620699191ee6fb9cf04daf48b48fd542c5e43daa9897763a199aaa4b6f10546109f47ac3564fade0", }, - { "8e32bc030a4c53de782ec75ba7d5e25e64a2a072a56e5170b77a4924ef3c32a9", "72d0e65f1ede79c4af0ba7ec14204e10f0f7ea09f2bc43259cd60ea8c3a087e2", "ef257d6e73706bb04878875c58aa385385bf439f7040ea8297f7798a0ea30c1c5eff5ddc05443f801849c68e98111ae65d088e726d1d9b7eeca2eb93b677860c", 40, "13ed795344c4448a3b256f23665336645a853c5c44dbff6db1b9224b5303b6447fbf8240a2249c55", }, - { "c83ce30fcb5b81a51ba58ff827ccbc0142d61c13e2ed39e78e876605da16d8d7", "3ec8923f9ea5ea14f8aaa7e7c2784653ed8c7de44e352ef9fc1dee81fc3fa1a3", "0c684e71b35fed4d92b222fc60561db34e0d8afe44bdd958aaf4ee965911bef5991236f3e1bced59fc44030693bcac37f34d29e5ae946669dc326e706e81b804", 49, "a2704638434e9f7340f22d08019c4c8e3dbee0df8dd4454a1d70844de11694f4c8ca67fdcb08fed0cec9abb2112b5e5f89", }, - { "2da2a0aae0f37235957b51d15843edde348a559692d8fa87b94848459899fc27", "d73d0b14a9754eec825fcb25ef1cfa9ae3b1370074eda53fc64c22334a26c254", "6f17f7b21ef9d6907a7ab104559f77d5a2532b557d95edffd6d88c073d87ac00fc838fc0d05282a0280368092a4bd67e95c20f3e14580be28d8b351968c65e03", 40, "d2488e854dbcdfdb2c9d16c8c0b2fdbc0abb6bac991bfe2b14d359a6bc99d66c00fd60d731ae06d0", }, - { "0c066261fb1b18ebf2a9bcdeda81eb47d5a3745438b3d0b9d19b75885ad0a154", "2e5773f0e725024bc0359ce93a44e15d6507e7b160b6c592200385fee4a269cf", "13b5d2dd1b04f62cc2ec1544fed256423684f2dbca4538ceddda1d15c59dc7196c87840ea303ea30f4f6914a6ec9167841980c1d717f47fd641225068de88507", 41, "f15cb706e29fcfbcb324e38cbac62bb355deddb845c142e970f0c029ea4d05e59fd6adf85573cf1775", }, - { "ef3d8e22a592f04c3a31aa736e10901757a821d053f1a49a525b4ec91eacdee3", "72a2b4910a502b30e13a96aba643c59c79328c1ba1462be6f254e817ef157fee", "95f2437a0210d2d2f125a3c377ed666c0d596cd104185e70204924a182a11a6eb3bdba4395bbfc3f4e827d38805752657ee52d1ce0f17e70f59bfd4999282509", 50, "6c3e4387345740b8d62cf0c9dec48f98c292539431b2b54020d8072d9cb55f0197f7d99ff066afcf9e41ea8b7aea78eb082d", }, - { "f7fb79743e9ba957d2a4f1bd95ceb1299552abecaf758bf840d2dc2c09f3e3cb", "8b7d7531280f76a8abac8293d87508e3953894087112ae01b6ad32485d4e9b67", "c868ecf31cee783fe8799ac7e6a662431c822967351d8b79687f4ddf608f79a080c4ff9eed4fdee8c99fe1be905f734cae2a172f1cfdb00771625c0695a5260e", 42, "55d8e60c307ee533b1af9ff677a2de40a6eace722bcc9eb5d79907b420e533bc06db674dafbd9f43d672", }, - { "8cc9a2469a77fad18b44b871b2b6932cd354641d2d1e84403f746c4fff829791", "aed5da202d4983dac560faf6704dc76ac111616318570e244043e82ed1bbcd2b", "aee9616db4135150818eaffa3e4503c2d7e9e834847a4c7d0a8856e952761d361a657104d36950c9b75770ded00d56a96e06f383fa2406bc935dcf51f272300e", 42, "d9b8be2f71b83261304e333d6e35563dc3c36c2eb5a23e1461b6e95aa7c6f381f9c3bd39deaa1b6df2f9", }, - { "a247abbef0c1affbf021d1aff128888550532fc0edd77bc39f6ef5312317ec47", "98ededbad1e5ad7a0d5a0cf4fcd7a794eb5c6900a65e7e921884a636f19b131d", "f8cc02933851432f0c5df0b70f2067f740ccb72de7d6fa1e9a9b0d6de1402b9c6c525fd848e45aaaac1423b52880ec3474a2f64b38db6fc8e008d95a310e6e0c", 47, "4a5f07eb713932532fc3132c96efdc45862fe7a954c1d2ae4640afdf4728fb58c65e8a4ebfe0d53d5797d5146442b9", }, - { "163d69079ddad1f16695c47d81c3b72f869b2fdd50e6e47113db6c85051a6ede", "93fe602642ee5773f4aaf6a3bc21e98e354035225353f419e78e43c3ec36c88a", "da747fa2cb47aae1effc1e4cfde0e39fa79937948592a712a7665bf948b8311e7f3f80f966301679520d5c2afa3eadd60e061f0d264887500d8d03a17e10fd02", 41, "65fe5c1a0214a59644892e5ac4216f09fbb4e191b89bfb63d6540177d25ef9e3714850b8453bd6b2b6", }, - { "7b061bf90eb760971b9ec66a96fd6609635ca4b531f33e3c126b9ae6fdb3d491", "cb392ebb6912df4111efeeb1278160daf9da396e9291b83979a5ac479f7276d2", "f6eebe86f7ea672e0707ee518e1798d6fbd118c11b2aa30be07d10e3882e3721f2030f9f044b77c3a7a9a2f1feba7e7ce75d1f7f3807a96a764fded35d341d02", 45, "a17f5ce39b9ba7b7cf1147e515d6aa84b22fd0e2d8323a91367198fc6c3aff04ebb21fc2bdbe7bc0364e8040a9", }, - { "c9f8ccbf761cec00ab236c52651e76b5f46d90f8936d44d40561ed5c277104de", "a3192641e343b669ffd43677c2e5cd4efaed174e876141f1d773bd6cfe30d875", "d44f884ec9eae2e99e74194b5acc769b7aa369aaad359e92ba6ff0fe629af2a9a7156c19b720e7de8c7f03c039563f160948073cab6f99b26a56a8bb1023ba08", 47, "3d7e33b0ecead8269966e9dcd192b73eb8a12573fc8a5fdfbe5753541026ef2e49f5280cba9bc2515a049b3a1c1b49", }, - { "ebfa409ac6f987df476858dd35310879bf564eeb62984a52115d2e6c24590124", "7bb1601fe7215f3f4da9c8ab5e804dc58f57ba41b03223f57ec80d9c9a2dd0e1", "f3e7c1abfcc9f35556cb1e4c5a2b34445177ac188312d9148f1d1d8467ea8411fa3cda031d023034e45bbe407ef7d1b937bfb098266138857d35cb4efe407306", 52, "0c37564f718eda683aa6f3e9ab2487620b1a8b5c8f20adb3b2d7550af0d635371e531f27cebe76a2abcc96de0875bdae987a45ac", }, - { "f993f61902b7da332f2bb001baa7accaf764d824eb0cd073315f7ec43158b8fb", "55fc8e0da1b454cab6ddefb235311db2b01504bf9ac3f71c7e3f3d0d1f09f80b", "178bd147673c0ca330e45da63cbd1f1811906bd5284bb44e4bb00f7d7163d1f396975610b6f71c1ae4686466fad4c5e7bb9685099e21ca4f1a45bb3fcf56ae0c", 42, "b7dd613bc9c364d9eeb9a52636d72bc881dfc81a836b6537bbb928bff5b73831358947ea9edea1570550", }, - { "05188c09c31b4bb63f0d49b47ccc1654c2aba907b8c6c0a82ee403e950169167", "e096d808dfabe8e44eb74950199dadcd586f9de6b141a0ce85ab94b3d97866eb", "669491c8eb7cedbbc0252f3eafb048b39a2a37f60ac87837777c72c879ac8b726c39e10060750c2f539102999b71889746111bc5f71ec8c158cc81cf566aef03", 44, "bb8e22469d1c7f1d5418563e8781f69eccb56678bd36d8919f358c2778562ff6b50de916c12d44f1a778a7f3", }, - { "eabe57e1a916ebbffa4ba7abc7f23e83d4deb1338816cc1784d7495d92e98d0b", "3aad275642f48a46ed1032f3de9f4053e0fd35cf217e065d2e4579c3683932f7", "b2e9dac2c83942ca374f29c8eff5a30c377c3db3c1c645e593e524d17484e7705b11f79573e2d63495fc3ce3bf216a209f0cb7bea477ae0f8bd297f193af8805", 44, "3f2c2d6682ee597f2a92d7e560ac53d5623550311a4939d68adfb904045ed8d215a9fdb757a2368ea4d89f5f", }, - { "fef7b893b4b517fab68ca12d36b603bc00826bf3c9b31a05149642ae10bb3f55", "b3fb891868708dfa5da5b9b5234058767ab42c117f12c3228c02a1976d1c0f83", "6243e289314b7c7587802909a9be6173a916b36f9de1e164954dfe5d1ebd57c869a79552d770e13b51855502be6b15e7be42a3675298a81284df58e609b06503", 47, "38c69f884045cdbeebe4478fdbd1ccc6cf00a08d8a3120c74e7167d3a2e26a67a043b8e5bd198f7b0ce0358cef7cf9", }, - { "16228bec9b724300a37e88e535fc1c58548d34d7148b57c226f2b3af974c1822", "3c92423a8360c9a5d9a093730d72831bec4601dcadfe84de19fc8c8f91fc3d4b", "6aebfa9a4294ec888d54bcb517fcb6821e4c16d2708a2afe701f431a28149ff4f139f9d16a52a63f1f91baf4c8dea37710c73f25c263a8035a39cc118ad0280f", 44, "a3d7b122cd4431b396b20d8cc46cc73ed4a5253a44a76fc83db62cdc845a2bf7081d069a857955a161cccf84", }, - { "2dc3f5f0a0bc32c6632534e1e8f27e59cbe0bf7617d31aff98098e974c828be7", "b998a416edc28ded988dcacb1caf2bd96c87354b0d1eeccb6980e54a3104f21f", "76a2ddfc4bea48c47e0c82bcbfee28a37c61ec626af39a468e643e0ef9f6533056a5a0b44e64d614ba3c641a40e5b003a99463445ae2c3c8e1e9882092d74b07", 42, "bdae276d738b9758ea3d322b54fd12fe82b767e8d817d8ef3d41f78705748e28d15e9c506962a1b85901", }, - }; - - ed25519_secret_key private_key; - ed25519_public_key public_key; - ed25519_signature signature; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - nem_private_key(tests[i].private_key, private_key); - MARK_SECRET_DATA(private_key, sizeof(private_key)); - - ed25519_publickey_keccak(private_key, public_key); - UNMARK_SECRET_DATA(public_key, sizeof(public_key)); - ck_assert_mem_eq(public_key, fromhex(tests[i].public_key), 32); - - ed25519_sign_keccak(fromhex(tests[i].data), tests[i].length, private_key, public_key, signature); - UNMARK_SECRET_DATA(signature, sizeof(signature)); - ck_assert_mem_eq(signature, fromhex(tests[i].signature), 64); - - UNMARK_SECRET_DATA(private_key, sizeof(private_key)); - } +// test vectors from +// https://raw.githubusercontent.com/NemProject/nem-test-vectors/master/2.test-sign.dat +START_TEST(test_ed25519_keccak) { + static const struct { + const char *private_key; + const char *public_key; + const char *signature; + size_t length; + const char *data; + } tests[] = { + { + "abf4cf55a2b3f742d7543d9cc17f50447b969e6e06f5ea9195d428ab12b7318d", + "8a558c728c21c126181e5e654b404a45b4f0137ce88177435a69978cc6bec1f4", + "d9cec0cc0e3465fab229f8e1d6db68ab9cc99a18cb0435f70deb6100948576cd5c0a" + "a1feb550bdd8693ef81eb10a556a622db1f9301986827b96716a7134230c", + 41, + "8ce03cd60514233b86789729102ea09e867fc6d964dea8c2018ef7d0a2e0e24bf7e3" + "48e917116690b9", + }, + { + "6aa6dad25d3acb3385d5643293133936cdddd7f7e11818771db1ff2f9d3f9215", + "bbc8cbb43dda3ecf70a555981a351a064493f09658fffe884c6fab2a69c845c6", + "98bca58b075d1748f1c3a7ae18f9341bc18e90d1beb8499e8a654c65d8a0b4fbd2e0" + "84661088d1e5069187a2811996ae31f59463668ef0f8cb0ac46a726e7902", + 49, + "e4a92208a6fc52282b620699191ee6fb9cf04daf48b48fd542c5e43daa9897763a19" + "9aaa4b6f10546109f47ac3564fade0", + }, + { + "8e32bc030a4c53de782ec75ba7d5e25e64a2a072a56e5170b77a4924ef3c32a9", + "72d0e65f1ede79c4af0ba7ec14204e10f0f7ea09f2bc43259cd60ea8c3a087e2", + "ef257d6e73706bb04878875c58aa385385bf439f7040ea8297f7798a0ea30c1c5eff" + "5ddc05443f801849c68e98111ae65d088e726d1d9b7eeca2eb93b677860c", + 40, + "13ed795344c4448a3b256f23665336645a853c5c44dbff6db1b9224b5303b6447fbf" + "8240a2249c55", + }, + { + "c83ce30fcb5b81a51ba58ff827ccbc0142d61c13e2ed39e78e876605da16d8d7", + "3ec8923f9ea5ea14f8aaa7e7c2784653ed8c7de44e352ef9fc1dee81fc3fa1a3", + "0c684e71b35fed4d92b222fc60561db34e0d8afe44bdd958aaf4ee965911bef59912" + "36f3e1bced59fc44030693bcac37f34d29e5ae946669dc326e706e81b804", + 49, + "a2704638434e9f7340f22d08019c4c8e3dbee0df8dd4454a1d70844de11694f4c8ca" + "67fdcb08fed0cec9abb2112b5e5f89", + }, + { + "2da2a0aae0f37235957b51d15843edde348a559692d8fa87b94848459899fc27", + "d73d0b14a9754eec825fcb25ef1cfa9ae3b1370074eda53fc64c22334a26c254", + "6f17f7b21ef9d6907a7ab104559f77d5a2532b557d95edffd6d88c073d87ac00fc83" + "8fc0d05282a0280368092a4bd67e95c20f3e14580be28d8b351968c65e03", + 40, + "d2488e854dbcdfdb2c9d16c8c0b2fdbc0abb6bac991bfe2b14d359a6bc99d66c00fd" + "60d731ae06d0", + }, + { + "0c066261fb1b18ebf2a9bcdeda81eb47d5a3745438b3d0b9d19b75885ad0a154", + "2e5773f0e725024bc0359ce93a44e15d6507e7b160b6c592200385fee4a269cf", + "13b5d2dd1b04f62cc2ec1544fed256423684f2dbca4538ceddda1d15c59dc7196c87" + "840ea303ea30f4f6914a6ec9167841980c1d717f47fd641225068de88507", + 41, + "f15cb706e29fcfbcb324e38cbac62bb355deddb845c142e970f0c029ea4d05e59fd6" + "adf85573cf1775", + }, + { + "ef3d8e22a592f04c3a31aa736e10901757a821d053f1a49a525b4ec91eacdee3", + "72a2b4910a502b30e13a96aba643c59c79328c1ba1462be6f254e817ef157fee", + "95f2437a0210d2d2f125a3c377ed666c0d596cd104185e70204924a182a11a6eb3bd" + "ba4395bbfc3f4e827d38805752657ee52d1ce0f17e70f59bfd4999282509", + 50, + "6c3e4387345740b8d62cf0c9dec48f98c292539431b2b54020d8072d9cb55f0197f7" + "d99ff066afcf9e41ea8b7aea78eb082d", + }, + { + "f7fb79743e9ba957d2a4f1bd95ceb1299552abecaf758bf840d2dc2c09f3e3cb", + "8b7d7531280f76a8abac8293d87508e3953894087112ae01b6ad32485d4e9b67", + "c868ecf31cee783fe8799ac7e6a662431c822967351d8b79687f4ddf608f79a080c4" + "ff9eed4fdee8c99fe1be905f734cae2a172f1cfdb00771625c0695a5260e", + 42, + "55d8e60c307ee533b1af9ff677a2de40a6eace722bcc9eb5d79907b420e533bc06db" + "674dafbd9f43d672", + }, + { + "8cc9a2469a77fad18b44b871b2b6932cd354641d2d1e84403f746c4fff829791", + "aed5da202d4983dac560faf6704dc76ac111616318570e244043e82ed1bbcd2b", + "aee9616db4135150818eaffa3e4503c2d7e9e834847a4c7d0a8856e952761d361a65" + "7104d36950c9b75770ded00d56a96e06f383fa2406bc935dcf51f272300e", + 42, + "d9b8be2f71b83261304e333d6e35563dc3c36c2eb5a23e1461b6e95aa7c6f381f9c3" + "bd39deaa1b6df2f9", + }, + { + "a247abbef0c1affbf021d1aff128888550532fc0edd77bc39f6ef5312317ec47", + "98ededbad1e5ad7a0d5a0cf4fcd7a794eb5c6900a65e7e921884a636f19b131d", + "f8cc02933851432f0c5df0b70f2067f740ccb72de7d6fa1e9a9b0d6de1402b9c6c52" + "5fd848e45aaaac1423b52880ec3474a2f64b38db6fc8e008d95a310e6e0c", + 47, + "4a5f07eb713932532fc3132c96efdc45862fe7a954c1d2ae4640afdf4728fb58c65e" + "8a4ebfe0d53d5797d5146442b9", + }, + { + "163d69079ddad1f16695c47d81c3b72f869b2fdd50e6e47113db6c85051a6ede", + "93fe602642ee5773f4aaf6a3bc21e98e354035225353f419e78e43c3ec36c88a", + "da747fa2cb47aae1effc1e4cfde0e39fa79937948592a712a7665bf948b8311e7f3f" + "80f966301679520d5c2afa3eadd60e061f0d264887500d8d03a17e10fd02", + 41, + "65fe5c1a0214a59644892e5ac4216f09fbb4e191b89bfb63d6540177d25ef9e37148" + "50b8453bd6b2b6", + }, + { + "7b061bf90eb760971b9ec66a96fd6609635ca4b531f33e3c126b9ae6fdb3d491", + "cb392ebb6912df4111efeeb1278160daf9da396e9291b83979a5ac479f7276d2", + "f6eebe86f7ea672e0707ee518e1798d6fbd118c11b2aa30be07d10e3882e3721f203" + "0f9f044b77c3a7a9a2f1feba7e7ce75d1f7f3807a96a764fded35d341d02", + 45, + "a17f5ce39b9ba7b7cf1147e515d6aa84b22fd0e2d8323a91367198fc6c3aff04ebb2" + "1fc2bdbe7bc0364e8040a9", + }, + { + "c9f8ccbf761cec00ab236c52651e76b5f46d90f8936d44d40561ed5c277104de", + "a3192641e343b669ffd43677c2e5cd4efaed174e876141f1d773bd6cfe30d875", + "d44f884ec9eae2e99e74194b5acc769b7aa369aaad359e92ba6ff0fe629af2a9a715" + "6c19b720e7de8c7f03c039563f160948073cab6f99b26a56a8bb1023ba08", + 47, + "3d7e33b0ecead8269966e9dcd192b73eb8a12573fc8a5fdfbe5753541026ef2e49f5" + "280cba9bc2515a049b3a1c1b49", + }, + { + "ebfa409ac6f987df476858dd35310879bf564eeb62984a52115d2e6c24590124", + "7bb1601fe7215f3f4da9c8ab5e804dc58f57ba41b03223f57ec80d9c9a2dd0e1", + "f3e7c1abfcc9f35556cb1e4c5a2b34445177ac188312d9148f1d1d8467ea8411fa3c" + "da031d023034e45bbe407ef7d1b937bfb098266138857d35cb4efe407306", + 52, + "0c37564f718eda683aa6f3e9ab2487620b1a8b5c8f20adb3b2d7550af0d635371e53" + "1f27cebe76a2abcc96de0875bdae987a45ac", + }, + { + "f993f61902b7da332f2bb001baa7accaf764d824eb0cd073315f7ec43158b8fb", + "55fc8e0da1b454cab6ddefb235311db2b01504bf9ac3f71c7e3f3d0d1f09f80b", + "178bd147673c0ca330e45da63cbd1f1811906bd5284bb44e4bb00f7d7163d1f39697" + "5610b6f71c1ae4686466fad4c5e7bb9685099e21ca4f1a45bb3fcf56ae0c", + 42, + "b7dd613bc9c364d9eeb9a52636d72bc881dfc81a836b6537bbb928bff5b738313589" + "47ea9edea1570550", + }, + { + "05188c09c31b4bb63f0d49b47ccc1654c2aba907b8c6c0a82ee403e950169167", + "e096d808dfabe8e44eb74950199dadcd586f9de6b141a0ce85ab94b3d97866eb", + "669491c8eb7cedbbc0252f3eafb048b39a2a37f60ac87837777c72c879ac8b726c39" + "e10060750c2f539102999b71889746111bc5f71ec8c158cc81cf566aef03", + 44, + "bb8e22469d1c7f1d5418563e8781f69eccb56678bd36d8919f358c2778562ff6b50d" + "e916c12d44f1a778a7f3", + }, + { + "eabe57e1a916ebbffa4ba7abc7f23e83d4deb1338816cc1784d7495d92e98d0b", + "3aad275642f48a46ed1032f3de9f4053e0fd35cf217e065d2e4579c3683932f7", + "b2e9dac2c83942ca374f29c8eff5a30c377c3db3c1c645e593e524d17484e7705b11" + "f79573e2d63495fc3ce3bf216a209f0cb7bea477ae0f8bd297f193af8805", + 44, + "3f2c2d6682ee597f2a92d7e560ac53d5623550311a4939d68adfb904045ed8d215a9" + "fdb757a2368ea4d89f5f", + }, + { + "fef7b893b4b517fab68ca12d36b603bc00826bf3c9b31a05149642ae10bb3f55", + "b3fb891868708dfa5da5b9b5234058767ab42c117f12c3228c02a1976d1c0f83", + "6243e289314b7c7587802909a9be6173a916b36f9de1e164954dfe5d1ebd57c869a7" + "9552d770e13b51855502be6b15e7be42a3675298a81284df58e609b06503", + 47, + "38c69f884045cdbeebe4478fdbd1ccc6cf00a08d8a3120c74e7167d3a2e26a67a043" + "b8e5bd198f7b0ce0358cef7cf9", + }, + { + "16228bec9b724300a37e88e535fc1c58548d34d7148b57c226f2b3af974c1822", + "3c92423a8360c9a5d9a093730d72831bec4601dcadfe84de19fc8c8f91fc3d4b", + "6aebfa9a4294ec888d54bcb517fcb6821e4c16d2708a2afe701f431a28149ff4f139" + "f9d16a52a63f1f91baf4c8dea37710c73f25c263a8035a39cc118ad0280f", + 44, + "a3d7b122cd4431b396b20d8cc46cc73ed4a5253a44a76fc83db62cdc845a2bf7081d" + "069a857955a161cccf84", + }, + { + "2dc3f5f0a0bc32c6632534e1e8f27e59cbe0bf7617d31aff98098e974c828be7", + "b998a416edc28ded988dcacb1caf2bd96c87354b0d1eeccb6980e54a3104f21f", + "76a2ddfc4bea48c47e0c82bcbfee28a37c61ec626af39a468e643e0ef9f6533056a5" + "a0b44e64d614ba3c641a40e5b003a99463445ae2c3c8e1e9882092d74b07", + 42, + "bdae276d738b9758ea3d322b54fd12fe82b767e8d817d8ef3d41f78705748e28d15e" + "9c506962a1b85901", + }, + }; + + ed25519_secret_key private_key; + ed25519_public_key public_key; + ed25519_signature signature; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + nem_private_key(tests[i].private_key, private_key); + MARK_SECRET_DATA(private_key, sizeof(private_key)); + + ed25519_publickey_keccak(private_key, public_key); + UNMARK_SECRET_DATA(public_key, sizeof(public_key)); + ck_assert_mem_eq(public_key, fromhex(tests[i].public_key), 32); + + ed25519_sign_keccak(fromhex(tests[i].data), tests[i].length, private_key, + public_key, signature); + UNMARK_SECRET_DATA(signature, sizeof(signature)); + ck_assert_mem_eq(signature, fromhex(tests[i].signature), 64); + + UNMARK_SECRET_DATA(private_key, sizeof(private_key)); + } } END_TEST START_TEST(test_ed25519_cosi) { - const int MAXN = 10; - ed25519_secret_key keys[MAXN]; - ed25519_public_key pubkeys[MAXN]; - ed25519_secret_key nonces[MAXN]; - ed25519_public_key Rs[MAXN]; - ed25519_cosi_signature sigs[MAXN]; - uint8_t msg[32]; - rfc6979_state rng; - int res; - - init_rfc6979(fromhex("26c76712d89d906e6672dafa614c42e5cb1caac8c6568e4d2493087db51f0d36"), - fromhex("26659c1cf7321c178c07437150639ff0c5b7679c7ea195253ed9abda2e081a37"), &rng); - - for (int N = 1; N < 11; N++) { - ed25519_public_key pk; - ed25519_public_key R; - ed25519_signature sig; - /* phase 0: create priv/pubkeys and combine pubkeys */ - for (int j = 0; j < N; j++) { - generate_rfc6979(keys[j], &rng); - ed25519_publickey(keys[j], pubkeys[j]); - } - res = ed25519_cosi_combine_publickeys(pk, pubkeys, N); - ck_assert_int_eq(res, 0); - - generate_rfc6979(msg, &rng); - - /* phase 1: create nonces, commitments (R values) and combine commitments */ - for (int j = 0; j < N; j++) { - generate_rfc6979(nonces[j], &rng); - ed25519_publickey(nonces[j], Rs[j]); - } - res = ed25519_cosi_combine_publickeys(R, Rs, N); - ck_assert_int_eq(res, 0); - - MARK_SECRET_DATA(keys, sizeof(keys)); - /* phase 2: sign and combine signatures */ - for (int j = 0; j < N; j++) { - ed25519_cosi_sign(msg, sizeof(msg), keys[j], nonces[j], R, pk, sigs[j]); - } - UNMARK_SECRET_DATA(sigs, sizeof(sigs)); - - ed25519_cosi_combine_signatures(sig, R, sigs, N); - - /* check signature */ - res = ed25519_sign_open(msg, sizeof(msg), pk, sig); - ck_assert_int_eq(res, 0); - - UNMARK_SECRET_DATA(keys, sizeof(keys)); - } + const int MAXN = 10; + ed25519_secret_key keys[MAXN]; + ed25519_public_key pubkeys[MAXN]; + ed25519_secret_key nonces[MAXN]; + ed25519_public_key Rs[MAXN]; + ed25519_cosi_signature sigs[MAXN]; + uint8_t msg[32]; + rfc6979_state rng; + int res; + + init_rfc6979( + fromhex( + "26c76712d89d906e6672dafa614c42e5cb1caac8c6568e4d2493087db51f0d36"), + fromhex( + "26659c1cf7321c178c07437150639ff0c5b7679c7ea195253ed9abda2e081a37"), + &rng); + + for (int N = 1; N < 11; N++) { + ed25519_public_key pk; + ed25519_public_key R; + ed25519_signature sig; + /* phase 0: create priv/pubkeys and combine pubkeys */ + for (int j = 0; j < N; j++) { + generate_rfc6979(keys[j], &rng); + ed25519_publickey(keys[j], pubkeys[j]); + } + res = ed25519_cosi_combine_publickeys(pk, pubkeys, N); + ck_assert_int_eq(res, 0); + + generate_rfc6979(msg, &rng); + + /* phase 1: create nonces, commitments (R values) and combine commitments */ + for (int j = 0; j < N; j++) { + generate_rfc6979(nonces[j], &rng); + ed25519_publickey(nonces[j], Rs[j]); + } + res = ed25519_cosi_combine_publickeys(R, Rs, N); + ck_assert_int_eq(res, 0); + + MARK_SECRET_DATA(keys, sizeof(keys)); + /* phase 2: sign and combine signatures */ + for (int j = 0; j < N; j++) { + ed25519_cosi_sign(msg, sizeof(msg), keys[j], nonces[j], R, pk, sigs[j]); + } + UNMARK_SECRET_DATA(sigs, sizeof(sigs)); + + ed25519_cosi_combine_signatures(sig, R, sigs, N); + + /* check signature */ + res = ed25519_sign_open(msg, sizeof(msg), pk, sig); + ck_assert_int_eq(res, 0); + + UNMARK_SECRET_DATA(keys, sizeof(keys)); + } } END_TEST -START_TEST(test_ed25519_modl_add) -{ - char tests[][3][65] = { - {"0000000000000000000000000000000000000000000000000000000000000000", - "0000000000000000000000000000000000000000000000000000000000000000", - "0000000000000000000000000000000000000000000000000000000000000000", - }, - - {"eef80ad5a9aad8b35b84f6a4eb3a7e2b222f403d455d8cdf40ad27e4cd5ae90a", - "0000000000000000000000000000000000000000000000000000000000000000", - "eef80ad5a9aad8b35b84f6a4eb3a7e2b222f403d455d8cdf40ad27e4cd5ae90a" - }, - - {"0000000000000000000000000000000000000000000000000000000000000000", - "eef80ad5a9aad8b35b84f6a4eb3a7e2b222f403d455d8cdf40ad27e4cd5ae90a", - "eef80ad5a9aad8b35b84f6a4eb3a7e2b222f403d455d8cdf40ad27e4cd5ae90a" - }, - - {"0100000000000000000000000000000000000000000000000000000000000000", - "0200000000000000000000000000000000000000000000000000000000000000", - "0300000000000000000000000000000000000000000000000000000000000000" - }, - - {"e3d3f55c1a631258d69cf7a2def9de1400000000000000000000000000000010", - "0a00000000000000000000000000000000000000000000000000000000000000", - "0000000000000000000000000000000000000000000000000000000000000000" - }, - - {"f7bb3bf42b3e58e2edd06f173fc7bfbc7aaf657217946b75648447101136aa08", - "3c16b013109cc27ff39805be2abe04ba4cd6a8526a1d3023047693e950936c06", - "33d2eb073cda1a62e16975d56985c476c7850ec581b19b9868fadaf961c9160f" - }, - }; - - unsigned char buff[32]; - bignum256modm a={0}, b={0}, c={0}; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - expand256_modm(a, fromhex(tests[i][0]), 32); - expand256_modm(b, fromhex(tests[i][1]), 32); - add256_modm(c, a, b); - contract256_modm(buff, c); - ck_assert_mem_eq(buff, fromhex(tests[i][2]), 32); - } +START_TEST(test_ed25519_modl_add) { + char tests[][3][65] = { + { + "0000000000000000000000000000000000000000000000000000000000000000", + "0000000000000000000000000000000000000000000000000000000000000000", + "0000000000000000000000000000000000000000000000000000000000000000", + }, + + {"eef80ad5a9aad8b35b84f6a4eb3a7e2b222f403d455d8cdf40ad27e4cd5ae90a", + "0000000000000000000000000000000000000000000000000000000000000000", + "eef80ad5a9aad8b35b84f6a4eb3a7e2b222f403d455d8cdf40ad27e4cd5ae90a"}, + + {"0000000000000000000000000000000000000000000000000000000000000000", + "eef80ad5a9aad8b35b84f6a4eb3a7e2b222f403d455d8cdf40ad27e4cd5ae90a", + "eef80ad5a9aad8b35b84f6a4eb3a7e2b222f403d455d8cdf40ad27e4cd5ae90a"}, + + {"0100000000000000000000000000000000000000000000000000000000000000", + "0200000000000000000000000000000000000000000000000000000000000000", + "0300000000000000000000000000000000000000000000000000000000000000"}, + + {"e3d3f55c1a631258d69cf7a2def9de1400000000000000000000000000000010", + "0a00000000000000000000000000000000000000000000000000000000000000", + "0000000000000000000000000000000000000000000000000000000000000000"}, + + {"f7bb3bf42b3e58e2edd06f173fc7bfbc7aaf657217946b75648447101136aa08", + "3c16b013109cc27ff39805be2abe04ba4cd6a8526a1d3023047693e950936c06", + "33d2eb073cda1a62e16975d56985c476c7850ec581b19b9868fadaf961c9160f"}, + }; + + unsigned char buff[32]; + bignum256modm a = {0}, b = {0}, c = {0}; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + expand256_modm(a, fromhex(tests[i][0]), 32); + expand256_modm(b, fromhex(tests[i][1]), 32); + add256_modm(c, a, b); + contract256_modm(buff, c); + ck_assert_mem_eq(buff, fromhex(tests[i][2]), 32); + } } END_TEST -START_TEST(test_ed25519_modl_neg) -{ - char tests[][2][65] = { - {"05d0f55c1a631258d69cf7a2def9de1400000000000000000000000000000010", - "e803000000000000000000000000000000000000000000000000000000000000"}, +START_TEST(test_ed25519_modl_neg) { + char tests[][2][65] = { + {"05d0f55c1a631258d69cf7a2def9de1400000000000000000000000000000010", + "e803000000000000000000000000000000000000000000000000000000000000"}, - {"4d4df45c1a631258d69cf7a2def9de1400000000000000000000000000000010", - "a086010000000000000000000000000000000000000000000000000000000000"}, + {"4d4df45c1a631258d69cf7a2def9de1400000000000000000000000000000010", + "a086010000000000000000000000000000000000000000000000000000000000"}, - {"25958944a1b7d4073975ca48996a1d740d0ed98ceec366760c5358da681e9608", - "c83e6c1879ab3d509d272d5a458fc1a0f2f12673113c9989f3aca72597e16907"}, + {"25958944a1b7d4073975ca48996a1d740d0ed98ceec366760c5358da681e9608", + "c83e6c1879ab3d509d272d5a458fc1a0f2f12673113c9989f3aca72597e16907"}, - {"0100000000000000000000000000000000000000000000000000000000000000", - "ecd3f55c1a631258d69cf7a2def9de1400000000000000000000000000000010"}, + {"0100000000000000000000000000000000000000000000000000000000000000", + "ecd3f55c1a631258d69cf7a2def9de1400000000000000000000000000000010"}, - {"ecd3f55c1a631258d69cf7a2def9de1400000000000000000000000000000010", - "0100000000000000000000000000000000000000000000000000000000000000"}, + {"ecd3f55c1a631258d69cf7a2def9de1400000000000000000000000000000010", + "0100000000000000000000000000000000000000000000000000000000000000"}, - {"0000000000000000000000000000000000000000000000000000000000000000", - "0000000000000000000000000000000000000000000000000000000000000000"}, - }; + {"0000000000000000000000000000000000000000000000000000000000000000", + "0000000000000000000000000000000000000000000000000000000000000000"}, + }; - unsigned char buff[32]; - bignum256modm a={0}, b={0}; + unsigned char buff[32]; + bignum256modm a = {0}, b = {0}; - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - expand256_modm(a, fromhex(tests[i][0]), 32); - neg256_modm(b, a); - contract256_modm((unsigned char *) buff, b); - ck_assert_mem_eq(buff, fromhex(tests[i][1]), 32); - } + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + expand256_modm(a, fromhex(tests[i][0]), 32); + neg256_modm(b, a); + contract256_modm((unsigned char *)buff, b); + ck_assert_mem_eq(buff, fromhex(tests[i][1]), 32); + } } END_TEST -START_TEST(test_ed25519_modl_sub) -{ - char tests[][3][65] = { - {"0000000000000000000000000000000000000000000000000000000000000000", - "0000000000000000000000000000000000000000000000000000000000000000", - "0000000000000000000000000000000000000000000000000000000000000000", - }, - - {"eef80ad5a9aad8b35b84f6a4eb3a7e2b222f403d455d8cdf40ad27e4cd5ae90a", - "53732f60e51ee3a48d21d2d526548c0dadbb79a185678fd7710613d0e76aad0c", - "8859d1d1deee0767a4ff1b72a3e0d0327573c69bbff5fc07cfa61414e6ef3b0e" - }, - - {"9d91e26dbe7a14fdca9f5b20d13e828dc8c1ffe03fe90136a6bba507436ce500", - "9ca406705ccce65eb8cbf63706d3df09fcc67216c0dc3990270731aacbb2e607", - "eec0d15a7c1140f6e8705c8ba9658198ccfa8cca7f0cc8a57eb4745d77b9fe08" - }, - - {"eef80ad5a9aad8b35b84f6a4eb3a7e2b222f403d455d8cdf40ad27e4cd5ae90a", - "0000000000000000000000000000000000000000000000000000000000000000", - "eef80ad5a9aad8b35b84f6a4eb3a7e2b222f403d455d8cdf40ad27e4cd5ae90a" - }, - - {"0000000000000000000000000000000000000000000000000000000000000000", - "39897fbebf137a34572b014b0638ac0186d17874e3cc142ebdfe24327f5b8509", - "b44a769e5a4f98237f71f657d8c132137a2e878b1c33ebd14201dbcd80a47a06" - }, - - {"0200000000000000000000000000000000000000000000000000000000000000", - "e3d3f55c1a631258d69cf7a2def9de1400000000000000000000000000000010", - "0c00000000000000000000000000000000000000000000000000000000000000" - }, - - {"e3d3f55c1a631258d69cf7a2def9de1400000000000000000000000000000010", - "0800000000000000000000000000000000000000000000000000000000000000", - "dbd3f55c1a631258d69cf7a2def9de1400000000000000000000000000000010" - }, - - {"ecd3f55c1a631258d69cf7a2def9de1400000000000000000000000000000010", - "0000000000000000000000000000000000000000000000000000000000000000", - "ecd3f55c1a631258d69cf7a2def9de1400000000000000000000000000000010" - }, - - {"0000000000000000000000000000000000000000000000000000000000000000", - "ecd3f55c1a631258d69cf7a2def9de1400000000000000000000000000000010", - "0100000000000000000000000000000000000000000000000000000000000000" - }, - - {"0000000000000000000000000000000000000000000000000000000000000000", - "0000000000000000000000000000000000000000000000000000000000000010", - "edd3f55c1a631258d69cf7a2def9de1400000000000000000000000000000000" - }, - - {"0000000000000000000000000000000000000000000000000000000000000000", - "ffffff3f00000000000000000000000000000000000000000000000000000010", - "eed3f51c1a631258d69cf7a2def9de1400000000000000000000000000000000" - }, - - {"0000000000000000000000000000000000000000000000000000000000000000", - "edd3f55c1a631258d69cf7a2def9de1400000000000000000000000000000000", - "0000000000000000000000000000000000000000000000000000000000000010" - }, - - {"0000000000000000000000000000000000000000000000000000000000000000", - "e75f947f11d49d25a137fac8757538a980dec23811235cf63c48ee6bc6e4ed03", - "067461dd088f74323565fdd96884a66b7f213dc7eedca309c3b71194391b120c" - }, - - {"0000000000000000000000000000000000000000000000000000000000000000", - "ecd3f55c1a631258d69cf7a2def9de140000000000000000000000000000ff0f", - "0100000000000000000000000000000000000000000000000000000000000100" - }, - - {"0000000000000000000000000000000000000000000000000000000000000000", - "edd3f55c1a631258d69cf7a2def9de140000000000000000000004000000ff0f", - "0000000000000000000000000000000000000000000000000000fcffffff0000" - }, - - {"0000000000000000000000000000000000000000000000000000000000000000", - "edd3f55c1a631258d69cf7a2def9de150000c0ffffffffffffffffffffffff0f", - "000000000000000000000000000000ffffff3f00000000000000000000000000" - }, - - {"0000000000000000000000000000000000000000000000000000000000000000", - "edd3f55c1a631258d69cf7a2def9de1200000000000000000000000000000110", - "edd3f55c1a631258d69cf7a2def9de160000000000000000000000000000ff0f" - }, - - {"0000000000000000000000000000000000000000000000000000000000000000", - "edd3f55c1a631258d69cf7a2def9de1300000000000000000000000000000010", - "0000000000000000000000000000000100000000000000000000000000000000" - }, - }; - - unsigned char buff[32]; - bignum256modm a={0}, b={0}, c={0}; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - expand256_modm(a, fromhex(tests[i][0]), 32); - expand256_modm(b, fromhex(tests[i][1]), 32); - sub256_modm(c, a, b); - contract256_modm(buff, c); - ck_assert_mem_eq(buff, fromhex(tests[i][2]), 32); - } +START_TEST(test_ed25519_modl_sub) { + char tests[][3][65] = { + { + "0000000000000000000000000000000000000000000000000000000000000000", + "0000000000000000000000000000000000000000000000000000000000000000", + "0000000000000000000000000000000000000000000000000000000000000000", + }, + + {"eef80ad5a9aad8b35b84f6a4eb3a7e2b222f403d455d8cdf40ad27e4cd5ae90a", + "53732f60e51ee3a48d21d2d526548c0dadbb79a185678fd7710613d0e76aad0c", + "8859d1d1deee0767a4ff1b72a3e0d0327573c69bbff5fc07cfa61414e6ef3b0e"}, + + {"9d91e26dbe7a14fdca9f5b20d13e828dc8c1ffe03fe90136a6bba507436ce500", + "9ca406705ccce65eb8cbf63706d3df09fcc67216c0dc3990270731aacbb2e607", + "eec0d15a7c1140f6e8705c8ba9658198ccfa8cca7f0cc8a57eb4745d77b9fe08"}, + + {"eef80ad5a9aad8b35b84f6a4eb3a7e2b222f403d455d8cdf40ad27e4cd5ae90a", + "0000000000000000000000000000000000000000000000000000000000000000", + "eef80ad5a9aad8b35b84f6a4eb3a7e2b222f403d455d8cdf40ad27e4cd5ae90a"}, + + {"0000000000000000000000000000000000000000000000000000000000000000", + "39897fbebf137a34572b014b0638ac0186d17874e3cc142ebdfe24327f5b8509", + "b44a769e5a4f98237f71f657d8c132137a2e878b1c33ebd14201dbcd80a47a06"}, + + {"0200000000000000000000000000000000000000000000000000000000000000", + "e3d3f55c1a631258d69cf7a2def9de1400000000000000000000000000000010", + "0c00000000000000000000000000000000000000000000000000000000000000"}, + + {"e3d3f55c1a631258d69cf7a2def9de1400000000000000000000000000000010", + "0800000000000000000000000000000000000000000000000000000000000000", + "dbd3f55c1a631258d69cf7a2def9de1400000000000000000000000000000010"}, + + {"ecd3f55c1a631258d69cf7a2def9de1400000000000000000000000000000010", + "0000000000000000000000000000000000000000000000000000000000000000", + "ecd3f55c1a631258d69cf7a2def9de1400000000000000000000000000000010"}, + + {"0000000000000000000000000000000000000000000000000000000000000000", + "ecd3f55c1a631258d69cf7a2def9de1400000000000000000000000000000010", + "0100000000000000000000000000000000000000000000000000000000000000"}, + + {"0000000000000000000000000000000000000000000000000000000000000000", + "0000000000000000000000000000000000000000000000000000000000000010", + "edd3f55c1a631258d69cf7a2def9de1400000000000000000000000000000000"}, + + {"0000000000000000000000000000000000000000000000000000000000000000", + "ffffff3f00000000000000000000000000000000000000000000000000000010", + "eed3f51c1a631258d69cf7a2def9de1400000000000000000000000000000000"}, + + {"0000000000000000000000000000000000000000000000000000000000000000", + "edd3f55c1a631258d69cf7a2def9de1400000000000000000000000000000000", + "0000000000000000000000000000000000000000000000000000000000000010"}, + + {"0000000000000000000000000000000000000000000000000000000000000000", + "e75f947f11d49d25a137fac8757538a980dec23811235cf63c48ee6bc6e4ed03", + "067461dd088f74323565fdd96884a66b7f213dc7eedca309c3b71194391b120c"}, + + {"0000000000000000000000000000000000000000000000000000000000000000", + "ecd3f55c1a631258d69cf7a2def9de140000000000000000000000000000ff0f", + "0100000000000000000000000000000000000000000000000000000000000100"}, + + {"0000000000000000000000000000000000000000000000000000000000000000", + "edd3f55c1a631258d69cf7a2def9de140000000000000000000004000000ff0f", + "0000000000000000000000000000000000000000000000000000fcffffff0000"}, + + {"0000000000000000000000000000000000000000000000000000000000000000", + "edd3f55c1a631258d69cf7a2def9de150000c0ffffffffffffffffffffffff0f", + "000000000000000000000000000000ffffff3f00000000000000000000000000"}, + + {"0000000000000000000000000000000000000000000000000000000000000000", + "edd3f55c1a631258d69cf7a2def9de1200000000000000000000000000000110", + "edd3f55c1a631258d69cf7a2def9de160000000000000000000000000000ff0f"}, + + {"0000000000000000000000000000000000000000000000000000000000000000", + "edd3f55c1a631258d69cf7a2def9de1300000000000000000000000000000010", + "0000000000000000000000000000000100000000000000000000000000000000"}, + }; + + unsigned char buff[32]; + bignum256modm a = {0}, b = {0}, c = {0}; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + expand256_modm(a, fromhex(tests[i][0]), 32); + expand256_modm(b, fromhex(tests[i][1]), 32); + sub256_modm(c, a, b); + contract256_modm(buff, c); + ck_assert_mem_eq(buff, fromhex(tests[i][2]), 32); + } } END_TEST -START_TEST(test_ge25519_double_scalarmult_vartime2) -{ - char tests[][5][65] = { - {"c537208ed4985e66e9f7a35c9a69448a732ba93960bbbd2823604f7ae9e3ed08", "365233e5af17c8888d5ce508787464f4642e91a6212b1b104e6c3769535601b1", "a84f871580176708b4ac21843cb197ad96e8456034442b50859c83c5807b9901", "f022360d1bce903fa3ac58ae42f997328b31f477b8d576a9f6d26fc1d08f14ea", "bf25da82c6b210948b823ae48422a2dcd205d3c94842e68ac27e5cbeaa704ebc"}, - {"4abfabc0dda33588a98127ef3bfe724fed286395fe15932e898b5621661ea102", "e5fd79d03f5df8edfc8def663dcb96bba6cadf857f2ae6f6f51f52f8d14079b7", "4754c286b23e3c1b50054fe3937ebdc4ec01b28da5d05fb6111798b42fc5bf06", "b7e7f9464b98de5bfcf6b02c1b7053cc359df407ad59d943523c6d2ee773b2f6", "6d7d5f729bfa4882dbff8e477cd2b4c354ba347f10e7b178a24f3f16a4e0fec6"}, - {"19f2af4d04cb8181f1fe0d01fe9bb9ecc476c67ceb4a9830dae1bc7fe5fe3b04", "d3c462f4f30991220387a1fbbd1ba1dc45ce058c70a8fb1475071e7b4f0fc463", "577790e025c1fd2014db44a8d613c4e2ab1f248a4a6d14b5d39cbbafd7b20f06", "1376c6837f131f6cd1a45b1056297d2314aa0ac5f7d581d2d878261eb3259b4d", "ce790760ada87dd819b59e4f6765d836d346567ec34f02bbcfcae0585c1d758f"}, - {"cf209db9e7ee85f1e648924ec97edd86b56a833b25707519d4fbe64fd50e150a", "804f0806087dc665a26230ed5fd44c062980ee182a6bd7dbdb33df018c983778", "30d3c448cb08935309753b3051366f52328ca1d9a0b63c72b989edee0da32b0e", "98e3c973a7e85b5eab8111521c66ca584bed5597f060ab0c6b5cdeece502ac48", "2646276e1305396a1b2473690066011a39789570a09e10ce1a013c8f32cd5bea"}, - {"b0a0ffeea67b656c4c585ba58ff528a6f45d2f915db98e4a14a8ff17f27fc105", "4fabe16274f6af526ee053028485db6acd13804e02dcdddccc4183a319ab9e1c", "1e140bb08a936ac6b7437644ca0769f3c165c7aa5501d49f064a0346179b4008", "68fc1be64fb68761542a655b8dbebf50980f1fbc1845528df8d8a06bf89a1495", "7dab86994b47014efe38493fc2b62ffcead806da6e0d73c992db8cb5618a19dc"}, - {"0fee422c2294b06ca83bc3704384dffc580e7ff5921881e51a755e5f9b80af03", "4359a663ead3f7ffc3a0ead5c3c2bde348017e7bfa620f21759c32e469a16dfe", "532066e3eec29334fffc37b17178dfbac3bee15f7845f01449ddbaf5e57a7b0c", "32e46c2fb99402837631c8175db31cdd334c145f922be9070d62e6d9c493c3ea", "8c7b7d2d61cdb648960434d894787426a76d16dd46949c7aa4b85dcf1054b4d5"}, - {"3a712d5b7ceb5257dcf6e6bb06548de6ef3deba5d456cd91fc305a12b46b5d01", "5e7da62e3ec42cf3e554639dd4d2006754ee6839b720cadba94a26b73b1665ee", "2a518ecab17a2d9dde219c775bcf4f2306b190bef2dea34fb65b8e4dccc13405", "3b5d66a4dfb068923b3bc21cc8b40b59e12f845e0b85a86d394db0fa310bf185", "2ec17f1cc0be093e9cdb741a991c0f417230dea275cd7babdad35e949e250521"}, - {"5f815f2d65cef584c5e5d48b2d3d3e4cae310d70b328f88af6e9f63c52b4c90d", "8a539a8c6b2339922b31cf4bc064f1fedeb3912fd89585d79dfcff2a60aee295", "385f7132b72db04146b9e472736b32adfca29556b4775a743c18e2bfab939007", "884aaf96d625968ddb2582922a87abca131272884c47f6b86890ebccf0a79d5b", "a7afdaf24fe8472d8b89e95c3ce4a40bdf700af7cedee44ed3aa5ccca09839bd"}, - {"a043340d072df16a8ab5135f8c1d601bff14c5aba01b9212b886ad71fe164506", "52f6de5fa0fae32d4020a54d395319509d6b92092a0bf849fb34e73f8e71fc99", "37d7472d360164da29e6dcb8f9796976022571c5df4ddf7e30e9a579ba13d509", "8c369e3fd5b1112e4437b1f09e987acca4966f2f8c5227eb15ace240a2c64cc7", "fc795fe7baff5c3ac98366e6882f25874ea2b0a649d16f139e5c54ea47042a1e"}, - {"97a3268db03fa184c8cba020bf216fc789292fa9615a28962385b86870ffd70f", "a76c215587022bb9252ece4c5afeb0e65b820834cd41ac76e6c062d3eea75dc6", "8310271017154cbddf7005e24eb9a9a86777b3f42fa5e35095eafaac4eb24802", "b822665c2406083c851ecaa91ea67aa740c057e7679b5755cee60a6c63f17fd6", "f83e2444527056eba595d49bde40b2e8da76d2c145f203331d26e94560993fbc"}, - {"edaad13efad39f26298e86ba8d06a46e59122232c9529bd22f2f656595421e00", "f38e56a79f5159eb3b581dea537ec12c9c6fac381b2cf6073e27fc621197cb62", "1eea79485954b5958d9d5478f86133af1088806d923535d483b115ab23099a0f", "b32c5e57d57db7a349f4ab845f12a5045c52b4a7a5bce7fd54a1a255b0118185", "3bfb42b4ffd2c6cfc8cce9e4187dc6fbcaecd9d44a4ca1d2b68b97410bb25b81"}, - {"b15eaebe0fc83cb11d755a6f067b710204d4a59101078d8286454b652879080a", "4667a2e61d9df1690f5c33c4168e480f7e26d2f0998168ebdc0a39712946f741", "125379da1a88bfdf5b928f8795d3ea5415ef8c3d9106eb16934c3842873fd707", "8727a692a25e38b1afa98e3dd5bf88815dec6d9810c1fd8a31b56b3de8630f1e", "540883dde400b909e9955a276c20e13d99252ebe542750b8bfbbe5c3b87c51e3"}, - {"e42bdd4af3121bea644a90a76b2007615621ee5b842b9a74c4334ac309478706", "6dc4ab715d3bb975ebfd0f08e2b6f3f39922d0121ae518a8f8d2952ea2fe0b5d", "0285059b0095c97f4a50d43c7726c64c2830bf2b55dfa934ebba7ad71064dc07", "f738c0a3cee31fd8f438f282aa6c823fccfa49cf7b5c86fbf9d56bf0394b6d8d", "a1bd106841e55010decd95a170a1d0dd11780fd00759819e024b15ea3a83b4be"}, - {"5077c30fd08795dbdc7a230c050ca07e316fa3b040fd0dac45907036ab25dd0e", "96f0897f000e49e2439a9166cab40ebc125a31b82851f0541516c19683e7bfaf", "2b67d79a2efdc6451508e7f3c97c4a61b135bb839c02338bb444ef8208dd970b", "7ef4cd7cdc29c2b88ccff49898b5d0b7be5993f93c5772476feec9dc57d7b6e3", "62449b901b25760c964704b28efc184fbd5947e83851ebaf3bbfeb6f742f679f"}, - {"a4b3ce6928fe8f77d13e65ae255eee8310ab0d75bca47028b4570f0511a66006", "4e9da8d77ee337e3bcce3730ccfff2121728641c7bb4fdeb2155890f998af09a", "ff01a5075569d0f6afee45da065c72f5841f46ce772917ef75eb4d230473580f", "36ca32da8a10f4083f5a60ee21868d9d448548d49c56f19cbe6005005e34f816", "99df362a3b762cc1cbb70bc5ddff3c8614ed306037013102e387ef32e7f2494f"}, - {"074aa76351dceb752aa09887d9aca932d5821f58eedb4988fd64d8548e3f2c09", "588b4552f3b98b2f77aee2ef8cc72f88acd424c4373b3e3626393ed2ea24cbda", "f2d9175633f2e3c661b01172b4b4176850cd5b3098ffb0f927e0a5e19c1c8a02", "a6c34868736b2517fd46f57a4e30805ffd475e44a8b1413078f43d9cb3d6edd6", "46e1e7d7b1e939dd5c07c8363af01f4f9dae7c3d10f237ff9776ddc4a1903771"}, - {"ae1c8abd5a542208ee0aa93ffbf0b8e5a957edc4854fe2b48153c5c85bbf3d08", "5e084b9541a70bd5bef400be6525c5a806a5b7fb12de38b07dcd35a22c57edbe", "d95f179a215fb322d81720bf3aecde78d6d676d6f941455d0e0920f1e3619707", "c3e5d43221824de51d8f95705de69c80a2440c0483ca88549d639aee15390429", "df9fea42d3b5ac243244abb4ca4948a69493becddc5d5906f9a4e4c5645b0eab"}, - {"2f1c5adedb7341dc7638bafacc6024bd48255197ea2347fc05714b9341dd4403", "47f55263001542f796c928988f641f59d0cd43294fc8d8616b184bfe9dddf368", "aa5e884e782ab116151c609680c37b1a49b52f23bce5e2ebf28dd8532510d20b", "ef2d6d97ad1a18edfce6450c1e70295b2c7ed2bc749ea8b438a523eae078d1f3", "2396a355c6ae8e2ac24da8f55a674c96fc4cc69b38678b2bd8eb91b96f462bca"}, - {"0242e14105ced74e91cf4d4dcd22a9c09279018901d2fb8319eb54c2a1c4900a", "fcb62a6c520d31fa46efeb4a1000330653b3402f575c2ddc0c688f527e7b97be", "73a7e2e0602e5345f040dedc4db67f6d8e37c5fca3bbb124fa43963d76dbbb08", "152bf4a3305c656f77e292b1256cc470da4d3f6efc3667199db4316d7f431174", "c21ba2080013dfb225e06378d9ac27df623df552526cfddbf9e71bb1d4705dd9"}, - {"07fab4fc7b02fbcf868ffb0326cf60425fef2af1fbad83a8926cc62c2b5dff05", "29ff12c5e052eb5829e8334e0e082c5edde1f293d2b4ed499a79bcca20e48010", "97afb3dd9167877b432a23503aad1ab39188b9be07cc124ceb3fbdbd8d8b890a", "ed121240a2f4591eeedbfd880305ccd17e522673900b03279fb66e73583514ae", "b27f209e88ce5701766565e231e8123adb1df9c9f1dc461920acbc2b38d9f6d7"}, - }; - - unsigned char buff[32]; - bignum256modm a={0}, b={0}; - ge25519 A, B, R; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - expand256_modm(a, fromhex(tests[i][0]), 32); - expand256_modm(b, fromhex(tests[i][2]), 32); - ge25519_unpack_negative_vartime(&A, fromhex(tests[i][1])); curve25519_neg(A.x, A.x); curve25519_neg(A.t, A.t); - ge25519_unpack_negative_vartime(&B, fromhex(tests[i][3])); curve25519_neg(B.x, B.x); curve25519_neg(B.t, B.t); - ge25519_double_scalarmult_vartime2(&R, &A, a, &B, b); - ge25519_pack(buff, &R); - ck_assert_mem_eq(buff, fromhex(tests[i][4]), 32); - } +START_TEST(test_ge25519_double_scalarmult_vartime2) { + char tests[][5][65] = { + {"c537208ed4985e66e9f7a35c9a69448a732ba93960bbbd2823604f7ae9e3ed08", + "365233e5af17c8888d5ce508787464f4642e91a6212b1b104e6c3769535601b1", + "a84f871580176708b4ac21843cb197ad96e8456034442b50859c83c5807b9901", + "f022360d1bce903fa3ac58ae42f997328b31f477b8d576a9f6d26fc1d08f14ea", + "bf25da82c6b210948b823ae48422a2dcd205d3c94842e68ac27e5cbeaa704ebc"}, + {"4abfabc0dda33588a98127ef3bfe724fed286395fe15932e898b5621661ea102", + "e5fd79d03f5df8edfc8def663dcb96bba6cadf857f2ae6f6f51f52f8d14079b7", + "4754c286b23e3c1b50054fe3937ebdc4ec01b28da5d05fb6111798b42fc5bf06", + "b7e7f9464b98de5bfcf6b02c1b7053cc359df407ad59d943523c6d2ee773b2f6", + "6d7d5f729bfa4882dbff8e477cd2b4c354ba347f10e7b178a24f3f16a4e0fec6"}, + {"19f2af4d04cb8181f1fe0d01fe9bb9ecc476c67ceb4a9830dae1bc7fe5fe3b04", + "d3c462f4f30991220387a1fbbd1ba1dc45ce058c70a8fb1475071e7b4f0fc463", + "577790e025c1fd2014db44a8d613c4e2ab1f248a4a6d14b5d39cbbafd7b20f06", + "1376c6837f131f6cd1a45b1056297d2314aa0ac5f7d581d2d878261eb3259b4d", + "ce790760ada87dd819b59e4f6765d836d346567ec34f02bbcfcae0585c1d758f"}, + {"cf209db9e7ee85f1e648924ec97edd86b56a833b25707519d4fbe64fd50e150a", + "804f0806087dc665a26230ed5fd44c062980ee182a6bd7dbdb33df018c983778", + "30d3c448cb08935309753b3051366f52328ca1d9a0b63c72b989edee0da32b0e", + "98e3c973a7e85b5eab8111521c66ca584bed5597f060ab0c6b5cdeece502ac48", + "2646276e1305396a1b2473690066011a39789570a09e10ce1a013c8f32cd5bea"}, + {"b0a0ffeea67b656c4c585ba58ff528a6f45d2f915db98e4a14a8ff17f27fc105", + "4fabe16274f6af526ee053028485db6acd13804e02dcdddccc4183a319ab9e1c", + "1e140bb08a936ac6b7437644ca0769f3c165c7aa5501d49f064a0346179b4008", + "68fc1be64fb68761542a655b8dbebf50980f1fbc1845528df8d8a06bf89a1495", + "7dab86994b47014efe38493fc2b62ffcead806da6e0d73c992db8cb5618a19dc"}, + {"0fee422c2294b06ca83bc3704384dffc580e7ff5921881e51a755e5f9b80af03", + "4359a663ead3f7ffc3a0ead5c3c2bde348017e7bfa620f21759c32e469a16dfe", + "532066e3eec29334fffc37b17178dfbac3bee15f7845f01449ddbaf5e57a7b0c", + "32e46c2fb99402837631c8175db31cdd334c145f922be9070d62e6d9c493c3ea", + "8c7b7d2d61cdb648960434d894787426a76d16dd46949c7aa4b85dcf1054b4d5"}, + {"3a712d5b7ceb5257dcf6e6bb06548de6ef3deba5d456cd91fc305a12b46b5d01", + "5e7da62e3ec42cf3e554639dd4d2006754ee6839b720cadba94a26b73b1665ee", + "2a518ecab17a2d9dde219c775bcf4f2306b190bef2dea34fb65b8e4dccc13405", + "3b5d66a4dfb068923b3bc21cc8b40b59e12f845e0b85a86d394db0fa310bf185", + "2ec17f1cc0be093e9cdb741a991c0f417230dea275cd7babdad35e949e250521"}, + {"5f815f2d65cef584c5e5d48b2d3d3e4cae310d70b328f88af6e9f63c52b4c90d", + "8a539a8c6b2339922b31cf4bc064f1fedeb3912fd89585d79dfcff2a60aee295", + "385f7132b72db04146b9e472736b32adfca29556b4775a743c18e2bfab939007", + "884aaf96d625968ddb2582922a87abca131272884c47f6b86890ebccf0a79d5b", + "a7afdaf24fe8472d8b89e95c3ce4a40bdf700af7cedee44ed3aa5ccca09839bd"}, + {"a043340d072df16a8ab5135f8c1d601bff14c5aba01b9212b886ad71fe164506", + "52f6de5fa0fae32d4020a54d395319509d6b92092a0bf849fb34e73f8e71fc99", + "37d7472d360164da29e6dcb8f9796976022571c5df4ddf7e30e9a579ba13d509", + "8c369e3fd5b1112e4437b1f09e987acca4966f2f8c5227eb15ace240a2c64cc7", + "fc795fe7baff5c3ac98366e6882f25874ea2b0a649d16f139e5c54ea47042a1e"}, + {"97a3268db03fa184c8cba020bf216fc789292fa9615a28962385b86870ffd70f", + "a76c215587022bb9252ece4c5afeb0e65b820834cd41ac76e6c062d3eea75dc6", + "8310271017154cbddf7005e24eb9a9a86777b3f42fa5e35095eafaac4eb24802", + "b822665c2406083c851ecaa91ea67aa740c057e7679b5755cee60a6c63f17fd6", + "f83e2444527056eba595d49bde40b2e8da76d2c145f203331d26e94560993fbc"}, + {"edaad13efad39f26298e86ba8d06a46e59122232c9529bd22f2f656595421e00", + "f38e56a79f5159eb3b581dea537ec12c9c6fac381b2cf6073e27fc621197cb62", + "1eea79485954b5958d9d5478f86133af1088806d923535d483b115ab23099a0f", + "b32c5e57d57db7a349f4ab845f12a5045c52b4a7a5bce7fd54a1a255b0118185", + "3bfb42b4ffd2c6cfc8cce9e4187dc6fbcaecd9d44a4ca1d2b68b97410bb25b81"}, + {"b15eaebe0fc83cb11d755a6f067b710204d4a59101078d8286454b652879080a", + "4667a2e61d9df1690f5c33c4168e480f7e26d2f0998168ebdc0a39712946f741", + "125379da1a88bfdf5b928f8795d3ea5415ef8c3d9106eb16934c3842873fd707", + "8727a692a25e38b1afa98e3dd5bf88815dec6d9810c1fd8a31b56b3de8630f1e", + "540883dde400b909e9955a276c20e13d99252ebe542750b8bfbbe5c3b87c51e3"}, + {"e42bdd4af3121bea644a90a76b2007615621ee5b842b9a74c4334ac309478706", + "6dc4ab715d3bb975ebfd0f08e2b6f3f39922d0121ae518a8f8d2952ea2fe0b5d", + "0285059b0095c97f4a50d43c7726c64c2830bf2b55dfa934ebba7ad71064dc07", + "f738c0a3cee31fd8f438f282aa6c823fccfa49cf7b5c86fbf9d56bf0394b6d8d", + "a1bd106841e55010decd95a170a1d0dd11780fd00759819e024b15ea3a83b4be"}, + {"5077c30fd08795dbdc7a230c050ca07e316fa3b040fd0dac45907036ab25dd0e", + "96f0897f000e49e2439a9166cab40ebc125a31b82851f0541516c19683e7bfaf", + "2b67d79a2efdc6451508e7f3c97c4a61b135bb839c02338bb444ef8208dd970b", + "7ef4cd7cdc29c2b88ccff49898b5d0b7be5993f93c5772476feec9dc57d7b6e3", + "62449b901b25760c964704b28efc184fbd5947e83851ebaf3bbfeb6f742f679f"}, + {"a4b3ce6928fe8f77d13e65ae255eee8310ab0d75bca47028b4570f0511a66006", + "4e9da8d77ee337e3bcce3730ccfff2121728641c7bb4fdeb2155890f998af09a", + "ff01a5075569d0f6afee45da065c72f5841f46ce772917ef75eb4d230473580f", + "36ca32da8a10f4083f5a60ee21868d9d448548d49c56f19cbe6005005e34f816", + "99df362a3b762cc1cbb70bc5ddff3c8614ed306037013102e387ef32e7f2494f"}, + {"074aa76351dceb752aa09887d9aca932d5821f58eedb4988fd64d8548e3f2c09", + "588b4552f3b98b2f77aee2ef8cc72f88acd424c4373b3e3626393ed2ea24cbda", + "f2d9175633f2e3c661b01172b4b4176850cd5b3098ffb0f927e0a5e19c1c8a02", + "a6c34868736b2517fd46f57a4e30805ffd475e44a8b1413078f43d9cb3d6edd6", + "46e1e7d7b1e939dd5c07c8363af01f4f9dae7c3d10f237ff9776ddc4a1903771"}, + {"ae1c8abd5a542208ee0aa93ffbf0b8e5a957edc4854fe2b48153c5c85bbf3d08", + "5e084b9541a70bd5bef400be6525c5a806a5b7fb12de38b07dcd35a22c57edbe", + "d95f179a215fb322d81720bf3aecde78d6d676d6f941455d0e0920f1e3619707", + "c3e5d43221824de51d8f95705de69c80a2440c0483ca88549d639aee15390429", + "df9fea42d3b5ac243244abb4ca4948a69493becddc5d5906f9a4e4c5645b0eab"}, + {"2f1c5adedb7341dc7638bafacc6024bd48255197ea2347fc05714b9341dd4403", + "47f55263001542f796c928988f641f59d0cd43294fc8d8616b184bfe9dddf368", + "aa5e884e782ab116151c609680c37b1a49b52f23bce5e2ebf28dd8532510d20b", + "ef2d6d97ad1a18edfce6450c1e70295b2c7ed2bc749ea8b438a523eae078d1f3", + "2396a355c6ae8e2ac24da8f55a674c96fc4cc69b38678b2bd8eb91b96f462bca"}, + {"0242e14105ced74e91cf4d4dcd22a9c09279018901d2fb8319eb54c2a1c4900a", + "fcb62a6c520d31fa46efeb4a1000330653b3402f575c2ddc0c688f527e7b97be", + "73a7e2e0602e5345f040dedc4db67f6d8e37c5fca3bbb124fa43963d76dbbb08", + "152bf4a3305c656f77e292b1256cc470da4d3f6efc3667199db4316d7f431174", + "c21ba2080013dfb225e06378d9ac27df623df552526cfddbf9e71bb1d4705dd9"}, + {"07fab4fc7b02fbcf868ffb0326cf60425fef2af1fbad83a8926cc62c2b5dff05", + "29ff12c5e052eb5829e8334e0e082c5edde1f293d2b4ed499a79bcca20e48010", + "97afb3dd9167877b432a23503aad1ab39188b9be07cc124ceb3fbdbd8d8b890a", + "ed121240a2f4591eeedbfd880305ccd17e522673900b03279fb66e73583514ae", + "b27f209e88ce5701766565e231e8123adb1df9c9f1dc461920acbc2b38d9f6d7"}, + }; + + unsigned char buff[32]; + bignum256modm a = {0}, b = {0}; + ge25519 A, B, R; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + expand256_modm(a, fromhex(tests[i][0]), 32); + expand256_modm(b, fromhex(tests[i][2]), 32); + ge25519_unpack_negative_vartime(&A, fromhex(tests[i][1])); + curve25519_neg(A.x, A.x); + curve25519_neg(A.t, A.t); + ge25519_unpack_negative_vartime(&B, fromhex(tests[i][3])); + curve25519_neg(B.x, B.x); + curve25519_neg(B.t, B.t); + ge25519_double_scalarmult_vartime2(&R, &A, a, &B, b); + ge25519_pack(buff, &R); + ck_assert_mem_eq(buff, fromhex(tests[i][4]), 32); + } } END_TEST -static void test_bip32_ecdh_init_node(HDNode *node, const char *seed_str, const char *curve_name) { - hdnode_from_seed((const uint8_t *)seed_str, strlen(seed_str), curve_name, node); - hdnode_fill_public_key(node); - if (node->public_key[0] == 1) { - node->public_key[0] = 0x40; // Curve25519 public keys start with 0x40 byte - } +static void test_bip32_ecdh_init_node(HDNode *node, const char *seed_str, + const char *curve_name) { + hdnode_from_seed((const uint8_t *)seed_str, strlen(seed_str), curve_name, + node); + hdnode_fill_public_key(node); + if (node->public_key[0] == 1) { + node->public_key[0] = 0x40; // Curve25519 public keys start with 0x40 byte + } } -static void test_bip32_ecdh(const char *curve_name, int expected_key_size, const uint8_t *expected_key) { - int res, key_size; - HDNode alice, bob; - uint8_t session_key1[expected_key_size], session_key2[expected_key_size]; - - test_bip32_ecdh_init_node(&alice, "Alice", curve_name); - test_bip32_ecdh_init_node(&bob, "Bob", curve_name); - - // Generate shared key from Alice's secret key and Bob's public key - res = hdnode_get_shared_key(&alice, bob.public_key, session_key1, &key_size); - ck_assert_int_eq(res, 0); - ck_assert_int_eq(key_size, expected_key_size); - ck_assert_mem_eq(session_key1, expected_key, key_size); - - // Generate shared key from Bob's secret key and Alice's public key - res = hdnode_get_shared_key(&bob, alice.public_key, session_key2, &key_size); - ck_assert_int_eq(res, 0); - ck_assert_int_eq(key_size, expected_key_size); - ck_assert_mem_eq(session_key2, expected_key, key_size); +static void test_bip32_ecdh(const char *curve_name, int expected_key_size, + const uint8_t *expected_key) { + int res, key_size; + HDNode alice, bob; + uint8_t session_key1[expected_key_size], session_key2[expected_key_size]; + + test_bip32_ecdh_init_node(&alice, "Alice", curve_name); + test_bip32_ecdh_init_node(&bob, "Bob", curve_name); + + // Generate shared key from Alice's secret key and Bob's public key + res = hdnode_get_shared_key(&alice, bob.public_key, session_key1, &key_size); + ck_assert_int_eq(res, 0); + ck_assert_int_eq(key_size, expected_key_size); + ck_assert_mem_eq(session_key1, expected_key, key_size); + + // Generate shared key from Bob's secret key and Alice's public key + res = hdnode_get_shared_key(&bob, alice.public_key, session_key2, &key_size); + ck_assert_int_eq(res, 0); + ck_assert_int_eq(key_size, expected_key_size); + ck_assert_mem_eq(session_key2, expected_key, key_size); } START_TEST(test_bip32_ecdh_nist256p1) { - test_bip32_ecdh( - NIST256P1_NAME, 65, - fromhex("044aa56f917323f071148cd29aa423f6bee96e7fe87f914d0b91a0f95388c6631646ea92e882773d7b0b1bec356b842c8559a1377673d3965fb931c8fe51e64873")); + test_bip32_ecdh( + NIST256P1_NAME, 65, + fromhex( + "044aa56f917323f071148cd29aa423f6bee96e7fe87f914d0b91a0f95388c6631646" + "ea92e882773d7b0b1bec356b842c8559a1377673d3965fb931c8fe51e64873")); } END_TEST START_TEST(test_bip32_ecdh_curve25519) { - test_bip32_ecdh( - CURVE25519_NAME, 33, - fromhex("04f34e35516325bb0d4a58507096c444a05ba13524ccf66910f11ce96c62224169")); + test_bip32_ecdh(CURVE25519_NAME, 33, + fromhex("04f34e35516325bb0d4a58507096c444a05ba13524ccf66910f1" + "1ce96c62224169")); } END_TEST START_TEST(test_bip32_ecdh_errors) { - HDNode node; - const uint8_t peer_public_key[65] = {0}; // invalid public key - uint8_t session_key[65]; - int res, key_size = 0; - - test_bip32_ecdh_init_node(&node, "Seed", ED25519_NAME); - res = hdnode_get_shared_key(&node, peer_public_key, session_key, &key_size); - ck_assert_int_eq(res, 1); - ck_assert_int_eq(key_size, 0); - - test_bip32_ecdh_init_node(&node, "Seed", CURVE25519_NAME); - res = hdnode_get_shared_key(&node, peer_public_key, session_key, &key_size); - ck_assert_int_eq(res, 1); - ck_assert_int_eq(key_size, 0); - - test_bip32_ecdh_init_node(&node, "Seed", NIST256P1_NAME); - res = hdnode_get_shared_key(&node, peer_public_key, session_key, &key_size); - ck_assert_int_eq(res, 1); - ck_assert_int_eq(key_size, 0); + HDNode node; + const uint8_t peer_public_key[65] = {0}; // invalid public key + uint8_t session_key[65]; + int res, key_size = 0; + + test_bip32_ecdh_init_node(&node, "Seed", ED25519_NAME); + res = hdnode_get_shared_key(&node, peer_public_key, session_key, &key_size); + ck_assert_int_eq(res, 1); + ck_assert_int_eq(key_size, 0); + + test_bip32_ecdh_init_node(&node, "Seed", CURVE25519_NAME); + res = hdnode_get_shared_key(&node, peer_public_key, session_key, &key_size); + ck_assert_int_eq(res, 1); + ck_assert_int_eq(key_size, 0); + + test_bip32_ecdh_init_node(&node, "Seed", NIST256P1_NAME); + res = hdnode_get_shared_key(&node, peer_public_key, session_key, &key_size); + ck_assert_int_eq(res, 1); + ck_assert_int_eq(key_size, 0); } END_TEST START_TEST(test_output_script) { - static const char *vectors[] = { - "76A914010966776006953D5567439E5E39F86A0D273BEE88AC", "16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM", - "A914010966776006953D5567439E5E39F86A0D273BEE87", "31nVrspaydBz8aMpxH9WkS2DuhgqS1fCuG", - "0014010966776006953D5567439E5E39F86A0D273BEE", "p2xtZoXeX5X8BP8JfFhQK2nD3emtjch7UeFm", - "00200102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F20", "7XhPD7te3C6CVKnJWUhrTJbFTwudhHqfrjpS59AS6sMzL4RYFiCNg", - 0, 0, - }; - const char **scr, **adr; - scr = vectors; - adr = vectors + 1; - char address[60]; - while (*scr && *adr) { - int r = script_output_to_address(fromhex(*scr), strlen(*scr)/2, address, 60); - ck_assert_int_eq(r, (int)(strlen(*adr) + 1)); - ck_assert_str_eq(address, *adr); - scr += 2; - adr += 2; - } + static const char *vectors[] = { + "76A914010966776006953D5567439E5E39F86A0D273BEE88AC", + "16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM", + "A914010966776006953D5567439E5E39F86A0D273BEE87", + "31nVrspaydBz8aMpxH9WkS2DuhgqS1fCuG", + "0014010966776006953D5567439E5E39F86A0D273BEE", + "p2xtZoXeX5X8BP8JfFhQK2nD3emtjch7UeFm", + "00200102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F20", + "7XhPD7te3C6CVKnJWUhrTJbFTwudhHqfrjpS59AS6sMzL4RYFiCNg", + 0, + 0, + }; + const char **scr, **adr; + scr = vectors; + adr = vectors + 1; + char address[60]; + while (*scr && *adr) { + int r = + script_output_to_address(fromhex(*scr), strlen(*scr) / 2, address, 60); + ck_assert_int_eq(r, (int)(strlen(*adr) + 1)); + ck_assert_str_eq(address, *adr); + scr += 2; + adr += 2; + } } END_TEST -START_TEST(test_ethereum_pubkeyhash) -{ - uint8_t pubkeyhash[20]; - int res; - HDNode node; - - // init m - hdnode_from_seed(fromhex("000102030405060708090a0b0c0d0e0f"), 16, SECP256K1_NAME, &node); - - // [Chain m] - res = hdnode_get_ethereum_pubkeyhash(&node, pubkeyhash); - ck_assert_int_eq(res, 1); - ck_assert_mem_eq(pubkeyhash, fromhex("056db290f8ba3250ca64a45d16284d04bc6f5fbf"), 20); - - // [Chain m/0'] - hdnode_private_ckd_prime(&node, 0); - res = hdnode_get_ethereum_pubkeyhash(&node, pubkeyhash); - ck_assert_int_eq(res, 1); - ck_assert_mem_eq(pubkeyhash, fromhex("bf6e48966d0dcf553b53e7b56cb2e0e72dca9e19"), 20); - - // [Chain m/0'/1] - hdnode_private_ckd(&node, 1); - res = hdnode_get_ethereum_pubkeyhash(&node, pubkeyhash); - ck_assert_int_eq(res, 1); - ck_assert_mem_eq(pubkeyhash, fromhex("29379f45f515c494483298225d1b347f73d1babf"), 20); - - // [Chain m/0'/1/2'] - hdnode_private_ckd_prime(&node, 2); - res = hdnode_get_ethereum_pubkeyhash(&node, pubkeyhash); - ck_assert_int_eq(res, 1); - ck_assert_mem_eq(pubkeyhash, fromhex("d8e85fbbb4b3b3c71c4e63a5580d0c12fb4d2f71"), 20); - - // [Chain m/0'/1/2'/2] - hdnode_private_ckd(&node, 2); - res = hdnode_get_ethereum_pubkeyhash(&node, pubkeyhash); - ck_assert_int_eq(res, 1); - ck_assert_mem_eq(pubkeyhash, fromhex("1d3462d2319ac0bfc1a52e177a9d372492752130"), 20); - - // [Chain m/0'/1/2'/2/1000000000] - hdnode_private_ckd(&node, 1000000000); - res = hdnode_get_ethereum_pubkeyhash(&node, pubkeyhash); - ck_assert_int_eq(res, 1); - ck_assert_mem_eq(pubkeyhash, fromhex("73659c60270d326c06ac204f1a9c63f889a3d14b"), 20); - - // init m - hdnode_from_seed(fromhex("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), 64, SECP256K1_NAME, &node); - - // [Chain m] - res = hdnode_get_ethereum_pubkeyhash(&node, pubkeyhash); - ck_assert_int_eq(res, 1); - ck_assert_mem_eq(pubkeyhash, fromhex("6dd2a6f3b05fd15d901fbeec61b87a34bdcfb843"), 20); - - // [Chain m/0] - hdnode_private_ckd(&node, 0); - res = hdnode_get_ethereum_pubkeyhash(&node, pubkeyhash); - ck_assert_int_eq(res, 1); - ck_assert_mem_eq(pubkeyhash, fromhex("abbcd4471a0b6e76a2f6fdc44008fe53831e208e"), 20); - - // [Chain m/0/2147483647'] - hdnode_private_ckd_prime(&node, 2147483647); - res = hdnode_get_ethereum_pubkeyhash(&node, pubkeyhash); - ck_assert_int_eq(res, 1); - ck_assert_mem_eq(pubkeyhash, fromhex("40ef2cef1b2588ae862e7a511162ec7ff33c30fd"), 20); - - // [Chain m/0/2147483647'/1] - hdnode_private_ckd(&node, 1); - res = hdnode_get_ethereum_pubkeyhash(&node, pubkeyhash); - ck_assert_int_eq(res, 1); - ck_assert_mem_eq(pubkeyhash, fromhex("3f2e8905488f795ebc84a39560d133971ccf9b50"), 20); - - // [Chain m/0/2147483647'/1/2147483646'] - hdnode_private_ckd_prime(&node, 2147483646); - res = hdnode_get_ethereum_pubkeyhash(&node, pubkeyhash); - ck_assert_int_eq(res, 1); - ck_assert_mem_eq(pubkeyhash, fromhex("a5016fdf975f767e4e6f355c7a82efa69bf42ea7"), 20); - - // [Chain m/0/2147483647'/1/2147483646'/2] - hdnode_private_ckd(&node, 2); - res = hdnode_get_ethereum_pubkeyhash(&node, pubkeyhash); - ck_assert_int_eq(res, 1); - ck_assert_mem_eq(pubkeyhash, fromhex("8ff2a9f7e7917804e8c8ec150d931d9c5a6fbc50"), 20); +START_TEST(test_ethereum_pubkeyhash) { + uint8_t pubkeyhash[20]; + int res; + HDNode node; + + // init m + hdnode_from_seed(fromhex("000102030405060708090a0b0c0d0e0f"), 16, + SECP256K1_NAME, &node); + + // [Chain m] + res = hdnode_get_ethereum_pubkeyhash(&node, pubkeyhash); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(pubkeyhash, + fromhex("056db290f8ba3250ca64a45d16284d04bc6f5fbf"), 20); + + // [Chain m/0'] + hdnode_private_ckd_prime(&node, 0); + res = hdnode_get_ethereum_pubkeyhash(&node, pubkeyhash); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(pubkeyhash, + fromhex("bf6e48966d0dcf553b53e7b56cb2e0e72dca9e19"), 20); + + // [Chain m/0'/1] + hdnode_private_ckd(&node, 1); + res = hdnode_get_ethereum_pubkeyhash(&node, pubkeyhash); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(pubkeyhash, + fromhex("29379f45f515c494483298225d1b347f73d1babf"), 20); + + // [Chain m/0'/1/2'] + hdnode_private_ckd_prime(&node, 2); + res = hdnode_get_ethereum_pubkeyhash(&node, pubkeyhash); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(pubkeyhash, + fromhex("d8e85fbbb4b3b3c71c4e63a5580d0c12fb4d2f71"), 20); + + // [Chain m/0'/1/2'/2] + hdnode_private_ckd(&node, 2); + res = hdnode_get_ethereum_pubkeyhash(&node, pubkeyhash); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(pubkeyhash, + fromhex("1d3462d2319ac0bfc1a52e177a9d372492752130"), 20); + + // [Chain m/0'/1/2'/2/1000000000] + hdnode_private_ckd(&node, 1000000000); + res = hdnode_get_ethereum_pubkeyhash(&node, pubkeyhash); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(pubkeyhash, + fromhex("73659c60270d326c06ac204f1a9c63f889a3d14b"), 20); + + // init m + hdnode_from_seed( + fromhex( + "fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c" + "999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), + 64, SECP256K1_NAME, &node); + + // [Chain m] + res = hdnode_get_ethereum_pubkeyhash(&node, pubkeyhash); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(pubkeyhash, + fromhex("6dd2a6f3b05fd15d901fbeec61b87a34bdcfb843"), 20); + + // [Chain m/0] + hdnode_private_ckd(&node, 0); + res = hdnode_get_ethereum_pubkeyhash(&node, pubkeyhash); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(pubkeyhash, + fromhex("abbcd4471a0b6e76a2f6fdc44008fe53831e208e"), 20); + + // [Chain m/0/2147483647'] + hdnode_private_ckd_prime(&node, 2147483647); + res = hdnode_get_ethereum_pubkeyhash(&node, pubkeyhash); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(pubkeyhash, + fromhex("40ef2cef1b2588ae862e7a511162ec7ff33c30fd"), 20); + + // [Chain m/0/2147483647'/1] + hdnode_private_ckd(&node, 1); + res = hdnode_get_ethereum_pubkeyhash(&node, pubkeyhash); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(pubkeyhash, + fromhex("3f2e8905488f795ebc84a39560d133971ccf9b50"), 20); + + // [Chain m/0/2147483647'/1/2147483646'] + hdnode_private_ckd_prime(&node, 2147483646); + res = hdnode_get_ethereum_pubkeyhash(&node, pubkeyhash); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(pubkeyhash, + fromhex("a5016fdf975f767e4e6f355c7a82efa69bf42ea7"), 20); + + // [Chain m/0/2147483647'/1/2147483646'/2] + hdnode_private_ckd(&node, 2); + res = hdnode_get_ethereum_pubkeyhash(&node, pubkeyhash); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(pubkeyhash, + fromhex("8ff2a9f7e7917804e8c8ec150d931d9c5a6fbc50"), 20); } END_TEST -START_TEST(test_ethereum_address) -{ - static const char *vectors[] = { - "52908400098527886E0F7030069857D2E4169EE7", - "8617E340B3D01FA5F11F306F4090FD50E238070D", - "de709f2102306220921060314715629080e2fb77", - "27b1fdb04752bbc536007a920d24acb045561c26", - "5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed", - "fB6916095ca1df60bB79Ce92cE3Ea74c37c5d359", - "dbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB", - "D1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb", - "5A4EAB120fB44eb6684E5e32785702FF45ea344D", - "5be4BDC48CeF65dbCbCaD5218B1A7D37F58A0741", - "a7dD84573f5ffF821baf2205745f768F8edCDD58", - "027a49d11d118c0060746F1990273FcB8c2fC196", - "CD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826", - 0 - }; - uint8_t addr[20]; - char address[41]; - const char **vec = vectors; - while (*vec) { - memcpy(addr, fromhex(*vec), 20); - ethereum_address_checksum(addr, address, false, 0); - ck_assert_str_eq(address, *vec); - vec++; - } +START_TEST(test_ethereum_address) { + static const char *vectors[] = {"52908400098527886E0F7030069857D2E4169EE7", + "8617E340B3D01FA5F11F306F4090FD50E238070D", + "de709f2102306220921060314715629080e2fb77", + "27b1fdb04752bbc536007a920d24acb045561c26", + "5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed", + "fB6916095ca1df60bB79Ce92cE3Ea74c37c5d359", + "dbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB", + "D1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb", + "5A4EAB120fB44eb6684E5e32785702FF45ea344D", + "5be4BDC48CeF65dbCbCaD5218B1A7D37F58A0741", + "a7dD84573f5ffF821baf2205745f768F8edCDD58", + "027a49d11d118c0060746F1990273FcB8c2fC196", + "CD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826", + 0}; + uint8_t addr[20]; + char address[41]; + const char **vec = vectors; + while (*vec) { + memcpy(addr, fromhex(*vec), 20); + ethereum_address_checksum(addr, address, false, 0); + ck_assert_str_eq(address, *vec); + vec++; + } } END_TEST -// test vectors from https://github.com/rsksmart/RSKIPs/blob/master/IPs/RSKIP60.md -START_TEST(test_rsk_address) -{ - uint8_t addr[20]; - char address[41]; - - static const char *rskip60_chain30[] = { - "5aaEB6053f3e94c9b9a09f33669435E7ef1bEAeD", - "Fb6916095cA1Df60bb79ce92cE3EA74c37c5d359", - "DBF03B407c01E7CD3cBea99509D93F8Dddc8C6FB", - "D1220A0Cf47c7B9BE7a2e6ba89F429762E7B9adB", - 0 - }; - const char **vec = rskip60_chain30; - while (*vec) { - memcpy(addr, fromhex(*vec), 20); - ethereum_address_checksum(addr, address, true, 30); - ck_assert_str_eq(address, *vec); - vec++; - } - - static const char *rskip60_chain31[] = { - "5aAeb6053F3e94c9b9A09F33669435E7EF1BEaEd", - "Fb6916095CA1dF60bb79CE92ce3Ea74C37c5D359", - "dbF03B407C01E7cd3cbEa99509D93f8dDDc8C6fB", - "d1220a0CF47c7B9Be7A2E6Ba89f429762E7b9adB", - 0 - }; - vec = rskip60_chain31; - while (*vec) { - memcpy(addr, fromhex(*vec), 20); - ethereum_address_checksum(addr, address, true, 31); - ck_assert_str_eq(address, *vec); - vec++; - } +// test vectors from +// https://github.com/rsksmart/RSKIPs/blob/master/IPs/RSKIP60.md +START_TEST(test_rsk_address) { + uint8_t addr[20]; + char address[41]; + + static const char *rskip60_chain30[] = { + "5aaEB6053f3e94c9b9a09f33669435E7ef1bEAeD", + "Fb6916095cA1Df60bb79ce92cE3EA74c37c5d359", + "DBF03B407c01E7CD3cBea99509D93F8Dddc8C6FB", + "D1220A0Cf47c7B9BE7a2e6ba89F429762E7B9adB", 0}; + const char **vec = rskip60_chain30; + while (*vec) { + memcpy(addr, fromhex(*vec), 20); + ethereum_address_checksum(addr, address, true, 30); + ck_assert_str_eq(address, *vec); + vec++; + } + + static const char *rskip60_chain31[] = { + "5aAeb6053F3e94c9b9A09F33669435E7EF1BEaEd", + "Fb6916095CA1dF60bb79CE92ce3Ea74C37c5D359", + "dbF03B407C01E7cd3cbEa99509D93f8dDDc8C6fB", + "d1220a0CF47c7B9Be7A2E6Ba89f429762E7b9adB", 0}; + vec = rskip60_chain31; + while (*vec) { + memcpy(addr, fromhex(*vec), 20); + ethereum_address_checksum(addr, address, true, 31); + ck_assert_str_eq(address, *vec); + vec++; + } } END_TEST -// test vectors from https://raw.githubusercontent.com/NemProject/nem-test-vectors/master/1.test-keys.dat -START_TEST(test_nem_address) -{ - static const struct { - const char *private_key; - const char *public_key; - const char *address; - } tests[] = { - { "575dbb3062267eff57c970a336ebbc8fbcfe12c5bd3ed7bc11eb0481d7704ced", "c5f54ba980fcbb657dbaaa42700539b207873e134d2375efeab5f1ab52f87844", "NDD2CT6LQLIYQ56KIXI3ENTM6EK3D44P5JFXJ4R4", }, - { "5b0e3fa5d3b49a79022d7c1e121ba1cbbf4db5821f47ab8c708ef88defc29bfe", "96eb2a145211b1b7ab5f0d4b14f8abc8d695c7aee31a3cfc2d4881313c68eea3", "NABHFGE5ORQD3LE4O6B7JUFN47ECOFBFASC3SCAC", }, - { "738ba9bb9110aea8f15caa353aca5653b4bdfca1db9f34d0efed2ce1325aeeda", "2d8425e4ca2d8926346c7a7ca39826acd881a8639e81bd68820409c6e30d142a", "NAVOZX4HDVOAR4W6K4WJHWPD3MOFU27DFHC7KZOZ", }, - { "e8bf9bc0f35c12d8c8bf94dd3a8b5b4034f1063948e3cc5304e55e31aa4b95a6", "4feed486777ed38e44c489c7c4e93a830e4c4a907fa19a174e630ef0f6ed0409", "NBZ6JK5YOCU6UPSSZ5D3G27UHAPHTY5HDQMGE6TT", }, - { "c325ea529674396db5675939e7988883d59a5fc17a28ca977e3ba85370232a83", "83ee32e4e145024d29bca54f71fa335a98b3e68283f1a3099c4d4ae113b53e54", "NCQW2P5DNZ5BBXQVGS367DQ4AHC3RXOEVGRCLY6V", }, - { "a811cb7a80a7227ae61f6da536534ee3c2744e3c7e4b85f3e0df3c6a9c5613df", "6d34c04f3a0e42f0c3c6f50e475ae018cfa2f56df58c481ad4300424a6270cbb", "NA5IG3XFXZHIPJ5QLKX2FBJPEZYPMBPPK2ZRC3EH", }, - { "9c66de1ec77f4dfaaebdf9c8bc599ca7e8e6f0bc71390ffee2c9dd3f3619242a", "a8fefd72a3b833dc7c7ed7d57ed86906dac22f88f1f4331873eb2da3152a3e77", "NAABHVFJDBM74XMJJ52R7QN2MTTG2ZUXPQS62QZ7", }, - { "c56bc16ecf727878c15e24f4ae68569600ac7b251218a44ef50ce54175776edc", "c92f761e6d83d20068fd46fe4bd5b97f4c6ba05d23180679b718d1f3e4fb066e", "NCLK3OLMHR3F2E3KSBUIZ4K5PNWUDN37MLSJBJZP", }, - { "9dd73599283882fa1561ddfc9be5830b5dd453c90465d3fe5eeb646a3606374e", "eaf16a4833e59370a04ccd5c63395058de34877b48c17174c71db5ed37b537ed", "ND3AHW4VTI5R5QE5V44KIGPRU5FBJ5AFUCJXOY5H", }, - { "d9639dc6f49dad02a42fd8c217f1b1b4f8ce31ccd770388b645e639c72ff24fa", "0f74a2f537cd9c986df018994dde75bdeee05e35eb9fe27adf506ca8475064f7", "NCTZ4YAP43ONK3UYTASQVNDMBO24ZHJE65F3QPYE", }, - { "efc1992cd50b70ca55ac12c07aa5d026a8b78ffe28a7dbffc9228b26e02c38c1", "2ebff201255f6cf948c78f528658b99a7c13ac791942fa22d59af610558111f5", "NDQ2TMCMXBSFPZQPE2YKH6XLC24HD6LUMN6Z4GIC", }, - { "143a815e92e43f3ed1a921ee48cd143931b88b7c3d8e1e981f743c2a5be3c5ba", "419ed11d48730e4ae2c93f0ea4df853b8d578713a36dab227517cf965861af4e", "NA32IDDW2C53BDSBJNFL3Z6UU3J5CJZJMCZDXCF4", }, - { "bc1a082f5ac6fdd3a83ade211e5986ac0551bad6c7da96727ec744e5df963e2a", "a160e6f9112233a7ce94202ed7a4443e1dac444b5095f9fecbb965fba3f92cac", "NADUCEQLC3FTGB25GTA5HOUTB53CBVQNVOIP7NTJ", }, - { "4e47b4c6f4c7886e49ec109c61f4af5cfbb1637283218941d55a7f9fe1053f72", "fbb91b16df828e21a9802980a44fc757c588bc1382a4cea429d6fa2ae0333f56", "NBAF3BFLLPWH33MYE6VUPP5T6DQBZBKIDEQKZQOE", }, - { "efc4389da48ce49f85365cfa578c746530e9eac42db1b64ec346119b1becd347", "2232f24dda0f2ded3ecd831210d4e8521a096b50cadd5a34f3f7083374e1ec12", "NBOGTK2I2ATOGGD7ZFJHROG5MWL7XCKAUKSWIVSA", }, - { "bdba57c78ca7da16a3360efd13f06276284db8c40351de7fcd38ba0c35ac754d", "c334c6c0dad5aaa2a0d0fb4c6032cb6a0edd96bf61125b5ea9062d5a00ee0eee", "NCLERTEFYXKLK7RA4MVACEFMXMK3P7QMWTM7FBW2", }, - { "20694c1ec3c4a311bcdb29ed2edc428f6d4f9a4c429ad6a5bf3222084e35695f", "518c4de412efa93de06a55947d11f697639443916ec8fcf04ebc3e6d17d0bd93", "NB5V4BPIJHXVONO7UGMJDPFARMFA73BOBNOOYCOV", }, - { "e0d4f3760ac107b33c22c2cac24ab2f520b282684f5f66a4212ff95d926323ce", "b3d16f4ead9de67c290144da535a0ed2504b03c05e5f1ceb8c7863762f786857", "NC4PBAO5TPCAVQKBVOC4F6DMZP3CFSQBU46PSKBD", }, - { "efa9afc617412093c9c7a7c211a5332dd556f941e1a88c494ec860608610eea2", "7e7716e4cebceb731d6f1fd28676f34888e9a0000fcfa1471db1c616c2ddf559", "NCFW2LPXIWLBWAQN2QVIWEOD7IVDO3HQBD2OU56K", }, - { "d98499b3db61944684ce06a91735af4e14105338473fcf6ebe2b0bcada3dfd21", "114171230ad6f8522a000cdc73fbc5c733b30bb71f2b146ccbdf34499f79a810", "NCUKWDY3J3THKQHAKOK5ALF6ANJQABZHCH7VN6DP", }, - }; - - HDNode node; - ed25519_secret_key private_key; - uint8_t chain_code[32]; - char address[41]; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - nem_private_key(tests[i].private_key, private_key); - - ck_assert(hdnode_from_xprv(0, 0, chain_code, private_key, ED25519_KECCAK_NAME, &node)); - - ck_assert(hdnode_get_nem_address(&node, NEM_NETWORK_MAINNET, address)); - ck_assert_str_eq(address, tests[i].address); - - ck_assert_mem_eq(&node.public_key[1], fromhex(tests[i].public_key), 32); - } +// test vectors from +// https://raw.githubusercontent.com/NemProject/nem-test-vectors/master/1.test-keys.dat +START_TEST(test_nem_address) { + static const struct { + const char *private_key; + const char *public_key; + const char *address; + } tests[] = { + { + "575dbb3062267eff57c970a336ebbc8fbcfe12c5bd3ed7bc11eb0481d7704ced", + "c5f54ba980fcbb657dbaaa42700539b207873e134d2375efeab5f1ab52f87844", + "NDD2CT6LQLIYQ56KIXI3ENTM6EK3D44P5JFXJ4R4", + }, + { + "5b0e3fa5d3b49a79022d7c1e121ba1cbbf4db5821f47ab8c708ef88defc29bfe", + "96eb2a145211b1b7ab5f0d4b14f8abc8d695c7aee31a3cfc2d4881313c68eea3", + "NABHFGE5ORQD3LE4O6B7JUFN47ECOFBFASC3SCAC", + }, + { + "738ba9bb9110aea8f15caa353aca5653b4bdfca1db9f34d0efed2ce1325aeeda", + "2d8425e4ca2d8926346c7a7ca39826acd881a8639e81bd68820409c6e30d142a", + "NAVOZX4HDVOAR4W6K4WJHWPD3MOFU27DFHC7KZOZ", + }, + { + "e8bf9bc0f35c12d8c8bf94dd3a8b5b4034f1063948e3cc5304e55e31aa4b95a6", + "4feed486777ed38e44c489c7c4e93a830e4c4a907fa19a174e630ef0f6ed0409", + "NBZ6JK5YOCU6UPSSZ5D3G27UHAPHTY5HDQMGE6TT", + }, + { + "c325ea529674396db5675939e7988883d59a5fc17a28ca977e3ba85370232a83", + "83ee32e4e145024d29bca54f71fa335a98b3e68283f1a3099c4d4ae113b53e54", + "NCQW2P5DNZ5BBXQVGS367DQ4AHC3RXOEVGRCLY6V", + }, + { + "a811cb7a80a7227ae61f6da536534ee3c2744e3c7e4b85f3e0df3c6a9c5613df", + "6d34c04f3a0e42f0c3c6f50e475ae018cfa2f56df58c481ad4300424a6270cbb", + "NA5IG3XFXZHIPJ5QLKX2FBJPEZYPMBPPK2ZRC3EH", + }, + { + "9c66de1ec77f4dfaaebdf9c8bc599ca7e8e6f0bc71390ffee2c9dd3f3619242a", + "a8fefd72a3b833dc7c7ed7d57ed86906dac22f88f1f4331873eb2da3152a3e77", + "NAABHVFJDBM74XMJJ52R7QN2MTTG2ZUXPQS62QZ7", + }, + { + "c56bc16ecf727878c15e24f4ae68569600ac7b251218a44ef50ce54175776edc", + "c92f761e6d83d20068fd46fe4bd5b97f4c6ba05d23180679b718d1f3e4fb066e", + "NCLK3OLMHR3F2E3KSBUIZ4K5PNWUDN37MLSJBJZP", + }, + { + "9dd73599283882fa1561ddfc9be5830b5dd453c90465d3fe5eeb646a3606374e", + "eaf16a4833e59370a04ccd5c63395058de34877b48c17174c71db5ed37b537ed", + "ND3AHW4VTI5R5QE5V44KIGPRU5FBJ5AFUCJXOY5H", + }, + { + "d9639dc6f49dad02a42fd8c217f1b1b4f8ce31ccd770388b645e639c72ff24fa", + "0f74a2f537cd9c986df018994dde75bdeee05e35eb9fe27adf506ca8475064f7", + "NCTZ4YAP43ONK3UYTASQVNDMBO24ZHJE65F3QPYE", + }, + { + "efc1992cd50b70ca55ac12c07aa5d026a8b78ffe28a7dbffc9228b26e02c38c1", + "2ebff201255f6cf948c78f528658b99a7c13ac791942fa22d59af610558111f5", + "NDQ2TMCMXBSFPZQPE2YKH6XLC24HD6LUMN6Z4GIC", + }, + { + "143a815e92e43f3ed1a921ee48cd143931b88b7c3d8e1e981f743c2a5be3c5ba", + "419ed11d48730e4ae2c93f0ea4df853b8d578713a36dab227517cf965861af4e", + "NA32IDDW2C53BDSBJNFL3Z6UU3J5CJZJMCZDXCF4", + }, + { + "bc1a082f5ac6fdd3a83ade211e5986ac0551bad6c7da96727ec744e5df963e2a", + "a160e6f9112233a7ce94202ed7a4443e1dac444b5095f9fecbb965fba3f92cac", + "NADUCEQLC3FTGB25GTA5HOUTB53CBVQNVOIP7NTJ", + }, + { + "4e47b4c6f4c7886e49ec109c61f4af5cfbb1637283218941d55a7f9fe1053f72", + "fbb91b16df828e21a9802980a44fc757c588bc1382a4cea429d6fa2ae0333f56", + "NBAF3BFLLPWH33MYE6VUPP5T6DQBZBKIDEQKZQOE", + }, + { + "efc4389da48ce49f85365cfa578c746530e9eac42db1b64ec346119b1becd347", + "2232f24dda0f2ded3ecd831210d4e8521a096b50cadd5a34f3f7083374e1ec12", + "NBOGTK2I2ATOGGD7ZFJHROG5MWL7XCKAUKSWIVSA", + }, + { + "bdba57c78ca7da16a3360efd13f06276284db8c40351de7fcd38ba0c35ac754d", + "c334c6c0dad5aaa2a0d0fb4c6032cb6a0edd96bf61125b5ea9062d5a00ee0eee", + "NCLERTEFYXKLK7RA4MVACEFMXMK3P7QMWTM7FBW2", + }, + { + "20694c1ec3c4a311bcdb29ed2edc428f6d4f9a4c429ad6a5bf3222084e35695f", + "518c4de412efa93de06a55947d11f697639443916ec8fcf04ebc3e6d17d0bd93", + "NB5V4BPIJHXVONO7UGMJDPFARMFA73BOBNOOYCOV", + }, + { + "e0d4f3760ac107b33c22c2cac24ab2f520b282684f5f66a4212ff95d926323ce", + "b3d16f4ead9de67c290144da535a0ed2504b03c05e5f1ceb8c7863762f786857", + "NC4PBAO5TPCAVQKBVOC4F6DMZP3CFSQBU46PSKBD", + }, + { + "efa9afc617412093c9c7a7c211a5332dd556f941e1a88c494ec860608610eea2", + "7e7716e4cebceb731d6f1fd28676f34888e9a0000fcfa1471db1c616c2ddf559", + "NCFW2LPXIWLBWAQN2QVIWEOD7IVDO3HQBD2OU56K", + }, + { + "d98499b3db61944684ce06a91735af4e14105338473fcf6ebe2b0bcada3dfd21", + "114171230ad6f8522a000cdc73fbc5c733b30bb71f2b146ccbdf34499f79a810", + "NCUKWDY3J3THKQHAKOK5ALF6ANJQABZHCH7VN6DP", + }, + }; + + HDNode node; + ed25519_secret_key private_key; + uint8_t chain_code[32]; + char address[41]; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + nem_private_key(tests[i].private_key, private_key); + + ck_assert(hdnode_from_xprv(0, 0, chain_code, private_key, + ED25519_KECCAK_NAME, &node)); + + ck_assert(hdnode_get_nem_address(&node, NEM_NETWORK_MAINNET, address)); + ck_assert_str_eq(address, tests[i].address); + + ck_assert_mem_eq(&node.public_key[1], fromhex(tests[i].public_key), 32); + } } END_TEST -// test vectors from https://raw.githubusercontent.com/NemProject/nem-test-vectors/master/3.test-derive.dat -START_TEST(test_nem_derive) -{ - static const struct { - const char *salt; - const char *private_key; - const char *public_key; - const char *mul; - const char *shared_key; - } tests[] = { - { "ad63ac08f9afc85eb0bf4f8881ca6eaa0215924c87aa2f137d56109bb76c6f98", "e8857f8e488d4e6d4b71bcd44bb4cff49208c32651e1f6500c3b58cafeb8def6", "9d8e5f200b05a2638fb084a375408cabd6d5989590d96e3eea5f2cb34668178e", "a8352060ba5718745ee4d78b9df564e0fbe13f50d50ab15a8dd524159d81d18b", "990a5f611c65fbcde735378bdec38e1039c5466503511e8c645bbe42795c752b", }, - { "96104f0a28f9cca40901c066cd435134662a3b053eb6c8df80ee0d05dc941963", "d7f67b5f52cbcd1a1367e0376a8eb1012b634acfcf35e8322bae8b22bb9e8dea", "9735c92d150dcee0ade5a8d1822f46a4db22c9cda25f33773ae856fe374a3e8a", "ea14d521d83328dba70982d42094300585818cc2da609fdb1f73bb32235576ff", "b498aa21d4ba4879ea9fd4225e93bacc760dcd9c119f8f38ab0716457d1a6f85", }, - { "d8f94a0bbb1de80aea17aab42e2ffb982e73fc49b649a318479e951e392d8728", "d026ddb445fb3bbf3020e4b55ed7b5f9b7fd1278c34978ca1a6ed6b358dadbae", "d19e6beca3b26b9d1abc127835ebeb7a6c19c33dec8ec472e1c4d458202f4ec8", "0d561f54728ad837ae108ec66c2ece2bb3b26041d3ee9b77fdc6d36d9ebfb2e3", "d012afe3d1d932304e613c91545bf571cf2c7281d6cafa8e81393a551f675540", }, - { "3f8c969678a8abdbfb76866a142c284a6f01636c1c1607947436e0d2c30d5245", "c522b38c391d1c3fa539cc58802bc66ac34bb3c73accd7f41b47f539bedcd016", "ea5b6a0053237f7712b1d2347c447d3e83e0f2191762d07e1f53f8eb7f2dfeaa", "23cccd3b63a9456e4425098b6df36f28c8999461a85e4b2b0c8d8f53c62c9ea9", "7e27efa50eed1c2ac51a12089cbab6a192624709c7330c016d5bc9af146584c1", }, - { "e66415c58b981c7f1f2b8f45a42149e9144616ff6de49ff83d97000ac6f6f992", "2f1b82be8e65d610a4e588f000a89a733a9de98ffc1ac9d55e138b3b0a855da0", "65aeda1b47f66c978a4a41d4dcdfbd8eab5cdeb135695c2b0c28f54417b1486d", "43e5b0a5cc8146c03ac63e6f8cf3d8825a9ca1ed53ea4a88304af4ddf5461b33", "bb4ab31c334e55d378937978c90bb33779b23cd5ef4c68342a394f4ec8fa1ada", }, - { "58487c9818c9d28ddf97cb09c13331941e05d0b62bf4c35ee368de80b552e4d1", "f3869b68183b2e4341307653e8f659bd7cd20e37ea5c00f5a9e203a8fa92359a", "c7e4153a18b4162f5c1f60e1ba483264aa5bb3f4889dca45b434fcd30b9cf56f", "5ae9408ab3156b8828c3e639730bd5e5db93d7afe2cee3fcda98079316c5bb3a", "0224d85ae8f17bfe127ec24b8960b7639a0dbde9c8c39a0575b939448687bb14", }, - { "ad66f3b654844e53d6fb3568134fae75672ba63868c113659d3ca58c2c39d24f", "d38f2ef8dfdc7224fef596130c3f4ff68ac83d3f932a56ee908061466ac28572", "d0c79d0340dc66f0a895ce5ad60a933cf6be659569096fb9d4b81e5d32292372", "1ea22db4708ed585ab541a4c70c3069f8e2c0c1faa188ddade3efaa53c8329f6", "886a7187246934aedf2794748deadfe038c9fd7e78d4b7be76c5a651440ac843", }, - { "eed48604eab279c6ad8128aa83483a3da0928271a4cae1a5745671284e1fb89d", "e2342a8450fc0adfa0ea2fbd0b1d28f100f0a3a905a3da29de34d1353afa7df7", "d2dbe07e0f2dbc3dbb01c70092e3c4247d12827ddcd8d76534fd740a65c30de2", "4c4b30eb6a2bfa17312f5729b4212cb51c2eee8fbfaea82a0e957ca68f4f6a30", "dcae613ac5641ff9d4c3ca58632245f93b0b8657fe4d48bac7b062cc53dd21ad", }, - { "f35b315287b268c0d0b386fb5b31810f65e1c4497cffae24527f69a3abac3884", "049016230dbef7a14a439e5ab2f6d12e78cb8df127db4e0c312673b3c361e350", "1b3b1925a8a535cd7d78725d25298f45bba8ca3dee2cdaabf14241c9b51b37c4", "04c9685dae1f8eb72a6438f24a87dc83a56d79c9024edf7e01aa1ae34656f29e", "b48469d0428c223b93cd1fe34bb2cafd3fb78a8fa15f98f89f1ac9c0ce7c9001", }, - { "d6cf082c5d9a96e756a94a2e27703138580a7c7c1af505c96c3abf7ab6802e1d", "67cd02b0b8b0adcf6fdd4d4d64a1f4193ced68bb8605d0ec941a62011326d140", "a842d5127c93a435e4672dcadd9fccbfd0e9208c79c5404848b298597eccdbdb", "d5c6bd6d81b99659d0bafe91025b6ecf73b16c6b07931cf44718b13f00fde3f7", "8aa160795b587f4be53aa35d26e9b618b4cd6ec765b523bc908e53c258ca8fd4", }, - { "dda32c91c95527a645b00dd05d13f0b98ed612a726ce5f5221431430b7660944", "eba026f92a8ffb5e95060a22e15d597fe838a99a0b2bbcb423c933b6bc718c50", "7dbaf9c313a1ff9128c54d6cd740c7d0cc46bca588e7910d438dd619ca4fd69a", "5bb20a145de83ba27a0c261e1f54bfd7dcea61888fc2eebbe6166876f7b000b8", "3a96f152ad8bf355cccb307e4a40108aa17f8e925522a2b5bb0b3f1e1a262914", }, - { "63c500acbd4ff747f7dadde7d3286482894ac4d7fe68f396712bca29879aa65c", "9663cd3c2030a5fe4a3ea3cc9a1d182b3a63ade68616aaeb4caf40b495f6f227", "b1e7d9070ac820d986d839b79f7aa594dcf708473529dad87af8682cc6197374", "1f7a97584d8db9f395b9ac4447de4b33c5c1f5020187cd4996286a49b07eb8a7", "4d2a974ec12dcf525b5654d31053460850c3092648b7e15598b7131d2930e9fb", }, - { "91f340961029398cc8bcd906388044a6801d24328efdf919d8ed0c609862a073", "45a588500d00142e2226231c01fd11ac6f842ab6a85872418f5b6a1999f8bd98", "397233c96069b6f4a57d6e93f759fa327222eaef71fc981afa673b248206df3f", "062123ef9782e3893f7b2e1d557b4ecce92b9f9aa8577e76380f228b75152f84", "235848cb04230a16d8978aa7c19fe7fbff3ebe29389ea6eb24fb8bc3cb50afc6", }, - { "46120b4da6ba4eb54fb65213cfef99b812c86f7c42a1de1107f8e8c12c0c3b6b", "cc19a97a99ad71ce348bcf831c0218e6a1f0a8d52186cabe6298b56f24e640f9", "c54631bb62f0f9d86b3301fcb2a671621e655e578c95504af5f78da83f7fec4f", "ab73cc20c75260ff3a7cefea8039291d4d15114a07a9250375628cca32225bb6", "70040a360b6a2dfa881272ef4fa6616e2e8fcc45194fa2a21a1eef1160271cd5", }, - { "f0a69ded09f1d731ab9561d0c3a40b7ef30bcb2bf60f92beccd8734e2441403d", "ea732822a381c46a7ac9999bf5ef85e16b7460b26aaf6c1a1c6ffa8c8c82c923", "110decbff79c382b1e60af4259564a3c473087792350b24fca98ae9a74ba9dd9", "81bdee95aecdcf821a9d682f79056f1abdcf1245d2f3b55244447881a283e0d4", "1bc29d4470ccf97d4e35e8d3cd4b12e3ebf2cb0a82425d35984aeedf7ad0f6f9", }, - { "e79cf4536fb1547e57626c0f1a87f71a396fdfb985b00731c0c2876a00645eda", "04213fc02b59c372e3e7f53faa71a2f73b31064102cb6fc8b68432ba7cdf7eb4", "ca1c750aaed53bc30dac07d0696ed86bcd7cdbbcbd3d15bb90d90cb5c6117bac", "c68cd0872a42a3a64e8a229ef7fcad3d722047d5af966f7dda4d4e32d0d57203", "bfdd3d07563d966d95afe4b8abea4b567265fceea8c4ecddb0946256c33e07b2", }, - { "81a40db4cddaf076e0206bd2b0fa7470a72cc456bad34aa3a0469a4859f286be", "52156799fd86cc63345cdbffd65ef4f5f8df0ffd9906a40af5f41d269bbcff5d", "54d61aa0b0b17a87f1376fe89cd8cd6b314827c1f1b9e5e7b20e7a7eee2a8335", "4553fb2cab8555068c32f86ceb692bbf1c2beeaf21627ef1b1be57344b52eea8", "55096b6710ade3bbe38702458ee13faa10c24413261bc076f17675dcbf2c4ee6", }, - { "d28e4a9e6832a3a4dad014a2bf1f666f01093cbba8b9ad4d1dcad3ea10cb42b9", "8ca134404c8fa199b0c72cb53cfa0adcf196dfa560fb521017cce5cbace3ba59", "3a6c39a1e5f9f550f1debedd9a0bc84210cce5f9834797db8f14122bf5817e45", "eb632ca818b4f659630226a339a3ce536b31c8e1e686fea8da3760e8abc20b8e", "9fbb3fbaf1cd54ee0cd90685f59b082545983f1f662ef701332379306a6ad546", }, - { "f9c4bfad9e2a3d98c44c12734881a6f217d6c9523cc210772fad1297993454b4", "b85960fcadda8d0a0960559b6b7818a0d8d4574b4e928b17c9b498fa9ffab4ef", "6a1d0ef23ce0b40a7077ecb7b7264945054e3bdb58ee25e1b0ee8b3e19dbfcdc", "bb145dddcb75074a6a03249fca1aa7d6fa9549e3ed965f138ca5e7071b7878f2", "87d3faea4a98e41009eb8625611ea0fc12094c295af540c126c14a0f55afa76e", }, - { "656df4789a369d220aceb7b318517787d27004ecccedea019d623bcb2d79f5ff", "acf83e30afb2a5066728ec5d93564c08abe5e68e3a2a2ff953bdcf4d44f9da06", "bdda65efe56d7890286aada1452f62f85ba157d0b4621ba641de15d8d1c9e331", "958beef5dc6babc6de383c32ad7dd3a6d6eb8bb3236ed5558eec0f9eb31e5458", "6f6d4ee36d9d76e462c9635adfbb6073134a276cfc7cb86762004ec47197afa0", }, - }; - - HDNode node; - ed25519_secret_key private_key; - uint8_t chain_code[32]; - ed25519_public_key public_key, mul; - uint8_t shared_key[SHA3_256_DIGEST_LENGTH]; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - nem_private_key(tests[i].private_key, private_key); - - ck_assert(hdnode_from_xprv(0, 0, chain_code, private_key, ED25519_KECCAK_NAME, &node)); - memcpy(public_key, fromhex(tests[i].public_key), 32); - - ck_assert(hdnode_get_nem_shared_key(&node, public_key, fromhex(tests[i].salt), mul, shared_key)); - ck_assert_mem_eq(mul, fromhex(tests[i].mul), sizeof(mul)); - ck_assert_mem_eq(shared_key, fromhex(tests[i].shared_key), sizeof(shared_key)); - } +// test vectors from +// https://raw.githubusercontent.com/NemProject/nem-test-vectors/master/3.test-derive.dat +START_TEST(test_nem_derive) { + static const struct { + const char *salt; + const char *private_key; + const char *public_key; + const char *mul; + const char *shared_key; + } tests[] = { + { + "ad63ac08f9afc85eb0bf4f8881ca6eaa0215924c87aa2f137d56109bb76c6f98", + "e8857f8e488d4e6d4b71bcd44bb4cff49208c32651e1f6500c3b58cafeb8def6", + "9d8e5f200b05a2638fb084a375408cabd6d5989590d96e3eea5f2cb34668178e", + "a8352060ba5718745ee4d78b9df564e0fbe13f50d50ab15a8dd524159d81d18b", + "990a5f611c65fbcde735378bdec38e1039c5466503511e8c645bbe42795c752b", + }, + { + "96104f0a28f9cca40901c066cd435134662a3b053eb6c8df80ee0d05dc941963", + "d7f67b5f52cbcd1a1367e0376a8eb1012b634acfcf35e8322bae8b22bb9e8dea", + "9735c92d150dcee0ade5a8d1822f46a4db22c9cda25f33773ae856fe374a3e8a", + "ea14d521d83328dba70982d42094300585818cc2da609fdb1f73bb32235576ff", + "b498aa21d4ba4879ea9fd4225e93bacc760dcd9c119f8f38ab0716457d1a6f85", + }, + { + "d8f94a0bbb1de80aea17aab42e2ffb982e73fc49b649a318479e951e392d8728", + "d026ddb445fb3bbf3020e4b55ed7b5f9b7fd1278c34978ca1a6ed6b358dadbae", + "d19e6beca3b26b9d1abc127835ebeb7a6c19c33dec8ec472e1c4d458202f4ec8", + "0d561f54728ad837ae108ec66c2ece2bb3b26041d3ee9b77fdc6d36d9ebfb2e3", + "d012afe3d1d932304e613c91545bf571cf2c7281d6cafa8e81393a551f675540", + }, + { + "3f8c969678a8abdbfb76866a142c284a6f01636c1c1607947436e0d2c30d5245", + "c522b38c391d1c3fa539cc58802bc66ac34bb3c73accd7f41b47f539bedcd016", + "ea5b6a0053237f7712b1d2347c447d3e83e0f2191762d07e1f53f8eb7f2dfeaa", + "23cccd3b63a9456e4425098b6df36f28c8999461a85e4b2b0c8d8f53c62c9ea9", + "7e27efa50eed1c2ac51a12089cbab6a192624709c7330c016d5bc9af146584c1", + }, + { + "e66415c58b981c7f1f2b8f45a42149e9144616ff6de49ff83d97000ac6f6f992", + "2f1b82be8e65d610a4e588f000a89a733a9de98ffc1ac9d55e138b3b0a855da0", + "65aeda1b47f66c978a4a41d4dcdfbd8eab5cdeb135695c2b0c28f54417b1486d", + "43e5b0a5cc8146c03ac63e6f8cf3d8825a9ca1ed53ea4a88304af4ddf5461b33", + "bb4ab31c334e55d378937978c90bb33779b23cd5ef4c68342a394f4ec8fa1ada", + }, + { + "58487c9818c9d28ddf97cb09c13331941e05d0b62bf4c35ee368de80b552e4d1", + "f3869b68183b2e4341307653e8f659bd7cd20e37ea5c00f5a9e203a8fa92359a", + "c7e4153a18b4162f5c1f60e1ba483264aa5bb3f4889dca45b434fcd30b9cf56f", + "5ae9408ab3156b8828c3e639730bd5e5db93d7afe2cee3fcda98079316c5bb3a", + "0224d85ae8f17bfe127ec24b8960b7639a0dbde9c8c39a0575b939448687bb14", + }, + { + "ad66f3b654844e53d6fb3568134fae75672ba63868c113659d3ca58c2c39d24f", + "d38f2ef8dfdc7224fef596130c3f4ff68ac83d3f932a56ee908061466ac28572", + "d0c79d0340dc66f0a895ce5ad60a933cf6be659569096fb9d4b81e5d32292372", + "1ea22db4708ed585ab541a4c70c3069f8e2c0c1faa188ddade3efaa53c8329f6", + "886a7187246934aedf2794748deadfe038c9fd7e78d4b7be76c5a651440ac843", + }, + { + "eed48604eab279c6ad8128aa83483a3da0928271a4cae1a5745671284e1fb89d", + "e2342a8450fc0adfa0ea2fbd0b1d28f100f0a3a905a3da29de34d1353afa7df7", + "d2dbe07e0f2dbc3dbb01c70092e3c4247d12827ddcd8d76534fd740a65c30de2", + "4c4b30eb6a2bfa17312f5729b4212cb51c2eee8fbfaea82a0e957ca68f4f6a30", + "dcae613ac5641ff9d4c3ca58632245f93b0b8657fe4d48bac7b062cc53dd21ad", + }, + { + "f35b315287b268c0d0b386fb5b31810f65e1c4497cffae24527f69a3abac3884", + "049016230dbef7a14a439e5ab2f6d12e78cb8df127db4e0c312673b3c361e350", + "1b3b1925a8a535cd7d78725d25298f45bba8ca3dee2cdaabf14241c9b51b37c4", + "04c9685dae1f8eb72a6438f24a87dc83a56d79c9024edf7e01aa1ae34656f29e", + "b48469d0428c223b93cd1fe34bb2cafd3fb78a8fa15f98f89f1ac9c0ce7c9001", + }, + { + "d6cf082c5d9a96e756a94a2e27703138580a7c7c1af505c96c3abf7ab6802e1d", + "67cd02b0b8b0adcf6fdd4d4d64a1f4193ced68bb8605d0ec941a62011326d140", + "a842d5127c93a435e4672dcadd9fccbfd0e9208c79c5404848b298597eccdbdb", + "d5c6bd6d81b99659d0bafe91025b6ecf73b16c6b07931cf44718b13f00fde3f7", + "8aa160795b587f4be53aa35d26e9b618b4cd6ec765b523bc908e53c258ca8fd4", + }, + { + "dda32c91c95527a645b00dd05d13f0b98ed612a726ce5f5221431430b7660944", + "eba026f92a8ffb5e95060a22e15d597fe838a99a0b2bbcb423c933b6bc718c50", + "7dbaf9c313a1ff9128c54d6cd740c7d0cc46bca588e7910d438dd619ca4fd69a", + "5bb20a145de83ba27a0c261e1f54bfd7dcea61888fc2eebbe6166876f7b000b8", + "3a96f152ad8bf355cccb307e4a40108aa17f8e925522a2b5bb0b3f1e1a262914", + }, + { + "63c500acbd4ff747f7dadde7d3286482894ac4d7fe68f396712bca29879aa65c", + "9663cd3c2030a5fe4a3ea3cc9a1d182b3a63ade68616aaeb4caf40b495f6f227", + "b1e7d9070ac820d986d839b79f7aa594dcf708473529dad87af8682cc6197374", + "1f7a97584d8db9f395b9ac4447de4b33c5c1f5020187cd4996286a49b07eb8a7", + "4d2a974ec12dcf525b5654d31053460850c3092648b7e15598b7131d2930e9fb", + }, + { + "91f340961029398cc8bcd906388044a6801d24328efdf919d8ed0c609862a073", + "45a588500d00142e2226231c01fd11ac6f842ab6a85872418f5b6a1999f8bd98", + "397233c96069b6f4a57d6e93f759fa327222eaef71fc981afa673b248206df3f", + "062123ef9782e3893f7b2e1d557b4ecce92b9f9aa8577e76380f228b75152f84", + "235848cb04230a16d8978aa7c19fe7fbff3ebe29389ea6eb24fb8bc3cb50afc6", + }, + { + "46120b4da6ba4eb54fb65213cfef99b812c86f7c42a1de1107f8e8c12c0c3b6b", + "cc19a97a99ad71ce348bcf831c0218e6a1f0a8d52186cabe6298b56f24e640f9", + "c54631bb62f0f9d86b3301fcb2a671621e655e578c95504af5f78da83f7fec4f", + "ab73cc20c75260ff3a7cefea8039291d4d15114a07a9250375628cca32225bb6", + "70040a360b6a2dfa881272ef4fa6616e2e8fcc45194fa2a21a1eef1160271cd5", + }, + { + "f0a69ded09f1d731ab9561d0c3a40b7ef30bcb2bf60f92beccd8734e2441403d", + "ea732822a381c46a7ac9999bf5ef85e16b7460b26aaf6c1a1c6ffa8c8c82c923", + "110decbff79c382b1e60af4259564a3c473087792350b24fca98ae9a74ba9dd9", + "81bdee95aecdcf821a9d682f79056f1abdcf1245d2f3b55244447881a283e0d4", + "1bc29d4470ccf97d4e35e8d3cd4b12e3ebf2cb0a82425d35984aeedf7ad0f6f9", + }, + { + "e79cf4536fb1547e57626c0f1a87f71a396fdfb985b00731c0c2876a00645eda", + "04213fc02b59c372e3e7f53faa71a2f73b31064102cb6fc8b68432ba7cdf7eb4", + "ca1c750aaed53bc30dac07d0696ed86bcd7cdbbcbd3d15bb90d90cb5c6117bac", + "c68cd0872a42a3a64e8a229ef7fcad3d722047d5af966f7dda4d4e32d0d57203", + "bfdd3d07563d966d95afe4b8abea4b567265fceea8c4ecddb0946256c33e07b2", + }, + { + "81a40db4cddaf076e0206bd2b0fa7470a72cc456bad34aa3a0469a4859f286be", + "52156799fd86cc63345cdbffd65ef4f5f8df0ffd9906a40af5f41d269bbcff5d", + "54d61aa0b0b17a87f1376fe89cd8cd6b314827c1f1b9e5e7b20e7a7eee2a8335", + "4553fb2cab8555068c32f86ceb692bbf1c2beeaf21627ef1b1be57344b52eea8", + "55096b6710ade3bbe38702458ee13faa10c24413261bc076f17675dcbf2c4ee6", + }, + { + "d28e4a9e6832a3a4dad014a2bf1f666f01093cbba8b9ad4d1dcad3ea10cb42b9", + "8ca134404c8fa199b0c72cb53cfa0adcf196dfa560fb521017cce5cbace3ba59", + "3a6c39a1e5f9f550f1debedd9a0bc84210cce5f9834797db8f14122bf5817e45", + "eb632ca818b4f659630226a339a3ce536b31c8e1e686fea8da3760e8abc20b8e", + "9fbb3fbaf1cd54ee0cd90685f59b082545983f1f662ef701332379306a6ad546", + }, + { + "f9c4bfad9e2a3d98c44c12734881a6f217d6c9523cc210772fad1297993454b4", + "b85960fcadda8d0a0960559b6b7818a0d8d4574b4e928b17c9b498fa9ffab4ef", + "6a1d0ef23ce0b40a7077ecb7b7264945054e3bdb58ee25e1b0ee8b3e19dbfcdc", + "bb145dddcb75074a6a03249fca1aa7d6fa9549e3ed965f138ca5e7071b7878f2", + "87d3faea4a98e41009eb8625611ea0fc12094c295af540c126c14a0f55afa76e", + }, + { + "656df4789a369d220aceb7b318517787d27004ecccedea019d623bcb2d79f5ff", + "acf83e30afb2a5066728ec5d93564c08abe5e68e3a2a2ff953bdcf4d44f9da06", + "bdda65efe56d7890286aada1452f62f85ba157d0b4621ba641de15d8d1c9e331", + "958beef5dc6babc6de383c32ad7dd3a6d6eb8bb3236ed5558eec0f9eb31e5458", + "6f6d4ee36d9d76e462c9635adfbb6073134a276cfc7cb86762004ec47197afa0", + }, + }; + + HDNode node; + ed25519_secret_key private_key; + uint8_t chain_code[32]; + ed25519_public_key public_key, mul; + uint8_t shared_key[SHA3_256_DIGEST_LENGTH]; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + nem_private_key(tests[i].private_key, private_key); + + ck_assert(hdnode_from_xprv(0, 0, chain_code, private_key, + ED25519_KECCAK_NAME, &node)); + memcpy(public_key, fromhex(tests[i].public_key), 32); + + ck_assert(hdnode_get_nem_shared_key( + &node, public_key, fromhex(tests[i].salt), mul, shared_key)); + ck_assert_mem_eq(mul, fromhex(tests[i].mul), sizeof(mul)); + ck_assert_mem_eq(shared_key, fromhex(tests[i].shared_key), + sizeof(shared_key)); + } } END_TEST -// test vectors from https://raw.githubusercontent.com/NemProject/nem-test-vectors/master/4.test-cipher.dat -START_TEST(test_nem_cipher) -{ - static const struct { - const char *private_key; - const char *public_key; - const char *salt; - const char *iv; - const char *input; - const char *output; - } tests[] = { - { "3140f94c79f249787d1ec75a97a885980eb8f0a7d9b7aa03e7200296e422b2b6", "57a70eb553a7b3fd621f0dba6abf51312ea2e2a2a1e19d0305516730f4bcbd21", "83616c67f076d356fd1288a6e0fd7a60488ba312a3adf0088b1b33c7655c3e6a", "a73ff5c32f8fd055b09775817a6a3f95", "86ddb9e713a8ebf67a51830eff03b837e147c20d75e67b2a54aa29e98c", "70815da779b1b954d7a7f00c16940e9917a0412a06a444b539bf147603eef87f", }, - { "3140f94c79f249787d1ec75a97a885980eb8f0a7d9b7aa03e7200296e422b2b6", "57a70eb553a7b3fd621f0dba6abf51312ea2e2a2a1e19d0305516730f4bcbd21", "703ce0b1d276b10eef35672df03234385a903460db18ba9d4e05b3ad31abb284", "91246c2d5493867c4fa3e78f85963677", "86ddb9e713a8ebf67a51830eff03b837e147c20d75e67b2a54aa29e98c", "564b2f40d42c0efc1bd6f057115a5abd1564cae36d7ccacf5d825d38401aa894", }, - { "3140f94c79f249787d1ec75a97a885980eb8f0a7d9b7aa03e7200296e422b2b6", "57a70eb553a7b3fd621f0dba6abf51312ea2e2a2a1e19d0305516730f4bcbd21", "b22e8e8e7373ac31ca7f0f6eb8b93130aba5266772a658593f3a11792e7e8d92", "9f8e33d82374dad6aac0e3dbe7aea704", "86ddb9e713a8ebf67a51830eff03b837e147c20d75e67b2a54aa29e98c", "7cab88d00a3fc656002eccbbd966e1d5d14a3090d92cf502cdbf843515625dcf", }, - { "3140f94c79f249787d1ec75a97a885980eb8f0a7d9b7aa03e7200296e422b2b6", "57a70eb553a7b3fd621f0dba6abf51312ea2e2a2a1e19d0305516730f4bcbd21", "af646c54cd153dffe453b60efbceeb85c1e95a414ea0036c4da94afb3366f5d9", "6acdf8e01acc8074ddc807281b6af888", "86ddb9e713a8ebf67a51830eff03b837e147c20d75e67b2a54aa29e98c", "aa70543a485b63a4dd141bb7fd78019092ac6fad731e914280a287c7467bae1a", }, - { "3140f94c79f249787d1ec75a97a885980eb8f0a7d9b7aa03e7200296e422b2b6", "57a70eb553a7b3fd621f0dba6abf51312ea2e2a2a1e19d0305516730f4bcbd21", "d9c0d386636c8a024935c024589f9cd39e820a16485b14951e690a967830e269", "f2e9f18aeb374965f54d2f4e31189a8f", "86ddb9e713a8ebf67a51830eff03b837e147c20d75e67b2a54aa29e98c", "33d97c216ea6498dfddabf94c2e2403d73efc495e9b284d9d90aaff840217d25", }, - { "d5c0762ecea2cd6b5c56751b58debcb32713aab348f4a59c493e38beb3244f3a", "66a35941d615b5644d19c2a602c363ada8b1a8a0dac3682623852dcab4afac04", "06c227baac1ae3b0b1dc583f4850f13f9ba5d53be4a98fa5c3ea16217847530d", "3735123e78c44895df6ea33fa57e9a72", "86ddb9e713a8ebf67a51830eff03b837e147c20d75e67b2a54aa29e98c", "d5b5d66ba8cee0eb7ecf95b143fa77a46d6de13749e12eff40f5a7e649167ccb", }, - { "d5c0762ecea2cd6b5c56751b58debcb32713aab348f4a59c493e38beb3244f3a", "66a35941d615b5644d19c2a602c363ada8b1a8a0dac3682623852dcab4afac04", "92f55ba5bc6fc2f23e3eedc299357c71518e36ba2447a4da7a9dfe9dfeb107b5", "1cbc4982e53e370052af97ab088fa942", "86ddb9e713a8ebf67a51830eff03b837e147c20d75e67b2a54aa29e98c", "d48ef1ef526d805656cfc932aff259eadb17aa3391dde1877a722cba31d935b2", }, - { "d5c0762ecea2cd6b5c56751b58debcb32713aab348f4a59c493e38beb3244f3a", "66a35941d615b5644d19c2a602c363ada8b1a8a0dac3682623852dcab4afac04", "10f15a39ba49866292a43b7781bc71ca8bbd4889f1616461caf056bcb91b0158", "c40d531d92bfee969dce91417346c892", "49de3cd5890e0cd0559f143807ff688ff62789b7236a332b7d7255ec0b4e73e6b3a4", "e6d75afdb542785669b42198577c5b358d95397d71ec6f5835dca46d332cc08dbf73ea790b7bcb169a65719c0d55054c", }, - { "d5c0762ecea2cd6b5c56751b58debcb32713aab348f4a59c493e38beb3244f3a", "66a35941d615b5644d19c2a602c363ada8b1a8a0dac3682623852dcab4afac04", "9c01ed42b219b3bbe1a43ae9d7af5c1dd09363baacfdba8f4d03d1046915e26e", "059a35d5f83249e632790015ed6518b9", "49de3cd5890e0cd0559f143807ff688ff62789b7236a332b7d7255ec0b4e73e6b3a4", "5ef11aadff2eccee8b712dab968fa842eb770818ec0e6663ed242ea8b6bbc1c66d6285ee5b5f03d55dfee382fb4fa25d", }, - { "d5c0762ecea2cd6b5c56751b58debcb32713aab348f4a59c493e38beb3244f3a", "66a35941d615b5644d19c2a602c363ada8b1a8a0dac3682623852dcab4afac04", "bc1067e2a7415ea45ff1ca9894338c591ff15f2e57ae2789ae31b9d5bea0f11e", "8c73f0d6613898daeefa3cf8b0686d37", "49de3cd5890e0cd0559f143807ff688ff62789b7236a332b7d7255ec0b4e73e6b3a4", "6d220213b1878cd40a458f2a1e6e3b48040455fdf504dcd857f4f2ca1ad642e3a44fc401d04e339d302f66a9fad3d919", }, - { "9ef87ba8aa2e664bdfdb978b98bc30fb61773d9298e7b8c72911683eeff41921", "441e76d7e53be0a967181076a842f69c20fd8c0e3f0ce3aa421b490b059fe094", "cf4a21cb790552165827b678ca9695fcaf77566d382325112ff79483455de667", "bfbf5482e06f55b88bdd9e053b7eee6e", "49de3cd5890e0cd0559f143807ff688ff62789b7236a332b7d7255ec0b4e73e6b3a4", "1198a78c29c215d5c450f7b8513ead253160bc9fde80d9cc8e6bee2efe9713cf5a09d6293c41033271c9e8c22036a28b", }, - { "9ef87ba8aa2e664bdfdb978b98bc30fb61773d9298e7b8c72911683eeff41921", "441e76d7e53be0a967181076a842f69c20fd8c0e3f0ce3aa421b490b059fe094", "eba5eae8aef79114082c3e70baef95bb02edf13b3897e8be7a70272962ef8838", "af9a56da3da18e2fbd2948a16332532b", "49de3cd5890e0cd0559f143807ff688ff62789b7236a332b7d7255ec0b4e73e6b3a4", "1062ab5fbbdee9042ad35bdadfd3047c0a2127fe0f001da1be1b0582185edfc9687be8d68f85795833bb04af9cedd3bb", }, - { "9ef87ba8aa2e664bdfdb978b98bc30fb61773d9298e7b8c72911683eeff41921", "441e76d7e53be0a967181076a842f69c20fd8c0e3f0ce3aa421b490b059fe094", "518f8dfd0c138f1ffb4ea8029db15441d70abd893c3d767dc668f23ba7770e27", "42d28307974a1b2a2d921d270cfce03b", "49de3cd5890e0cd0559f143807ff688ff62789b7236a332b7d7255ec0b4e73e6b3a4", "005e49fb7c5da540a84b034c853fc9f78a6b901ea495aed0c2abd4f08f1a96f9ffefc6a57f1ac09e0aea95ca0f03ffd8", }, - { "9ef87ba8aa2e664bdfdb978b98bc30fb61773d9298e7b8c72911683eeff41921", "441e76d7e53be0a967181076a842f69c20fd8c0e3f0ce3aa421b490b059fe094", "582fdf58b53715c26e10ba809e8f2ab70502e5a3d4e9a81100b7227732ab0bbc", "91f2aad3189bb2edc93bc891e73911ba", "49de3cd5890e0cd0559f143807ff688ff62789b7236a332b7d7255ec0b4e73e6b3a4", "821a69cb16c57f0cb866e590b38069e35faec3ae18f158bb067db83a11237d29ab1e6b868b3147236a0958f15c2e2167", }, - { "9ef87ba8aa2e664bdfdb978b98bc30fb61773d9298e7b8c72911683eeff41921", "441e76d7e53be0a967181076a842f69c20fd8c0e3f0ce3aa421b490b059fe094", "a415b4c006118fb72fc37b2746ef288e23ac45c8ff7ade5f368a31557b6ac93a", "2b7c5f75606c0b8106c6489ea5657a9e", "24512b714aefd5cbc4bcc4ef44ce6c67ffc447c65460a6c6e4a92e85", "2781d5ee8ef1cb1596f8902b33dfae5045f84a987ca58173af5830dbce386062", }, - { "ed93c5a101ab53382ceee4f7e6b5aa112621d3bb9d18891509b1834ede235bcc", "5a5e14c633d7d269302849d739d80344ff14db51d7bcda86045723f05c4e4541", "47e73ec362ea82d3a7c5d55532ad51d2cdf5316b981b2b2bd542b0efa027e8ea", "b2193f59030c8d05a7d3577b7f64dd33", "24512b714aefd5cbc4bcc4ef44ce6c67ffc447c65460a6c6e4a92e85", "3f43912db8dd6672b9996e5272e18c4b88fec9d7e8372db9c5f4709a4af1d86f", }, - { "ed93c5a101ab53382ceee4f7e6b5aa112621d3bb9d18891509b1834ede235bcc", "5a5e14c633d7d269302849d739d80344ff14db51d7bcda86045723f05c4e4541", "aaa006c57b6d1e402650577fe9787d8d285f4bacd7c01f998be49c766f8860c7", "130304ddb9adc8870cf56bcae9487b7f", "24512b714aefd5cbc4bcc4ef44ce6c67ffc447c65460a6c6e4a92e85", "878cc7d8c0ef8dac0182a78eedc8080a402f59d8062a6b4ca8f4a74f3c3b3de7", }, - { "ed93c5a101ab53382ceee4f7e6b5aa112621d3bb9d18891509b1834ede235bcc", "5a5e14c633d7d269302849d739d80344ff14db51d7bcda86045723f05c4e4541", "28dc7ccd6c2a939eef64b8be7b9ae248295e7fcd8471c22fa2f98733fea97611", "cb13890d3a11bc0a7433738263006710", "24512b714aefd5cbc4bcc4ef44ce6c67ffc447c65460a6c6e4a92e85", "e74ded846bebfa912fa1720e4c1415e6e5df7e7a1a7fedb5665d68f1763209a4", }, - { "ed93c5a101ab53382ceee4f7e6b5aa112621d3bb9d18891509b1834ede235bcc", "5a5e14c633d7d269302849d739d80344ff14db51d7bcda86045723f05c4e4541", "79974fa2cad95154d0873902c153ccc3e7d54b17f2eeb3f29b6344cad9365a9a", "22123357979d20f44cc8eb0263d84e0e", "24512b714aefd5cbc4bcc4ef44ce6c67ffc447c65460a6c6e4a92e85", "eb14dec7b8b64d81a2ee4db07b0adf144d4f79a519bbf332b823583fa2d45405", }, - { "ed93c5a101ab53382ceee4f7e6b5aa112621d3bb9d18891509b1834ede235bcc", "5a5e14c633d7d269302849d739d80344ff14db51d7bcda86045723f05c4e4541", "3409a6f8c4dcd9bd04144eb67e55a98696b674735b01bf1196191f29871ef966", "a823a0965969380ea1f8659ea5fd8fdd", "24512b714aefd5cbc4bcc4ef44ce6c67ffc447c65460a6c6e4a92e85", "00a7eb708eae745847173f8217efb05be13059710aee632e3f471ac3c6202b51", }, - { "a73a0b2686f7d699c018b6b08a352856e556070caa329c26241aec889eefde10", "9b493403bee45ae6277430ef8d0c4163ffd81ace2db6c7821205da09a664a86c", "c25701b9b7328c4ac3d23223d10623bd527c0a98e38ae9c62fbc403c80ab20ae", "4b4ee0e4443779f3af429a749212f476", "b6926d0ec82cec86c0d27ec9a33a0e0f", "f39f7d66e0fde39ecdf58be2c0ef361a17cfd6843e310adbe0ec3118cd72800d", }, - { "a73a0b2686f7d699c018b6b08a352856e556070caa329c26241aec889eefde10", "9b493403bee45ae6277430ef8d0c4163ffd81ace2db6c7821205da09a664a86c", "31d18fdffc480310828778496ff817039df5d6f30bf6d9edd0b4396863d05f93", "418bcbdf52860a450bfacc96920d02cf", "b6926d0ec82cec86c0d27ec9a33a0e0f", "0e6ce9889fe7b3cd82794b0ae27c1f5985d2f2a1f398371a138f8db1df1f54de", }, - { "e2e4dee102fad0f47f60202269605589cd9cf70f816b34016796c74b766f3041", "c5ce283033a3255ae14d42dff1e4c18a224ac79d084b285123421b105ee654c9", "56b4c645f81dbfb6ba0c6d3f1626e1e5cd648eeb36562715f7cd7e9ea86a0d7f", "dc9bdce76d68d2e4d72267cf4e72b022", "b6926d0ec82cec86c0d27ec9a33a0e0f", "dc6f046c3008002041517a7c4f3ababe609cf02616fcccda39c075d1be4175f5", }, - { "e2e4dee102fad0f47f60202269605589cd9cf70f816b34016796c74b766f3041", "c5ce283033a3255ae14d42dff1e4c18a224ac79d084b285123421b105ee654c9", "df180b91986c8c7000792f96d1faa61e30138330430a402322be1855089b0e7f", "ccf9b77341c866465b474e2f4a3b1cf8", "b6926d0ec82cec86c0d27ec9a33a0e0f", "94e4ae89041437f39826704f02cb5d775226f34344635e592846417497a5020b", }, - { "e2e4dee102fad0f47f60202269605589cd9cf70f816b34016796c74b766f3041", "c5ce283033a3255ae14d42dff1e4c18a224ac79d084b285123421b105ee654c9", "a0eee7e84c76e63fdae6e938b43330775eaf17d260e40b98c9e6616b668102a7", "662c681cfec6f6d052ff0e2c1255f2c2", "b6926d0ec82cec86c0d27ec9a33a0e0f", "70bba3c48be9c75a144b1888ca3d21a6b21f52eec133981a024390a6a0ba36f9", }, - { "e2e4dee102fad0f47f60202269605589cd9cf70f816b34016796c74b766f3041", "c5ce283033a3255ae14d42dff1e4c18a224ac79d084b285123421b105ee654c9", "c6acd2d90eb782c3053b366680ffa0e148de81fea198c87bb643869fd97e5cb0", "908dc33ba80520f2f0f04e7890e3a3c0", "b6926d0ec82cec86c0d27ec9a33a0e0f", "f6efe1d76d270aac264aa35d03049d9ce63be1996d543aef00559219c8666f71", }, - }; - - HDNode node; - ed25519_secret_key private_key; - uint8_t chain_code[32]; - ed25519_public_key public_key; - uint8_t salt[sizeof(public_key)]; - - uint8_t iv[AES_BLOCK_SIZE]; - uint8_t buffer[FROMHEX_MAXLEN]; - - uint8_t input[FROMHEX_MAXLEN]; - uint8_t output[FROMHEX_MAXLEN]; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - nem_private_key(tests[i].private_key, private_key); - - ck_assert(hdnode_from_xprv(0, 0, chain_code, private_key, ED25519_KECCAK_NAME, &node)); - memcpy(public_key, fromhex(tests[i].public_key), 32); - memcpy(salt, fromhex(tests[i].salt), sizeof(salt)); - - size_t input_size = strlen(tests[i].input) / 2; - size_t output_size = strlen(tests[i].output) / 2; - - memcpy(input, fromhex(tests[i].input), input_size); - memcpy(output, fromhex(tests[i].output), output_size); - - memcpy(iv, fromhex(tests[i].iv), sizeof(iv)); - ck_assert(hdnode_nem_encrypt(&node, public_key, iv, salt, input, input_size, buffer)); - ck_assert_int_eq(output_size, NEM_ENCRYPTED_SIZE(input_size)); - ck_assert_mem_eq(buffer, output, output_size); - - memcpy(iv, fromhex(tests[i].iv), sizeof(iv)); - ck_assert(hdnode_nem_decrypt(&node, public_key, iv, salt, output, output_size, buffer)); - ck_assert_int_eq(input_size, NEM_DECRYPTED_SIZE(buffer, output_size)); - ck_assert_mem_eq(buffer, input, input_size); - } +// test vectors from +// https://raw.githubusercontent.com/NemProject/nem-test-vectors/master/4.test-cipher.dat +START_TEST(test_nem_cipher) { + static const struct { + const char *private_key; + const char *public_key; + const char *salt; + const char *iv; + const char *input; + const char *output; + } tests[] = { + { + "3140f94c79f249787d1ec75a97a885980eb8f0a7d9b7aa03e7200296e422b2b6", + "57a70eb553a7b3fd621f0dba6abf51312ea2e2a2a1e19d0305516730f4bcbd21", + "83616c67f076d356fd1288a6e0fd7a60488ba312a3adf0088b1b33c7655c3e6a", + "a73ff5c32f8fd055b09775817a6a3f95", + "86ddb9e713a8ebf67a51830eff03b837e147c20d75e67b2a54aa29e98c", + "70815da779b1b954d7a7f00c16940e9917a0412a06a444b539bf147603eef87f", + }, + { + "3140f94c79f249787d1ec75a97a885980eb8f0a7d9b7aa03e7200296e422b2b6", + "57a70eb553a7b3fd621f0dba6abf51312ea2e2a2a1e19d0305516730f4bcbd21", + "703ce0b1d276b10eef35672df03234385a903460db18ba9d4e05b3ad31abb284", + "91246c2d5493867c4fa3e78f85963677", + "86ddb9e713a8ebf67a51830eff03b837e147c20d75e67b2a54aa29e98c", + "564b2f40d42c0efc1bd6f057115a5abd1564cae36d7ccacf5d825d38401aa894", + }, + { + "3140f94c79f249787d1ec75a97a885980eb8f0a7d9b7aa03e7200296e422b2b6", + "57a70eb553a7b3fd621f0dba6abf51312ea2e2a2a1e19d0305516730f4bcbd21", + "b22e8e8e7373ac31ca7f0f6eb8b93130aba5266772a658593f3a11792e7e8d92", + "9f8e33d82374dad6aac0e3dbe7aea704", + "86ddb9e713a8ebf67a51830eff03b837e147c20d75e67b2a54aa29e98c", + "7cab88d00a3fc656002eccbbd966e1d5d14a3090d92cf502cdbf843515625dcf", + }, + { + "3140f94c79f249787d1ec75a97a885980eb8f0a7d9b7aa03e7200296e422b2b6", + "57a70eb553a7b3fd621f0dba6abf51312ea2e2a2a1e19d0305516730f4bcbd21", + "af646c54cd153dffe453b60efbceeb85c1e95a414ea0036c4da94afb3366f5d9", + "6acdf8e01acc8074ddc807281b6af888", + "86ddb9e713a8ebf67a51830eff03b837e147c20d75e67b2a54aa29e98c", + "aa70543a485b63a4dd141bb7fd78019092ac6fad731e914280a287c7467bae1a", + }, + { + "3140f94c79f249787d1ec75a97a885980eb8f0a7d9b7aa03e7200296e422b2b6", + "57a70eb553a7b3fd621f0dba6abf51312ea2e2a2a1e19d0305516730f4bcbd21", + "d9c0d386636c8a024935c024589f9cd39e820a16485b14951e690a967830e269", + "f2e9f18aeb374965f54d2f4e31189a8f", + "86ddb9e713a8ebf67a51830eff03b837e147c20d75e67b2a54aa29e98c", + "33d97c216ea6498dfddabf94c2e2403d73efc495e9b284d9d90aaff840217d25", + }, + { + "d5c0762ecea2cd6b5c56751b58debcb32713aab348f4a59c493e38beb3244f3a", + "66a35941d615b5644d19c2a602c363ada8b1a8a0dac3682623852dcab4afac04", + "06c227baac1ae3b0b1dc583f4850f13f9ba5d53be4a98fa5c3ea16217847530d", + "3735123e78c44895df6ea33fa57e9a72", + "86ddb9e713a8ebf67a51830eff03b837e147c20d75e67b2a54aa29e98c", + "d5b5d66ba8cee0eb7ecf95b143fa77a46d6de13749e12eff40f5a7e649167ccb", + }, + { + "d5c0762ecea2cd6b5c56751b58debcb32713aab348f4a59c493e38beb3244f3a", + "66a35941d615b5644d19c2a602c363ada8b1a8a0dac3682623852dcab4afac04", + "92f55ba5bc6fc2f23e3eedc299357c71518e36ba2447a4da7a9dfe9dfeb107b5", + "1cbc4982e53e370052af97ab088fa942", + "86ddb9e713a8ebf67a51830eff03b837e147c20d75e67b2a54aa29e98c", + "d48ef1ef526d805656cfc932aff259eadb17aa3391dde1877a722cba31d935b2", + }, + { + "d5c0762ecea2cd6b5c56751b58debcb32713aab348f4a59c493e38beb3244f3a", + "66a35941d615b5644d19c2a602c363ada8b1a8a0dac3682623852dcab4afac04", + "10f15a39ba49866292a43b7781bc71ca8bbd4889f1616461caf056bcb91b0158", + "c40d531d92bfee969dce91417346c892", + "49de3cd5890e0cd0559f143807ff688ff62789b7236a332b7d7255ec0b4e73e6b3a" + "4", + "e6d75afdb542785669b42198577c5b358d95397d71ec6f5835dca46d332cc08dbf73" + "ea790b7bcb169a65719c0d55054c", + }, + { + "d5c0762ecea2cd6b5c56751b58debcb32713aab348f4a59c493e38beb3244f3a", + "66a35941d615b5644d19c2a602c363ada8b1a8a0dac3682623852dcab4afac04", + "9c01ed42b219b3bbe1a43ae9d7af5c1dd09363baacfdba8f4d03d1046915e26e", + "059a35d5f83249e632790015ed6518b9", + "49de3cd5890e0cd0559f143807ff688ff62789b7236a332b7d7255ec0b4e73e6b3a" + "4", + "5ef11aadff2eccee8b712dab968fa842eb770818ec0e6663ed242ea8b6bbc1c66d62" + "85ee5b5f03d55dfee382fb4fa25d", + }, + { + "d5c0762ecea2cd6b5c56751b58debcb32713aab348f4a59c493e38beb3244f3a", + "66a35941d615b5644d19c2a602c363ada8b1a8a0dac3682623852dcab4afac04", + "bc1067e2a7415ea45ff1ca9894338c591ff15f2e57ae2789ae31b9d5bea0f11e", + "8c73f0d6613898daeefa3cf8b0686d37", + "49de3cd5890e0cd0559f143807ff688ff62789b7236a332b7d7255ec0b4e73e6b3a" + "4", + "6d220213b1878cd40a458f2a1e6e3b48040455fdf504dcd857f4f2ca1ad642e3a44f" + "c401d04e339d302f66a9fad3d919", + }, + { + "9ef87ba8aa2e664bdfdb978b98bc30fb61773d9298e7b8c72911683eeff41921", + "441e76d7e53be0a967181076a842f69c20fd8c0e3f0ce3aa421b490b059fe094", + "cf4a21cb790552165827b678ca9695fcaf77566d382325112ff79483455de667", + "bfbf5482e06f55b88bdd9e053b7eee6e", + "49de3cd5890e0cd0559f143807ff688ff62789b7236a332b7d7255ec0b4e73e6b3a" + "4", + "1198a78c29c215d5c450f7b8513ead253160bc9fde80d9cc8e6bee2efe9713cf5a09" + "d6293c41033271c9e8c22036a28b", + }, + { + "9ef87ba8aa2e664bdfdb978b98bc30fb61773d9298e7b8c72911683eeff41921", + "441e76d7e53be0a967181076a842f69c20fd8c0e3f0ce3aa421b490b059fe094", + "eba5eae8aef79114082c3e70baef95bb02edf13b3897e8be7a70272962ef8838", + "af9a56da3da18e2fbd2948a16332532b", + "49de3cd5890e0cd0559f143807ff688ff62789b7236a332b7d7255ec0b4e73e6b3a" + "4", + "1062ab5fbbdee9042ad35bdadfd3047c0a2127fe0f001da1be1b0582185edfc9687b" + "e8d68f85795833bb04af9cedd3bb", + }, + { + "9ef87ba8aa2e664bdfdb978b98bc30fb61773d9298e7b8c72911683eeff41921", + "441e76d7e53be0a967181076a842f69c20fd8c0e3f0ce3aa421b490b059fe094", + "518f8dfd0c138f1ffb4ea8029db15441d70abd893c3d767dc668f23ba7770e27", + "42d28307974a1b2a2d921d270cfce03b", + "49de3cd5890e0cd0559f143807ff688ff62789b7236a332b7d7255ec0b4e73e6b3a" + "4", + "005e49fb7c5da540a84b034c853fc9f78a6b901ea495aed0c2abd4f08f1a96f9ffef" + "c6a57f1ac09e0aea95ca0f03ffd8", + }, + { + "9ef87ba8aa2e664bdfdb978b98bc30fb61773d9298e7b8c72911683eeff41921", + "441e76d7e53be0a967181076a842f69c20fd8c0e3f0ce3aa421b490b059fe094", + "582fdf58b53715c26e10ba809e8f2ab70502e5a3d4e9a81100b7227732ab0bbc", + "91f2aad3189bb2edc93bc891e73911ba", + "49de3cd5890e0cd0559f143807ff688ff62789b7236a332b7d7255ec0b4e73e6b3a" + "4", + "821a69cb16c57f0cb866e590b38069e35faec3ae18f158bb067db83a11237d29ab1e" + "6b868b3147236a0958f15c2e2167", + }, + { + "9ef87ba8aa2e664bdfdb978b98bc30fb61773d9298e7b8c72911683eeff41921", + "441e76d7e53be0a967181076a842f69c20fd8c0e3f0ce3aa421b490b059fe094", + "a415b4c006118fb72fc37b2746ef288e23ac45c8ff7ade5f368a31557b6ac93a", + "2b7c5f75606c0b8106c6489ea5657a9e", + "24512b714aefd5cbc4bcc4ef44ce6c67ffc447c65460a6c6e4a92e85", + "2781d5ee8ef1cb1596f8902b33dfae5045f84a987ca58173af5830dbce386062", + }, + { + "ed93c5a101ab53382ceee4f7e6b5aa112621d3bb9d18891509b1834ede235bcc", + "5a5e14c633d7d269302849d739d80344ff14db51d7bcda86045723f05c4e4541", + "47e73ec362ea82d3a7c5d55532ad51d2cdf5316b981b2b2bd542b0efa027e8ea", + "b2193f59030c8d05a7d3577b7f64dd33", + "24512b714aefd5cbc4bcc4ef44ce6c67ffc447c65460a6c6e4a92e85", + "3f43912db8dd6672b9996e5272e18c4b88fec9d7e8372db9c5f4709a4af1d86f", + }, + { + "ed93c5a101ab53382ceee4f7e6b5aa112621d3bb9d18891509b1834ede235bcc", + "5a5e14c633d7d269302849d739d80344ff14db51d7bcda86045723f05c4e4541", + "aaa006c57b6d1e402650577fe9787d8d285f4bacd7c01f998be49c766f8860c7", + "130304ddb9adc8870cf56bcae9487b7f", + "24512b714aefd5cbc4bcc4ef44ce6c67ffc447c65460a6c6e4a92e85", + "878cc7d8c0ef8dac0182a78eedc8080a402f59d8062a6b4ca8f4a74f3c3b3de7", + }, + { + "ed93c5a101ab53382ceee4f7e6b5aa112621d3bb9d18891509b1834ede235bcc", + "5a5e14c633d7d269302849d739d80344ff14db51d7bcda86045723f05c4e4541", + "28dc7ccd6c2a939eef64b8be7b9ae248295e7fcd8471c22fa2f98733fea97611", + "cb13890d3a11bc0a7433738263006710", + "24512b714aefd5cbc4bcc4ef44ce6c67ffc447c65460a6c6e4a92e85", + "e74ded846bebfa912fa1720e4c1415e6e5df7e7a1a7fedb5665d68f1763209a4", + }, + { + "ed93c5a101ab53382ceee4f7e6b5aa112621d3bb9d18891509b1834ede235bcc", + "5a5e14c633d7d269302849d739d80344ff14db51d7bcda86045723f05c4e4541", + "79974fa2cad95154d0873902c153ccc3e7d54b17f2eeb3f29b6344cad9365a9a", + "22123357979d20f44cc8eb0263d84e0e", + "24512b714aefd5cbc4bcc4ef44ce6c67ffc447c65460a6c6e4a92e85", + "eb14dec7b8b64d81a2ee4db07b0adf144d4f79a519bbf332b823583fa2d45405", + }, + { + "ed93c5a101ab53382ceee4f7e6b5aa112621d3bb9d18891509b1834ede235bcc", + "5a5e14c633d7d269302849d739d80344ff14db51d7bcda86045723f05c4e4541", + "3409a6f8c4dcd9bd04144eb67e55a98696b674735b01bf1196191f29871ef966", + "a823a0965969380ea1f8659ea5fd8fdd", + "24512b714aefd5cbc4bcc4ef44ce6c67ffc447c65460a6c6e4a92e85", + "00a7eb708eae745847173f8217efb05be13059710aee632e3f471ac3c6202b51", + }, + { + "a73a0b2686f7d699c018b6b08a352856e556070caa329c26241aec889eefde10", + "9b493403bee45ae6277430ef8d0c4163ffd81ace2db6c7821205da09a664a86c", + "c25701b9b7328c4ac3d23223d10623bd527c0a98e38ae9c62fbc403c80ab20ae", + "4b4ee0e4443779f3af429a749212f476", + "b6926d0ec82cec86c0d27ec9a33a0e0f", + "f39f7d66e0fde39ecdf58be2c0ef361a17cfd6843e310adbe0ec3118cd72800d", + }, + { + "a73a0b2686f7d699c018b6b08a352856e556070caa329c26241aec889eefde10", + "9b493403bee45ae6277430ef8d0c4163ffd81ace2db6c7821205da09a664a86c", + "31d18fdffc480310828778496ff817039df5d6f30bf6d9edd0b4396863d05f93", + "418bcbdf52860a450bfacc96920d02cf", + "b6926d0ec82cec86c0d27ec9a33a0e0f", + "0e6ce9889fe7b3cd82794b0ae27c1f5985d2f2a1f398371a138f8db1df1f54de", + }, + { + "e2e4dee102fad0f47f60202269605589cd9cf70f816b34016796c74b766f3041", + "c5ce283033a3255ae14d42dff1e4c18a224ac79d084b285123421b105ee654c9", + "56b4c645f81dbfb6ba0c6d3f1626e1e5cd648eeb36562715f7cd7e9ea86a0d7f", + "dc9bdce76d68d2e4d72267cf4e72b022", + "b6926d0ec82cec86c0d27ec9a33a0e0f", + "dc6f046c3008002041517a7c4f3ababe609cf02616fcccda39c075d1be4175f5", + }, + { + "e2e4dee102fad0f47f60202269605589cd9cf70f816b34016796c74b766f3041", + "c5ce283033a3255ae14d42dff1e4c18a224ac79d084b285123421b105ee654c9", + "df180b91986c8c7000792f96d1faa61e30138330430a402322be1855089b0e7f", + "ccf9b77341c866465b474e2f4a3b1cf8", + "b6926d0ec82cec86c0d27ec9a33a0e0f", + "94e4ae89041437f39826704f02cb5d775226f34344635e592846417497a5020b", + }, + { + "e2e4dee102fad0f47f60202269605589cd9cf70f816b34016796c74b766f3041", + "c5ce283033a3255ae14d42dff1e4c18a224ac79d084b285123421b105ee654c9", + "a0eee7e84c76e63fdae6e938b43330775eaf17d260e40b98c9e6616b668102a7", + "662c681cfec6f6d052ff0e2c1255f2c2", + "b6926d0ec82cec86c0d27ec9a33a0e0f", + "70bba3c48be9c75a144b1888ca3d21a6b21f52eec133981a024390a6a0ba36f9", + }, + { + "e2e4dee102fad0f47f60202269605589cd9cf70f816b34016796c74b766f3041", + "c5ce283033a3255ae14d42dff1e4c18a224ac79d084b285123421b105ee654c9", + "c6acd2d90eb782c3053b366680ffa0e148de81fea198c87bb643869fd97e5cb0", + "908dc33ba80520f2f0f04e7890e3a3c0", + "b6926d0ec82cec86c0d27ec9a33a0e0f", + "f6efe1d76d270aac264aa35d03049d9ce63be1996d543aef00559219c8666f71", + }, + }; + + HDNode node; + ed25519_secret_key private_key; + uint8_t chain_code[32]; + ed25519_public_key public_key; + uint8_t salt[sizeof(public_key)]; + + uint8_t iv[AES_BLOCK_SIZE]; + uint8_t buffer[FROMHEX_MAXLEN]; + + uint8_t input[FROMHEX_MAXLEN]; + uint8_t output[FROMHEX_MAXLEN]; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + nem_private_key(tests[i].private_key, private_key); + + ck_assert(hdnode_from_xprv(0, 0, chain_code, private_key, + ED25519_KECCAK_NAME, &node)); + memcpy(public_key, fromhex(tests[i].public_key), 32); + memcpy(salt, fromhex(tests[i].salt), sizeof(salt)); + + size_t input_size = strlen(tests[i].input) / 2; + size_t output_size = strlen(tests[i].output) / 2; + + memcpy(input, fromhex(tests[i].input), input_size); + memcpy(output, fromhex(tests[i].output), output_size); + + memcpy(iv, fromhex(tests[i].iv), sizeof(iv)); + ck_assert(hdnode_nem_encrypt(&node, public_key, iv, salt, input, input_size, + buffer)); + ck_assert_int_eq(output_size, NEM_ENCRYPTED_SIZE(input_size)); + ck_assert_mem_eq(buffer, output, output_size); + + memcpy(iv, fromhex(tests[i].iv), sizeof(iv)); + ck_assert(hdnode_nem_decrypt(&node, public_key, iv, salt, output, + output_size, buffer)); + ck_assert_int_eq(input_size, NEM_DECRYPTED_SIZE(buffer, output_size)); + ck_assert_mem_eq(buffer, input, input_size); + } } END_TEST -START_TEST(test_nem_transaction_transfer) -{ - nem_transaction_ctx ctx; - - uint8_t buffer[1024], hash[SHA3_256_DIGEST_LENGTH]; - - // http://bob.nem.ninja:8765/#/transfer/0acbf8df91e6a65dc56c56c43d65f31ff2a6a48d06fc66e78c7f3436faf3e74f - - nem_transaction_start(&ctx, fromhex("e59ef184a612d4c3c4d89b5950eb57262c69862b2f96e59c5043bf41765c482f"), buffer, sizeof(buffer)); - - ck_assert(nem_transaction_create_transfer(&ctx, - NEM_NETWORK_TESTNET, 0, NULL, 0, 0, - "TBGIMRE4SBFRUJXMH7DVF2IBY36L2EDWZ37GVSC4", 50000000000000, - NULL, 0, false, - 0)); - - keccak_256(ctx.buffer, ctx.offset, hash); - ck_assert_mem_eq(hash, fromhex("0acbf8df91e6a65dc56c56c43d65f31ff2a6a48d06fc66e78c7f3436faf3e74f"), sizeof(hash)); - - // http://bob.nem.ninja:8765/#/transfer/3409d9ece28d6296d6d5e220a7e3cb8641a3fb235ffcbd20c95da64f003ace6c - - nem_transaction_start(&ctx, fromhex("994793ba1c789fa9bdea918afc9b06e2d0309beb1081ac5b6952991e4defd324"), buffer, sizeof(buffer)); - - ck_assert(nem_transaction_create_transfer(&ctx, - NEM_NETWORK_TESTNET, 14072100, NULL, 194000000, 14075700, - "TBLOODPLWOWMZ2TARX4RFPOSOWLULHXMROBN2WXI", 3000000, - (uint8_t *) "sending you 3 pairs of paddles\n", 31, false, - 2)); - - ck_assert(nem_transaction_write_mosaic(&ctx, - "gimre.games.pong", "paddles", 2)); - - ck_assert(nem_transaction_write_mosaic(&ctx, - "nem", "xem", 44000000)); - - keccak_256(ctx.buffer, ctx.offset, hash); - ck_assert_mem_eq(hash, fromhex("3409d9ece28d6296d6d5e220a7e3cb8641a3fb235ffcbd20c95da64f003ace6c"), sizeof(hash)); - - // http://chain.nem.ninja/#/transfer/e90e98614c7598fbfa4db5411db1b331d157c2f86b558fb7c943d013ed9f71cb - - nem_transaction_start(&ctx, fromhex("8d07f90fb4bbe7715fa327c926770166a11be2e494a970605f2e12557f66c9b9"), buffer, sizeof(buffer)); - - ck_assert(nem_transaction_create_transfer(&ctx, - NEM_NETWORK_MAINNET, 0, NULL, 0, 0, - "NBT3WHA2YXG2IR4PWKFFMO772JWOITTD2V4PECSB", 5175000000000, - (uint8_t *) "Good luck!", 10, false, - 0)); - - keccak_256(ctx.buffer, ctx.offset, hash); - ck_assert_mem_eq(hash, fromhex("e90e98614c7598fbfa4db5411db1b331d157c2f86b558fb7c943d013ed9f71cb"), sizeof(hash)); - - // http://chain.nem.ninja/#/transfer/40e89160e6f83d37f7c82defc0afe2c1605ae8c919134570a51dd27ea1bb516c - - nem_transaction_start(&ctx, fromhex("f85ab43dad059b9d2331ddacc384ad925d3467f03207182e01296bacfb242d01"), buffer, sizeof(buffer)); - - ck_assert(nem_transaction_create_transfer(&ctx, - NEM_NETWORK_MAINNET, 77229, NULL, 30000000, 80829, - "NALICEPFLZQRZGPRIJTMJOCPWDNECXTNNG7QLSG3", 30000000, - fromhex("4d9dcf9186967d30be93d6d5404ded22812dbbae7c3f0de5" - "01bcd7228cba45bded13000eec7b4c6215fc4d3588168c92" - "18167cec98e6977359153a4132e050f594548e61e0dc61c1" - "53f0f53c5e65c595239c9eb7c4e7d48e0f4bb8b1dd2f5ddc"), 96, true, - 0)); - - keccak_256(ctx.buffer, ctx.offset, hash); - ck_assert_mem_eq(hash, fromhex("40e89160e6f83d37f7c82defc0afe2c1605ae8c919134570a51dd27ea1bb516c"), sizeof(hash)); - - // http://chain.nem.ninja/#/transfer/882dca18dcbe075e15e0ec5a1d7e6ccd69cc0f1309ffd3fde227bfbc107b3f6e - - nem_transaction_start(&ctx, fromhex("f85ab43dad059b9d2331ddacc384ad925d3467f03207182e01296bacfb242d01"), buffer, sizeof(buffer)); - - ck_assert(nem_transaction_create_transfer(&ctx, - NEM_NETWORK_MAINNET, 26730750, NULL, 179500000, 26734350, - "NBE223WPKEBHQPCYUC4U4CDUQCRRFMPZLOQLB5OP", 1000000, - (uint8_t *) "enjoy! :)", 9, false, - 1)); - - ck_assert(nem_transaction_write_mosaic(&ctx, - "imre.g", "tokens", 1)); - - keccak_256(ctx.buffer, ctx.offset, hash); - ck_assert_mem_eq(hash, fromhex("882dca18dcbe075e15e0ec5a1d7e6ccd69cc0f1309ffd3fde227bfbc107b3f6e"), sizeof(hash)); +START_TEST(test_nem_transaction_transfer) { + nem_transaction_ctx ctx; + + uint8_t buffer[1024], hash[SHA3_256_DIGEST_LENGTH]; + + // http://bob.nem.ninja:8765/#/transfer/0acbf8df91e6a65dc56c56c43d65f31ff2a6a48d06fc66e78c7f3436faf3e74f + + nem_transaction_start( + &ctx, + fromhex( + "e59ef184a612d4c3c4d89b5950eb57262c69862b2f96e59c5043bf41765c482f"), + buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_transfer( + &ctx, NEM_NETWORK_TESTNET, 0, NULL, 0, 0, + "TBGIMRE4SBFRUJXMH7DVF2IBY36L2EDWZ37GVSC4", 50000000000000, NULL, 0, + false, 0)); + + keccak_256(ctx.buffer, ctx.offset, hash); + ck_assert_mem_eq( + hash, + fromhex( + "0acbf8df91e6a65dc56c56c43d65f31ff2a6a48d06fc66e78c7f3436faf3e74f"), + sizeof(hash)); + + // http://bob.nem.ninja:8765/#/transfer/3409d9ece28d6296d6d5e220a7e3cb8641a3fb235ffcbd20c95da64f003ace6c + + nem_transaction_start( + &ctx, + fromhex( + "994793ba1c789fa9bdea918afc9b06e2d0309beb1081ac5b6952991e4defd324"), + buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_transfer( + &ctx, NEM_NETWORK_TESTNET, 14072100, NULL, 194000000, 14075700, + "TBLOODPLWOWMZ2TARX4RFPOSOWLULHXMROBN2WXI", 3000000, + (uint8_t *)"sending you 3 pairs of paddles\n", 31, false, 2)); + + ck_assert( + nem_transaction_write_mosaic(&ctx, "gimre.games.pong", "paddles", 2)); + + ck_assert(nem_transaction_write_mosaic(&ctx, "nem", "xem", 44000000)); + + keccak_256(ctx.buffer, ctx.offset, hash); + ck_assert_mem_eq( + hash, + fromhex( + "3409d9ece28d6296d6d5e220a7e3cb8641a3fb235ffcbd20c95da64f003ace6c"), + sizeof(hash)); + + // http://chain.nem.ninja/#/transfer/e90e98614c7598fbfa4db5411db1b331d157c2f86b558fb7c943d013ed9f71cb + + nem_transaction_start( + &ctx, + fromhex( + "8d07f90fb4bbe7715fa327c926770166a11be2e494a970605f2e12557f66c9b9"), + buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_transfer( + &ctx, NEM_NETWORK_MAINNET, 0, NULL, 0, 0, + "NBT3WHA2YXG2IR4PWKFFMO772JWOITTD2V4PECSB", 5175000000000, + (uint8_t *)"Good luck!", 10, false, 0)); + + keccak_256(ctx.buffer, ctx.offset, hash); + ck_assert_mem_eq( + hash, + fromhex( + "e90e98614c7598fbfa4db5411db1b331d157c2f86b558fb7c943d013ed9f71cb"), + sizeof(hash)); + + // http://chain.nem.ninja/#/transfer/40e89160e6f83d37f7c82defc0afe2c1605ae8c919134570a51dd27ea1bb516c + + nem_transaction_start( + &ctx, + fromhex( + "f85ab43dad059b9d2331ddacc384ad925d3467f03207182e01296bacfb242d01"), + buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_transfer( + &ctx, NEM_NETWORK_MAINNET, 77229, NULL, 30000000, 80829, + "NALICEPFLZQRZGPRIJTMJOCPWDNECXTNNG7QLSG3", 30000000, + fromhex("4d9dcf9186967d30be93d6d5404ded22812dbbae7c3f0de5" + "01bcd7228cba45bded13000eec7b4c6215fc4d3588168c92" + "18167cec98e6977359153a4132e050f594548e61e0dc61c1" + "53f0f53c5e65c595239c9eb7c4e7d48e0f4bb8b1dd2f5ddc"), + 96, true, 0)); + + keccak_256(ctx.buffer, ctx.offset, hash); + ck_assert_mem_eq( + hash, + fromhex( + "40e89160e6f83d37f7c82defc0afe2c1605ae8c919134570a51dd27ea1bb516c"), + sizeof(hash)); + + // http://chain.nem.ninja/#/transfer/882dca18dcbe075e15e0ec5a1d7e6ccd69cc0f1309ffd3fde227bfbc107b3f6e + + nem_transaction_start( + &ctx, + fromhex( + "f85ab43dad059b9d2331ddacc384ad925d3467f03207182e01296bacfb242d01"), + buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_transfer( + &ctx, NEM_NETWORK_MAINNET, 26730750, NULL, 179500000, 26734350, + "NBE223WPKEBHQPCYUC4U4CDUQCRRFMPZLOQLB5OP", 1000000, + (uint8_t *)"enjoy! :)", 9, false, 1)); + + ck_assert(nem_transaction_write_mosaic(&ctx, "imre.g", "tokens", 1)); + + keccak_256(ctx.buffer, ctx.offset, hash); + ck_assert_mem_eq( + hash, + fromhex( + "882dca18dcbe075e15e0ec5a1d7e6ccd69cc0f1309ffd3fde227bfbc107b3f6e"), + sizeof(hash)); } END_TEST -START_TEST(test_nem_transaction_multisig) -{ - nem_transaction_ctx ctx, other_trans; - - uint8_t buffer[1024], inner[1024]; - const uint8_t *signature; - - // http://bob.nem.ninja:8765/#/multisig/7d3a7087023ee29005262016706818579a2b5499eb9ca76bad98c1e6f4c46642 - - nem_transaction_start(&other_trans, fromhex("abac2ee3d4aaa7a3bfb65261a00cc04c761521527dd3f2cf741e2815cbba83ac"), inner, sizeof(inner)); - - ck_assert(nem_transaction_create_aggregate_modification(&other_trans, - NEM_NETWORK_TESTNET, 3939039, NULL, 16000000, 3960639, - 1, false)); - - ck_assert(nem_transaction_write_cosignatory_modification(&other_trans, 2, fromhex("e6cff9b3725a91f31089c3acca0fac3e341c00b1c8c6e9578f66c4514509c3b3"))); - - nem_transaction_start(&ctx, fromhex("59d89076964742ef2a2089d26a5aa1d2c7a7bb052a46c1de159891e91ad3d76e"), buffer, sizeof(buffer)); - - ck_assert(nem_transaction_create_multisig(&ctx, - NEM_NETWORK_TESTNET, 3939039, NULL, 6000000, 3960639, - &other_trans)); - - signature = fromhex("933930a8828b560168bddb3137df9252048678d829aa5135fa27bb306ff6562efb92755462988b852b0314bde058487d00e47816b6fb7df6bcfd7e1f150d1d00"); - ck_assert_int_eq(ed25519_sign_open_keccak(ctx.buffer, ctx.offset, ctx.public_key, signature), 0); - - nem_transaction_start(&ctx, fromhex("71cba4f2a28fd19f902ba40e9937994154d9eeaad0631d25d525ec37922567d4"), buffer, sizeof(buffer)); - - ck_assert(nem_transaction_create_multisig_signature(&ctx, - NEM_NETWORK_TESTNET, 3939891, NULL, 6000000, 3961491, - &other_trans)); - - signature = fromhex("a849f13bfeeba808a8a4a79d579febe584d831a3a6ad03da3b9d008530b3d7a79fcf7156121cd7ee847029d94af7ea7a683ca8e643dc5e5f489557c2054b830b"); - ck_assert_int_eq(ed25519_sign_open_keccak(ctx.buffer, ctx.offset, ctx.public_key, signature), 0); - - // http://chain.nem.ninja/#/multisig/1016cf3bdd61bd57b9b2b07b6ff2dee390279d8d899265bdc23d42360abe2e6c - - nem_transaction_start(&other_trans, fromhex("a1df5306355766bd2f9a64efdc089eb294be265987b3359093ae474c051d7d5a"), inner, sizeof(inner)); - - ck_assert(nem_transaction_create_provision_namespace(&other_trans, - NEM_NETWORK_MAINNET, 59414272, NULL, 20000000, 59500672, - "dim", NULL, - "NAMESPACEWH4MKFMBCVFERDPOOP4FK7MTBXDPZZA", 5000000000)); - - nem_transaction_start(&ctx, fromhex("cfe58463f0eaebceb5d00717f8aead49171a5d7c08f6b1299bd534f11715acc9"), buffer, sizeof(buffer)); - - ck_assert(nem_transaction_create_multisig(&ctx, - NEM_NETWORK_MAINNET, 59414272, NULL, 6000000, 59500672, - &other_trans)); - - signature = fromhex("52a876a37511068fe214bd710b2284823921ec7318c01e083419a062eae5369c9c11c3abfdb590f65c717fab82873431d52be62e10338cb5656d1833bbdac70c"); - ck_assert_int_eq(ed25519_sign_open_keccak(ctx.buffer, ctx.offset, ctx.public_key, signature), 0); - - nem_transaction_start(&ctx, fromhex("1b49b80203007117d034e45234ffcdf402c044aeef6dbb06351f346ca892bce2"), buffer, sizeof(buffer)); - - ck_assert(nem_transaction_create_multisig_signature(&ctx, - NEM_NETWORK_MAINNET, 59414342, NULL, 6000000, 59500742, - &other_trans)); - - signature = fromhex("b9a59239e5d06992c28840034ff7a7f13da9c4e6f4a6f72c1b1806c3b602f83a7d727a345371f5d15abf958208a32359c6dd77bde92273ada8ea6fda3dc76b00"); - ck_assert_int_eq(ed25519_sign_open_keccak(ctx.buffer, ctx.offset, ctx.public_key, signature), 0); - - nem_transaction_start(&ctx, fromhex("7ba4b39209f1b9846b098fe43f74381e43cb2882ccde780f558a63355840aa87"), buffer, sizeof(buffer)); - - ck_assert(nem_transaction_create_multisig_signature(&ctx, - NEM_NETWORK_MAINNET, 59414381, NULL, 6000000, 59500781, - &other_trans)); - - signature = fromhex("e874ae9f069f0538008631d2df9f2e8a59944ff182e8672f743d2700fb99224aafb7a0ab09c4e9ea39ee7c8ca04a8a3d6103ae1122d87772e871761d4f00ca01"); - ck_assert_int_eq(ed25519_sign_open_keccak(ctx.buffer, ctx.offset, ctx.public_key, signature), 0); +START_TEST(test_nem_transaction_multisig) { + nem_transaction_ctx ctx, other_trans; + + uint8_t buffer[1024], inner[1024]; + const uint8_t *signature; + + // http://bob.nem.ninja:8765/#/multisig/7d3a7087023ee29005262016706818579a2b5499eb9ca76bad98c1e6f4c46642 + + nem_transaction_start( + &other_trans, + fromhex( + "abac2ee3d4aaa7a3bfb65261a00cc04c761521527dd3f2cf741e2815cbba83ac"), + inner, sizeof(inner)); + + ck_assert(nem_transaction_create_aggregate_modification( + &other_trans, NEM_NETWORK_TESTNET, 3939039, NULL, 16000000, 3960639, 1, + false)); + + ck_assert(nem_transaction_write_cosignatory_modification( + &other_trans, 2, + fromhex( + "e6cff9b3725a91f31089c3acca0fac3e341c00b1c8c6e9578f66c4514509c3b3"))); + + nem_transaction_start( + &ctx, + fromhex( + "59d89076964742ef2a2089d26a5aa1d2c7a7bb052a46c1de159891e91ad3d76e"), + buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_multisig(&ctx, NEM_NETWORK_TESTNET, 3939039, + NULL, 6000000, 3960639, + &other_trans)); + + signature = fromhex( + "933930a8828b560168bddb3137df9252048678d829aa5135fa27bb306ff6562efb927554" + "62988b852b0314bde058487d00e47816b6fb7df6bcfd7e1f150d1d00"); + ck_assert_int_eq(ed25519_sign_open_keccak(ctx.buffer, ctx.offset, + ctx.public_key, signature), + 0); + + nem_transaction_start( + &ctx, + fromhex( + "71cba4f2a28fd19f902ba40e9937994154d9eeaad0631d25d525ec37922567d4"), + buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_multisig_signature(&ctx, NEM_NETWORK_TESTNET, + 3939891, NULL, 6000000, + 3961491, &other_trans)); + + signature = fromhex( + "a849f13bfeeba808a8a4a79d579febe584d831a3a6ad03da3b9d008530b3d7a79fcf7156" + "121cd7ee847029d94af7ea7a683ca8e643dc5e5f489557c2054b830b"); + ck_assert_int_eq(ed25519_sign_open_keccak(ctx.buffer, ctx.offset, + ctx.public_key, signature), + 0); + + // http://chain.nem.ninja/#/multisig/1016cf3bdd61bd57b9b2b07b6ff2dee390279d8d899265bdc23d42360abe2e6c + + nem_transaction_start( + &other_trans, + fromhex( + "a1df5306355766bd2f9a64efdc089eb294be265987b3359093ae474c051d7d5a"), + inner, sizeof(inner)); + + ck_assert(nem_transaction_create_provision_namespace( + &other_trans, NEM_NETWORK_MAINNET, 59414272, NULL, 20000000, 59500672, + "dim", NULL, "NAMESPACEWH4MKFMBCVFERDPOOP4FK7MTBXDPZZA", 5000000000)); + + nem_transaction_start( + &ctx, + fromhex( + "cfe58463f0eaebceb5d00717f8aead49171a5d7c08f6b1299bd534f11715acc9"), + buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_multisig(&ctx, NEM_NETWORK_MAINNET, 59414272, + NULL, 6000000, 59500672, + &other_trans)); + + signature = fromhex( + "52a876a37511068fe214bd710b2284823921ec7318c01e083419a062eae5369c9c11c3ab" + "fdb590f65c717fab82873431d52be62e10338cb5656d1833bbdac70c"); + ck_assert_int_eq(ed25519_sign_open_keccak(ctx.buffer, ctx.offset, + ctx.public_key, signature), + 0); + + nem_transaction_start( + &ctx, + fromhex( + "1b49b80203007117d034e45234ffcdf402c044aeef6dbb06351f346ca892bce2"), + buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_multisig_signature(&ctx, NEM_NETWORK_MAINNET, + 59414342, NULL, 6000000, + 59500742, &other_trans)); + + signature = fromhex( + "b9a59239e5d06992c28840034ff7a7f13da9c4e6f4a6f72c1b1806c3b602f83a7d727a34" + "5371f5d15abf958208a32359c6dd77bde92273ada8ea6fda3dc76b00"); + ck_assert_int_eq(ed25519_sign_open_keccak(ctx.buffer, ctx.offset, + ctx.public_key, signature), + 0); + + nem_transaction_start( + &ctx, + fromhex( + "7ba4b39209f1b9846b098fe43f74381e43cb2882ccde780f558a63355840aa87"), + buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_multisig_signature(&ctx, NEM_NETWORK_MAINNET, + 59414381, NULL, 6000000, + 59500781, &other_trans)); + + signature = fromhex( + "e874ae9f069f0538008631d2df9f2e8a59944ff182e8672f743d2700fb99224aafb7a0ab" + "09c4e9ea39ee7c8ca04a8a3d6103ae1122d87772e871761d4f00ca01"); + ck_assert_int_eq(ed25519_sign_open_keccak(ctx.buffer, ctx.offset, + ctx.public_key, signature), + 0); } END_TEST -START_TEST(test_nem_transaction_provision_namespace) -{ - nem_transaction_ctx ctx; - - uint8_t buffer[1024], hash[SHA3_256_DIGEST_LENGTH]; - - // http://bob.nem.ninja:8765/#/namespace/f7cab28da57204d01a907c697836577a4ae755e6c9bac60dcc318494a22debb3 - - nem_transaction_start(&ctx, fromhex("84afa1bbc993b7f5536344914dde86141e61f8cbecaf8c9cefc07391f3287cf5"), buffer, sizeof(buffer)); - - ck_assert(nem_transaction_create_provision_namespace(&ctx, - NEM_NETWORK_TESTNET, 56999445, NULL, 20000000, 57003045, - "gimre", NULL, - "TAMESPACEWH4MKFMBCVFERDPOOP4FK7MTDJEYP35", 5000000000)); - - keccak_256(ctx.buffer, ctx.offset, hash); - ck_assert_mem_eq(hash, fromhex("f7cab28da57204d01a907c697836577a4ae755e6c9bac60dcc318494a22debb3"), sizeof(hash)); - - // http://bob.nem.ninja:8765/#/namespace/7ddd5fe607e1bfb5606e0ac576024c318c8300d237273117d4db32a60c49524d - - nem_transaction_start(&ctx, fromhex("244fa194e2509ac0d2fbc18779c2618d8c2ebb61c16a3bcbebcf448c661ba8dc"), buffer, sizeof(buffer)); - - ck_assert(nem_transaction_create_provision_namespace(&ctx, - NEM_NETWORK_TESTNET, 21496797, NULL, 108000000, 21500397, - "misc", "alice", - "TAMESPACEWH4MKFMBCVFERDPOOP4FK7MTDJEYP35", 5000000000)); - - keccak_256(ctx.buffer, ctx.offset, hash); - ck_assert_mem_eq(hash, fromhex("7ddd5fe607e1bfb5606e0ac576024c318c8300d237273117d4db32a60c49524d"), sizeof(hash)); - - // http://chain.nem.ninja/#/namespace/57071aad93ca125dc231dc02c07ad8610cd243d35068f9b36a7d231383907569 - - nem_transaction_start(&ctx, fromhex("9f3c14f304309c8b72b2821339c4428793b1518bea72d58dd01f19d523518614"), buffer, sizeof(buffer)); - - ck_assert(nem_transaction_create_provision_namespace(&ctx, - NEM_NETWORK_MAINNET, 26699717, NULL, 108000000, 26703317, - "sex", NULL, - "NAMESPACEWH4MKFMBCVFERDPOOP4FK7MTBXDPZZA", 50000000000)); - - keccak_256(ctx.buffer, ctx.offset, hash); - ck_assert_mem_eq(hash, fromhex("57071aad93ca125dc231dc02c07ad8610cd243d35068f9b36a7d231383907569"), sizeof(hash)); +START_TEST(test_nem_transaction_provision_namespace) { + nem_transaction_ctx ctx; + + uint8_t buffer[1024], hash[SHA3_256_DIGEST_LENGTH]; + + // http://bob.nem.ninja:8765/#/namespace/f7cab28da57204d01a907c697836577a4ae755e6c9bac60dcc318494a22debb3 + + nem_transaction_start( + &ctx, + fromhex( + "84afa1bbc993b7f5536344914dde86141e61f8cbecaf8c9cefc07391f3287cf5"), + buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_provision_namespace( + &ctx, NEM_NETWORK_TESTNET, 56999445, NULL, 20000000, 57003045, "gimre", + NULL, "TAMESPACEWH4MKFMBCVFERDPOOP4FK7MTDJEYP35", 5000000000)); + + keccak_256(ctx.buffer, ctx.offset, hash); + ck_assert_mem_eq( + hash, + fromhex( + "f7cab28da57204d01a907c697836577a4ae755e6c9bac60dcc318494a22debb3"), + sizeof(hash)); + + // http://bob.nem.ninja:8765/#/namespace/7ddd5fe607e1bfb5606e0ac576024c318c8300d237273117d4db32a60c49524d + + nem_transaction_start( + &ctx, + fromhex( + "244fa194e2509ac0d2fbc18779c2618d8c2ebb61c16a3bcbebcf448c661ba8dc"), + buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_provision_namespace( + &ctx, NEM_NETWORK_TESTNET, 21496797, NULL, 108000000, 21500397, "misc", + "alice", "TAMESPACEWH4MKFMBCVFERDPOOP4FK7MTDJEYP35", 5000000000)); + + keccak_256(ctx.buffer, ctx.offset, hash); + ck_assert_mem_eq( + hash, + fromhex( + "7ddd5fe607e1bfb5606e0ac576024c318c8300d237273117d4db32a60c49524d"), + sizeof(hash)); + + // http://chain.nem.ninja/#/namespace/57071aad93ca125dc231dc02c07ad8610cd243d35068f9b36a7d231383907569 + + nem_transaction_start( + &ctx, + fromhex( + "9f3c14f304309c8b72b2821339c4428793b1518bea72d58dd01f19d523518614"), + buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_provision_namespace( + &ctx, NEM_NETWORK_MAINNET, 26699717, NULL, 108000000, 26703317, "sex", + NULL, "NAMESPACEWH4MKFMBCVFERDPOOP4FK7MTBXDPZZA", 50000000000)); + + keccak_256(ctx.buffer, ctx.offset, hash); + ck_assert_mem_eq( + hash, + fromhex( + "57071aad93ca125dc231dc02c07ad8610cd243d35068f9b36a7d231383907569"), + sizeof(hash)); } END_TEST -START_TEST(test_nem_transaction_mosaic_creation) -{ - nem_transaction_ctx ctx; - - uint8_t buffer[1024], hash[SHA3_256_DIGEST_LENGTH]; - - // http://bob.nem.ninja:8765/#/mosaic/68364353c29105e6d361ad1a42abbccbf419cfc7adb8b74c8f35d8f8bdaca3fa/0 - - nem_transaction_start(&ctx, fromhex("994793ba1c789fa9bdea918afc9b06e2d0309beb1081ac5b6952991e4defd324"), buffer, sizeof(buffer)); - - ck_assert(nem_transaction_create_mosaic_creation(&ctx, - NEM_NETWORK_TESTNET, 14070896, NULL, 108000000, 14074496, - "gimre.games.pong", "paddles", - "Paddles for the bong game.\n", - 0, 10000, true, true, - 0, 0, NULL, NULL, NULL, - "TBMOSAICOD4F54EE5CDMR23CCBGOAM2XSJBR5OLC", 50000000000)); - - keccak_256(ctx.buffer, ctx.offset, hash); - ck_assert_mem_eq(hash, fromhex("68364353c29105e6d361ad1a42abbccbf419cfc7adb8b74c8f35d8f8bdaca3fa"), sizeof(hash)); - - // http://bob.nem.ninja:8765/#/mosaic/b2f4a98113ff1f3a8f1e9d7197aa982545297fe0aa3fa6094af8031569953a55/0 - - nem_transaction_start(&ctx, fromhex("244fa194e2509ac0d2fbc18779c2618d8c2ebb61c16a3bcbebcf448c661ba8dc"), buffer, sizeof(buffer)); - - ck_assert(nem_transaction_create_mosaic_creation(&ctx, - NEM_NETWORK_TESTNET, 21497248, NULL, 108000000, 21500848, - "alice.misc", "bar", - "Special offer: get one bar extra by bying one foo!", - 0, 1000, false, true, - 1, 1, "TALICE2GMA34CXHD7XLJQ536NM5UNKQHTORNNT2J", "nem", "xem", - "TBMOSAICOD4F54EE5CDMR23CCBGOAM2XSJBR5OLC", 50000000000)); - - keccak_256(ctx.buffer, ctx.offset, hash); - ck_assert_mem_eq(hash, fromhex("b2f4a98113ff1f3a8f1e9d7197aa982545297fe0aa3fa6094af8031569953a55"), sizeof(hash)); - - // http://chain.nem.ninja/#/mosaic/269c6fda657aba3053a0e5b138c075808cc20e244e1182d9b730798b60a1f77b/0 - - nem_transaction_start(&ctx, fromhex("58956ac77951622dc5f1c938affbf017c458e30e6b21ddb5783d38b302531f23"), buffer, sizeof(buffer)); - - ck_assert(nem_transaction_create_mosaic_creation(&ctx, - NEM_NETWORK_MAINNET, 26729938, NULL, 108000000, 26733538, - "jabo38", "red_token", - "This token is to celebrate the release of Namespaces and Mosaics on the NEM system. " - "This token was the fist ever mosaic created other than nem.xem. " - "There are only 10,000 Red Tokens that will ever be created. " - "It has no levy and can be traded freely among third parties.", - 2, 10000, false, true, - 0, 0, NULL, NULL, NULL, - "NBMOSAICOD4F54EE5CDMR23CCBGOAM2XSIUX6TRS", 50000000000)); - - keccak_256(ctx.buffer, ctx.offset, hash); - ck_assert_mem_eq(hash, fromhex("269c6fda657aba3053a0e5b138c075808cc20e244e1182d9b730798b60a1f77b"), sizeof(hash)); - - // http://chain.nem.ninja/#/mosaic/e8dc14821dbea4831d9051f86158ef348001447968fc22c01644fdaf2bda75c6/0 - - nem_transaction_start(&ctx, fromhex("a1df5306355766bd2f9a64efdc089eb294be265987b3359093ae474c051d7d5a"), buffer, sizeof(buffer)); - - ck_assert(nem_transaction_create_mosaic_creation(&ctx, - NEM_NETWORK_MAINNET, 69251020, NULL, 20000000, 69337420, - "dim", "coin", - "DIM COIN", - 6, 9000000000, false, true, - 2, 10, "NCGGLVO2G3CUACVI5GNX2KRBJSQCN4RDL2ZWJ4DP", "dim", "coin", - "NBMOSAICOD4F54EE5CDMR23CCBGOAM2XSIUX6TRS", 500000000)); - - keccak_256(ctx.buffer, ctx.offset, hash); - ck_assert_mem_eq(hash, fromhex("e8dc14821dbea4831d9051f86158ef348001447968fc22c01644fdaf2bda75c6"), sizeof(hash)); +START_TEST(test_nem_transaction_mosaic_creation) { + nem_transaction_ctx ctx; + + uint8_t buffer[1024], hash[SHA3_256_DIGEST_LENGTH]; + + // http://bob.nem.ninja:8765/#/mosaic/68364353c29105e6d361ad1a42abbccbf419cfc7adb8b74c8f35d8f8bdaca3fa/0 + + nem_transaction_start( + &ctx, + fromhex( + "994793ba1c789fa9bdea918afc9b06e2d0309beb1081ac5b6952991e4defd324"), + buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_mosaic_creation( + &ctx, NEM_NETWORK_TESTNET, 14070896, NULL, 108000000, 14074496, + "gimre.games.pong", "paddles", "Paddles for the bong game.\n", 0, 10000, + true, true, 0, 0, NULL, NULL, NULL, + "TBMOSAICOD4F54EE5CDMR23CCBGOAM2XSJBR5OLC", 50000000000)); + + keccak_256(ctx.buffer, ctx.offset, hash); + ck_assert_mem_eq( + hash, + fromhex( + "68364353c29105e6d361ad1a42abbccbf419cfc7adb8b74c8f35d8f8bdaca3fa"), + sizeof(hash)); + + // http://bob.nem.ninja:8765/#/mosaic/b2f4a98113ff1f3a8f1e9d7197aa982545297fe0aa3fa6094af8031569953a55/0 + + nem_transaction_start( + &ctx, + fromhex( + "244fa194e2509ac0d2fbc18779c2618d8c2ebb61c16a3bcbebcf448c661ba8dc"), + buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_mosaic_creation( + &ctx, NEM_NETWORK_TESTNET, 21497248, NULL, 108000000, 21500848, + "alice.misc", "bar", "Special offer: get one bar extra by bying one foo!", + 0, 1000, false, true, 1, 1, "TALICE2GMA34CXHD7XLJQ536NM5UNKQHTORNNT2J", + "nem", "xem", "TBMOSAICOD4F54EE5CDMR23CCBGOAM2XSJBR5OLC", 50000000000)); + + keccak_256(ctx.buffer, ctx.offset, hash); + ck_assert_mem_eq( + hash, + fromhex( + "b2f4a98113ff1f3a8f1e9d7197aa982545297fe0aa3fa6094af8031569953a55"), + sizeof(hash)); + + // http://chain.nem.ninja/#/mosaic/269c6fda657aba3053a0e5b138c075808cc20e244e1182d9b730798b60a1f77b/0 + + nem_transaction_start( + &ctx, + fromhex( + "58956ac77951622dc5f1c938affbf017c458e30e6b21ddb5783d38b302531f23"), + buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_mosaic_creation( + &ctx, NEM_NETWORK_MAINNET, 26729938, NULL, 108000000, 26733538, "jabo38", + "red_token", + "This token is to celebrate the release of Namespaces and Mosaics on the " + "NEM system. " + "This token was the fist ever mosaic created other than nem.xem. " + "There are only 10,000 Red Tokens that will ever be created. " + "It has no levy and can be traded freely among third parties.", + 2, 10000, false, true, 0, 0, NULL, NULL, NULL, + "NBMOSAICOD4F54EE5CDMR23CCBGOAM2XSIUX6TRS", 50000000000)); + + keccak_256(ctx.buffer, ctx.offset, hash); + ck_assert_mem_eq( + hash, + fromhex( + "269c6fda657aba3053a0e5b138c075808cc20e244e1182d9b730798b60a1f77b"), + sizeof(hash)); + + // http://chain.nem.ninja/#/mosaic/e8dc14821dbea4831d9051f86158ef348001447968fc22c01644fdaf2bda75c6/0 + + nem_transaction_start( + &ctx, + fromhex( + "a1df5306355766bd2f9a64efdc089eb294be265987b3359093ae474c051d7d5a"), + buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_mosaic_creation( + &ctx, NEM_NETWORK_MAINNET, 69251020, NULL, 20000000, 69337420, "dim", + "coin", "DIM COIN", 6, 9000000000, false, true, 2, 10, + "NCGGLVO2G3CUACVI5GNX2KRBJSQCN4RDL2ZWJ4DP", "dim", "coin", + "NBMOSAICOD4F54EE5CDMR23CCBGOAM2XSIUX6TRS", 500000000)); + + keccak_256(ctx.buffer, ctx.offset, hash); + ck_assert_mem_eq( + hash, + fromhex( + "e8dc14821dbea4831d9051f86158ef348001447968fc22c01644fdaf2bda75c6"), + sizeof(hash)); } END_TEST -START_TEST(test_nem_transaction_mosaic_supply_change) -{ - nem_transaction_ctx ctx; - - uint8_t buffer[1024], hash[SHA3_256_DIGEST_LENGTH]; - - // http://bigalice2.nem.ninja:7890/transaction/get?hash=33a50fdd4a54913643a580b2af08b9a5b51b7cee922bde380e84c573a7969c50 - - nem_transaction_start(&ctx, fromhex("994793ba1c789fa9bdea918afc9b06e2d0309beb1081ac5b6952991e4defd324"), buffer, sizeof(buffer)); - - ck_assert(nem_transaction_create_mosaic_supply_change(&ctx, - NEM_NETWORK_TESTNET, 14071648, NULL, 108000000, 14075248, - "gimre.games.pong", "paddles", - 1, 1234)); - - keccak_256(ctx.buffer, ctx.offset, hash); - ck_assert_mem_eq(hash, fromhex("33a50fdd4a54913643a580b2af08b9a5b51b7cee922bde380e84c573a7969c50"), sizeof(hash)); - - // http://bigalice2.nem.ninja:7890/transaction/get?hash=1ce8e8894d077a66ff22294b000825d090a60742ec407efd80eb8b19657704f2 - - nem_transaction_start(&ctx, fromhex("84afa1bbc993b7f5536344914dde86141e61f8cbecaf8c9cefc07391f3287cf5"), buffer, sizeof(buffer)); - - ck_assert(nem_transaction_create_mosaic_supply_change(&ctx, - NEM_NETWORK_TESTNET, 14126909, NULL, 108000000, 14130509, - "jabo38_ltd.fuzzy_kittens_cafe", "coupons", - 2, 1)); - - keccak_256(ctx.buffer, ctx.offset, hash); - ck_assert_mem_eq(hash, fromhex("1ce8e8894d077a66ff22294b000825d090a60742ec407efd80eb8b19657704f2"), sizeof(hash)); - - // http://bigalice3.nem.ninja:7890/transaction/get?hash=694e493e9576d2bcf60d85747e302ac2e1cc27783187947180d4275a713ff1ff - - nem_transaction_start(&ctx, fromhex("b7ccc27b21ba6cf5c699a8dc86ba6ba98950442597ff9fa30e0abe0f5f4dd05d"), buffer, sizeof(buffer)); - - ck_assert(nem_transaction_create_mosaic_supply_change(&ctx, - NEM_NETWORK_MAINNET, 53377685, NULL, 20000000, 53464085, - "abvapp", "abv", - 1, 9000000)); - - keccak_256(ctx.buffer, ctx.offset, hash); - ck_assert_mem_eq(hash, fromhex("694e493e9576d2bcf60d85747e302ac2e1cc27783187947180d4275a713ff1ff"), sizeof(hash)); - - // http://bigalice3.nem.ninja:7890/transaction/get?hash=09836334e123970e068d5b411e4d1df54a3ead10acf1ad5935a2cdd9f9680185 - - nem_transaction_start(&ctx, fromhex("75f001a8641e2ce5c4386883dda561399ed346177411b492a677b73899502f13"), buffer, sizeof(buffer)); - - ck_assert(nem_transaction_create_mosaic_supply_change(&ctx, - NEM_NETWORK_MAINNET, 55176304, NULL, 20000000, 55262704, - "sushi", "wasabi", - 2, 20)); - - keccak_256(ctx.buffer, ctx.offset, hash); - ck_assert_mem_eq(hash, fromhex("09836334e123970e068d5b411e4d1df54a3ead10acf1ad5935a2cdd9f9680185"), sizeof(hash)); +START_TEST(test_nem_transaction_mosaic_supply_change) { + nem_transaction_ctx ctx; + + uint8_t buffer[1024], hash[SHA3_256_DIGEST_LENGTH]; + + // http://bigalice2.nem.ninja:7890/transaction/get?hash=33a50fdd4a54913643a580b2af08b9a5b51b7cee922bde380e84c573a7969c50 + + nem_transaction_start( + &ctx, + fromhex( + "994793ba1c789fa9bdea918afc9b06e2d0309beb1081ac5b6952991e4defd324"), + buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_mosaic_supply_change( + &ctx, NEM_NETWORK_TESTNET, 14071648, NULL, 108000000, 14075248, + "gimre.games.pong", "paddles", 1, 1234)); + + keccak_256(ctx.buffer, ctx.offset, hash); + ck_assert_mem_eq( + hash, + fromhex( + "33a50fdd4a54913643a580b2af08b9a5b51b7cee922bde380e84c573a7969c50"), + sizeof(hash)); + + // http://bigalice2.nem.ninja:7890/transaction/get?hash=1ce8e8894d077a66ff22294b000825d090a60742ec407efd80eb8b19657704f2 + + nem_transaction_start( + &ctx, + fromhex( + "84afa1bbc993b7f5536344914dde86141e61f8cbecaf8c9cefc07391f3287cf5"), + buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_mosaic_supply_change( + &ctx, NEM_NETWORK_TESTNET, 14126909, NULL, 108000000, 14130509, + "jabo38_ltd.fuzzy_kittens_cafe", "coupons", 2, 1)); + + keccak_256(ctx.buffer, ctx.offset, hash); + ck_assert_mem_eq( + hash, + fromhex( + "1ce8e8894d077a66ff22294b000825d090a60742ec407efd80eb8b19657704f2"), + sizeof(hash)); + + // http://bigalice3.nem.ninja:7890/transaction/get?hash=694e493e9576d2bcf60d85747e302ac2e1cc27783187947180d4275a713ff1ff + + nem_transaction_start( + &ctx, + fromhex( + "b7ccc27b21ba6cf5c699a8dc86ba6ba98950442597ff9fa30e0abe0f5f4dd05d"), + buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_mosaic_supply_change( + &ctx, NEM_NETWORK_MAINNET, 53377685, NULL, 20000000, 53464085, "abvapp", + "abv", 1, 9000000)); + + keccak_256(ctx.buffer, ctx.offset, hash); + ck_assert_mem_eq( + hash, + fromhex( + "694e493e9576d2bcf60d85747e302ac2e1cc27783187947180d4275a713ff1ff"), + sizeof(hash)); + + // http://bigalice3.nem.ninja:7890/transaction/get?hash=09836334e123970e068d5b411e4d1df54a3ead10acf1ad5935a2cdd9f9680185 + + nem_transaction_start( + &ctx, + fromhex( + "75f001a8641e2ce5c4386883dda561399ed346177411b492a677b73899502f13"), + buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_mosaic_supply_change( + &ctx, NEM_NETWORK_MAINNET, 55176304, NULL, 20000000, 55262704, "sushi", + "wasabi", 2, 20)); + + keccak_256(ctx.buffer, ctx.offset, hash); + ck_assert_mem_eq( + hash, + fromhex( + "09836334e123970e068d5b411e4d1df54a3ead10acf1ad5935a2cdd9f9680185"), + sizeof(hash)); } END_TEST -START_TEST(test_nem_transaction_aggregate_modification) -{ - nem_transaction_ctx ctx; - - uint8_t buffer[1024], hash[SHA3_256_DIGEST_LENGTH]; - - // http://bob.nem.ninja:8765/#/aggregate/6a55471b17159e5b6cd579c421e95a4e39d92e3f78b0a55ee337e785a601d3a2 - - nem_transaction_start(&ctx, fromhex("462ee976890916e54fa825d26bdd0235f5eb5b6a143c199ab0ae5ee9328e08ce"), buffer, sizeof(buffer)); - - ck_assert(nem_transaction_create_aggregate_modification(&ctx, - NEM_NETWORK_TESTNET, 0, NULL, 22000000, 0, - 2, false)); - - ck_assert(nem_transaction_write_cosignatory_modification(&ctx, 1, fromhex("994793ba1c789fa9bdea918afc9b06e2d0309beb1081ac5b6952991e4defd324"))); - ck_assert(nem_transaction_write_cosignatory_modification(&ctx, 1, fromhex("c54d6e33ed1446eedd7f7a80a588dd01857f723687a09200c1917d5524752f8b"))); - - keccak_256(ctx.buffer, ctx.offset, hash); - ck_assert_mem_eq(hash, fromhex("6a55471b17159e5b6cd579c421e95a4e39d92e3f78b0a55ee337e785a601d3a2"), sizeof(hash)); - - // http://bob.nem.ninja:8765/#/aggregate/1fbdae5ba753e68af270930413ae90f671eb8ab58988116684bac0abd5726584 - - nem_transaction_start(&ctx, fromhex("6bf7849c1eec6a2002995cc457dc00c4e29bad5c88de63f51e42dfdcd7b2131d"), buffer, sizeof(buffer)); - - ck_assert(nem_transaction_create_aggregate_modification(&ctx, - NEM_NETWORK_TESTNET, 6542254, NULL, 40000000, 6545854, - 4, true)); - - ck_assert(nem_transaction_write_cosignatory_modification(&ctx, 1, fromhex("5f53d076c8c3ec3110b98364bc423092c3ec2be2b1b3c40fd8ab68d54fa39295"))); - ck_assert(nem_transaction_write_cosignatory_modification(&ctx, 1, fromhex("9eb199c2b4d406f64cb7aa5b2b0815264b56ba8fe44d558a6cb423a31a33c4c2"))); - ck_assert(nem_transaction_write_cosignatory_modification(&ctx, 1, fromhex("94b2323dab23a3faba24fa6ddda0ece4fbb06acfedd74e76ad9fae38d006882b"))); - ck_assert(nem_transaction_write_cosignatory_modification(&ctx, 1, fromhex("d88c6ee2a2cd3929d0d76b6b14ecb549d21296ab196a2b3a4cb2536bcce32e87"))); - - ck_assert(nem_transaction_write_minimum_cosignatories(&ctx, 2)); - - keccak_256(ctx.buffer, ctx.offset, hash); - ck_assert_mem_eq(hash, fromhex("1fbdae5ba753e68af270930413ae90f671eb8ab58988116684bac0abd5726584"), sizeof(hash)); - - // http://chain.nem.ninja/#/aggregate/cc64ca69bfa95db2ff7ac1e21fe6d27ece189c603200ebc9778d8bb80ca25c3c - - nem_transaction_start(&ctx, fromhex("f41b99320549741c5cce42d9e4bb836d98c50ed5415d0c3c2912d1bb50e6a0e5"), buffer, sizeof(buffer)); - - ck_assert(nem_transaction_create_aggregate_modification(&ctx, - NEM_NETWORK_MAINNET, 0, NULL, 40000000, 0, - 5, false)); - - ck_assert(nem_transaction_write_cosignatory_modification(&ctx, 1, fromhex("1fbdbdde28daf828245e4533765726f0b7790e0b7146e2ce205df3e86366980b"))); - ck_assert(nem_transaction_write_cosignatory_modification(&ctx, 1, fromhex("f94e8702eb1943b23570b1b83be1b81536df35538978820e98bfce8f999e2d37"))); - ck_assert(nem_transaction_write_cosignatory_modification(&ctx, 1, fromhex("826cedee421ff66e708858c17815fcd831a4bb68e3d8956299334e9e24380ba8"))); - ck_assert(nem_transaction_write_cosignatory_modification(&ctx, 1, fromhex("719862cd7d0f4e875a6a0274c9a1738f38f40ad9944179006a54c34724c1274d"))); - ck_assert(nem_transaction_write_cosignatory_modification(&ctx, 1, fromhex("43aa69177018fc3e2bdbeb259c81cddf24be50eef9c5386db51d82386c41475a"))); - - keccak_256(ctx.buffer, ctx.offset, hash); - ck_assert_mem_eq(hash, fromhex("cc64ca69bfa95db2ff7ac1e21fe6d27ece189c603200ebc9778d8bb80ca25c3c"), sizeof(hash)); +START_TEST(test_nem_transaction_aggregate_modification) { + nem_transaction_ctx ctx; + + uint8_t buffer[1024], hash[SHA3_256_DIGEST_LENGTH]; + + // http://bob.nem.ninja:8765/#/aggregate/6a55471b17159e5b6cd579c421e95a4e39d92e3f78b0a55ee337e785a601d3a2 + + nem_transaction_start( + &ctx, + fromhex( + "462ee976890916e54fa825d26bdd0235f5eb5b6a143c199ab0ae5ee9328e08ce"), + buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_aggregate_modification( + &ctx, NEM_NETWORK_TESTNET, 0, NULL, 22000000, 0, 2, false)); + + ck_assert(nem_transaction_write_cosignatory_modification( + &ctx, 1, + fromhex( + "994793ba1c789fa9bdea918afc9b06e2d0309beb1081ac5b6952991e4defd324"))); + ck_assert(nem_transaction_write_cosignatory_modification( + &ctx, 1, + fromhex( + "c54d6e33ed1446eedd7f7a80a588dd01857f723687a09200c1917d5524752f8b"))); + + keccak_256(ctx.buffer, ctx.offset, hash); + ck_assert_mem_eq( + hash, + fromhex( + "6a55471b17159e5b6cd579c421e95a4e39d92e3f78b0a55ee337e785a601d3a2"), + sizeof(hash)); + + // http://bob.nem.ninja:8765/#/aggregate/1fbdae5ba753e68af270930413ae90f671eb8ab58988116684bac0abd5726584 + + nem_transaction_start( + &ctx, + fromhex( + "6bf7849c1eec6a2002995cc457dc00c4e29bad5c88de63f51e42dfdcd7b2131d"), + buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_aggregate_modification( + &ctx, NEM_NETWORK_TESTNET, 6542254, NULL, 40000000, 6545854, 4, true)); + + ck_assert(nem_transaction_write_cosignatory_modification( + &ctx, 1, + fromhex( + "5f53d076c8c3ec3110b98364bc423092c3ec2be2b1b3c40fd8ab68d54fa39295"))); + ck_assert(nem_transaction_write_cosignatory_modification( + &ctx, 1, + fromhex( + "9eb199c2b4d406f64cb7aa5b2b0815264b56ba8fe44d558a6cb423a31a33c4c2"))); + ck_assert(nem_transaction_write_cosignatory_modification( + &ctx, 1, + fromhex( + "94b2323dab23a3faba24fa6ddda0ece4fbb06acfedd74e76ad9fae38d006882b"))); + ck_assert(nem_transaction_write_cosignatory_modification( + &ctx, 1, + fromhex( + "d88c6ee2a2cd3929d0d76b6b14ecb549d21296ab196a2b3a4cb2536bcce32e87"))); + + ck_assert(nem_transaction_write_minimum_cosignatories(&ctx, 2)); + + keccak_256(ctx.buffer, ctx.offset, hash); + ck_assert_mem_eq( + hash, + fromhex( + "1fbdae5ba753e68af270930413ae90f671eb8ab58988116684bac0abd5726584"), + sizeof(hash)); + + // http://chain.nem.ninja/#/aggregate/cc64ca69bfa95db2ff7ac1e21fe6d27ece189c603200ebc9778d8bb80ca25c3c + + nem_transaction_start( + &ctx, + fromhex( + "f41b99320549741c5cce42d9e4bb836d98c50ed5415d0c3c2912d1bb50e6a0e5"), + buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_aggregate_modification( + &ctx, NEM_NETWORK_MAINNET, 0, NULL, 40000000, 0, 5, false)); + + ck_assert(nem_transaction_write_cosignatory_modification( + &ctx, 1, + fromhex( + "1fbdbdde28daf828245e4533765726f0b7790e0b7146e2ce205df3e86366980b"))); + ck_assert(nem_transaction_write_cosignatory_modification( + &ctx, 1, + fromhex( + "f94e8702eb1943b23570b1b83be1b81536df35538978820e98bfce8f999e2d37"))); + ck_assert(nem_transaction_write_cosignatory_modification( + &ctx, 1, + fromhex( + "826cedee421ff66e708858c17815fcd831a4bb68e3d8956299334e9e24380ba8"))); + ck_assert(nem_transaction_write_cosignatory_modification( + &ctx, 1, + fromhex( + "719862cd7d0f4e875a6a0274c9a1738f38f40ad9944179006a54c34724c1274d"))); + ck_assert(nem_transaction_write_cosignatory_modification( + &ctx, 1, + fromhex( + "43aa69177018fc3e2bdbeb259c81cddf24be50eef9c5386db51d82386c41475a"))); + + keccak_256(ctx.buffer, ctx.offset, hash); + ck_assert_mem_eq( + hash, + fromhex( + "cc64ca69bfa95db2ff7ac1e21fe6d27ece189c603200ebc9778d8bb80ca25c3c"), + sizeof(hash)); } END_TEST -START_TEST(test_multibyte_address) -{ - uint8_t priv_key[32]; - char wif[57]; - uint8_t pub_key[33]; - char address[40]; - uint8_t decode[24]; - int res; - - memcpy(priv_key, fromhex("47f7616ea6f9b923076625b4488115de1ef1187f760e65f89eb6f4f7ff04b012"), 32); - ecdsa_get_wif(priv_key, 0, HASHER_SHA2D, wif, sizeof(wif)); ck_assert_str_eq(wif, "13QtoXmbhELWcrwD9YA9KzvXy5rTaptiNuFR8L8ArpBNn4xmQj4N"); - ecdsa_get_wif(priv_key, 0x12, HASHER_SHA2D, wif, sizeof(wif)); ck_assert_str_eq(wif, "3hrF6SFnqzpzABB36uGDf8dJSuUCcMmoJrTmCWMshRkBr2Vx86qJ"); - ecdsa_get_wif(priv_key, 0x1234, HASHER_SHA2D, wif, sizeof(wif)); ck_assert_str_eq(wif, "CtPTF9awbVbfDWGepGdVhB3nBhr4HktUGya8nf8dLxgC8tbqBreB9"); - ecdsa_get_wif(priv_key, 0x123456, HASHER_SHA2D, wif, sizeof(wif)); ck_assert_str_eq(wif, "uTrDevVQt5QZgoL3iJ1cPWHaCz7ZMBncM7QXZfCegtxiMHqBvWoYJa"); - ecdsa_get_wif(priv_key, 0x12345678, HASHER_SHA2D, wif, sizeof(wif)); ck_assert_str_eq(wif, "4zZWMzv1SVbs95pmLXWrXJVp9ntPEam1mfwb6CXBLn9MpWNxLg9huYgv"); - ecdsa_get_wif(priv_key, 0xffffffff, HASHER_SHA2D, wif, sizeof(wif)); ck_assert_str_eq(wif, "y9KVfV1RJXcTxpVjeuh6WYWh8tMwnAUeyUwDEiRviYdrJ61njTmnfUjE"); - - memcpy(pub_key, fromhex("0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71"), 33); - ecdsa_get_address(pub_key, 0, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "1C7zdTfnkzmr13HfA2vNm5SJYRK6nEKyq8"); - ecdsa_get_address(pub_key, 0x12, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "8SCrMR2yYF7ciqoDbav7VLLTsVx5dTVPPq"); - ecdsa_get_address(pub_key, 0x1234, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "ZLH8q1UgMPg8o2s1MD55YVMpPV7vqms9kiV"); - ecdsa_get_address(pub_key, 0x123456, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "3ThqvsQVFnbiF66NwHtfe2j6AKn75DpLKpQSq"); - ecdsa_get_address(pub_key, 0x12345678, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "BrsGxAHga3VbopvSnb3gmLvMBhJNCGuDxBZL44"); - ecdsa_get_address(pub_key, 0xffffffff, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, sizeof(address)); ck_assert_str_eq(address, "3diW7paWGJyZRLGqMJZ55DMfPExob8QxQHkrfYT"); - - res = ecdsa_address_decode("1C7zdTfnkzmr13HfA2vNm5SJYRK6nEKyq8", 0, HASHER_SHA2D, decode); - ck_assert_int_eq(res, 1); - ck_assert_mem_eq(decode, fromhex("0079fbfc3f34e7745860d76137da68f362380c606c"), 21); - res = ecdsa_address_decode("8SCrMR2yYF7ciqoDbav7VLLTsVx5dTVPPq", 0x12, HASHER_SHA2D, decode); - ck_assert_int_eq(res, 1); - ck_assert_mem_eq(decode, fromhex("1279fbfc3f34e7745860d76137da68f362380c606c"), 21); - res = ecdsa_address_decode("ZLH8q1UgMPg8o2s1MD55YVMpPV7vqms9kiV", 0x1234, HASHER_SHA2D, decode); - ck_assert_int_eq(res, 1); - ck_assert_mem_eq(decode, fromhex("123479fbfc3f34e7745860d76137da68f362380c606c"), 21); - res = ecdsa_address_decode("3ThqvsQVFnbiF66NwHtfe2j6AKn75DpLKpQSq", 0x123456, HASHER_SHA2D, decode); - ck_assert_int_eq(res, 1); - ck_assert_mem_eq(decode, fromhex("12345679fbfc3f34e7745860d76137da68f362380c606c"), 21); - res = ecdsa_address_decode("BrsGxAHga3VbopvSnb3gmLvMBhJNCGuDxBZL44", 0x12345678, HASHER_SHA2D, decode); - ck_assert_int_eq(res, 1); - ck_assert_mem_eq(decode, fromhex("1234567879fbfc3f34e7745860d76137da68f362380c606c"), 21); - res = ecdsa_address_decode("3diW7paWGJyZRLGqMJZ55DMfPExob8QxQHkrfYT", 0xffffffff, HASHER_SHA2D, decode); - ck_assert_int_eq(res, 1); - ck_assert_mem_eq(decode, fromhex("ffffffff79fbfc3f34e7745860d76137da68f362380c606c"), 21); - - // wrong length - res = ecdsa_address_decode("BrsGxAHga3VbopvSnb3gmLvMBhJNCGuDxBZL44", 0x123456, HASHER_SHA2D, decode); - ck_assert_int_eq(res, 0); - - // wrong address prefix - res = ecdsa_address_decode("BrsGxAHga3VbopvSnb3gmLvMBhJNCGuDxBZL44", 0x22345678, HASHER_SHA2D, decode); - ck_assert_int_eq(res, 0); - - // wrong checksum - res = ecdsa_address_decode("BrsGxAHga3VbopvSnb3gmLvMBhJNCGuDxBZL45", 0x12345678, HASHER_SHA2D, decode); - ck_assert_int_eq(res, 0); +START_TEST(test_multibyte_address) { + uint8_t priv_key[32]; + char wif[57]; + uint8_t pub_key[33]; + char address[40]; + uint8_t decode[24]; + int res; + + memcpy( + priv_key, + fromhex( + "47f7616ea6f9b923076625b4488115de1ef1187f760e65f89eb6f4f7ff04b012"), + 32); + ecdsa_get_wif(priv_key, 0, HASHER_SHA2D, wif, sizeof(wif)); + ck_assert_str_eq(wif, "13QtoXmbhELWcrwD9YA9KzvXy5rTaptiNuFR8L8ArpBNn4xmQj4N"); + ecdsa_get_wif(priv_key, 0x12, HASHER_SHA2D, wif, sizeof(wif)); + ck_assert_str_eq(wif, "3hrF6SFnqzpzABB36uGDf8dJSuUCcMmoJrTmCWMshRkBr2Vx86qJ"); + ecdsa_get_wif(priv_key, 0x1234, HASHER_SHA2D, wif, sizeof(wif)); + ck_assert_str_eq(wif, + "CtPTF9awbVbfDWGepGdVhB3nBhr4HktUGya8nf8dLxgC8tbqBreB9"); + ecdsa_get_wif(priv_key, 0x123456, HASHER_SHA2D, wif, sizeof(wif)); + ck_assert_str_eq(wif, + "uTrDevVQt5QZgoL3iJ1cPWHaCz7ZMBncM7QXZfCegtxiMHqBvWoYJa"); + ecdsa_get_wif(priv_key, 0x12345678, HASHER_SHA2D, wif, sizeof(wif)); + ck_assert_str_eq(wif, + "4zZWMzv1SVbs95pmLXWrXJVp9ntPEam1mfwb6CXBLn9MpWNxLg9huYgv"); + ecdsa_get_wif(priv_key, 0xffffffff, HASHER_SHA2D, wif, sizeof(wif)); + ck_assert_str_eq(wif, + "y9KVfV1RJXcTxpVjeuh6WYWh8tMwnAUeyUwDEiRviYdrJ61njTmnfUjE"); + + memcpy( + pub_key, + fromhex( + "0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71"), + 33); + ecdsa_get_address(pub_key, 0, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, + sizeof(address)); + ck_assert_str_eq(address, "1C7zdTfnkzmr13HfA2vNm5SJYRK6nEKyq8"); + ecdsa_get_address(pub_key, 0x12, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, + sizeof(address)); + ck_assert_str_eq(address, "8SCrMR2yYF7ciqoDbav7VLLTsVx5dTVPPq"); + ecdsa_get_address(pub_key, 0x1234, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, + sizeof(address)); + ck_assert_str_eq(address, "ZLH8q1UgMPg8o2s1MD55YVMpPV7vqms9kiV"); + ecdsa_get_address(pub_key, 0x123456, HASHER_SHA2_RIPEMD, HASHER_SHA2D, + address, sizeof(address)); + ck_assert_str_eq(address, "3ThqvsQVFnbiF66NwHtfe2j6AKn75DpLKpQSq"); + ecdsa_get_address(pub_key, 0x12345678, HASHER_SHA2_RIPEMD, HASHER_SHA2D, + address, sizeof(address)); + ck_assert_str_eq(address, "BrsGxAHga3VbopvSnb3gmLvMBhJNCGuDxBZL44"); + ecdsa_get_address(pub_key, 0xffffffff, HASHER_SHA2_RIPEMD, HASHER_SHA2D, + address, sizeof(address)); + ck_assert_str_eq(address, "3diW7paWGJyZRLGqMJZ55DMfPExob8QxQHkrfYT"); + + res = ecdsa_address_decode("1C7zdTfnkzmr13HfA2vNm5SJYRK6nEKyq8", 0, + HASHER_SHA2D, decode); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(decode, + fromhex("0079fbfc3f34e7745860d76137da68f362380c606c"), 21); + res = ecdsa_address_decode("8SCrMR2yYF7ciqoDbav7VLLTsVx5dTVPPq", 0x12, + HASHER_SHA2D, decode); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(decode, + fromhex("1279fbfc3f34e7745860d76137da68f362380c606c"), 21); + res = ecdsa_address_decode("ZLH8q1UgMPg8o2s1MD55YVMpPV7vqms9kiV", 0x1234, + HASHER_SHA2D, decode); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(decode, + fromhex("123479fbfc3f34e7745860d76137da68f362380c606c"), 21); + res = ecdsa_address_decode("3ThqvsQVFnbiF66NwHtfe2j6AKn75DpLKpQSq", 0x123456, + HASHER_SHA2D, decode); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq( + decode, fromhex("12345679fbfc3f34e7745860d76137da68f362380c606c"), 21); + res = ecdsa_address_decode("BrsGxAHga3VbopvSnb3gmLvMBhJNCGuDxBZL44", + 0x12345678, HASHER_SHA2D, decode); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq( + decode, fromhex("1234567879fbfc3f34e7745860d76137da68f362380c606c"), 21); + res = ecdsa_address_decode("3diW7paWGJyZRLGqMJZ55DMfPExob8QxQHkrfYT", + 0xffffffff, HASHER_SHA2D, decode); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq( + decode, fromhex("ffffffff79fbfc3f34e7745860d76137da68f362380c606c"), 21); + + // wrong length + res = ecdsa_address_decode("BrsGxAHga3VbopvSnb3gmLvMBhJNCGuDxBZL44", 0x123456, + HASHER_SHA2D, decode); + ck_assert_int_eq(res, 0); + + // wrong address prefix + res = ecdsa_address_decode("BrsGxAHga3VbopvSnb3gmLvMBhJNCGuDxBZL44", + 0x22345678, HASHER_SHA2D, decode); + ck_assert_int_eq(res, 0); + + // wrong checksum + res = ecdsa_address_decode("BrsGxAHga3VbopvSnb3gmLvMBhJNCGuDxBZL45", + 0x12345678, HASHER_SHA2D, decode); + ck_assert_int_eq(res, 0); } END_TEST // https://tools.ietf.org/html/rfc6229#section-2 -START_TEST(test_rc4_rfc6229) -{ - static const size_t offsets[] = { - 0x0, - 0xf0, - 0x1f0, - 0x2f0, - 0x3f0, - 0x5f0, - 0x7f0, - 0xbf0, - 0xff0, - }; - - static const struct { - char key[65]; - char vectors[sizeof(offsets) / sizeof(*offsets)][65]; - } tests[] = { - { - "0102030405", - { - "b2396305f03dc027ccc3524a0a1118a8" "6982944f18fc82d589c403a47a0d0919", - "28cb1132c96ce286421dcaadb8b69eae" "1cfcf62b03eddb641d77dfcf7f8d8c93", - "42b7d0cdd918a8a33dd51781c81f4041" "6459844432a7da923cfb3eb4980661f6", - "ec10327bde2beefd18f9277680457e22" "eb62638d4f0ba1fe9fca20e05bf8ff2b", - "45129048e6a0ed0b56b490338f078da5" "30abbcc7c20b01609f23ee2d5f6bb7df", - "3294f744d8f9790507e70f62e5bbceea" "d8729db41882259bee4f825325f5a130", - "1eb14a0c13b3bf47fa2a0ba93ad45b8b" "cc582f8ba9f265e2b1be9112e975d2d7", - "f2e30f9bd102ecbf75aaade9bc35c43c" "ec0e11c479dc329dc8da7968fe965681", - "068326a2118416d21f9d04b2cd1ca050" "ff25b58995996707e51fbdf08b34d875", - } - }, { - "01020304050607", - { - "293f02d47f37c9b633f2af5285feb46b" "e620f1390d19bd84e2e0fd752031afc1", - "914f02531c9218810df60f67e338154c" "d0fdb583073ce85ab83917740ec011d5", - "75f81411e871cffa70b90c74c592e454" "0bb87202938dad609e87a5a1b079e5e4", - "c2911246b612e7e7b903dfeda1dad866" "32828f91502b6291368de8081de36fc2", - "f3b9a7e3b297bf9ad804512f9063eff1" "8ecb67a9ba1f55a5a067e2b026a3676f", - "d2aa902bd42d0d7cfd340cd45810529f" "78b272c96e42eab4c60bd914e39d06e3", - "f4332fd31a079396ee3cee3f2a4ff049" "05459781d41fda7f30c1be7e1246c623", - "adfd3868b8e51485d5e610017e3dd609" "ad26581c0c5be45f4cea01db2f3805d5", - "f3172ceffc3b3d997c85ccd5af1a950c" "e74b0b9731227fd37c0ec08a47ddd8b8", - } - }, { - "0102030405060708", - { - "97ab8a1bf0afb96132f2f67258da15a8" "8263efdb45c4a18684ef87e6b19e5b09", - "9636ebc9841926f4f7d1f362bddf6e18" "d0a990ff2c05fef5b90373c9ff4b870a", - "73239f1db7f41d80b643c0c52518ec63" "163b319923a6bdb4527c626126703c0f", - "49d6c8af0f97144a87df21d91472f966" "44173a103b6616c5d5ad1cee40c863d0", - "273c9c4b27f322e4e716ef53a47de7a4" "c6d0e7b226259fa9023490b26167ad1d", - "1fe8986713f07c3d9ae1c163ff8cf9d3" "8369e1a965610be887fbd0c79162aafb", - "0a0127abb44484b9fbef5abcae1b579f" "c2cdadc6402e8ee866e1f37bdb47e42c", - "26b51ea37df8e1d6f76fc3b66a7429b3" "bc7683205d4f443dc1f29dda3315c87b", - "d5fa5a3469d29aaaf83d23589db8c85b" "3fb46e2c8f0f068edce8cdcd7dfc5862", - } - }, { - "0102030405060708090a", - { - "ede3b04643e586cc907dc21851709902" "03516ba78f413beb223aa5d4d2df6711", - "3cfd6cb58ee0fdde640176ad0000044d" "48532b21fb6079c9114c0ffd9c04a1ad", - "3e8cea98017109979084b1ef92f99d86" "e20fb49bdb337ee48b8d8dc0f4afeffe", - "5c2521eacd7966f15e056544bea0d315" "e067a7031931a246a6c3875d2f678acb", - "a64f70af88ae56b6f87581c0e23e6b08" "f449031de312814ec6f319291f4a0516", - "bdae85924b3cb1d0a2e33a30c6d79599" "8a0feddbac865a09bcd127fb562ed60a", - "b55a0a5b51a12a8be34899c3e047511a" "d9a09cea3ce75fe39698070317a71339", - "552225ed1177f44584ac8cfa6c4eb5fc" "7e82cbabfc95381b080998442129c2f8", - "1f135ed14ce60a91369d2322bef25e3c" "08b6be45124a43e2eb77953f84dc8553", - } - }, { - "0102030405060708090a0b0c0d0e0f10", - { - "9ac7cc9a609d1ef7b2932899cde41b97" "5248c4959014126a6e8a84f11d1a9e1c", - "065902e4b620f6cc36c8589f66432f2b" "d39d566bc6bce3010768151549f3873f", - "b6d1e6c4a5e4771cad79538df295fb11" "c68c1d5c559a974123df1dbc52a43b89", - "c5ecf88de897fd57fed301701b82a259" "eccbe13de1fcc91c11a0b26c0bc8fa4d", - "e7a72574f8782ae26aabcf9ebcd66065" "bdf0324e6083dcc6d3cedd3ca8c53c16", - "b40110c4190b5622a96116b0017ed297" "ffa0b514647ec04f6306b892ae661181", - "d03d1bc03cd33d70dff9fa5d71963ebd" "8a44126411eaa78bd51e8d87a8879bf5", - "fabeb76028ade2d0e48722e46c4615a3" "c05d88abd50357f935a63c59ee537623", - "ff38265c1642c1abe8d3c2fe5e572bf8" "a36a4c301ae8ac13610ccbc12256cacc", - } - }, { - "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20", - { - "eaa6bd25880bf93d3f5d1e4ca2611d91" "cfa45c9f7e714b54bdfa80027cb14380", - "114ae344ded71b35f2e60febad727fd8" "02e1e7056b0f623900496422943e97b6", - "91cb93c787964e10d9527d999c6f936b" "49b18b42f8e8367cbeb5ef104ba1c7cd", - "87084b3ba700bade955610672745b374" "e7a7b9e9ec540d5ff43bdb12792d1b35", - "c799b596738f6b018c76c74b1759bd90" "7fec5bfd9f9b89ce6548309092d7e958", - "40f250b26d1f096a4afd4c340a588815" "3e34135c79db010200767651cf263073", - "f656abccf88dd827027b2ce917d464ec" "18b62503bfbc077fbabb98f20d98ab34", - "8aed95ee5b0dcbfbef4eb21d3a3f52f9" "625a1ab00ee39a5327346bddb01a9c18", - "a13a7c79c7e119b5ab0296ab28c300b9" "f3e4c0a2e02d1d01f7f0a74618af2b48", - } - }, { - "833222772a", - { - "80ad97bdc973df8a2e879e92a497efda" "20f060c2f2e5126501d3d4fea10d5fc0", - "faa148e99046181fec6b2085f3b20ed9" "f0daf5bab3d596839857846f73fbfe5a", - "1c7e2fc4639232fe297584b296996bc8" "3db9b249406cc8edffac55ccd322ba12", - "e4f9f7e0066154bbd125b745569bc897" "75d5ef262b44c41a9cf63ae14568e1b9", - "6da453dbf81e82334a3d8866cb50a1e3" "7828d074119cab5c22b294d7a9bfa0bb", - "adb89cea9a15fbe617295bd04b8ca05c" "6251d87fd4aaae9a7e4ad5c217d3f300", - "e7119bd6dd9b22afe8f89585432881e2" "785b60fd7ec4e9fcb6545f350d660fab", - "afecc037fdb7b0838eb3d70bcd268382" "dbc1a7b49d57358cc9fa6d61d73b7cf0", - "6349d126a37afcba89794f9804914fdc" "bf42c3018c2f7c66bfde524975768115", - } - }, { - "1910833222772a", - { - "bc9222dbd3274d8fc66d14ccbda6690b" "7ae627410c9a2be693df5bb7485a63e3", - "3f0931aa03defb300f060103826f2a64" "beaa9ec8d59bb68129f3027c96361181", - "74e04db46d28648d7dee8a0064b06cfe" "9b5e81c62fe023c55be42f87bbf932b8", - "ce178fc1826efecbc182f57999a46140" "8bdf55cd55061c06dba6be11de4a578a", - "626f5f4dce652501f3087d39c92cc349" "42daac6a8f9ab9a7fd137c6037825682", - "cc03fdb79192a207312f53f5d4dc33d9" "f70f14122a1c98a3155d28b8a0a8a41d", - "2a3a307ab2708a9c00fe0b42f9c2d6a1" "862617627d2261eab0b1246597ca0ae9", - "55f877ce4f2e1ddbbf8e13e2cde0fdc8" "1b1556cb935f173337705fbb5d501fc1", - "ecd0e96602be7f8d5092816cccf2c2e9" "027881fab4993a1c262024a94fff3f61", - } - }, { - "641910833222772a", - { - "bbf609de9413172d07660cb680716926" "46101a6dab43115d6c522b4fe93604a9", - "cbe1fff21c96f3eef61e8fe0542cbdf0" "347938bffa4009c512cfb4034b0dd1a7", - "7867a786d00a7147904d76ddf1e520e3" "8d3e9e1caefcccb3fbf8d18f64120b32", - "942337f8fd76f0fae8c52d7954810672" "b8548c10f51667f6e60e182fa19b30f7", - "0211c7c6190c9efd1237c34c8f2e06c4" "bda64f65276d2aacb8f90212203a808e", - "bd3820f732ffb53ec193e79d33e27c73" "d0168616861907d482e36cdac8cf5749", - "97b0f0f224b2d2317114808fb03af7a0" "e59616e469787939a063ceea9af956d1", - "c47e0dc1660919c11101208f9e69aa1f" "5ae4f12896b8379a2aad89b5b553d6b0", - "6b6b098d0c293bc2993d80bf0518b6d9" "8170cc3ccd92a698621b939dd38fe7b9", - } - }, { - "8b37641910833222772a", - { - "ab65c26eddb287600db2fda10d1e605c" "bb759010c29658f2c72d93a2d16d2930", - "b901e8036ed1c383cd3c4c4dd0a6ab05" "3d25ce4922924c55f064943353d78a6c", - "12c1aa44bbf87e75e611f69b2c38f49b" "28f2b3434b65c09877470044c6ea170d", - "bd9ef822de5288196134cf8af7839304" "67559c23f052158470a296f725735a32", - "8bab26fbc2c12b0f13e2ab185eabf241" "31185a6d696f0cfa9b42808b38e132a2", - "564d3dae183c5234c8af1e51061c44b5" "3c0778a7b5f72d3c23a3135c7d67b9f4", - "f34369890fcf16fb517dcaae4463b2dd" "02f31c81e8200731b899b028e791bfa7", - "72da646283228c14300853701795616f" "4e0a8c6f7934a788e2265e81d6d0c8f4", - "438dd5eafea0111b6f36b4b938da2a68" "5f6bfc73815874d97100f086979357d8", - } - }, { - "ebb46227c6cc8b37641910833222772a", - { - "720c94b63edf44e131d950ca211a5a30" "c366fdeacf9ca80436be7c358424d20b", - "b3394a40aabf75cba42282ef25a0059f" "4847d81da4942dbc249defc48c922b9f", - "08128c469f275342adda202b2b58da95" "970dacef40ad98723bac5d6955b81761", - "3cb89993b07b0ced93de13d2a11013ac" "ef2d676f1545c2c13dc680a02f4adbfe", - "b60595514f24bc9fe522a6cad7393644" "b515a8c5011754f59003058bdb81514e", - "3c70047e8cbc038e3b9820db601da495" "1175da6ee756de46a53e2b075660b770", - "00a542bba02111cc2c65b38ebdba587e" "5865fdbb5b48064104e830b380f2aede", - "34b21ad2ad44e999db2d7f0863f0d9b6" "84a9218fc36e8a5f2ccfbeae53a27d25", - "a2221a11b833ccb498a59540f0545f4a" "5bbeb4787d59e5373fdbea6c6f75c29b", - } - }, { - "c109163908ebe51debb46227c6cc8b37641910833222772a", - { - "54b64e6b5a20b5e2ec84593dc7989da7" "c135eee237a85465ff97dc03924f45ce", - "cfcc922fb4a14ab45d6175aabbf2d201" "837b87e2a446ad0ef798acd02b94124f", - "17a6dbd664926a0636b3f4c37a4f4694" "4a5f9f26aeeed4d4a25f632d305233d9", - "80a3d01ef00c8e9a4209c17f4eeb358c" "d15e7d5ffaaabc0207bf200a117793a2", - "349682bf588eaa52d0aa1560346aeafa" "f5854cdb76c889e3ad63354e5f7275e3", - "532c7ceccb39df3236318405a4b1279c" "baefe6d9ceb651842260e0d1e05e3b90", - "e82d8c6db54e3c633f581c952ba04207" "4b16e50abd381bd70900a9cd9a62cb23", - "3682ee33bd148bd9f58656cd8f30d9fb" "1e5a0b8475045d9b20b2628624edfd9e", - "63edd684fb826282fe528f9c0e9237bc" "e4dd2e98d6960fae0b43545456743391", - } - }, { - "1ada31d5cf688221c109163908ebe51debb46227c6cc8b37641910833222772a", - { - "dd5bcb0018e922d494759d7c395d02d3" "c8446f8f77abf737685353eb89a1c9eb", - "af3e30f9c095045938151575c3fb9098" "f8cb6274db99b80b1d2012a98ed48f0e", - "25c3005a1cb85de076259839ab7198ab" "9dcbc183e8cb994b727b75be3180769c", - "a1d3078dfa9169503ed9d4491dee4eb2" "8514a5495858096f596e4bcd66b10665", - "5f40d59ec1b03b33738efa60b2255d31" "3477c7f764a41baceff90bf14f92b7cc", - "ac4e95368d99b9eb78b8da8f81ffa795" "8c3c13f8c2388bb73f38576e65b7c446", - "13c4b9c1dfb66579eddd8a280b9f7316" "ddd27820550126698efaadc64b64f66e", - "f08f2e66d28ed143f3a237cf9de73559" "9ea36c525531b880ba124334f57b0b70", - "d5a39e3dfcc50280bac4a6b5aa0dca7d" "370b1c1fe655916d97fd0d47ca1d72b8", - } - } - }; - - RC4_CTX ctx; - uint8_t key[64]; - uint8_t buffer[0x1010]; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - size_t length = strlen(tests[i].key) / 2; - memcpy(key, fromhex(tests[i].key), length); - memzero(buffer, sizeof(buffer)); - - rc4_init(&ctx, key, length); - rc4_encrypt(&ctx, buffer, sizeof(buffer)); - - for (size_t j = 0; j < (sizeof(offsets) / sizeof(*offsets)); j++) { - size_t size = strlen(tests[i].vectors[j]) / 2; - ck_assert_mem_eq(&buffer[offsets[j]], fromhex(tests[i].vectors[j]), size); - } - } +START_TEST(test_rc4_rfc6229) { + static const size_t offsets[] = { + 0x0, 0xf0, 0x1f0, 0x2f0, 0x3f0, 0x5f0, 0x7f0, 0xbf0, 0xff0, + }; + + static const struct { + char key[65]; + char vectors[sizeof(offsets) / sizeof(*offsets)][65]; + } tests[] = { + {"0102030405", + { + "b2396305f03dc027ccc3524a0a1118a8" + "6982944f18fc82d589c403a47a0d0919", + "28cb1132c96ce286421dcaadb8b69eae" + "1cfcf62b03eddb641d77dfcf7f8d8c93", + "42b7d0cdd918a8a33dd51781c81f4041" + "6459844432a7da923cfb3eb4980661f6", + "ec10327bde2beefd18f9277680457e22" + "eb62638d4f0ba1fe9fca20e05bf8ff2b", + "45129048e6a0ed0b56b490338f078da5" + "30abbcc7c20b01609f23ee2d5f6bb7df", + "3294f744d8f9790507e70f62e5bbceea" + "d8729db41882259bee4f825325f5a130", + "1eb14a0c13b3bf47fa2a0ba93ad45b8b" + "cc582f8ba9f265e2b1be9112e975d2d7", + "f2e30f9bd102ecbf75aaade9bc35c43c" + "ec0e11c479dc329dc8da7968fe965681", + "068326a2118416d21f9d04b2cd1ca050" + "ff25b58995996707e51fbdf08b34d875", + }}, + {"01020304050607", + { + "293f02d47f37c9b633f2af5285feb46b" + "e620f1390d19bd84e2e0fd752031afc1", + "914f02531c9218810df60f67e338154c" + "d0fdb583073ce85ab83917740ec011d5", + "75f81411e871cffa70b90c74c592e454" + "0bb87202938dad609e87a5a1b079e5e4", + "c2911246b612e7e7b903dfeda1dad866" + "32828f91502b6291368de8081de36fc2", + "f3b9a7e3b297bf9ad804512f9063eff1" + "8ecb67a9ba1f55a5a067e2b026a3676f", + "d2aa902bd42d0d7cfd340cd45810529f" + "78b272c96e42eab4c60bd914e39d06e3", + "f4332fd31a079396ee3cee3f2a4ff049" + "05459781d41fda7f30c1be7e1246c623", + "adfd3868b8e51485d5e610017e3dd609" + "ad26581c0c5be45f4cea01db2f3805d5", + "f3172ceffc3b3d997c85ccd5af1a950c" + "e74b0b9731227fd37c0ec08a47ddd8b8", + }}, + {"0102030405060708", + { + "97ab8a1bf0afb96132f2f67258da15a8" + "8263efdb45c4a18684ef87e6b19e5b09", + "9636ebc9841926f4f7d1f362bddf6e18" + "d0a990ff2c05fef5b90373c9ff4b870a", + "73239f1db7f41d80b643c0c52518ec63" + "163b319923a6bdb4527c626126703c0f", + "49d6c8af0f97144a87df21d91472f966" + "44173a103b6616c5d5ad1cee40c863d0", + "273c9c4b27f322e4e716ef53a47de7a4" + "c6d0e7b226259fa9023490b26167ad1d", + "1fe8986713f07c3d9ae1c163ff8cf9d3" + "8369e1a965610be887fbd0c79162aafb", + "0a0127abb44484b9fbef5abcae1b579f" + "c2cdadc6402e8ee866e1f37bdb47e42c", + "26b51ea37df8e1d6f76fc3b66a7429b3" + "bc7683205d4f443dc1f29dda3315c87b", + "d5fa5a3469d29aaaf83d23589db8c85b" + "3fb46e2c8f0f068edce8cdcd7dfc5862", + }}, + {"0102030405060708090a", + { + "ede3b04643e586cc907dc21851709902" + "03516ba78f413beb223aa5d4d2df6711", + "3cfd6cb58ee0fdde640176ad0000044d" + "48532b21fb6079c9114c0ffd9c04a1ad", + "3e8cea98017109979084b1ef92f99d86" + "e20fb49bdb337ee48b8d8dc0f4afeffe", + "5c2521eacd7966f15e056544bea0d315" + "e067a7031931a246a6c3875d2f678acb", + "a64f70af88ae56b6f87581c0e23e6b08" + "f449031de312814ec6f319291f4a0516", + "bdae85924b3cb1d0a2e33a30c6d79599" + "8a0feddbac865a09bcd127fb562ed60a", + "b55a0a5b51a12a8be34899c3e047511a" + "d9a09cea3ce75fe39698070317a71339", + "552225ed1177f44584ac8cfa6c4eb5fc" + "7e82cbabfc95381b080998442129c2f8", + "1f135ed14ce60a91369d2322bef25e3c" + "08b6be45124a43e2eb77953f84dc8553", + }}, + {"0102030405060708090a0b0c0d0e0f10", + { + "9ac7cc9a609d1ef7b2932899cde41b97" + "5248c4959014126a6e8a84f11d1a9e1c", + "065902e4b620f6cc36c8589f66432f2b" + "d39d566bc6bce3010768151549f3873f", + "b6d1e6c4a5e4771cad79538df295fb11" + "c68c1d5c559a974123df1dbc52a43b89", + "c5ecf88de897fd57fed301701b82a259" + "eccbe13de1fcc91c11a0b26c0bc8fa4d", + "e7a72574f8782ae26aabcf9ebcd66065" + "bdf0324e6083dcc6d3cedd3ca8c53c16", + "b40110c4190b5622a96116b0017ed297" + "ffa0b514647ec04f6306b892ae661181", + "d03d1bc03cd33d70dff9fa5d71963ebd" + "8a44126411eaa78bd51e8d87a8879bf5", + "fabeb76028ade2d0e48722e46c4615a3" + "c05d88abd50357f935a63c59ee537623", + "ff38265c1642c1abe8d3c2fe5e572bf8" + "a36a4c301ae8ac13610ccbc12256cacc", + }}, + {"0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20", + { + "eaa6bd25880bf93d3f5d1e4ca2611d91" + "cfa45c9f7e714b54bdfa80027cb14380", + "114ae344ded71b35f2e60febad727fd8" + "02e1e7056b0f623900496422943e97b6", + "91cb93c787964e10d9527d999c6f936b" + "49b18b42f8e8367cbeb5ef104ba1c7cd", + "87084b3ba700bade955610672745b374" + "e7a7b9e9ec540d5ff43bdb12792d1b35", + "c799b596738f6b018c76c74b1759bd90" + "7fec5bfd9f9b89ce6548309092d7e958", + "40f250b26d1f096a4afd4c340a588815" + "3e34135c79db010200767651cf263073", + "f656abccf88dd827027b2ce917d464ec" + "18b62503bfbc077fbabb98f20d98ab34", + "8aed95ee5b0dcbfbef4eb21d3a3f52f9" + "625a1ab00ee39a5327346bddb01a9c18", + "a13a7c79c7e119b5ab0296ab28c300b9" + "f3e4c0a2e02d1d01f7f0a74618af2b48", + }}, + {"833222772a", + { + "80ad97bdc973df8a2e879e92a497efda" + "20f060c2f2e5126501d3d4fea10d5fc0", + "faa148e99046181fec6b2085f3b20ed9" + "f0daf5bab3d596839857846f73fbfe5a", + "1c7e2fc4639232fe297584b296996bc8" + "3db9b249406cc8edffac55ccd322ba12", + "e4f9f7e0066154bbd125b745569bc897" + "75d5ef262b44c41a9cf63ae14568e1b9", + "6da453dbf81e82334a3d8866cb50a1e3" + "7828d074119cab5c22b294d7a9bfa0bb", + "adb89cea9a15fbe617295bd04b8ca05c" + "6251d87fd4aaae9a7e4ad5c217d3f300", + "e7119bd6dd9b22afe8f89585432881e2" + "785b60fd7ec4e9fcb6545f350d660fab", + "afecc037fdb7b0838eb3d70bcd268382" + "dbc1a7b49d57358cc9fa6d61d73b7cf0", + "6349d126a37afcba89794f9804914fdc" + "bf42c3018c2f7c66bfde524975768115", + }}, + {"1910833222772a", + { + "bc9222dbd3274d8fc66d14ccbda6690b" + "7ae627410c9a2be693df5bb7485a63e3", + "3f0931aa03defb300f060103826f2a64" + "beaa9ec8d59bb68129f3027c96361181", + "74e04db46d28648d7dee8a0064b06cfe" + "9b5e81c62fe023c55be42f87bbf932b8", + "ce178fc1826efecbc182f57999a46140" + "8bdf55cd55061c06dba6be11de4a578a", + "626f5f4dce652501f3087d39c92cc349" + "42daac6a8f9ab9a7fd137c6037825682", + "cc03fdb79192a207312f53f5d4dc33d9" + "f70f14122a1c98a3155d28b8a0a8a41d", + "2a3a307ab2708a9c00fe0b42f9c2d6a1" + "862617627d2261eab0b1246597ca0ae9", + "55f877ce4f2e1ddbbf8e13e2cde0fdc8" + "1b1556cb935f173337705fbb5d501fc1", + "ecd0e96602be7f8d5092816cccf2c2e9" + "027881fab4993a1c262024a94fff3f61", + }}, + {"641910833222772a", + { + "bbf609de9413172d07660cb680716926" + "46101a6dab43115d6c522b4fe93604a9", + "cbe1fff21c96f3eef61e8fe0542cbdf0" + "347938bffa4009c512cfb4034b0dd1a7", + "7867a786d00a7147904d76ddf1e520e3" + "8d3e9e1caefcccb3fbf8d18f64120b32", + "942337f8fd76f0fae8c52d7954810672" + "b8548c10f51667f6e60e182fa19b30f7", + "0211c7c6190c9efd1237c34c8f2e06c4" + "bda64f65276d2aacb8f90212203a808e", + "bd3820f732ffb53ec193e79d33e27c73" + "d0168616861907d482e36cdac8cf5749", + "97b0f0f224b2d2317114808fb03af7a0" + "e59616e469787939a063ceea9af956d1", + "c47e0dc1660919c11101208f9e69aa1f" + "5ae4f12896b8379a2aad89b5b553d6b0", + "6b6b098d0c293bc2993d80bf0518b6d9" + "8170cc3ccd92a698621b939dd38fe7b9", + }}, + {"8b37641910833222772a", + { + "ab65c26eddb287600db2fda10d1e605c" + "bb759010c29658f2c72d93a2d16d2930", + "b901e8036ed1c383cd3c4c4dd0a6ab05" + "3d25ce4922924c55f064943353d78a6c", + "12c1aa44bbf87e75e611f69b2c38f49b" + "28f2b3434b65c09877470044c6ea170d", + "bd9ef822de5288196134cf8af7839304" + "67559c23f052158470a296f725735a32", + "8bab26fbc2c12b0f13e2ab185eabf241" + "31185a6d696f0cfa9b42808b38e132a2", + "564d3dae183c5234c8af1e51061c44b5" + "3c0778a7b5f72d3c23a3135c7d67b9f4", + "f34369890fcf16fb517dcaae4463b2dd" + "02f31c81e8200731b899b028e791bfa7", + "72da646283228c14300853701795616f" + "4e0a8c6f7934a788e2265e81d6d0c8f4", + "438dd5eafea0111b6f36b4b938da2a68" + "5f6bfc73815874d97100f086979357d8", + }}, + {"ebb46227c6cc8b37641910833222772a", + { + "720c94b63edf44e131d950ca211a5a30" + "c366fdeacf9ca80436be7c358424d20b", + "b3394a40aabf75cba42282ef25a0059f" + "4847d81da4942dbc249defc48c922b9f", + "08128c469f275342adda202b2b58da95" + "970dacef40ad98723bac5d6955b81761", + "3cb89993b07b0ced93de13d2a11013ac" + "ef2d676f1545c2c13dc680a02f4adbfe", + "b60595514f24bc9fe522a6cad7393644" + "b515a8c5011754f59003058bdb81514e", + "3c70047e8cbc038e3b9820db601da495" + "1175da6ee756de46a53e2b075660b770", + "00a542bba02111cc2c65b38ebdba587e" + "5865fdbb5b48064104e830b380f2aede", + "34b21ad2ad44e999db2d7f0863f0d9b6" + "84a9218fc36e8a5f2ccfbeae53a27d25", + "a2221a11b833ccb498a59540f0545f4a" + "5bbeb4787d59e5373fdbea6c6f75c29b", + }}, + {"c109163908ebe51debb46227c6cc8b37641910833222772a", + { + "54b64e6b5a20b5e2ec84593dc7989da7" + "c135eee237a85465ff97dc03924f45ce", + "cfcc922fb4a14ab45d6175aabbf2d201" + "837b87e2a446ad0ef798acd02b94124f", + "17a6dbd664926a0636b3f4c37a4f4694" + "4a5f9f26aeeed4d4a25f632d305233d9", + "80a3d01ef00c8e9a4209c17f4eeb358c" + "d15e7d5ffaaabc0207bf200a117793a2", + "349682bf588eaa52d0aa1560346aeafa" + "f5854cdb76c889e3ad63354e5f7275e3", + "532c7ceccb39df3236318405a4b1279c" + "baefe6d9ceb651842260e0d1e05e3b90", + "e82d8c6db54e3c633f581c952ba04207" + "4b16e50abd381bd70900a9cd9a62cb23", + "3682ee33bd148bd9f58656cd8f30d9fb" + "1e5a0b8475045d9b20b2628624edfd9e", + "63edd684fb826282fe528f9c0e9237bc" + "e4dd2e98d6960fae0b43545456743391", + }}, + {"1ada31d5cf688221c109163908ebe51debb46227c6cc8b37641910833222772a", + { + "dd5bcb0018e922d494759d7c395d02d3" + "c8446f8f77abf737685353eb89a1c9eb", + "af3e30f9c095045938151575c3fb9098" + "f8cb6274db99b80b1d2012a98ed48f0e", + "25c3005a1cb85de076259839ab7198ab" + "9dcbc183e8cb994b727b75be3180769c", + "a1d3078dfa9169503ed9d4491dee4eb2" + "8514a5495858096f596e4bcd66b10665", + "5f40d59ec1b03b33738efa60b2255d31" + "3477c7f764a41baceff90bf14f92b7cc", + "ac4e95368d99b9eb78b8da8f81ffa795" + "8c3c13f8c2388bb73f38576e65b7c446", + "13c4b9c1dfb66579eddd8a280b9f7316" + "ddd27820550126698efaadc64b64f66e", + "f08f2e66d28ed143f3a237cf9de73559" + "9ea36c525531b880ba124334f57b0b70", + "d5a39e3dfcc50280bac4a6b5aa0dca7d" + "370b1c1fe655916d97fd0d47ca1d72b8", + }}}; + + RC4_CTX ctx; + uint8_t key[64]; + uint8_t buffer[0x1010]; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + size_t length = strlen(tests[i].key) / 2; + memcpy(key, fromhex(tests[i].key), length); + memzero(buffer, sizeof(buffer)); + + rc4_init(&ctx, key, length); + rc4_encrypt(&ctx, buffer, sizeof(buffer)); + + for (size_t j = 0; j < (sizeof(offsets) / sizeof(*offsets)); j++) { + size_t size = strlen(tests[i].vectors[j]) / 2; + ck_assert_mem_eq(&buffer[offsets[j]], fromhex(tests[i].vectors[j]), size); + } + } } END_TEST -#include "test_check_segwit.h" +static int my_strncasecmp(const char *s1, const char *s2, size_t n) { + size_t i = 0; + while (i < n) { + char c1 = s1[i]; + char c2 = s2[i]; + if (c1 >= 'A' && c1 <= 'Z') c1 = (c1 - 'A') + 'a'; + if (c2 >= 'A' && c2 <= 'Z') c2 = (c2 - 'A') + 'a'; + if (c1 < c2) return -1; + if (c1 > c2) return 1; + if (c1 == 0) return 0; + ++i; + } + return 0; +} + #include "test_check_cashaddr.h" +#include "test_check_segwit.h" #if USE_CARDANO #include "test_check_cardano.h" @@ -4815,323 +8334,321 @@ END_TEST #endif // define test suite and cases -Suite *test_suite(void) -{ - Suite *s = suite_create("trezor-crypto"); - TCase *tc; - - tc = tcase_create("bignum"); - tcase_add_test(tc, test_bignum_read_be); - tcase_add_test(tc, test_bignum_write_be); - tcase_add_test(tc, test_bignum_is_equal); - tcase_add_test(tc, test_bignum_zero); - tcase_add_test(tc, test_bignum_is_zero); - tcase_add_test(tc, test_bignum_one); - tcase_add_test(tc, test_bignum_read_le); - tcase_add_test(tc, test_bignum_write_le); - tcase_add_test(tc, test_bignum_read_uint32); - tcase_add_test(tc, test_bignum_read_uint64); - tcase_add_test(tc, test_bignum_write_uint32); - tcase_add_test(tc, test_bignum_write_uint64); - tcase_add_test(tc, test_bignum_copy); - tcase_add_test(tc, test_bignum_is_even); - tcase_add_test(tc, test_bignum_is_odd); - tcase_add_test(tc, test_bignum_bitcount); - tcase_add_test(tc, test_bignum_digitcount); - tcase_add_test(tc, test_bignum_is_less); - tcase_add_test(tc, test_bignum_format); - tcase_add_test(tc, test_bignum_format_uint64); - suite_add_tcase(s, tc); - - tc = tcase_create("base32"); - tcase_add_test(tc, test_base32_rfc4648); - suite_add_tcase(s, tc); - - tc = tcase_create("base58"); - tcase_add_test(tc, test_base58); - suite_add_tcase(s, tc); +Suite *test_suite(void) { + Suite *s = suite_create("trezor-crypto"); + TCase *tc; + + tc = tcase_create("bignum"); + tcase_add_test(tc, test_bignum_read_be); + tcase_add_test(tc, test_bignum_write_be); + tcase_add_test(tc, test_bignum_is_equal); + tcase_add_test(tc, test_bignum_zero); + tcase_add_test(tc, test_bignum_is_zero); + tcase_add_test(tc, test_bignum_one); + tcase_add_test(tc, test_bignum_read_le); + tcase_add_test(tc, test_bignum_write_le); + tcase_add_test(tc, test_bignum_read_uint32); + tcase_add_test(tc, test_bignum_read_uint64); + tcase_add_test(tc, test_bignum_write_uint32); + tcase_add_test(tc, test_bignum_write_uint64); + tcase_add_test(tc, test_bignum_copy); + tcase_add_test(tc, test_bignum_is_even); + tcase_add_test(tc, test_bignum_is_odd); + tcase_add_test(tc, test_bignum_bitcount); + tcase_add_test(tc, test_bignum_digitcount); + tcase_add_test(tc, test_bignum_is_less); + tcase_add_test(tc, test_bignum_format); + tcase_add_test(tc, test_bignum_format_uint64); + suite_add_tcase(s, tc); + + tc = tcase_create("base32"); + tcase_add_test(tc, test_base32_rfc4648); + suite_add_tcase(s, tc); + + tc = tcase_create("base58"); + tcase_add_test(tc, test_base58); + suite_add_tcase(s, tc); #if USE_GRAPHENE - tc = tcase_create("base58gph"); - tcase_add_test(tc, test_base58gph); - suite_add_tcase(s, tc); + tc = tcase_create("base58gph"); + tcase_add_test(tc, test_base58gph); + suite_add_tcase(s, tc); #endif - tc = tcase_create("bignum_divmod"); - tcase_add_test(tc, test_bignum_divmod); - suite_add_tcase(s, tc); - - tc = tcase_create("bip32"); - tcase_add_test(tc, test_bip32_vector_1); - tcase_add_test(tc, test_bip32_vector_2); - tcase_add_test(tc, test_bip32_vector_3); - tcase_add_test(tc, test_bip32_compare); - tcase_add_test(tc, test_bip32_optimized); - tcase_add_test(tc, test_bip32_cache_1); - tcase_add_test(tc, test_bip32_cache_2); - suite_add_tcase(s, tc); - - tc = tcase_create("bip32-nist"); - tcase_add_test(tc, test_bip32_nist_seed); - tcase_add_test(tc, test_bip32_nist_vector_1); - tcase_add_test(tc, test_bip32_nist_vector_2); - tcase_add_test(tc, test_bip32_nist_compare); - tcase_add_test(tc, test_bip32_nist_repeat); - suite_add_tcase(s, tc); - - tc = tcase_create("bip32-ed25519"); - tcase_add_test(tc, test_bip32_ed25519_vector_1); - tcase_add_test(tc, test_bip32_ed25519_vector_2); - suite_add_tcase(s, tc); - - tc = tcase_create("bip32-ecdh"); - tcase_add_test(tc, test_bip32_ecdh_nist256p1); - tcase_add_test(tc, test_bip32_ecdh_curve25519); - tcase_add_test(tc, test_bip32_ecdh_errors); - suite_add_tcase(s, tc); - - tc = tcase_create("bip32-decred"); - tcase_add_test(tc, test_bip32_decred_vector_1); - tcase_add_test(tc, test_bip32_decred_vector_2); - suite_add_tcase(s, tc); - - tc = tcase_create("ecdsa"); - tcase_add_test(tc, test_ecdsa_signature); - suite_add_tcase(s, tc); - - tc = tcase_create("rfc6979"); - tcase_add_test(tc, test_rfc6979); - suite_add_tcase(s, tc); - - tc = tcase_create("address"); - tcase_add_test(tc, test_address); - suite_add_tcase(s, tc); - - tc = tcase_create("address_decode"); - tcase_add_test(tc, test_address_decode); - suite_add_tcase(s, tc); - - tc = tcase_create("ethereum_address"); - tcase_add_test(tc, test_ethereum_address); - suite_add_tcase(s, tc); - - tc = tcase_create("rsk_address"); - tcase_add_test(tc, test_rsk_address); - suite_add_tcase(s, tc); - - tc = tcase_create("wif"); - tcase_add_test(tc, test_wif); - suite_add_tcase(s, tc); - - tc = tcase_create("ecdsa_der"); - tcase_add_test(tc, test_ecdsa_der); - suite_add_tcase(s, tc); - - tc = tcase_create("aes"); - tcase_add_test(tc, test_aes); - suite_add_tcase(s, tc); - - tc = tcase_create("sha2"); - tcase_add_test(tc, test_sha1); - tcase_add_test(tc, test_sha256); - tcase_add_test(tc, test_sha512); - suite_add_tcase(s, tc); - - tc = tcase_create("sha3"); - tcase_add_test(tc, test_sha3_256); - tcase_add_test(tc, test_sha3_512); - tcase_add_test(tc, test_keccak_256); - suite_add_tcase(s, tc); - - tc = tcase_create("blake"); - tcase_add_test(tc, test_blake256); - suite_add_tcase(s, tc); - - tc = tcase_create("blake2"); - tcase_add_test(tc, test_blake2b); - tcase_add_test(tc, test_blake2s); - suite_add_tcase(s, tc); - - tc = tcase_create("pbkdf2"); - tcase_add_test(tc, test_pbkdf2_hmac_sha256); - tcase_add_test(tc, test_pbkdf2_hmac_sha512); - suite_add_tcase(s, tc); - - tc = tcase_create("bip39"); - tcase_add_test(tc, test_mnemonic); - tcase_add_test(tc, test_mnemonic_check); - tcase_add_test(tc, test_mnemonic_to_entropy); - suite_add_tcase(s, tc); - - tc = tcase_create("pubkey_validity"); - tcase_add_test(tc, test_pubkey_validity); - suite_add_tcase(s, tc); - - tc = tcase_create("pubkey_uncompress"); - tcase_add_test(tc, test_pubkey_uncompress); - suite_add_tcase(s, tc); - - tc = tcase_create("codepoints"); - tcase_add_test(tc, test_codepoints_secp256k1); - tcase_add_test(tc, test_codepoints_nist256p1); - suite_add_tcase(s, tc); - - tc = tcase_create("mult_border_cases"); - tcase_add_test(tc, test_mult_border_cases_secp256k1); - tcase_add_test(tc, test_mult_border_cases_nist256p1); - suite_add_tcase(s, tc); - - tc = tcase_create("scalar_mult"); - tcase_add_test(tc, test_scalar_mult_secp256k1); - tcase_add_test(tc, test_scalar_mult_nist256p1); - suite_add_tcase(s, tc); - - tc = tcase_create("point_mult"); - tcase_add_test(tc, test_point_mult_secp256k1); - tcase_add_test(tc, test_point_mult_nist256p1); - suite_add_tcase(s, tc); - - tc = tcase_create("scalar_point_mult"); - tcase_add_test(tc, test_scalar_point_mult_secp256k1); - tcase_add_test(tc, test_scalar_point_mult_nist256p1); - suite_add_tcase(s, tc); - - tc = tcase_create("ed25519"); - tcase_add_test(tc, test_ed25519); - suite_add_tcase(s, tc); - - tc = tcase_create("ed25519_keccak"); - tcase_add_test(tc, test_ed25519_keccak); - suite_add_tcase(s, tc); - - tc = tcase_create("ed25519_cosi"); - tcase_add_test(tc, test_ed25519_cosi); - suite_add_tcase(s, tc); - - tc = tcase_create("ed25519_modm"); - tcase_add_test(tc, test_ed25519_modl_add); - tcase_add_test(tc, test_ed25519_modl_neg); - tcase_add_test(tc, test_ed25519_modl_sub); - suite_add_tcase(s, tc); + tc = tcase_create("bignum_divmod"); + tcase_add_test(tc, test_bignum_divmod); + suite_add_tcase(s, tc); + + tc = tcase_create("bip32"); + tcase_add_test(tc, test_bip32_vector_1); + tcase_add_test(tc, test_bip32_vector_2); + tcase_add_test(tc, test_bip32_vector_3); + tcase_add_test(tc, test_bip32_compare); + tcase_add_test(tc, test_bip32_optimized); + tcase_add_test(tc, test_bip32_cache_1); + tcase_add_test(tc, test_bip32_cache_2); + suite_add_tcase(s, tc); + + tc = tcase_create("bip32-nist"); + tcase_add_test(tc, test_bip32_nist_seed); + tcase_add_test(tc, test_bip32_nist_vector_1); + tcase_add_test(tc, test_bip32_nist_vector_2); + tcase_add_test(tc, test_bip32_nist_compare); + tcase_add_test(tc, test_bip32_nist_repeat); + suite_add_tcase(s, tc); + + tc = tcase_create("bip32-ed25519"); + tcase_add_test(tc, test_bip32_ed25519_vector_1); + tcase_add_test(tc, test_bip32_ed25519_vector_2); + suite_add_tcase(s, tc); + + tc = tcase_create("bip32-ecdh"); + tcase_add_test(tc, test_bip32_ecdh_nist256p1); + tcase_add_test(tc, test_bip32_ecdh_curve25519); + tcase_add_test(tc, test_bip32_ecdh_errors); + suite_add_tcase(s, tc); + + tc = tcase_create("bip32-decred"); + tcase_add_test(tc, test_bip32_decred_vector_1); + tcase_add_test(tc, test_bip32_decred_vector_2); + suite_add_tcase(s, tc); + + tc = tcase_create("ecdsa"); + tcase_add_test(tc, test_ecdsa_signature); + suite_add_tcase(s, tc); + + tc = tcase_create("rfc6979"); + tcase_add_test(tc, test_rfc6979); + suite_add_tcase(s, tc); + + tc = tcase_create("address"); + tcase_add_test(tc, test_address); + suite_add_tcase(s, tc); + + tc = tcase_create("address_decode"); + tcase_add_test(tc, test_address_decode); + suite_add_tcase(s, tc); + + tc = tcase_create("ethereum_address"); + tcase_add_test(tc, test_ethereum_address); + suite_add_tcase(s, tc); + + tc = tcase_create("rsk_address"); + tcase_add_test(tc, test_rsk_address); + suite_add_tcase(s, tc); + + tc = tcase_create("wif"); + tcase_add_test(tc, test_wif); + suite_add_tcase(s, tc); + + tc = tcase_create("ecdsa_der"); + tcase_add_test(tc, test_ecdsa_der); + suite_add_tcase(s, tc); + + tc = tcase_create("aes"); + tcase_add_test(tc, test_aes); + suite_add_tcase(s, tc); + + tc = tcase_create("sha2"); + tcase_add_test(tc, test_sha1); + tcase_add_test(tc, test_sha256); + tcase_add_test(tc, test_sha512); + suite_add_tcase(s, tc); + + tc = tcase_create("sha3"); + tcase_add_test(tc, test_sha3_256); + tcase_add_test(tc, test_sha3_512); + tcase_add_test(tc, test_keccak_256); + suite_add_tcase(s, tc); + + tc = tcase_create("blake"); + tcase_add_test(tc, test_blake256); + suite_add_tcase(s, tc); + + tc = tcase_create("blake2"); + tcase_add_test(tc, test_blake2b); + tcase_add_test(tc, test_blake2s); + suite_add_tcase(s, tc); + + tc = tcase_create("pbkdf2"); + tcase_add_test(tc, test_pbkdf2_hmac_sha256); + tcase_add_test(tc, test_pbkdf2_hmac_sha512); + suite_add_tcase(s, tc); + + tc = tcase_create("bip39"); + tcase_add_test(tc, test_mnemonic); + tcase_add_test(tc, test_mnemonic_check); + tcase_add_test(tc, test_mnemonic_to_entropy); + suite_add_tcase(s, tc); + + tc = tcase_create("pubkey_validity"); + tcase_add_test(tc, test_pubkey_validity); + suite_add_tcase(s, tc); + + tc = tcase_create("pubkey_uncompress"); + tcase_add_test(tc, test_pubkey_uncompress); + suite_add_tcase(s, tc); + + tc = tcase_create("codepoints"); + tcase_add_test(tc, test_codepoints_secp256k1); + tcase_add_test(tc, test_codepoints_nist256p1); + suite_add_tcase(s, tc); + + tc = tcase_create("mult_border_cases"); + tcase_add_test(tc, test_mult_border_cases_secp256k1); + tcase_add_test(tc, test_mult_border_cases_nist256p1); + suite_add_tcase(s, tc); + + tc = tcase_create("scalar_mult"); + tcase_add_test(tc, test_scalar_mult_secp256k1); + tcase_add_test(tc, test_scalar_mult_nist256p1); + suite_add_tcase(s, tc); + + tc = tcase_create("point_mult"); + tcase_add_test(tc, test_point_mult_secp256k1); + tcase_add_test(tc, test_point_mult_nist256p1); + suite_add_tcase(s, tc); + + tc = tcase_create("scalar_point_mult"); + tcase_add_test(tc, test_scalar_point_mult_secp256k1); + tcase_add_test(tc, test_scalar_point_mult_nist256p1); + suite_add_tcase(s, tc); + + tc = tcase_create("ed25519"); + tcase_add_test(tc, test_ed25519); + suite_add_tcase(s, tc); + + tc = tcase_create("ed25519_keccak"); + tcase_add_test(tc, test_ed25519_keccak); + suite_add_tcase(s, tc); + + tc = tcase_create("ed25519_cosi"); + tcase_add_test(tc, test_ed25519_cosi); + suite_add_tcase(s, tc); + + tc = tcase_create("ed25519_modm"); + tcase_add_test(tc, test_ed25519_modl_add); + tcase_add_test(tc, test_ed25519_modl_neg); + tcase_add_test(tc, test_ed25519_modl_sub); + suite_add_tcase(s, tc); #if USE_MONERO - tc = tcase_create("ed25519_ge"); - tcase_add_test(tc, test_ge25519_double_scalarmult_vartime2); - suite_add_tcase(s, tc); + tc = tcase_create("ed25519_ge"); + tcase_add_test(tc, test_ge25519_double_scalarmult_vartime2); + suite_add_tcase(s, tc); #endif - tc = tcase_create("script"); - tcase_add_test(tc, test_output_script); - suite_add_tcase(s, tc); + tc = tcase_create("script"); + tcase_add_test(tc, test_output_script); + suite_add_tcase(s, tc); - tc = tcase_create("ethereum_pubkeyhash"); - tcase_add_test(tc, test_ethereum_pubkeyhash); - suite_add_tcase(s, tc); + tc = tcase_create("ethereum_pubkeyhash"); + tcase_add_test(tc, test_ethereum_pubkeyhash); + suite_add_tcase(s, tc); - tc = tcase_create("nem_address"); - tcase_add_test(tc, test_nem_address); - suite_add_tcase(s, tc); + tc = tcase_create("nem_address"); + tcase_add_test(tc, test_nem_address); + suite_add_tcase(s, tc); - tc = tcase_create("nem_encryption"); - tcase_add_test(tc, test_nem_derive); - tcase_add_test(tc, test_nem_cipher); - suite_add_tcase(s, tc); + tc = tcase_create("nem_encryption"); + tcase_add_test(tc, test_nem_derive); + tcase_add_test(tc, test_nem_cipher); + suite_add_tcase(s, tc); - tc = tcase_create("nem_transaction"); - tcase_add_test(tc, test_nem_transaction_transfer); - tcase_add_test(tc, test_nem_transaction_multisig); - tcase_add_test(tc, test_nem_transaction_provision_namespace); - tcase_add_test(tc, test_nem_transaction_mosaic_creation); - tcase_add_test(tc, test_nem_transaction_mosaic_supply_change); - tcase_add_test(tc, test_nem_transaction_aggregate_modification); - suite_add_tcase(s, tc); + tc = tcase_create("nem_transaction"); + tcase_add_test(tc, test_nem_transaction_transfer); + tcase_add_test(tc, test_nem_transaction_multisig); + tcase_add_test(tc, test_nem_transaction_provision_namespace); + tcase_add_test(tc, test_nem_transaction_mosaic_creation); + tcase_add_test(tc, test_nem_transaction_mosaic_supply_change); + tcase_add_test(tc, test_nem_transaction_aggregate_modification); + suite_add_tcase(s, tc); - tc = tcase_create("multibyte_address"); - tcase_add_test(tc, test_multibyte_address); - suite_add_tcase(s, tc); + tc = tcase_create("multibyte_address"); + tcase_add_test(tc, test_multibyte_address); + suite_add_tcase(s, tc); - tc = tcase_create("rc4"); - tcase_add_test(tc, test_rc4_rfc6229); - suite_add_tcase(s, tc); + tc = tcase_create("rc4"); + tcase_add_test(tc, test_rc4_rfc6229); + suite_add_tcase(s, tc); - tc = tcase_create("segwit"); - tcase_add_test(tc, test_segwit); - suite_add_tcase(s, tc); + tc = tcase_create("segwit"); + tcase_add_test(tc, test_segwit); + suite_add_tcase(s, tc); - tc = tcase_create("cashaddr"); - tcase_add_test(tc, test_cashaddr); - suite_add_tcase(s, tc); + tc = tcase_create("cashaddr"); + tcase_add_test(tc, test_cashaddr); + suite_add_tcase(s, tc); #if USE_CARDANO - tc = tcase_create("bip32-cardano"); - - tcase_add_test(tc, test_bip32_cardano_hdnode_vector_1); - tcase_add_test(tc, test_bip32_cardano_hdnode_vector_2); - tcase_add_test(tc, test_bip32_cardano_hdnode_vector_3); - tcase_add_test(tc, test_bip32_cardano_hdnode_vector_4); - tcase_add_test(tc, test_bip32_cardano_hdnode_vector_5); - tcase_add_test(tc, test_bip32_cardano_hdnode_vector_6); - tcase_add_test(tc, test_bip32_cardano_hdnode_vector_7); - - tcase_add_test(tc, test_ed25519_cardano_sign_vectors); - suite_add_tcase(s,tc); + tc = tcase_create("bip32-cardano"); + + tcase_add_test(tc, test_bip32_cardano_hdnode_vector_1); + tcase_add_test(tc, test_bip32_cardano_hdnode_vector_2); + tcase_add_test(tc, test_bip32_cardano_hdnode_vector_3); + tcase_add_test(tc, test_bip32_cardano_hdnode_vector_4); + tcase_add_test(tc, test_bip32_cardano_hdnode_vector_5); + tcase_add_test(tc, test_bip32_cardano_hdnode_vector_6); + tcase_add_test(tc, test_bip32_cardano_hdnode_vector_7); + + tcase_add_test(tc, test_ed25519_cardano_sign_vectors); + suite_add_tcase(s, tc); #endif #if USE_MONERO - tc = tcase_create("xmr_base58"); - tcase_add_test(tc, test_xmr_base58); - suite_add_tcase(s, tc); - - tc = tcase_create("xmr_crypto"); - tcase_add_test(tc, test_xmr_getset256_modm); - tcase_add_test(tc, test_xmr_cmp256_modm); - tcase_add_test(tc, test_xmr_copy_check_modm); - tcase_add_test(tc, test_xmr_mulsub256_modm); - tcase_add_test(tc, test_xmr_muladd256_modm); - tcase_add_test(tc, test_xmr_curve25519_set); - tcase_add_test(tc, test_xmr_curve25519_consts); - tcase_add_test(tc, test_xmr_curve25519_tests); - tcase_add_test(tc, test_xmr_curve25519_expand_reduce); - tcase_add_test(tc, test_xmr_ge25519_base); - tcase_add_test(tc, test_xmr_ge25519_check); - tcase_add_test(tc, test_xmr_ge25519_scalarmult_base_wrapper); - tcase_add_test(tc, test_xmr_ge25519_scalarmult); - tcase_add_test(tc, test_xmr_ge25519_ops); - suite_add_tcase(s, tc); - - tc = tcase_create("xmr_xmr"); - tcase_add_test(tc, test_xmr_check_point); - tcase_add_test(tc, test_xmr_h); - tcase_add_test(tc, test_xmr_fast_hash); - tcase_add_test(tc, test_xmr_hasher); - tcase_add_test(tc, test_xmr_hash_to_scalar); - tcase_add_test(tc, test_xmr_hash_to_ec); - tcase_add_test(tc, test_xmr_derivation_to_scalar); - tcase_add_test(tc, test_xmr_generate_key_derivation); - tcase_add_test(tc, test_xmr_derive_private_key); - tcase_add_test(tc, test_xmr_derive_public_key); - tcase_add_test(tc, test_xmr_add_keys2); - tcase_add_test(tc, test_xmr_add_keys3); - tcase_add_test(tc, test_xmr_get_subaddress_secret_key); - tcase_add_test(tc, test_xmr_gen_c); - tcase_add_test(tc, test_xmr_varint); - tcase_add_test(tc, test_xmr_gen_range_sig); - suite_add_tcase(s, tc); + tc = tcase_create("xmr_base58"); + tcase_add_test(tc, test_xmr_base58); + suite_add_tcase(s, tc); + + tc = tcase_create("xmr_crypto"); + tcase_add_test(tc, test_xmr_getset256_modm); + tcase_add_test(tc, test_xmr_cmp256_modm); + tcase_add_test(tc, test_xmr_copy_check_modm); + tcase_add_test(tc, test_xmr_mulsub256_modm); + tcase_add_test(tc, test_xmr_muladd256_modm); + tcase_add_test(tc, test_xmr_curve25519_set); + tcase_add_test(tc, test_xmr_curve25519_consts); + tcase_add_test(tc, test_xmr_curve25519_tests); + tcase_add_test(tc, test_xmr_curve25519_expand_reduce); + tcase_add_test(tc, test_xmr_ge25519_base); + tcase_add_test(tc, test_xmr_ge25519_check); + tcase_add_test(tc, test_xmr_ge25519_scalarmult_base_wrapper); + tcase_add_test(tc, test_xmr_ge25519_scalarmult); + tcase_add_test(tc, test_xmr_ge25519_ops); + suite_add_tcase(s, tc); + + tc = tcase_create("xmr_xmr"); + tcase_add_test(tc, test_xmr_check_point); + tcase_add_test(tc, test_xmr_h); + tcase_add_test(tc, test_xmr_fast_hash); + tcase_add_test(tc, test_xmr_hasher); + tcase_add_test(tc, test_xmr_hash_to_scalar); + tcase_add_test(tc, test_xmr_hash_to_ec); + tcase_add_test(tc, test_xmr_derivation_to_scalar); + tcase_add_test(tc, test_xmr_generate_key_derivation); + tcase_add_test(tc, test_xmr_derive_private_key); + tcase_add_test(tc, test_xmr_derive_public_key); + tcase_add_test(tc, test_xmr_add_keys2); + tcase_add_test(tc, test_xmr_add_keys3); + tcase_add_test(tc, test_xmr_get_subaddress_secret_key); + tcase_add_test(tc, test_xmr_gen_c); + tcase_add_test(tc, test_xmr_varint); + tcase_add_test(tc, test_xmr_gen_range_sig); + suite_add_tcase(s, tc); #endif - return s; + return s; } // run suite -int main(void) -{ - int number_failed; - Suite *s = test_suite(); - SRunner *sr = srunner_create(s); - srunner_run_all(sr, CK_VERBOSE); - number_failed = srunner_ntests_failed(sr); - srunner_free(sr); - if (number_failed == 0) { - printf("PASSED ALL TESTS\n"); - } - return number_failed; +int main(void) { + int number_failed; + Suite *s = test_suite(); + SRunner *sr = srunner_create(s); + srunner_run_all(sr, CK_VERBOSE); + number_failed = srunner_ntests_failed(sr); + srunner_free(sr); + if (number_failed == 0) { + printf("PASSED ALL TESTS\n"); + } + return number_failed; } diff --git a/tests/test_check_cardano.h b/tests/test_check_cardano.h index 4c734dfad..434ea96b9 100644 --- a/tests/test_check_cardano.h +++ b/tests/test_check_cardano.h @@ -1,215 +1,379 @@ // https://github.com/input-output-hk/cardano-crypto/blob/master/tests/goldens/cardano/crypto/wallet/BIP39-128 -START_TEST(test_ed25519_cardano_sign_vectors) -{ - ed25519_public_key public_key; - ed25519_secret_key secret_key; - ed25519_secret_key secret_key_extension; - ed25519_signature signature; - - static const char *vectors[] = { - "6065a956b1b34145c4416fdc3ba3276801850e91a77a31a7be782463288aea53", // private key - "60ba6e25b1a02157fb69c5d1d7b96c4619736e545447069a6a6f0ba90844bc8e", // private key extension - "64b20fa082b3143d6b5eed42c6ef63f99599d0888afe060620abc1b319935fe1", // public key - "45b1a75fe3119e13c6f60ab9ba674b42f946fdc558e07c83dfa0751c2eba69c79331bd8a4a975662b23628a438a0eba76367e44c12ca91b39ec59063f860f10d", // signature - - "e7d27516538403a53a8b041656a3f570909df641a0ab811fe7d87c9ba02a830c", // private key - "794a2c54ad8b525b781773c87d38cbf4197636bc427a9d551368286fe4c294a4", // private key extension - "95bb82ffd5707716bc65170ab4e8dafeed90fbe0ce9258713b7751e962d931df", // public key - "f2c9171782e7df7665126ac545ae53b05964b0160536efdb545e2460dbbec2b19ec6b338b8f1bf4dfee94360ed024b115e37b1d7e6f3f9ae4beb79539428560f", // signature - - "9b5a3d9a4c60bcd49bb64b72c082b164314d0f61d842f2575fd1d4fb30a28a0c", // private key - "b093e376f41eb7bf80abcd0073a52455d25b5d21815bc758e5f6f81536aedebb", // private key extension - "79fc8154554b97e4c56ef2f9dbb4c1421ff19509688931a1e964bda5dec0f19f", // public key - "2ba1439ae648a7e8da7c9ab1ee6da94fd4ebe37abd0978306e8fba2afa8f111a88a993dbf008bedae9167f4f68409e4c9ddaf02cba12418447b1848907ad800f", // signature - - "52e0c98aa600cfdcd1ff28fcda5227ed87063f4a98547a78b771052cf102b40c", // private key - "6c18d9f8075b1a6a1833540607479bd58b7beb8a83d2bb01ca7ae02452a25803", // private key extension - "dc907c7c06e6314eedd9e18c9f6c6f9cc4e205fb1c70da608234c319f1f7b0d6", // public key - "0cd34f84e0d2fcb1800bdb0e869b9041349955ced66aedbe6bda187ebe8d36a62a05b39647e92fcc42aa7a7368174240afba08b8c81f981a22f942d6bd781602", // signature - - "11fd6462a3a92b35c22703f6f1c124ddcf36b7c2b09cc2784f320e1cfa12ec04", // private key - "c2785803c61c46aeca192a1bb1b7b20a8c4cc7fa01db57fc5d1d8a5473402352", // private key extension - "839775a41876e328986aa26168958bba1176e67819b357eea84afceab8b1db78", // public key - "e41f73db2f8d2896a687802b2be76b7cabb73dfbb4891494883a0cbd9bbb9e5f9d3e14d2d0b06c6674333508496db660936737c0efd9511514147dac79fa4905", // signature - - "5b1e5cad02274ba461f4708d8598d3497faf8fe3e894a379573aa6ac3a03e505", // private key - "ba179d2e3c67aabb486c48d16002b51ad32eab434c738a1550962313b07098cd", // private key extension - "75eb8d197ec8627c85af88e66aa1e49065dd8ac98ed8991db52ece01635dfb76", // public key - "631015357cee3051116b4c2ff4d1c5beb13b6e5023635aa1eeb0563cadf0d4fbc10bd5e31b4a4220c67875558c41b5cc0328104ae39cc7ff20ff0c2bda598906", // signature - - "624b47150f58dfa44284fbc63c9f99b9b79f808c4955a461f0e2be44eb0be50d", // private key - "097aa006d694b165ef37cf23562e5967c96e49255d2f20faae478dee83aa5b02", // private key extension - "0588589cd9b51dfc028cf225674069cbe52e0e70deb02dc45b79b26ee3548b00", // public key - "1de1d275428ba9491a433cd473cd076c027f61e7a8b5391df9dea5cb4bc88d8a57b095906a30b13e68259851a8dd3f57b6f0ffa37a5d3ffc171240f2d404f901", // signature - - 0, 0, - }; - - const char **test_data; - test_data = vectors; - while (*test_data) { - memcpy(secret_key, fromhex(*test_data), 32); - MARK_SECRET_DATA(secret_key, sizeof(secret_key)); - - memcpy(secret_key_extension, fromhex(*(test_data + 1)), 32); - MARK_SECRET_DATA(secret_key_extension, sizeof(secret_key_extension)); - - ed25519_publickey_ext(secret_key, secret_key_extension, public_key); - UNMARK_SECRET_DATA(public_key, sizeof(public_key)); - - ck_assert_mem_eq(public_key, fromhex(*(test_data + 2)), 32); - - const uint8_t * message = (const uint8_t *) "Hello World"; - ed25519_sign_ext(message, 11, secret_key, secret_key_extension, public_key, signature); - UNMARK_SECRET_DATA(signature, sizeof(signature)); - - ck_assert_mem_eq(signature, fromhex(*(test_data + 3)), 64); - - UNMARK_SECRET_DATA(secret_key, sizeof(secret_key)); - UNMARK_SECRET_DATA(secret_key_extension, sizeof(secret_key_extension)); - - test_data += 4; - } +START_TEST(test_ed25519_cardano_sign_vectors) { + ed25519_public_key public_key; + ed25519_secret_key secret_key; + ed25519_secret_key secret_key_extension; + ed25519_signature signature; + + static const char + *vectors[] = + { + "6065a956b1b34145c4416fdc3ba3276801850e91a77a31a7be782463288aea5" + "3", // private key + "60ba6e25b1a02157fb69c5d1d7b96c4619736e545447069a6a6f0ba90844bc8" + "e", // private key extension + "64b20fa082b3143d6b5eed42c6ef63f99599d0888afe060620abc1b319935fe" + "1", // public key + "45b1a75fe3119e13c6f60ab9ba674b42f946fdc558e07c83dfa0751c2eba69c7" + "9331bd8a4a975662b23628a438a0eba76367e44c12ca91b39ec59063f860f10" + "d", // signature + + "e7d27516538403a53a8b041656a3f570909df641a0ab811fe7d87c9ba02a830" + "c", // private key + "794a2c54ad8b525b781773c87d38cbf4197636bc427a9d551368286fe4c294a" + "4", // private key extension + "95bb82ffd5707716bc65170ab4e8dafeed90fbe0ce9258713b7751e962d931d" + "f", // public key + "f2c9171782e7df7665126ac545ae53b05964b0160536efdb545e2460dbbec2b1" + "9ec6b338b8f1bf4dfee94360ed024b115e37b1d7e6f3f9ae4beb79539428560" + "f", // signature + + "9b5a3d9a4c60bcd49bb64b72c082b164314d0f61d842f2575fd1d4fb30a28a0" + "c", // private key + "b093e376f41eb7bf80abcd0073a52455d25b5d21815bc758e5f6f81536aedeb" + "b", // private key extension + "79fc8154554b97e4c56ef2f9dbb4c1421ff19509688931a1e964bda5dec0f19" + "f", // public key + "2ba1439ae648a7e8da7c9ab1ee6da94fd4ebe37abd0978306e8fba2afa8f111a" + "88a993dbf008bedae9167f4f68409e4c9ddaf02cba12418447b1848907ad800" + "f", // signature + + "52e0c98aa600cfdcd1ff28fcda5227ed87063f4a98547a78b771052cf102b40" + "c", // private key + "6c18d9f8075b1a6a1833540607479bd58b7beb8a83d2bb01ca7ae02452a2580" + "3", // private key extension + "dc907c7c06e6314eedd9e18c9f6c6f9cc4e205fb1c70da608234c319f1f7b0d" + "6", // public key + "0cd34f84e0d2fcb1800bdb0e869b9041349955ced66aedbe6bda187ebe8d36a6" + "2a05b39647e92fcc42aa7a7368174240afba08b8c81f981a22f942d6bd78160" + "2", // signature + + "11fd6462a3a92b35c22703f6f1c124ddcf36b7c2b09cc2784f320e1cfa12ec0" + "4", // private key + "c2785803c61c46aeca192a1bb1b7b20a8c4cc7fa01db57fc5d1d8a547340235" + "2", // private key extension + "839775a41876e328986aa26168958bba1176e67819b357eea84afceab8b1db7" + "8", // public key + "e41f73db2f8d2896a687802b2be76b7cabb73dfbb4891494883a0cbd9bbb9e5f" + "9d3e14d2d0b06c6674333508496db660936737c0efd9511514147dac79fa490" + "5", // signature + + "5b1e5cad02274ba461f4708d8598d3497faf8fe3e894a379573aa6ac3a03e50" + "5", // private key + "ba179d2e3c67aabb486c48d16002b51ad32eab434c738a1550962313b07098c" + "d", // private key extension + "75eb8d197ec8627c85af88e66aa1e49065dd8ac98ed8991db52ece01635dfb7" + "6", // public key + "631015357cee3051116b4c2ff4d1c5beb13b6e5023635aa1eeb0563cadf0d4fb" + "c10bd5e31b4a4220c67875558c41b5cc0328104ae39cc7ff20ff0c2bda59890" + "6", // signature + + "624b47150f58dfa44284fbc63c9f99b9b79f808c4955a461f0e2be44eb0be50" + "d", // private key + "097aa006d694b165ef37cf23562e5967c96e49255d2f20faae478dee83aa5b0" + "2", // private key extension + "0588589cd9b51dfc028cf225674069cbe52e0e70deb02dc45b79b26ee3548b0" + "0", // public key + "1de1d275428ba9491a433cd473cd076c027f61e7a8b5391df9dea5cb4bc88d8a" + "57b095906a30b13e68259851a8dd3f57b6f0ffa37a5d3ffc171240f2d404f90" + "1", // signature + + 0, + 0, + }; + + const char **test_data; + test_data = vectors; + while (*test_data) { + memcpy(secret_key, fromhex(*test_data), 32); + MARK_SECRET_DATA(secret_key, sizeof(secret_key)); + + memcpy(secret_key_extension, fromhex(*(test_data + 1)), 32); + MARK_SECRET_DATA(secret_key_extension, sizeof(secret_key_extension)); + + ed25519_publickey_ext(secret_key, secret_key_extension, public_key); + UNMARK_SECRET_DATA(public_key, sizeof(public_key)); + + ck_assert_mem_eq(public_key, fromhex(*(test_data + 2)), 32); + + const uint8_t *message = (const uint8_t *)"Hello World"; + ed25519_sign_ext(message, 11, secret_key, secret_key_extension, public_key, + signature); + UNMARK_SECRET_DATA(signature, sizeof(signature)); + + ck_assert_mem_eq(signature, fromhex(*(test_data + 3)), 64); + + UNMARK_SECRET_DATA(secret_key, sizeof(secret_key)); + UNMARK_SECRET_DATA(secret_key_extension, sizeof(secret_key_extension)); + + test_data += 4; + } } END_TEST -START_TEST(test_bip32_cardano_hdnode_vector_1) -{ - HDNode node; - - uint8_t seed[66]; - int seed_len = mnemonic_to_entropy("ring crime symptom enough erupt lady behave ramp apart settle citizen junk", seed); - ck_assert_int_eq(seed_len, 132); - hdnode_from_seed_cardano((const uint8_t *)"", 0, seed, seed_len / 8, &node); - - ck_assert_mem_eq(node.chain_code, fromhex("affbc325d9027c0f2d9f925b1dcf6c12bf5c1dd08904474066a4f2c00db56173"), 32); - ck_assert_mem_eq(node.private_key, fromhex("08a14df748e477a69d21c97c56db151fc19e2521f31dd0ac5360f269e5b6ea46"), 32); - ck_assert_mem_eq(node.private_key_extension, fromhex("daeb991f2d2128e2525415c56a07f4366baa26c1e48572a5e073934b6de35fbc"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key + 1, fromhex("9a1d04808b4c0682816961cf666e82a7fd35949658aba5354c517eccf12aacb4"), 32); +START_TEST(test_bip32_cardano_hdnode_vector_1) { + HDNode node; + + uint8_t seed[66]; + int seed_len = mnemonic_to_entropy( + "ring crime symptom enough erupt lady behave ramp apart settle citizen " + "junk", + seed); + ck_assert_int_eq(seed_len, 132); + hdnode_from_seed_cardano((const uint8_t *)"", 0, seed, seed_len / 8, &node); + + ck_assert_mem_eq( + node.chain_code, + fromhex( + "affbc325d9027c0f2d9f925b1dcf6c12bf5c1dd08904474066a4f2c00db56173"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "08a14df748e477a69d21c97c56db151fc19e2521f31dd0ac5360f269e5b6ea46"), + 32); + ck_assert_mem_eq( + node.private_key_extension, + fromhex( + "daeb991f2d2128e2525415c56a07f4366baa26c1e48572a5e073934b6de35fbc"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key + 1, + fromhex( + "9a1d04808b4c0682816961cf666e82a7fd35949658aba5354c517eccf12aacb4"), + 32); } END_TEST -START_TEST(test_bip32_cardano_hdnode_vector_2) -{ - HDNode node; - - uint8_t seed[66]; - int seed_len = mnemonic_to_entropy("ring crime symptom enough erupt lady behave ramp apart settle citizen junk", seed); - ck_assert_int_eq(seed_len, 132); - hdnode_from_seed_cardano((const uint8_t *)"", 0, seed, seed_len / 8, &node); - - hdnode_private_ckd_cardano(&node, 0x80000000); - - ck_assert_mem_eq(node.chain_code, fromhex("104c6a0736e501c9bfe2966ba3773f5320495b19c3f2ed222234850af2ccd5b1"), 32); - ck_assert_mem_eq(node.private_key, fromhex("6064bf06b2e981d7c9792b1482eeecd40ec3cfa12143f4a1f149d48ce8b6ea46"), 32); - ck_assert_mem_eq(node.private_key_extension, fromhex("64aa9a16331f14c981b769efcf96addcc4c6db44047fe7a7feae0be23d33bf54"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key + 1, fromhex("c651c14a13c2311fc30a7acf244add1fdac3683e7ba89b4571e4cbcab509b915"), 32); +START_TEST(test_bip32_cardano_hdnode_vector_2) { + HDNode node; + + uint8_t seed[66]; + int seed_len = mnemonic_to_entropy( + "ring crime symptom enough erupt lady behave ramp apart settle citizen " + "junk", + seed); + ck_assert_int_eq(seed_len, 132); + hdnode_from_seed_cardano((const uint8_t *)"", 0, seed, seed_len / 8, &node); + + hdnode_private_ckd_cardano(&node, 0x80000000); + + ck_assert_mem_eq( + node.chain_code, + fromhex( + "104c6a0736e501c9bfe2966ba3773f5320495b19c3f2ed222234850af2ccd5b1"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "6064bf06b2e981d7c9792b1482eeecd40ec3cfa12143f4a1f149d48ce8b6ea46"), + 32); + ck_assert_mem_eq( + node.private_key_extension, + fromhex( + "64aa9a16331f14c981b769efcf96addcc4c6db44047fe7a7feae0be23d33bf54"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key + 1, + fromhex( + "c651c14a13c2311fc30a7acf244add1fdac3683e7ba89b4571e4cbcab509b915"), + 32); } END_TEST -START_TEST(test_bip32_cardano_hdnode_vector_3) -{ - HDNode node; - - uint8_t seed[66]; - int seed_len = mnemonic_to_entropy("ring crime symptom enough erupt lady behave ramp apart settle citizen junk", seed); - ck_assert_int_eq(seed_len, 132); - hdnode_from_seed_cardano((const uint8_t *)"", 0, seed, seed_len / 8, &node); - - hdnode_private_ckd_cardano(&node, 0x80000001); - - ck_assert_mem_eq(node.chain_code, fromhex("da99870d7e69de2a76f255ba8c7ed22428c7e5b0a8df978753c707c95ec3d4ca"), 32); - ck_assert_mem_eq(node.private_key, fromhex("c85fa69f4a1891fd98d1d1fc5f0cf9b1d6e44b0e6906744ab23ea766edb6ea46"), 32); - ck_assert_mem_eq(node.private_key_extension, fromhex("b4fc241feffe840b8a54a26ab447f5a5caa31032db3a8091fca14f38b86ed539"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key + 1, fromhex("5a5b0c92530cd366f05cf072509c806f904262c259e79a0080bbd5ee35706bb1"), 32); +START_TEST(test_bip32_cardano_hdnode_vector_3) { + HDNode node; + + uint8_t seed[66]; + int seed_len = mnemonic_to_entropy( + "ring crime symptom enough erupt lady behave ramp apart settle citizen " + "junk", + seed); + ck_assert_int_eq(seed_len, 132); + hdnode_from_seed_cardano((const uint8_t *)"", 0, seed, seed_len / 8, &node); + + hdnode_private_ckd_cardano(&node, 0x80000001); + + ck_assert_mem_eq( + node.chain_code, + fromhex( + "da99870d7e69de2a76f255ba8c7ed22428c7e5b0a8df978753c707c95ec3d4ca"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "c85fa69f4a1891fd98d1d1fc5f0cf9b1d6e44b0e6906744ab23ea766edb6ea46"), + 32); + ck_assert_mem_eq( + node.private_key_extension, + fromhex( + "b4fc241feffe840b8a54a26ab447f5a5caa31032db3a8091fca14f38b86ed539"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key + 1, + fromhex( + "5a5b0c92530cd366f05cf072509c806f904262c259e79a0080bbd5ee35706bb1"), + 32); } END_TEST -START_TEST(test_bip32_cardano_hdnode_vector_4) -{ - HDNode node; - - uint8_t seed[66]; - int seed_len = mnemonic_to_entropy("ring crime symptom enough erupt lady behave ramp apart settle citizen junk", seed); - ck_assert_int_eq(seed_len, 132); - hdnode_from_seed_cardano((const uint8_t *)"", 0, seed, seed_len / 8, &node); - - hdnode_private_ckd_cardano(&node, 0x80000000); - hdnode_private_ckd_cardano(&node, 0x80000001); - - ck_assert_mem_eq(node.chain_code, fromhex("b40c44dfd9be08591b62be7f9991c85f812d8196927f3c824d9fcb17d275089e"), 32); - ck_assert_mem_eq(node.private_key, fromhex("d064dcf1449d9c3e47f5b422680343561989035bf2e4e23fc34cb61fedb6ea46"), 32); - ck_assert_mem_eq(node.private_key_extension, fromhex("a3071959013af95aaecf78a7a2e1b9838bbbc4864d6a8a2295243782078345cd"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key + 1, fromhex("aaaca5e7adc69a03ef1f5c017ed02879e8ca871df028461ed9bf19fb8fa15038"), 32); +START_TEST(test_bip32_cardano_hdnode_vector_4) { + HDNode node; + + uint8_t seed[66]; + int seed_len = mnemonic_to_entropy( + "ring crime symptom enough erupt lady behave ramp apart settle citizen " + "junk", + seed); + ck_assert_int_eq(seed_len, 132); + hdnode_from_seed_cardano((const uint8_t *)"", 0, seed, seed_len / 8, &node); + + hdnode_private_ckd_cardano(&node, 0x80000000); + hdnode_private_ckd_cardano(&node, 0x80000001); + + ck_assert_mem_eq( + node.chain_code, + fromhex( + "b40c44dfd9be08591b62be7f9991c85f812d8196927f3c824d9fcb17d275089e"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "d064dcf1449d9c3e47f5b422680343561989035bf2e4e23fc34cb61fedb6ea46"), + 32); + ck_assert_mem_eq( + node.private_key_extension, + fromhex( + "a3071959013af95aaecf78a7a2e1b9838bbbc4864d6a8a2295243782078345cd"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key + 1, + fromhex( + "aaaca5e7adc69a03ef1f5c017ed02879e8ca871df028461ed9bf19fb8fa15038"), + 32); } END_TEST -START_TEST(test_bip32_cardano_hdnode_vector_5) -{ - HDNode node; - - uint8_t seed[66]; - int seed_len = mnemonic_to_entropy("ring crime symptom enough erupt lady behave ramp apart settle citizen junk", seed); - ck_assert_int_eq(seed_len, 132); - hdnode_from_seed_cardano((const uint8_t *)"", 0, seed, seed_len / 8, &node); - - hdnode_private_ckd_cardano(&node, 0x80000000); - hdnode_private_ckd_cardano(&node, 0x80000001); - hdnode_private_ckd_cardano(&node, 0x80000002); - - ck_assert_mem_eq(node.chain_code, fromhex("2593896baf92f6ab2c0f253787ab16be0244ba95e0d48ba09da1a7fd3f926c72"), 32); - ck_assert_mem_eq(node.private_key, fromhex("0811b6d5d6f7120cb05d4ce5453d6ce42825c2a8e53b6d370a6b05ccf4b6ea46"), 32); - ck_assert_mem_eq(node.private_key_extension, fromhex("5bebf1eea68acd04932653d944b064b10baaf5886dd73c185cc285059bf93363"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key + 1, fromhex("1c87a32c5babad2fe33e0586bdc523574c6126f8368bc76598e17ea46201f980"), 32); +START_TEST(test_bip32_cardano_hdnode_vector_5) { + HDNode node; + + uint8_t seed[66]; + int seed_len = mnemonic_to_entropy( + "ring crime symptom enough erupt lady behave ramp apart settle citizen " + "junk", + seed); + ck_assert_int_eq(seed_len, 132); + hdnode_from_seed_cardano((const uint8_t *)"", 0, seed, seed_len / 8, &node); + + hdnode_private_ckd_cardano(&node, 0x80000000); + hdnode_private_ckd_cardano(&node, 0x80000001); + hdnode_private_ckd_cardano(&node, 0x80000002); + + ck_assert_mem_eq( + node.chain_code, + fromhex( + "2593896baf92f6ab2c0f253787ab16be0244ba95e0d48ba09da1a7fd3f926c72"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "0811b6d5d6f7120cb05d4ce5453d6ce42825c2a8e53b6d370a6b05ccf4b6ea46"), + 32); + ck_assert_mem_eq( + node.private_key_extension, + fromhex( + "5bebf1eea68acd04932653d944b064b10baaf5886dd73c185cc285059bf93363"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key + 1, + fromhex( + "1c87a32c5babad2fe33e0586bdc523574c6126f8368bc76598e17ea46201f980"), + 32); } END_TEST -START_TEST(test_bip32_cardano_hdnode_vector_6) -{ - HDNode node; - - uint8_t seed[66]; - int seed_len = mnemonic_to_entropy("ring crime symptom enough erupt lady behave ramp apart settle citizen junk", seed); - ck_assert_int_eq(seed_len, 132); - hdnode_from_seed_cardano((const uint8_t *)"", 0, seed, seed_len / 8, &node); - - hdnode_private_ckd_cardano(&node, 0x80000000); - hdnode_private_ckd_cardano(&node, 0x80000001); - hdnode_private_ckd_cardano(&node, 0x80000002); - hdnode_private_ckd_cardano(&node, 0x80000002); - - ck_assert_mem_eq(node.chain_code, fromhex("fe8c6c2ab1e30385513fcffb49dcfe3e7805260425ea76b3b72b9f5bbe3b3d40"), 32); - ck_assert_mem_eq(node.private_key, fromhex("6019b9f5ef6ca530b657bcdb500de5455db8d51afb951fa045b6fbb3f6b6ea46"), 32); - ck_assert_mem_eq(node.private_key_extension, fromhex("466332cb097934b43008701e7e27044aa56c7859019e4eba18d91a3bea23dff7"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key + 1, fromhex("0b8f04755481ced76b4e5795aaafdb3cbd757c10fe60e9c58f48cf29a7ec3575"), 32); +START_TEST(test_bip32_cardano_hdnode_vector_6) { + HDNode node; + + uint8_t seed[66]; + int seed_len = mnemonic_to_entropy( + "ring crime symptom enough erupt lady behave ramp apart settle citizen " + "junk", + seed); + ck_assert_int_eq(seed_len, 132); + hdnode_from_seed_cardano((const uint8_t *)"", 0, seed, seed_len / 8, &node); + + hdnode_private_ckd_cardano(&node, 0x80000000); + hdnode_private_ckd_cardano(&node, 0x80000001); + hdnode_private_ckd_cardano(&node, 0x80000002); + hdnode_private_ckd_cardano(&node, 0x80000002); + + ck_assert_mem_eq( + node.chain_code, + fromhex( + "fe8c6c2ab1e30385513fcffb49dcfe3e7805260425ea76b3b72b9f5bbe3b3d40"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "6019b9f5ef6ca530b657bcdb500de5455db8d51afb951fa045b6fbb3f6b6ea46"), + 32); + ck_assert_mem_eq( + node.private_key_extension, + fromhex( + "466332cb097934b43008701e7e27044aa56c7859019e4eba18d91a3bea23dff7"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key + 1, + fromhex( + "0b8f04755481ced76b4e5795aaafdb3cbd757c10fe60e9c58f48cf29a7ec3575"), + 32); } END_TEST -START_TEST(test_bip32_cardano_hdnode_vector_7) -{ - HDNode node; - - uint8_t seed[66]; - int seed_len = mnemonic_to_entropy("ring crime symptom enough erupt lady behave ramp apart settle citizen junk", seed); - ck_assert_int_eq(seed_len, 132); - hdnode_from_seed_cardano((const uint8_t *)"", 0, seed, seed_len / 8, &node); - - hdnode_private_ckd_cardano(&node, 0x80000000); - hdnode_private_ckd_cardano(&node, 0x80000001); - hdnode_private_ckd_cardano(&node, 0x80000002); - hdnode_private_ckd_cardano(&node, 0x80000002); - hdnode_private_ckd_cardano(&node, 0xBB9ACA00); - - ck_assert_mem_eq(node.chain_code, fromhex("ff77c08d37471c1d4cedd3fae2642c009324d9712492efc74dedab09c9bf973c"), 32); - ck_assert_mem_eq(node.private_key, fromhex("488f34840bba516f7920f91676b8681d0dd833b4ce14468e0810b255f9b6ea46"), 32); - ck_assert_mem_eq(node.private_key_extension, fromhex("01eccef768a79859f824a1d3c3e35e131184e2940c3fca9a4c9b307741f65363"), 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq(node.public_key + 1, fromhex("148605be54585773b44ba87e79265149ae444c4cc37cb1f8db8c08482fba293b"), 32); +START_TEST(test_bip32_cardano_hdnode_vector_7) { + HDNode node; + + uint8_t seed[66]; + int seed_len = mnemonic_to_entropy( + "ring crime symptom enough erupt lady behave ramp apart settle citizen " + "junk", + seed); + ck_assert_int_eq(seed_len, 132); + hdnode_from_seed_cardano((const uint8_t *)"", 0, seed, seed_len / 8, &node); + + hdnode_private_ckd_cardano(&node, 0x80000000); + hdnode_private_ckd_cardano(&node, 0x80000001); + hdnode_private_ckd_cardano(&node, 0x80000002); + hdnode_private_ckd_cardano(&node, 0x80000002); + hdnode_private_ckd_cardano(&node, 0xBB9ACA00); + + ck_assert_mem_eq( + node.chain_code, + fromhex( + "ff77c08d37471c1d4cedd3fae2642c009324d9712492efc74dedab09c9bf973c"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "488f34840bba516f7920f91676b8681d0dd833b4ce14468e0810b255f9b6ea46"), + 32); + ck_assert_mem_eq( + node.private_key_extension, + fromhex( + "01eccef768a79859f824a1d3c3e35e131184e2940c3fca9a4c9b307741f65363"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key + 1, + fromhex( + "148605be54585773b44ba87e79265149ae444c4cc37cb1f8db8c08482fba293b"), + 32); } END_TEST diff --git a/tests/test_check_cashaddr.h b/tests/test_check_cashaddr.h index cc4608730..d38b744a6 100644 --- a/tests/test_check_cashaddr.h +++ b/tests/test_check_cashaddr.h @@ -1,76 +1,67 @@ #include "cash_addr.h" static const char* valid_cashchecksum[] = { - "prefix:x64nx6hz", - "p:gpf8m4h7", - "bitcoincash:qpzry9x8gf2tvdw0s3jn54khce6mua7lcw20ayyn", - "bchtest:testnetaddress4d6njnut", - "bchreg:555555555555555555555555555555555555555555555udxmlmrz", + "prefix:x64nx6hz", + "p:gpf8m4h7", + "bitcoincash:qpzry9x8gf2tvdw0s3jn54khce6mua7lcw20ayyn", + "bchtest:testnetaddress4d6njnut", + "bchreg:555555555555555555555555555555555555555555555udxmlmrz", }; struct valid_cashaddr_data { - const char* legacy; - const char* cashaddress; + const char* legacy; + const char* cashaddress; }; static struct valid_cashaddr_data valid_cashaddr[] = { - { - "1BpEi6DfDAUFd7GtittLSdBeYJvcoaVggu", - "bitcoincash:qpm2qsznhks23z7629mms6s4cwef74vcwvy22gdx6a" - }, - { - "1KXrWXciRDZUpQwQmuM1DbwsKDLYAYsVLR", - "bitcoincash:qr95sy3j9xwd2ap32xkykttr4cvcu7as4y0qverfuy" - }, - { - "16w1D5WRVKJuZUsSRzdLp9w3YGcgoxDXb", - "bitcoincash:qqq3728yw0y47sqn6l2na30mcw6zm78dzqre909m2r" - }, - { - "3CWFddi6m4ndiGyKqzYvsFYagqDLPVMTzC", - "bitcoincash:ppm2qsznhks23z7629mms6s4cwef74vcwvn0h829pq" - }, - { - "3LDsS579y7sruadqu11beEJoTjdFiFCdX4", - "bitcoincash:pr95sy3j9xwd2ap32xkykttr4cvcu7as4yc93ky28e" - }, - { - "31nwvkZwyPdgzjBJZXfDmSWsC4ZLKpYyUw", - "bitcoincash:pqq3728yw0y47sqn6l2na30mcw6zm78dzq5ucqzc37" - } -}; + {"1BpEi6DfDAUFd7GtittLSdBeYJvcoaVggu", + "bitcoincash:qpm2qsznhks23z7629mms6s4cwef74vcwvy22gdx6a"}, + {"1KXrWXciRDZUpQwQmuM1DbwsKDLYAYsVLR", + "bitcoincash:qr95sy3j9xwd2ap32xkykttr4cvcu7as4y0qverfuy"}, + {"16w1D5WRVKJuZUsSRzdLp9w3YGcgoxDXb", + "bitcoincash:qqq3728yw0y47sqn6l2na30mcw6zm78dzqre909m2r"}, + {"3CWFddi6m4ndiGyKqzYvsFYagqDLPVMTzC", + "bitcoincash:ppm2qsznhks23z7629mms6s4cwef74vcwvn0h829pq"}, + {"3LDsS579y7sruadqu11beEJoTjdFiFCdX4", + "bitcoincash:pr95sy3j9xwd2ap32xkykttr4cvcu7as4yc93ky28e"}, + {"31nwvkZwyPdgzjBJZXfDmSWsC4ZLKpYyUw", + "bitcoincash:pqq3728yw0y47sqn6l2na30mcw6zm78dzq5ucqzc37"}}; -START_TEST(test_cashaddr) -{ - size_t i; - for (i = 0; i < sizeof(valid_cashchecksum) / sizeof(valid_cashchecksum[0]); ++i) { - uint8_t data[82]; - char rebuild[92]; - char hrp[84]; - size_t data_len; - int res = cash_decode(hrp, data, &data_len, valid_cashchecksum[i]); - ck_assert_int_eq(res, 1); - res = cash_encode(rebuild, hrp, data, data_len); - ck_assert_int_eq(res, 1); - ck_assert_int_eq(my_strncasecmp(rebuild, valid_cashchecksum[i], 92), 0); - } - for (i = 0; i < sizeof(valid_cashaddr) / sizeof(valid_cashaddr[0]); ++i) { - uint8_t prog[65]; - size_t prog_len; - const char* hrp = "bitcoincash"; - uint8_t rawdata[65]; - size_t rawdata_len; - char rebuild[93]; - int ret = cash_addr_decode(prog, &prog_len, hrp, valid_cashaddr[i].cashaddress); - ck_assert_int_eq(ret, 1); - ck_assert_int_eq(prog_len, 21); - rawdata_len = base58_decode_check(valid_cashaddr[i].legacy, HASHER_SHA2D, rawdata, sizeof(rawdata)); - ck_assert_int_eq(rawdata_len, 21); - ck_assert_int_eq(prog[0], rawdata[0] == 0 ? 0x00 : rawdata[0] == 5 ? 0x08 : -1); - ck_assert_int_eq(memcmp(rawdata + 1, prog + 1, 20), 0); - ret = cash_addr_encode(rebuild, hrp, prog, 21); - ck_assert_int_eq(ret, 1); - ck_assert_int_eq(my_strncasecmp(rebuild, valid_cashaddr[i].cashaddress, 92), 0); - } +START_TEST(test_cashaddr) { + size_t i; + for (i = 0; i < sizeof(valid_cashchecksum) / sizeof(valid_cashchecksum[0]); + ++i) { + uint8_t data[82]; + char rebuild[92]; + char hrp[84]; + size_t data_len; + int res = cash_decode(hrp, data, &data_len, valid_cashchecksum[i]); + ck_assert_int_eq(res, 1); + res = cash_encode(rebuild, hrp, data, data_len); + ck_assert_int_eq(res, 1); + ck_assert_int_eq(my_strncasecmp(rebuild, valid_cashchecksum[i], 92), 0); + } + for (i = 0; i < sizeof(valid_cashaddr) / sizeof(valid_cashaddr[0]); ++i) { + uint8_t prog[65]; + size_t prog_len; + const char* hrp = "bitcoincash"; + uint8_t rawdata[65]; + size_t rawdata_len; + char rebuild[93]; + int ret = + cash_addr_decode(prog, &prog_len, hrp, valid_cashaddr[i].cashaddress); + ck_assert_int_eq(ret, 1); + ck_assert_int_eq(prog_len, 21); + rawdata_len = base58_decode_check(valid_cashaddr[i].legacy, HASHER_SHA2D, + rawdata, sizeof(rawdata)); + ck_assert_int_eq(rawdata_len, 21); + ck_assert_int_eq(prog[0], + rawdata[0] == 0 ? 0x00 : rawdata[0] == 5 ? 0x08 : -1); + ck_assert_int_eq(memcmp(rawdata + 1, prog + 1, 20), 0); + ret = cash_addr_encode(rebuild, hrp, prog, 21); + ck_assert_int_eq(ret, 1); + ck_assert_int_eq(my_strncasecmp(rebuild, valid_cashaddr[i].cashaddress, 92), + 0); + } } END_TEST diff --git a/tests/test_check_monero.h b/tests/test_check_monero.h index 86e355d2a..80ad1eb8a 100644 --- a/tests/test_check_monero.h +++ b/tests/test_check_monero.h @@ -1,1225 +1,1180 @@ #if USE_MONERO -START_TEST(test_xmr_base58) -{ - static const struct { - uint64_t tag; - char *v1; - char *v2; - } tests[] = { - {0x12, - "3bec484c5d7f0246af520aab550452b5b6013733feabebd681c4a60d457b7fc12d5918e31d3c003da3c778592c07b398ad6f961a67082a75fd49394d51e69bbe", - "43tpGG9PKbwCpjRvNLn1jwXPpnacw2uVUcszAtgmDiVcZK4VgHwjJT9BJz1WGF9eMxSYASp8yNMkuLjeQfWqJn3CNWdWfzV" - }, - {0x12, - "639050436fa36c8288706771412c5972461578d564188cd7fc6f81d6973d064fa461afe66fb23879936d7225051bebbf7f3ae0c801a90bb99fbb346b2fd4d702", - "45PwgoUKaDHNqLL8o3okzLL7biv7GqPVmd8LTcTrYVrMEKdSYwFcyJfMLSRpfU3nh8Z2m81FJD4sUY3nXCdGe61k1HAp8T1" - }, - {53, - "5a10cca900ee47a7f412cd661b29f5ab356d6a1951884593bb170b5ec8b6f2e83b1da411527d062c9fedeb2dad669f2f5585a00a88462b8c95c809a630e5734c", - "9vacMKaj8JJV6MnwDzh2oNVdwTLJfTDyNRiB6NzV9TT7fqvzLivH2dB8Tv7VYR3ncn8vCb3KdNMJzQWrPAF1otYJ9cPKpkr" - }, - }; - - uint8_t rawn[512]; - char strn[512]; - int r; - uint64_t tag; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - const char *raw = tests[i].v1; - const char *str = tests[i].v2; - const size_t len = strlen(raw) / 2; - - memcpy(rawn, fromhex(raw), len); - - r = xmr_base58_addr_encode_check(tests[i].tag, rawn, len, strn, sizeof(strn)); - ck_assert_int_eq((size_t) r, strlen(str)); - ck_assert_mem_eq(strn, str, r); - - r = xmr_base58_addr_decode_check(strn, r, &tag, rawn, len); - ck_assert_int_eq(r, len); - ck_assert_mem_eq(rawn, fromhex(raw), len); - } +START_TEST(test_xmr_base58) { + static const struct { + uint64_t tag; + char *v1; + char *v2; + } tests[] = { + {0x12, + "3bec484c5d7f0246af520aab550452b5b6013733feabebd681c4a60d457b7fc12d5918e" + "31d3c003da3c778592c07b398ad6f961a67082a75fd49394d51e69bbe", + "43tpGG9PKbwCpjRvNLn1jwXPpnacw2uVUcszAtgmDiVcZK4VgHwjJT9BJz1WGF9eMxSYASp" + "8yNMkuLjeQfWqJn3CNWdWfzV"}, + {0x12, + "639050436fa36c8288706771412c5972461578d564188cd7fc6f81d6973d064fa461afe" + "66fb23879936d7225051bebbf7f3ae0c801a90bb99fbb346b2fd4d702", + "45PwgoUKaDHNqLL8o3okzLL7biv7GqPVmd8LTcTrYVrMEKdSYwFcyJfMLSRpfU3nh8Z2m81" + "FJD4sUY3nXCdGe61k1HAp8T1"}, + {53, + "5a10cca900ee47a7f412cd661b29f5ab356d6a1951884593bb170b5ec8b6f2e83b1da41" + "1527d062c9fedeb2dad669f2f5585a00a88462b8c95c809a630e5734c", + "9vacMKaj8JJV6MnwDzh2oNVdwTLJfTDyNRiB6NzV9TT7fqvzLivH2dB8Tv7VYR3ncn8vCb3" + "KdNMJzQWrPAF1otYJ9cPKpkr"}, + }; + + uint8_t rawn[512]; + char strn[512]; + int r; + uint64_t tag; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + const char *raw = tests[i].v1; + const char *str = tests[i].v2; + const size_t len = strlen(raw) / 2; + + memcpy(rawn, fromhex(raw), len); + + r = xmr_base58_addr_encode_check(tests[i].tag, rawn, len, strn, + sizeof(strn)); + ck_assert_int_eq((size_t)r, strlen(str)); + ck_assert_mem_eq(strn, str, r); + + r = xmr_base58_addr_decode_check(strn, r, &tag, rawn, len); + ck_assert_int_eq(r, len); + ck_assert_mem_eq(rawn, fromhex(raw), len); + } } END_TEST - -START_TEST(test_xmr_getset256_modm) -{ - static const struct { - uint64_t val; - int r; - char *a; - } tests[] = { - {0x0, 1, - "0000000000000000000000000000000000000000000000000000000000000000"}, - {0x7fffffffULL, 1, - "ffffff7f00000000000000000000000000000000000000000000000000000000"}, - {0x7fffffffffffffffULL, 1, - "ffffffffffffff7f000000000000000000000000000000000000000000000000"}, - {0xdeadc0deULL, 1, - "dec0adde00000000000000000000000000000000000000000000000000000000"}, - {0x0, 0, - "dec0adde000000000000000000000000000000000000000000000000000000ff"}, - {0x0, 0, - "ffffffffffffffffff0000000000000000000000000000000000000000000000"}, - }; - - uint8_t rawn[32]; - uint64_t v1; - bignum256modm a1 = {0}; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - int get_res = tests[i].r; - if (get_res) { - set256_modm(a1, tests[i].val); - ck_assert_int_eq(get256_modm(&v1, a1), 1); - ck_assert(v1 == tests[i].val); - - contract256_modm(rawn, a1); - ck_assert_mem_eq(rawn, fromhex(tests[i].a), 32); - - } else { - expand256_modm(a1, fromhex(tests[i].a), 32); - ck_assert_int_eq(get256_modm(&v1, a1), 0); - } - } +START_TEST(test_xmr_getset256_modm) { + static const struct { + uint64_t val; + int r; + char *a; + } tests[] = { + {0x0, 1, + "0000000000000000000000000000000000000000000000000000000000000000"}, + {0x7fffffffULL, 1, + "ffffff7f00000000000000000000000000000000000000000000000000000000"}, + {0x7fffffffffffffffULL, 1, + "ffffffffffffff7f000000000000000000000000000000000000000000000000"}, + {0xdeadc0deULL, 1, + "dec0adde00000000000000000000000000000000000000000000000000000000"}, + {0x0, 0, + "dec0adde000000000000000000000000000000000000000000000000000000ff"}, + {0x0, 0, + "ffffffffffffffffff0000000000000000000000000000000000000000000000"}, + }; + + uint8_t rawn[32]; + uint64_t v1; + bignum256modm a1 = {0}; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + int get_res = tests[i].r; + if (get_res) { + set256_modm(a1, tests[i].val); + ck_assert_int_eq(get256_modm(&v1, a1), 1); + ck_assert(v1 == tests[i].val); + + contract256_modm(rawn, a1); + ck_assert_mem_eq(rawn, fromhex(tests[i].a), 32); + + } else { + expand256_modm(a1, fromhex(tests[i].a), 32); + ck_assert_int_eq(get256_modm(&v1, a1), 0); + } + } } END_TEST - -START_TEST(test_xmr_cmp256_modm) -{ - static const struct { - char *a; - char *b; - int res_eq; - int res_cmp; - int res_is_zero_a; - } tests[] = { - { - "0000000000000000000000000000000000000000000000000000000000000000", - "0000000000000000000000000000000000000000000000000000000000000000", - 1, 0, 1 - }, - { - "0000000000000000000000000000000000000000000000000000000000000000", - "0100000000000000000000000000000000000000000000000000000000000000", - 0, -1, 1 - }, - { - "dec0adde00000000000000000000000000000000000000000000000000000000", - "dec0adde00000000000000000000000000000000000000000000000000000000", - 1, 0, 0 - }, - { - "863346d8863c461cde2ec7c2759352c2b952228f33a86ca06bb79574bbe5c30d", - "3ddbd65a6d3ba5e2ab120603685a353a27ce3fd21dfdbea7952d2dd26f1ca00a", - 0, 1, 0 - }, - { - "f7667f392edbea6e224b1aa9fbf2a3b238b4f977fb4a8f39130cc45f49b5c40a", - "b41b9b1e7e80be71cf290ed4bded58924086b8ac6bdfa1faa0c80c255f074d07", - 0, 1, 0 - }, - { - "0e4005c7826de8f9978749903f40efd140e4ae6d3bed09e558fcce8367b27501", - "0e4005c7826de8f9978749903f40efd140e4ae6d3bed09e558fcce8367b27504", - 0, -1, 0 - }, - { - "0e4005c7826de8f9978749903f40efd140e4ae6d3bed09e558fcce8367b27504", - "0e4005c7826de8f9978749903f40efd140e4ae6d3bed09e558fcce8367b27504", - 1, 0, 0 - }, - { - "0e4005c7826de8f9978749903f40efd140e4ae6d3bed09e558fcce8367b27504", - "0e4005c7826de8f9978749903f41efd140e4ae6d3bed09e558fcce8367b27504", - 0, -1, 0 - }, - }; - - bignum256modm a1 = {0}, a2 = {0}; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - expand256_modm(a1, fromhex(tests[i].a), 32); - expand256_modm(a2, fromhex(tests[i].b), 32); - - ck_assert_int_eq(eq256_modm(a1, a2), tests[i].res_eq); - ck_assert_int_eq(cmp256_modm(a1, a2), tests[i].res_cmp); - ck_assert_int_eq(iszero256_modm(a1), tests[i].res_is_zero_a); - } +START_TEST(test_xmr_cmp256_modm) { + static const struct { + char *a; + char *b; + int res_eq; + int res_cmp; + int res_is_zero_a; + } tests[] = { + {"0000000000000000000000000000000000000000000000000000000000000000", + "0000000000000000000000000000000000000000000000000000000000000000", 1, 0, + 1}, + {"0000000000000000000000000000000000000000000000000000000000000000", + "0100000000000000000000000000000000000000000000000000000000000000", 0, + -1, 1}, + {"dec0adde00000000000000000000000000000000000000000000000000000000", + "dec0adde00000000000000000000000000000000000000000000000000000000", 1, 0, + 0}, + {"863346d8863c461cde2ec7c2759352c2b952228f33a86ca06bb79574bbe5c30d", + "3ddbd65a6d3ba5e2ab120603685a353a27ce3fd21dfdbea7952d2dd26f1ca00a", 0, 1, + 0}, + {"f7667f392edbea6e224b1aa9fbf2a3b238b4f977fb4a8f39130cc45f49b5c40a", + "b41b9b1e7e80be71cf290ed4bded58924086b8ac6bdfa1faa0c80c255f074d07", 0, 1, + 0}, + {"0e4005c7826de8f9978749903f40efd140e4ae6d3bed09e558fcce8367b27501", + "0e4005c7826de8f9978749903f40efd140e4ae6d3bed09e558fcce8367b27504", 0, + -1, 0}, + {"0e4005c7826de8f9978749903f40efd140e4ae6d3bed09e558fcce8367b27504", + "0e4005c7826de8f9978749903f40efd140e4ae6d3bed09e558fcce8367b27504", 1, 0, + 0}, + {"0e4005c7826de8f9978749903f40efd140e4ae6d3bed09e558fcce8367b27504", + "0e4005c7826de8f9978749903f41efd140e4ae6d3bed09e558fcce8367b27504", 0, + -1, 0}, + }; + + bignum256modm a1 = {0}, a2 = {0}; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + expand256_modm(a1, fromhex(tests[i].a), 32); + expand256_modm(a2, fromhex(tests[i].b), 32); + + ck_assert_int_eq(eq256_modm(a1, a2), tests[i].res_eq); + ck_assert_int_eq(cmp256_modm(a1, a2), tests[i].res_cmp); + ck_assert_int_eq(iszero256_modm(a1), tests[i].res_is_zero_a); + } } END_TEST - -START_TEST(test_xmr_copy_check_modm) -{ - static const struct { - int check; - char *a; - } tests[] = { - {0, - "0000000000000000000000000000000000000000000000000000000000000000"}, - {1, - "ffffff7f00000000000000000000000000000000000000000000000000000000"}, - {1, - "ffffffffffffff7f000000000000000000000000000000000000000000000000"}, - {1, - "dec0adde00000000000000000000000000000000000000000000000000000000"}, - {0, - "dec0adde000000000000000000000fffffffffffffffffffffffffffffffffff"}, - }; - - bignum256modm a1 = {0}, a2 = {0}; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - expand_raw256_modm(a1, fromhex(tests[i].a)); - copy256_modm(a2, a1); - ck_assert_int_eq(eq256_modm(a1, a2), 1); - ck_assert_int_eq(check256_modm(a1), tests[i].check); - } - +START_TEST(test_xmr_copy_check_modm) { + static const struct { + int check; + char *a; + } tests[] = { + {0, "0000000000000000000000000000000000000000000000000000000000000000"}, + {1, "ffffff7f00000000000000000000000000000000000000000000000000000000"}, + {1, "ffffffffffffff7f000000000000000000000000000000000000000000000000"}, + {1, "dec0adde00000000000000000000000000000000000000000000000000000000"}, + {0, "dec0adde000000000000000000000fffffffffffffffffffffffffffffffffff"}, + }; + + bignum256modm a1 = {0}, a2 = {0}; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + expand_raw256_modm(a1, fromhex(tests[i].a)); + copy256_modm(a2, a1); + ck_assert_int_eq(eq256_modm(a1, a2), 1); + ck_assert_int_eq(check256_modm(a1), tests[i].check); + } } END_TEST - -START_TEST(test_xmr_mulsub256_modm) -{ - static const struct { - char *a; - char *b; - char *c; - char *r; - } tests[] = { - { - "713c199348cf7d14b67ae6265ea49c02c8647f07afcbcb6f8d3254b3db972e02", - "4e48a7b7a03ab1106fdfa9441a03c97c644395a12ac4b8effac7344e0719c200", - "1a5711b8c43bcab0161a620368d82727e1d027dc248f420d9bb4db2486c16405", - "6edcc08aa6ec3a5b3d333b5f826be7de9c268be8aaf9521586fbcccbed3b1c0c", - }, - { - "d4ade2c62d34af8cfd9daec6f46bf7e57962a8aa46935cb11fab64fa599b4700", - "22ea7989a9f4d34cd8c9442e03b5062dfe8493757cd18a63411cb1a25e44960f", - "772053e613f0859387badcefeb7fbe551a05b00b9337539c8d72661de5929806", - "a5063258df4520b33e97c0a46d80feeace5c251fc7ef7a938d160b8f25795106", - }, - { - "01fd2ef25c8221277a2b6daf1f1642bacb8d6ac0dd4f62731cdd73e26eb77900", - "0611b9357530aa638428002769ce0ad553421e971bea1f10d7009bf26d9af805", - "dfece232068b2f8059ca569f345baaed13ab464eb3bebb99de5625dc90a8cf03", - "85752e62bd8085c7c02d5edeb74969d22f1a5bb34349258d2e96de300176bb07", - }, - }; - - bignum256modm a = {0}, b = {0}, c = {0}, r = {0}, r2 = {0}; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - expand256_modm(a, fromhex(tests[i].a), 32); - expand256_modm(b, fromhex(tests[i].b), 32); - expand256_modm(c, fromhex(tests[i].c), 32); - expand256_modm(r, fromhex(tests[i].r), 32); - mulsub256_modm(r2, a, b, c); - ck_assert_int_eq(eq256_modm(r, r2), 1); - } +START_TEST(test_xmr_mulsub256_modm) { + static const struct { + char *a; + char *b; + char *c; + char *r; + } tests[] = { + { + "713c199348cf7d14b67ae6265ea49c02c8647f07afcbcb6f8d3254b3db972e02", + "4e48a7b7a03ab1106fdfa9441a03c97c644395a12ac4b8effac7344e0719c200", + "1a5711b8c43bcab0161a620368d82727e1d027dc248f420d9bb4db2486c16405", + "6edcc08aa6ec3a5b3d333b5f826be7de9c268be8aaf9521586fbcccbed3b1c0c", + }, + { + "d4ade2c62d34af8cfd9daec6f46bf7e57962a8aa46935cb11fab64fa599b4700", + "22ea7989a9f4d34cd8c9442e03b5062dfe8493757cd18a63411cb1a25e44960f", + "772053e613f0859387badcefeb7fbe551a05b00b9337539c8d72661de5929806", + "a5063258df4520b33e97c0a46d80feeace5c251fc7ef7a938d160b8f25795106", + }, + { + "01fd2ef25c8221277a2b6daf1f1642bacb8d6ac0dd4f62731cdd73e26eb77900", + "0611b9357530aa638428002769ce0ad553421e971bea1f10d7009bf26d9af805", + "dfece232068b2f8059ca569f345baaed13ab464eb3bebb99de5625dc90a8cf03", + "85752e62bd8085c7c02d5edeb74969d22f1a5bb34349258d2e96de300176bb07", + }, + }; + + bignum256modm a = {0}, b = {0}, c = {0}, r = {0}, r2 = {0}; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + expand256_modm(a, fromhex(tests[i].a), 32); + expand256_modm(b, fromhex(tests[i].b), 32); + expand256_modm(c, fromhex(tests[i].c), 32); + expand256_modm(r, fromhex(tests[i].r), 32); + mulsub256_modm(r2, a, b, c); + ck_assert_int_eq(eq256_modm(r, r2), 1); + } } END_TEST - -START_TEST(test_xmr_muladd256_modm) -{ - static const struct { - char *a; - char *b; - char *c; - char *r; - } tests[] = { - { - "7c3fd8abfbe2be3739d91679ac8dbda086961b941e0d4a00561f758927d8aa09", - "ac2d8d37e4f344aa4040d0f0fc29d45423ab7e69ecacb94ca9fc36819e0e990e", - "2f03f1bac09bc7d002848b68be069dc98b2db028390ae37e13a5166fcae08105", - "dce113add3392f08e3b38b7d31e237eba5066e5a95a1fdbf755b92d05e1ec70b", - }, - { - "6979b70f6198d043f4b14e2069f7b89cc9f09e3465e71d472946443989e0e80c", - "8dd5177bc8d7c5bd58c0be74b336952a73ac259ebb812ac8cd755773c6aab807", - "d7658e508a7454ccfb29e2890d6156ac10e18ebe6e00cc5a2d2d87a5080c7f06", - "51b33f6263772781cdbab26ef48870eaf94899894a437dac39496f15b9d0ae00", - }, - { - "ebfdb4eabedb1fb9a45b3204735b0511871e20358392fa16a851c519e3a29b09", - "59d98831e9f9e24260158986c4d4035438de9b8876cc11bdcf4c364c75f72908", - "93bce4764eee97dc67f2e37da40bc5641f2cdc637285d273287a3d4383b68f02", - "21547ca6855c85d5adcd673b9d801d0cb0f10dced8f8b68a8c2f74163defde0e", - }, - }; - - bignum256modm a = {0}, b = {0}, c = {0}, r = {0}, r2 = {0}; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - expand256_modm(a, fromhex(tests[i].a), 32); - expand256_modm(b, fromhex(tests[i].b), 32); - expand256_modm(c, fromhex(tests[i].c), 32); - expand256_modm(r, fromhex(tests[i].r), 32); - muladd256_modm(r2, a, b, c); - ck_assert_int_eq(eq256_modm(r, r2), 1); - } - +START_TEST(test_xmr_muladd256_modm) { + static const struct { + char *a; + char *b; + char *c; + char *r; + } tests[] = { + { + "7c3fd8abfbe2be3739d91679ac8dbda086961b941e0d4a00561f758927d8aa09", + "ac2d8d37e4f344aa4040d0f0fc29d45423ab7e69ecacb94ca9fc36819e0e990e", + "2f03f1bac09bc7d002848b68be069dc98b2db028390ae37e13a5166fcae08105", + "dce113add3392f08e3b38b7d31e237eba5066e5a95a1fdbf755b92d05e1ec70b", + }, + { + "6979b70f6198d043f4b14e2069f7b89cc9f09e3465e71d472946443989e0e80c", + "8dd5177bc8d7c5bd58c0be74b336952a73ac259ebb812ac8cd755773c6aab807", + "d7658e508a7454ccfb29e2890d6156ac10e18ebe6e00cc5a2d2d87a5080c7f06", + "51b33f6263772781cdbab26ef48870eaf94899894a437dac39496f15b9d0ae00", + }, + { + "ebfdb4eabedb1fb9a45b3204735b0511871e20358392fa16a851c519e3a29b09", + "59d98831e9f9e24260158986c4d4035438de9b8876cc11bdcf4c364c75f72908", + "93bce4764eee97dc67f2e37da40bc5641f2cdc637285d273287a3d4383b68f02", + "21547ca6855c85d5adcd673b9d801d0cb0f10dced8f8b68a8c2f74163defde0e", + }, + }; + + bignum256modm a = {0}, b = {0}, c = {0}, r = {0}, r2 = {0}; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + expand256_modm(a, fromhex(tests[i].a), 32); + expand256_modm(b, fromhex(tests[i].b), 32); + expand256_modm(c, fromhex(tests[i].c), 32); + expand256_modm(r, fromhex(tests[i].r), 32); + muladd256_modm(r2, a, b, c); + ck_assert_int_eq(eq256_modm(r, r2), 1); + } } END_TEST - -START_TEST(test_xmr_curve25519_set) -{ - static const struct { - uint32_t val; - char *a; - } tests[] = { - {0x0, - "0000000000000000000000000000000000000000000000000000000000000000"}, - {0x1, - "0100000000000000000000000000000000000000000000000000000000000000"}, - {0xdeadc0deUL, - "dec0adde00000000000000000000000000000000000000000000000000000000"}, - }; - - unsigned char buff[32]; - bignum25519 a = {0}; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - curve25519_set(a, tests[i].val); - curve25519_contract(buff, a); - ck_assert_mem_eq(buff, fromhex(tests[i].a), 32); - } +START_TEST(test_xmr_curve25519_set) { + static const struct { + uint32_t val; + char *a; + } tests[] = { + {0x0, "0000000000000000000000000000000000000000000000000000000000000000"}, + {0x1, "0100000000000000000000000000000000000000000000000000000000000000"}, + {0xdeadc0deUL, + "dec0adde00000000000000000000000000000000000000000000000000000000"}, + }; + + unsigned char buff[32]; + bignum25519 a = {0}; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + curve25519_set(a, tests[i].val); + curve25519_contract(buff, a); + ck_assert_mem_eq(buff, fromhex(tests[i].a), 32); + } } END_TEST +START_TEST(test_xmr_curve25519_consts) { + char *d = "a3785913ca4deb75abd841414d0a700098e879777940c78c73fe6f2bee6c0352"; + char *d2 = "59f1b226949bd6eb56b183829a14e00030d1f3eef2808e19e7fcdf56dcd90624"; + char *sqrtneg1 = + "b0a00e4a271beec478e42fad0618432fa7d7fb3d99004d2b0bdfc14f8024832b"; -START_TEST(test_xmr_curve25519_consts) -{ - char *d = "a3785913ca4deb75abd841414d0a700098e879777940c78c73fe6f2bee6c0352"; - char *d2 = "59f1b226949bd6eb56b183829a14e00030d1f3eef2808e19e7fcdf56dcd90624"; - char *sqrtneg1 = "b0a00e4a271beec478e42fad0618432fa7d7fb3d99004d2b0bdfc14f8024832b"; - - unsigned char buff[32]; - bignum25519 a = {0}; + unsigned char buff[32]; + bignum25519 a = {0}; - curve25519_set_d(a); - curve25519_contract(buff, a); - ck_assert_mem_eq(buff, fromhex(d), 32); + curve25519_set_d(a); + curve25519_contract(buff, a); + ck_assert_mem_eq(buff, fromhex(d), 32); - curve25519_set_2d(a); - curve25519_contract(buff, a); - ck_assert_mem_eq(buff, fromhex(d2), 32); + curve25519_set_2d(a); + curve25519_contract(buff, a); + ck_assert_mem_eq(buff, fromhex(d2), 32); - curve25519_set_sqrtneg1(a); - curve25519_contract(buff, a); - ck_assert_mem_eq(buff, fromhex(sqrtneg1), 32); + curve25519_set_sqrtneg1(a); + curve25519_contract(buff, a); + ck_assert_mem_eq(buff, fromhex(sqrtneg1), 32); } END_TEST - -START_TEST(test_xmr_curve25519_tests) -{ - static const struct { - char *a; - int res_neg; - int res_nonzero; - } tests[] = { - { - "0000000000000000000000000000000000000000000000000000000000000000", - 0, 0, - }, - { - "0100000000000000000000000000000000000000000000000000000000000000", - 1, 1, - }, - { - "05737aa6100ee54283dc0d483b8e39e61846f6b3736908243d0c824d250b3139", - 1, 1, - }, - { - "95587a5ef6900fa8e32d6a41bd8090b1e33e694284323d1d1f02d69865f2bc15", - 1, 1, - }, - { - "02587a5ef6900fa8e32d6a41bd8090b1e33e694284323d1d1f02d69865f2bc15", - 0, 1, - }, - }; - - bignum25519 a = {0}; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - curve25519_expand(a, fromhex(tests[i].a)); - ck_assert_int_eq(curve25519_isnegative(a), tests[i].res_neg); - ck_assert_int_eq(curve25519_isnonzero(a), tests[i].res_nonzero); - } +START_TEST(test_xmr_curve25519_tests) { + static const struct { + char *a; + int res_neg; + int res_nonzero; + } tests[] = { + { + "0000000000000000000000000000000000000000000000000000000000000000", + 0, + 0, + }, + { + "0100000000000000000000000000000000000000000000000000000000000000", + 1, + 1, + }, + { + "05737aa6100ee54283dc0d483b8e39e61846f6b3736908243d0c824d250b3139", + 1, + 1, + }, + { + "95587a5ef6900fa8e32d6a41bd8090b1e33e694284323d1d1f02d69865f2bc15", + 1, + 1, + }, + { + "02587a5ef6900fa8e32d6a41bd8090b1e33e694284323d1d1f02d69865f2bc15", + 0, + 1, + }, + }; + + bignum25519 a = {0}; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + curve25519_expand(a, fromhex(tests[i].a)); + ck_assert_int_eq(curve25519_isnegative(a), tests[i].res_neg); + ck_assert_int_eq(curve25519_isnonzero(a), tests[i].res_nonzero); + } } END_TEST - -START_TEST(test_xmr_curve25519_expand_reduce) -{ - static const struct { - char *a; - char *b; - } tests[] = { - { - "dec0adde00000000000000000000000000000000000000000000000000000000", - "dec0adde00000000000000000000000000000000000000000000000000000000" - }, - { - "95587a5ef6900fa8e32d6a41bd8090b1e33e694284323d1d1f02d69865f2bc15", - "95587a5ef6900fa8e32d6a41bd8090b1e33e694284323d1d1f02d69865f2bc15" - }, - { - "95587a5ef6900fa8e32d6a41bd8090b1e33e694284323d1d1f02d69865f2bcff", - "a8587a5ef6900fa8e32d6a41bd8090b1e33e694284323d1d1f02d69865f2bc7f" - }, - { - "95587a5ef6900fa8e32d6affbd8090b1e33e694284323fffff02d69865f2bcff", - "a8587a5ef6900fa8e32d6affbd8090b1e33e694284323fffff02d69865f2bc7f" - }, - }; - - unsigned char buff[32]; - bignum25519 a = {0}; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - curve25519_expand_reduce(a, fromhex(tests[i].a)); - curve25519_contract(buff, a); - ck_assert_mem_eq(buff, fromhex(tests[i].b), 32); - } - +START_TEST(test_xmr_curve25519_expand_reduce) { + static const struct { + char *a; + char *b; + } tests[] = { + {"dec0adde00000000000000000000000000000000000000000000000000000000", + "dec0adde00000000000000000000000000000000000000000000000000000000"}, + {"95587a5ef6900fa8e32d6a41bd8090b1e33e694284323d1d1f02d69865f2bc15", + "95587a5ef6900fa8e32d6a41bd8090b1e33e694284323d1d1f02d69865f2bc15"}, + {"95587a5ef6900fa8e32d6a41bd8090b1e33e694284323d1d1f02d69865f2bcff", + "a8587a5ef6900fa8e32d6a41bd8090b1e33e694284323d1d1f02d69865f2bc7f"}, + {"95587a5ef6900fa8e32d6affbd8090b1e33e694284323fffff02d69865f2bcff", + "a8587a5ef6900fa8e32d6affbd8090b1e33e694284323fffff02d69865f2bc7f"}, + }; + + unsigned char buff[32]; + bignum25519 a = {0}; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + curve25519_expand_reduce(a, fromhex(tests[i].a)); + curve25519_contract(buff, a); + ck_assert_mem_eq(buff, fromhex(tests[i].b), 32); + } } END_TEST - -START_TEST(test_xmr_ge25519_base) -{ - unsigned char buff[32]; - char *base = "5866666666666666666666666666666666666666666666666666666666666666"; - ge25519 b; - ge25519_set_base(&b); - ge25519_pack(buff, &b); - ck_assert_mem_eq(buff, fromhex(base), 32); +START_TEST(test_xmr_ge25519_base) { + unsigned char buff[32]; + char *base = + "5866666666666666666666666666666666666666666666666666666666666666"; + ge25519 b; + ge25519_set_base(&b); + ge25519_pack(buff, &b); + ck_assert_mem_eq(buff, fromhex(base), 32); } END_TEST - -START_TEST(test_xmr_ge25519_check) -{ - static const struct { - char *x; - char *y; - char *z; - char *t; - int r; - } tests[] = { - { - "4ff97748221f954414f836d84e8e7e207786bcd20eb67044756dca307e792c60", - "2c7be86ab07488ba43e8e03d85a67625cfbf98c8544de4c877241b7aaafc7f63", - "0100000000000000000000000000000000000000000000000000000000000000", - "3ec65b03954ce7432525b9b3f4a9f5747f57b40903d1bf8892527366325fe036", 1 - }, - { - "358fd25e4b84397d207e23cf3a75819bd6b2254cabc990b31ad63873cc38fc7c", - "ca48045f790145a1eec3946dfd73747fde0fdb4238607e0a203f8ef5bef90e0e", - "0100000000000000000000000000000000000000000000000000000000000000", - "6c5e5cbae4b05e149d0aca50bf7b4112acbbe6233ace9c8bd5bcedf34df9ce0b", 1 - }, - { - "4ff97748221f954414f836d84e8e7e207786bcd20eb6704475ffca307e792c60", - "2c7be86ab07488ba43e8e03d85a67625cfbf98c8544de4c877241b7aaafc7f63", - "0100000000000000000000000000000000000000000000000000000000000000", - "3ec65b03954ce7432525b9b3f4a9f5747f57b40903d1bf8892527366325fe036", 0 - }, - { - "358fd25e4b84397d207e23cf3a75819bd6b2254cabc990b31ad63873cc38fc7c", - "ca48045f790145a1eec3946dfd73747fdfffdb4238607e0a203f8ef5bef90e0e", - "0100000000000000000000000000000000000000000000000000000000000000", - "6c5e5cbae4b05e149d0aca50bf7b4112acbbe6233ace9c8bd5bcedf34df9ce0b", 0 - }, - { - "358fd25e4b84397d207e23cf3a75819bd6b2254cabc990b31ad63873cc38fc7c", - "ca48045f790145a1eec3946dfd73747fdfffdb4238607e0a203f8ef5bef90e0e", - "0100000000000000000000000000000000000000000000000000000000000000", - "6c5e5ffae4b05e149d0aca50bf7b4112acbbe6233ace9c8bd5bcedf34df9ce0b", 0 - }, - }; - - struct ge25519_t p; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - curve25519_expand_reduce(p.x, fromhex(tests[i].x)); - curve25519_expand_reduce(p.y, fromhex(tests[i].y)); - curve25519_expand_reduce(p.z, fromhex(tests[i].z)); - curve25519_expand_reduce(p.t, fromhex(tests[i].t)); - ck_assert_int_eq(ge25519_check(&p), tests[i].r); - } +START_TEST(test_xmr_ge25519_check) { + static const struct { + char *x; + char *y; + char *z; + char *t; + int r; + } tests[] = { + {"4ff97748221f954414f836d84e8e7e207786bcd20eb67044756dca307e792c60", + "2c7be86ab07488ba43e8e03d85a67625cfbf98c8544de4c877241b7aaafc7f63", + "0100000000000000000000000000000000000000000000000000000000000000", + "3ec65b03954ce7432525b9b3f4a9f5747f57b40903d1bf8892527366325fe036", 1}, + {"358fd25e4b84397d207e23cf3a75819bd6b2254cabc990b31ad63873cc38fc7c", + "ca48045f790145a1eec3946dfd73747fde0fdb4238607e0a203f8ef5bef90e0e", + "0100000000000000000000000000000000000000000000000000000000000000", + "6c5e5cbae4b05e149d0aca50bf7b4112acbbe6233ace9c8bd5bcedf34df9ce0b", 1}, + {"4ff97748221f954414f836d84e8e7e207786bcd20eb6704475ffca307e792c60", + "2c7be86ab07488ba43e8e03d85a67625cfbf98c8544de4c877241b7aaafc7f63", + "0100000000000000000000000000000000000000000000000000000000000000", + "3ec65b03954ce7432525b9b3f4a9f5747f57b40903d1bf8892527366325fe036", 0}, + {"358fd25e4b84397d207e23cf3a75819bd6b2254cabc990b31ad63873cc38fc7c", + "ca48045f790145a1eec3946dfd73747fdfffdb4238607e0a203f8ef5bef90e0e", + "0100000000000000000000000000000000000000000000000000000000000000", + "6c5e5cbae4b05e149d0aca50bf7b4112acbbe6233ace9c8bd5bcedf34df9ce0b", 0}, + {"358fd25e4b84397d207e23cf3a75819bd6b2254cabc990b31ad63873cc38fc7c", + "ca48045f790145a1eec3946dfd73747fdfffdb4238607e0a203f8ef5bef90e0e", + "0100000000000000000000000000000000000000000000000000000000000000", + "6c5e5ffae4b05e149d0aca50bf7b4112acbbe6233ace9c8bd5bcedf34df9ce0b", 0}, + }; + + struct ge25519_t p; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + curve25519_expand_reduce(p.x, fromhex(tests[i].x)); + curve25519_expand_reduce(p.y, fromhex(tests[i].y)); + curve25519_expand_reduce(p.z, fromhex(tests[i].z)); + curve25519_expand_reduce(p.t, fromhex(tests[i].t)); + ck_assert_int_eq(ge25519_check(&p), tests[i].r); + } } END_TEST - -START_TEST(test_xmr_ge25519_scalarmult_base_wrapper) -{ - static const struct { - char *sc; - char *pt; - } tests[] = { - { - "40be740e26bd1c84f5a8fec737c0ed30e87bd45adfcd91e320f8dfb68b1a870e", - "b7a8b2f3dbfd41b38d20aec733a316dbfc2633503799cd36f38570cafc8ea887", - }, - { - "1b3746add992215d427e43a58354c11ff9e6dfa1c187250938f7f9334fa41d05", - "e2a1bfbe38a9749fe6ede79d923b778fa4c89393473d633bec01fa68617d0828", - }, - { - "69af25c54090a9746d3f6043348452429ffd53c1530fa114fd0055b70d61020f", - "6bf1783b0a7495d5f6c36605dca95e723ca120a306c255084787f09b12771124", - }, - { - "0000000000000000000000000000000000000000000000000000000000000000", - "0100000000000000000000000000000000000000000000000000000000000000", - }, - { - "0100000000000000000000000000000000000000000000000000000000000000", - "5866666666666666666666666666666666666666666666666666666666666666", - }, - { - "0800000000000000000000000000000000000000000000000000000000000000", - "b4b937fca95b2f1e93e41e62fc3c78818ff38a66096fad6e7973e5c90006d321", - }, - { - "ffffffffffffffff000000000000000000000000000000000000000000000000", - "e185757a3fdc6519a6e7bebd97aa52bdc999e4c87d5c3aad0d995763ab6c6985", - }, - }; - - ge25519 pt, pt2; - bignum256modm sc; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - expand256_modm(sc, fromhex(tests[i].sc), 32); - ge25519_unpack_vartime(&pt, fromhex(tests[i].pt)); - ge25519_scalarmult_base_wrapper(&pt2, sc); - ck_assert_int_eq(ge25519_eq(&pt, &pt2), 1); - } +START_TEST(test_xmr_ge25519_scalarmult_base_wrapper) { + static const struct { + char *sc; + char *pt; + } tests[] = { + { + "40be740e26bd1c84f5a8fec737c0ed30e87bd45adfcd91e320f8dfb68b1a870e", + "b7a8b2f3dbfd41b38d20aec733a316dbfc2633503799cd36f38570cafc8ea887", + }, + { + "1b3746add992215d427e43a58354c11ff9e6dfa1c187250938f7f9334fa41d05", + "e2a1bfbe38a9749fe6ede79d923b778fa4c89393473d633bec01fa68617d0828", + }, + { + "69af25c54090a9746d3f6043348452429ffd53c1530fa114fd0055b70d61020f", + "6bf1783b0a7495d5f6c36605dca95e723ca120a306c255084787f09b12771124", + }, + { + "0000000000000000000000000000000000000000000000000000000000000000", + "0100000000000000000000000000000000000000000000000000000000000000", + }, + { + "0100000000000000000000000000000000000000000000000000000000000000", + "5866666666666666666666666666666666666666666666666666666666666666", + }, + { + "0800000000000000000000000000000000000000000000000000000000000000", + "b4b937fca95b2f1e93e41e62fc3c78818ff38a66096fad6e7973e5c90006d321", + }, + { + "ffffffffffffffff000000000000000000000000000000000000000000000000", + "e185757a3fdc6519a6e7bebd97aa52bdc999e4c87d5c3aad0d995763ab6c6985", + }, + }; + + ge25519 pt, pt2; + bignum256modm sc; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + expand256_modm(sc, fromhex(tests[i].sc), 32); + ge25519_unpack_vartime(&pt, fromhex(tests[i].pt)); + ge25519_scalarmult_base_wrapper(&pt2, sc); + ck_assert_int_eq(ge25519_eq(&pt, &pt2), 1); + } } END_TEST - -START_TEST(test_xmr_ge25519_scalarmult) -{ - static const struct { - char *sc; - char *pt; - char *pt2; - } tests[] = { - { - "0000000000000000000000000000000000000000000000000000000000000000", - "5cbb3b2784c16f0e7eb4f2a7f93288552bb24ec51c5e01504c1e6885cfbca6d0", - "0100000000000000000000000000000000000000000000000000000000000000", - }, - { - "0100000000000000000000000000000000000000000000000000000000000000", - "f39b6770008d069acb92eb95329dec2cb0054da024e437a1bdf1ae06527deff6", - "f39b6770008d069acb92eb95329dec2cb0054da024e437a1bdf1ae06527deff6", - }, - { - "3930000000000000000000000000000000000000000000000000000000000000", - "2835b3983e3cc01a640fd188bf6bbbafbf997a3344d800eed22e4e82a412941c", - "2fe8b2dd0f23e02fca6989e170135584d684583c0a44f6a7d3ebd964685d36c7", - }, - { - "ffffffffffffffff000000000000000000000000000000000000000000000000", - "bb8af7a53a8f1b477c810e833a84cdc789a6b81a6b6417be4f97ffd9ae0fe0b8", - "3a5c9a7dacca9dd8827881f38c36aad7d402a5efc2cab58c7553b903876e1491", - }, - { - "864203a09e1c788a482685c739af07355ebb2c840b7de6af87eff5f19ee3b807", - "d404a9bbf351e7320ea6d11cdeeccaf505f706731cb5e5d839b950edb7ba6286", - "11e09c89e0be7663e0e2d4a01fb05d6a3fd84a78a6fa4fd7daaacf2d19311a38", - }, - { - "3e01f05920a238e33766814d10f0c3a3e975072399ad90a823d4808db1d85209", - "52a2d35798a0ac209b8fa194fe398b869aba5f20d80ee3d8ca77759a8e0bae0d", - "4256addc2f036150f3fdc0a7905f01285239d6dd4eecc4be8e3b134eef4639fe", - }, - { - "ad63d591716a9e89a024a074bc6ce661268d1bb3665f91e8b981f189b1a49507", - "3928bde7a92e1341c3dfee35a66fa5639204f5b9747963278af430145028648d", - "9c959003ba91004956df98800a5024d94031db5ac659675b26350657d93c34f9", - }, - }; - - ge25519 pt, pt2, pt3; - bignum256modm sc; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - expand256_modm(sc, fromhex(tests[i].sc), 32); - ge25519_unpack_vartime(&pt, fromhex(tests[i].pt)); - ge25519_unpack_vartime(&pt2, fromhex(tests[i].pt2)); - ge25519_scalarmult(&pt3, &pt, sc); - ck_assert_int_eq(ge25519_eq(&pt3, &pt2), 1); - } +START_TEST(test_xmr_ge25519_scalarmult) { + static const struct { + char *sc; + char *pt; + char *pt2; + } tests[] = { + { + "0000000000000000000000000000000000000000000000000000000000000000", + "5cbb3b2784c16f0e7eb4f2a7f93288552bb24ec51c5e01504c1e6885cfbca6d0", + "0100000000000000000000000000000000000000000000000000000000000000", + }, + { + "0100000000000000000000000000000000000000000000000000000000000000", + "f39b6770008d069acb92eb95329dec2cb0054da024e437a1bdf1ae06527deff6", + "f39b6770008d069acb92eb95329dec2cb0054da024e437a1bdf1ae06527deff6", + }, + { + "3930000000000000000000000000000000000000000000000000000000000000", + "2835b3983e3cc01a640fd188bf6bbbafbf997a3344d800eed22e4e82a412941c", + "2fe8b2dd0f23e02fca6989e170135584d684583c0a44f6a7d3ebd964685d36c7", + }, + { + "ffffffffffffffff000000000000000000000000000000000000000000000000", + "bb8af7a53a8f1b477c810e833a84cdc789a6b81a6b6417be4f97ffd9ae0fe0b8", + "3a5c9a7dacca9dd8827881f38c36aad7d402a5efc2cab58c7553b903876e1491", + }, + { + "864203a09e1c788a482685c739af07355ebb2c840b7de6af87eff5f19ee3b807", + "d404a9bbf351e7320ea6d11cdeeccaf505f706731cb5e5d839b950edb7ba6286", + "11e09c89e0be7663e0e2d4a01fb05d6a3fd84a78a6fa4fd7daaacf2d19311a38", + }, + { + "3e01f05920a238e33766814d10f0c3a3e975072399ad90a823d4808db1d85209", + "52a2d35798a0ac209b8fa194fe398b869aba5f20d80ee3d8ca77759a8e0bae0d", + "4256addc2f036150f3fdc0a7905f01285239d6dd4eecc4be8e3b134eef4639fe", + }, + { + "ad63d591716a9e89a024a074bc6ce661268d1bb3665f91e8b981f189b1a49507", + "3928bde7a92e1341c3dfee35a66fa5639204f5b9747963278af430145028648d", + "9c959003ba91004956df98800a5024d94031db5ac659675b26350657d93c34f9", + }, + }; + + ge25519 pt, pt2, pt3; + bignum256modm sc; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + expand256_modm(sc, fromhex(tests[i].sc), 32); + ge25519_unpack_vartime(&pt, fromhex(tests[i].pt)); + ge25519_unpack_vartime(&pt2, fromhex(tests[i].pt2)); + ge25519_scalarmult(&pt3, &pt, sc); + ck_assert_int_eq(ge25519_eq(&pt3, &pt2), 1); + } } END_TEST - -START_TEST(test_xmr_ge25519_ops) -{ - int tests[] = {1, 2, 7, 8, 637, 9912, 12345}; - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - struct ge25519_t a, b, c, d; - bignum256modm s1 = {0}, s2 = {0}, s3 = {0}, s4 = {0}; - - set256_modm(s1, tests[i]); - set256_modm(s2, 8 * tests[i]); - set256_modm(s3, 8); - set256_modm(s4, 2); - - ge25519_scalarmult_base_niels(&a, ge25519_niels_base_multiples, s1); - ge25519_scalarmult_base_niels(&b, ge25519_niels_base_multiples, s2); - ge25519_scalarmult(&c, &a, s4); - ge25519_scalarmult(&c, &c, s4); - ge25519_scalarmult(&c, &c, s4); - ck_assert_int_eq(ge25519_eq(&c, &b), 1); - ck_assert_int_eq(ge25519_eq(&a, &b), 0); - - ge25519_scalarmult_base_wrapper(&a, s1); - ge25519_mul8(&b, &a); - ge25519_scalarmult_base_wrapper(&c, s2); - ck_assert_int_eq(ge25519_eq(&b, &c), 1); - - ge25519_scalarmult(&d, &a, s3); - ck_assert_int_eq(ge25519_eq(&d, &c), 1); - - ge25519_copy(&a, &b); - ge25519_neg_full(&b); - ck_assert_int_eq(ge25519_eq(&b, &c), 0); - - ge25519_add(&c, &a, &b, 0); - set256_modm(s2, 0); - ge25519_scalarmult_base_wrapper(&a, s2); - ck_assert_int_eq(ge25519_eq(&a, &c), 1); - } +START_TEST(test_xmr_ge25519_ops) { + int tests[] = {1, 2, 7, 8, 637, 9912, 12345}; + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + struct ge25519_t a, b, c, d; + bignum256modm s1 = {0}, s2 = {0}, s3 = {0}, s4 = {0}; + + set256_modm(s1, tests[i]); + set256_modm(s2, 8 * tests[i]); + set256_modm(s3, 8); + set256_modm(s4, 2); + + ge25519_scalarmult_base_niels(&a, ge25519_niels_base_multiples, s1); + ge25519_scalarmult_base_niels(&b, ge25519_niels_base_multiples, s2); + ge25519_scalarmult(&c, &a, s4); + ge25519_scalarmult(&c, &c, s4); + ge25519_scalarmult(&c, &c, s4); + ck_assert_int_eq(ge25519_eq(&c, &b), 1); + ck_assert_int_eq(ge25519_eq(&a, &b), 0); + + ge25519_scalarmult_base_wrapper(&a, s1); + ge25519_mul8(&b, &a); + ge25519_scalarmult_base_wrapper(&c, s2); + ck_assert_int_eq(ge25519_eq(&b, &c), 1); + + ge25519_scalarmult(&d, &a, s3); + ck_assert_int_eq(ge25519_eq(&d, &c), 1); + + ge25519_copy(&a, &b); + ge25519_neg_full(&b); + ck_assert_int_eq(ge25519_eq(&b, &c), 0); + + ge25519_add(&c, &a, &b, 0); + set256_modm(s2, 0); + ge25519_scalarmult_base_wrapper(&a, s2); + ck_assert_int_eq(ge25519_eq(&a, &c), 1); + } } END_TEST - -START_TEST(test_xmr_check_point) -{ - static const struct { - char *p; - bool on; - } tests[] = { - {"001000a93e0e6937b4feaf079e418a028ca85459aa39ac3871b94076f88ca608", true}, - {"54863a0464c008acc99cffb179bc6cf34eb1bbdf6c29f7a070a7c6376ae30ab5", true}, - {"bebe3c84092c0f7a92704cafb16562cc45c47f45e84baec8d4bba3559d1c1808", true}, - {"00000000000000c60073ec000000000000ff0000000000000000000000000080", false}, - {"00000000000000004e0000000000000000000000000000000000000000000000", false}, - {"0000008b0000000000000000b200000000000000000000000000000000000080", false}, - {"a0953eebe2f676256c37af4f6f84f32d397aaf3b73606e96c5ddfcecbb1ceec8", false}, - {"a82cd837efee505ec8425769ea925bee869ec3c78a57708c64c2ef2bd6ad3b88", false}, - {"031c56cfc99758f6f025630e77c6dea0b853c3ab0bf6cf8c8dab03d1a4618178", false}, - }; - - ge25519 tmp; - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - int res = ge25519_unpack_negative_vartime(&tmp, fromhex(tests[i].p)); - ck_assert_int_eq(ge25519_check(&tmp), tests[i].on); - ck_assert_int_eq(res, tests[i].on); - } +START_TEST(test_xmr_check_point) { + static const struct { + char *p; + bool on; + } tests[] = { + {"001000a93e0e6937b4feaf079e418a028ca85459aa39ac3871b94076f88ca608", + true}, + {"54863a0464c008acc99cffb179bc6cf34eb1bbdf6c29f7a070a7c6376ae30ab5", + true}, + {"bebe3c84092c0f7a92704cafb16562cc45c47f45e84baec8d4bba3559d1c1808", + true}, + {"00000000000000c60073ec000000000000ff0000000000000000000000000080", + false}, + {"00000000000000004e0000000000000000000000000000000000000000000000", + false}, + {"0000008b0000000000000000b200000000000000000000000000000000000080", + false}, + {"a0953eebe2f676256c37af4f6f84f32d397aaf3b73606e96c5ddfcecbb1ceec8", + false}, + {"a82cd837efee505ec8425769ea925bee869ec3c78a57708c64c2ef2bd6ad3b88", + false}, + {"031c56cfc99758f6f025630e77c6dea0b853c3ab0bf6cf8c8dab03d1a4618178", + false}, + }; + + ge25519 tmp; + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + int res = ge25519_unpack_negative_vartime(&tmp, fromhex(tests[i].p)); + ck_assert_int_eq(ge25519_check(&tmp), tests[i].on); + ck_assert_int_eq(res, tests[i].on); + } } END_TEST - -START_TEST(test_xmr_h) -{ - char *H = "8b655970153799af2aeadc9ff1add0ea6c7251d54154cfa92c173a0dd39c1f94"; - ge25519 H2, Z; - ge25519_p1p1 P_11; - ge25519_pniels P_ni; - uint8_t buff[32] = {0}; - - ge25519_pack(buff, &xmr_h); - ck_assert_mem_eq(buff, fromhex(H), 32); - - int res = ge25519_unpack_vartime(&H2, buff); - ck_assert_int_eq(res, 1); - ck_assert_int_eq(ge25519_eq(&xmr_h, &xmr_h), 1); - ck_assert_int_eq(ge25519_eq(&H2, &xmr_h), 1); - - res = ge25519_unpack_negative_vartime(&H2, buff); - ck_assert_int_eq(res, 1); - ck_assert_int_eq(ge25519_eq(&H2, &xmr_h), 0); - ge25519_neg_full(&H2); - ck_assert_int_eq(ge25519_eq(&H2, &xmr_h), 1); - - ge25519_full_to_pniels(&P_ni, &xmr_h); - ge25519_pnielsadd_p1p1(&P_11, &H2, &P_ni, 1); - ge25519_p1p1_to_full(&H2, &P_11); - ge25519_set_neutral(&Z); - ck_assert_int_eq(ge25519_eq(&Z, &H2), 1); +START_TEST(test_xmr_h) { + char *H = "8b655970153799af2aeadc9ff1add0ea6c7251d54154cfa92c173a0dd39c1f94"; + ge25519 H2, Z; + ge25519_p1p1 P_11; + ge25519_pniels P_ni; + uint8_t buff[32] = {0}; + + ge25519_pack(buff, &xmr_h); + ck_assert_mem_eq(buff, fromhex(H), 32); + + int res = ge25519_unpack_vartime(&H2, buff); + ck_assert_int_eq(res, 1); + ck_assert_int_eq(ge25519_eq(&xmr_h, &xmr_h), 1); + ck_assert_int_eq(ge25519_eq(&H2, &xmr_h), 1); + + res = ge25519_unpack_negative_vartime(&H2, buff); + ck_assert_int_eq(res, 1); + ck_assert_int_eq(ge25519_eq(&H2, &xmr_h), 0); + ge25519_neg_full(&H2); + ck_assert_int_eq(ge25519_eq(&H2, &xmr_h), 1); + + ge25519_full_to_pniels(&P_ni, &xmr_h); + ge25519_pnielsadd_p1p1(&P_11, &H2, &P_ni, 1); + ge25519_p1p1_to_full(&H2, &P_11); + ge25519_set_neutral(&Z); + ck_assert_int_eq(ge25519_eq(&Z, &H2), 1); } END_TEST - -START_TEST(test_xmr_fast_hash) -{ - uint8_t hash[32]; - char tests[][2][65] = { - {"", "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"}, - {"00", "bc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a"}, - {"000102", "f84a97f1f0a956e738abd85c2e0a5026f8874e3ec09c8f012159dfeeaab2b156"}, - {"000102030405", "51e8babe8b42352100dffa7f7b3843c95245d3d545c6cbf5052e80258ae80627"}, - {"000102030406", "74e7a0111ee2390dc68269a549a76dcfb553ca1260035eae982d669ff6494f32"}, - {"000102030407", "3a81c5d02a87786343f88414aae150a09f6933b1d3bb660d0a9ac54e12e5cd86"}, - {"259ef2aba8feb473cf39058a0fe30b9ff6d245b42b6826687ebd6b63128aff64", "7fb4d1c8e32f7414fe8c7b2774ec05bff6845e4278565d17f95559513a244da2"}, - {"44caa1c26187afe8dacc5d91cb8a51282334d9308a818fe4d3607275e2a61f05", "2998fe52f8b9883149babd9c546912c3edfbd3cd98896a0e57b1b5929fa5ff7b"}, - }; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - xmr_fast_hash(hash, fromhex(tests[i][0]), strlen(tests[i][0]) / 2); - ck_assert_mem_eq(hash, fromhex(tests[i][1]), 32); - } +START_TEST(test_xmr_fast_hash) { + uint8_t hash[32]; + char tests[][2][65] = { + {"", "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"}, + {"00", + "bc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a"}, + {"000102", + "f84a97f1f0a956e738abd85c2e0a5026f8874e3ec09c8f012159dfeeaab2b156"}, + {"000102030405", + "51e8babe8b42352100dffa7f7b3843c95245d3d545c6cbf5052e80258ae80627"}, + {"000102030406", + "74e7a0111ee2390dc68269a549a76dcfb553ca1260035eae982d669ff6494f32"}, + {"000102030407", + "3a81c5d02a87786343f88414aae150a09f6933b1d3bb660d0a9ac54e12e5cd86"}, + {"259ef2aba8feb473cf39058a0fe30b9ff6d245b42b6826687ebd6b63128aff64", + "7fb4d1c8e32f7414fe8c7b2774ec05bff6845e4278565d17f95559513a244da2"}, + {"44caa1c26187afe8dacc5d91cb8a51282334d9308a818fe4d3607275e2a61f05", + "2998fe52f8b9883149babd9c546912c3edfbd3cd98896a0e57b1b5929fa5ff7b"}, + }; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + xmr_fast_hash(hash, fromhex(tests[i][0]), strlen(tests[i][0]) / 2); + ck_assert_mem_eq(hash, fromhex(tests[i][1]), 32); + } } END_TEST - -START_TEST(test_xmr_hasher) -{ - Hasher hasher; - uint8_t hash[32]; - - static const struct { - char * chunk[3]; - char * hash; - } tests[] = { - { {"00", "01", "02"}, - "f84a97f1f0a956e738abd85c2e0a5026f8874e3ec09c8f012159dfeeaab2b156"}, - { {"001122334455667788", "00", ""}, - "72a228ee8d0d01c815f112ce315cfc215a0594abcec24162304ae0ffda139d9e"}, - { {"001000a93e0e6937b4feaf079e418a028ca85459aa39ac3871b94076f88ca608", "", "00112233445566"}, - "c3deafd96ff10cc190c6024548c344f6401cfe5151ab2fcd40df7cc501147e01"}, - }; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - xmr_hasher_init(&hasher); - for(int j = 0; j < 3; j++){ - xmr_hasher_update(&hasher, fromhex(tests[i].chunk[j]), strlen(tests[i].chunk[j]) / 2); - } - xmr_hasher_final(&hasher, hash); - ck_assert_mem_eq(hash, fromhex(tests[i].hash), 32); - } +START_TEST(test_xmr_hasher) { + Hasher hasher; + uint8_t hash[32]; + + static const struct { + char *chunk[3]; + char *hash; + } tests[] = { + {{"00", "01", "02"}, + "f84a97f1f0a956e738abd85c2e0a5026f8874e3ec09c8f012159dfeeaab2b156"}, + {{"001122334455667788", "00", ""}, + "72a228ee8d0d01c815f112ce315cfc215a0594abcec24162304ae0ffda139d9e"}, + {{"001000a93e0e6937b4feaf079e418a028ca85459aa39ac3871b94076f88ca608", "", + "00112233445566"}, + "c3deafd96ff10cc190c6024548c344f6401cfe5151ab2fcd40df7cc501147e01"}, + }; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + xmr_hasher_init(&hasher); + for (int j = 0; j < 3; j++) { + xmr_hasher_update(&hasher, fromhex(tests[i].chunk[j]), + strlen(tests[i].chunk[j]) / 2); + } + xmr_hasher_final(&hasher, hash); + ck_assert_mem_eq(hash, fromhex(tests[i].hash), 32); + } } END_TEST - -START_TEST(test_xmr_hash_to_scalar) -{ - bignum256modm a1; - unsigned char out[32]; - char tests[][2][65] = { - {"", "4a078e76cd41a3d3b534b83dc6f2ea2de500b653ca82273b7bfad8045d85a400"}, - {"00", "5497c9b6a7059553835f85118dc089d66512f7b477d66591ff96a9e064bcc90a"}, - {"000102", "5727ca206dbafa2e099b022ed528f5bdf7874e3ec09c8f012159dfeeaab2b106"}, - {"000102030405", "7740cf04577c107153a50b3abe44859f5245d3d545c6cbf5052e80258ae80607"}, - {"000102030406", "ad6bbffaceb8020543ac82bcadb9d090b553ca1260035eae982d669ff6494f02"}, - {"000102030407", "d2e116e9576ee5a29011c8fcb41259f99e6933b1d3bb660d0a9ac54e12e5cd06"}, - {"259ef2aba8feb473cf39058a0fe30b9ff6d245b42b6826687ebd6b63128aff64", "3d6d3727dc50bca39e6ccfc9c12950eef5845e4278565d17f95559513a244d02"}, - {"44caa1c26187afe8dacc5d91cb8a51282334d9308a818fe4d3607275e2a61f05", "aecc45c83f0408c96c70f8273e94f930edfbd3cd98896a0e57b1b5929fa5ff0b"}, - }; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - xmr_hash_to_scalar(a1, fromhex(tests[i][0]), strlen(tests[i][0]) / 2); - contract256_modm(out, a1); - ck_assert_mem_eq(out, fromhex(tests[i][1]), 32); - } +START_TEST(test_xmr_hash_to_scalar) { + bignum256modm a1; + unsigned char out[32]; + char tests[][2][65] = { + {"", "4a078e76cd41a3d3b534b83dc6f2ea2de500b653ca82273b7bfad8045d85a400"}, + {"00", + "5497c9b6a7059553835f85118dc089d66512f7b477d66591ff96a9e064bcc90a"}, + {"000102", + "5727ca206dbafa2e099b022ed528f5bdf7874e3ec09c8f012159dfeeaab2b106"}, + {"000102030405", + "7740cf04577c107153a50b3abe44859f5245d3d545c6cbf5052e80258ae80607"}, + {"000102030406", + "ad6bbffaceb8020543ac82bcadb9d090b553ca1260035eae982d669ff6494f02"}, + {"000102030407", + "d2e116e9576ee5a29011c8fcb41259f99e6933b1d3bb660d0a9ac54e12e5cd06"}, + {"259ef2aba8feb473cf39058a0fe30b9ff6d245b42b6826687ebd6b63128aff64", + "3d6d3727dc50bca39e6ccfc9c12950eef5845e4278565d17f95559513a244d02"}, + {"44caa1c26187afe8dacc5d91cb8a51282334d9308a818fe4d3607275e2a61f05", + "aecc45c83f0408c96c70f8273e94f930edfbd3cd98896a0e57b1b5929fa5ff0b"}, + }; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + xmr_hash_to_scalar(a1, fromhex(tests[i][0]), strlen(tests[i][0]) / 2); + contract256_modm(out, a1); + ck_assert_mem_eq(out, fromhex(tests[i][1]), 32); + } } END_TEST - -START_TEST(test_xmr_hash_to_ec) -{ - ge25519 p1; - unsigned char out[32]; - char tests[][2][65] = { - {"", "d6d7d783ab18e1be65586adb7902a4175b737ef0b902875e1d1d5c5cf0478c0b"}, - {"00", "8e2fecb36320bc4e192e10ef54afc7c83fbeb0c38b7debd4fea51301f0bd4f3d"}, - {"000102", "73b233e2e75d81b9657a857e38e7ab2bc3600e5c56622b9fe4b976ff312220fa"}, - {"000102030405", "bebe3c84092c0f7a92704cafb16562cc45c47f45e84baec8d4bba3559d1c1808"}, - {"000102030406", "525567a6a40a94f2d916bc1efea234bbd3b9162403ec2faba871a90f8d0d487e"}, - {"000102030407", "99b1be2a92cbd22b24b48fb7a9daadd4d13a56915c4f6ed696f271ad5bdbc149"}, - {"42f6835bf83114a1f5f6076fe79bdfa0bd67c74b88f127d54572d3910dd09201", "54863a0464c008acc99cffb179bc6cf34eb1bbdf6c29f7a070a7c6376ae30ab5"}, - {"44caa1c26187afe8dacc5d91cb8a51282334d9308a818fe4d3607275e2a61f05", "001000a93e0e6937b4feaf079e418a028ca85459aa39ac3871b94076f88ca608"}, - }; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - xmr_hash_to_ec(&p1, fromhex(tests[i][0]), strlen(tests[i][0]) / 2); - ge25519_pack(out, &p1); - ck_assert_mem_eq(out, fromhex(tests[i][1]), 32); - } +START_TEST(test_xmr_hash_to_ec) { + ge25519 p1; + unsigned char out[32]; + char tests[][2][65] = { + {"", "d6d7d783ab18e1be65586adb7902a4175b737ef0b902875e1d1d5c5cf0478c0b"}, + {"00", + "8e2fecb36320bc4e192e10ef54afc7c83fbeb0c38b7debd4fea51301f0bd4f3d"}, + {"000102", + "73b233e2e75d81b9657a857e38e7ab2bc3600e5c56622b9fe4b976ff312220fa"}, + {"000102030405", + "bebe3c84092c0f7a92704cafb16562cc45c47f45e84baec8d4bba3559d1c1808"}, + {"000102030406", + "525567a6a40a94f2d916bc1efea234bbd3b9162403ec2faba871a90f8d0d487e"}, + {"000102030407", + "99b1be2a92cbd22b24b48fb7a9daadd4d13a56915c4f6ed696f271ad5bdbc149"}, + {"42f6835bf83114a1f5f6076fe79bdfa0bd67c74b88f127d54572d3910dd09201", + "54863a0464c008acc99cffb179bc6cf34eb1bbdf6c29f7a070a7c6376ae30ab5"}, + {"44caa1c26187afe8dacc5d91cb8a51282334d9308a818fe4d3607275e2a61f05", + "001000a93e0e6937b4feaf079e418a028ca85459aa39ac3871b94076f88ca608"}, + }; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + xmr_hash_to_ec(&p1, fromhex(tests[i][0]), strlen(tests[i][0]) / 2); + ge25519_pack(out, &p1); + ck_assert_mem_eq(out, fromhex(tests[i][1]), 32); + } } END_TEST - -START_TEST(test_xmr_derivation_to_scalar) -{ - static const struct { - char *pt; - uint32_t idx; - char *sc; - } tests[] = { - { - "c655b2d9d2670a1c9f26f7586b6d6b1ec5173b8b33bca64c3d305a42d66738b1", 0, - "ca7ce31b273dd1ac00dc3553e654fb66036804800e27c826bd2b78649243900b", - }, - { - "2b1dbd7a007dcc4d729fa8359705595599737fcef60afb36b379fe033095dca7", 1, - "60afd5a63b14845d3b92d16eac386713e4ff617fdc5c1a07c3212098c1f5610c", - }, - { - "a48ed3797225dab4b4316b5e40107b6bd63e5f4dc517ba602774d703576ec771", 24, - "fe81804091e50a5c2233faa6277360fbe1948ea15dddbae62c1d40bbd1918606", - }, - { - "fa27b5b39741f5341b4e89269e3a05ff7e76ec7739843872468fc4bec8475410", 65537, - "1ba36841f57aa8b799c4dd02b39d53e5fb7780d3f09f91a57a86dcb418d8d506", - }, - }; - - ge25519 pt; - bignum256modm sc, sc2; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - expand256_modm(sc, fromhex(tests[i].sc), 32); - ge25519_unpack_vartime(&pt, fromhex(tests[i].pt)); - - xmr_derivation_to_scalar(sc2, &pt, tests[i].idx); - ck_assert_int_eq(eq256_modm(sc, sc2), 1); - - xmr_derivation_to_scalar(sc2, &pt, tests[i].idx + 1); - ck_assert_int_eq(eq256_modm(sc, sc2), 0); - } +START_TEST(test_xmr_derivation_to_scalar) { + static const struct { + char *pt; + uint32_t idx; + char *sc; + } tests[] = { + { + "c655b2d9d2670a1c9f26f7586b6d6b1ec5173b8b33bca64c3d305a42d66738b1", + 0, + "ca7ce31b273dd1ac00dc3553e654fb66036804800e27c826bd2b78649243900b", + }, + { + "2b1dbd7a007dcc4d729fa8359705595599737fcef60afb36b379fe033095dca7", + 1, + "60afd5a63b14845d3b92d16eac386713e4ff617fdc5c1a07c3212098c1f5610c", + }, + { + "a48ed3797225dab4b4316b5e40107b6bd63e5f4dc517ba602774d703576ec771", + 24, + "fe81804091e50a5c2233faa6277360fbe1948ea15dddbae62c1d40bbd1918606", + }, + { + "fa27b5b39741f5341b4e89269e3a05ff7e76ec7739843872468fc4bec8475410", + 65537, + "1ba36841f57aa8b799c4dd02b39d53e5fb7780d3f09f91a57a86dcb418d8d506", + }, + }; + + ge25519 pt; + bignum256modm sc, sc2; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + expand256_modm(sc, fromhex(tests[i].sc), 32); + ge25519_unpack_vartime(&pt, fromhex(tests[i].pt)); + + xmr_derivation_to_scalar(sc2, &pt, tests[i].idx); + ck_assert_int_eq(eq256_modm(sc, sc2), 1); + + xmr_derivation_to_scalar(sc2, &pt, tests[i].idx + 1); + ck_assert_int_eq(eq256_modm(sc, sc2), 0); + } } END_TEST - -START_TEST(test_xmr_generate_key_derivation) -{ - static const struct { - char *pt; - char *sc; - char *r; - } tests[] = { - { - "38f94f27c8037aff025e365275ed1029fd636dda5f69e5f98fdcf92e0a28f31a", - "8f1c73ee5327a43264a7b60b9e7882312b582f33e89846a8694dbf094bb3a90a", - "1fbfe4dcc8c824c274649545f297fa320cd4c1689b1d0ff4887567c4d4a75649", - }, - { - "26785c3941a32f194228eb659c5ee305e63868896defc50ee6c4e0e92d1e246a", - "dbbffec4686ba8ab25e2f1b04c0e7ae51c5143c91353bfb5998430ebe365a609", - "cca34db8dd682ec164d8973b555253934596b77849ef7709d9321121c25aba02", - }, - { - "43505a8ce7248f70d3aae4f57fb59c254ce2b2a0cc2bcf50f2344e51d59b36b3", - "19a802e35f6ff94efe96ec016effe04e635bbd9c1ce2612d5ba2ee4659456b06", - "fc6c93a93f77ff89c18b9abf95b28ec8591ab97eee8e4afee93aa766a4bd3934", - }, - }; - - ge25519 pt, pt2, pt3; - bignum256modm sc; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - expand256_modm(sc, fromhex(tests[i].sc), 32); - ge25519_unpack_vartime(&pt, fromhex(tests[i].pt)); - ge25519_unpack_vartime(&pt2, fromhex(tests[i].r)); - xmr_generate_key_derivation(&pt3, &pt, sc); - ck_assert_int_eq(ge25519_eq(&pt3, &pt2), 1); - ck_assert_int_eq(ge25519_eq(&pt3, &pt), 0); - } +START_TEST(test_xmr_generate_key_derivation) { + static const struct { + char *pt; + char *sc; + char *r; + } tests[] = { + { + "38f94f27c8037aff025e365275ed1029fd636dda5f69e5f98fdcf92e0a28f31a", + "8f1c73ee5327a43264a7b60b9e7882312b582f33e89846a8694dbf094bb3a90a", + "1fbfe4dcc8c824c274649545f297fa320cd4c1689b1d0ff4887567c4d4a75649", + }, + { + "26785c3941a32f194228eb659c5ee305e63868896defc50ee6c4e0e92d1e246a", + "dbbffec4686ba8ab25e2f1b04c0e7ae51c5143c91353bfb5998430ebe365a609", + "cca34db8dd682ec164d8973b555253934596b77849ef7709d9321121c25aba02", + }, + { + "43505a8ce7248f70d3aae4f57fb59c254ce2b2a0cc2bcf50f2344e51d59b36b3", + "19a802e35f6ff94efe96ec016effe04e635bbd9c1ce2612d5ba2ee4659456b06", + "fc6c93a93f77ff89c18b9abf95b28ec8591ab97eee8e4afee93aa766a4bd3934", + }, + }; + + ge25519 pt, pt2, pt3; + bignum256modm sc; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + expand256_modm(sc, fromhex(tests[i].sc), 32); + ge25519_unpack_vartime(&pt, fromhex(tests[i].pt)); + ge25519_unpack_vartime(&pt2, fromhex(tests[i].r)); + xmr_generate_key_derivation(&pt3, &pt, sc); + ck_assert_int_eq(ge25519_eq(&pt3, &pt2), 1); + ck_assert_int_eq(ge25519_eq(&pt3, &pt), 0); + } } END_TEST - -START_TEST(test_xmr_derive_private_key) -{ - static const struct { - char *pt; - uint32_t idx; - char *base; - char *r; - } tests[] = { - { - "0541d8f069e5e80a892e39bbf1944ef578008cf9ecf1d100760a05858c1b709e", 0, - "76967eeb0a3d181bb0b384be71c680a4287599f27b2ddbd07f8e06ab6f2c880e", - "45728c5cb658e470790f124a01699d2126832b7e5c6b7760b6f11119b96ad603", - }, - { - "fc6e0bd785a84e62c9ac8a97e0e604a79494bc2cf7b3b38ef8af7791c87b5bb8", 1, - "32fbe149562b7ccb34bc4105b87b2a834024799336c8eea5e94df77f1ae9a807", - "64508e83bbadf63f8ecfae4d9dcdd39a4ba23508a545e1a37026f0fa2539d601", - }, - { - "f6bd7a72dc9444dc7e09a0eb4d312d36fe173693d6405b132a5b090297a04ea9", 65537, - "333a8fcce6726457e4222a87b9b475c1fcf985f756c2029fcb39184c0a5c4804", - "37c16a22da4c0082ebf4bf807403b169f75142a9bd8560ed45f3f9347218260e", - }, - }; - - ge25519 pt; - bignum256modm base, res, res_exp; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - expand256_modm(base, fromhex(tests[i].base), 32); - expand256_modm(res_exp, fromhex(tests[i].r), 32); - ge25519_unpack_vartime(&pt, fromhex(tests[i].pt)); - - xmr_derive_private_key(res, &pt, tests[i].idx, base); - ck_assert_int_eq(eq256_modm(res, res_exp), 1); - ck_assert_int_eq(eq256_modm(res, base), 0); - } +START_TEST(test_xmr_derive_private_key) { + static const struct { + char *pt; + uint32_t idx; + char *base; + char *r; + } tests[] = { + { + "0541d8f069e5e80a892e39bbf1944ef578008cf9ecf1d100760a05858c1b709e", + 0, + "76967eeb0a3d181bb0b384be71c680a4287599f27b2ddbd07f8e06ab6f2c880e", + "45728c5cb658e470790f124a01699d2126832b7e5c6b7760b6f11119b96ad603", + }, + { + "fc6e0bd785a84e62c9ac8a97e0e604a79494bc2cf7b3b38ef8af7791c87b5bb8", + 1, + "32fbe149562b7ccb34bc4105b87b2a834024799336c8eea5e94df77f1ae9a807", + "64508e83bbadf63f8ecfae4d9dcdd39a4ba23508a545e1a37026f0fa2539d601", + }, + { + "f6bd7a72dc9444dc7e09a0eb4d312d36fe173693d6405b132a5b090297a04ea9", + 65537, + "333a8fcce6726457e4222a87b9b475c1fcf985f756c2029fcb39184c0a5c4804", + "37c16a22da4c0082ebf4bf807403b169f75142a9bd8560ed45f3f9347218260e", + }, + }; + + ge25519 pt; + bignum256modm base, res, res_exp; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + expand256_modm(base, fromhex(tests[i].base), 32); + expand256_modm(res_exp, fromhex(tests[i].r), 32); + ge25519_unpack_vartime(&pt, fromhex(tests[i].pt)); + + xmr_derive_private_key(res, &pt, tests[i].idx, base); + ck_assert_int_eq(eq256_modm(res, res_exp), 1); + ck_assert_int_eq(eq256_modm(res, base), 0); + } } END_TEST - -START_TEST(test_xmr_derive_public_key) -{ - static const struct { - char *pt; - uint32_t idx; - char *base; - char *r; - } tests[] = { - { - "653f03e7766d472826aa49793bc0cfde698e6745ae5e4217980ba307739f2ed9", 0, - "2a393f0858732970ac8dea003b17e1ce9371f0a045bd9b7af0d998262739f4cc", - "f7a3db27c45f265f6a68a30137ca44289a6cf1a6db2cf482c59ebfb0142ad419", - }, - { - "338e93f61e6470a5cc71c07b8caedd1a9a28da037aab65c1ca5538501b012c81", 1, - "af3a1d39397d778731c4510110fd117dc02f756e390713d58f94a06203ce39eb", - "779e2a043c881f06aba1952741fd753098615c4fafa8f62748467ab9bac43241", - }, - { - "7735e9476440927b89b18d7a1e0645b218a1a6d28c642aebb16c1dba0926d5e4", 65537, - "62c3eed062bd602f7f2164c69ad0b5a8eb3ea560c930f6b41abfc1c4839ea432", - "6da4ebd29498d16c4e813abb3e328c83f9b01a7ba1da6e818071f8ec563626c8", - }, - }; - - ge25519 pt, base, res, res_exp; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - ge25519_unpack_vartime(&pt, fromhex(tests[i].pt)); - ge25519_unpack_vartime(&base, fromhex(tests[i].base)); - ge25519_unpack_vartime(&res_exp, fromhex(tests[i].r)); - - xmr_derive_public_key(&res, &pt, tests[i].idx, &base); - - ck_assert_int_eq(ge25519_eq(&res, &res_exp), 1); - ck_assert_int_eq(ge25519_eq(&res, &base), 0); - } +START_TEST(test_xmr_derive_public_key) { + static const struct { + char *pt; + uint32_t idx; + char *base; + char *r; + } tests[] = { + { + "653f03e7766d472826aa49793bc0cfde698e6745ae5e4217980ba307739f2ed9", + 0, + "2a393f0858732970ac8dea003b17e1ce9371f0a045bd9b7af0d998262739f4cc", + "f7a3db27c45f265f6a68a30137ca44289a6cf1a6db2cf482c59ebfb0142ad419", + }, + { + "338e93f61e6470a5cc71c07b8caedd1a9a28da037aab65c1ca5538501b012c81", + 1, + "af3a1d39397d778731c4510110fd117dc02f756e390713d58f94a06203ce39eb", + "779e2a043c881f06aba1952741fd753098615c4fafa8f62748467ab9bac43241", + }, + { + "7735e9476440927b89b18d7a1e0645b218a1a6d28c642aebb16c1dba0926d5e4", + 65537, + "62c3eed062bd602f7f2164c69ad0b5a8eb3ea560c930f6b41abfc1c4839ea432", + "6da4ebd29498d16c4e813abb3e328c83f9b01a7ba1da6e818071f8ec563626c8", + }, + }; + + ge25519 pt, base, res, res_exp; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + ge25519_unpack_vartime(&pt, fromhex(tests[i].pt)); + ge25519_unpack_vartime(&base, fromhex(tests[i].base)); + ge25519_unpack_vartime(&res_exp, fromhex(tests[i].r)); + + xmr_derive_public_key(&res, &pt, tests[i].idx, &base); + + ck_assert_int_eq(ge25519_eq(&res, &res_exp), 1); + ck_assert_int_eq(ge25519_eq(&res, &base), 0); + } } END_TEST - -START_TEST(test_xmr_add_keys2) -{ - static const struct { - char *a; - char *b; - char *B; - char *r; - } tests[] = { - { - "631238da9578d7cb8db16fc4322671bfcb251cc5228b060664800ec1895be608", - "f9a73fca0be058415a148f9e2871be59e1fc7ae6f6193199125237e0d7c1630f", - "ef5ca4fc90f330e825adcdc953da0b3becd853aa819219842790bb39775f2255", - "06623fd0e7a3d787a4d224f6ca2fdab2dcd9d1221578515974b9c4dee65fdcf5", - }, - { - "dac2e629e5c75c312253b19d1d3a0a423158fdd9cdcf4c7a7bf2717d0b748602", - "0483d98d750d4977b499cefd558a0a61580823a37da2b011501e24718e6c7f0a", - "51fd3cd2f1a603ec7be3b35da9c105d91c4304e6a63facf48d7730712cedc0ee", - "f7a5d645ba01a5b7ccbe9636d14422bb587fc529317b23761f0e39222b783b87", - }, - { - "817c4d2fd3e841d860bdab6b7ccf098f3e637eca468d0a3825c50b71f61d0e0c", - "1f6c4795d7fb0d53b5775874ac4c0963607d2b7bd11a7c5d10735badc4a27207", - "bef0e0ed09d602bbe1dd38358b5f8fca27fcad60a69440f104441c3fc68df9c7", - "bc0fc824d74eca0e10eacd0bc2f3322e0bcb02a44ce53f2f5f1fc472f99be8d2", - }, - }; - - bignum256modm a, b; - ge25519 B, res, res_exp; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - expand256_modm(a, fromhex(tests[i].a), 32); - expand256_modm(b, fromhex(tests[i].b), 32); - ge25519_unpack_vartime(&B, fromhex(tests[i].B)); - ge25519_unpack_vartime(&res_exp, fromhex(tests[i].r)); - - xmr_add_keys2(&res, a, b, &B); - ck_assert_int_eq(ge25519_eq(&res, &res_exp), 1); - ck_assert_int_eq(ge25519_eq(&res, &B), 0); - - xmr_add_keys2_vartime(&res, a, b, &B); - ck_assert_int_eq(ge25519_eq(&res, &res_exp), 1); - ck_assert_int_eq(ge25519_eq(&res, &B), 0); - } +START_TEST(test_xmr_add_keys2) { + static const struct { + char *a; + char *b; + char *B; + char *r; + } tests[] = { + { + "631238da9578d7cb8db16fc4322671bfcb251cc5228b060664800ec1895be608", + "f9a73fca0be058415a148f9e2871be59e1fc7ae6f6193199125237e0d7c1630f", + "ef5ca4fc90f330e825adcdc953da0b3becd853aa819219842790bb39775f2255", + "06623fd0e7a3d787a4d224f6ca2fdab2dcd9d1221578515974b9c4dee65fdcf5", + }, + { + "dac2e629e5c75c312253b19d1d3a0a423158fdd9cdcf4c7a7bf2717d0b748602", + "0483d98d750d4977b499cefd558a0a61580823a37da2b011501e24718e6c7f0a", + "51fd3cd2f1a603ec7be3b35da9c105d91c4304e6a63facf48d7730712cedc0ee", + "f7a5d645ba01a5b7ccbe9636d14422bb587fc529317b23761f0e39222b783b87", + }, + { + "817c4d2fd3e841d860bdab6b7ccf098f3e637eca468d0a3825c50b71f61d0e0c", + "1f6c4795d7fb0d53b5775874ac4c0963607d2b7bd11a7c5d10735badc4a27207", + "bef0e0ed09d602bbe1dd38358b5f8fca27fcad60a69440f104441c3fc68df9c7", + "bc0fc824d74eca0e10eacd0bc2f3322e0bcb02a44ce53f2f5f1fc472f99be8d2", + }, + }; + + bignum256modm a, b; + ge25519 B, res, res_exp; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + expand256_modm(a, fromhex(tests[i].a), 32); + expand256_modm(b, fromhex(tests[i].b), 32); + ge25519_unpack_vartime(&B, fromhex(tests[i].B)); + ge25519_unpack_vartime(&res_exp, fromhex(tests[i].r)); + + xmr_add_keys2(&res, a, b, &B); + ck_assert_int_eq(ge25519_eq(&res, &res_exp), 1); + ck_assert_int_eq(ge25519_eq(&res, &B), 0); + + xmr_add_keys2_vartime(&res, a, b, &B); + ck_assert_int_eq(ge25519_eq(&res, &res_exp), 1); + ck_assert_int_eq(ge25519_eq(&res, &B), 0); + } } END_TEST - -START_TEST(test_xmr_add_keys3) -{ - static const struct { - char *a; - char *A; - char *b; - char *B; - char *r; - } tests[] = { - { - "7048b8c4603ae194c502fa458b0e11a4c7a330852bbef66b7c1d67e9f919f509", - "9167c5b182758699baeb421e7f1200272fc775e4c7c7c183cc47261dccbb569f", - "c2cb2bc0249fc7be8eb9b3bed7d37aa6f2c3f433abb3a4a00b13bed64b61f30b", - "b3ec53b07a1be70ac8d0fa365b86f0d6d4cbf98641e7704b3d684558e2ea59ef", - "4dc016d702d599bde5eaeb2bf0c2d0d3f6b9cede961bc539bcb369c3b3086358", - }, - { - "e9794a6652940474958936f07f3904d514228553247633cfb7ae8ffa9fa0f406", - "0e51cea6df2f6f56a9935689364f0d295a7c89f51d40efb2518c17d1b9db792b", - "c132e7be08afdd93984c52c6e1c596edc6b8fc8f1faed95f55e2f819ee806706", - "1a0e03c6858f6cf1b43f4b8456c03144af553bbbd050e152834fd1615b577cb3", - "088f19c6727f8704373d391a36c230395d386f69edb4151ecf8afcd27793fff5", - }, - { - "88920b0c96b15cc04e879f53a76f85f3c7a2a5f275b2772b5b74ee83372aea00", - "e95731ab61a98fedcded475cf21b4ecf2ef9f1adecefba8fdc476a5bb1cf60f9", - "c86026b66c1045fb69e4f24ff6c15d4fad4d565e646938a2ffb7db37ccb4100d", - "d80cbf2986c12e4c7ebac1e55abbdfc4212c00aec8bc90c965becf863262a074", - "047cebaeb3ec2132e7386ba52531b04070206ba1106565c0fbd7d7280694568a", - }, - }; - - bignum256modm a, b; - ge25519 A, B, res, res_exp; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - expand256_modm(a, fromhex(tests[i].a), 32); - expand256_modm(b, fromhex(tests[i].b), 32); - ge25519_unpack_vartime(&A, fromhex(tests[i].A)); - ge25519_unpack_vartime(&B, fromhex(tests[i].B)); - ge25519_unpack_vartime(&res_exp, fromhex(tests[i].r)); - - xmr_add_keys3(&res, a, &A, b, &B); - ck_assert_int_eq(ge25519_eq(&res, &res_exp), 1); - ck_assert_int_eq(ge25519_eq(&res, &B), 0); - - xmr_add_keys3_vartime(&res, a, &A, b, &B); - ck_assert_int_eq(ge25519_eq(&res, &res_exp), 1); - ck_assert_int_eq(ge25519_eq(&res, &B), 0); - } +START_TEST(test_xmr_add_keys3) { + static const struct { + char *a; + char *A; + char *b; + char *B; + char *r; + } tests[] = { + { + "7048b8c4603ae194c502fa458b0e11a4c7a330852bbef66b7c1d67e9f919f509", + "9167c5b182758699baeb421e7f1200272fc775e4c7c7c183cc47261dccbb569f", + "c2cb2bc0249fc7be8eb9b3bed7d37aa6f2c3f433abb3a4a00b13bed64b61f30b", + "b3ec53b07a1be70ac8d0fa365b86f0d6d4cbf98641e7704b3d684558e2ea59ef", + "4dc016d702d599bde5eaeb2bf0c2d0d3f6b9cede961bc539bcb369c3b3086358", + }, + { + "e9794a6652940474958936f07f3904d514228553247633cfb7ae8ffa9fa0f406", + "0e51cea6df2f6f56a9935689364f0d295a7c89f51d40efb2518c17d1b9db792b", + "c132e7be08afdd93984c52c6e1c596edc6b8fc8f1faed95f55e2f819ee806706", + "1a0e03c6858f6cf1b43f4b8456c03144af553bbbd050e152834fd1615b577cb3", + "088f19c6727f8704373d391a36c230395d386f69edb4151ecf8afcd27793fff5", + }, + { + "88920b0c96b15cc04e879f53a76f85f3c7a2a5f275b2772b5b74ee83372aea00", + "e95731ab61a98fedcded475cf21b4ecf2ef9f1adecefba8fdc476a5bb1cf60f9", + "c86026b66c1045fb69e4f24ff6c15d4fad4d565e646938a2ffb7db37ccb4100d", + "d80cbf2986c12e4c7ebac1e55abbdfc4212c00aec8bc90c965becf863262a074", + "047cebaeb3ec2132e7386ba52531b04070206ba1106565c0fbd7d7280694568a", + }, + }; + + bignum256modm a, b; + ge25519 A, B, res, res_exp; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + expand256_modm(a, fromhex(tests[i].a), 32); + expand256_modm(b, fromhex(tests[i].b), 32); + ge25519_unpack_vartime(&A, fromhex(tests[i].A)); + ge25519_unpack_vartime(&B, fromhex(tests[i].B)); + ge25519_unpack_vartime(&res_exp, fromhex(tests[i].r)); + + xmr_add_keys3(&res, a, &A, b, &B); + ck_assert_int_eq(ge25519_eq(&res, &res_exp), 1); + ck_assert_int_eq(ge25519_eq(&res, &B), 0); + + xmr_add_keys3_vartime(&res, a, &A, b, &B); + ck_assert_int_eq(ge25519_eq(&res, &res_exp), 1); + ck_assert_int_eq(ge25519_eq(&res, &B), 0); + } } END_TEST - -START_TEST(test_xmr_get_subaddress_secret_key) -{ - static const struct { - uint32_t major, minor; - char *m; - char *r; - } tests[] = { - { - 0, 0, - "36fad9f7bff465c15a755f1482fb2ecc3a4e434303df906882234e42b5813207", - "8a510a9fe1824b49abbae05958084f9c9098775f29e15427309177882471cf01", - }, - { - 0, 1, - "36fad9f7bff465c15a755f1482fb2ecc3a4e434303df906882234e42b5813207", - "2bbc9366c04abb0523e2b2d6e709670ffe6645bacedfee968d9c6bc8eefe9c0f", - }, - { - 100, 100, - "36fad9f7bff465c15a755f1482fb2ecc3a4e434303df906882234e42b5813207", - "c3837d41fedeaed126cf4fc1a5ea47b8b7f38f6a64aa534e3dd45a3c93f37600", - }, - }; - - bignum256modm m, res, res_exp; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - expand256_modm(m, fromhex(tests[i].m), 32); - expand256_modm(res_exp, fromhex(tests[i].r), 32); - xmr_get_subaddress_secret_key(res, tests[i].major, tests[i].minor, m); - - ck_assert_int_eq(eq256_modm(res, res_exp), 1); - ck_assert_int_eq(eq256_modm(res, m), 0); - } +START_TEST(test_xmr_get_subaddress_secret_key) { + static const struct { + uint32_t major, minor; + char *m; + char *r; + } tests[] = { + { + 0, + 0, + "36fad9f7bff465c15a755f1482fb2ecc3a4e434303df906882234e42b5813207", + "8a510a9fe1824b49abbae05958084f9c9098775f29e15427309177882471cf01", + }, + { + 0, + 1, + "36fad9f7bff465c15a755f1482fb2ecc3a4e434303df906882234e42b5813207", + "2bbc9366c04abb0523e2b2d6e709670ffe6645bacedfee968d9c6bc8eefe9c0f", + }, + { + 100, + 100, + "36fad9f7bff465c15a755f1482fb2ecc3a4e434303df906882234e42b5813207", + "c3837d41fedeaed126cf4fc1a5ea47b8b7f38f6a64aa534e3dd45a3c93f37600", + }, + }; + + bignum256modm m, res, res_exp; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + expand256_modm(m, fromhex(tests[i].m), 32); + expand256_modm(res_exp, fromhex(tests[i].r), 32); + xmr_get_subaddress_secret_key(res, tests[i].major, tests[i].minor, m); + + ck_assert_int_eq(eq256_modm(res, res_exp), 1); + ck_assert_int_eq(eq256_modm(res, m), 0); + } } END_TEST - -START_TEST(test_xmr_gen_c) -{ - static const struct { - char *a; - uint64_t amount; - char *r; - } tests[] = { - { - "e3e6558c291bbb98aa691d068b67d59dc520afb23fdd51bf65283626fc2ad903", 0, - "ef19d73bdf3749240b80ee7695f53ad7c2fc2cf868a93209799f41212d099750", - }, - { - "6788c9579c377f3228680bd0e6d01b1ee0c763b35ed39d36fa2146cc2ee16e0e", 1, - "4913b9af4f2725d87a4404c22cf366597d1c1e6a1f510ae14081d8b7c5a9de77", - }, - { - "ad9e89d67012935540427c241756d6a9d260c5e134603c41d31e24f8651bef08", 65537, - "f005721da08f24e68314abed3ddfd94165e4be3813398fb126e3f366820b9c90", - }, - { - "fdbb70ff07be24d98de3bffa0a33756646497224318fb7fe136f0e7789d12607", 0xffffffffffffffffULL, - "a9c38927f299c5f14c98a1a9c9981e59c606ff597274b9b709e1356f12e1498c", - }, - }; - - bignum256modm a; - ge25519 res, res_exp; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - expand256_modm(a, fromhex(tests[i].a), 32); - ge25519_unpack_vartime(&res_exp, fromhex(tests[i].r)); - xmr_gen_c(&res, a, tests[i].amount); - - ck_assert_int_eq(ge25519_eq(&res, &res_exp), 1); - } +START_TEST(test_xmr_gen_c) { + static const struct { + char *a; + uint64_t amount; + char *r; + } tests[] = { + { + "e3e6558c291bbb98aa691d068b67d59dc520afb23fdd51bf65283626fc2ad903", + 0, + "ef19d73bdf3749240b80ee7695f53ad7c2fc2cf868a93209799f41212d099750", + }, + { + "6788c9579c377f3228680bd0e6d01b1ee0c763b35ed39d36fa2146cc2ee16e0e", + 1, + "4913b9af4f2725d87a4404c22cf366597d1c1e6a1f510ae14081d8b7c5a9de77", + }, + { + "ad9e89d67012935540427c241756d6a9d260c5e134603c41d31e24f8651bef08", + 65537, + "f005721da08f24e68314abed3ddfd94165e4be3813398fb126e3f366820b9c90", + }, + { + "fdbb70ff07be24d98de3bffa0a33756646497224318fb7fe136f0e7789d12607", + 0xffffffffffffffffULL, + "a9c38927f299c5f14c98a1a9c9981e59c606ff597274b9b709e1356f12e1498c", + }, + }; + + bignum256modm a; + ge25519 res, res_exp; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + expand256_modm(a, fromhex(tests[i].a), 32); + ge25519_unpack_vartime(&res_exp, fromhex(tests[i].r)); + xmr_gen_c(&res, a, tests[i].amount); + + ck_assert_int_eq(ge25519_eq(&res, &res_exp), 1); + } } END_TEST - -START_TEST(test_xmr_varint) -{ - static const struct { - uint64_t x; - char *r; - } tests[] = { - { - 0, - "00", - }, - { - 24, - "18", - }, - { - 65535, - "ffff03", - }, - { - 65537, - "818004", - }, - { - 0x7fffffffULL, - "ffffffff07", - }, - { - 0xffffffffULL, - "ffffffff0f", - }, - { - 0xffffffffffffffffULL, - "ffffffffffffffffff01", - }, - { - 0xdeadc0deULL, - "de81b7f50d", - }, - }; - - uint64_t val; - unsigned char buff[64]; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - int s1 = xmr_size_varint(tests[i].x); - int written = 0; - int read = 0; - - ck_assert_int_eq(s1, strlen(tests[i].r)/2); - written = xmr_write_varint(buff, sizeof(buff), tests[i].x); - ck_assert_int_eq(s1, written); - ck_assert_mem_eq(buff, fromhex(tests[i].r), strlen(tests[i].r)/2); - - read = xmr_read_varint(buff, sizeof(buff), &val); - ck_assert_int_eq(read, written); - ck_assert(tests[i].x == val); - } +START_TEST(test_xmr_varint) { + static const struct { + uint64_t x; + char *r; + } tests[] = { + { + 0, + "00", + }, + { + 24, + "18", + }, + { + 65535, + "ffff03", + }, + { + 65537, + "818004", + }, + { + 0x7fffffffULL, + "ffffffff07", + }, + { + 0xffffffffULL, + "ffffffff0f", + }, + { + 0xffffffffffffffffULL, + "ffffffffffffffffff01", + }, + { + 0xdeadc0deULL, + "de81b7f50d", + }, + }; + + uint64_t val; + unsigned char buff[64]; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + int s1 = xmr_size_varint(tests[i].x); + int written = 0; + int read = 0; + + ck_assert_int_eq(s1, strlen(tests[i].r) / 2); + written = xmr_write_varint(buff, sizeof(buff), tests[i].x); + ck_assert_int_eq(s1, written); + ck_assert_mem_eq(buff, fromhex(tests[i].r), strlen(tests[i].r) / 2); + + read = xmr_read_varint(buff, sizeof(buff), &val); + ck_assert_int_eq(read, written); + ck_assert(tests[i].x == val); + } } END_TEST +START_TEST(test_xmr_gen_range_sig) { + uint64_t tests[] = { + 0, 1, 65535, 65537, 0xffffffffffffffffULL, 0xdeadc0deULL, + }; -START_TEST(test_xmr_gen_range_sig) -{ - uint64_t tests[] = { - 0, 1, 65535, 65537, 0xffffffffffffffffULL, 0xdeadc0deULL, - }; - - unsigned char buff[32]; - xmr_range_sig_t sig; - ge25519 C, Ctmp, Cb, Ch, P1, P2, LL; - bignum256modm mask, hsh, ee, s, ee_comp; - Hasher hasher; + unsigned char buff[32]; + xmr_range_sig_t sig; + ge25519 C, Ctmp, Cb, Ch, P1, P2, LL; + bignum256modm mask, hsh, ee, s, ee_comp; + Hasher hasher; - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - xmr_gen_range_sig(&sig, &C, mask, tests[i], NULL); + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + xmr_gen_range_sig(&sig, &C, mask, tests[i], NULL); - ge25519_set_neutral(&Ctmp); - for(int j = 0; j < XMR_ATOMS; j++){ - ge25519_unpack_vartime(&Cb, sig.Ci[j]); - ge25519_add(&Ctmp, &Ctmp, &Cb, 0); - } + ge25519_set_neutral(&Ctmp); + for (int j = 0; j < XMR_ATOMS; j++) { + ge25519_unpack_vartime(&Cb, sig.Ci[j]); + ge25519_add(&Ctmp, &Ctmp, &Cb, 0); + } - ck_assert_int_eq(ge25519_eq(&C, &Ctmp), 1); + ck_assert_int_eq(ge25519_eq(&C, &Ctmp), 1); - xmr_hasher_init(&hasher); - ge25519_set_xmr_h(&Ch); - expand256_modm(ee, sig.asig.ee, 32); + xmr_hasher_init(&hasher); + ge25519_set_xmr_h(&Ch); + expand256_modm(ee, sig.asig.ee, 32); - for(int j = 0; j < XMR_ATOMS; j++){ - ge25519_unpack_vartime(&P1, sig.Ci[j]); - ge25519_add(&P2, &P1, &Ch, 1); - expand256_modm(s, sig.asig.s0[j], 32); + for (int j = 0; j < XMR_ATOMS; j++) { + ge25519_unpack_vartime(&P1, sig.Ci[j]); + ge25519_add(&P2, &P1, &Ch, 1); + expand256_modm(s, sig.asig.s0[j], 32); - xmr_add_keys2(&LL, s, ee, &P1); - ge25519_pack(buff, &LL); - xmr_hash_to_scalar(hsh, buff, 32); + xmr_add_keys2(&LL, s, ee, &P1); + ge25519_pack(buff, &LL); + xmr_hash_to_scalar(hsh, buff, 32); - expand256_modm(s, sig.asig.s1[j], 32); - xmr_add_keys2(&LL, s, hsh, &P2); + expand256_modm(s, sig.asig.s1[j], 32); + xmr_add_keys2(&LL, s, hsh, &P2); - ge25519_pack(buff, &LL); - xmr_hasher_update(&hasher, buff, 32); + ge25519_pack(buff, &LL); + xmr_hasher_update(&hasher, buff, 32); - ge25519_double(&Ch, &Ch); - } + ge25519_double(&Ch, &Ch); + } - xmr_hasher_final(&hasher, buff); - expand256_modm(ee_comp, buff, 32); - ck_assert_int_eq(eq256_modm(ee, ee_comp), 1); - } + xmr_hasher_final(&hasher, buff); + expand256_modm(ee_comp, buff, 32); + ck_assert_int_eq(eq256_modm(ee, ee_comp), 1); + } } END_TEST #endif diff --git a/tests/test_check_segwit.h b/tests/test_check_segwit.h index c0b7ef403..89dcaf9ae 100644 --- a/tests/test_check_segwit.h +++ b/tests/test_check_segwit.h @@ -1,184 +1,160 @@ #include "segwit_addr.h" static const char* valid_checksum[] = { - "A12UEL5L", - "an83characterlonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1tt5tgs", - "abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw", - "11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc8247j", - "split1checkupstagehandshakeupstreamerranterredcaperred2y9e3w", + "A12UEL5L", + "an83characterlonghumanreadablepartthatcontainsthenumber1andtheexcludedchar" + "actersbio1tt5tgs", + "abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw", + "11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq" + "qqqqqqqqqqc8247j", + "split1checkupstagehandshakeupstreamerranterredcaperred2y9e3w", }; static const char* invalid_checksum[] = { - " 1nwldj5", - "\x7f""1axkwrx", - "an84characterslonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1569pvx", - "pzry9x0s0muk", - "1pzry9x0s0muk", - "x1b4n0q5v", - "li1dgmt3", - "de1lg7wt\xff", + " 1nwldj5", + "\x7f" + "1axkwrx", + "an84characterslonghumanreadablepartthatcontainsthenumber1andtheexcludedcha" + "ractersbio1569pvx", + "pzry9x0s0muk", + "1pzry9x0s0muk", + "x1b4n0q5v", + "li1dgmt3", + "de1lg7wt\xff", }; struct valid_address_data { - const char* address; - size_t scriptPubKeyLen; - const uint8_t scriptPubKey[42]; + const char* address; + size_t scriptPubKeyLen; + const uint8_t scriptPubKey[42]; }; struct invalid_address_data { - const char* hrp; - int version; - size_t program_length; + const char* hrp; + int version; + size_t program_length; }; static struct valid_address_data valid_address[] = { - { - "BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4", - 22, { - 0x00, 0x14, 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, - 0x94, 0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6 - } - }, - { - "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7", - 34, { - 0x00, 0x20, 0x18, 0x63, 0x14, 0x3c, 0x14, 0xc5, 0x16, 0x68, 0x04, - 0xbd, 0x19, 0x20, 0x33, 0x56, 0xda, 0x13, 0x6c, 0x98, 0x56, 0x78, - 0xcd, 0x4d, 0x27, 0xa1, 0xb8, 0xc6, 0x32, 0x96, 0x04, 0x90, 0x32, - 0x62 - } - }, - { - "bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7k7grplx", - 42, { - 0x51, 0x28, 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, - 0x94, 0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6, - 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, 0x94, 0x1c, - 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6 - } - }, - { - "BC1SW50QA3JX3S", - 4, { - 0x60, 0x02, 0x75, 0x1e - } - }, - { - "bc1zw508d6qejxtdg4y5r3zarvaryvg6kdaj", - 18, { - 0x52, 0x10, 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, - 0x94, 0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23 - } - }, - { - "tb1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesrxh6hy", - 34, { - 0x00, 0x20, 0x00, 0x00, 0x00, 0xc4, 0xa5, 0xca, 0xd4, 0x62, 0x21, - 0xb2, 0xa1, 0x87, 0x90, 0x5e, 0x52, 0x66, 0x36, 0x2b, 0x99, 0xd5, - 0xe9, 0x1c, 0x6c, 0xe2, 0x4d, 0x16, 0x5d, 0xab, 0x93, 0xe8, 0x64, - 0x33 - } - } -}; + {"BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4", + 22, + {0x00, 0x14, 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, + 0x94, 0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6}}, + {"tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7", + 34, + {0x00, 0x20, 0x18, 0x63, 0x14, 0x3c, 0x14, 0xc5, 0x16, 0x68, 0x04, 0xbd, + 0x19, 0x20, 0x33, 0x56, 0xda, 0x13, 0x6c, 0x98, 0x56, 0x78, 0xcd, 0x4d, + 0x27, 0xa1, 0xb8, 0xc6, 0x32, 0x96, 0x04, 0x90, 0x32, 0x62}}, + {"bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7k7grpl" + "x", + 42, + {0x51, 0x28, 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, + 0x94, 0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6, + 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, 0x94, 0x1c, + 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6}}, + {"BC1SW50QA3JX3S", 4, {0x60, 0x02, 0x75, 0x1e}}, + {"bc1zw508d6qejxtdg4y5r3zarvaryvg6kdaj", + 18, + {0x52, 0x10, 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, 0x94, + 0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23}}, + {"tb1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesrxh6hy", + 34, + {0x00, 0x20, 0x00, 0x00, 0x00, 0xc4, 0xa5, 0xca, 0xd4, 0x62, 0x21, 0xb2, + 0xa1, 0x87, 0x90, 0x5e, 0x52, 0x66, 0x36, 0x2b, 0x99, 0xd5, 0xe9, 0x1c, + 0x6c, 0xe2, 0x4d, 0x16, 0x5d, 0xab, 0x93, 0xe8, 0x64, 0x33}}}; static const char* invalid_address[] = { - "tc1qw508d6qejxtdg4y5r3zarvary0c5xw7kg3g4ty", - "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t5", - "BC13W508D6QEJXTDG4Y5R3ZARVARY0C5XW7KN40WF2", - "bc1rw5uspcuh", - "bc10w508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kw5rljs90", - "BC1QR508D6QEJXTDG4Y5R3ZARVARYV98GJ9P", - "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sL5k7", - "bc1zw508d6qejxtdg4y5r3zarvaryvqyzf3du", - "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3pjxtptv", - "bc1gmk9yu", + "tc1qw508d6qejxtdg4y5r3zarvary0c5xw7kg3g4ty", + "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t5", + "BC13W508D6QEJXTDG4Y5R3ZARVARY0C5XW7KN40WF2", + "bc1rw5uspcuh", + "bc10w508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kw5rljs" + "90", + "BC1QR508D6QEJXTDG4Y5R3ZARVARYV98GJ9P", + "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sL5k7", + "bc1zw508d6qejxtdg4y5r3zarvaryvqyzf3du", + "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3pjxtptv", + "bc1gmk9yu", }; static struct invalid_address_data invalid_address_enc[] = { - {"BC", 0, 20}, - {"bc", 0, 21}, - {"bc", 17, 32}, - {"bc", 1, 1}, - {"bc", 16, 41}, + {"BC", 0, 20}, {"bc", 0, 21}, {"bc", 17, 32}, {"bc", 1, 1}, {"bc", 16, 41}, }; -static void segwit_scriptpubkey(uint8_t* scriptpubkey, size_t* scriptpubkeylen, int witver, const uint8_t* witprog, size_t witprog_len) { - scriptpubkey[0] = witver ? (0x50 + witver) : 0; - scriptpubkey[1] = witprog_len; - memcpy(scriptpubkey + 2, witprog, witprog_len); - *scriptpubkeylen = witprog_len + 2; -} - -int my_strncasecmp(const char *s1, const char *s2, size_t n) { - size_t i = 0; - while (i < n) { - char c1 = s1[i]; - char c2 = s2[i]; - if (c1 >= 'A' && c1 <= 'Z') c1 = (c1 - 'A') + 'a'; - if (c2 >= 'A' && c2 <= 'Z') c2 = (c2 - 'A') + 'a'; - if (c1 < c2) return -1; - if (c1 > c2) return 1; - if (c1 == 0) return 0; - ++i; - } - return 0; +static void segwit_scriptpubkey(uint8_t* scriptpubkey, size_t* scriptpubkeylen, + int witver, const uint8_t* witprog, + size_t witprog_len) { + scriptpubkey[0] = witver ? (0x50 + witver) : 0; + scriptpubkey[1] = witprog_len; + memcpy(scriptpubkey + 2, witprog, witprog_len); + *scriptpubkeylen = witprog_len + 2; } -START_TEST(test_segwit) -{ - size_t i; - for (i = 0; i < sizeof(valid_checksum) / sizeof(valid_checksum[0]); ++i) { - uint8_t data[82]; - char rebuild[92]; - char hrp[84]; - size_t data_len; - int res = bech32_decode(hrp, data, &data_len, valid_checksum[i]); - ck_assert_int_eq(res, 1); - res = bech32_encode(rebuild, hrp, data, data_len); - ck_assert_int_eq(res, 1); - ck_assert_int_eq(my_strncasecmp(rebuild, valid_checksum[i], 92), 0); - } - for (i = 0; i < sizeof(invalid_checksum) / sizeof(invalid_checksum[0]); ++i) { - uint8_t data[82]; - char hrp[84]; - size_t data_len; - int res = bech32_decode(hrp, data, &data_len, invalid_checksum[i]); - ck_assert_int_eq(res, 0); - } - for (i = 0; i < sizeof(valid_address) / sizeof(valid_address[0]); ++i) { - uint8_t witprog[40]; - size_t witprog_len; - int witver; - const char* hrp = "bc"; - uint8_t scriptpubkey[42]; - size_t scriptpubkey_len; - char rebuild[93]; - int ret = segwit_addr_decode(&witver, witprog, &witprog_len, hrp, valid_address[i].address); - if (!ret) { - hrp = "tb"; - ret = segwit_addr_decode(&witver, witprog, &witprog_len, hrp, valid_address[i].address); - } - ck_assert_int_eq(ret, 1); - segwit_scriptpubkey(scriptpubkey, &scriptpubkey_len, witver, witprog, witprog_len); - ck_assert_int_eq(scriptpubkey_len, valid_address[i].scriptPubKeyLen); - ck_assert_int_eq(memcmp(scriptpubkey, valid_address[i].scriptPubKey, scriptpubkey_len), 0); - ck_assert_int_eq(segwit_addr_encode(rebuild, hrp, witver, witprog, witprog_len), 1); - ck_assert_int_eq(my_strncasecmp(valid_address[i].address, rebuild, 93), 0); - } - for (i = 0; i < sizeof(invalid_address) / sizeof(invalid_address[0]); ++i) { - uint8_t witprog[40]; - size_t witprog_len; - int witver; - int ret = segwit_addr_decode(&witver, witprog, &witprog_len, "bc", invalid_address[i]); - ck_assert_int_eq(ret, 0); - ret = segwit_addr_decode(&witver, witprog, &witprog_len, "tb", invalid_address[i]); - ck_assert_int_eq(ret, 0); - } - for (i = 0; i < sizeof(invalid_address_enc) / sizeof(invalid_address_enc[0]); ++i) { - char rebuild[93]; - static const uint8_t program[42] = {0}; - int ret = segwit_addr_encode(rebuild, invalid_address_enc[i].hrp, invalid_address_enc[i].version, program, invalid_address_enc[i].program_length); - ck_assert_int_eq(ret, 0); - } +START_TEST(test_segwit) { + size_t i; + for (i = 0; i < sizeof(valid_checksum) / sizeof(valid_checksum[0]); ++i) { + uint8_t data[82]; + char rebuild[92]; + char hrp[84]; + size_t data_len; + int res = bech32_decode(hrp, data, &data_len, valid_checksum[i]); + ck_assert_int_eq(res, 1); + res = bech32_encode(rebuild, hrp, data, data_len); + ck_assert_int_eq(res, 1); + ck_assert_int_eq(my_strncasecmp(rebuild, valid_checksum[i], 92), 0); + } + for (i = 0; i < sizeof(invalid_checksum) / sizeof(invalid_checksum[0]); ++i) { + uint8_t data[82]; + char hrp[84]; + size_t data_len; + int res = bech32_decode(hrp, data, &data_len, invalid_checksum[i]); + ck_assert_int_eq(res, 0); + } + for (i = 0; i < sizeof(valid_address) / sizeof(valid_address[0]); ++i) { + uint8_t witprog[40]; + size_t witprog_len; + int witver; + const char* hrp = "bc"; + uint8_t scriptpubkey[42]; + size_t scriptpubkey_len; + char rebuild[93]; + int ret = segwit_addr_decode(&witver, witprog, &witprog_len, hrp, + valid_address[i].address); + if (!ret) { + hrp = "tb"; + ret = segwit_addr_decode(&witver, witprog, &witprog_len, hrp, + valid_address[i].address); + } + ck_assert_int_eq(ret, 1); + segwit_scriptpubkey(scriptpubkey, &scriptpubkey_len, witver, witprog, + witprog_len); + ck_assert_int_eq(scriptpubkey_len, valid_address[i].scriptPubKeyLen); + ck_assert_int_eq( + memcmp(scriptpubkey, valid_address[i].scriptPubKey, scriptpubkey_len), + 0); + ck_assert_int_eq( + segwit_addr_encode(rebuild, hrp, witver, witprog, witprog_len), 1); + ck_assert_int_eq(my_strncasecmp(valid_address[i].address, rebuild, 93), 0); + } + for (i = 0; i < sizeof(invalid_address) / sizeof(invalid_address[0]); ++i) { + uint8_t witprog[40]; + size_t witprog_len; + int witver; + int ret = segwit_addr_decode(&witver, witprog, &witprog_len, "bc", + invalid_address[i]); + ck_assert_int_eq(ret, 0); + ret = segwit_addr_decode(&witver, witprog, &witprog_len, "tb", + invalid_address[i]); + ck_assert_int_eq(ret, 0); + } + for (i = 0; i < sizeof(invalid_address_enc) / sizeof(invalid_address_enc[0]); + ++i) { + char rebuild[93]; + static const uint8_t program[42] = {0}; + int ret = segwit_addr_encode(rebuild, invalid_address_enc[i].hrp, + invalid_address_enc[i].version, program, + invalid_address_enc[i].program_length); + ck_assert_int_eq(ret, 0); + } } END_TEST diff --git a/tests/test_openssl.c b/tests/test_openssl.c index d0a80f074..c6ce47894 100644 --- a/tests/test_openssl.c +++ b/tests/test_openssl.c @@ -27,118 +27,117 @@ #include #include #include -#include #include +#include #undef SHA256_CTX #undef SHA512_CTX -#include #include +#include #include #include "ecdsa.h" -#include "rand.h" #include "hasher.h" +#include "rand.h" #include "nist256p1.h" #include "secp256k1.h" #include "memzero.h" -void openssl_check(unsigned int iterations, int nid, const ecdsa_curve *curve) -{ - uint8_t sig[64], pub_key33[33], pub_key65[65], priv_key[32], msg[256], hash[32]; - struct SHA256state_st sha256; - EC_GROUP *ecgroup; - - ecgroup = EC_GROUP_new_by_curve_name(nid); - - for (unsigned int iter = 0; iter < iterations; iter++) { - - // random message len between 1 and 256 - int msg_len = (random32() & 0xFF) + 1; - // create random message - random_buffer(msg, msg_len); - - // new ECDSA key - EC_KEY *eckey = EC_KEY_new(); - EC_KEY_set_group(eckey, ecgroup); - - // generate the key - EC_KEY_generate_key(eckey); - // copy key to buffer - const BIGNUM *K = EC_KEY_get0_private_key(eckey); - int bn_off = sizeof(priv_key) - BN_num_bytes(K); - memzero(priv_key, bn_off); - BN_bn2bin(K, priv_key + bn_off); - - // use our ECDSA signer to sign the message with the key - if (ecdsa_sign(curve, HASHER_SHA2, priv_key, msg, msg_len, sig, NULL, NULL) != 0) { - printf("trezor-crypto signing failed\n"); - return; - } - - // generate public key from private key - ecdsa_get_public_key33(curve, priv_key, pub_key33); - ecdsa_get_public_key65(curve, priv_key, pub_key65); - - // use our ECDSA verifier to verify the message signature - if (ecdsa_verify(curve, HASHER_SHA2, pub_key65, sig, msg, msg_len) != 0) { - printf("trezor-crypto verification failed (pub_key_len = 65)\n"); - return; - } - if (ecdsa_verify(curve, HASHER_SHA2, pub_key33, sig, msg, msg_len) != 0) { - printf("trezor-crypto verification failed (pub_key_len = 33)\n"); - return; - } - - // copy signature to the OpenSSL struct - ECDSA_SIG *signature = ECDSA_SIG_new(); -#if OPENSSL_VERSION_NUMBER < 0x10100000L - BN_bin2bn(sig, 32, signature->r); - BN_bin2bn(sig + 32, 32, signature->s); +void openssl_check(unsigned int iterations, int nid, const ecdsa_curve *curve) { + uint8_t sig[64], pub_key33[33], pub_key65[65], priv_key[32], msg[256], + hash[32]; + struct SHA256state_st sha256; + EC_GROUP *ecgroup; + + ecgroup = EC_GROUP_new_by_curve_name(nid); + + for (unsigned int iter = 0; iter < iterations; iter++) { + // random message len between 1 and 256 + int msg_len = (random32() & 0xFF) + 1; + // create random message + random_buffer(msg, msg_len); + + // new ECDSA key + EC_KEY *eckey = EC_KEY_new(); + EC_KEY_set_group(eckey, ecgroup); + + // generate the key + EC_KEY_generate_key(eckey); + // copy key to buffer + const BIGNUM *K = EC_KEY_get0_private_key(eckey); + int bn_off = sizeof(priv_key) - BN_num_bytes(K); + memzero(priv_key, bn_off); + BN_bn2bin(K, priv_key + bn_off); + + // use our ECDSA signer to sign the message with the key + if (ecdsa_sign(curve, HASHER_SHA2, priv_key, msg, msg_len, sig, NULL, + NULL) != 0) { + printf("trezor-crypto signing failed\n"); + return; + } + + // generate public key from private key + ecdsa_get_public_key33(curve, priv_key, pub_key33); + ecdsa_get_public_key65(curve, priv_key, pub_key65); + + // use our ECDSA verifier to verify the message signature + if (ecdsa_verify(curve, HASHER_SHA2, pub_key65, sig, msg, msg_len) != 0) { + printf("trezor-crypto verification failed (pub_key_len = 65)\n"); + return; + } + if (ecdsa_verify(curve, HASHER_SHA2, pub_key33, sig, msg, msg_len) != 0) { + printf("trezor-crypto verification failed (pub_key_len = 33)\n"); + return; + } + + // copy signature to the OpenSSL struct + ECDSA_SIG *signature = ECDSA_SIG_new(); +#if OPENSSL_VERSION_NUMBER < 0x10100000L + BN_bin2bn(sig, 32, signature->r); + BN_bin2bn(sig + 32, 32, signature->s); #else - BIGNUM *R = BN_bin2bn(sig, 32, NULL); - BIGNUM *S = BN_bin2bn(sig + 32, 32, NULL); - ECDSA_SIG_set0(signature, R, S); + BIGNUM *R = BN_bin2bn(sig, 32, NULL); + BIGNUM *S = BN_bin2bn(sig + 32, 32, NULL); + ECDSA_SIG_set0(signature, R, S); #endif - // compute the digest of the message - // note: these are OpenSSL functions, not our own - SHA256_Init(&sha256); - SHA256_Update(&sha256, msg, msg_len); - SHA256_Final(hash, &sha256); - - // verify all went well, i.e. we can decrypt our signature with OpenSSL - int v = ECDSA_do_verify(hash, 32, signature, eckey); - if (v != 1) { - printf("OpenSSL verification failed (%d)\n", v); - return; - } - - ECDSA_SIG_free(signature); - EC_KEY_free(eckey); - if (((iter + 1) % 100) == 0) printf("Passed ... %d\n", iter + 1); - } - EC_GROUP_free(ecgroup); - printf("All OK\n"); + // compute the digest of the message + // note: these are OpenSSL functions, not our own + SHA256_Init(&sha256); + SHA256_Update(&sha256, msg, msg_len); + SHA256_Final(hash, &sha256); + + // verify all went well, i.e. we can decrypt our signature with OpenSSL + int v = ECDSA_do_verify(hash, 32, signature, eckey); + if (v != 1) { + printf("OpenSSL verification failed (%d)\n", v); + return; + } + + ECDSA_SIG_free(signature); + EC_KEY_free(eckey); + if (((iter + 1) % 100) == 0) printf("Passed ... %d\n", iter + 1); + } + EC_GROUP_free(ecgroup); + printf("All OK\n"); } -int main(int argc, char *argv[]) -{ - if (argc != 2) { - printf("Usage: test_openssl iterations\n"); - return 1; - } +int main(int argc, char *argv[]) { + if (argc != 2) { + printf("Usage: test_openssl iterations\n"); + return 1; + } - unsigned int iterations; - sscanf(argv[1], "%u", &iterations); + unsigned int iterations; + sscanf(argv[1], "%u", &iterations); - printf("Testing secp256k1:\n"); - openssl_check(iterations, NID_secp256k1, &secp256k1); + printf("Testing secp256k1:\n"); + openssl_check(iterations, NID_secp256k1, &secp256k1); - printf("Testing nist256p1:\n"); - openssl_check(iterations, NID_X9_62_prime256v1, &nist256p1); + printf("Testing nist256p1:\n"); + openssl_check(iterations, NID_X9_62_prime256v1, &nist256p1); - return 0; + return 0; } diff --git a/tests/test_speed.c b/tests/test_speed.c index 592186fbb..c9e67b5ee 100644 --- a/tests/test_speed.c +++ b/tests/test_speed.c @@ -1,215 +1,233 @@ -#include #include -#include -#include #include +#include +#include +#include +#include "bip32.h" #include "curves.h" #include "ecdsa.h" -#include "bip32.h" -#include "secp256k1.h" -#include "nist256p1.h" #include "ed25519-donna/ed25519.h" #include "hasher.h" +#include "nist256p1.h" +#include "secp256k1.h" static uint8_t msg[256]; -void prepare_msg(void) -{ - for (size_t i = 0; i < sizeof(msg); i++) { - msg[i] = i * 1103515245; - } +void prepare_msg(void) { + for (size_t i = 0; i < sizeof(msg); i++) { + msg[i] = i * 1103515245; + } } -void bench_sign_secp256k1(int iterations) -{ - uint8_t sig[64], priv[32], pby; +void bench_sign_secp256k1(int iterations) { + uint8_t sig[64], priv[32], pby; - const ecdsa_curve *curve = &secp256k1; + const ecdsa_curve *curve = &secp256k1; - memcpy(priv, "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", 32); + memcpy(priv, + "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3" + "\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", + 32); - for (int i = 0 ; i < iterations; i++) { - ecdsa_sign(curve, HASHER_SHA2, priv, msg, sizeof(msg), sig, &pby, NULL); - } + for (int i = 0; i < iterations; i++) { + ecdsa_sign(curve, HASHER_SHA2, priv, msg, sizeof(msg), sig, &pby, NULL); + } } -void bench_sign_nist256p1(int iterations) -{ - uint8_t sig[64], priv[32], pby; +void bench_sign_nist256p1(int iterations) { + uint8_t sig[64], priv[32], pby; - const ecdsa_curve *curve = &nist256p1; + const ecdsa_curve *curve = &nist256p1; - memcpy(priv, "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", 32); + memcpy(priv, + "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3" + "\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", + 32); - for (int i = 0 ; i < iterations; i++) { - ecdsa_sign(curve, HASHER_SHA2, priv, msg, sizeof(msg), sig, &pby, NULL); - } + for (int i = 0; i < iterations; i++) { + ecdsa_sign(curve, HASHER_SHA2, priv, msg, sizeof(msg), sig, &pby, NULL); + } } -void bench_sign_ed25519(int iterations) -{ - ed25519_public_key pk; - ed25519_secret_key sk; - ed25519_signature sig; +void bench_sign_ed25519(int iterations) { + ed25519_public_key pk; + ed25519_secret_key sk; + ed25519_signature sig; - memcpy(pk, "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", 32); - ed25519_publickey(sk, pk); + memcpy(pk, + "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3" + "\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", + 32); + ed25519_publickey(sk, pk); - for (int i = 0 ; i < iterations; i++) { - ed25519_sign(msg, sizeof(msg), sk, pk, sig); - } + for (int i = 0; i < iterations; i++) { + ed25519_sign(msg, sizeof(msg), sk, pk, sig); + } } -void bench_verify_secp256k1_33(int iterations) -{ - uint8_t sig[64], pub[33], priv[32], pby; +void bench_verify_secp256k1_33(int iterations) { + uint8_t sig[64], pub[33], priv[32], pby; - const ecdsa_curve *curve = &secp256k1; + const ecdsa_curve *curve = &secp256k1; - memcpy(priv, "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", 32); - ecdsa_get_public_key33(curve, priv, pub); - ecdsa_sign(curve, HASHER_SHA2, priv, msg, sizeof(msg), sig, &pby, NULL); + memcpy(priv, + "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3" + "\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", + 32); + ecdsa_get_public_key33(curve, priv, pub); + ecdsa_sign(curve, HASHER_SHA2, priv, msg, sizeof(msg), sig, &pby, NULL); - for (int i = 0 ; i < iterations; i++) { - ecdsa_verify(curve, HASHER_SHA2, pub, sig, msg, sizeof(msg)); - } + for (int i = 0; i < iterations; i++) { + ecdsa_verify(curve, HASHER_SHA2, pub, sig, msg, sizeof(msg)); + } } -void bench_verify_secp256k1_65(int iterations) -{ - uint8_t sig[64], pub[65], priv[32], pby; +void bench_verify_secp256k1_65(int iterations) { + uint8_t sig[64], pub[65], priv[32], pby; - const ecdsa_curve *curve = &secp256k1; + const ecdsa_curve *curve = &secp256k1; - memcpy(priv, "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", 32); - ecdsa_get_public_key65(curve, priv, pub); - ecdsa_sign(curve, HASHER_SHA2, priv, msg, sizeof(msg), sig, &pby, NULL); + memcpy(priv, + "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3" + "\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", + 32); + ecdsa_get_public_key65(curve, priv, pub); + ecdsa_sign(curve, HASHER_SHA2, priv, msg, sizeof(msg), sig, &pby, NULL); - for (int i = 0 ; i < iterations; i++) { - ecdsa_verify(curve, HASHER_SHA2, pub, sig, msg, sizeof(msg)); - } + for (int i = 0; i < iterations; i++) { + ecdsa_verify(curve, HASHER_SHA2, pub, sig, msg, sizeof(msg)); + } } -void bench_verify_nist256p1_33(int iterations) -{ - uint8_t sig[64], pub[33], priv[32], pby; +void bench_verify_nist256p1_33(int iterations) { + uint8_t sig[64], pub[33], priv[32], pby; - const ecdsa_curve *curve = &nist256p1; + const ecdsa_curve *curve = &nist256p1; - memcpy(priv, "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", 32); - ecdsa_get_public_key33(curve, priv, pub); - ecdsa_sign(curve, HASHER_SHA2, priv, msg, sizeof(msg), sig, &pby, NULL); + memcpy(priv, + "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3" + "\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", + 32); + ecdsa_get_public_key33(curve, priv, pub); + ecdsa_sign(curve, HASHER_SHA2, priv, msg, sizeof(msg), sig, &pby, NULL); - for (int i = 0 ; i < iterations; i++) { - ecdsa_verify(curve, HASHER_SHA2, pub, sig, msg, sizeof(msg)); - } + for (int i = 0; i < iterations; i++) { + ecdsa_verify(curve, HASHER_SHA2, pub, sig, msg, sizeof(msg)); + } } -void bench_verify_nist256p1_65(int iterations) -{ - uint8_t sig[64], pub[65], priv[32], pby; +void bench_verify_nist256p1_65(int iterations) { + uint8_t sig[64], pub[65], priv[32], pby; - const ecdsa_curve *curve = &nist256p1; + const ecdsa_curve *curve = &nist256p1; - memcpy(priv, "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", 32); - ecdsa_get_public_key65(curve, priv, pub); - ecdsa_sign(curve, HASHER_SHA2, priv, msg, sizeof(msg), sig, &pby, NULL); + memcpy(priv, + "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3" + "\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", + 32); + ecdsa_get_public_key65(curve, priv, pub); + ecdsa_sign(curve, HASHER_SHA2, priv, msg, sizeof(msg), sig, &pby, NULL); - for (int i = 0 ; i < iterations; i++) { - ecdsa_verify(curve, HASHER_SHA2, pub, sig, msg, sizeof(msg)); - } + for (int i = 0; i < iterations; i++) { + ecdsa_verify(curve, HASHER_SHA2, pub, sig, msg, sizeof(msg)); + } } -void bench_verify_ed25519(int iterations) -{ - ed25519_public_key pk; - ed25519_secret_key sk; - ed25519_signature sig; - - memcpy(pk, "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", 32); - ed25519_publickey(sk, pk); - ed25519_sign(msg, sizeof(msg), sk, pk, sig); - - for (int i = 0 ; i < iterations; i++) { - ed25519_sign_open(msg, sizeof(msg), pk, sig); - } +void bench_verify_ed25519(int iterations) { + ed25519_public_key pk; + ed25519_secret_key sk; + ed25519_signature sig; + + memcpy(pk, + "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3" + "\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", + 32); + ed25519_publickey(sk, pk); + ed25519_sign(msg, sizeof(msg), sk, pk, sig); + + for (int i = 0; i < iterations; i++) { + ed25519_sign_open(msg, sizeof(msg), pk, sig); + } } -void bench_multiply_curve25519(int iterations) -{ - uint8_t result[32]; - uint8_t secret[32]; - uint8_t basepoint[32]; - - memcpy(secret, "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", 32); - memcpy(basepoint, "\x96\x47\xda\xbe\x1e\xea\xaf\x25\x47\x1e\x68\x0b\x4d\x7c\x6f\xd1\x14\x38\x76\xbb\x77\x59\xd8\x3d\x0f\xf7\xa2\x49\x08\xfd\xda\xbc", 32); - - for (int i = 0 ; i < iterations; i++) { - curve25519_scalarmult(result, secret, basepoint); - } +void bench_multiply_curve25519(int iterations) { + uint8_t result[32]; + uint8_t secret[32]; + uint8_t basepoint[32]; + + memcpy(secret, + "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3" + "\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", + 32); + memcpy(basepoint, + "\x96\x47\xda\xbe\x1e\xea\xaf\x25\x47\x1e\x68\x0b\x4d\x7c\x6f\xd1\x14" + "\x38\x76\xbb\x77\x59\xd8\x3d\x0f\xf7\xa2\x49\x08\xfd\xda\xbc", + 32); + + for (int i = 0; i < iterations; i++) { + curve25519_scalarmult(result, secret, basepoint); + } } static HDNode root; -void prepare_node(void) -{ - hdnode_from_seed((uint8_t *)"NothingToSeeHere", 16, SECP256K1_NAME, &root); - hdnode_fill_public_key(&root); +void prepare_node(void) { + hdnode_from_seed((uint8_t *)"NothingToSeeHere", 16, SECP256K1_NAME, &root); + hdnode_fill_public_key(&root); } -void bench_ckd_normal(int iterations) -{ - char addr[MAX_ADDR_SIZE]; - HDNode node; - for (int i = 0; i < iterations; i++) { - memcpy(&node, &root, sizeof(HDNode)); - hdnode_public_ckd(&node, i); - hdnode_fill_public_key(&node); - ecdsa_get_address(node.public_key, HASHER_SHA2, HASHER_SHA2D, 0, addr, sizeof(addr)); - } +void bench_ckd_normal(int iterations) { + char addr[MAX_ADDR_SIZE]; + HDNode node; + for (int i = 0; i < iterations; i++) { + memcpy(&node, &root, sizeof(HDNode)); + hdnode_public_ckd(&node, i); + hdnode_fill_public_key(&node); + ecdsa_get_address(node.public_key, HASHER_SHA2, HASHER_SHA2D, 0, addr, + sizeof(addr)); + } } -void bench_ckd_optimized(int iterations) -{ - char addr[MAX_ADDR_SIZE]; - curve_point pub; - ecdsa_read_pubkey(&secp256k1, root.public_key, &pub); - for (int i = 0; i < iterations; i++) { - hdnode_public_ckd_address_optimized(&pub, root.chain_code, i, 0, HASHER_SHA2, HASHER_SHA2D, addr, sizeof(addr), false); - } +void bench_ckd_optimized(int iterations) { + char addr[MAX_ADDR_SIZE]; + curve_point pub; + ecdsa_read_pubkey(&secp256k1, root.public_key, &pub); + for (int i = 0; i < iterations; i++) { + hdnode_public_ckd_address_optimized(&pub, root.chain_code, i, 0, + HASHER_SHA2, HASHER_SHA2D, addr, + sizeof(addr), false); + } } -void bench(void (*func)(int), const char *name, int iterations) -{ - clock_t t = clock(); - func(iterations); - float speed = iterations / ((float)(clock() - t) / CLOCKS_PER_SEC); - printf("%25s: %8.2f ops/s\n", name, speed); +void bench(void (*func)(int), const char *name, int iterations) { + clock_t t = clock(); + func(iterations); + float speed = iterations / ((float)(clock() - t) / CLOCKS_PER_SEC); + printf("%25s: %8.2f ops/s\n", name, speed); } #define BENCH(FUNC, ITER) bench(FUNC, #FUNC, ITER) int main(void) { + prepare_msg(); - prepare_msg(); - - BENCH(bench_sign_secp256k1, 500); - BENCH(bench_verify_secp256k1_33, 500); - BENCH(bench_verify_secp256k1_65, 500); + BENCH(bench_sign_secp256k1, 500); + BENCH(bench_verify_secp256k1_33, 500); + BENCH(bench_verify_secp256k1_65, 500); - BENCH(bench_sign_nist256p1, 500); - BENCH(bench_verify_nist256p1_33, 500); - BENCH(bench_verify_nist256p1_65, 500); + BENCH(bench_sign_nist256p1, 500); + BENCH(bench_verify_nist256p1_33, 500); + BENCH(bench_verify_nist256p1_65, 500); - BENCH(bench_sign_ed25519, 4000); - BENCH(bench_verify_ed25519, 4000); + BENCH(bench_sign_ed25519, 4000); + BENCH(bench_verify_ed25519, 4000); - BENCH(bench_multiply_curve25519, 4000); + BENCH(bench_multiply_curve25519, 4000); - prepare_node(); + prepare_node(); - BENCH(bench_ckd_normal, 1000); - BENCH(bench_ckd_optimized, 1000); + BENCH(bench_ckd_normal, 1000); + BENCH(bench_ckd_optimized, 1000); - return 0; + return 0; } diff --git a/tools/bip39bruteforce.c b/tools/bip39bruteforce.c index be2fa5b76..723343fe2 100644 --- a/tools/bip39bruteforce.c +++ b/tools/bip39bruteforce.c @@ -1,10 +1,10 @@ #include -#include #include -#include "bip39.h" +#include #include "bip32.h" -#include "ecdsa.h" +#include "bip39.h" #include "curves.h" +#include "ecdsa.h" #include "secp256k1.h" char iter[256]; @@ -26,63 +26,64 @@ clock_t start; // address: "1N3uJ5AU3FTYQ1ZQgTMtYmgSvMBmQiGVBS" // passphrase: "testing" -int main(int argc, char **argv) -{ - if (argc != 2 && argc != 3) { - fprintf(stderr, "Usage: bip39bruteforce address [mnemonic]\n"); - return 1; - } - const char *address = argv[1]; - const char *mnemonic, *item; - if (argc == 3) { - mnemonic = argv[2]; - item = "passphrase"; - } else { - mnemonic = NULL; - item = "mnemonic"; - } - if (mnemonic && !mnemonic_check(mnemonic)) { - fprintf(stderr, "\"%s\" is not a valid mnemonic\n", mnemonic); - return 2; - } - if (!ecdsa_address_decode(address, 0, secp256k1_info.hasher_base58, addr)) { - fprintf(stderr, "\"%s\" is not a valid address\n", address); - return 3; - } - printf("Reading %ss from stdin ...\n", item); - start = clock(); - for (;;) { - if (fgets(iter, 256, stdin) == NULL) break; - int len = strlen(iter); - if (len <= 0) { - continue; - } - count++; - iter[len - 1] = 0; - if (mnemonic) { - mnemonic_to_seed(mnemonic, iter, seed, NULL); - } else { - mnemonic_to_seed(iter, "", seed, NULL); - } - hdnode_from_seed(seed, 512 / 8, SECP256K1_NAME, &node); - hdnode_private_ckd_prime(&node, 44); - hdnode_private_ckd_prime(&node, 0); - hdnode_private_ckd_prime(&node, 0); - hdnode_private_ckd(&node, 0); - hdnode_private_ckd(&node, 0); - hdnode_fill_public_key(&node); - ecdsa_get_pubkeyhash(node.public_key, secp256k1_info.hasher_pubkey, pubkeyhash); - if (memcmp(addr + 1, pubkeyhash, 20) == 0) { - found = 1; - break; - } - } - float dur = (float)(clock() - start) / CLOCKS_PER_SEC; - printf("Tried %d %ss in %f seconds = %f tries/second\n", count, item, dur, (float)count/dur); - if (found) { - printf("Correct %s found! :-)\n\"%s\"\n", item, iter); - return 0; - } - printf("Correct %s not found. :-(\n", item); - return 4; +int main(int argc, char **argv) { + if (argc != 2 && argc != 3) { + fprintf(stderr, "Usage: bip39bruteforce address [mnemonic]\n"); + return 1; + } + const char *address = argv[1]; + const char *mnemonic, *item; + if (argc == 3) { + mnemonic = argv[2]; + item = "passphrase"; + } else { + mnemonic = NULL; + item = "mnemonic"; + } + if (mnemonic && !mnemonic_check(mnemonic)) { + fprintf(stderr, "\"%s\" is not a valid mnemonic\n", mnemonic); + return 2; + } + if (!ecdsa_address_decode(address, 0, secp256k1_info.hasher_base58, addr)) { + fprintf(stderr, "\"%s\" is not a valid address\n", address); + return 3; + } + printf("Reading %ss from stdin ...\n", item); + start = clock(); + for (;;) { + if (fgets(iter, 256, stdin) == NULL) break; + int len = strlen(iter); + if (len <= 0) { + continue; + } + count++; + iter[len - 1] = 0; + if (mnemonic) { + mnemonic_to_seed(mnemonic, iter, seed, NULL); + } else { + mnemonic_to_seed(iter, "", seed, NULL); + } + hdnode_from_seed(seed, 512 / 8, SECP256K1_NAME, &node); + hdnode_private_ckd_prime(&node, 44); + hdnode_private_ckd_prime(&node, 0); + hdnode_private_ckd_prime(&node, 0); + hdnode_private_ckd(&node, 0); + hdnode_private_ckd(&node, 0); + hdnode_fill_public_key(&node); + ecdsa_get_pubkeyhash(node.public_key, secp256k1_info.hasher_pubkey, + pubkeyhash); + if (memcmp(addr + 1, pubkeyhash, 20) == 0) { + found = 1; + break; + } + } + float dur = (float)(clock() - start) / CLOCKS_PER_SEC; + printf("Tried %d %ss in %f seconds = %f tries/second\n", count, item, dur, + (float)count / dur); + if (found) { + printf("Correct %s found! :-)\n\"%s\"\n", item, iter); + return 0; + } + printf("Correct %s not found. :-(\n", item); + return 4; } diff --git a/tools/mktable.c b/tools/mktable.c index 01ec375c9..f9ab1c653 100644 --- a/tools/mktable.c +++ b/tools/mktable.c @@ -1,8 +1,8 @@ -#include #include +#include #include "bignum.h" -#include "ecdsa.h" #include "bip32.h" +#include "ecdsa.h" #include "rand.h" /* @@ -11,58 +11,58 @@ * where G is the generator of the specified elliptic curve. */ int main(int argc, char **argv) { - int i,j,k; - if (argc != 2) { - printf("Usage: %s CURVE_NAME\n", argv[0]); - return 1; - } - const char *name = argv[1]; - const curve_info *info = get_curve_by_name(name); - const ecdsa_curve *curve = info->params; - if (curve == 0) { - printf("Unknown curve '%s'\n", name); - return 1; - } + int i, j, k; + if (argc != 2) { + printf("Usage: %s CURVE_NAME\n", argv[0]); + return 1; + } + const char *name = argv[1]; + const curve_info *info = get_curve_by_name(name); + const ecdsa_curve *curve = info->params; + if (curve == 0) { + printf("Unknown curve '%s'\n", name); + return 1; + } - curve_point ng = curve->G; - curve_point pow2ig = curve->G; - for (i = 0; i < 64; i++) { - // invariants: - // pow2ig = 16^i * G - // ng = pow2ig - printf("\t{\n"); - for (j = 0; j < 8; j++) { - // invariants: - // pow2ig = 16^i * G - // ng = (2*j+1) * 16^i * G + curve_point ng = curve->G; + curve_point pow2ig = curve->G; + for (i = 0; i < 64; i++) { + // invariants: + // pow2ig = 16^i * G + // ng = pow2ig + printf("\t{\n"); + for (j = 0; j < 8; j++) { + // invariants: + // pow2ig = 16^i * G + // ng = (2*j+1) * 16^i * G #ifndef NDEBUG - curve_point checkresult; - bignum256 a; - bn_zero(&a); - a.val[(4*i) / 30] = ((uint32_t) 2*j+1) << ((4*i) % 30); - bn_normalize(&a); - point_multiply(curve, &a, &curve->G, &checkresult); - assert(point_is_equal(&checkresult, &ng)); + curve_point checkresult; + bignum256 a; + bn_zero(&a); + a.val[(4 * i) / 30] = ((uint32_t)2 * j + 1) << ((4 * i) % 30); + bn_normalize(&a); + point_multiply(curve, &a, &curve->G, &checkresult); + assert(point_is_equal(&checkresult, &ng)); #endif - printf("\t\t/* %2d*16^%d*G: */\n\t\t{{{", 2*j + 1, i); - // print x coordinate - for (k = 0; k < 9; k++) { - printf((k < 8 ? "0x%08x, " : "0x%04x"), ng.x.val[k]); - } - printf("}},\n\t\t {{"); - // print y coordinate - for (k = 0; k < 9; k++) { - printf((k < 8 ? "0x%08x, " : "0x%04x"), ng.y.val[k]); - } - if (j == 7) { - printf("}}}\n\t},\n"); - } else { - printf("}}},\n"); - point_add(curve, &pow2ig, &ng); - } - point_add(curve, &pow2ig, &ng); - } - pow2ig = ng; - } - return 0; + printf("\t\t/* %2d*16^%d*G: */\n\t\t{{{", 2 * j + 1, i); + // print x coordinate + for (k = 0; k < 9; k++) { + printf((k < 8 ? "0x%08x, " : "0x%04x"), ng.x.val[k]); + } + printf("}},\n\t\t {{"); + // print y coordinate + for (k = 0; k < 9; k++) { + printf((k < 8 ? "0x%08x, " : "0x%04x"), ng.y.val[k]); + } + if (j == 7) { + printf("}}}\n\t},\n"); + } else { + printf("}}},\n"); + point_add(curve, &pow2ig, &ng); + } + point_add(curve, &pow2ig, &ng); + } + pow2ig = ng; + } + return 0; } diff --git a/tools/xpubaddrgen.c b/tools/xpubaddrgen.c index 54c5ebc98..fd5e83fd7 100644 --- a/tools/xpubaddrgen.c +++ b/tools/xpubaddrgen.c @@ -1,47 +1,49 @@ +#include +#include #include #include -#include -#include #include "bip32.h" #include "curves.h" #include "ecdsa.h" -#define VERSION_PUBLIC 0x0488b21e +#define VERSION_PUBLIC 0x0488b21e #define VERSION_PRIVATE 0x0488ade4 -void process_job(uint32_t jobid, const char *xpub, uint32_t change, uint32_t from, uint32_t to) -{ - HDNode node, child; - if (change > 1 || to <= from || hdnode_deserialize(xpub, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node, NULL) != 0) { - printf("%d error\n", jobid); - return; - } - hdnode_public_ckd(&node, change); - uint32_t i; - char address[36]; - for (i = from; i < to; i++) { - memcpy(&child, &node, sizeof(HDNode)); - hdnode_public_ckd(&child, i); - ecdsa_get_address(child.public_key, 0, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address)); - printf("%d %d %s\n", jobid, i, address); - } +void process_job(uint32_t jobid, const char *xpub, uint32_t change, + uint32_t from, uint32_t to) { + HDNode node, child; + if (change > 1 || to <= from || + hdnode_deserialize(xpub, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, + &node, NULL) != 0) { + printf("%d error\n", jobid); + return; + } + hdnode_public_ckd(&node, change); + uint32_t i; + char address[36]; + for (i = from; i < to; i++) { + memcpy(&child, &node, sizeof(HDNode)); + hdnode_public_ckd(&child, i); + ecdsa_get_address(child.public_key, 0, HASHER_SHA2, HASHER_SHA2D, address, + sizeof(address)); + printf("%d %d %s\n", jobid, i, address); + } } -int main(void) -{ - char line[1024], xpub[1024]; - uint32_t jobid, change, from, to; - int r; - for (;;) { - if (!fgets(line, sizeof(line), stdin)) break; - r = sscanf(line, "%u %s %u %u %u\n", &jobid, xpub, &change, &from, &to); - if (r < 1) { - printf("error\n"); - } else if (r != 5) { - printf("%d error\n", jobid); - } else { - process_job(jobid, xpub, change, from, to); - } - } - return 0; +int main(void) { + char line[1024], xpub[1024]; + uint32_t jobid, change, from, to; + int r; + for (;;) { + if (!fgets(line, sizeof(line), stdin)) break; + r = sscanf(line, "%u %s %u %u %u\n", &jobid, xpub, &change, &from, &to); + if (r < 1) { + printf("error\n"); + } else if (r != 5) { + printf("%d error\n", jobid); + } else { + process_job(jobid, xpub, change, from, to); + } + } + return 0; }